[kernel] r7741 - in people/maks-guest/linux-2.6: . debian debian/arch debian/arch/_vserver debian/arch/_xen debian/arch/alpha debian/arch/alpha/vserver debian/arch/amd64 debian/arch/amd64/vserver debian/arch/amd64/xen debian/arch/amd64/xen-vserver debian/arch/arm debian/arch/hppa debian/arch/i386 debian/arch/i386/vserver debian/arch/i386/xen debian/arch/i386/xen-vserver debian/arch/ia64 debian/arch/m68k debian/arch/mips debian/arch/mipsel debian/arch/powerpc debian/arch/powerpc/vserver debian/arch/s390 debian/arch/s390/vserver debian/arch/sparc debian/arch/sparc/vserver debian/bin debian/lib debian/lib/python debian/lib/python/debian_linux debian/modules debian/patches debian/patches/bugfix debian/patches/bugfix/alpha debian/patches/bugfix/arm debian/patches/bugfix/ia64 debian/patches/bugfix/mips debian/patches/bugfix/powerpc debian/patches/bugfix/sparc debian/patches/debian debian/patches/features debian/patches/features/all debian/patches/features/all/drivers debian/patches/features/all/vserver debian/patches/features/all/xen debian/patches/features/alpha debian/patches/features/arm debian/patches/features/mips debian/patches/features/s390 debian/patches/series debian/templates
maximilian attems
maks-guest at alioth.debian.org
Sat Nov 11 01:52:12 UTC 2006
Author: maks-guest
Date: Sat Nov 11 02:48:00 2006
New Revision: 7741
Added:
people/maks-guest/linux-2.6/
people/maks-guest/linux-2.6/debian/
people/maks-guest/linux-2.6/debian/README
people/maks-guest/linux-2.6/debian/README.Debian
people/maks-guest/linux-2.6/debian/README.build
people/maks-guest/linux-2.6/debian/arch/
people/maks-guest/linux-2.6/debian/arch/_vserver/
people/maks-guest/linux-2.6/debian/arch/_vserver/config
people/maks-guest/linux-2.6/debian/arch/_xen/
people/maks-guest/linux-2.6/debian/arch/_xen/config
people/maks-guest/linux-2.6/debian/arch/alpha/
people/maks-guest/linux-2.6/debian/arch/alpha/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/alpha/config
people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-generic
people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-legacy
people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-smp
people/maks-guest/linux-2.6/debian/arch/alpha/defines
people/maks-guest/linux-2.6/debian/arch/alpha/vserver/
people/maks-guest/linux-2.6/debian/arch/alpha/vserver/defines
people/maks-guest/linux-2.6/debian/arch/amd64/
people/maks-guest/linux-2.6/debian/arch/amd64/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/amd64/config
people/maks-guest/linux-2.6/debian/arch/amd64/config.amd64
people/maks-guest/linux-2.6/debian/arch/amd64/defines
people/maks-guest/linux-2.6/debian/arch/amd64/vserver/
people/maks-guest/linux-2.6/debian/arch/amd64/vserver/defines
people/maks-guest/linux-2.6/debian/arch/amd64/xen/
people/maks-guest/linux-2.6/debian/arch/amd64/xen-vserver/
people/maks-guest/linux-2.6/debian/arch/amd64/xen-vserver/defines
people/maks-guest/linux-2.6/debian/arch/amd64/xen/config
people/maks-guest/linux-2.6/debian/arch/amd64/xen/defines
people/maks-guest/linux-2.6/debian/arch/arm/
people/maks-guest/linux-2.6/debian/arch/arm/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/arm/config
people/maks-guest/linux-2.6/debian/arch/arm/config.footbridge
people/maks-guest/linux-2.6/debian/arch/arm/config.iop32x
people/maks-guest/linux-2.6/debian/arch/arm/config.ixp4xx
people/maks-guest/linux-2.6/debian/arch/arm/config.rpc
people/maks-guest/linux-2.6/debian/arch/arm/config.s3c2410
people/maks-guest/linux-2.6/debian/arch/arm/config.versatile
people/maks-guest/linux-2.6/debian/arch/arm/defines
people/maks-guest/linux-2.6/debian/arch/config
people/maks-guest/linux-2.6/debian/arch/defines
people/maks-guest/linux-2.6/debian/arch/hppa/
people/maks-guest/linux-2.6/debian/arch/hppa/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/hppa/config
people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc
people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc-smp
people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc64
people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc64-smp
people/maks-guest/linux-2.6/debian/arch/hppa/defines
people/maks-guest/linux-2.6/debian/arch/i386/
people/maks-guest/linux-2.6/debian/arch/i386/config
people/maks-guest/linux-2.6/debian/arch/i386/config.486
people/maks-guest/linux-2.6/debian/arch/i386/config.686
people/maks-guest/linux-2.6/debian/arch/i386/config.686-bigmem
people/maks-guest/linux-2.6/debian/arch/i386/config.k7
people/maks-guest/linux-2.6/debian/arch/i386/defines
people/maks-guest/linux-2.6/debian/arch/i386/vserver/
people/maks-guest/linux-2.6/debian/arch/i386/vserver/defines
people/maks-guest/linux-2.6/debian/arch/i386/xen/
people/maks-guest/linux-2.6/debian/arch/i386/xen-vserver/
people/maks-guest/linux-2.6/debian/arch/i386/xen-vserver/defines
people/maks-guest/linux-2.6/debian/arch/i386/xen/config
people/maks-guest/linux-2.6/debian/arch/i386/xen/defines
people/maks-guest/linux-2.6/debian/arch/ia64/
people/maks-guest/linux-2.6/debian/arch/ia64/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/ia64/config
people/maks-guest/linux-2.6/debian/arch/ia64/config.itanium
people/maks-guest/linux-2.6/debian/arch/ia64/config.mckinley
people/maks-guest/linux-2.6/debian/arch/ia64/defines
people/maks-guest/linux-2.6/debian/arch/m68k/
people/maks-guest/linux-2.6/debian/arch/m68k/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/m68k/README.build
people/maks-guest/linux-2.6/debian/arch/m68k/config
people/maks-guest/linux-2.6/debian/arch/m68k/config.amiga
people/maks-guest/linux-2.6/debian/arch/m68k/config.atari
people/maks-guest/linux-2.6/debian/arch/m68k/config.bvme6000
people/maks-guest/linux-2.6/debian/arch/m68k/config.hp
people/maks-guest/linux-2.6/debian/arch/m68k/config.mac
people/maks-guest/linux-2.6/debian/arch/m68k/config.mvme147
people/maks-guest/linux-2.6/debian/arch/m68k/config.mvme16x
people/maks-guest/linux-2.6/debian/arch/m68k/config.q40
people/maks-guest/linux-2.6/debian/arch/m68k/config.sun3
people/maks-guest/linux-2.6/debian/arch/m68k/defines
people/maks-guest/linux-2.6/debian/arch/mips/
people/maks-guest/linux-2.6/debian/arch/mips/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/mips/config
people/maks-guest/linux-2.6/debian/arch/mips/config.qemu
people/maks-guest/linux-2.6/debian/arch/mips/config.r4k-ip22
people/maks-guest/linux-2.6/debian/arch/mips/config.r5k-ip32
people/maks-guest/linux-2.6/debian/arch/mips/config.sb1-bcm91250a
people/maks-guest/linux-2.6/debian/arch/mips/config.sb1a-bcm91480b
people/maks-guest/linux-2.6/debian/arch/mips/defines
people/maks-guest/linux-2.6/debian/arch/mipsel/
people/maks-guest/linux-2.6/debian/arch/mipsel/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/mipsel/config
people/maks-guest/linux-2.6/debian/arch/mipsel/config.qemu
people/maks-guest/linux-2.6/debian/arch/mipsel/config.r3k-kn02
people/maks-guest/linux-2.6/debian/arch/mipsel/config.r4k-kn04
people/maks-guest/linux-2.6/debian/arch/mipsel/config.r5k-cobalt
people/maks-guest/linux-2.6/debian/arch/mipsel/config.sb1-bcm91250a
people/maks-guest/linux-2.6/debian/arch/mipsel/config.sb1a-bcm91480b
people/maks-guest/linux-2.6/debian/arch/mipsel/defines
people/maks-guest/linux-2.6/debian/arch/powerpc/
people/maks-guest/linux-2.6/debian/arch/powerpc/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/powerpc/config
people/maks-guest/linux-2.6/debian/arch/powerpc/config.apus
people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc
people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc-miboot
people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc-smp
people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc64
people/maks-guest/linux-2.6/debian/arch/powerpc/config.prep
people/maks-guest/linux-2.6/debian/arch/powerpc/defines
people/maks-guest/linux-2.6/debian/arch/powerpc/modules
people/maks-guest/linux-2.6/debian/arch/powerpc/modules.README
people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc
people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc-miboot
people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc64
people/maks-guest/linux-2.6/debian/arch/powerpc/vserver/
people/maks-guest/linux-2.6/debian/arch/powerpc/vserver/defines
people/maks-guest/linux-2.6/debian/arch/s390/
people/maks-guest/linux-2.6/debian/arch/s390/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/s390/config
people/maks-guest/linux-2.6/debian/arch/s390/config.s390
people/maks-guest/linux-2.6/debian/arch/s390/config.s390-tape
people/maks-guest/linux-2.6/debian/arch/s390/config.s390x
people/maks-guest/linux-2.6/debian/arch/s390/defines
people/maks-guest/linux-2.6/debian/arch/s390/vserver/
people/maks-guest/linux-2.6/debian/arch/s390/vserver/defines
people/maks-guest/linux-2.6/debian/arch/sparc/
people/maks-guest/linux-2.6/debian/arch/sparc/Makefile.inc
people/maks-guest/linux-2.6/debian/arch/sparc/config
people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc32
people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc64
people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc64-smp
people/maks-guest/linux-2.6/debian/arch/sparc/defines
people/maks-guest/linux-2.6/debian/arch/sparc/vserver/
people/maks-guest/linux-2.6/debian/arch/sparc/vserver/defines
people/maks-guest/linux-2.6/debian/bin/
people/maks-guest/linux-2.6/debian/bin/abicheck.py (contents, props changed)
people/maks-guest/linux-2.6/debian/bin/abiupdate.py (contents, props changed)
people/maks-guest/linux-2.6/debian/bin/check-patches.sh (contents, props changed)
people/maks-guest/linux-2.6/debian/bin/gencontrol.py (contents, props changed)
people/maks-guest/linux-2.6/debian/bin/kconfig.py (contents, props changed)
people/maks-guest/linux-2.6/debian/bin/patch.apply
people/maks-guest/linux-2.6/debian/bin/patch.unpatch
people/maks-guest/linux-2.6/debian/bin/sparc32-image-postproc (contents, props changed)
people/maks-guest/linux-2.6/debian/changelog
people/maks-guest/linux-2.6/debian/compat
people/maks-guest/linux-2.6/debian/copyright
people/maks-guest/linux-2.6/debian/lib/
people/maks-guest/linux-2.6/debian/lib/python/
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/__init__.py
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/abi.py
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/config.py
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/debian.py
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/gencontrol.py
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/kconfig.py
people/maks-guest/linux-2.6/debian/lib/python/debian_linux/utils.py
people/maks-guest/linux-2.6/debian/modules/
people/maks-guest/linux-2.6/debian/modules/gencontrol.py (contents, props changed)
people/maks-guest/linux-2.6/debian/modules/rules.defs
people/maks-guest/linux-2.6/debian/modules/rules.include
people/maks-guest/linux-2.6/debian/modules/rules.real.include
people/maks-guest/linux-2.6/debian/patches/
people/maks-guest/linux-2.6/debian/patches/2.6.19-rc5
people/maks-guest/linux-2.6/debian/patches/alpha-prctl.patch
people/maks-guest/linux-2.6/debian/patches/arm-get_unaligned-gcc41-const.patch
people/maks-guest/linux-2.6/debian/patches/arm-iop-generic-backport.patch
people/maks-guest/linux-2.6/debian/patches/arm-iop-mtd-maps.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/
people/maks-guest/linux-2.6/debian/patches/bugfix/alpha/
people/maks-guest/linux-2.6/debian/patches/bugfix/alpha/asm-subarchs.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/arm/
people/maks-guest/linux-2.6/debian/patches/bugfix/arm/.n2100-serial-irq.patch.swp (contents, props changed)
people/maks-guest/linux-2.6/debian/patches/bugfix/arm/arm-generic-time.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/arm/iop3xx-mtd-map-fix.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/arm/n2100-eth1-irq.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/arm/n2100-serial-irq.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/copy-user-highpage-2.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/copy-user-highpage.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/fdomain-pci-id-table.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/ia64/
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/dec-scsi.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/dec-serial.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/header-exports.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/ip22-zilog-console.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-duart-tts.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-interrupt-handler.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sgi-ioc3.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/signal-handling.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/smp-cpu-bringup.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/syscall-wiring.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/mips/wait-race.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/net-netpoll.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/
people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/build-links.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/mv643xx-hotplug-support.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/oldworld-boot-fix.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/prep-utah-ide-interrupt.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/serial.patch
people/maks-guest/linux-2.6/debian/patches/bugfix/sparc/
people/maks-guest/linux-2.6/debian/patches/debian/
people/maks-guest/linux-2.6/debian/patches/debian/doc-build-parallel.patch
people/maks-guest/linux-2.6/debian/patches/debian/kernelvariables.patch
people/maks-guest/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch
people/maks-guest/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-ppc.patch
people/maks-guest/linux-2.6/debian/patches/debian/scripts-kconfig-reportoldconfig.patch
people/maks-guest/linux-2.6/debian/patches/debian/version.patch
people/maks-guest/linux-2.6/debian/patches/debian/vserver-version.patch
people/maks-guest/linux-2.6/debian/patches/fbdev-radeon-noaccel.patch
people/maks-guest/linux-2.6/debian/patches/features/
people/maks-guest/linux-2.6/debian/patches/features/all/
people/maks-guest/linux-2.6/debian/patches/features/all/drivers/
people/maks-guest/linux-2.6/debian/patches/features/all/fs-asfs.patch
people/maks-guest/linux-2.6/debian/patches/features/all/vserver/
people/maks-guest/linux-2.6/debian/patches/features/all/vserver/bindmount-dev.patch
people/maks-guest/linux-2.6/debian/patches/features/all/vserver/gen-patch (contents, props changed)
people/maks-guest/linux-2.6/debian/patches/features/all/xen/
people/maks-guest/linux-2.6/debian/patches/features/all/xen/fedora-36252.patch
people/maks-guest/linux-2.6/debian/patches/features/all/xen/gen-patch-vserver-update (contents, props changed)
people/maks-guest/linux-2.6/debian/patches/features/all/xen/vserver-clash.patch
people/maks-guest/linux-2.6/debian/patches/features/all/xen/vserver-update.patch
people/maks-guest/linux-2.6/debian/patches/features/alpha/
people/maks-guest/linux-2.6/debian/patches/features/alpha/titan-video.patch
people/maks-guest/linux-2.6/debian/patches/features/arm/
people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-0.2.1-driver.patch
people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-net-driver-fix-qmgr.patch
people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-net-driver-improve-mac-handling.patch
people/maks-guest/linux-2.6/debian/patches/features/arm/nslu2-eth-mac.patch
people/maks-guest/linux-2.6/debian/patches/features/arm/nslu2-setup-mac.patch
people/maks-guest/linux-2.6/debian/patches/features/fintek-f75375.patch
people/maks-guest/linux-2.6/debian/patches/features/mips/
people/maks-guest/linux-2.6/debian/patches/features/mips/backtrace.patch
people/maks-guest/linux-2.6/debian/patches/features/mips/qemu-kernel.patch
people/maks-guest/linux-2.6/debian/patches/features/net-forcedeth-swsusp.patch
people/maks-guest/linux-2.6/debian/patches/features/s390/
people/maks-guest/linux-2.6/debian/patches/features/s390/drivers-ccw-uevent-cleanup.patch
people/maks-guest/linux-2.6/debian/patches/features/s390/drivers-ccw-uevent-modalias.patch
people/maks-guest/linux-2.6/debian/patches/hppa-fix-cross-compile.patch
people/maks-guest/linux-2.6/debian/patches/hppa.patch
people/maks-guest/linux-2.6/debian/patches/ia64-irq-affinity-upfix.patch
people/maks-guest/linux-2.6/debian/patches/m68k-2.6.18.patch
people/maks-guest/linux-2.6/debian/patches/m68k-as.patch
people/maks-guest/linux-2.6/debian/patches/m68k-fbcon.patch
people/maks-guest/linux-2.6/debian/patches/m68k-macro.patch
people/maks-guest/linux-2.6/debian/patches/m68k-no-backlight.patch
people/maks-guest/linux-2.6/debian/patches/mips-arch-makefile.patch
people/maks-guest/linux-2.6/debian/patches/mips-ide-scan.patch
people/maks-guest/linux-2.6/debian/patches/mips-sb1-duart-tts.patch
people/maks-guest/linux-2.6/debian/patches/mips-sb1-duart.patch
people/maks-guest/linux-2.6/debian/patches/mips-sb1-eth-napi.patch
people/maks-guest/linux-2.6/debian/patches/mips-tulip.patch
people/maks-guest/linux-2.6/debian/patches/mips-tulip_dc21143.patch
people/maks-guest/linux-2.6/debian/patches/modular-ide-pnp.patch
people/maks-guest/linux-2.6/debian/patches/series/
people/maks-guest/linux-2.6/debian/patches/series/1
people/maks-guest/linux-2.6/debian/patches/series/1-extra
people/maks-guest/linux-2.6/debian/patches/sparc64-atyfb-xl-gr.patch
people/maks-guest/linux-2.6/debian/patches/sparc64-hme-lockup.patch
people/maks-guest/linux-2.6/debian/patches/video-vino-64-bit-fix-kernel.diff
people/maks-guest/linux-2.6/debian/rules (contents, props changed)
people/maks-guest/linux-2.6/debian/rules.defs
people/maks-guest/linux-2.6/debian/rules.gen
people/maks-guest/linux-2.6/debian/rules.real
people/maks-guest/linux-2.6/debian/templates/
people/maks-guest/linux-2.6/debian/templates/control.headers.arch.in
people/maks-guest/linux-2.6/debian/templates/control.headers.in
people/maks-guest/linux-2.6/debian/templates/control.headers.subarch.in
people/maks-guest/linux-2.6/debian/templates/control.image.type-modulesextra.in
people/maks-guest/linux-2.6/debian/templates/control.image.type-modulesinline.in
people/maks-guest/linux-2.6/debian/templates/control.image.type-standalone.in
people/maks-guest/linux-2.6/debian/templates/control.main.in
people/maks-guest/linux-2.6/debian/templates/control.source.in
people/maks-guest/linux-2.6/debian/templates/control.support.in
people/maks-guest/linux-2.6/debian/templates/control.tree.in
people/maks-guest/linux-2.6/debian/templates/control.xen-linux-system.in
people/maks-guest/linux-2.6/debian/templates/image.xen.postinst.in
people/maks-guest/linux-2.6/debian/templates/image.xen.postrm.in
people/maks-guest/linux-2.6/debian/templates/image.xen.prerm.in
people/maks-guest/linux-2.6/debian/templates/patch.apply.in
people/maks-guest/linux-2.6/debian/templates/patch.unpatch.in
Log:
sweet 2.6.19-rc5
usuall arch fall-out
Added: people/maks-guest/linux-2.6/debian/README
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/README Sat Nov 11 02:48:00 2006
@@ -0,0 +1,73 @@
+Migrating to the common kernel-image package
+--------------------------------------------
+Files for architecture <arch> should be placed into arch/<arch>. This
+directory normally contains a common config file for this architecture
+('config'), flavour-specific config files, Makefile.inc file,
+controlling the build for this arch, and the defines file, containing
+the machine descriptions for various flavours. For arches with
+subarches the subdirectory arch/<arch>/<subarch> with the same file
+structure must be created for each subarch.
+
+Kernel config files
+-------------------
+Configuration files are constructed dynamically by concatenating a number
+of config files as described below.
+
+For architecture without subarches:
+
+ arch/config
+ arch/<arch>/config
+ arch/<arch>/config.<flavour>
+
+For architecture with subarches:
+
+ arch/config
+ arch/<arch>/config
+ arch/<arch>/<subarch>/config
+ arch/<arch>/<subarch>/config.<flavour>
+
+Control file
+------------
+The master control file debian/control must be generated before
+the package is uploaded. debian/rules contains the debian/control
+target, which generates the control file by invoking the
+debian/bin/gencontrol.py script, which combines the templates from
+the templates directory and arch/subarch specific defines file to
+produce the debian/control file. Note that this target is intentionally
+made to fail with a non-zero exit code to make sure that it is never
+run during an automatic build. The following variables are substituted
+into the templates:
+
+ at version@ Upstream kernel version, for example 2.6.11.
+ at major@ The major version, for example 2.6
+ at arch@ The Debian arch name, such as powerpc or i386.
+ at subarch@ The subarch - only used by powerpc right now.
+ at flavour@ The build flavour, such as 686 or k7-smp.
+ at class@ The CPU/architecture class; displayed in synopsis. It should
+ be fairly short, as the synopsis is supposed to be <80 chars.
+ It should be in the form "foo class", and will show up in the
+ description as "foo class machines".
+ at longclass@ The CPU/architecture class; displayed in the extended
+ description. The same rules apply as in @class at . If
+ this is unset, it will default to @class at .
+ at desc@ (Potentially) multi-line verbiage that's appended to
+ -image descriptions.
+ at abiname@ Current abiname, a single digit.
+
+Normally, the arch-specific contents should be controlled by
+adjusting the corresponding defines file.
+
+Makefile.inc
+------------
+Each architecture subdirectory in arch may contain a Makefile.inc
+file, which is included by debian/rules after definining all the
+variables. It may be used to override the standard variables on
+per-architecture basis and other evil things. So far the valid uses of
+this file include the setting of the following variables:
+
+image_postproc
+
+ A command to be run after the kernel image is built. As far as I know,
+ it only required on sparc for stripping of the kernel which is too big
+ to be booted otherwise. Typical use is too ugly to be presented here.
+
Added: people/maks-guest/linux-2.6/debian/README.Debian
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/README.Debian Sat Nov 11 02:48:00 2006
@@ -0,0 +1,52 @@
+linux-2.6 for DEBIAN
+------------------------
+
+Patches
+-------
+Debian applies small changes to the kernel source. These are split up into
+separated patches addressing individual problems. Each of the patch files
+contains a description and mentions the author. The patches can be found
+at http://svn.debian.org/wsvn/kernel/dists/trunk/linux-2.6/debian/patches/.
+
+Config Files
+------------
+The .config files used to build the various linux-image files are dynamically
+generated during the linux-2.6 package build. See the source package for
+details. Each linux-image-* package provides the complete .config file that
+was used to generate it. This file is installed in /boot.
+
+Rebuilding Adaptec AIC7xxx/79xx firmware
+----------------------------------------
+You can rebuild the firmware for the Adaptec AIC7xxx/79xx SCSI Adapters. To
+do so you need to set AIC7XXX_BUILD_FIRMWARE/AIC79XX_BUILD_FIRMWARE config
+options. Note that this requires to have the development packages for
+berkelydb (libdb4.2-dev) installed.
+
+PS/2 Mice
+---------
+If your PS/2 mouse does not work, make sure that the modules psmouse and
+mousedev are loaded.
+
+mem= on 2.4.19 and later
+------------------------
+mem=xxxM can no longer be used to enlarge the RAM that the kernel uses.
+You must specify the exact memory map. For example, Compaq Proliant users
+can specify mem=48M at 16M if they have 64M of memory.
+
+Non-free bits removed
+---------------------
+* Keyspan firmware, driver disabled
+ . drivers/usb/serial/ksyspan_{mpr,usa*}_fw.h
+* Emagic EMI 2|6 usb audio interface firmware loader
+ . drivers/usb/misc/emi62_fw_*.h
+
+Firmware removed
+----------------
+* SMC Token Ring firmware, driver disabled:
+ . drivers/net/tokenring/smctr_firmware.h
+* ACENIC firwmare, driver disabled:
+ . drivers/net/acenic_firmware.h
+* DGRS firmware, driver disabled:
+ . drivers/net/dgrs_firmware.c
+* DAB firmware, driver disabled:
+ . drivers/usb/media/dabfirmware.h
Added: people/maks-guest/linux-2.6/debian/README.build
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/README.build Sat Nov 11 02:48:00 2006
@@ -0,0 +1,23 @@
+Building kernels from SVN (for official images):
+
+1) Start by downloading a kernel tarball from kernel.org (ie,
+linux-2.6.12.tar.bz2).
+2) Run trunk/scripts/prune-non-free <tarball> <version>. This will produce two
+additional tarballs; linux-kernel-<version>.orig.tar.gz and
+linux-kernel-nonfree-<version>.orig.tar.gz. Ignore the nonfree tarball
+for now.
+3) Unpack linux-kernel-<version>.orig.tar.gz, cd into the new directory,
+and do a 'svn export' to get the debian/ subdirectory.
+4) Build debian/control by running 'debian/rules debian/control'.
+5) .configs will be generated during build; to modify them, run
+trunk/scripts/split-config <arch dir> <flavour>. After modifying config
+options, you will be prompted for whether you want to change the config
+options globally (across *all* architectures), for the particular arch
+that you're working on, for the particular sub-arch you're working on,
+or just for that particular flavour.
+6) split-config sometimes create duplicates that are treated wrongly.
+Run trunk/scripts/split-config <arch dir> <flavour> if you made changes
+to your local subarch only.
+Run trunk/scripts/split-config -f <arch dir> <flavour> if you made
+changes either globally generally for your arch (and make sure you agree
+with others if doing so and comitting your changes to SVN).
Added: people/maks-guest/linux-2.6/debian/arch/_vserver/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/_vserver/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+CONFIG_VSERVER_LEGACY=y
+# CONFIG_VSERVER_LEGACY_VERSION is not set
+CONFIG_VSERVER_NGNET=y
+# CONFIG_VSERVER_REMAP_SADDR is not set
+CONFIG_VSERVER_PROC_SECURE=y
+# CONFIG_INOXID_NONE is not set
+# CONFIG_INOXID_UID16 is not set
+# CONFIG_INOXID_GID16 is not set
+CONFIG_INOXID_UGID24=y
+# CONFIG_INOXID_INTERN is not set
+# CONFIG_INOXID_RUNTIME is not set
+# CONFIG_XID_TAG_NFSD is not set
+# CONFIG_VSERVER_DEBUG is not set
+CONFIG_VSERVER_HARDCPU=y
+CONFIG_VSERVER_HARDCPU_IDLE=y
Added: people/maks-guest/linux-2.6/debian/arch/_xen/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/_xen/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,23 @@
+CONFIG_XEN_PCIDEV_FRONTEND=y
+# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
+CONFIG_XEN_PRIVILEGED_GUEST=y
+CONFIG_XEN_BACKEND=y
+CONFIG_XEN_BLKDEV_BACKEND=y
+# CONFIG_XEN_BLKDEV_TAP is not set
+# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
+CONFIG_XEN_NETDEV_BACKEND=y
+# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
+CONFIG_XEN_NETDEV_LOOPBACK=m
+CONFIG_XEN_PCIDEV_BACKEND=y
+CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
+# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
+# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
+# XEN_PCIDEV_BE_DEBUG is not set
+# CONFIG_XEN_TPMDEV_BACKEND is not set
+CONFIG_XEN_BLKDEV_FRONTEND=y
+CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_SCRUB_PAGES=y
+CONFIG_XEN_DISABLE_SERIAL=y
+CONFIG_XEN_SYSFS=y
+CONFIG_XEN_COMPAT_030002_AND_LATER=y
+# CONFIG_XEN_COMPAT_LATEST_ONLY is not set
Added: people/maks-guest/linux-2.6/debian/arch/alpha/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/alpha/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1625 @@
+CONFIG_ALPHA=y
+CONFIG_64BIT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_GENERIC_IOMAP is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_ALPHA_GENERIC=y
+# CONFIG_ALPHA_ALCOR is not set
+# CONFIG_ALPHA_XL is not set
+# CONFIG_ALPHA_BOOK1 is not set
+# CONFIG_ALPHA_AVANTI_CH is not set
+# CONFIG_ALPHA_CABRIOLET is not set
+# CONFIG_ALPHA_DP264 is not set
+# CONFIG_ALPHA_EB164 is not set
+# CONFIG_ALPHA_EB64P_CH is not set
+# CONFIG_ALPHA_EB66 is not set
+# CONFIG_ALPHA_EB66P is not set
+# CONFIG_ALPHA_EIGER is not set
+# CONFIG_ALPHA_JENSEN is not set
+# CONFIG_ALPHA_LX164 is not set
+# CONFIG_ALPHA_LYNX is not set
+# CONFIG_ALPHA_MARVEL is not set
+# CONFIG_ALPHA_MIATA is not set
+# CONFIG_ALPHA_MIKASA is not set
+# CONFIG_ALPHA_NAUTILUS is not set
+# CONFIG_ALPHA_NONAME_CH is not set
+# CONFIG_ALPHA_NORITAKE is not set
+# CONFIG_ALPHA_PC164 is not set
+# CONFIG_ALPHA_P2K is not set
+# CONFIG_ALPHA_RAWHIDE is not set
+# CONFIG_ALPHA_RUFFIAN is not set
+# CONFIG_ALPHA_RX164 is not set
+# CONFIG_ALPHA_SX164 is not set
+# CONFIG_ALPHA_SABLE is not set
+# CONFIG_ALPHA_SHARK is not set
+# CONFIG_ALPHA_TAKARA is not set
+# CONFIG_ALPHA_TITAN is not set
+# CONFIG_ALPHA_WILDFIRE is not set
+CONFIG_ISA=y
+CONFIG_ISA_DMA_API=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_ALPHA_CORE_AGP=y
+CONFIG_ALPHA_BROKEN_IRQ_MASK=y
+CONFIG_EISA=y
+# CONFIG_DISCONTIGMEM is not set
+# CONFIG_VERBOSE_MCHECK is not set
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_EISA_PCI_EISA=y
+CONFIG_EISA_VIRTUAL_ROOT=y
+CONFIG_EISA_NAMES=y
+CONFIG_PCCARD=m
+CONFIG_PCMCIA_DEBUG=y
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+CONFIG_YENTA=m
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+CONFIG_TCIC=m
+CONFIG_PCCARD_NONSTATIC=m
+CONFIG_SRM_ENV=m
+CONFIG_BINFMT_AOUT=m
+CONFIG_OSF4_COMPAT=y
+CONFIG_BINFMT_EM86=m
+CONFIG_STANDALONE=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_MAP_BANK_WIDTH_8=y
+CONFIG_MTD_MAP_BANK_WIDTH_16=y
+CONFIG_MTD_MAP_BANK_WIDTH_32=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_I4=y
+CONFIG_MTD_CFI_I8=y
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PCI=m
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLKMTD=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_DOC2000=m
+CONFIG_MTD_DOC2001=m
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+CONFIG_MTD_DOCPROBE_ADVANCED=y
+CONFIG_MTD_DOCPROBE_ADDRESS=0x0000
+CONFIG_MTD_DOCPROBE_HIGH=y
+CONFIG_MTD_DOCPROBE_55AA=y
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_NANDSIM=y
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+CONFIG_ISAPNP=y
+CONFIG_BLK_DEV_FD=m
+CONFIG_BLK_DEV_XD=m
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPATC8=y
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+CONFIG_CDROM_PKTCDVD_WCACHE=y
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=m
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5520=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+CONFIG_HPT34X_AUTODMA=y
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+CONFIG_PDC202XX_BURST=y
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_PDC202XX_FORCE=y
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_IDE_ARM is not set
+CONFIG_IDE_CHIPSETS=y
+CONFIG_BLK_DEV_4DRIVES=y
+CONFIG_BLK_DEV_ALI14XX=m
+CONFIG_BLK_DEV_DTC2278=m
+CONFIG_BLK_DEV_HT6560B=m
+CONFIG_BLK_DEV_QD65XX=m
+CONFIG_BLK_DEV_UMC8672=m
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+CONFIG_SCSI_IN2000=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_BUSLOGIC=m
+CONFIG_SCSI_OMIT_FLASHPOINT=y
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_DTC3280=m
+CONFIG_SCSI_EATA=m
+CONFIG_SCSI_EATA_TAGGED_QUEUE=y
+CONFIG_SCSI_EATA_LINKED_COMMANDS=y
+CONFIG_SCSI_EATA_MAX_TAGS=16
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+CONFIG_SCSI_GENERIC_NCR5380=m
+CONFIG_SCSI_GENERIC_NCR5380_MMIO=m
+CONFIG_SCSI_GENERIC_NCR53C400=y
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+CONFIG_SCSI_IZIP_EPP16=y
+CONFIG_SCSI_IZIP_SLOW_CTR=y
+CONFIG_SCSI_NCR53C406A=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_IOMAPPED=y
+CONFIG_SCSI_IPR=m
+CONFIG_SCSI_IPR_TRACE=y
+CONFIG_SCSI_IPR_DUMP=y
+CONFIG_SCSI_PAS16=m
+CONFIG_SCSI_PSI240I=m
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_FC=m
+CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLOGIC_1280_1040=y
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_SIM710=m
+CONFIG_53C700_IO_MAPPED=y
+CONFIG_SCSI_SYM53C416=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_T128=m
+CONFIG_SCSI_U14_34F=m
+CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y
+CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y
+CONFIG_SCSI_U14_34F_MAX_TAGS=8
+CONFIG_SCSI_DEBUG=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+CONFIG_CD_NO_IDESCSI=y
+CONFIG_AZTCD=m
+CONFIG_GSCD=m
+CONFIG_MCDX=m
+CONFIG_OPTCD=m
+CONFIG_SJCD=m
+CONFIG_ISP16_CDI=m
+CONFIG_CDU535=m
+CONFIG_DM_MULTIPATH_EMC=m
+CONFIG_FUSION_LAN=m
+CONFIG_IEEE1394=m
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_IEEE1394_PCILYNX=m
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+CONFIG_BRIDGE_NETFILTER=y
+CONFIG_DECNET_NF_GRABULATOR=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+CONFIG_ATM=y
+CONFIG_ATM_CLIP=y
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=y
+CONFIG_LLC2=m
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+# CONFIG_NET_DIVERT is not set
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+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=m
+CONFIG_NET_SCH_ATM=m
+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_EMATCH is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_BPQETHER=m
+CONFIG_SCC=m
+# CONFIG_SCC_DELAY is not set
+# CONFIG_SCC_TRXECHO is not set
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_YAM=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+CONFIG_IRTTY_SIR=m
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+CONFIG_WINBOND_FIR=m
+CONFIG_SMC_IRCC_FIR=m
+CONFIG_ALI_FIR=m
+CONFIG_VLSI_FIR=m
+CONFIG_VIA_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_BCSP_TXCRC is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_DUMMY=m
+CONFIG_NET_SB1000=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+CONFIG_ARCNET_COM90xx=m
+CONFIG_ARCNET_COM90xxIO=m
+CONFIG_ARCNET_RIM_I=m
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_ISA=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_ULTRA32=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+CONFIG_NI52=m
+CONFIG_NI65=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+CONFIG_AT1700=m
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+CONFIG_NET_ISA=y
+CONFIG_E2100=m
+CONFIG_EWRK3=m
+CONFIG_EEXPRESS=m
+CONFIG_EEXPRESS_PRO=m
+CONFIG_HPLAN_PLUS=m
+CONFIG_HPLAN=m
+CONFIG_LP486E=m
+CONFIG_ETH16I=m
+CONFIG_NE2000=m
+CONFIG_ZNET=m
+CONFIG_SEEQ8005=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_LNE390=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_NE3210=m
+CONFIG_ES3210=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_TUNE_TWISTER=y
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_DE600=m
+CONFIG_DE620=m
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_R8169_VLAN=y
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+CONFIG_IXGB=m
+CONFIG_S2IO=m
+CONFIG_2BUFF_MODE=y
+CONFIG_TR=y
+CONFIG_IBMTR=m
+CONFIG_IBMOL=m
+CONFIG_3C359=m
+CONFIG_TMS380TR=m
+CONFIG_TMSPCI=m
+CONFIG_SKISA=m
+CONFIG_PROTEON=m
+CONFIG_ABYSS=m
+CONFIG_NET_RADIO=y
+CONFIG_STRIP=m
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_ARCNET_COM20020_CS=m
+CONFIG_WAN=y
+CONFIG_HOSTESS_SV11=m
+CONFIG_COSA=m
+CONFIG_DSCC4=m
+CONFIG_DSCC4_PCISYNC=y
+CONFIG_DSCC4_PCI_RST=y
+CONFIG_LANMEDIA=m
+CONFIG_SEALEVEL_4021=m
+CONFIG_SYNCLINK_SYNCPPP=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW_ETH=y
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+CONFIG_HDLC_X25=y
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300=m
+CONFIG_PC300_MLPPP=y
+CONFIG_N2=m
+CONFIG_C101=m
+CONFIG_FARSYNC=m
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_SDLA=m
+CONFIG_WAN_ROUTER_DRIVERS=y
+CONFIG_CYCLADES_SYNC=m
+CONFIG_CYCLOMX_X25=y
+CONFIG_LAPBETHER=m
+CONFIG_X25_ASY=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+CONFIG_ATM_ZATM=m
+# CONFIG_ATM_ZATM_DEBUG is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+CONFIG_ATM_FORE200E_PCA=y
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y
+# CONFIG_ATM_FORE200E_USE_TASKLET is not set
+CONFIG_ATM_FORE200E_TX_RETRY=16
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+CONFIG_FDDI=y
+CONFIG_DEFXX=m
+CONFIG_SKFP=m
+CONFIG_HIPPI=y
+CONFIG_ROADRUNNER=m
+# CONFIG_ROADRUNNER_LARGE_RINGS is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_NET_FC=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+CONFIG_ISDN=m
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+CONFIG_ISDN_PPP_BSDCOMP=m
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+CONFIG_ISDN_X25=y
+CONFIG_ISDN_DIVERSION=m
+CONFIG_ISDN_DRV_HISAX=m
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+# CONFIG_HISAX_NO_SENDCOMPLETE is not set
+# CONFIG_HISAX_NO_LLC is not set
+# CONFIG_HISAX_NO_KEYPAD is not set
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_HFC4S8S=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_SC=m
+CONFIG_ISDN_DRV_ACT2000=m
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+CONFIG_CAPI_AVM=y
+CONFIG_ISDN_DRV_AVMB1_B1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_T1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
+CONFIG_PHONE_IXJ_PCMCIA=m
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_TSDEV=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_INPORT=m
+# CONFIG_MOUSE_ATIXL is not set
+CONFIG_MOUSE_LOGIBM=m
+CONFIG_MOUSE_PC110PAD=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461X=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_ROCKETPORT=m
+CONFIG_CYCLADES=m
+# CONFIG_CYZ_INTR is not set
+CONFIG_MOXA_SMARTIO=m
+CONFIG_ISI=m
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+CONFIG_SPECIALIX=m
+# CONFIG_SPECIALIX_RTSCTS is not set
+CONFIG_SX=m
+CONFIG_STALDRV=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_MULTIPORT=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_PCWATCHDOG=m
+CONFIG_MIXCOMWD=m
+CONFIG_WDT=m
+CONFIG_WDT_501=y
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+CONFIG_USBPCWATCHDOG=m
+CONFIG_RTC=m
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+CONFIG_APPLICOM=m
+CONFIG_AGP=m
+CONFIG_AGP_ALPHA_CORE=m
+CONFIG_AGP_SIS=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+CONFIG_SYNCLINK_CS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+# CONFIG_I2C_AMD756_S4882 is not set
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_PARPORT=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+CONFIG_SCx200_ACB=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_STUB=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+CONFIG_I2C_PCA_ISA=m
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_FSCPOS=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_DS1337=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_W1=m
+CONFIG_W1_MATROX=m
+CONFIG_W1_DS9490=m
+CONFIG_W1_DS9490_BRIDGE=m
+CONFIG_W1_THERM=m
+CONFIG_W1_SMEM=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_RADIO_MIROPCM20=m
+CONFIG_RADIO_MIROPCM20_RDS=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_SF16FMR2=m
+CONFIG_RADIO_TERRATEC=m
+CONFIG_RADIO_TRUST=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_DIBUSB=m
+# CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES is not set
+# CONFIG_DVB_DIBCOM_DEBUG is not set
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+CONFIG_DVB_B2C2_SKYSTAR=m
+CONFIG_DVB_BT8XX=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA80XX=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+CONFIG_DVB_NXT2002=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BUF_DVB=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_TGA=m
+CONFIG_FB_NVIDIA=m
+# CONFIG_FB_NVIDIA_I2C is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_RADEON_OLD=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+CONFIG_FB_3DFX_ACCEL=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_TRIDENT_ACCEL=y
+CONFIG_FB_S1D13XXX=m
+CONFIG_FB_VIRTUAL=m
+CONFIG_VGA_CONSOLE=y
+CONFIG_MDA_CONSOLE=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_GENERIC_PM=y
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL4_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_AD1848_LIB=m
+CONFIG_SND_CS4231_LIB=m
+CONFIG_SND_AD1816A=m
+CONFIG_SND_AD1848=m
+CONFIG_SND_CS4231=m
+CONFIG_SND_CS4232=m
+CONFIG_SND_CS4236=m
+CONFIG_SND_ES968=m
+CONFIG_SND_ES1688=m
+CONFIG_SND_ES18XX=m
+CONFIG_SND_GUS_SYNTH=m
+CONFIG_SND_GUSCLASSIC=m
+CONFIG_SND_GUSEXTREME=m
+CONFIG_SND_GUSMAX=m
+CONFIG_SND_INTERWAVE=m
+CONFIG_SND_INTERWAVE_STB=m
+CONFIG_SND_OPTI92X_AD1848=m
+CONFIG_SND_OPTI92X_CS4231=m
+CONFIG_SND_OPTI93X=m
+CONFIG_SND_SB8=m
+CONFIG_SND_SB16=m
+CONFIG_SND_SBAWE=m
+CONFIG_SND_SB16_CSP=y
+CONFIG_SND_WAVEFRONT=m
+CONFIG_SND_ALS100=m
+CONFIG_SND_AZT2320=m
+CONFIG_SND_CMI8330=m
+CONFIG_SND_DT019X=m
+CONFIG_SND_OPL3SA2=m
+CONFIG_SND_SGALAXY=m
+CONFIG_SND_SSCAPE=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_USX2Y=m
+CONFIG_SND_VXP440=m
+CONFIG_SOUND_PRIME=m
+CONFIG_SOUND_BT878=m
+CONFIG_SOUND_CMPCI=m
+CONFIG_SOUND_EMU10K1=m
+CONFIG_MIDI_EMU10K1=y
+CONFIG_SOUND_FUSION=m
+CONFIG_SOUND_CS4281=m
+CONFIG_SOUND_ES1370=m
+CONFIG_SOUND_ES1371=m
+CONFIG_SOUND_ESSSOLO1=m
+CONFIG_SOUND_MAESTRO=m
+CONFIG_SOUND_MAESTRO3=m
+CONFIG_SOUND_ICH=m
+CONFIG_SOUND_SONICVIBES=m
+CONFIG_SOUND_TRIDENT=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_VIA82CXXX=m
+CONFIG_MIDI_VIA82CXXX=y
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+CONFIG_SOUND_AD1816=m
+CONFIG_SOUND_AD1889=m
+CONFIG_SOUND_SGALAXY=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_ACI_MIXER=m
+CONFIG_SOUND_CS4232=m
+CONFIG_SOUND_SSCAPE=m
+CONFIG_SOUND_GUS=m
+CONFIG_SOUND_GUS16=y
+CONFIG_SOUND_GUSMAX=y
+CONFIG_SOUND_VMIDI=m
+CONFIG_SOUND_TRIX=m
+CONFIG_SOUND_MSS=m
+CONFIG_SOUND_MPU401=m
+CONFIG_SOUND_NM256=m
+CONFIG_SOUND_MAD16=m
+CONFIG_MAD16_OLDCARD=y
+CONFIG_SOUND_PAS=m
+CONFIG_SOUND_PSS=m
+CONFIG_PSS_MIXER=y
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_AWE32_SYNTH=m
+CONFIG_SOUND_WAVEFRONT=m
+CONFIG_SOUND_MAUI=m
+CONFIG_SOUND_YM3812=m
+CONFIG_SOUND_OPL3SA1=m
+CONFIG_SOUND_OPL3SA2=m
+CONFIG_SOUND_YMFPCI=m
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+CONFIG_SOUND_UART6850=m
+CONFIG_SOUND_AEDSP16=m
+CONFIG_SC6600=y
+CONFIG_SC6600_JOY=y
+CONFIG_SC6600_CDROM=4
+CONFIG_SC6600_CDROMBASE=0x0
+CONFIG_AEDSP16_MSS=y
+# CONFIG_AEDSP16_SBPRO is not set
+CONFIG_AEDSP16_MPU401=y
+CONFIG_SOUND_TVMIXER=m
+CONFIG_SOUND_KAHLUA=m
+CONFIG_SOUND_ALI5455=m
+CONFIG_SOUND_FORTE=m
+CONFIG_SOUND_RME96XX=m
+CONFIG_SOUND_AD1980=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_PWC=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+CONFIG_USB_AX8817X=y
+CONFIG_USB_ZD1201=m
+CONFIG_USB_USS720=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_NET2280=m
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_WBSD=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_EXT2_FS=y
+CONFIG_JBD=m
+CONFIG_FS_MBCACHE=y
+CONFIG_XFS_RT=y
+# CONFIG_TMPFS_XATTR is not set
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_ASFS_FS=m
+CONFIG_ASFS_DEFAULT_CODEPAGE=""
+# CONFIG_ASFS_RW is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_JFFS_FS=m
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_JFFS2_FS_NOR_ECC=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
+CONFIG_ACORN_PARTITION_ICS=y
+# CONFIG_ACORN_PARTITION_ADFS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+# 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_EARLY_PRINTK=y
+# CONFIG_DEBUG_RWLOCK is not set
+# CONFIG_DEBUG_SEMAPHORE is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=m
+# CONFIG_MTD_OTP is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_IPW2100 is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SENSORS_F71805F=m
+CONFIG_ESPSERIAL=m
+CONFIG_MOXA_INTELLIO=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_BLK_DEV_IDEPNP=y
+CONFIG_AGP_VIA=m
+CONFIG_SND_ADLIB=m
+CONFIG_SND_MIRO=m
+CONFIG_MTD_XIP=y
+CONFIG_SBPCD=m
+CONFIG_CM206=m
+CONFIG_CDU31A=m
+CONFIG_DMASCC=m
+CONFIG_IRPORT_SIR=m
+CONFIG_DONGLE_OLD=y
+CONFIG_ESI_DONGLE_OLD=m
+CONFIG_ACTISYS_DONGLE_OLD=m
+CONFIG_TEKRAM_DONGLE_OLD=m
+CONFIG_GIRBIL_DONGLE_OLD=m
+CONFIG_LITELINK_DONGLE_OLD=m
+CONFIG_MCP2120_DONGLE_OLD=m
+CONFIG_OLD_BELKIN_DONGLE_OLD=m
+CONFIG_ACT200L_DONGLE_OLD=m
+CONFIG_MA600_DONGLE_OLD=m
+CONFIG_NI5010=m
+CONFIG_PCMCIA_XIRTULIP=m
+CONFIG_ISDN_DRV_LOOP=m
+CONFIG_HYSDN=m
+CONFIG_HYSDN_CAPI=y
+CONFIG_COMPUTONE=m
+# CONFIG_DIGIEPCA is not set
+CONFIG_ESPSERIAL=m
+CONFIG_MOXA_INTELLIO=m
+CONFIG_RISCOM8=m
+# CONFIG_RIO is not set
+CONFIG_STALLION=m
+CONFIG_ISTALLION=m
+CONFIG_FTAPE=m
+CONFIG_ZFTAPE=m
+CONFIG_ZFT_DFLT_BLK_SZ=10240
+CONFIG_ZFT_COMPRESSOR=m
+CONFIG_FT_NR_BUFFERS=3
+CONFIG_FT_PROC_FS=y
+CONFIG_FT_NORMAL_DEBUG=y
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+CONFIG_FT_STD_FDC=y
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
+CONFIG_FT_FDC_THR=8
+CONFIG_FT_FDC_MAX_RATE=2000
+CONFIG_FT_ALPHA_CLOCK=0
+CONFIG_I2C_ELEKTOR=m
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_MATHEMU=m
+# CONFIG_AUDIT is not set
Added: people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-generic
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-generic Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_SMP is not set
+# CONFIG_ALPHA_LEGACY_START_ADDRESS is not set
Added: people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-legacy
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-legacy Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_SMP is not set
+CONFIG_ALPHA_LEGACY_START_ADDRESS=y
Added: people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-smp
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/config.alpha-smp Sat Nov 11 02:48:00 2006
@@ -0,0 +1,4 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
+# CONFIG_ALPHA_LEGACY_START_ADDRESS is not set
+CONFIG_SCSI=y
Added: people/maks-guest/linux-2.6/debian/arch/alpha/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,17 @@
+[base]
+flavours: alpha-generic alpha-smp alpha-legacy
+kernel-arch: alpha
+kernel-header-dirs: alpha
+subarches: vserver
+
+[image]
+suggests: aboot, fdutils
+
+[alpha-generic]
+class: Alpha
+
+[alpha-smp]
+class: Alpha SMP
+
+[alpha-legacy]
+class: Alpha Legacy
Added: people/maks-guest/linux-2.6/debian/arch/alpha/vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/alpha/vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,12 @@
+[base]
+flavours: alpha
+
+[image]
+configs: _vserver/config
+recommends: util-vserver
+
+[alpha]
+class: Alpha
+
+[alpha_image]
+configs: alpha/config.alpha-generic
Added: people/maks-guest/linux-2.6/debian/arch/amd64/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/amd64/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1443 @@
+CONFIG_X86_64=y
+CONFIG_64BIT=y
+CONFIG_X86=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_X86_TSC=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_MICROCODE=m
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_MTRR=y
+CONFIG_HPET_TIMER=y
+CONFIG_X86_PM_TIMER=y
+CONFIG_SWIOTLB=y
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_INTEL=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ISA_DMA_API=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+CONFIG_ACPI_AC=m
+CONFIG_ACPI_BATTERY=m
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_VIDEO=m
+CONFIG_ACPI_FAN=m
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_THERMAL=m
+CONFIG_ACPI_ASUS=m
+CONFIG_ACPI_IBM=m
+CONFIG_ACPI_TOSHIBA=m
+CONFIG_ACPI_BLACKLIST_YEAR=0
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_ACPI_CONTAINER=m
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=m
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_X86_POWERNOW_K8=m
+CONFIG_X86_POWERNOW_K8_ACPI=y
+CONFIG_X86_SPEEDSTEP_CENTRINO=m
+CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y
+CONFIG_X86_ACPI_CPUFREQ=m
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
+# CONFIG_X86_SPEEDSTEP_LIB is not set
+CONFIG_PCI=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=m
+# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+CONFIG_YENTA=m
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_TCIC=m
+CONFIG_PCCARD_NONSTATIC=m
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI_FAKE=m
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI_ACPI_IBM=m
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+CONFIG_HOTPLUG_PCI_SHPC=m
+# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
+CONFIG_IA32_EMULATION=y
+CONFIG_IA32_AOUT=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_UID16=y
+CONFIG_STANDALONE=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PNC2000=m
+CONFIG_MTD_SC520CDP=m
+CONFIG_MTD_NETSC520=m
+CONFIG_MTD_TS5500=m
+CONFIG_MTD_SBC_GXX=m
+# CONFIG_MTD_AMD76XROM is not set
+# CONFIG_MTD_ICHXROM is not set
+# CONFIG_MTD_SCB2_FLASH is not set
+CONFIG_MTD_NETtel=m
+CONFIG_MTD_DILNETPC=m
+CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000
+# CONFIG_MTD_L440GX is not set
+CONFIG_MTD_PCI=m
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_DOC2000=m
+CONFIG_MTD_DOC2001=m
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0
+# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_PNP=y
+CONFIG_PNP_DEBUG=y
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV_FD=m
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+# CONFIG_PARIDE_EPATC8 is not set
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_CMD640=y
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_RZ1000=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_ATIIXP=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5520=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+CONFIG_PDC202XX_BURST=y
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SIS5513=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_EATA=m
+CONFIG_SCSI_EATA_TAGGED_QUEUE=y
+CONFIG_SCSI_EATA_LINKED_COMMANDS=y
+CONFIG_SCSI_EATA_MAX_TAGS=16
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_QLOGIC_FC=m
+CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+CONFIG_DM_MULTIPATH_EMC=m
+CONFIG_FUSION_LAN=m
+CONFIG_IEEE1394=m
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_IEEE1394_PCILYNX=m
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+# CONFIG_IP_PNP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+CONFIG_ATM=y
+CONFIG_ATM_CLIP=y
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=y
+CONFIG_LLC2=m
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+# CONFIG_NET_DIVERT is not set
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+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=m
+CONFIG_NET_SCH_ATM=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_YAM=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+CONFIG_IRTTY_SIR=m
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+CONFIG_WINBOND_FIR=m
+CONFIG_SMC_IRCC_FIR=m
+CONFIG_ALI_FIR=m
+CONFIG_VLSI_FIR=m
+CONFIG_VIA_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_DUMMY=m
+CONFIG_NET_SB1000=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+CONFIG_ARCNET_COM90xx=m
+CONFIG_ARCNET_COM90xxIO=m
+CONFIG_ARCNET_RIM_I=m
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+CONFIG_HP100=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_TUNE_TWISTER=y
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+CONFIG_IXGB=m
+CONFIG_S2IO=m
+CONFIG_TR=y
+CONFIG_IBMOL=m
+CONFIG_3C359=m
+CONFIG_TMS380TR=m
+CONFIG_TMSPCI=m
+CONFIG_ABYSS=m
+CONFIG_NET_RADIO=y
+CONFIG_STRIP=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_ARCNET_COM20020_CS=m
+CONFIG_WAN=y
+CONFIG_DSCC4=m
+CONFIG_DSCC4_PCISYNC=y
+CONFIG_DSCC4_PCI_RST=y
+CONFIG_LANMEDIA=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW_ETH=y
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+CONFIG_HDLC_X25=y
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300=m
+CONFIG_PC300_MLPPP=y
+CONFIG_FARSYNC=m
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_WAN_ROUTER_DRIVERS=y
+CONFIG_CYCLADES_SYNC=m
+CONFIG_CYCLOMX_X25=y
+CONFIG_LAPBETHER=m
+CONFIG_X25_ASY=m
+CONFIG_SBNI=m
+# CONFIG_SBNI_MULTILINE is not set
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+CONFIG_ATM_ZATM=m
+# CONFIG_ATM_ZATM_DEBUG is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+CONFIG_ATM_FORE200E_PCA=y
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y
+# CONFIG_ATM_FORE200E_USE_TASKLET is not set
+CONFIG_ATM_FORE200E_TX_RETRY=16
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+CONFIG_FDDI=y
+CONFIG_DEFXX=m
+CONFIG_SKFP=m
+CONFIG_HIPPI=y
+CONFIG_ROADRUNNER=m
+# CONFIG_ROADRUNNER_LARGE_RINGS is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_NET_FC=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+CONFIG_ISDN=m
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+CONFIG_ISDN_PPP_BSDCOMP=m
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+CONFIG_ISDN_X25=y
+CONFIG_ISDN_DIVERSION=m
+CONFIG_ISDN_DRV_HISAX=m
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+# CONFIG_HISAX_NO_SENDCOMPLETE is not set
+# CONFIG_HISAX_NO_LLC is not set
+# CONFIG_HISAX_NO_KEYPAD is not set
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_HFC4S8S=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+CONFIG_CAPI_AVM=y
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
+CONFIG_PHONE_IXJ_PCMCIA=m
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_TSDEV=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_CT82C710=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_ROCKETPORT=m
+CONFIG_CYCLADES=m
+# CONFIG_CYZ_INTR is not set
+CONFIG_MOXA_SMARTIO=m
+CONFIG_ISI=m
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+CONFIG_SPECIALIX=m
+# CONFIG_SPECIALIX_RTSCTS is not set
+CONFIG_SX=m
+CONFIG_STALDRV=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_SC520_WDT=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_I8XX_TCO=m
+CONFIG_SC1200_WDT=m
+CONFIG_60XX_WDT=m
+CONFIG_CPU5_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_MACHZ_WDT=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+CONFIG_USBPCWATCHDOG=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+CONFIG_APPLICOM=m
+CONFIG_AGP=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I830=m
+CONFIG_DRM_I915=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+CONFIG_SYNCLINK_CS=m
+CONFIG_MWAVE=m
+CONFIG_RAW_DRIVER=m
+CONFIG_HPET=y
+# CONFIG_HPET_RTC_IRQ is not set
+CONFIG_HPET_MMAP=y
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_HANGCHECK_TIMER=m
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD756_S4882=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_PARPORT=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+CONFIG_SCx200_ACB=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_STUB=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+CONFIG_I2C_PCA_ISA=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_FSCPOS=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_DS1337=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_W1=m
+CONFIG_IBM_ASM=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+CONFIG_DVB_BT8XX=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BUF_DVB=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_FB=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=m
+CONFIG_FB_HGA=m
+# CONFIG_FB_HGA_ACCEL is not set
+CONFIG_FB_NVIDIA=m
+# CONFIG_FB_NVIDIA_I2C is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+# CONFIG_FB_GEODE is not set
+CONFIG_FB_S1D13XXX=m
+CONFIG_FB_VIRTUAL=m
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_USX2Y=m
+CONFIG_SOUND_PRIME=m
+CONFIG_SOUND_BT878=m
+CONFIG_SOUND_EMU10K1=m
+CONFIG_MIDI_EMU10K1=y
+CONFIG_SOUND_FUSION=m
+CONFIG_SOUND_ES1371=m
+CONFIG_SOUND_ICH=m
+CONFIG_SOUND_TRIDENT=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_VIA82CXXX=m
+CONFIG_MIDI_VIA82CXXX=y
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+CONFIG_SOUND_AD1816=m
+CONFIG_SOUND_AD1889=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_ACI_MIXER=m
+CONFIG_SOUND_CS4232=m
+CONFIG_SOUND_SSCAPE=m
+CONFIG_SOUND_VMIDI=m
+CONFIG_SOUND_TRIX=m
+CONFIG_SOUND_MSS=m
+CONFIG_SOUND_MPU401=m
+CONFIG_SOUND_NM256=m
+CONFIG_SOUND_PAS=m
+CONFIG_SOUND_PSS=m
+CONFIG_PSS_MIXER=y
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_YM3812=m
+CONFIG_SOUND_OPL3SA2=m
+CONFIG_SOUND_UART6850=m
+CONFIG_SOUND_AEDSP16=m
+CONFIG_SC6600=y
+CONFIG_SC6600_JOY=y
+CONFIG_SC6600_CDROM=4
+CONFIG_SC6600_CDROMBASE=0x0
+# CONFIG_AEDSP16_MSS is not set
+# CONFIG_AEDSP16_SBPRO is not set
+# CONFIG_AEDSP16_MPU401 is not set
+CONFIG_SOUND_TVMIXER=m
+CONFIG_SOUND_KAHLUA=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_PWC=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZD1201=m
+CONFIG_USB_USS720=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_NET2280=m
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_WBSD=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_EDD=m
+CONFIG_JBD=m
+CONFIG_XFS_RT=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_JFFS_FS=m
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
+CONFIG_ACORN_PARTITION_ICS=y
+# CONFIG_ACORN_PARTITION_ADFS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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_IOMMU_DEBUG is not set
+# CONFIG_KPROBES is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_REED_SOLOMON=m
+CONFIG_REED_SOLOMON_DEC16=y
+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+CONFIG_KEXEC=y
+CONFIG_CRYPTO_AES_X86_64=m
+CONFIG_ACPI_HOTKEY=m
+# CONFIG_ACPI_SLEEP_PROC_SLEEP is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_FB_VESA=y
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_ATP=m
+CONFIG_DE620=m
+# CONFIG_FRAME_POINTER is not set
+CONFIG_DE600=m
+CONFIG_DCDBAS=m
+CONFIG_SENSORS_HDAPS=m
+CONFIG_IBMASR=m
+CONFIG_SBC8360_WDT=m
+CONFIG_W83977F_WDT=m
+CONFIG_I6300ESB_WDT=m
+CONFIG_USB_SUSPEND=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PM_LEGACY=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_IPW2100 is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_X86_PC=y
+# CONFIG_X86_VSMP is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_COMPUTONE=m
+CONFIG_MOXA_INTELLIO=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_PCI_MSI=y
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_I82875P=m
+CONFIG_EDAC_AMD76X=m
+CONFIG_EDAC_E7XXX=m
+CONFIG_EDAC=m
+CONFIG_EDAC_MM_EDAC=m
+CONFIG_EDAC_POLL=y
+CONFIG_EDAC_I82860=m
+CONFIG_EDAC_E752X=m
+CONFIG_EDAC_R82600=m
+# CONFIG_ACPI_IBM_DOCK is not set
+CONFIG_REORDER=y
+CONFIG_AGP_VIA=m
+CONFIG_PHYSICAL_START=0x200000
+CONFIG_HOTPLUG_CPU=y
+CONFIG_X86_INTERNODE_CACHE_BYTES=128
+CONFIG_ACPI_HOTPLUG_MEMORY=m
+CONFIG_AGP_SIS=m
+CONFIG_RIO=m
+CONFIG_RIO_OLDPCI=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_X86_HT=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
+CONFIG_CALGARY_IOMMU=y
+CONFIG_K8_NB=y
+CONFIG_HW_RANDOM_GEODE=m
+CONFIG_INTEL_IOATDMA=m
+CONFIG_HW_RANDOM_AMD=m
+CONFIG_FB_INTEL=m
+CONFIG_RESOURCES_64BIT=y
+CONFIG_IOMMU=y
+CONFIG_HW_RANDOM_INTEL=m
+CONFIG_ACPI_SBS=m
+CONFIG_AUDIT_ARCH=y
+# CONFIG_ASFS_FS is not set
+CONFIG_SCSI_ARCMSR=m
Added: people/maks-guest/linux-2.6/debian/arch/amd64/config.amd64
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/config.amd64 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,34 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_SMP=y
+# CONFIG_NUMA_EMU is not set
+CONFIG_NUMA=y
+CONFIG_NR_CPUS=32
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_R8169_VLAN=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FS_MBCACHE=m
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_DIGIEPCA=m
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_ACPI_NUMA=y
+CONFIG_MIGRATION=y
+CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y
+CONFIG_SUSPEND_SMP=y
+CONFIG_ACPI_HOTPLUG_CPU=y
+CONFIG_NODES_SHIFT=6
+CONFIG_X86_L1_CACHE_BYTES=128
+CONFIG_X86_MCE_AMD=y
+CONFIG_X86_64_ACPI_NUMA=y
+CONFIG_K8_NUMA=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+# CONFIG_MPSC is not set
+# CONFIG_MK8 is not set
+CONFIG_GENERIC_CPU=y
Added: people/maks-guest/linux-2.6/debian/arch/amd64/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,19 @@
+[base]
+flavours:
+ amd64
+kernel-arch: x86_64
+kernel-header-dirs: x86_64 i386
+subarches:
+ vserver
+ xen
+ xen-vserver
+
+[image]
+conflicts: grub (<= 0.95+cvs20040624-17)
+depends: e2fsprogs (>= 1.35-7)
+suggests: grub (>= 0.97-3) | lilo (>= 19.1)
+
+[amd64]
+class: AMD64
+longclass: all 64bit single- and multiprocessor AMD and Intel
+
Added: people/maks-guest/linux-2.6/debian/arch/amd64/vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+[base]
+flavours:
+ amd64
+
+[image]
+configs: _vserver/config
+recommends: util-vserver
+
+[amd64_image]
+configs: amd64/config.amd64
+
Added: people/maks-guest/linux-2.6/debian/arch/amd64/xen-vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/xen-vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,19 @@
+[base]
+flavours:
+ amd64
+
+[image]
+configs:
+ _vserver/config
+ amd64/xen/config
+ _xen/config
+initramfs-generators: initramfs-tools
+suggests: grub (>= 0.97-16)
+type: plain-xen
+
+[xen]
+flavour: amd64
+
+[amd64_image]
+configs: amd64/config.amd64
+
Added: people/maks-guest/linux-2.6/debian/arch/amd64/xen/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/xen/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1 @@
+CONFIG_X86_64_XEN=y
Added: people/maks-guest/linux-2.6/debian/arch/amd64/xen/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/amd64/xen/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,16 @@
+[base]
+flavours:
+ amd64
+
+[image]
+configs: amd64/xen/config _xen/config
+initramfs-generators: initramfs-tools
+suggests: grub (>= 0.97-16)
+type: plain-xen
+
+[xen]
+flavour: amd64
+
+[amd64_image]
+configs: amd64/config.amd64
+
Added: people/maks-guest/linux-2.6/debian/arch/arm/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/arm/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,22 @@
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_SLIP_SMART=y
+CONFIG_SUNRPC_GSS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_XATTR=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_ECONET_AUNUDP=y
+CONFIG_RXRPC=m
+# CONFIG_CIFS_POSIX is not set
+CONFIG_ECONET_NATIVE=y
+CONFIG_EQUALIZER=m
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_IPW2100 is not set
+CONFIG_JBD=y
+# CONFIG_ARCH_REALVIEW is not set
+CONFIG_TMPFS=y
+# CONFIG_AEABI is not set
Added: people/maks-guest/linux-2.6/debian/arch/arm/config.footbridge
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config.footbridge Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1913 @@
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+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=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+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_EP93XX is not set
+CONFIG_ARCH_FOOTBRIDGE=y
+# 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_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# 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_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# Footbridge Implementations
+#
+CONFIG_ARCH_CATS=y
+CONFIG_ARCH_PERSONAL_SERVER=y
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+CONFIG_ARCH_EBSA285_HOST=y
+CONFIG_ARCH_NETWINDER=y
+CONFIG_FOOTBRIDGE=y
+CONFIG_FOOTBRIDGE_HOST=y
+CONFIG_ARCH_EBSA285=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_SA110=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
+
+#
+# Processor Features
+#
+
+#
+# Bus support
+#
+CONFIG_ISA=y
+CONFIG_ISA_DMA=y
+CONFIG_ISA_DMA_API=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# 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_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_NWFPE_XP=y
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+
+#
+# Networking options
+#
+# CONFIG_NET_KEY 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=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+CONFIG_ATM=y
+# CONFIG_ATM_CLIP is not set
+# CONFIG_ATM_LANE is not set
+# CONFIG_ATM_BR2684 is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+CONFIG_WINBOND_FIR=m
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_DC21285=y
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT_ARC is not set
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=y
+
+#
+# Parallel IDE high-level drivers
+#
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+# CONFIG_PARIDE_BPCK6 is not set
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+# CONFIG_PARIDE_EPATC8 is not set
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+# 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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_7000FASST=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_AIC79XX_ENABLE_RD_STRM=y
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_CTL=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_EL3 is not set
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_ULI526X=m
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA 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_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_CS89x0 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=m
+# 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
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# 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_SIS190=m
+CONFIG_SKGE=m
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_CHELSIO_T1=m
+# 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
+
+#
+# ATM drivers
+#
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_PPPOATM is not set
+CONFIG_SLIP=m
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# 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=m
+
+#
+# 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_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_21285=y
+CONFIG_SERIAL_21285_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=y
+CONFIG_21285_WATCHDOG=m
+CONFIG_977_WATCHDOG=m
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_DS1620=y
+CONFIG_NWBUTTON=y
+CONFIG_NWBUTTON_REBOOT=y
+CONFIG_NWFLASH=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+# 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=m
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+CONFIG_SENSORS_DS1374=m
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+CONFIG_SENSORS_PCA9539=m
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_SENSORS_MAX6875=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+CONFIG_SENSORS_ADM9240=m
+# CONFIG_SENSORS_ASB100 is not set
+CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+CONFIG_SENSORS_W83792D=m
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+CONFIG_SENSORS_W83627EHF=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX 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_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_PM2=m
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_VIDEO_SELECT=y
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=m
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SIS=m
+CONFIG_FB_NEOMAGIC=m
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+CONFIG_FB_CYBLA=m
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_RTCTIMER=m
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ISA devices
+#
+# CONFIG_SND_ADLIB is not set
+CONFIG_SND_CS4231_LIB=m
+# CONFIG_SND_AD1816A is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_ALS100 is not set
+# CONFIG_SND_AZT2320 is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4232 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_DT019X is not set
+# CONFIG_SND_ES968 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+CONFIG_SND_OPL3SA2=m
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_SGALAXY is not set
+# CONFIG_SND_SSCAPE is not set
+# CONFIG_SND_WAVEFRONT is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA ARM devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+CONFIG_OBSOLETE_OSS_DRIVER=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+CONFIG_SOUND_YM3812=m
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+CONFIG_SOUND_WAVEARTIST=m
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+CONFIG_USB_ACECAD=m
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+CONFIG_USB_ITMTOUCH=m
+# CONFIG_USB_EGALAX is not set
+CONFIG_USB_YEALINK=m
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_KEYSPAN_REMOTE=m
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_PWC is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI26=m
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+CONFIG_USB_LD=m
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+# CONFIG_USB_ATM 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_EXT3_FS=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=y
+# 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_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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
+CONFIG_9P_FS=m
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
+# CONFIG_ACORN_PARTITION_ICS is not set
+CONFIG_ACORN_PARTITION_ADFS=y
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+# CONFIG_ACORN_PARTITION_RISCIX 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+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_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_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO_DES=y
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_ATM_MPOA=m
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_SYNCLINK_CS is not set
+CONFIG_PCMCIA_WL3501=m
+CONFIG_BT_HIDP=m
+# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_I82365=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_PCCARD_NONSTATIC=m
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_SCSI_ADVANSYS is not set
+CONFIG_USB_SPEEDTOUCH=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_PCMCIA_3C574=m
+CONFIG_PRISM54=m
+# CONFIG_BLK_DEV_SLC90E66 is not set
+CONFIG_BLK_DEV_AEC62XX=m
+# CONFIG_FB_PM3 is not set
+CONFIG_AIRO_CS=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_PD6729=m
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_VIDEO_ZR36120 is not set
+CONFIG_IEEE1394_ETH1394=m
+# CONFIG_INFTL is not set
+CONFIG_WAVELAN=m
+# CONFIG_PCMCIA_SYM53C500 is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_TCIC=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_NCPFS_NFS_NS is not set
+CONFIG_PCMCIA_AXNET=m
+CONFIG_IEEE1394_PCILYNX=m
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_NET_PCMCIA=y
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_PCMCIA_AHA152X is not set
+CONFIG_TMD_HERMES=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_LOGO_LINUX_VGA16=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BT_HCIUART=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_PDC202XX_FORCE is not set
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_PCI_HERMES=m
+CONFIG_CARDBUS=y
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_NFTL is not set
+CONFIG_IEEE1394_OHCI1394=m
+# CONFIG_NCPFS_NLS is not set
+CONFIG_LLC=m
+CONFIG_BLK_DEV_CMD64X=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_PLX_HERMES=m
+CONFIG_STRIP=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_BNEP_MC_FILTER=y
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_BT_L2CAP=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_BT_BNEP=m
+CONFIG_PCMCIA_XIRTULIP=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_NETWAVE=m
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BLK_DEV_CS5520=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_PCMCIA_FMVJ18X=m
+# CONFIG_SMP is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_LOGO_LINUX_MONO=y
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+CONFIG_BLK_DEV_CS5530=m
+# CONFIG_FTL is not set
+CONFIG_I82092=m
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_YENTA=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_AIRO=m
+CONFIG_BLK_DEV_TRM290=m
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_USB_SL811_CS is not set
+CONFIG_HERMES=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_PCMCIA_FDOMAIN is not set
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BT_HCIBCM203X=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_BT_HCIDTL1=m
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_BT_HCIUSB=m
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_ATMEL=m
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BLK_DEV_UMC8672 is not set
+CONFIG_BT_HCIBTUART=m
+CONFIG_PCMCIA=m
+CONFIG_BROKEN=y
+CONFIG_ARLAN=m
+# CONFIG_BLK_DEV_QD65XX is not set
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_FS_MBCACHE=y
+CONFIG_NET_WIRELESS=y
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_PCI_ATMEL=m
+CONFIG_BT_HCIBT3C=m
+# CONFIG_IPX_INTERN is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BLK_DEV_HPT34X=m
+CONFIG_BT_SCO=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_BLK_DEV_SC1200=m
+# CONFIG_R8169_VLAN is not set
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_IEEE1394_AMDTP is not set
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_LANCE is not set
+CONFIG_VIDEO_TVEEPROM=m
+# CONFIG_USB_AUDIO is not set
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TUNER=m
+# CONFIG_MEGARAID_MM is not set
+CONFIG_VIDEO_BUF=m
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+# CONFIG_FB_NVIDIA_I2C is not set
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+CONFIG_FB_VOODOO1=m
+# CONFIG_MTD_BLOCK2MTD is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_ONENAND_GENERIC is not set
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PMC551 is not set
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+# CONFIG_JFFS_PROC_FS is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS_FS=m
+# CONFIG_VIDEO_SAA7134_ALSA is not set
+# CONFIG_VIDEO_SAA7134_OSS is not set
Added: people/maks-guest/linux-2.6/debian/arch/arm/config.iop32x
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config.iop32x Sat Nov 11 02:48:00 2006
@@ -0,0 +1,2025 @@
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# 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_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_IOP3XX=y
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# 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_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# IOP3xx Implementation Options
+#
+
+#
+# IOP3xx Platform Types
+#
+# CONFIG_ARCH_IQ80321 is not set
+CONFIG_MACH_N2100=y
+CONFIG_MACH_GLANTANK=y
+CONFIG_ARCH_IQ31244=y
+# CONFIG_ARCH_IQ80331 is not set
+# CONFIG_MACH_IQ80332 is not set
+CONFIG_ARCH_EP80219=y
+CONFIG_ARCH_IOP321=y
+# CONFIG_ARCH_IOP331 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+CONFIG_PCI=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_AEABI 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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+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=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CONNTRACK_NETLINK is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_H323 is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# DECnet: Netfilter Configuration
+#
+# CONFIG_DECNET_NF_GRABULATOR is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=y
+CONFIG_LLC2=y
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# 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
+
+#
+# Queueing/Scheduling
+#
+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
+
+#
+# Classification
+#
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_IEEE80211_SOFTMAC is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=m
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IOP3XX=y
+# CONFIG_MTD_PCI is not set
+CONFIG_MTD_PLATRAM=m
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDESCSI=m
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_OFFBOARD=y
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_SL82C105=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5520=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+CONFIG_HPT34X_AUTODMA=y
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_IT821X=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+CONFIG_PDC202XX_BURST=y
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_CTL=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI 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
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_E1000_NAPI=y
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=m
+CONFIG_R8169_NAPI=y
+CONFIG_R8169_VLAN=y
+CONFIG_SIS190=m
+CONFIG_SKGE=m
+# CONFIG_SKY2 is not set
+CONFIG_SK98LIN=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+
+#
+# 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=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+CONFIG_STRIP=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+# CONFIG_IPW2100_MONITOR is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW_QOS is not set
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+# CONFIG_PCI_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+# CONFIG_HOSTAP_FIRMWARE is not set
+CONFIG_HOSTAP_PLX=m
+# CONFIG_HOSTAP_PCI 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=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER 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=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT 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=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED 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
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_NVRAM 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_IOP3XX=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_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
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_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
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F is not set
+CONFIG_SENSORS_F75375S=y
+# 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L1=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_VIVI=m
+CONFIG_VIDEO_BT848=m
+# CONFIG_VIDEO_BT848_DVB is not set
+# CONFIG_VIDEO_SAA6588 is not set
+CONFIG_VIDEO_CPIA=m
+# CONFIG_VIDEO_CPIA_USB is not set
+CONFIG_VIDEO_CPIA2=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+# CONFIG_VIDEO_STRADIS is not set
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_SAA7134_ALSA=m
+# CONFIG_VIDEO_SAA7134_DVB is not set
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+# CONFIG_VIDEO_CX88_ALSA is not set
+# CONFIG_VIDEO_CX88_DVB is not set
+CONFIG_VIDEO_OVCAMCHIP=m
+
+#
+# Encoders and Decoders
+#
+CONFIG_VIDEO_MSP3400=m
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_CX25840 is not set
+CONFIG_VIDEO_SAA711X=m
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+
+#
+# V4L USB devices
+#
+CONFIG_VIDEO_EM28XX=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_W9968CF is not set
+CONFIG_USB_ZC0301=m
+# CONFIG_USB_PWC is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_DEBUG=y
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_CINERGYT2=m
+CONFIG_DVB_CINERGYT2_TUNING=y
+CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32
+CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512
+CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250
+# CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_FLEXCOP=m
+# CONFIG_DVB_B2C2_FLEXCOP_PCI is not set
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+
+#
+# Supported BT878 Adapters
+#
+# CONFIG_DVB_BT8XX is not set
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_STV0299=m
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_S5H1420=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+# CONFIG_DVB_SP887X is not set
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terresterial DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_USB_DABUSB=m
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_SEQUENCER_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_VIRMIDI is not set
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+CONFIG_SND_ALS300=m
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RIPTIDE=m
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA ARM devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+CONFIG_USB_STORAGE_FREECOM=y
+# CONFIG_USB_STORAGE_ISD200 is not set
+CONFIG_USB_STORAGE_DPCM=y
+# 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
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_ACECAD=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_TOUCHSCREEN=m
+CONFIG_USB_TOUCHSCREEN_EGALAX=y
+CONFIG_USB_TOUCHSCREEN_PANJIT=y
+CONFIG_USB_TOUCHSCREEN_3M=y
+CONFIG_USB_TOUCHSCREEN_ITM=y
+# CONFIG_USB_YEALINK is not set
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_ATI_REMOTE2=m
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+CONFIG_USB_APPLETOUCH=m
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MICROTEK=m
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_ZD1201=m
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+# CONFIG_USB_SERIAL_ARK3116 is not set
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+CONFIG_USB_SERIAL_EMPEG=m
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+# CONFIG_USB_SERIAL_IR is not set
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_TI=m
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+CONFIG_USB_SERIAL_XIRCOM=m
+# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI26=m
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_SISUSBVGA_CON is not set
+CONFIG_USB_LD=m
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_NET2280=m
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+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=m
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_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=y
+# 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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
Added: people/maks-guest/linux-2.6/debian/arch/arm/config.ixp4xx
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config.ixp4xx Sat Nov 11 02:48:00 2006
@@ -0,0 +1,2003 @@
+CONFIG_GENERIC_TIME=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+
+#
+# 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_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+CONFIG_ARCH_IXP4XX=y
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# 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_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP4xx Implementation Options
+#
+
+#
+# IXP4xx Platforms
+#
+CONFIG_MACH_NSLU2=y
+CONFIG_ARCH_AVILA=y
+CONFIG_ARCH_ADI_COYOTE=y
+CONFIG_ARCH_IXDP425=y
+CONFIG_MACH_IXDPG425=y
+CONFIG_MACH_IXDP465=y
+CONFIG_ARCH_PRPMC1100=y
+CONFIG_MACH_NAS100D=y
+# CONFIG_MACH_GTWX5715 is not set
+
+#
+# IXP4xx Options
+#
+CONFIG_DMABOUNCE=y
+# CONFIG_IXP4XX_INDIRECT_PCI is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_AEABI 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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+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=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DECnet: Netfilter Configuration
+#
+# CONFIG_DECNET_NF_GRABULATOR is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_DECNET=m
+CONFIG_DECNET_ROUTER=y
+# CONFIG_DECNET_ROUTE_FWMARK is not set
+CONFIG_LLC=y
+CONFIG_LLC2=y
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+
+#
+# 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
+
+#
+# Queueing/Scheduling
+#
+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
+
+#
+# Classification
+#
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+CONFIG_RFD_FTL=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=m
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP4XX=y
+# CONFIG_MTD_PCI is not set
+CONFIG_MTD_PLATRAM=m
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_M25P80=m
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_CTL=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_IXP4XX_QMGR=m
+CONFIG_IXP4XX_NPE=m
+CONFIG_IXP4XX_FW_LOAD=y
+CONFIG_IXP4XX_MAC=m
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI 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
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 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=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+CONFIG_STRIP=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+# CONFIG_IPW2100_MONITOR is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+# CONFIG_PCI_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+# CONFIG_HOSTAP_FIRMWARE is not set
+CONFIG_HOSTAP_PLX=m
+# CONFIG_HOSTAP_PCI 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=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# 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=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_IXP4XX_BEEPER=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT 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=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED 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
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP4XX_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_NVRAM 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
+CONFIG_TELCLOCK=m
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_IOP3XX is not set
+CONFIG_I2C_ISA=m
+CONFIG_I2C_IXP4XX=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+CONFIG_SENSORS_DS1374=m
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+CONFIG_SENSORS_PCA9539=m
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_SENSORS_MAX6875=m
+CONFIG_RTC_X1205_I2C=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+CONFIG_W1=m
+
+#
+# 1-wire Bus Masters
+#
+CONFIG_W1_MASTER_MATROX=m
+CONFIG_W1_MASTER_DS9490=m
+CONFIG_W1_MASTER_DS9490_BRIDGE=m
+CONFIG_W1_MASTER_DS2482=m
+
+#
+# 1-wire Slaves
+#
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2433=m
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+CONFIG_SENSORS_ADM9240=m
+# CONFIG_SENSORS_ASB100 is not set
+CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SENSORS_VT8231=m
+# CONFIG_SENSORS_W83781D is not set
+CONFIG_SENSORS_W83792D=m
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+CONFIG_SENSORS_W83627EHF=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_IXP4XX=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_BT848=m
+# CONFIG_VIDEO_BT848_DVB is not set
+# CONFIG_VIDEO_SAA6588 is not set
+CONFIG_VIDEO_CPIA=m
+# CONFIG_VIDEO_CPIA_USB is not set
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_SAA7134_ALSA=m
+# CONFIG_VIDEO_SAA7134_DVB is not set
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+# CONFIG_VIDEO_CX88_ALSA is not set
+# CONFIG_VIDEO_CX88_DVB is not set
+CONFIG_VIDEO_CX88_VP3054=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_VIDEO_AUDIO_DECODER=m
+CONFIG_VIDEO_DECODER=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_DEBUG=y
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_CINERGYT2=m
+CONFIG_DVB_CINERGYT2_TUNING=y
+CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32
+CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512
+CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250
+# CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_FLEXCOP=m
+# CONFIG_DVB_B2C2_FLEXCOP_PCI is not set
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+
+#
+# Supported BT878 Adapters
+#
+# CONFIG_DVB_BT8XX is not set
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_STV0299=m
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_S5H1420=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+# CONFIG_DVB_SP887X is not set
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terresterial DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_VIRMIDI is not set
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+CONFIG_SND_PCXHR=m
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA ARM devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+# CONFIG_THRUSTMASTER_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_ACECAD=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_ITMTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_YEALINK=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_ATI_REMOTE2=m
+CONFIG_USB_KEYSPAN_REMOTE=m
+CONFIG_USB_APPLETOUCH=m
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_PWC is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_ZD1201=m
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI26=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_SISUSBVGA_CON is not set
+CONFIG_USB_LD=m
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_NET2280=m
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_RTC_INTF_DEV=m
+
+#
+# RTC drivers
+#
+CONFIG_RTC_DRV_X1205=y
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+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=m
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+CONFIG_OCFS2_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_ASFS_FS=m
+CONFIG_ASFS_DEFAULT_CODEPAGE=""
+# CONFIG_ASFS_RW is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+CONFIG_9P_FS=m
+
+#
+# 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=y
+# 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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
Added: people/maks-guest/linux-2.6/debian/arch/arm/config.rpc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config.rpc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,992 @@
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_FIQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+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=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+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_EP93XX 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_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+CONFIG_ARCH_RPC=y
+# CONFIG_ARCH_SA1100 is not set
+# 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_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+CONFIG_ARCH_ACORN=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM610=y
+CONFIG_CPU_ARM710=y
+CONFIG_CPU_SA110=y
+CONFIG_CPU_32v3=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V3=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V3=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V3=y
+CONFIG_CPU_TLB_V4WB=y
+
+#
+# Processor Features
+#
+CONFIG_TIMER_ACORN=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# 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_SPARSEMEM_STATIC is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+
+#
+# Networking options
+#
+# CONFIG_NET_KEY is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_IP_DCCP_UNLOAD_HACK is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT_ARC is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# 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
+
+#
+# Acorn-specific block devices
+#
+
+#
+# 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=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_IDE_ARM=y
+CONFIG_BLK_DEV_IDE_ICSIDE=y
+CONFIG_BLK_DEV_IDEDMA_ICS=y
+CONFIG_IDEDMA_ICS_AUTO=y
+CONFIG_BLK_DEV_IDE_RAPIDE=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_ARXESCSI=m
+CONFIG_SCSI_CUMANA_2=m
+CONFIG_SCSI_EESOXSCSI=m
+CONFIG_SCSI_POWERTECSCSI=m
+
+#
+# The following drivers are not fully supported
+#
+CONFIG_SCSI_CUMANA_1=m
+CONFIG_SCSI_OAK1=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_ARM_ETHER1=y
+CONFIG_ARM_ETHER3=y
+CONFIG_ARM_ETHERH=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_NET_POCKET 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# 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=m
+
+#
+# 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 is not set
+# CONFIG_MOUSE_SERIAL is not set
+CONFIG_MOUSE_RISCPC=y
+# 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 is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_RPCKBD=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT 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=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_ACORN=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# 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_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+CONFIG_SENSORS_DS1374=m
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+CONFIG_SENSORS_PCA9539=m
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_SENSORS_MAX6875=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+CONFIG_SENSORS_ADM9240=m
+# CONFIG_SENSORS_ASB100 is not set
+CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+CONFIG_SENSORS_W83792D=m
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+CONFIG_SENSORS_W83627EHF=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# 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_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_ACORN=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+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=y
+# 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
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+CONFIG_SOUND_VIDC=m
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 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_EXT3_FS=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=y
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=y
+# 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_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=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
+CONFIG_9P_FS=m
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_ADFS=y
+CONFIG_ACORN_PARTITION_POWERTEC=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+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_INFO is not set
+# 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
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO_DES=y
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_SPLIT_PTLOCK_CPUS=4096
Added: people/maks-guest/linux-2.6/debian/arch/arm/config.s3c2410
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config.s3c2410 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1268 @@
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_UID16=y
+CONFIG_PRINTK=y
+CONFIG_HOTPLUG=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+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_EP93XX 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_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+CONFIG_ARCH_S3C2410=y
+# 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_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# S3C24XX Implementations
+#
+CONFIG_MACH_ANUBIS=y
+CONFIG_MACH_OSIRIS=y
+CONFIG_ARCH_BAST=y
+CONFIG_BAST_PC104_IRQ=y
+CONFIG_ARCH_H1940=y
+CONFIG_MACH_N30=y
+CONFIG_MACH_SMDK=y
+CONFIG_ARCH_SMDK2410=y
+CONFIG_ARCH_S3C2440=y
+CONFIG_MACH_VR1000=y
+CONFIG_MACH_RX3715=y
+CONFIG_MACH_OTOM=y
+CONFIG_MACH_NEXCODER_2440=y
+CONFIG_CPU_S3C2410=y
+CONFIG_CPU_S3C2440=y
+
+#
+# S3C2410 Boot
+#
+# CONFIG_S3C2410_BOOT_WATCHDOG is not set
+# CONFIG_S3C2410_BOOT_ERROR_RESET is not set
+
+#
+# S3C2410 Setup
+#
+CONFIG_S3C2410_DMA=y
+# CONFIG_S3C2410_DMA_DEBUG is not set
+# CONFIG_S3C2410_PM_DEBUG is not set
+# CONFIG_S3C2410_PM_CHECK is not set
+CONFIG_PM_SIMTEC=y
+CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+CONFIG_ISA=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# 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_SPARSEMEM_STATIC is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_APM=y
+
+#
+# Networking
+#
+
+#
+# Networking options
+#
+CONFIG_NET_KEY=m
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPGRE is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_IP_DCCP_UNLOAD_HACK is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_16=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+CONFIG_MTD_BAST=y
+CONFIG_MTD_BAST_MAXSIZE=4
+CONFIG_MTD_PLATRAM=m
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_S3C2410=y
+# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
+# CONFIG_MTD_NAND_S3C2410_HWECC is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT_ARC is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# 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=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDE_BAST=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_SCSI_SATA=m
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+CONFIG_BONDING=m
+CONFIG_TUN=m
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+CONFIG_DM9000=y
+# CONFIG_NET_POCKET 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_PLIP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# 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=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+CONFIG_SERIAL_8250_FOURPORT=m
+CONFIG_SERIAL_8250_ACCENT=m
+CONFIG_SERIAL_8250_BOCA=m
+CONFIG_SERIAL_8250_HUB6=m
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_S3C2410=y
+CONFIG_SERIAL_S3C2410_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=y
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_S3C2410_WATCHDOG=y
+# CONFIG_NVRAM is not set
+CONFIG_S3C2410_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_S3C2410=y
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+CONFIG_SENSORS_DS1374=m
+CONFIG_SENSORS_EEPROM=m
+# CONFIG_SENSORS_PCF8574 is not set
+CONFIG_SENSORS_PCA9539=m
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_SENSORS_MAX6875=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+CONFIG_SPI_S3C24XX_GPIO=m
+CONFIG_SPI_S3C24XX=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+CONFIG_SENSORS_ADM9240=m
+# CONFIG_SENSORS_ASB100 is not set
+CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F 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=m
+# CONFIG_SENSORS_LM77 is not set
+CONFIG_SENSORS_LM78=m
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+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_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+CONFIG_SENSORS_W83792D=m
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+CONFIG_SENSORS_W83627EHF=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+
+#
+# LED drivers
+#
+CONFIG_LEDS_S3C24XX=m
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+
+#
+# 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_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_S3C2410=y
+# CONFIG_FB_S3C2410_DEBUG is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO 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
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# 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_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=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
+CONFIG_9P_FS=m
+
+#
+# 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=y
+# CONFIG_MINIX_SUBPARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
+# 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
+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_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_S3C2410_PORT=y
+CONFIG_DEBUG_S3C2410_UART=0
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO_DES=y
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_USB_HIDDEV is not set
+CONFIG_BT_HIDP=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_TEST=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_LCD=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_AUERSWALD=m
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_USB_SL811_HCD is not set
+CONFIG_USB_LED=m
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KBD is not set
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_MTOUCH=m
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_USB_SERIAL_GARMIN=m
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_PPP_BSDCOMP=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_BT_HCIUART=m
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_USB_STORAGE_FREECOM=y
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+# CONFIG_USB_SUSPEND is not set
+CONFIG_USB_MDC800=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_ACORN_PARTITION_ADFS=y
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_RIO500=m
+# CONFIG_USB_OTG is not set
+CONFIG_BT_BNEP_MC_FILTER=y
+# CONFIG_USB_GADGET_PXA2XX is not set
+CONFIG_BT_L2CAP=m
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_USB_MICROTEK=m
+CONFIG_BT_BNEP=m
+CONFIG_USB_USS720=m
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_SDDR09=y
+# CONFIG_BT_HCIBPA10X is not set
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_ACM=m
+CONFIG_ACORN_PARTITION_EESOX=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_WACOM=m
+CONFIG_PPP_FILTER=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_PPPOE=m
+CONFIG_USB_STORAGE_SDDR55=y
+# CONFIG_USB_USBNET is not set
+CONFIG_ACORN_PARTITION_ICS=y
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_KBTAB=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_PPP_ASYNC=m
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_ACORN_PARTITION_POWERTEC=y
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_HID=m
+# CONFIG_HID_FF is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_SERIAL_KLSI=m
+# CONFIG_USB_G_SERIAL is not set
+CONFIG_BT_RFCOMM=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_BT_SCO=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_EGALAX=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_USB_STORAGE=m
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_PPP=m
+CONFIG_CRC_CCITT=m
+# CONFIG_LANCE is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_DEPCA is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_TR is not set
+# CONFIG_AT1700 is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_WDT is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_HP100 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_S3C2410_BOOT_ERROR_RESET is not set
+# CONFIG_ARCNET is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_MTD_ONENAND_GENERIC is not set
+# CONFIG_MDA_CONSOLE is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PNP is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_BLK_DEV_XD is not set
Added: people/maks-guest/linux-2.6/debian/arch/arm/config.versatile
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/config.versatile Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1408 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Mon Sep 25 14:26:30 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+CONFIG_ARCH_VERSATILE=y
+# CONFIG_ARCH_AT91 is not set
+# 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_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Versatile platform type
+#
+CONFIG_ARCH_VERSATILE_PB=y
+CONFIG_MACH_VERSATILE_AB=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_VIC=y
+CONFIG_ICST307=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+CONFIG_PCI=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_AEABI 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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_SECMARK is not set
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DECnet: Netfilter Configuration
+#
+CONFIG_DECNET_NF_GRABULATOR=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID2=m
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+
+#
+# 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
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+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_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_ATA_OVER_ETH=m
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+CONFIG_SCSI_HPTIOP=m
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB 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_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 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=m
+# CONFIG_ACENIC_OMIT_TIGON_I 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+CONFIG_MYRI10GE=m
+
+#
+# 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=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN 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 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=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_AMBAKMI=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=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
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_ARMCLCD=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+CONFIG_FB_VIRTUAL=m
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+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
+#
+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
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_RTC_INTF_DEV=m
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+CONFIG_RTC_DRV_DS1553=m
+CONFIG_RTC_DRV_DS1742=m
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_TEST is not set
+CONFIG_RTC_DRV_V3020=m
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_ASFS_FS=m
+CONFIG_ASFS_DEFAULT_CODEPAGE=""
+# CONFIG_ASFS_RW is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+CONFIG_9P_FS=m
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
+CONFIG_ACORN_PARTITION_ICS=y
+# CONFIG_ACORN_PARTITION_ADFS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_UNUSED_SYMBOLS=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_SECLVL is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
Added: people/maks-guest/linux-2.6/debian/arch/arm/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/arm/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,40 @@
+[base]
+flavours:
+ footbridge
+ iop32x
+ ixp4xx
+ rpc
+ s3c2410
+kernel-arch: arm
+kernel-header-dirs: arm
+
+[image]
+suggests: fdutils
+
+[footbridge_image]
+suggests: nwutil
+
+[footbridge]
+class: Footbridge based
+longclass: Footbridge (CATS, Netwinder)
+
+[iop32x]
+class: IOP32x
+longclass: IOP32x based (Thecus N2100, etc)
+
+[ixp4xx]
+class: IXP4xx
+longclass: IXP4xx based (Linksys NSLU2, etc)
+
+[rpc]
+class: RiscPC
+longclass: Arcon RiscPC
+
+[s3c2410]
+class: Samsung S3C2410
+longclass: Samsung S3C2410 based (BAST, IPAQ 1940, etc)
+
+[versatile]
+class: Versatile
+longclass: Versatile (PB, AB, Qemu)
+
Added: people/maks-guest/linux-2.6/debian/arch/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1061 @@
+CONFIG_MMU=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_SYSCTL=y
+CONFIG_HOTPLUG=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_KMOD=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_VLAN_8021Q=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_NET_ETHERNET=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+# CONFIG_SECCOMP is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_TCG_ATMEL=m
+CONFIG_TCG_NSC=m
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_6PACK=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_SERIAL_8250_ACCENT=m
+CONFIG_FB_ARC=m
+CONFIG_FUSION_SPI=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_FUSION_FC=m
+CONFIG_USB_ACECAD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_I2O_EXT_ADAPTEC=y
+CONFIG_USB_CXACRU=m
+CONFIG_DVB_USB_A800=m
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_BLK_DEV_IT821X=m
+CONFIG_TEXTSEARCH=y
+CONFIG_DRM_VIA=m
+CONFIG_USB_KEYSPAN_REMOTE=m
+CONFIG_DVB_S5H1420=m
+CONFIG_SND_HDSPM=m
+CONFIG_SENSORS_PCA9539=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_SKGE=m
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_SERIAL_8250_HUB6=m
+CONFIG_SERIAL_8250_MCA=m
+CONFIG_I2O_BUS=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_SERIAL_8250_BOCA=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_PLUTO2=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_DVB_BCM3510=m
+CONFIG_SENSORS_MAX6875=m
+CONFIG_MTD_PLATRAM=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_DS1374=m
+CONFIG_USB_XUSBATM=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_DVB_USB=m
+CONFIG_USB_LD=m
+CONFIG_SERIAL_8250_FOURPORT=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_NFS_ACL_SUPPORT=m
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_TCG_INFINEON=m
+CONFIG_SENSORS_ATXP1=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_HWMON=y
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_DEV_PADLOCK=m
+CONFIG_CRYPTO_DEV_PADLOCK_AES=y
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_AES=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_NFS_COMMON=y
+CONFIG_USB_MON=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_7000FASST=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AHA1740=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_PROBE_EISA_VL=y
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_AIC79XX_ENABLE_RD_STRM=y
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_BKL is not set
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_SECLVL is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DECnet: Netfilter Configuration
+#
+CONFIG_DECNET_NF_GRABULATOR=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+
+# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_LXT_PHY=m
+CONFIG_PCMCIA_SPECTRUM=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_YEALINK=m
+CONFIG_FUSE_FS=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_FB_CYBLA=m
+CONFIG_VIDEO_SELECT=y
+CONFIG_CRC16=m
+CONFIG_IP_DCCP=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+CONFIG_HOSTAP_CS=m
+CONFIG_HWMON_VID=m
+CONFIG_SIS190=m
+CONFIG_SND_AD1889=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_RAID_ATTRS=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_VIDEO_SAA6588=m
+CONFIG_CHELSIO_T1=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_SCSI_SAS_ATTRS=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_DAVICOM_PHY=m
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_USB_SISUSBVGA_CON=y
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_9P_FS=m
+CONFIG_FUSION_SAS=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_CASSINI=m
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_DRM_SAVAGE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_PHYLIB=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+CONFIG_MARVELL_PHY=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SND_AC97_BUS=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_USB_NET_GL620A=m
+CONFIG_FLATMEM=y
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_HOSTAP_PLX=m
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_NETFILTER_NETLINK=m
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_IP_DCCP_DEBUG is not set
+CONFIG_INET_DIAG=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_ULI526X=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_HOSTAP=m
+CONFIG_IPW2200=m
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SENSORS_W83792D=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_USB_EMI26=m
+CONFIG_CONNECTOR=m
+CONFIG_CICADA_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_IEEE80211=m
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_DELL_RBU=m
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_I2O_CONFIG_OLD_IOCTL=y
+CONFIG_FUSION_CTL=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_PCMCIA_PROBE=y
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_USB_APPLETOUCH is not set
+CONFIG_I2O_EXT_ADAPTEC_DMA64=y
+CONFIG_FUSION=y
+# CONFIG_NET_POCKET is not set
+CONFIG_FW_LOADER=m
+CONFIG_MII=m
+CONFIG_BLK_DEV_IDEPNP=m
+CONFIG_AIRO=m
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_XFS_QUOTA=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_INFINIBAND_SRP=m
+CONFIG_VIDEO_CX88_DVB_ALL_FRONTENDS=y
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_MTD_ONENAND=m
+CONFIG_PPP_MPPE=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_VIDEO_SAA7134_DVB_ALL_FRONTENDS=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_VIDEO_EM28XX=m
+CONFIG_RFD_FTL=m
+CONFIG_DVB_NXT200X=m
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_ISCSI_TCP=m
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_TELCLOCK=m
+CONFIG_CARDMAN_4000=m
+CONFIG_CARDMAN_4040=m
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_PACKET_MMAP=y
+CONFIG_MKISS=m
+CONFIG_VIDEO_BT848_DVB=y
+CONFIG_ATM_DUMMY=m
+CONFIG_VIDEO_SAA7134_OSS=m
+CONFIG_VIDEO_SAA7134_DVB=m
+CONFIG_VIDEO_SAA7134_ALSA=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_SYNCLINK_GT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_SPI_BITBANG=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_TIPC_ZONES=3
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_VIDEO_CX88_ALSA=m
+CONFIG_ELF_CORE=y
+CONFIG_USB_UEAGLEATM=m
+CONFIG_TIPC_NODES=255
+CONFIG_DVB_CX24123=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_TOUCHSCREEN_ADS7846=m
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_MTD_M25P80=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_YENTA_TOSHIBA=y
+CONFIG_TIPC=m
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+CONFIG_USB_ATI_REMOTE2=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_SBC_EPX_C3_WATCHDOG=m
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+CONFIG_YENTA_O2=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_SND_PCXHR=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+# CONFIG_SPI_DEBUG is not set
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_SPI=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_IFB=m
+CONFIG_KARMA_PARTITION=y
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+# CONFIG_USB_LIBUSUAL is not set
+CONFIG_CONFIGFS_FS=m
+CONFIG_SKY2=m
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+# CONFIG_CRASH_DUMP is not set
+CONFIG_YENTA_TI=y
+CONFIG_TIPC_LOG=0
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_DMI=y
+CONFIG_SPI_BUTTERFLY=m
+CONFIG_TIPC_SLAVE_NODES=0
+# CONFIG_TIPC_DEBUG is not set
+# CONFIG_SLOB is not set
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_TIPC_PORTS=8191
+CONFIG_SENSORS_VT8231=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_OCFS2_FS=m
+CONFIG_SPI_MASTER=y
+CONFIG_TIPC_ADVANCED=y
+CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y
+CONFIG_SLAB=y
+CONFIG_MTD_DATAFLASH=m
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+CONFIG_USB_ET61X251=m
+# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_FAULTY=m
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS=m
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_SECURITY=y
+CONFIG_AMD8111E_NAPI=y
+CONFIG_TULIP_NAPI=y
+CONFIG_R8169_NAPI=y
+CONFIG_IXGB_NAPI=y
+CONFIG_ADAPTEC_STARFIRE_NAPI=y
+CONFIG_TULIP_NAPI_HW_MITIGATION=y
+CONFIG_E1000_NAPI=y
+CONFIG_S2IO_NAPI=y
+CONFIG_VIDEO_CX88_VP3054=m
+CONFIG_NFSD_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFS_V4=y
+# CONFIG_GIGASET_UNDOCREQ is not set
+CONFIG_MMC_SDHCI=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_VIDEO_SAA7127=m
+# CONFIG_RELAY is not set
+# CONFIG_BCM43XX_DMA_MODE is not set
+CONFIG_RTC_LIB=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_GIGASET_BASE=m
+CONFIG_LSF=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_IEEE80211_SOFTMAC=m
+CONFIG_NEW_LEDS=y
+CONFIG_IP_NF_H323=m
+CONFIG_RTC_DRV_M48T86=m
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_SND_RIPTIDE=m
+CONFIG_VIDEO_SAA711X=m
+CONFIG_VIDEO_WM8775=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+# CONFIG_RTC_DRV_TEST is not set
+CONFIG_W1_MASTER_MATROX=m
+CONFIG_IPATH_CORE=m
+CONFIG_INFINIBAND_IPATH=m
+CONFIG_RTC_INTF_DEV=m
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_USB_ZC0301=m
+CONFIG_VIDEO_MSP3400=m
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_VIDEO_CX25840=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_LEDS_CLASS=m
+CONFIG_VIDEO_USBVIDEO=m
+# CONFIG_USB_GADGET_AT91 is not set
+CONFIG_RTC_CLASS=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_BCM43XX_DMA=y
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_GIGASET_M105=m
+CONFIG_NET_WIRELESS_RTNETLINK=y
+CONFIG_ISDN_DRV_GIGASET=m
+CONFIG_BCM43XX=m
+CONFIG_USB_DABUSB=m
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_DVB_ZL10353=m
+CONFIG_BCM43XX_DMA_AND_PIO_MODE=y
+CONFIG_IP_DCCP_CCID2=m
+CONFIG_VIDEO_UPD64083=m
+CONFIG_VIDEO_UPD64031A=m
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_GIGASET_DEBUG is not set
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_VIDEO_CS53L32A=m
+# CONFIG_BCM43XX_PIO_MODE is not set
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_VIDEO_WM8739=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_BCM43XX_PIO=y
+CONFIG_IP_NF_NAT_H323=m
+# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_SND_ALS300=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_IP_DCCP_ACKVEC=y
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_TOUCHSCREEN=m
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+CONFIG_USB_TOUCHSCREEN_PANJIT=y
+CONFIG_USB_TOUCHSCREEN_ITM=y
+# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
+CONFIG_USB_TOUCHSCREEN_EGALAX=y
+CONFIG_USB_TOUCHSCREEN_3M=y
+CONFIG_INFINIBAND_IPOIB_DEBUG=y
+CONFIG_INFINIBAND_MTHCA_DEBUG=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_RODATA is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_MUTEXES is not set
+CONFIG_BCM43XX_DEBUG=y
+CONFIG_SND_PDAUDIOCF=m
+CONFIG_SND_VXPOCKET=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_VIVI=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_SENSORS_W83791D=m
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_DMA_ENGINE=y
+CONFIG_RTC_DRV_ISL1208=m
+# CONFIG_ZD1211RW_DEBUG is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_VIDEO_ZORAN_AVS6EYES=m
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_MTD_ONENAND_OTP is not set
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_SND_INDIGOIO=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_IP_NF_NAT_SIP=m
+# CONFIG_W1_SLAVE_DS2433_CRC is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_FIXED_MII_10_FDX is not set
+CONFIG_VIDEO_CX88_BLACKBIRD=m
+# CONFIG_FIXED_MII_100_FDX is not set
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_SENSORS_LM70=m
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_USB_EMI62=m
+CONFIG_RTC_DRV_DS1553=m
+CONFIG_NETWORK_SECMARK=y
+CONFIG_PC8736x_GPIO=m
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_NSC_GPIO=m
+# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set
+CONFIG_SND_INDIGO=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_PCF8583=m
+# CONFIG_TASKSTATS is not set
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_VIDEO_PVRUSB2_24XXX=y
+CONFIG_NET_DMA=y
+# CONFIG_CIFS_DEBUG2 is not set
+CONFIG_TCP_CONG_LP=m
+CONFIG_DVB_ISL6421=m
+CONFIG_PLIST=y
+CONFIG_W1_CON=y
+CONFIG_INOTIFY_USER=y
+CONFIG_RT_MUTEXES=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RTC_DRV_V3020=m
+CONFIG_INFINIBAND_ADDR_TRANS=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_ACPI_DOCK=m
+CONFIG_SENSORS_SMSC47M192=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_SMSC_PHY=m
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_IPW2200_RADIOTAP is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+# CONFIG_DEBUG_RT_MUTEXES is not set
+CONFIG_VIA_RHINE_NAPI=y
+CONFIG_RTC_DRV_DS1742=m
+CONFIG_MYRI10GE=m
+CONFIG_ZD1211RW=m
+CONFIG_USB_QUICKCAM_MESSENGER=m
+CONFIG_DGRS=m
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_SND_GINA20=m
+CONFIG_VITESSE_PHY=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_SND_GINA24=m
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_VIDEO_TLV320AIC23B=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_VIDEO_CX2341X=m
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_W1_MASTER_DS2490=m
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_FIRMWARE_EDID=y
+CONFIG_VIDEO_PVRUSB2=m
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_IP_NF_SIP=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_SND_DARLA20=m
+CONFIG_SND_DARLA24=m
+CONFIG_ACENIC=m
+CONFIG_HW_RANDOM=y
+CONFIG_SND_MIA=m
+CONFIG_MCS_FIR=m
+# CONFIG_IP_NF_CONNTRACK_SECMARK is not set
+# CONFIG_IPW2200_PROMISCUOUS is not set
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+CONFIG_MD_RAID456=m
+CONFIG_INFINIBAND_ISER=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_DVB_LNBP21=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_STACKTRACE_SUPPORT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_PARPORT_AX88796=m
+CONFIG_SND_INDIGODJ=m
+CONFIG_SENSORS_ABITUGURU=m
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_SND_ECHO3G=m
+# CONFIG_FB_INTEL_DEBUG is not set
+CONFIG_SND_LAYLA20=m
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_SND_LAYLA24=m
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_LCD_DEVICE=y
+CONFIG_FIXED_PHY=m
+CONFIG_SND_MONA=m
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_IPW2200_QOS=y
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_I2C_OCORES=m
+CONFIG_DEV_APPLETALK=m
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=m
+CONFIG_MTD_NAND_CS553X=m
+CONFIG_LEDS_NET48XX=m
+CONFIG_SMCTR=m
+CONFIG_EARLY_PRINTK=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_OSS_OBSOLETE_DRIVER is not set
+CONFIG_PARPORT=m
+CONFIG_PARPORT_SERIAL=m
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_PC=m
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_NOT_PC=y
+CONFIG_PARPORT_PC_PCMCIA=m
+CONFIG_PARPORT_1284=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_NET_CLS=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_DVB_PLL=m
+CONFIG_CPUSETS=y
Added: people/maks-guest/linux-2.6/debian/arch/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,40 @@
+[abi]
+abiname: 2
+
+[base]
+arches:
+ alpha
+ amd64
+ arm
+ hppa
+ i386
+ ia64
+ m68k
+ mips
+ mipsel
+ powerpc
+ s390
+ sparc
+compiler: gcc-4.1
+
+[image]
+initramfs-generators: initramfs-tools yaird initramfs-fallback
+type: kernel-package
+
+[xen]
+versions:
+ 3.0.3-1
+
+[commands-image-initramfs-generators]
+initramfs-tools: mkinitramfs-kpkg
+yaird: mkinitrd.yaird
+
+[relations]
+gcc-3.3: gcc-3.3
+gcc-4.0: gcc-4.0
+gcc-4.1: gcc-4.1
+initramfs-fallback: linux-initramfs-tool
+initramfs-tools: initramfs-tools (>= 0.55)
+util-vserver: util-vserver (>= 0.30.210)
+yaird: yaird (>= 0.0.12-8)
+
Added: people/maks-guest/linux-2.6/debian/arch/hppa/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/hppa/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,773 @@
+CONFIG_PARISC=y
+CONFIG_MMU=y
+CONFIG_STACK_GROWSUP=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ISA_DMA_API=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_SYSCTL=y
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC 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_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
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+# CONFIG_PA7100LC is not set
+# CONFIG_PA7200 is not set
+# CONFIG_PA7300LC is not set
+CONFIG_PARISC_PAGE_SIZE_4KB=y
+# CONFIG_PARISC_PAGE_SIZE_16KB is not set
+# CONFIG_PARISC_PAGE_SIZE_64KB is not set
+CONFIG_GSC=y
+CONFIG_HPPB=y
+CONFIG_IOMMU_CCIO=y
+CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_EISA=y
+CONFIG_EISA_NAMES=y
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_GSC_DINO=y
+CONFIG_PCI_LBA=y
+CONFIG_IOSAPIC=y
+CONFIG_IOMMU_SBA=y
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+CONFIG_YENTA=m
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+# CONFIG_TCIC is not set
+CONFIG_PCCARD_NONSTATIC=m
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_SUPERIO=y
+CONFIG_CHASSIS_LCD_LED=y
+CONFIG_PDC_CHASSIS=y
+CONFIG_PDC_CHASSIS_WARN=y
+CONFIG_PDC_STABLE=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_MTD is not set
+# CONFIG_PNP is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE 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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=m
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+CONFIG_BLK_DEV_NS87415=m
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+CONFIG_MEGARAID_LEGACY=m
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+CONFIG_SCSI_INITIO=m
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_LASI700=m
+CONFIG_53C700_LE_ON_BE=y
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+CONFIG_SCSI_ZALON=m
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_LPFC=m
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_MD=y
+CONFIG_DM_MULTIPATH_EMC=m
+# CONFIG_IEEE1394 is not set
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+CONFIG_NET_KEY=m
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+CONFIG_BRIDGE_NETFILTER=y
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NET_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=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ARCNET is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_LASI_82596=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+# CONFIG_LANCE is not set
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_ULTRA32=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+CONFIG_NI52=m
+# CONFIG_NI65 is not set
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+CONFIG_PCMCIA_XIRCOM=m
+CONFIG_AT1700=m
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+CONFIG_NET_ISA=y
+CONFIG_E2100=m
+CONFIG_EWRK3=m
+CONFIG_EEXPRESS=m
+CONFIG_EEXPRESS_PRO=m
+CONFIG_HPLAN_PLUS=m
+CONFIG_HPLAN=m
+CONFIG_LP486E=m
+CONFIG_ETH16I=m
+CONFIG_NE2000=m
+CONFIG_ZNET=m
+CONFIG_SEEQ8005=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_LNE390=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_NE3210=m
+CONFIG_ES3210=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_R8169_VLAN=y
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+CONFIG_IXGB=m
+CONFIG_S2IO=m
+# CONFIG_2BUFF_MODE is not set
+# CONFIG_TR is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_RAYCS=m
+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
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_NET_FC is not set
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+CONFIG_INPUT=y
+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=m
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y
+# CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES is not set
+# 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_KEYBOARD_HIL_OLD=m
+CONFIG_KEYBOARD_HIL=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+# 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_MOUSE_HIL=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_UINPUT is not set
+CONFIG_HP_SDC_RTC=m
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_GSCPS2=y
+CONFIG_HP_SDC=m
+CONFIG_HIL_MLC=m
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+# CONFIG_GAMEPORT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=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
+CONFIG_SERIAL_MUX=y
+CONFIG_SERIAL_MUX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+CONFIG_SYNCLINK_CS=m
+# CONFIG_RAW_DRIVER is not set
+CONFIG_TCG_NSC=m
+CONFIG_TCG_ATMEL=m
+# CONFIG_I2C is not set
+# CONFIG_W1 is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_STI=y
+# 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
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=160
+CONFIG_DUMMY_CONSOLE_ROWS=64
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_STI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_PARISC_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4232 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_WAVEFRONT is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_SGALAXY is not set
+# CONFIG_SND_SSCAPE is not set
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_AD1889_OPL3 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 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
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_VXP440 is not set
+CONFIG_SND_HARMONY=m
+# CONFIG_SOUND_PRIME is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+CONFIG_USB_DEBUG=y
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_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_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
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_EXT2_FS=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=y
+CONFIG_VXFS_FS=m
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=15
+# 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_IOREMAP is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SND_HWDEP=m
+CONFIG_NFS_ACL_SUPPORT=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_IPW2100 is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
Added: people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,14 @@
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_PA7000=y
+# CONFIG_PA8X00 is not set
+CONFIG_PA11=y
+# CONFIG_SMP is not set
+# CONFIG_HPUX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_NSP32 is not set
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+# CONFIG_NI5010 is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
+CONFIG_TLAN=m
+# CONFIG_ARLAN is not set
Added: people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc-smp
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc-smp Sat Nov 11 02:48:00 2006
@@ -0,0 +1,16 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_PA7000=y
+# CONFIG_PA8X00 is not set
+CONFIG_PA11=y
+CONFIG_SMP=y
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_HPUX is not set
+CONFIG_NR_CPUS=8
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_NSP32 is not set
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_TLAN=m
+# CONFIG_ARLAN is not set
+# CONFIG_DEBUG_RWLOCK is not set
Added: people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc64
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc64 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,13 @@
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_PA7000 is not set
+CONFIG_PA8X00=y
+CONFIG_PA20=y
+CONFIG_PREFETCH=y
+CONFIG_64BIT=y
+# CONFIG_SMP is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_COMPAT=y
+# CONFIG_NI5010 is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
+CONFIG_NEED_MULTIPLE_NODES=y
+# CONFIG_FLATMEM_MANUAL is not set
Added: people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc64-smp
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/config.parisc64-smp Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_PA7000 is not set
+CONFIG_PA8X00=y
+CONFIG_PA20=y
+CONFIG_PREFETCH=y
+CONFIG_64BIT=y
+CONFIG_SMP=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_COMPAT=y
+CONFIG_NR_CPUS=8
+# CONFIG_DEBUG_RWLOCK is not set
+CONFIG_NEED_MULTIPLE_NODES=y
+# CONFIG_FLATMEM_MANUAL is not set
Added: people/maks-guest/linux-2.6/debian/arch/hppa/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/hppa/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,27 @@
+[base]
+flavours:
+ parisc
+ parisc-smp
+ parisc64
+ parisc64-smp
+kernel-arch: parisc
+kernel-header-dirs: parisc
+
+[image]
+suggests: palo
+
+[parisc]
+class: 32-bit PA-RISC
+
+[parisc-smp]
+class: multiprocessor 32-bit PA-RISC
+
+[parisc64]
+class: 64-bit PA-RISC
+
+[parisc64-smp]
+class: multiprocessor 64-bit PA-RISC
+
+[relations]
+gcc-4.1: gcc-4.1, binutils-hppa64, gcc-4.1-hppa64
+
Added: people/maks-guest/linux-2.6/debian/arch/i386/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1688 @@
+CONFIG_X86=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_IOMAP=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_X86_PC=y
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_GENERICARCH is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+CONFIG_HPET_TIMER=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+CONFIG_TOSHIBA=m
+CONFIG_I8K=m
+# CONFIG_X86_REBOOTFIXUPS is not set
+CONFIG_MICROCODE=m
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+CONFIG_EDD=m
+# CONFIG_HIGHMEM64G is not set
+CONFIG_MTRR=y
+CONFIG_REGPARM=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+# CONFIG_ACPI_SLEEP_PROC_SLEEP is not set
+CONFIG_ACPI_AC=m
+CONFIG_ACPI_BATTERY=m
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_VIDEO=m
+CONFIG_ACPI_HOTKEY=m
+CONFIG_ACPI_FAN=m
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_THERMAL=m
+CONFIG_ACPI_ASUS=m
+CONFIG_ACPI_IBM=m
+# CONFIG_ACPI_IBM_DOCK is not set
+CONFIG_ACPI_TOSHIBA=m
+CONFIG_ACPI_BLACKLIST_YEAR=0
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_X86_PM_TIMER=y
+CONFIG_ACPI_CONTAINER=m
+CONFIG_APM=m
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+# CONFIG_APM_CPU_IDLE is not set
+# CONFIG_APM_DISPLAY_BLANK is not set
+# CONFIG_APM_RTC_IS_GMT is not set
+# CONFIG_APM_ALLOW_INTS is not set
+# CONFIG_APM_REAL_MODE_POWER_OFF is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=m
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_X86_ACPI_CPUFREQ=m
+CONFIG_X86_POWERNOW_K6=m
+CONFIG_X86_POWERNOW_K7=m
+CONFIG_X86_POWERNOW_K7_ACPI=y
+CONFIG_X86_POWERNOW_K8=m
+CONFIG_X86_POWERNOW_K8_ACPI=y
+CONFIG_X86_GX_SUSPMOD=m
+CONFIG_X86_SPEEDSTEP_CENTRINO=m
+CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y
+CONFIG_X86_SPEEDSTEP_ICH=m
+CONFIG_X86_SPEEDSTEP_SMI=m
+CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_X86_CPUFREQ_NFORCE2=m
+CONFIG_X86_LONGRUN=m
+CONFIG_X86_LONGHAUL=m
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
+CONFIG_X86_SPEEDSTEP_LIB=m
+CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=m
+# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_ISA_DMA_API=y
+CONFIG_ISA=y
+CONFIG_SCx200=m
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+CONFIG_YENTA=m
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+CONFIG_TCIC=m
+CONFIG_PCCARD_NONSTATIC=m
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI_FAKE=m
+CONFIG_HOTPLUG_PCI_COMPAQ=m
+CONFIG_HOTPLUG_PCI_IBM=m
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI_ACPI_IBM=m
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m
+CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m
+CONFIG_HOTPLUG_PCI_SHPC=m
+# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
+CONFIG_BINFMT_AOUT=m
+CONFIG_STANDALONE=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PNC2000=m
+CONFIG_MTD_SC520CDP=m
+CONFIG_MTD_NETSC520=m
+CONFIG_MTD_TS5500=m
+CONFIG_MTD_SBC_GXX=m
+CONFIG_MTD_SCx200_DOCFLASH=m
+# CONFIG_MTD_AMD76XROM is not set
+# CONFIG_MTD_ICHXROM is not set
+# CONFIG_MTD_SCB2_FLASH is not set
+CONFIG_MTD_NETtel=m
+CONFIG_MTD_DILNETPC=m
+CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000
+# CONFIG_MTD_L440GX is not set
+CONFIG_MTD_PCI=m
+CONFIG_MTD_PCMCIA=m
+# CONFIG_MTD_PCMCIA_ANONYMOUS is not set
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_DOC2000=m
+CONFIG_MTD_DOC2001=m
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0
+# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+CONFIG_ISAPNP=y
+CONFIG_PNPBIOS=y
+CONFIG_PNPBIOS_PROC_FS=y
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV_FD=m
+CONFIG_BLK_DEV_XD=m
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_BPCK6=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+# CONFIG_PARIDE_EPATC8 is not set
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_CMD640=y
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_RZ1000=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_ATIIXP=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5520=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+CONFIG_PDC202XX_BURST=y
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SIS5513=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+CONFIG_SCSI_DPT_I2O=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_IN2000=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_DTC3280=m
+CONFIG_SCSI_EATA=m
+CONFIG_SCSI_EATA_TAGGED_QUEUE=y
+CONFIG_SCSI_EATA_LINKED_COMMANDS=y
+CONFIG_SCSI_EATA_MAX_TAGS=16
+CONFIG_SCSI_EATA_PIO=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+CONFIG_SCSI_GENERIC_NCR5380=m
+CONFIG_SCSI_GENERIC_NCR5380_MMIO=m
+CONFIG_SCSI_GENERIC_NCR53C400=y
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_SCSI_NCR53C406A=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_PAS16=m
+CONFIG_SCSI_PSI240I=m
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_FC=m
+CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_LPFC=m
+# CONFIG_SCSI_SEAGATE is not set
+CONFIG_SCSI_SYM53C416=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_T128=m
+CONFIG_SCSI_U14_34F=m
+CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y
+CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y
+CONFIG_SCSI_U14_34F_MAX_TAGS=8
+CONFIG_SCSI_ULTRASTOR=m
+CONFIG_SCSI_NSP32=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+CONFIG_CD_NO_IDESCSI=y
+CONFIG_AZTCD=m
+CONFIG_GSCD=m
+CONFIG_MCDX=m
+CONFIG_OPTCD=m
+CONFIG_SJCD=m
+CONFIG_ISP16_CDI=m
+CONFIG_CDU535=m
+CONFIG_DM_MULTIPATH_EMC=m
+CONFIG_FUSION_LAN=m
+CONFIG_IEEE1394=m
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_IEEE1394_PCILYNX=m
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+# CONFIG_IP_PNP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+CONFIG_ATM=y
+CONFIG_ATM_CLIP=y
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=y
+CONFIG_LLC2=m
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+# CONFIG_NET_DIVERT is not set
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+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=m
+CONFIG_NET_SCH_ATM=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_BPQETHER=m
+CONFIG_SCC=m
+# CONFIG_SCC_DELAY is not set
+# CONFIG_SCC_TRXECHO is not set
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_BAYCOM_EPP=m
+CONFIG_YAM=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+CONFIG_IRTTY_SIR=m
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+CONFIG_WINBOND_FIR=m
+CONFIG_TOSHIBA_FIR=m
+CONFIG_SMC_IRCC_FIR=m
+CONFIG_ALI_FIR=m
+CONFIG_VLSI_FIR=m
+CONFIG_VIA_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_DUMMY=m
+CONFIG_NET_SB1000=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+CONFIG_ARCNET_COM90xx=m
+CONFIG_ARCNET_COM90xxIO=m
+CONFIG_ARCNET_RIM_I=m
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_ISA=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+CONFIG_NI52=m
+CONFIG_NI65=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+CONFIG_AT1700=m
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+CONFIG_NET_ISA=y
+CONFIG_E2100=m
+CONFIG_EWRK3=m
+CONFIG_EEXPRESS=m
+CONFIG_EEXPRESS_PRO=m
+CONFIG_HPLAN_PLUS=m
+CONFIG_HPLAN=m
+CONFIG_LP486E=m
+CONFIG_ETH16I=m
+CONFIG_NE2000=m
+CONFIG_ZNET=m
+CONFIG_SEEQ8005=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+CONFIG_8139TOO_TUNE_TWISTER=y
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_ATP=m
+CONFIG_DE600=m
+CONFIG_DE620=m
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_R8169_VLAN=y
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+CONFIG_IXGB=m
+CONFIG_S2IO=m
+CONFIG_TR=y
+CONFIG_IBMTR=m
+CONFIG_IBMOL=m
+CONFIG_IBMLS=m
+CONFIG_3C359=m
+CONFIG_TMS380TR=m
+CONFIG_TMSPCI=m
+CONFIG_SKISA=m
+CONFIG_PROTEON=m
+CONFIG_ABYSS=m
+CONFIG_NET_RADIO=y
+CONFIG_STRIP=m
+CONFIG_ARLAN=m
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_ARCNET_COM20020_CS=m
+CONFIG_PCMCIA_IBMTR=m
+CONFIG_WAN=y
+CONFIG_HOSTESS_SV11=m
+CONFIG_COSA=m
+CONFIG_DSCC4=m
+CONFIG_DSCC4_PCISYNC=y
+CONFIG_DSCC4_PCI_RST=y
+CONFIG_LANMEDIA=m
+CONFIG_SEALEVEL_4021=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW_ETH=y
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+CONFIG_HDLC_X25=y
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300=m
+CONFIG_PC300_MLPPP=y
+CONFIG_N2=m
+CONFIG_C101=m
+CONFIG_FARSYNC=m
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_SDLA=m
+CONFIG_WAN_ROUTER_DRIVERS=y
+CONFIG_CYCLADES_SYNC=m
+CONFIG_CYCLOMX_X25=y
+CONFIG_LAPBETHER=m
+CONFIG_X25_ASY=m
+CONFIG_SBNI=m
+# CONFIG_SBNI_MULTILINE is not set
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+CONFIG_ATM_ZATM=m
+# CONFIG_ATM_ZATM_DEBUG is not set
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+CONFIG_ATM_IA=m
+# CONFIG_ATM_IA_DEBUG is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+CONFIG_ATM_FORE200E_PCA=y
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y
+# CONFIG_ATM_FORE200E_USE_TASKLET is not set
+CONFIG_ATM_FORE200E_TX_RETRY=16
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+CONFIG_FDDI=y
+CONFIG_DEFXX=m
+CONFIG_SKFP=m
+CONFIG_HIPPI=y
+CONFIG_ROADRUNNER=m
+# CONFIG_ROADRUNNER_LARGE_RINGS is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_NET_FC=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+CONFIG_ISDN=m
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+CONFIG_ISDN_PPP_BSDCOMP=m
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+CONFIG_ISDN_X25=y
+# CONFIG_ISDN_DIVERSION is not set
+CONFIG_ISDN_DRV_HISAX=m
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+# CONFIG_HISAX_NO_SENDCOMPLETE is not set
+# CONFIG_HISAX_NO_LLC is not set
+# CONFIG_HISAX_NO_KEYPAD is not set
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_HFC4S8S=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_SC=m
+CONFIG_ISDN_DRV_ACT2000=m
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+CONFIG_CAPI_AVM=y
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
+CONFIG_PHONE_IXJ_PCMCIA=m
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_TSDEV=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_INPORT=m
+# CONFIG_MOUSE_ATIXL is not set
+CONFIG_MOUSE_LOGIBM=m
+CONFIG_MOUSE_PC110PAD=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_CT82C710=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_ROCKETPORT=m
+CONFIG_CYCLADES=m
+# CONFIG_CYZ_INTR is not set
+# CONFIG_ESPSERIAL is not set
+CONFIG_MOXA_SMARTIO=m
+# CONFIG_ISI is not set
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+CONFIG_STALDRV=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_SC520_WDT=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_I8XX_TCO=m
+CONFIG_SC1200_WDT=m
+CONFIG_SCx200_WDT=m
+CONFIG_60XX_WDT=m
+CONFIG_CPU5_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_MACHZ_WDT=m
+CONFIG_PCWATCHDOG=m
+CONFIG_MIXCOMWD=m
+CONFIG_WDT=m
+CONFIG_WDT_501=y
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+CONFIG_USBPCWATCHDOG=m
+CONFIG_NVRAM=m
+CONFIG_RTC=m
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+CONFIG_APPLICOM=m
+CONFIG_SONYPI=m
+CONFIG_AGP=m
+CONFIG_AGP_ALI=m
+CONFIG_AGP_ATI=m
+CONFIG_AGP_AMD=m
+CONFIG_AGP_AMD64=m
+CONFIG_AGP_INTEL=m
+CONFIG_AGP_NVIDIA=m
+CONFIG_AGP_SIS=m
+CONFIG_AGP_SWORKS=m
+CONFIG_AGP_VIA=m
+CONFIG_AGP_EFFICEON=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I830=m
+CONFIG_DRM_I915=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+CONFIG_SYNCLINK_CS=m
+CONFIG_MWAVE=m
+CONFIG_SCx200_GPIO=m
+CONFIG_RAW_DRIVER=m
+CONFIG_HPET=y
+# CONFIG_HPET_RTC_IRQ is not set
+CONFIG_HPET_MMAP=y
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_HANGCHECK_TIMER=m
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD756_S4882=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_PARPORT=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+CONFIG_SCx200_I2C=m
+CONFIG_SCx200_I2C_SCL=12
+CONFIG_SCx200_I2C_SDA=13
+CONFIG_SCx200_ACB=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+CONFIG_I2C_PCA_ISA=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_FSCPOS=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_DS1337=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_W1=m
+CONFIG_IBM_ASM=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+# CONFIG_VIDEO_ZR36120 is not set
+CONFIG_VIDEO_MEYE=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_RADIO_MIROPCM20=m
+CONFIG_RADIO_MIROPCM20_RDS=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_SF16FMR2=m
+CONFIG_RADIO_TERRATEC=m
+CONFIG_RADIO_TRUST=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+CONFIG_DVB_BT8XX=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BUF_DVB=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=m
+CONFIG_FB_VESA=y
+CONFIG_FB_HGA=m
+# CONFIG_FB_HGA_ACCEL is not set
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_I810=m
+# CONFIG_FB_I810_GTF is not set
+CONFIG_FB_INTEL=m
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GENERIC_LCD=y
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SAVAGE_I2C=y
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+# CONFIG_FB_PM3 is not set
+CONFIG_FB_GEODE=y
+CONFIG_FB_GEODE_GX=m
+CONFIG_FB_GEODE_GX1=m
+CONFIG_FB_S1D13XXX=m
+CONFIG_FB_VIRTUAL=m
+CONFIG_VGA_CONSOLE=y
+CONFIG_MDA_CONSOLE=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL4_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_ADLIB=m
+CONFIG_SND_AD1848_LIB=m
+CONFIG_SND_CS4231_LIB=m
+CONFIG_SND_AD1816A=m
+CONFIG_SND_AD1848=m
+CONFIG_SND_CS4231=m
+CONFIG_SND_CS4232=m
+CONFIG_SND_CS4236=m
+CONFIG_SND_ES968=m
+CONFIG_SND_ES1688=m
+CONFIG_SND_ES18XX=m
+CONFIG_SND_GUS_SYNTH=m
+CONFIG_SND_GUSCLASSIC=m
+CONFIG_SND_GUSEXTREME=m
+CONFIG_SND_GUSMAX=m
+CONFIG_SND_INTERWAVE=m
+CONFIG_SND_INTERWAVE_STB=m
+CONFIG_SND_OPTI92X_AD1848=m
+CONFIG_SND_OPTI92X_CS4231=m
+CONFIG_SND_OPTI93X=m
+CONFIG_SND_MIRO=m
+CONFIG_SND_SB8=m
+CONFIG_SND_SB16=m
+CONFIG_SND_SBAWE=m
+CONFIG_SND_SB16_CSP=y
+CONFIG_SND_WAVEFRONT=m
+CONFIG_SND_ALS100=m
+CONFIG_SND_AZT2320=m
+CONFIG_SND_CMI8330=m
+CONFIG_SND_DT019X=m
+CONFIG_SND_OPL3SA2=m
+CONFIG_SND_SGALAXY=m
+CONFIG_SND_SSCAPE=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_USX2Y=m
+CONFIG_SOUND_PRIME=m
+CONFIG_SOUND_BT878=m
+CONFIG_SOUND_EMU10K1=m
+CONFIG_MIDI_EMU10K1=y
+CONFIG_SOUND_FUSION=m
+CONFIG_SOUND_ES1371=m
+CONFIG_SOUND_ICH=m
+CONFIG_SOUND_TRIDENT=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_VIA82CXXX=m
+CONFIG_MIDI_VIA82CXXX=y
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+CONFIG_SOUND_AD1889=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_ACI_MIXER=m
+CONFIG_SOUND_CS4232=m
+CONFIG_SOUND_SSCAPE=m
+CONFIG_SOUND_VMIDI=m
+CONFIG_SOUND_TRIX=m
+CONFIG_SOUND_MSS=m
+CONFIG_SOUND_MPU401=m
+CONFIG_SOUND_NM256=m
+CONFIG_SOUND_PAS=m
+CONFIG_SOUND_PSS=m
+CONFIG_PSS_MIXER=y
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_YM3812=m
+CONFIG_SOUND_OPL3SA2=m
+CONFIG_SOUND_UART6850=m
+CONFIG_SOUND_AEDSP16=m
+CONFIG_SC6600=y
+CONFIG_SC6600_JOY=y
+CONFIG_SC6600_CDROM=4
+CONFIG_SC6600_CDROMBASE=0x0
+# CONFIG_AEDSP16_MSS is not set
+# CONFIG_AEDSP16_SBPRO is not set
+# CONFIG_AEDSP16_MPU401 is not set
+CONFIG_SOUND_TVMIXER=m
+CONFIG_SOUND_KAHLUA=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_PWC=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZD1201=m
+CONFIG_USB_USS720=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_NET2280=m
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_WBSD=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_JBD=m
+CONFIG_XFS_RT=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_JFFS_FS=m
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
+CONFIG_ACORN_PARTITION_ICS=y
+# CONFIG_ACORN_PARTITION_ADFS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+# CONFIG_KPROBES is not set
+# CONFIG_4KSTACKS is not set
+CONFIG_X86_FIND_SMP_CONFIG=y
+CONFIG_X86_MPPARSE=y
+CONFIG_CRYPTO_AES_586=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_REED_SOLOMON=m
+CONFIG_REED_SOLOMON_DEC16=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_KEXEC=y
+CONFIG_PHYSICAL_START=0x100000
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_CX88=m
+CONFIG_SENSORS_HDAPS=m
+CONFIG_DCDBAS=m
+CONFIG_IBMASR=m
+CONFIG_SBC8360_WDT=m
+CONFIG_W83977F_WDT=m
+CONFIG_I6300ESB_WDT=m
+CONFIG_X86_32=y
+CONFIG_BLK_DEV_CS5535=m
+CONFIG_PM_LEGACY=y
+CONFIG_INPUT_WISTRON_BTNS=m
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_KTIME_SCALAR=y
+CONFIG_DOUBLEFAULT=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_CS5535_GPIO=m
+# CONFIG_MGEODE_LX is not set
+CONFIG_SND_CS5535AUDIO=m
+CONFIG_VM86=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_I82875P=m
+CONFIG_EDAC_AMD76X=m
+CONFIG_EDAC_E7XXX=m
+CONFIG_EDAC=m
+CONFIG_EDAC_MM_EDAC=m
+CONFIG_EDAC_POLL=y
+# CONFIG_VMSPLIT_3G is not set
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_EDAC_I82860=m
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_EDAC_E752X=m
+CONFIG_EDAC_R82600=m
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
+CONFIG_EFI_VARS=m
+CONFIG_BOOT_IOREMAP=y
+CONFIG_EFI=y
+CONFIG_HW_RANDOM_INTEL=m
+CONFIG_K8_NB=y
+CONFIG_GENERIC_TIME=y
+CONFIG_HW_RANDOM_GEODE=m
+CONFIG_INTEL_IOATDMA=m
+CONFIG_SCx200HR_TIMER=m
+# CONFIG_FB_IMAC is not set
+CONFIG_ACPI_SBS=m
+CONFIG_HW_RANDOM_AMD=m
+CONFIG_COMPAT_VDSO=y
+CONFIG_HW_RANDOM_VIA=m
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SX=m
Added: people/maks-guest/linux-2.6/debian/arch/i386/config.486
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/config.486 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,112 @@
+CONFIG_M486=y
+# CONFIG_M686 is not set
+# CONFIG_MK7 is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_INTEL_USERCOPY=y
+# CONFIG_SMP is not set
+CONFIG_X86_UP_APIC=y
+CONFIG_X86_UP_IOAPIC=y
+# CONFIG_X86_MCE is not set
+CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_EISA=y
+CONFIG_EISA_VLB_PRIMING=y
+CONFIG_EISA_PCI_EISA=y
+CONFIG_EISA_VIRTUAL_ROOT=y
+CONFIG_EISA_NAMES=y
+CONFIG_MCA=y
+CONFIG_MCA_LEGACY=y
+# CONFIG_MCA_PROC_FS is not set
+CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y
+# CONFIG_MTD_XIP is not set
+CONFIG_BLK_DEV_PS2=m
+CONFIG_SCSI_FD_MCS=m
+CONFIG_SCSI_IBMMCA=m
+CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y
+# CONFIG_IBMMCA_SCSI_DEV_RESET is not set
+CONFIG_SCSI_NCR_D700=m
+CONFIG_SCSI_NCR_Q720=m
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+CONFIG_SCSI_MCA_53C9X=m
+CONFIG_SCSI_SIM710=m
+CONFIG_53C700_IO_MAPPED=y
+CONFIG_SBPCD=m
+CONFIG_CM206=m
+CONFIG_CDU31A=m
+CONFIG_DMASCC=m
+CONFIG_IRPORT_SIR=m
+# CONFIG_DONGLE_OLD is not set
+CONFIG_ELMC=m
+CONFIG_ELMC_II=m
+CONFIG_ULTRAMCA=m
+CONFIG_ULTRA32=m
+CONFIG_NI5010=m
+CONFIG_PCMCIA_XIRTULIP=m
+# CONFIG_SKMC is not set
+CONFIG_NE2_MCA=m
+CONFIG_IBMLANA=m
+CONFIG_LNE390=m
+CONFIG_NE3210=m
+CONFIG_ES3210=m
+CONFIG_MADGEMC=m
+CONFIG_ISDN_DRV_LOOP=m
+CONFIG_HYSDN=m
+CONFIG_HYSDN_CAPI=y
+CONFIG_ISDN_DRV_AVMB1_B1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_T1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+CONFIG_COMPUTONE=m
+CONFIG_DIGIEPCA=m
+CONFIG_MOXA_INTELLIO=m
+CONFIG_RIO=m
+CONFIG_RIO_OLDPCI=y
+CONFIG_STALLION=m
+CONFIG_ISTALLION=m
+CONFIG_FTAPE=m
+CONFIG_ZFTAPE=m
+CONFIG_ZFT_DFLT_BLK_SZ=10240
+CONFIG_ZFT_COMPRESSOR=m
+CONFIG_FT_NR_BUFFERS=3
+CONFIG_FT_PROC_FS=y
+CONFIG_FT_NORMAL_DEBUG=y
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+CONFIG_FT_STD_FDC=y
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
+CONFIG_FT_FDC_THR=8
+CONFIG_FT_FDC_MAX_RATE=2000
+CONFIG_FT_ALPHA_CLOCK=0
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_STUB=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_EXT2_FS=y
+CONFIG_FS_MBCACHE=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_M386 is not set
+CONFIG_X86_POPAD_OK=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_XADD=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_ALIGNMENT_16=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_BROKEN_ON_SMP=y
Added: people/maks-guest/linux-2.6/debian/arch/i386/config.686
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/config.686 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,71 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_M386 is not set
+CONFIG_M686=y
+# CONFIG_MK7 is not set
+# CONFIG_X86_GENERIC is not set
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=5
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_X86_TSC=y
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_NONFATAL=m
+CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_NOHIGHMEM is not set
+CONFIG_HIGHMEM4G=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_IRQBALANCE=y
+CONFIG_HAVE_DEC_LOCK=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_SBPCD is not set
+# CONFIG_CM206 is not set
+# CONFIG_CDU31A is not set
+# CONFIG_DMASCC is not set
+# CONFIG_IRPORT_SIR is not set
+# CONFIG_NI5010 is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_HYSDN is not set
+# CONFIG_ISDN_DRV_AVMB1_B1ISA is not set
+# CONFIG_ISDN_DRV_AVMB1_B1PCI is not set
+# CONFIG_ISDN_DRV_AVMB1_T1ISA is not set
+# CONFIG_ISDN_DRV_AVMB1_B1PCMCIA is not set
+# CONFIG_ISDN_DRV_AVMB1_T1PCI is not set
+# CONFIG_ISDN_DRV_AVMB1_C4 is not set
+# CONFIG_COMPUTONE is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_RIO is not set
+# CONFIG_STALLION is not set
+# CONFIG_ISTALLION is not set
+# CONFIG_FTAPE is not set
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_STUB=m
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_X86_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_TRAMPOLINE=y
+CONFIG_X86_CMPXCHG64=y
+# CONFIG_M486 is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_SUSPEND_SMP=y
+CONFIG_ACPI_HOTPLUG_CPU=y
Added: people/maks-guest/linux-2.6/debian/arch/i386/config.686-bigmem
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/config.686-bigmem Sat Nov 11 02:48:00 2006
@@ -0,0 +1,71 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_M386 is not set
+CONFIG_M686=y
+# CONFIG_MK7 is not set
+# CONFIG_X86_GENERIC is not set
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=5
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=32
+CONFIG_X86_TSC=y
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_NONFATAL=m
+CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_NOHIGHMEM is not set
+# CONFIG_HIGHMEM4G is not set
+CONFIG_HIGHMEM64G=y
+CONFIG_HIGHMEM=y
+CONFIG_X86_PAE=y
+# CONFIG_HIGHPTE is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_IRQBALANCE=y
+CONFIG_HAVE_DEC_LOCK=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_SBPCD is not set
+# CONFIG_CM206 is not set
+# CONFIG_CDU31A is not set
+# CONFIG_DMASCC is not set
+# CONFIG_IRPORT_SIR is not set
+# CONFIG_NI5010 is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_HYSDN is not set
+# CONFIG_ISDN_DRV_AVMB1_B1ISA is not set
+# CONFIG_ISDN_DRV_AVMB1_B1PCI is not set
+# CONFIG_ISDN_DRV_AVMB1_T1ISA is not set
+# CONFIG_ISDN_DRV_AVMB1_B1PCMCIA is not set
+# CONFIG_ISDN_DRV_AVMB1_T1PCI is not set
+# CONFIG_ISDN_DRV_AVMB1_C4 is not set
+# CONFIG_COMPUTONE is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALLION is not set
+# CONFIG_ISTALLION is not set
+# CONFIG_FTAPE is not set
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_STUB=m
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_X86_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_TRAMPOLINE=y
+CONFIG_X86_CMPXCHG64=y
+# CONFIG_M486 is not set
Added: people/maks-guest/linux-2.6/debian/arch/i386/config.k7
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/config.k7 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,72 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_M386 is not set
+# CONFIG_M686 is not set
+CONFIG_MK7=y
+# CONFIG_X86_GENERIC is not set
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_USE_3DNOW=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_X86_TSC=y
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_NONFATAL=m
+CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_NOHIGHMEM is not set
+CONFIG_HIGHMEM4G=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_IRQBALANCE=y
+CONFIG_HAVE_DEC_LOCK=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_SBPCD is not set
+# CONFIG_CM206 is not set
+# CONFIG_CDU31A is not set
+# CONFIG_DMASCC is not set
+# CONFIG_IRPORT_SIR is not set
+# CONFIG_NI5010 is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_HYSDN is not set
+# CONFIG_ISDN_DRV_AVMB1_B1ISA is not set
+# CONFIG_ISDN_DRV_AVMB1_B1PCI is not set
+# CONFIG_ISDN_DRV_AVMB1_T1ISA is not set
+# CONFIG_ISDN_DRV_AVMB1_B1PCMCIA is not set
+# CONFIG_ISDN_DRV_AVMB1_T1PCI is not set
+# CONFIG_ISDN_DRV_AVMB1_C4 is not set
+# CONFIG_COMPUTONE is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_RIO is not set
+# CONFIG_STALLION is not set
+# CONFIG_ISTALLION is not set
+# CONFIG_FTAPE is not set
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_STUB=m
+CONFIG_USB_W9968CF=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_X86_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_TRAMPOLINE=y
+CONFIG_X86_CMPXCHG64=y
+# CONFIG_M486 is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_SUSPEND_SMP=y
+CONFIG_ACPI_HOTPLUG_CPU=y
Added: people/maks-guest/linux-2.6/debian/arch/i386/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,42 @@
+[base]
+flavours:
+ 486
+ 686
+ k7
+ 686-bigmem
+kernel-arch: i386
+kernel-header-dirs: i386
+subarches:
+# vserver
+# xen
+# xen-vserver
+
+[image]
+conflicts: grub (<= 0.95+cvs20040624-17)
+suggests: grub (>= 0.97-3) | lilo (>= 19.1)
+
+[486]
+class: x86
+longclass: x86 and compatible
+
+[686]
+class: PPro/Celeron/PII/PIII/P4
+longclass: Pentium Pro/Celeron/Pentium II/Pentium III/Pentium 4
+
+[686_image]
+recommends: libc6-i686
+
+[686-bigmem]
+class: PPro/Celeron/PII/PIII/P4
+longclass: Pentium Pro/Celeron/Pentium II/Pentium III/Pentium 4 with 4-64G RAM
+
+[686-bigmem_image]
+recommends: libc6-i686
+
+[k7]
+class: AMD K7
+longclass: 32bit AMD Duron/Athlon/AthlonXP
+
+[k7_image]
+recommends: libc6-i686
+
Added: people/maks-guest/linux-2.6/debian/arch/i386/vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+[base]
+flavours:
+ 686
+ k7
+
+[image]
+configs: _vserver/config
+recommends: util-vserver, libc6-i686
+
+[686_image]
+configs: i386/config.686
+
+[k7_image]
+configs: i386/config.k7
+
Added: people/maks-guest/linux-2.6/debian/arch/i386/xen-vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/xen-vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,20 @@
+[base]
+flavours:
+ 686
+
+[image]
+configs:
+ _vserver/config
+ i386/xen/config
+ _xen/config
+initramfs-generators: initramfs-tools
+recommends: libc6-xen
+suggests: grub (>= 0.97-16)
+type: plain-xen
+
+[xen]
+flavour: i386
+
+[686_image]
+configs: i386/config.686
+
Added: people/maks-guest/linux-2.6/debian/arch/i386/xen/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/xen/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,2 @@
+# CONFIG_X86_PC is not set
+CONFIG_X86_XEN=y
Added: people/maks-guest/linux-2.6/debian/arch/i386/xen/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/i386/xen/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,21 @@
+[base]
+flavours:
+ 686
+ k7
+
+[image]
+configs: i386/xen/config _xen/config
+initramfs-generators: initramfs-tools
+recommends: libc6-xen
+suggests: grub (>= 0.97-16)
+type: plain-xen
+
+[xen]
+flavour: i386
+
+[686_image]
+configs: i386/config.686
+
+[k7_image]
+configs: i386/config.k7
+
Added: people/maks-guest/linux-2.6/debian/arch/ia64/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/ia64/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/ia64/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/ia64/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1268 @@
+CONFIG_CLEAN_COMPILE=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_IA64=y
+CONFIG_64BIT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_TIME_INTERPOLATION=y
+CONFIG_EFI=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_IA64_GENERIC=y
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_PGTABLE_3=y
+# CONFIG_PGTABLE_4 is not set
+CONFIG_NUMA=y
+CONFIG_VIRTUAL_MEM_MAP=y
+CONFIG_HOLES_IN_ZONE=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+# CONFIG_IA64_CYCLONE is not set
+CONFIG_IOSAPIC=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_IA64_SGI_SN_XP=m
+CONFIG_FORCE_MAX_ZONEORDER=17
+CONFIG_IA32_SUPPORT=y
+CONFIG_COMPAT=y
+CONFIG_IA64_MCA_RECOVERY=m
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_ACPI_DEALLOCATE_IRQ=y
+CONFIG_EFI_VARS=m
+CONFIG_EFI_PCDP=y
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+CONFIG_ACPI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_VIDEO=m
+CONFIG_ACPI_HOTKEY=m
+CONFIG_ACPI_FAN=m
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_THERMAL=m
+CONFIG_ACPI_NUMA=y
+CONFIG_ACPI_BLACKLIST_YEAR=0
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_ACPI_CONTAINER=m
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI_FAKE=m
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI_ACPI_IBM=m
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HOTPLUG_PCI_SGI=m
+# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+# CONFIG_YENTA is not set
+CONFIG_PD6729=m
+# CONFIG_I82092 is not set
+CONFIG_TCIC=m
+CONFIG_PCCARD_NONSTATIC=m
+CONFIG_STANDALONE=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PCI=m
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLKMTD=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_DOC2000=m
+CONFIG_MTD_DOC2001=m
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0
+# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+CONFIG_PNPACPI=y
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPATC8=y
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=m
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+CONFIG_WDC_ALI15X3=y
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5520=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+# CONFIG_PDC202XX_FORCE is not set
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SGIIOC4=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_DMX3191D=m
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_QLOGIC_FC=m
+CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLOGIC_1280_1040=y
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+CONFIG_DM_MULTIPATH_EMC=m
+CONFIG_FUSION_LAN=m
+CONFIG_IEEE1394=m
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_IEEE1394_PCILYNX=m
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+CONFIG_BRIDGE_NETFILTER=y
+CONFIG_DECNET_NF_GRABULATOR=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=y
+CONFIG_LLC2=m
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+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=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_AX25_DAMA_SLAVE=y
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_YAM=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+CONFIG_IRTTY_SIR=m
+# CONFIG_DONGLE is not set
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+# CONFIG_VLSI_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+# CONFIG_BT_RFCOMM_TTY is not set
+CONFIG_BT_BNEP=m
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+CONFIG_BT_HCIUART=m
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_DUMMY=m
+CONFIG_NET_SB1000=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+# CONFIG_ARCNET_COM90xx is not set
+CONFIG_ARCNET_COM90xxIO=m
+# CONFIG_ARCNET_RIM_I is not set
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_PCI=m
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_R8169_VLAN=y
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+CONFIG_IXGB=m
+CONFIG_S2IO=m
+# CONFIG_2BUFF_MODE is not set
+CONFIG_TR=y
+CONFIG_IBMOL=m
+CONFIG_3C359=m
+# CONFIG_TMS380TR is not set
+CONFIG_NET_RADIO=y
+CONFIG_STRIP=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_ARCNET_COM20020_CS=m
+CONFIG_WAN=y
+CONFIG_DSCC4=m
+# CONFIG_DSCC4_PCISYNC is not set
+# CONFIG_DSCC4_PCI_RST is not set
+CONFIG_LANMEDIA=m
+CONFIG_SYNCLINK_SYNCPPP=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW_ETH=y
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300=m
+CONFIG_PC300_MLPPP=y
+CONFIG_FARSYNC=m
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_WAN_ROUTER_DRIVERS=y
+# CONFIG_CYCLADES_SYNC is not set
+CONFIG_FDDI=y
+CONFIG_DEFXX=m
+CONFIG_SKFP=m
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_NET_FC=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+# CONFIG_ISDN is not set
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
+CONFIG_PHONE_IXJ_PCMCIA=m
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_TSDEV=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+# CONFIG_JOYSTICK_IFORCE_USB is not set
+# CONFIG_JOYSTICK_IFORCE_232 is not set
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_JOYSTICK_JOYDUMP=m
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461X=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_COMPUTONE=m
+CONFIG_ROCKETPORT=m
+# CONFIG_CYCLADES is not set
+CONFIG_MOXA_INTELLIO=m
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+CONFIG_SPECIALIX=m
+# CONFIG_SPECIALIX_RTSCTS is not set
+CONFIG_SX=m
+CONFIG_STALDRV=y
+CONFIG_SGI_SNSC=y
+CONFIG_SGI_TIOCX=y
+CONFIG_SGI_MBCS=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_ACPI=y
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_MULTIPORT=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_SGI_L1_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_SGI_IOC3=m
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+# CONFIG_WATCHDOG is not set
+CONFIG_EFI_RTC=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+CONFIG_APPLICOM=m
+CONFIG_AGP=m
+CONFIG_AGP_I460=m
+CONFIG_AGP_HP_ZX1=m
+CONFIG_AGP_SGI_TIOCA=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+CONFIG_SYNCLINK_CS=m
+CONFIG_RAW_DRIVER=m
+# CONFIG_HPET is not set
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_HANGCHECK_TIMER=m
+# CONFIG_MMTIMER is not set
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD756_S4882=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_PARPORT=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+CONFIG_SCx200_ACB=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_STUB=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+CONFIG_I2C_PCA_ISA=m
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_FSCPOS=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_DS1337=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_W1=m
+CONFIG_W1_MATROX=m
+CONFIG_W1_DS9490=m
+CONFIG_W1_DS9490_BRIDGE=m
+CONFIG_W1_THERM=m
+CONFIG_W1_SMEM=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_DIBUSB=m
+CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES=y
+# CONFIG_DVB_DIBCOM_DEBUG is not set
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+CONFIG_DVB_B2C2_SKYSTAR=m
+CONFIG_DVB_BT8XX=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA80XX=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+CONFIG_DVB_NXT2002=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BUF_DVB=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_PM2=m
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_CYBER2000=m
+CONFIG_FB_ASILIANT=y
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_RADEON_OLD=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GENERIC_LCD=y
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SAVAGE_I2C=y
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+CONFIG_FB_S1D13XXX=m
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SOUND_PRIME=m
+CONFIG_SOUND_BT878=m
+CONFIG_SOUND_CMPCI=m
+CONFIG_SOUND_EMU10K1=m
+# CONFIG_MIDI_EMU10K1 is not set
+CONFIG_SOUND_FUSION=m
+CONFIG_SOUND_CS4281=m
+CONFIG_SOUND_ES1370=m
+CONFIG_SOUND_ES1371=m
+CONFIG_SOUND_ESSSOLO1=m
+CONFIG_SOUND_MAESTRO=m
+CONFIG_SOUND_MAESTRO3=m
+CONFIG_SOUND_ICH=m
+CONFIG_SOUND_SONICVIBES=m
+CONFIG_SOUND_TRIDENT=m
+CONFIG_SOUND_MSNDCLAS=m
+CONFIG_MSNDCLAS_INIT_FILE="m"
+CONFIG_MSNDCLAS_PERM_FILE="m"
+CONFIG_SOUND_MSNDPIN=m
+CONFIG_MSNDPIN_INIT_FILE="m"
+CONFIG_MSNDPIN_PERM_FILE="m"
+CONFIG_SOUND_VIA82CXXX=m
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+CONFIG_SOUND_TVMIXER=m
+CONFIG_SOUND_ALI5455=m
+CONFIG_SOUND_FORTE=m
+CONFIG_SOUND_RME96XX=m
+CONFIG_SOUND_AD1980=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_HID_FF=y
+# CONFIG_HID_PID is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_THRUSTMASTER_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_PWC=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+CONFIG_USB_AX8817X=y
+CONFIG_USB_ZD1201=m
+CONFIG_USB_USS720=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_TEST=m
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_SGI_IOC3=m
+CONFIG_JBD=m
+CONFIG_FS_MBCACHE=m
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_ASFS_FS=m
+CONFIG_ASFS_DEFAULT_CODEPAGE=""
+# CONFIG_ASFS_RW is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_JFFS_FS=m
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_JFFS2_FS_NOR_ECC=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+CONFIG_CODA_FS_OLD_API=y
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+CONFIG_ACORN_PARTITION_EESOX=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_ADFS=y
+CONFIG_ACORN_PARTITION_POWERTEC=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_REED_SOLOMON=m
+CONFIG_REED_SOLOMON_DEC16=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_HP_SIMETH is not set
+# CONFIG_HP_SIMSERIAL is not set
+# CONFIG_HP_SIMSCSI is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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 is not set
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_DIGIEPCA=m
+# CONFIG_CPU_FREQ is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_IPW2100 is not set
+CONFIG_RIO=m
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_DMA_IS_DMA32=y
+CONFIG_NODES_SHIFT=8
+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_AGP_SIS=m
+CONFIG_SWIOTLB=y
+CONFIG_RIO_OLDPCI=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_IA64_UNCACHED_ALLOCATOR=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SGI_SN=y
+CONFIG_MIGRATION=y
+CONFIG_ACPI_EC=y
+CONFIG_AGP_VIA=m
+# CONFIG_BLK_DEV_IDEPNP is not set
Added: people/maks-guest/linux-2.6/debian/arch/ia64/config.itanium
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/ia64/config.itanium Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+CONFIG_IA64_BRL_EMU=y
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_DEC_LOCK=y
Added: people/maks-guest/linux-2.6/debian/arch/ia64/config.mckinley
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/ia64/config.mckinley Sat Nov 11 02:48:00 2006
@@ -0,0 +1,10 @@
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
+CONFIG_IA64_L1_CACHE_SHIFT=7
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_DEC_LOCK=y
Added: people/maks-guest/linux-2.6/debian/arch/ia64/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/ia64/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+[base]
+flavours:
+ itanium
+ mckinley
+kernel-arch: ia64
+kernel-header-dirs: ia64
+
+[image]
+suggests: elilo, fdutils
+
+[itanium]
+class: Itanium
+
+[mckinley]
+class: Itanium II
Added: people/maks-guest/linux-2.6/debian/arch/m68k/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/m68k/README.build
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/README.build Sat Nov 11 02:48:00 2006
@@ -0,0 +1,26 @@
+HOWTO cross-build m68k linux-image
+
+Building linux-image packages takes a while, especially on the "slower
+arches", ie m68k. Cross-compiling is an alternative, and it works very well
+for m68k.
+
+You need to set up a cross-compiler. The toolchain-source package has some
+limitations, I prefer using cross-tools, see this page for instructions:
+
+ http://people.debian.org/~cts/debian-m68k/cross-compile/
+
+Now you only have to tell the debian build system, that you do want to build
+packages for m68k. It used to be sufficient to pass an option to debuild,
+since recently you also have to set an environment variable, like this:
+
+ DEB_HOST_ARCH=m68k debuild -B -am68k
+
+If you also want to build source packages, omit the -B.
+
+If you want to build images for just one of the currently nine subarches,
+you can uncomment some lines in the flavours section in:
+ debian/arch/m68k/defines
+
+The first run of debuild will give you an error message that updating the
+configs suceeded, the second run will build the images.
+
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,224 @@
+# we don't trust the compiler, unfortunately, this does not fix the *vme* problems
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# build in SCSI for m68k
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# disable ISCSI to avoid
+# include/scsi/iscsi_if.h:241: error: syntax error before "volatile"
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_ISCSI_TCP is not set
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_SYSCTL=y
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG 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_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
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+# CONFIG_ADVANCED is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_HARDWARE=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_MTD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_MD=y
+CONFIG_NET_KEY=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_ATALK=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+CONFIG_INPUT=y
+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=m
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_I2C is not set
+# CONFIG_W1 is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_ADFS_FS is not set
+CONFIG_ASFS_FS=m
+CONFIG_ASFS_DEFAULT_CODEPAGE=""
+# CONFIG_ASFS_RW is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+# CONFIG_AFS_FS is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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_FRAME_POINTER is not set
+CONFIG_CRC_CCITT=m
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_IEEE80211_CRYPT_WEP is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_IPW2100 is not set
+# new for 2.6.16:
+CONFIG_DM_MULTIPATH_EMC=m
+# CONFIG_SENSORS_F71805F is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.amiga
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.amiga Sat Nov 11 02:48:00 2006
@@ -0,0 +1,197 @@
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+# CONFIG_SUN3 is not set
+CONFIG_AMIGA=y
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+CONFIG_ZORRO=y
+CONFIG_AMIGA_PCMCIA=y
+# CONFIG_HEARTBEAT is not set
+CONFIG_ISA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_ZORRO_NAMES=y
+CONFIG_PARPORT_AMIGA=m
+CONFIG_PARPORT_MFC3=m
+# CONFIG_PNP is not set
+CONFIG_AMIGA_FLOPPY=y
+CONFIG_AMIGA_Z2RAM=y
+# CONFIG_PARIDE is not set
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# disable IDETAPE, causes ICE
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_GAYLE=y
+CONFIG_BLK_DEV_IDEDOUBLER=y
+CONFIG_BLK_DEV_BUDDHA=y
+# 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
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+CONFIG_A3000_SCSI=y
+CONFIG_A2091_SCSI=y
+CONFIG_GVP11_SCSI=y
+CONFIG_CYBERSTORM_SCSI=y
+CONFIG_CYBERSTORMII_SCSI=y
+CONFIG_BLZ2060_SCSI=y
+CONFIG_BLZ1230_SCSI=y
+CONFIG_FASTLANE_SCSI=y
+CONFIG_SCSI_AMIGA7XX=y
+# CONFIG_OKTAGON_SCSI is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+# CONFIG_ARCNET is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_ARIADNE=m
+CONFIG_A2065=m
+CONFIG_HYDRA=m
+CONFIG_ZORRO8390=m
+CONFIG_APNE=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC 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_TR is not set
+CONFIG_PLIP=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_AMIGA=y
+# CONFIG_MOUSE_PS2 is not set
+# 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_AMIGA=y
+CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDJOY is not set
+# CONFIG_JOYSTICK_DB9 is not set
+# CONFIG_JOYSTICK_GAMECON is not set
+# CONFIG_JOYSTICK_TURBOGRAFX is not set
+CONFIG_JOYSTICK_AMIGA=m
+# CONFIG_JOYSTICK_JOYDUMP is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_A2232=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+CONFIG_GEN_RTC=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_CIRRUS=y
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_AMIGA=y
+CONFIG_FB_AMIGA_OCS=y
+CONFIG_FB_AMIGA_ECS=y
+CONFIG_FB_AMIGA_AGA=y
+# CONFIG_FB_CYBER is not set
+# CONFIG_FB_VIRGE is not set
+# CONFIG_FB_RETINAZ3 is not set
+CONFIG_FB_FM2=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_PEARL_8x8=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_DMASOUND_PAULA=m
+CONFIG_DMASOUND=m
+CONFIG_AMIGA_BUILTIN_SERIAL=y
+# CONFIG_WHIPPET_SERIAL is not set
+CONFIG_MULTIFACE_III_TTY=m
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_HUGETLBFS is not set
+CONFIG_AFFS_FS=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_LOCKD=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_AMIGA_PARTITION=y
+CONFIG_CRC32=y
+# 2.6.16
+# temporary workaround for old/buggy(?) 53c7xx.c driver
+CONFIG_SCSI_SPI_ATTRS=y
+# 2.6.18
+# don't try to build lib/audit.c
+# CONFIG_AUDIT is not set
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.atari
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.atari Sat Nov 11 02:48:00 2006
@@ -0,0 +1,103 @@
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+CONFIG_ATARI=y
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+CONFIG_STRAM_PROC=y
+CONFIG_HEARTBEAT=y
+CONFIG_PARPORT_ATARI=m
+CONFIG_ATARI_FLOPPY=y
+# CONFIG_PARIDE is not set
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# disable IDETAPE, causes ICE
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_FALCON_IDE=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_M68K_BEEP=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIAL_8250 is not set
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_ATY=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+CONFIG_SOUND=m
+CONFIG_DMASOUND_ATARI=m
+CONFIG_DMASOUND=m
+CONFIG_ATARI_MFPSER=m
+CONFIG_ATARI_SCC=y
+CONFIG_ATARI_SCC_DMA=y
+CONFIG_ATARI_MIDI=m
+CONFIG_ATARI_DSP56K=m
+# CONFIG_SERIAL_CONSOLE is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=m
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_ATARI_PARTITION=y
+CONFIG_CRC32=y
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.bvme6000
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.bvme6000 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,67 @@
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+CONFIG_VME=y
+# CONFIG_MVME147 is not set
+# CONFIG_MVME16x is not set
+CONFIG_BVME6000=y
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+# CONFIG_M68020 is not set
+# CONFIG_M68030 is not set
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_IDE is not set
+CONFIG_BVME6000_SCSI=y
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_IEEE1394 is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_IPX is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_BVME6000_NET=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_CORE=m
+CONFIG_GEN_RTC=m
+# CONFIG_FB is not set
+# CONFIG_SOUND is not set
+CONFIG_BVME6000_SCC=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_CRC32=m
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.hp
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.hp Sat Nov 11 02:48:00 2006
@@ -0,0 +1,63 @@
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+CONFIG_HP300=y
+# CONFIG_DIO is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+CONFIG_HEARTBEAT=y
+# CONFIG_IDE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_HIL is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_HP_SDC is not set
+# CONFIG_HIL_MLC is not set
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_GEN_RTC=y
+# CONFIG_FB is not set
+# CONFIG_SOUND is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_CRC32=y
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.mac
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.mac Sat Nov 11 02:48:00 2006
@@ -0,0 +1,128 @@
+# CONFIG_WINDFARM is not set
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+CONFIG_MAC=y
+CONFIG_NUBUS=y
+CONFIG_M68K_L2_CACHE=y
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+# CONFIG_M68060 is not set
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_HEARTBEAT is not set
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# disable IDETAPE, causes ICE
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_MAC_IDE=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MAC_SCSI=y
+CONFIG_SCSI_MAC_ESP=y
+CONFIG_ADB=y
+# switched off the next four CONFIG_ADB_* as requested by Finn Thain
+CONFIG_ADB_MACII=n
+CONFIG_ADB_MACIISI=n
+CONFIG_ADB_IOP=n
+CONFIG_ADB_PMU68K=n
+CONFIG_ADB_CUDA=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+# CONFIG_IP_PNP is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MAC8390=y
+CONFIG_MAC89x0=y
+CONFIG_MACSONIC=y # switched back on as requested by Finn Thain
+CONFIG_MACMACE=y
+# CONFIG_NET_VENDOR_SMC is not set
+CONFIG_PPP_FILTER=y
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_GEN_RTC=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_MAC=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_6x11=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_MAC_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_MAC_SCC=y
+CONFIG_MAC_HID=y
+CONFIG_MAC_ADBKEYCODES=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=y
+CONFIG_HFSPLUS_FS=y
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_LOCKD=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+CONFIG_CRC32=y
+# 2.6.18
+# don't try to build lib/audit.c
+# CONFIG_AUDIT is not set
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.mvme147
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.mvme147 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,75 @@
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+CONFIG_VME=y
+CONFIG_MVME147=y
+# CONFIG_MVME16x is not set
+# CONFIG_BVME6000 is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+# CONFIG_M68020 is not set
+CONFIG_M68030=y
+# CONFIG_M68040 is not set
+# CONFIG_M68060 is not set
+CONFIG_MMU_MOTOROLA=y
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_IDE is not set
+CONFIG_MVME147_SCSI=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MVME147_NET=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_GEN_RTC=m
+CONFIG_FB=y
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_MVME147_SCC=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_CRC32=y
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.mvme16x
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.mvme16x Sat Nov 11 02:48:00 2006
@@ -0,0 +1,80 @@
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+CONFIG_VME=y
+# CONFIG_MVME147 is not set
+CONFIG_MVME16x=y
+# CONFIG_BVME6000 is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+# CONFIG_M68020 is not set
+# CONFIG_M68030 is not set
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_IDE is not set
+CONFIG_MVME16x_SCSI=y
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_IEEE1394 is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MVME16x_NET=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_GEN_RTC=m
+CONFIG_FB=y
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_SERIAL167=y
+CONFIG_MVME162_SCC=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_CRC32=y
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.q40
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.q40 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,120 @@
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+CONFIG_Q40=y
+# CONFIG_M68020 is not set
+# CONFIG_M68030 is not set
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_HEARTBEAT is not set
+CONFIG_ISA=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PNP is not set
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# disable IDETAPE, causes ICE
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_Q40IDE=y
+# 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
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+# CONFIG_ARCNET is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC 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_NE2000=m
+# CONFIG_NET_PCI is not set
+# CONFIG_TR is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_Q40KBD=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_GEN_RTC=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_Q40=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_DMASOUND_Q40=y
+CONFIG_DMASOUND=y
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_UFS_FS_WRITE=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_CRC32=y
Added: people/maks-guest/linux-2.6/debian/arch/m68k/config.sun3
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/config.sun3 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,65 @@
+CONFIG_CLEAN_COMPILE=y
+CONFIG_SUN3=y
+CONFIG_M68020=y
+CONFIG_MMU_SUN3=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_IDE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_SUN3LANCE=y
+CONFIG_SUN3_82586=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_SUNKBD=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_MISC is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIAL_8250 is not set
+CONFIG_GEN_RTC=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_UFS_FS_WRITE=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_CRC32=y
+# 2.6.16-14
+# enable SCSI
+CONFIG_SUN3_SCSI=y
Added: people/maks-guest/linux-2.6/debian/arch/m68k/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/m68k/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,46 @@
+[base]
+compiler: gcc-3.3
+flavours:
+ amiga
+# atari
+# bvme6000
+# hp
+ mac
+# mvme147
+# mvme16x
+# q40
+# sun3
+kernel-arch: m68k
+kernel-header-dirs: m68k
+
+[image]
+initramfs: false
+suggests: vmelilo, fdutils
+
+[amiga]
+class: Amiga
+
+[atari]
+class: Atari
+
+[bvme6000]
+class: BVM BVME4000 and BVME6000
+
+[hp]
+class: HP
+
+[mac]
+class: Macintosh
+
+[mvme147]
+class: Motorola MVME147
+
+[mvme16x]
+class: Motorola MVME162/6/7, MVME172/7
+
+[q40]
+class: Q40 and Q60
+
+[sun3]
+class: sun3
+
Added: people/maks-guest/linux-2.6/debian/arch/mips/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/mips/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+CONFIG_MIPS=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
Added: people/maks-guest/linux-2.6/debian/arch/mips/config.qemu
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/config.qemu Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1332 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+CONFIG_QEMU=y
+# CONFIG_MARKEINS is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_COHERENT=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_I8259=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=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_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_ISA=y
+CONFIG_MMU=y
+CONFIG_I8253=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_SECMARK is not set
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+# CONFIG_IP_NF_SIP is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID2=m
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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_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
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+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_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=m
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_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
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+
+#
+# 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=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
+# 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_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+# CONFIG_MD_RAID456 is not set
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_NET_SB1000 is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 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=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=y
+# CONFIG_SEEQ8005 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# 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_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+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=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# 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=m
+# 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=y
+# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_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 is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+# CONFIG_MDA_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
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_RTC_INTF_DEV=m
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=m
+
+#
+# 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=y
+# 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=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+# 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=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_SECLVL is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=m
+CONFIG_LIBCRC32C=m
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
Added: people/maks-guest/linux-2.6/debian/arch/mips/config.r4k-ip22
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/config.r4k-ip22 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1360 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+CONFIG_SGI_IP22=y
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARC=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_ARC32=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_ARC_CONSOLE=y
+CONFIG_ARC_PROMLIB=y
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+CONFIG_CPU_R4X00=y
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_R4X00=y
+CONFIG_SYS_HAS_CPU_R5000=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_BOARD_SCACHE=y
+CONFIG_IP22_CPU_SCACHE=y
+# CONFIG_MIPS_MT is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_EISA=y
+CONFIG_ISA=y
+CONFIG_EISA=y
+CONFIG_EISA_NAMES=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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 is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+CONFIG_SGIWD93_SCSI=y
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP 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
+CONFIG_SGISEEQ=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+
+#
+# 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_PARKBD is not set
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=y
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_IP22_ZILOG=y
+CONFIG_SERIAL_IP22_ZILOG_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_INDYDOG=m
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+CONFIG_RTC=m
+CONFIG_SGI_DS1286=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_ALGO_SGI=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+CONFIG_VIDEO_VINO=m
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_SGI_NEWPORT_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_SGI_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
+CONFIG_SOUND_HAL2=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_TVMIXER 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'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=m
+CONFIG_CRAMFS=y
+# 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_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_VIDEO_BUF=m
+CONFIG_SERIO_I8042=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
Added: people/maks-guest/linux-2.6/debian/arch/mips/config.r5k-ip32
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/config.r5k-ip32 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1495 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+CONFIG_SGI_IP32=y
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARC=y
+CONFIG_DMA_IP32=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_OWN_DMA=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_ARC32=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_ARC_MEMORY=y
+CONFIG_ARC_PROMLIB=y
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+CONFIG_CPU_R5000=y
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_R5000=y
+CONFIG_SYS_HAS_CPU_NEVADA=y
+CONFIG_SYS_HAS_CPU_RM7000=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_BOARD_SCACHE=y
+CONFIG_R5000_CPU_SCACHE=y
+CONFIG_RM7000_CPU_SCACHE=y
+# CONFIG_MIPS_MT is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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 is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT_IP32=m
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC 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
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SGI_O2MACE_ETH=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 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
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_MACEPS2=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=y
+# CONFIG_GAMEPORT 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_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED 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_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_RTC=m
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_ALGO_SGI=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO 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_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_GBE=y
+CONFIG_FB_GBE_MEM=4
+# CONFIG_FB_S1D13XXX 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
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_SGI_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=m
+CONFIG_CRAMFS=y
+# 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_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_SND_OPL3_LIB=m
+# CONFIG_SOUND_ES1371 is not set
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin"
+CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin"
+CONFIG_SOUND_EMU10K1=m
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SOUND_BT878=m
+CONFIG_VIDEO_BUF=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_BT87X_OVERCLOCK=y
+CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin"
+CONFIG_SND_HWDEP=m
+CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin"
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_KORG1212=m
Added: people/maks-guest/linux-2.6/debian/arch/mips/config.sb1-bcm91250a
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/config.sb1-bcm91250a Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1850 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+CONFIG_SIBYTE_SWARM=y
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_SIBYTE_SB1250=y
+CONFIG_SIBYTE_SB1xxx_SOC=y
+# CONFIG_CPU_SB1_PASS_1 is not set
+# CONFIG_CPU_SB1_PASS_2_1250 is not set
+CONFIG_CPU_SB1_PASS_2_2=y
+# CONFIG_CPU_SB1_PASS_4 is not set
+# CONFIG_CPU_SB1_PASS_2_112x is not set
+# CONFIG_CPU_SB1_PASS_3 is not set
+CONFIG_SIBYTE_HAS_LDT=y
+# CONFIG_SIMULATION is not set
+# CONFIG_SB1_CEX_ALWAYS_FATAL is not set
+# CONFIG_SB1_CERR_STALL is not set
+CONFIG_SIBYTE_CFE=y
+# CONFIG_SIBYTE_CFE_CONSOLE is not set
+# CONFIG_SIBYTE_BUS_WATCHER is not set
+# CONFIG_SIBYTE_SB1250_PROF is not set
+# CONFIG_SIBYTE_TBPROF is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_COHERENT=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+CONFIG_CPU_SB1=y
+CONFIG_SYS_HAS_CPU_SB1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_SIBYTE_DMA_PAGEOPS is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+CONFIG_SB1_PASS_2_WORKAROUNDS=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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 is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# 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_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+# CONFIG_BLK_DEV_CS5520 is not set
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_IT821X=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+CONFIG_BLK_DEV_IDE_SWARM=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+# CONFIG_MEGARAID_NEWGEN is not set
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+CONFIG_SCSI_QLOGIC_FC=m
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_DEBUG=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_SB1250_MAC=y
+CONFIG_SBMAC_NAPI=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 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=m
+CONFIG_AMD8111_ETH=m
+# CONFIG_AMD8111E_NAPI is not set
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_ADAPTEC_STARFIRE_NAPI is not set
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_DL2K=m
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+# CONFIG_R8169_NAPI is not set
+CONFIG_SIS190=m
+CONFIG_SKGE=m
+CONFIG_SKY2=m
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+
+#
+# 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SIBYTE_SB1250_DUART=y
+CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_RTC=m
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_ALGO_SIBYTE=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+CONFIG_I2C_SIBYTE=m
+# 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=m
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SENSORS_VT8231=m
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+CONFIG_FB_PM2=m
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=m
+# CONFIG_FB_NVIDIA_I2C is not set
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+CONFIG_FB_RADEON_OLD=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+# CONFIG_FB_ATY_CT is not set
+# CONFIG_FB_ATY_GX is not set
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_AD1889=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_BT87X_OVERCLOCK=y
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_BCM_CS4297A is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_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
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# 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_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_ATI_REMOTE2=m
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_ET61X251=m
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# 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
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_SISUSBVGA_CON is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=m
+CONFIG_CRAMFS=y
+# 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_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+# CONFIG_SB1XXX_CORELIS is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+# CONFIG_SOUND_ES1371 is not set
+CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin"
+CONFIG_USB_NET2280=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin"
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SOUND_EMU10K1=m
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_USB_EPSON2888=y
+CONFIG_SND_VIRMIDI=m
+CONFIG_USB_AN2720=y
+# CONFIG_USB_GADGET_PXA2XX is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_GADGET_OMAP is not set
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_SOUND_BT878=m
+CONFIG_VIDEO_BUF=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin"
+CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin"
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ZERO=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SOUND_TVMIXER=m
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_ACM=m
Added: people/maks-guest/linux-2.6/debian/arch/mips/config.sb1a-bcm91480b
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/config.sb1a-bcm91480b Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1824 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+CONFIG_SIBYTE_BIGSUR=y
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_SIBYTE_BCM1x80=y
+CONFIG_SIBYTE_SB1xxx_SOC=y
+# CONFIG_CPU_SB1_PASS_1 is not set
+# CONFIG_CPU_SB1_PASS_2_1250 is not set
+# CONFIG_CPU_SB1_PASS_2_2 is not set
+# CONFIG_CPU_SB1_PASS_4 is not set
+# CONFIG_CPU_SB1_PASS_2_112x is not set
+# CONFIG_CPU_SB1_PASS_3 is not set
+# CONFIG_SIMULATION is not set
+# CONFIG_SB1_CEX_ALWAYS_FATAL is not set
+# CONFIG_SB1_CERR_STALL is not set
+CONFIG_SIBYTE_CFE=y
+# CONFIG_SIBYTE_CFE_CONSOLE is not set
+# CONFIG_SIBYTE_BUS_WATCHER is not set
+# CONFIG_SIBYTE_SB1250_PROF is not set
+# CONFIG_SIBYTE_TBPROF is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_COHERENT=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+CONFIG_CPU_SB1=y
+CONFIG_SYS_HAS_CPU_SB1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_SIBYTE_DMA_PAGEOPS is not set
+# CONFIG_MIPS_MT is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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 is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# 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_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+# CONFIG_BLK_DEV_CS5520 is not set
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_IT821X=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_BLK_DEV_IDE_SWARM is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+# CONFIG_MEGARAID_NEWGEN is not set
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+CONFIG_SCSI_QLOGIC_FC=m
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_DEBUG=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_SB1250_MAC=y
+CONFIG_SBMAC_NAPI=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 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=m
+CONFIG_AMD8111_ETH=m
+# CONFIG_AMD8111E_NAPI is not set
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_ADAPTEC_STARFIRE_NAPI is not set
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_DL2K=m
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+# CONFIG_R8169_NAPI is not set
+CONFIG_SIS190=m
+CONFIG_SKGE=m
+CONFIG_SKY2=m
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+
+#
+# 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SIBYTE_SB1250_DUART=y
+CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_RTC=m
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_ALGO_SIBYTE=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+CONFIG_I2C_SIBYTE=m
+# 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=m
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SENSORS_VT8231=m
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+CONFIG_FB_PM2=m
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=m
+# CONFIG_FB_NVIDIA_I2C is not set
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+CONFIG_FB_RADEON_OLD=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+# CONFIG_FB_ATY_CT is not set
+# CONFIG_FB_ATY_GX is not set
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_AD1889=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_BT87X_OVERCLOCK=y
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_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
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# 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_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_ATI_REMOTE2=m
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_ET61X251=m
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# 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
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_SISUSBVGA_CON is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=m
+CONFIG_CRAMFS=y
+# 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_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+# CONFIG_SB1XXX_CORELIS is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+# CONFIG_SOUND_ES1371 is not set
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SND_VIRMIDI=m
+# CONFIG_SOUND_BT878 is not set
+CONFIG_VIDEO_BUF=m
+# CONFIG_USB_W9968CF is not set
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin"
+CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin"
+CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin"
+CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin"
+CONFIG_SOUND_TVMIXER=m
Added: people/maks-guest/linux-2.6/debian/arch/mips/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mips/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,32 @@
+[base]
+flavours:
+ r4k-ip22
+ r5k-ip32
+ sb1-bcm91250a
+ sb1a-bcm91480b
+ qemu
+kernel-arch: mips
+kernel-header-dirs: mips
+
+[image]
+initramfs: false
+
+[r4k-ip22]
+class: SGI IP22
+longclass: SGI IP22 (Indy, Indigo2)
+
+[r5k-ip32]
+class: SGI IP32
+longclass: SGI IP32 (O2)
+
+[sb1-bcm91250a]
+class: BCM91250A
+longclass: Broadcom BCM91250A (aka SWARM)
+
+[sb1a-bcm91480b]
+class: BCM91480B
+longclass: Broadcom BCM91480B (aka BigSur)
+
+[qemu]
+class: QEMU
+longclass: QEMU virtual machine
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1 @@
+CONFIG_MIPS=y
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config.qemu
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config.qemu Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1332 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+CONFIG_QEMU=y
+# CONFIG_MARKEINS is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_COHERENT=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_I8259=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=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_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_ISA=y
+CONFIG_MMU=y
+CONFIG_I8253=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_SECMARK is not set
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+# CONFIG_IP_NF_SIP is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID2=m
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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_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
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+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_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=m
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_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
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+
+#
+# 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=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
+# 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_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+# CONFIG_MD_RAID456 is not set
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_NET_SB1000 is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 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=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=y
+# CONFIG_SEEQ8005 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# 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_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+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=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# 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=m
+# 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=y
+# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_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 is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+# CONFIG_MDA_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
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_RTC_INTF_DEV=m
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=m
+
+#
+# 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=y
+# 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=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+# 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=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_SECLVL is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=m
+CONFIG_LIBCRC32C=m
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config.r3k-kn02
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config.r3k-kn02 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1163 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16
+# Wed May 24 16:44:02 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+CONFIG_MACH_DECSTATION=y
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=4
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+CONFIG_CPU_R3000=y
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_R3000=y
+CONFIG_SYS_HAS_CPU_R4X00=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_MIPS_MT is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_WB=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_TC=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE 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=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_DECNCR=y
+# CONFIG_SCSI_DECSII is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_DM9000 is not set
+# CONFIG_NET_POCKET is not set
+CONFIG_DECLANCE=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+CONFIG_ATMEL=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+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=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_LKKBD=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+# CONFIG_MOUSE_SERIAL is not set
+CONFIG_MOUSE_VSXXXAA=y
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_DEC=y
+CONFIG_SERIAL_DEC_CONSOLE=y
+CONFIG_ZS=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_DZ=y
+CONFIG_SERIAL_DZ_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+# CONFIG_SPI_BUTTERFLY is not set
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO 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_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_PMAG_AA is not set
+CONFIG_FB_PMAG_BA=y
+CONFIG_FB_PMAGB_B=y
+CONFIG_FB_MAXINE=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_RTCTIMER=m
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME 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'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+CONFIG_OCFS2_FS=m
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="n"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config.r4k-kn04
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config.r4k-kn04 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1165 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16
+# Wed May 24 16:43:27 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+CONFIG_MACH_DECSTATION=y
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=4
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+CONFIG_CPU_R4X00=y
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_R3000=y
+CONFIG_SYS_HAS_CPU_R4X00=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_TC=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE 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=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_DECNCR=y
+# CONFIG_SCSI_DECSII is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_DM9000 is not set
+# CONFIG_NET_POCKET is not set
+CONFIG_DECLANCE=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+CONFIG_ATMEL=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+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=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_LKKBD=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+# CONFIG_MOUSE_SERIAL is not set
+CONFIG_MOUSE_VSXXXAA=y
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_DEC=y
+CONFIG_SERIAL_DEC_CONSOLE=y
+CONFIG_ZS=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_DZ=y
+CONFIG_SERIAL_DZ_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+# CONFIG_SPI_BUTTERFLY is not set
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO 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_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_PMAG_AA is not set
+CONFIG_FB_PMAG_BA=y
+CONFIG_FB_PMAGB_B=y
+CONFIG_FB_MAXINE=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_RTCTIMER=m
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME 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'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+CONFIG_OCFS2_FS=m
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="n"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config.r5k-cobalt
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config.r5k-cobalt Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1649 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+CONFIG_MIPS_COBALT=y
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_I8259=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_GT64111=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+CONFIG_CPU_NEVADA=y
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_NEVADA=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_MIPS_MT is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE 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=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_PARIDE 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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# 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_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_QLOGIC_FC=m
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB 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_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=y
+CONFIG_TULIP=y
+CONFIG_TULIP_MWI=y
+CONFIG_TULIP_MWI_DC21143=y
+CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+# CONFIG_AMD8111E_NAPI is not set
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_ADAPTEC_STARFIRE_NAPI is not set
+CONFIG_B44=m
+# CONFIG_FORCEDETH is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 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)
+#
+# 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=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+# CONFIG_IPW2100_MONITOR is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+
+#
+# ISDN subsystem
+#
+CONFIG_ISDN=m
+
+#
+# Old ISDN4Linux
+#
+# CONFIG_ISDN_I4L is not set
+
+#
+# CAPI subsystem
+#
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+
+#
+# CAPI hardware drivers
+#
+
+#
+# Active AVM cards
+#
+CONFIG_CAPI_AVM=y
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+
+#
+# Active Eicon DIVA Server cards
+#
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+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=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# 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=m
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW 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=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED 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
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_RTC=y
+CONFIG_COBALT_LCD=y
+# 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+# CONFIG_SPI_BUTTERFLY is not set
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_RTCTIMER=m
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_AD1889=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+# CONFIG_SND_CS46XX_NEW_DSP is not set
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_USB_W9968CF is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_SOUND_BT878=n
+CONFIG_SOUND_EMU10K1=m
+CONFIG_SOUND_ES1371=m
+CONFIG_SOUND_VIA82CXXX=m
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+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=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_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
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_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_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_ATI_REMOTE2=m
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_ET61X251=m
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# 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
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+CONFIG_OCFS2_FS=m
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=y
+# 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_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="n"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+# 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=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config.sb1-bcm91250a
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config.sb1-bcm91250a Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1850 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+CONFIG_SIBYTE_SWARM=y
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_SIBYTE_SB1250=y
+CONFIG_SIBYTE_SB1xxx_SOC=y
+# CONFIG_CPU_SB1_PASS_1 is not set
+# CONFIG_CPU_SB1_PASS_2_1250 is not set
+CONFIG_CPU_SB1_PASS_2_2=y
+# CONFIG_CPU_SB1_PASS_4 is not set
+# CONFIG_CPU_SB1_PASS_2_112x is not set
+# CONFIG_CPU_SB1_PASS_3 is not set
+CONFIG_SIBYTE_HAS_LDT=y
+# CONFIG_SIMULATION is not set
+# CONFIG_SB1_CEX_ALWAYS_FATAL is not set
+# CONFIG_SB1_CERR_STALL is not set
+CONFIG_SIBYTE_CFE=y
+# CONFIG_SIBYTE_CFE_CONSOLE is not set
+# CONFIG_SIBYTE_BUS_WATCHER is not set
+# CONFIG_SIBYTE_SB1250_PROF is not set
+# CONFIG_SIBYTE_TBPROF is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_COHERENT=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+CONFIG_CPU_SB1=y
+CONFIG_SYS_HAS_CPU_SB1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_SIBYTE_DMA_PAGEOPS is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+CONFIG_SB1_PASS_2_WORKAROUNDS=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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 is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# 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_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+# CONFIG_BLK_DEV_CS5520 is not set
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_IT821X=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+CONFIG_BLK_DEV_IDE_SWARM=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+# CONFIG_MEGARAID_NEWGEN is not set
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+CONFIG_SCSI_QLOGIC_FC=m
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_DEBUG=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_SB1250_MAC=y
+CONFIG_SBMAC_NAPI=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 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=m
+CONFIG_AMD8111_ETH=m
+# CONFIG_AMD8111E_NAPI is not set
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_ADAPTEC_STARFIRE_NAPI is not set
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_DL2K=m
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+# CONFIG_R8169_NAPI is not set
+CONFIG_SIS190=m
+CONFIG_SKGE=m
+CONFIG_SKY2=m
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+
+#
+# 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SIBYTE_SB1250_DUART=y
+CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_RTC=m
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_ALGO_SIBYTE=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+CONFIG_I2C_SIBYTE=m
+# 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=m
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SENSORS_VT8231=m
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+CONFIG_FB_PM2=m
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=m
+# CONFIG_FB_NVIDIA_I2C is not set
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+CONFIG_FB_RADEON_OLD=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+# CONFIG_FB_ATY_CT is not set
+# CONFIG_FB_ATY_GX is not set
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_AD1889=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_BT87X_OVERCLOCK=y
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_BCM_CS4297A is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_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
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# 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_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_ATI_REMOTE2=m
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_ET61X251=m
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# 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
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_SISUSBVGA_CON is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=m
+CONFIG_CRAMFS=y
+# 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_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+# CONFIG_SB1XXX_CORELIS is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+# CONFIG_SOUND_ES1371 is not set
+CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin"
+CONFIG_USB_NET2280=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin"
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SOUND_EMU10K1=m
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_USB_EPSON2888=y
+CONFIG_SND_VIRMIDI=m
+CONFIG_USB_AN2720=y
+# CONFIG_USB_GADGET_PXA2XX is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_GADGET_OMAP is not set
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_SOUND_BT878=m
+CONFIG_VIDEO_BUF=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin"
+CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin"
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ZERO=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SOUND_TVMIXER=m
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_ACM=m
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/config.sb1a-bcm91480b
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/config.sb1a-bcm91480b Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1824 @@
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+CONFIG_SIBYTE_BIGSUR=y
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_SIBYTE_BCM1x80=y
+CONFIG_SIBYTE_SB1xxx_SOC=y
+# CONFIG_CPU_SB1_PASS_1 is not set
+# CONFIG_CPU_SB1_PASS_2_1250 is not set
+# CONFIG_CPU_SB1_PASS_2_2 is not set
+# CONFIG_CPU_SB1_PASS_4 is not set
+# CONFIG_CPU_SB1_PASS_2_112x is not set
+# CONFIG_CPU_SB1_PASS_3 is not set
+# CONFIG_SIMULATION is not set
+# CONFIG_SB1_CEX_ALWAYS_FATAL is not set
+# CONFIG_SB1_CERR_STALL is not set
+CONFIG_SIBYTE_CFE=y
+# CONFIG_SIBYTE_CFE_CONSOLE is not set
+# CONFIG_SIBYTE_BUS_WATCHER is not set
+# CONFIG_SIBYTE_SB1250_PROF is not set
+# CONFIG_SIBYTE_TBPROF is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_COHERENT=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+CONFIG_CPU_SB1=y
+CONFIG_SYS_HAS_CPU_SB1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_SIBYTE_DMA_PAGEOPS is not set
+# CONFIG_MIPS_MT is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=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_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_POLICY=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG 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 is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# 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_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=m
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_BLK_DEV_TRIFLEX=m
+CONFIG_BLK_DEV_CY82C693=m
+# CONFIG_BLK_DEV_CS5520 is not set
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_IT821X=m
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+# CONFIG_BLK_DEV_IDE_SWARM is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+# CONFIG_MEGARAID_NEWGEN is not set
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_SATA=m
+CONFIG_SCSI_SATA_AHCI=m
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_MV=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_PDC_ADMA=m
+CONFIG_SCSI_SATA_QSTOR=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIL24=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_ULI=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+CONFIG_SCSI_QLOGIC_FC=m
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_DEBUG=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_SB1250_MAC=y
+CONFIG_SBMAC_NAPI=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 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=m
+CONFIG_AMD8111_ETH=m
+# CONFIG_AMD8111E_NAPI is not set
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_ADAPTEC_STARFIRE_NAPI is not set
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_DL2K=m
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+# CONFIG_R8169_NAPI is not set
+CONFIG_SIS190=m
+CONFIG_SKGE=m
+CONFIG_SKY2=m
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+
+#
+# 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_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SIBYTE_SB1250_DUART=y
+CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_RTC=m
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_ALGO_SIBYTE=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+CONFIG_I2C_SIBYTE=m
+# 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=m
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous 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_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ADM1021 is not set
+# 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_F71805F 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SENSORS_VT8231=m
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+CONFIG_FB_PM2=m
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_CYBER2000=m
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=m
+# CONFIG_FB_NVIDIA_I2C is not set
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+CONFIG_FB_RADEON_OLD=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+# CONFIG_FB_ATY_CT is not set
+# CONFIG_FB_ATY_GX is not set
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_AD1889=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_BT87X_OVERCLOCK=y
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_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
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# 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_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+CONFIG_USB_ATI_REMOTE2=m
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_ET61X251=m
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# 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
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_ANYDATA=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+CONFIG_USB_SISUSBVGA=m
+# CONFIG_USB_SISUSBVGA_CON is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
+# 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
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_OCFS2_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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=m
+CONFIG_CRAMFS=y
+# 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_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# 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
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_CROSSCOMPILE is not set
+CONFIG_CMDLINE=""
+# CONFIG_SB1XXX_CORELIS is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+# CONFIG_SOUND_ES1371 is not set
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SND_VIRMIDI=m
+# CONFIG_SOUND_BT878 is not set
+CONFIG_VIDEO_BUF=m
+# CONFIG_USB_W9968CF is not set
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin"
+CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin"
+CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin"
+CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin"
+CONFIG_SOUND_TVMIXER=m
Added: people/maks-guest/linux-2.6/debian/arch/mipsel/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/mipsel/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,38 @@
+[base]
+flavours:
+ r5k-cobalt
+ sb1-bcm91250a
+ sb1a-bcm91480b
+ r3k-kn02
+ r4k-kn04
+ qemu
+kernel-arch: mips
+kernel-header-dirs: mips
+
+[image]
+initramfs: false
+
+[r5k-cobalt]
+class: Cobalt
+longclass: Cobalt (Qube, RaQ, Qube2, RaQ2)
+
+[sb1-bcm91250a]
+class: BCM91250A
+longclass: Broadcom BCM91250A (aka SWARM)
+
+[sb1a-bcm91480b]
+class: BCM91480B
+longclass: Broadcom BCM91480B (aka BigSur)
+
+[r3k-kn02]
+class: R3000 based DECstation
+longclass: R3000 based DECstations with KN02 mainboard, such as the DECstation 5000/1xx series with xx=20,25,33 and the DECstation 5000/240
+
+[r4k-kn04]
+class: R4x00 based DECstation
+longclass: R4x00 based DECstations with KN04 mainboard, such as the DECstation 5000/150, the
+ Personal DECstation 5000/50 and the DECstation 5000/260
+
+[qemu]
+class: QEMU
+longclass: QEMU virtual machine
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1230 @@
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
+# CONFIG_TAU_CALIBRATED is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_PMAC=y
+CONFIG_PPC601_SYNC_FIX=y
+CONFIG_PM=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_PPC_CHRP=y
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_PREP=y
+CONFIG_PPC_OF=y
+CONFIG_PPCBUG_NVRAM=y
+CONFIG_HIGHMEM=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_PREP_RESIDUAL=y
+CONFIG_PROC_PREPRESIDUAL=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 console=tty0"
+# CONFIG_PM_DEBUG is not set
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISA is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+CONFIG_YENTA=m
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_TCIC=m
+CONFIG_PCCARD_NONSTATIC=m
+# CONFIG_ADVANCED_OPTIONS is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+CONFIG_STANDALONE=y
+# CONFIG_MTD is not set
+CONFIG_BLK_DEV_FD=m
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_IDE_GENERIC is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_SL82C105=m
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_AEC62XX=m
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=m
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+CONFIG_BLK_DEV_HPT34X=m
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_SC1200=m
+# CONFIG_BLK_DEV_PIIX is not set
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_PDC202XX_FORCE=y
+# CONFIG_BLK_DEV_SVWKS is not set
+CONFIG_BLK_DEV_SIIMAGE=m
+# CONFIG_BLK_DEV_SLC90E66 is not set
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+# CONFIG_BLK_DEV_IDE_PMAC_BLINK is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_SCSI_DPT_I2O=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_ATA_PIIX is not set
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_EATA=m
+# CONFIG_SCSI_EATA_TAGGED_QUEUE is not set
+# CONFIG_SCSI_EATA_LINKED_COMMANDS is not set
+CONFIG_SCSI_EATA_MAX_TAGS=16
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+CONFIG_SCSI_IPS=m
+# CONFIG_SCSI_INITIO is not set
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_QLOGIC_FC=m
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_NSP32=m
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_MESH=m
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
+CONFIG_SCSI_MAC53C94=m
+CONFIG_PCMCIA_AHA152X=m
+# CONFIG_PCMCIA_FDOMAIN is not set
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+CONFIG_DM_MULTIPATH_EMC=m
+# CONFIG_FUSION_LAN is not set
+CONFIG_IEEE1394=m
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_IEEE1394_PCILYNX=m
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+CONFIG_ADB=y
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_PBOOK=y
+CONFIG_PMAC_APM_EMU=m
+CONFIG_PMAC_BACKLIGHT=y
+CONFIG_ADB_MACIO=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+CONFIG_THERM_WINDTUNNEL=m
+CONFIG_THERM_ADT746X=m
+CONFIG_ANSLCD=m
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_DECNET=m
+CONFIG_DECNET_ROUTER=y
+CONFIG_DECNET_ROUTE_FWMARK=y
+CONFIG_LLC=y
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_NET_DIVERT=y
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+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=m
+CONFIG_NET_SCH_ATM=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_CLS_POLICE=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_AX25_DAMA_SLAVE=y
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+CONFIG_IRTTY_SIR=m
+# CONFIG_DONGLE is not set
+CONFIG_USB_IRDA=m
+# CONFIG_SIGMATEL_FIR is not set
+CONFIG_NSC_FIR=m
+CONFIG_WINBOND_FIR=m
+# CONFIG_TOSHIBA_FIR is not set
+CONFIG_SMC_IRCC_FIR=m
+CONFIG_ALI_FIR=m
+# CONFIG_VLSI_FIR is not set
+CONFIG_VIA_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_DUMMY=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+# CONFIG_ARCNET_COM90xx is not set
+CONFIG_ARCNET_COM90xxIO=m
+# CONFIG_ARCNET_RIM_I is not set
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_MACE=m
+# CONFIG_MACE_AAUI_PORT is not set
+CONFIG_BMAC=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+# CONFIG_AMD8111_ETH is not set
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_B44=m
+# CONFIG_FORCEDETH is not set
+CONFIG_EEPRO100=m
+CONFIG_E100=m
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+CONFIG_SUNDANCE_MMIO=y
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_R8169_VLAN=y
+CONFIG_SK98LIN=m
+CONFIG_VIA_VELOCITY=m
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+CONFIG_MV643XX_ETH=m
+# CONFIG_MV643XX_ETH_0 is not set
+CONFIG_MV643XX_ETH_1=y
+# CONFIG_MV643XX_ETH_2 is not set
+CONFIG_IXGB=m
+CONFIG_S2IO=m
+# CONFIG_2BUFF_MODE is not set
+CONFIG_TR=y
+CONFIG_IBMOL=m
+CONFIG_IBMLS=m
+CONFIG_3C359=m
+CONFIG_TMS380TR=m
+CONFIG_TMSPCI=m
+CONFIG_ABYSS=m
+CONFIG_NET_RADIO=y
+CONFIG_STRIP=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_HERMES=m
+CONFIG_APPLE_AIRPORT=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+# CONFIG_PCI_ATMEL is not set
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_ARCNET_COM20020_CS=m
+CONFIG_PCMCIA_IBMTR=m
+CONFIG_WAN=y
+CONFIG_DSCC4=m
+# CONFIG_DSCC4_PCISYNC is not set
+# CONFIG_DSCC4_PCI_RST is not set
+CONFIG_LANMEDIA=m
+CONFIG_SYNCLINK_SYNCPPP=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW_ETH=y
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+CONFIG_HDLC_X25=y
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300=m
+CONFIG_PC300_MLPPP=y
+CONFIG_FARSYNC=m
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_WAN_ROUTER_DRIVERS=y
+CONFIG_CYCLADES_SYNC=m
+CONFIG_CYCLOMX_X25=y
+CONFIG_LAPBETHER=m
+CONFIG_X25_ASY=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+CONFIG_ATM_ZATM=m
+CONFIG_ATM_ZATM_DEBUG=y
+CONFIG_ATM_NICSTAR=m
+CONFIG_ATM_NICSTAR_USE_SUNI=y
+CONFIG_ATM_NICSTAR_USE_IDT77105=y
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+CONFIG_ATM_IA=m
+# CONFIG_ATM_IA_DEBUG is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+CONFIG_ATM_FORE200E_PCA=y
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y
+CONFIG_ATM_FORE200E_USE_TASKLET=y
+CONFIG_ATM_FORE200E_TX_RETRY=16
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_HE=m
+# CONFIG_ATM_HE_USE_SUNI is not set
+CONFIG_FDDI=y
+CONFIG_DEFXX=m
+CONFIG_SKFP=m
+CONFIG_HIPPI=y
+# CONFIG_ROADRUNNER is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_SLIP=m
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_NET_FC=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+CONFIG_ISDN=m
+# CONFIG_ISDN_I4L is not set
+CONFIG_ISDN_CAPI=m
+# CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON is not set
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+# CONFIG_ISDN_CAPI_CAPIFS_BOOL is not set
+CONFIG_CAPI_AVM=y
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
+CONFIG_PHONE_IXJ_PCMCIA=m
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_TSDEV=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# 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=m
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO=m
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=m
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461X=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_PMACZILOG=y
+CONFIG_SERIAL_PMACZILOG_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_PRINTER=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+CONFIG_USBPCWATCHDOG=m
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+CONFIG_APPLICOM=m
+CONFIG_AGP=m
+CONFIG_AGP_SIS=m
+CONFIG_AGP_UNINORTH=m
+CONFIG_AGP_VIA=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+CONFIG_SYNCLINK_CS=m
+# CONFIG_RAW_DRIVER is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_I2C_HYDRA=m
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_POWERMAC=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_KEYWEST=y
+CONFIG_I2C_MPC=m
+# CONFIG_I2C_NFORCE2 is not set
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+CONFIG_SCx200_ACB=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+# CONFIG_I2C_STUB is not set
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+CONFIG_I2C_PCA_ISA=m
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_FSCPOS=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_DS1337=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+CONFIG_SENSORS_M41T00=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_W1=m
+CONFIG_W1_MATROX=m
+CONFIG_W1_DS9490=m
+CONFIG_W1_DS9490_BRIDGE=m
+CONFIG_W1_THERM=m
+CONFIG_W1_SMEM=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_DIBUSB=m
+CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES=y
+# CONFIG_DVB_DIBCOM_DEBUG is not set
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+CONFIG_DVB_B2C2_SKYSTAR=m
+CONFIG_DVB_BT8XX=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA80XX=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_STV0297=m
+CONFIG_DVB_NXT2002=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BUF_DVB=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_FB=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_CIRRUS=m
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+CONFIG_FB_CT65550=y
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_VGA16 is not set
+CONFIG_FB_NVIDIA=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GENERIC_LCD=y
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SAVAGE_I2C=y
+CONFIG_FB_SAVAGE_ACCEL=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=y
+# CONFIG_FB_3DFX_ACCEL is not set
+CONFIG_FB_VOODOO1=y
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_TRIDENT_ACCEL=y
+CONFIG_FB_S1D13XXX=m
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+CONFIG_LOGO_LINUX_VGA16=y
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=m
+CONFIG_DMASOUND_PMAC=m
+CONFIG_DMASOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_ALI5451 is not set
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VX222=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_POWERMAC=m
+CONFIG_SND_AOA=m
+CONFIG_SND_AOA_FABRIC_LAYOUT=m
+CONFIG_SND_AOA_ONYX=m
+CONFIG_SND_AOA_TAS=m
+CONFIG_SND_AOA_TOONIE=m
+CONFIG_SND_AOA_SOUNDBUS=m
+CONFIG_SND_AOA_SOUNDBUS_I2S=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_USX2Y=m
+# CONFIG_SOUND_PRIME is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_PWC=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+CONFIG_USB_AX8817X=y
+CONFIG_USB_ZD1201=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_NET2280=y
+CONFIG_USB_NET2280=m
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_USB_G_SERIAL=m
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_WBSD=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_JBD=m
+CONFIG_FS_MBCACHE=m
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_ASFS_FS=m
+CONFIG_ASFS_DEFAULT_CODEPAGE=""
+CONFIG_ASFS_RW=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="iso8859-1"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+# CONFIG_CIFS_POSIX is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_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
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+# CONFIG_BDI_SWITCH is not set
+CONFIG_BOOTX_TEXT=y
+CONFIG_KEXEC=y
+CONFIG_PMAC_MEDIABAY=y
+CONFIG_SND_POWERMAC_AUTO_DRC=y
+CONFIG_USB_APPLETOUCH=m
+CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_HOTPLUG=y
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_I2C_PMAC_SMU=m
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PM_LEGACY=y
+CONFIG_PPC_I8259=y
+CONFIG_WINDFARM=m
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PPC_MPC106=y
+CONFIG_PPC_MERGE=y
+CONFIG_MPIC=y
+CONFIG_DEBUGGER=y
+CONFIG_PPC_RTAS=y
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_RTAS_ERROR_LOGGING is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+# CONFIG_XMON_DEFAULT is not set
+# CONFIG_GENERIC_TBSYNC is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_STD_MMU_32=y
+CONFIG_WATCHDOG_RTAS=m
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_RTAS_PROC=y
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+CONFIG_XMON=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_IPW2100 is not set
+CONFIG_HVC_RTAS=y
+CONFIG_SCSI_ARCMSR=m
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config.apus
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config.apus Sat Nov 11 02:48:00 2006
@@ -0,0 +1,166 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12
+# Sun Jul 31 18:13:08 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=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=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG 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_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_OBSOLETE_MODPARM=y
+CONFIG_KMOD=y
+
+#
+# Processor
+#
+CONFIG_6xx=y
+CONFIG_A2065=y
+CONFIG_A2091_SCSI=y
+CONFIG_A2232=m
+CONFIG_A3000_SCSI=y
+CONFIG_ABSTRACT_CONSOLE=y
+CONFIG_AFFS_FS=y
+CONFIG_AMIGA=y
+CONFIG_AMIGA_BUILTIN_SERIAL=y
+CONFIG_AMIGA_FLOPPY=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_AMIGA_PCMCIA=y
+CONFIG_APNE=y
+# CONFIG_PPC_MULTIPLATFORM is not set
+CONFIG_APUS=y
+CONFIG_APUS_FAST_EXCEPT=y
+CONFIG_ARIADNE=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_BLK_DEV_BUDDHA=y
+CONFIG_BLK_DEV_GAYLE=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_OKTAGON_SCSI=y
+CONFIG_PARPORT_AMIGA=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PPC32=y
+CONFIG_PPC=y
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_ZORRO=y
+CONFIG_ZORRO_NAMES=y
+CONFIG_GVPIOEXT=m
+# CONFIG_SMP is not set
+CONFIG_GVPIOEXT_LP=m
+CONFIG_GVPIOEXT_PLIP=m
+CONFIG_MULTIFACE_III_TTY=m
+CONFIG_WHIPPET_SERIAL=m
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_HEARTBEAT=y
+# CONFIG_PCI_PERMEDIA is not set
+CONFIG_AMIGA_Z2RAM=m
+CONFIG_BLK_DEV_IDEDOUBLER=y
+CONFIG_GVP11_SCSI=m
+CONFIG_ZORRO8390=m
+CONFIG_MOUSE_AMIGA=m
+CONFIG_JOYSTICK_AMIGA=m
+CONFIG_FB_AMIGA_OCS=y
+CONFIG_FB_AMIGA_ECS=y
+CONFIG_FB_FM2=y
+CONFIG_PROC_HARDWARE=y
+# CONFIG_IRPORT_SIR is not set
+CONFIG_PARPORT_MFC3=m
+CONFIG_PARIDE=n
+# CONFIG_SCSI_PPA is not set
+CONFIG_SCSI_IMM=m
+CONFIG_SCSI_IZIP_EPP16=y
+CONFIG_SCSI_IZIP_SLOW_CTR=y
+CONFIG_PLIP=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_LP_CONSOLE=y
+CONFIG_PPDEV=n
+CONFIG_TIPAR=m
+CONFIG_I2C_PARPORT=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_BAYCOM_EPP=m
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_OKTAGON_SCSI is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+CONFIG_BOOT_LOAD=0x00800000
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DMASOUND=m
+CONFIG_DMASOUND_PAULA=m
+CONFIG_FB=y
+CONFIG_FB_AMIGA=y
+CONFIG_FB_AMIGA_AGA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_HW_CONSOLE=y
+CONFIG_HYDRA=y
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_KEYBOARD_AMIGA=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_LINUX_MONO=y
+# CONFIG_FASTLANE_SCSI is not set
+# CONFIG_CYBERSTORMII_SCSI is not set
+# CONFIG_CYBERSTORM_SCSI is not set
+# CONFIG_BLZ1230_SCSI is not set
+# CONFIG_BLZ2060_SCSI is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_SND_AOA is not set
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+# CONFIG_APUS is not set
+CONFIG_PPC32=y
+# CONFIG_SMP is not set
+CONFIG_PM_STD_PARTITION=""
+# CONFIG_IRPORT_SIR is not set
+CONFIG_PCMCIA_XIRTULIP=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_MAC_FLOPPY=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_IMSTT=y
+# CONFIG_PPC64 is not set
+CONFIG_CLASSIC32=y
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc-miboot
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc-miboot Sat Nov 11 02:48:00 2006
@@ -0,0 +1,83 @@
+# CONFIG_APUS is not set
+CONFIG_PPC32=y
+CONFIG_MAC_FLOPPY=y
+# CONFIG_SMP is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_AUDIT is not set
+# CONFIG_KOBJECT_UEVENT is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_BASE_FULL is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_BASE_SMALL=1
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_PREP_RESIDUAL is not set
+# CONFIG_LBD is not set
+# CONFIG_THERM_WINDTUNNEL is not set
+# CONFIG_THERM_ADT746X is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_BT is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_NET_FC is not set
+CONFIG_SERIAL_8250=m
+CONFIG_I2C_KEYWEST=m
+# CONFIG_FB_OF is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+CONFIG_FB_3DFX=m
+CONFIG_FB_VOODOO1=m
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_PROC_KCORE is not set
+# CONFIG_DEVPTS_FS_SECURITY is not set
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_PROFILING is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_CHR_DEV_SCH=m
+# CONFIG_MEGARAID_LEGACY is not set
+CONFIG_IRDA=m
+CONFIG_PCMCIA_XIRTULIP=m
+# CONFIG_IRPORT_SIR is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_PMAC_BACKLIGHT is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_IMSTT=y
+# CONFIG_PPC64 is not set
+CONFIG_CLASSIC32=y
+CONFIG_FB_SIS=m
+
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc-smp
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc-smp Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+# CONFIG_APUS is not set
+CONFIG_PPC32=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_NR_CPUS=4
+# CONFIG_MAC_FLOPPY is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_IMSTT=y
+# CONFIG_PPC64 is not set
+CONFIG_CLASSIC32=y
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc64
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config.powerpc64 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,112 @@
+# CONFIG_APUS is not set
+CONFIG_PPC64=y
+CONFIG_64BIT=y
+CONFIG_COMPAT=y
+# CONFIG_DEBUGGER is not set
+CONFIG_EEH=y
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_NVIDIA is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_GEN_RTC is not set
+CONFIG_HANGCHECK_TIMER=m
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HUGETLBFS is not set
+CONFIG_HVC_CONSOLE=y
+CONFIG_HVCS=m
+CONFIG_IBMVETH=m
+CONFIG_IBMVIO=y
+CONFIG_IOMMU_VMERGE=y
+# CONFIG_IRQSTACKS is not set
+CONFIG_KEYS_COMPAT=y
+# CONFIG_KPROBES is not set
+CONFIG_LOCK_KERNEL=y
+CONFIG_LPARCFG=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_NR_CPUS=32
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_NUMA=y
+# CONFIG_PMAC_BACKLIGHT is not set
+# CONFIG_PMAC_PBOOK is not set
+CONFIG_PMAC_SMU=y
+# CONFIG_POWER4_ONLY is not set
+# CONFIG_PPCDBG is not set
+# CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_MAPLE=y
+CONFIG_PPC_PMAC64=y
+CONFIG_PPC_PSERIES=y
+# CONFIG_PPC_BPA is not set
+CONFIG_PPC_RTAS=y
+CONFIG_PPC_SPLPAR=y
+CONFIG_RTAS_FLASH=m
+CONFIG_RTAS_PROC=y
+# CONFIG_RTC is not set
+CONFIG_SCANLOG=m
+CONFIG_SCHED_SMT=y
+CONFIG_SCSI_QLOGIC_1280_1040=y
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_IBMVSCSI=m
+# CONFIG_SERIAL_ICOM is not set
+CONFIG_SMP=y
+CONFIG_STOP_MACHINE=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_THERM_PM72=m
+CONFIG_U3_DART=y
+CONFIG_WATCHDOG_RTAS=m
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+CONFIG_MPIC=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_XICS=y
+CONFIG_NODES_SPAN_OTHER_NODES=y
+# CONFIG_PPC_MPC106 is not set
+CONFIG_CPU_FREQ_PMAC64=y
+CONFIG_PPC_MERGE=y
+CONFIG_CELL_IIC=y
+CONFIG_MMIO_NVRAM=y
+CONFIG_PPC_CELL=y
+CONFIG_RTAS_ERROR_LOGGING=y
+CONFIG_GENERIC_TBSYNC=y
+# CONFIG_EMBEDDED6xx is not set
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_I2C_PMAC_SMU=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_POWER3=y
+CONFIG_POWER4=y
+CONFIG_WINDFARM=m
+CONFIG_WINDFARM_PM91=m
+CONFIG_WINDFARM_PM112=m
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_WINDFARM_PM81=m
+CONFIG_KERNEL_START=0xc000000000000000
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_IBMEBUS is not set
+CONFIG_SPU_FS=m
+CONFIG_SPIDER_NET=m
+# CONFIG_LPARCFG is not set
+CONFIG_VIRT_CPU_ACCOUNTING=y
+CONFIG_MIGRATION=y
+CONFIG_CMDLINE="console=hvsi0 console=hvc0 console=ttyS0,9600 console=tty0"
+# CONFIG_MV643XX_ETH is not set
+CONFIG_BLK_DEV_AMD74XX=m
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/config.prep
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/config.prep Sat Nov 11 02:48:00 2006
@@ -0,0 +1,21 @@
+# CONFIG_APUS is not set
+CONFIG_PPC32=y
+# CONFIG_SMP is not set
+CONFIG_PM_STD_PARTITION=""
+# CONFIG_IRPORT_SIR is not set
+CONFIG_PCMCIA_XIRTULIP=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_MAC_FLOPPY=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_IMSTT=y
+# CONFIG_PPC64 is not set
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PREP_RESIDUAL is not set
+# CONFIG_WINDFARM is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_CPU_FREQ_TABLE=m
+# CONFIG_SND_AOA is not set
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,39 @@
+[base]
+flavours:
+ powerpc
+ powerpc-smp
+ powerpc-miboot
+ powerpc64
+ prep
+# apus
+kernel-header-dirs: powerpc ppc m68k
+kernel-arch: powerpc
+kpkg-subarch: ppc
+subarches:
+ vserver
+
+[apus]
+depends: mkvmlinuz (>= 24)
+kernel-arch: ppc
+
+[prep]
+class: PReP PowerPC
+depends: mkvmlinuz (>= 24)
+kernel-arch: ppc
+kpkg-subarch: prep
+
+[powerpc]
+class: uniprocessor 32-bit PowerPC
+depends: mkvmlinuz (>= 24)
+
+[powerpc-smp]
+class: multiprocessor 32-bit PowerPC
+depends: mkvmlinuz (>= 24)
+
+[powerpc-miboot]
+class: 32-bit PowerPC for miboot floppy
+depends: mkvmlinuz (>= 24)
+
+[powerpc64]
+class: 64-bit PowerPC
+kpkg-subarch: powerpc64
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/modules
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/modules Sat Nov 11 02:48:00 2006
@@ -0,0 +1,213 @@
+kernel/fs/affs/affs.ko
+kernel/drivers/cdrom/cdrom.ko
+kernel/drivers/ide/ide-cd.ko
+kernel/drivers/scsi/sr_mod.ko
+kernel/fs/ext2/ext2.ko
+kernel/fs/ext3/ext3.ko
+kernel/fs/jbd/jbd.ko
+kernel/fs/fat/fat.ko
+kernel/fs/nls/nls_cp437.ko
+kernel/fs/nls/nls_iso8859-1.ko
+kernel/fs/vfat/vfat.ko
+kernel/drivers/ieee1394/ieee1394.ko
+kernel/drivers/ieee1394/ohci1394.ko
+kernel/drivers/ieee1394/sbp2.ko
+kernel/drivers/base/firmware_class.ko
+kernel/drivers/block/floppy.ko
+kernel/fs/mbcache.ko
+kernel/fs/nls/nls_utf8.ko
+kernel/fs/hfs/hfs.ko
+kernel/fs/hfsplus/hfsplus.ko
+kernel/drivers/ide/ide-disk.ko
+kernel/drivers/ide/ide-floppy.ko
+kernel/drivers/ide/ide-tape.ko
+kernel/drivers/ide/pci/aec62xx.ko
+kernel/drivers/ide/pci/cmd64x.ko
+kernel/drivers/ide/pci/generic.ko
+kernel/drivers/ide/pci/hpt34x.ko
+kernel/drivers/ide/pci/hpt366.ko
+kernel/drivers/ide/pci/ns87415.ko
+kernel/drivers/ide/pci/pdc202xx_new.ko
+kernel/drivers/ide/pci/pdc202xx_old.ko
+kernel/drivers/ide/pci/sc1200.ko
+kernel/drivers/ide/pci/siimage.ko
+kernel/drivers/ide/pci/sl82c105.ko
+kernel/drivers/ide/pci/trm290.ko
+kernel/drivers/ide/pci/via82cxxx.ko
+kernel/fs/isofs/isofs.ko
+kernel/drivers/input/keyboard/atkbd.ko
+kernel/drivers/input/serio/i8042.ko
+kernel/drivers/input/serio/libps2.ko
+kernel/drivers/input/serio/serio.ko
+kernel/drivers/usb/input/usbhid.ko
+kernel/net/ipv6/ipv6.ko
+kernel/drivers/net/irda/irtty-sir.ko
+kernel/drivers/net/irda/sir-dev.ko
+kernel/net/irda/ircomm/ircomm-tty.ko
+kernel/net/irda/ircomm/ircomm.ko
+kernel/net/irda/irda.ko
+kernel/net/irda/irlan/irlan.ko
+kernel/net/irda/irnet/irnet.ko
+kernel/fs/jfs/jfs.ko
+kernel/drivers/block/loop.ko
+kernel/drivers/md/dm-crypt.ko
+kernel/drivers/md/dm-mirror.ko
+kernel/drivers/md/dm-mod.ko
+kernel/drivers/md/dm-snapshot.ko
+kernel/drivers/md/linear.ko
+kernel/drivers/md/md-mod.ko
+kernel/drivers/md/multipath.ko
+kernel/drivers/md/raid0.ko
+kernel/drivers/md/raid1.ko
+kernel/drivers/md/raid5.ko
+kernel/drivers/md/xor.ko
+kernel/drivers/input/evdev.ko
+kernel/drivers/input/mouse/psmouse.ko
+kernel/drivers/net/dl2k.ko
+kernel/drivers/net/fealnx.ko
+kernel/drivers/net/hamachi.ko
+kernel/drivers/net/ixgb/ixgb.ko
+kernel/drivers/net/ns83820.ko
+kernel/drivers/net/r8169.ko
+kernel/drivers/net/s2io.ko
+kernel/drivers/net/sk98lin/sk98lin.ko
+kernel/drivers/net/starfire.ko
+kernel/drivers/net/tokenring/3c359.ko
+kernel/drivers/net/tokenring/abyss.ko
+kernel/drivers/net/tokenring/olympic.ko
+kernel/drivers/net/tokenring/tms380tr.ko
+kernel/drivers/net/tokenring/tmspci.ko
+kernel/drivers/net/tulip/de2104x.ko
+kernel/drivers/net/tulip/de4x5.ko
+kernel/drivers/net/tulip/dmfe.ko
+kernel/drivers/net/tulip/winbond-840.ko
+kernel/drivers/net/wireless/prism54/prism54.ko
+kernel/drivers/net/yellowfin.ko
+kernel/drivers/ieee1394/eth1394.ko
+kernel/drivers/net/3c59x.ko
+kernel/drivers/net/8139cp.ko
+kernel/drivers/net/8139too.ko
+kernel/drivers/net/appletalk/ipddp.ko
+kernel/drivers/net/b44.ko
+kernel/drivers/net/dummy.ko
+kernel/drivers/net/e100.ko
+kernel/drivers/net/e1000/e1000.ko
+kernel/drivers/net/eepro100.ko
+kernel/drivers/net/epic100.ko
+kernel/drivers/net/mv643xx_eth.ko
+kernel/drivers/net/natsemi.ko
+kernel/drivers/net/ne2k-pci.ko
+kernel/drivers/net/pcnet32.ko
+kernel/drivers/net/sis900.ko
+kernel/drivers/net/sundance.ko
+kernel/drivers/net/sungem.ko
+kernel/drivers/net/sungem_phy.ko
+kernel/drivers/net/sunhme.ko
+kernel/drivers/net/tulip/tulip.ko
+kernel/drivers/net/typhoon.ko
+kernel/drivers/net/via-rhine.ko
+kernel/drivers/net/wireless/airport.ko
+kernel/drivers/net/wireless/orinoco_pci.ko
+kernel/drivers/net/wireless/orinoco_plx.ko
+kernel/drivers/net/wireless/orinoco_tmd.ko
+kernel/net/appletalk/appletalk.ko
+kernel/drivers/net/arcnet/arcnet.ko
+kernel/drivers/net/arcnet/com20020.ko
+kernel/drivers/net/pcmcia/3c574_cs.ko
+kernel/drivers/net/pcmcia/3c589_cs.ko
+kernel/drivers/net/pcmcia/axnet_cs.ko
+kernel/drivers/net/pcmcia/com20020_cs.ko
+kernel/drivers/net/pcmcia/fmvj18x_cs.ko
+kernel/drivers/net/pcmcia/nmclan_cs.ko
+kernel/drivers/net/pcmcia/pcnet_cs.ko
+kernel/drivers/net/pcmcia/smc91c92_cs.ko
+kernel/drivers/net/pcmcia/xirc2ps_cs.ko
+kernel/drivers/net/tulip/xircom_cb.ko
+kernel/drivers/net/wireless/airo_cs.ko
+kernel/drivers/net/wireless/atmel.ko
+kernel/drivers/net/wireless/atmel_cs.ko
+kernel/drivers/net/wireless/netwave_cs.ko
+kernel/drivers/net/wireless/orinoco_cs.ko
+kernel/drivers/net/wireless/ray_cs.ko
+kernel/drivers/net/wireless/wavelan_cs.ko
+kernel/drivers/net/wireless/wl3501_cs.ko
+kernel/drivers/net/8390.ko
+kernel/drivers/net/mii.ko
+kernel/drivers/net/wireless/airo.ko
+kernel/drivers/net/wireless/hermes.ko
+kernel/drivers/net/wireless/orinoco.ko
+kernel/drivers/pcmcia/i82092.ko
+kernel/drivers/pcmcia/pcmcia.ko
+kernel/drivers/pcmcia/pcmcia_core.ko
+kernel/drivers/pcmcia/pd6729.ko
+kernel/drivers/pcmcia/rsrc_nonstatic.ko
+kernel/drivers/pcmcia/yenta_socket.ko
+kernel/drivers/ide/legacy/ide-cs.ko
+kernel/drivers/net/ppp_async.ko
+kernel/drivers/net/ppp_deflate.ko
+kernel/drivers/net/ppp_generic.ko
+kernel/drivers/net/ppp_synctty.ko
+kernel/drivers/net/pppoe.ko
+kernel/drivers/net/pppox.ko
+kernel/drivers/net/slhc.ko
+kernel/lib/crc-ccitt.ko
+kernel/lib/zlib_deflate/zlib_deflate.ko
+kernel/fs/reiserfs/reiserfs.ko
+kernel/drivers/block/sx8.ko
+kernel/drivers/scsi/ahci.ko
+kernel/drivers/scsi/libata.ko
+kernel/drivers/scsi/sata_mv.ko
+kernel/drivers/scsi/sata_nv.ko
+kernel/drivers/scsi/sata_promise.ko
+kernel/drivers/scsi/sata_qstor.ko
+kernel/drivers/scsi/sata_sil.ko
+kernel/drivers/scsi/sata_sis.ko
+kernel/drivers/scsi/sata_svw.ko
+kernel/drivers/scsi/sata_sx4.ko
+kernel/drivers/scsi/sata_uli.ko
+kernel/drivers/scsi/sata_via.ko
+kernel/drivers/scsi/sata_vsc.ko
+kernel/drivers/scsi/BusLogic.ko
+kernel/drivers/scsi/aic7xxx/aic79xx.ko
+kernel/drivers/scsi/aic7xxx/aic7xxx.ko
+kernel/drivers/scsi/scsi_transport_spi.ko
+kernel/drivers/scsi/sym53c8xx_2/sym53c8xx.ko
+kernel/drivers/scsi/scsi_mod.ko
+kernel/drivers/scsi/sd_mod.ko
+kernel/drivers/block/DAC960.ko
+kernel/drivers/block/cciss.ko
+kernel/drivers/block/cpqarray.ko
+kernel/drivers/message/fusion/mptbase.ko
+kernel/drivers/message/fusion/mptscsih.ko
+kernel/drivers/scsi/3w-xxxx.ko
+kernel/drivers/scsi/aacraid/aacraid.ko
+kernel/drivers/scsi/aic7xxx_old.ko
+kernel/drivers/scsi/ch.ko
+kernel/drivers/scsi/dc395x.ko
+kernel/drivers/scsi/eata.ko
+kernel/drivers/scsi/ips.ko
+kernel/drivers/scsi/megaraid/megaraid_mbox.ko
+kernel/drivers/scsi/megaraid/megaraid_mm.ko
+kernel/drivers/scsi/osst.ko
+kernel/drivers/scsi/st.ko
+kernel/drivers/scsi/a100u2w.ko
+kernel/drivers/scsi/atp870u.ko
+kernel/drivers/scsi/dmx3191d.ko
+kernel/drivers/scsi/ipr.ko
+kernel/drivers/scsi/qlogicfas408.ko
+kernel/drivers/scsi/qlogicfc.ko
+kernel/drivers/scsi/sg.ko
+kernel/drivers/scsi/tmscsim.ko
+kernel/drivers/char/pcmcia/synclink_cs.ko
+kernel/drivers/net/wan/hdlc.ko
+kernel/drivers/net/wan/syncppp.ko
+kernel/drivers/usb/serial/usbserial.ko
+kernel/net/lapb/lapb.ko
+kernel/fs/ufs/ufs.ko
+kernel/drivers/usb/core/usbcore.ko
+kernel/drivers/usb/host/ehci-hcd.ko
+kernel/drivers/usb/host/ohci-hcd.ko
+kernel/drivers/usb/host/uhci-hcd.ko
+kernel/drivers/usb/storage/usb-storage.ko
+kernel/fs/exportfs/exportfs.ko
+kernel/fs/xfs/xfs.ko
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/modules.README
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/modules.README Sat Nov 11 02:48:00 2006
@@ -0,0 +1,58 @@
+Just for info, and to avoid bad blood or anything, this is for now just an
+experimentation to be able to test and experiment my ideas, before it is either
+abandoned, or declared good enough to be generalized. The main caveat joeyh had
+about this when we discussed it in the past, apart from it being just words and
+nobody doing the work behind it, was the effect the multiplication of .udeb
+packages had on the d-i Packages file parsing on low-memory systems. Especially
+as it seems d-i maintains three simultaneous in-memory copies of this Package
+file, not sure why exactly, but this could be obtimized maybe, but see 7) also.
+
+The plan goes as follows :
+
+ 1) We will provide one .udeb per module, this will bring it to 600 or so
+ .udebs for powerpc, for the three flavours (not counting apus or upcoming
+ nubus/legacy-iseries).
+
+ 2) Each udeb description will be taken from the appropriate Kconfig file in
+ the future, not sure how to best do that, though, we could match the modules
+ to Makefiles, and then to CONFIG_ entries, which we take the description
+ from the corresponding Kconfig. Maybe a better solution would be to list the
+ modules per CONFIG_ entry, and make one .udeb per main CONFIG_ option. This
+ would be easier to track in the long end also.
+
+ 3) Module/udeb dependency is taken from the depmod output or directly from
+ the modules.
+
+ 4) In the future, we should list only the main CONFIG_ options, and package
+ the modules in grouping, and list only the modules we actually need.
+ The modules only pulled in by dependency should be automatically split out
+ into packages that should never be used directly, and in a minimum way, using
+ a bit of graph analysis to determine the minimum set of such packages.
+ The problem with that is how to take the name and description of those
+ non-primary packages in an automated way.
+
+ 5) We really need a way to make the config option choice / module list more
+ robust, as the split-config thingy is not all that sane right now, and there
+ is no easy link from modules to config options. Needs more investigation.
+
+ 6) It may be possible that the packaging infrastructure still has some
+ trouble with this approach, even after those 2 years or so since the d-i team
+ chose to split its kernel-udeb packages. This needs solving before we go with
+ this for all arches, so let's experiment a bit with powerpc only.
+
+ 7) To ease the weight of this multiplication on .udeb packages on the d-i
+ Packages parsing, one could imagine to split off a separate Packages file for
+ each kernel flavour, residing in .../debian-installer/kernel/<version>-<abi>-<flavour>.
+ Not sure if all three d-i Packages parsing parts can handle multiple sources,
+ i think not, but this is something which it would be worth to fix independently
+ of this issue.
+
+
+Well, that is it, works needs done, but i sincerely think this is the right
+option for this, especially given the poor status of the inter-arch synchronization
+the d-i team has done with the kernel .udebs, and they rejecting all responsability
+to porters.
+
+Friendly,
+
+Sven Luther
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,12 @@
+kernel/drivers/net/defxx.ko
+kernel/drivers/net/skfp/skfp.ko
+kernel/drivers/net/tlan.ko
+kernel/drivers/net/tokenring/lanstreamer.ko
+kernel/drivers/net/bmac.ko
+kernel/drivers/net/mace.ko
+kernel/drivers/net/pcmcia/ibmtr_cs.ko
+kernel/drivers/net/tulip/xircom_tulip_cb.ko
+kernel/drivers/scsi/3w-9xxx.ko
+kernel/drivers/scsi/dpt_i2o.ko
+kernel/drivers/scsi/mac53c94.ko
+kernel/drivers/scsi/mesh.ko
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc-miboot
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc-miboot Sat Nov 11 02:48:00 2006
@@ -0,0 +1,10 @@
+kernel/drivers/net/tlan.ko
+kernel/drivers/net/tokenring/lanstreamer.ko
+kernel/drivers/net/bmac.ko
+kernel/drivers/net/mace.ko
+kernel/drivers/net/pcmcia/ibmtr_cs.ko
+kernel/drivers/net/tulip/xircom_tulip_cb.ko
+kernel/drivers/scsi/3w-9xxx.ko
+kernel/drivers/scsi/dpt_i2o.ko
+kernel/drivers/scsi/mac53c94.ko
+kernel/drivers/scsi/mesh.ko
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc64
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/modules.powerpc64 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,6 @@
+kernel/arch/ppc64/kernel/hvcserver.ko
+kernel/drivers/char/hvcs.ko
+kernel/drivers/net/defxx.ko
+kernel/drivers/net/skfp/skfp.ko
+kernel/drivers/net/ibmveth.ko
+kernel/drivers/scsi/ibmvscsi/ibmvscsic.ko
Added: people/maks-guest/linux-2.6/debian/arch/powerpc/vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/powerpc/vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+[base]
+flavours:
+ powerpc
+ powerpc64
+
+[image]
+configs: _vserver/config
+recommends: util-vserver
+
+[powerpc_image]
+configs: powerpc/config.powerpc-smp
+
+[powerpc64_image]
+configs: powerpc/config.powerpc64
+
Added: people/maks-guest/linux-2.6/debian/arch/s390/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+#
+# Variables
+#
Added: people/maks-guest/linux-2.6/debian/arch/s390/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,167 @@
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_S390=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=32
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_PACK_STACK is not set
+# CONFIG_CHECK_STACK is not set
+# CONFIG_WARN_STACK is not set
+CONFIG_MACHCHK_WARNING=y
+CONFIG_QDIO=y
+# CONFIG_QDIO_PERF_STATS is not set
+# CONFIG_QDIO_DEBUG is not set
+CONFIG_IPL=y
+# CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
+CONFIG_CMM=y
+CONFIG_CMM_PROC=y
+CONFIG_VIRT_TIMER=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
+CONFIG_APPLDATA_BASE=y
+CONFIG_APPLDATA_MEM=m
+CONFIG_APPLDATA_OS=m
+CONFIG_APPLDATA_NET_SUM=m
+CONFIG_NO_IDLE_HZ=y
+CONFIG_NO_IDLE_HZ_INIT=y
+# CONFIG_PCMCIA is not set
+CONFIG_STANDALONE=y
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_ZFCP=m
+CONFIG_CCW=y
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM_SIZE=24576
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_BLK_DEV_XPRAM=m
+CONFIG_DCSSBLK=m
+CONFIG_DASD=m
+# CONFIG_DASD_PROFILE is not set
+CONFIG_DASD_ECKD=m
+CONFIG_DASD_FBA=m
+# CONFIG_DASD_DIAG is not set
+# CONFIG_DASD_EER is not set
+# CONFIG_DASD_CMB is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_DM_MULTIPATH_EMC is not set
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_WATCHDOG is not set
+CONFIG_TN3270=y
+# CONFIG_TN3270_TTY is not set
+# CONFIG_TN3270_FS is not set
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
+CONFIG_CCW_CONSOLE=y
+CONFIG_SCLP=y
+CONFIG_SCLP_TTY=y
+CONFIG_SCLP_CONSOLE=y
+CONFIG_SCLP_VT220_TTY=y
+CONFIG_SCLP_VT220_CONSOLE=y
+# CONFIG_SCLP_CPI is not set
+CONFIG_S390_TAPE=m
+CONFIG_S390_TAPE_BLOCK=y
+CONFIG_S390_TAPE_34XX=m
+CONFIG_S390_TAPE_3590=m
+CONFIG_VMLOGRDR=m
+CONFIG_VMCP=m
+CONFIG_MONREADER=m
+CONFIG_Z90CRYPT=m
+CONFIG_IPV6=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# 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_DUMMY is not set
+CONFIG_TR=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_WAN is not set
+CONFIG_LCS=m
+CONFIG_CTC=m
+CONFIG_IUCV=m
+CONFIG_NETIUCV=m
+CONFIG_SMSGIUCV=m
+CONFIG_CLAW=m
+CONFIG_QETH=m
+CONFIG_QETH_IPV6=y
+CONFIG_QETH_VLAN=y
+# CONFIG_QETH_PERF_STATS is not set
+CONFIG_CCWGROUP=m
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_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_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
+# 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
+# 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_IBM_PARTITION=y
+# CONFIG_MAC_PARTITION is not set
+CONFIG_BSD_DISKLABEL=y
+# 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
+# CONFIG_PROFILING is not set
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA256_S390=m
+CONFIG_CRYPTO_DES_S390=m
+CONFIG_CRYPTO_AES_S390=m
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=m
+CONFIG_KEXEC=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_HANGCHECK_TIMER is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_S390_HYPFS_FS=y
+CONFIG_RESOURCES_64BIT=y
Added: people/maks-guest/linux-2.6/debian/arch/s390/config.s390
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/config.s390 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+CONFIG_UID16=y
+# CONFIG_ARCH_S390X is not set
+# CONFIG_64BIT is not set
+CONFIG_ARCH_S390_31=y
+CONFIG_MATHEMU=y
+CONFIG_MARCH_G5=y
+# CONFIG_MARCH_Z900 is not set
+# CONFIG_MARCH_Z990 is not set
+# CONFIG_IPL_TAPE is not set
+CONFIG_IPL_VM=y
+# CONFIG_LBD is not set
Added: people/maks-guest/linux-2.6/debian/arch/s390/config.s390-tape
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/config.s390-tape Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+CONFIG_UID16=y
+# CONFIG_ARCH_S390X is not set
+# CONFIG_64BIT is not set
+CONFIG_ARCH_S390_31=y
+CONFIG_MATHEMU=y
+CONFIG_MARCH_G5=y
+# CONFIG_MARCH_Z900 is not set
+# CONFIG_MARCH_Z990 is not set
+CONFIG_IPL_TAPE=y
+# CONFIG_IPL_VM is not set
+# CONFIG_LBD is not set
Added: people/maks-guest/linux-2.6/debian/arch/s390/config.s390x
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/config.s390x Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+CONFIG_ARCH_S390X=y
+CONFIG_64BIT=y
+CONFIG_S390_SUPPORT=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_BINFMT_ELF32=y
+# CONFIG_MARCH_G5 is not set
+CONFIG_MARCH_Z900=y
+# CONFIG_MARCH_Z990 is not set
+# CONFIG_IPL_TAPE is not set
+CONFIG_IPL_VM=y
Added: people/maks-guest/linux-2.6/debian/arch/s390/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,29 @@
+[base]
+flavours:
+ s390
+ s390-tape
+ s390x
+kernel-arch: s390
+kernel-header-dirs: s390
+subarches:
+ vserver
+
+[image]
+desc: This kernel has support to IPL (boot) from a VM reader or DASD device.
+suggests: s390-tools
+
+[s390]
+class: IBM S/390
+
+[s390-tape]
+class: IBM S/390 tape
+modules: false
+
+[s390-tape_image]
+desc: This kernel has support to IPL (boot) from a tape.
+initramfs: false
+type: plain-s390-tape
+
+[s390x]
+class: IBM zSeries
+
Added: people/maks-guest/linux-2.6/debian/arch/s390/vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/s390/vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,9 @@
+[base]
+flavours: s390x
+
+[image]
+configs: _vserver/config
+
+[s390x_image]
+configs: s390/config.s390x
+
Added: people/maks-guest/linux-2.6/debian/arch/sparc/Makefile.inc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/Makefile.inc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,4 @@
+#
+# Variables
+#
+image_postproc = strip -R .comment -R .note -K sun4u_init -K _end -K _start arch/$(subst 32,,$(subst -smp,,$*))/boot/image
Added: people/maks-guest/linux-2.6/debian/arch/sparc/config
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/config Sat Nov 11 02:48:00 2006
@@ -0,0 +1,430 @@
+CONFIG_NET_SCH_GRED=m
+CONFIG_SND_HWDEP=m
+# Native Language Support
+# Open Sound System
+CONFIG_NET_SCH_DSMARK=m
+# LED Triggers
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+CONFIG_SND_PCM=m
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SND_SUN_CS4231=m
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MMC is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_SND_OPL3_LIB=m
+# Plug and Play support
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_SND_AZT3328 is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_BT is not set
+CONFIG_EFS_FS=m
+CONFIG_ARPD=y
+CONFIG_PPP_BSDCOMP=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_SUNQE=m
+# CONFIG_WAN is not set
+# CONFIG_ARCNET is not set
+# CONFIG_SUN_BPP is not set
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_NFS_DIRECTIO is not set
+# Console display driver support
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SERIAL_JSM=m
+# SCSI Transport Attributes
+# CONFIG_SND_HDSP is not set
+CONFIG_LLC2=m
+# Block devices
+# CONFIG_BLK_CPQ_DA is not set
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_NET_SCH_HFSC=m
+# CONFIG_IP_PNP_BOOTP is not set
+# Telephony Support
+CONFIG_SND=m
+CONFIG_SUN_OPENPROMIO=y
+CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SND_SONICVIBES is not set
+CONFIG_PPP=m
+# Real Time Clock
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_LAPB is not set
+CONFIG_BLK_DEV_FD=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_NET_EMATCH is not set
+CONFIG_INPUT_MISC=y
+CONFIG_SND_SUN_DBRI=m
+CONFIG_BRIDGE=m
+# CONFIG_SGI_PARTITION is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_SND_ES1938 is not set
+# Userland interfaces
+# CONFIG_NCPFS_STRONG is not set
+# Misc devices
+CONFIG_HFSPLUS_FS=m
+CONFIG_SUN_IO=y
+# CONFIG_INPUT_EVBUG is not set
+CONFIG_NET_SCH_NETEM=m
+# Wireless LAN (non-hamradio)
+# CONFIG_HP100 is not set
+# I2C support
+# CONFIG_DVB is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_PPP_FILTER=y
+CONFIG_INPUT=y
+# CONFIG_IPMI_HANDLER is not set
+# RTC interfaces
+# CONFIG_USB_GADGET is not set
+# CONFIG_FB_P9100 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_ES1968 is not set
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+# CONFIG_IKCONFIG is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+CONFIG_INPUT_SPARCSPKR=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SND_FM801 is not set
+CONFIG_PLIP=m
+# Code maturity level options
+CONFIG_SERIAL_SUNCORE=y
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_R3964 is not set
+# CONFIG_CODA_FS_OLD_API is not set
+# Queueing/Scheduling
+CONFIG_AFS_FS=m
+# Cryptographic options
+CONFIG_SND_MPU401_UART=m
+# CONFIG_IP_SCTP is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_NET_DIVERT is not set
+CONFIG_NCPFS_NFS_NS=y
+# Serial drivers
+# ISDN subsystem
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_W1 is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_AU8810 is not set
+# Kernel hacking
+CONFIG_SND_TIMER=m
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# Ethernet (10 or 100Mbit)
+# ATA/ATAPI/MFM/RLL support
+CONFIG_FB_SBUS=y
+CONFIG_NETCONSOLE=m
+CONFIG_NET_ESTIMATOR=y
+# SCSI device support
+# CONFIG_SND_CS4281 is not set
+# Multimedia devices
+# CONFIG_NET_SCH_CLK_CPU is not set
+# CONFIG_SND_NM256 is not set
+CONFIG_UID16=y
+# CONFIG_HIPPI is not set
+CONFIG_UFS_FS=m
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPX=m
+CONFIG_PPP_ASYNC=m
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LLC=m
+# File systems
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PPP_MULTILINK=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IPX_INTERN is not set
+CONFIG_SCSI_LPFC=m
+# LED drivers
+# CONFIG_SND_RME96 is not set
+# CD-ROM/DVD Filesystems
+# CONFIG_FB_CIRRUS is not set
+# USB Gadget Support
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_ATALK=m
+CONFIG_IP_PNP_RARP=y
+CONFIG_INPUT_MOUSE=y
+# CONFIG_SND_VX222 is not set
+# CONFIG_I2O is not set
+CONFIG_DECNET=m
+# CONFIG_SND_MIXART is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_PARPORT_SUNBPP=m
+CONFIG_SOUND=m
+# CONFIG_ECONET is not set
+# CONFIG_SND_BT87X is not set
+CONFIG_NET_FC=y
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# Digital Video Broadcasting Devices
+CONFIG_PARPORT_NOT_PC=y
+# CONFIG_PHONE is not set
+CONFIG_CODA_FS=m
+CONFIG_SND_MIXER_OSS=m
+# CONFIG_X25 is not set
+# CONFIG_CIFS_XATTR is not set
+# Input device support
+# CONFIG_TR is not set
+# CONFIG_SND_CA0106 is not set
+CONFIG_NET_SCH_TBF=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SLIP=m
+CONFIG_NET_CLS_POLICE=y
+CONFIG_LOGO=y
+# CONFIG_ATM is not set
+# CONFIG_SND_RME32 is not set
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_FB=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# Network device support
+CONFIG_DECNET_ROUTE_FWMARK=y
+CONFIG_PPPOE=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_AFFS_FS=m
+# Device Drivers
+# CONFIG_TIPAR is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_NCPFS_OS2_NS=y
+# Miscellaneous filesystems
+# CONFIG_EFI_PARTITION is not set
+# Connector - unified userspace <-> kernelspace linker
+# CONFIG_RAW_DRIVER is not set
+# DOS/FAT/NT Filesystems
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_NET_SCH_HTB=m
+CONFIG_PRINTER=m
+# Graphics support
+CONFIG_SBUSCHAR=y
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_ATIIXP is not set
+CONFIG_SUNLANCE=m
+CONFIG_SUN_AUXIO=y
+# CONFIG_FB_PCI is not set
+CONFIG_DM_MULTIPATH_EMC=m
+# Ethernet (1000 Mbit)
+CONFIG_RXRPC=m
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_QNX4FS_FS is not set
+# Generic devices
+# CONFIG_SND_ATIIXP_MODEM is not set
+CONFIG_NET_SCH_INGRESS=m
+# Watchdog Cards
+# CONFIG_EMBEDDED is not set
+CONFIG_HAPPYMEAL=m
+# Ethernet (10000 Mbit)
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_PROM_CONSOLE=y
+# RTC drivers
+# Linux kernel version: 2.6.17
+# CONFIG_LP_CONSOLE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_SUNRPC_GSS=m
+# Input Device Drivers
+# InfiniBand support
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# Core Netfilter Configuration
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+# CONFIG_SERIO_PCIPS2 is not set
+# Logo configuration
+CONFIG_INPUT_EVDEV=m
+# CONFIG_SCSI_IPS is not set
+# CONFIG_DEV_APPLETALK is not set
+CONFIG_SCSI_QLOGICPTI=m
+CONFIG_IP_PNP=y
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_PCI=y
+# Hardware Monitoring support
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_NET_SCHED=y
+# CONFIG_SND_AU8820 is not set
+# CONFIG_ISDN is not set
+# MMC/SD Card support
+# CONFIG_SCSI_INIA100 is not set
+# SCSI support type (disk, tape, CD-ROM)
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_SCSI_DEBUG is not set
+# ARCnet devices
+# CONFIG_SND_AU8830 is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_SUN_OPENPROMFS=m
+# Sound
+CONFIG_SLIP_SMART=y
+CONFIG_LEGACY_PTYS=y
+# CONFIG_MOUSE_VSXXXAA is not set
+# IO Schedulers
+# DCCP Configuration (EXPERIMENTAL)
+# CONFIG_PPDEV is not set
+# IPMI
+# Hardware crypto devices
+# CONFIG_SENSORS_F71805F is not set
+CONFIG_DECNET_ROUTER=y
+CONFIG_NET_SCH_SFQ=m
+CONFIG_SND_SUN_AMD7930=m
+# CONFIG_SND_ICE1712 is not set
+# Ftape, the floppy tape device driver
+# PHY device support
+# CONFIG_INFINIBAND is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_VXFS_FS is not set
+# Generic Driver Options
+# CONFIG_SERIO_SERPORT is not set
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+CONFIG_DUMMY=m
+CONFIG_SCSI_SUNESP=m
+CONFIG_FB_CG6=y
+# Wan interfaces
+CONFIG_PARPORT_1284=y
+# TPM devices
+# LED devices
+# USB support
+# CONFIG_SERIO_RAW is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_HPFS_FS=m
+# CONFIG_ADFS_FS is not set
+# CONFIG_INPUT_UINPUT is not set
+# SPI Protocol Masters
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_ATA_OVER_ETH=m
+# IEEE 1394 (FireWire) support
+CONFIG_BFS_FS=m
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_IRDA is not set
+CONFIG_VT_CONSOLE=y
+# Library routines
+CONFIG_JBD=m
+CONFIG_KEYBOARD_SUNKBD=y
+CONFIG_NETPOLL=y
+# CONFIG_GAMEPORT is not set
+# Classification
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# Block layer
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_FB_3DFX is not set
+# Non-8250 serial port support
+# SCSI low-level drivers
+# ALSA Sparc devices
+# Token Ring devices
+# Multi-device support (RAID and LVM)
+# Loadable module support
+# Memory Technology Devices (MTD)
+CONFIG_CRC32=y
+# CONFIG_ASFS_FS is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_SUNBMAC=m
+# I2O device support
+CONFIG_PARPORT=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_NCP_FS=m
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_FB_SIS is not set
+CONFIG_SHAPER=m
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SBUS=y
+# Hardware I/O ports
+CONFIG_NET_SCH_CBQ=m
+CONFIG_SPARC=y
+# CONFIG_SND_DEBUG is not set
+# CONFIG_R8169 is not set
+CONFIG_FONT_SUN8x16=y
+CONFIG_BNX2=m
+# CONFIG_FB_RIVA is not set
+# CONFIG_MTD is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_DTLK is not set
+CONFIG_VT=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# Advanced Linux Sound Architecture
+CONFIG_SND_PCM_OSS=m
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_SND_DUMMY is not set
+# Misc Linux/SPARC drivers
+CONFIG_SERIAL_SUNZILOG_CONSOLE=y
+# PCI devices
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SERIAL_SUNZILOG=y
+CONFIG_SYSV_FS=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_NET_SCH_RED=m
+# CONFIG_IP_PNP_DHCP is not set
+# TIPC Configuration (EXPERIMENTAL)
+# CONFIG_CIFS_STATS is not set
+# CONFIG_FONTS is not set
+# Network testing
+# CONFIG_INPUT_TSDEV is not set
+# Pseudo filesystems
+# CONFIG_SND_VIA82XX is not set
+CONFIG_SERIO_I8042=y
+# CONFIG_SND_RME9652 is not set
+CONFIG_EXT2_FS=y
+# CONFIG_NET_IPGRE is not set
+# SPI support
+# CONFIG_SND_MPU401 is not set
+# General setup
+# CONFIG_FB_KYRO is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+CONFIG_BEFS_FS=m
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCPFS_NLS is not set
+# Tulip family network device support
+# CONFIG_LDM_PARTITION is not set
+# Character devices
+# QoS and/or fair queueing
+# General machine setup
+CONFIG_HFS_FS=m
+CONFIG_SERIO=y
+# Fusion MPT device support
+# CONFIG_AMIGA_PARTITION is not set
+# Parallel port support
+# CONFIG_SND_ICE1724 is not set
+CONFIG_HW_CONSOLE=y
+# SPI Master Controller Drivers
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_FB_SAVAGE is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_FB_MATROX is not set
+# Partition Types
+# CONFIG_SND_EMU10K1X is not set
+# Security options
+# CONFIG_APPLICOM is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# Automatically generated make config: don't edit
+# CONFIG_SOLARIS_X86_PARTITION is not set
+CONFIG_CIFS=m
+# Dallas's 1-wire bus
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# Network File Systems
+# CONFIG_SND_HDA_INTEL is not set
+# MII PHY device drivers
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+CONFIG_SCSI_ARCMSR=m
Added: people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc32
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc32 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,100 @@
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_SPARC32=y
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_AUDIT is not set
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_LOGO_SUN_CLUT224 is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_FB_CG14=y
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_FDDI is not set
+# CONFIG_SCSI_AIC7XXX is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SUN4 is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_DL2K is not set
+# CONFIG_IDE is not set
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SUN_JSFLASH is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_S2IO is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SND_CMIPCI is not set
+CONFIG_FB_TCX=y
+# CONFIG_SECURITY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_TADPOLE_TS102_UCTRL is not set
+CONFIG_HIGHMEM=y
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_SND_ENS1371 is not set
+CONFIG_SPARC_LED=m
+CONFIG_SERIAL_SUNSAB=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_SUN_PM=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_I2C is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_SUNOS_EMUL is not set
+# CONFIG_STANDALONE is not set
+# Sat Sep 16 21:12:18 2006
+# CONFIG_SCSI_IPR is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_FUSION_LAN is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_KEYS is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_DRM is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_IXGB is not set
+# CONFIG_SUN_VIDEOPIX is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_SERIAL_SUNSU is not set
+# CONFIG_SCSI_DMX3191D is not set
+# Unix98 PTY support
+# CONFIG_SMP is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_HWMON_VID is not set
+CONFIG_FB_BW2=y
+# CONFIG_NTFS_FS is not set
+# CONFIG_RTC is not set
+# CONFIG_USB is not set
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_BINFMT_AOUT=y
+CONFIG_FB_CG3=y
+CONFIG_FB_LEO=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SCSI_AIC79XX is not set
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_EMU10K1 is not set
Added: people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc64
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc64 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,416 @@
+CONFIG_FB_MODE_HELPERS=y
+# USB Device Class drivers
+CONFIG_IDEDMA_AUTO=y
+CONFIG_E1000=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_SOLARIS_EMUL=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_BLK_DEV_IDEDISK=m
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_DRM_TDFX=m
+# CONFIG_EEPRO100 is not set
+CONFIG_IEEE1394_DV1394=m
+CONFIG_FDDI=y
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_USB_EHCI_HCD=m
+CONFIG_SERIAL_SUNSAB=y
+CONFIG_NET_TULIP=y
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# Fibre Channel support
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_DISPLAY7SEG=m
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SERIAL is not set
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_SND_EMU10K1=m
+CONFIG_FUSION_LAN=m
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_SCSI_PLUTO=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_MOUSE_SERIAL=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_OBP_FLASH=m
+CONFIG_FB_PM2=y
+# CONFIG_I2C_VIAPRO is not set
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_IXGB=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SPARC32_COMPAT=y
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BINFMT_ELF32=y
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_USB_MDC800=m
+# CONFIG_TUNER_3036 is not set
+# CONFIG_SPARC64_PAGE_SIZE_64KB is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+CONFIG_S2IO=m
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_HID_FF is not set
+CONFIG_I2C_ALGOPCA=m
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_I2C_CHARDEV=m
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_USB_KAWETH=m
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_SPARC64_PAGE_SIZE_4MB is not set
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_WINBOND_840=m
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_FB_BW2 is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_FC4_SOC=m
+CONFIG_USB_CYTHERM=m
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_FONT_8x16=y
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_ENVCTRL=m
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_HD is not set
+# USB devices
+# CONFIG_USB_OV511 is not set
+CONFIG_LOGO_SUN_CLUT224=y
+# CONFIG_USB_DEBUG is not set
+# Miscellaneous I2C Chip support
+CONFIG_BROKEN_ON_SMP=y
+# Miscellaneous USB options
+CONFIG_PCI_DOMAINS=y
+CONFIG_BLK_DEV_VIA82CXXX=m
+# USB Miscellaneous drivers
+# CONFIG_SENSORS_ADM1031 is not set
+CONFIG_BLK_DEV_CS5530=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_SENSORS_PCF8574 is not set
+CONFIG_SND_ENS1371=m
+# CONFIG_SCSI_IPR_DUMP is not set
+# CONFIG_TULIP_MWI is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+CONFIG_SND_MAESTRO3=m
+CONFIG_DL2K=m
+CONFIG_USB_AN2720=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_I2C_SIS630 is not set
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C=m
+CONFIG_COMPAT=y
+CONFIG_DRM_RADEON=m
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# USB Serial Converter support
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_SENSORS_ADM1026 is not set
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_STANDALONE=y
+CONFIG_USB_RIO500=m
+CONFIG_USB_BELKIN=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_64BIT=y
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# Executable file formats
+# USB port drivers
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_FSCHER is not set
+CONFIG_USB_USBNET=m
+# CONFIG_SPARC64_PAGE_SIZE_512KB is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_USB_USS720 is not set
+CONFIG_SND_ALI5451=m
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_USB_CATC=m
+CONFIG_MEGARAID_MM=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_VIDEO_BUF=m
+# CONFIG_VIDEO_SAA5246A is not set
+CONFIG_IEEE1394_SBP2=m
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_VOODOO3 is not set
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_RTC=y
+CONFIG_YELLOWFIN=m
+CONFIG_SERIAL_SUNHV=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_DEFXX is not set
+# CONFIG_RADIO_MAESTRO is not set
+CONFIG_FC4=m
+# CONFIG_FB_TCX is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_VIA is not set
+# Video Capture Adapters
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_B44=m
+# CONFIG_USB_KBTAB is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SENSORS_LM75 is not set
+CONFIG_DM9102=m
+# USB Network Adapters
+CONFIG_USB_STORAGE_FREECOM=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+# CONFIG_USB_BANDWIDTH is not set
+# Subsystem Options
+# CONFIG_USB_XPAD is not set
+CONFIG_BLK_DEV_SIIMAGE=m
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_SENSORS_FSCPOS is not set
+CONFIG_SND_CMIPCI=m
+# CONFIG_USB_AIPTEK is not set
+CONFIG_LARGE_ALLOCS=y
+CONFIG_FB_ATY=y
+CONFIG_SK98LIN=m
+CONFIG_SERIAL_SUNSU_CONSOLE=y
+# Sat Sep 16 21:13:13 2006
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_USB_PWC is not set
+CONFIG_PCNET32=m
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_IDE=y
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_VIDEO_BTCX=m
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_SENSORS_GL520SM is not set
+# may also be needed; see USB_STORAGE Help for more information
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+CONFIG_NATSEMI=m
+# USB Imaging devices
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_SND_SEQ_DUMMY=m
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_POWERMATE is not set
+CONFIG_FC4_SOCAL=m
+CONFIG_VIA_VELOCITY=m
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_SENSORS_W83781D is not set
+CONFIG_USB_STORAGE_ISD200=y
+# CONFIG_PROFILING is not set
+# I2C Hardware Bus support
+# CONFIG_VIDEO_MXB is not set
+CONFIG_BLK_DEV_CS5520=m
+# CONFIG_PARIDE is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_FB_CG3 is not set
+CONFIG_FB_ATY128=y
+# CONFIG_CPU_FREQ is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_IDEDMA_ONLYDISK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SPARC64_PAGE_SIZE_8KB=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_AMD8111_ETH is not set
+CONFIG_BLK_DEV_SVWKS=m
+# CONFIG_SENSORS_SMSC47M1 is not set
+CONFIG_IEEE1394_OUI_DB=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_USB_MICROTEK=m
+# CONFIG_8139CP is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# Radio Adapters
+CONFIG_FB_ATY_CT=y
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_HID=y
+# USB Host Controller Drivers
+CONFIG_DRM_MGA=m
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_BLK_DEV_PIIX is not set
+CONFIG_SUNDANCE=m
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_SND_VIRMIDI=m
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_SENSORS_LM92 is not set
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_MEGARAID_LEGACY=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_EPIC100=m
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_USB_ALI_M5632=y
+CONFIG_SERIAL_SUNSAB_CONSOLE=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_USB_OTG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_PARPORT_PC=m
+# CONFIG_BLK_DEV_HPT366 is not set
+# USB DSL modem support
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_HUGETLBFS is not set
+# CONFIG_USB_IBMCAM is not set
+CONFIG_TIGON3=m
+# CONFIG_RADIO_GEMTEK_PCI is not set
+CONFIG_IDE_GENERIC=m
+CONFIG_SKFP=m
+# CONFIG_USB_W9968CF is not set
+CONFIG_IEEE1394=m
+# FC4 drivers
+# V4L USB devices
+CONFIG_VORTEX=m
+CONFIG_BLK_DEV_IDE=y
+CONFIG_TIME_INTERPOLATION=y
+# CONFIG_FB_LEO is not set
+CONFIG_FB_ATY_GX=y
+CONFIG_TULIP=m
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_FB_RADEON=y
+CONFIG_SND_ENS1370=m
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SENSORS_IT87 is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_BINFMT_AOUT32 is not set
+CONFIG_SCSI_IMM=m
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+CONFIG_NE2K_PCI=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_USB_WACOM is not set
+CONFIG_SUNDANCE_MMIO=y
+CONFIG_SCSI_FCAL=m
+# CONFIG_BLK_DEV_TRIFLEX is not set
+CONFIG_SCSI_IPR=m
+# Please see Documentation/ide.txt for help/info on IDE drives
+CONFIG_BLK_DEV_SX8=m
+CONFIG_SCSI_DC395x=m
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_FB_FFB=y
+CONFIG_SPARSEMEM=y
+CONFIG_SCSI_INITIO=m
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_I2C_NFORCE2 is not set
+CONFIG_USB_EPSON2888=y
+# CONFIG_DE2104X is not set
+# IDE chipset support/bugfixes
+# CONFIG_VIDEO_ZORAN is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_VIDEO_BT848=m
+# CONFIG_FB_CG14 is not set
+# CONFIG_SMP is not set
+# CONFIG_USB_VICAM is not set
+CONFIG_SERIAL_SUNSU=y
+# CONFIG_SENSORS_LM83 is not set
+CONFIG_HAVE_MEMORY_PRESENT=y
+# Instrumentation Support
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_USB_SE401 is not set
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_SN9C102 is not set
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_SPARC64=y
+CONFIG_SUNGEM=m
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+# CONFIG_USB_STV680 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_USB_PRINTER=m
+CONFIG_DRM=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_SND_SEQUENCER=m
+CONFIG_BBC_I2C=m
+CONFIG_FEALNX=m
+# CONFIG_FORCEDETH is not set
+CONFIG_I2C_PARPORT=m
+CONFIG_DRM_R128=m
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# Encoders and Decoders
+# USB Input Devices
+# CONFIG_KPROBES is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_USB_STORAGE=m
+CONFIG_MYRI_SBUS=m
+CONFIG_MOUSE_PS2=y
+CONFIG_8139TOO=m
+# CONFIG_I2C_I801 is not set
+CONFIG_SCSI_DMX3191D=m
+# CONFIG_TULIP_MMIO is not set
+CONFIG_USB_LED=m
+CONFIG_USB_PEGASUS=m
+# CONFIG_SENSORS_LM77 is not set
+CONFIG_USB_STORAGE_DPCM=y
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# FC4 targets
+CONFIG_USB_LCD=m
+CONFIG_USB=y
+# CONFIG_I2C_I810 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SPARSEMEM_EXTREME=y
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_FB_RADEON_I2C is not set
+CONFIG_E100=m
+CONFIG_IEEE1394_PCILYNX=m
+# Protocol Drivers
+CONFIG_VIDEO_IR=m
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_SIS900=m
+# CONFIG_USB_STORAGE_DATAFAB is not set
+CONFIG_NET_PCI=y
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# I2C Algorithms
+# CONFIG_SENSORS_ADM1025 is not set
+CONFIG_TYPHOON=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_SCSI_PPA=m
+CONFIG_NS83820=m
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_USB_ARMLINUX=y
Added: people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc64-smp
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/config.sparc64-smp Sat Nov 11 02:48:00 2006
@@ -0,0 +1,419 @@
+CONFIG_FB_MODE_HELPERS=y
+# USB Device Class drivers
+CONFIG_IDEDMA_AUTO=y
+CONFIG_E1000=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_SOLARIS_EMUL=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_BLK_DEV_IDEDISK=m
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_DRM_TDFX=m
+# CONFIG_EEPRO100 is not set
+CONFIG_IEEE1394_DV1394=m
+CONFIG_FDDI=y
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_USB_EHCI_HCD=m
+CONFIG_SERIAL_SUNSAB=y
+CONFIG_NET_TULIP=y
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# Fibre Channel support
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_DISPLAY7SEG=m
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SERIAL is not set
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_SND_EMU10K1=m
+CONFIG_FUSION_LAN=m
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_SCSI_PLUTO=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_MOUSE_SERIAL=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_OBP_FLASH=m
+CONFIG_FB_PM2=y
+# CONFIG_I2C_VIAPRO is not set
+CONFIG_USB_ATI_REMOTE=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_IXGB=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SPARC32_COMPAT=y
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BINFMT_ELF32=y
+CONFIG_BLK_DEV_CMD64X=m
+CONFIG_USB_MDC800=m
+# CONFIG_TUNER_3036 is not set
+# CONFIG_SPARC64_PAGE_SIZE_64KB is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+CONFIG_S2IO=m
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_HID_FF is not set
+CONFIG_I2C_ALGOPCA=m
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_I2C_CHARDEV=m
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_LOCK_KERNEL=y
+CONFIG_USB_KAWETH=m
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_SPARC64_PAGE_SIZE_4MB is not set
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_WINBOND_840=m
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_FB_BW2 is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_FC4_SOC=m
+CONFIG_USB_CYTHERM=m
+CONFIG_BLK_DEV_GENERIC=m
+CONFIG_FONT_8x16=y
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_ENVCTRL=m
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_HD is not set
+# USB devices
+# CONFIG_USB_OV511 is not set
+CONFIG_LOGO_SUN_CLUT224=y
+# CONFIG_USB_DEBUG is not set
+# Miscellaneous I2C Chip support
+# Miscellaneous USB options
+CONFIG_PCI_DOMAINS=y
+CONFIG_BLK_DEV_VIA82CXXX=m
+# USB Miscellaneous drivers
+# CONFIG_SENSORS_ADM1031 is not set
+CONFIG_BLK_DEV_CS5530=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_SENSORS_PCF8574 is not set
+CONFIG_SND_ENS1371=m
+# CONFIG_SCSI_IPR_DUMP is not set
+# CONFIG_TULIP_MWI is not set
+# CONFIG_I2C_AMD756 is not set
+CONFIG_SCHED_SMT=y
+# CONFIG_VIDEO_OVCAMCHIP is not set
+CONFIG_SND_MAESTRO3=m
+CONFIG_DL2K=m
+CONFIG_USB_AN2720=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_I2C_SIS630 is not set
+CONFIG_SMP=y
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C=m
+CONFIG_COMPAT=y
+CONFIG_DRM_RADEON=m
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_I2C_PARPORT=m
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_SENSORS_ADM1026 is not set
+CONFIG_IEEE1394_OHCI1394=m
+CONFIG_STANDALONE=y
+CONFIG_USB_RIO500=m
+CONFIG_USB_BELKIN=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_64BIT=y
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# Executable file formats
+# USB port drivers
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_FSCHER is not set
+CONFIG_USB_USBNET=m
+# CONFIG_SPARC64_PAGE_SIZE_512KB is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_USB_USS720 is not set
+CONFIG_SND_ALI5451=m
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_USB_CATC=m
+CONFIG_MEGARAID_MM=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_VIDEO_BUF=m
+# CONFIG_VIDEO_SAA5246A is not set
+CONFIG_IEEE1394_SBP2=m
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_VOODOO3 is not set
+CONFIG_BLK_DEV_NS87415=m
+CONFIG_RTC=y
+CONFIG_YELLOWFIN=m
+CONFIG_SERIAL_SUNHV=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_DEFXX is not set
+# CONFIG_RADIO_MAESTRO is not set
+CONFIG_FC4=m
+# CONFIG_FB_TCX is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_VIA is not set
+# Video Capture Adapters
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_B44=m
+# CONFIG_USB_KBTAB is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SENSORS_LM75 is not set
+CONFIG_DM9102=m
+# USB Network Adapters
+CONFIG_USB_STORAGE_FREECOM=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+# CONFIG_USB_BANDWIDTH is not set
+# Subsystem Options
+# CONFIG_USB_XPAD is not set
+CONFIG_BLK_DEV_SIIMAGE=m
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_SENSORS_FSCPOS is not set
+CONFIG_SND_CMIPCI=m
+# CONFIG_USB_AIPTEK is not set
+CONFIG_LARGE_ALLOCS=y
+CONFIG_FB_ATY=y
+CONFIG_SK98LIN=m
+CONFIG_SERIAL_SUNSU_CONSOLE=y
+CONFIG_BLK_DEV_ALI15X3=m
+# CONFIG_USB_PWC is not set
+CONFIG_PCNET32=m
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_IDE=y
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_VIDEO_BTCX=m
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_SENSORS_GL520SM is not set
+# may also be needed; see USB_STORAGE Help for more information
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+CONFIG_NATSEMI=m
+# USB Imaging devices
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_SND_SEQ_DUMMY=m
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_POWERMATE is not set
+CONFIG_FC4_SOCAL=m
+CONFIG_VIA_VELOCITY=m
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_SENSORS_W83781D is not set
+CONFIG_USB_STORAGE_ISD200=y
+# CONFIG_PROFILING is not set
+# I2C Hardware Bus support
+# CONFIG_VIDEO_MXB is not set
+CONFIG_BLK_DEV_CS5520=m
+# CONFIG_PARIDE is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_FB_CG3 is not set
+CONFIG_FB_ATY128=y
+# CONFIG_CPU_FREQ is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_IDEDMA_ONLYDISK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SPARC64_PAGE_SIZE_8KB=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_AMD8111_ETH is not set
+CONFIG_BLK_DEV_SVWKS=m
+# CONFIG_SENSORS_SMSC47M1 is not set
+CONFIG_IEEE1394_OUI_DB=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_USB_MICROTEK=m
+# CONFIG_8139CP is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# Radio Adapters
+CONFIG_FB_ATY_CT=y
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_HID=y
+# USB Host Controller Drivers
+CONFIG_DRM_MGA=m
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_BLK_DEV_PIIX is not set
+CONFIG_SUNDANCE=m
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_SND_VIRMIDI=m
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_SENSORS_LM92 is not set
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_MEGARAID_LEGACY=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+CONFIG_EPIC100=m
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_USB_ALI_M5632=y
+CONFIG_SERIAL_SUNSAB_CONSOLE=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_USB_OTG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_PARPORT_PC=m
+# CONFIG_BLK_DEV_HPT366 is not set
+# USB DSL modem support
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_HUGETLBFS is not set
+# CONFIG_USB_IBMCAM is not set
+CONFIG_TIGON3=m
+# CONFIG_RADIO_GEMTEK_PCI is not set
+CONFIG_USB_LCD=m
+# Sat Sep 16 21:14:07 2006
+CONFIG_SKFP=m
+# CONFIG_USB_W9968CF is not set
+CONFIG_IEEE1394=m
+# FC4 drivers
+# V4L USB devices
+CONFIG_VORTEX=m
+CONFIG_BLK_DEV_IDE=y
+CONFIG_TIME_INTERPOLATION=y
+# CONFIG_FB_LEO is not set
+CONFIG_FB_ATY_GX=y
+CONFIG_TULIP=m
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+CONFIG_FB_RADEON=y
+CONFIG_SND_ENS1370=m
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SENSORS_IT87 is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_BINFMT_AOUT32 is not set
+CONFIG_SCSI_IMM=m
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+CONFIG_NE2K_PCI=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_USB_WACOM is not set
+CONFIG_SUNDANCE_MMIO=y
+CONFIG_SCSI_FCAL=m
+# CONFIG_BLK_DEV_TRIFLEX is not set
+CONFIG_SCSI_IPR=m
+# Please see Documentation/ide.txt for help/info on IDE drives
+CONFIG_BLK_DEV_SX8=m
+CONFIG_STOP_MACHINE=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_FB_FFB=y
+CONFIG_SPARSEMEM=y
+CONFIG_SCSI_INITIO=m
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_I2C_NFORCE2 is not set
+CONFIG_USB_EPSON2888=y
+# CONFIG_DE2104X is not set
+# IDE chipset support/bugfixes
+# CONFIG_VIDEO_ZORAN is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_VIDEO_BT848=m
+# CONFIG_FB_CG14 is not set
+CONFIG_E100=m
+# CONFIG_USB_VICAM is not set
+CONFIG_SERIAL_SUNSU=y
+# CONFIG_SENSORS_LM83 is not set
+CONFIG_HAVE_MEMORY_PRESENT=y
+# Instrumentation Support
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_USB_SE401 is not set
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_SN9C102 is not set
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_SPARC64=y
+CONFIG_SUNGEM=m
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+# CONFIG_USB_STV680 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_USB_PRINTER=m
+CONFIG_DRM=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_SND_SEQUENCER=m
+CONFIG_BBC_I2C=m
+CONFIG_FEALNX=m
+# CONFIG_FORCEDETH is not set
+# USB Serial Converter support
+CONFIG_DRM_R128=m
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# Encoders and Decoders
+CONFIG_NR_CPUS=32
+# USB Input Devices
+# CONFIG_KPROBES is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_USB_STORAGE=m
+CONFIG_MYRI_SBUS=m
+CONFIG_MOUSE_PS2=y
+CONFIG_8139TOO=m
+# CONFIG_I2C_I801 is not set
+CONFIG_SCSI_DMX3191D=m
+# CONFIG_TULIP_MMIO is not set
+CONFIG_USB_LED=m
+CONFIG_USB_PEGASUS=m
+# CONFIG_SENSORS_LM77 is not set
+CONFIG_USB_STORAGE_DPCM=y
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# FC4 targets
+CONFIG_IDE_GENERIC=m
+CONFIG_USB=y
+# CONFIG_I2C_I810 is not set
+# CONFIG_SENSORS_VIA686A is not set
+CONFIG_SPARSEMEM_EXTREME=y
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_FB_RADEON_I2C is not set
+CONFIG_SCSI_DC395x=m
+CONFIG_IEEE1394_PCILYNX=m
+# Protocol Drivers
+CONFIG_VIDEO_IR=m
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_SIS900=m
+# CONFIG_USB_STORAGE_DATAFAB is not set
+CONFIG_NET_PCI=y
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# I2C Algorithms
+# CONFIG_SENSORS_ADM1025 is not set
+CONFIG_TYPHOON=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_SCSI_PPA=m
+CONFIG_NS83820=m
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_USB_ARMLINUX=y
Added: people/maks-guest/linux-2.6/debian/arch/sparc/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,30 @@
+[base]
+flavours:
+ sparc32
+ sparc64
+ sparc64-smp
+kernel-header-dirs: sparc sparc64
+subarches:
+ vserver
+
+[image]
+suggests: silo, fdutils
+
+[sparc32]
+class: uniprocessor sparc32 (sun4m)
+kernel-arch: sparc
+kpkg-subarch: sparc
+
+[sparc32_image]
+image-postproc: sparc32-image-postproc
+
+[sparc64]
+class: uniprocessor 64-bit UltraSPARC
+kernel-arch: sparc64
+kpkg-subarch: sparc64
+
+[sparc64-smp]
+class: multiprocessor 64-bit UltraSPARC
+kernel-arch: sparc64
+kpkg-subarch: sparc64
+
Added: people/maks-guest/linux-2.6/debian/arch/sparc/vserver/defines
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/arch/sparc/vserver/defines Sat Nov 11 02:48:00 2006
@@ -0,0 +1,10 @@
+[base]
+flavours:
+ sparc64
+
+[image]
+configs: _vserver/config
+recommends: util-vserver, libc6-sparc64
+
+[sparc64_image]
+configs: sparc/config.sparc64-smp
Added: people/maks-guest/linux-2.6/debian/bin/abicheck.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/abicheck.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,90 @@
+#!/usr/bin/env python2.4
+
+import sys
+from debian_linux.abi import *
+from debian_linux.config import *
+
+class checker(object):
+ def __init__(self, dir, arch, subarch, flavour):
+ self.config = config_reader_arch(["debian/arch"])
+ self.filename_new = "%s/Module.symvers" % dir
+ abiname = self.config['abi',]['abiname']
+ if subarch == 'none':
+ self.filename_ref = "debian/arch/%s/abi-%s.%s" % (arch, abiname, flavour)
+ else:
+ self.filename_ref = "debian/arch/%s/%s/abi-%s.%s" % (arch, subarch, abiname, flavour)
+
+ def __call__(self, out):
+ ret = 0
+
+ new = symbols(self.filename_new)
+ try:
+ ref = symbols(self.filename_ref)
+ except IOError:
+ out.write("Can't read ABI reference. ABI not checked! Continuing.\n")
+ return 0
+
+ add_info, change_info, remove_info = ref.cmp(new)
+ add = set(add_info.keys())
+ change = set(change_info.keys())
+ remove = set(remove_info.keys())
+ add_ignore, change_ignore, remove_ignore = self._ignore(add_info, change_info, remove_info)
+
+ add_effective = add - add_ignore
+ change_effective = change - change_ignore
+ remove_effective = remove - remove_ignore
+
+ if change_effective or remove_effective:
+ out.write("ABI has changed! Refusing to continue.\n")
+ ret = 1
+ elif change or remove:
+ out.write("ABI has changed but all changes have been ignored. Continuing.\n")
+ elif add_effective:
+ out.write("New symbols have been added. Continuing.\n")
+ elif add:
+ out.write("New symbols have been added but have been ignored. Continuing.\n")
+ else:
+ out.write("No ABI changes.\n")
+ if add:
+ out.write("\nAdded symbols:\n")
+ t = list(add)
+ t.sort()
+ for symbol in t:
+ info = []
+ if symbol in add_ignore:
+ info.append("ignored")
+ info.append("module: %s" % add_info[symbol]['module'])
+ out.write("%-48s %s\n" % (symbol, ", ".join(info)))
+ if change:
+ out.write("\nChanged symbols:\n")
+ t = list(change)
+ t.sort()
+ for symbol in t:
+ info = []
+ if symbol in change_ignore:
+ info.append("ignored")
+ if change_info[symbol].has_key('module'):
+ info.append("module: %s -> %s" % change_info[symbol]['module'])
+ if change_info[symbol].has_key('version'):
+ info.append("version: %s -> %s" % change_info[symbol]['version'])
+ if change_info[symbol].has_key('export'):
+ info.append("export: %s -> %s" % change_info[symbol]['export'])
+ out.write("%-48s %s\n" % (symbol, ", ".join(info)))
+ if remove:
+ out.write("\nRemoved symbols:\n")
+ t = list(remove)
+ t.sort()
+ for symbol in t:
+ info = []
+ if symbol in remove_ignore:
+ info.append("ignored")
+ info.append("module: %s" % remove_info[symbol]['module'])
+ out.write("%-48s %s\n" % (symbol, ", ".join(info)))
+
+ return ret
+
+ def _ignore(self, add, change, remove):
+ return set(), set(), set()
+
+if __name__ == '__main__':
+ sys.exit(checker(*sys.argv[1:])(sys.stdout))
Added: people/maks-guest/linux-2.6/debian/bin/abiupdate.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/abiupdate.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,194 @@
+#!/usr/bin/env python2.4
+
+import sys
+sys.path.append(sys.path[0] + "/../lib/python")
+
+import optparse, os, os.path
+from debian_linux.abi import *
+from debian_linux.config import *
+from debian_linux.debian import *
+
+default_url_base = "http://ftp.de.debian.org/debian/"
+default_url_base_incoming = "http://incoming.debian.org/"
+
+class url_debian_flat(object):
+ def __init__(self, base):
+ self.base = base
+
+ def __call__(self, source, filename):
+ return self.base + filename
+
+class url_debian_pool(object):
+ def __init__(self, base):
+ self.base = base
+
+ def __call__(self, source, filename):
+ return self.base + "pool/main/" + source[0] + "/" + source + "/" + filename
+
+class main(object):
+ dir = None
+
+ def __init__(self, url, url_config = None, arch = None, subarch = None, flavour = None):
+ self.log = sys.stdout.write
+
+ self.url = self.url_config = url
+ if url_config is not None:
+ self.url_config = url_config
+ self.override_arch = arch
+ self.override_subarch = subarch
+ self.override_flavour = flavour
+
+ changelog = read_changelog()
+ while changelog[0]['Distribution'] == 'UNRELEASED':
+ changelog.pop(0)
+ changelog = changelog[0]
+
+ self.source = changelog['Source']
+ self.version = changelog['Version']['linux']['version']
+ self.version_source = changelog['Version']['linux']['source']
+
+ local_config = config_reader_arch(["debian/arch"])
+
+ self.abiname = local_config['abi',]['abiname']
+ self.version_abi = self.version + '-' + self.abiname
+
+ def __call__(self):
+ import tempfile
+ self.dir = tempfile.mkdtemp(prefix = 'abiupdate')
+ try:
+ self.log("Retreive config\n")
+ config = self.get_config()
+ if self.override_arch:
+ arches = [self.override_arch]
+ else:
+ arches = config[('base',)]['arches']
+ for arch in arches:
+ self.update_arch(config, arch)
+ finally:
+ self._rmtree(self.dir)
+
+ def _rmtree(self, dir):
+ import stat
+ for root, dirs, files in os.walk(dir, topdown=False):
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ real = os.path.join(root, name)
+ mode = os.lstat(real)[stat.ST_MODE]
+ if stat.S_ISDIR(mode):
+ os.rmdir(real)
+ else:
+ os.remove(real)
+ os.rmdir(dir)
+
+ def extract_package(self, filename, base = "tmp"):
+ base_out = self.dir + "/" + base
+ os.mkdir(base_out)
+ os.system("dpkg-deb --extract %s %s" % (filename, base_out))
+ return base_out
+
+ def get_abi(self, arch, subarch, flavour):
+ if subarch == 'none':
+ prefix = flavour
+ else:
+ prefix = subarch + '-' + flavour
+ filename = "linux-headers-%s-%s_%s_%s.deb" % (self.version_abi, prefix, self.version_source, arch)
+ f = self.retrieve_package(self.url, filename)
+ d = self.extract_package(f)
+ f1 = d + "/usr/src/linux-headers-%s-%s/Module.symvers" % (self.version_abi, prefix)
+ s = symbols(f1)
+ self._rmtree(d)
+ return s
+
+ def get_config(self):
+ filename = "linux-support-%s_%s_all.deb" % (self.version_abi, self.version_source)
+ f = self.retrieve_package(self.url_config, filename)
+ d = self.extract_package(f)
+ dir = d + "/usr/src/linux-support-" + self.version_abi + "/arch"
+ config = config_reader_arch([dir])
+ self._rmtree(d)
+ return config
+
+ def retrieve_package(self, url, filename):
+ import urllib2
+ u = url(self.source, filename)
+ filename_out = self.dir + "/" + filename
+ f_in = urllib2.urlopen(u)
+ f_out = file(filename_out, 'w')
+ while 1:
+ r = f_in.read()
+ if not r:
+ break
+ f_out.write(r)
+ return filename_out
+
+ def save_abi(self, symbols, arch, subarch, flavour):
+ out = "debian/arch/%s" % arch
+ if subarch != 'none':
+ out += "/%s" % subarch
+ out += "/abi-%s.%s" % (self.abiname, flavour)
+ symbols.write(file(out, 'w'))
+
+ def update_arch(self, config, arch):
+ if self.override_subarch:
+ subarches = [self.override_subarch]
+ else:
+ subarches = config[('base', arch)]['subarches']
+ for subarch in subarches:
+ self.update_subarch(config, arch, subarch)
+
+ def update_subarch(self, config, arch, subarch):
+ config_entry = config[('base', arch, subarch)]
+ if not config_entry.get('modules', True):
+ return
+ if self.override_flavour:
+ flavours = [self.override_flavour]
+ else:
+ flavours = config_entry['flavours']
+ for flavour in flavours:
+ self.update_flavour(config, arch, subarch, flavour)
+
+ def update_flavour(self, config, arch, subarch, flavour):
+ config_entry = config[('base', arch, subarch, flavour)]
+ if not config_entry.get('modules', True):
+ return
+ self.log("Updating ABI for arch %s, subarch %s, flavour %s: " % (arch, subarch, flavour))
+ try:
+ abi = self.get_abi(arch, subarch, flavour)
+ self.save_abi(abi, arch, subarch, flavour)
+ self.log("Ok.\n")
+ except KeyboardInterrupt:
+ self.log("Interrupted!\n")
+ sys.exit(1)
+ except Exception, e:
+ self.log("FAILED! (%s)\n" % str(e))
+
+if __name__ == '__main__':
+ options = optparse.OptionParser()
+ options.add_option("-i", "--incoming", action = "store_true", dest = "incoming")
+ options.add_option("--incoming-config", action = "store_true", dest = "incoming_config")
+ options.add_option("-u", "--url-base", dest = "url_base", default = default_url_base)
+ options.add_option("--url-base-incoming", dest = "url_base_incoming", default = default_url_base_incoming)
+
+ opts, args = options.parse_args()
+
+ kw = {}
+ if len(args) >= 1:
+ kw['arch'] =args[0]
+ if len(args) >= 2:
+ kw['subarch'] =args[1]
+ if len(args) >= 3:
+ kw['flavour'] =args[2]
+
+ url_base = url_debian_pool(opts.url_base)
+ url_base_incoming = url_debian_flat(opts.url_base_incoming)
+ if opts.incoming_config:
+ url = url_config = url_base_incoming
+ else:
+ url_config = url_base
+ if opts.incoming:
+ url = url_base_incoming
+ else:
+ url = url_base
+
+ main(url, url_config, **kw)()
Added: people/maks-guest/linux-2.6/debian/bin/check-patches.sh
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/check-patches.sh Sat Nov 11 02:48:00 2006
@@ -0,0 +1,13 @@
+#!/bin/sh -e
+
+TMPDIR=$(mktemp -d)
+trap "rm -rf $TMPDIR" EXIT
+awk '{if (NF >= 2) print "debian/patches/" $2}' debian/patches/series/* | sort -u > $TMPDIR/used
+find debian/patches ! -path '*/series*' -type f -printf "%p\n" | sort > $TMPDIR/avail
+echo "Used patches"
+echo "=============="
+cat $TMPDIR/used
+echo
+echo "Unused patches"
+echo "=============="
+fgrep -v -f $TMPDIR/used $TMPDIR/avail
Added: people/maks-guest/linux-2.6/debian/bin/gencontrol.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/gencontrol.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,260 @@
+#!/usr/bin/env python2.4
+import os, os.path, re, sys, textwrap, ConfigParser
+sys.path.append("debian/lib/python")
+import debian_linux.gencontrol
+from debian_linux.debian import *
+
+class gencontrol(debian_linux.gencontrol.gencontrol):
+ def __init__(self):
+ super(gencontrol, self).__init__()
+ self.changelog = read_changelog()
+ self.process_changelog()
+
+ def do_main_setup(self, vars, makeflags, extra):
+ super(gencontrol, self).do_main_setup(vars, makeflags, extra)
+ vars.update(self.config['image',])
+ makeflags.update({
+ 'SOURCEVERSION': self.version['linux']['source'],
+ })
+
+ def do_main_packages(self, packages, extra):
+ packages.extend(self.process_packages(self.templates["control.main"], self.vars))
+ packages.append(self.process_real_tree(self.templates["control.tree"][0], self.vars))
+ packages.extend(self.process_packages(self.templates["control.support"], self.vars))
+
+ def do_arch_setup(self, vars, makeflags, arch, extra):
+ vars.update(self.config.get(('image', arch), {}))
+
+ def do_arch_packages(self, packages, makefile, arch, vars, makeflags, extra):
+ headers_arch = self.templates["control.headers.arch"]
+ packages_headers_arch = self.process_packages(headers_arch, vars)
+
+ extra['headers_arch_depends'] = packages_headers_arch[-1]['Depends'] = package_relation_list()
+
+ for package in packages_headers_arch:
+ name = package['Package']
+ if packages.has_key(name):
+ package = packages.get(name)
+ package['Architecture'].append(arch)
+ else:
+ package['Architecture'] = [arch]
+ packages.append(package)
+
+ cmds_binary_arch = []
+ cmds_binary_arch.append(("$(MAKE) -f debian/rules.real binary-arch-arch %s" % makeflags))
+ cmds_source = []
+ cmds_source.append(("$(MAKE) -f debian/rules.real source-arch %s" % makeflags,))
+ makefile.append(("binary-arch-%s-real:" % arch, cmds_binary_arch))
+ makefile.append(("build-%s-real:" % arch))
+ makefile.append(("setup-%s-real:" % arch))
+ makefile.append(("source-%s-real:" % arch, cmds_source))
+
+ def do_subarch_setup(self, vars, makeflags, arch, subarch, extra):
+ vars.update(self.config.get(('image', arch, subarch), {}))
+ vars['localversion_headers'] = vars['localversion']
+ for i in (
+ ('kernel-header-dirs', 'KERNEL_HEADER_DIRS'),
+ ('localversion_headers', 'LOCALVERSION_HEADERS'),
+ ):
+ if vars.has_key(i[0]):
+ makeflags[i[1]] = vars[i[0]]
+
+ def do_subarch_packages(self, packages, makefile, arch, subarch, vars, makeflags, extra):
+ headers_subarch = self.templates["control.headers.subarch"]
+ package_headers = self.process_package(headers_subarch[0], vars)
+
+ name = package_headers['Package']
+ if packages.has_key(name):
+ package_headers = packages.get(name)
+ package_headers['Architecture'].append(arch)
+ else:
+ package_headers['Architecture'] = [arch]
+ packages.append(package_headers)
+
+ cmds_binary_arch = []
+ cmds_binary_arch.append(("$(MAKE) -f debian/rules.real binary-arch-subarch %s" % makeflags,))
+ cmds_source = []
+ cmds_source.append(("$(MAKE) -f debian/rules.real source-subarch %s" % makeflags,))
+ makefile.append(("binary-arch-%s-%s-real:" % (arch, subarch), cmds_binary_arch))
+ makefile.append("build-%s-%s-real:" % (arch, subarch))
+ makefile.append(("setup-%s-%s-real:" % (arch, subarch)))
+ makefile.append(("source-%s-%s-real:" % (arch, subarch), cmds_source))
+
+ def do_flavour_setup(self, vars, makeflags, arch, subarch, flavour, extra):
+ vars.update(self.config.get(('image', arch, subarch, flavour), {}))
+ for i in (
+ ('compiler', 'COMPILER'),
+ ('image-postproc', 'IMAGE_POSTPROC'),
+ ('initramfs', 'INITRAMFS',),
+ ('kernel-arch', 'KERNEL_ARCH'),
+ ('kernel-header-dirs', 'KERNEL_HEADER_DIRS'),
+ ('kpkg-arch', 'KPKG_ARCH'),
+ ('kpkg-subarch', 'KPKG_SUBARCH'),
+ ('localversion', 'LOCALVERSION'),
+ ('type', 'TYPE'),
+ ):
+ if vars.has_key(i[0]):
+ makeflags[i[1]] = vars[i[0]]
+
+ def do_flavour_packages(self, packages, makefile, arch, subarch, flavour, vars, makeflags, extra):
+ image_type_modulesextra = self.templates["control.image.type-modulesextra"]
+ image_type_modulesinline = self.templates["control.image.type-modulesinline"]
+ image_type_standalone = self.templates["control.image.type-standalone"]
+ headers = self.templates["control.headers"]
+
+ config_entry_base = self.config.merge('base', arch, subarch, flavour)
+ config_entry_relations = self.config.merge('relations', arch, subarch, flavour)
+
+ compiler = config_entry_base.get('compiler', 'gcc')
+ relations_compiler = package_relation_list(config_entry_relations[compiler])
+ relations_compiler_build_dep = package_relation_list(config_entry_relations[compiler])
+ for group in relations_compiler_build_dep:
+ for item in group:
+ item.arches = [arch]
+ packages['source']['Build-Depends'].extend(relations_compiler_build_dep)
+
+ image_depends = package_relation_list()
+ if vars.get('initramfs', True):
+ generators = vars['initramfs-generators']
+ config_entry_commands_initramfs = self.config.merge('commands-image-initramfs-generators', arch, subarch, flavour)
+ commands = [config_entry_commands_initramfs[i] for i in generators if config_entry_commands_initramfs.has_key(i)]
+ makeflags['INITRD_CMD'] = ' '.join(commands)
+ l = package_relation_group()
+ l.extend(generators)
+ image_depends.append(l)
+
+ packages_dummy = []
+ packages_own = []
+
+ if vars['type'] == 'plain-s390-tape':
+ image = image_type_standalone
+ elif vars['type'] == 'plain-xen':
+ image = image_type_modulesextra
+ config_entry_xen = self.config.merge('xen', arch, subarch, flavour)
+ p = self.process_packages(self.templates['control.xen-linux-system'], vars)
+ l = package_relation_group()
+ for version in config_entry_xen['versions']:
+ l.append("xen-hypervisor-%s-%s" % (version, config_entry_xen['flavour']))
+ makeflags['XEN_VERSIONS'] = ' '.join(['%s-%s' % (i, config_entry_xen['flavour']) for i in config_entry_xen['versions']])
+ p[0]['Depends'].append(l)
+ packages_dummy.extend(p)
+ else:
+ image = image_type_modulesinline
+
+ if not vars.has_key('desc'):
+ vars['desc'] = None
+
+ packages_own.append(self.process_real_image(image[0], {'depends': image_depends}, config_entry_relations, vars))
+ packages_own.extend(self.process_packages(image[1:], vars))
+
+ if image in (image_type_modulesextra, image_type_modulesinline):
+ makeflags['MODULES'] = True
+ package_headers = self.process_package(headers[0], vars)
+ package_headers['Depends'].extend(relations_compiler)
+ packages_own.append(package_headers)
+ extra['headers_arch_depends'].append('%s (= ${Source-Version})' % packages_own[-1]['Package'])
+
+ for package in packages_own + packages_dummy:
+ name = package['Package']
+ if packages.has_key(name):
+ package = packages.get(name)
+ package['Architecture'].append(arch)
+ else:
+ package['Architecture'] = [arch]
+ packages.append(package)
+
+ if vars['type'] == 'plain-xen':
+ for i in ('postinst', 'postrm', 'prerm'):
+ j = self.substitute(self.templates["image.xen.%s" % i], vars)
+ file("debian/%s.%s" % (packages_own[0]['Package'], i), 'w').write(j)
+
+ def get_config(default, *entry_name):
+ entry_real = ('image',) + entry_name
+ entry = self.config.get(entry_real, None)
+ if entry is None:
+ return default
+ configs = entry.get('configs', None)
+ if configs is None:
+ return default
+ return configs
+
+ kconfig = ['config']
+ kconfig.extend(get_config(["%s/config" % arch], arch))
+ if subarch == 'none':
+ kconfig.extend(get_config(["%s/config.%s" % (arch, flavour)], arch, subarch, flavour))
+ else:
+ kconfig.extend(get_config(["%s/%s/config" % (arch, subarch)], arch, subarch))
+ kconfig.extend(get_config(["%s/%s/config.%s" % (arch, subarch, flavour)], arch, subarch, flavour))
+ makeflags['KCONFIG'] = ' '.join(kconfig)
+
+ cmds_binary_arch = []
+ cmds_binary_arch.append(("$(MAKE) -f debian/rules.real binary-arch-flavour %s" % makeflags,))
+ if packages_dummy:
+ cmds_binary_arch.append(("$(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='%s' %s" % (' '.join(["-p%s" % i['Package'] for i in packages_dummy]), makeflags),))
+ cmds_build = []
+ cmds_build.append(("$(MAKE) -f debian/rules.real build %s" % makeflags,))
+ cmds_setup = []
+ cmds_setup.append(("$(MAKE) -f debian/rules.real setup-flavour %s" % makeflags,))
+ makefile.append(("binary-arch-%s-%s-%s-real:" % (arch, subarch, flavour), cmds_binary_arch))
+ makefile.append(("build-%s-%s-%s-real:" % (arch, subarch, flavour), cmds_build))
+ makefile.append(("setup-%s-%s-%s-real:" % (arch, subarch, flavour), cmds_setup))
+ makefile.append(("source-%s-%s-%s-real:" % (arch, subarch, flavour)))
+
+ def do_extra(self, packages, makefile):
+ apply = self.templates['patch.apply']
+ unpatch = self.templates['patch.unpatch']
+
+ vars = {
+ 'home': '/usr/src/kernel-patches/all/%s/debian' % self.version['linux']['upstream'],
+ 'revisions': ' '.join([i['Version']['debian'] for i in self.changelog[::-1]]),
+ }
+ vars.update(self.version['linux'])
+
+ apply = self.substitute(apply, vars)
+ unpatch = self.substitute(unpatch, vars)
+
+ file('debian/bin/patch.apply', 'w').write(apply)
+ file('debian/bin/patch.unpatch', 'w').write(unpatch)
+
+ def process_changelog(self):
+ self.version = self.changelog[0]['Version']
+ if self.version['linux']['modifier'] is not None:
+ self.abiname = ''
+ else:
+ self.abiname = '-%s' % self.config['abi',]['abiname']
+ self.vars = self.process_version_linux(self.version, self.abiname)
+
+ def process_real_image(self, in_entry, relations, config, vars):
+ entry = self.process_package(in_entry, vars)
+ for field in 'Depends', 'Provides', 'Suggests', 'Recommends', 'Conflicts':
+ value = entry.get(field, package_relation_list())
+ t = vars.get(field.lower(), [])
+ value.extend(t)
+ t = relations.get(field.lower(), [])
+ value.extend(t)
+ value.config(config)
+ if value:
+ entry[field] = value
+ return entry
+
+ def process_real_tree(self, in_entry, vars):
+ entry = self.process_package(in_entry, vars)
+ tmp = self.changelog[0]['Version']['linux']['upstream']
+ versions = []
+ for i in self.changelog:
+ if i['Version']['linux']['upstream'] != tmp:
+ break
+ versions.insert(0, i['Version']['linux'])
+ for i in (('Depends', 'Provides')):
+ value = package_relation_list()
+ value.extend(entry.get(i, []))
+ if i == 'Depends':
+ value.append("linux-patch-debian-%(version)s (= %(source)s)" % self.changelog[0]['Version']['linux'])
+ value.append(' | '.join(["linux-source-%(version)s (= %(source)s)" % v for v in versions]))
+ elif i == 'Provides':
+ value.extend(["linux-tree-%s" % v['source'].replace('~', '-') for v in versions])
+ entry[i] = value
+ return entry
+
+if __name__ == '__main__':
+ gencontrol()()
Added: people/maks-guest/linux-2.6/debian/bin/kconfig.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/kconfig.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,17 @@
+#!/usr/bin/env python2.4
+
+import optparse, os.path, sys
+from debian_linux.abi import *
+from debian_linux.config import *
+from debian_linux.kconfig import *
+
+def merge(output, *config):
+ config = [os.path.join('debian/arch', c) for c in config]
+
+ kconfig = kconfigfile()
+ for c in config:
+ kconfig.read(file(c))
+ file(output, "w").write(str(kconfig))
+
+if __name__ == '__main__':
+ sys.exit(merge(*sys.argv[1:]))
Added: people/maks-guest/linux-2.6/debian/bin/patch.apply
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/patch.apply Sat Nov 11 02:48:00 2006
@@ -0,0 +1,423 @@
+#!/usr/bin/env python2.4
+
+import os, os.path, re, sys
+from warnings import warn
+
+_default_home = "/usr/src/kernel-patches/all/2.6.18-6~2.6.19-rc5/debian"
+_default_revisions = "1"
+_default_source = "2.6.18-6~2.6.19-rc5-1"
+
+class series(list):
+ def __init__(self, name, home, reverse = False):
+ self.name = name
+ self.reverse = reverse
+
+ filename = os.path.join(home, 'series', name)
+ if not os.path.exists(filename):
+ raise RuntimeError, "Can't find series file for %s" % name
+
+ f = file(filename)
+ for line in f.readlines():
+ line = line.strip()
+
+ if len(line) == 0 or line[0] == '#':
+ continue
+
+ items = line.split(' ')
+ if len(items) != 2:
+ raise RuntimeError, "Line '%s' in file %s malformed." % (line, filename)
+ else:
+ operation, patch = items
+
+ if operation in ('+', '-'):
+ patchfile = os.path.join(home, patch)
+ for suffix, type in (('', 0), ('.bz2', 1), ('.gz', 2)):
+ if os.path.exists(patchfile + suffix):
+ patchinfo = patchfile + suffix, type
+ break
+ else:
+ raise RuntimeError, "Can't find patch %s for series %s" % (patchfile, name)
+ else:
+ raise RuntimeError, 'Undefined operation "%s" in series %s' % (operation, name)
+
+ self.append((operation, patch, patchinfo))
+
+ def __repr__(self):
+ return '<%s object for %s>' % (self.__class__.__name__, self.name)
+
+ def apply(self):
+ if self.reverse:
+ for operation, patch, patchinfo in self[::-1]:
+ if operation == '.':
+ print """\
+ (.) IGNORED %s\
+""" % patch
+ elif operation == '+':
+ self.patch_deapply(patch, patchinfo)
+ elif operation == '-':
+ self.patch_apply(patch, patchinfo)
+ print "--> %s fully unapplied." % self.name
+
+ else:
+ for operation, patch, patchinfo in self:
+ if operation == '.':
+ print """\
+ (.) IGNORED %s\
+""" % patch
+ elif operation == '+':
+ self.patch_apply(patch, patchinfo)
+ elif operation == '-':
+ self.patch_deapply(patch, patchinfo)
+ print "--> %s fully applied." % self.name
+
+ def patch_apply(self, patch, patchinfo):
+ ret = self.patch_call(patchinfo, '--fuzz=1')
+ if ret == 0:
+ print """\
+ (+) OK %s\
+""" % patch
+ else:
+ print """\
+ (+) FAIL %s\
+""" % patch
+ raise SystemExit, 1
+
+ def patch_call(self, patchinfo, patchargs):
+ patchfile, type = patchinfo
+ cmdline = []
+ if type == 0:
+ cmdline.append('cat')
+ elif type == 1:
+ cmdline.append('bzcat')
+ elif type == 2:
+ cmdline.append('zcat')
+ cmdline.append(patchfile + ' | patch -p1 -f -s -t --no-backup-if-mismatch')
+ cmdline.append(patchargs)
+ return os.spawnv(os.P_WAIT, '/bin/sh', ['sh', '-c', ' '.join(cmdline)])
+
+ def patch_deapply(self, patch, patchinfo):
+ ret = self.patch_call(patchinfo, '-R')
+ if ret == 0:
+ print """\
+ (-) OK %s\
+""" % patch
+ else:
+ print """\
+ (-) FAIL %s\
+""" % patch
+ raise SystemExit, 1
+
+ @staticmethod
+ def read_all(s, home, reverse = False):
+ ret = []
+
+ for name in s:
+ filename = os.path.join(home, 'series', name)
+ if not os.path.exists(filename):
+ warn("Can't find series file for %s" % name)
+ else:
+ i = series(name, home, reverse)
+ ret.append(i)
+
+ return ret
+
+class series_extra(series):
+ def __init__(self, name, home, extra, reverse = False):
+ self.extra = extra
+ self.extra_used = ()
+ self.name = name
+ self.reverse = reverse
+
+ filename = os.path.join(home, 'series', name + '-extra')
+ if not os.path.exists(filename):
+ raise RuntimeError, "Can't find series file for %s" % name
+
+ f = file(filename)
+ for line in f.readlines():
+ line = line.strip()
+
+ if len(line) == 0 or line[0] == '#':
+ continue
+
+ items = line.split(' ')
+ operation, patch = items[:2]
+
+ if operation in ('+', '-'):
+ patchfile = os.path.join(home, patch)
+ for suffix, type in (('', 0), ('.bz2', 1), ('.gz', 2)):
+ if os.path.exists(patchfile + suffix):
+ patchinfo = patchfile + suffix, type
+ break
+ else:
+ raise RuntimeError, "Can't find patch %s for series %s" % (patchfile, name)
+ else:
+ raise RuntimeError, 'Undefined operation "%s" in series %s' % (operation, name)
+
+ extra = {}
+ for s in items[2:]:
+ s = tuple(s.split('_'))
+ if len(s) > 3:
+ raise RuntimeError, "parse error"
+ if len(s) == 3:
+ raise RuntimeError, "Patch per flavour is not supported currently"
+ extra[s] = True
+ if not self._check_extra(extra):
+ operation = '.'
+
+ self.append((operation, patch, patchinfo))
+
+ def _check_extra(self, extra):
+ for i in (1, 2, 3):
+ t = self.extra[:i]
+ if extra.has_key(t):
+ if i > len(self.extra_used):
+ self.extra_used = t
+ return True
+ for i in (2, 3):
+ t = ('*',) + self.extra[1:i]
+ if extra.has_key(t):
+ if i > len(self.extra_used):
+ self.extra_used = t
+ return True
+ return False
+
+ @staticmethod
+ def read_all(s, home, extra, reverse = False):
+ ret = []
+
+ for name in s:
+ filename = os.path.join(home, 'series', name + '-extra')
+ if not os.path.exists(filename):
+ warn("Can't find series file for %s" % name)
+ else:
+ i = series_extra(name, home, extra, reverse)
+ ret.append(i)
+
+ return ret
+
+class version(object):
+ __slots__ = "upstream", "revision"
+
+ def __init__(self, string = None):
+ if string is not None:
+ self.upstream, self.revision = self.parse(string)
+
+ def __str__(self):
+ return "%s-%s" % (self.upstream, self.revision)
+
+ _re = r"""
+^
+(
+ (?:
+ \d+\.\d+\.\d+\+
+ )?
+ \d+\.\d+\.\d+
+ (?:
+ -.+?
+ )?
+)
+-
+([^-]+)
+$
+"""
+
+ def parse(self, version):
+ match = re.match(self._re, version, re.X)
+ if match is None:
+ raise ValueError
+ return match.groups()
+
+class version_file(object):
+ _file = 'version.Debian'
+ extra = ()
+ in_progress = False
+
+ def __init__(self, ver = None, overwrite = False):
+ if overwrite:
+ self._read(ver)
+ elif os.path.exists(self._file):
+ s = file(self._file).readline().strip()
+ self._read(s)
+ elif ver:
+ warn('No %s file, assuming pristine Linux %s' % (self._file, ver.upstream))
+ self.version = version()
+ self.version.upstream = ver.upstream
+ self.version.revision = '0'
+ else:
+ raise RuntimeError, "Not possible to determine version"
+
+ def __str__(self):
+ if self.in_progress:
+ return "unstable"
+ if self.extra:
+ return "%s %s" % (self.version, '_'.join(self.extra))
+ return str(self.version)
+
+ def _read(self, s):
+ list = s.split(' ')
+ if len(list) > 2:
+ raise RuntimeError, "Can't parse %s" % self._file
+ try:
+ self.version = version(list[0])
+ except ValueError:
+ raise RuntimeError, 'Can\'t read version in %s: "%s"' % (self._file, list[0])
+ if len(list) == 2:
+ self.extra = tuple(list[1].split('_'))
+
+ def _write(self):
+ if os.path.lexists(self._file):
+ os.unlink(self._file)
+ file(self._file, 'w').write('%s\n' % self)
+
+ def begin(self):
+ self.in_progress = True
+ self._write()
+
+ def commit(self, version = None, extra = None):
+ self.in_progress = False
+ if version is not None:
+ self.version = version
+ if extra is not None:
+ self.extra = extra
+ self._write()
+
+def main():
+ options, args = parse_options()
+
+ if len(args) > 1:
+ print "Too much arguments"
+ return
+
+ home = options.home
+ revisions = ['0'] + options.revisions.split()
+ source = version(options.source)
+ if len(args) == 1:
+ target = version(args[0])
+ else:
+ target = source
+
+ if options.current is not None:
+ vfile = version_file(options.current, True)
+ else:
+ vfile = version_file(source)
+ current = vfile.version
+ current_extra = vfile.extra
+
+ target_extra = []
+ if options.arch: target_extra.append(options.arch)
+ if options.subarch: target_extra.append(options.subarch)
+ if options.flavour: target_extra.append(options.flavour)
+ target_extra = tuple(target_extra)
+
+ if current.revision not in revisions:
+ raise RuntimeError, "Current revision is not in our list of revisions"
+ if target.revision not in revisions:
+ raise RuntimeError, "Target revision is not in our list of revisions"
+
+ if current.revision == target.revision and current_extra == target_extra:
+ print "Nothing to do"
+ return
+
+ current_index = revisions.index(current.revision)
+ source_index = revisions.index(source.revision)
+ target_index = revisions.index(target.revision)
+
+ if current_extra:
+ if current_index != source_index:
+ raise RuntimeError, "Can't patch from %s with options %s" % (current, ' '.join(current_extra))
+ consider = revisions[current_index:0:-1]
+ s = series_extra.read_all(consider, home, current_extra, reverse = True)
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(current, ())
+
+ if current_index < target_index:
+ consider = revisions[current_index + 1:target_index + 1]
+ s = series.read_all(consider, home)
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(target, ())
+ elif current_index > target_index:
+ consider = revisions[current_index:target_index:-1]
+ s = series.read_all(consider, home, reverse = True)
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(target, ())
+
+ if target_extra:
+ consider = revisions[1:target_index + 1]
+ s = series_extra.read_all(consider, home, target_extra)
+ real_extra = ()
+ for i in s:
+ t = i.extra_used
+ if len(t) > len(real_extra):
+ real_extra = t
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(target, real_extra)
+
+def parse_options():
+ from optparse import OptionParser
+ parser = OptionParser(
+ usage = "%prog [OPTION]... [TARGET]",
+ )
+ parser.add_option(
+ '-a', '--arch',
+ dest = 'arch',
+ help = "arch",
+ )
+ parser.add_option(
+ '-f', '--flavour',
+ dest = 'flavour',
+ help = "flavour",
+ )
+ parser.add_option(
+ '-s', '--subarch',
+ dest = 'subarch',
+ help = "subarch",
+ )
+ parser.add_option(
+ '-C', '--overwrite-current',
+ dest = 'current',
+ help = "overwrite current",
+ )
+ parser.add_option(
+ '-H', '--overwrite-home',
+ default = _default_home, dest = 'home',
+ help = "overwrite home [default: %default]",
+ )
+ parser.add_option(
+ '-R', '--overwrite-revisions',
+ default = _default_revisions, dest = 'revisions',
+ help = "overwrite revisions [default: %default]",
+ )
+ parser.add_option(
+ '-S', '--overwrite-source',
+ default = _default_source, dest = 'source',
+ help = "overwrite source [default: %default]",
+ )
+
+ options, args = parser.parse_args()
+
+ if options.arch is None and options.subarch is not None:
+ raise RuntimeError('You specified a subarch without an arch, this is not really working')
+ if options.subarch is None and options.flavour is not None:
+ raise RuntimeError('You specified a flavour without a subarch, this is not really working')
+
+ return options, args
+
+if __name__ == '__main__':
+ def showwarning(message, category, filename, lineno):
+ sys.stderr.write("Warning: %s\n" % message)
+ import warnings
+ warnings.showwarning = showwarning
+ try:
+ main()
+ except RuntimeError, e:
+ sys.stderr.write("Error: %s\n" % e)
+ raise SystemExit, 1
+
Added: people/maks-guest/linux-2.6/debian/bin/patch.unpatch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/patch.unpatch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -e
+
+upstream="2.6.18-6~2.6.19-rc5"
+exec "/usr/src/kernel-patches/all/$upstream/apply/debian" "$upstream-0"
Added: people/maks-guest/linux-2.6/debian/bin/sparc32-image-postproc
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/bin/sparc32-image-postproc Sat Nov 11 02:48:00 2006
@@ -0,0 +1,10 @@
+#!/bin/sh
+# It is a bit cumbersome here. Since we are executed when
+# the image is already installed and in place, we must
+# unpack it, then strip it, then gzip it again.
+image_dest="${IMAGE_TOP}/boot/vmlinuz-${version}"
+image_temp="$(mktemp)"
+gzip -dc "${image_dest}" > "${image_temp}"
+strip -R .comment -R .note -K sun4u_init -K _end -K _start "${image_temp}"
+gzip -9c "${image_temp}" > "${image_dest}"
+rm -rf "${image_temp}"
Added: people/maks-guest/linux-2.6/debian/changelog
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/changelog Sat Nov 11 02:48:00 2006
@@ -0,0 +1,2648 @@
+linux-2.6 (2.6.18-6~2.6.19-rc5-1) UNRELEASED; urgency=low
+
+ * Add new upstream 2.6.19-rc5.
+ Remove merged patches, leave a lot to check.
+
+ -- maximilian attems <maks at sternwelten.at> Sat, 11 Nov 2006 02:46:16 +0100
+
+linux-2.6 (2.6.18-6) UNRELEASED; urgency=low
+
+ [ maximilian attems ]
+ * Enable the new ACT modules globaly. They were already set for amd64, hppa
+ and mips/mipsel - needed by newer iproute2. (closes: #395882)
+
+ [ Steve Langasek ]
+ * [alpha] new titan-video patch, for compatibility with TITAN and similar
+ systems with non-standard VGA hose configs
+ * [alpha] bugfix for srm_env module from upstream (Jan-Benedict Glaw),
+ makes the module compatible with the current /proc interface so that
+ reads no longer return EFAULT. Closes: #353079.
+
+ [ Martin Michlmayr ]
+ - arm: Set CONFIG_BINFMT_MISC=m
+
+ -- maximilian attems <maks at sternwelten.at> Fri, 10 Nov 2006 08:57:45 +0100
+
+linux-2.6 (2.6.18-5) unstable; urgency=low
+
+ [ maximilian attems ]
+ * [s390] readd the fix for "S390: user readable uninitialised kernel memory
+ (CVE-2006-5174)"
+ * [s390] temporarily add patch queued for 2.6.18.3 fixing 32 bit opcodes and
+ instructions.
+
+ [ Thiemo Seufer ]
+ * Fix build failure of hugetlbfs (closes: #397139).
+ * Add kernel configuration for qemu's mips/mipsel emulation, thanks to
+ Aurelien Jarno.
+
+ [ Bastian Blank ]
+ * Update vserver patch to 2.0.2.2-rc6.
+ * Update xen parts for vserver. (closes: #397281)
+
+ [ dann frazier ]
+ * [ia64] Move to upstream version of sal-flush-fix patch, which is slightly
+ different than the early version added in 2.6.18-3.
+
+ [ Frederik Schüler ]
+ * [i386] Acticate CONFIG_SX for all flavours. (closes: #391275)
+
+ [ Steve Langasek ]
+ * [alpha] new asm-subarchs patch: tell the compiler that we're
+ deliberately emitting ev56 or ev6 instructions, so that this code
+ will still compile without having to cripple gcc-4.1's checking of
+ whether the correct instruction set is used. Closes: #397139.
+
+ [ Martin Michlmayr ]
+ * arm/ixp4xx: Enable CONFIG_USB_ATM.
+ * arm/iop32x: Enable CONFIG_PPPOE.
+ * arm/iop32x: Enable CONFIG_USB_ATM.
+
+ -- Bastian Blank <waldi at debian.org> Wed, 8 Nov 2006 17:15:55 +0100
+
+linux-2.6 (2.6.18-4) unstable; urgency=low
+
+ [ Norbert Tretkowski ]
+ * [alpha] Switched to gcc-4.1.
+
+ [ Jurij Smakov ]
+ * [sparc] Remove sparc64-atyfb-xl-gr.patch, it does more harm than
+ good in 2.6.18.
+ * [sparc] Add bugfix/sparc/compat-alloc-user-space-alignment.patch
+ (thanks to David Miller) to make sure that compat_alloc_user_space()
+ always returns memory aligned on a 8-byte boundary on sparc. This
+ prevents a number of unaligned memory accesses, like the ones in
+ sys_msgrcv() and compat_sys_msgrcv(), triggered every 5 seconds whenever
+ fakeroot is running.
+ * [sparc] Add bugfix/sparc/bus-id-size.patch (thanks to David Miller)
+ to ensure that the size of the strings stored in the bus_id field of
+ struct device never exceeds the amount of memory allocated for them
+ (20 bytes). It fixes the situations in which storing longer device
+ names in this field would cause corruption of adjacent memory regions.
+ (closes: #394697).
+ * [sparc] Add bugfix/sparc/sunblade1k-boot-fix.patch (thanks to David
+ Miller) to fix a boottime crash on SunBlade1000.
+ * [sparc] Add bugfix/sparc/t1k-cpu-lockup.patch (thanks to David Miller)
+ to prevent soft CPU lockup on T1000 servers, which can be triggered from
+ userspace, resulting in denial of service.
+
+ [ Martin Michlmayr ]
+ * arm/iop32x: Fix the interrupt of the 2nd Ethernet slot on N2100.
+ * arm/iop32x: Allow USB and serial to co-exist on N2100.
+ * arm/ixp4xx: Add clocksource for Intel IXP4xx platforms.
+ * arm: Enable CONFIG_AUDIT=y again.
+ * arm/ixp4xx: Add the IXP4xx Ethernet driver.
+ * arm/ixp4xx: Build LED support into the kernel.
+ * Add a driver for Fintek F75375S/SP and F75373.
+ * arm/iop32x: Build F75375S/SP support in.
+ * arm/iop32x: Fix the size of the RedBoot config partition.
+
+ [ maximilian attems ]
+ * Add netpoll leak fix.
+ * Add upstream forcedeth swsusp support.
+ * r8169: PCI ID for Corega Gigabit network card.
+ * r8169: the MMIO region of the 8167 stands behin BAR#1.
+ * r8169: Add upstream fix for infinite loop during hotplug.
+ * Bump build-dependency on kernel-package to 10.063.
+ * r8169: pull revert mac address change support.
+ * bcm43xx: Add full netdev watchout timeout patch. (closes: 392065)
+ Thanks Sjoerd Simons <sjoerd at spring.luon.net> for the testing.
+ * Add stable release 2.6.18.2:
+ - Remove not yet released, revert the included patches.
+ - Keep aboves bcm43xx fix, it's more complete.
+ - Watchdog: sc1200wdt - fix missing pnp_unregister_driver()
+ - fix missing ifdefs in syscall classes hookup for generic targets
+ - JMB 368 PATA detection
+ - usbfs: private mutex for open, release, and remove
+ - sound/pci/au88x0/au88x0.c: ioremap balanced with iounmap
+ - x86-64: Fix C3 timer test
+ - Reintroduce NODES_SPAN_OTHER_NODES for powerpc
+ - ALSA: emu10k1: Fix outl() in snd_emu10k1_resume_regs()
+ - IB/mthca: Use mmiowb after doorbell ring
+ - SCSI: DAC960: PCI id table fixup
+ - ALSA: snd_rtctimer: handle RTC interrupts with a tasklet
+ - JFS: pageno needs to be long
+ - SPARC64: Fix central/FHC bus handling on Ex000 systems.
+ - SPARC64: Fix memory corruption in pci_4u_free_consistent().
+ - SPARC64: Fix PCI memory space root resource on Hummingbird.
+ (closes: #392078)
+ - Fix uninitialised spinlock in via-pmu-backlight code.
+ - SCSI: aic7xxx: pause sequencer before touching SBLKCTL
+ - IPoIB: Rejoin all multicast groups after a port event
+ - ALSA: Dereference after free in snd_hwdep_release()
+ - rtc-max6902: month conversion fix
+ - NET: Fix skb_segment() handling of fully linear SKBs
+ - SCTP: Always linearise packet on input
+ - SCSI: aic7xxx: avoid checking SBLKCTL register for certain cards
+ - IPV6: fix lockup via /proc/net/ip6_flowlabel [CVE-2006-5619]
+ - fix Intel RNG detection
+ - ISDN: check for userspace copy faults
+ - ISDN: fix drivers, by handling errors thrown by ->readstat()
+ - splice: fix pipe_to_file() ->prepare_write() error path
+ - ALSA: Fix bug in snd-usb-usx2y's usX2Y_pcms_lock_check()
+ - ALSA: Repair snd-usb-usx2y for usb 2.6.18
+ - PCI: Remove quirk_via_abnormal_poweroff
+ - Bluetooth: Check if DLC is still attached to the TTY
+ - vmscan: Fix temp_priority race
+ - Use min of two prio settings in calculating distress for reclaim
+ - __div64_32 for 31 bit. Fixes funny clock speed on hercules emulator.
+ (closes: 395247)
+ - DVB: fix dvb_pll_attach for mt352/zl10353 in cx88-dvb, and nxt200x
+ - fuse: fix hang on SMP
+ - md: Fix bug where spares don't always get rebuilt properly when they become live.
+ - md: Fix calculation of ->degraded for multipath and raid10
+ - knfsd: Fix race that can disable NFS server.
+ - md: check bio address after mapping through partitions.
+ - fill_tgid: fix task_struct leak and possible oops
+ - uml: fix processor selection to exclude unsupported processors and features
+ - uml: remove warnings added by previous -stable patch
+ - Fix sfuzz hanging on 2.6.18
+ - SERIAL: Fix resume handling bug
+ - SERIAL: Fix oops when removing suspended serial port
+ - sky2: MSI test race and message
+ - sky2: pause parameter adjustment
+ - sky2: turn off PHY IRQ on shutdown
+ - sky2: accept multicast pause frames
+ - sky2: GMAC pause frame
+ - sky2: 88E803X transmit lockup (2.6.18)
+ - tcp: cubic scaling error
+ - mm: fix a race condition under SMC + COW
+ - ALSA: powermac - Fix Oops when conflicting with aoa driver
+ - ALSA: Fix re-use of va_list
+ - posix-cpu-timers: prevent signal delivery starvation
+ - NFS: nfs_lookup - don't hash dentry when optimising away the lookup
+ - uml: make Uml compile on FC6 kernel headers
+ - Fix potential interrupts during alternative patching
+ * Backport atkbd - supress "too many keys" error message.
+ * [s390] Revert temporarly 2.6.18.1 "S390: user readable uninitialised
+ kernel memory (CVE-2006-5174)" fix as it causes ftfbs
+
+ [ Sven Luther ]
+ * [powerpc] Added exception alignement patch from Benjamin Herrenschmidt.
+
+ [ Frederik Schüler ]
+ * Bump ABI to 2.
+ * Update vserver patch to 2.0.2.2-rc4.
+
+ [ Thiemo Seufer ]
+ * Add patches from linux-mips.org's 2.6.18-stable branch:
+ - bugfix/copy-user-highpage.patch, needed for cache alias handling
+ on mips/mipsel/hppa.
+ - bugfix/mips/syscall-wiring.patch, fixes TLS register access, and
+ n32 rt_sigqueueinfo.
+ - bugfix/mips/sb1-flush-cache-data-page.patch, missing cache flush
+ on SB-1.
+ - bugfix/mips/trylock.patch, fix trylock implementation for R1x000
+ and R3xxx.
+ - bugfix/mips/smp-cpu-bringup.patch, correct initialization of
+ non-contiguous CPU topology.
+ - bugfix/mips/header-exports.patch, clean up userland exports of
+ kernel headers.
+ - bugfix/mips/sb1-interrupt-handler.patch, fix broken interrupt
+ routing on SB-1.
+ - bugfix/mips/cache-alias.patch, fixes #387498 for mips/mipsel.
+ - bugfix/mips/ip22-zilog-console.patch, fix long delays seen with
+ SGI ip22 serial console.
+ - bugfix/mips/signal-handling.patch, fixes a signal handling race
+ condition shown with gdb.
+ - bugfix/mips/sb1-duart-tts.patch, replaces mips-sb1-duart-tts.patch,
+ use standard Linux names for SB-1 consoles.
+ - bugfix/mips/wait-race.patch, correct behaviour of the idle loop.
+ - bugfix/mips/sgi-ioc3.patch, checksumming fix for IOC3 network
+ driver.
+ - features/mips/qemu-kernel.patch, support for the mips/mipsel
+ machine emulated by Qemu.
+ - features/mips/backtrace.patch, reimplementation of stack analysis
+ and backtrace printing, useful for in-kernel debugging.
+ - bugfix/mips/dec-scsi.patch, replaces mips-dec-scsi.patch, fixes DSP
+ SCSI driver for DECstations.
+ - bugfix/mips/dec-serial.patch, replaces mips-dec-serial.patch, fix
+ serial console handling on DECstations.
+
+ -- Frederik Schüler <fs at debian.org> Sat, 4 Nov 2006 18:45:02 +0100
+
+linux-2.6 (2.6.18-3) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * Fix home of patch apply script.
+ * Unify CPUSET option. (closes: #391931)
+ * Support xen version 3.0.3-1.
+ * Add AHCI suspend support.
+ * Add patch to support bindmount without nodev on vserver.
+ * Update fedora xen patch to changeset 36252.
+
+ [ Steve Langasek ]
+ * [alpha] restore alpha-prctl.patch, which keeps disappearing every time
+ there's a kernel upgrade :/
+
+ [ Frederik Schüler ]
+ * Activate CONFIG_NET_CLS_* globaly. (Closes: #389918)
+ * Make CONFIG_EFI_VARS modular on i386. (Closes: #381951)
+ * Activate CONFIG_SCSI_ARCMSR on amd64, powerpc, sparc too.
+ * [vserver] Activate HARDCPU and HARDCPU_IDLE.
+ * [vserver] Upgrade to vs2.0.2.2-rc2.
+
+ [ maximilian attems ]
+ * [mipsel] Disable CONFIG_SECURITY_SECLVL on DECstations too.
+ * Add stable release 2.6.18.1:
+ - add utsrelease.h to the dontdiff file
+ - V4L: copy-paste bug in videodev.c
+ - block layer: elv_iosched_show should get elv_list_lock
+ - NETFILTER: NAT: fix NOTRACK checksum handling
+ - bcm43xx: fix regressions in 2.6.18 (Closes: #392065)
+ - x86-64: Calgary IOMMU: Fix off by one when calculating register space
+ location
+ - ide-generic: jmicron fix
+ - scx200_hrt: fix precedence bug manifesting as 27x clock in 1 MHz mode
+ - invalidate_inode_pages2(): ignore page refcounts
+ - rtc driver rtc-pcf8563 century bit inversed
+ - fbdev: correct buffer size limit in fbmem_read_proc()
+ - mm: bug in set_page_dirty_buffers
+ - TCP: Fix and simplify microsecond rtt sampling
+ - MD: Fix problem where hot-added drives are not resynced.
+ - IPV6: Disable SG for GSO unless we have checksum
+ - PKT_SCHED: cls_basic: Use unsigned int when generating handle
+ - sata_mv: fix oops
+ - [SPARC64]: Kill bogus check from bootmem_init().
+ - IPV6: bh_lock_sock_nested on tcp_v6_rcv
+ - [CPUFREQ] Fix some more CPU hotplug locking.
+ - SPARC64: Fix serious bug in sched_clock() on sparc64
+ - Fix VIDIOC_ENUMSTD bug
+ - load_module: no BUG if module_subsys uninitialized
+ - i386: fix flat mode numa on a real numa system
+ - cpu to node relationship fixup: map cpu to node
+ - cpu to node relationship fixup: acpi_map_cpu2node
+ - backlight: fix oops in __mutex_lock_slowpath during head
+ /sys/class/graphics/fb0/*
+ - do not free non slab allocated per_cpu_pageset
+ - rtc: lockdep fix/workaround
+ - powerpc: Fix ohare IDE irq workaround on old powermacs
+ - sysfs: remove duplicated dput in sysfs_update_file
+ - powerpc: fix building gdb against asm/ptrace.h
+ - Remove offsetof() from user-visible <linux/stddef.h>
+ - Clean up exported headers on CRIS
+ - Fix v850 exported headers
+ - Don't advertise (or allow) headers_{install,check} where inappropriate.
+ - Remove UML header export
+ - Remove ARM26 header export.
+ - Fix H8300 exported headers.
+ - Fix m68knommu exported headers
+ - Fix exported headers for SPARC, SPARC64
+ - Fix 'make headers_check' on m32r
+ - Fix 'make headers_check' on sh64
+ - Fix 'make headers_check' on sh
+ - Fix ARM 'make headers_check'
+ - One line per header in Kbuild files to reduce conflicts
+ - sky2 network driver device ids
+ - sky2: tx pause bug fix
+ - netdrvr: lp486e: fix typo
+ - mv643xx_eth: fix obvious typo, which caused build breakage
+ - zone_reclaim: dynamic slab reclaim
+ - Fix longstanding load balancing bug in the scheduler
+ - jbd: fix commit of ordered data buffers
+ - ALSA: Fix initiailization of user-space controls
+ - USB: Allow compile in g_ether, fix typo
+ - IB/mthca: Fix lid used for sending traps
+ - S390: user readable uninitialised kernel memory (CVE-2006-5174)
+ - zd1211rw: ZD1211B ASIC/FWT, not jointly decoder
+ - V4L: pvrusb2: Limit hor res for 24xxx devices
+ - V4L: pvrusb2: Suppress compiler warning
+ - V4L: pvrusb2: improve 24XXX config option description
+ - V4L: pvrusb2: Solve mutex deadlock
+ - DVB: cx24123: fix PLL divisor setup
+ - V4L: Fix msp343xG handling regression
+ - UML: Fix UML build failure
+ - uml: use DEFCONFIG_LIST to avoid reading host's config
+ - uml: allow using again x86/x86_64 crypto code
+ - NET_SCHED: Fix fallout from dev->qdisc RCU change
+ * Add backported git patch remving BSD secure level - request by the
+ Debian Security Team. (closes: 389282)
+ * [powerpc] Add DAC960-ipr PCI id table fixup.
+ * [powerpc] Fix uninitialised spinlock in via-pmu-backlight code.
+ * Fix serial_cs resume handling.
+ * Fix oops when removing suspended serial port.
+ * Check if DLC is still attached to the TTY.
+ * Add fedora backport of i965 DRM support.
+
+ [ Martin Michlmayr ]
+ * [mips] Apply some patches from linux-mips' linux-2.6.18-stable GIT tree:
+ - The o32 fstatat syscall behaves differently on 32 and 64 bit kernels
+ - fstatat syscall names
+ - BCM1480: Mask pending interrupts against c0_status.im.
+ - Cobalt: Time runs too quickly
+ - Show actual CPU information in /proc/cpuinfo
+ - Workaround for bug in gcc -EB / -EL options
+ - Do not use -msym32 option for modules
+ - Fix O32 personality(2) call with 0xffffffff argument
+ - Use compat_sys_mount
+
+ [ dann frazier ]
+ * [ia64]: Fix booting on HP cell systems, thanks to Troy Heber
+ - Enable CONFIG_HUGETLBFS
+ - bugfix/ia64/sal-flush-fix.patch: delay sal cache flush
+ * bugfix/sky2-receive-FIFO-fix.patch: fix sky2 hangs on some chips
+ Thanks to Stephen Hemminger for the patch. (Closes: #391382)
+ * features/all/drivers/cciss-support-for-gt-2TB-volumes.patch:
+ Add support for > 2TB volumes
+ * bugfix/sym2-dont-claim-raid-devs.patch: Prevent cpqarray/sym2 conflict
+ by telling sym2 not to claim raid devices. (Closes: #391384)
+
+ [ Sven Luther ]
+ * [powerpc] Added AMD74xx driver module to the powerpc64 flavour
+ (Closes: #391861).
+
+ [ Kyle McMartin ]
+ * [hppa] Force CROSS_COMPILE=hppa64-linux-gnu- (closes: #389296)
+
+ -- Bastian Blank <waldi at debian.org> Sat, 21 Oct 2006 15:59:43 +0200
+
+linux-2.6 (2.6.18-2) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * hppa: Fix compiler dependencies. (closes: #389296)
+ * Make cfq the default io scheduler.
+ * Add arcmsr (Areca) driver.
+ * powerpc/prep: Fix compatibility asm symlink.
+ * m68k: Disable initramfs support.
+
+ [ Kyle McMartin ]
+ * hppa: Add parisc patchset.
+
+ [ Norbert Tretkowski ]
+ * [alpha] Workaround undefined symbols by setting CONFIG_SCSI=y for smp flavour.
+ (closes: #369517)
+
+ [ Christian T. Steiges ]
+ * m68k: Update patches for 2.6.18.
+ * m68k: Re-Add m68k-as and m68k-macro patch which allow building with current binutils.
+ * m68k: disable CONFIG_AUDIT for m68k.
+ * m68k/mac: add m68k-no-backlight and m68k-fbcon patch.
+ * m68k/mac: enable SONIC, disable all ADB but CUDA.
+
+ [ Jurij Smakov ]
+ * Add bugfix/proc-fb-reading.patch to fix the inconsistent behaviour
+ of /proc/fb. (Closes: #388815)
+ * sparc: Enable vserver flavour for sparc64. (Closes: #386656)
+
+ -- Bastian Blank <waldi at debian.org> Fri, 29 Sep 2006 14:12:19 +0200
+
+linux-2.6 (2.6.18-1) unstable; urgency=low
+
+ The unpruned release
+
+ [ Martin Michlmayr ]
+ * Bump build-dependency on kernel-package to 10.054.
+ * arm/iop32x: Build ext2/3 as modules.
+ * arm/iop32x: Disable CONFIG_EMBEDDED.
+ * mipsel/r5k-cobalt: Enable ISDN.
+ * arm/footbridge: Enable the CIFS module (closes: #274808).
+ * arm/nslu2: Drop flavour since this machine is supported by arm/ixp4xx.
+ * arm: Make get_unaligned() work with const pointers and GCC 4.1.
+ * mipsel/r5k-cobalt: Enable CONFIG_BONDING as a module.
+ * arm/iop32x: Likewise.
+ * arm/ixp4xx: Likewise.
+ * arm: Disable CONFIG_AUDIT for now since it's broken.
+
+ [ Sven Luther ]
+ * [powerpc] Enabled the -prep flavour. (Closes: #359025)
+ * [powerpc] The sisfb framebuffer device is now builtin.
+ * [powerpc] Updated the powerpc serial patch. This fixes the XServe serial
+ port, but at the cost powermac pcmcia serial cards support.
+ Thanks go to Mark Hymers for providing the patch.
+ (Closes: #364637, #375194)
+ * [powerpc] Added patch to fix oldworld/quik booting.
+ Thanks fo to Christian Aichinger for investigating to Benjamin
+ Herrenschmidt for providing the patch. (Closes: #366620, #375035).
+ * [powerpc] Fixes hvc_console caused suspsend-to-disk breakage. Thanks to
+ Andrew Morton for providing the patch. (Closes: #387178)
+ * [powerpc] Disabled mv643xx_eth on powerpc64 flavours, as there never was a
+ Marvell Discovery northbrige for 64bit powerpc cpus.
+
+ [ Frederik Schüler ]
+ * Remove obsolete options from amd64 and i386 configs.
+ * Deactivate EVBUG.
+ * Make PARPORT options global.
+ * [i386] Add class definition for 486 flavour.
+
+ [ maximilian attems ]
+ * Enable CONFIG_PRINTER=m for all powerpc flavours.
+ * Enable the new alsa CONFIG_SND_AOA framework for powerpc.
+ * Add the merged advansys pci table patch.
+
+ [ Bastian Blank ]
+ * hppa: Use gcc-4.1.
+ * Only provide 16 legacy ptys.
+
+ [ Norbert Tretkowski ]
+ * [alpha] Updated configs.
+ * [alpha] Disabled CONFIG_AUDIT, broken.
+ * [alpha] Added vserver flavour.
+
+ -- Bastian Blank <waldi at debian.org> Sun, 24 Sep 2006 15:55:37 +0200
+
+linux-2.6 (2.6.17-9) unstable; urgency=medium
+
+ [ Bastian Blank ]
+ * Update vserver patch to 2.0.2.
+ - Fix possible priviledge escalation in remount code. (CVE-2006-4243)
+
+ [ Frederik Schüler ]
+ * Add stable release 2.5.17.12:
+ - sky2: version 1.6.1
+ - sky2: fix fiber support
+ - sky2: MSI test timing
+ - sky2: use dev_alloc_skb for receive buffers
+ - sky2: clear status IRQ after empty
+ - sky2: accept flow control
+ - dm: Fix deadlock under high i/o load in raid1 setup.
+ - Remove redundant up() in stop_machine()
+ - Missing PCI id update for VIA IDE
+ - PKTGEN: Fix oops when used with balance-tlb bonding
+ - PKTGEN: Make sure skb->{nh,h} are initialized in fill_packet_ipv6() too.
+ - Silent data corruption caused by XPC
+ - uhci-hcd: fix list access bug
+ - binfmt_elf: fix checks for bad address
+ - [s390] bug in futex unqueue_me
+ - fcntl(F_SETSIG) fix
+ - IPV6 OOPS'er triggerable by any user
+ - SCTP: Fix sctp_primitive_ABORT() call in sctp_close().
+ - SPARC64: Fix X server crashes on sparc64
+ - TG3: Disable TSO by default
+ - dm: mirror sector offset fix
+ - dm: fix block device initialisation
+ - dm: add module ref counting
+ - dm: fix mapped device ref counting
+ - dm: add DMF_FREEING
+ - dm: change minor_lock to spinlock
+ - dm: move idr_pre_get
+ - dm: fix idr minor allocation
+ - dm snapshot: unify chunk_size
+ - Have ext2 reject file handles with bad inode numbers early.
+ - Allow per-route window scale limiting
+ - bridge-netfilter: don't overwrite memory outside of skb
+ - fix compilation error on IA64
+ - Fix output framentation of paged-skbs
+ - spectrum_cs: Fix firmware uploading errors
+ - TEXTSEARCH: Fix Boyer Moore initialization bug
+ * Add stable release 2.6.17.13:
+ - lib: add idr_replace
+ - pci_ids.h: add some VIA IDE identifiers
+ * Remove patches merged upstream:
+ - s390-kernel-futex-barrier.patch
+ * Unpatch ia64-mman.h-fix.patch
+
+ -- Bastian Blank <waldi at debian.org> Wed, 13 Sep 2006 14:54:14 +0200
+
+linux-2.6 (2.6.17-8) unstable; urgency=low
+
+ [ Martin Michlmayr ]
+ * arm/ixp4xx: Enable CONFIG_W1.
+
+ [ dann frazier ]
+ * sound-pci-hda-mac-mini-quirks.diff, sound-pci-hda-intel-d965.diff
+ sound-pci-hda-mac-mini-intel945.diff:
+ Updates to patch_sigmatel.c to add x86 mac-mini sound support
+ Thanks to Matt Kraai. (closes: #384972)
+
+ [ Kyle McMartin ]
+ * hppa: Re-enable pa8800 fixing patches from James Bottomley.
+ Pulled fresh from parisc-linux git tree.
+ * ia64: Pull in compile-failure fix from Christian Cotte-Barrot.
+ Pulled from linux-ia64 mailing list. Fix is correct.
+ * hppa/alpha/mips: Fix compile-failure due to missing arch_mmap_check. Patch sent
+ upstream to stable at kernel.org.
+
+ [ dann frazier ]
+ * sym2: only claim "Storage" class devices - the cpqarray driver should be
+ used for 5c1510 devices in RAID mode. (closes: #380272)
+
+ [ Bastian Blank ]
+ * Backport change to allow all hypercalls for xen.
+
+ -- Bastian Blank <waldi at debian.org> Thu, 31 Aug 2006 12:12:51 +0200
+
+linux-2.6 (2.6.17-7) unstable; urgency=low
+
+ [ Martin Michlmayr ]
+ * arm/iop32x: Enable CONFIG_BLK_DEV_OFFBOARD.
+ * arm/iop32x: Unset CONFIG_BLK_DEV_AMD74XX since it fails on ARM
+ with "Unknown symbol pci_get_legacy_ide_irq".
+ * arm/iop32x: Enable a number of MD and DM modules.
+ * arm/iop32x: Enable some more USB network modules.
+ * mipsel/r5k-cobalt: Increase 8250 NR_UARTS and RUNTIME_UARTS to 4.
+ * mipsel/r5k-cobalt: Fix MAC detection problem on Qube 2700.
+
+ [ Bastian Blank ]
+ * Update vserver patch to 2.0.2-rc29.
+ * Add stable release 2.6.17.10:
+ - Fix possible UDF deadlock and memory corruption (CVE-2006-4145)
+ - elv_unregister: fix possible crash on module unload
+ - Fix sctp privilege elevation (CVE-2006-3745)
+
+ [ maximilian attems ]
+ * Add RAM range to longclass for -bigmem. (closes: 382799)
+ * Add stable release 2.6.17.9:
+ - powerpc: Clear HID0 attention enable on PPC970 at boot time
+ (CVE-2006-4093)
+ * Add stable release 2.6.17.11:
+ - Fix ipv4 routing locking bug
+ - disable debugging version of write_lock()
+ - PCI: fix ICH6 quirks
+ - 1394: fix for recently added firewire patch that breaks things on ppc
+ - Fix IFLA_ADDRESS handling
+ - Fix BeFS slab corruption
+ - Fix timer race in dst GC code
+ - Have ext3 reject file handles with bad inode numbers early
+ - Kill HASH_HIGHMEM from route cache hash sizing
+ - sys_getppid oopses on debug kernel
+ - IA64: local DoS with corrupted ELFs
+ - tpm: interrupt clear fix
+ - ulog: fix panic on SMP kernels
+ - dm: BUG/OOPS fix
+ - MD: Fix a potential NULL dereference in md/raid1
+ - ip_tables: fix table locking in ipt_do_table
+ - swsusp: Fix swap_type_of
+ - sky2: phy power problem on 88e805x
+ - ipx: header length validation needed
+
+ [ Frederik Schüler ]
+ * Activate CONFIG_R8169_VLAN on amd64. (closes: #383707)
+ * Activate EFI boot support on i386. (closes: #381951)
+
+ [ dann frazier ]
+ * Include module.lds in headers package if it exists. (closes: #342246)
+ * Add Apple MacBook product IDs to usbhid and set
+ CONFIG_USB_HIDINPUT_POWERBOOK=y on i386 and amd64. (closes: #383620)
+
+ -- Bastian Blank <waldi at debian.org> Thu, 24 Aug 2006 15:54:51 +0000
+
+linux-2.6 (2.6.17-6) unstable; urgency=low
+
+ [ maximilian attems ]
+ * debian/arch/i386/defines: Activate 686-bigmem flavour for enterprise
+ usage.
+ * Add ubuntu pci table patch for scsi drivers advansys and fdomain.
+
+ [ Martin Michlmayr ]
+ * arm/armeb: Use gcc-4.1.
+ * mips/mipsel: Use gcc-4.1.
+ * arm/ixp4xx: Update config based on the NSLU2 config.
+ * arm/s3c2410: Unset CONFIG_DEBUG_INFO.
+ * arm/iop32x: xscale: don't mis-report 80219 as an iop32x
+ * arm/iop32x: Add an MTD map for IOP3xx boards
+ * arm/iop32x: Add support for the Thecus N2100.
+ * arm/iop32x: Add support for the GLAN Tank.
+ * arm/iop32x: Add a flavour for IOP32x based machines.
+
+ [ Bastian Blank ]
+ * Shrink short descriptions.
+ * Make gcc-4.1 the default compiler.
+ * [powerpc]: Use gcc-4.1.
+ * Move latest and transitional packages to linux-latest-2.6.
+
+ [ Frederik Schüler ]
+ * [amd64] Add smp-alternatives backport.
+ * [amd64] Drop smp flavours.
+ * [amd64] Merge k8 and p4 flavours into a generic one, following upstreams
+ advice.
+ * Activate BSD_PROCESS_ACCT_V3.
+ * Add stable release 2.6.17.8:
+ - ALSA: Don't reject O_RDWR at opening PCM OSS
+ - Add stable branch to maintainers file
+ - tty serialize flush_to_ldisc
+ - S390: fix futex_atomic_cmpxchg_inatomic
+ - Fix budget-av compile failure
+ - cond_resched() fix
+ - e1000: add forgotten PCI ID for supported device
+ - ext3: avoid triggering ext3_error on bad NFS file handle
+ - ext3 -nobh option causes oops
+ - Fix race related problem when adding items to and svcrpc auth cache.
+ - ieee1394: sbp2: enable auto spin-up for Maxtor disks
+ - invalidate_bdev() speedup
+ - Sparc64 quad-float emulation fix
+ - VLAN state handling fix
+ - Update frag_list in pskb_trim
+ - UHCI: Fix handling of short last packet
+ - sky2: NAPI bug
+ - i2c: Fix 'ignore' module parameter handling in i2c-core
+ - scx200_acb: Fix the block transactions
+ - scx200_acb: Fix the state machine
+ - H.323 helper: fix possible NULL-ptr dereference
+ - Don't allow chmod() on the /proc/<pid>/ files
+ - PCI: fix issues with extended conf space when MMCONFIG disabled because of e820
+
+ [ Sven Luther ]
+ * [powerpc] Added console=hvsi0 too to CMDLINE to the powerpc64 flavour, for
+ non-virtualized IBM power machines serial console.
+
+ -- Bastian Blank <waldi at debian.org> Fri, 11 Aug 2006 19:58:06 +0200
+
+linux-2.6 (2.6.17-5) unstable; urgency=low
+
+ [ Martin Michlmayr ]
+ * [arm/nslu2] Enable CONFIG_USB_EHCI_SPLIT_ISO. Closes: #378554
+
+ [ maximilian attems ]
+ * Add stable release 2.6.17.7:
+ - BLOCK: Fix bounce limit address check
+ - v4l/dvb: Fix budget-av frontend detection
+ - v4l/dvb: Fix CI on old KNC1 DVBC cards
+ - v4l/dvb: Fix CI interface on PRO KNC1 cards
+ - v4l/dvb: Backport fix to artec USB DVB devices
+ - v4l/dvb: Backport the DISEQC regression fix to 2.6.17.x
+ - v4l/dvb: stradis: dont export MODULE_DEVICE_TABLE
+ - pnp: suppress request_irq() warning
+ - generic_file_buffered_write(): handle zero-length iovec segments
+ - serial 8250: sysrq deadlock fix
+ - Reduce ACPI verbosity on null handle condition
+ - ieee80211: TKIP requires CRC32
+ - Make powernow-k7 work on SMP kernels.
+ - via-velocity: the link is not correctly detected when the device starts
+ - Add missing UFO initialisations
+ - USB serial ftdi_sio: Prevent userspace DoS (CVE-2006-2936)
+ - cdrom: fix bad cgc.buflen assignment
+ - splice: fix problems with sys_tee()
+ - fix fdset leakage
+ - struct file leakage
+ - XFS: corruption fix
+ - v4l/dvb: Kconfig: fix description and dependencies for saa7115 module
+ - dvb-bt8xx: fix frontend detection for DViCO FusionHDTV DVB-T Lite rev 1.2
+ - IB/mthca: restore missing PCI registers after reset
+ - v4l/dvb: Backport the budget driver DISEQC instability fix
+ - Fix IPv4/DECnet routing rule dumping
+ - pdflush: handle resume wakeups
+ - x86_64: Fix modular pc speaker
+ - Fix powernow-k8 SMP kernel on UP hardware bug.
+ - ALSA: RME HDSP - fixed proc interface (missing {})
+ - ALSA: au88x0 - Fix 64bit address of MPU401 MMIO port
+ - ALSA: Fix a deadlock in snd-rtctimer
+ - ALSA: Fix missing array terminators in AD1988 codec support
+ - ALSA: Fix model for HP dc7600
+ - ALSA: Fix mute switch on VAIO laptops with STAC7661
+ - ALSA: fix the SND_FM801_TEA575X dependencies
+ - ALSA: Fix undefined (missing) references in ISA MIRO sound driver
+ - ALSA: Fix workaround for AD1988A rev2 codec
+ - ALSA: hda-intel - Fix race in remove
+ - Suppress irq handler mismatch messages in ALSA ISA drivers
+ - PKT_SCHED: Fix illegal memory dereferences when dumping actions
+ - PKT_SCHED: Return ENOENT if action module is unavailable
+ - PKT_SCHED: Fix error handling while dumping actions
+ - generic_file_buffered_write(): deadlock on vectored write
+ - ethtool: oops in ethtool_set_pauseparam()
+ - memory hotplug: solve config broken: undefined reference to `online_page'
+ * Add budget-av-compile-fix.patch stable compile fix.
+ * Enable in all configs setting SND_FM801_TEA575X SND_FM801_TEA575X_BOOL=y.
+
+ -- Bastian Blank <waldi at debian.org> Sat, 29 Jul 2006 13:30:06 +0200
+
+linux-2.6 (2.6.17-4) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * Add stable release 2.6.17.5:
+ - Fix nasty /proc vulnerability (CVE-2006-3626)
+ * Add stable release 2.6.17.6:
+ - Relax /proc fix a bit
+ * Set section of images to admin.
+
+ [ dann frazier ]
+ * [ia64] Drop the non-SMP flavours; they are not well maintained upstream.
+ Note that the non-SMP flavours have been identical to the SMP builds
+ since 2.6.13-1; this was to avoid having to drop then re-add these
+ flavours if upstream resolved the issue - but that never happened.
+ Note that this is a measurable performance penalty on non-SMP systems.
+
+ -- Bastian Blank <waldi at debian.org> Mon, 17 Jul 2006 11:08:41 +0200
+
+linux-2.6 (2.6.17-3) unstable; urgency=low
+
+ [ maximilian attems ]
+ * Add stable release 2.6.17.2:
+ - ide-io: increase timeout value to allow for slave wakeup
+ - NTFS: Critical bug fix (affects MIPS and possibly others)
+ - Link error when futexes are disabled on 64bit architectures
+ - SCTP: Reset rtt_in_progress for the chunk when processing its sack.
+ - SPARC32: Fix iommu_flush_iotlb end address
+ - ETHTOOL: Fix UFO typo
+ - UML: fix uptime
+ - x86: compile fix for asm-i386/alternatives.h
+ - bcm43xx: init fix for possible Machine Check
+ - SCTP: Fix persistent slowdown in sctp when a gap ack consumes rx buffer.
+ - kbuild: bugfix with initramfs
+ - Input: return correct size when reading modalias attribute
+ - ohci1394: Fix broken suspend/resume in ohci1394
+ - idr: fix race in idr code
+ - USB: Whiteheat: fix firmware spurious errors
+ - libata: minor patch for ATA_DFLAG_PIO
+ - SCTP: Send only 1 window update SACK per message.
+ - PFKEYV2: Fix inconsistent typing in struct sadb_x_kmprivate.
+ - SCTP: Limit association max_retrans setting in setsockopt.
+ - SCTP: Reject sctp packets with broadcast addresses.
+ - IPV6: Sum real space for RTAs.
+ - IPV6 ADDRCONF: Fix default source address selection without
+ CONFIG_IPV6_PRIVACY
+ - IPV6: Fix source address selection.
+ * Add stable release 2.6.17.3:
+ - NETFILTER: SCTP conntrack: fix crash triggered by packet without chunks
+ [CVE-2006-2934]
+ * Deapply merged sparc32-iotlb.patch.
+ * Fix README.Debian: Correct svn location, remove old boot param bswap
+ reference, the asfs patch is in the Debian kernel. Remove reference to
+ AMD 768 erratum 10, it was solved in 2.6.12. Add wording corrections.
+ * Set CONFIG_SERIAL_8250_RN_UARTS=16 for all archs beside mips/m68k unless
+ explicitly set on a specific value. (closes: 377151)
+ * Add stable release 2.6.17.4:
+ - fix prctl privilege escalation and suid_dumpable (CVE-2006-2451)
+
+ [ Sven Luther ]
+ * Re-enabled fs-asfs patch.
+
+ [ Thiemo Seufer ]
+ * [mips,mipsel] Fix sb1 interrupt handlers.
+ * [mips,mipsel] Fix devfs-induced build failure in sb1250 serial driver.
+ * [mips] SGI ip22 RTC was broken, fixed thanks to Julien Blache.
+ * [mips] Fix SGI ip22 serial console, thanks to Julien Blache.
+
+ [ Martin Michlmayr ]
+ * [arm/nslu2] Enable HFS and some other filesystems.
+ * [arm/nslu2] Unset CONFIG_USB_STORAGE_DEBUG. Closes: #377853.
+
+ -- Bastian Blank <waldi at debian.org> Thu, 13 Jul 2006 13:14:53 +0200
+
+linux-2.6 (2.6.17-2) unstable; urgency=low
+
+ [ Jurij Smakov ]
+ * [sparc] Switch to gcc-4.1 as it produces a working kernel,
+ while gcc-4.0 does not. No ABI bump neccessary, because
+ 2.6.17-1 sparc binaries never made it to the archive.
+ * [sparc32] Add sparc32-iotlb.patch to fix DMA errors on sparc32.
+
+ [ Sven Luther ]
+ * [powerpc] Added console=hvc0 default commandline option to powerpc64 flavour.
+ * [powerpc] Fixed mkvmlinuz support, which was missing from -1. (Closes: #375645)
+ * [powerpc] Added PowerBook HID support for last-gen PowerBook keyboards.
+ (Closes: #307327)
+
+ [ Martin Michlmayr ]
+ * [mipsel] Fix compilation error in dz serial driver.
+ * [mipsel] Update configs.
+ * [mipsel] Add a build fix for the Cobalt early console support.
+ * [arm/nslu2] Disable SE Linux support for now so the kernel fits into flash.
+
+ [ Christian T. Steigies ]
+ * [m68k] Update patches for 2.6.17.
+ * [m68k] Add m68k-as and m68k-macro patch which allow building with current binutils.
+ * [m68k] Disable all subarches but amiga and mac for official linux-images.
+
+ [ Kyle McMartin ]
+ * [hppa] Update patchset (2.6.17-pa6) from parisc-linux.org.
+ Which fixes relocation errors in modules with 64-bit kernels, and
+ a softlockup on non-SMP flavours with gettimeofday.
+
+ -- Bastian Blank <waldi at debian.org> Thu, 29 Jun 2006 18:49:35 +0200
+
+linux-2.6 (2.6.17-1) unstable; urgency=low
+
+ [ Frederik Schüler ]
+ * New upstream release.
+ * [amd64] Use gcc 4.1.
+ * [amd64] Drop amd64-generic flavor. We will use amd64-k8 for the
+ installer.
+
+ [ Martin Michlmayr ]
+ * [mips] Update patches for 2.6.17.
+ * [arm] Update configs.
+ * [armeb] Update configs.
+
+ [ Thiemo Seufer ]
+ * [mips] Fix SWARM FPU detection.
+ * [mips] Update configurations.
+
+ [ Kyle McMartin ]
+ * [hppa] Set PDC_CHASSIS_WARN to y.
+ * [hppa] Update patchset (2.6.17-pa2) from parisc-linux.org.
+ * [hppa] Change NR_CPUS to 8 from 32 on both SMP flavours.
+ * [hppa] Set PARISC_PAGE_SIZE to 4K on all platforms.
+
+ [ Bastian Blank ]
+ * [s390] Use gcc 4.1.
+ * [i386] Enable REGPARM.
+ * [i386] Use gcc 4.1.
+ * [powerpc] Disable prep.
+
+ [ dann frazier ]
+ * [ia64] Update configs
+ * [ia64] Use gcc 4.1.
+
+ [ maximilian attems ]
+ * Add stable release 2.6.17.1:
+ - xt_sctp: fix endless loop caused by 0 chunk length (CVE-2006-3085)
+
+ -- Bastian Blank <waldi at debian.org> Thu, 22 Jun 2006 12:13:15 +0200
+
+linux-2.6 (2.6.16+2.6.17-rc3-0experimental.1) experimental; urgency=low
+
+ [ Frederik Schüler ]
+ * New upstream release candidate.
+ * Switch HZ from 1000 to 250, following upstreams default.
+ * Activate CONFIG_BCM43XX_DEBUG.
+
+ [ maximilian attems ]
+ * Disable broken and known unsecure LSM modules: CONFIG_SECURITY_SECLVL,
+ CONFIG_SECURITY_ROOTPLUG. Upstream plans to remove them for 2.6.18
+
+ -- Frederik Schüler <fs at debian.org> Sun, 7 May 2006 17:06:29 +0200
+
+linux-2.6.16 (2.6.16-18) unstable; urgency=high
+
+ [ Sven Luther ]
+ * [powerpc] Added console=hvsi0 too to CMDLINE to the powerpc64 flavour,
+ for non-virtualized IBM power machines serial console.
+
+ [ dann frazier ]
+ * fs-ext3-bad-nfs-handle.patch: avoid triggering ext3_error on bad NFS
+ file handle (CVE-2006-3468)
+ * cdrom-bad-cgc.buflen-assign.patch: fix buffer overflow in dvd_read_bca
+ * usb-serial-ftdi_sio-dos.patch: fix userspace DoS in ftdi_sio driver
+
+ [ Bastian Blank ]
+ * Update xen patch to changeset 9762.
+
+ -- Frederik Schüler <fs at debian.org> Fri, 18 Aug 2006 20:29:17 +0200
+
+linux-2.6.16 (2.6.16-17) unstable; urgency=high
+
+ [ Martin Michlmayr ]
+ * Add stable release 2.6.16.22:
+ - powernow-k8 crash workaround
+ - NTFS: Critical bug fix (affects MIPS and possibly others)
+ - JFS: Fix multiple errors in metapage_releasepage
+ - SPARC64: Fix D-cache corruption in mremap
+ - SPARC64: Respect gfp_t argument to dma_alloc_coherent().
+ - SPARC64: Fix missing fold at end of checksums.
+ - scsi_lib.c: properly count the number of pages in scsi_req_map_sg()
+ - I2O: Bugfixes to get I2O working again
+ - Missed error checking for intent's filp in open_namei().
+ - tmpfs: time granularity fix for [acm]time going backwards
+ - USB: Whiteheat: fix firmware spurious errors
+ - fs/namei.c: Call to file_permission() under a spinlock in do_lookup_path()
+ * Add stable release 2.6.16.23:
+ - revert PARPORT_SERIAL should depend on SERIAL_8250_PCI patch
+ - NETFILTER: SCTP conntrack: fix crash triggered by packet without
+ chunks (CVE-2006-2934)
+ * Add stable release 2.6.16.24:
+ - fix prctl privilege escalation and suid_dumpable (CVE-2006-2451)
+ * Add stable release 2.6.16.25:
+ - Fix nasty /proc vulnerability (CVE-2006-3626)
+ * Relax /proc fix a bit (Linus Torvalds)
+
+ * [arm/nslu2] Unset CONFIG_USB_STORAGE_DEBUG. Closes: #377853.
+ * [mips] SGI ip22 RTC was broken, fixed thanks to Julien Blache.
+ * [mips] Fix SGI ip22 serial console, thanks to Julien Blache.
+
+ [ Bastian Blank ]
+ * Fix vserver patch.
+
+ -- Bastian Blank <waldi at debian.org> Sat, 15 Jul 2006 17:18:49 +0200
+
+linux-2.6.16 (2.6.16-16) unstable; urgency=low
+
+ [ Sven Luther ]
+ * [powerpc] Added console=hvc0 default commandline option to powerpc64 flavour.
+ * [powerpc] Now THERM_PM72 and all WINDFARMs are builtin, for better fan control.
+
+ [ Martin Michlmayr ]
+ * [arm/nslu2] Disable SE Linux support for now so the kernel fits into
+ flash. Closes: #376926.
+
+ [ Bastian Blank ]
+ * [powerpc,powerpc-miboot] Enable OpenFirmware device tree support.
+ (closes: #376012)
+
+ -- Bastian Blank <waldi at debian.org> Sat, 8 Jul 2006 17:57:57 +0200
+
+linux-2.6.16 (2.6.16-15) unstable; urgency=low
+
+ [ maximilian attems ]
+ * Add stable release 2.6.16.18:
+ - NETFILTER: SNMP NAT: fix memory corruption (CVE-2006-2444)
+ * Add stable release 2.6.16.19:
+ - NETFILTER: Fix small information leak in SO_ORIGINAL_DST (CVE-2006-1343)
+ * Add stable release 2.6.16.20:
+ - x86_64: Don't do syscall exit tracing twice
+ - Altix: correct ioc4 port order
+ - Input: psmouse - fix new device detection logic
+ - PowerMac: force only suspend-to-disk to be valid
+ - the latest consensus libata resume fix
+ - Altix: correct ioc3 port order
+ - Cpuset: might sleep checking zones allowed fix
+ - ohci1394, sbp2: fix "scsi_add_device failed" with PL-3507 based devices
+ - sbp2: backport read_capacity workaround for iPod
+ - sbp2: fix check of return value of hpsb_allocate_and_register_addrspace
+ - x86_64: x86_64 add crashdump trigger points
+ - ipw2200: Filter unsupported channels out in ad-hoc mode
+ * Add stable release 2.6.16.21:
+ - check_process_timers: fix possible lockup
+ - run_posix_cpu_timers: remove a bogus BUG_ON() (CVE-2006-2445)
+ - xt_sctp: fix endless loop caused by 0 chunk length (CVE-2006-3085)
+ - powerpc: Fix machine check problem on 32-bit kernels (CVE-2006-2448)
+
+ [ Christian T. Steigies ]
+ * [m68k] Add mac via patch from Finn Thain.
+ * [m68k] Enable INPUT_EVDEV.
+
+ [ Martin Michlmayr ]
+ * [mips/b1-bcm91250a] Enable SMP.
+ * [mips] Add a compile fix for the Maxine fb.
+ * [mipsel] Add a patch that let's you enable serial console on DECstation.
+ * [mipsel] Add a patch to get SCSI working on DECstation.
+ * [mipsel] Handle memory-mapped RTC chips properly.
+ * [mipsel] Add configs for r3k-kn02 and r4k-kn04 DECstation.
+ * [arm] Allow RiscPC machines to boot an initrd (tagged list fix).
+ * [arm/nslu2] Enable many modules.
+ * [arm] Build loop support as a module.
+ * [arm] Use the generic netfilter configuration.
+ * [arm/footbridge] Enable sound.
+
+ [ Kyle McMartin ]
+ * [hppa] Pulled patch from cvs to fix build of kernel/ptrace.c which needs
+ {read,write}_can_lock.
+ * [hppa] Disable CONFIG_DETECT_SOFTLOCKUP to fix boot on pa8800 machines.
+
+ [ Sven Luther ]
+ * [powerpc,prep] Added a new ARCH=ppc PReP flavour, currently mostly a copy
+ of the -powerpc one.
+ * Upgraded mkvmlinuz dependency to mkvmlinuz 21.
+
+ [ Bastian Blank ]
+ * Update vserver patch to 2.0.2-rc21.
+ * Bump build-dependency on kernel-package to 10.049.
+
+ [ Jurij Smakov ]
+ * Add dcache-memory-corruption.patch to fix the mremap(), occasionally
+ triggered on sparc in the form of dpkg database corruption. Affects
+ sparc64, mips and generic includes. Thanks to David Miller, original
+ patch is included in 2.6.17.
+ Ref: http://marc.theaimsgroup.com/?l=linux-sparc&m=114920963824047&w=2
+ * Add sparc32-iotlb.patch to fix the DMA errors encountered with latest
+ kernels on sparc32, in particularly HyperSparcs. Thanks to Bob Breuer.
+ Ref: http://marc.theaimsgroup.com/?l=linux-sparc&m=115077649707675&w=2
+
+ -- Bastian Blank <waldi at debian.org> Wed, 21 Jun 2006 14:09:11 +0200
+
+linux-2.6 (2.6.16-14) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * Add stable release 2.6.16.16:
+ - fs/locks.c: Fix lease_init (CVE-2006-1860)
+ * Make i386 xen images recommend libc6-xen.
+ * Update vserver patch to 2.0.2-rc20.
+ * Update xen patch to changeset 9687.
+
+ [ Christian T. Steigies ]
+ * [m68k] Add generic m68k ide fix.
+ * [m68k] Add cross-compile instructions.
+ * [m68k] Enable INPUT_EVDEV for yaird.
+ * [m68k] sun3 general compile and scsi fixes, enable sun3 SCSI again.
+
+ [ dann frazier ]
+ * cs4281 - Fix the check of timeout in probe to deal with variable HZ.
+ (closes: #361197)
+
+ [ Norbert Tretkowski ]
+ * [alpha] Readded patch to support prctl syscall, got lost when upgrading
+ to 2.6.16.
+
+ [ Frederik Schüler ]
+ * Add stable release 2.6.16.17:
+ - SCTP: Validate the parameter length in HB-ACK chunk (CVE-2006-1857)
+ - SCTP: Respect the real chunk length when walking parameters
+ (CVE-2006-1858)
+ - ptrace_attach: fix possible deadlock schenario with irqs
+ - Fix ptrace_attach()/ptrace_traceme()/de_thread() race
+ - page migration: Fix fallback behavior for dirty pages
+ - add migratepage address space op to shmem
+ - Remove cond_resched in gather_stats()
+ - VIA quirk fixup, additional PCI IDs
+ - PCI quirk: VIA IRQ fixup should only run for VIA southbridges
+ - Fix udev device creation
+ - limit request_fn recursion
+ - PCI: correctly allocate return buffers for osc calls
+ - selinux: check for failed kmalloc in security_sid_to_context()
+ - TG3: ethtool always report port is TP.
+ - Netfilter: do_add_counters race, possible oops or info leak
+ (CVE-2006-0039)
+ - scx200_acb: Fix resource name use after free
+ - smbus unhiding kills thermal management
+ - fs/compat.c: fix 'if (a |= b )' typo
+ - smbfs: Fix slab corruption in samba error path
+ - fs/locks.c: Fix sys_flock() race
+ - USB: ub oops in block_uevent
+ - via-rhine: zero pad short packets on Rhine I ethernet cards
+ - md: Avoid oops when attempting to fix read errors on raid10
+
+ -- Bastian Blank <waldi at debian.org> Mon, 22 May 2006 14:56:11 +0200
+
+linux-2.6 (2.6.16-13) unstable; urgency=low
+
+ [ Frederik Schüler ]
+ * Add stable release 2.6.16.14:
+ - smbfs chroot issue (CVE-2006-1864)
+
+ [ Bastian Blank ]
+ * Don't make headers packages depend on images.
+ * Bump abiname to 2. (closes: #366291)
+ * Update vserver patch to 2.0.2-rc19.
+ * Update xen patch to changeset 9668.
+ * Remove abi fixes.
+ * Add stable release 2.6.16.15:
+ - SCTP: Allow spillover of receive buffer to avoid deadlock. (CVE-2006-2275)
+ - SCTP: Fix panic's when receiving fragmented SCTP control chunks. (CVE-2006-2272)
+ - SCTP: Fix state table entries for chunks received in CLOSED state. (CVE-2006-2271)
+ - SCTP: Prevent possible infinite recursion with multiple bundled DATA. (CVE-2006-2274)
+ * Switch HZ from 1000 to 250.
+
+ [ Christian T. Steigies ]
+ * [m68k] Add patches that allow building images for atari
+ * [m68k] Enable atyfb driver for atari
+
+ -- Bastian Blank <waldi at debian.org> Wed, 10 May 2006 18:58:44 +0200
+
+linux-2.6 (2.6.16-12) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * Add stable release 2.6.16.12:
+ - dm snapshot: fix kcopyd destructor
+ - x86_64: Pass -32 to the assembler when compiling the 32bit vsyscall pages
+ - for_each_possible_cpu
+ - Simplify proc/devices and fix early termination regression
+ - sonypi: correct detection of new ICH7-based laptops
+ - MIPS: Fix tx49_blast_icache32_page_indexed.
+ - NET: e1000: Update truesize with the length of the packet for packet split
+ - i386: fix broken FP exception handling
+ - tipar oops fix
+ - USB: fix array overrun in drivers/usb/serial/option.c
+ - Altix snsc: duplicate kobject fix
+ - Alpha: strncpy() fix
+ - LSM: add missing hook to do_compat_readv_writev()
+ - Fix reiserfs deadlock
+ - make vm86 call audit_syscall_exit
+ - fix saa7129 support in saa7127 module for pvr350 tv out
+ - dm flush queue EINTR
+ - get_dvb_firmware: download nxt2002 firmware from new driver location
+ - cxusb-bluebird: bug-fix: power down corrupts frontend
+ - x86_64: Fix a race in the free_iommu path.
+ - MIPS: Use "R" constraint for cache_op.
+ - MIPS: R2 build fixes for gcc < 3.4.
+ - cs5535_gpio.c: call cdev_del() during module_exit to unmap kobject references and other cleanups
+ - MIPS: Fix branch emulation for floating-point exceptions.
+ - x86/PAE: Fix pte_clear for the >4GB RAM case
+ * Add stable release 2.6.16.13:
+ - NETFILTER: SCTP conntrack: fix infinite loop (CVE-2006-1527)
+ * Remove merged patches.
+ * Rediff xen patch.
+ * Bump build-dependency on kernel-package to 10.047.
+
+ [ Martin Michlmayr ]
+ * [arm] Enable cramfs for ixp4xx and rpc.
+
+ -- Bastian Blank <waldi at debian.org> Thu, 4 May 2006 11:37:26 +0200
+
+linux-2.6 (2.6.16-11) unstable; urgency=low
+
+ * Update vserver patch to 2.0.2-rc18.
+ - Limit ccaps to root inside a guest (CVE-2006-2110)
+ * Conflict with known broken grub versions. (closes: #361308)
+ * Enable s390 vserver image.
+ * Enable xen and xen-vserver images.
+ * Use localversion for kernel-package images. (closes: #365505)
+
+ -- Bastian Blank <waldi at debian.org> Mon, 1 May 2006 16:38:45 +0200
+
+linux-2.6 (2.6.16-10) unstable; urgency=low
+
+ [ Norbert Tretkowski ]
+ * [alpha] Added backport of for_each_possible_cpu() to fix alpha build.
+ (closes: #364206)
+ * Add stable release 2.6.16.10:
+ - IPC: access to unmapped vmalloc area in grow_ary()
+ - Add more prevent_tail_call()
+ - alim15x3: ULI M-1573 south Bridge support
+ - apm: fix Armada laptops again
+ - fbdev: Fix return error of fb_write
+ - Fix file lookup without ref
+ - m41t00: fix bitmasks when writing to chip
+ - Open IPMI BT overflow
+ - x86: be careful about tailcall breakage for sys_open[at] too
+ - x86: don't allow tail-calls in sys_ftruncate[64]()
+ - IPV6: XFRM: Fix decoding session with preceding extension header(s).
+ - IPV6: XFRM: Don't use old copy of pointer after pskb_may_pull().
+ - IPV6: Ensure to have hop-by-hop options in our header of &sk_buff.
+ - selinux: Fix MLS compatibility off-by-one bug
+ - PPC: fix oops in alsa powermac driver
+ - MTD_NAND_SHARPSL and MTD_NAND_NANDSIM should be tristate's
+ - i2c-i801: Fix resume when PEC is used
+ - Fix hotplug race during device registration
+ - Fix truesize underflow
+ - efficeon-agp: Add missing memory mask
+ - 3ware 9000 disable local irqs during kmap_atomic
+ - 3ware: kmap_atomic() fix
+
+ [ maximilian attems ]
+ * Add stable release 2.6.16.11:
+ - Don't allow a backslash in a path component (CVE-2006-1863)
+
+ -- Bastian Blank <waldi at debian.org> Tue, 25 Apr 2006 13:56:19 +0200
+
+linux-2.6 (2.6.16-9) unstable; urgency=low
+
+ [ maximilian attems ]
+ * Add stable release 2.6.16.8:
+ - ip_route_input panic fix (CVE-2006-1525)
+ * Add stable release 2.6.16.9:
+ - i386/x86-64: Fix x87 information leak between processes (CVE-2006-1056)
+
+ [ Bastian Blank ]
+ * Update vserver patch to 2.0.2-rc17.
+
+ -- Bastian Blank <waldi at debian.org> Thu, 20 Apr 2006 15:37:28 +0200
+
+linux-2.6 (2.6.16-8) unstable; urgency=low
+
+ * Fix ABI-breakage introduced in -7. (closes: #363032)
+ * Add stable release 2.6.16.6:
+ - ext3: Fix missed mutex unlock
+ - RLIMIT_CPU: fix handling of a zero limit
+ - alpha: SMP boot fixes
+ - m32r: security fix of {get, put}_user macros
+ - m32r: Fix cpu_possible_map and cpu_present_map initialization for SMP kernel
+ - shmat: stop mprotect from giving write permission to a readonly attachment (CVE-2006-1524)
+ - powerpc: fix incorrect SA_ONSTACK behaviour for 64-bit processes
+ - MPBL0010 driver sysfs permissions wide open
+ - cciss: bug fix for crash when running hpacucli
+ - fuse: fix oops in fuse_send_readpages()
+ - Fix utime(2) in the case that no times parameter was passed in.
+ - Fix buddy list race that could lead to page lru list corruptions
+ - NETFILTER: Fix fragmentation issues with bridge netfilter
+ - USB: remove __init from usb_console_setup
+ - Fix suspend with traced tasks
+ - isd200: limit to BLK_DEV_IDE
+ - edac_752x needs CONFIG_HOTPLUG
+ - fix non-leader exec under ptrace
+ - sky2: bad memory reference on dual port cards
+ - atm: clip causes unregister hang
+ - powerpc: iSeries needs slb_initialize to be called
+ - Fix block device symlink name
+ - Incorrect signature sent on SMB Read
+ * Add stable release 2.6.16.7:
+ - fix MADV_REMOVE vulnerability (CVE-2006-1524 for real this time)
+
+ -- Bastian Blank <waldi at debian.org> Tue, 18 Apr 2006 16:22:31 +0200
+
+linux-2.6 (2.6.16-7) unstable; urgency=low
+
+ [ Frederik Schüler ]
+ * Add stable release 2.6.16.3:
+ - Keys: Fix oops when adding key to non-keyring (CVE-2006-1522)
+
+ [ Bastian Blank ]
+ * Add stable release 2.6.16.4:
+ - RCU signal handling (CVE-2006-1523)
+
+ [ Sven Luther ]
+ * [powerpc] Transitioned mkvmlinuz support patch to the 2.6.16 ARCH=powerpc
+ tree. PReP is broken in 2.6.16 though.
+
+ [ maximilian attems ]
+ * Add stable release 2.6.16.5:
+ - x86_64: Clean up execve
+ - x86_64: When user could have changed RIP always force IRET (CVE-2006-0744)
+ * Disable CONFIG_SECCOMP (adds useless overhead on context-switch) -
+ thanks to fs for checking abi.
+
+ [ Christian T. Steigies ]
+ * [m68k] update m68k patch and config to 2.6.16, temporarily disable atari
+
+ -- Bastian Blank <waldi at debian.org> Sat, 15 Apr 2006 13:56:05 +0200
+
+linux-2.6 (2.6.16-6) unstable; urgency=medium
+
+ [ Bastian Blank ]
+ * Provide version infos in support package and don't longer rely on the
+ changelog.
+ * [amd64/i386] Enable cpu hotplug support.
+
+ [ maximilian attems ]
+ * Add stable release 2.6.16.2:
+ - PCMCIA_SPECTRUM must select FW_LOADER
+ - drivers/net/wireless/ipw2200.c: fix an array overun
+ - AIRO{,_CS} <-> CRYPTO fixes
+ - tlclk: fix handling of device major
+ - fbcon: Fix big-endian bogosity in slow_imageblit()
+ - Fix NULL pointer dereference in node_read_numastat()
+ - USB: EHCI full speed ISO bugfixes
+ - Mark longhaul driver as broken.
+ - fib_trie.c node freeing fix
+ - USB: Fix irda-usb use after use
+ - sysfs: zero terminate sysfs write buffers (CVE-2006-1055)
+ - USB: usbcore: usb_set_configuration oops (NULL ptr dereference)
+ - pcmcia: permit single-character-identifiers
+ - hostap: Fix EAPOL frame encryption
+ - wrong error path in dup_fd() leading to oopses in RCU
+ - {ip, nf}_conntrack_netlink: fix expectation notifier unregistration
+ - isicom must select FW_LOADER
+ - knfsd: Correct reserved reply space for read requests.
+ - Fix module refcount leak in __set_personality()
+ - sbp2: fix spinlock recursion
+ - powerpc: make ISA floppies work again
+ - opti9x - Fix compile without CONFIG_PNP
+ - Add default entry for CTL Travel Master U553W
+ - Fix the p4-clockmod N60 errata workaround.
+ - kdump proc vmcore size oveflow fix
+
+ -- Bastian Blank <waldi at debian.org> Mon, 10 Apr 2006 16:09:51 +0200
+
+linux-2.6 (2.6.16-5) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * Provide real dependency packages for module building.
+ - Add linux-headers-$version-$abiname-all and
+ linux-headers-$version-$abiname-all-$arch.
+ * Rename support package to linux-support-$version-$abiname.
+ * Fix module package output.
+ * Include .kernelrelease in headers packages. (closes: #359813)
+ * Disable Cumana partition support completely. (closes: #359207)
+ * Update vserver patch to 2.0.2-rc15.
+
+ [ dann frazier ]
+ * [ia64] initramfs-tools works now, no longer restrict initramfs-generators
+
+ -- Bastian Blank <waldi at debian.org> Mon, 3 Apr 2006 14:00:08 +0200
+
+linux-2.6 (2.6.16-4) unstable; urgency=medium
+
+ [ Martin Michlmayr ]
+ * [arm/armeb] Update nslu2 config.
+ * Add stable release 2.6.16.1:
+ - Fix speedstep-smi assembly bug in speedstep_smi_ownership
+ - DMI: fix DMI onboard device discovery
+ - cciss: fix use-after-free in cciss_init_one
+ - DM: Fix bug: BIO_RW_BARRIER requests to md/raid1 hang.
+ - fix scheduler deadlock
+ - proc: fix duplicate line in /proc/devices
+ - rtc.h broke strace(1) builds
+ - dm: bio split bvec fix
+ - v9fs: assign dentry ops to negative dentries
+ - i810fb_cursor(): use GFP_ATOMIC
+ - NET: Ensure device name passed to SO_BINDTODEVICE is NULL terminated.
+ - XFS writeout fix
+ - sysfs: fix a kobject leak in sysfs_add_link on the error path
+ - get_cpu_sysdev() signedness fix
+ - firmware: fix BUG: in fw_realloc_buffer
+ - sysfs: sysfs_remove_dir() needs to invalidate the dentry
+ - TCP: Do not use inet->id of global tcp_socket when sending RST (CVE-2006-1242)
+ - 2.6.xx: sata_mv: another critical fix
+ - Kconfig: VIDEO_DECODER must select FW_LOADER
+ - V4L/DVB (3324): Fix Samsung tuner frequency ranges
+ - sata_mv: fix irq port status usage
+
+ -- Bastian Blank <waldi at debian.org> Tue, 28 Mar 2006 17:19:10 +0200
+
+linux-2.6 (2.6.16-3) unstable; urgency=low
+
+ [ Frederik Schüler ]
+ * [amd64] Add asm-i386 to the linux-headers packages.
+
+ [ Jonas Smedegaard ]
+ * Tighten yaird dependency to at least 0.0.12-8 (supporting Linux
+ 2.6.16 uppercase hex in Kconfig and new IDE sysfs naming, and VIA
+ IDE on powerpc).
+
+ [ Martin Michlmayr ]
+ * [arm/armeb] Enable CONFIG_NFSD on NSLU2 again. Closes: #358709.
+ * [arm/footbridge] CONFIG_NE2K_PCI should be a module, not built-in.
+ * [arm/footbridge] Enable CONFIG_BLK_DEV_IDECD=m since the CATS can
+ have a CD-ROM drive.
+ * [mips/sb1*] Use ttyS rather than duart as the name for the serial
+ console since the latter causes problems with debian-installer.
+
+ [ Bastian Blank ]
+ * Update vserver patch to 2.0.2-rc14.
+ - Fix sendfile. (closes: #358391, #358752)
+
+ -- Bastian Blank <waldi at debian.org> Mon, 27 Mar 2006 16:08:20 +0200
+
+linux-2.6 (2.6.16-2) unstable; urgency=low
+
+ [ dann frazier ]
+ * [ia64] Set unconfigured options:
+ CONFIG_PNP_DEBUG=n and CONFIG_NET_SB1000=m
+ * [hppa] Update config for 2.6.16
+
+ [ Martin Michlmayr ]
+ * [mips/mipsel] Put something in the generic config file because diff
+ will otherwise remove the empty file, causing the build to fail.
+ * [mipsel/r5k-cobalt] Set CONFIG_PACKET=y.
+ * [arm] Set CONFIG_MACLIST=y for ixp4xx because nas100d needs it.
+
+ [ Frederik Schüler ]
+ * Add Maximilian Attems to uploaders list.
+
+ -- Martin Michlmayr <tbm at cyrius.com> Wed, 22 Mar 2006 15:15:14 +0000
+
+linux-2.6 (2.6.16-1) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * New upstream release.
+ * Default to initramfs-tools 0.55 or higher on s390.
+
+ [ maximilian attems ]
+ * Default to initramfs-tools on arm and armeb.
+
+ [ Martin Michlmayr ]
+ * [mips/mipsel] Add an image for the Broadcom BCM91480B evaluation board
+ (aka "BigSur").
+ * [arm, armeb] Enable the netconsole module.
+ * [mipsel/cobalt] Enable the netconsole module.
+ * [mips] SB1: Fix interrupt disable hazard (Ralf Baechle).
+ * [mips] SB1: Support for 1480 ethernet (Broadcom).
+ * [mips] SB1: Support for NAPI (Tom Rix).
+ * [mips] SB1: DUART support (Broadcom).
+ * [mips] Work around bad code generation for <asm/io.h> (Ralf Baechle).
+ * [mips] Fix VINO drivers when using a 64-bit kernel (Mikael Nousiainen).
+ * [arm/armeb] Update configs for 2.6.16.
+ * [mips/mipsel] Update configs for 2.6.16.
+ * [arm/armeb] Enable the SMB module on NSLU2.
+ * [mipsel] Enable parallel port modules for Cobalt since there are PCI
+ cards that can be used in a Qube.
+ * [mipsel] Enable the JFS module on Cobalt.
+
+ [ dann frazier ]
+ * [ia64] use yaird on ia64 until #357414 is fixed
+ * [ia64] Update configs for 2.6.16
+
+ -- Bastian Blank <waldi at debian.org> Tue, 21 Mar 2006 16:12:16 +0100
+
+linux-2.6 (2.6.15+2.6.16-rc5-0experimental.1) experimental; urgency=low
+
+ [ Frederik Schüler ]
+ * New upstream release candidate.
+
+ [ Martin Michlmayr ]
+ * Add initial mips/mipsel 2.6 kernels.
+ * Important changes compared to the 2.4 kernels:
+ - Drop the XXS1500 flavour since there's little interest in it.
+ - Drop the LASAT flavour since these machines never went into
+ production.
+ - Drop the IP22 R5K (Indy, Indigo2) flavour since the IP22 R4K
+ image now also works on machines with a R5K CPU.
+ - Add an image for SGI IP32 (O2).
+ - Rename the sb1-swarm-bn flavour to sb1-bcm91250a.
+ - Enable PCI network (and other) modules on Cobalt. Closes: #315895.
+ * Add various MIPS related patches:
+ - Fix iomap compilation on machines without COW.
+ - Improve gettimeofday on MIPS.
+ - Fix an oops on IP22 zerilog (serial console).
+ - Improve IDE probing so it won't take so long on Cobalt.
+ - Probe for IDE disks on SWARM.
+ - Test whether there's a scache (fixes Cobalt crash).
+ - Add Tulip fixes for Cobalt.
+ * Fix a typo in the description of the linux-doc-* package,
+ thanks Justin Pryzby. Closes: #343424.
+ * [arm] Enable nfs and nfsd modules.
+ * [arm/footbride] Suggest nwutil (Netwinder utilities).
+
+ -- Frederik Schüler <fs at debian.org> Thu, 9 Mar 2006 14:13:17 +0000
+
+linux-2.6 (2.6.15+2.6.16-rc4-0experimental.1) experimental; urgency=low
+
+ [ Frederik Schüler ]
+ * New upstream release.
+ * Activate CONFIG_DVB_AV7110_OSD on alpha amd64 and ia64.
+ Closes: #353292
+ * Globally enable NAPI on all network card drivers which support it.
+
+ [ maximilian attems ]
+ * Drop fdutils from i386 and amd64 Suggests.
+ * Swap lilo and grub Suggests for i386 and amd64.
+
+ [ Jurij Smakov ]
+ * Make sure that LOCALVERSION environment variable is not
+ passed to a shell while invoking make-kpkg, since it
+ appends it to the version string, breaking the build.
+ Closes: #349472
+ * [sparc32] Re-enable the building of sparc32 images.
+ * [sparc64] Re-add (partial) sparc64-atyf-xl-gr.patch, since it
+ was only partially applied upstream, so the problem (garbled
+ screen output on SunBlade 100) is still present. Thanks to
+ Luis Ortiz for pointing it out.
+ * Bump the build-dep on kernel-package to 10.035, which fixes
+ the problem with building documentation packages.
+
+ [ Martin Michlmayr ]
+ * [sparc] Add sys_newfstatat -> sys_fstatat64 fix from git.
+ * [arm] Update configs for 2.6.16-rc3.
+ * [armeb] Update configs for 2.6.16-rc3.
+ * [arm/armeb] Fix compilation error on NSLU2 due to recent flash
+ changes.
+ * [arm/armeb] Fix a compilation error in the IXP4xx beeper support
+ (Alessandro Zummo).
+
+ [ Norbert Tretkowski ]
+ * [alpha] Update arch/alpha/config* for 2.6.16-rc3.
+
+ -- Bastian Blank <waldi at debian.org> Fri, 24 Feb 2006 16:02:11 +0000
+
+linux-2.6 (2.6.15-8) unstable; urgency=high
+
+ [ maximilian attems ]
+ * Add stable Release 2.6.15.5:
+ - Fix deadlock in br_stp_disable_bridge
+ - Fix a severe bug
+ - i386: Move phys_proc_id/early intel workaround to correct function
+ - ramfs: update dir mtime and ctime
+ - sys_mbind sanity checking
+ - Fix s390 build failure.
+ - Revert skb_copy_datagram_iovec() recursion elimination.
+ - s390: add #ifdef __KERNEL__ to asm-s390/setup.h
+ - netfilter missing symbol has_bridge_parent
+ - hugetlbfs mmap ENOMEM failure
+ - IB/mthca: max_inline_data handling tweaks
+ - it87: Fix oops on removal
+ - hwmon it87: Probe i2c 0x2d only
+ - reiserfs: disable automatic enabling of reiserfs inode attributes
+ - Fix snd-usb-audio in 32-bit compat environment
+ - dm: missing bdput/thaw_bdev at removal
+ - dm: free minor after unlink gendisk
+ - gbefb: IP32 gbefb depth change fix
+ - shmdt cannot detach not-alined shm segment cleanly.
+ - Address autoconfiguration does not work after device down/up cycle
+ - gbefb: Set default of FB_GBE_MEM to 4 MB
+ - XFS ftruncate() bug could expose stale data (CVE-2006-0554)
+ - sys_signal: initialize ->sa_mask
+ - do_sigaction: cleanup ->sa_mask manipulation
+ - fix zap_thread's ptrace related problems
+ - fix deadlock in ext2
+ - cfi: init wait queue in chip struct
+ - sd: fix memory corruption with broken mode page headers
+ - sbp2: fix another deadlock after disconnection
+ - skge: speed setting
+ - skge: fix NAPI/irq race
+ - skge: genesis phy initialization fix
+ - skge: fix SMP race
+ - x86_64: Check for bad elf entry address (CVE-2006-0741)
+ - alsa: fix bogus snd_device_free() in opl3-oss.c
+ - ppc32: Put cache flush routines back into .relocate_code section
+ - sys32_signal() forgets to initialize ->sa_mask
+ - Normal user can panic NFS client with direct I/O (CVE-2006-0555)
+ * Deactivate merged duplicates: s390-klibc-buildfix.patch,
+ powerpc-relocate_code.patch.
+ * Add stable Release 2.6.15.6:
+ - Don't reset rskq_defer_accept in reqsk_queue_alloc
+ - fs/nfs/direct.c compile fix
+ - mempolicy.c compile fix, make sure BITS_PER_BYTE is defined
+ - [IA64] die_if_kernel() can return (CVE-2006-0742)
+
+ [ Sven Luther ]
+ * [powerpc] Disabled CONFIG_IEEE1394_SBP2_PHYS_DMA, which was broken on
+ powerpc64, as it used the long deprecated bus_to_virt symbol.
+ (Closes: #330225)
+ * [powerpc] Fixed gettimeofday breakage causing clock drift.
+
+ -- Bastian Blank <waldi at debian.org> Mon, 6 Mar 2006 11:06:28 +0100
+
+linux-2.6 (2.6.15-7) unstable; urgency=low
+
+ [ Norbert Tretkowski ]
+ * [alpha] Disabled CONFIG_ALPHA_LEGACY_START_ADDRESS for -alpha-generic and
+ -alpha-smp flavours, and introduced a new -alpha-legacy flavour for MILO
+ based machines, which has CONFIG_ALPHA_LEGACY_START_ADDRESS enabled.
+ (closes: #352186)
+ * [alpha] Added new patch to support prctl syscall. (closes: #349765)
+ * [i386] Renamed kernel-image-2.6-486 to kernel-image-2.6-386, it's meant for
+ transition only, and kernel-image-2.6-386 is the package name in sarge.
+
+ [ Jurij Smakov ]
+ * Bump build-dependency on kernel-package to 10.035, which is fixed
+ to build the documentation packages again.
+ Closes: #352000, #348332
+
+ [ Frederik Schüler ]
+ * Activate CONFIG_DVB_AV7110_OSD on alpha amd64 and ia64.
+ Closes: #353292
+ * Deactivate CONFIG_FB_ATY_XL_INIT on all architectures: it is broken and
+ already removed in 2.6.16-rc.
+ Closes: #353310
+
+ [ Christian T. Steigies ]
+ * [m68k] build in cirrusfb driver
+
+ -- Bastian Blank <waldi at debian.org> Tue, 21 Feb 2006 17:35:21 +0000
+
+linux-2.6 (2.6.15-6) unstable; urgency=low
+
+ [ Bastian Blank ]
+ * Moved the mkvmlinuz support patch modification to a -1 version of the
+ patch.
+
+ [ maximilian attems ]
+ * Add stable treee 2.6.15.4
+ - PCMCIA=m, HOSTAP_CS=y is not a legal configuration
+ - Input: iforce - do not return ENOMEM upon successful allocation
+ - x86_64: Let impossible CPUs point to reference per cpu data
+ - x86_64: Clear more state when ignoring empty node in SRAT parsing
+ - x86_64: Dont record local apic ids when they are disabled in MADT
+ - Fix keyctl usage of strnlen_user()
+ - Kill compat_sys_clock_settime sign extension stub.
+ - Input: grip - fix crash when accessing device
+ - Input: db9 - fix possible crash with Saturn gamepads
+ - Input: iforce - fix detection of USB devices
+ - Fixed hardware RX checksum handling
+ - SCSI: turn off ordered flush barriers
+ - Input: mousedev - fix memory leak
+ - seclvl settime fix
+ - fix regression in xfs_buf_rele
+ - md: remove slashes from disk names when creation dev names in sysfs
+ - d_instantiate_unique / NFS inode leakage
+ - dm-crypt: zero key before freeing it
+ - bridge: netfilter races on device removal
+ - bridge: fix RCU race on device removal
+ - SELinux: fix size-128 slab leak
+ - __cmpxchg() must really always be inlined
+ - emu10k1 - Fix the confliction of 'Front' control
+ - Input: sidewinder - fix an oops
+ * Deactivate merged alpha-cmpxchg-inline.patch, sparc64-clock-settime.patch.
+
+ [ Christian T. Steigies ]
+ * [m68k] Add fix for m68k/buddha IDE and m68k/mac SCSI driver
+ * [m68k] Patch by Peter Krummrich to stop flickering pixels with PicassoII
+ * [m68k] make Amiga keyboard usable again, patch by Roman Zippel
+ * [m68k] prevent wd33c93 SCSI driver from crashing the kernel, patch by Roman Zippel
+ * [m68k] remove SBCs from VME descriptions (closes: #351924)
+
+ -- Frederik Schüler <fs at debian.org> Fri, 10 Feb 2006 15:33:21 +0000
+
+linux-2.6 (2.6.15-5) unstable; urgency=low
+
+ [ Martin Michlmayr ]
+ * Add a fix for the input support for the ixp4xx beeper driver from
+ 2.6.16-rc2.
+ * Add stable tree 2.6.15.3:
+ - Fix extra dst release when ip_options_echo fails (CVE-2006-0454)
+
+ [ Sven Luther ]
+ * [powerpc] Removed -o root -g root option to mkvmlinuz support patch.
+ (Closes: #351412)
+
+ -- Sven Luther <luther at debian.org> Tue, 7 Feb 2006 19:23:14 +0000
+
+linux-2.6 (2.6.15-4) unstable; urgency=low
+
+ [ Jurij Smakov ]
+ * [sparc64] Add sparc64-clock-settime.patch to fix the incorrect
+ handling of the clock_settime syscall arguments, which resulted
+ in a hang when trying to set the date using 'date -s'. Patch
+ by David Miller is applied upstream. Thanks to Ludovic Courtes
+ and Frans Pop for reporting and testing.
+ Ref: http://marc.theaimsgroup.com/?t=113861017400002&r=1&w=2
+
+ [ Christian T. Steigies ]
+ * [m68k] update m68k patch and config to 2.6.15
+ * [m68k] SCSI drivers need to be built in until ramdisk generator tools
+ supports loading scsi modules
+ * [m68k] ISCSI and IDE-TAPE don't compile, disabled
+ * [m68k] set CC_OPTIMIZE_FOR_SIZE=n
+ * [m68k] added vmeints patch which fixes building for vme
+
+ [ maximilian attems ]
+ * Use initramfs-tools for ia64 - fixed klibc.
+ * Add stable tree 2.6.15.2:
+ - Fix double decrement of mqueue_mnt->mnt_count in sys_mq_open
+ - (CVE-2005-3356)
+ - Mask off GFP flags before swiotlb_alloc_coherent
+ - usb-audio: don't use empty packets at start of playback
+ - Make second arg to skb_reserved() signed.
+ - Input: HID - fix an oops in PID initialization code
+ - Fix oops in ufs_fill_super at mount time
+ - Kill blk_attempt_remerge()
+ - Fix i2o_scsi oops on abort
+ - Fix mkiss locking bug
+ - Fix timekeeping on sparc64 ultra-IIe machines
+ - Someone broke reiserfs v3 mount options and this fixes it
+ * Deactivate sparc64-jumping-time.patch, amd64-pppd-fix.patch incl in aboves.
+ * Add s390-klibc-buildfix.patch, regression due to header file changes.
+
+ [ Steve Langasek ]
+ * [alpha] set __attribute__((always_inline)) on __cmpxchg(), to avoid
+ wrong optimizations with -Os (Closes: #347556).
+
+ [ Martin Michlmayr ]
+ * Add input support for the ixp4xx beeper driver (Alessandro Zummo).
+ * [arm] Add NSLU2 specific portion of ixp4xx beeper driver (Alessandro Zummo).
+ * [arm/nslu2] Build PPP as a module.
+ * [arm/nslu2] Enable wireless.
+ * [arm/nslu2] Enable most USB modules.
+ * [arm/nslu2] Enable ALSA and USB sound modules.
+ * [arm/nslu2] Set 4 MB as the size of the initrd in the kernel cmd line.
+ * [arm/footbridge] Set CONFIG_BLK_DEV_RAM_SIZE to 8192.
+ * [armeb] Add support for big-endian ARM.
+ * [armeb/nslu2] Use the nslu2 config from arm.
+
+ [ Frederik Schüler ]
+ * [amd64] Add amd64-pppd-fix.patch to fix kernel panic when using pppd.
+ (Closes: #347711)
+ * Add 64bit-vidiocswin-ioctl-fix.patch to fix VIDIOCSWIN ioctl on 64bit
+ kernel 32bit userland setups. (Closes: #349338)
+
+ [ Sven Luther ]
+ * [powerpc] Adapted apus config file to be more modular and in sync with the
+ other powerpc configs. Scsi drivers are disabled as they don't build
+ cleanly though (need some esp stuff).
+ * [powerpc] Default to initramfs-tools as initramfs generator, as klibc
+ build is fixed now.
+
+ [ Bastian Blank ]
+ * [powerpc] Fix dependencies of image packages.
+
+ -- maximilian attems <maks at sternwelten.at> Wed, 1 Feb 2006 11:34:20 +0100
+
+linux-2.6 (2.6.15-3) unstable; urgency=low
+
+ [ Martin Michlmayr ]
+ * [arm] Update configs for 2.6.15; closes: #347998.
+ * [arm] Activate tmpfs.
+ * [arm] Allow modules to be unloaded.
+ * [arm] Enable CONFIG_INPUT_EVDEV since yaird needs this module in
+ order to generate initrds.
+ * [arm/footbridge] Activate IDEPCI so SL82C105 will really be
+ compiled in.
+ * [arm/footbridge] Activate the right network drivers (Tulip and
+ NE2K).
+ * [arm/footbridge] Enable more framebuffer drivers.
+ * debian/patches/arm-fix-dc21285.patch: Fix compilation of DC21285
+ flash driver.
+ * [arm/footbridge] Enable MTD and the DC21285 flash driver.
+ * [arm/footbridge] Enable RAID and LVM modules.
+ * [arm/footbridge] Enable USB modules.
+ * [arm/nslu2] Add an image for Network Storage Link for USB 2.0 Disk
+ Drives.
+ * debian/patches/arm-memory-h-page-shift.patch: Fix error "PAGE_SHIFT
+ undeclared" (Rod Whitby).
+ * debian/patches/mtdpart-redboot-fis-byteswap.patch: recognise a foreign
+ endian RedBoot partition table (John Bowler).
+ * debian/patches/maclist.patch: Add support for the maclist interface
+ (John Bowler).
+ * debian/patches/arm-nslu2-maclist.patch: Add NSLU2 maclist support
+ (John Bowler).
+ * [arm/nslu2] Activate maclist.
+
+ [ maximilian attems ]
+ * Add stable tree 2.6.15.1:
+ - arch/sparc64/Kconfig: fix HUGETLB_PAGE_SIZE_64K dependencies
+ - moxa serial: add proper capability check
+ - fix /sys/class/net/<if>/wireless without dev->get_wireless_stats
+ - Don't match tcp/udp source/destination port for IP fragments
+ - Fix sys_fstat64() entry in 64-bit syscall table.
+ - UFS: inode->i_sem is not released in error path
+ - netlink oops fix due to incorrect error code
+ - Fix onboard video on SPARC Blade 100 for 2.6.{13,14,15}
+ - Fix DoS in netlink_rcv_skb() (CVE-2006-0035)
+ - fix workqueue oops during cpu offline
+ - Fix crash in ip_nat_pptp (CVE-2006-0036)
+ - Fix another crash in ip_nat_pptp (CVE-2006-0037)
+ - ppc32: Re-add embed_config.c to ml300/ep405
+ - Fix ptrace/strace
+ - vgacon: fix doublescan mode
+ - BRIDGE: Fix faulty check in br_stp_recalculate_bridge_id()
+ - skge: handle out of memory on ring changes
+ * Drop merged patch:
+ - sparc64-atyfb-xl-gr-final.patch
+
+ [ Simon Horman ]
+ * Fix booting on PReP machines
+ (Closes: #348040)
+ powerpc-relocate_code.patch
+
+ -- Simon Horman <horms at verge.net.au> Tue, 17 Jan 2006 18:01:17 +0900
+
+linux-2.6 (2.6.15-2) unstable; urgency=low
+
+ [ maximilian attems ]
+ * Default to initramfs-tools as initramfs generator for amd64, hppa, i386,
+ alpha and sparc. More archs will be added once klibc matures.
+ (Closes: #346141, #343147, #341524, #346305)
+ * Backport alsa patch for opl3 - Fix the unreleased resources.
+ (Closes: #346273)
+ * Readd buslogic-pci-id-table.patch.
+
+ [ dann frazier ]
+ * [ia64] Update config for 2.6.15.
+
+ [ Frederik Schüler ]
+ * Make CONFIG_IPW2100 a per-architecture option and deactivate it on all
+ architectures but i386. (Closes: #344515)
+
+ [ Sven Luther ]
+ * Removed spurious file from powerpc-apus patch. (Closes: #346159)
+
+ [ Norbert Tretkowski ]
+ * Backport the generic irq framework for alpha. (closes: #339080)
+
+ [ Bastian Blank ]
+ * Remove pre-sarge conflict with hotplug.
+ * Fix hppa diff to apply.
+ * Make the latest packages depend on the corect version of the real images.
+ (closes: #346366)
+
+ -- Bastian Blank <waldi at debian.org> Tue, 10 Jan 2006 16:54:21 +0100
+
+linux-2.6 (2.6.15-1) unstable; urgency=low
+
+ [ Sven Luther ]
+ * New upstream release.
+ * [powerpc] Now use ARCH=powerpc for 64bit powerpc flavours, 32bit still
+ stays with ARCH=ppc for now.
+ * [powerpc] Readded PReP Motorola PowerStack II Utah IDE interrupt
+ (Closes: #345424)
+ * [powerpc] Fixed apus patch.
+ * Added make-kpkg --arch option support to gencontrol.py.
+ * Added debian/bin/kconfig.ml to process config file snipplet, so we can
+ preserve the pre 2.6.15 ordering of config file snipplets. Upto 2.6.15
+ the kernel Kconfig magic apparently kept the later occuring config options,
+ but it seems that this is no more the case. Instead of catting the config
+ files together, not use the kconfig.ml script to read in the files from
+ more generic to more specific, and keep only the more specific.
+
+ [ Bastian Blank ]
+ * [s390] Update configs.
+
+ [ Kyle McMartin ]
+ * [hppa] Snag latest hppa.diff from cvs.parisc-linux.org.
+ * [hppa] Update configs for 2.6.15.
+ * [hppa] Change parisc kernel names to something less ambiguous.
+
+ [ dann frazier ]
+ * [ia64] Update ia64 configs
+
+ [ maximilian attems ]
+ * Drop modular-ide.patch, nacked by ide upstream. Prevents udev to load
+ ide-generic and those successfull boots with initramfs-tools.
+ * Disable CONFIG_USB_BANDWIDTH, causes major trouble for alsa usb cards.
+
+ [ Norbert Tretkowski ]
+ * [alpha] Removed conflict with initramfs-tools, thanks vorlon for finding
+ the klibc bug!
+
+ [ Jonas Smedegaard ]
+ * Adjust short description of transitional package kernel-image-2.6-
+ 486 to mention 2.6 (not 2.6.12).
+ * Clean duplicate Kconfig options.
+
+ [ Frederik Schüler ]
+ * Add updated version of drivers-scsi-megaraid_splitup.patch.
+ * Deactivate CONFIG_IDE_TASK_IOCTL on alpha and ia64 and make it a global
+ option.
+ * Make CONFIG_VIDEO_SAA7134 a global option.
+ * New option CONFIG_CC_OPTIMIZE_FOR_SIZE set per-arch.
+ * Rename i386 368 flavour to 486.
+ * Add myself to uploaders.
+ * Readdition of qla2xxx drivers, as firmware license has been fixed.
+ * Make CONFIG_PACKET, PACKET_MM and UNIX builtin on all architectures:
+ statically linked has better performance then modules due to TLB issue.
+ * clean up debian-patches dir: remove all obsolete patches:
+ - alpha-compile-fix.patch: obsolete
+ - amd64-int3-fix.patch: fixed since 2.6.12
+ - net-ipconntrack-nat-fix.patch: merged upstream after 2.6.14 release
+ - net-nf_queue-oops.patch: merged upstream after 2.6.14 release
+ - qla2xxx-removed.patch: obsolete
+ * Drop M386 support remains from the i386 386 flavour: built with M486
+ from now on.
+
+ [ Martin Michlmayr ]
+ * [arm] Don't define "compiler" since GCC 4.x is the default now anyway.
+ * [arm] Add descriptions for "class" and "longclass".
+ * [arm] Compile CONFIG_BLK_DEV_SL82C105 support into the kernel on
+ Footbridge.
+ * [arm] Compile ext3 support into the kernel on Footbridge.
+ * [arm] Turn on CONFIG_SERIAL_8250 support on Footbridge.
+
+ [ Jurij Smakov ]
+ * [sparc] Correct the patch for the atyfb framebuffer driver
+ (sparc64-atyfb-xl-gr.patch) to finally fix the console and X
+ image defects on Blade 100/150. The new patch is named
+ sparc64-atyfb-xl-gr-final.patch to avoid the confusion.
+ Thanks to Luis F. Ortiz for fixing the patch and Luigi Gangitano
+ for testing it out.
+ * Drop tty-locking-fixes9.patch, which was preventing the oops during
+ shutdown on some sparc machines with serial console. Proper fix has
+ been incorporated upstream.
+
+ [ Simon Horman ]
+ * Enable MKISS globally (closes: #340215)
+ * Add recommends libc6-i686 to 686 and k7 image packages
+ (closes: #278729)
+ * Enable OBSOLETE_OSS_USB_DRIVER and USB_AUDIO
+ as alsa snd-usb-audio still isn't quite there.
+ I expect this to be re-disabled at some stage,
+ possibly soon if it proves to be a source of bugs.
+ (closes: #340388)
+
+ -- Sven Luther <luther at debian.org> Tue, 3 Jan 2006 06:48:07 +0000
+
+linux-2.6 (2.6.14-7) unstable; urgency=low
+
+ [ maximilian attems ]
+ * Add stable tree 2.6.14.5 fixes:
+ - setting ACLs on readonly mounted NFS filesystems (CVE-2005-3623)
+ - Fix bridge-nf ipv6 length check
+ - Perform SA switchover immediately.
+ - Input: fix an OOPS in HID driver
+ - Fix hardware checksum modification
+ - kernel/params.c: fix sysfs access with CONFIG_MODULES=n
+ - Fix RTNLGRP definitions in rtnetlink.h
+ - Fix CTA_PROTO_NUM attribute size in ctnetlink
+ - Fix unbalanced read_unlock_bh in ctnetlink
+ - Fix NAT init order
+ - Fix incorrect dependency for IP6_NF_TARGET_NFQUEUE
+ - dpt_i2o fix for deadlock condition
+ - SCSI: fix transfer direction in sd (kernel panic when ejecting iPod)
+ - SCSI: fix transfer direction in scsi_lib and st
+ - Fix hardware rx csum errors
+ - Fix route lifetime.
+ - apci: fix NULL deref in video/lcd/brightness
+ * Disable CONFIG_USB_BANDWIDTH, causes major trouble on alsa usb cards.
+ (Closes: #344939)
+
+ -- maximilian attems <maks at sternwelten.at> Tue, 27 Dec 2005 20:50:28 +0100
+
+linux-2.6 (2.6.14-6) unstable; urgency=low
+
+ [ Kyle McMartin ]
+ * Change parisc kernel names to something less ambiguous.
+
+ [ maximilian attems ]
+ * Drop modular-ide.patch, nacked by ide upstream. Prevents udev to load
+ ide-generic and those successfull boots with initramfs-tools.
+ * Add stable tree 2.6.14.4 with the following fixes:
+ - drivers/scsi/dpt_i2o.c: fix a user-after-free
+ - drivers/message/i2o/pci.c: fix a use-after-free
+ - drivers/infiniband/core/mad.c: fix a use-after-free
+ - DVB: BUDGET CI card depends on STV0297 demodulator
+ - setkeys needs root
+ - Fix listxattr() for generic security attributes
+ - AGPGART: Fix serverworks TLB flush.
+ - Fix crash when ptrace poking hugepage areas
+ - I8K: fix /proc reporting of blank service tags
+ - i82365: release all resources if no devices are found
+ - bonding: fix feature consolidation
+ - libata: locking rewrite (== fix)
+ - cciss: bug fix for BIG_PASS_THRU
+ - ALSA: nm256: reset workaround for Latitude CSx
+ - cciss: bug fix for hpacucli
+ - V4L/DVB: Fix analog NTSC for Thomson DTT 761X hybrid tuner
+ - BRIDGE: recompute features when adding a new device
+ - 32bit integer overflow in invalidate_inode_pages2()
+ - USB: Adapt microtek driver to new scsi features
+ - ide-floppy: software eject not working with LS-120 drive
+ - Add try_to_freeze to kauditd
+ - V4L/DVB (3135) Fix tuner init for Pinnacle PCTV Stereo
+ - NETLINK: Fix processing of fib_lookup netlink messages
+ - ACPI: fix HP nx8220 boot hang regression
+
+ [ Norbert Tretkowski ]
+ * [alpha] Removed conflict with initramfs-tools, thanks vorlon for finding
+ the klibc bug!
+
+ [ Frederik Schüler ]
+ * Add updated drivers-scsi-megaraid_splitup.patch. (Closes: #317258)
+ * Add ppc64-thermal-overtemp.patch to fix a thermal control bug in G5
+ machines. (Closes: #343980)
+ * Unpatch the following patches which are included in 2.6.14.4:
+ - setkeys-needs-root-1.patch
+ - setkeys-needs-root-2.patch
+ - mm-invalidate_inode_pages2-overflow.patch
+ - net-bonding-consolidation-fix.patch
+
+ -- Frederik Schüler <fs at debian.org> Tue, 20 Dec 2005 18:50:41 +0000
+
+linux-2.6 (2.6.14-5) unstable; urgency=low
+
+ [ dann frazier ]
+ * ia64-new-assembler-fix.patch
+ Fix ia64 builds with newer assembler (Closes: #341257)
+
+ [ Sven Luther ]
+ * [powerpc] incremented ramdisk size to 24576 from 8192, needed by the
+ graphical installer, maybe we can bring this to 16384 later.
+
+ [ Simon Horman ]
+ * Add recommends libc6-i686 to 686 and k7 image packages
+ (closes: #278729)
+ * Enable OBSOLETE_OSS_USB_DRIVER and USB_AUDIO
+ as alsa snd-usb-audio still isn't quite there.
+ I expect this to be re-disabled at some stage,
+ possibly soon if it proves to be a source of bugs.
+ (closes: #340388)
+
+ [ dann frazier ]
+ * buslogic-pci-id-table.patch
+ add a pci device id table to fix initramfs-tools discovery.
+ (closes #342057)
+ * fix feature consolidation in bonding driver. (closes #340068)
+
+ -- dann frazier <dannf at debian.org> Thu, 8 Dec 2005 10:59:31 -0700
+
+linux-2.6 (2.6.14-4) unstable; urgency=low
+
+ [ dann frazier ]
+ * setkeys-needs-root-1.patch, setkeys-needs-root-2.patch:
+ [SECURITY] Require root privilege to write the current
+ function key string entry of other user's terminals.
+ See CVE-2005-3257 (Closes: #334113)
+
+ [ Simon Horman ]
+ * Enable MKISS globally (closes: #340215)
+ * mm-invalidate_inode_pages2-overflow.patch
+ [SECURITY] 32bit integer overflow in invalidate_inode_pages2() (local DoS)
+ * ctnetlink-check-if-protoinfo-is-present.patch
+ [SECURITY] ctnetlink: check if protoinfo is present (local DoS)
+ * ctnetlink-fix-oops-when-no-icmp-id-info-in-message.patch
+ [SECURITY] ctnetlink: Fix oops when no ICMP ID info in message (local DoS)
+
+ [ Sven Luther ]
+ * Re-added powerpc/apus patch, now that Roman Zippel merged it in.
+ * Let's create asm-(ppc|ppc64) -> asm-powerpc symlink farm. (Closes: #340571)
+
+ [ maximilian attems ]
+ * Add 2.6.14.3 patch - features changelog:
+ - isdn/hardware/eicon/os_4bri.c: correct the xdiLoadFile() signature
+ - x86_64/i386: Compute correct MTRR mask on early Noconas
+ - PPTP helper: Fix endianness bug in GRE key / CallID NAT
+ - nf_queue: Fix Ooops when no queue handler registered
+ - ctnetlink: check if protoinfo is present
+ - ip_conntrack: fix ftp/irc/tftp helpers on ports >= 32768
+ - VFS: Fix memory leak with file leases
+ - hwmon: Fix lm78 VID conversion
+ - hwmon: Fix missing it87 fan div init
+ - ppc64 memory model depends on NUMA
+ - Generic HDLC WAN drivers - disable netif_carrier_off()
+ - ctnetlink: Fix oops when no ICMP ID info in message
+ - Don't auto-reap traced children
+ - packet writing oops fix
+ - PPTP helper: fix PNS-PAC expectation call id
+ - NAT: Fix module refcount dropping too far
+ - Fix soft lockup with ALSA rtc-timer
+ - Fix calculation of AH length during filling ancillary data.
+ - ip_conntrack TCP: Accept SYN+PUSH like SYN
+ - refcount leak of proto when ctnetlink dumping tuple
+ - Fix memory management error during setting up new advapi sockopts.
+ - Fix sending extension headers before and including routing header.
+ - hwmon: Fix missing boundary check when setting W83627THF in0 limits
+ * Remove ctnetlink-check-if-protoinfo-is-present.patch,
+ net-nf_queue-oops.patch - already included in 2.6.14.3.
+
+ [ Frederik Schüler ]
+ * Make CONFIG_PACKET, PACKET_MM and UNIX builtin on all architectures:
+ statically linked has better performance then modules due to TLB issue.
+ * Add myself to uploaders.
+
+ -- Frederik Schüler <fs at debian.org> Sat, 26 Nov 2005 13:18:41 +0100
+
+linux-2.6 (2.6.14-3) unstable; urgency=low
+
+ [ Norbert Tretkowski ]
+ * [alpha] Switch to gcc 4.0.
+ * [alpha] Conflict with initramfs-tools, klibc is broken on alpha.
+ * [alpha] Enabled CONFIG_KOBJECT_UEVENT in arch/alphaconfig to fix trouble
+ with latest udev, thanks to Uwe Schindler for reporting. (closes: #338911)
+ * Bumped ABI revision:
+ + ABI changes on sparc and alpha because of compiler switch.
+ + 2.6.14.1 changes ABI of procfs.
+
+ [ Sven Luther ]
+ * Set default TCP congestion algorithm to NewReno + BIC (Closes: #337089)
+
+ [ maximilian attems ]
+ * Reenable CONFIG_SOFTWARE_SUSPEND on i386 and ppc, resume=/dev/<other device>
+ must be set by boot loader. (Closes: #267600)
+ * Set CONFIG_USB_SUSPEND on i386. Usefull for suspend to ram and apm suspend.
+ * Add 2.6.14.1 patch:
+ - Al Viro: CVE-2005-2709 sysctl unregistration oops
+ * Add 2.6.14.2 patch:
+ - airo.c/airo_cs.c: correct prototypes
+ - fix XFS_QUOTA for modular XFS (closes: #337072)
+ - USB: always export interface information for modalias
+ - NET: Fix zero-size datagram reception
+ - fix alpha breakage
+ - Oops on suspend after on-the-fly switch to anticipatory i/o scheduler
+ - ipvs: fix connection leak if expire_nodest_conn=1
+ - Fix ptrace self-attach rule
+ - fix signal->live leak in copy_process()
+ - fix de_thread() vs send_group_sigqueue() race
+ - prism54 : Fix frame length
+ - tcp: BIC max increment too large
+ * Remove alpha compile fix as contained in 2.6.14.2
+ * Readd CONFIG_XFS_QUOTA=y.
+ * Disable ACPI cutoff year on i386, was set to 2001.
+ No need for acpi=force on boot.
+
+ [ Jurij Smakov ]
+ * Fix the install-image script to correctly include all the necessary
+ stuff in scripts. (Closes: #336424)
+ * Enable CONFIG_SND_ALI5451 on sparc.
+ * Switch sparc to gcc-4.0. Thanks to Norbert for making sure it successfully
+ builds a working kernel now.
+ * Apply patch to fix ATI framebuffer output corruption on SunBlade 100
+ (sparc64-atyfb-xl-gr.patch). Thanks to Luigi Gangitano. (Closes: #321200)
+ * Disable CONFIG_PARPORT_PC_FIFO on sparc, since it causes a hang whenever
+ something is sent to the parallel port device. Thanks to Attilla
+ (boera at rdslink.ro) for pointing that out.
+
+ [ Simon Horman ]
+ * [386, AMD64] Set CONFIG_FRAMEBUFFER_CONSOLE=y instead of m.
+ As vesadb now built into the kernel, after finally dropping the
+ debian-specific patch to make it modular, make fbcons builtin too, else
+ all sorts of weird stuff happens which is hard for the inird builders to
+ automatically compenste for. (Closes: #336450)
+ * Redisable CONFIG_SOFTWARE_SUSPEND on ppc/miboot as it required
+ CONFIG_PM to compile.
+ * [NETFILTER] nf_queue: Fix Ooops when no queue handler registered
+ This is a regression introduced in 2.6.14.
+ net-nf_queue-oops.patch. (Closes: #337713)
+ * Make manuals with defconfig, as is required for kernel-package 10.008
+
+ [ dann frazier ]
+ * net-ipconntrack-nat-fix.patch - fix compilation of
+ ip_conntrack_helper_pptp.c when NAT is disabled. (Closes: #336431)
+
+ [ Christian T. Steigies ]
+ * update m68k.diff to 2.6.14
+ * add m68k-*vme* patches
+ * disable macsonic driver until the dma patch is fixed
+ * disable IEEE80211 drivers for all of m68k
+
+ [ Frederik Schüler ]
+ * activate CONFIG_SECURITY_NETWORK to fix SElinux operation.
+ (Closes: #338543)
+
+ -- Norbert Tretkowski <nobse at debian.org> Mon, 14 Nov 2005 10:23:05 +0100
+
+linux-2.6 (2.6.14-2) unstable; urgency=low
+
+ [ Simon Horman ]
+ * [SECURITY] Avoid 'names_cache' memory leak with CONFIG_AUDITSYSCALL
+ This fix, included as part of the 2.6.13.4 patch in
+ 2.6.13+2.6.14-rc4-0experimental.1 is CVE-2005-3181
+ * Fix genearation of .extraversion, again (closes: #333842)
+ * Add missing kernel-arch and kernel-header-dirs to defines
+ so headers get included. (closes: #336521)
+ N.B: I only filled in arches where other's hadn't done so alread.
+ Please fix if its wrong.
+ * Allow powerpc64 to compile with AUDIT enabled but
+ AUDITSYSCALL disabled. powerpc64-audit_sysctl-build.patch
+
+ [ dann frazier ]
+ * Update hppa.diff to 2.6.14-pa0
+
+ [ Norbert Tretkowski ]
+ * [alpha] New patch to include compiler.h in barrier.h, barrier() is used in
+ non-SMP case.
+ * [alpha] Added kernel-header-dirs and kernel-arch to debian/arch/alpha/defines
+ to include asm-alpha in linux-headers package.
+ * Added myself to Uploaders.
+
+ [ Frederik Schüler ]
+ * [amd64] use DISCONTIGMEM instead of SPARSEMEM on amd64-k8-smp flavour to
+ fix bootup kernel panic.
+ * [amd64] include asm-x86_64 in linux-headers package.
+ * Deactivate AUDITSYSCALL globally, it slows down the kernel and is not
+ needed for selinux at all.
+
+ -- Simon Horman <horms at debian.org> Tue, 1 Nov 2005 15:27:40 +0900
+
+linux-2.6 (2.6.14-1) unstable; urgency=low
+
+ [ Sven Luther ]
+ * New upstream release.
+
+ [ Norbert Tretkowski ]
+ * [alpha] Update arch/alpha/config* for 2.6.14.
+
+ [ Simon Horman ]
+ * Fix misformatting of long description of
+ linux-patch-debian-linux-patch-debian-X.Y.Z.
+ templates/control.main.in
+ (closes: #335088)
+ * Make sure version is seeded in apply and unapply scripts.
+ Actually changed in some earlier, post 2.6.12, release,
+ but the changelog seems to be missing.
+ (closes: #324583)
+
+ [ dann frazier ]
+ * [ia64] Disable the CONFIG_IA64_SGI_SN_XP module. This forces
+ CONFIG_GENERIC_ALLOCATOR and CONFIG_IA64_UNCACHED_ALLOCATOR to y, which
+ appears to break on zx1 systems.
+
+ -- Simon Horman <horms at debian.org> Fri, 28 Oct 2005 16:26:03 +0900
+
+linux-2.6 (2.6.13+2.6.14-rc5-0experimental.1) experimental; urgency=low
+
+ [ Sven Luther ]
+ * Upgraded to 2.6.14-rc5.
+
+ [ Jonas Smedegaard ]
+ * Quote variables in debian/rules.real and postinstall (making it
+ safer to run with weird characters in path of build environment).
+
+ [ Bastian Blank ]
+ * Add some missing files from scripts to headers packages.
+ * Add new patch powerpc-build-links.patch: Emit relative symlinks in
+ arch/ppc{,64}/include.
+ * Include arch/*/include into headers package.
+
+ -- Sven Luther <luther at debian.org> Tue, 25 Oct 2005 03:56:11 +0000
+
+linux-2.6 (2.6.13+2.6.14-rc4-0experimental.1) experimental; urgency=low
+
+ [ Sven Luther ]
+ * Upgraded to 2.6.14-rc4.
+
+ [ Simon Horman ]
+ * Fix genearation of .extraversion (closes: #333842)
+
+ [ dann frazier ]
+ * Enhance the linux-source description to explain the types of patches
+ Debian adds to it. (closes: #258043)
+ * Correct linux-patch-debian description. It replaces the
+ kernel-patch-debian packages, not the kernel-source packages.
+
+ [ Jonas Smedegaard ]
+ * Fix building from within a very long dir (all patches was applied at
+ once - exhausting shell commandline, now applied one by one).
+ * Add Simon Horman, Sven Luther and myself as Uploaders.
+
+ [ Bastian Blank ]
+ * Use list of revisions in patch scripts.
+ * Use correct names for tarball and scripts.
+
+ [ Jurij Smakov ]
+ * [i386] Set the CONFIG_HPET_EMULATE_RTC option to make the clock
+ work properly on certain Dell machines. This required setting the
+ CONFIG_RTC option to 'y' instead of 'm'. (closes: #309909)
+ [i386] Enable VIDEO_CX88 and VIDEO_CX88_DVB (both set to 'm') by
+ popular demand. (closes: #330916)
+
+ [ Norbert Tretkowski ]
+ * [alpha] Update arch/alpha/config for 2.6.13.
+
+ [ Kyle McMartin ]
+ * [hppa] Oops. Fix linux-headers not including asm-parisc by adding
+ headers_dirs = parisc to Makefile.inc.
+
+ [ maximilian attems ]
+ * Set CONFIG_FB_VESA=y for i386 and amd64 configs. (closes: #333003)
+
+ [ Sven Luther ]
+ * [powerpc] Fixed apus build, now use mkvmlinuz too to generate the vmlinuz
+ kernel.
+ * Fixed control.image.in to depend on :
+ initramfs-tools | yaird | linux-ramdisk-tool
+ where linux-ramdisk-tools is the virtual package provided by all
+ initrd/initramfs generating tools.
+
+ [ Frederik Schüler ]
+ * deactivate FB_RIVA on all architectures.
+ * deactivate BLK_DEV_IDESCSI on all architectures.
+ * Added patch-2.6.13.4:
+ - [SECURITY] key: plug request_key_auth memleak
+ See CAN-2005-3119
+ - [SECURITY] Fix drm 'debug' sysfs permissions
+ See CAN-2005-3179
+ - [SECURITY] Avoid 'names_cache' memory leak with CONFIG_AUDITSYSCALL
+ - [SPARC64] Fix userland FPU state corruption.
+ - BIC coding bug in Linux 2.6.13
+ - [SECURITY] orinoco: Information leakage due to incorrect padding
+ See CAN-2005-3180
+ - ieee1394/sbp2: fixes for hot-unplug and module unloading
+
+ [ Christian T. Steigies ]
+ * disable CONFIG_EXT2_FS_XIP for m68k like on all(?) other arches
+ * deactivate OKTAGON_SCSI for amiga/m68k until it can be compiled again
+ * deactivate CONFIG_KEYBOARD_HIL_OLD, CONFIG_KEYBOARD_HIL, CONFIG_MOUSE_HIL,
+ CONFIG_HIL_MLC, and CONFIG_HP_SDC for hp/m68k
+ * update m68k.diff for 2.6.13
+ * split out patches that do not intefere with other arches to
+ patches-debian/m68k-*
+
+ -- Bastian Blank <waldi at debian.org> Fri, 21 Oct 2005 12:17:47 +0000
+
+linux-2.6 (2.6.13-1) experimental; urgency=low
+
+ * New upstream release "git booost":
+ - new arch xtensa
+ - kexec/kdump
+ - execute-in-place
+ - inotify (closes: #304387)
+ - time-sharing cfq I/O scheduler
+ - manual driver binding
+ - voluntary preemption
+ - user-space I/O initiation for InfiniBand
+ - new speedy DES (crypto) implementation
+ - uml "almost-skas" mode support
+ - 250 HZ default (closes: #320366)
+ - fixes all over (alsa, archs, ide, input, ntfs, scsi, swsusp, usb, ..)
+ - orinoco driver updates (closes: #291684)
+ - md, dm updates (closes: #317787)
+
+ [ Frederik Schüler ]
+ * [amd64] Added class and longclass descriptions for amd64 flavours.
+ * [amd64] add amd64-tlb-flush-sigsegv-fix.patch: disable tlb flush
+ filtering on smp systems to workaround processor errata.
+ * backport kernel-api-documentation-generation-fix.diff from git to fix
+ documentation build.
+ * Added patch-2.6.13.1:
+ - raw_sendmsg DoS (CAN-2005-2492)
+ - 32bit sendmsg() flaw (CAN-2005-2490)
+ - Reassembly trim not clearing CHECKSUM_HW
+ - Use SA_SHIRQ in sparc specific code.
+ - Fix boundary check in standard multi-block cipher processors
+ - 2.6.13 breaks libpcap (and tcpdump)
+ - x86: pci_assign_unassigned_resources() update
+ - Fix PCI ROM mapping
+ - aacraid: 2.6.13 aacraid bad BUG_ON fix
+ - Kconfig: saa7134-dvb must select tda1004x
+
+ [ Simon Horman ]
+ * Disable BSDv3 accounting on hppa and alpha, it was already
+ disabled on all other architectures. Also unify BSD accounting
+ config into top level config, rather than per flavour configs.
+ * [SECURITY] The seq_file memory leak fix included in 2.6.12-6
+ as part of upstream's 2.6.12.6 patchset is now CAN-2005-2800.
+
+ [ Jurij Smakov, Simon Horman ]
+ * Ensure that only one kernel-manual/linux-manual package can
+ be installed at a time to avoid file conflicts. (closes: #320042)
+
+ [ Bastian Blank ]
+ * Move audit, preempt and security settings to core config file.
+ * Fix powerpc configuration.
+ * Add debian version information to kernel version string.
+ * Drop coreutils | fileutils dependencies.
+ * Drop modular-vesafb patch. (closes: #222374, #289810)
+
+ [ Christian T. Steigies ]
+ * update m68k.diff for linux-2.6.13
+ * add m68k-42_dma.patch and m68k-sonic.patch that will be in upstream 2.6.14
+ (which makes sun3 build fail, needs fixing)
+
+ [ maximilian attems ]
+ * Drop drivers-add-scsi_changer.patch (merged)
+ * Drop drivers-ide-dma-blacklist-toshiba.patch (merged)
+ * Drop drivers-ide-__devinit.patch (merged)
+ * Added patch-2.6.13.2:
+ - USB: ftdi_sio: custom baud rate fix
+ - Fix up more strange byte writes to the PCI_ROM_ADDRESS config word
+ - Fix MPOL_F_VERIFY
+ - jfs: jfs_delete_inode must call clear_inode
+ - Fix DHCP + MASQUERADE problem
+ - Sun HME: enable and map PCI ROM properly
+ - Sun GEM ethernet: enable and map PCI ROM properly
+ - hpt366: write the full 4 bytes of ROM address, not just low 1 byte
+ - forcedeth: Initialize link settings in every nv_open()
+ - Lost sockfd_put() in routing_ioctl()
+ - lost fput in 32bit ioctl on x86-64
+ * Added patch-2.6.13.3:
+ - Fix fs/exec.c:788 (de_thread()) BUG_ON
+ - Don't over-clamp window in tcp_clamp_window()
+ - fix IPv6 per-socket multicast filtering in exact-match case
+ - yenta oops fix
+ - ipvs: ip_vs_ftp breaks connections using persistence
+ - uml - Fix x86_64 page leak
+ - skge: set mac address oops with bonding
+ - tcp: set default congestion control correctly for incoming connections
+
+ [ Sven Luther ]
+ * [powerpc] Added hotplug support to the mv643xx_eth driver :
+ powerpc-mv643xx-hotplug-support.patch
+ thanks go to Nicolas Det for providing the patch.
+ * [powerpc] Modified a couple of configuration options for the powerpc64
+ flavour, fixes and enhances Apple G5 support (Closes: #323724, #328324)
+ * [powerpc] Added powerpc-miboot flavour to use exclusively with oldworld
+ powermac miboot floppies for debian-installer.
+ * [powerpc] Checked upgraded version of the apus patches, separated them in
+ a part which is safe to apply, and one which needs checking, and is thus
+ not applied yet.
+
+ [ Kyle McMartin ]
+ * [hppa] Update hppa.diff to 2.6.13-pa4.
+ * [hppa] Add space register fix to pacache.S to hppa.diff.
+
+ [ dann frazier ]
+ * Add a note to README.Debian that explains where users can find the .config
+ files used to generate the linux-image packages. Closes: #316809
+ * [ia64] Workaround #325070 until upstream works out an acceptable solution.
+ This bug breaks module loading on non-SMP ia64 kernels. The workaround
+ is to temporarily use an SMP config for the non-SMP kernels. (Note that
+ John Wright is running benchmarks to determine the overhead of running
+ an SMP kernel on UP systems to help decide if this should be a
+ permanent change).
+ * [ia64] Update arch/ia64/config for 2.6.13
+
+ -- Simon Horman <horms at debian.org> Thu, 6 Oct 2005 15:45:21 +0900
+
+linux-2.6 (2.6.12-6) unstable; urgency=high
+
+ [ Andres Salomon, Bastian Blank ]
+ * Change ATM and Classical-IP-over-ATM to be modular, instead of being
+ statically included. (closes: #323143)
+
+ [ Sven Luther ]
+ * [powerpc] powerpc-pmac-sound-check.patch: Added pmac-sound sanity check.
+ * [powerpc] powerpc-apus.patch:
+ Added preliminary apus patch to package, not applied to kernel tree yet.
+
+ [ Simon Horman ]
+ * Unset CC_OPTIMIZE_FOR_SIZE in i386 config,
+ it breaks iproute's (and other netlink users) ability
+ to set routes. (closes: #322723)
+ * Added 2.6.12.6
+ - [SECURITY: CAN-2005-2555] Restrict socket policy loading to
+ CAP_NET_ADMIN.
+ - [SECURITY] Fix DST leak in icmp_push_reply(). Possible remote
+ DoS?
+ - [SECURITY] NPTL signal delivery deadlock fix; possible local
+ DoS.
+ - fix gl_skb/skb type error in genelink driver in usbnet
+ - [SECURITY] fix a memory leak in devices seq_file implementation;
+ local DoS.
+ - [SECURITY] Fix SKB leak in ip6_input_finish(); local DoS.
+
+ [ Andres Salomon ]
+ * [hppa] enable discontiguous memory support for 32bit hppa images, so
+ they build.
+
+ -- Andres Salomon <dilinger at debian.org> Tue, 06 Sep 2005 10:14:35 -0400
+
+linux-2.6 (2.6.12-5) unstable; urgency=low
+
+ * Change ARM to use GCC 3.3 to avoid FTBFS errors with GCC 4
+ (dann frazier)
+
+ * Remove spurious double quote character from ia64 package descriptions.
+ (dann frazier)
+
+ * Add transitional meta packages (kernel-image-2.6-*) for ia64.
+ (dann frazier)
+
+ * Change fuzz factor to 1, stricter patch appliance. (Maximilian Attems)
+
+ * Enabled CONFIG_THERM_PM72 on powerpc64 flavour. (Sven Luther)
+
+ -- Bastian Blank <waldi at debian.org> Tue, 16 Aug 2005 21:43:31 +0200
+
+linux-2.6 (2.6.12-4) unstable; urgency=low
+
+ * Supply correct subarch values for the powerpc images.
+
+ -- Bastian Blank <waldi at debian.org> Mon, 15 Aug 2005 21:06:18 +0200
+
+linux-2.6 (2.6.12-3) unstable; urgency=low
+
+ * Added reference to old kernel-* package names to make
+ transition a little more obvious to end users.
+ A Dan Jacobson special. (Simon Horman) Closes: #321167
+
+ * By the time this makes it into the archive, it will
+ be handling kernel-image-2.6-* packages. (Simon Horman)
+ Closes: #321867
+
+ * Link palinfo statically on ia64. (dann frazier) (Closes: #321885)
+
+ * [hppa] :
+ - Add hppa arch specific patch.
+ - Build-Depend on binutils-hppa64 and gcc-4.0-hppa64.
+ (Kyle McMartin)
+
+ * Fix permissions in source tarball. (Bastian Blank) (Closes: #322409)
+
+ * Enable the CONFIG_IP_ADVANCED_ROUTER and related options on
+ sparc64 to sync with other architectures. (Jurij Smakov)
+ Closes: #321236
+
+ * Include all executables as well as *.sh and *.pl files found in
+ scripts directory in the headers package. (Bastian Blank)
+ Closes: #322612, #322680, #322765
+
+ * Include m68k headers into the arch-common headers package on
+ powerpc and make sure that all the directories are linked to
+ properly from the flavour-specific headers packages. (Jurij Smakov)
+ Closes: #322610
+
+ * [powerpc] Enabled the powerpc64 flavour, now that we have a real biarch
+ toolchain in sid. Many thanks go to GOTO Masanori and Matthias Klose as
+ well as any other who worked on the biarch toolchain to make this happen.
+
+ * Added 2.6.12.5 (Simon Horman)
+ - Fix BUG() is triggered by a call to set_mempolicy() with a negativ
+ first argument.
+ - [amd64] Fix a SRAT handling on systems with dual cores.
+ - [amd64] SMP timing problem
+ - [security] Zlib fixes See CAN-2005-2458, CAN-2005-2459
+ http://sources.redhat.com/ml/bug-gnu-utils/1999-06/msg00183.html
+ http://bugs.gentoo.org/show_bug.cgi
+ - Add zlib deflateBound()
+ - [security] Fix error during session join. See CAN-2005-2098
+ - [security] Fix keyring destructor. See CAN-2005-2099
+ - Module per-cpu alignment cannot always be met
+ http://www.ussg.iu.edu/hypermail/linux/kernel/0409.0/0768.html
+ Closes: #323039
+
+ -- Bastian Blank <waldi at debian.org> Mon, 15 Aug 2005 16:42:05 +0200
+
+linux-2.6 (2.6.12-2) unstable; urgency=low
+
+ * The Kernel Team offers its condolences to the family of Jens Schmalzing
+ (jensen at debian), who died Saturday, July 30, 2005 in a tragic accident in
+ Munich. Jens was a member of the Kernel Team, and was instrumental in
+ taking the powerpc kernel package to 2.6, as well as maintaining MOL
+ and its kernel modules.
+
+ * Add @longclass@ variable to control file autogeneration. (Andres Salomon)
+
+ * Bump build-depends on kernel-package to a fixed version (>= 9.005).
+ (Jurij Smakov, Sven Luther) (closes: #319657, #320422, #321625)
+
+ * Change default ramdisk size for sparc to 16,384K to accomodate a fatter
+ d-i initrd for netboot installs.
+ (Joshua Kwan)
+
+ * Don't build-depend on console-tools on s390. (Bastian Blank)
+
+ * Add ARM support. (Vincent Sanders)
+
+ * Add ia64 descriptions. (dann frazier)
+
+ * Strip down the scripts dir in the headers packages. (Bastian Blank)
+
+ * Add m68k support. (Christian T. Steigies)
+
+ * Added 2.6.12.4 (Frederik Schüler)
+ - Fix powernow oops on dual-core athlon
+ - Fix early vlan adding leads to not functional device
+ - sys_get_thread_area does not clear the returned argument
+ - bio_clone fix
+ - Fix possible overflow of sock->sk_policy (CAN-2005-2456)
+ (closes: #321401)
+ - Wait until all references to ip_conntrack_untracked are dropped on
+ unload
+ - Fix potential memory corruption in NAT code (aka memory NAT)
+ - Fix deadlock in ip6_queue
+ - Fix signedness issues in net/core/filter.c
+ - x86_64 memleak from malicious 32bit elf program
+ - rocket.c: Fix ldisc ref count handling
+ - kbuild: build TAGS problem with O=
+
+ * Enable CONFIG_6PACK=m for all archs (Andres Salomon)
+ (closes: #319646)
+
+ * Overhaul the generation of the control file. Now it is handled
+ by debian/bin/gencontrol.py. The debian/control target in rules
+ also fails now, since we don't want the control file generated
+ during build. Arch-specific Depends and suggests are now generated
+ correctly. (Bastian Blank) (Closes: #319896)
+
+ * [powerpc] Fixed typo which made asm-ppc and asm-ppc64 not being included
+ in the header package. (Sven Luther) (Closes: #320817)
+
+ * Added list of flavours built to common header package. (Sven Luther)
+
+ -- Bastian Blank <waldi at debian.org> Tue, 09 Aug 2005 11:12:40 +0200
+
+linux-2.6 (2.6.12-1) unstable; urgency=low
+
+ * New upstream release:
+ - "git rocks"
+ - address space randomization
+ - conversion of ide driver code to the device model
+ - restored Philips webcam driver
+ - new Broadcom bcm5706 gigabit driver
+ - new resource limits for the audio community
+ - Multipath device mapper
+ - Intel HD Audio alsa driver
+ - fixes + arch updates..
+ - readdition of tg3 driver, as firmware license has been fixed
+
+ * Dropped the following patches:
+ - patch-2.6.11.*.patch (merged)
+ - powerpc-ppc64-ibmvscsi.patch (Christoph didn't like it, and it failed
+ to build anyways) (Sven Luther)
+ - doc-post_halloween.patch (unless someone can come up w/ a valid
+ reason for carrying around rapidly bitrotting documentation...)
+ (Andres Salomon)
+ - sparc32-hypersparc-srmmu.patch (dropped until sparc32 is working
+ again, and we can figure out whether it's necessary)
+ - fix-alpha-ext3-oops.patch (no longer needed, fixed by compiler)
+ - x86-i486_emu.patch (buggy and insecure 80486 instruction emulation
+ for 80386; we're no longer supporting this) (closes: #250468)
+ - amd64-outs.patch (according to
+ http://www.ussg.iu.edu/hypermail/linux/kernel/0502.3/1095.html, this
+ is unnecessary for us) (Andres Salomon)
+ - sparc64-rtc-mostek.patch (merged)
+ - sparc64-compat-nanoseconds.patch (merged)
+ - sparc64-sunsu-init-2.6.11.patch (merged)
+ - sunsab-uart-update-timeout.patch (merged)
+ - alpha-read-trylock.patch (different version got merged)
+ - powerpc-prep-motorola-irq-fix.patch (merged)
+ - drivers-media-video-saa7134-update.patch (merged)
+ - drivers-media-video-saa7134-update-2.patch (merged)
+ - drivers-media-video-pll-lib.patch (merged)
+ - drivers-media-video-pll-lib-2.patch (merged)
+ - drivers-media-video-tuner-update-1.patch (merged)
+ - drivers-media-video-tuner-update-2.patch (merged)
+ - drivers-media-video-v4l-mpeg-support.patch (merged)
+ - drivers-media-video-mt352-update.patch (merged)
+ - arch-ppc64-hugepage-aio-panic.patch (merged)
+ - drivers-input-serio-nmouse.patch (merged)
+ - sparc64-sb1500-clock-2.6.patch (merged)
+ - docbook-allow-preprocessor-directives-... (merged)
+ - docbook-fix-function-parameter-descriptin-in-fbmem.patch (merged)
+ - docbook-move-kernel-doc-comment-next-to-function.patch (merged)
+ - powerpc-therm-adt746x-new-i2c-fix.patch (merged)
+ - powerpc-mv643xx-enet.patch (merged)
+ - powerpc-mv643xx-eth-pegasos.patch (merged)
+ - powerpc-pmac-agp-sleep.patch (merged)
+ - drivers-input-serio-8042-resume.patch (merged)
+
+ * Premiere of the common-source kernel package
+ (Jurij Smakov, Andres Salomon)
+ - build all architectures out of kernel source package
+ - rename source and binary packages
+ - create a common config for different architectures, and management
+ tools to allow for easier modification of config options
+ - drop default configs, autogenerate them instead; requires
+ kernel-package >= 9.002.
+
+ * Add 2.6.12.1 (Maximilian Attems)
+ - Clean up subthread exec (CAN-2005-1913)
+ - ia64 ptrace + sigrestore_context (CAN-2005-1761)
+
+ * Add 2.6.12.2 (Frederik Schüler)
+ - Fix two socket hashing bugs.
+ - ACPI: Make sure we call acpi_register_gsi() even for default PCI
+ interrupt assignment
+ - Add "memory" clobbers to the x86 inline asm of strncmp and friends
+ - e1000: fix spinlock bug
+ - fix remap_pte_range BUG
+ - Fix typo in drivers/pci/pci-driver.c
+
+ * Add 2.6.12.3 (Joshua Kwan)
+ - Fix semaphore handling in __unregister_chrdev
+ - Fix TT mode in UML.
+ - Check for a null return in tty_ldisc_ref.
+ - v4l: cx88 hue offset fix
+ - Fix 8139cp breakage that occurs with tpm driver.
+ - Fix the 6pack driver in SMP environments.
+ - Switch to spinlocks in the shaper driver.
+ - ppc32: stop misusing NTP's time_offset value
+ - netfilter: go back to dropping conntrack references manually
+ - ACPI: don't accept 0 as a PCI IRQ.
+
+ * Enable CONFIG_SCSI_INITIO. (Maximilian Attems) (closes: #318121)
+
+ * [powerpc] :
+ - Added powerpc-mkvmlinuz-support patch which allows, together with
+ kernel-package 9.0002 to add mkvmlinuz support to hand built packages.
+ - Removed powerpc-ppc64-ibmvscsi.patch, FTBFS, and Christoph doesn't like
+ it and thinks it is not needed.
+ - Disabled swim3 on powerpc-smp, FTBFS.
+ - Disabled software-suspend on powerpc-smp, FTBFS, amd64/i386 only smp code.
+ - Rediffed and readded the G4 L2 hardware flush assist patch from Jacob Pan.
+ (Sven Luther)
+
+ * [sparc]
+ - Drop sparc32 flavour for now. sparc32 kernel is currently in the
+ category "too buggy for us to support". In spite of numerous efforts
+ I still see occasional random filesystem corruptions in my tests.
+ That does NOT mean that we are dropping sparc32 support, we will
+ work with upstream trying to solve these problems for the next
+ kernel release. Those interested in helping/testing are encouraged
+ to subscribe to debian-sparc mailing list.
+ (Jurij Smakov)
+
+ * [alpha]
+ - Renamed resulting binary packages for alpha, kernel-image-x.y.z-generic
+ wasn't a generic kernel, it was a generic kernel for alpha machines, so
+ we're now using linux-image-x.y.z-alpha-generic (and of course, the same
+ change for the smp kernel-image). This change was postponed after the
+ sarge release. (closes: #260003)
+ (Norbert Tretkowski)
+
+ * [amd64]
+ - Now using the default compiler (gcc-4.0), thus we get rid of the
+ annoying MAKEFLAGS="CC=gcc-3.4" make-kpkg... invocation for third-party
+ modules.
+ This release lacks 64bit kernels for i386 userland; support will be
+ added in a later release as soon as the toolchain has stabilized again.
+ (Frederik Schüler)
+
+ -- Andres Salomon <dilinger at debian.org> Wed, 20 Jul 2005 17:16:04 -0400
+
Added: people/maks-guest/linux-2.6/debian/compat
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/compat Sat Nov 11 02:48:00 2006
@@ -0,0 +1 @@
+4
Added: people/maks-guest/linux-2.6/debian/copyright
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/copyright Sat Nov 11 02:48:00 2006
@@ -0,0 +1,35 @@
+This is the Debian GNU/Linux prepackaged version of the Linux kernel.
+Linux was written by Linus Torvalds <Linus.Torvalds at cs.Helsinki.FI>
+and others.
+
+This package was put together by Simon Shapiro <Shimon at i-Connect.Net>, from
+sources retrieved from directories under
+ftp.cs.helsinki.fi:/pub/Software/Linux/Kernel/
+The sources may be found at most Linux ftp sites, including
+ftp://ftp.kernel.org/pub/linux/kernel/
+
+This package was then maintained by Sven Rudolph.
+
+This package was maintained by Herbert Xu <herbert at debian.org>
+from March 1997 to May 2004.
+
+This package is currently maintained by the
+Debian Kernel Team <debian-kernel at lists.debian.org>
+
+Linux is copyrighted by Linus Torvalds 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; version 2 dated June, 1991.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+On Debian GNU/Linux systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/__init__.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/__init__.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,6 @@
+import os, os.path, re, sys, textwrap, ConfigParser
+
+from config import config_reader
+from debian import *
+from utils import *
+
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/abi.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/abi.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,75 @@
+class symbols(object):
+ def __init__(self, filename = None):
+ if filename is not None:
+ self.read(file(filename))
+
+ def cmp(self, new):
+ symbols_ref = set(self.symbols.keys())
+ symbols_new = set(new.symbols.keys())
+
+ symbols_add = {}
+ symbols_remove = {}
+
+ symbols_change = {}
+
+ for symbol in symbols_new - symbols_ref:
+ symbols_add[symbol] = {'module': new.symbols[symbol][0]}
+
+ for symbol in symbols_ref.intersection(symbols_new):
+ module_ref, version_ref, export_ref = self.symbols[symbol]
+ module_new, version_new, export_new = new.symbols[symbol]
+
+ ent = {}
+ if module_ref != module_new:
+ ent['module'] = module_ref, module_new
+ if version_ref != version_new:
+ ent['version'] = version_ref, version_new
+ if export_ref != export_new:
+ ent['export'] = export_ref, export_new
+ if ent:
+ symbols_change[symbol] = ent
+
+ for symbol in symbols_ref - symbols_new:
+ symbols_remove[symbol] = {'module': self.symbols[symbol][0]}
+
+ return symbols_add, symbols_change, symbols_remove
+
+ def read(self, file):
+ self.modules = {}
+ self.symbols = {}
+
+ for line in file.readlines():
+ version, symbol, module, export = line.strip().split()
+
+ symbols = self.modules.get(module, {})
+ symbols[symbol] = version
+ self.modules[module] = symbols
+ if self.symbols.has_key(symbol):
+ pass
+ self.symbols[symbol] = module, version, export
+
+ def write(self, file):
+ symbols = self.symbols.items()
+ symbols.sort()
+ for symbol, i in symbols:
+ module, version, export = i
+ file.write("%s %s %s %s\n" % (version, symbol, module, export))
+
+ def write_human(self, file):
+ modules = self.modules.keys()
+ modules.sort()
+ modules.remove('vmlinux')
+
+ file.write("Symbols in vmlinux\n\n")
+ symbols = self.modules['vmlinux'].items()
+ symbols.sort()
+ for symbol, version, export in symbols:
+ file.write("%-48s %s %s\n" % (symbol, version, export))
+
+ for module in modules:
+ file.write("\n\nSymbols in module %s\n\n" % module)
+ symbols = self.modules[module].items()
+ symbols.sort()
+ for symbol, version, export in symbols:
+ file.write("%-48s %s %s\n" % (symbol, version, export))
+
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/config.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/config.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,244 @@
+import os, os.path, re, sys, textwrap, ConfigParser
+
+__all__ = [
+ 'config_parser',
+ 'config_reader',
+ 'config_reader_arch',
+]
+
+_marker = object()
+
+class schema_item_boolean(object):
+ def __call__(self, i):
+ i = i.strip().lower()
+ if i in ("true", "1"):
+ return True
+ if i in ("false", "0"):
+ return False
+ raise Error
+
+class schema_item_list(object):
+ def __init__(self, type = "\s+"):
+ self.type = type
+
+ def __call__(self, i):
+ i = i.strip()
+ if not i:
+ return []
+ return [j.strip() for j in re.split(self.type, i)]
+
+class config_reader(dict):
+ config_name = "defines"
+
+ def __init__(self, dirs = []):
+ self._dirs = dirs
+
+ def __getitem__(self, key):
+ return self.get(key)
+
+ def _get_files(self, name):
+ return [os.path.join(i, name) for i in self._dirs if i]
+
+ def _update(self, ret, inputkey):
+ for key, value in super(config_reader, self).get(tuple(inputkey), {}).iteritems():
+ ret[key] = value
+
+ def get(self, key, default = _marker):
+ if isinstance(key, basestring):
+ key = key,
+
+ ret = super(config_reader, self).get(tuple(key), default)
+ if ret == _marker:
+ raise KeyError, key
+ return ret
+
+ def merge(self, section, *args):
+ ret = {}
+ for i in xrange(0, len(args) + 1):
+ ret.update(self.get(tuple([section] + list(args[:i])), {}))
+ return ret
+
+ def sections(self):
+ return super(config_reader, self).keys()
+
+class config_reader_arch(config_reader):
+ schema = {
+ 'arches': schema_item_list(),
+ 'available': schema_item_boolean(),
+ 'configs': schema_item_list(),
+ 'flavours': schema_item_list(),
+ 'initramfs': schema_item_boolean(),
+ 'initramfs-generators': schema_item_list(),
+ 'modules': schema_item_boolean(),
+ 'subarches': schema_item_list(),
+ 'versions': schema_item_list(),
+ }
+
+ def __init__(self, dirs = []):
+ super(config_reader_arch, self).__init__(dirs)
+ self._read_base()
+
+ def _read_arch(self, arch):
+ files = self._get_files("%s/%s" % (arch, self.config_name))
+ config = config_parser(self.schema, files)
+
+ subarches = config['base',].get('subarches', [])
+ flavours = config['base',].get('flavours', [])
+
+ for section in iter(config):
+ real = list(section)
+ # TODO
+ if real[-1] in subarches:
+ real[0:0] = ['base', arch]
+ elif real[-1] in flavours:
+ real[0:0] = ['base', arch, 'none']
+ else:
+ real[0:0] = [real.pop()]
+ if real[-1] in flavours:
+ real[1:1] = [arch, 'none']
+ else:
+ real[1:1] = [arch]
+ real = tuple(real)
+ s = self.get(real, {})
+ s.update(config[section])
+ self[tuple(real)] = s
+
+ for subarch in subarches:
+ if self.has_key(('base', arch, subarch)):
+ avail = self['base', arch, subarch].get('available', True)
+ else:
+ avail = True
+ if avail:
+ self._read_subarch(arch, subarch)
+
+ if flavours:
+ base = self['base', arch]
+ subarches.insert(0, 'none')
+ base['subarches'] = subarches
+ del base['flavours']
+ self['base', arch] = base
+ self['base', arch, 'none'] = {'flavours': flavours}
+ for flavour in flavours:
+ self._read_flavour(arch, 'none', flavour)
+
+ def _read_base(self):
+ files = self._get_files(self.config_name)
+ config = config_parser(self.schema, files)
+
+ arches = config['base',]['arches']
+
+ for section in iter(config):
+ real = list(section)
+ if real[-1] in arches:
+ real.insert(0, 'base')
+ else:
+ real.insert(0, real.pop())
+ self[tuple(real)] = config[section]
+
+ for arch in arches:
+ try:
+ avail = self['base', arch].get('available', True)
+ except KeyError:
+ avail = True
+ if avail:
+ self._read_arch(arch)
+
+ def _read_flavour(self, arch, subarch, flavour):
+ if not self.has_key(('base', arch, subarch, flavour)):
+ if subarch == 'none':
+ import warnings
+ warnings.warn('No config entry for flavour %s, subarch none, arch %s' % (flavour, arch), DeprecationWarning)
+ self['base', arch, subarch, flavour] = {}
+
+ def _read_subarch(self, arch, subarch):
+ files = self._get_files("%s/%s/%s" % (arch, subarch, self.config_name))
+ config = config_parser(self.schema, files)
+
+ flavours = config['base',].get('flavours', [])
+
+ for section in iter(config):
+ real = list(section)
+ if real[-1] in flavours:
+ real[0:0] = ['base', arch, subarch]
+ else:
+ real[0:0] = [real.pop(), arch, subarch]
+ real = tuple(real)
+ s = self.get(real, {})
+ s.update(config[section])
+ self[tuple(real)] = s
+
+ for flavour in flavours:
+ self._read_flavour(arch, subarch, flavour)
+
+ def merge(self, section, arch = None, subarch = None, flavour = None):
+ ret = {}
+ ret.update(self.get((section,), {}))
+ if arch:
+ ret.update(self.get((section, arch), {}))
+ if flavour and subarch and subarch != 'none':
+ ret.update(self.get((section, arch, 'none', flavour), {}))
+ if subarch:
+ ret.update(self.get((section, arch, subarch), {}))
+ if flavour:
+ ret.update(self.get((section, arch, subarch, flavour), {}))
+ return ret
+
+class config_parser(object):
+ __slots__ = 'configs', 'schema'
+
+ def __init__(self, schema, files):
+ self.configs = []
+ self.schema = schema
+ for file in files:
+ config = ConfigParser.ConfigParser()
+ config.read(file)
+ self.configs.append(config)
+
+ def __getitem__(self, key):
+ return self.items(key)
+
+ def __iter__(self):
+ return iter(self.sections())
+
+ def items(self, section, var = {}):
+ ret = {}
+ section = '_'.join(section)
+ exceptions = []
+ for config in self.configs:
+ try:
+ items = config.items(section)
+ except ConfigParser.NoSectionError, e:
+ exceptions.append(e)
+ else:
+ for key, value in items:
+ try:
+ value = self.schema[key](value)
+ except KeyError: pass
+ ret[key] = value
+ if len(exceptions) == len(self.configs):
+ raise exceptions[0]
+ return ret
+
+ def sections(self):
+ sections = []
+ for config in self.configs:
+ for section in config.sections():
+ section = tuple(section.split('_'))
+ if section not in sections:
+ sections.append(section)
+ return sections
+
+if __name__ == '__main__':
+ import sys
+ config = config_reader()
+ sections = config.sections()
+ sections.sort()
+ for section in sections:
+ print "[%s]" % (section,)
+ items = config[section]
+ items_keys = items.keys()
+ items_keys.sort()
+ for item in items:
+ print "%s: %s" % (item, items[item])
+ print
+
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/debian.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/debian.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,300 @@
+import itertools, os.path, re, utils
+
+def read_changelog(dir = ''):
+ r = re.compile(r"""
+^
+(
+(?P<header>
+ (?P<header_source>
+ \w[-+0-9a-z.]+
+ )
+ \
+ \(
+ (?P<header_version>
+ [^\(\)\ \t]+
+ )
+ \)
+ \s+
+ (?P<header_distribution>
+ [-0-9a-zA-Z]+
+ )
+ \;
+)
+)
+""", re.VERBOSE)
+ f = file(os.path.join(dir, "debian/changelog"))
+ entries = []
+ act_upstream = None
+ while True:
+ line = f.readline()
+ if not line:
+ break
+ line = line.strip('\n')
+ match = r.match(line)
+ if not match:
+ continue
+ if match.group('header'):
+ e = {}
+ e['Distribution'] = match.group('header_distribution')
+ e['Source'] = match.group('header_source')
+ version = parse_version(match.group('header_version'))
+ e['Version'] = version
+ if act_upstream is None:
+ act_upstream = version['upstream']
+ elif version['upstream'] != act_upstream:
+ break
+ entries.append(e)
+ return entries
+
+def parse_version(version):
+ ret = {
+ 'complete': version,
+ 'upstream': version,
+ 'debian': None,
+ 'linux': None,
+ }
+ try:
+ i = len(version) - version[::-1].index('-')
+ except ValueError:
+ return ret
+ ret['upstream'] = version[:i-1]
+ ret['debian'] = version[i:]
+ try:
+ ret['linux'] = parse_version_linux(version)
+ except ValueError:
+ pass
+ return ret
+
+def parse_version_linux(version):
+ version_re = ur"""
+^
+(?P<source>
+ (?P<parent>
+ \d+\.\d+\.\d+\+
+ )?
+ (?P<upstream>
+ (?P<version>
+ (?P<major>\d+\.\d+)
+ \.
+ \d+
+ )
+ (?:
+ -
+ (?P<modifier>
+ .+?
+ )
+ )?
+ )
+ -
+ (?P<debian>[^-]+)
+)
+$
+"""
+ match = re.match(version_re, version, re.X)
+ if match is None:
+ raise ValueError
+ ret = match.groupdict()
+ if ret['parent'] is not None:
+ ret['source_upstream'] = ret['parent'] + ret['upstream']
+ else:
+ ret['source_upstream'] = ret['upstream']
+ return ret
+
+class package_description(object):
+ __slots__ = "short", "long"
+
+ def __init__(self, value = None):
+ self.long = []
+ if value is not None:
+ self.short, long = value.split("\n", 1)
+ self.append(long)
+ else:
+ self.short = None
+
+ def __str__(self):
+ ret = self.short + '\n'
+ w = utils.wrap(width = 74, fix_sentence_endings = True)
+ pars = []
+ for i in self.long:
+ pars.append('\n '.join(w.wrap(i)))
+ return self.short + '\n ' + '\n .\n '.join(pars)
+
+ def append(self, str):
+ str = str.strip()
+ if str:
+ self.long.extend(str.split("\n.\n"))
+
+class package_relation(object):
+ __slots__ = "name", "version", "arches"
+
+ _re = re.compile(r'^(\S+)(?: \(([^)]+)\))?(?: \[([^]]+)\])?$')
+
+ def __init__(self, value = None):
+ if value is not None:
+ self.parse(value)
+ else:
+ self.name = None
+ self.version = None
+ self.arches = []
+
+ def __str__(self):
+ ret = [self.name]
+ if self.version is not None:
+ ret.extend([' (', self.version, ')'])
+ if self.arches:
+ ret.extend([' [', ' '.join(self.arches), ']'])
+ return ''.join(ret)
+
+ def config(self, entry):
+ if self.version is not None or self.arches:
+ return
+ value = entry.get(self.name, None)
+ if value is None:
+ return
+ self.parse(value)
+
+ def parse(self, value):
+ match = self._re.match(value)
+ if match is None:
+ raise RuntimeError, "Can't parse dependency %s" % value
+ match = match.groups()
+ self.name = match[0]
+ self.version = match[1]
+ if match[2] is not None:
+ self.arches = re.split('\s+', match[2])
+ else:
+ self.arches = []
+
+class package_relation_list(list):
+ def __init__(self, value = None):
+ if value is not None:
+ self.extend(value)
+
+ def __str__(self):
+ return ', '.join([str(i) for i in self])
+
+ def _match(self, value):
+ for i in self:
+ if i._match(value):
+ return i
+ return None
+
+ def append(self, value):
+ if isinstance(value, basestring):
+ value = package_relation_group(value)
+ elif not isinstance(value, package_relation_group):
+ raise ValueError, "got %s" % type(value)
+ j = self._match(value)
+ if j:
+ j._update_arches(value)
+ else:
+ super(package_relation_list, self).append(value)
+
+ def config(self, entry):
+ for i in self:
+ i.config(entry)
+
+ def extend(self, value):
+ if isinstance(value, basestring):
+ value = [j.strip() for j in re.split(',', value.strip())]
+ elif not isinstance(value, (list, tuple)):
+ raise ValueError, "got %s" % type(value)
+ for i in value:
+ self.append(i)
+
+class package_relation_group(list):
+ def __init__(self, value = None):
+ if value is not None:
+ self.extend(value)
+
+ def __str__(self):
+ return ' | '.join([str(i) for i in self])
+
+ def _match(self, value):
+ for i, j in itertools.izip(self, value):
+ if i.name != j.name or i.version != j.version:
+ return None
+ return self
+
+ def _update_arches(self, value):
+ for i, j in itertools.izip(self, value):
+ if i.arches:
+ for arch in j.arches:
+ if arch not in i.arches:
+ i.arches.append(arch)
+
+ def append(self, value):
+ if isinstance(value, basestring):
+ value = package_relation(value)
+ elif not isinstance(value, package_relation):
+ raise ValueError
+ super(package_relation_group, self).append(value)
+
+ def config(self, entry):
+ for i in self:
+ i.config(entry)
+
+ def extend(self, value):
+ if isinstance(value, basestring):
+ value = [j.strip() for j in re.split('\|', value.strip())]
+ elif not isinstance(value, (list, tuple)):
+ raise ValueError
+ for i in value:
+ self.append(i)
+
+class package(dict):
+ _fields = utils.sorted_dict((
+ ('Package', str),
+ ('Source', str),
+ ('Architecture', utils.field_list),
+ ('Section', str),
+ ('Priority', str),
+ ('Maintainer', str),
+ ('Uploaders', str),
+ ('Standards-Version', str),
+ ('Build-Depends', package_relation_list),
+ ('Build-Depends-Indep', package_relation_list),
+ ('Provides', package_relation_list),
+ ('Depends', package_relation_list),
+ ('Recommends', package_relation_list),
+ ('Suggests', package_relation_list),
+ ('Replaces', package_relation_list),
+ ('Conflicts', package_relation_list),
+ ('Description', package_description),
+ ))
+
+ def __setitem__(self, key, value):
+ try:
+ cls = self._fields[key]
+ if not isinstance(value, cls):
+ value = cls(value)
+ except KeyError: pass
+ super(package, self).__setitem__(key, value)
+
+ def iterkeys(self):
+ keys = set(self.keys())
+ for i in self._fields.iterkeys():
+ if self.has_key(i):
+ keys.remove(i)
+ yield i
+ for i in keys:
+ yield i
+
+ def iteritems(self):
+ keys = set(self.keys())
+ for i in self._fields.iterkeys():
+ if self.has_key(i):
+ keys.remove(i)
+ yield (i, self[i])
+ for i in keys:
+ yield (i, self[i])
+
+ def itervalues(self):
+ keys = set(self.keys())
+ for i in self._fields.iterkeys():
+ if self.has_key(i):
+ keys.remove(i)
+ yield self[i]
+ for i in keys:
+ yield self[i]
+
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/gencontrol.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/gencontrol.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,279 @@
+from config import *
+from debian import *
+from utils import *
+
+class packages_list(sorted_dict):
+ def append(self, package):
+ self[package['Package']] = package
+
+ def extend(self, packages):
+ for package in packages:
+ self[package['Package']] = package
+
+class flags(dict):
+ def __repr__(self):
+ repr = super(flags, self).__repr__()
+ return "%s(%s)" % (self.__class__.__name__, repr)
+
+ def __str__(self):
+ return ' '.join(["%s='%s'" % i for i in self.iteritems()])
+
+ def copy(self):
+ return self.__class__(super(flags, self).copy())
+
+class gencontrol(object):
+ makefile_targets = ('binary-arch', 'build', 'setup', 'source')
+
+ def __init__(self, underlay = None):
+ self.config = config_reader_arch([underlay, "debian/arch"])
+ self.templates = templates()
+
+ def __call__(self):
+ packages = packages_list()
+ makefile = [('.NOTPARALLEL:', ())]
+
+ self.do_source(packages)
+ self.do_main(packages, makefile)
+ self.do_extra(packages, makefile)
+
+ self.write_control(packages.itervalues())
+ self.write_makefile(makefile)
+
+ def do_source(self, packages):
+ source = self.templates["control.source"]
+ packages['source'] = self.process_package(source[0], self.vars)
+
+ def do_main(self, packages, makefile):
+ config_entry = self.config['base',]
+ vars = self.vars.copy()
+ vars.update(config_entry)
+
+ makeflags = flags()
+ extra = {}
+
+ self.do_main_setup(vars, makeflags, extra)
+ self.do_main_packages(packages, extra)
+ self.do_main_makefile(makefile, makeflags, extra)
+
+ for arch in iter(self.config['base',]['arches']):
+ self.do_arch(packages, makefile, arch, vars.copy(), makeflags.copy(), extra)
+
+ def do_main_setup(self, vars, makeflags, extra):
+ makeflags.update({
+ 'MAJOR': self.version['linux']['major'],
+ 'VERSION': self.version['linux']['version'],
+ 'UPSTREAMVERSION': self.version['linux']['upstream'],
+ 'ABINAME': self.abiname,
+ })
+
+ def do_main_makefile(self, makefile, makeflags, extra):
+ cmds_binary_indep = []
+ cmds_binary_indep.append(("$(MAKE) -f debian/rules.real binary-indep %s" % makeflags,))
+ makefile.append(("binary-indep:", cmds_binary_indep))
+
+ def do_main_packages(self, packages, extra):
+ pass
+
+ def do_extra(self, packages, makefile):
+ try:
+ templates_extra = self.templates["control.extra"]
+ except IOError:
+ return
+
+ packages.extend(self.process_packages(templates_extra, {}))
+ extra_arches = {}
+ for package in templates_extra:
+ arches = package['Architecture']
+ for arch in arches:
+ i = extra_arches.get(arch, [])
+ i.append(package)
+ extra_arches[arch] = i
+ archs = extra_arches.keys()
+ archs.sort()
+ for arch in archs:
+ cmds = []
+ for i in extra_arches[arch]:
+ tmp = []
+ if i.has_key('X-Version-Overwrite-Epoch'):
+ tmp.append("-v1:%s" % self.version['source'])
+ cmds.append("$(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-p%s' GENCONTROL_ARGS='%s'" % (i['Package'], ' '.join(tmp)))
+ makefile.append("binary-arch-%s:: binary-arch-%s-extra" % (arch, arch))
+ makefile.append(("binary-arch-%s-extra:" % arch, cmds))
+
+ def do_arch(self, packages, makefile, arch, vars, makeflags, extra):
+ config_entry = self.config['base', arch]
+ vars.update(config_entry)
+ vars['arch'] = arch
+
+ if not config_entry.get('available', True):
+ for i in self.makefile_targets:
+ makefile.append(("%s-%s:" % (i, arch), ["@echo Architecture %s is not available!" % arch, "@exit 1"]))
+ return
+
+ makeflags['ARCH'] = arch
+
+ vars['localversion'] = ''
+
+ self.do_arch_setup(vars, makeflags, arch, extra)
+ self.do_arch_makefile(makefile, arch, makeflags, extra)
+ self.do_arch_packages(packages, makefile, arch, vars, makeflags, extra)
+ self.do_arch_recurse(packages, makefile, arch, vars, makeflags, extra)
+
+ def do_arch_setup(self, vars, makeflags, arch, extra):
+ pass
+
+ def do_arch_makefile(self, makefile, arch, makeflags, extra):
+ for i in self.makefile_targets:
+ makefile.append("%s:: %s-%s" % (i, i, arch))
+ makefile.append("%s-%s:: %s-%s-real" % (i, arch, i, arch))
+
+ def do_arch_packages(self, packages, makefile, arch, vars, makeflags, extra):
+ for i in self.makefile_targets:
+ makefile.append("%s-%s-real:" % (i, arch))
+
+ def do_arch_recurse(self, packages, makefile, arch, vars, makeflags, extra):
+ for subarch in self.config['base', arch]['subarches']:
+ self.do_subarch(packages, makefile, arch, subarch, vars.copy(), makeflags.copy(), extra)
+
+ def do_subarch(self, packages, makefile, arch, subarch, vars, makeflags, extra):
+ config_entry = self.config['base', arch, subarch]
+ vars.update(config_entry)
+
+ makeflags['SUBARCH'] = subarch
+ if subarch != 'none':
+ vars['localversion'] += '-' + subarch
+
+ self.do_subarch_setup(vars, makeflags, arch, subarch, extra)
+ self.do_subarch_makefile(makefile, arch, subarch, makeflags, extra)
+ self.do_subarch_packages(packages, makefile, arch, subarch, vars, makeflags, extra)
+ self.do_subarch_recurse(packages, makefile, arch, subarch, vars, makeflags, extra)
+
+ def do_subarch_setup(self, vars, makeflags, arch, subarch, extra):
+ pass
+
+ def do_subarch_makefile(self, makefile, arch, subarch, makeflags, extra):
+ for i in self.makefile_targets:
+ makefile.append("%s-%s:: %s-%s-%s" % (i, arch, i, arch, subarch))
+ makefile.append("%s-%s-%s:: %s-%s-%s-real" % (i, arch, subarch, i, arch, subarch))
+
+ def do_subarch_packages(self, packages, makefile, arch, subarch, vars, makeflags, extra):
+ for i in self.makefile_targets:
+ makefile.append("%s-%s-%s-real:" % (i, arch, subarch))
+
+ def do_subarch_recurse(self, packages, makefile, arch, subarch, vars, makeflags, extra):
+ for flavour in self.config['base', arch, subarch]['flavours']:
+ self.do_flavour(packages, makefile, arch, subarch, flavour, vars.copy(), makeflags.copy(), extra)
+
+ def do_flavour(self, packages, makefile, arch, subarch, flavour, vars, makeflags, extra):
+ config_entry = self.config.merge('base', arch, subarch, flavour)
+ vars.update(config_entry)
+
+ if not vars.has_key('longclass'):
+ vars['longclass'] = vars['class']
+
+ makeflags['FLAVOUR'] = flavour
+ vars['localversion'] += '-' + flavour
+
+ self.do_flavour_setup(vars, makeflags, arch, subarch, flavour, extra)
+ self.do_flavour_makefile(makefile, arch, subarch, flavour, makeflags, extra)
+ self.do_flavour_packages(packages, makefile, arch, subarch, flavour, vars, makeflags, extra)
+
+ def do_flavour_setup(self, vars, makeflags, arch, subarch, flavour, extra):
+ for i in (
+ ('kernel-arch', 'KERNEL_ARCH'),
+ ('localversion', 'LOCALVERSION'),
+ ):
+ if vars.has_key(i[0]):
+ makeflags[i[1]] = vars[i[0]]
+
+ def do_flavour_makefile(self, makefile, arch, subarch, flavour, makeflags, extra):
+ for i in self.makefile_targets:
+ makefile.append("%s-%s-%s:: %s-%s-%s-%s" % (i, arch, subarch, i, arch, subarch, flavour))
+ makefile.append("%s-%s-%s-%s:: %s-%s-%s-%s-real" % (i, arch, subarch, flavour, i, arch, subarch, flavour))
+
+ def do_flavour_packages(self, packages, makefile, arch, subarch, flavour, vars, makeflags, extra):
+ pass
+
+ def process_relation(self, key, e, in_e, vars):
+ in_dep = in_e[key]
+ dep = package_relation_list()
+ for in_groups in in_dep:
+ groups = package_relation_group()
+ for in_item in in_groups:
+ item = package_relation()
+ item.name = self.substitute(in_item.name, vars)
+ if in_item.version is not None:
+ item.version = self.substitute(in_item.version, vars)
+ item.arches = in_item.arches
+ groups.append(item)
+ dep.append(groups)
+ e[key] = dep
+
+ def process_description(self, e, in_e, vars):
+ in_desc = in_e['Description']
+ desc = in_desc.__class__()
+ desc.short = self.substitute(in_desc.short, vars)
+ for i in in_desc.long:
+ desc.append(self.substitute(i, vars))
+ e['Description'] = desc
+
+ def process_package(self, in_entry, vars):
+ e = package()
+ for key, value in in_entry.iteritems():
+ if isinstance(value, package_relation_list):
+ self.process_relation(key, e, in_entry, vars)
+ elif key == 'Description':
+ self.process_description(e, in_entry, vars)
+ elif key[:2] == 'X-':
+ pass
+ else:
+ e[key] = self.substitute(value, vars)
+ return e
+
+ def process_packages(self, in_entries, vars):
+ entries = []
+ for i in in_entries:
+ entries.append(self.process_package(i, vars))
+ return entries
+
+ def process_version_linux(self, version, abiname):
+ return {
+ 'upstreamversion': version['linux']['upstream'],
+ 'version': version['linux']['version'],
+ 'source_upstream': version['linux']['source_upstream'],
+ 'major': version['linux']['major'],
+ 'abiname': abiname,
+ }
+
+ def substitute(self, s, vars):
+ if isinstance(s, (list, tuple)):
+ for i in xrange(len(s)):
+ s[i] = self.substitute(s[i], vars)
+ return s
+ def subst(match):
+ return vars[match.group(1)]
+ return re.sub(r'@([-_a-z]+)@', subst, s)
+
+ def write_control(self, list):
+ self.write_rfc822(file("debian/control", 'w'), list)
+
+ def write_makefile(self, out_list):
+ out = file("debian/rules.gen", 'w')
+ for item in out_list:
+ if isinstance(item, (list, tuple)):
+ out.write("%s\n" % item[0])
+ cmd_list = item[1]
+ if isinstance(cmd_list, basestring):
+ cmd_list = cmd_list.split('\n')
+ for j in cmd_list:
+ out.write("\t%s\n" % j)
+ else:
+ out.write("%s\n" % item)
+
+ def write_rfc822(self, f, list):
+ for entry in list:
+ for key, value in entry.iteritems():
+ f.write("%s: %s\n" % (key, value))
+ f.write('\n')
+
+
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/kconfig.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/kconfig.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,77 @@
+__all__ = (
+ "kconfigfile",
+)
+
+class _entry(object):
+ __slots__ = "name"
+
+ def __init__(self, name):
+ self.name = name
+
+class _entry_string(_entry):
+ __slots__ = "value"
+
+ def __init__(self, name, value):
+ super(_entry_string, self).__init__(name)
+ self.value = value
+
+ def __str__(self):
+ return "CONFIG_%s=%s" % (self.name, self.value)
+
+class _entry_tristate(_entry):
+ __slots__ = "value"
+
+ VALUE_NO = 0
+ VALUE_YES = 1
+ VALUE_MOD = 2
+
+ def __init__(self, name, value = None):
+ super(_entry_tristate, self).__init__(name)
+
+ if value == 'n' or value is None:
+ self.value = self.VALUE_NO
+ elif value == 'y':
+ self.value = self.VALUE_YES
+ elif value == 'm':
+ self.value = self.VALUE_MOD
+
+ def __str__(self):
+ conf = "CONFIG_%s" % self.name
+ if self.value == self.VALUE_NO:
+ return "# %s is not set" % conf
+ elif self.value == self.VALUE_YES:
+ return "%s=y" % conf
+ elif self.value == self.VALUE_MOD:
+ return "%s=m" % conf
+
+class kconfigfile(dict):
+ def __str__(self):
+ ret = []
+ for i in self.str_iter():
+ ret.append(i)
+ return '\n'.join(ret) + '\n'
+
+ def read(self, f):
+ for line in iter(f.readlines()):
+ line = line.strip()
+ if line.startswith("CONFIG_"):
+ i = line.find('=')
+ option = line[7:i]
+ value = line[i+1:]
+ if value in ('y', 'm'):
+ entry = _entry_tristate(option, value)
+ else:
+ entry = _entry_string(option, value)
+ self[option] = entry
+ elif line.startswith("# CONFIG_"):
+ option = line[9:-11]
+ self[option] = _entry_tristate(option)
+ elif line.startswith("#") or not line:
+ pass
+ else:
+ raise RuntimeError, "Can't recognize %s" % line
+
+ def str_iter(self):
+ for key, value in self.iteritems():
+ yield str(value)
+
Added: people/maks-guest/linux-2.6/debian/lib/python/debian_linux/utils.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/lib/python/debian_linux/utils.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,140 @@
+import debian, re, textwrap
+
+class sorted_dict(dict):
+ __slots__ = '_list',
+
+ def __init__(self, entries = None):
+ super(sorted_dict, self).__init__()
+ self._list = []
+ if entries is not None:
+ for key, value in entries:
+ self[key] = value
+
+ def __delitem__(self, key):
+ super(sorted_dict, self).__delitem__(key)
+ self._list.remove(key)
+
+ def __setitem__(self, key, value):
+ super(sorted_dict, self).__setitem__(key, value)
+ if key not in self._list:
+ self._list.append(key)
+
+ def iterkeys(self):
+ for i in iter(self._list):
+ yield i
+
+ def iteritems(self):
+ for i in iter(self._list):
+ yield (i, self[i])
+
+ def itervalues(self):
+ for i in iter(self._list):
+ yield self[i]
+
+class field_list(list):
+ TYPE_WHITESPACE = object()
+ TYPE_COMMATA = object()
+
+ def __init__(self, value = None, type = TYPE_WHITESPACE):
+ self.type = type
+ if isinstance(value, field_list):
+ self.type = value.type
+ self.extend(value)
+ elif isinstance(value, (list, tuple)):
+ self.extend(value)
+ else:
+ self._extend(value)
+
+ def __str__(self):
+ if self.type is self.TYPE_WHITESPACE:
+ type = ' '
+ elif self.type is self.TYPE_COMMATA:
+ type = ', '
+ return type.join(self)
+
+ def _extend(self, value):
+ if self.type is self.TYPE_WHITESPACE:
+ type = '\s'
+ elif self.type is self.TYPE_COMMATA:
+ type = ','
+ if value is not None:
+ self.extend([j.strip() for j in re.split(type, value.strip())])
+
+ def extend(self, value):
+ if isinstance(value, str):
+ self._extend(value)
+ else:
+ super(field_list, self).extend(value)
+
+class field_list_commata(field_list):
+ def __init__(self, value = None):
+ super(field_list_commata, self).__init__(value, field_list.TYPE_COMMATA)
+
+class field_string(str):
+ def __str__(self):
+ return '\n '.join(self.split('\n'))
+
+class templates(dict):
+ def __init__(self, dir = "debian/templates"):
+ self.dir = dir
+
+ def __getitem__(self, key):
+ try:
+ return dict.__getitem__(self, key)
+ except KeyError: pass
+ ret = self._read(key)
+ dict.__setitem__(self, key, ret)
+ return ret
+
+ def __setitem__(self, key, value):
+ raise NotImplemented()
+
+ def _read(self, name):
+ prefix, id = name.split('.', 1)
+ f = file("%s/%s.in" % (self.dir, name))
+
+ if prefix == 'control':
+ return self._read_control(f)
+
+ return f.read()
+
+ def _read_control(self, f):
+ entries = []
+
+ while True:
+ e = debian.package()
+ last = None
+ lines = []
+ while True:
+ line = f.readline()
+ if not line:
+ break
+ line = line.strip('\n')
+ if not line:
+ break
+ if line[0] in ' \t':
+ if not last:
+ raise ValueError('Continuation line seen before first header')
+ lines.append(line.lstrip())
+ continue
+ if last:
+ e[last] = '\n'.join(lines)
+ i = line.find(':')
+ if i < 0:
+ raise ValueError("Not a header, not a continuation: ``%s''" % line)
+ last = line[:i]
+ lines = [line[i+1:].lstrip()]
+ if last:
+ e[last] = '\n'.join(lines)
+ if not e:
+ break
+
+ entries.append(e)
+
+ return entries
+
+class wrap(textwrap.TextWrapper):
+ wordsep_re = re.compile(
+ r'(\s+|' # any whitespace
+ r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash
+
Added: people/maks-guest/linux-2.6/debian/modules/gencontrol.py
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/modules/gencontrol.py Sat Nov 11 02:48:00 2006
@@ -0,0 +1,66 @@
+#!/usr/bin/env python2.4
+import sys
+sys.path.append(sys.path[0] + "/../lib/python")
+import debian_linux.gencontrol
+from debian_linux.config import *
+from debian_linux.debian import *
+
+class gencontrol(debian_linux.gencontrol.gencontrol):
+ def __init__(self, config):
+ super(gencontrol, self).__init__(config)
+ self.process_config_version(config_parser({}, [sys.path[0] + "/../version"]))
+
+ def do_main_packages(self, packages, extra):
+ vars = self.vars
+
+ main = self.templates["control.main"]
+ packages.extend(self.process_packages(main, vars))
+
+ packages['source']['Build-Depends'].extend(
+ ['linux-support-%s%s' % (self.version['upstream'], self.abiname)]
+ )
+ packages['source']['Build-Depends'].extend(
+ ['linux-headers-%s%s-all-%s [%s]' % (self.version['upstream'], self.abiname, arch, arch)
+ for arch in self.config['base',]['arches']],
+ )
+
+ def do_flavour(self, packages, makefile, arch, subarch, flavour, vars, makeflags, extra):
+ config_entry = self.config.merge('base', arch, subarch, flavour)
+ if config_entry.get('modules', True) is False:
+ return
+
+ super(gencontrol, self).do_flavour(packages, makefile, arch, subarch, flavour, vars, makeflags, extra)
+
+ def do_flavour_packages(self, packages, makefile, arch, subarch, flavour, vars, makeflags, extra):
+ modules = self.templates["control.modules"]
+ modules = self.process_packages(modules, vars)
+
+ for package in modules:
+ name = package['Package']
+ if packages.has_key(name):
+ package = packages.get(name)
+ package['Architecture'].append(arch)
+ else:
+ package['Architecture'] = [arch]
+ packages.append(package)
+
+ makeflags_string = ' '.join(["%s='%s'" % i for i in makeflags.iteritems()])
+
+ cmds_binary_arch = []
+ cmds_binary_arch.append(("$(MAKE) -f debian/rules.real binary-arch-flavour %s" % makeflags_string,))
+ cmds_build = []
+ cmds_build.append(("$(MAKE) -f debian/rules.real build %s" % makeflags_string,))
+ cmds_setup = []
+ cmds_setup.append(("$(MAKE) -f debian/rules.real setup-flavour %s" % makeflags_string,))
+ makefile.append(("binary-arch-%s-%s-%s-real:" % (arch, subarch, flavour), cmds_binary_arch))
+ makefile.append(("build-%s-%s-%s-real:" % (arch, subarch, flavour), cmds_build))
+ makefile.append(("setup-%s-%s-%s-real:" % (arch, subarch, flavour), cmds_setup))
+
+ def process_config_version(self, config):
+ entry = config['version',]
+ self.version = parse_version(entry['source'])
+ self.abiname = entry['abiname']
+ self.vars = self.process_version_linux(self.version, self.abiname)
+
+if __name__ == '__main__':
+ gencontrol(sys.path[0] + "/../arch")()
Added: people/maks-guest/linux-2.6/debian/modules/rules.defs
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/modules/rules.defs Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3 @@
+BUILD_DIR = debian/build
+STAMPS_DIR = debian/stamps
+TEMPLATES_DIR = debian/templates
Added: people/maks-guest/linux-2.6/debian/modules/rules.include
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/modules/rules.include Sat Nov 11 02:48:00 2006
@@ -0,0 +1,57 @@
+__MODULES_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+
+DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_BUILD_ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH)
+
+include $(__MODULES_DIR)rules.defs
+
+BUILD_STAMP = $(STAMPS_DIR)/build-base
+
+build: debian/control $(BUILD_STAMP)
+$(BUILD_STAMP): $(BUILD_DIR) $(STAMPS_DIR)
+ dh_testdir
+ $(MAKE) -f debian/rules.gen build-$(DEB_HOST_ARCH)
+ touch $@
+
+$(BUILD_DIR) $(STAMPS_DIR):
+ @[ -d $@ ] || mkdir $@
+
+clean: debian/control
+ dh_testdir
+ rm -rf $(BUILD_DIR) $(STAMPS_DIR)
+ dh_clean
+
+binary-indep:
+ dh_testdir
+ $(MAKE) -f debian/rules.gen binary-indep
+
+binary-arch:
+ dh_testdir
+ $(MAKE) -f debian/rules.gen binary-arch-$(DEB_HOST_ARCH)
+
+binary: binary-indep binary-arch
+
+CONTROL_FILES += debian/changelog $(wildcard debian/templates/control.*)
+CONTROL_FILES += $(wildcard debian/arch/defines) $(wildcard debian/arch/*/defines) $(wildcard debian/arch/*/*/defines)
+GENCONTROL = $(__MODULES_DIR)gencontrol.py
+debian/control debian/rules.gen: $(CONTROL_FILES)
+ if [ -f debian/control ] && [ -f debian/control.md5sum ] && [ -f debian/rules.gen ]; then \
+ if md5sum $^ | diff - debian/control.md5sum > /dev/null; then true; else \
+ $(MAKE) -f debian/rules debian/control-real; \
+ fi \
+ else \
+ $(MAKE) -f debian/rules debian/control-real; \
+ fi
+
+debian/control-real: $(CONTROL_FILES)
+ $(GENCONTROL) $(__MODULES_DIR)..
+ md5sum $^ > debian/control.md5sum
+ @echo
+ @echo This target is made to fail intentionally, to make sure
+ @echo that it is NEVER run during the automated build. Please
+ @echo ignore the following error, the debian/control file has
+ @echo been generated SUCCESSFULLY.
+ @echo
+ exit 1
+
+.PHONY: clean build binary-indep binary-arch binary
Added: people/maks-guest/linux-2.6/debian/modules/rules.real.include
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/modules/rules.real.include Sat Nov 11 02:48:00 2006
@@ -0,0 +1,16 @@
+__MODULES_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+
+DEB_HOST_ARCH := $(shell dpkg-architecture -a$(ARCH) -qDEB_HOST_ARCH)
+DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -a$(ARCH) -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_ARCH := $(shell dpkg-architecture -a$(ARCH) -qDEB_BUILD_ARCH)
+
+export DH_OPTIONS
+
+HEADERS_DIR = /usr/src/linux-headers-$(UPSTREAMVERSION)$(ABINAME)$(LOCALVERSION)
+
+include $(__MODULES_DIR)rules.defs
+
+ifdef DEBIAN_KERNEL_JOBS
+ JOBS_ARG = -j$(DEBIAN_KERNEL_JOBS)
+endif
+
Added: people/maks-guest/linux-2.6/debian/patches/2.6.19-rc5
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/2.6.19-rc5 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1135688 @@
+diff --git a/CREDITS b/CREDITS
+index 0fe904e..5329ead 100644
+--- a/CREDITS
++++ b/CREDITS
+@@ -34,6 +34,7 @@ E: magrawal at nortelnetworks.com
+ D: Basic Interphase 5575 driver with UBR and ABR support.
+ S: 75 Donald St, Apt 42
+ S: Weymouth, MA 02188
++S: USA
+
+ N: Dave Airlie
+ E: airlied at linux.ie
+@@ -202,6 +203,7 @@ S: MS42
+ S: Hewlett-Packard
+ S: 3404 E Harmony Rd
+ S: Fort Collins, CO 80525
++S: USA
+
+ N: Arindam Banerji
+ E: axb at cse.nd.edu
+@@ -444,6 +446,7 @@ E: rbradetich at uswest.net
+ D: Linux/PA-RISC hacker
+ S: 1200 Goldenrod Dr.
+ S: Nampa, Idaho 83686
++S: USA
+
+ N: Derrick J. Brashear
+ E: shadow at dementia.org
+@@ -633,6 +636,7 @@ E: scole at lanl.gov
+ E: elenstev at mesatop.com
+ D: Various build fixes and kernel documentation.
+ S: Los Alamos, New Mexico
++S: USA
+
+ N: Hamish Coleman
+ E: hamish at zot.apana.org.au
+@@ -951,6 +955,12 @@ S: Brevia 1043
+ S: S-114 79 Stockholm
+ S: Sweden
+
++N: Pekka Enberg
++E: penberg at cs.helsinki.fi
++W: http://www.cs.helsinki.fi/u/penberg/
++D: Various kernel hacks, fixes, and cleanups.
++S: Finland
++
+ N: David Engebretsen
+ E: engebret at us.ibm.com
+ D: Linux port to 64-bit PowerPC architecture
+@@ -1620,7 +1630,8 @@ D: fbdev hacking
+
+ N: Jesper Juhl
+ E: jesper.juhl at gmail.com
+-D: Various fixes, cleanups and minor features.
++D: Various fixes, cleanups and minor features all over the tree.
++D: Wrote initial version of the hdaps driver (since passed on to others).
+ S: Lemnosvej 1, 3.tv
+ S: 2300 Copenhagen S.
+ S: Denmark
+@@ -2002,6 +2013,7 @@ W: http://www.mathematik.uni-stuttgart.d
+ D: Busmaster driver for HP 10/100 Mbit Network Adapters
+ S: University of Stuttgart, Germany and
+ S: Ecole Nationale Superieure des Telecommunications, Paris
++S: France
+
+ N: Jamie Lokier
+ E: jamie at shareable.org
+@@ -2171,6 +2183,7 @@ S: Hewlett Packard
+ S: MS 42
+ S: 3404 E. Harmony Road
+ S: Fort Collins, CO 80528
++S: USA
+
+ N: Torben Mathiasen
+ E: torben.mathiasen at compaq.com
+@@ -2227,6 +2240,12 @@ D: tc: HFSC scheduler
+ S: Freiburg
+ S: Germany
+
++N: Paul E. McKenney
++E: paulmck at us.ibm.com
++W: http://www.rdrop.com/users/paulmck/
++D: RCU and variants
++D: rcutorture module
++
+ N: Mike McLagan
+ E: mike.mclagan at linux.org
+ W: http://www.invlogic.com/~mmclagan
+@@ -2384,6 +2403,13 @@ N: Thomas Molina
+ E: tmolina at cablespeed.com
+ D: bug fixes, documentation, minor hackery
+
++N: Paul Moore
++E: paul.moore at hp.com
++D: NetLabel author
++S: Hewlett-Packard
++S: 110 Spit Brook Road
++S: Nashua, NH 03062
++
+ N: James Morris
+ E: jmorris at namei.org
+ W: http://namei.org/
+@@ -2470,7 +2496,8 @@ S: Derbyshire DE4 3RL
+ S: United Kingdom
+
+ N: Ian S. Nelson
+-E: ian.nelson at echostar.com
++E: nelsonis at earthlink.net
++P: 1024D/00D3D983 3EFD 7B86 B888 D7E2 29B6 9E97 576F 1B97 00D3 D983
+ D: Minor mmap and ide hacks
+ S: 1370 Atlantis Ave.
+ S: Lafayette CO, 80026
+@@ -2960,6 +2987,10 @@ S: 69 rue Dunois
+ S: 75013 Paris
+ S: France
+
++N: Dipankar Sarma
++E: dipankar at in.ibm.com
++D: RCU
++
+ N: Hannu Savolainen
+ E: hannu at opensound.com
+ D: Maintainer of the sound drivers until 2.1.x days.
+@@ -3272,6 +3303,12 @@ S: 3 Ballow Crescent
+ S: MacGregor A.C.T 2615
+ S: Australia
+
++N: Josh Triplett
++E: josh at freedesktop.org
++P: 1024D/D0FE7AFB B24A 65C9 1D71 2AC2 DE87 CA26 189B 9946 D0FE 7AFB
++D: rcutorture maintainer
++D: lock annotations, finding and fixing lock bugs
++
+ N: Winfried Trümper
+ E: winni at xpilot.org
+ W: http://www.shop.de/~winni/
+@@ -3541,11 +3578,11 @@ S: Fargo, North Dakota 58122
+ S: USA
+
+ N: Steven Whitehouse
+-E: SteveW at ACM.org
++E: steve at chygwyn.com
+ W: http://www.chygwyn.com/~steve
+-D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
++D: Linux DECnet project
+ D: Minor debugging of other networking protocols.
+-D: Misc bug fixes and filesystem development
++D: Misc bug fixes and GFS2 filesystem development
+
+ N: Hans-Joachim Widmaier
+ E: hjw at zvw.de
+@@ -3643,7 +3680,7 @@ S: Portland, OR
+ S: USA
+
+ N: Michal Wronski
+-E: Michal.Wronski at motorola.com
++E: michal.wronski at gmail.com
+ D: POSIX message queues fs (with K. Benedyczak)
+ S: Krakow
+ S: Poland
+diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
+index 5f7f7d7..02457ec 100644
+--- a/Documentation/00-INDEX
++++ b/Documentation/00-INDEX
+@@ -184,6 +184,8 @@ mtrr.txt
+ - how to use PPro Memory Type Range Registers to increase performance.
+ nbd.txt
+ - info on a TCP implementation of a network block device.
++netlabel/
++ - directory with information on the NetLabel subsystem.
+ networking/
+ - directory with info on various aspects of networking with Linux.
+ nfsroot.txt
+diff --git a/Documentation/ABI/obsolete/devfs b/Documentation/ABI/obsolete/devfs
+deleted file mode 100644
+index b8b8739..0000000
+--- a/Documentation/ABI/obsolete/devfs
++++ /dev/null
+@@ -1,13 +0,0 @@
+-What: devfs
+-Date: July 2005
+-Contact: Greg Kroah-Hartman <gregkh at suse.de>
+-Description:
+- devfs has been unmaintained for a number of years, has unfixable
+- races, contains a naming policy within the kernel that is
+- against the LSB, and can be replaced by using udev.
+- The files fs/devfs/*, include/linux/devfs_fs*.h will be removed,
+- along with the the assorted devfs function calls throughout the
+- kernel tree.
+-
+-Users:
+-
+diff --git a/Documentation/ABI/removed/devfs b/Documentation/ABI/removed/devfs
+new file mode 100644
+index 0000000..8195c4e
+--- /dev/null
++++ b/Documentation/ABI/removed/devfs
+@@ -0,0 +1,12 @@
++What: devfs
++Date: July 2005 (scheduled), finally removed in kernel v2.6.18
++Contact: Greg Kroah-Hartman <gregkh at suse.de>
++Description:
++ devfs has been unmaintained for a number of years, has unfixable
++ races, contains a naming policy within the kernel that is
++ against the LSB, and can be replaced by using udev.
++ The files fs/devfs/*, include/linux/devfs_fs*.h were removed,
++ along with the the assorted devfs function calls throughout the
++ kernel tree.
++
++Users:
+diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
+new file mode 100644
+index 0000000..dcff4d0
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-power
+@@ -0,0 +1,103 @@
++What: /sys/power/
++Date: August 2006
++Contact: Rafael J. Wysocki <rjw at sisk.pl>
++Description:
++ The /sys/power directory will contain files that will
++ provide a unified interface to the power management
++ subsystem.
++
++What: /sys/power/state
++Date: August 2006
++Contact: Rafael J. Wysocki <rjw at sisk.pl>
++Description:
++ The /sys/power/state file controls the system power state.
++ Reading from this file returns what states are supported,
++ which is hard-coded to 'standby' (Power-On Suspend), 'mem'
++ (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
++
++ Writing to this file one of these strings causes the system to
++ transition into that state. Please see the file
++ Documentation/power/states.txt for a description of each of
++ these states.
++
++What: /sys/power/disk
++Date: September 2006
++Contact: Rafael J. Wysocki <rjw at sisk.pl>
++Description:
++ The /sys/power/disk file controls the operating mode of the
++ suspend-to-disk mechanism. Reading from this file returns
++ the name of the method by which the system will be put to
++ sleep on the next suspend. There are four methods supported:
++ 'firmware' - means that the memory image will be saved to disk
++ by some firmware, in which case we also assume that the
++ firmware will handle the system suspend.
++ 'platform' - the memory image will be saved by the kernel and
++ the system will be put to sleep by the platform driver (e.g.
++ ACPI or other PM registers).
++ 'shutdown' - the memory image will be saved by the kernel and
++ the system will be powered off.
++ 'reboot' - the memory image will be saved by the kernel and
++ the system will be rebooted.
++
++ Additionally, /sys/power/disk can be used to turn on one of the
++ two testing modes of the suspend-to-disk mechanism: 'testproc'
++ or 'test'. If the suspend-to-disk mechanism is in the
++ 'testproc' mode, writing 'disk' to /sys/power/state will cause
++ the kernel to disable nonboot CPUs and freeze tasks, wait for 5
++ seconds, unfreeze tasks and enable nonboot CPUs. If it is in
++ the 'test' mode, writing 'disk' to /sys/power/state will cause
++ the kernel to disable nonboot CPUs and freeze tasks, shrink
++ memory, suspend devices, wait for 5 seconds, resume devices,
++ unfreeze tasks and enable nonboot CPUs. Then, we are able to
++ look in the log messages and work out, for example, which code
++ is being slow and which device drivers are misbehaving.
++
++ The suspend-to-disk method may be chosen by writing to this
++ file one of the accepted strings:
++
++ 'firmware'
++ 'platform'
++ 'shutdown'
++ 'reboot'
++ 'testproc'
++ 'test'
++
++ It will only change to 'firmware' or 'platform' if the system
++ supports that.
++
++What: /sys/power/image_size
++Date: August 2006
++Contact: Rafael J. Wysocki <rjw at sisk.pl>
++Description:
++ The /sys/power/image_size file controls the size of the image
++ created by the suspend-to-disk mechanism. It can be written a
++ string representing a non-negative integer that will be used
++ as an upper limit of the image size, in bytes. The kernel's
++ suspend-to-disk code will do its best to ensure the image size
++ will not exceed this number. However, if it turns out to be
++ impossible, the kernel will try to suspend anyway using the
++ smallest image possible. In particular, if "0" is written to
++ this file, the suspend image will be as small as possible.
++
++ Reading from this file will display the current image size
++ limit, which is set to 500 MB by default.
++
++What: /sys/power/pm_trace
++Date: August 2006
++Contact: Rafael J. Wysocki <rjw at sisk.pl>
++Description:
++ The /sys/power/pm_trace file controls the code which saves the
++ last PM event point in the RTC across reboots, so that you can
++ debug a machine that just hangs during suspend (or more
++ commonly, during resume). Namely, the RTC is only used to save
++ the last PM event point if this file contains '1'. Initially
++ it contains '0' which may be changed to '1' by writing a
++ string representing a nonzero integer into it.
++
++ To use this debugging feature you should attempt to suspend
++ the machine, then reboot it and run
++
++ dmesg -s 1000000 | grep 'hash matches'
++
++ CAUTION: Using it will cause your machine's real-time (CMOS)
++ clock to be set to a random invalid time after a resume.
+diff --git a/Documentation/Changes b/Documentation/Changes
+index 4882720..abee7f5 100644
+--- a/Documentation/Changes
++++ b/Documentation/Changes
+@@ -37,15 +37,14 @@ o e2fsprogs 1.29
+ 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 pcmciautils 004 # pccardctl -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.9 # oprofiled --version
+-o udev 071 # udevinfo -V
++o udev 081 # udevinfo -V
+
+ Kernel compilation
+ ==================
+@@ -268,7 +267,7 @@ active clients.
+
+ To enable this new functionality, you need to:
+
+- mount -t nfsd nfsd /proc/fs/nfs
++ mount -t nfsd nfsd /proc/fs/nfsd
+
+ before running exportfs or mountd. It is recommended that all NFS
+ services be protected from the internet-at-large by a firewall where
+diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
+index 6d2412e..29c1896 100644
+--- a/Documentation/CodingStyle
++++ b/Documentation/CodingStyle
+@@ -532,6 +532,40 @@ appears outweighs the potential value of
+ something it would have done anyway.
+
+
++ Chapter 16: Function return values and names
++
++Functions can return values of many different kinds, and one of the
++most common is a value indicating whether the function succeeded or
++failed. Such a value can be represented as an error-code integer
++(-Exxx = failure, 0 = success) or a "succeeded" boolean (0 = failure,
++non-zero = success).
++
++Mixing up these two sorts of representations is a fertile source of
++difficult-to-find bugs. If the C language included a strong distinction
++between integers and booleans then the compiler would find these mistakes
++for us... but it doesn't. To help prevent such bugs, always follow this
++convention:
++
++ If the name of a function is an action or an imperative command,
++ the function should return an error-code integer. If the name
++ is a predicate, the function should return a "succeeded" boolean.
++
++For example, "add work" is a command, and the add_work() function returns 0
++for success or -EBUSY for failure. In the same way, "PCI device present" is
++a predicate, and the pci_dev_present() function returns 1 if it succeeds in
++finding a matching device or 0 if it doesn't.
++
++All EXPORTed functions must respect this convention, and so should all
++public functions. Private (static) functions need not, but it is
++recommended that they do.
++
++Functions whose return value is the actual result of a computation, rather
++than an indication of whether the computation succeeded, are not subject to
++this rule. Generally they indicate failure by returning some out-of-range
++result. Typical examples would be functions that return pointers; they use
++NULL or the ERR_PTR mechanism to report failure.
++
++
+
+ Appendix I: References
+
+diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
+index 63392c9..028614c 100644
+--- a/Documentation/DMA-mapping.txt
++++ b/Documentation/DMA-mapping.txt
+@@ -107,7 +107,7 @@ The query is performed via a call to pci
+
+ int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask);
+
+-The query for consistent allocations is performed via a a call to
++The query for consistent allocations is performed via a call to
+ pci_set_consistent_dma_mask():
+
+ int pci_set_consistent_dma_mask(struct pci_dev *pdev, u64 device_mask);
+@@ -117,7 +117,7 @@ device_mask is a bit mask describing whi
+ device supports. It returns zero if your card can perform DMA
+ properly on the machine given the address mask you provided.
+
+-If it returns non-zero, your device can not perform DMA properly on
++If it returns non-zero, your device cannot perform DMA properly on
+ this platform, and attempting to do so will result in undefined
+ behavior. You must either use a different mask, or not use DMA.
+
+diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
+index 66e1cf7..db9499a 100644
+--- a/Documentation/DocBook/Makefile
++++ b/Documentation/DocBook/Makefile
+@@ -9,7 +9,7 @@
+ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
+ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
+ procfs-guide.xml writing_usb_driver.xml \
+- kernel-api.xml journal-api.xml lsm.xml usb.xml \
++ kernel-api.xml filesystems.xml lsm.xml usb.xml \
+ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
+ genericirq.xml
+
+diff --git a/Documentation/DocBook/filesystems.tmpl b/Documentation/DocBook/filesystems.tmpl
+new file mode 100644
+index 0000000..39fa2ab
+--- /dev/null
++++ b/Documentation/DocBook/filesystems.tmpl
+@@ -0,0 +1,401 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
++ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
++
++<book id="Linux-filesystems-API">
++ <bookinfo>
++ <title>Linux Filesystems API</title>
++
++ <legalnotice>
++ <para>
++ This documentation 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.
++ </para>
++
++ <para>
++ 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.
++ </para>
++
++ <para>
++ 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
++ </para>
++
++ <para>
++ For more details see the file COPYING in the source
++ distribution of Linux.
++ </para>
++ </legalnotice>
++ </bookinfo>
++
++<toc></toc>
++
++ <chapter id="vfs">
++ <title>The Linux VFS</title>
++ <sect1><title>The Filesystem types</title>
++!Iinclude/linux/fs.h
++ </sect1>
++ <sect1><title>The Directory Cache</title>
++!Efs/dcache.c
++!Iinclude/linux/dcache.h
++ </sect1>
++ <sect1><title>Inode Handling</title>
++!Efs/inode.c
++!Efs/bad_inode.c
++ </sect1>
++ <sect1><title>Registration and Superblocks</title>
++!Efs/super.c
++ </sect1>
++ <sect1><title>File Locks</title>
++!Efs/locks.c
++!Ifs/locks.c
++ </sect1>
++ <sect1><title>Other Functions</title>
++!Efs/mpage.c
++!Efs/namei.c
++!Efs/buffer.c
++!Efs/bio.c
++!Efs/seq_file.c
++!Efs/filesystems.c
++!Efs/fs-writeback.c
++!Efs/block_dev.c
++ </sect1>
++ </chapter>
++
++ <chapter id="proc">
++ <title>The proc filesystem</title>
++
++ <sect1><title>sysctl interface</title>
++!Ekernel/sysctl.c
++ </sect1>
++
++ <sect1><title>proc filesystem interface</title>
++!Ifs/proc/base.c
++ </sect1>
++ </chapter>
++
++ <chapter id="sysfs">
++ <title>The Filesystem for Exporting Kernel Objects</title>
++!Efs/sysfs/file.c
++!Efs/sysfs/symlink.c
++!Efs/sysfs/bin.c
++ </chapter>
++
++ <chapter id="debugfs">
++ <title>The debugfs filesystem</title>
++
++ <sect1><title>debugfs interface</title>
++!Efs/debugfs/inode.c
++!Efs/debugfs/file.c
++ </sect1>
++ </chapter>
++
++ <chapter id="LinuxJDBAPI">
++ <chapterinfo>
++ <title>The Linux Journalling API</title>
++
++ <authorgroup>
++ <author>
++ <firstname>Roger</firstname>
++ <surname>Gammans</surname>
++ <affiliation>
++ <address>
++ <email>rgammans at computer-surgery.co.uk</email>
++ </address>
++ </affiliation>
++ </author>
++ </authorgroup>
++
++ <authorgroup>
++ <author>
++ <firstname>Stephen</firstname>
++ <surname>Tweedie</surname>
++ <affiliation>
++ <address>
++ <email>sct at redhat.com</email>
++ </address>
++ </affiliation>
++ </author>
++ </authorgroup>
++
++ <copyright>
++ <year>2002</year>
++ <holder>Roger Gammans</holder>
++ </copyright>
++ </chapterinfo>
++
++ <title>The Linux Journalling API</title>
++
++ <sect1>
++ <title>Overview</title>
++ <sect2>
++ <title>Details</title>
++<para>
++The journalling layer is easy to use. You need to
++first of all create a journal_t data structure. There are
++two calls to do this dependent on how you decide to allocate the physical
++media on which the journal resides. The journal_init_inode() call
++is for journals stored in filesystem inodes, or the journal_init_dev()
++call can be use for journal stored on a raw device (in a continuous range
++of blocks). A journal_t is a typedef for a struct pointer, so when
++you are finally finished make sure you call journal_destroy() on it
++to free up any used kernel memory.
++</para>
++
++<para>
++Once you have got your journal_t object you need to 'mount' or load the journal
++file, unless of course you haven't initialised it yet - in which case you
++need to call journal_create().
++</para>
++
++<para>
++Most of the time however your journal file will already have been created, but
++before you load it you must call journal_wipe() to empty the journal file.
++Hang on, you say , what if the filesystem wasn't cleanly umount()'d . Well, it is the
++job of the client file system to detect this and skip the call to journal_wipe().
++</para>
++
++<para>
++In either case the next call should be to journal_load() which prepares the
++journal file for use. Note that journal_wipe(..,0) calls journal_skip_recovery()
++for you if it detects any outstanding transactions in the journal and similarly
++journal_load() will call journal_recover() if necessary.
++I would advise reading fs/ext3/super.c for examples on this stage.
++[RGG: Why is the journal_wipe() call necessary - doesn't this needlessly
++complicate the API. Or isn't a good idea for the journal layer to hide
++dirty mounts from the client fs]
++</para>
++
++<para>
++Now you can go ahead and start modifying the underlying
++filesystem. Almost.
++</para>
++
++<para>
++
++You still need to actually journal your filesystem changes, this
++is done by wrapping them into transactions. Additionally you
++also need to wrap the modification of each of the buffers
++with calls to the journal layer, so it knows what the modifications
++you are actually making are. To do this use journal_start() which
++returns a transaction handle.
++</para>
++
++<para>
++journal_start()
++and its counterpart journal_stop(), which indicates the end of a transaction
++are nestable calls, so you can reenter a transaction if necessary,
++but remember you must call journal_stop() the same number of times as
++journal_start() before the transaction is completed (or more accurately
++leaves the update phase). Ext3/VFS makes use of this feature to simplify
++quota support.
++</para>
++
++<para>
++Inside each transaction you need to wrap the modifications to the
++individual buffers (blocks). Before you start to modify a buffer you
++need to call journal_get_{create,write,undo}_access() as appropriate,
++this allows the journalling layer to copy the unmodified data if it
++needs to. After all the buffer may be part of a previously uncommitted
++transaction.
++At this point you are at last ready to modify a buffer, and once
++you are have done so you need to call journal_dirty_{meta,}data().
++Or if you've asked for access to a buffer you now know is now longer
++required to be pushed back on the device you can call journal_forget()
++in much the same way as you might have used bforget() in the past.
++</para>
++
++<para>
++A journal_flush() may be called at any time to commit and checkpoint
++all your transactions.
++</para>
++
++<para>
++Then at umount time , in your put_super() (2.4) or write_super() (2.5)
++you can then call journal_destroy() to clean up your in-core journal object.
++</para>
++
++<para>
++Unfortunately there a couple of ways the journal layer can cause a deadlock.
++The first thing to note is that each task can only have
++a single outstanding transaction at any one time, remember nothing
++commits until the outermost journal_stop(). This means
++you must complete the transaction at the end of each file/inode/address
++etc. operation you perform, so that the journalling system isn't re-entered
++on another journal. Since transactions can't be nested/batched
++across differing journals, and another filesystem other than
++yours (say ext3) may be modified in a later syscall.
++</para>
++
++<para>
++The second case to bear in mind is that journal_start() can
++block if there isn't enough space in the journal for your transaction
++(based on the passed nblocks param) - when it blocks it merely(!) needs to
++wait for transactions to complete and be committed from other tasks,
++so essentially we are waiting for journal_stop(). So to avoid
++deadlocks you must treat journal_start/stop() as if they
++were semaphores and include them in your semaphore ordering rules to prevent
++deadlocks. Note that journal_extend() has similar blocking behaviour to
++journal_start() so you can deadlock here just as easily as on journal_start().
++</para>
++
++<para>
++Try to reserve the right number of blocks the first time. ;-). This will
++be the maximum number of blocks you are going to touch in this transaction.
++I advise having a look at at least ext3_jbd.h to see the basis on which
++ext3 uses to make these decisions.
++</para>
++
++<para>
++Another wriggle to watch out for is your on-disk block allocation strategy.
++why? Because, if you undo a delete, you need to ensure you haven't reused any
++of the freed blocks in a later transaction. One simple way of doing this
++is make sure any blocks you allocate only have checkpointed transactions
++listed against them. Ext3 does this in ext3_test_allocatable().
++</para>
++
++<para>
++Lock is also providing through journal_{un,}lock_updates(),
++ext3 uses this when it wants a window with a clean and stable fs for a moment.
++eg.
++</para>
++
++<programlisting>
++
++ journal_lock_updates() //stop new stuff happening..
++ journal_flush() // checkpoint everything.
++ ..do stuff on stable fs
++ journal_unlock_updates() // carry on with filesystem use.
++</programlisting>
++
++<para>
++The opportunities for abuse and DOS attacks with this should be obvious,
++if you allow unprivileged userspace to trigger codepaths containing these
++calls.
++</para>
++
++<para>
++A new feature of jbd since 2.5.25 is commit callbacks with the new
++journal_callback_set() function you can now ask the journalling layer
++to call you back when the transaction is finally committed to disk, so that
++you can do some of your own management. The key to this is the journal_callback
++struct, this maintains the internal callback information but you can
++extend it like this:-
++</para>
++<programlisting>
++ struct myfs_callback_s {
++ //Data structure element required by jbd..
++ struct journal_callback for_jbd;
++ // Stuff for myfs allocated together.
++ myfs_inode* i_commited;
++
++ }
++</programlisting>
++
++<para>
++this would be useful if you needed to know when data was committed to a
++particular inode.
++</para>
++
++ </sect2>
++
++ <sect2>
++ <title>Summary</title>
++<para>
++Using the journal is a matter of wrapping the different context changes,
++being each mount, each modification (transaction) and each changed buffer
++to tell the journalling layer about them.
++</para>
++
++<para>
++Here is a some pseudo code to give you an idea of how it works, as
++an example.
++</para>
++
++<programlisting>
++ journal_t* my_jnrl = journal_create();
++ journal_init_{dev,inode}(jnrl,...)
++ if (clean) journal_wipe();
++ journal_load();
++
++ foreach(transaction) { /*transactions must be
++ completed before
++ a syscall returns to
++ userspace*/
++
++ handle_t * xct=journal_start(my_jnrl);
++ foreach(bh) {
++ journal_get_{create,write,undo}_access(xact,bh);
++ if ( myfs_modify(bh) ) { /* returns true
++ if makes changes */
++ journal_dirty_{meta,}data(xact,bh);
++ } else {
++ journal_forget(bh);
++ }
++ }
++ journal_stop(xct);
++ }
++ journal_destroy(my_jrnl);
++</programlisting>
++ </sect2>
++
++ </sect1>
++
++ <sect1>
++ <title>Data Types</title>
++ <para>
++ The journalling layer uses typedefs to 'hide' the concrete definitions
++ of the structures used. As a client of the JBD layer you can
++ just rely on the using the pointer as a magic cookie of some sort.
++
++ Obviously the hiding is not enforced as this is 'C'.
++ </para>
++ <sect2><title>Structures</title>
++!Iinclude/linux/jbd.h
++ </sect2>
++ </sect1>
++
++ <sect1>
++ <title>Functions</title>
++ <para>
++ The functions here are split into two groups those that
++ affect a journal as a whole, and those which are used to
++ manage transactions
++ </para>
++ <sect2><title>Journal Level</title>
++!Efs/jbd/journal.c
++!Ifs/jbd/recovery.c
++ </sect2>
++ <sect2><title>Transasction Level</title>
++!Efs/jbd/transaction.c
++ </sect2>
++ </sect1>
++ <sect1>
++ <title>See also</title>
++ <para>
++ <citation>
++ <ulink url="ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/journal-design.ps.gz">
++ Journaling the Linux ext2fs Filesystem, LinuxExpo 98, Stephen Tweedie
++ </ulink>
++ </citation>
++ </para>
++ <para>
++ <citation>
++ <ulink url="http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html">
++ Ext3 Journalling FileSystem, OLS 2000, Dr. Stephen Tweedie
++ </ulink>
++ </citation>
++ </para>
++ </sect1>
++
++ </chapter>
++
++</book>
+diff --git a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl
+deleted file mode 100644
+index 2077f9a..0000000
+--- a/Documentation/DocBook/journal-api.tmpl
++++ /dev/null
+@@ -1,333 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+- "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+-
+-<book id="LinuxJBDAPI">
+- <bookinfo>
+- <title>The Linux Journalling API</title>
+- <authorgroup>
+- <author>
+- <firstname>Roger</firstname>
+- <surname>Gammans</surname>
+- <affiliation>
+- <address>
+- <email>rgammans at computer-surgery.co.uk</email>
+- </address>
+- </affiliation>
+- </author>
+- </authorgroup>
+-
+- <authorgroup>
+- <author>
+- <firstname>Stephen</firstname>
+- <surname>Tweedie</surname>
+- <affiliation>
+- <address>
+- <email>sct at redhat.com</email>
+- </address>
+- </affiliation>
+- </author>
+- </authorgroup>
+-
+- <copyright>
+- <year>2002</year>
+- <holder>Roger Gammans</holder>
+- </copyright>
+-
+-<legalnotice>
+- <para>
+- This documentation 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.
+- </para>
+-
+- <para>
+- 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.
+- </para>
+-
+- <para>
+- 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
+- </para>
+-
+- <para>
+- For more details see the file COPYING in the source
+- distribution of Linux.
+- </para>
+- </legalnotice>
+- </bookinfo>
+-
+-<toc></toc>
+-
+- <chapter id="Overview">
+- <title>Overview</title>
+- <sect1>
+- <title>Details</title>
+-<para>
+-The journalling layer is easy to use. You need to
+-first of all create a journal_t data structure. There are
+-two calls to do this dependent on how you decide to allocate the physical
+-media on which the journal resides. The journal_init_inode() call
+-is for journals stored in filesystem inodes, or the journal_init_dev()
+-call can be use for journal stored on a raw device (in a continuous range
+-of blocks). A journal_t is a typedef for a struct pointer, so when
+-you are finally finished make sure you call journal_destroy() on it
+-to free up any used kernel memory.
+-</para>
+-
+-<para>
+-Once you have got your journal_t object you need to 'mount' or load the journal
+-file, unless of course you haven't initialised it yet - in which case you
+-need to call journal_create().
+-</para>
+-
+-<para>
+-Most of the time however your journal file will already have been created, but
+-before you load it you must call journal_wipe() to empty the journal file.
+-Hang on, you say , what if the filesystem wasn't cleanly umount()'d . Well, it is the
+-job of the client file system to detect this and skip the call to journal_wipe().
+-</para>
+-
+-<para>
+-In either case the next call should be to journal_load() which prepares the
+-journal file for use. Note that journal_wipe(..,0) calls journal_skip_recovery()
+-for you if it detects any outstanding transactions in the journal and similarly
+-journal_load() will call journal_recover() if necessary.
+-I would advise reading fs/ext3/super.c for examples on this stage.
+-[RGG: Why is the journal_wipe() call necessary - doesn't this needlessly
+-complicate the API. Or isn't a good idea for the journal layer to hide
+-dirty mounts from the client fs]
+-</para>
+-
+-<para>
+-Now you can go ahead and start modifying the underlying
+-filesystem. Almost.
+-</para>
+-
+-
+-<para>
+-
+-You still need to actually journal your filesystem changes, this
+-is done by wrapping them into transactions. Additionally you
+-also need to wrap the modification of each of the buffers
+-with calls to the journal layer, so it knows what the modifications
+-you are actually making are. To do this use journal_start() which
+-returns a transaction handle.
+-</para>
+-
+-<para>
+-journal_start()
+-and its counterpart journal_stop(), which indicates the end of a transaction
+-are nestable calls, so you can reenter a transaction if necessary,
+-but remember you must call journal_stop() the same number of times as
+-journal_start() before the transaction is completed (or more accurately
+-leaves the update phase). Ext3/VFS makes use of this feature to simplify
+-quota support.
+-</para>
+-
+-<para>
+-Inside each transaction you need to wrap the modifications to the
+-individual buffers (blocks). Before you start to modify a buffer you
+-need to call journal_get_{create,write,undo}_access() as appropriate,
+-this allows the journalling layer to copy the unmodified data if it
+-needs to. After all the buffer may be part of a previously uncommitted
+-transaction.
+-At this point you are at last ready to modify a buffer, and once
+-you are have done so you need to call journal_dirty_{meta,}data().
+-Or if you've asked for access to a buffer you now know is now longer
+-required to be pushed back on the device you can call journal_forget()
+-in much the same way as you might have used bforget() in the past.
+-</para>
+-
+-<para>
+-A journal_flush() may be called at any time to commit and checkpoint
+-all your transactions.
+-</para>
+-
+-<para>
+-Then at umount time , in your put_super() (2.4) or write_super() (2.5)
+-you can then call journal_destroy() to clean up your in-core journal object.
+-</para>
+-
+-
+-<para>
+-Unfortunately there a couple of ways the journal layer can cause a deadlock.
+-The first thing to note is that each task can only have
+-a single outstanding transaction at any one time, remember nothing
+-commits until the outermost journal_stop(). This means
+-you must complete the transaction at the end of each file/inode/address
+-etc. operation you perform, so that the journalling system isn't re-entered
+-on another journal. Since transactions can't be nested/batched
+-across differing journals, and another filesystem other than
+-yours (say ext3) may be modified in a later syscall.
+-</para>
+-
+-<para>
+-The second case to bear in mind is that journal_start() can
+-block if there isn't enough space in the journal for your transaction
+-(based on the passed nblocks param) - when it blocks it merely(!) needs to
+-wait for transactions to complete and be committed from other tasks,
+-so essentially we are waiting for journal_stop(). So to avoid
+-deadlocks you must treat journal_start/stop() as if they
+-were semaphores and include them in your semaphore ordering rules to prevent
+-deadlocks. Note that journal_extend() has similar blocking behaviour to
+-journal_start() so you can deadlock here just as easily as on journal_start().
+-</para>
+-
+-<para>
+-Try to reserve the right number of blocks the first time. ;-). This will
+-be the maximum number of blocks you are going to touch in this transaction.
+-I advise having a look at at least ext3_jbd.h to see the basis on which
+-ext3 uses to make these decisions.
+-</para>
+-
+-<para>
+-Another wriggle to watch out for is your on-disk block allocation strategy.
+-why? Because, if you undo a delete, you need to ensure you haven't reused any
+-of the freed blocks in a later transaction. One simple way of doing this
+-is make sure any blocks you allocate only have checkpointed transactions
+-listed against them. Ext3 does this in ext3_test_allocatable().
+-</para>
+-
+-<para>
+-Lock is also providing through journal_{un,}lock_updates(),
+-ext3 uses this when it wants a window with a clean and stable fs for a moment.
+-eg.
+-</para>
+-
+-<programlisting>
+-
+- journal_lock_updates() //stop new stuff happening..
+- journal_flush() // checkpoint everything.
+- ..do stuff on stable fs
+- journal_unlock_updates() // carry on with filesystem use.
+-</programlisting>
+-
+-<para>
+-The opportunities for abuse and DOS attacks with this should be obvious,
+-if you allow unprivileged userspace to trigger codepaths containing these
+-calls.
+-</para>
+-
+-<para>
+-A new feature of jbd since 2.5.25 is commit callbacks with the new
+-journal_callback_set() function you can now ask the journalling layer
+-to call you back when the transaction is finally committed to disk, so that
+-you can do some of your own management. The key to this is the journal_callback
+-struct, this maintains the internal callback information but you can
+-extend it like this:-
+-</para>
+-<programlisting>
+- struct myfs_callback_s {
+- //Data structure element required by jbd..
+- struct journal_callback for_jbd;
+- // Stuff for myfs allocated together.
+- myfs_inode* i_commited;
+-
+- }
+-</programlisting>
+-
+-<para>
+-this would be useful if you needed to know when data was committed to a
+-particular inode.
+-</para>
+-
+-</sect1>
+-
+-<sect1>
+-<title>Summary</title>
+-<para>
+-Using the journal is a matter of wrapping the different context changes,
+-being each mount, each modification (transaction) and each changed buffer
+-to tell the journalling layer about them.
+-</para>
+-
+-<para>
+-Here is a some pseudo code to give you an idea of how it works, as
+-an example.
+-</para>
+-
+-<programlisting>
+- journal_t* my_jnrl = journal_create();
+- journal_init_{dev,inode}(jnrl,...)
+- if (clean) journal_wipe();
+- journal_load();
+-
+- foreach(transaction) { /*transactions must be
+- completed before
+- a syscall returns to
+- userspace*/
+-
+- handle_t * xct=journal_start(my_jnrl);
+- foreach(bh) {
+- journal_get_{create,write,undo}_access(xact,bh);
+- if ( myfs_modify(bh) ) { /* returns true
+- if makes changes */
+- journal_dirty_{meta,}data(xact,bh);
+- } else {
+- journal_forget(bh);
+- }
+- }
+- journal_stop(xct);
+- }
+- journal_destroy(my_jrnl);
+-</programlisting>
+-</sect1>
+-
+-</chapter>
+-
+- <chapter id="adt">
+- <title>Data Types</title>
+- <para>
+- The journalling layer uses typedefs to 'hide' the concrete definitions
+- of the structures used. As a client of the JBD layer you can
+- just rely on the using the pointer as a magic cookie of some sort.
+-
+- Obviously the hiding is not enforced as this is 'C'.
+- </para>
+- <sect1><title>Structures</title>
+-!Iinclude/linux/jbd.h
+- </sect1>
+-</chapter>
+-
+- <chapter id="calls">
+- <title>Functions</title>
+- <para>
+- The functions here are split into two groups those that
+- affect a journal as a whole, and those which are used to
+- manage transactions
+-</para>
+- <sect1><title>Journal Level</title>
+-!Efs/jbd/journal.c
+-!Ifs/jbd/recovery.c
+- </sect1>
+- <sect1><title>Transasction Level</title>
+-!Efs/jbd/transaction.c
+- </sect1>
+-</chapter>
+-<chapter>
+- <title>See also</title>
+- <para>
+- <citation>
+- <ulink url="ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/journal-design.ps.gz">
+- Journaling the Linux ext2fs Filesystem,LinuxExpo 98, Stephen Tweedie
+- </ulink>
+- </citation>
+- </para>
+- <para>
+- <citation>
+- <ulink url="http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html">
+- Ext3 Journalling FileSystem , OLS 2000, Dr. Stephen Tweedie
+- </ulink>
+- </citation>
+- </para>
+-</chapter>
+-
+-</book>
+diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
+index f8fe882..a166675 100644
+--- a/Documentation/DocBook/kernel-api.tmpl
++++ b/Documentation/DocBook/kernel-api.tmpl
+@@ -158,6 +158,7 @@ X!Ilib/string.c
+ !Emm/filemap.c
+ !Emm/memory.c
+ !Emm/vmalloc.c
++!Imm/page_alloc.c
+ !Emm/mempool.c
+ !Emm/page-writeback.c
+ !Emm/truncate.c
+@@ -181,56 +182,19 @@ X!Ilib/string.c
+ </sect1>
+ </chapter>
+
+- <chapter id="proc">
+- <title>The proc filesystem</title>
+-
+- <sect1><title>sysctl interface</title>
+-!Ekernel/sysctl.c
+- </sect1>
++ <chapter id="relayfs">
++ <title>relay interface support</title>
+
+- <sect1><title>proc filesystem interface</title>
+-!Ifs/proc/base.c
+- </sect1>
+- </chapter>
++ <para>
++ Relay interface support
++ is designed to provide an efficient mechanism for tools and
++ facilities to relay large amounts of data from kernel space to
++ user space.
++ </para>
+
+- <chapter id="debugfs">
+- <title>The debugfs filesystem</title>
+-
+- <sect1><title>debugfs interface</title>
+-!Efs/debugfs/inode.c
+-!Efs/debugfs/file.c
+- </sect1>
+- </chapter>
+-
+- <chapter id="vfs">
+- <title>The Linux VFS</title>
+- <sect1><title>The Filesystem types</title>
+-!Iinclude/linux/fs.h
+- </sect1>
+- <sect1><title>The Directory Cache</title>
+-!Efs/dcache.c
+-!Iinclude/linux/dcache.h
+- </sect1>
+- <sect1><title>Inode Handling</title>
+-!Efs/inode.c
+-!Efs/bad_inode.c
+- </sect1>
+- <sect1><title>Registration and Superblocks</title>
+-!Efs/super.c
+- </sect1>
+- <sect1><title>File Locks</title>
+-!Efs/locks.c
+-!Ifs/locks.c
+- </sect1>
+- <sect1><title>Other Functions</title>
+-!Efs/mpage.c
+-!Efs/namei.c
+-!Efs/buffer.c
+-!Efs/bio.c
+-!Efs/seq_file.c
+-!Efs/filesystems.c
+-!Efs/fs-writeback.c
+-!Efs/block_dev.c
++ <sect1><title>relay interface</title>
++!Ekernel/relay.c
++!Ikernel/relay.c
+ </sect1>
+ </chapter>
+
+@@ -302,8 +266,13 @@ X!Ekernel/module.c
+ !Ekernel/irq/manage.c
+ </sect1>
+
++ <sect1><title>DMA Channels</title>
++!Ekernel/dma.c
++ </sect1>
++
+ <sect1><title>Resources Management</title>
+ !Ikernel/resource.c
++!Ekernel/resource.c
+ </sect1>
+
+ <sect1><title>MTRR Handling</title>
+@@ -349,13 +318,6 @@ X!Earch/i386/kernel/mca.c
+ </sect1>
+ </chapter>
+
+- <chapter id="sysfs">
+- <title>The Filesystem for Exporting Kernel Objects</title>
+-!Efs/sysfs/file.c
+-!Efs/sysfs/symlink.c
+-!Efs/sysfs/bin.c
+- </chapter>
+-
+ <chapter id="security">
+ <title>Security Framework</title>
+ !Esecurity/security.c
+@@ -386,6 +348,7 @@ X!Iinclude/linux/device.h
+ -->
+ !Edrivers/base/driver.c
+ !Edrivers/base/core.c
++!Edrivers/base/class.c
+ !Edrivers/base/firmware_class.c
+ !Edrivers/base/transport_class.c
+ !Edrivers/base/dmapool.c
+@@ -437,6 +400,11 @@ X!Edrivers/pnp/system.c
+ !Eblock/ll_rw_blk.c
+ </chapter>
+
++ <chapter id="chrdev">
++ <title>Char devices</title>
++!Efs/char_dev.c
++ </chapter>
++
+ <chapter id="miscdev">
+ <title>Miscellaneous Devices</title>
+ !Edrivers/char/misc.c
+diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
+index e97c323..07a6355 100644
+--- a/Documentation/DocBook/libata.tmpl
++++ b/Documentation/DocBook/libata.tmpl
+@@ -14,7 +14,7 @@
+ </authorgroup>
+
+ <copyright>
+- <year>2003-2005</year>
++ <year>2003-2006</year>
+ <holder>Jeff Garzik</holder>
+ </copyright>
+
+@@ -868,18 +868,18 @@ and other resources, etc.
+
+ <chapter id="libataExt">
+ <title>libata Library</title>
+-!Edrivers/scsi/libata-core.c
++!Edrivers/ata/libata-core.c
+ </chapter>
+
+ <chapter id="libataInt">
+ <title>libata Core Internals</title>
+-!Idrivers/scsi/libata-core.c
++!Idrivers/ata/libata-core.c
+ </chapter>
+
+ <chapter id="libataScsiInt">
+ <title>libata SCSI translation/emulation</title>
+-!Edrivers/scsi/libata-scsi.c
+-!Idrivers/scsi/libata-scsi.c
++!Edrivers/ata/libata-scsi.c
++!Idrivers/ata/libata-scsi.c
+ </chapter>
+
+ <chapter id="ataExceptions">
+@@ -1400,7 +1400,7 @@ and other resources, etc.
+ <listitem>
+ <para>
+ When it's known that HBA is in ready state but ATA/ATAPI
+- device in in unknown state, reset only device.
++ device is in unknown state, reset only device.
+ </para>
+ </listitem>
+
+@@ -1600,12 +1600,12 @@ and other resources, etc.
+
+ <chapter id="PiixInt">
+ <title>ata_piix Internals</title>
+-!Idrivers/scsi/ata_piix.c
++!Idrivers/ata/ata_piix.c
+ </chapter>
+
+ <chapter id="SILInt">
+ <title>sata_sil Internals</title>
+-!Idrivers/scsi/sata_sil.c
++!Idrivers/ata/sata_sil.c
+ </chapter>
+
+ <chapter id="libataThanks">
+diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl
+index 320af25..143e5ff 100644
+--- a/Documentation/DocBook/usb.tmpl
++++ b/Documentation/DocBook/usb.tmpl
+@@ -43,59 +43,52 @@
+
+ <para>A Universal Serial Bus (USB) is used to connect a host,
+ such as a PC or workstation, to a number of peripheral
+- devices. USB uses a tree structure, with the host at the
++ devices. USB uses a tree structure, with the host as the
+ root (the system's master), hubs as interior nodes, and
+- peripheral devices as leaves (and slaves).
++ peripherals as leaves (and slaves).
+ Modern PCs support several such trees of USB devices, usually
+ one USB 2.0 tree (480 Mbit/sec each) with
+ a few USB 1.1 trees (12 Mbit/sec each) that are used when you
+ connect a USB 1.1 device directly to the machine's "root hub".
+ </para>
+
+- <para>That master/slave asymmetry was designed in part for
+- ease of use. It is not physically possible to assemble
+- (legal) USB cables incorrectly: all upstream "to-the-host"
+- connectors are the rectangular type, matching the sockets on
+- root hubs, and the downstream type are the squarish type
+- (or they are built in to the peripheral).
+- Software doesn't need to deal with distributed autoconfiguration
+- since the pre-designated master node manages all that.
+- At the electrical level, bus protocol overhead is reduced by
+- eliminating arbitration and moving scheduling into host software.
++ <para>That master/slave asymmetry was designed-in for a number of
++ reasons, one being ease of use. It is not physically possible to
++ assemble (legal) USB cables incorrectly: all upstream "to the host"
++ connectors are the rectangular type (matching the sockets on
++ root hubs), and all downstream connectors are the squarish type
++ (or they are built into the peripheral).
++ Also, the host software doesn't need to deal with distributed
++ auto-configuration since the pre-designated master node manages all that.
++ And finally, at the electrical level, bus protocol overhead is reduced by
++ eliminating arbitration and moving scheduling into the host software.
+ </para>
+
+- <para>USB 1.0 was announced in January 1996, and was revised
++ <para>USB 1.0 was announced in January 1996 and was revised
+ as USB 1.1 (with improvements in hub specification and
+ support for interrupt-out transfers) in September 1998.
+- USB 2.0 was released in April 2000, including high speed
+- transfers and transaction translating hubs (used for USB 1.1
++ USB 2.0 was released in April 2000, adding high-speed
++ transfers and transaction-translating hubs (used for USB 1.1
+ and 1.0 backward compatibility).
+ </para>
+
+- <para>USB support was added to Linux early in the 2.2 kernel series
+- shortly before the 2.3 development forked off. Updates
+- from 2.3 were regularly folded back into 2.2 releases, bringing
+- new features such as <filename>/sbin/hotplug</filename> support,
+- more drivers, and more robustness.
+- The 2.5 kernel series continued such improvements, and also
+- worked on USB 2.0 support,
+- higher performance,
+- better consistency between host controller drivers,
+- API simplification (to make bugs less likely),
+- and providing internal "kerneldoc" documentation.
++ <para>Kernel developers added USB support to Linux early in the 2.2 kernel
++ series, shortly before 2.3 development forked. Updates from 2.3 were
++ regularly folded back into 2.2 releases, which improved reliability and
++ brought <filename>/sbin/hotplug</filename> support as well more drivers.
++ Such improvements were continued in the 2.5 kernel series, where they added
++ USB 2.0 support, improved performance, and made the host controller drivers
++ (HCDs) more consistent. They also simplified the API (to make bugs less
++ likely) and added internal "kerneldoc" documentation.
+ </para>
+
+ <para>Linux can run inside USB devices as well as on
+ the hosts that control the devices.
+- Because the Linux 2.x USB support evolved to support mass market
+- platforms such as Apple Macintosh or PC-compatible systems,
+- it didn't address design concerns for those types of USB systems.
+- So it can't be used inside mass-market PDAs, or other peripherals.
+- USB device drivers running inside those Linux peripherals
++ But USB device drivers running inside those peripherals
+ don't do the same things as the ones running inside hosts,
+- and so they've been given a different name:
+- they're called <emphasis>gadget drivers</emphasis>.
+- This document does not present gadget drivers.
++ so they've been given a different name:
++ <emphasis>gadget drivers</emphasis>.
++ This document does not cover gadget drivers.
+ </para>
+
+ </chapter>
+@@ -103,17 +96,14 @@
+ <chapter id="host">
+ <title>USB Host-Side API Model</title>
+
+- <para>Within the kernel,
+- host-side drivers for USB devices talk to the "usbcore" APIs.
+- There are two types of public "usbcore" APIs, targetted at two different
+- layers of USB driver. Those are
+- <emphasis>general purpose</emphasis> drivers, exposed through
+- driver frameworks such as block, character, or network devices;
+- and drivers that are <emphasis>part of the core</emphasis>,
+- which are involved in managing a USB bus.
+- Such core drivers include the <emphasis>hub</emphasis> driver,
+- which manages trees of USB devices, and several different kinds
+- of <emphasis>host controller driver (HCD)</emphasis>,
++ <para>Host-side drivers for USB devices talk to the "usbcore" APIs.
++ There are two. One is intended for
++ <emphasis>general-purpose</emphasis> drivers (exposed through
++ driver frameworks), and the other is for drivers that are
++ <emphasis>part of the core</emphasis>.
++ Such core drivers include the <emphasis>hub</emphasis> driver
++ (which manages trees of USB devices) and several different kinds
++ of <emphasis>host controller drivers</emphasis>,
+ which control individual busses.
+ </para>
+
+@@ -122,21 +112,21 @@
+
+ <itemizedlist>
+
+- <listitem><para>USB supports four kinds of data transfer
+- (control, bulk, interrupt, and isochronous). Two transfer
+- types use bandwidth as it's available (control and bulk),
+- while the other two types of transfer (interrupt and isochronous)
++ <listitem><para>USB supports four kinds of data transfers
++ (control, bulk, interrupt, and isochronous). Two of them (control
++ and bulk) use bandwidth as it's available,
++ while the other two (interrupt and isochronous)
+ are scheduled to provide guaranteed bandwidth.
+ </para></listitem>
+
+ <listitem><para>The device description model includes one or more
+ "configurations" per device, only one of which is active at a time.
+- Devices that are capable of high speed operation must also support
+- full speed configurations, along with a way to ask about the
+- "other speed" configurations that might be used.
++ Devices that are capable of high-speed operation must also support
++ full-speed configurations, along with a way to ask about the
++ "other speed" configurations which might be used.
+ </para></listitem>
+
+- <listitem><para>Configurations have one or more "interface", each
++ <listitem><para>Configurations have one or more "interfaces", each
+ of which may have "alternate settings". Interfaces may be
+ standardized by USB "Class" specifications, or may be specific to
+ a vendor or device.</para>
+@@ -162,7 +152,7 @@
+ </para></listitem>
+
+ <listitem><para>The Linux USB API supports synchronous calls for
+- control and bulk messaging.
++ control and bulk messages.
+ It also supports asynchnous calls for all kinds of data transfer,
+ using request structures called "URBs" (USB Request Blocks).
+ </para></listitem>
+@@ -324,8 +314,7 @@
+ <emphasis>usbdevfs</emphasis> although it wasn't solving what
+ <emphasis>devfs</emphasis> was.
+ Every USB device will appear in usbfs, regardless of whether or
+- not it has a kernel driver; but only devices with kernel drivers
+- show up in devfs.
++ not it has a kernel driver.
+ </para>
+
+ <sect1>
+@@ -463,14 +452,25 @@
+ file in your Linux kernel sources.
+ </para>
+
+- <para>Otherwise the main use for this file from programs
+- is to poll() it to get notifications of usb devices
+- as they're plugged or unplugged.
+- To see what changed, you'd need to read the file and
+- compare "before" and "after" contents, scan the filesystem,
+- or see its hotplug event.
++ <para>This file, in combination with the poll() system call, can
++ also be used to detect when devices are added or removed:
++<programlisting>int fd;
++struct pollfd pfd;
++
++fd = open("/proc/bus/usb/devices", O_RDONLY);
++pfd = { fd, POLLIN, 0 };
++for (;;) {
++ /* The first time through, this call will return immediately. */
++ poll(&pfd, 1, -1);
++
++ /* To see what's changed, compare the file's previous and current
++ contents or scan the filesystem. (Scanning is more precise.) */
++}</programlisting>
++ Note that this behavior is intended to be used for informational
++ and debug purposes. It would be more appropriate to use programs
++ such as udev or HAL to initialize a device or start a user-mode
++ helper program, for instance.
+ </para>
+-
+ </sect1>
+
+ <sect1>
+@@ -740,7 +740,7 @@ usbdev_ioctl (int fd, int ifno, unsigned
+ <title>Synchronous I/O Support</title>
+
+ <para>Synchronous requests involve the kernel blocking
+- until until the user mode request completes, either by
++ until the user mode request completes, either by
+ finishing successfully or by reporting an error.
+ In most cases this is the simplest way to use usbfs,
+ although as noted above it does prevent performing I/O
+diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl
+index 008a341..07cd34c 100644
+--- a/Documentation/DocBook/writing_usb_driver.tmpl
++++ b/Documentation/DocBook/writing_usb_driver.tmpl
+@@ -224,13 +224,8 @@ static int skel_probe(struct usb_interfa
+ Conversely, when the device is removed from the USB bus, the disconnect
+ function is called with the device pointer. The driver needs to clean any
+ private data that has been allocated at this time and to shut down any
+- pending urbs that are in the USB system. The driver also unregisters
+- itself from the devfs subsystem with the call:
++ pending urbs that are in the USB system.
+ </para>
+- <programlisting>
+-/* remove our devfs node */
+-devfs_unregister(skel->devfs);
+- </programlisting>
+ <para>
+ Now that the device is plugged into the system and the driver is bound to
+ the device, any of the functions in the file_operations structure that
+diff --git a/Documentation/HOWTO b/Documentation/HOWTO
+index 915ae8c..8d51c14 100644
+--- a/Documentation/HOWTO
++++ b/Documentation/HOWTO
+@@ -358,7 +358,8 @@ Here is a list of some of the different
+ quilt trees:
+ - USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman <gregkh at suse.de>
+ kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+-
++ - x86-64, partly i386, Andi Kleen <ak at suse.de>
++ ftp.firstfloor.org:/pub/ak/x86_64/quilt/
+
+ Bug Reporting
+ -------------
+@@ -374,6 +375,46 @@ of information is needed by the kernel d
+ problem.
+
+
++Managing bug reports
++--------------------
++
++One of the best ways to put into practice your hacking skills is by fixing
++bugs reported by other people. Not only you will help to make the kernel
++more stable, you'll learn to fix real world problems and you will improve
++your skills, and other developers will be aware of your presence. Fixing
++bugs is one of the best ways to earn merit amongst the developers, because
++not many people like wasting time fixing other people's bugs.
++
++To work in the already reported bug reports, go to http://bugzilla.kernel.org.
++If you want to be advised of the future bug reports, you can subscribe to the
++bugme-new mailing list (only new bug reports are mailed here) or to the
++bugme-janitor mailing list (every change in the bugzilla is mailed here)
++
++ http://lists.osdl.org/mailman/listinfo/bugme-new
++ http://lists.osdl.org/mailman/listinfo/bugme-janitors
++
++
++
++Managing bug reports
++--------------------
++
++One of the best ways to put into practice your hacking skills is by fixing
++bugs reported by other people. Not only you will help to make the kernel
++more stable, you'll learn to fix real world problems and you will improve
++your skills, and other developers will be aware of your presence. Fixing
++bugs is one of the best ways to get merits among other developers, because
++not many people like wasting time fixing other people's bugs.
++
++To work in the already reported bug reports, go to http://bugzilla.kernel.org.
++If you want to be advised of the future bug reports, you can subscribe to the
++bugme-new mailing list (only new bug reports are mailed here) or to the
++bugme-janitor mailing list (every change in the bugzilla is mailed here)
++
++ http://lists.osdl.org/mailman/listinfo/bugme-new
++ http://lists.osdl.org/mailman/listinfo/bugme-janitors
++
++
++
+ Mailing lists
+ -------------
+
+diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
+index 0256805..0e3924e 100644
+--- a/Documentation/IPMI.txt
++++ b/Documentation/IPMI.txt
+@@ -326,9 +326,12 @@ for events, they will all receive all ev
+
+ For receiving commands, you have to individually register commands you
+ want to receive. Call ipmi_register_for_cmd() and supply the netfn
+-and command name for each command you want to receive. Only one user
+-may be registered for each netfn/cmd, but different users may register
+-for different commands.
++and command name for each command you want to receive. You also
++specify a bitmask of the channels you want to receive the command from
++(or use IPMI_CHAN_ALL for all channels if you don't care). Only one
++user may be registered for each netfn/cmd/channel, but different users
++may register for different commands, or the same command if the
++channel bitmasks do not overlap.
+
+ From userland, equivalent IOCTLs are provided to do these functions.
+
+@@ -361,6 +364,7 @@ You can change this at module load time
+ regspacings=<sp1>,<sp2>,... regsizes=<size1>,<size2>,...
+ regshifts=<shift1>,<shift2>,...
+ slave_addrs=<addr1>,<addr2>,...
++ force_kipmid=<enable1>,<enable2>,...
+
+ Each of these except si_trydefaults is a list, the first item for the
+ first interface, second item for the second interface, etc.
+@@ -406,7 +410,13 @@ The slave_addrs specifies the IPMI addre
+ usually 0x20 and the driver defaults to that, but in case it's not, it
+ can be specified when the driver starts up.
+
+-When compiled into the kernel, the addresses can be specified on the
++The force_ipmid parameter forcefully enables (if set to 1) or disables
++(if set to 0) the kernel IPMI daemon. Normally this is auto-detected
++by the driver, but systems with broken interrupts might need an enable,
++or users that don't want the daemon (don't need the performance, don't
++want the CPU hit) can disable it.
++
++When compiled into the kernel, the parameters can be specified on the
+ kernel command line as:
+
+ ipmi_si.type=<type1>,<type2>...
+@@ -416,6 +426,7 @@ kernel command line as:
+ ipmi_si.regsizes=<size1>,<size2>,...
+ ipmi_si.regshifts=<shift1>,<shift2>,...
+ ipmi_si.slave_addrs=<addr1>,<addr2>,...
++ ipmi_si.force_kipmid=<enable1>,<enable2>,...
+
+ It works the same as the module parameters of the same names.
+
+@@ -457,12 +468,12 @@ BMCs specified on the smb_addr line will
+ Setting smb_dbg_probe to 1 will enable debugging of the probing and
+ detection process for BMCs on the SMBusses.
+
+-Discovering the IPMI compilant BMC on the SMBus can cause devices
++Discovering the IPMI compliant BMC on the SMBus can cause devices
+ on the I2C bus to fail. The SMBus driver writes a "Get Device ID" IPMI
+ message as a block write to the I2C bus and waits for a response.
+ This action can be detrimental to some I2C devices. It is highly recommended
+ that the known I2c address be given to the SMBus driver in the smb_addr
+-parameter. The default adrress range will not be used when a smb_addr
++parameter. The default address range will not be used when a smb_addr
+ parameter is provided.
+
+ When compiled into the kernel, the addresses can be specified on the
+diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt
+index 3ec6c72..5c34910 100644
+--- a/Documentation/MSI-HOWTO.txt
++++ b/Documentation/MSI-HOWTO.txt
+@@ -267,7 +267,7 @@ y = The number of MSI capable devices po
+ vector reserved to avoid the case where some MSI-X capable
+ drivers may attempt to claim all available vector resources.
+
+-z = The number of MSI-X capable devices pupulated in the system.
++z = The number of MSI-X capable devices populated in the system.
+ This policy ensures that maximum (x - y) is distributed
+ evenly among MSI-X capable devices.
+
+@@ -470,7 +470,68 @@ LOC: 324553 325068
+ ERR: 0
+ MIS: 0
+
+-6. FAQ
++6. MSI quirks
++
++Several PCI chipsets or devices are known to not support MSI.
++The PCI stack provides 3 possible levels of MSI disabling:
++* on a single device
++* on all devices behind a specific bridge
++* globally
++
++6.1. Disabling MSI on a single device
++
++Under some circumstances, it might be required to disable MSI on a
++single device, It may be achived by either not calling pci_enable_msi()
++or all, or setting the pci_dev->no_msi flag before (most of the time
++in a quirk).
++
++6.2. Disabling MSI below a bridge
++
++The vast majority of MSI quirks are required by PCI bridges not
++being able to route MSI between busses. In this case, MSI have to be
++disabled on all devices behind this bridge. It is achieves by setting
++the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
++subordinate bus. There is no need to set the same flag on bridges that
++are below the broken brigde. When pci_enable_msi() is called to enable
++MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
++flag in all parent busses of the device.
++
++Some bridges actually support dynamic MSI support enabling/disabling
++by changing some bits in their PCI configuration space (especially
++the Hypertransport chipsets such as the nVidia nForce and Serverworks
++HT2000). It may then be required to update the NO_MSI flag on the
++corresponding devices in the sysfs hierarchy. To enable MSI support
++on device "0000:00:0e", do:
++
++ echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus
++
++To disable MSI support, echo 0 instead of 1. Note that it should be
++used with caution since changing this value might break interrupts.
++
++6.3. Disabling MSI globally
++
++Some extreme cases may require to disable MSI globally on the system.
++For now, the only known case is a Serverworks PCI-X chipsets (MSI are
++not supported on several busses that are not all connected to the
++chipset in the Linux PCI hierarchy). In the vast majority of other
++cases, disabling only behind a specific bridge is enough.
++
++For debugging purpose, the user may also pass pci=nomsi on the kernel
++command-line to explicitly disable MSI globally. But, once the appro-
++priate quirks are added to the kernel, this option should not be
++required anymore.
++
++6.4. Finding why MSI cannot be enabled on a device
++
++Assuming that MSI are not enabled on a device, you should look at
++dmesg to find messages that quirks may output when disabling MSI
++on some devices, some bridges or even globally.
++Then, lspci -t gives the list of bridges above a device. Reading
++/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI
++are enabled (1) or disabled (0). In 0 is found in a single bridge
++msi_bus file above the device, MSI cannot be enabled.
++
++7. FAQ
+
+ Q1. Are there any limitations on using the MSI?
+
+diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
+index 1d50cf0..f4dffad 100644
+--- a/Documentation/RCU/checklist.txt
++++ b/Documentation/RCU/checklist.txt
+@@ -221,3 +221,41 @@ over a rather long period of time, but i
+ disable irq on a given acquisition of that lock will result in
+ deadlock as soon as the RCU callback happens to interrupt that
+ acquisition's critical section.
++
++13. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu())
++ may only be invoked from process context. Unlike other forms of
++ RCU, it -is- permissible to block in an SRCU read-side critical
++ section (demarked by srcu_read_lock() and srcu_read_unlock()),
++ hence the "SRCU": "sleepable RCU". Please note that if you
++ don't need to sleep in read-side critical sections, you should
++ be using RCU rather than SRCU, because RCU is almost always
++ faster and easier to use than is SRCU.
++
++ Also unlike other forms of RCU, explicit initialization
++ and cleanup is required via init_srcu_struct() and
++ cleanup_srcu_struct(). These are passed a "struct srcu_struct"
++ that defines the scope of a given SRCU domain. Once initialized,
++ the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
++ and synchronize_srcu(). A given synchronize_srcu() waits only
++ for SRCU read-side critical sections governed by srcu_read_lock()
++ and srcu_read_unlock() calls that have been passd the same
++ srcu_struct. This property is what makes sleeping read-side
++ critical sections tolerable -- a given subsystem delays only
++ its own updates, not those of other subsystems using SRCU.
++ Therefore, SRCU is less prone to OOM the system than RCU would
++ be if RCU's read-side critical sections were permitted to
++ sleep.
++
++ The ability to sleep in read-side critical sections does not
++ come for free. First, corresponding srcu_read_lock() and
++ srcu_read_unlock() calls must be passed the same srcu_struct.
++ Second, grace-period-detection overhead is amortized only
++ over those updates sharing a given srcu_struct, rather than
++ being globally amortized as they are for other forms of RCU.
++ Therefore, SRCU should be used in preference to rw_semaphore
++ only in extremely read-intensive situations, or in situations
++ requiring SRCU's read-side deadlock immunity or low read-side
++ realtime latency.
++
++ Note that, rcu_assign_pointer() and rcu_dereference() relate to
++ SRCU just as they do to other forms of RCU.
+diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
+index 02e27bf..f84407c 100644
+--- a/Documentation/RCU/rcu.txt
++++ b/Documentation/RCU/rcu.txt
+@@ -45,7 +45,8 @@ o How can I see where RCU is currently u
+
+ Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
+ "rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
+- "synchronize_rcu", and "synchronize_net".
++ "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
++ "synchronize_net", and "synchronize_srcu".
+
+ o What guidelines should I follow when writing code that uses RCU?
+
+diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
+index a494859..25a3c3f 100644
+--- a/Documentation/RCU/torture.txt
++++ b/Documentation/RCU/torture.txt
+@@ -28,6 +28,15 @@ nreaders This is the number of RCU readi
+ To properly exercise RCU implementations with preemptible
+ read-side critical sections.
+
++nfakewriters This is the number of RCU fake writer threads to run. Fake
++ writer threads repeatedly use the synchronous "wait for
++ current readers" function of the interface selected by
++ torture_type, with a delay between calls to allow for various
++ different numbers of writers running in parallel.
++ nfakewriters defaults to 4, which provides enough parallelism
++ to trigger special cases caused by multiple writers, such as
++ the synchronize_srcu() early return optimization.
++
+ stat_interval The number of seconds between output of torture
+ statistics (via printk()). Regardless of the interval,
+ statistics are printed when the module is unloaded.
+@@ -44,9 +53,12 @@ test_no_idle_hz Whether or not to test t
+ a kernel that disables the scheduling-clock interrupt to
+ idle CPUs. Boolean parameter, "1" to test, "0" otherwise.
+
+-torture_type The type of RCU to test: "rcu" for the rcu_read_lock()
+- API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
+- for the "srcu_read_lock()" API.
++torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API,
++ "rcu_sync" for rcu_read_lock() with synchronous reclamation,
++ "rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for
++ rcu_read_lock_bh() with synchronous reclamation, "srcu" for
++ the "srcu_read_lock()" API, and "sched" for the use of
++ preempt_disable() together with synchronize_sched().
+
+ verbose Enable debug printk()s. Default is disabled.
+
+@@ -118,6 +130,21 @@ o "Free-Block Circulation": Shows the nu
+ as it is only incremented if a torture structure's counter
+ somehow gets incremented farther than it should.
+
++Different implementations of RCU can provide implementation-specific
++additional information. For example, SRCU provides the following:
++
++ srcu-torture: rtc: f8cf46a8 ver: 355 tfle: 0 rta: 356 rtaf: 0 rtf: 346 rtmbe: 0
++ srcu-torture: Reader Pipe: 559738 939 0 0 0 0 0 0 0 0 0
++ srcu-torture: Reader Batch: 560434 243 0 0 0 0 0 0 0 0
++ srcu-torture: Free-Block Circulation: 355 354 353 352 351 350 349 348 347 346 0
++ srcu-torture: per-CPU(idx=1): 0(0,1) 1(0,1) 2(0,0) 3(0,1)
++
++The first four lines are similar to those for RCU. The last line shows
++the per-CPU counter state. The numbers in parentheses are the values
++of the "old" and "current" counters for the corresponding CPU. The
++"idx" value maps the "old" and "current" values to the underlying array,
++and is useful for debugging.
++
+
+ USAGE
+
+diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
+index 318df44..e0d6d99 100644
+--- a/Documentation/RCU/whatisRCU.txt
++++ b/Documentation/RCU/whatisRCU.txt
+@@ -582,7 +582,7 @@ The rcu_read_lock() and rcu_read_unlock(
+ and release a global reader-writer lock. The synchronize_rcu()
+ primitive write-acquires this same lock, then immediately releases
+ it. This means that once synchronize_rcu() exits, all RCU read-side
+-critical sections that were in progress before synchonize_rcu() was
++critical sections that were in progress before synchronize_rcu() was
+ called are guaranteed to have completed -- there is no way that
+ synchronize_rcu() would have been able to write-acquire the lock
+ otherwise.
+@@ -750,7 +750,7 @@ Or, for those who prefer a side-by-side
+
+ Either way, the differences are quite small. Read-side locking moves
+ to rcu_read_lock() and rcu_read_unlock, update-side locking moves from
+-from a reader-writer lock to a simple spinlock, and a synchronize_rcu()
++a reader-writer lock to a simple spinlock, and a synchronize_rcu()
+ precedes the kfree().
+
+ However, there is one potential catch: the read-side and update-side
+@@ -778,6 +778,8 @@ Markers for RCU read-side critical secti
+ rcu_read_unlock
+ rcu_read_lock_bh
+ rcu_read_unlock_bh
++ srcu_read_lock
++ srcu_read_unlock
+
+ RCU pointer/list traversal:
+
+@@ -804,6 +806,7 @@ RCU grace period:
+ synchronize_net
+ synchronize_sched
+ synchronize_rcu
++ synchronize_srcu
+ call_rcu
+ call_rcu_bh
+
+diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
+index a10bfb6..7ac61f6 100644
+--- a/Documentation/SubmitChecklist
++++ b/Documentation/SubmitChecklist
+@@ -61,3 +61,8 @@ kernel patches.
+ Documentation/kernel-parameters.txt.
+
+ 18: All new module parameters are documented with MODULE_PARM_DESC()
++
++19: All new userspace interfaces are documented in Documentation/ABI/.
++ See Documentation/ABI/README for more information.
++
++20: Check that it all passes `make headers_check'.
+diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
+index 6bd30fd..58bead0 100644
+--- a/Documentation/SubmittingDrivers
++++ b/Documentation/SubmittingDrivers
+@@ -59,11 +59,11 @@ Copyright: The copyright owner must agre
+ are the same person/entity. If not, the name of
+ the person/entity authorizing use of GPL should be
+ listed in case it's necessary to verify the will of
+- the copright owner.
++ the copyright owner.
+
+ Interfaces: If your driver uses existing interfaces and behaves like
+ other drivers in the same class it will be much more likely
+- to be accepted than if it invents gratuitous new ones.
++ to be accepted than if it invents gratuitous new ones.
+ If you need to implement a common API over Linux and NT
+ drivers do it in userspace.
+
+@@ -88,7 +88,7 @@ Clarity: It helps if anyone can see how
+ it will go in the bitbucket.
+
+ Control: In general if there is active maintainance of a driver by
+- the author then patches will be redirected to them unless
++ the author then patches will be redirected to them unless
+ they are totally obvious and without need of checking.
+ If you want to be the contact and update point for the
+ driver it is a good idea to state this in the comments,
+@@ -100,7 +100,7 @@ What Criteria Do Not Determine Acceptanc
+ Vendor: Being the hardware vendor and maintaining the driver is
+ often a good thing. If there is a stable working driver from
+ other people already in the tree don't expect 'we are the
+- vendor' to get your driver chosen. Ideally work with the
++ vendor' to get your driver chosen. Ideally work with the
+ existing driver author to build a single perfect driver.
+
+ Author: It doesn't matter if a large Linux company wrote the driver,
+@@ -116,17 +116,13 @@ Linux kernel master tree:
+ ftp.??.kernel.org:/pub/linux/kernel/...
+ ?? == your country code, such as "us", "uk", "fr", etc.
+
+-Linux kernel mailing list:
++Linux kernel mailing list:
+ linux-kernel at vger.kernel.org
+ [mail majordomo at vger.kernel.org to subscribe]
+
+ Linux Device Drivers, Third Edition (covers 2.6.10):
+ http://lwn.net/Kernel/LDD3/ (free version)
+
+-Kernel traffic:
+- Weekly summary of kernel list activity (much easier to read)
+- http://www.kerneltraffic.org/kernel-traffic/
+-
+ LWN.net:
+ Weekly summary of kernel development activity - http://lwn.net/
+ 2.6 API changes:
+@@ -145,11 +141,8 @@ KernelNewbies:
+ Linux USB project:
+ http://www.linux-usb.org/
+
+-How to NOT write kernel driver by arjanv at redhat.com
+- http://people.redhat.com/arjanv/olspaper.pdf
++How to NOT write kernel driver by Arjan van de Ven:
++ http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
+
+ Kernel Janitor:
+ http://janitor.kernelnewbies.org/
+-
+---
+-Last updated on 17 Nov 2005.
+diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
+index d42ab4c..302d148 100644
+--- a/Documentation/SubmittingPatches
++++ b/Documentation/SubmittingPatches
+@@ -173,15 +173,15 @@ For small patches you may want to CC the
+ trivial at kernel.org managed by Adrian Bunk; 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).
++ 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).
++ 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
++ 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/bunk/trivial/>
+
+@@ -209,6 +209,19 @@ Exception: If your mailer is mangling p
+ you to re-send them using MIME.
+
+
++WARNING: Some mailers like Mozilla send your messages with
++---- message header ----
++Content-Type: text/plain; charset=us-ascii; format=flowed
++---- message header ----
++The problem is that "format=flowed" makes some of the mailers
++on receiving side to replace TABs with spaces and do similar
++changes. Thus the patches from you can look corrupted.
++
++To fix this just make your mozilla defaults/pref/mailnews.js file to look like:
++pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
++pref("mailnews.display.disable_format_flowed_support", true);
++
++
+
+ 7) E-mail size.
+
+@@ -245,13 +258,13 @@ updated change.
+ It is quite common for Linus to "drop" your patch without comment.
+ That's the nature of the system. If he drops your patch, it could be
+ due to
+-* Your patch did not apply cleanly to the latest kernel version
++* Your patch did not apply cleanly to the latest kernel version.
+ * Your patch was not sufficiently discussed on linux-kernel.
+-* A style issue (see section 2),
+-* An e-mail formatting issue (re-read this section)
+-* A technical problem with your change
+-* He gets tons of e-mail, and yours got lost in the shuffle
+-* You are being annoying (See Figure 1)
++* A style issue (see section 2).
++* An e-mail formatting issue (re-read this section).
++* A technical problem with your change.
++* He gets tons of e-mail, and yours got lost in the shuffle.
++* You are being annoying.
+
+ When in doubt, solicit comments on linux-kernel mailing list.
+
+@@ -476,10 +489,10 @@ SECTION 3 - REFERENCES
+ Andrew Morton, "The perfect patch" (tpp).
+ <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+
+-Jeff Garzik, "Linux kernel patch submission format."
++Jeff Garzik, "Linux kernel patch submission format".
+ <http://linux.yyz.us/patch-format.html>
+
+-Greg Kroah-Hartman "How to piss off a kernel subsystem maintainer".
++Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
+ <http://www.kroah.com/log/2005/03/31/>
+ <http://www.kroah.com/log/2005/07/08/>
+ <http://www.kroah.com/log/2005/10/19/>
+@@ -488,9 +501,9 @@ Greg Kroah-Hartman "How to piss off a ke
+ NO!!!! No more huge patch bombs to linux-kernel at vger.kernel.org people!
+ <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+
+-Kernel Documentation/CodingStyle
++Kernel Documentation/CodingStyle:
+ <http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
+
+-Linus Torvald's mail on the canonical patch format:
++Linus Torvalds's mail on the canonical patch format:
+ <http://lkml.org/lkml/2005/4/7/183>
+ --
+diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
+index 795ca39..bf2b0e2 100644
+--- a/Documentation/accounting/getdelays.c
++++ b/Documentation/accounting/getdelays.c
+@@ -49,7 +49,7 @@ __u64 stime, utime;
+ }
+
+ /* Maximum size of response requested or message sent */
+-#define MAX_MSG_SIZE 256
++#define MAX_MSG_SIZE 1024
+ /* Maximum number of cpus expected to be specified in a cpumask */
+ #define MAX_CPUS 32
+ /* Maximum length of pathname to log file */
+@@ -285,7 +285,7 @@ int main(int argc, char *argv[])
+ if (maskset) {
+ rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
+ TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
+- &cpumask, sizeof(cpumask));
++ &cpumask, strlen(cpumask) + 1);
+ PRINTF("Sent register cpumask, retval %d\n", rc);
+ if (rc < 0) {
+ printf("error sending register cpumask\n");
+@@ -315,7 +315,8 @@ int main(int argc, char *argv[])
+ }
+ if (msg.n.nlmsg_type == NLMSG_ERROR ||
+ !NLMSG_OK((&msg.n), rep_len)) {
+- printf("fatal reply error, errno %d\n", errno);
++ struct nlmsgerr *err = NLMSG_DATA(&msg);
++ printf("fatal reply error, errno %d\n", err->error);
+ goto done;
+ }
+
+@@ -383,7 +384,7 @@ done:
+ if (maskset) {
+ rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
+ TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
+- &cpumask, sizeof(cpumask));
++ &cpumask, strlen(cpumask) + 1);
+ printf("Sent deregister mask, retval %d\n", rc);
+ if (rc < 0)
+ err(rc, "error sending deregister cpumask\n");
+diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt
+new file mode 100644
+index 0000000..661c797
+--- /dev/null
++++ b/Documentation/accounting/taskstats-struct.txt
+@@ -0,0 +1,161 @@
++The struct taskstats
++--------------------
++
++This document contains an explanation of the struct taskstats fields.
++
++There are three different groups of fields in the struct taskstats:
++
++1) Common and basic accounting fields
++ If CONFIG_TASKSTATS is set, the taskstats inteface is enabled and
++ the common fields and basic accounting fields are collected for
++ delivery at do_exit() of a task.
++2) Delay accounting fields
++ These fields are placed between
++ /* Delay accounting fields start */
++ and
++ /* Delay accounting fields end */
++ Their values are collected if CONFIG_TASK_DELAY_ACCT is set.
++3) Extended accounting fields
++ These fields are placed between
++ /* Extended accounting fields start */
++ and
++ /* Extended accounting fields end */
++ Their values are collected if CONFIG_TASK_XACCT is set.
++
++Future extension should add fields to the end of the taskstats struct, and
++should not change the relative position of each field within the struct.
++
++
++struct taskstats {
++
++1) Common and basic accounting fields:
++ /* The version number of this struct. This field is always set to
++ * TAKSTATS_VERSION, which is defined in <linux/taskstats.h>.
++ * Each time the struct is changed, the value should be incremented.
++ */
++ __u16 version;
++
++ /* The exit code of a task. */
++ __u32 ac_exitcode; /* Exit status */
++
++ /* The accounting flags of a task as defined in <linux/acct.h>
++ * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG.
++ */
++ __u8 ac_flag; /* Record flags */
++
++ /* The value of task_nice() of a task. */
++ __u8 ac_nice; /* task_nice */
++
++ /* The name of the command that started this task. */
++ char ac_comm[TS_COMM_LEN]; /* Command name */
++
++ /* The scheduling discipline as set in task->policy field. */
++ __u8 ac_sched; /* Scheduling discipline */
++
++ __u8 ac_pad[3];
++ __u32 ac_uid; /* User ID */
++ __u32 ac_gid; /* Group ID */
++ __u32 ac_pid; /* Process ID */
++ __u32 ac_ppid; /* Parent process ID */
++
++ /* The time when a task begins, in [secs] since 1970. */
++ __u32 ac_btime; /* Begin time [sec since 1970] */
++
++ /* The elapsed time of a task, in [usec]. */
++ __u64 ac_etime; /* Elapsed time [usec] */
++
++ /* The user CPU time of a task, in [usec]. */
++ __u64 ac_utime; /* User CPU time [usec] */
++
++ /* The system CPU time of a task, in [usec]. */
++ __u64 ac_stime; /* System CPU time [usec] */
++
++ /* The minor page fault count of a task, as set in task->min_flt. */
++ __u64 ac_minflt; /* Minor Page Fault Count */
++
++ /* The major page fault count of a task, as set in task->maj_flt. */
++ __u64 ac_majflt; /* Major Page Fault Count */
++
++
++2) Delay accounting fields:
++ /* Delay accounting fields start
++ *
++ * All values, until the comment "Delay accounting fields end" are
++ * available only if delay accounting is enabled, even though the last
++ * few fields are not delays
++ *
++ * xxx_count is the number of delay values recorded
++ * xxx_delay_total is the corresponding cumulative delay in nanoseconds
++ *
++ * xxx_delay_total wraps around to zero on overflow
++ * xxx_count incremented regardless of overflow
++ */
++
++ /* Delay waiting for cpu, while runnable
++ * count, delay_total NOT updated atomically
++ */
++ __u64 cpu_count;
++ __u64 cpu_delay_total;
++
++ /* Following four fields atomically updated using task->delays->lock */
++
++ /* Delay waiting for synchronous block I/O to complete
++ * does not account for delays in I/O submission
++ */
++ __u64 blkio_count;
++ __u64 blkio_delay_total;
++
++ /* Delay waiting for page fault I/O (swap in only) */
++ __u64 swapin_count;
++ __u64 swapin_delay_total;
++
++ /* cpu "wall-clock" running time
++ * On some architectures, value will adjust for cpu time stolen
++ * from the kernel in involuntary waits due to virtualization.
++ * Value is cumulative, in nanoseconds, without a corresponding count
++ * and wraps around to zero silently on overflow
++ */
++ __u64 cpu_run_real_total;
++
++ /* cpu "virtual" running time
++ * Uses time intervals seen by the kernel i.e. no adjustment
++ * for kernel's involuntary waits due to virtualization.
++ * Value is cumulative, in nanoseconds, without a corresponding count
++ * and wraps around to zero silently on overflow
++ */
++ __u64 cpu_run_virtual_total;
++ /* Delay accounting fields end */
++ /* version 1 ends here */
++
++
++3) Extended accounting fields
++ /* Extended accounting fields start */
++
++ /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
++ * The current rss usage is added to this counter every time
++ * a tick is charged to a task's system time. So, at the end we
++ * will have memory usage multiplied by system time. Thus an
++ * average usage per system time unit can be calculated.
++ */
++ __u64 coremem; /* accumulated RSS usage in MB-usec */
++
++ /* Accumulated virtual memory usage in duration of a task.
++ * Same as acct_rss_mem1 above except that we keep track of VM usage.
++ */
++ __u64 virtmem; /* accumulated VM usage in MB-usec */
++
++ /* High watermark of RSS usage in duration of a task, in KBytes. */
++ __u64 hiwater_rss; /* High-watermark of RSS usage */
++
++ /* High watermark of VM usage in duration of a task, in KBytes. */
++ __u64 hiwater_vm; /* High-water virtual memory usage */
++
++ /* The following four fields are I/O statistics of a task. */
++ __u64 read_char; /* bytes read */
++ __u64 write_char; /* bytes written */
++ __u64 read_syscalls; /* read syscalls */
++ __u64 write_syscalls; /* write syscalls */
++
++ /* Extended accounting fields end */
++
++}
+diff --git a/Documentation/aoe/todo.txt b/Documentation/aoe/todo.txt
+index 7fee1e1..c09dfad 100644
+--- a/Documentation/aoe/todo.txt
++++ b/Documentation/aoe/todo.txt
+@@ -7,7 +7,7 @@ not been observed, but it would be nice
+ deadlock under memory pressure.
+
+ Because ATA over Ethernet is not fragmented by the kernel's IP code,
+-the destructore member of the struct sk_buff is available to the aoe
++the destructor member of the struct sk_buff is available to the aoe
+ driver. By using a mempool for allocating all but the first few
+ sk_buffs, and by registering a destructor, we should be able to
+ efficiently allocate sk_buffs without introducing any potential for
+diff --git a/Documentation/arm/SA1100/serial_UART b/Documentation/arm/SA1100/serial_UART
+index aea2e91..a63966f 100644
+--- a/Documentation/arm/SA1100/serial_UART
++++ b/Documentation/arm/SA1100/serial_UART
+@@ -24,8 +24,8 @@ The SA1100 serial port had its major/min
+ > 7 = /dev/cusa2 Callout device for ttySA2
+ >
+
+-If you're not using devfs, you must create those inodes in /dev
+-on the root filesystem used by your SA1100-based device:
++You must create those inodes in /dev on the root filesystem used
++by your SA1100-based device:
+
+ mknod ttySA0 c 204 5
+ mknod ttySA1 c 204 6
+diff --git a/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt b/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
+index 000e3d7..26422f0 100644
+--- a/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
++++ b/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
+@@ -38,7 +38,7 @@ MTD
+ ---
+
+ The NAND and NOR support has been merged from the linux-mtd project.
+- Any prolbems, see http://www.linux-mtd.infradead.org/ for more
++ Any problems, see http://www.linux-mtd.infradead.org/ for more
+ information or up-to-date versions of linux-mtd.
+
+
+diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
+index 0822764..8caea8c 100644
+--- a/Documentation/arm/Samsung-S3C24XX/GPIO.txt
++++ b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
+@@ -24,7 +24,7 @@ Headers
+ header include/asm-arm/arch-s3c2410/hardware.h which can be
+ included by #include <asm/arch/hardware.h>
+
+- A useful ammount of documentation can be found in the hardware
++ A useful amount of documentation can be found in the hardware
+ header on how the GPIO functions (and others) work.
+
+ Whilst a number of these functions do make some checks on what
+diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
+index 3e46d2a..dda7ecd 100644
+--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
++++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
+@@ -80,7 +80,7 @@ Machines
+ Adding New Machines
+ -------------------
+
+- The archicture has been designed to support as many machines as can
++ The architecture has been designed to support as many machines as can
+ be configured for it in one kernel build, and any future additions
+ should keep this in mind before altering items outside of their own
+ machine files.
+diff --git a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
+index cb82a7f..295d971 100644
+--- a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
++++ b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
+@@ -80,7 +80,7 @@ RTC
+ Watchdog
+ --------
+
+- The watchdog harware is the same as the S3C2410, and is supported by
++ The watchdog hardware is the same as the S3C2410, and is supported by
+ the s3c2410_wdt driver.
+
+
+diff --git a/Documentation/block/as-iosched.txt b/Documentation/block/as-iosched.txt
+index 6f47332..e2a66f8 100644
+--- a/Documentation/block/as-iosched.txt
++++ b/Documentation/block/as-iosched.txt
+@@ -99,8 +99,8 @@ contrast, many write requests may be dis
+ at a time during a write batch. It is this characteristic that can make
+ the anticipatory scheduler perform anomalously with controllers supporting
+ TCQ, or with hardware striped RAID devices. Setting the antic_expire
+-queue paramter (see below) to zero disables this behavior, and the anticipatory
+-scheduler behaves essentially like the deadline scheduler.
++queue parameter (see below) to zero disables this behavior, and the
++anticipatory scheduler behaves essentially like the deadline scheduler.
+
+ When read anticipation is enabled (antic_expire is not zero), reads
+ are dispatched to the disk controller one at a time.
+diff --git a/Documentation/block/barrier.txt b/Documentation/block/barrier.txt
+index 0397151..a272c3d 100644
+--- a/Documentation/block/barrier.txt
++++ b/Documentation/block/barrier.txt
+@@ -25,7 +25,7 @@ of the following three ways.
+ i. For devices which have queue depth greater than 1 (TCQ devices) and
+ support ordered tags, block layer can just issue the barrier as an
+ ordered request and the lower level driver, controller and drive
+-itself are responsible for making sure that the ordering contraint is
++itself are responsible for making sure that the ordering constraint is
+ met. Most modern SCSI controllers/drives should support this.
+
+ NOTE: SCSI ordered tag isn't currently used due to limitation in the
+@@ -42,7 +42,7 @@ iii. Devices which have queue depth of 1
+ of ii. Just keeping issue order suffices. Ancient SCSI
+ controllers/drives and IDE drives are in this category.
+
+-2. Forced flushing to physcial medium
++2. Forced flushing to physical medium
+
+ Again, if you're not gonna do synchronization with disk drives (dang,
+ it sounds even more appealing now!), the reason you use I/O barriers
+@@ -56,7 +56,7 @@ There are four cases,
+ i. No write-back cache. Keeping requests ordered is enough.
+
+ ii. Write-back cache but no flush operation. There's no way to
+-gurantee physical-medium commit order. This kind of devices can't to
++guarantee physical-medium commit order. This kind of devices can't to
+ I/O barriers.
+
+ iii. Write-back cache and flush operation but no FUA (forced unit
+diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
+index f989a9e..34bf8f6 100644
+--- a/Documentation/block/biodoc.txt
++++ b/Documentation/block/biodoc.txt
+@@ -135,7 +135,7 @@ Some new queue property settings:
+ Sets two variables that limit the size of the request.
+
+ - The request queue's max_sectors, which is a soft size in
+- in units of 512 byte sectors, and could be dynamically varied
++ units of 512 byte sectors, and could be dynamically varied
+ by the core kernel.
+
+ - The request queue's max_hw_sectors, which is a hard limit
+@@ -783,7 +783,7 @@ all the outstanding requests. There's a
+
+ blk_queue_invalidate_tags(request_queue_t *q)
+
+- Clear the internal block tag queue and readd all the pending requests
++ Clear the internal block tag queue and re-add all the pending requests
+ to the request queue. The driver will receive them again on the
+ next request_fn run, just like it did the first time it encountered
+ them.
+@@ -890,7 +890,7 @@ Aside:
+
+ Kvec i/o:
+
+- Ben LaHaise's aio code uses a slighly different structure instead
++ Ben LaHaise's aio code uses a slightly different structure instead
+ of kiobufs, called a kvec_cb. This contains an array of <page, offset, len>
+ tuples (very much like the networking code), together with a callback function
+ and data pointer. This is embedded into a brw_cb structure when passed
+@@ -988,7 +988,7 @@ elevator_exit_fn Allocate and free any
+ for a queue.
+
+ 4.2 Request flows seen by I/O schedulers
+-All requests seens by I/O schedulers strictly follow one of the following three
++All requests seen by I/O schedulers strictly follow one of the following three
+ flows.
+
+ set_req_fn ->
+@@ -1203,6 +1203,6 @@ temporarily map a bio into the virtual a
+ and Linus' comments - Jan 2001)
+ 9.2 Discussions about kiobuf and bh design on lkml between sct, linus, alan
+ et al - Feb-March 2001 (many of the initial thoughts that led to bio were
+-brought up in this discusion thread)
++brought up in this discussion thread)
+ 9.3 Discussions on mempool on lkml - Dec 2001.
+
+diff --git a/Documentation/block/deadline-iosched.txt b/Documentation/block/deadline-iosched.txt
+index c918b3a..be08ffd 100644
+--- a/Documentation/block/deadline-iosched.txt
++++ b/Documentation/block/deadline-iosched.txt
+@@ -23,11 +23,11 @@ you can do so by typing:
+ read_expire (in ms)
+ -----------
+
+-The goal of the deadline io scheduler is to attempt to guarentee a start
++The goal of the deadline io scheduler is to attempt to guarantee a start
+ service time for a request. As we focus mainly on read latencies, this is
+ tunable. When a read request first enters the io scheduler, it is assigned
+ a deadline that is the current time + the read_expire value in units of
+-miliseconds.
++milliseconds.
+
+
+ write_expire (in ms)
+diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
+index 9c629ff..f74affe 100644
+--- a/Documentation/cciss.txt
++++ b/Documentation/cciss.txt
+@@ -80,7 +80,7 @@ the /proc filesystem entry which the "bl
+ the SCSI core may not yet be initialized (because the driver is a block
+ driver) and attempting to register it with the SCSI core in such a case
+ would cause a hang. This is best done via an initialization script
+-(typically in /etc/init.d, but could vary depending on distibution).
++(typically in /etc/init.d, but could vary depending on distribution).
+ For example:
+
+ for x in /proc/driver/cciss/cciss[0-9]*
+@@ -152,7 +152,7 @@ side during the SCSI error recovery proc
+ implements the first two of these actions, aborting the command, and
+ resetting the device. Additionally, most tape drives will not oblige
+ in aborting commands, and sometimes it appears they will not even
+-obey a reset coommand, though in most circumstances they will. In
++obey a reset command, though in most circumstances they will. In
+ the case that the command cannot be aborted and the device cannot be
+ reset, the device will be set offline.
+
+diff --git a/Documentation/computone.txt b/Documentation/computone.txt
+index b1cf59b..5e2a0c7 100644
+--- a/Documentation/computone.txt
++++ b/Documentation/computone.txt
+@@ -199,30 +199,6 @@ boxes this will leave gaps in the sequen
+ Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
+ cuf0 - cuf255 for callout devices.
+
+-If you are using devfs, existing devices are automatically created within
+-the devfs name space. Normal devices will be tts/F0 - tts/F255 and callout
+-devices will be cua/F0 - cua/F255. With devfs installed, ip2mkdev will
+-create symbolic links in /dev from the old conventional names to the newer
+-devfs names as follows:
+-
+- /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3
+- /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3
+- /dev/ttyF[n] -> /dev/tts/F[n] n = 0 - 255
+- /dev/cuf[n] -> /dev/cua/F[n] n = 0 - 255
+-
+-Only devices for existing ports and boards will be created.
+-
+-IMPORTANT NOTE: The naming convention used for devfs by this driver
+-was changed from 1.2.12 to 1.2.13. The old naming convention was to
+-use ttf/%d for the tty device and cuf/%d for the cua device. That
+-has been changed to conform to an agreed-upon standard of placing
+-all the tty devices under tts. The device names are now tts/F%d for
+-the tty device and cua/F%d for the cua devices. If you were using
+-the older devfs names, you must update for the newer convention.
+-
+-You do not need to run ip2mkdev if you are using devfs and only want to
+-use the devfs native device names.
+-
+
+ 4. USING THE DRIVERS
+
+@@ -256,57 +232,15 @@ cut out and run as "ip2mkdev" to create
+ use the ip2mkdev script, you must have procfs enabled and the proc file
+ system mounted on /proc.
+
+-You do not need to run ip2mkdev if you are using devfs and only want to
+-use the devfs native device names.
+-
+-
+-6. DEVFS
+-
+-DEVFS is the DEVice File System available as an add on package for the
+-2.2.x kernels and available as a configuration option in 2.3.46 and higher.
+-Devfs allows for the automatic creation and management of device names
+-under control of the device drivers themselves. The Devfs namespace is
+-hierarchical and reduces the clutter present in the normal flat /dev
+-namespace. Devfs names and conventional device names may be intermixed.
+-A userspace daemon, devfsd, exists to allow for automatic creation and
+-management of symbolic links from the devfs name space to the conventional
+-names. More details on devfs can be found on the DEVFS home site at
+-<http://www.atnf.csiro.au/~rgooch/linux/> or in the file kernel
+-documentation files, .../linux/Documentation/filesystems/devfs/README.
+-
+-If you are using devfs, existing devices are automatically created within
+-the devfs name space. Normal devices will be tts/F0 - tts/F255 and callout
+-devices will be cua/F0 - cua/F255. With devfs installed, ip2mkdev will
+-create symbolic links in /dev from the old conventional names to the newer
+-devfs names as follows:
+-
+- /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3
+- /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3
+- /dev/ttyF[n] -> /dev/tts/F[n] n = 0 - 255
+- /dev/cuf[n] -> /dev/cua/F[n] n = 0 - 255
+-
+-Only devices for existing ports and boards will be created.
+-
+-IMPORTANT NOTE: The naming convention used for devfs by this driver
+-was changed from 1.2.12 to 1.2.13. The old naming convention was to
+-use ttf/%d for the tty device and cuf/%d for the cua device. That
+-has been changed to conform to an agreed-upon standard of placing
+-all the tty devices under tts. The device names are now tts/F%d for
+-the tty device and cua/F%d for the cua devices. If you were using
+-the older devfs names, you must update for the newer convention.
+-
+-You do not need to run ip2mkdev if you are using devfs and only want to
+-use the devfs native device names.
+-
+
+-7. NOTES
++6. NOTES
+
+ This is a release version of the driver, but it is impossible to test it
+ in all configurations of Linux. If there is any anomalous behaviour that
+ does not match the standard serial port's behaviour please let us know.
+
+
+-8. ip2mkdev shell script
++7. ip2mkdev shell script
+
+ Previously, this script was simply attached here. It is now attached as a
+ shar archive to make it easier to extract the script from the documentation.
+diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt
+index 6a82948..53d62c1 100644
+--- a/Documentation/cpu-freq/cpufreq-stats.txt
++++ b/Documentation/cpu-freq/cpufreq-stats.txt
+@@ -1,5 +1,5 @@
+
+- CPU frequency and voltage scaling statictics in the Linux(TM) kernel
++ CPU frequency and voltage scaling statistics in the Linux(TM) kernel
+
+
+ L i n u x c p u f r e q - s t a t s d r i v e r
+@@ -18,8 +18,8 @@ Contents
+ 1. Introduction
+
+ cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
+-This statistics is provided in /sysfs as a bunch of read_only interfaces. This
+-interface (when configured) will appear in a seperate directory under cpufreq
++These statistics are provided in /sysfs as a bunch of read_only interfaces. This
++interface (when configured) will appear in a separate directory under cpufreq
+ in /sysfs (<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU.
+ Various statistics will form read_only files under this directory.
+
+@@ -53,7 +53,7 @@ drwxr-xr-x 3 root root 0 May 14 15:5
+ This gives the amount of time spent in each of the frequencies supported by
+ this CPU. The cat output will have "<frequency> <time>" pair in each line, which
+ will mean this CPU spent <time> usertime units of time at <frequency>. Output
+-will have one line for each of the supported freuencies. usertime units here
++will have one line for each of the supported frequencies. usertime units here
+ is 10mS (similar to other time exported in /proc).
+
+ --------------------------------------------------------------------------------
+@@ -115,7 +115,7 @@ basic statistics which includes time_in_
+
+ "CPU frequency translation statistics details" (CONFIG_CPU_FREQ_STAT_DETAILS)
+ provides fine grained cpufreq stats by trans_table. The reason for having a
+-seperate config option for trans_table is:
++separate config option for trans_table is:
+ - trans_table goes against the traditional /sysfs rule of one value per
+ interface. It provides a whole bunch of value in a 2 dimensional matrix
+ form.
+diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
+index f4b8dc4..6a9c55b 100644
+--- a/Documentation/cpu-freq/governors.txt
++++ b/Documentation/cpu-freq/governors.txt
+@@ -57,7 +57,7 @@ selected for each specific use.
+
+ Basically, it's the following flow graph:
+
+-CPU can be set to switch independetly | CPU can only be set
++CPU can be set to switch independently | CPU can only be set
+ within specific "limits" | to specific frequencies
+
+ "CPUfreq policy"
+@@ -109,7 +109,7 @@ directory.
+ 2.4 Ondemand
+ ------------
+
+-The CPUfreq govenor "ondemand" sets the CPU depending on the
++The CPUfreq governor "ondemand" sets the CPU depending on the
+ current usage. To do this the CPU must have the capability to
+ switch the frequency very quickly. There are a number of sysfs file
+ accessible parameters:
+@@ -137,11 +137,11 @@ have to be made in a row before the CPU
+ If set to '1' then the frequency decreases as quickly as it increases,
+ if set to '2' it decreases at half the rate of the increase.
+
+-ignore_nice_load: this parameter takes a value of '0' or '1', when set
+-to '0' (its default) then all processes are counted towards towards the
+-'cpu utilisation' value. When set to '1' then processes that are
++ignore_nice_load: this parameter takes a value of '0' or '1'. When
++set to '0' (its default), all processes are counted towards the
++'cpu utilisation' value. When set to '1', the processes that are
+ run with a 'nice' value will not count (and thus be ignored) in the
+-overal usage calculation. This is useful if you are running a CPU
++overall usage calculation. This is useful if you are running a CPU
+ intensive calculation on your laptop that you do not care how long it
+ takes to complete as you can 'nice' it and prevent it from taking part
+ in the deciding process of whether to increase your CPU frequency.
+diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
+index bc107cb..4868c34 100644
+--- a/Documentation/cpu-hotplug.txt
++++ b/Documentation/cpu-hotplug.txt
+@@ -46,7 +46,7 @@ maxcpus=n Restrict boot time cpus to
+ maxcpus=2 will only boot 2. You can choose to bring the
+ other cpus later online, read FAQ's for more info.
+
+-additional_cpus*=n Use this to limit hotpluggable cpus. This option sets
++additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets
+ cpu_possible_map = cpu_present_map + additional_cpus
+
+ (*) Option valid only for following architectures
+@@ -101,15 +101,15 @@ cpu_possible_map/for_each_possible_cpu()
+
+ Never use anything other than cpumask_t to represent bitmap of CPUs.
+
+-#include <linux/cpumask.h>
++ #include <linux/cpumask.h>
+
+-for_each_possible_cpu - Iterate over cpu_possible_map
+-for_each_online_cpu - Iterate over cpu_online_map
+-for_each_present_cpu - Iterate over cpu_present_map
+-for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
++ for_each_possible_cpu - Iterate over cpu_possible_map
++ for_each_online_cpu - Iterate over cpu_online_map
++ for_each_present_cpu - Iterate over cpu_present_map
++ for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
+
+-#include <linux/cpu.h>
+-lock_cpu_hotplug() and unlock_cpu_hotplug():
++ #include <linux/cpu.h>
++ lock_cpu_hotplug() and unlock_cpu_hotplug():
+
+ The above calls are used to inhibit cpu hotplug operations. While holding the
+ cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid
+@@ -120,7 +120,7 @@ will work as long as stop_machine_run()
+
+ CPU Hotplug - Frequently Asked Questions.
+
+-Q: How to i enable my kernel to support CPU hotplug?
++Q: How to enable my kernel to support CPU hotplug?
+ A: When doing make defconfig, Enable CPU hotplug support
+
+ "Processor type and Features" -> Support for Hotpluggable CPUs
+@@ -141,39 +141,39 @@ A: You should now notice an entry in sys
+ Check if sysfs is mounted, using the "mount" command. You should notice
+ an entry as shown below in the output.
+
+-....
+-none on /sys type sysfs (rw)
+-....
++ ....
++ none on /sys type sysfs (rw)
++ ....
+
+-if this is not mounted, do the following.
++If this is not mounted, do the following.
+
+-#mkdir /sysfs
+-#mount -t sysfs sys /sys
++ #mkdir /sysfs
++ #mount -t sysfs sys /sys
+
+-now you should see entries for all present cpu, the following is an example
++Now you should see entries for all present cpu, the following is an example
+ in a 8-way system.
+
+-#pwd
+-#/sys/devices/system/cpu
+-#ls -l
+-total 0
+-drwxr-xr-x 10 root root 0 Sep 19 07:44 .
+-drwxr-xr-x 13 root root 0 Sep 19 07:45 ..
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5
+-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6
+-drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7
++ #pwd
++ #/sys/devices/system/cpu
++ #ls -l
++ total 0
++ drwxr-xr-x 10 root root 0 Sep 19 07:44 .
++ drwxr-xr-x 13 root root 0 Sep 19 07:45 ..
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5
++ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6
++ drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7
+
+ Under each directory you would find an "online" file which is the control
+ file to logically online/offline a processor.
+
+ Q: Does hot-add/hot-remove refer to physical add/remove of cpus?
+ A: The usage of hot-add/remove may not be very consistently used in the code.
+-CONFIG_CPU_HOTPLUG enables logical online/offline capability in the kernel.
++CONFIG_HOTPLUG_CPU enables logical online/offline capability in the kernel.
+ To support physical addition/removal, one would need some BIOS hooks and
+ the platform should have something like an attention button in PCI hotplug.
+ CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs.
+@@ -181,17 +181,17 @@ CONFIG_ACPI_HOTPLUG_CPU enables ACPI sup
+ Q: How do i logically offline a CPU?
+ A: Do the following.
+
+-#echo 0 > /sys/devices/system/cpu/cpuX/online
++ #echo 0 > /sys/devices/system/cpu/cpuX/online
+
+-once the logical offline is successful, check
++Once the logical offline is successful, check
+
+-#cat /proc/interrupts
++ #cat /proc/interrupts
+
+-you should now not see the CPU that you removed. Also online file will report
++You should now not see the CPU that you removed. Also online file will report
+ the state as 0 when a cpu if offline and 1 when its online.
+
+-#To display the current cpu state.
+-#cat /sys/devices/system/cpu/cpuX/online
++ #To display the current cpu state.
++ #cat /sys/devices/system/cpu/cpuX/online
+
+ Q: Why cant i remove CPU0 on some systems?
+ A: Some architectures may have some special dependency on a certain CPU.
+@@ -234,8 +234,8 @@ Q: If i have some kernel code that needs
+ departure, how to i arrange for proper notification?
+ A: This is what you would need in your kernel code to receive notifications.
+
+- #include <linux/cpu.h>
+- static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb,
++ #include <linux/cpu.h>
++ static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+ {
+ unsigned int cpu = (unsigned long)hcpu;
+@@ -279,10 +279,10 @@ Q: I don't see my action being called fo
+ A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
+ If you need to perform some action for each cpu already in the system, then
+
+- for_each_online_cpu(i) {
++ for_each_online_cpu(i) {
+ foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
+- foobar_cpu_callback(&foobar-cpu_notifier, CPU_ONLINE, i);
+- }
++ foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);
++ }
+
+ Q: If i would like to develop cpu hotplug support for a new architecture,
+ what do i need at a minimum?
+@@ -307,38 +307,38 @@ Q: I need to ensure that a particular cp
+ work specific to this cpu is in progress.
+ A: First switch the current thread context to preferred cpu
+
+- int my_func_on_cpu(int cpu)
+- {
+- cpumask_t saved_mask, new_mask = CPU_MASK_NONE;
+- int curr_cpu, err = 0;
+-
+- saved_mask = current->cpus_allowed;
+- cpu_set(cpu, new_mask);
+- err = set_cpus_allowed(current, new_mask);
+-
+- if (err)
+- return err;
+-
+- /*
+- * If we got scheduled out just after the return from
+- * set_cpus_allowed() before running the work, this ensures
+- * we stay locked.
+- */
+- curr_cpu = get_cpu();
+-
+- if (curr_cpu != cpu) {
+- err = -EAGAIN;
+- goto ret;
+- } else {
+- /*
+- * Do work : But cant sleep, since get_cpu() disables preempt
+- */
+- }
+- ret:
+- put_cpu();
+- set_cpus_allowed(current, saved_mask);
+- return err;
+- }
++ int my_func_on_cpu(int cpu)
++ {
++ cpumask_t saved_mask, new_mask = CPU_MASK_NONE;
++ int curr_cpu, err = 0;
++
++ saved_mask = current->cpus_allowed;
++ cpu_set(cpu, new_mask);
++ err = set_cpus_allowed(current, new_mask);
++
++ if (err)
++ return err;
++
++ /*
++ * If we got scheduled out just after the return from
++ * set_cpus_allowed() before running the work, this ensures
++ * we stay locked.
++ */
++ curr_cpu = get_cpu();
++
++ if (curr_cpu != cpu) {
++ err = -EAGAIN;
++ goto ret;
++ } else {
++ /*
++ * Do work : But cant sleep, since get_cpu() disables preempt
++ */
++ }
++ ret:
++ put_cpu();
++ set_cpus_allowed(current, saved_mask);
++ return err;
++ }
+
+
+ Q: How do we determine how many CPUs are available for hotplug.
+diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
+index 76b4429..842f0d1 100644
+--- a/Documentation/cpusets.txt
++++ b/Documentation/cpusets.txt
+@@ -217,11 +217,11 @@ exclusive cpuset. Also, the use of a Li
+ to represent the cpuset hierarchy provides for a familiar permission
+ and name space for cpusets, with a minimum of additional kernel code.
+
+-The cpus file in the root (top_cpuset) cpuset is read-only.
+-It automatically tracks the value of cpu_online_map, using a CPU
+-hotplug notifier. If and when memory nodes can be hotplugged,
+-we expect to make the mems file in the root cpuset read-only
+-as well, and have it track the value of node_online_map.
++The cpus and mems files in the root (top_cpuset) cpuset are
++read-only. The cpus file automatically tracks the value of
++cpu_online_map using a CPU hotplug notifier, and the mems file
++automatically tracks the value of node_online_map using the
++cpuset_track_online_nodes() hook.
+
+
+ 1.4 What are exclusive cpusets ?
+diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt
+index 2b28e9e..b61cb95 100644
+--- a/Documentation/cputopology.txt
++++ b/Documentation/cputopology.txt
+@@ -26,7 +26,7 @@ The type of **_id is int.
+ The type of siblings is cpumask_t.
+
+ To be consistent on all architectures, the 4 attributes should have
+-deafult values if their values are unavailable. Below is the rule.
++default values if their values are unavailable. Below is the rule.
+ 1) physical_package_id: If cpu has no physical package id, -1 is the
+ default value.
+ 2) core_id: If cpu doesn't support multi-core, its core id is 0.
+diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
+index 74dffc6..5a03a28 100644
+--- a/Documentation/crypto/api-intro.txt
++++ b/Documentation/crypto/api-intro.txt
+@@ -19,15 +19,14 @@ At the lowest level are algorithms, whic
+ API.
+
+ 'Transforms' are user-instantiated objects, which maintain state, handle all
+-of the implementation logic (e.g. manipulating page vectors), provide an
+-abstraction to the underlying algorithms, and handle common logical
+-operations (e.g. cipher modes, HMAC for digests). However, at the user
++of the implementation logic (e.g. manipulating page vectors) and provide an
++abstraction to the underlying algorithms. However, at the user
+ level they are very simple.
+
+ Conceptually, the API layering looks like this:
+
+ [transform api] (user interface)
+- [transform ops] (per-type logic glue e.g. cipher.c, digest.c)
++ [transform ops] (per-type logic glue e.g. cipher.c, compress.c)
+ [algorithm api] (for registering algorithms)
+
+ The idea is to make the user interface and algorithm registration API
+@@ -44,22 +43,27 @@ under development.
+ Here's an example of how to use the API:
+
+ #include <linux/crypto.h>
++ #include <linux/err.h>
++ #include <linux/scatterlist.h>
+
+ struct scatterlist sg[2];
+ char result[128];
+- struct crypto_tfm *tfm;
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
+
+- tfm = crypto_alloc_tfm("md5", 0);
+- if (tfm == NULL)
++ tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm))
+ fail();
+
+ /* ... set up the scatterlists ... */
++
++ desc.tfm = tfm;
++ desc.flags = 0;
+
+- crypto_digest_init(tfm);
+- crypto_digest_update(tfm, &sg, 2);
+- crypto_digest_final(tfm, result);
++ if (crypto_hash_digest(&desc, &sg, 2, result))
++ fail();
+
+- crypto_free_tfm(tfm);
++ crypto_free_hash(tfm);
+
+
+ Many real examples are available in the regression test module (tcrypt.c).
+@@ -126,7 +130,7 @@ might already be working on.
+ BUGS
+
+ Send bug reports to:
+-James Morris <jmorris at redhat.com>
++Herbert Xu <herbert at gondor.apana.org.au>
+ Cc: David S. Miller <davem at redhat.com>
+
+
+@@ -134,13 +138,14 @@ FURTHER INFORMATION
+
+ For further patches and various updates, including the current TODO
+ list, see:
+-http://samba.org/~jamesm/crypto/
++http://gondor.apana.org.au/~herbert/crypto/
+
+
+ AUTHORS
+
+ James Morris
+ David S. Miller
++Herbert Xu
+
+
+ CREDITS
+@@ -238,8 +243,11 @@ Anubis algorithm contributors:
+ Tiger algorithm contributors:
+ Aaron Grothe
+
++VIA PadLock contributors:
++ Michal Ludvig
++
+ Generic scatterwalk code by Adam J. Richter <adam at yggdrasil.com>
+
+ Please send any credits updates or corrections to:
+-James Morris <jmorris at redhat.com>
++Herbert Xu <herbert at gondor.apana.org.au>
+
+diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt
+index 941343a..2c0d631 100644
+--- a/Documentation/dell_rbu.txt
++++ b/Documentation/dell_rbu.txt
+@@ -4,7 +4,7 @@ for updating BIOS images on Dell servers
+
+ Scope:
+ This document discusses the functionality of the rbu driver only.
+-It does not cover the support needed from aplications to enable the BIOS to
++It does not cover the support needed from applications to enable the BIOS to
+ update itself with the image downloaded in to the memory.
+
+ Overview:
+@@ -16,8 +16,8 @@ OpenManage and Dell Update packages (DUP
+ Libsmbios can also be used to update BIOS on Dell systems go to
+ http://linux.dell.com/libsmbios/ for details.
+
+-Dell_RBU driver supports BIOS update using the monilothic image and packetized
+-image methods. In case of moniolithic the driver allocates a contiguous chunk
++Dell_RBU driver supports BIOS update using the monolithic image and packetized
++image methods. In case of monolithic the driver allocates a contiguous chunk
+ of physical pages having the BIOS image. In case of packetized the app
+ using the driver breaks the image in to packets of fixed sizes and the driver
+ would place each packet in contiguous physical memory. The driver also
+@@ -41,7 +41,7 @@ The driver supports two types of update
+ These update mechanism depends upon the BIOS currently running on the system.
+ Most of the Dell systems support a monolithic update where the BIOS image is
+ copied to a single contiguous block of physical memory.
+-In case of packet mechanism the single memory can be broken in smaller chuks
++In case of packet mechanism the single memory can be broken in smaller chunks
+ of contiguous memory and the BIOS image is scattered in these packets.
+
+ By default the driver uses monolithic memory for the update type. This can be
+@@ -52,11 +52,11 @@ echo packet > /sys/devices/platform/dell
+ In packet update mode the packet size has to be given before any packets can
+ be downloaded. It is done as below
+ echo XXXX > /sys/devices/platform/dell_rbu/packet_size
+-In the packet update mechanism, the user neesd to create a new file having
++In the packet update mechanism, the user needs to create a new file having
+ packets of data arranged back to back. It can be done as follows
+ The user creates packets header, gets the chunk of the BIOS image and
+-placs it next to the packetheader; now, the packetheader + BIOS image chunk
+-added to geather should match the specified packet_size. This makes one
++places it next to the packetheader; now, the packetheader + BIOS image chunk
++added together should match the specified packet_size. This makes one
+ packet, the user needs to create more such packets out of the entire BIOS
+ image file and then arrange all these packets back to back in to one single
+ file.
+@@ -93,8 +93,8 @@ read back the image downloaded.
+ NOTE:
+ This driver requires a patch for firmware_class.c which has the modified
+ request_firmware_nowait function.
+-Also after updating the BIOS image an user mdoe application neeeds to execute
+-code which message the BIOS update request to the BIOS. So on the next reboot
+-the BIOS knows about the new image downloaded and it updates it self.
+-Also don't unload the rbu drive if the image has to be updated.
++Also after updating the BIOS image a user mode application needs to execute
++code which sends the BIOS update request to the BIOS. So on the next reboot
++the BIOS knows about the new image downloaded and it updates itself.
++Also don't unload the rbu driver if the image has to be updated.
+
+diff --git a/Documentation/devices.txt b/Documentation/devices.txt
+index 66c725f..28c4f79 100644
+--- a/Documentation/devices.txt
++++ b/Documentation/devices.txt
+@@ -2005,7 +2005,7 @@ Your cooperation is appreciated.
+ 116 char Advanced Linux Sound Driver (ALSA)
+
+ 116 block MicroMemory battery backed RAM adapter (NVRAM)
+- Supports 16 boards, 15 paritions each.
++ Supports 16 boards, 15 partitions each.
+ Requested by neilb at cse.unsw.edu.au.
+
+ 0 = /dev/umem/d0 Whole of first board
+@@ -2543,6 +2543,9 @@ Your cooperation is appreciated.
+ 64 = /dev/usb/rio500 Diamond Rio 500
+ 65 = /dev/usb/usblcd USBLCD Interface (info at usblcd.de)
+ 66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
++ 67 = /dev/usb/adutux0 1st Ontrak ADU device
++ ...
++ 76 = /dev/usb/adutux10 10th Ontrak ADU device
+ 96 = /dev/usb/hiddev0 1st USB HID device
+ ...
+ 111 = /dev/usb/hiddev15 16th USB HID device
+@@ -3091,7 +3094,7 @@ Your cooperation is appreciated.
+ This major is reserved to assist the expansion to a
+ larger number space. No device nodes with this major
+ should ever be created on the filesystem.
+- (This is probaly not true anymore, but I'll leave it
++ (This is probably not true anymore, but I'll leave it
+ for now /Torben)
+
+ ---LARGE MAJORS!!!!!---
+@@ -3202,7 +3205,7 @@ for a session; this includes virtual con
+ pseudoterminals (PTYs).
+
+ All terminal devices share a common set of capabilities known as line
+-diciplines; these include the common terminal line dicipline as well
++disciplines; these include the common terminal line discipline as well
+ as SLIP and PPP modes.
+
+ All terminal devices are named similarly; this section explains the
+@@ -3282,7 +3285,7 @@ port TTY, for which no alternate device
+ Pseudoterminals (PTYs)
+
+ Pseudoterminals, or PTYs, are used to create login sessions or provide
+-other capabilities requiring a TTY line dicipline (including SLIP or
++other capabilities requiring a TTY line discipline (including SLIP or
+ PPP capability) to arbitrary data-generation processes. Each PTY has
+ a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named
+ /dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by
+diff --git a/Documentation/dontdiff b/Documentation/dontdiff
+index 24adfe9..63c2d0c 100644
+--- a/Documentation/dontdiff
++++ b/Documentation/dontdiff
+@@ -135,6 +135,7 @@ tags
+ times.h*
+ tkparse
+ trix_boot.h
++utsrelease.h*
+ version.h*
+ vmlinux
+ vmlinux-*
+diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt
+index 2d1d893..548505f 100644
+--- a/Documentation/driver-model/class.txt
++++ b/Documentation/driver-model/class.txt
+@@ -12,7 +12,7 @@ device. The following device classes hav
+
+ Each device class defines a set of semantics and a programming interface
+ that devices of that class adhere to. Device drivers are the
+-implemention of that programming interface for a particular device on
++implementation of that programming interface for a particular device on
+ a particular bus.
+
+ Device classes are agnostic with respect to what bus a device resides
+diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
+index 59806c9..8213216 100644
+--- a/Documentation/driver-model/driver.txt
++++ b/Documentation/driver-model/driver.txt
+@@ -178,7 +178,7 @@ the driver to that device.
+
+ A driver's probe() may return a negative errno value to indicate that
+ the driver did not bind to this device, in which case it should have
+-released all reasources it allocated.
++released all resources it allocated.
+
+ int (*remove) (struct device * dev);
+
+diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
+index 2050c9f..07236ed 100644
+--- a/Documentation/driver-model/overview.txt
++++ b/Documentation/driver-model/overview.txt
+@@ -57,7 +57,7 @@ the two.
+
+ The PCI bus layer freely accesses the fields of struct device. It knows about
+ the structure of struct pci_dev, and it should know the structure of struct
+-device. Individual PCI device drivers that have been converted the the current
++device. Individual PCI device drivers that have been converted to the current
+ driver model generally do not and should not touch the fields of struct device,
+ unless there is a strong compelling reason to do so.
+
+diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt
+index 8bab846..e44c009 100644
+--- a/Documentation/dvb/avermedia.txt
++++ b/Documentation/dvb/avermedia.txt
+@@ -45,9 +45,9 @@ Assumptions and Introduction
+ by circuitry on the card and is often presented uncompressed.
+ For a PAL TV signal encoded at a resolution of 768x576 24-bit
+ color pixels over 25 frames per second - a fair amount of data
+- is generated and must be proceesed by the PC before it can be
++ is generated and must be processed by the PC before it can be
+ displayed on the video monitor screen. Some Analogue TV cards
+- for PC's have onboard MPEG2 encoders which permit the raw
++ for PCs have onboard MPEG2 encoders which permit the raw
+ digital data stream to be presented to the PC in an encoded
+ and compressed form - similar to the form that is used in
+ Digital TV.
+diff --git a/Documentation/dvb/cards.txt b/Documentation/dvb/cards.txt
+index 9e10092..ca58e33 100644
+--- a/Documentation/dvb/cards.txt
++++ b/Documentation/dvb/cards.txt
+@@ -5,7 +5,7 @@ Hardware supported by the linuxtv.org DV
+ frontends (i.e. tuner / demodulator units) used, usually without
+ changing the product name, revision number or specs. Some cards
+ are also available in versions with different frontends for
+- DVB-S/DVB-C/DVB-T. Thus the frontend drivers are listed seperately.
++ DVB-S/DVB-C/DVB-T. Thus the frontend drivers are listed separately.
+
+ Note 1: There is no guarantee that every frontend driver works
+ out of the box with every card, because of different wiring.
+diff --git a/Documentation/dvb/ci.txt b/Documentation/dvb/ci.txt
+index 95f0e73..531239b 100644
+--- a/Documentation/dvb/ci.txt
++++ b/Documentation/dvb/ci.txt
+@@ -32,7 +32,7 @@ This application requires the following
+ descrambler to function,
+ eg: $ ca_zap channels.conf "TMC"
+
+- (d) Hopeflly Enjoy your favourite subscribed channel as you do with
++ (d) Hopefully enjoy your favourite subscribed channel as you do with
+ a FTA card.
+
+ (3) Currently ca_zap, and dst_test, both are meant for demonstration
+@@ -65,7 +65,7 @@ Modules that have been tested by this dr
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ With the High Level CI approach any new card with almost any random
+ architecture can be implemented with this style, the definitions
+-insidethe switch statement can be easily adapted for any card, thereby
++inside the switch statement can be easily adapted for any card, thereby
+ eliminating the need for any additional ioctls.
+
+ The disadvantage is that the driver/hardware has to manage the rest. For
+diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt
+index a42132d..dbcedf5 100644
+--- a/Documentation/dvb/faq.txt
++++ b/Documentation/dvb/faq.txt
+@@ -5,7 +5,7 @@ Some very frequently asked questions abo
+ It's not a bug, it's a feature. Because the frontends have
+ significant power requirements (and hence get very hot), they
+ are powered down if they are unused (i.e. if the frontend device
+- is closed). The dvb-core.o module paramter "dvb_shutdown_timeout"
++ is closed). The dvb-core.o module parameter "dvb_shutdown_timeout"
+ allow you to change the timeout (default 5 seconds). Setting the
+ timeout to 0 disables the timeout feature.
+
+@@ -138,7 +138,7 @@ Some very frequently asked questions abo
+
+ - v4l2-common: common functions for Video4Linux-2 drivers
+
+- - v4l1-compat: backward compatiblity layer for Video4Linux-1 legacy
++ - v4l1-compat: backward compatibility layer for Video4Linux-1 legacy
+ applications
+
+ - dvb-core: DVB core module. This provides you with the
+@@ -153,7 +153,7 @@ Some very frequently asked questions abo
+ - video-buf: capture helper module for the saa7146_vv driver. This
+ one is responsible to handle capture buffers.
+
+- - dvb-ttpci: The main driver for AV7110 based, full-featued
++ - dvb-ttpci: The main driver for AV7110 based, full-featured
+ DVB-S/C/T cards
+
+ eof
+diff --git a/Documentation/ecryptfs.txt b/Documentation/ecryptfs.txt
+new file mode 100644
+index 0000000..01d8a08
+--- /dev/null
++++ b/Documentation/ecryptfs.txt
+@@ -0,0 +1,77 @@
++eCryptfs: A stacked cryptographic filesystem for Linux
++
++eCryptfs is free software. Please see the file COPYING for details.
++For documentation, please see the files in the doc/ subdirectory. For
++building and installation instructions please see the INSTALL file.
++
++Maintainer: Phillip Hellewell
++Lead developer: Michael A. Halcrow <mhalcrow at us.ibm.com>
++Developers: Michael C. Thompson
++ Kent Yoder
++Web Site: http://ecryptfs.sf.net
++
++This software is currently undergoing development. Make sure to
++maintain a backup copy of any data you write into eCryptfs.
++
++eCryptfs requires the userspace tools downloadable from the
++SourceForge site:
++
++http://sourceforge.net/projects/ecryptfs/
++
++Userspace requirements include:
++ - David Howells' userspace keyring headers and libraries (version
++ 1.0 or higher), obtainable from
++ http://people.redhat.com/~dhowells/keyutils/
++ - Libgcrypt
++
++
++NOTES
++
++In the beta/experimental releases of eCryptfs, when you upgrade
++eCryptfs, you should copy the files to an unencrypted location and
++then copy the files back into the new eCryptfs mount to migrate the
++files.
++
++
++MOUNT-WIDE PASSPHRASE
++
++Create a new directory into which eCryptfs will write its encrypted
++files (i.e., /root/crypt). Then, create the mount point directory
++(i.e., /mnt/crypt). Now it's time to mount eCryptfs:
++
++mount -t ecryptfs /root/crypt /mnt/crypt
++
++You should be prompted for a passphrase and a salt (the salt may be
++blank).
++
++Try writing a new file:
++
++echo "Hello, World" > /mnt/crypt/hello.txt
++
++The operation will complete. Notice that there is a new file in
++/root/crypt that is at least 12288 bytes in size (depending on your
++host page size). This is the encrypted underlying file for what you
++just wrote. To test reading, from start to finish, you need to clear
++the user session keyring:
++
++keyctl clear @u
++
++Then umount /mnt/crypt and mount again per the instructions given
++above.
++
++cat /mnt/crypt/hello.txt
++
++
++NOTES
++
++eCryptfs version 0.1 should only be mounted on (1) empty directories
++or (2) directories containing files only created by eCryptfs. If you
++mount a directory that has pre-existing files not created by eCryptfs,
++then behavior is undefined. Do not run eCryptfs in higher verbosity
++levels unless you are doing so for the sole purpose of debugging or
++development, since secret values will be written out to the system log
++in that case.
++
++
++Mike Halcrow
++mhalcrow at us.ibm.com
+diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt
+index 8c8388d..6a099ed 100644
+--- a/Documentation/eisa.txt
++++ b/Documentation/eisa.txt
+@@ -18,7 +18,7 @@ The EISA infrastructure is made up of th
+
+ - The bus code implements most of the generic code. It is shared
+ among all the architectures that the EISA code runs on. It
+- implements bus probing (detecting EISA cards avaible on the bus),
++ implements bus probing (detecting EISA cards available on the bus),
+ allocates I/O resources, allows fancy naming through sysfs, and
+ offers interfaces for driver to register.
+
+@@ -84,7 +84,7 @@ struct eisa_driver {
+
+ id_table : an array of NULL terminated EISA id strings,
+ followed by an empty string. Each string can
+- optionnaly be paired with a driver-dependant value
++ optionally be paired with a driver-dependant value
+ (driver_data).
+
+ driver : a generic driver, such as described in
+diff --git a/Documentation/exception.txt b/Documentation/exception.txt
+index 3cb39ad..2d5aded 100644
+--- a/Documentation/exception.txt
++++ b/Documentation/exception.txt
+@@ -10,7 +10,7 @@ int verify_area(int type, const void * a
+ function (which has since been replaced by access_ok()).
+
+ This function verified that the memory area starting at address
+-addr and of size size was accessible for the operation specified
++'addr' and of size 'size' was accessible for the operation specified
+ in type (read or write). To do this, verify_read had to look up the
+ virtual memory area (vma) that contained the address addr. In the
+ normal case (correctly working program), this test was successful.
+diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt
+index f373df1..99ea58e 100644
+--- a/Documentation/fb/fbcon.txt
++++ b/Documentation/fb/fbcon.txt
+@@ -163,7 +163,7 @@ from the console layer before unloading
+ unloaded if it is still bound to the console layer. (See
+ Documentation/console/console.txt for more information).
+
+-This is more complicated in the case of the the framebuffer console (fbcon),
++This is more complicated in the case of the framebuffer console (fbcon),
+ because fbcon is an intermediate layer between the console and the drivers:
+
+ console ---> fbcon ---> fbdev drivers ---> hardware
+diff --git a/Documentation/fb/intel810.txt b/Documentation/fb/intel810.txt
+index 4f0d6bc..be3e783 100644
+--- a/Documentation/fb/intel810.txt
++++ b/Documentation/fb/intel810.txt
+@@ -9,8 +9,9 @@ Intel 810/815 Framebuffer driver
+ ================================================================
+
+ A. Introduction
++
+ This is a framebuffer driver for various Intel 810/815 compatible
+-graphics devices. These would include:
++ graphics devices. These include:
+
+ Intel 810
+ Intel 810E
+@@ -21,136 +22,136 @@ graphics devices. These would include:
+
+ B. Features
+
+- - Choice of using Discrete Video Timings, VESA Generalized Timing
++ - Choice of using Discrete Video Timings, VESA Generalized Timing
+ Formula, or a framebuffer specific database to set the video mode
+
+- - Supports a variable range of horizontal and vertical resolution, and
+- vertical refresh rates if the VESA Generalized Timing Formula is
++ - Supports a variable range of horizontal and vertical resolution and
++ vertical refresh rates if the VESA Generalized Timing Formula is
+ enabled.
+
+- - Supports color depths of 8, 16, 24 and 32 bits per pixel
++ - Supports color depths of 8, 16, 24 and 32 bits per pixel
+
+ - Supports pseudocolor, directcolor, or truecolor visuals
+
+- - Full and optimized hardware acceleration at 8, 16 and 24 bpp
++ - Full and optimized hardware acceleration at 8, 16 and 24 bpp
+
+ - Robust video state save and restore
+
+- - MTRR support
++ - MTRR support
+
+ - Utilizes user-entered monitor specifications to automatically
+ calculate required video mode parameters.
+
+- - Can concurrently run with xfree86 running with native i810 drivers
++ - Can concurrently run with xfree86 running with native i810 drivers
+
+ - Hardware Cursor Support
+
+ - Supports EDID probing either by DDC/I2C or through the BIOS
+
+ C. List of available options
+-
+- a. "video=i810fb"
++
++ a. "video=i810fb"
+ enables the i810 driver
+
+ Recommendation: required
+-
+- b. "xres:<value>"
++
++ b. "xres:<value>"
+ select horizontal resolution in pixels. (This parameter will be
+ ignored if 'mode_option' is specified. See 'o' below).
+
+- Recommendation: user preference
++ Recommendation: user preference
+ (default = 640)
+
+ c. "yres:<value>"
+ select vertical resolution in scanlines. If Discrete Video Timings
+ is enabled, this will be ignored and computed as 3*xres/4. (This
+ parameter will be ignored if 'mode_option' is specified. See 'o'
+- below)
++ below)
+
+ Recommendation: user preference
+ (default = 480)
+-
+- d. "vyres:<value>"
++
++ d. "vyres:<value>"
+ select virtual vertical resolution in scanlines. If (0) or none
+- is specified, this will be computed against maximum available memory.
++ is specified, this will be computed against maximum available memory.
+
+ Recommendation: do not set
+ (default = 480)
+
+ e. "vram:<value>"
+- select amount of system RAM in MB to allocate for the video memory
++ select amount of system RAM in MB to allocate for the video memory
+
+ Recommendation: 1 - 4 MB.
+ (default = 4)
+
+- f. "bpp:<value>"
+- select desired pixel depth
++ f. "bpp:<value>"
++ select desired pixel depth
+
+ Recommendation: 8
+ (default = 8)
+
+- g. "hsync1/hsync2:<value>"
+- select the minimum and maximum Horizontal Sync Frequency of the
+- monitor in KHz. If a using a fixed frequency monitor, hsync1 must
++ g. "hsync1/hsync2:<value>"
++ select the minimum and maximum Horizontal Sync Frequency of the
++ monitor in kHz. If using a fixed frequency monitor, hsync1 must
+ be equal to hsync2. If EDID probing is successful, these will be
+ ignored and values will be taken from the EDID block.
+
+ Recommendation: check monitor manual for correct values
+- default (29/30)
++ (default = 29/30)
+
+- h. "vsync1/vsync2:<value>"
++ h. "vsync1/vsync2:<value>"
+ select the minimum and maximum Vertical Sync Frequency of the monitor
+- in Hz. You can also use this option to lock your monitor's refresh
++ in Hz. You can also use this option to lock your monitor's refresh
+ rate. If EDID probing is successful, these will be ignored and values
+ will be taken from the EDID block.
+
+ Recommendation: check monitor manual for correct values
+ (default = 60/60)
+
+- IMPORTANT: If you need to clamp your timings, try to give some
+- leeway for computational errors (over/underflows). Example: if
++ IMPORTANT: If you need to clamp your timings, try to give some
++ leeway for computational errors (over/underflows). Example: if
+ using vsync1/vsync2 = 60/60, make sure hsync1/hsync2 has at least
+ a 1 unit difference, and vice versa.
+
+- i. "voffset:<value>"
+- select at what offset in MB of the logical memory to allocate the
++ i. "voffset:<value>"
++ select at what offset in MB of the logical memory to allocate the
+ framebuffer memory. The intent is to avoid the memory blocks
+ used by standard graphics applications (XFree86). The default
+- offset (16 MB for a 64MB aperture, 8 MB for a 32MB aperture) will
+- avoid XFree86's usage and allows up to 7MB/15MB of framebuffer
+- memory. Depending on your usage, adjust the value up or down,
+- (0 for maximum usage, 31/63 MB for the least amount). Note, an
++ offset (16 MB for a 64 MB aperture, 8 MB for a 32 MB aperture) will
++ avoid XFree86's usage and allows up to 7 MB/15 MB of framebuffer
++ memory. Depending on your usage, adjust the value up or down
++ (0 for maximum usage, 31/63 MB for the least amount). Note, an
+ arbitrary setting may conflict with XFree86.
+
+ Recommendation: do not set
+ (default = 8 or 16 MB)
+-
+- j. "accel"
+- enable text acceleration. This can be enabled/reenabled anytime
+- by using 'fbset -accel true/false'.
++
++ j. "accel"
++ enable text acceleration. This can be enabled/reenabled anytime
++ by using 'fbset -accel true/false'.
+
+ Recommendation: enable
+- (default = not set)
++ (default = not set)
+
+- k. "mtrr"
++ k. "mtrr"
+ enable MTRR. This allows data transfers to the framebuffer memory
+ to occur in bursts which can significantly increase performance.
+- Not very helpful with the i810/i815 because of 'shared memory'.
++ Not very helpful with the i810/i815 because of 'shared memory'.
+
+ Recommendation: do not set
+- (default = not set)
++ (default = not set)
+
+ l. "extvga"
+ if specified, secondary/external VGA output will always be enabled.
+ Useful if the BIOS turns off the VGA port when no monitor is attached.
+- The external VGA monitor can then be attached without rebooting.
++ The external VGA monitor can then be attached without rebooting.
+
+ Recommendation: do not set
+ (default = not set)
+-
+- m. "sync"
++
++ m. "sync"
+ Forces the hardware engine to do a "sync" or wait for the hardware
+- to finish before starting another instruction. This will produce a
++ to finish before starting another instruction. This will produce a
+ more stable setup, but will be slower.
+
+ Recommendation: do not set
+@@ -162,6 +163,7 @@ C. List of available options
+
+ Recommendation: do not set
+ (default = not set)
++
+ o. <xres>x<yres>[-<bpp>][@<refresh>]
+ The driver will now accept specification of boot mode option. If this
+ is specified, the options 'xres' and 'yres' will be ignored. See
+@@ -183,8 +185,8 @@ append="video=i810fb:vram:2,xres:1024,yr
+ vsync1:50,vsync2:85,accel,mtrr"
+
+ This will initialize the framebuffer to 1024x768 at 8bpp. The framebuffer
+-will use 2 MB of System RAM. MTRR support will be enabled. The refresh rate
+-will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
++will use 2 MB of System RAM. MTRR support will be enabled. The refresh rate
++will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
+
+ IMPORTANT:
+ You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
+@@ -194,10 +196,10 @@ vsync1 and vsync2 parameters. These par
+ block.
+
+ E. Module options
+-
+- The module parameters are essentially similar to the kernel
+-parameters. The main difference is that you need to include a Boolean value
+-(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
++
++The module parameters are essentially similar to the kernel
++parameters. The main difference is that you need to include a Boolean value
++(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
+
+ Example, to enable MTRR, include "mtrr=1".
+
+@@ -214,62 +216,62 @@ Or just add the following to /etc/modpro
+ options i810fb vram=2 xres=1024 bpp=16 hsync1=30 hsync2=55 vsync1=50 \
+ vsync2=85 accel=1 mtrr=1
+
+-and just do a
++and just do a
+
+ modprobe i810fb
+
+
+ F. Setup
+
+- a. Do your usual method of configuring the kernel.
+-
++ a. Do your usual method of configuring the kernel.
++
+ make menuconfig/xconfig/config
+
+- b. Under "Code Maturity Options", enable "Prompt for experimental/
+- incomplete code/drivers".
++ b. Under "Code maturity level options" enable "Prompt for development
++ and/or incomplete code/drivers".
+
+ c. Enable agpgart support for the Intel 810/815 on-board graphics.
+- This is required. The option is under "Character Devices"
++ This is required. The option is under "Character Devices".
+
+ d. Under "Graphics Support", select "Intel 810/815" either statically
+ or as a module. Choose "use VESA Generalized Timing Formula" if
+- you need to maximize the capability of your display. To be on the
+- safe side, you can leave this unselected.
+-
++ you need to maximize the capability of your display. To be on the
++ safe side, you can leave this unselected.
++
+ e. If you want support for DDC/I2C probing (Plug and Play Displays),
+ set 'Enable DDC Support' to 'y'. To make this option appear, set
+ 'use VESA Generalized Timing Formula' to 'y'.
+
+- f. If you want a framebuffer console, enable it under "Console
+- Drivers"
++ f. If you want a framebuffer console, enable it under "Console
++ Drivers".
++
++ g. Compile your kernel.
++
++ h. Load the driver as described in sections D and E.
+
+- g. Compile your kernel.
+-
+- h. Load the driver as described in section D and E.
+-
+ i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
+ patch to see the chipset in action (or inaction :-).
+
+ G. Acknowledgment:
+-
++
+ 1. Geert Uytterhoeven - his excellent howto and the virtual
+- framebuffer driver code made this possible.
++ framebuffer driver code made this possible.
+
+- 2. Jeff Hartmann for his agpgart code.
++ 2. Jeff Hartmann for his agpgart code.
+
+ 3. The X developers. Insights were provided just by reading the
+ XFree86 source code.
+
+ 4. Intel(c). For this value-oriented chipset driver and for
+- providing documentation.
++ providing documentation.
+
+ 5. Matt Sottek. His inputs and ideas helped in making some
+- optimizations possible.
++ optimizations possible.
+
+ H. Home Page:
+
+ A more complete, and probably updated information is provided at
+-http://i810fb.sourceforge.net.
++ http://i810fb.sourceforge.net.
+
+ ###########################
+ Tony
+diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt
+index c12d39a..da5ee74 100644
+--- a/Documentation/fb/intelfb.txt
++++ b/Documentation/fb/intelfb.txt
+@@ -1,16 +1,19 @@
+-Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver
++Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver
+ ================================================================
+
+ A. Introduction
+- This is a framebuffer driver for various Intel 810/815 compatible
++ This is a framebuffer driver for various Intel 8xx/9xx compatible
+ graphics devices. These would include:
+
+ Intel 830M
+- Intel 810E845G
++ Intel 845G
+ Intel 852GM
+ Intel 855GM
+ Intel 865G
+ Intel 915G
++ Intel 915GM
++ Intel 945G
++ Intel 945GM
+
+ B. List of available options
+
+@@ -78,19 +81,27 @@ C. Kernel booting
+ Separate each option/option-pair by commas (,) and the option from its value
+ with an equals sign (=) as in the following:
+
+-video=i810fb:option1,option2=value2
++video=intelfb:option1,option2=value2
+
+ Sample Usage
+ ------------
+
+ In /etc/lilo.conf, add the line:
+
+-append="video=intelfb:800x600-32 at 75,accel,hwcursor,vram=8"
++append="video=intelfb:mode=800x600-32 at 75,accel,hwcursor,vram=8"
+
+ This will initialize the framebuffer to 800x600 at 32bpp and 75Hz. The
+ framebuffer will use 8 MB of System RAM. hw acceleration of text and cursor
+ will be enabled.
+
++Remarks
++-------
++
++If setting this parameter doesn't work (you stay in a 80x25 text-mode),
++you might need to set the "vga=<mode>" parameter too - see vesafb.txt
++in this directory.
++
++
+ D. Module options
+
+ The module parameters are essentially similar to the kernel
+diff --git a/Documentation/fb/sisfb.txt b/Documentation/fb/sisfb.txt
+index 3b50c51..2e68e50 100644
+--- a/Documentation/fb/sisfb.txt
++++ b/Documentation/fb/sisfb.txt
+@@ -72,7 +72,7 @@ information. Additionally, "modinfo sisf
+ supported options including some explanation.
+
+ The desired display mode can be specified using the keyword "mode" with
+-a parameter in one of the follwing formats:
++a parameter in one of the following formats:
+ - XxYxDepth or
+ - XxY-Depth or
+ - XxY-Depth at Rate or
+diff --git a/Documentation/fb/sstfb.txt b/Documentation/fb/sstfb.txt
+index 628d7ff..df27f5b 100644
+--- a/Documentation/fb/sstfb.txt
++++ b/Documentation/fb/sstfb.txt
+@@ -48,12 +48,12 @@ Module Usage
+
+ Module insertion:
+ # insmod sstfb.o
+- you should see some strange output frome the board:
++ you should see some strange output from the board:
+ a big blue square, a green and a red small squares and a vertical
+- white rectangle. why ? the function's name is self explanatory :
++ white rectangle. why? the function's name is self-explanatory:
+ "sstfb_test()"...
+ (if you don't have a second monitor, you'll have to plug your monitor
+- directely to the 2D videocard to see what you're typing)
++ directly to the 2D videocard to see what you're typing)
+ # con2fb /dev/fbx /dev/ttyx
+ bind a tty to the new frame buffer. if you already have a frame
+ buffer driver, the voodoo fb will likely be /dev/fb1. if not,
+@@ -72,12 +72,12 @@ Module Usage
+
+ Kernel/Modules Options
+
+- You can pass some otions to sstfb module, and via the kernel command
+- line when the driver is compiled in :
++ You can pass some options to the sstfb module, and via the kernel
++ command line when the driver is compiled in:
+ for module : insmod sstfb.o option1=value1 option2=value2 ...
+ in kernel : video=sstfb:option1,option2:value2,option3 ...
+
+- sstfb supports the folowing options :
++ sstfb supports the following options :
+
+ Module Kernel Description
+
+@@ -95,11 +95,11 @@ inverse=1 inverse Supposed to enable in
+
+ clipping=1 clipping Enable or disable clipping.
+ clipping=0 noclipping With clipping enabled, all offscreen
+- reads and writes are disgarded.
++ reads and writes are discarded.
+ Default: enable clipping.
+
+ gfxclk=x gfxclk:x Force graphic clock frequency (in MHz).
+- Be carefull with this option, it may be
++ Be careful with this option, it may be
+ DANGEROUS.
+ Default: auto
+ 50Mhz for Voodoo 1,
+@@ -137,23 +137,23 @@ Bugs
+ - The driver is 16 bpp only, 24/32 won't work.
+ - The driver is not your_favorite_toy-safe. this includes SMP...
+ [Actually from inspection it seems to be safe - Alan]
+- - when using XFree86 FBdev (X over fbdev) you may see strange color
++ - When using XFree86 FBdev (X over fbdev) you may see strange color
+ patterns at the border of your windows (the pixels lose the lowest
+- byte -> basicaly the blue component nd some of the green) . I'm unable
++ byte -> basically the blue component and some of the green). I'm unable
+ to reproduce this with XFree86-3.3, but one of the testers has this
+- problem with XFree86-4. apparently recent Xfree86-4.x solve this
++ problem with XFree86-4. Apparently recent Xfree86-4.x solve this
+ problem.
+ - I didn't really test changing the palette, so you may find some weird
+ things when playing with that.
+- - Sometimes the driver will not recognise the DAC , and the
+- initialisation will fail. this is specificaly true for
+- voodoo 2 boards , but it should be solved in recent versions. please
+- contact me .
+- - the 24/32 is not likely to work anytime soon , knowing that the
+- hardware does ... unusual thigs in 24/32 bpp
+- - When used with anther video board, current limitations of linux
+- console subsystem can cause some troubles, specificaly, you should
+- disable software scrollback , as it can oops badly ...
++ - Sometimes the driver will not recognise the DAC, and the
++ initialisation will fail. This is specifically true for
++ voodoo 2 boards, but it should be solved in recent versions. Please
++ contact me.
++ - The 24/32 is not likely to work anytime soon, knowing that the
++ hardware does ... unusual things in 24/32 bpp.
++ - When used with another video board, current limitations of the linux
++ console subsystem can cause some troubles, specifically, you should
++ disable software scrollback, as it can oops badly ...
+
+ Todo
+
+@@ -161,7 +161,7 @@ Todo
+ - Buy more coffee.
+ - test/port to other arch.
+ - try to add panning using tweeks with front and back buffer .
+- - try to implement accel on voodoo2 , this board can actualy do a
++ - try to implement accel on voodoo2, this board can actually do a
+ lot in 2D even if it was sold as a 3D only board ...
+
+ ghoz.
+diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
+index 552507f..1ac3c74 100644
+--- a/Documentation/feature-removal-schedule.txt
++++ b/Documentation/feature-removal-schedule.txt
+@@ -6,6 +6,21 @@ be removed from this file.
+
+ ---------------------------
+
++What: /sys/devices/.../power/state
++ dev->power.power_state
++ dpm_runtime_{suspend,resume)()
++When: July 2007
++Why: Broken design for runtime control over driver power states, confusing
++ driver-internal runtime power management with: mechanisms to support
++ system-wide sleep state transitions; event codes that distinguish
++ different phases of swsusp "sleep" transitions; and userspace policy
++ inputs. This framework was never widely used, and most attempts to
++ use it were broken. Drivers should instead be exposing domain-specific
++ interfaces either to kernel or to userspace.
++Who: Pavel Machek <pavel at suse.cz>
++
++---------------------------
++
+ What: RAW driver (CONFIG_RAW_DRIVER)
+ When: December 2005
+ Why: declared obsolete since kernel 2.6.3
+@@ -14,14 +29,6 @@ Who: Adrian Bunk <bunk at stusta.de>
+
+ ---------------------------
+
+-What: drivers that were depending on OBSOLETE_OSS_DRIVER
+- (config options already removed)
+-When: before 2.6.19
+-Why: OSS drivers with ALSA replacements
+-Who: Adrian Bunk <bunk at stusta.de>
+-
+----------------------------
+-
+ What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
+ When: November 2006
+ Why: Deprecated in favour of the new ioctl-based rawiso interface, which is
+@@ -31,17 +38,8 @@ Who: Jody McIntyre <scjody at modernduck.co
+
+ ---------------------------
+
+-What: sbp2: module parameter "force_inquiry_hack"
+-When: July 2006
+-Why: Superceded by parameter "workarounds". Both parameters are meant to be
+- used ad-hoc and for single devices only, i.e. not in modprobe.conf,
+- therefore the impact of this feature replacement should be low.
+-Who: Stefan Richter <stefanr at s5r6.in-berlin.de>
+-
+----------------------------
+-
+ What: Video4Linux API 1 ioctls and video_decoder.h from Video devices.
+-When: July 2006
++When: December 2006
+ Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
+ series. The old API have lots of drawbacks and don't provide enough
+ means to work with all video and audio standards. The newer API is
+@@ -55,6 +53,18 @@ Who: Mauro Carvalho Chehab <mchehab at brtu
+
+ ---------------------------
+
++What: sys_sysctl
++When: January 2007
++Why: The same information is available through /proc/sys and that is the
++ interface user space prefers to use. And there do not appear to be
++ any existing user in user space of sys_sysctl. The additional
++ maintenance overhead of keeping a set of binary names gets
++ in the way of doing a good job of maintaining this interface.
++
++Who: Eric Biederman <ebiederm at xmission.com>
++
++---------------------------
++
+ What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
+ When: November 2005
+ Files: drivers/pcmcia/: pcmcia_ioctl.c
+@@ -104,15 +114,6 @@ Who: Arjan van de Ven
+
+ ---------------------------
+
+-What: START_ARRAY ioctl for md
+-When: July 2006
+-Files: drivers/md/md.c
+-Why: Not reliable by design - can fail when most needed.
+- Alternatives exist
+-Who: NeilBrown <neilb at suse.de>
+-
+----------------------------
+-
+ What: eepro100 network driver
+ When: January 2007
+ Why: replaced by the e100 driver
+@@ -175,7 +176,7 @@ Who: Greg Kroah-Hartman <gregkh at suse.de>
+ ---------------------------
+
+ What: USB driver API moves to EXPORT_SYMBOL_GPL
+-When: Febuary 2008
++When: February 2008
+ Files: include/linux/usb.h, drivers/usb/core/driver.c
+ Why: The USB subsystem has changed a lot over time, and it has been
+ possible to create userspace USB drivers using usbfs/libusb/gadgetfs
+@@ -202,50 +203,6 @@ Who: Nick Piggin <npiggin at suse.de>
+
+ ---------------------------
+
+-What: Support for the MIPS EV96100 evaluation board
+-When: September 2006
+-Why: Does no longer build since at least November 15, 2003, apparently
+- no userbase left.
+-Who: Ralf Baechle <ralf at linux-mips.org>
+-
+----------------------------
+-
+-What: Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board
+-When: September 2006
+-Why: Does no longer build since quite some time, and was never popular,
+- due to the platform being replaced by successor models. Apparently
+- no user base left. It also is one of the last users of
+- WANT_PAGE_VIRTUAL.
+-Who: Ralf Baechle <ralf at linux-mips.org>
+-
+----------------------------
+-
+-What: Support for the Momentum Ocelot, Ocelot 3, Ocelot C and Ocelot G
+-When: September 2006
+-Why: Some do no longer build and apparently there is no user base left
+- for these platforms.
+-Who: Ralf Baechle <ralf at linux-mips.org>
+-
+----------------------------
+-
+-What: Support for MIPS Technologies' Altas and SEAD evaluation board
+-When: September 2006
+-Why: Some do no longer build and apparently there is no user base left
+- for these platforms. Hardware out of production since several years.
+-Who: Ralf Baechle <ralf at linux-mips.org>
+-
+----------------------------
+-
+-What: Support for the IT8172-based platforms, ITE 8172G and Globespan IVR
+-When: September 2006
+-Why: Code does no longer build since at least 2.6.0, apparently there is
+- no user base left for these platforms. Hardware out of production
+- since several years and hardly a trace of the manufacturer left on
+- the net.
+-Who: Ralf Baechle <ralf at linux-mips.org>
+-
+----------------------------
+-
+ What: Interrupt only SA_* flags
+ When: Januar 2007
+ Why: The interrupt related SA_* flags are replaced by IRQF_* to move them
+@@ -294,3 +251,32 @@ Why: The frame diverter is included in m
+ It is not clear if anyone is still using it.
+ Who: Stephen Hemminger <shemminger at osdl.org>
+
++---------------------------
++
++
++What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
++When: October 2008
++Why: The stacking of class devices makes these values misleading and
++ inconsistent.
++ Class devices should not carry any of these properties, and bus
++ devices have SUBSYTEM and DRIVER as a replacement.
++Who: Kay Sievers <kay.sievers at suse.de>
++
++---------------------------
++
++What: i2c-isa
++When: December 2006
++Why: i2c-isa is a non-sense and doesn't fit in the device driver
++ model. Drivers relying on it are better implemented as platform
++ drivers.
++Who: Jean Delvare <khali at linux-fr.org>
++
++---------------------------
++
++What: ftape
++When: 2.6.20
++Why: Orphaned for ages. SMP bugs long unfixed. Few users left
++ in the world.
++Who: Jeff Garzik <jeff at garzik.org>
++
++---------------------------
+diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
+index 16dec61..4dc28cc 100644
+--- a/Documentation/filesystems/00-INDEX
++++ b/Documentation/filesystems/00-INDEX
+@@ -26,8 +26,6 @@ cramfs.txt
+ - info on the cram filesystem for small storage (ROMs etc).
+ dentry-locking.txt
+ - info on the RCU-based dcache locking model.
+-devfs/
+- - directory containing devfs documentation.
+ directory-locking
+ - info about the locking scheme used for directory operations.
+ dlmfs.txt
+@@ -36,6 +34,8 @@ ext2.txt
+ - info, mount options and specifications for the Ext2 filesystem.
+ ext3.txt
+ - info, mount options and specifications for the Ext3 filesystem.
++ext4.txt
++ - info, mount options and specifications for the Ext4 filesystem.
+ files.txt
+ - info on file management in the Linux kernel.
+ fuse.txt
+diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
+index 247d7f6..eb1a6ca 100644
+--- a/Documentation/filesystems/Locking
++++ b/Documentation/filesystems/Locking
+@@ -356,10 +356,9 @@ The last two are called only from check_
+ prototypes:
+ loff_t (*llseek) (struct file *, loff_t, int);
+ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+- ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
+ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+- ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t,
+- loff_t);
++ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
++ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ int (*readdir) (struct file *, void *, filldir_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int,
+diff --git a/Documentation/filesystems/befs.txt b/Documentation/filesystems/befs.txt
+index 877a7b1..67391a1 100644
+--- a/Documentation/filesystems/befs.txt
++++ b/Documentation/filesystems/befs.txt
+@@ -7,7 +7,7 @@ WARNING
+ Make sure you understand that this is alpha software. This means that the
+ implementation is neither complete nor well-tested.
+
+-I DISCLAIM ALL RESPONSIBILTY FOR ANY POSSIBLE BAD EFFECTS OF THIS CODE!
++I DISCLAIM ALL RESPONSIBILITY FOR ANY POSSIBLE BAD EFFECTS OF THIS CODE!
+
+ LICENSE
+ =====
+@@ -22,7 +22,7 @@ He has been working on the code since Au
+ details.
+
+ Original Author: Makoto Kato <m_kato at ga2.so-net.ne.jp>
+-His orriginal code can still be found at:
++His original code can still be found at:
+ <http://hp.vector.co.jp/authors/VA008030/bfs/>
+ Does anyone know of a more current email address for Makoto? He doesn't
+ respond to the address given above...
+@@ -39,7 +39,7 @@ Which is it, BFS or BEFS?
+ ================
+ Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS".
+ But Unixware Boot Filesystem is called bfs, too. And they are already in
+-the kernel. Because of this nameing conflict, on Linux the BeOS
++the kernel. Because of this naming conflict, on Linux the BeOS
+ filesystem is called befs.
+
+ HOW TO INSTALL
+@@ -57,7 +57,7 @@ if the patching step fails (i.e. there a
+ figure it out yourself (it shouldn't be hard), or mail the maintainer
+ (Will Dyson <will_dyson at pobox.com>) for help.
+
+-step 2. Configuretion & make kernel
++step 2. Configuration & make kernel
+
+ The linux kernel has many compile-time options. Most of them are beyond the
+ scope of this document. I suggest the Kernel-HOWTO document as a good general
+diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
+index c4ff96b..c3a7afb 100644
+--- a/Documentation/filesystems/configfs/configfs.txt
++++ b/Documentation/filesystems/configfs/configfs.txt
+@@ -1,5 +1,5 @@
+
+-configfs - Userspace-driven kernel object configuation.
++configfs - Userspace-driven kernel object configuration.
+
+ Joel Becker <joel.becker at oracle.com>
+
+@@ -254,7 +254,7 @@ using the group _init() functions on the
+
+ Finally, when userspace calls rmdir(2) on the item or group,
+ ct_group_ops->drop_item() is called. As a config_group is also a
+-config_item, it is not necessary for a seperate drop_group() method.
++config_item, it is not necessary for a separate drop_group() method.
+ The subsystem must config_item_put() the reference that was initialized
+ upon item allocation. If a subsystem has no work to do, it may omit
+ the ct_group_ops->drop_item() method, and configfs will call
+@@ -406,7 +406,7 @@ that condition is met.
+
+ Far better would be an explicit action notifying the subsystem that the
+ config_item is ready to go. More importantly, an explicit action allows
+-the subsystem to provide feedback as to whether the attibutes are
++the subsystem to provide feedback as to whether the attributes are
+ initialized in a way that makes sense. configfs provides this as
+ committable items.
+
+@@ -422,7 +422,7 @@ support mkdir(2) or rmdir(2) either. It
+ "pending" directory does allow mkdir(2) and rmdir(2). An item is
+ created in the "pending" directory. Its attributes can be modified at
+ will. Userspace commits the item by renaming it into the "live"
+-directory. At this point, the subsystem recieves the ->commit_item()
++directory. At this point, the subsystem receives the ->commit_item()
+ callback. If all required attributes are filled to satisfaction, the
+ method returns zero and the item is moved to the "live" directory.
+
+diff --git a/Documentation/filesystems/directory-locking b/Documentation/filesystems/directory-locking
+index 34380d4..d7099a9 100644
+--- a/Documentation/filesystems/directory-locking
++++ b/Documentation/filesystems/directory-locking
+@@ -82,7 +82,7 @@ own descendent. Moreover, there is exac
+
+ Consider the object blocking the cross-directory rename. One
+ of its descendents is locked by cross-directory rename (otherwise we
+-would again have an infinite set of of contended objects). But that
++would again have an infinite set of contended objects). But that
+ means that cross-directory rename is taking locks out of order. Due
+ to (2) the order hadn't changed since we had acquired filesystem lock.
+ But locking rules for cross-directory rename guarantee that we do not
+diff --git a/Documentation/filesystems/dlmfs.txt b/Documentation/filesystems/dlmfs.txt
+index 9afab84..c50bbb2 100644
+--- a/Documentation/filesystems/dlmfs.txt
++++ b/Documentation/filesystems/dlmfs.txt
+@@ -68,7 +68,7 @@ request for an already acquired lock wil
+ call. Userspace programs are assumed to handle their own local
+ locking.
+
+-Two levels of locks are supported - Shared Read, and Exlcusive.
++Two levels of locks are supported - Shared Read, and Exclusive.
+ Also supported is a Trylock operation.
+
+ For information on the libo2dlm interface, please see o2dlm.h,
+diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
+index 3dd2872..4333e83 100644
+--- a/Documentation/filesystems/ext2.txt
++++ b/Documentation/filesystems/ext2.txt
+@@ -205,7 +205,7 @@ Reserved Space
+
+ In ext2, there is a mechanism for reserving a certain number of blocks
+ for a particular user (normally the super-user). This is intended to
+-allow for the system to continue functioning even if non-priveleged users
++allow for the system to continue functioning even if non-privileged users
+ fill up all the space available to them (this is independent of filesystem
+ quotas). It also keeps the filesystem from filling up entirely which
+ helps combat fragmentation.
+diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
+new file mode 100644
+index 0000000..6a4adca
+--- /dev/null
++++ b/Documentation/filesystems/ext4.txt
+@@ -0,0 +1,236 @@
++
++Ext4 Filesystem
++===============
++
++This is a development version of the ext4 filesystem, an advanced level
++of the ext3 filesystem which incorporates scalability and reliability
++enhancements for supporting large filesystems (64 bit) in keeping with
++increasing disk capacities and state-of-the-art feature requirements.
++
++Mailing list: linux-ext4 at vger.kernel.org
++
++
++1. Quick usage instructions:
++===========================
++
++ - Grab updated e2fsprogs from
++ ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs-interim/
++ This is a patchset on top of e2fsprogs-1.39, which can be found at
++ ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/
++
++ - It's still mke2fs -j /dev/hda1
++
++ - mount /dev/hda1 /wherever -t ext4dev
++
++ - To enable extents,
++
++ mount /dev/hda1 /wherever -t ext4dev -o extents
++
++ - The filesystem is compatible with the ext3 driver until you add a file
++ which has extents (ie: `mount -o extents', then create a file).
++
++ NOTE: The "extents" mount flag is temporary. It will soon go away and
++ extents will be enabled by the "-o extents" flag to mke2fs or tune2fs
++
++ - When comparing performance with other filesystems, remember that
++ ext3/4 by default offers higher data integrity guarantees than most. So
++ when comparing with a metadata-only journalling filesystem, use `mount -o
++ data=writeback'. And you might as well use `mount -o nobh' too along
++ with it. Making the journal larger than the mke2fs default often helps
++ performance with metadata-intensive workloads.
++
++2. Features
++===========
++
++2.1 Currently available
++
++* ability to use filesystems > 16TB
++* extent format reduces metadata overhead (RAM, IO for access, transactions)
++* extent format more robust in face of on-disk corruption due to magics,
++* internal redunancy in tree
++
++2.1 Previously available, soon to be enabled by default by "mkefs.ext4":
++
++* dir_index and resize inode will be on by default
++* large inodes will be used by default for fast EAs, nsec timestamps, etc
++
++2.2 Candidate features for future inclusion
++
++There are several under discussion, whether they all make it in is
++partly a function of how much time everyone has to work on them:
++
++* improved file allocation (multi-block alloc, delayed alloc; basically done)
++* fix 32000 subdirectory limit (patch exists, needs some e2fsck work)
++* nsec timestamps for mtime, atime, ctime, create time (patch exists,
++ needs some e2fsck work)
++* inode version field on disk (NFSv4, Lustre; prototype exists)
++* reduced mke2fs/e2fsck time via uninitialized groups (prototype exists)
++* journal checksumming for robustness, performance (prototype exists)
++* persistent file preallocation (e.g for streaming media, databases)
++
++Features like metadata checksumming have been discussed and planned for
++a bit but no patches exist yet so I'm not sure they're in the near-term
++roadmap.
++
++The big performance win will come with mballoc and delalloc. CFS has
++been using mballoc for a few years already with Lustre, and IBM + Bull
++did a lot of benchmarking on it. The reason it isn't in the first set of
++patches is partly a manageability issue, and partly because it doesn't
++directly affect the on-disk format (outside of much better allocation)
++so it isn't critical to get into the first round of changes. I believe
++Alex is working on a new set of patches right now.
++
++3. Options
++==========
++
++When mounting an ext4 filesystem, the following option are accepted:
++(*) == default
++
++extents ext4 will use extents to address file data. The
++ file system will no longer be mountable by ext3.
++
++journal=update Update the ext4 file system's journal to the current
++ format.
++
++journal=inum When a journal already exists, this option is ignored.
++ Otherwise, it specifies the number of the inode which
++ will represent the ext4 file system's journal file.
++
++journal_dev=devnum When the external journal device's major/minor numbers
++ have changed, this option allows the user to specify
++ the new journal location. The journal device is
++ identified through its new major/minor numbers encoded
++ in devnum.
++
++noload Don't load the journal on mounting.
++
++data=journal All data are committed into the journal prior to being
++ written into the main file system.
++
++data=ordered (*) All data are forced directly out to the main file
++ system prior to its metadata being committed to the
++ journal.
++
++data=writeback Data ordering is not preserved, data may be written
++ into the main file system after its metadata has been
++ committed to the journal.
++
++commit=nrsec (*) Ext4 can be told to sync all its data and metadata
++ every 'nrsec' seconds. The default value is 5 seconds.
++ This means that if you lose your power, you will lose
++ as much as the latest 5 seconds of work (your
++ filesystem will not be damaged though, thanks to the
++ journaling). This default value (or any low value)
++ will hurt performance, but it's good for data-safety.
++ Setting it to 0 will have the same effect as leaving
++ it at the default (5 seconds).
++ Setting it to very large values will improve
++ performance.
++
++barrier=1 This enables/disables barriers. barrier=0 disables
++ it, barrier=1 enables it.
++
++orlov (*) This enables the new Orlov block allocator. It is
++ enabled by default.
++
++oldalloc This disables the Orlov block allocator and enables
++ the old block allocator. Orlov should have better
++ performance - we'd like to get some feedback if it's
++ the contrary for you.
++
++user_xattr Enables Extended User Attributes. Additionally, you
++ need to have extended attribute support enabled in the
++ kernel configuration (CONFIG_EXT4_FS_XATTR). See the
++ attr(5) manual page and http://acl.bestbits.at/ to
++ learn more about extended attributes.
++
++nouser_xattr Disables Extended User Attributes.
++
++acl Enables POSIX Access Control Lists support.
++ Additionally, you need to have ACL support enabled in
++ the kernel configuration (CONFIG_EXT4_FS_POSIX_ACL).
++ See the acl(5) manual page and http://acl.bestbits.at/
++ for more information.
++
++noacl This option disables POSIX Access Control List
++ support.
++
++reservation
++
++noreservation
++
++bsddf (*) Make 'df' act like BSD.
++minixdf Make 'df' act like Minix.
++
++check=none Don't do extra checking of bitmaps on mount.
++nocheck
++
++debug Extra debugging information is sent to syslog.
++
++errors=remount-ro(*) Remount the filesystem read-only on an error.
++errors=continue Keep going on a filesystem error.
++errors=panic Panic and halt the machine if an error occurs.
++
++grpid Give objects the same group ID as their creator.
++bsdgroups
++
++nogrpid (*) New objects have the group ID of their creator.
++sysvgroups
++
++resgid=n The group ID which may use the reserved blocks.
++
++resuid=n The user ID which may use the reserved blocks.
++
++sb=n Use alternate superblock at this location.
++
++quota
++noquota
++grpquota
++usrquota
++
++bh (*) ext4 associates buffer heads to data pages to
++nobh (a) cache disk block mapping information
++ (b) link pages into transaction to provide
++ ordering guarantees.
++ "bh" option forces use of buffer heads.
++ "nobh" option tries to avoid associating buffer
++ heads (supported only for "writeback" mode).
++
++
++Data Mode
++---------
++There are 3 different data modes:
++
++* writeback mode
++In data=writeback mode, ext4 does not journal data at all. This mode provides
++a similar level of journaling as that of XFS, JFS, and ReiserFS in its default
++mode - metadata journaling. A crash+recovery can cause incorrect data to
++appear in files which were written shortly before the crash. This mode will
++typically provide the best ext4 performance.
++
++* ordered mode
++In data=ordered mode, ext4 only officially journals metadata, but it logically
++groups metadata and data blocks into a single unit called a transaction. When
++it's time to write the new metadata out to disk, the associated data blocks
++are written first. In general, this mode performs slightly slower than
++writeback but significantly faster than journal mode.
++
++* journal mode
++data=journal mode provides full data and metadata journaling. All new data is
++written to the journal first, and then to its final location.
++In the event of a crash, the journal can be replayed, bringing both data and
++metadata into a consistent state. This mode is the slowest except when data
++needs to be read from and written to disk at the same time where it
++outperforms all others modes.
++
++References
++==========
++
++kernel source: <file:fs/ext4/>
++ <file:fs/jbd2/>
++
++programs: http://e2fsprogs.sourceforge.net/
++ http://ext2resize.sourceforge.net
++
++useful links: http://fedoraproject.org/wiki/ext3-devel
++ http://www.bullopensource.org/ext4/
+diff --git a/Documentation/filesystems/files.txt b/Documentation/filesystems/files.txt
+index 8c206f4..133e213 100644
+--- a/Documentation/filesystems/files.txt
++++ b/Documentation/filesystems/files.txt
+@@ -55,7 +55,7 @@ the fdtable structure -
+ 2. Reading of the fdtable as described above must be protected
+ by rcu_read_lock()/rcu_read_unlock().
+
+-3. For any update to the the fd table, files->file_lock must
++3. For any update to the fd table, files->file_lock must
+ be held.
+
+ 4. To look up the file structure given an fd, a reader
+diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt
+new file mode 100644
+index 0000000..593004b
+--- /dev/null
++++ b/Documentation/filesystems/gfs2.txt
+@@ -0,0 +1,43 @@
++Global File System
++------------------
++
++http://sources.redhat.com/cluster/
++
++GFS is a cluster file system. It allows a cluster of computers to
++simultaneously use a block device that is shared between them (with FC,
++iSCSI, NBD, etc). GFS reads and writes to the block device like a local
++file system, but also uses a lock module to allow the computers coordinate
++their I/O so file system consistency is maintained. One of the nifty
++features of GFS is perfect consistency -- changes made to the file system
++on one machine show up immediately on all other machines in the cluster.
++
++GFS uses interchangable inter-node locking mechanisms. Different lock
++modules can plug into GFS and each file system selects the appropriate
++lock module at mount time. Lock modules include:
++
++ lock_nolock -- allows gfs to be used as a local file system
++
++ lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking
++ The dlm is found at linux/fs/dlm/
++
++In addition to interfacing with an external locking manager, a gfs lock
++module is responsible for interacting with external cluster management
++systems. Lock_dlm depends on user space cluster management systems found
++at the URL above.
++
++To use gfs as a local file system, no external clustering systems are
++needed, simply:
++
++ $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device
++ $ mount -t gfs2 /dev/block_device /dir
++
++GFS2 is not on-disk compatible with previous versions of GFS.
++
++The following man pages can be found at the URL above:
++ gfs2_fsck to repair a filesystem
++ gfs2_grow to expand a filesystem online
++ gfs2_jadd to add journals to a filesystem online
++ gfs2_tool to manipulate, examine and tune a filesystem
++ gfs2_quota to examine and change quota values in a filesystem
++ mount.gfs2 to help mount(8) mount a filesystem
++ mkfs.gfs2 to make a filesystem
+diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
+index 638cbd3..35f105b 100644
+--- a/Documentation/filesystems/ntfs.txt
++++ b/Documentation/filesystems/ntfs.txt
+@@ -13,7 +13,7 @@ Table of contents
+ - Using NTFS volume and stripe sets
+ - The Device-Mapper driver
+ - The Software RAID / MD driver
+- - Limitiations when using the MD driver
++ - Limitations when using the MD driver
+ - ChangeLog
+
+
+@@ -43,7 +43,7 @@ There is plenty of additional informatio
+ at http://linux-ntfs.sourceforge.net/
+
+ The web site has a lot of additional information, such as a comprehensive
+-FAQ, documentation on the NTFS on-disk format, informaiton on the Linux-NTFS
++FAQ, documentation on the NTFS on-disk format, information on the Linux-NTFS
+ userspace utilities, etc.
+
+
+@@ -383,14 +383,14 @@ Software RAID / MD driver. For which yo
+ appropriately (see man 5 raidtab).
+
+ Linear volume sets, i.e. linear raid, as well as stripe sets, i.e. raid level
+-0, have been tested and work fine (though see section "Limitiations when using
++0, have been tested and work fine (though see section "Limitations when using
+ the MD driver with NTFS volumes" especially if you want to use linear raid).
+ Even though untested, there is no reason why mirrors, i.e. raid level 1, and
+ stripes with parity, i.e. raid level 5, should not work, too.
+
+ You have to use the "persistent-superblock 0" option for each raid-disk in the
+ NTFS volume/stripe you are configuring in /etc/raidtab as the persistent
+-superblock used by the MD driver would damange the NTFS volume.
++superblock used by the MD driver would damage the NTFS volume.
+
+ Windows by default uses a stripe chunk size of 64k, so you probably want the
+ "chunk-size 64k" option for each raid-disk, too.
+@@ -435,7 +435,7 @@ setup correctly to avoid the possibility
+ ntfs volume.
+
+
+-Limitiations when using the Software RAID / MD driver
++Limitations when using the Software RAID / MD driver
+ -----------------------------------------------------
+
+ Using the md driver will not work properly if any of your NTFS partitions have
+diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
+index 99902ae..3355e69 100644
+--- a/Documentation/filesystems/proc.txt
++++ b/Documentation/filesystems/proc.txt
+@@ -39,6 +39,8 @@ Table of Contents
+ 2.9 Appletalk
+ 2.10 IPX
+ 2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
++ 2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
++ 2.13 /proc/<pid>/oom_score - Display current oom-killer score
+
+ ------------------------------------------------------------------------------
+ Preface
+@@ -408,7 +410,7 @@ VmallocChunk: 111088 kB
+ this memory, making it slower to access than lowmem.
+ LowTotal:
+ LowFree: Lowmem is memory which can be used for everything that
+- highmem can be used for, but it is also availble for the
++ highmem can be used for, but it is also available for the
+ kernel's use for its own data structures. Among many
+ other things, it is where everything from the Slab is
+ allocated. Bad things happen when you're out of lowmem.
+@@ -1124,11 +1126,15 @@ debugging information is displayed on co
+ NMI switch that most IA32 servers have fires unknown NMI up, for example.
+ If a system hangs up, try pressing the NMI switch.
+
+-[NOTE]
+- This function and oprofile share a NMI callback. Therefore this function
+- cannot be enabled when oprofile is activated.
+- And NMI watchdog will be disabled when the value in this file is set to
+- non-zero.
++nmi_watchdog
++------------
++
++Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero
++the NMI watchdog is enabled and will continuously test all online cpus to
++determine whether or not they are still functioning properly.
++
++Because the NMI watchdog shares registers with oprofile, by disabling the NMI
++watchdog, oprofile may have more registers to utilize.
+
+
+ 2.4 /proc/sys/vm - The virtual memory subsystem
+@@ -1249,7 +1255,7 @@ to allocate (but not use) more memory th
+ address space are refused. Used for a typical system. It
+ ensures a seriously wild allocation fails while allowing
+ overcommit to reduce swap usage. root is allowed to
+- allocate slighly more memory in this mode. This is the
++ allocate slightly more memory in this mode. This is the
+ default.
+
+ 1 - Always overcommit. Appropriate for some scientific
+@@ -1582,7 +1588,7 @@ Enable the strict RFC793 interpretatio
+ default is to use the BSD compatible interpretation of the urgent pointer
+ pointing to the first byte after the urgent data. The RFC793 interpretation is
+ to have it point to the last byte of urgent data. Enabling this option may
+-lead to interoperatibility problems. Disabled by default.
++lead to interoperability problems. Disabled by default.
+
+ tcp_syncookies
+ --------------
+@@ -1727,7 +1733,7 @@ error_burst and error_cost
+
+ These parameters are used to limit how many ICMP destination unreachable to
+ send from the host in question. ICMP destination unreachable messages are
+-sent when we can not reach the next hop, while trying to transmit a packet.
++sent when we cannot reach the next hop while trying to transmit a packet.
+ It will also print some error messages to kernel logs if someone is ignoring
+ our ICMP redirects. The higher the error_cost factor is, the fewer
+ destination unreachable and error messages will be let through. Error_burst
+@@ -1851,7 +1857,7 @@ proxy_qlen
+
+ Maximum queue length of the delayed proxy arp timer. (see proxy_delay).
+
+-app_solcit
++app_solicit
+ ----------
+
+ Determines the number of requests to send to the user level ARP daemon. Use 0
+@@ -1958,6 +1964,22 @@ a queue must be less or equal then msg_m
+ maximum message size value (it is every message queue's attribute set during
+ its creation).
+
++2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
++------------------------------------------------------
++
++This file can be used to adjust the score used to select which processes
++should be killed in an out-of-memory situation. Giving it a high score will
++increase the likelihood of this process being killed by the oom-killer. Valid
++values are in the range -16 to +15, plus the special value -17, which disables
++oom-killing altogether for this process.
++
++2.13 /proc/<pid>/oom_score - Display current oom-killer score
++-------------------------------------------------------------
++
++------------------------------------------------------------------------------
++This file can be used to check the current score used by the oom-killer is for
++any given <pid>. Use it together with /proc/<pid>/oom_adj to tune which
++process should be killed in an out-of-memory situation.
+
+ ------------------------------------------------------------------------------
+ Summary
+diff --git a/Documentation/filesystems/spufs.txt b/Documentation/filesystems/spufs.txt
+index 8edc395..982645a 100644
+--- a/Documentation/filesystems/spufs.txt
++++ b/Documentation/filesystems/spufs.txt
+@@ -84,7 +84,7 @@ FILES
+ /ibox
+ The second SPU to CPU communication mailbox. This file is similar to
+ the first mailbox file, but can be read in blocking I/O mode, and the
+- poll familiy of system calls can be used to wait for it. The possible
++ poll family of system calls can be used to wait for it. The possible
+ operations on an open ibox file are:
+
+ read(2)
+@@ -105,7 +105,7 @@ FILES
+
+
+ /wbox
+- The CPU to SPU communation mailbox. It is write-only can can be written
++ The CPU to SPU communation mailbox. It is write-only and can be written
+ in units of 32 bits. If the mailbox is full, write() will block and
+ poll can be used to wait for it becoming empty again. The possible
+ operations on an open wbox file are: write(2) If a count smaller than
+@@ -359,7 +359,7 @@ ERRORS
+ EFAULT npc is not a valid pointer or status is neither NULL nor a valid
+ pointer.
+
+- EINTR A signal occured while spu_run was in progress. The npc value
++ EINTR A signal occurred while spu_run was in progress. The npc value
+ has been updated to the new program counter value if necessary.
+
+ EINVAL fd is not a file descriptor returned from spu_create(2).
+diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt
+index 89b1d19..4b5ca26 100644
+--- a/Documentation/filesystems/sysfs.txt
++++ b/Documentation/filesystems/sysfs.txt
+@@ -238,7 +238,7 @@ Top Level Directory Layout
+ The sysfs directory arrangement exposes the relationship of kernel
+ data structures.
+
+-The top level sysfs diretory looks like:
++The top level sysfs directory looks like:
+
+ block/
+ bus/
+diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt
+index 1773106..6dd0508 100644
+--- a/Documentation/filesystems/tmpfs.txt
++++ b/Documentation/filesystems/tmpfs.txt
+@@ -39,7 +39,7 @@ tmpfs has the following uses:
+ tmpfs /dev/shm tmpfs defaults 0 0
+
+ Remember to create the directory that you intend to mount tmpfs on
+- if necessary (/dev/shm is automagically created if you use devfs).
++ if necessary.
+
+ This mount is _not_ needed for SYSV shared memory. The internal
+ mount is used for that. (In the 2.3 kernel versions it was
+@@ -63,7 +63,7 @@ size: The limit of allocated bytes
+ nr_blocks: The same as size, but in blocks of PAGE_CACHE_SIZE.
+ nr_inodes: The maximum number of inodes for this instance. The default
+ is half of the number of your physical RAM pages, or (on a
+- a machine with highmem) the number of lowmem RAM pages,
++ machine with highmem) the number of lowmem RAM pages,
+ whichever is the lower.
+
+ These parameters accept a suffix k, m or g for kilo, mega and giga and
+diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
+index 2001abb..069cb10 100644
+--- a/Documentation/filesystems/vfat.txt
++++ b/Documentation/filesystems/vfat.txt
+@@ -35,7 +35,7 @@ iocharset=name -- Character set to use f
+ you should consider the following option instead.
+
+ utf8=<bool> -- UTF-8 is the filesystem safe version of Unicode that
+- is used by the console. It can be be enabled for the
++ is used by the console. It can be enabled for the
+ filesystem with this option. If 'uni_xlate' gets set,
+ UTF-8 gets disabled.
+
+diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
+index 1cb7e8b..7737bfd 100644
+--- a/Documentation/filesystems/vfs.txt
++++ b/Documentation/filesystems/vfs.txt
+@@ -410,7 +410,7 @@ otherwise noted.
+
+ put_link: called by the VFS to release resources allocated by
+ follow_link(). The cookie returned by follow_link() is passed
+- to to this method as the last parameter. It is used by
++ to this method as the last parameter. It is used by
+ filesystems such as NFS where page cache is not stable
+ (i.e. page that was installed when the symbolic link walk
+ started might not be in the page cache at the end of the
+@@ -699,9 +699,9 @@ This describes how the VFS can manipulat
+ struct file_operations {
+ loff_t (*llseek) (struct file *, loff_t, int);
+ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+- ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
+ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+- ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
++ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
++ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ int (*readdir) (struct file *, void *, filldir_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+diff --git a/Documentation/fujitsu/frv/mmu-layout.txt b/Documentation/fujitsu/frv/mmu-layout.txt
+index 11dcc56..db10250 100644
+--- a/Documentation/fujitsu/frv/mmu-layout.txt
++++ b/Documentation/fujitsu/frv/mmu-layout.txt
+@@ -233,7 +233,7 @@ related kernel services:
+ (*) __debug_mmu.iamr[]
+ (*) __debug_mmu.damr[]
+
+- These receive the current IAMR and DAMR contents. These can be viewed with with the _amr
++ These receive the current IAMR and DAMR contents. These can be viewed with the _amr
+ GDB macro:
+
+ (gdb) _amr
+diff --git a/Documentation/highuid.txt b/Documentation/highuid.txt
+index 2c33926..76034d9 100644
+--- a/Documentation/highuid.txt
++++ b/Documentation/highuid.txt
+@@ -57,7 +57,7 @@ What's left to be done for 32-bit UIDs o
+
+ Other filesystems have not been checked yet.
+
+-- The ncpfs and smpfs filesystems can not presently use 32-bit UIDs in
++- The ncpfs and smpfs filesystems cannot presently use 32-bit UIDs in
+ all ioctl()s. Some new ioctl()s have been added with 32-bit UIDs, but
+ more are needed. (as well as new user<->kernel data structures)
+
+diff --git a/Documentation/hrtimers.txt b/Documentation/hrtimers.txt
+index 7620ff7..ce31f65 100644
+--- a/Documentation/hrtimers.txt
++++ b/Documentation/hrtimers.txt
+@@ -10,7 +10,7 @@ back and forth trying to integrate high-
+ features into the existing timer framework, and after testing various
+ such high-resolution timer implementations in practice, we came to the
+ conclusion that the timer wheel code is fundamentally not suitable for
+-such an approach. We initially didnt believe this ('there must be a way
++such an approach. We initially didn't believe this ('there must be a way
+ to solve this'), and spent a considerable effort trying to integrate
+ things into the timer wheel, but we failed. In hindsight, there are
+ several reasons why such integration is hard/impossible:
+@@ -27,7 +27,7 @@ several reasons why such integration is
+ high-res timers.
+
+ - the unpredictable [O(N)] overhead of cascading leads to delays which
+- necessiate a more complex handling of high resolution timers, which
++ necessitate a more complex handling of high resolution timers, which
+ in turn decreases robustness. Such a design still led to rather large
+ timing inaccuracies. Cascading is a fundamental property of the timer
+ wheel concept, it cannot be 'designed out' without unevitably
+@@ -58,7 +58,7 @@ several reasons why such integration is
+ The primary users of precision timers are user-space applications that
+ utilize nanosleep, posix-timers and itimer interfaces. Also, in-kernel
+ users like drivers and subsystems which require precise timed events
+-(e.g. multimedia) can benefit from the availability of a seperate
++(e.g. multimedia) can benefit from the availability of a separate
+ high-resolution timer subsystem as well.
+
+ While this subsystem does not offer high-resolution clock sources just
+@@ -68,7 +68,7 @@ The increasing demand for realtime and m
+ with other potential users for precise timers gives another reason to
+ separate the "timeout" and "precise timer" subsystems.
+
+-Another potential benefit is that such a seperation allows even more
++Another potential benefit is that such a separation allows even more
+ special-purpose optimization of the existing timer wheel for the low
+ resolution and low precision use cases - once the precision-sensitive
+ APIs are separated from the timer wheel and are migrated over to
+@@ -96,8 +96,8 @@ file systems. The rbtree is solely used
+ a separate list is used to give the expiry code fast access to the
+ queued timers, without having to walk the rbtree.
+
+-(This seperate list is also useful for later when we'll introduce
+-high-resolution clocks, where we need seperate pending and expired
++(This separate list is also useful for later when we'll introduce
++high-resolution clocks, where we need separate pending and expired
+ queues while keeping the time-order intact.)
+
+ Time-ordered enqueueing is not purely for the purposes of
+diff --git a/Documentation/hwmon/adm9240 b/Documentation/hwmon/adm9240
+index 35f618f..2c6f1fe 100644
+--- a/Documentation/hwmon/adm9240
++++ b/Documentation/hwmon/adm9240
+@@ -24,7 +24,7 @@ Authors:
+ Frodo Looijaard <frodol at dds.nl>,
+ Philip Edelbrock <phil at netroedge.com>,
+ Michiel Rook <michiel at grendelproject.nl>,
+- Grant Coady <gcoady at gmail.com> with guidance
++ Grant Coady <gcoady.lk at gmail.com> with guidance
+ from Jean Delvare <khali at linux-fr.org>
+
+ Interface
+diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f
+index 28c5b7d..2ca69df 100644
+--- a/Documentation/hwmon/f71805f
++++ b/Documentation/hwmon/f71805f
+@@ -17,7 +17,7 @@ Thanks to Kris Chen from Fintek for answ
+ providing additional documentation.
+
+ Thanks to Chris Lin from Jetway for providing wiring schematics and
+-anwsering technical questions.
++answering technical questions.
+
+
+ Description
+diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
+index 9555be1..e783fd6 100644
+--- a/Documentation/hwmon/it87
++++ b/Documentation/hwmon/it87
+@@ -13,12 +13,25 @@ Supported chips:
+ from Super I/O config space (8 I/O ports)
+ Datasheet: Publicly available at the ITE website
+ http://www.ite.com.tw/
++ * IT8716F
++ Prefix: 'it8716'
++ Addresses scanned: from Super I/O config space (8 I/O ports)
++ Datasheet: Publicly available at the ITE website
++ http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP
++ * IT8718F
++ Prefix: 'it8718'
++ Addresses scanned: from Super I/O config space (8 I/O ports)
++ Datasheet: Publicly available at the ITE website
++ http://www.ite.com.tw/product_info/file/pc/IT8718F_V0.2.zip
++ http://www.ite.com.tw/product_info/file/pc/IT8718F_V0%203_(for%20C%20version).zip
+ * SiS950 [clone of IT8705F]
+ Prefix: 'it87'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: No longer be available
+
+-Author: Christophe Gauthron <chrisg at 0-in.com>
++Authors:
++ Christophe Gauthron <chrisg at 0-in.com>
++ Jean Delvare <khali at linux-fr.org>
+
+
+ Module Parameters
+@@ -43,26 +56,46 @@ Module Parameters
+ Description
+ -----------
+
+-This driver implements support for the IT8705F, IT8712F and SiS950 chips.
+-
+-This driver also supports IT8712F, which adds SMBus access, and a VID
+-input, used to report the Vcore voltage of the Pentium processor.
+-The IT8712F additionally features VID inputs.
++This driver implements support for the IT8705F, IT8712F, IT8716F,
++IT8718F and SiS950 chips.
+
+ These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
+ joysticks and other miscellaneous stuff. For hardware monitoring, they
+ include an 'environment controller' with 3 temperature sensors, 3 fan
+ rotation speed sensors, 8 voltage sensors, and associated alarms.
+
++The IT8712F and IT8716F additionally feature VID inputs, used to report
++the Vcore voltage of the processor. The early IT8712F have 5 VID pins,
++the IT8716F and late IT8712F have 6. They are shared with other functions
++though, so the functionality may not be available on a given system.
++The driver dumbly assume it is there.
++
++The IT8718F also features VID inputs (up to 8 pins) but the value is
++stored in the Super-I/O configuration space. Due to technical limitations,
++this value can currently only be read once at initialization time, so
++the driver won't notice and report changes in the VID value. The two
++upper VID bits share their pins with voltage inputs (in5 and in6) so you
++can't have both on a given board.
++
++The IT8716F, IT8718F and later IT8712F revisions have support for
++2 additional fans. They are not yet supported by the driver.
++
++The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
++16-bit tachometer counters for fans 1 to 3. This is better (no more fan
++clock divider mess) but not compatible with the older chips and
++revisions. For now, the driver only uses the 16-bit mode on the
++IT8716F and IT8718F.
++
+ Temperatures are measured in degrees Celsius. An alarm is triggered once
+ when the Overtemperature Shutdown limit is crossed.
+
+ Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+-triggered if the rotation speed has dropped below a programmable limit. Fan
+-readings can be divided by a programmable divider (1, 2, 4 or 8) to give the
+-readings more range or accuracy. Not all RPM values can accurately be
+-represented, so some rounding is done. With a divider of 2, the lowest
+-representable value is around 2600 RPM.
++triggered if the rotation speed has dropped below a programmable limit. When
++16-bit tachometer counters aren't used, fan readings can be divided by
++a programmable divider (1, 2, 4 or 8) to give the readings more range or
++accuracy. With a divider of 2, the lowest representable value is around
++2600 RPM. Not all RPM values can accurately be represented, so some rounding
++is done.
+
+ Voltage sensors (also known as IN sensors) report their values in volts. An
+ alarm is triggered if the voltage has crossed a programmable minimum or
+@@ -71,9 +104,9 @@ zero'; this is important for negative vo
+ inputs can measure voltages between 0 and 4.08 volts, with a resolution of
+ 0.016 volt. The battery voltage in8 does not have limit registers.
+
+-The VID lines (IT8712F only) encode the core voltage value: the voltage
+-level your processor should work with. This is hardcoded by the mainboard
+-and/or processor itself. It is a value in volts.
++The VID lines (IT8712F/IT8716F/IT8718F) encode the core voltage value:
++the voltage level your processor should work with. This is hardcoded by
++the mainboard and/or processor itself. It is a value in volts.
+
+ If an alarm triggers, it will remain triggered until the hardware register
+ is read at least once. This means that the cause for the alarm may already
+diff --git a/Documentation/hwmon/k8temp b/Documentation/hwmon/k8temp
+new file mode 100644
+index 0000000..30d123b
+--- /dev/null
++++ b/Documentation/hwmon/k8temp
+@@ -0,0 +1,55 @@
++Kernel driver k8temp
++====================
++
++Supported chips:
++ * AMD Athlon64/FX or Opteron CPUs
++ Prefix: 'k8temp'
++ Addresses scanned: PCI space
++ Datasheet: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
++
++Author: Rudolf Marek
++Contact: Rudolf Marek <r.marek at sh.cvut.cz>
++
++Description
++-----------
++
++This driver permits reading temperature sensor(s) embedded inside AMD K8
++family CPUs (Athlon64/FX, Opteron). Official documentation says that it works
++from revision F of K8 core, but in fact it seems to be implemented for all
++revisions of K8 except the first two revisions (SH-B0 and SH-B3).
++
++Please note that you will need at least lm-sensors 2.10.1 for proper userspace
++support.
++
++There can be up to four temperature sensors inside single CPU. The driver
++will auto-detect the sensors and will display only temperatures from
++implemented sensors.
++
++Mapping of /sys files is as follows:
++
++temp1_input - temperature of Core 0 and "place" 0
++temp2_input - temperature of Core 0 and "place" 1
++temp3_input - temperature of Core 1 and "place" 0
++temp4_input - temperature of Core 1 and "place" 1
++
++Temperatures are measured in degrees Celsius and measurement resolution is
++1 degree C. It is expected that future CPU will have better resolution. The
++temperature is updated once a second. Valid temperatures are from -49 to
++206 degrees C.
++
++Temperature known as TCaseMax was specified for processors up to revision E.
++This temperature is defined as temperature between heat-spreader and CPU
++case, so the internal CPU temperature supplied by this driver can be higher.
++There is no easy way how to measure the temperature which will correlate
++with TCaseMax temperature.
++
++For newer revisions of CPU (rev F, socket AM2) there is a mathematically
++computed temperature called TControl, which must be lower than TControlMax.
++
++The relationship is following:
++
++temp1_input - TjOffset*2 < TControlMax,
++
++TjOffset is not yet exported by the driver, TControlMax is usually
++70 degrees C. The rule of the thumb -> CPU temperature should not cross
++60 degrees C too much.
+diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1
+index c15bbe6..04a1112 100644
+--- a/Documentation/hwmon/smsc47m1
++++ b/Documentation/hwmon/smsc47m1
+@@ -2,12 +2,14 @@ Kernel driver smsc47m1
+ ======================
+
+ Supported chips:
+- * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192
++ * SMSC LPC47B27x, LPC47M112, LPC47M10x, LPC47M13x, LPC47M14x,
++ LPC47M15x and LPC47M192
+ Addresses scanned: none, address read from Super I/O config space
+ Prefix: 'smsc47m1'
+ Datasheets:
+ http://www.smsc.com/main/datasheets/47b27x.pdf
+ http://www.smsc.com/main/datasheets/47m10x.pdf
++ http://www.smsc.com/main/datasheets/47m112.pdf
+ http://www.smsc.com/main/tools/discontinued/47m13x.pdf
+ http://www.smsc.com/main/datasheets/47m14x.pdf
+ http://www.smsc.com/main/tools/discontinued/47m15x.pdf
+diff --git a/Documentation/hwmon/vt1211 b/Documentation/hwmon/vt1211
+new file mode 100644
+index 0000000..77fa633
+--- /dev/null
++++ b/Documentation/hwmon/vt1211
+@@ -0,0 +1,206 @@
++Kernel driver vt1211
++====================
++
++Supported chips:
++ * VIA VT1211
++ Prefix: 'vt1211'
++ Addresses scanned: none, address read from Super-I/O config space
++ Datasheet: Provided by VIA upon request and under NDA
++
++Authors: Juerg Haefliger <juergh at gmail.com>
++
++This driver is based on the driver for kernel 2.4 by Mark D. Studebaker and
++its port to kernel 2.6 by Lars Ekman.
++
++Thanks to Joseph Chan and Fiona Gatt from VIA for providing documentation and
++technical support.
++
++
++Module Parameters
++-----------------
++
++* uch_config: int Override the BIOS default universal channel (UCH)
++ configuration for channels 1-5.
++ Legal values are in the range of 0-31. Bit 0 maps to
++ UCH1, bit 1 maps to UCH2 and so on. Setting a bit to 1
++ enables the thermal input of that particular UCH and
++ setting a bit to 0 enables the voltage input.
++
++* int_mode: int Override the BIOS default temperature interrupt mode.
++ The only possible value is 0 which forces interrupt
++ mode 0. In this mode, any pending interrupt is cleared
++ when the status register is read but is regenerated as
++ long as the temperature stays above the hysteresis
++ limit.
++
++Be aware that overriding BIOS defaults might cause some unwanted side effects!
++
++
++Description
++-----------
++
++The VIA VT1211 Super-I/O chip includes complete hardware monitoring
++capabilities. It monitors 2 dedicated temperature sensor inputs (temp1 and
++temp2), 1 dedicated voltage (in5) and 2 fans. Additionally, the chip
++implements 5 universal input channels (UCH1-5) that can be individually
++programmed to either monitor a voltage or a temperature.
++
++This chip also provides manual and automatic control of fan speeds (according
++to the datasheet). The driver only supports automatic control since the manual
++mode doesn't seem to work as advertised in the datasheet. In fact I couldn't
++get manual mode to work at all! Be aware that automatic mode hasn't been
++tested very well (due to the fact that my EPIA M10000 doesn't have the fans
++connected to the PWM outputs of the VT1211 :-().
++
++The following table shows the relationship between the vt1211 inputs and the
++sysfs nodes.
++
++Sensor Voltage Mode Temp Mode Default Use (from the datasheet)
++------ ------------ --------- --------------------------------
++Reading 1 temp1 Intel thermal diode
++Reading 3 temp2 Internal thermal diode
++UCH1/Reading2 in0 temp3 NTC type thermistor
++UCH2 in1 temp4 +2.5V
++UCH3 in2 temp5 VccP (processor core)
++UCH4 in3 temp6 +5V
++UCH5 in4 temp7 +12V
+++3.3V in5 Internal VCC (+3.3V)
++
++
++Voltage Monitoring
++------------------
++
++Voltages are sampled by an 8-bit ADC with a LSB of ~10mV. The supported input
++range is thus from 0 to 2.60V. Voltage values outside of this range need
++external scaling resistors. This external scaling needs to be compensated for
++via compute lines in sensors.conf, like:
++
++compute inx @*(1+R1/R2), @/(1+R1/R2)
++
++The board level scaling resistors according to VIA's recommendation are as
++follows. And this is of course totally dependent on the actual board
++implementation :-) You will have to find documentation for your own
++motherboard and edit sensors.conf accordingly.
++
++ Expected
++Voltage R1 R2 Divider Raw Value
++-----------------------------------------------
+++2.5V 2K 10K 1.2 2083 mV
++VccP --- --- 1.0 1400 mV (1)
+++5V 14K 10K 2.4 2083 mV
+++12V 47K 10K 5.7 2105 mV
+++3.3V (int) 2K 3.4K 1.588 3300 mV (2)
+++3.3V (ext) 6.8K 10K 1.68 1964 mV
++
++(1) Depending on the CPU (1.4V is for a VIA C3 Nehemiah).
++(2) R1 and R2 for 3.3V (int) are internal to the VT1211 chip and the driver
++ performs the scaling and returns the properly scaled voltage value.
++
++Each measured voltage has an associated low and high limit which triggers an
++alarm when crossed.
++
++
++Temperature Monitoring
++----------------------
++
++Temperatures are reported in millidegree Celsius. Each measured temperature
++has a high limit which triggers an alarm if crossed. There is an associated
++hysteresis value with each temperature below which the temperature has to drop
++before the alarm is cleared (this is only true for interrupt mode 0). The
++interrupt mode can be forced to 0 in case the BIOS doesn't do it
++automatically. See the 'Module Parameters' section for details.
++
++All temperature channels except temp2 are external. Temp2 is the VT1211
++internal thermal diode and the driver does all the scaling for temp2 and
++returns the temperature in millidegree Celsius. For the external channels
++temp1 and temp3-temp7, scaling depends on the board implementation and needs
++to be performed in userspace via sensors.conf.
++
++Temp1 is an Intel-type thermal diode which requires the following formula to
++convert between sysfs readings and real temperatures:
++
++compute temp1 (@-Offset)/Gain, (@*Gain)+Offset
++
++According to the VIA VT1211 BIOS porting guide, the following gain and offset
++values should be used:
++
++Diode Type Offset Gain
++---------- ------ ----
++Intel CPU 88.638 0.9528
++ 65.000 0.9686 *)
++VIA C3 Ezra 83.869 0.9528
++VIA C3 Ezra-T 73.869 0.9528
++
++*) This is the formula from the lm_sensors 2.10.0 sensors.conf file. I don't
++know where it comes from or how it was derived, it's just listed here for
++completeness.
++
++Temp3-temp7 support NTC thermistors. For these channels, the driver returns
++the voltages as seen at the individual pins of UCH1-UCH5. The voltage at the
++pin (Vpin) is formed by a voltage divider made of the thermistor (Rth) and a
++scaling resistor (Rs):
++
++Vpin = 2200 * Rth / (Rs + Rth) (2200 is the ADC max limit of 2200 mV)
++
++The equation for the thermistor is as follows (google it if you want to know
++more about it):
++
++Rth = Ro * exp(B * (1 / T - 1 / To)) (To is 298.15K (25C) and Ro is the
++ nominal resistance at 25C)
++
++Mingling the above two equations and assuming Rs = Ro and B = 3435 yields the
++following formula for sensors.conf:
++
++compute tempx 1 / (1 / 298.15 - (` (2200 / @ - 1)) / 3435) - 273.15,
++ 2200 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
++
++
++Fan Speed Control
++-----------------
++
++The VT1211 provides 2 programmable PWM outputs to control the speeds of 2
++fans. Writing a 2 to any of the two pwm[1-2]_enable sysfs nodes will put the
++PWM controller in automatic mode. There is only a single controller that
++controls both PWM outputs but each PWM output can be individually enabled and
++disabled.
++
++Each PWM has 4 associated distinct output duty-cycles: full, high, low and
++off. Full and off are internally hard-wired to 255 (100%) and 0 (0%),
++respectively. High and low can be programmed via
++pwm[1-2]_auto_point[2-3]_pwm. Each PWM output can be associated with a
++different thermal input but - and here's the weird part - only one set of
++thermal thresholds exist that controls both PWMs output duty-cycles. The
++thermal thresholds are accessible via pwm[1-2]_auto_point[1-4]_temp. Note
++that even though there are 2 sets of 4 auto points each, they map to the same
++registers in the VT1211 and programming one set is sufficient (actually only
++the first set pwm1_auto_point[1-4]_temp is writable, the second set is
++read-only).
++
++PWM Auto Point PWM Output Duty-Cycle
++------------------------------------------------
++pwm[1-2]_auto_point4_pwm full speed duty-cycle (hard-wired to 255)
++pwm[1-2]_auto_point3_pwm high speed duty-cycle
++pwm[1-2]_auto_point2_pwm low speed duty-cycle
++pwm[1-2]_auto_point1_pwm off duty-cycle (hard-wired to 0)
++
++Temp Auto Point Thermal Threshold
++---------------------------------------------
++pwm[1-2]_auto_point4_temp full speed temp
++pwm[1-2]_auto_point3_temp high speed temp
++pwm[1-2]_auto_point2_temp low speed temp
++pwm[1-2]_auto_point1_temp off temp
++
++Long story short, the controller implements the following algorithm to set the
++PWM output duty-cycle based on the input temperature:
++
++Thermal Threshold Output Duty-Cycle
++ (Rising Temp) (Falling Temp)
++----------------------------------------------------------
++ full speed duty-cycle full speed duty-cycle
++full speed temp
++ high speed duty-cycle full speed duty-cycle
++high speed temp
++ low speed duty-cycle high speed duty-cycle
++low speed temp
++ off duty-cycle low speed duty-cycle
++off temp
+diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
+new file mode 100644
+index 0000000..caa610a
+--- /dev/null
++++ b/Documentation/hwmon/w83627ehf
+@@ -0,0 +1,85 @@
++Kernel driver w83627ehf
++=======================
++
++Supported chips:
++ * Winbond W83627EHF/EHG (ISA access ONLY)
++ Prefix: 'w83627ehf'
++ Addresses scanned: ISA address retrieved from Super I/O registers
++ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
++
++Authors:
++ Jean Delvare <khali at linux-fr.org>
++ Yuan Mu (Winbond)
++ Rudolf Marek <r.marek at sh.cvut.cz>
++
++Description
++-----------
++
++This driver implements support for the Winbond W83627EHF and W83627EHG
++super I/O chips. We will refer to them collectively as Winbond chips.
++
++The chips implement three temperature sensors, five fan rotation
++speed sensors, ten analog voltage sensors, alarms with beep warnings (control
++unimplemented), and some automatic fan regulation strategies (plus manual
++fan control mode).
++
++Temperatures are measured in degrees Celsius and measurement resolution is 1
++degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
++the temperature gets higher than high limit; it stays on until the temperature
++falls below the hysteresis value.
++
++Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
++triggered if the rotation speed has dropped below a programmable limit. Fan
++readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or
++128) to give the readings more range or accuracy. The driver sets the most
++suitable fan divisor itself. Some fans might not be present because they
++share pins with other functions.
++
++Voltage sensors (also known as IN sensors) report their values in millivolts.
++An alarm is triggered if the voltage has crossed a programmable minimum
++or maximum limit.
++
++The driver supports automatic fan control mode known as Thermal Cruise.
++In this mode, the chip attempts to keep the measured temperature in a
++predefined temperature range. If the temperature goes out of range, fan
++is driven slower/faster to reach the predefined range again.
++
++The mode works for fan1-fan4. Mapping of temperatures to pwm outputs is as
++follows:
++
++temp1 -> pwm1
++temp2 -> pwm2
++temp3 -> pwm3
++prog -> pwm4 (the programmable setting is not supported by the driver)
++
++/sys files
++----------
++
++pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
++ 0 (stop) to 255 (full)
++
++pwm[1-4]_enable - this file controls mode of fan/temperature control:
++ * 1 Manual Mode, write to pwm file any value 0-255 (full speed)
++ * 2 Thermal Cruise
++
++Thermal Cruise mode
++-------------------
++
++If the temperature is in the range defined by:
++
++pwm[1-4]_target - set target temperature, unit millidegree Celsius
++ (range 0 - 127000)
++pwm[1-4]_tolerance - tolerance, unit millidegree Celsius (range 0 - 15000)
++
++there are no changes to fan speed. Once the temperature leaves the interval,
++fan speed increases (temp is higher) or decreases if lower than desired.
++There are defined steps and times, but not exported by the driver yet.
++
++pwm[1-4]_min_output - minimum fan speed (range 1 - 255), when the temperature
++ is below defined range.
++pwm[1-4]_stop_time - how many milliseconds [ms] must elapse to switch
++ corresponding fan off. (when the temperature was below
++ defined range).
++
++Note: last two functions are influenced by other control bits, not yet exported
++ by the driver, so a change might not have any effect.
+diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d
+index 83a3836..19b2ed7 100644
+--- a/Documentation/hwmon/w83791d
++++ b/Documentation/hwmon/w83791d
+@@ -5,7 +5,7 @@ Supported chips:
+ * Winbond W83791D
+ Prefix: 'w83791d'
+ Addresses scanned: I2C 0x2c - 0x2f
+- Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791Da.pdf
++ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791D_W83791Gb.pdf
+
+ Author: Charles Spirakis <bezaur at gmail.com>
+
+@@ -20,6 +20,9 @@ Credits:
+ Chunhao Huang <DZShen at Winbond.com.tw>,
+ Rudolf Marek <r.marek at sh.cvut.cz>
+
++Additional contributors:
++ Sven Anders <anders at anduras.de>
++
+ Module Parameters
+ -----------------
+
+@@ -46,7 +49,8 @@ Module Parameters
+ Description
+ -----------
+
+-This driver implements support for the Winbond W83791D chip.
++This driver implements support for the Winbond W83791D chip. The W83791G
++chip appears to be the same as the W83791D but is lead free.
+
+ Detection of the chip can sometimes be foiled because it can be in an
+ internal state that allows no clean access (Bank with ID register is not
+@@ -71,34 +75,36 @@ Voltage sensors (also known as IN sensor
+ An alarm is triggered if the voltage has crossed a programmable minimum
+ or maximum limit.
+
+-Alarms are provided as output from a "realtime status register". The
+-following bits are defined:
+-
+-bit - alarm on:
+-0 - Vcore
+-1 - VINR0
+-2 - +3.3VIN
+-3 - 5VDD
+-4 - temp1
+-5 - temp2
+-6 - fan1
+-7 - fan2
+-8 - +12VIN
+-9 - -12VIN
+-10 - -5VIN
+-11 - fan3
+-12 - chassis
+-13 - temp3
+-14 - VINR1
+-15 - reserved
+-16 - tart1
+-17 - tart2
+-18 - tart3
+-19 - VSB
+-20 - VBAT
+-21 - fan4
+-22 - fan5
+-23 - reserved
++The bit ordering for the alarm "realtime status register" and the
++"beep enable registers" are different.
++
++in0 (VCORE) : alarms: 0x000001 beep_enable: 0x000001
++in1 (VINR0) : alarms: 0x000002 beep_enable: 0x002000 <== mismatch
++in2 (+3.3VIN): alarms: 0x000004 beep_enable: 0x000004
++in3 (5VDD) : alarms: 0x000008 beep_enable: 0x000008
++in4 (+12VIN) : alarms: 0x000100 beep_enable: 0x000100
++in5 (-12VIN) : alarms: 0x000200 beep_enable: 0x000200
++in6 (-5VIN) : alarms: 0x000400 beep_enable: 0x000400
++in7 (VSB) : alarms: 0x080000 beep_enable: 0x010000 <== mismatch
++in8 (VBAT) : alarms: 0x100000 beep_enable: 0x020000 <== mismatch
++in9 (VINR1) : alarms: 0x004000 beep_enable: 0x004000
++temp1 : alarms: 0x000010 beep_enable: 0x000010
++temp2 : alarms: 0x000020 beep_enable: 0x000020
++temp3 : alarms: 0x002000 beep_enable: 0x000002 <== mismatch
++fan1 : alarms: 0x000040 beep_enable: 0x000040
++fan2 : alarms: 0x000080 beep_enable: 0x000080
++fan3 : alarms: 0x000800 beep_enable: 0x000800
++fan4 : alarms: 0x200000 beep_enable: 0x200000
++fan5 : alarms: 0x400000 beep_enable: 0x400000
++tart1 : alarms: 0x010000 beep_enable: 0x040000 <== mismatch
++tart2 : alarms: 0x020000 beep_enable: 0x080000 <== mismatch
++tart3 : alarms: 0x040000 beep_enable: 0x100000 <== mismatch
++case_open : alarms: 0x001000 beep_enable: 0x001000
++user_enable : alarms: -------- beep_enable: 0x800000
++
++*** NOTE: It is the responsibility of user-space code to handle the fact
++that the beep enable and alarm bits are in different positions when using that
++feature of the chip.
+
+ When an alarm goes off, you can be warned by a beeping signal through your
+ computer speaker. It is possible to enable all beeping globally, or only
+@@ -109,5 +115,6 @@ often will do no harm, but will return '
+
+ W83791D TODO:
+ ---------------
+-Provide a patch for per-file alarms as discussed on the mailing list
++Provide a patch for per-file alarms and beep enables as defined in the hwmon
++ documentation (Documentation/hwmon/sysfs-interface)
+ Provide a patch for smart-fan control (still need appropriate motherboard/fans)
+diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
+index 1677566..2568034 100644
+--- a/Documentation/i2c/busses/i2c-viapro
++++ b/Documentation/i2c/busses/i2c-viapro
+@@ -7,9 +7,12 @@ Supported adapters:
+ * VIA Technologies, Inc. VT82C686A/B
+ Datasheet: Sometimes available at the VIA website
+
+- * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R
++ * VIA Technologies, Inc. VT8231, VT8233, VT8233A
+ Datasheet: available on request from VIA
+
++ * VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251
++ Datasheet: available on request and under NDA from VIA
++
+ Authors:
+ Kyösti Mälkki <kmalkki at cc.hut.fi>,
+ Mark D. Studebaker <mdsxyz123 at yahoo.com>,
+@@ -39,6 +42,8 @@ Your lspci -n listing must show one of t
+ device 1106:8235 (VT8231 function 4)
+ device 1106:3177 (VT8235)
+ device 1106:3227 (VT8237R)
++ device 1106:3337 (VT8237A)
++ device 1106:3287 (VT8251)
+
+ If none of these show up, you should look in the BIOS for settings like
+ enable ACPI / SMBus or even USB.
+diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub
+index d6dcb13..9cc081e 100644
+--- a/Documentation/i2c/i2c-stub
++++ b/Documentation/i2c/i2c-stub
+@@ -6,9 +6,12 @@ This module is a very simple fake I2C/SM
+ types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
+ (r/w) word data.
+
++You need to provide a chip address as a module parameter when loading
++this driver, which will then only react to SMBus commands to this address.
++
+ No hardware is needed nor associated with this module. It will accept write
+-quick commands to all addresses; it will respond to the other commands (also
+-to all addresses) by reading from or writing to an array in memory. It will
++quick commands to one address; it will respond to the other commands (also
++to one address) by reading from or writing to an array in memory. It will
+ also spam the kernel logs for every command it handles.
+
+ A pointer register with auto-increment is implemented for all byte
+@@ -21,6 +24,11 @@ The typical use-case is like this:
+ 3. load the target sensors chip driver module
+ 4. observe its behavior in the kernel log
+
++PARAMETERS:
++
++int chip_addr:
++ The SMBus address to emulate a chip at.
++
+ CAVEATS:
+
+ There are independent arrays for byte/data and word/data commands. Depending
+@@ -33,6 +41,9 @@ If the hardware for your driver has bank
+ chips) this module will not work well - although it could be extended to
+ support that pretty easily.
+
++Only one chip address is supported - although this module could be
++extended to support more.
++
+ If you spam it hard enough, printk can be lossy. This module really wants
+ something like relayfs.
+
+diff --git a/Documentation/ia64/efirtc.txt b/Documentation/ia64/efirtc.txt
+index ede2c1e..057e6be 100644
+--- a/Documentation/ia64/efirtc.txt
++++ b/Documentation/ia64/efirtc.txt
+@@ -26,7 +26,7 @@ to initialize the system view of the tim
+ Because we wanted to minimize the impact on existing user-level apps using
+ the CMOS clock, we decided to expose an API that was very similar to the one
+ used today with the legacy RTC driver (driver/char/rtc.c). However, because
+-EFI provides a simpler services, not all all ioctl() are available. Also
++EFI provides a simpler services, not all ioctl() are available. Also
+ new ioctl()s have been introduced for things that EFI provides but not the
+ legacy.
+
+diff --git a/Documentation/ia64/fsys.txt b/Documentation/ia64/fsys.txt
+index 28da181..59dd689 100644
+--- a/Documentation/ia64/fsys.txt
++++ b/Documentation/ia64/fsys.txt
+@@ -165,7 +165,7 @@ complicated cases.
+ * Signal handling
+
+ The delivery of (asynchronous) signals must be delayed until fsys-mode
+-is exited. This is acomplished with the help of the lower-privilege
++is exited. This is accomplished with the help of the lower-privilege
+ transfer trap: arch/ia64/kernel/process.c:do_notify_resume_user()
+ checks whether the interrupted task was in fsys-mode and, if so, sets
+ PSR.lp and returns immediately. When fsys-mode is exited via the
+diff --git a/Documentation/ia64/mca.txt b/Documentation/ia64/mca.txt
+index a71cc6a..f097c60 100644
+--- a/Documentation/ia64/mca.txt
++++ b/Documentation/ia64/mca.txt
+@@ -12,7 +12,7 @@ by locks is indeterminate, including lin
+ ---
+
+ The complicated ia64 MCA process. All of this is mandated by Intel's
+-specification for ia64 SAL, error recovery and and unwind, it is not as
++specification for ia64 SAL, error recovery and unwind, it is not as
+ if we have a choice here.
+
+ * MCA occurs on one cpu, usually due to a double bit memory error.
+@@ -94,7 +94,7 @@ if we have a choice here.
+
+ INIT is less complicated than MCA. Pressing the nmi button or using
+ the equivalent command on the management console sends INIT to all
+-cpus. SAL picks one one of the cpus as the monarch and the rest are
++cpus. SAL picks one of the cpus as the monarch and the rest are
+ slaves. All the OS INIT handlers are entered at approximately the same
+ time. The OS monarch prints the state of all tasks and returns, after
+ which the slaves return and the system resumes.
+diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt
+index f51eb4b..040b977 100644
+--- a/Documentation/ia64/serial.txt
++++ b/Documentation/ia64/serial.txt
+@@ -124,6 +124,13 @@ TROUBLESHOOTING SERIAL CONSOLE PROBLEMS
+
+ - Add entry to /etc/securetty for console tty.
+
++ No ACPI serial devices found in 2.6.17 or later:
++
++ - Turn on CONFIG_PNP and CONFIG_PNPACPI. Prior to 2.6.17, ACPI
++ serial devices were discovered by 8250_acpi. In 2.6.17,
++ 8250_acpi was replaced by the combination of 8250_pnp and
++ CONFIG_PNPACPI.
++
+
+
+ [1] http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
+diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
+index 8b3fd82..e50595b 100644
+--- a/Documentation/ibm-acpi.txt
++++ b/Documentation/ibm-acpi.txt
+@@ -30,9 +30,10 @@ detailed description):
+ - ACPI sounds
+ - temperature sensors
+ - Experimental: embedded controller register dump
+- - Experimental: LCD brightness control
+- - Experimental: volume control
++ - LCD brightness control
++ - Volume control
+ - Experimental: fan speed, fan enable/disable
++ - Experimental: WAN enable and disable
+
+ A compatibility table by model and feature is maintained on the web
+ site, http://ibm-acpi.sf.net/. I appreciate any success or failure
+@@ -52,40 +53,7 @@ Installation
+
+ If you are compiling this driver as included in the Linux kernel
+ sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
+-ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes
+-how to install this driver when downloaded from the web site.
+-
+-First, you need to get a kernel with ACPI support up and running.
+-Please refer to http://acpi.sourceforge.net/ for help with this
+-step. How successful you will be depends a lot on you ThinkPad model,
+-the kernel you are using and any additional patches applied. The
+-kernel provided with your distribution may not be good enough. I
+-needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get
+-ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not
+-be supported at all.
+-
+-Assuming you have the basic ACPI support working (e.g. you can see the
+-/proc/acpi directory), follow the following steps to install this
+-driver:
+-
+- - unpack the archive:
+-
+- tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y
+-
+- - compile the driver:
+-
+- make
+-
+- - install the module in your kernel modules directory:
+-
+- make install
+-
+- - load the module:
+-
+- modprobe ibm_acpi
+-
+-After loading the module, check the "dmesg" output for any error messages.
+-
++ACPI / IBM ThinkPad Laptop Extras).
+
+ Features
+ --------
+@@ -450,7 +418,7 @@ his laptop (the location of sensors may
+
+ No commands can be written to this file.
+
+-EXPERIMENTAL: Embedded controller reigster dump -- /proc/acpi/ibm/ecdump
++EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
+ ------------------------------------------------------------------------
+
+ This feature is marked EXPERIMENTAL because the implementation
+@@ -523,13 +491,8 @@ registers contain the current battery ca
+ with this, do send me your results (including some complete dumps with
+ a description of the conditions when they were taken.)
+
+-EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness
+------------------------------------------------------------------
+-
+-This feature is marked EXPERIMENTAL because the implementation
+-directly accesses hardware registers and may not work as expected. USE
+-WITH CAUTION! To use this feature, you need to supply the
+-experimental=1 parameter when loading the module.
++LCD brightness control -- /proc/acpi/ibm/brightness
++---------------------------------------------------
+
+ This feature allows software control of the LCD brightness on ThinkPad
+ models which don't have a hardware brightness slider. The available
+@@ -542,13 +505,8 @@ commands are:
+ The <level> number range is 0 to 7, although not all of them may be
+ distinct. The current brightness level is shown in the file.
+
+-EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume
+------------------------------------------------------
+-
+-This feature is marked EXPERIMENTAL because the implementation
+-directly accesses hardware registers and may not work as expected. USE
+-WITH CAUTION! To use this feature, you need to supply the
+-experimental=1 parameter when loading the module.
++Volume control -- /proc/acpi/ibm/volume
++---------------------------------------
+
+ This feature allows volume control on ThinkPad models which don't have
+ a hardware volume knob. The available commands are:
+@@ -611,6 +569,23 @@ with the following command:
+
+ echo 'level <level>' > /proc/acpi/ibm/thermal
+
++EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
++---------------------------------------
++
++This feature is marked EXPERIMENTAL because the implementation
++directly accesses hardware registers and may not work as expected. USE
++WITH CAUTION! To use this feature, you need to supply the
++experimental=1 parameter when loading the module.
++
++This feature shows the presence and current state of a WAN (Sierra
++Wireless EV-DO) device. If WAN is installed, the following commands can
++be used:
++
++ echo enable > /proc/acpi/ibm/wan
++ echo disable > /proc/acpi/ibm/wan
++
++It was tested on a Lenovo Thinkpad X60. It should probably work on other
++Thinkpad models which come with this module installed.
+
+ Multiple Commands, Module Parameters
+ ------------------------------------
+diff --git a/Documentation/ide.txt b/Documentation/ide.txt
+index 29866fb..0bf38ba 100644
+--- a/Documentation/ide.txt
++++ b/Documentation/ide.txt
+@@ -281,7 +281,7 @@ Summary of ide driver parameters for ker
+
+ "idex=serialize" : do not overlap operations on idex. Please note
+ that you will have to specify this option for
+- both the respecitve primary and secondary channel
++ both the respective primary and secondary channel
+ to take effect.
+
+ "idex=four" : four drives on idex and ide(x^1) share same ports
+diff --git a/Documentation/input/amijoy.txt b/Documentation/input/amijoy.txt
+index 3b8b2d4..4f0e89d 100644
+--- a/Documentation/input/amijoy.txt
++++ b/Documentation/input/amijoy.txt
+@@ -79,10 +79,10 @@ JOY0DAT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+ JOY1DAT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
+
+ 0=LEFT CONTROLLER PAIR, 1=RIGHT CONTROLLER PAIR.
+- (4 counters total).The bit usage for both left and right
++ (4 counters total). The bit usage for both left and right
+ addresses is shown below. Each 6 bit counter (Y7-Y2,X7-X2) is
+ clocked by 2 of the signals input from the mouse serial
+- stream. Starting with first bit recived:
++ stream. Starting with first bit received:
+
+ +-------------------+-----------------------------------------+
+ | Serial | Bit Name | Description |
+diff --git a/Documentation/input/atarikbd.txt b/Documentation/input/atarikbd.txt
+index 8fb896c..1e7e585 100644
+--- a/Documentation/input/atarikbd.txt
++++ b/Documentation/input/atarikbd.txt
+@@ -10,7 +10,7 @@ provides a convenient connection point f
+ The ikbd processor also maintains a time-of-day clock with one second
+ resolution.
+ The ikbd has been designed to be general enough that it can be used with a
+-ariety of new computer products. Product variations in a number of
++variety of new computer products. Product variations in a number of
+ keyswitches, mouse resolution, etc. can be accommodated.
+ The ikbd communicates with the main processor over a high speed bi-directional
+ serial interface. It can function in a variety of modes to facilitate
+@@ -30,7 +30,7 @@ is obtained by ORing 0x80 with the make
+ The special codes 0xF6 through 0xFF are reserved for use as follows:
+ 0xF6 status report
+ 0xF7 absolute mouse position record
+- 0xF8-0xFB relative mouse position records(lsbs determind by
++ 0xF8-0xFB relative mouse position records (lsbs determined by
+ mouse button states)
+ 0xFC time-of-day
+ 0xFD joystick report (both sticks)
+@@ -84,7 +84,7 @@ selected.
+ 4.2 Absolute Position reporting
+
+ The ikbd can also maintain absolute mouse position. Commands exist for
+-reseting the mouse position, setting X/Y scaling, and interrogating the
++resetting the mouse position, setting X/Y scaling, and interrogating the
+ current mouse position.
+
+ 4.3 Mouse Cursor Key Mode
+@@ -406,7 +406,7 @@ INTERROGATION MODE.
+ 9.18 SET JOYSTICK MONITORING
+
+ 0x17
+- rate ; time between samples in hundreths of a second
++ rate ; time between samples in hundredths of a second
+ Returns: (in packets of two as long as in mode)
+ %000000xy ; where y is JOYSTICK1 Fire button
+ ; and x is JOYSTICK0 Fire button
+@@ -522,7 +522,7 @@ controller memory. The time between data
+ 0x20 ; memory access
+ { data } ; 6 data bytes starting at ADR
+
+-This comand permits the host to read from the ikbd controller memory.
++This command permits the host to read from the ikbd controller memory.
+
+ 9.26 CONTROLLER EXECUTE
+
+diff --git a/Documentation/input/cs461x.txt b/Documentation/input/cs461x.txt
+index 6181747..afe0d65 100644
+--- a/Documentation/input/cs461x.txt
++++ b/Documentation/input/cs461x.txt
+@@ -27,7 +27,7 @@ This driver have the basic support for P
+ ISA or PnP ISA cards supported. AFAIK the ns558 have support for Crystal
+ ISA and PnP ISA series.
+
+-The driver works witn ALSA drivers simultaneously. For exmple, the xracer
++The driver works with ALSA drivers simultaneously. For example, the xracer
+ uses joystick as input device and PCM device as sound output in one time.
+ There are no sound or input collisions detected. The source code have
+ comments about them; but I've found the joystick can be initialized
+diff --git a/Documentation/input/ff.txt b/Documentation/input/ff.txt
+index c7e10ea..085eb15 100644
+--- a/Documentation/input/ff.txt
++++ b/Documentation/input/ff.txt
+@@ -1,78 +1,48 @@
+ Force feedback for Linux.
+ By Johann Deneux <deneux at ifrance.com> on 2001/04/22.
++Updated by Anssi Hannula <anssi.hannula at gmail.com> on 2006/04/09.
+ You may redistribute this file. Please remember to include shape.fig and
+ interactive.fig as well.
+ ----------------------------------------------------------------------------
+
+-0. Introduction
++1. Introduction
+ ~~~~~~~~~~~~~~~
+ This document describes how to use force feedback devices under Linux. The
+ goal is not to support these devices as if they were simple input-only devices
+ (as it is already the case), but to really enable the rendering of force
+ effects.
+-At the moment, only I-Force devices are supported, and not officially. That
+-means I had to find out how the protocol works on my own. Of course, the
+-information I managed to grasp is far from being complete, and I can not
+-guarranty that this driver will work for you.
+-This document only describes the force feedback part of the driver for I-Force
+-devices. Please read joystick.txt before reading further this document.
++This document only describes the force feedback part of the Linux input
++interface. Please read joystick.txt and input.txt before reading further this
++document.
+
+ 2. Instructions to the user
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-Here are instructions on how to compile and use the driver. In fact, this
+-driver is the normal iforce, input and evdev drivers written by Vojtech
+-Pavlik, plus additions to support force feedback.
++To enable force feedback, you have to:
++
++1. have your kernel configured with evdev and a driver that supports your
++ device.
++2. make sure evdev module is loaded and /dev/input/event* device files are
++ created.
+
+ Before you start, let me WARN you that some devices shake violently during the
+ initialisation phase. This happens for example with my "AVB Top Shot Pegasus".
+ To stop this annoying behaviour, move you joystick to its limits. Anyway, you
+-should keep a hand on your device, in order to avoid it to brake down if
++should keep a hand on your device, in order to avoid it to break down if
+ something goes wrong.
+
+-At the kernel's compilation:
+- - Enable IForce/Serial
+- - Enable Event interface
+-
+-Compile the modules, install them.
+-
+-You also need inputattach.
+-
+-You then need to insert the modules into the following order:
+-% modprobe joydev
+-% modprobe serport # Only for serial
+-% modprobe iforce
+-% modprobe evdev
+-% ./inputattach -ifor $2 & # Only for serial
+-If you are using USB, you don't need the inputattach step.
+-
+-Please check that you have all the /dev/input entries needed:
+-cd /dev
+-rm js*
+-mkdir input
+-mknod input/js0 c 13 0
+-mknod input/js1 c 13 1
+-mknod input/js2 c 13 2
+-mknod input/js3 c 13 3
+-ln -s input/js0 js0
+-ln -s input/js1 js1
+-ln -s input/js2 js2
+-ln -s input/js3 js3
+-
+-mknod input/event0 c 13 64
+-mknod input/event1 c 13 65
+-mknod input/event2 c 13 66
+-mknod input/event3 c 13 67
++If you have a serial iforce device, you need to start inputattach. See
++joystick.txt for details.
+
+ 2.1 Does it work ?
+ ~~~~~~~~~~~~~~~~~~
+ There is an utility called fftest that will allow you to test the driver.
+ % fftest /dev/input/eventXX
+
+-3. Instructions to the developper
++3. Instructions to the developer
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- All interactions are done using the event API. That is, you can use ioctl()
++All interactions are done using the event API. That is, you can use ioctl()
+ and write() on /dev/input/eventXX.
+- This information is subject to change.
++This information is subject to change.
+
+ 3.1 Querying device capabilities
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+@@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int reque
+
+ Returns the features supported by the device. features is a bitfield with the
+ following bits:
+-- FF_X has an X axis (usually joysticks)
+-- FF_Y has an Y axis (usually joysticks)
+-- FF_WHEEL has a wheel (usually sterring wheels)
+ - FF_CONSTANT can render constant force effects
+-- FF_PERIODIC can render periodic effects (sine, triangle, square...)
++- FF_PERIODIC can render periodic effects with the following waveforms:
++ - FF_SQUARE square waveform
++ - FF_TRIANGLE triangle waveform
++ - FF_SINE sine waveform
++ - FF_SAW_UP sawtooth up waveform
++ - FF_SAW_DOWN sawtooth down waveform
++ - FF_CUSTOM custom waveform
+ - FF_RAMP can render ramp effects
+ - FF_SPRING can simulate the presence of a spring
+-- FF_FRICTION can simulate friction
++- FF_FRICTION can simulate friction
+ - FF_DAMPER can simulate damper effects
+-- FF_RUMBLE rumble effects (normally the only effect supported by rumble
+- pads)
++- FF_RUMBLE rumble effects
+ - FF_INERTIA can simulate inertia
++- FF_GAIN gain is adjustable
++- FF_AUTOCENTER autocenter is adjustable
++
++Note: In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All
++ devices that support FF_RUMBLE support FF_PERIODIC (square, triangle,
++ sine) and the other way around.
++
++Note: The exact syntax FF_CUSTOM is undefined for the time being as no driver
++ supports it yet.
+
+
+ int ioctl(int fd, EVIOCGEFFECTS, int *n);
+@@ -108,7 +89,7 @@ Returns the number of effects the device
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ #include <linux/input.h>
+ #include <sys/ioctl.h>
+-
++
+ int ioctl(int file_descriptor, int request, struct ff_effect *effect);
+
+ "request" must be EVIOCSFF.
+@@ -120,6 +101,9 @@ to the unique id assigned by the driver.
+ some operations (removing an effect, controlling the playback).
+ This if field must be set to -1 by the user in order to tell the driver to
+ allocate a new effect.
++
++Effects are file descriptor specific.
++
+ See <linux/input.h> for a description of the ff_effect struct. You should also
+ find help in a few sketches, contained in files shape.fig and interactive.fig.
+ You need xfig to visualize these files.
+@@ -128,8 +112,8 @@ You need xfig to visualize these files.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ int ioctl(int fd, EVIOCRMFF, effect.id);
+
+-This makes room for new effects in the device's memory. Please note this won't
+-stop the effect if it was playing.
++This makes room for new effects in the device's memory. Note that this also
++stops the effect if it was playing.
+
+ 3.4 Controlling the playback of effects
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+@@ -149,22 +133,21 @@ Control of playing is done with write().
+ play.type = EV_FF;
+ play.code = effect.id;
+ play.value = 3;
+-
++
+ write(fd, (const void*) &play, sizeof(play));
+ ...
+ /* Stop an effect */
+ stop.type = EV_FF;
+ stop.code = effect.id;
+ stop.value = 0;
+-
++
+ write(fd, (const void*) &play, sizeof(stop));
+
+ 3.5 Setting the gain
+ ~~~~~~~~~~~~~~~~~~~~
+ Not all devices have the same strength. Therefore, users should set a gain
+ factor depending on how strong they want effects to be. This setting is
+-persistent across access to the driver, so you should not care about it if
+-you are writing games, as another utility probably already set this for you.
++persistent across access to the driver.
+
+ /* Set the gain of the device
+ int gain; /* between 0 and 100 */
+@@ -204,11 +187,14 @@ type of device, not all parameters can b
+ the direction of an effect cannot be updated with iforce devices. In this
+ case, the driver stops the effect, up-load it, and restart it.
+
++Therefore it is recommended to dynamically change direction while the effect
++is playing only when it is ok to restart the effect with a replay count of 1.
+
+ 3.8 Information about the status of effects
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Every time the status of an effect is changed, an event is sent. The values
+ and meanings of the fields of the event are as follows:
++
+ struct input_event {
+ /* When the status of the effect changed */
+ struct timeval time;
+@@ -225,3 +211,9 @@ struct input_event {
+
+ FF_STATUS_STOPPED The effect stopped playing
+ FF_STATUS_PLAYING The effect started to play
++
++NOTE: Status feedback is only supported by iforce driver. If you have
++ a really good reason to use this, please contact
++ linux-joystick at atrey.karlin.mff.cuni.cz or anssi.hannula at gmail.com
++ so that support for it can be added to the rest of the drivers.
++
+diff --git a/Documentation/input/gameport-programming.txt b/Documentation/input/gameport-programming.txt
+index 1ba3d32..14e0a8b 100644
+--- a/Documentation/input/gameport-programming.txt
++++ b/Documentation/input/gameport-programming.txt
+@@ -18,8 +18,8 @@ Make sure struct gameport is initialized
+ gameport generic code will take care of the rest.
+
+ If your hardware supports more than one io address, and your driver can
+-choose which one program the hardware to, starting from the more exotic
+-addresses is preferred, because the likelyhood of clashing with the standard
++choose which one to program the hardware to, starting from the more exotic
++addresses is preferred, because the likelihood of clashing with the standard
+ 0x201 address is smaller.
+
+ Eg. if your driver supports addresses 0x200, 0x208, 0x210 and 0x218, then
+diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt
+index 47137e7..ff8cea0 100644
+--- a/Documentation/input/input.txt
++++ b/Documentation/input/input.txt
+@@ -68,8 +68,8 @@ will be available as a character device
+
+ crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice
+
+- This device has to be created, unless you use devfs, in which case it's
+-created automatically. The commands to do create it by hand are:
++ This device has to be created.
++ The commands to create it by hand are:
+
+ cd /dev
+ mkdir input
+@@ -154,7 +154,7 @@ about it.
+
+ 3.2 Event handlers
+ ~~~~~~~~~~~~~~~~~~
+- Event handlers distrubite the events from the devices to userland and
++ Event handlers distribute the events from the devices to userland and
+ kernel, as needed.
+
+ 3.2.1 keybdev
+@@ -230,7 +230,7 @@ generated in the kernel straight to the
+ API is still evolving, but should be useable now. It's described in
+ section 5.
+
+- This should be the way for GPM and X to get keyboard and mouse mouse
++ This should be the way for GPM and X to get keyboard and mouse
+ events. It allows for multihead in X without any specific multihead
+ kernel support. The event codes are the same on all architectures and
+ are hardware independent.
+@@ -279,7 +279,7 @@ struct input_event {
+ };
+
+ 'time' is the timestamp, it returns the time at which the event happened.
+-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
++Type is for example EV_REL for relative moment, REL_KEY for a keypress or
+ release. More types are defined in include/linux/input.h.
+
+ 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+@@ -289,24 +289,3 @@ list is in include/linux/input.h.
+ EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
+ release, 1 for keypress and 2 for autorepeat.
+
+-6. Contacts
+-~~~~~~~~~~~
+- This effort has its home page at:
+-
+- http://www.suse.cz/development/input/
+-
+-You'll find both the latest HID driver and the complete Input driver
+-there as well as information how to access the CVS repository for
+-latest revisions of the drivers.
+-
+- There is also a mailing list for this:
+-
+- majordomo at atrey.karlin.mff.cuni.cz
+-
+-Send "subscribe linux-input" to subscribe to it.
+-
+-The input changes are also being worked on as part of the LinuxConsole
+-project, see:
+-
+- http://sourceforge.net/projects/linuxconsole/
+-
+diff --git a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt
+index d537c48..ede5f33 100644
+--- a/Documentation/input/joystick-parport.txt
++++ b/Documentation/input/joystick-parport.txt
+@@ -456,8 +456,8 @@ uses the following kernel/module command
+ 8 | Sony PSX DDR controller
+ 9 | SNES mouse
+
+- The exact type of the PSX controller type is autoprobed when used so
+-hot swapping should work (but is not recomended).
++ The exact type of the PSX controller type is autoprobed when used, so
++hot swapping should work (but is not recommended).
+
+ Should you want to use more than one of parallel ports at once, you can use
+ gamecon.map2 and gamecon.map3 as additional command line parameters for two
+@@ -465,8 +465,8 @@ more parallel ports.
+
+ There are two options specific to PSX driver portion. gamecon.psx_delay sets
+ the command delay when talking to the controllers. The default of 25 should
+-work but you can try lowering it for better performace. If your pads don't
+-respond try raising it untill they work. Setting the type to 8 allows the
++work but you can try lowering it for better performance. If your pads don't
++respond try raising it until they work. Setting the type to 8 allows the
+ driver to be used with Dance Dance Revolution or similar games. Arrow keys are
+ registered as key presses instead of X and Y axes.
+
+diff --git a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt
+index 841c353..389de9b 100644
+--- a/Documentation/input/joystick.txt
++++ b/Documentation/input/joystick.txt
+@@ -60,7 +60,7 @@ and install it before going on.
+
+ 2.2 Device nodes
+ ~~~~~~~~~~~~~~~~
+-For applications to be able to use the joysticks, in you don't use devfs,
++For applications to be able to use the joysticks,
+ you'll have to manually create these nodes in /dev:
+
+ cd /dev
+diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt
+index b9111a7..5427bdf 100644
+--- a/Documentation/input/xpad.txt
++++ b/Documentation/input/xpad.txt
+@@ -3,20 +3,37 @@ xpad - Linux USB driver for X-Box gamepa
+ This is the very first release of a driver for X-Box gamepads.
+ Basically, this was hacked away in just a few hours, so don't expect
+ miracles.
++
+ In particular, there is currently NO support for the rumble pack.
+ You won't find many ff-aware linux applications anyway.
+
+
+-0. Status
+----------
++0. Notes
++--------
++
++Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.)
+
+-For now, this driver has only been tested on just one Linux-Box.
+-This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600.
++The number of buttons/axes reported varies based on 3 things:
++- if you are using a known controller
++- if you are using a known dance pad
++- if using an unknown device (one not listed below), what you set in the
++ module configuration for "Map D-PAD to buttons rather than axes for unknown
++ pads" (module option dpad_to_buttons)
+
+-The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
+-8 axes and 10 buttons.
++If you set dpad_to_buttons to 0 and you are using an unknown device (one
++not listed below), the driver will map the directional pad to axes (X/Y),
++if you said N it will map the d-pad to buttons, which is needed for dance
++style games to function correctly. The default is Y.
++
++dpad_to_buttons has no effect for known pads.
++
++0.1 Normal Controllers
++----------------------
++With a normal controller, the directional pad is mapped to its own X/Y axes.
++The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) will report 8
++axes and 10 buttons.
+
+-Alls 8 axes work, though they all have the same range (-32768..32767)
++All 8 axes work, though they all have the same range (-32768..32767)
+ and the zero-setting is not correct for the triggers (I don't know if that
+ is some limitation of jstest, since the input device setup should be fine. I
+ didn't have a look at jstest itself yet).
+@@ -30,16 +47,50 @@ in game functionality were OK. However,
+ play first person shooters with a pad. Your mileage may vary.
+
+
++0.2 Xbox Dance Pads
++-------------------
++When using a known dance pad, jstest will report 6 axes and 14 buttons.
++
++For dance style pads (like the redoctane pad) several changes
++have been made. The old driver would map the d-pad to axes, resulting
++in the driver being unable to report when the user was pressing both
++left+right or up+down, making DDR style games unplayable.
++
++Known dance pads automatically map the d-pad to buttons and will work
++correctly out of the box.
++
++If your dance pad is recognized by the driver but is using axes instead
++of buttons, see section 0.3 - Unknown Controllers
++
++I've tested this with Stepmania, and it works quite well.
++
++
++0.3 Unkown Controllers
++----------------------
++If you have an unkown xbox controller, it should work just fine with
++the default settings.
++
++HOWEVER if you have an unknown dance pad not listed below, it will not
++work UNLESS you set "dpad_to_buttons" to 1 in the module configuration.
++
++PLEASE if you have an unkown controller, email Dom <binary1230 at yahoo.com> with
++a dump from /proc/bus/usb and a description of the pad (manufacturer, country,
++whether it is a dance pad or normal controller) so that we can add your pad
++to the list of supported devices, ensuring that it will work out of the
++box in the future.
++
++
+ 1. USB adapter
+ --------------
+
+ Before you can actually use the driver, you need to get yourself an
+-adapter cable to connect the X-Box controller to your Linux-Box.
++adapter cable to connect the X-Box controller to your Linux-Box. You
++can buy these online fairly cheap, or build your own.
+
+-Such a cable is pretty easy to build. The Controller itself is a USB compound
+-device (a hub with three ports for two expansion slots and the controller
+-device) with the only difference in a nonstandard connector (5 pins vs. 4 on
+-standard USB connector).
++Such a cable is pretty easy to build. The Controller itself is a USB
++compound device (a hub with three ports for two expansion slots and
++the controller device) with the only difference in a nonstandard connector
++(5 pins vs. 4 on standard USB connector).
+
+ You just need to solder a USB connector onto the cable and keep the
+ yellow wire unconnected. The other pins have the same order on both
+@@ -51,36 +102,36 @@ original one. You can buy an extension c
+ you can still use the controller with your X-Box, if you have one ;)
+
+
+-2. driver installation
++2. Driver Installation
+ ----------------------
+
+ Once you have the adapter cable and the controller is connected, you need
+ to load your USB subsystem and should cat /proc/bus/usb/devices.
+ There should be an entry like the one at the end [4].
+
+-Currently (as of version 0.0.4), the following three devices are included:
++Currently (as of version 0.0.6), the following devices are included:
+ original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202
++ smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289
+ original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285
+ InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a
++ RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809
+
+-If you have another controller that is not listed above and is not recognized
+-by the driver, please drop me a line with the appropriate info (that is, include
+-the name, vendor and product ID, as well as the country where you bought it;
+-sending the whole dump out of /proc/bus/usb/devices along would be even better).
++The driver should work with xbox pads not listed above as well, however
++you will need to do something extra for dance pads to work.
+
+-In theory, the driver should work with other controllers than mine
+-(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this
+-for I only have this one controller.
++If you have a controller not listed above, see 0.3 - Unknown Controllers
+
+ If you compiled and installed the driver, test the functionality:
+ > modprobe xpad
+ > modprobe joydev
+ > jstest /dev/js0
+
+-There should be a single line showing 18 inputs (8 axes, 10 buttons), and
+-it's values should change if you move the sticks and push the buttons.
++If you're using a normal controller, there should be a single line showing
++18 inputs (8 axes, 10 buttons), and its values should change if you move
++the sticks and push the buttons. If you're using a dance pad, it should
++show 20 inputs (6 axes, 14 buttons).
+
+-It works? Voila, your done ;)
++It works? Voila, you're done ;)
+
+
+ 3. Thanks
+@@ -111,6 +162,22 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. )
+ E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms
+ E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms
+
++5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US):
++
++T: Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12 MxCh= 0
++D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
++P: Vendor=0c12 ProdID=8809 Rev= 0.01
++S: Product=XBOX DDR
++C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
++I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad
++E: Ad=82(I) Atr=03(Int.) MxPS= 32 Ivl=4ms
++E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl=4ms
++
+ --
+ Marko Friedemann <mfr at bmx-chemnitz.de>
+ 2002-07-16
++ - original doc
++
++Dominic Cerquetti <binary1230 at yahoo.com>
++2005-03-19
++ - added stuff for dance pads, new d-pad->axes mappings
+diff --git a/Documentation/input/yealink.txt b/Documentation/input/yealink.txt
+index 0962c5c..0a8c97e 100644
+--- a/Documentation/input/yealink.txt
++++ b/Documentation/input/yealink.txt
+@@ -87,13 +87,13 @@ Line 3 Format : 888888888888
+
+
+ Format description:
+- From a user space perspective the world is seperated in "digits" and "icons".
++ From a userspace perspective the world is separated into "digits" and "icons".
+ A digit can have a character set, an icon can only be ON or OFF.
+
+ Format specifier
+ '8' : Generic 7 segment digit with individual addressable segments
+
+- Reduced capabillity 7 segm digit, when segments are hard wired together.
++ Reduced capability 7 segm digit, when segments are hard wired together.
+ '1' : 2 segments digit only able to produce a 1.
+ 'e' : Most significant day of the month digit,
+ able to produce at least 1 2 3.
+diff --git a/Documentation/ioctl/hdio.txt b/Documentation/ioctl/hdio.txt
+index 11c9be4..c19efde 100644
+--- a/Documentation/ioctl/hdio.txt
++++ b/Documentation/ioctl/hdio.txt
+@@ -203,7 +203,7 @@ HDIO_SET_MULTCOUNT change IDE blockmode
+
+ Source code comments read:
+
+- This is tightly woven into the driver->do_special can not
++ This is tightly woven into the driver->do_special cannot
+ touch. DON'T do it again until a total personality rewrite
+ is committed.
+
+diff --git a/Documentation/isdn/INTERFACE.fax b/Documentation/isdn/INTERFACE.fax
+index 7e57313..9c8c6d9 100644
+--- a/Documentation/isdn/INTERFACE.fax
++++ b/Documentation/isdn/INTERFACE.fax
+@@ -26,7 +26,7 @@ Structure T30_s description:
+ If the HL-driver receives ISDN_CMD_FAXCMD, all needed information
+ is in this struct set by the LL.
+ To signal information to the LL, the HL-driver has to set the
+- the parameters and use ISDN_STAT_FAXIND.
++ parameters and use ISDN_STAT_FAXIND.
+ (Please refer to INTERFACE)
+
+ Structure T30_s:
+diff --git a/Documentation/isdn/README.hysdn b/Documentation/isdn/README.hysdn
+index 56cc59d..eeca11f 100644
+--- a/Documentation/isdn/README.hysdn
++++ b/Documentation/isdn/README.hysdn
+@@ -1,6 +1,6 @@
+ $Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $
+ The hysdn driver has been written by
+-by Werner Cornelius (werner at isdn4linux.de or werner at titro.de)
++Werner Cornelius (werner at isdn4linux.de or werner at titro.de)
+ for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
+ under the GNU General Public License.
+
+diff --git a/Documentation/java.txt b/Documentation/java.txt
+index e4814c2..c768dc6 100644
+--- a/Documentation/java.txt
++++ b/Documentation/java.txt
+@@ -22,7 +22,7 @@ other program after you have done the fo
+ the kernel (CONFIG_BINFMT_MISC) and set it up properly.
+ If you choose to compile it as a module, you will have
+ to insert it manually with modprobe/insmod, as kmod
+- can not easily be supported with binfmt_misc.
++ cannot easily be supported with binfmt_misc.
+ Read the file 'binfmt_misc.txt' in this directory to know
+ more about the configuration process.
+
+diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
+index ca1967f..125093c 100644
+--- a/Documentation/kbuild/kconfig-language.txt
++++ b/Documentation/kbuild/kconfig-language.txt
+@@ -1,7 +1,7 @@
+ Introduction
+ ------------
+
+-The configuration database is collection of configuration options
++The configuration database is a collection of configuration options
+ organized in a tree structure:
+
+ +- Code maturity level options
+@@ -67,19 +67,19 @@ applicable everywhere (see syntax).
+ - default value: "default" <expr> ["if" <expr>]
+ A config option can have any number of default values. If multiple
+ default values are visible, only the first defined one is active.
+- Default values are not limited to the menu entry, where they are
+- defined, this means the default can be defined somewhere else or be
++ Default values are not limited to the menu entry where they are
++ defined. This means the default can be defined somewhere else or be
+ overridden by an earlier definition.
+ The default value is only assigned to the config symbol if no other
+ value was set by the user (via the input prompt above). If an input
+ prompt is visible the default value is presented to the user and can
+ be overridden by him.
+- Optionally dependencies only for this default value can be added with
++ Optionally, dependencies only for this default value can be added with
+ "if".
+
+ - dependencies: "depends on"/"requires" <expr>
+ This defines a dependency for this menu entry. If multiple
+- dependencies are defined they are connected with '&&'. Dependencies
++ dependencies are defined, they are connected with '&&'. Dependencies
+ are applied to all other options within this menu entry (which also
+ accept an "if" expression), so these two examples are equivalent:
+
+@@ -110,7 +110,7 @@ applicable everywhere (see syntax).
+ the indentation level, this means it ends at the first line which has
+ a smaller indentation than the first line of the help text.
+ "---help---" and "help" do not differ in behaviour, "---help---" is
+- used to help visually seperate configuration logic from help within
++ used to help visually separate configuration logic from help within
+ the file as an aid to developers.
+
+
+@@ -153,7 +153,7 @@ Nonconstant symbols are the most common
+ 'config' statement. Nonconstant symbols consist entirely of alphanumeric
+ characters or underscores.
+ Constant symbols are only part of expressions. Constant symbols are
+-always surrounded by single or double quotes. Within the quote any
++always surrounded by single or double quotes. Within the quote, any
+ other character is allowed and the quotes can be escaped using '\'.
+
+ Menu structure
+@@ -226,7 +226,7 @@ menuconfig:
+ "menuconfig" <symbol>
+ <config options>
+
+-This is similiar to the simple config entry above, but it also gives a
++This is similar to the simple config entry above, but it also gives a
+ hint to front ends, that all suboptions should be displayed as a
+ separate list of options.
+
+@@ -237,7 +237,7 @@ choices:
+ <choice block>
+ "endchoice"
+
+-This defines a choice group and accepts any of above attributes as
++This defines a choice group and accepts any of the above attributes as
+ options. A choice can only be of type bool or tristate, while a boolean
+ choice only allows a single config entry to be selected, a tristate
+ choice also allows any number of config entries to be set to 'm'. This
+diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
+index 0706699..50f4edd 100644
+--- a/Documentation/kbuild/makefiles.txt
++++ b/Documentation/kbuild/makefiles.txt
+@@ -22,7 +22,7 @@ This document describes the Linux kernel
+ === 4 Host Program support
+ --- 4.1 Simple Host Program
+ --- 4.2 Composite Host Programs
+- --- 4.3 Defining shared libraries
++ --- 4.3 Defining shared libraries
+ --- 4.4 Using C++ for host programs
+ --- 4.5 Controlling compiler options for host programs
+ --- 4.6 When host programs are actually built
+@@ -69,7 +69,7 @@ architecture-specific information to the
+
+ Each subdirectory has a kbuild Makefile which carries out the commands
+ passed down from above. The kbuild Makefile uses information from the
+-.config file to construct various file lists used by kbuild to build
++.config file to construct various file lists used by kbuild to build
+ any built-in or modular targets.
+
+ scripts/Makefile.* contains all the definitions/rules etc. that
+@@ -86,7 +86,7 @@ any kernel Makefiles (or any other sourc
+
+ *Normal developers* are people who work on features such as device
+ drivers, file systems, and network protocols. These people need to
+-maintain the kbuild Makefiles for the subsystem that they are
++maintain the kbuild Makefiles for the subsystem they are
+ working on. In order to do this effectively, they need some overall
+ knowledge about the kernel Makefiles, plus detailed knowledge about the
+ public interface for kbuild.
+@@ -104,10 +104,10 @@ This document is aimed towards normal de
+ === 3 The kbuild files
+
+ Most Makefiles within the kernel are kbuild Makefiles that use the
+-kbuild infrastructure. This chapter introduce the syntax used in the
++kbuild infrastructure. This chapter introduces the syntax used in the
+ kbuild makefiles.
+ The preferred name for the kbuild files are 'Makefile' but 'Kbuild' can
+-be used and if both a 'Makefile' and a 'Kbuild' file exists then the 'Kbuild'
++be used and if both a 'Makefile' and a 'Kbuild' file exists, then the 'Kbuild'
+ file will be used.
+
+ Section 3.1 "Goal definitions" is a quick intro, further chapters provide
+@@ -124,7 +124,7 @@ more details, with real examples.
+ Example:
+ obj-y += foo.o
+
+- This tell kbuild that there is one object in that directory named
++ This tell kbuild that there is one object in that directory, named
+ foo.o. foo.o will be built from foo.c or foo.S.
+
+ If foo.o shall be built as a module, the variable obj-m is used.
+@@ -140,7 +140,7 @@ more details, with real examples.
+ --- 3.2 Built-in object goals - obj-y
+
+ The kbuild Makefile specifies object files for vmlinux
+- in the lists $(obj-y). These lists depend on the kernel
++ in the $(obj-y) lists. These lists depend on the kernel
+ configuration.
+
+ Kbuild compiles all the $(obj-y) files. It then calls
+@@ -154,8 +154,8 @@ more details, with real examples.
+ Link order is significant, because certain functions
+ (module_init() / __initcall) will be called during boot in the
+ order they appear. So keep in mind that changing the link
+- order may e.g. change the order in which your SCSI
+- controllers are detected, and thus you disks are renumbered.
++ order may e.g. change the order in which your SCSI
++ controllers are detected, and thus your disks are renumbered.
+
+ Example:
+ #drivers/isdn/i4l/Makefile
+@@ -203,11 +203,11 @@ more details, with real examples.
+ Example:
+ #fs/ext2/Makefile
+ obj-$(CONFIG_EXT2_FS) += ext2.o
+- ext2-y := balloc.o bitmap.o
++ ext2-y := balloc.o bitmap.o
+ ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
+-
+- In this example xattr.o is only part of the composite object
+- ext2.o, if $(CONFIG_EXT2_FS_XATTR) evaluates to 'y'.
++
++ In this example, xattr.o is only part of the composite object
++ ext2.o if $(CONFIG_EXT2_FS_XATTR) evaluates to 'y'.
+
+ Note: Of course, when you are building objects into the kernel,
+ the syntax above will also work. So, if you have CONFIG_EXT2_FS=y,
+@@ -221,16 +221,16 @@ more details, with real examples.
+
+ --- 3.5 Library file goals - lib-y
+
+- Objects listed with obj-* are used for modules or
++ Objects listed with obj-* are used for modules, or
+ combined in a built-in.o for that specific directory.
+ There is also the possibility to list objects that will
+ be included in a library, lib.a.
+ All objects listed with lib-y are combined in a single
+ library for that directory.
+- Objects that are listed in obj-y and additional listed in
++ Objects that are listed in obj-y and additionaly listed in
+ lib-y will not be included in the library, since they will anyway
+ be accessible.
+- For consistency objects listed in lib-m will be included in lib.a.
++ For consistency, objects listed in lib-m will be included in lib.a.
+
+ Note that the same kbuild makefile may list files to be built-in
+ and to be part of a library. Therefore the same directory
+@@ -241,11 +241,11 @@ more details, with real examples.
+ lib-y := checksum.o delay.o
+
+ This will create a library lib.a based on checksum.o and delay.o.
+- For kbuild to actually recognize that there is a lib.a being build
++ For kbuild to actually recognize that there is a lib.a being built,
+ the directory shall be listed in libs-y.
+ See also "6.3 List directories to visit when descending".
+-
+- Usage of lib-y is normally restricted to lib/ and arch/*/lib.
++
++ Use of lib-y is normally restricted to lib/ and arch/*/lib.
+
+ --- 3.6 Descending down in directories
+
+@@ -255,7 +255,7 @@ more details, with real examples.
+ invoke make recursively in subdirectories, provided you let it know of
+ them.
+
+- To do so obj-y and obj-m are used.
++ To do so, obj-y and obj-m are used.
+ ext2 lives in a separate directory, and the Makefile present in fs/
+ tells kbuild to descend down using the following assignment.
+
+@@ -353,8 +353,8 @@ more details, with real examples.
+ Special rules are used when the kbuild infrastructure does
+ not provide the required support. A typical example is
+ header files generated during the build process.
+- Another example is the architecture specific Makefiles which
+- needs special rules to prepare boot images etc.
++ Another example are the architecture specific Makefiles which
++ need special rules to prepare boot images etc.
+
+ Special rules are written as normal Make rules.
+ Kbuild is not executing in the directory where the Makefile is
+@@ -387,28 +387,28 @@ more details, with real examples.
+
+ --- 3.11 $(CC) support functions
+
+- The kernel may be build with several different versions of
++ The kernel may be built with several different versions of
+ $(CC), each supporting a unique set of features and options.
+ kbuild provide basic support to check for valid options for $(CC).
+- $(CC) is useally the gcc compiler, but other alternatives are
++ $(CC) is usually the gcc compiler, but other alternatives are
+ available.
+
+ as-option
+- as-option is used to check if $(CC) when used to compile
+- assembler (*.S) files supports the given option. An optional
+- second option may be specified if first option are not supported.
++ as-option is used to check if $(CC) -- when used to compile
++ assembler (*.S) files -- supports the given option. An optional
++ second option may be specified if the first option is not supported.
+
+ Example:
+ #arch/sh/Makefile
+ cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
+
+- In the above example cflags-y will be assinged the the option
++ In the above example, cflags-y will be assigned the option
+ -Wa$(comma)-isa=$(isa-y) if it is supported by $(CC).
+ The second argument is optional, and if supplied will be used
+ if first argument is not supported.
+
+ ld-option
+- ld-option is used to check if $(CC) when used to link object files
++ ld-option is used to check if $(CC) when used to link object files
+ supports the given option. An optional second option may be
+ specified if first option are not supported.
+
+@@ -421,8 +421,13 @@ more details, with real examples.
+ The second argument is optional, and if supplied will be used
+ if first argument is not supported.
+
++ as-instr
++ as-instr checks if the assembler reports a specific instruction
++ and then outputs either option1 or option2
++ C escapes are supported in the test instruction
++
+ cc-option
+- cc-option is used to check if $(CC) support a given option, and not
++ cc-option is used to check if $(CC) supports a given option, and not
+ supported to use an optional second option.
+
+ Example:
+@@ -430,12 +435,12 @@ more details, with real examples.
+ cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)
+
+ In the above example cflags-y will be assigned the option
+- -march=pentium-mmx if supported by $(CC), otherwise -march-i586.
+- The second argument to cc-option is optional, and if omitted
++ -march=pentium-mmx if supported by $(CC), otherwise -march=i586.
++ The second argument to cc-option is optional, and if omitted,
+ cflags-y will be assigned no value if first option is not supported.
+
+ cc-option-yn
+- cc-option-yn is used to check if gcc supports a given option
++ cc-option-yn is used to check if gcc supports a given option
+ and return 'y' if supported, otherwise 'n'.
+
+ Example:
+@@ -443,32 +448,33 @@ more details, with real examples.
+ biarch := $(call cc-option-yn, -m32)
+ aflags-$(biarch) += -a32
+ cflags-$(biarch) += -m32
+-
+- In the above example $(biarch) is set to y if $(CC) supports the -m32
+- option. When $(biarch) equals to y the expanded variables $(aflags-y)
+- and $(cflags-y) will be assigned the values -a32 and -m32.
++
++ In the above example, $(biarch) is set to y if $(CC) supports the -m32
++ option. When $(biarch) equals 'y', the expanded variables $(aflags-y)
++ and $(cflags-y) will be assigned the values -a32 and -m32,
++ respectively.
+
+ cc-option-align
+- gcc version >= 3.0 shifted type of options used to speify
+- alignment of functions, loops etc. $(cc-option-align) whrn used
+- as prefix to the align options will select the right prefix:
++ gcc versions >= 3.0 changed the type of options used to specify
++ alignment of functions, loops etc. $(cc-option-align), when used
++ as prefix to the align options, will select the right prefix:
+ gcc < 3.00
+ cc-option-align = -malign
+ gcc >= 3.00
+ cc-option-align = -falign
+-
++
+ Example:
+ CFLAGS += $(cc-option-align)-functions=4
+
+- In the above example the option -falign-functions=4 is used for
+- gcc >= 3.00. For gcc < 3.00 -malign-functions=4 is used.
+-
++ In the above example, the option -falign-functions=4 is used for
++ gcc >= 3.00. For gcc < 3.00, -malign-functions=4 is used.
++
+ cc-version
+- cc-version return a numerical version of the $(CC) compiler version.
++ cc-version returns a numerical version of the $(CC) compiler version.
+ The format is <major><minor> where both are two digits. So for example
+ gcc 3.41 would return 0341.
+ cc-version is useful when a specific $(CC) version is faulty in one
+- area, for example the -mregparm=3 were broken in some gcc version
++ area, for example -mregparm=3 was broken in some gcc versions
+ even though the option was accepted by gcc.
+
+ Example:
+@@ -477,20 +483,20 @@ more details, with real examples.
+ if [ $(call cc-version) -ge 0300 ] ; then \
+ echo "-mregparm=3"; fi ;)
+
+- In the above example -mregparm=3 is only used for gcc version greater
++ In the above example, -mregparm=3 is only used for gcc version greater
+ than or equal to gcc 3.0.
+
+ cc-ifversion
+- cc-ifversion test the version of $(CC) and equals last argument if
++ cc-ifversion tests the version of $(CC) and equals last argument if
+ version expression is true.
+
+ Example:
+ #fs/reiserfs/Makefile
+ EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0402, -O1)
+
+- In this example EXTRA_CFLAGS will be assigned the value -O1 if the
++ In this example, EXTRA_CFLAGS will be assigned the value -O1 if the
+ $(CC) version is less than 4.2.
+- cc-ifversion takes all the shell operators:
++ cc-ifversion takes all the shell operators:
+ -eq, -ne, -lt, -le, -gt, and -ge
+ The third parameter may be a text as in this example, but it may also
+ be an expanded variable or a macro.
+@@ -506,7 +512,7 @@ The first step is to tell kbuild that a
+ done utilising the variable hostprogs-y.
+
+ The second step is to add an explicit dependency to the executable.
+-This can be done in two ways. Either add the dependency in a rule,
++This can be done in two ways. Either add the dependency in a rule,
+ or utilise the variable $(always).
+ Both possibilities are described in the following.
+
+@@ -523,28 +529,28 @@ Both possibilities are described in the
+ Kbuild assumes in the above example that bin2hex is made from a single
+ c-source file named bin2hex.c located in the same directory as
+ the Makefile.
+-
++
+ --- 4.2 Composite Host Programs
+
+ Host programs can be made up based on composite objects.
+ The syntax used to define composite objects for host programs is
+ similar to the syntax used for kernel objects.
+- $(<executeable>-objs) list all objects used to link the final
++ $(<executeable>-objs) lists all objects used to link the final
+ executable.
+
+ Example:
+ #scripts/lxdialog/Makefile
+- hostprogs-y := lxdialog
++ hostprogs-y := lxdialog
+ lxdialog-objs := checklist.o lxdialog.o
+
+ Objects with extension .o are compiled from the corresponding .c
+- files. In the above example checklist.c is compiled to checklist.o
++ files. In the above example, checklist.c is compiled to checklist.o
+ and lxdialog.c is compiled to lxdialog.o.
+- Finally the two .o files are linked to the executable, lxdialog.
++ Finally, the two .o files are linked to the executable, lxdialog.
+ Note: The syntax <executable>-y is not permitted for host-programs.
+
+---- 4.3 Defining shared libraries
+-
++--- 4.3 Defining shared libraries
++
+ Objects with extension .so are considered shared libraries, and
+ will be compiled as position independent objects.
+ Kbuild provides support for shared libraries, but the usage
+@@ -557,7 +563,7 @@ Both possibilities are described in the
+ hostprogs-y := conf
+ conf-objs := conf.o libkconfig.so
+ libkconfig-objs := expr.o type.o
+-
++
+ Shared libraries always require a corresponding -objs line, and
+ in the example above the shared library libkconfig is composed by
+ the two objects expr.o and type.o.
+@@ -578,7 +584,7 @@ Both possibilities are described in the
+
+ In the example above the executable is composed of the C++ file
+ qconf.cc - identified by $(qconf-cxxobjs).
+-
++
+ If qconf is composed by a mixture of .c and .cc files, then an
+ additional line can be used to identify this.
+
+@@ -587,34 +593,35 @@ Both possibilities are described in the
+ hostprogs-y := qconf
+ qconf-cxxobjs := qconf.o
+ qconf-objs := check.o
+-
++
+ --- 4.5 Controlling compiler options for host programs
+
+ When compiling host programs, it is possible to set specific flags.
+ The programs will always be compiled utilising $(HOSTCC) passed
+ the options specified in $(HOSTCFLAGS).
+ To set flags that will take effect for all host programs created
+- in that Makefile use the variable HOST_EXTRACFLAGS.
++ in that Makefile, use the variable HOST_EXTRACFLAGS.
+
+ Example:
+ #scripts/lxdialog/Makefile
+ HOST_EXTRACFLAGS += -I/usr/include/ncurses
+-
++
+ To set specific flags for a single file the following construction
+ is used:
+
+ Example:
+ #arch/ppc64/boot/Makefile
+ HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)
+-
++
+ It is also possible to specify additional options to the linker.
+-
++
+ Example:
+ #scripts/kconfig/Makefile
+ HOSTLOADLIBES_qconf := -L$(QTDIR)/lib
+
+- When linking qconf it will be passed the extra option "-L$(QTDIR)/lib".
+-
++ When linking qconf, it will be passed the extra option
++ "-L$(QTDIR)/lib".
++
+ --- 4.6 When host programs are actually built
+
+ Kbuild will only build host-programs when they are referenced
+@@ -629,7 +636,7 @@ Both possibilities are described in the
+ $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist
+ ( cd $(obj); ./gen-devlist ) < $<
+
+- The target $(obj)/devlist.h will not be built before
++ The target $(obj)/devlist.h will not be built before
+ $(obj)/gen-devlist is updated. Note that references to
+ the host programs in special rules must be prefixed with $(obj).
+
+@@ -648,7 +655,7 @@ Both possibilities are described in the
+
+ --- 4.7 Using hostprogs-$(CONFIG_FOO)
+
+- A typcal pattern in a Kbuild file lok like this:
++ A typical pattern in a Kbuild file looks like this:
+
+ Example:
+ #scripts/Makefile
+@@ -656,13 +663,13 @@ Both possibilities are described in the
+
+ Kbuild knows about both 'y' for built-in and 'm' for module.
+ So if a config symbol evaluate to 'm', kbuild will still build
+- the binary. In other words Kbuild handle hostprogs-m exactly
+- like hostprogs-y. But only hostprogs-y is recommend used
+- when no CONFIG symbol are involved.
++ the binary. In other words, Kbuild handles hostprogs-m exactly
++ like hostprogs-y. But only hostprogs-y is recommended to be used
++ when no CONFIG symbols are involved.
+
+ === 5 Kbuild clean infrastructure
+
+-"make clean" deletes most generated files in the src tree where the kernel
++"make clean" deletes most generated files in the obj tree where the kernel
+ is compiled. This includes generated files such as host programs.
+ Kbuild knows targets listed in $(hostprogs-y), $(hostprogs-m), $(always),
+ $(extra-y) and $(targets). They are all deleted during "make clean".
+@@ -680,7 +687,8 @@ When executing "make clean", the two fil
+ be deleted. Kbuild will assume files to be in same relative directory as the
+ Makefile except if an absolute path is specified (path starting with '/').
+
+-To delete a directory hirachy use:
++To delete a directory hierarchy use:
++
+ Example:
+ #scripts/package/Makefile
+ clean-dirs := $(objtree)/debian/
+@@ -723,29 +731,29 @@ be visited during "make clean".
+
+ The top level Makefile sets up the environment and does the preparation,
+ before starting to descend down in the individual directories.
+-The top level makefile contains the generic part, whereas the
+-arch/$(ARCH)/Makefile contains what is required to set-up kbuild
+-to the said architecture.
+-To do so arch/$(ARCH)/Makefile sets a number of variables, and defines
++The top level makefile contains the generic part, whereas
++arch/$(ARCH)/Makefile contains what is required to set up kbuild
++for said architecture.
++To do so, arch/$(ARCH)/Makefile sets up a number of variables and defines
+ a few targets.
+
+-When kbuild executes the following steps are followed (roughly):
+-1) Configuration of the kernel => produced .config
++When kbuild executes, the following steps are followed (roughly):
++1) Configuration of the kernel => produce .config
+ 2) Store kernel version in include/linux/version.h
+ 3) Symlink include/asm to include/asm-$(ARCH)
+ 4) Updating all other prerequisites to the target prepare:
+ - Additional prerequisites are specified in arch/$(ARCH)/Makefile
+ 5) Recursively descend down in all directories listed in
+ init-* core* drivers-* net-* libs-* and build all targets.
+- - The value of the above variables are extended in arch/$(ARCH)/Makefile.
+-6) All object files are then linked and the resulting file vmlinux is
+- located at the root of the src tree.
++ - The values of the above variables are expanded in arch/$(ARCH)/Makefile.
++6) All object files are then linked and the resulting file vmlinux is
++ located at the root of the obj tree.
+ The very first objects linked are listed in head-y, assigned by
+ arch/$(ARCH)/Makefile.
+-7) Finally the architecture specific part does any required post processing
++7) Finally, the architecture specific part does any required post processing
+ and builds the final bootimage.
+ - This includes building boot records
+- - Preparing initrd images and the like
++ - Preparing initrd images and thelike
+
+
+ --- 6.1 Set variables to tweak the build to the architecture
+@@ -760,7 +768,7 @@ When kbuild executes the following steps
+ LDFLAGS := -m elf_s390
+ Note: EXTRA_LDFLAGS and LDFLAGS_$@ can be used to further customise
+ the flags used. See chapter 7.
+-
++
+ LDFLAGS_MODULE Options for $(LD) when linking modules
+
+ LDFLAGS_MODULE is used to set specific flags for $(LD) when
+@@ -770,7 +778,7 @@ When kbuild executes the following steps
+ LDFLAGS_vmlinux Options for $(LD) when linking vmlinux
+
+ LDFLAGS_vmlinux is used to specify additional flags to pass to
+- the linker when linking the final vmlinux.
++ the linker when linking the final vmlinux image.
+ LDFLAGS_vmlinux uses the LDFLAGS_$@ support.
+
+ Example:
+@@ -780,7 +788,7 @@ When kbuild executes the following steps
+ OBJCOPYFLAGS objcopy flags
+
+ When $(call if_changed,objcopy) is used to translate a .o file,
+- then the flags specified in OBJCOPYFLAGS will be used.
++ the flags specified in OBJCOPYFLAGS will be used.
+ $(call if_changed,objcopy) is often used to generate raw binaries on
+ vmlinux.
+
+@@ -792,7 +800,7 @@ When kbuild executes the following steps
+ $(obj)/image: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+- In this example the binary $(obj)/image is a binary version of
++ In this example, the binary $(obj)/image is a binary version of
+ vmlinux. The usage of $(call if_changed,xxx) will be described later.
+
+ AFLAGS $(AS) assembler flags
+@@ -809,7 +817,7 @@ When kbuild executes the following steps
+ Default value - see top level Makefile
+ Append or modify as required per architecture.
+
+- Often the CFLAGS variable depends on the configuration.
++ Often, the CFLAGS variable depends on the configuration.
+
+ Example:
+ #arch/i386/Makefile
+@@ -830,7 +838,7 @@ When kbuild executes the following steps
+ ...
+
+
+- The first examples utilises the trick that a config option expands
++ The first example utilises the trick that a config option expands
+ to 'y' when selected.
+
+ CFLAGS_KERNEL $(CC) options specific for built-in
+@@ -843,18 +851,18 @@ When kbuild executes the following steps
+ $(CFLAGS_MODULE) contains extra C compiler flags used to compile code
+ for loadable kernel modules.
+
+-
++
+ --- 6.2 Add prerequisites to archprepare:
+
+- The archprepare: rule is used to list prerequisites that needs to be
++ The archprepare: rule is used to list prerequisites that need to be
+ built before starting to descend down in the subdirectories.
+- This is usual header files containing assembler constants.
++ This is usually used for header files containing assembler constants.
+
+ Example:
+ #arch/arm/Makefile
+ archprepare: maketools
+
+- In this example the file target maketools will be processed
++ In this example, the file target maketools will be processed
+ before descending down in the subdirectories.
+ See also chapter XXX-TODO that describe how kbuild supports
+ generating offset header files.
+@@ -867,18 +875,19 @@ When kbuild executes the following steps
+ corresponding arch-specific section for modules; the module-building
+ machinery is all architecture-independent.
+
+-
++
+ head-y, init-y, core-y, libs-y, drivers-y, net-y
+
+- $(head-y) list objects to be linked first in vmlinux.
+- $(libs-y) list directories where a lib.a archive can be located.
+- The rest list directories where a built-in.o object file can be located.
++ $(head-y) lists objects to be linked first in vmlinux.
++ $(libs-y) lists directories where a lib.a archive can be located.
++ The rest lists directories where a built-in.o object file can be
++ located.
+
+ $(init-y) objects will be located after $(head-y).
+ Then the rest follows in this order:
+ $(core-y), $(libs-y), $(drivers-y) and $(net-y).
+
+- The top level Makefile define values for all generic directories,
++ The top level Makefile defines values for all generic directories,
+ and arch/$(ARCH)/Makefile only adds architecture specific directories.
+
+ Example:
+@@ -915,27 +924,27 @@ When kbuild executes the following steps
+ "$(Q)$(MAKE) $(build)=<dir>" is the recommended way to invoke
+ make in a subdirectory.
+
+- There are no rules for naming of the architecture specific targets,
++ There are no rules for naming architecture specific targets,
+ but executing "make help" will list all relevant targets.
+- To support this $(archhelp) must be defined.
++ To support this, $(archhelp) must be defined.
+
+ Example:
+ #arch/i386/Makefile
+ define archhelp
+ echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)'
+- endef
++ endif
+
+ When make is executed without arguments, the first goal encountered
+ will be built. In the top level Makefile the first goal present
+ is all:.
+- An architecture shall always per default build a bootable image.
+- In "make help" the default goal is highlighted with a '*'.
++ An architecture shall always, per default, build a bootable image.
++ In "make help", the default goal is highlighted with a '*'.
+ Add a new prerequisite to all: to select a default goal different
+ from vmlinux.
+
+ Example:
+ #arch/i386/Makefile
+- all: bzImage
++ all: bzImage
+
+ When "make" is executed without arguments, bzImage will be built.
+
+@@ -955,10 +964,10 @@ When kbuild executes the following steps
+ #arch/i386/kernel/Makefile
+ extra-y := head.o init_task.o
+
+- In this example extra-y is used to list object files that
++ In this example, extra-y is used to list object files that
+ shall be built, but shall not be linked as part of built-in.o.
+
+-
++
+ --- 6.6 Commands useful for building a boot image
+
+ Kbuild provides a few macros that are useful when building a
+@@ -972,8 +981,8 @@ When kbuild executes the following steps
+ target: source(s) FORCE
+ $(call if_changed,ld/objcopy/gzip)
+
+- When the rule is evaluated it is checked to see if any files
+- needs an update, or the commandline has changed since last
++ When the rule is evaluated, it is checked to see if any files
++ needs an update, or the command line has changed since the last
+ invocation. The latter will force a rebuild if any options
+ to the executable have changed.
+ Any target that utilises if_changed must be listed in $(targets),
+@@ -991,8 +1000,8 @@ When kbuild executes the following steps
+ #WRONG!# $(call if_changed, ld/objcopy/gzip)
+
+ ld
+- Link target. Often LDFLAGS_$@ is used to set specific options to ld.
+-
++ Link target. Often, LDFLAGS_$@ is used to set specific options to ld.
++
+ objcopy
+ Copy binary. Uses OBJCOPYFLAGS usually specified in
+ arch/$(ARCH)/Makefile.
+@@ -1010,10 +1019,10 @@ When kbuild executes the following steps
+ $(obj)/setup $(obj)/bootsect: %: %.o FORCE
+ $(call if_changed,ld)
+
+- In this example there are two possible targets, requiring different
+- options to the linker. the linker options are specified using the
++ In this example, there are two possible targets, requiring different
++ options to the linker. The linker options are specified using the
+ LDFLAGS_$@ syntax - one for each potential target.
+- $(targets) are assinged all potential targets, herby kbuild knows
++ $(targets) are assinged all potential targets, by which kbuild knows
+ the targets and will:
+ 1) check for commandline changes
+ 2) delete target during make clean
+@@ -1027,7 +1036,7 @@ When kbuild executes the following steps
+
+ --- 6.7 Custom kbuild commands
+
+- When kbuild is executing with KBUILD_VERBOSE=0 then only a shorthand
++ When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand
+ of a command is normally displayed.
+ To enable this behaviour for custom commands kbuild requires
+ two variables to be set:
+@@ -1045,34 +1054,34 @@ When kbuild executes the following steps
+ $(call if_changed,image)
+ @echo 'Kernel: $@ is ready'
+
+- When updating the $(obj)/bzImage target the line:
++ When updating the $(obj)/bzImage target, the line
+
+ BUILD arch/i386/boot/bzImage
+
+ will be displayed with "make KBUILD_VERBOSE=0".
+-
++
+
+ --- 6.8 Preprocessing linker scripts
+
+- When the vmlinux image is build the linker script:
++ When the vmlinux image is built, the linker script
+ arch/$(ARCH)/kernel/vmlinux.lds is used.
+ The script is a preprocessed variant of the file vmlinux.lds.S
+ located in the same directory.
+- kbuild knows .lds file and includes a rule *lds.S -> *lds.
+-
++ kbuild knows .lds files and includes a rule *lds.S -> *lds.
++
+ Example:
+ #arch/i386/kernel/Makefile
+ always := vmlinux.lds
+-
++
+ #Makefile
+ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
+-
+- The assigment to $(always) is used to tell kbuild to build the
+- target: vmlinux.lds.
+- The assignment to $(CPPFLAGS_vmlinux.lds) tell kbuild to use the
++
++ The assignment to $(always) is used to tell kbuild to build the
++ target vmlinux.lds.
++ The assignment to $(CPPFLAGS_vmlinux.lds) tells kbuild to use the
+ specified options when building the target vmlinux.lds.
+-
+- When building the *.lds target kbuild used the variakles:
++
++ When building the *.lds target, kbuild uses the variables:
+ CPPFLAGS : Set in top-level Makefile
+ EXTRA_CPPFLAGS : May be set in the kbuild makefile
+ CPPFLAGS_$(@F) : Target specific flags.
+@@ -1147,7 +1156,7 @@ The top Makefile exports the following v
+
+ === 8 Makefile language
+
+-The kernel Makefiles are designed to run with GNU Make. The Makefiles
++The kernel Makefiles are designed to be run with GNU Make. The Makefiles
+ use only the documented features of GNU Make, but they do use many
+ GNU extensions.
+
+@@ -1169,10 +1178,13 @@ is the right choice.
+ Original version made by Michael Elizabeth Chastain, <mailto:mec at shout.net>
+ Updates by Kai Germaschewski <kai at tp1.ruhr-uni-bochum.de>
+ Updates by Sam Ravnborg <sam at ravnborg.org>
++Language QA by Jan Engelhardt <jengelh at gmx.de>
+
+ === 10 TODO
+
+-- Describe how kbuild support shipped files with _shipped.
++- Describe how kbuild supports shipped files with _shipped.
+ - Generating offset header files.
+ - Add more variables to section 7?
+
++
++
+diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt
+index 61fc079..769ee05 100644
+--- a/Documentation/kbuild/modules.txt
++++ b/Documentation/kbuild/modules.txt
+@@ -1,7 +1,7 @@
+
+ In this document you will find information about:
+ - how to build external modules
+-- how to make your module use kbuild infrastructure
++- how to make your module use the kbuild infrastructure
+ - how kbuild will install a kernel
+ - how to install modules in a non-standard location
+
+@@ -24,7 +24,7 @@ In this document you will find informati
+ --- 6.1 INSTALL_MOD_PATH
+ --- 6.2 INSTALL_MOD_DIR
+ === 7. Module versioning & Module.symvers
+- --- 7.1 Symbols fron the kernel (vmlinux + modules)
++ --- 7.1 Symbols from the kernel (vmlinux + modules)
+ --- 7.2 Symbols and external modules
+ --- 7.3 Symbols from another external module
+ === 8. Tips & Tricks
+@@ -36,14 +36,14 @@ In this document you will find informati
+
+ kbuild includes functionality for building modules both
+ within the kernel source tree and outside the kernel source tree.
+-The latter is usually referred to as external modules and is used
+-both during development and for modules that are not planned to be
+-included in the kernel tree.
++The latter is usually referred to as external or "out-of-tree"
++modules and is used both during development and for modules that
++are not planned to be included in the kernel tree.
+
+ What is covered within this file is mainly information to authors
+-of modules. The author of an external modules should supply
+-a makefile that hides most of the complexity so one only has to type
+-'make' to build the module. A complete example will be present in
++of modules. The author of an external module should supply
++a makefile that hides most of the complexity, so one only has to type
++'make' to build the module. A complete example will be presented in
+ chapter 4, "Creating a kbuild file for an external module".
+
+
+@@ -61,16 +61,18 @@ when building an external module.
+ make -C <path-to-kernel> M=`pwd`
+
+ For the running kernel use:
++
+ make -C /lib/modules/`uname -r`/build M=`pwd`
+
+- For the above command to succeed the kernel must have been built with
+- modules enabled.
++ For the above command to succeed, the kernel must have been
++ built with modules enabled.
+
+ To install the modules that were just built:
+
+ make -C <path-to-kernel> M=`pwd` modules_install
+
+- More complex examples later, the above should get you going.
++ More complex examples will be shown later, the above should
++ be enough to get you started.
+
+ --- 2.2 Available targets
+
+@@ -89,13 +91,13 @@ when building an external module.
+ Same functionality as if no target was specified.
+ See description above.
+
+- make -C $KDIR M=$PWD modules_install
++ make -C $KDIR M=`pwd` modules_install
+ Install the external module(s).
+ Installation default is in /lib/modules/<kernel-version>/extra,
+ but may be prefixed with INSTALL_MOD_PATH - see separate
+ chapter.
+
+- make -C $KDIR M=$PWD clean
++ make -C $KDIR M=`pwd` clean
+ Remove all generated files for the module - the kernel
+ source directory is not modified.
+
+@@ -129,29 +131,28 @@ when building an external module.
+
+ To make sure the kernel contains the information required to
+ build external modules the target 'modules_prepare' must be used.
+- 'module_prepare' solely exists as a simple way to prepare
+- a kernel for building external modules.
++ 'modules_prepare' exists solely as a simple way to prepare
++ a kernel source tree for building external modules.
+ Note: modules_prepare will not build Module.symvers even if
+- CONFIG_MODULEVERSIONING is set.
+- Therefore a full kernel build needs to be executed to make
+- module versioning work.
++ CONFIG_MODVERSIONS is set. Therefore a full kernel build
++ needs to be executed to make module versioning work.
+
+ --- 2.5 Building separate files for a module
+- It is possible to build single files which is part of a module.
+- This works equal for the kernel, a module and even for external
+- modules.
++ It is possible to build single files which are part of a module.
++ This works equally well for the kernel, a module and even for
++ external modules.
+ Examples (module foo.ko, consist of bar.o, baz.o):
+ make -C $KDIR M=`pwd` bar.lst
+ make -C $KDIR M=`pwd` bar.o
+ make -C $KDIR M=`pwd` foo.ko
+ make -C $KDIR M=`pwd` /
+-
++
+
+ === 3. Example commands
+
+ This example shows the actual commands to be executed when building
+ an external module for the currently running kernel.
+-In the example below the distribution is supposed to use the
++In the example below, the distribution is supposed to use the
+ facility to locate output files for a kernel compile in a different
+ directory than the kernel source - but the examples will also work
+ when the source and the output files are mixed in the same directory.
+@@ -170,14 +171,14 @@ the following commands to build the modu
+ O=/lib/modules/`uname-r`/build \
+ M=`pwd`
+
+-Then to install the module use the following command:
++Then, to install the module use the following command:
+
+ make -C /usr/src/`uname -r`/source \
+ O=/lib/modules/`uname-r`/build \
+ M=`pwd` \
+ modules_install
+
+-If one looks closely you will see that this is the same commands as
++If you look closely you will see that this is the same command as
+ listed before - with the directories spelled out.
+
+ The above are rather long commands, and the following chapter
+@@ -230,7 +231,7 @@ following files:
+
+ endif
+
+- In example 1 the check for KERNELRELEASE is used to separate
++ In example 1, the check for KERNELRELEASE is used to separate
+ the two parts of the Makefile. kbuild will only see the two
+ assignments whereas make will see everything except the two
+ kbuild assignments.
+@@ -255,7 +256,7 @@ following files:
+ echo "X" > 8123_bin_shipped
+
+
+- In example 2 we are down to two fairly simple files and for simple
++ In example 2, we are down to two fairly simple files and for simple
+ files as used in this example the split is questionable. But some
+ external modules use Makefiles of several hundred lines and here it
+ really pays off to separate the kbuild part from the rest.
+@@ -282,9 +283,9 @@ following files:
+
+ endif
+
+- The trick here is to include the Kbuild file from Makefile so
+- if an older version of kbuild picks up the Makefile the Kbuild
+- file will be included.
++ The trick here is to include the Kbuild file from Makefile, so
++ if an older version of kbuild picks up the Makefile, the Kbuild
++ file will be included.
+
+ --- 4.2 Binary blobs included in a module
+
+@@ -301,18 +302,19 @@ following files:
+ obj-m := 8123.o
+ 8123-y := 8123_if.o 8123_pci.o 8123_bin.o
+
+- In example 4 there is no distinction between the ordinary .c/.h files
++ In example 4, there is no distinction between the ordinary .c/.h files
+ and the binary file. But kbuild will pick up different rules to create
+ the .o file.
+
+
+ === 5. Include files
+
+-Include files are a necessity when a .c file uses something from another .c
+-files (not strictly in the sense of .c but if good programming practice is
+-used). Any module that consist of more than one .c file will have a .h file
+-for one of the .c files.
+-- If the .h file only describes a module internal interface then the .h file
++Include files are a necessity when a .c file uses something from other .c
++files (not strictly in the sense of C, but if good programming practice is
++used). Any module that consists of more than one .c file will have a .h file
++for one of the .c files.
++
++- If the .h file only describes a module internal interface, then the .h file
+ shall be placed in the same directory as the .c files.
+ - If the .h files describe an interface used by other parts of the kernel
+ located in different directories, the .h files shall be located in
+@@ -323,11 +325,11 @@ under include/ such as include/scsi. Ano
+ .h files which are located under include/asm-$(ARCH)/*.
+
+ External modules have a tendency to locate include files in a separate include/
+-directory and therefore needs to deal with this in their kbuild file.
++directory and therefore need to deal with this in their kbuild file.
+
+ --- 5.1 How to include files from the kernel include dir
+
+- When a module needs to include a file from include/linux/ then one
++ When a module needs to include a file from include/linux/, then one
+ just uses:
+
+ #include <linux/modules.h>
+@@ -348,7 +350,7 @@ directory and therefore needs to deal wi
+ The trick here is to use either EXTRA_CFLAGS (take effect for all .c
+ files) or CFLAGS_$F.o (take effect only for a single file).
+
+- In our example if we move 8123_if.h to a subdirectory named include/
++ In our example, if we move 8123_if.h to a subdirectory named include/
+ the resulting Kbuild file would look like:
+
+ --> filename: Kbuild
+@@ -362,19 +364,19 @@ directory and therefore needs to deal wi
+
+ --- 5.3 External modules using several directories
+
+- If an external module does not follow the usual kernel style but
+- decide to spread files over several directories then kbuild can
+- support this too.
++ If an external module does not follow the usual kernel style, but
++ decides to spread files over several directories, then kbuild can
++ handle this too.
+
+ Consider the following example:
+-
++
+ |
+ +- src/complex_main.c
+ | +- hal/hardwareif.c
+ | +- hal/include/hardwareif.h
+ +- include/complex.h
+-
+- To build a single module named complex.ko we then need the following
++
++ To build a single module named complex.ko, we then need the following
+ kbuild file:
+
+ Kbuild:
+@@ -387,12 +389,12 @@ directory and therefore needs to deal wi
+
+
+ kbuild knows how to handle .o files located in another directory -
+- although this is NOT reccommended practice. The syntax is to specify
++ although this is NOT recommended practice. The syntax is to specify
+ the directory relative to the directory where the Kbuild file is
+ located.
+
+- To find the .h files we have to explicitly tell kbuild where to look
+- for the .h files. When kbuild executes current directory is always
++ To find the .h files, we have to explicitly tell kbuild where to look
++ for the .h files. When kbuild executes, the current directory is always
+ the root of the kernel tree (argument to -C) and therefore we have to
+ tell kbuild how to find the .h files using absolute paths.
+ $(src) will specify the absolute path to the directory where the
+@@ -412,7 +414,7 @@ External modules are installed in the di
+
+ --- 6.1 INSTALL_MOD_PATH
+
+- Above are the default directories, but as always some level of
++ Above are the default directories, but as always, some level of
+ customization is possible. One can prefix the path using the variable
+ INSTALL_MOD_PATH:
+
+@@ -420,17 +422,17 @@ External modules are installed in the di
+ => Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel
+
+ INSTALL_MOD_PATH may be set as an ordinary shell variable or as in the
+- example above be specified on the command line when calling make.
++ example above, can be specified on the command line when calling make.
+ INSTALL_MOD_PATH has effect both when installing modules included in
+ the kernel as well as when installing external modules.
+
+ --- 6.2 INSTALL_MOD_DIR
+
+- When installing external modules they are default installed in a
++ When installing external modules they are by default installed to a
+ directory under /lib/modules/$(KERNELRELEASE)/extra, but one may wish
+ to locate modules for a specific functionality in a separate
+- directory. For this purpose one can use INSTALL_MOD_DIR to specify an
+- alternative name than 'extra'.
++ directory. For this purpose, one can use INSTALL_MOD_DIR to specify an
++ alternative name to 'extra'.
+
+ $ make INSTALL_MOD_DIR=gandalf -C KERNELDIR \
+ M=`pwd` modules_install
+@@ -444,16 +446,16 @@ Module versioning is enabled by the CONF
+ Module versioning is used as a simple ABI consistency check. The Module
+ versioning creates a CRC value of the full prototype for an exported symbol and
+ when a module is loaded/used then the CRC values contained in the kernel are
+-compared with similar values in the module. If they are not equal then the
++compared with similar values in the module. If they are not equal, then the
+ kernel refuses to load the module.
+
+ Module.symvers contains a list of all exported symbols from a kernel build.
+
+---- 7.1 Symbols fron the kernel (vmlinux + modules)
++--- 7.1 Symbols from the kernel (vmlinux + modules)
+
+- During a kernel build a file named Module.symvers will be generated.
++ During a kernel build, a file named Module.symvers will be generated.
+ Module.symvers contains all exported symbols from the kernel and
+- compiled modules. For each symbols the corresponding CRC value
++ compiled modules. For each symbols, the corresponding CRC value
+ is stored too.
+
+ The syntax of the Module.symvers file is:
+@@ -461,27 +463,27 @@ Module.symvers contains a list of all ex
+ Sample:
+ 0x2d036834 scsi_remove_host drivers/scsi/scsi_mod
+
+- For a kernel build without CONFIG_MODVERSIONING enabled the crc
++ For a kernel build without CONFIG_MODVERSIONS enabled, the crc
+ would read: 0x00000000
+
+- Module.symvers serve two purposes.
+- 1) It list all exported symbols both from vmlinux and all modules
+- 2) It list CRC if CONFIG_MODVERSION is enabled
++ Module.symvers serves two purposes:
++ 1) It lists all exported symbols both from vmlinux and all modules
++ 2) It lists the CRC if CONFIG_MODVERSIONS is enabled
+
+ --- 7.2 Symbols and external modules
+
+- When building an external module the build system needs access to
++ When building an external module, the build system needs access to
+ the symbols from the kernel to check if all external symbols are
+ defined. This is done in the MODPOST step and to obtain all
+- symbols modpost reads Module.symvers from the kernel.
++ symbols, modpost reads Module.symvers from the kernel.
+ If a Module.symvers file is present in the directory where
+- the external module is being build this file will be read too.
+- During the MODPOST step a new Module.symvers file will be written
+- containing all exported symbols that was not defined in the kernel.
+-
++ the external module is being built, this file will be read too.
++ During the MODPOST step, a new Module.symvers file will be written
++ containing all exported symbols that were not defined in the kernel.
++
+ --- 7.3 Symbols from another external module
+
+- Sometimes one external module uses exported symbols from another
++ Sometimes, an external module uses exported symbols from another
+ external module. Kbuild needs to have full knowledge on all symbols
+ to avoid spitting out warnings about undefined symbols.
+ Two solutions exist to let kbuild know all symbols of more than
+@@ -490,15 +492,15 @@ Module.symvers contains a list of all ex
+ impractical in certain situations.
+
+ Use a top-level Kbuild file
+- If you have two modules: 'foo', 'bar' and 'foo' needs symbols
+- from 'bar' then one can use a common top-level kbuild file so
+- both modules are compiled in same build.
++ If you have two modules: 'foo' and 'bar', and 'foo' needs
++ symbols from 'bar', then one can use a common top-level kbuild
++ file so both modules are compiled in same build.
+
+ Consider following directory layout:
+ ./foo/ <= contains the foo module
+ ./bar/ <= contains the bar module
+ The top-level Kbuild file would then look like:
+-
++
+ #./Kbuild: (this file may also be named Makefile)
+ obj-y := foo/ bar/
+
+@@ -509,23 +511,23 @@ Module.symvers contains a list of all ex
+ knowledge on symbols from both modules.
+
+ Use an extra Module.symvers file
+- When an external module is build a Module.symvers file is
++ When an external module is built, a Module.symvers file is
+ generated containing all exported symbols which are not
+ defined in the kernel.
+- To get access to symbols from module 'bar' one can copy the
++ To get access to symbols from module 'bar', one can copy the
+ Module.symvers file from the compilation of the 'bar' module
+- to the directory where the 'foo' module is build.
+- During the module build kbuild will read the Module.symvers
++ to the directory where the 'foo' module is built.
++ During the module build, kbuild will read the Module.symvers
+ file in the directory of the external module and when the
+- build is finished a new Module.symvers file is created
++ build is finished, a new Module.symvers file is created
+ containing the sum of all symbols defined and not part of the
+ kernel.
+-
++
+ === 8. Tips & Tricks
+
+ --- 8.1 Testing for CONFIG_FOO_BAR
+
+- Modules often needs to check for certain CONFIG_ options to decide if
++ Modules often need to check for certain CONFIG_ options to decide if
+ a specific feature shall be included in the module. When kbuild is used
+ this is done by referencing the CONFIG_ variable directly.
+
+@@ -537,7 +539,7 @@ Module.symvers contains a list of all ex
+
+ External modules have traditionally used grep to check for specific
+ CONFIG_ settings directly in .config. This usage is broken.
+- As introduced before external modules shall use kbuild when building
+- and therefore can use the same methods as in-kernel modules when testing
+- for CONFIG_ definitions.
++ As introduced before, external modules shall use kbuild when building
++ and therefore can use the same methods as in-kernel modules when
++ testing for CONFIG_ definitions.
+
+diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
+index 08bafa8..99f2d4d 100644
+--- a/Documentation/kdump/kdump.txt
++++ b/Documentation/kdump/kdump.txt
+@@ -249,7 +249,7 @@ If die() is called, and it happens to be
+ is called inside interrupt context or die() is called and panic_on_oops is set,
+ the system will boot into the dump-capture kernel.
+
+-On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system system will boot into the dump-capture kernel.
++On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system will boot into the dump-capture kernel.
+
+ For testing purposes, you can trigger a crash by using "ALT-SysRq-c",
+ "echo c > /proc/sysrq-trigger or write a module to force the panic.
+diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt
+index c65233d..284e7e1 100644
+--- a/Documentation/kernel-doc-nano-HOWTO.txt
++++ b/Documentation/kernel-doc-nano-HOWTO.txt
+@@ -17,7 +17,7 @@ are:
+ special place-holders for where the extracted documentation should
+ go.
+
+-- scripts/docproc.c
++- scripts/basic/docproc.c
+
+ This is a program for converting SGML template files into SGML
+ files. When a file is referenced it is searched for symbols
+diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
+index 99d24f2..b53bccb 100644
+--- a/Documentation/kernel-docs.txt
++++ b/Documentation/kernel-docs.txt
+@@ -290,17 +290,6 @@
+ Description: Very nice 92 pages GPL book on the topic of modules
+ programming. Lots of examples.
+
+- * Title: "Device File System (devfs) Overview"
+- Author: Richard Gooch.
+- URL: http://www.atnf.csiro.au/people/rgooch/linux/docs/devfs.html
+- Keywords: filesystem, /dev, devfs, dynamic devices, major/minor
+- allocation, device management.
+- Description: Document describing Richard Gooch's controversial
+- devfs, which allows for dynamic devices, only shows present
+- devices in /dev, gets rid of major/minor numbers allocation
+- problems, and allows for hundreds of identical devices (which some
+- USB systems might demand soon).
+-
+ * Title: "I/O Event Handling Under Linux"
+ Author: Richard Gooch.
+ URL: http://www.atnf.csiro.au/~rgooch/linux/docs/io-events.html
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 71d05f4..dd00fd5 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -110,6 +110,13 @@ be entered as an environment variable, w
+ it will appear as a kernel argument readable via /proc/cmdline by programs
+ running once the system is up.
+
++The number of kernel parameters is not limited, but the length of the
++complete command line (parameters including spaces etc.) is limited to
++a fixed number of characters. This limit depends on the architecture
++and is between 256 and 4096 characters. It is defined in the file
++./include/asm/setup.h as COMMAND_LINE_SIZE.
++
++
+ 53c7xx= [HW,SCSI] Amiga SCSI controllers
+ See header of drivers/scsi/53c7xx.c.
+ See also Documentation/scsi/ncr53c7xx.txt.
+@@ -282,9 +289,6 @@ running once the system is up.
+
+ autotest [IA64]
+
+- awe= [HW,OSS] AWE32/SB32/AWE64 wave table synth
+- Format: <io>,<memsize>,<isapnp>
+-
+ aztcd= [HW,CD] Aztech CD268 CDROM driver
+ Format: <io>,0x79 (?)
+
+@@ -348,9 +352,9 @@ running once the system is up.
+
+ clock= [BUGS=IA-32, HW] gettimeofday clocksource override.
+ [Deprecated]
+- Forces specified clocksource (if avaliable) to be used
++ Forces specified clocksource (if available) to be used
+ when calculating gettimeofday(). If specified
+- clocksource is not avalible, it defaults to PIT.
++ clocksource is not available, it defaults to PIT.
+ Format: { pit | tsc | cyclone | pmtmr }
+
+ disable_8254_timer
+@@ -529,10 +533,6 @@ running once the system is up.
+ Default value is 0.
+ Value can be changed at runtime via /selinux/enforce.
+
+- es1370= [HW,OSS]
+- Format: <lineout>[,<micbias>]
+- See also header of sound/oss/es1370.c.
+-
+ es1371= [HW,OSS]
+ Format: <spdif>,[<nomix>,[<amplifier>]]
+ See also header of sound/oss/es1371.c.
+@@ -573,11 +573,6 @@ running once the system is up.
+ gscd= [HW,CD]
+ Format: <io>
+
+- gt96100eth= [NET] MIPS GT96100 Advanced Communication Controller
+-
+- gus= [HW,OSS]
+- Format: <io>,<irq>,<dma>,<dma16>
+-
+ gvp11= [HW,SCSI]
+
+ hashdist= [KNL,NUMA] Large hashes allocated during boot
+@@ -606,8 +601,8 @@ running once the system is up.
+ noirqbalance [IA-32,SMP,KNL] Disable kernel irq balancing
+
+ i8042.direct [HW] Put keyboard port into non-translated mode
+- i8042.dumbkbd [HW] Pretend that controlled can only read data from
+- keyboard and can not control its state
++ i8042.dumbkbd [HW] Pretend that controller can only read data from
++ keyboard and cannot control its state
+ (Don't attempt to blink the leds)
+ i8042.noaux [HW] Don't check for auxiliary (== mouse) port
+ i8042.nokbd [HW] Don't check/create keyboard port
+@@ -836,12 +831,6 @@ running once the system is up.
+ (machvec) in a generic kernel.
+ Example: machvec=hpzx1_swiotlb
+
+- mad16= [HW,OSS] Format:
+- <io>,<irq>,<dma>,<dma16>,<mpu_io>,<mpu_irq>,<joystick>
+-
+- maui= [HW,OSS]
+- Format: <io>,<irq>
+-
+ max_loop= [LOOP] Maximum number of loopback devices that can
+ be mounted
+ Format: <1-256>
+@@ -1109,9 +1098,6 @@ running once the system is up.
+ opl3= [HW,OSS]
+ Format: <io>
+
+- opl3sa= [HW,OSS]
+- Format: <io>,<irq>,<dma>,<dma2>,<mpu_io>,<mpu_irq>
+-
+ opl3sa2= [HW,OSS] Format:
+ <io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
+
+@@ -1240,6 +1226,15 @@ running once the system is up.
+ bootloader. This is currently used on
+ IXP2000 systems where the bus has to be
+ configured a certain way for adjunct CPUs.
++ noearly [X86] Don't do any early type 1 scanning.
++ This might help on some broken boards which
++ machine check when some devices' config space
++ is read. But various workarounds are disabled
++ and some IOMMU drivers will not work.
++ bfsort Sort PCI devices into breadth-first order.
++ This sorting is done to get a device
++ order compatible with older (<= 2.4) kernels.
++ nobfsort Don't sort PCI devices into breadth-first order.
+
+ pcmv= [HW,PCMCIA] BadgePAD 4
+
+@@ -1322,7 +1317,7 @@ running once the system is up.
+ pt. [PARIDE]
+ See Documentation/paride.txt.
+
+- quiet= [KNL] Disable log messages
++ quiet [KNL] Disable most log messages
+
+ r128= [HW,DRM]
+
+@@ -1348,10 +1343,6 @@ running once the system is up.
+ rcu.qlowmark= [KNL,BOOT] Set threshold of queued
+ RCU callbacks below which batch limiting is re-enabled.
+
+- rcu.rsinterval= [KNL,BOOT,SMP] Set the number of additional
+- RCU callbacks to queued before forcing reschedule
+- on all cpus.
+-
+ rdinit= [KNL]
+ Format: <full_path>
+ Run specified binary instead of /init from the ramdisk,
+@@ -1359,10 +1350,18 @@ running once the system is up.
+
+ reboot= [BUGS=IA-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
+ Format: <reboot_mode>[,<reboot_mode2>[,...]]
+- See arch/*/kernel/reboot.c.
++ See arch/*/kernel/reboot.c or arch/*/kernel/process.c
+
+ reserve= [KNL,BUGS] Force the kernel to ignore some iomem area
+
++ reservetop= [IA-32]
++ Format: nn[KMG]
++ Reserves a hole at the top of the kernel virtual
++ address space.
++
++ reset_devices [KNL] Force drivers to reset the underlying device
++ during initialization.
++
+ resume= [SWSUSP]
+ Specify the partition device for software suspend
+
+@@ -1438,9 +1437,6 @@ running once the system is up.
+
+ sg_def_reserved_size= [SCSI]
+
+- sgalaxy= [HW,OSS]
+- Format: <io>,<irq>,<dma>,<dma2>,<sgbase>
+-
+ shapers= [NET]
+ Maximal number of shapers.
+
+@@ -1581,9 +1577,6 @@ running once the system is up.
+
+ snd-ymfpci= [HW,ALSA]
+
+- sonicvibes= [HW,OSS]
+- Format: <reverb>
+-
+ sonycd535= [HW,CD]
+ Format: <io>[,<irq>]
+
+diff --git a/Documentation/keys.txt b/Documentation/keys.txt
+index e373f02..3da586b 100644
+--- a/Documentation/keys.txt
++++ b/Documentation/keys.txt
+@@ -671,7 +671,7 @@ The keyctl syscall functions are:
+
+ Note that this setting is inherited across fork/exec.
+
+- [1] The default default is: the thread keyring if there is one, otherwise
++ [1] The 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.
+
+@@ -708,14 +708,14 @@ The keyctl syscall functions are:
+
+ If the specified key is 0, then any assumed authority will be divested.
+
+- The assumed authorititive key is inherited across fork and exec.
++ The assumed authoritative key is inherited across fork and exec.
+
+
+ ===============
+ KERNEL SERVICES
+ ===============
+
+-The kernel services for key managment are fairly simple to deal with. They can
++The kernel services for key management are fairly simple to deal with. They can
+ be broken down into two areas: keys and key types.
+
+ Dealing with keys is fairly straightforward. Firstly, the kernel service
+diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt
+index 949f7b5..e448555 100644
+--- a/Documentation/kobject.txt
++++ b/Documentation/kobject.txt
+@@ -51,7 +51,7 @@ more complex object types. It provides a
+ almost all complex data types share. kobjects are intended to be
+ embedded in larger data structures and replace fields they duplicate.
+
+-1.2 Defintion
++1.2 Definition
+
+ struct kobject {
+ char name[KOBJ_NAME_LEN];
+diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
+index 2c3b1ea..ba26201 100644
+--- a/Documentation/kprobes.txt
++++ b/Documentation/kprobes.txt
+@@ -151,9 +151,9 @@ So that you can load and unload Kprobes-
+ make sure "Loadable module support" (CONFIG_MODULES) and "Module
+ unloading" (CONFIG_MODULE_UNLOAD) are set to "y".
+
+-You may also want to ensure that CONFIG_KALLSYMS and perhaps even
+-CONFIG_KALLSYMS_ALL are set to "y", since kallsyms_lookup_name()
+-is a handy, version-independent way to find a function's address.
++Also make sure that CONFIG_KALLSYMS and perhaps even CONFIG_KALLSYMS_ALL
++are set to "y", since kallsyms_lookup_name() is used by the in-kernel
++kprobe address resolution code.
+
+ If you need to insert a probe in the middle of a function, you may find
+ it useful to "Compile the kernel with debug info" (CONFIG_DEBUG_INFO),
+@@ -179,6 +179,27 @@ occurs during execution of kp->pre_handl
+ or during single-stepping of the probed instruction, Kprobes calls
+ kp->fault_handler. Any or all handlers can be NULL.
+
++NOTE:
++1. With the introduction of the "symbol_name" field to struct kprobe,
++the probepoint address resolution will now be taken care of by the kernel.
++The following will now work:
++
++ kp.symbol_name = "symbol_name";
++
++(64-bit powerpc intricacies such as function descriptors are handled
++transparently)
++
++2. Use the "offset" field of struct kprobe if the offset into the symbol
++to install a probepoint is known. This field is used to calculate the
++probepoint.
++
++3. Specify either the kprobe "symbol_name" OR the "addr". If both are
++specified, kprobe registration will fail with -EINVAL.
++
++4. With CISC architectures (such as i386 and x86_64), the kprobes code
++does not validate if the kprobe.addr is at an instruction boundary.
++Use "offset" with caution.
++
+ register_kprobe() returns 0 on success, or a negative errno otherwise.
+
+ User's pre-handler (kp->pre_handler):
+@@ -225,6 +246,12 @@ control to Kprobes.) If the probed func
+ fastcall, or anything else that affects how args are passed, the
+ handler's declaration must match.
+
++NOTE: A macro JPROBE_ENTRY is provided to handle architecture-specific
++aliasing of jp->entry. In the interest of portability, it is advised
++to use:
++
++ jp->entry = JPROBE_ENTRY(handler);
++
+ register_jprobe() returns 0 on success, or a negative errno otherwise.
+
+ 4.3 register_kretprobe
+@@ -251,6 +278,11 @@ of interest:
+ - ret_addr: the return address
+ - rp: points to the corresponding kretprobe object
+ - task: points to the corresponding task struct
++
++The regs_return_value(regs) macro provides a simple abstraction to
++extract the return value from the appropriate register as defined by
++the architecture's ABI.
++
+ The handler's return value is currently ignored.
+
+ 4.4 unregister_*probe
+@@ -369,7 +401,6 @@ stack trace and selected i386 registers
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/kprobes.h>
+-#include <linux/kallsyms.h>
+ #include <linux/sched.h>
+
+ /*For each probe you need to allocate a kprobe structure*/
+@@ -403,18 +434,14 @@ int handler_fault(struct kprobe *p, stru
+ return 0;
+ }
+
+-int init_module(void)
++static int __init kprobe_init(void)
+ {
+ int ret;
+ kp.pre_handler = handler_pre;
+ kp.post_handler = handler_post;
+ kp.fault_handler = handler_fault;
+- kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("do_fork");
+- /* register the kprobe now */
+- if (!kp.addr) {
+- printk("Couldn't find %s to plant kprobe\n", "do_fork");
+- return -1;
+- }
++ kp.symbol_name = "do_fork";
++
+ if ((ret = register_kprobe(&kp) < 0)) {
+ printk("register_kprobe failed, returned %d\n", ret);
+ return -1;
+@@ -423,12 +450,14 @@ int init_module(void)
+ return 0;
+ }
+
+-void cleanup_module(void)
++static void __exit kprobe_exit(void)
+ {
+ unregister_kprobe(&kp);
+ printk("kprobe unregistered\n");
+ }
+
++module_init(kprobe_init)
++module_exit(kprobe_exit)
+ MODULE_LICENSE("GPL");
+ ----- cut here -----
+
+@@ -463,7 +492,6 @@ the arguments of do_fork().
+ #include <linux/fs.h>
+ #include <linux/uio.h>
+ #include <linux/kprobes.h>
+-#include <linux/kallsyms.h>
+
+ /*
+ * Jumper probe for do_fork.
+@@ -485,17 +513,13 @@ long jdo_fork(unsigned long clone_flags,
+ }
+
+ static struct jprobe my_jprobe = {
+- .entry = (kprobe_opcode_t *) jdo_fork
++ .entry = JPROBE_ENTRY(jdo_fork)
+ };
+
+-int init_module(void)
++static int __init jprobe_init(void)
+ {
+ int ret;
+- my_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("do_fork");
+- if (!my_jprobe.kp.addr) {
+- printk("Couldn't find %s to plant jprobe\n", "do_fork");
+- return -1;
+- }
++ my_jprobe.kp.symbol_name = "do_fork";
+
+ if ((ret = register_jprobe(&my_jprobe)) <0) {
+ printk("register_jprobe failed, returned %d\n", ret);
+@@ -506,12 +530,14 @@ int init_module(void)
+ return 0;
+ }
+
+-void cleanup_module(void)
++static void __exit jprobe_exit(void)
+ {
+ unregister_jprobe(&my_jprobe);
+ printk("jprobe unregistered\n");
+ }
+
++module_init(jprobe_init)
++module_exit(jprobe_exit)
+ MODULE_LICENSE("GPL");
+ ----- cut here -----
+
+@@ -530,16 +556,13 @@ report failed calls to sys_open().
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/kprobes.h>
+-#include <linux/kallsyms.h>
+
+ static const char *probed_func = "sys_open";
+
+ /* Return-probe handler: If the probed function fails, log the return value. */
+ static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+ {
+- // Substitute the appropriate register name for your architecture --
+- // e.g., regs->rax for x86_64, regs->gpr[3] for ppc64.
+- int retval = (int) regs->eax;
++ int retval = regs_return_value(regs);
+ if (retval < 0) {
+ printk("%s returns %d\n", probed_func, retval);
+ }
+@@ -552,15 +575,11 @@ static struct kretprobe my_kretprobe = {
+ .maxactive = 20
+ };
+
+-int init_module(void)
++static int __init kretprobe_init(void)
+ {
+ int ret;
+- my_kretprobe.kp.addr =
+- (kprobe_opcode_t *) kallsyms_lookup_name(probed_func);
+- if (!my_kretprobe.kp.addr) {
+- printk("Couldn't find %s to plant return probe\n", probed_func);
+- return -1;
+- }
++ my_kretprobe.kp.symbol_name = (char *)probed_func;
++
+ if ((ret = register_kretprobe(&my_kretprobe)) < 0) {
+ printk("register_kretprobe failed, returned %d\n", ret);
+ return -1;
+@@ -569,7 +588,7 @@ int init_module(void)
+ return 0;
+ }
+
+-void cleanup_module(void)
++static void __exit kretprobe_exit(void)
+ {
+ unregister_kretprobe(&my_kretprobe);
+ printk("kretprobe unregistered\n");
+@@ -578,6 +597,8 @@ void cleanup_module(void)
+ my_kretprobe.nmissed, probed_func);
+ }
+
++module_init(kretprobe_init)
++module_exit(kretprobe_exit)
+ MODULE_LICENSE("GPL");
+ ----- cut here -----
+
+@@ -590,3 +611,5 @@ messages.)
+ For additional information on Kprobes, refer to the following URLs:
+ http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
+ http://www.redhat.com/magazine/005mar05/features/kprobes/
++http://www-users.cs.umn.edu/~boutcher/kprobes/
++http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
+diff --git a/Documentation/laptop-mode.txt b/Documentation/laptop-mode.txt
+index 5696e87..c487186 100644
+--- a/Documentation/laptop-mode.txt
++++ b/Documentation/laptop-mode.txt
+@@ -152,7 +152,7 @@ loaded on demand while the application e
+ DO_REMOUNTS:
+
+ The control script automatically remounts any mounted journaled filesystems
+-with approriate commit interval options. When this option is set to 0, this
++with appropriate commit interval options. When this option is set to 0, this
+ feature is disabled.
+
+ DO_REMOUNT_NOATIME:
+diff --git a/Documentation/lockdep-design.txt b/Documentation/lockdep-design.txt
+index 00d9360..4887730 100644
+--- a/Documentation/lockdep-design.txt
++++ b/Documentation/lockdep-design.txt
+@@ -36,6 +36,28 @@ The validator tracks lock-class usage hi
+
+ - 'ever used' [ == !unused ]
+
++When locking rules are violated, these 4 state bits are presented in the
++locking error messages, inside curlies. A contrived example:
++
++ modprobe/2287 is trying to acquire lock:
++ (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
++
++ but task is already holding lock:
++ (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
++
++
++The bit position indicates hardirq, softirq, hardirq-read,
++softirq-read respectively, and the character displayed in each
++indicates:
++
++ '.' acquired while irqs disabled
++ '+' acquired in irq context
++ '-' acquired with irqs enabled
++ '?' read acquired in irq context with irqs enabled.
++
++Unused mutexes cannot be part of the cause of an error.
++
++
+ Single-lock state rules:
+ ------------------------
+
+@@ -111,7 +133,7 @@ cases there is an inherent "natural" ord
+ (defined by the properties of the hierarchy), and the kernel grabs the
+ locks in this fixed order on each of the objects.
+
+-An example of such an object hieararchy that results in "nested locking"
++An example of such an object hierarchy that results in "nested locking"
+ is that of a "whole disk" block-dev object and a "partition" block-dev
+ object; the partition is "part of" the whole device and as long as one
+ always takes the whole disk lock as a higher lock than the partition
+@@ -136,11 +158,11 @@ enum bdev_bd_mutex_lock_class
+ In this case the locking is done on a bdev object that is known to be a
+ partition.
+
+-The validator treats a lock that is taken in such a nested fasion as a
++The validator treats a lock that is taken in such a nested fashion as a
+ separate (sub)class for the purposes of validation.
+
+ Note: When changing code to use the _nested() primitives, be careful and
+-check really thoroughly that the hiearchy is correctly mapped; otherwise
++check really thoroughly that the hierarchy is correctly mapped; otherwise
+ you can get false positives or false negatives.
+
+ Proof of 100% correctness:
+@@ -148,7 +170,7 @@ Proof of 100% correctness:
+
+ The validator achieves perfect, mathematical 'closure' (proof of locking
+ correctness) in the sense that for every simple, standalone single-task
+-locking sequence that occured at least once during the lifetime of the
++locking sequence that occurred at least once during the lifetime of the
+ kernel, the validator proves it with a 100% certainty that no
+ combination and timing of these locking sequences can cause any class of
+ lock related deadlock. [*]
+diff --git a/Documentation/m68k/kernel-options.txt b/Documentation/m68k/kernel-options.txt
+index d5d3f06..1c41db2 100644
+--- a/Documentation/m68k/kernel-options.txt
++++ b/Documentation/m68k/kernel-options.txt
+@@ -415,7 +415,7 @@ switch to another mode once Linux has st
+
+ The first 3 parameters of this sub-option should be obvious: <xres>,
+ <yres> and <depth> give the dimensions of the screen and the number of
+-planes (depth). The depth is is the logarithm to base 2 of the number
++planes (depth). The depth is the logarithm to base 2 of the number
+ of colors possible. (Or, the other way round: The number of colors is
+ 2^depth).
+
+diff --git a/Documentation/mca.txt b/Documentation/mca.txt
+index 6091335..aabce4a 100644
+--- a/Documentation/mca.txt
++++ b/Documentation/mca.txt
+@@ -177,7 +177,7 @@ Currently, there are a number of MCA-spe
+ with clones that have a different adapter id than the original
+ NE/2.
+
+-6) Future Domain MCS-600/700, OEM'd IBM Fast SCSI Aapter/A and
++6) Future Domain MCS-600/700, OEM'd IBM Fast SCSI Adapter/A and
+ Reply Sound Blaster/SCSI (SCSI part)
+ Better support for these cards than the driver for ISA.
+ Supports multiple cards with IRQ sharing.
+diff --git a/Documentation/md.txt b/Documentation/md.txt
+index 0668f9d..2202f5d 100644
+--- a/Documentation/md.txt
++++ b/Documentation/md.txt
+@@ -62,7 +62,7 @@ be reconstructed (due to no parity).
+
+ For this reason, md will normally refuse to start such an array. This
+ requires the sysadmin to take action to explicitly start the array
+-desipite possible corruption. This is normally done with
++despite possible corruption. This is normally done with
+ mdadm --assemble --force ....
+
+ This option is not really available if the array has the root
+@@ -154,11 +154,12 @@ contains further md-specific information
+
+ All md devices contain:
+ level
+- a text file indicating the 'raid level'. This may be a standard
+- numerical level prefixed by "RAID-" - e.g. "RAID-5", or some
+- other name such as "linear" or "multipath".
++ a text file indicating the 'raid level'. e.g. raid0, raid1,
++ raid5, linear, multipath, faulty.
+ If no raid level has been set yet (array is still being
+- assembled), this file will be empty.
++ assembled), the value will reflect whatever has been written
++ to it, which may be a name like the above, or may be a number
++ such as '0', '5', etc.
+
+ raid_disks
+ a text file with a simple number indicating the number of devices
+@@ -174,7 +175,7 @@ All md devices contain:
+ raid levels that involve striping (1,4,5,6,10). The address space
+ of the array is conceptually divided into chunks and consecutive
+ chunks are striped onto neighbouring devices.
+- The size should be atleast PAGE_SIZE (4k) and should be a power
++ The size should be at least PAGE_SIZE (4k) and should be a power
+ of 2. This can only be set while assembling an array
+
+ component_size
+@@ -192,14 +193,6 @@ All md devices contain:
+ 1.2 (newer format in varying locations) or "none" indicating that
+ the kernel isn't managing metadata at all.
+
+- level
+- The raid 'level' for this array. The name will often (but not
+- always) be the same as the name of the module that implements the
+- level. To be auto-loaded the module must have an alias
+- md-$LEVEL e.g. md-raid5
+- This can be written only while the array is being assembled, not
+- after it is started.
+-
+ layout
+ The "layout" for the array for the particular level. This is
+ simply a number that is interpretted differently by different
+@@ -221,8 +214,8 @@ All md devices contain:
+ safe_mode_delay
+ When an md array has seen no write requests for a certain period
+ of time, it will be marked as 'clean'. When another write
+- request arrive, the array is marked as 'dirty' before the write
+- commenses. This is known as 'safe_mode'.
++ request arrives, the array is marked as 'dirty' before the write
++ commences. This is known as 'safe_mode'.
+ The 'certain period' is controlled by this file which stores the
+ period as a number of seconds. The default is 200msec (0.200).
+ Writing a value of 0 disables safemode.
+@@ -314,8 +307,8 @@ Each directory contains:
+ This applies only to raid1 arrays.
+ spare - device is working, but not a full member.
+ This includes spares that are in the process
+- of being recoverred to
+- This list make grow in future.
++ of being recovered to
++ This list may grow in future.
+ This can be written to.
+ Writing "faulty" simulates a failure on the device.
+ Writing "remove" removes the device from the array.
+@@ -337,7 +330,7 @@ Each directory contains:
+ This gives the role that the device has in the array. It will
+ either be 'none' if the device is not active in the array
+ (i.e. is a spare or has failed) or an integer less than the
+- 'raid_disks' number for the array indicating which possition
++ 'raid_disks' number for the array indicating which position
+ it currently fills. This can only be set while assembling an
+ array. A device for which this is set is assumed to be working.
+
+@@ -360,7 +353,7 @@ in the array. These are named
+
+ rdNN
+
+-where 'NN' is the possition in the array, starting from 0.
++where 'NN' is the position in the array, starting from 0.
+ So for a 3 drive array there will be rd0, rd1, rd2.
+ These are symbolic links to the appropriate 'dev-XXX' entry.
+ Thus, for example,
+@@ -410,6 +403,15 @@ also have
+ than sectors, this my be larger than the number of actual errors
+ by a factor of the number of sectors in a page.
+
++ bitmap_set_bits
++ If the array has a write-intent bitmap, then writing to this
++ attribute can set bits in the bitmap, indicating that a resync
++ would need to check the corresponding blocks. Either individual
++ numbers or start-end pairs can be written. Multiple numbers
++ can be separated by a space.
++ Note that the numbers are 'bit' numbers, not 'block' numbers.
++ They should be scaled by the bitmap_chunksize.
++
+ Each active md device may also have attributes specific to the
+ personality module that manages it.
+ These are specific to the implementation of the module and could
+diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
+index 46b9b38..7f790f6 100644
+--- a/Documentation/memory-barriers.txt
++++ b/Documentation/memory-barriers.txt
+@@ -670,7 +670,7 @@ effectively random order, despite the wr
+
+
+ In the above example, CPU 2 perceives that B is 7, despite the load of *C
+-(which would be B) coming after the the LOAD of C.
++(which would be B) coming after the LOAD of C.
+
+ If, however, a data dependency barrier were to be placed between the load of C
+ and the load of *C (ie: B) on CPU 2:
+@@ -1898,7 +1898,7 @@ queue before processing any further requ
+ smp_wmb();
+ <A:modify v=2> <C:busy>
+ <C:queue v=2>
+- p = &b; q = p;
++ p = &v; q = p;
+ <D:request p>
+ <B:modify p=&v> <D:commit p=&v>
+ <D:read p>
+@@ -1915,7 +1915,7 @@ Whilst most CPUs do imply a data depende
+ access depends on a read, not all do, so it may not be relied on.
+
+ Other CPUs may also have split caches, but must coordinate between the various
+-cachelets for normal memory accesss. The semantics of the Alpha removes the
++cachelets for normal memory accesses. The semantics of the Alpha removes the
+ need for coordination in absence of memory barriers.
+
+
+diff --git a/Documentation/mips/time.README b/Documentation/mips/time.README
+index 69ddc5c..a4ce603 100644
+--- a/Documentation/mips/time.README
++++ b/Documentation/mips/time.README
+@@ -38,19 +38,14 @@ The new time code provide the following
+
+ a) Implements functions required by Linux common code:
+ time_init
+- do_gettimeofday
+- do_settimeofday
+
+ b) provides an abstraction of RTC and null RTC implementation as default.
+ extern unsigned long (*rtc_get_time)(void);
+ extern int (*rtc_set_time)(unsigned long);
+
+- c) a set of gettimeoffset functions for different CPUs and different
+- needs.
+-
+- d) high-level and low-level timer interrupt routines where the timer
+- interrupt source may or may not be the CPU timer. The high-level
+- routine is dispatched through do_IRQ() while the low-level is
++ c) high-level and low-level timer interrupt routines where the timer
++ interrupt source may or may not be the CPU timer. The high-level
++ routine is dispatched through do_IRQ() while the low-level is
+ dispatched in assemably code (usually int-handler.S)
+
+
+@@ -63,7 +58,7 @@ the following functions or values:
+ a) board_time_init - a function pointer. Invoked at the beginnig of
+ time_init(). It is optional.
+ 1. (optional) set up RTC routines
+- 2. (optional) calibrate and set the mips_counter_frequency
++ 2. (optional) calibrate and set the mips_hpt_frequency
+
+ b) plat_timer_setup - a function pointer. Invoked at the end of time_init()
+ 1. (optional) over-ride any decisions made in time_init()
+@@ -72,9 +67,8 @@ the following functions or values:
+
+ c) (optional) board-specific RTC routines.
+
+- d) (optional) mips_counter_frequency - It must be definied if the board
+- is using CPU counter for timer interrupt or it is using fixed rate
+- gettimeoffset().
++ d) (optional) mips_hpt_frequency - It must be definied if the board
++ is using CPU counter for timer interrupt.
+
+
+ PORTING GUIDE
+@@ -89,22 +83,12 @@ Step 1: decide how you like to implement
+ If the answer is no, you need a timer to provide the timer interrupt
+ at 100 HZ speed.
+
+- You cannot use the fast gettimeoffset functions, i.e.,
+-
+- unsigned long fixed_rate_gettimeoffset(void);
+- unsigned long calibrate_div32_gettimeoffset(void);
+- unsigned long calibrate_div64_gettimeoffset(void);
+-
+- You can use null_gettimeoffset() will gives the same time resolution as
+- jiffy. Or you can implement your own gettimeoffset (probably based on
+- some ad hoc hardware on your machine.)
+-
+ c) The following sub steps assume your CPU has counter register.
+ Do you plan to use the CPU counter register as the timer interrupt
+ or use an exnternal timer?
+
+ In order to use CPU counter register as the timer interrupt source, you
+- must know the counter speed (mips_counter_frequency). It is usually the
++ must know the counter speed (mips_hpt_frequency). It is usually the
+ same as the CPU speed or an integral divisor of it.
+
+ d) decide on whether you want to use high-level or low-level timer
+@@ -121,10 +105,10 @@ Step 3: implement rtc routines, board_ti
+ if needed.
+
+ board_time_init() -
+- a) (optional) set up RTC routines,
+- b) (optional) calibrate and set the mips_counter_frequency
+- (only needed if you intended to use fixed_rate_gettimeoffset
+- or use cpu counter as timer interrupt source)
++ a) (optional) set up RTC routines,
++ b) (optional) calibrate and set the mips_hpt_frequency
++ (only needed if you intended to use cpu counter as timer interrupt
++ source)
+
+ plat_timer_setup() -
+ a) (optional) over-write any choices made above by time_init().
+@@ -154,8 +138,8 @@ for some of the functions in time.c.
+ For example, you may define your own timer interrupt routine, which does
+ some of its own processing and then calls timer_interrupt().
+
+-You can also over-ride any of the built-in functions (gettimeoffset,
+-RTC routines and/or timer interrupt routine).
++You can also over-ride any of the built-in functions (RTC routines
++and/or timer interrupt routine).
+
+
+ PORTING NOTES FOR SMP
+@@ -187,10 +171,3 @@ You need to decide on your timer interru
+
+ You can also do the low-level version of those interrupt routines,
+ following similar dispatching routes described above.
+-
+-Note about do_gettimeoffset():
+-
+- It is very likely the CPU counter registers are not sync'ed up in a SMP box.
+- Therefore you cannot really use the many of the existing routines that
+- are based on CPU counter. You should wirte your own gettimeoffset rouinte
+- if you want intra-jiffy resolution.
+diff --git a/Documentation/mono.txt b/Documentation/mono.txt
+index 807a0c7..e8e1758 100644
+--- a/Documentation/mono.txt
++++ b/Documentation/mono.txt
+@@ -26,7 +26,7 @@ other program after you have done the fo
+ the kernel (CONFIG_BINFMT_MISC) and set it up properly.
+ If you choose to compile it as a module, you will have
+ to insert it manually with modprobe/insmod, as kmod
+- can not be easily supported with binfmt_misc.
++ cannot be easily supported with binfmt_misc.
+ Read the file 'binfmt_misc.txt' in this directory to know
+ more about the configuration process.
+
+diff --git a/Documentation/netlabel/00-INDEX b/Documentation/netlabel/00-INDEX
+new file mode 100644
+index 0000000..837bf35
+--- /dev/null
++++ b/Documentation/netlabel/00-INDEX
+@@ -0,0 +1,10 @@
++00-INDEX
++ - this file.
++cipso_ipv4.txt
++ - documentation on the IPv4 CIPSO protocol engine.
++draft-ietf-cipso-ipsecurity-01.txt
++ - IETF draft of the CIPSO protocol, dated 16 July 1992.
++introduction.txt
++ - NetLabel introduction, READ THIS FIRST.
++lsm_interface.txt
++ - documentation on the NetLabel kernel security module API.
+diff --git a/Documentation/netlabel/cipso_ipv4.txt b/Documentation/netlabel/cipso_ipv4.txt
+new file mode 100644
+index 0000000..93dacb1
+--- /dev/null
++++ b/Documentation/netlabel/cipso_ipv4.txt
+@@ -0,0 +1,48 @@
++NetLabel CIPSO/IPv4 Protocol Engine
++==============================================================================
++Paul Moore, paul.moore at hp.com
++
++May 17, 2006
++
++ * Overview
++
++The NetLabel CIPSO/IPv4 protocol engine is based on the IETF Commercial IP
++Security Option (CIPSO) draft from July 16, 1992. A copy of this draft can be
++found in this directory, consult '00-INDEX' for the filename. While the IETF
++draft never made it to an RFC standard it has become a de-facto standard for
++labeled networking and is used in many trusted operating systems.
++
++ * Outbound Packet Processing
++
++The CIPSO/IPv4 protocol engine applies the CIPSO IP option to packets by
++adding the CIPSO label to the socket. This causes all packets leaving the
++system through the socket to have the CIPSO IP option applied. The socket's
++CIPSO label can be changed at any point in time, however, it is recommended
++that it is set upon the socket's creation. The LSM can set the socket's CIPSO
++label by using the NetLabel security module API; if the NetLabel "domain" is
++configured to use CIPSO for packet labeling then a CIPSO IP option will be
++generated and attached to the socket.
++
++ * Inbound Packet Processing
++
++The CIPSO/IPv4 protocol engine validates every CIPSO IP option it finds at the
++IP layer without any special handling required by the LSM. However, in order
++to decode and translate the CIPSO label on the packet the LSM must use the
++NetLabel security module API to extract the security attributes of the packet.
++This is typically done at the socket layer using the 'socket_sock_rcv_skb()'
++LSM hook.
++
++ * Label Translation
++
++The CIPSO/IPv4 protocol engine contains a mechanism to translate CIPSO security
++attributes such as sensitivity level and category to values which are
++appropriate for the host. These mappings are defined as part of a CIPSO
++Domain Of Interpretation (DOI) definition and are configured through the
++NetLabel user space communication layer. Each DOI definition can have a
++different security attribute mapping table.
++
++ * Label Translation Cache
++
++The NetLabel system provides a framework for caching security attribute
++mappings from the network labels to the corresponding LSM identifiers. The
++CIPSO/IPv4 protocol engine supports this caching mechanism.
+diff --git a/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt b/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt
+new file mode 100644
+index 0000000..256c2c9
+--- /dev/null
++++ b/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt
+@@ -0,0 +1,791 @@
++IETF CIPSO Working Group
++16 July, 1992
++
++
++
++ COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
++
++
++
++1. Status
++
++This Internet Draft provides the high level specification for a Commercial
++IP Security Option (CIPSO). This draft reflects the version as approved by
++the CIPSO IETF Working Group. Distribution of this memo is unlimited.
++
++This document is an Internet Draft. Internet Drafts are working documents
++of the Internet Engineering Task Force (IETF), its Areas, and its Working
++Groups. Note that other groups may also distribute working documents as
++Internet Drafts.
++
++Internet Drafts are draft documents valid for a maximum of six months.
++Internet Drafts may be updated, replaced, or obsoleted by other documents
++at any time. It is not appropriate to use Internet Drafts as reference
++material or to cite them other than as a "working draft" or "work in
++progress."
++
++Please check the I-D abstract listing contained in each Internet Draft
++directory to learn the current status of this or any other Internet Draft.
++
++
++
++
++2. Background
++
++Currently the Internet Protocol includes two security options. One of
++these options is the DoD Basic Security Option (BSO) (Type 130) which allows
++IP datagrams to be labeled with security classifications. This option
++provides sixteen security classifications and a variable number of handling
++restrictions. To handle additional security information, such as security
++categories or compartments, another security option (Type 133) exists and
++is referred to as the DoD Extended Security Option (ESO). The values for
++the fixed fields within these two options are administered by the Defense
++Information Systems Agency (DISA).
++
++Computer vendors are now building commercial operating systems with
++mandatory access controls and multi-level security. These systems are
++no longer built specifically for a particular group in the defense or
++intelligence communities. They are generally available commercial systems
++for use in a variety of government and civil sector environments.
++
++The small number of ESO format codes can not support all the possible
++applications of a commercial security option. The BSO and ESO were
++designed to only support the United States DoD. CIPSO has been designed
++to support multiple security policies. This Internet Draft provides the
++format and procedures required to support a Mandatory Access Control
++security policy. Support for additional security policies shall be
++defined in future RFCs.
++
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 1]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++
++3. CIPSO Format
++
++Option type: 134 (Class 0, Number 6, Copy on Fragmentation)
++Option length: Variable
++
++This option permits security related information to be passed between
++systems within a single Domain of Interpretation (DOI). A DOI is a
++collection of systems which agree on the meaning of particular values
++in the security option. An authority that has been assigned a DOI
++identifier will define a mapping between appropriate CIPSO field values
++and their human readable equivalent. This authority will distribute that
++mapping to hosts within the authority's domain. These mappings may be
++sensitive, therefore a DOI authority is not required to make these
++mappings available to anyone other than the systems that are included in
++the DOI.
++
++This option MUST be copied on fragmentation. This option appears at most
++once in a datagram. All multi-octet fields in the option are defined to be
++transmitted in network byte order. The format of this option is as follows:
++
+++----------+----------+------//------+-----------//---------+
++| 10000110 | LLLLLLLL | DDDDDDDDDDDD | TTTTTTTTTTTTTTTTTTTT |
+++----------+----------+------//------+-----------//---------+
++
++ TYPE=134 OPTION DOMAIN OF TAGS
++ LENGTH INTERPRETATION
++
++
++ Figure 1. CIPSO Format
++
++
++3.1 Type
++
++This field is 1 octet in length. Its value is 134.
++
++
++3.2 Length
++
++This field is 1 octet in length. It is the total length of the option
++including the type and length fields. With the current IP header length
++restriction of 40 octets the value of this field MUST not exceed 40.
++
++
++3.3 Domain of Interpretation Identifier
++
++This field is an unsigned 32 bit integer. The value 0 is reserved and MUST
++not appear as the DOI identifier in any CIPSO option. Implementations
++should assume that the DOI identifier field is not aligned on any particular
++byte boundary.
++
++To conserve space in the protocol, security levels and categories are
++represented by numbers rather than their ASCII equivalent. This requires
++a mapping table within CIPSO hosts to map these numbers to their
++corresponding ASCII representations. Non-related groups of systems may
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 2]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++have their own unique mappings. For example, one group of systems may
++use the number 5 to represent Unclassified while another group may use the
++number 1 to represent that same security level. The DOI identifier is used
++to identify which mapping was used for the values within the option.
++
++
++3.4 Tag Types
++
++A common format for passing security related information is necessary
++for interoperability. CIPSO uses sets of "tags" to contain the security
++information relevant to the data in the IP packet. Each tag begins with
++a tag type identifier followed by the length of the tag and ends with the
++actual security information to be passed. All multi-octet fields in a tag
++are defined to be transmitted in network byte order. Like the DOI
++identifier field in the CIPSO header, implementations should assume that
++all tags, as well as fields within a tag, are not aligned on any particular
++octet boundary. The tag types defined in this document contain alignment
++bytes to assist alignment of some information, however alignment can not
++be guaranteed if CIPSO is not the first IP option.
++
++CIPSO tag types 0 through 127 are reserved for defining standard tag
++formats. Their definitions will be published in RFCs. Tag types whose
++identifiers are greater than 127 are defined by the DOI authority and may
++only be meaningful in certain Domains of Interpretation. For these tag
++types, implementations will require the DOI identifier as well as the tag
++number to determine the security policy and the format associated with the
++tag. Use of tag types above 127 are restricted to closed networks where
++interoperability with other networks will not be an issue. Implementations
++that support a tag type greater than 127 MUST support at least one DOI that
++requires only tag types 1 to 127.
++
++Tag type 0 is reserved. Tag types 1, 2, and 5 are defined in this
++Internet Draft. Types 3 and 4 are reserved for work in progress.
++The standard format for all current and future CIPSO tags is shown below:
++
+++----------+----------+--------//--------+
++| TTTTTTTT | LLLLLLLL | IIIIIIIIIIIIIIII |
+++----------+----------+--------//--------+
++ TAG TAG TAG
++ TYPE LENGTH INFORMATION
++
++ Figure 2: Standard Tag Format
++
++In the three tag types described in this document, the length and count
++restrictions are based on the current IP limitation of 40 octets for all
++IP options. If the IP header is later expanded, then the length and count
++restrictions specified in this document may increase to use the full area
++provided for IP options.
++
++
++3.4.1 Tag Type Classes
++
++Tag classes consist of tag types that have common processing requirements
++and support the same security policy. The three tags defined in this
++Internet Draft belong to the Mandatory Access Control (MAC) Sensitivity
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 3]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++class and support the MAC Sensitivity security policy.
++
++
++3.4.2 Tag Type 1
++
++This is referred to as the "bit-mapped" tag type. Tag type 1 is included
++in the MAC Sensitivity tag type class. The format of this tag type is as
++follows:
++
+++----------+----------+----------+----------+--------//---------+
++| 00000001 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCC |
+++----------+----------+----------+----------+--------//---------+
++
++ TAG TAG ALIGNMENT SENSITIVITY BIT MAP OF
++ TYPE LENGTH OCTET LEVEL CATEGORIES
++
++ Figure 3. Tag Type 1 Format
++
++
++3.4.2.1 Tag Type
++
++This field is 1 octet in length and has a value of 1.
++
++
++3.4.2.2 Tag Length
++
++This field is 1 octet in length. It is the total length of the tag type
++including the type and length fields. With the current IP header length
++restriction of 40 bytes the value within this field is between 4 and 34.
++
++
++3.4.2.3 Alignment Octet
++
++This field is 1 octet in length and always has the value of 0. Its purpose
++is to align the category bitmap field on an even octet boundary. This will
++speed many implementations including router implementations.
++
++
++3.4.2.4 Sensitivity Level
++
++This field is 1 octet in length. Its value is from 0 to 255. The values
++are ordered with 0 being the minimum value and 255 representing the maximum
++value.
++
++
++3.4.2.5 Bit Map of Categories
++
++The length of this field is variable and ranges from 0 to 30 octets. This
++provides representation of categories 0 to 239. The ordering of the bits
++is left to right or MSB to LSB. For example category 0 is represented by
++the most significant bit of the first byte and category 15 is represented
++by the least significant bit of the second byte. Figure 4 graphically
++shows this ordering. Bit N is binary 1 if category N is part of the label
++for the datagram, and bit N is binary 0 if category N is not part of the
++label. Except for the optimized tag 1 format described in the next section,
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 4]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++minimal encoding SHOULD be used resulting in no trailing zero octets in the
++category bitmap.
++
++ octet 0 octet 1 octet 2 octet 3 octet 4 octet 5
++ XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX . . .
++bit 01234567 89111111 11112222 22222233 33333333 44444444
++number 012345 67890123 45678901 23456789 01234567
++
++ Figure 4. Ordering of Bits in Tag 1 Bit Map
++
++
++3.4.2.6 Optimized Tag 1 Format
++
++Routers work most efficiently when processing fixed length fields. To
++support these routers there is an optimized form of tag type 1. The format
++does not change. The only change is to the category bitmap which is set to
++a constant length of 10 octets. Trailing octets required to fill out the 10
++octets are zero filled. Ten octets, allowing for 80 categories, was chosen
++because it makes the total length of the CIPSO option 20 octets. If CIPSO
++is the only option then the option will be full word aligned and additional
++filler octets will not be required.
++
++
++3.4.3 Tag Type 2
++
++This is referred to as the "enumerated" tag type. It is used to describe
++large but sparsely populated sets of categories. Tag type 2 is in the MAC
++Sensitivity tag type class. The format of this tag type is as follows:
++
+++----------+----------+----------+----------+-------------//-------------+
++| 00000010 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCCCCCCCCCCC |
+++----------+----------+----------+----------+-------------//-------------+
++
++ TAG TAG ALIGNMENT SENSITIVITY ENUMERATED
++ TYPE LENGTH OCTET LEVEL CATEGORIES
++
++ Figure 5. Tag Type 2 Format
++
++
++3.4.3.1 Tag Type
++
++This field is one octet in length and has a value of 2.
++
++
++3.4.3.2 Tag Length
++
++This field is 1 octet in length. It is the total length of the tag type
++including the type and length fields. With the current IP header length
++restriction of 40 bytes the value within this field is between 4 and 34.
++
++
++3.4.3.3 Alignment Octet
++
++This field is 1 octet in length and always has the value of 0. Its purpose
++is to align the category field on an even octet boundary. This will
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 5]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++speed many implementations including router implementations.
++
++
++3.4.3.4 Sensitivity Level
++
++This field is 1 octet in length. Its value is from 0 to 255. The values
++are ordered with 0 being the minimum value and 255 representing the
++maximum value.
++
++
++3.4.3.5 Enumerated Categories
++
++In this tag, categories are represented by their actual value rather than
++by their position within a bit field. The length of each category is 2
++octets. Up to 15 categories may be represented by this tag. Valid values
++for categories are 0 to 65534. Category 65535 is not a valid category
++value. The categories MUST be listed in ascending order within the tag.
++
++
++3.4.4 Tag Type 5
++
++This is referred to as the "range" tag type. It is used to represent
++labels where all categories in a range, or set of ranges, are included
++in the sensitivity label. Tag type 5 is in the MAC Sensitivity tag type
++class. The format of this tag type is as follows:
++
+++----------+----------+----------+----------+------------//-------------+
++| 00000101 | LLLLLLLL | 00000000 | LLLLLLLL | Top/Bottom | Top/Bottom |
+++----------+----------+----------+----------+------------//-------------+
++
++ TAG TAG ALIGNMENT SENSITIVITY CATEGORY RANGES
++ TYPE LENGTH OCTET LEVEL
++
++ Figure 6. Tag Type 5 Format
++
++
++3.4.4.1 Tag Type
++
++This field is one octet in length and has a value of 5.
++
++
++3.4.4.2 Tag Length
++
++This field is 1 octet in length. It is the total length of the tag type
++including the type and length fields. With the current IP header length
++restriction of 40 bytes the value within this field is between 4 and 34.
++
++
++3.4.4.3 Alignment Octet
++
++This field is 1 octet in length and always has the value of 0. Its purpose
++is to align the category range field on an even octet boundary. This will
++speed many implementations including router implementations.
++
++
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 6]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++3.4.4.4 Sensitivity Level
++
++This field is 1 octet in length. Its value is from 0 to 255. The values
++are ordered with 0 being the minimum value and 255 representing the maximum
++value.
++
++
++3.4.4.5 Category Ranges
++
++A category range is a 4 octet field comprised of the 2 octet index of the
++highest numbered category followed by the 2 octet index of the lowest
++numbered category. These range endpoints are inclusive within the range of
++categories. All categories within a range are included in the sensitivity
++label. This tag may contain a maximum of 7 category pairs. The bottom
++category endpoint for the last pair in the tag MAY be omitted and SHOULD be
++assumed to be 0. The ranges MUST be non-overlapping and be listed in
++descending order. Valid values for categories are 0 to 65534. Category
++65535 is not a valid category value.
++
++
++3.4.5 Minimum Requirements
++
++A CIPSO implementation MUST be capable of generating at least tag type 1 in
++the non-optimized form. In addition, a CIPSO implementation MUST be able
++to receive any valid tag type 1 even those using the optimized tag type 1
++format.
++
++
++4. Configuration Parameters
++
++The configuration parameters defined below are required for all CIPSO hosts,
++gateways, and routers that support multiple sensitivity labels. A CIPSO
++host is defined to be the origination or destination system for an IP
++datagram. A CIPSO gateway provides IP routing services between two or more
++IP networks and may be required to perform label translations between
++networks. A CIPSO gateway may be an enhanced CIPSO host or it may just
++provide gateway services with no end system CIPSO capabilities. A CIPSO
++router is a dedicated IP router that routes IP datagrams between two or more
++IP networks.
++
++An implementation of CIPSO on a host MUST have the capability to reject a
++datagram for reasons that the information contained can not be adequately
++protected by the receiving host or if acceptance may result in violation of
++the host or network security policy. In addition, a CIPSO gateway or router
++MUST be able to reject datagrams going to networks that can not provide
++adequate protection or may violate the network's security policy. To
++provide this capability the following minimal set of configuration
++parameters are required for CIPSO implementations:
++
++HOST_LABEL_MAX - This parameter contains the maximum sensitivity label that
++a CIPSO host is authorized to handle. All datagrams that have a label
++greater than this maximum MUST be rejected by the CIPSO host. This
++parameter does not apply to CIPSO gateways or routers. This parameter need
++not be defined explicitly as it can be implicitly derived from the
++PORT_LABEL_MAX parameters for the associated interfaces.
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 7]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++
++HOST_LABEL_MIN - This parameter contains the minimum sensitivity label that
++a CIPSO host is authorized to handle. All datagrams that have a label less
++than this minimum MUST be rejected by the CIPSO host. This parameter does
++not apply to CIPSO gateways or routers. This parameter need not be defined
++explicitly as it can be implicitly derived from the PORT_LABEL_MIN
++parameters for the associated interfaces.
++
++PORT_LABEL_MAX - This parameter contains the maximum sensitivity label for
++all datagrams that may exit a particular network interface port. All
++outgoing datagrams that have a label greater than this maximum MUST be
++rejected by the CIPSO system. The label within this parameter MUST be
++less than or equal to the label within the HOST_LABEL_MAX parameter. This
++parameter does not apply to CIPSO hosts that support only one network port.
++
++PORT_LABEL_MIN - This parameter contains the minimum sensitivity label for
++all datagrams that may exit a particular network interface port. All
++outgoing datagrams that have a label less than this minimum MUST be
++rejected by the CIPSO system. The label within this parameter MUST be
++greater than or equal to the label within the HOST_LABEL_MIN parameter.
++This parameter does not apply to CIPSO hosts that support only one network
++port.
++
++PORT_DOI - This parameter is used to assign a DOI identifier value to a
++particular network interface port. All CIPSO labels within datagrams
++going out this port MUST use the specified DOI identifier. All CIPSO
++hosts and gateways MUST support either this parameter, the NET_DOI
++parameter, or the HOST_DOI parameter.
++
++NET_DOI - This parameter is used to assign a DOI identifier value to a
++particular IP network address. All CIPSO labels within datagrams destined
++for the particular IP network MUST use the specified DOI identifier. All
++CIPSO hosts and gateways MUST support either this parameter, the PORT_DOI
++parameter, or the HOST_DOI parameter.
++
++HOST_DOI - This parameter is used to assign a DOI identifier value to a
++particular IP host address. All CIPSO labels within datagrams destined for
++the particular IP host will use the specified DOI identifier. All CIPSO
++hosts and gateways MUST support either this parameter, the PORT_DOI
++parameter, or the NET_DOI parameter.
++
++This list represents the minimal set of configuration parameters required
++to be compliant. Implementors are encouraged to add to this list to
++provide enhanced functionality and control. For example, many security
++policies may require both incoming and outgoing datagrams be checked against
++the port and host label ranges.
++
++
++4.1 Port Range Parameters
++
++The labels represented by the PORT_LABEL_MAX and PORT_LABEL_MIN parameters
++MAY be in CIPSO or local format. Some CIPSO systems, such as routers, may
++want to have the range parameters expressed in CIPSO format so that incoming
++labels do not have to be converted to a local format before being compared
++against the range. If multiple DOIs are supported by one of these CIPSO
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 8]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++systems then multiple port range parameters would be needed, one set for
++each DOI supported on a particular port.
++
++The port range will usually represent the total set of labels that may
++exist on the logical network accessed through the corresponding network
++interface. It may, however, represent a subset of these labels that are
++allowed to enter the CIPSO system.
++
++
++4.2 Single Label CIPSO Hosts
++
++CIPSO implementations that support only one label are not required to
++support the parameters described above. These limited implementations are
++only required to support a NET_LABEL parameter. This parameter contains
++the CIPSO label that may be inserted in datagrams that exit the host. In
++addition, the host MUST reject any incoming datagram that has a label which
++is not equivalent to the NET_LABEL parameter.
++
++
++5. Handling Procedures
++
++This section describes the processing requirements for incoming and
++outgoing IP datagrams. Just providing the correct CIPSO label format
++is not enough. Assumptions will be made by one system on how a
++receiving system will handle the CIPSO label. Wrong assumptions may
++lead to non-interoperability or even a security incident. The
++requirements described below represent the minimal set needed for
++interoperability and that provide users some level of confidence.
++Many other requirements could be added to increase user confidence,
++however at the risk of restricting creativity and limiting vendor
++participation.
++
++
++5.1 Input Procedures
++
++All datagrams received through a network port MUST have a security label
++associated with them, either contained in the datagram or assigned to the
++receiving port. Without this label the host, gateway, or router will not
++have the information it needs to make security decisions. This security
++label will be obtained from the CIPSO if the option is present in the
++datagram. See section 4.1.2 for handling procedures for unlabeled
++datagrams. This label will be compared against the PORT (if appropriate)
++and HOST configuration parameters defined in section 3.
++
++If any field within the CIPSO option, such as the DOI identifier, is not
++recognized the IP datagram is discarded and an ICMP "parameter problem"
++(type 12) is generated and returned. The ICMP code field is set to "bad
++parameter" (code 0) and the pointer is set to the start of the CIPSO field
++that is unrecognized.
++
++If the contents of the CIPSO are valid but the security label is
++outside of the configured host or port label range, the datagram is
++discarded and an ICMP "destination unreachable" (type 3) is generated
++and returned. The code field of the ICMP is set to "communication with
++destination network administratively prohibited" (code 9) or to
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 9]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++"communication with destination host administratively prohibited"
++(code 10). The value of the code field used is dependent upon whether
++the originator of the ICMP message is acting as a CIPSO host or a CIPSO
++gateway. The recipient of the ICMP message MUST be able to handle either
++value. The same procedure is performed if a CIPSO can not be added to an
++IP packet because it is too large to fit in the IP options area.
++
++If the error is triggered by receipt of an ICMP message, the message
++is discarded and no response is permitted (consistent with general ICMP
++processing rules).
++
++
++5.1.1 Unrecognized tag types
++
++The default condition for any CIPSO implementation is that an
++unrecognized tag type MUST be treated as a "parameter problem" and
++handled as described in section 4.1. A CIPSO implementation MAY allow
++the system administrator to identify tag types that may safely be
++ignored. This capability is an allowable enhancement, not a
++requirement.
++
++
++5.1.2 Unlabeled Packets
++
++A network port may be configured to not require a CIPSO label for all
++incoming datagrams. For this configuration a CIPSO label must be
++assigned to that network port and associated with all unlabeled IP
++datagrams. This capability might be used for single level networks or
++networks that have CIPSO and non-CIPSO hosts and the non-CIPSO hosts
++all operate at the same label.
++
++If a CIPSO option is required and none is found, the datagram is
++discarded and an ICMP "parameter problem" (type 12) is generated and
++returned to the originator of the datagram. The code field of the ICMP
++is set to "option missing" (code 1) and the ICMP pointer is set to 134
++(the value of the option type for the missing CIPSO option).
++
++
++5.2 Output Procedures
++
++A CIPSO option MUST appear only once in a datagram. Only one tag type
++from the MAC Sensitivity class MAY be included in a CIPSO option. Given
++the current set of defined tag types, this means that CIPSO labels at
++first will contain only one tag.
++
++All datagrams leaving a CIPSO system MUST meet the following condition:
++
++ PORT_LABEL_MIN <= CIPSO label <= PORT_LABEL_MAX
++
++If this condition is not satisfied the datagram MUST be discarded.
++If the CIPSO system only supports one port, the HOST_LABEL_MIN and the
++HOST_LABEL_MAX parameters MAY be substituted for the PORT parameters in
++the above condition.
++
++The DOI identifier to be used for all outgoing datagrams is configured by
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 10]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++the administrator. If port level DOI identifier assignment is used, then
++the PORT_DOI configuration parameter MUST contain the DOI identifier to
++use. If network level DOI assignment is used, then the NET_DOI parameter
++MUST contain the DOI identifier to use. And if host level DOI assignment
++is employed, then the HOST_DOI parameter MUST contain the DOI identifier
++to use. A CIPSO implementation need only support one level of DOI
++assignment.
++
++
++5.3 DOI Processing Requirements
++
++A CIPSO implementation MUST support at least one DOI and SHOULD support
++multiple DOIs. System and network administrators are cautioned to
++ensure that at least one DOI is common within an IP network to allow for
++broadcasting of IP datagrams.
++
++CIPSO gateways MUST be capable of translating a CIPSO option from one
++DOI to another when forwarding datagrams between networks. For
++efficiency purposes this capability is only a desired feature for CIPSO
++routers.
++
++
++5.4 Label of ICMP Messages
++
++The CIPSO label to be used on all outgoing ICMP messages MUST be equivalent
++to the label of the datagram that caused the ICMP message. If the ICMP was
++generated due to a problem associated with the original CIPSO label then the
++following responses are allowed:
++
++ a. Use the CIPSO label of the original IP datagram
++ b. Drop the original datagram with no return message generated
++
++In most cases these options will have the same effect. If you can not
++interpret the label or if it is outside the label range of your host or
++interface then an ICMP message with the same label will probably not be
++able to exit the system.
++
++
++6. Assignment of DOI Identifier Numbers =
++
++Requests for assignment of a DOI identifier number should be addressed to
++the Internet Assigned Numbers Authority (IANA).
++
++
++7. Acknowledgements
++
++Much of the material in this RFC is based on (and copied from) work
++done by Gary Winiger of Sun Microsystems and published as Commercial
++IP Security Option at the INTEROP 89, Commercial IPSO Workshop.
++
++
++8. Author's Address
++
++To submit mail for distribution to members of the IETF CIPSO Working
++Group, send mail to: cipso at wdl1.wdl.loral.com.
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 11]
++
++
++
++CIPSO INTERNET DRAFT 16 July, 1992
++
++
++
++
++To be added to or deleted from this distribution, send mail to:
++cipso-request at wdl1.wdl.loral.com.
++
++
++9. References
++
++RFC 1038, "Draft Revised IP Security Option", M. St. Johns, IETF, January
++1988.
++
++RFC 1108, "U.S. Department of Defense Security Options
++for the Internet Protocol", Stephen Kent, IAB, 1 March, 1991.
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++Internet Draft, Expires 15 Jan 93 [PAGE 12]
++
++
++
+diff --git a/Documentation/netlabel/introduction.txt b/Documentation/netlabel/introduction.txt
+new file mode 100644
+index 0000000..a4ffba1
+--- /dev/null
++++ b/Documentation/netlabel/introduction.txt
+@@ -0,0 +1,46 @@
++NetLabel Introduction
++==============================================================================
++Paul Moore, paul.moore at hp.com
++
++August 2, 2006
++
++ * Overview
++
++NetLabel is a mechanism which can be used by kernel security modules to attach
++security attributes to outgoing network packets generated from user space
++applications and read security attributes from incoming network packets. It
++is composed of three main components, the protocol engines, the communication
++layer, and the kernel security module API.
++
++ * Protocol Engines
++
++The protocol engines are responsible for both applying and retrieving the
++network packet's security attributes. If any translation between the network
++security attributes and those on the host are required then the protocol
++engine will handle those tasks as well. Other kernel subsystems should
++refrain from calling the protocol engines directly, instead they should use
++the NetLabel kernel security module API described below.
++
++Detailed information about each NetLabel protocol engine can be found in this
++directory, consult '00-INDEX' for filenames.
++
++ * Communication Layer
++
++The communication layer exists to allow NetLabel configuration and monitoring
++from user space. The NetLabel communication layer uses a message based
++protocol built on top of the Generic NETLINK transport mechanism. The exact
++formatting of these NetLabel messages as well as the Generic NETLINK family
++names can be found in the the 'net/netlabel/' directory as comments in the
++header files as well as in 'include/net/netlabel.h'.
++
++ * Security Module API
++
++The purpose of the NetLabel security module API is to provide a protocol
++independent interface to the underlying NetLabel protocol engines. In addition
++to protocol independence, the security module API is designed to be completely
++LSM independent which should allow multiple LSMs to leverage the same code
++base.
++
++Detailed information about the NetLabel security module API can be found in the
++'include/net/netlabel.h' header file as well as the 'lsm_interface.txt' file
++found in this directory.
+diff --git a/Documentation/netlabel/lsm_interface.txt b/Documentation/netlabel/lsm_interface.txt
+new file mode 100644
+index 0000000..98dd9f7
+--- /dev/null
++++ b/Documentation/netlabel/lsm_interface.txt
+@@ -0,0 +1,47 @@
++NetLabel Linux Security Module Interface
++==============================================================================
++Paul Moore, paul.moore at hp.com
++
++May 17, 2006
++
++ * Overview
++
++NetLabel is a mechanism which can set and retrieve security attributes from
++network packets. It is intended to be used by LSM developers who want to make
++use of a common code base for several different packet labeling protocols.
++The NetLabel security module API is defined in 'include/net/netlabel.h' but a
++brief overview is given below.
++
++ * NetLabel Security Attributes
++
++Since NetLabel supports multiple different packet labeling protocols and LSMs
++it uses the concept of security attributes to refer to the packet's security
++labels. The NetLabel security attributes are defined by the
++'netlbl_lsm_secattr' structure in the NetLabel header file. Internally the
++NetLabel subsystem converts the security attributes to and from the correct
++low-level packet label depending on the NetLabel build time and run time
++configuration. It is up to the LSM developer to translate the NetLabel
++security attributes into whatever security identifiers are in use for their
++particular LSM.
++
++ * NetLabel LSM Protocol Operations
++
++These are the functions which allow the LSM developer to manipulate the labels
++on outgoing packets as well as read the labels on incoming packets. Functions
++exist to operate both on sockets as well as the sk_buffs directly. These high
++level functions are translated into low level protocol operations based on how
++the administrator has configured the NetLabel subsystem.
++
++ * NetLabel Label Mapping Cache Operations
++
++Depending on the exact configuration, translation between the network packet
++label and the internal LSM security identifier can be time consuming. The
++NetLabel label mapping cache is a caching mechanism which can be used to
++sidestep much of this overhead once a mapping has been established. Once the
++LSM has received a packet, used NetLabel to decode it's security attributes,
++and translated the security attributes into a LSM internal identifier the LSM
++can use the NetLabel caching functions to associate the LSM internal
++identifier with the network packet's label. This means that in the future
++when a incoming packet matches a cached value not only are the internal
++NetLabel translation mechanisms bypassed but the LSM translation mechanisms are
++bypassed as well which should result in a significant reduction in overhead.
+diff --git a/Documentation/networking/3c509.txt b/Documentation/networking/3c509.txt
+index 867a99f..0643e3b 100644
+--- a/Documentation/networking/3c509.txt
++++ b/Documentation/networking/3c509.txt
+@@ -126,7 +126,7 @@ packets faster than they can be removed
+ or impossible in normal operation. Possible causes of this error report are:
+
+ - a "green" mode enabled that slows the processor down when there is no
+- keyboard activitiy.
++ keyboard activity.
+
+ - some other device or device driver hogging the bus or disabling interrupts.
+ Check /proc/interrupts for excessive interrupt counts. The timer tick
+diff --git a/Documentation/networking/LICENSE.qla3xxx b/Documentation/networking/LICENSE.qla3xxx
+new file mode 100644
+index 0000000..2f2077e
+--- /dev/null
++++ b/Documentation/networking/LICENSE.qla3xxx
+@@ -0,0 +1,46 @@
++Copyright (c) 2003-2006 QLogic Corporation
++QLogic Linux Networking HBA Driver
++
++This program includes a device driver for Linux 2.6 that may be
++distributed with QLogic hardware specific firmware binary file.
++You may modify and redistribute the device driver code under the
++GNU General Public License as published by the Free Software
++Foundation (version 2 or a later version).
++
++You may redistribute the hardware specific firmware binary file
++under the following terms:
++
++ 1. Redistribution of source code (only if applicable),
++ must retain the above copyright notice, this list of
++ conditions and the following disclaimer.
++
++ 2. Redistribution 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. The name of QLogic Corporation may not be used to
++ endorse or promote products derived from this software
++ without specific prior written permission
++
++REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
++THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "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.
++
++USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
++CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
++OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
++TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
++ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
++COMBINATION WITH THIS PROGRAM.
++
+diff --git a/Documentation/networking/NAPI_HOWTO.txt b/Documentation/networking/NAPI_HOWTO.txt
+index 54376e8..93af3e8 100644
+--- a/Documentation/networking/NAPI_HOWTO.txt
++++ b/Documentation/networking/NAPI_HOWTO.txt
+@@ -35,7 +35,7 @@ Legend:
+ packets out of the rx ring. Note from this that the lower the
+ load the more we could clean up the rxring
+ "Ndone" == is the converse of "Done". Note again, that the higher
+-the load the more times we couldnt clean up the rxring.
++the load the more times we couldn't clean up the rxring.
+
+ Observe that:
+ when the NIC receives 890Kpackets/sec only 17 rx interrupts are generated.
+diff --git a/Documentation/networking/arcnet-hardware.txt b/Documentation/networking/arcnet-hardware.txt
+index 30a5f01..731de41 100644
+--- a/Documentation/networking/arcnet-hardware.txt
++++ b/Documentation/networking/arcnet-hardware.txt
+@@ -139,7 +139,7 @@ And now to the cabling. What you can co
+
+ 5. An active hub to passive hub.
+
+-Remember, that you can not connect two passive hubs together. The power loss
++Remember that you cannot connect two passive hubs together. The power loss
+ implied by such a connection is too high for the net to operate reliably.
+
+ An example of a typical ARCnet network:
+diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
+index afac780..de809e5 100644
+--- a/Documentation/networking/bonding.txt
++++ b/Documentation/networking/bonding.txt
+@@ -192,6 +192,17 @@ or, for backwards compatibility, the opt
+ arp_interval
+
+ Specifies the ARP link monitoring frequency in milliseconds.
++
++ The ARP monitor works by periodically checking the slave
++ devices to determine whether they have sent or received
++ traffic recently (the precise criteria depends upon the
++ bonding mode, and the state of the slave). Regular traffic is
++ generated via ARP probes issued for the addresses specified by
++ the arp_ip_target option.
++
++ This behavior can be modified by the arp_validate option,
++ below.
++
+ If ARP monitoring is used in an etherchannel compatible mode
+ (modes 0 and 2), the switch should be configured in a mode
+ that evenly distributes packets across all links. If the
+@@ -213,6 +224,54 @@ arp_ip_target
+ maximum number of targets that can be specified is 16. The
+ default value is no IP addresses.
+
++arp_validate
++
++ Specifies whether or not ARP probes and replies should be
++ validated in the active-backup mode. This causes the ARP
++ monitor to examine the incoming ARP requests and replies, and
++ only consider a slave to be up if it is receiving the
++ appropriate ARP traffic.
++
++ Possible values are:
++
++ none or 0
++
++ No validation is performed. This is the default.
++
++ active or 1
++
++ Validation is performed only for the active slave.
++
++ backup or 2
++
++ Validation is performed only for backup slaves.
++
++ all or 3
++
++ Validation is performed for all slaves.
++
++ For the active slave, the validation checks ARP replies to
++ confirm that they were generated by an arp_ip_target. Since
++ backup slaves do not typically receive these replies, the
++ validation performed for backup slaves is on the ARP request
++ sent out via the active slave. It is possible that some
++ switch or network configurations may result in situations
++ wherein the backup slaves do not receive the ARP requests; in
++ such a situation, validation of backup slaves must be
++ disabled.
++
++ This option is useful in network configurations in which
++ multiple bonding hosts are concurrently issuing ARPs to one or
++ more targets beyond a common switch. Should the link between
++ the switch and target fail (but not the switch itself), the
++ probe traffic generated by the multiple bonding instances will
++ fool the standard ARP monitor into considering the links as
++ still up. Use of the arp_validate option can resolve this, as
++ the ARP monitor will only consider ARP requests and replies
++ associated with its own instance of bonding.
++
++ This option was added in bonding version 3.1.0.
++
+ downdelay
+
+ Specifies the time, in milliseconds, to wait before disabling
+@@ -964,7 +1023,7 @@ Changing a Bond's Configuration
+ files located in /sys/class/net/<bond name>/bonding
+
+ The names of these files correspond directly with the command-
+-line parameters described elsewhere in in this file, and, with the
++line parameters described elsewhere in this file, and, with the
+ exception of arp_ip_target, they accept the same values. To see the
+ current setting, simply cat the appropriate file.
+
+diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt
+index 188beb7..6489647 100644
+--- a/Documentation/networking/cs89x0.txt
++++ b/Documentation/networking/cs89x0.txt
+@@ -227,7 +227,7 @@ configuration options are available on t
+ * media=rj45 - specify media type
+ or media=bnc
+ or media=aui
+- or medai=auto
++ or media=auto
+ * duplex=full - specify forced half/full/autonegotiate duplex
+ or duplex=half
+ or duplex=auto
+@@ -584,7 +584,7 @@ of four ways after installing and or con
+
+ 1.) The system does not boot properly (or at all).
+
+- 2.) The driver can not communicate with the adapter, reporting an "Adapter
++ 2.) The driver cannot communicate with the adapter, reporting an "Adapter
+ not found" error message.
+
+ 3.) You cannot connect to the network or the driver will not load.
+@@ -684,7 +684,7 @@ ethernet at crystal.cirrus.com) and request
+ software-update notification.
+
+ Cirrus Logic maintains a web page at http://www.cirrus.com with the
+-the latest drivers and technical publications.
++latest drivers and technical publications.
+
+
+ 6.4 Current maintainer
+diff --git a/Documentation/networking/cxgb.txt b/Documentation/networking/cxgb.txt
+index 7632463..20a8876 100644
+--- a/Documentation/networking/cxgb.txt
++++ b/Documentation/networking/cxgb.txt
+@@ -56,7 +56,7 @@ FEATURES
+
+ ethtool -C eth0 rx-usecs 100
+
+- You may also provide a timer latency value while disabling adpative-rx:
++ You may also provide a timer latency value while disabling adaptive-rx:
+
+ ethtool -C <interface> adaptive-rx off rx-usecs <microseconds>
+
+@@ -172,7 +172,7 @@ PERFORMANCE
+ smaller window prevents congestion and facilitates better pacing,
+ especially if/when MAC level flow control does not work well or when it is
+ not supported on the machine. Experimentation may be necessary to attain
+- the correct value. This method is provided as a starting point fot the
++ the correct value. This method is provided as a starting point for the
+ correct receive buffer size.
+ Setting the min, max, and default receive buffer (RX_WINDOW) size is
+ performed in the same manner as single connection.
+diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
+index c45daab..74563b3 100644
+--- a/Documentation/networking/dccp.txt
++++ b/Documentation/networking/dccp.txt
+@@ -1,7 +1,6 @@
+ DCCP protocol
+ ============
+
+-Last updated: 10 November 2005
+
+ Contents
+ ========
+@@ -42,8 +41,11 @@ Socket options
+ DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
+ calculations.
+
+-DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the
+-specification. If you don't set it you will get EPROTO.
++DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
++service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
++the socket will fall back to 0 (which means that no meaningful service code
++is present). Connecting sockets set at most one service option; for
++listening sockets, multiple service codes can be specified.
+
+ Notes
+ =====
+diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
+index e6c39c5..badb748 100644
+--- a/Documentation/networking/decnet.txt
++++ b/Documentation/networking/decnet.txt
+@@ -82,7 +82,7 @@ ethernet address of your ethernet card h
+ address of the node in order for it to be autoconfigured (and then appear in
+ /proc/net/decnet_dev). There is a utility available at the above
+ FTP sites called dn2ethaddr which can compute the correct ethernet
+-address to use. The address can be set by ifconfig either before at
++address to use. The address can be set by ifconfig either before or
+ at the time the device is brought up. If you are using RedHat you can
+ add the line:
+
+diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
+index d460492..10e8490 100644
+--- a/Documentation/networking/dl2k.txt
++++ b/Documentation/networking/dl2k.txt
+@@ -173,7 +173,7 @@ Installing the Driver
+
+ Parameter Description
+ =====================
+-You can install this driver without any addtional parameter. However, if you
++You can install this driver without any additional parameter. However, if you
+ are going to have extensive functions then it is necessary to set extra
+ parameter. Below is a list of the command line parameters supported by the
+ Linux device
+@@ -222,7 +222,7 @@ rx_timeout=n - Rx DMA wait time for an
+ reach timeout of n * 640 nano seconds.
+ Set proper rx_coalesce and rx_timeout can
+ reduce congestion collapse and overload which
+- has been a bottlenect for high speed network.
++ has been a bottleneck for high speed network.
+
+ For example, rx_coalesce=10 rx_timeout=800.
+ that is, hardware assert only 1 interrupt
+diff --git a/Documentation/networking/dmfe.txt b/Documentation/networking/dmfe.txt
+index 0463635..b1b7499 100644
+--- a/Documentation/networking/dmfe.txt
++++ b/Documentation/networking/dmfe.txt
+@@ -34,7 +34,7 @@ Next you should configure your network i
+
+ ifconfig eth0 172.22.3.18
+ ^^^^^^^^^^^
+- Your IP Adress
++ Your IP Address
+
+ Then you may have to modify the default routing table with command :
+
+diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt
+index a9ad58b..4f7da5a 100644
+--- a/Documentation/networking/driver.txt
++++ b/Documentation/networking/driver.txt
+@@ -37,7 +37,7 @@ Transmit path guidelines:
+ ...
+ }
+
+- And then at the end of your TX reclaimation event handling:
++ And then at the end of your TX reclamation event handling:
+
+ if (netif_queue_stopped(dp->dev) &&
+ TX_BUFFS_AVAIL(dp) > (MAX_SKB_FRAGS + 1))
+diff --git a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt
+index 71fe15a..5c0a5cc 100644
+--- a/Documentation/networking/e1000.txt
++++ b/Documentation/networking/e1000.txt
+@@ -350,7 +350,7 @@ Additional Configurations
+
+ As an example, if you install the e1000 driver for two PRO/1000 adapters
+ (eth0 and eth1) and set the speed and duplex to 10full and 100half, add
+- the following to modules.conf or or modprobe.conf:
++ the following to modules.conf or modprobe.conf:
+
+ alias eth0 e1000
+ alias eth1 e1000
+diff --git a/Documentation/networking/fib_trie.txt b/Documentation/networking/fib_trie.txt
+index f50d0c6..0723db7 100644
+--- a/Documentation/networking/fib_trie.txt
++++ b/Documentation/networking/fib_trie.txt
+@@ -79,7 +79,7 @@ trie_rebalance()
+
+ resize()
+ Analyzes a tnode and optimizes the child array size by either inflating
+- or shrinking it repeatedly until it fullfills the criteria for optimal
++ or shrinking it repeatedly until it fulfills the criteria for optimal
+ level compression. This part follows the original paper pretty closely
+ and there may be some room for experimentation here.
+
+diff --git a/Documentation/networking/gen_stats.txt b/Documentation/networking/gen_stats.txt
+index c3297f7..70e6275 100644
+--- a/Documentation/networking/gen_stats.txt
++++ b/Documentation/networking/gen_stats.txt
+@@ -79,8 +79,8 @@ Rate Estimator:
+
+ 0) Prepare an estimator attribute. Most likely this would be in user
+ space. The value of this TLV should contain a tc_estimator structure.
+- As usual, such a TLV nees to be 32 bit aligned and therefore the
+- length needs to be appropriately set etc. The estimator interval
++ As usual, such a TLV needs to be 32 bit aligned and therefore the
++ length needs to be appropriately set, etc. The estimator interval
+ and ewma log need to be converted to the appropriate values.
+ tc_estimator.c::tc_setup_estimator() is advisable to be used as the
+ conversion routine. It does a few clever things. It takes a time
+@@ -103,8 +103,8 @@ In the kernel when setting up:
+ else
+ failed
+
+-From now on, everytime you dump my_rate_est_stats it will contain
+-uptodate info.
++From now on, every time you dump my_rate_est_stats it will contain
++up-to-date info.
+
+ Once you are done, call gen_kill_estimator(my_basicstats,
+ my_rate_est_stats) Make sure that my_basicstats and my_rate_est_stats
+diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
+index 90ed781..fd3c0c0 100644
+--- a/Documentation/networking/ip-sysctl.txt
++++ b/Documentation/networking/ip-sysctl.txt
+@@ -375,6 +375,41 @@ tcp_slow_start_after_idle - BOOLEAN
+ be timed out after an idle period.
+ Default: 1
+
++CIPSOv4 Variables:
++
++cipso_cache_enable - BOOLEAN
++ If set, enable additions to and lookups from the CIPSO label mapping
++ cache. If unset, additions are ignored and lookups always result in a
++ miss. However, regardless of the setting the cache is still
++ invalidated when required when means you can safely toggle this on and
++ off and the cache will always be "safe".
++ Default: 1
++
++cipso_cache_bucket_size - INTEGER
++ The CIPSO label cache consists of a fixed size hash table with each
++ hash bucket containing a number of cache entries. This variable limits
++ the number of entries in each hash bucket; the larger the value the
++ more CIPSO label mappings that can be cached. When the number of
++ entries in a given hash bucket reaches this limit adding new entries
++ causes the oldest entry in the bucket to be removed to make room.
++ Default: 10
++
++cipso_rbm_optfmt - BOOLEAN
++ Enable the "Optimized Tag 1 Format" as defined in section 3.4.2.6 of
++ the CIPSO draft specification (see Documentation/netlabel for details).
++ This means that when set the CIPSO tag will be padded with empty
++ categories in order to make the packet data 32-bit aligned.
++ Default: 0
++
++cipso_rbm_structvalid - BOOLEAN
++ If set, do a very strict check of the CIPSO option when
++ ip_options_compile() is called. If unset, relax the checks done during
++ ip_options_compile(). Either way is "safe" as errors are caught else
++ where in the CIPSO processing code but setting this to 0 (False) should
++ result in less work (i.e. it should be faster) but could cause problems
++ with other implementations that require strict checking.
++ Default: 0
++
+ IP Variables:
+
+ ip_local_port_range - 2 INTEGERS
+@@ -460,7 +495,7 @@ icmp_errors_use_inbound_ifaddr - BOOLEAN
+
+ Note that if no primary address exists for the interface selected,
+ then the primary address of the first non-loopback interface that
+- has one will be used regarldess of this setting.
++ has one will be used regardless of this setting.
+
+ Default: 0
+
+@@ -730,6 +765,9 @@ conf/all/forwarding - BOOLEAN
+
+ This referred to as global forwarding.
+
++proxy_ndp - BOOLEAN
++ Do proxy ndp.
++
+ conf/interface/*:
+ Change special settings per interface.
+
+@@ -749,7 +787,7 @@ accept_ra_defrtr - BOOLEAN
+ disabled if accept_ra is disabled.
+
+ accept_ra_pinfo - BOOLEAN
+- Learn Prefix Inforamtion in Router Advertisement.
++ Learn Prefix Information in Router Advertisement.
+
+ Functional default: enabled if accept_ra is enabled.
+ disabled if accept_ra is disabled.
+diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
+index 53618fb..1caa6c7 100644
+--- a/Documentation/networking/netconsole.txt
++++ b/Documentation/networking/netconsole.txt
+@@ -52,6 +52,6 @@ messages is high, but should have no oth
+ Netconsole was designed to be as instantaneous as possible, to
+ enable the logging of even the most critical kernel bugs. It works
+ from IRQ contexts as well, and does not enable interrupts while
+-sending packets. Due to these unique needs, configuration can not
++sending packets. Due to these unique needs, configuration cannot
+ be more automatic, and some fundamental limitations will remain:
+ only IP networks, UDP packets and ethernet devices are supported.
+diff --git a/Documentation/networking/netif-msg.txt b/Documentation/networking/netif-msg.txt
+index 18ad4ce..c967ddb 100644
+--- a/Documentation/networking/netif-msg.txt
++++ b/Documentation/networking/netif-msg.txt
+@@ -40,7 +40,7 @@ History
+ Per-interface rather than per-driver message level setting.
+ More selective control over the type of messages emitted.
+
+- The netif_msg recommandation adds these features with only a minor
++ The netif_msg recommendation adds these features with only a minor
+ complexity and code size increase.
+
+ The recommendation is the following points
+diff --git a/Documentation/networking/operstates.txt b/Documentation/networking/operstates.txt
+index 4a21d9b..c9074f9 100644
+--- a/Documentation/networking/operstates.txt
++++ b/Documentation/networking/operstates.txt
+@@ -2,7 +2,7 @@
+ 1. Introduction
+
+ Linux distinguishes between administrative and operational state of an
+-interface. Admininstrative state is the result of "ip link set dev
++interface. Administrative state is the result of "ip link set dev
+ <dev> up or down" and reflects whether the administrator wants to use
+ the device for traffic.
+
+diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
+index aaf99d5..12a008a 100644
+--- a/Documentation/networking/packet_mmap.txt
++++ b/Documentation/networking/packet_mmap.txt
+@@ -66,7 +66,7 @@ the following process:
+
+ [setup] socket() -------> creation of the capture socket
+ setsockopt() ---> allocation of the circular buffer (ring)
+- mmap() ---------> maping of the allocated buffer to the
++ mmap() ---------> mapping of the allocated buffer to the
+ user process
+
+ [capture] poll() ---------> to wait for incoming packets
+@@ -93,7 +93,7 @@ The destruction of the socket and all as
+ is done by a simple call to close(fd).
+
+ Next I will describe PACKET_MMAP settings and it's constraints,
+-also the maping of the circular buffer in the user process and
++also the mapping of the circular buffer in the user process and
+ the use of this buffer.
+
+ --------------------------------------------------------------------------------
+@@ -153,8 +153,8 @@ we will get the following buffer structu
+
+ A frame can be of any size with the only condition it can fit in a block. A block
+ can only hold an integer number of frames, or in other words, a frame cannot
+-be spawn accross two blocks so there are some datails you have to take into
+-account when choosing the frame_size. See "Maping and use of the circular
++be spawned accross two blocks, so there are some details you have to take into
++account when choosing the frame_size. See "Mapping and use of the circular
+ buffer (ring)".
+
+
+@@ -215,8 +215,8 @@ called pg_vec, its size limits the numbe
+ block #1
+
+
+-kmalloc allocates any number of bytes of phisically contiguous memory from
+-a pool of pre-determined sizes. This pool of memory is mantained by the slab
++kmalloc allocates any number of bytes of physically contiguous memory from
++a pool of pre-determined sizes. This pool of memory is maintained by the slab
+ allocator which is at the end the responsible for doing the allocation and
+ hence which imposes the maximum memory that kmalloc can allocate.
+
+@@ -262,7 +262,7 @@ i386 architecture:
+ <pagesize> = 4096 bytes
+ <max-order> = 11
+
+-and a value for <frame size> of 2048 byteas. These parameters will yield
++and a value for <frame size> of 2048 bytes. These parameters will yield
+
+ <block number> = 131072/4 = 32768 blocks
+ <block size> = 4096 << 11 = 8 MiB.
+@@ -278,7 +278,7 @@ an i386 kernel's memory size is limited
+ All memory allocations are not freed until the socket is closed. The memory
+ allocations are done with GFP_KERNEL priority, this basically means that
+ the allocation can wait and swap other process' memory in order to allocate
+-the nececessary memory, so normally limits can be reached.
++the necessary memory, so normally limits can be reached.
+
+ Other constraints
+ -------------------
+@@ -296,7 +296,7 @@ the following (from include/linux/if_pac
+ - struct tpacket_hdr
+ - pad to TPACKET_ALIGNMENT=16
+ - struct sockaddr_ll
+- - Gap, chosen so that packet data (Start+tp_net) alignes to
++ - Gap, chosen so that packet data (Start+tp_net) aligns to
+ TPACKET_ALIGNMENT=16
+ - Start+tp_mac: [ Optional MAC header ]
+ - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
+@@ -311,14 +311,14 @@ the following (from include/linux/if_pac
+ tp_frame_size must be a multiple of TPACKET_ALIGNMENT
+ tp_frame_nr must be exactly frames_per_block*tp_block_nr
+
+-Note that tp_block_size should be choosed to be a power of two or there will
++Note that tp_block_size should be chosen to be a power of two or there will
+ be a waste of memory.
+
+ --------------------------------------------------------------------------------
+-+ Maping and use of the circular buffer (ring)
+++ Mapping and use of the circular buffer (ring)
+ --------------------------------------------------------------------------------
+
+-The maping of the buffer in the user process is done with the conventional
++The mapping of the buffer in the user process is done with the conventional
+ mmap function. Even the circular buffer is compound of several physically
+ discontiguous blocks of memory, they are contiguous to the user space, hence
+ just one call to mmap is needed:
+diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
+index 44f2f76..c8eee23 100644
+--- a/Documentation/networking/pktgen.txt
++++ b/Documentation/networking/pktgen.txt
+@@ -7,7 +7,7 @@ Date: 041221
+
+ Enable CONFIG_NET_PKTGEN to compile and build pktgen.o either in kernel
+ or as module. Module is preferred. insmod pktgen if needed. Once running
+-pktgen creates a thread on each CPU where each thread has affinty it's CPU.
++pktgen creates a thread on each CPU where each thread has affinity to its CPU.
+ Monitoring and controlling is done via /proc. Easiest to select a suitable
+ a sample script and configure.
+
+@@ -18,7 +18,7 @@ root 129 0.3 0.0 0 0 ?
+ root 130 0.3 0.0 0 0 ? SW 2003 509:50 [pktgen/1]
+
+
+-For montoring and control pktgen creates:
++For monitoring and control pktgen creates:
+ /proc/net/pktgen/pgctrl
+ /proc/net/pktgen/kpktgend_X
+ /proc/net/pktgen/ethX
+@@ -32,7 +32,7 @@ Running:
+ Stopped: eth1
+ Result: OK: max_before_softirq=10000
+
+-Most important the devices assigend to thread. Note! A device can only belong
++Most important the devices assigned to thread. Note! A device can only belong
+ to one thread.
+
+
+@@ -100,6 +100,7 @@ Examples:
+ are: IPSRC_RND #IP Source is random (between min/max),
+ IPDST_RND, UDPSRC_RND,
+ UDPDST_RND, MACSRC_RND, MACDST_RND
++ MPLS_RND, VID_RND, SVID_RND
+
+ pgset "udp_src_min 9" set UDP source port min, If < udp_src_max, then
+ cycle through the port range.
+@@ -125,13 +126,28 @@ Examples:
+
+ pgset "mpls 0" turn off mpls (or any invalid argument works too!)
+
++ pgset "vlan_id 77" set VLAN ID 0-4095
++ pgset "vlan_p 3" set priority bit 0-7 (default 0)
++ pgset "vlan_cfi 0" set canonical format identifier 0-1 (default 0)
++
++ pgset "svlan_id 22" set SVLAN ID 0-4095
++ pgset "svlan_p 3" set priority bit 0-7 (default 0)
++ pgset "svlan_cfi 0" set canonical format identifier 0-1 (default 0)
++
++ pgset "vlan_id 9999" > 4095 remove vlan and svlan tags
++ pgset "svlan 9999" > 4095 remove svlan tag
++
++
++ pgset "tos XX" set former IPv4 TOS field (e.g. "tos 28" for AF11 no ECN, default 00)
++ pgset "traffic_class XX" set former IPv6 TRAFFIC CLASS (e.g. "traffic_class B8" for EF no ECN, default 00)
++
+ pgset stop aborts injection. Also, ^C aborts generator.
+
+
+ Example scripts
+ ===============
+
+-A collection of small tutorial scripts for pktgen is in expamples dir.
++A collection of small tutorial scripts for pktgen is in examples dir.
+
+ pktgen.conf-1-1 # 1 CPU 1 dev
+ pktgen.conf-1-2 # 1 CPU 2 dev
+diff --git a/Documentation/networking/s2io.txt b/Documentation/networking/s2io.txt
+index bd528ff..4bde53e 100644
+--- a/Documentation/networking/s2io.txt
++++ b/Documentation/networking/s2io.txt
+@@ -126,7 +126,7 @@ However, you may want to set PCI latency
+ #setpci -d 17d5:* LATENCY_TIMER=f8
+ For detailed description of the PCI registers, please see Xframe User Guide.
+ b. Use 2-buffer mode. This results in large performance boost on
+-on certain platforms(eg. SGI Altix, IBM xSeries).
++certain platforms(eg. SGI Altix, IBM xSeries).
+ c. Ensure Receive Checksum offload is enabled. Use "ethtool -K ethX" command to
+ set/verify this option.
+ d. Enable NAPI feature(in kernel configuration Device Drivers ---> Network
+diff --git a/Documentation/networking/secid.txt b/Documentation/networking/secid.txt
+new file mode 100644
+index 0000000..95ea067
+--- /dev/null
++++ b/Documentation/networking/secid.txt
+@@ -0,0 +1,14 @@
++flowi structure:
++
++The secid member in the flow structure is used in LSMs (e.g. SELinux) to indicate
++the label of the flow. This label of the flow is currently used in selecting
++matching labeled xfrm(s).
++
++If this is an outbound flow, the label is derived from the socket, if any, or
++the incoming packet this flow is being generated as a response to (e.g. tcp
++resets, timewait ack, etc.). It is also conceivable that the label could be
++derived from other sources such as process context, device, etc., in special
++cases, as may be appropriate.
++
++If this is an inbound flow, the label is derived from the IPSec security
++associations, if any, used by the packet.
+diff --git a/Documentation/networking/sk98lin.txt b/Documentation/networking/sk98lin.txt
+index 7837c53..4e1cc74 100644
+--- a/Documentation/networking/sk98lin.txt
++++ b/Documentation/networking/sk98lin.txt
+@@ -180,7 +180,7 @@ To set the driver parameters in this fil
+ 1. Insert a line of the form :
+ options sk98lin ...
+ For "...", the same syntax is required as described for the command
+- line paramaters of modprobe below.
++ line parameters of modprobe below.
+ 2. To activate the new parameters, either reboot your computer
+ or
+ unload and reload the driver.
+@@ -320,7 +320,7 @@ Parameter: Moderation
+ Values: None, Static, Dynamic
+ Default: None
+
+-Interrupt moderation is employed to limit the maxmimum number of interrupts
++Interrupt moderation is employed to limit the maximum number of interrupts
+ the driver has to serve. That is, one or more interrupts (which indicate any
+ transmit or receive packet to be processed) are queued until the driver
+ processes them. When queued interrupts are to be served, is determined by the
+@@ -364,9 +364,9 @@ Parameter: IntsPerSec
+ Values: 30...40000 (interrupts per second)
+ Default: 2000
+
+-This parameter is only used, if either static or dynamic interrupt moderation
+-is used on a network adapter card. Using this paramter if no moderation is
+-applied, will lead to no action performed.
++This parameter is only used if either static or dynamic interrupt moderation
++is used on a network adapter card. Using this parameter if no moderation is
++applied will lead to no action performed.
+
+ This parameter determines the length of any interrupt moderation interval.
+ Assuming that static interrupt moderation is to be used, an 'IntsPerSec'
+@@ -484,7 +484,7 @@ If any problems occur during the install
+ following list:
+
+
+-Problem: The SK-98xx adapter can not be found by the driver.
++Problem: The SK-98xx adapter cannot be found by the driver.
+ Solution: In /proc/pci search for the following entry:
+ 'Ethernet controller: SysKonnect SK-98xx ...'
+ If this entry exists, the SK-98xx or SK-98xx V2.0 adapter has
+@@ -497,12 +497,12 @@ Solution: In /proc/pci search for the fo
+ www.syskonnect.com
+
+ Some COMPAQ machines have problems dealing with PCI under Linux.
+- Linux. This problem is described in the 'PCI howto' document
++ This problem is described in the 'PCI howto' document
+ (included in some distributions or available from the
+ web, e.g. at 'www.linux.org').
+
+
+-Problem: Programs such as 'ifconfig' or 'route' can not be found or the
++Problem: Programs such as 'ifconfig' or 'route' cannot be found or the
+ error message 'Operation not permitted' is displayed.
+ Reason: You are not logged in as user 'root'.
+ Solution: Logout and login as 'root' or change to 'root' via 'su'.
+diff --git a/Documentation/networking/skfp.txt b/Documentation/networking/skfp.txt
+index 3a419ed..abfddf8 100644
+--- a/Documentation/networking/skfp.txt
++++ b/Documentation/networking/skfp.txt
+@@ -81,7 +81,7 @@ Makes my life much easier :-)
+
+ If you run into problems during installation, check those items:
+
+-Problem: The FDDI adapter can not be found by the driver.
++Problem: The FDDI adapter cannot be found by the driver.
+ Reason: Look in /proc/pci for the following entry:
+ 'FDDI network controller: SysKonnect SK-FDDI-PCI ...'
+ If this entry exists, then the FDDI adapter has been
+@@ -99,7 +99,7 @@ Reason: Look in /proc/pci for the foll
+
+ Problem: You want to use your computer as a router between
+ multiple IP subnetworks (using multiple adapters), but
+- you can not reach computers in other subnetworks.
++ you cannot reach computers in other subnetworks.
+ Reason: Either the router's kernel is not configured for IP
+ forwarding or there is a problem with the routing table
+ and gateway configuration in at least one of the
+diff --git a/Documentation/networking/slicecom.txt b/Documentation/networking/slicecom.txt
+index 59cfd95..2f04c92 100644
+--- a/Documentation/networking/slicecom.txt
++++ b/Documentation/networking/slicecom.txt
+@@ -89,7 +89,7 @@ red: green: meaning:
+
+ - - no frame-sync, no signal received, or signal SNAFU.
+ - on "Everything is OK"
+-on on Recepion is ok, but the remote end sends Remote Alarm
++on on Reception is ok, but the remote end sends Remote Alarm
+ on - The interface is unconfigured
+
+ -----------------------------------------------------------------
+@@ -257,12 +257,12 @@ which begin with '//' are the comments.
+ // No alarms - Everything OK
+ //
+ // LOS - Loss Of Signal - No signal sensed on the input
+-// AIS - Alarm Indication Signal - The remot side sends '11111111'-s,
++// AIS - Alarm Indication Signal - The remote side sends '11111111'-s,
+ // it tells, that there's an error condition, or it's not
+ // initialised.
+ // AUXP - Auxiliary Pattern Indication - 01010101.. received.
+ // LFA - Loss of Frame Alignment - no frame sync received.
+-// RRA - Receive Remote Alarm - the remote end's OK, but singnals error cond.
++// RRA - Receive Remote Alarm - the remote end's OK, but signals error cond.
+ // LMFA - Loss of CRC4 Multiframe Alignment - no CRC4 multiframe sync.
+ // NMF - No Multiframe alignment Found after 400 msec - no such alarm using
+ // no-crc4 or crc4 framing, see below.
+@@ -364,6 +364,6 @@ Treat them very carefully, these can cau
+
+ # echo >lbireg 0x1d 0x21
+
+- - Swithing the loop off:
++ - Switching the loop off:
+
+ # echo >lbireg 0x1d 0x00
+diff --git a/Documentation/networking/smctr.txt b/Documentation/networking/smctr.txt
+index 4c866f5..9af25b8 100644
+--- a/Documentation/networking/smctr.txt
++++ b/Documentation/networking/smctr.txt
+@@ -11,7 +11,7 @@ This driver is rather simple to use. Sel
+ in the kernel configuration. A choice for SMC Token Ring adapters will
+ appear. This drives supports all SMC ISA/MCA adapters. Choose this
+ option. I personally recommend compiling the driver as a module (M), but if you
+-you would like to compile it staticly answer Y instead.
++you would like to compile it statically answer Y instead.
+
+ This driver supports multiple adapters without the need to load multiple copies
+ of the driver. You should be able to load up to 7 adapters without any kernel
+diff --git a/Documentation/networking/tcp.txt b/Documentation/networking/tcp.txt
+index 0fa3004..0121edc 100644
+--- a/Documentation/networking/tcp.txt
++++ b/Documentation/networking/tcp.txt
+@@ -62,7 +62,7 @@ if needed and you will get the expected
+ 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
++available one. Since reno cannot be built as a module, and cannot be
+ deleted, it will always be available.
+
+ How the new TCP output machine [nyi] works.
+diff --git a/Documentation/networking/tms380tr.txt b/Documentation/networking/tms380tr.txt
+index 179e527..c169a57 100644
+--- a/Documentation/networking/tms380tr.txt
++++ b/Documentation/networking/tms380tr.txt
+@@ -24,7 +24,7 @@ This driver is rather simple to use. Sel
+ in the kernel configuration. A choice for SysKonnect Token Ring adapters will
+ appear. This drives supports all SysKonnect ISA and PCI adapters. Choose this
+ option. I personally recommend compiling the driver as a module (M), but if you
+-you would like to compile it staticly answer Y instead.
++you would like to compile it statically answer Y instead.
+
+ This driver supports multiple adapters without the need to load multiple copies
+ of the driver. You should be able to load up to 7 adapters without any kernel
+diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
+index 6091e5f..6356d3f 100644
+--- a/Documentation/networking/vortex.txt
++++ b/Documentation/networking/vortex.txt
+@@ -359,13 +359,13 @@ steps you should take:
+
+ Eliminate some variables: try different cards, different
+ computers, different cables, different ports on the switch/hub,
+- different versions of the kernel or ofthe driver, etc.
++ different versions of the kernel or of the driver, etc.
+
+ - OK, it's a driver problem.
+
+ You need to generate a report. Typically this is an email to the
+ maintainer and/or linux-net at vger.kernel.org. The maintainer's
+- email address will be inthe driver source or in the MAINTAINERS file.
++ email address will be in the driver source or in the MAINTAINERS file.
+
+ - The contents of your report will vary a lot depending upon the
+ problem. If it's a kernel crash then you should refer to the
+diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt
+index c96897a..0cf6541 100644
+--- a/Documentation/networking/wan-router.txt
++++ b/Documentation/networking/wan-router.txt
+@@ -148,7 +148,7 @@ NEW IN THIS RELEASE
+ for async connections.
+
+ o Added the PPPCONFIG utility
+- Used to configure the PPPD dameon for the
++ Used to configure the PPPD daemon for the
+ WANPIPE Async PPP and standard serial port.
+ The wancfg calls the pppconfig to configure
+ the pppd.
+@@ -214,7 +214,7 @@ PRODUCT COMPONENTS AND RELATED FILES
+ /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
++ version if the kernel source has already been patched with
+ WANPIPE drivers.
+
+ /usr/local/wanrouter/samples:
+@@ -350,7 +350,7 @@ REVISION HISTORY
+ Available as a patch.
+
+ 2.0.6 Aug 17, 1999 Increased debugging in statup scripts
+- Fixed insallation bugs from 2.0.5
++ Fixed installation 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
+
+@@ -434,11 +434,11 @@ beta3-2.1.4 Jul 2000 o X25 M_BIT Proble
+ change.
+
+ beta1-2.1.5 Nov 15 2000
+- o Fixed the MulitPort PPP Support for kernels 2.2.16 and above.
++ o Fixed the MultiPort 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
++ - All illegal network debugging calls are reported to
+ the log.
+ - Defined a set of allowed commands, all other denied.
+
+@@ -451,7 +451,7 @@ beta1-2.1.5 Nov 15 2000
+
+ o Keyboard Led Monitor/Debugger
+ - A new utilty /usr/sbin/wpkbdmon uses keyboard leds
+- to convey operatinal statistic information of the
++ to convey operational 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)
+@@ -470,7 +470,7 @@ beta1-2.1.5 Nov 15 2000
+ 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.
++ all WANPIPE network 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.
+@@ -570,7 +570,7 @@ bata1-2.2.1 Feb 09 2001
+
+ Option to COMPILE WANPIPE modules against the currently
+ running kernel, thus no need for manual kernel and module
+- re-compilatin.
++ re-compilation.
+
+ o Updates and Bug Fixes to wancfg utility.
+
+diff --git a/Documentation/nfsroot.txt b/Documentation/nfsroot.txt
+index 3cc953c..719f9a9 100644
+--- a/Documentation/nfsroot.txt
++++ b/Documentation/nfsroot.txt
+@@ -11,7 +11,7 @@ Updated 2006 by Horms <horms at verge.net.a
+ In order to use a diskless system, such as an X-terminal or printer server
+ for example, it is necessary for the root filesystem to be present on a
+ non-disk device. This may be an initramfs (see Documentation/filesystems/
+-ramfs-rootfs-initramfs.txt), a ramdisk (see Documenation/initrd.txt) or a
++ramfs-rootfs-initramfs.txt), a ramdisk (see Documentation/initrd.txt) or a
+ filesystem mounted via NFS. The following text describes on how to use NFS
+ for the root filesystem. For the rest of this text 'client' means the
+ diskless system, and 'server' means the NFS server.
+diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt
+index b88ebe4..7714f57 100644
+--- a/Documentation/nommu-mmap.txt
++++ b/Documentation/nommu-mmap.txt
+@@ -116,6 +116,9 @@ FURTHER NOTES ON NO-MMU MMAP
+ (*) A list of all the mappings on the system is visible through /proc/maps in
+ no-MMU mode.
+
++ (*) A list of all the mappings in use by a process is visible through
++ /proc/<pid>/maps in no-MMU mode.
++
+ (*) Supplying MAP_FIXED or a requesting a particular mapping address will
+ result in an error.
+
+@@ -125,6 +128,49 @@ FURTHER NOTES ON NO-MMU MMAP
+ error will result if they don't. This is most likely to be encountered
+ with character device files, pipes, fifos and sockets.
+
++
++==========================
++INTERPROCESS SHARED MEMORY
++==========================
++
++Both SYSV IPC SHM shared memory and POSIX shared memory is supported in NOMMU
++mode. The former through the usual mechanism, the latter through files created
++on ramfs or tmpfs mounts.
++
++
++=======
++FUTEXES
++=======
++
++Futexes are supported in NOMMU mode if the arch supports them. An error will
++be given if an address passed to the futex system call lies outside the
++mappings made by a process or if the mapping in which the address lies does not
++support futexes (such as an I/O chardev mapping).
++
++
++=============
++NO-MMU MREMAP
++=============
++
++The mremap() function is partially supported. It may change the size of a
++mapping, and may move it[*] if MREMAP_MAYMOVE is specified and if the new size
++of the mapping exceeds the size of the slab object currently occupied by the
++memory to which the mapping refers, or if a smaller slab object could be used.
++
++MREMAP_FIXED is not supported, though it is ignored if there's no change of
++address and the object does not need to be moved.
++
++Shared mappings may not be moved. Shareable mappings may not be moved either,
++even if they are not currently shared.
++
++The mremap() function must be given an exact match for base address and size of
++a previously mapped object. It may not be used to create holes in existing
++mappings, move parts of existing mappings or resize parts of mappings. It must
++act on a complete mapping.
++
++[*] Not currently supported.
++
++
+ ============================================
+ PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT
+ ============================================
+diff --git a/Documentation/pci-error-recovery.txt b/Documentation/pci-error-recovery.txt
+index 634d3e5..6650af4 100644
+--- a/Documentation/pci-error-recovery.txt
++++ b/Documentation/pci-error-recovery.txt
+@@ -172,7 +172,7 @@ is STEP 6 (Permanent Failure).
+ >>> a value of 0xff on read, and writes will be dropped. If the device
+ >>> driver attempts more than 10K I/O's to a frozen adapter, it will
+ >>> assume that the device driver has gone into an infinite loop, and
+->>> it will panic the the kernel. There doesn't seem to be any other
++>>> it will panic the kernel. There doesn't seem to be any other
+ >>> way of stopping a device driver that insists on spinning on I/O.
+
+ STEP 2: MMIO Enabled
+diff --git a/Documentation/pcieaer-howto.txt b/Documentation/pcieaer-howto.txt
+new file mode 100644
+index 0000000..16c2512
+--- /dev/null
++++ b/Documentation/pcieaer-howto.txt
+@@ -0,0 +1,253 @@
++ The PCI Express Advanced Error Reporting Driver Guide HOWTO
++ T. Long Nguyen <tom.l.nguyen at intel.com>
++ Yanmin Zhang <yanmin.zhang at intel.com>
++ 07/29/2006
++
++
++1. Overview
++
++1.1 About this guide
++
++This guide describes the basics of the PCI Express Advanced Error
++Reporting (AER) driver and provides information on how to use it, as
++well as how to enable the drivers of endpoint devices to conform with
++PCI Express AER driver.
++
++1.2 Copyright © Intel Corporation 2006.
++
++1.3 What is the PCI Express AER Driver?
++
++PCI Express error signaling can occur on the PCI Express link itself
++or on behalf of transactions initiated on the link. PCI Express
++defines two error reporting paradigms: the baseline capability and
++the Advanced Error Reporting capability. The baseline capability is
++required of all PCI Express components providing a minimum defined
++set of error reporting requirements. Advanced Error Reporting
++capability is implemented with a PCI Express advanced error reporting
++extended capability structure providing more robust error reporting.
++
++The PCI Express AER driver provides the infrastructure to support PCI
++Express Advanced Error Reporting capability. The PCI Express AER
++driver provides three basic functions:
++
++- Gathers the comprehensive error information if errors occurred.
++- Reports error to the users.
++- Performs error recovery actions.
++
++AER driver only attaches root ports which support PCI-Express AER
++capability.
++
++
++2. User Guide
++
++2.1 Include the PCI Express AER Root Driver into the Linux Kernel
++
++The PCI Express AER Root driver is a Root Port service driver attached
++to the PCI Express Port Bus driver. If a user wants to use it, the driver
++has to be compiled. Option CONFIG_PCIEAER supports this capability. It
++depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and
++CONFIG_PCIEAER = y.
++
++2.2 Load PCI Express AER Root Driver
++There is a case where a system has AER support in BIOS. Enabling the AER
++Root driver and having AER support in BIOS may result unpredictable
++behavior. To avoid this conflict, a successful load of the AER Root driver
++requires ACPI _OSC support in the BIOS to allow the AER Root driver to
++request for native control of AER. See the PCI FW 3.0 Specification for
++details regarding OSC usage. Currently, lots of firmwares don't provide
++_OSC support while they use PCI Express. To support such firmwares,
++forceload, a parameter of type bool, could enable AER to continue to
++be initiated although firmwares have no _OSC support. To enable the
++walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line
++when booting kernel. Note that forceload=n by default.
++
++2.3 AER error output
++When a PCI-E AER error is captured, an error message will be outputed to
++console. If it's a correctable error, it is outputed as a warning.
++Otherwise, it is printed as an error. So users could choose different
++log level to filter out correctable error messages.
++
++Below shows an example.
+++------ PCI-Express Device Error -----+
++Error Severity : Uncorrected (Fatal)
++PCIE Bus Error type : Transaction Layer
++Unsupported Request : First
++Requester ID : 0500
++VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h
++TLB Header:
++04000001 00200a03 05010000 00050100
++
++In the example, 'Requester ID' means the ID of the device who sends
++the error message to root port. Pls. refer to pci express specs for
++other fields.
++
++
++3. Developer Guide
++
++To enable AER aware support requires a software driver to configure
++the AER capability structure within its device and to provide callbacks.
++
++To support AER better, developers need understand how AER does work
++firstly.
++
++PCI Express errors are classified into two types: correctable errors
++and uncorrectable errors. This classification is based on the impacts
++of those errors, which may result in degraded performance or function
++failure.
++
++Correctable errors pose no impacts on the functionality of the
++interface. The PCI Express protocol can recover without any software
++intervention or any loss of data. These errors are detected and
++corrected by hardware. Unlike correctable errors, uncorrectable
++errors impact functionality of the interface. Uncorrectable errors
++can cause a particular transaction or a particular PCI Express link
++to be unreliable. Depending on those error conditions, uncorrectable
++errors are further classified into non-fatal errors and fatal errors.
++Non-fatal errors cause the particular transaction to be unreliable,
++but the PCI Express link itself is fully functional. Fatal errors, on
++the other hand, cause the link to be unreliable.
++
++When AER is enabled, a PCI Express device will automatically send an
++error message to the PCIE root port above it when the device captures
++an error. The Root Port, upon receiving an error reporting message,
++internally processes and logs the error message in its PCI Express
++capability structure. Error information being logged includes storing
++the error reporting agent's requestor ID into the Error Source
++Identification Registers and setting the error bits of the Root Error
++Status Register accordingly. If AER error reporting is enabled in Root
++Error Command Register, the Root Port generates an interrupt if an
++error is detected.
++
++Note that the errors as described above are related to the PCI Express
++hierarchy and links. These errors do not include any device specific
++errors because device specific errors will still get sent directly to
++the device driver.
++
++3.1 Configure the AER capability structure
++
++AER aware drivers of PCI Express component need change the device
++control registers to enable AER. They also could change AER registers,
++including mask and severity registers. Helper function
++pci_enable_pcie_error_reporting could be used to enable AER. See
++section 3.3.
++
++3.2. Provide callbacks
++
++3.2.1 callback reset_link to reset pci express link
++
++This callback is used to reset the pci express physical link when a
++fatal error happens. The root port aer service driver provides a
++default reset_link function, but different upstream ports might
++have different specifications to reset pci express link, so all
++upstream ports should provide their own reset_link functions.
++
++In struct pcie_port_service_driver, a new pointer, reset_link, is
++added.
++
++pci_ers_result_t (*reset_link) (struct pci_dev *dev);
++
++Section 3.2.2.2 provides more detailed info on when to call
++reset_link.
++
++3.2.2 PCI error-recovery callbacks
++
++The PCI Express AER Root driver uses error callbacks to coordinate
++with downstream device drivers associated with a hierarchy in question
++when performing error recovery actions.
++
++Data struct pci_driver has a pointer, err_handler, to point to
++pci_error_handlers who consists of a couple of callback function
++pointers. AER driver follows the rules defined in
++pci-error-recovery.txt except pci express specific parts (e.g.
++reset_link). Pls. refer to pci-error-recovery.txt for detailed
++definitions of the callbacks.
++
++Below sections specify when to call the error callback functions.
++
++3.2.2.1 Correctable errors
++
++Correctable errors pose no impacts on the functionality of
++the interface. The PCI Express protocol can recover without any
++software intervention or any loss of data. These errors do not
++require any recovery actions. The AER driver clears the device's
++correctable error status register accordingly and logs these errors.
++
++3.2.2.2 Non-correctable (non-fatal and fatal) errors
++
++If an error message indicates a non-fatal error, performing link reset
++at upstream is not required. The AER driver calls error_detected(dev,
++pci_channel_io_normal) to all drivers associated within a hierarchy in
++question. for example,
++EndPoint<==>DownstreamPort B<==>UpstreamPort A<==>RootPort.
++If Upstream port A captures an AER error, the hierarchy consists of
++Downstream port B and EndPoint.
++
++A driver may return PCI_ERS_RESULT_CAN_RECOVER,
++PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on
++whether it can recover or the AER driver calls mmio_enabled as next.
++
++If an error message indicates a fatal error, kernel will broadcast
++error_detected(dev, pci_channel_io_frozen) to all drivers within
++a hierarchy in question. Then, performing link reset at upstream is
++necessary. As different kinds of devices might use different approaches
++to reset link, AER port service driver is required to provide the
++function to reset link. Firstly, kernel looks for if the upstream
++component has an aer driver. If it has, kernel uses the reset_link
++callback of the aer driver. If the upstream component has no aer driver
++and the port is downstream port, we will use the aer driver of the
++root port who reports the AER error. As for upstream ports,
++they should provide their own aer service drivers with reset_link
++function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
++reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
++to mmio_enabled.
++
++3.3 helper functions
++
++3.3.1 int pci_find_aer_capability(struct pci_dev *dev);
++pci_find_aer_capability locates the PCI Express AER capability
++in the device configuration space. If the device doesn't support
++PCI-Express AER, the function returns 0.
++
++3.3.2 int pci_enable_pcie_error_reporting(struct pci_dev *dev);
++pci_enable_pcie_error_reporting enables the device to send error
++messages to root port when an error is detected. Note that devices
++don't enable the error reporting by default, so device drivers need
++call this function to enable it.
++
++3.3.3 int pci_disable_pcie_error_reporting(struct pci_dev *dev);
++pci_disable_pcie_error_reporting disables the device to send error
++messages to root port when an error is detected.
++
++3.3.4 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
++pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable
++error status register.
++
++3.4 Frequent Asked Questions
++
++Q: What happens if a PCI Express device driver does not provide an
++error recovery handler (pci_driver->err_handler is equal to NULL)?
++
++A: The devices attached with the driver won't be recovered. If the
++error is fatal, kernel will print out warning messages. Please refer
++to section 3 for more information.
++
++Q: What happens if an upstream port service driver does not provide
++callback reset_link?
++
++A: Fatal error recovery will fail if the errors are reported by the
++upstream ports who are attached by the service driver.
++
++Q: How does this infrastructure deal with driver that is not PCI
++Express aware?
++
++A: This infrastructure calls the error callback functions of the
++driver when an error happens. But if the driver is not aware of
++PCI Express, the device might not report its own errors to root
++port.
++
++Q: What modifications will that driver need to make it compatible
++with the PCI Express AER Root driver?
++
++A: It could call the helper functions to enable AER in devices and
++cleanup uncorrectable status register. Pls. refer to section 3.3.
++
+diff --git a/Documentation/pi-futex.txt b/Documentation/pi-futex.txt
+index 5d61dac..9a5bc86 100644
+--- a/Documentation/pi-futex.txt
++++ b/Documentation/pi-futex.txt
+@@ -118,4 +118,4 @@ properties of futexes, and all four comb
+ robust-futex, PI-futex, robust+PI-futex.
+
+ More details about priority inheritance can be found in
+-Documentation/rtmutex.txt.
++Documentation/rt-mutex.txt.
+diff --git a/Documentation/pm.txt b/Documentation/pm.txt
+index 79c0f32..da8589a 100644
+--- a/Documentation/pm.txt
++++ b/Documentation/pm.txt
+@@ -18,10 +18,10 @@ enabled by default). If a working ACPI
+ ACPI driver will override and disable APM, otherwise the APM driver
+ will be used.
+
+-No sorry, you can not have both ACPI and APM enabled and running at
++No, sorry, you cannot have both ACPI and APM enabled and running at
+ once. Some people with broken ACPI or broken APM implementations
+ would like to use both to get a full set of working features, but you
+-simply can not mix and match the two. Only one power management
++simply cannot mix and match the two. Only one power management
+ interface can be in control of the machine at once. Think about it..
+
+ User-space Daemons
+@@ -106,7 +106,7 @@ void pm_unregister_all(pm_callback cback
+ *
+ * Returns: 0 if the request is successful
+ * EINVAL if the request is not supported
+- * EBUSY if the device is now busy and can not handle the request
++ * EBUSY if the device is now busy and cannot handle the request
+ * ENOMEM if the device was unable to handle the request due to memory
+ *
+ * Details: The device request callback will be called before the
+diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
+index 9529c9c..9ff966b 100644
+--- a/Documentation/pnp.txt
++++ b/Documentation/pnp.txt
+@@ -222,7 +222,7 @@ static struct pnp_driver serial_pnp_driv
+ .remove = serial_pnp_remove,
+ };
+
+-* name and id_table can not be NULL.
++* name and id_table cannot be NULL.
+
+ 4.) register the driver
+ ex:
+diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
+index fba1e05..d0e79d5 100644
+--- a/Documentation/power/devices.txt
++++ b/Documentation/power/devices.txt
+@@ -1,208 +1,553 @@
++Most of the code in Linux is device drivers, so most of the Linux power
++management code is also driver-specific. Most drivers will do very little;
++others, especially for platforms with small batteries (like cell phones),
++will do a lot.
++
++This writeup gives an overview of how drivers interact with system-wide
++power management goals, emphasizing the models and interfaces that are
++shared by everything that hooks up to the driver model core. Read it as
++background for the domain-specific work you'd do with any specific driver.
++
++
++Two Models for Device Power Management
++======================================
++Drivers will use one or both of these models to put devices into low-power
++states:
++
++ System Sleep model:
++ Drivers can enter low power states as part of entering system-wide
++ low-power states like "suspend-to-ram", or (mostly for systems with
++ disks) "hibernate" (suspend-to-disk).
++
++ This is something that device, bus, and class drivers collaborate on
++ by implementing various role-specific suspend and resume methods to
++ cleanly power down hardware and software subsystems, then reactivate
++ them without loss of data.
++
++ Some drivers can manage hardware wakeup events, which make the system
++ leave that low-power state. This feature may be disabled using the
++ relevant /sys/devices/.../power/wakeup file; enabling it may cost some
++ power usage, but let the whole system enter low power states more often.
++
++ Runtime Power Management model:
++ Drivers may also enter low power states while the system is running,
++ independently of other power management activity. Upstream drivers
++ will normally not know (or care) if the device is in some low power
++ state when issuing requests; the driver will auto-resume anything
++ that's needed when it gets a request.
++
++ This doesn't have, or need much infrastructure; it's just something you
++ should do when writing your drivers. For example, clk_disable() unused
++ clocks as part of minimizing power drain for currently-unused hardware.
++ Of course, sometimes clusters of drivers will collaborate with each
++ other, which could involve task-specific power management.
++
++There's not a lot to be said about those low power states except that they
++are very system-specific, and often device-specific. Also, that if enough
++drivers put themselves into low power states (at "runtime"), the effect may be
++the same as entering some system-wide low-power state (system sleep) ... and
++that synergies exist, so that several drivers using runtime pm might put the
++system into a state where even deeper power saving options are available.
++
++Most suspended devices will have quiesced all I/O: no more DMA or irqs, no
++more data read or written, and requests from upstream drivers are no longer
++accepted. A given bus or platform may have different requirements though.
++
++Examples of hardware wakeup events include an alarm from a real time clock,
++network wake-on-LAN packets, keyboard or mouse activity, and media insertion
++or removal (for PCMCIA, MMC/SD, USB, and so on).
++
++
++Interfaces for Entering System Sleep States
++===========================================
++Most of the programming interfaces a device driver needs to know about
++relate to that first model: entering a system-wide low power state,
++rather than just minimizing power consumption by one device.
++
++
++Bus Driver Methods
++------------------
++The core methods to suspend and resume devices reside in struct bus_type.
++These are mostly of interest to people writing infrastructure for busses
++like PCI or USB, or because they define the primitives that device drivers
++may need to apply in domain-specific ways to their devices:
+
+-Device Power Management
+-
+-
+-Device power management encompasses two areas - the ability to save
+-state and transition a device to a low-power state when the system is
+-entering a low-power state; and the ability to transition a device to
+-a low-power state while the system is running (and independently of
+-any other power management activity).
+-
+-
+-Methods
++struct bus_type {
++ ...
++ int (*suspend)(struct device *dev, pm_message_t state);
++ int (*suspend_late)(struct device *dev, pm_message_t state);
+
+-The methods to suspend and resume devices reside in struct bus_type:
++ int (*resume_early)(struct device *dev);
++ int (*resume)(struct device *dev);
++};
+
+-struct bus_type {
+- ...
+- int (*suspend)(struct device * dev, pm_message_t state);
+- int (*resume)(struct device * dev);
++Bus drivers implement those methods as appropriate for the hardware and
++the drivers using it; PCI works differently from USB, and so on. Not many
++people write bus drivers; most driver code is a "device driver" that
++builds on top of bus-specific framework code.
++
++For more information on these driver calls, see the description later;
++they are called in phases for every device, respecting the parent-child
++sequencing in the driver model tree. Note that as this is being written,
++only the suspend() and resume() are widely available; not many bus drivers
++leverage all of those phases, or pass them down to lower driver levels.
++
++
++/sys/devices/.../power/wakeup files
++-----------------------------------
++All devices in the driver model have two flags to control handling of
++wakeup events, which are hardware signals that can force the device and/or
++system out of a low power state. These are initialized by bus or device
++driver code using device_init_wakeup(dev,can_wakeup).
++
++The "can_wakeup" flag just records whether the device (and its driver) can
++physically support wakeup events. When that flag is clear, the sysfs
++"wakeup" file is empty, and device_may_wakeup() returns false.
++
++For devices that can issue wakeup events, a separate flag controls whether
++that device should try to use its wakeup mechanism. The initial value of
++device_may_wakeup() will be true, so that the device's "wakeup" file holds
++the value "enabled". Userspace can change that to "disabled" so that
++device_may_wakeup() returns false; or change it back to "enabled" (so that
++it returns true again).
++
++
++EXAMPLE: PCI Device Driver Methods
++-----------------------------------
++PCI framework software calls these methods when the PCI device driver bound
++to a device device has provided them:
++
++struct pci_driver {
++ ...
++ int (*suspend)(struct pci_device *pdev, pm_message_t state);
++ int (*suspend_late)(struct pci_device *pdev, pm_message_t state);
++
++ int (*resume_early)(struct pci_device *pdev);
++ int (*resume)(struct pci_device *pdev);
+ };
+
+-Each bus driver is responsible implementing these methods, translating
+-the call into a bus-specific request and forwarding the call to the
+-bus-specific drivers. For example, PCI drivers implement suspend() and
+-resume() methods in struct pci_driver. The PCI core is simply
+-responsible for translating the pointers to PCI-specific ones and
+-calling the low-level driver.
+-
+-This is done to a) ease transition to the new power management methods
+-and leverage the existing PM code in various bus drivers; b) allow
+-buses to implement generic and default PM routines for devices, and c)
+-make the flow of execution obvious to the reader.
+-
+-
+-System Power Management
+-
+-When the system enters a low-power state, the device tree is walked in
+-a depth-first fashion to transition each device into a low-power
+-state. The ordering of the device tree is guaranteed by the order in
+-which devices get registered - children are never registered before
+-their ancestors, and devices are placed at the back of the list when
+-registered. By walking the list in reverse order, we are guaranteed to
+-suspend devices in the proper order.
+-
+-Devices are suspended once with interrupts enabled. Drivers are
+-expected to stop I/O transactions, save device state, and place the
+-device into a low-power state. Drivers may sleep, allocate memory,
+-etc. at will.
+-
+-Some devices are broken and will inevitably have problems powering
+-down or disabling themselves with interrupts enabled. For these
+-special cases, they may return -EAGAIN. This will put the device on a
+-list to be taken care of later. When interrupts are disabled, before
+-we enter the low-power state, their drivers are called again to put
+-their device to sleep.
+-
+-On resume, the devices that returned -EAGAIN will be called to power
+-themselves back on with interrupts disabled. Once interrupts have been
+-re-enabled, the rest of the drivers will be called to resume their
+-devices. On resume, a driver is responsible for powering back on each
+-device, restoring state, and re-enabling I/O transactions for that
+-device.
++Drivers will implement those methods, and call PCI-specific procedures
++like pci_set_power_state(), pci_enable_wake(), pci_save_state(), and
++pci_restore_state() to manage PCI-specific mechanisms. (PCI config space
++could be saved during driver probe, if it weren't for the fact that some
++systems rely on userspace tweaking using setpci.) Devices are suspended
++before their bridges enter low power states, and likewise bridges resume
++before their devices.
++
++
++Upper Layers of Driver Stacks
++-----------------------------
++Device drivers generally have at least two interfaces, and the methods
++sketched above are the ones which apply to the lower level (nearer PCI, USB,
++or other bus hardware). The network and block layers are examples of upper
++level interfaces, as is a character device talking to userspace.
++
++Power management requests normally need to flow through those upper levels,
++which often use domain-oriented requests like "blank that screen". In
++some cases those upper levels will have power management intelligence that
++relates to end-user activity, or other devices that work in cooperation.
++
++When those interfaces are structured using class interfaces, there is a
++standard way to have the upper layer stop issuing requests to a given
++class device (and restart later):
++
++struct class {
++ ...
++ int (*suspend)(struct device *dev, pm_message_t state);
++ int (*resume)(struct device *dev);
++};
+
++Those calls are issued in specific phases of the process by which the
++system enters a low power "suspend" state, or resumes from it.
++
++
++Calling Drivers to Enter System Sleep States
++============================================
++When the system enters a low power state, each device's driver is asked
++to suspend the device by putting it into state compatible with the target
++system state. That's usually some version of "off", but the details are
++system-specific. Also, wakeup-enabled devices will usually stay partly
++functional in order to wake the system.
++
++When the system leaves that low power state, the device's driver is asked
++to resume it. The suspend and resume operations always go together, and
++both are multi-phase operations.
++
++For simple drivers, suspend might quiesce the device using the class code
++and then turn its hardware as "off" as possible with late_suspend. The
++matching resume calls would then completely reinitialize the hardware
++before reactivating its class I/O queues.
++
++More power-aware drivers drivers will use more than one device low power
++state, either at runtime or during system sleep states, and might trigger
++system wakeup events.
++
++
++Call Sequence Guarantees
++------------------------
++To ensure that bridges and similar links needed to talk to a device are
++available when the device is suspended or resumed, the device tree is
++walked in a bottom-up order to suspend devices. A top-down order is
++used to resume those devices.
++
++The ordering of the device tree is defined by the order in which devices
++get registered: a child can never be registered, probed or resumed before
++its parent; and can't be removed or suspended after that parent.
++
++The policy is that the device tree should match hardware bus topology.
++(Or at least the control bus, for devices which use multiple busses.)
++
++
++Suspending Devices
++------------------
++Suspending a given device is done in several phases. Suspending the
++system always includes every phase, executing calls for every device
++before the next phase begins. Not all busses or classes support all
++these callbacks; and not all drivers use all the callbacks.
++
++The phases are seen by driver notifications issued in this order:
++
++ 1 class.suspend(dev, message) is called after tasks are frozen, for
++ devices associated with a class that has such a method. This
++ method may sleep.
++
++ Since I/O activity usually comes from such higher layers, this is
++ a good place to quiesce all drivers of a given type (and keep such
++ code out of those drivers).
++
++ 2 bus.suspend(dev, message) is called next. This method may sleep,
++ and is often morphed into a device driver call with bus-specific
++ parameters and/or rules.
++
++ This call should handle parts of device suspend logic that require
++ sleeping. It probably does work to quiesce the device which hasn't
++ been abstracted into class.suspend() or bus.suspend_late().
++
++ 3 bus.suspend_late(dev, message) is called with IRQs disabled, and
++ with only one CPU active. Until the bus.resume_early() phase
++ completes (see later), IRQs are not enabled again. This method
++ won't be exposed by all busses; for message based busses like USB,
++ I2C, or SPI, device interactions normally require IRQs. This bus
++ call may be morphed into a driver call with bus-specific parameters.
++
++ This call might save low level hardware state that might otherwise
++ be lost in the upcoming low power state, and actually put the
++ device into a low power state ... so that in some cases the device
++ may stay partly usable until this late. This "late" call may also
++ help when coping with hardware that behaves badly.
++
++The pm_message_t parameter is currently used to refine those semantics
++(described later).
++
++At the end of those phases, drivers should normally have stopped all I/O
++transactions (DMA, IRQs), saved enough state that they can re-initialize
++or restore previous state (as needed by the hardware), and placed the
++device into a low-power state. On many platforms they will also use
++clk_disable() to gate off one or more clock sources; sometimes they will
++also switch off power supplies, or reduce voltages. Drivers which have
++runtime PM support may already have performed some or all of the steps
++needed to prepare for the upcoming system sleep state.
++
++When any driver sees that its device_can_wakeup(dev), it should make sure
++to use the relevant hardware signals to trigger a system wakeup event.
++For example, enable_irq_wake() might identify GPIO signals hooked up to
++a switch or other external hardware, and pci_enable_wake() does something
++similar for PCI's PME# signal.
++
++If a driver (or bus, or class) fails it suspend method, the system won't
++enter the desired low power state; it will resume all the devices it's
++suspended so far.
++
++Note that drivers may need to perform different actions based on the target
++system lowpower/sleep state. At this writing, there are only platform
++specific APIs through which drivers could determine those target states.
++
++
++Device Low Power (suspend) States
++---------------------------------
++Device low-power states aren't very standard. One device might only handle
++"on" and "off, while another might support a dozen different versions of
++"on" (how many engines are active?), plus a state that gets back to "on"
++faster than from a full "off".
++
++Some busses define rules about what different suspend states mean. PCI
++gives one example: after the suspend sequence completes, a non-legacy
++PCI device may not perform DMA or issue IRQs, and any wakeup events it
++issues would be issued through the PME# bus signal. Plus, there are
++several PCI-standard device states, some of which are optional.
++
++In contrast, integrated system-on-chip processors often use irqs as the
++wakeup event sources (so drivers would call enable_irq_wake) and might
++be able to treat DMA completion as a wakeup event (sometimes DMA can stay
++active too, it'd only be the CPU and some peripherals that sleep).
++
++Some details here may be platform-specific. Systems may have devices that
++can be fully active in certain sleep states, such as an LCD display that's
++refreshed using DMA while most of the system is sleeping lightly ... and
++its frame buffer might even be updated by a DSP or other non-Linux CPU while
++the Linux control processor stays idle.
++
++Moreover, the specific actions taken may depend on the target system state.
++One target system state might allow a given device to be very operational;
++another might require a hard shut down with re-initialization on resume.
++And two different target systems might use the same device in different
++ways; the aforementioned LCD might be active in one product's "standby",
++but a different product using the same SOC might work differently.
++
++
++Meaning of pm_message_t.event
++-----------------------------
++Parameters to suspend calls include the device affected and a message of
++type pm_message_t, which has one field: the event. If driver does not
++recognize the event code, suspend calls may abort the request and return
++a negative errno. However, most drivers will be fine if they implement
++PM_EVENT_SUSPEND semantics for all messages.
++
++The event codes are used to refine the goal of suspending the device, and
++mostly matter when creating or resuming system memory image snapshots, as
++used with suspend-to-disk:
++
++ PM_EVENT_SUSPEND -- quiesce the driver and put hardware into a low-power
++ state. When used with system sleep states like "suspend-to-RAM" or
++ "standby", the upcoming resume() call will often be able to rely on
++ state kept in hardware, or issue system wakeup events. When used
++ instead with suspend-to-disk, few devices support this capability;
++ most are completely powered off.
++
++ PM_EVENT_FREEZE -- quiesce the driver, but don't necessarily change into
++ any low power mode. A system snapshot is about to be taken, often
++ followed by a call to the driver's resume() method. Neither wakeup
++ events nor DMA are allowed.
++
++ PM_EVENT_PRETHAW -- quiesce the driver, knowing that the upcoming resume()
++ will restore a suspend-to-disk snapshot from a different kernel image.
++ Drivers that are smart enough to look at their hardware state during
++ resume() processing need that state to be correct ... a PRETHAW could
++ be used to invalidate that state (by resetting the device), like a
++ shutdown() invocation would before a kexec() or system halt. Other
++ drivers might handle this the same way as PM_EVENT_FREEZE. Neither
++ wakeup events nor DMA are allowed.
++
++To enter "standby" (ACPI S1) or "Suspend to RAM" (STR, ACPI S3) states, or
++the similarly named APM states, only PM_EVENT_SUSPEND is used; for "Suspend
++to Disk" (STD, hibernate, ACPI S4), all of those event codes are used.
++
++There's also PM_EVENT_ON, a value which never appears as a suspend event
++but is sometimes used to record the "not suspended" device state.
++
++
++Resuming Devices
++----------------
++Resuming is done in multiple phases, much like suspending, with all
++devices processing each phase's calls before the next phase begins.
++
++The phases are seen by driver notifications issued in this order:
++
++ 1 bus.resume_early(dev) is called with IRQs disabled, and with
++ only one CPU active. As with bus.suspend_late(), this method
++ won't be supported on busses that require IRQs in order to
++ interact with devices.
++
++ This reverses the effects of bus.suspend_late().
++
++ 2 bus.resume(dev) is called next. This may be morphed into a device
++ driver call with bus-specific parameters; implementations may sleep.
++
++ This reverses the effects of bus.suspend().
++
++ 3 class.resume(dev) is called for devices associated with a class
++ that has such a method. Implementations may sleep.
++
++ This reverses the effects of class.suspend(), and would usually
++ reactivate the device's I/O queue.
++
++At the end of those phases, drivers should normally be as functional as
++they were before suspending: I/O can be performed using DMA and IRQs, and
++the relevant clocks are gated on. The device need not be "fully on"; it
++might be in a runtime lowpower/suspend state that acts as if it were.
++
++However, the details here may again be platform-specific. For example,
++some systems support multiple "run" states, and the mode in effect at
++the end of resume() might not be the one which preceded suspension.
++That means availability of certain clocks or power supplies changed,
++which could easily affect how a driver works.
++
++
++Drivers need to be able to handle hardware which has been reset since the
++suspend methods were called, for example by complete reinitialization.
++This may be the hardest part, and the one most protected by NDA'd documents
++and chip errata. It's simplest if the hardware state hasn't changed since
++the suspend() was called, but that can't always be guaranteed.
++
++Drivers must also be prepared to notice that the device has been removed
++while the system was powered off, whenever that's physically possible.
++PCMCIA, MMC, USB, Firewire, SCSI, and even IDE are common examples of busses
++where common Linux platforms will see such removal. Details of how drivers
++will notice and handle such removals are currently bus-specific, and often
++involve a separate thread.
++
++
++Note that the bus-specific runtime PM wakeup mechanism can exist, and might
++be defined to share some of the same driver code as for system wakeup. For
++example, a bus-specific device driver's resume() method might be used there,
++so it wouldn't only be called from bus.resume() during system-wide wakeup.
++See bus-specific information about how runtime wakeup events are handled.
++
++
++System Devices
++--------------
+ System devices follow a slightly different API, which can be found in
+
+ include/linux/sysdev.h
+ drivers/base/sys.c
+
+-System devices will only be suspended with interrupts disabled, and
+-after all other devices have been suspended. On resume, they will be
+-resumed before any other devices, and also with interrupts disabled.
++System devices will only be suspended with interrupts disabled, and after
++all other devices have been suspended. On resume, they will be resumed
++before any other devices, and also with interrupts disabled.
+
++That is, IRQs are disabled, the suspend_late() phase begins, then the
++sysdev_driver.suspend() phase, and the system enters a sleep state. Then
++the sysdev_driver.resume() phase begins, followed by the resume_early()
++phase, after which IRQs are enabled.
+
+-Runtime Power Management
++Code to actually enter and exit the system-wide low power state sometimes
++involves hardware details that are only known to the boot firmware, and
++may leave a CPU running software (from SRAM or flash memory) that monitors
++the system and manages its wakeup sequence.
+
+-Many devices are able to dynamically power down while the system is
+-still running. This feature is useful for devices that are not being
+-used, and can offer significant power savings on a running system.
+-
+-In each device's directory, there is a 'power' directory, which
+-contains at least a 'state' file. Reading from this file displays what
+-power state the device is currently in. Writing to this file initiates
+-a transition to the specified power state, which must be a decimal in
+-the range 1-3, inclusive; or 0 for 'On'.
+-
+-The PM core will call the ->suspend() method in the bus_type object
+-that the device belongs to if the specified state is not 0, or
+-->resume() if it is.
+-
+-Nothing will happen if the specified state is the same state the
+-device is currently in.
+-
+-If the device is already in a low-power state, and the specified state
+-is another, but different, low-power state, the ->resume() method will
+-first be called to power the device back on, then ->suspend() will be
+-called again with the new state.
+-
+-The driver is responsible for saving the working state of the device
+-and putting it into the low-power state specified. If this was
+-successful, it returns 0, and the device's power_state field is
+-updated.
+-
+-The driver must take care to know whether or not it is able to
+-properly resume the device, including all step of reinitialization
+-necessary. (This is the hardest part, and the one most protected by
+-NDA'd documents).
+-
+-The driver must also take care not to suspend a device that is
+-currently in use. It is their responsibility to provide their own
+-exclusion mechanisms.
+-
+-The runtime power transition happens with interrupts enabled. If a
+-device cannot support being powered down with interrupts, it may
+-return -EAGAIN (as it would during a system power management
+-transition), but it will _not_ be called again, and the transaction
+-will fail.
+-
+-There is currently no way to know what states a device or driver
+-supports a priori. This will change in the future.
+-
+-pm_message_t meaning
+-
+-pm_message_t has two fields. event ("major"), and flags. If driver
+-does not know event code, it aborts the request, returning error. Some
+-drivers may need to deal with special cases based on the actual type
+-of suspend operation being done at the system level. This is why
+-there are flags.
+-
+-Event codes are:
+-
+-ON -- no need to do anything except special cases like broken
+-HW.
+-
+-# NOTIFICATION -- pretty much same as ON?
+-
+-FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from
+-scratch. That probably means stop accepting upstream requests, the
+-actual policy of what to do with them being specific to a given
+-driver. It's acceptable for a network driver to just drop packets
+-while a block driver is expected to block the queue so no request is
+-lost. (Use IDE as an example on how to do that). FREEZE requires no
+-power state change, and it's expected for drivers to be able to
+-quickly transition back to operating state.
+-
+-SUSPEND -- like FREEZE, but also put hardware into low-power state. If
+-there's need to distinguish several levels of sleep, additional flag
+-is probably best way to do that.
+-
+-Transitions are only from a resumed state to a suspended state, never
+-between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen,
+-FREEZE -> SUSPEND or SUSPEND -> FREEZE can not).
+-
+-All events are:
+-
+-[NOTE NOTE NOTE: If you are driver author, you should not care; you
+-should only look at event, and ignore flags.]
+-
+-#Prepare for suspend -- userland is still running but we are going to
+-#enter suspend state. This gives drivers chance to load firmware from
+-#disk and store it in memory, or do other activities taht require
+-#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these
+-#are forbiden once the suspend dance is started.. event = ON, flags =
+-#PREPARE_TO_SUSPEND
+-
+-Apm standby -- prepare for APM event. Quiesce devices to make life
+-easier for APM BIOS. event = FREEZE, flags = APM_STANDBY
+-
+-Apm suspend -- same as APM_STANDBY, but it we should probably avoid
+-spinning down disks. event = FREEZE, flags = APM_SUSPEND
+-
+-System halt, reboot -- quiesce devices to make life easier for BIOS. event
+-= FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT
+-
+-System shutdown -- at least disks need to be spun down, or data may be
+-lost. Quiesce devices, just to make life easier for BIOS. event =
+-FREEZE, flags = SYSTEM_SHUTDOWN
+-
+-Kexec -- turn off DMAs and put hardware into some state where new
+-kernel can take over. event = FREEZE, flags = KEXEC
+-
+-Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake
+-may need to be enabled on some devices. This actually has at least 3
+-subtypes, system can reboot, enter S4 and enter S5 at the end of
+-swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT,
+-SYSTEM_SHUTDOWN, SYSTEM_S4
+-
+-Suspend to ram -- put devices into low power state. event = SUSPEND,
+-flags = SUSPEND_TO_RAM
+-
+-Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put
+-devices into low power mode, but you must be able to reinitialize
+-device from scratch in resume method. This has two flavors, its done
+-once on suspending kernel, once on resuming kernel. event = FREEZE,
+-flags = DURING_SUSPEND or DURING_RESUME
+-
+-Device detach requested from /sys -- deinitialize device; proably same as
+-SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
+-= FREEZE, flags = DEV_DETACH.
+-
+-#These are not really events sent:
+-#
+-#System fully on -- device is working normally; this is probably never
+-#passed to suspend() method... event = ON, flags = 0
+-#
+-#Ready after resume -- userland is now running, again. Time to free any
+-#memory you ate during prepare to suspend... event = ON, flags =
+-#READY_AFTER_RESUME
+-#
++
++Runtime Power Management
++========================
++Many devices are able to dynamically power down while the system is still
++running. This feature is useful for devices that are not being used, and
++can offer significant power savings on a running system. These devices
++often support a range of runtime power states, which might use names such
++as "off", "sleep", "idle", "active", and so on. Those states will in some
++cases (like PCI) be partially constrained by a bus the device uses, and will
++usually include hardware states that are also used in system sleep states.
++
++However, note that if a driver puts a device into a runtime low power state
++and the system then goes into a system-wide sleep state, it normally ought
++to resume into that runtime low power state rather than "full on". Such
++distinctions would be part of the driver-internal state machine for that
++hardware; the whole point of runtime power management is to be sure that
++drivers are decoupled in that way from the state machine governing phases
++of the system-wide power/sleep state transitions.
++
++
++Power Saving Techniques
++-----------------------
++Normally runtime power management is handled by the drivers without specific
++userspace or kernel intervention, by device-aware use of techniques like:
++
++ Using information provided by other system layers
++ - stay deeply "off" except between open() and close()
++ - if transceiver/PHY indicates "nobody connected", stay "off"
++ - application protocols may include power commands or hints
++
++ Using fewer CPU cycles
++ - using DMA instead of PIO
++ - removing timers, or making them lower frequency
++ - shortening "hot" code paths
++ - eliminating cache misses
++ - (sometimes) offloading work to device firmware
++
++ Reducing other resource costs
++ - gating off unused clocks in software (or hardware)
++ - switching off unused power supplies
++ - eliminating (or delaying/merging) IRQs
++ - tuning DMA to use word and/or burst modes
++
++ Using device-specific low power states
++ - using lower voltages
++ - avoiding needless DMA transfers
++
++Read your hardware documentation carefully to see the opportunities that
++may be available. If you can, measure the actual power usage and check
++it against the budget established for your project.
++
++
++Examples: USB hosts, system timer, system CPU
++----------------------------------------------
++USB host controllers make interesting, if complex, examples. In many cases
++these have no work to do: no USB devices are connected, or all of them are
++in the USB "suspend" state. Linux host controller drivers can then disable
++periodic DMA transfers that would otherwise be a constant power drain on the
++memory subsystem, and enter a suspend state. In power-aware controllers,
++entering that suspend state may disable the clock used with USB signaling,
++saving a certain amount of power.
++
++The controller will be woken from that state (with an IRQ) by changes to the
++signal state on the data lines of a given port, for example by an existing
++peripheral requesting "remote wakeup" or by plugging a new peripheral. The
++same wakeup mechanism usually works from "standby" sleep states, and on some
++systems also from "suspend to RAM" (or even "suspend to disk") states.
++(Except that ACPI may be involved instead of normal IRQs, on some hardware.)
++
++System devices like timers and CPUs may have special roles in the platform
++power management scheme. For example, system timers using a "dynamic tick"
++approach don't just save CPU cycles (by eliminating needless timer IRQs),
++but they may also open the door to using lower power CPU "idle" states that
++cost more than a jiffie to enter and exit. On x86 systems these are states
++like "C3"; note that periodic DMA transfers from a USB host controller will
++also prevent entry to a C3 state, much like a periodic timer IRQ.
++
++That kind of runtime mechanism interaction is common. "System On Chip" (SOC)
++processors often have low power idle modes that can't be entered unless
++certain medium-speed clocks (often 12 or 48 MHz) are gated off. When the
++drivers gate those clocks effectively, then the system idle task may be able
++to use the lower power idle modes and thereby increase battery life.
++
++If the CPU can have a "cpufreq" driver, there also may be opportunities
++to shift to lower voltage settings and reduce the power cost of executing
++a given number of instructions. (Without voltage adjustment, it's rare
++for cpufreq to save much power; the cost-per-instruction must go down.)
++
++
++/sys/devices/.../power/state files
++==================================
++For now you can also test some of this functionality using sysfs.
++
++ DEPRECATED: USE "power/state" ONLY FOR DRIVER TESTING, AND
++ AVOID USING dev->power.power_state IN DRIVERS.
++
++ THESE WILL BE REMOVED. IF THE "power/state" FILE GETS REPLACED,
++ IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
++
++In each device's directory, there is a 'power' directory, which contains
++at least a 'state' file. The value of this field is effectively boolean,
++PM_EVENT_ON or PM_EVENT_SUSPEND.
++
++ * Reading from this file displays a value corresponding to
++ the power.power_state.event field. All nonzero values are
++ displayed as "2", corresponding to a low power state; zero
++ is displayed as "0", corresponding to normal operation.
++
++ * Writing to this file initiates a transition using the
++ specified event code number; only '0', '2', and '3' are
++ accepted (without a newline); '2' and '3' are both
++ mapped to PM_EVENT_SUSPEND.
++
++On writes, the PM core relies on that recorded event code and the device/bus
++capabilities to determine whether it uses a partial suspend() or resume()
++sequence to change things so that the recorded event corresponds to the
++numeric parameter.
++
++ - If the bus requires the irqs-disabled suspend_late()/resume_early()
++ phases, writes fail because those operations are not supported here.
++
++ - If the recorded value is the expected value, nothing is done.
++
++ - If the recorded value is nonzero, the device is partially resumed,
++ using the bus.resume() and/or class.resume() methods.
++
++ - If the target value is nonzero, the device is partially suspended,
++ using the class.suspend() and/or bus.suspend() methods and the
++ PM_EVENT_SUSPEND message.
++
++Drivers have no way to tell whether their suspend() and resume() calls
++have come through the sysfs power/state file or as part of entering a
++system sleep state, except that when accessed through sysfs the normal
++parent/child sequencing rules are ignored. Drivers (such as bus, bridge,
++or hub drivers) which expose child devices may need to enforce those rules
++on their own.
+diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt
+index 4117802..74311d7 100644
+--- a/Documentation/power/interface.txt
++++ b/Documentation/power/interface.txt
+@@ -30,6 +30,17 @@ testing). The system will support either
+ that is known a priori. But, the user may choose 'shutdown' or
+ 'reboot' as alternatives.
+
++Additionally, /sys/power/disk can be used to turn on one of the two testing
++modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the
++suspend-to-disk mechanism is in the 'testproc' mode, writing 'disk' to
++/sys/power/state will cause the kernel to disable nonboot CPUs and freeze
++tasks, wait for 5 seconds, unfreeze tasks and enable nonboot CPUs. If it is
++in the 'test' mode, writing 'disk' to /sys/power/state will cause the kernel
++to disable nonboot CPUs and freeze tasks, shrink memory, suspend devices, wait
++for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then,
++we are able to look in the log messages and work out, for example, which code
++is being slow and which device drivers are misbehaving.
++
+ Reading from this file will display what the mode is currently set
+ to. Writing to this file will accept one of
+
+@@ -37,6 +48,8 @@ to. Writing to this file will accept one
+ 'platform'
+ 'shutdown'
+ 'reboot'
++ 'testproc'
++ 'test'
+
+ It will only change to 'firmware' or 'platform' if the system supports
+ it.
+@@ -52,3 +65,18 @@ suspend image will be as small as possib
+
+ Reading from this file will display the current image size limit, which
+ is set to 500 MB by default.
++
++/sys/power/pm_trace controls the code which saves the last PM event point in
++the RTC across reboots, so that you can debug a machine that just hangs
++during suspend (or more commonly, during resume). Namely, the RTC is only
++used to save the last PM event point if this file contains '1'. Initially it
++contains '0' which may be changed to '1' by writing a string representing a
++nonzero integer into it.
++
++To use this debugging feature you should attempt to suspend the machine, then
++reboot it and run
++
++ dmesg -s 1000000 | grep 'hash matches'
++
++CAUTION: Using it will cause your machine's real-time (CMOS) clock to be
++set to a random invalid time after a resume.
+diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
+index 73fc87e..24edf25 100644
+--- a/Documentation/power/pci.txt
++++ b/Documentation/power/pci.txt
+@@ -326,7 +326,7 @@ A reference implementation
+
+ 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
++more driver 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 823b2cf..9ea2208 100644
+--- a/Documentation/power/swsusp.txt
++++ b/Documentation/power/swsusp.txt
+@@ -156,7 +156,7 @@ instead set the PF_NOFREEZE process flag
+ be very carefull).
+
+
+-Q: What is the difference between between "platform", "shutdown" and
++Q: What is the difference between "platform", "shutdown" and
+ "firmware" in /sys/power/disk?
+
+ A:
+@@ -175,8 +175,8 @@ reliable.
+ Q: I do not understand why you have such strong objections to idea of
+ selective suspend.
+
+-A: Do selective suspend during runtime power managment, that's okay. But
+-its useless for suspend-to-disk. (And I do not see how you could use
++A: Do selective suspend during runtime power management, that's okay. But
++it's useless for suspend-to-disk. (And I do not see how you could use
+ it for suspend-to-ram, I hope you do not want that).
+
+ Lets see, so you suggest to
+@@ -211,7 +211,7 @@ slowness may not matter to you. It can a
+ For devices like disk it does matter, you do not want to spindown for
+ FREEZE.
+
+-Q: After resuming, system is paging heavilly, leading to very bad interactivity.
++Q: After resuming, system is paging heavily, leading to very bad interactivity.
+
+ A: Try running
+
+diff --git a/Documentation/power/tricks.txt b/Documentation/power/tricks.txt
+index c6d58d3..3b26bb5 100644
+--- a/Documentation/power/tricks.txt
++++ b/Documentation/power/tricks.txt
+@@ -9,7 +9,7 @@ If you want to trick swsusp/S3 into work
+
+ * turn off APIC and preempt
+
+-* use ext2. At least it has working fsck. [If something seemes to go
++* use ext2. At least it has working fsck. [If something seems to go
+ wrong, force fsck when you have a chance]
+
+ * turn off modules
+diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
+index 9405822..64755e9 100644
+--- a/Documentation/power/userland-swsusp.txt
++++ b/Documentation/power/userland-swsusp.txt
+@@ -91,7 +91,7 @@ unfreeze user space processes frozen by
+ still frozen when the device is being closed).
+
+ Currently it is assumed that the userland utilities reading/writing the
+-snapshot image from/to the kernel will use a swap parition, called the resume
++snapshot image from/to the kernel will use a swap partition, called the resume
+ partition, as storage space. However, this is not really required, as they
+ can use, for example, a special (blank) suspend partition or a file on a partition
+ that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and mounted afterwards.
+diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
+index d859faa..2b35849 100644
+--- a/Documentation/power/video.txt
++++ b/Documentation/power/video.txt
+@@ -16,7 +16,7 @@ problem for S1 standby, because hardware
+ that.
+
+ We either have to run video BIOS during early resume, or interpret it
+-using vbetool later, or maybe nothing is neccessary on particular
++using vbetool later, or maybe nothing is necessary on particular
+ system because video state is preserved. Unfortunately different
+ methods work on different systems, and no known method suits all of
+ them.
+diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
+index 5c0ba23..27b457c 100644
+--- a/Documentation/powerpc/booting-without-of.txt
++++ b/Documentation/powerpc/booting-without-of.txt
+@@ -145,7 +145,7 @@ it with special cases.
+ in case you are entering the kernel with MMU enabled
+ and a non-1:1 mapping.
+
+- r5 : NULL (as to differenciate with method a)
++ r5 : NULL (as to differentiate with method a)
+
+ Note about SMP entry: Either your firmware puts your other
+ CPUs in some sleep loop or spin loop in ROM where you can get
+@@ -245,7 +245,7 @@ the block to RAM before passing it to th
+ ---------
+
+ The kernel is entered with r3 pointing to an area of memory that is
+- roughtly described in include/asm-powerpc/prom.h by the structure
++ roughly described in include/asm-powerpc/prom.h by the structure
+ boot_param_header:
+
+ struct boot_param_header {
+@@ -335,7 +335,7 @@ struct boot_param_header {
+ "compact" format for the tree itself that is however not backward
+ compatible. You should always generate a structure of the highest
+ version defined at the time of your implementation. Currently
+- that is version 16, unless you explicitely aim at being backward
++ that is version 16, unless you explicitly aim at being backward
+ compatible.
+
+ - last_comp_version
+@@ -418,9 +418,9 @@ zero terminated string and is mandatory
+ format definition (as it is in Open Firmware). Version 0x10 makes it
+ optional as it can generate it from the unit name defined below.
+
+-There is also a "unit name" that is used to differenciate nodes with
++There is also a "unit name" that is used to differentiate nodes with
+ the same name at the same level, it is usually made of the node
+-name's, the "@" sign, and a "unit address", which definition is
++names, the "@" sign, and a "unit address", which definition is
+ specific to the bus type the node sits on.
+
+ The unit name doesn't exist as a property per-se but is included in
+@@ -550,11 +550,11 @@ Here's the basic structure of a single n
+ * [child nodes if any]
+ * token OF_DT_END_NODE (that is 0x00000002)
+
+-So the node content can be summmarised as a start token, a full path,
+-a list of properties, a list of child node and an end token. Every
++So the node content can be summarised as a start token, a full path,
++a list of properties, a list of child nodes, and an end token. Every
+ child node is a full node structure itself as defined above.
+
+-4) Device tree 'strings" block
++4) Device tree "strings" block
+
+ In order to save space, property names, which are generally redundant,
+ are stored separately in the "strings" block. This block is simply the
+@@ -573,7 +573,7 @@ implementation of Open Firmware or an im
+ the Open Firmware client interface, those properties will be created
+ by the trampoline code in the kernel's prom_init() file. For example,
+ that's where you'll have to add code to detect your board model and
+-set the platform number. However, when using the flatenned device-tree
++set the platform number. However, when using the flattened device-tree
+ entry point, there is no prom_init() pass, and thus you have to
+ provide those properties yourself.
+
+@@ -630,12 +630,11 @@ like address space bits, you'll have to
+ prom_parse.c file of the recent kernels for your bus type.
+
+ The "reg" property only defines addresses and sizes (if #size-cells
+-is
+-non-0) within a given bus. In order to translate addresses upward
++is non-0) within a given bus. In order to translate addresses upward
+ (that is into parent bus addresses, and possibly into cpu physical
+ addresses), all busses must contain a "ranges" property. If the
+ "ranges" property is missing at a given level, it's assumed that
+-translation isn't possible. The format of the "ranges" proprety for a
++translation isn't possible. The format of the "ranges" property for a
+ bus is a list of:
+
+ bus address, parent bus address, size
+@@ -689,7 +688,7 @@ is present).
+ 4) Note about node and property names and character set
+ -------------------------------------------------------
+
+-While open firmware provides more flexibe usage of 8859-1, this
++While open firmware provides more flexible usage of 8859-1, this
+ specification enforces more strict rules. Nodes and properties should
+ be comprised only of ASCII characters 'a' to 'z', '0' to
+ '9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
+@@ -732,12 +731,12 @@ address which can extend beyond that lim
+ that typically get driven by the same platform code in the
+ kernel, you would use a different "model" property but put a
+ value in "compatible". The kernel doesn't directly use that
+- value (see /chosen/linux,platform for how the kernel choses a
++ value (see /chosen/linux,platform for how the kernel chooses a
+ platform type) but it is generally useful.
+
+ The root node is also generally where you add additional properties
+ specific to your board like the serial number if any, that sort of
+- thing. it is recommended that if you add any "custom" property whose
++ thing. It is recommended that if you add any "custom" property whose
+ name may clash with standard defined ones, you prefix them with your
+ vendor name and a comma.
+
+@@ -817,7 +816,7 @@ address which can extend beyond that lim
+ your board. It's a list of addresses/sizes concatenated
+ together, with the number of cells of each defined by the
+ #address-cells and #size-cells of the root node. For example,
+- with both of these properties beeing 2 like in the example given
++ with both of these properties being 2 like in the example given
+ earlier, a 970 based machine with 6Gb of RAM could typically
+ have a "reg" property here that looks like:
+
+@@ -970,7 +969,7 @@ device-tree in another format. The curre
+ - "asm": assembly language file. This is a file that can be
+ sourced by gas to generate a device-tree "blob". That file can
+ then simply be added to your Makefile. Additionally, the
+- assembly file exports some symbols that can be use
++ assembly file exports some symbols that can be used.
+
+
+ The syntax of the dtc tool is
+@@ -984,10 +983,10 @@ generated. Supported versions are 1,2,3
+ currently version 3 but that may change in the future to version 16.
+
+ Additionally, dtc performs various sanity checks on the tree, like the
+-uniqueness of linux,phandle properties, validity of strings, etc...
++uniqueness of linux, phandle properties, validity of strings, etc...
+
+ The format of the .dts "source" file is "C" like, supports C and C++
+-style commments.
++style comments.
+
+ / {
+ }
+@@ -1069,13 +1068,13 @@ while all this has been defined and impl
+ around. It contains no internal offsets or pointers for this
+ purpose.
+
+- - An example of code for iterating nodes & retreiving properties
++ - An example of code for iterating nodes & retrieving properties
+ directly from the flattened tree format can be found in the kernel
+ file arch/ppc64/kernel/prom.c, look at scan_flat_dt() function,
+- it's usage in early_init_devtree(), and the corresponding various
++ its usage in early_init_devtree(), and the corresponding various
+ early_init_dt_scan_*() callbacks. That code can be re-used in a
+ GPL bootloader, and as the author of that code, I would be happy
+- do discuss possible free licencing to any vendor who wishes to
++ to discuss possible free licencing to any vendor who wishes to
+ integrate all or part of this code into a non-GPL bootloader.
+
+
+@@ -1441,6 +1440,258 @@ platforms are moved over to use the flat
+ descriptor-types-mask = <012b0ebf>;
+ };
+
++ h) Board Control and Status (BCSR)
++
++ Required properties:
++
++ - device_type : Should be "board-control"
++ - reg : Offset and length of the register set for the device
++
++ Example:
++
++ bcsr at f8000000 {
++ device_type = "board-control";
++ reg = <f8000000 8000>;
++ };
++
++ i) Freescale QUICC Engine module (QE)
++ This represents qe module that is installed on PowerQUICC II Pro.
++ Hopefully it will merge backward compatibility with CPM/CPM2.
++ Basically, it is a bus of devices, that could act more or less
++ as a complete entity (UCC, USB etc ). All of them should be siblings on
++ the "root" qe node, using the common properties from there.
++ The description below applies to the the qe of MPC8360 and
++ more nodes and properties would be extended in the future.
++
++ i) Root QE device
++
++ Required properties:
++ - device_type : should be "qe";
++ - model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
++ - reg : offset and length of the device registers.
++ - bus-frequency : the clock frequency for QUICC Engine.
++
++ Recommended properties
++ - brg-frequency : the internal clock source frequency for baud-rate
++ generators in Hz.
++
++ Example:
++ qe at e0100000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "qe";
++ model = "QE";
++ ranges = <0 e0100000 00100000>;
++ reg = <e0100000 480>;
++ brg-frequency = <0>;
++ bus-frequency = <179A7B00>;
++ }
++
++
++ ii) SPI (Serial Peripheral Interface)
++
++ Required properties:
++ - device_type : should be "spi".
++ - compatible : should be "fsl_spi".
++ - mode : the spi operation mode, it can be "cpu" or "qe".
++ - reg : Offset and length of the register set for the device
++ - interrupts : <a b> where a is the interrupt number and b is a
++ field that represents an encoding of the sense and level
++ information for the interrupt. This should be encoded based on
++ the information in section 2) depending on the type of interrupt
++ controller you have.
++ - interrupt-parent : the phandle for the interrupt controller that
++ services interrupts for this device.
++
++ Example:
++ spi at 4c0 {
++ device_type = "spi";
++ compatible = "fsl_spi";
++ reg = <4c0 40>;
++ interrupts = <82 0>;
++ interrupt-parent = <700>;
++ mode = "cpu";
++ };
++
++
++ iii) USB (Universal Serial Bus Controller)
++
++ Required properties:
++ - device_type : should be "usb".
++ - compatible : could be "qe_udc" or "fhci-hcd".
++ - mode : the could be "host" or "slave".
++ - reg : Offset and length of the register set for the device
++ - interrupts : <a b> where a is the interrupt number and b is a
++ field that represents an encoding of the sense and level
++ information for the interrupt. This should be encoded based on
++ the information in section 2) depending on the type of interrupt
++ controller you have.
++ - interrupt-parent : the phandle for the interrupt controller that
++ services interrupts for this device.
++
++ Example(slave):
++ usb at 6c0 {
++ device_type = "usb";
++ compatible = "qe_udc";
++ reg = <6c0 40>;
++ interrupts = <8b 0>;
++ interrupt-parent = <700>;
++ mode = "slave";
++ };
++
++
++ iv) UCC (Unified Communications Controllers)
++
++ Required properties:
++ - device_type : should be "network", "hldc", "uart", "transparent"
++ "bisync" or "atm".
++ - compatible : could be "ucc_geth" or "fsl_atm" and so on.
++ - model : should be "UCC".
++ - device-id : the ucc number(1-8), corresponding to UCCx in UM.
++ - reg : Offset and length of the register set for the device
++ - interrupts : <a b> where a is the interrupt number and b is a
++ field that represents an encoding of the sense and level
++ information for the interrupt. This should be encoded based on
++ the information in section 2) depending on the type of interrupt
++ controller you have.
++ - interrupt-parent : the phandle for the interrupt controller that
++ services interrupts for this device.
++ - pio-handle : The phandle for the Parallel I/O port configuration.
++ - rx-clock : represents the UCC receive clock source.
++ 0x00 : clock source is disabled;
++ 0x1~0x10 : clock source is BRG1~BRG16 respectively;
++ 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
++ - tx-clock: represents the UCC transmit clock source;
++ 0x00 : clock source is disabled;
++ 0x1~0x10 : clock source is BRG1~BRG16 respectively;
++ 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
++
++ Required properties for network device_type:
++ - mac-address : list of bytes representing the ethernet address.
++ - phy-handle : The phandle for the PHY connected to this controller.
++
++ Example:
++ ucc at 2000 {
++ device_type = "network";
++ compatible = "ucc_geth";
++ model = "UCC";
++ device-id = <1>;
++ reg = <2000 200>;
++ interrupts = <a0 0>;
++ interrupt-parent = <700>;
++ mac-address = [ 00 04 9f 00 23 23 ];
++ rx-clock = "none";
++ tx-clock = "clk9";
++ phy-handle = <212000>;
++ pio-handle = <140001>;
++ };
++
++
++ v) Parallel I/O Ports
++
++ This node configures Parallel I/O ports for CPUs with QE support.
++ The node should reside in the "soc" node of the tree. For each
++ device that using parallel I/O ports, a child node should be created.
++ See the definition of the Pin configuration nodes below for more
++ information.
++
++ Required properties:
++ - device_type : should be "par_io".
++ - reg : offset to the register set and its length.
++ - num-ports : number of Parallel I/O ports
++
++ Example:
++ par_io at 1400 {
++ reg = <1400 100>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ device_type = "par_io";
++ num-ports = <7>;
++ ucc_pin at 01 {
++ ......
++ };
++
++
++ vi) Pin configuration nodes
++
++ Required properties:
++ - linux,phandle : phandle of this node; likely referenced by a QE
++ device.
++ - pio-map : array of pin configurations. Each pin is defined by 6
++ integers. The six numbers are respectively: port, pin, dir,
++ open_drain, assignment, has_irq.
++ - port : port number of the pin; 0-6 represent port A-G in UM.
++ - pin : pin number in the port.
++ - dir : direction of the pin, should encode as follows:
++
++ 0 = The pin is disabled
++ 1 = The pin is an output
++ 2 = The pin is an input
++ 3 = The pin is I/O
++
++ - open_drain : indicates the pin is normal or wired-OR:
++
++ 0 = The pin is actively driven as an output
++ 1 = The pin is an open-drain driver. As an output, the pin is
++ driven active-low, otherwise it is three-stated.
++
++ - assignment : function number of the pin according to the Pin Assignment
++ tables in User Manual. Each pin can have up to 4 possible functions in
++ QE and two options for CPM.
++ - has_irq : indicates if the pin is used as source of exteral
++ interrupts.
++
++ Example:
++ ucc_pin at 01 {
++ linux,phandle = <140001>;
++ pio-map = <
++ /* port pin dir open_drain assignment has_irq */
++ 0 3 1 0 1 0 /* TxD0 */
++ 0 4 1 0 1 0 /* TxD1 */
++ 0 5 1 0 1 0 /* TxD2 */
++ 0 6 1 0 1 0 /* TxD3 */
++ 1 6 1 0 3 0 /* TxD4 */
++ 1 7 1 0 1 0 /* TxD5 */
++ 1 9 1 0 2 0 /* TxD6 */
++ 1 a 1 0 2 0 /* TxD7 */
++ 0 9 2 0 1 0 /* RxD0 */
++ 0 a 2 0 1 0 /* RxD1 */
++ 0 b 2 0 1 0 /* RxD2 */
++ 0 c 2 0 1 0 /* RxD3 */
++ 0 d 2 0 1 0 /* RxD4 */
++ 1 1 2 0 2 0 /* RxD5 */
++ 1 0 2 0 2 0 /* RxD6 */
++ 1 4 2 0 2 0 /* RxD7 */
++ 0 7 1 0 1 0 /* TX_EN */
++ 0 8 1 0 1 0 /* TX_ER */
++ 0 f 2 0 1 0 /* RX_DV */
++ 0 10 2 0 1 0 /* RX_ER */
++ 0 0 2 0 1 0 /* RX_CLK */
++ 2 9 1 0 3 0 /* GTX_CLK - CLK10 */
++ 2 8 2 0 1 0>; /* GTX125 - CLK9 */
++ };
++
++ vii) Multi-User RAM (MURAM)
++
++ Required properties:
++ - device_type : should be "muram".
++ - mode : the could be "host" or "slave".
++ - ranges : Should be defined as specified in 1) to describe the
++ translation of MURAM addresses.
++ - data-only : sub-node which defines the address area under MURAM
++ bus that can be allocated as data/parameter
++
++ Example:
++
++ muram at 10000 {
++ device_type = "muram";
++ ranges = <0 00010000 0000c000>;
++
++ data-only at 0{
++ reg = <0 c000>;
++ };
++ };
+
+ More devices will be defined as this spec matures.
+
+diff --git a/Documentation/powerpc/eeh-pci-error-recovery.txt b/Documentation/powerpc/eeh-pci-error-recovery.txt
+index 3764dd4..4530d1b 100644
+--- a/Documentation/powerpc/eeh-pci-error-recovery.txt
++++ b/Documentation/powerpc/eeh-pci-error-recovery.txt
+@@ -90,7 +90,7 @@ EEH-isolated, there is a firmware call i
+ this is the case. If so, then the device driver should put itself
+ into a consistent state (given that it won't be able to complete any
+ pending work) and start recovery of the card. Recovery normally
+-would consist of reseting the PCI device (holding the PCI #RST
++would consist of resetting the PCI device (holding the PCI #RST
+ line high for two seconds), followed by setting up the device
+ config space (the base address registers (BAR's), latency timer,
+ cache line size, interrupt line, and so on). This is followed by a
+@@ -116,7 +116,7 @@ At this time, a generic EEH recovery mec
+ so that individual device drivers do not need to be modified to support
+ EEH recovery. This generic mechanism piggy-backs on the PCI hotplug
+ infrastructure, and percolates events up through the userspace/udev
+-infrastructure. Followiing is a detailed description of how this is
++infrastructure. Following is a detailed description of how this is
+ accomplished.
+
+ EEH must be enabled in the PHB's very early during the boot process,
+diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt
+index 1e38166..f93462c 100644
+--- a/Documentation/powerpc/hvcs.txt
++++ b/Documentation/powerpc/hvcs.txt
+@@ -259,7 +259,7 @@ This index of '2' means that in order to
+
+ It should be noted that due to the system hotplug I/O capabilities of a
+ system the /dev/hvcs* entry that interacts with a particular vty-server
+-adapter is not guarenteed to remain the same across system reboots. Look
++adapter is not guaranteed to remain the same across system reboots. Look
+ in the Q & A section for more on this issue.
+
+ ---------------------------------------------------------------------------
+diff --git a/Documentation/prio_tree.txt b/Documentation/prio_tree.txt
+index 2fbb0c4..3aa68f9 100644
+--- a/Documentation/prio_tree.txt
++++ b/Documentation/prio_tree.txt
+@@ -88,7 +88,7 @@ path which is not desirable. Hence, we d
+ heap-and-size indexed overflow-sub-trees using prio_tree->index_bits.
+ Instead the overflow sub-trees are indexed using full BITS_PER_LONG bits
+ of size_index. This may lead to skewed sub-trees because most of the
+-higher significant bits of the size_index are likely to be be 0 (zero). In
++higher significant bits of the size_index are likely to be 0 (zero). In
+ the example above, all 3 overflow-sub-trees are skewed. This may marginally
+ affect the performance. However, processes rarely map many vmas with the
+ same start_vm_pgoff but different end_vm_pgoffs. Therefore, we normally
+diff --git a/Documentation/rocket.txt b/Documentation/rocket.txt
+index a106780..1d85829 100644
+--- a/Documentation/rocket.txt
++++ b/Documentation/rocket.txt
+@@ -97,7 +97,7 @@ a range of I/O addresses for it to use.
+ requires a 68-byte contiguous block of I/O addresses, starting at one
+ of the following: 0x100h, 0x140h, 0x180h, 0x200h, 0x240h, 0x280h,
+ 0x300h, 0x340h, 0x380h. This I/O address must be reflected in the DIP
+-switiches of *all* of the Rocketport cards.
++switches of *all* of the Rocketport cards.
+
+ The second, third, and fourth RocketPort cards require a 64-byte
+ contiguous block of I/O addresses, starting at one of the following
+@@ -107,7 +107,7 @@ second, third, and fourth Rocketport car
+ software control. The DIP switch settings for the I/O address must be
+ set to the value of the first Rocketport cards.
+
+-In order to destinguish each of the card from the others, each card
++In order to distinguish each of the card from the others, each card
+ must have a unique board ID set on the dip switches. The first
+ Rocketport board must be set with the DIP switches corresponding to
+ the first board, the second board must be set with the DIP switches
+@@ -120,7 +120,7 @@ conflict with any other cards in the sys
+ RocketPort cards. Below, you will find a list of commonly used I/O
+ address ranges which may be in use by other devices in your system.
+ On a Linux system, "cat /proc/ioports" will also be helpful in
+-identifying what I/O addresses are being used by devics on your
++identifying what I/O addresses are being used by devices on your
+ system.
+
+ Remember, the FIRST RocketPort uses 68 I/O addresses. So, if you set it
+diff --git a/Documentation/rpc-cache.txt b/Documentation/rpc-cache.txt
+index 5f757c8..8a382be 100644
+--- a/Documentation/rpc-cache.txt
++++ b/Documentation/rpc-cache.txt
+@@ -24,7 +24,7 @@ The common code handles such things as:
+ - general cache lookup with correct locking
+ - supporting 'NEGATIVE' as well as positive entries
+ - allowing an EXPIRED time on cache items, and removing
+- items after they expire, and are no longe in-use.
++ items after they expire, and are no longer in-use.
+ - making requests to user-space to fill in cache entries
+ - allowing user-space to directly set entries in the cache
+ - delaying RPC requests that depend on as-yet incomplete
+@@ -53,7 +53,7 @@ Creating a Cache
+ structure
+ void cache_put(struct kref *)
+ This is called when the last reference to an item is
+- is dropped. The pointer passed is to the 'ref' field
++ dropped. The pointer passed is to the 'ref' field
+ in the cache_head. cache_put should release any
+ references create by 'cache_init' and, if CACHE_VALID
+ is set, any references created by cache_update.
+diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
+index c472ffa..4b736d2 100644
+--- a/Documentation/rt-mutex-design.txt
++++ b/Documentation/rt-mutex-design.txt
+@@ -333,11 +333,11 @@ cmpxchg is basically the following funct
+
+ unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
+ {
+- unsigned long T = *A;
+- if (*A == *B) {
+- *A = *C;
+- }
+- return T;
++ unsigned long T = *A;
++ if (*A == *B) {
++ *A = *C;
++ }
++ return T;
+ }
+ #define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
+
+@@ -582,7 +582,7 @@ contention).
+ try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
+ slow path. The first thing that is done here is an atomic setting of
+ the "Has Waiters" flag of the mutex's owner field. Yes, this could really
+-be false, because if the the mutex has no owner, there are no waiters and
++be false, because if the mutex has no owner, there are no waiters and
+ the current task also won't have any waiters. But we don't have the lock
+ yet, so we assume we are going to be a waiter. The reason for this is to
+ play nice for those architectures that do have CMPXCHG. By setting this flag
+@@ -735,7 +735,7 @@ do have CMPXCHG, that check is done in t
+ in the slow path too. If a waiter of a mutex woke up because of a signal
+ or timeout between the time the owner failed the fast path CMPXCHG check and
+ the grabbing of the wait_lock, the mutex may not have any waiters, thus the
+-owner still needs to make this check. If there are no waiters than the mutex
++owner still needs to make this check. If there are no waiters then the mutex
+ owner field is set to NULL, the wait_lock is released and nothing more is
+ needed.
+
+diff --git a/Documentation/s390/3270.txt b/Documentation/s390/3270.txt
+index 0a044e6..7a5c73a 100644
+--- a/Documentation/s390/3270.txt
++++ b/Documentation/s390/3270.txt
+@@ -111,9 +111,7 @@ Here are the installation steps in detai
+ config3270.sh. Inspect the output script it produces,
+ /tmp/mkdev3270, and then run that script. This will create the
+ necessary character special device files and make the necessary
+- changes to /etc/inittab. If you have selected DEVFS, the driver
+- itself creates the device files, and /tmp/mkdev3270 only changes
+- /etc/inittab.
++ changes to /etc/inittab.
+
+ Then notify /sbin/init that /etc/inittab has changed, by issuing
+ the telinit command with the q operand:
+diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
+index 59d1166..d684a6a 100644
+--- a/Documentation/s390/CommonIO
++++ b/Documentation/s390/CommonIO
+@@ -66,7 +66,7 @@ Command line parameters
+
+ When a device is un-ignored, device recognition and sensing is performed and
+ the device driver will be notified if possible, so the device will become
+- available to the system.
++ available to the system. Note that un-ignoring is performed asynchronously.
+
+ You can also add ranges of devices to be ignored by piping to
+ /proc/cio_ignore; "add <device range>, <device range>, ..." will ignore the
+diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
+index 844c03f..4dd25ee 100644
+--- a/Documentation/s390/Debugging390.txt
++++ b/Documentation/s390/Debugging390.txt
+@@ -8,8 +8,8 @@
+ Overview of Document:
+ =====================
+ This document is intended to give an good overview of how to debug
+-Linux for s/390 & z/Architecture it isn't intended as a complete reference & not a
+-tutorial on the fundamentals of C & assembly, it dosen't go into
++Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a
++tutorial on the fundamentals of C & assembly. It doesn't go into
+ 390 IO in any detail. It is intended to complement the documents in the
+ reference section below & any other worthwhile references you get.
+
+@@ -88,7 +88,7 @@ s/390 z/Architecture
+ 0 0 Reserved ( must be 0 ) otherwise specification exception occurs.
+
+ 1 1 Program Event Recording 1 PER enabled,
+- PER is used to facilititate debugging e.g. single stepping.
++ PER is used to facilitate debugging e.g. single stepping.
+
+ 2-4 2-4 Reserved ( must be 0 ).
+
+@@ -163,7 +163,7 @@ s/390 z/Architecture
+ 1 1 64 bit
+
+ 32 1=31 bit addressing mode 0=24 bit addressing mode (for backward
+- compatibility ), linux always runs with this bit set to 1
++ compatibility), linux always runs with this bit set to 1
+
+ 33-64 Instruction address.
+ 33-63 Reserved must be 0
+@@ -188,7 +188,7 @@ Bytes 0-512 ( 200 hex ) on s/390 & 0-512
+ are used by the processor itself for holding such information as exception indications &
+ entry points for exceptions.
+ Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture
+-( there is a gap on z/Architecure too currently between 0xc00 & 1000 which linux uses ).
++( there is a gap on z/Architecture too currently between 0xc00 & 1000 which linux uses ).
+ The closest thing to this on traditional architectures is the interrupt
+ vector table. This is a good thing & does simplify some of the kernel coding
+ however it means that we now cannot catch stray NULL pointers in the
+@@ -239,7 +239,7 @@ they go to 64 Bit.
+
+ On 390 our limitations & strengths make us slightly different.
+ For backward compatibility we are only allowed use 31 bits (2GB)
+-of our 32 bit addresses,however, we use entirely separate address
++of our 32 bit addresses, however, we use entirely separate address
+ spaces for the user & kernel.
+
+ This means we can support 2GB of non Extended RAM on s/390, & more
+@@ -317,9 +317,9 @@ Each process/thread under Linux for S390
+ defined in linux/include/linux/sched.h
+ The S390 on initialisation & resuming of a process on a cpu sets
+ the __LC_KERNEL_STACK variable in the spare prefix area for this cpu
+-( which we use for per processor globals).
++(which we use for per-processor globals).
+
+-The kernel stack pointer is intimately tied with the task stucture for
++The kernel stack pointer is intimately tied with the task structure for
+ each processor as follows.
+
+ s/390
+@@ -354,7 +354,7 @@ static inline struct task_struct * get_c
+ }
+
+ i.e. just anding the current kernel stack pointer with the mask -8192.
+-Thankfully because Linux dosen't have support for nested IO interrupts
++Thankfully because Linux doesn't have support for nested IO interrupts
+ & our devices have large buffers can survive interrupts being shut for
+ short amounts of time we don't need a separate stack for interrupts.
+
+@@ -366,8 +366,8 @@ Register Usage & Stackframes on Linux fo
+ Overview:
+ ---------
+ This is the code that gcc produces at the top & the bottom of
+-each function, it usually is fairly consistent & similar from
+-function to function & if you know its layout you can probalby
++each function. It usually is fairly consistent & similar from
++function to function & if you know its layout you can probably
+ make some headway in finding the ultimate cause of a problem
+ after a crash without a source level debugger.
+
+@@ -394,7 +394,7 @@ i.e they aren't in registers & they aren
+ back-chain:
+ This is a pointer to the stack pointer before entering a
+ framed functions ( see frameless function ) prologue got by
+-deferencing the address of the current stack pointer,
++dereferencing the address of the current stack pointer,
+ i.e. got by accessing the 32 bit value at the stack pointers
+ current location.
+
+@@ -724,7 +724,7 @@ This is useful for debugging because
+ 1) You can double check whether the files you expect to be included are the ones
+ that are being included ( e.g. double check that you aren't going to the i386 asm directory ).
+ 2) Check that macro definitions aren't clashing with typedefs,
+-3) Check that definitons aren't being used before they are being included.
++3) Check that definitions aren't being used before they are being included.
+ 4) Helps put the line emitting the error under the microscope if it contains macros.
+
+ For convenience the Linux kernel's makefile will do preprocessing automatically for you
+@@ -840,12 +840,11 @@ using the strip command to make it a mor
+
+ A source/assembly mixed dump of the kernel can be done with the line
+ objdump --source vmlinux > vmlinux.lst
+-Also if the file isn't compiled -g this will output as much debugging information
+-as it can ( e.g. function names ), however, this is very slow as it spends lots
+-of time searching for debugging info, the following self explanitory line should be used
+-instead if the code isn't compiled -g.
++Also, if the file isn't compiled -g, this will output as much debugging information
++as it can (e.g. function names). This is very slow as it spends lots
++of time searching for debugging info. The following self explanatory line should be used
++instead if the code isn't compiled -g, as it is much faster:
+ objdump --disassemble-all --syms vmlinux > vmlinux.lst
+-as it is much faster
+
+ As hard drive space is valuble most of us use the following approach.
+ 1) Look at the emitted psw on the console to find the crash address in the kernel.
+@@ -861,7 +860,7 @@ Linux source tree.
+ 6) rm /arch/s390/kernel/signal.o
+ 7) make /arch/s390/kernel/signal.o
+ 8) watch the gcc command line emitted
+-9) type it in again or alernatively cut & paste it on the console adding the -g option.
++9) type it in again or alternatively cut & paste it on the console adding the -g option.
+ 10) objdump --source arch/s390/kernel/signal.o > signal.lst
+ This will output the source & the assembly intermixed, as the snippet below shows
+ This will unfortunately output addresses which aren't the same
+@@ -913,8 +912,8 @@ If you wanted to know does ping work but
+ strace ping -c 1 127.0.0.1
+ & then look at the man pages for each of the syscalls below,
+ ( In fact this is sometimes easier than looking at some spagetti
+-source which conditionally compiles for several architectures )
+-Not everything that it throws out needs to make sense immeadiately
++source which conditionally compiles for several architectures ).
++Not everything that it throws out needs to make sense immediately.
+
+ Just looking quickly you can see that it is making up a RAW socket
+ for the ICMP protocol.
+@@ -974,8 +973,9 @@ through the pipe for each line containin
+
+ Example 3
+ ---------
+-Getting sophistocated
+-telnetd crashes on & I don't know why
++Getting sophisticated
++telnetd crashes & I don't know why
++
+ Steps
+ -----
+ 1) Replace the following line in /etc/inetd.conf
+@@ -1085,8 +1085,7 @@ Notes
+ -----
+ Addresses & values in the VM debugger are always hex never decimal
+ Address ranges are of the format <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2>
+-e.g. The address range 0x2000 to 0x3000 can be described described as
+-2000-3000 or 2000.1000
++e.g. The address range 0x2000 to 0x3000 can be described as 2000-3000 or 2000.1000
+
+ The VM Debugger is case insensitive.
+
+@@ -1311,7 +1310,7 @@ for finding out when a particular variab
+
+ An alternative way of finding the STD of a currently running process
+ is to do the following, ( this method is more complex but
+-could be quite convient if you aren't updating the kernel much &
++could be quite convenient if you aren't updating the kernel much &
+ so your kernel structures will stay constant for a reasonable period of
+ time ).
+
+@@ -1413,7 +1412,7 @@ SMP Specific commands
+ To find out how many cpus you have
+ Q CPUS displays all the CPU's available to your virtual machine
+ To find the cpu that the current cpu VM debugger commands are being directed at do
+-Q CPU to change the current cpu cpu VM debugger commands are being directed at do
++Q CPU to change the current cpu VM debugger commands are being directed at do
+ CPU <desired cpu no>
+
+ On a SMP guest issue a command to all CPUs try prefixing the command with cpu all.
+@@ -1674,8 +1673,8 @@ channel is idle & the second for device
+ concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each interrupt,
+ from which you receive an Interruption response block (IRB). If you get channel & device end
+ status in the IRB without channel checks etc. your IO probably went okay. If you didn't you
+-probably need a doctorto examine the IRB & extended status word etc.
+-If an error occurs more sophistocated control units have a facitity known as
++probably need a doctor to examine the IRB & extended status word etc.
++If an error occurs, more sophistocated control units have a facitity known as
+ concurrent sense this means that if an error occurs Extended sense information will
+ be presented in the Extended status word in the IRB if not you have to issue a
+ subsequent SENSE CCW command after the test subchannel.
+@@ -1704,7 +1703,7 @@ concentrate on data processing.
+ IOP's can use one or more links ( known as channel paths ) to talk to each
+ IO device. It first checks for path availability & chooses an available one,
+ then starts ( & sometimes terminates IO ).
+-There are two types of channel path ESCON & the Paralell IO interface.
++There are two types of channel path: ESCON & the Parallel IO interface.
+
+ IO devices are attached to control units, control units provide the
+ logic to interface the channel paths & channel path IO protocols to
+@@ -1743,11 +1742,11 @@ controllers or a control unit which conn
+
+ The 390 IO systems come in 2 flavours the current 390 machines support both
+
+-The Older 360 & 370 Interface,sometimes called the paralell I/O interface,
++The Older 360 & 370 Interface,sometimes called the Parallel I/O interface,
+ sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers
+ Interface (OEMI).
+
+-This byte wide paralell channel path/bus has parity & data on the "Bus" cable
++This byte wide Parallel channel path/bus has parity & data on the "Bus" cable
+ & control lines on the "Tag" cable. These can operate in byte multiplex mode for
+ sharing between several slow devices or burst mode & monopolize the channel for the
+ whole burst. Upto 256 devices can be addressed on one of these cables. These cables are
+@@ -1777,7 +1776,7 @@ Consoles 3270 & 3215 ( a teletype emulat
+ DASD's direct access storage devices ( otherwise known as hard disks ).
+ Tape Drives.
+ CTC ( Channel to Channel Adapters ),
+-ESCON or Paralell Cables used as a very high speed serial link
++ESCON or Parallel Cables used as a very high speed serial link
+ between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
+
+
+@@ -1803,8 +1802,8 @@ OSA 7C09 ON OSA 7C09 SUBCHANNEL = 000
+ OSA 7C14 ON OSA 7C14 SUBCHANNEL = 0002
+ OSA 7C15 ON OSA 7C15 SUBCHANNEL = 0003
+
+-If you have a guest with certain priviliges you may be able to see devices
+-which don't belong to you to avoid this do add the option V.
++If you have a guest with certain privileges you may be able to see devices
++which don't belong to you. To avoid this, add the option V.
+ e.g.
+ Q V OSA
+
+@@ -1837,7 +1836,7 @@ RDRLIST
+ RECEIVE / LOG TXT A1 ( replace
+ 8)
+ filel & press F11 to look at it
+-You should see someting like.
++You should see something like:
+
+ 00020942' SSCH B2334000 0048813C CC 0 SCH 0000 DEV 7C08
+ CPA 000FFDF0 PARM 00E2C9C4 KEY 0 FPI C0 LPM 80
+@@ -1916,7 +1915,7 @@ Assembly
+ --------
+ info registers: displays registers other than floating point.
+ info all-registers: displays floating points as well.
+-disassemble: dissassembles
++disassemble: disassembles
+ e.g.
+ disassemble without parameters will disassemble the current function
+ disassemble $pc $pc+10
+@@ -1935,7 +1934,7 @@ undisplay : undo's display's
+
+ info breakpoints: shows all current breakpoints
+
+-info stack: shows stack back trace ( if this dosent work too well, I'll show you the
++info stack: shows stack back trace ( if this doesn't work too well, I'll show you the
+ stacktrace by hand below ).
+
+ info locals: displays local variables.
+@@ -2045,13 +2044,13 @@ what gdb does when the victim receives c
+ list:
+ e.g.
+ list lists current function source
+-list 1,10 list first 10 lines of curret file.
++list 1,10 list first 10 lines of current file.
+ list test.c:1,10
+
+
+ directory:
+ Adds directories to be searched for source if gdb cannot find the source.
+-(note it is a bit sensititive about slashes )
++(note it is a bit sensititive about slashes)
+ e.g. To add the root of the filesystem to the searchpath do
+ directory //
+
+@@ -2123,9 +2122,9 @@ p/x (*(**$sp+56))&0x7fffffff
+
+ Disassembling instructions without debug info
+ ---------------------------------------------
+-gdb typically compains if there is a lack of debugging
+-symbols in the disassemble command with
+-"No function contains specified address." to get around
++gdb typically complains if there is a lack of debugging
++symbols in the disassemble command with
++"No function contains specified address." To get around
+ this do
+ x/<number lines to disassemble>xi <address>
+ e.g.
+@@ -2184,7 +2183,7 @@ ps -aux | grep gdb
+ kill -SIGSEGV <gdb's pid>
+ or alternatively use killall -SIGSEGV gdb if you have the killall command.
+ Now look at the core dump.
+-./gdb ./gdb core
++./gdb core
+ Displays the following
+ GNU gdb 4.18
+ Copyright 1998 Free Software Foundation, Inc.
+@@ -2316,7 +2315,7 @@ Showing us the shared libraries init use
+ /proc/1/mem is the current running processes memory which you
+ can read & write to like a file.
+ strace uses this sometimes as it is a bit faster than the
+-rather inefficent ptrace interface for peeking at DATA.
++rather inefficient ptrace interface for peeking at DATA.
+
+
+ cat status
+@@ -2446,7 +2445,7 @@ displays the following lines as it execu
+ + RELSTATUS=release
+ + MACHTYPE=i586-pc-linux-gnu
+
+-perl -d <scriptname> runs the perlscript in a fully intercative debugger
++perl -d <scriptname> runs the perlscript in a fully interactive debugger
+ <like gdb>.
+ Type 'h' in the debugger for help.
+
+@@ -2477,7 +2476,7 @@ Lcrash is a perfectly normal program,how
+ additional files, Kerntypes which is built using a patch to the
+ linux kernel sources in the linux root directory & the System.map.
+
+-Kerntypes is an an objectfile whose sole purpose in life
++Kerntypes is an objectfile whose sole purpose in life
+ is to provide stabs debug info to lcrash, to do this
+ Kerntypes is built from kerntypes.c which just includes the most commonly
+ referenced header files used when debugging, lcrash can then read the
+diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt
+index f0be389..32a96cc 100644
+--- a/Documentation/s390/cds.txt
++++ b/Documentation/s390/cds.txt
+@@ -133,7 +133,7 @@ determine the device driver owning the d
+ In order not to introduce a new I/O concept to the common Linux code,
+ Linux/390 preserves the IRQ concept and semantically maps the ESA/390
+ subchannels to Linux as IRQs. This allows Linux/390 to support up to 64k
+-different IRQs, uniquely representig a single device each.
++different IRQs, uniquely representing a single device each.
+
+ Up to kernel 2.4, Linux/390 used to provide interfaces via the IRQ (subchannel).
+ For internal use of the common I/O layer, these are still there. However,
+@@ -143,7 +143,7 @@ During its startup the Linux/390 system
+ of those devices is uniquely defined by a so called subchannel by the ESA/390
+ channel subsystem. While the subchannel numbers are system generated, each
+ subchannel also takes a user defined attribute, the so called device number.
+-Both subchannel number and device number can not exceed 65535. During driverfs
++Both subchannel number and device number cannot exceed 65535. During driverfs
+ initialisation, the information about control unit type and device types that
+ imply specific I/O commands (channel command words - CCWs) in order to operate
+ the device are gathered. Device drivers can retrieve this set of hardware
+@@ -174,14 +174,10 @@ read_dev_chars() - Read Device Character
+
+ This routine returns the characteristics for the device specified.
+
+-The function is meant to be called with an irq handler in place; that is,
++The function is meant to be called with the device already enabled; that is,
+ at earliest during set_online() processing.
+
+-While the request is procesed synchronously, the device interrupt
+-handler is called for final ending status. In case of error situations the
+-interrupt handler may recover appropriately. The device irq handler can
+-recognize the corresponding interrupts by the interruption parameter be
+-0x00524443.The ccw_device must not be locked prior to calling read_dev_chars().
++The ccw_device must not be locked prior to calling read_dev_chars().
+
+ The function may be called enabled or disabled.
+
+@@ -325,7 +321,7 @@ with the following CCW flags values defi
+
+ CCW_FLAG_DC - data chaining
+ CCW_FLAG_CC - command chaining
+-CCW_FLAG_SLI - suppress incorrct length
++CCW_FLAG_SLI - suppress incorrect length
+ CCW_FLAG_SKIP - skip
+ CCW_FLAG_PCI - PCI
+ CCW_FLAG_IDA - indirect addressing
+@@ -348,7 +344,7 @@ The ccw_device_start() function returns
+ not online.
+
+ When the I/O request completes, the CDS first level interrupt handler will
+-accumalate the status in a struct irb and then call the device interrupt handler.
++accumulate the status in a struct irb and then call the device interrupt handler.
+ The intparm field will contain the value the device driver has associated with a
+ particular I/O request. If a pending device status was recognized,
+ intparm will be set to 0 (zero). This may happen during I/O initiation or delayed
+@@ -410,30 +406,11 @@ individual flag meanings.
+
+ Usage Notes :
+
+-Prior to call ccw_device_start() the device driver must assure disabled state,
+-i.e. the I/O mask value in the PSW must be disabled. This can be accomplished
+-by calling local_save_flags( flags). The current PSW flags are preserved and
+-can be restored by local_irq_restore( flags) at a later time.
+-
+-If the device driver violates this rule while running in a uni-processor
+-environment an interrupt might be presented prior to the ccw_device_start()
+-routine returning to the device driver main path. In this case we will end in a
+-deadlock situation as the interrupt handler will try to obtain the irq
+-lock the device driver still owns (see below) !
+-
+-The driver must assure to hold the device specific lock. This can be
+-accomplished by
+-
+-(i) spin_lock(get_ccwdev_lock(cdev)), or
+-(ii) spin_lock_irqsave(get_ccwdev_lock(cdev), flags)
+-
+-Option (i) should be used if the calling routine is running disabled for
+-I/O interrupts (see above) already. Option (ii) obtains the device gate und
+-puts the CPU into I/O disabled state by preserving the current PSW flags.
++ccw_device_start() must be called disabled and with the ccw device lock held.
+
+ The device driver is allowed to issue the next ccw_device_start() call from
+ within its interrupt handler already. It is not required to schedule a
+-bottom-half, unless an non deterministicly long running error recovery procedure
++bottom-half, unless an non deterministically long running error recovery procedure
+ or similar needs to be scheduled. During I/O processing the Linux/390 generic
+ I/O device driver support has already obtained the IRQ lock, i.e. the handler
+ must not try to obtain it again when calling ccw_device_start() or we end in a
+@@ -488,7 +465,7 @@ int ccw_device_resume(struct ccw_device
+
+ cdev - ccw_device the resume operation is requested for
+
+-The resume_IO() function returns:
++The ccw_device_resume() function returns:
+
+ 0 - suspended channel program is resumed
+ -EBUSY - status pending
+@@ -507,6 +484,8 @@ a long-running channel program or the de
+ a halt subchannel (HSCH) I/O command. For those purposes the ccw_device_halt()
+ command is provided.
+
++ccw_device_halt() must be called disabled and with the ccw device lock held.
++
+ int ccw_device_halt(struct ccw_device *cdev,
+ unsigned long intparm);
+
+@@ -517,7 +496,7 @@ intparm : interruption parameter; value
+
+ The ccw_device_halt() function returns :
+
+- 0 - successful completion or request successfully initiated
++ 0 - request successfully initiated
+ -EBUSY - the device is currently busy, or status pending.
+ -ENODEV - cdev invalid.
+ -EINVAL - The device is not operational or the ccw device is not online.
+@@ -533,6 +512,23 @@ can then perform an appropriate action.
+ read to a network device (with or without PCI flag) a ccw_device_halt()
+ is required to end the pending operation.
+
++ccw_device_clear() - Terminage I/O Request Processing
++
++In order to terminate all I/O processing at the subchannel, the clear subchannel
++(CSCH) command is used. It can be issued via ccw_device_clear().
++
++ccw_device_clear() must be called disabled and with the ccw device lock held.
++
++int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm);
++
++cdev: ccw_device the clear operation is requested for
++intparm: interruption parameter (see ccw_device_halt())
++
++The ccw_device_clear() function returns:
++
++ 0 - request successfully initiated
++-ENODEV - cdev invalid
++-EINVAL - The device is not operational or the ccw device is not online.
+
+ Miscellaneous Support Routines
+
+diff --git a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt
+index 78a7762..29dee79 100644
+--- a/Documentation/s390/crypto/crypto-API.txt
++++ b/Documentation/s390/crypto/crypto-API.txt
+@@ -61,9 +61,9 @@ Example: z990 crypto instruction for SHA
+ -> when the sha1 algorithm is requested through the crypto API
+ (which has a module autoloader) the z990 module will be loaded.
+
+-TBD: a userspace module probin mechanism
++TBD: a userspace module probing mechanism
+ something like 'probe sha1 sha1_z990 sha1' in modprobe.conf
+- -> try module sha1_z990, if it fails to load load standard module sha1
++ -> try module sha1_z990, if it fails to load standard module sha1
+ the 'probe' statement is currently not supported in modprobe.conf
+
+
+diff --git a/Documentation/s390/driver-model.txt b/Documentation/s390/driver-model.txt
+index efb674e..77bf450 100644
+--- a/Documentation/s390/driver-model.txt
++++ b/Documentation/s390/driver-model.txt
+@@ -157,7 +157,7 @@ notify: This function is called by the c
+ * In online state, device detached (CIO_GONE) or last path gone
+ (CIO_NO_PATH). The driver must return !0 to keep the device; for
+ return code 0, the device will be deleted as usual (also when no
+- notify function is registerd). If the driver wants to keep the
++ notify function is registered). If the driver wants to keep the
+ device, it is moved into disconnected state.
+ * In disconnected state, device operational again (CIO_OPER). The
+ common I/O layer performs some sanity checks on device number and
+@@ -239,6 +239,9 @@ status - Can be 'online' or 'offline'.
+
+ type - The physical type of the channel path.
+
++shared - Whether the channel path is shared.
++
++cmg - The channel measurement group.
+
+ 3. System devices
+ -----------------
+@@ -262,7 +265,7 @@ attribute 'online' which can be 0 or 1.
+ -----------
+
+ The netiucv driver creates an attribute 'connection' under
+-bus/iucv/drivers/netiucv. Piping to this attibute creates a new netiucv
++bus/iucv/drivers/netiucv. Piping to this attribute creates a new netiucv
+ connection to the specified host.
+
+ Netiucv connections show up under devices/iucv/ as "netiucv<ifnum>". The interface
+diff --git a/Documentation/s390/monreader.txt b/Documentation/s390/monreader.txt
+index d843bb0..beeaa4b 100644
+--- a/Documentation/s390/monreader.txt
++++ b/Documentation/s390/monreader.txt
+@@ -83,7 +83,7 @@ This loads the module and sets the DCSS
+
+ NOTE:
+ -----
+-This API provides no interface to control the *MONITOR service, e.g. specifiy
++This API provides no interface to control the *MONITOR service, e.g. specify
+ which data should be collected. This can be done by the CP command MONITOR
+ (Class E privileged), see "CP Command and Utility Reference".
+
+diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt
+index e321a8e..000230c 100644
+--- a/Documentation/s390/s390dbf.txt
++++ b/Documentation/s390/s390dbf.txt
+@@ -11,7 +11,7 @@ where log records can be stored efficien
+ (e.g. device drivers) can have one separate debug log.
+ 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,
++If the system still runs but only a subcomponent which uses dbf fails,
+ 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.
+@@ -65,7 +65,7 @@ Predefined views for hex/ascii, sprintf
+ It is also possible to define other views. The content of
+ 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).
++All debug logs have an actual debug level (range from 0 to 6).
+ The default level is 3. Event and Exception functions have a 'level'
+ parameter. Only debug entries with a level that is lower or equal
+ than the actual level are written to the log. This means, when
+@@ -83,8 +83,8 @@ Example:
+ It is also possible to deactivate the debug feature globally for every
+ debug log. You can change the behavior using 2 sysctl parameters in
+ /proc/sys/s390dbf:
+-There are currently 2 possible triggers, which stop the debug feature
+-globally. The first possbility is to use the "debug_active" sysctl. If
++There are currently 2 possible triggers, which stop the debug feature
++globally. The first possibility is to use the "debug_active" sysctl. If
+ set to 1 the debug feature is running. If "debug_active" is set to 0 the
+ debug feature is turned off.
+ The second trigger which stops the debug feature is an kernel oops.
+@@ -468,7 +468,7 @@ The hex_ascii view shows the data field
+ The raw view returns a bytestream as the debug areas are stored in memory.
+
+ The sprintf view formats the debug entries in the same way as the sprintf
+-function would do. The sprintf event/expection functions write to the
++function would do. The sprintf event/exception functions write to the
+ debug entry a pointer to the format string (size = sizeof(long))
+ and for each vararg a long value. So e.g. for a debug entry with a format
+ string plus two varargs one would need to allocate a (3 * sizeof(long))
+@@ -556,7 +556,7 @@ The input_proc can be used to implement
+ 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.
++debug_dflt_header_fn() which is defined in debug.h.
+ and which produces the same header output as the predefined views.
+ E.g:
+ 00 00964419409:440761 2 - 00 88023ec
+diff --git a/Documentation/sched-coding.txt b/Documentation/sched-coding.txt
+index 2b75ef6..cbd8db7 100644
+--- a/Documentation/sched-coding.txt
++++ b/Documentation/sched-coding.txt
+@@ -15,7 +15,7 @@ Main Scheduling Methods
+ void load_balance(runqueue_t *this_rq, int idle)
+ Attempts to pull tasks from one cpu to another to balance cpu usage,
+ if needed. This method is called explicitly if the runqueues are
+- inbalanced or periodically by the timer tick. Prior to calling,
++ imbalanced or periodically by the timer tick. Prior to calling,
+ the current runqueue must be locked and interrupts disabled.
+
+ void schedule()
+diff --git a/Documentation/sched-design.txt b/Documentation/sched-design.txt
+index 9d04e7b..1605bf0 100644
+--- a/Documentation/sched-design.txt
++++ b/Documentation/sched-design.txt
+@@ -93,9 +93,9 @@ and the goal is also to add a few new th
+ Design
+ ======
+
+-the core of the new scheduler are the following mechanizms:
++The core of the new scheduler contains the following mechanisms:
+
+- - *two*, priority-ordered 'priority arrays' per CPU. There is an 'active'
++ - *two* priority-ordered 'priority arrays' per CPU. There is an 'active'
+ array and an 'expired' array. The active array contains all tasks that
+ are affine to this CPU and have timeslices left. The expired array
+ contains all tasks which have used up their timeslices - but this array
+diff --git a/Documentation/scsi/ChangeLog.1992-1997 b/Documentation/scsi/ChangeLog.1992-1997
+index dc88ee2..6faad7e 100644
+--- a/Documentation/scsi/ChangeLog.1992-1997
++++ b/Documentation/scsi/ChangeLog.1992-1997
+@@ -1214,7 +1214,7 @@ Thu Jul 21 10:37:39 1994 Eric Youngdale
+
+ * sr.c(sr_open): Do not allow opens with write access.
+
+-Mon Jul 18 09:51:22 1994 1994 Eric Youngdale (eric at esp22)
++Mon Jul 18 09:51:22 1994 Eric Youngdale (eric at esp22)
+
+ * Linux 1.1.31 released.
+
+diff --git a/Documentation/scsi/ChangeLog.arcmsr b/Documentation/scsi/ChangeLog.arcmsr
+new file mode 100644
+index 0000000..162c47f
+--- /dev/null
++++ b/Documentation/scsi/ChangeLog.arcmsr
+@@ -0,0 +1,56 @@
++**************************************************************************
++** History
++**
++** REV# DATE NAME DESCRIPTION
++** 1.00.00.00 3/31/2004 Erich Chen First release
++** 1.10.00.04 7/28/2004 Erich Chen modify for ioctl
++** 1.10.00.06 8/28/2004 Erich Chen modify for 2.6.x
++** 1.10.00.08 9/28/2004 Erich Chen modify for x86_64
++** 1.10.00.10 10/10/2004 Erich Chen bug fix for SMP & ioctl
++** 1.20.00.00 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error
++** 1.20.00.02 12/09/2004 Erich Chen bug fix with over 2T bytes RAID Volume
++** 1.20.00.04 1/09/2005 Erich Chen fits for Debian linux kernel version 2.2.xx
++** 1.20.00.05 2/20/2005 Erich Chen cleanly as look like a Linux driver at 2.6.x
++** thanks for peoples kindness comment
++** Kornel Wieliczek
++** Christoph Hellwig
++** Adrian Bunk
++** Andrew Morton
++** Christoph Hellwig
++** James Bottomley
++** Arjan van de Ven
++** 1.20.00.06 3/12/2005 Erich Chen fix with arcmsr_pci_unmap_dma "unsigned long" cast,
++** modify PCCB POOL allocated by "dma_alloc_coherent"
++** (Kornel Wieliczek's comment)
++** 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init
++** occur segmentation fault,
++** if RAID adapter does not on PCI slot
++** and modprobe/rmmod this driver twice.
++** bug fix enormous stack usage (Adrian Bunk's comment)
++** 1.20.00.08 6/23/2005 Erich Chen bug fix with abort command,
++** in case of heavy loading when sata cable
++** working on low quality connection
++** 1.20.00.09 9/12/2005 Erich Chen bug fix with abort command handling, firmware version check
++** and firmware update notify for hardware bug fix
++** 1.20.00.10 9/23/2005 Erich Chen enhance sysfs function for change driver's max tag Q number.
++** add DMA_64BIT_MASK for backward compatible with all 2.6.x
++** add some useful message for abort command
++** add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE'
++** customer can send this command for sync raid volume data
++** 1.20.00.11 9/29/2005 Erich Chen by comment of Arjan van de Ven fix incorrect msleep redefine
++** cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask
++** 1.20.00.12 9/30/2005 Erich Chen bug fix with 64bit platform's ccbs using if over 4G system memory
++** change 64bit pci_set_consistent_dma_mask into 32bit
++** increcct adapter count if adapter initialize fail.
++** miss edit at arcmsr_build_ccb....
++** psge += sizeof(struct _SG64ENTRY *) =>
++** psge += sizeof(struct _SG64ENTRY)
++** 64 bits sg entry would be incorrectly calculated
++** thanks Kornel Wieliczek give me kindly notify
++** and detail description
++** 1.20.00.13 11/15/2005 Erich Chen scheduling pending ccb with FIFO
++** change the architecture of arcmsr command queue list
++** for linux standard list
++** enable usage of pci message signal interrupt
++** follow Randy.Danlup kindness suggestion cleanup this code
++**************************************************************************
+\ No newline at end of file
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index d9e5960..5eb9275 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,4 +1,49 @@
+
++1 Release Date : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro <Sumant.Patro at lsil.com>
++2 Current Version : 00.00.03.05
++3 Older Version : 00.00.03.04
++
++i. PCI_DEVICE macro used
++
++ Convert the pci_device_id-table of the megaraid_sas-driver to the PCI_DEVICE-macro, to safe some lines.
++
++ - Henrik Kretzschmar <henne at nachtwindheim.de>
++ii. All compiler warnings removed
++iii. megasas_ctrl_info struct reverted to 3.02 release
++iv. Default value of megasas_dbg_lvl set to 0
++v. Removing in megasas_exit the sysfs entry created for megasas_dbg_lvl
++vi. In megasas_teardown_frame_pool(), cmd->frame was passed instead of
++ cmd->sense to pci_pool_free. Fixed. Bug was pointed out by
++ Eric Sesterhenn
++
++1 Release Date : Wed Sep 13 14:22:51 PDT 2006 - Sumant Patro <Sumant.Patro at lsil.com>
++2 Current Version : 00.00.03.04
++3 Older Version : 00.00.03.03
++
++i. Added Reboot notify
++ii. Reduced by 1 max cmds sent to FW from Driver to make the reply_q_sz same
++ as Max Cmds FW can support
++
++1 Release Date : Tue Aug 22 16:33:14 PDT 2006 - Sumant Patro <Sumant.Patro at lsil.com>
++2 Current Version : 00.00.03.03
++3 Older Version : 00.00.03.02
++
++i. Send stop adapter to FW & Dump pending FW cmds before declaring adapter dead.
++ New varible added to set dbg level.
++ii. Disable interrupt made as fn pointer as they are different for 1068 / 1078
++iii. Frame count optimization. Main frame can contain 2 SGE for 64 bit SGLs and
++ 3 SGE for 32 bit SGL
++iv. Tasklet added for cmd completion
++v. If FW in operational state before firing INIT, now we send RESET Flag to FW instead of just READY. This is used to do soft reset.
++vi. megasas_ctrl_prop structure updated (based on FW struct)
++vii. Added print : FW now in Ready State during initialization
++
++1 Release Date : Sun Aug 06 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro at lsil.com>
++2 Current Version : 00.00.03.02
++3 Older Version : 00.00.03.01
++
++i. Added FW tranistion state for Hotplug scenario
++
+ 1 Release Date : Sun May 14 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro at lsil.com>
+ 2 Current Version : 00.00.03.01
+ 3 Older Version : 00.00.02.04
+diff --git a/Documentation/scsi/NinjaSCSI.txt b/Documentation/scsi/NinjaSCSI.txt
+index 041780f..3229b64 100644
+--- a/Documentation/scsi/NinjaSCSI.txt
++++ b/Documentation/scsi/NinjaSCSI.txt
+@@ -24,7 +24,7 @@ SCSI device: I-O data CDPS-PX24 (CD-ROM
+ You can also use "cardctl" program (this program is in pcmcia-cs source
+ code) to get more info.
+
+-# cat /var/log/messgaes
++# cat /var/log/messages
+ ...
+ Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1
+ Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0"
+@@ -36,18 +36,18 @@ Socket 1:
+ product info: "IO DATA", "CBSC16 ", "1"
+
+
+-[2] Get Linux kernel source, and extract it to /usr/src.
+- Because NinjaSCSI driver requiers some SCSI header files in Linux kernel
+- source.
+- I recomend rebuilding your kernel. This eliminate some versioning problem.
++[2] Get the Linux kernel source, and extract it to /usr/src.
++ Because the NinjaSCSI driver requires some SCSI header files in Linux
++ kernel source, I recommend rebuilding your kernel; this eliminates
++ some versioning problems.
+ $ cd /usr/src
+ $ tar -zxvf linux-x.x.x.tar.gz
+ $ cd linux
+ $ make config
+ ...
+
+-[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory
+- and make & install. This driver requies pcmcia-cs header file.
++[3] If you use this driver with Kernel 2.2, unpack pcmcia-cs in some directory
++ and make & install. This driver requires the pcmcia-cs header file.
+ $ cd /usr/src
+ $ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz
+ ...
+@@ -59,10 +59,10 @@ $ emacs Makefile
+ ...
+ $ make
+
+-[5] Copy nsp_cs.o to suitable plase, like /lib/modules/<Kernel version>/pcmcia/ .
++[5] Copy nsp_cs.ko to suitable place, like /lib/modules/<Kernel version>/pcmcia/ .
+
+ [6] Add these lines to /etc/pcmcia/config .
+- If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file.
++ If you use pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file.
+ So, you don't need to edit file. Just copy to /etc/pcmcia/ .
+
+ -------------------------------------
+diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
+index be55670..3367130 100644
+--- a/Documentation/scsi/aacraid.txt
++++ b/Documentation/scsi/aacraid.txt
+@@ -4,45 +4,50 @@ Introduction
+ -------------------------
+ The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+ RAID controllers. This is a major rewrite from the original
+-Adaptec supplied driver. It has signficantly cleaned up both the code
++Adaptec supplied driver. It has significantly cleaned up both the code
+ and the running binary size (the module is less than half the size of
+ the original).
+
+ Supported Cards/Chipsets
+ -------------------------
+ PCI ID (pci.ids) OEM Product
+- 9005:0285:9005:028a Adaptec 2020ZCR (Skyhawk)
+- 9005:0285:9005:028e Adaptec 2020SA (Skyhawk)
+- 9005:0285:9005:028b Adaptec 2025ZCR (Terminator)
+- 9005:0285:9005:028f Adaptec 2025SA (Terminator)
+- 9005:0285:9005:0286 Adaptec 2120S (Crusader)
+- 9005:0286:9005:028d Adaptec 2130S (Lancer)
++ 9005:0283:9005:0283 Adaptec Catapult (3210S with arc firmware)
++ 9005:0284:9005:0284 Adaptec Tomcat (3410S with arc firmware)
+ 9005:0285:9005:0285 Adaptec 2200S (Vulcan)
++ 9005:0285:9005:0286 Adaptec 2120S (Crusader)
+ 9005:0285:9005:0287 Adaptec 2200S (Vulcan-2m)
++ 9005:0285:9005:0288 Adaptec 3230S (Harrier)
++ 9005:0285:9005:0289 Adaptec 3240S (Tornado)
++ 9005:0285:9005:028a Adaptec 2020ZCR (Skyhawk)
++ 9005:0285:9005:028b Adaptec 2025ZCR (Terminator)
+ 9005:0286:9005:028c Adaptec 2230S (Lancer)
+ 9005:0286:9005:028c Adaptec 2230SLP (Lancer)
+- 9005:0285:9005:0296 Adaptec 2240S (SabreExpress)
++ 9005:0286:9005:028d Adaptec 2130S (Lancer)
++ 9005:0285:9005:028e Adaptec 2020SA (Skyhawk)
++ 9005:0285:9005:028f Adaptec 2025SA (Terminator)
+ 9005:0285:9005:0290 Adaptec 2410SA (Jaguar)
+- 9005:0285:9005:0293 Adaptec 21610SA (Corsair-16)
+ 9005:0285:103c:3227 Adaptec 2610SA (Bearcat HP release)
++ 9005:0285:9005:0293 Adaptec 21610SA (Corsair-16)
++ 9005:0285:9005:0296 Adaptec 2240S (SabreExpress)
+ 9005:0285:9005:0292 Adaptec 2810SA (Corsair-8)
+ 9005:0285:9005:0294 Adaptec Prowler
+- 9005:0286:9005:029d Adaptec 2420SA (Intruder HP release)
+- 9005:0286:9005:029c Adaptec 2620SA (Intruder)
+- 9005:0286:9005:029b Adaptec 2820SA (Intruder)
+- 9005:0286:9005:02a7 Adaptec 2830SA (Skyray)
+- 9005:0286:9005:02a8 Adaptec 2430SA (Skyray)
+- 9005:0285:9005:0288 Adaptec 3230S (Harrier)
+- 9005:0285:9005:0289 Adaptec 3240S (Tornado)
+- 9005:0285:9005:0298 Adaptec 4000SAS (BlackBird)
+ 9005:0285:9005:0297 Adaptec 4005SAS (AvonPark)
++ 9005:0285:9005:0298 Adaptec 4000SAS (BlackBird)
+ 9005:0285:9005:0299 Adaptec 4800SAS (Marauder-X)
+ 9005:0285:9005:029a Adaptec 4805SAS (Marauder-E)
++ 9005:0286:9005:029b Adaptec 2820SA (Intruder)
++ 9005:0286:9005:029c Adaptec 2620SA (Intruder)
++ 9005:0286:9005:029d Adaptec 2420SA (Intruder HP release)
+ 9005:0286:9005:02a2 Adaptec 3800SAS (Hurricane44)
++ 9005:0286:9005:02a7 Adaptec 3805SAS (Hurricane80)
++ 9005:0286:9005:02a8 Adaptec 3400SAS (Hurricane40)
++ 9005:0286:9005:02ac Adaptec 1800SAS (Typhoon44)
++ 9005:0286:9005:02b3 Adaptec 2400SAS (Hurricane40lm)
++ 9005:0285:9005:02b5 Adaptec ASR5800 (Voodoo44)
++ 9005:0285:9005:02b6 Adaptec ASR5805 (Voodoo80)
++ 9005:0285:9005:02b7 Adaptec ASR5808 (Voodoo08)
+ 1011:0046:9005:0364 Adaptec 5400S (Mustang)
+ 1011:0046:9005:0365 Adaptec 5400S (Mustang)
+- 9005:0283:9005:0283 Adaptec Catapult (3210S with arc firmware)
+- 9005:0284:9005:0284 Adaptec Tomcat (3410S with arc firmware)
+ 9005:0287:9005:0800 Adaptec Themisto (Jupiter)
+ 9005:0200:9005:0200 Adaptec Themisto (Jupiter)
+ 9005:0286:9005:0800 Adaptec Callisto (Jupiter)
+@@ -64,18 +69,20 @@ Supported Cards/Chipsets
+ 9005:0285:9005:0290 IBM ServeRAID 7t (Jaguar)
+ 9005:0285:1014:02F2 IBM ServeRAID 8i (AvonPark)
+ 9005:0285:1014:0312 IBM ServeRAID 8i (AvonParkLite)
+- 9005:0286:1014:9580 IBM ServeRAID 8k/8k-l8 (Aurora)
+ 9005:0286:1014:9540 IBM ServeRAID 8k/8k-l4 (AuroraLite)
+- 9005:0286:9005:029f ICP ICP9014R0 (Lancer)
++ 9005:0286:1014:9580 IBM ServeRAID 8k/8k-l8 (Aurora)
++ 9005:0286:1014:034d IBM ServeRAID 8s (Hurricane)
+ 9005:0286:9005:029e ICP ICP9024R0 (Lancer)
++ 9005:0286:9005:029f ICP ICP9014R0 (Lancer)
+ 9005:0286:9005:02a0 ICP ICP9047MA (Lancer)
+ 9005:0286:9005:02a1 ICP ICP9087MA (Lancer)
++ 9005:0286:9005:02a3 ICP ICP5445AU (Hurricane44)
+ 9005:0286:9005:02a4 ICP ICP9085LI (Marauder-X)
+ 9005:0286:9005:02a5 ICP ICP5085BR (Marauder-E)
+- 9005:0286:9005:02a3 ICP ICP5445AU (Hurricane44)
+ 9005:0286:9005:02a6 ICP ICP9067MA (Intruder-6)
+- 9005:0286:9005:02a9 ICP ICP5087AU (Skyray)
+- 9005:0286:9005:02aa ICP ICP5047AU (Skyray)
++ 9005:0286:9005:02a9 ICP ICP5085AU (Hurricane80)
++ 9005:0286:9005:02aa ICP ICP5045AU (Hurricane40)
++ 9005:0286:9005:02b4 ICP ICP5045AL (Hurricane40lm)
+
+ People
+ -------------------------
+diff --git a/Documentation/scsi/aic79xx.txt b/Documentation/scsi/aic79xx.txt
+index 382b439..904d49e 100644
+--- a/Documentation/scsi/aic79xx.txt
++++ b/Documentation/scsi/aic79xx.txt
+@@ -81,7 +81,7 @@ The following information is available i
+ an SDTR with an offset of 0 to be sure the target
+ knows we are async. This works around a firmware defect
+ in the Quantum Atlas 10K.
+- - Implement controller susupend and resume.
++ - Implement controller suspend and resume.
+ - Clear PCI error state during driver attach so that we
+ don't disable memory mapped I/O due to a stray write
+ by some other driver probe that occurred before we
+@@ -94,7 +94,7 @@ The following information is available i
+ - Add support for scsi_report_device_reset() found in
+ 2.5.X kernels.
+ - Add 7901B support.
+- - Simplify handling of the packtized lun Rev A workaround.
++ - Simplify handling of the packetized lun Rev A workaround.
+ - Correct and simplify handling of the ignore wide residue
+ message. The previous code would fail to report a residual
+ if the transaction data length was even and we received
+diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
+index 3481fcd..9b894f1 100644
+--- a/Documentation/scsi/aic7xxx.txt
++++ b/Documentation/scsi/aic7xxx.txt
+@@ -160,7 +160,7 @@ The following information is available i
+
+ 6.2.34 (May 5th, 2003)
+ - Fix locking regression instroduced in 6.2.29 that
+- could cuase a lock order reversal between the io_request_lock
++ could cause a lock order reversal between the io_request_lock
+ and our per-softc lock. This was only possible on RH9,
+ SuSE, and kernel.org 2.4.X kernels.
+
+diff --git a/Documentation/scsi/aic7xxx_old.txt b/Documentation/scsi/aic7xxx_old.txt
+index 79e5ac6..c92f447 100644
+--- a/Documentation/scsi/aic7xxx_old.txt
++++ b/Documentation/scsi/aic7xxx_old.txt
+@@ -102,7 +102,7 @@ linux-1.1.x and fairly stable since linu
+ The hardware RAID devices sold by Adaptec are *NOT* supported by this
+ driver (and will people please stop emailing me about them, they are
+ a totally separate beast from the bare SCSI controllers and this driver
+- can not be retrofitted in any sane manner to support the hardware RAID
++ cannot be retrofitted in any sane manner to support the hardware RAID
+ features on those cards - Doug Ledford).
+
+
+@@ -241,7 +241,7 @@ linux-1.1.x and fairly stable since linu
+ that instead of dumping the register contents on the card, this
+ option dumps the contents of the sequencer program RAM. This gives
+ the ability to verify that the instructions downloaded to the
+- card's sequencer are indeed what they are suppossed to be. Again,
++ card's sequencer are indeed what they are supposed to be. Again,
+ unless you have documentation to tell you how to interpret these
+ numbers, then it is totally useless.
+
+@@ -317,7 +317,7 @@ linux-1.1.x and fairly stable since linu
+ initial DEVCONFIG values for each of your aic7xxx controllers as
+ they are listed, and also record what the machine is detecting as
+ the proper termination on your controllers. NOTE: the order in
+- which the initial DEVCONFIG values are printed out is not gauranteed
++ which the initial DEVCONFIG values are printed out is not guaranteed
+ to be the same order as the SCSI controllers are registered. The
+ above option and this option both work on the order of the SCSI
+ controllers as they are registered, so make sure you match the right
+diff --git a/Documentation/scsi/arcmsr_spec.txt b/Documentation/scsi/arcmsr_spec.txt
+new file mode 100644
+index 0000000..5e00423
+--- /dev/null
++++ b/Documentation/scsi/arcmsr_spec.txt
+@@ -0,0 +1,574 @@
++*******************************************************************************
++** ARECA FIRMWARE SPEC
++*******************************************************************************
++** Usage of IOP331 adapter
++** (All In/Out is in IOP331's view)
++** 1. Message 0 --> InitThread message and retrun code
++** 2. Doorbell is used for RS-232 emulation
++** inDoorBell : bit0 -- data in ready
++** (DRIVER DATA WRITE OK)
++** bit1 -- data out has been read
++** (DRIVER DATA READ OK)
++** outDooeBell: bit0 -- data out ready
++** (IOP331 DATA WRITE OK)
++** bit1 -- data in has been read
++** (IOP331 DATA READ OK)
++** 3. Index Memory Usage
++** offset 0xf00 : for RS232 out (request buffer)
++** offset 0xe00 : for RS232 in (scratch buffer)
++** offset 0xa00 : for inbound message code message_rwbuffer
++** (driver send to IOP331)
++** offset 0xa00 : for outbound message code message_rwbuffer
++** (IOP331 send to driver)
++** 4. RS-232 emulation
++** Currently 128 byte buffer is used
++** 1st uint32_t : Data length (1--124)
++** Byte 4--127 : Max 124 bytes of data
++** 5. PostQ
++** All SCSI Command must be sent through postQ:
++** (inbound queue port) Request frame must be 32 bytes aligned
++** #bit27--bit31 => flag for post ccb
++** #bit0--bit26 => real address (bit27--bit31) of post arcmsr_cdb
++** bit31 :
++** 0 : 256 bytes frame
++** 1 : 512 bytes frame
++** bit30 :
++** 0 : normal request
++** 1 : BIOS request
++** bit29 : reserved
++** bit28 : reserved
++** bit27 : reserved
++** ---------------------------------------------------------------------------
++** (outbount queue port) Request reply
++** #bit27--bit31
++** => flag for reply
++** #bit0--bit26
++** => real address (bit27--bit31) of reply arcmsr_cdb
++** bit31 : must be 0 (for this type of reply)
++** bit30 : reserved for BIOS handshake
++** bit29 : reserved
++** bit28 :
++** 0 : no error, ignore AdapStatus/DevStatus/SenseData
++** 1 : Error, error code in AdapStatus/DevStatus/SenseData
++** bit27 : reserved
++** 6. BIOS request
++** All BIOS request is the same with request from PostQ
++** Except :
++** Request frame is sent from configuration space
++** offset: 0x78 : Request Frame (bit30 == 1)
++** offset: 0x18 : writeonly to generate
++** IRQ to IOP331
++** Completion of request:
++** (bit30 == 0, bit28==err flag)
++** 7. Definition of SGL entry (structure)
++** 8. Message1 Out - Diag Status Code (????)
++** 9. Message0 message code :
++** 0x00 : NOP
++** 0x01 : Get Config
++** ->offset 0xa00 :for outbound message code message_rwbuffer
++** (IOP331 send to driver)
++** Signature 0x87974060(4)
++** Request len 0x00000200(4)
++** numbers of queue 0x00000100(4)
++** SDRAM Size 0x00000100(4)-->256 MB
++** IDE Channels 0x00000008(4)
++** vendor 40 bytes char
++** model 8 bytes char
++** FirmVer 16 bytes char
++** Device Map 16 bytes char
++** FirmwareVersion DWORD <== Added for checking of
++** new firmware capability
++** 0x02 : Set Config
++** ->offset 0xa00 :for inbound message code message_rwbuffer
++** (driver send to IOP331)
++** Signature 0x87974063(4)
++** UPPER32 of Request Frame (4)-->Driver Only
++** 0x03 : Reset (Abort all queued Command)
++** 0x04 : Stop Background Activity
++** 0x05 : Flush Cache
++** 0x06 : Start Background Activity
++** (re-start if background is halted)
++** 0x07 : Check If Host Command Pending
++** (Novell May Need This Function)
++** 0x08 : Set controller time
++** ->offset 0xa00 : for inbound message code message_rwbuffer
++** (driver to IOP331)
++** byte 0 : 0xaa <-- signature
++** byte 1 : 0x55 <-- signature
++** byte 2 : year (04)
++** byte 3 : month (1..12)
++** byte 4 : date (1..31)
++** byte 5 : hour (0..23)
++** byte 6 : minute (0..59)
++** byte 7 : second (0..59)
++*******************************************************************************
++*******************************************************************************
++** RS-232 Interface for Areca Raid Controller
++** The low level command interface is exclusive with VT100 terminal
++** --------------------------------------------------------------------
++** 1. Sequence of command execution
++** --------------------------------------------------------------------
++** (A) Header : 3 bytes sequence (0x5E, 0x01, 0x61)
++** (B) Command block : variable length of data including length,
++** command code, data and checksum byte
++** (C) Return data : variable length of data
++** --------------------------------------------------------------------
++** 2. Command block
++** --------------------------------------------------------------------
++** (A) 1st byte : command block length (low byte)
++** (B) 2nd byte : command block length (high byte)
++** note ..command block length shouldn't > 2040 bytes,
++** length excludes these two bytes
++** (C) 3rd byte : command code
++** (D) 4th and following bytes : variable length data bytes
++** depends on command code
++** (E) last byte : checksum byte (sum of 1st byte until last data byte)
++** --------------------------------------------------------------------
++** 3. Command code and associated data
++** --------------------------------------------------------------------
++** The following are command code defined in raid controller Command
++** code 0x10--0x1? are used for system level management,
++** no password checking is needed and should be implemented in separate
++** well controlled utility and not for end user access.
++** Command code 0x20--0x?? always check the password,
++** password must be entered to enable these command.
++** enum
++** {
++** GUI_SET_SERIAL=0x10,
++** GUI_SET_VENDOR,
++** GUI_SET_MODEL,
++** GUI_IDENTIFY,
++** GUI_CHECK_PASSWORD,
++** GUI_LOGOUT,
++** GUI_HTTP,
++** GUI_SET_ETHERNET_ADDR,
++** GUI_SET_LOGO,
++** GUI_POLL_EVENT,
++** GUI_GET_EVENT,
++** GUI_GET_HW_MONITOR,
++** // GUI_QUICK_CREATE=0x20, (function removed)
++** GUI_GET_INFO_R=0x20,
++** GUI_GET_INFO_V,
++** GUI_GET_INFO_P,
++** GUI_GET_INFO_S,
++** GUI_CLEAR_EVENT,
++** GUI_MUTE_BEEPER=0x30,
++** GUI_BEEPER_SETTING,
++** GUI_SET_PASSWORD,
++** GUI_HOST_INTERFACE_MODE,
++** GUI_REBUILD_PRIORITY,
++** GUI_MAX_ATA_MODE,
++** GUI_RESET_CONTROLLER,
++** GUI_COM_PORT_SETTING,
++** GUI_NO_OPERATION,
++** GUI_DHCP_IP,
++** GUI_CREATE_PASS_THROUGH=0x40,
++** GUI_MODIFY_PASS_THROUGH,
++** GUI_DELETE_PASS_THROUGH,
++** GUI_IDENTIFY_DEVICE,
++** GUI_CREATE_RAIDSET=0x50,
++** GUI_DELETE_RAIDSET,
++** GUI_EXPAND_RAIDSET,
++** GUI_ACTIVATE_RAIDSET,
++** GUI_CREATE_HOT_SPARE,
++** GUI_DELETE_HOT_SPARE,
++** GUI_CREATE_VOLUME=0x60,
++** GUI_MODIFY_VOLUME,
++** GUI_DELETE_VOLUME,
++** GUI_START_CHECK_VOLUME,
++** GUI_STOP_CHECK_VOLUME
++** };
++** Command description :
++** GUI_SET_SERIAL : Set the controller serial#
++** byte 0,1 : length
++** byte 2 : command code 0x10
++** byte 3 : password length (should be 0x0f)
++** byte 4-0x13 : should be "ArEcATecHnoLogY"
++** byte 0x14--0x23 : Serial number string (must be 16 bytes)
++** GUI_SET_VENDOR : Set vendor string for the controller
++** byte 0,1 : length
++** byte 2 : command code 0x11
++** byte 3 : password length (should be 0x08)
++** byte 4-0x13 : should be "ArEcAvAr"
++** byte 0x14--0x3B : vendor string (must be 40 bytes)
++** GUI_SET_MODEL : Set the model name of the controller
++** byte 0,1 : length
++** byte 2 : command code 0x12
++** byte 3 : password length (should be 0x08)
++** byte 4-0x13 : should be "ArEcAvAr"
++** byte 0x14--0x1B : model string (must be 8 bytes)
++** GUI_IDENTIFY : Identify device
++** byte 0,1 : length
++** byte 2 : command code 0x13
++** return "Areca RAID Subsystem "
++** GUI_CHECK_PASSWORD : Verify password
++** byte 0,1 : length
++** byte 2 : command code 0x14
++** byte 3 : password length
++** byte 4-0x?? : user password to be checked
++** GUI_LOGOUT : Logout GUI (force password checking on next command)
++** byte 0,1 : length
++** byte 2 : command code 0x15
++** GUI_HTTP : HTTP interface (reserved for Http proxy service)(0x16)
++**
++** GUI_SET_ETHERNET_ADDR : Set the ethernet MAC address
++** byte 0,1 : length
++** byte 2 : command code 0x17
++** byte 3 : password length (should be 0x08)
++** byte 4-0x13 : should be "ArEcAvAr"
++** byte 0x14--0x19 : Ethernet MAC address (must be 6 bytes)
++** GUI_SET_LOGO : Set logo in HTTP
++** byte 0,1 : length
++** byte 2 : command code 0x18
++** byte 3 : Page# (0/1/2/3) (0xff --> clear OEM logo)
++** byte 4/5/6/7 : 0x55/0xaa/0xa5/0x5a
++** byte 8 : TITLE.JPG data (each page must be 2000 bytes)
++** note page0 1st 2 byte must be
++** actual length of the JPG file
++** GUI_POLL_EVENT : Poll If Event Log Changed
++** byte 0,1 : length
++** byte 2 : command code 0x19
++** GUI_GET_EVENT : Read Event
++** byte 0,1 : length
++** byte 2 : command code 0x1a
++** byte 3 : Event Page (0:1st page/1/2/3:last page)
++** GUI_GET_HW_MONITOR : Get HW monitor data
++** byte 0,1 : length
++** byte 2 : command code 0x1b
++** byte 3 : # of FANs(example 2)
++** byte 4 : # of Voltage sensor(example 3)
++** byte 5 : # of temperature sensor(example 2)
++** byte 6 : # of power
++** byte 7/8 : Fan#0 (RPM)
++** byte 9/10 : Fan#1
++** byte 11/12 : Voltage#0 original value in *1000
++** byte 13/14 : Voltage#0 value
++** byte 15/16 : Voltage#1 org
++** byte 17/18 : Voltage#1
++** byte 19/20 : Voltage#2 org
++** byte 21/22 : Voltage#2
++** byte 23 : Temp#0
++** byte 24 : Temp#1
++** byte 25 : Power indicator (bit0 : power#0,
++** bit1 : power#1)
++** byte 26 : UPS indicator
++** GUI_QUICK_CREATE : Quick create raid/volume set
++** byte 0,1 : length
++** byte 2 : command code 0x20
++** byte 3/4/5/6 : raw capacity
++** byte 7 : raid level
++** byte 8 : stripe size
++** byte 9 : spare
++** byte 10/11/12/13: device mask (the devices to create raid/volume)
++** This function is removed, application like
++** to implement quick create function
++** need to use GUI_CREATE_RAIDSET and GUI_CREATE_VOLUMESET function.
++** GUI_GET_INFO_R : Get Raid Set Information
++** byte 0,1 : length
++** byte 2 : command code 0x20
++** byte 3 : raidset#
++** typedef struct sGUI_RAIDSET
++** {
++** BYTE grsRaidSetName[16];
++** DWORD grsCapacity;
++** DWORD grsCapacityX;
++** DWORD grsFailMask;
++** BYTE grsDevArray[32];
++** BYTE grsMemberDevices;
++** BYTE grsNewMemberDevices;
++** BYTE grsRaidState;
++** BYTE grsVolumes;
++** BYTE grsVolumeList[16];
++** BYTE grsRes1;
++** BYTE grsRes2;
++** BYTE grsRes3;
++** BYTE grsFreeSegments;
++** DWORD grsRawStripes[8];
++** DWORD grsRes4;
++** DWORD grsRes5; // Total to 128 bytes
++** DWORD grsRes6; // Total to 128 bytes
++** } sGUI_RAIDSET, *pGUI_RAIDSET;
++** GUI_GET_INFO_V : Get Volume Set Information
++** byte 0,1 : length
++** byte 2 : command code 0x21
++** byte 3 : volumeset#
++** typedef struct sGUI_VOLUMESET
++** {
++** BYTE gvsVolumeName[16]; // 16
++** DWORD gvsCapacity;
++** DWORD gvsCapacityX;
++** DWORD gvsFailMask;
++** DWORD gvsStripeSize;
++** DWORD gvsNewFailMask;
++** DWORD gvsNewStripeSize;
++** DWORD gvsVolumeStatus;
++** DWORD gvsProgress; // 32
++** sSCSI_ATTR gvsScsi;
++** BYTE gvsMemberDisks;
++** BYTE gvsRaidLevel; // 8
++** BYTE gvsNewMemberDisks;
++** BYTE gvsNewRaidLevel;
++** BYTE gvsRaidSetNumber;
++** BYTE gvsRes0; // 4
++** BYTE gvsRes1[4]; // 64 bytes
++** } sGUI_VOLUMESET, *pGUI_VOLUMESET;
++** GUI_GET_INFO_P : Get Physical Drive Information
++** byte 0,1 : length
++** byte 2 : command code 0x22
++** byte 3 : drive # (from 0 to max-channels - 1)
++** typedef struct sGUI_PHY_DRV
++** {
++** BYTE gpdModelName[40];
++** BYTE gpdSerialNumber[20];
++** BYTE gpdFirmRev[8];
++** DWORD gpdCapacity;
++** DWORD gpdCapacityX; // Reserved for expansion
++** BYTE gpdDeviceState;
++** BYTE gpdPioMode;
++** BYTE gpdCurrentUdmaMode;
++** BYTE gpdUdmaMode;
++** BYTE gpdDriveSelect;
++** BYTE gpdRaidNumber; // 0xff if not belongs to a raid set
++** sSCSI_ATTR gpdScsi;
++** BYTE gpdReserved[40]; // Total to 128 bytes
++** } sGUI_PHY_DRV, *pGUI_PHY_DRV;
++** GUI_GET_INFO_S : Get System Information
++** byte 0,1 : length
++** byte 2 : command code 0x23
++** typedef struct sCOM_ATTR
++** {
++** BYTE comBaudRate;
++** BYTE comDataBits;
++** BYTE comStopBits;
++** BYTE comParity;
++** BYTE comFlowControl;
++** } sCOM_ATTR, *pCOM_ATTR;
++** typedef struct sSYSTEM_INFO
++** {
++** BYTE gsiVendorName[40];
++** BYTE gsiSerialNumber[16];
++** BYTE gsiFirmVersion[16];
++** BYTE gsiBootVersion[16];
++** BYTE gsiMbVersion[16];
++** BYTE gsiModelName[8];
++** BYTE gsiLocalIp[4];
++** BYTE gsiCurrentIp[4];
++** DWORD gsiTimeTick;
++** DWORD gsiCpuSpeed;
++** DWORD gsiICache;
++** DWORD gsiDCache;
++** DWORD gsiScache;
++** DWORD gsiMemorySize;
++** DWORD gsiMemorySpeed;
++** DWORD gsiEvents;
++** BYTE gsiMacAddress[6];
++** BYTE gsiDhcp;
++** BYTE gsiBeeper;
++** BYTE gsiChannelUsage;
++** BYTE gsiMaxAtaMode;
++** BYTE gsiSdramEcc; // 1:if ECC enabled
++** BYTE gsiRebuildPriority;
++** sCOM_ATTR gsiComA; // 5 bytes
++** sCOM_ATTR gsiComB; // 5 bytes
++** BYTE gsiIdeChannels;
++** BYTE gsiScsiHostChannels;
++** BYTE gsiIdeHostChannels;
++** BYTE gsiMaxVolumeSet;
++** BYTE gsiMaxRaidSet;
++** BYTE gsiEtherPort; // 1:if ether net port supported
++** BYTE gsiRaid6Engine; // 1:Raid6 engine supported
++** BYTE gsiRes[75];
++** } sSYSTEM_INFO, *pSYSTEM_INFO;
++** GUI_CLEAR_EVENT : Clear System Event
++** byte 0,1 : length
++** byte 2 : command code 0x24
++** GUI_MUTE_BEEPER : Mute current beeper
++** byte 0,1 : length
++** byte 2 : command code 0x30
++** GUI_BEEPER_SETTING : Disable beeper
++** byte 0,1 : length
++** byte 2 : command code 0x31
++** byte 3 : 0->disable, 1->enable
++** GUI_SET_PASSWORD : Change password
++** byte 0,1 : length
++** byte 2 : command code 0x32
++** byte 3 : pass word length ( must <= 15 )
++** byte 4 : password (must be alpha-numerical)
++** GUI_HOST_INTERFACE_MODE : Set host interface mode
++** byte 0,1 : length
++** byte 2 : command code 0x33
++** byte 3 : 0->Independent, 1->cluster
++** GUI_REBUILD_PRIORITY : Set rebuild priority
++** byte 0,1 : length
++** byte 2 : command code 0x34
++** byte 3 : 0/1/2/3 (low->high)
++** GUI_MAX_ATA_MODE : Set maximum ATA mode to be used
++** byte 0,1 : length
++** byte 2 : command code 0x35
++** byte 3 : 0/1/2/3 (133/100/66/33)
++** GUI_RESET_CONTROLLER : Reset Controller
++** byte 0,1 : length
++** byte 2 : command code 0x36
++** *Response with VT100 screen (discard it)
++** GUI_COM_PORT_SETTING : COM port setting
++** byte 0,1 : length
++** byte 2 : command code 0x37
++** byte 3 : 0->COMA (term port),
++** 1->COMB (debug port)
++** byte 4 : 0/1/2/3/4/5/6/7
++** (1200/2400/4800/9600/19200/38400/57600/115200)
++** byte 5 : data bit
++** (0:7 bit, 1:8 bit : must be 8 bit)
++** byte 6 : stop bit (0:1, 1:2 stop bits)
++** byte 7 : parity (0:none, 1:off, 2:even)
++** byte 8 : flow control
++** (0:none, 1:xon/xoff, 2:hardware => must use none)
++** GUI_NO_OPERATION : No operation
++** byte 0,1 : length
++** byte 2 : command code 0x38
++** GUI_DHCP_IP : Set DHCP option and local IP address
++** byte 0,1 : length
++** byte 2 : command code 0x39
++** byte 3 : 0:dhcp disabled, 1:dhcp enabled
++** byte 4/5/6/7 : IP address
++** GUI_CREATE_PASS_THROUGH : Create pass through disk
++** byte 0,1 : length
++** byte 2 : command code 0x40
++** byte 3 : device #
++** byte 4 : scsi channel (0/1)
++** byte 5 : scsi id (0-->15)
++** byte 6 : scsi lun (0-->7)
++** byte 7 : tagged queue (1 : enabled)
++** byte 8 : cache mode (1 : enabled)
++** byte 9 : max speed (0/1/2/3/4,
++** async/20/40/80/160 for scsi)
++** (0/1/2/3/4, 33/66/100/133/150 for ide )
++** GUI_MODIFY_PASS_THROUGH : Modify pass through disk
++** byte 0,1 : length
++** byte 2 : command code 0x41
++** byte 3 : device #
++** byte 4 : scsi channel (0/1)
++** byte 5 : scsi id (0-->15)
++** byte 6 : scsi lun (0-->7)
++** byte 7 : tagged queue (1 : enabled)
++** byte 8 : cache mode (1 : enabled)
++** byte 9 : max speed (0/1/2/3/4,
++** async/20/40/80/160 for scsi)
++** (0/1/2/3/4, 33/66/100/133/150 for ide )
++** GUI_DELETE_PASS_THROUGH : Delete pass through disk
++** byte 0,1 : length
++** byte 2 : command code 0x42
++** byte 3 : device# to be deleted
++** GUI_IDENTIFY_DEVICE : Identify Device
++** byte 0,1 : length
++** byte 2 : command code 0x43
++** byte 3 : Flash Method
++** (0:flash selected, 1:flash not selected)
++** byte 4/5/6/7 : IDE device mask to be flashed
++** note .... no response data available
++** GUI_CREATE_RAIDSET : Create Raid Set
++** byte 0,1 : length
++** byte 2 : command code 0x50
++** byte 3/4/5/6 : device mask
++** byte 7-22 : raidset name (if byte 7 == 0:use default)
++** GUI_DELETE_RAIDSET : Delete Raid Set
++** byte 0,1 : length
++** byte 2 : command code 0x51
++** byte 3 : raidset#
++** GUI_EXPAND_RAIDSET : Expand Raid Set
++** byte 0,1 : length
++** byte 2 : command code 0x52
++** byte 3 : raidset#
++** byte 4/5/6/7 : device mask for expansion
++** byte 8/9/10 : (8:0 no change, 1 change, 0xff:terminate,
++** 9:new raid level,
++** 10:new stripe size
++** 0/1/2/3/4/5->4/8/16/32/64/128K )
++** byte 11/12/13 : repeat for each volume in the raidset
++** GUI_ACTIVATE_RAIDSET : Activate incomplete raid set
++** byte 0,1 : length
++** byte 2 : command code 0x53
++** byte 3 : raidset#
++** GUI_CREATE_HOT_SPARE : Create hot spare disk
++** byte 0,1 : length
++** byte 2 : command code 0x54
++** byte 3/4/5/6 : device mask for hot spare creation
++** GUI_DELETE_HOT_SPARE : Delete hot spare disk
++** byte 0,1 : length
++** byte 2 : command code 0x55
++** byte 3/4/5/6 : device mask for hot spare deletion
++** GUI_CREATE_VOLUME : Create volume set
++** byte 0,1 : length
++** byte 2 : command code 0x60
++** byte 3 : raidset#
++** byte 4-19 : volume set name
++** (if byte4 == 0, use default)
++** byte 20-27 : volume capacity (blocks)
++** byte 28 : raid level
++** byte 29 : stripe size
++** (0/1/2/3/4/5->4/8/16/32/64/128K)
++** byte 30 : channel
++** byte 31 : ID
++** byte 32 : LUN
++** byte 33 : 1 enable tag
++** byte 34 : 1 enable cache
++** byte 35 : speed
++** (0/1/2/3/4->async/20/40/80/160 for scsi)
++** (0/1/2/3/4->33/66/100/133/150 for IDE )
++** byte 36 : 1 to select quick init
++**
++** GUI_MODIFY_VOLUME : Modify volume Set
++** byte 0,1 : length
++** byte 2 : command code 0x61
++** byte 3 : volumeset#
++** byte 4-19 : new volume set name
++** (if byte4 == 0, not change)
++** byte 20-27 : new volume capacity (reserved)
++** byte 28 : new raid level
++** byte 29 : new stripe size
++** (0/1/2/3/4/5->4/8/16/32/64/128K)
++** byte 30 : new channel
++** byte 31 : new ID
++** byte 32 : new LUN
++** byte 33 : 1 enable tag
++** byte 34 : 1 enable cache
++** byte 35 : speed
++** (0/1/2/3/4->async/20/40/80/160 for scsi)
++** (0/1/2/3/4->33/66/100/133/150 for IDE )
++** GUI_DELETE_VOLUME : Delete volume set
++** byte 0,1 : length
++** byte 2 : command code 0x62
++** byte 3 : volumeset#
++** GUI_START_CHECK_VOLUME : Start volume consistency check
++** byte 0,1 : length
++** byte 2 : command code 0x63
++** byte 3 : volumeset#
++** GUI_STOP_CHECK_VOLUME : Stop volume consistency check
++** byte 0,1 : length
++** byte 2 : command code 0x64
++** ---------------------------------------------------------------------
++** 4. Returned data
++** ---------------------------------------------------------------------
++** (A) Header : 3 bytes sequence (0x5E, 0x01, 0x61)
++** (B) Length : 2 bytes
++** (low byte 1st, excludes length and checksum byte)
++** (C) status or data :
++** <1> If length == 1 ==> 1 byte status code
++** #define GUI_OK 0x41
++** #define GUI_RAIDSET_NOT_NORMAL 0x42
++** #define GUI_VOLUMESET_NOT_NORMAL 0x43
++** #define GUI_NO_RAIDSET 0x44
++** #define GUI_NO_VOLUMESET 0x45
++** #define GUI_NO_PHYSICAL_DRIVE 0x46
++** #define GUI_PARAMETER_ERROR 0x47
++** #define GUI_UNSUPPORTED_COMMAND 0x48
++** #define GUI_DISK_CONFIG_CHANGED 0x49
++** #define GUI_INVALID_PASSWORD 0x4a
++** #define GUI_NO_DISK_SPACE 0x4b
++** #define GUI_CHECKSUM_ERROR 0x4c
++** #define GUI_PASSWORD_REQUIRED 0x4d
++** <2> If length > 1 ==>
++** data block returned from controller
++** and the contents depends on the command code
++** (E) Checksum : checksum of length and status or data byte
++**************************************************************************
+diff --git a/Documentation/scsi/dc395x.txt b/Documentation/scsi/dc395x.txt
+index ae3b79a..88219f9 100644
+--- a/Documentation/scsi/dc395x.txt
++++ b/Documentation/scsi/dc395x.txt
+@@ -20,7 +20,7 @@ Parameters
+ ----------
+ The driver uses the settings from the EEPROM set in the SCSI BIOS
+ setup. If there is no EEPROM, the driver uses default values.
+-Both can be overriden by command line parameters (module or kernel
++Both can be overridden by command line parameters (module or kernel
+ parameters).
+
+ The following parameters are available:
+diff --git a/Documentation/scsi/dpti.txt b/Documentation/scsi/dpti.txt
+index 6e45e70..f36dc0e 100644
+--- a/Documentation/scsi/dpti.txt
++++ b/Documentation/scsi/dpti.txt
+@@ -48,7 +48,7 @@
+ * Implemented suggestions from Alan Cox
+ * Added calculation of resid for sg layer
+ * Better error handling
+- * Added checking underflow condtions
++ * Added checking underflow conditions
+ * Added DATAPROTECT checking
+ * Changed error return codes
+ * Fixed pointer bug in bus reset routine
+diff --git a/Documentation/scsi/ibmmca.txt b/Documentation/scsi/ibmmca.txt
+index d16ce5b..35f6b8e 100644
+--- a/Documentation/scsi/ibmmca.txt
++++ b/Documentation/scsi/ibmmca.txt
+@@ -229,7 +229,7 @@
+
+ In a second step of the driver development, the following improvement has
+ been applied: The first approach limited the number of devices to 7, far
+- fewer than the 15 that it could usem then it just maped ldn ->
++ fewer than the 15 that it could use, then it just mapped ldn ->
+ (ldn/8,ldn%8) for pun,lun. We ended up with a real mishmash of puns
+ and luns, but it all seemed to work.
+
+@@ -254,12 +254,12 @@
+ device to be existant, but it has no ldn assigned, it gets a ldn out of 7
+ to 14. The numbers are assigned in cyclic order. Therefore it takes 8
+ dynamical reassignments on the SCSI-devices, until a certain device
+- loses its ldn again. This assures, that dynamical remapping is avoided
++ loses its ldn again. This assures that dynamical remapping is avoided
+ during intense I/O between up to 15 SCSI-devices (means pun,lun
+- combinations). A further advantage of this method is, that people who
++ combinations). A further advantage of this method is that people who
+ build their kernel without probing on all luns will get what they expect,
+ because the driver just won't assign everything with lun>0 when
+- multpile lun probing is inactive.
++ multiple lun probing is inactive.
+
+ 2.4 SCSI-Device Order
+ ---------------------
+@@ -309,9 +309,9 @@
+ 2.6 Abort & Reset Commands
+ --------------------------
+ These are implemented with busy waiting for interrupt to arrive.
+- ibmmca_reset() and ibmmca_abort() do not work sufficently well
+- up to now and need still a lot of development work. But, this seems
+- to be even a problem with other SCSI-low level drivers, too. However,
++ ibmmca_reset() and ibmmca_abort() do not work sufficiently well
++ up to now and need still a lot of development work. This seems
++ to be a problem with other low-level SCSI drivers too, however
+ this should be no excuse.
+
+ 2.7 Disk Geometry
+@@ -684,8 +684,8 @@
+ not like sending commands to non-existing SCSI-devices and will react
+ with a command error as a sign of protest. While this error is not
+ present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI
+- Adapters. Therefore, I implemented a workarround to forgive those
+- adapters their protests, but it is marked up in the statisctis, so
++ Adapters. Therefore, I implemented a workaround to forgive those
++ adapters their protests, but it is marked up in the statistics, so
+ after a successful boot, you can see in /proc/scsi/ibmmca/<host_number>
+ how often the command errors have been forgiven to the SCSI-subsystem.
+ If the number is bigger than 0, you have a SCSI subsystem of older
+@@ -778,15 +778,15 @@
+ not accept this, as they stick quite near to ANSI-SCSI and report
+ a COMMAND_ERROR message which causes the driver to panic. The main
+ problem was located around the INQUIRY command. Now, for all the
+- mentioned commands, the buffersize, sent to the adapter is at
++ mentioned commands, the buffersize sent to the adapter is at
+ maximum 255 which seems to be a quite reasonable solution.
+- TEST_UNIT_READY gets a buffersize of 0 to make sure, that no
++ TEST_UNIT_READY gets a buffersize of 0 to make sure that no
+ data is transferred in order to avoid any possible command failure.
+- 2) On unsuccessful TEST_UNIT_READY, the midlevel-driver has to send
+- a REQUEST_SENSE in order to see, where the problem is located. This
++ 2) On unsuccessful TEST_UNIT_READY, the mid-level driver has to send
++ a REQUEST_SENSE in order to see where the problem is located. This
+ REQUEST_SENSE may have various length in its answer-buffer. IBM
+- SCSI-subsystems report a command failure, if the returned buffersize
+- is different from the sent buffersize, but this can be supressed by
++ SCSI-subsystems report a command failure if the returned buffersize
++ is different from the sent buffersize, but this can be suppressed by
+ a special bit, which is now done and problems seem to be solved.
+ 2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on
+ 2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes.
+@@ -1086,7 +1086,7 @@
+
+ Q: "Reset SCSI-devices at boottime" halts the system at boottime, why?
+ A: This is only tested with the IBM SCSI Adapter w/cache. It is not
+- yet prooved to run on other adapters, however you may be lucky.
++ yet proven to run on other adapters, however you may be lucky.
+ In version 3.1d this has been hugely improved and should work better,
+ now. Normally you really won't need to activate this flag in the
+ kernel configuration, as all post 1989 SCSI-devices should accept
+@@ -1104,7 +1104,7 @@
+ The parameter 'normal' sets the new industry standard, starting
+ from pun 0, scanning up to pun 6. This allows you to change your
+ opinion still after having already compiled the kernel.
+- Q: Why I cannot find the IBM MCA SCSI support in the config menue?
++ Q: Why can't I find IBM MCA SCSI support in the config menu?
+ A: You have to activate MCA bus support, first.
+ Q: Where can I find the latest info about this driver?
+ A: See the file MAINTAINERS for the current WWW-address, which offers
+@@ -1156,7 +1156,7 @@
+ Guide) what has to be done for reset, we still share the bad shape of
+ the reset functions with all other low level SCSI-drivers.
+ Astonishingly, reset works in most cases quite ok, but the harddisks
+- won't run in synchonous mode anymore after a reset, until you reboot.
++ won't run in synchronous mode anymore after a reset, until you reboot.
+ Q: Why does my XXX w/Cache adapter not use read-prefetch?
+ A: Ok, that is not completely possible. If a cache is present, the
+ adapter tries to use it internally. Explicitly, one can use the cache
+diff --git a/Documentation/scsi/libsas.txt b/Documentation/scsi/libsas.txt
+new file mode 100644
+index 0000000..9e2078b
+--- /dev/null
++++ b/Documentation/scsi/libsas.txt
+@@ -0,0 +1,484 @@
++SAS Layer
++---------
++
++The SAS Layer is a management infrastructure which manages
++SAS LLDDs. It sits between SCSI Core and SAS LLDDs. The
++layout is as follows: while SCSI Core is concerned with
++SAM/SPC issues, and a SAS LLDD+sequencer is concerned with
++phy/OOB/link management, the SAS layer is concerned with:
++
++ * SAS Phy/Port/HA event management (LLDD generates,
++ SAS Layer processes),
++ * SAS Port management (creation/destruction),
++ * SAS Domain discovery and revalidation,
++ * SAS Domain device management,
++ * SCSI Host registration/unregistration,
++ * Device registration with SCSI Core (SAS) or libata
++ (SATA), and
++ * Expander management and exporting expander control
++ to user space.
++
++A SAS LLDD is a PCI device driver. It is concerned with
++phy/OOB management, and vendor specific tasks and generates
++events to the SAS layer.
++
++The SAS Layer does most SAS tasks as outlined in the SAS 1.1
++spec.
++
++The sas_ha_struct describes the SAS LLDD to the SAS layer.
++Most of it is used by the SAS Layer but a few fields need to
++be initialized by the LLDDs.
++
++After initializing your hardware, from the probe() function
++you call sas_register_ha(). It will register your LLDD with
++the SCSI subsystem, creating a SCSI host and it will
++register your SAS driver with the sysfs SAS tree it creates.
++It will then return. Then you enable your phys to actually
++start OOB (at which point your driver will start calling the
++notify_* event callbacks).
++
++Structure descriptions:
++
++struct sas_phy --------------------
++Normally this is statically embedded to your driver's
++phy structure:
++ struct my_phy {
++ blah;
++ struct sas_phy sas_phy;
++ bleh;
++ };
++And then all the phys are an array of my_phy in your HA
++struct (shown below).
++
++Then as you go along and initialize your phys you also
++initialize the sas_phy struct, along with your own
++phy structure.
++
++In general, the phys are managed by the LLDD and the ports
++are managed by the SAS layer. So the phys are initialized
++and updated by the LLDD and the ports are initialized and
++updated by the SAS layer.
++
++There is a scheme where the LLDD can RW certain fields,
++and the SAS layer can only read such ones, and vice versa.
++The idea is to avoid unnecessary locking.
++
++enabled -- must be set (0/1)
++id -- must be set [0,MAX_PHYS)
++class, proto, type, role, oob_mode, linkrate -- must be set
++oob_mode -- you set this when OOB has finished and then notify
++the SAS Layer.
++
++sas_addr -- this normally points to an array holding the sas
++address of the phy, possibly somewhere in your my_phy
++struct.
++
++attached_sas_addr -- set this when you (LLDD) receive an
++IDENTIFY frame or a FIS frame, _before_ notifying the SAS
++layer. The idea is that sometimes the LLDD may want to fake
++or provide a different SAS address on that phy/port and this
++allows it to do this. At best you should copy the sas
++address from the IDENTIFY frame or maybe generate a SAS
++address for SATA directly attached devices. The Discover
++process may later change this.
++
++frame_rcvd -- this is where you copy the IDENTIFY/FIS frame
++when you get it; you lock, copy, set frame_rcvd_size and
++unlock the lock, and then call the event. It is a pointer
++since there's no way to know your hw frame size _exactly_,
++so you define the actual array in your phy struct and let
++this pointer point to it. You copy the frame from your
++DMAable memory to that area holding the lock.
++
++sas_prim -- this is where primitives go when they're
++received. See sas.h. Grab the lock, set the primitive,
++release the lock, notify.
++
++port -- this points to the sas_port if the phy belongs
++to a port -- the LLDD only reads this. It points to the
++sas_port this phy is part of. Set by the SAS Layer.
++
++ha -- may be set; the SAS layer sets it anyway.
++
++lldd_phy -- you should set this to point to your phy so you
++can find your way around faster when the SAS layer calls one
++of your callbacks and passes you a phy. If the sas_phy is
++embedded you can also use container_of -- whatever you
++prefer.
++
++
++struct sas_port --------------------
++The LLDD doesn't set any fields of this struct -- it only
++reads them. They should be self explanatory.
++
++phy_mask is 32 bit, this should be enough for now, as I
++haven't heard of a HA having more than 8 phys.
++
++lldd_port -- I haven't found use for that -- maybe other
++LLDD who wish to have internal port representation can make
++use of this.
++
++
++struct sas_ha_struct --------------------
++It normally is statically declared in your own LLDD
++structure describing your adapter:
++struct my_sas_ha {
++ blah;
++ struct sas_ha_struct sas_ha;
++ struct my_phy phys[MAX_PHYS];
++ struct sas_port sas_ports[MAX_PHYS]; /* (1) */
++ bleh;
++};
++
++(1) If your LLDD doesn't have its own port representation.
++
++What needs to be initialized (sample function given below).
++
++pcidev
++sas_addr -- since the SAS layer doesn't want to mess with
++ memory allocation, etc, this points to statically
++ allocated array somewhere (say in your host adapter
++ structure) and holds the SAS address of the host
++ adapter as given by you or the manufacturer, etc.
++sas_port
++sas_phy -- an array of pointers to structures. (see
++ note above on sas_addr).
++ These must be set. See more notes below.
++num_phys -- the number of phys present in the sas_phy array,
++ and the number of ports present in the sas_port
++ array. There can be a maximum num_phys ports (one per
++ port) so we drop the num_ports, and only use
++ num_phys.
++
++The event interface:
++
++ /* LLDD calls these to notify the class of an event. */
++ void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
++ void (*notify_port_event)(struct sas_phy *, enum port_event);
++ void (*notify_phy_event)(struct sas_phy *, enum phy_event);
++
++When sas_register_ha() returns, those are set and can be
++called by the LLDD to notify the SAS layer of such events
++the SAS layer.
++
++The port notification:
++
++ /* The class calls these to notify the LLDD of an event. */
++ void (*lldd_port_formed)(struct sas_phy *);
++ void (*lldd_port_deformed)(struct sas_phy *);
++
++If the LLDD wants notification when a port has been formed
++or deformed it sets those to a function satisfying the type.
++
++A SAS LLDD should also implement at least one of the Task
++Management Functions (TMFs) described in SAM:
++
++ /* Task Management Functions. Must be called from process context. */
++ int (*lldd_abort_task)(struct sas_task *);
++ int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
++ int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
++ int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
++ int (*lldd_I_T_nexus_reset)(struct domain_device *);
++ int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
++ int (*lldd_query_task)(struct sas_task *);
++
++For more information please read SAM from T10.org.
++
++Port and Adapter management:
++
++ /* Port and Adapter management */
++ int (*lldd_clear_nexus_port)(struct sas_port *);
++ int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
++
++A SAS LLDD should implement at least one of those.
++
++Phy management:
++
++ /* Phy management */
++ int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
++
++lldd_ha -- set this to point to your HA struct. You can also
++use container_of if you embedded it as shown above.
++
++A sample initialization and registration function
++can look like this (called last thing from probe())
++*but* before you enable the phys to do OOB:
++
++static int register_sas_ha(struct my_sas_ha *my_ha)
++{
++ int i;
++ static struct sas_phy *sas_phys[MAX_PHYS];
++ static struct sas_port *sas_ports[MAX_PHYS];
++
++ my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0];
++
++ for (i = 0; i < MAX_PHYS; i++) {
++ sas_phys[i] = &my_ha->phys[i].sas_phy;
++ sas_ports[i] = &my_ha->sas_ports[i];
++ }
++
++ my_ha->sas_ha.sas_phy = sas_phys;
++ my_ha->sas_ha.sas_port = sas_ports;
++ my_ha->sas_ha.num_phys = MAX_PHYS;
++
++ my_ha->sas_ha.lldd_port_formed = my_port_formed;
++
++ my_ha->sas_ha.lldd_dev_found = my_dev_found;
++ my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
++
++ my_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; (1)
++
++ my_ha->sas_ha.lldd_queue_size = ha_can_queue;
++ my_ha->sas_ha.lldd_execute_task = my_execute_task;
++
++ my_ha->sas_ha.lldd_abort_task = my_abort_task;
++ my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set;
++ my_ha->sas_ha.lldd_clear_aca = my_clear_aca;
++ my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set;
++ my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2)
++ my_ha->sas_ha.lldd_lu_reset = my_lu_reset;
++ my_ha->sas_ha.lldd_query_task = my_query_task;
++
++ my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port;
++ my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha;
++
++ my_ha->sas_ha.lldd_control_phy = my_control_phy;
++
++ return sas_register_ha(&my_ha->sas_ha);
++}
++
++(1) This is normally a LLDD parameter, something of the
++lines of a task collector. What it tells the SAS Layer is
++whether the SAS layer should run in Direct Mode (default:
++value 0 or 1) or Task Collector Mode (value greater than 1).
++
++In Direct Mode, the SAS Layer calls Execute Task as soon as
++it has a command to send to the SDS, _and_ this is a single
++command, i.e. not linked.
++
++Some hardware (e.g. aic94xx) has the capability to DMA more
++than one task at a time (interrupt) from host memory. Task
++Collector Mode is an optional feature for HAs which support
++this in their hardware. (Again, it is completely optional
++even if your hardware supports it.)
++
++In Task Collector Mode, the SAS Layer would do _natural_
++coalescing of tasks and at the appropriate moment it would
++call your driver to DMA more than one task in a single HA
++interrupt. DMBS may want to use this by insmod/modprobe
++setting the lldd_max_execute_num to something greater than
++1.
++
++(2) SAS 1.1 does not define I_T Nexus Reset TMF.
++
++Events
++------
++
++Events are _the only way_ a SAS LLDD notifies the SAS layer
++of anything. There is no other method or way a LLDD to tell
++the SAS layer of anything happening internally or in the SAS
++domain.
++
++Phy events:
++ PHYE_LOSS_OF_SIGNAL, (C)
++ PHYE_OOB_DONE,
++ PHYE_OOB_ERROR, (C)
++ PHYE_SPINUP_HOLD.
++
++Port events, passed on a _phy_:
++ PORTE_BYTES_DMAED, (M)
++ PORTE_BROADCAST_RCVD, (E)
++ PORTE_LINK_RESET_ERR, (C)
++ PORTE_TIMER_EVENT, (C)
++ PORTE_HARD_RESET.
++
++Host Adapter event:
++ HAE_RESET
++
++A SAS LLDD should be able to generate
++ - at least one event from group C (choice),
++ - events marked M (mandatory) are mandatory (only one),
++ - events marked E (expander) if it wants the SAS layer
++ to handle domain revalidation (only one such).
++ - Unmarked events are optional.
++
++Meaning:
++
++HAE_RESET -- when your HA got internal error and was reset.
++
++PORTE_BYTES_DMAED -- on receiving an IDENTIFY/FIS frame
++PORTE_BROADCAST_RCVD -- on receiving a primitive
++PORTE_LINK_RESET_ERR -- timer expired, loss of signal, loss
++of DWS, etc. (*)
++PORTE_TIMER_EVENT -- DWS reset timeout timer expired (*)
++PORTE_HARD_RESET -- Hard Reset primitive received.
++
++PHYE_LOSS_OF_SIGNAL -- the device is gone (*)
++PHYE_OOB_DONE -- OOB went fine and oob_mode is valid
++PHYE_OOB_ERROR -- Error while doing OOB, the device probably
++got disconnected. (*)
++PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent.
++
++(*) should set/clear the appropriate fields in the phy,
++ or alternatively call the inlined sas_phy_disconnected()
++ which is just a helper, from their tasklet.
++
++The Execute Command SCSI RPC:
++
++ int (*lldd_execute_task)(struct sas_task *, int num,
++ unsigned long gfp_flags);
++
++Used to queue a task to the SAS LLDD. @task is the tasks to
++be executed. @num should be the number of tasks being
++queued at this function call (they are linked listed via
++task::list), @gfp_mask should be the gfp_mask defining the
++context of the caller.
++
++This function should implement the Execute Command SCSI RPC,
++or if you're sending a SCSI Task as linked commands, you
++should also use this function.
++
++That is, when lldd_execute_task() is called, the command(s)
++go out on the transport *immediately*. There is *no*
++queuing of any sort and at any level in a SAS LLDD.
++
++The use of task::list is two-fold, one for linked commands,
++the other discussed below.
++
++It is possible to queue up more than one task at a time, by
++initializing the list element of struct sas_task, and
++passing the number of tasks enlisted in this manner in num.
++
++Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued;
++ 0, the task(s) were queued.
++
++If you want to pass num > 1, then either
++A) you're the only caller of this function and keep track
++ of what you've queued to the LLDD, or
++B) you know what you're doing and have a strategy of
++ retrying.
++
++As opposed to queuing one task at a time (function call),
++batch queuing of tasks, by having num > 1, greatly
++simplifies LLDD code, sequencer code, and _hardware design_,
++and has some performance advantages in certain situations
++(DBMS).
++
++The LLDD advertises if it can take more than one command at
++a time at lldd_execute_task(), by setting the
++lldd_max_execute_num parameter (controlled by "collector"
++module parameter in aic94xx SAS LLDD).
++
++You should leave this to the default 1, unless you know what
++you're doing.
++
++This is a function of the LLDD, to which the SAS layer can
++cater to.
++
++int lldd_queue_size
++ The host adapter's queue size. This is the maximum
++number of commands the lldd can have pending to domain
++devices on behalf of all upper layers submitting through
++lldd_execute_task().
++
++You really want to set this to something (much) larger than
++1.
++
++This _really_ has absolutely nothing to do with queuing.
++There is no queuing in SAS LLDDs.
++
++struct sas_task {
++ dev -- the device this task is destined to
++ list -- must be initialized (INIT_LIST_HEAD)
++ task_proto -- _one_ of enum sas_proto
++ scatter -- pointer to scatter gather list array
++ num_scatter -- number of elements in scatter
++ total_xfer_len -- total number of bytes expected to be transfered
++ data_dir -- PCI_DMA_...
++ task_done -- callback when the task has finished execution
++};
++
++When an external entity, entity other than the LLDD or the
++SAS Layer, wants to work with a struct domain_device, it
++_must_ call kobject_get() when getting a handle on the
++device and kobject_put() when it is done with the device.
++
++This does two things:
++ A) implements proper kfree() for the device;
++ B) increments/decrements the kref for all players:
++ domain_device
++ all domain_device's ... (if past an expander)
++ port
++ host adapter
++ pci device
++ and up the ladder, etc.
++
++DISCOVERY
++---------
++
++The sysfs tree has the following purposes:
++ a) It shows you the physical layout of the SAS domain at
++ the current time, i.e. how the domain looks in the
++ physical world right now.
++ b) Shows some device parameters _at_discovery_time_.
++
++This is a link to the tree(1) program, very useful in
++viewing the SAS domain:
++ftp://mama.indstate.edu/linux/tree/
++I expect user space applications to actually create a
++graphical interface of this.
++
++That is, the sysfs domain tree doesn't show or keep state if
++you e.g., change the meaning of the READY LED MEANING
++setting, but it does show you the current connection status
++of the domain device.
++
++Keeping internal device state changes is responsibility of
++upper layers (Command set drivers) and user space.
++
++When a device or devices are unplugged from the domain, this
++is reflected in the sysfs tree immediately, and the device(s)
++removed from the system.
++
++The structure domain_device describes any device in the SAS
++domain. It is completely managed by the SAS layer. A task
++points to a domain device, this is how the SAS LLDD knows
++where to send the task(s) to. A SAS LLDD only reads the
++contents of the domain_device structure, but it never creates
++or destroys one.
++
++Expander management from User Space
++-----------------------------------
++
++In each expander directory in sysfs, there is a file called
++"smp_portal". It is a binary sysfs attribute file, which
++implements an SMP portal (Note: this is *NOT* an SMP port),
++to which user space applications can send SMP requests and
++receive SMP responses.
++
++Functionality is deceptively simple:
++
++1. Build the SMP frame you want to send. The format and layout
++ is described in the SAS spec. Leave the CRC field equal 0.
++open(2)
++2. Open the expander's SMP portal sysfs file in RW mode.
++write(2)
++3. Write the frame you built in 1.
++read(2)
++4. Read the amount of data you expect to receive for the frame you built.
++ If you receive different amount of data you expected to receive,
++ then there was some kind of error.
++close(2)
++All this process is shown in detail in the function do_smp_func()
++and its callers, in the file "expander_conf.c".
++
++The kernel functionality is implemented in the file
++"sas_expander.c".
++
++The program "expander_conf.c" implements this. It takes one
++argument, the sysfs file name of the SMP portal to the
++expander, and gives expander information, including routing
++tables.
++
++The SMP portal gives you complete control of the expander,
++so please be careful.
+diff --git a/Documentation/scsi/megaraid.txt b/Documentation/scsi/megaraid.txt
+index ff864c0..3c7cea5 100644
+--- a/Documentation/scsi/megaraid.txt
++++ b/Documentation/scsi/megaraid.txt
+@@ -4,11 +4,11 @@
+ Overview:
+ --------
+
+-Different classes of controllers from LSI Logic, accept and respond to the
++Different classes of controllers from LSI Logic accept and respond to the
+ user applications in a similar way. They understand the same firmware control
+ commands. Furthermore, the applications also can treat different classes of
+ the controllers uniformly. Hence it is logical to have a single module that
+-interefaces with the applications on one side and all the low level drivers
++interfaces with the applications on one side and all the low level drivers
+ on the other.
+
+ The advantages, though obvious, are listed for completeness:
+diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt
+index 822d2ac..58ad8db 100644
+--- a/Documentation/scsi/ncr53c8xx.txt
++++ b/Documentation/scsi/ncr53c8xx.txt
+@@ -70,7 +70,7 @@ Written by Gerard Roudier <groudier at free
+ 15. SCSI problem troubleshooting
+ 15.1 Problem tracking
+ 15.2 Understanding hardware error reports
+-16. Synchonous transfer negotiation tables
++16. Synchronous transfer negotiation tables
+ 16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
+ 16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
+ 17. Serial NVRAM support (by Richard Waltham)
+@@ -96,10 +96,10 @@ The original driver has been written for
+ It is now available as a bundle of 2 drivers:
+
+ - ncr53c8xx generic driver that supports all the SYM53C8XX family including
+- the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
++ the earliest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
+ the new 895A (1 channel LVD SCSI controller).
+ - sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest
+- chips in order to gain advantage of new features, as LOAD/STORE intructions
++ chips in order to gain advantage of new features, as LOAD/STORE instructions
+ available since the 810A and hardware phase mismatch available with the
+ 896 and the 895A.
+
+@@ -207,7 +207,7 @@ The 896 and the 895A allows handling of
+ SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor
+ until the C code has saved the context of the transfer).
+ Implementing this without using LOAD/STORE instructions would be painfull
+-and I did'nt even want to try it.
++and I didn't even want to try it.
+
+ The 896 chip supports 64 bit PCI transactions and addressing, while the
+ 895A supports 32 bit PCI transactions and 64 bit addressing.
+@@ -631,8 +631,8 @@ string variable using 'insmod'.
+
+ A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the
+ driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects
+-an optionnal list of integers separated with comma followed by an optional
+-list of comma-separated strings. Example of boot setup command under lilo
++an optional list of integers separated with comma followed by an optional
++list of comma-separated strings. Example of boot setup command under lilo
+ prompt:
+
+ lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
+@@ -778,7 +778,7 @@ port address 0x1400.
+ Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
+ If you have connected a wide device with a 50 pins to 68 pins cable
+ converter, any accepted wide negotiation will break further data transfers.
+- In such a case, using "wide:0" in the bootup command will be helpfull.
++ In such a case, using "wide:0" in the bootup command will be helpful.
+
+ 10.2.14 Differential mode
+ diff:0 never set up diff mode
+@@ -899,7 +899,7 @@ boot setup can be:
+ ncr53c8xx=safe:y,mpar:y
+ ncr53c8xx=safe:y
+
+-My personnal system works flawlessly with the following equivalent setup:
++My personal system works flawlessly with the following equivalent setup:
+
+ ncr53c8xx=mpar:y,spar:y,disc:y,specf:1,fsn:n,ultra:2,fsn:n,revprob:n,verb:1\
+ tags:32,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0
+@@ -1151,7 +1151,7 @@ Driver files:
+
+ New driver versions are made available separately in order to allow testing
+ changes and new features prior to including them into the linux kernel
+-distribution. The following URL provides informations on latest avalaible
++distribution. The following URL provides information on latest available
+ patches:
+
+ ftp://ftp.tux.org/pub/people/gerard-roudier/README
+@@ -1382,7 +1382,7 @@ SCSI standards, chip cores functionnals
+ You are not required to decode and understand them, unless you want to help
+ maintain the driver code.
+
+-16. Synchonous transfer negotiation tables
++16. Synchronous transfer negotiation tables
+
+ Tables below have been created by calling the routine the driver uses
+ for synchronisation negotiation timing calculation and chip setting.
+diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt
+index ce574e7..f536907 100644
+--- a/Documentation/scsi/osst.txt
++++ b/Documentation/scsi/osst.txt
+@@ -56,8 +56,7 @@ Compile your kernel and install the modu
+
+ Now, your osst driver is inside the kernel or available as a module,
+ depending on your choice during kernel config. You may still need to create
+-the device nodes by calling the Makedevs.sh script (see below) manually,
+-unless you use a devfs kernel, where this won't be needed.
++the device nodes by calling the Makedevs.sh script (see below) manually.
+
+ To load your module, you may use the command
+ modprobe osst
+diff --git a/Documentation/scsi/ppa.txt b/Documentation/scsi/ppa.txt
+index 5d9223b..067ac39 100644
+--- a/Documentation/scsi/ppa.txt
++++ b/Documentation/scsi/ppa.txt
+@@ -3,7 +3,7 @@
+ General Iomega ZIP drive page for Linux:
+ http://www.torque.net/~campbell/
+
+-Driver achive for old drivers:
++Driver archive for old drivers:
+ http://www.torque.net/~campbell/ppa/
+
+ Linux Parport page (parallel port)
+diff --git a/Documentation/scsi/scsi-changer.txt b/Documentation/scsi/scsi-changer.txt
+index c132687..d74bbd2 100644
+--- a/Documentation/scsi/scsi-changer.txt
++++ b/Documentation/scsi/scsi-changer.txt
+@@ -31,7 +31,7 @@ changers. But it allows to handle nearly
+ media transport - this one shuffles around the media, i.e. the
+ transport arm. Also known as "picker".
+ storage - a slot which can hold a media.
+- import/export - the same as above, but is accessable from outside,
++ import/export - the same as above, but is accessible from outside,
+ i.e. there the operator (you !) can use this to
+ fill in and remove media from the changer.
+ Sometimes named "mailslot".
+diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt
+index ce767b9..b964eef 100644
+--- a/Documentation/scsi/scsi_eh.txt
++++ b/Documentation/scsi/scsi_eh.txt
+@@ -160,7 +160,7 @@ ways.
+ - Fine-grained EH callbacks
+ LLDD can implement fine-grained EH callbacks and let SCSI
+ midlayer drive error handling and call appropriate callbacks.
+- This will be dicussed further in [2-1].
++ This will be discussed further in [2-1].
+
+ - eh_strategy_handler() callback
+ This is one big callback which should perform whole error
+@@ -194,7 +194,7 @@ lower layers and lower layers are ready
+ again.
+
+ To achieve these goals, EH performs recovery actions with increasing
+-severity. Some actions are performed by issueing SCSI commands and
++severity. Some actions are performed by issuing SCSI commands and
+ others are performed by invoking one of the following fine-grained
+ hostt EH callbacks. Callbacks may be omitted and omitted ones are
+ considered to fail always.
+diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
+index 20e30cf..5ff65b1 100644
+--- a/Documentation/scsi/st.txt
++++ b/Documentation/scsi/st.txt
+@@ -249,7 +249,7 @@ BOOT TIME CONFIGURATION
+
+ If the driver is compiled into the kernel, the same parameters can be
+ also set using, e.g., the LILO command line. The preferred syntax is
+-is to use the same keyword used when loading as module but prepended
++to use the same keyword used when loading as module but prepended
+ with 'st.'. For instance, to set the maximum number of scatter/gather
+ segments, the parameter 'st.max_sg_segs=xx' should be used (xx is the
+ number of scatter/gather segments).
+@@ -369,7 +369,7 @@ MTSETDRVBUFFER
+ the device dependent address. It is recommended to set
+ this flag unless there are tapes using the device
+ dependent (from the old times) (global)
+- MT_ST_SYSV sets the SYSV sematics (mode)
++ MT_ST_SYSV sets the SYSV semantics (mode)
+ MT_ST_NOWAIT enables immediate mode (i.e., don't wait for
+ the command to finish) for some commands (e.g., rewind)
+ MT_ST_DEBUGGING debugging (global; debugging must be
+diff --git a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt
+index 7f516cd..26c8a08 100644
+--- a/Documentation/scsi/sym53c8xx_2.txt
++++ b/Documentation/scsi/sym53c8xx_2.txt
+@@ -67,7 +67,7 @@ under Linux is contained in 2 files name
+ Other drivers files are intended not to depend on the Operating System
+ on which the driver is used.
+
+-The history of this driver can be summerized as follows:
++The history of this driver can be summarized as follows:
+
+ 1993: ncr driver written for 386bsd and FreeBSD by:
+ Wolfgang Stanglmeier <wolf at cologne.de>
+@@ -684,7 +684,7 @@ Field H : SCNTL3 Scsi Control Register 3
+ Contains the setting of timing values for both asynchronous and
+ synchronous data transfers.
+ Field I : SCNTL4 Scsi Control Register 4
+- Only meaninful for 53C1010 Ultra3 controllers.
++ Only meaningful for 53C1010 Ultra3 controllers.
+
+ Understanding Fields J, K, L and dumps requires to have good knowledge of
+ SCSI standards, chip cores functionnals and internal driver data structures.
+diff --git a/Documentation/scsi/tmscsim.txt b/Documentation/scsi/tmscsim.txt
+index df7a02b..8b2168a 100644
+--- a/Documentation/scsi/tmscsim.txt
++++ b/Documentation/scsi/tmscsim.txt
+@@ -27,7 +27,7 @@ Tekram DC390(T) adapter. This is where t
+ scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
+ (NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
+ tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more,
+-as the ncr53c8xx is perfectly supporting these adpaters since some time.
++as the ncr53c8xx is perfectly supporting these adapters since some time.
+
+ The driver first appeared in April 1996, exclusively supported the DC390
+ and has been enhanced since then in various steps. In May 1998 support for
+@@ -381,7 +381,7 @@ Please see http://www.garloff.de/kurt/li
+ replaced by the dev index of your scanner). You may try to reset your SCSI
+ bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?).
+ The problem seems to be solved as of 2.0d18, thanks to Andreas Rick.
+-* If there is a valid partition table, the driver will use it for determing
++* If there is a valid partition table, the driver will use it for determining
+ the mapping. If there's none, a reasonable mapping (Symbios-like) will be
+ assumed. Other operating systems may not like this mapping, though
+ it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
+diff --git a/Documentation/seclvl.txt b/Documentation/seclvl.txt
+deleted file mode 100644
+index 97274d1..0000000
+--- a/Documentation/seclvl.txt
++++ /dev/null
+@@ -1,97 +0,0 @@
+-BSD Secure Levels Linux Security Module
+-Michael A. Halcrow <mike at halcrow.us>
+-
+-
+-Introduction
+-
+-Under the BSD Secure Levels security model, sets of policies are
+-associated with levels. Levels range from -1 to 2, with -1 being the
+-weakest and 2 being the strongest. These security policies are
+-enforced at the kernel level, so not even the superuser is able to
+-disable or circumvent them. This hardens the machine against attackers
+-who gain root access to the system.
+-
+-
+-Levels and Policies
+-
+-Level -1 (Permanently Insecure):
+- - Cannot increase the secure level
+-
+-Level 0 (Insecure):
+- - Cannot ptrace the init process
+-
+-Level 1 (Default):
+- - /dev/mem and /dev/kmem are read-only
+- - IMMUTABLE and APPEND extended attributes, if set, may not be unset
+- - Cannot load or unload kernel modules
+- - Cannot write directly to a mounted block device
+- - Cannot perform raw I/O operations
+- - Cannot perform network administrative tasks
+- - Cannot setuid any file
+-
+-Level 2 (Secure):
+- - Cannot decrement the system time
+- - Cannot write to any block device, whether mounted or not
+- - Cannot unmount any mounted filesystems
+-
+-
+-Compilation
+-
+-To compile the BSD Secure Levels LSM, seclvl.ko, enable the
+-SECURITY_SECLVL configuration option. This is found under Security
+-options -> BSD Secure Levels in the kernel configuration menu.
+-
+-
+-Basic Usage
+-
+-Once the machine is in a running state, with all the necessary modules
+-loaded and all the filesystems mounted, you can load the seclvl.ko
+-module:
+-
+-# insmod seclvl.ko
+-
+-The module defaults to secure level 1, except when compiled directly
+-into the kernel, in which case it defaults to secure level 0. To raise
+-the secure level to 2, the administrator writes ``2'' to the
+-seclvl/seclvl file under the sysfs mount point (assumed to be /sys in
+-these examples):
+-
+-# echo -n "2" > /sys/seclvl/seclvl
+-
+-Alternatively, you can initialize the module at secure level 2 with
+-the initlvl module parameter:
+-
+-# insmod seclvl.ko initlvl=2
+-
+-At this point, it is impossible to remove the module or reduce the
+-secure level. If the administrator wishes to have the option of doing
+-so, he must provide a module parameter, sha1_passwd, that specifies
+-the SHA1 hash of the password that can be used to reduce the secure
+-level to 0.
+-
+-To generate this SHA1 hash, the administrator can use OpenSSL:
+-
+-# echo -n "boogabooga" | openssl sha1
+-abeda4e0f33defa51741217592bf595efb8d289c
+-
+-In order to use password-instigated secure level reduction, the SHA1
+-crypto module must be loaded or compiled into the kernel:
+-
+-# insmod sha1.ko
+-
+-The administrator can then insmod the seclvl module, including the
+-SHA1 hash of the password:
+-
+-# insmod seclvl.ko
+- sha1_passwd=abeda4e0f33defa51741217592bf595efb8d289c
+-
+-To reduce the secure level, write the password to seclvl/passwd under
+-your sysfs mount point:
+-
+-# echo -n "boogabooga" > /sys/seclvl/passwd
+-
+-The September 2004 edition of Sys Admin Magazine has an article about
+-the BSD Secure Levels LSM. I encourage you to refer to that article
+-for a more in-depth treatment of this security module:
+-
+-http://www.samag.com/documents/s=9304/sam0409a/0409a.htm
+diff --git a/Documentation/sh/kgdb.txt b/Documentation/sh/kgdb.txt
+index 5b04f7f..05b4ba8 100644
+--- a/Documentation/sh/kgdb.txt
++++ b/Documentation/sh/kgdb.txt
+@@ -69,7 +69,7 @@ might specify the halt option:
+
+ kgdb=halt
+
+-Boot the TARGET machinem, which will appear to hang.
++Boot the TARGET machine, which will appear to hang.
+
+ On your DEVELOPMENT machine, cd to the source directory and run the gdb
+ program. (This is likely to be a cross GDB which runs on your host but
+diff --git a/Documentation/sh/new-machine.txt b/Documentation/sh/new-machine.txt
+index eb2dd2e..73988e0 100644
+--- a/Documentation/sh/new-machine.txt
++++ b/Documentation/sh/new-machine.txt
+@@ -41,11 +41,6 @@ Board-specific code:
+ |
+ .. more boards here ...
+
+-It should also be noted that each board is required to have some certain
+-headers. At the time of this writing, io.h is the only thing that needs
+-to be provided for each board, and can generally just reference generic
+-functions (with the exception of isa_port2addr).
+-
+ Next, for companion chips:
+ .
+ `-- arch
+@@ -104,12 +99,13 @@ and then populate that with sub-director
+ Both the Solution Engine and the hp6xx boards are an example of this.
+
+ After you have setup your new arch/sh/boards/ directory, remember that you
+-also must add a directory in include/asm-sh for headers localized to this
+-board. In order to interoperate seamlessly with the build system, it's best
+-to have this directory the same as the arch/sh/boards/ directory name,
+-though if your board is again part of a family, the build system has ways
+-of dealing with this, and you can feel free to name the directory after
+-the family member itself.
++should also add a directory in include/asm-sh for headers localized to this
++board (if there are going to be more than one). In order to interoperate
++seamlessly with the build system, it's best to have this directory the same
++as the arch/sh/boards/ directory name, though if your board is again part of
++a family, the build system has ways of dealing with this (via incdir-y
++overloading), and you can feel free to name the directory after the family
++member itself.
+
+ There are a few things that each board is required to have, both in the
+ arch/sh/boards and the include/asm-sh/ heirarchy. In order to better
+@@ -122,6 +118,7 @@ might look something like:
+ * arch/sh/boards/vapor/setup.c - Setup code for imaginary board
+ */
+ #include <linux/init.h>
++#include <asm/rtc.h> /* for board_time_init() */
+
+ const char *get_system_type(void)
+ {
+@@ -152,79 +149,57 @@ int __init platform_setup(void)
+ }
+
+ Our new imaginary board will also have to tie into the machvec in order for it
+-to be of any use. Currently the machvec is slowly on its way out, but is still
+-required for the time being. As such, let us take a look at what needs to be
+-done for the machvec assignment.
++to be of any use.
+
+ machvec functions fall into a number of categories:
+
+ - I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
+- - I/O remapping functions (ioremap etc)
+- - some initialisation functions
+- - a 'heartbeat' function
+- - some miscellaneous flags
+-
+-The tree can be built in two ways:
+- - as a fully generic build. All drivers are linked in, and all functions
+- go through the machvec
+- - as a machine specific build. In this case only the required drivers
+- will be linked in, and some macros may be redefined to not go through
+- the machvec where performance is important (in particular IO functions).
+-
+-There are three ways in which IO can be performed:
+- - none at all. This is really only useful for the 'unknown' machine type,
+- which us designed to run on a machine about which we know nothing, and
+- so all all IO instructions do nothing.
+- - fully custom. In this case all IO functions go to a machine specific
+- set of functions which can do what they like
+- - a generic set of functions. These will cope with most situations,
+- and rely on a single function, mv_port2addr, which is called through the
+- machine vector, and converts an IO address into a memory address, which
+- can be read from/written to directly.
+-
+-Thus adding a new machine involves the following steps (I will assume I am
+-adding a machine called vapor):
+-
+- - add a new file include/asm-sh/vapor/io.h which contains prototypes for
++ - I/O mapping functions (ioport_map, ioport_unmap, etc).
++ - a 'heartbeat' function.
++ - PCI and IRQ initialization routines.
++ - Consistent allocators (for boards that need special allocators,
++ particularly for allocating out of some board-specific SRAM for DMA
++ handles).
++
++There are machvec functions added and removed over time, so always be sure to
++consult include/asm-sh/machvec.h for the current state of the machvec.
++
++The kernel will automatically wrap in generic routines for undefined function
++pointers in the machvec at boot time, as machvec functions are referenced
++unconditionally throughout most of the tree. Some boards have incredibly
++sparse machvecs (such as the dreamcast and sh03), whereas others must define
++virtually everything (rts7751r2d).
++
++Adding a new machine is relatively trivial (using vapor as an example):
++
++If the board-specific definitions are quite minimalistic, as is the case for
++the vast majority of boards, simply having a single board-specific header is
++sufficient.
++
++ - add a new file include/asm-sh/vapor.h which contains prototypes for
+ any machine specific IO functions prefixed with the machine name, for
+ example vapor_inb. These will be needed when filling out the machine
+ vector.
+
+- This is the minimum that is required, however there are ample
+- opportunities to optimise this. In particular, by making the prototypes
+- inline function definitions, it is possible to inline the function when
+- building machine specific versions. Note that the machine vector
+- functions will still be needed, so that a module built for a generic
+- setup can be loaded.
+-
+- - add a new file arch/sh/boards/vapor/mach.c. This contains the definition
+- of the machine vector. When building the machine specific version, this
+- will be the real machine vector (via an alias), while in the generic
+- version is used to initialise the machine vector, and then freed, by
+- making it initdata. This should be defined as:
+-
+- struct sh_machine_vector mv_vapor __initmv = {
+- .mv_name = "vapor",
+- }
+- ALIAS_MV(vapor)
+-
+- - finally add a file arch/sh/boards/vapor/io.c, which contains
+- definitions of the machine specific io functions.
+-
+-A note about initialisation functions. Three initialisation functions are
+-provided in the machine vector:
+- - mv_arch_init - called very early on from setup_arch
+- - mv_init_irq - called from init_IRQ, after the generic SH interrupt
+- initialisation
+- - mv_init_pci - currently not used
+-
+-Any other remaining functions which need to be called at start up can be
+-added to the list using the __initcalls macro (or module_init if the code
+-can be built as a module). Many generic drivers probe to see if the device
+-they are targeting is present, however this may not always be appropriate,
+-so a flag can be added to the machine vector which will be set on those
+-machines which have the hardware in question, reducing the probe to a
+-single conditional.
++ Note that these prototypes are generated automatically by setting
++ __IO_PREFIX to something sensible. A typical example would be:
++
++ #define __IO_PREFIX vapor
++ #include <asm/io_generic.h>
++
++ somewhere in the board-specific header. Any boards being ported that still
++ have a legacy io.h should remove it entirely and switch to the new model.
++
++ - Add machine vector definitions to the board's setup.c. At a bare minimum,
++ this must be defined as something like:
++
++ struct sh_machine_vector mv_vapor __initmv = {
++ .mv_name = "vapor",
++ };
++ ALIAS_MV(vapor)
++
++ - finally add a file arch/sh/boards/vapor/io.c, which contains definitions of
++ the machine specific io functions (if there are enough to warrant it).
+
+ 3. Hooking into the Build System
+ ================================
+@@ -303,4 +278,3 @@ which will in turn copy the defconfig fo
+ oldconfig (prompting you for any new options since the time of creation),
+ and start you on your way to having a functional kernel for your new
+ board.
+-
+diff --git a/Documentation/sh/register-banks.txt b/Documentation/sh/register-banks.txt
+new file mode 100644
+index 0000000..a6719f2
+--- /dev/null
++++ b/Documentation/sh/register-banks.txt
+@@ -0,0 +1,33 @@
++ Notes on register bank usage in the kernel
++ ==========================================
++
++Introduction
++------------
++
++The SH-3 and SH-4 CPU families traditionally include a single partial register
++bank (selected by SR.RB, only r0 ... r7 are banked), whereas other families
++may have more full-featured banking or simply no such capabilities at all.
++
++SR.RB banking
++-------------
++
++In the case of this type of banking, banked registers are mapped directly to
++r0 ... r7 if SR.RB is set to the bank we are interested in, otherwise ldc/stc
++can still be used to reference the banked registers (as r0_bank ... r7_bank)
++when in the context of another bank. The developer must keep the SR.RB value
++in mind when writing code that utilizes these banked registers, for obvious
++reasons. Userspace is also not able to poke at the bank1 values, so these can
++be used rather effectively as scratch registers by the kernel.
++
++Presently the kernel uses several of these registers.
++
++ - r0_bank, r1_bank (referenced as k0 and k1, used for scratch
++ registers when doing exception handling).
++ - r2_bank (used to track the EXPEVT/INTEVT code)
++ - Used by do_IRQ() and friends for doing irq mapping based off
++ of the interrupt exception vector jump table offset
++ - r6_bank (global interrupt mask)
++ - The SR.IMASK interrupt handler makes use of this to set the
++ interrupt priority level (used by local_irq_enable())
++ - r7_bank (current)
++
+diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
+index f61af23..138673a 100644
+--- a/Documentation/sound/alsa/ALSA-Configuration.txt
++++ b/Documentation/sound/alsa/ALSA-Configuration.txt
+@@ -57,11 +57,6 @@ Prior to version 0.9.0rc4 options had a
+ - Default: 1
+ - For auto-loading more than one card, specify this
+ option together with snd-card-X aliases.
+- device_mode
+- - permission mask for dynamic sound device filesystem
+- - This is available only when DEVFS is enabled
+- - Default: 0666
+- - E.g.: device_mode=0660
+
+
+ Module snd-pcm-oss
+@@ -758,6 +753,7 @@ Prior to version 0.9.0rc4 options had a
+ position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+ single_cmd - Use single immediate commands to communicate with
+ codecs (for debugging only)
++ disable_msi - Disable Message Signaled Interrupt (MSI)
+
+ This module supports one card and autoprobe.
+
+@@ -778,11 +774,16 @@ Prior to version 0.9.0rc4 options had a
+ 6stack-digout 6-jack with a SPDIF out
+ w810 3-jack
+ z71v 3-jack (HP shared SPDIF)
+- asus 3-jack
++ asus 3-jack (ASUS Mobo)
++ asus-w1v ASUS W1V
++ asus-dig ASUS with SPDIF out
++ asus-dig2 ASUS with SPDIF out (using GPIO2)
+ uniwill 3-jack
+ F1734 2-jack
+ lg LG laptop (m1 express dual)
+- lg-lw LG LW20 laptop
++ lg-lw LG LW20/LW25 laptop
++ tcl TCL S700
++ clevo Clevo laptops (m520G, m665n)
+ test for testing/debugging purpose, almost all controls can be
+ adjusted. Appearing only when compiled with
+ $CONFIG_SND_DEBUG=y
+@@ -790,6 +791,7 @@ Prior to version 0.9.0rc4 options had a
+
+ ALC260
+ hp HP machines
++ hp-3013 HP machines (3013-variant)
+ fujitsu Fujitsu S7020
+ acer Acer TravelMate
+ basic fixed pin assignment (old default model)
+@@ -797,24 +799,32 @@ Prior to version 0.9.0rc4 options had a
+
+ ALC262
+ fujitsu Fujitsu Laptop
++ hp-bpc HP xw4400/6400/8400/9400 laptops
++ benq Benq ED8
+ basic fixed pin assignment w/o SPDIF
+ auto auto-config reading BIOS (default)
+
+ ALC882/885
+ 3stack-dig 3-jack with SPDIF I/O
+ 6stck-dig 6-jack digital with SPDIF I/O
++ arima Arima W820Di1
+ auto auto-config reading BIOS (default)
+
+ ALC883/888
+ 3stack-dig 3-jack with SPDIF I/O
+ 6stack-dig 6-jack digital with SPDIF I/O
+- 6stack-dig-demo 6-stack digital for Intel demo board
++ 3stack-6ch 3-jack 6-channel
++ 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
++ 6stack-dig-demo 6-jack digital for Intel demo board
++ acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
+ auto auto-config reading BIOS (default)
+
+ ALC861/660
+ 3stack 3-jack
+ 3stack-dig 3-jack with SPDIF I/O
+ 6stack-dig 6-jack with SPDIF I/O
++ 3stack-660 3-jack (for ALC660)
++ uniwill-m31 Uniwill M31 laptop
+ auto auto-config reading BIOS (default)
+
+ CMI9880
+@@ -843,10 +853,21 @@ Prior to version 0.9.0rc4 options had a
+ 3stack-dig ditto with SPDIF
+ laptop 3-jack with hp-jack automute
+ laptop-dig ditto with SPDIF
+- auto auto-confgi reading BIOS (default)
++ auto auto-config reading BIOS (default)
++
++ STAC9200/9205/9220/9221/9254
++ ref Reference board
++ 3stack D945 3stack
++ 5stack D945 5stack + SPDIF
+
+- STAC7661(?)
++ STAC9227/9228/9229/927x
++ ref Reference board
++ 3stack D965 3stack
++ 5stack D965 5stack + SPDIF
++
++ STAC9872
+ vaio Setup for VAIO FE550G/SZ110
++ vaio-ar Setup for VAIO AR
+
+ If the default configuration doesn't work and one of the above
+ matches with your device, report it together with the PCI
+@@ -1213,6 +1234,14 @@ Prior to version 0.9.0rc4 options had a
+
+ Module supports only 1 card. This module has no enable option.
+
++ Module snd-mts64
++ ----------------
++
++ Module for Ego Systems (ESI) Miditerminal 4140
++
++ This module supports multiple devices.
++ Requires parport (CONFIG_PARPORT).
++
+ Module snd-nm256
+ ----------------
+
+@@ -1234,8 +1263,8 @@ Prior to version 0.9.0rc4 options had a
+
+ Note: on some notebooks the buffer address cannot be detected
+ automatically, or causes hang-up during initialization.
+- In such a case, specify the buffer top address explicity via
+- buffer_top option.
++ In such a case, specify the buffer top address explicitly via
++ the buffer_top option.
+ For example,
+ Sony F250: buffer_top=0x25a800
+ Sony F270: buffer_top=0x272800
+@@ -1853,7 +1882,7 @@ options snd-ens1371 index=1
+ # OSS/Free portion
+ alias sound-slot-0 snd-interwave
+ alias sound-slot-1 snd-ens1371
+------ /etc/moprobe.conf
++----- /etc/modprobe.conf
+
+ In this example, the interwave card is always loaded as the first card
+ (index 0) and ens1371 as the second (index 1).
+@@ -1881,21 +1910,6 @@ Please note that the device mapping abov
+ options of snd-pcm-oss module.
+
+
+-DEVFS support
+-=============
+-
+-The ALSA driver fully supports the devfs extension.
+-You should add lines below to your devfsd.conf file:
+-
+-LOOKUP snd MODLOAD ACTION snd
+-REGISTER ^sound/.* PERMISSIONS root.audio 660
+-REGISTER ^snd/.* PERMISSIONS root.audio 660
+-
+-Warning: These lines assume that you have the audio group in your system.
+- Otherwise replace audio word with another group name (root for
+- example).
+-
+-
+ Proc interfaces (/proc/asound)
+ ==============================
+
+diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
+index b535c2a..e40cce8 100644
+--- a/Documentation/sound/alsa/Audiophile-Usb.txt
++++ b/Documentation/sound/alsa/Audiophile-Usb.txt
+@@ -126,7 +126,7 @@ Here is a list of supported device_setup
+ - Alsa driver default mode
+ - maintains backward compatibility with setups that do not use this
+ parameter by not introducing any change
+- - results sometimes in corrupted sound as decribed earlier
++ - results sometimes in corrupted sound as described earlier
+ * device_setup=0x01
+ - 16bits 48kHz mode with Di disabled
+ - Ai,Ao,Do can be used at the same time
+diff --git a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt
+index 1872e24..4b2b153 100644
+--- a/Documentation/sound/alsa/CMIPCI.txt
++++ b/Documentation/sound/alsa/CMIPCI.txt
+@@ -16,11 +16,11 @@ As default, ALSA driver assigns the firs
+ card#0) for front and 4/6ch playbacks, while the second PCM device
+ (hw:0,1) is assigned to the second DAC for rear playback.
+
+-There are slight difference between two DACs.
++There are slight differences between the two DACs:
+
+ - The first DAC supports U8 and S16LE formats, while the second DAC
+ supports only S16LE.
+-- The seconde DAC supports only two channel stereo.
++- The second DAC supports only two channel stereo.
+
+ Please note that the CM8x38 DAC doesn't support continuous playback
+ rate but only fixed rates: 5512, 8000, 11025, 16000, 22050, 32000,
+@@ -76,7 +76,7 @@ in alsa-lib. For example, you can play
+
+ % aplay -Dsurround51 sixchannels.wav
+
+-For programmin the 4/6 channel playback, you need to specify the PCM
++For programming the 4/6 channel playback, you need to specify the PCM
+ channels as you like and set the format S16LE. For example, for playback
+ with 4 channels,
+
+diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+index b8dc51c..077fbe2 100644
+--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
++++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+@@ -1054,9 +1054,8 @@
+
+ <para>
+ For a device which allows hotplugging, you can use
+- <function>snd_card_free_in_thread</function>. This one will
+- postpone the destruction and wait in a kernel-thread until all
+- devices are closed.
++ <function>snd_card_free_when_closed</function>. This one will
++ postpone the destruction until all devices are closed.
+ </para>
+
+ </section>
+@@ -5487,7 +5486,7 @@ struct _snd_pcm_runtime {
+ <chapter id="power-management">
+ <title>Power Management</title>
+ <para>
+- If the chip is supposed to work with with suspend/resume
++ If the chip is supposed to work with suspend/resume
+ functions, you need to add the power-management codes to the
+ driver. The additional codes for the power-management should be
+ <function>ifdef</function>'ed with
+diff --git a/Documentation/sound/alsa/MIXART.txt b/Documentation/sound/alsa/MIXART.txt
+index 5cb9706..ef42c44 100644
+--- a/Documentation/sound/alsa/MIXART.txt
++++ b/Documentation/sound/alsa/MIXART.txt
+@@ -31,7 +31,7 @@ With a miXart8AES/EBU there is in additi
+ Formats
+ -------
+ U8, S16_LE, S16_BE, S24_3LE, S24_3BE, FLOAT_LE, FLOAT_BE
+-Sample rates : 8000 - 48000 Hz continously
++Sample rates : 8000 - 48000 Hz continuously
+
+ Playback
+ --------
+@@ -39,7 +39,7 @@ For instance the playback devices are co
+ substreams performing hardware mixing. This could be changed to a
+ maximum of 24 substreams if wished.
+ Mono files will be played on the left and right channel. Each channel
+-can be muted for each stream to use 8 analog/digital outputs seperately.
++can be muted for each stream to use 8 analog/digital outputs separately.
+
+ Capture
+ -------
+@@ -97,4 +97,4 @@ COPYRIGHT
+ =========
+
+ Copyright (c) 2003 Digigram SA <alsa at digigram.com>
+-Distributalbe under GPL.
++Distributable under GPL.
+diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
+index 1fe4884..f738b29 100644
+--- a/Documentation/sound/alsa/Procfile.txt
++++ b/Documentation/sound/alsa/Procfile.txt
+@@ -71,7 +71,7 @@ The status of MIDI I/O is found in midi*
+ name and the received/transmitted bytes through the MIDI device.
+
+ When the card is equipped with AC97 codecs, there are codec97#*
+-subdirectories (desribed later).
++subdirectories (described later).
+
+ When the OSS mixer emulation is enabled (and the module is loaded),
+ oss_mixer file appears here, too. This shows the current mapping of
+@@ -161,12 +161,12 @@ seq/drivers
+ Lists the currently available ALSA sequencer drivers.
+
+ seq/clients
+- Shows the list of currently available sequencer clinets and
++ Shows the list of currently available sequencer clients and
+ ports. The connection status and the running status are shown
+ in this file, too.
+
+ seq/queues
+- Lists the currently allocated/running sequener queues.
++ Lists the currently allocated/running sequencer queues.
+
+ seq/timer
+ Lists the currently allocated/running sequencer timers.
+@@ -182,10 +182,10 @@ When the problem is related with PCM, fi
+ mode. This will give you the kernel messages when and where xrun
+ happened.
+
+-If it's really a bug, report it with the following information
++If it's really a bug, report it with the following information:
+
+ - the name of the driver/card, show in /proc/asound/cards
+- - the reigster dump, if available (e.g. card*/cmipci)
++ - the register dump, if available (e.g. card*/cmipci)
+
+ when it's a PCM problem,
+
+diff --git a/Documentation/sound/oss/AWE32 b/Documentation/sound/oss/AWE32
+deleted file mode 100644
+index cb179bf..0000000
+--- a/Documentation/sound/oss/AWE32
++++ /dev/null
+@@ -1,76 +0,0 @@
+- Installing and using Creative AWE midi sound under Linux.
+-
+-This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and
+-SB32.
+-
+-1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
+- is important, because the driver works only with real Creative cards.
+-
+-2) The first thing you need to do is re-compile your kernel with support for
+- your sound card. Run your favourite tool to configure the kernel and when
+- you get to the "Sound" menu you should enable support for the following:
+-
+- Sound card support,
+- OSS sound modules,
+- 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
+- AWE32 synth
+-
+- If your card is "Plug and Play" you will also need to enable these two
+- options, found under the "Plug and Play configuration" menu:
+-
+- Plug and Play support
+- ISA Plug and Play support
+-
+- Now compile and install the kernel in normal fashion. If you don't know
+- how to do this you can find instructions for this in the README file
+- located in the root directory of the kernel source.
+-
+-3) Before you can start playing midi files you will have to load a sound
+- bank file. The utility needed for doing this is called "sfxload", and it
+- is one of the utilities found in a package called "awesfx". If this
+- package is not available in your distribution you can download the AWE
+- snapshot from Creative Labs Open Source website:
+-
+- http://www.opensource.creative.com/snapshot.html
+-
+- Once you have unpacked the AWE snapshot you will see a "awesfx"
+- directory. Follow the instructions in awesfx/docs/INSTALL to install the
+- utilities in this package. After doing this, sfxload should be installed
+- as:
+-
+- /usr/local/bin/sfxload
+-
+- To enable AWE general midi synthesis you should also get the sound bank
+- file for general midi from:
+-
+- http://members.xoom.com/yar/synthgm.sbk.gz
+-
+- Copy it to a directory of your choice, and unpack it there.
+-
+-4) Edit /etc/modprobe.conf, and insert the following lines at the end of the
+- file:
+-
+- alias sound-slot-0 sb
+- alias sound-service-0-1 awe_wave
+- install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
+-
+- You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
+- path of of the sound bank file. That will enable the Sound Blaster and AWE
+- wave synthesis. To play midi files you should get one of these programs if
+- you don't already have them:
+-
+- Playmidi: http://playmidi.openprojects.net
+-
+- AWEMidi Player (drvmidi) Included in the previously mentioned AWE
+- snapshot.
+-
+- You will probably have to pass the "-e" switch to playmidi to have it use
+- your midi device. drvmidi should work without switches.
+-
+- If something goes wrong please e-mail me. All comments and suggestions are
+- welcome.
+-
+- Yaroslav Rosomakho (alons55 at dialup.ptt.ru)
+- http://www.yar.opennet.ru
+-
+-Last Updated: Feb 3 2001
+diff --git a/Documentation/sound/oss/CMI8338 b/Documentation/sound/oss/CMI8338
+deleted file mode 100644
+index 387d058..0000000
+--- a/Documentation/sound/oss/CMI8338
++++ /dev/null
+@@ -1,85 +0,0 @@
+-Audio driver for CM8338/CM8738 chips by Chen-Li Tien
+-
+-
+-HARDWARE SUPPORTED
+-================================================================================
+-C-Media CMI8338
+-C-Media CMI8738
+-On-board C-Media chips
+-
+-
+-STEPS TO BUILD DRIVER
+-================================================================================
+-
+- 1. Backup the Config.in and Makefile in the sound driver directory
+- (/usr/src/linux/driver/sound).
+- The Configure.help provide help when you config driver in step
+- 4, please backup the original one (/usr/src/linux/Document) and
+- copy this file.
+- The cmpci is document for the driver in detail, please copy it
+- to /usr/src/linux/Document/sound so you can refer it. Backup if
+- there is already one.
+-
+- 2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
+- directory.
+-
+- 3. Change directory to /usr/src/linux
+-
+- 4. Config cm8338 driver by 'make menuconfig', 'make config' or
+- 'make xconfig' command.
+-
+- 5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
+- driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
+- For driver option, please refer 'DRIVER PARAMETER'
+-
+- 6. Compile the kernel if necessary.
+-
+- 7. Compile the modules by 'make modules'.
+-
+- 8. Install the modules by 'make modules_install'
+-
+-
+-INSTALL DRIVER
+-================================================================================
+-
+- 1. Before first time to run the driver, create module dependency by
+- 'depmod -a'
+-
+- 2. To install the driver manually, enter 'modprobe cmpci'.
+-
+- 3. Driver installation for various distributions:
+-
+- a. Slackware 4.0
+- Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
+- file.so you can start the driver automatically each time booting.
+-
+- b. Caldera OpenLinux 2.2
+- Use LISA to load the cmpci module.
+-
+- c. RedHat 6.0 and S.u.S.E. 6.1
+- Add following command in /etc/conf.modules:
+-
+- alias sound cmpci
+-
+- also visit http://www.cmedia.com.tw for installation instruction.
+-
+-DRIVER PARAMETER
+-================================================================================
+-
+- Some functions for the cm8738 can be configured in Kernel Configuration
+- or modules parameters. Set these parameters to 1 to enable.
+-
+- mpuio: I/O ports base for MPU-401, 0 if disabled.
+- fmio: I/O ports base for OPL-3, 0 if disabled.
+- spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
+- CD-ROM or DVD-ROM.
+- spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
+- directly.
+- speakers: Number of speakers used.
+- use_line_as_rear:Enable this if you want to use line-in as
+- rear-out.
+- use_line_as_bass:Enable this if you want to use line-in as
+- bass-out.
+- joystick: Enable joystick. You will need to install Linux joystick
+- driver.
+-
+diff --git a/Documentation/sound/oss/INSTALL.awe b/Documentation/sound/oss/INSTALL.awe
+deleted file mode 100644
+index 310f42c..0000000
+--- a/Documentation/sound/oss/INSTALL.awe
++++ /dev/null
+@@ -1,134 +0,0 @@
+-================================================================
+- INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
+- Takashi Iwai <iwai at ww.uni-erlangen.de>
+-================================================================
+-
+-----------------------------------------------------------------
+-* Attention to SB-PnP Card Users
+-
+-If you're using PnP cards, the initialization of PnP is required
+-before loading this driver. You have now three options:
+- 1. Use isapnptools.
+- 2. Use in-kernel isapnp support.
+- 3. Initialize PnP on DOS/Windows, then boot linux by loadlin.
+-In this document, only the case 1 case is treated.
+-
+-----------------------------------------------------------------
+-* Installation on Red Hat 5.0 Sound Driver
+-
+-Please use install-rh.sh under RedHat5.0 directory.
+-DO NOT USE install.sh below.
+-See INSTALL.RH for more details.
+-
+-----------------------------------------------------------------
+-* Installation/Update by Shell Script
+-
+- 1. Become root
+-
+- % su
+-
+- 2. If you have never configured the kernel tree yet, run make config
+- once (to make dependencies and symlinks).
+-
+- # cd /usr/src/linux
+- # make xconfig
+-
+- 3. Run install.sh script
+-
+- # sh ./install.sh
+-
+- 4. Configure your kernel
+-
+- (for Linux 2.[01].x user)
+- # cd /usr/src/linux
+- # make xconfig (or make menuconfig)
+-
+- (for Linux 1.2.x user)
+- # cd /usr/src/linux
+- # make config
+-
+- Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items
+- in Sound menu. ("lowlevel drivers" will appear only in 2.x
+- kernel.)
+-
+- 5. Make your kernel (and modules), and install them as usual.
+-
+- 5a. make kernel image
+- # make zImage
+-
+- 5b. make modules and install them
+- # make modules && make modules_install
+-
+- 5c. If you're using lilo, copy the kernel image and run lilo.
+- Otherwise, copy the kernel image to suitable directory or
+- media for your system.
+-
+- 6. Reboot the kernel if necessary.
+- - If you updated only the modules, you don't have to reboot
+- the system. Just remove the old sound modules here.
+- in
+- # rmmod sound.o (linux-2.0 or OSS/Free)
+- # rmmod awe_wave.o (linux-2.1)
+-
+- 7. If your AWE card is a PnP and not initialized yet, you'll have to
+- do it by isapnp tools. Otherwise, skip to 8.
+-
+- This section described only a brief explanation. For more
+- details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
+-
+- 7a. If you have no isapnp.conf file, generate it by pnpdump.
+- Otherwise, skip to 7d.
+- # pnpdump > /etc/isapnp.conf
+-
+- 7b. Edit isapnp.conf file. Comment out the appropriate
+- lines containing desirable I/O ports, DMA and IRQs.
+- Don't forget to enable (ACT Y) line.
+-
+- 7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part.
+- ex)
+- (CONFIGURE CTL0048/58128 (LD 2
+- # ANSI string -->WaveTable<--
+- (IO 0 (BASE 0x0620))
+- (IO 1 (BASE 0x0A20))
+- (IO 2 (BASE 0x0E20))
+- (ACT Y)
+- ))
+-
+- 7d. Load the config file.
+- CAUTION: This will reset all PnP cards!
+-
+- # isapnp /etc/isapnp.conf
+-
+- 8. Load the sound module (if you configured it as a module):
+-
+- for 2.0 kernel or OSS/Free monolithic module:
+-
+- # modprobe sound.o
+-
+- for 2.1 kernel:
+-
+- # modprobe sound
+- # insmod uart401
+- # insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
+- (These values depend on your settings.)
+- # insmod awe_wave
+- (Be sure to load awe_wave after sb!)
+-
+- See Documentation/sound/oss/AWE32 for
+- more details.
+-
+- 9. (only for obsolete systems) If you don't have /dev/sequencer
+- device file, make it according to Readme.linux file on
+- /usr/src/linux/drivers/sound. (Run a shell script included in
+- that file). <-- This file no longer exists in the recent kernels!
+-
+- 10. OK, load your own soundfont file, and enjoy MIDI!
+-
+- % sfxload synthgm.sbk
+- % drvmidi foo.mid
+-
+- 11. For more advanced use (eg. dynamic loading, virtual bank and
+- etc.), please read the awedrv FAQ or the instructions in awesfx
+- and awemidi packages.
+-
+-Good luck!
+diff --git a/Documentation/sound/oss/MAD16 b/Documentation/sound/oss/MAD16
+deleted file mode 100644
+index 865dbd8..0000000
+--- a/Documentation/sound/oss/MAD16
++++ /dev/null
+@@ -1,56 +0,0 @@
+-(This recipe has been edited to update the configuration symbols,
+- and change over to modprobe.conf for 2.6)
+-
+-From: Shaw Carruthers <shaw at shawc.demon.co.uk>
+-
+-I have been using mad16 sound for some time now with no problems, current
+-kernel 2.1.89
+-
+-lsmod shows:
+-
+-mad16 5176 0
+-sb 22044 0 [mad16]
+-uart401 5576 0 [mad16 sb]
+-ad1848 14176 1 [mad16]
+-sound 61928 0 [mad16 sb uart401 ad1848]
+-
+-.config has:
+-
+-CONFIG_SOUND=m
+-CONFIG_SOUND_ADLIB=m
+-CONFIG_SOUND_MAD16=m
+-CONFIG_SOUND_YM3812=m
+-
+-modprobe.conf has:
+-
+-alias char-major-14-* mad16
+-options sb mad16=1
+-options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
+-
+-
+-To get the built in mixer to work this needs to be:
+-
+-options adlib_card io=0x388 # FM synthesizer
+-options sb mad16=1
+-options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
+-
+-The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
+-
+-------------------------------------------------------------------------
+-The mad16 module in addition supports the following options:
+-
+-option: meaning: default:
+-joystick=0,1 disabled, enabled disabled
+-cdtype=0x00,0x02,0x04, disabled, Sony CDU31A, disabled
+- 0x06,0x08,0x0a Mitsumi, Panasonic,
+- Secondary IDE, Primary IDE
+-cdport=0x340,0x320, 0x340
+- 0x330,0x360
+-cdirq=0,3,5,7,9,10,11 disabled, IRQ3, ... disabled
+-cddma=0,5,6,7 disabled, DMA5, ... DMA5 for Mitsumi or IDE
+-cddma=0,1,2,3 disabled, DMA1, ... DMA3 for Sony or Panasonic
+-opl4=0,1 OPL3, OPL4 OPL3
+-
+-for more details see linux/drivers/sound/mad16.c
+-
+-Rui Sousa
+diff --git a/Documentation/sound/oss/Maestro b/Documentation/sound/oss/Maestro
+deleted file mode 100644
+index 4a80eb3..0000000
+--- a/Documentation/sound/oss/Maestro
++++ /dev/null
+@@ -1,123 +0,0 @@
+- An OSS/Lite Driver for the ESS Maestro family of sound cards
+-
+- Zach Brown, December 1999
+-
+-Driver Status and Availability
+-------------------------------
+-
+-The most recent version of this driver will hopefully always be available at
+- http://www.zabbo.net/maestro/
+-
+-I will try and maintain the most recent stable version of the driver
+-in both the stable and development kernel lines.
+-
+-ESS Maestro Chip Family
+------------------------
+-
+-There are 3 main variants of the ESS Maestro PCI sound chip. The first
+-is the Maestro 1. It was originally produced by Platform Tech as the
+-'AGOGO'. It can be recognized by Platform Tech's PCI ID 0x1285 with
+-0x0100 as the device ID. It was put on some sound boards and a few laptops.
+-ESS bought the design and cleaned it up as the Maestro 2. This starts
+-their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
+-The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
+-
+-The various families of Maestro are mostly identical as far as this
+-driver is concerned. It doesn't touch the DSP parts that differ (though
+-it could for FM synthesis).
+-
+-Driver OSS Behavior
+---------------------
+-
+-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+-mostly adhere to the OSS spec. This driver doesn't register itself
+-with /dev/sndstat, so don't expect information to appear there.
+-
+-The /dev/dsp device exported behaves almost as expected. Playback is
+-supported in all the various lovely formats. 8/16bit stereo/mono from
+-8khz to 48khz, and mmap()ing for playback behaves. Capture/recording
+-is limited due to oddities with the Maestro hardware. One can only
+-record in 16bit stereo. For recording the maestro uses non interleaved
+-stereo buffers so that mmap()ing the incoming data does not result in
+-a ring buffer of LRLR data. mmap()ing of the read buffers is therefore
+-disallowed until this can be cleaned up.
+-
+-/dev/mixer is an interface to the AC'97 codec on the Maestro. It is
+-worth noting that there are a variety of AC'97s that can be wired to
+-the Maestro. Which is used is entirely up to the hardware implementor.
+-This should only be visible to the user by the presence, or lack, of
+-'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
+-
+-The driver doesn't support MIDI or FM playback at the moment. Typically
+-the Maestro is wired to an MPU MIDI chip, but some hardware implementations
+-don't. We need to assemble a white list of hardware implementations that
+-have MIDI wired properly before we can claim to support it safely.
+-
+-Compiling and Installing
+-------------------------
+-
+-With the drivers inclusion into the kernel, compiling and installing
+-is the same as most OSS/Lite modular sound drivers. Compilation
+-of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
+-in the config system.
+-
+-It may be modular or statically linked. If it is modular it should be
+-installed with the rest of the modules for the kernel on the system.
+-Typically this will be in /lib/modules/ somewhere. 'alias sound maestro'
+-should also be added to your module configs (typically /etc/conf.modules)
+-if you're using modular OSS/Lite sound and want to default to using a
+-maestro chip.
+-
+-As this is a PCI device, the module does not need to be informed of
+-any IO or IRQ resources it should use, it devines these from the
+-system. Sometimes, on sucky PCs, the BIOS fails to allocated resources
+-for the maestro. This will result in a message like:
+- maestro: PCI subsystem reports IRQ 0, this might not be correct.
+-from the kernel. Should this happen the sound chip most likely will
+-not operate correctly. To solve this one has to dig through their BIOS
+-(typically entered by hitting a hot key at boot time) and figure out
+-what magic needs to happen so that the BIOS will reward the maestro with
+-an IRQ. This operation is incredibly system specific, so you're on your
+-own. Sometimes the magic lies in 'PNP Capable Operating System' settings.
+-
+-There are very few options to the driver. One is 'debug' which will
+-tell the driver to print minimal debugging information as it runs. This
+-can be collected with 'dmesg' or through the klogd daemon.
+-
+-The other, more interesting option, is 'dsps_order'. Typically at
+-install time the driver will only register one available /dev/dsp device
+-for its use. The 'dsps_order' module parameter allows for more devices
+-to be allocated, as a power of two. Up to 4 devices can be registered
+-( dsps_order=2 ). These devices act as fully distinct units and use
+-separate channels in the maestro.
+-
+-Power Management
+-----------------
+-
+-As of version 0.14, this driver has a minimal understanding of PCI
+-Power Management. If it finds a valid power management capability
+-on the PCI device it will attempt to use the power management
+-functions of the maestro. It will only do this on Maestro 2Es and
+-only on machines that are known to function well. You can
+-force the use of power management by setting the 'use_pm' module
+-option to 1, or can disable it entirely by setting it to 0.
+-
+-When using power management, the driver does a few things
+-differently. It will keep the chip in a lower power mode
+-when the module is inserted but /dev/dsp is not open. This
+-allows the mixer to function but turns off the clocks
+-on other parts of the chip. When /dev/dsp is opened the chip
+-is brought into full power mode, and brought back down
+-when it is closed. It also powers down the chip entirely
+-when the module is removed or the machine is shutdown. This
+-can have nonobvious consequences. CD audio may not work
+-after a power managing driver is removed. Also, software that
+-doesn't understand power management may not be able to talk
+-to the powered down chip until the machine goes through a hard
+-reboot to bring it back.
+-
+-.. more details ..
+-------------------
+-
+-drivers/sound/maestro.c contains comments that hopefully explain
+-the maestro implementation.
+diff --git a/Documentation/sound/oss/Maestro3 b/Documentation/sound/oss/Maestro3
+deleted file mode 100644
+index a113718..0000000
+--- a/Documentation/sound/oss/Maestro3
++++ /dev/null
+@@ -1,92 +0,0 @@
+- An OSS/Lite Driver for the ESS Maestro3 family of sound chips
+-
+- Zach Brown, January 2001
+-
+-Driver Status and Availability
+-------------------------------
+-
+-The most recent version of this driver will hopefully always be available at
+- http://www.zabbo.net/maestro3/
+-
+-I will try and maintain the most recent stable version of the driver
+-in both the stable and development kernel lines.
+-
+-Historically I've sucked pretty hard at actually doing that, however.
+-
+-ESS Maestro3 Chip Family
+------------------------
+-
+-The 'Maestro3' is much like the Maestro2 chip. The noted improvement
+-is the removal of the silicon in the '2' that did PCM mixing. All that
+-work is now done through a custom DSP called the ASSP, the Asynchronus
+-Specific Signal Processor.
+-
+-The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear
+-on the extent of the differences, but the driver supports them both :)
+-
+-The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
+-both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as
+-0x199a when hardware strapping is used.
+-
+-The chip can also act as a multi function device. The modem IDs follow
+-the audio multimedia device IDs. (so the modem part of an Allegro shows
+-up as 0x1989)
+-
+-Driver OSS Behavior
+---------------------
+-
+-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+-mostly adhere to the OSS spec. This driver doesn't register itself
+-with /dev/sndstat, so don't expect information to appear there.
+-
+-The /dev/dsp device exported behaves as expected. Playback is
+-supported in all the various lovely formats. 8/16bit stereo/mono from
+-8khz to 48khz, with both read()/write(), and mmap().
+-
+-/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is
+-worth noting that there are a variety of AC'97s that can be wired to
+-the Maestro3. Which is used is entirely up to the hardware implementor.
+-This should only be visible to the user by the presence, or lack, of
+-'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
+-The Allegro has an onchip AC'97.
+-
+-The driver doesn't support MIDI or FM playback at the moment.
+-
+-Compiling and Installing
+-------------------------
+-
+-With the drivers inclusion into the kernel, compiling and installing
+-is the same as most OSS/Lite modular sound drivers. Compilation
+-of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
+-in the config system.
+-
+-It may be modular or statically linked. If it is modular it should be
+-installed with the rest of the modules for the kernel on the system.
+-Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0
+-maestro3' should also be added to your module configs (typically
+-/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to
+-default to using a maestro3 chip.
+-
+-There are very few options to the driver. One is 'debug' which will
+-tell the driver to print minimal debugging information as it runs. This
+-can be collected with 'dmesg' or through the klogd daemon.
+-
+-One is 'external_amp', which tells the driver to attempt to enable
+-an external amplifier. This defaults to '1', you can tell the driver
+-not to bother enabling such an amplifier by setting it to '0'.
+-
+-And the last is 'gpio_pin', which tells the driver which GPIO pin number
+-the external amp uses (0-15), The Allegro uses 8 by default, all others 1.
+-If everything loads correctly and seems to be working but you get no sound,
+-try tweaking this value.
+-
+-Systems known to need a different value
+- Panasonic ToughBook CF-72: gpio_pin=13
+-
+-Power Management
+-----------------
+-
+-This driver has a minimal understanding of PCI Power Management. It will
+-try and power down the chip when the system is suspended, and power
+-it up with it is resumed. It will also try and power down the chip
+-when the machine is shut down.
+diff --git a/Documentation/sound/oss/NEWS b/Documentation/sound/oss/NEWS
+deleted file mode 100644
+index a81e0ef..0000000
+--- a/Documentation/sound/oss/NEWS
++++ /dev/null
+@@ -1,42 +0,0 @@
+-Linux 2.4 Sound Changes
+-2000-September-25
+-Christoph Hellwig, <hch at infradead.org>
+-
+-
+-
+-=== isapnp support
+-
+-The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
+-Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
+-detecting and configuring isapnp devices.
+-If you have a not yet supported isapnp soundcard, mail me the content
+-of '/proc/isapnp' on your system and some information about your card
+-and its driver(s) so I can try to get isapnp working for it.
+-
+-
+-
+-=== soundcard resources on kernel commandline
+-
+-Before Linux 2.4 you had to specify the resources for sounddrivers
+-statically linked into the kernel at compile time
+-(in make config/menuconfig/xconfig). In Linux 2.4 the resources are
+-now specified at the boot-time kernel commandline (e.g. the lilo
+-'append=' line or everything that's after the kernel name in grub).
+-Read the Configure.help entry for your card for the parameters.
+-
+-
+-=== softoss is gone
+-
+-In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable.
+-Use a user space software synthesizer like timidity instead.
+-
+-
+-
+-=== /dev/sndstat and /proc/sound are gone
+-
+-In older Linux versions those files exported some information about the
+-OSS/Free configuration to userspace. In Linux 2.3 they were removed because
+-they did not support the growing number of pci soundcards and there were
+-some general problems with this interface.
+-
+-
+diff --git a/Documentation/sound/oss/OPL3-SA b/Documentation/sound/oss/OPL3-SA
+deleted file mode 100644
+index 66a9183..0000000
+--- a/Documentation/sound/oss/OPL3-SA
++++ /dev/null
+@@ -1,52 +0,0 @@
+-OPL3-SA1 sound driver (opl3sa.o)
+-
+----
+-Note: This howto only describes how to setup the OPL3-SA1 chip; this info
+-does not apply to the SA2, SA3, or SA4.
+----
+-
+-The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
+-it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401
+-and OPL3 FM Synth capabilities.
+-
+-You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or
+-CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'.
+-
+-You'll need to know all of the relevant info (irq, dma, and io port) for the
+-chip's WSS mode, since that is the mode the kernel sound driver uses, and of
+-course you'll also need to know about where the MPU401 and OPL3 ports and
+-IRQs are if you want to use those.
+-
+-Here's the skinny on how to load it as a module:
+-
+- modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5
+-
+-Module options in detail:
+-
+- io: This is the WSS's port base.
+- irq: This is the WSS's IRQ.
+- dma: This is the WSS's DMA line. In my BIOS setup screen this was
+- listed as "WSS Play DMA"
+- dma2: This is the WSS's secondary DMA line. My BIOS calls it the
+- "WSS capture DMA"
+-
+- mpu_io: This is the MPU401's port base.
+- mpu_irq: This is the MPU401's IRQ.
+-
+-If you'd like to use the OPL3 FM Synthesizer, make sure you enable
+-CONFIG_SOUND_YM3812 (in 'make config'). That'll build the opl3.o module.
+-
+-Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
+-
+-You can also use the SoftOSS software synthesizer instead of the builtin OPL3.
+-Here's how:
+-
+-Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
+-
+-If you said yes, the software synth is available once you boot your new
+-kernel.
+-
+-If you chose to build it as a module, just insmod the resulting softoss2.o
+-
+-Questions? Comments?
+-<stiker at northlink.com>
+diff --git a/Documentation/sound/oss/README.awe b/Documentation/sound/oss/README.awe
+deleted file mode 100644
+index 80054cd..0000000
+--- a/Documentation/sound/oss/README.awe
++++ /dev/null
+@@ -1,218 +0,0 @@
+-================================================================
+- AWE32 Sound Driver for Linux / FreeBSD
+- version 0.4.3; Nov. 1, 1998
+-
+- Takashi Iwai <iwai at ww.uni-erlangen.de>
+-================================================================
+-
+-* GENERAL NOTES
+-
+-This is a sound driver extension for SoundBlaster AWE32 and other
+-compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
+-the wave synth operations. The driver is provided for Linux 1.2.x
+-and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
+-Alpha systems.
+-
+-This driver was written by Takashi Iwai <iwai at ww.uni-erlangen.de>,
+-and provided "as is". The original source (awedrv-0.4.3.tar.gz) and
+-binary packages are available on the following URL:
+- http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
+-Note that since the author is apart from this web site, the update is
+-not frequent now.
+-
+-
+-* NOTE TO LINUX USERS
+-
+-To enable this driver on linux-2.[01].x kernels, you need turn on
+-"AWE32 synth" options in sound menu when configure your linux kernel
+-and modules. The precise installation procedure is described in the
+-AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
+-
+-If you're using PnP cards, the card must be initialized before loading
+-the sound driver. There're several options to do this:
+- - Initialize the card via ISA PnP tools, and load the sound module.
+- - Initialize the card on DOS, and load linux by loadlin.exe
+- - Use PnP kernel driver (for Linux-2.x.x)
+-The detailed instruction for the solution using isapnp tools is found
+-in many documents like above. A brief instruction is also included in
+-the installation document of this package.
+-For PnP driver project, please refer to the following URL:
+- http://www-jcr.lmh.ox.ac.uk/~pnp/
+-
+-
+-* USING THE DRIVER
+-
+-The awedrv has several different playing modes to realize easy channel
+-allocation for MIDI songs. To hear the exact sound quality, you need
+-to obtain the extended sequencer program, drvmidi or playmidi-2.5.
+-
+-For playing MIDI files, you *MUST* load the soundfont file on the
+-driver previously by sfxload utility. Otherwise you'll here no sounds
+-at all! All the utilities and driver source packages are found in the
+-above URL. The sfxload program is included in the package
+-awesfx-0.4.3.tgz. Binary packages are available there, too. See the
+-instruction in each package for installation.
+-
+-Loading a soundfont file is very simple. Just execute the command
+-
+- % sfxload synthgm.sbk
+-
+-Then, sfxload transfers the file "synthgm.sbk" to the driver.
+-Both SF1 and SF2 formats are accepted.
+-
+-Now you can hear midi musics by a midi player.
+-
+- % drvmidi foo.mid
+-
+-If you run MIDI player after MOD player, you need to load soundfont
+-files again, since MOD player programs clear the previous loaded
+-samples by their own data.
+-
+-If you have only 512kb on the sound card, I recommend to use dynamic
+-sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is
+-available in most midi files.
+-
+- % sfxload synthgm
+- % drvmidi -L 2mbgmgs foo.mid
+-
+-This makes a big difference (believe me)! For more details, please
+-refer to the FAQ list which is available on the URL above.
+-
+-The current chorus, reverb and equalizer status can be changed by
+-aweset utility program (included in awesfx package). Note that
+-some awedrv-native programs (like drvmidi and xmp) will change the
+-current settings by themselves. The aweset program is effective
+-only for other programs like playmidi.
+-
+-Enjoy.
+-
+-
+-* COMPILE FLAGS
+-
+-Compile conditions are defined in awe_config.h.
+-
+-[Compatibility Conditions]
+-The following flags are defined automatically when using installation
+-shell script.
+-
+-- AWE_MODULE_SUPPORT
+- indicates your Linux kernel supports module for each sound card
+- (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
+- as distributed in the RH5.0 package).
+- This flag is automatically set when you're using 2.1.x kernels.
+- You can pass the base address and memory size via the following
+- module options,
+- io = base I/O port address (eg. 0x620)
+- memsize = DRAM size in kilobytes (eg. 512)
+- As default, AWE driver probes these values automatically.
+-
+-
+-[Hardware Conditions]
+-You DON'T have to define the following two values.
+-Define them only when the driver couldn't detect the card properly.
+-
+-- AWE_DEFAULT_BASE_ADDR (default: not defined)
+- specifies the base port address of your AWE32 card.
+- 0 means to autodetect the address.
+-
+-- AWE_DEFAULT_MEM_SIZE (default: not defined)
+- specifies the memory size of your AWE32 card in kilobytes.
+- -1 means to autodetect its size.
+-
+-
+-[Sample Table Size]
+-From ver.0.4.0, sample tables are allocated dynamically (except
+-Linux-1.2.x system), so you need NOT to touch these parameters.
+-Linux-1.2.x users may need to increase these values to appropriate size
+-if the sound card is equipped with more DRAM.
+-
+-- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
+-
+-
+-[Other Conditions]
+-
+-- AWE_ALWAYS_INIT_FM (default: not defined)
+- indicates the AWE driver always initialize FM passthrough even
+- without DRAM on board. Emu8000 chip has a restriction for playing
+- samples on DRAM that at least two channels must be occupied as
+- passthrough channels.
+-
+-- AWE_DEBUG_ON (default: defined)
+- turns on debugging messages if defined.
+-
+-- AWE_HAS_GUS_COMPATIBILITY (default: defined)
+- Enables GUS compatibility mode if defined, reading GUS patches and
+- GUS control commands. Define this option to use GMOD or other
+- GUS module players.
+-
+-- CONFIG_AWE32_MIDIEMU (default: defined)
+- Adds a MIDI emulation device by Emu8000 wavetable. The emulation
+- device can be accessed as an external MIDI, and sends the MIDI
+- control codes directly. XG and GS sysex/NRPN are accepted.
+- No MIDI input is supported.
+-
+-- CONFIG_AWE32_MIXER (default: not defined)
+- Adds a mixer device for AWE32 bass/treble equalizer control.
+- You can access this device using /dev/mixer?? (usually mixer01).
+-
+-- AWE_USE_NEW_VOLUME_CALC (default: defined)
+- Use the new method to calculate the volume change as compatible
+- with DOS/Win drivers. This option can be toggled via aweset
+- program, or drvmidi player.
+-
+-- AWE_CHECK_VTARGET (default: defined)
+- Check the current volume target value when searching for an
+- empty channel to allocate a new voice. This is experimentally
+- implemented in this version. (probably, this option doesn't
+- affect the sound quality severely...)
+-
+-- AWE_ALLOW_SAMPLE_SHARING (default: defined)
+- Allow sample sharing for differently loaded patches.
+- This function is available only together with awesfx-0.4.3p3.
+- Note that this is still an experimental option.
+-
+-- DEF_FM_CHORUS_DEPTH (default: 0x10)
+- The default strength to be sent to the chorus effect engine.
+- From 0 to 0xff. Larger numbers may often cause weird sounds.
+-
+-- DEF_FM_REVERB_DEPTH (default: 0x10)
+- The default strength to be sent to the reverb effect engine.
+- From 0 to 0xff. Larger numbers may often cause weird sounds.
+-
+-
+-* ACKNOWLEDGMENTS
+-
+-Thanks to Witold Jachimczyk (witek at xfactor.wpi.edu) for much advice
+-on programming of AWE32. Much code is brought from his AWE32-native
+-MOD player, ALMP.
+-The port of awedrv to FreeBSD is done by Randall Hopper
+-(rhh at ct.picker.com).
+-The new volume calculation routine was derived from Mark Weaver's
+-ADIP compatible routines.
+-I also thank linux-awe-ml members for their efforts
+-to reboot their system many times :-)
+-
+-
+-* TODO'S
+-
+-- Complete DOS/Win compatibility
+-- DSP-like output
+-
+-
+-* COPYRIGHT
+-
+-Copyright (C) 1996-1998 Takashi Iwai
+-
+-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.
+diff --git a/Documentation/sound/oss/Wavefront b/Documentation/sound/oss/Wavefront
+deleted file mode 100644
+index 16f57ea..0000000
+--- a/Documentation/sound/oss/Wavefront
++++ /dev/null
+@@ -1,339 +0,0 @@
+- An OSS/Free Driver for WaveFront soundcards
+- (Turtle Beach Maui, Tropez, Tropez Plus)
+-
+- Paul Barton-Davis, July 1998
+-
+- VERSION 0.2.5
+-
+-Driver Status
+--------------
+-
+-Requires: Kernel 2.1.106 or later (the driver is included with kernels
+-2.1.109 and above)
+-
+-As of 7/22/1998, this driver is currently in *BETA* state. This means
+-that it compiles and runs, and that I use it on my system (Linux
+-2.1.106) with some reasonably demanding applications and uses. I
+-believe the code is approaching an initial "finished" state that
+-provides bug-free support for the Tropez Plus.
+-
+-Please note that to date, the driver has ONLY been tested on a Tropez
+-Plus. I would very much like to hear (and help out) people with Tropez
+-and Maui cards, since I think the driver can support those cards as
+-well.
+-
+-Finally, the driver has not been tested (or even compiled) as a static
+-(non-modular) part of the kernel. Alan Cox's good work in modularizing
+-OSS/Free for Linux makes this rather unnecessary.
+-
+-Some Questions
+---------------
+-
+-**********************************************************************
+-0) What does this driver do that the maui driver did not ?
+-**********************************************************************
+-
+-* can fully initialize a WaveFront card from cold boot - no DOS
+- utilities needed
+-* working patch/sample/program loading and unloading (the maui
+- driver didn't document how to make this work, and assumed
+- user-level preparation of the patch data for writing
+- to the board. ick.)
+-* full user-level access to all WaveFront commands
+-* for the Tropez Plus, (primitive) control of the YSS225 FX processor
+-* Virtual MIDI mode supported - 2 MIDI devices accessible via the
+- WaveFront's MPU401/UART emulation. One
+- accesses the WaveFront synth, the other accesses the
+- external MIDI connector. Full MIDI read/write semantics
+- for both devices.
+-* OSS-compliant /dev/sequencer interface for the WaveFront synth,
+- including native and GUS-format patch downloading.
+-* semi-intelligent patch management (prototypical at this point)
+-
+-**********************************************************************
+-1) What to do about MIDI interfaces ?
+-**********************************************************************
+-
+-The Tropez Plus (and perhaps other WF cards) can in theory support up
+-to 2 physical MIDI interfaces. One of these is connected to the
+-ICS2115 chip (the WaveFront synth itself) and is controlled by
+-MPU/UART-401 emulation code running as part of the WaveFront OS. The
+-other is controlled by the CS4232 chip present on the board. However,
+-physical access to the CS4232 connector is difficult, and it is
+-unlikely (though not impossible) that you will want to use it.
+-
+-An older version of this driver introduced an additional kernel config
+-variable which controlled whether or not the CS4232 MIDI interface was
+-configured. Because of Alan Cox's work on modularizing the sound
+-drivers, and now backporting them to 2.0.34 kernels, there seems to be
+-little reason to support "static" configuration variables, and so this
+-has been abandoned in favor of *only* module parameters. Specifying
+-"mpuio" and "mpuirq" for the cs4232 parameter will result in the
+-CS4232 MIDI interface being configured; leaving them unspecified will
+-leave it unconfigured (and thus unusable).
+-
+-BTW, I have heard from one Tropez+ user that the CS4232 interface is
+-more reliable than the ICS2115 one. I have had no problems with the
+-latter, and I don't have the right cable to test the former one
+-out. Reports welcome.
+-
+-**********************************************************************
+-2) Why does line XXX of the code look like this .... ?
+-**********************************************************************
+-
+-Either because it's not finished yet, or because you're a better coder
+-than I am, or because you don't understand some aspect of how the card
+-or the code works.
+-
+-I absolutely welcome comments, criticisms and suggestions about the
+-design and implementation of the driver.
+-
+-**********************************************************************
+-3) What files are included ?
+-**********************************************************************
+-
+- drivers/sound/README.wavefront -- this file
+-
+- drivers/sound/wavefront.patch -- patches for the 2.1.106 sound drivers
+- needed to make the rest of this work
+- DO NOT USE IF YOU'VE APPLIED THEM
+- BEFORE, OR HAVE 2.1.109 OR ABOVE
+-
+- drivers/sound/wavfront.c -- the driver
+- drivers/sound/ys225.h -- data declarations for FX config
+- drivers/sound/ys225.c -- data definitions for FX config
+- drivers/sound/wf_midi.c -- the "uart401" driver
+- to support virtual MIDI mode.
+- include/wavefront.h -- the header file
+- Documentation/sound/oss/Tropez+ -- short docs on configuration
+-
+-**********************************************************************
+-4) How do I compile/install/use it ?
+-**********************************************************************
+-
+-PART ONE: install the source code into your sound driver directory
+-
+- cd <top-of-your-2.1.106-code-base-e.g.-/usr/src/linux>
+- tar -zxvf <where-you-put/wavefront.tar.gz>
+-
+-PART TWO: apply the patches
+-
+- DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109
+- AND HAVE NOT ALREADY INSTALLED THE PATCH(ES).
+-
+- cd drivers/sound
+- patch < wavefront.patch
+-
+-PART THREE: configure your kernel
+-
+- cd <top of your kernel tree>
+- make xconfig (or whichever config option you use)
+-
+- - choose YES for Sound Support
+- - choose MODULE (M) for OSS Sound Modules
+- - choose MODULE(M) to YM3812/OPL3 support
+- - choose MODULE(M) for WaveFront support
+- - choose MODULE(M) for CS4232 support
+-
+- - choose "N" for everything else (unless you have other
+- soundcards you want support for)
+-
+-
+- make boot
+- .
+- .
+- .
+- <whatever you normally do for a kernel install>
+- make modules
+- .
+- .
+- .
+- make modules_install
+-
+-Here's my autoconf.h SOUND section:
+-
+-/*
+- * Sound
+- */
+-#define CONFIG_SOUND 1
+-#undef CONFIG_SOUND_OSS
+-#define CONFIG_SOUND_OSS_MODULE 1
+-#undef CONFIG_SOUND_PAS
+-#undef CONFIG_SOUND_SB
+-#undef CONFIG_SOUND_ADLIB
+-#undef CONFIG_SOUND_GUS
+-#undef CONFIG_SOUND_MPU401
+-#undef CONFIG_SOUND_PSS
+-#undef CONFIG_SOUND_MSS
+-#undef CONFIG_SOUND_SSCAPE
+-#undef CONFIG_SOUND_TRIX
+-#undef CONFIG_SOUND_MAD16
+-#undef CONFIG_SOUND_WAVEFRONT
+-#define CONFIG_SOUND_WAVEFRONT_MODULE 1
+-#undef CONFIG_SOUND_CS4232
+-#define CONFIG_SOUND_CS4232_MODULE 1
+-#undef CONFIG_SOUND_MAUI
+-#undef CONFIG_SOUND_SGALAXY
+-#undef CONFIG_SOUND_OPL3SA1
+-#undef CONFIG_SOUND_SOFTOSS
+-#undef CONFIG_SOUND_YM3812
+-#define CONFIG_SOUND_YM3812_MODULE 1
+-#undef CONFIG_SOUND_VMIDI
+-#undef CONFIG_SOUND_UART6850
+-/*
+- * Additional low level sound drivers
+- */
+-#undef CONFIG_LOWLEVEL_SOUND
+-
+-************************************************************
+-6) How do I configure my card ?
+-************************************************************
+-
+-You need to edit /etc/modprobe.conf. Here's mine (edited to show the
+-relevant details):
+-
+- # Sound system
+- alias char-major-14-* wavefront
+- alias synth0 wavefront
+- alias mixer0 cs4232
+- alias audio0 cs4232
+- install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3
+- options wavefront io=0x200 irq=9
+- options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
+- options opl3 io=0x388
+-
+-Things to note:
+-
+- the wavefront options "io" and "irq" ***MUST*** match the "synthio"
+- and "synthirq" cs4232 options.
+-
+- you can do without the opl3 module if you don't
+- want to use the OPL/[34] FM synth on the soundcard
+-
+- the opl3 io parameter is conventionally not adjustable.
+- In theory, any not-in-use IO port address would work, but
+- just use 0x388 and stick with the crowd.
+-
+-**********************************************************************
+-7) What about firmware ?
+-**********************************************************************
+-
+-Turtle Beach have not given me permission to distribute their firmware
+-for the ICS2115. However, if you have a WaveFront card, then you
+-almost certainly have the firmware, and if not, its freely available
+-on their website, at:
+-
+- http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus
+-
+-The file is called WFOS2001.MOT (for the Tropez+).
+-
+-This driver, however, doesn't use the pure firmware as distributed,
+-but instead relies on a somewhat processed form of it. You can
+-generate this very easily. Following an idea from Andrew Veliath's
+-Pinnacle driver, the following flex program will generate the
+-processed version:
+-
+----- cut here -------------------------
+-%option main
+-%%
+-^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext);
+-<<EOF>> { fputc ('\0', stdout); return; }
+-\n {}
+-. {}
+----- cut here -------------------------
+-
+-To use it, put the above in file (say, ws.l) compile it like this:
+-
+- shell> flex -ows.c ws.l
+- shell> cc -o ws ws.c
+-
+-and then use it like this:
+-
+- ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os
+-
+-If you put it somewhere else, you'll always have to use the wf_ospath
+-module parameter (see below) or alter the source code.
+-
+-**********************************************************************
+-7) How do I get it working ?
+-**********************************************************************
+-
+-Optionally, you can reboot with the "new" kernel (even though the only
+-changes have really been made to a module).
+-
+-Then, as root do:
+-
+- modprobe wavefront
+-
+-You should get something like this in /var/log/messages:
+-
+- WaveFront: firmware 1.20 already loaded.
+-
+-or
+-
+- WaveFront: no response to firmware probe, assume raw.
+-
+-then:
+-
+- WaveFront: waiting for memory configuration ...
+- WaveFront: hardware version 1.64
+- WaveFront: available DRAM 8191k
+- WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty
+- WaveFront: 128 programs slots in use
+- WaveFront: 256 patch slots filled, 142 in use
+-
+-The whole process takes about 16 seconds, the longest waits being
+-after reporting the hardware version (during the firmware download),
+-and after reporting program status (during patch status inquiry). Its
+-shorter (about 10 secs) if the firmware is already loaded (i.e. only
+-warm reboots since the last firmware load).
+-
+-The "available DRAM" line will vary depending on how much added RAM
+-your card has. Mine has 8MB.
+-
+-To check basically functionality, use play(1) or splay(1) to send a
+-.WAV or other audio file through the audio portion. Then use playmidi
+-to play a General MIDI file. Try the "-D 0" to hear the
+-difference between sending MIDI to the WaveFront and using the OPL/3,
+-which is the default (I think ...). If you have an external synth(s)
+-hooked to the soundcard, you can use "-e" to route to the
+-external synth(s) (in theory, -D 1 should work as well, but I think
+-there is a bug in playmidi which prevents this from doing what it
+-should).
+-
+-**********************************************************************
+-8) What are the module parameters ?
+-**********************************************************************
+-
+-Its best to read wavefront.c for this, but here is a summary:
+-
+-integers:
+- wf_raw - if set, ignore apparent presence of firmware
+- loaded onto the ICS2115, reset the whole
+- board, and initialize it from scratch. (default = 0)
+-
+- fx_raw - if set, always initialize the YSS225 processor
+- on the Tropez plus. (default = 1)
+-
+- < The next 4 are basically for kernel hackers to allow
+- tweaking the driver for testing purposes. >
+-
+- wait_usecs - loop timer used when waiting for
+- status conditions on the board.
+- The default is 150.
+-
+- debug_default - debugging flags. See sound/wavefront.h
+- for WF_DEBUG_* values. Default is zero.
+- Setting this allows you to debug the
+- driver during module installation.
+-strings:
+- ospath - path to get to the pre-processed OS firmware.
+- (default: /etc/sound/wavefront.os)
+-
+-**********************************************************************
+-9) Who should I contact if I have problems?
+-**********************************************************************
+-
+-Just me: Paul Barton-Davis <pbd at op.net>
+-
+-
+diff --git a/Documentation/sound/oss/es1370 b/Documentation/sound/oss/es1370
+deleted file mode 100644
+index 7b38b1a..0000000
+--- a/Documentation/sound/oss/es1370
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/proc/sound, /dev/sndstat
+--------------------------
+-
+-/proc/sound and /dev/sndstat is not supported by the
+-driver. To find out whether the driver succeeded loading,
+-check the kernel log (dmesg).
+-
+-
+-ALaw/uLaw sample formats
+-------------------------
+-
+-This driver does not support the ALaw/uLaw sample formats.
+-ALaw is the default mode when opening a sound device
+-using OSS/Free. The reason for the lack of support is
+-that the hardware does not support these formats, and adding
+-conversion routines to the kernel would lead to very ugly
+-code in the presence of the mmap interface to the driver.
+-And since xquake uses mmap, mmap is considered important :-)
+-and no sane application uses ALaw/uLaw these days anyway.
+-In short, playing a Sun .au file as follows:
+-
+-cat my_file.au > /dev/dsp
+-
+-does not work. Instead, you may use the play script from
+-Chris Bagwell's sox-12.14 package (available from the URL
+-below) to play many different audio file formats.
+-The script automatically determines the audio format
+-and does do audio conversions if necessary.
+-http://home.sprynet.com/sprynet/cbagwell/projects.html
+-
+-
+-Blocking vs. nonblocking IO
+----------------------------
+-
+-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+-not only during open, but also during read and write.
+-This is an effort to make the sound driver interface more
+-regular. Timidity has problems with this; a patch
+-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+-(Timidity patched will also run on OSS/Free).
+-
+-
+-MIDI UART
+----------
+-
+-The driver supports a simple MIDI UART interface, with
+-no ioctl's supported.
+-
+-
+-MIDI synthesizer
+-----------------
+-
+-This soundcard does not have any hardware MIDI synthesizer;
+-MIDI synthesis has to be done in software. To allow this
+-the driver/soundcard supports two PCM (/dev/dsp) interfaces.
+-The second one goes to the mixer "synth" setting and supports
+-only a limited set of sampling rates (44100, 22050, 11025, 5512).
+-By setting lineout to 1 on the driver command line
+-(eg. insmod es1370 lineout=1) it is even possible on some
+-cards to convert the LINEIN jack into a second LINEOUT jack, thus
+-making it possible to output four independent audio channels!
+-
+-There is a freely available software package that allows
+-MIDI file playback on this soundcard called Timidity.
+-See http://www.cgs.fi/~tt/timidity/.
+-
+-
+-
+-Thomas Sailer
+-t.sailer at alumni.ethz.ch
+diff --git a/Documentation/sound/oss/rme96xx b/Documentation/sound/oss/rme96xx
+deleted file mode 100644
+index 87d7b7b..0000000
+--- a/Documentation/sound/oss/rme96xx
++++ /dev/null
+@@ -1,767 +0,0 @@
+-Beta release of the rme96xx (driver for RME 96XX cards like the
+-"Hammerfall" and the "Hammerfall light")
+-
+-Important: The driver module has to be installed on a freshly rebooted system,
+-otherwise the driver might not be able to acquire its buffers.
+-
+-features:
+-
+- - OSS programming interface (i.e. runs with standard OSS soundsoftware)
+- - OSS/Multichannel interface (OSS multichannel is done by just aquiring
+- more than 2 channels). The driver does not use more than one device
+- ( yet .. this feature may be implemented later )
+- - more than one RME card supported
+-
+-The driver uses a specific multichannel interface, which I will document
+-when the driver gets stable. (take a look at the defines in rme96xx.h,
+-which adds blocked multichannel formats i.e instead of
+-lrlrlrlr --> llllrrrr etc.
+-
+-Use the "rmectrl" programm to look at the status of the card ..
+-or use xrmectrl, a GUI interface for the ctrl program.
+-
+-What you can do with the rmectrl program is to set the stereo device for
+-OSS emulation (e.g. if you use SPDIF out).
+-
+-You do:
+-
+-./ctrl offset 24 24
+-
+-which makes the stereo device use channels 25 and 26.
+-
+-Guenter Geiger <geiger at epy.co.at>
+-
+-copy the first part of the attached source code into rmectrl.c
+-and the second part into xrmectrl (or get the program from
+-http://gige.xdv.org/pages/soft/pages/rme)
+-
+-to compile: gcc -o rmectrl rmectrl.c
+------------------------------- snip ------------------------------------
+-
+-#include <stdio.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <sys/ioctl.h>
+-#include <fcntl.h>
+-#include <linux/soundcard.h>
+-#include <math.h>
+-#include <unistd.h>
+-#include <stdlib.h>
+-#include "rme96xx.h"
+-
+-/*
+- remctrl.c
+- (C) 2000 Guenter Geiger <geiger at debian.org>
+- HP20020201 - Heiko Purnhagen <purnhage at tnt.uni-hannover.de>
+-*/
+-
+-/* # define DEVICE_NAME "/dev/mixer" */
+-# define DEVICE_NAME "/dev/mixer1"
+-
+-
+-void usage(void)
+-{
+- fprintf(stderr,"usage: rmectrl [/dev/mixer<n>] [command [options]]\n\n");
+- fprintf(stderr,"where command is one of:\n");
+- fprintf(stderr," help show this help\n");
+- fprintf(stderr," status show status bits\n");
+- fprintf(stderr," control show control bits\n");
+- fprintf(stderr," mix show mixer/offset status\n");
+- fprintf(stderr," master <n> set sync master\n");
+- fprintf(stderr," pro <n> set spdif out pro\n");
+- fprintf(stderr," emphasis <n> set spdif out emphasis\n");
+- fprintf(stderr," dolby <n> set spdif out no audio\n");
+- fprintf(stderr," optout <n> set spdif out optical\n");
+- fprintf(stderr," wordclock <n> set sync wordclock\n");
+- fprintf(stderr," spdifin <n> set spdif in (0=optical,1=coax,2=intern)\n");
+- fprintf(stderr," syncref <n> set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n");
+- fprintf(stderr," adat1cd <n> set ADAT1 on internal CD\n");
+- fprintf(stderr," offset <devnr> <in> <out> set dev (0..3) offset (0..25)\n");
+- exit(-1);
+-}
+-
+-
+-int main(int argc, char* argv[])
+-{
+- int cards;
+- int ret;
+- int i;
+- double ft;
+- int fd, fdwr;
+- int param,orig;
+- rme_status_t stat;
+- rme_ctrl_t ctrl;
+- char *device;
+- int argidx;
+-
+- if (argc < 2)
+- usage();
+-
+- if (*argv[1]=='/') {
+- device = argv[1];
+- argidx = 2;
+- }
+- else {
+- device = DEVICE_NAME;
+- argidx = 1;
+- }
+-
+- fprintf(stdout,"mixer device %s\n",device);
+- if ((fd = open(device,O_RDONLY)) < 0) {
+- fprintf(stdout,"opening device failed\n");
+- exit(-1);
+- }
+-
+- if ((fdwr = open(device,O_WRONLY)) < 0) {
+- fprintf(stdout,"opening device failed\n");
+- exit(-1);
+- }
+-
+- if (argc < argidx+1)
+- usage();
+-
+- if (!strcmp(argv[argidx],"help"))
+- usage();
+- if (!strcmp(argv[argidx],"-h"))
+- usage();
+- if (!strcmp(argv[argidx],"--help"))
+- usage();
+-
+- if (!strcmp(argv[argidx],"status")) {
+- ioctl(fd,SOUND_MIXER_PRIVATE2,&stat);
+- fprintf(stdout,"stat.irq %d\n",stat.irq);
+- fprintf(stdout,"stat.lockmask %d\n",stat.lockmask);
+- fprintf(stdout,"stat.sr48 %d\n",stat.sr48);
+- fprintf(stdout,"stat.wclock %d\n",stat.wclock);
+- fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint);
+- fprintf(stdout,"stat.syncmask %d\n",stat.syncmask);
+- fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed);
+- fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy);
+- fprintf(stdout,"stat.tc_out %d\n",stat.tc_out);
+- fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate);
+- fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error);
+- fprintf(stdout,"stat.bufid %d\n",stat.bufid);
+- fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"control")) {
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- fprintf(stdout,"ctrl.start %d\n",ctrl.start);
+- fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency);
+- fprintf(stdout,"ctrl.master %d\n",ctrl.master);
+- fprintf(stdout,"ctrl.ie %d\n",ctrl.ie);
+- fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48);
+- fprintf(stdout,"ctrl.spare %d\n",ctrl.spare);
+- fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed);
+- fprintf(stdout,"ctrl.pro %d\n",ctrl.pro);
+- fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis);
+- fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby);
+- fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out);
+- fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock);
+- fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in);
+- fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref);
+- fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset);
+- fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select);
+- fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock);
+- fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write);
+- fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"mix")) {
+- rme_mixer mix;
+- int i;
+-
+- for (i=0; i<4; i++) {
+- mix.devnr = i;
+- ioctl(fd,SOUND_MIXER_PRIVATE1,&mix);
+- if (mix.devnr == i) {
+- fprintf(stdout,"devnr %d\n",mix.devnr);
+- fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset);
+- fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset);
+- }
+- }
+- exit (0);
+- }
+-
+-/* the control flags */
+-
+- if (argc < argidx+2)
+- usage();
+-
+- if (!strcmp(argv[argidx],"master")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("master = %d\n",val);
+- ctrl.master = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"pro")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("pro = %d\n",val);
+- ctrl.pro = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"emphasis")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("emphasis = %d\n",val);
+- ctrl.emphasis = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"dolby")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("dolby = %d\n",val);
+- ctrl.dolby = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"optout")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("optout = %d\n",val);
+- ctrl.opt_out = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"wordclock")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("wordclock = %d\n",val);
+- ctrl.wordclock = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"spdifin")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("spdifin = %d\n",val);
+- ctrl.spdif_in = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"syncref")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("syncref = %d\n",val);
+- ctrl.sync_ref = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+- if (!strcmp(argv[argidx],"adat1cd")) {
+- int val = atoi(argv[argidx+1]);
+- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+- printf("adat1cd = %d\n",val);
+- ctrl.adat1_cd = val;
+- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+- exit (0);
+- }
+-
+-/* setting offset */
+-
+- if (argc < argidx+4)
+- usage();
+-
+- if (!strcmp(argv[argidx],"offset")) {
+- rme_mixer mix;
+-
+- mix.devnr = atoi(argv[argidx+1]);
+-
+- mix.i_offset = atoi(argv[argidx+2]);
+- mix.o_offset = atoi(argv[argidx+3]);
+- ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix);
+- fprintf(stdout,"devnr %d\n",mix.devnr);
+- fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset);
+- fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset);
+- exit (0);
+- }
+-
+- usage();
+- exit (0); /* to avoid warning */
+-}
+-
+-
+----------------------------- <snip> --------------------------------
+-#!/usr/bin/wish
+-
+-# xrmectrl
+-# (C) 2000 Guenter Geiger <geiger at debian.org>
+-# HP20020201 - Heiko Purnhagen <purnhage at tnt.uni-hannover.de>
+-
+-#set defaults "-relief ridged"
+-set CTRLPROG "./rmectrl"
+-if {$argc} {
+- set CTRLPROG "$CTRLPROG $argv"
+-}
+-puts "CTRLPROG $CTRLPROG"
+-
+-frame .butts
+-button .butts.exit -text "Exit" -command "exit" -relief ridge
+-#button .butts.state -text "State" -command "get_all"
+-
+-pack .butts.exit -side left
+-pack .butts -side bottom
+-
+-
+-#
+-# STATUS
+-#
+-
+-frame .status
+-
+-# Sampling Rate
+-
+-frame .status.sr
+-label .status.sr.text -text "Sampling Rate" -justify left
+-radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times
+-radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times
+-radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times
+-radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw -variable srate -value 96000 -font times
+-
+-pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3
+-
+-# Lock
+-
+-frame .status.lock
+-label .status.lock.text -text "Lock" -justify left
+-checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times
+-checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times
+-checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times
+-
+-pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3
+-
+-# Sync
+-
+-frame .status.sync
+-label .status.sync.text -text "Sync" -justify left
+-checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times
+-checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times
+-checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times
+-
+-pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3
+-
+-# Timecode
+-
+-frame .status.tc
+-label .status.tc.text -text "Timecode" -justify left
+-checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times
+-checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times
+-checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times
+-
+-pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3
+-
+-# SPDIF In
+-
+-frame .status.spdif
+-label .status.spdif.text -text "SPDIF In" -justify left
+-label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times
+-checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times
+-
+-pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3
+-
+-pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1
+-
+-
+-#
+-# CONTROL
+-#
+-
+-proc setprof {} {
+- global CTRLPROG
+- global spprof
+- exec $CTRLPROG pro $spprof
+-}
+-
+-proc setemph {} {
+- global CTRLPROG
+- global spemph
+- exec $CTRLPROG emphasis $spemph
+-}
+-
+-proc setnoaud {} {
+- global CTRLPROG
+- global spnoaud
+- exec $CTRLPROG dolby $spnoaud
+-}
+-
+-proc setoptical {} {
+- global CTRLPROG
+- global spoptical
+- exec $CTRLPROG optout $spoptical
+-}
+-
+-proc setspdifin {} {
+- global CTRLPROG
+- global spdifin
+- exec $CTRLPROG spdifin [expr $spdifin - 1]
+-}
+-
+-proc setsyncsource {} {
+- global CTRLPROG
+- global syncsource
+- exec $CTRLPROG syncref [expr $syncsource -1]
+-}
+-
+-
+-proc setmaster {} {
+- global CTRLPROG
+- global master
+- exec $CTRLPROG master $master
+-}
+-
+-proc setwordclock {} {
+- global CTRLPROG
+- global wordclock
+- exec $CTRLPROG wordclock $wordclock
+-}
+-
+-proc setadat1cd {} {
+- global CTRLPROG
+- global adat1cd
+- exec $CTRLPROG adat1cd $adat1cd
+-}
+-
+-
+-frame .control
+-
+-# SPDIF In & SPDIF Out
+-
+-
+-frame .control.spdif
+-
+-frame .control.spdif.in
+-label .control.spdif.in.text -text "SPDIF In" -justify left
+-radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times
+-radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times
+-radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times
+-
+-checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times
+-
+-pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd
+-
+-label .control.spdif.space
+-
+-frame .control.spdif.out
+-label .control.spdif.out.text -text "SPDIF Out" -justify left
+-checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times
+-checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times
+-checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times
+-checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times
+-
+-pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom
+-
+-pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1
+-
+-# Sync Mode & Sync Source
+-
+-frame .control.sync
+-frame .control.sync.mode
+-label .control.sync.mode.text -text "Sync Mode" -justify left
+-checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times
+-checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times
+-
+-pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc
+-
+-label .control.sync.space
+-
+-frame .control.sync.src
+-label .control.sync.src.text -text "Sync Source" -justify left
+-radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times
+-radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times
+-radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times
+-radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times
+-
+-pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom
+-
+-pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1
+-
+-label .control.space -text "" -width 10
+-
+-# Buffer Size
+-
+-frame .control.buf
+-label .control.buf.text -text "Buffer Size (Latency)" -justify left
+-radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times
+-radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times
+-radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times
+-radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times
+-radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times
+-radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times
+-radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times
+-radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times
+-
+-pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3
+-
+-# Offset
+-
+-frame .control.offset
+-
+-frame .control.offset.in
+-label .control.offset.in.text -text "Offset In" -justify left
+-label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
+-label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
+-label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
+-label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
+-
+-pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3
+-
+-label .control.offset.space
+-
+-frame .control.offset.out
+-label .control.offset.out.text -text "Offset Out" -justify left
+-label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
+-label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
+-label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
+-label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
+-
+-pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom
+-
+-pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1
+-
+-
+-pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1
+-
+-
+-label .statustext -text Status -justify center -relief ridge
+-label .controltext -text Control -justify center -relief ridge
+-
+-label .statusspace
+-label .controlspace
+-
+-pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1
+-
+-
+-proc get_bit {output sstr} {
+- set idx1 [string last [concat $sstr 1] $output]
+- set idx1 [expr $idx1 != -1]
+- return $idx1
+-}
+-
+-proc get_val {output sstr} {
+- set val [string wordend $output [string last $sstr $output]]
+- set val [string range $output $val [expr $val+1]]
+- return $val
+-}
+-
+-proc get_val2 {output sstr} {
+- set val [string wordend $output [string first $sstr $output]]
+- set val [string range $output $val [expr $val+2]]
+- return $val
+-}
+-
+-proc get_control {} {
+- global spprof
+- global spemph
+- global spnoaud
+- global spoptical
+- global spdifin
+- global ssrate
+- global master
+- global wordclock
+- global syncsource
+- global CTRLPROG
+-
+- set f [open "| $CTRLPROG control" r+]
+- set ooo [read $f 1000]
+- close $f
+-# puts $ooo
+-
+- set spprof [ get_bit $ooo "pro"]
+- set spemph [ get_bit $ooo "emphasis"]
+- set spnoaud [ get_bit $ooo "dolby"]
+- set spoptical [ get_bit $ooo "opt_out"]
+- set spdifin [ expr [ get_val $ooo "spdif_in"] + 1]
+- set ssrate [ expr [ get_val $ooo "latency"] + 1]
+- set master [ expr [ get_val $ooo "master"]]
+- set wordclock [ expr [ get_val $ooo "wordclock"]]
+- set syncsource [ expr [ get_val $ooo "sync_ref"] + 1]
+-}
+-
+-proc get_status {} {
+- global srate
+- global ctrlcom
+-
+- global adatlock1
+- global adatlock2
+- global adatlock3
+-
+- global adatsync1
+- global adatsync2
+- global adatsync3
+-
+- global tcbusy
+- global tcout
+- global tcvalid
+-
+- global spdiferr
+- global crystal
+- global .status.spdif.text
+- global CTRLPROG
+-
+-
+- set f [open "| $CTRLPROG status" r+]
+- set ooo [read $f 1000]
+- close $f
+-# puts $ooo
+-
+-# samplerate
+-
+- set idx1 [string last "sr48 1" $ooo]
+- set idx2 [string last "doublespeed 1" $ooo]
+- if {$idx1 >= 0} {
+- set fact1 48000
+- } else {
+- set fact1 44100
+- }
+-
+- if {$idx2 >= 0} {
+- set fact2 2
+- } else {
+- set fact2 1
+- }
+- set srate [expr $fact1 * $fact2]
+-# ADAT lock
+-
+- set val [get_val $ooo lockmask]
+- set adatlock1 0
+- set adatlock2 0
+- set adatlock3 0
+- if {[expr $val & 1]} {
+- set adatlock3 1
+- }
+- if {[expr $val & 2]} {
+- set adatlock2 1
+- }
+- if {[expr $val & 4]} {
+- set adatlock1 1
+- }
+-
+-# ADAT sync
+- set val [get_val $ooo syncmask]
+- set adatsync1 0
+- set adatsync2 0
+- set adatsync3 0
+-
+- if {[expr $val & 1]} {
+- set adatsync3 1
+- }
+- if {[expr $val & 2]} {
+- set adatsync2 1
+- }
+- if {[expr $val & 4]} {
+- set adatsync1 1
+- }
+-
+-# TC busy
+-
+- set tcbusy [get_bit $ooo "busy"]
+- set tcout [get_bit $ooo "out"]
+- set tcvalid [get_bit $ooo "valid"]
+- set spdiferr [expr [get_bit $ooo "spdif_error"] == 0]
+-
+-# 000=64kHz, 100=88.2kHz, 011=96kHz
+-# 111=32kHz, 110=44.1kHz, 101=48kHz
+-
+- set val [get_val $ooo crystalrate]
+-
+- set crystal "--.- kHz"
+- if {$val == 0} {
+- set crystal "64 kHz"
+- }
+- if {$val == 4} {
+- set crystal "88.2 kHz"
+- }
+- if {$val == 3} {
+- set crystal "96 kHz"
+- }
+- if {$val == 7} {
+- set crystal "32 kHz"
+- }
+- if {$val == 6} {
+- set crystal "44.1 kHz"
+- }
+- if {$val == 5} {
+- set crystal "48 kHz"
+- }
+- .status.spdif.sr configure -text $crystal
+-}
+-
+-proc get_offset {} {
+- global inoffset
+- global outoffset
+- global CTRLPROG
+-
+- set f [open "| $CTRLPROG mix" r+]
+- set ooo [read $f 1000]
+- close $f
+-# puts $ooo
+-
+- if { [string match "*devnr*" $ooo] } {
+- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+- set val [get_val2 $ooo i_offset]
+- .control.offset.in.off0 configure -text "dev\#0: $val"
+- set val [get_val2 $ooo o_offset]
+- .control.offset.out.off0 configure -text "dev\#0: $val"
+- } else {
+- .control.offset.in.off0 configure -text "dev\#0: -"
+- .control.offset.out.off0 configure -text "dev\#0: -"
+- }
+- if { [string match "*devnr*" $ooo] } {
+- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+- set val [get_val2 $ooo i_offset]
+- .control.offset.in.off1 configure -text "dev\#1: $val"
+- set val [get_val2 $ooo o_offset]
+- .control.offset.out.off1 configure -text "dev\#1: $val"
+- } else {
+- .control.offset.in.off1 configure -text "dev\#1: -"
+- .control.offset.out.off1 configure -text "dev\#1: -"
+- }
+- if { [string match "*devnr*" $ooo] } {
+- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+- set val [get_val2 $ooo i_offset]
+- .control.offset.in.off2 configure -text "dev\#2: $val"
+- set val [get_val2 $ooo o_offset]
+- .control.offset.out.off2 configure -text "dev\#2: $val"
+- } else {
+- .control.offset.in.off2 configure -text "dev\#2: -"
+- .control.offset.out.off2 configure -text "dev\#2: -"
+- }
+- if { [string match "*devnr*" $ooo] } {
+- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+- set val [get_val2 $ooo i_offset]
+- .control.offset.in.off3 configure -text "dev\#3: $val"
+- set val [get_val2 $ooo o_offset]
+- .control.offset.out.off3 configure -text "dev\#3: $val"
+- } else {
+- .control.offset.in.off3 configure -text "dev\#3: -"
+- .control.offset.out.off3 configure -text "dev\#3: -"
+- }
+-}
+-
+-
+-proc get_all {} {
+-get_status
+-get_control
+-get_offset
+-}
+-
+-# main
+-while {1} {
+- after 200
+- get_all
+- update
+-}
+diff --git a/Documentation/sound/oss/solo1 b/Documentation/sound/oss/solo1
+deleted file mode 100644
+index 6f53d40..0000000
+--- a/Documentation/sound/oss/solo1
++++ /dev/null
+@@ -1,70 +0,0 @@
+-Recording
+----------
+-
+-Recording does not work on the author's card, but there
+-is at least one report of it working on later silicon.
+-The chip behaves differently than described in the data sheet,
+-likely due to a chip bug. Working around this would require
+-the help of ESS (for example by publishing an errata sheet),
+-but ESS has not done so so far.
+-
+-Also, the chip only supports 24 bit addresses for recording,
+-which means it cannot work on some Alpha mainboards.
+-
+-
+-/proc/sound, /dev/sndstat
+--------------------------
+-
+-/proc/sound and /dev/sndstat is not supported by the
+-driver. To find out whether the driver succeeded loading,
+-check the kernel log (dmesg).
+-
+-
+-ALaw/uLaw sample formats
+-------------------------
+-
+-This driver does not support the ALaw/uLaw sample formats.
+-ALaw is the default mode when opening a sound device
+-using OSS/Free. The reason for the lack of support is
+-that the hardware does not support these formats, and adding
+-conversion routines to the kernel would lead to very ugly
+-code in the presence of the mmap interface to the driver.
+-And since xquake uses mmap, mmap is considered important :-)
+-and no sane application uses ALaw/uLaw these days anyway.
+-In short, playing a Sun .au file as follows:
+-
+-cat my_file.au > /dev/dsp
+-
+-does not work. Instead, you may use the play script from
+-Chris Bagwell's sox-12.14 package (or later, available from the URL
+-below) to play many different audio file formats.
+-The script automatically determines the audio format
+-and does do audio conversions if necessary.
+-http://home.sprynet.com/sprynet/cbagwell/projects.html
+-
+-
+-Blocking vs. nonblocking IO
+----------------------------
+-
+-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+-not only during open, but also during read and write.
+-This is an effort to make the sound driver interface more
+-regular. Timidity has problems with this; a patch
+-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+-(Timidity patched will also run on OSS/Free).
+-
+-
+-MIDI UART
+----------
+-
+-The driver supports a simple MIDI UART interface, with
+-no ioctl's supported.
+-
+-
+-MIDI synthesizer
+-----------------
+-
+-The card has an OPL compatible FM synthesizer.
+-
+-Thomas Sailer
+-t.sailer at alumni.ethz.ch
+diff --git a/Documentation/sound/oss/sonicvibes b/Documentation/sound/oss/sonicvibes
+deleted file mode 100644
+index 84dee2e..0000000
+--- a/Documentation/sound/oss/sonicvibes
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/proc/sound, /dev/sndstat
+--------------------------
+-
+-/proc/sound and /dev/sndstat is not supported by the
+-driver. To find out whether the driver succeeded loading,
+-check the kernel log (dmesg).
+-
+-
+-ALaw/uLaw sample formats
+-------------------------
+-
+-This driver does not support the ALaw/uLaw sample formats.
+-ALaw is the default mode when opening a sound device
+-using OSS/Free. The reason for the lack of support is
+-that the hardware does not support these formats, and adding
+-conversion routines to the kernel would lead to very ugly
+-code in the presence of the mmap interface to the driver.
+-And since xquake uses mmap, mmap is considered important :-)
+-and no sane application uses ALaw/uLaw these days anyway.
+-In short, playing a Sun .au file as follows:
+-
+-cat my_file.au > /dev/dsp
+-
+-does not work. Instead, you may use the play script from
+-Chris Bagwell's sox-12.14 package (available from the URL
+-below) to play many different audio file formats.
+-The script automatically determines the audio format
+-and does do audio conversions if necessary.
+-http://home.sprynet.com/sprynet/cbagwell/projects.html
+-
+-
+-Blocking vs. nonblocking IO
+----------------------------
+-
+-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+-not only during open, but also during read and write.
+-This is an effort to make the sound driver interface more
+-regular. Timidity has problems with this; a patch
+-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+-(Timidity patched will also run on OSS/Free).
+-
+-
+-MIDI UART
+----------
+-
+-The driver supports a simple MIDI UART interface, with
+-no ioctl's supported.
+-
+-
+-MIDI synthesizer
+-----------------
+-
+-The card both has an OPL compatible FM synthesizer as well as
+-a wavetable synthesizer.
+-
+-I haven't managed so far to get the OPL synth running.
+-
+-Using the wavetable synthesizer requires allocating
+-1-4MB of physically contiguous memory, which isn't possible
+-currently on Linux without ugly hacks like the bigphysarea
+-patch. Therefore, the driver doesn't support wavetable
+-synthesis.
+-
+-
+-No support from S3
+-------------------
+-
+-I do not get any support from S3. Therefore, the driver
+-still has many problems. For example, although the manual
+-states that the chip should be able to access the sample
+-buffer anywhere in 32bit address space, I haven't managed to
+-get it working with buffers above 16M. Therefore, the card
+-has the same disadvantages as ISA soundcards.
+-
+-Given that the card is also very noisy, and if you haven't
+-already bought it, you should strongly opt for one of the
+-comparatively priced Ensoniq products.
+-
+-
+-Thomas Sailer
+-t.sailer at alumni.ethz.ch
+diff --git a/Documentation/sound/oss/ultrasound b/Documentation/sound/oss/ultrasound
+index 32cd504..eed331c 100644
+--- a/Documentation/sound/oss/ultrasound
++++ b/Documentation/sound/oss/ultrasound
+@@ -19,7 +19,7 @@ db16 ???
+ no_wave_dma option
+
+ This option defaults to a value of 0, which allows the Ultrasound wavetable
+-DSP to use DMA for for playback and downloading samples. This is the same
++DSP to use DMA for playback and downloading samples. This is the same
+ as the old behaviour. If set to 1, no DMA is needed for downloading samples,
+ and allows owners of a GUS MAX to make use of simultaneous digital audio
+ (/dev/dsp), MIDI, and wavetable playback.
+diff --git a/Documentation/sound/oss/vwsnd b/Documentation/sound/oss/vwsnd
+index a6ea0a1..4c6cbdb 100644
+--- a/Documentation/sound/oss/vwsnd
++++ b/Documentation/sound/oss/vwsnd
+@@ -12,7 +12,7 @@ boxes.
+
+ The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio
+ codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also
+-known as Lithium. This driver programs both both chips.
++known as Lithium. This driver programs both chips.
+
+ ==============================================================================
+ QUICK CONFIGURATION
+diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
+index 4b93516..8418d35 100644
+--- a/Documentation/sparc/sbus_drivers.txt
++++ b/Documentation/sparc/sbus_drivers.txt
+@@ -25,8 +25,8 @@ the bits necessary to run your device.
+ used members of this structure, and their typical usage,
+ will be detailed below.
+
+- Here is a piece of skeleton code for perofming a device
+-probe in an SBUS driverunder Linux:
++ Here is a piece of skeleton code for performing a device
++probe in an SBUS driver under Linux:
+
+ static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
+ {
+@@ -98,7 +98,7 @@ in your .remove method.
+
+ Any memory allocated, registers mapped, IRQs registered,
+ etc. must be undone by your .remove method so that all resources
+-of your device are relased by the time it returns.
++of your device are released by the time it returns.
+
+ You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
+ and for_all_sbusdev() interfaces. They are deprecated, will be
+diff --git a/Documentation/sparse.txt b/Documentation/sparse.txt
+index 5a311c3..f9c99c9 100644
+--- a/Documentation/sparse.txt
++++ b/Documentation/sparse.txt
+@@ -69,10 +69,10 @@ recompiled, or use "make C=2" to run spa
+ be recompiled or not. The latter is a fast way to check the whole tree if you
+ have already built it.
+
+-The optional make variable CF can be used to pass arguments to sparse. The
+-build system passes -Wbitwise to sparse automatically. To perform endianness
+-checks, you may define __CHECK_ENDIAN__:
++The optional make variable CHECKFLAGS can be used to pass arguments to sparse.
++The build system passes -Wbitwise to sparse automatically. To perform
++endianness checks, you may define __CHECK_ENDIAN__:
+
+- make C=2 CF="-D__CHECK_ENDIAN__"
++ make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
+
+ These checks are disabled by default as they generate a host of warnings.
+diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
+index 9c45f3d..a1e0ee2 100644
+--- a/Documentation/spi/pxa2xx
++++ b/Documentation/spi/pxa2xx
+@@ -124,12 +124,12 @@ use a value of 8.
+ The "pxa2xx_spi_chip.timeout_microsecs" fields is used to efficiently handle
+ trailing bytes in the SSP receiver fifo. The correct value for this field is
+ dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
+-slave device. Please note the the PXA2xx SSP 1 does not support trailing byte
++slave device. Please note that the PXA2xx SSP 1 does not support trailing byte
+ timeouts and must busy-wait any trailing bytes.
+
+ The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting
+ into internal loopback mode. In this mode the SSP controller internally
+-connects the SSPTX pin the the SSPRX pin. This is useful for initial setup
++connects the SSPTX pin to the SSPRX pin. This is useful for initial setup
+ testing.
+
+ The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
+@@ -208,7 +208,7 @@ DMA and PIO I/O Support
+ -----------------------
+ The pxa2xx_spi driver support both DMA and interrupt driven PIO message
+ transfers. The driver defaults to PIO mode and DMA transfers must enabled by
+-setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and and
++setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and
+ ensuring that the "pxa2xx_spi_chip.dma_burst_size" field is non-zero. The DMA
+ mode support both coherent and stream based DMA mappings.
+
+diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
+index 068732d..7279579 100644
+--- a/Documentation/spi/spi-summary
++++ b/Documentation/spi/spi-summary
+@@ -262,7 +262,7 @@ NON-STATIC CONFIGURATIONS
+ Developer boards often play by different rules than product boards, and one
+ example is the potential need to hotplug SPI devices and/or controllers.
+
+-For those cases you might need to use use spi_busnum_to_master() to look
++For those cases you might need to use spi_busnum_to_master() to look
+ up the spi bus master, and will likely need spi_new_device() to provide the
+ board info based on the board that was hotplugged. Of course, you'd later
+ call at least spi_unregister_device() when that board is removed.
+@@ -322,7 +322,7 @@ As soon as it enters probe(), the driver
+ the SPI device using "struct spi_message". When remove() returns,
+ the driver guarantees that it won't submit any more such messages.
+
+- - An spi_message is a sequence of of protocol operations, executed
++ - An spi_message is a sequence of protocol operations, executed
+ as one atomic sequence. SPI driver controls include:
+
+ + when bidirectional reads and writes start ... by how its
+diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
+index e409e5d..02a4812 100644
+--- a/Documentation/stable_kernel_rules.txt
++++ b/Documentation/stable_kernel_rules.txt
+@@ -4,7 +4,7 @@ Rules on what kind of patches are accept
+ "-stable" tree:
+
+ - It must be obviously correct and tested.
+- - It can not be bigger than 100 lines, with context.
++ - It cannot be bigger than 100 lines, with context.
+ - It must fix only one thing.
+ - It must fix a real bug that bothers people (not a, "This could be a
+ problem..." type thing).
+@@ -14,7 +14,7 @@ Rules on what kind of patches are accept
+ critical.
+ - No "theoretical race condition" issues, unless an explanation of how the
+ race can be exploited is also provided.
+- - It can not contain any "trivial" fixes in it (spelling changes,
++ - It cannot contain any "trivial" fixes in it (spelling changes,
+ whitespace cleanups, etc).
+ - It must be accepted by the relevant subsystem maintainer.
+ - It must follow the Documentation/SubmittingPatches rules.
+diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
+index 89bf8c2..0bc7f1e 100644
+--- a/Documentation/sysctl/kernel.txt
++++ b/Documentation/sysctl/kernel.txt
+@@ -86,7 +86,7 @@ valid for 30 seconds.
+ core_pattern:
+
+ core_pattern is used to specify a core dumpfile pattern name.
+-. max length 64 characters; default value is "core"
++. max length 128 characters; default value is "core"
+ . core_pattern is used as a pattern template for the output filename;
+ certain string patterns (beginning with '%') are substituted with
+ their actual values.
+@@ -105,6 +105,9 @@ core_pattern is used to specify a core d
+ %h hostname
+ %e executable filename
+ %<OTHER> both are dropped
++. If the first character of the pattern is a '|', the kernel will treat
++ the rest of the pattern as a command to run. The core dump will be
++ written to the standard input of that program instead of to a file.
+
+ ==============================================================
+
+diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
+index 7cee902..20d0d79 100644
+--- a/Documentation/sysctl/vm.txt
++++ b/Documentation/sysctl/vm.txt
+@@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/
+ - drop-caches
+ - zone_reclaim_mode
+ - min_unmapped_ratio
++- min_slab_ratio
+ - panic_on_oom
+
+ ==============================================================
+@@ -138,7 +139,6 @@ This is value ORed together of
+ 1 = Zone reclaim on
+ 2 = Zone reclaim writes dirty pages out
+ 4 = Zone reclaim swaps pages
+-8 = Also do a global slab reclaim pass
+
+ zone_reclaim_mode is set during bootup to 1 if it is determined that pages
+ from remote zones will cause a measurable performance reduction. The
+@@ -162,18 +162,13 @@ Allowing regular swap effectively restri
+ node unless explicitly overridden by memory policies or cpuset
+ configurations.
+
+-It may be advisable to allow slab reclaim if the system makes heavy
+-use of files and builds up large slab caches. However, the slab
+-shrink operation is global, may take a long time and free slabs
+-in all nodes of the system.
+-
+ =============================================================
+
+ min_unmapped_ratio:
+
+ This is available only on NUMA kernels.
+
+-A percentage of the file backed pages in each zone. Zone reclaim will only
++A percentage of the total pages in each zone. Zone reclaim will only
+ occur if more than this percentage of pages are file backed and unmapped.
+ This is to insure that a minimal amount of local pages is still available for
+ file I/O even if the node is overallocated.
+@@ -182,6 +177,24 @@ The default is 1 percent.
+
+ =============================================================
+
++min_slab_ratio:
++
++This is available only on NUMA kernels.
++
++A percentage of the total pages in each zone. On Zone reclaim
++(fallback from the local zone occurs) slabs will be reclaimed if more
++than this percentage of pages in a zone are reclaimable slab pages.
++This insures that the slab growth stays under control even in NUMA
++systems that rarely perform global reclaim.
++
++The default is 5 percent.
++
++Note that slab reclaim is triggered in a per zone / node fashion.
++The process of reclaiming slab memory is currently not node specific
++and may not be fast.
++
++=============================================================
++
+ panic_on_oom
+
+ This enables or disables panic on out-of-memory feature. If this is set to 1,
+diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt
+index 544430e..b60590e 100644
+--- a/Documentation/uml/UserModeLinux-HOWTO.txt
++++ b/Documentation/uml/UserModeLinux-HOWTO.txt
+@@ -157,7 +157,7 @@
+ 13. What to do when UML doesn't work
+
+ 13.1 Strange compilation errors when you build from source
+- 13.2 UML hangs on boot after mounting devfs
++ 13.2 (obsolete)
+ 13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem
+ 13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid'
+ 13.5 UML doesn't work when /tmp is an NFS filesystem
+@@ -379,31 +379,6 @@
+ bug fixes and enhancements that have gone into subsequent releases.
+
+
+- If you build your own kernel, and want to boot it from one of the
+- filesystems distributed from this site, then, in nearly all cases,
+- devfs must be compiled into the kernel and mounted at boot time. The
+- exception is the SuSE filesystem. For this, devfs must either not be
+- in the kernel at all, or "devfs=nomount" must be on the kernel command
+- line. Any disagreement between the kernel and the filesystem being
+- booted about whether devfs is being used will result in the boot
+- getting no further than single-user mode.
+-
+-
+- If you don't want to use devfs, you can remove the need for it from a
+- filesystem by copying /dev from someplace, making a bunch of /dev/ubd
+- devices:
+-
+-
+- UML# for i in 0 1 2 3 4 5 6 7; do mknod ubd$i b 98 $i; done
+-
+-
+-
+-
+- and changing /etc/fstab and /etc/inittab to refer to the non-devfs
+- devices.
+-
+-
+-
+ 22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess
+
+ UML modules are built in the same way as the native kernel (with the
+@@ -839,9 +814,7 @@
+ +o None - device=none
+
+
+- This causes the device to disappear. If you are using devfs, the
+- device will not appear in /dev. If not, then attempts to open it
+- will return -ENODEV.
++ This causes the device to disappear.
+
+
+
+@@ -1047,7 +1020,7 @@
+
+ Note that the IP address you assign to the host end of the tap device
+ must be different than the IP you assign to the eth device inside UML.
+- If you are short on IPs and don't want to comsume two per UML, then
++ If you are short on IPs and don't want to consume two per UML, then
+ you can reuse the host's eth IP address for the host ends of the tap
+ devices. Internally, the UMLs must still get unique IPs for their eth
+ devices. You can also give the UMLs non-routable IPs (192.168.x.x or
+@@ -2058,7 +2031,7 @@
+ there are multiple COWs associated with a backing file, a -d merge of
+ one of them will invalidate all of the others. However, it is
+ convenient if you're short of disk space, and it should also be
+- noticably faster than a non-destructive merge.
++ noticeably faster than a non-destructive merge.
+
+
+
+@@ -3898,29 +3871,6 @@
+
+
+
+- 1133..22.. UUMMLL hhaannggss oonn bboooott aafftteerr mmoouunnttiinngg ddeevvffss
+-
+- The boot looks like this:
+-
+-
+- VFS: Mounted root (ext2 filesystem) readonly.
+- Mounted devfs on /dev
+-
+-
+-
+-
+- You're probably running a recent distribution on an old machine. I
+- saw this with the RH7.1 filesystem running on a Pentium. The shared
+- library loader, ld.so, was executing an instruction (cmove) which the
+- Pentium didn't support. That instruction was apparently added later.
+- If you run UML under the debugger, you'll see the hang caused by one
+- instruction causing an infinite SIGILL stream.
+-
+-
+- The fix is to boot UML on an older filesystem.
+-
+-
+-
+ 1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss--
+ tteemm
+
+@@ -3953,9 +3903,9 @@
+
+ 1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm
+
+- This seems to be a similar situation with the resierfs problem above.
++ This seems to be a similar situation with the ReiserFS problem above.
+ Some versions of NFS seems not to handle mmap correctly, which UML
+- depends on. The workaround is have /tmp be non-NFS directory.
++ depends on. The workaround is have /tmp be a non-NFS directory.
+
+
+ 1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt
+@@ -4022,7 +3972,7 @@
+ nneett
+
+ If you can connect to the host, and the host can connect to UML, but
+- you can not connect to any other machines, then you may need to enable
++ you cannot connect to any other machines, then you may need to enable
+ IP Masquerading on the host. Usually this is only experienced when
+ using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML
+ networking, rather than the public address space that your host is
+@@ -4671,7 +4621,7 @@
+ Chris Reahard built a specialized root filesystem for running a DNS
+ server jailed inside UML. It's available from the download
+ <http://user-mode-linux.sourceforge.net/dl-sf.html> page in the Jail
+- Filesysems section.
++ Filesystems section.
+
+
+
+diff --git a/Documentation/unshare.txt b/Documentation/unshare.txt
+index 90a5e9e..a864351 100644
+--- a/Documentation/unshare.txt
++++ b/Documentation/unshare.txt
+@@ -260,7 +260,7 @@ items:
+ a pointer to it.
+
+ 7.4) Appropriately modify architecture specific code to register the
+- the new system call.
++ new system call.
+
+ 8) Test Specification
+ ---------------------
+diff --git a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt
+index a49e5f2..8ffce74 100644
+--- a/Documentation/usb/URB.txt
++++ b/Documentation/usb/URB.txt
+@@ -184,7 +184,7 @@ you can pass information to the completi
+ Note that even when an error (or unlink) is reported, data may have been
+ transferred. That's because USB transfers are packetized; it might take
+ sixteen packets to transfer your 1KByte buffer, and ten of them might
+-have transferred succesfully before the completion was called.
++have transferred successfully before the completion was called.
+
+
+ NOTE: ***** WARNING *****
+diff --git a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt
+index 8ef45ea..737d610 100644
+--- a/Documentation/usb/acm.txt
++++ b/Documentation/usb/acm.txt
+@@ -49,20 +49,6 @@ Abstract Control Model (USB CDC ACM) spe
+ Unfortunately many modems and most ISDN TAs use proprietary interfaces and
+ thus won't work with this drivers. Check for ACM compliance before buying.
+
+- The driver (with devfs) creates these devices in /dev/usb/acm:
+-
+- crw-r--r-- 1 root root 166, 0 Apr 1 10:49 0
+- crw-r--r-- 1 root root 166, 1 Apr 1 10:49 1
+- crw-r--r-- 1 root root 166, 2 Apr 1 10:49 2
+-
+- And so on, up to 31, with the limit being possible to change in acm.c to up
+-to 256, so you can use up to 256 USB modems with one computer (you'll need
+-three USB cards for that, though).
+-
+- If you don't use devfs, then you can create device nodes with the same
+-minor/major numbers anywhere you want, but either the above location or
+-/dev/usb/ttyACM0 is preferred.
+-
+ To use the modems you need these modules loaded:
+
+ usbcore.ko
+diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
+index 867f4c3..9cf83e8 100644
+--- a/Documentation/usb/error-codes.txt
++++ b/Documentation/usb/error-codes.txt
+@@ -98,13 +98,13 @@ one or more packets could finish before
+ error, a failure to respond (often caused by
+ device disconnect), or some other fault.
+
+--ETIMEDOUT (**) No response packet received within the prescribed
++-ETIME (**) No response packet received within the prescribed
+ bus turn-around time. This error may instead be
+ reported as -EPROTO or -EILSEQ.
+
+- Note that the synchronous USB message functions
+- also use this code to indicate timeout expired
+- before the transfer completed.
++-ETIMEDOUT Synchronous USB message functions use this code
++ to indicate timeout expired before the transfer
++ completed, and no other error was reported by HC.
+
+ -EPIPE (**) Endpoint stalled. For non-control endpoints,
+ reset this status with usb_clear_halt().
+@@ -126,7 +126,7 @@ one or more packets could finish before
+ urb->transfer_flags.
+
+ -ENODEV Device was removed. Often preceded by a burst of
+- other errors, since the hub driver does't detect
++ other errors, since the hub driver doesn't detect
+ device removal events immediately.
+
+ -EXDEV ISO transfer only partially completed
+@@ -145,7 +145,7 @@ one or more packets could finish before
+ hardware problems such as bad devices (including firmware) or cables.
+
+ (**) This is also one of several codes that different kinds of host
+-controller use to to indicate a transfer has failed because of device
++controller use to indicate a transfer has failed because of device
+ disconnect. In the interval before the hub driver starts disconnect
+ processing, devices may receive such fault reports for every request.
+
+@@ -163,6 +163,3 @@ usb_get_*/usb_set_*():
+ usb_control_msg():
+ usb_bulk_msg():
+ -ETIMEDOUT Timeout expired before the transfer completed.
+- In the future this code may change to -ETIME,
+- whose definition is a closer match to this sort
+- of error.
+diff --git a/Documentation/usb/hiddev.txt b/Documentation/usb/hiddev.txt
+index cd6fb4b..6a79075 100644
+--- a/Documentation/usb/hiddev.txt
++++ b/Documentation/usb/hiddev.txt
+@@ -118,7 +118,7 @@ index, the ioctl returns -1 and sets err
+ HIDIOCGDEVINFO - struct hiddev_devinfo (read)
+ Gets a hiddev_devinfo structure which describes the device.
+
+-HIDIOCGSTRING - struct struct hiddev_string_descriptor (read/write)
++HIDIOCGSTRING - struct hiddev_string_descriptor (read/write)
+ Gets a string descriptor from the device. The caller must fill in the
+ "index" field to indicate which descriptor should be returned.
+
+diff --git a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt
+index cd806bf..e43cfff 100644
+--- a/Documentation/usb/mtouchusb.txt
++++ b/Documentation/usb/mtouchusb.txt
+@@ -11,7 +11,7 @@ CHANGES
+ Changed reset from standard USB dev reset to vendor reset
+ Changed data sent to host from compensated to raw coordinates
+ Eliminated vendor/product module params
+- Performed multiple successfull tests with an EXII-5010UC
++ Performed multiple successful tests with an EXII-5010UC
+
+ SUPPORTED HARDWARE:
+
+@@ -38,7 +38,7 @@ This driver appears to be one of possibl
+ drivers. Although 3M produces a binary only driver available for
+ download, I persist in updating this driver since I would like to use the
+ touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
+-logical choice is to use Linux Imput.
++logical choice is to use Linux Input.
+
+ Currently there is no way to calibrate the device via this driver. Even if
+ the device could be calibrated, the driver pulls to raw coordinate data from
+@@ -63,7 +63,7 @@ TODO:
+ Implement a control urb again to handle requests to and from the device
+ such as calibration, etc once/if it becomes available.
+
+-DISCLAMER:
++DISCLAIMER:
+
+ I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support
+ this driver! If you want touch drivers only supported within X, please go to:
+diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
+index 02b0f7b..50436e1 100644
+--- a/Documentation/usb/usb-serial.txt
++++ b/Documentation/usb/usb-serial.txt
+@@ -13,7 +13,6 @@ CONFIGURATION
+ Currently the driver can handle up to 256 different serial interfaces at
+ one time.
+
+- If you are not using devfs:
+ The major number that the driver uses is 188 so to use the driver,
+ create the following nodes:
+ mknod /dev/ttyUSB0 c 188 0
+@@ -26,10 +25,6 @@ CONFIGURATION
+ mknod /dev/ttyUSB254 c 188 254
+ mknod /dev/ttyUSB255 c 188 255
+
+- If you are using devfs:
+- The devices supported by this driver will show up as
+- /dev/usb/tts/{0,1,...}
+-
+ When the device is connected and recognized by the driver, the driver
+ will print to the system log, which node(s) the device has been bound
+ to.
+@@ -228,7 +223,7 @@ Cypress M8 CY4601 Family Serial Driver
+ -Cypress HID->COM RS232 adapter
+
+ Note: Cypress Semiconductor claims no affiliation with the
+- the hid->com device.
++ hid->com device.
+
+ Most devices using chipsets under the CY4601 family should
+ work with the driver. As long as they stay true to the CY4601
+@@ -277,7 +272,7 @@ Digi AccelePort Driver
+ work under SMP with the uhci driver.
+
+ The driver is generally working, though we still have a few more ioctls
+- to implement and final testing and debugging to do. The paralled port
++ to implement and final testing and debugging to do. The parallel port
+ on the USB 2 is supported as a serial to parallel converter; in other
+ words, it appears as another USB serial port on Linux, even though
+ physically it is really a parallel port. The Digi Acceleport USB 8
+@@ -427,13 +422,12 @@ Options supported:
+ debug - extra verbose debugging info
+ (default: 0; nonzero enables)
+ use_lowlatency - use low_latency flag to speed up tty layer
+- when reading from from the device.
++ when reading from the device.
+ (default: 0; nonzero enables)
+
+ See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
+ information on this driver.
+
+-
+ Generic Serial driver
+
+ If your device is not one of the above listed devices, compatible with
+diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
+index 00d9a1f..8755b3e 100644
+--- a/Documentation/video4linux/CARDLIST.cx88
++++ b/Documentation/video4linux/CARDLIST.cx88
+@@ -7,16 +7,16 @@
+ 6 -> AverTV Studio 303 (M126) [1461:000b]
+ 7 -> MSI TV- at nywhere Master [1462:8606]
+ 8 -> Leadtek Winfast DV2000 [107d:6620]
+- 9 -> Leadtek PVR 2000 [107d:663b,107d:663C]
++ 9 -> Leadtek PVR 2000 [107d:663b,107d:663c,107d:6632]
+ 10 -> IODATA GV-VCP3/PCI [10fc:d003]
+ 11 -> Prolink PlayTV PVR
+- 12 -> ASUS PVR-416 [1043:4823]
++ 12 -> ASUS PVR-416 [1043:4823,1461:c111]
+ 13 -> MSI TV- at nywhere
+ 14 -> KWorld/VStream XPert DVB-T [17de:08a6]
+ 15 -> DViCO FusionHDTV DVB-T1 [18ac:db00]
+ 16 -> KWorld LTV883RF
+ 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810,18ac:d800]
+- 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001]
++ 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001,0070:9000]
+ 19 -> Conexant DVB-T reference design [14f1:0187]
+ 20 -> Provideo PV259 [1540:2580]
+ 21 -> DViCO FusionHDTV DVB-T Plus [18ac:db10,18ac:db11]
+@@ -41,7 +41,7 @@
+ 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
+ 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
+ 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019]
+- 43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1]
++ 43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1,12ab:2300]
+ 44 -> DViCO FusionHDTV DVB-T Dual Digital [18ac:db50,18ac:db54]
+ 45 -> KWorld HardwareMpegTV XPert [17de:0840]
+ 46 -> DViCO FusionHDTV DVB-T Hybrid [18ac:db40,18ac:db44]
+@@ -51,3 +51,7 @@
+ 50 -> NPG Tech Real TV FM Top 10 [14f1:0842]
+ 51 -> WinFast DTV2000 H [107d:665e]
+ 52 -> Geniatech DVB-S [14f1:0084]
++ 53 -> Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T [0070:1404,0070:1400,0070:1401,0070:1402]
++ 54 -> Norwood Micro TV Tuner
++ 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980]
++ 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602]
+diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
+index 9068b66..53ce6a3 100644
+--- a/Documentation/video4linux/CARDLIST.saa7134
++++ b/Documentation/video4linux/CARDLIST.saa7134
+@@ -58,7 +58,7 @@
+ 57 -> Avermedia AVerTV GO 007 FM [1461:f31f]
+ 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370]
+ 59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
+- 60 -> LifeView/Typhoon FlyDVB-T Duo Cardbus [5168:0502,4e42:0502]
++ 60 -> LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus [5168:0502,4e42:0502,1489:0502]
+ 61 -> Philips TOUGH DVB-T reference design [1131:2004]
+ 62 -> Compro VideoMate TV Gold+II
+ 63 -> Kworld Xpert TV PVR7134
+@@ -83,7 +83,7 @@
+ 82 -> MSI TV at Anywhere plus [1462:6231]
+ 83 -> Terratec Cinergy 250 PCI TV [153b:1160]
+ 84 -> LifeView FlyDVB Trio [5168:0319]
+- 85 -> AverTV DVB-T 777 [1461:2c05]
++ 85 -> AverTV DVB-T 777 [1461:2c05,1461:2c05]
+ 86 -> LifeView FlyDVB-T / Genius VideoWonder DVB-T [5168:0301,1489:0301]
+ 87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421]
+ 88 -> Tevion/KWorld DVB-T 220RF [17de:7201]
+@@ -94,3 +94,8 @@
+ 93 -> Medion 7134 Bridge #2 [16be:0005]
+ 94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502]
+ 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138]
++ 96 -> Medion Md8800 Quadro [16be:0007,16be:0008]
++ 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300]
++ 98 -> Proteus Pro 2309 [0919:2003]
++ 99 -> AVerMedia TV Hybrid A16AR [1461:2c00]
++100 -> Asus Europa2 OEM [1043:4860]
+diff --git a/Documentation/video4linux/README.pvrusb2 b/Documentation/video4linux/README.pvrusb2
+index c73a32c..a4b7ae8 100644
+--- a/Documentation/video4linux/README.pvrusb2
++++ b/Documentation/video4linux/README.pvrusb2
+@@ -155,7 +155,7 @@ Source file list / functional overview:
+ pvrusb2-i2c-core.[ch] - This module provides an implementation of a
+ kernel-friendly I2C adaptor driver, through which other external
+ I2C client drivers (e.g. msp3400, tuner, lirc) may connect and
+- operate corresponding chips within the the pvrusb2 device. It is
++ operate corresponding chips within the pvrusb2 device. It is
+ through here that other V4L modules can reach into this driver to
+ operate specific pieces (and those modules are in turn driven by
+ glue logic which is coordinated by pvrusb2-hdw, doled out by
+diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
+index 040a2c8..deb218f 100644
+--- a/Documentation/video4linux/Zoran
++++ b/Documentation/video4linux/Zoran
+@@ -144,7 +144,7 @@ tv broadcast formats all aver the world.
+
+ The CCIR defines parameters needed for broadcasting the signal.
+ The CCIR has defined different standards: A,B,D,E,F,G,D,H,I,K,K1,L,M,N,...
+-The CCIR says not much about about the colorsystem used !!!
++The CCIR says not much about the colorsystem used !!!
+ And talking about a colorsystem says not to much about how it is broadcast.
+
+ The CCIR standards A,E,F are not used any more.
+diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options
+index fc94ff2..bb7c2ca 100644
+--- a/Documentation/video4linux/bttv/Insmod-options
++++ b/Documentation/video4linux/bttv/Insmod-options
+@@ -54,6 +54,12 @@ bttv.o
+ dropouts.
+ chroma_agc=0/1 AGC of chroma signal, off by default.
+ adc_crush=0/1 Luminance ADC crush, on by default.
++ i2c_udelay= Allow reduce I2C speed. Default is 5 usecs
++ (meaning 66,67 Kbps). The default is the
++ maximum supported speed by kernel bitbang
++ algoritm. You may use lower numbers, if I2C
++ messages are lost (16 is known to work on
++ all supported cards).
+
+ bttv_gpio=0/1
+ gpiomask=
+diff --git a/Documentation/video4linux/cx2341x/README.hm12 b/Documentation/video4linux/cx2341x/README.hm12
+new file mode 100644
+index 0000000..0e213ed
+--- /dev/null
++++ b/Documentation/video4linux/cx2341x/README.hm12
+@@ -0,0 +1,116 @@
++The cx23416 can produce (and the cx23415 can also read) raw YUV output. The
++format of a YUV frame is specific to this chip and is called HM12. 'HM' stands
++for 'Hauppauge Macroblock', which is a misnomer as 'Conexant Macroblock' would
++be more accurate.
++
++The format is YUV 4:2:0 which uses 1 Y byte per pixel and 1 U and V byte per
++four pixels.
++
++The data is encoded as two macroblock planes, the first containing the Y
++values, the second containing UV macroblocks.
++
++The Y plane is divided into blocks of 16x16 pixels from left to right
++and from top to bottom. Each block is transmitted in turn, line-by-line.
++
++So the first 16 bytes are the first line of the top-left block, the
++second 16 bytes are the second line of the top-left block, etc. After
++transmitting this block the first line of the block on the right to the
++first block is transmitted, etc.
++
++The UV plane is divided into blocks of 16x8 UV values going from left
++to right, top to bottom. Each block is transmitted in turn, line-by-line.
++
++So the first 16 bytes are the first line of the top-left block and
++contain 8 UV value pairs (16 bytes in total). The second 16 bytes are the
++second line of 8 UV pairs of the top-left block, etc. After transmitting
++this block the first line of the block on the right to the first block is
++transmitted, etc.
++
++The code below is given as an example on how to convert HM12 to separate
++Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels.
++
++The width of a frame is always 720 pixels, regardless of the actual specified
++width.
++
++--------------------------------------------------------------------------
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static unsigned char frame[576*720*3/2];
++static unsigned char framey[576*720];
++static unsigned char frameu[576*720 / 4];
++static unsigned char framev[576*720 / 4];
++
++static void de_macro_y(unsigned char* dst, unsigned char *src, int dstride, int w, int h)
++{
++ unsigned int y, x, i;
++
++ // descramble Y plane
++ // dstride = 720 = w
++ // The Y plane is divided into blocks of 16x16 pixels
++ // Each block in transmitted in turn, line-by-line.
++ for (y = 0; y < h; y += 16) {
++ for (x = 0; x < w; x += 16) {
++ for (i = 0; i < 16; i++) {
++ memcpy(dst + x + (y + i) * dstride, src, 16);
++ src += 16;
++ }
++ }
++ }
++}
++
++static void de_macro_uv(unsigned char *dstu, unsigned char *dstv, unsigned char *src, int dstride, int w, int h)
++{
++ unsigned int y, x, i;
++
++ // descramble U/V plane
++ // dstride = 720 / 2 = w
++ // The U/V values are interlaced (UVUV...).
++ // Again, the UV plane is divided into blocks of 16x16 UV values.
++ // Each block in transmitted in turn, line-by-line.
++ for (y = 0; y < h; y += 16) {
++ for (x = 0; x < w; x += 8) {
++ for (i = 0; i < 16; i++) {
++ int idx = x + (y + i) * dstride;
++
++ dstu[idx+0] = src[0]; dstv[idx+0] = src[1];
++ dstu[idx+1] = src[2]; dstv[idx+1] = src[3];
++ dstu[idx+2] = src[4]; dstv[idx+2] = src[5];
++ dstu[idx+3] = src[6]; dstv[idx+3] = src[7];
++ dstu[idx+4] = src[8]; dstv[idx+4] = src[9];
++ dstu[idx+5] = src[10]; dstv[idx+5] = src[11];
++ dstu[idx+6] = src[12]; dstv[idx+6] = src[13];
++ dstu[idx+7] = src[14]; dstv[idx+7] = src[15];
++ src += 16;
++ }
++ }
++ }
++}
++
++/*************************************************************************/
++int main(int argc, char **argv)
++{
++ FILE *fin;
++ int i;
++
++ if (argc == 1) fin = stdin;
++ else fin = fopen(argv[1], "r");
++
++ if (fin == NULL) {
++ fprintf(stderr, "cannot open input\n");
++ exit(-1);
++ }
++ while (fread(frame, sizeof(frame), 1, fin) == 1) {
++ de_macro_y(framey, frame, 720, 720, 576);
++ de_macro_uv(frameu, framev, frame + 720 * 576, 720 / 2, 720 / 2, 576 / 2);
++ fwrite(framey, sizeof(framey), 1, stdout);
++ fwrite(framev, sizeof(framev), 1, stdout);
++ fwrite(frameu, sizeof(frameu), 1, stdout);
++ }
++ fclose(fin);
++ return 0;
++}
++
++--------------------------------------------------------------------------
+diff --git a/Documentation/video4linux/cx2341x/README.vbi b/Documentation/video4linux/cx2341x/README.vbi
+new file mode 100644
+index 0000000..5807cf1
+--- /dev/null
++++ b/Documentation/video4linux/cx2341x/README.vbi
+@@ -0,0 +1,45 @@
++
++Format of embedded V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data
++=========================================================
++
++This document describes the V4L2_MPEG_STREAM_VBI_FMT_IVTV format of the VBI data
++embedded in an MPEG-2 program stream. This format is in part dictated by some
++hardware limitations of the ivtv driver (the driver for the Conexant cx23415/6
++chips), in particular a maximum size for the VBI data. Anything longer is cut
++off when the MPEG stream is played back through the cx23415.
++
++The advantage of this format is it is very compact and that all VBI data for
++all lines can be stored while still fitting within the maximum allowed size.
++
++The stream ID of the VBI data is 0xBD. The maximum size of the embedded data is
++4 + 43 * 36, which is 4 bytes for a header and 2 * 18 VBI lines with a 1 byte
++header and a 42 bytes payload each. Anything beyond this limit is cut off by
++the cx23415/6 firmware. Besides the data for the VBI lines we also need 36 bits
++for a bitmask determining which lines are captured and 4 bytes for a magic cookie,
++signifying that this data package contains V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data.
++If all lines are used, then there is no longer room for the bitmask. To solve this
++two different magic numbers were introduced:
++
++'itv0': After this magic number two unsigned longs follow. Bits 0-17 of the first
++unsigned long denote which lines of the first field are captured. Bits 18-31 of
++the first unsigned long and bits 0-3 of the second unsigned long are used for the
++second field.
++
++'ITV0': This magic number assumes all VBI lines are captured, i.e. it implicitly
++implies that the bitmasks are 0xffffffff and 0xf.
++
++After these magic cookies (and the 8 byte bitmask in case of cookie 'itv0') the
++captured VBI lines start:
++
++For each line the least significant 4 bits of the first byte contain the data type.
++Possible values are shown in the table below. The payload is in the following 42
++bytes.
++
++Here is the list of possible data types:
++
++#define IVTV_SLICED_TYPE_TELETEXT 0x1 // Teletext (uses lines 6-22 for PAL)
++#define IVTV_SLICED_TYPE_CC 0x4 // Closed Captions (line 21 NTSC)
++#define IVTV_SLICED_TYPE_WSS 0x5 // Wide Screen Signal (line 23 PAL)
++#define IVTV_SLICED_TYPE_VPS 0x7 // Video Programming System (PAL) (line 16)
++
++Hans Verkuil <hverkuil at xs4all.nl>
+diff --git a/Documentation/video4linux/cx2341x/fw-decoder-api.txt b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
+index 9df4fb3..78bf5f2 100644
+--- a/Documentation/video4linux/cx2341x/fw-decoder-api.txt
++++ b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
+@@ -102,7 +102,7 @@ Param[0]
+ Name CX2341X_DEC_GET_XFER_INFO
+ Enum 9/0x09
+ Description
+- This API call may be used to detect an end of stream condtion.
++ This API call may be used to detect an end of stream condition.
+ Result[0]
+ Stream type
+ Result[1]
+diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
+index 001c686..15df0df 100644
+--- a/Documentation/video4linux/cx2341x/fw-encoder-api.txt
++++ b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
+@@ -280,7 +280,7 @@ Param[0]
+ Param[1]
+ Unknown, but leaving this to 0 seems to work best. Indications are that
+ this might have to do with USB support, although passing anything but 0
+- onl breaks things.
++ only breaks things.
+
+ -------------------------------------------------------------------------------
+
+diff --git a/Documentation/video4linux/cx2341x/fw-osd-api.txt b/Documentation/video4linux/cx2341x/fw-osd-api.txt
+index da98ae3..0a602f3 100644
+--- a/Documentation/video4linux/cx2341x/fw-osd-api.txt
++++ b/Documentation/video4linux/cx2341x/fw-osd-api.txt
+@@ -97,7 +97,7 @@ Result[0]
+ Result[1]
+ top left vertical offset
+ Result[2]
+- bottom right hotizontal offset
++ bottom right horizontal offset
+ Result[3]
+ bottom right vertical offset
+
+diff --git a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
+index 93fec32..faccee6 100644
+--- a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
++++ b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
+@@ -30,7 +30,7 @@ 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.
++rate; you get an interrupt when a full DWORD is received.
+ 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.
+diff --git a/Documentation/video4linux/et61x251.txt b/Documentation/video4linux/et61x251.txt
+index cd584f2..1bdee8f 100644
+--- a/Documentation/video4linux/et61x251.txt
++++ b/Documentation/video4linux/et61x251.txt
+@@ -80,7 +80,7 @@ Some of the features of the driver are:
+ high compression quality (see also "Notes for V4L2 application developers"
+ paragraph);
+ - full support for the capabilities of every possible image sensors that can
+- be connected to the ET61X[12]51 bridges, including, for istance, red, green,
++ be connected to the ET61X[12]51 bridges, including, for instance, red, green,
+ blue and global gain adjustments and exposure control (see "Supported
+ devices" paragraph for details);
+ - use of default color settings for sunlight conditions;
+@@ -222,7 +222,7 @@ identifier - of the camera registered as
+ [root at localhost #] echo 1 > i2c_reg
+ [root at localhost #] cat i2c_val
+
+-Note that if the sensor registers can not be read, "cat" will fail.
++Note that if the sensor registers cannot be read, "cat" will fail.
+ To avoid race conditions, all the I/O accesses to the files are serialized.
+
+
+diff --git a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
+index 93fec32..faccee6 100644
+--- a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
++++ b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
+@@ -30,7 +30,7 @@ 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.
++rate; you get an interrupt when a full DWORD is received.
+ 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.
+diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
+index 2137da9..ecb3416 100644
+--- a/Documentation/video4linux/meye.txt
++++ b/Documentation/video4linux/meye.txt
+@@ -29,7 +29,7 @@ driver (PCI vendor/device is 0x136b/0xff
+
+ The third one, present in recent (more or less last year) Picturebooks
+ (C1M* models), is not supported. The manufacturer has given the specs
+-to the developers under a NDA (which allows the develoment of a GPL
++to the developers under a NDA (which allows the development of a GPL
+ driver however), but things are not moving very fast (see
+ http://r-engine.sourceforge.net/) (PCI vendor/device is 0x10cf/0x2011).
+
+diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
+index 1d20895..8cda472 100644
+--- a/Documentation/video4linux/sn9c102.txt
++++ b/Documentation/video4linux/sn9c102.txt
+@@ -60,7 +60,7 @@ It's worth to note that SONiX has never
+ development of this project, despite several requests for enough detailed
+ specifications of the register tables, compression engine and video data format
+ of the above chips. Nevertheless, these informations are no longer necessary,
+-becouse all the aspects related to these chips are known and have been
++because all the aspects related to these chips are known and have been
+ described in detail in this documentation.
+
+ The driver relies on the Video4Linux2 and USB core modules. It has been
+@@ -85,7 +85,7 @@ Some of the features of the driver are:
+ high compression quality (see also "Notes for V4L2 application developers"
+ and "Video frame formats" paragraphs);
+ - full support for the capabilities of many of the possible image sensors that
+- can be connected to the SN9C10x bridges, including, for istance, red, green,
++ can be connected to the SN9C10x bridges, including, for instance, red, green,
+ blue and global gain adjustments and exposure (see "Supported devices"
+ paragraph for details);
+ - use of default color settings for sunlight conditions;
+diff --git a/Documentation/video4linux/w9968cf.txt b/Documentation/video4linux/w9968cf.txt
+index 0d53ce7..e0bba83 100644
+--- a/Documentation/video4linux/w9968cf.txt
++++ b/Documentation/video4linux/w9968cf.txt
+@@ -15,7 +15,7 @@ Index
+ 5. Supported devices
+ 6. Module dependencies
+ 7. Module loading
+-8. Module paramaters
++8. Module parameters
+ 9. Contact information
+ 10. Credits
+
+diff --git a/Documentation/video4linux/zr36120.txt b/Documentation/video4linux/zr36120.txt
+index ac6d92d..1a1c2d0 100644
+--- a/Documentation/video4linux/zr36120.txt
++++ b/Documentation/video4linux/zr36120.txt
+@@ -118,9 +118,9 @@ card is not there, please try if any oth
+ response, and mail me if you got a working tvcard addition.
+
+ PS. <TVCard editors behold!)
+- Dont forget to set video_input to the number of inputs
++ Don't forget to set video_input to the number of inputs
+ you defined in the video_mux part of the tvcard definition.
+- Its a common error to add a channel but not incrementing
++ It's a common error to add a channel but not incrementing
+ video_input and getting angry with me/v4l/linux/linus :(
+
+ You are now ready to test the framegrabber with your favorite
+diff --git a/Documentation/vm/numa b/Documentation/vm/numa
+index 4b8db1b..e93ad94 100644
+--- a/Documentation/vm/numa
++++ b/Documentation/vm/numa
+@@ -22,7 +22,7 @@ The initial port includes NUMAizing the
+ encapsulating all the pieces of information into a bootmem_data_t
+ structure. Node specific calls have been added to the allocator.
+ In theory, any platform which uses the bootmem allocator should
+-be able to to put the bootmem and mem_map data structures anywhere
++be able to put the bootmem and mem_map data structures anywhere
+ it deems best.
+
+ Each node's page allocation data structures have also been encapsulated
+diff --git a/Documentation/watchdog/src/watchdog-simple.c b/Documentation/watchdog/src/watchdog-simple.c
+index 85cf17c..47801bc 100644
+--- a/Documentation/watchdog/src/watchdog-simple.c
++++ b/Documentation/watchdog/src/watchdog-simple.c
+@@ -1,4 +1,6 @@
++#include <stdio.h>
+ #include <stdlib.h>
++#include <unistd.h>
+ #include <fcntl.h>
+
+ int main(int argc, const char *argv[]) {
+diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt
+index 958ff3d..7e8ae83 100644
+--- a/Documentation/watchdog/watchdog-api.txt
++++ b/Documentation/watchdog/watchdog-api.txt
+@@ -45,7 +45,7 @@ daemon and it crashes the system will no
+ some of the drivers support the configuration option "Disable watchdog
+ shutdown on close", CONFIG_WATCHDOG_NOWAYOUT. If it is set to Y when
+ compiling the kernel, there is no way of disabling the watchdog once
+-it has been started. So, if the watchdog dameon crashes, the system
++it has been started. So, if the watchdog daemon crashes, the system
+ will reboot after the timeout has passed.
+
+ Some other drivers will not disable the watchdog, unless a specific
+@@ -207,7 +207,7 @@ Note that not all devices support these
+ support the GETBOOTSTATUS call.
+
+ Some drivers can measure the temperature using the GETTEMP ioctl. The
+-returned value is the temperature in degrees farenheit.
++returned value is the temperature in degrees fahrenheit.
+
+ int temperature;
+ ioctl(fd, WDIOC_GETTEMP, &temperature);
+@@ -258,13 +258,13 @@ booke_wdt.c -- PowerPC BookE Watchdog Ti
+ Timeout default varies according to frequency, supports
+ SETTIMEOUT
+
+- Watchdog can not be turned off, CONFIG_WATCHDOG_NOWAYOUT
++ Watchdog cannot be turned off, CONFIG_WATCHDOG_NOWAYOUT
+ does not make sense
+
+ GETSUPPORT returns the watchdog_info struct, and
+ GETSTATUS returns the supported options. GETBOOTSTATUS
+ returns a 1 if the last reset was caused by the
+- watchdog and a 0 otherwise. This watchdog can not be
++ watchdog and a 0 otherwise. This watchdog cannot be
+ disabled once it has been started. The wdt_period kernel
+ parameter selects which bit of the time base changing
+ from 0->1 will trigger the watchdog exception. Changing
+diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
+index 6da24e7..f3c57f4 100644
+--- a/Documentation/x86_64/boot-options.txt
++++ b/Documentation/x86_64/boot-options.txt
+@@ -109,7 +109,7 @@ Idle loop
+ Rebooting
+
+ reboot=b[ios] | t[riple] | k[bd] [, [w]arm | [c]old]
+- bios Use the CPU reboto vector for warm reset
++ bios Use the CPU reboot vector for warm reset
+ warm Don't set the cold reboot flag
+ cold Set the cold reboot flag
+ triple Force a triple fault (init)
+@@ -199,6 +199,11 @@ IOMMU
+ allowed overwrite iommu off workarounds for specific chipsets.
+ soft Use software bounce buffering (default for Intel machines)
+ noaperture Don't touch the aperture for AGP.
++ allowdac Allow DMA >4GB
++ When off all DMA over >4GB is forced through an IOMMU or bounce
++ buffering.
++ nodac Forbid DMA >4GB
++ panic Always panic when IOMMU overflows
+
+ swiotlb=pages[,force]
+
+@@ -245,6 +250,13 @@ Debugging
+ newfallback: use new unwinder but fall back to old if it gets
+ stuck (default)
+
++ call_trace=[old|both|newfallback|new]
++ old: use old inexact backtracer
++ new: use new exact dwarf2 unwinder
++ both: print entries from both
++ newfallback: use new unwinder but fall back to old if it gets
++ stuck (default)
++
+ Misc
+
+ noreplacement Don't replace instructions with more appropriate ones
+diff --git a/Documentation/x86_64/kernel-stacks b/Documentation/x86_64/kernel-stacks
+new file mode 100644
+index 0000000..bddfddd
+--- /dev/null
++++ b/Documentation/x86_64/kernel-stacks
+@@ -0,0 +1,99 @@
++Most of the text from Keith Owens, hacked by AK
++
++x86_64 page size (PAGE_SIZE) is 4K.
++
++Like all other architectures, x86_64 has a kernel stack for every
++active thread. These thread stacks are THREAD_SIZE (2*PAGE_SIZE) big.
++These stacks contain useful data as long as a thread is alive or a
++zombie. While the thread is in user space the kernel stack is empty
++except for the thread_info structure at the bottom.
++
++In addition to the per thread stacks, there are specialized stacks
++associated with each cpu. These stacks are only used while the kernel
++is in control on that cpu, when a cpu returns to user space the
++specialized stacks contain no useful data. The main cpu stacks is
++
++* Interrupt stack. IRQSTACKSIZE
++
++ Used for external hardware interrupts. If this is the first external
++ hardware interrupt (i.e. not a nested hardware interrupt) then the
++ kernel switches from the current task to the interrupt stack. Like
++ the split thread and interrupt stacks on i386 (with CONFIG_4KSTACKS),
++ this gives more room for kernel interrupt processing without having
++ to increase the size of every per thread stack.
++
++ The interrupt stack is also used when processing a softirq.
++
++Switching to the kernel interrupt stack is done by software based on a
++per CPU interrupt nest counter. This is needed because x86-64 "IST"
++hardware stacks cannot nest without races.
++
++x86_64 also has a feature which is not available on i386, the ability
++to automatically switch to a new stack for designated events such as
++double fault or NMI, which makes it easier to handle these unusual
++events on x86_64. This feature is called the Interrupt Stack Table
++(IST). There can be up to 7 IST entries per cpu. The IST code is an
++index into the Task State Segment (TSS), the IST entries in the TSS
++point to dedicated stacks, each stack can be a different size.
++
++An IST is selected by an non-zero value in the IST field of an
++interrupt-gate descriptor. When an interrupt occurs and the hardware
++loads such a descriptor, the hardware automatically sets the new stack
++pointer based on the IST value, then invokes the interrupt handler. If
++software wants to allow nested IST interrupts then the handler must
++adjust the IST values on entry to and exit from the interrupt handler.
++(this is occasionally done, e.g. for debug exceptions)
++
++Events with different IST codes (i.e. with different stacks) can be
++nested. For example, a debug interrupt can safely be interrupted by an
++NMI. arch/x86_64/kernel/entry.S::paranoidentry adjusts the stack
++pointers on entry to and exit from all IST events, in theory allowing
++IST events with the same code to be nested. However in most cases, the
++stack size allocated to an IST assumes no nesting for the same code.
++If that assumption is ever broken then the stacks will become corrupt.
++
++The currently assigned IST stacks are :-
++
++* STACKFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
++
++ Used for interrupt 12 - Stack Fault Exception (#SS).
++
++ This allows to recover from invalid stack segments. Rarely
++ happens.
++
++* DOUBLEFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
++
++ Used for interrupt 8 - Double Fault Exception (#DF).
++
++ Invoked when handling a exception causes another exception. Happens
++ when the kernel is very confused (e.g. kernel stack pointer corrupt)
++ Using a separate stack allows to recover from it well enough in many
++ cases to still output an oops.
++
++* NMI_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
++
++ Used for non-maskable interrupts (NMI).
++
++ NMI can be delivered at any time, including when the kernel is in the
++ middle of switching stacks. Using IST for NMI events avoids making
++ assumptions about the previous state of the kernel stack.
++
++* DEBUG_STACK. DEBUG_STKSZ
++
++ Used for hardware debug interrupts (interrupt 1) and for software
++ debug interrupts (INT3).
++
++ When debugging a kernel, debug interrupts (both hardware and
++ software) can occur at any time. Using IST for these interrupts
++ avoids making assumptions about the previous state of the kernel
++ stack.
++
++* MCE_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
++
++ Used for interrupt 18 - Machine Check Exception (#MC).
++
++ MCE can be delivered at any time, including when the kernel is in the
++ middle of switching stacks. Using IST for MCE events avoids making
++ assumptions about the previous state of the kernel stack.
++
++For more details see the Intel IA32 or AMD AMD64 architecture manuals.
+diff --git a/Kbuild b/Kbuild
+index 2d4f95e..0451f69 100644
+--- a/Kbuild
++++ b/Kbuild
+@@ -28,7 +28,7 @@ define cmd_offsets
+ echo "/*"; \
+ echo " * DO NOT MODIFY."; \
+ echo " *"; \
+- echo " * This file was generated by $(srctree)/Kbuild"; \
++ echo " * This file was generated by Kbuild"; \
+ echo " *"; \
+ echo " */"; \
+ echo ""; \
+diff --git a/MAINTAINERS b/MAINTAINERS
+index a34c53c..d708702 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -144,11 +144,9 @@ L: netdev at vger.kernel.org
+ S: Maintained
+
+ 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
+-P: Russell King
+-M: rmk+serial at arm.linux.org.uk
+ L: linux-serial at vger.kernel.org
+ W: http://serial.sourceforge.net
+-S: Maintained
++S: Orphan
+
+ 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
+ P: Paul Gortmaker
+@@ -298,6 +296,14 @@ L: info-linux at geode.amd.com
+ W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
+ S: Supported
+
++AMSO1100 RNIC DRIVER
++P: Tom Tucker
++M: tom at opengridcomputing.com
++P: Steve Wise
++M: swise at opengridcomputing.com
++L: openib-general at openib.org
++S: Maintained
++
+ AOA (Apple Onboard Audio) ALSA DRIVER
+ P: Johannes Berg
+ M: johannes at sipsolutions.net
+@@ -435,6 +441,23 @@ W: http://people.redhat.com/sgrubb/audit
+ T: git kernel.org:/pub/scm/linux/kernel/git/dwmw2/audit-2.6.git
+ S: Maintained
+
++AVR32 ARCHITECTURE
++P: Atmel AVR32 Support Team
++M: avr32 at atmel.com
++P: Haavard Skinnemoen
++M: hskinnemoen at atmel.com
++W: http://www.atmel.com/products/AVR32/
++W: http://avr32linux.org/
++W: http://avrfreaks.net/
++S: Supported
++
++AVR32/AT32AP MACHINE SUPPORT
++P: Atmel AVR32 Support Team
++M: avr32 at atmel.com
++P: Haavard Skinnemoen
++M: hskinnemoen at atmel.com
++S: Supported
++
+ AX.25 NETWORK LAYER
+ P: Ralf Baechle
+ M: ralf at linux-mips.org
+@@ -449,9 +472,9 @@ L: linux-hams at vger.kernel.org
+ W: http://www.baycom.org/~tom/ham/ham.html
+ S: Maintained
+
+-BCM43XX WIRELESS DRIVER
+-P: Michael Buesch
+-M: mb at bu3sch.de
++BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION)
++P: Larry Finger
++M: Larry.Finger at lwfinger.net
+ P: Stefano Brivio
+ M: st3 at riseup.net
+ W: http://bcm43xx.berlios.de/
+@@ -476,7 +499,7 @@ S: Maintained
+
+ BLOCK LAYER
+ P: Jens Axboe
+-M: axboe at suse.de
++M: axboe at kernel.dk
+ L: linux-kernel at vger.kernel.org
+ T: git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+ S: Maintained
+@@ -618,7 +641,7 @@ CALGARY x86-64 IOMMU
+ P: Muli Ben-Yehuda
+ M: muli at il.ibm.com
+ P: Jon D. Mason
+-M: jdmason at us.ibm.com
++M: jdmason at kudzu.us
+ L: linux-kernel at vger.kernel.org
+ L: discuss at x86-64.org
+ S: Maintained
+@@ -826,7 +849,7 @@ P: Doug Warzecha
+ M: Douglas_Warzecha at dell.com
+ S: Maintained
+
+-DEVICE-MAPPER
++DEVICE-MAPPER (LVM)
+ P: Alasdair Kergon
+ L: dm-devel at redhat.com
+ W: http://sources.redhat.com/dm
+@@ -875,6 +898,17 @@ M: jack at suse.cz
+ L: linux-kernel at vger.kernel.org
+ S: Maintained
+
++DISTRIBUTED LOCK MANAGER
++P: Patrick Caulfield
++M: pcaulfie at redhat.com
++P: David Teigland
++M: teigland at redhat.com
++L: cluster-devel at redhat.com
++W: http://sources.redhat.com/cluster/
++T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
++T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
++S: Supported
++
+ DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
+ P: Tobias Ringstrom
+ M: tori at unhappy.mine.nu
+@@ -954,6 +988,13 @@ L: ebtables-devel at lists.sourceforge.net
+ W: http://ebtables.sourceforge.net/
+ S: Maintained
+
++ECRYPT FILE SYSTEM
++P: Mike Halcrow, Phillip Hellewell
++M: mhalcrow at us.ibm.com, phillip at hellewell.homeip.net
++L: ecryptfs-devel at lists.sourceforge.net
++W: http://ecryptfs.sourceforge.net/
++S: Supported
++
+ EDAC-CORE
+ P: Doug Thompson
+ M: norsk5 at xmission.com
+@@ -991,6 +1032,14 @@ EFS FILESYSTEM
+ W: http://aeschi.ch.eu.org/efs/
+ S: Orphan
+
++EHCA (IBM GX bus InfiniBand adapter) DRIVER:
++P: Hoang-Nam Nguyen
++M: hnguyen at de.ibm.com
++P: Christoph Raisch
++M: raisch at de.ibm.com
++L: openib-general at openib.org
++S: Supported
++
+ EMU10K1 SOUND DRIVER
+ P: James Courtier-Dutton
+ M: James at superbug.demon.co.uk
+@@ -1135,6 +1184,15 @@ M: khc at pm.waw.pl
+ W: http://www.kernel.org/pub/linux/utils/net/hdlc/
+ S: Maintained
+
++GFS2 FILE SYSTEM
++P: Steven Whitehouse
++M: swhiteho at redhat.com
++L: cluster-devel at redhat.com
++W: http://sources.redhat.com/cluster/
++T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
++T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
++S: Supported
++
+ GIGASET ISDN DRIVERS
+ P: Hansjoerg Lipp
+ M: hjlipp at web.de
+@@ -1347,7 +1405,7 @@ S: Maintained
+
+ IDE/ATAPI CDROM DRIVER
+ P: Jens Axboe
+-M: axboe at suse.de
++M: axboe at kernel.dk
+ L: linux-kernel at vger.kernel.org
+ W: http://www.kernel.dk
+ S: Maintained
+@@ -1365,36 +1423,29 @@ M: Gadi Oxman <gadio at netvision.net.il>
+ L: linux-kernel at vger.kernel.org
+ S: Maintained
+
+-IEEE 1394 ETHERNET (eth1394)
+-L: linux1394-devel at lists.sourceforge.net
+-W: http://www.linux1394.org/
+-S: Orphan
+-
+ IEEE 1394 SUBSYSTEM
+ P: Ben Collins
+ M: bcollins at debian.org
+-P: Jody McIntyre
+-M: scjody at modernduck.com
++P: Stefan Richter
++M: stefanr at s5r6.in-berlin.de
+ L: linux1394-devel at lists.sourceforge.net
+ W: http://www.linux1394.org/
+-T: git kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
++T: git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
+ S: Maintained
+
+-IEEE 1394 OHCI DRIVER
+-P: Ben Collins
+-M: bcollins at debian.org
+-P: Jody McIntyre
+-M: scjody at modernduck.com
++IEEE 1394 IPV4 DRIVER (eth1394)
++P: Stefan Richter
++M: stefanr at s5r6.in-berlin.de
+ L: linux1394-devel at lists.sourceforge.net
+-W: http://www.linux1394.org/
+-S: Maintained
++S: Odd Fixes
+
+ IEEE 1394 PCILYNX DRIVER
+ P: Jody McIntyre
+ M: scjody at modernduck.com
++P: Stefan Richter
++M: stefanr at s5r6.in-berlin.de
+ L: linux1394-devel at lists.sourceforge.net
+-W: http://www.linux1394.org/
+-S: Maintained
++S: Odd Fixes
+
+ IEEE 1394 RAW I/O DRIVER
+ P: Ben Collins
+@@ -1402,16 +1453,6 @@ M: bcollins at debian.org
+ P: Dan Dennedy
+ M: dan at dennedy.org
+ L: linux1394-devel at lists.sourceforge.net
+-W: http://www.linux1394.org/
+-S: Maintained
+-
+-IEEE 1394 SBP2
+-P: Ben Collins
+-M: bcollins at debian.org
+-P: Stefan Richter
+-M: stefanr at s5r6.in-berlin.de
+-L: linux1394-devel at lists.sourceforge.net
+-W: http://www.linux1394.org/
+ S: Maintained
+
+ IMS TWINTURBO FRAMEBUFFER DRIVER
+@@ -1627,6 +1668,12 @@ M: sct at redhat.com, akpm at osdl.org
+ L: ext2-devel at lists.sourceforge.net
+ S: Maintained
+
++K8TEMP HARDWARE MONITORING DRIVER
++P: Rudolf Marek
++M: r.marek at assembler.cz
++L: lm-sensors at lm-sensors.org
++S: Maintained
++
+ KCONFIG
+ P: Roman Zippel
+ M: zippel at linux-m68k.org
+@@ -1783,6 +1830,13 @@ W: http://www.penguinppc.org/
+ L: linuxppc-embedded at ozlabs.org
+ S: Maintained
+
++LINUX FOR POWERPC PA SEMI PWRFICIENT
++P: Olof Johansson
++M: olof at lixom.net
++W: http://www.pasemi.com/
++L: linuxppc-dev at ozlabs.org
++S: Supported
++
+ LLC (802.2)
+ P: Arnaldo Carvalho de Melo
+ M: acme at conectiva.com.br
+@@ -1872,11 +1926,6 @@ M: rroesler at syskonnect.de
+ W: http://www.syskonnect.com
+ S: Supported
+
+-MAESTRO PCI SOUND DRIVERS
+-P: Zach Brown
+-M: zab at zabbo.net
+-S: Odd Fixes
+-
+ MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
+ P: Michael Kerrisk
+ M: mtk-manpages at gmx.net
+@@ -1955,6 +2004,13 @@ M: rubini at ipvvis.unipv.it
+ L: linux-kernel at vger.kernel.org
+ S: Maintained
+
++MSI LAPTOP SUPPORT
++P: Lennart Poettering
++M: mzxreary at 0pointer.de
++L: https://tango.0pointer.de/mailman/listinfo/s270-linux
++W: http://0pointer.de/lennart/tchibo.html
++S: Maintained
++
+ MTRR AND SIMILAR SUPPORT [i386]
+ P: Richard Gooch
+ M: rgooch at atnf.csiro.au
+@@ -1962,9 +2018,10 @@ L: linux-kernel at vger.kernel.org
+ W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html
+ S: Maintained
+
+-MULTIMEDIA CARD (MMC) SUBSYSTEM
+-P: Russell King
+-M: rmk+mmc at arm.linux.org.uk
++MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM
++P: Pierre Ossman
++M: drzeus-mmc at drzeus.cx
++L: linux-kernel at vger.kernel.org
+ S: Maintained
+
+ MULTISOUND SOUND DRIVER
+@@ -2001,11 +2058,20 @@ P: Marc Boucher
+ P: James Morris
+ P: Harald Welte
+ P: Jozsef Kadlecsik
+-M: coreteam at netfilter.org
++P: Patrick McHardy
++M: kaber at trash.net
++L: netfilter-devel at lists.netfilter.org
++L: netfilter at lists.netfilter.org
++L: coreteam at netfilter.org
+ W: http://www.netfilter.org/
+ W: http://www.iptables.org/
+-L: netfilter at lists.netfilter.org
+-L: netfilter-devel at lists.netfilter.org
++S: Supported
++
++NETLABEL
++P: Paul Moore
++M: paul.moore at hp.com
++W: http://netlabel.sf.net
++L: netdev at vger.kernel.org
+ S: Supported
+
+ NETROM NETWORK LAYER
+@@ -2015,7 +2081,7 @@ L: linux-hams at vger.kernel.org
+ W: http://www.linux-ax25.org/
+ S: Maintained
+
+-NETWORK BLOCK DEVICE
++NETWORK BLOCK DEVICE (NBD)
+ P: Paul Clements
+ M: Paul.Clements at steeleye.com
+ S: Maintained
+@@ -2215,6 +2281,17 @@ T: git kernel.org:/pub/scm/linux/kernel/
+ T: cvs cvs.parisc-linux.org:/var/cvs/linux-2.6
+ S: Maintained
+
++PC87360 HARDWARE MONITORING DRIVER
++P: Jim Cromie
++M: jim.cromie at gmail.com
++L: lm-sensors at lm-sensors.org
++S: Maintained
++
++PC8736x GPIO DRIVER
++P: Jim Cromie
++M: jim.cromie at gmail.com
++S: Maintained
++
+ PCI ERROR RECOVERY
+ P: Linas Vepstas
+ M: linas at austin.ibm.com
+@@ -2238,8 +2315,8 @@ T: quilt kernel.org/pub/linux/kernel/peo
+ S: Supported
+
+ PCI HOTPLUG CORE
+-P: Greg Kroah-Hartman
+-M: gregkh at suse.de
++P: Kristen Carlson Accardi
++M: kristen.c.accardi at intel.com
+ S: Supported
+
+ PCI HOTPLUG COMPAQ DRIVER
+@@ -2366,6 +2443,12 @@ M: linux-driver at qlogic.com
+ L: linux-scsi at vger.kernel.org
+ S: Supported
+
++QLOGIC QLA3XXX NETWORK DRIVER
++P: Ron Mercer
++M: linux-driver at qlogic.com
++L: netdev at vger.kernel.org
++S: Supported
++
+ QNX4 FILESYSTEM
+ P: Anders Larsen
+ M: al at alarsen.net
+@@ -2402,6 +2485,19 @@ M: mporter at kernel.crashing.org
+ L: linux-kernel at vger.kernel.org
+ S: Maintained
+
++READ-COPY UPDATE (RCU)
++P: Dipankar Sarma
++M: dipankar at in.ibm.com
++W: http://www.rdrop.com/users/paulmck/rclock/
++L: linux-kernel at vger.kernel.org
++S: Supported
++
++RCUTORTURE MODULE
++P: Josh Triplett
++M: josh at freedesktop.org
++L: linux-kernel at vger.kernel.org
++S: Maintained
++
+ REAL TIME CLOCK DRIVER
+ P: Paul Gortmaker
+ M: p_gortmaker at yahoo.com
+@@ -2445,6 +2541,8 @@ S: Maintained
+ S390
+ P: Martin Schwidefsky
+ M: schwidefsky at de.ibm.com
++P: Heiko Carstens
++M: heiko.carstens at de.ibm.com
+ M: linux390 at de.ibm.com
+ L: linux-390 at vm.marist.edu
+ W: http://www.ibm.com/developerworks/linux/linux390/
+@@ -2459,8 +2557,8 @@ W: http://www.ibm.com/developerworks/lin
+ S: Supported
+
+ S390 ZFCP DRIVER
+-P: Andreas Herrmann
+-M: aherrman at de.ibm.com
++P: Swen Schillig
++M: swen at vnet.ibm.com
+ M: linux390 at de.ibm.com
+ L: linux-390 at vm.marist.edu
+ W: http://www.ibm.com/developerworks/linux/linux390/
+@@ -2493,7 +2591,7 @@ S: Maintained
+
+ SCSI CDROM DRIVER
+ P: Jens Axboe
+-M: axboe at suse.de
++M: axboe at kernel.dk
+ L: linux-scsi at vger.kernel.org
+ W: http://www.kernel.dk
+ S: Maintained
+@@ -2525,10 +2623,19 @@ L: lksctp-developers at lists.sourceforge.n
+ S: Supported
+
+ SCx200 CPU SUPPORT
+-P: Christer Weinigel
+-M: christer at weinigel.se
+-W: http://www.weinigel.se
+-S: Supported
++P: Jim Cromie
++M: jim.cromie at gmail.com
++S: Odd Fixes
++
++SCx200 GPIO DRIVER
++P: Jim Cromie
++M: jim.cromie at gmail.com
++S: Maintained
++
++SCx200 HRT CLOCKSOURCE DRIVER
++P: Jim Cromie
++M: jim.cromie at gmail.com
++S: Maintained
+
+ SECURITY CONTACT
+ P: Security Officers
+@@ -2616,6 +2723,17 @@ P: Nicolas Pitre
+ M: nico at cam.org
+ S: Maintained
+
++SOFTMAC LAYER (IEEE 802.11)
++P: Johannes Berg
++M: johannes at sipsolutions.net
++P: Joe Jezak
++M: josejx at gentoo.org
++P: Daniel Drake
++M: dsd at gentoo.org
++W: http://softmac.sipsolutions.net/
++L: netdev at vger.kernel.org
++S: Maintained
++
+ SOFTWARE RAID (Multiple Disks) SUPPORT
+ P: Ingo Molnar
+ M: mingo at redhat.com
+@@ -2662,14 +2780,6 @@ M: chrisw at sous-sol.org
+ L: stable at kernel.org
+ S: Maintained
+
+-STABLE BRANCH:
+-P: Greg Kroah-Hartman
+-M: greg at kroah.com
+-P: Chris Wright
+-M: chrisw at sous-sol.org
+-L: stable at kernel.org
+-S: Maintained
+-
+ TPM DEVICE DRIVER
+ P: Kylene Hall
+ M: kjhall at us.ibm.com
+@@ -2690,14 +2800,7 @@ S: Maintained
+ UltraSPARC (sparc64):
+ P: David S. Miller
+ M: davem at davemloft.net
+-P: Eddie C. Dost
+-M: ecd at brainaid.de
+-P: Jakub Jelinek
+-M: jj at sunsite.ms.mff.cuni.cz
+-P: Anton Blanchard
+-M: anton at samba.org
+ L: sparclinux at vger.kernel.org
+-L: ultralinux at vger.kernel.org
+ T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git
+ S: Maintained
+
+@@ -2744,6 +2847,12 @@ M: R.E.Wolff at BitWizard.nl
+ L: linux-kernel at vger.kernel.org ?
+ S: Supported
+
++SPIDERNET NETWORK DRIVER for CELL
++P: Jim Lewis
++M: jim at jklewis.com
++L: netdev at vger.kernel.org
++S: Supported
++
+ SRM (Alpha) environment access
+ P: Jan-Benedict Glaw
+ M: jbglaw at lug-owl.de
+@@ -2768,22 +2877,15 @@ S: Maintained
+ SUPERH (sh)
+ P: Paul Mundt
+ M: lethal at linux-sh.org
+-P: Kazumoto Kojima
+-M: kkojima at rr.iij4u.or.jp
+-L: linuxsh-dev at lists.sourceforge.net
++L: linuxsh-dev at lists.sourceforge.net (subscribers-only)
+ W: http://www.linux-sh.org
+-W: http://www.m17n.org/linux-sh/
+-W: http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html
+ S: Maintained
+
+ SUPERH64 (sh64)
+ P: Paul Mundt
+ M: lethal at linux-sh.org
+-P: Richard Curnow
+-M: rc at rc0.org.uk
+ L: linuxsh-shmedia-dev at lists.sourceforge.net
+ W: http://www.linux-sh.org
+-W: http://www.rc0.org.uk/sh64
+ S: Maintained
+
+ SUN3/3X
+@@ -2818,6 +2920,11 @@ M: hlhung3i at gmail.com
+ W: http://tcp-lp-mod.sourceforge.net/
+ S: Maintained
+
++TI FLASH MEDIA INTERFACE DRIVER
++P: Alex Dubov
++M: oakad at yahoo.com
++S: Maintained
++
+ TI OMAP RANDOM NUMBER GENERATOR SUPPORT
+ P: Deepak Saxena
+ M: dsaxena at plexity.net
+@@ -2897,8 +3004,8 @@ W: http://www.auk.cx/tms380tr/
+ S: Maintained
+
+ TULIP NETWORK DRIVER
+-P: Jeff Garzik
+-M: jgarzik at pobox.com
++P: Valerie Henson
++M: val_henson at linux.intel.com
+ L: tulip-users at lists.sourceforge.net
+ W: http://sourceforge.net/projects/tulip/
+ S: Maintained
+@@ -2924,7 +3031,7 @@ S: Maintained
+
+ UNIFORM CDROM DRIVER
+ P: Jens Axboe
+-M: axboe at suse.de
++M: axboe at kernel.dk
+ L: linux-kernel at vger.kernel.org
+ W: http://www.kernel.dk
+ S: Maintained
+@@ -3243,6 +3350,12 @@ W: http://linuxtv.org
+ T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
+ S: Maintained
+
++VT1211 HARDWARE MONITOR DRIVER
++P: Juerg Haefliger
++M: juergh at gmail.com
++L: lm-sensors at lm-sensors.org
++S: Maintained
++
+ VT8231 HARDWARE MONITOR DRIVER
+ P: Roger Lucas
+ M: roger at planbit.co.uk
+@@ -3335,12 +3448,6 @@ M: Henk.Vergonet at gmail.com
+ L: usbb2k-api-dev at nongnu.org
+ S: Maintained
+
+-YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
+-P: Pete Zaitcev
+-M: zaitcev at yahoo.com
+-L: linux-kernel at vger.kernel.org
+-S: Obsolete
+-
+ Z8530 DRIVER FOR AX.25
+ P: Joerg Reuter
+ M: jreuter at yaina.de
+@@ -3349,6 +3456,15 @@ W: http://www.qsl.net/dl1bke/
+ L: linux-hams at vger.kernel.org
+ S: Maintained
+
++ZD1211RW WIRELESS DRIVER
++P: Daniel Drake
++M: dsd at gentoo.org
++P: Ulrich Kunitz
++M: kune at deine-taler.de
++W: http://zd1211.ath.cx/wiki/DriverRewrite
++L: zd1211-devs at lists.sourceforge.net (subscribers-only)
++S: Maintained
++
+ ZF MACHZ WATCHDOG
+ P: Fernando Fuganti
+ M: fuganti at netbank.com.br
+diff --git a/Makefile b/Makefile
+index edfc2fd..8484be1 100644
+--- a/Makefile
++++ b/Makefile
+@@ -41,9 +41,15 @@ ifndef KBUILD_VERBOSE
+ KBUILD_VERBOSE = 0
+ endif
+
+-# Call checker as part of compilation of C files
+-# Use 'make C=1' to enable checking (sparse, by default)
+-# Override with 'make C=1 CHECK=checker_executable CHECKFLAGS=....'
++# Call a source code checker (by default, "sparse") as part of the
++# C compilation.
++#
++# Use 'make C=1' to enable checking of only re-compiled files.
++# Use 'make C=2' to enable checking of *all* source files, regardless
++# of whether they are re-compiled or not.
++#
++# See the file "Documentation/sparse.txt" for more details, including
++# where to get the "sparse" utility.
+
+ ifdef C
+ ifeq ("$(origin C)", "command line")
+@@ -493,6 +499,7 @@ endif
+
+ ifdef CONFIG_UNWIND_INFO
+ CFLAGS += -fasynchronous-unwind-tables
++LDFLAGS_vmlinux += --eh-frame-hdr
+ endif
+
+ ifdef CONFIG_DEBUG_INFO
+@@ -639,12 +646,12 @@ define rule_vmlinux__
+ $(call cmd,vmlinux__)
+ $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
+
+- $(Q)$(if $($(quiet)cmd_sysmap), \
+- echo ' $($(quiet)cmd_sysmap) System.map' &&) \
+- $(cmd_sysmap) $@ System.map; \
+- if [ $$? -ne 0 ]; then \
+- rm -f $@; \
+- /bin/false; \
++ $(Q)$(if $($(quiet)cmd_sysmap), \
++ echo ' $($(quiet)cmd_sysmap) System.map' &&) \
++ $(cmd_sysmap) $@ System.map; \
++ if [ $$? -ne 0 ]; then \
++ rm -f $@; \
++ /bin/false; \
+ fi;
+ $(verify_kallsyms)
+ endef
+@@ -677,12 +684,12 @@ endif
+ kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
+
+ define verify_kallsyms
+- $(Q)$(if $($(quiet)cmd_sysmap), \
+- echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \
++ $(Q)$(if $($(quiet)cmd_sysmap), \
++ echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \
+ $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map
+- $(Q)cmp -s System.map .tmp_System.map || \
+- (echo Inconsistent kallsyms data; \
+- echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \
++ $(Q)cmp -s System.map .tmp_System.map || \
++ (echo Inconsistent kallsyms data; \
++ echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \
+ rm .tmp_kallsyms* ; /bin/false )
+ endef
+
+@@ -735,7 +742,11 @@ endif # ifdef CONFIG_KALLSYMS
+
+ # vmlinux image - including updated kernel symbols
+ vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
++ifdef CONFIG_HEADERS_CHECK
++ $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
++endif
+ $(call if_changed_rule,vmlinux__)
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
+ $(Q)rm -f .old_version
+
+ # The actual objects are generated when descending,
+@@ -753,12 +764,34 @@ $(vmlinux-dirs): prepare scripts
+ $(Q)$(MAKE) $(build)=$@
+
+ # Build the kernel release string
+-# The KERNELRELEASE is stored in a file named include/config/kernel.release
+-# to be used when executing for example make install or make modules_install
+ #
+-# Take the contents of any files called localversion* and the config
+-# variable CONFIG_LOCALVERSION and append them to KERNELRELEASE.
+-# LOCALVERSION from the command line override all of this
++# The KERNELRELEASE value built here is stored in the file
++# include/config/kernel.release, and is used when executing several
++# make targets, such as "make install" or "make modules_install."
++#
++# The eventual kernel release string consists of the following fields,
++# shown in a hierarchical format to show how smaller parts are concatenated
++# to form the larger and final value, with values coming from places like
++# the Makefile, kernel config options, make command line options and/or
++# SCM tag information.
++#
++# $(KERNELVERSION)
++# $(VERSION) eg, 2
++# $(PATCHLEVEL) eg, 6
++# $(SUBLEVEL) eg, 18
++# $(EXTRAVERSION) eg, -rc6
++# $(localver-full)
++# $(localver)
++# localversion* (all localversion* files)
++# $(CONFIG_LOCALVERSION) (from kernel config setting)
++# $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set)
++# ./scripts/setlocalversion (SCM tag, if one exists)
++# $(LOCALVERSION) (from make command line if provided)
++#
++# Note how the final $(localver-auto) string is included *only* if the
++# kernel config option CONFIG_LOCALVERSION_AUTO is selected. Also, at the
++# moment, only git is supported but other SCMs can edit the script
++# scripts/setlocalversion and add the appropriate checks as needed.
+
+ nullstring :=
+ space := $(nullstring) # end of line
+@@ -892,15 +925,26 @@ depend dep:
+ INSTALL_HDR_PATH=$(objtree)/usr
+ export INSTALL_HDR_PATH
+
++HDRARCHES=$(filter-out generic,$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild)))
++
++PHONY += headers_install_all
++headers_install_all: include/linux/version.h scripts_basic FORCE
++ $(Q)$(MAKE) $(build)=scripts scripts/unifdef
++ $(Q)for arch in $(HDRARCHES); do \
++ $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch ;\
++ done
++
+ PHONY += headers_install
+-headers_install: include/linux/version.h
+- $(Q)unifdef -Ux /dev/null
+- $(Q)rm -rf $(INSTALL_HDR_PATH)/include
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.headersinst obj=include
++headers_install: include/linux/version.h scripts_basic FORCE
++ @if [ ! -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \
++ echo '*** Error: Headers not exportable for this architecture ($(ARCH))'; \
++ exit 1 ; fi
++ $(Q)$(MAKE) $(build)=scripts scripts/unifdef
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include
+
+ PHONY += headers_check
+ headers_check: headers_install
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.headersinst obj=include HDRCHECK=1
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include HDRCHECK=1
+
+ # ---------------------------------------------------------------------------
+ # Modules
+@@ -916,7 +960,7 @@ all: modules
+ PHONY += modules
+ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
+ @echo ' Building modules, stage 2.';
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
+
+
+ # Target to prepare building external modules
+@@ -942,7 +986,7 @@ _modinst_:
+ rm -f $(MODLIB)/build ; \
+ ln -s $(objtree) $(MODLIB)/build ; \
+ fi
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst
+
+ # If System.map exists, run depmod. This deliberately does not have a
+ # dependency on System.map since that would run the dependency tree on
+@@ -1057,8 +1101,10 @@ boards := $(notdir $(boards))
+
+ help:
+ @echo 'Cleaning targets:'
+- @echo ' clean - remove most generated files but keep the config'
++ @echo ' clean - remove most generated files but keep the config and'
++ @echo ' enough build support to build external modules'
+ @echo ' mrproper - remove all generated files + config + various backup files'
++ @echo ' distclean - mrproper + remove editor backup and patch files'
+ @echo ''
+ @echo 'Configuration targets:'
+ @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help
+@@ -1076,13 +1122,17 @@ help:
+ @echo ' cscope - Generate cscope index'
+ @echo ' kernelrelease - Output the release version string'
+ @echo ' kernelversion - Output the version stored in Makefile'
+- @echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'
++ @if [ -r include/asm-$(ARCH)/Kbuild ]; then \
++ echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
++ fi
+ @echo ' (default: $(INSTALL_HDR_PATH))'
+ @echo ''
+ @echo 'Static analysers'
+ @echo ' checkstack - Generate a list of stack hogs'
+ @echo ' namespacecheck - Name space analysis on compiled kernel'
+- @echo ' headers_check - Sanity check on exported headers'
++ @if [ -r include/asm-$(ARCH)/Kbuild ]; then \
++ echo ' headers_check - Sanity check on exported headers'; \
++ fi
+ @echo ''
+ @echo 'Kernel packaging:'
+ @$(MAKE) $(build)=$(package-dir) help
+@@ -1100,6 +1150,7 @@ help:
+ echo '')
+
+ @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
++ @echo ' make V=2 [targets] 2 => give reason for rebuild of target'
+ @echo ' make O=dir [targets] Locate all output files in "dir", including .config'
+ @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)'
+ @echo ' make C=2 [targets] Force check of all c source with $$CHECK'
+@@ -1154,7 +1205,7 @@ $(module-dirs): crmodverdir $(objtree)/M
+
+ modules: $(module-dirs)
+ @echo ' Building modules, stage 2.';
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
+
+ PHONY += modules_install
+ modules_install: _emodinst_ _emodinst_post
+@@ -1163,7 +1214,7 @@ install-dir := $(if $(INSTALL_MOD_DIR),$
+ PHONY += _emodinst_
+ _emodinst_:
+ $(Q)mkdir -p $(MODLIB)/$(install-dir)
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst
+
+ # Run depmod only is we have System.map and depmod is executable
+ quiet_cmd_depmod = DEPMOD $(KERNELRELEASE)
+@@ -1264,6 +1315,32 @@ define all-defconfigs
+ $(call find-sources,'defconfig')
+ endef
+
++define xtags
++ if $1 --version 2>&1 | grep -iq exuberant; then \
++ $(all-sources) | xargs $1 -a \
++ -I __initdata,__exitdata,__acquires,__releases \
++ -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
++ --extra=+f --c-kinds=+px \
++ --regex-asm='/ENTRY\(([^)]*)\).*/\1/'; \
++ $(all-kconfigs) | xargs $1 -a \
++ --langdef=kconfig \
++ --language-force=kconfig \
++ --regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \
++ $(all-defconfigs) | xargs -r $1 -a \
++ --langdef=dotconfig \
++ --language-force=dotconfig \
++ --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \
++ elif $1 --version 2>&1 | grep -iq emacs; then \
++ $(all-sources) | xargs $1 -a; \
++ $(all-kconfigs) | xargs $1 -a \
++ --regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
++ $(all-defconfigs) | xargs -r $1 -a \
++ --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
++ else \
++ $(all-sources) | xargs $1 -a; \
++ fi
++endef
++
+ quiet_cmd_cscope-file = FILELST cscope.files
+ cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files
+
+@@ -1277,31 +1354,16 @@ cscope: FORCE
+ quiet_cmd_TAGS = MAKE $@
+ define cmd_TAGS
+ rm -f $@; \
+- ETAGSF=`etags --version | grep -i exuberant >/dev/null && \
+- echo "-I __initdata,__exitdata,__acquires,__releases \
+- -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
+- --extra=+f --c-kinds=+px"`; \
+- $(all-sources) | xargs etags $$ETAGSF -a; \
+- if test "x$$ETAGSF" = x; then \
+- $(all-kconfigs) | xargs etags -a \
+- --regex='/^config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
+- $(all-defconfigs) | xargs etags -a \
+- --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
+- fi
++ $(call xtags,etags)
+ endef
+
+ TAGS: FORCE
+ $(call cmd,TAGS)
+
+-
+ quiet_cmd_tags = MAKE $@
+ define cmd_tags
+ rm -f $@; \
+- CTAGSF=`ctags --version | grep -i exuberant >/dev/null && \
+- echo "-I __initdata,__exitdata,__acquires,__releases \
+- -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
+- --extra=+f --c-kinds=+px"`; \
+- $(all-sources) | xargs ctags $$CTAGSF -a
++ $(call xtags,ctags)
+ endef
+
+ tags: FORCE
+@@ -1328,9 +1390,13 @@ endif #ifeq ($(config-targets),1)
+ endif #ifeq ($(mixed-targets),1)
+
+ PHONY += checkstack kernelrelease kernelversion
++
++# Use $(SUBARCH) here instead of $(ARCH) so that this works for UML.
++# In the UML case, $(SUBARCH) is the name of the underlying
++# architecture, while for all other arches, it is the same as $(ARCH).
+ checkstack:
+ $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
+- $(PERL) $(src)/scripts/checkstack.pl $(ARCH)
++ $(PERL) $(src)/scripts/checkstack.pl $(SUBARCH)
+
+ kernelrelease:
+ $(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
+@@ -1379,7 +1445,7 @@ endif
+ %.ko: prepare scripts FORCE
+ $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
+ $(build)=$(build-dir) $(@:.ko=.o)
+- $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
+
+ # FIXME Should go into a make.lib or something
+ # ===========================================================================
+diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
+index 213c785..7e55ea6 100644
+--- a/arch/alpha/Kconfig
++++ b/arch/alpha/Kconfig
+@@ -381,7 +381,7 @@ config ALPHA_EV56
+
+ config ALPHA_EV56
+ prompt "EV56 CPU (speed >= 333MHz)?"
+- depends on ALPHA_NORITAKE && ALPHA_PRIMO
++ depends on ALPHA_NORITAKE || ALPHA_PRIMO
+
+ config ALPHA_EV56
+ prompt "EV56 CPU (speed >= 400MHz)?"
+@@ -534,7 +534,7 @@ config ARCH_DISCONTIGMEM_ENABLE
+ bool "Discontiguous Memory Support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+- Say Y to upport efficient handling of discontiguous physical memory,
++ Say Y to support efficient handling of discontiguous physical memory,
+ for architectures which are either NUMA (Non-Uniform Memory Access)
+ or have huge holes in the physical address space for other reasons.
+ See <file:Documentation/vm/numa> for more.
+diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
+index f042cc4..e9762a3 100644
+--- a/arch/alpha/kernel/alpha_ksyms.c
++++ b/arch/alpha/kernel/alpha_ksyms.c
+@@ -1,46 +1,18 @@
+ /*
+- * linux/arch/alpha/kernel/ksyms.c
++ * linux/arch/alpha/kernel/alpha_ksyms.c
+ *
+ * Export the alpha-specific functions that are needed for loadable
+ * modules.
+ */
+
+ #include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/user.h>
+-#include <linux/elfcore.h>
+-#include <linux/socket.h>
+-#include <linux/syscalls.h>
+-#include <linux/in.h>
+-#include <linux/in6.h>
+-#include <linux/pci.h>
+-#include <linux/screen_info.h>
+-#include <linux/tty.h>
+-#include <linux/mm.h>
+-#include <linux/delay.h>
+-#include <linux/dma-mapping.h>
+-
+-#include <asm/io.h>
+ #include <asm/console.h>
+-#include <asm/hwrpb.h>
+ #include <asm/uaccess.h>
+-#include <asm/processor.h>
+ #include <asm/checksum.h>
+-#include <linux/interrupt.h>
+ #include <asm/fpu.h>
+-#include <asm/irq.h>
+ #include <asm/machvec.h>
+-#include <asm/pgalloc.h>
+-#include <asm/semaphore.h>
+-#include <asm/tlbflush.h>
+-#include <asm/cacheflush.h>
+-#include <asm/vga.h>
+
+-#define __KERNEL_SYSCALLS__
+-#include <asm/unistd.h>
+-
+-extern struct hwrpb_struct *hwrpb;
+-extern spinlock_t rtc_lock;
++#include <linux/syscalls.h>
+
+ /* these are C runtime functions with special calling conventions: */
+ extern void __divl (void);
+@@ -53,14 +25,9 @@ extern void __divqu (void);
+ extern void __remqu (void);
+
+ EXPORT_SYMBOL(alpha_mv);
+-EXPORT_SYMBOL(screen_info);
+-EXPORT_SYMBOL(perf_irq);
+ EXPORT_SYMBOL(callback_getenv);
+ EXPORT_SYMBOL(callback_setenv);
+ EXPORT_SYMBOL(callback_save_env);
+-#ifdef CONFIG_ALPHA_GENERIC
+-EXPORT_SYMBOL(alpha_using_srm);
+-#endif /* CONFIG_ALPHA_GENERIC */
+
+ /* platform dependent support */
+ EXPORT_SYMBOL(strcat);
+@@ -78,47 +45,14 @@ EXPORT_SYMBOL(__constant_c_memset);
+ EXPORT_SYMBOL(copy_page);
+ EXPORT_SYMBOL(clear_page);
+
+-EXPORT_SYMBOL(__direct_map_base);
+-EXPORT_SYMBOL(__direct_map_size);
+-
+-#ifdef CONFIG_PCI
+-EXPORT_SYMBOL(pci_alloc_consistent);
+-EXPORT_SYMBOL(pci_free_consistent);
+-EXPORT_SYMBOL(pci_map_single);
+-EXPORT_SYMBOL(pci_map_page);
+-EXPORT_SYMBOL(pci_unmap_single);
+-EXPORT_SYMBOL(pci_unmap_page);
+-EXPORT_SYMBOL(pci_map_sg);
+-EXPORT_SYMBOL(pci_unmap_sg);
+-EXPORT_SYMBOL(pci_dma_supported);
+-EXPORT_SYMBOL(pci_dac_dma_supported);
+-EXPORT_SYMBOL(pci_dac_page_to_dma);
+-EXPORT_SYMBOL(pci_dac_dma_to_page);
+-EXPORT_SYMBOL(pci_dac_dma_to_offset);
+-EXPORT_SYMBOL(alpha_gendev_to_pci);
+-#endif
+-EXPORT_SYMBOL(dma_set_mask);
+-
+-EXPORT_SYMBOL(dump_thread);
+-EXPORT_SYMBOL(dump_elf_thread);
+-EXPORT_SYMBOL(dump_elf_task);
+-EXPORT_SYMBOL(dump_elf_task_fp);
+-EXPORT_SYMBOL(hwrpb);
+-EXPORT_SYMBOL(start_thread);
+ EXPORT_SYMBOL(alpha_read_fp_reg);
+ EXPORT_SYMBOL(alpha_read_fp_reg_s);
+ EXPORT_SYMBOL(alpha_write_fp_reg);
+ EXPORT_SYMBOL(alpha_write_fp_reg_s);
+
+-/* In-kernel system calls. */
++/* entry.S */
+ EXPORT_SYMBOL(kernel_thread);
+-EXPORT_SYMBOL(sys_dup);
+-EXPORT_SYMBOL(sys_exit);
+-EXPORT_SYMBOL(sys_write);
+-EXPORT_SYMBOL(sys_lseek);
+-EXPORT_SYMBOL(execve);
+-EXPORT_SYMBOL(sys_setsid);
+-EXPORT_SYMBOL(sys_wait4);
++EXPORT_SYMBOL(kernel_execve);
+
+ /* Networking helper routines. */
+ EXPORT_SYMBOL(csum_tcpudp_magic);
+@@ -135,10 +69,6 @@ EXPORT_SYMBOL(alpha_fp_emul_imprecise);
+ EXPORT_SYMBOL(alpha_fp_emul);
+ #endif
+
+-#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+-EXPORT_SYMBOL(__min_ipl);
+-#endif
+-
+ /*
+ * The following are specially called from the uaccess assembly stubs.
+ */
+@@ -161,27 +91,10 @@ EXPORT_SYMBOL(up);
+ */
+
+ #ifdef CONFIG_SMP
+-EXPORT_SYMBOL(flush_tlb_mm);
+-EXPORT_SYMBOL(flush_tlb_range);
+-EXPORT_SYMBOL(flush_tlb_page);
+-EXPORT_SYMBOL(smp_imb);
+-EXPORT_SYMBOL(cpu_data);
+-EXPORT_SYMBOL(smp_num_cpus);
+-EXPORT_SYMBOL(smp_call_function);
+-EXPORT_SYMBOL(smp_call_function_on_cpu);
+ EXPORT_SYMBOL(_atomic_dec_and_lock);
+ #endif /* CONFIG_SMP */
+
+ /*
+- * NUMA specific symbols
+- */
+-#ifdef CONFIG_DISCONTIGMEM
+-EXPORT_SYMBOL(node_data);
+-#endif /* CONFIG_DISCONTIGMEM */
+-
+-EXPORT_SYMBOL(rtc_lock);
+-
+-/*
+ * The following are special because they're not called
+ * explicitly (the C compiler or assembler generates them in
+ * response to division operations). Fortunately, their
+@@ -201,8 +114,3 @@ EXPORT_SYMBOL(__remqu);
+ EXPORT_SYMBOL(memcpy);
+ EXPORT_SYMBOL(memset);
+ EXPORT_SYMBOL(memchr);
+-
+-#ifdef CONFIG_ALPHA_IRONGATE
+-EXPORT_SYMBOL(irongate_ioremap);
+-EXPORT_SYMBOL(irongate_iounmap);
+-#endif
+diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c
+index a27ba12..ca46b2c 100644
+--- a/arch/alpha/kernel/core_apecs.c
++++ b/arch/alpha/kernel/core_apecs.c
+@@ -387,8 +387,7 @@ apecs_pci_clr_err(void)
+ }
+
+ void
+-apecs_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++apecs_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ struct el_common *mchk_header;
+ struct el_apecs_procdata *mchk_procdata;
+@@ -412,7 +411,7 @@ apecs_machine_check(unsigned long vector
+ wrmces(0x7); /* reset machine check pending flag */
+ mb();
+
+- process_mcheck_info(vector, la_ptr, regs, "APECS",
++ process_mcheck_info(vector, la_ptr, "APECS",
+ (mcheck_expected(0)
+ && (mchk_sysdata->epic_dcsr & 0x0c00UL)));
+ }
+diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
+index fd56306..1d6ee6c 100644
+--- a/arch/alpha/kernel/core_cia.c
++++ b/arch/alpha/kernel/core_cia.c
+@@ -1192,8 +1192,7 @@ cia_decode_mchk(unsigned long la_ptr)
+ }
+
+ void
+-cia_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++cia_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ int expected;
+
+@@ -1208,5 +1207,5 @@ cia_machine_check(unsigned long vector,
+ expected = mcheck_expected(0);
+ if (!expected && vector == 0x660)
+ expected = cia_decode_mchk(la_ptr);
+- process_mcheck_info(vector, la_ptr, regs, "CIA", expected);
++ process_mcheck_info(vector, la_ptr, "CIA", expected);
+ }
+diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c
+index 138d497..e4a0bcf 100644
+--- a/arch/alpha/kernel/core_irongate.c
++++ b/arch/alpha/kernel/core_irongate.c
+@@ -404,6 +404,7 @@ irongate_ioremap(unsigned long addr, uns
+ #endif
+ return (void __iomem *)vaddr;
+ }
++EXPORT_SYMBOL(irongate_ioremap);
+
+ void
+ irongate_iounmap(volatile void __iomem *xaddr)
+@@ -414,3 +415,4 @@ irongate_iounmap(volatile void __iomem *
+ if (addr)
+ return vfree((void *)(PAGE_MASK & addr));
+ }
++EXPORT_SYMBOL(irongate_iounmap);
+diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c
+index 6a5a914..4843f6e 100644
+--- a/arch/alpha/kernel/core_lca.c
++++ b/arch/alpha/kernel/core_lca.c
+@@ -19,6 +19,7 @@
+ #include <linux/tty.h>
+
+ #include <asm/ptrace.h>
++#include <asm/irq_regs.h>
+ #include <asm/smp.h>
+
+ #include "proto.h"
+@@ -386,8 +387,7 @@ ioc_error(__u32 stat0, __u32 stat1)
+ }
+
+ void
+-lca_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs *regs)
++lca_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ const char * reason;
+ union el_lca el;
+@@ -397,7 +397,7 @@ lca_machine_check(unsigned long vector,
+ wrmces(rdmces()); /* reset machine check pending flag */
+
+ printk(KERN_CRIT "LCA machine check: vector=%#lx pc=%#lx code=%#x\n",
+- vector, regs->pc, (unsigned int) el.c->code);
++ vector, get_irq_regs()->pc, (unsigned int) el.c->code);
+
+ /*
+ * The first quadword after the common header always seems to
+diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c
+index 28849c8..8d01907 100644
+--- a/arch/alpha/kernel/core_mcpcia.c
++++ b/arch/alpha/kernel/core_mcpcia.c
+@@ -572,8 +572,7 @@ mcpcia_print_system_area(unsigned long l
+ }
+
+ void
+-mcpcia_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++mcpcia_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ struct el_common *mchk_header;
+ struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
+@@ -610,7 +609,7 @@ mcpcia_machine_check(unsigned long vecto
+ wrmces(0x7);
+ mb();
+
+- process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0);
++ process_mcheck_info(vector, la_ptr, "MCPCIA", expected != 0);
+ if (!expected && vector != 0x620 && vector != 0x630) {
+ mcpcia_print_uncorrectable(mchk_logout);
+ mcpcia_print_system_area(la_ptr);
+diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c
+index 277674a..c5a271d 100644
+--- a/arch/alpha/kernel/core_polaris.c
++++ b/arch/alpha/kernel/core_polaris.c
+@@ -187,8 +187,7 @@ polaris_pci_clr_err(void)
+ }
+
+ void
+-polaris_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++polaris_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ /* Clear the error before any reporting. */
+ mb();
+@@ -198,6 +197,6 @@ polaris_machine_check(unsigned long vect
+ wrmces(0x7);
+ mb();
+
+- process_mcheck_info(vector, la_ptr, regs, "POLARIS",
++ process_mcheck_info(vector, la_ptr, "POLARIS",
+ mcheck_expected(0));
+ }
+diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
+index ecce09e..f5ca525 100644
+--- a/arch/alpha/kernel/core_t2.c
++++ b/arch/alpha/kernel/core_t2.c
+@@ -551,8 +551,7 @@ t2_clear_errors(int cpu)
+ * Hence all the taken/expected/any_expected/last_taken stuff...
+ */
+ void
+-t2_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++t2_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ int cpu = smp_processor_id();
+ #ifdef CONFIG_VERBOSE_MCHECK
+@@ -618,5 +617,5 @@ t2_machine_check(unsigned long vector, u
+ }
+ #endif
+
+- process_mcheck_info(vector, la_ptr, regs, "T2", mcheck_expected(cpu));
++ process_mcheck_info(vector, la_ptr, "T2", mcheck_expected(cpu));
+ }
+diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
+index 8aa305b..ce623c6 100644
+--- a/arch/alpha/kernel/core_tsunami.c
++++ b/arch/alpha/kernel/core_tsunami.c
+@@ -443,8 +443,7 @@ tsunami_pci_clr_err(void)
+ }
+
+ void
+-tsunami_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ /* Clear error before any reporting. */
+ mb();
+@@ -454,6 +453,6 @@ tsunami_machine_check(unsigned long vect
+ wrmces(0x7);
+ mb();
+
+- process_mcheck_info(vector, la_ptr, regs, "TSUNAMI",
++ process_mcheck_info(vector, la_ptr, "TSUNAMI",
+ mcheck_expected(smp_processor_id()));
+ }
+diff --git a/arch/alpha/kernel/core_wildfire.c b/arch/alpha/kernel/core_wildfire.c
+index 2b767a1..7e07244 100644
+--- a/arch/alpha/kernel/core_wildfire.c
++++ b/arch/alpha/kernel/core_wildfire.c
+@@ -322,8 +322,7 @@ wildfire_init_arch(void)
+ }
+
+ void
+-wildfire_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++wildfire_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ mb();
+ mb(); /* magic */
+@@ -332,7 +331,7 @@ wildfire_machine_check(unsigned long vec
+ wrmces(0x7);
+ mb();
+
+- process_mcheck_info(vector, la_ptr, regs, "WILDFIRE",
++ process_mcheck_info(vector, la_ptr, "WILDFIRE",
+ mcheck_expected(smp_processor_id()));
+ }
+
+diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
+index 01ecd09..c95e95e 100644
+--- a/arch/alpha/kernel/entry.S
++++ b/arch/alpha/kernel/entry.S
+@@ -655,12 +655,12 @@ kernel_thread:
+ .end kernel_thread
+
+ /*
+- * execve(path, argv, envp)
++ * kernel_execve(path, argv, envp)
+ */
+ .align 4
+- .globl execve
+- .ent execve
+-execve:
++ .globl kernel_execve
++ .ent kernel_execve
++kernel_execve:
+ /* We can be called from a module. */
+ ldgp $gp, 0($27)
+ lda $sp, -(32+SIZEOF_PT_REGS+8)($sp)
+@@ -704,7 +704,7 @@ execve:
+
+ 1: lda $sp, 32+SIZEOF_PT_REGS+8($sp)
+ ret
+-.end execve
++.end kernel_execve
+
+
+ /*
+diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
+index 64f59f2..69b5f4e 100644
+--- a/arch/alpha/kernel/err_ev6.c
++++ b/arch/alpha/kernel/err_ev6.c
+@@ -11,6 +11,7 @@
+ #include <linux/sched.h>
+
+ #include <asm/io.h>
++#include <asm/irq_regs.h>
+ #include <asm/hwrpb.h>
+ #include <asm/smp.h>
+ #include <asm/err_common.h>
+@@ -229,7 +230,7 @@ ev6_process_logout_frame(struct el_commo
+ }
+
+ void
+-ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
++ev6_machine_check(u64 vector, u64 la_ptr)
+ {
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+
+@@ -260,7 +261,7 @@ ev6_machine_check(u64 vector, u64 la_ptr
+ (unsigned int)vector, (int)smp_processor_id());
+
+ ev6_process_logout_frame(mchk_header, 1);
+- dik_show_regs(regs, NULL);
++ dik_show_regs(get_irq_regs(), NULL);
+
+ err_print_prefix = saved_err_prefix;
+ }
+diff --git a/arch/alpha/kernel/err_ev7.c b/arch/alpha/kernel/err_ev7.c
+index fed6b3d..95463ab 100644
+--- a/arch/alpha/kernel/err_ev7.c
++++ b/arch/alpha/kernel/err_ev7.c
+@@ -118,7 +118,7 @@ ev7_collect_logout_frame_subpackets(stru
+ }
+
+ void
+-ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
++ev7_machine_check(u64 vector, u64 la_ptr)
+ {
+ struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+ char *saved_err_prefix = err_print_prefix;
+diff --git a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h
+index 64e9b73..3c12258 100644
+--- a/arch/alpha/kernel/err_impl.h
++++ b/arch/alpha/kernel/err_impl.h
+@@ -60,26 +60,26 @@ extern struct ev7_lf_subpackets *
+ ev7_collect_logout_frame_subpackets(struct el_subpacket *,
+ struct ev7_lf_subpackets *);
+ extern void ev7_register_error_handlers(void);
+-extern void ev7_machine_check(u64, u64, struct pt_regs *);
++extern void ev7_machine_check(u64, u64);
+
+ /*
+ * err_ev6.c
+ */
+ extern void ev6_register_error_handlers(void);
+ extern int ev6_process_logout_frame(struct el_common *, int);
+-extern void ev6_machine_check(u64, u64, struct pt_regs *);
++extern void ev6_machine_check(u64, u64);
+
+ /*
+ * err_marvel.c
+ */
+-extern void marvel_machine_check(u64, u64, struct pt_regs *);
++extern void marvel_machine_check(u64, u64);
+ extern void marvel_register_error_handlers(void);
+
+ /*
+ * err_titan.c
+ */
+ extern int titan_process_logout_frame(struct el_common *, int);
+-extern void titan_machine_check(u64, u64, struct pt_regs *);
++extern void titan_machine_check(u64, u64);
+ extern void titan_register_error_handlers(void);
+ extern int privateer_process_logout_frame(struct el_common *, int);
+-extern void privateer_machine_check(u64, u64, struct pt_regs *);
++extern void privateer_machine_check(u64, u64);
+diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c
+index 70b38b1..f2956ac 100644
+--- a/arch/alpha/kernel/err_marvel.c
++++ b/arch/alpha/kernel/err_marvel.c
+@@ -1042,7 +1042,7 @@ marvel_process_logout_frame(struct ev7_l
+ }
+
+ void
+-marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
++marvel_machine_check(u64 vector, u64 la_ptr)
+ {
+ struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+ int (*process_frame)(struct ev7_lf_subpackets *, int) = NULL;
+@@ -1077,7 +1077,7 @@ marvel_machine_check(u64 vector, u64 la_
+
+ default:
+ /* Don't know it - pass it up. */
+- ev7_machine_check(vector, la_ptr, regs);
++ ev7_machine_check(vector, la_ptr);
+ return;
+ }
+
+diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c
+index 7e6720d..febe71c 100644
+--- a/arch/alpha/kernel/err_titan.c
++++ b/arch/alpha/kernel/err_titan.c
+@@ -379,7 +379,7 @@ titan_process_logout_frame(struct el_com
+ }
+
+ void
+-titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
++titan_machine_check(u64 vector, u64 la_ptr)
+ {
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+ struct el_TITAN_sysdata_mcheck *tmchk =
+@@ -408,7 +408,7 @@ titan_machine_check(u64 vector, u64 la_p
+ * Only handle system errors here
+ */
+ if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) {
+- ev6_machine_check(vector, la_ptr, regs);
++ ev6_machine_check(vector, la_ptr);
+ return;
+ }
+
+@@ -442,7 +442,7 @@ titan_machine_check(u64 vector, u64 la_p
+ #ifdef CONFIG_VERBOSE_MCHECK
+ titan_process_logout_frame(mchk_header, alpha_verbose_mcheck);
+ if (alpha_verbose_mcheck)
+- dik_show_regs(regs, NULL);
++ dik_show_regs(get_irq_regs(), NULL);
+ #endif /* CONFIG_VERBOSE_MCHECK */
+
+ err_print_prefix = saved_err_prefix;
+@@ -452,7 +452,7 @@ titan_machine_check(u64 vector, u64 la_p
+ * machine checks to interrupts
+ */
+ irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
+- titan_dispatch_irqs(irqmask, regs);
++ titan_dispatch_irqs(irqmask);
+ }
+
+
+@@ -701,7 +701,7 @@ privateer_process_logout_frame(struct el
+ }
+
+ void
+-privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
++privateer_machine_check(u64 vector, u64 la_ptr)
+ {
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+ struct el_TITAN_sysdata_mcheck *tmchk =
+@@ -723,7 +723,7 @@ privateer_machine_check(u64 vector, u64
+ * Only handle system events here.
+ */
+ if (vector != SCB_Q_SYSEVENT)
+- return titan_machine_check(vector, la_ptr, regs);
++ return titan_machine_check(vector, la_ptr);
+
+ /*
+ * Report the event - System Events should be reported even if no
+@@ -746,7 +746,7 @@ privateer_machine_check(u64 vector, u64
+ /*
+ * Dispatch the interrupt(s).
+ */
+- titan_dispatch_irqs(irqmask, regs);
++ titan_dispatch_irqs(irqmask);
+
+ /*
+ * Release the logout frame.
+diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
+index 1e2a62a..e27d23c 100644
+--- a/arch/alpha/kernel/head.S
++++ b/arch/alpha/kernel/head.S
+@@ -1,5 +1,5 @@
+ /*
+- * alpha/boot/head.S
++ * arch/alpha/kernel/head.S
+ *
+ * initial boot stuff.. At this point, the bootloader has already
+ * switched into OSF/1 PAL-code, and loaded us at the correct address
+diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
+index 729c475..facf82a 100644
+--- a/arch/alpha/kernel/irq.c
++++ b/arch/alpha/kernel/irq.c
+@@ -127,7 +127,7 @@ unlock:
+ #define MAX_ILLEGAL_IRQS 16
+
+ void
+-handle_irq(int irq, struct pt_regs * regs)
++handle_irq(int irq)
+ {
+ /*
+ * We ack quickly, we don't want the irq controller
+@@ -157,6 +157,6 @@ handle_irq(int irq, struct pt_regs * reg
+ * at IPL 0.
+ */
+ local_irq_disable();
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+ irq_exit();
+ }
+diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
+index ddf5cf8..e16aeb6 100644
+--- a/arch/alpha/kernel/irq_alpha.c
++++ b/arch/alpha/kernel/irq_alpha.c
+@@ -6,6 +6,7 @@
+ #include <linux/sched.h>
+ #include <linux/irq.h>
+ #include <linux/kernel_stat.h>
++#include <linux/module.h>
+
+ #include <asm/machvec.h>
+ #include <asm/dma.h>
+@@ -16,6 +17,7 @@
+ /* Hack minimum IPL during interrupt processing for broken hardware. */
+ #ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+ int __min_ipl;
++EXPORT_SYMBOL(__min_ipl);
+ #endif
+
+ /*
+@@ -30,6 +32,7 @@ dummy_perf(unsigned long vector, struct
+ }
+
+ void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
++EXPORT_SYMBOL(perf_irq);
+
+ /*
+ * The main interrupt entry point.
+@@ -39,6 +42,7 @@ asmlinkage void
+ do_entInt(unsigned long type, unsigned long vector,
+ unsigned long la_ptr, struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ switch (type) {
+ case 0:
+ #ifdef CONFIG_SMP
+@@ -51,6 +55,7 @@ do_entInt(unsigned long type, unsigned l
+ #endif
+ break;
+ case 1:
++ old_regs = set_irq_regs(regs);
+ #ifdef CONFIG_SMP
+ {
+ long cpu;
+@@ -61,18 +66,23 @@ do_entInt(unsigned long type, unsigned l
+ if (cpu != boot_cpuid) {
+ kstat_cpu(cpu).irqs[RTC_IRQ]++;
+ } else {
+- handle_irq(RTC_IRQ, regs);
++ handle_irq(RTC_IRQ);
+ }
+ }
+ #else
+- handle_irq(RTC_IRQ, regs);
++ handle_irq(RTC_IRQ);
+ #endif
++ set_irq_regs(old_regs);
+ return;
+ case 2:
+- alpha_mv.machine_check(vector, la_ptr, regs);
++ old_regs = set_irq_regs(regs);
++ alpha_mv.machine_check(vector, la_ptr);
++ set_irq_regs(old_regs);
+ return;
+ case 3:
+- alpha_mv.device_interrupt(vector, regs);
++ old_regs = set_irq_regs(regs);
++ alpha_mv.device_interrupt(vector);
++ set_irq_regs(old_regs);
+ return;
+ case 4:
+ perf_irq(la_ptr, regs);
+@@ -120,8 +130,7 @@ struct mcheck_info __mcheck_info;
+
+ void
+ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs *regs, const char *machine,
+- int expected)
++ const char *machine, int expected)
+ {
+ struct el_common *mchk_header;
+ const char *reason;
+@@ -148,7 +157,7 @@ process_mcheck_info(unsigned long vector
+ mchk_header = (struct el_common *)la_ptr;
+
+ printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
+- machine, vector, regs->pc, mchk_header->code);
++ machine, vector, get_irq_regs()->pc, mchk_header->code);
+
+ switch (mchk_header->code) {
+ /* Machine check reasons. Defined according to PALcode sources. */
+@@ -189,7 +198,7 @@ process_mcheck_info(unsigned long vector
+ printk(KERN_CRIT "machine check type: %s%s\n",
+ reason, mchk_header->retry ? " (retryable)" : "");
+
+- dik_show_regs(regs, NULL);
++ dik_show_regs(get_irq_regs(), NULL);
+
+ #ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
+index ebbadbc..9405bee 100644
+--- a/arch/alpha/kernel/irq_i8259.c
++++ b/arch/alpha/kernel/irq_i8259.c
+@@ -137,7 +137,7 @@ init_i8259a_irqs(void)
+
+ #if defined(IACK_SC)
+ void
+-isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
++isa_device_interrupt(unsigned long vector)
+ {
+ /*
+ * Generate a PCI interrupt acknowledge cycle. The PIC will
+@@ -147,13 +147,13 @@ isa_device_interrupt(unsigned long vecto
+ */
+ int j = *(vuip) IACK_SC;
+ j &= 0xff;
+- handle_irq(j, regs);
++ handle_irq(j);
+ }
+ #endif
+
+ #if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
+ void
+-isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs)
++isa_no_iack_sc_device_interrupt(unsigned long vector)
+ {
+ unsigned long pic;
+
+@@ -176,7 +176,7 @@ isa_no_iack_sc_device_interrupt(unsigned
+ while (pic) {
+ int j = ffz(~pic);
+ pic &= pic - 1;
+- handle_irq(j, regs);
++ handle_irq(j);
+ }
+ }
+ #endif
+diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h
+index f201d8f..cc9a8a7 100644
+--- a/arch/alpha/kernel/irq_impl.h
++++ b/arch/alpha/kernel/irq_impl.h
+@@ -15,10 +15,10 @@
+
+ #define RTC_IRQ 8
+
+-extern void isa_device_interrupt(unsigned long, struct pt_regs *);
+-extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *);
+-extern void srm_device_interrupt(unsigned long, struct pt_regs *);
+-extern void pyxis_device_interrupt(unsigned long, struct pt_regs *);
++extern void isa_device_interrupt(unsigned long);
++extern void isa_no_iack_sc_device_interrupt(unsigned long);
++extern void srm_device_interrupt(unsigned long);
++extern void pyxis_device_interrupt(unsigned long);
+
+ extern struct irqaction timer_irqaction;
+ extern struct irqaction isa_cascade_irqaction;
+@@ -39,4 +39,4 @@ extern void i8259a_end_irq(unsigned int)
+ extern struct hw_interrupt_type i8259a_irq_type;
+ extern void init_i8259a_irqs(void);
+
+-extern void handle_irq(int irq, struct pt_regs * regs);
++extern void handle_irq(int irq);
+diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c
+index 3b58141..d53edbc 100644
+--- a/arch/alpha/kernel/irq_pyxis.c
++++ b/arch/alpha/kernel/irq_pyxis.c
+@@ -81,7 +81,7 @@ static struct hw_interrupt_type pyxis_ir
+ };
+
+ void
+-pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
++pyxis_device_interrupt(unsigned long vector)
+ {
+ unsigned long pld;
+ unsigned int i;
+@@ -98,9 +98,9 @@ pyxis_device_interrupt(unsigned long vec
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 7)
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ else
+- handle_irq(16+i, regs);
++ handle_irq(16+i);
+ }
+ }
+
+diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c
+index 8e4d121..3221201 100644
+--- a/arch/alpha/kernel/irq_srm.c
++++ b/arch/alpha/kernel/irq_srm.c
+@@ -72,8 +72,8 @@ init_srm_irqs(long max, unsigned long ig
+ }
+
+ void
+-srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++srm_device_interrupt(unsigned long vector)
+ {
+ int irq = (vector - 0x800) >> 4;
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
+index 08b8302..0caa45a 100644
+--- a/arch/alpha/kernel/machvec_impl.h
++++ b/arch/alpha/kernel/machvec_impl.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/alpha/kernel/machvec.h
++ * linux/arch/alpha/kernel/machvec_impl.h
+ *
+ * Copyright (C) 1997, 1998 Richard Henderson
+ *
+diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
+index 73c7622..ad61736 100644
+--- a/arch/alpha/kernel/osf_sys.c
++++ b/arch/alpha/kernel/osf_sys.c
+@@ -111,22 +111,26 @@ struct osf_dirent_callback {
+
+ static int
+ osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
+- ino_t ino, unsigned int d_type)
++ u64 ino, unsigned int d_type)
+ {
+ struct osf_dirent __user *dirent;
+ struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
+ unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
++ unsigned int d_ino;
+
+ buf->error = -EINVAL; /* only used if we fail */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ if (buf->basep) {
+ if (put_user(offset, buf->basep))
+ return -EFAULT;
+ buf->basep = NULL;
+ }
+ dirent = buf->dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ if (copy_to_user(dirent->d_name, name, namlen) ||
+@@ -402,15 +406,15 @@ osf_utsname(char __user *name)
+
+ down_read(&uts_sem);
+ error = -EFAULT;
+- if (copy_to_user(name + 0, system_utsname.sysname, 32))
++ if (copy_to_user(name + 0, utsname()->sysname, 32))
+ goto out;
+- if (copy_to_user(name + 32, system_utsname.nodename, 32))
++ if (copy_to_user(name + 32, utsname()->nodename, 32))
+ goto out;
+- if (copy_to_user(name + 64, system_utsname.release, 32))
++ if (copy_to_user(name + 64, utsname()->release, 32))
+ goto out;
+- if (copy_to_user(name + 96, system_utsname.version, 32))
++ if (copy_to_user(name + 96, utsname()->version, 32))
+ goto out;
+- if (copy_to_user(name + 128, system_utsname.machine, 32))
++ if (copy_to_user(name + 128, utsname()->machine, 32))
+ goto out;
+
+ error = 0;
+@@ -449,8 +453,8 @@ osf_getdomainname(char __user *name, int
+
+ down_read(&uts_sem);
+ for (i = 0; i < len; ++i) {
+- __put_user(system_utsname.domainname[i], name + i);
+- if (system_utsname.domainname[i] == '\0')
++ __put_user(utsname()->domainname[i], name + i);
++ if (utsname()->domainname[i] == '\0')
+ break;
+ }
+ up_read(&uts_sem);
+@@ -607,12 +611,12 @@ osf_sigstack(struct sigstack __user *uss
+ asmlinkage long
+ osf_sysinfo(int command, char __user *buf, long count)
+ {
+- static char * sysinfo_table[] = {
+- system_utsname.sysname,
+- system_utsname.nodename,
+- system_utsname.release,
+- system_utsname.version,
+- system_utsname.machine,
++ char *sysinfo_table[] = {
++ utsname()->sysname,
++ utsname()->nodename,
++ utsname()->release,
++ utsname()->version,
++ utsname()->machine,
+ "alpha", /* instruction set architecture */
+ "dummy", /* hardware serial number */
+ "dummy", /* hardware manufacturer */
+diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
+index fff5cf9..174b729 100644
+--- a/arch/alpha/kernel/pci-noop.c
++++ b/arch/alpha/kernel/pci-noop.c
+@@ -201,6 +201,7 @@ dma_set_mask(struct device *dev, u64 mas
+
+ return 0;
+ }
++EXPORT_SYMBOL(dma_set_mask);
+
+ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+ {
+diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
+index c468e31..6e7d1fe 100644
+--- a/arch/alpha/kernel/pci_iommu.c
++++ b/arch/alpha/kernel/pci_iommu.c
+@@ -300,6 +300,7 @@ pci_map_single(struct pci_dev *pdev, voi
+ dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
+ return pci_map_single_1(pdev, cpu_addr, size, dac_allowed);
+ }
++EXPORT_SYMBOL(pci_map_single);
+
+ dma_addr_t
+ pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset,
+@@ -314,6 +315,7 @@ pci_map_page(struct pci_dev *pdev, struc
+ return pci_map_single_1(pdev, (char *)page_address(page) + offset,
+ size, dac_allowed);
+ }
++EXPORT_SYMBOL(pci_map_page);
+
+ /* Unmap a single streaming mode DMA translation. The DMA_ADDR and
+ SIZE must match what was provided for in a previous pci_map_single
+@@ -379,6 +381,7 @@ pci_unmap_single(struct pci_dev *pdev, d
+ DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n",
+ dma_addr, size, npages, __builtin_return_address(0));
+ }
++EXPORT_SYMBOL(pci_unmap_single);
+
+ void
+ pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr,
+@@ -386,6 +389,7 @@ pci_unmap_page(struct pci_dev *pdev, dma
+ {
+ pci_unmap_single(pdev, dma_addr, size, direction);
+ }
++EXPORT_SYMBOL(pci_unmap_page);
+
+ /* Allocate and map kernel buffer using consistent mode DMA for PCI
+ device. Returns non-NULL cpu-view pointer to the buffer if
+@@ -427,6 +431,7 @@ try_again:
+
+ return cpu_addr;
+ }
++EXPORT_SYMBOL(pci_alloc_consistent);
+
+ /* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must
+ be values that were returned from pci_alloc_consistent. SIZE must
+@@ -444,7 +449,7 @@ pci_free_consistent(struct pci_dev *pdev
+ DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
+ dma_addr, size, __builtin_return_address(0));
+ }
+-
++EXPORT_SYMBOL(pci_free_consistent);
+
+ /* Classify the elements of the scatterlist. Write dma_address
+ of each element with:
+@@ -672,6 +677,7 @@ pci_map_sg(struct pci_dev *pdev, struct
+ pci_unmap_sg(pdev, start, out - start, direction);
+ return 0;
+ }
++EXPORT_SYMBOL(pci_map_sg);
+
+ /* Unmap a set of streaming mode DMA translations. Again, cpu read
+ rules concerning calls here are the same as for pci_unmap_single()
+@@ -752,6 +758,7 @@ pci_unmap_sg(struct pci_dev *pdev, struc
+
+ DBGA("pci_unmap_sg: %ld entries\n", nents - (end - sg));
+ }
++EXPORT_SYMBOL(pci_unmap_sg);
+
+
+ /* Return whether the given PCI device DMA address mask can be
+@@ -786,6 +793,7 @@ pci_dma_supported(struct pci_dev *pdev,
+
+ return 0;
+ }
++EXPORT_SYMBOL(pci_dma_supported);
+
+
+ /*
+@@ -908,6 +916,7 @@ pci_dac_dma_supported(struct pci_dev *de
+
+ return ok;
+ }
++EXPORT_SYMBOL(pci_dac_dma_supported);
+
+ dma64_addr_t
+ pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page,
+@@ -917,6 +926,7 @@ pci_dac_page_to_dma(struct pci_dev *pdev
+ + __pa(page_address(page))
+ + (dma64_addr_t) offset);
+ }
++EXPORT_SYMBOL(pci_dac_page_to_dma);
+
+ struct page *
+ pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+@@ -924,13 +934,14 @@ pci_dac_dma_to_page(struct pci_dev *pdev
+ unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset;
+ return virt_to_page(__va(paddr));
+ }
++EXPORT_SYMBOL(pci_dac_dma_to_page);
+
+ unsigned long
+ pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+ {
+ return (dma_addr & ~PAGE_MASK);
+ }
+-
++EXPORT_SYMBOL(pci_dac_dma_to_offset);
+
+ /* Helper for generic DMA-mapping functions. */
+
+@@ -957,6 +968,7 @@ alpha_gendev_to_pci(struct device *dev)
+ /* This assumes ISA bus master with dma_mask 0xffffff. */
+ return NULL;
+ }
++EXPORT_SYMBOL(alpha_gendev_to_pci);
+
+ int
+ dma_set_mask(struct device *dev, u64 mask)
+@@ -969,3 +981,4 @@ dma_set_mask(struct device *dev, u64 mas
+
+ return 0;
+ }
++EXPORT_SYMBOL(dma_set_mask);
+diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
+index b3a8a29..3370e6f 100644
+--- a/arch/alpha/kernel/process.c
++++ b/arch/alpha/kernel/process.c
+@@ -205,6 +205,7 @@ start_thread(struct pt_regs * regs, unsi
+ regs->ps = 8;
+ wrusp(sp);
+ }
++EXPORT_SYMBOL(start_thread);
+
+ /*
+ * Free current thread data structures etc..
+@@ -376,6 +377,7 @@ dump_thread(struct pt_regs * pt, struct
+ dump->regs[EF_A2] = pt->r18;
+ memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
+ }
++EXPORT_SYMBOL(dump_thread);
+
+ /*
+ * Fill in the user structure for a ELF core dump.
+@@ -424,6 +426,7 @@ dump_elf_thread(elf_greg_t *dest, struct
+ useful value of the thread's UNIQUE field. */
+ dest[32] = ti->pcb.unique;
+ }
++EXPORT_SYMBOL(dump_elf_thread);
+
+ int
+ dump_elf_task(elf_greg_t *dest, struct task_struct *task)
+@@ -431,6 +434,7 @@ dump_elf_task(elf_greg_t *dest, struct t
+ dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task));
+ return 1;
+ }
++EXPORT_SYMBOL(dump_elf_task);
+
+ int
+ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
+@@ -439,6 +443,7 @@ dump_elf_task_fp(elf_fpreg_t *dest, stru
+ memcpy(dest, sw->fp, 32 * 8);
+ return 1;
+ }
++EXPORT_SYMBOL(dump_elf_task_fp);
+
+ /*
+ * sys_execve() executes a new program.
+diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
+index 2a6e3da..95912ec 100644
+--- a/arch/alpha/kernel/proto.h
++++ b/arch/alpha/kernel/proto.h
+@@ -1,5 +1,7 @@
+ #include <linux/interrupt.h>
++#include <linux/io.h>
+
++#include <asm/pgtable.h>
+
+ /* Prototypes of functions used across modules here in this directory. */
+
+@@ -18,7 +20,7 @@ struct pci_controller;
+ extern struct pci_ops apecs_pci_ops;
+ extern void apecs_init_arch(void);
+ extern void apecs_pci_clr_err(void);
+-extern void apecs_machine_check(u64, u64, struct pt_regs *);
++extern void apecs_machine_check(u64, u64);
+ extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
+ /* core_cia.c */
+@@ -27,27 +29,27 @@ extern void cia_init_pci(void);
+ extern void cia_init_arch(void);
+ extern void pyxis_init_arch(void);
+ extern void cia_kill_arch(int);
+-extern void cia_machine_check(u64, u64, struct pt_regs *);
++extern void cia_machine_check(u64, u64);
+ extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
+ /* core_irongate.c */
+ extern struct pci_ops irongate_pci_ops;
+ extern int irongate_pci_clr_err(void);
+ extern void irongate_init_arch(void);
+-extern void irongate_machine_check(u64, u64, struct pt_regs *);
++extern void irongate_machine_check(u64, u64);
+ #define irongate_pci_tbi ((void *)0)
+
+ /* core_lca.c */
+ extern struct pci_ops lca_pci_ops;
+ extern void lca_init_arch(void);
+-extern void lca_machine_check(u64, u64, struct pt_regs *);
++extern void lca_machine_check(u64, u64);
+ extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
+ /* core_marvel.c */
+ extern struct pci_ops marvel_pci_ops;
+ extern void marvel_init_arch(void);
+ extern void marvel_kill_arch(int);
+-extern void marvel_machine_check(u64, u64, struct pt_regs *);
++extern void marvel_machine_check(u64, u64);
+ extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+ extern int marvel_pa_to_nid(unsigned long);
+ extern int marvel_cpuid_to_nid(int);
+@@ -62,7 +64,7 @@ void io7_clear_errors(struct io7 *io7);
+ extern struct pci_ops mcpcia_pci_ops;
+ extern void mcpcia_init_arch(void);
+ extern void mcpcia_init_hoses(void);
+-extern void mcpcia_machine_check(u64, u64, struct pt_regs *);
++extern void mcpcia_machine_check(u64, u64);
+ extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
+ /* core_polaris.c */
+@@ -70,21 +72,21 @@ extern struct pci_ops polaris_pci_ops;
+ extern int polaris_read_config_dword(struct pci_dev *, int, u32 *);
+ extern int polaris_write_config_dword(struct pci_dev *, int, u32);
+ extern void polaris_init_arch(void);
+-extern void polaris_machine_check(u64, u64, struct pt_regs *);
++extern void polaris_machine_check(u64, u64);
+ #define polaris_pci_tbi ((void *)0)
+
+ /* core_t2.c */
+ extern struct pci_ops t2_pci_ops;
+ extern void t2_init_arch(void);
+ extern void t2_kill_arch(int);
+-extern void t2_machine_check(u64, u64, struct pt_regs *);
++extern void t2_machine_check(u64, u64);
+ extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
+ /* core_titan.c */
+ extern struct pci_ops titan_pci_ops;
+ extern void titan_init_arch(void);
+ extern void titan_kill_arch(int);
+-extern void titan_machine_check(u64, u64, struct pt_regs *);
++extern void titan_machine_check(u64, u64);
+ extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+ extern struct _alpha_agp_info *titan_agp_info(void);
+
+@@ -92,14 +94,14 @@ extern struct _alpha_agp_info *titan_agp
+ extern struct pci_ops tsunami_pci_ops;
+ extern void tsunami_init_arch(void);
+ extern void tsunami_kill_arch(int);
+-extern void tsunami_machine_check(u64, u64, struct pt_regs *);
++extern void tsunami_machine_check(u64, u64);
+ extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
+ /* core_wildfire.c */
+ extern struct pci_ops wildfire_pci_ops;
+ extern void wildfire_init_arch(void);
+ extern void wildfire_kill_arch(int);
+-extern void wildfire_machine_check(u64, u64, struct pt_regs *);
++extern void wildfire_machine_check(u64, u64);
+ extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+ extern int wildfire_pa_to_nid(unsigned long);
+ extern int wildfire_cpuid_to_nid(int);
+@@ -131,7 +133,7 @@ extern void smp_percpu_timer_interrupt(s
+ /* extern void reset_for_srm(void); */
+
+ /* time.c */
+-extern irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs);
++extern irqreturn_t timer_interrupt(int irq, void *dev);
+ extern void common_init_rtc(void);
+ extern unsigned long est_cycle_freq;
+
+@@ -175,15 +177,22 @@ extern void dik_show_regs(struct pt_regs
+ extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *);
+
+ /* sys_titan.c */
+-extern void titan_dispatch_irqs(u64, struct pt_regs *);
++extern void titan_dispatch_irqs(u64);
+
+ /* ../mm/init.c */
+ extern void switch_to_system_map(void);
+ extern void srm_paging_stop(void);
+
+-/* ../mm/remap.c */
+-extern int __alpha_remap_area_pages(unsigned long, unsigned long,
+- unsigned long, unsigned long);
++static inline int
++__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
++ unsigned long size, unsigned long flags)
++{
++ pgprot_t prot;
++
++ prot = __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE
++ | _PAGE_KWE | flags);
++ return ioremap_page_range(address, address + size, phys_addr, prot);
++}
+
+ /* irq.c */
+
+@@ -205,5 +214,4 @@ extern struct mcheck_info
+ #endif
+
+ extern void process_mcheck_info(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs *regs, const char *machine,
+- int expected);
++ const char *machine, int expected);
+diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
+index fd4a8fa..1aea7c7 100644
+--- a/arch/alpha/kernel/setup.c
++++ b/arch/alpha/kernel/setup.c
+@@ -21,7 +21,6 @@
+ #include <linux/a.out.h>
+ #include <linux/screen_info.h>
+ #include <linux/delay.h>
+-#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
+ #include <linux/mc146818rtc.h>
+ #include <linux/console.h>
+ #include <linux/cpu.h>
+@@ -67,6 +66,7 @@ static struct notifier_block alpha_panic
+
+
+ struct hwrpb_struct *hwrpb;
++EXPORT_SYMBOL(hwrpb);
+ unsigned long srm_hae;
+
+ int alpha_l1i_cacheshape;
+@@ -112,6 +112,7 @@ unsigned long alpha_agpgart_size = DEFAU
+ #ifdef CONFIG_ALPHA_GENERIC
+ struct alpha_machine_vector alpha_mv;
+ int alpha_using_srm;
++EXPORT_SYMBOL(alpha_using_srm);
+ #endif
+
+ static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long,
+@@ -138,6 +139,8 @@ struct screen_info screen_info = {
+ .orig_video_points = 16
+ };
+
++EXPORT_SYMBOL(screen_info);
++
+ /*
+ * The direct map I/O window, if any. This should be the same
+ * for all busses, since it's used by virt_to_bus.
+@@ -145,6 +148,8 @@ struct screen_info screen_info = {
+
+ unsigned long __direct_map_base;
+ unsigned long __direct_map_size;
++EXPORT_SYMBOL(__direct_map_base);
++EXPORT_SYMBOL(__direct_map_size);
+
+ /*
+ * Declare all of the machine vectors.
+diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
+index 4dc273e..d1ec4f5 100644
+--- a/arch/alpha/kernel/smp.c
++++ b/arch/alpha/kernel/smp.c
+@@ -52,6 +52,7 @@
+
+ /* A collection of per-processor data. */
+ struct cpuinfo_alpha cpu_data[NR_CPUS];
++EXPORT_SYMBOL(cpu_data);
+
+ /* A collection of single bit ipi messages. */
+ static struct {
+@@ -74,6 +75,7 @@ EXPORT_SYMBOL(cpu_online_map);
+
+ int smp_num_probed; /* Internal processor count */
+ int smp_num_cpus = 1; /* Number that came online. */
++EXPORT_SYMBOL(smp_num_cpus);
+
+ extern void calibrate_delay(void);
+
+@@ -515,12 +517,15 @@ smp_cpus_done(unsigned int max_cpus)
+ void
+ smp_percpu_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ int cpu = smp_processor_id();
+ unsigned long user = user_mode(regs);
+ struct cpuinfo_alpha *data = &cpu_data[cpu];
+
++ old_regs = set_irq_regs(regs);
++
+ /* Record kernel PC. */
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+
+ if (!--data->prof_counter) {
+ /* We need to make like a normal interrupt -- otherwise
+@@ -534,6 +539,7 @@ smp_percpu_timer_interrupt(struct pt_reg
+
+ irq_exit();
+ }
++ set_irq_regs(old_regs);
+ }
+
+ int __init
+@@ -786,6 +792,7 @@ smp_call_function_on_cpu (void (*func) (
+
+ return 0;
+ }
++EXPORT_SYMBOL(smp_call_function_on_cpu);
+
+ int
+ smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+@@ -793,6 +800,7 @@ smp_call_function (void (*func) (void *i
+ return smp_call_function_on_cpu (func, info, retry, wait,
+ cpu_online_map);
+ }
++EXPORT_SYMBOL(smp_call_function);
+
+ static void
+ ipi_imb(void *ignored)
+@@ -807,6 +815,7 @@ smp_imb(void)
+ if (on_each_cpu(ipi_imb, NULL, 1, 1))
+ printk(KERN_CRIT "smp_imb: timed out\n");
+ }
++EXPORT_SYMBOL(smp_imb);
+
+ static void
+ ipi_flush_tlb_all(void *ignored)
+@@ -862,6 +871,7 @@ flush_tlb_mm(struct mm_struct *mm)
+
+ preempt_enable();
+ }
++EXPORT_SYMBOL(flush_tlb_mm);
+
+ struct flush_tlb_page_struct {
+ struct vm_area_struct *vma;
+@@ -914,6 +924,7 @@ flush_tlb_page(struct vm_area_struct *vm
+
+ preempt_enable();
+ }
++EXPORT_SYMBOL(flush_tlb_page);
+
+ void
+ flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+@@ -921,6 +932,7 @@ flush_tlb_range(struct vm_area_struct *v
+ /* On the Alpha we always flush the whole user tlb. */
+ flush_tlb_mm(vma->vm_mm);
+ }
++EXPORT_SYMBOL(flush_tlb_range);
+
+ static void
+ ipi_flush_icache_page(void *x)
+diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c
+index 990ac61..f7dd081 100644
+--- a/arch/alpha/kernel/srm_env.c
++++ b/arch/alpha/kernel/srm_env.c
+@@ -2,7 +2,7 @@
+ * srm_env.c - Access to SRM environment
+ * variables through linux' procfs
+ *
+- * Copyright (C) 2001-2002 Jan-Benedict Glaw <jbglaw at lug-owl.de>
++ * (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw at lug-owl.de>
+ *
+ * This driver is at all a modified version of Erik Mouw's
+ * Documentation/DocBook/procfs_example.c, so: thank
+@@ -21,7 +21,7 @@
+ * 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,
+@@ -29,33 +29,6 @@
+ *
+ */
+
+-/*
+- * Changelog
+- * ~~~~~~~~~
+- *
+- * Thu, 22 Aug 2002 15:10:43 +0200
+- * - Update Config.help entry. I got a number of emails asking
+- * me to tell their senders if they could make use of this
+- * piece of code... So: "SRM is something like BIOS for your
+- * Alpha"
+- * - Update code formatting a bit to better conform CodingStyle
+- * rules.
+- * - So this is v0.0.5, with no changes (except formatting)
+- *
+- * Wed, 22 May 2002 00:11:21 +0200
+- * - Fix typo on comment (SRC -> SRM)
+- * - Call this "Version 0.0.4"
+- *
+- * Tue, 9 Apr 2002 18:44:40 +0200
+- * - Implement access by variable name and additionally
+- * by number. This is done by creating two subdirectories
+- * where one holds all names (like the old directory
+- * did) and the other holding 256 files named like "0",
+- * "1" and so on.
+- * - Call this "Version 0.0.3"
+- *
+- */
+-
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+@@ -67,7 +40,7 @@
+ #define BASE_DIR "srm_environment" /* Subdir in /proc/ */
+ #define NAMED_DIR "named_variables" /* Subdir for known variables */
+ #define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */
+-#define VERSION "0.0.5" /* Module version */
++#define VERSION "0.0.6" /* Module version */
+ #define NAME "srm_env" /* Module name */
+
+ MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw at lug-owl.de>");
+@@ -106,7 +79,6 @@ static srm_env_t srm_named_entries[] = {
+ static srm_env_t srm_numbered_entries[256];
+
+
+-
+ static int
+ srm_env_read(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+@@ -115,21 +87,23 @@ srm_env_read(char *page, char **start, o
+ unsigned long ret;
+ srm_env_t *entry;
+
+- if(off != 0)
+- return -EFAULT;
++ if (off != 0) {
++ *eof = 1;
++ return 0;
++ }
+
+ entry = (srm_env_t *) data;
+ ret = callback_getenv(entry->id, page, count);
+
+- if((ret >> 61) == 0)
++ if ((ret >> 61) == 0) {
+ nbytes = (int) ret;
+- else
++ *eof = 1;
++ } else
+ nbytes = -EFAULT;
+
+ return nbytes;
+ }
+
+-
+ static int
+ srm_env_write(struct file *file, const char __user *buffer, unsigned long count,
+ void *data)
+@@ -155,7 +129,7 @@ srm_env_write(struct file *file, const c
+
+ ret1 = callback_setenv(entry->id, buf, count);
+ if ((ret1 >> 61) == 0) {
+- do
++ do
+ ret2 = callback_save_env();
+ while((ret2 >> 61) == 1);
+ res = (int) ret1;
+@@ -172,14 +146,14 @@ srm_env_cleanup(void)
+ srm_env_t *entry;
+ unsigned long var_num;
+
+- if(base_dir) {
++ if (base_dir) {
+ /*
+ * Remove named entries
+ */
+- if(named_dir) {
++ if (named_dir) {
+ entry = srm_named_entries;
+- while(entry->name != NULL && entry->id != 0) {
+- if(entry->proc_entry) {
++ while (entry->name != NULL && entry->id != 0) {
++ if (entry->proc_entry) {
+ remove_proc_entry(entry->name,
+ named_dir);
+ entry->proc_entry = NULL;
+@@ -192,11 +166,11 @@ srm_env_cleanup(void)
+ /*
+ * Remove numbered entries
+ */
+- if(numbered_dir) {
+- for(var_num = 0; var_num <= 255; var_num++) {
++ if (numbered_dir) {
++ for (var_num = 0; var_num <= 255; var_num++) {
+ entry = &srm_numbered_entries[var_num];
+
+- if(entry->proc_entry) {
++ if (entry->proc_entry) {
+ remove_proc_entry(entry->name,
+ numbered_dir);
+ entry->proc_entry = NULL;
+@@ -212,7 +186,6 @@ srm_env_cleanup(void)
+ return;
+ }
+
+-
+ static int __init
+ srm_env_init(void)
+ {
+@@ -222,7 +195,7 @@ srm_env_init(void)
+ /*
+ * Check system
+ */
+- if(!alpha_using_srm) {
++ if (!alpha_using_srm) {
+ printk(KERN_INFO "%s: This Alpha system doesn't "
+ "know about SRM (or you've booted "
+ "SRM->MILO->Linux, which gets "
+@@ -233,14 +206,14 @@ srm_env_init(void)
+ /*
+ * Init numbers
+ */
+- for(var_num = 0; var_num <= 255; var_num++)
++ for (var_num = 0; var_num <= 255; var_num++)
+ sprintf(number[var_num], "%ld", var_num);
+
+ /*
+ * Create base directory
+ */
+ base_dir = proc_mkdir(BASE_DIR, NULL);
+- if(base_dir == NULL) {
++ if (!base_dir) {
+ printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
+ BASE_DIR);
+ goto cleanup;
+@@ -251,7 +224,7 @@ srm_env_init(void)
+ * Create per-name subdirectory
+ */
+ named_dir = proc_mkdir(NAMED_DIR, base_dir);
+- if(named_dir == NULL) {
++ if (!named_dir) {
+ printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
+ BASE_DIR, NAMED_DIR);
+ goto cleanup;
+@@ -262,7 +235,7 @@ srm_env_init(void)
+ * Create per-number subdirectory
+ */
+ numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
+- if(numbered_dir == NULL) {
++ if (!numbered_dir) {
+ printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
+ BASE_DIR, NUMBERED_DIR);
+ goto cleanup;
+@@ -274,10 +247,10 @@ srm_env_init(void)
+ * Create all named nodes
+ */
+ entry = srm_named_entries;
+- while(entry->name != NULL && entry->id != 0) {
++ while (entry->name && entry->id) {
+ entry->proc_entry = create_proc_entry(entry->name,
+ 0644, named_dir);
+- if(entry->proc_entry == NULL)
++ if (!entry->proc_entry)
+ goto cleanup;
+
+ entry->proc_entry->data = (void *) entry;
+@@ -291,13 +264,13 @@ srm_env_init(void)
+ /*
+ * Create all numbered nodes
+ */
+- for(var_num = 0; var_num <= 255; var_num++) {
++ for (var_num = 0; var_num <= 255; var_num++) {
+ entry = &srm_numbered_entries[var_num];
+ entry->name = number[var_num];
+
+ entry->proc_entry = create_proc_entry(entry->name,
+ 0644, numbered_dir);
+- if(entry->proc_entry == NULL)
++ if (!entry->proc_entry)
+ goto cleanup;
+
+ entry->id = var_num;
+@@ -318,7 +291,6 @@ cleanup:
+ return -ENOMEM;
+ }
+
+-
+ static void __exit
+ srm_env_exit(void)
+ {
+@@ -328,7 +300,5 @@ srm_env_exit(void)
+ return;
+ }
+
+-
+ module_init(srm_env_init);
+ module_exit(srm_env_exit);
+-
+diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
+index 9d7dff2..7569232 100644
+--- a/arch/alpha/kernel/srmcons.c
++++ b/arch/alpha/kernel/srmcons.c
+@@ -229,7 +229,7 @@ srmcons_close(struct tty_struct *tty, st
+
+ static struct tty_driver *srmcons_driver;
+
+-static struct tty_operations srmcons_ops = {
++static const struct tty_operations srmcons_ops = {
+ .open = srmcons_open,
+ .close = srmcons_close,
+ .write = srmcons_write,
+diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
+index d6926b7..49bedfb 100644
+--- a/arch/alpha/kernel/sys_alcor.c
++++ b/arch/alpha/kernel/sys_alcor.c
+@@ -100,7 +100,7 @@ static struct hw_interrupt_type alcor_ir
+ };
+
+ static void
+-alcor_device_interrupt(unsigned long vector, struct pt_regs *regs)
++alcor_device_interrupt(unsigned long vector)
+ {
+ unsigned long pld;
+ unsigned int i;
+@@ -116,9 +116,9 @@ alcor_device_interrupt(unsigned long vec
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 31) {
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ } else {
+- handle_irq(16 + i, regs);
++ handle_irq(16 + i);
+ }
+ }
+ }
+diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
+index 25a2150..ace475c 100644
+--- a/arch/alpha/kernel/sys_cabriolet.c
++++ b/arch/alpha/kernel/sys_cabriolet.c
+@@ -82,7 +82,7 @@ static struct hw_interrupt_type cabriole
+ };
+
+ static void
+-cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
++cabriolet_device_interrupt(unsigned long v)
+ {
+ unsigned long pld;
+ unsigned int i;
+@@ -98,15 +98,15 @@ cabriolet_device_interrupt(unsigned long
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 4) {
+- isa_device_interrupt(v, r);
++ isa_device_interrupt(v);
+ } else {
+- handle_irq(16 + i, r);
++ handle_irq(16 + i);
+ }
+ }
+ }
+
+ static void __init
+-common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
++common_init_irq(void (*srm_dev_int)(unsigned long v))
+ {
+ init_i8259a_irqs();
+
+@@ -154,18 +154,18 @@ cabriolet_init_irq(void)
+ too invasive though. */
+
+ static void
+-pc164_srm_device_interrupt(unsigned long v, struct pt_regs *r)
++pc164_srm_device_interrupt(unsigned long v)
+ {
+ __min_ipl = getipl();
+- srm_device_interrupt(v, r);
++ srm_device_interrupt(v);
+ __min_ipl = 0;
+ }
+
+ static void
+-pc164_device_interrupt(unsigned long v, struct pt_regs *r)
++pc164_device_interrupt(unsigned long v)
+ {
+ __min_ipl = getipl();
+- cabriolet_device_interrupt(v, r);
++ cabriolet_device_interrupt(v);
+ __min_ipl = 0;
+ }
+
+diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
+index dd6103b..85d2f93 100644
+--- a/arch/alpha/kernel/sys_dp264.c
++++ b/arch/alpha/kernel/sys_dp264.c
+@@ -217,7 +217,7 @@ static struct hw_interrupt_type clipper_
+ };
+
+ static void
+-dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
++dp264_device_interrupt(unsigned long vector)
+ {
+ #if 1
+ printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n");
+@@ -236,9 +236,9 @@ dp264_device_interrupt(unsigned long vec
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 55)
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ else
+- handle_irq(16 + i, 16 + i, regs);
++ handle_irq(16 + i);
+ #if 0
+ TSUNAMI_cchip->dir0.csr = 1UL << i; mb();
+ tmp = TSUNAMI_cchip->dir0.csr;
+@@ -248,7 +248,7 @@ dp264_device_interrupt(unsigned long vec
+ }
+
+ static void
+-dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++dp264_srm_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -268,11 +268,11 @@ dp264_srm_device_interrupt(unsigned long
+ if (irq >= 32)
+ irq -= 16;
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void
+-clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++clipper_srm_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -290,7 +290,7 @@ clipper_srm_device_interrupt(unsigned lo
+ *
+ * Eg IRQ 24 is DRIR bit 8, etc, etc
+ */
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
+index ed108b6..9c5a306 100644
+--- a/arch/alpha/kernel/sys_eb64p.c
++++ b/arch/alpha/kernel/sys_eb64p.c
+@@ -80,7 +80,7 @@ static struct hw_interrupt_type eb64p_ir
+ };
+
+ static void
+-eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
++eb64p_device_interrupt(unsigned long vector)
+ {
+ unsigned long pld;
+ unsigned int i;
+@@ -97,9 +97,9 @@ eb64p_device_interrupt(unsigned long vec
+ pld &= pld - 1; /* clear least bit set */
+
+ if (i == 5) {
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ } else {
+- handle_irq(16 + i, regs);
++ handle_irq(16 + i);
+ }
+ }
+ }
+diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
+index 64a785b..7ef3b6f 100644
+--- a/arch/alpha/kernel/sys_eiger.c
++++ b/arch/alpha/kernel/sys_eiger.c
+@@ -91,7 +91,7 @@ static struct hw_interrupt_type eiger_ir
+ };
+
+ static void
+-eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
++eiger_device_interrupt(unsigned long vector)
+ {
+ unsigned intstatus;
+
+@@ -118,20 +118,20 @@ eiger_device_interrupt(unsigned long vec
+ * despatch an interrupt if it's set.
+ */
+
+- if (intstatus & 8) handle_irq(16+3, regs);
+- if (intstatus & 4) handle_irq(16+2, regs);
+- if (intstatus & 2) handle_irq(16+1, regs);
+- if (intstatus & 1) handle_irq(16+0, regs);
++ if (intstatus & 8) handle_irq(16+3);
++ if (intstatus & 4) handle_irq(16+2);
++ if (intstatus & 2) handle_irq(16+1);
++ if (intstatus & 1) handle_irq(16+0);
+ } else {
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ }
+ }
+
+ static void
+-eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++eiger_srm_device_interrupt(unsigned long vector)
+ {
+ int irq = (vector - 0x800) >> 4;
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
+index 4ac2b32..2c3de97 100644
+--- a/arch/alpha/kernel/sys_jensen.c
++++ b/arch/alpha/kernel/sys_jensen.c
+@@ -129,7 +129,7 @@ static struct hw_interrupt_type jensen_l
+ };
+
+ static void
+-jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
++jensen_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -189,7 +189,7 @@ jensen_device_interrupt(unsigned long ve
+ if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) ||
+ irq != last_irq) {
+ printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n",
+- irq, count, cc-last_cc, regs->pc);
++ irq, count, cc-last_cc, get_irq_regs()->pc);
+ count = 0;
+ last_msg = cc;
+ last_irq = irq;
+@@ -198,7 +198,7 @@ jensen_device_interrupt(unsigned long ve
+ }
+ #endif
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+@@ -244,7 +244,7 @@ jensen_init_arch(void)
+ }
+
+ static void
+-jensen_machine_check (u64 vector, u64 la, struct pt_regs *regs)
++jensen_machine_check (u64 vector, u64 la)
+ {
+ printk(KERN_CRIT "Machine check\n");
+ }
+diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
+index 36d2159..e349f03 100644
+--- a/arch/alpha/kernel/sys_marvel.c
++++ b/arch/alpha/kernel/sys_marvel.c
+@@ -38,7 +38,7 @@
+ * Interrupt handling.
+ */
+ static void
+-io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
++io7_device_interrupt(unsigned long vector)
+ {
+ unsigned int pid;
+ unsigned int irq;
+@@ -64,7 +64,7 @@ io7_device_interrupt(unsigned long vecto
+ irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* not too many bits */
+ irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static volatile unsigned long *
+diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c
+index 61ac56f..b8b817f 100644
+--- a/arch/alpha/kernel/sys_miata.c
++++ b/arch/alpha/kernel/sys_miata.c
+@@ -33,7 +33,7 @@
+
+
+ static void
+-miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++miata_srm_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -56,7 +56,7 @@ miata_srm_device_interrupt(unsigned long
+ if (irq >= 16)
+ irq = irq + 8;
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
+index cc4c581..8d3e942 100644
+--- a/arch/alpha/kernel/sys_mikasa.c
++++ b/arch/alpha/kernel/sys_mikasa.c
+@@ -79,7 +79,7 @@ static struct hw_interrupt_type mikasa_i
+ };
+
+ static void
+-mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
++mikasa_device_interrupt(unsigned long vector)
+ {
+ unsigned long pld;
+ unsigned int i;
+@@ -97,9 +97,9 @@ mikasa_device_interrupt(unsigned long ve
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i < 16) {
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ } else {
+- handle_irq(i, regs);
++ handle_irq(i);
+ }
+ }
+ }
+@@ -182,8 +182,7 @@ mikasa_map_irq(struct pci_dev *dev, u8 s
+
+ #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+ static void
+-mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ #define MCHK_NO_DEVSEL 0x205U
+ #define MCHK_NO_TABT 0x204U
+@@ -202,7 +201,7 @@ mikasa_apecs_machine_check(unsigned long
+ mb();
+
+ code = mchk_header->code;
+- process_mcheck_info(vector, la_ptr, regs, "MIKASA APECS",
++ process_mcheck_info(vector, la_ptr, "MIKASA APECS",
+ (mcheck_expected(0)
+ && (code == MCHK_NO_DEVSEL
+ || code == MCHK_NO_TABT)));
+diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
+index c0d696e..93744ba 100644
+--- a/arch/alpha/kernel/sys_nautilus.c
++++ b/arch/alpha/kernel/sys_nautilus.c
+@@ -124,8 +124,7 @@ naut_sys_machine_check(unsigned long vec
+ in the system. They are analysed separately but all starts here. */
+
+ void
+-nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs *regs)
++nautilus_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ char *mchk_class;
+
+@@ -165,7 +164,7 @@ nautilus_machine_check(unsigned long vec
+ else if (vector == SCB_Q_SYSMCHK)
+ mchk_class = "Fatal";
+ else {
+- ev6_machine_check(vector, la_ptr, regs);
++ ev6_machine_check(vector, la_ptr);
+ return;
+ }
+
+@@ -173,7 +172,7 @@ nautilus_machine_check(unsigned long vec
+ "[%s System Machine Check (NMI)]\n",
+ vector, mchk_class);
+
+- naut_sys_machine_check(vector, la_ptr, regs);
++ naut_sys_machine_check(vector, la_ptr, get_irq_regs());
+
+ /* Tell the PALcode to clear the machine check */
+ draina();
+diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
+index 2d3cff7..de6ba34 100644
+--- a/arch/alpha/kernel/sys_noritake.c
++++ b/arch/alpha/kernel/sys_noritake.c
+@@ -77,7 +77,7 @@ static struct hw_interrupt_type noritake
+ };
+
+ static void
+-noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
++noritake_device_interrupt(unsigned long vector)
+ {
+ unsigned long pld;
+ unsigned int i;
+@@ -96,15 +96,15 @@ noritake_device_interrupt(unsigned long
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i < 16) {
+- isa_device_interrupt(vector, regs);
++ isa_device_interrupt(vector);
+ } else {
+- handle_irq(i, regs);
++ handle_irq(i);
+ }
+ }
+ }
+
+ static void
+-noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++noritake_srm_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -122,7 +122,7 @@ noritake_srm_device_interrupt(unsigned l
+ if (irq >= 16)
+ irq = irq + 1;
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+@@ -264,8 +264,7 @@ noritake_swizzle(struct pci_dev *dev, u8
+
+ #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+ static void
+-noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
+- struct pt_regs * regs)
++noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr)
+ {
+ #define MCHK_NO_DEVSEL 0x205U
+ #define MCHK_NO_TABT 0x204U
+@@ -284,7 +283,7 @@ noritake_apecs_machine_check(unsigned lo
+ mb();
+
+ code = mchk_header->code;
+- process_mcheck_info(vector, la_ptr, regs, "NORITAKE APECS",
++ process_mcheck_info(vector, la_ptr, "NORITAKE APECS",
+ (mcheck_expected(0)
+ && (code == MCHK_NO_DEVSEL
+ || code == MCHK_NO_TABT)));
+diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
+index 949607e..581d08c 100644
+--- a/arch/alpha/kernel/sys_rawhide.c
++++ b/arch/alpha/kernel/sys_rawhide.c
+@@ -134,7 +134,7 @@ static struct hw_interrupt_type rawhide_
+ };
+
+ static void
+-rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++rawhide_srm_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -158,7 +158,7 @@ rawhide_srm_device_interrupt(unsigned lo
+ /* Adjust by which hose it is from. */
+ irq -= ((irq + 16) >> 2) & 0x38;
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c
+index 6ae5060..ce1faa6 100644
+--- a/arch/alpha/kernel/sys_rx164.c
++++ b/arch/alpha/kernel/sys_rx164.c
+@@ -83,7 +83,7 @@ static struct hw_interrupt_type rx164_ir
+ };
+
+ static void
+-rx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
++rx164_device_interrupt(unsigned long vector)
+ {
+ unsigned long pld;
+ volatile unsigned int *dirr;
+@@ -102,9 +102,9 @@ rx164_device_interrupt(unsigned long vec
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 20) {
+- isa_no_iack_sc_device_interrupt(vector, regs);
++ isa_no_iack_sc_device_interrupt(vector);
+ } else {
+- handle_irq(16+i, regs);
++ handle_irq(16+i);
+ }
+ }
+ }
+diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
+index a7a1464..906019c 100644
+--- a/arch/alpha/kernel/sys_sable.c
++++ b/arch/alpha/kernel/sys_sable.c
+@@ -512,7 +512,7 @@ static struct hw_interrupt_type sable_ly
+ };
+
+ static void
+-sable_lynx_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++sable_lynx_srm_device_interrupt(unsigned long vector)
+ {
+ /* Note that the vector reported by the SRM PALcode corresponds
+ to the interrupt mask bits, but we have to manage via the
+@@ -526,7 +526,7 @@ sable_lynx_srm_device_interrupt(unsigned
+ printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n",
+ __FUNCTION__, vector, bit, irq);
+ #endif
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c
+index 2c75cd1..9bd9a31 100644
+--- a/arch/alpha/kernel/sys_takara.c
++++ b/arch/alpha/kernel/sys_takara.c
+@@ -85,7 +85,7 @@ static struct hw_interrupt_type takara_i
+ };
+
+ static void
+-takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
++takara_device_interrupt(unsigned long vector)
+ {
+ unsigned intstatus;
+
+@@ -112,20 +112,20 @@ takara_device_interrupt(unsigned long ve
+ * despatch an interrupt if it's set.
+ */
+
+- if (intstatus & 8) handle_irq(16+3, regs);
+- if (intstatus & 4) handle_irq(16+2, regs);
+- if (intstatus & 2) handle_irq(16+1, regs);
+- if (intstatus & 1) handle_irq(16+0, regs);
++ if (intstatus & 8) handle_irq(16+3);
++ if (intstatus & 4) handle_irq(16+2);
++ if (intstatus & 2) handle_irq(16+1);
++ if (intstatus & 1) handle_irq(16+0);
+ } else {
+- isa_device_interrupt (vector, regs);
++ isa_device_interrupt (vector);
+ }
+ }
+
+ static void
+-takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++takara_srm_device_interrupt(unsigned long vector)
+ {
+ int irq = (vector - 0x800) >> 4;
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+ static void __init
+diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
+index 302aab3..29ab7db 100644
+--- a/arch/alpha/kernel/sys_titan.c
++++ b/arch/alpha/kernel/sys_titan.c
+@@ -167,18 +167,18 @@ titan_set_irq_affinity(unsigned int irq,
+ }
+
+ static void
+-titan_device_interrupt(unsigned long vector, struct pt_regs * regs)
++titan_device_interrupt(unsigned long vector)
+ {
+ printk("titan_device_interrupt: NOT IMPLEMENTED YET!! \n");
+ }
+
+ static void
+-titan_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
++titan_srm_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+ irq = (vector - 0x800) >> 4;
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ }
+
+
+@@ -204,7 +204,7 @@ static struct hw_interrupt_type titan_ir
+ };
+
+ static irqreturn_t
+-titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs)
++titan_intr_nop(int irq, void *dev_id)
+ {
+ /*
+ * This is a NOP interrupt handler for the purposes of
+@@ -243,7 +243,7 @@ titan_legacy_init_irq(void)
+ }
+
+ void
+-titan_dispatch_irqs(u64 mask, struct pt_regs *regs)
++titan_dispatch_irqs(u64 mask)
+ {
+ unsigned long vector;
+
+@@ -263,7 +263,7 @@ titan_dispatch_irqs(u64 mask, struct pt_
+ vector = 0x900 + (vector << 4); /* convert to SRM vector */
+
+ /* dispatch it */
+- alpha_mv.device_interrupt(vector, regs);
++ alpha_mv.device_interrupt(vector);
+ }
+ }
+
+diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c
+index 22c5798..42c3eed 100644
+--- a/arch/alpha/kernel/sys_wildfire.c
++++ b/arch/alpha/kernel/sys_wildfire.c
+@@ -234,7 +234,7 @@ wildfire_init_irq(void)
+ }
+
+ static void
+-wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs)
++wildfire_device_interrupt(unsigned long vector)
+ {
+ int irq;
+
+@@ -246,7 +246,7 @@ wildfire_device_interrupt(unsigned long
+ * bits 5-0: irq in PCA
+ */
+
+- handle_irq(irq, regs);
++ handle_irq(irq);
+ return;
+ }
+
+diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
+index 4342cea..f6cfe8c 100644
+--- a/arch/alpha/kernel/systbls.S
++++ b/arch/alpha/kernel/systbls.S
+@@ -4,7 +4,6 @@
+ * The system call table.
+ */
+
+-#include <linux/config.h> /* CONFIG_OSF4_COMPAT */
+ #include <asm/unistd.h>
+
+ .data
+diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
+index b191cc7..d7053eb 100644
+--- a/arch/alpha/kernel/time.c
++++ b/arch/alpha/kernel/time.c
+@@ -54,11 +54,10 @@
+ #include "proto.h"
+ #include "irq_impl.h"
+
+-extern unsigned long wall_jiffies; /* kernel/timer.c */
+-
+ static int set_rtc_mmss(unsigned long);
+
+ DEFINE_SPINLOCK(rtc_lock);
++EXPORT_SYMBOL(rtc_lock);
+
+ #define TICK_SIZE (tick_nsec / 1000)
+
+@@ -106,7 +105,7 @@ unsigned long long sched_clock(void)
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+-irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs)
++irqreturn_t timer_interrupt(int irq, void *dev)
+ {
+ unsigned long delta;
+ __u32 now;
+@@ -114,7 +113,7 @@ irqreturn_t timer_interrupt(int irq, voi
+
+ #ifndef CONFIG_SMP
+ /* Not SMP, do kernel PC profiling here. */
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ #endif
+
+ write_seqlock(&xtime_lock);
+@@ -132,9 +131,9 @@ irqreturn_t timer_interrupt(int irq, voi
+ nticks = delta >> FIX_SHIFT;
+
+ while (nticks > 0) {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ nticks--;
+ }
+@@ -413,7 +412,7 @@ void
+ do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+- unsigned long sec, usec, lost, seq;
++ unsigned long sec, usec, seq;
+ unsigned long delta_cycles, delta_usec, partial_tick;
+
+ do {
+@@ -423,14 +422,13 @@ do_gettimeofday(struct timeval *tv)
+ sec = xtime.tv_sec;
+ usec = (xtime.tv_nsec / 1000);
+ partial_tick = state.partial_tick;
+- lost = jiffies - wall_jiffies;
+
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+ #ifdef CONFIG_SMP
+ /* Until and unless we figure out how to get cpu cycle counters
+ in sync and keep them there, we can't use the rpcc tricks. */
+- delta_usec = lost * (1000000 / HZ);
++ delta_usec = 0;
+ #else
+ /*
+ * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
+@@ -446,8 +444,7 @@ do_gettimeofday(struct timeval *tv)
+ */
+
+ delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
+- + partial_tick
+- + (lost << FIX_SHIFT)) * 15625;
++ + partial_tick) * 15625;
+ delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+ #endif
+
+@@ -480,12 +477,11 @@ do_settimeofday(struct timespec *tv)
+ time. Without this, a full-tick error is possible. */
+
+ #ifdef CONFIG_SMP
+- delta_nsec = (jiffies - wall_jiffies) * (NSEC_PER_SEC / HZ);
++ delta_nsec = 0;
+ #else
+ delta_nsec = rpcc() - state.last_time;
+ delta_nsec = (delta_nsec * state.scaled_ticks_per_cycle
+- + state.partial_tick
+- + ((jiffies - wall_jiffies) << FIX_SHIFT)) * 15625;
++ + state.partial_tick) * 15625;
+ delta_nsec = ((delta_nsec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+ delta_nsec *= 1000;
+ #endif
+diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
+index 71470e9..76bf071 100644
+--- a/arch/alpha/kernel/vmlinux.lds.S
++++ b/arch/alpha/kernel/vmlinux.lds.S
+@@ -48,13 +48,7 @@ SECTIONS
+ . = ALIGN(8);
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+
+diff --git a/arch/alpha/lib/dbg_stackcheck.S b/arch/alpha/lib/dbg_stackcheck.S
+index 3c1f3e6..78f6b92 100644
+--- a/arch/alpha/lib/dbg_stackcheck.S
++++ b/arch/alpha/lib/dbg_stackcheck.S
+@@ -1,5 +1,5 @@
+ /*
+- * arch/alpha/lib/stackcheck.S
++ * arch/alpha/lib/dbg_stackcheck.S
+ * Contributed by Richard Henderson (rth at tamu.edu)
+ *
+ * Verify that we have not overflowed the stack. Oops if we have.
+diff --git a/arch/alpha/lib/dbg_stackkill.S b/arch/alpha/lib/dbg_stackkill.S
+index e9f6a9d..c1e40a1 100644
+--- a/arch/alpha/lib/dbg_stackkill.S
++++ b/arch/alpha/lib/dbg_stackkill.S
+@@ -1,5 +1,5 @@
+ /*
+- * arch/alpha/lib/killstack.S
++ * arch/alpha/lib/dbg_stackkill.S
+ * Contributed by Richard Henderson (rth at cygnus.com)
+ *
+ * Clobber the balance of the kernel stack, hoping to catch
+diff --git a/arch/alpha/lib/memset.S b/arch/alpha/lib/memset.S
+index 8ff6e7e..311b8cf 100644
+--- a/arch/alpha/lib/memset.S
++++ b/arch/alpha/lib/memset.S
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/alpha/memset.S
++ * linux/arch/alpha/lib/memset.S
+ *
+ * This is an efficient (and small) implementation of the C library "memset()"
+ * function for the alpha.
+diff --git a/arch/alpha/mm/Makefile b/arch/alpha/mm/Makefile
+index 6edd9a0..09399c5 100644
+--- a/arch/alpha/mm/Makefile
++++ b/arch/alpha/mm/Makefile
+@@ -4,6 +4,6 @@
+
+ EXTRA_CFLAGS := -Werror
+
+-obj-y := init.o fault.o extable.o remap.o
++obj-y := init.o fault.o extable.o
+
+ obj-$(CONFIG_DISCONTIGMEM) += numa.o
+diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
+index 622dabd..8871529 100644
+--- a/arch/alpha/mm/fault.c
++++ b/arch/alpha/mm/fault.c
+@@ -193,7 +193,7 @@ do_page_fault(unsigned long address, uns
+ /* 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:
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
+index 917dad1..550f490 100644
+--- a/arch/alpha/mm/init.c
++++ b/arch/alpha/mm/init.c
+@@ -270,7 +270,7 @@ callback_init(void * kernel_end)
+ void
+ paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+ unsigned long dma_pfn, high_pfn;
+
+ dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
+index b826f58..e3e3806 100644
+--- a/arch/alpha/mm/numa.c
++++ b/arch/alpha/mm/numa.c
+@@ -13,12 +13,14 @@
+ #include <linux/swap.h>
+ #include <linux/initrd.h>
+ #include <linux/pfn.h>
++#include <linux/module.h>
+
+ #include <asm/hwrpb.h>
+ #include <asm/pgalloc.h>
+
+ pg_data_t node_data[MAX_NUMNODES];
+ bootmem_data_t node_bdata[MAX_NUMNODES];
++EXPORT_SYMBOL(node_data);
+
+ #undef DEBUG_DISCONTIG
+ #ifdef DEBUG_DISCONTIG
+diff --git a/arch/alpha/mm/remap.c b/arch/alpha/mm/remap.c
+deleted file mode 100644
+index a78356c..0000000
+--- a/arch/alpha/mm/remap.c
++++ /dev/null
+@@ -1,86 +0,0 @@
+-#include <linux/vmalloc.h>
+-#include <asm/pgalloc.h>
+-#include <asm/cacheflush.h>
+-
+-static inline void
+-remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+- unsigned long pfn;
+-
+- address &= ~PMD_MASK;
+- end = address + size;
+- if (end > PMD_SIZE)
+- end = PMD_SIZE;
+- if (address >= end)
+- BUG();
+- pfn = phys_addr >> PAGE_SHIFT;
+- do {
+- if (!pte_none(*pte)) {
+- printk("remap_area_pte: page already exists\n");
+- BUG();
+- }
+- set_pte(pte, pfn_pte(pfn,
+- __pgprot(_PAGE_VALID | _PAGE_ASM |
+- _PAGE_KRE | _PAGE_KWE | flags)));
+- address += PAGE_SIZE;
+- pfn++;
+- pte++;
+- } while (address && (address < end));
+-}
+-
+-static inline int
+-remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+-
+- address &= ~PGDIR_MASK;
+- end = address + size;
+- if (end > PGDIR_SIZE)
+- end = PGDIR_SIZE;
+- phys_addr -= address;
+- if (address >= end)
+- BUG();
+- do {
+- pte_t * pte = pte_alloc_kernel(pmd, address);
+- if (!pte)
+- return -ENOMEM;
+- remap_area_pte(pte, address, end - address,
+- address + phys_addr, flags);
+- address = (address + PMD_SIZE) & PMD_MASK;
+- pmd++;
+- } while (address && (address < end));
+- return 0;
+-}
+-
+-int
+-__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
+- unsigned long size, unsigned long flags)
+-{
+- pgd_t * dir;
+- int error = 0;
+- unsigned long end = address + size;
+-
+- phys_addr -= address;
+- dir = pgd_offset(&init_mm, address);
+- flush_cache_all();
+- if (address >= end)
+- BUG();
+- do {
+- pmd_t *pmd;
+- pmd = pmd_alloc(&init_mm, dir, address);
+- error = -ENOMEM;
+- if (!pmd)
+- break;
+- if (remap_area_pmd(pmd, address, end - address,
+- phys_addr + address, flags))
+- break;
+- error = 0;
+- address = (address + PGDIR_SIZE) & PGDIR_MASK;
+- dir++;
+- } while (address && (address < end));
+- return error;
+-}
+-
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index f81a623..adb05de 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -17,6 +17,10 @@ config ARM
+ Europe. There is an ARM Linux project with a web page at
+ <http://www.arm.linux.org.uk/>.
+
++config GENERIC_TIME
++ bool
++ default n
++
+ config MMU
+ bool
+ default y
+@@ -51,6 +55,10 @@ config GENERIC_HARDIRQS
+ bool
+ default y
+
++config TRACE_IRQFLAGS_SUPPORT
++ bool
++ default y
++
+ config HARDIRQS_SW_RESEND
+ bool
+ default y
+@@ -91,7 +99,7 @@ config ARCH_MTD_XIP
+
+ config VECTORS_BASE
+ hex
+- default 0xffff0000 if MMU
++ default 0xffff0000 if MMU || CPU_HIGH_VECTOR
+ default DRAM_BASE if REMAP_VECTORS_TO_RAM
+ default 0x00000000
+ help
+@@ -198,16 +206,27 @@ config ARCH_IMX
+ help
+ Support for Motorola's i.MX family of processors (MX1, MXL).
+
+-config ARCH_IOP3XX
+- bool "IOP3xx-based"
++config ARCH_IOP32X
++ bool "IOP32x-based"
++ depends on MMU
++ select PLAT_IOP
++ select PCI
++ help
++ Support for Intel's 80219 and IOP32X (XScale) family of
++ processors.
++
++config ARCH_IOP33X
++ bool "IOP33x-based"
+ depends on MMU
++ select PLAT_IOP
+ select PCI
+ help
+- Support for Intel's IOP3XX (XScale) family of processors.
++ Support for Intel's IOP33X (XScale) family of processors.
+
+ config ARCH_IXP4XX
+ bool "IXP4xx-based"
+ depends on MMU
++ select GENERIC_TIME
+ help
+ Support for Intel's IXP4XX (XScale) family of processors.
+
+@@ -308,7 +327,9 @@ source "arch/arm/mach-footbridge/Kconfig
+
+ source "arch/arm/mach-integrator/Kconfig"
+
+-source "arch/arm/mach-iop3xx/Kconfig"
++source "arch/arm/mach-iop32x/Kconfig"
++
++source "arch/arm/mach-iop33x/Kconfig"
+
+ source "arch/arm/mach-ixp4xx/Kconfig"
+
+@@ -348,6 +369,9 @@ source "arch/arm/mach-netx/Kconfig"
+ config ARCH_ACORN
+ bool
+
++config PLAT_IOP
++ bool
++
+ source arch/arm/mm/Kconfig
+
+ # bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
+@@ -602,9 +626,10 @@ config LEDS_CPU
+
+ config ALIGNMENT_TRAP
+ bool
++ depends on CPU_CP15_MMU
+ default y if !ARCH_EBSA110
+ help
+- ARM processors can not fetch/store information which is not
++ ARM processors cannot fetch/store information which is not
+ naturally aligned on the bus, i.e., a 4 byte fetch must start at an
+ address divisible by 4. On 32-bit ARM processors, these non-aligned
+ fetch/store instructions will be emulated in software if you say
+@@ -633,11 +658,12 @@ config ZBOOT_ROM_BSS
+ hex "Compressed ROM boot loader BSS address"
+ default "0"
+ help
+- The base address of 64KiB of read/write memory in the target
+- for the ROM-able zImage, which must be available while the
+- decompressor is running. Platforms which normally make use of
+- ROM-able zImage formats normally set this to a suitable
+- value in their defconfig file.
++ The base address of an area of read/write memory in the target
++ for the ROM-able zImage which must be available while the
++ decompressor is running. It must be large enough to hold the
++ entire decompressed kernel plus an additional 128 KiB.
++ Platforms which normally make use of ROM-able zImage formats
++ normally set this to a suitable value in their defconfig file.
+
+ If ZBOOT_ROM is not enabled, this has no effect.
+
+@@ -832,7 +858,7 @@ source "drivers/base/Kconfig"
+
+ source "drivers/connector/Kconfig"
+
+-if ALIGNMENT_TRAP
++if ALIGNMENT_TRAP || !CPU_CP15_MMU
+ source "drivers/mtd/Kconfig"
+ endif
+
+@@ -844,7 +870,7 @@ source "drivers/block/Kconfig"
+
+ source "drivers/acorn/block/Kconfig"
+
+-if PCMCIA || ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX \
++if PCMCIA || ARCH_CLPS7500 || ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX \
+ || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \
+ || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE \
+ || ARCH_IXP23XX
+diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
+index e1574be..f087376 100644
+--- a/arch/arm/Kconfig-nommu
++++ b/arch/arm/Kconfig-nommu
+@@ -25,6 +25,14 @@ config FLASH_SIZE
+ hex 'FLASH Size' if SET_MEM_PARAM
+ default 0x00400000
+
++config PROCESSOR_ID
++ hex
++ default 0x00007700
++ depends on !CPU_CP15
++ help
++ If processor has no CP15 register, this processor ID is
++ used instead of the auto-probing which utilizes the register.
++
+ config REMAP_VECTORS_TO_RAM
+ bool 'Install vectors to the begining of RAM' if DRAM_BASE
+ depends on DRAM_BASE
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 92873cd..6f4f8bf 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -55,7 +55,12 @@ arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM
+ # This selects how we optimise for the processor.
+ tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610
+ tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710
++tune-$(CONFIG_CPU_ARM7TDMI) :=-mtune=arm7tdmi
+ tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi
++tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi
++tune-$(CONFIG_CPU_ARM9TDMI) :=-mtune=arm9tdmi
++tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi
++tune-$(CONFIG_CPU_ARM946T) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
+ tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi
+@@ -101,7 +106,8 @@ endif
+ machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
+ textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000
+ machine-$(CONFIG_ARCH_CLPS711X) := clps711x
+- machine-$(CONFIG_ARCH_IOP3XX) := iop3xx
++ machine-$(CONFIG_ARCH_IOP32X) := iop32x
++ machine-$(CONFIG_ARCH_IOP33X) := iop33x
+ machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
+ machine-$(CONFIG_ARCH_IXP2000) := ixp2000
+ machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx
+@@ -157,6 +163,7 @@ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_
+ core-$(CONFIG_VFP) += arch/arm/vfp/
+
+ # If we have a common platform directory, then include it in the build.
++core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
+ core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
+
+ drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
+@@ -167,11 +174,13 @@ libs-y := arch/arm/lib/ $(libs-y)
+
+ # Default target when executing plain make
+ ifeq ($(CONFIG_XIP_KERNEL),y)
+-all: xipImage
++KBUILD_IMAGE := xipImage
+ else
+-all: zImage
++KBUILD_IMAGE := zImage
+ endif
+
++all: $(KBUILD_IMAGE)
++
+ boot := arch/arm/boot
+
+ # Update machine arch and proc symlinks if something which affects
+diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
+index 2adc152..adddc71 100644
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -51,7 +51,11 @@ OBJS += head-at91rm9200.o
+ endif
+
+ ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
++ifeq ($(CONFIG_CPU_CP15),y)
+ OBJS += big-endian.o
++else
++# The endian should be set by h/w design.
++endif
+ endif
+
+ #
+diff --git a/arch/arm/boot/compressed/head-clps7500.S b/arch/arm/boot/compressed/head-clps7500.S
+index 941c5f5..4f3c78a 100644
+--- a/arch/arm/boot/compressed/head-clps7500.S
++++ b/arch/arm/boot/compressed/head-clps7500.S
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/boot/compressed/head.S
++ * linux/arch/arm/boot/compressed/head-clps7500.S
+ *
+ * Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd
+ */
+diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
+index 14a9ff9..2568d31 100644
+--- a/arch/arm/boot/compressed/head.S
++++ b/arch/arm/boot/compressed/head.S
+@@ -20,11 +20,21 @@
+ #ifdef DEBUG
+
+ #if defined(CONFIG_DEBUG_ICEDCC)
++
++#ifdef CONFIG_CPU_V6
++ .macro loadsp, rb
++ .endm
++ .macro writeb, ch, rb
++ mcr p14, 0, \ch, c0, c5, 0
++ .endm
++#else
+ .macro loadsp, rb
+ .endm
+ .macro writeb, ch, rb
+ mcr p14, 0, \ch, c0, c1, 0
+ .endm
++#endif
++
+ #else
+
+ #include <asm/arch/debug-macro.S>
+@@ -42,12 +52,6 @@
+ add \rb, \rb, #0x00010000 @ Ser1
+ #endif
+ .endm
+-#elif defined(CONFIG_ARCH_IOP331)
+- .macro loadsp, rb
+- mov \rb, #0xff000000
+- orr \rb, \rb, #0x00ff0000
+- orr \rb, \rb, #0x0000f700 @ location of the UART
+- .endm
+ #elif defined(CONFIG_ARCH_S3C2410)
+ .macro loadsp, rb
+ mov \rb, #0x50000000
+@@ -78,9 +82,11 @@
+ kphex r6, 8 /* processor id */
+ kputc #':'
+ kphex r7, 8 /* architecture id */
++#ifdef CONFIG_CPU_CP15
+ kputc #':'
+ mrc p15, 0, r0, c1, c0
+ kphex r0, 8 /* control reg */
++#endif
+ kputc #'\n'
+ kphex r5, 8 /* decompressed kernel start */
+ kputc #'-'
+@@ -231,7 +237,8 @@ not_relocated: mov r0, #0
+ */
+ cmp r4, r2
+ bhs wont_overwrite
+- add r0, r4, #4096*1024 @ 4MB largest kernel size
++ sub r3, sp, r5 @ > compressed kernel size
++ add r0, r4, r3, lsl #2 @ allow for 4x expansion
+ cmp r0, r5
+ bls wont_overwrite
+
+@@ -503,7 +510,11 @@ call_kernel: bl cache_clean_flush
+ */
+
+ call_cache_fn: adr r12, proc_types
++#ifdef CONFIG_CPU_CP15
+ mrc p15, 0, r6, c0, c0 @ get processor ID
++#else
++ ldr r6, =CONFIG_PROCESSOR_ID
++#endif
+ 1: ldr r1, [r12, #0] @ get value
+ ldr r2, [r12, #4] @ get mask
+ eor r1, r1, r6 @ (real ^ match)
+diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
+index ace3fb5..283891c 100644
+--- a/arch/arm/boot/compressed/misc.c
++++ b/arch/arm/boot/compressed/misc.c
+@@ -30,6 +30,25 @@ static void putstr(const char *ptr);
+ #include <asm/arch/uncompress.h>
+
+ #ifdef CONFIG_DEBUG_ICEDCC
++
++#ifdef CONFIG_CPU_V6
++
++static void icedcc_putc(int ch)
++{
++ int status, i = 0x4000000;
++
++ do {
++ if (--i < 0)
++ return;
++
++ asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
++ } while (status & (1 << 29));
++
++ asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
++}
++
++#else
++
+ static void icedcc_putc(int ch)
+ {
+ int status, i = 0x4000000;
+@@ -44,6 +63,8 @@ static void icedcc_putc(int ch)
+ asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
+ }
+
++#endif
++
+ #define putc(ch) icedcc_putc(ch)
+ #define flush() do { } while (0)
+ #endif
+diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
+index 028bdc9..2e635b8 100644
+--- a/arch/arm/common/dmabounce.c
++++ b/arch/arm/common/dmabounce.c
+@@ -662,7 +662,8 @@ EXPORT_SYMBOL(dma_map_single);
+ EXPORT_SYMBOL(dma_unmap_single);
+ EXPORT_SYMBOL(dma_map_sg);
+ EXPORT_SYMBOL(dma_unmap_sg);
+-EXPORT_SYMBOL(dma_sync_single);
++EXPORT_SYMBOL(dma_sync_single_for_cpu);
++EXPORT_SYMBOL(dma_sync_single_for_device);
+ EXPORT_SYMBOL(dma_sync_sg);
+ EXPORT_SYMBOL(dmabounce_register_dev);
+ EXPORT_SYMBOL(dmabounce_unregister_dev);
+diff --git a/arch/arm/common/icst307.c b/arch/arm/common/icst307.c
+index bafe8b1..6d094c1 100644
+--- a/arch/arm/common/icst307.c
++++ b/arch/arm/common/icst307.c
+@@ -57,7 +57,7 @@ icst307_khz_to_vco(const struct icst307_
+ break;
+ } while (i < ARRAY_SIZE(idx2s));
+
+- if (i > ARRAY_SIZE(idx2s))
++ if (i >= ARRAY_SIZE(idx2s))
+ return vco;
+
+ vco.s = idx2s[i];
+@@ -119,7 +119,7 @@ icst307_ps_to_vco(const struct icst307_p
+ break;
+ } while (i < ARRAY_SIZE(idx2s));
+
+- if (i > ARRAY_SIZE(idx2s))
++ if (i >= ARRAY_SIZE(idx2s))
+ return vco;
+
+ vco.s = idx2s[i];
+diff --git a/arch/arm/common/icst525.c b/arch/arm/common/icst525.c
+index 943ef88..3d377c5 100644
+--- a/arch/arm/common/icst525.c
++++ b/arch/arm/common/icst525.c
+@@ -55,7 +55,7 @@ icst525_khz_to_vco(const struct icst525_
+ break;
+ } while (i < ARRAY_SIZE(idx2s));
+
+- if (i > ARRAY_SIZE(idx2s))
++ if (i >= ARRAY_SIZE(idx2s))
+ return vco;
+
+ vco.s = idx2s[i];
+@@ -118,7 +118,7 @@ icst525_ps_to_vco(const struct icst525_p
+ break;
+ } while (i < ARRAY_SIZE(idx2s));
+
+- if (i > ARRAY_SIZE(idx2s))
++ if (i >= ARRAY_SIZE(idx2s))
+ return vco;
+
+ vco.s = idx2s[i];
+diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
+index 4e0dcae..80a72c7 100644
+--- a/arch/arm/common/locomo.c
++++ b/arch/arm/common/locomo.c
+@@ -121,6 +121,13 @@ static struct locomo_dev_info locomo_dev
+ .offset = 0,
+ .length = 0,
+ },
++ {
++ .devid = LOCOMO_DEVID_SPI,
++ .irq = {},
++ .name = "locomo-spi",
++ .offset = LOCOMO_SPI,
++ .length = 0x30,
++ },
+ };
+
+
+@@ -156,8 +163,7 @@ static struct locomo_dev_info locomo_dev
+ #define LOCOMO_IRQ_LT_START (IRQ_LOCOMO_LT)
+ #define LOCOMO_IRQ_SPI_START (IRQ_LOCOMO_SPI_RFR)
+
+-static void locomo_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void locomo_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ int req, i;
+ struct irqdesc *d;
+@@ -175,7 +181,7 @@ static void locomo_handler(unsigned int
+ d = irq_desc + irq;
+ for (i = 0; i <= 3; i++, d++, irq++) {
+ if (req & (0x0100 << i)) {
+- desc_handle_irq(irq, d, regs);
++ desc_handle_irq(irq, d);
+ }
+
+ }
+@@ -211,15 +217,14 @@ static struct irq_chip locomo_chip = {
+ .unmask = locomo_unmask_irq,
+ };
+
+-static void locomo_key_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void locomo_key_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ struct irqdesc *d;
+ void __iomem *mapbase = get_irq_chipdata(irq);
+
+ if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
+ d = irq_desc + LOCOMO_IRQ_KEY_START;
+- desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs);
++ desc_handle_irq(LOCOMO_IRQ_KEY_START, d);
+ }
+ }
+
+@@ -257,8 +262,7 @@ static struct irq_chip locomo_key_chip =
+ .unmask = locomo_key_unmask_irq,
+ };
+
+-static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ int req, i;
+ struct irqdesc *d;
+@@ -273,7 +277,7 @@ static void locomo_gpio_handler(unsigned
+ d = irq_desc + LOCOMO_IRQ_GPIO_START;
+ for (i = 0; i <= 15; i++, irq++, d++) {
+ if (req & (0x0001 << i)) {
+- desc_handle_irq(irq, d, regs);
++ desc_handle_irq(irq, d);
+ }
+ }
+ }
+@@ -321,15 +325,14 @@ static struct irq_chip locomo_gpio_chip
+ .unmask = locomo_gpio_unmask_irq,
+ };
+
+-static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ struct irqdesc *d;
+ void __iomem *mapbase = get_irq_chipdata(irq);
+
+ if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) {
+ d = irq_desc + LOCOMO_IRQ_LT_START;
+- desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs);
++ desc_handle_irq(LOCOMO_IRQ_LT_START, d);
+ }
+ }
+
+@@ -367,21 +370,20 @@ static struct irq_chip locomo_lt_chip =
+ .unmask = locomo_lt_unmask_irq,
+ };
+
+-static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ int req, i;
+ struct irqdesc *d;
+ void __iomem *mapbase = get_irq_chipdata(irq);
+
+- req = locomo_readl(mapbase + LOCOMO_SPIIR) & 0x000F;
++ req = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIR) & 0x000F;
+ if (req) {
+ irq = LOCOMO_IRQ_SPI_START;
+ d = irq_desc + irq;
+
+ for (i = 0; i <= 3; i++, irq++, d++) {
+ if (req & (0x0001 << i)) {
+- desc_handle_irq(irq, d, regs);
++ desc_handle_irq(irq, d);
+ }
+ }
+ }
+@@ -391,35 +393,35 @@ static void locomo_spi_ack_irq(unsigned
+ {
+ void __iomem *mapbase = get_irq_chipdata(irq);
+ unsigned int r;
+- r = locomo_readl(mapbase + LOCOMO_SPIWE);
++ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
+ r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START));
+- locomo_writel(r, mapbase + LOCOMO_SPIWE);
++ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
+
+- r = locomo_readl(mapbase + LOCOMO_SPIIS);
++ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIS);
+ r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
+- locomo_writel(r, mapbase + LOCOMO_SPIIS);
++ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIIS);
+
+- r = locomo_readl(mapbase + LOCOMO_SPIWE);
++ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
+ r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
+- locomo_writel(r, mapbase + LOCOMO_SPIWE);
++ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
+ }
+
+ static void locomo_spi_mask_irq(unsigned int irq)
+ {
+ void __iomem *mapbase = get_irq_chipdata(irq);
+ unsigned int r;
+- r = locomo_readl(mapbase + LOCOMO_SPIIE);
++ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
+ r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
+- locomo_writel(r, mapbase + LOCOMO_SPIIE);
++ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
+ }
+
+ static void locomo_spi_unmask_irq(unsigned int irq)
+ {
+ void __iomem *mapbase = get_irq_chipdata(irq);
+ unsigned int r;
+- r = locomo_readl(mapbase + LOCOMO_SPIIE);
++ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
+ r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START));
+- locomo_writel(r, mapbase + LOCOMO_SPIIE);
++ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
+ }
+
+ static struct irq_chip locomo_spi_chip = {
+@@ -814,12 +816,15 @@ static inline struct locomo *locomo_chip
+ return (struct locomo *)dev_get_drvdata(ldev->dev.parent);
+ }
+
+-void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir)
++void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir)
+ {
+- struct locomo *lchip = locomo_chip_driver(ldev);
++ struct locomo *lchip = dev_get_drvdata(dev);
+ unsigned long flags;
+ unsigned int r;
+
++ if (!lchip)
++ return;
++
+ spin_lock_irqsave(&lchip->lock, flags);
+
+ r = locomo_readl(lchip->base + LOCOMO_GPD);
+@@ -836,12 +841,15 @@ void locomo_gpio_set_dir(struct locomo_d
+ spin_unlock_irqrestore(&lchip->lock, flags);
+ }
+
+-unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits)
++int locomo_gpio_read_level(struct device *dev, unsigned int bits)
+ {
+- struct locomo *lchip = locomo_chip_driver(ldev);
++ struct locomo *lchip = dev_get_drvdata(dev);
+ unsigned long flags;
+ unsigned int ret;
+
++ if (!lchip)
++ return -ENODEV;
++
+ spin_lock_irqsave(&lchip->lock, flags);
+ ret = locomo_readl(lchip->base + LOCOMO_GPL);
+ spin_unlock_irqrestore(&lchip->lock, flags);
+@@ -850,12 +858,15 @@ unsigned int locomo_gpio_read_level(stru
+ return ret;
+ }
+
+-unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits)
++int locomo_gpio_read_output(struct device *dev, unsigned int bits)
+ {
+- struct locomo *lchip = locomo_chip_driver(ldev);
++ struct locomo *lchip = dev_get_drvdata(dev);
+ unsigned long flags;
+ unsigned int ret;
+
++ if (!lchip)
++ return -ENODEV;
++
+ spin_lock_irqsave(&lchip->lock, flags);
+ ret = locomo_readl(lchip->base + LOCOMO_GPO);
+ spin_unlock_irqrestore(&lchip->lock, flags);
+@@ -864,12 +875,15 @@ unsigned int locomo_gpio_read_output(str
+ return ret;
+ }
+
+-void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set)
++void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set)
+ {
+- struct locomo *lchip = locomo_chip_driver(ldev);
++ struct locomo *lchip = dev_get_drvdata(dev);
+ unsigned long flags;
+ unsigned int r;
+
++ if (!lchip)
++ return;
++
+ spin_lock_irqsave(&lchip->lock, flags);
+
+ r = locomo_readl(lchip->base + LOCOMO_GPO);
+@@ -1058,9 +1072,9 @@ void locomo_frontlight_set(struct locomo
+ struct locomo *lchip = locomo_chip_driver(dev);
+
+ if (vr)
+- locomo_gpio_write(dev, LOCOMO_GPIO_FL_VR, 1);
++ locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 1);
+ else
+- locomo_gpio_write(dev, LOCOMO_GPIO_FL_VR, 0);
++ locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
+
+ spin_lock_irqsave(&lchip->lock, flags);
+ locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
+diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
+index 29818bd..d5f7201 100644
+--- a/arch/arm/common/sa1111.c
++++ b/arch/arm/common/sa1111.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-sa1100/sa1111.c
++ * linux/arch/arm/common/sa1111.c
+ *
+ * SA1111 support
+ *
+@@ -147,7 +147,7 @@ void __init sa1111_adjust_zones(int node
+ * will call us again if there are more interrupts to process.
+ */
+ static void
+-sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++sa1111_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int stat0, stat1, i;
+ void __iomem *base = get_irq_data(irq);
+@@ -162,17 +162,17 @@ sa1111_irq_handler(unsigned int irq, str
+ sa1111_writel(stat1, base + SA1111_INTSTATCLR1);
+
+ if (stat0 == 0 && stat1 == 0) {
+- do_bad_IRQ(irq, desc, regs);
++ do_bad_IRQ(irq, desc);
+ return;
+ }
+
+ for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1)
+ if (stat0 & 1)
+- handle_edge_irq(i, irq_desc + i, regs);
++ handle_edge_irq(i, irq_desc + i);
+
+ for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
+ if (stat1 & 1)
+- handle_edge_irq(i, irq_desc + i, regs);
++ handle_edge_irq(i, irq_desc + i);
+
+ /* For level-based interrupts */
+ desc->chip->unmask(irq);
+diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
+index 59b5dde..605dedf 100644
+--- a/arch/arm/common/sharpsl_pm.c
++++ b/arch/arm/common/sharpsl_pm.c
+@@ -40,6 +40,7 @@
+ #define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */
+ #define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */
+ #define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */
++
+ #define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */
+ #define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */
+ #define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */
+@@ -257,7 +258,7 @@ static void sharpsl_ac_timer(unsigned lo
+ }
+
+
+-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp)
++irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
+ {
+ /* Delay the event slightly to debounce */
+ /* Must be a smaller delay than the chrg_full_isr below */
+@@ -292,7 +293,7 @@ static void sharpsl_chrg_full_timer(unsi
+ /* Charging Finished Interrupt (Not present on Corgi) */
+ /* Can trigger at the same time as an AC staus change so
+ delay until after that has been processed */
+-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp)
++irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
+ {
+ if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
+ return IRQ_HANDLED;
+@@ -303,7 +304,7 @@ irqreturn_t sharpsl_chrg_full_isr(int ir
+ return IRQ_HANDLED;
+ }
+
+-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp)
++irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
+ {
+ int is_fatal = 0;
+
+@@ -575,6 +576,9 @@ static int corgi_pxa_pm_enter(suspend_st
+ while (corgi_enter_suspend(alarm_time,alarm_status,state))
+ {}
+
++ if (sharpsl_pm.machinfo->earlyresume)
++ sharpsl_pm.machinfo->earlyresume();
++
+ dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
+
+ return 0;
+diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c
+index 3f60dd9..34038ec 100644
+--- a/arch/arm/common/time-acorn.c
++++ b/arch/arm/common/time-acorn.c
+@@ -67,10 +67,10 @@ void __init ioctime_init(void)
+ }
+
+ static irqreturn_t
+-ioc_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++ioc_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig
+index 4f3d8d3..b430414 100644
+--- a/arch/arm/configs/at91rm9200dk_defconfig
++++ b/arch/arm/configs/at91rm9200dk_defconfig
+@@ -553,9 +553,9 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+@@ -577,7 +577,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
+ # Watchdog Device Drivers
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_AT91_WATCHDOG=y
++CONFIG_AT91RM9200_WATCHDOG=y
+
+ #
+ # USB-based Watchdog Cards
+diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig
+index 08b5dc3..d96fc83 100644
+--- a/arch/arm/configs/at91rm9200ek_defconfig
++++ b/arch/arm/configs/at91rm9200ek_defconfig
+@@ -534,9 +534,9 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+@@ -558,7 +558,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
+ # Watchdog Device Drivers
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_AT91_WATCHDOG=y
++CONFIG_AT91RM9200_WATCHDOG=y
+
+ #
+ # USB-based Watchdog Cards
+diff --git a/arch/arm/configs/ateb9200_defconfig b/arch/arm/configs/ateb9200_defconfig
+index bee7813..15e6b0b 100644
+--- a/arch/arm/configs/ateb9200_defconfig
++++ b/arch/arm/configs/ateb9200_defconfig
+@@ -656,9 +656,9 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+diff --git a/arch/arm/configs/bast_defconfig b/arch/arm/configs/bast_defconfig
+deleted file mode 100644
+index 4a8564f..0000000
+--- a/arch/arm/configs/bast_defconfig
++++ /dev/null
+@@ -1,947 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 02:24:16 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 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_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_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 is not set
+-CONFIG_ARCH_S3C2410=y
+-# 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
+-
+-#
+-# S3C24XX Implementations
+-#
+-CONFIG_ARCH_BAST=y
+-# CONFIG_ARCH_H1940 is not set
+-# CONFIG_MACH_N30 is not set
+-# CONFIG_ARCH_SMDK2410 is not set
+-# CONFIG_ARCH_S3C2440 is not set
+-CONFIG_MACH_VR1000=y
+-# CONFIG_MACH_RX3715 is not set
+-# CONFIG_MACH_OTOM is not set
+-# CONFIG_MACH_NEXCODER_2440 is not set
+-CONFIG_CPU_S3C2410=y
+-
+-#
+-# S3C2410 Boot
+-#
+-# CONFIG_S3C2410_BOOT_WATCHDOG is not set
+-
+-#
+-# S3C2410 Setup
+-#
+-CONFIG_S3C2410_DMA=y
+-# CONFIG_S3C2410_DMA_DEBUG is not set
+-# CONFIG_S3C2410_PM_DEBUG is not set
+-# CONFIG_S3C2410_PM_CHECK is not set
+-CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_ARM920T=y
+-CONFIG_CPU_32v4=y
+-CONFIG_CPU_ABRT_EV4T=y
+-CONFIG_CPU_CACHE_V4WT=y
+-CONFIG_CPU_CACHE_VIVT=y
+-CONFIG_CPU_COPY_V4WB=y
+-CONFIG_CPU_TLB_V4WBI=y
+-
+-#
+-# Processor Features
+-#
+-# CONFIG_ARM_THUMB is not set
+-# CONFIG_CPU_ICACHE_DISABLE is not set
+-# CONFIG_CPU_DCACHE_DISABLE is not set
+-# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+-
+-#
+-# Bus support
+-#
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
+-# CONFIG_XIP_KERNEL is not set
+-
+-#
+-# Floating point emulation
+-#
+-
+-#
+-# At least one emulation must be selected
+-#
+-CONFIG_FPE_NWFPE=y
+-# CONFIG_FPE_NWFPE_XP 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=y
+-CONFIG_APM=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=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-CONFIG_MTD_PARTITIONS=y
+-CONFIG_MTD_REDBOOT_PARTS=y
+-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+-# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+-CONFIG_MTD_CMDLINE_PARTS=y
+-# CONFIG_MTD_AFS_PARTS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-CONFIG_MTD_JEDECPROBE=y
+-CONFIG_MTD_GEN_PROBE=y
+-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_16=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_OBSOLETE_CHIPS is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-# CONFIG_MTD_PHYSMAP is not set
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-# CONFIG_MTD_IMPA7 is not set
+-CONFIG_MTD_BAST=y
+-CONFIG_MTD_BAST_MAXSIZE=4
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-CONFIG_MTD_NAND=y
+-# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+-CONFIG_MTD_NAND_IDS=y
+-CONFIG_MTD_NAND_S3C2410=y
+-# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
+-# CONFIG_MTD_NAND_S3C2410_HWECC is not set
+-# CONFIG_MTD_NAND_DISKONCHIP is not set
+-# CONFIG_MTD_NAND_NANDSIM is not set
+-
+-#
+-# Parallel port support
+-#
+-CONFIG_PARPORT=y
+-# CONFIG_PARPORT_PC is not set
+-# CONFIG_PARPORT_ARC is not set
+-# CONFIG_PARPORT_GSC is not set
+-CONFIG_PARPORT_1284=y
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# 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
+-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+-CONFIG_BLK_DEV_NBD=m
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_INITRD=y
+-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_IDECD=y
+-CONFIG_BLK_DEV_IDETAPE=m
+-CONFIG_BLK_DEV_IDEFLOPPY=m
+-# CONFIG_IDE_TASK_IOCTL is not set
+-
+-#
+-# IDE chipset support/bugfixes
+-#
+-CONFIG_IDE_GENERIC=y
+-# CONFIG_IDE_ARM is not set
+-CONFIG_BLK_DEV_IDE_BAST=y
+-# 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 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 is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_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 is not set
+-# CONFIG_SMC91X 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_PLIP 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_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_PARKBD is not set
+-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=y
+-# CONFIG_COMPUTONE is not set
+-# CONFIG_ROCKETPORT is not set
+-# CONFIG_CYCLADES is not set
+-# CONFIG_DIGIEPCA is not set
+-# CONFIG_MOXA_INTELLIO is not set
+-# CONFIG_MOXA_SMARTIO is not set
+-# CONFIG_ISI is not set
+-# CONFIG_SYNCLINKMP is not set
+-# CONFIG_N_HDLC is not set
+-# CONFIG_RISCOM8 is not set
+-# CONFIG_SPECIALIX is not set
+-# CONFIG_SX is not set
+-# CONFIG_RIO is not set
+-# CONFIG_STALDRV is not set
+-
+-#
+-# Serial drivers
+-#
+-CONFIG_SERIAL_8250=y
+-CONFIG_SERIAL_8250_CONSOLE=y
+-CONFIG_SERIAL_8250_NR_UARTS=8
+-CONFIG_SERIAL_8250_EXTENDED=y
+-CONFIG_SERIAL_8250_MANY_PORTS=y
+-CONFIG_SERIAL_8250_SHARE_IRQ=y
+-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+-# CONFIG_SERIAL_8250_MULTIPORT is not set
+-# CONFIG_SERIAL_8250_RSA is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_S3C2410=y
+-CONFIG_SERIAL_S3C2410_CONSOLE=y
+-CONFIG_SERIAL_CORE=y
+-CONFIG_SERIAL_CORE_CONSOLE=y
+-CONFIG_UNIX98_PTYS=y
+-CONFIG_LEGACY_PTYS=y
+-CONFIG_LEGACY_PTY_COUNT=256
+-CONFIG_PRINTER=y
+-# CONFIG_LP_CONSOLE is not set
+-CONFIG_PPDEV=y
+-# CONFIG_TIPAR is not set
+-
+-#
+-# IPMI
+-#
+-# CONFIG_IPMI_HANDLER is not set
+-
+-#
+-# Watchdog Cards
+-#
+-CONFIG_WATCHDOG=y
+-# CONFIG_WATCHDOG_NOWAYOUT is not set
+-
+-#
+-# Watchdog Device Drivers
+-#
+-# CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_S3C2410_WATCHDOG=y
+-# CONFIG_NVRAM is not set
+-# CONFIG_RTC is not set
+-CONFIG_S3C2410_RTC=y
+-# 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
+-
+-#
+-# TPM devices
+-#
+-# CONFIG_TCG_TPM is not set
+-
+-#
+-# I2C support
+-#
+-CONFIG_I2C=y
+-CONFIG_I2C_CHARDEV=m
+-
+-#
+-# I2C Algorithms
+-#
+-CONFIG_I2C_ALGOBIT=m
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ISA is not set
+-# CONFIG_I2C_PARPORT is not set
+-# CONFIG_I2C_PARPORT_LIGHT is not set
+-CONFIG_I2C_S3C2410=y
+-# CONFIG_I2C_STUB is not set
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Hardware Sensors Chip support
+-#
+-CONFIG_I2C_SENSOR=m
+-# CONFIG_SENSORS_ADM1021 is not set
+-# CONFIG_SENSORS_ADM1025 is not set
+-# CONFIG_SENSORS_ADM1026 is not set
+-# CONFIG_SENSORS_ADM1031 is not set
+-# CONFIG_SENSORS_ASB100 is not set
+-# CONFIG_SENSORS_DS1621 is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_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=m
+-# CONFIG_SENSORS_LM77 is not set
+-CONFIG_SENSORS_LM78=m
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-CONFIG_SENSORS_LM85=m
+-# CONFIG_SENSORS_LM87 is not set
+-# CONFIG_SENSORS_LM90 is not set
+-# CONFIG_SENSORS_MAX1619 is not set
+-# CONFIG_SENSORS_PC87360 is not set
+-# CONFIG_SENSORS_SMSC47B397 is not set
+-# CONFIG_SENSORS_SMSC47M1 is not set
+-# CONFIG_SENSORS_W83781D is not set
+-# CONFIG_SENSORS_W83L785TS is not set
+-# CONFIG_SENSORS_W83627HF is not set
+-
+-#
+-# Other I2C Chip support
+-#
+-CONFIG_SENSORS_EEPROM=m
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_RTC8564 is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
+-
+-#
+-# 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 is not set
+-# CONFIG_FB_CFB_COPYAREA is not set
+-# CONFIG_FB_CFB_IMAGEBLIT is not set
+-# CONFIG_FB_SOFT_CURSOR is not set
+-CONFIG_FB_MODE_HELPERS=y
+-# CONFIG_FB_TILEBLITTING is not set
+-# CONFIG_FB_VIRTUAL is not set
+-
+-#
+-# Console display driver support
+-#
+-# CONFIG_VGA_CONSOLE is not set
+-CONFIG_DUMMY_CONSOLE=y
+-# CONFIG_FRAMEBUFFER_CONSOLE 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=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=y
+-# 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=y
+-CONFIG_FAT_DEFAULT_CODEPAGE=437
+-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+-# CONFIG_NTFS_FS is not set
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_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_JFFS_FS=y
+-CONFIG_JFFS_FS_VERBOSE=0
+-# CONFIG_JFFS_PROC_FS is not set
+-CONFIG_JFFS2_FS=y
+-CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
+-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+-CONFIG_JFFS2_ZLIB=y
+-CONFIG_JFFS2_RTIME=y
+-# CONFIG_JFFS2_RUBIN is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-# CONFIG_NFS_V3 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=y
+-# CONFIG_MINIX_SUBPARTITION is not set
+-CONFIG_SOLARIS_X86_PARTITION=y
+-# 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=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=y
+-# CONFIG_MAGIC_SYSRQ is not set
+-CONFIG_LOG_BUF_SHIFT=16
+-# 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_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 is not set
+-CONFIG_DEBUG_LL=y
+-# CONFIG_DEBUG_ICEDCC is not set
+-CONFIG_DEBUG_S3C2410_PORT=y
+-CONFIG_DEBUG_S3C2410_UART=0
+-
+-#
+-# 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
+-CONFIG_ZLIB_INFLATE=y
+-CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/arm/configs/carmeva_defconfig b/arch/arm/configs/carmeva_defconfig
+index 8a075c8..d24ae87 100644
+--- a/arch/arm/configs/carmeva_defconfig
++++ b/arch/arm/configs/carmeva_defconfig
+@@ -455,8 +455,8 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig
+index cf3fa5c..20e6825 100644
+--- a/arch/arm/configs/csb337_defconfig
++++ b/arch/arm/configs/csb337_defconfig
+@@ -591,9 +591,9 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+@@ -615,7 +615,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
+ # Watchdog Device Drivers
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_AT91_WATCHDOG=y
++CONFIG_AT91RM9200_WATCHDOG=y
+
+ #
+ # USB-based Watchdog Cards
+diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig
+index 640d70c..df8595a 100644
+--- a/arch/arm/configs/csb637_defconfig
++++ b/arch/arm/configs/csb637_defconfig
+@@ -591,9 +591,9 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+@@ -615,7 +615,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
+ # Watchdog Device Drivers
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_AT91_WATCHDOG=y
++CONFIG_AT91RM9200_WATCHDOG=y
+
+ #
+ # USB-based Watchdog Cards
+diff --git a/arch/arm/configs/ep80219_defconfig b/arch/arm/configs/ep80219_defconfig
+deleted file mode 100644
+index 3c73b70..0000000
+--- a/arch/arm/configs/ep80219_defconfig
++++ /dev/null
+@@ -1,952 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 22:34:12 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=y
+-# CONFIG_BSD_PROCESS_ACCT_V3 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 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=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
+-
+-#
+-# 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_FOOTBRIDGE is not set
+-# CONFIG_ARCH_INTEGRATOR is not set
+-CONFIG_ARCH_IOP3XX=y
+-# 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 is not set
+-# 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
+-
+-#
+-# IOP3xx Implementation Options
+-#
+-
+-#
+-# IOP3xx Platform Types
+-#
+-# CONFIG_ARCH_IQ80321 is not set
+-CONFIG_ARCH_IQ31244=y
+-# CONFIG_ARCH_IQ80331 is not set
+-# CONFIG_MACH_IQ80332 is not set
+-CONFIG_ARCH_EP80219=y
+-CONFIG_ARCH_IOP321=y
+-# CONFIG_ARCH_IOP331 is not set
+-
+-#
+-# IOP3xx Chipset Features
+-#
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_XSCALE=y
+-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
+-#
+-# CONFIG_ARM_THUMB is not set
+-CONFIG_XSCALE_PMU=y
+-
+-#
+-# Bus support
+-#
+-CONFIG_PCI=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+-# CONFIG_XIP_KERNEL is not set
+-
+-#
+-# Floating point emulation
+-#
+-
+-#
+-# At least one emulation must be selected
+-#
+-CONFIG_FPE_NWFPE=y
+-# CONFIG_FPE_NWFPE_XP 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=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-CONFIG_MTD_PARTITIONS=y
+-CONFIG_MTD_REDBOOT_PARTS=y
+-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+-# CONFIG_MTD_CMDLINE_PARTS is not set
+-# CONFIG_MTD_AFS_PARTS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=0xf0000000
+-CONFIG_MTD_PHYSMAP_LEN=0x00800000
+-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_PMC551 is not set
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_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=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=8192
+-# CONFIG_BLK_DEV_INITRD is not set
+-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=y
+-CONFIG_SCSI_PROC_FS=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-# CONFIG_CHR_DEV_ST is not set
+-# CONFIG_CHR_DEV_OSST is not set
+-# CONFIG_BLK_DEV_SR is not set
+-CONFIG_CHR_DEV_SG=y
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-# CONFIG_SCSI_MULTI_LUN is not set
+-# CONFIG_SCSI_CONSTANTS is not set
+-# CONFIG_SCSI_LOGGING is not set
+-
+-#
+-# SCSI Transport Attributes
+-#
+-# CONFIG_SCSI_SPI_ATTRS is not set
+-# CONFIG_SCSI_FC_ATTRS is not set
+-# CONFIG_SCSI_ISCSI_ATTRS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+-# CONFIG_SCSI_3W_9XXX is not set
+-# CONFIG_SCSI_ACARD is not set
+-# CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
+-# CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_DPT_I2O is not set
+-# CONFIG_MEGARAID_NEWGEN is not set
+-# CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_BUSLOGIC is not set
+-# CONFIG_SCSI_DMX3191D is not set
+-# CONFIG_SCSI_EATA is not set
+-# CONFIG_SCSI_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
+-# CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+-# CONFIG_SCSI_QLOGIC_1280 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
+-# CONFIG_SCSI_DC395x is not set
+-# CONFIG_SCSI_DC390T is not set
+-# CONFIG_SCSI_NSP32 is not set
+-# CONFIG_SCSI_DEBUG is not set
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-CONFIG_MD=y
+-CONFIG_BLK_DEV_MD=y
+-# CONFIG_MD_LINEAR is not set
+-CONFIG_MD_RAID0=y
+-CONFIG_MD_RAID1=y
+-# CONFIG_MD_RAID10 is not set
+-CONFIG_MD_RAID5=y
+-# CONFIG_MD_RAID6 is not set
+-# CONFIG_MD_MULTIPATH is not set
+-# CONFIG_MD_FAULTY is not set
+-CONFIG_BLK_DEV_DM=y
+-# CONFIG_DM_CRYPT is not set
+-# CONFIG_DM_SNAPSHOT is not set
+-# CONFIG_DM_MIRROR is not set
+-# CONFIG_DM_ZERO is not set
+-# CONFIG_DM_MULTIPATH 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=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=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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
+-
+-#
+-# 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
+-# CONFIG_SMC91X 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=y
+-# CONFIG_FEALNX is not set
+-# CONFIG_NATSEMI is not set
+-# CONFIG_NE2K_PCI is not set
+-# CONFIG_8139CP is not set
+-# CONFIG_8139TOO is not set
+-# CONFIG_SIS900 is not set
+-# CONFIG_EPIC100 is not set
+-# CONFIG_SUNDANCE is not set
+-# CONFIG_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=y
+-CONFIG_E1000_NAPI=y
+-# CONFIG_E1000_DISABLE_PACKET_SPLIT 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_VIA_VELOCITY is not set
+-# CONFIG_TIGON3 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# 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 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
+-
+-#
+-# Hardware I/O ports
+-#
+-# CONFIG_SERIO 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=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_NVRAM is not set
+-# CONFIG_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=y
+-CONFIG_I2C_CHARDEV=y
+-
+-#
+-# I2C Algorithms
+-#
+-# CONFIG_I2C_ALGOBIT is not set
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-CONFIG_I2C_IOP3XX=y
+-# CONFIG_I2C_ISA 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
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Hardware Sensors Chip support
+-#
+-# CONFIG_I2C_SENSOR is not set
+-# CONFIG_SENSORS_ADM1021 is not set
+-# CONFIG_SENSORS_ADM1025 is not set
+-# CONFIG_SENSORS_ADM1026 is not set
+-# CONFIG_SENSORS_ADM1031 is not set
+-# CONFIG_SENSORS_ASB100 is not set
+-# CONFIG_SENSORS_DS1621 is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_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
+-# CONFIG_SENSORS_LM77 is not set
+-# CONFIG_SENSORS_LM78 is not set
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-# CONFIG_SENSORS_LM85 is not set
+-# CONFIG_SENSORS_LM87 is not set
+-# CONFIG_SENSORS_LM90 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
+-
+-#
+-# Other I2C Chip support
+-#
+-# CONFIG_SENSORS_EEPROM is not set
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_RTC8564 is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
+-
+-#
+-# 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
+-
+-#
+-# 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
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-CONFIG_EXT3_FS=y
+-CONFIG_EXT3_FS_XATTR=y
+-# CONFIG_EXT3_FS_POSIX_ACL is not set
+-# CONFIG_EXT3_FS_SECURITY is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
+-CONFIG_XFS_FS=y
+-CONFIG_XFS_EXPORT=y
+-# CONFIG_XFS_RT is not set
+-# CONFIG_XFS_QUOTA is not set
+-CONFIG_XFS_SECURITY=y
+-CONFIG_XFS_POSIX_ACL=y
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-# CONFIG_QUOTA is not set
+-CONFIG_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_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
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_JFFS_FS is not set
+-CONFIG_JFFS2_FS=y
+-CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
+-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+-CONFIG_JFFS2_ZLIB=y
+-CONFIG_JFFS2_RTIME=y
+-# CONFIG_JFFS2_RUBIN is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V4 is not set
+-# CONFIG_NFS_DIRECTIO is not set
+-CONFIG_NFSD=y
+-CONFIG_NFSD_V3=y
+-# CONFIG_NFSD_V4 is not set
+-# CONFIG_NFSD_TCP is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
+-CONFIG_SUNRPC=y
+-# CONFIG_RPCSEC_GSS_KRB5 is not set
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# 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
+-
+-#
+-# 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=y
+-
+-#
+-# 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
+-CONFIG_ZLIB_INFLATE=y
+-CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
+index 2948b45..3b4802a 100644
+--- a/arch/arm/configs/ep93xx_defconfig
++++ b/arch/arm/configs/ep93xx_defconfig
+@@ -126,6 +126,7 @@ CONFIG_CRUNCH=y
+ # EP93xx Platforms
+ #
+ CONFIG_MACH_EDB9302=y
++CONFIG_MACH_EDB9312=y
+ CONFIG_MACH_EDB9315=y
+ CONFIG_MACH_EDB9315A=y
+ CONFIG_MACH_GESBC9312=y
+diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig
+new file mode 100644
+index 0000000..0d67f66
+--- /dev/null
++++ b/arch/arm/configs/iop32x_defconfig
+@@ -0,0 +1,1236 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18-rc7
++# Tue Sep 19 00:30:18 2006
++#
++CONFIG_ARM=y
++CONFIG_MMU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++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_TASKSTATS is not set
++CONFIG_SYSCTL=y
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_UID16=y
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++# CONFIG_EMBEDDED is not set
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++# CONFIG_BLK_DEV_IO_TRACE is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# 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_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX is not set
++CONFIG_ARCH_IOP32X=y
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_OMAP is not set
++
++#
++# IOP32x Implementation Options
++#
++
++#
++# IOP32x Platform Types
++#
++CONFIG_MACH_GLANTANK=y
++CONFIG_ARCH_IQ80321=y
++CONFIG_ARCH_IQ31244=y
++CONFIG_MACH_N2100=y
++CONFIG_PLAT_IOP=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_XSCALE=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_TLB_V4WBI=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_THUMB is not set
++CONFIG_XSCALE_PMU=y
++
++#
++# Bus support
++#
++CONFIG_PCI=y
++# CONFIG_PCI_DEBUG is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++# CONFIG_PREEMPT is not set
++# CONFIG_NO_IDLE_HZ is not set
++CONFIG_HZ=100
++# CONFIG_AEABI 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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp"
++# CONFIG_XIP_KERNEL is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP 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
++# CONFIG_APM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# 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=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_BIC=y
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++CONFIG_MTD_REDBOOT_PARTS=y
++CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
++CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
++CONFIG_MTD_REDBOOT_PARTS_READONLY=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x0
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=1
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_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=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transport Attributes
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_IPR is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++CONFIG_MD=y
++CONFIG_BLK_DEV_MD=y
++# CONFIG_MD_LINEAR is not set
++CONFIG_MD_RAID0=y
++CONFIG_MD_RAID1=y
++# CONFIG_MD_RAID10 is not set
++# CONFIG_MD_RAID456 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_MD_FAULTY is not set
++CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_CRYPT is not set
++# CONFIG_DM_SNAPSHOT is not set
++# CONFIG_DM_MIRROR is not set
++# CONFIG_DM_ZERO is not set
++# CONFIG_DM_MULTIPATH is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++
++#
++# Network device support
++#
++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
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB 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_CASSINI 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
++#
++# 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=y
++# CONFIG_FEALNX is not set
++# CONFIG_NATSEMI is not set
++# CONFIG_NE2K_PCI is not set
++# CONFIG_8139CP is not set
++# CONFIG_8139TOO is not set
++# CONFIG_SIS900 is not set
++# CONFIG_EPIC100 is not set
++# CONFIG_SUNDANCE is not set
++# CONFIG_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=y
++CONFIG_E1000_NAPI=y
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++CONFIG_R8169=y
++# CONFIG_R8169_NAPI is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 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)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER 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 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 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
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
++CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
++# CONFIG_SERIAL_8250_EXTENDED 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=y
++CONFIG_LEGACY_PTY_COUNT=256
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_NVRAM 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
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=y
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_I810 is not set
++# CONFIG_I2C_PIIX4 is not set
++CONFIG_I2C_IOP3XX=y
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_PROSAVAGE is not set
++# CONFIG_I2C_SAVAGE4 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
++# CONFIG_I2C_PCA_ISA is not set
++
++#
++# Miscellaneous 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_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
++# CONFIG_I2C_DEBUG_CHIP is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# 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_F71805F 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
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_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_SIS5595 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# 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=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_SPLIT_ISO=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++CONFIG_USB_UHCI_HCD=y
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# may also be needed; see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_DPCM 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
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Input Devices
++#
++# CONFIG_USB_HID is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# 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_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# Real Time Clock
++#
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++
++#
++# File systems
++#
++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=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_XFS_FS=y
++# CONFIG_XFS_QUOTA is not set
++CONFIG_XFS_SECURITY=y
++CONFIG_XFS_POSIX_ACL=y
++# CONFIG_XFS_RT is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# 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_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=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
++# CONFIG_9P_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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS 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_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
++# CONFIG_FORCED_INLINING is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_WAITQ is not set
++# CONFIG_DEBUG_ERRORS is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC 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_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/arm/configs/iop33x_defconfig b/arch/arm/configs/iop33x_defconfig
+new file mode 100644
+index 0000000..2a8fc15
+--- /dev/null
++++ b/arch/arm/configs/iop33x_defconfig
+@@ -0,0 +1,1081 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18-rc7
++# Tue Sep 19 00:30:42 2006
++#
++CONFIG_ARM=y
++CONFIG_MMU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++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_TASKSTATS is not set
++CONFIG_SYSCTL=y
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_UID16=y
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++# CONFIG_EMBEDDED is not set
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++# CONFIG_BLK_DEV_IO_TRACE is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# 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_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX is not set
++# CONFIG_ARCH_IOP32X is not set
++CONFIG_ARCH_IOP33X=y
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_OMAP is not set
++
++#
++# IOP33x Implementation Options
++#
++
++#
++# IOP33x Platform Types
++#
++CONFIG_ARCH_IQ80331=y
++CONFIG_MACH_IQ80332=y
++CONFIG_PLAT_IOP=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_XSCALE=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_TLB_V4WBI=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_THUMB is not set
++CONFIG_XSCALE_PMU=y
++
++#
++# Bus support
++#
++CONFIG_PCI=y
++# CONFIG_PCI_DEBUG is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++# CONFIG_PREEMPT is not set
++# CONFIG_NO_IDLE_HZ is not set
++CONFIG_HZ=100
++# CONFIG_AEABI 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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp"
++# CONFIG_XIP_KERNEL is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP 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
++# CONFIG_APM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# 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=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_BIC=y
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++CONFIG_MTD_REDBOOT_PARTS=y
++CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
++CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
++CONFIG_MTD_REDBOOT_PARTS_READONLY=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_GEOMETRY is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_OTP is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x0
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=1
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_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=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transport Attributes
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_IPR is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++CONFIG_MD=y
++CONFIG_BLK_DEV_MD=y
++CONFIG_MD_LINEAR=y
++CONFIG_MD_RAID0=y
++CONFIG_MD_RAID1=y
++# CONFIG_MD_RAID10 is not set
++# CONFIG_MD_RAID456 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_MD_FAULTY is not set
++CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_CRYPT is not set
++# CONFIG_DM_SNAPSHOT is not set
++# CONFIG_DM_MIRROR is not set
++# CONFIG_DM_ZERO is not set
++# CONFIG_DM_MULTIPATH is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++
++#
++# Network device support
++#
++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
++
++#
++# PHY device support
++#
++
++#
++# Ethernet (10 or 100Mbit)
++#
++# CONFIG_NET_ETHERNET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++CONFIG_E1000=y
++CONFIG_E1000_NAPI=y
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++
++#
++# Ethernet (10000 Mbit)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER 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 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 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
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
++CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
++# CONFIG_SERIAL_8250_EXTENDED 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=y
++CONFIG_LEGACY_PTY_COUNT=256
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_NVRAM 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
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=y
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_I810 is not set
++# CONFIG_I2C_PIIX4 is not set
++CONFIG_I2C_IOP3XX=y
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_PROSAVAGE is not set
++# CONFIG_I2C_SAVAGE4 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
++# CONFIG_I2C_PCA_ISA is not set
++
++#
++# Miscellaneous 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_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
++# CONFIG_I2C_DEBUG_CHIP is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# 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_F71805F 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
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_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_SIS5595 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# 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=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# Real Time Clock
++#
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++
++#
++# File systems
++#
++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=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_XFS_FS=y
++# CONFIG_XFS_QUOTA is not set
++CONFIG_XFS_SECURITY=y
++CONFIG_XFS_POSIX_ACL=y
++# CONFIG_XFS_RT is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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_JFFS_FS is not set
++# CONFIG_JFFS2_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_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# 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_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=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
++# CONFIG_9P_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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS 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_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
++# CONFIG_FORCED_INLINING is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_WAITQ is not set
++# CONFIG_DEBUG_ERRORS is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC 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_CRC16 is not set
++# CONFIG_CRC32 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+diff --git a/arch/arm/configs/iq31244_defconfig b/arch/arm/configs/iq31244_defconfig
+deleted file mode 100644
+index 3246716..0000000
+--- a/arch/arm/configs/iq31244_defconfig
++++ /dev/null
+@@ -1,922 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 02:10:38 2005
+-#
+-CONFIG_ARM=y
+-CONFIG_MMU=y
+-CONFIG_UID16=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_GENERIC_IOMAP=y
+-
+-#
+-# Code maturity level options
+-#
+-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_HOTPLUG is not set
+-CONFIG_KOBJECT_UEVENT=y
+-CONFIG_IKCONFIG=y
+-CONFIG_IKCONFIG_PROC=y
+-# 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=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
+-
+-#
+-# 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_FOOTBRIDGE is not set
+-# CONFIG_ARCH_INTEGRATOR is not set
+-CONFIG_ARCH_IOP3XX=y
+-# 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 is not set
+-# 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
+-
+-#
+-# IOP3xx Implementation Options
+-#
+-
+-#
+-# IOP3xx Platform Types
+-#
+-# CONFIG_ARCH_IQ80321 is not set
+-CONFIG_ARCH_IQ31244=y
+-# CONFIG_ARCH_IQ80331 is not set
+-# CONFIG_MACH_IQ80332 is not set
+-# CONFIG_ARCH_EP80219 is not set
+-CONFIG_ARCH_IOP321=y
+-# CONFIG_ARCH_IOP331 is not set
+-
+-#
+-# IOP3xx Chipset Features
+-#
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_XSCALE=y
+-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
+-#
+-# CONFIG_ARM_THUMB is not set
+-CONFIG_XSCALE_PMU=y
+-
+-#
+-# Bus support
+-#
+-CONFIG_PCI=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+-# CONFIG_XIP_KERNEL is not set
+-
+-#
+-# Floating point emulation
+-#
+-
+-#
+-# At least one emulation must be selected
+-#
+-CONFIG_FPE_NWFPE=y
+-# CONFIG_FPE_NWFPE_XP 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=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-CONFIG_MTD_PARTITIONS=y
+-CONFIG_MTD_REDBOOT_PARTS=y
+-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+-# CONFIG_MTD_CMDLINE_PARTS is not set
+-# CONFIG_MTD_AFS_PARTS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=0xf0000000
+-CONFIG_MTD_PHYSMAP_LEN=0x00800000
+-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_PMC551 is not set
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_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=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=8192
+-# CONFIG_BLK_DEV_INITRD is not set
+-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=y
+-CONFIG_SCSI_PROC_FS=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-# CONFIG_CHR_DEV_ST is not set
+-# CONFIG_CHR_DEV_OSST is not set
+-# CONFIG_BLK_DEV_SR is not set
+-CONFIG_CHR_DEV_SG=y
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-# CONFIG_SCSI_MULTI_LUN is not set
+-# CONFIG_SCSI_CONSTANTS is not set
+-# CONFIG_SCSI_LOGGING is not set
+-
+-#
+-# SCSI Transport Attributes
+-#
+-# CONFIG_SCSI_SPI_ATTRS is not set
+-# CONFIG_SCSI_FC_ATTRS is not set
+-# CONFIG_SCSI_ISCSI_ATTRS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+-# CONFIG_SCSI_3W_9XXX is not set
+-# CONFIG_SCSI_ACARD is not set
+-# CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
+-# CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_DPT_I2O is not set
+-# CONFIG_MEGARAID_NEWGEN is not set
+-# CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_BUSLOGIC is not set
+-# CONFIG_SCSI_DMX3191D is not set
+-# CONFIG_SCSI_EATA is not set
+-# CONFIG_SCSI_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
+-# CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+-# CONFIG_SCSI_QLOGIC_1280 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
+-# CONFIG_SCSI_DC395x is not set
+-# CONFIG_SCSI_DC390T is not set
+-# CONFIG_SCSI_NSP32 is not set
+-# CONFIG_SCSI_DEBUG is not set
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-CONFIG_MD=y
+-CONFIG_BLK_DEV_MD=y
+-# CONFIG_MD_LINEAR is not set
+-CONFIG_MD_RAID0=y
+-CONFIG_MD_RAID1=y
+-# CONFIG_MD_RAID10 is not set
+-CONFIG_MD_RAID5=y
+-# CONFIG_MD_RAID6 is not set
+-# CONFIG_MD_MULTIPATH is not set
+-# CONFIG_MD_FAULTY is not set
+-CONFIG_BLK_DEV_DM=y
+-# CONFIG_DM_CRYPT is not set
+-# CONFIG_DM_SNAPSHOT is not set
+-# CONFIG_DM_MIRROR is not set
+-# CONFIG_DM_ZERO is not set
+-# CONFIG_DM_MULTIPATH 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=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=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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
+-
+-#
+-# ARCnet devices
+-#
+-# CONFIG_ARCNET is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-# CONFIG_NET_ETHERNET is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-CONFIG_E1000=y
+-CONFIG_E1000_NAPI=y
+-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-# CONFIG_R8169 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_TIGON3 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# 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 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
+-
+-#
+-# Hardware I/O ports
+-#
+-# CONFIG_SERIO 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=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_NVRAM is not set
+-# CONFIG_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=y
+-CONFIG_I2C_CHARDEV=y
+-
+-#
+-# I2C Algorithms
+-#
+-# CONFIG_I2C_ALGOBIT is not set
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-CONFIG_I2C_IOP3XX=y
+-# CONFIG_I2C_ISA 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
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Hardware Sensors Chip support
+-#
+-# CONFIG_I2C_SENSOR is not set
+-# CONFIG_SENSORS_ADM1021 is not set
+-# CONFIG_SENSORS_ADM1025 is not set
+-# CONFIG_SENSORS_ADM1026 is not set
+-# CONFIG_SENSORS_ADM1031 is not set
+-# CONFIG_SENSORS_ASB100 is not set
+-# CONFIG_SENSORS_DS1621 is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_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
+-# CONFIG_SENSORS_LM77 is not set
+-# CONFIG_SENSORS_LM78 is not set
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-# CONFIG_SENSORS_LM85 is not set
+-# CONFIG_SENSORS_LM87 is not set
+-# CONFIG_SENSORS_LM90 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
+-
+-#
+-# Other I2C Chip support
+-#
+-# CONFIG_SENSORS_EEPROM is not set
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_RTC8564 is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
+-
+-#
+-# 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
+-
+-#
+-# 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
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-CONFIG_EXT3_FS=y
+-CONFIG_EXT3_FS_XATTR=y
+-# CONFIG_EXT3_FS_POSIX_ACL is not set
+-# CONFIG_EXT3_FS_SECURITY is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
+-CONFIG_XFS_FS=y
+-CONFIG_XFS_EXPORT=y
+-# CONFIG_XFS_RT is not set
+-# CONFIG_XFS_QUOTA is not set
+-CONFIG_XFS_SECURITY=y
+-CONFIG_XFS_POSIX_ACL=y
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-# CONFIG_QUOTA is not set
+-CONFIG_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_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
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_JFFS_FS is not set
+-CONFIG_JFFS2_FS=y
+-CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
+-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+-CONFIG_JFFS2_ZLIB=y
+-CONFIG_JFFS2_RTIME=y
+-# CONFIG_JFFS2_RUBIN is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V4 is not set
+-# CONFIG_NFS_DIRECTIO is not set
+-CONFIG_NFSD=y
+-CONFIG_NFSD_V3=y
+-# CONFIG_NFSD_V4 is not set
+-# CONFIG_NFSD_TCP is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
+-CONFIG_SUNRPC=y
+-# CONFIG_RPCSEC_GSS_KRB5 is not set
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# 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
+-
+-#
+-# 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=y
+-
+-#
+-# 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
+-CONFIG_ZLIB_INFLATE=y
+-CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/arm/configs/iq80321_defconfig b/arch/arm/configs/iq80321_defconfig
+deleted file mode 100644
+index b000da7..0000000
+--- a/arch/arm/configs/iq80321_defconfig
++++ /dev/null
+@@ -1,843 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 13:24:10 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=y
+-# CONFIG_BSD_PROCESS_ACCT_V3 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 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=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
+-
+-#
+-# 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_FOOTBRIDGE is not set
+-# CONFIG_ARCH_INTEGRATOR is not set
+-CONFIG_ARCH_IOP3XX=y
+-# 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 is not set
+-# 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
+-
+-#
+-# IOP3xx Implementation Options
+-#
+-
+-#
+-# IOP3xx Platform Types
+-#
+-CONFIG_ARCH_IQ80321=y
+-# CONFIG_ARCH_IQ31244 is not set
+-# CONFIG_ARCH_IQ80331 is not set
+-# CONFIG_MACH_IQ80332 is not set
+-# CONFIG_ARCH_EP80219 is not set
+-CONFIG_ARCH_IOP321=y
+-# CONFIG_ARCH_IOP331 is not set
+-
+-#
+-# IOP3xx Chipset Features
+-#
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_XSCALE=y
+-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
+-#
+-# CONFIG_ARM_THUMB is not set
+-CONFIG_XSCALE_PMU=y
+-
+-#
+-# Bus support
+-#
+-CONFIG_PCI=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+-# CONFIG_XIP_KERNEL is not set
+-
+-#
+-# Floating point emulation
+-#
+-
+-#
+-# At least one emulation must be selected
+-#
+-CONFIG_FPE_NWFPE=y
+-# CONFIG_FPE_NWFPE_XP 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=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-CONFIG_MTD_PARTITIONS=y
+-CONFIG_MTD_REDBOOT_PARTS=y
+-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+-# CONFIG_MTD_CMDLINE_PARTS is not set
+-# CONFIG_MTD_AFS_PARTS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=0xf0000000
+-CONFIG_MTD_PHYSMAP_LEN=0x00800000
+-CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_PMC551 is not set
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_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=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=8192
+-# CONFIG_BLK_DEV_INITRD is not set
+-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=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=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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
+-
+-#
+-# ARCnet devices
+-#
+-# CONFIG_ARCNET is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-# CONFIG_NET_ETHERNET is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-CONFIG_E1000=y
+-CONFIG_E1000_NAPI=y
+-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-# CONFIG_R8169 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_TIGON3 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_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 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 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
+-
+-#
+-# Hardware I/O ports
+-#
+-# CONFIG_SERIO 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=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_NVRAM is not set
+-# CONFIG_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=y
+-CONFIG_I2C_CHARDEV=y
+-
+-#
+-# I2C Algorithms
+-#
+-# CONFIG_I2C_ALGOBIT is not set
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-CONFIG_I2C_IOP3XX=y
+-# CONFIG_I2C_ISA 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
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Hardware Sensors Chip support
+-#
+-# CONFIG_I2C_SENSOR is not set
+-# CONFIG_SENSORS_ADM1021 is not set
+-# CONFIG_SENSORS_ADM1025 is not set
+-# CONFIG_SENSORS_ADM1026 is not set
+-# CONFIG_SENSORS_ADM1031 is not set
+-# CONFIG_SENSORS_ASB100 is not set
+-# CONFIG_SENSORS_DS1621 is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_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
+-# CONFIG_SENSORS_LM77 is not set
+-# CONFIG_SENSORS_LM78 is not set
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-# CONFIG_SENSORS_LM85 is not set
+-# CONFIG_SENSORS_LM87 is not set
+-# CONFIG_SENSORS_LM90 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
+-
+-#
+-# Other I2C Chip support
+-#
+-# CONFIG_SENSORS_EEPROM is not set
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_RTC8564 is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
+-
+-#
+-# 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
+-
+-#
+-# 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
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-CONFIG_EXT3_FS=y
+-CONFIG_EXT3_FS_XATTR=y
+-# CONFIG_EXT3_FS_POSIX_ACL is not set
+-# CONFIG_EXT3_FS_SECURITY is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
+-CONFIG_XFS_FS=y
+-CONFIG_XFS_EXPORT=y
+-# CONFIG_XFS_RT is not set
+-# CONFIG_XFS_QUOTA is not set
+-CONFIG_XFS_SECURITY=y
+-CONFIG_XFS_POSIX_ACL=y
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-# CONFIG_QUOTA is not set
+-CONFIG_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_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
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_JFFS_FS is not set
+-CONFIG_JFFS2_FS=y
+-CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
+-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+-CONFIG_JFFS2_ZLIB=y
+-CONFIG_JFFS2_RTIME=y
+-# CONFIG_JFFS2_RUBIN is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V4 is not set
+-# CONFIG_NFS_DIRECTIO is not set
+-CONFIG_NFSD=y
+-CONFIG_NFSD_V3=y
+-# CONFIG_NFSD_V4 is not set
+-# CONFIG_NFSD_TCP is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
+-CONFIG_SUNRPC=y
+-# CONFIG_RPCSEC_GSS_KRB5 is not set
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# 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
+-
+-#
+-# 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=y
+-
+-#
+-# 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
+-CONFIG_ZLIB_INFLATE=y
+-CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/arm/configs/iq80331_defconfig b/arch/arm/configs/iq80331_defconfig
+deleted file mode 100644
+index 46c79e1..0000000
+--- a/arch/arm/configs/iq80331_defconfig
++++ /dev/null
+@@ -1,916 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 15:13:37 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=y
+-# CONFIG_BSD_PROCESS_ACCT_V3 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 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=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
+-
+-#
+-# 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_FOOTBRIDGE is not set
+-# CONFIG_ARCH_INTEGRATOR is not set
+-CONFIG_ARCH_IOP3XX=y
+-# 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 is not set
+-# 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
+-
+-#
+-# IOP3xx Implementation Options
+-#
+-
+-#
+-# IOP3xx Platform Types
+-#
+-# CONFIG_ARCH_IQ80321 is not set
+-# CONFIG_ARCH_IQ31244 is not set
+-CONFIG_ARCH_IQ80331=y
+-# CONFIG_MACH_IQ80332 is not set
+-# CONFIG_ARCH_EP80219 is not set
+-CONFIG_ARCH_IOP331=y
+-
+-#
+-# IOP3xx Chipset Features
+-#
+-CONFIG_IOP331_STEPD=y
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_XSCALE=y
+-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
+-#
+-# CONFIG_ARM_THUMB is not set
+-CONFIG_XSCALE_PMU=y
+-
+-#
+-# Bus support
+-#
+-CONFIG_PCI=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+-# CONFIG_XIP_KERNEL is not set
+-
+-#
+-# Floating point emulation
+-#
+-
+-#
+-# At least one emulation must be selected
+-#
+-CONFIG_FPE_NWFPE=y
+-# CONFIG_FPE_NWFPE_XP 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=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-CONFIG_MTD_PARTITIONS=y
+-CONFIG_MTD_REDBOOT_PARTS=y
+-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+-# CONFIG_MTD_CMDLINE_PARTS is not set
+-# CONFIG_MTD_AFS_PARTS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-CONFIG_MTD_CFI_ADV_OPTIONS=y
+-CONFIG_MTD_CFI_NOSWAP=y
+-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+-# CONFIG_MTD_CFI_GEOMETRY is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=0xc0000000
+-CONFIG_MTD_PHYSMAP_LEN=0x00800000
+-CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_PMC551 is not set
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_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=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=8192
+-# CONFIG_BLK_DEV_INITRD is not set
+-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=y
+-CONFIG_SCSI_PROC_FS=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-# CONFIG_CHR_DEV_ST is not set
+-# CONFIG_CHR_DEV_OSST is not set
+-# CONFIG_BLK_DEV_SR is not set
+-CONFIG_CHR_DEV_SG=y
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-# CONFIG_SCSI_MULTI_LUN is not set
+-# CONFIG_SCSI_CONSTANTS is not set
+-# CONFIG_SCSI_LOGGING is not set
+-
+-#
+-# SCSI Transport Attributes
+-#
+-# CONFIG_SCSI_SPI_ATTRS is not set
+-# CONFIG_SCSI_FC_ATTRS is not set
+-# CONFIG_SCSI_ISCSI_ATTRS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+-# CONFIG_SCSI_3W_9XXX is not set
+-# CONFIG_SCSI_ACARD is not set
+-# CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
+-# CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_DPT_I2O is not set
+-# CONFIG_MEGARAID_NEWGEN is not set
+-# CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_BUSLOGIC is not set
+-# CONFIG_SCSI_DMX3191D is not set
+-# CONFIG_SCSI_EATA is not set
+-# CONFIG_SCSI_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
+-# CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+-# CONFIG_SCSI_QLOGIC_1280 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
+-# CONFIG_SCSI_DC395x is not set
+-# CONFIG_SCSI_DC390T is not set
+-# CONFIG_SCSI_NSP32 is not set
+-# CONFIG_SCSI_DEBUG is not set
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-CONFIG_MD=y
+-CONFIG_BLK_DEV_MD=y
+-CONFIG_MD_LINEAR=y
+-CONFIG_MD_RAID0=y
+-CONFIG_MD_RAID1=y
+-# CONFIG_MD_RAID10 is not set
+-CONFIG_MD_RAID5=y
+-# CONFIG_MD_RAID6 is not set
+-# CONFIG_MD_MULTIPATH is not set
+-# CONFIG_MD_FAULTY is not set
+-CONFIG_BLK_DEV_DM=y
+-# CONFIG_DM_CRYPT is not set
+-# CONFIG_DM_SNAPSHOT is not set
+-# CONFIG_DM_MIRROR is not set
+-# CONFIG_DM_ZERO is not set
+-# CONFIG_DM_MULTIPATH 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=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=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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
+-
+-#
+-# ARCnet devices
+-#
+-# CONFIG_ARCNET is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-# CONFIG_NET_ETHERNET is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-CONFIG_E1000=y
+-CONFIG_E1000_NAPI=y
+-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-# CONFIG_R8169 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_TIGON3 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# 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 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
+-
+-#
+-# Hardware I/O ports
+-#
+-# CONFIG_SERIO 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=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_NVRAM is not set
+-# CONFIG_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=y
+-CONFIG_I2C_CHARDEV=y
+-
+-#
+-# I2C Algorithms
+-#
+-# CONFIG_I2C_ALGOBIT is not set
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-CONFIG_I2C_IOP3XX=y
+-# CONFIG_I2C_ISA 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
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Hardware Sensors Chip support
+-#
+-# CONFIG_I2C_SENSOR is not set
+-# CONFIG_SENSORS_ADM1021 is not set
+-# CONFIG_SENSORS_ADM1025 is not set
+-# CONFIG_SENSORS_ADM1026 is not set
+-# CONFIG_SENSORS_ADM1031 is not set
+-# CONFIG_SENSORS_ASB100 is not set
+-# CONFIG_SENSORS_DS1621 is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_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
+-# CONFIG_SENSORS_LM77 is not set
+-# CONFIG_SENSORS_LM78 is not set
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-# CONFIG_SENSORS_LM85 is not set
+-# CONFIG_SENSORS_LM87 is not set
+-# CONFIG_SENSORS_LM90 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
+-
+-#
+-# Other I2C Chip support
+-#
+-# CONFIG_SENSORS_EEPROM is not set
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_RTC8564 is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
+-
+-#
+-# 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
+-
+-#
+-# 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
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-CONFIG_EXT3_FS=y
+-CONFIG_EXT3_FS_XATTR=y
+-# CONFIG_EXT3_FS_POSIX_ACL is not set
+-# CONFIG_EXT3_FS_SECURITY is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
+-CONFIG_XFS_FS=y
+-CONFIG_XFS_EXPORT=y
+-# CONFIG_XFS_RT is not set
+-# CONFIG_XFS_QUOTA is not set
+-CONFIG_XFS_SECURITY=y
+-CONFIG_XFS_POSIX_ACL=y
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-# CONFIG_QUOTA is not set
+-CONFIG_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_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
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_JFFS_FS is not set
+-# CONFIG_JFFS2_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=y
+-CONFIG_NFSD_V3=y
+-# CONFIG_NFSD_V4 is not set
+-# CONFIG_NFSD_TCP is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
+-CONFIG_SUNRPC=y
+-# CONFIG_RPCSEC_GSS_KRB5 is not set
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# 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
+-
+-#
+-# 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=y
+-
+-#
+-# 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/arm/configs/iq80332_defconfig b/arch/arm/configs/iq80332_defconfig
+deleted file mode 100644
+index 11959b7..0000000
+--- a/arch/arm/configs/iq80332_defconfig
++++ /dev/null
+@@ -1,916 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 17:33:39 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=y
+-# CONFIG_BSD_PROCESS_ACCT_V3 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 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=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
+-
+-#
+-# 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_FOOTBRIDGE is not set
+-# CONFIG_ARCH_INTEGRATOR is not set
+-CONFIG_ARCH_IOP3XX=y
+-# 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 is not set
+-# 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
+-
+-#
+-# IOP3xx Implementation Options
+-#
+-
+-#
+-# IOP3xx Platform Types
+-#
+-# CONFIG_ARCH_IQ80321 is not set
+-# CONFIG_ARCH_IQ31244 is not set
+-# CONFIG_ARCH_IQ80331 is not set
+-CONFIG_MACH_IQ80332=y
+-# CONFIG_ARCH_EP80219 is not set
+-CONFIG_ARCH_IOP331=y
+-
+-#
+-# IOP3xx Chipset Features
+-#
+-# CONFIG_IOP331_STEPD is not set
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_XSCALE=y
+-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
+-#
+-# CONFIG_ARM_THUMB is not set
+-CONFIG_XSCALE_PMU=y
+-
+-#
+-# Bus support
+-#
+-CONFIG_PCI=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+-# CONFIG_XIP_KERNEL is not set
+-
+-#
+-# Floating point emulation
+-#
+-
+-#
+-# At least one emulation must be selected
+-#
+-CONFIG_FPE_NWFPE=y
+-# CONFIG_FPE_NWFPE_XP 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=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-CONFIG_MTD_PARTITIONS=y
+-CONFIG_MTD_REDBOOT_PARTS=y
+-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+-# CONFIG_MTD_CMDLINE_PARTS is not set
+-# CONFIG_MTD_AFS_PARTS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-CONFIG_MTD_CFI_ADV_OPTIONS=y
+-CONFIG_MTD_CFI_NOSWAP=y
+-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+-# CONFIG_MTD_CFI_GEOMETRY is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=0xc0000000
+-CONFIG_MTD_PHYSMAP_LEN=0x00800000
+-CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_PMC551 is not set
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_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=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=8192
+-# CONFIG_BLK_DEV_INITRD is not set
+-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=y
+-CONFIG_SCSI_PROC_FS=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-# CONFIG_CHR_DEV_ST is not set
+-# CONFIG_CHR_DEV_OSST is not set
+-# CONFIG_BLK_DEV_SR is not set
+-CONFIG_CHR_DEV_SG=y
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-# CONFIG_SCSI_MULTI_LUN is not set
+-# CONFIG_SCSI_CONSTANTS is not set
+-# CONFIG_SCSI_LOGGING is not set
+-
+-#
+-# SCSI Transport Attributes
+-#
+-# CONFIG_SCSI_SPI_ATTRS is not set
+-# CONFIG_SCSI_FC_ATTRS is not set
+-# CONFIG_SCSI_ISCSI_ATTRS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+-# CONFIG_SCSI_3W_9XXX is not set
+-# CONFIG_SCSI_ACARD is not set
+-# CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
+-# CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_DPT_I2O is not set
+-# CONFIG_MEGARAID_NEWGEN is not set
+-# CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_BUSLOGIC is not set
+-# CONFIG_SCSI_DMX3191D is not set
+-# CONFIG_SCSI_EATA is not set
+-# CONFIG_SCSI_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
+-# CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+-# CONFIG_SCSI_QLOGIC_1280 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
+-# CONFIG_SCSI_DC395x is not set
+-# CONFIG_SCSI_DC390T is not set
+-# CONFIG_SCSI_NSP32 is not set
+-# CONFIG_SCSI_DEBUG is not set
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-CONFIG_MD=y
+-CONFIG_BLK_DEV_MD=y
+-CONFIG_MD_LINEAR=y
+-CONFIG_MD_RAID0=y
+-CONFIG_MD_RAID1=y
+-# CONFIG_MD_RAID10 is not set
+-CONFIG_MD_RAID5=y
+-# CONFIG_MD_RAID6 is not set
+-# CONFIG_MD_MULTIPATH is not set
+-# CONFIG_MD_FAULTY is not set
+-CONFIG_BLK_DEV_DM=y
+-# CONFIG_DM_CRYPT is not set
+-# CONFIG_DM_SNAPSHOT is not set
+-# CONFIG_DM_MIRROR is not set
+-# CONFIG_DM_ZERO is not set
+-# CONFIG_DM_MULTIPATH 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=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=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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
+-
+-#
+-# ARCnet devices
+-#
+-# CONFIG_ARCNET is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-# CONFIG_NET_ETHERNET is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-CONFIG_E1000=y
+-CONFIG_E1000_NAPI=y
+-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-# CONFIG_R8169 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_TIGON3 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# 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 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
+-
+-#
+-# Hardware I/O ports
+-#
+-# CONFIG_SERIO 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=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_NVRAM is not set
+-# CONFIG_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=y
+-CONFIG_I2C_CHARDEV=y
+-
+-#
+-# I2C Algorithms
+-#
+-# CONFIG_I2C_ALGOBIT is not set
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-CONFIG_I2C_IOP3XX=y
+-# CONFIG_I2C_ISA 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
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Hardware Sensors Chip support
+-#
+-# CONFIG_I2C_SENSOR is not set
+-# CONFIG_SENSORS_ADM1021 is not set
+-# CONFIG_SENSORS_ADM1025 is not set
+-# CONFIG_SENSORS_ADM1026 is not set
+-# CONFIG_SENSORS_ADM1031 is not set
+-# CONFIG_SENSORS_ASB100 is not set
+-# CONFIG_SENSORS_DS1621 is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_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
+-# CONFIG_SENSORS_LM77 is not set
+-# CONFIG_SENSORS_LM78 is not set
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-# CONFIG_SENSORS_LM85 is not set
+-# CONFIG_SENSORS_LM87 is not set
+-# CONFIG_SENSORS_LM90 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
+-
+-#
+-# Other I2C Chip support
+-#
+-# CONFIG_SENSORS_EEPROM is not set
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_RTC8564 is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
+-
+-#
+-# 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
+-
+-#
+-# 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
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-CONFIG_EXT3_FS=y
+-CONFIG_EXT3_FS_XATTR=y
+-# CONFIG_EXT3_FS_POSIX_ACL is not set
+-# CONFIG_EXT3_FS_SECURITY is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
+-CONFIG_XFS_FS=y
+-CONFIG_XFS_EXPORT=y
+-# CONFIG_XFS_RT is not set
+-# CONFIG_XFS_QUOTA is not set
+-CONFIG_XFS_SECURITY=y
+-CONFIG_XFS_POSIX_ACL=y
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-# CONFIG_QUOTA is not set
+-CONFIG_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_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
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_JFFS_FS is not set
+-# CONFIG_JFFS2_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=y
+-CONFIG_NFSD_V3=y
+-# CONFIG_NFSD_V4 is not set
+-# CONFIG_NFSD_TCP is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
+-CONFIG_SUNRPC=y
+-# CONFIG_RPCSEC_GSS_KRB5 is not set
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# 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
+-
+-#
+-# 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=y
+-
+-#
+-# 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/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig
+index 1db633e..a4cdafc 100644
+--- a/arch/arm/configs/kafa_defconfig
++++ b/arch/arm/configs/kafa_defconfig
+@@ -536,9 +536,9 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+@@ -560,7 +560,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
+ # Watchdog Device Drivers
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_AT91_WATCHDOG=y
++CONFIG_AT91RM9200_WATCHDOG=y
+ # CONFIG_NVRAM is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+diff --git a/arch/arm/configs/kb9202_defconfig b/arch/arm/configs/kb9202_defconfig
+index 45396e0..b4cd4b4 100644
+--- a/arch/arm/configs/kb9202_defconfig
++++ b/arch/arm/configs/kb9202_defconfig
+@@ -418,8 +418,8 @@ CONFIG_HW_CONSOLE=y
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig
+index 6a93e3a..9b9f215 100644
+--- a/arch/arm/configs/onearm_defconfig
++++ b/arch/arm/configs/onearm_defconfig
+@@ -583,9 +583,9 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ #
+ # Non-8250 serial port support
+ #
+-CONFIG_SERIAL_AT91=y
+-CONFIG_SERIAL_AT91_CONSOLE=y
+-# CONFIG_SERIAL_AT91_TTYAT is not set
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+@@ -607,7 +607,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
+ # Watchdog Device Drivers
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+-CONFIG_AT91_WATCHDOG=y
++CONFIG_AT91RM9200_WATCHDOG=y
+
+ #
+ # USB-based Watchdog Cards
+diff --git a/arch/arm/configs/realview-smp_defconfig b/arch/arm/configs/realview-smp_defconfig
+new file mode 100644
+index 0000000..ffd905f
+--- /dev/null
++++ b/arch/arm/configs/realview-smp_defconfig
+@@ -0,0 +1,994 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.19-rc3
++# Wed Oct 25 14:12:00 2006
++#
++CONFIG_ARM=y
++# CONFIG_GENERIC_TIME is not set
++CONFIG_MMU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_CPUSETS is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++CONFIG_STOP_MACHINE=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_BLK_DEV_IO_TRACE is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_AS is not set
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++# CONFIG_DEFAULT_AS is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++CONFIG_ARCH_REALVIEW=y
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# 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_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_OMAP is not set
++
++#
++# RealView platform type
++#
++CONFIG_MACH_REALVIEW_EB=y
++CONFIG_REALVIEW_MPCORE=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_CACHE_V6=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V6=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_HAS_TLS_REG=y
++CONFIG_ARM_GIC=y
++CONFIG_ICST307=y
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_SMP=y
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++CONFIG_LOCAL_TIMERS=y
++# CONFIG_PREEMPT is not set
++# CONFIG_NO_IDLE_HZ is not set
++CONFIG_HZ=100
++# CONFIG_AEABI 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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
++# CONFIG_XIP_KERNEL is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_ARTHUR is not set
++
++#
++# Power management options
++#
++# CONFIG_PM is not set
++# CONFIG_APM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++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_FIB_HASH=y
++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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PHYSMAP is not set
++CONFIG_MTD_ARM_INTEGRATOR=y
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# 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_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK 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
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++CONFIG_SMC91X=y
++# CONFIG_DM9000 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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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_KEYBOARD_STOWAWAY is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++# CONFIG_SERIO_SERPORT is not set
++CONFIG_SERIO_AMBAKMI=y
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=16
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
++
++#
++# Misc devices
++#
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB=y
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++CONFIG_FB_ARMCLCD=y
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
++# CONFIG_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++
++#
++# Logo configuration
++#
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++
++#
++# Advanced Linux Sound Architecture
++#
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++
++#
++# Generic devices
++#
++CONFIG_SND_AC97_CODEC=m
++CONFIG_SND_AC97_BUS=m
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++
++#
++# ALSA ARM devices
++#
++CONFIG_SND_ARMAACI=m
++
++#
++# Open Sound System
++#
++# CONFIG_SOUND_PRIME is not set
++
++#
++# USB support
++#
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++# CONFIG_USB is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_ARMMMCI=y
++# CONFIG_MMC_TIFM_SD is not set
++
++#
++# Real Time Clock
++#
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++CONFIG_RTC_INTF_DEV_UIE_EMUL=y
++
++#
++# RTC drivers
++#
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++CONFIG_RTC_DRV_PL031=y
++# CONFIG_RTC_DRV_TEST is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# File systems
++#
++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_EXT4DEV_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++# CONFIG_INOTIFY_USER is not set
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++CONFIG_CRAMFS=y
++# 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_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
++# 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
++# CONFIG_9P_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=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS 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_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_MUTEXES=y
++CONFIG_DEBUG_RWSEMS=y
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
++CONFIG_FORCED_INLINING=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++# CONFIG_CRYPTO is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
+index f20814e..0563c14 100644
+--- a/arch/arm/configs/s3c2410_defconfig
++++ b/arch/arm/configs/s3c2410_defconfig
+@@ -1,14 +1,20 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.17-git9
+-# Sun Jun 25 23:56:32 2006
++# Linux kernel version: 2.6.19-rc4
++# Fri Nov 3 17:41:31 2006
+ #
+ CONFIG_ARM=y
++# CONFIG_GENERIC_TIME is not set
+ CONFIG_MMU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+@@ -24,16 +30,20 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_UID16=y
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -46,6 +56,8 @@ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -54,7 +66,8 @@ CONFIG_BASE_SMALL=0
+ # Loadable module support
+ #
+ CONFIG_MODULES=y
+-# CONFIG_MODULE_UNLOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+@@ -62,6 +75,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -84,7 +98,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ # CONFIG_ARCH_INTEGRATOR is not set
+ # CONFIG_ARCH_REALVIEW is not set
+ # CONFIG_ARCH_VERSATILE is not set
+-# CONFIG_ARCH_AT91RM9200 is not set
++# CONFIG_ARCH_AT91 is not set
+ # CONFIG_ARCH_CLPS7500 is not set
+ # CONFIG_ARCH_CLPS711X is not set
+ # CONFIG_ARCH_CO285 is not set
+@@ -94,7 +108,8 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ # CONFIG_ARCH_NETX is not set
+ # CONFIG_ARCH_H720X is not set
+ # CONFIG_ARCH_IMX is not set
+-# CONFIG_ARCH_IOP3XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
+ # CONFIG_ARCH_IXP4XX is not set
+ # CONFIG_ARCH_IXP2000 is not set
+ # CONFIG_ARCH_IXP23XX is not set
+@@ -111,6 +126,7 @@ CONFIG_ARCH_S3C2410=y
+ #
+ # S3C24XX Implementations
+ #
++# CONFIG_MACH_AML_M5900 is not set
+ CONFIG_MACH_ANUBIS=y
+ CONFIG_MACH_OSIRIS=y
+ CONFIG_ARCH_BAST=y
+@@ -122,13 +138,18 @@ CONFIG_ARCH_SMDK2410=y
+ CONFIG_ARCH_S3C2440=y
+ CONFIG_SMDK2440_CPU2440=y
+ CONFIG_SMDK2440_CPU2442=y
++CONFIG_MACH_S3C2413=y
+ CONFIG_MACH_SMDK2413=y
+ CONFIG_MACH_VR1000=y
+ CONFIG_MACH_RX3715=y
+ CONFIG_MACH_OTOM=y
+ CONFIG_MACH_NEXCODER_2440=y
++CONFIG_MACH_VSTMS=y
+ CONFIG_S3C2410_CLOCK=y
++CONFIG_S3C2410_PM=y
++CONFIG_CPU_S3C2410_DMA=y
+ CONFIG_CPU_S3C2410=y
++CONFIG_S3C2412_PM=y
+ CONFIG_CPU_S3C2412=y
+ CONFIG_CPU_S3C244X=y
+ CONFIG_CPU_S3C2440=y
+@@ -156,7 +177,7 @@ CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+ CONFIG_CPU_32=y
+ CONFIG_CPU_ARM920T=y
+ CONFIG_CPU_ARM926T=y
+-CONFIG_CPU_32v4=y
++CONFIG_CPU_32v4T=y
+ CONFIG_CPU_32v5=y
+ CONFIG_CPU_ABRT_EV4T=y
+ CONFIG_CPU_ABRT_EV5TJ=y
+@@ -164,6 +185,8 @@ CONFIG_CPU_CACHE_V4WT=y
+ CONFIG_CPU_CACHE_VIVT=y
+ CONFIG_CPU_COPY_V4WB=y
+ CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
+
+ #
+ # Processor Features
+@@ -200,6 +223,7 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
+ CONFIG_ALIGNMENT_TRAP=y
+
+ #
+@@ -236,6 +260,7 @@ CONFIG_BINFMT_AOUT=y
+ CONFIG_PM=y
+ CONFIG_PM_LEGACY=y
+ # CONFIG_PM_DEBUG is not set
++# CONFIG_PM_SYSFS_DEPRECATED is not set
+ CONFIG_APM=y
+
+ #
+@@ -251,6 +276,7 @@ CONFIG_NET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ # CONFIG_IP_MULTICAST is not set
+@@ -271,10 +297,12 @@ CONFIG_IP_PNP_BOOTP=y
+ # CONFIG_INET_TUNNEL is not set
+ CONFIG_INET_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_IPV6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+@@ -304,7 +332,6 @@ CONFIG_TCP_CONG_BIC=y
+ # 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
+
+@@ -363,6 +390,7 @@ CONFIG_MTD_BLOCK=y
+ # CONFIG_NFTL is not set
+ # CONFIG_INFTL is not set
+ # CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
+
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -404,6 +432,8 @@ CONFIG_MTD_BAST_MAXSIZE=4
+ #
+ # Self-contained MTD device drivers
+ #
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_PHRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+@@ -460,6 +490,7 @@ CONFIG_BLK_DEV_NBD=m
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ CONFIG_ATA_OVER_ETH=m
+@@ -497,6 +528,7 @@ CONFIG_BLK_DEV_IDE_BAST=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -591,6 +623,7 @@ CONFIG_DM9000=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -613,6 +646,7 @@ CONFIG_KEYBOARD_ATKBD=y
+ # CONFIG_KEYBOARD_LKKBD is not set
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ # CONFIG_MOUSE_SERIAL is not set
+@@ -640,6 +674,7 @@ CONFIG_SERIO_LIBPS2=y
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ CONFIG_SERIAL_NONSTANDARD=y
+ # CONFIG_COMPUTONE is not set
+ # CONFIG_ROCKETPORT is not set
+@@ -716,8 +751,8 @@ CONFIG_S3C2410_WATCHDOG=y
+ # USB-based Watchdog Cards
+ #
+ # CONFIG_USBPCWATCHDOG is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_NVRAM is not set
+-CONFIG_S3C2410_RTC=y
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+
+@@ -730,7 +765,6 @@ CONFIG_S3C2410_RTC=y
+ # TPM devices
+ #
+ # CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+
+ #
+ # I2C support
+@@ -775,12 +809,26 @@ CONFIG_SENSORS_EEPROM=m
+ #
+ # SPI support
+ #
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++CONFIG_SPI_BITBANG=m
++# CONFIG_SPI_BUTTERFLY is not set
++CONFIG_SPI_S3C24XX_GPIO=m
++CONFIG_SPI_S3C24XX=m
++
++#
++# SPI Protocol Masters
++#
+
+ #
+ # Dallas's 1-wire bus
+ #
++# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -803,6 +851,7 @@ CONFIG_HWMON_VID=m
+ # CONFIG_SENSORS_GL520SM is not set
+ # CONFIG_SENSORS_IT87 is not set
+ # CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
+ CONFIG_SENSORS_LM75=m
+ # CONFIG_SENSORS_LM77 is not set
+ CONFIG_SENSORS_LM78=m
+@@ -817,6 +866,7 @@ CONFIG_SENSORS_LM85=m
+ # CONFIG_SENSORS_SMSC47M1 is not set
+ # CONFIG_SENSORS_SMSC47M192 is not set
+ # CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_SENSORS_W83781D is not set
+ # CONFIG_SENSORS_W83791D is not set
+ # CONFIG_SENSORS_W83792D is not set
+@@ -828,25 +878,31 @@ CONFIG_SENSORS_LM85=m
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # LED devices
+ #
+-# CONFIG_NEW_LEDS is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=m
+
+ #
+ # LED drivers
+ #
++CONFIG_LEDS_S3C24XX=m
+
+ #
+ # LED Triggers
+ #
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=m
++# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
++CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -857,12 +913,13 @@ CONFIG_VIDEO_V4L2=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ CONFIG_FB=y
++# CONFIG_FB_DDC is not set
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_MACMODES is not set
+-CONFIG_FB_FIRMWARE_EDID=y
+ # CONFIG_FB_BACKLIGHT is not set
+ CONFIG_FB_MODE_HELPERS=y
+ # CONFIG_FB_TILEBLITTING is not set
+@@ -934,7 +991,6 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+ #
+ # may also be needed; see USB_STORAGE Help for more information
+ #
+-# CONFIG_USB_STORAGE is not set
+ # CONFIG_USB_LIBUSUAL is not set
+
+ #
+@@ -990,18 +1046,20 @@ CONFIG_USB_MON=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
+-# CONFIG_USB_CY7C63 is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
+ # CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+ # CONFIG_USB_TEST is not set
+
+ #
+@@ -1022,7 +1080,37 @@ CONFIG_USB_MON=y
+ # Real Time Clock
+ #
+ CONFIG_RTC_LIB=y
+-# CONFIG_RTC_CLASS is not set
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++
++#
++# RTC drivers
++#
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++CONFIG_RTC_DRV_S3C=y
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_TEST is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_V3020 is not set
+
+ #
+ # File systems
+@@ -1034,6 +1122,7 @@ 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_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+@@ -1041,6 +1130,7 @@ CONFIG_FS_MBCACHE=y
+ # CONFIG_JFS_FS is not set
+ # CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ CONFIG_ROMFS_FS=y
+@@ -1072,6 +1162,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ # Pseudo filesystems
+ #
+ CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ # CONFIG_TMPFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+@@ -1095,6 +1186,7 @@ CONFIG_JFFS2_FS=y
+ CONFIG_JFFS2_FS_DEBUG=0
+ CONFIG_JFFS2_FS_WRITEBUFFER=y
+ # CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
+ # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+ CONFIG_JFFS2_ZLIB=y
+ CONFIG_JFFS2_RTIME=y
+@@ -1201,23 +1293,30 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=16
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+-CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ CONFIG_DEBUG_BUGVERBOSE=y
+ CONFIG_DEBUG_INFO=y
+ # CONFIG_DEBUG_FS is not set
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ CONFIG_FRAME_POINTER=y
+-# CONFIG_UNWIND_INFO is not set
+ CONFIG_FORCED_INLINING=y
++# CONFIG_HEADERS_CHECK is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_DEBUG_USER=y
+ # CONFIG_DEBUG_WAITQ is not set
+@@ -1239,10 +1338,6 @@ CONFIG_DEBUG_S3C2410_UART=0
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+@@ -1251,3 +1346,4 @@ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/arm/configs/smdk2410_defconfig b/arch/arm/configs/smdk2410_defconfig
+deleted file mode 100644
+index 4d123d3..0000000
+--- a/arch/arm/configs/smdk2410_defconfig
++++ /dev/null
+@@ -1,735 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.12-rc1-bk2
+-# Sun Mar 27 22:42:40 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 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_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 is not set
+-
+-#
+-# 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_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 is not set
+-CONFIG_ARCH_S3C2410=y
+-# 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
+-
+-#
+-# S3C24XX Implementations
+-#
+-# CONFIG_ARCH_BAST is not set
+-# CONFIG_ARCH_H1940 is not set
+-# CONFIG_MACH_N30 is not set
+-CONFIG_ARCH_SMDK2410=y
+-# CONFIG_ARCH_S3C2440 is not set
+-# CONFIG_MACH_VR1000 is not set
+-# CONFIG_MACH_RX3715 is not set
+-# CONFIG_MACH_OTOM is not set
+-# CONFIG_MACH_NEXCODER_2440 is not set
+-CONFIG_CPU_S3C2410=y
+-
+-#
+-# S3C2410 Boot
+-#
+-
+-#
+-# S3C2410 Setup
+-#
+-# CONFIG_S3C2410_DMA is not set
+-CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+-
+-#
+-# Processor Type
+-#
+-CONFIG_CPU_32=y
+-CONFIG_CPU_ARM920T=y
+-CONFIG_CPU_32v4=y
+-CONFIG_CPU_ABRT_EV4T=y
+-CONFIG_CPU_CACHE_V4WT=y
+-CONFIG_CPU_CACHE_VIVT=y
+-CONFIG_CPU_COPY_V4WB=y
+-CONFIG_CPU_TLB_V4WBI=y
+-
+-#
+-# Processor Features
+-#
+-CONFIG_ARM_THUMB=y
+-# CONFIG_CPU_ICACHE_DISABLE is not set
+-# CONFIG_CPU_DCACHE_DISABLE is not set
+-# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+-
+-#
+-# Bus support
+-#
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# Kernel Features
+-#
+-# CONFIG_PREEMPT is not set
+-CONFIG_ALIGNMENT_TRAP=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZBOOT_ROM_TEXT=0x0
+-CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="root=1f04 mem=32M"
+-# CONFIG_XIP_KERNEL 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
+-# CONFIG_DEBUG_DRIVER is not set
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-CONFIG_MTD=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-# CONFIG_MTD_PARTITIONS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-CONFIG_MTD_BLOCK=y
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_XIP is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-# CONFIG_MTD_PHYSMAP is not set
+-# CONFIG_MTD_ARM_INTEGRATOR is not set
+-# CONFIG_MTD_EDB7312 is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-# CONFIG_BLK_DEV_LOOP is not set
+-# CONFIG_BLK_DEV_NBD is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-# CONFIG_BLK_DEV_INITRD is not set
+-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
+-#
+-
+-#
+-# I2O device support
+-#
+-
+-#
+-# Networking support
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-# CONFIG_PACKET is not set
+-# CONFIG_NETLINK_DEV is not set
+-CONFIG_UNIX=y
+-# CONFIG_NET_KEY is not set
+-CONFIG_INET=y
+-# CONFIG_IP_MULTICAST is not set
+-# CONFIG_IP_ADVANCED_ROUTER is not set
+-CONFIG_IP_PNP=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_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_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_SMC91X 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
+-
+-#
+-# 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_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_S3C2410=y
+-CONFIG_SERIAL_S3C2410_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_S3C2410_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
+-
+-#
+-# 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_VIRTUAL=y
+-
+-#
+-# Console display driver support
+-#
+-# CONFIG_VGA_CONSOLE is not set
+-CONFIG_DUMMY_CONSOLE=y
+-CONFIG_FRAMEBUFFER_CONSOLE=y
+-# CONFIG_FONTS is not set
+-CONFIG_FONT_8x8=y
+-CONFIG_FONT_8x16=y
+-
+-#
+-# Logo configuration
+-#
+-# CONFIG_LOGO 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=y
+-# 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_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_JFFS_FS is not set
+-# CONFIG_JFFS2_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 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
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING 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_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_BUGVERBOSE=y
+-# CONFIG_DEBUG_INFO is not set
+-# CONFIG_DEBUG_FS is not set
+-CONFIG_FRAME_POINTER=y
+-CONFIG_DEBUG_USER=y
+-# CONFIG_DEBUG_WAITQ is not set
+-# CONFIG_DEBUG_ERRORS is not set
+-CONFIG_DEBUG_LL=y
+-# CONFIG_DEBUG_ICEDCC is not set
+-CONFIG_DEBUG_S3C2410_PORT=y
+-CONFIG_DEBUG_S3C2410_UART=0
+-
+-#
+-# 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=y
+diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c
+index 33c5568..ecf4f94 100644
+--- a/arch/arm/kernel/apm.c
++++ b/arch/arm/kernel/apm.c
+@@ -25,6 +25,7 @@
+ #include <linux/list.h>
+ #include <linux/init.h>
+ #include <linux/completion.h>
++#include <linux/kthread.h>
+
+ #include <asm/apm.h> /* apm_power_info */
+ #include <asm/system.h>
+@@ -80,7 +81,7 @@ struct apm_user {
+ */
+ static int suspends_pending;
+ static int apm_disabled;
+-static int arm_apm_active;
++static struct task_struct *kapmd_tsk;
+
+ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
+ static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+@@ -97,7 +98,6 @@ static LIST_HEAD(apm_user_list);
+ * to be suspending the system.
+ */
+ static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
+-static DECLARE_COMPLETION(kapmd_exit);
+ static DEFINE_SPINLOCK(kapmd_queue_lock);
+ static struct apm_queue kapmd_queue;
+
+@@ -468,16 +468,13 @@ static int apm_get_info(char *buf, char
+
+ static int kapmd(void *arg)
+ {
+- daemonize("kapmd");
+- current->flags |= PF_NOFREEZE;
+-
+ do {
+ apm_event_t event;
+
+ wait_event_interruptible(kapmd_wait,
+- !queue_empty(&kapmd_queue) || !arm_apm_active);
++ !queue_empty(&kapmd_queue) || kthread_should_stop());
+
+- if (!arm_apm_active)
++ if (kthread_should_stop())
+ break;
+
+ spin_lock_irq(&kapmd_queue_lock);
+@@ -508,7 +505,7 @@ static int kapmd(void *arg)
+ }
+ } while (1);
+
+- complete_and_exit(&kapmd_exit, 0);
++ return 0;
+ }
+
+ static int __init apm_init(void)
+@@ -520,13 +517,14 @@ static int __init apm_init(void)
+ return -ENODEV;
+ }
+
+- arm_apm_active = 1;
+-
+- ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
+- if (ret < 0) {
+- arm_apm_active = 0;
++ kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");
++ if (IS_ERR(kapmd_tsk)) {
++ ret = PTR_ERR(kapmd_tsk);
++ kapmd_tsk = NULL;
+ return ret;
+ }
++ kapmd_tsk->flags |= PF_NOFREEZE;
++ wake_up_process(kapmd_tsk);
+
+ #ifdef CONFIG_PROC_FS
+ create_proc_info_entry("apm", 0, NULL, apm_get_info);
+@@ -535,10 +533,7 @@ static int __init apm_init(void)
+ ret = misc_register(&apm_device);
+ if (ret != 0) {
+ remove_proc_entry("apm", NULL);
+-
+- arm_apm_active = 0;
+- wake_up(&kapmd_wait);
+- wait_for_completion(&kapmd_exit);
++ kthread_stop(kapmd_tsk);
+ }
+
+ return ret;
+@@ -549,9 +544,7 @@ static void __exit apm_exit(void)
+ misc_deregister(&apm_device);
+ remove_proc_entry("apm", NULL);
+
+- arm_apm_active = 0;
+- wake_up(&kapmd_wait);
+- wait_for_completion(&kapmd_exit);
++ kthread_stop(kapmd_tsk);
+ }
+
+ module_init(apm_init);
+diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
+index da69e66..4779f47 100644
+--- a/arch/arm/kernel/armksyms.c
++++ b/arch/arm/kernel/armksyms.c
+@@ -178,9 +178,3 @@ EXPORT_SYMBOL(_find_next_zero_bit_be);
+ EXPORT_SYMBOL(_find_first_bit_be);
+ EXPORT_SYMBOL(_find_next_bit_be);
+ #endif
+-
+- /* syscalls */
+-EXPORT_SYMBOL(sys_write);
+-EXPORT_SYMBOL(sys_lseek);
+-EXPORT_SYMBOL(sys_exit);
+-EXPORT_SYMBOL(sys_wait4);
+diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
+index 7481759..cec8378 100644
+--- a/arch/arm/kernel/crunch.c
++++ b/arch/arm/kernel/crunch.c
+@@ -10,7 +10,6 @@
+ */
+
+ #include <linux/module.h>
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/signal.h>
+diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
+index a5747e5..5617566 100644
+--- a/arch/arm/kernel/debug.S
++++ b/arch/arm/kernel/debug.S
+@@ -21,6 +21,36 @@
+
+ #if defined(CONFIG_DEBUG_ICEDCC)
+ @@ debug using ARM EmbeddedICE DCC channel
++
++#if defined(CONFIG_CPU_V6)
++
++ .macro addruart, rx
++ .endm
++
++ .macro senduart, rd, rx
++ mcr p14, 0, \rd, c0, c5, 0
++ .endm
++
++ .macro busyuart, rd, rx
++1001:
++ mrc p14, 0, \rx, c0, c1, 0
++ tst \rx, #0x20000000
++ beq 1001b
++ .endm
++
++ .macro waituart, rd, rx
++ mov \rd, #0x2000000
++1001:
++ subs \rd, \rd, #1
++ bmi 1002f
++ mrc p14, 0, \rx, c0, c1, 0
++ tst \rx, #0x20000000
++ bne 1001b
++1002:
++ .endm
++
++#else
++
+ .macro addruart, rx
+ .endm
+
+@@ -46,9 +76,12 @@
+ bne 1001b
+ 1002:
+ .endm
++
++#endif /* CONFIG_CPU_V6 */
++
+ #else
+ #include <asm/arch/debug-macro.S>
+-#endif
++#endif /* CONFIG_DEBUG_ICEDCC */
+
+ /*
+ * Useful debugging routines
+diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
+index eca248d..b27513a 100644
+--- a/arch/arm/kernel/ecard.c
++++ b/arch/arm/kernel/ecard.c
+@@ -295,7 +295,7 @@ ecard_task(void * unused)
+ */
+ static void ecard_call(struct ecard_request *req)
+ {
+- DECLARE_COMPLETION(completion);
++ DECLARE_COMPLETION_ONSTACK(completion);
+
+ req->complete = &completion;
+
+@@ -567,7 +567,7 @@ static void ecard_check_lockup(struct ir
+ }
+
+ static void
+-ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++ecard_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ ecard_t *ec;
+ int called = 0;
+@@ -586,7 +586,7 @@ ecard_irq_handler(unsigned int irq, stru
+
+ if (pending) {
+ struct irqdesc *d = irq_desc + ec->irq;
+- desc_handle_irq(ec->irq, d, regs);
++ desc_handle_irq(ec->irq, d);
+ called ++;
+ }
+ }
+@@ -609,7 +609,7 @@ static unsigned char first_set[] =
+ };
+
+ static void
+-ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ const unsigned int statusmask = 15;
+ unsigned int status;
+@@ -633,7 +633,7 @@ ecard_irqexp_handler(unsigned int irq, s
+ * Serial cards should go in 0/1, ethernet/scsi in 2/3
+ * otherwise you will lose serial data at high speeds!
+ */
+- desc_handle_irq(ec->irq, d, regs);
++ desc_handle_irq(ec->irq, d);
+ } else {
+ printk(KERN_WARNING "card%d: interrupt from unclaimed "
+ "card???\n", slot);
+diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
+index de4e331..bd623b7 100644
+--- a/arch/arm/kernel/entry-armv.S
++++ b/arch/arm/kernel/entry-armv.S
+@@ -191,6 +191,9 @@ __dabt_svc:
+ __irq_svc:
+ svc_entry
+
++#ifdef CONFIG_TRACE_IRQFLAGS
++ bl trace_hardirqs_off
++#endif
+ #ifdef CONFIG_PREEMPT
+ get_thread_info tsk
+ ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
+@@ -211,6 +214,10 @@ preempt_return:
+ #endif
+ ldr r0, [sp, #S_PSR] @ irqs are already disabled
+ msr spsr_cxsf, r0
++#ifdef CONFIG_TRACE_IRQFLAGS
++ tst r0, #PSR_I_BIT
++ bleq trace_hardirqs_on
++#endif
+ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+
+ .ltorg
+@@ -398,6 +405,9 @@ __dabt_usr:
+ __irq_usr:
+ usr_entry
+
++#ifdef CONFIG_TRACE_IRQFLAGS
++ bl trace_hardirqs_off
++#endif
+ get_thread_info tsk
+ #ifdef CONFIG_PREEMPT
+ ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
+@@ -412,6 +422,9 @@ __irq_usr:
+ teq r0, r7
+ strne r0, [r0, -r0]
+ #endif
++#ifdef CONFIG_TRACE_IRQFLAGS
++ bl trace_hardirqs_on
++#endif
+
+ mov why, #0
+ b ret_to_user
+diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
+index ac9eb3d..f359a18 100644
+--- a/arch/arm/kernel/head-nommu.S
++++ b/arch/arm/kernel/head-nommu.S
+@@ -9,7 +9,6 @@
+ * published by the Free Software Foundation.
+ *
+ * Common kernel startup code (non-paged MM)
+- * for 32-bit CPUs which has a process ID register(CP15).
+ *
+ */
+ #include <linux/linkage.h>
+@@ -40,7 +39,11 @@
+ ENTRY(stext)
+ msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
+ @ and irqs disabled
++#ifndef CONFIG_CPU_CP15
++ ldr r9, =CONFIG_PROCESSOR_ID
++#else
+ mrc p15, 0, r9, c0, c0 @ get processor id
++#endif
+ bl __lookup_processor_type @ r5=procinfo r9=cpuid
+ movs r10, r5 @ invalid processor (r5=0)?
+ beq __error_p @ yes, error 'p'
+@@ -58,6 +61,7 @@ ENTRY(stext)
+ */
+ .type __after_proc_init, %function
+ __after_proc_init:
++#ifdef CONFIG_CPU_CP15
+ mrc p15, 0, r0, c1, c0, 0 @ read control reg
+ #ifdef CONFIG_ALIGNMENT_TRAP
+ orr r0, r0, #CR_A
+@@ -73,7 +77,13 @@ __after_proc_init:
+ #ifdef CONFIG_CPU_ICACHE_DISABLE
+ bic r0, r0, #CR_I
+ #endif
++#ifdef CONFIG_CPU_HIGH_VECTOR
++ orr r0, r0, #CR_V
++#else
++ bic r0, r0, #CR_V
++#endif
+ mcr p15, 0, r0, c1, c0, 0 @ write control reg
++#endif /* CONFIG_CPU_CP15 */
+
+ mov pc, r13 @ clear the BSS and jump
+ @ to start_kernel
+diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
+index 5365d4e..ebc3e74 100644
+--- a/arch/arm/kernel/head.S
++++ b/arch/arm/kernel/head.S
+@@ -234,18 +234,18 @@ __create_page_tables:
+
+ /*
+ * Now setup the pagetables for our kernel direct
+- * mapped region. We round TEXTADDR down to the
+- * nearest megabyte boundary. It is assumed that
+- * the kernel fits within 4 contigous 1MB sections.
++ * mapped region.
+ */
+ add r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
+ str r3, [r0, #(TEXTADDR & 0x00f00000) >> 18]!
+- add r3, r3, #1 << 20
+- str r3, [r0, #4]! @ KERNEL + 1MB
+- add r3, r3, #1 << 20
+- str r3, [r0, #4]! @ KERNEL + 2MB
+- add r3, r3, #1 << 20
+- str r3, [r0, #4] @ KERNEL + 3MB
++
++ ldr r6, =(_end - PAGE_OFFSET - 1) @ r6 = number of sections
++ mov r6, r6, lsr #20 @ needed for kernel minus 1
++
++1: add r3, r3, #1 << 20
++ str r3, [r0, #4]!
++ subs r6, r6, #1
++ bgt 1b
+
+ /*
+ * Then map first 1MB of ram in case it contains our boot params.
+diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
+index 2e1bf83..2c4ff1c 100644
+--- a/arch/arm/kernel/irq.c
++++ b/arch/arm/kernel/irq.c
+@@ -111,6 +111,7 @@ static struct irq_desc bad_irq_desc = {
+ */
+ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ struct irqdesc *desc = irq_desc + irq;
+
+ /*
+@@ -122,12 +123,13 @@ asmlinkage void asm_do_IRQ(unsigned int
+
+ irq_enter();
+
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+
+ /* AT91 specific workaround */
+ irq_finish(irq);
+
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ void set_irq_flags(unsigned int irq, unsigned int iflags)
+diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c
+index 44a86c3..0d1a1db 100644
+--- a/arch/arm/kernel/iwmmxt-notifier.c
++++ b/arch/arm/kernel/iwmmxt-notifier.c
+@@ -15,7 +15,6 @@
+ */
+
+ #include <linux/module.h>
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/signal.h>
+diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
+index 298363d..1b06158 100644
+--- a/arch/arm/kernel/module.c
++++ b/arch/arm/kernel/module.c
+@@ -2,6 +2,7 @@
+ * linux/arch/arm/kernel/module.c
+ *
+ * Copyright (C) 2002 Russell King.
++ * Modified for nommu by Hyok S. Choi
+ *
+ * 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
+@@ -32,6 +33,7 @@ extern void _etext;
+ #define MODULE_START (((unsigned long)&_etext + ~PGDIR_MASK) & PGDIR_MASK)
+ #endif
+
++#ifdef CONFIG_MMU
+ void *module_alloc(unsigned long size)
+ {
+ struct vm_struct *area;
+@@ -46,6 +48,12 @@ void *module_alloc(unsigned long size)
+
+ return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
+ }
++#else /* CONFIG_MMU */
++void *module_alloc(unsigned long size)
++{
++ return size == 0 ? NULL : vmalloc(size);
++}
++#endif /* !CONFIG_MMU */
+
+ void module_free(struct module *module, void *region)
+ {
+diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
+index 3079535..bf35c17 100644
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -221,16 +221,26 @@ void __show_regs(struct pt_regs *regs)
+ processor_modes[processor_mode(regs)],
+ thumb_mode(regs) ? " (T)" : "",
+ get_fs() == get_ds() ? "kernel" : "user");
++#if CONFIG_CPU_CP15
+ {
+- unsigned int ctrl, transbase, dac;
++ unsigned int ctrl;
+ __asm__ (
+ " mrc p15, 0, %0, c1, c0\n"
+- " mrc p15, 0, %1, c2, c0\n"
+- " mrc p15, 0, %2, c3, c0\n"
+- : "=r" (ctrl), "=r" (transbase), "=r" (dac));
+- printk("Control: %04X Table: %08X DAC: %08X\n",
+- ctrl, transbase, dac);
++ : "=r" (ctrl));
++ printk("Control: %04X\n", ctrl);
+ }
++#ifdef CONFIG_CPU_CP15_MMU
++ {
++ unsigned int transbase, dac;
++ __asm__ (
++ " mrc p15, 0, %0, c2, c0\n"
++ " mrc p15, 0, %1, c3, c0\n"
++ : "=r" (transbase), "=r" (dac));
++ printk("Table: %08X DAC: %08X\n",
++ transbase, dac);
++ }
++#endif
++#endif
+ }
+
+ void show_regs(struct pt_regs * regs)
+diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
+index 0a722e7..29efc9f 100644
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -348,7 +348,7 @@ static void __init setup_processor(void)
+ cpu_name, processor_id, (int)processor_id & 15,
+ proc_arch[cpu_architecture()], cr_alignment);
+
+- sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
++ sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
+ sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
+ elf_hwcap = list->elf_hwcap;
+ #ifndef CONFIG_ARM_THUMB
+@@ -357,6 +357,9 @@ static void __init setup_processor(void)
+ #ifndef CONFIG_VFP
+ elf_hwcap &= ~HWCAP_VFP;
+ #endif
++#ifndef CONFIG_IWMMXT
++ elf_hwcap &= ~HWCAP_IWMMXT;
++#endif
+
+ cpu_proc_init();
+ }
+@@ -854,6 +857,7 @@ static const char *hwcap_str[] = {
+ "vfp",
+ "edsp",
+ "java",
++ "iwmmxt",
+ NULL
+ };
+
+diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
+index 68e9634..a07d202 100644
+--- a/arch/arm/kernel/smp.c
++++ b/arch/arm/kernel/smp.c
+@@ -7,6 +7,7 @@
+ * 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/delay.h>
+ #include <linux/init.h>
+ #include <linux/spinlock.h>
+@@ -19,6 +20,7 @@
+ #include <linux/cpu.h>
+ #include <linux/smp.h>
+ #include <linux/seq_file.h>
++#include <linux/irq.h>
+
+ #include <asm/atomic.h>
+ #include <asm/cacheflush.h>
+@@ -36,7 +38,9 @@
+ * The online bitmask indicates that the CPU is up and running.
+ */
+ cpumask_t cpu_possible_map;
++EXPORT_SYMBOL(cpu_possible_map);
+ cpumask_t cpu_online_map;
++EXPORT_SYMBOL(cpu_online_map);
+
+ /*
+ * as from 2.5, kernels no longer have an init_tasks structure
+@@ -472,25 +476,26 @@ void show_local_irqs(struct seq_file *p)
+ seq_putc(p, '\n');
+ }
+
+-static void ipi_timer(struct pt_regs *regs)
++static void ipi_timer(void)
+ {
+- int user = user_mode(regs);
+-
+ irq_enter();
+- profile_tick(CPU_PROFILING, regs);
+- update_process_times(user);
++ profile_tick(CPU_PROFILING);
++ update_process_times(user_mode(get_irq_regs()));
+ irq_exit();
+ }
+
+ #ifdef CONFIG_LOCAL_TIMERS
+ asmlinkage void do_local_timer(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ int cpu = smp_processor_id();
+
+ if (local_timer_ack()) {
+ irq_stat[cpu].local_timer_irqs++;
+- ipi_timer(regs);
++ ipi_timer();
+ }
++
++ set_irq_regs(old_regs);
+ }
+ #endif
+
+@@ -549,6 +554,7 @@ asmlinkage void do_IPI(struct pt_regs *r
+ {
+ unsigned int cpu = smp_processor_id();
+ struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
++ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ ipi->ipi_count++;
+
+@@ -572,7 +578,7 @@ asmlinkage void do_IPI(struct pt_regs *r
+
+ switch (nextmsg) {
+ case IPI_TIMER:
+- ipi_timer(regs);
++ ipi_timer();
+ break;
+
+ case IPI_RESCHEDULE:
+@@ -597,6 +603,8 @@ asmlinkage void do_IPI(struct pt_regs *r
+ }
+ } while (msgs);
+ }
++
++ set_irq_regs(old_regs);
+ }
+
+ void smp_send_reschedule(int cpu)
+diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
+index 8170af4..00c18d3 100644
+--- a/arch/arm/kernel/sys_arm.c
++++ b/arch/arm/kernel/sys_arm.c
+@@ -279,7 +279,7 @@ out:
+ return error;
+ }
+
+-long execve(const char *filename, char **argv, char **envp)
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+ {
+ struct pt_regs regs;
+ int ret;
+@@ -317,7 +317,7 @@ long execve(const char *filename, char *
+ out:
+ return ret;
+ }
+-EXPORT_SYMBOL(execve);
++EXPORT_SYMBOL(kernel_execve);
+
+ /*
+ * Since loff_t is a 64 bit type we avoid a lot of ABI hastle
+diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
+index 09a67d7..6ff5e3f 100644
+--- a/arch/arm/kernel/time.c
++++ b/arch/arm/kernel/time.c
+@@ -27,6 +27,7 @@
+ #include <linux/profile.h>
+ #include <linux/sysdev.h>
+ #include <linux/timer.h>
++#include <linux/irq.h>
+
+ #include <asm/leds.h>
+ #include <asm/thread_info.h>
+@@ -37,8 +38,6 @@
+ */
+ struct sys_timer *system_timer;
+
+-extern unsigned long wall_jiffies;
+-
+ /* this needs a better home */
+ DEFINE_SPINLOCK(rtc_lock);
+
+@@ -69,10 +68,12 @@ EXPORT_SYMBOL(profile_pc);
+ */
+ int (*set_rtc)(void);
+
++#ifndef CONFIG_GENERIC_TIME
+ static unsigned long dummy_gettimeoffset(void)
+ {
+ return 0;
+ }
++#endif
+
+ /*
+ * Scheduler clock - returns current time in nanosec units.
+@@ -219,10 +220,10 @@ EXPORT_SYMBOL(leds_event);
+ #ifdef CONFIG_LEDS_TIMER
+ static inline void do_leds(void)
+ {
+- static unsigned int count = 50;
++ static unsigned int count = HZ/2;
+
+ if (--count == 0) {
+- count = 50;
++ count = HZ/2;
+ leds_event(led_timer);
+ }
+ }
+@@ -230,20 +231,16 @@ static inline void do_leds(void)
+ #define do_leds()
+ #endif
+
++#ifndef CONFIG_GENERIC_TIME
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+ unsigned long seq;
+- unsigned long usec, sec, lost;
++ unsigned long usec, sec;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = system_timer->offset();
+-
+- lost = jiffies - wall_jiffies;
+- if (lost)
+- usec += lost * USECS_PER_JIFFY;
+-
+ sec = xtime.tv_sec;
+ usec += xtime.tv_nsec / 1000;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+@@ -276,7 +273,6 @@ int do_settimeofday(struct timespec *tv)
+ * done, and then undo it!
+ */
+ nsec -= system_timer->offset() * NSEC_PER_USEC;
+- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+@@ -291,6 +287,7 @@ int do_settimeofday(struct timespec *tv)
+ }
+
+ EXPORT_SYMBOL(do_settimeofday);
++#endif /* !CONFIG_GENERIC_TIME */
+
+ /**
+ * save_time_delta - Save the offset between system time and RTC time
+@@ -328,14 +325,14 @@ EXPORT_SYMBOL(restore_time_delta);
+ /*
+ * Kernel system timer support.
+ */
+-void timer_tick(struct pt_regs *regs)
++void timer_tick(void)
+ {
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ do_leds();
+ do_set_rtc();
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ }
+
+@@ -500,8 +497,10 @@ device_initcall(timer_init_sysfs);
+
+ void __init time_init(void)
+ {
++#ifndef CONFIG_GENERIC_TIME
+ if (system_timer->offset == NULL)
+ system_timer->offset = dummy_gettimeoffset;
++#endif
+ system_timer->init();
+
+ #ifdef CONFIG_NO_IDLE_HZ
+diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
+index aeeed80..bede380 100644
+--- a/arch/arm/kernel/traps.c
++++ b/arch/arm/kernel/traps.c
+@@ -191,7 +191,7 @@ void show_stack(struct task_struct *tsk,
+ if (tsk != current)
+ fp = thread_saved_fp(tsk);
+ else
+- asm("mov%? %0, fp" : "=r" (fp));
++ asm("mov %0, fp" : "=r" (fp) : : "cc");
+
+ c_backtrace(fp, 0x10);
+ barrier();
+diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
+index 3ca574e..a8fa75e 100644
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -45,13 +45,7 @@ SECTIONS
+ *(.early_param.init)
+ __early_end = .;
+ __initcall_start = .;
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ __initcall_end = .;
+ __con_initcall_start = .;
+ *(.con_initcall.init)
+diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
+index baa997c..fe3d297 100644
+--- a/arch/arm/mach-aaec2000/core.c
++++ b/arch/arm/mach-aaec2000/core.c
+@@ -127,12 +127,12 @@ static unsigned long aaec2000_gettimeoff
+
+ /* We enter here with IRQs enabled */
+ static irqreturn_t
+-aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++aaec2000_timer_interrupt(int irq, void *dev_id)
+ {
+ /* TODO: Check timer accuracy */
+ write_seqlock(&xtime_lock);
+
+- timer_tick(regs);
++ timer_tick();
+ TIMER1_CLEAR = 1;
+
+ write_sequnlock(&xtime_lock);
+diff --git a/arch/arm/mach-at91rm9200/at91rm9200.c b/arch/arm/mach-at91rm9200/at91rm9200.c
+index 0985b1c..dcf6136 100644
+--- a/arch/arm/mach-at91rm9200/at91rm9200.c
++++ b/arch/arm/mach-at91rm9200/at91rm9200.c
+@@ -17,6 +17,7 @@
+
+ #include <asm/hardware.h>
+ #include "generic.h"
++#include "clock.h"
+
+ static struct map_desc at91rm9200_io_desc[] __initdata = {
+ {
+@@ -26,87 +27,224 @@ static struct map_desc at91rm9200_io_des
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_VA_BASE_SPI,
+- .pfn = __phys_to_pfn(AT91_BASE_SPI),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_SSC2,
+- .pfn = __phys_to_pfn(AT91_BASE_SSC2),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_SSC1,
+- .pfn = __phys_to_pfn(AT91_BASE_SSC1),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_SSC0,
+- .pfn = __phys_to_pfn(AT91_BASE_SSC0),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_US3,
+- .pfn = __phys_to_pfn(AT91_BASE_US3),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_US2,
+- .pfn = __phys_to_pfn(AT91_BASE_US2),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_US1,
+- .pfn = __phys_to_pfn(AT91_BASE_US1),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_US0,
+- .pfn = __phys_to_pfn(AT91_BASE_US0),
++ .pfn = __phys_to_pfn(AT91RM9200_BASE_SPI),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_VA_BASE_EMAC,
+- .pfn = __phys_to_pfn(AT91_BASE_EMAC),
++ .pfn = __phys_to_pfn(AT91RM9200_BASE_EMAC),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_VA_BASE_TWI,
+- .pfn = __phys_to_pfn(AT91_BASE_TWI),
++ .pfn = __phys_to_pfn(AT91RM9200_BASE_TWI),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_VA_BASE_MCI,
+- .pfn = __phys_to_pfn(AT91_BASE_MCI),
++ .pfn = __phys_to_pfn(AT91RM9200_BASE_MCI),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_VA_BASE_UDP,
+- .pfn = __phys_to_pfn(AT91_BASE_UDP),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_TCB1,
+- .pfn = __phys_to_pfn(AT91_BASE_TCB1),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- }, {
+- .virtual = AT91_VA_BASE_TCB0,
+- .pfn = __phys_to_pfn(AT91_BASE_TCB0),
++ .pfn = __phys_to_pfn(AT91RM9200_BASE_UDP),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_SRAM_VIRT_BASE,
+- .pfn = __phys_to_pfn(AT91_SRAM_BASE),
+- .length = AT91_SRAM_SIZE,
++ .pfn = __phys_to_pfn(AT91RM9200_SRAM_BASE),
++ .length = AT91RM9200_SRAM_SIZE,
+ .type = MT_DEVICE,
+ },
+ };
+
+-void __init at91rm9200_map_io(void)
++/* --------------------------------------------------------------------
++ * Clocks
++ * -------------------------------------------------------------------- */
++
++/*
++ * The peripheral clocks.
++ */
++static struct clk udc_clk = {
++ .name = "udc_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_UDP,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk ohci_clk = {
++ .name = "ohci_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_UHP,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk ether_clk = {
++ .name = "ether_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_EMAC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk mmc_clk = {
++ .name = "mci_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_MCI,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi_clk = {
++ .name = "twi_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_TWI,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart0_clk = {
++ .name = "usart0_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_US0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart1_clk = {
++ .name = "usart1_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_US1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart2_clk = {
++ .name = "usart2_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_US2,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart3_clk = {
++ .name = "usart3_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_US3,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi_clk = {
++ .name = "spi_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_SPI,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pioA_clk = {
++ .name = "pioA_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_PIOA,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pioB_clk = {
++ .name = "pioB_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_PIOB,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pioC_clk = {
++ .name = "pioC_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_PIOC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pioD_clk = {
++ .name = "pioD_clk",
++ .pmc_mask = 1 << AT91RM9200_ID_PIOD,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
++static struct clk *periph_clocks[] __initdata = {
++ &pioA_clk,
++ &pioB_clk,
++ &pioC_clk,
++ &pioD_clk,
++ &usart0_clk,
++ &usart1_clk,
++ &usart2_clk,
++ &usart3_clk,
++ &mmc_clk,
++ &udc_clk,
++ &twi_clk,
++ &spi_clk,
++ // ssc 0 .. ssc2
++ // tc0 .. tc5
++ &ohci_clk,
++ ðer_clk,
++ // irq0 .. irq6
++};
++
++/*
++ * The four programmable clocks.
++ * You must configure pin multiplexing to bring these signals out.
++ */
++static struct clk pck0 = {
++ .name = "pck0",
++ .pmc_mask = AT91_PMC_PCK0,
++ .type = CLK_TYPE_PROGRAMMABLE,
++ .id = 0,
++};
++static struct clk pck1 = {
++ .name = "pck1",
++ .pmc_mask = AT91_PMC_PCK1,
++ .type = CLK_TYPE_PROGRAMMABLE,
++ .id = 1,
++};
++static struct clk pck2 = {
++ .name = "pck2",
++ .pmc_mask = AT91_PMC_PCK2,
++ .type = CLK_TYPE_PROGRAMMABLE,
++ .id = 2,
++};
++static struct clk pck3 = {
++ .name = "pck3",
++ .pmc_mask = AT91_PMC_PCK3,
++ .type = CLK_TYPE_PROGRAMMABLE,
++ .id = 3,
++};
++
++static void __init at91rm9200_register_clocks(void)
+ {
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
++ clk_register(periph_clocks[i]);
++
++ clk_register(&pck0);
++ clk_register(&pck1);
++ clk_register(&pck2);
++ clk_register(&pck3);
++}
++
++/* --------------------------------------------------------------------
++ * GPIO
++ * -------------------------------------------------------------------- */
++
++static struct at91_gpio_bank at91rm9200_gpio[] = {
++ {
++ .id = AT91RM9200_ID_PIOA,
++ .offset = AT91_PIOA,
++ .clock = &pioA_clk,
++ }, {
++ .id = AT91RM9200_ID_PIOB,
++ .offset = AT91_PIOB,
++ .clock = &pioB_clk,
++ }, {
++ .id = AT91RM9200_ID_PIOC,
++ .offset = AT91_PIOC,
++ .clock = &pioC_clk,
++ }, {
++ .id = AT91RM9200_ID_PIOD,
++ .offset = AT91_PIOD,
++ .clock = &pioD_clk,
++ }
++};
++
++/* --------------------------------------------------------------------
++ * AT91RM9200 processor initialization
++ * -------------------------------------------------------------------- */
++void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks)
++{
++ /* Map peripherals */
+ iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
++
++ /* Init clock subsystem */
++ at91_clock_init(main_clock);
++
++ /* Register the processor-specific clocks */
++ at91rm9200_register_clocks();
++
++ /* Initialize GPIO subsystem */
++ at91_gpio_init(at91rm9200_gpio, banks);
+ }
+
++
++/* --------------------------------------------------------------------
++ * Interrupt initialization
++ * -------------------------------------------------------------------- */
++
+ /*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+@@ -145,10 +283,14 @@ static unsigned int at91rm9200_default_i
+ 0 /* Advanced Interrupt Controller (IRQ6) */
+ };
+
+-void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
++void __init at91rm9200_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+ {
+ if (!priority)
+ priority = at91rm9200_default_irq_priority;
+
++ /* Initialize the AIC interrupt controller */
+ at91_aic_init(priority);
++
++ /* Enable GPIO interrupts */
++ at91_gpio_irq_setup();
+ }
+diff --git a/arch/arm/mach-at91rm9200/at91rm9200_time.c b/arch/arm/mach-at91rm9200/at91rm9200_time.c
+index a92a862..07c9cea 100644
+--- a/arch/arm/mach-at91rm9200/at91rm9200_time.c
++++ b/arch/arm/mach-at91rm9200/at91rm9200_time.c
+@@ -65,13 +65,13 @@ static unsigned long at91rm9200_gettimeo
+ /*
+ * IRQ handler for the timer.
+ */
+-static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
+ {
+ if (at91_sys_read(AT91_ST_SR) & AT91_ST_PITS) { /* This is a shared interrupt */
+ write_seqlock(&xtime_lock);
+
+ while (((read_CRTR() - last_crtr) & AT91_ST_ALMV) >= LATCH) {
+- timer_tick(regs);
++ timer_tick();
+ last_crtr = (last_crtr + LATCH) & AT91_ST_ALMV;
+ }
+
+diff --git a/arch/arm/mach-at91rm9200/board-1arm.c b/arch/arm/mach-at91rm9200/board-1arm.c
+index dc79e09..971c3e2 100644
+--- a/arch/arm/mach-at91rm9200/board-1arm.c
++++ b/arch/arm/mach-at91rm9200/board-1arm.c
+@@ -18,7 +18,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+@@ -34,20 +33,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init onearm_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(PQFP_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -62,15 +52,18 @@ static struct at91_uart_config __initdat
+
+ static void __init onearm_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 18.432 MHz crystal */
+- at91_clock_init(18432000);
++ /* Initialize processor: 18.432 MHz crystal */
++ at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+
+ /* Setup the serial ports and console */
+ at91_init_serial(&onearm_uart_config);
+ }
+
++static void __init onearm_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata onearm_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 1,
+diff --git a/arch/arm/mach-at91rm9200/board-carmeva.c b/arch/arm/mach-at91rm9200/board-carmeva.c
+index 2c138b5..9820874 100644
+--- a/arch/arm/mach-at91rm9200/board-carmeva.c
++++ b/arch/arm/mach-at91rm9200/board-carmeva.c
+@@ -19,7 +19,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+@@ -35,20 +34,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init carmeva_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(BGA_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -63,15 +53,19 @@ static struct at91_uart_config __initdat
+
+ static void __init carmeva_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 20.000 MHz crystal */
+- at91_clock_init(20000000);
++ /* Initialize processor: 20.000 MHz crystal */
++ at91rm9200_initialize(20000000, AT91RM9200_BGA);
+
+ /* Setup the serial ports and console */
+ at91_init_serial(&carmeva_uart_config);
+ }
+
++static void __init carmeva_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
++
+ static struct at91_eth_data __initdata carmeva_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 1,
+diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c
+index 794d3fb..8eeae49 100644
+--- a/arch/arm/mach-at91rm9200/board-csb337.c
++++ b/arch/arm/mach-at91rm9200/board-csb337.c
+@@ -34,20 +34,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init csb337_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(BGA_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -62,10 +53,8 @@ static struct at91_uart_config __initdat
+
+ static void __init csb337_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 3.6864 MHz crystal */
+- at91_clock_init(3686400);
++ /* Initialize processor: 3.6864 MHz crystal */
++ at91rm9200_initialize(3686400, AT91RM9200_BGA);
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+@@ -74,6 +63,11 @@ static void __init csb337_map_io(void)
+ at91_init_serial(&csb337_uart_config);
+ }
+
++static void __init csb337_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata csb337_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC2,
+ .is_rmii = 0,
+diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c
+index c8b6f33..a29fa0e 100644
+--- a/arch/arm/mach-at91rm9200/board-csb637.c
++++ b/arch/arm/mach-at91rm9200/board-csb637.c
+@@ -33,20 +33,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init csb637_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(BGA_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -61,10 +52,8 @@ static struct at91_uart_config __initdat
+
+ static void __init csb637_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 3.6864 MHz crystal */
+- at91_clock_init(3686400);
++ /* Initialize processor: 3.6864 MHz crystal */
++ at91rm9200_initialize(3686400, AT91RM9200_BGA);
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+@@ -73,6 +62,11 @@ static void __init csb637_map_io(void)
+ at91_init_serial(&csb637_uart_config);
+ }
+
++static void __init csb637_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata csb637_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC0,
+ .is_rmii = 0,
+diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c
+index 6587303..c699f39 100644
+--- a/arch/arm/mach-at91rm9200/board-dk.c
++++ b/arch/arm/mach-at91rm9200/board-dk.c
+@@ -37,20 +37,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init dk_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(BGA_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -65,10 +56,8 @@ static struct at91_uart_config __initdat
+
+ static void __init dk_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 18.432 MHz crystal */
+- at91_clock_init(18432000);
++ /* Initialize processor: 18.432 MHz crystal */
++ at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+@@ -77,6 +66,11 @@ static void __init dk_map_io(void)
+ at91_init_serial(&dk_uart_config);
+ }
+
++static void __init dk_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata dk_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 1,
+@@ -128,6 +122,29 @@ static struct spi_board_info dk_spi_devi
+ #endif
+ };
+
++static struct mtd_partition __initdata dk_nand_partition[] = {
++ {
++ .name = "NAND Partition 1",
++ .offset = 0,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static struct mtd_partition *nand_partitions(int size, int *num_partitions)
++{
++ *num_partitions = ARRAY_SIZE(dk_nand_partition);
++ return dk_nand_partition;
++}
++
++static struct at91_nand_data __initdata dk_nand_data = {
++ .ale = 22,
++ .cle = 21,
++ .det_pin = AT91_PIN_PB1,
++ .rdy_pin = AT91_PIN_PC2,
++ // .enable_pin = ... not there
++ .partition_info = nand_partitions,
++};
++
+ static void __init dk_board_init(void)
+ {
+ /* Serial */
+@@ -153,6 +170,8 @@ static void __init dk_board_init(void)
+ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+ at91_add_device_mmc(&dk_mmc_data);
+ #endif
++ /* NAND */
++ at91_add_device_nand(&dk_nand_data);
+ /* VGA */
+ // dk_add_device_video();
+ }
+diff --git a/arch/arm/mach-at91rm9200/board-eb9200.c b/arch/arm/mach-at91rm9200/board-eb9200.c
+index a3e2df9..65e867b 100644
+--- a/arch/arm/mach-at91rm9200/board-eb9200.c
++++ b/arch/arm/mach-at91rm9200/board-eb9200.c
+@@ -19,7 +19,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+@@ -35,20 +34,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init eb9200_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(BGA_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -63,15 +53,18 @@ static struct at91_uart_config __initdat
+
+ static void __init eb9200_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 18.432 MHz crystal */
+- at91_clock_init(18432000);
++ /* Initialize processor: 18.432 MHz crystal */
++ at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+ /* Setup the serial ports and console */
+ at91_init_serial(&eb9200_uart_config);
+ }
+
++static void __init eb9200_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata eb9200_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 1,
+diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c
+index 8681923..830eb79 100644
+--- a/arch/arm/mach-at91rm9200/board-ek.c
++++ b/arch/arm/mach-at91rm9200/board-ek.c
+@@ -37,20 +37,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init ek_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(BGA_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -65,10 +56,8 @@ static struct at91_uart_config __initdat
+
+ static void __init ek_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 18.432 MHz crystal */
+- at91_clock_init(18432000);
++ /* Initialize processor: 18.432 MHz crystal */
++ at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+@@ -77,6 +66,11 @@ static void __init ek_map_io(void)
+ at91_init_serial(&ek_uart_config);
+ }
+
++static void __init ek_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata ek_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 1,
+diff --git a/arch/arm/mach-at91rm9200/board-kafa.c b/arch/arm/mach-at91rm9200/board-kafa.c
+index bf760c5..6ef3c48 100644
+--- a/arch/arm/mach-at91rm9200/board-kafa.c
++++ b/arch/arm/mach-at91rm9200/board-kafa.c
+@@ -18,7 +18,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+@@ -34,20 +33,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init kafa_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(PQFP_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -62,10 +52,8 @@ static struct at91_uart_config __initdat
+
+ static void __init kafa_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 18.432 MHz crystal */
+- at91_clock_init(18432000);
++ /* Initialize processor: 18.432 MHz crystal */
++ at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+
+ /* Set up the LEDs */
+ at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
+@@ -74,6 +62,11 @@ static void __init kafa_map_io(void)
+ at91_init_serial(&kafa_uart_config);
+ }
+
++static void __init kafa_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata kafa_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 0,
+diff --git a/arch/arm/mach-at91rm9200/board-kb9202.c b/arch/arm/mach-at91rm9200/board-kb9202.c
+index f06d2b5..35a954a 100644
+--- a/arch/arm/mach-at91rm9200/board-kb9202.c
++++ b/arch/arm/mach-at91rm9200/board-kb9202.c
+@@ -19,7 +19,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+@@ -35,20 +34,11 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+
+-#include <asm/hardware.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+
+ #include "generic.h"
+
+-static void __init kb9202_init_irq(void)
+-{
+- /* Initialize AIC controller */
+- at91rm9200_init_irq(NULL);
+-
+- /* Set up the GPIO interrupts */
+- at91_gpio_irq_setup(PQFP_GPIO_BANKS);
+-}
+
+ /*
+ * Serial port configuration.
+@@ -63,10 +53,8 @@ static struct at91_uart_config __initdat
+
+ static void __init kb9202_map_io(void)
+ {
+- at91rm9200_map_io();
+-
+- /* Initialize clocks: 10 MHz crystal */
+- at91_clock_init(10000000);
++ /* Initialize processor: 10 MHz crystal */
++ at91rm9200_initialize(10000000, AT91RM9200_PQFP);
+
+ /* Set up the LEDs */
+ at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
+@@ -75,6 +63,11 @@ static void __init kb9202_map_io(void)
+ at91_init_serial(&kb9202_uart_config);
+ }
+
++static void __init kb9202_init_irq(void)
++{
++ at91rm9200_init_interrupts(NULL);
++}
++
+ static struct at91_eth_data __initdata kb9202_eth_data = {
+ .phy_irq_pin = AT91_PIN_PB29,
+ .is_rmii = 0,
+@@ -95,6 +88,29 @@ static struct at91_mmc_data __initdata k
+ .wire4 = 1,
+ };
+
++static struct mtd_partition __initdata kb9202_nand_partition[] = {
++ {
++ .name = "nand_fs",
++ .offset = 0,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static struct mtd_partition *nand_partitions(int size, int *num_partitions)
++{
++ *num_partitions = ARRAY_SIZE(kb9202_nand_partition);
++ return kb9202_nand_partition;
++}
++
++static struct at91_nand_data __initdata kb9202_nand_data = {
++ .ale = 22,
++ .cle = 21,
++ // .det_pin = ... not there
++ .rdy_pin = AT91_PIN_PC29,
++ .enable_pin = AT91_PIN_PC28,
++ .partition_info = nand_partitions,
++};
++
+ static void __init kb9202_board_init(void)
+ {
+ /* Serial */
+@@ -111,6 +127,8 @@ static void __init kb9202_board_init(voi
+ at91_add_device_i2c();
+ /* SPI */
+ at91_add_device_spi(NULL, 0);
++ /* NAND */
++ at91_add_device_nand(&kb9202_nand_data);
+ }
+
+ MACHINE_START(KB9200, "KB920x")
+diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91rm9200/clock.c
+index edc2cc8..a43b061 100644
+--- a/arch/arm/mach-at91rm9200/clock.c
++++ b/arch/arm/mach-at91rm9200/clock.c
+@@ -29,7 +29,7 @@
+
+ #include <asm/hardware.h>
+
+-#include "generic.h"
++#include "clock.h"
+
+
+ /*
+@@ -38,23 +38,15 @@
+ * PLLB be used at other rates (on boards that don't need USB), etc.
+ */
+
+-struct clk {
+- const char *name; /* unique clock name */
+- const char *function; /* function of the clock */
+- struct device *dev; /* device associated with function */
+- unsigned long rate_hz;
+- struct clk *parent;
+- u32 pmc_mask;
+- void (*mode)(struct clk *, int);
+- unsigned id:2; /* PCK0..3, or 32k/main/a/b */
+- unsigned primary:1;
+- unsigned pll:1;
+- unsigned programmable:1;
+- u16 users;
+-};
++#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY)
++#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE)
++#define clk_is_peripheral(x) ((x)->type & CLK_TYPE_PERIPHERAL)
++
++
++static LIST_HEAD(clocks);
++static DEFINE_SPINLOCK(clk_lock);
+
+-static spinlock_t clk_lock;
+-static u32 at91_pllb_usb_init;
++static u32 at91_pllb_usb_init;
+
+ /*
+ * Four primary clock sources: two crystal oscillators (32K, main), and
+@@ -67,21 +59,20 @@ static struct clk clk32k = {
+ .rate_hz = AT91_SLOW_CLOCK,
+ .users = 1, /* always on */
+ .id = 0,
+- .primary = 1,
++ .type = CLK_TYPE_PRIMARY,
+ };
+ static struct clk main_clk = {
+ .name = "main",
+ .pmc_mask = AT91_PMC_MOSCS, /* in PMC_SR */
+ .id = 1,
+- .primary = 1,
++ .type = CLK_TYPE_PRIMARY,
+ };
+ static struct clk plla = {
+ .name = "plla",
+ .parent = &main_clk,
+ .pmc_mask = AT91_PMC_LOCKA, /* in PMC_SR */
+ .id = 2,
+- .primary = 1,
+- .pll = 1,
++ .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
+ };
+
+ static void pllb_mode(struct clk *clk, int is_on)
+@@ -94,6 +85,7 @@ static void pllb_mode(struct clk *clk, i
+ } else
+ value = 0;
+
++ // REVISIT: Add work-around for AT91RM9200 Errata #26 ?
+ at91_sys_write(AT91_CKGR_PLLBR, value);
+
+ do {
+@@ -107,8 +99,7 @@ static struct clk pllb = {
+ .pmc_mask = AT91_PMC_LOCKB, /* in PMC_SR */
+ .mode = pllb_mode,
+ .id = 3,
+- .primary = 1,
+- .pll = 1,
++ .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
+ };
+
+ static void pmc_sys_mode(struct clk *clk, int is_on)
+@@ -133,41 +124,6 @@ static struct clk uhpck = {
+ .mode = pmc_sys_mode,
+ };
+
+-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+-/*
+- * The four programmable clocks can be parented by any primary clock.
+- * You must configure pin multiplexing to bring these signals out.
+- */
+-static struct clk pck0 = {
+- .name = "pck0",
+- .pmc_mask = AT91_PMC_PCK0,
+- .mode = pmc_sys_mode,
+- .programmable = 1,
+- .id = 0,
+-};
+-static struct clk pck1 = {
+- .name = "pck1",
+- .pmc_mask = AT91_PMC_PCK1,
+- .mode = pmc_sys_mode,
+- .programmable = 1,
+- .id = 1,
+-};
+-static struct clk pck2 = {
+- .name = "pck2",
+- .pmc_mask = AT91_PMC_PCK2,
+- .mode = pmc_sys_mode,
+- .programmable = 1,
+- .id = 2,
+-};
+-static struct clk pck3 = {
+- .name = "pck3",
+- .pmc_mask = AT91_PMC_PCK3,
+- .mode = pmc_sys_mode,
+- .programmable = 1,
+- .id = 3,
+-};
+-#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
+-
+
+ /*
+ * The master clock is divided from the CPU clock (by 1-4). It's used for
+@@ -187,131 +143,21 @@ static void pmc_periph_mode(struct clk *
+ at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
+ }
+
+-static struct clk udc_clk = {
+- .name = "udc_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_UDP,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk ohci_clk = {
+- .name = "ohci_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_UHP,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk ether_clk = {
+- .name = "ether_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_EMAC,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk mmc_clk = {
+- .name = "mci_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_MCI,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk twi_clk = {
+- .name = "twi_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_TWI,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk usart0_clk = {
+- .name = "usart0_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_US0,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk usart1_clk = {
+- .name = "usart1_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_US1,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk usart2_clk = {
+- .name = "usart2_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_US2,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk usart3_clk = {
+- .name = "usart3_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_US3,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk spi_clk = {
+- .name = "spi0_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_SPI,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk pioA_clk = {
+- .name = "pioA_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_PIOA,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk pioB_clk = {
+- .name = "pioB_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_PIOB,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk pioC_clk = {
+- .name = "pioC_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_PIOC,
+- .mode = pmc_periph_mode,
+-};
+-static struct clk pioD_clk = {
+- .name = "pioD_clk",
+- .parent = &mck,
+- .pmc_mask = 1 << AT91_ID_PIOD,
+- .mode = pmc_periph_mode,
+-};
+-
+-static struct clk *const clock_list[] = {
+- /* four primary clocks -- MUST BE FIRST! */
+- &clk32k,
+- &main_clk,
+- &plla,
+- &pllb,
+-
+- /* PLLB children (USB) */
+- &udpck,
+- &uhpck,
+-
+-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+- /* programmable clocks */
+- &pck0,
+- &pck1,
+- &pck2,
+- &pck3,
+-#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
+-
+- /* MCK and peripherals */
+- &mck,
+- &usart0_clk,
+- &usart1_clk,
+- &usart2_clk,
+- &usart3_clk,
+- &mmc_clk,
+- &udc_clk,
+- &twi_clk,
+- &spi_clk,
+- &pioA_clk,
+- &pioB_clk,
+- &pioC_clk,
+- &pioD_clk,
+- // ssc0..ssc2
+- // tc0..tc5
+- // irq0..irq6
+- &ohci_clk,
+- ðer_clk,
+-};
++static struct clk __init *at91_css_to_clk(unsigned long css)
++{
++ switch (css) {
++ case AT91_PMC_CSS_SLOW:
++ return &clk32k;
++ case AT91_PMC_CSS_MAIN:
++ return &main_clk;
++ case AT91_PMC_CSS_PLLA:
++ return &plla;
++ case AT91_PMC_CSS_PLLB:
++ return &pllb;
++ }
+
++ return NULL;
++}
+
+ /*
+ * Associate a particular clock with a function (eg, "uart") and device.
+@@ -329,14 +175,12 @@ void __init at91_clock_associate(const c
+ clk->dev = dev;
+ }
+
+-/* clocks are all static for now; no refcounting necessary */
++/* clocks cannot be de-registered no refcounting necessary */
+ struct clk *clk_get(struct device *dev, const char *id)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
+- struct clk *clk = clock_list[i];
++ struct clk *clk;
+
++ list_for_each_entry(clk, &clocks, node) {
+ if (strcmp(id, clk->name) == 0)
+ return clk;
+ if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0)
+@@ -424,7 +268,7 @@ long clk_round_rate(struct clk *clk, uns
+ unsigned prescale;
+ unsigned long actual;
+
+- if (!clk->programmable)
++ if (!clk_is_programmable(clk))
+ return -EINVAL;
+ spin_lock_irqsave(&clk_lock, flags);
+
+@@ -446,7 +290,7 @@ int clk_set_rate(struct clk *clk, unsign
+ unsigned prescale;
+ unsigned long actual;
+
+- if (!clk->programmable)
++ if (!clk_is_programmable(clk))
+ return -EINVAL;
+ if (clk->users)
+ return -EBUSY;
+@@ -484,7 +328,7 @@ int clk_set_parent(struct clk *clk, stru
+
+ if (clk->users)
+ return -EBUSY;
+- if (!parent->primary || !clk->programmable)
++ if (!clk_is_primary(parent) || !clk_is_programmable(clk))
+ return -EINVAL;
+ spin_lock_irqsave(&clk_lock, flags);
+
+@@ -497,6 +341,18 @@ int clk_set_parent(struct clk *clk, stru
+ }
+ EXPORT_SYMBOL(clk_set_parent);
+
++/* establish PCK0..PCK3 parentage and rate */
++static void init_programmable_clock(struct clk *clk)
++{
++ struct clk *parent;
++ u32 pckr;
++
++ pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
++ parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
++ clk->parent = parent;
++ clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
++}
++
+ #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
+
+ /*------------------------------------------------------------------------*/
+@@ -506,6 +362,7 @@ EXPORT_SYMBOL(clk_set_parent);
+ static int at91_clk_show(struct seq_file *s, void *unused)
+ {
+ u32 scsr, pcsr, sr;
++ struct clk *clk;
+ unsigned i;
+
+ seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR));
+@@ -523,9 +380,8 @@ static int at91_clk_show(struct seq_file
+
+ seq_printf(s, "\n");
+
+- for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
+- char *state;
+- struct clk *clk = clock_list[i];
++ list_for_each_entry(clk, &clocks, node) {
++ char *state;
+
+ if (clk->mode == pmc_sys_mode)
+ state = (scsr & clk->pmc_mask) ? "on" : "off";
+@@ -570,6 +426,28 @@ postcore_initcall(at91_clk_debugfs_init)
+
+ /*------------------------------------------------------------------------*/
+
++/* Register a new clock */
++int __init clk_register(struct clk *clk)
++{
++ if (clk_is_peripheral(clk)) {
++ clk->parent = &mck;
++ clk->mode = pmc_periph_mode;
++ list_add_tail(&clk->node, &clocks);
++ }
++#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
++ else if (clk_is_programmable(clk)) {
++ clk->mode = pmc_sys_mode;
++ init_programmable_clock(clk);
++ list_add_tail(&clk->node, &clocks);
++ }
++#endif
++
++ return 0;
++}
++
++
++/*------------------------------------------------------------------------*/
++
+ static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
+ {
+ unsigned mul, div;
+@@ -640,20 +518,17 @@ fail:
+ return 0;
+ }
+
+-
+ /*
+ * Several unused clocks may be active. Turn them off.
+ */
+-static void at91_periphclk_reset(void)
++static void __init at91_periphclk_reset(void)
+ {
+ unsigned long reg;
+- int i;
++ struct clk *clk;
+
+ reg = at91_sys_read(AT91_PMC_PCSR);
+
+- for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
+- struct clk *clk = clock_list[i];
+-
++ list_for_each_entry(clk, &clocks, node) {
+ if (clk->mode != pmc_periph_mode)
+ continue;
+
+@@ -664,11 +539,25 @@ static void at91_periphclk_reset(void)
+ at91_sys_write(AT91_PMC_PCDR, reg);
+ }
+
++static struct clk *const standard_pmc_clocks[] __initdata = {
++ /* four primary clocks */
++ &clk32k,
++ &main_clk,
++ &plla,
++ &pllb,
++
++ /* PLLB children (USB) */
++ &udpck,
++ &uhpck,
++
++ /* MCK */
++ &mck
++};
++
+ int __init at91_clock_init(unsigned long main_clock)
+ {
+ unsigned tmp, freq, mckr;
+-
+- spin_lock_init(&clk_lock);
++ int i;
+
+ /*
+ * When the bootloader initialized the main oscillator correctly,
+@@ -709,11 +598,15 @@ int __init at91_clock_init(unsigned long
+ * For now, assume this parentage won't change.
+ */
+ mckr = at91_sys_read(AT91_PMC_MCKR);
+- mck.parent = clock_list[mckr & AT91_PMC_CSS];
++ mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
+ freq = mck.parent->rate_hz;
+ freq /= (1 << ((mckr >> 2) & 3)); /* prescale */
+ mck.rate_hz = freq / (1 + ((mckr >> 8) & 3)); /* mdiv */
+
++ /* Register the PMC's standard clocks */
++ for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
++ list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
++
+ /* MCK and CPU clock are "always on" */
+ clk_enable(&mck);
+
+@@ -722,35 +615,8 @@ int __init at91_clock_init(unsigned long
+ (unsigned) main_clock / 1000000,
+ ((unsigned) main_clock % 1000000) / 1000);
+
+-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+- /* establish PCK0..PCK3 parentage */
+- for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) {
+- struct clk *clk = clock_list[tmp], *parent;
+- u32 pckr;
+-
+- if (!clk->programmable)
+- continue;
+-
+- pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
+- parent = clock_list[pckr & AT91_PMC_CSS];
+- clk->parent = parent;
+- clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
+-
+- if (clk->users == 0) {
+- /* not being used, so switch it off */
+- at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);
+- }
+- }
+-#else
+ /* disable all programmable clocks */
+ at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3);
+-#endif
+-
+- /* enable the PIO clocks */
+- clk_enable(&pioA_clk);
+- clk_enable(&pioB_clk);
+- clk_enable(&pioC_clk);
+- clk_enable(&pioD_clk);
+
+ /* disable all other unused peripheral clocks */
+ at91_periphclk_reset();
+diff --git a/arch/arm/mach-at91rm9200/clock.h b/arch/arm/mach-at91rm9200/clock.h
+new file mode 100644
+index 0000000..0592e66
+--- /dev/null
++++ b/arch/arm/mach-at91rm9200/clock.h
+@@ -0,0 +1,30 @@
++/*
++ * linux/arch/arm/mach-at91rm9200/clock.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.
++ */
++
++#define CLK_TYPE_PRIMARY 0x1
++#define CLK_TYPE_PLL 0x2
++#define CLK_TYPE_PROGRAMMABLE 0x4
++#define CLK_TYPE_PERIPHERAL 0x8
++
++
++struct clk {
++ struct list_head node;
++ const char *name; /* unique clock name */
++ const char *function; /* function of the clock */
++ struct device *dev; /* device associated with function */
++ unsigned long rate_hz;
++ struct clk *parent;
++ u32 pmc_mask;
++ void (*mode)(struct clk *, int);
++ unsigned id:2; /* PCK0..3, or 32k/main/a/b */
++ unsigned type; /* clock type */
++ u16 users;
++};
++
++
++extern int __init clk_register(struct clk *clk);
+diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c
+index 4352acb..0598243 100644
+--- a/arch/arm/mach-at91rm9200/devices.c
++++ b/arch/arm/mach-at91rm9200/devices.c
+@@ -35,13 +35,13 @@ static struct at91_usbh_data usbh_data;
+
+ static struct resource at91_usbh_resources[] = {
+ [0] = {
+- .start = AT91_UHP_BASE,
+- .end = AT91_UHP_BASE + SZ_1M - 1,
++ .start = AT91RM9200_UHP_BASE,
++ .end = AT91RM9200_UHP_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_UHP,
+- .end = AT91_ID_UHP,
++ .start = AT91RM9200_ID_UHP,
++ .end = AT91RM9200_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -80,13 +80,13 @@ static struct at91_udc_data udc_data;
+
+ static struct resource at91_udc_resources[] = {
+ [0] = {
+- .start = AT91_BASE_UDP,
+- .end = AT91_BASE_UDP + SZ_16K - 1,
++ .start = AT91RM9200_BASE_UDP,
++ .end = AT91RM9200_BASE_UDP + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_UDP,
+- .end = AT91_ID_UDP,
++ .start = AT91RM9200_ID_UDP,
++ .end = AT91RM9200_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -131,13 +131,13 @@ static struct at91_eth_data eth_data;
+
+ static struct resource at91_eth_resources[] = {
+ [0] = {
+- .start = AT91_BASE_EMAC,
+- .end = AT91_BASE_EMAC + SZ_16K - 1,
++ .start = AT91_VA_BASE_EMAC,
++ .end = AT91_VA_BASE_EMAC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_EMAC,
+- .end = AT91_ID_EMAC,
++ .start = AT91RM9200_ID_EMAC,
++ .end = AT91RM9200_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -263,13 +263,13 @@ static struct at91_mmc_data mmc_data;
+
+ static struct resource at91_mmc_resources[] = {
+ [0] = {
+- .start = AT91_BASE_MCI,
+- .end = AT91_BASE_MCI + SZ_16K - 1,
++ .start = AT91RM9200_BASE_MCI,
++ .end = AT91RM9200_BASE_MCI + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_MCI,
+- .end = AT91_ID_MCI,
++ .start = AT91RM9200_ID_MCI,
++ .end = AT91RM9200_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -423,13 +423,13 @@ static u64 spi_dmamask = 0xffffffffUL;
+
+ static struct resource at91_spi_resources[] = {
+ [0] = {
+- .start = AT91_BASE_SPI,
+- .end = AT91_BASE_SPI + SZ_16K - 1,
++ .start = AT91RM9200_BASE_SPI,
++ .end = AT91RM9200_BASE_SPI + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SPI,
+- .end = AT91_ID_SPI,
++ .start = AT91RM9200_ID_SPI,
++ .end = AT91RM9200_ID_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -544,7 +544,7 @@ void __init at91_init_leds(u8 cpu_led, u
+ * UART
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_SERIAL_AT91)
++#if defined(CONFIG_SERIAL_ATMEL)
+ static struct resource dbgu_resources[] = {
+ [0] = {
+ .start = AT91_VA_BASE_SYS + AT91_DBGU,
+@@ -558,13 +558,14 @@ static struct resource dbgu_resources[]
+ },
+ };
+
+-static struct at91_uart_data dbgu_data = {
++static struct atmel_uart_data dbgu_data = {
+ .use_dma_tx = 0,
+ .use_dma_rx = 0, /* DBGU not capable of receive DMA */
++ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
+
+ static struct platform_device at91rm9200_dbgu_device = {
+- .name = "at91_usart",
++ .name = "atmel_usart",
+ .id = 0,
+ .dev = {
+ .platform_data = &dbgu_data,
+@@ -582,24 +583,24 @@ static inline void configure_dbgu_pins(v
+
+ static struct resource uart0_resources[] = {
+ [0] = {
+- .start = AT91_BASE_US0,
+- .end = AT91_BASE_US0 + SZ_16K - 1,
++ .start = AT91RM9200_BASE_US0,
++ .end = AT91RM9200_BASE_US0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_US0,
+- .end = AT91_ID_US0,
++ .start = AT91RM9200_ID_US0,
++ .end = AT91RM9200_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+-static struct at91_uart_data uart0_data = {
++static struct atmel_uart_data uart0_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+ };
+
+ static struct platform_device at91rm9200_uart0_device = {
+- .name = "at91_usart",
++ .name = "atmel_usart",
+ .id = 1,
+ .dev = {
+ .platform_data = &uart0_data,
+@@ -624,24 +625,24 @@ static inline void configure_usart0_pins
+
+ static struct resource uart1_resources[] = {
+ [0] = {
+- .start = AT91_BASE_US1,
+- .end = AT91_BASE_US1 + SZ_16K - 1,
++ .start = AT91RM9200_BASE_US1,
++ .end = AT91RM9200_BASE_US1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_US1,
+- .end = AT91_ID_US1,
++ .start = AT91RM9200_ID_US1,
++ .end = AT91RM9200_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+-static struct at91_uart_data uart1_data = {
++static struct atmel_uart_data uart1_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+ };
+
+ static struct platform_device at91rm9200_uart1_device = {
+- .name = "at91_usart",
++ .name = "atmel_usart",
+ .id = 2,
+ .dev = {
+ .platform_data = &uart1_data,
+@@ -665,24 +666,24 @@ static inline void configure_usart1_pins
+
+ static struct resource uart2_resources[] = {
+ [0] = {
+- .start = AT91_BASE_US2,
+- .end = AT91_BASE_US2 + SZ_16K - 1,
++ .start = AT91RM9200_BASE_US2,
++ .end = AT91RM9200_BASE_US2 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_US2,
+- .end = AT91_ID_US2,
++ .start = AT91RM9200_ID_US2,
++ .end = AT91RM9200_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+-static struct at91_uart_data uart2_data = {
++static struct atmel_uart_data uart2_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+ };
+
+ static struct platform_device at91rm9200_uart2_device = {
+- .name = "at91_usart",
++ .name = "atmel_usart",
+ .id = 3,
+ .dev = {
+ .platform_data = &uart2_data,
+@@ -700,24 +701,24 @@ static inline void configure_usart2_pins
+
+ static struct resource uart3_resources[] = {
+ [0] = {
+- .start = AT91_BASE_US3,
+- .end = AT91_BASE_US3 + SZ_16K - 1,
++ .start = AT91RM9200_BASE_US3,
++ .end = AT91RM9200_BASE_US3 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_US3,
+- .end = AT91_ID_US3,
++ .start = AT91RM9200_ID_US3,
++ .end = AT91RM9200_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+-static struct at91_uart_data uart3_data = {
++static struct atmel_uart_data uart3_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+ };
+
+ static struct platform_device at91rm9200_uart3_device = {
+- .name = "at91_usart",
++ .name = "atmel_usart",
+ .id = 4,
+ .dev = {
+ .platform_data = &uart3_data,
+@@ -733,8 +734,8 @@ static inline void configure_usart3_pins
+ at91_set_B_periph(AT91_PIN_PA6, 0); /* RXD3 */
+ }
+
+-struct platform_device *at91_uarts[AT91_NR_UART]; /* the UARTs to use */
+-struct platform_device *at91_default_console_device; /* the serial console device */
++struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
++struct platform_device *atmel_default_console_device; /* the serial console device */
+
+ void __init at91_init_serial(struct at91_uart_config *config)
+ {
+@@ -775,9 +776,9 @@ void __init at91_init_serial(struct at91
+ }
+
+ /* Set serial console device */
+- if (config->console_tty < AT91_NR_UART)
+- at91_default_console_device = at91_uarts[config->console_tty];
+- if (!at91_default_console_device)
++ if (config->console_tty < ATMEL_MAX_UART)
++ atmel_default_console_device = at91_uarts[config->console_tty];
++ if (!atmel_default_console_device)
+ printk(KERN_INFO "AT91: No default serial console defined.\n");
+ }
+
+@@ -785,7 +786,7 @@ void __init at91_add_device_serial(void)
+ {
+ int i;
+
+- for (i = 0; i < AT91_NR_UART; i++) {
++ for (i = 0; i < ATMEL_MAX_UART; i++) {
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[i]);
+ }
+diff --git a/arch/arm/mach-at91rm9200/generic.h b/arch/arm/mach-at91rm9200/generic.h
+index 7979d8a..694e411 100644
+--- a/arch/arm/mach-at91rm9200/generic.h
++++ b/arch/arm/mach-at91rm9200/generic.h
+@@ -8,18 +8,17 @@
+ * published by the Free Software Foundation.
+ */
+
++ /* Processors */
++extern void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks);
++
+ /* Interrupts */
+-extern void __init at91rm9200_init_irq(unsigned int priority[]);
++extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
+ extern void __init at91_aic_init(unsigned int priority[]);
+-extern void __init at91_gpio_irq_setup(unsigned banks);
+
+ /* Timer */
+ struct sys_timer;
+ extern struct sys_timer at91rm9200_timer;
+
+- /* Memory Map */
+-extern void __init at91rm9200_map_io(void);
+-
+ /* Clocks */
+ extern int __init at91_clock_init(unsigned long main_clock);
+ struct device;
+@@ -29,3 +28,14 @@ extern void __init at91_clock_associate(
+ extern void at91_irq_suspend(void);
+ extern void at91_irq_resume(void);
+
++ /* GPIO */
++#define AT91RM9200_PQFP 3 /* AT91RM9200 PQFP package has 3 banks */
++#define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */
++
++struct at91_gpio_bank {
++ unsigned short id; /* peripheral ID */
++ unsigned long offset; /* offset from system peripheral base */
++ struct clk *clock; /* associated clock */
++};
++extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
++extern void __init at91_gpio_irq_setup(void);
+diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c
+index cec199f..7467d64 100644
+--- a/arch/arm/mach-at91rm9200/gpio.c
++++ b/arch/arm/mach-at91rm9200/gpio.c
+@@ -9,6 +9,7 @@
+ * (at your option) any later version.
+ */
+
++#include <linux/clk.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+@@ -20,12 +21,12 @@
+ #include <asm/hardware.h>
+ #include <asm/arch/gpio.h>
+
+-static const u32 pio_controller_offset[4] = {
+- AT91_PIOA,
+- AT91_PIOB,
+- AT91_PIOC,
+- AT91_PIOD,
+-};
++#include "generic.h"
++
++
++static struct at91_gpio_bank *gpio;
++static int gpio_banks;
++
+
+ static inline void __iomem *pin_to_controller(unsigned pin)
+ {
+@@ -33,8 +34,8 @@ static inline void __iomem *pin_to_contr
+
+ pin -= PIN_BASE;
+ pin /= 32;
+- if (likely(pin < BGA_GPIO_BANKS))
+- return sys_base + pio_controller_offset[pin];
++ if (likely(pin < gpio_banks))
++ return sys_base + gpio[pin].offset;
+
+ return NULL;
+ }
+@@ -179,7 +180,6 @@ EXPORT_SYMBOL(at91_set_multi_drive);
+
+ /*--------------------------------------------------------------------------*/
+
+-
+ /*
+ * assuming the pin is muxed as a gpio output, set its value.
+ */
+@@ -216,8 +216,8 @@ EXPORT_SYMBOL(at91_get_gpio_value);
+
+ #ifdef CONFIG_PM
+
+-static u32 wakeups[BGA_GPIO_BANKS];
+-static u32 backups[BGA_GPIO_BANKS];
++static u32 wakeups[MAX_GPIO_BANKS];
++static u32 backups[MAX_GPIO_BANKS];
+
+ static int gpio_irq_set_wake(unsigned pin, unsigned state)
+ {
+@@ -226,7 +226,7 @@ static int gpio_irq_set_wake(unsigned pi
+ pin -= PIN_BASE;
+ pin /= 32;
+
+- if (unlikely(pin >= BGA_GPIO_BANKS))
++ if (unlikely(pin >= MAX_GPIO_BANKS))
+ return -EINVAL;
+
+ if (state)
+@@ -241,8 +241,8 @@ void at91_gpio_suspend(void)
+ {
+ int i;
+
+- for (i = 0; i < BGA_GPIO_BANKS; i++) {
+- u32 pio = pio_controller_offset[i];
++ for (i = 0; i < gpio_banks; i++) {
++ u32 pio = gpio[i].offset;
+
+ /*
+ * Note: drivers should have disabled GPIO interrupts that
+@@ -257,14 +257,14 @@ void at91_gpio_suspend(void)
+ * first place!
+ */
+ backups[i] = at91_sys_read(pio + PIO_IMR);
+- at91_sys_write(pio_controller_offset[i] + PIO_IDR, backups[i]);
+- at91_sys_write(pio_controller_offset[i] + PIO_IER, wakeups[i]);
++ at91_sys_write(pio + PIO_IDR, backups[i]);
++ at91_sys_write(pio + PIO_IER, wakeups[i]);
+
+ if (!wakeups[i]) {
+- disable_irq_wake(AT91_ID_PIOA + i);
+- at91_sys_write(AT91_PMC_PCDR, 1 << (AT91_ID_PIOA + i));
++ disable_irq_wake(gpio[i].id);
++ at91_sys_write(AT91_PMC_PCDR, 1 << gpio[i].id);
+ } else {
+- enable_irq_wake(AT91_ID_PIOA + i);
++ enable_irq_wake(gpio[i].id);
+ #ifdef CONFIG_PM_DEBUG
+ printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]);
+ #endif
+@@ -276,16 +276,13 @@ void at91_gpio_resume(void)
+ {
+ int i;
+
+- for (i = 0; i < BGA_GPIO_BANKS; i++) {
+- at91_sys_write(pio_controller_offset[i] + PIO_IDR, wakeups[i]);
+- at91_sys_write(pio_controller_offset[i] + PIO_IER, backups[i]);
+- }
++ for (i = 0; i < gpio_banks; i++) {
++ u32 pio = gpio[i].offset;
+
+- at91_sys_write(AT91_PMC_PCER,
+- (1 << AT91_ID_PIOA)
+- | (1 << AT91_ID_PIOB)
+- | (1 << AT91_ID_PIOC)
+- | (1 << AT91_ID_PIOD));
++ at91_sys_write(pio + PIO_IDR, wakeups[i]);
++ at91_sys_write(pio + PIO_IER, backups[i]);
++ at91_sys_write(AT91_PMC_PCER, 1 << gpio[i].id);
++ }
+ }
+
+ #else
+@@ -335,7 +332,7 @@ static struct irq_chip gpio_irqchip = {
+ .set_wake = gpio_irq_set_wake,
+ };
+
+-static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs)
++static void gpio_irq_handler(unsigned irq, struct irqdesc *desc)
+ {
+ unsigned pin;
+ struct irqdesc *gpio;
+@@ -366,7 +363,7 @@ static void gpio_irq_handler(unsigned ir
+ gpio_irq_mask(pin);
+ }
+ else
+- desc_handle_irq(pin, gpio, regs);
++ desc_handle_irq(pin, gpio);
+ }
+ pin++;
+ gpio++;
+@@ -377,20 +374,25 @@ static void gpio_irq_handler(unsigned ir
+ /* now it may re-trigger */
+ }
+
+-/* call this from board-specific init_irq */
+-void __init at91_gpio_irq_setup(unsigned banks)
++/*--------------------------------------------------------------------------*/
++
++/*
++ * Called from the processor-specific init to enable GPIO interrupt support.
++ */
++void __init at91_gpio_irq_setup(void)
+ {
+- unsigned pioc, pin, id;
++ unsigned pioc, pin;
+
+- if (banks > 4)
+- banks = 4;
+- for (pioc = 0, pin = PIN_BASE, id = AT91_ID_PIOA;
+- pioc < banks;
+- pioc++, id++) {
++ for (pioc = 0, pin = PIN_BASE;
++ pioc < gpio_banks;
++ pioc++) {
+ void __iomem *controller;
++ unsigned id = gpio[pioc].id;
+ unsigned i;
+
+- controller = (void __iomem *) AT91_VA_BASE_SYS + pio_controller_offset[pioc];
++ clk_enable(gpio[pioc].clock); /* enable PIO controller's clock */
++
++ controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset;
+ __raw_writel(~0, controller + PIO_IDR);
+
+ set_irq_data(id, (void *) pin);
+@@ -408,5 +410,16 @@ void __init at91_gpio_irq_setup(unsigned
+
+ set_irq_chained_handler(id, gpio_irq_handler);
+ }
+- pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, banks);
++ pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
++}
++
++/*
++ * Called from the processor-specific init to enable GPIO pin support.
++ */
++void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
++{
++ BUG_ON(nr_banks > MAX_GPIO_BANKS);
++
++ gpio = data;
++ gpio_banks = nr_banks;
+ }
+diff --git a/arch/arm/mach-at91rm9200/irq.c b/arch/arm/mach-at91rm9200/irq.c
+index c3a5e77..3e48811 100644
+--- a/arch/arm/mach-at91rm9200/irq.c
++++ b/arch/arm/mach-at91rm9200/irq.c
+@@ -34,8 +34,6 @@
+ #include <asm/mach/irq.h>
+ #include <asm/mach/map.h>
+
+-#include "generic.h"
+-
+
+ static void at91_aic_mask_irq(unsigned int irq)
+ {
+@@ -61,12 +59,12 @@ static int at91_aic_set_type(unsigned ir
+ srctype = AT91_AIC_SRCTYPE_RISING;
+ break;
+ case IRQT_LOW:
+- if ((irq > AT91_ID_FIQ) && (irq < AT91_ID_IRQ0)) /* only supported on external interrupts */
++ if ((irq > AT91_ID_FIQ) && (irq < AT91RM9200_ID_IRQ0)) /* only supported on external interrupts */
+ return -EINVAL;
+ srctype = AT91_AIC_SRCTYPE_LOW;
+ break;
+ case IRQT_FALLING:
+- if ((irq > AT91_ID_FIQ) && (irq < AT91_ID_IRQ0)) /* only supported on external interrupts */
++ if ((irq > AT91_ID_FIQ) && (irq < AT91RM9200_ID_IRQ0)) /* only supported on external interrupts */
+ return -EINVAL;
+ srctype = AT91_AIC_SRCTYPE_FALLING;
+ break;
+diff --git a/arch/arm/mach-at91rm9200/pm.c b/arch/arm/mach-at91rm9200/pm.c
+index 47e5480..32c95d8 100644
+--- a/arch/arm/mach-at91rm9200/pm.c
++++ b/arch/arm/mach-at91rm9200/pm.c
+@@ -123,13 +123,13 @@ static int at91_pm_enter(suspend_state_t
+ (at91_sys_read(AT91_PMC_PCSR)
+ | (1 << AT91_ID_FIQ)
+ | (1 << AT91_ID_SYS)
+- | (1 << AT91_ID_IRQ0)
+- | (1 << AT91_ID_IRQ1)
+- | (1 << AT91_ID_IRQ2)
+- | (1 << AT91_ID_IRQ3)
+- | (1 << AT91_ID_IRQ4)
+- | (1 << AT91_ID_IRQ5)
+- | (1 << AT91_ID_IRQ6))
++ | (1 << AT91RM9200_ID_IRQ0)
++ | (1 << AT91RM9200_ID_IRQ1)
++ | (1 << AT91RM9200_ID_IRQ2)
++ | (1 << AT91RM9200_ID_IRQ3)
++ | (1 << AT91RM9200_ID_IRQ4)
++ | (1 << AT91RM9200_ID_IRQ5)
++ | (1 << AT91RM9200_ID_IRQ6))
+ & at91_sys_read(AT91_AIC_IMR),
+ state);
+
+diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
+index a071eac..428493d 100644
+--- a/arch/arm/mach-clps711x/time.c
++++ b/arch/arm/mach-clps711x/time.c
+@@ -48,10 +48,10 @@ static unsigned long clps711x_gettimeoff
+ * IRQ handler for the timer
+ */
+ static irqreturn_t
+-p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++p720t_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
+index 92eaebd..fb10cf2 100644
+--- a/arch/arm/mach-clps7500/core.c
++++ b/arch/arm/mach-clps7500/core.c
+@@ -292,11 +292,11 @@ extern void ioctime_init(void);
+ extern unsigned long ioc_timer_gettimeoffset(void);
+
+ static irqreturn_t
+-clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++clps7500_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+- timer_tick(regs);
++ timer_tick();
+
+ /* Why not using do_leds interface?? */
+ {
+diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
+index 70dd12e..90103ab 100644
+--- a/arch/arm/mach-ebsa110/core.c
++++ b/arch/arm/mach-ebsa110/core.c
+@@ -174,7 +174,7 @@ static unsigned long ebsa110_gettimeoffs
+ }
+
+ static irqreturn_t
+-ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++ebsa110_timer_interrupt(int irq, void *dev_id)
+ {
+ u32 count;
+
+@@ -190,7 +190,7 @@ ebsa110_timer_interrupt(int irq, void *d
+ __raw_writeb(count & 0xff, PIT_T1);
+ __raw_writeb(count >> 8, PIT_T1);
+
+- timer_tick(regs);
++ timer_tick();
+
+ write_sequnlock(&xtime_lock);
+
+diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
+index f1b7400..e346b03 100644
+--- a/arch/arm/mach-ep93xx/Kconfig
++++ b/arch/arm/mach-ep93xx/Kconfig
+@@ -15,6 +15,12 @@ config MACH_EDB9302
+ Say 'Y' here if you want your kernel to support the Cirrus
+ Logic EDB9302 Evaluation Board.
+
++config MACH_EDB9312
++ bool "Support Cirrus Logic EDB9312"
++ help
++ Say 'Y' here if you want your kernel to support the Cirrus
++ Logic EDB9312 Evaluation Board.
++
+ config MACH_EDB9315
+ bool "Support Cirrus Logic EDB9315"
+ help
+diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile
+index 1f5a6b0..c2eb18b 100644
+--- a/arch/arm/mach-ep93xx/Makefile
++++ b/arch/arm/mach-ep93xx/Makefile
+@@ -7,6 +7,7 @@ obj-n :=
+ obj- :=
+
+ obj-$(CONFIG_MACH_EDB9302) += edb9302.o
++obj-$(CONFIG_MACH_EDB9312) += edb9312.o
+ obj-$(CONFIG_MACH_EDB9315) += edb9315.o
+ obj-$(CONFIG_MACH_EDB9315A) += edb9315a.o
+ obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o
+diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
+index a87a784..e3fd1ab 100644
+--- a/arch/arm/mach-ep93xx/core.c
++++ b/arch/arm/mach-ep93xx/core.c
+@@ -97,7 +97,7 @@ static unsigned int last_jiffy_time;
+
+ #define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
+
+-static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static int ep93xx_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+@@ -106,7 +106,7 @@ static int ep93xx_timer_interrupt(int ir
+ (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
+ >= TIMER4_TICKS_PER_JIFFY) {
+ last_jiffy_time += TIMER4_TICKS_PER_JIFFY;
+- timer_tick(regs);
++ timer_tick();
+ }
+
+ write_sequnlock(&xtime_lock);
+@@ -245,7 +245,7 @@ EXPORT_SYMBOL(gpio_line_set);
+ * EP93xx IRQ handling
+ *************************************************************************/
+ static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
+- struct irqdesc *desc, struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ unsigned char status;
+ int i;
+@@ -254,7 +254,7 @@ static void ep93xx_gpio_ab_irq_handler(u
+ for (i = 0; i < 8; i++) {
+ if (status & (1 << i)) {
+ desc = irq_desc + IRQ_EP93XX_GPIO(0) + i;
+- desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc, regs);
++ desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc);
+ }
+ }
+
+@@ -262,7 +262,7 @@ static void ep93xx_gpio_ab_irq_handler(u
+ for (i = 0; i < 8; i++) {
+ if (status & (1 << i)) {
+ desc = irq_desc + IRQ_EP93XX_GPIO(8) + i;
+- desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc, regs);
++ desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc);
+ }
+ }
+ }
+diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c
+index 62a8efd..0315615 100644
+--- a/arch/arm/mach-ep93xx/edb9302.c
++++ b/arch/arm/mach-ep93xx/edb9302.c
+@@ -10,7 +10,6 @@
+ * your option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c
+new file mode 100644
+index 0000000..e310e4d
+--- /dev/null
++++ b/arch/arm/mach-ep93xx/edb9312.c
+@@ -0,0 +1,62 @@
++/*
++ * arch/arm/mach-ep93xx/edb9312.c
++ * Cirrus Logic EDB9312 support.
++ *
++ * Copyright (C) 2006 Infosys Technologies Limited
++ * Toufeeq Hussain <toufeeq_hussain at infosys.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/mm.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++
++static struct physmap_flash_data edb9312_flash_data = {
++ .width = 4,
++};
++
++static struct resource edb9312_flash_resource = {
++ .start = 0x60000000,
++ .end = 0x61ffffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device edb9312_flash = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &edb9312_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &edb9312_flash_resource,
++};
++
++static void __init edb9312_init_machine(void)
++{
++ ep93xx_init_devices();
++ platform_device_register(&edb9312_flash);
++}
++
++MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
++ /* Maintainer: Toufeeq Hussain <toufeeq_hussain at infosys.com> */
++ .phys_io = EP93XX_APB_PHYS_BASE,
++ .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
++ .boot_params = 0x00000100,
++ .map_io = ep93xx_map_io,
++ .init_irq = ep93xx_init_irq,
++ .timer = &ep93xx_timer,
++ .init_machine = edb9312_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
+index ef7482f..249ca9e 100644
+--- a/arch/arm/mach-ep93xx/edb9315.c
++++ b/arch/arm/mach-ep93xx/edb9315.c
+@@ -10,7 +10,6 @@
+ * your option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c
+index bfefdaa..7ca0e61 100644
+--- a/arch/arm/mach-ep93xx/edb9315a.c
++++ b/arch/arm/mach-ep93xx/edb9315a.c
+@@ -10,7 +10,6 @@
+ * your option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/mm.h>
+@@ -44,10 +43,40 @@ static struct platform_device edb9315a_f
+ .resource = &edb9315a_flash_resource,
+ };
+
++static struct ep93xx_eth_data edb9315a_eth_data = {
++ .phy_id = 1,
++};
++
++static struct resource edb9315a_eth_resource[] = {
++ {
++ .start = EP93XX_ETHERNET_PHYS_BASE,
++ .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = IRQ_EP93XX_ETHERNET,
++ .end = IRQ_EP93XX_ETHERNET,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device edb9315a_eth_device = {
++ .name = "ep93xx-eth",
++ .id = -1,
++ .dev = {
++ .platform_data = &edb9315a_eth_data,
++ },
++ .num_resources = 2,
++ .resource = edb9315a_eth_resource,
++};
++
+ static void __init edb9315a_init_machine(void)
+ {
+ ep93xx_init_devices();
+ platform_device_register(&edb9315a_flash);
++
++ memcpy(edb9315a_eth_data.dev_addr,
++ (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
++ platform_device_register(&edb9315a_eth_device);
+ }
+
+ MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
+diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
+index e760fd4..694590a 100644
+--- a/arch/arm/mach-ep93xx/gesbc9312.c
++++ b/arch/arm/mach-ep93xx/gesbc9312.c
+@@ -43,10 +43,37 @@ static struct platform_device gesbc9312_
+ .resource = &gesbc9312_flash_resource,
+ };
+
++static struct ep93xx_eth_data gesbc9312_eth_data = {
++ .phy_id = 1,
++};
++
++static struct resource gesbc9312_eth_resource[] = {
++ {
++ .start = EP93XX_ETHERNET_PHYS_BASE,
++ .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = IRQ_EP93XX_ETHERNET,
++ .end = IRQ_EP93XX_ETHERNET,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device gesbc9312_eth_device = {
++ .name = "ep93xx-eth",
++ .id = -1,
++ .dev = {
++ .platform_data = &gesbc9312_eth_data,
++ },
++ .num_resources = 2,
++ .resource = gesbc9312_eth_resource,
++};
++
+ static void __init gesbc9312_init_machine(void)
+ {
+ ep93xx_init_devices();
+ platform_device_register(&gesbc9312_flash);
++ platform_device_register(&gesbc9312_eth_device);
+ }
+
+ MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
+diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
+index df315f2..3a4bf90 100644
+--- a/arch/arm/mach-ep93xx/ts72xx.c
++++ b/arch/arm/mach-ep93xx/ts72xx.c
+@@ -157,12 +157,42 @@ static struct platform_device ts72xx_rtc
+ .num_resources = 0,
+ };
+
++static struct ep93xx_eth_data ts72xx_eth_data = {
++ .phy_id = 1,
++};
++
++static struct resource ts72xx_eth_resource[] = {
++ {
++ .start = EP93XX_ETHERNET_PHYS_BASE,
++ .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = IRQ_EP93XX_ETHERNET,
++ .end = IRQ_EP93XX_ETHERNET,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device ts72xx_eth_device = {
++ .name = "ep93xx-eth",
++ .id = -1,
++ .dev = {
++ .platform_data = &ts72xx_eth_data,
++ },
++ .num_resources = 2,
++ .resource = ts72xx_eth_resource,
++};
++
+ static void __init ts72xx_init_machine(void)
+ {
+ ep93xx_init_devices();
+ if (board_is_ts7200())
+ platform_device_register(&ts72xx_flash);
+ platform_device_register(&ts72xx_rtc_device);
++
++ memcpy(ts72xx_eth_data.dev_addr,
++ (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
++ platform_device_register(&ts72xx_eth_device);
+ }
+
+ MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
+diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
+index 2af6108..fa6be87 100644
+--- a/arch/arm/mach-footbridge/dc21285-timer.c
++++ b/arch/arm/mach-footbridge/dc21285-timer.c
+@@ -28,13 +28,13 @@ static unsigned long timer1_gettimeoffse
+ }
+
+ static irqreturn_t
+-timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++timer1_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+ *CSR_TIMER1_CLR = 0;
+
+- timer_tick(regs);
++ timer_tick();
+
+ write_sequnlock(&xtime_lock);
+
+diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
+index 823e25d..1463330 100644
+--- a/arch/arm/mach-footbridge/dc21285.c
++++ b/arch/arm/mach-footbridge/dc21285.c
+@@ -16,6 +16,7 @@
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/ioport.h>
++#include <linux/irq.h>
+
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -69,16 +70,16 @@ dc21285_read_config(struct pci_bus *bus,
+ if (addr)
+ switch (size) {
+ case 1:
+- asm("ldr%?b %0, [%1, %2]"
+- : "=r" (v) : "r" (addr), "r" (where));
++ asm("ldrb %0, [%1, %2]"
++ : "=r" (v) : "r" (addr), "r" (where) : "cc");
+ break;
+ case 2:
+- asm("ldr%?h %0, [%1, %2]"
+- : "=r" (v) : "r" (addr), "r" (where));
++ asm("ldrh %0, [%1, %2]"
++ : "=r" (v) : "r" (addr), "r" (where) : "cc");
+ break;
+ case 4:
+- asm("ldr%? %0, [%1, %2]"
+- : "=r" (v) : "r" (addr), "r" (where));
++ asm("ldr %0, [%1, %2]"
++ : "=r" (v) : "r" (addr), "r" (where) : "cc");
+ break;
+ }
+
+@@ -103,16 +104,19 @@ dc21285_write_config(struct pci_bus *bus
+ if (addr)
+ switch (size) {
+ case 1:
+- asm("str%?b %0, [%1, %2]"
+- : : "r" (value), "r" (addr), "r" (where));
++ asm("strb %0, [%1, %2]"
++ : : "r" (value), "r" (addr), "r" (where)
++ : "cc");
+ break;
+ case 2:
+- asm("str%?h %0, [%1, %2]"
+- : : "r" (value), "r" (addr), "r" (where));
++ asm("strh %0, [%1, %2]"
++ : : "r" (value), "r" (addr), "r" (where)
++ : "cc");
+ break;
+ case 4:
+- asm("str%? %0, [%1, %2]"
+- : : "r" (value), "r" (addr), "r" (where));
++ asm("str %0, [%1, %2]"
++ : : "r" (value), "r" (addr), "r" (where)
++ : "cc");
+ break;
+ }
+
+@@ -151,7 +155,7 @@ static void dc21285_enable_error(unsigne
+ /*
+ * Warn on PCI errors.
+ */
+-static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dc21285_abort_irq(int irq, void *dev_id)
+ {
+ unsigned int cmd;
+ unsigned int status;
+@@ -162,7 +166,7 @@ static irqreturn_t dc21285_abort_irq(int
+
+ if (status & PCI_STATUS_REC_MASTER_ABORT) {
+ printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n",
+- instruction_pointer(regs));
++ instruction_pointer(get_irq_regs()));
+ cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
+ }
+
+@@ -181,7 +185,7 @@ static irqreturn_t dc21285_abort_irq(int
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dc21285_serr_irq(int irq, void *dev_id)
+ {
+ struct timer_list *timer = dev_id;
+ unsigned int cntl;
+@@ -203,7 +207,7 @@ static irqreturn_t dc21285_serr_irq(int
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dc21285_discard_irq(int irq, void *dev_id)
+ {
+ printk(KERN_DEBUG "PCI: discard timer expired\n");
+ *CSR_SA110_CNTL &= 0xffffde07;
+@@ -211,7 +215,7 @@ static irqreturn_t dc21285_discard_irq(i
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id)
+ {
+ unsigned int cmd;
+
+@@ -225,7 +229,7 @@ static irqreturn_t dc21285_dparity_irq(i
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dc21285_parity_irq(int irq, void *dev_id)
+ {
+ struct timer_list *timer = dev_id;
+ unsigned int cmd;
+diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c
+index 87448c2..888dedd 100644
+--- a/arch/arm/mach-footbridge/isa-irq.c
++++ b/arch/arm/mach-footbridge/isa-irq.c
+@@ -85,17 +85,17 @@ static struct irqchip isa_hi_chip = {
+ };
+
+ static void
+-isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++isa_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE;
+
+ if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) {
+- do_bad_IRQ(isa_irq, desc, regs);
++ do_bad_IRQ(isa_irq, desc);
+ return;
+ }
+
+ desc = irq_desc + isa_irq;
+- desc_handle_irq(isa_irq, desc, regs);
++ desc_handle_irq(isa_irq, desc);
+ }
+
+ static struct irqaction irq_cascade = {
+diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
+index c4810a4..d884a39 100644
+--- a/arch/arm/mach-footbridge/isa-timer.c
++++ b/arch/arm/mach-footbridge/isa-timer.c
+@@ -62,10 +62,10 @@ static unsigned long isa_gettimeoffset(v
+ }
+
+ static irqreturn_t
+-isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++isa_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
+index c096b45..4719229 100644
+--- a/arch/arm/mach-h720x/common.c
++++ b/arch/arm/mach-h720x/common.c
+@@ -101,14 +101,14 @@ static void inline unmask_gpio_irq(u32 i
+
+ static void
+ h720x_gpio_handler(unsigned int mask, unsigned int irq,
+- struct irqdesc *desc, struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ IRQDBG("%s irq: %d\n",__FUNCTION__,irq);
+ desc = irq_desc + irq;
+ while (mask) {
+ if (mask & 1) {
+ IRQDBG("handling irq %d\n", irq);
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ }
+ irq++;
+ desc++;
+@@ -117,63 +117,58 @@ h720x_gpio_handler(unsigned int mask, un
+ }
+
+ static void
+-h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT);
+ irq = IRQ_CHAINED_GPIOA(0);
+ IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+- h720x_gpio_handler(mask, irq, desc, regs);
++ h720x_gpio_handler(mask, irq, desc);
+ }
+
+ static void
+-h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+ mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT);
+ irq = IRQ_CHAINED_GPIOB(0);
+ IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+- h720x_gpio_handler(mask, irq, desc, regs);
++ h720x_gpio_handler(mask, irq, desc);
+ }
+
+ static void
+-h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT);
+ irq = IRQ_CHAINED_GPIOC(0);
+ IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+- h720x_gpio_handler(mask, irq, desc, regs);
++ h720x_gpio_handler(mask, irq, desc);
+ }
+
+ static void
+-h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT);
+ irq = IRQ_CHAINED_GPIOD(0);
+ IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+- h720x_gpio_handler(mask, irq, desc, regs);
++ h720x_gpio_handler(mask, irq, desc);
+ }
+
+ #ifdef CONFIG_CPU_H7202
+ static void
+-h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT);
+ irq = IRQ_CHAINED_GPIOE(0);
+ IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+- h720x_gpio_handler(mask, irq, desc, regs);
++ h720x_gpio_handler(mask, irq, desc);
+ }
+ #endif
+
+diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
+index a9a8255..13f76bd 100644
+--- a/arch/arm/mach-h720x/cpu-h7201.c
++++ b/arch/arm/mach-h720x/cpu-h7201.c
+@@ -27,12 +27,12 @@
+ * Timer interrupt handler
+ */
+ static irqreturn_t
+-h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++h7201_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+ CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
+- timer_tick(regs);
++ timer_tick();
+
+ write_sequnlock(&xtime_lock);
+
+diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
+index da678d1..06fecae 100644
+--- a/arch/arm/mach-h720x/cpu-h7202.c
++++ b/arch/arm/mach-h720x/cpu-h7202.c
+@@ -106,8 +106,7 @@ static struct platform_device *devices[]
+ * we have to handle all timer interrupts in one place.
+ */
+ static void
+-h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+@@ -115,7 +114,7 @@ h7202_timerx_demux_handler(unsigned int
+
+ if ( mask & TSTAT_T0INT ) {
+ write_seqlock(&xtime_lock);
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+ if( mask == TSTAT_T0INT )
+ return;
+@@ -126,7 +125,7 @@ h7202_timerx_demux_handler(unsigned int
+ desc = irq_desc + irq;
+ while (mask) {
+ if (mask & 1)
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ irq++;
+ desc++;
+ mask >>= 1;
+@@ -137,9 +136,9 @@ h7202_timerx_demux_handler(unsigned int
+ * Timer interrupt handler
+ */
+ static irqreturn_t
+-h7202_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++h7202_timer_interrupt(int irq, void *dev_id)
+ {
+- h7202_timerx_demux_handler(0, NULL, regs);
++ h7202_timerx_demux_handler(0, NULL);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
+index 3657887..6d50d85 100644
+--- a/arch/arm/mach-imx/dma.c
++++ b/arch/arm/mach-imx/dma.c
+@@ -279,8 +279,8 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
+ */
+ int
+ imx_dma_setup_handlers(imx_dmach_t dma_ch,
+- void (*irq_handler) (int, void *, struct pt_regs *),
+- void (*err_handler) (int, void *, struct pt_regs *, int),
++ void (*irq_handler) (int, void *),
++ void (*err_handler) (int, void *, int),
+ void *data)
+ {
+ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
+@@ -461,7 +461,7 @@ imx_dma_request_by_prio(imx_dmach_t * pd
+ return -ENODEV;
+ }
+
+-static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_err_handler(int irq, void *dev_id)
+ {
+ int i, disr = DISR;
+ struct imx_dma_channel *channel;
+@@ -500,7 +500,7 @@ static irqreturn_t dma_err_handler(int i
+ /*imx_dma_channels[i].sg = NULL;*/
+
+ if (channel->name && channel->err_handler) {
+- channel->err_handler(i, channel->data, regs, errcode);
++ channel->err_handler(i, channel->data, errcode);
+ continue;
+ }
+
+@@ -517,7 +517,7 @@ static irqreturn_t dma_err_handler(int i
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+ {
+ int i, disr = DISR;
+
+@@ -536,7 +536,7 @@ static irqreturn_t dma_irq_handler(int i
+ } else {
+ if (channel->irq_handler)
+ channel->irq_handler(i,
+- channel->data, regs);
++ channel->data);
+ }
+ } else {
+ /*
+diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
+index 2688bd8..368b13b 100644
+--- a/arch/arm/mach-imx/irq.c
++++ b/arch/arm/mach-imx/irq.c
+@@ -146,13 +146,13 @@ imx_gpio_unmask_irq(unsigned int irq)
+
+ static void
+ imx_gpio_handler(unsigned int mask, unsigned int irq,
+- struct irqdesc *desc, struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ desc = irq_desc + irq;
+ while (mask) {
+ if (mask & 1) {
+ DEBUG_IRQ("handling irq %d\n", irq);
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ }
+ irq++;
+ desc++;
+@@ -161,47 +161,43 @@ imx_gpio_handler(unsigned int mask, unsi
+ }
+
+ static void
+-imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = ISR(0);
+ irq = IRQ_GPIOA(0);
+- imx_gpio_handler(mask, irq, desc, regs);
++ imx_gpio_handler(mask, irq, desc);
+ }
+
+ static void
+-imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = ISR(1);
+ irq = IRQ_GPIOB(0);
+- imx_gpio_handler(mask, irq, desc, regs);
++ imx_gpio_handler(mask, irq, desc);
+ }
+
+ static void
+-imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = ISR(2);
+ irq = IRQ_GPIOC(0);
+- imx_gpio_handler(mask, irq, desc, regs);
++ imx_gpio_handler(mask, irq, desc);
+ }
+
+ static void
+-imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int mask, irq;
+
+ mask = ISR(3);
+ irq = IRQ_GPIOD(0);
+- imx_gpio_handler(mask, irq, desc, regs);
++ imx_gpio_handler(mask, irq, desc);
+ }
+
+ static struct irq_chip imx_internal_chip = {
+diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
+index 471c1db..cf30803 100644
+--- a/arch/arm/mach-imx/leds.c
++++ b/arch/arm/mach-imx/leds.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-imx/leds.h
++ * linux/arch/arm/mach-imx/leds.c
+ *
+ * Copyright (C) 2004 Sascha Hauer <sascha at saschahauer.de>
+ *
+diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
+index 83fa21e..49dc1c1 100644
+--- a/arch/arm/mach-imx/leds.h
++++ b/arch/arm/mach-imx/leds.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-arm/arch-imx/leds.h
++ * arch/arm/mach-imx/leds.h
+ *
+ * Copyright (c) 2004 Sascha Hauer <sascha at saschahauer.de>
+ *
+diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
+index 6ed7523..8ae4a2c 100644
+--- a/arch/arm/mach-imx/time.c
++++ b/arch/arm/mach-imx/time.c
+@@ -56,7 +56,7 @@ static unsigned long imx_gettimeoffset(v
+ * IRQ handler for the timer
+ */
+ static irqreturn_t
+-imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++imx_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+@@ -64,7 +64,7 @@ imx_timer_interrupt(int irq, void *dev_i
+ if (IMX_TSTAT(TIMER_BASE))
+ IMX_TSTAT(TIMER_BASE) = 0;
+
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
+index 42021fd..8d880cb 100644
+--- a/arch/arm/mach-integrator/core.c
++++ b/arch/arm/mach-integrator/core.c
+@@ -248,7 +248,7 @@ unsigned long integrator_gettimeoffset(v
+ * IRQ handler for the timer
+ */
+ static irqreturn_t
+-integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++integrator_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+@@ -262,7 +262,7 @@ integrator_timer_interrupt(int irq, void
+ * primary CPU
+ */
+ if (hard_smp_processor_id() == 0) {
+- timer_tick(regs);
++ timer_tick();
+ #ifdef CONFIG_SMP
+ smp_send_timer();
+ #endif
+@@ -272,7 +272,7 @@ integrator_timer_interrupt(int irq, void
+ /*
+ * this is the ARM equivalent of the APIC timer interrupt
+ */
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif /* CONFIG_SMP */
+
+ write_sequnlock(&xtime_lock);
+diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
+index 678b6ba..771b65b 100644
+--- a/arch/arm/mach-integrator/integrator_cp.c
++++ b/arch/arm/mach-integrator/integrator_cp.c
+@@ -202,12 +202,12 @@ static struct irq_chip sic_chip = {
+ };
+
+ static void
+-sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++sic_handle_irq(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
+
+ if (status == 0) {
+- do_bad_IRQ(irq, desc, regs);
++ do_bad_IRQ(irq, desc);
+ return;
+ }
+
+@@ -218,7 +218,7 @@ sic_handle_irq(unsigned int irq, struct
+ irq += IRQ_SIC_START;
+
+ desc = irq_desc + irq;
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ } while (status);
+ }
+
+diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
+index 4418f6d..fb8c6d9 100644
+--- a/arch/arm/mach-integrator/pci_v3.c
++++ b/arch/arm/mach-integrator/pci_v3.c
+@@ -440,9 +440,10 @@ v3_pci_fault(unsigned long addr, unsigne
+ return 1;
+ }
+
+-static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t v3_irq(int irq, void *devid)
+ {
+ #ifdef CONFIG_DEBUG_LL
++ struct pt_regs *regs = get_irq_regs();
+ unsigned long pc = instruction_pointer(regs);
+ unsigned long instr = *(unsigned long *)pc;
+ char buf[128];
+diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
+index ee49cf7..5278f58 100644
+--- a/arch/arm/mach-integrator/time.c
++++ b/arch/arm/mach-integrator/time.c
+@@ -96,8 +96,7 @@ static struct rtc_ops rtc_ops = {
+ .set_alarm = integrator_rtc_set_alarm,
+ };
+
+-static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id)
+ {
+ writel(0, rtc_base + RTC_EOI);
+ return IRQ_HANDLED;
+diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig
+new file mode 100644
+index 0000000..c072d94
+--- /dev/null
++++ b/arch/arm/mach-iop32x/Kconfig
+@@ -0,0 +1,35 @@
++if ARCH_IOP32X
++
++menu "IOP32x Implementation Options"
++
++comment "IOP32x Platform Types"
++
++config MACH_GLANTANK
++ bool "Enable support for the IO-Data GLAN Tank"
++ help
++ Say Y here if you want to run your kernel on the GLAN Tank
++ NAS appliance or machines from IO-Data's HDL-Gxxx, HDL-GWxxx
++ and HDL-GZxxx series.
++
++config ARCH_IQ80321
++ bool "Enable support for IQ80321"
++ help
++ Say Y here if you want to run your kernel on the Intel IQ80321
++ evaluation kit for the IOP321 processor.
++
++config ARCH_IQ31244
++ bool "Enable support for EP80219/IQ31244"
++ help
++ Say Y here if you want to run your kernel on the Intel EP80219
++ evaluation kit for the Intel 80219 processor (a IOP321 variant)
++ or the IQ31244 evaluation kit for the IOP321 processor.
++
++config MACH_N2100
++ bool "Enable support for the Thecus n2100"
++ help
++ Say Y here if you want to run your kernel on the Thecus n2100
++ NAS appliance.
++
++endmenu
++
++endif
+diff --git a/arch/arm/mach-iop32x/Makefile b/arch/arm/mach-iop32x/Makefile
+new file mode 100644
+index 0000000..7b05b37
+--- /dev/null
++++ b/arch/arm/mach-iop32x/Makefile
+@@ -0,0 +1,13 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y := irq.o
++obj-m :=
++obj-n :=
++obj- :=
++
++obj-$(CONFIG_MACH_GLANTANK) += glantank.o
++obj-$(CONFIG_ARCH_IQ80321) += iq80321.o
++obj-$(CONFIG_ARCH_IQ31244) += iq31244.o
++obj-$(CONFIG_MACH_N2100) += n2100.o
+diff --git a/arch/arm/mach-iop32x/Makefile.boot b/arch/arm/mach-iop32x/Makefile.boot
+new file mode 100644
+index 0000000..47000dc
+--- /dev/null
++++ b/arch/arm/mach-iop32x/Makefile.boot
+@@ -0,0 +1,3 @@
++ zreladdr-y := 0xa0008000
++params_phys-y := 0xa0000100
++initrd_phys-y := 0xa0800000
+diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
+new file mode 100644
+index 0000000..b9b7650
+--- /dev/null
++++ b/arch/arm/mach-iop32x/glantank.c
+@@ -0,0 +1,195 @@
++/*
++ * arch/arm/mach-iop32x/glantank.c
++ *
++ * Board support code for the GLAN Tank.
++ *
++ * Copyright (C) 2006 Martin Michlmayr <tbm at cyrius.com>
++ * Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.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 the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/page.h>
++
++/*
++ * GLAN Tank timer tick configuration.
++ */
++static void __init glantank_timer_init(void)
++{
++ /* 33.333 MHz crystal. */
++ iop3xx_init_time(200000000);
++}
++
++static struct sys_timer glantank_timer = {
++ .init = glantank_timer_init,
++ .offset = iop3xx_gettimeoffset,
++};
++
++
++/*
++ * GLAN Tank I/O.
++ */
++static struct map_desc glantank_io_desc[] __initdata = {
++ { /* on-board devices */
++ .virtual = GLANTANK_UART,
++ .pfn = __phys_to_pfn(GLANTANK_UART),
++ .length = 0x00100000,
++ .type = MT_DEVICE
++ },
++};
++
++void __init glantank_map_io(void)
++{
++ iop3xx_map_io();
++ iotable_init(glantank_io_desc, ARRAY_SIZE(glantank_io_desc));
++}
++
++
++/*
++ * GLAN Tank PCI.
++ */
++#define INTA IRQ_IOP32X_XINT0
++#define INTB IRQ_IOP32X_XINT1
++#define INTC IRQ_IOP32X_XINT2
++#define INTD IRQ_IOP32X_XINT3
++
++static inline int __init
++glantank_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ static int pci_irq_table[][4] = {
++ /*
++ * PCI IDSEL/INTPIN->INTLINE
++ * A B C D
++ */
++ {INTD, INTD, INTD, INTD}, /* UART (8250) */
++ {INTA, INTA, INTA, INTA}, /* Ethernet (E1000) */
++ {INTB, INTB, INTB, INTB}, /* IDE (AEC6280R) */
++ {INTC, INTC, INTC, INTC}, /* USB (NEC) */
++ };
++
++ BUG_ON(pin < 1 || pin > 4);
++
++ return pci_irq_table[slot % 4][pin - 1];
++}
++
++static struct hw_pci glantank_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = glantank_pci_map_irq,
++};
++
++static int __init glantank_pci_init(void)
++{
++ if (machine_is_glantank())
++ pci_common_init(&glantank_pci);
++
++ return 0;
++}
++
++subsys_initcall(glantank_pci_init);
++
++
++/*
++ * GLAN Tank machine initialization.
++ */
++static struct physmap_flash_data glantank_flash_data = {
++ .width = 1,
++};
++
++static struct resource glantank_flash_resource = {
++ .start = 0xf0000000,
++ .end = 0xf007ffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device glantank_flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &glantank_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &glantank_flash_resource,
++};
++
++static struct plat_serial8250_port glantank_serial_port[] = {
++ {
++ .mapbase = GLANTANK_UART,
++ .membase = (char *)GLANTANK_UART,
++ .irq = IRQ_IOP32X_XINT3,
++ .flags = UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 1843200,
++ },
++ { },
++};
++
++static struct resource glantank_uart_resource = {
++ .start = GLANTANK_UART,
++ .end = GLANTANK_UART + 7,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device glantank_serial_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = glantank_serial_port,
++ },
++ .num_resources = 1,
++ .resource = &glantank_uart_resource,
++};
++
++static void glantank_power_off(void)
++{
++ __raw_writeb(0x01, 0xfe8d0004);
++
++ while (1)
++ ;
++}
++
++static void __init glantank_init_machine(void)
++{
++ platform_device_register(&iop3xx_i2c0_device);
++ platform_device_register(&iop3xx_i2c1_device);
++ platform_device_register(&glantank_flash_device);
++ platform_device_register(&glantank_serial_device);
++
++ pm_power_off = glantank_power_off;
++}
++
++MACHINE_START(GLANTANK, "GLAN Tank")
++ /* Maintainer: Lennert Buytenhek <buytenh at wantstofly.org> */
++ .phys_io = GLANTANK_UART,
++ .io_pg_offst = ((GLANTANK_UART) >> 18) & 0xfffc,
++ .boot_params = 0xa0000100,
++ .map_io = glantank_map_io,
++ .init_irq = iop32x_init_irq,
++ .timer = &glantank_timer,
++ .init_machine = glantank_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
+new file mode 100644
+index 0000000..be4aedf
+--- /dev/null
++++ b/arch/arm/mach-iop32x/iq31244.c
+@@ -0,0 +1,293 @@
++/*
++ * arch/arm/mach-iop32x/iq31244.c
++ *
++ * Board support code for the Intel EP80219 and IQ31244 platforms.
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ * Copyright 2003 (c) MontaVista, Software, Inc.
++ * Copyright (C) 2004 Intel 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 <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/pm.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++
++
++/*
++ * The EP80219 and IQ31244 use the same machine ID. To find out
++ * which of the two we're running on, we look at the processor ID.
++ */
++static int is_80219(void)
++{
++ extern int processor_id;
++ return !!((processor_id & 0xffffffe0) == 0x69052e20);
++}
++
++
++/*
++ * EP80219/IQ31244 timer tick configuration.
++ */
++static void __init iq31244_timer_init(void)
++{
++ if (is_80219()) {
++ /* 33.333 MHz crystal. */
++ iop3xx_init_time(200000000);
++ } else {
++ /* 33.000 MHz crystal. */
++ iop3xx_init_time(198000000);
++ }
++}
++
++static struct sys_timer iq31244_timer = {
++ .init = iq31244_timer_init,
++ .offset = iop3xx_gettimeoffset,
++};
++
++
++/*
++ * IQ31244 I/O.
++ */
++static struct map_desc iq31244_io_desc[] __initdata = {
++ { /* on-board devices */
++ .virtual = IQ31244_UART,
++ .pfn = __phys_to_pfn(IQ31244_UART),
++ .length = 0x00100000,
++ .type = MT_DEVICE,
++ },
++};
++
++void __init iq31244_map_io(void)
++{
++ iop3xx_map_io();
++ iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc));
++}
++
++
++/*
++ * EP80219/IQ31244 PCI.
++ */
++static inline int __init
++ep80219_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if (slot == 0) {
++ /* CFlash */
++ irq = IRQ_IOP32X_XINT1;
++ } else if (slot == 1) {
++ /* 82551 Pro 100 */
++ irq = IRQ_IOP32X_XINT0;
++ } else if (slot == 2) {
++ /* PCI-X Slot */
++ irq = IRQ_IOP32X_XINT3;
++ } else if (slot == 3) {
++ /* SATA */
++ irq = IRQ_IOP32X_XINT2;
++ } else {
++ printk(KERN_ERR "ep80219_pci_map_irq() called for unknown "
++ "device PCI:%d:%d:%d\n", dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ irq = -1;
++ }
++
++ return irq;
++}
++
++static struct hw_pci ep80219_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = ep80219_pci_map_irq,
++};
++
++static inline int __init
++iq31244_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if (slot == 0) {
++ /* CFlash */
++ irq = IRQ_IOP32X_XINT1;
++ } else if (slot == 1) {
++ /* SATA */
++ irq = IRQ_IOP32X_XINT2;
++ } else if (slot == 2) {
++ /* PCI-X Slot */
++ irq = IRQ_IOP32X_XINT3;
++ } else if (slot == 3) {
++ /* 82546 GigE */
++ irq = IRQ_IOP32X_XINT0;
++ } else {
++ printk(KERN_ERR "iq31244_pci_map_irq called for unknown "
++ "device PCI:%d:%d:%d\n", dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ irq = -1;
++ }
++
++ return irq;
++}
++
++static struct hw_pci iq31244_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = iq31244_pci_map_irq,
++};
++
++static int __init iq31244_pci_init(void)
++{
++ if (machine_is_iq31244()) {
++ if (is_80219()) {
++ pci_common_init(&ep80219_pci);
++ } else {
++ pci_common_init(&iq31244_pci);
++ }
++ }
++
++ return 0;
++}
++
++subsys_initcall(iq31244_pci_init);
++
++
++/*
++ * IQ31244 machine initialisation.
++ */
++static struct physmap_flash_data iq31244_flash_data = {
++ .width = 2,
++};
++
++static struct resource iq31244_flash_resource = {
++ .start = 0xf0000000,
++ .end = 0xf07fffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device iq31244_flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &iq31244_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &iq31244_flash_resource,
++};
++
++static struct plat_serial8250_port iq31244_serial_port[] = {
++ {
++ .mapbase = IQ31244_UART,
++ .membase = (char *)IQ31244_UART,
++ .irq = IRQ_IOP32X_XINT1,
++ .flags = UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 1843200,
++ },
++ { },
++};
++
++static struct resource iq31244_uart_resource = {
++ .start = IQ31244_UART,
++ .end = IQ31244_UART + 7,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device iq31244_serial_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = iq31244_serial_port,
++ },
++ .num_resources = 1,
++ .resource = &iq31244_uart_resource,
++};
++
++/*
++ * This function will send a SHUTDOWN_COMPLETE message to the PIC
++ * controller over I2C. We are not using the i2c subsystem since
++ * we are going to power off and it may be removed
++ */
++void ep80219_power_off(void)
++{
++ /*
++ * Send the Address byte w/ the start condition
++ */
++ *IOP3XX_IDBR1 = 0x60;
++ *IOP3XX_ICR1 = 0xE9;
++ mdelay(1);
++
++ /*
++ * Send the START_MSG byte w/ no start or stop condition
++ */
++ *IOP3XX_IDBR1 = 0x0F;
++ *IOP3XX_ICR1 = 0xE8;
++ mdelay(1);
++
++ /*
++ * Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or
++ * stop condition
++ */
++ *IOP3XX_IDBR1 = 0x03;
++ *IOP3XX_ICR1 = 0xE8;
++ mdelay(1);
++
++ /*
++ * Send an ignored byte w/ stop condition
++ */
++ *IOP3XX_IDBR1 = 0x00;
++ *IOP3XX_ICR1 = 0xEA;
++
++ while (1)
++ ;
++}
++
++static void __init iq31244_init_machine(void)
++{
++ platform_device_register(&iop3xx_i2c0_device);
++ platform_device_register(&iop3xx_i2c1_device);
++ platform_device_register(&iq31244_flash_device);
++ platform_device_register(&iq31244_serial_device);
++
++ if (is_80219())
++ pm_power_off = ep80219_power_off;
++}
++
++MACHINE_START(IQ31244, "Intel IQ31244")
++ /* Maintainer: Intel Corp. */
++ .phys_io = IQ31244_UART,
++ .io_pg_offst = ((IQ31244_UART) >> 18) & 0xfffc,
++ .boot_params = 0xa0000100,
++ .map_io = iq31244_map_io,
++ .init_irq = iop32x_init_irq,
++ .timer = &iq31244_timer,
++ .init_machine = iq31244_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
+new file mode 100644
+index 0000000..1f37b55
+--- /dev/null
++++ b/arch/arm/mach-iop32x/iq80321.c
+@@ -0,0 +1,193 @@
++/*
++ * arch/arm/mach-iop32x/iq80321.c
++ *
++ * Board support code for the Intel IQ80321 platform.
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ * Copyright (C) 2004 Intel 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 <linux/mm.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++
++/*
++ * IQ80321 timer tick configuration.
++ */
++static void __init iq80321_timer_init(void)
++{
++ /* 33.333 MHz crystal. */
++ iop3xx_init_time(200000000);
++}
++
++static struct sys_timer iq80321_timer = {
++ .init = iq80321_timer_init,
++ .offset = iop3xx_gettimeoffset,
++};
++
++
++/*
++ * IQ80321 I/O.
++ */
++static struct map_desc iq80321_io_desc[] __initdata = {
++ { /* on-board devices */
++ .virtual = IQ80321_UART,
++ .pfn = __phys_to_pfn(IQ80321_UART),
++ .length = 0x00100000,
++ .type = MT_DEVICE,
++ },
++};
++
++void __init iq80321_map_io(void)
++{
++ iop3xx_map_io();
++ iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc));
++}
++
++
++/*
++ * IQ80321 PCI.
++ */
++static inline int __init
++iq80321_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if ((slot == 2 || slot == 6) && pin == 1) {
++ /* PCI-X Slot INTA */
++ irq = IRQ_IOP32X_XINT2;
++ } else if ((slot == 2 || slot == 6) && pin == 2) {
++ /* PCI-X Slot INTA */
++ irq = IRQ_IOP32X_XINT3;
++ } else if ((slot == 2 || slot == 6) && pin == 3) {
++ /* PCI-X Slot INTA */
++ irq = IRQ_IOP32X_XINT0;
++ } else if ((slot == 2 || slot == 6) && pin == 4) {
++ /* PCI-X Slot INTA */
++ irq = IRQ_IOP32X_XINT1;
++ } else if (slot == 4 || slot == 8) {
++ /* Gig-E */
++ irq = IRQ_IOP32X_XINT0;
++ } else {
++ printk(KERN_ERR "iq80321_pci_map_irq() called for unknown "
++ "device PCI:%d:%d:%d\n", dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ irq = -1;
++ }
++
++ return irq;
++}
++
++static struct hw_pci iq80321_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = iq80321_pci_map_irq,
++};
++
++static int __init iq80321_pci_init(void)
++{
++ if (machine_is_iq80321())
++ pci_common_init(&iq80321_pci);
++
++ return 0;
++}
++
++subsys_initcall(iq80321_pci_init);
++
++
++/*
++ * IQ80321 machine initialisation.
++ */
++static struct physmap_flash_data iq80321_flash_data = {
++ .width = 1,
++};
++
++static struct resource iq80321_flash_resource = {
++ .start = 0xf0000000,
++ .end = 0xf07fffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device iq80321_flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &iq80321_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &iq80321_flash_resource,
++};
++
++static struct plat_serial8250_port iq80321_serial_port[] = {
++ {
++ .mapbase = IQ80321_UART,
++ .membase = (char *)IQ80321_UART,
++ .irq = IRQ_IOP32X_XINT1,
++ .flags = UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 1843200,
++ },
++ { },
++};
++
++static struct resource iq80321_uart_resource = {
++ .start = IQ80321_UART,
++ .end = IQ80321_UART + 7,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device iq80321_serial_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = iq80321_serial_port,
++ },
++ .num_resources = 1,
++ .resource = &iq80321_uart_resource,
++};
++
++static void __init iq80321_init_machine(void)
++{
++ platform_device_register(&iop3xx_i2c0_device);
++ platform_device_register(&iop3xx_i2c1_device);
++ platform_device_register(&iq80321_flash_device);
++ platform_device_register(&iq80321_serial_device);
++}
++
++MACHINE_START(IQ80321, "Intel IQ80321")
++ /* Maintainer: Intel Corp. */
++ .phys_io = IQ80321_UART,
++ .io_pg_offst = ((IQ80321_UART) >> 18) & 0xfffc,
++ .boot_params = 0xa0000100,
++ .map_io = iq80321_map_io,
++ .init_irq = iop32x_init_irq,
++ .timer = &iq80321_timer,
++ .init_machine = iq80321_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c
+new file mode 100644
+index 0000000..69d6302
+--- /dev/null
++++ b/arch/arm/mach-iop32x/irq.c
+@@ -0,0 +1,76 @@
++/*
++ * arch/arm/mach-iop32x/irq.c
++ *
++ * Generic IOP32X IRQ handling functionality
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ *
++ * 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/init.h>
++#include <linux/interrupt.h>
++#include <linux/list.h>
++#include <asm/mach/irq.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++
++static u32 iop32x_mask;
++
++static inline void intctl_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static inline void intstr_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c4, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static void
++iop32x_irq_mask(unsigned int irq)
++{
++ iop32x_mask &= ~(1 << irq);
++ intctl_write(iop32x_mask);
++}
++
++static void
++iop32x_irq_unmask(unsigned int irq)
++{
++ iop32x_mask |= 1 << irq;
++ intctl_write(iop32x_mask);
++}
++
++struct irq_chip ext_chip = {
++ .name = "IOP32x",
++ .ack = iop32x_irq_mask,
++ .mask = iop32x_irq_mask,
++ .unmask = iop32x_irq_unmask,
++};
++
++void __init iop32x_init_irq(void)
++{
++ int i;
++
++ intctl_write(0);
++ intstr_write(0);
++ if (machine_is_glantank() ||
++ machine_is_iq80321() ||
++ machine_is_iq31244() ||
++ machine_is_n2100())
++ *IOP3XX_PCIIRSR = 0x0f;
++
++ for (i = 0; i < NR_IRQS; i++) {
++ set_irq_chip(i, &ext_chip);
++ set_irq_handler(i, do_level_IRQ);
++ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
++ }
++}
+diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
+new file mode 100644
+index 0000000..2499a77
+--- /dev/null
++++ b/arch/arm/mach-iop32x/n2100.c
+@@ -0,0 +1,251 @@
++/*
++ * arch/arm/mach-iop32x/n2100.c
++ *
++ * Board support code for the Thecus N2100 platform.
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ * Copyright 2003 (c) MontaVista, Software, Inc.
++ * Copyright (C) 2004 Intel 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 <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/pm.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <linux/reboot.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++
++/*
++ * N2100 timer tick configuration.
++ */
++static void __init n2100_timer_init(void)
++{
++ /* 33.000 MHz crystal. */
++ iop3xx_init_time(198000000);
++}
++
++static struct sys_timer n2100_timer = {
++ .init = n2100_timer_init,
++ .offset = iop3xx_gettimeoffset,
++};
++
++
++/*
++ * N2100 I/O.
++ */
++static struct map_desc n2100_io_desc[] __initdata = {
++ { /* on-board devices */
++ .virtual = N2100_UART,
++ .pfn = __phys_to_pfn(N2100_UART),
++ .length = 0x00100000,
++ .type = MT_DEVICE
++ },
++};
++
++void __init n2100_map_io(void)
++{
++ iop3xx_map_io();
++ iotable_init(n2100_io_desc, ARRAY_SIZE(n2100_io_desc));
++}
++
++
++/*
++ * N2100 PCI.
++ */
++static inline int __init
++n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if (PCI_SLOT(dev->devfn) == 1) {
++ /* RTL8110SB #1 */
++ irq = IRQ_IOP32X_XINT0;
++ } else if (PCI_SLOT(dev->devfn) == 2) {
++ /* RTL8110SB #2 */
++ irq = IRQ_IOP32X_XINT3;
++ } else if (PCI_SLOT(dev->devfn) == 3) {
++ /* Sil3512 */
++ irq = IRQ_IOP32X_XINT2;
++ } else if (PCI_SLOT(dev->devfn) == 4 && pin == 1) {
++ /* VT6212 INTA */
++ irq = IRQ_IOP32X_XINT1;
++ } else if (PCI_SLOT(dev->devfn) == 4 && pin == 2) {
++ /* VT6212 INTB */
++ irq = IRQ_IOP32X_XINT0;
++ } else if (PCI_SLOT(dev->devfn) == 4 && pin == 3) {
++ /* VT6212 INTC */
++ irq = IRQ_IOP32X_XINT2;
++ } else if (PCI_SLOT(dev->devfn) == 5) {
++ /* Mini-PCI slot */
++ irq = IRQ_IOP32X_XINT3;
++ } else {
++ printk(KERN_ERR "n2100_pci_map_irq() called for unknown "
++ "device PCI:%d:%d:%d\n", dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ irq = -1;
++ }
++
++ return irq;
++}
++
++static struct hw_pci n2100_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = n2100_pci_map_irq,
++};
++
++static int __init n2100_pci_init(void)
++{
++ if (machine_is_n2100())
++ pci_common_init(&n2100_pci);
++
++ return 0;
++}
++
++subsys_initcall(n2100_pci_init);
++
++
++/*
++ * N2100 machine initialisation.
++ */
++static struct physmap_flash_data n2100_flash_data = {
++ .width = 2,
++};
++
++static struct resource n2100_flash_resource = {
++ .start = 0xf0000000,
++ .end = 0xf0ffffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device n2100_flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &n2100_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &n2100_flash_resource,
++};
++
++
++static struct plat_serial8250_port n2100_serial_port[] = {
++ {
++ .mapbase = N2100_UART,
++ .membase = (char *)N2100_UART,
++ .irq = 0,
++ .flags = UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 1843200,
++ },
++ { },
++};
++
++static struct resource n2100_uart_resource = {
++ .start = N2100_UART,
++ .end = N2100_UART + 7,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device n2100_serial_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = n2100_serial_port,
++ },
++ .num_resources = 1,
++ .resource = &n2100_uart_resource,
++};
++
++
++/*
++ * Pull PCA9532 GPIO #8 low to power off the machine.
++ */
++static void n2100_power_off(void)
++{
++ local_irq_disable();
++
++ /* Start condition, I2C address of PCA9532, write transaction. */
++ *IOP3XX_IDBR0 = 0xc0;
++ *IOP3XX_ICR0 = 0xe9;
++ mdelay(1);
++
++ /* Write address 0x08. */
++ *IOP3XX_IDBR0 = 0x08;
++ *IOP3XX_ICR0 = 0xe8;
++ mdelay(1);
++
++ /* Write data 0x01, stop condition. */
++ *IOP3XX_IDBR0 = 0x01;
++ *IOP3XX_ICR0 = 0xea;
++
++ while (1)
++ ;
++}
++
++
++static struct timer_list power_button_poll_timer;
++
++static void power_button_poll(unsigned long dummy)
++{
++ if (gpio_line_get(N2100_POWER_BUTTON) == 0) {
++ ctrl_alt_del();
++ return;
++ }
++
++ power_button_poll_timer.expires = jiffies + (HZ / 10);
++ add_timer(&power_button_poll_timer);
++}
++
++
++static void __init n2100_init_machine(void)
++{
++ platform_device_register(&iop3xx_i2c0_device);
++ platform_device_register(&n2100_flash_device);
++ platform_device_register(&n2100_serial_device);
++
++ pm_power_off = n2100_power_off;
++
++ init_timer(&power_button_poll_timer);
++ power_button_poll_timer.function = power_button_poll;
++ power_button_poll_timer.expires = jiffies + (HZ / 10);
++ add_timer(&power_button_poll_timer);
++}
++
++MACHINE_START(N2100, "Thecus N2100")
++ /* Maintainer: Lennert Buytenhek <buytenh at wantstofly.org> */
++ .phys_io = N2100_UART,
++ .io_pg_offst = ((N2100_UART) >> 18) & 0xfffc,
++ .boot_params = 0xa0000100,
++ .map_io = n2100_map_io,
++ .init_irq = iop32x_init_irq,
++ .timer = &n2100_timer,
++ .init_machine = n2100_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig
+new file mode 100644
+index 0000000..9aa016b
+--- /dev/null
++++ b/arch/arm/mach-iop33x/Kconfig
+@@ -0,0 +1,21 @@
++if ARCH_IOP33X
++
++menu "IOP33x Implementation Options"
++
++comment "IOP33x Platform Types"
++
++config ARCH_IQ80331
++ bool "Enable support for IQ80331"
++ help
++ Say Y here if you want to run your kernel on the Intel IQ80331
++ evaluation kit for the IOP331 chipset.
++
++config MACH_IQ80332
++ bool "Enable support for IQ80332"
++ help
++ Say Y here if you want to run your kernel on the Intel IQ80332
++ evaluation kit for the IOP332 chipset.
++
++endmenu
++
++endif
+diff --git a/arch/arm/mach-iop33x/Makefile b/arch/arm/mach-iop33x/Makefile
+new file mode 100644
+index 0000000..90081d8
+--- /dev/null
++++ b/arch/arm/mach-iop33x/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y := irq.o uart.o
++obj-m :=
++obj-n :=
++obj- :=
++
++obj-$(CONFIG_ARCH_IQ80331) += iq80331.o
++obj-$(CONFIG_MACH_IQ80332) += iq80332.o
+diff --git a/arch/arm/mach-iop33x/Makefile.boot b/arch/arm/mach-iop33x/Makefile.boot
+new file mode 100644
+index 0000000..67039c3
+--- /dev/null
++++ b/arch/arm/mach-iop33x/Makefile.boot
+@@ -0,0 +1,3 @@
++ zreladdr-y := 0x00008000
++params_phys-y := 0x00000100
++initrd_phys-y := 0x00800000
+diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
+new file mode 100644
+index 0000000..97a7b74
+--- /dev/null
++++ b/arch/arm/mach-iop33x/iq80331.c
+@@ -0,0 +1,148 @@
++/*
++ * arch/arm/mach-iop33x/iq80331.c
++ *
++ * Board support code for the Intel IQ80331 platform.
++ *
++ * Author: Dave Jiang <dave.jiang at intel.com>
++ * Copyright (C) 2003 Intel 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 <linux/mm.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++
++/*
++ * IQ80331 timer tick configuration.
++ */
++static void __init iq80331_timer_init(void)
++{
++ /* D-Step parts run at a higher internal bus frequency */
++ if (*IOP3XX_ATURID >= 0xa)
++ iop3xx_init_time(333000000);
++ else
++ iop3xx_init_time(266000000);
++}
++
++static struct sys_timer iq80331_timer = {
++ .init = iq80331_timer_init,
++ .offset = iop3xx_gettimeoffset,
++};
++
++
++/*
++ * IQ80331 PCI.
++ */
++static inline int __init
++iq80331_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if (slot == 1 && pin == 1) {
++ /* PCI-X Slot INTA */
++ irq = IRQ_IOP33X_XINT1;
++ } else if (slot == 1 && pin == 2) {
++ /* PCI-X Slot INTB */
++ irq = IRQ_IOP33X_XINT2;
++ } else if (slot == 1 && pin == 3) {
++ /* PCI-X Slot INTC */
++ irq = IRQ_IOP33X_XINT3;
++ } else if (slot == 1 && pin == 4) {
++ /* PCI-X Slot INTD */
++ irq = IRQ_IOP33X_XINT0;
++ } else if (slot == 2) {
++ /* GigE */
++ irq = IRQ_IOP33X_XINT2;
++ } else {
++ printk(KERN_ERR "iq80331_pci_map_irq() called for unknown "
++ "device PCI:%d:%d:%d\n", dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ irq = -1;
++ }
++
++ return irq;
++}
++
++static struct hw_pci iq80331_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = iq80331_pci_map_irq,
++};
++
++static int __init iq80331_pci_init(void)
++{
++ if (machine_is_iq80331())
++ pci_common_init(&iq80331_pci);
++
++ return 0;
++}
++
++subsys_initcall(iq80331_pci_init);
++
++
++/*
++ * IQ80331 machine initialisation.
++ */
++static struct physmap_flash_data iq80331_flash_data = {
++ .width = 1,
++};
++
++static struct resource iq80331_flash_resource = {
++ .start = 0xc0000000,
++ .end = 0xc07fffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device iq80331_flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &iq80331_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &iq80331_flash_resource,
++};
++
++static void __init iq80331_init_machine(void)
++{
++ platform_device_register(&iop3xx_i2c0_device);
++ platform_device_register(&iop3xx_i2c1_device);
++ platform_device_register(&iop33x_uart0_device);
++ platform_device_register(&iop33x_uart1_device);
++ platform_device_register(&iq80331_flash_device);
++}
++
++MACHINE_START(IQ80331, "Intel IQ80331")
++ /* Maintainer: Intel Corp. */
++ .phys_io = 0xfefff000,
++ .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc,
++ .boot_params = 0x00000100,
++ .map_io = iop3xx_map_io,
++ .init_irq = iop33x_init_irq,
++ .timer = &iq80331_timer,
++ .init_machine = iq80331_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
+new file mode 100644
+index 0000000..9887bfc
+--- /dev/null
++++ b/arch/arm/mach-iop33x/iq80332.c
+@@ -0,0 +1,148 @@
++/*
++ * arch/arm/mach-iop33x/iq80332.c
++ *
++ * Board support code for the Intel IQ80332 platform.
++ *
++ * Author: Dave Jiang <dave.jiang at intel.com>
++ * Copyright (C) 2004 Intel 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 <linux/mm.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++
++/*
++ * IQ80332 timer tick configuration.
++ */
++static void __init iq80332_timer_init(void)
++{
++ /* D-Step parts and the iop333 run at a higher internal bus frequency */
++ if (*IOP3XX_ATURID >= 0xa || *IOP3XX_ATUDID == 0x374)
++ iop3xx_init_time(333000000);
++ else
++ iop3xx_init_time(266000000);
++}
++
++static struct sys_timer iq80332_timer = {
++ .init = iq80332_timer_init,
++ .offset = iop3xx_gettimeoffset,
++};
++
++
++/*
++ * IQ80332 PCI.
++ */
++static inline int __init
++iq80332_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if (slot == 4 && pin == 1) {
++ /* PCI-X Slot INTA */
++ irq = IRQ_IOP33X_XINT0;
++ } else if (slot == 4 && pin == 2) {
++ /* PCI-X Slot INTB */
++ irq = IRQ_IOP33X_XINT1;
++ } else if (slot == 4 && pin == 3) {
++ /* PCI-X Slot INTC */
++ irq = IRQ_IOP33X_XINT2;
++ } else if (slot == 4 && pin == 4) {
++ /* PCI-X Slot INTD */
++ irq = IRQ_IOP33X_XINT3;
++ } else if (slot == 6) {
++ /* GigE */
++ irq = IRQ_IOP33X_XINT2;
++ } else {
++ printk(KERN_ERR "iq80332_pci_map_irq() called for unknown "
++ "device PCI:%d:%d:%d\n", dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ irq = -1;
++ }
++
++ return irq;
++}
++
++static struct hw_pci iq80332_pci __initdata = {
++ .swizzle = pci_std_swizzle,
++ .nr_controllers = 1,
++ .setup = iop3xx_pci_setup,
++ .preinit = iop3xx_pci_preinit,
++ .scan = iop3xx_pci_scan_bus,
++ .map_irq = iq80332_pci_map_irq,
++};
++
++static int __init iq80332_pci_init(void)
++{
++ if (machine_is_iq80332())
++ pci_common_init(&iq80332_pci);
++
++ return 0;
++}
++
++subsys_initcall(iq80332_pci_init);
++
++
++/*
++ * IQ80332 machine initialisation.
++ */
++static struct physmap_flash_data iq80332_flash_data = {
++ .width = 1,
++};
++
++static struct resource iq80332_flash_resource = {
++ .start = 0xc0000000,
++ .end = 0xc07fffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device iq80332_flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &iq80332_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &iq80332_flash_resource,
++};
++
++static void __init iq80332_init_machine(void)
++{
++ platform_device_register(&iop3xx_i2c0_device);
++ platform_device_register(&iop3xx_i2c1_device);
++ platform_device_register(&iop33x_uart0_device);
++ platform_device_register(&iop33x_uart1_device);
++ platform_device_register(&iq80332_flash_device);
++}
++
++MACHINE_START(IQ80332, "Intel IQ80332")
++ /* Maintainer: Intel Corp. */
++ .phys_io = 0xfefff000,
++ .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc,
++ .boot_params = 0x00000100,
++ .map_io = iop3xx_map_io,
++ .init_irq = iop33x_init_irq,
++ .timer = &iq80332_timer,
++ .init_machine = iq80332_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c
+new file mode 100644
+index 0000000..63304b3
+--- /dev/null
++++ b/arch/arm/mach-iop33x/irq.c
+@@ -0,0 +1,127 @@
++/*
++ * arch/arm/mach-iop33x/irq.c
++ *
++ * Generic IOP331 IRQ handling functionality
++ *
++ * Author: Dave Jiang <dave.jiang at intel.com>
++ * Copyright (C) 2003 Intel Corp.
++ *
++ * 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/init.h>
++#include <linux/interrupt.h>
++#include <linux/list.h>
++#include <asm/mach/irq.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++
++static u32 iop33x_mask0;
++static u32 iop33x_mask1;
++
++static inline void intctl0_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static inline void intctl1_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c1, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static inline void intstr0_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c2, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static inline void intstr1_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c3, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static inline void intbase_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c12, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static inline void intsize_write(u32 val)
++{
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c13, c0, 0" : : "r" (val));
++ iop3xx_cp6_disable();
++}
++
++static void
++iop33x_irq_mask1 (unsigned int irq)
++{
++ iop33x_mask0 &= ~(1 << irq);
++ intctl0_write(iop33x_mask0);
++}
++
++static void
++iop33x_irq_mask2 (unsigned int irq)
++{
++ iop33x_mask1 &= ~(1 << (irq - 32));
++ intctl1_write(iop33x_mask1);
++}
++
++static void
++iop33x_irq_unmask1(unsigned int irq)
++{
++ iop33x_mask0 |= 1 << irq;
++ intctl0_write(iop33x_mask0);
++}
++
++static void
++iop33x_irq_unmask2(unsigned int irq)
++{
++ iop33x_mask1 |= (1 << (irq - 32));
++ intctl1_write(iop33x_mask1);
++}
++
++struct irq_chip iop33x_irqchip1 = {
++ .name = "IOP33x-1",
++ .ack = iop33x_irq_mask1,
++ .mask = iop33x_irq_mask1,
++ .unmask = iop33x_irq_unmask1,
++};
++
++struct irq_chip iop33x_irqchip2 = {
++ .name = "IOP33x-2",
++ .ack = iop33x_irq_mask2,
++ .mask = iop33x_irq_mask2,
++ .unmask = iop33x_irq_unmask2,
++};
++
++void __init iop33x_init_irq(void)
++{
++ int i;
++
++ intctl0_write(0);
++ intctl1_write(0);
++ intstr0_write(0);
++ intstr1_write(0);
++ intbase_write(0);
++ intsize_write(1);
++ if (machine_is_iq80331())
++ *IOP3XX_PCIIRSR = 0x0f;
++
++ for (i = 0; i < NR_IRQS; i++) {
++ set_irq_chip(i, (i < 32) ? &iop33x_irqchip1 : &iop33x_irqchip2);
++ set_irq_handler(i, do_level_IRQ);
++ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
++ }
++}
+diff --git a/arch/arm/mach-iop33x/uart.c b/arch/arm/mach-iop33x/uart.c
+new file mode 100644
+index 0000000..ac297cd
+--- /dev/null
++++ b/arch/arm/mach-iop33x/uart.c
+@@ -0,0 +1,105 @@
++/*
++ * arch/arm/mach-iop33x/uart.c
++ *
++ * Author: Dave Jiang (dave.jiang at 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.
++ */
++
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/platform_device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/mach/map.h>
++#include <asm/setup.h>
++#include <asm/system.h>
++#include <asm/memory.h>
++#include <asm/hardware.h>
++#include <asm/hardware/iop3xx.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++
++#define IOP33X_UART_XTAL 33334000
++
++static struct plat_serial8250_port iop33x_uart0_data[] = {
++ {
++ .membase = (char *)IOP33X_UART0_VIRT,
++ .mapbase = IOP33X_UART0_PHYS,
++ .irq = IRQ_IOP33X_UART0,
++ .uartclk = IOP33X_UART_XTAL,
++ .regshift = 2,
++ .iotype = UPIO_MEM,
++ .flags = UPF_SKIP_TEST,
++ },
++ { },
++};
++
++static struct resource iop33x_uart0_resources[] = {
++ [0] = {
++ .start = IOP33X_UART0_PHYS,
++ .end = IOP33X_UART0_PHYS + 0x3f,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_IOP33X_UART0,
++ .end = IRQ_IOP33X_UART0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++struct platform_device iop33x_uart0_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = iop33x_uart0_data,
++ },
++ .num_resources = 2,
++ .resource = iop33x_uart0_resources,
++};
++
++
++static struct resource iop33x_uart1_resources[] = {
++ [0] = {
++ .start = IOP33X_UART1_PHYS,
++ .end = IOP33X_UART1_PHYS + 0x3f,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_IOP33X_UART1,
++ .end = IRQ_IOP33X_UART1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct plat_serial8250_port iop33x_uart1_data[] = {
++ {
++ .membase = (char *)IOP33X_UART1_VIRT,
++ .mapbase = IOP33X_UART1_PHYS,
++ .irq = IRQ_IOP33X_UART1,
++ .uartclk = IOP33X_UART_XTAL,
++ .regshift = 2,
++ .iotype = UPIO_MEM,
++ .flags = UPF_SKIP_TEST,
++ },
++ { },
++};
++
++struct platform_device iop33x_uart1_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM1,
++ .dev = {
++ .platform_data = iop33x_uart1_data,
++ },
++ .num_resources = 2,
++ .resource = iop33x_uart1_resources,
++};
+diff --git a/arch/arm/mach-iop3xx/Kconfig b/arch/arm/mach-iop3xx/Kconfig
+deleted file mode 100644
+index 4422f23..0000000
+--- a/arch/arm/mach-iop3xx/Kconfig
++++ /dev/null
+@@ -1,66 +0,0 @@
+-if ARCH_IOP3XX
+-
+-menu "IOP3xx Implementation Options"
+-
+-comment "IOP3xx Platform Types"
+-
+-config ARCH_IQ80321
+- bool "Enable support for IQ80321"
+- select ARCH_IOP321
+- help
+- Say Y here if you want to run your kernel on the Intel IQ80321
+- evaluation kit for the IOP321 chipset.
+-
+-config ARCH_IQ31244
+- bool "Enable support for IQ31244"
+- select ARCH_IOP321
+- help
+- Say Y here if you want to run your kernel on the Intel IQ31244
+- evaluation kit for the IOP321 chipset.
+-
+-config ARCH_IQ80331
+- bool "Enable support for IQ80331"
+- select ARCH_IOP331
+- help
+- Say Y here if you want to run your kernel on the Intel IQ80331
+- evaluation kit for the IOP331 chipset.
+-
+-config MACH_IQ80332
+- bool "Enable support for IQ80332"
+- select ARCH_IOP331
+- help
+- Say Y here if you want to run your kernel on the Intel IQ80332
+- evaluation kit for the IOP332 chipset.
+-
+-config ARCH_EP80219
+- bool "Enable support for EP80219"
+- select ARCH_IOP321
+- select ARCH_IQ31244
+- help
+- Say Y here if you want to run your kernel on the Intel EP80219
+- evaluation kit for the Intel 80219 chipset (a IOP321 variant).
+-
+-# Which IOP variant are we running?
+-config ARCH_IOP321
+- bool
+- help
+- The IQ80321 uses the IOP321 variant.
+- The IQ31244 and EP80219 uses the IOP321 variant.
+-
+-config ARCH_IOP331
+- bool
+- default ARCH_IQ80331
+- help
+- The IQ80331, IQ80332, and IQ80333 uses the IOP331 variant.
+-
+-comment "IOP3xx Chipset Features"
+-
+-config IOP331_STEPD
+- bool "Chip stepping D of the IOP80331 processor or IOP80333"
+- depends on (ARCH_IOP331)
+- help
+- Say Y here if you have StepD of the IOP80331 or IOP8033
+- based platforms.
+-
+-endmenu
+-endif
+diff --git a/arch/arm/mach-iop3xx/Makefile b/arch/arm/mach-iop3xx/Makefile
+deleted file mode 100644
+index b17eb1f..0000000
+--- a/arch/arm/mach-iop3xx/Makefile
++++ /dev/null
+@@ -1,23 +0,0 @@
+-#
+-# Makefile for the linux kernel.
+-#
+-
+-# Object file lists.
+-
+-obj-y := common.o
+-
+-obj-m :=
+-obj-n :=
+-obj- :=
+-
+-obj-$(CONFIG_ARCH_IOP321) += iop321-setup.o iop321-irq.o iop321-pci.o iop321-time.o
+-
+-obj-$(CONFIG_ARCH_IOP331) += iop331-setup.o iop331-irq.o iop331-pci.o iop331-time.o
+-
+-obj-$(CONFIG_ARCH_IQ80321) += iq80321-mm.o iq80321-pci.o
+-
+-obj-$(CONFIG_ARCH_IQ31244) += iq31244-mm.o iq31244-pci.o
+-
+-obj-$(CONFIG_ARCH_IQ80331) += iq80331-mm.o iq80331-pci.o
+-
+-obj-$(CONFIG_MACH_IQ80332) += iq80332-mm.o iq80332-pci.o
+diff --git a/arch/arm/mach-iop3xx/Makefile.boot b/arch/arm/mach-iop3xx/Makefile.boot
+deleted file mode 100644
+index 6387aa2..0000000
+--- a/arch/arm/mach-iop3xx/Makefile.boot
++++ /dev/null
+@@ -1,9 +0,0 @@
+- zreladdr-y := 0xa0008000
+-params_phys-y := 0xa0000100
+-initrd_phys-y := 0xa0800000
+-ifeq ($(CONFIG_ARCH_IOP331),y)
+- zreladdr-y := 0x00008000
+-params_phys-y := 0x00000100
+-initrd_phys-y := 0x00800000
+-endif
+-
+diff --git a/arch/arm/mach-iop3xx/common.c b/arch/arm/mach-iop3xx/common.c
+deleted file mode 100644
+index d7f50e5..0000000
+--- a/arch/arm/mach-iop3xx/common.c
++++ /dev/null
+@@ -1,72 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/common.c
+- *
+- * Common routines shared across all IOP3xx implementations
+- *
+- * Author: Deepak Saxena <dsaxena at mvista.com>
+- *
+- * Copyright 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/delay.h>
+-#include <asm/hardware.h>
+-
+-/*
+- * Shared variables
+- */
+-unsigned long iop3xx_pcibios_min_io = 0;
+-unsigned long iop3xx_pcibios_min_mem = 0;
+-
+-#ifdef CONFIG_ARCH_EP80219
+-#include <linux/kernel.h>
+-/*
+- * Default power-off for EP80219
+- */
+-
+-static inline void ep80219_send_to_pic(__u8 c) {
+-}
+-
+-void ep80219_power_off(void)
+-{
+- /*
+- * This function will send a SHUTDOWN_COMPLETE message to the PIC controller
+- * over I2C. We are not using the i2c subsystem since we are going to power
+- * off and it may be removed
+- */
+-
+- /* Send the Address byte w/ the start condition */
+- *IOP321_IDBR1 = 0x60;
+- *IOP321_ICR1 = 0xE9;
+- mdelay(1);
+-
+- /* Send the START_MSG byte w/ no start or stop condition */
+- *IOP321_IDBR1 = 0x0F;
+- *IOP321_ICR1 = 0xE8;
+- mdelay(1);
+-
+- /* Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or stop condition */
+- *IOP321_IDBR1 = 0x03;
+- *IOP321_ICR1 = 0xE8;
+- mdelay(1);
+-
+- /* Send an ignored byte w/ stop condition */
+- *IOP321_IDBR1 = 0x00;
+- *IOP321_ICR1 = 0xEA;
+-
+- while (1) ;
+-}
+-
+-#include <linux/init.h>
+-#include <linux/pm.h>
+-
+-static int __init ep80219_init(void)
+-{
+- pm_power_off = ep80219_power_off;
+- return 0;
+-}
+-arch_initcall(ep80219_init);
+-#endif
+diff --git a/arch/arm/mach-iop3xx/iop321-irq.c b/arch/arm/mach-iop3xx/iop321-irq.c
+deleted file mode 100644
+index 88ac333..0000000
+--- a/arch/arm/mach-iop3xx/iop321-irq.c
++++ /dev/null
+@@ -1,97 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/iop321-irq.c
+- *
+- * Generic IOP321 IRQ handling functionality
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- *
+- * 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.
+- *
+- * Added IOP3XX chipset and IQ80321 board masking code.
+- *
+- */
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/list.h>
+-
+-#include <asm/mach/irq.h>
+-#include <asm/irq.h>
+-#include <asm/hardware.h>
+-
+-#include <asm/mach-types.h>
+-
+-static u32 iop321_mask /* = 0 */;
+-
+-static inline void intctl_write(u32 val)
+-{
+- asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
+-}
+-
+-static inline void intstr_write(u32 val)
+-{
+- asm volatile("mcr p6,0,%0,c4,c0,0"::"r" (val));
+-}
+-
+-static void
+-iop321_irq_mask (unsigned int irq)
+-{
+-
+- iop321_mask &= ~(1 << (irq - IOP321_IRQ_OFS));
+-
+- intctl_write(iop321_mask);
+-}
+-
+-static void
+-iop321_irq_unmask (unsigned int irq)
+-{
+- iop321_mask |= (1 << (irq - IOP321_IRQ_OFS));
+-
+- intctl_write(iop321_mask);
+-}
+-
+-struct irq_chip ext_chip = {
+- .name = "IOP",
+- .ack = iop321_irq_mask,
+- .mask = iop321_irq_mask,
+- .unmask = iop321_irq_unmask,
+-};
+-
+-void __init iop321_init_irq(void)
+-{
+- unsigned int i, tmp;
+-
+- /* Enable access to coprocessor 6 for dealing with IRQs.
+- * From RMK:
+- * Basically, the Intel documentation here is poor. It appears that
+- * you need to set the bit to be able to access the coprocessor from
+- * SVC mode. Whether that allows access from user space or not is
+- * unclear.
+- */
+- asm volatile (
+- "mrc p15, 0, %0, c15, c1, 0\n\t"
+- "orr %0, %0, %1\n\t"
+- "mcr p15, 0, %0, c15, c1, 0\n\t"
+- /* The action is delayed, so we have to do this: */
+- "mrc p15, 0, %0, c15, c1, 0\n\t"
+- "mov %0, %0\n\t"
+- "sub pc, pc, #4"
+- : "=r" (tmp) : "i" (1 << 6) );
+-
+- intctl_write(0); // disable all interrupts
+- intstr_write(0); // treat all as IRQ
+- if(machine_is_iq80321() ||
+- machine_is_iq31244()) // all interrupts are inputs to chip
+- *IOP321_PCIIRSR = 0x0f;
+-
+- for(i = IOP321_IRQ_OFS; i < NR_IOP321_IRQS; i++)
+- {
+- set_irq_chip(i, &ext_chip);
+- set_irq_handler(i, do_level_IRQ);
+- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+-
+- }
+-}
+-
+diff --git a/arch/arm/mach-iop3xx/iop321-pci.c b/arch/arm/mach-iop3xx/iop321-pci.c
+deleted file mode 100644
+index 8ba6a0e..0000000
+--- a/arch/arm/mach-iop3xx/iop321-pci.c
++++ /dev/null
+@@ -1,220 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iop321-pci.c
+- *
+- * PCI support for the Intel IOP321 chipset
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- *
+- * 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/pci.h>
+-#include <linux/slab.h>
+-#include <linux/mm.h>
+-#include <linux/init.h>
+-#include <linux/ioport.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/system.h>
+-#include <asm/hardware.h>
+-#include <asm/mach/pci.h>
+-
+-#include <asm/arch/iop321.h>
+-
+-// #define DEBUG
+-
+-#ifdef DEBUG
+-#define DBG(x...) printk(x)
+-#else
+-#define DBG(x...) do { } while (0)
+-#endif
+-
+-/*
+- * This routine builds either a type0 or type1 configuration command. If the
+- * bus is on the 80321 then a type0 made, else a type1 is created.
+- */
+-static u32 iop321_cfg_address(struct pci_bus *bus, int devfn, int where)
+-{
+- struct pci_sys_data *sys = bus->sysdata;
+- u32 addr;
+-
+- if (sys->busnr == bus->number)
+- addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
+- else
+- addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
+-
+- addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
+-
+- return addr;
+-}
+-
+-/*
+- * This routine checks the status of the last configuration cycle. If an error
+- * was detected it returns a 1, else it returns a 0. The errors being checked
+- * are parity, master abort, target abort (master and target). These types of
+- * errors occure during a config cycle where there is no device, like during
+- * the discovery stage.
+- */
+-static int iop321_pci_status(void)
+-{
+- unsigned int status;
+- int ret = 0;
+-
+- /*
+- * Check the status registers.
+- */
+- status = *IOP321_ATUSR;
+- if (status & 0xf900)
+- {
+- DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
+- *IOP321_ATUSR = status & 0xf900;
+- ret = 1;
+- }
+- status = *IOP321_ATUISR;
+- if (status & 0x679f)
+- {
+- DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
+- *IOP321_ATUISR = status & 0x679f;
+- ret = 1;
+- }
+- return ret;
+-}
+-
+-/*
+- * Simply write the address register and read the configuration
+- * data. Note that the 4 nop's ensure that we are able to handle
+- * a delayed abort (in theory.)
+- */
+-static inline u32 iop321_read(unsigned long addr)
+-{
+- u32 val;
+-
+- __asm__ __volatile__(
+- "str %1, [%2]\n\t"
+- "ldr %0, [%3]\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- : "=r" (val)
+- : "r" (addr), "r" (IOP321_OCCAR), "r" (IOP321_OCCDR));
+-
+- return val;
+-}
+-
+-/*
+- * The read routines must check the error status of the last configuration
+- * cycle. If there was an error, the routine returns all hex f's.
+- */
+-static int
+-iop321_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+- int size, u32 *value)
+-{
+- unsigned long addr = iop321_cfg_address(bus, devfn, where);
+- u32 val = iop321_read(addr) >> ((where & 3) * 8);
+-
+- if( iop321_pci_status() )
+- val = 0xffffffff;
+-
+- *value = val;
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int
+-iop321_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+- int size, u32 value)
+-{
+- unsigned long addr = iop321_cfg_address(bus, devfn, where);
+- u32 val;
+-
+- if (size != 4) {
+- val = iop321_read(addr);
+- if (!iop321_pci_status() == 0)
+- return PCIBIOS_SUCCESSFUL;
+-
+- where = (where & 3) * 8;
+-
+- if (size == 1)
+- val &= ~(0xff << where);
+- else
+- val &= ~(0xffff << where);
+-
+- *IOP321_OCCDR = val | value << where;
+- } else {
+- asm volatile(
+- "str %1, [%2]\n\t"
+- "str %0, [%3]\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- :
+- : "r" (value), "r" (addr),
+- "r" (IOP321_OCCAR), "r" (IOP321_OCCDR));
+- }
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static struct pci_ops iop321_ops = {
+- .read = iop321_read_config,
+- .write = iop321_write_config,
+-};
+-
+-/*
+- * When a PCI device does not exist during config cycles, the 80200 gets a
+- * bus error instead of returning 0xffffffff. This handler simply returns.
+- */
+-int
+-iop321_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+-{
+- DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
+- addr, fsr, regs->ARM_pc, regs->ARM_lr);
+-
+- /*
+- * If it was an imprecise abort, then we need to correct the
+- * return address to be _after_ the instruction.
+- */
+- if (fsr & (1 << 10))
+- regs->ARM_pc += 4;
+-
+- return 0;
+-}
+-
+-/*
+- * Scan an IOP321 PCI bus. sys->bus defines which bus we scan.
+- */
+-struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *sys)
+-{
+- return pci_scan_bus(sys->busnr, &iop321_ops, sys);
+-}
+-
+-void iop321_init(void)
+-{
+- DBG("PCI: Intel 80321 PCI init code.\n");
+- DBG("ATU: IOP321_ATUCMD=0x%04x\n", *IOP321_ATUCMD);
+- DBG("ATU: IOP321_OMWTVR0=0x%04x, IOP321_OIOWTVR=0x%04x\n",
+- *IOP321_OMWTVR0,
+- *IOP321_OIOWTVR);
+- DBG("ATU: IOP321_ATUCR=0x%08x\n", *IOP321_ATUCR);
+- DBG("ATU: IOP321_IABAR0=0x%08x IOP321_IALR0=0x%08x IOP321_IATVR0=%08x\n",
+- *IOP321_IABAR0, *IOP321_IALR0, *IOP321_IATVR0);
+- DBG("ATU: IOP321_OMWTVR0=0x%08x\n", *IOP321_OMWTVR0);
+- DBG("ATU: IOP321_IABAR1=0x%08x IOP321_IALR1=0x%08x\n",
+- *IOP321_IABAR1, *IOP321_IALR1);
+- DBG("ATU: IOP321_ERBAR=0x%08x IOP321_ERLR=0x%08x IOP321_ERTVR=%08x\n",
+- *IOP321_ERBAR, *IOP321_ERLR, *IOP321_ERTVR);
+- DBG("ATU: IOP321_IABAR2=0x%08x IOP321_IALR2=0x%08x IOP321_IATVR2=%08x\n",
+- *IOP321_IABAR2, *IOP321_IALR2, *IOP321_IATVR2);
+- DBG("ATU: IOP321_IABAR3=0x%08x IOP321_IALR3=0x%08x IOP321_IATVR3=%08x\n",
+- *IOP321_IABAR3, *IOP321_IALR3, *IOP321_IATVR3);
+-
+- hook_fault_code(16+6, iop321_pci_abort, SIGBUS, "imprecise external abort");
+-}
+-
+diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
+deleted file mode 100644
+index b6d0969..0000000
+--- a/arch/arm/mach-iop3xx/iop321-setup.c
++++ /dev/null
+@@ -1,173 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/iop321-setup.c
+- *
+- * Author: Nicolas Pitre <nico at cam.org>
+- * Copyright (C) 2001 MontaVista Software, Inc.
+- * 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.
+- *
+- */
+-#include <linux/mm.h>
+-#include <linux/init.h>
+-#include <linux/major.h>
+-#include <linux/fs.h>
+-#include <linux/platform_device.h>
+-#include <linux/serial.h>
+-#include <linux/tty.h>
+-#include <linux/serial_core.h>
+-
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-#include <asm/mach/map.h>
+-#include <asm/setup.h>
+-#include <asm/system.h>
+-#include <asm/memory.h>
+-#include <asm/hardware.h>
+-#include <asm/mach-types.h>
+-#include <asm/mach/arch.h>
+-
+-#define IOP321_UART_XTAL 1843200
+-
+-/*
+- * Standard IO mapping for all IOP321 based systems
+- */
+-static struct map_desc iop321_std_desc[] __initdata = {
+- { /* mem mapped registers */
+- .virtual = IOP321_VIRT_MEM_BASE,
+- .pfn = __phys_to_pfn(IOP321_PHYS_MEM_BASE),
+- .length = 0x00002000,
+- .type = MT_DEVICE
+- }, { /* PCI IO space */
+- .virtual = IOP321_PCI_LOWER_IO_VA,
+- .pfn = __phys_to_pfn(IOP321_PCI_LOWER_IO_PA),
+- .length = IOP321_PCI_IO_WINDOW_SIZE,
+- .type = MT_DEVICE
+- }
+-};
+-
+-#ifdef CONFIG_ARCH_IQ80321
+-#define UARTBASE IQ80321_UART
+-#define IRQ_UART IRQ_IQ80321_UART
+-#endif
+-
+-#ifdef CONFIG_ARCH_IQ31244
+-#define UARTBASE IQ31244_UART
+-#define IRQ_UART IRQ_IQ31244_UART
+-#endif
+-
+-static struct uart_port iop321_serial_ports[] = {
+- {
+- .membase = (char*)(UARTBASE),
+- .mapbase = (UARTBASE),
+- .irq = IRQ_UART,
+- .flags = UPF_SKIP_TEST,
+- .iotype = UPIO_MEM,
+- .regshift = 0,
+- .uartclk = IOP321_UART_XTAL,
+- .line = 0,
+- .type = PORT_16550A,
+- .fifosize = 16
+- }
+-};
+-
+-static struct resource iop32x_i2c_0_resources[] = {
+- [0] = {
+- .start = 0xfffff680,
+- .end = 0xfffff698,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_IOP321_I2C_0,
+- .end = IRQ_IOP321_I2C_0,
+- .flags = IORESOURCE_IRQ
+- }
+-};
+-
+-static struct resource iop32x_i2c_1_resources[] = {
+- [0] = {
+- .start = 0xfffff6a0,
+- .end = 0xfffff6b8,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_IOP321_I2C_1,
+- .end = IRQ_IOP321_I2C_1,
+- .flags = IORESOURCE_IRQ
+- }
+-};
+-
+-static struct platform_device iop32x_i2c_0_controller = {
+- .name = "IOP3xx-I2C",
+- .id = 0,
+- .num_resources = 2,
+- .resource = iop32x_i2c_0_resources
+-};
+-
+-static struct platform_device iop32x_i2c_1_controller = {
+- .name = "IOP3xx-I2C",
+- .id = 1,
+- .num_resources = 2,
+- .resource = iop32x_i2c_1_resources
+-};
+-
+-static struct platform_device *iop32x_devices[] __initdata = {
+- &iop32x_i2c_0_controller,
+- &iop32x_i2c_1_controller
+-};
+-
+-void __init iop32x_init(void)
+-{
+- if(iop_is_321())
+- {
+- platform_add_devices(iop32x_devices,
+- ARRAY_SIZE(iop32x_devices));
+- }
+-}
+-
+-void __init iop321_map_io(void)
+-{
+- iotable_init(iop321_std_desc, ARRAY_SIZE(iop321_std_desc));
+- early_serial_setup(&iop321_serial_ports[0]);
+-}
+-
+-#ifdef CONFIG_ARCH_IQ80321
+-extern void iq80321_map_io(void);
+-extern struct sys_timer iop321_timer;
+-extern void iop321_init_time(void);
+-#endif
+-
+-#ifdef CONFIG_ARCH_IQ31244
+-extern void iq31244_map_io(void);
+-extern struct sys_timer iop321_timer;
+-extern void iop321_init_time(void);
+-#endif
+-
+-#if defined(CONFIG_ARCH_IQ80321)
+-MACHINE_START(IQ80321, "Intel IQ80321")
+- /* Maintainer: Intel Corporation */
+- .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,
+-MACHINE_END
+-#elif defined(CONFIG_ARCH_IQ31244)
+-MACHINE_START(IQ31244, "Intel IQ31244")
+- /* Maintainer: Intel Corp. */
+- .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,
+-MACHINE_END
+-#else
+-#error No machine descriptor defined for this IOP3XX implementation
+-#endif
+diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c
+deleted file mode 100644
+index 04b1a6f..0000000
+--- a/arch/arm/mach-iop3xx/iop321-time.c
++++ /dev/null
+@@ -1,108 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iop321-time.c
+- *
+- * Timer code for IOP321 based systems
+- *
+- * Author: Deepak Saxena <dsaxena at mvista.com>
+- *
+- * Copyright 2002-2003 MontaVista Software Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the
+- * Free Software Foundation; either version 2 of the License, or (at your
+- * option) any later version.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/interrupt.h>
+-#include <linux/time.h>
+-#include <linux/init.h>
+-#include <linux/timex.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-#include <asm/mach/irq.h>
+-#include <asm/mach/time.h>
+-
+-#define IOP321_TIME_SYNC 0
+-
+-static inline unsigned long get_elapsed(void)
+-{
+- return LATCH - *IOP321_TU_TCR0;
+-}
+-
+-static unsigned long iop321_gettimeoffset(void)
+-{
+- unsigned long elapsed, usec;
+- u32 tisr1, tisr2;
+-
+- /*
+- * If an interrupt was pending before we read the timer,
+- * we've already wrapped. Factor this into the time.
+- * If an interrupt was pending after we read the timer,
+- * it may have wrapped between checking the interrupt
+- * status and reading the timer. Re-read the timer to
+- * be sure its value is after the wrap.
+- */
+-
+- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
+- elapsed = get_elapsed();
+- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
+-
+- if(tisr1 & 1)
+- elapsed += LATCH;
+- else if (tisr2 & 1)
+- elapsed = LATCH + get_elapsed();
+-
+- /*
+- * Now convert them to usec.
+- */
+- usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
+-
+- return usec;
+-}
+-
+-static irqreturn_t
+-iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- u32 tisr;
+-
+- write_seqlock(&xtime_lock);
+-
+- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
+- tisr |= 1;
+- asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
+-
+- timer_tick(regs);
+-
+- write_sequnlock(&xtime_lock);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static struct irqaction iop321_timer_irq = {
+- .name = "IOP321 Timer Tick",
+- .handler = iop321_timer_interrupt,
+- .flags = IRQF_DISABLED | IRQF_TIMER,
+-};
+-
+-static void __init iop321_timer_init(void)
+-{
+- u32 timer_ctl;
+-
+- setup_irq(IRQ_IOP321_TIMER0, &iop321_timer_irq);
+-
+- timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD |
+- IOP321_TMR_RATIO_1_1;
+-
+- asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH));
+-
+- asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
+-}
+-
+-struct sys_timer iop321_timer = {
+- .init = &iop321_timer_init,
+- .offset = iop321_gettimeoffset,
+-};
+diff --git a/arch/arm/mach-iop3xx/iop331-irq.c b/arch/arm/mach-iop3xx/iop331-irq.c
+deleted file mode 100644
+index cab1172..0000000
+--- a/arch/arm/mach-iop3xx/iop331-irq.c
++++ /dev/null
+@@ -1,129 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/iop331-irq.c
+- *
+- * Generic IOP331 IRQ handling functionality
+- *
+- * Author: Dave Jiang <dave.jiang at intel.com>
+- * Copyright (C) 2003 Intel Corp.
+- *
+- * 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/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/list.h>
+-
+-#include <asm/mach/irq.h>
+-#include <asm/irq.h>
+-#include <asm/hardware.h>
+-
+-#include <asm/mach-types.h>
+-
+-static u32 iop331_mask0 = 0;
+-static u32 iop331_mask1 = 0;
+-
+-static inline void intctl_write0(u32 val)
+-{
+- // INTCTL0
+- asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
+-}
+-
+-static inline void intctl_write1(u32 val)
+-{
+- // INTCTL1
+- asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val));
+-}
+-
+-static inline void intstr_write0(u32 val)
+-{
+- // INTSTR0
+- asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val));
+-}
+-
+-static inline void intstr_write1(u32 val)
+-{
+- // INTSTR1
+- asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val));
+-}
+-
+-static void
+-iop331_irq_mask1 (unsigned int irq)
+-{
+- iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS));
+- intctl_write0(iop331_mask0);
+-}
+-
+-static void
+-iop331_irq_mask2 (unsigned int irq)
+-{
+- iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32));
+- intctl_write1(iop331_mask1);
+-}
+-
+-static void
+-iop331_irq_unmask1(unsigned int irq)
+-{
+- iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS));
+- intctl_write0(iop331_mask0);
+-}
+-
+-static void
+-iop331_irq_unmask2(unsigned int irq)
+-{
+- iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32));
+- intctl_write1(iop331_mask1);
+-}
+-
+-struct irq_chip iop331_irqchip1 = {
+- .name = "IOP-1",
+- .ack = iop331_irq_mask1,
+- .mask = iop331_irq_mask1,
+- .unmask = iop331_irq_unmask1,
+-};
+-
+-struct irq_chip iop331_irqchip2 = {
+- .name = "IOP-2",
+- .ack = iop331_irq_mask2,
+- .mask = iop331_irq_mask2,
+- .unmask = iop331_irq_unmask2,
+-};
+-
+-void __init iop331_init_irq(void)
+-{
+- unsigned int i, tmp;
+-
+- /* Enable access to coprocessor 6 for dealing with IRQs.
+- * From RMK:
+- * Basically, the Intel documentation here is poor. It appears that
+- * you need to set the bit to be able to access the coprocessor from
+- * SVC mode. Whether that allows access from user space or not is
+- * unclear.
+- */
+- asm volatile (
+- "mrc p15, 0, %0, c15, c1, 0\n\t"
+- "orr %0, %0, %1\n\t"
+- "mcr p15, 0, %0, c15, c1, 0\n\t"
+- /* The action is delayed, so we have to do this: */
+- "mrc p15, 0, %0, c15, c1, 0\n\t"
+- "mov %0, %0\n\t"
+- "sub pc, pc, #4"
+- : "=r" (tmp) : "i" (1 << 6) );
+-
+- intctl_write0(0); // disable all interrupts
+- intctl_write1(0);
+- intstr_write0(0); // treat all as IRQ
+- intstr_write1(0);
+- if(machine_is_iq80331()) // all interrupts are inputs to chip
+- *IOP331_PCIIRSR = 0x0f;
+-
+- for(i = IOP331_IRQ_OFS; i < NR_IOP331_IRQS; i++)
+- {
+- set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2);
+- set_irq_handler(i, do_level_IRQ);
+- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+- }
+-}
+-
+diff --git a/arch/arm/mach-iop3xx/iop331-pci.c b/arch/arm/mach-iop3xx/iop331-pci.c
+deleted file mode 100644
+index 44dd213..0000000
+--- a/arch/arm/mach-iop3xx/iop331-pci.c
++++ /dev/null
+@@ -1,222 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iop331-pci.c
+- *
+- * PCI support for the Intel IOP331 chipset
+- *
+- * Author: Dave Jiang (dave.jiang at intel.com)
+- * Copyright (C) 2003, 2004 Intel Corp.
+- *
+- * 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/pci.h>
+-#include <linux/slab.h>
+-#include <linux/mm.h>
+-#include <linux/init.h>
+-#include <linux/ioport.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/system.h>
+-#include <asm/hardware.h>
+-#include <asm/mach/pci.h>
+-
+-#include <asm/arch/iop331.h>
+-
+-#undef DEBUG
+-#undef DEBUG1
+-
+-#ifdef DEBUG
+-#define DBG(x...) printk(x)
+-#else
+-#define DBG(x...) do { } while (0)
+-#endif
+-
+-#ifdef DEBUG1
+-#define DBG1(x...) printk(x)
+-#else
+-#define DBG1(x...) do { } while (0)
+-#endif
+-
+-/*
+- * This routine builds either a type0 or type1 configuration command. If the
+- * bus is on the 80331 then a type0 made, else a type1 is created.
+- */
+-static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where)
+-{
+- struct pci_sys_data *sys = bus->sysdata;
+- u32 addr;
+-
+- if (sys->busnr == bus->number)
+- addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
+- else
+- addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
+-
+- addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
+-
+- return addr;
+-}
+-
+-/*
+- * This routine checks the status of the last configuration cycle. If an error
+- * was detected it returns a 1, else it returns a 0. The errors being checked
+- * are parity, master abort, target abort (master and target). These types of
+- * errors occure during a config cycle where there is no device, like during
+- * the discovery stage.
+- */
+-static int iop331_pci_status(void)
+-{
+- unsigned int status;
+- int ret = 0;
+-
+- /*
+- * Check the status registers.
+- */
+- status = *IOP331_ATUSR;
+- if (status & 0xf900)
+- {
+- DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
+- *IOP331_ATUSR = status & 0xf900;
+- ret = 1;
+- }
+- status = *IOP331_ATUISR;
+- if (status & 0x679f)
+- {
+- DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
+- *IOP331_ATUISR = status & 0x679f;
+- ret = 1;
+- }
+- return ret;
+-}
+-
+-/*
+- * Simply write the address register and read the configuration
+- * data. Note that the 4 nop's ensure that we are able to handle
+- * a delayed abort (in theory.)
+- */
+-static inline u32 iop331_read(unsigned long addr)
+-{
+- u32 val;
+-
+- __asm__ __volatile__(
+- "str %1, [%2]\n\t"
+- "ldr %0, [%3]\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- : "=r" (val)
+- : "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
+-
+- return val;
+-}
+-
+-/*
+- * The read routines must check the error status of the last configuration
+- * cycle. If there was an error, the routine returns all hex f's.
+- */
+-static int
+-iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+- int size, u32 *value)
+-{
+- unsigned long addr = iop331_cfg_address(bus, devfn, where);
+- u32 val = iop331_read(addr) >> ((where & 3) * 8);
+-
+- if( iop331_pci_status() )
+- val = 0xffffffff;
+-
+- *value = val;
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int
+-iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+- int size, u32 value)
+-{
+- unsigned long addr = iop331_cfg_address(bus, devfn, where);
+- u32 val;
+-
+- if (size != 4) {
+- val = iop331_read(addr);
+- if (!iop331_pci_status() == 0)
+- return PCIBIOS_SUCCESSFUL;
+-
+- where = (where & 3) * 8;
+-
+- if (size == 1)
+- val &= ~(0xff << where);
+- else
+- val &= ~(0xffff << where);
+-
+- *IOP331_OCCDR = val | value << where;
+- } else {
+- asm volatile(
+- "str %1, [%2]\n\t"
+- "str %0, [%3]\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- :
+- : "r" (value), "r" (addr),
+- "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
+- }
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static struct pci_ops iop331_ops = {
+- .read = iop331_read_config,
+- .write = iop331_write_config,
+-};
+-
+-/*
+- * When a PCI device does not exist during config cycles, the XScale gets a
+- * bus error instead of returning 0xffffffff. This handler simply returns.
+- */
+-int
+-iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+-{
+- DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
+- addr, fsr, regs->ARM_pc, regs->ARM_lr);
+-
+- /*
+- * If it was an imprecise abort, then we need to correct the
+- * return address to be _after_ the instruction.
+- */
+- if (fsr & (1 << 10))
+- regs->ARM_pc += 4;
+-
+- return 0;
+-}
+-
+-/*
+- * Scan an IOP331 PCI bus. sys->bus defines which bus we scan.
+- */
+-struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys)
+-{
+- return pci_scan_bus(sys->busnr, &iop331_ops, sys);
+-}
+-
+-void iop331_init(void)
+-{
+- DBG1("PCI: Intel 80331 PCI init code.\n");
+- DBG1("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD);
+- DBG1("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n",
+- *IOP331_OMWTVR0,
+- *IOP331_OIOWTVR);
+- DBG1("\tATU: IOP331_OMWTVR1=0x%04x\n", *IOP331_OMWTVR1);
+- DBG1("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR);
+- DBG1("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0);
+- DBG1("\tATU: IOP31_IABAR1=0x%08x IOP331_IALR1=0x%08x\n", *IOP331_IABAR1, *IOP331_IALR1);
+- DBG1("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR);
+- DBG1("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2);
+- DBG1("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3);
+-
+- hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort");
+-}
+-
+diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c
+deleted file mode 100644
+index 3cc98d8..0000000
+--- a/arch/arm/mach-iop3xx/iop331-setup.c
++++ /dev/null
+@@ -1,221 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/iop331-setup.c
+- *
+- * Author: Dave Jiang (dave.jiang at 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.
+- *
+- */
+-#include <linux/mm.h>
+-#include <linux/init.h>
+-#include <linux/major.h>
+-#include <linux/fs.h>
+-#include <linux/platform_device.h>
+-#include <linux/serial.h>
+-#include <linux/tty.h>
+-#include <linux/serial_8250.h>
+-
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-#include <asm/mach/map.h>
+-#include <asm/setup.h>
+-#include <asm/system.h>
+-#include <asm/memory.h>
+-#include <asm/hardware.h>
+-#include <asm/mach-types.h>
+-#include <asm/mach/arch.h>
+-
+-#define IOP331_UART_XTAL 33334000
+-
+-/*
+- * Standard IO mapping for all IOP331 based systems
+- */
+-static struct map_desc iop331_std_desc[] __initdata = {
+- { /* mem mapped registers */
+- .virtual = IOP331_VIRT_MEM_BASE,
+- .pfn = __phys_to_pfn(IOP331_PHYS_MEM_BASE),
+- .length = 0x00002000,
+- .type = MT_DEVICE
+- }, { /* PCI IO space */
+- .virtual = IOP331_PCI_LOWER_IO_VA,
+- .pfn = __phys_to_pfn(IOP331_PCI_LOWER_IO_PA),
+- .length = IOP331_PCI_IO_WINDOW_SIZE,
+- .type = MT_DEVICE
+- }
+-};
+-
+-static struct resource iop33x_uart0_resources[] = {
+- [0] = {
+- .start = IOP331_UART0_PHYS,
+- .end = IOP331_UART0_PHYS + 0x3f,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_IOP331_UART0,
+- .end = IRQ_IOP331_UART0,
+- .flags = IORESOURCE_IRQ
+- }
+-};
+-
+-static struct resource iop33x_uart1_resources[] = {
+- [0] = {
+- .start = IOP331_UART1_PHYS,
+- .end = IOP331_UART1_PHYS + 0x3f,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_IOP331_UART1,
+- .end = IRQ_IOP331_UART1,
+- .flags = IORESOURCE_IRQ
+- }
+-};
+-
+-static struct plat_serial8250_port iop33x_uart0_data[] = {
+- {
+- .membase = (char*)(IOP331_UART0_VIRT),
+- .mapbase = (IOP331_UART0_PHYS),
+- .irq = IRQ_IOP331_UART0,
+- .uartclk = IOP331_UART_XTAL,
+- .regshift = 2,
+- .iotype = UPIO_MEM,
+- .flags = UPF_SKIP_TEST,
+- },
+- { },
+-};
+-
+-static struct plat_serial8250_port iop33x_uart1_data[] = {
+- {
+- .membase = (char*)(IOP331_UART1_VIRT),
+- .mapbase = (IOP331_UART1_PHYS),
+- .irq = IRQ_IOP331_UART1,
+- .uartclk = IOP331_UART_XTAL,
+- .regshift = 2,
+- .iotype = UPIO_MEM,
+- .flags = UPF_SKIP_TEST,
+- },
+- { },
+-};
+-
+-static struct platform_device iop33x_uart0 = {
+- .name = "serial8250",
+- .id = PLAT8250_DEV_PLATFORM,
+- .dev.platform_data = iop33x_uart0_data,
+- .num_resources = 2,
+- .resource = iop33x_uart0_resources,
+-};
+-
+-static struct platform_device iop33x_uart1 = {
+- .name = "serial8250",
+- .id = PLAT8250_DEV_PLATFORM1,
+- .dev.platform_data = iop33x_uart1_data,
+- .num_resources = 2,
+- .resource = iop33x_uart1_resources,
+-};
+-
+-static struct resource iop33x_i2c_0_resources[] = {
+- [0] = {
+- .start = 0xfffff680,
+- .end = 0xfffff698,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_IOP331_I2C_0,
+- .end = IRQ_IOP331_I2C_0,
+- .flags = IORESOURCE_IRQ
+- }
+-};
+-
+-static struct resource iop33x_i2c_1_resources[] = {
+- [0] = {
+- .start = 0xfffff6a0,
+- .end = 0xfffff6b8,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_IOP331_I2C_1,
+- .end = IRQ_IOP331_I2C_1,
+- .flags = IORESOURCE_IRQ
+- }
+-};
+-
+-static struct platform_device iop33x_i2c_0_controller = {
+- .name = "IOP3xx-I2C",
+- .id = 0,
+- .num_resources = 2,
+- .resource = iop33x_i2c_0_resources
+-};
+-
+-static struct platform_device iop33x_i2c_1_controller = {
+- .name = "IOP3xx-I2C",
+- .id = 1,
+- .num_resources = 2,
+- .resource = iop33x_i2c_1_resources
+-};
+-
+-static struct platform_device *iop33x_devices[] __initdata = {
+- &iop33x_uart0,
+- &iop33x_uart1,
+- &iop33x_i2c_0_controller,
+- &iop33x_i2c_1_controller
+-};
+-
+-void __init iop33x_init(void)
+-{
+- if(iop_is_331())
+- {
+- platform_add_devices(iop33x_devices,
+- ARRAY_SIZE(iop33x_devices));
+- }
+-}
+-
+-void __init iop331_map_io(void)
+-{
+- iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc));
+-}
+-
+-#ifdef CONFIG_ARCH_IOP331
+-extern void iop331_init_irq(void);
+-extern struct sys_timer iop331_timer;
+-#endif
+-
+-#ifdef CONFIG_ARCH_IQ80331
+-extern void iq80331_map_io(void);
+-#endif
+-
+-#ifdef CONFIG_MACH_IQ80332
+-extern void iq80332_map_io(void);
+-#endif
+-
+-#if defined(CONFIG_ARCH_IQ80331)
+-MACHINE_START(IQ80331, "Intel IQ80331")
+- /* Maintainer: Intel Corp. */
+- .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,
+-MACHINE_END
+-
+-#elif defined(CONFIG_MACH_IQ80332)
+-MACHINE_START(IQ80332, "Intel IQ80332")
+- /* Maintainer: Intel Corp. */
+- .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,
+-MACHINE_END
+-
+-#else
+-#error No machine descriptor defined for this IOP3XX implementation
+-#endif
+-
+-
+diff --git a/arch/arm/mach-iop3xx/iop331-time.c b/arch/arm/mach-iop3xx/iop331-time.c
+deleted file mode 100644
+index 0c09e74..0000000
+--- a/arch/arm/mach-iop3xx/iop331-time.c
++++ /dev/null
+@@ -1,106 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iop331-time.c
+- *
+- * Timer code for IOP331 based systems
+- *
+- * Author: Dave Jiang <dave.jiang at intel.com>
+- *
+- * Copyright 2003 Intel 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 <linux/kernel.h>
+-#include <linux/interrupt.h>
+-#include <linux/time.h>
+-#include <linux/init.h>
+-#include <linux/timex.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-#include <asm/mach/irq.h>
+-#include <asm/mach/time.h>
+-
+-static inline unsigned long get_elapsed(void)
+-{
+- return LATCH - *IOP331_TU_TCR0;
+-}
+-
+-static unsigned long iop331_gettimeoffset(void)
+-{
+- unsigned long elapsed, usec;
+- u32 tisr1, tisr2;
+-
+- /*
+- * If an interrupt was pending before we read the timer,
+- * we've already wrapped. Factor this into the time.
+- * If an interrupt was pending after we read the timer,
+- * it may have wrapped between checking the interrupt
+- * status and reading the timer. Re-read the timer to
+- * be sure its value is after the wrap.
+- */
+-
+- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
+- elapsed = get_elapsed();
+- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
+-
+- if(tisr1 & 1)
+- elapsed += LATCH;
+- else if (tisr2 & 1)
+- elapsed = LATCH + get_elapsed();
+-
+- /*
+- * Now convert them to usec.
+- */
+- usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
+-
+- return usec;
+-}
+-
+-static irqreturn_t
+-iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- u32 tisr;
+-
+- write_seqlock(&xtime_lock);
+-
+- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
+- tisr |= 1;
+- asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
+-
+- timer_tick(regs);
+-
+- write_sequnlock(&xtime_lock);
+- return IRQ_HANDLED;
+-}
+-
+-static struct irqaction iop331_timer_irq = {
+- .name = "IOP331 Timer Tick",
+- .handler = iop331_timer_interrupt,
+- .flags = IRQF_DISABLED | IRQF_TIMER,
+-};
+-
+-static void __init iop331_timer_init(void)
+-{
+- u32 timer_ctl;
+-
+- setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq);
+-
+- timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD |
+- IOP331_TMR_RATIO_1_1;
+-
+- asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH));
+-
+- asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
+-
+-}
+-
+-struct sys_timer iop331_timer = {
+- .init = iop331_timer_init,
+- .offset = iop331_gettimeoffset,
+-};
+diff --git a/arch/arm/mach-iop3xx/iq31244-mm.c b/arch/arm/mach-iop3xx/iq31244-mm.c
+deleted file mode 100644
+index e874b54..0000000
+--- a/arch/arm/mach-iop3xx/iq31244-mm.c
++++ /dev/null
+@@ -1,45 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/mm.c
+- *
+- * Low level memory initialization for iq80321 platform
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- *
+- * 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/mm.h>
+-#include <linux/init.h>
+-
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-
+-#include <asm/mach/map.h>
+-
+-
+-/*
+- * IQ80321 specific IO mappings
+- *
+- * We use RedBoot's setup for the onboard devices.
+- */
+-static struct map_desc iq31244_io_desc[] __initdata = {
+- { /* on-board devices */
+- .virtual = IQ31244_UART,
+- .pfn = __phys_to_pfn(IQ31244_UART),
+- .length = 0x00100000,
+- .type = MT_DEVICE
+- }
+-};
+-
+-void __init iq31244_map_io(void)
+-{
+- iop321_map_io();
+-
+- iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc));
+-}
+diff --git a/arch/arm/mach-iop3xx/iq31244-pci.c b/arch/arm/mach-iop3xx/iq31244-pci.c
+deleted file mode 100644
+index f3c6413..0000000
+--- a/arch/arm/mach-iop3xx/iq31244-pci.c
++++ /dev/null
+@@ -1,129 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iq80321-pci.c
+- *
+- * PCI support for the Intel IQ80321 reference board
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- * Copyright (C) 2004 Intel Corp.
+- *
+- * 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/pci.h>
+-#include <linux/init.h>
+-#include <linux/string.h>
+-#include <linux/slab.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/irq.h>
+-#include <asm/mach/pci.h>
+-#include <asm/mach-types.h>
+-
+-/*
+- * The following macro is used to lookup irqs in a standard table
+- * format for those systems that do not already have PCI
+- * interrupts properly routed. We assume 1 <= pin <= 4
+- */
+-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
+-({ int _ctl_ = -1; \
+- unsigned int _idsel = idsel - minid; \
+- if (_idsel <= maxid) \
+- _ctl_ = pci_irq_table[_idsel][pin-1]; \
+- _ctl_; })
+-
+-#define INTA IRQ_IQ31244_INTA
+-#define INTB IRQ_IQ31244_INTB
+-#define INTC IRQ_IQ31244_INTC
+-#define INTD IRQ_IQ31244_INTD
+-
+-#define INTE IRQ_IQ31244_I82546
+-
+-static inline int __init
+-iq31244_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+-{
+- static int pci_irq_table[][4] = {
+- /*
+- * PCI IDSEL/INTPIN->INTLINE
+- * A B C D
+- */
+-#ifdef CONFIG_ARCH_EP80219
+- {INTB, INTB, INTB, INTB}, /* CFlash */
+- {INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */
+- {INTD, INTD, INTD, INTD}, /* PCI-X Slot */
+- {INTC, INTC, INTC, INTC}, /* SATA */
+-#else
+- {INTB, INTB, INTB, INTB}, /* CFlash */
+- {INTC, INTC, INTC, INTC}, /* SATA */
+- {INTD, INTD, INTD, INTD}, /* PCI-X Slot */
+- {INTE, INTE, INTE, INTE}, /* 82546 GigE */
+-#endif // CONFIG_ARCH_EP80219
+- };
+-
+- BUG_ON(pin < 1 || pin > 4);
+-
+- return PCI_IRQ_TABLE_LOOKUP(0, 7);
+-}
+-
+-static int iq31244_setup(int nr, struct pci_sys_data *sys)
+-{
+- struct resource *res;
+-
+- if(nr != 0)
+- return 0;
+-
+- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+- if (!res)
+- panic("PCI: unable to alloc resources");
+-
+- res[0].start = IOP321_PCI_LOWER_IO_VA;
+- res[0].end = IOP321_PCI_UPPER_IO_VA;
+- res[0].name = "IQ31244 PCI I/O Space";
+- res[0].flags = IORESOURCE_IO;
+-
+- res[1].start = IOP321_PCI_LOWER_MEM_PA;
+- res[1].end = IOP321_PCI_UPPER_MEM_PA;
+- res[1].name = "IQ31244 PCI Memory Space";
+- res[1].flags = IORESOURCE_MEM;
+-
+- request_resource(&ioport_resource, &res[0]);
+- request_resource(&iomem_resource, &res[1]);
+-
+- sys->mem_offset = IOP321_PCI_MEM_OFFSET;
+- sys->io_offset = IOP321_PCI_IO_OFFSET;
+-
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
+-
+- return 1;
+-}
+-
+-static void iq31244_preinit(void)
+-{
+- iop321_init();
+-}
+-
+-static struct hw_pci iq31244_pci __initdata = {
+- .swizzle = pci_std_swizzle,
+- .nr_controllers = 1,
+- .setup = iq31244_setup,
+- .scan = iop321_scan_bus,
+- .preinit = iq31244_preinit,
+- .map_irq = iq31244_map_irq
+-};
+-
+-static int __init iq31244_pci_init(void)
+-{
+- if (machine_is_iq31244())
+- pci_common_init(&iq31244_pci);
+- return 0;
+-}
+-
+-subsys_initcall(iq31244_pci_init);
+-
+-
+-
+-
+diff --git a/arch/arm/mach-iop3xx/iq80321-mm.c b/arch/arm/mach-iop3xx/iq80321-mm.c
+deleted file mode 100644
+index d9cac5e..0000000
+--- a/arch/arm/mach-iop3xx/iq80321-mm.c
++++ /dev/null
+@@ -1,45 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/mm.c
+- *
+- * Low level memory initialization for iq80321 platform
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- *
+- * 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/mm.h>
+-#include <linux/init.h>
+-
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-
+-#include <asm/mach/map.h>
+-
+-
+-/*
+- * IQ80321 specific IO mappings
+- *
+- * We use RedBoot's setup for the onboard devices.
+- */
+-static struct map_desc iq80321_io_desc[] __initdata = {
+- { /* on-board devices */
+- .virtual = IQ80321_UART,
+- .pfn = __phys_to_pfn(IQ80321_UART),
+- .length = 0x00100000,
+- .type = MT_DEVICE
+- }
+-};
+-
+-void __init iq80321_map_io(void)
+-{
+- iop321_map_io();
+-
+- iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc));
+-}
+diff --git a/arch/arm/mach-iop3xx/iq80321-pci.c b/arch/arm/mach-iop3xx/iq80321-pci.c
+deleted file mode 100644
+index d9758d3..0000000
+--- a/arch/arm/mach-iop3xx/iq80321-pci.c
++++ /dev/null
+@@ -1,123 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iq80321-pci.c
+- *
+- * PCI support for the Intel IQ80321 reference board
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- * Copyright (C) 2004 Intel Corp.
+- *
+- * 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/pci.h>
+-#include <linux/init.h>
+-#include <linux/string.h>
+-#include <linux/slab.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/irq.h>
+-#include <asm/mach/pci.h>
+-#include <asm/mach-types.h>
+-
+-/*
+- * The following macro is used to lookup irqs in a standard table
+- * format for those systems that do not already have PCI
+- * interrupts properly routed. We assume 1 <= pin <= 4
+- */
+-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
+-({ int _ctl_ = -1; \
+- unsigned int _idsel = idsel - minid; \
+- if (_idsel <= maxid) \
+- _ctl_ = pci_irq_table[_idsel][pin-1]; \
+- _ctl_; })
+-
+-#define INTA IRQ_IQ80321_INTA
+-#define INTB IRQ_IQ80321_INTB
+-#define INTC IRQ_IQ80321_INTC
+-#define INTD IRQ_IQ80321_INTD
+-
+-#define INTE IRQ_IQ80321_I82544
+-
+-static inline int __init
+-iq80321_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+-{
+- static int pci_irq_table[][4] = {
+- /*
+- * PCI IDSEL/INTPIN->INTLINE
+- * A B C D
+- */
+- {INTE, INTE, INTE, INTE}, /* Gig-E */
+- {-1, -1, -1, -1}, /* Unused */
+- {INTC, INTD, INTA, INTB}, /* PCI-X Slot */
+- {-1, -1, -1, -1},
+- };
+-
+- BUG_ON(pin < 1 || pin > 4);
+-
+-// return PCI_IRQ_TABLE_LOOKUP(4, 7);
+- return pci_irq_table[idsel%4][pin-1];
+-}
+-
+-static int iq80321_setup(int nr, struct pci_sys_data *sys)
+-{
+- struct resource *res;
+-
+- if(nr != 0)
+- return 0;
+-
+- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+- if (!res)
+- panic("PCI: unable to alloc resources");
+-
+- res[0].start = IOP321_PCI_LOWER_IO_VA;
+- res[0].end = IOP321_PCI_UPPER_IO_VA;
+- res[0].name = "IQ80321 PCI I/O Space";
+- res[0].flags = IORESOURCE_IO;
+-
+- res[1].start = IOP321_PCI_LOWER_MEM_PA;
+- res[1].end = IOP321_PCI_UPPER_MEM_PA;
+- res[1].name = "IQ80321 PCI Memory Space";
+- res[1].flags = IORESOURCE_MEM;
+-
+- request_resource(&ioport_resource, &res[0]);
+- request_resource(&iomem_resource, &res[1]);
+-
+- sys->mem_offset = IOP321_PCI_MEM_OFFSET;
+- sys->io_offset = IOP321_PCI_IO_OFFSET;
+-
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
+-
+- return 1;
+-}
+-
+-static void iq80321_preinit(void)
+-{
+- iop321_init();
+-}
+-
+-static struct hw_pci iq80321_pci __initdata = {
+- .swizzle = pci_std_swizzle,
+- .nr_controllers = 1,
+- .setup = iq80321_setup,
+- .scan = iop321_scan_bus,
+- .preinit = iq80321_preinit,
+- .map_irq = iq80321_map_irq
+-};
+-
+-static int __init iq80321_pci_init(void)
+-{
+- if (machine_is_iq80321())
+- pci_common_init(&iq80321_pci);
+- return 0;
+-}
+-
+-subsys_initcall(iq80321_pci_init);
+-
+-
+-
+-
+diff --git a/arch/arm/mach-iop3xx/iq80331-mm.c b/arch/arm/mach-iop3xx/iq80331-mm.c
+deleted file mode 100644
+index 129eb49..0000000
+--- a/arch/arm/mach-iop3xx/iq80331-mm.c
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/mm.c
+- *
+- * Low level memory initialization for iq80331 platform
+- *
+- * Author: Dave Jiang <dave.jiang at intel.com>
+- * Copyright (C) 2003 Intel 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 <linux/mm.h>
+-#include <linux/init.h>
+-
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-
+-#include <asm/mach/map.h>
+-
+-
+-/*
+- * IQ80331 specific IO mappings
+- *
+- * We use RedBoot's setup for the onboard devices.
+- */
+-
+-void __init iq80331_map_io(void)
+-{
+- iop331_map_io();
+-}
+diff --git a/arch/arm/mach-iop3xx/iq80331-pci.c b/arch/arm/mach-iop3xx/iq80331-pci.c
+deleted file mode 100644
+index 40d8610..0000000
+--- a/arch/arm/mach-iop3xx/iq80331-pci.c
++++ /dev/null
+@@ -1,119 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iq80331-pci.c
+- *
+- * PCI support for the Intel IQ80331 reference board
+- *
+- * Author: Dave Jiang <dave.jiang at intel.com>
+- * Copyright (C) 2003, 2004 Intel Corp.
+- *
+- * 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/pci.h>
+-#include <linux/init.h>
+-#include <linux/string.h>
+-#include <linux/slab.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/irq.h>
+-#include <asm/mach/pci.h>
+-#include <asm/mach-types.h>
+-
+-/*
+- * The following macro is used to lookup irqs in a standard table
+- * format for those systems that do not already have PCI
+- * interrupts properly routed. We assume 1 <= pin <= 4
+- */
+-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
+-({ int _ctl_ = -1; \
+- unsigned int _idsel = idsel - minid; \
+- if (_idsel <= maxid) \
+- _ctl_ = pci_irq_table[_idsel][pin-1]; \
+- _ctl_; })
+-
+-#define INTA IRQ_IQ80331_INTA
+-#define INTB IRQ_IQ80331_INTB
+-#define INTC IRQ_IQ80331_INTC
+-#define INTD IRQ_IQ80331_INTD
+-
+-//#define INTE IRQ_IQ80331_I82544
+-
+-static inline int __init
+-iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+-{
+- static int pci_irq_table[][4] = {
+- /*
+- * PCI IDSEL/INTPIN->INTLINE
+- * A B C D
+- */
+- {INTB, INTC, INTD, INTA}, /* PCI-X Slot */
+- {INTC, INTC, INTC, INTC}, /* GigE */
+- };
+-
+- BUG_ON(pin < 1 || pin > 4);
+-
+- return PCI_IRQ_TABLE_LOOKUP(1, 7);
+-}
+-
+-static int iq80331_setup(int nr, struct pci_sys_data *sys)
+-{
+- struct resource *res;
+-
+- if(nr != 0)
+- return 0;
+-
+- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+- if (!res)
+- panic("PCI: unable to alloc resources");
+-
+- res[0].start = IOP331_PCI_LOWER_IO_VA;
+- res[0].end = IOP331_PCI_UPPER_IO_VA;
+- res[0].name = "IQ80331 PCI I/O Space";
+- res[0].flags = IORESOURCE_IO;
+-
+- res[1].start = IOP331_PCI_LOWER_MEM_PA;
+- res[1].end = IOP331_PCI_UPPER_MEM_PA;
+- res[1].name = "IQ80331 PCI Memory Space";
+- res[1].flags = IORESOURCE_MEM;
+-
+- request_resource(&ioport_resource, &res[0]);
+- request_resource(&iomem_resource, &res[1]);
+-
+- sys->mem_offset = IOP331_PCI_MEM_OFFSET;
+- sys->io_offset = IOP331_PCI_IO_OFFSET;
+-
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
+-
+- return 1;
+-}
+-
+-static void iq80331_preinit(void)
+-{
+- iop331_init();
+-}
+-
+-static struct hw_pci iq80331_pci __initdata = {
+- .swizzle = pci_std_swizzle,
+- .nr_controllers = 1,
+- .setup = iq80331_setup,
+- .scan = iop331_scan_bus,
+- .preinit = iq80331_preinit,
+- .map_irq = iq80331_map_irq
+-};
+-
+-static int __init iq80331_pci_init(void)
+-{
+- if (machine_is_iq80331())
+- pci_common_init(&iq80331_pci);
+- return 0;
+-}
+-
+-subsys_initcall(iq80331_pci_init);
+-
+-
+-
+-
+diff --git a/arch/arm/mach-iop3xx/iq80332-mm.c b/arch/arm/mach-iop3xx/iq80332-mm.c
+deleted file mode 100644
+index 2feaf75..0000000
+--- a/arch/arm/mach-iop3xx/iq80332-mm.c
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * linux/arch/arm/mach-iop3xx/mm.c
+- *
+- * Low level memory initialization for iq80332 platform
+- *
+- * Author: Dave Jiang <dave.jiang at intel.com>
+- * Copyright (C) 2004 Intel 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 <linux/mm.h>
+-#include <linux/init.h>
+-
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-
+-#include <asm/mach/map.h>
+-
+-
+-/*
+- * IQ80332 specific IO mappings
+- *
+- * We use RedBoot's setup for the onboard devices.
+- */
+-
+-void __init iq80332_map_io(void)
+-{
+- iop331_map_io();
+-}
+diff --git a/arch/arm/mach-iop3xx/iq80332-pci.c b/arch/arm/mach-iop3xx/iq80332-pci.c
+deleted file mode 100644
+index afc0676..0000000
+--- a/arch/arm/mach-iop3xx/iq80332-pci.c
++++ /dev/null
+@@ -1,125 +0,0 @@
+-/*
+- * arch/arm/mach-iop3xx/iq80332-pci.c
+- *
+- * PCI support for the Intel IQ80332 reference board
+- *
+- * Author: Dave Jiang <dave.jiang at intel.com>
+- * Copyright (C) 2004 Intel Corp.
+- *
+- * 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/pci.h>
+-#include <linux/init.h>
+-#include <linux/string.h>
+-#include <linux/slab.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/irq.h>
+-#include <asm/mach/pci.h>
+-#include <asm/mach-types.h>
+-
+-/*
+- * The following macro is used to lookup irqs in a standard table
+- * format for those systems that do not already have PCI
+- * interrupts properly routed. We assume 1 <= pin <= 4
+- */
+-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
+-({ int _ctl_ = -1; \
+- unsigned int _idsel = idsel - minid; \
+- if (_idsel <= maxid) \
+- _ctl_ = pci_irq_table[_idsel][pin-1]; \
+- _ctl_; })
+-
+-#define INTA IRQ_IQ80332_INTA
+-#define INTB IRQ_IQ80332_INTB
+-#define INTC IRQ_IQ80332_INTC
+-#define INTD IRQ_IQ80332_INTD
+-
+-//#define INTE IRQ_IQ80332_I82544
+-
+-static inline int __init
+-iq80332_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+-{
+- static int pci_irq_table[][8] = {
+- /*
+- * PCI IDSEL/INTPIN->INTLINE
+- * A B C D
+- */
+- {-1, -1, -1, -1},
+- {-1, -1, -1, -1},
+- {-1, -1, -1, -1},
+- {INTA, INTB, INTC, INTD}, /* PCI-X Slot */
+- {-1, -1, -1, -1},
+- {INTC, INTC, INTC, INTC}, /* GigE */
+- {-1, -1, -1, -1},
+- {-1, -1, -1, -1},
+- };
+-
+- BUG_ON(pin < 1 || pin > 4);
+-
+- return PCI_IRQ_TABLE_LOOKUP(1, 7);
+-}
+-
+-static int iq80332_setup(int nr, struct pci_sys_data *sys)
+-{
+- struct resource *res;
+-
+- if(nr != 0)
+- return 0;
+-
+- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+- if (!res)
+- panic("PCI: unable to alloc resources");
+-
+- res[0].start = IOP331_PCI_LOWER_IO_VA;
+- res[0].end = IOP331_PCI_UPPER_IO_VA;
+- res[0].name = "IQ80332 PCI I/O Space";
+- res[0].flags = IORESOURCE_IO;
+-
+- res[1].start = IOP331_PCI_LOWER_MEM_PA;
+- res[1].end = IOP331_PCI_UPPER_MEM_PA;
+- res[1].name = "IQ80332 PCI Memory Space";
+- res[1].flags = IORESOURCE_MEM;
+-
+- request_resource(&ioport_resource, &res[0]);
+- request_resource(&iomem_resource, &res[1]);
+-
+- sys->mem_offset = IOP331_PCI_MEM_OFFSET;
+- sys->io_offset = IOP331_PCI_IO_OFFSET;
+-
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
+-
+- return 1;
+-}
+-
+-static void iq80332_preinit(void)
+-{
+- iop331_init();
+-}
+-
+-static struct hw_pci iq80332_pci __initdata = {
+- .swizzle = pci_std_swizzle,
+- .nr_controllers = 1,
+- .setup = iq80332_setup,
+- .scan = iop331_scan_bus,
+- .preinit = iq80332_preinit,
+- .map_irq = iq80332_map_irq
+-};
+-
+-static int __init iq80332_pci_init(void)
+-{
+- if (machine_is_iq80332())
+- pci_common_init(&iq80332_pci);
+- return 0;
+-}
+-
+-subsys_initcall(iq80332_pci_init);
+-
+-
+-
+-
+diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
+index 7f91f68..22c98e9 100644
+--- a/arch/arm/mach-ixp2000/core.c
++++ b/arch/arm/mach-ixp2000/core.c
+@@ -204,7 +204,7 @@ unsigned long ixp2000_gettimeoffset (voi
+ return offset / ticks_per_usec;
+ }
+
+-static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static int ixp2000_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+@@ -213,7 +213,7 @@ static int ixp2000_timer_interrupt(int i
+
+ while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr)
+ >= ticks_per_jiffy) {
+- timer_tick(regs);
++ timer_tick();
+ next_jiffy_time -= ticks_per_jiffy;
+ }
+
+@@ -308,7 +308,7 @@ EXPORT_SYMBOL(gpio_line_config);
+ /*************************************************************************
+ * IRQ handling IXP2000
+ *************************************************************************/
+-static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ int i;
+ unsigned long status = *IXP2000_GPIO_INST;
+@@ -316,7 +316,7 @@ static void ixp2000_GPIO_irq_handler(uns
+ for (i = 0; i <= 7; i++) {
+ if (status & (1<<i)) {
+ desc = irq_desc + i + IRQ_IXP2000_GPIO0;
+- desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc, regs);
++ desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc);
+ }
+ }
+ }
+@@ -401,7 +401,7 @@ static void ixp2000_pci_irq_unmask(unsig
+ /*
+ * Error interrupts. These are used extensively by the microengine drivers
+ */
+-static void ixp2000_err_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void ixp2000_err_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ int i;
+ unsigned long status = *IXP2000_IRQ_ERR_STATUS;
+@@ -409,7 +409,7 @@ static void ixp2000_err_irq_handler(unsi
+ for(i = 31; i >= 0; i--) {
+ if(status & (1 << i)) {
+ desc = irq_desc + IRQ_IXP2000_DRAM0_MIN_ERR + i;
+- desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc, regs);
++ desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc);
+ }
+ }
+ }
+diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
+index a6f1480..0fdd03a 100644
+--- a/arch/arm/mach-ixp2000/ixdp2400.c
++++ b/arch/arm/mach-ixp2000/ixdp2400.c
+@@ -133,11 +133,13 @@ static void ixdp2400_pci_postinit(void)
+ struct pci_dev *dev;
+
+ if (ixdp2x00_master_npu()) {
+- dev = pci_find_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
++ dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
+ pci_remove_bus_device(dev);
++ pci_dev_put(dev);
+ } else {
+- dev = pci_find_slot(1, IXDP2400_MASTER_ENET_DEVFN);
++ dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
+ pci_remove_bus_device(dev);
++ pci_dev_put(dev);
+
+ ixdp2x00_slave_pci_postinit();
+ }
+diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
+index 91d36d9..70d247f 100644
+--- a/arch/arm/mach-ixp2000/ixdp2800.c
++++ b/arch/arm/mach-ixp2000/ixdp2800.c
+@@ -261,14 +261,16 @@ int __init ixdp2800_pci_init(void)
+
+ pci_common_init(&ixdp2800_pci);
+ if (ixdp2x00_master_npu()) {
+- dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
++ dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
+ pci_remove_bus_device(dev);
++ pci_dev_put(dev);
+
+ ixdp2800_master_enable_slave();
+ ixdp2800_master_wait_for_slave_bus_scan();
+ } else {
+- dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
++ dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
+ pci_remove_bus_device(dev);
++ pci_dev_put(dev);
+ }
+ }
+
+diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
+index 40eef8b..aa26550 100644
+--- a/arch/arm/mach-ixp2000/ixdp2x00.c
++++ b/arch/arm/mach-ixp2000/ixdp2x00.c
+@@ -106,7 +106,7 @@ static void ixdp2x00_irq_unmask(unsigned
+ ixp2000_release_slowport(&old_cfg);
+ }
+
+-static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ volatile u32 ex_interrupt = 0;
+ static struct slowport_cfg old_cfg;
+@@ -132,7 +132,7 @@ static void ixdp2x00_irq_handler(unsigne
+ struct irqdesc *cpld_desc;
+ int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
+ cpld_desc = irq_desc + cpld_irq;
+- desc_handle_irq(cpld_irq, cpld_desc, regs);
++ desc_handle_irq(cpld_irq, cpld_desc);
+ }
+ }
+
+@@ -241,11 +241,14 @@ void ixdp2x00_slave_pci_postinit(void)
+ /*
+ * Remove PMC device is there is one
+ */
+- if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN)))
++ if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
+ pci_remove_bus_device(dev);
++ pci_dev_put(dev);
++ }
+
+- dev = pci_find_slot(0, IXDP2X00_21555_DEVFN);
++ dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
+ pci_remove_bus_device(dev);
++ pci_dev_put(dev);
+ }
+
+ /**************************************************************************
+diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
+index 7f42366..9ccae9e 100644
+--- a/arch/arm/mach-ixp2000/ixdp2x01.c
++++ b/arch/arm/mach-ixp2000/ixdp2x01.c
+@@ -63,7 +63,7 @@ static void ixdp2x01_irq_unmask(unsigned
+
+ static u32 valid_irq_mask;
+
+-static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ u32 ex_interrupt;
+ int i;
+@@ -82,7 +82,7 @@ static void ixdp2x01_irq_handler(unsigne
+ struct irqdesc *cpld_desc;
+ int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
+ cpld_desc = irq_desc + cpld_irq;
+- desc_handle_irq(cpld_irq, cpld_desc, regs);
++ desc_handle_irq(cpld_irq, cpld_desc);
+ }
+ }
+
+diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
+index 566a078..a704a18 100644
+--- a/arch/arm/mach-ixp23xx/core.c
++++ b/arch/arm/mach-ixp23xx/core.c
+@@ -251,7 +251,7 @@ static void ixp23xx_pci_irq_unmask(unsig
+ /*
+ * TODO: Should this just be done at ASM level?
+ */
+-static void pci_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void pci_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ u32 pci_interrupt;
+ unsigned int irqno;
+@@ -271,7 +271,7 @@ static void pci_handler(unsigned int irq
+ }
+
+ int_desc = irq_desc + irqno;
+- desc_handle_irq(irqno, int_desc, regs);
++ desc_handle_irq(irqno, int_desc);
+
+ desc->chip->unmask(irq);
+ }
+@@ -348,12 +348,12 @@ ixp23xx_gettimeoffset(void)
+ }
+
+ static irqreturn_t
+-ixp23xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++ixp23xx_timer_interrupt(int irq, void *dev_id)
+ {
+ /* Clear Pending Interrupt by writing '1' to it */
+ *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
+ while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) {
+- timer_tick(regs);
++ timer_tick();
+ next_jiffy_time += LATCH;
+ }
+
+diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
+index 37a32e6..b6ab0e8 100644
+--- a/arch/arm/mach-ixp23xx/ixdp2351.c
++++ b/arch/arm/mach-ixp23xx/ixdp2351.c
+@@ -60,7 +60,7 @@ static void ixdp2351_inta_unmask(unsigne
+ *IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(irq);
+ }
+
+-static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ u16 ex_interrupt =
+ *IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID;
+@@ -74,7 +74,7 @@ static void ixdp2351_inta_handler(unsign
+ int cpld_irq =
+ IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i);
+ cpld_desc = irq_desc + cpld_irq;
+- desc_handle_irq(cpld_irq, cpld_desc, regs);
++ desc_handle_irq(cpld_irq, cpld_desc);
+ }
+ }
+
+@@ -97,7 +97,7 @@ static void ixdp2351_intb_unmask(unsigne
+ *IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(irq);
+ }
+
+-static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ u16 ex_interrupt =
+ *IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID;
+@@ -111,7 +111,7 @@ static void ixdp2351_intb_handler(unsign
+ int cpld_irq =
+ IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i);
+ cpld_desc = irq_desc + cpld_irq;
+- desc_handle_irq(cpld_irq, cpld_desc, regs);
++ desc_handle_irq(cpld_irq, cpld_desc);
+ }
+ }
+
+diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
+index 7c25dbd..fbe288a 100644
+--- a/arch/arm/mach-ixp4xx/common.c
++++ b/arch/arm/mach-ixp4xx/common.c
+@@ -26,6 +26,7 @@
+ #include <linux/bitops.h>
+ #include <linux/time.h>
+ #include <linux/timex.h>
++#include <linux/clocksource.h>
+
+ #include <asm/hardware.h>
+ #include <asm/uaccess.h>
+@@ -85,7 +86,8 @@ enum ixp4xx_irq_type {
+ IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
+ };
+
+-static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
++/* Each bit represents an IRQ: 1: edge-triggered, 0: level triggered */
++static unsigned long long ixp4xx_irq_edge = 0;
+
+ /*
+ * IRQ -> GPIO mapping table
+@@ -134,7 +136,11 @@ static int ixp4xx_set_irq_type(unsigned
+ default:
+ return -EINVAL;
+ }
+- ixp4xx_config_irq(irq, irq_type);
++
++ if (irq_type == IXP4XX_IRQ_EDGE)
++ ixp4xx_irq_edge |= (1 << irq);
++ else
++ ixp4xx_irq_edge &= ~(1 << irq);
+
+ if (line >= 8) { /* pins 8-15 */
+ line -= 8;
+@@ -166,14 +172,6 @@ static void ixp4xx_irq_mask(unsigned int
+ *IXP4XX_ICMR &= ~(1 << irq);
+ }
+
+-static void ixp4xx_irq_unmask(unsigned int irq)
+-{
+- if (cpu_is_ixp46x() && irq >= 32)
+- *IXP4XX_ICMR2 |= (1 << (irq - 32));
+- else
+- *IXP4XX_ICMR |= (1 << irq);
+-}
+-
+ static void ixp4xx_irq_ack(unsigned int irq)
+ {
+ int line = (irq < 32) ? irq2gpio[irq] : -1;
+@@ -186,41 +184,25 @@ static void ixp4xx_irq_ack(unsigned int
+ * Level triggered interrupts on GPIO lines can only be cleared when the
+ * interrupt condition disappears.
+ */
+-static void ixp4xx_irq_level_unmask(unsigned int irq)
++static void ixp4xx_irq_unmask(unsigned int irq)
+ {
+- ixp4xx_irq_ack(irq);
+- ixp4xx_irq_unmask(irq);
+-}
++ if (!(ixp4xx_irq_edge & (1 << irq)))
++ ixp4xx_irq_ack(irq);
+
+-static struct irqchip ixp4xx_irq_level_chip = {
+- .ack = ixp4xx_irq_mask,
+- .mask = ixp4xx_irq_mask,
+- .unmask = ixp4xx_irq_level_unmask,
+- .set_type = ixp4xx_set_irq_type,
+-};
++ if (cpu_is_ixp46x() && irq >= 32)
++ *IXP4XX_ICMR2 |= (1 << (irq - 32));
++ else
++ *IXP4XX_ICMR |= (1 << irq);
++}
+
+-static struct irqchip ixp4xx_irq_edge_chip = {
++static struct irqchip ixp4xx_irq_chip = {
++ .name = "IXP4xx",
+ .ack = ixp4xx_irq_ack,
+ .mask = ixp4xx_irq_mask,
+ .unmask = ixp4xx_irq_unmask,
+ .set_type = ixp4xx_set_irq_type,
+ };
+
+-static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
+-{
+- switch (type) {
+- case IXP4XX_IRQ_LEVEL:
+- set_irq_chip(irq, &ixp4xx_irq_level_chip);
+- set_irq_handler(irq, do_level_IRQ);
+- break;
+- case IXP4XX_IRQ_EDGE:
+- set_irq_chip(irq, &ixp4xx_irq_edge_chip);
+- set_irq_handler(irq, do_edge_IRQ);
+- break;
+- }
+- set_irq_flags(irq, IRQF_VALID);
+-}
+-
+ void __init ixp4xx_init_irq(void)
+ {
+ int i = 0;
+@@ -240,8 +222,11 @@ void __init ixp4xx_init_irq(void)
+ }
+
+ /* Default to all level triggered */
+- for(i = 0; i < NR_IRQS; i++)
+- ixp4xx_config_irq(i, IXP4XX_IRQ_LEVEL);
++ for(i = 0; i < NR_IRQS; i++) {
++ set_irq_chip(i, &ixp4xx_irq_chip);
++ set_irq_handler(i, do_level_IRQ);
++ set_irq_flags(i, IRQF_VALID);
++ }
+ }
+
+
+@@ -255,17 +240,7 @@ static unsigned volatile last_jiffy_time
+
+ #define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
+
+-/* IRQs are disabled before entering here from do_gettimeofday() */
+-static unsigned long ixp4xx_gettimeoffset(void)
+-{
+- u32 elapsed;
+-
+- elapsed = *IXP4XX_OSTS - last_jiffy_time;
+-
+- return elapsed / CLOCK_TICKS_PER_USEC;
+-}
+-
+-static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+@@ -276,7 +251,7 @@ static irqreturn_t ixp4xx_timer_interrup
+ * Catch up with the real idea of time
+ */
+ while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
+- timer_tick(regs);
++ timer_tick();
+ last_jiffy_time += LATCH;
+ }
+
+@@ -309,7 +284,6 @@ static void __init ixp4xx_timer_init(voi
+
+ struct sys_timer ixp4xx_timer = {
+ .init = ixp4xx_timer_init,
+- .offset = ixp4xx_gettimeoffset,
+ };
+
+ static struct resource ixp46x_i2c_resources[] = {
+@@ -365,3 +339,29 @@ void __init ixp4xx_sys_init(void)
+ ixp4xx_exp_bus_size >> 20);
+ }
+
++cycle_t ixp4xx_get_cycles(void)
++{
++ return *IXP4XX_OSTS;
++}
++
++static struct clocksource clocksource_ixp4xx = {
++ .name = "OSTS",
++ .rating = 200,
++ .read = ixp4xx_get_cycles,
++ .mask = CLOCKSOURCE_MASK(32),
++ .shift = 20,
++ .is_continuous = 1,
++};
++
++unsigned long ixp4xx_timer_freq = FREQ;
++static int __init ixp4xx_clocksource_init(void)
++{
++ clocksource_ixp4xx.mult =
++ clocksource_hz2mult(ixp4xx_timer_freq,
++ clocksource_ixp4xx.shift);
++ clocksource_register(&clocksource_ixp4xx);
++
++ return 0;
++}
++
++device_initcall(ixp4xx_clocksource_init);
+diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c
+index 2cebb28..7bc94f3 100644
+--- a/arch/arm/mach-ixp4xx/coyote-pci.c
++++ b/arch/arm/mach-ixp4xx/coyote-pci.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/arch/mach-ixp4xx/coyote-pci.c
++ * arch/arm/mach-ixp4xx/coyote-pci.c
+ *
+ * PCI setup routines for ADI Engineering Coyote platform
+ *
+diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
+index ed52708..509a95a 100644
+--- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c
++++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/arch/mach-ixp4xx/ixdpg425-pci.c
++ * arch/arm/mach-ixp4xx/ixdpg425-pci.c
+ *
+ * PCI setup routines for Intel IXDPG425 Platform
+ *
+diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c
+index 81ffcae..29aa98d 100644
+--- a/arch/arm/mach-ixp4xx/nas100d-power.c
++++ b/arch/arm/mach-ixp4xx/nas100d-power.c
+@@ -24,7 +24,7 @@
+
+ #include <asm/mach-types.h>
+
+-static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
+ {
+ /* Signal init to do the ctrlaltdel action, this will bypass init if
+ * it hasn't started and do a kernel_restart.
+diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
+index a29b3b2..acd71e9 100644
+--- a/arch/arm/mach-ixp4xx/nslu2-power.c
++++ b/arch/arm/mach-ixp4xx/nslu2-power.c
+@@ -25,7 +25,7 @@
+
+ #include <asm/mach-types.h>
+
+-static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
+ {
+ /* Signal init to do the ctrlaltdel action, this will bypass init if
+ * it hasn't started and do a kernel_restart.
+@@ -35,7 +35,7 @@ static irqreturn_t nslu2_power_handler(i
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t nslu2_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
+ {
+ /* This is the paper-clip reset, it shuts the machine down directly.
+ */
+diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
+index 749a337..162c266 100644
+--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
++++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
+@@ -159,6 +159,8 @@ static void nslu2_power_off(void)
+
+ static void __init nslu2_init(void)
+ {
++ ixp4xx_timer_freq = NSLU2_FREQ;
++
+ ixp4xx_sys_init();
+
+ nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+diff --git a/arch/arm/mach-lh7a40x/Kconfig b/arch/arm/mach-lh7a40x/Kconfig
+index 558a34f..147b019 100644
+--- a/arch/arm/mach-lh7a40x/Kconfig
++++ b/arch/arm/mach-lh7a40x/Kconfig
+@@ -14,7 +14,7 @@ config MACH_LPD7A400
+ bool "LPD7A400 Card Engine"
+ select ARCH_LH7A400
+ # select IDE_POLL
+- select HAS_TOUCHSCREEN_ADS7843_LH7
++# select HAS_TOUCHSCREEN_ADS7843_LH7
+ help
+ Say Y here if you are using Logic Product Development's
+ LPD7A400 CardEngine. For the time being, the LPD7A400 and
+@@ -24,7 +24,7 @@ config MACH_LPD7A404
+ bool "LPD7A404 Card Engine"
+ select ARCH_LH7A404
+ # select IDE_POLL
+- select HAS_TOUCHSCREEN_ADC_LH7
++# select HAS_TOUCHSCREEN_ADC_LH7
+ help
+ Say Y here if you are using Logic Product Development's
+ LPD7A404 CardEngine. For the time being, the LPD7A400 and
+diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
+index 4f2ab48..15fbcc9 100644
+--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
++++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
+@@ -71,14 +71,13 @@ static struct irq_chip kev7a400_cpld_chi
+ };
+
+
+-static void kev7a400_cpld_handler (unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void kev7a400_cpld_handler (unsigned int irq, struct irqdesc *desc)
+ {
+ u32 mask = CPLD_LATCHED_INTS;
+ irq = IRQ_KEV7A400_CPLD;
+ for (; mask; mask >>= 1, ++irq) {
+ if (mask & 1)
+- desc[irq].handle (irq, desc, regs);
++ desc[irq].handle (irq, desc);
+ }
+ }
+
+diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+index a691011..8441e0a 100644
+--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
++++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+@@ -164,7 +164,7 @@ static void lh7a40x_ack_cpld_irq (u32 ir
+ /* CPLD doesn't have ack capability, but some devices may */
+
+ #if defined (CPLD_INTMASK_TOUCH)
+- /* The touch control *must* mask the the interrupt because the
++ /* The touch control *must* mask the interrupt because the
+ * interrupt bit is read by the driver to determine if the pen
+ * is still down. */
+ if (irq == IRQ_TOUCH)
+@@ -207,8 +207,7 @@ static struct irq_chip lpd7a40x_cpld_chi
+ .unmask = lh7a40x_unmask_cpld_irq,
+ };
+
+-static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int mask = CPLD_INTERRUPTS;
+
+diff --git a/arch/arm/mach-lh7a40x/clcd.c b/arch/arm/mach-lh7a40x/clcd.c
+index 93751fe..1992db4 100644
+--- a/arch/arm/mach-lh7a40x/clcd.c
++++ b/arch/arm/mach-lh7a40x/clcd.c
+@@ -8,7 +8,7 @@
+ * version 2 as published by the Free Software Foundation.
+ *
+ */
+-#include <linux/config.h>
++
+ #include <linux/init.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+diff --git a/arch/arm/mach-lh7a40x/clocks.c b/arch/arm/mach-lh7a40x/clocks.c
+index 2291afe..7530a95 100644
+--- a/arch/arm/mach-lh7a40x/clocks.c
++++ b/arch/arm/mach-lh7a40x/clocks.c
+@@ -8,7 +8,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/cpufreq.h>
+ #include <asm/hardware.h>
+ #include <asm/arch/clocks.h>
+diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h
+index 18e8bb4..0ca20c6 100644
+--- a/arch/arm/mach-lh7a40x/common.h
++++ b/arch/arm/mach-lh7a40x/common.h
+@@ -15,4 +15,4 @@ extern void lh7a404_init_irq (void);
+ extern void lh7a40x_clcd_init (void);
+ extern void lh7a40x_init_board_irq (void);
+
+-#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs)
++#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq))
+diff --git a/arch/arm/mach-lh7a40x/irq-kev7a400.c b/arch/arm/mach-lh7a40x/irq-kev7a400.c
+index f9b3fe9..6460713 100644
+--- a/arch/arm/mach-lh7a40x/irq-kev7a400.c
++++ b/arch/arm/mach-lh7a40x/irq-kev7a400.c
+@@ -51,14 +51,13 @@ irq_chip lh7a400_cpld_chip = {
+ };
+
+ static void
+-lh7a400_cpld_handler (unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++lh7a400_cpld_handler (unsigned int irq, struct irqdesc *desc)
+ {
+ u32 mask = CPLD_LATCHED_INTS;
+ irq = IRQ_KEV_7A400_CPLD;
+ for (; mask; mask >>= 1, ++irq) {
+ if (mask & 1)
+- desc[irq].handle (irq, desc, regs);
++ desc[irq].handle (irq, desc);
+ }
+ }
+
+diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+index d6055dd..b203768 100644
+--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
++++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+@@ -57,8 +57,7 @@ static struct irq_chip lh7a40x_cpld_chip
+ .unmask = lh7a40x_unmask_cpld_irq,
+ };
+
+-static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int mask = CPLD_INTERRUPTS;
+
+diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
+index ad5652e..bef3c4b 100644
+--- a/arch/arm/mach-lh7a40x/time.c
++++ b/arch/arm/mach-lh7a40x/time.c
+@@ -39,12 +39,12 @@
+ #endif
+
+ static irqreturn_t
+-lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++lh7a40x_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+ TIMER_EOI = 0;
+- timer_tick(regs);
++ timer_tick();
+
+ write_sequnlock(&xtime_lock);
+
+diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
+index af0b135..edbbbdc 100644
+--- a/arch/arm/mach-netx/generic.c
++++ b/arch/arm/mach-netx/generic.c
+@@ -69,8 +69,7 @@ static struct platform_device *devices[]
+ #endif
+
+ static void
+-netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+- struct pt_regs *regs)
++netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
+ {
+ unsigned int irq = NETX_IRQ_HIF_CHAINED(0);
+ unsigned int stat;
+@@ -83,7 +82,7 @@ netx_hif_demux_handler(unsigned int irq_
+ while (stat) {
+ if (stat & 1) {
+ DEBUG_IRQ("handling irq %d\n", irq);
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ }
+ irq++;
+ desc++;
+diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
+index 6d72c81..0993336 100644
+--- a/arch/arm/mach-netx/time.c
++++ b/arch/arm/mach-netx/time.c
+@@ -38,11 +38,11 @@ static unsigned long netx_gettimeoffset(
+ * IRQ handler for the timer
+ */
+ static irqreturn_t
+-netx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++netx_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+
+ /* acknowledge interrupt */
+diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
+index c753a3c..62e42c7 100644
+--- a/arch/arm/mach-omap1/board-fsample.c
++++ b/arch/arm/mach-omap1/board-fsample.c
+@@ -172,9 +172,11 @@ static struct resource kp_resources[] =
+ };
+
+ static struct omap_kp_platform_data kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = fsample_keymap,
++ .rows = 8,
++ .cols = 8,
++ .keymap = fsample_keymap,
++ .keymapsize = ARRAY_SIZE(fsample_keymap),
++ .delay = 4,
+ };
+
+ static struct platform_device kp_device = {
+diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
+index cd3a06d..6e11307 100644
+--- a/arch/arm/mach-omap1/board-h2.c
++++ b/arch/arm/mach-omap1/board-h2.c
+@@ -167,10 +167,13 @@ static struct resource h2_kp_resources[]
+ };
+
+ static struct omap_kp_platform_data h2_kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = h2_keymap,
+- .rep = 1,
++ .rows = 8,
++ .cols = 8,
++ .keymap = h2_keymap,
++ .keymapsize = ARRAY_SIZE(h2_keymap),
++ .rep = 1,
++ .delay = 9,
++ .dbounce = 1,
+ };
+
+ static struct platform_device h2_kp_device = {
+diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
+index 7b20611..f225a08 100644
+--- a/arch/arm/mach-omap1/board-h3.c
++++ b/arch/arm/mach-omap1/board-h3.c
+@@ -247,10 +247,13 @@ static struct resource h3_kp_resources[]
+ };
+
+ static struct omap_kp_platform_data h3_kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = h3_keymap,
+- .rep = 1,
++ .rows = 8,
++ .cols = 8,
++ .keymap = h3_keymap,
++ .keymapsize = ARRAY_SIZE(h3_keymap),
++ .rep = 1,
++ .delay = 9,
++ .dbounce = 1,
+ };
+
+ static struct platform_device h3_kp_device = {
+diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
+index 4cbc62d..cb00530 100644
+--- a/arch/arm/mach-omap1/board-innovator.c
++++ b/arch/arm/mach-omap1/board-innovator.c
+@@ -159,9 +159,11 @@ static struct resource innovator_kp_reso
+ };
+
+ static struct omap_kp_platform_data innovator_kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = innovator_keymap,
++ .rows = 8,
++ .cols = 8,
++ .keymap = innovator_keymap,
++ .keymapsize = ARRAY_SIZE(innovator_keymap),
++ .delay = 4,
+ };
+
+ static struct platform_device innovator_kp_device = {
+diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
+index 02b980d..dbc555d 100644
+--- a/arch/arm/mach-omap1/board-nokia770.c
++++ b/arch/arm/mach-omap1/board-nokia770.c
+@@ -71,9 +71,11 @@ static struct resource nokia770_kp_resou
+ };
+
+ static struct omap_kp_platform_data nokia770_kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = nokia770_keymap
++ .rows = 8,
++ .cols = 8,
++ .keymap = nokia770_keymap,
++ .keymapsize = ARRAY_SIZE(nokia770_keymap)
++ .delay = 4,
+ };
+
+ static struct platform_device nokia770_kp_device = {
+diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
+index b742261..3a62280 100644
+--- a/arch/arm/mach-omap1/board-osk.c
++++ b/arch/arm/mach-omap1/board-osk.c
+@@ -266,9 +266,11 @@ static const int osk_keymap[] = {
+ };
+
+ static struct omap_kp_platform_data osk_kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = (int *) osk_keymap,
++ .rows = 8,
++ .cols = 8,
++ .keymap = (int *) osk_keymap,
++ .keymapsize = ARRAY_SIZE(osk_keymap),
++ .delay = 9,
+ };
+
+ static struct resource osk5912_kp_resources[] = {
+@@ -325,7 +327,7 @@ static struct spi_board_info __initdata
+
+ #ifdef CONFIG_PM
+ static irqreturn_t
+-osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs)
++osk_mistral_wake_interrupt(int irq, void *ignored)
+ {
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
+index 64b45d8..fa4be96 100644
+--- a/arch/arm/mach-omap1/board-perseus2.c
++++ b/arch/arm/mach-omap1/board-perseus2.c
+@@ -171,9 +171,12 @@ static struct resource kp_resources[] =
+ };
+
+ static struct omap_kp_platform_data kp_data = {
+- .rows = 8,
+- .cols = 8,
+- .keymap = p2_keymap,
++ .rows = 8,
++ .cols = 8,
++ .keymap = p2_keymap,
++ .keymapsize = ARRAY_SIZE(p2_keymap),
++ .delay = 4,
++ .dbounce = 1,
+ };
+
+ static struct platform_device kp_device = {
+diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
+index f1958e8..638490e 100644
+--- a/arch/arm/mach-omap1/clock.c
++++ b/arch/arm/mach-omap1/clock.c
+@@ -20,6 +20,7 @@
+ #include <linux/clk.h>
+
+ #include <asm/io.h>
++#include <asm/mach-types.h>
+
+ #include <asm/arch/cpu.h>
+ #include <asm/arch/usb.h>
+@@ -586,77 +587,53 @@ static int omap1_clk_set_rate(struct clk
+ *-------------------------------------------------------------------------*/
+
+ #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 omap1_early_clk_reset(void)
+-{
+- //omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+-}
+
+-static int __init omap1_late_clk_reset(void)
++static void __init omap1_clk_disable_unused(struct clk *clk)
+ {
+- /* Turn off all unused clocks */
+- struct clk *p;
+ __u32 regval32;
+
+- /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
+- regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
+- omap_writew(regval32, 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;
+-
+- /* Clocks in the DSP domain need api_ck. Just assume bootloader
+- * has not enabled any DSP clocks */
+- if ((u32)p->enable_reg == DSP_IDLECT2) {
+- printk(KERN_INFO "Skipping reset check for DSP domain "
+- "clock \"%s\"\n", p->name);
+- continue;
+- }
++ /* Clocks in the DSP domain need api_ck. Just assume bootloader
++ * has not enabled any DSP clocks */
++ if ((u32)clk->enable_reg == DSP_IDLECT2) {
++ printk(KERN_INFO "Skipping reset check for DSP domain "
++ "clock \"%s\"\n", clk->name);
++ return;
++ }
+
+- /* 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);
++ /* Is the clock already disabled? */
++ if (clk->flags & ENABLE_REG_32BIT) {
++ if (clk->flags & VIRTUAL_IO_ADDRESS)
++ regval32 = __raw_readl(clk->enable_reg);
+ else
+- regval32 = omap_readw(p->enable_reg);
+- }
+-
+- if ((regval32 & (1 << p->enable_bit)) == 0)
+- continue;
++ regval32 = omap_readl(clk->enable_reg);
++ } else {
++ if (clk->flags & VIRTUAL_IO_ADDRESS)
++ regval32 = __raw_readw(clk->enable_reg);
++ else
++ regval32 = omap_readw(clk->enable_reg);
++ }
+
+- /* 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.clk // FIX: SoSSI, SSR
+- || p == &arm_gpio_ck // FIX: GPIO code for 1510
+- ) {
+- printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+- p->name);
+- continue;
+- }
++ if ((regval32 & (1 << clk->enable_bit)) == 0)
++ return;
+
+- printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+- p->disable(p);
+- printk(" done\n");
++ /* FIXME: This clock seems to be necessary but no-one
++ * has asked for its activation. */
++ if (clk == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera
++ || clk == &ck_dpll1out.clk // FIX: SoSSI, SSR
++ || clk == &arm_gpio_ck // FIX: GPIO code for 1510
++ ) {
++ printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
++ clk->name);
++ return;
+ }
+
+- return 0;
++ printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->name);
++ clk->disable(clk);
++ printk(" done\n");
+ }
+-late_initcall(omap1_late_clk_reset);
+
+ #else
+-#define omap1_early_clk_reset() {}
++#define omap1_clk_disable_unused NULL
+ #endif
+
+ static struct clk_functions omap1_clk_functions = {
+@@ -664,6 +641,7 @@ static struct clk_functions omap1_clk_fu
+ .clk_disable = omap1_clk_disable,
+ .clk_round_rate = omap1_clk_round_rate,
+ .clk_set_rate = omap1_clk_set_rate,
++ .clk_disable_unused = omap1_clk_disable_unused,
+ };
+
+ int __init omap1_clk_init(void)
+@@ -671,8 +649,13 @@ int __init omap1_clk_init(void)
+ struct clk ** clkp;
+ const struct omap_clock_config *info;
+ int crystal_type = 0; /* Default 12 MHz */
++ u32 reg;
++
++ /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
++ reg = omap_readw(SOFT_REQ_REG) & (1 << 4);
++ omap_writew(reg, SOFT_REQ_REG);
++ omap_writew(0, SOFT_REQ_REG2);
+
+- omap1_early_clk_reset();
+ clk_init(&omap1_clk_functions);
+
+ /* By default all idlect1 clocks are allowed to idle */
+@@ -772,6 +755,12 @@ int __init omap1_clk_init(void)
+ omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
+ #endif
+
++ /* Amstrad Delta wants BCLK high when inactive */
++ if (machine_is_ams_delta())
++ omap_writel(omap_readl(ULPD_CLOCK_CTRL) |
++ (1 << SDW_MCLK_INV_BIT),
++ ULPD_CLOCK_CTRL);
++
+ /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
+ /* (on 730, bit 13 must not be cleared) */
+ if (cpu_is_omap730())
+diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h
+index b7c6881..f7df002 100644
+--- a/arch/arm/mach-omap1/clock.h
++++ b/arch/arm/mach-omap1/clock.h
+@@ -89,6 +89,7 @@ struct arm_idlect1_clk {
+ #define EN_DSPTIMCK 5
+
+ /* Various register defines for clock controls scattered around OMAP chip */
++#define SDW_MCLK_INV_BIT 2 /* In ULPD_CLKC_CTRL */
+ #define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */
+ #define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */
+ #define SWD_ULPD_PLL_CLK_REQ 1 /* In SWD_CLK_DIV_CTRL_SEL */
+@@ -741,6 +742,18 @@ static struct clk i2c_fck = {
+ .disable = &omap1_clk_disable_generic,
+ };
+
++static struct clk i2c_ick = {
++ .name = "i2c_ick",
++ .id = 1,
++ .flags = CLOCK_IN_OMAP16XX |
++ VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
++ ALWAYS_ENABLED,
++ .parent = &armper_ck.clk,
++ .recalc = &followparent_recalc,
++ .enable = &omap1_clk_enable_generic,
++ .disable = &omap1_clk_disable_generic,
++};
++
+ static struct clk * onchip_clks[] = {
+ /* non-ULPD clocks */
+ &ck_ref,
+@@ -790,6 +803,7 @@ static struct clk * onchip_clks[] = {
+ /* Virtual clocks */
+ &virtual_ck_mpu,
+ &i2c_fck,
++ &i2c_ick,
+ };
+
+ #endif
+diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
+index efe9bfc..8e40208 100644
+--- a/arch/arm/mach-omap1/fpga.c
++++ b/arch/arm/mach-omap1/fpga.c
+@@ -84,8 +84,7 @@ static void fpga_mask_ack_irq(unsigned i
+ fpga_ack_irq(irq);
+ }
+
+-void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc)
+ {
+ struct irqdesc *d;
+ u32 stat;
+@@ -101,7 +100,7 @@ void innovator_fpga_IRQ_demux(unsigned i
+ fpga_irq++, stat >>= 1) {
+ if (stat & 1) {
+ d = irq_desc + fpga_irq;
+- desc_handle_irq(fpga_irq, d, regs);
++ desc_handle_irq(fpga_irq, d);
+ }
+ }
+ }
+diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
+index fa74ef7..5432335 100644
+--- a/arch/arm/mach-omap1/mux.c
++++ b/arch/arm/mach-omap1/mux.c
+@@ -199,6 +199,17 @@ MUX_CFG("N14_1610_UWIRE_CS0", 8, 9,
+ MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1)
+ MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1)
+
++/* OMAP-1610 SPI */
++MUX_CFG("U19_1610_SPIF_SCK", 7, 21, 6, 1, 15, 0, 1, 1, 1)
++MUX_CFG("U18_1610_SPIF_DIN", 8, 0, 6, 1, 18, 1, 1, 0, 1)
++MUX_CFG("P20_1610_SPIF_DIN", 6, 27, 4, 1, 7, 1, 1, 0, 1)
++MUX_CFG("W21_1610_SPIF_DOUT", 8, 3, 6, 1, 19, 0, 1, 0, 1)
++MUX_CFG("R18_1610_SPIF_DOUT", 7, 9, 3, 1, 11, 0, 1, 0, 1)
++MUX_CFG("N14_1610_SPIF_CS0", 8, 9, 6, 1, 21, 0, 1, 1, 1)
++MUX_CFG("N15_1610_SPIF_CS1", 7, 18, 6, 1, 14, 0, 1, 1, 1)
++MUX_CFG("T19_1610_SPIF_CS2", 7, 15, 4, 1, 13, 0, 1, 1, 1)
++MUX_CFG("P15_1610_SPIF_CS3", 8, 12, 3, 1, 22, 0, 1, 1, 1)
++
+ /* OMAP-1610 Flash */
+ MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1)
+ MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1)
+diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
+index cd76185..4834758 100644
+--- a/arch/arm/mach-omap1/pm.c
++++ b/arch/arm/mach-omap1/pm.c
+@@ -682,8 +682,7 @@ static int omap_pm_finish(suspend_state_
+ }
+
+
+-static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
+- struct pt_regs * regs)
++static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
+ {
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
+index 976edfb..4cc98a5 100644
+--- a/arch/arm/mach-omap1/serial.c
++++ b/arch/arm/mach-omap1/serial.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap1/id.c
++ * linux/arch/arm/mach-omap1/serial.c
+ *
+ * OMAP1 CPU identification code
+ *
+@@ -204,8 +204,7 @@ void __init omap_serial_init(void)
+
+ #ifdef CONFIG_OMAP_SERIAL_WAKE
+
+-static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id)
+ {
+ /* Need to do something with serial port right after wake-up? */
+ return IRQ_HANDLED;
+diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
+index 4d91b9f..1b7e4a5 100644
+--- a/arch/arm/mach-omap1/time.c
++++ b/arch/arm/mach-omap1/time.c
+@@ -160,8 +160,7 @@ static unsigned long omap_mpu_timer_gett
+ * Latency during the interrupt is calculated using timer1.
+ * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ */
+-static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id)
+ {
+ unsigned long now, latency;
+
+@@ -169,7 +168,7 @@ static irqreturn_t omap_mpu_timer_interr
+ now = 0 - omap_mpu_timer_read(0);
+ latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
+ omap_mpu_timer_last = now - latency;
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+@@ -182,8 +181,7 @@ static struct irqaction omap_mpu_timer_i
+ };
+
+ static unsigned long omap_mpu_timer1_overflows;
+-static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+ {
+ omap_mpu_timer1_overflows++;
+ return IRQ_HANDLED;
+diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
+index 7993b7b..03d6905 100644
+--- a/arch/arm/mach-omap2/board-apollon.c
++++ b/arch/arm/mach-omap2/board-apollon.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap/omap2/board-apollon.c
++ * linux/arch/arm/mach-omap2/board-apollon.c
+ *
+ * Copyright (C) 2005,2006 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park at samsung.com>
+@@ -166,8 +166,8 @@ static struct omap_uart_config apollon_u
+
+ static struct omap_mmc_config apollon_mmc_config __initdata = {
+ .mmc [0] = {
+- .enabled = 0,
+- .wire4 = 0,
++ .enabled = 1,
++ .wire4 = 1,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+@@ -203,7 +203,7 @@ static void __init apollon_led_init(void
+ omap_set_gpio_dataout(LED2_GPIO15, 0);
+ }
+
+-static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs)
++static irqreturn_t apollon_sw_interrupt(int irq, void *ignored)
+ {
+ static unsigned int led0, led1, led2;
+
+@@ -257,6 +257,9 @@ static void __init omap_apollon_init(voi
+ /* REVISIT: where's the correct place */
+ omap_cfg_reg(W19_24XX_SYS_NIRQ);
+
++ /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */
++ CONTROL_DEVCONF |= (1 << 24);
++
+ /*
+ * Make sure the serial ports are muxed on at this point.
+ * You have to mux them off in device drivers later on
+diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
+index eaecbf4..9093815 100644
+--- a/arch/arm/mach-omap2/board-generic.c
++++ b/arch/arm/mach-omap2/board-generic.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap/omap2/board-generic.c
++ * linux/arch/arm/mach-omap2/board-generic.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt at nokia.com>
+diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
+index 4933fce..26a95a6 100644
+--- a/arch/arm/mach-omap2/board-h4.c
++++ b/arch/arm/mach-omap2/board-h4.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap/omap2/board-h4.c
++ * linux/arch/arm/mach-omap2/board-h4.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt at nokia.com>
+@@ -245,6 +245,7 @@ static struct omap_kp_platform_data h4_k
+ .rows = 6,
+ .cols = 7,
+ .keymap = h4_keymap,
++ .keymapsize = ARRAY_SIZE(h4_keymap),
+ .rep = 1,
+ .row_gpios = row_gpios,
+ .col_gpios = col_gpios,
+diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
+index d1b648a..0de201c 100644
+--- a/arch/arm/mach-omap2/clock.c
++++ b/arch/arm/mach-omap2/clock.c
+@@ -32,10 +32,14 @@
+ #include "memory.h"
+ #include "clock.h"
+
++#undef DEBUG
++
+ //#define DOWN_VARIABLE_DPLL 1 /* Experimental */
+
+ static struct prcm_config *curr_prcm_set;
+ static u32 curr_perf_level = PRCM_FULL_SPEED;
++static struct clk *vclk;
++static struct clk *sclk;
+
+ /*-------------------------------------------------------------------------
+ * Omap2 specific clock functions
+@@ -79,6 +83,14 @@ static void omap2_propagate_rate(struct
+ propagate_rate(clk);
+ }
+
++static void omap2_set_osc_ck(int enable)
++{
++ if (enable)
++ PRCM_CLKSRC_CTRL &= ~(0x3 << 3);
++ else
++ PRCM_CLKSRC_CTRL |= 0x3 << 3;
++}
++
+ /* Enable an APLL if off */
+ static void omap2_clk_fixed_enable(struct clk *clk)
+ {
+@@ -101,12 +113,54 @@ static void omap2_clk_fixed_enable(struc
+ else if (clk == &apll54_ck)
+ cval = (1 << 6);
+
+- while (!CM_IDLEST_CKGEN & cval) { /* Wait for lock */
++ while (!(CM_IDLEST_CKGEN & cval)) { /* Wait for lock */
+ ++i;
+ udelay(1);
+- if (i == 100000)
++ if (i == 100000) {
++ printk(KERN_ERR "Clock %s didn't lock\n", clk->name);
++ break;
++ }
++ }
++}
++
++static void omap2_clk_wait_ready(struct clk *clk)
++{
++ unsigned long reg, other_reg, st_reg;
++ u32 bit;
++ int i;
++
++ reg = (unsigned long) clk->enable_reg;
++ if (reg == (unsigned long) &CM_FCLKEN1_CORE ||
++ reg == (unsigned long) &CM_FCLKEN2_CORE)
++ other_reg = (reg & ~0xf0) | 0x10;
++ else if (reg == (unsigned long) &CM_ICLKEN1_CORE ||
++ reg == (unsigned long) &CM_ICLKEN2_CORE)
++ other_reg = (reg & ~0xf0) | 0x00;
++ else
++ return;
++
++ /* No check for DSS or cam clocks */
++ if ((reg & 0x0f) == 0) {
++ if (clk->enable_bit <= 1 || clk->enable_bit == 31)
++ return;
++ }
++
++ /* Check if both functional and interface clocks
++ * are running. */
++ bit = 1 << clk->enable_bit;
++ if (!(__raw_readl(other_reg) & bit))
++ return;
++ st_reg = (other_reg & ~0xf0) | 0x20;
++ i = 0;
++ while (!(__raw_readl(st_reg) & bit)) {
++ i++;
++ if (i == 100000) {
++ printk(KERN_ERR "Timeout enabling clock %s\n", clk->name);
+ break;
++ }
+ }
++ if (i)
++ pr_debug("Clock %s stable after %d loops\n", clk->name, i);
+ }
+
+ /* Enables clock without considering parent dependencies or use count
+@@ -119,6 +173,11 @@ static int _omap2_clk_enable(struct clk
+ if (clk->flags & ALWAYS_ENABLED)
+ return 0;
+
++ if (unlikely(clk == &osc_ck)) {
++ omap2_set_osc_ck(1);
++ return 0;
++ }
++
+ if (unlikely(clk->enable_reg == 0)) {
+ printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+ clk->name);
+@@ -133,6 +192,9 @@ static int _omap2_clk_enable(struct clk
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
++ wmb();
++
++ omap2_clk_wait_ready(clk);
+
+ return 0;
+ }
+@@ -155,6 +217,11 @@ static void _omap2_clk_disable(struct cl
+ {
+ u32 regval32;
+
++ if (unlikely(clk == &osc_ck)) {
++ omap2_set_osc_ck(0);
++ return;
++ }
++
+ if (clk->enable_reg == 0)
+ return;
+
+@@ -166,6 +233,7 @@ static void _omap2_clk_disable(struct cl
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
++ wmb();
+ }
+
+ static int omap2_clk_enable(struct clk *clk)
+@@ -695,12 +763,14 @@ static int omap2_clk_set_rate(struct clk
+ reg_val = __raw_readl(reg);
+ reg_val &= ~(field_mask << div_off);
+ reg_val |= (field_val << div_off);
+-
+ __raw_writel(reg_val, reg);
++ wmb();
+ clk->rate = clk->parent->rate / field_val;
+
+- if (clk->flags & DELAYED_APP)
++ if (clk->flags & DELAYED_APP) {
+ __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
++ wmb();
++ }
+ ret = 0;
+ } else if (clk->set_rate != 0)
+ ret = clk->set_rate(clk, rate);
+@@ -836,10 +906,12 @@ static int omap2_clk_set_parent(struct c
+ reg_val = __raw_readl(reg) & ~(field_mask << src_off);
+ reg_val |= (field_val << src_off);
+ __raw_writel(reg_val, reg);
++ wmb();
+
+- if (clk->flags & DELAYED_APP)
++ if (clk->flags & DELAYED_APP) {
+ __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
+-
++ wmb();
++ }
+ if (clk->usecount > 0)
+ _omap2_clk_enable(clk);
+
+@@ -953,12 +1025,29 @@ static int omap2_select_table_rate(struc
+ * Omap2 clock reset and init functions
+ *-------------------------------------------------------------------------*/
+
++#ifdef CONFIG_OMAP_RESET_CLOCKS
++static void __init omap2_clk_disable_unused(struct clk *clk)
++{
++ u32 regval32;
++
++ regval32 = __raw_readl(clk->enable_reg);
++ if ((regval32 & (1 << clk->enable_bit)) == 0)
++ return;
++
++ printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
++ _omap2_clk_disable(clk);
++}
++#else
++#define omap2_clk_disable_unused NULL
++#endif
++
+ static struct clk_functions omap2_clk_functions = {
+ .clk_enable = omap2_clk_enable,
+ .clk_disable = omap2_clk_disable,
+ .clk_round_rate = omap2_clk_round_rate,
+ .clk_set_rate = omap2_clk_set_rate,
+ .clk_set_parent = omap2_clk_set_parent,
++ .clk_disable_unused = omap2_clk_disable_unused,
+ };
+
+ static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
+@@ -984,27 +1073,19 @@ static void __init omap2_get_crystal_rat
+ sys->rate = sclk;
+ }
+
+-#ifdef CONFIG_OMAP_RESET_CLOCKS
+-static void __init omap2_disable_unused_clocks(void)
++/*
++ * Set clocks for bypass mode for reboot to work.
++ */
++void omap2_clk_prepare_for_reboot(void)
+ {
+- struct clk *ck;
+- u32 regval32;
++ u32 rate;
+
+- list_for_each_entry(ck, &clocks, node) {
+- if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
+- ck->enable_reg == 0)
+- continue;
+-
+- regval32 = __raw_readl(ck->enable_reg);
+- if ((regval32 & (1 << ck->enable_bit)) == 0)
+- continue;
++ if (vclk == NULL || sclk == NULL)
++ return;
+
+- printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name);
+- _omap2_clk_disable(ck);
+- }
++ rate = clk_get_rate(sclk);
++ clk_set_rate(vclk, rate);
+ }
+-late_initcall(omap2_disable_unused_clocks);
+-#endif
+
+ /*
+ * Switch the MPU rate if specified on cmdline.
+@@ -1077,8 +1158,27 @@ int __init omap2_clk_init(void)
+ */
+ clk_enable(&sync_32k_ick);
+ clk_enable(&omapctrl_ick);
++
++ /* Force the APLLs active during bootup to avoid disabling and
++ * enabling them unnecessarily. */
++ clk_enable(&apll96_ck);
++ clk_enable(&apll54_ck);
++
+ if (cpu_is_omap2430())
+ clk_enable(&sdrc_ick);
+
++ /* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
++ vclk = clk_get(NULL, "virt_prcm_set");
++ sclk = clk_get(NULL, "sys_ck");
++
++ return 0;
++}
++
++static int __init omap2_disable_aplls(void)
++{
++ clk_disable(&apll96_ck);
++ clk_disable(&apll54_ck);
++
+ return 0;
+ }
++late_initcall(omap2_disable_aplls);
+diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
+index 2781dfb..8816f5a 100644
+--- a/arch/arm/mach-omap2/clock.h
++++ b/arch/arm/mach-omap2/clock.h
+@@ -560,7 +560,7 @@ static struct clk osc_ck = { /* (*12, *
+ .name = "osc_ck",
+ .rate = 26000000, /* fixed up in clock init */
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+- RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
++ RATE_FIXED | RATE_PROPAGATES,
+ };
+
+ /* With out modem likely 12MHz, with modem likely 13MHz */
+@@ -1368,7 +1368,8 @@ static struct clk mcbsp5_fck = {
+ };
+
+ static struct clk mcspi1_ick = {
+- .name = "mcspi1_ick",
++ .name = "mcspi_ick",
++ .id = 1,
+ .parent = &l4_ck,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
+@@ -1377,7 +1378,8 @@ static struct clk mcspi1_ick = {
+ };
+
+ static struct clk mcspi1_fck = {
+- .name = "mcspi1_fck",
++ .name = "mcspi_fck",
++ .id = 1,
+ .parent = &func_48m_ck,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
+@@ -1386,7 +1388,8 @@ static struct clk mcspi1_fck = {
+ };
+
+ static struct clk mcspi2_ick = {
+- .name = "mcspi2_ick",
++ .name = "mcspi_ick",
++ .id = 2,
+ .parent = &l4_ck,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
+@@ -1395,7 +1398,8 @@ static struct clk mcspi2_ick = {
+ };
+
+ static struct clk mcspi2_fck = {
+- .name = "mcspi2_fck",
++ .name = "mcspi_fck",
++ .id = 2,
+ .parent = &func_48m_ck,
+ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
+@@ -1404,7 +1408,8 @@ static struct clk mcspi2_fck = {
+ };
+
+ static struct clk mcspi3_ick = {
+- .name = "mcspi3_ick",
++ .name = "mcspi_ick",
++ .id = 3,
+ .parent = &l4_ck,
+ .flags = CLOCK_IN_OMAP243X,
+ .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE,
+@@ -1413,7 +1418,8 @@ static struct clk mcspi3_ick = {
+ };
+
+ static struct clk mcspi3_fck = {
+- .name = "mcspi3_fck",
++ .name = "mcspi_fck",
++ .id = 3,
+ .parent = &func_48m_ck,
+ .flags = CLOCK_IN_OMAP243X,
+ .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE,
+diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
+index c7a48f9..f4f04d8 100644
+--- a/arch/arm/mach-omap2/gpmc.c
++++ b/arch/arm/mach-omap2/gpmc.c
+@@ -13,6 +13,8 @@
+ #include <linux/init.h>
+ #include <linux/err.h>
+ #include <linux/clk.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
+
+ #include <asm/io.h>
+ #include <asm/arch/gpmc.h>
+@@ -41,6 +43,19 @@
+ #define GPMC_CS0 0x60
+ #define GPMC_CS_SIZE 0x30
+
++#define GPMC_CS_NUM 8
++#define GPMC_MEM_START 0x00000000
++#define GPMC_MEM_END 0x3FFFFFFF
++#define BOOT_ROM_SPACE 0x100000 /* 1MB */
++
++#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
++#define GPMC_SECTION_SHIFT 28 /* 128 MB */
++
++static struct resource gpmc_mem_root;
++static struct resource gpmc_cs_mem[GPMC_CS_NUM];
++static spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED;
++static unsigned gpmc_cs_map;
++
+ static void __iomem *gpmc_base =
+ (void __iomem *) IO_ADDRESS(GPMC_BASE);
+ static void __iomem *gpmc_cs_base =
+@@ -187,9 +202,168 @@ int gpmc_cs_set_timings(int cs, const st
+ return 0;
+ }
+
+-unsigned long gpmc_cs_get_base_addr(int cs)
++static void gpmc_cs_enable_mem(int cs, u32 base, u32 size)
++{
++ u32 l;
++ u32 mask;
++
++ mask = (1 << GPMC_SECTION_SHIFT) - size;
++ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
++ l &= ~0x3f;
++ l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
++ l &= ~(0x0f << 8);
++ l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
++ l |= 1 << 6; /* CSVALID */
++ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
++}
++
++static void gpmc_cs_disable_mem(int cs)
++{
++ u32 l;
++
++ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
++ l &= ~(1 << 6); /* CSVALID */
++ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
++}
++
++static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
++{
++ u32 l;
++ u32 mask;
++
++ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
++ *base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
++ mask = (l >> 8) & 0x0f;
++ *size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
++}
++
++static int gpmc_cs_mem_enabled(int cs)
++{
++ u32 l;
++
++ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
++ return l & (1 << 6);
++}
++
++static void gpmc_cs_set_reserved(int cs, int reserved)
+ {
+- return (gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7) & 0x1f) << 24;
++ gpmc_cs_map &= ~(1 << cs);
++ gpmc_cs_map |= (reserved ? 1 : 0) << cs;
++}
++
++static int gpmc_cs_reserved(int cs)
++{
++ return gpmc_cs_map & (1 << cs);
++}
++
++static unsigned long gpmc_mem_align(unsigned long size)
++{
++ int order;
++
++ size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
++ order = GPMC_CHUNK_SHIFT - 1;
++ do {
++ size >>= 1;
++ order++;
++ } while (size);
++ size = 1 << order;
++ return size;
++}
++
++static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
++{
++ struct resource *res = &gpmc_cs_mem[cs];
++ int r;
++
++ size = gpmc_mem_align(size);
++ spin_lock(&gpmc_mem_lock);
++ res->start = base;
++ res->end = base + size - 1;
++ r = request_resource(&gpmc_mem_root, res);
++ spin_unlock(&gpmc_mem_lock);
++
++ return r;
++}
++
++int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
++{
++ struct resource *res = &gpmc_cs_mem[cs];
++ int r = -1;
++
++ if (cs > GPMC_CS_NUM)
++ return -ENODEV;
++
++ size = gpmc_mem_align(size);
++ if (size > (1 << GPMC_SECTION_SHIFT))
++ return -ENOMEM;
++
++ spin_lock(&gpmc_mem_lock);
++ if (gpmc_cs_reserved(cs)) {
++ r = -EBUSY;
++ goto out;
++ }
++ if (gpmc_cs_mem_enabled(cs))
++ r = adjust_resource(res, res->start & ~(size - 1), size);
++ if (r < 0)
++ r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
++ size, NULL, NULL);
++ if (r < 0)
++ goto out;
++
++ gpmc_cs_enable_mem(cs, res->start, res->end - res->start + 1);
++ *base = res->start;
++ gpmc_cs_set_reserved(cs, 1);
++out:
++ spin_unlock(&gpmc_mem_lock);
++ return r;
++}
++
++void gpmc_cs_free(int cs)
++{
++ spin_lock(&gpmc_mem_lock);
++ if (cs >= GPMC_CS_NUM || !gpmc_cs_reserved(cs)) {
++ printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
++ BUG();
++ spin_unlock(&gpmc_mem_lock);
++ return;
++ }
++ gpmc_cs_disable_mem(cs);
++ release_resource(&gpmc_cs_mem[cs]);
++ gpmc_cs_set_reserved(cs, 0);
++ spin_unlock(&gpmc_mem_lock);
++}
++
++void __init gpmc_mem_init(void)
++{
++ int cs;
++ unsigned long boot_rom_space = 0;
++
++ if (cpu_is_omap242x()) {
++ u32 l;
++ l = omap_readl(OMAP242X_CONTROL_STATUS);
++ /* In case of internal boot the 1st MB is redirected to the
++ * boot ROM memory space.
++ */
++ if (l & (1 << 3))
++ boot_rom_space = BOOT_ROM_SPACE;
++ } else
++ /* We assume internal boot if the mode can't be
++ * determined.
++ */
++ boot_rom_space = BOOT_ROM_SPACE;
++ gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
++ gpmc_mem_root.end = GPMC_MEM_END;
++
++ /* Reserve all regions that has been set up by bootloader */
++ for (cs = 0; cs < GPMC_CS_NUM; cs++) {
++ u32 base, size;
++
++ if (!gpmc_cs_mem_enabled(cs))
++ continue;
++ gpmc_cs_get_memconf(cs, &base, &size);
++ if (gpmc_cs_insert_mem(cs, base, size) < 0)
++ BUG();
++ }
+ }
+
+ void __init gpmc_init(void)
+@@ -206,4 +380,6 @@ void __init gpmc_init(void)
+ l &= 0x03 << 3;
+ l |= (0x02 << 3) | (1 << 0);
+ gpmc_write_reg(GPMC_SYSCONFIG, l);
++
++ gpmc_mem_init();
+ }
+diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
+index dfc3b35..1187009 100644
+--- a/arch/arm/mach-omap2/irq.c
++++ b/arch/arm/mach-omap2/irq.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap/omap2/irq.c
++ * linux/arch/arm/mach-omap2/irq.c
+ *
+ * Interrupt handler for OMAP2 boards.
+ *
+@@ -41,18 +41,6 @@ static struct omap_irq_bank {
+ .nr_irqs = 96,
+ }, {
+ /* XXX: DSP INTC */
+-
+-#if 0
+- /*
+- * Commented out for now until we fix the IVA clocking
+- */
+-#ifdef CONFIG_ARCH_OMAP2420
+- }, {
+- /* IVA INTC (2420 only) */
+- .base_reg = OMAP24XX_IVA_INTC_BASE,
+- .nr_irqs = 16, /* Actually 32, but only 16 are used */
+-#endif
+-#endif
+ }
+ };
+
+diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
+index 60ef084..f538d0f 100644
+--- a/arch/arm/mach-omap2/mux.c
++++ b/arch/arm/mach-omap2/mux.c
+@@ -104,6 +104,20 @@ MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108,
+ MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1)
+ MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1)
+
++/* MMC/SDIO */
++MUX_CFG_24XX("G19_24XX_MMC_CLKO", 0x0f3, 0, 0, 0, 1)
++MUX_CFG_24XX("H18_24XX_MMC_CMD", 0x0f4, 0, 0, 0, 1)
++MUX_CFG_24XX("F20_24XX_MMC_DAT0", 0x0f5, 0, 0, 0, 1)
++MUX_CFG_24XX("H14_24XX_MMC_DAT1", 0x0f6, 0, 0, 0, 1)
++MUX_CFG_24XX("E19_24XX_MMC_DAT2", 0x0f7, 0, 0, 0, 1)
++MUX_CFG_24XX("D19_24XX_MMC_DAT3", 0x0f8, 0, 0, 0, 1)
++MUX_CFG_24XX("F19_24XX_MMC_DAT_DIR0", 0x0f9, 0, 0, 0, 1)
++MUX_CFG_24XX("E20_24XX_MMC_DAT_DIR1", 0x0fa, 0, 0, 0, 1)
++MUX_CFG_24XX("F18_24XX_MMC_DAT_DIR2", 0x0fb, 0, 0, 0, 1)
++MUX_CFG_24XX("E18_24XX_MMC_DAT_DIR3", 0x0fc, 0, 0, 0, 1)
++MUX_CFG_24XX("G18_24XX_MMC_CMD_DIR", 0x0fd, 0, 0, 0, 1)
++MUX_CFG_24XX("H15_24XX_MMC_CLKI", 0x0fe, 0, 0, 0, 1)
++
+ /* Keypad GPIO*/
+ MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1)
+ MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1)
+diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c
+index 5e20e74..2494091 100644
+--- a/arch/arm/mach-omap2/pm-domain.c
++++ b/arch/arm/mach-omap2/pm-domain.c
+@@ -15,7 +15,6 @@
+ * published by the Free Software Foundation.
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/clk.h>
+diff --git a/arch/arm/mach-omap2/prcm-regs.h b/arch/arm/mach-omap2/prcm-regs.h
+index 22ac7be..5e1c4b5 100644
+--- a/arch/arm/mach-omap2/prcm-regs.h
++++ b/arch/arm/mach-omap2/prcm-regs.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap2/prcm-reg.h
++ * linux/arch/arm/mach-omap2/prcm-regs.h
+ *
+ * OMAP24XX Power Reset and Clock Management (PRCM) registers
+ *
+diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
+index c2bf57e..90f5305 100644
+--- a/arch/arm/mach-omap2/prcm.c
++++ b/arch/arm/mach-omap2/prcm.c
+@@ -19,6 +19,8 @@
+
+ #include "prcm-regs.h"
+
++extern void omap2_clk_prepare_for_reboot(void);
++
+ u32 omap_prcm_get_reset_sources(void)
+ {
+ return RM_RSTST_WKUP & 0x7f;
+@@ -28,12 +30,6 @@ EXPORT_SYMBOL(omap_prcm_get_reset_source
+ /* Resets clock rates and reboots the system. Only called from system.h */
+ void omap_prcm_arch_reset(char mode)
+ {
+- u32 rate;
+- struct clk *vclk, *sclk;
+-
+- vclk = clk_get(NULL, "virt_prcm_set");
+- sclk = clk_get(NULL, "sys_ck");
+- rate = clk_get_rate(sclk);
+- clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */
++ omap2_clk_prepare_for_reboot();
+ RM_RSTCTRL_WKUP |= 2;
+ }
+diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
+index 0884bc7..aaa5589 100644
+--- a/arch/arm/mach-omap2/serial.c
++++ b/arch/arm/mach-omap2/serial.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/arm/mach-omap/omap2/serial.c
++ * arch/arm/mach-omap2/serial.c
+ *
+ * OMAP2 serial support.
+ *
+diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S
+index a5ef7f6..b275766 100644
+--- a/arch/arm/mach-omap2/sram-fn.S
++++ b/arch/arm/mach-omap2/sram-fn.S
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-omap2/sram.S
++ * linux/arch/arm/mach-omap2/sram-fn.S
+ *
+ * Omap2 specific functions that need to be run in internal SRAM
+ *
+diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
+index fe5fd6d..973189c 100644
+--- a/arch/arm/mach-omap2/timer-gp.c
++++ b/arch/arm/mach-omap2/timer-gp.c
+@@ -37,13 +37,12 @@ static inline void omap2_gp_timer_start(
+ omap_dm_timer_start(gptimer);
+ }
+
+-static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+ omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
+- timer_tick(regs);
++ timer_tick();
+
+ write_sequnlock(&xtime_lock);
+
+diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c
+index f582ed2..daa8d3d 100644
+--- a/arch/arm/mach-pnx4008/clock.c
++++ b/arch/arm/mach-pnx4008/clock.c
+@@ -735,6 +735,16 @@ static struct clk uart6_ck = {
+ .enable_reg = UARTCLKCTRL_REG,
+ };
+
++static struct clk wdt_ck = {
++ .name = "wdt_ck",
++ .parent = &per_ck,
++ .flags = NEEDS_INITIALIZATION,
++ .round_rate = &on_off_round_rate,
++ .set_rate = &on_off_set_rate,
++ .enable_shift = 0,
++ .enable_reg = TIMCLKCTRL_REG,
++};
++
+ /* These clocks are visible outside this module
+ * and can be initialized
+ */
+@@ -765,6 +775,7 @@ static struct clk *onchip_clks[] = {
+ &uart4_ck,
+ &uart5_ck,
+ &uart6_ck,
++ &wdt_ck,
+ };
+
+ static int local_clk_enable(struct clk *clk)
+diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c
+index ec01574..d6a279e 100644
+--- a/arch/arm/mach-pnx4008/dma.c
++++ b/arch/arm/mach-pnx4008/dma.c
+@@ -32,7 +32,7 @@
+
+ static struct dma_channel {
+ char *name;
+- void (*irq_handler) (int, int, void *, struct pt_regs *);
++ void (*irq_handler) (int, int, void *);
+ void *data;
+ struct pnx4008_dma_ll *ll;
+ u32 ll_dma;
+@@ -150,8 +150,7 @@ static inline void pnx4008_dma_unlock(vo
+ #define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
+
+ int pnx4008_request_channel(char *name, int ch,
+- void (*irq_handler) (int, int, void *,
+- struct pt_regs *), void *data)
++ void (*irq_handler) (int, int, void *), void *data)
+ {
+ int i, found = 0;
+
+@@ -1033,7 +1032,7 @@ int pnx4008_dma_ch_enabled(int ch)
+
+ EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
+
+-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+ {
+ int i;
+ unsigned long dint = __raw_readl(DMAC_INT_STAT);
+@@ -1053,8 +1052,7 @@ static irqreturn_t dma_irq_handler(int i
+ cause |= DMA_ERR_INT;
+ if (tcint & i_bit)
+ cause |= DMA_TC_INT;
+- channel->irq_handler(i, cause, channel->data,
+- regs);
++ channel->irq_handler(i, cause, channel->data);
+ } else {
+ /*
+ * IRQ for an unregistered DMA channel
+diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c
+index e1ce050..1ab84ce 100644
+--- a/arch/arm/mach-pnx4008/gpio.c
++++ b/arch/arm/mach-pnx4008/gpio.c
+@@ -14,7 +14,6 @@
+ * or implied.
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+diff --git a/arch/arm/mach-pnx4008/sleep.S b/arch/arm/mach-pnx4008/sleep.S
+index 93c802b..fea1e17 100644
+--- a/arch/arm/mach-pnx4008/sleep.S
++++ b/arch/arm/mach-pnx4008/sleep.S
+@@ -11,7 +11,6 @@
+ * or implied.
+ */
+
+-#include <linux/config.h>
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+ #include <asm/hardware.h>
+diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
+index 756228d..8621c20 100644
+--- a/arch/arm/mach-pnx4008/time.c
++++ b/arch/arm/mach-pnx4008/time.c
+@@ -11,7 +11,6 @@
+ * or implied.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -48,15 +47,14 @@ static unsigned long pnx4008_gettimeoffs
+ /*!
+ * IRQ handler for the timer
+ */
+-static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id)
+ {
+ if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
+
+ write_seqlock(&xtime_lock);
+
+ do {
+- timer_tick(regs);
++ timer_tick();
+
+ /*
+ * this algorithm takes care of possible delay
+diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
+index cce2657..a1a900d 100644
+--- a/arch/arm/mach-pxa/corgi.c
++++ b/arch/arm/mach-pxa/corgi.c
+@@ -212,7 +212,7 @@ static struct platform_device corgits_de
+ */
+ static struct pxamci_platform_data corgi_mci_platform_data;
+
+-static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *, struct pt_regs *), void *data)
++static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, void *data)
+ {
+ int err;
+
+@@ -284,21 +284,9 @@ static struct pxaficp_platform_data corg
+ /*
+ * USB Device Controller
+ */
+-static void corgi_udc_command(int cmd)
+-{
+- switch(cmd) {
+- case PXA2XX_UDC_CMD_CONNECT:
+- GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
+- break;
+- case PXA2XX_UDC_CMD_DISCONNECT:
+- GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
+- break;
+- }
+-}
+-
+ static struct pxa2xx_udc_mach_info udc_info __initdata = {
+ /* no connect GPIO; corgi can't tell connection status */
+- .udc_command = corgi_udc_command,
++ .gpio_pullup = CORGI_GPIO_USB_PULLUP,
+ };
+
+
+@@ -350,7 +338,6 @@ static void __init corgi_init(void)
+ corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
+
+ pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
+- pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
+
+ pxa_set_udc_info(&udc_info);
+diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
+index 6dbcaf1..a72476c 100644
+--- a/arch/arm/mach-pxa/corgi_lcd.c
++++ b/arch/arm/mach-pxa/corgi_lcd.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/video/w100fb.c
++ * linux/arch/arm/mach-pxa/corgi_lcd.c
+ *
+ * Corgi/Spitz LCD Specific Code
+ *
+@@ -431,10 +431,10 @@ struct platform_device corgifb_device =
+
+ #include <asm/arch/pxafb.h>
+
+-void spitz_lcd_power(int on)
++void spitz_lcd_power(int on, struct fb_var_screeninfo *var)
+ {
+ if (on)
+- lcdtg_hw_init(480);
++ lcdtg_hw_init(var->xres);
+ else
+ lcdtg_suspend();
+ }
+diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c
+index 7d8c854..4440bab 100644
+--- a/arch/arm/mach-pxa/dma.c
++++ b/arch/arm/mach-pxa/dma.c
+@@ -27,13 +27,13 @@
+
+ static struct dma_channel {
+ char *name;
+- void (*irq_handler)(int, void *, struct pt_regs *);
++ void (*irq_handler)(int, void *);
+ void *data;
+ } dma_channels[PXA_DMA_CHANNELS];
+
+
+ int pxa_request_dma (char *name, pxa_dma_prio prio,
+- void (*irq_handler)(int, void *, struct pt_regs *),
++ void (*irq_handler)(int, void *),
+ void *data)
+ {
+ unsigned long flags;
+@@ -87,7 +87,7 @@ void pxa_free_dma (int dma_ch)
+ local_irq_restore(flags);
+ }
+
+-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+ {
+ int i, dint = DINT;
+
+@@ -95,7 +95,7 @@ static irqreturn_t dma_irq_handler(int i
+ if (dint & (1 << i)) {
+ struct dma_channel *channel = &dma_channels[i];
+ if (channel->name && channel->irq_handler) {
+- channel->irq_handler(i, channel->data, regs);
++ channel->irq_handler(i, channel->data);
+ } else {
+ /*
+ * IRQ for an unregistered DMA channel:
+diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
+index 5efa847..45fb2c3 100644
+--- a/arch/arm/mach-pxa/generic.c
++++ b/arch/arm/mach-pxa/generic.c
+@@ -204,13 +204,6 @@ static struct platform_device udc_device
+ }
+ };
+
+-static struct pxafb_mach_info pxa_fb_info;
+-
+-void __init set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info)
+-{
+- memcpy(&pxa_fb_info,hard_pxa_fb_info,sizeof(struct pxafb_mach_info));
+-}
+-
+ static struct resource pxafb_resources[] = {
+ [0] = {
+ .start = 0x44000000,
+@@ -230,7 +223,6 @@ static struct platform_device pxafb_devi
+ .name = "pxa2xx-fb",
+ .id = -1,
+ .dev = {
+- .platform_data = &pxa_fb_info,
+ .dma_mask = &fb_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+@@ -238,6 +230,11 @@ static struct platform_device pxafb_devi
+ .resource = pxafb_resources,
+ };
+
++void __init set_pxa_fb_info(struct pxafb_mach_info *info)
++{
++ pxafb_device.dev.platform_data = info;
++}
++
+ void __init set_pxa_fb_parent(struct device *parent_dev)
+ {
+ pxafb_device.dev.parent = parent_dev;
+diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
+index 6914d22..64df440 100644
+--- a/arch/arm/mach-pxa/idp.c
++++ b/arch/arm/mach-pxa/idp.c
+@@ -82,7 +82,7 @@ static void idp_vlcd(int on)
+ }
+ }
+
+-static void idp_lcd_power(int on)
++static void idp_lcd_power(int on, struct fb_var_screeninfo *var)
+ {
+ if (on) {
+ IDP_CPLD_LCD |= (1<<0);
+@@ -99,7 +99,7 @@ static void idp_lcd_power(int on)
+ idp_vlcd(on);
+ }
+
+-static struct pxafb_mach_info sharp_lm8v31 __initdata = {
++static struct pxafb_mode_info sharp_lm8v31_mode = {
+ .pixclock = 270000,
+ .xres = 640,
+ .yres = 480,
+@@ -112,6 +112,11 @@ static struct pxafb_mach_info sharp_lm8v
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .cmap_greyscale = 0,
++};
++
++static struct pxafb_mach_info sharp_lm8v31 = {
++ .modes = &sharp_lm8v31_mode,
++ .num_modes = 1,
+ .cmap_inverse = 0,
+ .cmap_static = 0,
+ .lccr0 = LCCR0_SDS,
+@@ -120,7 +125,7 @@ static struct pxafb_mach_info sharp_lm8v
+ .pxafb_lcd_power = &idp_lcd_power
+ };
+
+-static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data)
++static int idp_mci_init(struct device *dev, irq_handler_t idp_detect_int, void *data)
+ {
+ /* setup GPIO for PXA25x MMC controller */
+ pxa_gpio_mode(GPIO6_MMCCLK_MD);
+diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
+index 12141e2..ab1a160 100644
+--- a/arch/arm/mach-pxa/irq.c
++++ b/arch/arm/mach-pxa/irq.c
+@@ -143,8 +143,7 @@ static struct irq_chip pxa_low_gpio_chip
+ * Demux handler for GPIO>=2 edge detect interrupts
+ */
+
+-static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int mask;
+ int loop;
+@@ -160,7 +159,7 @@ static void pxa_gpio_demux_handler(unsig
+ mask >>= 2;
+ do {
+ if (mask & 1)
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ irq++;
+ desc++;
+ mask >>= 1;
+@@ -175,7 +174,7 @@ static void pxa_gpio_demux_handler(unsig
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ irq++;
+ desc++;
+ mask >>= 1;
+@@ -190,7 +189,7 @@ static void pxa_gpio_demux_handler(unsig
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ irq++;
+ desc++;
+ mask >>= 1;
+@@ -206,7 +205,7 @@ static void pxa_gpio_demux_handler(unsig
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ irq++;
+ desc++;
+ mask >>= 1;
+diff --git a/arch/arm/mach-pxa/leds-trizeps4.c b/arch/arm/mach-pxa/leds-trizeps4.c
+index 14cfc85..2271d20 100644
+--- a/arch/arm/mach-pxa/leds-trizeps4.c
++++ b/arch/arm/mach-pxa/leds-trizeps4.c
+@@ -10,7 +10,6 @@
+ * published by the Free Software Foundation.
+ */
+
+-#include <linux/config.h>
+ #include <linux/init.h>
+
+ #include <asm/hardware.h>
+diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h
+index 4f829b8..7f0dfe0 100644
+--- a/arch/arm/mach-pxa/leds.h
++++ b/arch/arm/mach-pxa/leds.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-arm/arch-pxa/leds.h
++ * arch/arm/mach-pxa/leds.h
+ *
+ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
+ *
+diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
+index 12479ae..5749f6b 100644
+--- a/arch/arm/mach-pxa/lpd270.c
++++ b/arch/arm/mach-pxa/lpd270.c
+@@ -75,8 +75,7 @@ static struct irq_chip lpd270_irq_chip =
+ .unmask = lpd270_unmask_irq,
+ };
+
+-static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned long pending;
+
+@@ -86,7 +85,7 @@ static void lpd270_irq_handler(unsigned
+ if (likely(pending)) {
+ irq = LPD270_IRQ(0) + __ffs(pending);
+ desc = irq_desc + irq;
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+
+ pending = __raw_readw(LPD270_INT_STATUS) &
+ lpd270_irq_enabled;
+@@ -248,7 +247,7 @@ static void lpd270_backlight_power(int o
+ }
+
+ /* 5.7" TFT QVGA (LoLo display number 1) */
+-static struct pxafb_mach_info sharp_lq057q3dc02 __initdata = {
++static struct pxafb_mode_info sharp_lq057q3dc02_mode = {
+ .pixclock = 150000,
+ .xres = 320,
+ .yres = 240,
+@@ -260,13 +259,18 @@ static struct pxafb_mach_info sharp_lq05
+ .upper_margin = 0x08,
+ .lower_margin = 0x14,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info sharp_lq057q3dc02 = {
++ .modes = &sharp_lq057q3dc02_mode,
++ .num_modes = 1,
+ .lccr0 = 0x07800080,
+ .lccr3 = 0x00400000,
+ .pxafb_backlight_power = lpd270_backlight_power,
+ };
+
+ /* 12.1" TFT SVGA (LoLo display number 2) */
+-static struct pxafb_mach_info sharp_lq121s1dg31 __initdata = {
++static struct pxafb_mode_info sharp_lq121s1dg31_mode = {
+ .pixclock = 50000,
+ .xres = 800,
+ .yres = 600,
+@@ -278,13 +282,18 @@ static struct pxafb_mach_info sharp_lq12
+ .upper_margin = 0x14,
+ .lower_margin = 0x0a,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info sharp_lq121s1dg31 = {
++ .modes = &sharp_lq121s1dg31_mode,
++ .num_modes = 1,
+ .lccr0 = 0x07800080,
+ .lccr3 = 0x00400000,
+ .pxafb_backlight_power = lpd270_backlight_power,
+ };
+
+ /* 3.6" TFT QVGA (LoLo display number 3) */
+-static struct pxafb_mach_info sharp_lq036q1da01 __initdata = {
++static struct pxafb_mode_info sharp_lq036q1da01_mode = {
+ .pixclock = 150000,
+ .xres = 320,
+ .yres = 240,
+@@ -296,13 +305,18 @@ static struct pxafb_mach_info sharp_lq03
+ .upper_margin = 0x03,
+ .lower_margin = 0x03,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info sharp_lq036q1da01 = {
++ .modes = &sharp_lq036q1da01_mode,
++ .num_modes = 1,
+ .lccr0 = 0x07800080,
+ .lccr3 = 0x00400000,
+ .pxafb_backlight_power = lpd270_backlight_power,
+ };
+
+ /* 6.4" TFT VGA (LoLo display number 5) */
+-static struct pxafb_mach_info sharp_lq64d343 __initdata = {
++static struct pxafb_mode_info sharp_lq64d343_mode = {
+ .pixclock = 25000,
+ .xres = 640,
+ .yres = 480,
+@@ -314,13 +328,18 @@ static struct pxafb_mach_info sharp_lq64
+ .upper_margin = 0x22,
+ .lower_margin = 0x00,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info sharp_lq64d343 = {
++ .modes = &sharp_lq64d343_mode,
++ .num_modes = 1,
+ .lccr0 = 0x07800080,
+ .lccr3 = 0x00400000,
+ .pxafb_backlight_power = lpd270_backlight_power,
+ };
+
+ /* 10.4" TFT VGA (LoLo display number 7) */
+-static struct pxafb_mach_info sharp_lq10d368 __initdata = {
++static struct pxafb_mode_info sharp_lq10d368_mode = {
+ .pixclock = 25000,
+ .xres = 640,
+ .yres = 480,
+@@ -332,13 +351,18 @@ static struct pxafb_mach_info sharp_lq10
+ .upper_margin = 0x22,
+ .lower_margin = 0x00,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info sharp_lq10d368 = {
++ .modes = &sharp_lq10d368_mode,
++ .num_modes = 1,
+ .lccr0 = 0x07800080,
+ .lccr3 = 0x00400000,
+ .pxafb_backlight_power = lpd270_backlight_power,
+ };
+
+ /* 3.5" TFT QVGA (LoLo display number 8) */
+-static struct pxafb_mach_info sharp_lq035q7db02_20 __initdata = {
++static struct pxafb_mode_info sharp_lq035q7db02_20_mode = {
+ .pixclock = 150000,
+ .xres = 240,
+ .yres = 320,
+@@ -350,6 +374,11 @@ static struct pxafb_mach_info sharp_lq03
+ .upper_margin = 0x05,
+ .lower_margin = 0x14,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info sharp_lq035q7db02_20 = {
++ .modes = &sharp_lq035q7db02_20_mode,
++ .num_modes = 1,
+ .lccr0 = 0x07800080,
+ .lccr3 = 0x00400000,
+ .pxafb_backlight_power = lpd270_backlight_power,
+diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
+index 83ff5ce..142c33c 100644
+--- a/arch/arm/mach-pxa/lubbock.c
++++ b/arch/arm/mach-pxa/lubbock.c
+@@ -85,8 +85,7 @@ static struct irq_chip lubbock_irq_chip
+ .unmask = lubbock_unmask_irq,
+ };
+
+-static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
+ do {
+@@ -94,7 +93,7 @@ static void lubbock_irq_handler(unsigned
+ if (likely(pending)) {
+ irq = LUBBOCK_IRQ(0) + __ffs(pending);
+ desc = irq_desc + irq;
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ }
+ pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
+ } while (pending);
+@@ -352,7 +351,7 @@ static struct platform_device *devices[]
+ &pxa_ssp,
+ };
+
+-static struct pxafb_mach_info sharp_lm8v31 __initdata = {
++static struct pxafb_mode_info sharp_lm8v31_mode = {
+ .pixclock = 270000,
+ .xres = 640,
+ .yres = 480,
+@@ -365,6 +364,11 @@ static struct pxafb_mach_info sharp_lm8v
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .cmap_greyscale = 0,
++};
++
++static struct pxafb_mach_info sharp_lm8v31 = {
++ .modes = &sharp_lm8v31_mode,
++ .num_modes = 1,
+ .cmap_inverse = 0,
+ .cmap_static = 0,
+ .lccr0 = LCCR0_SDS,
+@@ -374,7 +378,7 @@ static struct pxafb_mach_info sharp_lm8v
+ #define MMC_POLL_RATE msecs_to_jiffies(1000)
+
+ static void lubbock_mmc_poll(unsigned long);
+-static irqreturn_t (*mmc_detect_int)(int, void *, struct pt_regs *);
++static irq_handler_t mmc_detect_int;
+
+ static struct timer_list mmc_timer = {
+ .function = lubbock_mmc_poll,
+@@ -393,22 +397,22 @@ static void lubbock_mmc_poll(unsigned lo
+ if (LUB_IRQ_SET_CLR & (1 << 0))
+ mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
+ else {
+- (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL);
++ (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data);
+ enable_irq(LUBBOCK_SD_IRQ);
+ }
+ }
+
+-static irqreturn_t lubbock_detect_int(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t lubbock_detect_int(int irq, void *data)
+ {
+ /* IRQ is level triggered; disable, and poll for removal */
+ disable_irq(irq);
+ mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
+
+- return mmc_detect_int(irq, data, regs);
++ return mmc_detect_int(irq, data);
+ }
+
+ static int lubbock_mci_init(struct device *dev,
+- irqreturn_t (*detect_int)(int, void *, struct pt_regs *),
++ irq_handler_t detect_int,
+ void *data)
+ {
+ /* setup GPIO for PXA25x MMC controller */
+diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
+index a7e9b96..49c34d9 100644
+--- a/arch/arm/mach-pxa/mainstone.c
++++ b/arch/arm/mach-pxa/mainstone.c
+@@ -71,8 +71,7 @@ static struct irq_chip mainstone_irq_chi
+ .unmask = mainstone_unmask_irq,
+ };
+
+-static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
+ do {
+@@ -80,7 +79,7 @@ static void mainstone_irq_handler(unsign
+ if (likely(pending)) {
+ irq = MAINSTONE_IRQ(0) + __ffs(pending);
+ desc = irq_desc + irq;
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ }
+ pending = MST_INTSETCLR & mainstone_irq_enabled;
+ } while (pending);
+@@ -279,7 +278,7 @@ static void mainstone_backlight_power(in
+ }
+ }
+
+-static struct pxafb_mach_info toshiba_ltm04c380k __initdata = {
++static struct pxafb_mode_info toshiba_ltm04c380k_mode = {
+ .pixclock = 50000,
+ .xres = 640,
+ .yres = 480,
+@@ -291,12 +290,9 @@ static struct pxafb_mach_info toshiba_lt
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+- .lccr0 = LCCR0_Act,
+- .lccr3 = LCCR3_PCP,
+- .pxafb_backlight_power = mainstone_backlight_power,
+ };
+
+-static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
++static struct pxafb_mode_info toshiba_ltm035a776c_mode = {
+ .pixclock = 110000,
+ .xres = 240,
+ .yres = 320,
+@@ -308,12 +304,16 @@ static struct pxafb_mach_info toshiba_lt
+ .upper_margin = 1,
+ .lower_margin = 10,
+ .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct pxafb_mach_info mainstone_pxafb_info = {
++ .num_modes = 1,
+ .lccr0 = LCCR0_Act,
+ .lccr3 = LCCR3_PCP,
+ .pxafb_backlight_power = mainstone_backlight_power,
+ };
+
+-static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data)
++static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_int, void *data)
+ {
+ int err;
+
+@@ -448,9 +448,11 @@ static void __init mainstone_init(void)
+ /* reading Mainstone's "Virtual Configuration Register"
+ might be handy to select LCD type here */
+ if (0)
+- set_pxa_fb_info(&toshiba_ltm04c380k);
++ mainstone_pxafb_info.modes = &toshiba_ltm04c380k_mode;
+ else
+- set_pxa_fb_info(&toshiba_ltm035a776c);
++ mainstone_pxafb_info.modes = &toshiba_ltm035a776c_mode;
++
++ set_pxa_fb_info(&mainstone_pxafb_info);
+
+ pxa_set_mci_info(&mainstone_mci_platform_data);
+ pxa_set_ficp_info(&mainstone_ficp_platform_data);
+diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
+index 6dbff6d..34fb80b 100644
+--- a/arch/arm/mach-pxa/poodle.c
++++ b/arch/arm/mach-pxa/poodle.c
+@@ -197,7 +197,7 @@ static struct platform_device poodle_ts_
+ */
+ static struct pxamci_platform_data poodle_mci_platform_data;
+
+-static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(int, void *, struct pt_regs *), void *data)
++static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int, void *data)
+ {
+ int err;
+
+@@ -296,27 +296,25 @@ static struct pxa2xx_udc_mach_info udc_i
+
+
+ /* PXAFB device */
+-static struct pxafb_mach_info poodle_fb_info __initdata = {
++static struct pxafb_mode_info poodle_fb_mode = {
+ .pixclock = 144700,
+-
+ .xres = 320,
+ .yres = 240,
+ .bpp = 16,
+-
+ .hsync_len = 7,
+ .left_margin = 11,
+ .right_margin = 30,
+-
+ .vsync_len = 2,
+ .upper_margin = 2,
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
+
++static struct pxafb_mach_info poodle_fb_info = {
++ .modes = &poodle_fb_mode,
++ .num_modes = 1,
+ .lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color,
+ .lccr3 = 0,
+-
+- .pxafb_backlight_power = NULL,
+- .pxafb_lcd_power = NULL,
+ };
+
+ static struct platform_device *devices[] __initdata = {
+diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
+index 1c32a93..3cbac63 100644
+--- a/arch/arm/mach-pxa/spitz.c
++++ b/arch/arm/mach-pxa/spitz.c
+@@ -291,7 +291,7 @@ static struct platform_device spitzts_de
+
+ static struct pxamci_platform_data spitz_mci_platform_data;
+
+-static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *, struct pt_regs *), void *data)
++static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, void *data)
+ {
+ int err;
+
+@@ -407,21 +407,42 @@ static struct pxaficp_platform_data spit
+ /*
+ * Spitz PXA Framebuffer
+ */
+-static struct pxafb_mach_info spitz_pxafb_info __initdata = {
+- .pixclock = 19231,
+- .xres = 480,
+- .yres = 640,
+- .bpp = 16,
+- .hsync_len = 40,
+- .left_margin = 46,
+- .right_margin = 125,
+- .vsync_len = 3,
+- .upper_margin = 1,
+- .lower_margin = 0,
+- .sync = 0,
+- .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
+- .lccr3 = LCCR3_PixRsEdg | LCCR3_OutEnH,
+- .pxafb_lcd_power = spitz_lcd_power,
++
++static struct pxafb_mode_info spitz_pxafb_modes[] = {
++{
++ .pixclock = 19231,
++ .xres = 480,
++ .yres = 640,
++ .bpp = 16,
++ .hsync_len = 40,
++ .left_margin = 46,
++ .right_margin = 125,
++ .vsync_len = 3,
++ .upper_margin = 1,
++ .lower_margin = 0,
++ .sync = 0,
++},{
++ .pixclock = 134617,
++ .xres = 240,
++ .yres = 320,
++ .bpp = 16,
++ .hsync_len = 20,
++ .left_margin = 20,
++ .right_margin = 46,
++ .vsync_len = 2,
++ .upper_margin = 1,
++ .lower_margin = 0,
++ .sync = 0,
++},
++};
++
++static struct pxafb_mach_info spitz_pxafb_info = {
++ .modes = &spitz_pxafb_modes[0],
++ .num_modes = 2,
++ .fixed_modes = 1,
++ .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
++ .lccr3 = LCCR3_PixRsEdg | LCCR3_OutEnH,
++ .pxafb_lcd_power = spitz_lcd_power,
+ };
+
+
+diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
+index 1fddfea..6cc2027 100644
+--- a/arch/arm/mach-pxa/ssp.c
++++ b/arch/arm/mach-pxa/ssp.c
+@@ -65,7 +65,7 @@ static const struct ssp_info_ ssp_info[P
+ static DEFINE_MUTEX(mutex);
+ static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
+
+-static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+ {
+ struct ssp_dev *dev = (struct ssp_dev*) dev_id;
+ unsigned int status = SSSR_P(dev->port);
+diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
+index 5dbd191..3ac268f 100644
+--- a/arch/arm/mach-pxa/time.c
++++ b/arch/arm/mach-pxa/time.c
+@@ -75,7 +75,7 @@ static int match_posponed;
+ #endif
+
+ static irqreturn_t
+-pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++pxa_timer_interrupt(int irq, void *dev_id)
+ {
+ int next_match;
+
+@@ -105,7 +105,7 @@ pxa_timer_interrupt(int irq, void *dev_i
+ * exactly one tick period which should be a pretty rare event.
+ */
+ do {
+- timer_tick(regs);
++ timer_tick();
+ OSSR = OSSR_M0; /* Clear match on timer 0 */
+ next_match = (OSMR0 += LATCH);
+ } while( (signed long)(next_match - OSCR) <= 8 );
+@@ -157,13 +157,13 @@ static void pxa_dyn_tick_reprogram(unsig
+ }
+
+ static irqreturn_t
+-pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
++pxa_dyn_tick_handler(int irq, void *dev_id)
+ {
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ if ( (signed long)(initial_match - OSCR) <= 8 )
+- return pxa_timer_interrupt(irq, dev_id, regs);
++ return pxa_timer_interrupt(irq, dev_id);
+ }
+ return IRQ_NONE;
+ }
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 2493536..7915a5a 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -174,7 +174,7 @@ static struct pxa2xx_udc_mach_info udc_i
+ */
+ static struct pxamci_platform_data tosa_mci_platform_data;
+
+-static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *, struct pt_regs *), void *data)
++static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void *data)
+ {
+ int err;
+
+diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
+index 7c3007d..c1827d0 100644
+--- a/arch/arm/mach-pxa/trizeps4.c
++++ b/arch/arm/mach-pxa/trizeps4.c
+@@ -270,7 +270,7 @@ void board_pcmcia_power(int power) {;}
+ #endif /* CONFIG_MACH_TRIZEPS4_CONXS */
+ EXPORT_SYMBOL(board_pcmcia_power);
+
+-static int trizeps4_mci_init(struct device *dev, irqreturn_t (*mci_detect_int)(int, void *, struct pt_regs *), void *data)
++static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, void *data)
+ {
+ int err;
+ /* setup GPIO for PXA27x MMC controller */
+@@ -368,7 +368,7 @@ static struct map_desc trizeps4_io_desc[
+ }
+ };
+
+-static struct pxafb_mach_info sharp_lcd __initdata = {
++static struct pxafb_mode_info sharp_lcd_mode = {
+ .pixclock = 78000,
+ .xres = 640,
+ .yres = 480,
+@@ -381,6 +381,11 @@ static struct pxafb_mach_info sharp_lcd
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .cmap_greyscale = 0,
++};
++
++static struct pxafb_mach_info sharp_lcd = {
++ .modes = &sharp_lcd_mode,
++ .num_modes = 1,
+ .cmap_inverse = 0,
+ .cmap_static = 0,
+ .lccr0 = LCCR0_Color | LCCR0_Pas | LCCR0_Dual,
+diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
+index da02869..68c6705 100644
+--- a/arch/arm/mach-realview/core.c
++++ b/arch/arm/mach-realview/core.c
+@@ -515,18 +515,18 @@ static unsigned long realview_gettimeoff
+ /*
+ * IRQ handler for the timer
+ */
+-static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+ // ...clear the interrupt
+ writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
+
+- timer_tick(regs);
++ timer_tick();
+
+ #if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
+ smp_send_timer();
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+
+ write_sequnlock(&xtime_lock);
+diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
+index ac511d4..596379a 100644
+--- a/arch/arm/mach-rpc/dma.c
++++ b/arch/arm/mach-rpc/dma.c
+@@ -83,7 +83,7 @@ static void iomd_get_next_sg(struct scat
+ sg->length |= flags;
+ }
+
+-static irqreturn_t iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
+ {
+ dma_t *dma = (dma_t *)dev_id;
+ unsigned long base = dma->dma_base;
+diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
+index bbd138b..63965c7 100644
+--- a/arch/arm/mach-s3c2410/Kconfig
++++ b/arch/arm/mach-s3c2410/Kconfig
+@@ -2,11 +2,18 @@ if ARCH_S3C2410
+
+ menu "S3C24XX Implementations"
+
++config MACH_AML_M5900
++ bool "AML M5900 Series"
++ select CPU_S3C2410
++ help
++ Say Y here if you are using the American Microsystems M5900 Series
++ <http://www.amltd.com>
++
+ config MACH_ANUBIS
+ bool "Simtec Electronics ANUBIS"
+ select CPU_S3C2440
+ help
+- Say Y gere if you are using the Simtec Electronics ANUBIS
++ Say Y here if you are using the Simtec Electronics ANUBIS
+ development system
+
+ config MACH_OSIRIS
+@@ -126,6 +133,12 @@ config MACH_NEXCODER_2440
+ help
+ Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
+
++config MACH_VSTMS
++ bool "VMSTMS"
++ select CPU_S3C2412
++ help
++ Say Y here if you are using an VSTMS board
++
+ endmenu
+
+ config S3C2410_CLOCK
+@@ -133,10 +146,24 @@ config S3C2410_CLOCK
+ help
+ Clock code for the S3C2410, and similar processors
+
++config S3C2410_PM
++ bool
++ depends on CONFIG_PM
++ help
++ Power Management code common to S3C2410 and better
++
++config CPU_S3C2410_DMA
++ bool
++ depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
++ default y if CPU_S3C2410 || CPU_S3C2442
++ help
++ DMA device selection for S3C2410 and compatible CPUs
++
+ config CPU_S3C2410
+ bool
+ depends on ARCH_S3C2410
+ select S3C2410_CLOCK
++ select S3C2410_PM
+ help
+ Support for S3C2410 and S3C2410A family from the S3C24XX line
+ of Samsung Mobile CPUs.
+@@ -149,6 +176,13 @@ config CPU_S3C2412_ONLY
+ !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
+ default y if CPU_S3C2412
+
++config S3C2412_PM
++ bool
++ default y if PM
++ depends on CPU_S3C2412
++ help
++ Internal config node to apply S3C2412 power management
++
+ config CPU_S3C2412
+ bool
+ depends on ARCH_S3C2410
+@@ -165,6 +199,7 @@ config CPU_S3C2440
+ bool
+ depends on ARCH_S3C2410
+ select S3C2410_CLOCK
++ select S3C2410_PM
+ select CPU_S3C244X
+ help
+ Support for S3C2440 Samsung Mobile CPU based systems.
+@@ -173,6 +208,7 @@ config CPU_S3C2442
+ bool
+ depends on ARCH_S3C2420
+ select S3C2410_CLOCK
++ select S3C2410_PM
+ select CPU_S3C244X
+ help
+ Support for S3C2442 Samsung Mobile CPU based systems.
+@@ -256,7 +292,7 @@ config S3C2410_PM_CHECK_CHUNKSIZE
+
+ config PM_SIMTEC
+ bool
+- depends on PM && (ARCH_BAST || MACH_VR1000)
++ depends on PM && (ARCH_BAST || MACH_VR1000 || MACH_AML_M5900)
+ default y
+
+ config S3C2410_LOWLEVEL_UART_PORT
+diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
+index 0eadec9..d660133 100644
+--- a/arch/arm/mach-s3c2410/Makefile
++++ b/arch/arm/mach-s3c2410/Makefile
+@@ -9,6 +9,8 @@ obj-y := cpu.o irq.o time.o gpio.o clo
+ obj-m :=
+ obj-n :=
+ obj- :=
++obj-dma-y :=
++obj-dma-n :=
+
+ # DMA
+ obj-$(CONFIG_S3C2410_DMA) += dma.o
+@@ -20,6 +22,10 @@ obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpi
+
+ obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
+ obj-$(CONFIG_CPU_S3C2410) += s3c2410-gpio.o
++obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o
++
++obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o
++obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o
+
+ # Power Management support
+
+@@ -30,6 +36,9 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
+ obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
+ obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o
+ obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
++obj-dma-$(CONFIG_CPU_S3C2412) += s3c2412-dma.o
++
++obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o
+
+ #
+ # S3C244X support
+@@ -47,6 +56,7 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s
+ obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
+ obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
+ obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o
++obj-dma-$(CONFIG_CPU_S3C2440) += s3c2440-dma.o
+
+ # S3C2442 support
+
+@@ -57,8 +67,13 @@ obj-$(CONFIG_CPU_S3C2442) += s3c2442-clo
+
+ obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
+
++# merge in dma objects
++
++obj-y += $(obj-dma-y)
++
+ # machine specific support
+
++obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
+ obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
+ obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
+ obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
+@@ -71,5 +86,6 @@ obj-$(CONFIG_MACH_VR1000) += mach-vr1000
+ obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
+ obj-$(CONFIG_MACH_OTOM) += mach-otom.o
+ obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
++obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o
+
+ obj-$(CONFIG_MACH_SMDK) += common-smdk.o
+\ No newline at end of file
+diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
+index def4441..23d5bee 100644
+--- a/arch/arm/mach-s3c2410/bast-irq.c
++++ b/arch/arm/mach-s3c2410/bast-irq.c
+@@ -18,10 +18,6 @@
+ * 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
+- *
+- * Modifications:
+- * 08-Jan-2003 BJD Moved from central IRQ code
+- * 21-Aug-2005 BJD Fixed missing code and compile errors
+ */
+
+
+@@ -116,8 +112,7 @@ static struct irqchip bast_pc104_chip =
+
+ static void
+ bast_irq_pc104_demux(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ unsigned int stat;
+ unsigned int irqno;
+@@ -137,7 +132,7 @@ bast_irq_pc104_demux(unsigned int irq,
+ if (stat & 1) {
+ irqno = bast_pc104_irqs[i];
+ desc = irq_desc + irqno;
+- desc_handle_irq(irqno, desc, regs);
++ desc_handle_irq(irqno, desc);
+ }
+ }
+ }
+diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
+index 1c3c6ad..9d4899e 100644
+--- a/arch/arm/mach-s3c2410/cpu.c
++++ b/arch/arm/mach-s3c2410/cpu.c
+@@ -124,6 +124,15 @@ static struct cpu_table cpu_ids[] __init
+ .init = s3c2412_init,
+ .name = name_s3c2412,
+ },
++ { /* a newer version of the s3c2412 */
++ .idcode = 0x32412003,
++ .idmask = 0xffffffff,
++ .map_io = s3c2412_map_io,
++ .init_clocks = s3c2412_init_clocks,
++ .init_uarts = s3c2412_init_uarts,
++ .init = s3c2412_init,
++ .name = name_s3c2412,
++ },
+ {
+ .idcode = 0x0, /* S3C2400 doesn't have an idcode */
+ .idmask = 0xffffffff,
+diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h
+index 726e2ea..14fb0ba 100644
+--- a/arch/arm/mach-s3c2410/devs.h
++++ b/arch/arm/mach-s3c2410/devs.h
+@@ -8,11 +8,6 @@
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+- *
+- * Modifications:
+- * 18-Aug-2004 BJD Created initial version
+- * 27-Aug-2004 BJD Added timers 0 through 3
+- * 10-Feb-2005 BJD Added camera from guillaume.gourat at nexvision.tv
+ */
+ #include <linux/platform_device.h>
+
+diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
+index cc92a7b..3d211dc 100644
+--- a/arch/arm/mach-s3c2410/dma.c
++++ b/arch/arm/mach-s3c2410/dma.c
+@@ -1,35 +1,16 @@
+-/* linux/arch/arm/mach-bast/dma.c
++/* linux/arch/arm/mach-s3c2410/dma.c
+ *
+- * (c) 2003-2005 Simtec Electronics
++ * (c) 2003-2005,2006 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+ *
+ * S3C2410 DMA core
+ *
+- * http://www.simtec.co.uk/products/EB2410ITX/
++ * http://armlinux.simtec.co.uk/
+ *
+ * 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:
+- * 27-Feb-2005 BJD Added kmem cache for dma descriptors
+- * 18-Nov-2004 BJD Removed error for loading onto stopped channel
+- * 10-Nov-2004 BJD Ensure all external symbols exported for modules
+- * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management
+- * 08-Aug-2004 BJD Apply rmk's suggestions
+- * 21-Jul-2004 BJD Ported to linux 2.6
+- * 12-Jul-2004 BJD Finished re-write and change of API
+- * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems
+- * 23-May-2003 BJD Created file
+- * 19-Aug-2003 BJD Cleanup, header fix, added URL
+- *
+- * This file is based on the Sangwook Lee/Samsung patches, re-written due
+- * to various ommisions from the code (such as flexible dma configuration)
+- * for use with the BAST system board.
+- *
+- * The re-write is pretty much complete, and should be good enough for any
+- * possible DMA function
+- */
++*/
+
+
+ #ifdef CONFIG_S3C2410_DMA_DEBUG
+@@ -55,10 +36,14 @@
+ #include <asm/mach/dma.h>
+ #include <asm/arch/map.h>
+
++#include "dma.h"
++
+ /* io map for dma */
+ static void __iomem *dma_base;
+ static kmem_cache_t *dma_kmem;
+
++struct s3c24xx_dma_selection dma_sel;
++
+ /* dma channel state information */
+ struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
+
+@@ -79,7 +64,6 @@ dma_wrreg(struct s3c2410_dma_chan *chan,
+ pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
+ writel(val, dma_regaddr(chan, reg));
+ }
+-
+ #endif
+
+ #define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
+@@ -151,12 +135,20 @@ dmadbg_showregs(const char *fname, int l
+ #define dbg_showchan(chan) do { } while(0)
+ #endif /* CONFIG_S3C2410_DMA_DEBUG */
+
+-#define check_channel(chan) \
+- do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
+- printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
+- return -EINVAL; \
+- } } while(0)
++static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
+
++/* lookup_dma_channel
++ *
++ * change the dma channel number given into a real dma channel id
++*/
++
++static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
++{
++ if (channel & DMACH_LOW_LEVEL)
++ return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
++ else
++ return dma_chan_map[channel];
++}
+
+ /* s3c2410_dma_stats_timeout
+ *
+@@ -321,8 +313,10 @@ static inline void
+ s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
+ enum s3c2410_dma_buffresult result)
+ {
++#if 0
+ pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
+ chan->callback_fn, buf, buf->id, buf->size, result);
++#endif
+
+ if (chan->callback_fn != NULL) {
+ (chan->callback_fn)(chan, buf->id, buf->size, result);
+@@ -439,7 +433,6 @@ s3c2410_dma_canload(struct s3c2410_dma_c
+ return 0;
+ }
+
+-
+ /* s3c2410_dma_enqueue
+ *
+ * queue an given buffer for dma transfer.
+@@ -460,11 +453,12 @@ s3c2410_dma_canload(struct s3c2410_dma_c
+ int s3c2410_dma_enqueue(unsigned int channel, void *id,
+ dma_addr_t data, int size)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+ struct s3c2410_dma_buf *buf;
+ unsigned long flags;
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ pr_debug("%s: id=%p, data=%08x, size=%d\n",
+ __FUNCTION__, id, (unsigned int)data, size);
+@@ -562,8 +556,10 @@ s3c2410_dma_freebuf(struct s3c2410_dma_b
+ static inline void
+ s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
+ {
++#if 0
+ pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
+ chan->number, chan->load_state);
++#endif
+
+ switch (chan->load_state) {
+ case S3C2410_DMALOAD_NONE:
+@@ -599,7 +595,7 @@ s3c2410_dma_lastxfer(struct s3c2410_dma_
+ #define dmadbg2(x...)
+
+ static irqreturn_t
+-s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
++s3c2410_dma_irq(int irq, void *devpw)
+ {
+ struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
+ struct s3c2410_dma_buf *buf;
+@@ -718,7 +714,8 @@ s3c2410_dma_irq(int irq, void *devpw, st
+ if (chan->load_state == S3C2410_DMALOAD_NONE) {
+ pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
+ chan->number, jiffies);
+- s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
++ s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
++ S3C2410_DMAOP_STOP);
+ }
+ }
+
+@@ -726,37 +723,34 @@ s3c2410_dma_irq(int irq, void *devpw, st
+ return IRQ_HANDLED;
+ }
+
++static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
++
+ /* s3c2410_request_dma
+ *
+ * get control of an dma channel
+ */
+
+-int s3c2410_dma_request(unsigned int channel, struct s3c2410_dma_client *client,
++int s3c2410_dma_request(unsigned int channel,
++ struct s3c2410_dma_client *client,
+ void *dev)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan;
+ unsigned long flags;
+ int err;
+
+ pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
+ channel, client->name, dev);
+
+- check_channel(channel);
+-
+ local_irq_save(flags);
+
+- dbg_showchan(chan);
+-
+- if (chan->in_use) {
+- if (client != chan->client) {
+- printk(KERN_ERR "dma%d: already in use\n", channel);
+- local_irq_restore(flags);
+- return -EBUSY;
+- } else {
+- printk(KERN_ERR "dma%d: client already has channel\n", channel);
+- }
++ chan = s3c2410_dma_map_channel(channel);
++ if (chan == NULL) {
++ local_irq_restore(flags);
++ return -EBUSY;
+ }
+
++ dbg_showchan(chan);
++
+ chan->client = client;
+ chan->in_use = 1;
+
+@@ -809,14 +803,14 @@ EXPORT_SYMBOL(s3c2410_dma_request);
+
+ int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+ unsigned long flags;
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ local_irq_save(flags);
+
+-
+ if (chan->client != client) {
+ printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
+ channel, chan->client, client);
+@@ -837,8 +831,12 @@ int s3c2410_dma_free(dmach_t channel, st
+
+ if (chan->irq_claimed)
+ free_irq(chan->irq, (void *)chan);
++
+ chan->irq_claimed = 0;
+
++ if (!(channel & DMACH_LOW_LEVEL))
++ dma_chan_map[channel] = NULL;
++
+ local_irq_restore(flags);
+
+ return 0;
+@@ -848,8 +846,8 @@ EXPORT_SYMBOL(s3c2410_dma_free);
+
+ static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
+ {
+- unsigned long tmp;
+ unsigned long flags;
++ unsigned long tmp;
+
+ pr_debug("%s:\n", __FUNCTION__);
+
+@@ -997,9 +995,10 @@ s3c2410_dma_started(struct s3c2410_dma_c
+ int
+ s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ switch (op) {
+ case S3C2410_DMAOP_START:
+@@ -1046,12 +1045,19 @@ int s3c2410_dma_config(dmach_t channel,
+ int xferunit,
+ int dcon)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
+ __FUNCTION__, channel, xferunit, dcon);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
++
++ printk("Initial dcon is %08x\n", dcon);
++
++ dcon |= chan->dcon & dma_sel.dcon_mask;
++
++ printk("New dcon is %08x\n", dcon);
+
+ switch (xferunit) {
+ case 1:
+@@ -1086,9 +1092,10 @@ EXPORT_SYMBOL(s3c2410_dma_config);
+
+ int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
+
+@@ -1106,9 +1113,10 @@ EXPORT_SYMBOL(s3c2410_dma_setflags);
+
+ int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
+
+@@ -1121,9 +1129,10 @@ EXPORT_SYMBOL(s3c2410_dma_set_opfn);
+
+ int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
+
+@@ -1153,9 +1162,10 @@ int s3c2410_dma_devconfig(int channel,
+ int hwcfg,
+ unsigned long devaddr)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
+ __FUNCTION__, (int)source, hwcfg, devaddr);
+@@ -1200,9 +1210,10 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
+
+ int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
+ {
+- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
++ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+- check_channel(channel);
++ if (chan == NULL)
++ return -EINVAL;
+
+ if (src != NULL)
+ *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
+@@ -1252,7 +1263,7 @@ static int s3c2410_dma_resume(struct sys
+ #define s3c2410_dma_resume NULL
+ #endif /* CONFIG_PM */
+
+-static struct sysdev_class dma_sysclass = {
++struct sysdev_class dma_sysclass = {
+ set_kset_name("s3c24xx-dma"),
+ .suspend = s3c2410_dma_suspend,
+ .resume = s3c2410_dma_resume,
+@@ -1265,7 +1276,6 @@ static void s3c2410_dma_cache_ctor(void
+ memset(p, 0, sizeof(struct s3c2410_dma_buf));
+ }
+
+-
+ /* initialisation code */
+
+ static int __init s3c2410_init_dma(void)
+@@ -1274,7 +1284,7 @@ static int __init s3c2410_init_dma(void)
+ int channel;
+ int ret;
+
+- printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
++ printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
+
+ dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
+ if (dma_base == NULL) {
+@@ -1282,6 +1292,8 @@ static int __init s3c2410_init_dma(void)
+ return -ENOMEM;
+ }
+
++ printk("Registering sysclass\n");
++
+ ret = sysdev_class_register(&dma_sysclass);
+ if (ret != 0) {
+ printk(KERN_ERR "dma sysclass registration failed\n");
+@@ -1335,4 +1347,95 @@ static int __init s3c2410_init_dma(void)
+ return ret;
+ }
+
+-__initcall(s3c2410_init_dma);
++core_initcall(s3c2410_init_dma);
++
++static inline int is_channel_valid(unsigned int channel)
++{
++ return (channel & DMA_CH_VALID);
++}
++
++/* s3c2410_dma_map_channel()
++ *
++ * turn the virtual channel number into a real, and un-used hardware
++ * channel.
++ *
++ * currently this code uses first-free channel from the specified harware
++ * map, not taking into account anything that the board setup code may
++ * have to say about the likely peripheral set to be in use.
++*/
++
++struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
++{
++ struct s3c24xx_dma_map *ch_map;
++ struct s3c2410_dma_chan *dmach;
++ int ch;
++
++ if (dma_sel.map == NULL || channel > dma_sel.map_size)
++ return NULL;
++
++ ch_map = dma_sel.map + channel;
++
++ for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
++ if (!is_channel_valid(ch_map->channels[ch]))
++ continue;
++
++ if (s3c2410_chans[ch].in_use == 0) {
++ printk("mapped channel %d to %d\n", channel, ch);
++ break;
++ }
++ }
++
++ if (ch >= S3C2410_DMA_CHANNELS)
++ return NULL;
++
++ /* update our channel mapping */
++
++ dmach = &s3c2410_chans[ch];
++ dma_chan_map[channel] = dmach;
++
++ /* select the channel */
++
++ (dma_sel.select)(dmach, ch_map);
++
++ return dmach;
++}
++
++static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
++{
++ /* show the channel configuration */
++
++ printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
++ (is_channel_valid(map->channels[0]) ? '0' : '-'),
++ (is_channel_valid(map->channels[1]) ? '1' : '-'),
++ (is_channel_valid(map->channels[2]) ? '2' : '-'),
++ (is_channel_valid(map->channels[3]) ? '3' : '-'));
++}
++
++static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
++{
++ if (1)
++ s3c24xx_dma_show_ch(map, ch);
++
++ return 0;
++}
++
++int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
++{
++ struct s3c24xx_dma_map *nmap;
++ size_t map_sz = sizeof(*nmap) * sel->map_size;
++ int ptr;
++
++ nmap = kmalloc(map_sz, GFP_KERNEL);
++ if (nmap == NULL)
++ return -ENOMEM;
++
++ memcpy(nmap, sel->map, map_sz);
++ memcpy(&dma_sel, sel, sizeof(*sel));
++
++ dma_sel.map = nmap;
++
++ for (ptr = 0; ptr < sel->map_size; ptr++)
++ s3c24xx_dma_check_entry(nmap+ptr, ptr);
++
++ return 0;
++}
+diff --git a/arch/arm/mach-s3c2410/dma.h b/arch/arm/mach-s3c2410/dma.h
+new file mode 100644
+index 0000000..0ebfe0a
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/dma.h
+@@ -0,0 +1,45 @@
++/* arch/arm/mach-s3c2410/dma.h
++ *
++ * Copyright (C) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * Samsung S3C24XX DMA support
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++*/
++
++extern struct sysdev_class dma_sysclass;
++extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
++
++#define DMA_CH_VALID (1<<31)
++
++struct s3c24xx_dma_addr {
++ unsigned long from;
++ unsigned long to;
++};
++
++/* struct s3c24xx_dma_map
++ *
++ * this holds the mapping information for the channel selected
++ * to be connected to the specified device
++*/
++
++struct s3c24xx_dma_map {
++ const char *name;
++ struct s3c24xx_dma_addr hw_addr;
++
++ unsigned long channels[S3C2410_DMA_CHANNELS];
++};
++
++struct s3c24xx_dma_selection {
++ struct s3c24xx_dma_map *map;
++ unsigned long map_size;
++ unsigned long dcon_mask;
++
++ void (*select)(struct s3c2410_dma_chan *chan,
++ struct s3c24xx_dma_map *map);
++};
++
++extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
+index cd39e86..ba34654 100644
+--- a/arch/arm/mach-s3c2410/gpio.c
++++ b/arch/arm/mach-s3c2410/gpio.c
+@@ -3,7 +3,7 @@
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+ *
+- * S3C2410 GPIO support
++ * S3C24XX GPIO 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
+@@ -18,21 +18,7 @@
+ * 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
+- *
+- * Changelog
+- * 13-Sep-2004 BJD Implemented change of MISCCR
+- * 14-Sep-2004 BJD Added getpin call
+- * 14-Sep-2004 BJD Fixed bug in setpin() call
+- * 30-Sep-2004 BJD Fixed cfgpin() mask bug
+- * 01-Oct-2004 BJD Added getcfg() to get pin configuration
+- * 01-Oct-2004 BJD Fixed mask bug in pullup() call
+- * 01-Oct-2004 BJD Added getirq() to turn pin into irqno
+- * 04-Oct-2004 BJD Added irq filter controls for GPIO
+- * 05-Nov-2004 BJD EXPORT_SYMBOL() added for all code
+- * 13-Mar-2005 BJD Updates for __iomem
+- * 26-Oct-2005 BJD Added generic configuration types
+- * 15-Jan-2006 LCVR Added support for the S3C2400
+- */
++*/
+
+
+ #include <linux/kernel.h>
+@@ -177,3 +163,22 @@ unsigned int s3c2410_modify_misccr(unsig
+ }
+
+ EXPORT_SYMBOL(s3c2410_modify_misccr);
++
++int s3c2410_gpio_getirq(unsigned int pin)
++{
++ if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
++ return -1; /* not valid interrupts */
++
++ if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
++ return -1; /* not valid pin */
++
++ if (pin < S3C2410_GPF4)
++ return (pin - S3C2410_GPF0) + IRQ_EINT0;
++
++ if (pin < S3C2410_GPG0)
++ return (pin - S3C2410_GPF4) + IRQ_EINT4;
++
++ return (pin - S3C2410_GPG0) + IRQ_EINT8;
++}
++
++EXPORT_SYMBOL(s3c2410_gpio_getirq);
+diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
+index cd6139b..683b349 100644
+--- a/arch/arm/mach-s3c2410/irq.c
++++ b/arch/arm/mach-s3c2410/irq.c
+@@ -181,17 +181,19 @@ s3c_irq_unmask(unsigned int irqno)
+ }
+
+ struct irqchip s3c_irq_level_chip = {
+- .ack = s3c_irq_maskack,
+- .mask = s3c_irq_mask,
+- .unmask = s3c_irq_unmask,
+- .set_wake = s3c_irq_wake
++ .name = "s3c-level",
++ .ack = s3c_irq_maskack,
++ .mask = s3c_irq_mask,
++ .unmask = s3c_irq_unmask,
++ .set_wake = s3c_irq_wake
+ };
+
+ static struct irqchip s3c_irq_chip = {
+- .ack = s3c_irq_ack,
+- .mask = s3c_irq_mask,
+- .unmask = s3c_irq_unmask,
+- .set_wake = s3c_irq_wake
++ .name = "s3c",
++ .ack = s3c_irq_ack,
++ .mask = s3c_irq_mask,
++ .unmask = s3c_irq_unmask,
++ .set_wake = s3c_irq_wake
+ };
+
+ static void
+@@ -343,19 +345,21 @@ s3c_irqext_type(unsigned int irq, unsign
+ }
+
+ static struct irqchip s3c_irqext_chip = {
+- .mask = s3c_irqext_mask,
+- .unmask = s3c_irqext_unmask,
+- .ack = s3c_irqext_ack,
+- .set_type = s3c_irqext_type,
+- .set_wake = s3c_irqext_wake
++ .name = "s3c-ext",
++ .mask = s3c_irqext_mask,
++ .unmask = s3c_irqext_unmask,
++ .ack = s3c_irqext_ack,
++ .set_type = s3c_irqext_type,
++ .set_wake = s3c_irqext_wake
+ };
+
+ static struct irqchip s3c_irq_eint0t4 = {
+- .ack = s3c_irq_ack,
+- .mask = s3c_irq_mask,
+- .unmask = s3c_irq_unmask,
+- .set_wake = s3c_irq_wake,
+- .set_type = s3c_irqext_type,
++ .name = "s3c-ext0",
++ .ack = s3c_irq_ack,
++ .mask = s3c_irq_mask,
++ .unmask = s3c_irq_unmask,
++ .set_wake = s3c_irq_wake,
++ .set_type = s3c_irqext_type,
+ };
+
+ /* mask values for the parent registers for each of the interrupt types */
+@@ -387,9 +391,10 @@ s3c_irq_uart0_ack(unsigned int irqno)
+ }
+
+ static struct irqchip s3c_irq_uart0 = {
+- .mask = s3c_irq_uart0_mask,
+- .unmask = s3c_irq_uart0_unmask,
+- .ack = s3c_irq_uart0_ack,
++ .name = "s3c-uart0",
++ .mask = s3c_irq_uart0_mask,
++ .unmask = s3c_irq_uart0_unmask,
++ .ack = s3c_irq_uart0_ack,
+ };
+
+ /* UART1 */
+@@ -413,9 +418,10 @@ s3c_irq_uart1_ack(unsigned int irqno)
+ }
+
+ static struct irqchip s3c_irq_uart1 = {
+- .mask = s3c_irq_uart1_mask,
+- .unmask = s3c_irq_uart1_unmask,
+- .ack = s3c_irq_uart1_ack,
++ .name = "s3c-uart1",
++ .mask = s3c_irq_uart1_mask,
++ .unmask = s3c_irq_uart1_unmask,
++ .ack = s3c_irq_uart1_ack,
+ };
+
+ /* UART2 */
+@@ -439,9 +445,10 @@ s3c_irq_uart2_ack(unsigned int irqno)
+ }
+
+ static struct irqchip s3c_irq_uart2 = {
+- .mask = s3c_irq_uart2_mask,
+- .unmask = s3c_irq_uart2_unmask,
+- .ack = s3c_irq_uart2_ack,
++ .name = "s3c-uart2",
++ .mask = s3c_irq_uart2_mask,
++ .unmask = s3c_irq_uart2_unmask,
++ .ack = s3c_irq_uart2_ack,
+ };
+
+ /* ADC and Touchscreen */
+@@ -465,15 +472,15 @@ s3c_irq_adc_ack(unsigned int irqno)
+ }
+
+ static struct irqchip s3c_irq_adc = {
+- .mask = s3c_irq_adc_mask,
+- .unmask = s3c_irq_adc_unmask,
+- .ack = s3c_irq_adc_ack,
++ .name = "s3c-adc",
++ .mask = s3c_irq_adc_mask,
++ .unmask = s3c_irq_adc_unmask,
++ .ack = s3c_irq_adc_ack,
+ };
+
+ /* irq demux for adc */
+ static void s3c_irq_demux_adc(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ unsigned int subsrc, submsk;
+ unsigned int offset = 9;
+@@ -492,17 +499,16 @@ static void s3c_irq_demux_adc(unsigned i
+ if (subsrc != 0) {
+ if (subsrc & 1) {
+ mydesc = irq_desc + IRQ_TC;
+- desc_handle_irq(IRQ_TC, mydesc, regs);
++ desc_handle_irq(IRQ_TC, mydesc);
+ }
+ if (subsrc & 2) {
+ mydesc = irq_desc + IRQ_ADC;
+- desc_handle_irq(IRQ_ADC, mydesc, regs);
++ desc_handle_irq(IRQ_ADC, mydesc);
+ }
+ }
+ }
+
+-static void s3c_irq_demux_uart(unsigned int start,
+- struct pt_regs *regs)
++static void s3c_irq_demux_uart(unsigned int start)
+ {
+ unsigned int subsrc, submsk;
+ unsigned int offset = start - IRQ_S3CUART_RX0;
+@@ -525,17 +531,17 @@ static void s3c_irq_demux_uart(unsigned
+ desc = irq_desc + start;
+
+ if (subsrc & 1)
+- desc_handle_irq(start, desc, regs);
++ desc_handle_irq(start, desc);
+
+ desc++;
+
+ if (subsrc & 2)
+- desc_handle_irq(start+1, desc, regs);
++ desc_handle_irq(start+1, desc);
+
+ desc++;
+
+ if (subsrc & 4)
+- desc_handle_irq(start+2, desc, regs);
++ desc_handle_irq(start+2, desc);
+ }
+ }
+
+@@ -543,49 +549,125 @@ static void s3c_irq_demux_uart(unsigned
+
+ static void
+ s3c_irq_demux_uart0(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ irq = irq;
+- s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs);
++ s3c_irq_demux_uart(IRQ_S3CUART_RX0);
+ }
+
+ static void
+ s3c_irq_demux_uart1(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ irq = irq;
+- s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs);
++ s3c_irq_demux_uart(IRQ_S3CUART_RX1);
+ }
+
+ static void
+ s3c_irq_demux_uart2(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ irq = irq;
+- s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
++ s3c_irq_demux_uart(IRQ_S3CUART_RX2);
+ }
+
+ static void
+-s3c_irq_demux_extint(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++s3c_irq_demux_extint8(unsigned int irq,
++ struct irqdesc *desc)
+ {
+ unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
+ unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
+
+ eintpnd &= ~eintmsk;
++ eintpnd &= ~0xff; /* ignore lower irqs */
+
+- if (eintpnd) {
+- irq = fls(eintpnd);
+- irq += (IRQ_EINT4 - (4 + 1));
++ /* we may as well handle all the pending IRQs here */
+
+- desc_handle_irq(irq, irq_desc + irq, regs);
++ while (eintpnd) {
++ irq = __ffs(eintpnd);
++ eintpnd &= ~(1<<irq);
++
++ irq += (IRQ_EINT4 - 4);
++ desc_handle_irq(irq, irq_desc + irq);
+ }
++
+ }
+
++static void
++s3c_irq_demux_extint4t7(unsigned int irq,
++ struct irqdesc *desc)
++{
++ unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
++ unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
++
++ eintpnd &= ~eintmsk;
++ eintpnd &= 0xff; /* only lower irqs */
++
++ /* we may as well handle all the pending IRQs here */
++
++ while (eintpnd) {
++ irq = __ffs(eintpnd);
++ eintpnd &= ~(1<<irq);
++
++ irq += (IRQ_EINT4 - 4);
++
++ desc_handle_irq(irq, irq_desc + irq);
++ }
++}
++
++#ifdef CONFIG_PM
++
++static struct sleep_save irq_save[] = {
++ SAVE_ITEM(S3C2410_INTMSK),
++ SAVE_ITEM(S3C2410_INTSUBMSK),
++};
++
++/* the extint values move between the s3c2410/s3c2440 and the s3c2412
++ * so we use an array to hold them, and to calculate the address of
++ * the register at run-time
++*/
++
++static unsigned long save_extint[3];
++static unsigned long save_eintflt[4];
++static unsigned long save_eintmask;
++
++int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
++ save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
++
++ for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
++ save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
++
++ s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
++ save_eintmask = __raw_readl(S3C24XX_EINTMASK);
++
++ return 0;
++}
++
++int s3c24xx_irq_resume(struct sys_device *dev)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
++ __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
++
++ for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
++ __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
++
++ s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
++ __raw_writel(save_eintmask, S3C24XX_EINTMASK);
++
++ return 0;
++}
++
++#else
++#define s3c24xx_irq_suspend NULL
++#define s3c24xx_irq_resume NULL
++#endif
++
+ /* s3c24xx_init_irq
+ *
+ * Initialise S3C2410 IRQ system
+@@ -674,8 +756,8 @@ void __init s3c24xx_init_irq(void)
+
+ /* setup the cascade irq handlers */
+
+- set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);
+- set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);
++ set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
++ set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
+
+ set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
+ set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
+diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
+new file mode 100644
+index 0000000..817e2c6
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
+@@ -0,0 +1,266 @@
++/***********************************************************************
++ *
++ * linux/arch/arm/mach-s3c2410/mach-amlm5900.c
++ *
++ * Copyright (c) 2006 American Microsystems Limited
++ * David Anders <danders at amltd.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
++ *
++ * @History:
++ * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ ***********************************************************************/
++
++#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 <linux/platform_device.h>
++#include <linux/proc_fs.h>
++
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++#include <asm/mach/flash.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/arch/fb.h>
++
++#include <asm/arch/regs-serial.h>
++#include <asm/arch/regs-lcd.h>
++#include <asm/arch/regs-gpio.h>
++
++#include "devs.h"
++#include "cpu.h"
++
++#ifdef CONFIG_MTD_PARTITIONS
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/physmap.h>
++
++static struct resource amlm5900_nor_resource = {
++ .start = 0x00000000,
++ .end = 0x01000000 - 1,
++ .flags = IORESOURCE_MEM,
++};
++
++
++
++static struct mtd_partition amlm5900_mtd_partitions[] = {
++ {
++ .name = "System",
++ .size = 0x240000,
++ .offset = 0,
++ .mask_flags = MTD_WRITEABLE, /* force read-only */
++ }, {
++ .name = "Kernel",
++ .size = 0x100000,
++ .offset = MTDPART_OFS_APPEND,
++ }, {
++ .name = "Ramdisk",
++ .size = 0x300000,
++ .offset = MTDPART_OFS_APPEND,
++ }, {
++ .name = "JFFS2",
++ .size = 0x9A0000,
++ .offset = MTDPART_OFS_APPEND,
++ }, {
++ .name = "Settings",
++ .size = MTDPART_SIZ_FULL,
++ .offset = MTDPART_OFS_APPEND,
++ }
++};
++
++static struct physmap_flash_data amlm5900_flash_data = {
++ .width = 2,
++ .parts = amlm5900_mtd_partitions,
++ .nr_parts = ARRAY_SIZE(amlm5900_mtd_partitions),
++};
++
++static struct platform_device amlm5900_device_nor = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &amlm5900_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &amlm5900_nor_resource,
++};
++#endif
++
++static struct map_desc amlm5900_iodesc[] __initdata = {
++ {
++ .virtual = (u32)S3C24XX_VA_SPI,
++ .pfn = __phys_to_pfn(S3C2410_PA_SPI),
++ .length = SZ_1M,
++ .type = MT_DEVICE
++ }
++};
++
++#define UCON S3C2410_UCON_DEFAULT
++#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
++#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
++
++static struct s3c2410_uartcfg amlm5900_uartcfgs[] = {
++ [0] = {
++ .hwport = 0,
++ .flags = 0,
++ .ucon = UCON,
++ .ulcon = ULCON,
++ .ufcon = UFCON,
++ },
++ [1] = {
++ .hwport = 1,
++ .flags = 0,
++ .ucon = UCON,
++ .ulcon = ULCON,
++ .ufcon = UFCON,
++ },
++ [2] = {
++ .hwport = 2,
++ .flags = 0,
++ .ucon = UCON,
++ .ulcon = ULCON,
++ .ufcon = UFCON,
++ }
++};
++
++
++static struct platform_device *amlm5900_devices[] __initdata = {
++#ifdef CONFIG_FB_S3C2410
++ &s3c_device_lcd,
++#endif
++ &s3c_device_adc,
++ &s3c_device_wdt,
++ &s3c_device_i2c,
++ &s3c_device_usb,
++ &s3c_device_rtc,
++ &s3c_device_usbgadget,
++ &s3c_device_sdi,
++#ifdef CONFIG_MTD_PARTITIONS
++ &amlm5900_device_nor,
++#endif
++};
++
++static struct s3c24xx_board amlm5900_board __initdata = {
++ .devices = amlm5900_devices,
++ .devices_count = ARRAY_SIZE(amlm5900_devices)
++};
++
++void __init amlm5900_map_io(void)
++{
++ s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc));
++ s3c24xx_init_clocks(0);
++ s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs));
++ s3c24xx_set_board(&amlm5900_board);
++}
++
++#ifdef CONFIG_FB_S3C2410
++static struct s3c2410fb_mach_info __initdata amlm5900_lcd_info = {
++ .width = 160,
++ .height = 160,
++
++/* commented out until stn patch is submitted
++* .type = S3C2410_LCDCON1_STN4,
++*/
++ .gpccon = 0xaaaaaaaa,
++ .gpccon_mask = 0xffffffff,
++ .gpcup = 0x0000ffff,
++ .gpcup_mask = 0xffffffff,
++
++ .gpdcon = 0xaaaaaaaa,
++ .gpdcon_mask = 0xffffffff,
++ .gpdup = 0x0000ffff,
++ .gpdup_mask = 0xffffffff,
++
++ .xres = {
++ .min = 160,
++ .max = 160,
++ .defval = 160,
++ },
++
++ .yres = {
++ .min = 160,
++ .max = 160,
++ .defval = 160,
++ },
++
++ .bpp = {
++ .min = 4,
++ .max = 4,
++ .defval = 4,
++ },
++
++ .regs = {
++ .lcdcon1 = 0x00008225,
++ .lcdcon2 = 0x0027c000,
++ .lcdcon3 = 0x00182708,
++ .lcdcon4 = 0x00000002,
++ .lcdcon5 = 0x00000001,
++ }
++};
++#endif
++
++static irqreturn_t
++amlm5900_wake_interrupt(int irq, void *ignored)
++{
++ return IRQ_HANDLED;
++}
++
++static void amlm5900_init_pm(void)
++{
++ int ret = 0;
++
++ ret = request_irq(IRQ_EINT9, &amlm5900_wake_interrupt,
++ IRQF_TRIGGER_RISING | IRQF_SHARED,
++ "amlm5900_wakeup", &amlm5900_wake_interrupt);
++ if (ret != 0) {
++ printk(KERN_ERR "AML-M5900: no wakeup irq, %d?\n", ret);
++ } else {
++ enable_irq_wake(IRQ_EINT9);
++ /* configure the suspend/resume status pin */
++ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP);
++ s3c2410_gpio_pullup(S3C2410_GPF2, 0);
++ }
++}
++static void __init amlm5900_init(void)
++{
++ amlm5900_init_pm();
++#ifdef CONFIG_FB_S3C2410
++ s3c24xx_fb_set_platdata(&amlm5900_lcd_info);
++#endif
++}
++
++MACHINE_START(AML_M5900, "AML_M5900")
++ .phys_io = S3C2410_PA_UART,
++ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
++ .boot_params = S3C2410_SDRAM_PA + 0x100,
++ .map_io = amlm5900_map_io,
++ .init_irq = s3c24xx_init_irq,
++ .init_machine = amlm5900_init,
++ .timer = &s3c24xx_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
+index 60641d4..e94cdcd 100644
+--- a/arch/arm/mach-s3c2410/mach-anubis.c
++++ b/arch/arm/mach-s3c2410/mach-anubis.c
+@@ -4,15 +4,9 @@
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben at simtec.co.uk>
+ *
+- *
+- *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+- *
+- * Modifications:
+- * 02-May-2005 BJD Copied from mach-bast.c
+- * 20-Sep-2005 BJD Added static to non-exported items
+ */
+
+ #include <linux/kernel.h>
+diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
+index d661c6b..e2205ff 100644
+--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
++++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
+@@ -11,15 +11,6 @@
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+- * Modifications:
+- * 01-Nov-2004 BJD Initial version
+- * 12-Nov-2004 BJD Updated for release
+- * 04-Jan-2005 BJD Fixes for pre-release
+- * 22-Feb-2005 BJD Updated for 2.6.11-rc5 relesa
+- * 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA
+- * 14-Mar-2005 BJD void __iomem fixes
+- * 20-Sep-2005 BJD Added static to non-exported items
+- * 26-Oct-2005 BJD Added framebuffer data
+ */
+
+ #include <linux/kernel.h>
+diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2410/mach-vstms.c
+new file mode 100644
+index 0000000..ea554e7
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/mach-vstms.c
+@@ -0,0 +1,168 @@
++/* linux/arch/arm/mach-s3c2410/mach-vstms.c
++ *
++ * (C) 2006 Thomas Gleixner <tglx at linutronix.de>
++ *
++ * Derived from mach-smdk2413.c - (C) 2006 Simtec Electronics
++ *
++ * 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/platform_device.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/hardware.h>
++#include <asm/hardware/iomd.h>
++#include <asm/setup.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++
++#include <asm/arch/regs-serial.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-lcd.h>
++
++#include <asm/arch/idle.h>
++#include <asm/arch/fb.h>
++
++#include <asm/arch/nand.h>
++
++#include "s3c2410.h"
++#include "s3c2412.h"
++#include "clock.h"
++#include "devs.h"
++#include "cpu.h"
++
++
++static struct map_desc vstms_iodesc[] __initdata = {
++};
++
++static struct s3c2410_uartcfg vstms_uartcfgs[] __initdata = {
++ [0] = {
++ .hwport = 0,
++ .flags = 0,
++ .ucon = 0x3c5,
++ .ulcon = 0x03,
++ .ufcon = 0x51,
++ },
++ [1] = {
++ .hwport = 1,
++ .flags = 0,
++ .ucon = 0x3c5,
++ .ulcon = 0x03,
++ .ufcon = 0x51,
++ },
++ [2] = {
++ .hwport = 2,
++ .flags = 0,
++ .ucon = 0x3c5,
++ .ulcon = 0x03,
++ .ufcon = 0x51,
++ }
++};
++
++static struct mtd_partition vstms_nand_part[] = {
++ [0] = {
++ .name = "Boot Agent",
++ .size = 0x7C000,
++ .offset = 0,
++ },
++ [1] = {
++ .name = "UBoot Config",
++ .offset = 0x7C000,
++ .size = 0x4000,
++ },
++ [2] = {
++ .name = "Kernel",
++ .offset = 0x80000,
++ .size = 0x200000,
++ },
++ [3] = {
++ .name = "RFS",
++ .offset = 0x280000,
++ .size = 0x3d80000,
++ },
++};
++
++static struct s3c2410_nand_set vstms_nand_sets[] = {
++ [0] = {
++ .name = "NAND",
++ .nr_chips = 1,
++ .nr_partitions = ARRAY_SIZE(vstms_nand_part),
++ .partitions = vstms_nand_part,
++ },
++};
++
++/* choose a set of timings which should suit most 512Mbit
++ * chips and beyond.
++*/
++
++static struct s3c2410_platform_nand vstms_nand_info = {
++ .tacls = 20,
++ .twrph0 = 60,
++ .twrph1 = 20,
++ .nr_sets = ARRAY_SIZE(vstms_nand_sets),
++ .sets = vstms_nand_sets,
++};
++
++static struct platform_device *vstms_devices[] __initdata = {
++ &s3c_device_usb,
++ &s3c_device_wdt,
++ &s3c_device_i2c,
++ &s3c_device_iis,
++ &s3c_device_rtc,
++ &s3c_device_nand,
++};
++
++static struct s3c24xx_board vstms_board __initdata = {
++ .devices = vstms_devices,
++ .devices_count = ARRAY_SIZE(vstms_devices)
++};
++
++static void __init vstms_fixup(struct machine_desc *desc,
++ struct tag *tags, char **cmdline,
++ struct meminfo *mi)
++{
++ if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
++ mi->nr_banks=1;
++ mi->bank[0].start = 0x30000000;
++ mi->bank[0].size = SZ_64M;
++ mi->bank[0].node = 0;
++ }
++}
++
++static void __init vstms_map_io(void)
++{
++ s3c_device_nand.dev.platform_data = &vstms_nand_info;
++
++ s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
++ s3c24xx_init_clocks(12000000);
++ s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
++ s3c24xx_set_board(&vstms_board);
++}
++
++MACHINE_START(VSTMS, "VSTMS")
++ .phys_io = S3C2410_PA_UART,
++ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
++ .boot_params = S3C2410_SDRAM_PA + 0x100,
++
++ .fixup = vstms_fixup,
++ .init_irq = s3c24xx_init_irq,
++ .map_io = vstms_map_io,
++ .timer = &s3c24xx_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
+index 7b24456..42cd05e 100644
+--- a/arch/arm/mach-s3c2410/pm-simtec.c
++++ b/arch/arm/mach-s3c2410/pm-simtec.c
+@@ -49,7 +49,8 @@ static __init int pm_simtec_init(void)
+ /* check which machine we are running on */
+
+ if (!machine_is_bast() && !machine_is_vr1000() &&
+- !machine_is_anubis() && !machine_is_osiris())
++ !machine_is_anubis() && !machine_is_osiris() &&
++ !machine_is_aml_m5900())
+ return 0;
+
+ printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
+diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
+index a589fe7..b49a0b3 100644
+--- a/arch/arm/mach-s3c2410/pm.c
++++ b/arch/arm/mach-s3c2410/pm.c
+@@ -1,9 +1,9 @@
+ /* linux/arch/arm/mach-s3c2410/pm.c
+ *
+- * Copyright (c) 2004 Simtec Electronics
++ * Copyright (c) 2004,2006 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+ *
+- * S3C2410 Power Manager (Suspend-To-RAM) support
++ * S3C24XX Power Manager (Suspend-To-RAM) support
+ *
+ * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
+ *
+@@ -24,9 +24,6 @@
+ * Parts based on arch/arm/mach-pxa/pm.c
+ *
+ * Thanks to Dimitry Andric for debugging
+- *
+- * Modifications:
+- * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART
+ */
+
+ #include <linux/init.h>
+@@ -38,6 +35,7 @@
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+
++#include <asm/cacheflush.h>
+ #include <asm/hardware.h>
+ #include <asm/io.h>
+
+@@ -55,14 +53,6 @@
+
+ unsigned long s3c_pm_flags;
+
+-/* cache functions from arch/arm/mm/proc-arm920.S */
+-
+-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+-extern void arm920_flush_kern_cache_all(void);
+-#else
+-static void arm920_flush_kern_cache_all(void) { }
+-#endif
+-
+ #define PFX "s3c24xx-pm: "
+
+ static struct sleep_save core_save[] = {
+@@ -92,19 +82,6 @@ static struct sleep_save core_save[] = {
+ SAVE_ITEM(S3C2410_REFRESH),
+ };
+
+-/* this lot should be really saved by the IRQ code */
+-static struct sleep_save irq_save[] = {
+- SAVE_ITEM(S3C2410_EXTINT0),
+- SAVE_ITEM(S3C2410_EXTINT1),
+- SAVE_ITEM(S3C2410_EXTINT2),
+- SAVE_ITEM(S3C2410_EINFLT0),
+- SAVE_ITEM(S3C2410_EINFLT1),
+- SAVE_ITEM(S3C2410_EINFLT2),
+- SAVE_ITEM(S3C2410_EINFLT3),
+- SAVE_ITEM(S3C2410_EINTMASK),
+- SAVE_ITEM(S3C2410_INTMSK)
+-};
+-
+ static struct sleep_save gpio_save[] = {
+ SAVE_ITEM(S3C2410_GPACON),
+ SAVE_ITEM(S3C2410_GPADAT),
+@@ -165,7 +142,7 @@ static struct sleep_save uart_save[] = {
+
+ extern void printascii(const char *);
+
+-static void pm_dbg(const char *fmt, ...)
++void pm_dbg(const char *fmt, ...)
+ {
+ va_list va;
+ char buff[256];
+@@ -509,6 +486,9 @@ static void s3c2410_pm_configure_extint(
+ }
+ }
+
++void (*pm_cpu_prep)(void);
++void (*pm_cpu_sleep)(void);
++
+ #define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
+
+ /* s3c2410_pm_enter
+@@ -519,7 +499,6 @@ static void s3c2410_pm_configure_extint(
+ static int s3c2410_pm_enter(suspend_state_t state)
+ {
+ unsigned long regs_save[16];
+- unsigned long tmp;
+
+ /* ensure the debug is initialised (if enabled) */
+
+@@ -527,6 +506,11 @@ static int s3c2410_pm_enter(suspend_stat
+
+ DBG("s3c2410_pm_enter(%d)\n", state);
+
++ if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
++ printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
++ return -EINVAL;
++ }
++
+ if (state != PM_SUSPEND_MEM) {
+ printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
+ return -EINVAL;
+@@ -554,17 +538,9 @@ static int s3c2410_pm_enter(suspend_stat
+
+ DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
+
+- /* ensure at least GESTATUS3 has the resume address */
+-
+- __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
+-
+- DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
+- DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
+-
+ /* save all necessary core registers not covered by the drivers */
+
+ s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
+- s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+ s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
+ s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
+
+@@ -581,10 +557,16 @@ static int s3c2410_pm_enter(suspend_stat
+ /* ack any outstanding external interrupts before we go to sleep */
+
+ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
++ __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
++ __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
++
++ /* call cpu specific preperation */
++
++ pm_cpu_prep();
+
+ /* flush cache back to ram */
+
+- arm920_flush_kern_cache_all();
++ flush_cache_all();
+
+ s3c2410_pm_check_store();
+
+@@ -592,23 +574,23 @@ static int s3c2410_pm_enter(suspend_stat
+
+ __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
+
+- s3c2410_cpu_suspend(regs_save);
++ /* s3c2410_cpu_save will also act as our return point from when
++ * we resume as it saves its own register state, so use the return
++ * code to differentiate return from save and return from sleep */
++
++ if (s3c2410_cpu_save(regs_save) == 0) {
++ flush_cache_all();
++ pm_cpu_sleep();
++ }
+
+ /* restore the cpu state */
+
+ cpu_init();
+
+- /* unset the return-from-sleep flag, to ensure reset */
+-
+- tmp = __raw_readl(S3C2410_GSTATUS2);
+- tmp &= S3C2410_GSTATUS2_OFFRESET;
+- __raw_writel(tmp, S3C2410_GSTATUS2);
+-
+ /* restore the system state */
+
+ s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+ s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
+- s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+ s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
+
+ s3c2410_pm_debug_init();
+diff --git a/arch/arm/mach-s3c2410/pm.h b/arch/arm/mach-s3c2410/pm.h
+index 7a5e714..ffe197a 100644
+--- a/arch/arm/mach-s3c2410/pm.h
++++ b/arch/arm/mach-s3c2410/pm.h
+@@ -34,13 +34,19 @@ extern unsigned long s3c_irqwake_eintmas
+ extern unsigned long s3c_irqwake_intallow;
+ extern unsigned long s3c_irqwake_eintallow;
+
++/* per-cpu sleep functions */
++
++extern void (*pm_cpu_prep)(void);
++extern void (*pm_cpu_sleep)(void);
++
+ /* Flags for PM Control */
+
+ extern unsigned long s3c_pm_flags;
+
+ /* from sleep.S */
+
+-extern void s3c2410_cpu_suspend(unsigned long *saveblk);
++extern int s3c2410_cpu_save(unsigned long *saveblk);
++extern void s3c2410_cpu_suspend(void);
+ extern void s3c2410_cpu_resume(void);
+
+ extern unsigned long s3c2410_sleep_save_phys;
+@@ -57,3 +63,11 @@ struct sleep_save {
+
+ extern void s3c2410_pm_do_save(struct sleep_save *ptr, int count);
+ extern void s3c2410_pm_do_restore(struct sleep_save *ptr, int count);
++
++#ifdef CONFIG_PM
++extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state);
++extern int s3c24xx_irq_resume(struct sys_device *dev);
++#else
++#define s3c24xx_irq_suspend NULL
++#define s3c24xx_irq_resume NULL
++#endif
+diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2410/s3c2400-gpio.c
+index f2a7817..1576d01 100644
+--- a/arch/arm/mach-s3c2410/s3c2400-gpio.c
++++ b/arch/arm/mach-s3c2410/s3c2400-gpio.c
+@@ -1,4 +1,4 @@
+-/* linux/arch/arm/mach-s3c2410/gpio.c
++/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c
+ *
+ * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr at gobolinux.org>
+ *
+diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
+index 9971866..00abe19 100644
+--- a/arch/arm/mach-s3c2410/s3c2410-clock.c
++++ b/arch/arm/mach-s3c2410/s3c2410-clock.c
+@@ -1,4 +1,4 @@
+-/* linux/arch/arm/mach-s3c2410/clock.c
++/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c
+new file mode 100644
+index 0000000..51e5098
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2410-dma.c
+@@ -0,0 +1,158 @@
++/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
++ *
++ * (c) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2410 DMA selection
++ *
++ * http://armlinux.simtec.co.uk/
++ *
++ * 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/init.h>
++#include <linux/sysdev.h>
++
++#include <asm/dma.h>
++#include <asm/arch/dma.h>
++#include "dma.h"
++
++#include "cpu.h"
++
++#include <asm/arch/regs-serial.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-ac97.h>
++#include <asm/arch/regs-mem.h>
++#include <asm/arch/regs-lcd.h>
++#include <asm/arch/regs-sdi.h>
++#include <asm/arch/regs-iis.h>
++#include <asm/arch/regs-spi.h>
++
++static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
++ [DMACH_XD0] = {
++ .name = "xdreq0",
++ .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
++ },
++ [DMACH_XD1] = {
++ .name = "xdreq1",
++ .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
++ },
++ [DMACH_SDI] = {
++ .name = "sdi",
++ .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
++ .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_SPI0] = {
++ .name = "spi0",
++ .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
++ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
++ },
++ [DMACH_SPI1] = {
++ .name = "spi1",
++ .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
++ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
++ },
++ [DMACH_UART0] = {
++ .name = "uart0",
++ .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
++ },
++ [DMACH_UART1] = {
++ .name = "uart1",
++ .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
++ },
++ [DMACH_UART2] = {
++ .name = "uart2",
++ .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
++ },
++ [DMACH_TIMER] = {
++ .name = "timer",
++ .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
++ .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
++ },
++ [DMACH_I2S_IN] = {
++ .name = "i2s-sdi",
++ .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
++ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_I2S_OUT] = {
++ .name = "i2s-sdo",
++ .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_USB_EP1] = {
++ .name = "usb-ep1",
++ .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
++ },
++ [DMACH_USB_EP2] = {
++ .name = "usb-ep2",
++ .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
++ },
++ [DMACH_USB_EP3] = {
++ .name = "usb-ep3",
++ .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
++ },
++ [DMACH_USB_EP4] = {
++ .name = "usb-ep4",
++ .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
++ },
++};
++
++static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
++ struct s3c24xx_dma_map *map)
++{
++ chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
++}
++
++static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
++ .select = s3c2410_dma_select,
++ .dcon_mask = 7 << 24,
++ .map = s3c2410_dma_mappings,
++ .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
++};
++
++static int s3c2410_dma_add(struct sys_device *sysdev)
++{
++ return s3c24xx_dma_init_map(&s3c2410_dma_sel);
++}
++
++static struct sysdev_driver s3c2410_dma_driver = {
++ .add = s3c2410_dma_add,
++};
++
++static int __init s3c2410_dma_init(void)
++{
++ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
++}
++
++arch_initcall(s3c2410_dma_init);
++
++/* S3C2442 DMA contains the same selection table as the S3C2410 */
++
++static struct sysdev_driver s3c2442_dma_driver = {
++ .add = s3c2410_dma_add,
++};
++
++static int __init s3c2442_dma_init(void)
++{
++ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
++}
++
++arch_initcall(s3c2442_dma_init);
++
++
+diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
+index 471a714..ec3a276 100644
+--- a/arch/arm/mach-s3c2410/s3c2410-gpio.c
++++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c
+@@ -1,4 +1,4 @@
+-/* linux/arch/arm/mach-s3c2410/gpio.c
++/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+@@ -69,22 +69,3 @@ int s3c2410_gpio_irqfilter(unsigned int
+ }
+
+ EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
+-
+-int s3c2410_gpio_getirq(unsigned int pin)
+-{
+- if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
+- return -1; /* not valid interrupts */
+-
+- if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
+- return -1; /* not valid pin */
+-
+- if (pin < S3C2410_GPF4)
+- return (pin - S3C2410_GPF0) + IRQ_EINT0;
+-
+- if (pin < S3C2410_GPG0)
+- return (pin - S3C2410_GPF4) + IRQ_EINT4;
+-
+- return (pin - S3C2410_GPG0) + IRQ_EINT8;
+-}
+-
+-EXPORT_SYMBOL(s3c2410_gpio_getirq);
+diff --git a/arch/arm/mach-s3c2410/s3c2410-irq.c b/arch/arm/mach-s3c2410/s3c2410-irq.c
+new file mode 100644
+index 0000000..c796c9c
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2410-irq.c
+@@ -0,0 +1,48 @@
++/* linux/arch/arm/mach-s3c2410/s3c2410-irq.c
++ *
++ * Copyright (c) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.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; 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/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/ptrace.h>
++#include <linux/sysdev.h>
++
++#include "cpu.h"
++#include "pm.h"
++
++static int s3c2410_irq_add(struct sys_device *sysdev)
++{
++ return 0;
++}
++
++static struct sysdev_driver s3c2410_irq_driver = {
++ .add = s3c2410_irq_add,
++ .suspend = s3c24xx_irq_suspend,
++ .resume = s3c24xx_irq_resume,
++};
++
++static int s3c2410_irq_init(void)
++{
++ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
++}
++
++arch_initcall(s3c2410_irq_init);
+diff --git a/arch/arm/mach-s3c2410/s3c2410-pm.c b/arch/arm/mach-s3c2410/s3c2410-pm.c
+new file mode 100644
+index 0000000..e51d766
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2410-pm.c
+@@ -0,0 +1,120 @@
++/* linux/arch/arm/mach-s3c2410/s3c2410-pm.c
++ *
++ * Copyright (c) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) 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/init.h>
++#include <linux/suspend.h>
++#include <linux/errno.h>
++#include <linux/time.h>
++#include <linux/sysdev.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++
++#include <asm/mach-types.h>
++
++#include <asm/arch/regs-gpio.h>
++
++#include "cpu.h"
++#include "pm.h"
++
++#ifdef CONFIG_S3C2410_PM_DEBUG
++extern void pm_dbg(const char *fmt, ...);
++#define DBG(fmt...) pm_dbg(fmt)
++#else
++#define DBG(fmt...) printk(KERN_DEBUG fmt)
++#endif
++
++static void s3c2410_pm_prepare(void)
++{
++ /* ensure at least GSTATUS3 has the resume address */
++
++ __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
++
++ DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
++ DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
++
++ if ( machine_is_aml_m5900() )
++ s3c2410_gpio_setpin(S3C2410_GPF2, 1);
++
++}
++
++int s3c2410_pm_resume(struct sys_device *dev)
++{
++ unsigned long tmp;
++
++ /* unset the return-from-sleep flag, to ensure reset */
++
++ tmp = __raw_readl(S3C2410_GSTATUS2);
++ tmp &= S3C2410_GSTATUS2_OFFRESET;
++ __raw_writel(tmp, S3C2410_GSTATUS2);
++
++ if ( machine_is_aml_m5900() )
++ s3c2410_gpio_setpin(S3C2410_GPF2, 0);
++
++ return 0;
++}
++
++static int s3c2410_pm_add(struct sys_device *dev)
++{
++ pm_cpu_prep = s3c2410_pm_prepare;
++ pm_cpu_sleep = s3c2410_cpu_suspend;
++
++ return 0;
++}
++
++static struct sysdev_driver s3c2410_pm_driver = {
++ .add = s3c2410_pm_add,
++ .resume = s3c2410_pm_resume,
++};
++
++/* register ourselves */
++
++static int __init s3c2410_pm_drvinit(void)
++{
++ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
++}
++
++arch_initcall(s3c2410_pm_drvinit);
++
++static struct sysdev_driver s3c2440_pm_driver = {
++ .add = s3c2410_pm_add,
++ .resume = s3c2410_pm_resume,
++};
++
++static int __init s3c2440_pm_drvinit(void)
++{
++ return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
++}
++
++arch_initcall(s3c2440_pm_drvinit);
++
++static struct sysdev_driver s3c2442_pm_driver = {
++ .add = s3c2410_pm_add,
++ .resume = s3c2410_pm_resume,
++};
++
++static int __init s3c2442_pm_drvinit(void)
++{
++ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
++}
++
++arch_initcall(s3c2442_pm_drvinit);
+diff --git a/arch/arm/mach-s3c2410/s3c2410-sleep.S b/arch/arm/mach-s3c2410/s3c2410-sleep.S
+new file mode 100644
+index 0000000..9179a10
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2410-sleep.S
+@@ -0,0 +1,68 @@
++/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
++ *
++ * Copyright (c) 2004 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2410 Power Manager (Suspend-To-RAM) support
++ *
++ * Based on PXA/SA1100 sleep code by:
++ * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
++ * Cliff Brake, (c) 2001
++ *
++ * 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/linkage.h>
++#include <asm/assembler.h>
++#include <asm/hardware.h>
++#include <asm/arch/map.h>
++
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-clock.h>
++#include <asm/arch/regs-mem.h>
++#include <asm/arch/regs-serial.h>
++
++ /* s3c2410_cpu_suspend
++ *
++ * put the cpu into sleep mode
++ */
++
++ENTRY(s3c2410_cpu_suspend)
++ @@ prepare cpu to sleep
++
++ ldr r4, =S3C2410_REFRESH
++ ldr r5, =S3C24XX_MISCCR
++ ldr r6, =S3C2410_CLKCON
++ ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
++ ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
++ ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
++
++ orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
++ orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
++ orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
++
++ teq pc, #0 @ first as a trial-run to load cache
++ bl s3c2410_do_sleep
++ teq r0, r0 @ now do it for real
++ b s3c2410_do_sleep @
++
++ @@ align next bit of code to cache line
++ .align 8
++s3c2410_do_sleep:
++ streq r7, [ r4 ] @ SDRAM sleep command
++ streq r8, [ r5 ] @ SDRAM power-down config
++ streq r9, [ r6 ] @ CPU sleep
++1: beq 1b
++ mov pc, r14
+diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
+index a110cff..183e403 100644
+--- a/arch/arm/mach-s3c2410/s3c2410.c
++++ b/arch/arm/mach-s3c2410/s3c2410.c
+@@ -8,17 +8,6 @@
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+- *
+- * Modifications:
+- * 16-May-2003 BJD Created initial version
+- * 16-Aug-2003 BJD Fixed header files and copyright, added URL
+- * 05-Sep-2003 BJD Moved to kernel v2.6
+- * 18-Jan-2004 BJD Added serial port configuration
+- * 21-Aug-2004 BJD Added new struct s3c2410_board handler
+- * 28-Sep-2004 BJD Updates for new serial port bits
+- * 04-Nov-2004 BJD Updated UART configuration process
+- * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
+- * 13-Aug-2005 DA Removed UART from initial I/O mappings
+ */
+
+ #include <linux/kernel.h>
+diff --git a/arch/arm/mach-s3c2410/s3c2412-dma.c b/arch/arm/mach-s3c2410/s3c2412-dma.c
+new file mode 100644
+index 0000000..171f370
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2412-dma.c
+@@ -0,0 +1,160 @@
++/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c
++ *
++ * (c) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2412 DMA selection
++ *
++ * http://armlinux.simtec.co.uk/
++ *
++ * 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/init.h>
++#include <linux/sysdev.h>
++
++#include <asm/dma.h>
++#include <asm/arch/dma.h>
++#include <asm/io.h>
++
++#include "dma.h"
++#include "cpu.h"
++
++#include <asm/arch/regs-serial.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-ac97.h>
++#include <asm/arch/regs-mem.h>
++#include <asm/arch/regs-lcd.h>
++#include <asm/arch/regs-sdi.h>
++#include <asm/arch/regs-iis.h>
++#include <asm/arch/regs-spi.h>
++
++#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
++
++static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
++ [DMACH_XD0] = {
++ .name = "xdreq0",
++ .channels = MAP(S3C2412_DMAREQSEL_XDREQ0),
++ },
++ [DMACH_XD1] = {
++ .name = "xdreq1",
++ .channels = MAP(S3C2412_DMAREQSEL_XDREQ1),
++ },
++ [DMACH_SDI] = {
++ .name = "sdi",
++ .channels = MAP(S3C2412_DMAREQSEL_SDI),
++ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_SPI0] = {
++ .name = "spi0",
++ .channels = MAP(S3C2412_DMAREQSEL_SPI0TX),
++ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
++ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
++ },
++ [DMACH_SPI1] = {
++ .name = "spi1",
++ .channels = MAP(S3C2412_DMAREQSEL_SPI1TX),
++ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
++ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
++ },
++ [DMACH_UART0] = {
++ .name = "uart0",
++ .channels = MAP(S3C2412_DMAREQSEL_UART0_0),
++ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
++ },
++ [DMACH_UART1] = {
++ .name = "uart1",
++ .channels = MAP(S3C2412_DMAREQSEL_UART1_0),
++ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
++ },
++ [DMACH_UART2] = {
++ .name = "uart2",
++ .channels = MAP(S3C2412_DMAREQSEL_UART2_0),
++ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
++ },
++ [DMACH_UART0_SRC2] = {
++ .name = "uart0",
++ .channels = MAP(S3C2412_DMAREQSEL_UART0_1),
++ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
++ },
++ [DMACH_UART1_SRC2] = {
++ .name = "uart1",
++ .channels = MAP(S3C2412_DMAREQSEL_UART1_1),
++ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
++ },
++ [DMACH_UART2_SRC2] = {
++ .name = "uart2",
++ .channels = MAP(S3C2412_DMAREQSEL_UART2_1),
++ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
++ },
++ [DMACH_TIMER] = {
++ .name = "timer",
++ .channels = MAP(S3C2412_DMAREQSEL_TIMER),
++ },
++ [DMACH_I2S_IN] = {
++ .name = "i2s-sdi",
++ .channels = MAP(S3C2412_DMAREQSEL_I2SRX),
++ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_I2S_OUT] = {
++ .name = "i2s-sdo",
++ .channels = MAP(S3C2412_DMAREQSEL_I2STX),
++ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_USB_EP1] = {
++ .name = "usb-ep1",
++ .channels = MAP(S3C2412_DMAREQSEL_USBEP1),
++ },
++ [DMACH_USB_EP2] = {
++ .name = "usb-ep2",
++ .channels = MAP(S3C2412_DMAREQSEL_USBEP2),
++ },
++ [DMACH_USB_EP3] = {
++ .name = "usb-ep3",
++ .channels = MAP(S3C2412_DMAREQSEL_USBEP3),
++ },
++ [DMACH_USB_EP4] = {
++ .name = "usb-ep4",
++ .channels = MAP(S3C2412_DMAREQSEL_USBEP4),
++ },
++};
++
++static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
++ struct s3c24xx_dma_map *map)
++{
++ writel(chan->regs + S3C2412_DMA_DMAREQSEL,
++ map->channels[0] | S3C2412_DMAREQSEL_HW);
++}
++
++static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
++ .select = s3c2412_dma_select,
++ .dcon_mask = 0,
++ .map = s3c2412_dma_mappings,
++ .map_size = ARRAY_SIZE(s3c2412_dma_mappings),
++};
++
++static int s3c2412_dma_add(struct sys_device *sysdev)
++{
++ return s3c24xx_dma_init_map(&s3c2412_dma_sel);
++}
++
++static struct sysdev_driver s3c2412_dma_driver = {
++ .add = s3c2412_dma_add,
++};
++
++static int __init s3c2412_dma_init(void)
++{
++ return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_dma_driver);
++}
++
++arch_initcall(s3c2412_dma_init);
+diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2410/s3c2412-irq.c
+index c80ec93..7f74154 100644
+--- a/arch/arm/mach-s3c2410/s3c2412-irq.c
++++ b/arch/arm/mach-s3c2410/s3c2412-irq.c
+@@ -37,6 +37,7 @@
+
+ #include "cpu.h"
+ #include "irq.h"
++#include "pm.h"
+
+ /* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
+ * having them turn up in both the INT* and the EINT* registers. Whilst
+@@ -120,6 +121,8 @@ static int s3c2412_irq_add(struct sys_de
+
+ static struct sysdev_driver s3c2412_irq_driver = {
+ .add = s3c2412_irq_add,
++ .suspend = s3c24xx_irq_suspend,
++ .resume = s3c24xx_irq_resume,
+ };
+
+ static int s3c2412_irq_init(void)
+diff --git a/arch/arm/mach-s3c2410/s3c2412-pm.c b/arch/arm/mach-s3c2410/s3c2412-pm.c
+new file mode 100644
+index 0000000..19b6332
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2412-pm.c
+@@ -0,0 +1,128 @@
++/* linux/arch/arm/mach-s3c2410/s3c2412-pm.c
++ *
++ * Copyright (c) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * http://armlinux.simtec.co.uk/.
++ *
++ * 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/sysdev.h>
++#include <linux/platform_device.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/arch/regs-power.h>
++#include <asm/arch/regs-gpioj.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-dsc.h>
++
++#include "cpu.h"
++#include "pm.h"
++
++#include "s3c2412.h"
++
++static void s3c2412_cpu_suspend(void)
++{
++ unsigned long tmp;
++
++ /* set our standby method to sleep */
++
++ tmp = __raw_readl(S3C2412_PWRCFG);
++ tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
++ __raw_writel(tmp, S3C2412_PWRCFG);
++
++ /* issue the standby signal into the pm unit. Note, we
++ * issue a write-buffer drain just in case */
++
++ tmp = 0;
++
++ asm("b 1f\n\t"
++ ".align 5\n\t"
++ "1:\n\t"
++ "mcr p15, 0, %0, c7, c10, 4\n\t"
++ "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
++
++ /* we should never get past here */
++
++ panic("sleep resumed to originator?");
++}
++
++static void s3c2412_pm_prepare(void)
++{
++}
++
++static int s3c2412_pm_add(struct sys_device *sysdev)
++{
++ pm_cpu_prep = s3c2412_pm_prepare;
++ pm_cpu_sleep = s3c2412_cpu_suspend;
++
++ return 0;
++}
++
++static struct sleep_save s3c2412_sleep[] = {
++ SAVE_ITEM(S3C2412_DSC0),
++ SAVE_ITEM(S3C2412_DSC1),
++ SAVE_ITEM(S3C2413_GPJDAT),
++ SAVE_ITEM(S3C2413_GPJCON),
++ SAVE_ITEM(S3C2413_GPJUP),
++
++ /* save the PWRCFG to get back to original sleep method */
++
++ SAVE_ITEM(S3C2412_PWRCFG),
++
++ /* save the sleep configuration anyway, just in case these
++ * get damaged during wakeup */
++
++ SAVE_ITEM(S3C2412_GPBSLPCON),
++ SAVE_ITEM(S3C2412_GPCSLPCON),
++ SAVE_ITEM(S3C2412_GPDSLPCON),
++ SAVE_ITEM(S3C2412_GPESLPCON),
++ SAVE_ITEM(S3C2412_GPFSLPCON),
++ SAVE_ITEM(S3C2412_GPGSLPCON),
++ SAVE_ITEM(S3C2412_GPHSLPCON),
++ SAVE_ITEM(S3C2413_GPJSLPCON),
++};
++
++static int s3c2412_pm_suspend(struct sys_device *dev, pm_message_t state)
++{
++ s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
++ return 0;
++}
++
++static int s3c2412_pm_resume(struct sys_device *dev)
++{
++ unsigned long tmp;
++
++ tmp = __raw_readl(S3C2412_PWRCFG);
++ tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
++ tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
++ __raw_writel(tmp, S3C2412_PWRCFG);
++
++ s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
++ return 0;
++}
++
++static struct sysdev_driver s3c2412_pm_driver = {
++ .add = s3c2412_pm_add,
++ .suspend = s3c2412_pm_suspend,
++ .resume = s3c2412_pm_resume,
++};
++
++static __init int s3c2412_pm_init(void)
++{
++ return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver);
++}
++
++arch_initcall(s3c2412_pm_init);
+diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c
+index 2d163f7..e76431c 100644
+--- a/arch/arm/mach-s3c2410/s3c2412.c
++++ b/arch/arm/mach-s3c2410/s3c2412.c
+@@ -8,17 +8,6 @@
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+- *
+- * Modifications:
+- * 16-May-2003 BJD Created initial version
+- * 16-Aug-2003 BJD Fixed header files and copyright, added URL
+- * 05-Sep-2003 BJD Moved to kernel v2.6
+- * 18-Jan-2004 BJD Added serial port configuration
+- * 21-Aug-2004 BJD Added new struct s3c2410_board handler
+- * 28-Sep-2004 BJD Updates for new serial port bits
+- * 04-Nov-2004 BJD Updated UART configuration process
+- * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
+- * 13-Aug-2005 DA Removed UART from initial I/O mappings
+ */
+
+ #include <linux/kernel.h>
+@@ -56,6 +45,13 @@
+
+ #ifndef CONFIG_CPU_S3C2412_ONLY
+ void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
++
++static inline void s3c2412_init_gpio2(void)
++{
++ s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
++}
++#else
++#define s3c2412_init_gpio2() do { } while(0)
+ #endif
+
+ /* Initial IO mappings */
+@@ -76,6 +72,7 @@ void __init s3c2412_init_uarts(struct s3
+
+ /* rename devices that are s3c2412/s3c2413 specific */
+ s3c_device_sdi.name = "s3c2412-sdi";
++ s3c_device_lcd.name = "s3c2412-lcd";
+ s3c_device_nand.name = "s3c2412-nand";
+ }
+
+@@ -110,7 +107,7 @@ void __init s3c2412_map_io(struct map_de
+ {
+ /* move base of IO */
+
+- s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
++ s3c2412_init_gpio2();
+
+ /* set our idle function */
+
+@@ -161,48 +158,8 @@ void __init s3c2412_init_clocks(int xtal
+ * as a driver which may support both 2410 and 2440 may try and use it.
+ */
+
+-#ifdef CONFIG_PM
+-static struct sleep_save s3c2412_sleep[] = {
+- SAVE_ITEM(S3C2412_DSC0),
+- SAVE_ITEM(S3C2412_DSC1),
+- SAVE_ITEM(S3C2413_GPJDAT),
+- SAVE_ITEM(S3C2413_GPJCON),
+- SAVE_ITEM(S3C2413_GPJUP),
+-
+- /* save the sleep configuration anyway, just in case these
+- * get damaged during wakeup */
+-
+- SAVE_ITEM(S3C2412_GPBSLPCON),
+- SAVE_ITEM(S3C2412_GPCSLPCON),
+- SAVE_ITEM(S3C2412_GPDSLPCON),
+- SAVE_ITEM(S3C2412_GPESLPCON),
+- SAVE_ITEM(S3C2412_GPFSLPCON),
+- SAVE_ITEM(S3C2412_GPGSLPCON),
+- SAVE_ITEM(S3C2412_GPHSLPCON),
+- SAVE_ITEM(S3C2413_GPJSLPCON),
+-};
+-
+-static int s3c2412_suspend(struct sys_device *dev, pm_message_t state)
+-{
+- s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+- return 0;
+-}
+-
+-static int s3c2412_resume(struct sys_device *dev)
+-{
+- s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+- return 0;
+-}
+-
+-#else
+-#define s3c2412_suspend NULL
+-#define s3c2412_resume NULL
+-#endif
+-
+ struct sysdev_class s3c2412_sysclass = {
+ set_kset_name("s3c2412-core"),
+- .suspend = s3c2412_suspend,
+- .resume = s3c2412_resume
+ };
+
+ static int __init s3c2412_core_init(void)
+diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2410/s3c2440-dma.c
+new file mode 100644
+index 0000000..11e109c
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/s3c2440-dma.c
+@@ -0,0 +1,164 @@
++/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c
++ *
++ * (c) 2006 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2440 DMA selection
++ *
++ * http://armlinux.simtec.co.uk/
++ *
++ * 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/init.h>
++#include <linux/sysdev.h>
++
++#include <asm/dma.h>
++#include <asm/arch/dma.h>
++#include "dma.h"
++
++#include "cpu.h"
++
++#include <asm/arch/regs-serial.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-ac97.h>
++#include <asm/arch/regs-mem.h>
++#include <asm/arch/regs-lcd.h>
++#include <asm/arch/regs-sdi.h>
++#include <asm/arch/regs-iis.h>
++#include <asm/arch/regs-spi.h>
++
++static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
++ [DMACH_XD0] = {
++ .name = "xdreq0",
++ .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
++ },
++ [DMACH_XD1] = {
++ .name = "xdreq1",
++ .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
++ },
++ [DMACH_SDI] = {
++ .name = "sdi",
++ .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
++ .channels[1] = S3C2440_DCON_CH1_SDI | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
++ .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_SPI0] = {
++ .name = "spi0",
++ .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
++ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
++ },
++ [DMACH_SPI1] = {
++ .name = "spi1",
++ .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
++ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
++ },
++ [DMACH_UART0] = {
++ .name = "uart0",
++ .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
++ },
++ [DMACH_UART1] = {
++ .name = "uart1",
++ .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
++ },
++ [DMACH_UART2] = {
++ .name = "uart2",
++ .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
++ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
++ },
++ [DMACH_TIMER] = {
++ .name = "timer",
++ .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
++ .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
++ },
++ [DMACH_I2S_IN] = {
++ .name = "i2s-sdi",
++ .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
++ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_I2S_OUT] = {
++ .name = "i2s-sdo",
++ .channels[0] = S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID,
++ .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
++ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
++ },
++ [DMACH_PCM_IN] = {
++ .name = "pcm-in",
++ .channels[0] = S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID,
++ .channels[2] = S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID,
++ .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
++ },
++ [DMACH_PCM_OUT] = {
++ .name = "pcm-out",
++ .channels[1] = S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID,
++ .channels[3] = S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID,
++ .hw_addr.to = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
++ },
++ [DMACH_MIC_IN] = {
++ .name = "mic-in",
++ .channels[2] = S3C2440_DCON_CH2_MICIN | DMA_CH_VALID,
++ .channels[3] = S3C2440_DCON_CH3_MICIN | DMA_CH_VALID,
++ .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
++ },
++ [DMACH_USB_EP1] = {
++ .name = "usb-ep1",
++ .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
++ },
++ [DMACH_USB_EP2] = {
++ .name = "usb-ep2",
++ .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
++ },
++ [DMACH_USB_EP3] = {
++ .name = "usb-ep3",
++ .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
++ },
++ [DMACH_USB_EP4] = {
++ .name = "usb-ep4",
++ .channels[3] = S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
++ },
++};
++
++static void s3c2440_dma_select(struct s3c2410_dma_chan *chan,
++ struct s3c24xx_dma_map *map)
++{
++ chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
++}
++
++static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
++ .select = s3c2440_dma_select,
++ .dcon_mask = 7 << 24,
++ .map = s3c2440_dma_mappings,
++ .map_size = ARRAY_SIZE(s3c2440_dma_mappings),
++};
++
++static int s3c2440_dma_add(struct sys_device *sysdev)
++{
++ return s3c24xx_dma_init_map(&s3c2440_dma_sel);
++}
++
++static struct sysdev_driver s3c2440_dma_driver = {
++ .add = s3c2440_dma_add,
++};
++
++static int __init s3c2440_dma_init(void)
++{
++ return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_dma_driver);
++}
++
++arch_initcall(s3c2440_dma_init);
++
+diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c
+index 16fa2a3..c92ea66 100644
+--- a/arch/arm/mach-s3c2410/s3c2440-dsc.c
++++ b/arch/arm/mach-s3c2410/s3c2440-dsc.c
+@@ -8,11 +8,6 @@
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+- *
+- * Modifications:
+- * 29-Aug-2004 BJD Start of drive-strength control
+- * 09-Nov-2004 BJD Added symbol export
+- * 11-Jan-2005 BJD Include fix
+ */
+
+ #include <linux/kernel.h>
+diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2410/s3c2440-irq.c
+index 1667ba1..39db075 100644
+--- a/arch/arm/mach-s3c2410/s3c2440-irq.c
++++ b/arch/arm/mach-s3c2410/s3c2440-irq.c
+@@ -42,8 +42,7 @@
+ /* WDT/AC97 */
+
+ static void s3c_irq_demux_wdtac97(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ unsigned int subsrc, submsk;
+ struct irqdesc *mydesc;
+@@ -61,11 +60,11 @@ static void s3c_irq_demux_wdtac97(unsign
+ if (subsrc != 0) {
+ if (subsrc & 1) {
+ mydesc = irq_desc + IRQ_S3C2440_WDT;
+- desc_handle_irq(IRQ_S3C2440_WDT, mydesc, regs);
++ desc_handle_irq(IRQ_S3C2440_WDT, mydesc);
+ }
+ if (subsrc & 2) {
+ mydesc = irq_desc + IRQ_S3C2440_AC97;
+- desc_handle_irq(IRQ_S3C2440_AC97, mydesc, regs);
++ desc_handle_irq(IRQ_S3C2440_AC97, mydesc);
+ }
+ }
+ }
+@@ -119,7 +118,7 @@ static int s3c2440_irq_add(struct sys_de
+ }
+
+ static struct sysdev_driver s3c2440_irq_driver = {
+- .add = s3c2440_irq_add,
++ .add = s3c2440_irq_add,
+ };
+
+ static int s3c2440_irq_init(void)
+diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2410/s3c2442.c
+index debae24..581667e 100644
+--- a/arch/arm/mach-s3c2410/s3c2442.c
++++ b/arch/arm/mach-s3c2410/s3c2442.c
+@@ -1,4 +1,4 @@
+-/* linux/arch/arm/mach-s3c2410/s3c2440.c
++/* linux/arch/arm/mach-s3c2410/s3c2442.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/mach-s3c2410/s3c244x-irq.c
+index 44c5aff..146f210 100644
+--- a/arch/arm/mach-s3c2410/s3c244x-irq.c
++++ b/arch/arm/mach-s3c2410/s3c244x-irq.c
+@@ -1,4 +1,4 @@
+-/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
++/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+@@ -42,8 +42,7 @@
+ /* camera irq */
+
+ static void s3c_irq_demux_cam(unsigned int irq,
+- struct irqdesc *desc,
+- struct pt_regs *regs)
++ struct irqdesc *desc)
+ {
+ unsigned int subsrc, submsk;
+ struct irqdesc *mydesc;
+@@ -61,11 +60,11 @@ static void s3c_irq_demux_cam(unsigned i
+ if (subsrc != 0) {
+ if (subsrc & 1) {
+ mydesc = irq_desc + IRQ_S3C2440_CAM_C;
+- desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
++ desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc);
+ }
+ if (subsrc & 2) {
+ mydesc = irq_desc + IRQ_S3C2440_CAM_P;
+- desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
++ desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc);
+ }
+ }
+ }
+@@ -120,7 +119,9 @@ static int s3c244x_irq_add(struct sys_de
+ }
+
+ static struct sysdev_driver s3c2440_irq_driver = {
+- .add = s3c244x_irq_add,
++ .add = s3c244x_irq_add,
++ .suspend = s3c24xx_irq_suspend,
++ .resume = s3c24xx_irq_resume,
+ };
+
+ static int s3c2440_irq_init(void)
+@@ -131,9 +132,12 @@ static int s3c2440_irq_init(void)
+ arch_initcall(s3c2440_irq_init);
+
+ static struct sysdev_driver s3c2442_irq_driver = {
+- .add = s3c244x_irq_add,
++ .add = s3c244x_irq_add,
++ .suspend = s3c24xx_irq_suspend,
++ .resume = s3c24xx_irq_resume,
+ };
+
++
+ static int s3c2442_irq_init(void)
+ {
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_irq_driver);
+diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/mach-s3c2410/s3c244x.h
+index 3e7f5f7..1488c1e 100644
+--- a/arch/arm/mach-s3c2410/s3c244x.h
++++ b/arch/arm/mach-s3c2410/s3c244x.h
+@@ -1,4 +1,4 @@
+-/* arch/arm/mach-s3c2410/s3c2440.h
++/* arch/arm/mach-s3c2410/s3c244x.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
+index a7561a7..2018c2e 100644
+--- a/arch/arm/mach-s3c2410/sleep.S
++++ b/arch/arm/mach-s3c2410/sleep.S
+@@ -41,15 +41,25 @@
+
+ .text
+
+- /* s3c2410_cpu_suspend
++ /* s3c2410_cpu_save
+ *
+- * put the cpu into sleep mode
++ * save enough of the CPU state to allow us to re-start
++ * pm.c code. as we store items like the sp/lr, we will
++ * end up returning from this function when the cpu resumes
++ * so the return value is set to mark this.
++ *
++ * This arangement means we avoid having to flush the cache
++ * from this code.
+ *
+ * entry:
+- * r0 = sleep save block
++ * r0 = pointer to save block
++ *
++ * exit:
++ * r0 = 0 => we stored everything
++ * 1 => resumed from sleep
+ */
+
+-ENTRY(s3c2410_cpu_suspend)
++ENTRY(s3c2410_cpu_save)
+ stmfd sp!, { r4 - r12, lr }
+
+ @@ store co-processor registers
+@@ -62,44 +72,14 @@ ENTRY(s3c2410_cpu_suspend)
+
+ stmia r0, { r4 - r13 }
+
+- @@ flush the caches to ensure everything is back out to
+- @@ SDRAM before the core powers down
+-
+-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+- bl arm920_flush_kern_cache_all
+-#endif
+-
+- @@ prepare cpu to sleep
+-
+- ldr r4, =S3C2410_REFRESH
+- ldr r5, =S3C24XX_MISCCR
+- ldr r6, =S3C2410_CLKCON
+- ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
+- ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
+- ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
+-
+- orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
+- orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
+- orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
+-
+- teq pc, #0 @ first as a trial-run to load cache
+- bl s3c2410_do_sleep
+- teq r0, r0 @ now do it for real
+- b s3c2410_do_sleep @
+-
+- @@ align next bit of code to cache line
+- .align 8
+-s3c2410_do_sleep:
+- streq r7, [ r4 ] @ SDRAM sleep command
+- streq r8, [ r5 ] @ SDRAM power-down config
+- streq r9, [ r6 ] @ CPU sleep
+-1: beq 1b
+- mov pc, r14
++ mov r0, #0
++ ldmfd sp, { r4 - r12, pc }
+
+ @@ return to the caller, after having the MMU
+ @@ turned on, this restores the last bits from the
+ @@ stack
+ resume_with_mmu:
++ mov r0, #1
+ ldmfd sp!, { r4 - r12, pc }
+
+ .ltorg
+diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c
+index 00d1cfc..9910bf0 100644
+--- a/arch/arm/mach-s3c2410/time.c
++++ b/arch/arm/mach-s3c2410/time.c
+@@ -128,10 +128,10 @@ static unsigned long s3c2410_gettimeoffs
+ * IRQ handler for the timer
+ */
+ static irqreturn_t
+-s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++s3c2410_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
+index 6b22d8f..22b0e1c 100644
+--- a/arch/arm/mach-s3c2410/usb-simtec.c
++++ b/arch/arm/mach-s3c2410/usb-simtec.c
+@@ -10,12 +10,6 @@
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+- *
+- * Modifications:
+- * 14-Sep-2004 BJD Created
+- * 18-Oct-2004 BJD Cleanups, and added code to report OC cleared
+- * 09-Aug-2005 BJD Renamed s3c2410_report_oc to s3c2410_usb_report_oc
+- * 09-Aug-2005 BJD Ports powered only if both are enabled
+ */
+
+ #define DEBUG
+@@ -64,7 +58,7 @@ usb_simtec_powercontrol(int port, int to
+ }
+
+ static irqreturn_t
+-usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs)
++usb_simtec_ocirq(int irq, void *pw)
+ {
+ struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;
+
+diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
+index 92c0cc8..d8aa612 100644
+--- a/arch/arm/mach-s3c2410/usb-simtec.h
++++ b/arch/arm/mach-s3c2410/usb-simtec.h
+@@ -1,4 +1,4 @@
+-/* linux/arch/arm/mach-s3c2410/usb-simtec.c
++/* linux/arch/arm/mach-s3c2410/usb-simtec.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
+index a0dfa39..6496eb6 100644
+--- a/arch/arm/mach-sa1100/collie.c
++++ b/arch/arm/mach-sa1100/collie.c
+@@ -91,30 +91,29 @@ static struct mcp_plat_data collie_mcp_d
+ /*
+ * low-level UART features.
+ */
+-static struct locomo_dev *uart_dev = NULL;
++struct platform_device collie_locomo_device;
+
+ static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+ {
+- if (!uart_dev) return;
+-
+ if (mctrl & TIOCM_RTS)
+- locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 0);
++ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0);
+ else
+- locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 1);
++ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1);
+
+ if (mctrl & TIOCM_DTR)
+- locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 0);
++ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0);
+ else
+- locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 1);
++ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1);
+ }
+
+ static u_int collie_uart_get_mctrl(struct uart_port *port)
+ {
+ int ret = TIOCM_CD;
+ unsigned int r;
+- if (!uart_dev) return ret;
+
+- r = locomo_gpio_read_output(uart_dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
++ r = locomo_gpio_read_output(&collie_locomo_device.dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
++ if (r == -ENODEV)
++ return ret;
+ if (r & LOCOMO_GPIO_CTS)
+ ret |= TIOCM_CTS;
+ if (r & LOCOMO_GPIO_DSR)
+@@ -130,13 +129,11 @@ static struct sa1100_port_fns collie_por
+
+ static int collie_uart_probe(struct locomo_dev *dev)
+ {
+- uart_dev = dev;
+ return 0;
+ }
+
+ static int collie_uart_remove(struct locomo_dev *dev)
+ {
+- uart_dev = NULL;
+ return 0;
+ }
+
+@@ -170,7 +167,7 @@ static struct resource locomo_resources[
+ },
+ };
+
+-static struct platform_device locomo_device = {
++struct platform_device collie_locomo_device = {
+ .name = "locomo",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(locomo_resources),
+@@ -178,7 +175,7 @@ static struct platform_device locomo_dev
+ };
+
+ static struct platform_device *devices[] __initdata = {
+- &locomo_device,
++ &collie_locomo_device,
+ &colliescoop_device,
+ };
+
+diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
+index 6395977..78f4c13 100644
+--- a/arch/arm/mach-sa1100/cpu-sa1110.c
++++ b/arch/arm/mach-sa1100/cpu-sa1110.c
+@@ -82,6 +82,14 @@ static struct sdram_params sdram_tbl[] _
+ .twr = 9,
+ .refresh = 64000,
+ .cas_latency = 3,
++ }, { /* Samsung K4S281632B-1H */
++ .name = "K4S281632B-1H",
++ .rows = 12,
++ .tck = 10,
++ .trp = 20,
++ .twr = 10,
++ .refresh = 64000,
++ .cas_latency = 3,
+ }, { /* Samsung KM416S4030CT */
+ .name = "KM416S4030CT",
+ .rows = 13,
+@@ -366,6 +374,8 @@ static int __init sa1110_clk_init(void)
+
+ if (machine_is_h3100())
+ name = "KM416S4030CT";
++ if (machine_is_jornada720())
++ name = "K4S281632B-1H";
+ }
+
+ sdram = sa1110_find_sdram(name);
+diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
+index 3c6441d..1fbe053 100644
+--- a/arch/arm/mach-sa1100/dma.c
++++ b/arch/arm/mach-sa1100/dma.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/arm/kernel/dma-sa1100.c
++ * arch/arm/mach-sa1100/dma.c
+ *
+ * Support functions for the SA11x0 internal DMA channels.
+ *
+@@ -42,7 +42,7 @@ static sa1100_dma_t dma_chan[SA1100_DMA_
+ static spinlock_t dma_list_lock;
+
+
+-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+ {
+ dma_regs_t *dma_regs = dev_id;
+ sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
+diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
+index 7364478..fa6dc71 100644
+--- a/arch/arm/mach-sa1100/h3600.c
++++ b/arch/arm/mach-sa1100/h3600.c
+@@ -702,7 +702,7 @@ static u32 gpio_irq_mask[] = {
+ GPIO2_SD_CON_SLT,
+ };
+
+-static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc)
+ {
+ int i;
+
+@@ -719,14 +719,14 @@ static void h3800_IRQ_demux(unsigned int
+ if (0) printk("%s KPIO 0x%08X\n", __FUNCTION__, irq);
+ for (j = 0; j < H3800_KPIO_IRQ_COUNT; j++)
+ if (irq & kpio_irq_mask[j])
+- do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j, regs);
++ do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j);
+
+ /* GPIO2 */
+ irq = H3800_ASIC2_GPIINTFLAG;
+ if (0) printk("%s GPIO 0x%08X\n", __FUNCTION__, irq);
+ for (j = 0; j < H3800_GPIO_IRQ_COUNT; j++)
+ if (irq & gpio_irq_mask[j])
+- do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j , regs);
++ do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j);
+ }
+
+ if (i >= MAX_ASIC_ISR_LOOPS)
+diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
+index b55b90a..f4c6322 100644
+--- a/arch/arm/mach-sa1100/irq.c
++++ b/arch/arm/mach-sa1100/irq.c
+@@ -110,8 +110,7 @@ static struct irq_chip sa1100_low_gpio_c
+ * and call the handler.
+ */
+ static void
+-sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int mask;
+
+@@ -128,7 +127,7 @@ sa1100_high_gpio_handler(unsigned int ir
+ mask >>= 11;
+ do {
+ if (mask & 1)
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ mask >>= 1;
+ irq++;
+ desc++;
+diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
+index af6d277..354d5e9 100644
+--- a/arch/arm/mach-sa1100/neponset.c
++++ b/arch/arm/mach-sa1100/neponset.c
+@@ -29,7 +29,7 @@
+ * is rather unfortunate.
+ */
+ static void
+-neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++neponset_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned int irr;
+
+@@ -69,12 +69,12 @@ neponset_irq_handler(unsigned int irq, s
+
+ if (irr & IRR_ETHERNET) {
+ d = irq_desc + IRQ_NEPONSET_SMC9196;
+- desc_handle_irq(IRQ_NEPONSET_SMC9196, d, regs);
++ desc_handle_irq(IRQ_NEPONSET_SMC9196, d);
+ }
+
+ if (irr & IRR_USAR) {
+ d = irq_desc + IRQ_NEPONSET_USAR;
+- desc_handle_irq(IRQ_NEPONSET_USAR, d, regs);
++ desc_handle_irq(IRQ_NEPONSET_USAR, d);
+ }
+
+ desc->chip->unmask(irq);
+@@ -82,7 +82,7 @@ neponset_irq_handler(unsigned int irq, s
+
+ if (irr & IRR_SA1111) {
+ d = irq_desc + IRQ_NEPONSET_SA1111;
+- desc_handle_irq(IRQ_NEPONSET_SA1111, d, regs);
++ desc_handle_irq(IRQ_NEPONSET_SA1111, d);
+ }
+ }
+ }
+diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
+index 5eba5fb..59703c6 100644
+--- a/arch/arm/mach-sa1100/ssp.c
++++ b/arch/arm/mach-sa1100/ssp.c
+@@ -25,7 +25,7 @@
+
+ #define TIMEOUT 100000
+
+-static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+ {
+ unsigned int status = Ser4SSSR;
+
+diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
+index 49ae716..4284bd6 100644
+--- a/arch/arm/mach-sa1100/time.c
++++ b/arch/arm/mach-sa1100/time.c
+@@ -77,7 +77,7 @@ static int match_posponed;
+ #endif
+
+ static irqreturn_t
+-sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++sa1100_timer_interrupt(int irq, void *dev_id)
+ {
+ unsigned int next_match;
+
+@@ -99,7 +99,7 @@ sa1100_timer_interrupt(int irq, void *de
+ * handlers.
+ */
+ do {
+- timer_tick(regs);
++ timer_tick();
+ OSSR = OSSR_M0; /* Clear match on timer 0 */
+ next_match = (OSMR0 += LATCH);
+ } while ((signed long)(next_match - OSCR) <= 0);
+@@ -151,13 +151,13 @@ static void sa1100_dyn_tick_reprogram(un
+ }
+
+ static irqreturn_t
+-sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
++sa1100_dyn_tick_handler(int irq, void *dev_id)
+ {
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ if ((signed long)(initial_match - OSCR) <= 0)
+- return sa1100_timer_interrupt(irq, dev_id, regs);
++ return sa1100_timer_interrupt(irq, dev_id);
+ }
+ return IRQ_NONE;
+ }
+diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
+index 1095df3..0e480fa 100644
+--- a/arch/arm/mach-shark/core.c
++++ b/arch/arm/mach-shark/core.c
+@@ -80,10 +80,10 @@ static void __init shark_map_io(void)
+ #define HZ_TIME ((1193180 + HZ/2) / HZ)
+
+ static irqreturn_t
+-shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++shark_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+- timer_tick(regs);
++ timer_tick();
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c
+index b227052..297ecf1 100644
+--- a/arch/arm/mach-shark/irq.c
++++ b/arch/arm/mach-shark/irq.c
+@@ -61,7 +61,7 @@ static void shark_enable_8259A_irq(unsig
+
+ static void shark_ack_8259A_irq(unsigned int irq){}
+
+-static irqreturn_t bogus_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bogus_int(int irq, void *dev_id)
+ {
+ printk("Got interrupt %i!\n",irq);
+ return IRQ_NONE;
+diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
+index 7cd86d3..5386a81 100644
+--- a/arch/arm/mach-shark/leds.c
++++ b/arch/arm/mach-shark/leds.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/arm/kernel/leds-shark.c
++ * arch/arm/mach-shark/leds.c
+ * by Alexander Schulz
+ *
+ * derived from:
+diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
+index f2bbef0..3b85761 100644
+--- a/arch/arm/mach-versatile/core.c
++++ b/arch/arm/mach-versatile/core.c
+@@ -77,12 +77,12 @@ static struct irq_chip sic_chip = {
+ };
+
+ static void
+-sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++sic_handle_irq(unsigned int irq, struct irqdesc *desc)
+ {
+ unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS);
+
+ if (status == 0) {
+- do_bad_IRQ(irq, desc, regs);
++ do_bad_IRQ(irq, desc);
+ return;
+ }
+
+@@ -93,7 +93,7 @@ sic_handle_irq(unsigned int irq, struct
+ irq += IRQ_SIC_START;
+
+ desc = irq_desc + irq;
+- desc_handle_irq(irq, desc, regs);
++ desc_handle_irq(irq, desc);
+ } while (status);
+ }
+
+@@ -188,12 +188,12 @@ static struct map_desc versatile_io_desc
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+- .virtual = VERSATILE_PCI_VIRT_BASE,
++ .virtual = (unsigned long)VERSATILE_PCI_VIRT_BASE,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_BASE),
+ .length = VERSATILE_PCI_BASE_SIZE,
+ .type = MT_DEVICE
+ }, {
+- .virtual = VERSATILE_PCI_CFG_VIRT_BASE,
++ .virtual = (unsigned long)VERSATILE_PCI_CFG_VIRT_BASE,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
+ .length = VERSATILE_PCI_CFG_BASE_SIZE,
+ .type = MT_DEVICE
+@@ -851,14 +851,14 @@ static unsigned long versatile_gettimeof
+ /*
+ * IRQ handler for the timer
+ */
+-static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
+ {
+ write_seqlock(&xtime_lock);
+
+ // ...clear the interrupt
+ writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
+
+- timer_tick(regs);
++ timer_tick();
+
+ write_sequnlock(&xtime_lock);
+
+diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
+index 41b3700..5cd0b5d 100644
+--- a/arch/arm/mach-versatile/pci.c
++++ b/arch/arm/mach-versatile/pci.c
+@@ -40,14 +40,15 @@
+ * Cfg 42000000 - 42FFFFFF PCI config
+ *
+ */
+-#define SYS_PCICTL IO_ADDRESS(VERSATILE_SYS_PCICTL)
+-#define PCI_IMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
+-#define PCI_IMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
+-#define PCI_IMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
+-#define PCI_SMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
+-#define PCI_SMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
+-#define PCI_SMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
+-#define PCI_SELFID IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
++#define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n))
++#define SYS_PCICTL __IO_ADDRESS(VERSATILE_SYS_PCICTL)
++#define PCI_IMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
++#define PCI_IMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
++#define PCI_IMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
++#define PCI_SMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
++#define PCI_SMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
++#define PCI_SMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
++#define PCI_SELFID __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
+
+ #define DEVICE_ID_OFFSET 0x00
+ #define CSR_OFFSET 0x04
+@@ -76,7 +77,7 @@ static int __init versatile_pci_slot_ign
+ __setup("pci_slot_ignore=", versatile_pci_slot_ignore);
+
+
+-static unsigned long __pci_addr(struct pci_bus *bus,
++static void __iomem *__pci_addr(struct pci_bus *bus,
+ unsigned int devfn, int offset)
+ {
+ unsigned int busnr = bus->number;
+@@ -91,14 +92,14 @@ static unsigned long __pci_addr(struct p
+ if (devfn > 255)
+ BUG();
+
+- return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) |
++ return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) |
+ (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset);
+ }
+
+ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *val)
+ {
+- unsigned long addr = __pci_addr(bus, devfn, where);
++ void __iomem *addr = __pci_addr(bus, devfn, where & ~3);
+ u32 v;
+ int slot = PCI_SLOT(devfn);
+
+@@ -117,18 +118,16 @@ static int versatile_read_config(struct
+ } else {
+ switch (size) {
+ case 1:
+- addr &= ~3;
+ v = __raw_readb(addr);
+ break;
+
+ case 2:
+- v = __raw_readl(addr & ~3);
+- if (addr & 2) v >>= 16;
++ v = __raw_readl(addr);
++ if (where & 2) v >>= 16;
+ v &= 0xffff;
+ break;
+
+ default:
+- addr &= ~3;
+ v = __raw_readl(addr);
+ break;
+ }
+@@ -141,7 +140,7 @@ static int versatile_read_config(struct
+ static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+ {
+- unsigned long addr = __pci_addr(bus, devfn, where);
++ void __iomem *addr = __pci_addr(bus, devfn, where);
+ int slot = PCI_SLOT(devfn);
+
+ if (pci_slot_ignore & (1 << slot)) {
+@@ -280,7 +279,7 @@ int __init pci_versatile_setup(int nr, s
+ printk("PCI core found (slot %d)\n",myslot);
+
+ __raw_writel(myslot, PCI_SELFID);
+- local_pci_cfg_base = (void *) VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
++ local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
+
+ val = __raw_readl(local_pci_cfg_base + CSR_OFFSET);
+ val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index b4f220d..c0bfb82 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -15,6 +15,7 @@ config CPU_ARM610
+ select CPU_32v3
+ select CPU_CACHE_V3
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V3 if MMU
+ select CPU_TLB_V3 if MMU
+ help
+@@ -24,6 +25,20 @@ config CPU_ARM610
+ Say Y if you want support for the ARM610 processor.
+ Otherwise, say N.
+
++# ARM7TDMI
++config CPU_ARM7TDMI
++ bool "Support ARM7TDMI processor"
++ depends on !MMU
++ select CPU_32v4T
++ select CPU_ABRT_LV4T
++ select CPU_CACHE_V4
++ help
++ A 32-bit RISC microprocessor based on the ARM7 processor core
++ which has no memory control unit and cache.
++
++ Say Y if you want support for the ARM7TDMI processor.
++ Otherwise, say N.
++
+ # ARM710
+ config CPU_ARM710
+ bool "Support ARM710 processor" if !ARCH_CLPS7500 && ARCH_RPC
+@@ -31,6 +46,7 @@ config CPU_ARM710
+ select CPU_32v3
+ select CPU_CACHE_V3
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V3 if MMU
+ select CPU_TLB_V3 if MMU
+ help
+@@ -50,6 +66,7 @@ config CPU_ARM720T
+ select CPU_ABRT_LV4T
+ select CPU_CACHE_V4
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WT if MMU
+ select CPU_TLB_V4WT if MMU
+ help
+@@ -59,6 +76,36 @@ config CPU_ARM720T
+ Say Y if you want support for the ARM720T processor.
+ Otherwise, say N.
+
++# ARM740T
++config CPU_ARM740T
++ bool "Support ARM740T processor" if ARCH_INTEGRATOR
++ depends on !MMU
++ select CPU_32v4T
++ select CPU_ABRT_LV4T
++ select CPU_CACHE_V3 # although the core is v4t
++ select CPU_CP15_MPU
++ help
++ A 32-bit RISC processor with 8KB cache or 4KB variants,
++ write buffer and MPU(Protection Unit) built around
++ an ARM7TDMI core.
++
++ Say Y if you want support for the ARM740T processor.
++ Otherwise, say N.
++
++# ARM9TDMI
++config CPU_ARM9TDMI
++ bool "Support ARM9TDMI processor"
++ depends on !MMU
++ select CPU_32v4T
++ select CPU_ABRT_NOMMU
++ select CPU_CACHE_V4
++ help
++ A 32-bit RISC microprocessor based on the ARM9 processor core
++ which has no memory control unit and cache.
++
++ Say Y if you want support for the ARM9TDMI processor.
++ Otherwise, say N.
++
+ # ARM920T
+ config CPU_ARM920T
+ bool "Support ARM920T processor"
+@@ -68,6 +115,7 @@ config CPU_ARM920T
+ select CPU_ABRT_EV4T
+ select CPU_CACHE_V4WT
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -89,6 +137,7 @@ config CPU_ARM922T
+ select CPU_ABRT_EV4T
+ select CPU_CACHE_V4WT
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -108,6 +157,7 @@ config CPU_ARM925T
+ select CPU_ABRT_EV4T
+ select CPU_CACHE_V4WT
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -126,6 +176,7 @@ config CPU_ARM926T
+ select CPU_32v5
+ select CPU_ABRT_EV5TJ
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -136,6 +187,39 @@ config CPU_ARM926T
+ Say Y if you want support for the ARM926T processor.
+ Otherwise, say N.
+
++# ARM940T
++config CPU_ARM940T
++ bool "Support ARM940T processor" if ARCH_INTEGRATOR
++ depends on !MMU
++ select CPU_32v4T
++ select CPU_ABRT_NOMMU
++ select CPU_CACHE_VIVT
++ select CPU_CP15_MPU
++ help
++ ARM940T is a member of the ARM9TDMI family of general-
++ purpose microprocessors with MPU and seperate 4KB
++ instruction and 4KB data cases, each with a 4-word line
++ length.
++
++ Say Y if you want support for the ARM940T processor.
++ Otherwise, say N.
++
++# ARM946E-S
++config CPU_ARM946E
++ bool "Support ARM946E-S processor" if ARCH_INTEGRATOR
++ depends on !MMU
++ select CPU_32v5
++ select CPU_ABRT_NOMMU
++ select CPU_CACHE_VIVT
++ select CPU_CP15_MPU
++ help
++ ARM946E-S is a member of the ARM9E-S family of high-
++ performance, 32-bit system-on-chip processor solutions.
++ The TCM and ARMv5TE 32-bit instruction set is supported.
++
++ Say Y if you want support for the ARM946E-S processor.
++ Otherwise, say N.
++
+ # ARM1020 - needs validating
+ config CPU_ARM1020
+ bool "Support ARM1020T (rev 0) processor"
+@@ -144,6 +228,7 @@ config CPU_ARM1020
+ select CPU_ABRT_EV4T
+ select CPU_CACHE_V4WT
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -161,6 +246,7 @@ config CPU_ARM1020E
+ select CPU_ABRT_EV4T
+ select CPU_CACHE_V4WT
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WBI if MMU
+ depends on n
+@@ -172,6 +258,7 @@ config CPU_ARM1022
+ select CPU_32v5
+ select CPU_ABRT_EV4T
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU # can probably do better
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -189,6 +276,7 @@ config CPU_ARM1026
+ select CPU_32v5
+ select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU # can probably do better
+ select CPU_TLB_V4WBI if MMU
+ help
+@@ -207,6 +295,7 @@ config CPU_SA110
+ select CPU_ABRT_EV4
+ select CPU_CACHE_V4WB
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_COPY_V4WB if MMU
+ select CPU_TLB_V4WB if MMU
+ help
+@@ -227,16 +316,18 @@ config CPU_SA1100
+ select CPU_ABRT_EV4
+ select CPU_CACHE_V4WB
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_TLB_V4WB if MMU
+
+ # XScale
+ config CPU_XSCALE
+ bool
+- depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000
++ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000
+ default y
+ select CPU_32v5
+ select CPU_ABRT_EV5T
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_TLB_V4WBI if MMU
+
+ # XScale Core Version 3
+@@ -247,6 +338,7 @@ config CPU_XSC3
+ select CPU_32v5
+ select CPU_ABRT_EV5T
+ select CPU_CACHE_VIVT
++ select CPU_CP15_MMU
+ select CPU_TLB_V4WBI if MMU
+ select IO_36
+
+@@ -258,6 +350,7 @@ config CPU_V6
+ select CPU_ABRT_EV6
+ select CPU_CACHE_V6
+ select CPU_CACHE_VIPT
++ select CPU_CP15_MMU
+ select CPU_COPY_V6 if MMU
+ select CPU_TLB_V6 if MMU
+
+@@ -299,6 +392,9 @@ config CPU_32v6
+ bool
+
+ # The abort model
++config CPU_ABRT_NOMMU
++ bool
++
+ config CPU_ABRT_EV4
+ bool
+
+@@ -380,6 +476,23 @@ config CPU_TLB_V6
+
+ endif
+
++config CPU_CP15
++ bool
++ help
++ Processor has the CP15 register.
++
++config CPU_CP15_MMU
++ bool
++ select CPU_CP15
++ help
++ Processor has the CP15 register, which has MMU related registers.
++
++config CPU_CP15_MPU
++ bool
++ select CPU_CP15
++ help
++ Processor has the CP15 register, which has MPU related registers.
++
+ #
+ # CPU supports 36-bit I/O
+ #
+@@ -390,7 +503,7 @@ comment "Processor Features"
+
+ config ARM_THUMB
+ bool "Support Thumb user binaries"
+- depends on CPU_ARM720T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6
++ depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6
+ default y
+ help
+ Say Y if you want to include kernel support for running user space
+@@ -411,23 +524,48 @@ config CPU_BIG_ENDIAN
+ port must properly enable any big-endian related features
+ of your chipset/board/processor.
+
++config CPU_HIGH_VECTOR
++ depends !MMU && CPU_CP15 && !CPU_ARM740T
++ bool "Select the High exception vector"
++ default n
++ help
++ Say Y here to select high exception vector(0xFFFF0000~).
++ The exception vector can be vary depending on the platform
++ design in nommu mode. If your platform needs to select
++ high exception vector, say Y.
++ Otherwise or if you are unsure, say N, and the low exception
++ vector (0x00000000~) will be used.
++
+ config CPU_ICACHE_DISABLE
+- bool "Disable I-Cache"
+- depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6
++ bool "Disable I-Cache (I-bit)"
++ depends on CPU_CP15 && !(CPU_ARM610 || CPU_ARM710 || CPU_ARM720T || CPU_ARM740T || CPU_XSCALE || CPU_XSC3)
+ help
+ Say Y here to disable the processor instruction cache. Unless
+ you have a reason not to or are unsure, say N.
+
+ config CPU_DCACHE_DISABLE
+- bool "Disable D-Cache"
+- depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6
++ bool "Disable D-Cache (C-bit)"
++ depends on CPU_CP15
+ help
+ Say Y here to disable the processor data cache. Unless
+ you have a reason not to or are unsure, say N.
+
++config CPU_DCACHE_SIZE
++ hex
++ depends on CPU_ARM740T || CPU_ARM946E
++ default 0x00001000 if CPU_ARM740T
++ default 0x00002000 # default size for ARM946E-S
++ help
++ Some cores are synthesizable to have various sized cache. For
++ ARM946E-S case, it can vary from 0KB to 1MB.
++ To support such cache operations, it is efficient to know the size
++ before compile time.
++ If your SoC is configured to have a different size, define the value
++ here with proper conditions.
++
+ config CPU_DCACHE_WRITETHROUGH
+ bool "Force write through D-cache"
+- depends on (CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE
++ depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE
+ default y if CPU_ARM925T
+ help
+ Say Y here to use the data cache in writethrough mode. Unless you
+@@ -435,7 +573,7 @@ config CPU_DCACHE_WRITETHROUGH
+
+ config CPU_CACHE_ROUND_ROBIN
+ bool "Round robin I and D cache replacement algorithm"
+- depends on (CPU_ARM926T || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
++ depends on (CPU_ARM926T || CPU_ARM946E || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
+ help
+ Say Y here to use the predictable round-robin cache replacement
+ policy. Unless you specifically require this or are unsure, say N.
+diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
+index 21a2770..d2f5672 100644
+--- a/arch/arm/mm/Makefile
++++ b/arch/arm/mm/Makefile
+@@ -6,7 +6,7 @@ obj-y := consistent.o extable.o fault
+ iomap.o
+
+ obj-$(CONFIG_MMU) += fault-armv.o flush.o ioremap.o mmap.o \
+- mm-armv.o
++ pgd.o mmu.o
+
+ ifneq ($(CONFIG_MMU),y)
+ obj-y += nommu.o
+@@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
+ obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
+ obj-$(CONFIG_DISCONTIGMEM) += discontig.o
+
++obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
+ obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
+ obj-$(CONFIG_CPU_ABRT_EV4T) += abort-ev4t.o
+ obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o
+@@ -33,7 +34,7 @@ obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
+ obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
+ obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
+ obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o
+-obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o mmu.o
++obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o context.o
+ obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o
+ obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
+ obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o
+@@ -46,11 +47,16 @@ obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
+
+ obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
+ obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
++obj-$(CONFIG_CPU_ARM7TDMI) += proc-arm7tdmi.o
+ obj-$(CONFIG_CPU_ARM720T) += proc-arm720.o
++obj-$(CONFIG_CPU_ARM740T) += proc-arm740.o
++obj-$(CONFIG_CPU_ARM9TDMI) += proc-arm9tdmi.o
+ obj-$(CONFIG_CPU_ARM920T) += proc-arm920.o
+ obj-$(CONFIG_CPU_ARM922T) += proc-arm922.o
+ obj-$(CONFIG_CPU_ARM925T) += proc-arm925.o
+ obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o
++obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o
++obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o
+ obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o
+ obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o
+ obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o
+diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S
+index db743e5..9fb7b0e 100644
+--- a/arch/arm/mm/abort-lv4t.S
++++ b/arch/arm/mm/abort-lv4t.S
+@@ -19,11 +19,16 @@
+ */
+ ENTRY(v4t_late_abort)
+ tst r3, #PSR_T_BIT @ check for thumb mode
++#ifdef CONFIG_CPU_CP15_MMU
+ mrc p15, 0, r1, c5, c0, 0 @ get FSR
+ mrc p15, 0, r0, c6, c0, 0 @ get FAR
++ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
++#else
++ mov r0, #0 @ clear r0, r1 (no FSR/FAR)
++ mov r1, #0
++#endif
+ bne .data_thumb_abort
+ ldr r8, [r2] @ read arm instruction
+- bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
+ tst r8, #1 << 20 @ L = 1 -> write?
+ orreq r1, r1, #1 << 11 @ yes.
+ and r7, r8, #15 << 24
+diff --git a/arch/arm/mm/abort-nommu.S b/arch/arm/mm/abort-nommu.S
+new file mode 100644
+index 0000000..a7cc7f9
+--- /dev/null
++++ b/arch/arm/mm/abort-nommu.S
+@@ -0,0 +1,19 @@
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++/*
++ * Function: nommu_early_abort
++ *
++ * Params : r2 = address of aborted instruction
++ * : r3 = saved SPSR
++ *
++ * Returns : r0 = 0 (abort address)
++ * : r1 = 0 (FSR)
++ *
++ * Note: There is no FSR/FAR on !CPU_CP15_MMU cores.
++ * Just fill zero into the registers.
++ */
++ .align 5
++ENTRY(nommu_early_abort)
++ mov r0, #0 @ clear r0, r1 (no FSR/FAR)
++ mov r1, #0
++ mov pc, lr
+diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
+index e0d21bb..aa109f0 100644
+--- a/arch/arm/mm/alignment.c
++++ b/arch/arm/mm/alignment.c
+@@ -735,7 +735,7 @@ do_alignment(unsigned long addr, unsigne
+ /*
+ * We got a fault - fix it up, or die.
+ */
+- do_bad_area(current, current->mm, addr, fsr, regs);
++ do_bad_area(addr, fsr, regs);
+ return 0;
+
+ swp:
+diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
+index b8ad5d5..b290806 100644
+--- a/arch/arm/mm/cache-v4.S
++++ b/arch/arm/mm/cache-v4.S
+@@ -29,9 +29,13 @@ ENTRY(v4_flush_user_cache_all)
+ * Clean and invalidate the entire cache.
+ */
+ ENTRY(v4_flush_kern_cache_all)
++#ifdef CPU_CP15
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
+ mov pc, lr
++#else
++ /* FALLTHROUGH */
++#endif
+
+ /*
+ * flush_user_cache_range(start, end, flags)
+@@ -44,9 +48,13 @@ ENTRY(v4_flush_kern_cache_all)
+ * - flags - vma_area_struct flags describing address space
+ */
+ ENTRY(v4_flush_user_cache_range)
++#ifdef CPU_CP15
+ mov ip, #0
+ mcreq p15, 0, ip, c7, c7, 0 @ flush ID cache
+ mov pc, lr
++#else
++ /* FALLTHROUGH */
++#endif
+
+ /*
+ * coherent_kern_range(start, end)
+@@ -108,8 +116,10 @@ ENTRY(v4_dma_inv_range)
+ * - end - virtual end address
+ */
+ ENTRY(v4_dma_flush_range)
++#ifdef CPU_CP15
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
++#endif
+ /* FALLTHROUGH */
+
+ /*
+diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
+new file mode 100644
+index 0000000..79e8002
+--- /dev/null
++++ b/arch/arm/mm/context.c
+@@ -0,0 +1,45 @@
++/*
++ * linux/arch/arm/mm/context.c
++ *
++ * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++
++#include <asm/mmu_context.h>
++#include <asm/tlbflush.h>
++
++unsigned int cpu_last_asid = { 1 << ASID_BITS };
++
++/*
++ * We fork()ed a process, and we need a new context for the child
++ * to run in. We reserve version 0 for initial tasks so we will
++ * always allocate an ASID.
++ */
++void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++ mm->context.id = 0;
++}
++
++void __new_context(struct mm_struct *mm)
++{
++ unsigned int asid;
++
++ asid = ++cpu_last_asid;
++ if (asid == 0)
++ asid = cpu_last_asid = 1 << ASID_BITS;
++
++ /*
++ * If we've used up all our ASIDs, we need
++ * to start a new version and flush the TLB.
++ */
++ if ((asid & ~ASID_MASK) == 0)
++ flush_tlb_all();
++
++ mm->context.id = asid;
++}
+diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
+index fc69dcc..df1645e 100644
+--- a/arch/arm/mm/copypage-v4mc.c
++++ b/arch/arm/mm/copypage-v4mc.c
+@@ -20,6 +20,8 @@
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
+
++#include "mm.h"
++
+ /*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+@@ -27,8 +29,6 @@
+ #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
+ L_PTE_CACHEABLE)
+
+-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
+-
+ static DEFINE_SPINLOCK(minicache_lock);
+
+ /*
+diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
+index 269ce69..3d0d3a9 100644
+--- a/arch/arm/mm/copypage-v6.c
++++ b/arch/arm/mm/copypage-v6.c
+@@ -17,6 +17,8 @@
+ #include <asm/tlbflush.h>
+ #include <asm/cacheflush.h>
+
++#include "mm.h"
++
+ #if SHMLBA > 16384
+ #error FIX ME
+ #endif
+@@ -24,8 +26,6 @@
+ #define from_address (0xffff8000)
+ #define to_address (0xffffc000)
+
+-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
+-
+ static DEFINE_SPINLOCK(v6_lock);
+
+ /*
+diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
+index 42a6ee2..84ebe0a 100644
+--- a/arch/arm/mm/copypage-xscale.c
++++ b/arch/arm/mm/copypage-xscale.c
+@@ -20,6 +20,8 @@
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
+
++#include "mm.h"
++
+ /*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+@@ -29,8 +31,6 @@
+ #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
+ L_PTE_CACHEABLE)
+
+-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
+-
+ static DEFINE_SPINLOCK(minicache_lock);
+
+ /*
+diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
+index c5e0622..5e658a8 100644
+--- a/arch/arm/mm/fault.c
++++ b/arch/arm/mm/fault.c
+@@ -131,10 +131,11 @@ __do_user_fault(struct task_struct *tsk,
+ force_sig_info(sig, &si, tsk);
+ }
+
+-void
+-do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
+- unsigned int fsr, struct pt_regs *regs)
++void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
++ struct task_struct *tsk = current;
++ struct mm_struct *mm = tsk->active_mm;
++
+ /*
+ * If we are in kernel mode at this point, we
+ * have no context to handle this fault with.
+@@ -170,7 +171,7 @@ good_area:
+ if (fsr & (1 << 11)) /* write? */
+ mask = VM_WRITE;
+ else
+- mask = VM_READ|VM_EXEC;
++ mask = VM_READ|VM_EXEC|VM_WRITE;
+
+ fault = VM_FAULT_BADACCESS;
+ if (!(vma->vm_flags & mask))
+@@ -197,7 +198,7 @@ survive:
+ return fault;
+ }
+
+- if (tsk->pid != 1)
++ if (!is_init(tsk))
+ goto out;
+
+ /*
+@@ -319,7 +320,6 @@ static int
+ do_translation_fault(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
+ {
+- struct task_struct *tsk;
+ unsigned int index;
+ pgd_t *pgd, *pgd_k;
+ pmd_t *pmd, *pmd_k;
+@@ -351,9 +351,7 @@ do_translation_fault(unsigned long addr,
+ return 0;
+
+ bad_area:
+- tsk = current;
+-
+- do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
++ do_bad_area(addr, fsr, regs);
+ return 0;
+ }
+
+@@ -364,8 +362,7 @@ bad_area:
+ static int
+ do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+- struct task_struct *tsk = current;
+- do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
++ do_bad_area(addr, fsr, regs);
+ return 0;
+ }
+
+diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h
+index 73b59e8..49e9e38 100644
+--- a/arch/arm/mm/fault.h
++++ b/arch/arm/mm/fault.h
+@@ -1,6 +1,3 @@
+-void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
+- unsigned long addr, unsigned int fsr, struct pt_regs *regs);
+-
+-void show_pte(struct mm_struct *mm, unsigned long addr);
++void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
+
+ unsigned long search_exception_table(unsigned long addr);
+diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
+index d438ce4..454205b 100644
+--- a/arch/arm/mm/flush.c
++++ b/arch/arm/mm/flush.c
+@@ -15,12 +15,12 @@
+ #include <asm/system.h>
+ #include <asm/tlbflush.h>
+
++#include "mm.h"
++
+ #ifdef CONFIG_CPU_CACHE_VIPT
+
+ #define ALIAS_FLUSH_START 0xffff4000
+
+-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
+-
+ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
+ {
+ unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
+@@ -107,7 +107,7 @@ void flush_ptrace_access(struct vm_area_
+
+ /* VIPT non-aliasing cache */
+ if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask) &&
+- vma->vm_flags | VM_EXEC) {
++ vma->vm_flags & VM_EXEC) {
+ unsigned long addr = (unsigned long)kaddr;
+ /* only flushing the kernel mapping on non-aliasing VIPT */
+ __cpuc_coherent_kern_range(addr, addr + len);
+diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
+index fe3f7f6..b5814b4 100644
+--- a/arch/arm/mm/init.c
++++ b/arch/arm/mm/init.c
+@@ -25,54 +25,58 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+
+-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
++#include "mm.h"
+
+-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+-extern void _stext, _text, _etext, __data_start, _end, __init_begin, __init_end;
++extern void _text, _etext, __data_start, _end, __init_begin, __init_end;
+ extern unsigned long phys_initrd_start;
+ extern unsigned long phys_initrd_size;
+
+ /*
+- * The sole use of this is to pass memory configuration
+- * data from paging_init to mem_init.
++ * This is used to pass memory configuration data from paging_init
++ * to mem_init, and by show_mem() to skip holes in the memory map.
+ */
+-static struct meminfo meminfo __initdata = { 0, };
++static struct meminfo meminfo = { 0, };
+
+-/*
+- * empty_zero_page is a special page that is used for
+- * zero-initialized data and COW.
+- */
+-struct page *empty_zero_page;
++#define for_each_nodebank(iter,mi,no) \
++ for (iter = 0; iter < mi->nr_banks; iter++) \
++ if (mi->bank[iter].node == no)
+
+ void show_mem(void)
+ {
+ int free = 0, total = 0, reserved = 0;
+- int shared = 0, cached = 0, slab = 0, node;
++ int shared = 0, cached = 0, slab = 0, node, i;
++ struct meminfo * mi = &meminfo;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+
+ for_each_online_node(node) {
+- struct page *page, *end;
+-
+- page = NODE_MEM_MAP(node);
+- end = page + NODE_DATA(node)->node_spanned_pages;
+-
+- do {
+- total++;
+- if (PageReserved(page))
+- reserved++;
+- else if (PageSwapCache(page))
+- cached++;
+- else if (PageSlab(page))
+- slab++;
+- else if (!page_count(page))
+- free++;
+- else
+- shared += page_count(page) - 1;
+- page++;
+- } while (page < end);
++ for_each_nodebank (i,mi,node) {
++ unsigned int pfn1, pfn2;
++ struct page *page, *end;
++
++ pfn1 = mi->bank[i].start >> PAGE_SHIFT;
++ pfn2 = (mi->bank[i].size + mi->bank[i].start) >> PAGE_SHIFT;
++
++ page = NODE_MEM_MAP(node) + pfn1;
++ end = NODE_MEM_MAP(node) + pfn2;
++
++ do {
++ total++;
++ if (PageReserved(page))
++ reserved++;
++ else if (PageSwapCache(page))
++ cached++;
++ else if (PageSlab(page))
++ slab++;
++ else if (!page_count(page))
++ free++;
++ else
++ shared += page_count(page) - 1;
++ page++;
++ } while (page < end);
++ }
+ }
+
+ printk("%d pages of RAM\n", total);
+@@ -83,20 +87,6 @@ void show_mem(void)
+ printk("%d pages swap cached\n", cached);
+ }
+
+-static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+-{
+- return pmd_offset(pgd, virt);
+-}
+-
+-static inline pmd_t *pmd_off_k(unsigned long virt)
+-{
+- return pmd_off(pgd_offset_k(virt), virt);
+-}
+-
+-#define for_each_nodebank(iter,mi,no) \
+- for (iter = 0; iter < mi->nr_banks; iter++) \
+- if (mi->bank[iter].node == no)
+-
+ /*
+ * FIXME: We really want to avoid allocating the bootmap bitmap
+ * over the top of the initrd. Hopefully, this is located towards
+@@ -176,62 +166,20 @@ static int __init check_initrd(struct me
+ return initrd_node;
+ }
+
+-/*
+- * Reserve the various regions of node 0
+- */
+-static __init void reserve_node_zero(pg_data_t *pgdat)
++static inline void map_memory_bank(struct membank *bank)
+ {
+- unsigned long res_size = 0;
+-
+- /*
+- * Register the kernel text and data with bootmem.
+- * Note that this can only be in node 0.
+- */
+-#ifdef CONFIG_XIP_KERNEL
+- reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
+-#else
+- reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
+-#endif
+-
+- /*
+- * Reserve the page tables. These are already in use,
+- * and can only be in node 0.
+- */
+- reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
+- PTRS_PER_PGD * sizeof(pgd_t));
+-
+- /*
+- * Hmm... This should go elsewhere, but we really really need to
+- * stop things allocating the low memory; ideally we need a better
+- * implementation of GFP_DMA which does not assume that DMA-able
+- * memory starts at zero.
+- */
+- if (machine_is_integrator() || machine_is_cintegrator())
+- res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
++#ifdef CONFIG_MMU
++ struct map_desc map;
+
+- /*
+- * These should likewise go elsewhere. They pre-reserve the
+- * screen memory region at the start of main system memory.
+- */
+- if (machine_is_edb7211())
+- res_size = 0x00020000;
+- if (machine_is_p720t())
+- res_size = 0x00014000;
++ map.pfn = __phys_to_pfn(bank->start);
++ map.virtual = __phys_to_virt(bank->start);
++ map.length = bank->size;
++ map.type = MT_MEMORY;
+
+-#ifdef CONFIG_SA1111
+- /*
+- * Because of the SA1111 DMA bug, we want to preserve our
+- * precious DMA-able memory...
+- */
+- res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
++ create_mapping(&map);
+ #endif
+- if (res_size)
+- reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
+ }
+
+-void __init build_mem_type_table(void);
+-void __init create_mapping(struct map_desc *md);
+-
+ static unsigned long __init
+ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
+ {
+@@ -248,23 +196,18 @@ bootmem_init_node(int node, int initrd_n
+ * Calculate the pfn range, and map the memory banks for this node.
+ */
+ for_each_nodebank(i, mi, node) {
++ struct membank *bank = &mi->bank[i];
+ unsigned long start, end;
+- struct map_desc map;
+
+- start = mi->bank[i].start >> PAGE_SHIFT;
+- end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT;
++ start = bank->start >> PAGE_SHIFT;
++ end = (bank->start + bank->size) >> PAGE_SHIFT;
+
+ if (start_pfn > start)
+ start_pfn = start;
+ if (end_pfn < end)
+ end_pfn = end;
+
+- map.pfn = __phys_to_pfn(mi->bank[i].start);
+- map.virtual = __phys_to_virt(mi->bank[i].start);
+- map.length = mi->bank[i].size;
+- map.type = MT_MEMORY;
+-
+- create_mapping(&map);
++ map_memory_bank(bank);
+ }
+
+ /*
+@@ -346,9 +289,9 @@ bootmem_init_node(int node, int initrd_n
+ return end_pfn;
+ }
+
+-static void __init bootmem_init(struct meminfo *mi)
++void __init bootmem_init(struct meminfo *mi)
+ {
+- unsigned long addr, memend_pfn = 0;
++ unsigned long memend_pfn = 0;
+ int node, initrd_node, i;
+
+ /*
+@@ -361,26 +304,6 @@ static void __init bootmem_init(struct m
+ memcpy(&meminfo, mi, sizeof(meminfo));
+
+ /*
+- * Clear out all the mappings below the kernel image.
+- */
+- for (addr = 0; addr < MODULE_START; addr += PGDIR_SIZE)
+- pmd_clear(pmd_off_k(addr));
+-#ifdef CONFIG_XIP_KERNEL
+- /* The XIP kernel is mapped in the module area -- skip over it */
+- addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
+-#endif
+- for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
+- pmd_clear(pmd_off_k(addr));
+-
+- /*
+- * Clear out all the kernel space mappings, except for the first
+- * memory bank, up to the end of the vmalloc region.
+- */
+- for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
+- addr < VMALLOC_END; addr += PGDIR_SIZE)
+- pmd_clear(pmd_off_k(addr));
+-
+- /*
+ * Locate which node contains the ramdisk image, if any.
+ */
+ initrd_node = check_initrd(mi);
+@@ -413,114 +336,6 @@ static void __init bootmem_init(struct m
+ max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET;
+ }
+
+-/*
+- * Set up device the mappings. Since we clear out the page tables for all
+- * mappings above VMALLOC_END, we will remove any debug device mappings.
+- * This means you have to be careful how you debug this function, or any
+- * called function. This means you can't use any function or debugging
+- * method which may touch any device, otherwise the kernel _will_ crash.
+- */
+-static void __init devicemaps_init(struct machine_desc *mdesc)
+-{
+- struct map_desc map;
+- unsigned long addr;
+- void *vectors;
+-
+- /*
+- * Allocate the vector page early.
+- */
+- vectors = alloc_bootmem_low_pages(PAGE_SIZE);
+- BUG_ON(!vectors);
+-
+- for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
+- pmd_clear(pmd_off_k(addr));
+-
+- /*
+- * Map the kernel if it is XIP.
+- * It is always first in the modulearea.
+- */
+-#ifdef CONFIG_XIP_KERNEL
+- map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & PGDIR_MASK);
+- map.virtual = MODULE_START;
+- map.length = ((unsigned long)&_etext - map.virtual + ~PGDIR_MASK) & PGDIR_MASK;
+- map.type = MT_ROM;
+- create_mapping(&map);
+-#endif
+-
+- /*
+- * Map the cache flushing regions.
+- */
+-#ifdef FLUSH_BASE
+- map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);
+- map.virtual = FLUSH_BASE;
+- map.length = SZ_1M;
+- map.type = MT_CACHECLEAN;
+- create_mapping(&map);
+-#endif
+-#ifdef FLUSH_BASE_MINICACHE
+- map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M);
+- map.virtual = FLUSH_BASE_MINICACHE;
+- map.length = SZ_1M;
+- map.type = MT_MINICLEAN;
+- create_mapping(&map);
+-#endif
+-
+- /*
+- * Create a mapping for the machine vectors at the high-vectors
+- * location (0xffff0000). If we aren't using high-vectors, also
+- * create a mapping at the low-vectors virtual address.
+- */
+- map.pfn = __phys_to_pfn(virt_to_phys(vectors));
+- map.virtual = 0xffff0000;
+- map.length = PAGE_SIZE;
+- map.type = MT_HIGH_VECTORS;
+- create_mapping(&map);
+-
+- if (!vectors_high()) {
+- map.virtual = 0;
+- map.type = MT_LOW_VECTORS;
+- create_mapping(&map);
+- }
+-
+- /*
+- * Ask the machine support to map in the statically mapped devices.
+- */
+- if (mdesc->map_io)
+- mdesc->map_io();
+-
+- /*
+- * Finally flush the caches and tlb to ensure that we're in a
+- * consistent state wrt the writebuffer. This also ensures that
+- * any write-allocated cache lines in the vector page are written
+- * back. After this point, we can start to touch devices again.
+- */
+- local_flush_tlb_all();
+- flush_cache_all();
+-}
+-
+-/*
+- * paging_init() sets up the page tables, initialises the zone memory
+- * maps, and sets up the zero page, bad page and bad page tables.
+- */
+-void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
+-{
+- void *zero_page;
+-
+- build_mem_type_table();
+- bootmem_init(mi);
+- devicemaps_init(mdesc);
+-
+- top_pmd = pmd_off_k(0xffff0000);
+-
+- /*
+- * allocate the zero page. Note that we count on this going ok.
+- */
+- zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
+- memzero(zero_page, PAGE_SIZE);
+- empty_zero_page = virt_to_page(zero_page);
+- flush_dcache_page(empty_zero_page);
+-}
+-
+ static inline void free_area(unsigned long addr, unsigned long end, char *s)
+ {
+ unsigned int size = (end - addr) >> 10;
+diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
+index 88a999d..4654405 100644
+--- a/arch/arm/mm/ioremap.c
++++ b/arch/arm/mm/ioremap.c
+@@ -177,7 +177,7 @@ static void unmap_area_sections(unsigned
+ * Free the page table, if there was one.
+ */
+ if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
+- pte_free_kernel(pmd_page_kernel(pmd));
++ pte_free_kernel(pmd_page_vaddr(pmd));
+ }
+
+ addr += PGDIR_SIZE;
+@@ -361,14 +361,14 @@ __ioremap(unsigned long phys_addr, size_
+ }
+ EXPORT_SYMBOL(__ioremap);
+
+-void __iounmap(void __iomem *addr)
++void __iounmap(volatile void __iomem *addr)
+ {
+ #ifndef CONFIG_SMP
+ struct vm_struct **p, *tmp;
+ #endif
+ unsigned int section_mapping = 0;
+
+- addr = (void __iomem *)(PAGE_MASK & (unsigned long)addr);
++ addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long)addr);
+
+ #ifndef CONFIG_SMP
+ /*
+@@ -395,6 +395,6 @@ void __iounmap(void __iomem *addr)
+ #endif
+
+ if (!section_mapping)
+- vunmap(addr);
++ vunmap((void __force *)addr);
+ }
+ EXPORT_SYMBOL(__iounmap);
+diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
+deleted file mode 100644
+index 38769f5..0000000
+--- a/arch/arm/mm/mm-armv.c
++++ /dev/null
+@@ -1,663 +0,0 @@
+-/*
+- * linux/arch/arm/mm/mm-armv.c
+- *
+- * Copyright (C) 1998-2005 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.
+- *
+- * Page table sludge for ARM v3 and v4 processor architectures.
+- */
+-#include <linux/module.h>
+-#include <linux/mm.h>
+-#include <linux/init.h>
+-#include <linux/bootmem.h>
+-#include <linux/highmem.h>
+-#include <linux/nodemask.h>
+-
+-#include <asm/pgalloc.h>
+-#include <asm/page.h>
+-#include <asm/setup.h>
+-#include <asm/tlbflush.h>
+-
+-#include <asm/mach/map.h>
+-
+-#define CPOLICY_UNCACHED 0
+-#define CPOLICY_BUFFERED 1
+-#define CPOLICY_WRITETHROUGH 2
+-#define CPOLICY_WRITEBACK 3
+-#define CPOLICY_WRITEALLOC 4
+-
+-static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
+-static unsigned int ecc_mask __initdata = 0;
+-pgprot_t pgprot_kernel;
+-
+-EXPORT_SYMBOL(pgprot_kernel);
+-
+-pmd_t *top_pmd;
+-
+-struct cachepolicy {
+- const char policy[16];
+- unsigned int cr_mask;
+- unsigned int pmd;
+- unsigned int pte;
+-};
+-
+-static struct cachepolicy cache_policies[] __initdata = {
+- {
+- .policy = "uncached",
+- .cr_mask = CR_W|CR_C,
+- .pmd = PMD_SECT_UNCACHED,
+- .pte = 0,
+- }, {
+- .policy = "buffered",
+- .cr_mask = CR_C,
+- .pmd = PMD_SECT_BUFFERED,
+- .pte = PTE_BUFFERABLE,
+- }, {
+- .policy = "writethrough",
+- .cr_mask = 0,
+- .pmd = PMD_SECT_WT,
+- .pte = PTE_CACHEABLE,
+- }, {
+- .policy = "writeback",
+- .cr_mask = 0,
+- .pmd = PMD_SECT_WB,
+- .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
+- }, {
+- .policy = "writealloc",
+- .cr_mask = 0,
+- .pmd = PMD_SECT_WBWA,
+- .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
+- }
+-};
+-
+-/*
+- * These are useful for identifing cache coherency
+- * problems by allowing the cache or the cache and
+- * writebuffer to be turned off. (Note: the write
+- * buffer should not be on and the cache off).
+- */
+-static void __init early_cachepolicy(char **p)
+-{
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
+- int len = strlen(cache_policies[i].policy);
+-
+- if (memcmp(*p, cache_policies[i].policy, len) == 0) {
+- cachepolicy = i;
+- cr_alignment &= ~cache_policies[i].cr_mask;
+- cr_no_alignment &= ~cache_policies[i].cr_mask;
+- *p += len;
+- break;
+- }
+- }
+- if (i == ARRAY_SIZE(cache_policies))
+- printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
+- flush_cache_all();
+- set_cr(cr_alignment);
+-}
+-
+-static void __init early_nocache(char **__unused)
+-{
+- char *p = "buffered";
+- printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
+- early_cachepolicy(&p);
+-}
+-
+-static void __init early_nowrite(char **__unused)
+-{
+- char *p = "uncached";
+- printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
+- early_cachepolicy(&p);
+-}
+-
+-static void __init early_ecc(char **p)
+-{
+- if (memcmp(*p, "on", 2) == 0) {
+- ecc_mask = PMD_PROTECTION;
+- *p += 2;
+- } else if (memcmp(*p, "off", 3) == 0) {
+- ecc_mask = 0;
+- *p += 3;
+- }
+-}
+-
+-__early_param("nocache", early_nocache);
+-__early_param("nowb", early_nowrite);
+-__early_param("cachepolicy=", early_cachepolicy);
+-__early_param("ecc=", early_ecc);
+-
+-static int __init noalign_setup(char *__unused)
+-{
+- cr_alignment &= ~CR_A;
+- cr_no_alignment &= ~CR_A;
+- set_cr(cr_alignment);
+- return 1;
+-}
+-
+-__setup("noalign", noalign_setup);
+-
+-#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
+-
+-static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+-{
+- return pmd_offset(pgd, virt);
+-}
+-
+-static inline pmd_t *pmd_off_k(unsigned long virt)
+-{
+- return pmd_off(pgd_offset_k(virt), virt);
+-}
+-
+-/*
+- * need to get a 16k page for level 1
+- */
+-pgd_t *get_pgd_slow(struct mm_struct *mm)
+-{
+- pgd_t *new_pgd, *init_pgd;
+- pmd_t *new_pmd, *init_pmd;
+- pte_t *new_pte, *init_pte;
+-
+- new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
+- if (!new_pgd)
+- goto no_pgd;
+-
+- 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()) {
+- /*
+- * On ARM, first page must always be allocated since it
+- * contains the machine vectors.
+- */
+- new_pmd = pmd_alloc(mm, new_pgd, 0);
+- if (!new_pmd)
+- goto no_pmd;
+-
+- new_pte = pte_alloc_map(mm, new_pmd, 0);
+- if (!new_pte)
+- goto no_pte;
+-
+- init_pmd = pmd_offset(init_pgd, 0);
+- init_pte = pte_offset_map_nested(init_pmd, 0);
+- set_pte(new_pte, *init_pte);
+- pte_unmap_nested(init_pte);
+- pte_unmap(new_pte);
+- }
+-
+- return new_pgd;
+-
+-no_pte:
+- pmd_free(new_pmd);
+-no_pmd:
+- free_pages((unsigned long)new_pgd, 2);
+-no_pgd:
+- return NULL;
+-}
+-
+-void free_pgd_slow(pgd_t *pgd)
+-{
+- pmd_t *pmd;
+- struct page *pte;
+-
+- if (!pgd)
+- return;
+-
+- /* pgd is always present and good */
+- pmd = pmd_off(pgd, 0);
+- if (pmd_none(*pmd))
+- goto free;
+- if (pmd_bad(*pmd)) {
+- pmd_ERROR(*pmd);
+- pmd_clear(pmd);
+- goto free;
+- }
+-
+- pte = pmd_page(*pmd);
+- pmd_clear(pmd);
+- dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
+- pte_lock_deinit(pte);
+- pte_free(pte);
+- pmd_free(pmd);
+-free:
+- free_pages((unsigned long) pgd, 2);
+-}
+-
+-/*
+- * Create a SECTION PGD between VIRT and PHYS in domain
+- * DOMAIN with protection PROT. This operates on half-
+- * pgdir entry increments.
+- */
+-static inline void
+-alloc_init_section(unsigned long virt, unsigned long phys, int prot)
+-{
+- pmd_t *pmdp = pmd_off_k(virt);
+-
+- if (virt & (1 << 20))
+- pmdp++;
+-
+- *pmdp = __pmd(phys | prot);
+- flush_pmd_entry(pmdp);
+-}
+-
+-/*
+- * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
+- */
+-static inline void
+-alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
+-{
+- int i;
+-
+- for (i = 0; i < 16; i += 1) {
+- alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
+-
+- virt += (PGDIR_SIZE / 2);
+- }
+-}
+-
+-/*
+- * Add a PAGE mapping between VIRT and PHYS in domain
+- * DOMAIN with protection PROT. Note that due to the
+- * way we map the PTEs, we must allocate two PTE_SIZE'd
+- * blocks - one for the Linux pte table, and one for
+- * the hardware pte table.
+- */
+-static inline void
+-alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
+-{
+- pmd_t *pmdp = pmd_off_k(virt);
+- pte_t *ptep;
+-
+- if (pmd_none(*pmdp)) {
+- ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
+- sizeof(pte_t));
+-
+- __pmd_populate(pmdp, __pa(ptep) | prot_l1);
+- }
+- ptep = pte_offset_kernel(pmdp, virt);
+-
+- set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
+-}
+-
+-struct mem_types {
+- unsigned int prot_pte;
+- unsigned int prot_l1;
+- unsigned int prot_sect;
+- unsigned int domain;
+-};
+-
+-static struct mem_types mem_types[] __initdata = {
+- [MT_DEVICE] = {
+- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+- L_PTE_WRITE,
+- .prot_l1 = PMD_TYPE_TABLE,
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
+- PMD_SECT_AP_WRITE,
+- .domain = DOMAIN_IO,
+- },
+- [MT_CACHECLEAN] = {
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+- .domain = DOMAIN_KERNEL,
+- },
+- [MT_MINICLEAN] = {
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE,
+- .domain = DOMAIN_KERNEL,
+- },
+- [MT_LOW_VECTORS] = {
+- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+- L_PTE_EXEC,
+- .prot_l1 = PMD_TYPE_TABLE,
+- .domain = DOMAIN_USER,
+- },
+- [MT_HIGH_VECTORS] = {
+- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+- L_PTE_USER | L_PTE_EXEC,
+- .prot_l1 = PMD_TYPE_TABLE,
+- .domain = DOMAIN_USER,
+- },
+- [MT_MEMORY] = {
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE,
+- .domain = DOMAIN_KERNEL,
+- },
+- [MT_ROM] = {
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+- .domain = DOMAIN_KERNEL,
+- },
+- [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
+- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+- L_PTE_WRITE,
+- .prot_l1 = PMD_TYPE_TABLE,
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
+- PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
+- PMD_SECT_TEX(1),
+- .domain = DOMAIN_IO,
+- },
+- [MT_NONSHARED_DEVICE] = {
+- .prot_l1 = PMD_TYPE_TABLE,
+- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_NONSHARED_DEV |
+- PMD_SECT_AP_WRITE,
+- .domain = DOMAIN_IO,
+- }
+-};
+-
+-/*
+- * Adjust the PMD section entries according to the CPU in use.
+- */
+-void __init build_mem_type_table(void)
+-{
+- struct cachepolicy *cp;
+- unsigned int cr = get_cr();
+- unsigned int user_pgprot, kern_pgprot;
+- int cpu_arch = cpu_architecture();
+- int i;
+-
+-#if defined(CONFIG_CPU_DCACHE_DISABLE)
+- if (cachepolicy > CPOLICY_BUFFERED)
+- cachepolicy = CPOLICY_BUFFERED;
+-#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
+- if (cachepolicy > CPOLICY_WRITETHROUGH)
+- cachepolicy = CPOLICY_WRITETHROUGH;
+-#endif
+- if (cpu_arch < CPU_ARCH_ARMv5) {
+- if (cachepolicy >= CPOLICY_WRITEALLOC)
+- cachepolicy = CPOLICY_WRITEBACK;
+- ecc_mask = 0;
+- }
+-
+- /*
+- * Xscale must not have PMD bit 4 set for section mappings.
+- */
+- if (cpu_is_xscale())
+- for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+- mem_types[i].prot_sect &= ~PMD_BIT4;
+-
+- /*
+- * ARMv5 and lower, excluding Xscale, bit 4 must be set for
+- * page tables.
+- */
+- if (cpu_arch < CPU_ARCH_ARMv6 && !cpu_is_xscale())
+- for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+- if (mem_types[i].prot_l1)
+- mem_types[i].prot_l1 |= PMD_BIT4;
+-
+- cp = &cache_policies[cachepolicy];
+- kern_pgprot = user_pgprot = cp->pte;
+-
+- /*
+- * Enable CPU-specific coherency if supported.
+- * (Only available on XSC3 at the moment.)
+- */
+- if (arch_is_coherent()) {
+- if (cpu_is_xsc3()) {
+- mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+- mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT;
+- }
+- }
+-
+- /*
+- * ARMv6 and above have extended page tables.
+- */
+- if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
+- /*
+- * bit 4 becomes XN which we must clear for the
+- * kernel memory mapping.
+- */
+- mem_types[MT_MEMORY].prot_sect &= ~PMD_SECT_XN;
+- mem_types[MT_ROM].prot_sect &= ~PMD_SECT_XN;
+-
+- /*
+- * Mark cache clean areas and XIP ROM read only
+- * from SVC mode and no access from userspace.
+- */
+- mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+- mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+- mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+-
+- /*
+- * Mark the device area as "shared device"
+- */
+- mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
+- mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
+-
+- /*
+- * User pages need to be mapped with the ASID
+- * (iow, non-global)
+- */
+- user_pgprot |= L_PTE_ASID;
+-
+-#ifdef CONFIG_SMP
+- /*
+- * Mark memory with the "shared" attribute for SMP systems
+- */
+- user_pgprot |= L_PTE_SHARED;
+- kern_pgprot |= L_PTE_SHARED;
+- mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+-#endif
+- }
+-
+- for (i = 0; i < 16; i++) {
+- unsigned long v = pgprot_val(protection_map[i]);
+- v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot;
+- protection_map[i] = __pgprot(v);
+- }
+-
+- mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot;
+- mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot;
+-
+- if (cpu_arch >= CPU_ARCH_ARMv5) {
+-#ifndef CONFIG_SMP
+- /*
+- * Only use write-through for non-SMP systems
+- */
+- mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
+- mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
+-#endif
+- } else {
+- mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
+- }
+-
+- pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
+- L_PTE_DIRTY | L_PTE_WRITE |
+- L_PTE_EXEC | kern_pgprot);
+-
+- mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
+- mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
+- mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
+- mem_types[MT_ROM].prot_sect |= cp->pmd;
+-
+- switch (cp->pmd) {
+- case PMD_SECT_WT:
+- mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT;
+- break;
+- case PMD_SECT_WB:
+- case PMD_SECT_WBWA:
+- mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB;
+- break;
+- }
+- printk("Memory policy: ECC %sabled, Data cache %s\n",
+- ecc_mask ? "en" : "dis", cp->policy);
+-}
+-
+-#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
+-
+-/*
+- * Create the page directory entries and any necessary
+- * page tables for the mapping specified by `md'. We
+- * are able to cope here with varying sizes and address
+- * offsets, and we take full advantage of sections and
+- * supersections.
+- */
+-void __init create_mapping(struct map_desc *md)
+-{
+- unsigned long virt, length;
+- int prot_sect, prot_l1, domain;
+- pgprot_t prot_pte;
+- unsigned long off = (u32)__pfn_to_phys(md->pfn);
+-
+- if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+- printk(KERN_WARNING "BUG: not creating mapping for "
+- "0x%08llx at 0x%08lx in user region\n",
+- __pfn_to_phys((u64)md->pfn), md->virtual);
+- return;
+- }
+-
+- if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
+- md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
+- printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
+- "overlaps vmalloc space\n",
+- __pfn_to_phys((u64)md->pfn), md->virtual);
+- }
+-
+- domain = mem_types[md->type].domain;
+- prot_pte = __pgprot(mem_types[md->type].prot_pte);
+- prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
+- prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
+-
+- /*
+- * Catch 36-bit addresses
+- */
+- if(md->pfn >= 0x100000) {
+- if(domain) {
+- printk(KERN_ERR "MM: invalid domain in supersection "
+- "mapping for 0x%08llx at 0x%08lx\n",
+- __pfn_to_phys((u64)md->pfn), md->virtual);
+- return;
+- }
+- if((md->virtual | md->length | __pfn_to_phys(md->pfn))
+- & ~SUPERSECTION_MASK) {
+- printk(KERN_ERR "MM: cannot create mapping for "
+- "0x%08llx at 0x%08lx invalid alignment\n",
+- __pfn_to_phys((u64)md->pfn), md->virtual);
+- return;
+- }
+-
+- /*
+- * Shift bits [35:32] of address into bits [23:20] of PMD
+- * (See ARMv6 spec).
+- */
+- off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+- }
+-
+- virt = md->virtual;
+- off -= virt;
+- length = md->length;
+-
+- if (mem_types[md->type].prot_l1 == 0 &&
+- (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
+- printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
+- "be mapped using pages, ignoring.\n",
+- __pfn_to_phys(md->pfn), md->virtual);
+- return;
+- }
+-
+- while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
+- alloc_init_page(virt, virt + off, prot_l1, prot_pte);
+-
+- virt += PAGE_SIZE;
+- length -= PAGE_SIZE;
+- }
+-
+- /* N.B. ARMv6 supersections are only defined to work with domain 0.
+- * Since domain assignments can in fact be arbitrary, the
+- * 'domain == 0' check below is required to insure that ARMv6
+- * supersections are only allocated for domain 0 regardless
+- * of the actual domain assignments in use.
+- */
+- if ((cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())
+- && domain == 0) {
+- /*
+- * Align to supersection boundary if !high pages.
+- * High pages have already been checked for proper
+- * alignment above and they will fail the SUPSERSECTION_MASK
+- * check because of the way the address is encoded into
+- * offset.
+- */
+- if (md->pfn <= 0x100000) {
+- while ((virt & ~SUPERSECTION_MASK ||
+- (virt + off) & ~SUPERSECTION_MASK) &&
+- length >= (PGDIR_SIZE / 2)) {
+- alloc_init_section(virt, virt + off, prot_sect);
+-
+- virt += (PGDIR_SIZE / 2);
+- length -= (PGDIR_SIZE / 2);
+- }
+- }
+-
+- while (length >= SUPERSECTION_SIZE) {
+- alloc_init_supersection(virt, virt + off, prot_sect);
+-
+- virt += SUPERSECTION_SIZE;
+- length -= SUPERSECTION_SIZE;
+- }
+- }
+-
+- /*
+- * A section mapping covers half a "pgdir" entry.
+- */
+- while (length >= (PGDIR_SIZE / 2)) {
+- alloc_init_section(virt, virt + off, prot_sect);
+-
+- virt += (PGDIR_SIZE / 2);
+- length -= (PGDIR_SIZE / 2);
+- }
+-
+- while (length >= PAGE_SIZE) {
+- alloc_init_page(virt, virt + off, prot_l1, prot_pte);
+-
+- virt += PAGE_SIZE;
+- length -= PAGE_SIZE;
+- }
+-}
+-
+-/*
+- * In order to soft-boot, we need to insert a 1:1 mapping in place of
+- * the user-mode pages. This will then ensure that we have predictable
+- * results when turning the mmu off
+- */
+-void setup_mm_for_reboot(char mode)
+-{
+- unsigned long base_pmdval;
+- pgd_t *pgd;
+- int i;
+-
+- if (current->mm && current->mm->pgd)
+- pgd = current->mm->pgd;
+- else
+- pgd = init_mm.pgd;
+-
+- base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
+- if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
+- base_pmdval |= PMD_BIT4;
+-
+- for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
+- unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
+- pmd_t *pmd;
+-
+- pmd = pmd_off(pgd, i << PGDIR_SHIFT);
+- pmd[0] = __pmd(pmdval);
+- pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+- flush_pmd_entry(pmd);
+- }
+-}
+-
+-/*
+- * Create the architecture specific mappings
+- */
+-void __init iotable_init(struct map_desc *io_desc, int nr)
+-{
+- int i;
+-
+- for (i = 0; i < nr; i++)
+- create_mapping(io_desc + i);
+-}
+diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
+new file mode 100644
+index 0000000..bb2bc9a
+--- /dev/null
++++ b/arch/arm/mm/mm.h
+@@ -0,0 +1,22 @@
++/* the upper-most page table pointer */
++extern pmd_t *top_pmd;
++
++#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
++
++static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
++{
++ return pmd_offset(pgd, virt);
++}
++
++static inline pmd_t *pmd_off_k(unsigned long virt)
++{
++ return pmd_off(pgd_offset_k(virt), virt);
++}
++
++struct map_desc;
++struct meminfo;
++struct pglist_data;
++
++void __init create_mapping(struct map_desc *md);
++void __init bootmem_init(struct meminfo *mi);
++void reserve_node_zero(struct pglist_data *pgdat);
+diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
+index 29e5480..b0b5f46 100644
+--- a/arch/arm/mm/mmap.c
++++ b/arch/arm/mm/mmap.c
+@@ -114,3 +114,25 @@ full_search:
+ }
+ }
+
++
++/*
++ * You really shouldn't be using read() or write() on /dev/mem. This
++ * might go away in the future.
++ */
++int valid_phys_addr_range(unsigned long addr, size_t size)
++{
++ if (addr + size > __pa(high_memory))
++ return 0;
++
++ return 1;
++}
++
++/*
++ * We don't use supersection mappings for mmap() on /dev/mem, which
++ * means that we can't map the memory area above the 4G barrier into
++ * userspace.
++ */
++int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
++{
++ return !(pfn + (size >> PAGE_SHIFT) > 0x00100000);
++}
+diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
+index 0d90227..f866bf6 100644
+--- a/arch/arm/mm/mmu.c
++++ b/arch/arm/mm/mmu.c
+@@ -1,45 +1,771 @@
+ /*
+ * linux/arch/arm/mm/mmu.c
+ *
+- * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
++ * Copyright (C) 1995-2005 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/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
+ #include <linux/init.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
++#include <linux/bootmem.h>
++#include <linux/mman.h>
++#include <linux/nodemask.h>
+
+-#include <asm/mmu_context.h>
+-#include <asm/tlbflush.h>
++#include <asm/mach-types.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <asm/tlb.h>
+
+-unsigned int cpu_last_asid = { 1 << ASID_BITS };
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include "mm.h"
++
++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
++
++extern void _stext, _etext, __data_start, _end;
++extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
++
++/*
++ * empty_zero_page is a special page that is used for
++ * zero-initialized data and COW.
++ */
++struct page *empty_zero_page;
+
+ /*
+- * We fork()ed a process, and we need a new context for the child
+- * to run in. We reserve version 0 for initial tasks so we will
+- * always allocate an ASID.
++ * The pmd table for the upper-most set of pages.
+ */
+-void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++pmd_t *top_pmd;
++
++#define CPOLICY_UNCACHED 0
++#define CPOLICY_BUFFERED 1
++#define CPOLICY_WRITETHROUGH 2
++#define CPOLICY_WRITEBACK 3
++#define CPOLICY_WRITEALLOC 4
++
++static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
++static unsigned int ecc_mask __initdata = 0;
++pgprot_t pgprot_kernel;
++
++EXPORT_SYMBOL(pgprot_kernel);
++
++struct cachepolicy {
++ const char policy[16];
++ unsigned int cr_mask;
++ unsigned int pmd;
++ unsigned int pte;
++};
++
++static struct cachepolicy cache_policies[] __initdata = {
++ {
++ .policy = "uncached",
++ .cr_mask = CR_W|CR_C,
++ .pmd = PMD_SECT_UNCACHED,
++ .pte = 0,
++ }, {
++ .policy = "buffered",
++ .cr_mask = CR_C,
++ .pmd = PMD_SECT_BUFFERED,
++ .pte = PTE_BUFFERABLE,
++ }, {
++ .policy = "writethrough",
++ .cr_mask = 0,
++ .pmd = PMD_SECT_WT,
++ .pte = PTE_CACHEABLE,
++ }, {
++ .policy = "writeback",
++ .cr_mask = 0,
++ .pmd = PMD_SECT_WB,
++ .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
++ }, {
++ .policy = "writealloc",
++ .cr_mask = 0,
++ .pmd = PMD_SECT_WBWA,
++ .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
++ }
++};
++
++/*
++ * These are useful for identifing cache coherency
++ * problems by allowing the cache or the cache and
++ * writebuffer to be turned off. (Note: the write
++ * buffer should not be on and the cache off).
++ */
++static void __init early_cachepolicy(char **p)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
++ int len = strlen(cache_policies[i].policy);
++
++ if (memcmp(*p, cache_policies[i].policy, len) == 0) {
++ cachepolicy = i;
++ cr_alignment &= ~cache_policies[i].cr_mask;
++ cr_no_alignment &= ~cache_policies[i].cr_mask;
++ *p += len;
++ break;
++ }
++ }
++ if (i == ARRAY_SIZE(cache_policies))
++ printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
++ flush_cache_all();
++ set_cr(cr_alignment);
++}
++__early_param("cachepolicy=", early_cachepolicy);
++
++static void __init early_nocache(char **__unused)
++{
++ char *p = "buffered";
++ printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
++ early_cachepolicy(&p);
++}
++__early_param("nocache", early_nocache);
++
++static void __init early_nowrite(char **__unused)
++{
++ char *p = "uncached";
++ printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
++ early_cachepolicy(&p);
++}
++__early_param("nowb", early_nowrite);
++
++static void __init early_ecc(char **p)
++{
++ if (memcmp(*p, "on", 2) == 0) {
++ ecc_mask = PMD_PROTECTION;
++ *p += 2;
++ } else if (memcmp(*p, "off", 3) == 0) {
++ ecc_mask = 0;
++ *p += 3;
++ }
++}
++__early_param("ecc=", early_ecc);
++
++static int __init noalign_setup(char *__unused)
+ {
+- mm->context.id = 0;
++ cr_alignment &= ~CR_A;
++ cr_no_alignment &= ~CR_A;
++ set_cr(cr_alignment);
++ return 1;
+ }
++__setup("noalign", noalign_setup);
++
++struct mem_types {
++ unsigned int prot_pte;
++ unsigned int prot_l1;
++ unsigned int prot_sect;
++ unsigned int domain;
++};
+
+-void __new_context(struct mm_struct *mm)
++static struct mem_types mem_types[] __initdata = {
++ [MT_DEVICE] = {
++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
++ L_PTE_WRITE,
++ .prot_l1 = PMD_TYPE_TABLE,
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
++ PMD_SECT_AP_WRITE,
++ .domain = DOMAIN_IO,
++ },
++ [MT_CACHECLEAN] = {
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
++ .domain = DOMAIN_KERNEL,
++ },
++ [MT_MINICLEAN] = {
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE,
++ .domain = DOMAIN_KERNEL,
++ },
++ [MT_LOW_VECTORS] = {
++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
++ L_PTE_EXEC,
++ .prot_l1 = PMD_TYPE_TABLE,
++ .domain = DOMAIN_USER,
++ },
++ [MT_HIGH_VECTORS] = {
++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
++ L_PTE_USER | L_PTE_EXEC,
++ .prot_l1 = PMD_TYPE_TABLE,
++ .domain = DOMAIN_USER,
++ },
++ [MT_MEMORY] = {
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE,
++ .domain = DOMAIN_KERNEL,
++ },
++ [MT_ROM] = {
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
++ .domain = DOMAIN_KERNEL,
++ },
++ [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
++ L_PTE_WRITE,
++ .prot_l1 = PMD_TYPE_TABLE,
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
++ PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
++ PMD_SECT_TEX(1),
++ .domain = DOMAIN_IO,
++ },
++ [MT_NONSHARED_DEVICE] = {
++ .prot_l1 = PMD_TYPE_TABLE,
++ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_NONSHARED_DEV |
++ PMD_SECT_AP_WRITE,
++ .domain = DOMAIN_IO,
++ }
++};
++
++/*
++ * Adjust the PMD section entries according to the CPU in use.
++ */
++static void __init build_mem_type_table(void)
+ {
+- unsigned int asid;
++ struct cachepolicy *cp;
++ unsigned int cr = get_cr();
++ unsigned int user_pgprot, kern_pgprot;
++ int cpu_arch = cpu_architecture();
++ int i;
+
+- asid = ++cpu_last_asid;
+- if (asid == 0)
+- asid = cpu_last_asid = 1 << ASID_BITS;
++#if defined(CONFIG_CPU_DCACHE_DISABLE)
++ if (cachepolicy > CPOLICY_BUFFERED)
++ cachepolicy = CPOLICY_BUFFERED;
++#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
++ if (cachepolicy > CPOLICY_WRITETHROUGH)
++ cachepolicy = CPOLICY_WRITETHROUGH;
++#endif
++ if (cpu_arch < CPU_ARCH_ARMv5) {
++ if (cachepolicy >= CPOLICY_WRITEALLOC)
++ cachepolicy = CPOLICY_WRITEBACK;
++ ecc_mask = 0;
++ }
++
++ /*
++ * Xscale must not have PMD bit 4 set for section mappings.
++ */
++ if (cpu_is_xscale())
++ for (i = 0; i < ARRAY_SIZE(mem_types); i++)
++ mem_types[i].prot_sect &= ~PMD_BIT4;
+
+ /*
+- * If we've used up all our ASIDs, we need
+- * to start a new version and flush the TLB.
++ * ARMv5 and lower, excluding Xscale, bit 4 must be set for
++ * page tables.
+ */
+- if ((asid & ~ASID_MASK) == 0)
+- flush_tlb_all();
++ if (cpu_arch < CPU_ARCH_ARMv6 && !cpu_is_xscale())
++ for (i = 0; i < ARRAY_SIZE(mem_types); i++)
++ if (mem_types[i].prot_l1)
++ mem_types[i].prot_l1 |= PMD_BIT4;
++
++ cp = &cache_policies[cachepolicy];
++ kern_pgprot = user_pgprot = cp->pte;
++
++ /*
++ * Enable CPU-specific coherency if supported.
++ * (Only available on XSC3 at the moment.)
++ */
++ if (arch_is_coherent()) {
++ if (cpu_is_xsc3()) {
++ mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
++ mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT;
++ }
++ }
++
++ /*
++ * ARMv6 and above have extended page tables.
++ */
++ if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
++ /*
++ * bit 4 becomes XN which we must clear for the
++ * kernel memory mapping.
++ */
++ mem_types[MT_MEMORY].prot_sect &= ~PMD_SECT_XN;
++ mem_types[MT_ROM].prot_sect &= ~PMD_SECT_XN;
++
++ /*
++ * Mark cache clean areas and XIP ROM read only
++ * from SVC mode and no access from userspace.
++ */
++ mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
++ mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
++ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
++
++ /*
++ * Mark the device area as "shared device"
++ */
++ mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
++ mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
++
++ /*
++ * User pages need to be mapped with the ASID
++ * (iow, non-global)
++ */
++ user_pgprot |= L_PTE_ASID;
++
++#ifdef CONFIG_SMP
++ /*
++ * Mark memory with the "shared" attribute for SMP systems
++ */
++ user_pgprot |= L_PTE_SHARED;
++ kern_pgprot |= L_PTE_SHARED;
++ mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
++#endif
++ }
++
++ for (i = 0; i < 16; i++) {
++ unsigned long v = pgprot_val(protection_map[i]);
++ v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot;
++ protection_map[i] = __pgprot(v);
++ }
++
++ mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot;
++ mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot;
++
++ if (cpu_arch >= CPU_ARCH_ARMv5) {
++#ifndef CONFIG_SMP
++ /*
++ * Only use write-through for non-SMP systems
++ */
++ mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
++ mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
++#endif
++ } else {
++ mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
++ }
++
++ pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
++ L_PTE_DIRTY | L_PTE_WRITE |
++ L_PTE_EXEC | kern_pgprot);
++
++ mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
++ mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
++ mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
++ mem_types[MT_ROM].prot_sect |= cp->pmd;
++
++ switch (cp->pmd) {
++ case PMD_SECT_WT:
++ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT;
++ break;
++ case PMD_SECT_WB:
++ case PMD_SECT_WBWA:
++ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB;
++ break;
++ }
++ printk("Memory policy: ECC %sabled, Data cache %s\n",
++ ecc_mask ? "en" : "dis", cp->policy);
++}
++
++#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
++
++/*
++ * Create a SECTION PGD between VIRT and PHYS in domain
++ * DOMAIN with protection PROT. This operates on half-
++ * pgdir entry increments.
++ */
++static inline void
++alloc_init_section(unsigned long virt, unsigned long phys, int prot)
++{
++ pmd_t *pmdp = pmd_off_k(virt);
++
++ if (virt & (1 << 20))
++ pmdp++;
++
++ *pmdp = __pmd(phys | prot);
++ flush_pmd_entry(pmdp);
++}
++
++/*
++ * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
++ */
++static inline void
++alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
++{
++ int i;
++
++ for (i = 0; i < 16; i += 1) {
++ alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
++
++ virt += (PGDIR_SIZE / 2);
++ }
++}
++
++/*
++ * Add a PAGE mapping between VIRT and PHYS in domain
++ * DOMAIN with protection PROT. Note that due to the
++ * way we map the PTEs, we must allocate two PTE_SIZE'd
++ * blocks - one for the Linux pte table, and one for
++ * the hardware pte table.
++ */
++static inline void
++alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
++{
++ pmd_t *pmdp = pmd_off_k(virt);
++ pte_t *ptep;
++
++ if (pmd_none(*pmdp)) {
++ ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
++ sizeof(pte_t));
++
++ __pmd_populate(pmdp, __pa(ptep) | prot_l1);
++ }
++ ptep = pte_offset_kernel(pmdp, virt);
++
++ set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
++}
++
++/*
++ * Create the page directory entries and any necessary
++ * page tables for the mapping specified by `md'. We
++ * are able to cope here with varying sizes and address
++ * offsets, and we take full advantage of sections and
++ * supersections.
++ */
++void __init create_mapping(struct map_desc *md)
++{
++ unsigned long virt, length;
++ int prot_sect, prot_l1, domain;
++ pgprot_t prot_pte;
++ unsigned long off = (u32)__pfn_to_phys(md->pfn);
++
++ if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
++ printk(KERN_WARNING "BUG: not creating mapping for "
++ "0x%08llx at 0x%08lx in user region\n",
++ __pfn_to_phys((u64)md->pfn), md->virtual);
++ return;
++ }
++
++ if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
++ md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
++ printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
++ "overlaps vmalloc space\n",
++ __pfn_to_phys((u64)md->pfn), md->virtual);
++ }
++
++ domain = mem_types[md->type].domain;
++ prot_pte = __pgprot(mem_types[md->type].prot_pte);
++ prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
++ prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
++
++ /*
++ * Catch 36-bit addresses
++ */
++ if(md->pfn >= 0x100000) {
++ if(domain) {
++ printk(KERN_ERR "MM: invalid domain in supersection "
++ "mapping for 0x%08llx at 0x%08lx\n",
++ __pfn_to_phys((u64)md->pfn), md->virtual);
++ return;
++ }
++ if((md->virtual | md->length | __pfn_to_phys(md->pfn))
++ & ~SUPERSECTION_MASK) {
++ printk(KERN_ERR "MM: cannot create mapping for "
++ "0x%08llx at 0x%08lx invalid alignment\n",
++ __pfn_to_phys((u64)md->pfn), md->virtual);
++ return;
++ }
++
++ /*
++ * Shift bits [35:32] of address into bits [23:20] of PMD
++ * (See ARMv6 spec).
++ */
++ off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
++ }
++
++ virt = md->virtual;
++ off -= virt;
++ length = md->length;
++
++ if (mem_types[md->type].prot_l1 == 0 &&
++ (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
++ printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
++ "be mapped using pages, ignoring.\n",
++ __pfn_to_phys(md->pfn), md->virtual);
++ return;
++ }
++
++ while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
++ alloc_init_page(virt, virt + off, prot_l1, prot_pte);
++
++ virt += PAGE_SIZE;
++ length -= PAGE_SIZE;
++ }
++
++ /* N.B. ARMv6 supersections are only defined to work with domain 0.
++ * Since domain assignments can in fact be arbitrary, the
++ * 'domain == 0' check below is required to insure that ARMv6
++ * supersections are only allocated for domain 0 regardless
++ * of the actual domain assignments in use.
++ */
++ if ((cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())
++ && domain == 0) {
++ /*
++ * Align to supersection boundary if !high pages.
++ * High pages have already been checked for proper
++ * alignment above and they will fail the SUPSERSECTION_MASK
++ * check because of the way the address is encoded into
++ * offset.
++ */
++ if (md->pfn <= 0x100000) {
++ while ((virt & ~SUPERSECTION_MASK ||
++ (virt + off) & ~SUPERSECTION_MASK) &&
++ length >= (PGDIR_SIZE / 2)) {
++ alloc_init_section(virt, virt + off, prot_sect);
++
++ virt += (PGDIR_SIZE / 2);
++ length -= (PGDIR_SIZE / 2);
++ }
++ }
++
++ while (length >= SUPERSECTION_SIZE) {
++ alloc_init_supersection(virt, virt + off, prot_sect);
++
++ virt += SUPERSECTION_SIZE;
++ length -= SUPERSECTION_SIZE;
++ }
++ }
++
++ /*
++ * A section mapping covers half a "pgdir" entry.
++ */
++ while (length >= (PGDIR_SIZE / 2)) {
++ alloc_init_section(virt, virt + off, prot_sect);
++
++ virt += (PGDIR_SIZE / 2);
++ length -= (PGDIR_SIZE / 2);
++ }
++
++ while (length >= PAGE_SIZE) {
++ alloc_init_page(virt, virt + off, prot_l1, prot_pte);
++
++ virt += PAGE_SIZE;
++ length -= PAGE_SIZE;
++ }
++}
++
++/*
++ * Create the architecture specific mappings
++ */
++void __init iotable_init(struct map_desc *io_desc, int nr)
++{
++ int i;
++
++ for (i = 0; i < nr; i++)
++ create_mapping(io_desc + i);
++}
++
++static inline void prepare_page_table(struct meminfo *mi)
++{
++ unsigned long addr;
++
++ /*
++ * Clear out all the mappings below the kernel image.
++ */
++ for (addr = 0; addr < MODULE_START; addr += PGDIR_SIZE)
++ pmd_clear(pmd_off_k(addr));
++
++#ifdef CONFIG_XIP_KERNEL
++ /* The XIP kernel is mapped in the module area -- skip over it */
++ addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
++#endif
++ for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
++ pmd_clear(pmd_off_k(addr));
++
++ /*
++ * Clear out all the kernel space mappings, except for the first
++ * memory bank, up to the end of the vmalloc region.
++ */
++ for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
++ addr < VMALLOC_END; addr += PGDIR_SIZE)
++ pmd_clear(pmd_off_k(addr));
++}
++
++/*
++ * Reserve the various regions of node 0
++ */
++void __init reserve_node_zero(pg_data_t *pgdat)
++{
++ unsigned long res_size = 0;
++
++ /*
++ * Register the kernel text and data with bootmem.
++ * Note that this can only be in node 0.
++ */
++#ifdef CONFIG_XIP_KERNEL
++ reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
++#else
++ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
++#endif
++
++ /*
++ * Reserve the page tables. These are already in use,
++ * and can only be in node 0.
++ */
++ reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
++ PTRS_PER_PGD * sizeof(pgd_t));
++
++ /*
++ * Hmm... This should go elsewhere, but we really really need to
++ * stop things allocating the low memory; ideally we need a better
++ * implementation of GFP_DMA which does not assume that DMA-able
++ * memory starts at zero.
++ */
++ if (machine_is_integrator() || machine_is_cintegrator())
++ res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
++
++ /*
++ * These should likewise go elsewhere. They pre-reserve the
++ * screen memory region at the start of main system memory.
++ */
++ if (machine_is_edb7211())
++ res_size = 0x00020000;
++ if (machine_is_p720t())
++ res_size = 0x00014000;
++
++#ifdef CONFIG_SA1111
++ /*
++ * Because of the SA1111 DMA bug, we want to preserve our
++ * precious DMA-able memory...
++ */
++ res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
++#endif
++ if (res_size)
++ reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
++}
++
++/*
++ * Set up device the mappings. Since we clear out the page tables for all
++ * mappings above VMALLOC_END, we will remove any debug device mappings.
++ * This means you have to be careful how you debug this function, or any
++ * called function. This means you can't use any function or debugging
++ * method which may touch any device, otherwise the kernel _will_ crash.
++ */
++static void __init devicemaps_init(struct machine_desc *mdesc)
++{
++ struct map_desc map;
++ unsigned long addr;
++ void *vectors;
++
++ /*
++ * Allocate the vector page early.
++ */
++ vectors = alloc_bootmem_low_pages(PAGE_SIZE);
++ BUG_ON(!vectors);
++
++ for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
++ pmd_clear(pmd_off_k(addr));
++
++ /*
++ * Map the kernel if it is XIP.
++ * It is always first in the modulearea.
++ */
++#ifdef CONFIG_XIP_KERNEL
++ map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK);
++ map.virtual = MODULE_START;
++ map.length = ((unsigned long)&_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK;
++ map.type = MT_ROM;
++ create_mapping(&map);
++#endif
++
++ /*
++ * Map the cache flushing regions.
++ */
++#ifdef FLUSH_BASE
++ map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);
++ map.virtual = FLUSH_BASE;
++ map.length = SZ_1M;
++ map.type = MT_CACHECLEAN;
++ create_mapping(&map);
++#endif
++#ifdef FLUSH_BASE_MINICACHE
++ map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M);
++ map.virtual = FLUSH_BASE_MINICACHE;
++ map.length = SZ_1M;
++ map.type = MT_MINICLEAN;
++ create_mapping(&map);
++#endif
++
++ /*
++ * Create a mapping for the machine vectors at the high-vectors
++ * location (0xffff0000). If we aren't using high-vectors, also
++ * create a mapping at the low-vectors virtual address.
++ */
++ map.pfn = __phys_to_pfn(virt_to_phys(vectors));
++ map.virtual = 0xffff0000;
++ map.length = PAGE_SIZE;
++ map.type = MT_HIGH_VECTORS;
++ create_mapping(&map);
++
++ if (!vectors_high()) {
++ map.virtual = 0;
++ map.type = MT_LOW_VECTORS;
++ create_mapping(&map);
++ }
++
++ /*
++ * Ask the machine support to map in the statically mapped devices.
++ */
++ if (mdesc->map_io)
++ mdesc->map_io();
++
++ /*
++ * Finally flush the caches and tlb to ensure that we're in a
++ * consistent state wrt the writebuffer. This also ensures that
++ * any write-allocated cache lines in the vector page are written
++ * back. After this point, we can start to touch devices again.
++ */
++ local_flush_tlb_all();
++ flush_cache_all();
++}
++
++/*
++ * paging_init() sets up the page tables, initialises the zone memory
++ * maps, and sets up the zero page, bad page and bad page tables.
++ */
++void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
++{
++ void *zero_page;
++
++ build_mem_type_table();
++ prepare_page_table(mi);
++ bootmem_init(mi);
++ devicemaps_init(mdesc);
++
++ top_pmd = pmd_off_k(0xffff0000);
++
++ /*
++ * allocate the zero page. Note that we count on this going ok.
++ */
++ zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
++ memzero(zero_page, PAGE_SIZE);
++ empty_zero_page = virt_to_page(zero_page);
++ flush_dcache_page(empty_zero_page);
++}
++
++/*
++ * In order to soft-boot, we need to insert a 1:1 mapping in place of
++ * the user-mode pages. This will then ensure that we have predictable
++ * results when turning the mmu off
++ */
++void setup_mm_for_reboot(char mode)
++{
++ unsigned long base_pmdval;
++ pgd_t *pgd;
++ int i;
++
++ if (current->mm && current->mm->pgd)
++ pgd = current->mm->pgd;
++ else
++ pgd = init_mm.pgd;
++
++ base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
++ if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
++ base_pmdval |= PMD_BIT4;
++
++ for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
++ unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
++ pmd_t *pmd;
+
+- mm->context.id = asid;
++ pmd = pmd_off(pgd, i << PGDIR_SHIFT);
++ pmd[0] = __pmd(pmdval);
++ pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
++ flush_pmd_entry(pmd);
++ }
+ }
+diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
+index 1464ed8..d0e6642 100644
+--- a/arch/arm/mm/nommu.c
++++ b/arch/arm/mm/nommu.c
+@@ -11,6 +11,49 @@
+ #include <asm/io.h>
+ #include <asm/page.h>
+
++#include "mm.h"
++
++extern void _stext, __data_start, _end;
++
++/*
++ * Reserve the various regions of node 0
++ */
++void __init reserve_node_zero(pg_data_t *pgdat)
++{
++ /*
++ * Register the kernel text and data with bootmem.
++ * Note that this can only be in node 0.
++ */
++#ifdef CONFIG_XIP_KERNEL
++ reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
++#else
++ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
++#endif
++
++ /*
++ * Register the exception vector page.
++ * some architectures which the DRAM is the exception vector to trap,
++ * alloc_page breaks with error, although it is not NULL, but "0."
++ */
++ reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE);
++}
++
++/*
++ * paging_init() sets up the page tables, initialises the zone memory
++ * maps, and sets up the zero page, bad page and bad page tables.
++ */
++void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
++{
++ bootmem_init(mi);
++}
++
++/*
++ * We don't need to do anything here for nommu machines.
++ */
++void setup_mm_for_reboot(char mode)
++{
++}
++
+ void flush_dcache_page(struct page *page)
+ {
+ __cpuc_flush_dcache_page(page_address(page));
+diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
+new file mode 100644
+index 0000000..20c1b0d
+--- /dev/null
++++ b/arch/arm/mm/pgd.c
+@@ -0,0 +1,101 @@
++/*
++ * linux/arch/arm/mm/pgd.c
++ *
++ * Copyright (C) 1998-2005 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/mm.h>
++#include <linux/highmem.h>
++
++#include <asm/pgalloc.h>
++#include <asm/page.h>
++#include <asm/tlbflush.h>
++
++#include "mm.h"
++
++#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
++
++/*
++ * need to get a 16k page for level 1
++ */
++pgd_t *get_pgd_slow(struct mm_struct *mm)
++{
++ pgd_t *new_pgd, *init_pgd;
++ pmd_t *new_pmd, *init_pmd;
++ pte_t *new_pte, *init_pte;
++
++ new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
++ if (!new_pgd)
++ goto no_pgd;
++
++ 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()) {
++ /*
++ * On ARM, first page must always be allocated since it
++ * contains the machine vectors.
++ */
++ new_pmd = pmd_alloc(mm, new_pgd, 0);
++ if (!new_pmd)
++ goto no_pmd;
++
++ new_pte = pte_alloc_map(mm, new_pmd, 0);
++ if (!new_pte)
++ goto no_pte;
++
++ init_pmd = pmd_offset(init_pgd, 0);
++ init_pte = pte_offset_map_nested(init_pmd, 0);
++ set_pte(new_pte, *init_pte);
++ pte_unmap_nested(init_pte);
++ pte_unmap(new_pte);
++ }
++
++ return new_pgd;
++
++no_pte:
++ pmd_free(new_pmd);
++no_pmd:
++ free_pages((unsigned long)new_pgd, 2);
++no_pgd:
++ return NULL;
++}
++
++void free_pgd_slow(pgd_t *pgd)
++{
++ pmd_t *pmd;
++ struct page *pte;
++
++ if (!pgd)
++ return;
++
++ /* pgd is always present and good */
++ pmd = pmd_off(pgd, 0);
++ if (pmd_none(*pmd))
++ goto free;
++ if (pmd_bad(*pmd)) {
++ pmd_ERROR(*pmd);
++ pmd_clear(pmd);
++ goto free;
++ }
++
++ pte = pmd_page(*pmd);
++ pmd_clear(pmd);
++ dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
++ pte_lock_deinit(pte);
++ pte_free(pte);
++ pmd_free(pmd);
++free:
++ free_pages((unsigned long) pgd, 2);
++}
+diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S
+new file mode 100644
+index 0000000..4071381
+--- /dev/null
++++ b/arch/arm/mm/proc-arm740.S
+@@ -0,0 +1,174 @@
++/*
++ * linux/arch/arm/mm/arm740.S: utility functions for ARM740
++ *
++ * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi at samsung.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/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/asm-offsets.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/procinfo.h>
++#include <asm/ptrace.h>
++
++ .text
++/*
++ * cpu_arm740_proc_init()
++ * cpu_arm740_do_idle()
++ * cpu_arm740_dcache_clean_area()
++ * cpu_arm740_switch_mm()
++ *
++ * These are not required.
++ */
++ENTRY(cpu_arm740_proc_init)
++ENTRY(cpu_arm740_do_idle)
++ENTRY(cpu_arm740_dcache_clean_area)
++ENTRY(cpu_arm740_switch_mm)
++ mov pc, lr
++
++/*
++ * cpu_arm740_proc_fin()
++ */
++ENTRY(cpu_arm740_proc_fin)
++ stmfd sp!, {lr}
++ mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++ msr cpsr_c, ip
++ mrc p15, 0, r0, c1, c0, 0
++ bic r0, r0, #0x3f000000 @ bank/f/lock/s
++ bic r0, r0, #0x0000000c @ w-buffer/cache
++ mcr p15, 0, r0, c1, c0, 0 @ disable caches
++ mcr p15, 0, r0, c7, c0, 0 @ invalidate cache
++ ldmfd sp!, {pc}
++
++/*
++ * cpu_arm740_reset(loc)
++ * Params : r0 = address to jump to
++ * Notes : This sets up everything for a reset
++ */
++ENTRY(cpu_arm740_reset)
++ mov ip, #0
++ mcr p15, 0, ip, c7, c0, 0 @ invalidate cache
++ mrc p15, 0, ip, c1, c0, 0 @ get ctrl register
++ bic ip, ip, #0x0000000c @ ............wc..
++ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
++ mov pc, r0
++
++ __INIT
++
++ .type __arm740_setup, #function
++__arm740_setup:
++ mov r0, #0
++ mcr p15, 0, r0, c7, c0, 0 @ invalidate caches
++
++ mcr p15, 0, r0, c6, c3 @ disable area 3~7
++ mcr p15, 0, r0, c6, c4
++ mcr p15, 0, r0, c6, c5
++ mcr p15, 0, r0, c6, c6
++ mcr p15, 0, r0, c6, c7
++
++ mov r0, #0x0000003F @ base = 0, size = 4GB
++ mcr p15, 0, r0, c6, c0 @ set area 0, default
++
++ ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
++ ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
++ mov r2, #10 @ 11 is the minimum (4KB)
++1: add r2, r2, #1 @ area size *= 2
++ mov r1, r1, lsr #1
++ bne 1b @ count not zero r-shift
++ orr r0, r0, r2, lsl #1 @ the area register value
++ orr r0, r0, #1 @ set enable bit
++ mcr p15, 0, r0, c6, c1 @ set area 1, RAM
++
++ ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
++ ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
++ mov r2, #10 @ 11 is the minimum (4KB)
++1: add r2, r2, #1 @ area size *= 2
++ mov r1, r1, lsr #1
++ bne 1b @ count not zero r-shift
++ orr r0, r0, r2, lsl #1 @ the area register value
++ orr r0, r0, #1 @ set enable bit
++ mcr p15, 0, r0, c6, c2 @ set area 2, ROM/FLASH
++
++ mov r0, #0x06
++ mcr p15, 0, r0, c2, c0 @ Region 1&2 cacheable
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mov r0, #0x00 @ disable whole write buffer
++#else
++ mov r0, #0x02 @ Region 1 write bufferred
++#endif
++ mcr p15, 0, r0, c3, c0
++
++ mov r0, #0x10000
++ sub r0, r0, #1 @ r0 = 0xffff
++ mcr p15, 0, r0, c5, c0 @ all read/write access
++
++ mrc p15, 0, r0, c1, c0 @ get control register
++ bic r0, r0, #0x3F000000 @ set to standard caching mode
++ @ need some benchmark
++ orr r0, r0, #0x0000000d @ MPU/Cache/WB
++
++ mov pc, lr
++
++ .size __arm740_setup, . - __arm740_setup
++
++ __INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ * come through these
++ */
++ .type arm740_processor_functions, #object
++ENTRY(arm740_processor_functions)
++ .word v4t_late_abort
++ .word cpu_arm740_proc_init
++ .word cpu_arm740_proc_fin
++ .word cpu_arm740_reset
++ .word cpu_arm740_do_idle
++ .word cpu_arm740_dcache_clean_area
++ .word cpu_arm740_switch_mm
++ .word 0 @ cpu_*_set_pte
++ .size arm740_processor_functions, . - arm740_processor_functions
++
++ .section ".rodata"
++
++ .type cpu_arch_name, #object
++cpu_arch_name:
++ .asciz "armv4"
++ .size cpu_arch_name, . - cpu_arch_name
++
++ .type cpu_elf_name, #object
++cpu_elf_name:
++ .asciz "v4"
++ .size cpu_elf_name, . - cpu_elf_name
++
++ .type cpu_arm740_name, #object
++cpu_arm740_name:
++ .ascii "ARM740T"
++ .size cpu_arm740_name, . - cpu_arm740_name
++
++ .align
++
++ .section ".proc.info.init", #alloc, #execinstr
++ .type __arm740_proc_info,#object
++__arm740_proc_info:
++ .long 0x41807400
++ .long 0xfffffff0
++ .long 0
++ b __arm740_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
++ .long cpu_arm740_name
++ .long arm740_processor_functions
++ .long 0
++ .long 0
++ .long v3_cache_fns @ cache model
++ .size __arm740_proc_info, . - __arm740_proc_info
++
++
+diff --git a/arch/arm/mm/proc-arm7tdmi.S b/arch/arm/mm/proc-arm7tdmi.S
+new file mode 100644
+index 0000000..22d7e31
+--- /dev/null
++++ b/arch/arm/mm/proc-arm7tdmi.S
+@@ -0,0 +1,249 @@
++/*
++ * linux/arch/arm/mm/proc-arm7tdmi.S: utility functions for ARM7TDMI
++ *
++ * Copyright (C) 2003-2006 Hyok S. Choi <hyok.choi at samsung.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/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/asm-offsets.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/procinfo.h>
++#include <asm/ptrace.h>
++
++ .text
++/*
++ * cpu_arm7tdmi_proc_init()
++ * cpu_arm7tdmi_do_idle()
++ * cpu_arm7tdmi_dcache_clean_area()
++ * cpu_arm7tdmi_switch_mm()
++ *
++ * These are not required.
++ */
++ENTRY(cpu_arm7tdmi_proc_init)
++ENTRY(cpu_arm7tdmi_do_idle)
++ENTRY(cpu_arm7tdmi_dcache_clean_area)
++ENTRY(cpu_arm7tdmi_switch_mm)
++ mov pc, lr
++
++/*
++ * cpu_arm7tdmi_proc_fin()
++ */
++ENTRY(cpu_arm7tdmi_proc_fin)
++ mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++ msr cpsr_c, r0
++ mov pc, lr
++
++/*
++ * Function: cpu_arm7tdmi_reset(loc)
++ * Params : loc(r0) address to jump to
++ * Purpose : Sets up everything for a reset and jump to the location for soft reset.
++ */
++ENTRY(cpu_arm7tdmi_reset)
++ mov pc, r0
++
++ __INIT
++
++ .type __arm7tdmi_setup, #function
++__arm7tdmi_setup:
++ mov pc, lr
++ .size __arm7tdmi_setup, . - __arm7tdmi_setup
++
++ __INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ * come through these
++ */
++ .type arm7tdmi_processor_functions, #object
++ENTRY(arm7tdmi_processor_functions)
++ .word v4t_late_abort
++ .word cpu_arm7tdmi_proc_init
++ .word cpu_arm7tdmi_proc_fin
++ .word cpu_arm7tdmi_reset
++ .word cpu_arm7tdmi_do_idle
++ .word cpu_arm7tdmi_dcache_clean_area
++ .word cpu_arm7tdmi_switch_mm
++ .word 0 @ cpu_*_set_pte
++ .size arm7tdmi_processor_functions, . - arm7tdmi_processor_functions
++
++ .section ".rodata"
++
++ .type cpu_arch_name, #object
++cpu_arch_name:
++ .asciz "armv4t"
++ .size cpu_arch_name, . - cpu_arch_name
++
++ .type cpu_elf_name, #object
++cpu_elf_name:
++ .asciz "v4"
++ .size cpu_elf_name, . - cpu_elf_name
++
++ .type cpu_arm7tdmi_name, #object
++cpu_arm7tdmi_name:
++ .asciz "ARM7TDMI"
++ .size cpu_arm7tdmi_name, . - cpu_arm7tdmi_name
++
++ .type cpu_triscenda7_name, #object
++cpu_triscenda7_name:
++ .asciz "Triscend-A7x"
++ .size cpu_triscenda7_name, . - cpu_triscenda7_name
++
++ .type cpu_at91_name, #object
++cpu_at91_name:
++ .asciz "Atmel-AT91M40xxx"
++ .size cpu_at91_name, . - cpu_at91_name
++
++ .type cpu_s3c3410_name, #object
++cpu_s3c3410_name:
++ .asciz "Samsung-S3C3410"
++ .size cpu_s3c3410_name, . - cpu_s3c3410_name
++
++ .type cpu_s3c44b0x_name, #object
++cpu_s3c44b0x_name:
++ .asciz "Samsung-S3C44B0x"
++ .size cpu_s3c44b0x_name, . - cpu_s3c44b0x_name
++
++ .type cpu_s3c4510b, #object
++cpu_s3c4510b_name:
++ .asciz "Samsung-S3C4510B"
++ .size cpu_s3c4510b_name, . - cpu_s3c4510b_name
++
++ .type cpu_s3c4530_name, #object
++cpu_s3c4530_name:
++ .asciz "Samsung-S3C4530"
++ .size cpu_s3c4530_name, . - cpu_s3c4530_name
++
++ .type cpu_netarm_name, #object
++cpu_netarm_name:
++ .asciz "NETARM"
++ .size cpu_netarm_name, . - cpu_netarm_name
++
++ .align
++
++ .section ".proc.info.init", #alloc, #execinstr
++
++ .type __arm7tdmi_proc_info, #object
++__arm7tdmi_proc_info:
++ .long 0x41007700
++ .long 0xfff8ff00
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_26BIT
++ .long cpu_arm7tdmi_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __arm7tdmi_proc_info, . - __arm7dmi_proc_info
++
++ .type __triscenda7_proc_info, #object
++__triscenda7_proc_info:
++ .long 0x0001d2ff
++ .long 0x0001ffff
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_triscenda7_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __triscenda7_proc_info, . - __triscenda7_proc_info
++
++ .type __at91_proc_info, #object
++__at91_proc_info:
++ .long 0x14000040
++ .long 0xfff000e0
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_at91_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __at91_proc_info, . - __at91_proc_info
++
++ .type __s3c4510b_proc_info, #object
++__s3c4510b_proc_info:
++ .long 0x36365000
++ .long 0xfffff000
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_s3c4510b_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __s3c4510b_proc_info, . - __s3c4510b_proc_info
++
++ .type __s3c4530_proc_info, #object
++__s3c4530_proc_info:
++ .long 0x4c000000
++ .long 0xfff000e0
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_s3c4530_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __s3c4530_proc_info, . - __s3c4530_proc_info
++
++ .type __s3c3410_proc_info, #object
++__s3c3410_proc_info:
++ .long 0x34100000
++ .long 0xffff0000
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_s3c3410_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __s3c3410_proc_info, . - __s3c3410_proc_info
++
++ .type __s3c44b0x_proc_info, #object
++__s3c44b0x_proc_info:
++ .long 0x44b00000
++ .long 0xffff0000
++ .long 0
++ .long 0
++ b __arm7tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_s3c44b0x_name
++ .long arm7tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __s3c44b0x_proc_info, . - __s3c44b0x_proc_info
+diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
+new file mode 100644
+index 0000000..2397f4b
+--- /dev/null
++++ b/arch/arm/mm/proc-arm940.S
+@@ -0,0 +1,369 @@
++/*
++ * linux/arch/arm/mm/arm940.S: utility functions for ARM940T
++ *
++ * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi at samsung.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/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/procinfo.h>
++#include <asm/ptrace.h>
++
++/* ARM940T has a 4KB DCache comprising 256 lines of 4 words */
++#define CACHE_DLINESIZE 16
++#define CACHE_DSEGMENTS 4
++#define CACHE_DENTRIES 64
++
++ .text
++/*
++ * cpu_arm940_proc_init()
++ * cpu_arm940_switch_mm()
++ *
++ * These are not required.
++ */
++ENTRY(cpu_arm940_proc_init)
++ENTRY(cpu_arm940_switch_mm)
++ mov pc, lr
++
++/*
++ * cpu_arm940_proc_fin()
++ */
++ENTRY(cpu_arm940_proc_fin)
++ stmfd sp!, {lr}
++ mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++ msr cpsr_c, ip
++ bl arm940_flush_kern_cache_all
++ mrc p15, 0, r0, c1, c0, 0 @ ctrl register
++ bic r0, r0, #0x00001000 @ i-cache
++ bic r0, r0, #0x00000004 @ d-cache
++ mcr p15, 0, r0, c1, c0, 0 @ disable caches
++ ldmfd sp!, {pc}
++
++/*
++ * cpu_arm940_reset(loc)
++ * Params : r0 = address to jump to
++ * Notes : This sets up everything for a reset
++ */
++ENTRY(cpu_arm940_reset)
++ mov ip, #0
++ mcr p15, 0, ip, c7, c5, 0 @ flush I cache
++ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
++ mcr p15, 0, ip, c7, c10, 4 @ drain WB
++ mrc p15, 0, ip, c1, c0, 0 @ ctrl register
++ bic ip, ip, #0x00000005 @ .............c.p
++ bic ip, ip, #0x00001000 @ i-cache
++ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
++ mov pc, r0
++
++/*
++ * cpu_arm940_do_idle()
++ */
++ .align 5
++ENTRY(cpu_arm940_do_idle)
++ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
++ mov pc, lr
++
++/*
++ * flush_user_cache_all()
++ */
++ENTRY(arm940_flush_user_cache_all)
++ /* FALLTHROUGH */
++
++/*
++ * flush_kern_cache_all()
++ *
++ * Clean and invalidate the entire cache.
++ */
++ENTRY(arm940_flush_kern_cache_all)
++ mov r2, #VM_EXEC
++ /* FALLTHROUGH */
++
++/*
++ * flush_user_cache_range(start, end, flags)
++ *
++ * There is no efficient way to flush a range of cache entries
++ * in the specified address range. Thus, flushes all.
++ *
++ * - start - start address (inclusive)
++ * - end - end address (exclusive)
++ * - flags - vm_flags describing address space
++ */
++ENTRY(arm940_flush_user_cache_range)
++ mov ip, #0
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
++#else
++ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
++1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
++2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index
++ subs r3, r3, #1 << 26
++ bcs 2b @ entries 63 to 0
++ subs r1, r1, #1 << 4
++ bcs 1b @ segments 3 to 0
++#endif
++ tst r2, #VM_EXEC
++ mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
++ mcrne p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * coherent_kern_range(start, end)
++ *
++ * Ensure coherency between the Icache and the Dcache in the
++ * region described by start, end. If you have non-snooping
++ * Harvard caches, you need to implement this function.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ */
++ENTRY(arm940_coherent_kern_range)
++ /* FALLTHROUGH */
++
++/*
++ * coherent_user_range(start, end)
++ *
++ * Ensure coherency between the Icache and the Dcache in the
++ * region described by start, end. If you have non-snooping
++ * Harvard caches, you need to implement this function.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ */
++ENTRY(arm940_coherent_user_range)
++ /* FALLTHROUGH */
++
++/*
++ * flush_kern_dcache_page(void *page)
++ *
++ * Ensure no D cache aliasing occurs, either with itself or
++ * the I cache
++ *
++ * - addr - page aligned address
++ */
++ENTRY(arm940_flush_kern_dcache_page)
++ mov ip, #0
++ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
++1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
++2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index
++ subs r3, r3, #1 << 26
++ bcs 2b @ entries 63 to 0
++ subs r1, r1, #1 << 4
++ bcs 1b @ segments 7 to 0
++ mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
++ mcr p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * dma_inv_range(start, end)
++ *
++ * There is no efficient way to invalidate a specifid virtual
++ * address range. Thus, invalidates all.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ */
++ENTRY(arm940_dma_inv_range)
++ mov ip, #0
++ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
++1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
++2: mcr p15, 0, r3, c7, c6, 2 @ flush D entry
++ subs r3, r3, #1 << 26
++ bcs 2b @ entries 63 to 0
++ subs r1, r1, #1 << 4
++ bcs 1b @ segments 7 to 0
++ mcr p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * dma_clean_range(start, end)
++ *
++ * There is no efficient way to clean a specifid virtual
++ * address range. Thus, cleans all.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ */
++ENTRY(arm940_dma_clean_range)
++ENTRY(cpu_arm940_dcache_clean_area)
++ mov ip, #0
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
++1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
++2: mcr p15, 0, r3, c7, c10, 2 @ clean D entry
++ subs r3, r3, #1 << 26
++ bcs 2b @ entries 63 to 0
++ subs r1, r1, #1 << 4
++ bcs 1b @ segments 7 to 0
++#endif
++ mcr p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * dma_flush_range(start, end)
++ *
++ * There is no efficient way to clean and invalidate a specifid
++ * virtual address range.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ */
++ENTRY(arm940_dma_flush_range)
++ mov ip, #0
++ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
++1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
++2:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mcr p15, 0, r3, c7, c14, 2 @ clean/flush D entry
++#else
++ mcr p15, 0, r3, c7, c10, 2 @ clean D entry
++#endif
++ subs r3, r3, #1 << 26
++ bcs 2b @ entries 63 to 0
++ subs r1, r1, #1 << 4
++ bcs 1b @ segments 7 to 0
++ mcr p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++ENTRY(arm940_cache_fns)
++ .long arm940_flush_kern_cache_all
++ .long arm940_flush_user_cache_all
++ .long arm940_flush_user_cache_range
++ .long arm940_coherent_kern_range
++ .long arm940_coherent_user_range
++ .long arm940_flush_kern_dcache_page
++ .long arm940_dma_inv_range
++ .long arm940_dma_clean_range
++ .long arm940_dma_flush_range
++
++ __INIT
++
++ .type __arm940_setup, #function
++__arm940_setup:
++ mov r0, #0
++ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
++ mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++
++ mcr p15, 0, r0, c6, c3, 0 @ disable data area 3~7
++ mcr p15, 0, r0, c6, c4, 0
++ mcr p15, 0, r0, c6, c5, 0
++ mcr p15, 0, r0, c6, c6, 0
++ mcr p15, 0, r0, c6, c7, 0
++
++ mcr p15, 0, r0, c6, c3, 1 @ disable instruction area 3~7
++ mcr p15, 0, r0, c6, c4, 1
++ mcr p15, 0, r0, c6, c5, 1
++ mcr p15, 0, r0, c6, c6, 1
++ mcr p15, 0, r0, c6, c7, 1
++
++ mov r0, #0x0000003F @ base = 0, size = 4GB
++ mcr p15, 0, r0, c6, c0, 0 @ set area 0, default
++ mcr p15, 0, r0, c6, c0, 1
++
++ ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
++ ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
++ mov r2, #10 @ 11 is the minimum (4KB)
++1: add r2, r2, #1 @ area size *= 2
++ mov r1, r1, lsr #1
++ bne 1b @ count not zero r-shift
++ orr r0, r0, r2, lsl #1 @ the area register value
++ orr r0, r0, #1 @ set enable bit
++ mcr p15, 0, r0, c6, c1, 0 @ set area 1, RAM
++ mcr p15, 0, r0, c6, c1, 1
++
++ ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
++ ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
++ mov r2, #10 @ 11 is the minimum (4KB)
++1: add r2, r2, #1 @ area size *= 2
++ mov r1, r1, lsr #1
++ bne 1b @ count not zero r-shift
++ orr r0, r0, r2, lsl #1 @ the area register value
++ orr r0, r0, #1 @ set enable bit
++ mcr p15, 0, r0, c6, c2, 0 @ set area 2, ROM/FLASH
++ mcr p15, 0, r0, c6, c2, 1
++
++ mov r0, #0x06
++ mcr p15, 0, r0, c2, c0, 0 @ Region 1&2 cacheable
++ mcr p15, 0, r0, c2, c0, 1
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mov r0, #0x00 @ disable whole write buffer
++#else
++ mov r0, #0x02 @ Region 1 write bufferred
++#endif
++ mcr p15, 0, r0, c3, c0, 0
++
++ mov r0, #0x10000
++ sub r0, r0, #1 @ r0 = 0xffff
++ mcr p15, 0, r0, c5, c0, 0 @ all read/write access
++ mcr p15, 0, r0, c5, c0, 1
++
++ mrc p15, 0, r0, c1, c0 @ get control register
++ orr r0, r0, #0x00001000 @ I-cache
++ orr r0, r0, #0x00000005 @ MPU/D-cache
++
++ mov pc, lr
++
++ .size __arm940_setup, . - __arm940_setup
++
++ __INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ * come through these
++ */
++ .type arm940_processor_functions, #object
++ENTRY(arm940_processor_functions)
++ .word nommu_early_abort
++ .word cpu_arm940_proc_init
++ .word cpu_arm940_proc_fin
++ .word cpu_arm940_reset
++ .word cpu_arm940_do_idle
++ .word cpu_arm940_dcache_clean_area
++ .word cpu_arm940_switch_mm
++ .word 0 @ cpu_*_set_pte
++ .size arm940_processor_functions, . - arm940_processor_functions
++
++ .section ".rodata"
++
++.type cpu_arch_name, #object
++cpu_arch_name:
++ .asciz "armv4t"
++ .size cpu_arch_name, . - cpu_arch_name
++
++ .type cpu_elf_name, #object
++cpu_elf_name:
++ .asciz "v4"
++ .size cpu_elf_name, . - cpu_elf_name
++
++ .type cpu_arm940_name, #object
++cpu_arm940_name:
++ .ascii "ARM940T"
++ .size cpu_arm940_name, . - cpu_arm940_name
++
++ .align
++
++ .section ".proc.info.init", #alloc, #execinstr
++
++ .type __arm940_proc_info,#object
++__arm940_proc_info:
++ .long 0x41009400
++ .long 0xff00fff0
++ .long 0
++ b __arm940_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
++ .long cpu_arm940_name
++ .long arm940_processor_functions
++ .long 0
++ .long 0
++ .long arm940_cache_fns
++ .size __arm940_proc_info, . - __arm940_proc_info
++
+diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
+new file mode 100644
+index 0000000..e186175
+--- /dev/null
++++ b/arch/arm/mm/proc-arm946.S
+@@ -0,0 +1,424 @@
++/*
++ * linux/arch/arm/mm/arm946.S: utility functions for ARM946E-S
++ *
++ * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi at samsung.com)
++ *
++ * (Many of cache codes are from proc-arm926.S)
++ *
++ * 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/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/procinfo.h>
++#include <asm/ptrace.h>
++
++/*
++ * ARM946E-S is synthesizable to have 0KB to 1MB sized D-Cache,
++ * comprising 256 lines of 32 bytes (8 words).
++ */
++#define CACHE_DSIZE (CONFIG_CPU_DCACHE_SIZE) /* typically 8KB. */
++#define CACHE_DLINESIZE 32 /* fixed */
++#define CACHE_DSEGMENTS 4 /* fixed */
++#define CACHE_DENTRIES (CACHE_DSIZE / CACHE_DSEGMENTS / CACHE_DLINESIZE)
++#define CACHE_DLIMIT (CACHE_DSIZE * 4) /* benchmark needed */
++
++ .text
++/*
++ * cpu_arm946_proc_init()
++ * cpu_arm946_switch_mm()
++ *
++ * These are not required.
++ */
++ENTRY(cpu_arm946_proc_init)
++ENTRY(cpu_arm946_switch_mm)
++ mov pc, lr
++
++/*
++ * cpu_arm946_proc_fin()
++ */
++ENTRY(cpu_arm946_proc_fin)
++ stmfd sp!, {lr}
++ mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++ msr cpsr_c, ip
++ bl arm946_flush_kern_cache_all
++ mrc p15, 0, r0, c1, c0, 0 @ ctrl register
++ bic r0, r0, #0x00001000 @ i-cache
++ bic r0, r0, #0x00000004 @ d-cache
++ mcr p15, 0, r0, c1, c0, 0 @ disable caches
++ ldmfd sp!, {pc}
++
++/*
++ * cpu_arm946_reset(loc)
++ * Params : r0 = address to jump to
++ * Notes : This sets up everything for a reset
++ */
++ENTRY(cpu_arm946_reset)
++ mov ip, #0
++ mcr p15, 0, ip, c7, c5, 0 @ flush I cache
++ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
++ mcr p15, 0, ip, c7, c10, 4 @ drain WB
++ mrc p15, 0, ip, c1, c0, 0 @ ctrl register
++ bic ip, ip, #0x00000005 @ .............c.p
++ bic ip, ip, #0x00001000 @ i-cache
++ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
++ mov pc, r0
++
++/*
++ * cpu_arm946_do_idle()
++ */
++ .align 5
++ENTRY(cpu_arm946_do_idle)
++ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
++ mov pc, lr
++
++/*
++ * flush_user_cache_all()
++ */
++ENTRY(arm946_flush_user_cache_all)
++ /* FALLTHROUGH */
++
++/*
++ * flush_kern_cache_all()
++ *
++ * Clean and invalidate the entire cache.
++ */
++ENTRY(arm946_flush_kern_cache_all)
++ mov r2, #VM_EXEC
++ mov ip, #0
++__flush_whole_cache:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
++#else
++ mov r1, #(CACHE_DSEGMENTS - 1) << 29 @ 4 segments
++1: orr r3, r1, #(CACHE_DENTRIES - 1) << 4 @ n entries
++2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index
++ subs r3, r3, #1 << 4
++ bcs 2b @ entries n to 0
++ subs r1, r1, #1 << 29
++ bcs 1b @ segments 3 to 0
++#endif
++ tst r2, #VM_EXEC
++ mcrne p15, 0, ip, c7, c5, 0 @ flush I cache
++ mcrne p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * flush_user_cache_range(start, end, flags)
++ *
++ * Clean and invalidate a range of cache entries in the
++ * specified address range.
++ *
++ * - start - start address (inclusive)
++ * - end - end address (exclusive)
++ * - flags - vm_flags describing address space
++ * (same as arm926)
++ */
++ENTRY(arm946_flush_user_cache_range)
++ mov ip, #0
++ sub r3, r1, r0 @ calculate total size
++ cmp r3, #CACHE_DLIMIT
++ bhs __flush_whole_cache
++
++1: tst r2, #VM_EXEC
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
++ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
++ add r0, r0, #CACHE_DLINESIZE
++ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
++ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
++ add r0, r0, #CACHE_DLINESIZE
++#else
++ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
++ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
++ add r0, r0, #CACHE_DLINESIZE
++ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
++ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
++ add r0, r0, #CACHE_DLINESIZE
++#endif
++ cmp r0, r1
++ blo 1b
++ tst r2, #VM_EXEC
++ mcrne p15, 0, ip, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * coherent_kern_range(start, end)
++ *
++ * Ensure coherency between the Icache and the Dcache in the
++ * region described by start, end. If you have non-snooping
++ * Harvard caches, you need to implement this function.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ */
++ENTRY(arm946_coherent_kern_range)
++ /* FALLTHROUGH */
++
++/*
++ * coherent_user_range(start, end)
++ *
++ * Ensure coherency between the Icache and the Dcache in the
++ * region described by start, end. If you have non-snooping
++ * Harvard caches, you need to implement this function.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ * (same as arm926)
++ */
++ENTRY(arm946_coherent_user_range)
++ bic r0, r0, #CACHE_DLINESIZE - 1
++1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
++ mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
++ add r0, r0, #CACHE_DLINESIZE
++ cmp r0, r1
++ blo 1b
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * flush_kern_dcache_page(void *page)
++ *
++ * Ensure no D cache aliasing occurs, either with itself or
++ * the I cache
++ *
++ * - addr - page aligned address
++ * (same as arm926)
++ */
++ENTRY(arm946_flush_kern_dcache_page)
++ add r1, r0, #PAGE_SZ
++1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
++ add r0, r0, #CACHE_DLINESIZE
++ cmp r0, r1
++ blo 1b
++ mov r0, #0
++ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * dma_inv_range(start, end)
++ *
++ * Invalidate (discard) the specified virtual address range.
++ * May not write back any entries. If 'start' or 'end'
++ * are not cache line aligned, those lines must be written
++ * back.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ * (same as arm926)
++ */
++ENTRY(arm946_dma_inv_range)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++ tst r0, #CACHE_DLINESIZE - 1
++ mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
++ tst r1, #CACHE_DLINESIZE - 1
++ mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
++#endif
++ bic r0, r0, #CACHE_DLINESIZE - 1
++1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
++ add r0, r0, #CACHE_DLINESIZE
++ cmp r0, r1
++ blo 1b
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * dma_clean_range(start, end)
++ *
++ * Clean the specified virtual address range.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ *
++ * (same as arm926)
++ */
++ENTRY(arm946_dma_clean_range)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++ bic r0, r0, #CACHE_DLINESIZE - 1
++1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
++ add r0, r0, #CACHE_DLINESIZE
++ cmp r0, r1
++ blo 1b
++#endif
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++/*
++ * dma_flush_range(start, end)
++ *
++ * Clean and invalidate the specified virtual address range.
++ *
++ * - start - virtual start address
++ * - end - virtual end address
++ *
++ * (same as arm926)
++ */
++ENTRY(arm946_dma_flush_range)
++ bic r0, r0, #CACHE_DLINESIZE - 1
++1:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
++#else
++ mcr p15, 0, r0, c7, c10, 1 @ clean D entry
++#endif
++ add r0, r0, #CACHE_DLINESIZE
++ cmp r0, r1
++ blo 1b
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++ENTRY(arm946_cache_fns)
++ .long arm946_flush_kern_cache_all
++ .long arm946_flush_user_cache_all
++ .long arm946_flush_user_cache_range
++ .long arm946_coherent_kern_range
++ .long arm946_coherent_user_range
++ .long arm946_flush_kern_dcache_page
++ .long arm946_dma_inv_range
++ .long arm946_dma_clean_range
++ .long arm946_dma_flush_range
++
++
++ENTRY(cpu_arm946_dcache_clean_area)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
++ add r0, r0, #CACHE_DLINESIZE
++ subs r1, r1, #CACHE_DLINESIZE
++ bhi 1b
++#endif
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mov pc, lr
++
++ __INIT
++
++ .type __arm946_setup, #function
++__arm946_setup:
++ mov r0, #0
++ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
++ mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++
++ mcr p15, 0, r0, c6, c3, 0 @ disable memory region 3~7
++ mcr p15, 0, r0, c6, c4, 0
++ mcr p15, 0, r0, c6, c5, 0
++ mcr p15, 0, r0, c6, c6, 0
++ mcr p15, 0, r0, c6, c7, 0
++
++ mov r0, #0x0000003F @ base = 0, size = 4GB
++ mcr p15, 0, r0, c6, c0, 0 @ set region 0, default
++
++ ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
++ ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
++ mov r2, #10 @ 11 is the minimum (4KB)
++1: add r2, r2, #1 @ area size *= 2
++ mov r1, r1, lsr #1
++ bne 1b @ count not zero r-shift
++ orr r0, r0, r2, lsl #1 @ the region register value
++ orr r0, r0, #1 @ set enable bit
++ mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM
++
++ ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
++ ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
++ mov r2, #10 @ 11 is the minimum (4KB)
++1: add r2, r2, #1 @ area size *= 2
++ mov r1, r1, lsr #1
++ bne 1b @ count not zero r-shift
++ orr r0, r0, r2, lsl #1 @ the region register value
++ orr r0, r0, #1 @ set enable bit
++ mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH
++
++ mov r0, #0x06
++ mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable
++ mcr p15, 0, r0, c2, c0, 1 @ region 1,2 i-cacheable
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++ mov r0, #0x00 @ disable whole write buffer
++#else
++ mov r0, #0x02 @ region 1 write bufferred
++#endif
++ mcr p15, 0, r0, c3, c0, 0
++
++/*
++ * Access Permission Settings for future permission control by PU.
++ *
++ * priv. user
++ * region 0 (whole) rw -- : b0001
++ * region 1 (RAM) rw rw : b0011
++ * region 2 (FLASH) rw r- : b0010
++ * region 3~7 (none) -- -- : b0000
++ */
++ mov r0, #0x00000031
++ orr r0, r0, #0x00000200
++ mcr p15, 0, r0, c5, c0, 2 @ set data access permission
++ mcr p15, 0, r0, c5, c0, 3 @ set inst. access permission
++
++ mrc p15, 0, r0, c1, c0 @ get control register
++ orr r0, r0, #0x00001000 @ I-cache
++ orr r0, r0, #0x00000005 @ MPU/D-cache
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++ orr r0, r0, #0x00004000 @ .1.. .... .... ....
++#endif
++ mov pc, lr
++
++ .size __arm946_setup, . - __arm946_setup
++
++ __INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ * come through these
++ */
++ .type arm946_processor_functions, #object
++ENTRY(arm946_processor_functions)
++ .word nommu_early_abort
++ .word cpu_arm946_proc_init
++ .word cpu_arm946_proc_fin
++ .word cpu_arm946_reset
++ .word cpu_arm946_do_idle
++
++ .word cpu_arm946_dcache_clean_area
++ .word cpu_arm946_switch_mm
++ .word 0 @ cpu_*_set_pte
++ .size arm946_processor_functions, . - arm946_processor_functions
++
++ .section ".rodata"
++
++ .type cpu_arch_name, #object
++cpu_arch_name:
++ .asciz "armv5te"
++ .size cpu_arch_name, . - cpu_arch_name
++
++ .type cpu_elf_name, #object
++cpu_elf_name:
++ .asciz "v5t"
++ .size cpu_elf_name, . - cpu_elf_name
++
++ .type cpu_arm946_name, #object
++cpu_arm946_name:
++ .ascii "ARM946E-S"
++ .size cpu_arm946_name, . - cpu_arm946_name
++
++ .align
++
++ .section ".proc.info.init", #alloc, #execinstr
++ .type __arm946_proc_info,#object
++__arm946_proc_info:
++ .long 0x41009460
++ .long 0xff00fff0
++ .long 0
++ b __arm946_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
++ .long cpu_arm946_name
++ .long arm946_processor_functions
++ .long 0
++ .long 0
++ .long arm940_cache_fns
++ .size __arm946_proc_info, . - __arm946_proc_info
++
+diff --git a/arch/arm/mm/proc-arm9tdmi.S b/arch/arm/mm/proc-arm9tdmi.S
+new file mode 100644
+index 0000000..918ebf6
+--- /dev/null
++++ b/arch/arm/mm/proc-arm9tdmi.S
+@@ -0,0 +1,134 @@
++/*
++ * linux/arch/arm/mm/proc-arm9tdmi.S: utility functions for ARM9TDMI
++ *
++ * Copyright (C) 2003-2006 Hyok S. Choi <hyok.choi at samsung.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/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/asm-offsets.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/procinfo.h>
++#include <asm/ptrace.h>
++
++ .text
++/*
++ * cpu_arm9tdmi_proc_init()
++ * cpu_arm9tdmi_do_idle()
++ * cpu_arm9tdmi_dcache_clean_area()
++ * cpu_arm9tdmi_switch_mm()
++ *
++ * These are not required.
++ */
++ENTRY(cpu_arm9tdmi_proc_init)
++ENTRY(cpu_arm9tdmi_do_idle)
++ENTRY(cpu_arm9tdmi_dcache_clean_area)
++ENTRY(cpu_arm9tdmi_switch_mm)
++ mov pc, lr
++
++/*
++ * cpu_arm9tdmi_proc_fin()
++ */
++ENTRY(cpu_arm9tdmi_proc_fin)
++ mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++ msr cpsr_c, r0
++ mov pc, lr
++
++/*
++ * Function: cpu_arm9tdmi_reset(loc)
++ * Params : loc(r0) address to jump to
++ * Purpose : Sets up everything for a reset and jump to the location for soft reset.
++ */
++ENTRY(cpu_arm9tdmi_reset)
++ mov pc, r0
++
++ __INIT
++
++ .type __arm9tdmi_setup, #function
++__arm9tdmi_setup:
++ mov pc, lr
++ .size __arm9tdmi_setup, . - __arm9tdmi_setup
++
++ __INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ * come through these
++ */
++ .type arm9tdmi_processor_functions, #object
++ENTRY(arm9tdmi_processor_functions)
++ .word nommu_early_abort
++ .word cpu_arm9tdmi_proc_init
++ .word cpu_arm9tdmi_proc_fin
++ .word cpu_arm9tdmi_reset
++ .word cpu_arm9tdmi_do_idle
++ .word cpu_arm9tdmi_dcache_clean_area
++ .word cpu_arm9tdmi_switch_mm
++ .word 0 @ cpu_*_set_pte
++ .size arm9tdmi_processor_functions, . - arm9tdmi_processor_functions
++
++ .section ".rodata"
++
++ .type cpu_arch_name, #object
++cpu_arch_name:
++ .asciz "armv4t"
++ .size cpu_arch_name, . - cpu_arch_name
++
++ .type cpu_elf_name, #object
++cpu_elf_name:
++ .asciz "v4"
++ .size cpu_elf_name, . - cpu_elf_name
++
++ .type cpu_arm9tdmi_name, #object
++cpu_arm9tdmi_name:
++ .asciz "ARM9TDMI"
++ .size cpu_arm9tdmi_name, . - cpu_arm9tdmi_name
++
++ .type cpu_p2001_name, #object
++cpu_p2001_name:
++ .asciz "P2001"
++ .size cpu_p2001_name, . - cpu_p2001_name
++
++ .align
++
++ .section ".proc.info.init", #alloc, #execinstr
++
++ .type __arm9tdmi_proc_info, #object
++__arm9tdmi_proc_info:
++ .long 0x41009900
++ .long 0xfff8ff00
++ .long 0
++ .long 0
++ b __arm9tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_arm9tdmi_name
++ .long arm9tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __arm9tdmi_proc_info, . - __arm9dmi_proc_info
++
++ .type __p2001_proc_info, #object
++__p2001_proc_info:
++ .long 0x41029000
++ .long 0xffffffff
++ .long 0
++ .long 0
++ b __arm9tdmi_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
++ .long cpu_p2001_name
++ .long arm9tdmi_processor_functions
++ .long 0
++ .long 0
++ .long v4_cache_fns
++ .size __p2001_proc_info, . - __p2001_proc_info
+diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
+index 3ca0c92..2749c1f 100644
+--- a/arch/arm/mm/proc-xscale.S
++++ b/arch/arm/mm/proc-xscale.S
+@@ -311,12 +311,6 @@ ENTRY(xscale_flush_kern_dcache_page)
+ * - end - virtual end address
+ */
+ ENTRY(xscale_dma_inv_range)
+- mrc p15, 0, r2, c0, c0, 0 @ read ID
+- eor r2, r2, #0x69000000
+- eor r2, r2, #0x00052000
+- bics r2, r2, #1
+- beq xscale_dma_flush_range
+-
+ tst r0, #CACHELINESIZE - 1
+ bic r0, r0, #CACHELINESIZE - 1
+ mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
+@@ -375,6 +369,30 @@ ENTRY(xscale_cache_fns)
+ .long xscale_dma_clean_range
+ .long xscale_dma_flush_range
+
++/*
++ * On stepping A0/A1 of the 80200, invalidating D-cache by line doesn't
++ * clear the dirty bits, which means that if we invalidate a dirty line,
++ * the dirty data can still be written back to external memory later on.
++ *
++ * The recommended workaround is to always do a clean D-cache line before
++ * doing an invalidate D-cache line, so on the affected processors,
++ * dma_inv_range() is implemented as dma_flush_range().
++ *
++ * See erratum #25 of "Intel 80200 Processor Specification Update",
++ * revision January 22, 2003, available at:
++ * http://www.intel.com/design/iio/specupdt/273415.htm
++ */
++ENTRY(xscale_80200_A0_A1_cache_fns)
++ .long xscale_flush_kern_cache_all
++ .long xscale_flush_user_cache_all
++ .long xscale_flush_user_cache_range
++ .long xscale_coherent_kern_range
++ .long xscale_coherent_user_range
++ .long xscale_flush_kern_dcache_page
++ .long xscale_dma_flush_range
++ .long xscale_dma_clean_range
++ .long xscale_dma_flush_range
++
+ ENTRY(cpu_xscale_dcache_clean_area)
+ 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ add r0, r0, #CACHELINESIZE
+@@ -531,6 +549,11 @@ cpu_elf_name:
+ .asciz "v5"
+ .size cpu_elf_name, . - cpu_elf_name
+
++ .type cpu_80200_A0_A1_name, #object
++cpu_80200_A0_A1_name:
++ .asciz "XScale-80200 A0/A1"
++ .size cpu_80200_A0_A1_name, . - cpu_80200_A0_A1_name
++
+ .type cpu_80200_name, #object
+ cpu_80200_name:
+ .asciz "XScale-80200"
+@@ -595,6 +618,29 @@ cpu_pxa270_name:
+
+ .section ".proc.info.init", #alloc, #execinstr
+
++ .type __80200_A0_A1_proc_info,#object
++__80200_A0_A1_proc_info:
++ .long 0x69052000
++ .long 0xfffffffe
++ .long PMD_TYPE_SECT | \
++ PMD_SECT_BUFFERABLE | \
++ PMD_SECT_CACHEABLE | \
++ PMD_SECT_AP_WRITE | \
++ PMD_SECT_AP_READ
++ .long PMD_TYPE_SECT | \
++ PMD_SECT_AP_WRITE | \
++ PMD_SECT_AP_READ
++ b __xscale_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
++ .long cpu_80200_name
++ .long xscale_processor_functions
++ .long v4wbi_tlb_fns
++ .long xscale_mc_user_fns
++ .long xscale_80200_A0_A1_cache_fns
++ .size __80200_A0_A1_proc_info, . - __80200_A0_A1_proc_info
++
+ .type __80200_proc_info,#object
+ __80200_proc_info:
+ .long 0x69052000
+@@ -863,7 +909,7 @@ __pxa270_proc_info:
+ b __xscale_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+- .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_IWMMXT
+ .long cpu_pxa270_name
+ .long xscale_processor_functions
+ .long v4wbi_tlb_fns
+diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c
+index 34fdc73..7c3289c 100644
+--- a/arch/arm/oprofile/op_model_xscale.c
++++ b/arch/arm/oprofile/op_model_xscale.c
+@@ -20,7 +20,8 @@
+ #include <linux/sched.h>
+ #include <linux/oprofile.h>
+ #include <linux/interrupt.h>
+-#include <asm/irq.h>
++#include <linux/irq.h>
++
+ #include <asm/system.h>
+
+ #include "op_counter.h"
+@@ -33,14 +34,11 @@
+ #define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */
+
+ /* TODO do runtime detection */
+-#ifdef CONFIG_ARCH_IOP310
+-#define XSCALE_PMU_IRQ IRQ_XS80200_PMU
+-#endif
+-#ifdef CONFIG_ARCH_IOP321
+-#define XSCALE_PMU_IRQ IRQ_IOP321_CORE_PMU
++#ifdef CONFIG_ARCH_IOP32X
++#define XSCALE_PMU_IRQ IRQ_IOP32X_CORE_PMU
+ #endif
+-#ifdef CONFIG_ARCH_IOP331
+-#define XSCALE_PMU_IRQ IRQ_IOP331_CORE_PMU
++#ifdef CONFIG_ARCH_IOP33X
++#define XSCALE_PMU_IRQ IRQ_IOP33X_CORE_PMU
+ #endif
+ #ifdef CONFIG_ARCH_PXA
+ #define XSCALE_PMU_IRQ IRQ_PMU
+@@ -88,7 +86,7 @@ static struct pmu_counter results[MAX_CO
+ /*
+ * There are two versions of the PMU in current XScale processors
+ * with differing register layouts and number of performance counters.
+- * e.g. IOP321 is xsc1 whilst IOP331 is xsc2.
++ * e.g. IOP32x is xsc1 whilst IOP33x is xsc2.
+ * We detect which register layout to use in xscale_detect_pmu()
+ */
+ enum { PMU_XSC1, PMU_XSC2 };
+@@ -344,7 +342,7 @@ static void inline __xsc2_check_ctrs(voi
+ __asm__ __volatile__ ("mcr p14, 0, %0, c5, c1, 0" : : "r" (flag));
+ }
+
+-static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
+ {
+ int i;
+ u32 pmnc;
+@@ -359,7 +357,7 @@ static irqreturn_t xscale_pmu_interrupt(
+ continue;
+
+ write_counter(i, -(u32)results[i].reset_counter);
+- oprofile_add_sample(regs, i);
++ oprofile_add_sample(get_irq_regs(), i);
+ results[i].ovf--;
+ }
+
+diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile
+new file mode 100644
+index 0000000..23da00b
+--- /dev/null
++++ b/arch/arm/plat-iop/Makefile
+@@ -0,0 +1,8 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y := gpio.o i2c.o pci.o setup.o time.o
++obj-m :=
++obj-n :=
++obj- :=
+diff --git a/arch/arm/plat-iop/gpio.c b/arch/arm/plat-iop/gpio.c
+new file mode 100644
+index 0000000..eda4360
+--- /dev/null
++++ b/arch/arm/plat-iop/gpio.c
+@@ -0,0 +1,48 @@
++/*
++ * arch/arm/plat-iop/gpio.c
++ * GPIO handling for Intel IOP3xx processors.
++ *
++ * Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.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
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/device.h>
++#include <asm/hardware/iop3xx.h>
++
++void gpio_line_config(int line, int direction)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ if (direction == GPIO_IN) {
++ *IOP3XX_GPOE |= 1 << line;
++ } else if (direction == GPIO_OUT) {
++ *IOP3XX_GPOE &= ~(1 << line);
++ }
++ local_irq_restore(flags);
++}
++EXPORT_SYMBOL(gpio_line_config);
++
++int gpio_line_get(int line)
++{
++ return !!(*IOP3XX_GPID & (1 << line));
++}
++EXPORT_SYMBOL(gpio_line_get);
++
++void gpio_line_set(int line, int value)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ if (value == GPIO_LOW) {
++ *IOP3XX_GPOD &= ~(1 << line);
++ } else if (value == GPIO_HIGH) {
++ *IOP3XX_GPOD |= 1 << line;
++ }
++ local_irq_restore(flags);
++}
++EXPORT_SYMBOL(gpio_line_set);
+diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/plat-iop/i2c.c
+new file mode 100644
+index 0000000..e99909b
+--- /dev/null
++++ b/arch/arm/plat-iop/i2c.c
+@@ -0,0 +1,81 @@
++/*
++ * arch/arm/plat-iop/i2c.c
++ *
++ * Author: Nicolas Pitre <nico at cam.org>
++ * Copyright (C) 2001 MontaVista Software, Inc.
++ * 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.
++ */
++
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/platform_device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_core.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/mach/map.h>
++#include <asm/setup.h>
++#include <asm/system.h>
++#include <asm/memory.h>
++#include <asm/hardware.h>
++#include <asm/hardware/iop3xx.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++
++#ifdef CONFIG_ARCH_IOP32X
++#define IRQ_IOP3XX_I2C_0 IRQ_IOP32X_I2C_0
++#define IRQ_IOP3XX_I2C_1 IRQ_IOP32X_I2C_1
++#endif
++#ifdef CONFIG_ARCH_IOP33X
++#define IRQ_IOP3XX_I2C_0 IRQ_IOP33X_I2C_0
++#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1
++#endif
++
++static struct resource iop3xx_i2c0_resources[] = {
++ [0] = {
++ .start = 0xfffff680,
++ .end = 0xfffff697,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_IOP3XX_I2C_0,
++ .end = IRQ_IOP3XX_I2C_0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++struct platform_device iop3xx_i2c0_device = {
++ .name = "IOP3xx-I2C",
++ .id = 0,
++ .num_resources = 2,
++ .resource = iop3xx_i2c0_resources,
++};
++
++
++static struct resource iop3xx_i2c1_resources[] = {
++ [0] = {
++ .start = 0xfffff6a0,
++ .end = 0xfffff6b7,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_IOP3XX_I2C_1,
++ .end = IRQ_IOP3XX_I2C_1,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++struct platform_device iop3xx_i2c1_device = {
++ .name = "IOP3xx-I2C",
++ .id = 1,
++ .num_resources = 2,
++ .resource = iop3xx_i2c1_resources,
++};
+diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
+new file mode 100644
+index 0000000..e647812
+--- /dev/null
++++ b/arch/arm/plat-iop/pci.c
+@@ -0,0 +1,247 @@
++/*
++ * arch/arm/plat-iop/pci.c
++ *
++ * PCI support for the Intel IOP32X and IOP33X processors
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ *
++ * 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/pci.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/mach/pci.h>
++#include <asm/hardware/iop3xx.h>
++
++// #define DEBUG
++
++#ifdef DEBUG
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...) do { } while (0)
++#endif
++
++/*
++ * This routine builds either a type0 or type1 configuration command. If the
++ * bus is on the 803xx then a type0 made, else a type1 is created.
++ */
++static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where)
++{
++ struct pci_sys_data *sys = bus->sysdata;
++ u32 addr;
++
++ if (sys->busnr == bus->number)
++ addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
++ else
++ addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
++
++ addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
++
++ return addr;
++}
++
++/*
++ * This routine checks the status of the last configuration cycle. If an error
++ * was detected it returns a 1, else it returns a 0. The errors being checked
++ * are parity, master abort, target abort (master and target). These types of
++ * errors occure during a config cycle where there is no device, like during
++ * the discovery stage.
++ */
++static int iop3xx_pci_status(void)
++{
++ unsigned int status;
++ int ret = 0;
++
++ /*
++ * Check the status registers.
++ */
++ status = *IOP3XX_ATUSR;
++ if (status & 0xf900) {
++ DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
++ *IOP3XX_ATUSR = status & 0xf900;
++ ret = 1;
++ }
++
++ status = *IOP3XX_ATUISR;
++ if (status & 0x679f) {
++ DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
++ *IOP3XX_ATUISR = status & 0x679f;
++ ret = 1;
++ }
++
++ return ret;
++}
++
++/*
++ * Simply write the address register and read the configuration
++ * data. Note that the 4 nop's ensure that we are able to handle
++ * a delayed abort (in theory.)
++ */
++static inline u32 iop3xx_read(unsigned long addr)
++{
++ u32 val;
++
++ __asm__ __volatile__(
++ "str %1, [%2]\n\t"
++ "ldr %0, [%3]\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ : "=r" (val)
++ : "r" (addr), "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR));
++
++ return val;
++}
++
++/*
++ * The read routines must check the error status of the last configuration
++ * cycle. If there was an error, the routine returns all hex f's.
++ */
++static int
++iop3xx_read_config(struct pci_bus *bus, unsigned int devfn, int where,
++ int size, u32 *value)
++{
++ unsigned long addr = iop3xx_cfg_address(bus, devfn, where);
++ u32 val = iop3xx_read(addr) >> ((where & 3) * 8);
++
++ if (iop3xx_pci_status())
++ val = 0xffffffff;
++
++ *value = val;
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int
++iop3xx_write_config(struct pci_bus *bus, unsigned int devfn, int where,
++ int size, u32 value)
++{
++ unsigned long addr = iop3xx_cfg_address(bus, devfn, where);
++ u32 val;
++
++ if (size != 4) {
++ val = iop3xx_read(addr);
++ if (iop3xx_pci_status())
++ return PCIBIOS_SUCCESSFUL;
++
++ where = (where & 3) * 8;
++
++ if (size == 1)
++ val &= ~(0xff << where);
++ else
++ val &= ~(0xffff << where);
++
++ *IOP3XX_OCCDR = val | value << where;
++ } else {
++ asm volatile(
++ "str %1, [%2]\n\t"
++ "str %0, [%3]\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ :
++ : "r" (value), "r" (addr),
++ "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR));
++ }
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops iop3xx_ops = {
++ .read = iop3xx_read_config,
++ .write = iop3xx_write_config,
++};
++
++/*
++ * When a PCI device does not exist during config cycles, the 80200 gets a
++ * bus error instead of returning 0xffffffff. This handler simply returns.
++ */
++static int
++iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
++{
++ DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
++ addr, fsr, regs->ARM_pc, regs->ARM_lr);
++
++ /*
++ * If it was an imprecise abort, then we need to correct the
++ * return address to be _after_ the instruction.
++ */
++ if (fsr & (1 << 10))
++ regs->ARM_pc += 4;
++
++ return 0;
++}
++
++int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
++{
++ struct resource *res;
++
++ if (nr != 0)
++ return 0;
++
++ res = kzalloc(2 * sizeof(struct resource), GFP_KERNEL);
++ if (!res)
++ panic("PCI: unable to alloc resources");
++
++ res[0].start = IOP3XX_PCI_LOWER_IO_VA;
++ res[0].end = IOP3XX_PCI_LOWER_IO_VA + IOP3XX_PCI_IO_WINDOW_SIZE - 1;
++ res[0].name = "IOP3XX PCI I/O Space";
++ res[0].flags = IORESOURCE_IO;
++ request_resource(&ioport_resource, &res[0]);
++
++ res[1].start = IOP3XX_PCI_LOWER_MEM_PA;
++ res[1].end = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
++ res[1].name = "IOP3XX PCI Memory Space";
++ res[1].flags = IORESOURCE_MEM;
++ request_resource(&iomem_resource, &res[1]);
++
++ sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - IOP3XX_PCI_LOWER_MEM_BA;
++ sys->io_offset = IOP3XX_PCI_LOWER_IO_VA - IOP3XX_PCI_LOWER_IO_BA;
++
++ sys->resource[0] = &res[0];
++ sys->resource[1] = &res[1];
++ sys->resource[2] = NULL;
++
++ return 1;
++}
++
++struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys)
++{
++ return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
++}
++
++void iop3xx_pci_preinit(void)
++{
++ DBG("PCI: Intel 803xx PCI init code.\n");
++ DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD);
++ DBG("ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x\n",
++ *IOP3XX_OMWTVR0,
++ *IOP3XX_OIOWTVR);
++ DBG("ATU: IOP3XX_ATUCR=0x%08x\n", *IOP3XX_ATUCR);
++ DBG("ATU: IOP3XX_IABAR0=0x%08x IOP3XX_IALR0=0x%08x IOP3XX_IATVR0=%08x\n",
++ *IOP3XX_IABAR0, *IOP3XX_IALR0, *IOP3XX_IATVR0);
++ DBG("ATU: IOP3XX_OMWTVR0=0x%08x\n", *IOP3XX_OMWTVR0);
++ DBG("ATU: IOP3XX_IABAR1=0x%08x IOP3XX_IALR1=0x%08x\n",
++ *IOP3XX_IABAR1, *IOP3XX_IALR1);
++ DBG("ATU: IOP3XX_ERBAR=0x%08x IOP3XX_ERLR=0x%08x IOP3XX_ERTVR=%08x\n",
++ *IOP3XX_ERBAR, *IOP3XX_ERLR, *IOP3XX_ERTVR);
++ DBG("ATU: IOP3XX_IABAR2=0x%08x IOP3XX_IALR2=0x%08x IOP3XX_IATVR2=%08x\n",
++ *IOP3XX_IABAR2, *IOP3XX_IALR2, *IOP3XX_IATVR2);
++ DBG("ATU: IOP3XX_IABAR3=0x%08x IOP3XX_IALR3=0x%08x IOP3XX_IATVR3=%08x\n",
++ *IOP3XX_IABAR3, *IOP3XX_IALR3, *IOP3XX_IATVR3);
++
++ hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort");
++}
+diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/plat-iop/setup.c
+new file mode 100644
+index 0000000..4689db6
+--- /dev/null
++++ b/arch/arm/plat-iop/setup.c
+@@ -0,0 +1,38 @@
++/*
++ * arch/arm/plat-iop/setup.c
++ *
++ * Author: Nicolas Pitre <nico at cam.org>
++ * Copyright (C) 2001 MontaVista Software, Inc.
++ * 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.
++ */
++
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <asm/mach/map.h>
++#include <asm/hardware/iop3xx.h>
++
++/*
++ * Standard IO mapping for all IOP3xx based systems
++ */
++static struct map_desc iop3xx_std_desc[] __initdata = {
++ { /* mem mapped registers */
++ .virtual = IOP3XX_PERIPHERAL_VIRT_BASE,
++ .pfn = __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE),
++ .length = IOP3XX_PERIPHERAL_SIZE,
++ .type = MT_DEVICE,
++ }, { /* PCI IO space */
++ .virtual = IOP3XX_PCI_LOWER_IO_VA,
++ .pfn = __phys_to_pfn(IOP3XX_PCI_LOWER_IO_PA),
++ .length = IOP3XX_PCI_IO_WINDOW_SIZE,
++ .type = MT_DEVICE,
++ },
++};
++
++void __init iop3xx_map_io(void)
++{
++ iotable_init(iop3xx_std_desc, ARRAY_SIZE(iop3xx_std_desc));
++}
+diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
+new file mode 100644
+index 0000000..f530abd
+--- /dev/null
++++ b/arch/arm/plat-iop/time.c
+@@ -0,0 +1,98 @@
++/*
++ * arch/arm/plat-iop/time.c
++ *
++ * Timer code for IOP32x and IOP33x based systems
++ *
++ * Author: Deepak Saxena <dsaxena at mvista.com>
++ *
++ * Copyright 2002-2003 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++#include <linux/init.h>
++#include <linux/timex.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/mach/irq.h>
++#include <asm/mach/time.h>
++
++#ifdef CONFIG_ARCH_IOP32X
++#define IRQ_IOP3XX_TIMER0 IRQ_IOP32X_TIMER0
++#else
++#ifdef CONFIG_ARCH_IOP33X
++#define IRQ_IOP3XX_TIMER0 IRQ_IOP33X_TIMER0
++#endif
++#endif
++
++static unsigned long ticks_per_jiffy;
++static unsigned long ticks_per_usec;
++static unsigned long next_jiffy_time;
++
++unsigned long iop3xx_gettimeoffset(void)
++{
++ unsigned long offset;
++
++ offset = next_jiffy_time - *IOP3XX_TU_TCR1;
++
++ return offset / ticks_per_usec;
++}
++
++static irqreturn_t
++iop3xx_timer_interrupt(int irq, void *dev_id)
++{
++ write_seqlock(&xtime_lock);
++
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (1));
++ iop3xx_cp6_disable();
++
++ while ((signed long)(next_jiffy_time - *IOP3XX_TU_TCR1)
++ >= ticks_per_jiffy) {
++ timer_tick();
++ next_jiffy_time -= ticks_per_jiffy;
++ }
++
++ write_sequnlock(&xtime_lock);
++
++ return IRQ_HANDLED;
++}
++
++static struct irqaction iop3xx_timer_irq = {
++ .name = "IOP3XX Timer Tick",
++ .handler = iop3xx_timer_interrupt,
++ .flags = IRQF_DISABLED | IRQF_TIMER,
++};
++
++void __init iop3xx_init_time(unsigned long tick_rate)
++{
++ u32 timer_ctl;
++
++ ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
++ ticks_per_usec = tick_rate / 1000000;
++ next_jiffy_time = 0xffffffff;
++
++ timer_ctl = IOP3XX_TMR_EN | IOP3XX_TMR_PRIVILEGED |
++ IOP3XX_TMR_RELOAD | IOP3XX_TMR_RATIO_1_1;
++
++ /*
++ * We use timer 0 for our timer interrupt, and timer 1 as
++ * monotonic counter for tracking missed jiffies.
++ */
++ iop3xx_cp6_enable();
++ asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (ticks_per_jiffy - 1));
++ asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
++ asm volatile("mcr p6, 0, %0, c5, c1, 0" : : "r" (0xffffffff));
++ asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl));
++ iop3xx_cp6_disable();
++
++ setup_irq(IRQ_IOP3XX_TIMER0, &iop3xx_timer_irq);
++}
+diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
+index 7f45c7c..f1179ad 100644
+--- a/arch/arm/plat-omap/clock.c
++++ b/arch/arm/plat-omap/clock.c
+@@ -100,6 +100,7 @@ void clk_disable(struct clk *clk)
+ return;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
++ BUG_ON(clk->usecount == 0);
+ if (arch_clock->clk_disable)
+ arch_clock->clk_disable(clk);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+@@ -322,6 +323,31 @@ EXPORT_SYMBOL(clk_allow_idle);
+
+ /*-------------------------------------------------------------------------*/
+
++#ifdef CONFIG_OMAP_RESET_CLOCKS
++/*
++ * Disable any unused clocks left on by the bootloader
++ */
++static int __init clk_disable_unused(void)
++{
++ struct clk *ck;
++ unsigned long flags;
++
++ list_for_each_entry(ck, &clocks, node) {
++ if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
++ ck->enable_reg == 0)
++ continue;
++
++ spin_lock_irqsave(&clockfw_lock, flags);
++ if (arch_clock->clk_disable_unused)
++ arch_clock->clk_disable_unused(ck);
++ spin_unlock_irqrestore(&clockfw_lock, flags);
++ }
++
++ return 0;
++}
++late_initcall(clk_disable_unused);
++#endif
++
+ int __init clk_init(struct clk_functions * custom_clocks)
+ {
+ if (!custom_clocks) {
+diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
+index 1812f23..dbc3f44 100644
+--- a/arch/arm/plat-omap/devices.c
++++ b/arch/arm/plat-omap/devices.c
+@@ -148,7 +148,7 @@ static inline void omap_init_kp(void) {}
+
+ #ifdef CONFIG_ARCH_OMAP24XX
+ #define OMAP_MMC1_BASE 0x4809c000
+-#define OMAP_MMC1_INT 83
++#define OMAP_MMC1_INT INT_24XX_MMC_IRQ
+ #else
+ #define OMAP_MMC1_BASE 0xfffb7800
+ #define OMAP_MMC1_INT INT_MMC
+@@ -225,7 +225,14 @@ static void __init omap_init_mmc(void)
+ /* block 1 is always available and has just one pinout option */
+ mmc = &mmc_conf->mmc[0];
+ if (mmc->enabled) {
+- if (!cpu_is_omap24xx()) {
++ if (cpu_is_omap24xx()) {
++ omap_cfg_reg(H18_24XX_MMC_CMD);
++ omap_cfg_reg(H15_24XX_MMC_CLKI);
++ omap_cfg_reg(G19_24XX_MMC_CLKO);
++ omap_cfg_reg(F20_24XX_MMC_DAT0);
++ omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
++ omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
++ } else {
+ omap_cfg_reg(MMC_CMD);
+ omap_cfg_reg(MMC_CLK);
+ omap_cfg_reg(MMC_DAT0);
+@@ -236,7 +243,14 @@ static void __init omap_init_mmc(void)
+ }
+ }
+ if (mmc->wire4) {
+- if (!cpu_is_omap24xx()) {
++ if (cpu_is_omap24xx()) {
++ omap_cfg_reg(H14_24XX_MMC_DAT1);
++ omap_cfg_reg(E19_24XX_MMC_DAT2);
++ omap_cfg_reg(D19_24XX_MMC_DAT3);
++ omap_cfg_reg(E20_24XX_MMC_DAT_DIR1);
++ omap_cfg_reg(F18_24XX_MMC_DAT_DIR2);
++ omap_cfg_reg(E18_24XX_MMC_DAT_DIR3);
++ } else {
+ omap_cfg_reg(MMC_DAT1);
+ /* NOTE: DAT2 can be on W10 (here) or M15 */
+ if (!mmc->nomux)
+diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
+index 9eddc95..bb045e5 100644
+--- a/arch/arm/plat-omap/dma.c
++++ b/arch/arm/plat-omap/dma.c
+@@ -119,32 +119,41 @@ static void clear_lch_regs(int lch)
+ omap_writew(0, lch_base + i);
+ }
+
+-void omap_set_dma_priority(int dst_port, int priority)
++void omap_set_dma_priority(int lch, int dst_port, int priority)
+ {
+ unsigned long reg;
+ u32 l;
+
+- switch (dst_port) {
+- case OMAP_DMA_PORT_OCP_T1: /* FFFECC00 */
+- reg = OMAP_TC_OCPT1_PRIOR;
+- break;
+- case OMAP_DMA_PORT_OCP_T2: /* FFFECCD0 */
+- reg = OMAP_TC_OCPT2_PRIOR;
+- break;
+- case OMAP_DMA_PORT_EMIFF: /* FFFECC08 */
+- reg = OMAP_TC_EMIFF_PRIOR;
+- break;
+- case OMAP_DMA_PORT_EMIFS: /* FFFECC04 */
+- reg = OMAP_TC_EMIFS_PRIOR;
+- break;
+- default:
+- BUG();
+- return;
++ if (cpu_class_is_omap1()) {
++ switch (dst_port) {
++ case OMAP_DMA_PORT_OCP_T1: /* FFFECC00 */
++ reg = OMAP_TC_OCPT1_PRIOR;
++ break;
++ case OMAP_DMA_PORT_OCP_T2: /* FFFECCD0 */
++ reg = OMAP_TC_OCPT2_PRIOR;
++ break;
++ case OMAP_DMA_PORT_EMIFF: /* FFFECC08 */
++ reg = OMAP_TC_EMIFF_PRIOR;
++ break;
++ case OMAP_DMA_PORT_EMIFS: /* FFFECC04 */
++ reg = OMAP_TC_EMIFS_PRIOR;
++ break;
++ default:
++ BUG();
++ return;
++ }
++ l = omap_readl(reg);
++ l &= ~(0xf << 8);
++ l |= (priority & 0xf) << 8;
++ omap_writel(l, reg);
++ }
++
++ if (cpu_is_omap24xx()) {
++ if (priority)
++ OMAP_DMA_CCR_REG(lch) |= (1 << 6);
++ else
++ OMAP_DMA_CCR_REG(lch) &= ~(1 << 6);
+ }
+- l = omap_readl(reg);
+- l &= ~(0xf << 8);
+- l |= (priority & 0xf) << 8;
+- omap_writel(l, reg);
+ }
+
+ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
+@@ -234,6 +243,14 @@ void omap_set_dma_color_mode(int lch, en
+ OMAP1_DMA_LCH_CTRL_REG(lch) = w;
+ }
+
++void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode)
++{
++ if (cpu_is_omap24xx()) {
++ OMAP_DMA_CSDP_REG(lch) &= ~(0x3 << 16);
++ OMAP_DMA_CSDP_REG(lch) |= (mode << 16);
++ }
++}
++
+ /* Note that src_port is only for omap1 */
+ void omap_set_dma_src_params(int lch, int src_port, int src_amode,
+ unsigned long src_start,
+@@ -698,6 +715,32 @@ void omap_stop_dma(int lch)
+ }
+
+ /*
++ * Allows changing the DMA callback function or data. This may be needed if
++ * the driver shares a single DMA channel for multiple dma triggers.
++ */
++int omap_set_dma_callback(int lch,
++ void (* callback)(int lch, u16 ch_status, void *data),
++ void *data)
++{
++ unsigned long flags;
++
++ if (lch < 0)
++ return -ENODEV;
++
++ spin_lock_irqsave(&dma_chan_lock, flags);
++ if (dma_chan[lch].dev_id == -1) {
++ printk(KERN_ERR "DMA callback for not set for free channel\n");
++ spin_unlock_irqrestore(&dma_chan_lock, flags);
++ return -EINVAL;
++ }
++ dma_chan[lch].callback = callback;
++ dma_chan[lch].data = data;
++ spin_unlock_irqrestore(&dma_chan_lock, flags);
++
++ return 0;
++}
++
++/*
+ * Returns current physical source address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+@@ -856,8 +899,7 @@ static int omap1_dma_handle_ch(int ch)
+ return 1;
+ }
+
+-static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id)
+ {
+ int ch = ((int) dev_id) - 1;
+ int handled = 0;
+@@ -919,8 +961,7 @@ static int omap2_dma_handle_ch(int ch)
+ }
+
+ /* STATUS register count is from 1-32 while our is 0-31 */
+-static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id)
+ {
+ u32 val;
+ int i;
+@@ -1177,8 +1218,7 @@ static void set_b1_regs(void)
+ omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
+ }
+
+-static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)
+ {
+ u16 w;
+
+@@ -1339,6 +1379,14 @@ static int __init omap_init_dma(void)
+ dma_chan_count = 16;
+ } else
+ dma_chan_count = 9;
++ if (cpu_is_omap16xx()) {
++ u16 w;
++
++ /* this would prevent OMAP sleep */
++ w = omap_readw(OMAP1610_DMA_LCD_CTRL);
++ w &= ~(1 << 8);
++ omap_writew(w, OMAP1610_DMA_LCD_CTRL);
++ }
+ } else if (cpu_is_omap24xx()) {
+ u8 revision = omap_readb(OMAP_DMA4_REVISION);
+ printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
+@@ -1414,11 +1462,13 @@ EXPORT_SYMBOL(omap_request_dma);
+ EXPORT_SYMBOL(omap_free_dma);
+ EXPORT_SYMBOL(omap_start_dma);
+ EXPORT_SYMBOL(omap_stop_dma);
++EXPORT_SYMBOL(omap_set_dma_callback);
+ EXPORT_SYMBOL(omap_enable_dma_irq);
+ EXPORT_SYMBOL(omap_disable_dma_irq);
+
+ EXPORT_SYMBOL(omap_set_dma_transfer_params);
+ EXPORT_SYMBOL(omap_set_dma_color_mode);
++EXPORT_SYMBOL(omap_set_dma_write_mode);
+
+ EXPORT_SYMBOL(omap_set_dma_src_params);
+ EXPORT_SYMBOL(omap_set_dma_src_index);
+diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
+index 5052443..bcbb8d7 100644
+--- a/arch/arm/plat-omap/dmtimer.c
++++ b/arch/arm/plat-omap/dmtimer.c
+@@ -75,10 +75,14 @@ struct omap_dm_timer {
+ #endif
+ void __iomem *io_base;
+ unsigned reserved:1;
++ unsigned enabled:1;
+ };
+
+ #ifdef CONFIG_ARCH_OMAP1
+
++#define omap_dm_clk_enable(x)
++#define omap_dm_clk_disable(x)
++
+ static struct omap_dm_timer dm_timers[] = {
+ { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
+ { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
+@@ -92,6 +96,9 @@ static struct omap_dm_timer dm_timers[]
+
+ #elif defined(CONFIG_ARCH_OMAP2)
+
++#define omap_dm_clk_enable(x) clk_enable(x)
++#define omap_dm_clk_disable(x) clk_disable(x)
++
+ static struct omap_dm_timer dm_timers[] = {
+ { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
+ { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
+@@ -154,24 +161,28 @@ static void omap_dm_timer_reset(struct o
+ {
+ u32 l;
+
+- if (timer != &dm_timers[0]) {
++ if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
+ omap_dm_timer_wait_for_reset(timer);
+ }
+- omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK);
++ omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+ /* Set to smart-idle mode */
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
+ l |= 0x02 << 3;
++
++ if (cpu_class_is_omap2() && timer == &dm_timers[0]) {
++ /* Enable wake-up only for GPT1 on OMAP2 CPUs*/
++ l |= 1 << 2;
++ /* Non-posted mode */
++ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0);
++ }
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
+ }
+
+ static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+ {
+-#ifdef CONFIG_ARCH_OMAP2
+- clk_enable(timer->iclk);
+- clk_enable(timer->fclk);
+-#endif
++ omap_dm_timer_enable(timer);
+ omap_dm_timer_reset(timer);
+ }
+
+@@ -223,15 +234,36 @@ struct omap_dm_timer *omap_dm_timer_requ
+
+ void omap_dm_timer_free(struct omap_dm_timer *timer)
+ {
++ omap_dm_timer_enable(timer);
+ omap_dm_timer_reset(timer);
+-#ifdef CONFIG_ARCH_OMAP2
+- clk_disable(timer->iclk);
+- clk_disable(timer->fclk);
+-#endif
++ omap_dm_timer_disable(timer);
++
+ WARN_ON(!timer->reserved);
+ timer->reserved = 0;
+ }
+
++void omap_dm_timer_enable(struct omap_dm_timer *timer)
++{
++ if (timer->enabled)
++ return;
++
++ omap_dm_clk_enable(timer->fclk);
++ omap_dm_clk_enable(timer->iclk);
++
++ timer->enabled = 1;
++}
++
++void omap_dm_timer_disable(struct omap_dm_timer *timer)
++{
++ if (!timer->enabled)
++ return;
++
++ omap_dm_clk_disable(timer->iclk);
++ omap_dm_clk_disable(timer->fclk);
++
++ timer->enabled = 0;
++}
++
+ int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
+ {
+ return timer->irq;
+@@ -276,7 +308,7 @@ __u32 omap_dm_timer_modify_idlect_mask(_
+
+ struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
+ {
+- return timer->fclk;
++ return timer->fclk;
+ }
+
+ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
+@@ -406,11 +438,16 @@ void omap_dm_timer_set_int_enable(struct
+ unsigned int value)
+ {
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
++ omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
+ }
+
+ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
+ {
+- return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
++ unsigned int l;
++
++ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
++
++ return l;
+ }
+
+ void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
+@@ -420,12 +457,16 @@ void omap_dm_timer_write_status(struct o
+
+ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
+ {
+- return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
++ unsigned int l;
++
++ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
++
++ return l;
+ }
+
+ void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
+ {
+- return omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
++ omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+ }
+
+ int omap_dm_timers_active(void)
+@@ -436,9 +477,14 @@ int omap_dm_timers_active(void)
+ struct omap_dm_timer *timer;
+
+ timer = &dm_timers[i];
++
++ if (!timer->enabled)
++ continue;
++
+ if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
+- OMAP_TIMER_CTRL_ST)
++ OMAP_TIMER_CTRL_ST) {
+ return 1;
++ }
+ }
+ return 0;
+ }
+diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
+index cd7f973..8162eed 100644
+--- a/arch/arm/plat-omap/gpio.c
++++ b/arch/arm/plat-omap/gpio.c
+@@ -94,6 +94,8 @@
+ #define OMAP24XX_GPIO_SYSCONFIG 0x0010
+ #define OMAP24XX_GPIO_SYSSTATUS 0x0014
+ #define OMAP24XX_GPIO_IRQSTATUS1 0x0018
++#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
++#define OMAP24XX_GPIO_IRQENABLE2 0x002c
+ #define OMAP24XX_GPIO_IRQENABLE1 0x001c
+ #define OMAP24XX_GPIO_CTRL 0x0030
+ #define OMAP24XX_GPIO_OE 0x0034
+@@ -110,8 +112,6 @@
+ #define OMAP24XX_GPIO_CLEARDATAOUT 0x0090
+ #define OMAP24XX_GPIO_SETDATAOUT 0x0094
+
+-#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff)
+-
+ struct gpio_bank {
+ void __iomem *base;
+ u16 irq;
+@@ -216,11 +216,13 @@ static inline int gpio_valid(int gpio)
+ {
+ if (gpio < 0)
+ return -1;
++#ifndef CONFIG_ARCH_OMAP24XX
+ if (OMAP_GPIO_IS_MPUIO(gpio)) {
+- if ((gpio & OMAP_MPUIO_MASK) > 16)
++ if (gpio >= OMAP_MAX_GPIO_LINES + 16)
+ return -1;
+ return 0;
+ }
++#endif
+ #ifdef CONFIG_ARCH_OMAP15XX
+ if (cpu_is_omap15xx() && gpio < 16)
+ return 0;
+@@ -529,6 +531,10 @@ static void _clear_gpio_irqbank(struct g
+ return;
+ }
+ __raw_writel(gpio_mask, reg);
++
++ /* Workaround for clearing DSP GPIO interrupts to allow retention */
++ if (cpu_is_omap2420())
++ __raw_writel(gpio_mask, bank->base + OMAP24XX_GPIO_IRQSTATUS2);
+ }
+
+ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
+@@ -662,6 +668,14 @@ static int _set_gpio_wakeup(struct gpio_
+ }
+ }
+
++static void _reset_gpio(struct gpio_bank *bank, int gpio)
++{
++ _set_gpio_direction(bank, get_gpio_index(gpio), 1);
++ _set_gpio_irqenable(bank, gpio, 0);
++ _clear_gpio_irqstatus(bank, gpio);
++ _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
++}
++
+ /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
+ static int gpio_wake_enable(unsigned int irq, unsigned int enable)
+ {
+@@ -672,9 +686,7 @@ static int gpio_wake_enable(unsigned int
+ if (check_gpio(gpio) < 0)
+ return -ENODEV;
+ bank = get_gpio_bank(gpio);
+- spin_lock(&bank->lock);
+ retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
+- spin_unlock(&bank->lock);
+
+ return retval;
+ }
+@@ -696,7 +708,9 @@ int omap_request_gpio(int gpio)
+ }
+ bank->reserved_map |= (1 << get_gpio_index(gpio));
+
+- /* Set trigger to none. You need to enable the trigger after request_irq */
++ /* Set trigger to none. You need to enable the desired trigger with
++ * request_irq() or set_irq_type().
++ */
+ _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
+
+ #ifdef CONFIG_ARCH_OMAP15XX
+@@ -756,9 +770,7 @@ void omap_free_gpio(int gpio)
+ }
+ #endif
+ bank->reserved_map &= ~(1 << get_gpio_index(gpio));
+- _set_gpio_direction(bank, get_gpio_index(gpio), 1);
+- _set_gpio_irqenable(bank, gpio, 0);
+- _clear_gpio_irqstatus(bank, gpio);
++ _reset_gpio(bank, gpio);
+ spin_unlock(&bank->lock);
+ }
+
+@@ -771,8 +783,7 @@ void omap_free_gpio(int gpio)
+ * line's interrupt handler has been run, we may miss some nested
+ * interrupts.
+ */
+-static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
+- struct pt_regs *regs)
++static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc)
+ {
+ void __iomem *isr_reg = NULL;
+ u32 isr;
+@@ -870,7 +881,7 @@ static void gpio_irq_handler(unsigned in
+ continue;
+ }
+
+- desc_handle_irq(gpio_irq, d, regs);
++ desc_handle_irq(gpio_irq, d);
+
+ if (unlikely((d->status & IRQ_PENDING) && !d->depth)) {
+ irq_mask = 1 <<
+@@ -898,6 +909,14 @@ static void gpio_irq_handler(unsigned in
+
+ }
+
++static void gpio_irq_shutdown(unsigned int irq)
++{
++ unsigned int gpio = irq - IH_GPIO_BASE;
++ struct gpio_bank *bank = get_gpio_bank(gpio);
++
++ _reset_gpio(bank, gpio);
++}
++
+ static void gpio_ack_irq(unsigned int irq)
+ {
+ unsigned int gpio = irq - IH_GPIO_BASE;
+@@ -946,6 +965,7 @@ static void mpuio_unmask_irq(unsigned in
+
+ static struct irq_chip gpio_irq_chip = {
+ .name = "GPIO",
++ .shutdown = gpio_irq_shutdown,
+ .ack = gpio_ack_irq,
+ .mask = gpio_mask_irq,
+ .unmask = gpio_unmask_irq,
+@@ -985,7 +1005,7 @@ static int __init _omap_gpio_init(void)
+ else
+ clk_enable(gpio_ick);
+ gpio_fck = clk_get(NULL, "gpios_fck");
+- if (IS_ERR(gpio_ick))
++ if (IS_ERR(gpio_fck))
+ printk("Could not get gpios_fck\n");
+ else
+ clk_enable(gpio_fck);
+@@ -1144,8 +1164,8 @@ static int omap_gpio_resume(struct sys_d
+ wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+ break;
+ case METHOD_GPIO_24XX:
+- wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+- wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
++ wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
++ wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
+ break;
+ default:
+ continue;
+diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
+index 196aac3..ec50008 100644
+--- a/arch/arm/plat-omap/mcbsp.c
++++ b/arch/arm/plat-omap/mcbsp.c
+@@ -75,8 +75,6 @@ static struct clk *mcbsp1_ick = 0;
+ static struct clk *mcbsp1_fck = 0;
+ static struct clk *mcbsp2_ick = 0;
+ static struct clk *mcbsp2_fck = 0;
+-static struct clk *sys_ck = 0;
+-static struct clk *sys_clkout = 0;
+ #endif
+
+ static void omap_mcbsp_dump_reg(u8 id)
+@@ -98,7 +96,7 @@ static void omap_mcbsp_dump_reg(u8 id)
+ DBG("***********************\n");
+ }
+
+-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
+ {
+ struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
+
+@@ -108,7 +106,7 @@ static irqreturn_t omap_mcbsp_tx_irq_han
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
+ {
+ struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
+
+@@ -232,7 +230,6 @@ static void omap2_mcbsp2_mux_setup(void)
+ omap_cfg_reg(W15_24XX_MCBSP2_DR);
+ omap_cfg_reg(V15_24XX_MCBSP2_DX);
+ omap_cfg_reg(V14_24XX_GPIO117);
+- omap_cfg_reg(W14_24XX_SYS_CLKOUT);
+ }
+ #endif
+
+@@ -984,13 +981,7 @@ static int __init omap_mcbsp_init(void)
+ if (cpu_is_omap24xx()) {
+ mcbsp_info = mcbsp_24xx;
+ mcbsp_count = ARRAY_SIZE(mcbsp_24xx);
+-
+- /* REVISIT: where's the right place? */
+ omap2_mcbsp2_mux_setup();
+- sys_ck = clk_get(0, "sys_ck");
+- sys_clkout = clk_get(0, "sys_clkout");
+- clk_set_parent(sys_clkout, sys_ck);
+- clk_enable(sys_clkout);
+ }
+ #endif
+ for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
+diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c
+deleted file mode 100644
+index 04b4102..0000000
+--- a/arch/arm/plat-omap/pm.c
++++ /dev/null
+@@ -1,670 +0,0 @@
+-/*
+- * linux/arch/arm/plat-omap/pm.c
+- *
+- * OMAP Power Management Routines
+- *
+- * Original code for the SA11x0:
+- * Copyright (c) 2001 Cliff Brake <cbrake at accelent.com>
+- *
+- * Modified for the PXA250 by Nicolas Pitre:
+- * Copyright (c) 2002 Monta Vista Software, Inc.
+- *
+- * Modified for the OMAP1510 by David Singleton:
+- * Copyright (c) 2002 Monta Vista Software, Inc.
+- *
+- * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme at de.bosch.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 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/pm.h>
+-#include <linux/sched.h>
+-#include <linux/proc_fs.h>
+-#include <linux/pm.h>
+-#include <linux/interrupt.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/mach/time.h>
+-#include <asm/mach/irq.h>
+-
+-#include <asm/mach-types.h>
+-#include <asm/arch/irqs.h>
+-#include <asm/arch/tc.h>
+-#include <asm/arch/pm.h>
+-#include <asm/arch/mux.h>
+-#include <asm/arch/tps65010.h>
+-#include <asm/arch/dsp_common.h>
+-
+-#include <asm/arch/clock.h>
+-#include <asm/arch/sram.h>
+-
+-static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
+-static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+-static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
+-static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
+-static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+-
+-static void (*omap_sram_idle)(void) = NULL;
+-static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+-
+-/*
+- * Let's power down on idle, but only if we are really
+- * idle, because once we start down the path of
+- * going idle we continue to do idle even if we get
+- * a clock tick interrupt . .
+- */
+-void omap_pm_idle(void)
+-{
+- unsigned int mask32 = 0;
+-
+- /*
+- * If the DSP is being used let's just idle the CPU, the overhead
+- * to wake up from Big Sleep is big, milliseconds versus micro
+- * seconds for wait for interrupt.
+- */
+-
+- local_irq_disable();
+- local_fiq_disable();
+- if (need_resched()) {
+- local_fiq_enable();
+- local_irq_enable();
+- return;
+- }
+- mask32 = omap_readl(ARM_SYSST);
+-
+- /*
+- * Prevent the ULPD from entering low power state by setting
+- * POWER_CTRL_REG:4 = 0
+- */
+- omap_writew(omap_readw(ULPD_POWER_CTRL) &
+- ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL);
+-
+- /*
+- * 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");
+- } else
+- omap_sram_idle();
+-
+- local_fiq_enable();
+- local_irq_enable();
+-}
+-
+-/*
+- * Configuration of the wakeup event is board specific. For the
+- * moment we put it into this helper function. Later it may move
+- * to board specific files.
+- */
+-static void omap_pm_wakeup_setup(void)
+-{
+- u32 level1_wake = 0;
+- u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
+-
+- /*
+- * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
+- * and the L2 wakeup interrupts: keypad and UART2. Note that the
+- * drivers must still separately call omap_set_gpio_wakeup() to
+- * wake up to a GPIO interrupt.
+- */
+- if (cpu_is_omap730())
+- level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
+- OMAP_IRQ_BIT(INT_730_IH2_IRQ);
+- else if (cpu_is_omap1510())
+- level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+- OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
+- else if (cpu_is_omap16xx())
+- level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+- OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
+-
+- omap_writel(~level1_wake, OMAP_IH1_MIR);
+-
+- if (cpu_is_omap730()) {
+- omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+- omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), OMAP_IH2_1_MIR);
+- } else if (cpu_is_omap1510()) {
+- level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+- omap_writel(~level2_wake, OMAP_IH2_MIR);
+- } else if (cpu_is_omap16xx()) {
+- level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+- omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+-
+- /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
+- omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
+- omap_writel(~0x0, OMAP_IH2_2_MIR);
+- omap_writel(~0x0, OMAP_IH2_3_MIR);
+- }
+-
+- /* New IRQ agreement, recalculate in cascade order */
+- omap_writel(1, OMAP_IH2_CONTROL);
+- omap_writel(1, OMAP_IH1_CONTROL);
+-}
+-
+-void omap_pm_suspend(void)
+-{
+- unsigned long arg0 = 0, arg1 = 0;
+-
+- printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
+-
+- omap_serial_wake_trigger(1);
+-
+- if (machine_is_omap_osk()) {
+- /* Stop LED1 (D9) blink */
+- tps65010_set_led(LED1, OFF);
+- }
+-
+- omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+-
+- /*
+- * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
+- */
+-
+- local_irq_disable();
+- local_fiq_disable();
+-
+- /*
+- * Step 2: save registers
+- *
+- * The omap is a strange/beautiful device. The caches, memory
+- * and register state are preserved across power saves.
+- * We have to save and restore very little register state to
+- * idle the omap.
+- *
+- * Save interrupt, MPUI, ARM and UPLD control registers.
+- */
+-
+- if (cpu_is_omap730()) {
+- MPUI730_SAVE(OMAP_IH1_MIR);
+- MPUI730_SAVE(OMAP_IH2_0_MIR);
+- MPUI730_SAVE(OMAP_IH2_1_MIR);
+- MPUI730_SAVE(MPUI_CTRL);
+- MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+- MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+- MPUI730_SAVE(EMIFS_CONFIG);
+- MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+-
+- } else if (cpu_is_omap1510()) {
+- MPUI1510_SAVE(OMAP_IH1_MIR);
+- MPUI1510_SAVE(OMAP_IH2_MIR);
+- MPUI1510_SAVE(MPUI_CTRL);
+- MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+- MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+- MPUI1510_SAVE(EMIFS_CONFIG);
+- MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+- } else if (cpu_is_omap16xx()) {
+- MPUI1610_SAVE(OMAP_IH1_MIR);
+- MPUI1610_SAVE(OMAP_IH2_0_MIR);
+- MPUI1610_SAVE(OMAP_IH2_1_MIR);
+- MPUI1610_SAVE(OMAP_IH2_2_MIR);
+- MPUI1610_SAVE(OMAP_IH2_3_MIR);
+- MPUI1610_SAVE(MPUI_CTRL);
+- MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+- MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+- MPUI1610_SAVE(EMIFS_CONFIG);
+- MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+- }
+-
+- ARM_SAVE(ARM_CKCTL);
+- ARM_SAVE(ARM_IDLECT1);
+- ARM_SAVE(ARM_IDLECT2);
+- if (!(cpu_is_omap1510()))
+- ARM_SAVE(ARM_IDLECT3);
+- ARM_SAVE(ARM_EWUPCT);
+- ARM_SAVE(ARM_RSTCT1);
+- ARM_SAVE(ARM_RSTCT2);
+- ARM_SAVE(ARM_SYSST);
+- ULPD_SAVE(ULPD_CLOCK_CTRL);
+- ULPD_SAVE(ULPD_STATUS_REQ);
+-
+- /* (Step 3 removed - we now allow deep sleep by default) */
+-
+- /*
+- * Step 4: OMAP DSP Shutdown
+- */
+-
+-
+- /*
+- * Step 5: Wakeup Event Setup
+- */
+-
+- omap_pm_wakeup_setup();
+-
+- /*
+- * Step 6: ARM and Traffic controller shutdown
+- */
+-
+- /* disable ARM watchdog */
+- omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
+- omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
+-
+- /*
+- * Step 6b: ARM and Traffic controller shutdown
+- *
+- * Step 6 continues here. Prepare jump to power management
+- * assembly code in internal SRAM.
+- *
+- * Since the omap_cpu_suspend routine has been copied to
+- * SRAM, we'll do an indirect procedure call to it and pass the
+- * contents of arm_idlect1 and arm_idlect2 so it can restore
+- * them when it wakes up and it will return.
+- */
+-
+- arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
+- arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
+-
+- /*
+- * Step 6c: ARM and Traffic controller shutdown
+- *
+- * Jump to assembly code. The processor will stay there
+- * until wake up.
+- */
+- omap_sram_suspend(arg0, arg1);
+-
+- /*
+- * If we are here, processor is woken up!
+- */
+-
+- /*
+- * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
+- */
+-
+- if (!(cpu_is_omap1510()))
+- ARM_RESTORE(ARM_IDLECT3);
+- ARM_RESTORE(ARM_CKCTL);
+- ARM_RESTORE(ARM_EWUPCT);
+- ARM_RESTORE(ARM_RSTCT1);
+- ARM_RESTORE(ARM_RSTCT2);
+- ARM_RESTORE(ARM_SYSST);
+- ULPD_RESTORE(ULPD_CLOCK_CTRL);
+- ULPD_RESTORE(ULPD_STATUS_REQ);
+-
+- if (cpu_is_omap730()) {
+- MPUI730_RESTORE(EMIFS_CONFIG);
+- MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
+- MPUI730_RESTORE(OMAP_IH1_MIR);
+- MPUI730_RESTORE(OMAP_IH2_0_MIR);
+- MPUI730_RESTORE(OMAP_IH2_1_MIR);
+- } else if (cpu_is_omap1510()) {
+- MPUI1510_RESTORE(MPUI_CTRL);
+- MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
+- MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
+- MPUI1510_RESTORE(EMIFS_CONFIG);
+- MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
+- MPUI1510_RESTORE(OMAP_IH1_MIR);
+- MPUI1510_RESTORE(OMAP_IH2_MIR);
+- } else if (cpu_is_omap16xx()) {
+- MPUI1610_RESTORE(MPUI_CTRL);
+- MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
+- MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
+- MPUI1610_RESTORE(EMIFS_CONFIG);
+- MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
+-
+- MPUI1610_RESTORE(OMAP_IH1_MIR);
+- MPUI1610_RESTORE(OMAP_IH2_0_MIR);
+- MPUI1610_RESTORE(OMAP_IH2_1_MIR);
+- MPUI1610_RESTORE(OMAP_IH2_2_MIR);
+- MPUI1610_RESTORE(OMAP_IH2_3_MIR);
+- }
+-
+- omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+-
+- /*
+- * Reenable interrupts
+- */
+-
+- local_irq_enable();
+- local_fiq_enable();
+-
+- omap_serial_wake_trigger(0);
+-
+- printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
+-
+- if (machine_is_omap_osk()) {
+- /* Let LED1 (D9) blink again */
+- tps65010_set_led(LED1, BLINK);
+- }
+-}
+-
+-#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+-static int g_read_completed;
+-
+-/*
+- * Read system PM registers for debugging
+- */
+-static int omap_pm_read_proc(
+- char *page_buffer,
+- char **my_first_byte,
+- off_t virtual_start,
+- int length,
+- int *eof,
+- void *data)
+-{
+- int my_buffer_offset = 0;
+- char * const my_base = page_buffer;
+-
+- ARM_SAVE(ARM_CKCTL);
+- ARM_SAVE(ARM_IDLECT1);
+- ARM_SAVE(ARM_IDLECT2);
+- if (!(cpu_is_omap1510()))
+- ARM_SAVE(ARM_IDLECT3);
+- ARM_SAVE(ARM_EWUPCT);
+- ARM_SAVE(ARM_RSTCT1);
+- ARM_SAVE(ARM_RSTCT2);
+- ARM_SAVE(ARM_SYSST);
+-
+- ULPD_SAVE(ULPD_IT_STATUS);
+- ULPD_SAVE(ULPD_CLOCK_CTRL);
+- ULPD_SAVE(ULPD_SOFT_REQ);
+- ULPD_SAVE(ULPD_STATUS_REQ);
+- ULPD_SAVE(ULPD_DPLL_CTRL);
+- ULPD_SAVE(ULPD_POWER_CTRL);
+-
+- if (cpu_is_omap730()) {
+- MPUI730_SAVE(MPUI_CTRL);
+- MPUI730_SAVE(MPUI_DSP_STATUS);
+- MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+- MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+- MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+- MPUI730_SAVE(EMIFS_CONFIG);
+- } else if (cpu_is_omap1510()) {
+- MPUI1510_SAVE(MPUI_CTRL);
+- MPUI1510_SAVE(MPUI_DSP_STATUS);
+- MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+- MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+- MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+- MPUI1510_SAVE(EMIFS_CONFIG);
+- } else if (cpu_is_omap16xx()) {
+- MPUI1610_SAVE(MPUI_CTRL);
+- MPUI1610_SAVE(MPUI_DSP_STATUS);
+- MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+- MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+- MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+- MPUI1610_SAVE(EMIFS_CONFIG);
+- }
+-
+- if (virtual_start == 0) {
+- g_read_completed = 0;
+-
+- my_buffer_offset += sprintf(my_base + my_buffer_offset,
+- "ARM_CKCTL_REG: 0x%-8x \n"
+- "ARM_IDLECT1_REG: 0x%-8x \n"
+- "ARM_IDLECT2_REG: 0x%-8x \n"
+- "ARM_IDLECT3_REG: 0x%-8x \n"
+- "ARM_EWUPCT_REG: 0x%-8x \n"
+- "ARM_RSTCT1_REG: 0x%-8x \n"
+- "ARM_RSTCT2_REG: 0x%-8x \n"
+- "ARM_SYSST_REG: 0x%-8x \n"
+- "ULPD_IT_STATUS_REG: 0x%-4x \n"
+- "ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
+- "ULPD_SOFT_REQ_REG: 0x%-4x \n"
+- "ULPD_DPLL_CTRL_REG: 0x%-4x \n"
+- "ULPD_STATUS_REQ_REG: 0x%-4x \n"
+- "ULPD_POWER_CTRL_REG: 0x%-4x \n",
+- ARM_SHOW(ARM_CKCTL),
+- ARM_SHOW(ARM_IDLECT1),
+- ARM_SHOW(ARM_IDLECT2),
+- ARM_SHOW(ARM_IDLECT3),
+- ARM_SHOW(ARM_EWUPCT),
+- ARM_SHOW(ARM_RSTCT1),
+- ARM_SHOW(ARM_RSTCT2),
+- ARM_SHOW(ARM_SYSST),
+- ULPD_SHOW(ULPD_IT_STATUS),
+- ULPD_SHOW(ULPD_CLOCK_CTRL),
+- ULPD_SHOW(ULPD_SOFT_REQ),
+- ULPD_SHOW(ULPD_DPLL_CTRL),
+- ULPD_SHOW(ULPD_STATUS_REQ),
+- ULPD_SHOW(ULPD_POWER_CTRL));
+-
+- if (cpu_is_omap730()) {
+- my_buffer_offset += sprintf(my_base + my_buffer_offset,
+- "MPUI730_CTRL_REG 0x%-8x \n"
+- "MPUI730_DSP_STATUS_REG: 0x%-8x \n"
+- "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+- "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n"
+- "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n"
+- "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n",
+- MPUI730_SHOW(MPUI_CTRL),
+- MPUI730_SHOW(MPUI_DSP_STATUS),
+- MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
+- MPUI730_SHOW(MPUI_DSP_API_CONFIG),
+- MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
+- MPUI730_SHOW(EMIFS_CONFIG));
+- } else if (cpu_is_omap1510()) {
+- my_buffer_offset += sprintf(my_base + my_buffer_offset,
+- "MPUI1510_CTRL_REG 0x%-8x \n"
+- "MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
+- "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+- "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
+- "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
+- "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
+- MPUI1510_SHOW(MPUI_CTRL),
+- MPUI1510_SHOW(MPUI_DSP_STATUS),
+- MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
+- MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
+- MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
+- MPUI1510_SHOW(EMIFS_CONFIG));
+- } else if (cpu_is_omap16xx()) {
+- my_buffer_offset += sprintf(my_base + my_buffer_offset,
+- "MPUI1610_CTRL_REG 0x%-8x \n"
+- "MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
+- "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+- "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
+- "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
+- "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
+- MPUI1610_SHOW(MPUI_CTRL),
+- MPUI1610_SHOW(MPUI_DSP_STATUS),
+- MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
+- MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
+- MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
+- MPUI1610_SHOW(EMIFS_CONFIG));
+- }
+-
+- g_read_completed++;
+- } else if (g_read_completed >= 1) {
+- *eof = 1;
+- return 0;
+- }
+- g_read_completed++;
+-
+- *my_first_byte = page_buffer;
+- return my_buffer_offset;
+-}
+-
+-static void omap_pm_init_proc(void)
+-{
+- struct proc_dir_entry *entry;
+-
+- entry = create_proc_read_entry("driver/omap_pm",
+- S_IWUSR | S_IRUGO, NULL,
+- omap_pm_read_proc, NULL);
+-}
+-
+-#endif /* DEBUG && CONFIG_PROC_FS */
+-
+-/*
+- * omap_pm_prepare - Do preliminary suspend work.
+- * @state: suspend state we're entering.
+- *
+- */
+-//#include <asm/hardware.h>
+-
+-static int omap_pm_prepare(suspend_state_t state)
+-{
+- int error = 0;
+-
+- switch (state)
+- {
+- case PM_SUSPEND_STANDBY:
+- case PM_SUSPEND_MEM:
+- break;
+-
+- case PM_SUSPEND_DISK:
+- return -ENOTSUPP;
+-
+- default:
+- return -EINVAL;
+- }
+-
+- return error;
+-}
+-
+-
+-/*
+- * omap_pm_enter - Actually enter a sleep state.
+- * @state: State we're entering.
+- *
+- */
+-
+-static int omap_pm_enter(suspend_state_t state)
+-{
+- switch (state)
+- {
+- case PM_SUSPEND_STANDBY:
+- case PM_SUSPEND_MEM:
+- omap_pm_suspend();
+- break;
+-
+- case PM_SUSPEND_DISK:
+- return -ENOTSUPP;
+-
+- default:
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-
+-/**
+- * omap_pm_finish - Finish up suspend sequence.
+- * @state: State we're coming out of.
+- *
+- * This is called after we wake back up (or if entering the sleep state
+- * failed).
+- */
+-
+-static int omap_pm_finish(suspend_state_t state)
+-{
+- return 0;
+-}
+-
+-
+-static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
+- struct pt_regs * regs)
+-{
+- return IRQ_HANDLED;
+-}
+-
+-static struct irqaction omap_wakeup_irq = {
+- .name = "peripheral wakeup",
+- .flags = IRQF_DISABLED,
+- .handler = omap_wakeup_interrupt
+-};
+-
+-
+-
+-static struct pm_ops omap_pm_ops ={
+- .pm_disk_mode = 0,
+- .prepare = omap_pm_prepare,
+- .enter = omap_pm_enter,
+- .finish = omap_pm_finish,
+-};
+-
+-static int __init omap_pm_init(void)
+-{
+- printk("Power Management for TI OMAP.\n");
+- /*
+- * We copy the assembler sleep/wakeup routines to SRAM.
+- * These routines need to be in SRAM as that's the only
+- * memory the MPU can see when it wakes up.
+- */
+- if (cpu_is_omap730()) {
+- omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
+- omap730_idle_loop_suspend_sz);
+- omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
+- omap730_cpu_suspend_sz);
+- } else if (cpu_is_omap1510()) {
+- omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
+- omap1510_idle_loop_suspend_sz);
+- omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
+- omap1510_cpu_suspend_sz);
+- } else if (cpu_is_omap16xx()) {
+- omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
+- omap1610_idle_loop_suspend_sz);
+- omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
+- omap1610_cpu_suspend_sz);
+- }
+-
+- if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
+- printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
+- return -ENODEV;
+- }
+-
+- pm_idle = omap_pm_idle;
+-
+- if (cpu_is_omap730())
+- setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
+- else if (cpu_is_omap16xx())
+- setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+-
+-#if 0
+- /* --- BEGIN BOARD-DEPENDENT CODE --- */
+- /* Sleepx mask direction */
+- omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
+- /* Unmask sleepx signal */
+- omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
+- /* --- END BOARD-DEPENDENT CODE --- */
+-#endif
+-
+- /* Program new power ramp-up time
+- * (0 for most boards since we don't lower voltage when in deep sleep)
+- */
+- omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
+-
+- /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
+- omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
+-
+- /* Configure IDLECT3 */
+- if (cpu_is_omap730())
+- omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
+- else if (cpu_is_omap16xx())
+- omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
+-
+- pm_set_ops(&omap_pm_ops);
+-
+-#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+- omap_pm_init_proc();
+-#endif
+-
+- if (cpu_is_omap16xx()) {
+- /* configure LOW_PWR pin */
+- omap_cfg_reg(T20_1610_LOW_PWR);
+- }
+-
+- return 0;
+-}
+-__initcall(omap_pm_init);
+-
+diff --git a/arch/arm/plat-omap/sram-fn.S b/arch/arm/plat-omap/sram-fn.S
+index 85cffe2..9e1813c 100644
+--- a/arch/arm/plat-omap/sram-fn.S
++++ b/arch/arm/plat-omap/sram-fn.S
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/plat-omap/sram.S
++ * linux/arch/arm/plat-omap/sram-fn.S
+ *
+ * Functions that need to be run in internal SRAM
+ *
+diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
+index e757183..19014b2 100644
+--- a/arch/arm/plat-omap/sram.c
++++ b/arch/arm/plat-omap/sram.c
+@@ -174,10 +174,7 @@ void __init omap_map_sram(void)
+ if (cpu_is_omap24xx()) {
+ omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
+
+- if (is_sram_locked())
+- base = OMAP2_SRAM_PUB_PA;
+- else
+- base = OMAP2_SRAM_PA;
++ base = OMAP2_SRAM_PA;
+ base = ROUND_DOWN(base, PAGE_SIZE);
+ omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+ }
+diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
+index 281ecc7..2653106 100644
+--- a/arch/arm/plat-omap/timer32k.c
++++ b/arch/arm/plat-omap/timer32k.c
+@@ -105,6 +105,8 @@ static inline unsigned long omap_32k_tim
+
+ static inline void omap_32k_timer_start(unsigned long load_val)
+ {
++ if (!load_val)
++ load_val = 1;
+ omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
+ omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
+ }
+@@ -192,21 +194,17 @@ unsigned long long sched_clock(void)
+ * issues with dynamic tick. In the dynamic tick case, we need to lock
+ * with irqsave.
+ */
+-static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
+ {
+- unsigned long flags;
+ unsigned long now;
+
+- write_seqlock_irqsave(&xtime_lock, flags);
+-
+ omap_32k_timer_ack_irq();
+ now = omap_32k_sync_timer_read();
+
+ while ((signed long)(now - omap_32k_last_tick)
+ >= OMAP_32K_TICKS_PER_HZ) {
+ omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
+- timer_tick(regs);
++ timer_tick();
+ }
+
+ /* Restart timer so we don't drift off due to modulo or dynamic tick.
+@@ -215,6 +213,21 @@ static irqreturn_t omap_32k_timer_interr
+ * continuous timer can be overridden from pm_idle to be longer.
+ */
+ omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
++{
++ return _omap_32k_timer_interrupt(irq, dev_id);
++}
++
++static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
++{
++ unsigned long flags;
++
++ write_seqlock_irqsave(&xtime_lock, flags);
++ _omap_32k_timer_interrupt(irq, dev_id);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ return IRQ_HANDLED;
+@@ -230,7 +243,15 @@ static irqreturn_t omap_32k_timer_interr
+ */
+ void omap_32k_timer_reprogram(unsigned long next_tick)
+ {
+- omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
++ unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1;
++ unsigned long now = omap_32k_sync_timer_read();
++ unsigned long idled = now - omap_32k_last_tick;
++
++ if (idled + 1 < ticks)
++ ticks -= idled;
++ else
++ ticks = 1;
++ omap_32k_timer_start(ticks);
+ }
+
+ static struct irqaction omap_32k_timer_irq;
+@@ -252,7 +273,7 @@ static struct dyn_tick_timer omap_dyn_ti
+ .enable = omap_32k_timer_enable_dyn_tick,
+ .disable = omap_32k_timer_disable_dyn_tick,
+ .reprogram = omap_32k_timer_reprogram,
+- .handler = omap_32k_timer_interrupt,
++ .handler = omap_32k_timer_handler,
+ };
+ #endif /* CONFIG_NO_IDLE_HZ */
+
+diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
+index 9b81532..7e80968 100644
+--- a/arch/arm/plat-omap/usb.c
++++ b/arch/arm/plat-omap/usb.c
+@@ -26,7 +26,7 @@
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
+-#include <linux/usb_otg.h>
++#include <linux/usb/otg.h>
+
+ #include <asm/io.h>
+ #include <asm/irq.h>
+diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
+index 2f9c9b5..ce319ef 100644
+--- a/arch/arm/tools/gen-mach-types
++++ b/arch/arm/tools/gen-mach-types
+@@ -28,7 +28,6 @@ END {
+ printf(" */\n\n");
+ printf("#ifndef __ASM_ARM_MACH_TYPE_H\n");
+ printf("#define __ASM_ARM_MACH_TYPE_H\n\n");
+- printf("#include <linux/config.h>\n\n");
+ printf("#ifndef __ASSEMBLY__\n");
+ printf("/* The type of machine we're running on */\n");
+ printf("extern unsigned int __machine_arch_type;\n");
+diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
+index e1372a2..579c69a 100644
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -4,7 +4,7 @@
+ #
+ # Up to date versions of this file can be obtained from:
+ #
+-# http://www.arm.linux.org.uk/developer/machines/?action=download
++# http://www.arm.linux.org.uk/developer/machines/download.php
+ #
+ # Please do not send patches to this file; it is automatically generated!
+ # To add an entry into this database, please see Documentation/arm/README,
+@@ -12,7 +12,7 @@
+ #
+ # http://www.arm.linux.org.uk/developer/machines/?action=new
+ #
+-# Last update: Mon Jun 26 22:26:08 2006
++# Last update: Mon Oct 16 21:13:36 2006
+ #
+ # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
+ #
+@@ -329,7 +329,7 @@ nimbra29x ARCH_NIMBRA29X NIMBRA29X 31
+ nimbra210 ARCH_NIMBRA210 NIMBRA210 312
+ hhp_d95xx ARCH_HHP_D95XX HHP_D95XX 313
+ labarm ARCH_LABARM LABARM 314
+-comcerto ARCH_M825XX M825XX 315
++m825xx ARCH_M825XX M825XX 315
+ m7100 SA1100_M7100 M7100 316
+ nipc2 ARCH_NIPC2 NIPC2 317
+ fu7202 ARCH_FU7202 FU7202 318
+@@ -857,12 +857,12 @@ osiris MACH_OSIRIS OSIRIS 842
+ maestro MACH_MAESTRO MAESTRO 843
+ tunge2 MACH_TUNGE2 TUNGE2 844
+ ixbbm MACH_IXBBM IXBBM 845
+-mx27ads MACH_MX27 MX27 846
++mx27ads MACH_MX27ADS MX27ADS 846
+ ax8004 MACH_AX8004 AX8004 847
+ at91sam9261ek MACH_AT91SAM9261EK AT91SAM9261EK 848
+ loft MACH_LOFT LOFT 849
+ magpie MACH_MAGPIE MAGPIE 850
+-mx21ads MACH_MX21 MX21 851
++mx21ads MACH_MX21ADS MX21ADS 851
+ mb87m3400 MACH_MB87M3400 MB87M3400 852
+ mguard_delta MACH_MGUARD_DELTA MGUARD_DELTA 853
+ davinci_dvdp MACH_DAVINCI_DVDP DAVINCI_DVDP 854
+@@ -1058,7 +1058,7 @@ akai9307 MACH_AKAI9307 AKAI9307 1044
+ fontaine MACH_FONTAINE FONTAINE 1045
+ wombat MACH_WOMBAT WOMBAT 1046
+ acq300 MACH_ACQ300 ACQ300 1047
+-mod_270 MACH_MOD_270 MOD_270 1048
++mod272 MACH_MOD_270 MOD_270 1048
+ vmc_vc0820 MACH_VC0820 VC0820 1049
+ ani_aim MACH_ANI_AIM ANI_AIM 1050
+ jellyfish MACH_JELLYFISH JELLYFISH 1051
+@@ -1093,3 +1093,81 @@ msm6100 MACH_MSM6100 MSM6100 1079
+ eti_b1 MACH_ETI_B1 ETI_B1 1080
+ za9l_series MACH_ZILOG_ZA9L ZILOG_ZA9L 1081
+ bit2440 MACH_BIT2440 BIT2440 1082
++nbi MACH_NBI NBI 1083
++smdk2443 MACH_SMDK2443 SMDK2443 1084
++vdavinci MACH_VDAVINCI VDAVINCI 1085
++atc6 MACH_ATC6 ATC6 1086
++multmdw MACH_MULTMDW MULTMDW 1087
++mba2440 MACH_MBA2440 MBA2440 1088
++ecsd MACH_ECSD ECSD 1089
++zire31 MACH_ZIRE31 ZIRE31 1090
++fsg MACH_FSG FSG 1091
++razor101 MACH_RAZOR101 RAZOR101 1092
++opera_tdm MACH_OPERA_TDM OPERA_TDM 1093
++comcerto MACH_COMCERTO COMCERTO 1094
++tb0319 MACH_TB0319 TB0319 1095
++kws8000 MACH_KWS8000 KWS8000 1096
++b2 MACH_B2 B2 1097
++lcl54 MACH_LCL54 LCL54 1098
++at91sam9260ek MACH_AT91SAM9260EK AT91SAM9260EK 1099
++glantank MACH_GLANTANK GLANTANK 1100
++n2100 MACH_N2100 N2100 1101
++n4100 MACH_N4100 N4100 1102
++rsc4 MACH_VERTICAL_RSC4 VERTICAL_RSC4 1103
++sg8100 MACH_SG8100 SG8100 1104
++im42xx MACH_IM42XX IM42XX 1105
++ftxx MACH_FTXX FTXX 1106
++lwfusion MACH_LWFUSION LWFUSION 1107
++qt2410 MACH_QT2410 QT2410 1108
++kixrp435 MACH_KIXRP435 KIXRP435 1109
++ccw9c MACH_CCW9C CCW9C 1110
++dabhs MACH_DABHS DABHS 1111
++gzmx MACH_GZMX GZMX 1112
++ipnw100ap MACH_IPNW100AP IPNW100AP 1113
++cc9p9360dev MACH_CC9P9360DEV CC9P9360DEV 1114
++cc9p9750dev MACH_CC9P9750DEV CC9P9750DEV 1115
++cc9p9360val MACH_CC9P9360VAL CC9P9360VAL 1116
++cc9p9750val MACH_CC9P9750VAL CC9P9750VAL 1117
++nx70v MACH_NX70V NX70V 1118
++at91rm9200df MACH_AT91RM9200DF AT91RM9200DF 1119
++se_pilot2 MACH_SE_PILOT2 SE_PILOT2 1120
++mtcn_t800 MACH_MTCN_T800 MTCN_T800 1121
++vcmx212 MACH_VCMX212 VCMX212 1122
++lynx MACH_LYNX LYNX 1123
++at91sam9260id MACH_AT91SAM9260ID AT91SAM9260ID 1124
++hw86052 MACH_HW86052 HW86052 1125
++pilz_pmi3 MACH_PILZ_PMI3 PILZ_PMI3 1126
++edb9302a MACH_EDB9302A EDB9302A 1127
++edb9307a MACH_EDB9307A EDB9307A 1128
++ct_dfs MACH_CT_DFS CT_DFS 1129
++pilz_pmi4 MACH_PILZ_PMI4 PILZ_PMI4 1130
++xceednp_ixp MACH_XCEEDNP_IXP XCEEDNP_IXP 1131
++smdk2442b MACH_SMDK2442B SMDK2442B 1132
++xnode MACH_XNODE XNODE 1133
++aidx270 MACH_AIDX270 AIDX270 1134
++rema MACH_REMA REMA 1135
++bps1000 MACH_BPS1000 BPS1000 1136
++hw90350 MACH_HW90350 HW90350 1137
++omap_sdp3430 MACH_OMAP_SDP3430 OMAP_SDP3430 1138
++bluetouch MACH_BLUETOUCH BLUETOUCH 1139
++vstms MACH_VSTMS VSTMS 1140
++xsbase270 MACH_XSBASE270 XSBASE270 1141
++at91sam9260ek_cn MACH_AT91SAM9260EK_CN AT91SAM9260EK_CN 1142
++adsturboxb MACH_ADSTURBOXB ADSTURBOXB 1143
++oti4110 MACH_OTI4110 OTI4110 1144
++hme_pxa MACH_HME_PXA HME_PXA 1145
++deisterdca MACH_DEISTERDCA DEISTERDCA 1146
++ces_ssem2 MACH_CES_SSEM2 CES_SSEM2 1147
++ces_mtr MACH_CES_MTR CES_MTR 1148
++tds_avng_sbc MACH_TDS_AVNG_SBC TDS_AVNG_SBC 1149
++everest MACH_EVEREST EVEREST 1150
++pnx4010 MACH_PNX4010 PNX4010 1151
++oxnas MACH_OXNAS OXNAS 1152
++fiori MACH_FIORI FIORI 1153
++ml1200 MACH_ML1200 ML1200 1154
++cactus MACH_CACTUS CACTUS 1155
++nb2xxx MACH_NB2XXX NB2XXX 1156
++hw6900 MACH_HW6900 HW6900 1157
++cdcs_quoll MACH_CDCS_QUOLL CDCS_QUOLL 1158
++quicksilver MACH_QUICKSILVER QUICKSILVER 1159
++uplat926 MACH_UPLAT926 UPLAT926 1160
+diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
+index 96fdf30..f279789 100644
+--- a/arch/arm/vfp/vfp.h
++++ b/arch/arm/vfp/vfp.h
+@@ -355,3 +355,18 @@ u32 vfp_estimate_sqrt_significand(u32 ex
+ * we check for an error.
+ */
+ #define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
++
++/*
++ * A flag to tell vfp instruction type.
++ * OP_SCALAR - this operation always operates in scalar mode
++ * OP_SD - the instruction exceptionally writes to a single precision result.
++ * OP_DD - the instruction exceptionally writes to a double precision result.
++ */
++#define OP_SCALAR (1 << 0)
++#define OP_SD (1 << 1)
++#define OP_DD (1 << 1)
++
++struct op {
++ u32 (* const fn)(int dd, int dn, int dm, u32 fpscr);
++ u32 flags;
++};
+diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
+index add48e3..e44b9ed 100644
+--- a/arch/arm/vfp/vfpdouble.c
++++ b/arch/arm/vfp/vfpdouble.c
+@@ -56,7 +56,7 @@ static void vfp_double_normalise_denorma
+ {
+ int bits = 31 - fls(vd->significand >> 32);
+ if (bits == 31)
+- bits = 62 - fls(vd->significand);
++ bits = 63 - fls(vd->significand);
+
+ vfp_double_dump("normalise_denormal: in", vd);
+
+@@ -659,22 +659,22 @@ static u32 vfp_double_ftosiz(int dd, int
+ }
+
+
+-static u32 (* const fop_extfns[32])(int dd, int unused, int dm, u32 fpscr) = {
+- [FEXT_TO_IDX(FEXT_FCPY)] = vfp_double_fcpy,
+- [FEXT_TO_IDX(FEXT_FABS)] = vfp_double_fabs,
+- [FEXT_TO_IDX(FEXT_FNEG)] = vfp_double_fneg,
+- [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_double_fsqrt,
+- [FEXT_TO_IDX(FEXT_FCMP)] = vfp_double_fcmp,
+- [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_double_fcmpe,
+- [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_double_fcmpz,
+- [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_double_fcmpez,
+- [FEXT_TO_IDX(FEXT_FCVT)] = vfp_double_fcvts,
+- [FEXT_TO_IDX(FEXT_FUITO)] = vfp_double_fuito,
+- [FEXT_TO_IDX(FEXT_FSITO)] = vfp_double_fsito,
+- [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_double_ftoui,
+- [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_double_ftouiz,
+- [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_double_ftosi,
+- [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_double_ftosiz,
++static struct op fops_ext[32] = {
++ [FEXT_TO_IDX(FEXT_FCPY)] = { vfp_double_fcpy, 0 },
++ [FEXT_TO_IDX(FEXT_FABS)] = { vfp_double_fabs, 0 },
++ [FEXT_TO_IDX(FEXT_FNEG)] = { vfp_double_fneg, 0 },
++ [FEXT_TO_IDX(FEXT_FSQRT)] = { vfp_double_fsqrt, 0 },
++ [FEXT_TO_IDX(FEXT_FCMP)] = { vfp_double_fcmp, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCMPE)] = { vfp_double_fcmpe, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCMPZ)] = { vfp_double_fcmpz, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCMPEZ)] = { vfp_double_fcmpez, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCVT)] = { vfp_double_fcvts, OP_SCALAR|OP_SD },
++ [FEXT_TO_IDX(FEXT_FUITO)] = { vfp_double_fuito, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FSITO)] = { vfp_double_fsito, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FTOUI)] = { vfp_double_ftoui, OP_SCALAR|OP_SD },
++ [FEXT_TO_IDX(FEXT_FTOUIZ)] = { vfp_double_ftouiz, OP_SCALAR|OP_SD },
++ [FEXT_TO_IDX(FEXT_FTOSI)] = { vfp_double_ftosi, OP_SCALAR|OP_SD },
++ [FEXT_TO_IDX(FEXT_FTOSIZ)] = { vfp_double_ftosiz, OP_SCALAR|OP_SD },
+ };
+
+
+@@ -1108,16 +1108,16 @@ static u32 vfp_double_fdiv(int dd, int d
+ return FPSCR_IOC;
+ }
+
+-static u32 (* const fop_fns[16])(int dd, int dn, int dm, u32 fpscr) = {
+- [FOP_TO_IDX(FOP_FMAC)] = vfp_double_fmac,
+- [FOP_TO_IDX(FOP_FNMAC)] = vfp_double_fnmac,
+- [FOP_TO_IDX(FOP_FMSC)] = vfp_double_fmsc,
+- [FOP_TO_IDX(FOP_FNMSC)] = vfp_double_fnmsc,
+- [FOP_TO_IDX(FOP_FMUL)] = vfp_double_fmul,
+- [FOP_TO_IDX(FOP_FNMUL)] = vfp_double_fnmul,
+- [FOP_TO_IDX(FOP_FADD)] = vfp_double_fadd,
+- [FOP_TO_IDX(FOP_FSUB)] = vfp_double_fsub,
+- [FOP_TO_IDX(FOP_FDIV)] = vfp_double_fdiv,
++static struct op fops[16] = {
++ [FOP_TO_IDX(FOP_FMAC)] = { vfp_double_fmac, 0 },
++ [FOP_TO_IDX(FOP_FNMAC)] = { vfp_double_fnmac, 0 },
++ [FOP_TO_IDX(FOP_FMSC)] = { vfp_double_fmsc, 0 },
++ [FOP_TO_IDX(FOP_FNMSC)] = { vfp_double_fnmsc, 0 },
++ [FOP_TO_IDX(FOP_FMUL)] = { vfp_double_fmul, 0 },
++ [FOP_TO_IDX(FOP_FNMUL)] = { vfp_double_fnmul, 0 },
++ [FOP_TO_IDX(FOP_FADD)] = { vfp_double_fadd, 0 },
++ [FOP_TO_IDX(FOP_FSUB)] = { vfp_double_fsub, 0 },
++ [FOP_TO_IDX(FOP_FDIV)] = { vfp_double_fdiv, 0 },
+ };
+
+ #define FREG_BANK(x) ((x) & 0x0c)
+@@ -1131,69 +1131,60 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
+ unsigned int dn = vfp_get_dn(inst);
+ unsigned int dm = vfp_get_dm(inst);
+ unsigned int vecitr, veclen, vecstride;
+- u32 (*fop)(int, int, s32, u32);
++ struct op *fop;
+
+- veclen = fpscr & FPSCR_LENGTH_MASK;
+ vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2;
+
++ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
++
+ /*
+ * fcvtds takes an sN register number as destination, not dN.
+ * It also always operates on scalars.
+ */
+- if ((inst & FEXT_MASK) == FEXT_FCVT) {
+- veclen = 0;
++ if (fop->flags & OP_SD)
+ dest = vfp_get_sd(inst);
+- } else
++ else
+ dest = vfp_get_dd(inst);
+
+ /*
+ * If destination bank is zero, vector length is always '1'.
+ * ARM DDI0100F C5.1.3, C5.3.2.
+ */
+- if (FREG_BANK(dest) == 0)
++ if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
+ veclen = 0;
++ else
++ veclen = fpscr & FPSCR_LENGTH_MASK;
+
+ pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+- fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)];
+- if (!fop)
++ if (!fop->fn)
+ goto invalid;
+
+ for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+ u32 except;
++ char type;
+
+- if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT)
+- pr_debug("VFP: itr%d (s%u) = op[%u] (d%u)\n",
+- vecitr >> FPSCR_LENGTH_BIT,
+- dest, dn, dm);
+- else if (op == FOP_EXT)
+- pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n",
++ type = fop->flags & OP_SD ? 's' : 'd';
++ if (op == FOP_EXT)
++ pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
+ vecitr >> FPSCR_LENGTH_BIT,
+- dest, dn, dm);
++ type, dest, dn, dm);
+ else
+- pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n",
++ pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
+ vecitr >> FPSCR_LENGTH_BIT,
+- dest, dn, FOP_TO_IDX(op), dm);
++ type, dest, dn, FOP_TO_IDX(op), dm);
+
+- except = fop(dest, dn, dm, fpscr);
++ except = fop->fn(dest, dn, dm, fpscr);
+ pr_debug("VFP: itr%d: exceptions=%08x\n",
+ vecitr >> FPSCR_LENGTH_BIT, except);
+
+ exceptions |= except;
+
+ /*
+- * This ensures that comparisons only operate on scalars;
+- * comparisons always return with one FPSCR status bit set.
+- */
+- if (except & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
+- break;
+-
+- /*
+ * CHECK: It appears to be undefined whether we stop when
+ * we encounter an exception. We continue.
+ */
+-
+ dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 6);
+ dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6);
+ if (FREG_BANK(dm) != 0)
+diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h
+index 6c819ae..7f343a4 100644
+--- a/arch/arm/vfp/vfpinstr.h
++++ b/arch/arm/vfp/vfpinstr.h
+@@ -73,14 +73,14 @@
+
+ #define fmrx(_vfp_) ({ \
+ u32 __v; \
+- asm("mrc%? p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmrx %0, " #_vfp_ \
+- : "=r" (__v)); \
++ asm("mrc p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmrx %0, " #_vfp_ \
++ : "=r" (__v) : : "cc"); \
+ __v; \
+ })
+
+ #define fmxr(_vfp_,_var_) \
+- asm("mcr%? p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \
+- : : "r" (_var_))
++ asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \
++ : : "r" (_var_) : "cc")
+
+ u32 vfp_single_cpdo(u32 inst, u32 fpscr);
+ u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs);
+diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
+index 4178f6c..f08eafb 100644
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -40,10 +40,19 @@ unsigned int VFP_arch;
+ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
+ {
+ struct thread_info *thread = v;
+- union vfp_state *vfp = &thread->vfpstate;
++ union vfp_state *vfp;
+
+- switch (cmd) {
+- case THREAD_NOTIFY_FLUSH:
++ if (likely(cmd == THREAD_NOTIFY_SWITCH)) {
++ /*
++ * Always disable VFP so we can lazily save/restore the
++ * old state.
++ */
++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
++ return NOTIFY_DONE;
++ }
++
++ vfp = &thread->vfpstate;
++ if (cmd == THREAD_NOTIFY_FLUSH) {
+ /*
+ * Per-thread VFP initialisation.
+ */
+@@ -56,29 +65,12 @@ static int vfp_notifier(struct notifier_
+ * Disable VFP to ensure we initialise it first.
+ */
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+-
+- /*
+- * FALLTHROUGH: Ensure we don't try to overwrite our newly
+- * initialised state information on the first fault.
+- */
+-
+- case THREAD_NOTIFY_RELEASE:
+- /*
+- * Per-thread VFP cleanup.
+- */
+- if (last_VFP_context == vfp)
+- last_VFP_context = NULL;
+- break;
+-
+- case THREAD_NOTIFY_SWITCH:
+- /*
+- * Always disable VFP so we can lazily save/restore the
+- * old state.
+- */
+- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+- break;
+ }
+
++ /* flush and release case: Per-thread VFP cleanup. */
++ if (last_VFP_context == vfp)
++ last_VFP_context = NULL;
++
+ return NOTIFY_DONE;
+ }
+
+@@ -98,7 +90,7 @@ void vfp_raise_sigfpe(unsigned int sicod
+
+ info.si_signo = SIGFPE;
+ info.si_code = sicode;
+- info.si_addr = (void *)(instruction_pointer(regs) - 4);
++ info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
+
+ /*
+ * This is the same as NWFPE, because it's not clear what
+@@ -156,6 +148,7 @@ static void vfp_raise_exceptions(u32 exc
+ /*
+ * These are arranged in priority order, least to highest.
+ */
++ RAISE(FPSCR_DZC, FPSCR_DZE, FPE_FLTDIV);
+ RAISE(FPSCR_IXC, FPSCR_IXE, FPE_FLTRES);
+ RAISE(FPSCR_UFC, FPSCR_UFE, FPE_FLTUND);
+ RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
+diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
+index 8f6c179..0221ba3 100644
+--- a/arch/arm/vfp/vfpsingle.c
++++ b/arch/arm/vfp/vfpsingle.c
+@@ -198,8 +198,10 @@ u32 vfp_single_normaliseround(int sd, st
+ vfp_single_dump("pack: final", vs);
+ {
+ s32 d = vfp_single_pack(vs);
++#ifdef DEBUG
+ pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
+ sd, d, exceptions);
++#endif
+ vfp_put_float(d, sd);
+ }
+
+@@ -702,22 +704,22 @@ static u32 vfp_single_ftosiz(int sd, int
+ return vfp_single_ftosi(sd, unused, m, FPSCR_ROUND_TOZERO);
+ }
+
+-static u32 (* const fop_extfns[32])(int sd, int unused, s32 m, u32 fpscr) = {
+- [FEXT_TO_IDX(FEXT_FCPY)] = vfp_single_fcpy,
+- [FEXT_TO_IDX(FEXT_FABS)] = vfp_single_fabs,
+- [FEXT_TO_IDX(FEXT_FNEG)] = vfp_single_fneg,
+- [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_single_fsqrt,
+- [FEXT_TO_IDX(FEXT_FCMP)] = vfp_single_fcmp,
+- [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_single_fcmpe,
+- [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_single_fcmpz,
+- [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_single_fcmpez,
+- [FEXT_TO_IDX(FEXT_FCVT)] = vfp_single_fcvtd,
+- [FEXT_TO_IDX(FEXT_FUITO)] = vfp_single_fuito,
+- [FEXT_TO_IDX(FEXT_FSITO)] = vfp_single_fsito,
+- [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_single_ftoui,
+- [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_single_ftouiz,
+- [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_single_ftosi,
+- [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_single_ftosiz,
++static struct op fops_ext[32] = {
++ [FEXT_TO_IDX(FEXT_FCPY)] = { vfp_single_fcpy, 0 },
++ [FEXT_TO_IDX(FEXT_FABS)] = { vfp_single_fabs, 0 },
++ [FEXT_TO_IDX(FEXT_FNEG)] = { vfp_single_fneg, 0 },
++ [FEXT_TO_IDX(FEXT_FSQRT)] = { vfp_single_fsqrt, 0 },
++ [FEXT_TO_IDX(FEXT_FCMP)] = { vfp_single_fcmp, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCMPE)] = { vfp_single_fcmpe, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCMPZ)] = { vfp_single_fcmpz, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCMPEZ)] = { vfp_single_fcmpez, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FCVT)] = { vfp_single_fcvtd, OP_SCALAR|OP_DD },
++ [FEXT_TO_IDX(FEXT_FUITO)] = { vfp_single_fuito, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FSITO)] = { vfp_single_fsito, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FTOUI)] = { vfp_single_ftoui, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FTOUIZ)] = { vfp_single_ftouiz, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FTOSI)] = { vfp_single_ftosi, OP_SCALAR },
++ [FEXT_TO_IDX(FEXT_FTOSIZ)] = { vfp_single_ftosiz, OP_SCALAR },
+ };
+
+
+@@ -1151,16 +1153,16 @@ static u32 vfp_single_fdiv(int sd, int s
+ return FPSCR_IOC;
+ }
+
+-static u32 (* const fop_fns[16])(int sd, int sn, s32 m, u32 fpscr) = {
+- [FOP_TO_IDX(FOP_FMAC)] = vfp_single_fmac,
+- [FOP_TO_IDX(FOP_FNMAC)] = vfp_single_fnmac,
+- [FOP_TO_IDX(FOP_FMSC)] = vfp_single_fmsc,
+- [FOP_TO_IDX(FOP_FNMSC)] = vfp_single_fnmsc,
+- [FOP_TO_IDX(FOP_FMUL)] = vfp_single_fmul,
+- [FOP_TO_IDX(FOP_FNMUL)] = vfp_single_fnmul,
+- [FOP_TO_IDX(FOP_FADD)] = vfp_single_fadd,
+- [FOP_TO_IDX(FOP_FSUB)] = vfp_single_fsub,
+- [FOP_TO_IDX(FOP_FDIV)] = vfp_single_fdiv,
++static struct op fops[16] = {
++ [FOP_TO_IDX(FOP_FMAC)] = { vfp_single_fmac, 0 },
++ [FOP_TO_IDX(FOP_FNMAC)] = { vfp_single_fnmac, 0 },
++ [FOP_TO_IDX(FOP_FMSC)] = { vfp_single_fmsc, 0 },
++ [FOP_TO_IDX(FOP_FNMSC)] = { vfp_single_fnmsc, 0 },
++ [FOP_TO_IDX(FOP_FMUL)] = { vfp_single_fmul, 0 },
++ [FOP_TO_IDX(FOP_FNMUL)] = { vfp_single_fnmul, 0 },
++ [FOP_TO_IDX(FOP_FADD)] = { vfp_single_fadd, 0 },
++ [FOP_TO_IDX(FOP_FSUB)] = { vfp_single_fsub, 0 },
++ [FOP_TO_IDX(FOP_FDIV)] = { vfp_single_fdiv, 0 },
+ };
+
+ #define FREG_BANK(x) ((x) & 0x18)
+@@ -1174,70 +1176,63 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
+ unsigned int sn = vfp_get_sn(inst);
+ unsigned int sm = vfp_get_sm(inst);
+ unsigned int vecitr, veclen, vecstride;
+- u32 (*fop)(int, int, s32, u32);
++ struct op *fop;
+
+- veclen = fpscr & FPSCR_LENGTH_MASK;
+ vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
+
++ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
++
+ /*
+ * fcvtsd takes a dN register number as destination, not sN.
+ * Technically, if bit 0 of dd is set, this is an invalid
+ * instruction. However, we ignore this for efficiency.
+ * It also only operates on scalars.
+ */
+- if ((inst & FEXT_MASK) == FEXT_FCVT) {
+- veclen = 0;
++ if (fop->flags & OP_DD)
+ dest = vfp_get_dd(inst);
+- } else
++ else
+ dest = vfp_get_sd(inst);
+
+ /*
+ * If destination bank is zero, vector length is always '1'.
+ * ARM DDI0100F C5.1.3, C5.3.2.
+ */
+- if (FREG_BANK(dest) == 0)
++ if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
+ veclen = 0;
++ else
++ veclen = fpscr & FPSCR_LENGTH_MASK;
+
+ pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+- fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)];
+- if (!fop)
++ if (!fop->fn)
+ goto invalid;
+
+ for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+ s32 m = vfp_get_float(sm);
+ u32 except;
++ char type;
+
+- if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT)
+- pr_debug("VFP: itr%d (d%u) = op[%u] (s%u=%08x)\n",
+- vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
+- else if (op == FOP_EXT)
+- pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n",
+- vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
++ type = fop->flags & OP_DD ? 'd' : 's';
++ if (op == FOP_EXT)
++ pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
++ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
++ sm, m);
+ else
+- pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n",
+- vecitr >> FPSCR_LENGTH_BIT, dest, sn,
++ pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
++ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ FOP_TO_IDX(op), sm, m);
+
+- except = fop(dest, sn, m, fpscr);
++ except = fop->fn(dest, sn, m, fpscr);
+ pr_debug("VFP: itr%d: exceptions=%08x\n",
+ vecitr >> FPSCR_LENGTH_BIT, except);
+
+ exceptions |= except;
+
+ /*
+- * This ensures that comparisons only operate on scalars;
+- * comparisons always return with one FPSCR status bit set.
+- */
+- if (except & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
+- break;
+-
+- /*
+ * CHECK: It appears to be undefined whether we stop when
+ * we encounter an exception. We continue.
+ */
+-
+ dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
+ sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
+ if (FREG_BANK(sm) != 0)
+diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
+index 07907b6..93293d0 100644
+--- a/arch/arm26/kernel/armksyms.c
++++ b/arch/arm26/kernel/armksyms.c
+@@ -202,14 +202,6 @@ EXPORT_SYMBOL(_find_next_zero_bit_le);
+ EXPORT_SYMBOL(elf_platform);
+ EXPORT_SYMBOL(elf_hwcap);
+
+- /* syscalls */
+-EXPORT_SYMBOL(sys_write);
+-EXPORT_SYMBOL(sys_read);
+-EXPORT_SYMBOL(sys_lseek);
+-EXPORT_SYMBOL(sys_open);
+-EXPORT_SYMBOL(sys_exit);
+-EXPORT_SYMBOL(sys_wait4);
+-
+ #ifdef CONFIG_PREEMPT
+ EXPORT_SYMBOL(kernel_flag);
+ #endif
+diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c
+index e7eb070..466ddb5 100644
+--- a/arch/arm26/kernel/setup.c
++++ b/arch/arm26/kernel/setup.c
+@@ -143,7 +143,7 @@ static void __init setup_processor(void)
+
+ dump_cpu_info();
+
+- sprintf(system_utsname.machine, "%s", list->arch_name);
++ sprintf(init_utsname()->machine, "%s", list->arch_name);
+ sprintf(elf_platform, "%s", list->elf_name);
+ elf_hwcap = list->elf_hwcap;
+
+diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c
+index 8545789..dc05aba 100644
+--- a/arch/arm26/kernel/sys_arm.c
++++ b/arch/arm26/kernel/sys_arm.c
+@@ -283,7 +283,7 @@ out:
+ }
+
+ /* FIXME - see if this is correct for arm26 */
+-long execve(const char *filename, char **argv, char **envp)
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+ {
+ struct pt_regs regs;
+ int ret;
+@@ -320,4 +320,4 @@ long execve(const char *filename, char *
+ return ret;
+ }
+
+-EXPORT_SYMBOL(execve);
++EXPORT_SYMBOL(kernel_execve);
+diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c
+index db63d75..1206469 100644
+--- a/arch/arm26/kernel/time.c
++++ b/arch/arm26/kernel/time.c
+@@ -33,8 +33,6 @@
+ #include <asm/irq.h>
+ #include <asm/ioc.h>
+
+-extern unsigned long wall_jiffies;
+-
+ /* this needs a better home */
+ DEFINE_SPINLOCK(rtc_lock);
+
+@@ -136,16 +134,11 @@ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+ unsigned long seq;
+- unsigned long usec, sec, lost;
++ unsigned long usec, sec;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = gettimeoffset();
+-
+- lost = jiffies - wall_jiffies;
+- if (lost)
+- usec += lost * USECS_PER_JIFFY;
+-
+ sec = xtime.tv_sec;
+ usec += xtime.tv_nsec / 1000;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+@@ -174,8 +167,7 @@ int do_settimeofday(struct timespec *tv)
+ * wall time. Discover what correction gettimeofday() would have
+ * done, and then undo it!
+ */
+- tv->tv_nsec -= 1000 * (gettimeoffset() +
+- (jiffies - wall_jiffies) * USECS_PER_JIFFY);
++ tv->tv_nsec -= 1000 * gettimeoffset();
+
+ while (tv->tv_nsec < 0) {
+ tv->tv_nsec += NSEC_PER_SEC;
+@@ -194,7 +186,7 @@ EXPORT_SYMBOL(do_settimeofday);
+
+ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+diff --git a/arch/arm26/lib/ecard.S b/arch/arm26/lib/ecard.S
+index b463315..658bc45 100644
+--- a/arch/arm26/lib/ecard.S
++++ b/arch/arm26/lib/ecard.S
+@@ -7,7 +7,6 @@
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+-#include <linux/config.h> /* for CONFIG_CPU_nn */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+ #include <asm/hardware.h>
+diff --git a/arch/arm26/lib/io-acorn.S b/arch/arm26/lib/io-acorn.S
+index f6c3e30..5f62ade 100644
+--- a/arch/arm26/lib/io-acorn.S
++++ b/arch/arm26/lib/io-acorn.S
+@@ -7,7 +7,6 @@
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+-#include <linux/config.h> /* for CONFIG_CPU_nn */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+ #include <asm/hardware.h>
+diff --git a/arch/arm26/mm/fault.c b/arch/arm26/mm/fault.c
+index 761938b..a1f6d8a 100644
+--- a/arch/arm26/mm/fault.c
++++ b/arch/arm26/mm/fault.c
+@@ -155,7 +155,7 @@ __do_page_fault(struct mm_struct *mm, un
+ */
+ good_area:
+ if (READ_FAULT(fsr)) /* read? */
+- mask = VM_READ|VM_EXEC;
++ mask = VM_READ|VM_EXEC|VM_WRITE;
+ else
+ mask = VM_WRITE;
+
+@@ -185,7 +185,7 @@ survive:
+ }
+
+ fault = -3; /* out of memory */
+- if (tsk->pid != 1)
++ if (!is_init(tsk))
+ goto out;
+
+ /*
+diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
+new file mode 100644
+index 0000000..5f1694e
+--- /dev/null
++++ b/arch/avr32/Kconfig
+@@ -0,0 +1,196 @@
++#
++# For a description of the syntax of this configuration file,
++# see Documentation/kbuild/kconfig-language.txt.
++#
++
++mainmenu "Linux Kernel Configuration"
++
++config AVR32
++ bool
++ default y
++ # With EMBEDDED=n, we get lots of stuff automatically selected
++ # that we usually don't need on AVR32.
++ select EMBEDDED
++ help
++ AVR32 is a high-performance 32-bit RISC microprocessor core,
++ designed for cost-sensitive embedded applications, with particular
++ emphasis on low power consumption and high code density.
++
++ There is an AVR32 Linux project with a web page at
++ http://avr32linux.org/.
++
++config UID16
++ bool
++
++config GENERIC_HARDIRQS
++ bool
++ default y
++
++config HARDIRQS_SW_RESEND
++ bool
++ default y
++
++config GENERIC_IRQ_PROBE
++ bool
++ default y
++
++config RWSEM_GENERIC_SPINLOCK
++ bool
++ default y
++
++config GENERIC_TIME
++ bool
++ default y
++
++config RWSEM_XCHGADD_ALGORITHM
++ bool
++
++config GENERIC_BUST_SPINLOCK
++ bool
++
++config GENERIC_HWEIGHT
++ bool
++ default y
++
++config GENERIC_CALIBRATE_DELAY
++ bool
++ default y
++
++source "init/Kconfig"
++
++menu "System Type and features"
++
++config SUBARCH_AVR32B
++ bool
++config MMU
++ bool
++config PERFORMANCE_COUNTERS
++ bool
++
++config PLATFORM_AT32AP
++ bool
++ select SUBARCH_AVR32B
++ select MMU
++ select PERFORMANCE_COUNTERS
++
++choice
++ prompt "AVR32 CPU type"
++ default CPU_AT32AP7000
++
++config CPU_AT32AP7000
++ bool "AT32AP7000"
++ select PLATFORM_AT32AP
++endchoice
++
++#
++# CPU Daughterboards for ATSTK1000
++config BOARD_ATSTK1002
++ bool
++
++choice
++ prompt "AVR32 board type"
++ default BOARD_ATSTK1000
++
++config BOARD_ATSTK1000
++ bool "ATSTK1000 evaluation board"
++ select BOARD_ATSTK1002 if CPU_AT32AP7000
++endchoice
++
++choice
++ prompt "Boot loader type"
++ default LOADER_U_BOOT
++
++config LOADER_U_BOOT
++ bool "U-Boot (or similar) bootloader"
++endchoice
++
++config LOAD_ADDRESS
++ hex
++ default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
++
++config ENTRY_ADDRESS
++ hex
++ default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
++
++config PHYS_OFFSET
++ hex
++ default 0x10000000 if CPU_AT32AP7000=y
++
++source "kernel/Kconfig.preempt"
++
++config HAVE_ARCH_BOOTMEM_NODE
++ bool
++ default n
++
++config ARCH_HAVE_MEMORY_PRESENT
++ bool
++ default n
++
++config NEED_NODE_MEMMAP_SIZE
++ bool
++ default n
++
++config ARCH_FLATMEM_ENABLE
++ bool
++ default y
++
++config ARCH_DISCONTIGMEM_ENABLE
++ bool
++ default n
++
++config ARCH_SPARSEMEM_ENABLE
++ bool
++ default n
++
++source "mm/Kconfig"
++
++config OWNERSHIP_TRACE
++ bool "Ownership trace support"
++ default y
++ help
++ Say Y to generate an Ownership Trace message on every context switch,
++ enabling Nexus-compliant debuggers to keep track of the PID of the
++ currently executing task.
++
++# FPU emulation goes here
++
++source "kernel/Kconfig.hz"
++
++config CMDLINE
++ string "Default kernel command line"
++ default ""
++ help
++ If you don't have a boot loader capable of passing a command line string
++ to the kernel, you may specify one here. As a minimum, you should specify
++ the memory size and the root device (e.g., mem=8M, root=/dev/nfs).
++
++endmenu
++
++menu "Bus options"
++
++config PCI
++ bool
++
++source "drivers/pci/Kconfig"
++
++source "drivers/pcmcia/Kconfig"
++
++endmenu
++
++menu "Executable file formats"
++source "fs/Kconfig.binfmt"
++endmenu
++
++source "net/Kconfig"
++
++source "drivers/Kconfig"
++
++source "fs/Kconfig"
++
++source "arch/avr32/Kconfig.debug"
++
++source "security/Kconfig"
++
++source "crypto/Kconfig"
++
++source "lib/Kconfig"
+diff --git a/arch/avr32/Kconfig.debug b/arch/avr32/Kconfig.debug
+new file mode 100644
+index 0000000..64ace00
+--- /dev/null
++++ b/arch/avr32/Kconfig.debug
+@@ -0,0 +1,19 @@
++menu "Kernel hacking"
++
++config TRACE_IRQFLAGS_SUPPORT
++ bool
++ default y
++
++source "lib/Kconfig.debug"
++
++config KPROBES
++ bool "Kprobes"
++ depends on DEBUG_KERNEL
++ help
++ Kprobes allows you to trap at almost any kernel address and
++ execute a callback function. register_kprobe() establishes
++ a probepoint and specifies the callback. Kprobes is useful
++ for kernel debugging, non-intrusive instrumentation and testing.
++ If in doubt, say "N".
++
++endmenu
+diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
+new file mode 100644
+index 0000000..7b842e9
+--- /dev/null
++++ b/arch/avr32/Makefile
+@@ -0,0 +1,89 @@
++#
++# 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-2006 Atmel Corporation.
++
++# Default target when executing plain make
++.PHONY: all
++all: uImage vmlinux.elf
++
++KBUILD_DEFCONFIG := atstk1002_defconfig
++
++CFLAGS += -pipe -fno-builtin -mno-pic
++AFLAGS += -mrelax -mno-pic
++CFLAGS_MODULE += -mno-relax
++LDFLAGS_vmlinux += --relax
++
++cpuflags-$(CONFIG_CPU_AP7000) += -mcpu=ap7000
++
++CFLAGS += $(cpuflags-y)
++AFLAGS += $(cpuflags-y)
++
++CHECKFLAGS += -D__avr32__ -D__BIG_ENDIAN
++
++head-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/head.o
++head-y += arch/avr32/kernel/head.o
++core-$(CONFIG_PLATFORM_AT32AP) += arch/avr32/mach-at32ap/
++core-$(CONFIG_BOARD_ATSTK1000) += arch/avr32/boards/atstk1000/
++core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/
++core-y += arch/avr32/kernel/
++core-y += arch/avr32/mm/
++libs-y += arch/avr32/lib/
++
++archincdir-$(CONFIG_PLATFORM_AT32AP) := arch-at32ap
++
++include/asm-avr32/.arch: $(wildcard include/config/platform/*.h) include/config/auto.conf
++ @echo ' SYMLINK include/asm-avr32/arch -> include/asm-avr32/$(archincdir-y)'
++ifneq ($(KBUILD_SRC),)
++ $(Q)mkdir -p include/asm-avr32
++ $(Q)ln -fsn $(srctree)/include/asm-avr32/$(archincdir-y) include/asm-avr32/arch
++else
++ $(Q)ln -fsn $(archincdir-y) include/asm-avr32/arch
++endif
++ @touch $@
++
++archprepare: include/asm-avr32/.arch
++
++CLEAN_FILES += include/asm-avr32/.arch include/asm-avr32/arch
++
++BOOT_TARGETS := vmlinux.elf vmlinux.bin uImage uImage.srec
++
++.PHONY: $(BOOT_TARGETS) install
++
++boot := arch/$(ARCH)/boot/images
++
++ KBUILD_IMAGE := $(boot)/uImage
++vmlinux.elf: KBUILD_IMAGE := $(boot)/vmlinux.elf
++vmlinux.cso: KBUILD_IMAGE := $(boot)/vmlinux.cso
++uImage.srec: KBUILD_IMAGE := $(boot)/uImage.srec
++uImage: KBUILD_IMAGE := $(boot)/uImage
++
++quiet_cmd_listing = LST $@
++ cmd_listing = avr32-linux-objdump $(OBJDUMPFLAGS) -lS $< > $@
++quiet_cmd_disasm = DIS $@
++ cmd_disasm = avr32-linux-objdump $(OBJDUMPFLAGS) -d $< > $@
++
++vmlinux.elf vmlinux.bin uImage.srec uImage vmlinux.cso: vmlinux
++ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
++
++install: vmlinux
++ $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
++
++vmlinux.s: vmlinux
++ $(call if_changed,disasm)
++
++vmlinux.lst: vmlinux
++ $(call if_changed,listing)
++
++CLEAN_FILES += vmlinux.s vmlinux.lst
++
++archclean:
++ $(Q)$(MAKE) $(clean)=$(boot)
++
++define archhelp
++ @echo '* vmlinux.elf - ELF image with load address 0'
++ @echo ' vmlinux.cso - PathFinder CSO image'
++ @echo '* uImage - Create a bootable image for U-Boot'
++endef
+diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile
+new file mode 100644
+index 0000000..df94994
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/Makefile
+@@ -0,0 +1,2 @@
++obj-y += setup.o spi.o flash.o
++obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o
+diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
+new file mode 100644
+index 0000000..cced73c
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/atstk1002.c
+@@ -0,0 +1,47 @@
++/*
++ * ATSTK1002 daughterboard-specific init code
++ *
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++#include <linux/init.h>
++
++#include <asm/arch/board.h>
++#include <asm/arch/init.h>
++
++struct eth_platform_data __initdata eth0_data = {
++ .valid = 1,
++ .mii_phy_addr = 0x10,
++ .is_rmii = 0,
++ .hw_addr = { 0x6a, 0x87, 0x71, 0x14, 0xcd, 0xcb },
++};
++
++extern struct lcdc_platform_data atstk1000_fb0_data;
++
++void __init setup_board(void)
++{
++ at32_map_usart(1, 0); /* /dev/ttyS0 */
++ at32_map_usart(2, 1); /* /dev/ttyS1 */
++ at32_map_usart(3, 2); /* /dev/ttyS2 */
++
++ at32_setup_serial_console(0);
++}
++
++static int __init atstk1002_init(void)
++{
++ at32_add_system_devices();
++
++ at32_add_device_usart(0);
++ at32_add_device_usart(1);
++ at32_add_device_usart(2);
++
++ at32_add_device_eth(0, ð0_data);
++ at32_add_device_spi(0);
++ at32_add_device_lcdc(0, &atstk1000_fb0_data);
++
++ return 0;
++}
++postcore_initcall(atstk1002_init);
+diff --git a/arch/avr32/boards/atstk1000/flash.c b/arch/avr32/boards/atstk1000/flash.c
+new file mode 100644
+index 0000000..aac4300
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/flash.c
+@@ -0,0 +1,95 @@
++/*
++ * ATSTK1000 board-specific flash initialization
++ *
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/physmap.h>
++
++#include <asm/arch/smc.h>
++
++static struct smc_config flash_config __initdata = {
++ .ncs_read_setup = 0,
++ .nrd_setup = 40,
++ .ncs_write_setup = 0,
++ .nwe_setup = 10,
++
++ .ncs_read_pulse = 80,
++ .nrd_pulse = 40,
++ .ncs_write_pulse = 65,
++ .nwe_pulse = 55,
++
++ .read_cycle = 120,
++ .write_cycle = 120,
++
++ .bus_width = 2,
++ .nrd_controlled = 1,
++ .nwe_controlled = 1,
++ .byte_write = 1,
++};
++
++static struct mtd_partition flash_parts[] = {
++ {
++ .name = "u-boot",
++ .offset = 0x00000000,
++ .size = 0x00020000, /* 128 KiB */
++ .mask_flags = MTD_WRITEABLE,
++ },
++ {
++ .name = "root",
++ .offset = 0x00020000,
++ .size = 0x007d0000,
++ },
++ {
++ .name = "env",
++ .offset = 0x007f0000,
++ .size = 0x00010000,
++ .mask_flags = MTD_WRITEABLE,
++ },
++};
++
++static struct physmap_flash_data flash_data = {
++ .width = 2,
++ .nr_parts = ARRAY_SIZE(flash_parts),
++ .parts = flash_parts,
++};
++
++static struct resource flash_resource = {
++ .start = 0x00000000,
++ .end = 0x007fffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device flash_device = {
++ .name = "physmap-flash",
++ .id = 0,
++ .resource = &flash_resource,
++ .num_resources = 1,
++ .dev = {
++ .platform_data = &flash_data,
++ },
++};
++
++/* This needs to be called after the SMC has been initialized */
++static int __init atstk1000_flash_init(void)
++{
++ int ret;
++
++ ret = smc_set_configuration(0, &flash_config);
++ if (ret < 0) {
++ printk(KERN_ERR "atstk1000: failed to set NOR flash timing\n");
++ return ret;
++ }
++
++ platform_device_register(&flash_device);
++
++ return 0;
++}
++device_initcall(atstk1000_flash_init);
+diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
+new file mode 100644
+index 0000000..272c011
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/setup.c
+@@ -0,0 +1,50 @@
++/*
++ * ATSTK1000 board-specific setup code.
++ *
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++#include <linux/bootmem.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/linkage.h>
++
++#include <asm/setup.h>
++
++#include <asm/arch/board.h>
++
++/* Initialized by bootloader-specific startup code. */
++struct tag *bootloader_tags __initdata;
++
++struct lcdc_platform_data __initdata atstk1000_fb0_data;
++
++void __init board_setup_fbmem(unsigned long fbmem_start,
++ unsigned long fbmem_size)
++{
++ if (!fbmem_size)
++ return;
++
++ if (!fbmem_start) {
++ void *fbmem;
++
++ fbmem = alloc_bootmem_low_pages(fbmem_size);
++ fbmem_start = __pa(fbmem);
++ } else {
++ pg_data_t *pgdat;
++
++ for_each_online_pgdat(pgdat) {
++ if (fbmem_start >= pgdat->bdata->node_boot_start
++ && fbmem_start <= pgdat->bdata->node_low_pfn)
++ reserve_bootmem_node(pgdat, fbmem_start,
++ fbmem_size);
++ }
++ }
++
++ printk("%luKiB framebuffer memory at address 0x%08lx\n",
++ fbmem_size >> 10, fbmem_start);
++ atstk1000_fb0_data.fbmem_start = fbmem_start;
++ atstk1000_fb0_data.fbmem_size = fbmem_size;
++}
+diff --git a/arch/avr32/boards/atstk1000/spi.c b/arch/avr32/boards/atstk1000/spi.c
+new file mode 100644
+index 0000000..567726c
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/spi.c
+@@ -0,0 +1,27 @@
++/*
++ * ATSTK1000 SPI devices
++ *
++ * Copyright (C) 2005 Atmel Norway
++ *
++ * 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/device.h>
++#include <linux/spi/spi.h>
++
++static struct spi_board_info spi_board_info[] __initdata = {
++ {
++ .modalias = "ltv350qv",
++ .max_speed_hz = 16000000,
++ .bus_num = 0,
++ .chip_select = 1,
++ },
++};
++
++static int board_init_spi(void)
++{
++ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
++ return 0;
++}
++arch_initcall(board_init_spi);
+diff --git a/arch/avr32/boot/images/Makefile b/arch/avr32/boot/images/Makefile
+new file mode 100644
+index 0000000..219720a
+--- /dev/null
++++ b/arch/avr32/boot/images/Makefile
+@@ -0,0 +1,60 @@
++#
++# Copyright (C) 2004-2006 Atmel Corporation
++#
++# 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.
++#
++
++MKIMAGE := $(srctree)/scripts/mkuboot.sh
++
++extra-y := vmlinux.bin vmlinux.gz
++
++OBJCOPYFLAGS_vmlinux.bin := -O binary
++$(obj)/vmlinux.bin: vmlinux FORCE
++ $(call if_changed,objcopy)
++
++$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
++ $(call if_changed,gzip)
++
++quiet_cmd_uimage = UIMAGE $@
++ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A avr32 -O linux -T kernel \
++ -C gzip -a $(CONFIG_LOAD_ADDRESS) -e $(CONFIG_ENTRY_ADDRESS) \
++ -n 'Linux-$(KERNELRELEASE)' -d $< $@
++
++targets += uImage uImage.srec
++$(obj)/uImage: $(obj)/vmlinux.gz
++ $(call if_changed,uimage)
++ @echo ' Image $@ is ready'
++
++OBJCOPYFLAGS_uImage.srec := -I binary -O srec
++$(obj)/uImage.srec: $(obj)/uImage
++ $(call if_changed,objcopy)
++
++OBJCOPYFLAGS_vmlinux.elf := --change-section-lma .text-0x80000000 \
++ --change-section-lma __ex_table-0x80000000 \
++ --change-section-lma .rodata-0x80000000 \
++ --change-section-lma .data-0x80000000 \
++ --change-section-lma .init-0x80000000 \
++ --change-section-lma .bss-0x80000000 \
++ --change-section-lma __param-0x80000000 \
++ --change-section-lma __ksymtab-0x80000000 \
++ --change-section-lma __ksymtab_gpl-0x80000000 \
++ --change-section-lma __kcrctab-0x80000000 \
++ --change-section-lma __kcrctab_gpl-0x80000000 \
++ --change-section-lma __ksymtab_strings-0x80000000 \
++ --set-start 0xa0000000
++$(obj)/vmlinux.elf: vmlinux FORCE
++ $(call if_changed,objcopy)
++
++quiet_cmd_sfdwarf = SFDWARF $@
++ cmd_sfdwarf = sfdwarf $< TO $@ GNUAVR IW $(SFDWARF_FLAGS) > $(obj)/sfdwarf.log
++
++$(obj)/vmlinux.cso: $(obj)/vmlinux.elf FORCE
++ $(call if_changed,sfdwarf)
++
++install: $(BOOTIMAGE)
++ sh $(srctree)/install-kernel.sh $<
++
++# Generated files to be removed upon make clean
++clean-files := vmlinux.elf vmlinux.bin vmlinux.gz uImage uImage.srec
+diff --git a/arch/avr32/boot/u-boot/Makefile b/arch/avr32/boot/u-boot/Makefile
+new file mode 100644
+index 0000000..125ddc9
+--- /dev/null
++++ b/arch/avr32/boot/u-boot/Makefile
+@@ -0,0 +1,3 @@
++extra-y := head.o
++
++obj-y := empty.o
+diff --git a/arch/avr32/boot/u-boot/empty.S b/arch/avr32/boot/u-boot/empty.S
+new file mode 100644
+index 0000000..8ac91a5
+--- /dev/null
++++ b/arch/avr32/boot/u-boot/empty.S
+@@ -0,0 +1 @@
++/* Empty file */
+diff --git a/arch/avr32/boot/u-boot/head.S b/arch/avr32/boot/u-boot/head.S
+new file mode 100644
+index 0000000..4488fa2
+--- /dev/null
++++ b/arch/avr32/boot/u-boot/head.S
+@@ -0,0 +1,60 @@
++/*
++ * Startup code for use with the u-boot bootloader.
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <asm/setup.h>
++
++ /*
++ * The kernel is loaded where we want it to be and all caches
++ * have just been flushed. We get two parameters from u-boot:
++ *
++ * r12 contains a magic number (ATAG_MAGIC)
++ * r11 points to a tag table providing information about
++ * the system.
++ */
++ .section .init.text,"ax"
++ .global _start
++_start:
++ /* Check if the boot loader actually provided a tag table */
++ lddpc r0, magic_number
++ cp.w r12, r0
++ brne no_tag_table
++
++ /* Initialize .bss */
++ lddpc r2, bss_start_addr
++ lddpc r3, end_addr
++ mov r0, 0
++ mov r1, 0
++1: st.d r2++, r0
++ cp r2, r3
++ brlo 1b
++
++ /*
++ * Save the tag table address for later use. This must be done
++ * _after_ .bss has been initialized...
++ */
++ lddpc r0, tag_table_addr
++ st.w r0[0], r11
++
++ /* Jump to loader-independent setup code */
++ rjmp kernel_entry
++
++ .align 2
++magic_number:
++ .long ATAG_MAGIC
++tag_table_addr:
++ .long bootloader_tags
++bss_start_addr:
++ .long __bss_start
++end_addr:
++ .long _end
++
++no_tag_table:
++ sub r12, pc, (. - 2f)
++ bral panic
++2: .asciz "Boot loader didn't provide correct magic number\n"
+diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
+new file mode 100644
+index 0000000..ae92a14
+--- /dev/null
++++ b/arch/avr32/configs/atstk1002_defconfig
+@@ -0,0 +1,819 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.19-rc2
++# Fri Oct 20 11:52:37 2006
++#
++CONFIG_AVR32=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++# CONFIG_UTS_NS is not set
++CONFIG_AUDIT=y
++# CONFIG_IKCONFIG is not set
++CONFIG_RELAY=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++# CONFIG_TASK_XACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++# CONFIG_BASE_FULL is not set
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=1
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_BLK_DEV_IO_TRACE 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_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++CONFIG_DEFAULT_NOOP=y
++CONFIG_DEFAULT_IOSCHED="noop"
++
++#
++# System Type and features
++#
++CONFIG_SUBARCH_AVR32B=y
++CONFIG_MMU=y
++CONFIG_PERFORMANCE_COUNTERS=y
++CONFIG_PLATFORM_AT32AP=y
++CONFIG_CPU_AT32AP7000=y
++CONFIG_BOARD_ATSTK1002=y
++CONFIG_BOARD_ATSTK1000=y
++CONFIG_LOADER_U_BOOT=y
++CONFIG_LOAD_ADDRESS=0x10000000
++CONFIG_ENTRY_ADDRESS=0x90000000
++CONFIG_PHYS_OFFSET=0x10000000
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
++# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
++# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
++CONFIG_ARCH_FLATMEM_ENABLE=y
++# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
++# CONFIG_ARCH_SPARSEMEM_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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_OWNERSHIP_TRACE is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++CONFIG_CMDLINE=""
++
++#
++# Bus options
++#
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++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 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++# CONFIG_FW_LOADER is not set
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x8000000
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=2
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# 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=m
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# Misc devices
++#
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA 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
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++CONFIG_DUMMY=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=m
++
++#
++# PHY device support
++#
++
++#
++# Ethernet (10 or 100Mbit)
++#
++# CONFIG_NET_ETHERNET 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=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPP_MPPE is not set
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=m
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER 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_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=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_HW_RANDOM is not set
++# CONFIG_RTC is not set
++# CONFIG_GEN_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB is not set
++# 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
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=m
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4DEV_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_MINIX_FS=m
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_VFAT_FS=m
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++CONFIG_CONFIGFS_FS=m
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++# CONFIG_NFS_FS is not set
++# CONFIG_NFSD 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
++# CONFIG_9P_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS=m
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# 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=m
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++CONFIG_NLS_UTF8=m
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS 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_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
++CONFIG_FORCED_INLINING=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_KPROBES is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++# CONFIG_CRYPTO is not set
++
++#
++# Library routines
++#
++CONFIG_CRC_CCITT=m
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_AUDIT_GENERIC=y
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile
+new file mode 100644
+index 0000000..90e5aff
+--- /dev/null
++++ b/arch/avr32/kernel/Makefile
+@@ -0,0 +1,18 @@
++#
++# Makefile for the Linux/AVR32 kernel.
++#
++
++extra-y := head.o vmlinux.lds
++
++obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o
++obj-y += syscall_table.o syscall-stubs.o irq.o
++obj-y += setup.o traps.o semaphore.o ptrace.o
++obj-y += signal.o sys_avr32.o process.o time.o
++obj-y += init_task.o switch_to.o cpu.o
++obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o
++obj-$(CONFIG_KPROBES) += kprobes.o
++
++USE_STANDARD_AS_RULE := true
++
++%.lds: %.lds.c FORCE
++ $(call if_changed_dep,cpp_lds_S)
+diff --git a/arch/avr32/kernel/asm-offsets.c b/arch/avr32/kernel/asm-offsets.c
+new file mode 100644
+index 0000000..97d8658
+--- /dev/null
++++ b/arch/avr32/kernel/asm-offsets.c
+@@ -0,0 +1,25 @@
++/*
++ * Generate definitions needed by assembly language modules.
++ * This code generates raw asm output which is post-processed
++ * to extract and format the required data.
++ */
++
++#include <linux/thread_info.h>
++
++#define DEFINE(sym, val) \
++ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
++
++#define BLANK() asm volatile("\n->" : : )
++
++#define OFFSET(sym, str, mem) \
++ DEFINE(sym, offsetof(struct str, mem));
++
++void foo(void)
++{
++ OFFSET(TI_task, thread_info, task);
++ OFFSET(TI_exec_domain, thread_info, exec_domain);
++ OFFSET(TI_flags, thread_info, flags);
++ OFFSET(TI_cpu, thread_info, cpu);
++ OFFSET(TI_preempt_count, thread_info, preempt_count);
++ OFFSET(TI_restart_block, thread_info, restart_block);
++}
+diff --git a/arch/avr32/kernel/avr32_ksyms.c b/arch/avr32/kernel/avr32_ksyms.c
+new file mode 100644
+index 0000000..372e3f8
+--- /dev/null
++++ b/arch/avr32/kernel/avr32_ksyms.c
+@@ -0,0 +1,64 @@
++/*
++ * Export AVR32-specific functions for loadable modules.
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/io.h>
++#include <linux/module.h>
++
++#include <asm/checksum.h>
++#include <asm/uaccess.h>
++#include <asm/delay.h>
++
++/*
++ * GCC functions
++ */
++extern unsigned long long __avr32_lsl64(unsigned long long u, unsigned long b);
++extern unsigned long long __avr32_lsr64(unsigned long long u, unsigned long b);
++extern unsigned long long __avr32_asr64(unsigned long long u, unsigned long b);
++EXPORT_SYMBOL(__avr32_lsl64);
++EXPORT_SYMBOL(__avr32_lsr64);
++EXPORT_SYMBOL(__avr32_asr64);
++
++/*
++ * String functions
++ */
++EXPORT_SYMBOL(memset);
++EXPORT_SYMBOL(memcpy);
++
++/*
++ * Userspace access stuff.
++ */
++EXPORT_SYMBOL(copy_from_user);
++EXPORT_SYMBOL(copy_to_user);
++EXPORT_SYMBOL(__copy_user);
++EXPORT_SYMBOL(strncpy_from_user);
++EXPORT_SYMBOL(__strncpy_from_user);
++EXPORT_SYMBOL(clear_user);
++EXPORT_SYMBOL(__clear_user);
++EXPORT_SYMBOL(csum_partial);
++EXPORT_SYMBOL(csum_partial_copy_generic);
++
++/* Delay loops (lib/delay.S) */
++EXPORT_SYMBOL(__ndelay);
++EXPORT_SYMBOL(__udelay);
++EXPORT_SYMBOL(__const_udelay);
++
++/* Bit operations (lib/findbit.S) */
++EXPORT_SYMBOL(find_first_zero_bit);
++EXPORT_SYMBOL(find_next_zero_bit);
++EXPORT_SYMBOL(find_first_bit);
++EXPORT_SYMBOL(find_next_bit);
++EXPORT_SYMBOL(generic_find_next_zero_le_bit);
++
++/* I/O primitives (lib/io-*.S) */
++EXPORT_SYMBOL(__raw_readsb);
++EXPORT_SYMBOL(__raw_readsw);
++EXPORT_SYMBOL(__raw_readsl);
++EXPORT_SYMBOL(__raw_writesb);
++EXPORT_SYMBOL(__raw_writesw);
++EXPORT_SYMBOL(__raw_writesl);
+diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
+new file mode 100644
+index 0000000..342452b
+--- /dev/null
++++ b/arch/avr32/kernel/cpu.c
+@@ -0,0 +1,327 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++#include <linux/init.h>
++#include <linux/sysdev.h>
++#include <linux/seq_file.h>
++#include <linux/cpu.h>
++#include <linux/percpu.h>
++#include <linux/param.h>
++#include <linux/errno.h>
++
++#include <asm/setup.h>
++#include <asm/sysreg.h>
++
++static DEFINE_PER_CPU(struct cpu, cpu_devices);
++
++#ifdef CONFIG_PERFORMANCE_COUNTERS
++
++/*
++ * XXX: If/when a SMP-capable implementation of AVR32 will ever be
++ * made, we must make sure that the code executes on the correct CPU.
++ */
++static ssize_t show_pc0event(struct sys_device *dev, char *buf)
++{
++ unsigned long pccr;
++
++ pccr = sysreg_read(PCCR);
++ return sprintf(buf, "0x%lx\n", (pccr >> 12) & 0x3f);
++}
++static ssize_t store_pc0event(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (endp == buf || val > 0x3f)
++ return -EINVAL;
++ val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff);
++ sysreg_write(PCCR, val);
++ return count;
++}
++static ssize_t show_pc0count(struct sys_device *dev, char *buf)
++{
++ unsigned long pcnt0;
++
++ pcnt0 = sysreg_read(PCNT0);
++ return sprintf(buf, "%lu\n", pcnt0);
++}
++static ssize_t store_pc0count(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (endp == buf)
++ return -EINVAL;
++ sysreg_write(PCNT0, val);
++
++ return count;
++}
++
++static ssize_t show_pc1event(struct sys_device *dev, char *buf)
++{
++ unsigned long pccr;
++
++ pccr = sysreg_read(PCCR);
++ return sprintf(buf, "0x%lx\n", (pccr >> 18) & 0x3f);
++}
++static ssize_t store_pc1event(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (endp == buf || val > 0x3f)
++ return -EINVAL;
++ val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff);
++ sysreg_write(PCCR, val);
++ return count;
++}
++static ssize_t show_pc1count(struct sys_device *dev, char *buf)
++{
++ unsigned long pcnt1;
++
++ pcnt1 = sysreg_read(PCNT1);
++ return sprintf(buf, "%lu\n", pcnt1);
++}
++static ssize_t store_pc1count(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (endp == buf)
++ return -EINVAL;
++ sysreg_write(PCNT1, val);
++
++ return count;
++}
++
++static ssize_t show_pccycles(struct sys_device *dev, char *buf)
++{
++ unsigned long pccnt;
++
++ pccnt = sysreg_read(PCCNT);
++ return sprintf(buf, "%lu\n", pccnt);
++}
++static ssize_t store_pccycles(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (endp == buf)
++ return -EINVAL;
++ sysreg_write(PCCNT, val);
++
++ return count;
++}
++
++static ssize_t show_pcenable(struct sys_device *dev, char *buf)
++{
++ unsigned long pccr;
++
++ pccr = sysreg_read(PCCR);
++ return sprintf(buf, "%c\n", (pccr & 1)?'1':'0');
++}
++static ssize_t store_pcenable(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned long pccr, val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (endp == buf)
++ return -EINVAL;
++ if (val)
++ val = 1;
++
++ pccr = sysreg_read(PCCR);
++ pccr = (pccr & ~1UL) | val;
++ sysreg_write(PCCR, pccr);
++
++ return count;
++}
++
++static SYSDEV_ATTR(pc0event, 0600, show_pc0event, store_pc0event);
++static SYSDEV_ATTR(pc0count, 0600, show_pc0count, store_pc0count);
++static SYSDEV_ATTR(pc1event, 0600, show_pc1event, store_pc1event);
++static SYSDEV_ATTR(pc1count, 0600, show_pc1count, store_pc1count);
++static SYSDEV_ATTR(pccycles, 0600, show_pccycles, store_pccycles);
++static SYSDEV_ATTR(pcenable, 0600, show_pcenable, store_pcenable);
++
++#endif /* CONFIG_PERFORMANCE_COUNTERS */
++
++static int __init topology_init(void)
++{
++ int cpu;
++
++ for_each_possible_cpu(cpu) {
++ struct cpu *c = &per_cpu(cpu_devices, cpu);
++
++ register_cpu(c, cpu);
++
++#ifdef CONFIG_PERFORMANCE_COUNTERS
++ sysdev_create_file(&c->sysdev, &attr_pc0event);
++ sysdev_create_file(&c->sysdev, &attr_pc0count);
++ sysdev_create_file(&c->sysdev, &attr_pc1event);
++ sysdev_create_file(&c->sysdev, &attr_pc1count);
++ sysdev_create_file(&c->sysdev, &attr_pccycles);
++ sysdev_create_file(&c->sysdev, &attr_pcenable);
++#endif
++ }
++
++ return 0;
++}
++
++subsys_initcall(topology_init);
++
++static const char *cpu_names[] = {
++ "Morgan",
++ "AP7000",
++};
++#define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
++
++static const char *arch_names[] = {
++ "AVR32A",
++ "AVR32B",
++};
++#define NR_ARCH_NAMES ARRAY_SIZE(arch_names)
++
++static const char *mmu_types[] = {
++ "No MMU",
++ "ITLB and DTLB",
++ "Shared TLB",
++ "MPU"
++};
++
++void __init setup_processor(void)
++{
++ unsigned long config0, config1;
++ unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
++ unsigned tmp;
++
++ config0 = sysreg_read(CONFIG0); /* 0x0000013e; */
++ config1 = sysreg_read(CONFIG1); /* 0x01f689a2; */
++ cpu_id = config0 >> 24;
++ cpu_rev = (config0 >> 16) & 0xff;
++ arch_id = (config0 >> 13) & 0x07;
++ arch_rev = (config0 >> 10) & 0x07;
++ mmu_type = (config0 >> 7) & 0x03;
++
++ boot_cpu_data.arch_type = arch_id;
++ boot_cpu_data.cpu_type = cpu_id;
++ boot_cpu_data.arch_revision = arch_rev;
++ boot_cpu_data.cpu_revision = cpu_rev;
++ boot_cpu_data.tlb_config = mmu_type;
++
++ tmp = (config1 >> 13) & 0x07;
++ if (tmp) {
++ boot_cpu_data.icache.ways = 1 << ((config1 >> 10) & 0x07);
++ boot_cpu_data.icache.sets = 1 << ((config1 >> 16) & 0x0f);
++ boot_cpu_data.icache.linesz = 1 << (tmp + 1);
++ }
++ tmp = (config1 >> 3) & 0x07;
++ if (tmp) {
++ boot_cpu_data.dcache.ways = 1 << (config1 & 0x07);
++ boot_cpu_data.dcache.sets = 1 << ((config1 >> 6) & 0x0f);
++ boot_cpu_data.dcache.linesz = 1 << (tmp + 1);
++ }
++
++ if ((cpu_id >= NR_CPU_NAMES) || (arch_id >= NR_ARCH_NAMES)) {
++ printk ("Unknown CPU configuration (ID %02x, arch %02x), "
++ "continuing anyway...\n",
++ cpu_id, arch_id);
++ return;
++ }
++
++ printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
++ cpu_names[cpu_id], cpu_id, cpu_rev,
++ arch_names[arch_id], arch_rev);
++ printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
++ printk ("CPU: features:");
++ if (config0 & (1 << 6))
++ printk(" fpu");
++ if (config0 & (1 << 5))
++ printk(" java");
++ if (config0 & (1 << 4))
++ printk(" perfctr");
++ if (config0 & (1 << 3))
++ printk(" ocd");
++ printk("\n");
++}
++
++#ifdef CONFIG_PROC_FS
++static int c_show(struct seq_file *m, void *v)
++{
++ unsigned int icache_size, dcache_size;
++ unsigned int cpu = smp_processor_id();
++
++ icache_size = boot_cpu_data.icache.ways *
++ boot_cpu_data.icache.sets *
++ boot_cpu_data.icache.linesz;
++ dcache_size = boot_cpu_data.dcache.ways *
++ boot_cpu_data.dcache.sets *
++ boot_cpu_data.dcache.linesz;
++
++ seq_printf(m, "processor\t: %d\n", cpu);
++
++ if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
++ seq_printf(m, "cpu family\t: %s revision %d\n",
++ arch_names[boot_cpu_data.arch_type],
++ boot_cpu_data.arch_revision);
++ if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
++ seq_printf(m, "cpu type\t: %s revision %d\n",
++ cpu_names[boot_cpu_data.cpu_type],
++ boot_cpu_data.cpu_revision);
++
++ seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
++ icache_size >> 10,
++ boot_cpu_data.icache.ways,
++ boot_cpu_data.icache.sets,
++ boot_cpu_data.icache.linesz);
++ seq_printf(m, "d-cache\t\t: %dK (%u ways x %u sets x %u)\n",
++ dcache_size >> 10,
++ boot_cpu_data.dcache.ways,
++ boot_cpu_data.dcache.sets,
++ boot_cpu_data.dcache.linesz);
++ seq_printf(m, "bogomips\t: %lu.%02lu\n",
++ boot_cpu_data.loops_per_jiffy / (500000/HZ),
++ (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
++
++ return 0;
++}
++
++static void *c_start(struct seq_file *m, loff_t *pos)
++{
++ return *pos < 1 ? (void *)1 : NULL;
++}
++
++static void *c_next(struct seq_file *m, void *v, loff_t *pos)
++{
++ ++*pos;
++ return NULL;
++}
++
++static void c_stop(struct seq_file *m, void *v)
++{
++
++}
++
++struct seq_operations cpuinfo_op = {
++ .start = c_start,
++ .next = c_next,
++ .stop = c_stop,
++ .show = c_show
++};
++#endif /* CONFIG_PROC_FS */
+diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
+new file mode 100644
+index 0000000..eeb6679
+--- /dev/null
++++ b/arch/avr32/kernel/entry-avr32b.S
+@@ -0,0 +1,678 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++/*
++ * This file contains the low-level entry-points into the kernel, that is,
++ * exception handlers, debug trap handlers, interrupt handlers and the
++ * system call handler.
++ */
++#include <linux/errno.h>
++
++#include <asm/asm.h>
++#include <asm/hardirq.h>
++#include <asm/irq.h>
++#include <asm/ocd.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/ptrace.h>
++#include <asm/sysreg.h>
++#include <asm/thread_info.h>
++#include <asm/unistd.h>
++
++#ifdef CONFIG_PREEMPT
++# define preempt_stop mask_interrupts
++#else
++# define preempt_stop
++# define fault_resume_kernel fault_restore_all
++#endif
++
++#define __MASK(x) ((1 << (x)) - 1)
++#define IRQ_MASK ((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \
++ (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT))
++
++ .section .ex.text,"ax", at progbits
++ .align 2
++exception_vectors:
++ bral handle_critical
++ .align 2
++ bral handle_critical
++ .align 2
++ bral do_bus_error_write
++ .align 2
++ bral do_bus_error_read
++ .align 2
++ bral do_nmi_ll
++ .align 2
++ bral handle_address_fault
++ .align 2
++ bral handle_protection_fault
++ .align 2
++ bral handle_debug
++ .align 2
++ bral do_illegal_opcode_ll
++ .align 2
++ bral do_illegal_opcode_ll
++ .align 2
++ bral do_illegal_opcode_ll
++ .align 2
++ bral do_fpe_ll
++ .align 2
++ bral do_illegal_opcode_ll
++ .align 2
++ bral handle_address_fault
++ .align 2
++ bral handle_address_fault
++ .align 2
++ bral handle_protection_fault
++ .align 2
++ bral handle_protection_fault
++ .align 2
++ bral do_dtlb_modified
++
++ /*
++ * r0 : PGD/PT/PTE
++ * r1 : Offending address
++ * r2 : Scratch register
++ * r3 : Cause (5, 12 or 13)
++ */
++#define tlbmiss_save pushm r0-r3
++#define tlbmiss_restore popm r0-r3
++
++ .section .tlbx.ex.text,"ax", at progbits
++ .global itlb_miss
++itlb_miss:
++ tlbmiss_save
++ rjmp tlb_miss_common
++
++ .section .tlbr.ex.text,"ax", at progbits
++dtlb_miss_read:
++ tlbmiss_save
++ rjmp tlb_miss_common
++
++ .section .tlbw.ex.text,"ax", at progbits
++dtlb_miss_write:
++ tlbmiss_save
++
++ .global tlb_miss_common
++tlb_miss_common:
++ mfsr r0, SYSREG_PTBR
++ mfsr r1, SYSREG_TLBEAR
++
++ /* Is it the vmalloc space? */
++ bld r1, 31
++ brcs handle_vmalloc_miss
++
++ /* First level lookup */
++pgtbl_lookup:
++ lsr r2, r1, PGDIR_SHIFT
++ ld.w r0, r0[r2 << 2]
++ bld r0, _PAGE_BIT_PRESENT
++ brcc page_table_not_present
++
++ /* TODO: Check access rights on page table if necessary */
++
++ /* Translate to virtual address in P1. */
++ andl r0, 0xf000
++ sbr r0, 31
++
++ /* Second level lookup */
++ lsl r1, (32 - PGDIR_SHIFT)
++ lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
++ add r2, r0, r1 << 2
++ ld.w r1, r2[0]
++ bld r1, _PAGE_BIT_PRESENT
++ brcc page_not_present
++
++ /* Mark the page as accessed */
++ sbr r1, _PAGE_BIT_ACCESSED
++ st.w r2[0], r1
++
++ /* Drop software flags */
++ andl r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
++ mtsr SYSREG_TLBELO, r1
++
++ /* Figure out which entry we want to replace */
++ mfsr r0, SYSREG_TLBARLO
++ clz r2, r0
++ brcc 1f
++ mov r1, -1 /* All entries have been accessed, */
++ mtsr SYSREG_TLBARLO, r1 /* so reset TLBAR */
++ mov r2, 0 /* and start at 0 */
++1: mfsr r1, SYSREG_MMUCR
++ lsl r2, 14
++ andl r1, 0x3fff, COH
++ or r1, r2
++ mtsr SYSREG_MMUCR, r1
++
++ tlbw
++
++ tlbmiss_restore
++ rete
++
++handle_vmalloc_miss:
++ /* Simply do the lookup in init's page table */
++ mov r0, lo(swapper_pg_dir)
++ orh r0, hi(swapper_pg_dir)
++ rjmp pgtbl_lookup
++
++
++ /* --- System Call --- */
++
++ .section .scall.text,"ax", at progbits
++system_call:
++ pushm r12 /* r12_orig */
++ stmts --sp, r0-lr
++ zero_fp
++ mfsr r0, SYSREG_RAR_SUP
++ mfsr r1, SYSREG_RSR_SUP
++ stm --sp, r0-r1
++
++ /* check for syscall tracing */
++ get_thread_info r0
++ ld.w r1, r0[TI_flags]
++ bld r1, TIF_SYSCALL_TRACE
++ brcs syscall_trace_enter
++
++syscall_trace_cont:
++ cp.w r8, NR_syscalls
++ brhs syscall_badsys
++
++ lddpc lr, syscall_table_addr
++ ld.w lr, lr[r8 << 2]
++ mov r8, r5 /* 5th argument (6th is pushed by stub) */
++ icall lr
++
++ .global syscall_return
++syscall_return:
++ get_thread_info r0
++ mask_interrupts /* make sure we don't miss an interrupt
++ setting need_resched or sigpending
++ between sampling and the rets */
++
++ /* Store the return value so that the correct value is loaded below */
++ stdsp sp[REG_R12], r12
++
++ ld.w r1, r0[TI_flags]
++ andl r1, _TIF_ALLWORK_MASK, COH
++ brne syscall_exit_work
++
++syscall_exit_cont:
++ popm r8-r9
++ mtsr SYSREG_RAR_SUP, r8
++ mtsr SYSREG_RSR_SUP, r9
++ ldmts sp++, r0-lr
++ sub sp, -4 /* r12_orig */
++ rets
++
++ .align 2
++syscall_table_addr:
++ .long sys_call_table
++
++syscall_badsys:
++ mov r12, -ENOSYS
++ rjmp syscall_return
++
++ .global ret_from_fork
++ret_from_fork:
++ rcall schedule_tail
++
++ /* check for syscall tracing */
++ get_thread_info r0
++ ld.w r1, r0[TI_flags]
++ andl r1, _TIF_ALLWORK_MASK, COH
++ brne syscall_exit_work
++ rjmp syscall_exit_cont
++
++syscall_trace_enter:
++ pushm r8-r12
++ rcall syscall_trace
++ popm r8-r12
++ rjmp syscall_trace_cont
++
++syscall_exit_work:
++ bld r1, TIF_SYSCALL_TRACE
++ brcc 1f
++ unmask_interrupts
++ rcall syscall_trace
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++
++1: bld r1, TIF_NEED_RESCHED
++ brcc 2f
++ unmask_interrupts
++ rcall schedule
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++ rjmp 1b
++
++2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
++ tst r1, r2
++ breq 3f
++ unmask_interrupts
++ mov r12, sp
++ mov r11, r0
++ rcall do_notify_resume
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++ rjmp 1b
++
++3: bld r1, TIF_BREAKPOINT
++ brcc syscall_exit_cont
++ mfsr r3, SYSREG_TLBEHI
++ lddsp r2, sp[REG_PC]
++ andl r3, 0xff, COH
++ lsl r3, 1
++ sbr r3, 30
++ sbr r3, 0
++ mtdr DBGREG_BWA2A, r2
++ mtdr DBGREG_BWC2A, r3
++ rjmp syscall_exit_cont
++
++
++ /* The slow path of the TLB miss handler */
++page_table_not_present:
++page_not_present:
++ tlbmiss_restore
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ mfsr r12, SYSREG_ECR
++ mov r11, sp
++ rcall do_page_fault
++ rjmp ret_from_exception
++
++ /* This function expects to find offending PC in SYSREG_RAR_EX */
++save_full_context_ex:
++ mfsr r8, SYSREG_RSR_EX
++ mov r12, r8
++ andh r8, (MODE_MASK >> 16), COH
++ mfsr r11, SYSREG_RAR_EX
++ brne 2f
++
++1: pushm r11, r12 /* PC and SR */
++ unmask_exceptions
++ ret r12
++
++2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR)
++ stdsp sp[4], r10 /* replace saved SP */
++ rjmp 1b
++
++ /* Low-level exception handlers */
++handle_critical:
++ pushm r12
++ pushm r0-r12
++ rcall save_full_context_ex
++ mfsr r12, SYSREG_ECR
++ mov r11, sp
++ rcall do_critical_exception
++
++ /* We should never get here... */
++bad_return:
++ sub r12, pc, (. - 1f)
++ bral panic
++ .align 2
++1: .asciz "Return from critical exception!"
++
++ .align 1
++do_bus_error_write:
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ mov r11, 1
++ rjmp 1f
++
++do_bus_error_read:
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ mov r11, 0
++1: mfsr r12, SYSREG_BEAR
++ mov r10, sp
++ rcall do_bus_error
++ rjmp ret_from_exception
++
++ .align 1
++do_nmi_ll:
++ sub sp, 4
++ stmts --sp, r0-lr
++ /* FIXME: Make sure RAR_NMI and RSR_NMI are pushed instead of *_EX */
++ rcall save_full_context_ex
++ mfsr r12, SYSREG_ECR
++ mov r11, sp
++ rcall do_nmi
++ rjmp bad_return
++
++handle_address_fault:
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ mfsr r12, SYSREG_ECR
++ mov r11, sp
++ rcall do_address_exception
++ rjmp ret_from_exception
++
++handle_protection_fault:
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ mfsr r12, SYSREG_ECR
++ mov r11, sp
++ rcall do_page_fault
++ rjmp ret_from_exception
++
++ .align 1
++do_illegal_opcode_ll:
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ mfsr r12, SYSREG_ECR
++ mov r11, sp
++ rcall do_illegal_opcode
++ rjmp ret_from_exception
++
++do_dtlb_modified:
++ pushm r0-r3
++ mfsr r1, SYSREG_TLBEAR
++ mfsr r0, SYSREG_PTBR
++ lsr r2, r1, PGDIR_SHIFT
++ ld.w r0, r0[r2 << 2]
++ lsl r1, (32 - PGDIR_SHIFT)
++ lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
++
++ /* Translate to virtual address in P1 */
++ andl r0, 0xf000
++ sbr r0, 31
++ add r2, r0, r1 << 2
++ ld.w r3, r2[0]
++ sbr r3, _PAGE_BIT_DIRTY
++ mov r0, r3
++ st.w r2[0], r3
++
++ /* The page table is up-to-date. Update the TLB entry as well */
++ andl r0, lo(_PAGE_FLAGS_HARDWARE_MASK)
++ mtsr SYSREG_TLBELO, r0
++
++ /* MMUCR[DRP] is updated automatically, so let's go... */
++ tlbw
++
++ popm r0-r3
++ rete
++
++do_fpe_ll:
++ sub sp, 4
++ stmts --sp, r0-lr
++ rcall save_full_context_ex
++ unmask_interrupts
++ mov r12, 26
++ mov r11, sp
++ rcall do_fpe
++ rjmp ret_from_exception
++
++ret_from_exception:
++ mask_interrupts
++ lddsp r4, sp[REG_SR]
++ andh r4, (MODE_MASK >> 16), COH
++ brne fault_resume_kernel
++
++ get_thread_info r0
++ ld.w r1, r0[TI_flags]
++ andl r1, _TIF_WORK_MASK, COH
++ brne fault_exit_work
++
++fault_resume_user:
++ popm r8-r9
++ mask_exceptions
++ mtsr SYSREG_RAR_EX, r8
++ mtsr SYSREG_RSR_EX, r9
++ ldmts sp++, r0-lr
++ sub sp, -4
++ rete
++
++fault_resume_kernel:
++#ifdef CONFIG_PREEMPT
++ get_thread_info r0
++ ld.w r2, r0[TI_preempt_count]
++ cp.w r2, 0
++ brne 1f
++ ld.w r1, r0[TI_flags]
++ bld r1, TIF_NEED_RESCHED
++ brcc 1f
++ lddsp r4, sp[REG_SR]
++ bld r4, SYSREG_GM_OFFSET
++ brcs 1f
++ rcall preempt_schedule_irq
++1:
++#endif
++
++ popm r8-r9
++ mask_exceptions
++ mfsr r1, SYSREG_SR
++ mtsr SYSREG_RAR_EX, r8
++ mtsr SYSREG_RSR_EX, r9
++ popm lr
++ sub sp, -4 /* ignore SP */
++ popm r0-r12
++ sub sp, -4 /* ignore r12_orig */
++ rete
++
++irq_exit_work:
++ /* Switch to exception mode so that we can share the same code. */
++ mfsr r8, SYSREG_SR
++ cbr r8, SYSREG_M0_OFFSET
++ orh r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2))
++ mtsr SYSREG_SR, r8
++ sub pc, -2
++ get_thread_info r0
++ ld.w r1, r0[TI_flags]
++
++fault_exit_work:
++ bld r1, TIF_NEED_RESCHED
++ brcc 1f
++ unmask_interrupts
++ rcall schedule
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++ rjmp fault_exit_work
++
++1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
++ tst r1, r2
++ breq 2f
++ unmask_interrupts
++ mov r12, sp
++ mov r11, r0
++ rcall do_notify_resume
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++ rjmp fault_exit_work
++
++2: bld r1, TIF_BREAKPOINT
++ brcc fault_resume_user
++ mfsr r3, SYSREG_TLBEHI
++ lddsp r2, sp[REG_PC]
++ andl r3, 0xff, COH
++ lsl r3, 1
++ sbr r3, 30
++ sbr r3, 0
++ mtdr DBGREG_BWA2A, r2
++ mtdr DBGREG_BWC2A, r3
++ rjmp fault_resume_user
++
++ /* If we get a debug trap from privileged context we end up here */
++handle_debug_priv:
++ /* Fix up LR and SP in regs. r11 contains the mode we came from */
++ mfsr r8, SYSREG_SR
++ mov r9, r8
++ andh r8, hi(~MODE_MASK)
++ or r8, r11
++ mtsr SYSREG_SR, r8
++ sub pc, -2
++ stdsp sp[REG_LR], lr
++ mtsr SYSREG_SR, r9
++ sub pc, -2
++ sub r10, sp, -FRAME_SIZE_FULL
++ stdsp sp[REG_SP], r10
++ mov r12, sp
++ rcall do_debug_priv
++
++ /* Now, put everything back */
++ ssrf SR_EM_BIT
++ popm r10, r11
++ mtsr SYSREG_RAR_DBG, r10
++ mtsr SYSREG_RSR_DBG, r11
++ mfsr r8, SYSREG_SR
++ mov r9, r8
++ andh r8, hi(~MODE_MASK)
++ andh r11, hi(MODE_MASK)
++ or r8, r11
++ mtsr SYSREG_SR, r8
++ sub pc, -2
++ popm lr
++ mtsr SYSREG_SR, r9
++ sub pc, -2
++ sub sp, -4 /* skip SP */
++ popm r0-r12
++ sub sp, -4
++ retd
++
++ /*
++ * At this point, everything is masked, that is, interrupts,
++ * exceptions and debugging traps. We might get called from
++ * interrupt or exception context in some rare cases, but this
++ * will be taken care of by do_debug(), so we're not going to
++ * do a 100% correct context save here.
++ */
++handle_debug:
++ sub sp, 4 /* r12_orig */
++ stmts --sp, r0-lr
++ mfsr r10, SYSREG_RAR_DBG
++ mfsr r11, SYSREG_RSR_DBG
++ unmask_exceptions
++ pushm r10,r11
++ andh r11, (MODE_MASK >> 16), COH
++ brne handle_debug_priv
++
++ mov r12, sp
++ rcall do_debug
++
++ lddsp r10, sp[REG_SR]
++ andh r10, (MODE_MASK >> 16), COH
++ breq debug_resume_user
++
++debug_restore_all:
++ popm r10,r11
++ mask_exceptions
++ mtsr SYSREG_RSR_DBG, r11
++ mtsr SYSREG_RAR_DBG, r10
++ ldmts sp++, r0-lr
++ sub sp, -4
++ retd
++
++debug_resume_user:
++ get_thread_info r0
++ mask_interrupts
++
++ ld.w r1, r0[TI_flags]
++ andl r1, _TIF_DBGWORK_MASK, COH
++ breq debug_restore_all
++
++1: bld r1, TIF_NEED_RESCHED
++ brcc 2f
++ unmask_interrupts
++ rcall schedule
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++ rjmp 1b
++
++2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
++ tst r1, r2
++ breq 3f
++ unmask_interrupts
++ mov r12, sp
++ mov r11, r0
++ rcall do_notify_resume
++ mask_interrupts
++ ld.w r1, r0[TI_flags]
++ rjmp 1b
++
++3: bld r1, TIF_SINGLE_STEP
++ brcc debug_restore_all
++ mfdr r2, DBGREG_DC
++ sbr r2, DC_SS_BIT
++ mtdr DBGREG_DC, r2
++ rjmp debug_restore_all
++
++ .set rsr_int0, SYSREG_RSR_INT0
++ .set rsr_int1, SYSREG_RSR_INT1
++ .set rsr_int2, SYSREG_RSR_INT2
++ .set rsr_int3, SYSREG_RSR_INT3
++ .set rar_int0, SYSREG_RAR_INT0
++ .set rar_int1, SYSREG_RAR_INT1
++ .set rar_int2, SYSREG_RAR_INT2
++ .set rar_int3, SYSREG_RAR_INT3
++
++ .macro IRQ_LEVEL level
++ .type irq_level\level, @function
++irq_level\level:
++ sub sp, 4 /* r12_orig */
++ stmts --sp,r0-lr
++ mfsr r8, rar_int\level
++ mfsr r9, rsr_int\level
++ pushm r8-r9
++
++ mov r11, sp
++ mov r12, \level
++
++ rcall do_IRQ
++
++ lddsp r4, sp[REG_SR]
++ andh r4, (MODE_MASK >> 16), COH
++#ifdef CONFIG_PREEMPT
++ brne 2f
++#else
++ brne 1f
++#endif
++
++ get_thread_info r0
++ ld.w r1, r0[TI_flags]
++ andl r1, _TIF_WORK_MASK, COH
++ brne irq_exit_work
++
++1: popm r8-r9
++ mtsr rar_int\level, r8
++ mtsr rsr_int\level, r9
++ ldmts sp++,r0-lr
++ sub sp, -4 /* ignore r12_orig */
++ rete
++
++#ifdef CONFIG_PREEMPT
++2:
++ get_thread_info r0
++ ld.w r2, r0[TI_preempt_count]
++ cp.w r2, 0
++ brne 1b
++ ld.w r1, r0[TI_flags]
++ bld r1, TIF_NEED_RESCHED
++ brcc 1b
++ lddsp r4, sp[REG_SR]
++ bld r4, SYSREG_GM_OFFSET
++ brcs 1b
++ rcall preempt_schedule_irq
++ rjmp 1b
++#endif
++ .endm
++
++ .section .irq.text,"ax", at progbits
++
++ .global irq_level0
++ .global irq_level1
++ .global irq_level2
++ .global irq_level3
++ IRQ_LEVEL 0
++ IRQ_LEVEL 1
++ IRQ_LEVEL 2
++ IRQ_LEVEL 3
+diff --git a/arch/avr32/kernel/head.S b/arch/avr32/kernel/head.S
+new file mode 100644
+index 0000000..6163bd0
+--- /dev/null
++++ b/arch/avr32/kernel/head.S
+@@ -0,0 +1,42 @@
++/*
++ * Non-board-specific low-level startup code
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/linkage.h>
++
++#include <asm/page.h>
++#include <asm/thread_info.h>
++#include <asm/sysreg.h>
++
++ .section .init.text,"ax"
++ .global kernel_entry
++kernel_entry:
++ /* Initialize status register */
++ lddpc r0, init_sr
++ mtsr SYSREG_SR, r0
++
++ /* Set initial stack pointer */
++ lddpc sp, stack_addr
++ sub sp, -THREAD_SIZE
++
++#ifdef CONFIG_FRAME_POINTER
++ /* Mark last stack frame */
++ mov lr, 0
++ mov r7, 0
++#endif
++
++ /* Start the show */
++ lddpc pc, kernel_start_addr
++
++ .align 2
++init_sr:
++ .long 0x007f0000 /* Supervisor mode, everything masked */
++stack_addr:
++ .long init_thread_union
++kernel_start_addr:
++ .long start_kernel
+diff --git a/arch/avr32/kernel/init_task.c b/arch/avr32/kernel/init_task.c
+new file mode 100644
+index 0000000..effcacf
+--- /dev/null
++++ b/arch/avr32/kernel/init_task.c
+@@ -0,0 +1,38 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/init_task.h>
++#include <linux/mqueue.h>
++
++#include <asm/pgtable.h>
++
++static struct fs_struct init_fs = INIT_FS;
++static struct files_struct init_files = INIT_FILES;
++static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
++static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
++struct mm_struct init_mm = INIT_MM(init_mm);
++
++EXPORT_SYMBOL(init_mm);
++
++/*
++ * Initial thread structure. Must be aligned on an 8192-byte boundary.
++ */
++union thread_union init_thread_union
++ __attribute__((__section__(".data.init_task"))) =
++ { INIT_THREAD_INFO(init_task) };
++
++/*
++ * Initial task structure.
++ *
++ * All other task structs will be allocated on slabs in fork.c
++ */
++struct task_struct init_task = INIT_TASK(init_task);
++
++EXPORT_SYMBOL(init_task);
+diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
+new file mode 100644
+index 0000000..856f354
+--- /dev/null
++++ b/arch/avr32/kernel/irq.c
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on arch/i386/kernel/irq.c
++ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This file contains the code used by various IRQ handling routines:
++ * asking for different IRQ's should be done through these routines
++ * instead of just grabbing them. Thus setups with different IRQ numbers
++ * shouldn't result in any weird surprises, and installing new handlers
++ * should be easier.
++ *
++ * IRQ's are in fact implemented a bit like signal handlers for the kernel.
++ * Naturally it's not a 1:1 relation, but there are similarities.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/kernel_stat.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/sysdev.h>
++
++/*
++ * '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 %u\n", irq);
++}
++
++#ifdef CONFIG_PROC_FS
++int show_interrupts(struct seq_file *p, void *v)
++{
++ int i = *(loff_t *)v, cpu;
++ struct irqaction *action;
++ unsigned long flags;
++
++ if (i == 0) {
++ seq_puts(p, " ");
++ for_each_online_cpu(cpu)
++ seq_printf(p, "CPU%d ", cpu);
++ seq_putc(p, '\n');
++ }
++
++ if (i < NR_IRQS) {
++ spin_lock_irqsave(&irq_desc[i].lock, flags);
++ action = irq_desc[i].action;
++ if (!action)
++ goto unlock;
++
++ seq_printf(p, "%3d: ", i);
++ for_each_online_cpu(cpu)
++ seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
++ seq_printf(p, " %s", action->name);
++ for (action = action->next; action; action = action->next)
++ seq_printf(p, ", %s", action->name);
++
++ seq_putc(p, '\n');
++ unlock:
++ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
++ }
++
++ return 0;
++}
++#endif
+diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
+new file mode 100644
+index 0000000..ca41fc1
+--- /dev/null
++++ b/arch/avr32/kernel/kprobes.c
+@@ -0,0 +1,270 @@
++/*
++ * Kernel Probes (KProbes)
++ *
++ * Copyright (C) 2005-2006 Atmel Corporation
++ *
++ * Based on arch/ppc64/kernel/kprobes.c
++ * Copyright (C) IBM Corporation, 2002, 2004
++ *
++ * 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/kprobes.h>
++#include <linux/ptrace.h>
++
++#include <asm/cacheflush.h>
++#include <asm/kdebug.h>
++#include <asm/ocd.h>
++
++DEFINE_PER_CPU(struct kprobe *, current_kprobe);
++static unsigned long kprobe_status;
++static struct pt_regs jprobe_saved_regs;
++
++int __kprobes arch_prepare_kprobe(struct kprobe *p)
++{
++ int ret = 0;
++
++ if ((unsigned long)p->addr & 0x01) {
++ printk("Attempt to register kprobe at an unaligned address\n");
++ ret = -EINVAL;
++ }
++
++ /* XXX: Might be a good idea to check if p->addr is a valid
++ * kernel address as well... */
++
++ if (!ret) {
++ pr_debug("copy kprobe at %p\n", p->addr);
++ memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
++ p->opcode = *p->addr;
++ }
++
++ return ret;
++}
++
++void __kprobes arch_arm_kprobe(struct kprobe *p)
++{
++ pr_debug("arming kprobe at %p\n", p->addr);
++ *p->addr = BREAKPOINT_INSTRUCTION;
++ flush_icache_range((unsigned long)p->addr,
++ (unsigned long)p->addr + sizeof(kprobe_opcode_t));
++}
++
++void __kprobes arch_disarm_kprobe(struct kprobe *p)
++{
++ pr_debug("disarming kprobe at %p\n", p->addr);
++ *p->addr = p->opcode;
++ flush_icache_range((unsigned long)p->addr,
++ (unsigned long)p->addr + sizeof(kprobe_opcode_t));
++}
++
++static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
++{
++ unsigned long dc;
++
++ pr_debug("preparing to singlestep over %p (PC=%08lx)\n",
++ p->addr, regs->pc);
++
++ BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D)));
++
++ dc = __mfdr(DBGREG_DC);
++ dc |= DC_SS;
++ __mtdr(DBGREG_DC, dc);
++
++ /*
++ * We must run the instruction from its original location
++ * since it may actually reference PC.
++ *
++ * TODO: Do the instruction replacement directly in icache.
++ */
++ *p->addr = p->opcode;
++ flush_icache_range((unsigned long)p->addr,
++ (unsigned long)p->addr + sizeof(kprobe_opcode_t));
++}
++
++static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
++{
++ unsigned long dc;
++
++ pr_debug("resuming execution at PC=%08lx\n", regs->pc);
++
++ dc = __mfdr(DBGREG_DC);
++ dc &= ~DC_SS;
++ __mtdr(DBGREG_DC, dc);
++
++ *p->addr = BREAKPOINT_INSTRUCTION;
++ flush_icache_range((unsigned long)p->addr,
++ (unsigned long)p->addr + sizeof(kprobe_opcode_t));
++}
++
++static void __kprobes set_current_kprobe(struct kprobe *p)
++{
++ __get_cpu_var(current_kprobe) = p;
++}
++
++static int __kprobes kprobe_handler(struct pt_regs *regs)
++{
++ struct kprobe *p;
++ void *addr = (void *)regs->pc;
++ int ret = 0;
++
++ pr_debug("kprobe_handler: kprobe_running=%p\n",
++ kprobe_running());
++
++ /*
++ * We don't want to be preempted for the entire
++ * duration of kprobe processing
++ */
++ preempt_disable();
++
++ /* Check that we're not recursing */
++ if (kprobe_running()) {
++ p = get_kprobe(addr);
++ if (p) {
++ if (kprobe_status == KPROBE_HIT_SS) {
++ printk("FIXME: kprobe hit while single-stepping!\n");
++ goto no_kprobe;
++ }
++
++ printk("FIXME: kprobe hit while handling another kprobe\n");
++ goto no_kprobe;
++ } else {
++ p = kprobe_running();
++ if (p->break_handler && p->break_handler(p, regs))
++ goto ss_probe;
++ }
++ /* If it's not ours, can't be delete race, (we hold lock). */
++ goto no_kprobe;
++ }
++
++ p = get_kprobe(addr);
++ if (!p)
++ goto no_kprobe;
++
++ kprobe_status = KPROBE_HIT_ACTIVE;
++ set_current_kprobe(p);
++ if (p->pre_handler && p->pre_handler(p, regs))
++ /* handler has already set things up, so skip ss setup */
++ return 1;
++
++ss_probe:
++ prepare_singlestep(p, regs);
++ kprobe_status = KPROBE_HIT_SS;
++ return 1;
++
++no_kprobe:
++ return ret;
++}
++
++static int __kprobes post_kprobe_handler(struct pt_regs *regs)
++{
++ struct kprobe *cur = kprobe_running();
++
++ pr_debug("post_kprobe_handler, cur=%p\n", cur);
++
++ if (!cur)
++ return 0;
++
++ if (cur->post_handler) {
++ kprobe_status = KPROBE_HIT_SSDONE;
++ cur->post_handler(cur, regs, 0);
++ }
++
++ resume_execution(cur, regs);
++ reset_current_kprobe();
++ preempt_enable_no_resched();
++
++ return 1;
++}
++
++static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
++{
++ struct kprobe *cur = kprobe_running();
++
++ pr_debug("kprobe_fault_handler: trapnr=%d\n", trapnr);
++
++ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
++ return 1;
++
++ if (kprobe_status & KPROBE_HIT_SS) {
++ resume_execution(cur, regs);
++ preempt_enable_no_resched();
++ }
++ return 0;
++}
++
++/*
++ * Wrapper routine to for handling exceptions.
++ */
++int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data)
++{
++ struct die_args *args = (struct die_args *)data;
++ int ret = NOTIFY_DONE;
++
++ pr_debug("kprobe_exceptions_notify: val=%lu, data=%p\n",
++ val, data);
++
++ switch (val) {
++ case DIE_BREAKPOINT:
++ if (kprobe_handler(args->regs))
++ ret = NOTIFY_STOP;
++ break;
++ case DIE_SSTEP:
++ if (post_kprobe_handler(args->regs))
++ ret = NOTIFY_STOP;
++ break;
++ case DIE_FAULT:
++ if (kprobe_running()
++ && kprobe_fault_handler(args->regs, args->trapnr))
++ ret = NOTIFY_STOP;
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
++{
++ struct jprobe *jp = container_of(p, struct jprobe, kp);
++
++ memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
++
++ /*
++ * TODO: We should probably save some of the stack here as
++ * well, since gcc may pass arguments on the stack for certain
++ * functions (lots of arguments, large aggregates, varargs)
++ */
++
++ /* setup return addr to the jprobe handler routine */
++ regs->pc = (unsigned long)jp->entry;
++ return 1;
++}
++
++void __kprobes jprobe_return(void)
++{
++ asm volatile("breakpoint" ::: "memory");
++}
++
++int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
++{
++ /*
++ * FIXME - we should ideally be validating that we got here 'cos
++ * of the "trap" in jprobe_return() above, before restoring the
++ * saved regs...
++ */
++ memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
++ return 1;
++}
++
++int __init arch_init_kprobes(void)
++{
++ printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
++ __mtdr(DBGREG_DC, DC_MM | DC_DBE);
++
++ /* TODO: Register kretprobe trampoline */
++ return 0;
++}
+diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
+new file mode 100644
+index 0000000..b599eae
+--- /dev/null
++++ b/arch/avr32/kernel/module.c
+@@ -0,0 +1,324 @@
++/*
++ * AVR32-specific kernel module loader
++ *
++ * Copyright (C) 2005-2006 Atmel Corporation
++ *
++ * GOT initialization parts are based on the s390 version
++ * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
++ * IBM 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.
++ */
++
++#include <linux/moduleloader.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/elf.h>
++#include <linux/vmalloc.h>
++
++void *module_alloc(unsigned long size)
++{
++ if (size == 0)
++ return NULL;
++ return vmalloc(size);
++}
++
++void module_free(struct module *mod, void *module_region)
++{
++ vfree(mod->arch.syminfo);
++ mod->arch.syminfo = NULL;
++
++ vfree(module_region);
++ /* FIXME: if module_region == mod->init_region, trim exception
++ * table entries. */
++}
++
++static inline int check_rela(Elf32_Rela *rela, struct module *module,
++ char *strings, Elf32_Sym *symbols)
++{
++ struct mod_arch_syminfo *info;
++
++ info = module->arch.syminfo + ELF32_R_SYM(rela->r_info);
++ switch (ELF32_R_TYPE(rela->r_info)) {
++ case R_AVR32_GOT32:
++ case R_AVR32_GOT16:
++ case R_AVR32_GOT8:
++ case R_AVR32_GOT21S:
++ case R_AVR32_GOT18SW: /* mcall */
++ case R_AVR32_GOT16S: /* ld.w */
++ if (rela->r_addend != 0) {
++ printk(KERN_ERR
++ "GOT relocation against %s at offset %u with addend\n",
++ strings + symbols[ELF32_R_SYM(rela->r_info)].st_name,
++ rela->r_offset);
++ return -ENOEXEC;
++ }
++ if (info->got_offset == -1UL) {
++ info->got_offset = module->arch.got_size;
++ module->arch.got_size += sizeof(void *);
++ }
++ pr_debug("GOT[%3lu] %s\n", info->got_offset,
++ strings + symbols[ELF32_R_SYM(rela->r_info)].st_name);
++ break;
++ }
++
++ return 0;
++}
++
++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
++ char *secstrings, struct module *module)
++{
++ Elf32_Shdr *symtab;
++ Elf32_Sym *symbols;
++ Elf32_Rela *rela;
++ char *strings;
++ int nrela, i, j;
++ int ret;
++
++ /* Find the symbol table */
++ symtab = NULL;
++ for (i = 0; i < hdr->e_shnum; i++)
++ switch (sechdrs[i].sh_type) {
++ case SHT_SYMTAB:
++ symtab = &sechdrs[i];
++ break;
++ }
++ if (!symtab) {
++ printk(KERN_ERR "module %s: no symbol table\n", module->name);
++ return -ENOEXEC;
++ }
++
++ /* Allocate room for one syminfo structure per symbol. */
++ module->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym);
++ module->arch.syminfo = vmalloc(module->arch.nsyms
++ * sizeof(struct mod_arch_syminfo));
++ if (!module->arch.syminfo)
++ return -ENOMEM;
++
++ symbols = (void *)hdr + symtab->sh_offset;
++ strings = (void *)hdr + sechdrs[symtab->sh_link].sh_offset;
++ for (i = 0; i < module->arch.nsyms; i++) {
++ if (symbols[i].st_shndx == SHN_UNDEF &&
++ strcmp(strings + symbols[i].st_name,
++ "_GLOBAL_OFFSET_TABLE_") == 0)
++ /* "Define" it as absolute. */
++ symbols[i].st_shndx = SHN_ABS;
++ module->arch.syminfo[i].got_offset = -1UL;
++ module->arch.syminfo[i].got_initialized = 0;
++ }
++
++ /* Allocate GOT entries for symbols that need it. */
++ module->arch.got_size = 0;
++ for (i = 0; i < hdr->e_shnum; i++) {
++ if (sechdrs[i].sh_type != SHT_RELA)
++ continue;
++ nrela = sechdrs[i].sh_size / sizeof(Elf32_Rela);
++ rela = (void *)hdr + sechdrs[i].sh_offset;
++ for (j = 0; j < nrela; j++) {
++ ret = check_rela(rela + j, module,
++ strings, symbols);
++ if (ret)
++ goto out_free_syminfo;
++ }
++ }
++
++ /*
++ * Increase core size to make room for GOT and set start
++ * offset for GOT.
++ */
++ module->core_size = ALIGN(module->core_size, 4);
++ module->arch.got_offset = module->core_size;
++ module->core_size += module->arch.got_size;
++
++ return 0;
++
++out_free_syminfo:
++ vfree(module->arch.syminfo);
++ module->arch.syminfo = NULL;
++
++ return ret;
++}
++
++static inline int reloc_overflow(struct module *module, const char *reloc_name,
++ Elf32_Addr relocation)
++{
++ printk(KERN_ERR "module %s: Value %lx does not fit relocation %s\n",
++ module->name, (unsigned long)relocation, reloc_name);
++ return -ENOEXEC;
++}
++
++#define get_u16(loc) (*((uint16_t *)loc))
++#define put_u16(loc, val) (*((uint16_t *)loc) = (val))
++
++int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
++ unsigned int symindex, unsigned int relindex,
++ struct module *module)
++{
++ Elf32_Shdr *symsec = sechdrs + symindex;
++ Elf32_Shdr *relsec = sechdrs + relindex;
++ Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
++ Elf32_Rela *rel = (void *)relsec->sh_addr;
++ unsigned int i;
++ int ret = 0;
++
++ for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) {
++ struct mod_arch_syminfo *info;
++ Elf32_Sym *sym;
++ Elf32_Addr relocation;
++ uint32_t *location;
++ uint32_t value;
++
++ location = (void *)dstsec->sh_addr + rel->r_offset;
++ sym = (Elf32_Sym *)symsec->sh_addr + ELF32_R_SYM(rel->r_info);
++ relocation = sym->st_value + rel->r_addend;
++
++ info = module->arch.syminfo + ELF32_R_SYM(rel->r_info);
++
++ /* Initialize GOT entry if necessary */
++ switch (ELF32_R_TYPE(rel->r_info)) {
++ case R_AVR32_GOT32:
++ case R_AVR32_GOT16:
++ case R_AVR32_GOT8:
++ case R_AVR32_GOT21S:
++ case R_AVR32_GOT18SW:
++ case R_AVR32_GOT16S:
++ if (!info->got_initialized) {
++ Elf32_Addr *gotent;
++
++ gotent = (module->module_core
++ + module->arch.got_offset
++ + info->got_offset);
++ *gotent = relocation;
++ info->got_initialized = 1;
++ }
++
++ relocation = info->got_offset;
++ break;
++ }
++
++ switch (ELF32_R_TYPE(rel->r_info)) {
++ case R_AVR32_32:
++ case R_AVR32_32_CPENT:
++ *location = relocation;
++ break;
++ case R_AVR32_22H_PCREL:
++ relocation -= (Elf32_Addr)location;
++ if ((relocation & 0xffe00001) != 0
++ && (relocation & 0xffc00001) != 0xffc00000)
++ return reloc_overflow(module,
++ "R_AVR32_22H_PCREL",
++ relocation);
++ relocation >>= 1;
++
++ value = *location;
++ value = ((value & 0xe1ef0000)
++ | (relocation & 0xffff)
++ | ((relocation & 0x10000) << 4)
++ | ((relocation & 0x1e0000) << 8));
++ *location = value;
++ break;
++ case R_AVR32_11H_PCREL:
++ relocation -= (Elf32_Addr)location;
++ if ((relocation & 0xfffffc01) != 0
++ && (relocation & 0xfffff801) != 0xfffff800)
++ return reloc_overflow(module,
++ "R_AVR32_11H_PCREL",
++ relocation);
++ value = get_u16(location);
++ value = ((value & 0xf00c)
++ | ((relocation & 0x1fe) << 3)
++ | ((relocation & 0x600) >> 9));
++ put_u16(location, value);
++ break;
++ case R_AVR32_9H_PCREL:
++ relocation -= (Elf32_Addr)location;
++ if ((relocation & 0xffffff01) != 0
++ && (relocation & 0xfffffe01) != 0xfffffe00)
++ return reloc_overflow(module,
++ "R_AVR32_9H_PCREL",
++ relocation);
++ value = get_u16(location);
++ value = ((value & 0xf00f)
++ | ((relocation & 0x1fe) << 3));
++ put_u16(location, value);
++ break;
++ case R_AVR32_9UW_PCREL:
++ relocation -= ((Elf32_Addr)location) & 0xfffffffc;
++ if ((relocation & 0xfffffc03) != 0)
++ return reloc_overflow(module,
++ "R_AVR32_9UW_PCREL",
++ relocation);
++ value = get_u16(location);
++ value = ((value & 0xf80f)
++ | ((relocation & 0x1fc) << 2));
++ put_u16(location, value);
++ break;
++ case R_AVR32_GOTPC:
++ /*
++ * R6 = PC - (PC - GOT)
++ *
++ * At this point, relocation contains the
++ * value of PC. Just subtract the value of
++ * GOT, and we're done.
++ */
++ pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n",
++ relocation, module->arch.got_offset,
++ module->module_core);
++ relocation -= ((unsigned long)module->module_core
++ + module->arch.got_offset);
++ *location = relocation;
++ break;
++ case R_AVR32_GOT18SW:
++ if ((relocation & 0xfffe0003) != 0
++ && (relocation & 0xfffc0003) != 0xffff0000)
++ return reloc_overflow(module, "R_AVR32_GOT18SW",
++ relocation);
++ relocation >>= 2;
++ /* fall through */
++ case R_AVR32_GOT16S:
++ if ((relocation & 0xffff8000) != 0
++ && (relocation & 0xffff0000) != 0xffff0000)
++ return reloc_overflow(module, "R_AVR32_GOT16S",
++ relocation);
++ pr_debug("GOT reloc @ 0x%x -> %u\n",
++ rel->r_offset, relocation);
++ value = *location;
++ value = ((value & 0xffff0000)
++ | (relocation & 0xffff));
++ *location = value;
++ break;
++
++ default:
++ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
++ module->name, ELF32_R_TYPE(rel->r_info));
++ return -ENOEXEC;
++ }
++ }
++
++ return ret;
++}
++
++int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab,
++ unsigned int symindex, unsigned int relindex,
++ struct module *module)
++{
++ printk(KERN_ERR "module %s: REL relocations are not supported\n",
++ module->name);
++ return -ENOEXEC;
++}
++
++int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
++ struct module *module)
++{
++ vfree(module->arch.syminfo);
++ module->arch.syminfo = NULL;
++
++ return 0;
++}
++
++void module_arch_cleanup(struct module *module)
++{
++
++}
+diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
+new file mode 100644
+index 0000000..317dc50
+--- /dev/null
++++ b/arch/avr32/kernel/process.c
+@@ -0,0 +1,276 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++#include <linux/fs.h>
++#include <linux/ptrace.h>
++#include <linux/reboot.h>
++#include <linux/unistd.h>
++
++#include <asm/sysreg.h>
++#include <asm/ocd.h>
++
++void (*pm_power_off)(void) = NULL;
++EXPORT_SYMBOL(pm_power_off);
++
++/*
++ * This file handles the architecture-dependent parts of process handling..
++ */
++
++void cpu_idle(void)
++{
++ /* endless idle loop with no priority at all */
++ while (1) {
++ /* TODO: Enter sleep mode */
++ while (!need_resched())
++ cpu_relax();
++ preempt_enable_no_resched();
++ schedule();
++ preempt_disable();
++ }
++}
++
++void machine_halt(void)
++{
++}
++
++void machine_power_off(void)
++{
++}
++
++void machine_restart(char *cmd)
++{
++ __mtdr(DBGREG_DC, DC_DBE);
++ __mtdr(DBGREG_DC, DC_RES);
++ while (1) ;
++}
++
++/*
++ * PC is actually discarded when returning from a system call -- the
++ * return address must be stored in LR. This function will make sure
++ * LR points to do_exit before starting the thread.
++ *
++ * Also, when returning from fork(), r12 is 0, so we must copy the
++ * argument as well.
++ *
++ * r0 : The argument to the main thread function
++ * r1 : The address of do_exit
++ * r2 : The address of the main thread function
++ */
++asmlinkage extern void kernel_thread_helper(void);
++__asm__(" .type kernel_thread_helper, @function\n"
++ "kernel_thread_helper:\n"
++ " mov r12, r0\n"
++ " mov lr, r2\n"
++ " mov pc, r1\n"
++ " .size kernel_thread_helper, . - kernel_thread_helper");
++
++int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
++{
++ struct pt_regs regs;
++
++ memset(®s, 0, sizeof(regs));
++
++ regs.r0 = (unsigned long)arg;
++ regs.r1 = (unsigned long)fn;
++ regs.r2 = (unsigned long)do_exit;
++ regs.lr = (unsigned long)kernel_thread_helper;
++ regs.pc = (unsigned long)kernel_thread_helper;
++ regs.sr = MODE_SUPERVISOR;
++
++ return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
++ 0, ®s, 0, NULL, NULL);
++}
++EXPORT_SYMBOL(kernel_thread);
++
++/*
++ * Free current thread data structures etc
++ */
++void exit_thread(void)
++{
++ /* nothing to do */
++}
++
++void flush_thread(void)
++{
++ /* nothing to do */
++}
++
++void release_thread(struct task_struct *dead_task)
++{
++ /* do nothing */
++}
++
++static const char *cpu_modes[] = {
++ "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
++ "Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
++};
++
++void show_regs(struct pt_regs *regs)
++{
++ unsigned long sp = regs->sp;
++ unsigned long lr = regs->lr;
++ unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
++
++ if (!user_mode(regs))
++ sp = (unsigned long)regs + FRAME_SIZE_FULL;
++
++ print_symbol("PC is at %s\n", instruction_pointer(regs));
++ print_symbol("LR is at %s\n", lr);
++ printk("pc : [<%08lx>] lr : [<%08lx>] %s\n"
++ "sp : %08lx r12: %08lx r11: %08lx\n",
++ instruction_pointer(regs),
++ lr, print_tainted(), sp, regs->r12, regs->r11);
++ printk("r10: %08lx r9 : %08lx r8 : %08lx\n",
++ regs->r10, regs->r9, regs->r8);
++ printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
++ regs->r7, regs->r6, regs->r5, regs->r4);
++ printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
++ regs->r3, regs->r2, regs->r1, regs->r0);
++ printk("Flags: %c%c%c%c%c\n",
++ regs->sr & SR_Q ? 'Q' : 'q',
++ regs->sr & SR_V ? 'V' : 'v',
++ regs->sr & SR_N ? 'N' : 'n',
++ regs->sr & SR_Z ? 'Z' : 'z',
++ regs->sr & SR_C ? 'C' : 'c');
++ printk("Mode bits: %c%c%c%c%c%c%c%c%c\n",
++ regs->sr & SR_H ? 'H' : 'h',
++ regs->sr & SR_R ? 'R' : 'r',
++ regs->sr & SR_J ? 'J' : 'j',
++ regs->sr & SR_EM ? 'E' : 'e',
++ regs->sr & SR_I3M ? '3' : '.',
++ regs->sr & SR_I2M ? '2' : '.',
++ regs->sr & SR_I1M ? '1' : '.',
++ regs->sr & SR_I0M ? '0' : '.',
++ regs->sr & SR_GM ? 'G' : 'g');
++ printk("CPU Mode: %s\n", cpu_modes[mode]);
++
++ show_trace(NULL, (unsigned long *)sp, regs);
++}
++EXPORT_SYMBOL(show_regs);
++
++/* Fill in the fpu structure for a core dump. This is easy -- we don't have any */
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
++{
++ /* Not valid */
++ return 0;
++}
++
++asmlinkage void ret_from_fork(void);
++
++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;
++
++ childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)p->thread_info)) - 1;
++ *childregs = *regs;
++
++ if (user_mode(regs))
++ childregs->sp = usp;
++ else
++ childregs->sp = (unsigned long)p->thread_info + THREAD_SIZE;
++
++ childregs->r12 = 0; /* Set return value for child */
++
++ p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
++ p->thread.cpu_context.ksp = (unsigned long)childregs;
++ p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
++
++ return 0;
++}
++
++/* r12-r8 are dummy parameters to force the compiler to use the stack */
++asmlinkage int sys_fork(struct pt_regs *regs)
++{
++ return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
++}
++
++asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
++ unsigned long parent_tidptr,
++ unsigned long child_tidptr, struct pt_regs *regs)
++{
++ if (!newsp)
++ newsp = regs->sp;
++ return do_fork(clone_flags, newsp, regs, 0,
++ (int __user *)parent_tidptr,
++ (int __user *)child_tidptr);
++}
++
++asmlinkage int sys_vfork(struct pt_regs *regs)
++{
++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs,
++ 0, NULL, NULL);
++}
++
++asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv,
++ char __user *__user *uenvp, struct pt_regs *regs)
++{
++ int error;
++ char *filename;
++
++ filename = getname(ufilename);
++ error = PTR_ERR(filename);
++ if (IS_ERR(filename))
++ goto out;
++
++ error = do_execve(filename, uargv, uenvp, regs);
++ if (error == 0)
++ current->ptrace &= ~PT_DTRACE;
++ putname(filename);
++
++out:
++ return error;
++}
++
++
++/*
++ * This function is supposed to answer the question "who called
++ * schedule()?"
++ */
++unsigned long get_wchan(struct task_struct *p)
++{
++ unsigned long pc;
++ unsigned long stack_page;
++
++ if (!p || p == current || p->state == TASK_RUNNING)
++ return 0;
++
++ stack_page = (unsigned long)p->thread_info;
++ BUG_ON(!stack_page);
++
++ /*
++ * The stored value of PC is either the address right after
++ * the call to __switch_to() or ret_from_fork.
++ */
++ pc = thread_saved_pc(p);
++ if (in_sched_functions(pc)) {
++#ifdef CONFIG_FRAME_POINTER
++ unsigned long fp = p->thread.cpu_context.r7;
++ BUG_ON(fp < stack_page || fp > (THREAD_SIZE + stack_page));
++ pc = *(unsigned long *)fp;
++#else
++ /*
++ * We depend on the frame size of schedule here, which
++ * is actually quite ugly. It might be possible to
++ * determine the frame size automatically at build
++ * time by doing this:
++ * - compile sched.c
++ * - disassemble the resulting sched.o
++ * - look for 'sub sp,??' shortly after '<schedule>:'
++ */
++ unsigned long sp = p->thread.cpu_context.ksp + 16;
++ BUG_ON(sp < stack_page || sp > (THREAD_SIZE + stack_page));
++ pc = *(unsigned long *)sp;
++#endif
++ }
++
++ return pc;
++}
+diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
+new file mode 100644
+index 0000000..f2e81cd
+--- /dev/null
++++ b/arch/avr32/kernel/ptrace.c
+@@ -0,0 +1,371 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#undef DEBUG
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/smp_lock.h>
++#include <linux/ptrace.h>
++#include <linux/errno.h>
++#include <linux/user.h>
++#include <linux/security.h>
++#include <linux/unistd.h>
++#include <linux/notifier.h>
++
++#include <asm/traps.h>
++#include <asm/uaccess.h>
++#include <asm/ocd.h>
++#include <asm/mmu_context.h>
++#include <asm/kdebug.h>
++
++static struct pt_regs *get_user_regs(struct task_struct *tsk)
++{
++ return (struct pt_regs *)((unsigned long) tsk->thread_info +
++ THREAD_SIZE - sizeof(struct pt_regs));
++}
++
++static void ptrace_single_step(struct task_struct *tsk)
++{
++ pr_debug("ptrace_single_step: pid=%u, SR=0x%08lx\n",
++ tsk->pid, tsk->thread.cpu_context.sr);
++ if (!(tsk->thread.cpu_context.sr & SR_D)) {
++ /*
++ * Set a breakpoint at the current pc to force the
++ * process into debug mode. The syscall/exception
++ * exit code will set a breakpoint at the return
++ * address when this flag is set.
++ */
++ pr_debug("ptrace_single_step: Setting TIF_BREAKPOINT\n");
++ set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
++ }
++
++ /* The monitor code will do the actual step for us */
++ set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
++}
++
++/*
++ * Called by kernel/ptrace.c when detaching
++ *
++ * Make sure any single step bits, etc. are not set
++ */
++void ptrace_disable(struct task_struct *child)
++{
++ clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
++}
++
++/*
++ * Handle hitting a breakpoint
++ */
++static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
++{
++ siginfo_t info;
++
++ info.si_signo = SIGTRAP;
++ info.si_errno = 0;
++ info.si_code = TRAP_BRKPT;
++ info.si_addr = (void __user *)instruction_pointer(regs);
++
++ pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n",
++ tsk->pid, info.si_addr);
++ force_sig_info(SIGTRAP, &info, tsk);
++}
++
++/*
++ * Read the word at offset "offset" into the task's "struct user". We
++ * actually access the pt_regs struct stored on the kernel stack.
++ */
++static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
++ unsigned long __user *data)
++{
++ unsigned long *regs;
++ unsigned long value;
++
++ pr_debug("ptrace_read_user(%p, %#lx, %p)\n",
++ tsk, offset, data);
++
++ if (offset & 3 || offset >= sizeof(struct user)) {
++ printk("ptrace_read_user: invalid offset 0x%08lx\n", offset);
++ return -EIO;
++ }
++
++ regs = (unsigned long *)get_user_regs(tsk);
++
++ value = 0;
++ if (offset < sizeof(struct pt_regs))
++ value = regs[offset / sizeof(regs[0])];
++
++ return put_user(value, data);
++}
++
++/*
++ * Write the word "value" to offset "offset" into the task's "struct
++ * user". We actually access the pt_regs struct stored on the kernel
++ * stack.
++ */
++static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
++ unsigned long value)
++{
++ unsigned long *regs;
++
++ if (offset & 3 || offset >= sizeof(struct user)) {
++ printk("ptrace_write_user: invalid offset 0x%08lx\n", offset);
++ return -EIO;
++ }
++
++ if (offset >= sizeof(struct pt_regs))
++ return 0;
++
++ regs = (unsigned long *)get_user_regs(tsk);
++ regs[offset / sizeof(regs[0])] = value;
++
++ return 0;
++}
++
++static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
++{
++ struct pt_regs *regs = get_user_regs(tsk);
++
++ return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0;
++}
++
++static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
++{
++ struct pt_regs newregs;
++ int ret;
++
++ ret = -EFAULT;
++ if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) {
++ struct pt_regs *regs = get_user_regs(tsk);
++
++ ret = -EINVAL;
++ if (valid_user_regs(&newregs)) {
++ *regs = newregs;
++ ret = 0;
++ }
++ }
++
++ return ret;
++}
++
++long arch_ptrace(struct task_struct *child, long request, long addr, long data)
++{
++ unsigned long tmp;
++ int ret;
++
++ pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n",
++ request, child->pid, addr, data);
++
++ pr_debug("ptrace: Enabling monitor mode...\n");
++ __mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE);
++
++ switch (request) {
++ /* Read the word at location addr in the child process */
++ case PTRACE_PEEKTEXT:
++ case PTRACE_PEEKDATA:
++ ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
++ if (ret == sizeof(tmp))
++ ret = put_user(tmp, (unsigned long __user *)data);
++ else
++ ret = -EIO;
++ break;
++
++ case PTRACE_PEEKUSR:
++ ret = ptrace_read_user(child, addr,
++ (unsigned long __user *)data);
++ break;
++
++ /* Write the word in data at location addr */
++ case PTRACE_POKETEXT:
++ case PTRACE_POKEDATA:
++ ret = access_process_vm(child, addr, &data, sizeof(data), 1);
++ if (ret == sizeof(data))
++ ret = 0;
++ else
++ ret = -EIO;
++ break;
++
++ case PTRACE_POKEUSR:
++ ret = ptrace_write_user(child, addr, data);
++ break;
++
++ /* continue and stop at next (return from) syscall */
++ case PTRACE_SYSCALL:
++ /* restart after signal */
++ case PTRACE_CONT:
++ 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;
++ /* XXX: Are we sure no breakpoints are active here? */
++ 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->exit_state == EXIT_ZOMBIE)
++ break;
++ child->exit_code = SIGKILL;
++ wake_up_process(child);
++ break;
++
++ /*
++ * execute single instruction.
++ */
++ case PTRACE_SINGLESTEP:
++ ret = -EIO;
++ if (!valid_signal(data))
++ break;
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ ptrace_single_step(child);
++ child->exit_code = data;
++ wake_up_process(child);
++ ret = 0;
++ break;
++
++ /* Detach a process that was attached */
++ case PTRACE_DETACH:
++ ret = ptrace_detach(child, data);
++ break;
++
++ case PTRACE_GETREGS:
++ ret = ptrace_getregs(child, (void __user *)data);
++ break;
++
++ case PTRACE_SETREGS:
++ ret = ptrace_setregs(child, (const void __user *)data);
++ break;
++
++ default:
++ ret = ptrace_request(child, request, addr, data);
++ break;
++ }
++
++ pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
++ return ret;
++}
++
++asmlinkage void syscall_trace(void)
++{
++ pr_debug("syscall_trace called\n");
++ if (!test_thread_flag(TIF_SYSCALL_TRACE))
++ return;
++ if (!(current->ptrace & PT_PTRACED))
++ return;
++
++ pr_debug("syscall_trace: notifying parent\n");
++ /* 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) {
++ pr_debug("syscall_trace: sending signal %d to PID %u\n",
++ current->exit_code, current->pid);
++ send_sig(current->exit_code, current, 1);
++ current->exit_code = 0;
++ }
++}
++
++asmlinkage void do_debug_priv(struct pt_regs *regs)
++{
++ unsigned long dc, ds;
++ unsigned long die_val;
++
++ ds = __mfdr(DBGREG_DS);
++
++ pr_debug("do_debug_priv: pc = %08lx, ds = %08lx\n", regs->pc, ds);
++
++ if (ds & DS_SSS)
++ die_val = DIE_SSTEP;
++ else
++ die_val = DIE_BREAKPOINT;
++
++ if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP)
++ return;
++
++ if (likely(ds & DS_SSS)) {
++ extern void itlb_miss(void);
++ extern void tlb_miss_common(void);
++ struct thread_info *ti;
++
++ dc = __mfdr(DBGREG_DC);
++ dc &= ~DC_SS;
++ __mtdr(DBGREG_DC, dc);
++
++ ti = current_thread_info();
++ ti->flags |= _TIF_BREAKPOINT;
++
++ /* The TLB miss handlers don't check thread flags */
++ if ((regs->pc >= (unsigned long)&itlb_miss)
++ && (regs->pc <= (unsigned long)&tlb_miss_common)) {
++ __mtdr(DBGREG_BWA2A, sysreg_read(RAR_EX));
++ __mtdr(DBGREG_BWC2A, 0x40000001 | (get_asid() << 1));
++ }
++
++ /*
++ * If we're running in supervisor mode, the breakpoint
++ * will take us where we want directly, no need to
++ * single step.
++ */
++ if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR)
++ ti->flags |= TIF_SINGLE_STEP;
++ } else {
++ panic("Unable to handle debug trap at pc = %08lx\n",
++ regs->pc);
++ }
++}
++
++/*
++ * Handle breakpoints, single steps and other debuggy things. To keep
++ * things simple initially, we run with interrupts and exceptions
++ * disabled all the time.
++ */
++asmlinkage void do_debug(struct pt_regs *regs)
++{
++ unsigned long dc, ds;
++
++ ds = __mfdr(DBGREG_DS);
++ pr_debug("do_debug: pc = %08lx, ds = %08lx\n", regs->pc, ds);
++
++ if (test_thread_flag(TIF_BREAKPOINT)) {
++ pr_debug("TIF_BREAKPOINT set\n");
++ /* We're taking care of it */
++ clear_thread_flag(TIF_BREAKPOINT);
++ __mtdr(DBGREG_BWC2A, 0);
++ }
++
++ if (test_thread_flag(TIF_SINGLE_STEP)) {
++ pr_debug("TIF_SINGLE_STEP set, ds = 0x%08lx\n", ds);
++ if (ds & DS_SSS) {
++ dc = __mfdr(DBGREG_DC);
++ dc &= ~DC_SS;
++ __mtdr(DBGREG_DC, dc);
++
++ clear_thread_flag(TIF_SINGLE_STEP);
++ ptrace_break(current, regs);
++ }
++ } else {
++ /* regular breakpoint */
++ ptrace_break(current, regs);
++ }
++}
+diff --git a/arch/avr32/kernel/semaphore.c b/arch/avr32/kernel/semaphore.c
+new file mode 100644
+index 0000000..1e2705a
+--- /dev/null
++++ b/arch/avr32/kernel/semaphore.c
+@@ -0,0 +1,148 @@
++/*
++ * AVR32 sempahore implementation.
++ *
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on linux/arch/i386/kernel/semaphore.c
++ * Copyright (C) 1999 Linus Torvalds
++ *
++ * 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/sched.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++
++#include <asm/semaphore.h>
++#include <asm/atomic.h>
++
++/*
++ * Semaphores are implemented using a two-way counter:
++ * The "count" variable is decremented for each process
++ * that tries to acquire the semaphore, while the "sleeping"
++ * variable is a count of such acquires.
++ *
++ * Notably, the inline "up()" and "down()" functions can
++ * efficiently test if they need to do any extra work (up
++ * needs to do something only if count was negative before
++ * the increment operation.
++ *
++ * "sleeping" and the contention routine ordering is protected
++ * by the spinlock in the semaphore's waitqueue head.
++ *
++ * Note that these functions are only called when there is
++ * contention on the lock, and as such all this is the
++ * "non-critical" part of the whole semaphore business. The
++ * critical part is the inline stuff in <asm/semaphore.h>
++ * where we want to avoid any extra jumps and calls.
++ */
++
++/*
++ * Logic:
++ * - only on a boundary condition do we need to care. When we go
++ * from a negative count to a non-negative, we wake people up.
++ * - when we go from a non-negative count to a negative do we
++ * (a) synchronize with the "sleeper" count and (b) make sure
++ * that we're on the wakeup list before we synchronize so that
++ * we cannot lose wakeup events.
++ */
++
++void __up(struct semaphore *sem)
++{
++ wake_up(&sem->wait);
++}
++EXPORT_SYMBOL(__up);
++
++void __sched __down(struct semaphore *sem)
++{
++ struct task_struct *tsk = current;
++ DECLARE_WAITQUEUE(wait, tsk);
++ unsigned long flags;
++
++ tsk->state = TASK_UNINTERRUPTIBLE;
++ spin_lock_irqsave(&sem->wait.lock, flags);
++ add_wait_queue_exclusive_locked(&sem->wait, &wait);
++
++ sem->sleepers++;
++ for (;;) {
++ int sleepers = sem->sleepers;
++
++ /*
++ * Add "everybody else" into it. They aren't
++ * playing, because we own the spinlock in
++ * the wait_queue_head.
++ */
++ if (atomic_add_return(sleepers - 1, &sem->count) >= 0) {
++ sem->sleepers = 0;
++ break;
++ }
++ sem->sleepers = 1; /* us - see -1 above */
++ spin_unlock_irqrestore(&sem->wait.lock, flags);
++
++ schedule();
++
++ spin_lock_irqsave(&sem->wait.lock, flags);
++ tsk->state = TASK_UNINTERRUPTIBLE;
++ }
++ remove_wait_queue_locked(&sem->wait, &wait);
++ wake_up_locked(&sem->wait);
++ spin_unlock_irqrestore(&sem->wait.lock, flags);
++ tsk->state = TASK_RUNNING;
++}
++EXPORT_SYMBOL(__down);
++
++int __sched __down_interruptible(struct semaphore *sem)
++{
++ int retval = 0;
++ struct task_struct *tsk = current;
++ DECLARE_WAITQUEUE(wait, tsk);
++ unsigned long flags;
++
++ tsk->state = TASK_INTERRUPTIBLE;
++ spin_lock_irqsave(&sem->wait.lock, flags);
++ add_wait_queue_exclusive_locked(&sem->wait, &wait);
++
++ sem->sleepers++;
++ for (;;) {
++ int sleepers = sem->sleepers;
++
++ /*
++ * With signals pending, this turns into the trylock
++ * failure case - we won't be sleeping, and we can't
++ * get the lock as it has contention. Just correct the
++ * count and exit.
++ */
++ if (signal_pending(current)) {
++ retval = -EINTR;
++ sem->sleepers = 0;
++ atomic_add(sleepers, &sem->count);
++ break;
++ }
++
++ /*
++ * Add "everybody else" into it. They aren't
++ * playing, because we own the spinlock in
++ * the wait_queue_head.
++ */
++ if (atomic_add_return(sleepers - 1, &sem->count) >= 0) {
++ sem->sleepers = 0;
++ break;
++ }
++ sem->sleepers = 1; /* us - see -1 above */
++ spin_unlock_irqrestore(&sem->wait.lock, flags);
++
++ schedule();
++
++ spin_lock_irqsave(&sem->wait.lock, flags);
++ tsk->state = TASK_INTERRUPTIBLE;
++ }
++ remove_wait_queue_locked(&sem->wait, &wait);
++ wake_up_locked(&sem->wait);
++ spin_unlock_irqrestore(&sem->wait.lock, flags);
++
++ tsk->state = TASK_RUNNING;
++ return retval;
++}
++EXPORT_SYMBOL(__down_interruptible);
+diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
+new file mode 100644
+index 0000000..ea2d1ff
+--- /dev/null
++++ b/arch/avr32/kernel/setup.c
+@@ -0,0 +1,336 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <linux/clk.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/console.h>
++#include <linux/ioport.h>
++#include <linux/bootmem.h>
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/root_dev.h>
++#include <linux/cpu.h>
++
++#include <asm/sections.h>
++#include <asm/processor.h>
++#include <asm/pgtable.h>
++#include <asm/setup.h>
++#include <asm/sysreg.h>
++
++#include <asm/arch/board.h>
++#include <asm/arch/init.h>
++
++extern int root_mountflags;
++
++/*
++ * Bootloader-provided information about physical memory
++ */
++struct tag_mem_range *mem_phys;
++struct tag_mem_range *mem_reserved;
++struct tag_mem_range *mem_ramdisk;
++
++/*
++ * Initialize loops_per_jiffy as 5000000 (500MIPS).
++ * Better make it too large than too small...
++ */
++struct avr32_cpuinfo boot_cpu_data = {
++ .loops_per_jiffy = 5000000
++};
++EXPORT_SYMBOL(boot_cpu_data);
++
++static char command_line[COMMAND_LINE_SIZE];
++
++/*
++ * Should be more than enough, but if you have a _really_ complex
++ * setup, you might need to increase the size of this...
++ */
++static struct tag_mem_range __initdata mem_range_cache[32];
++static unsigned mem_range_next_free;
++
++/*
++ * Standard memory resources
++ */
++static struct resource mem_res[] = {
++ {
++ .name = "Kernel code",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .name = "Kernel data",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++#define kernel_code mem_res[0]
++#define kernel_data mem_res[1]
++
++/*
++ * Early framebuffer allocation. Works as follows:
++ * - If fbmem_size is zero, nothing will be allocated or reserved.
++ * - If fbmem_start is zero when setup_bootmem() is called,
++ * fbmem_size bytes will be allocated from the bootmem allocator.
++ * - If fbmem_start is nonzero, an area of size fbmem_size will be
++ * reserved at the physical address fbmem_start if necessary. If
++ * the area isn't in a memory region known to the kernel, it will
++ * be left alone.
++ *
++ * Board-specific code may use these variables to set up platform data
++ * for the framebuffer driver if fbmem_size is nonzero.
++ */
++static unsigned long __initdata fbmem_start;
++static unsigned long __initdata fbmem_size;
++
++/*
++ * "fbmem=xxx[kKmM]" allocates the specified amount of boot memory for
++ * use as framebuffer.
++ *
++ * "fbmem=xxx[kKmM]@yyy[kKmM]" defines a memory region of size xxx and
++ * starting at yyy to be reserved for use as framebuffer.
++ *
++ * The kernel won't verify that the memory region starting at yyy
++ * actually contains usable RAM.
++ */
++static int __init early_parse_fbmem(char *p)
++{
++ fbmem_size = memparse(p, &p);
++ if (*p == '@')
++ fbmem_start = memparse(p, &p);
++ return 0;
++}
++early_param("fbmem", early_parse_fbmem);
++
++static inline void __init resource_init(void)
++{
++ struct tag_mem_range *region;
++
++ kernel_code.start = __pa(init_mm.start_code);
++ kernel_code.end = __pa(init_mm.end_code - 1);
++ kernel_data.start = __pa(init_mm.end_code);
++ kernel_data.end = __pa(init_mm.brk - 1);
++
++ for (region = mem_phys; region; region = region->next) {
++ struct resource *res;
++ unsigned long phys_start, phys_end;
++
++ if (region->size == 0)
++ continue;
++
++ phys_start = region->addr;
++ phys_end = phys_start + region->size - 1;
++
++ res = alloc_bootmem_low(sizeof(*res));
++ res->name = "System RAM";
++ res->start = phys_start;
++ res->end = phys_end;
++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++
++ request_resource (&iomem_resource, res);
++
++ if (kernel_code.start >= res->start &&
++ kernel_code.end <= res->end)
++ request_resource (res, &kernel_code);
++ if (kernel_data.start >= res->start &&
++ kernel_data.end <= res->end)
++ request_resource (res, &kernel_data);
++ }
++}
++
++static int __init parse_tag_core(struct tag *tag)
++{
++ if (tag->hdr.size > 2) {
++ if ((tag->u.core.flags & 1) == 0)
++ root_mountflags &= ~MS_RDONLY;
++ ROOT_DEV = new_decode_dev(tag->u.core.rootdev);
++ }
++ return 0;
++}
++__tagtable(ATAG_CORE, parse_tag_core);
++
++static int __init parse_tag_mem_range(struct tag *tag,
++ struct tag_mem_range **root)
++{
++ struct tag_mem_range *cur, **pprev;
++ struct tag_mem_range *new;
++
++ /*
++ * Ignore zero-sized entries. If we're running standalone, the
++ * SDRAM code may emit such entries if something goes
++ * wrong...
++ */
++ if (tag->u.mem_range.size == 0)
++ return 0;
++
++ /*
++ * Copy the data so the bootmem init code doesn't need to care
++ * about it.
++ */
++ if (mem_range_next_free >=
++ (sizeof(mem_range_cache) / sizeof(mem_range_cache[0])))
++ panic("Physical memory map too complex!\n");
++
++ new = &mem_range_cache[mem_range_next_free++];
++ *new = tag->u.mem_range;
++
++ pprev = root;
++ cur = *root;
++ while (cur) {
++ pprev = &cur->next;
++ cur = cur->next;
++ }
++
++ *pprev = new;
++ new->next = NULL;
++
++ return 0;
++}
++
++static int __init parse_tag_mem(struct tag *tag)
++{
++ return parse_tag_mem_range(tag, &mem_phys);
++}
++__tagtable(ATAG_MEM, parse_tag_mem);
++
++static int __init parse_tag_cmdline(struct tag *tag)
++{
++ strlcpy(saved_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
++ return 0;
++}
++__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
++
++static int __init parse_tag_rdimg(struct tag *tag)
++{
++ return parse_tag_mem_range(tag, &mem_ramdisk);
++}
++__tagtable(ATAG_RDIMG, parse_tag_rdimg);
++
++static int __init parse_tag_clock(struct tag *tag)
++{
++ /*
++ * We'll figure out the clocks by peeking at the system
++ * manager regs directly.
++ */
++ return 0;
++}
++__tagtable(ATAG_CLOCK, parse_tag_clock);
++
++static int __init parse_tag_rsvd_mem(struct tag *tag)
++{
++ return parse_tag_mem_range(tag, &mem_reserved);
++}
++__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
++
++static int __init parse_tag_ethernet(struct tag *tag)
++{
++#if 0
++ const struct platform_device *pdev;
++
++ /*
++ * We really need a bus type that supports "classes"...this
++ * will do for now (until we must handle other kinds of
++ * ethernet controllers)
++ */
++ pdev = platform_get_device("macb", tag->u.ethernet.mac_index);
++ if (pdev && pdev->dev.platform_data) {
++ struct eth_platform_data *data = pdev->dev.platform_data;
++
++ data->valid = 1;
++ data->mii_phy_addr = tag->u.ethernet.mii_phy_addr;
++ memcpy(data->hw_addr, tag->u.ethernet.hw_address,
++ sizeof(data->hw_addr));
++ }
++#endif
++ return 0;
++}
++__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
++
++/*
++ * Scan the tag table for this tag, and call its parse function. The
++ * tag table is built by the linker from all the __tagtable
++ * declarations.
++ */
++static int __init parse_tag(struct tag *tag)
++{
++ extern struct tagtable __tagtable_begin, __tagtable_end;
++ struct tagtable *t;
++
++ for (t = &__tagtable_begin; t < &__tagtable_end; t++)
++ if (tag->hdr.tag == t->tag) {
++ t->parse(tag);
++ break;
++ }
++
++ return t < &__tagtable_end;
++}
++
++/*
++ * Parse all tags in the list we got from the boot loader
++ */
++static void __init parse_tags(struct tag *t)
++{
++ for (; t->hdr.tag != ATAG_NONE; t = tag_next(t))
++ if (!parse_tag(t))
++ printk(KERN_WARNING
++ "Ignoring unrecognised tag 0x%08x\n",
++ t->hdr.tag);
++}
++
++void __init setup_arch (char **cmdline_p)
++{
++ struct clk *cpu_clk;
++
++ parse_tags(bootloader_tags);
++
++ setup_processor();
++ setup_platform();
++ setup_board();
++
++ cpu_clk = clk_get(NULL, "cpu");
++ if (IS_ERR(cpu_clk)) {
++ printk(KERN_WARNING "Warning: Unable to get CPU clock\n");
++ } else {
++ unsigned long cpu_hz = clk_get_rate(cpu_clk);
++
++ /*
++ * Well, duh, but it's probably a good idea to
++ * increment the use count.
++ */
++ clk_enable(cpu_clk);
++
++ boot_cpu_data.clk = cpu_clk;
++ boot_cpu_data.loops_per_jiffy = cpu_hz * 4;
++ printk("CPU: Running at %lu.%03lu MHz\n",
++ ((cpu_hz + 500) / 1000) / 1000,
++ ((cpu_hz + 500) / 1000) % 1000);
++ }
++
++ init_mm.start_code = (unsigned long) &_text;
++ init_mm.end_code = (unsigned long) &_etext;
++ init_mm.end_data = (unsigned long) &_edata;
++ init_mm.brk = (unsigned long) &_end;
++
++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE);
++ *cmdline_p = command_line;
++ parse_early_param();
++
++ setup_bootmem();
++
++ board_setup_fbmem(fbmem_start, fbmem_size);
++
++#ifdef CONFIG_VT
++ conswitchp = &dummy_con;
++#endif
++
++ paging_init();
++
++ resource_init();
++}
+diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
+new file mode 100644
+index 0000000..3309665
+--- /dev/null
++++ b/arch/avr32/kernel/signal.c
+@@ -0,0 +1,328 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on linux/arch/sh/kernel/signal.c
++ * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * 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/sched.h>
++#include <linux/mm.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/unistd.h>
++#include <linux/suspend.h>
++
++#include <asm/uaccess.h>
++#include <asm/ucontext.h>
++
++#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
++
++asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
++ struct pt_regs *regs)
++{
++ return do_sigaltstack(uss, uoss, regs->sp);
++}
++
++struct rt_sigframe
++{
++ struct siginfo info;
++ struct ucontext uc;
++ unsigned long retcode;
++};
++
++static int
++restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
++{
++ int err = 0;
++
++#define COPY(x) err |= __get_user(regs->x, &sc->x)
++ COPY(sr);
++ COPY(pc);
++ COPY(lr);
++ COPY(sp);
++ COPY(r12);
++ COPY(r11);
++ COPY(r10);
++ COPY(r9);
++ COPY(r8);
++ COPY(r7);
++ COPY(r6);
++ COPY(r5);
++ COPY(r4);
++ COPY(r3);
++ COPY(r2);
++ COPY(r1);
++ COPY(r0);
++#undef COPY
++
++ /*
++ * Don't allow anyone to pretend they're running in supervisor
++ * mode or something...
++ */
++ err |= !valid_user_regs(regs);
++
++ return err;
++}
++
++
++asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
++{
++ struct rt_sigframe __user *frame;
++ sigset_t set;
++
++ frame = (struct rt_sigframe __user *)regs->sp;
++ pr_debug("SIG return: frame = %p\n", frame);
++
++ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
++ goto badframe;
++
++ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
++ goto badframe;
++
++ sigdelsetmask(&set, ~_BLOCKABLE);
++ spin_lock_irq(¤t->sighand->siglock);
++ current->blocked = set;
++ recalc_sigpending();
++ spin_unlock_irq(¤t->sighand->siglock);
++
++ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
++ goto badframe;
++
++ pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
++ regs->pc, regs->lr, regs->sp);
++
++ return regs->r12;
++
++badframe:
++ force_sig(SIGSEGV, current);
++ return 0;
++}
++
++static int
++setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
++{
++ int err = 0;
++
++#define COPY(x) err |= __put_user(regs->x, &sc->x)
++ COPY(sr);
++ COPY(pc);
++ COPY(lr);
++ COPY(sp);
++ COPY(r12);
++ COPY(r11);
++ COPY(r10);
++ COPY(r9);
++ COPY(r8);
++ COPY(r7);
++ COPY(r6);
++ COPY(r5);
++ COPY(r4);
++ COPY(r3);
++ COPY(r2);
++ COPY(r1);
++ COPY(r0);
++#undef COPY
++
++ return err;
++}
++
++static inline void __user *
++get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
++{
++ unsigned long sp = regs->sp;
++
++ if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
++ sp = current->sas_ss_sp + current->sas_ss_size;
++
++ return (void __user *)((sp - framesize) & ~3);
++}
++
++static int
++setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
++ sigset_t *set, struct pt_regs *regs)
++{
++ struct rt_sigframe __user *frame;
++ int err = 0;
++
++ frame = get_sigframe(ka, regs, sizeof(*frame));
++ err = -EFAULT;
++ if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
++ goto out;
++
++ /*
++ * Set up the return code:
++ *
++ * mov r8, __NR_rt_sigreturn
++ * scall
++ *
++ * Note: This will blow up since we're using a non-executable
++ * stack. Better use SA_RESTORER.
++ */
++#if __NR_rt_sigreturn > 127
++# error __NR_rt_sigreturn must be < 127 to fit in a short mov
++#endif
++ err = __put_user(0x3008d733 | (__NR_rt_sigreturn << 20),
++ &frame->retcode);
++
++ err |= copy_siginfo_to_user(&frame->info, info);
++
++ /* Set up the ucontext */
++ err |= __put_user(0, &frame->uc.uc_flags);
++ err |= __put_user(NULL, &frame->uc.uc_link);
++ err |= __put_user((void __user *)current->sas_ss_sp,
++ &frame->uc.uc_stack.ss_sp);
++ err |= __put_user(sas_ss_flags(regs->sp),
++ &frame->uc.uc_stack.ss_flags);
++ err |= __put_user(current->sas_ss_size,
++ &frame->uc.uc_stack.ss_size);
++ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
++ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
++
++ if (err)
++ goto out;
++
++ regs->r12 = sig;
++ regs->r11 = (unsigned long) &frame->info;
++ regs->r10 = (unsigned long) &frame->uc;
++ regs->sp = (unsigned long) frame;
++ if (ka->sa.sa_flags & SA_RESTORER)
++ regs->lr = (unsigned long)ka->sa.sa_restorer;
++ else {
++ printk(KERN_NOTICE "[%s:%d] did not set SA_RESTORER\n",
++ current->comm, current->pid);
++ regs->lr = (unsigned long) &frame->retcode;
++ }
++
++ pr_debug("SIG deliver [%s:%d]: sig=%d sp=0x%lx pc=0x%lx->0x%p lr=0x%lx\n",
++ current->comm, current->pid, sig, regs->sp,
++ regs->pc, ka->sa.sa_handler, regs->lr);
++
++ regs->pc = (unsigned long) ka->sa.sa_handler;
++
++out:
++ return err;
++}
++
++static inline void restart_syscall(struct pt_regs *regs)
++{
++ if (regs->r12 == -ERESTART_RESTARTBLOCK)
++ regs->r8 = __NR_restart_syscall;
++ else
++ regs->r12 = regs->r12_orig;
++ regs->pc -= 2;
++}
++
++static inline void
++handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
++ sigset_t *oldset, struct pt_regs *regs, int syscall)
++{
++ int ret;
++
++ /*
++ * Set up the stack frame
++ */
++ ret = setup_rt_frame(sig, ka, info, oldset, regs);
++
++ /*
++ * Check that the resulting registers are sane
++ */
++ ret |= !valid_user_regs(regs);
++
++ /*
++ * Block the signal if we were unsuccessful.
++ */
++ if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
++ spin_lock_irq(¤t->sighand->siglock);
++ sigorsets(¤t->blocked, ¤t->blocked,
++ &ka->sa.sa_mask);
++ sigaddset(¤t->blocked, sig);
++ recalc_sigpending();
++ spin_unlock_irq(¤t->sighand->siglock);
++ }
++
++ if (ret == 0)
++ return;
++
++ force_sigsegv(sig, 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.
++ */
++int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
++{
++ siginfo_t info;
++ int signr;
++ struct k_sigaction ka;
++
++ /*
++ * We want the common case to go fast, which is why we may in
++ * certain cases get here from kernel mode. Just return
++ * without doing anything if so.
++ */
++ if (!user_mode(regs))
++ return 0;
++
++ if (try_to_freeze()) {
++ signr = 0;
++ if (!signal_pending(current))
++ goto no_signal;
++ }
++
++ if (test_thread_flag(TIF_RESTORE_SIGMASK))
++ oldset = ¤t->saved_sigmask;
++ else if (!oldset)
++ oldset = ¤t->blocked;
++
++ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
++no_signal:
++ if (syscall) {
++ switch (regs->r12) {
++ case -ERESTART_RESTARTBLOCK:
++ case -ERESTARTNOHAND:
++ if (signr > 0) {
++ regs->r12 = -EINTR;
++ break;
++ }
++ /* fall through */
++ case -ERESTARTSYS:
++ if (signr > 0 && !(ka.sa.sa_flags & SA_RESTART)) {
++ regs->r12 = -EINTR;
++ break;
++ }
++ /* fall through */
++ case -ERESTARTNOINTR:
++ restart_syscall(regs);
++ }
++ }
++
++ if (signr == 0) {
++ /* No signal to deliver -- put the saved sigmask back */
++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
++ }
++ return 0;
++ }
++
++ handle_signal(signr, &ka, &info, oldset, regs, syscall);
++ return 1;
++}
++
++asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
++{
++ int syscall = 0;
++
++ if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR)
++ syscall = 1;
++
++ if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
++ do_signal(regs, ¤t->blocked, syscall);
++}
+diff --git a/arch/avr32/kernel/switch_to.S b/arch/avr32/kernel/switch_to.S
+new file mode 100644
+index 0000000..a48d046
+--- /dev/null
++++ b/arch/avr32/kernel/switch_to.S
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <asm/sysreg.h>
++
++ .text
++ .global __switch_to
++ .type __switch_to, @function
++
++ /* Switch thread context from "prev" to "next", returning "last"
++ * r12 : prev
++ * r11 : &prev->thread + 1
++ * r10 : &next->thread
++ */
++__switch_to:
++ stm --r11, r0,r1,r2,r3,r4,r5,r6,r7,sp,lr
++ mfsr r9, SYSREG_SR
++ st.w --r11, r9
++ ld.w r8, r10++
++ /*
++ * schedule() may have been called from a mode with a different
++ * set of registers. Make sure we don't lose anything here.
++ */
++ pushm r10,r12
++ mtsr SYSREG_SR, r8
++ frs /* flush the return stack */
++ sub pc, -2 /* flush the pipeline */
++ popm r10,r12
++ ldm r10++, r0,r1,r2,r3,r4,r5,r6,r7,sp,pc
++ .size __switch_to, . - __switch_to
+diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c
+new file mode 100644
+index 0000000..8deb600
+--- /dev/null
++++ b/arch/avr32/kernel/sys_avr32.c
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/mm.h>
++#include <linux/unistd.h>
++
++#include <asm/mman.h>
++#include <asm/uaccess.h>
++
++asmlinkage int sys_pipe(unsigned long __user *filedes)
++{
++ int fd[2];
++ int error;
++
++ error = do_pipe(fd);
++ if (!error) {
++ if (copy_to_user(filedes, fd, sizeof(fd)))
++ error = -EFAULT;
++ }
++ return error;
++}
++
++asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
++ unsigned long prot, unsigned long flags,
++ unsigned long fd, off_t offset)
++{
++ int error = -EBADF;
++ struct file *file = NULL;
++
++ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
++ if (!(flags & MAP_ANONYMOUS)) {
++ file = fget(fd);
++ if (!file)
++ return error;
++ }
++
++ down_write(¤t->mm->mmap_sem);
++ error = do_mmap_pgoff(file, addr, len, prot, flags, offset);
++ up_write(¤t->mm->mmap_sem);
++
++ if (file)
++ fput(file);
++ return error;
++}
++
++int kernel_execve(const char *file, char **argv, char **envp)
++{
++ register long scno asm("r8") = __NR_execve;
++ register long sc1 asm("r12") = (long)file;
++ register long sc2 asm("r11") = (long)argv;
++ register long sc3 asm("r10") = (long)envp;
++
++ asm volatile("scall"
++ : "=r"(sc1)
++ : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3)
++ : "cc", "memory");
++ return sc1;
++}
+diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S
+new file mode 100644
+index 0000000..890286a
+--- /dev/null
++++ b/arch/avr32/kernel/syscall-stubs.S
+@@ -0,0 +1,111 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++
++/*
++ * Stubs for syscalls that require access to pt_regs or that take more
++ * than five parameters.
++ */
++
++#define ARG6 r3
++
++ .text
++ .global __sys_rt_sigsuspend
++ .type __sys_rt_sigsuspend, at function
++__sys_rt_sigsuspend:
++ mov r10, sp
++ rjmp sys_rt_sigsuspend
++
++ .global __sys_sigaltstack
++ .type __sys_sigaltstack, at function
++__sys_sigaltstack:
++ mov r10, sp
++ rjmp sys_sigaltstack
++
++ .global __sys_rt_sigreturn
++ .type __sys_rt_sigreturn, at function
++__sys_rt_sigreturn:
++ mov r12, sp
++ rjmp sys_rt_sigreturn
++
++ .global __sys_fork
++ .type __sys_fork, at function
++__sys_fork:
++ mov r12, sp
++ rjmp sys_fork
++
++ .global __sys_clone
++ .type __sys_clone, at function
++__sys_clone:
++ mov r8, sp
++ rjmp sys_clone
++
++ .global __sys_vfork
++ .type __sys_vfork, at function
++__sys_vfork:
++ mov r12, sp
++ rjmp sys_vfork
++
++ .global __sys_execve
++ .type __sys_execve, at function
++__sys_execve:
++ mov r9, sp
++ rjmp sys_execve
++
++ .global __sys_mmap2
++ .type __sys_mmap2, at function
++__sys_mmap2:
++ pushm lr
++ st.w --sp, ARG6
++ rcall sys_mmap2
++ sub sp, -4
++ popm pc
++
++ .global __sys_sendto
++ .type __sys_sendto, at function
++__sys_sendto:
++ pushm lr
++ st.w --sp, ARG6
++ rcall sys_sendto
++ sub sp, -4
++ popm pc
++
++ .global __sys_recvfrom
++ .type __sys_recvfrom, at function
++__sys_recvfrom:
++ pushm lr
++ st.w --sp, ARG6
++ rcall sys_recvfrom
++ sub sp, -4
++ popm pc
++
++ .global __sys_pselect6
++ .type __sys_pselect6, at function
++__sys_pselect6:
++ pushm lr
++ st.w --sp, ARG6
++ rcall sys_pselect6
++ sub sp, -4
++ popm pc
++
++ .global __sys_splice
++ .type __sys_splice, at function
++__sys_splice:
++ pushm lr
++ st.w --sp, ARG6
++ rcall sys_splice
++ sub sp, -4
++ popm pc
++
++ .global __sys_epoll_pwait
++ .type __sys_epoll_pwait, at function
++__sys_epoll_pwait:
++ pushm lr
++ st.w --sp, ARG6
++ rcall sys_epoll_pwait
++ sub sp, -4
++ popm pc
+diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
+new file mode 100644
+index 0000000..db8f8b5
+--- /dev/null
++++ b/arch/avr32/kernel/syscall_table.S
+@@ -0,0 +1,290 @@
++/*
++ * AVR32 system call table
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
++#define sys_nfsservctl sys_ni_syscall
++#endif
++
++#if !defined(CONFIG_SYSV_IPC)
++# define sys_ipc sys_ni_syscall
++#endif
++
++ .section .rodata,"a", at progbits
++ .type sys_call_table, at object
++ .global sys_call_table
++ .align 2
++sys_call_table:
++ .long sys_restart_syscall
++ .long sys_exit
++ .long __sys_fork
++ .long sys_read
++ .long sys_write
++ .long sys_open /* 5 */
++ .long sys_close
++ .long sys_umask
++ .long sys_creat
++ .long sys_link
++ .long sys_unlink /* 10 */
++ .long __sys_execve
++ .long sys_chdir
++ .long sys_time
++ .long sys_mknod
++ .long sys_chmod /* 15 */
++ .long sys_chown
++ .long sys_lchown
++ .long sys_lseek
++ .long sys_llseek
++ .long sys_getpid /* 20 */
++ .long sys_mount
++ .long sys_umount
++ .long sys_setuid
++ .long sys_getuid
++ .long sys_stime /* 25 */
++ .long sys_ptrace
++ .long sys_alarm
++ .long sys_pause
++ .long sys_utime
++ .long sys_newstat /* 30 */
++ .long sys_newfstat
++ .long sys_newlstat
++ .long sys_access
++ .long sys_chroot
++ .long sys_sync /* 35 */
++ .long sys_fsync
++ .long sys_kill
++ .long sys_rename
++ .long sys_mkdir
++ .long sys_rmdir /* 40 */
++ .long sys_dup
++ .long sys_pipe
++ .long sys_times
++ .long __sys_clone
++ .long sys_brk /* 45 */
++ .long sys_setgid
++ .long sys_getgid
++ .long sys_getcwd
++ .long sys_geteuid
++ .long sys_getegid /* 50 */
++ .long sys_acct
++ .long sys_setfsuid
++ .long sys_setfsgid
++ .long sys_ioctl
++ .long sys_fcntl /* 55 */
++ .long sys_setpgid
++ .long sys_mremap
++ .long sys_setresuid
++ .long sys_getresuid
++ .long sys_setreuid /* 60 */
++ .long sys_setregid
++ .long sys_ustat
++ .long sys_dup2
++ .long sys_getppid
++ .long sys_getpgrp /* 65 */
++ .long sys_setsid
++ .long sys_rt_sigaction
++ .long __sys_rt_sigreturn
++ .long sys_rt_sigprocmask
++ .long sys_rt_sigpending /* 70 */
++ .long sys_rt_sigtimedwait
++ .long sys_rt_sigqueueinfo
++ .long __sys_rt_sigsuspend
++ .long sys_sethostname
++ .long sys_setrlimit /* 75 */
++ .long sys_getrlimit
++ .long sys_getrusage
++ .long sys_gettimeofday
++ .long sys_settimeofday
++ .long sys_getgroups /* 80 */
++ .long sys_setgroups
++ .long sys_select
++ .long sys_symlink
++ .long sys_fchdir
++ .long sys_readlink /* 85 */
++ .long sys_pread64
++ .long sys_pwrite64
++ .long sys_swapon
++ .long sys_reboot
++ .long __sys_mmap2 /* 90 */
++ .long sys_munmap
++ .long sys_truncate
++ .long sys_ftruncate
++ .long sys_fchmod
++ .long sys_fchown /* 95 */
++ .long sys_getpriority
++ .long sys_setpriority
++ .long sys_wait4
++ .long sys_statfs
++ .long sys_fstatfs /* 100 */
++ .long sys_vhangup
++ .long __sys_sigaltstack
++ .long sys_syslog
++ .long sys_setitimer
++ .long sys_getitimer /* 105 */
++ .long sys_swapoff
++ .long sys_sysinfo
++ .long sys_ipc
++ .long sys_sendfile
++ .long sys_setdomainname /* 110 */
++ .long sys_newuname
++ .long sys_adjtimex
++ .long sys_mprotect
++ .long __sys_vfork
++ .long sys_init_module /* 115 */
++ .long sys_delete_module
++ .long sys_quotactl
++ .long sys_getpgid
++ .long sys_bdflush
++ .long sys_sysfs /* 120 */
++ .long sys_personality
++ .long sys_ni_syscall /* reserved for afs_syscall */
++ .long sys_getdents
++ .long sys_flock
++ .long sys_msync /* 125 */
++ .long sys_readv
++ .long sys_writev
++ .long sys_getsid
++ .long sys_fdatasync
++ .long sys_sysctl /* 130 */
++ .long sys_mlock
++ .long sys_munlock
++ .long sys_mlockall
++ .long sys_munlockall
++ .long sys_sched_setparam /* 135 */
++ .long sys_sched_getparam
++ .long sys_sched_setscheduler
++ .long sys_sched_getscheduler
++ .long sys_sched_yield
++ .long sys_sched_get_priority_max /* 140 */
++ .long sys_sched_get_priority_min
++ .long sys_sched_rr_get_interval
++ .long sys_nanosleep
++ .long sys_poll
++ .long sys_nfsservctl /* 145 */
++ .long sys_setresgid
++ .long sys_getresgid
++ .long sys_prctl
++ .long sys_socket
++ .long sys_bind /* 150 */
++ .long sys_connect
++ .long sys_listen
++ .long sys_accept
++ .long sys_getsockname
++ .long sys_getpeername /* 155 */
++ .long sys_socketpair
++ .long sys_send
++ .long sys_recv
++ .long __sys_sendto
++ .long __sys_recvfrom /* 160 */
++ .long sys_shutdown
++ .long sys_setsockopt
++ .long sys_getsockopt
++ .long sys_sendmsg
++ .long sys_recvmsg /* 165 */
++ .long sys_truncate64
++ .long sys_ftruncate64
++ .long sys_stat64
++ .long sys_lstat64
++ .long sys_fstat64 /* 170 */
++ .long sys_pivot_root
++ .long sys_mincore
++ .long sys_madvise
++ .long sys_getdents64
++ .long sys_fcntl64 /* 175 */
++ .long sys_gettid
++ .long sys_readahead
++ .long sys_setxattr
++ .long sys_lsetxattr
++ .long sys_fsetxattr /* 180 */
++ .long sys_getxattr
++ .long sys_lgetxattr
++ .long sys_fgetxattr
++ .long sys_listxattr
++ .long sys_llistxattr /* 185 */
++ .long sys_flistxattr
++ .long sys_removexattr
++ .long sys_lremovexattr
++ .long sys_fremovexattr
++ .long sys_tkill /* 190 */
++ .long sys_sendfile64
++ .long sys_futex
++ .long sys_sched_setaffinity
++ .long sys_sched_getaffinity
++ .long sys_capget /* 195 */
++ .long sys_capset
++ .long sys_io_setup
++ .long sys_io_destroy
++ .long sys_io_getevents
++ .long sys_io_submit /* 200 */
++ .long sys_io_cancel
++ .long sys_fadvise64
++ .long sys_exit_group
++ .long sys_lookup_dcookie
++ .long sys_epoll_create /* 205 */
++ .long sys_epoll_ctl
++ .long sys_epoll_wait
++ .long sys_remap_file_pages
++ .long sys_set_tid_address
++ .long sys_timer_create /* 210 */
++ .long sys_timer_settime
++ .long sys_timer_gettime
++ .long sys_timer_getoverrun
++ .long sys_timer_delete
++ .long sys_clock_settime /* 215 */
++ .long sys_clock_gettime
++ .long sys_clock_getres
++ .long sys_clock_nanosleep
++ .long sys_statfs64
++ .long sys_fstatfs64 /* 220 */
++ .long sys_tgkill
++ .long sys_ni_syscall /* reserved for TUX */
++ .long sys_utimes
++ .long sys_fadvise64_64
++ .long sys_cacheflush /* 225 */
++ .long sys_ni_syscall /* sys_vserver */
++ .long sys_mq_open
++ .long sys_mq_unlink
++ .long sys_mq_timedsend
++ .long sys_mq_timedreceive /* 230 */
++ .long sys_mq_notify
++ .long sys_mq_getsetattr
++ .long sys_kexec_load
++ .long sys_waitid
++ .long sys_add_key /* 235 */
++ .long sys_request_key
++ .long sys_keyctl
++ .long sys_ioprio_set
++ .long sys_ioprio_get
++ .long sys_inotify_init /* 240 */
++ .long sys_inotify_add_watch
++ .long sys_inotify_rm_watch
++ .long sys_openat
++ .long sys_mkdirat
++ .long sys_mknodat /* 245 */
++ .long sys_fchownat
++ .long sys_futimesat
++ .long sys_fstatat64
++ .long sys_unlinkat
++ .long sys_renameat /* 250 */
++ .long sys_linkat
++ .long sys_symlinkat
++ .long sys_readlinkat
++ .long sys_fchmodat
++ .long sys_faccessat /* 255 */
++ .long __sys_pselect6
++ .long sys_ppoll
++ .long sys_unshare
++ .long sys_set_robust_list
++ .long sys_get_robust_list /* 260 */
++ .long __sys_splice
++ .long sys_sync_file_range
++ .long sys_tee
++ .long sys_vmsplice
++ .long __sys_epoll_pwait /* 265 */
++ .long sys_ni_syscall /* r8 is saturated at nr_syscalls */
+diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
+new file mode 100644
+index 0000000..5a247ba
+--- /dev/null
++++ b/arch/avr32/kernel/time.c
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on MIPS implementation arch/mips/kernel/time.c
++ * Copyright 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/clk.h>
++#include <linux/clocksource.h>
++#include <linux/time.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/kernel_stat.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/profile.h>
++#include <linux/sysdev.h>
++
++#include <asm/div64.h>
++#include <asm/sysreg.h>
++#include <asm/io.h>
++#include <asm/sections.h>
++
++static cycle_t read_cycle_count(void)
++{
++ return (cycle_t)sysreg_read(COUNT);
++}
++
++static struct clocksource clocksource_avr32 = {
++ .name = "avr32",
++ .rating = 350,
++ .read = read_cycle_count,
++ .mask = CLOCKSOURCE_MASK(32),
++ .shift = 16,
++ .is_continuous = 1,
++};
++
++/*
++ * By default we provide the null RTC ops
++ */
++static unsigned long null_rtc_get_time(void)
++{
++ return mktime(2004, 1, 1, 0, 0, 0);
++}
++
++static int null_rtc_set_time(unsigned long sec)
++{
++ return 0;
++}
++
++static unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
++static int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
++
++/* how many counter cycles in a jiffy? */
++static unsigned long cycles_per_jiffy;
++
++/* cycle counter value at the previous timer interrupt */
++static unsigned int timerhi, timerlo;
++
++/* the count value for the next timer interrupt */
++static unsigned int expirelo;
++
++static void avr32_timer_ack(void)
++{
++ unsigned int count;
++
++ /* Ack this timer interrupt and set the next one */
++ expirelo += cycles_per_jiffy;
++ if (expirelo == 0) {
++ printk(KERN_DEBUG "expirelo == 0\n");
++ sysreg_write(COMPARE, expirelo + 1);
++ } else {
++ sysreg_write(COMPARE, expirelo);
++ }
++
++ /* Check to see if we have missed any timer interrupts */
++ count = sysreg_read(COUNT);
++ if ((count - expirelo) < 0x7fffffff) {
++ expirelo = count + cycles_per_jiffy;
++ sysreg_write(COMPARE, expirelo);
++ }
++}
++
++static unsigned int avr32_hpt_read(void)
++{
++ return sysreg_read(COUNT);
++}
++
++/*
++ * Taken from MIPS c0_hpt_timer_init().
++ *
++ * Why is it so complicated, and what is "count"? My assumption is
++ * that `count' specifies the "reference cycle", i.e. the cycle since
++ * reset that should mean "zero". The reason COUNT is written twice is
++ * probably to make sure we don't get any timer interrupts while we
++ * are messing with the counter.
++ */
++static void avr32_hpt_init(unsigned int count)
++{
++ count = sysreg_read(COUNT) - count;
++ expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
++ sysreg_write(COUNT, expirelo - cycles_per_jiffy);
++ sysreg_write(COMPARE, expirelo);
++ sysreg_write(COUNT, count);
++}
++
++/*
++ * Scheduler clock - returns current time in nanosec units.
++ */
++unsigned long long sched_clock(void)
++{
++ /* There must be better ways...? */
++ return (unsigned long long)jiffies * (1000000000 / HZ);
++}
++
++/*
++ * local_timer_interrupt() does profiling and process accounting on a
++ * per-CPU basis.
++ *
++ * In UP mode, it is invoked from the (global) timer_interrupt.
++ */
++static void local_timer_interrupt(int irq, void *dev_id)
++{
++ if (current->pid)
++ profile_tick(CPU_PROFILING);
++ update_process_times(user_mode(get_irq_regs()));
++}
++
++static irqreturn_t
++timer_interrupt(int irq, void *dev_id)
++{
++ unsigned int count;
++
++ /* ack timer interrupt and try to set next interrupt */
++ count = avr32_hpt_read();
++ avr32_timer_ack();
++
++ /* Update timerhi/timerlo for intra-jiffy calibration */
++ timerhi += count < timerlo; /* Wrap around */
++ timerlo = count;
++
++ /*
++ * Call the generic timer interrupt handler
++ */
++ write_seqlock(&xtime_lock);
++ do_timer(1);
++ write_sequnlock(&xtime_lock);
++
++ /*
++ * In UP mode, we call local_timer_interrupt() to do profiling
++ * and process accounting.
++ *
++ * SMP is not supported yet.
++ */
++ local_timer_interrupt(irq, dev_id);
++
++ return IRQ_HANDLED;
++}
++
++static struct irqaction timer_irqaction = {
++ .handler = timer_interrupt,
++ .flags = IRQF_DISABLED,
++ .name = "timer",
++};
++
++void __init time_init(void)
++{
++ unsigned long mult, shift, count_hz;
++ int ret;
++
++ xtime.tv_sec = rtc_get_time();
++ xtime.tv_nsec = 0;
++
++ set_normalized_timespec(&wall_to_monotonic,
++ -xtime.tv_sec, -xtime.tv_nsec);
++
++ printk("Before time_init: count=%08lx, compare=%08lx\n",
++ (unsigned long)sysreg_read(COUNT),
++ (unsigned long)sysreg_read(COMPARE));
++
++ count_hz = clk_get_rate(boot_cpu_data.clk);
++ shift = clocksource_avr32.shift;
++ mult = clocksource_hz2mult(count_hz, shift);
++ clocksource_avr32.mult = mult;
++
++ printk("Cycle counter: mult=%lu, shift=%lu\n", mult, shift);
++
++ {
++ u64 tmp;
++
++ tmp = TICK_NSEC;
++ tmp <<= shift;
++ tmp += mult / 2;
++ do_div(tmp, mult);
++
++ cycles_per_jiffy = tmp;
++ }
++
++ /* This sets up the high precision timer for the first interrupt. */
++ avr32_hpt_init(avr32_hpt_read());
++
++ printk("After time_init: count=%08lx, compare=%08lx\n",
++ (unsigned long)sysreg_read(COUNT),
++ (unsigned long)sysreg_read(COMPARE));
++
++ ret = clocksource_register(&clocksource_avr32);
++ if (ret)
++ printk(KERN_ERR
++ "timer: could not register clocksource: %d\n", ret);
++
++ ret = setup_irq(0, &timer_irqaction);
++ if (ret)
++ printk("timer: could not request IRQ 0: %d\n", ret);
++}
++
++static struct sysdev_class timer_class = {
++ set_kset_name("timer"),
++};
++
++static struct sys_device timer_device = {
++ .id = 0,
++ .cls = &timer_class,
++};
++
++static int __init init_timer_sysfs(void)
++{
++ int err = sysdev_class_register(&timer_class);
++ if (!err)
++ err = sysdev_register(&timer_device);
++ return err;
++}
++
++device_initcall(init_timer_sysfs);
+diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
+new file mode 100644
+index 0000000..7e803f4
+--- /dev/null
++++ b/arch/avr32/kernel/traps.c
+@@ -0,0 +1,425 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#undef DEBUG
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++#include <linux/notifier.h>
++
++#include <asm/traps.h>
++#include <asm/sysreg.h>
++#include <asm/addrspace.h>
++#include <asm/ocd.h>
++#include <asm/mmu_context.h>
++#include <asm/uaccess.h>
++
++static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
++{
++ unsigned long p;
++ int i;
++
++ printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
++
++ for (p = bottom & ~31; p < top; ) {
++ printk("%04lx: ", p & 0xffff);
++
++ for (i = 0; i < 8; i++, p += 4) {
++ unsigned int val;
++
++ if (p < bottom || p >= top)
++ printk(" ");
++ else {
++ if (__get_user(val, (unsigned int __user *)p)) {
++ printk("\n");
++ goto out;
++ }
++ printk("%08x ", val);
++ }
++ }
++ printk("\n");
++ }
++
++out:
++ return;
++}
++
++#ifdef CONFIG_FRAME_POINTER
++static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
++ struct pt_regs *regs)
++{
++ unsigned long __user *fp;
++ unsigned long __user *last_fp = NULL;
++
++ if (regs) {
++ fp = (unsigned long __user *)regs->r7;
++ } else if (tsk == current) {
++ register unsigned long __user *real_fp __asm__("r7");
++ fp = real_fp;
++ } else {
++ fp = (unsigned long __user *)tsk->thread.cpu_context.r7;
++ }
++
++ /*
++ * Walk the stack until (a) we get an exception, (b) the frame
++ * pointer becomes zero, or (c) the frame pointer gets stuck
++ * at the same value.
++ */
++ while (fp && fp != last_fp) {
++ unsigned long lr, new_fp = 0;
++
++ last_fp = fp;
++ if (__get_user(lr, fp))
++ break;
++ if (fp && __get_user(new_fp, fp + 1))
++ break;
++ fp = (unsigned long __user *)new_fp;
++
++ printk(" [<%08lx>] ", lr);
++ print_symbol("%s\n", lr);
++ }
++ printk("\n");
++}
++#else
++static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
++ struct pt_regs *regs)
++{
++ unsigned long addr;
++
++ while (!kstack_end(sp)) {
++ addr = *sp++;
++ if (kernel_text_address(addr)) {
++ printk(" [<%08lx>] ", addr);
++ print_symbol("%s\n", addr);
++ }
++ }
++}
++#endif
++
++void show_trace(struct task_struct *tsk, unsigned long *sp,
++ struct pt_regs *regs)
++{
++ if (regs &&
++ (((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
++ ((regs->sr & MODE_MASK) == MODE_USER)))
++ return;
++
++ printk ("Call trace:");
++#ifdef CONFIG_KALLSYMS
++ printk("\n");
++#endif
++
++ __show_trace(tsk, sp, regs);
++ printk("\n");
++}
++
++void show_stack(struct task_struct *tsk, unsigned long *sp)
++{
++ unsigned long stack;
++
++ if (!tsk)
++ tsk = current;
++ if (sp == 0) {
++ if (tsk == current) {
++ register unsigned long *real_sp __asm__("sp");
++ sp = real_sp;
++ } else {
++ sp = (unsigned long *)tsk->thread.cpu_context.ksp;
++ }
++ }
++
++ stack = (unsigned long)sp;
++ dump_mem("Stack: ", stack,
++ THREAD_SIZE + (unsigned long)tsk->thread_info);
++ show_trace(tsk, sp, NULL);
++}
++
++void dump_stack(void)
++{
++ show_stack(NULL, NULL);
++}
++EXPORT_SYMBOL(dump_stack);
++
++ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
++
++int register_die_notifier(struct notifier_block *nb)
++{
++ pr_debug("register_die_notifier: %p\n", nb);
++
++ return atomic_notifier_chain_register(&avr32_die_chain, nb);
++}
++EXPORT_SYMBOL(register_die_notifier);
++
++int unregister_die_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(&avr32_die_chain, nb);
++}
++EXPORT_SYMBOL(unregister_die_notifier);
++
++static DEFINE_SPINLOCK(die_lock);
++
++void __die(const char *str, struct pt_regs *regs, unsigned long err,
++ const char *file, const char *func, unsigned long line)
++{
++ struct task_struct *tsk = current;
++ static int die_counter;
++
++ console_verbose();
++ spin_lock_irq(&die_lock);
++ bust_spinlocks(1);
++
++ printk(KERN_ALERT "%s", str);
++ if (file && func)
++ printk(" in %s:%s, line %ld", file, func, line);
++ printk("[#%d]:\n", ++die_counter);
++ print_modules();
++ show_regs(regs);
++ printk("Process %s (pid: %d, stack limit = 0x%p)\n",
++ tsk->comm, tsk->pid, tsk->thread_info + 1);
++
++ if (!user_mode(regs) || in_interrupt()) {
++ dump_mem("Stack: ", regs->sp,
++ THREAD_SIZE + (unsigned long)tsk->thread_info);
++ }
++
++ bust_spinlocks(0);
++ spin_unlock_irq(&die_lock);
++ do_exit(SIGSEGV);
++}
++
++void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err,
++ const char *file, const char *func, unsigned long line)
++{
++ if (!user_mode(regs))
++ __die(str, regs, err, file, func, line);
++}
++
++asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
++{
++#ifdef CONFIG_SUBARCH_AVR32B
++ /*
++ * The exception entry always saves RSR_EX. For NMI, this is
++ * wrong; it should be RSR_NMI
++ */
++ regs->sr = sysreg_read(RSR_NMI);
++#endif
++
++ printk("NMI taken!!!!\n");
++ die("NMI", regs, ecr);
++ BUG();
++}
++
++asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
++{
++ printk("Unable to handle critical exception %lu at pc = %08lx!\n",
++ ecr, regs->pc);
++ die("Oops", regs, ecr);
++ BUG();
++}
++
++asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
++{
++ siginfo_t info;
++
++ die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);
++
++#ifdef DEBUG
++ if (ecr == ECR_ADDR_ALIGN_X)
++ pr_debug("Instruction Address Exception at pc = %08lx\n",
++ regs->pc);
++ else if (ecr == ECR_ADDR_ALIGN_R)
++ pr_debug("Data Address Exception (Read) at pc = %08lx\n",
++ regs->pc);
++ else if (ecr == ECR_ADDR_ALIGN_W)
++ pr_debug("Data Address Exception (Write) at pc = %08lx\n",
++ regs->pc);
++ else
++ BUG();
++
++ show_regs(regs);
++#endif
++
++ info.si_signo = SIGBUS;
++ info.si_errno = 0;
++ info.si_code = BUS_ADRALN;
++ info.si_addr = (void __user *)regs->pc;
++
++ force_sig_info(SIGBUS, &info, current);
++}
++
++/* This way of handling undefined instructions is stolen from ARM */
++static LIST_HEAD(undef_hook);
++static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
++
++void register_undef_hook(struct undef_hook *hook)
++{
++ spin_lock_irq(&undef_lock);
++ list_add(&hook->node, &undef_hook);
++ spin_unlock_irq(&undef_lock);
++}
++
++void unregister_undef_hook(struct undef_hook *hook)
++{
++ spin_lock_irq(&undef_lock);
++ list_del(&hook->node);
++ spin_unlock_irq(&undef_lock);
++}
++
++static int do_cop_absent(u32 insn)
++{
++ int cop_nr;
++ u32 cpucr;
++ if ( (insn & 0xfdf00000) == 0xf1900000 )
++ /* LDC0 */
++ cop_nr = 0;
++ else
++ cop_nr = (insn >> 13) & 0x7;
++
++ /* Try enabling the coprocessor */
++ cpucr = sysreg_read(CPUCR);
++ cpucr |= (1 << (24 + cop_nr));
++ sysreg_write(CPUCR, cpucr);
++
++ cpucr = sysreg_read(CPUCR);
++ if ( !(cpucr & (1 << (24 + cop_nr))) ){
++ printk("Coprocessor #%i not found!\n", cop_nr);
++ return -1;
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_BUG
++#ifdef CONFIG_DEBUG_BUGVERBOSE
++static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
++{
++ char *file;
++ u16 line;
++ char c;
++
++ if (__get_user(line, (u16 __user *)(regs->pc + 2)))
++ return;
++ if (__get_user(file, (char * __user *)(regs->pc + 4))
++ || (unsigned long)file < PAGE_OFFSET
++ || __get_user(c, file))
++ file = "<bad filename>";
++
++ printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
++}
++#else
++static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
++{
++
++}
++#endif
++#endif
++
++asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
++{
++ u32 insn;
++ struct undef_hook *hook;
++ siginfo_t info;
++ void __user *pc;
++
++ if (!user_mode(regs))
++ goto kernel_trap;
++
++ local_irq_enable();
++
++ pc = (void __user *)instruction_pointer(regs);
++ if (__get_user(insn, (u32 __user *)pc))
++ goto invalid_area;
++
++ if (ecr == ECR_COPROC_ABSENT) {
++ if (do_cop_absent(insn) == 0)
++ return;
++ }
++
++ spin_lock_irq(&undef_lock);
++ list_for_each_entry(hook, &undef_hook, node) {
++ if ((insn & hook->insn_mask) == hook->insn_val) {
++ if (hook->fn(regs, insn) == 0) {
++ spin_unlock_irq(&undef_lock);
++ return;
++ }
++ }
++ }
++ spin_unlock_irq(&undef_lock);
++
++invalid_area:
++
++#ifdef DEBUG
++ printk("Illegal instruction at pc = %08lx\n", regs->pc);
++ if (regs->pc < TASK_SIZE) {
++ unsigned long ptbr, pgd, pte, *p;
++
++ ptbr = sysreg_read(PTBR);
++ p = (unsigned long *)ptbr;
++ pgd = p[regs->pc >> 22];
++ p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
++ pte = p[(regs->pc >> 12) & 0x3ff];
++ printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
++ }
++#endif
++
++ info.si_signo = SIGILL;
++ info.si_errno = 0;
++ info.si_addr = (void __user *)regs->pc;
++ switch (ecr) {
++ case ECR_ILLEGAL_OPCODE:
++ case ECR_UNIMPL_INSTRUCTION:
++ info.si_code = ILL_ILLOPC;
++ break;
++ case ECR_PRIVILEGE_VIOLATION:
++ info.si_code = ILL_PRVOPC;
++ break;
++ case ECR_COPROC_ABSENT:
++ info.si_code = ILL_COPROC;
++ break;
++ default:
++ BUG();
++ }
++
++ force_sig_info(SIGILL, &info, current);
++ return;
++
++kernel_trap:
++#ifdef CONFIG_BUG
++ if (__kernel_text_address(instruction_pointer(regs))) {
++ insn = *(u16 *)instruction_pointer(regs);
++ if (insn == AVR32_BUG_OPCODE) {
++ do_bug_verbose(regs, insn);
++ die("Kernel BUG", regs, 0);
++ return;
++ }
++ }
++#endif
++
++ die("Oops: Illegal instruction in kernel code", regs, ecr);
++}
++
++asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
++{
++ siginfo_t info;
++
++ printk("Floating-point exception at pc = %08lx\n", regs->pc);
++
++ /* We have no FPU... */
++ info.si_signo = SIGILL;
++ info.si_errno = 0;
++ info.si_addr = (void __user *)regs->pc;
++ info.si_code = ILL_COPROC;
++
++ force_sig_info(SIGILL, &info, current);
++}
++
++
++void __init trap_init(void)
++{
++
++}
+diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
+new file mode 100644
+index 0000000..5c4424e
+--- /dev/null
++++ b/arch/avr32/kernel/vmlinux.lds.c
+@@ -0,0 +1,133 @@
++/*
++ * AVR32 linker script for the Linux kernel
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#define LOAD_OFFSET 0x00000000
++#include <asm-generic/vmlinux.lds.h>
++
++OUTPUT_FORMAT("elf32-avr32", "elf32-avr32", "elf32-avr32")
++OUTPUT_ARCH(avr32)
++ENTRY(_start)
++
++/* Big endian */
++jiffies = jiffies_64 + 4;
++
++SECTIONS
++{
++ . = CONFIG_ENTRY_ADDRESS;
++ .init : AT(ADDR(.init) - LOAD_OFFSET) {
++ _stext = .;
++ __init_begin = .;
++ _sinittext = .;
++ *(.text.reset)
++ *(.init.text)
++ _einittext = .;
++ . = ALIGN(4);
++ __tagtable_begin = .;
++ *(.taglist)
++ __tagtable_end = .;
++ *(.init.data)
++ . = ALIGN(16);
++ __setup_start = .;
++ *(.init.setup)
++ __setup_end = .;
++ . = ALIGN(4);
++ __initcall_start = .;
++ INITCALLS
++ __initcall_end = .;
++ __con_initcall_start = .;
++ *(.con_initcall.init)
++ __con_initcall_end = .;
++ __security_initcall_start = .;
++ *(.security_initcall.init)
++ __security_initcall_end = .;
++ . = ALIGN(32);
++ __initramfs_start = .;
++ *(.init.ramfs)
++ __initramfs_end = .;
++ . = ALIGN(4096);
++ __init_end = .;
++ }
++
++ . = ALIGN(8192);
++ .text : AT(ADDR(.text) - LOAD_OFFSET) {
++ _evba = .;
++ _text = .;
++ *(.ex.text)
++ . = 0x50;
++ *(.tlbx.ex.text)
++ . = 0x60;
++ *(.tlbr.ex.text)
++ . = 0x70;
++ *(.tlbw.ex.text)
++ . = 0x100;
++ *(.scall.text)
++ *(.irq.text)
++ *(.text)
++ SCHED_TEXT
++ LOCK_TEXT
++ KPROBES_TEXT
++ *(.fixup)
++ *(.gnu.warning)
++ _etext = .;
++ } = 0xd703d703
++
++ . = ALIGN(4);
++ __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
++ __start___ex_table = .;
++ *(__ex_table)
++ __stop___ex_table = .;
++ }
++
++ RODATA
++
++ . = ALIGN(8192);
++
++ .data : AT(ADDR(.data) - LOAD_OFFSET) {
++ _data = .;
++ _sdata = .;
++ /*
++ * First, the init task union, aligned to an 8K boundary.
++ */
++ *(.data.init_task)
++
++ /* Then, the cacheline aligned data */
++ . = ALIGN(32);
++ *(.data.cacheline_aligned)
++
++ /* And the rest... */
++ *(.data.rel*)
++ *(.data)
++ CONSTRUCTORS
++
++ _edata = .;
++ }
++
++
++ . = ALIGN(8);
++ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
++ __bss_start = .;
++ *(.bss)
++ *(COMMON)
++ . = ALIGN(8);
++ __bss_stop = .;
++ _end = .;
++ }
++
++ /* When something in the kernel is NOT compiled as a module, the module
++ * cleanup code and data are put into these segments. Both can then be
++ * thrown away, as cleanup code is never called unless it's a module.
++ */
++ /DISCARD/ : {
++ *(.exit.text)
++ *(.exit.data)
++ *(.exitcall.exit)
++ }
++
++ DWARF_DEBUG
++}
+diff --git a/arch/avr32/lib/Makefile b/arch/avr32/lib/Makefile
+new file mode 100644
+index 0000000..084d95b
+--- /dev/null
++++ b/arch/avr32/lib/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for AVR32-specific library files
++#
++
++lib-y := copy_user.o clear_user.o
++lib-y += strncpy_from_user.o strnlen_user.o
++lib-y += delay.o memset.o memcpy.o findbit.o
++lib-y += csum_partial.o csum_partial_copy_generic.o
++lib-y += io-readsw.o io-readsl.o io-writesw.o io-writesl.o
++lib-y += io-readsb.o io-writesb.o
++lib-y += __avr32_lsl64.o __avr32_lsr64.o __avr32_asr64.o
+diff --git a/arch/avr32/lib/__avr32_asr64.S b/arch/avr32/lib/__avr32_asr64.S
+new file mode 100644
+index 0000000..368b6bc
+--- /dev/null
++++ b/arch/avr32/lib/__avr32_asr64.S
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++
++ /*
++ * DWtype __avr32_asr64(DWtype u, word_type b)
++ */
++ .text
++ .global __avr32_asr64
++ .type __avr32_asr64, at function
++__avr32_asr64:
++ cp.w r12, 0
++ reteq r12
++
++ rsub r9, r12, 32
++ brle 1f
++
++ lsl r8, r11, r9
++ lsr r10, r10, r12
++ asr r11, r11, r12
++ or r10, r8
++ retal r12
++
++1: neg r9
++ asr r10, r11, r9
++ asr r11, 31
++ retal r12
+diff --git a/arch/avr32/lib/__avr32_lsl64.S b/arch/avr32/lib/__avr32_lsl64.S
+new file mode 100644
+index 0000000..f1dbc2b
+--- /dev/null
++++ b/arch/avr32/lib/__avr32_lsl64.S
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++
++ /*
++ * DWtype __avr32_lsl64(DWtype u, word_type b)
++ */
++ .text
++ .global __avr32_lsl64
++ .type __avr32_lsl64, at function
++__avr32_lsl64:
++ cp.w r12, 0
++ reteq r12
++
++ rsub r9, r12, 32
++ brle 1f
++
++ lsr r8, r10, r9
++ lsl r10, r10, r12
++ lsl r11, r11, r12
++ or r11, r8
++ retal r12
++
++1: neg r9
++ lsl r11, r10, r9
++ mov r10, 0
++ retal r12
+diff --git a/arch/avr32/lib/__avr32_lsr64.S b/arch/avr32/lib/__avr32_lsr64.S
+new file mode 100644
+index 0000000..e65bb7f
+--- /dev/null
++++ b/arch/avr32/lib/__avr32_lsr64.S
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++
++ /*
++ * DWtype __avr32_lsr64(DWtype u, word_type b)
++ */
++ .text
++ .global __avr32_lsr64
++ .type __avr32_lsr64, at function
++__avr32_lsr64:
++ cp.w r12, 0
++ reteq r12
++
++ rsub r9, r12, 32
++ brle 1f
++
++ lsl r8, r11, r9
++ lsr r11, r11, r12
++ lsr r10, r10, r12
++ or r10, r8
++ retal r12
++
++1: neg r9
++ lsr r10, r11, r9
++ mov r11, 0
++ retal r12
+diff --git a/arch/avr32/lib/clear_user.S b/arch/avr32/lib/clear_user.S
+new file mode 100644
+index 0000000..d8991b6
+--- /dev/null
++++ b/arch/avr32/lib/clear_user.S
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 2004-2006 Atmel 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.
++ */
++#include <asm/page.h>
++#include <asm/thread_info.h>
++#include <asm/asm.h>
++
++ .text
++ .align 1
++ .global clear_user
++ .type clear_user, "function"
++clear_user:
++ branch_if_kernel r8, __clear_user
++ ret_if_privileged r8, r12, r11, r11
++
++ .global __clear_user
++ .type __clear_user, "function"
++__clear_user:
++ mov r9, r12
++ mov r8, 0
++ andl r9, 3, COH
++ brne 5f
++
++1: sub r11, 4
++ brlt 2f
++
++10: st.w r12++, r8
++ sub r11, 4
++ brge 10b
++
++2: sub r11, -4
++ reteq 0
++
++ /* Unaligned count or address */
++ bld r11, 1
++ brcc 12f
++11: st.h r12++, r8
++ sub r11, 2
++ reteq 0
++12: st.b r12++, r8
++ retal 0
++
++ /* Unaligned address */
++5: cp.w r11, 4
++ brlt 2b
++
++ lsl r9, 2
++ add pc, pc, r9
++13: st.b r12++, r8
++ sub r11, 1
++14: st.b r12++, r8
++ sub r11, 1
++15: st.b r12++, r8
++ sub r11, 1
++ rjmp 1b
++
++ .size clear_user, . - clear_user
++ .size __clear_user, . - __clear_user
++
++ .section .fixup, "ax"
++ .align 1
++18: sub r11, -4
++19: retal r11
++
++ .section __ex_table, "a"
++ .align 2
++ .long 10b, 18b
++ .long 11b, 19b
++ .long 12b, 19b
++ .long 13b, 19b
++ .long 14b, 19b
++ .long 15b, 19b
+diff --git a/arch/avr32/lib/copy_user.S b/arch/avr32/lib/copy_user.S
+new file mode 100644
+index 0000000..ea59c04
+--- /dev/null
++++ b/arch/avr32/lib/copy_user.S
+@@ -0,0 +1,119 @@
++/*
++ * Copy to/from userspace with optional address space checking.
++ *
++ * Copyright 2004-2006 Atmel 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.
++ */
++#include <asm/page.h>
++#include <asm/thread_info.h>
++#include <asm/asm.h>
++
++ /*
++ * __kernel_size_t
++ * __copy_user(void *to, const void *from, __kernel_size_t n)
++ *
++ * Returns the number of bytes not copied. Might be off by
++ * max 3 bytes if we get a fault in the main loop.
++ *
++ * The address-space checking functions simply fall through to
++ * the non-checking version.
++ */
++ .text
++ .align 1
++ .global copy_from_user
++ .type copy_from_user, @function
++copy_from_user:
++ branch_if_kernel r8, __copy_user
++ ret_if_privileged r8, r11, r10, r10
++ rjmp __copy_user
++ .size copy_from_user, . - copy_from_user
++
++ .global copy_to_user
++ .type copy_to_user, @function
++copy_to_user:
++ branch_if_kernel r8, __copy_user
++ ret_if_privileged r8, r12, r10, r10
++ .size copy_to_user, . - copy_to_user
++
++ .global __copy_user
++ .type __copy_user, @function
++__copy_user:
++ mov r9, r11
++ andl r9, 3, COH
++ brne 6f
++
++ /* At this point, from is word-aligned */
++1: sub r10, 4
++ brlt 3f
++
++2:
++10: ld.w r8, r11++
++11: st.w r12++, r8
++ sub r10, 4
++ brge 2b
++
++3: sub r10, -4
++ reteq 0
++
++ /*
++ * Handle unaligned count. Need to be careful with r10 here so
++ * that we return the correct value even if we get a fault
++ */
++4:
++20: ld.ub r8, r11++
++21: st.b r12++, r8
++ sub r10, 1
++ reteq 0
++22: ld.ub r8, r11++
++23: st.b r12++, r8
++ sub r10, 1
++ reteq 0
++24: ld.ub r8, r11++
++25: st.b r12++, r8
++ retal 0
++
++ /* Handle unaligned from-pointer */
++6: cp.w r10, 4
++ brlt 4b
++ rsub r9, r9, 4
++
++30: ld.ub r8, r11++
++31: st.b r12++, r8
++ sub r10, 1
++ sub r9, 1
++ breq 1b
++32: ld.ub r8, r11++
++33: st.b r12++, r8
++ sub r10, 1
++ sub r9, 1
++ breq 1b
++34: ld.ub r8, r11++
++35: st.b r12++, r8
++ sub r10, 1
++ rjmp 1b
++ .size __copy_user, . - __copy_user
++
++ .section .fixup,"ax"
++ .align 1
++19: sub r10, -4
++29: retal r10
++
++ .section __ex_table,"a"
++ .align 2
++ .long 10b, 19b
++ .long 11b, 19b
++ .long 20b, 29b
++ .long 21b, 29b
++ .long 22b, 29b
++ .long 23b, 29b
++ .long 24b, 29b
++ .long 25b, 29b
++ .long 30b, 29b
++ .long 31b, 29b
++ .long 32b, 29b
++ .long 33b, 29b
++ .long 34b, 29b
++ .long 35b, 29b
+diff --git a/arch/avr32/lib/csum_partial.S b/arch/avr32/lib/csum_partial.S
+new file mode 100644
+index 0000000..6a262b5
+--- /dev/null
++++ b/arch/avr32/lib/csum_partial.S
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++ /*
++ * unsigned int csum_partial(const unsigned char *buff,
++ * int len, unsigned int sum)
++ */
++ .text
++ .global csum_partial
++ .type csum_partial,"function"
++ .align 1
++csum_partial:
++ /* checksum complete words, aligned or not */
++3: sub r11, 4
++ brlt 5f
++4: ld.w r9, r12++
++ add r10, r9
++ acr r10
++ sub r11, 4
++ brge 4b
++
++ /* return if we had a whole number of words */
++5: sub r11, -4
++ reteq r10
++
++ /* checksum any remaining bytes at the end */
++ mov r9, 0
++ mov r8, 0
++ cp r11, 2
++ brlt 6f
++ ld.uh r9, r12++
++ sub r11, 2
++ breq 7f
++ lsl r9, 16
++6: ld.ub r8, r12++
++ lsl r8, 8
++7: or r9, r8
++ add r10, r9
++ acr r10
++
++ retal r10
++ .size csum_partial, . - csum_partial
+diff --git a/arch/avr32/lib/csum_partial_copy_generic.S b/arch/avr32/lib/csum_partial_copy_generic.S
+new file mode 100644
+index 0000000..a3a0f9b
+--- /dev/null
++++ b/arch/avr32/lib/csum_partial_copy_generic.S
+@@ -0,0 +1,99 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <asm/errno.h>
++#include <asm/asm.h>
++
++ /*
++ * unsigned int csum_partial_copy_generic(const char *src, char *dst, int len
++ * int sum, int *src_err_ptr,
++ * int *dst_err_ptr)
++ *
++ * Copy src to dst while checksumming, otherwise like csum_partial.
++ */
++
++ .macro ld_src size, reg, ptr
++9999: ld.\size \reg, \ptr
++ .section __ex_table, "a"
++ .long 9999b, fixup_ld_src
++ .previous
++ .endm
++
++ .macro st_dst size, ptr, reg
++9999: st.\size \ptr, \reg
++ .section __ex_table, "a"
++ .long 9999b, fixup_st_dst
++ .previous
++ .endm
++
++ .text
++ .global csum_partial_copy_generic
++ .type csum_partial_copy_generic,"function"
++ .align 1
++csum_partial_copy_generic:
++ pushm r4-r7,lr
++
++ /* The inner loop */
++1: sub r10, 4
++ brlt 5f
++2: ld_src w, r5, r12++
++ st_dst w, r11++, r5
++ add r9, r5
++ acr r9
++ sub r10, 4
++ brge 2b
++
++ /* return if we had a whole number of words */
++5: sub r10, -4
++ brne 7f
++
++6: mov r12, r9
++ popm r4-r7,pc
++
++ /* handle additional bytes at the tail */
++7: mov r5, 0
++ mov r4, 32
++8: ld_src ub, r6, r12++
++ st_dst b, r11++, r6
++ lsl r5, 8
++ sub r4, 8
++ bfins r5, r6, 0, 8
++ sub r10, 1
++ brne 8b
++
++ lsl r5, r5, r4
++ add r9, r5
++ acr r9
++ rjmp 6b
++
++ /* Exception handler */
++ .section .fixup,"ax"
++ .align 1
++fixup_ld_src:
++ mov r9, -EFAULT
++ cp.w r8, 0
++ breq 1f
++ st.w r8[0], r9
++
++1: /*
++ * TODO: zero the complete destination - computing the rest
++ * is too much work
++ */
++
++ mov r9, 0
++ rjmp 6b
++
++fixup_st_dst:
++ mov r9, -EFAULT
++ lddsp r8, sp[20]
++ cp.w r8, 0
++ breq 1f
++ st.w r8[0], r9
++1: mov r9, 0
++ rjmp 6b
++
++ .previous
+diff --git a/arch/avr32/lib/delay.c b/arch/avr32/lib/delay.c
+new file mode 100644
+index 0000000..462c830
+--- /dev/null
++++ b/arch/avr32/lib/delay.c
+@@ -0,0 +1,55 @@
++/*
++ * Precise Delay Loops for avr32
++ *
++ * Copyright (C) 1993 Linus Torvalds
++ * Copyright (C) 1997 Martin Mares <mj at atrey.karlin.mff.cuni.cz>
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/types.h>
++
++#include <asm/delay.h>
++#include <asm/processor.h>
++#include <asm/sysreg.h>
++
++int read_current_timer(unsigned long *timer_value)
++{
++ *timer_value = sysreg_read(COUNT);
++ return 0;
++}
++
++void __delay(unsigned long loops)
++{
++ unsigned bclock, now;
++
++ bclock = sysreg_read(COUNT);
++ do {
++ now = sysreg_read(COUNT);
++ } while ((now - bclock) < loops);
++}
++
++inline void __const_udelay(unsigned long xloops)
++{
++ unsigned long long loops;
++
++ asm("mulu.d %0, %1, %2"
++ : "=r"(loops)
++ : "r"(current_cpu_data.loops_per_jiffy * HZ), "r"(xloops));
++ __delay(loops >> 32);
++}
++
++void __udelay(unsigned long usecs)
++{
++ __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
++}
++
++void __ndelay(unsigned long nsecs)
++{
++ __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
++}
+diff --git a/arch/avr32/lib/findbit.S b/arch/avr32/lib/findbit.S
+new file mode 100644
+index 0000000..c6b91de
+--- /dev/null
++++ b/arch/avr32/lib/findbit.S
+@@ -0,0 +1,155 @@
++/*
++ * Copyright (C) 2006 Atmel 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.
++ */
++#include <linux/linkage.h>
++
++ .text
++ /*
++ * unsigned long find_first_zero_bit(const unsigned long *addr,
++ * unsigned long size)
++ */
++ENTRY(find_first_zero_bit)
++ cp.w r11, 0
++ reteq r11
++ mov r9, r11
++1: ld.w r8, r12[0]
++ com r8
++ brne .L_found
++ sub r12, -4
++ sub r9, 32
++ brgt 1b
++ retal r11
++
++ /*
++ * unsigned long find_next_zero_bit(const unsigned long *addr,
++ * unsigned long size,
++ * unsigned long offset)
++ */
++ENTRY(find_next_zero_bit)
++ lsr r8, r10, 5
++ sub r9, r11, r10
++ retle r11
++
++ lsl r8, 2
++ add r12, r8
++ andl r10, 31, COH
++ breq 1f
++
++ /* offset is not word-aligned. Handle the first (32 - r10) bits */
++ ld.w r8, r12[0]
++ com r8
++ sub r12, -4
++ lsr r8, r8, r10
++ brne .L_found
++
++ /* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
++ add r9, r10
++ sub r9, 32
++ retle r11
++
++ /* Main loop. offset must be word-aligned */
++1: ld.w r8, r12[0]
++ com r8
++ brne .L_found
++ sub r12, -4
++ sub r9, 32
++ brgt 1b
++ retal r11
++
++ /* Common return path for when a bit is actually found. */
++.L_found:
++ brev r8
++ clz r10, r8
++ rsub r9, r11
++ add r10, r9
++
++ /* XXX: If we don't have to return exactly "size" when the bit
++ is not found, we may drop this "min" thing */
++ min r12, r11, r10
++ retal r12
++
++ /*
++ * unsigned long find_first_bit(const unsigned long *addr,
++ * unsigned long size)
++ */
++ENTRY(find_first_bit)
++ cp.w r11, 0
++ reteq r11
++ mov r9, r11
++1: ld.w r8, r12[0]
++ cp.w r8, 0
++ brne .L_found
++ sub r12, -4
++ sub r9, 32
++ brgt 1b
++ retal r11
++
++ /*
++ * unsigned long find_next_bit(const unsigned long *addr,
++ * unsigned long size,
++ * unsigned long offset)
++ */
++ENTRY(find_next_bit)
++ lsr r8, r10, 5
++ sub r9, r11, r10
++ retle r11
++
++ lsl r8, 2
++ add r12, r8
++ andl r10, 31, COH
++ breq 1f
++
++ /* offset is not word-aligned. Handle the first (32 - r10) bits */
++ ld.w r8, r12[0]
++ sub r12, -4
++ lsr r8, r8, r10
++ brne .L_found
++
++ /* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
++ add r9, r10
++ sub r9, 32
++ retle r11
++
++ /* Main loop. offset must be word-aligned */
++1: ld.w r8, r12[0]
++ cp.w r8, 0
++ brne .L_found
++ sub r12, -4
++ sub r9, 32
++ brgt 1b
++ retal r11
++
++ENTRY(generic_find_next_zero_le_bit)
++ lsr r8, r10, 5
++ sub r9, r11, r10
++ retle r11
++
++ lsl r8, 2
++ add r12, r8
++ andl r10, 31, COH
++ breq 1f
++
++ /* offset is not word-aligned. Handle the first (32 - r10) bits */
++ ldswp.w r8, r12[0]
++ sub r12, -4
++ com r8
++ lsr r8, r8, r10
++ brne .L_found
++
++ /* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
++ add r9, r10
++ sub r9, 32
++ retle r11
++
++ /* Main loop. offset must be word-aligned */
++1: ldswp.w r8, r12[0]
++ com r8
++ brne .L_found
++ sub r12, -4
++ sub r9, 32
++ brgt 1b
++ retal r11
+diff --git a/arch/avr32/lib/io-readsb.S b/arch/avr32/lib/io-readsb.S
+new file mode 100644
+index 0000000..2be5da7
+--- /dev/null
++++ b/arch/avr32/lib/io-readsb.S
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++ .text
++.Lnot_word_aligned:
++1: ld.ub r8, r12[0]
++ sub r10, 1
++ st.b r11++, r8
++ reteq r12
++ tst r11, r9
++ brne 1b
++
++ /* fall through */
++
++ .global __raw_readsb
++ .type __raw_readsb, at function
++__raw_readsb:
++ cp.w r10, 0
++ mov r9, 3
++ reteq r12
++
++ tst r11, r9
++ brne .Lnot_word_aligned
++
++ sub r10, 4
++ brlt 2f
++
++1: ldins.b r8:t, r12[0]
++ ldins.b r8:u, r12[0]
++ ldins.b r8:l, r12[0]
++ ldins.b r8:b, r12[0]
++ st.w r11++, r8
++ sub r10, 4
++ brge 1b
++
++2: sub r10, -4
++ reteq r12
++
++3: ld.uh r8, r12[0]
++ sub r10, 1
++ st.b r11++, r8
++ brne 3b
++
++ retal r12
+diff --git a/arch/avr32/lib/io-readsl.S b/arch/avr32/lib/io-readsl.S
+new file mode 100644
+index 0000000..b103511
+--- /dev/null
++++ b/arch/avr32/lib/io-readsl.S
+@@ -0,0 +1,24 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++ .global __raw_readsl
++ .type __raw_readsl, at function
++__raw_readsl:
++ cp.w r10, 0
++ reteq r12
++
++ /*
++ * If r11 isn't properly aligned, we might get an exception on
++ * some implementations. But there's not much we can do about it.
++ */
++1: ld.w r8, r12[0]
++ sub r10, 1
++ st.w r11++, r8
++ brne 1b
++
++ retal r12
+diff --git a/arch/avr32/lib/io-readsw.S b/arch/avr32/lib/io-readsw.S
+new file mode 100644
+index 0000000..456be99
+--- /dev/null
++++ b/arch/avr32/lib/io-readsw.S
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++.Lnot_word_aligned:
++ /*
++ * Bad alignment will cause a hardware exception, which is as
++ * good as anything. No need for us to check for proper alignment.
++ */
++ ld.uh r8, r12[0]
++ sub r10, 1
++ st.h r11++, r8
++
++ /* fall through */
++
++ .global __raw_readsw
++ .type __raw_readsw, at function
++__raw_readsw:
++ cp.w r10, 0
++ reteq r12
++ mov r9, 3
++ tst r11, r9
++ brne .Lnot_word_aligned
++
++ sub r10, 2
++ brlt 2f
++
++1: ldins.h r8:t, r12[0]
++ ldins.h r8:b, r12[0]
++ st.w r11++, r8
++ sub r10, 2
++ brge 1b
++
++2: sub r10, -2
++ reteq r12
++
++ ld.uh r8, r12[0]
++ st.h r11++, r8
++ retal r12
+diff --git a/arch/avr32/lib/io-writesb.S b/arch/avr32/lib/io-writesb.S
+new file mode 100644
+index 0000000..b4ebaac
+--- /dev/null
++++ b/arch/avr32/lib/io-writesb.S
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++ .text
++.Lnot_word_aligned:
++1: ld.ub r8, r11++
++ sub r10, 1
++ st.b r12[0], r8
++ reteq r12
++ tst r11, r9
++ brne 1b
++
++ /* fall through */
++
++ .global __raw_writesb
++ .type __raw_writesb, at function
++__raw_writesb:
++ cp.w r10, 0
++ mov r9, 3
++ reteq r12
++
++ tst r11, r9
++ brne .Lnot_word_aligned
++
++ sub r10, 4
++ brlt 2f
++
++1: ld.w r8, r11++
++ bfextu r9, r8, 24, 8
++ st.b r12[0], r9
++ bfextu r9, r8, 16, 8
++ st.b r12[0], r9
++ bfextu r9, r8, 8, 8
++ st.b r12[0], r9
++ st.b r12[0], r8
++ sub r10, 4
++ brge 1b
++
++2: sub r10, -4
++ reteq r12
++
++3: ld.ub r8, r11++
++ sub r10, 1
++ st.b r12[0], r8
++ brne 3b
++
++ retal r12
+diff --git a/arch/avr32/lib/io-writesl.S b/arch/avr32/lib/io-writesl.S
+new file mode 100644
+index 0000000..22138b3
+--- /dev/null
++++ b/arch/avr32/lib/io-writesl.S
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++ .global __raw_writesl
++ .type __raw_writesl, at function
++__raw_writesl:
++ cp.w r10, 0
++ reteq r12
++
++1: ld.w r8, r11++
++ sub r10, 1
++ st.w r12[0], r8
++ brne 1b
++
++ retal r12
+diff --git a/arch/avr32/lib/io-writesw.S b/arch/avr32/lib/io-writesw.S
+new file mode 100644
+index 0000000..8c4a53f
+--- /dev/null
++++ b/arch/avr32/lib/io-writesw.S
+@@ -0,0 +1,38 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++.Lnot_word_aligned:
++ ld.uh r8, r11++
++ sub r10, 1
++ st.h r12[0], r8
++
++ .global __raw_writesw
++ .type __raw_writesw, at function
++__raw_writesw:
++ cp.w r10, 0
++ mov r9, 3
++ reteq r12
++ tst r11, r9
++ brne .Lnot_word_aligned
++
++ sub r10, 2
++ brlt 2f
++
++1: ld.w r8, r11++
++ bfextu r9, r8, 16, 16
++ st.h r12[0], r9
++ st.h r12[0], r8
++ sub r10, 2
++ brge 1b
++
++2: sub r10, -2
++ reteq r12
++
++ ld.uh r8, r11++
++ st.h r12[0], r8
++ retal r12
+diff --git a/arch/avr32/lib/libgcc.h b/arch/avr32/lib/libgcc.h
+new file mode 100644
+index 0000000..5a091b5
+--- /dev/null
++++ b/arch/avr32/lib/libgcc.h
+@@ -0,0 +1,33 @@
++/* Definitions for various functions 'borrowed' from gcc-3.4.3 */
++
++#define BITS_PER_UNIT 8
++
++typedef int QItype __attribute__ ((mode (QI)));
++typedef unsigned int UQItype __attribute__ ((mode (QI)));
++typedef int HItype __attribute__ ((mode (HI)));
++typedef unsigned int UHItype __attribute__ ((mode (HI)));
++typedef int SItype __attribute__ ((mode (SI)));
++typedef unsigned int USItype __attribute__ ((mode (SI)));
++typedef int DItype __attribute__ ((mode (DI)));
++typedef unsigned int UDItype __attribute__ ((mode (DI)));
++typedef float SFtype __attribute__ ((mode (SF)));
++typedef float DFtype __attribute__ ((mode (DF)));
++typedef int word_type __attribute__ ((mode (__word__)));
++
++#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
++#define Wtype SItype
++#define UWtype USItype
++#define HWtype SItype
++#define UHWtype USItype
++#define DWtype DItype
++#define UDWtype UDItype
++#define __NW(a,b) __ ## a ## si ## b
++#define __NDW(a,b) __ ## a ## di ## b
++
++struct DWstruct {Wtype high, low;};
++
++typedef union
++{
++ struct DWstruct s;
++ DWtype ll;
++} DWunion;
+diff --git a/arch/avr32/lib/longlong.h b/arch/avr32/lib/longlong.h
+new file mode 100644
+index 0000000..cd5e369
+--- /dev/null
++++ b/arch/avr32/lib/longlong.h
+@@ -0,0 +1,98 @@
++/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
++ Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
++ 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-3.4.3 */
++
++#define __BITS4 (W_TYPE_SIZE / 4)
++#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
++#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
++#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
++
++#define count_leading_zeros(count, x) ((count) = __builtin_clz(x))
++
++#define __udiv_qrnnd_c(q, r, n1, n0, d) \
++ do { \
++ UWtype __d1, __d0, __q1, __q0; \
++ UWtype __r1, __r0, __m; \
++ __d1 = __ll_highpart (d); \
++ __d0 = __ll_lowpart (d); \
++ \
++ __r1 = (n1) % __d1; \
++ __q1 = (n1) / __d1; \
++ __m = (UWtype) __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 = (UWtype) __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) = (UWtype) __q1 * __ll_B | __q0; \
++ (r) = __r0; \
++ } while (0)
++
++#define udiv_qrnnd __udiv_qrnnd_c
++
++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
++ do { \
++ UWtype __x; \
++ __x = (al) - (bl); \
++ (sh) = (ah) - (bh) - (__x > (al)); \
++ (sl) = __x; \
++ } while (0)
++
++#define umul_ppmm(w1, w0, u, v) \
++ do { \
++ UWtype __x0, __x1, __x2, __x3; \
++ UHWtype __ul, __vl, __uh, __vh; \
++ \
++ __ul = __ll_lowpart (u); \
++ __uh = __ll_highpart (u); \
++ __vl = __ll_lowpart (v); \
++ __vh = __ll_highpart (v); \
++ \
++ __x0 = (UWtype) __ul * __vl; \
++ __x1 = (UWtype) __ul * __vh; \
++ __x2 = (UWtype) __uh * __vl; \
++ __x3 = (UWtype) __uh * __vh; \
++ \
++ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
++ __x1 += __x2; /* but this indeed can */ \
++ if (__x1 < __x2) /* did we get it? */ \
++ __x3 += __ll_B; /* yes, add it in the proper pos. */ \
++ \
++ (w1) = __x3 + __ll_highpart (__x1); \
++ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
++ } while (0)
+diff --git a/arch/avr32/lib/memcpy.S b/arch/avr32/lib/memcpy.S
+new file mode 100644
+index 0000000..0abb261
+--- /dev/null
++++ b/arch/avr32/lib/memcpy.S
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++ /*
++ * void *memcpy(void *to, const void *from, unsigned long n)
++ *
++ * This implementation does word-aligned loads in the main loop,
++ * possibly sacrificing alignment of stores.
++ *
++ * Hopefully, in most cases, both "to" and "from" will be
++ * word-aligned to begin with.
++ */
++ .text
++ .global memcpy
++ .type memcpy, @function
++memcpy:
++ mov r9, r11
++ andl r9, 3, COH
++ brne 1f
++
++ /* At this point, "from" is word-aligned */
++2: sub r10, 4
++ mov r9, r12
++ brlt 4f
++
++3: ld.w r8, r11++
++ sub r10, 4
++ st.w r12++, r8
++ brge 3b
++
++4: neg r10
++ reteq r9
++
++ /* Handle unaligned count */
++ lsl r10, 2
++ add pc, pc, r10
++ ld.ub r8, r11++
++ st.b r12++, r8
++ ld.ub r8, r11++
++ st.b r12++, r8
++ ld.ub r8, r11++
++ st.b r12++, r8
++ retal r9
++
++ /* Handle unaligned "from" pointer */
++1: sub r10, 4
++ brlt 4b
++ add r10, r9
++ lsl r9, 2
++ add pc, pc, r9
++ ld.ub r8, r11++
++ st.b r12++, r8
++ ld.ub r8, r11++
++ st.b r12++, r8
++ ld.ub r8, r11++
++ st.b r12++, r8
++ rjmp 2b
+diff --git a/arch/avr32/lib/memset.S b/arch/avr32/lib/memset.S
+new file mode 100644
+index 0000000..40da32c
+--- /dev/null
++++ b/arch/avr32/lib/memset.S
+@@ -0,0 +1,72 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on linux/arch/arm/lib/memset.S
++ * Copyright (C) 1995-2000 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.
++ *
++ * ASM optimised string functions
++ */
++#include <asm/asm.h>
++
++ /*
++ * r12: void *b
++ * r11: int c
++ * r10: size_t len
++ *
++ * Returns b in r12
++ */
++ .text
++ .global memset
++ .type memset, @function
++ .align 5
++memset:
++ mov r9, r12
++ mov r8, r12
++ or r11, r11, r11 << 8
++ andl r9, 3, COH
++ brne 1f
++
++2: or r11, r11, r11 << 16
++ sub r10, 4
++ brlt 5f
++
++ /* Let's do some real work */
++4: st.w r8++, r11
++ sub r10, 4
++ brge 4b
++
++ /*
++ * When we get here, we've got less than 4 bytes to set. r10
++ * might be negative.
++ */
++5: sub r10, -4
++ reteq r12
++
++ /* Fastpath ends here, exactly 32 bytes from memset */
++
++ /* Handle unaligned count or pointer */
++ bld r10, 1
++ brcc 6f
++ st.b r8++, r11
++ st.b r8++, r11
++ bld r10, 0
++ retcc r12
++6: st.b r8++, r11
++ retal r12
++
++ /* Handle unaligned pointer */
++1: sub r10, 4
++ brlt 5b
++ add r10, r9
++ lsl r9, 1
++ add pc, r9
++ st.b r8++, r11
++ st.b r8++, r11
++ st.b r8++, r11
++ rjmp 2b
++
++ .size memset, . - memset
+diff --git a/arch/avr32/lib/strncpy_from_user.S b/arch/avr32/lib/strncpy_from_user.S
+new file mode 100644
+index 0000000..72bd505
+--- /dev/null
++++ b/arch/avr32/lib/strncpy_from_user.S
+@@ -0,0 +1,60 @@
++/*
++ * Copy to/from userspace with optional address space checking.
++ *
++ * Copyright 2004-2006 Atmel 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.
++ */
++#include <linux/errno.h>
++
++#include <asm/page.h>
++#include <asm/thread_info.h>
++#include <asm/asm.h>
++
++ /*
++ * long strncpy_from_user(char *dst, const char *src, long count)
++ *
++ * On success, returns the length of the string, not including
++ * the terminating NUL.
++ *
++ * If the string is longer than count, returns count
++ *
++ * If userspace access fails, returns -EFAULT
++ */
++ .text
++ .align 1
++ .global strncpy_from_user
++ .type strncpy_from_user, "function"
++strncpy_from_user:
++ mov r9, -EFAULT
++ branch_if_kernel r8, __strncpy_from_user
++ ret_if_privileged r8, r11, r10, r9
++
++ .global __strncpy_from_user
++ .type __strncpy_from_user, "function"
++__strncpy_from_user:
++ cp.w r10, 0
++ reteq 0
++
++ mov r9, r10
++
++1: ld.ub r8, r11++
++ st.b r12++, r8
++ cp.w r8, 0
++ breq 2f
++ sub r9, 1
++ brne 1b
++
++2: sub r10, r9
++ retal r10
++
++ .section .fixup, "ax"
++ .align 1
++3: mov r12, -EFAULT
++ retal r12
++
++ .section __ex_table, "a"
++ .align 2
++ .long 1b, 3b
+diff --git a/arch/avr32/lib/strnlen_user.S b/arch/avr32/lib/strnlen_user.S
+new file mode 100644
+index 0000000..65ce11a
+--- /dev/null
++++ b/arch/avr32/lib/strnlen_user.S
+@@ -0,0 +1,67 @@
++/*
++ * Copy to/from userspace with optional address space checking.
++ *
++ * Copyright 2004-2006 Atmel 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.
++ */
++#include <asm/page.h>
++#include <asm/thread_info.h>
++#include <asm/processor.h>
++#include <asm/asm.h>
++
++ .text
++ .align 1
++ .global strnlen_user
++ .type strnlen_user, "function"
++strnlen_user:
++ branch_if_kernel r8, __strnlen_user
++ sub r8, r11, 1
++ add r8, r12
++ retcs 0
++ brmi adjust_length /* do a closer inspection */
++
++ .global __strnlen_user
++ .type __strnlen_user, "function"
++__strnlen_user:
++ mov r10, r12
++
++10: ld.ub r8, r12++
++ cp.w r8, 0
++ breq 2f
++ sub r11, 1
++ brne 10b
++
++ sub r12, -1
++2: sub r12, r10
++ retal r12
++
++
++ .type adjust_length, "function"
++adjust_length:
++ cp.w r12, 0 /* addr must always be < TASK_SIZE */
++ retmi 0
++
++ pushm lr
++ lddpc lr, _task_size
++ sub r11, lr, r12
++ mov r9, r11
++ rcall __strnlen_user
++ cp.w r12, r9
++ brgt 1f
++ popm pc
++1: popm pc, r12=0
++
++ .align 2
++_task_size:
++ .long TASK_SIZE
++
++ .section .fixup, "ax"
++ .align 1
++19: retal 0
++
++ .section __ex_table, "a"
++ .align 2
++ .long 10b, 19b
+diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
+new file mode 100644
+index 0000000..f62eb69
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/Makefile
+@@ -0,0 +1,2 @@
++obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o
++obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o
+diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/at32ap.c
+new file mode 100644
+index 0000000..90f207e
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/at32ap.c
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2006 Atmel 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.
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++
++#include <asm/arch/init.h>
++#include <asm/arch/sm.h>
++
++struct at32_sm system_manager;
++
++static int __init at32_sm_init(void)
++{
++ struct resource *regs;
++ struct at32_sm *sm = &system_manager;
++ int ret = -ENXIO;
++
++ regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
++ if (!regs)
++ goto fail;
++
++ spin_lock_init(&sm->lock);
++ sm->pdev = &at32_sm_device;
++
++ ret = -ENOMEM;
++ sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!sm->regs)
++ goto fail;
++
++ return 0;
++
++fail:
++ printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
++ return ret;
++}
++
++void __init setup_platform(void)
++{
++ at32_sm_init();
++ at32_clock_init();
++ at32_portmux_init();
++}
++
++static int __init pdc_probe(struct platform_device *pdev)
++{
++ struct clk *pclk, *hclk;
++
++ pclk = clk_get(&pdev->dev, "pclk");
++ if (IS_ERR(pclk)) {
++ dev_err(&pdev->dev, "no pclk defined\n");
++ return PTR_ERR(pclk);
++ }
++ hclk = clk_get(&pdev->dev, "hclk");
++ if (IS_ERR(hclk)) {
++ dev_err(&pdev->dev, "no hclk defined\n");
++ clk_put(pclk);
++ return PTR_ERR(hclk);
++ }
++
++ clk_enable(pclk);
++ clk_enable(hclk);
++
++ dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n");
++ return 0;
++}
++
++static struct platform_driver pdc_driver = {
++ .probe = pdc_probe,
++ .driver = {
++ .name = "pdc",
++ },
++};
++
++static int __init pdc_init(void)
++{
++ return platform_driver_register(&pdc_driver);
++}
++arch_initcall(pdc_init);
+diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
+new file mode 100644
+index 0000000..7ff6ad8
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/at32ap7000.c
+@@ -0,0 +1,895 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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.
++ */
++#include <linux/clk.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++
++#include <asm/arch/board.h>
++#include <asm/arch/portmux.h>
++#include <asm/arch/sm.h>
++
++#include "clock.h"
++#include "pio.h"
++#include "sm.h"
++
++#define PBMEM(base) \
++ { \
++ .start = base, \
++ .end = base + 0x3ff, \
++ .flags = IORESOURCE_MEM, \
++ }
++#define IRQ(num) \
++ { \
++ .start = num, \
++ .end = num, \
++ .flags = IORESOURCE_IRQ, \
++ }
++#define NAMED_IRQ(num, _name) \
++ { \
++ .start = num, \
++ .end = num, \
++ .name = _name, \
++ .flags = IORESOURCE_IRQ, \
++ }
++
++#define DEFINE_DEV(_name, _id) \
++static struct platform_device _name##_id##_device = { \
++ .name = #_name, \
++ .id = _id, \
++ .resource = _name##_id##_resource, \
++ .num_resources = ARRAY_SIZE(_name##_id##_resource), \
++}
++#define DEFINE_DEV_DATA(_name, _id) \
++static struct platform_device _name##_id##_device = { \
++ .name = #_name, \
++ .id = _id, \
++ .dev = { \
++ .platform_data = &_name##_id##_data, \
++ }, \
++ .resource = _name##_id##_resource, \
++ .num_resources = ARRAY_SIZE(_name##_id##_resource), \
++}
++
++#define DEV_CLK(_name, devname, bus, _index) \
++static struct clk devname##_##_name = { \
++ .name = #_name, \
++ .dev = &devname##_device.dev, \
++ .parent = &bus##_clk, \
++ .mode = bus##_clk_mode, \
++ .get_rate = bus##_clk_get_rate, \
++ .index = _index, \
++}
++
++enum {
++ PIOA,
++ PIOB,
++ PIOC,
++ PIOD,
++};
++
++enum {
++ FUNC_A,
++ FUNC_B,
++};
++
++unsigned long at32ap7000_osc_rates[3] = {
++ [0] = 32768,
++ /* FIXME: these are ATSTK1002-specific */
++ [1] = 20000000,
++ [2] = 12000000,
++};
++
++static unsigned long osc_get_rate(struct clk *clk)
++{
++ return at32ap7000_osc_rates[clk->index];
++}
++
++static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
++{
++ unsigned long div, mul, rate;
++
++ if (!(control & SM_BIT(PLLEN)))
++ return 0;
++
++ div = SM_BFEXT(PLLDIV, control) + 1;
++ mul = SM_BFEXT(PLLMUL, control) + 1;
++
++ rate = clk->parent->get_rate(clk->parent);
++ rate = (rate + div / 2) / div;
++ rate *= mul;
++
++ return rate;
++}
++
++static unsigned long pll0_get_rate(struct clk *clk)
++{
++ u32 control;
++
++ control = sm_readl(&system_manager, PM_PLL0);
++
++ return pll_get_rate(clk, control);
++}
++
++static unsigned long pll1_get_rate(struct clk *clk)
++{
++ u32 control;
++
++ control = sm_readl(&system_manager, PM_PLL1);
++
++ return pll_get_rate(clk, control);
++}
++
++/*
++ * The AT32AP7000 has five primary clock sources: One 32kHz
++ * oscillator, two crystal oscillators and two PLLs.
++ */
++static struct clk osc32k = {
++ .name = "osc32k",
++ .get_rate = osc_get_rate,
++ .users = 1,
++ .index = 0,
++};
++static struct clk osc0 = {
++ .name = "osc0",
++ .get_rate = osc_get_rate,
++ .users = 1,
++ .index = 1,
++};
++static struct clk osc1 = {
++ .name = "osc1",
++ .get_rate = osc_get_rate,
++ .index = 2,
++};
++static struct clk pll0 = {
++ .name = "pll0",
++ .get_rate = pll0_get_rate,
++ .parent = &osc0,
++};
++static struct clk pll1 = {
++ .name = "pll1",
++ .get_rate = pll1_get_rate,
++ .parent = &osc0,
++};
++
++/*
++ * The main clock can be either osc0 or pll0. The boot loader may
++ * have chosen one for us, so we don't really know which one until we
++ * have a look at the SM.
++ */
++static struct clk *main_clock;
++
++/*
++ * Synchronous clocks are generated from the main clock. The clocks
++ * must satisfy the constraint
++ * fCPU >= fHSB >= fPB
++ * i.e. each clock must not be faster than its parent.
++ */
++static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
++{
++ return main_clock->get_rate(main_clock) >> shift;
++};
++
++static void cpu_clk_mode(struct clk *clk, int enabled)
++{
++ struct at32_sm *sm = &system_manager;
++ unsigned long flags;
++ u32 mask;
++
++ spin_lock_irqsave(&sm->lock, flags);
++ mask = sm_readl(sm, PM_CPU_MASK);
++ if (enabled)
++ mask |= 1 << clk->index;
++ else
++ mask &= ~(1 << clk->index);
++ sm_writel(sm, PM_CPU_MASK, mask);
++ spin_unlock_irqrestore(&sm->lock, flags);
++}
++
++static unsigned long cpu_clk_get_rate(struct clk *clk)
++{
++ unsigned long cksel, shift = 0;
++
++ cksel = sm_readl(&system_manager, PM_CKSEL);
++ if (cksel & SM_BIT(CPUDIV))
++ shift = SM_BFEXT(CPUSEL, cksel) + 1;
++
++ return bus_clk_get_rate(clk, shift);
++}
++
++static void hsb_clk_mode(struct clk *clk, int enabled)
++{
++ struct at32_sm *sm = &system_manager;
++ unsigned long flags;
++ u32 mask;
++
++ spin_lock_irqsave(&sm->lock, flags);
++ mask = sm_readl(sm, PM_HSB_MASK);
++ if (enabled)
++ mask |= 1 << clk->index;
++ else
++ mask &= ~(1 << clk->index);
++ sm_writel(sm, PM_HSB_MASK, mask);
++ spin_unlock_irqrestore(&sm->lock, flags);
++}
++
++static unsigned long hsb_clk_get_rate(struct clk *clk)
++{
++ unsigned long cksel, shift = 0;
++
++ cksel = sm_readl(&system_manager, PM_CKSEL);
++ if (cksel & SM_BIT(HSBDIV))
++ shift = SM_BFEXT(HSBSEL, cksel) + 1;
++
++ return bus_clk_get_rate(clk, shift);
++}
++
++static void pba_clk_mode(struct clk *clk, int enabled)
++{
++ struct at32_sm *sm = &system_manager;
++ unsigned long flags;
++ u32 mask;
++
++ spin_lock_irqsave(&sm->lock, flags);
++ mask = sm_readl(sm, PM_PBA_MASK);
++ if (enabled)
++ mask |= 1 << clk->index;
++ else
++ mask &= ~(1 << clk->index);
++ sm_writel(sm, PM_PBA_MASK, mask);
++ spin_unlock_irqrestore(&sm->lock, flags);
++}
++
++static unsigned long pba_clk_get_rate(struct clk *clk)
++{
++ unsigned long cksel, shift = 0;
++
++ cksel = sm_readl(&system_manager, PM_CKSEL);
++ if (cksel & SM_BIT(PBADIV))
++ shift = SM_BFEXT(PBASEL, cksel) + 1;
++
++ return bus_clk_get_rate(clk, shift);
++}
++
++static void pbb_clk_mode(struct clk *clk, int enabled)
++{
++ struct at32_sm *sm = &system_manager;
++ unsigned long flags;
++ u32 mask;
++
++ spin_lock_irqsave(&sm->lock, flags);
++ mask = sm_readl(sm, PM_PBB_MASK);
++ if (enabled)
++ mask |= 1 << clk->index;
++ else
++ mask &= ~(1 << clk->index);
++ sm_writel(sm, PM_PBB_MASK, mask);
++ spin_unlock_irqrestore(&sm->lock, flags);
++}
++
++static unsigned long pbb_clk_get_rate(struct clk *clk)
++{
++ unsigned long cksel, shift = 0;
++
++ cksel = sm_readl(&system_manager, PM_CKSEL);
++ if (cksel & SM_BIT(PBBDIV))
++ shift = SM_BFEXT(PBBSEL, cksel) + 1;
++
++ return bus_clk_get_rate(clk, shift);
++}
++
++static struct clk cpu_clk = {
++ .name = "cpu",
++ .get_rate = cpu_clk_get_rate,
++ .users = 1,
++};
++static struct clk hsb_clk = {
++ .name = "hsb",
++ .parent = &cpu_clk,
++ .get_rate = hsb_clk_get_rate,
++};
++static struct clk pba_clk = {
++ .name = "pba",
++ .parent = &hsb_clk,
++ .mode = hsb_clk_mode,
++ .get_rate = pba_clk_get_rate,
++ .index = 1,
++};
++static struct clk pbb_clk = {
++ .name = "pbb",
++ .parent = &hsb_clk,
++ .mode = hsb_clk_mode,
++ .get_rate = pbb_clk_get_rate,
++ .users = 1,
++ .index = 2,
++};
++
++/* --------------------------------------------------------------------
++ * Generic Clock operations
++ * -------------------------------------------------------------------- */
++
++static void genclk_mode(struct clk *clk, int enabled)
++{
++ u32 control;
++
++ BUG_ON(clk->index > 7);
++
++ control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
++ if (enabled)
++ control |= SM_BIT(CEN);
++ else
++ control &= ~SM_BIT(CEN);
++ sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
++}
++
++static unsigned long genclk_get_rate(struct clk *clk)
++{
++ u32 control;
++ unsigned long div = 1;
++
++ BUG_ON(clk->index > 7);
++
++ if (!clk->parent)
++ return 0;
++
++ control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
++ if (control & SM_BIT(DIVEN))
++ div = 2 * (SM_BFEXT(DIV, control) + 1);
++
++ return clk->parent->get_rate(clk->parent) / div;
++}
++
++static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
++{
++ u32 control;
++ unsigned long parent_rate, actual_rate, div;
++
++ BUG_ON(clk->index > 7);
++
++ if (!clk->parent)
++ return 0;
++
++ parent_rate = clk->parent->get_rate(clk->parent);
++ control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
++
++ if (rate > 3 * parent_rate / 4) {
++ actual_rate = parent_rate;
++ control &= ~SM_BIT(DIVEN);
++ } else {
++ div = (parent_rate + rate) / (2 * rate) - 1;
++ control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
++ actual_rate = parent_rate / (2 * (div + 1));
++ }
++
++ printk("clk %s: new rate %lu (actual rate %lu)\n",
++ clk->name, rate, actual_rate);
++
++ if (apply)
++ sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
++ control);
++
++ return actual_rate;
++}
++
++int genclk_set_parent(struct clk *clk, struct clk *parent)
++{
++ u32 control;
++
++ BUG_ON(clk->index > 7);
++
++ printk("clk %s: new parent %s (was %s)\n",
++ clk->name, parent->name,
++ clk->parent ? clk->parent->name : "(null)");
++
++ control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
++
++ if (parent == &osc1 || parent == &pll1)
++ control |= SM_BIT(OSCSEL);
++ else if (parent == &osc0 || parent == &pll0)
++ control &= ~SM_BIT(OSCSEL);
++ else
++ return -EINVAL;
++
++ if (parent == &pll0 || parent == &pll1)
++ control |= SM_BIT(PLLSEL);
++ else
++ control &= ~SM_BIT(PLLSEL);
++
++ sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
++ clk->parent = parent;
++
++ return 0;
++}
++
++/* --------------------------------------------------------------------
++ * System peripherals
++ * -------------------------------------------------------------------- */
++static struct resource sm_resource[] = {
++ PBMEM(0xfff00000),
++ NAMED_IRQ(19, "eim"),
++ NAMED_IRQ(20, "pm"),
++ NAMED_IRQ(21, "rtc"),
++};
++struct platform_device at32_sm_device = {
++ .name = "sm",
++ .id = 0,
++ .resource = sm_resource,
++ .num_resources = ARRAY_SIZE(sm_resource),
++};
++DEV_CLK(pclk, at32_sm, pbb, 0);
++
++static struct resource intc0_resource[] = {
++ PBMEM(0xfff00400),
++};
++struct platform_device at32_intc0_device = {
++ .name = "intc",
++ .id = 0,
++ .resource = intc0_resource,
++ .num_resources = ARRAY_SIZE(intc0_resource),
++};
++DEV_CLK(pclk, at32_intc0, pbb, 1);
++
++static struct clk ebi_clk = {
++ .name = "ebi",
++ .parent = &hsb_clk,
++ .mode = hsb_clk_mode,
++ .get_rate = hsb_clk_get_rate,
++ .users = 1,
++};
++static struct clk hramc_clk = {
++ .name = "hramc",
++ .parent = &hsb_clk,
++ .mode = hsb_clk_mode,
++ .get_rate = hsb_clk_get_rate,
++ .users = 1,
++};
++
++static struct resource smc0_resource[] = {
++ PBMEM(0xfff03400),
++};
++DEFINE_DEV(smc, 0);
++DEV_CLK(pclk, smc0, pbb, 13);
++DEV_CLK(mck, smc0, hsb, 0);
++
++static struct platform_device pdc_device = {
++ .name = "pdc",
++ .id = 0,
++};
++DEV_CLK(hclk, pdc, hsb, 4);
++DEV_CLK(pclk, pdc, pba, 16);
++
++static struct clk pico_clk = {
++ .name = "pico",
++ .parent = &cpu_clk,
++ .mode = cpu_clk_mode,
++ .get_rate = cpu_clk_get_rate,
++ .users = 1,
++};
++
++/* --------------------------------------------------------------------
++ * PIO
++ * -------------------------------------------------------------------- */
++
++static struct resource pio0_resource[] = {
++ PBMEM(0xffe02800),
++ IRQ(13),
++};
++DEFINE_DEV(pio, 0);
++DEV_CLK(mck, pio0, pba, 10);
++
++static struct resource pio1_resource[] = {
++ PBMEM(0xffe02c00),
++ IRQ(14),
++};
++DEFINE_DEV(pio, 1);
++DEV_CLK(mck, pio1, pba, 11);
++
++static struct resource pio2_resource[] = {
++ PBMEM(0xffe03000),
++ IRQ(15),
++};
++DEFINE_DEV(pio, 2);
++DEV_CLK(mck, pio2, pba, 12);
++
++static struct resource pio3_resource[] = {
++ PBMEM(0xffe03400),
++ IRQ(16),
++};
++DEFINE_DEV(pio, 3);
++DEV_CLK(mck, pio3, pba, 13);
++
++void __init at32_add_system_devices(void)
++{
++ system_manager.eim_first_irq = NR_INTERNAL_IRQS;
++
++ platform_device_register(&at32_sm_device);
++ platform_device_register(&at32_intc0_device);
++ platform_device_register(&smc0_device);
++ platform_device_register(&pdc_device);
++
++ platform_device_register(&pio0_device);
++ platform_device_register(&pio1_device);
++ platform_device_register(&pio2_device);
++ platform_device_register(&pio3_device);
++}
++
++/* --------------------------------------------------------------------
++ * USART
++ * -------------------------------------------------------------------- */
++
++static struct atmel_uart_data atmel_usart0_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++static struct resource atmel_usart0_resource[] = {
++ PBMEM(0xffe00c00),
++ IRQ(7),
++};
++DEFINE_DEV_DATA(atmel_usart, 0);
++DEV_CLK(usart, atmel_usart0, pba, 4);
++
++static struct atmel_uart_data atmel_usart1_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++static struct resource atmel_usart1_resource[] = {
++ PBMEM(0xffe01000),
++ IRQ(7),
++};
++DEFINE_DEV_DATA(atmel_usart, 1);
++DEV_CLK(usart, atmel_usart1, pba, 4);
++
++static struct atmel_uart_data atmel_usart2_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++static struct resource atmel_usart2_resource[] = {
++ PBMEM(0xffe01400),
++ IRQ(8),
++};
++DEFINE_DEV_DATA(atmel_usart, 2);
++DEV_CLK(usart, atmel_usart2, pba, 5);
++
++static struct atmel_uart_data atmel_usart3_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++static struct resource atmel_usart3_resource[] = {
++ PBMEM(0xffe01800),
++ IRQ(9),
++};
++DEFINE_DEV_DATA(atmel_usart, 3);
++DEV_CLK(usart, atmel_usart3, pba, 6);
++
++static inline void configure_usart0_pins(void)
++{
++ portmux_set_func(PIOA, 8, FUNC_B); /* RXD */
++ portmux_set_func(PIOA, 9, FUNC_B); /* TXD */
++}
++
++static inline void configure_usart1_pins(void)
++{
++ portmux_set_func(PIOA, 17, FUNC_A); /* RXD */
++ portmux_set_func(PIOA, 18, FUNC_A); /* TXD */
++}
++
++static inline void configure_usart2_pins(void)
++{
++ portmux_set_func(PIOB, 26, FUNC_B); /* RXD */
++ portmux_set_func(PIOB, 27, FUNC_B); /* TXD */
++}
++
++static inline void configure_usart3_pins(void)
++{
++ portmux_set_func(PIOB, 18, FUNC_B); /* RXD */
++ portmux_set_func(PIOB, 17, FUNC_B); /* TXD */
++}
++
++static struct platform_device *at32_usarts[4];
++
++void __init at32_map_usart(unsigned int hw_id, unsigned int line)
++{
++ struct platform_device *pdev;
++
++ switch (hw_id) {
++ case 0:
++ pdev = &atmel_usart0_device;
++ configure_usart0_pins();
++ break;
++ case 1:
++ pdev = &atmel_usart1_device;
++ configure_usart1_pins();
++ break;
++ case 2:
++ pdev = &atmel_usart2_device;
++ configure_usart2_pins();
++ break;
++ case 3:
++ pdev = &atmel_usart3_device;
++ configure_usart3_pins();
++ break;
++ default:
++ return;
++ }
++
++ if (PXSEG(pdev->resource[0].start) == P4SEG) {
++ /* Addresses in the P4 segment are permanently mapped 1:1 */
++ struct atmel_uart_data *data = pdev->dev.platform_data;
++ data->regs = (void __iomem *)pdev->resource[0].start;
++ }
++
++ pdev->id = line;
++ at32_usarts[line] = pdev;
++}
++
++struct platform_device *__init at32_add_device_usart(unsigned int id)
++{
++ platform_device_register(at32_usarts[id]);
++ return at32_usarts[id];
++}
++
++struct platform_device *atmel_default_console_device;
++
++void __init at32_setup_serial_console(unsigned int usart_id)
++{
++ atmel_default_console_device = at32_usarts[usart_id];
++}
++
++/* --------------------------------------------------------------------
++ * Ethernet
++ * -------------------------------------------------------------------- */
++
++static struct eth_platform_data macb0_data;
++static struct resource macb0_resource[] = {
++ PBMEM(0xfff01800),
++ IRQ(25),
++};
++DEFINE_DEV_DATA(macb, 0);
++DEV_CLK(hclk, macb0, hsb, 8);
++DEV_CLK(pclk, macb0, pbb, 6);
++
++struct platform_device *__init
++at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
++{
++ struct platform_device *pdev;
++
++ switch (id) {
++ case 0:
++ pdev = &macb0_device;
++
++ portmux_set_func(PIOC, 3, FUNC_A); /* TXD0 */
++ portmux_set_func(PIOC, 4, FUNC_A); /* TXD1 */
++ portmux_set_func(PIOC, 7, FUNC_A); /* TXEN */
++ portmux_set_func(PIOC, 8, FUNC_A); /* TXCK */
++ portmux_set_func(PIOC, 9, FUNC_A); /* RXD0 */
++ portmux_set_func(PIOC, 10, FUNC_A); /* RXD1 */
++ portmux_set_func(PIOC, 13, FUNC_A); /* RXER */
++ portmux_set_func(PIOC, 15, FUNC_A); /* RXDV */
++ portmux_set_func(PIOC, 16, FUNC_A); /* MDC */
++ portmux_set_func(PIOC, 17, FUNC_A); /* MDIO */
++
++ if (!data->is_rmii) {
++ portmux_set_func(PIOC, 0, FUNC_A); /* COL */
++ portmux_set_func(PIOC, 1, FUNC_A); /* CRS */
++ portmux_set_func(PIOC, 2, FUNC_A); /* TXER */
++ portmux_set_func(PIOC, 5, FUNC_A); /* TXD2 */
++ portmux_set_func(PIOC, 6, FUNC_A); /* TXD3 */
++ portmux_set_func(PIOC, 11, FUNC_A); /* RXD2 */
++ portmux_set_func(PIOC, 12, FUNC_A); /* RXD3 */
++ portmux_set_func(PIOC, 14, FUNC_A); /* RXCK */
++ portmux_set_func(PIOC, 18, FUNC_A); /* SPD */
++ }
++ break;
++
++ default:
++ return NULL;
++ }
++
++ memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
++ platform_device_register(pdev);
++
++ return pdev;
++}
++
++/* --------------------------------------------------------------------
++ * SPI
++ * -------------------------------------------------------------------- */
++static struct resource spi0_resource[] = {
++ PBMEM(0xffe00000),
++ IRQ(3),
++};
++DEFINE_DEV(spi, 0);
++DEV_CLK(mck, spi0, pba, 0);
++
++struct platform_device *__init at32_add_device_spi(unsigned int id)
++{
++ struct platform_device *pdev;
++
++ switch (id) {
++ case 0:
++ pdev = &spi0_device;
++ portmux_set_func(PIOA, 0, FUNC_A); /* MISO */
++ portmux_set_func(PIOA, 1, FUNC_A); /* MOSI */
++ portmux_set_func(PIOA, 2, FUNC_A); /* SCK */
++ portmux_set_func(PIOA, 3, FUNC_A); /* NPCS0 */
++ portmux_set_func(PIOA, 4, FUNC_A); /* NPCS1 */
++ portmux_set_func(PIOA, 5, FUNC_A); /* NPCS2 */
++ break;
++
++ default:
++ return NULL;
++ }
++
++ platform_device_register(pdev);
++ return pdev;
++}
++
++/* --------------------------------------------------------------------
++ * LCDC
++ * -------------------------------------------------------------------- */
++static struct lcdc_platform_data lcdc0_data;
++static struct resource lcdc0_resource[] = {
++ {
++ .start = 0xff000000,
++ .end = 0xff000fff,
++ .flags = IORESOURCE_MEM,
++ },
++ IRQ(1),
++};
++DEFINE_DEV_DATA(lcdc, 0);
++DEV_CLK(hclk, lcdc0, hsb, 7);
++static struct clk lcdc0_pixclk = {
++ .name = "pixclk",
++ .dev = &lcdc0_device.dev,
++ .mode = genclk_mode,
++ .get_rate = genclk_get_rate,
++ .set_rate = genclk_set_rate,
++ .set_parent = genclk_set_parent,
++ .index = 7,
++};
++
++struct platform_device *__init
++at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
++{
++ struct platform_device *pdev;
++
++ switch (id) {
++ case 0:
++ pdev = &lcdc0_device;
++ portmux_set_func(PIOC, 19, FUNC_A); /* CC */
++ portmux_set_func(PIOC, 20, FUNC_A); /* HSYNC */
++ portmux_set_func(PIOC, 21, FUNC_A); /* PCLK */
++ portmux_set_func(PIOC, 22, FUNC_A); /* VSYNC */
++ portmux_set_func(PIOC, 23, FUNC_A); /* DVAL */
++ portmux_set_func(PIOC, 24, FUNC_A); /* MODE */
++ portmux_set_func(PIOC, 25, FUNC_A); /* PWR */
++ portmux_set_func(PIOC, 26, FUNC_A); /* DATA0 */
++ portmux_set_func(PIOC, 27, FUNC_A); /* DATA1 */
++ portmux_set_func(PIOC, 28, FUNC_A); /* DATA2 */
++ portmux_set_func(PIOC, 29, FUNC_A); /* DATA3 */
++ portmux_set_func(PIOC, 30, FUNC_A); /* DATA4 */
++ portmux_set_func(PIOC, 31, FUNC_A); /* DATA5 */
++ portmux_set_func(PIOD, 0, FUNC_A); /* DATA6 */
++ portmux_set_func(PIOD, 1, FUNC_A); /* DATA7 */
++ portmux_set_func(PIOD, 2, FUNC_A); /* DATA8 */
++ portmux_set_func(PIOD, 3, FUNC_A); /* DATA9 */
++ portmux_set_func(PIOD, 4, FUNC_A); /* DATA10 */
++ portmux_set_func(PIOD, 5, FUNC_A); /* DATA11 */
++ portmux_set_func(PIOD, 6, FUNC_A); /* DATA12 */
++ portmux_set_func(PIOD, 7, FUNC_A); /* DATA13 */
++ portmux_set_func(PIOD, 8, FUNC_A); /* DATA14 */
++ portmux_set_func(PIOD, 9, FUNC_A); /* DATA15 */
++ portmux_set_func(PIOD, 10, FUNC_A); /* DATA16 */
++ portmux_set_func(PIOD, 11, FUNC_A); /* DATA17 */
++ portmux_set_func(PIOD, 12, FUNC_A); /* DATA18 */
++ portmux_set_func(PIOD, 13, FUNC_A); /* DATA19 */
++ portmux_set_func(PIOD, 14, FUNC_A); /* DATA20 */
++ portmux_set_func(PIOD, 15, FUNC_A); /* DATA21 */
++ portmux_set_func(PIOD, 16, FUNC_A); /* DATA22 */
++ portmux_set_func(PIOD, 17, FUNC_A); /* DATA23 */
++
++ clk_set_parent(&lcdc0_pixclk, &pll0);
++ clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
++ break;
++
++ default:
++ return NULL;
++ }
++
++ memcpy(pdev->dev.platform_data, data,
++ sizeof(struct lcdc_platform_data));
++
++ platform_device_register(pdev);
++ return pdev;
++}
++
++struct clk *at32_clock_list[] = {
++ &osc32k,
++ &osc0,
++ &osc1,
++ &pll0,
++ &pll1,
++ &cpu_clk,
++ &hsb_clk,
++ &pba_clk,
++ &pbb_clk,
++ &at32_sm_pclk,
++ &at32_intc0_pclk,
++ &ebi_clk,
++ &hramc_clk,
++ &smc0_pclk,
++ &smc0_mck,
++ &pdc_hclk,
++ &pdc_pclk,
++ &pico_clk,
++ &pio0_mck,
++ &pio1_mck,
++ &pio2_mck,
++ &pio3_mck,
++ &atmel_usart0_usart,
++ &atmel_usart1_usart,
++ &atmel_usart2_usart,
++ &atmel_usart3_usart,
++ &macb0_hclk,
++ &macb0_pclk,
++ &spi0_mck,
++ &lcdc0_hclk,
++ &lcdc0_pixclk,
++};
++unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
++
++void __init at32_portmux_init(void)
++{
++ at32_init_pio(&pio0_device);
++ at32_init_pio(&pio1_device);
++ at32_init_pio(&pio2_device);
++ at32_init_pio(&pio3_device);
++}
++
++void __init at32_clock_init(void)
++{
++ struct at32_sm *sm = &system_manager;
++ u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
++ int i;
++
++ if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
++ main_clock = &pll0;
++ else
++ main_clock = &osc0;
++
++ if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
++ pll0.parent = &osc1;
++ if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
++ pll1.parent = &osc1;
++
++ /*
++ * Turn on all clocks that have at least one user already, and
++ * turn off everything else. We only do this for module
++ * clocks, and even though it isn't particularly pretty to
++ * check the address of the mode function, it should do the
++ * trick...
++ */
++ for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
++ struct clk *clk = at32_clock_list[i];
++
++ if (clk->mode == &cpu_clk_mode)
++ cpu_mask |= 1 << clk->index;
++ else if (clk->mode == &hsb_clk_mode)
++ hsb_mask |= 1 << clk->index;
++ else if (clk->mode == &pba_clk_mode)
++ pba_mask |= 1 << clk->index;
++ else if (clk->mode == &pbb_clk_mode)
++ pbb_mask |= 1 << clk->index;
++ }
++
++ sm_writel(sm, PM_CPU_MASK, cpu_mask);
++ sm_writel(sm, PM_HSB_MASK, hsb_mask);
++ sm_writel(sm, PM_PBA_MASK, pba_mask);
++ sm_writel(sm, PM_PBB_MASK, pbb_mask);
++}
+diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
+new file mode 100644
+index 0000000..3d0d109
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/clock.c
+@@ -0,0 +1,148 @@
++/*
++ * Clock management for AT32AP CPUs
++ *
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * Based on arch/arm/mach-at91rm9200/clock.c
++ * Copyright (C) 2005 David Brownell
++ * Copyright (C) 2005 Ivan Kokshaysky
++ *
++ * 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/clk.h>
++#include <linux/err.h>
++#include <linux/device.h>
++#include <linux/string.h>
++
++#include "clock.h"
++
++static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED;
++
++struct clk *clk_get(struct device *dev, const char *id)
++{
++ int i;
++
++ for (i = 0; i < at32_nr_clocks; i++) {
++ struct clk *clk = at32_clock_list[i];
++
++ if (clk->dev == dev && strcmp(id, clk->name) == 0)
++ return clk;
++ }
++
++ return ERR_PTR(-ENOENT);
++}
++EXPORT_SYMBOL(clk_get);
++
++void clk_put(struct clk *clk)
++{
++ /* clocks are static for now, we can't free them */
++}
++EXPORT_SYMBOL(clk_put);
++
++static void __clk_enable(struct clk *clk)
++{
++ if (clk->parent)
++ __clk_enable(clk->parent);
++ if (clk->users++ == 0 && clk->mode)
++ clk->mode(clk, 1);
++}
++
++int clk_enable(struct clk *clk)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&clk_lock, flags);
++ __clk_enable(clk);
++ spin_unlock_irqrestore(&clk_lock, flags);
++
++ return 0;
++}
++EXPORT_SYMBOL(clk_enable);
++
++static void __clk_disable(struct clk *clk)
++{
++ BUG_ON(clk->users == 0);
++
++ if (--clk->users == 0 && clk->mode)
++ clk->mode(clk, 0);
++ if (clk->parent)
++ __clk_disable(clk->parent);
++}
++
++void clk_disable(struct clk *clk)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&clk_lock, flags);
++ __clk_disable(clk);
++ spin_unlock_irqrestore(&clk_lock, flags);
++}
++EXPORT_SYMBOL(clk_disable);
++
++unsigned long clk_get_rate(struct clk *clk)
++{
++ unsigned long flags;
++ unsigned long rate;
++
++ spin_lock_irqsave(&clk_lock, flags);
++ rate = clk->get_rate(clk);
++ spin_unlock_irqrestore(&clk_lock, flags);
++
++ return rate;
++}
++EXPORT_SYMBOL(clk_get_rate);
++
++long clk_round_rate(struct clk *clk, unsigned long rate)
++{
++ unsigned long flags, actual_rate;
++
++ if (!clk->set_rate)
++ return -ENOSYS;
++
++ spin_lock_irqsave(&clk_lock, flags);
++ actual_rate = clk->set_rate(clk, rate, 0);
++ spin_unlock_irqrestore(&clk_lock, flags);
++
++ return actual_rate;
++}
++EXPORT_SYMBOL(clk_round_rate);
++
++int clk_set_rate(struct clk *clk, unsigned long rate)
++{
++ unsigned long flags;
++ long ret;
++
++ if (!clk->set_rate)
++ return -ENOSYS;
++
++ spin_lock_irqsave(&clk_lock, flags);
++ ret = clk->set_rate(clk, rate, 1);
++ spin_unlock_irqrestore(&clk_lock, flags);
++
++ return (ret < 0) ? ret : 0;
++}
++EXPORT_SYMBOL(clk_set_rate);
++
++int clk_set_parent(struct clk *clk, struct clk *parent)
++{
++ unsigned long flags;
++ int ret;
++
++ if (!clk->set_parent)
++ return -ENOSYS;
++
++ spin_lock_irqsave(&clk_lock, flags);
++ ret = clk->set_parent(clk, parent);
++ spin_unlock_irqrestore(&clk_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(clk_set_parent);
++
++struct clk *clk_get_parent(struct clk *clk)
++{
++ return clk->parent;
++}
++EXPORT_SYMBOL(clk_get_parent);
+diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h
+new file mode 100644
+index 0000000..f953f04
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/clock.h
+@@ -0,0 +1,30 @@
++/*
++ * Clock management for AT32AP CPUs
++ *
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * Based on arch/arm/mach-at91rm9200/clock.c
++ * Copyright (C) 2005 David Brownell
++ * Copyright (C) 2005 Ivan Kokshaysky
++ *
++ * 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/clk.h>
++
++struct clk {
++ const char *name; /* Clock name/function */
++ struct device *dev; /* Device the clock is used by */
++ struct clk *parent; /* Parent clock, if any */
++ void (*mode)(struct clk *clk, int enabled);
++ unsigned long (*get_rate)(struct clk *clk);
++ long (*set_rate)(struct clk *clk, unsigned long rate,
++ int apply);
++ int (*set_parent)(struct clk *clk, struct clk *parent);
++ u16 users; /* Enabled if non-zero */
++ u16 index; /* Sibling index */
++};
++
++extern struct clk *at32_clock_list[];
++extern unsigned int at32_nr_clocks;
+diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
+new file mode 100644
+index 0000000..4dff1f9
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/extint.c
+@@ -0,0 +1,170 @@
++/*
++ * External interrupt handling for AT32AP CPUs
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/platform_device.h>
++#include <linux/random.h>
++
++#include <asm/io.h>
++
++#include <asm/arch/sm.h>
++
++#include "sm.h"
++
++static void eim_ack_irq(unsigned int irq)
++{
++ struct at32_sm *sm = get_irq_chip_data(irq);
++ sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
++}
++
++static void eim_mask_irq(unsigned int irq)
++{
++ struct at32_sm *sm = get_irq_chip_data(irq);
++ sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
++}
++
++static void eim_mask_ack_irq(unsigned int irq)
++{
++ struct at32_sm *sm = get_irq_chip_data(irq);
++ sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
++ sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
++}
++
++static void eim_unmask_irq(unsigned int irq)
++{
++ struct at32_sm *sm = get_irq_chip_data(irq);
++ sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
++}
++
++static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
++{
++ struct at32_sm *sm = get_irq_chip_data(irq);
++ unsigned int i = irq - sm->eim_first_irq;
++ u32 mode, edge, level;
++ unsigned long flags;
++ int ret = 0;
++
++ flow_type &= IRQ_TYPE_SENSE_MASK;
++
++ spin_lock_irqsave(&sm->lock, flags);
++
++ mode = sm_readl(sm, EIM_MODE);
++ edge = sm_readl(sm, EIM_EDGE);
++ level = sm_readl(sm, EIM_LEVEL);
++
++ switch (flow_type) {
++ case IRQ_TYPE_LEVEL_LOW:
++ mode |= 1 << i;
++ level &= ~(1 << i);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ mode |= 1 << i;
++ level |= 1 << i;
++ break;
++ case IRQ_TYPE_EDGE_RISING:
++ mode &= ~(1 << i);
++ edge |= 1 << i;
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ mode &= ~(1 << i);
++ edge &= ~(1 << i);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ sm_writel(sm, EIM_MODE, mode);
++ sm_writel(sm, EIM_EDGE, edge);
++ sm_writel(sm, EIM_LEVEL, level);
++
++ spin_unlock_irqrestore(&sm->lock, flags);
++
++ return ret;
++}
++
++struct irq_chip eim_chip = {
++ .name = "eim",
++ .ack = eim_ack_irq,
++ .mask = eim_mask_irq,
++ .mask_ack = eim_mask_ack_irq,
++ .unmask = eim_unmask_irq,
++ .set_type = eim_set_irq_type,
++};
++
++static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
++{
++ struct at32_sm *sm = desc->handler_data;
++ struct irq_desc *ext_desc;
++ unsigned long status, pending;
++ unsigned int i, ext_irq;
++
++ spin_lock(&sm->lock);
++
++ status = sm_readl(sm, EIM_ISR);
++ pending = status & sm_readl(sm, EIM_IMR);
++
++ while (pending) {
++ i = fls(pending) - 1;
++ pending &= ~(1 << i);
++
++ ext_irq = i + sm->eim_first_irq;
++ ext_desc = irq_desc + ext_irq;
++ ext_desc->handle_irq(ext_irq, ext_desc);
++ }
++
++ spin_unlock(&sm->lock);
++}
++
++static int __init eim_init(void)
++{
++ struct at32_sm *sm = &system_manager;
++ unsigned int i;
++ unsigned int nr_irqs;
++ unsigned int int_irq;
++ u32 pattern;
++
++ /*
++ * The EIM is really the same module as SM, so register
++ * mapping, etc. has been taken care of already.
++ */
++
++ /*
++ * Find out how many interrupt lines that are actually
++ * implemented in hardware.
++ */
++ sm_writel(sm, EIM_IDR, ~0UL);
++ sm_writel(sm, EIM_MODE, ~0UL);
++ pattern = sm_readl(sm, EIM_MODE);
++ nr_irqs = fls(pattern);
++
++ sm->eim_chip = &eim_chip;
++
++ for (i = 0; i < nr_irqs; i++) {
++ set_irq_chip(sm->eim_first_irq + i, &eim_chip);
++ set_irq_chip_data(sm->eim_first_irq + i, sm);
++ }
++
++ int_irq = platform_get_irq_byname(sm->pdev, "eim");
++
++ set_irq_chained_handler(int_irq, demux_eim_irq);
++ set_irq_data(int_irq, sm);
++
++ printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
++ sm->regs, int_irq);
++ printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
++ nr_irqs, sm->eim_first_irq);
++
++ return 0;
++}
++arch_initcall(eim_init);
+diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c
+new file mode 100644
+index 0000000..7691721
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/hsmc.c
+@@ -0,0 +1,164 @@
++/*
++ * Static Memory Controller for AT32 chips
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++#define DEBUG
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++#include <asm/arch/smc.h>
++
++#include "hsmc.h"
++
++#define NR_CHIP_SELECTS 6
++
++struct hsmc {
++ void __iomem *regs;
++ struct clk *pclk;
++ struct clk *mck;
++};
++
++static struct hsmc *hsmc;
++
++int smc_set_configuration(int cs, const struct smc_config *config)
++{
++ unsigned long mul;
++ unsigned long offset;
++ u32 setup, pulse, cycle, mode;
++
++ if (!hsmc)
++ return -ENODEV;
++ if (cs >= NR_CHIP_SELECTS)
++ return -EINVAL;
++
++ /*
++ * cycles = x / T = x * f
++ * = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536
++ * = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536
++ */
++ mul = (clk_get_rate(hsmc->mck) / 10000) << 16;
++ mul /= 100000;
++
++#define ns2cyc(x) ((((x) * mul) + 65535) >> 16)
++
++ setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup))
++ | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup))
++ | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup))
++ | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup)));
++ pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse))
++ | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse))
++ | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse))
++ | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse)));
++ cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle))
++ | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle)));
++
++ switch (config->bus_width) {
++ case 1:
++ mode = HSMC_BF(DBW, HSMC_DBW_8_BITS);
++ break;
++ case 2:
++ mode = HSMC_BF(DBW, HSMC_DBW_16_BITS);
++ break;
++ case 4:
++ mode = HSMC_BF(DBW, HSMC_DBW_32_BITS);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (config->nrd_controlled)
++ mode |= HSMC_BIT(READ_MODE);
++ if (config->nwe_controlled)
++ mode |= HSMC_BIT(WRITE_MODE);
++ if (config->byte_write)
++ mode |= HSMC_BIT(BAT);
++
++ pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
++ cs, setup, pulse, cycle, mode);
++
++ offset = cs * 0x10;
++ hsmc_writel(hsmc, SETUP0 + offset, setup);
++ hsmc_writel(hsmc, PULSE0 + offset, pulse);
++ hsmc_writel(hsmc, CYCLE0 + offset, cycle);
++ hsmc_writel(hsmc, MODE0 + offset, mode);
++ hsmc_readl(hsmc, MODE0); /* I/O barrier */
++
++ return 0;
++}
++EXPORT_SYMBOL(smc_set_configuration);
++
++static int hsmc_probe(struct platform_device *pdev)
++{
++ struct resource *regs;
++ struct clk *pclk, *mck;
++ int ret;
++
++ if (hsmc)
++ return -EBUSY;
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs)
++ return -ENXIO;
++ pclk = clk_get(&pdev->dev, "pclk");
++ if (IS_ERR(pclk))
++ return PTR_ERR(pclk);
++ mck = clk_get(&pdev->dev, "mck");
++ if (IS_ERR(mck)) {
++ ret = PTR_ERR(mck);
++ goto out_put_pclk;
++ }
++
++ ret = -ENOMEM;
++ hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL);
++ if (!hsmc)
++ goto out_put_clocks;
++
++ clk_enable(pclk);
++ clk_enable(mck);
++
++ hsmc->pclk = pclk;
++ hsmc->mck = mck;
++ hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!hsmc->regs)
++ goto out_disable_clocks;
++
++ dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n",
++ (unsigned long)regs->start);
++
++ platform_set_drvdata(pdev, hsmc);
++
++ return 0;
++
++out_disable_clocks:
++ clk_disable(mck);
++ clk_disable(pclk);
++ kfree(hsmc);
++out_put_clocks:
++ clk_put(mck);
++out_put_pclk:
++ clk_put(pclk);
++ hsmc = NULL;
++ return ret;
++}
++
++static struct platform_driver hsmc_driver = {
++ .probe = hsmc_probe,
++ .driver = {
++ .name = "smc",
++ },
++};
++
++static int __init hsmc_init(void)
++{
++ return platform_driver_register(&hsmc_driver);
++}
++arch_initcall(hsmc_init);
+diff --git a/arch/avr32/mach-at32ap/hsmc.h b/arch/avr32/mach-at32ap/hsmc.h
+new file mode 100644
+index 0000000..d1d48e2
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/hsmc.h
+@@ -0,0 +1,127 @@
++/*
++ * Register definitions for Atmel Static Memory Controller (SMC)
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_HSMC_H__
++#define __ASM_AVR32_HSMC_H__
++
++/* HSMC register offsets */
++#define HSMC_SETUP0 0x0000
++#define HSMC_PULSE0 0x0004
++#define HSMC_CYCLE0 0x0008
++#define HSMC_MODE0 0x000c
++#define HSMC_SETUP1 0x0010
++#define HSMC_PULSE1 0x0014
++#define HSMC_CYCLE1 0x0018
++#define HSMC_MODE1 0x001c
++#define HSMC_SETUP2 0x0020
++#define HSMC_PULSE2 0x0024
++#define HSMC_CYCLE2 0x0028
++#define HSMC_MODE2 0x002c
++#define HSMC_SETUP3 0x0030
++#define HSMC_PULSE3 0x0034
++#define HSMC_CYCLE3 0x0038
++#define HSMC_MODE3 0x003c
++#define HSMC_SETUP4 0x0040
++#define HSMC_PULSE4 0x0044
++#define HSMC_CYCLE4 0x0048
++#define HSMC_MODE4 0x004c
++#define HSMC_SETUP5 0x0050
++#define HSMC_PULSE5 0x0054
++#define HSMC_CYCLE5 0x0058
++#define HSMC_MODE5 0x005c
++
++/* Bitfields in SETUP0 */
++#define HSMC_NWE_SETUP_OFFSET 0
++#define HSMC_NWE_SETUP_SIZE 6
++#define HSMC_NCS_WR_SETUP_OFFSET 8
++#define HSMC_NCS_WR_SETUP_SIZE 6
++#define HSMC_NRD_SETUP_OFFSET 16
++#define HSMC_NRD_SETUP_SIZE 6
++#define HSMC_NCS_RD_SETUP_OFFSET 24
++#define HSMC_NCS_RD_SETUP_SIZE 6
++
++/* Bitfields in PULSE0 */
++#define HSMC_NWE_PULSE_OFFSET 0
++#define HSMC_NWE_PULSE_SIZE 7
++#define HSMC_NCS_WR_PULSE_OFFSET 8
++#define HSMC_NCS_WR_PULSE_SIZE 7
++#define HSMC_NRD_PULSE_OFFSET 16
++#define HSMC_NRD_PULSE_SIZE 7
++#define HSMC_NCS_RD_PULSE_OFFSET 24
++#define HSMC_NCS_RD_PULSE_SIZE 7
++
++/* Bitfields in CYCLE0 */
++#define HSMC_NWE_CYCLE_OFFSET 0
++#define HSMC_NWE_CYCLE_SIZE 9
++#define HSMC_NRD_CYCLE_OFFSET 16
++#define HSMC_NRD_CYCLE_SIZE 9
++
++/* Bitfields in MODE0 */
++#define HSMC_READ_MODE_OFFSET 0
++#define HSMC_READ_MODE_SIZE 1
++#define HSMC_WRITE_MODE_OFFSET 1
++#define HSMC_WRITE_MODE_SIZE 1
++#define HSMC_EXNW_MODE_OFFSET 4
++#define HSMC_EXNW_MODE_SIZE 2
++#define HSMC_BAT_OFFSET 8
++#define HSMC_BAT_SIZE 1
++#define HSMC_DBW_OFFSET 12
++#define HSMC_DBW_SIZE 2
++#define HSMC_TDF_CYCLES_OFFSET 16
++#define HSMC_TDF_CYCLES_SIZE 4
++#define HSMC_TDF_MODE_OFFSET 20
++#define HSMC_TDF_MODE_SIZE 1
++#define HSMC_PMEN_OFFSET 24
++#define HSMC_PMEN_SIZE 1
++#define HSMC_PS_OFFSET 28
++#define HSMC_PS_SIZE 2
++
++/* Constants for READ_MODE */
++#define HSMC_READ_MODE_NCS_CONTROLLED 0
++#define HSMC_READ_MODE_NRD_CONTROLLED 1
++
++/* Constants for WRITE_MODE */
++#define HSMC_WRITE_MODE_NCS_CONTROLLED 0
++#define HSMC_WRITE_MODE_NWE_CONTROLLED 1
++
++/* Constants for EXNW_MODE */
++#define HSMC_EXNW_MODE_DISABLED 0
++#define HSMC_EXNW_MODE_RESERVED 1
++#define HSMC_EXNW_MODE_FROZEN 2
++#define HSMC_EXNW_MODE_READY 3
++
++/* Constants for BAT */
++#define HSMC_BAT_BYTE_SELECT 0
++#define HSMC_BAT_BYTE_WRITE 1
++
++/* Constants for DBW */
++#define HSMC_DBW_8_BITS 0
++#define HSMC_DBW_16_BITS 1
++#define HSMC_DBW_32_BITS 2
++
++/* Bit manipulation macros */
++#define HSMC_BIT(name) \
++ (1 << HSMC_##name##_OFFSET)
++#define HSMC_BF(name,value) \
++ (((value) & ((1 << HSMC_##name##_SIZE) - 1)) \
++ << HSMC_##name##_OFFSET)
++#define HSMC_BFEXT(name,value) \
++ (((value) >> HSMC_##name##_OFFSET) \
++ & ((1 << HSMC_##name##_SIZE) - 1))
++#define HSMC_BFINS(name,value,old) \
++ (((old) & ~(((1 << HSMC_##name##_SIZE) - 1) \
++ << HSMC_##name##_OFFSET)) | HSMC_BF(name,value))
++
++/* Register access macros */
++#define hsmc_readl(port,reg) \
++ __raw_readl((port)->regs + HSMC_##reg)
++#define hsmc_writel(port,reg,value) \
++ __raw_writel((value), (port)->regs + HSMC_##reg)
++
++#endif /* __ASM_AVR32_HSMC_H__ */
+diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
+new file mode 100644
+index 0000000..eb87a18
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/intc.c
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2006 Atmel 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.
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++
++#include "intc.h"
++
++struct intc {
++ void __iomem *regs;
++ struct irq_chip chip;
++};
++
++extern struct platform_device at32_intc0_device;
++
++/*
++ * TODO: We may be able to implement mask/unmask by setting IxM flags
++ * in the status register.
++ */
++static void intc_mask_irq(unsigned int irq)
++{
++
++}
++
++static void intc_unmask_irq(unsigned int irq)
++{
++
++}
++
++static struct intc intc0 = {
++ .chip = {
++ .name = "intc",
++ .mask = intc_mask_irq,
++ .unmask = intc_unmask_irq,
++ },
++};
++
++/*
++ * All interrupts go via intc at some point.
++ */
++asmlinkage void do_IRQ(int level, struct pt_regs *regs)
++{
++ struct irq_desc *desc;
++ struct pt_regs *old_regs;
++ unsigned int irq;
++ unsigned long status_reg;
++
++ local_irq_disable();
++
++ old_regs = set_irq_regs(regs);
++
++ irq_enter();
++
++ irq = intc_readl(&intc0, INTCAUSE0 - 4 * level);
++ desc = irq_desc + irq;
++ desc->handle_irq(irq, desc);
++
++ /*
++ * Clear all interrupt level masks so that we may handle
++ * interrupts during softirq processing. If this is a nested
++ * interrupt, interrupts must stay globally disabled until we
++ * return.
++ */
++ status_reg = sysreg_read(SR);
++ status_reg &= ~(SYSREG_BIT(I0M) | SYSREG_BIT(I1M)
++ | SYSREG_BIT(I2M) | SYSREG_BIT(I3M));
++ sysreg_write(SR, status_reg);
++
++ irq_exit();
++
++ set_irq_regs(old_regs);
++}
++
++void __init init_IRQ(void)
++{
++ extern void _evba(void);
++ extern void irq_level0(void);
++ struct resource *regs;
++ struct clk *pclk;
++ unsigned int i;
++ u32 offset, readback;
++
++ regs = platform_get_resource(&at32_intc0_device, IORESOURCE_MEM, 0);
++ if (!regs) {
++ printk(KERN_EMERG "intc: no mmio resource defined\n");
++ goto fail;
++ }
++ pclk = clk_get(&at32_intc0_device.dev, "pclk");
++ if (IS_ERR(pclk)) {
++ printk(KERN_EMERG "intc: no clock defined\n");
++ goto fail;
++ }
++
++ clk_enable(pclk);
++
++ intc0.regs = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!intc0.regs) {
++ printk(KERN_EMERG "intc: failed to map registers (0x%08lx)\n",
++ (unsigned long)regs->start);
++ goto fail;
++ }
++
++ /*
++ * Initialize all interrupts to level 0 (lowest priority). The
++ * priority level may be changed by calling
++ * irq_set_priority().
++ *
++ */
++ offset = (unsigned long)&irq_level0 - (unsigned long)&_evba;
++ for (i = 0; i < NR_INTERNAL_IRQS; i++) {
++ intc_writel(&intc0, INTPR0 + 4 * i, offset);
++ readback = intc_readl(&intc0, INTPR0 + 4 * i);
++ if (readback == offset)
++ set_irq_chip_and_handler(i, &intc0.chip,
++ handle_simple_irq);
++ }
++
++ /* Unmask all interrupt levels */
++ sysreg_write(SR, (sysreg_read(SR)
++ & ~(SR_I3M | SR_I2M | SR_I1M | SR_I0M)));
++
++ return;
++
++fail:
++ panic("Interrupt controller initialization failed!\n");
++}
++
+diff --git a/arch/avr32/mach-at32ap/intc.h b/arch/avr32/mach-at32ap/intc.h
+new file mode 100644
+index 0000000..4d3664e
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/intc.h
+@@ -0,0 +1,329 @@
++/*
++ * Automatically generated by gen-header.xsl
++ */
++#ifndef __ASM_AVR32_PERIHP_INTC_H__
++#define __ASM_AVR32_PERIHP_INTC_H__
++
++#define INTC_NUM_INT_GRPS 33
++
++#define INTC_INTPR0 0x0
++# define INTC_INTPR0_INTLEV_OFFSET 30
++# define INTC_INTPR0_INTLEV_SIZE 2
++# define INTC_INTPR0_OFFSET_OFFSET 0
++# define INTC_INTPR0_OFFSET_SIZE 24
++#define INTC_INTREQ0 0x100
++# define INTC_INTREQ0_IREQUEST0_OFFSET 0
++# define INTC_INTREQ0_IREQUEST0_SIZE 1
++# define INTC_INTREQ0_IREQUEST1_OFFSET 1
++# define INTC_INTREQ0_IREQUEST1_SIZE 1
++#define INTC_INTPR1 0x4
++# define INTC_INTPR1_INTLEV_OFFSET 30
++# define INTC_INTPR1_INTLEV_SIZE 2
++# define INTC_INTPR1_OFFSET_OFFSET 0
++# define INTC_INTPR1_OFFSET_SIZE 24
++#define INTC_INTREQ1 0x104
++# define INTC_INTREQ1_IREQUEST32_OFFSET 0
++# define INTC_INTREQ1_IREQUEST32_SIZE 1
++# define INTC_INTREQ1_IREQUEST33_OFFSET 1
++# define INTC_INTREQ1_IREQUEST33_SIZE 1
++# define INTC_INTREQ1_IREQUEST34_OFFSET 2
++# define INTC_INTREQ1_IREQUEST34_SIZE 1
++# define INTC_INTREQ1_IREQUEST35_OFFSET 3
++# define INTC_INTREQ1_IREQUEST35_SIZE 1
++# define INTC_INTREQ1_IREQUEST36_OFFSET 4
++# define INTC_INTREQ1_IREQUEST36_SIZE 1
++# define INTC_INTREQ1_IREQUEST37_OFFSET 5
++# define INTC_INTREQ1_IREQUEST37_SIZE 1
++#define INTC_INTPR2 0x8
++# define INTC_INTPR2_INTLEV_OFFSET 30
++# define INTC_INTPR2_INTLEV_SIZE 2
++# define INTC_INTPR2_OFFSET_OFFSET 0
++# define INTC_INTPR2_OFFSET_SIZE 24
++#define INTC_INTREQ2 0x108
++# define INTC_INTREQ2_IREQUEST64_OFFSET 0
++# define INTC_INTREQ2_IREQUEST64_SIZE 1
++# define INTC_INTREQ2_IREQUEST65_OFFSET 1
++# define INTC_INTREQ2_IREQUEST65_SIZE 1
++# define INTC_INTREQ2_IREQUEST66_OFFSET 2
++# define INTC_INTREQ2_IREQUEST66_SIZE 1
++# define INTC_INTREQ2_IREQUEST67_OFFSET 3
++# define INTC_INTREQ2_IREQUEST67_SIZE 1
++# define INTC_INTREQ2_IREQUEST68_OFFSET 4
++# define INTC_INTREQ2_IREQUEST68_SIZE 1
++#define INTC_INTPR3 0xc
++# define INTC_INTPR3_INTLEV_OFFSET 30
++# define INTC_INTPR3_INTLEV_SIZE 2
++# define INTC_INTPR3_OFFSET_OFFSET 0
++# define INTC_INTPR3_OFFSET_SIZE 24
++#define INTC_INTREQ3 0x10c
++# define INTC_INTREQ3_IREQUEST96_OFFSET 0
++# define INTC_INTREQ3_IREQUEST96_SIZE 1
++#define INTC_INTPR4 0x10
++# define INTC_INTPR4_INTLEV_OFFSET 30
++# define INTC_INTPR4_INTLEV_SIZE 2
++# define INTC_INTPR4_OFFSET_OFFSET 0
++# define INTC_INTPR4_OFFSET_SIZE 24
++#define INTC_INTREQ4 0x110
++# define INTC_INTREQ4_IREQUEST128_OFFSET 0
++# define INTC_INTREQ4_IREQUEST128_SIZE 1
++#define INTC_INTPR5 0x14
++# define INTC_INTPR5_INTLEV_OFFSET 30
++# define INTC_INTPR5_INTLEV_SIZE 2
++# define INTC_INTPR5_OFFSET_OFFSET 0
++# define INTC_INTPR5_OFFSET_SIZE 24
++#define INTC_INTREQ5 0x114
++# define INTC_INTREQ5_IREQUEST160_OFFSET 0
++# define INTC_INTREQ5_IREQUEST160_SIZE 1
++#define INTC_INTPR6 0x18
++# define INTC_INTPR6_INTLEV_OFFSET 30
++# define INTC_INTPR6_INTLEV_SIZE 2
++# define INTC_INTPR6_OFFSET_OFFSET 0
++# define INTC_INTPR6_OFFSET_SIZE 24
++#define INTC_INTREQ6 0x118
++# define INTC_INTREQ6_IREQUEST192_OFFSET 0
++# define INTC_INTREQ6_IREQUEST192_SIZE 1
++#define INTC_INTPR7 0x1c
++# define INTC_INTPR7_INTLEV_OFFSET 30
++# define INTC_INTPR7_INTLEV_SIZE 2
++# define INTC_INTPR7_OFFSET_OFFSET 0
++# define INTC_INTPR7_OFFSET_SIZE 24
++#define INTC_INTREQ7 0x11c
++# define INTC_INTREQ7_IREQUEST224_OFFSET 0
++# define INTC_INTREQ7_IREQUEST224_SIZE 1
++#define INTC_INTPR8 0x20
++# define INTC_INTPR8_INTLEV_OFFSET 30
++# define INTC_INTPR8_INTLEV_SIZE 2
++# define INTC_INTPR8_OFFSET_OFFSET 0
++# define INTC_INTPR8_OFFSET_SIZE 24
++#define INTC_INTREQ8 0x120
++# define INTC_INTREQ8_IREQUEST256_OFFSET 0
++# define INTC_INTREQ8_IREQUEST256_SIZE 1
++#define INTC_INTPR9 0x24
++# define INTC_INTPR9_INTLEV_OFFSET 30
++# define INTC_INTPR9_INTLEV_SIZE 2
++# define INTC_INTPR9_OFFSET_OFFSET 0
++# define INTC_INTPR9_OFFSET_SIZE 24
++#define INTC_INTREQ9 0x124
++# define INTC_INTREQ9_IREQUEST288_OFFSET 0
++# define INTC_INTREQ9_IREQUEST288_SIZE 1
++#define INTC_INTPR10 0x28
++# define INTC_INTPR10_INTLEV_OFFSET 30
++# define INTC_INTPR10_INTLEV_SIZE 2
++# define INTC_INTPR10_OFFSET_OFFSET 0
++# define INTC_INTPR10_OFFSET_SIZE 24
++#define INTC_INTREQ10 0x128
++# define INTC_INTREQ10_IREQUEST320_OFFSET 0
++# define INTC_INTREQ10_IREQUEST320_SIZE 1
++#define INTC_INTPR11 0x2c
++# define INTC_INTPR11_INTLEV_OFFSET 30
++# define INTC_INTPR11_INTLEV_SIZE 2
++# define INTC_INTPR11_OFFSET_OFFSET 0
++# define INTC_INTPR11_OFFSET_SIZE 24
++#define INTC_INTREQ11 0x12c
++# define INTC_INTREQ11_IREQUEST352_OFFSET 0
++# define INTC_INTREQ11_IREQUEST352_SIZE 1
++#define INTC_INTPR12 0x30
++# define INTC_INTPR12_INTLEV_OFFSET 30
++# define INTC_INTPR12_INTLEV_SIZE 2
++# define INTC_INTPR12_OFFSET_OFFSET 0
++# define INTC_INTPR12_OFFSET_SIZE 24
++#define INTC_INTREQ12 0x130
++# define INTC_INTREQ12_IREQUEST384_OFFSET 0
++# define INTC_INTREQ12_IREQUEST384_SIZE 1
++#define INTC_INTPR13 0x34
++# define INTC_INTPR13_INTLEV_OFFSET 30
++# define INTC_INTPR13_INTLEV_SIZE 2
++# define INTC_INTPR13_OFFSET_OFFSET 0
++# define INTC_INTPR13_OFFSET_SIZE 24
++#define INTC_INTREQ13 0x134
++# define INTC_INTREQ13_IREQUEST416_OFFSET 0
++# define INTC_INTREQ13_IREQUEST416_SIZE 1
++#define INTC_INTPR14 0x38
++# define INTC_INTPR14_INTLEV_OFFSET 30
++# define INTC_INTPR14_INTLEV_SIZE 2
++# define INTC_INTPR14_OFFSET_OFFSET 0
++# define INTC_INTPR14_OFFSET_SIZE 24
++#define INTC_INTREQ14 0x138
++# define INTC_INTREQ14_IREQUEST448_OFFSET 0
++# define INTC_INTREQ14_IREQUEST448_SIZE 1
++#define INTC_INTPR15 0x3c
++# define INTC_INTPR15_INTLEV_OFFSET 30
++# define INTC_INTPR15_INTLEV_SIZE 2
++# define INTC_INTPR15_OFFSET_OFFSET 0
++# define INTC_INTPR15_OFFSET_SIZE 24
++#define INTC_INTREQ15 0x13c
++# define INTC_INTREQ15_IREQUEST480_OFFSET 0
++# define INTC_INTREQ15_IREQUEST480_SIZE 1
++#define INTC_INTPR16 0x40
++# define INTC_INTPR16_INTLEV_OFFSET 30
++# define INTC_INTPR16_INTLEV_SIZE 2
++# define INTC_INTPR16_OFFSET_OFFSET 0
++# define INTC_INTPR16_OFFSET_SIZE 24
++#define INTC_INTREQ16 0x140
++# define INTC_INTREQ16_IREQUEST512_OFFSET 0
++# define INTC_INTREQ16_IREQUEST512_SIZE 1
++#define INTC_INTPR17 0x44
++# define INTC_INTPR17_INTLEV_OFFSET 30
++# define INTC_INTPR17_INTLEV_SIZE 2
++# define INTC_INTPR17_OFFSET_OFFSET 0
++# define INTC_INTPR17_OFFSET_SIZE 24
++#define INTC_INTREQ17 0x144
++# define INTC_INTREQ17_IREQUEST544_OFFSET 0
++# define INTC_INTREQ17_IREQUEST544_SIZE 1
++#define INTC_INTPR18 0x48
++# define INTC_INTPR18_INTLEV_OFFSET 30
++# define INTC_INTPR18_INTLEV_SIZE 2
++# define INTC_INTPR18_OFFSET_OFFSET 0
++# define INTC_INTPR18_OFFSET_SIZE 24
++#define INTC_INTREQ18 0x148
++# define INTC_INTREQ18_IREQUEST576_OFFSET 0
++# define INTC_INTREQ18_IREQUEST576_SIZE 1
++#define INTC_INTPR19 0x4c
++# define INTC_INTPR19_INTLEV_OFFSET 30
++# define INTC_INTPR19_INTLEV_SIZE 2
++# define INTC_INTPR19_OFFSET_OFFSET 0
++# define INTC_INTPR19_OFFSET_SIZE 24
++#define INTC_INTREQ19 0x14c
++# define INTC_INTREQ19_IREQUEST608_OFFSET 0
++# define INTC_INTREQ19_IREQUEST608_SIZE 1
++# define INTC_INTREQ19_IREQUEST609_OFFSET 1
++# define INTC_INTREQ19_IREQUEST609_SIZE 1
++# define INTC_INTREQ19_IREQUEST610_OFFSET 2
++# define INTC_INTREQ19_IREQUEST610_SIZE 1
++# define INTC_INTREQ19_IREQUEST611_OFFSET 3
++# define INTC_INTREQ19_IREQUEST611_SIZE 1
++#define INTC_INTPR20 0x50
++# define INTC_INTPR20_INTLEV_OFFSET 30
++# define INTC_INTPR20_INTLEV_SIZE 2
++# define INTC_INTPR20_OFFSET_OFFSET 0
++# define INTC_INTPR20_OFFSET_SIZE 24
++#define INTC_INTREQ20 0x150
++# define INTC_INTREQ20_IREQUEST640_OFFSET 0
++# define INTC_INTREQ20_IREQUEST640_SIZE 1
++#define INTC_INTPR21 0x54
++# define INTC_INTPR21_INTLEV_OFFSET 30
++# define INTC_INTPR21_INTLEV_SIZE 2
++# define INTC_INTPR21_OFFSET_OFFSET 0
++# define INTC_INTPR21_OFFSET_SIZE 24
++#define INTC_INTREQ21 0x154
++# define INTC_INTREQ21_IREQUEST672_OFFSET 0
++# define INTC_INTREQ21_IREQUEST672_SIZE 1
++#define INTC_INTPR22 0x58
++# define INTC_INTPR22_INTLEV_OFFSET 30
++# define INTC_INTPR22_INTLEV_SIZE 2
++# define INTC_INTPR22_OFFSET_OFFSET 0
++# define INTC_INTPR22_OFFSET_SIZE 24
++#define INTC_INTREQ22 0x158
++# define INTC_INTREQ22_IREQUEST704_OFFSET 0
++# define INTC_INTREQ22_IREQUEST704_SIZE 1
++# define INTC_INTREQ22_IREQUEST705_OFFSET 1
++# define INTC_INTREQ22_IREQUEST705_SIZE 1
++# define INTC_INTREQ22_IREQUEST706_OFFSET 2
++# define INTC_INTREQ22_IREQUEST706_SIZE 1
++#define INTC_INTPR23 0x5c
++# define INTC_INTPR23_INTLEV_OFFSET 30
++# define INTC_INTPR23_INTLEV_SIZE 2
++# define INTC_INTPR23_OFFSET_OFFSET 0
++# define INTC_INTPR23_OFFSET_SIZE 24
++#define INTC_INTREQ23 0x15c
++# define INTC_INTREQ23_IREQUEST736_OFFSET 0
++# define INTC_INTREQ23_IREQUEST736_SIZE 1
++# define INTC_INTREQ23_IREQUEST737_OFFSET 1
++# define INTC_INTREQ23_IREQUEST737_SIZE 1
++# define INTC_INTREQ23_IREQUEST738_OFFSET 2
++# define INTC_INTREQ23_IREQUEST738_SIZE 1
++#define INTC_INTPR24 0x60
++# define INTC_INTPR24_INTLEV_OFFSET 30
++# define INTC_INTPR24_INTLEV_SIZE 2
++# define INTC_INTPR24_OFFSET_OFFSET 0
++# define INTC_INTPR24_OFFSET_SIZE 24
++#define INTC_INTREQ24 0x160
++# define INTC_INTREQ24_IREQUEST768_OFFSET 0
++# define INTC_INTREQ24_IREQUEST768_SIZE 1
++#define INTC_INTPR25 0x64
++# define INTC_INTPR25_INTLEV_OFFSET 30
++# define INTC_INTPR25_INTLEV_SIZE 2
++# define INTC_INTPR25_OFFSET_OFFSET 0
++# define INTC_INTPR25_OFFSET_SIZE 24
++#define INTC_INTREQ25 0x164
++# define INTC_INTREQ25_IREQUEST800_OFFSET 0
++# define INTC_INTREQ25_IREQUEST800_SIZE 1
++#define INTC_INTPR26 0x68
++# define INTC_INTPR26_INTLEV_OFFSET 30
++# define INTC_INTPR26_INTLEV_SIZE 2
++# define INTC_INTPR26_OFFSET_OFFSET 0
++# define INTC_INTPR26_OFFSET_SIZE 24
++#define INTC_INTREQ26 0x168
++# define INTC_INTREQ26_IREQUEST832_OFFSET 0
++# define INTC_INTREQ26_IREQUEST832_SIZE 1
++#define INTC_INTPR27 0x6c
++# define INTC_INTPR27_INTLEV_OFFSET 30
++# define INTC_INTPR27_INTLEV_SIZE 2
++# define INTC_INTPR27_OFFSET_OFFSET 0
++# define INTC_INTPR27_OFFSET_SIZE 24
++#define INTC_INTREQ27 0x16c
++# define INTC_INTREQ27_IREQUEST864_OFFSET 0
++# define INTC_INTREQ27_IREQUEST864_SIZE 1
++#define INTC_INTPR28 0x70
++# define INTC_INTPR28_INTLEV_OFFSET 30
++# define INTC_INTPR28_INTLEV_SIZE 2
++# define INTC_INTPR28_OFFSET_OFFSET 0
++# define INTC_INTPR28_OFFSET_SIZE 24
++#define INTC_INTREQ28 0x170
++# define INTC_INTREQ28_IREQUEST896_OFFSET 0
++# define INTC_INTREQ28_IREQUEST896_SIZE 1
++#define INTC_INTPR29 0x74
++# define INTC_INTPR29_INTLEV_OFFSET 30
++# define INTC_INTPR29_INTLEV_SIZE 2
++# define INTC_INTPR29_OFFSET_OFFSET 0
++# define INTC_INTPR29_OFFSET_SIZE 24
++#define INTC_INTREQ29 0x174
++# define INTC_INTREQ29_IREQUEST928_OFFSET 0
++# define INTC_INTREQ29_IREQUEST928_SIZE 1
++#define INTC_INTPR30 0x78
++# define INTC_INTPR30_INTLEV_OFFSET 30
++# define INTC_INTPR30_INTLEV_SIZE 2
++# define INTC_INTPR30_OFFSET_OFFSET 0
++# define INTC_INTPR30_OFFSET_SIZE 24
++#define INTC_INTREQ30 0x178
++# define INTC_INTREQ30_IREQUEST960_OFFSET 0
++# define INTC_INTREQ30_IREQUEST960_SIZE 1
++#define INTC_INTPR31 0x7c
++# define INTC_INTPR31_INTLEV_OFFSET 30
++# define INTC_INTPR31_INTLEV_SIZE 2
++# define INTC_INTPR31_OFFSET_OFFSET 0
++# define INTC_INTPR31_OFFSET_SIZE 24
++#define INTC_INTREQ31 0x17c
++# define INTC_INTREQ31_IREQUEST992_OFFSET 0
++# define INTC_INTREQ31_IREQUEST992_SIZE 1
++#define INTC_INTPR32 0x80
++# define INTC_INTPR32_INTLEV_OFFSET 30
++# define INTC_INTPR32_INTLEV_SIZE 2
++# define INTC_INTPR32_OFFSET_OFFSET 0
++# define INTC_INTPR32_OFFSET_SIZE 24
++#define INTC_INTREQ32 0x180
++# define INTC_INTREQ32_IREQUEST1024_OFFSET 0
++# define INTC_INTREQ32_IREQUEST1024_SIZE 1
++#define INTC_INTCAUSE0 0x20c
++# define INTC_INTCAUSE0_CAUSEGRP_OFFSET 0
++# define INTC_INTCAUSE0_CAUSEGRP_SIZE 6
++#define INTC_INTCAUSE1 0x208
++# define INTC_INTCAUSE1_CAUSEGRP_OFFSET 0
++# define INTC_INTCAUSE1_CAUSEGRP_SIZE 6
++#define INTC_INTCAUSE2 0x204
++# define INTC_INTCAUSE2_CAUSEGRP_OFFSET 0
++# define INTC_INTCAUSE2_CAUSEGRP_SIZE 6
++#define INTC_INTCAUSE3 0x200
++# define INTC_INTCAUSE3_CAUSEGRP_OFFSET 0
++# define INTC_INTCAUSE3_CAUSEGRP_SIZE 6
++
++#define INTC_BIT(name) (1 << INTC_##name##_OFFSET)
++#define INTC_MKBF(name, value) (((value) & ((1 << INTC_##name##_SIZE) - 1)) << INTC_##name##_OFFSET)
++#define INTC_GETBF(name, value) (((value) >> INTC_##name##_OFFSET) & ((1 << INTC_##name##_SIZE) - 1))
++
++#define intc_readl(port,reg) \
++ __raw_readl((port)->regs + INTC_##reg)
++#define intc_writel(port,reg,value) \
++ __raw_writel((value), (port)->regs + INTC_##reg)
++
++#endif /* __ASM_AVR32_PERIHP_INTC_H__ */
+diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
+new file mode 100644
+index 0000000..d3aabfc
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/pio.c
+@@ -0,0 +1,118 @@
++/*
++ * Atmel PIO2 Port Multiplexer support
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <linux/clk.h>
++#include <linux/debugfs.h>
++#include <linux/fs.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++
++#include <asm/arch/portmux.h>
++
++#include "pio.h"
++
++#define MAX_NR_PIO_DEVICES 8
++
++struct pio_device {
++ void __iomem *regs;
++ const struct platform_device *pdev;
++ struct clk *clk;
++ u32 alloc_mask;
++ char name[32];
++};
++
++static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
++
++void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
++ unsigned int function_id)
++{
++ struct pio_device *pio;
++ u32 mask = 1 << pin_id;
++
++ BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES);
++
++ pio = &pio_dev[portmux_id];
++
++ if (function_id)
++ pio_writel(pio, BSR, mask);
++ else
++ pio_writel(pio, ASR, mask);
++ pio_writel(pio, PDR, mask);
++}
++
++static int __init pio_probe(struct platform_device *pdev)
++{
++ struct pio_device *pio = NULL;
++
++ BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES);
++ pio = &pio_dev[pdev->id];
++ BUG_ON(!pio->regs);
++
++ /* TODO: Interrupts */
++
++ platform_set_drvdata(pdev, pio);
++
++ printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n",
++ pio->name, pio->regs, platform_get_irq(pdev, 0));
++
++ return 0;
++}
++
++static struct platform_driver pio_driver = {
++ .probe = pio_probe,
++ .driver = {
++ .name = "pio",
++ },
++};
++
++static int __init pio_init(void)
++{
++ return platform_driver_register(&pio_driver);
++}
++subsys_initcall(pio_init);
++
++void __init at32_init_pio(struct platform_device *pdev)
++{
++ struct resource *regs;
++ struct pio_device *pio;
++
++ if (pdev->id > MAX_NR_PIO_DEVICES) {
++ dev_err(&pdev->dev, "only %d PIO devices supported\n",
++ MAX_NR_PIO_DEVICES);
++ return;
++ }
++
++ pio = &pio_dev[pdev->id];
++ snprintf(pio->name, sizeof(pio->name), "pio%d", pdev->id);
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs) {
++ dev_err(&pdev->dev, "no mmio resource defined\n");
++ return;
++ }
++
++ pio->clk = clk_get(&pdev->dev, "mck");
++ if (IS_ERR(pio->clk))
++ /*
++ * This is a fatal error, but if we continue we might
++ * be so lucky that we manage to initialize the
++ * console and display this message...
++ */
++ dev_err(&pdev->dev, "no mck clock defined\n");
++ else
++ clk_enable(pio->clk);
++
++ pio->pdev = pdev;
++ pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
++
++ pio_writel(pio, ODR, ~0UL);
++ pio_writel(pio, PER, ~0UL);
++}
+diff --git a/arch/avr32/mach-at32ap/pio.h b/arch/avr32/mach-at32ap/pio.h
+new file mode 100644
+index 0000000..50fa3ac
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/pio.h
+@@ -0,0 +1,180 @@
++/*
++ * Atmel PIO2 Port Multiplexer support
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ARCH_AVR32_AT32AP_PIO_H__
++#define __ARCH_AVR32_AT32AP_PIO_H__
++
++/* PIO register offsets */
++#define PIO_PER 0x0000
++#define PIO_PDR 0x0004
++#define PIO_PSR 0x0008
++#define PIO_OER 0x0010
++#define PIO_ODR 0x0014
++#define PIO_OSR 0x0018
++#define PIO_IFER 0x0020
++#define PIO_IFDR 0x0024
++#define PIO_ISFR 0x0028
++#define PIO_SODR 0x0030
++#define PIO_CODR 0x0034
++#define PIO_ODSR 0x0038
++#define PIO_PDSR 0x003c
++#define PIO_IER 0x0040
++#define PIO_IDR 0x0044
++#define PIO_IMR 0x0048
++#define PIO_ISR 0x004c
++#define PIO_MDER 0x0050
++#define PIO_MDDR 0x0054
++#define PIO_MDSR 0x0058
++#define PIO_PUDR 0x0060
++#define PIO_PUER 0x0064
++#define PIO_PUSR 0x0068
++#define PIO_ASR 0x0070
++#define PIO_BSR 0x0074
++#define PIO_ABSR 0x0078
++#define PIO_OWER 0x00a0
++#define PIO_OWDR 0x00a4
++#define PIO_OWSR 0x00a8
++
++/* Bitfields in PER */
++
++/* Bitfields in PDR */
++
++/* Bitfields in PSR */
++
++/* Bitfields in OER */
++
++/* Bitfields in ODR */
++
++/* Bitfields in OSR */
++
++/* Bitfields in IFER */
++
++/* Bitfields in IFDR */
++
++/* Bitfields in ISFR */
++
++/* Bitfields in SODR */
++
++/* Bitfields in CODR */
++
++/* Bitfields in ODSR */
++
++/* Bitfields in PDSR */
++
++/* Bitfields in IER */
++
++/* Bitfields in IDR */
++
++/* Bitfields in IMR */
++
++/* Bitfields in ISR */
++
++/* Bitfields in MDER */
++
++/* Bitfields in MDDR */
++
++/* Bitfields in MDSR */
++
++/* Bitfields in PUDR */
++
++/* Bitfields in PUER */
++
++/* Bitfields in PUSR */
++
++/* Bitfields in ASR */
++
++/* Bitfields in BSR */
++
++/* Bitfields in ABSR */
++#define PIO_P0_OFFSET 0
++#define PIO_P0_SIZE 1
++#define PIO_P1_OFFSET 1
++#define PIO_P1_SIZE 1
++#define PIO_P2_OFFSET 2
++#define PIO_P2_SIZE 1
++#define PIO_P3_OFFSET 3
++#define PIO_P3_SIZE 1
++#define PIO_P4_OFFSET 4
++#define PIO_P4_SIZE 1
++#define PIO_P5_OFFSET 5
++#define PIO_P5_SIZE 1
++#define PIO_P6_OFFSET 6
++#define PIO_P6_SIZE 1
++#define PIO_P7_OFFSET 7
++#define PIO_P7_SIZE 1
++#define PIO_P8_OFFSET 8
++#define PIO_P8_SIZE 1
++#define PIO_P9_OFFSET 9
++#define PIO_P9_SIZE 1
++#define PIO_P10_OFFSET 10
++#define PIO_P10_SIZE 1
++#define PIO_P11_OFFSET 11
++#define PIO_P11_SIZE 1
++#define PIO_P12_OFFSET 12
++#define PIO_P12_SIZE 1
++#define PIO_P13_OFFSET 13
++#define PIO_P13_SIZE 1
++#define PIO_P14_OFFSET 14
++#define PIO_P14_SIZE 1
++#define PIO_P15_OFFSET 15
++#define PIO_P15_SIZE 1
++#define PIO_P16_OFFSET 16
++#define PIO_P16_SIZE 1
++#define PIO_P17_OFFSET 17
++#define PIO_P17_SIZE 1
++#define PIO_P18_OFFSET 18
++#define PIO_P18_SIZE 1
++#define PIO_P19_OFFSET 19
++#define PIO_P19_SIZE 1
++#define PIO_P20_OFFSET 20
++#define PIO_P20_SIZE 1
++#define PIO_P21_OFFSET 21
++#define PIO_P21_SIZE 1
++#define PIO_P22_OFFSET 22
++#define PIO_P22_SIZE 1
++#define PIO_P23_OFFSET 23
++#define PIO_P23_SIZE 1
++#define PIO_P24_OFFSET 24
++#define PIO_P24_SIZE 1
++#define PIO_P25_OFFSET 25
++#define PIO_P25_SIZE 1
++#define PIO_P26_OFFSET 26
++#define PIO_P26_SIZE 1
++#define PIO_P27_OFFSET 27
++#define PIO_P27_SIZE 1
++#define PIO_P28_OFFSET 28
++#define PIO_P28_SIZE 1
++#define PIO_P29_OFFSET 29
++#define PIO_P29_SIZE 1
++#define PIO_P30_OFFSET 30
++#define PIO_P30_SIZE 1
++#define PIO_P31_OFFSET 31
++#define PIO_P31_SIZE 1
++
++/* Bitfields in OWER */
++
++/* Bitfields in OWDR */
++
++/* Bitfields in OWSR */
++
++/* Bit manipulation macros */
++#define PIO_BIT(name) (1 << PIO_##name##_OFFSET)
++#define PIO_BF(name,value) (((value) & ((1 << PIO_##name##_SIZE) - 1)) << PIO_##name##_OFFSET)
++#define PIO_BFEXT(name,value) (((value) >> PIO_##name##_OFFSET) & ((1 << PIO_##name##_SIZE) - 1))
++#define PIO_BFINS(name,value,old) (((old) & ~(((1 << PIO_##name##_SIZE) - 1) << PIO_##name##_OFFSET)) | PIO_BF(name,value))
++
++/* Register access macros */
++#define pio_readl(port,reg) \
++ __raw_readl((port)->regs + PIO_##reg)
++#define pio_writel(port,reg,value) \
++ __raw_writel((value), (port)->regs + PIO_##reg)
++
++void at32_init_pio(struct platform_device *pdev);
++
++#endif /* __ARCH_AVR32_AT32AP_PIO_H__ */
+diff --git a/arch/avr32/mach-at32ap/sm.c b/arch/avr32/mach-at32ap/sm.c
+new file mode 100644
+index 0000000..03306eb
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/sm.c
+@@ -0,0 +1,289 @@
++/*
++ * System Manager driver for AT32AP CPUs
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/random.h>
++#include <linux/spinlock.h>
++
++#include <asm/intc.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/arch/sm.h>
++
++#include "sm.h"
++
++#define SM_EIM_IRQ_RESOURCE 1
++#define SM_PM_IRQ_RESOURCE 2
++#define SM_RTC_IRQ_RESOURCE 3
++
++#define to_eim(irqc) container_of(irqc, struct at32_sm, irqc)
++
++struct at32_sm system_manager;
++
++int __init at32_sm_init(void)
++{
++ struct resource *regs;
++ struct at32_sm *sm = &system_manager;
++ int ret = -ENXIO;
++
++ regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
++ if (!regs)
++ goto fail;
++
++ spin_lock_init(&sm->lock);
++ sm->pdev = &at32_sm_device;
++
++ ret = -ENOMEM;
++ sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!sm->regs)
++ goto fail;
++
++ return 0;
++
++fail:
++ printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
++ return ret;
++}
++
++/*
++ * External Interrupt Module (EIM).
++ *
++ * EIM gets level- or edge-triggered interrupts of either polarity
++ * from the outside and converts it to active-high level-triggered
++ * interrupts that the internal interrupt controller can handle. EIM
++ * also provides masking/unmasking of interrupts, as well as
++ * acknowledging of edge-triggered interrupts.
++ */
++
++static irqreturn_t spurious_eim_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++ printk(KERN_WARNING "Spurious EIM interrupt %d\n", irq);
++ disable_irq(irq);
++ return IRQ_NONE;
++}
++
++static struct irqaction eim_spurious_action = {
++ .handler = spurious_eim_interrupt,
++};
++
++static irqreturn_t eim_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct irq_controller * irqc = dev_id;
++ struct at32_sm *sm = to_eim(irqc);
++ unsigned long pending;
++
++ /*
++ * No need to disable interrupts globally. The interrupt
++ * level relevant to this group must be masked all the time,
++ * so we know that this particular EIM instance will not be
++ * re-entered.
++ */
++ spin_lock(&sm->lock);
++
++ pending = intc_get_pending(sm->irqc.irq_group);
++ if (unlikely(!pending)) {
++ printk(KERN_ERR "EIM (group %u): No interrupts pending!\n",
++ sm->irqc.irq_group);
++ goto unlock;
++ }
++
++ do {
++ struct irqaction *action;
++ unsigned int i;
++
++ i = fls(pending) - 1;
++ pending &= ~(1 << i);
++ action = sm->action[i];
++
++ /* Acknowledge the interrupt */
++ sm_writel(sm, EIM_ICR, 1 << i);
++
++ spin_unlock(&sm->lock);
++
++ if (action->flags & SA_INTERRUPT)
++ local_irq_disable();
++ action->handler(sm->irqc.first_irq + i, action->dev_id, regs);
++ local_irq_enable();
++ spin_lock(&sm->lock);
++ if (action->flags & SA_SAMPLE_RANDOM)
++ add_interrupt_randomness(sm->irqc.first_irq + i);
++ } while (pending);
++
++unlock:
++ spin_unlock(&sm->lock);
++ return IRQ_HANDLED;
++}
++
++static void eim_mask(struct irq_controller *irqc, unsigned int irq)
++{
++ struct at32_sm *sm = to_eim(irqc);
++ unsigned int i;
++
++ i = irq - sm->irqc.first_irq;
++ sm_writel(sm, EIM_IDR, 1 << i);
++}
++
++static void eim_unmask(struct irq_controller *irqc, unsigned int irq)
++{
++ struct at32_sm *sm = to_eim(irqc);
++ unsigned int i;
++
++ i = irq - sm->irqc.first_irq;
++ sm_writel(sm, EIM_IER, 1 << i);
++}
++
++static int eim_setup(struct irq_controller *irqc, unsigned int irq,
++ struct irqaction *action)
++{
++ struct at32_sm *sm = to_eim(irqc);
++ sm->action[irq - sm->irqc.first_irq] = action;
++ /* Acknowledge earlier interrupts */
++ sm_writel(sm, EIM_ICR, (1<<(irq - sm->irqc.first_irq)));
++ eim_unmask(irqc, irq);
++ return 0;
++}
++
++static void eim_free(struct irq_controller *irqc, unsigned int irq,
++ void *dev)
++{
++ struct at32_sm *sm = to_eim(irqc);
++ eim_mask(irqc, irq);
++ sm->action[irq - sm->irqc.first_irq] = &eim_spurious_action;
++}
++
++static int eim_set_type(struct irq_controller *irqc, unsigned int irq,
++ unsigned int type)
++{
++ struct at32_sm *sm = to_eim(irqc);
++ unsigned long flags;
++ u32 value, pattern;
++
++ spin_lock_irqsave(&sm->lock, flags);
++
++ pattern = 1 << (irq - sm->irqc.first_irq);
++
++ value = sm_readl(sm, EIM_MODE);
++ if (type & IRQ_TYPE_LEVEL)
++ value |= pattern;
++ else
++ value &= ~pattern;
++ sm_writel(sm, EIM_MODE, value);
++ value = sm_readl(sm, EIM_EDGE);
++ if (type & IRQ_EDGE_RISING)
++ value |= pattern;
++ else
++ value &= ~pattern;
++ sm_writel(sm, EIM_EDGE, value);
++ value = sm_readl(sm, EIM_LEVEL);
++ if (type & IRQ_LEVEL_HIGH)
++ value |= pattern;
++ else
++ value &= ~pattern;
++ sm_writel(sm, EIM_LEVEL, value);
++
++ spin_unlock_irqrestore(&sm->lock, flags);
++
++ return 0;
++}
++
++static unsigned int eim_get_type(struct irq_controller *irqc,
++ unsigned int irq)
++{
++ struct at32_sm *sm = to_eim(irqc);
++ unsigned long flags;
++ unsigned int type = 0;
++ u32 mode, edge, level, pattern;
++
++ pattern = 1 << (irq - sm->irqc.first_irq);
++
++ spin_lock_irqsave(&sm->lock, flags);
++ mode = sm_readl(sm, EIM_MODE);
++ edge = sm_readl(sm, EIM_EDGE);
++ level = sm_readl(sm, EIM_LEVEL);
++ spin_unlock_irqrestore(&sm->lock, flags);
++
++ if (mode & pattern)
++ type |= IRQ_TYPE_LEVEL;
++ if (edge & pattern)
++ type |= IRQ_EDGE_RISING;
++ if (level & pattern)
++ type |= IRQ_LEVEL_HIGH;
++
++ return type;
++}
++
++static struct irq_controller_class eim_irq_class = {
++ .typename = "EIM",
++ .handle = eim_handle_irq,
++ .setup = eim_setup,
++ .free = eim_free,
++ .mask = eim_mask,
++ .unmask = eim_unmask,
++ .set_type = eim_set_type,
++ .get_type = eim_get_type,
++};
++
++static int __init eim_init(void)
++{
++ struct at32_sm *sm = &system_manager;
++ unsigned int i;
++ u32 pattern;
++ int ret;
++
++ /*
++ * The EIM is really the same module as SM, so register
++ * mapping, etc. has been taken care of already.
++ */
++
++ /*
++ * Find out how many interrupt lines that are actually
++ * implemented in hardware.
++ */
++ sm_writel(sm, EIM_IDR, ~0UL);
++ sm_writel(sm, EIM_MODE, ~0UL);
++ pattern = sm_readl(sm, EIM_MODE);
++ sm->irqc.nr_irqs = fls(pattern);
++
++ ret = -ENOMEM;
++ sm->action = kmalloc(sizeof(*sm->action) * sm->irqc.nr_irqs,
++ GFP_KERNEL);
++ if (!sm->action)
++ goto out;
++
++ for (i = 0; i < sm->irqc.nr_irqs; i++)
++ sm->action[i] = &eim_spurious_action;
++
++ spin_lock_init(&sm->lock);
++ sm->irqc.irq_group = sm->pdev->resource[SM_EIM_IRQ_RESOURCE].start;
++ sm->irqc.class = &eim_irq_class;
++
++ ret = intc_register_controller(&sm->irqc);
++ if (ret < 0)
++ goto out_free_actions;
++
++ printk("EIM: External Interrupt Module at 0x%p, IRQ group %u\n",
++ sm->regs, sm->irqc.irq_group);
++ printk("EIM: Handling %u external IRQs, starting with IRQ%u\n",
++ sm->irqc.nr_irqs, sm->irqc.first_irq);
++
++ return 0;
++
++out_free_actions:
++ kfree(sm->action);
++out:
++ return ret;
++}
++arch_initcall(eim_init);
+diff --git a/arch/avr32/mach-at32ap/sm.h b/arch/avr32/mach-at32ap/sm.h
+new file mode 100644
+index 0000000..cad02b5
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/sm.h
+@@ -0,0 +1,242 @@
++/*
++ * Register definitions for SM
++ *
++ * System Manager
++ */
++#ifndef __ASM_AVR32_SM_H__
++#define __ASM_AVR32_SM_H__
++
++/* SM register offsets */
++#define SM_PM_MCCTRL 0x0000
++#define SM_PM_CKSEL 0x0004
++#define SM_PM_CPU_MASK 0x0008
++#define SM_PM_HSB_MASK 0x000c
++#define SM_PM_PBA_MASK 0x0010
++#define SM_PM_PBB_MASK 0x0014
++#define SM_PM_PLL0 0x0020
++#define SM_PM_PLL1 0x0024
++#define SM_PM_VCTRL 0x0030
++#define SM_PM_VMREF 0x0034
++#define SM_PM_VMV 0x0038
++#define SM_PM_IER 0x0040
++#define SM_PM_IDR 0x0044
++#define SM_PM_IMR 0x0048
++#define SM_PM_ISR 0x004c
++#define SM_PM_ICR 0x0050
++#define SM_PM_GCCTRL 0x0060
++#define SM_RTC_CTRL 0x0080
++#define SM_RTC_VAL 0x0084
++#define SM_RTC_TOP 0x0088
++#define SM_RTC_IER 0x0090
++#define SM_RTC_IDR 0x0094
++#define SM_RTC_IMR 0x0098
++#define SM_RTC_ISR 0x009c
++#define SM_RTC_ICR 0x00a0
++#define SM_WDT_CTRL 0x00b0
++#define SM_WDT_CLR 0x00b4
++#define SM_WDT_EXT 0x00b8
++#define SM_RC_RCAUSE 0x00c0
++#define SM_EIM_IER 0x0100
++#define SM_EIM_IDR 0x0104
++#define SM_EIM_IMR 0x0108
++#define SM_EIM_ISR 0x010c
++#define SM_EIM_ICR 0x0110
++#define SM_EIM_MODE 0x0114
++#define SM_EIM_EDGE 0x0118
++#define SM_EIM_LEVEL 0x011c
++#define SM_EIM_TEST 0x0120
++#define SM_EIM_NMIC 0x0124
++
++/* Bitfields in PM_MCCTRL */
++
++/* Bitfields in PM_CKSEL */
++#define SM_CPUSEL_OFFSET 0
++#define SM_CPUSEL_SIZE 3
++#define SM_CPUDIV_OFFSET 7
++#define SM_CPUDIV_SIZE 1
++#define SM_HSBSEL_OFFSET 8
++#define SM_HSBSEL_SIZE 3
++#define SM_HSBDIV_OFFSET 15
++#define SM_HSBDIV_SIZE 1
++#define SM_PBASEL_OFFSET 16
++#define SM_PBASEL_SIZE 3
++#define SM_PBADIV_OFFSET 23
++#define SM_PBADIV_SIZE 1
++#define SM_PBBSEL_OFFSET 24
++#define SM_PBBSEL_SIZE 3
++#define SM_PBBDIV_OFFSET 31
++#define SM_PBBDIV_SIZE 1
++
++/* Bitfields in PM_CPU_MASK */
++
++/* Bitfields in PM_HSB_MASK */
++
++/* Bitfields in PM_PBA_MASK */
++
++/* Bitfields in PM_PBB_MASK */
++
++/* Bitfields in PM_PLL0 */
++#define SM_PLLEN_OFFSET 0
++#define SM_PLLEN_SIZE 1
++#define SM_PLLOSC_OFFSET 1
++#define SM_PLLOSC_SIZE 1
++#define SM_PLLOPT_OFFSET 2
++#define SM_PLLOPT_SIZE 3
++#define SM_PLLDIV_OFFSET 8
++#define SM_PLLDIV_SIZE 8
++#define SM_PLLMUL_OFFSET 16
++#define SM_PLLMUL_SIZE 8
++#define SM_PLLCOUNT_OFFSET 24
++#define SM_PLLCOUNT_SIZE 6
++#define SM_PLLTEST_OFFSET 31
++#define SM_PLLTEST_SIZE 1
++
++/* Bitfields in PM_PLL1 */
++
++/* Bitfields in PM_VCTRL */
++#define SM_VAUTO_OFFSET 0
++#define SM_VAUTO_SIZE 1
++#define SM_PM_VCTRL_VAL_OFFSET 8
++#define SM_PM_VCTRL_VAL_SIZE 7
++
++/* Bitfields in PM_VMREF */
++#define SM_REFSEL_OFFSET 0
++#define SM_REFSEL_SIZE 4
++
++/* Bitfields in PM_VMV */
++#define SM_PM_VMV_VAL_OFFSET 0
++#define SM_PM_VMV_VAL_SIZE 8
++
++/* Bitfields in PM_IER */
++
++/* Bitfields in PM_IDR */
++
++/* Bitfields in PM_IMR */
++
++/* Bitfields in PM_ISR */
++
++/* Bitfields in PM_ICR */
++#define SM_LOCK0_OFFSET 0
++#define SM_LOCK0_SIZE 1
++#define SM_LOCK1_OFFSET 1
++#define SM_LOCK1_SIZE 1
++#define SM_WAKE_OFFSET 2
++#define SM_WAKE_SIZE 1
++#define SM_VOK_OFFSET 3
++#define SM_VOK_SIZE 1
++#define SM_VMRDY_OFFSET 4
++#define SM_VMRDY_SIZE 1
++#define SM_CKRDY_OFFSET 5
++#define SM_CKRDY_SIZE 1
++
++/* Bitfields in PM_GCCTRL */
++#define SM_OSCSEL_OFFSET 0
++#define SM_OSCSEL_SIZE 1
++#define SM_PLLSEL_OFFSET 1
++#define SM_PLLSEL_SIZE 1
++#define SM_CEN_OFFSET 2
++#define SM_CEN_SIZE 1
++#define SM_CPC_OFFSET 3
++#define SM_CPC_SIZE 1
++#define SM_DIVEN_OFFSET 4
++#define SM_DIVEN_SIZE 1
++#define SM_DIV_OFFSET 8
++#define SM_DIV_SIZE 8
++
++/* Bitfields in RTC_CTRL */
++#define SM_PCLR_OFFSET 1
++#define SM_PCLR_SIZE 1
++#define SM_TOPEN_OFFSET 2
++#define SM_TOPEN_SIZE 1
++#define SM_CLKEN_OFFSET 3
++#define SM_CLKEN_SIZE 1
++#define SM_PSEL_OFFSET 8
++#define SM_PSEL_SIZE 16
++
++/* Bitfields in RTC_VAL */
++#define SM_RTC_VAL_VAL_OFFSET 0
++#define SM_RTC_VAL_VAL_SIZE 31
++
++/* Bitfields in RTC_TOP */
++#define SM_RTC_TOP_VAL_OFFSET 0
++#define SM_RTC_TOP_VAL_SIZE 32
++
++/* Bitfields in RTC_IER */
++
++/* Bitfields in RTC_IDR */
++
++/* Bitfields in RTC_IMR */
++
++/* Bitfields in RTC_ISR */
++
++/* Bitfields in RTC_ICR */
++#define SM_TOPI_OFFSET 0
++#define SM_TOPI_SIZE 1
++
++/* Bitfields in WDT_CTRL */
++#define SM_KEY_OFFSET 24
++#define SM_KEY_SIZE 8
++
++/* Bitfields in WDT_CLR */
++
++/* Bitfields in WDT_EXT */
++
++/* Bitfields in RC_RCAUSE */
++#define SM_POR_OFFSET 0
++#define SM_POR_SIZE 1
++#define SM_BOD_OFFSET 1
++#define SM_BOD_SIZE 1
++#define SM_EXT_OFFSET 2
++#define SM_EXT_SIZE 1
++#define SM_WDT_OFFSET 3
++#define SM_WDT_SIZE 1
++#define SM_NTAE_OFFSET 4
++#define SM_NTAE_SIZE 1
++#define SM_SERP_OFFSET 5
++#define SM_SERP_SIZE 1
++
++/* Bitfields in EIM_IER */
++
++/* Bitfields in EIM_IDR */
++
++/* Bitfields in EIM_IMR */
++
++/* Bitfields in EIM_ISR */
++
++/* Bitfields in EIM_ICR */
++
++/* Bitfields in EIM_MODE */
++
++/* Bitfields in EIM_EDGE */
++#define SM_INT0_OFFSET 0
++#define SM_INT0_SIZE 1
++#define SM_INT1_OFFSET 1
++#define SM_INT1_SIZE 1
++#define SM_INT2_OFFSET 2
++#define SM_INT2_SIZE 1
++#define SM_INT3_OFFSET 3
++#define SM_INT3_SIZE 1
++
++/* Bitfields in EIM_LEVEL */
++
++/* Bitfields in EIM_TEST */
++#define SM_TESTEN_OFFSET 31
++#define SM_TESTEN_SIZE 1
++
++/* Bitfields in EIM_NMIC */
++#define SM_EN_OFFSET 0
++#define SM_EN_SIZE 1
++
++/* Bit manipulation macros */
++#define SM_BIT(name) (1 << SM_##name##_OFFSET)
++#define SM_BF(name,value) (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET)
++#define SM_BFEXT(name,value) (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1))
++#define SM_BFINS(name,value,old) (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value))
++
++/* Register access macros */
++#define sm_readl(port,reg) \
++ __raw_readl((port)->regs + SM_##reg)
++#define sm_writel(port,reg,value) \
++ __raw_writel((value), (port)->regs + SM_##reg)
++
++#endif /* __ASM_AVR32_SM_H__ */
+diff --git a/arch/avr32/mm/Makefile b/arch/avr32/mm/Makefile
+new file mode 100644
+index 0000000..0066491
+--- /dev/null
++++ b/arch/avr32/mm/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for the Linux/AVR32 kernel.
++#
++
++obj-y += init.o clear_page.o copy_page.o dma-coherent.o
++obj-y += ioremap.o cache.o fault.o tlb.o
+diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
+new file mode 100644
+index 0000000..450515b
+--- /dev/null
++++ b/arch/avr32/mm/cache.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <linux/highmem.h>
++#include <linux/unistd.h>
++
++#include <asm/cacheflush.h>
++#include <asm/cachectl.h>
++#include <asm/processor.h>
++#include <asm/uaccess.h>
++
++/*
++ * If you attempt to flush anything more than this, you need superuser
++ * privileges. The value is completely arbitrary.
++ */
++#define CACHEFLUSH_MAX_LEN 1024
++
++void invalidate_dcache_region(void *start, size_t size)
++{
++ unsigned long v, begin, end, linesz;
++
++ linesz = boot_cpu_data.dcache.linesz;
++
++ //printk("invalidate dcache: %p + %u\n", start, size);
++
++ /* You asked for it, you got it */
++ begin = (unsigned long)start & ~(linesz - 1);
++ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
++
++ for (v = begin; v < end; v += linesz)
++ invalidate_dcache_line((void *)v);
++}
++
++void clean_dcache_region(void *start, size_t size)
++{
++ unsigned long v, begin, end, linesz;
++
++ linesz = boot_cpu_data.dcache.linesz;
++ begin = (unsigned long)start & ~(linesz - 1);
++ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
++
++ for (v = begin; v < end; v += linesz)
++ clean_dcache_line((void *)v);
++ flush_write_buffer();
++}
++
++void flush_dcache_region(void *start, size_t size)
++{
++ unsigned long v, begin, end, linesz;
++
++ linesz = boot_cpu_data.dcache.linesz;
++ begin = (unsigned long)start & ~(linesz - 1);
++ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
++
++ for (v = begin; v < end; v += linesz)
++ flush_dcache_line((void *)v);
++ flush_write_buffer();
++}
++
++void invalidate_icache_region(void *start, size_t size)
++{
++ unsigned long v, begin, end, linesz;
++
++ linesz = boot_cpu_data.icache.linesz;
++ begin = (unsigned long)start & ~(linesz - 1);
++ end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
++
++ for (v = begin; v < end; v += linesz)
++ invalidate_icache_line((void *)v);
++}
++
++static inline void __flush_icache_range(unsigned long start, unsigned long end)
++{
++ unsigned long v, linesz;
++
++ linesz = boot_cpu_data.dcache.linesz;
++ for (v = start; v < end; v += linesz) {
++ clean_dcache_line((void *)v);
++ invalidate_icache_line((void *)v);
++ }
++
++ flush_write_buffer();
++}
++
++/*
++ * This one is called after a module has been loaded.
++ */
++void flush_icache_range(unsigned long start, unsigned long end)
++{
++ unsigned long linesz;
++
++ linesz = boot_cpu_data.dcache.linesz;
++ __flush_icache_range(start & ~(linesz - 1),
++ (end + linesz - 1) & ~(linesz - 1));
++}
++
++/*
++ * This one is called from do_no_page(), do_swap_page() and install_page().
++ */
++void flush_icache_page(struct vm_area_struct *vma, struct page *page)
++{
++ if (vma->vm_flags & VM_EXEC) {
++ void *v = kmap(page);
++ __flush_icache_range((unsigned long)v, (unsigned long)v + PAGE_SIZE);
++ kunmap(v);
++ }
++}
++
++/*
++ * This one is used by copy_to_user_page()
++ */
++void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
++ unsigned long addr, int len)
++{
++ if (vma->vm_flags & VM_EXEC)
++ flush_icache_range(addr, addr + len);
++}
++
++asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
++{
++ int ret;
++
++ if (len > CACHEFLUSH_MAX_LEN) {
++ ret = -EPERM;
++ if (!capable(CAP_SYS_ADMIN))
++ goto out;
++ }
++
++ ret = -EFAULT;
++ if (!access_ok(VERIFY_WRITE, addr, len))
++ goto out;
++
++ switch (operation) {
++ case CACHE_IFLUSH:
++ flush_icache_range((unsigned long)addr,
++ (unsigned long)addr + len);
++ ret = 0;
++ break;
++ default:
++ ret = -EINVAL;
++ }
++
++out:
++ return ret;
++}
+diff --git a/arch/avr32/mm/clear_page.S b/arch/avr32/mm/clear_page.S
+new file mode 100644
+index 0000000..5d70dca
+--- /dev/null
++++ b/arch/avr32/mm/clear_page.S
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <linux/linkage.h>
++#include <asm/page.h>
++
++/*
++ * clear_page
++ * r12: P1 address (to)
++ */
++ .text
++ .global clear_page
++clear_page:
++ sub r9, r12, -PAGE_SIZE
++ mov r10, 0
++ mov r11, 0
++0: st.d r12++, r10
++ cp r12, r9
++ brne 0b
++ mov pc, lr
+diff --git a/arch/avr32/mm/copy_page.S b/arch/avr32/mm/copy_page.S
+new file mode 100644
+index 0000000..c2b3752
+--- /dev/null
++++ b/arch/avr32/mm/copy_page.S
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/linkage.h>
++#include <asm/page.h>
++
++/*
++ * copy_page
++ *
++ * r12 to (P1 address)
++ * r11 from (P1 address)
++ * r8-r10 scratch
++ */
++ .text
++ .global copy_page
++copy_page:
++ sub r10, r11, -(1 << PAGE_SHIFT)
++ /* pref r11[0] */
++1: /* pref r11[8] */
++ ld.d r8, r11++
++ st.d r12++, r8
++ cp r11, r10
++ brlo 1b
++ mov pc, lr
+diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
+new file mode 100644
+index 0000000..44ab8a7
+--- /dev/null
++++ b/arch/avr32/mm/dma-coherent.c
+@@ -0,0 +1,139 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <linux/dma-mapping.h>
++
++#include <asm/addrspace.h>
++#include <asm/cacheflush.h>
++
++void dma_cache_sync(void *vaddr, size_t size, int direction)
++{
++ /*
++ * No need to sync an uncached area
++ */
++ if (PXSEG(vaddr) == P2SEG)
++ return;
++
++ switch (direction) {
++ case DMA_FROM_DEVICE: /* invalidate only */
++ dma_cache_inv(vaddr, size);
++ break;
++ case DMA_TO_DEVICE: /* writeback only */
++ dma_cache_wback(vaddr, size);
++ break;
++ case DMA_BIDIRECTIONAL: /* writeback and invalidate */
++ dma_cache_wback_inv(vaddr, size);
++ break;
++ default:
++ BUG();
++ }
++}
++EXPORT_SYMBOL(dma_cache_sync);
++
++static struct page *__dma_alloc(struct device *dev, size_t size,
++ dma_addr_t *handle, gfp_t gfp)
++{
++ struct page *page, *free, *end;
++ int order;
++
++ size = PAGE_ALIGN(size);
++ order = get_order(size);
++
++ page = alloc_pages(gfp, order);
++ if (!page)
++ return NULL;
++ split_page(page, order);
++
++ /*
++ * When accessing physical memory with valid cache data, we
++ * get a cache hit even if the virtual memory region is marked
++ * as uncached.
++ *
++ * Since the memory is newly allocated, there is no point in
++ * doing a writeback. If the previous owner cares, he should
++ * have flushed the cache before releasing the memory.
++ */
++ invalidate_dcache_region(phys_to_virt(page_to_phys(page)), size);
++
++ *handle = page_to_bus(page);
++ free = page + (size >> PAGE_SHIFT);
++ end = page + (1 << order);
++
++ /*
++ * Free any unused pages
++ */
++ while (free < end) {
++ __free_page(free);
++ free++;
++ }
++
++ return page;
++}
++
++static void __dma_free(struct device *dev, size_t size,
++ struct page *page, dma_addr_t handle)
++{
++ struct page *end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT);
++
++ while (page < end)
++ __free_page(page++);
++}
++
++void *dma_alloc_coherent(struct device *dev, size_t size,
++ dma_addr_t *handle, gfp_t gfp)
++{
++ struct page *page;
++ void *ret = NULL;
++
++ page = __dma_alloc(dev, size, handle, gfp);
++ if (page)
++ ret = phys_to_uncached(page_to_phys(page));
++
++ return ret;
++}
++EXPORT_SYMBOL(dma_alloc_coherent);
++
++void dma_free_coherent(struct device *dev, size_t size,
++ void *cpu_addr, dma_addr_t handle)
++{
++ void *addr = phys_to_cached(uncached_to_phys(cpu_addr));
++ struct page *page;
++
++ pr_debug("dma_free_coherent addr %p (phys %08lx) size %u\n",
++ cpu_addr, (unsigned long)handle, (unsigned)size);
++ BUG_ON(!virt_addr_valid(addr));
++ page = virt_to_page(addr);
++ __dma_free(dev, size, page, handle);
++}
++EXPORT_SYMBOL(dma_free_coherent);
++
++#if 0
++void *dma_alloc_writecombine(struct device *dev, size_t size,
++ dma_addr_t *handle, gfp_t gfp)
++{
++ struct page *page;
++
++ page = __dma_alloc(dev, size, handle, gfp);
++
++ /* Now, map the page into P3 with write-combining turned on */
++ return __ioremap(page_to_phys(page), size, _PAGE_BUFFER);
++}
++EXPORT_SYMBOL(dma_alloc_writecombine);
++
++void dma_free_writecombine(struct device *dev, size_t size,
++ void *cpu_addr, dma_addr_t handle)
++{
++ struct page *page;
++
++ iounmap(cpu_addr);
++
++ page = bus_to_page(handle);
++ __dma_free(dev, size, page, handle);
++}
++EXPORT_SYMBOL(dma_free_writecombine);
++#endif
+diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
+new file mode 100644
+index 0000000..6785572
+--- /dev/null
++++ b/arch/avr32/mm/fault.c
+@@ -0,0 +1,315 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on linux/arch/sh/mm/fault.c:
++ * Copyright (C) 1999 Niibe Yutaka
++ *
++ * 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/mm.h>
++#include <linux/module.h>
++#include <linux/pagemap.h>
++
++#include <asm/kdebug.h>
++#include <asm/mmu_context.h>
++#include <asm/sysreg.h>
++#include <asm/uaccess.h>
++#include <asm/tlb.h>
++
++#ifdef DEBUG
++static void dump_code(unsigned long pc)
++{
++ char *p = (char *)pc;
++ char val;
++ int i;
++
++
++ printk(KERN_DEBUG "Code:");
++ for (i = 0; i < 16; i++) {
++ if (__get_user(val, p + i))
++ break;
++ printk(" %02x", val);
++ }
++ printk("\n");
++}
++#endif
++
++#ifdef CONFIG_KPROBES
++ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++
++/* Hook to register for page fault notifications */
++int register_page_fault_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
++}
++
++int unregister_page_fault_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
++}
++
++static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
++ int trap, int sig)
++{
++ struct die_args args = {
++ .regs = regs,
++ .trapnr = trap,
++ };
++ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
++}
++#else
++static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
++ int trap, int sig)
++{
++ return NOTIFY_DONE;
++}
++#endif
++
++/*
++ * This routine handles page faults. It determines the address and the
++ * problem, and then passes it off to one of the appropriate routines.
++ *
++ * ecr is the Exception Cause Register. Possible values are:
++ * 5: Page not found (instruction access)
++ * 6: Protection fault (instruction access)
++ * 12: Page not found (read access)
++ * 13: Page not found (write access)
++ * 14: Protection fault (read access)
++ * 15: Protection fault (write access)
++ */
++asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
++{
++ struct task_struct *tsk;
++ struct mm_struct *mm;
++ struct vm_area_struct *vma;
++ const struct exception_table_entry *fixup;
++ unsigned long address;
++ unsigned long page;
++ int writeaccess = 0;
++
++ if (notify_page_fault(DIE_PAGE_FAULT, regs,
++ ecr, SIGSEGV) == NOTIFY_STOP)
++ return;
++
++ address = sysreg_read(TLBEAR);
++
++ tsk = current;
++ mm = tsk->mm;
++
++ /*
++ * If we're in an interrupt or have no user context, we must
++ * not take the fault...
++ */
++ if (in_atomic() || !mm || regs->sr & SYSREG_BIT(GM))
++ goto no_context;
++
++ local_irq_enable();
++
++ 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:
++ //pr_debug("good area: vm_flags = 0x%lx\n", vma->vm_flags);
++ switch (ecr) {
++ case ECR_PROTECTION_X:
++ case ECR_TLB_MISS_X:
++ if (!(vma->vm_flags & VM_EXEC))
++ goto bad_area;
++ break;
++ case ECR_PROTECTION_R:
++ case ECR_TLB_MISS_R:
++ if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
++ goto bad_area;
++ break;
++ case ECR_PROTECTION_W:
++ case ECR_TLB_MISS_W:
++ if (!(vma->vm_flags & VM_WRITE))
++ goto bad_area;
++ writeaccess = 1;
++ break;
++ default:
++ panic("Unhandled case %lu in do_page_fault!", ecr);
++ }
++
++ /*
++ * 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, writeaccess)) {
++ case VM_FAULT_MINOR:
++ tsk->min_flt++;
++ break;
++ case VM_FAULT_MAJOR:
++ tsk->maj_flt++;
++ break;
++ case VM_FAULT_SIGBUS:
++ goto do_sigbus;
++ case VM_FAULT_OOM:
++ goto out_of_memory;
++ default:
++ BUG();
++ }
++
++ up_read(&mm->mmap_sem);
++ return;
++
++ /*
++ * Something tried to access memory that isn't in our memory
++ * map. Fix it, but check if it's kernel or user first...
++ */
++bad_area:
++ pr_debug("Bad area [%s:%u]: addr %08lx, ecr %lu\n",
++ tsk->comm, tsk->pid, address, ecr);
++
++ up_read(&mm->mmap_sem);
++
++ if (user_mode(regs)) {
++ /* Hmm...we have to pass address and ecr somehow... */
++ /* tsk->thread.address = address;
++ tsk->thread.error_code = ecr; */
++#ifdef DEBUG
++ show_regs(regs);
++ dump_code(regs->pc);
++
++ page = sysreg_read(PTBR);
++ printk("ptbr = %08lx", page);
++ if (page) {
++ page = ((unsigned long *)page)[address >> 22];
++ printk(" pgd = %08lx", page);
++ if (page & _PAGE_PRESENT) {
++ page &= PAGE_MASK;
++ address &= 0x003ff000;
++ page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
++ printk(" pte = %08lx\n", page);
++ }
++ }
++#endif
++ pr_debug("Sending SIGSEGV to PID %d...\n",
++ tsk->pid);
++ force_sig(SIGSEGV, tsk);
++ return;
++ }
++
++no_context:
++ pr_debug("No context\n");
++
++ /* Are we prepared to handle this kernel fault? */
++ fixup = search_exception_tables(regs->pc);
++ if (fixup) {
++ regs->pc = fixup->fixup;
++ pr_debug("Found fixup at %08lx\n", fixup->fixup);
++ return;
++ }
++
++ /*
++ * Oops. The kernel tried to access some bad page. We'll have
++ * to terminate things with extreme prejudice.
++ */
++ if (address < PAGE_SIZE)
++ printk(KERN_ALERT
++ "Unable to handle kernel NULL pointer dereference");
++ else
++ printk(KERN_ALERT
++ "Unable to handle kernel paging request");
++ printk(" at virtual address %08lx\n", address);
++ printk(KERN_ALERT "pc = %08lx\n", regs->pc);
++
++ page = sysreg_read(PTBR);
++ printk(KERN_ALERT "ptbr = %08lx", page);
++ if (page) {
++ page = ((unsigned long *)page)[address >> 22];
++ printk(" pgd = %08lx", page);
++ if (page & _PAGE_PRESENT) {
++ page &= PAGE_MASK;
++ address &= 0x003ff000;
++ page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
++ printk(" pte = %08lx\n", page);
++ }
++ }
++ die("\nOops", regs, ecr);
++ do_exit(SIGKILL);
++
++ /*
++ * We ran out of memory, or some other thing happened to us
++ * that made us unable to handle the page fault gracefully.
++ */
++out_of_memory:
++ printk("Out of memory\n");
++ up_read(&mm->mmap_sem);
++ if (current->pid == 1) {
++ yield();
++ down_read(&mm->mmap_sem);
++ goto survive;
++ }
++ printk("VM: Killing process %s\n", tsk->comm);
++ if (user_mode(regs))
++ do_exit(SIGKILL);
++ goto no_context;
++
++do_sigbus:
++ up_read(&mm->mmap_sem);
++
++ /*
++ * Send a sigbus, regardless of whether we were in kernel or
++ * user mode.
++ */
++ /* address, error_code, trap_no, ... */
++#ifdef DEBUG
++ show_regs(regs);
++ dump_code(regs->pc);
++#endif
++ pr_debug("Sending SIGBUS to PID %d...\n", tsk->pid);
++ force_sig(SIGBUS, tsk);
++
++ /* Kernel mode? Handle exceptions or die */
++ if (!user_mode(regs))
++ goto no_context;
++}
++
++asmlinkage void do_bus_error(unsigned long addr, int write_access,
++ struct pt_regs *regs)
++{
++ printk(KERN_ALERT
++ "Bus error at physical address 0x%08lx (%s access)\n",
++ addr, write_access ? "write" : "read");
++ printk(KERN_INFO "DTLB dump:\n");
++ dump_dtlb();
++ die("Bus Error", regs, write_access);
++ do_exit(SIGKILL);
++}
++
++/*
++ * This functionality is currently not possible to implement because
++ * we're using segmentation to ensure a fixed mapping of the kernel
++ * virtual address space.
++ *
++ * It would be possible to implement this, but it would require us to
++ * disable segmentation at startup and load the kernel mappings into
++ * the TLB like any other pages. There will be lots of trickery to
++ * avoid recursive invocation of the TLB miss handler, though...
++ */
++#ifdef CONFIG_DEBUG_PAGEALLOC
++void kernel_map_pages(struct page *page, int numpages, int enable)
++{
++
++}
++EXPORT_SYMBOL(kernel_map_pages);
++#endif
+diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
+new file mode 100644
+index 0000000..70da689
+--- /dev/null
++++ b/arch/avr32/mm/init.c
+@@ -0,0 +1,480 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/swap.h>
++#include <linux/init.h>
++#include <linux/initrd.h>
++#include <linux/mmzone.h>
++#include <linux/bootmem.h>
++#include <linux/pagemap.h>
++#include <linux/pfn.h>
++#include <linux/nodemask.h>
++
++#include <asm/page.h>
++#include <asm/mmu_context.h>
++#include <asm/tlb.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/setup.h>
++#include <asm/sections.h>
++
++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
++
++pgd_t swapper_pg_dir[PTRS_PER_PGD];
++
++struct page *empty_zero_page;
++
++/*
++ * Cache of MMU context last used.
++ */
++unsigned long mmu_context_cache = NO_CONTEXT;
++
++#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
++#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn)
++
++void show_mem(void)
++{
++ int total = 0, reserved = 0, cached = 0;
++ int slab = 0, free = 0, shared = 0;
++ pg_data_t *pgdat;
++
++ printk("Mem-info:\n");
++ show_free_areas();
++
++ for_each_online_pgdat(pgdat) {
++ struct page *page, *end;
++
++ page = pgdat->node_mem_map;
++ end = page + pgdat->node_spanned_pages;
++
++ do {
++ total++;
++ if (PageReserved(page))
++ reserved++;
++ else if (PageSwapCache(page))
++ cached++;
++ else if (PageSlab(page))
++ slab++;
++ else if (!page_count(page))
++ free++;
++ else
++ shared += page_count(page) - 1;
++ page++;
++ } while (page < end);
++ }
++
++ printk ("%d pages of RAM\n", total);
++ printk ("%d free pages\n", free);
++ printk ("%d reserved pages\n", reserved);
++ printk ("%d slab pages\n", slab);
++ printk ("%d pages shared\n", shared);
++ printk ("%d pages swap cached\n", cached);
++}
++
++static void __init print_memory_map(const char *what,
++ struct tag_mem_range *mem)
++{
++ printk ("%s:\n", what);
++ for (; mem; mem = mem->next) {
++ printk (" %08lx - %08lx\n",
++ (unsigned long)mem->addr,
++ (unsigned long)(mem->addr + mem->size));
++ }
++}
++
++#define MAX_LOWMEM HIGHMEM_START
++#define MAX_LOWMEM_PFN PFN_DOWN(MAX_LOWMEM)
++
++/*
++ * Sort a list of memory regions in-place by ascending address.
++ *
++ * We're using bubble sort because we only have singly linked lists
++ * with few elements.
++ */
++static void __init sort_mem_list(struct tag_mem_range **pmem)
++{
++ int done;
++ struct tag_mem_range **a, **b;
++
++ if (!*pmem)
++ return;
++
++ do {
++ done = 1;
++ a = pmem, b = &(*pmem)->next;
++ while (*b) {
++ if ((*a)->addr > (*b)->addr) {
++ struct tag_mem_range *tmp;
++ tmp = (*b)->next;
++ (*b)->next = *a;
++ *a = *b;
++ *b = tmp;
++ done = 0;
++ }
++ a = &(*a)->next;
++ b = &(*a)->next;
++ }
++ } while (!done);
++}
++
++/*
++ * Find a free memory region large enough for storing the
++ * bootmem bitmap.
++ */
++static unsigned long __init
++find_bootmap_pfn(const struct tag_mem_range *mem)
++{
++ unsigned long bootmap_pages, bootmap_len;
++ unsigned long node_pages = PFN_UP(mem->size);
++ unsigned long bootmap_addr = mem->addr;
++ struct tag_mem_range *reserved = mem_reserved;
++ struct tag_mem_range *ramdisk = mem_ramdisk;
++ unsigned long kern_start = virt_to_phys(_stext);
++ unsigned long kern_end = virt_to_phys(_end);
++
++ bootmap_pages = bootmem_bootmap_pages(node_pages);
++ bootmap_len = bootmap_pages << PAGE_SHIFT;
++
++ /*
++ * Find a large enough region without reserved pages for
++ * storing the bootmem bitmap. We can take advantage of the
++ * fact that all lists have been sorted.
++ *
++ * We have to check explicitly reserved regions as well as the
++ * kernel image and any RAMDISK images...
++ *
++ * Oh, and we have to make sure we don't overwrite the taglist
++ * since we're going to use it until the bootmem allocator is
++ * fully up and running.
++ */
++ while (1) {
++ if ((bootmap_addr < kern_end) &&
++ ((bootmap_addr + bootmap_len) > kern_start))
++ bootmap_addr = kern_end;
++
++ while (reserved &&
++ (bootmap_addr >= (reserved->addr + reserved->size)))
++ reserved = reserved->next;
++
++ if (reserved &&
++ ((bootmap_addr + bootmap_len) >= reserved->addr)) {
++ bootmap_addr = reserved->addr + reserved->size;
++ continue;
++ }
++
++ while (ramdisk &&
++ (bootmap_addr >= (ramdisk->addr + ramdisk->size)))
++ ramdisk = ramdisk->next;
++
++ if (!ramdisk ||
++ ((bootmap_addr + bootmap_len) < ramdisk->addr))
++ break;
++
++ bootmap_addr = ramdisk->addr + ramdisk->size;
++ }
++
++ if ((PFN_UP(bootmap_addr) + bootmap_len) >= (mem->addr + mem->size))
++ return ~0UL;
++
++ return PFN_UP(bootmap_addr);
++}
++
++void __init setup_bootmem(void)
++{
++ unsigned bootmap_size;
++ unsigned long first_pfn, bootmap_pfn, pages;
++ unsigned long max_pfn, max_low_pfn;
++ unsigned long kern_start = virt_to_phys(_stext);
++ unsigned long kern_end = virt_to_phys(_end);
++ unsigned node = 0;
++ struct tag_mem_range *bank, *res;
++
++ sort_mem_list(&mem_phys);
++ sort_mem_list(&mem_reserved);
++
++ print_memory_map("Physical memory", mem_phys);
++ print_memory_map("Reserved memory", mem_reserved);
++
++ nodes_clear(node_online_map);
++
++ if (mem_ramdisk) {
++#ifdef CONFIG_BLK_DEV_INITRD
++ initrd_start = (unsigned long)__va(mem_ramdisk->addr);
++ initrd_end = initrd_start + mem_ramdisk->size;
++
++ print_memory_map("RAMDISK images", mem_ramdisk);
++ if (mem_ramdisk->next)
++ printk(KERN_WARNING
++ "Warning: Only the first RAMDISK image "
++ "will be used\n");
++ sort_mem_list(&mem_ramdisk);
++#else
++ printk(KERN_WARNING "RAM disk image present, but "
++ "no initrd support in kernel!\n");
++#endif
++ }
++
++ if (mem_phys->next)
++ printk(KERN_WARNING "Only using first memory bank\n");
++
++ for (bank = mem_phys; bank; bank = NULL) {
++ first_pfn = PFN_UP(bank->addr);
++ max_low_pfn = max_pfn = PFN_DOWN(bank->addr + bank->size);
++ bootmap_pfn = find_bootmap_pfn(bank);
++ if (bootmap_pfn > max_pfn)
++ panic("No space for bootmem bitmap!\n");
++
++ if (max_low_pfn > MAX_LOWMEM_PFN) {
++ max_low_pfn = MAX_LOWMEM_PFN;
++#ifndef CONFIG_HIGHMEM
++ /*
++ * Lowmem is memory that can be addressed
++ * directly through P1/P2
++ */
++ printk(KERN_WARNING
++ "Node %u: Only %ld MiB of memory will be used.\n",
++ node, MAX_LOWMEM >> 20);
++ printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
++#else
++#error HIGHMEM is not supported by AVR32 yet
++#endif
++ }
++
++ /* Initialize the boot-time allocator with low memory only. */
++ bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn,
++ first_pfn, max_low_pfn);
++
++ printk("Node %u: bdata = %p, bdata->node_bootmem_map = %p\n",
++ node, NODE_DATA(node)->bdata,
++ NODE_DATA(node)->bdata->node_bootmem_map);
++
++ /*
++ * Register fully available RAM pages with the bootmem
++ * allocator.
++ */
++ pages = max_low_pfn - first_pfn;
++ free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn),
++ PFN_PHYS(pages));
++
++ /*
++ * Reserve space for the kernel image (if present in
++ * this node)...
++ */
++ if ((kern_start >= PFN_PHYS(first_pfn)) &&
++ (kern_start < PFN_PHYS(max_pfn))) {
++ printk("Node %u: Kernel image %08lx - %08lx\n",
++ node, kern_start, kern_end);
++ reserve_bootmem_node(NODE_DATA(node), kern_start,
++ kern_end - kern_start);
++ }
++
++ /* ...the bootmem bitmap... */
++ reserve_bootmem_node(NODE_DATA(node),
++ PFN_PHYS(bootmap_pfn),
++ bootmap_size);
++
++ /* ...any RAMDISK images... */
++ for (res = mem_ramdisk; res; res = res->next) {
++ if (res->addr > PFN_PHYS(max_pfn))
++ break;
++
++ if (res->addr >= PFN_PHYS(first_pfn)) {
++ printk("Node %u: RAMDISK %08lx - %08lx\n",
++ node,
++ (unsigned long)res->addr,
++ (unsigned long)(res->addr + res->size));
++ reserve_bootmem_node(NODE_DATA(node),
++ res->addr, res->size);
++ }
++ }
++
++ /* ...and any other reserved regions. */
++ for (res = mem_reserved; res; res = res->next) {
++ if (res->addr > PFN_PHYS(max_pfn))
++ break;
++
++ if (res->addr >= PFN_PHYS(first_pfn)) {
++ printk("Node %u: Reserved %08lx - %08lx\n",
++ node,
++ (unsigned long)res->addr,
++ (unsigned long)(res->addr + res->size));
++ reserve_bootmem_node(NODE_DATA(node),
++ res->addr, res->size);
++ }
++ }
++
++ node_set_online(node);
++ }
++}
++
++/*
++ * paging_init() sets up the page tables
++ *
++ * This routine also unmaps the page at virtual kernel address 0, so
++ * that we can trap those pesky NULL-reference errors in the kernel.
++ */
++void __init paging_init(void)
++{
++ extern unsigned long _evba;
++ void *zero_page;
++ int nid;
++
++ /*
++ * Make sure we can handle exceptions before enabling
++ * paging. Not that we should ever _get_ any exceptions this
++ * early, but you never know...
++ */
++ printk("Exception vectors start at %p\n", &_evba);
++ sysreg_write(EVBA, (unsigned long)&_evba);
++
++ /*
++ * Since we are ready to handle exceptions now, we should let
++ * the CPU generate them...
++ */
++ __asm__ __volatile__ ("csrf %0" : : "i"(SR_EM_BIT));
++
++ /*
++ * Allocate the zero page. The allocator will panic if it
++ * can't satisfy the request, so no need to check.
++ */
++ zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0),
++ PAGE_SIZE);
++
++ {
++ pgd_t *pg_dir;
++ int i;
++
++ pg_dir = swapper_pg_dir;
++ sysreg_write(PTBR, (unsigned long)pg_dir);
++
++ for (i = 0; i < PTRS_PER_PGD; i++)
++ pgd_val(pg_dir[i]) = 0;
++
++ enable_mmu();
++ printk ("CPU: Paging enabled\n");
++ }
++
++ for_each_online_node(nid) {
++ pg_data_t *pgdat = NODE_DATA(nid);
++ unsigned long zones_size[MAX_NR_ZONES];
++ unsigned long low, start_pfn;
++
++ start_pfn = pgdat->bdata->node_boot_start;
++ start_pfn >>= PAGE_SHIFT;
++ low = pgdat->bdata->node_low_pfn;
++
++ memset(zones_size, 0, sizeof(zones_size));
++ zones_size[ZONE_NORMAL] = low - start_pfn;
++
++ printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n",
++ nid, start_pfn, low);
++
++ free_area_init_node(nid, pgdat, zones_size, start_pfn, NULL);
++
++ printk("Node %u: mem_map starts at %p\n",
++ pgdat->node_id, pgdat->node_mem_map);
++ }
++
++ mem_map = NODE_DATA(0)->node_mem_map;
++
++ memset(zero_page, 0, PAGE_SIZE);
++ empty_zero_page = virt_to_page(zero_page);
++ flush_dcache_page(empty_zero_page);
++}
++
++void __init mem_init(void)
++{
++ int codesize, reservedpages, datasize, initsize;
++ int nid, i;
++
++ reservedpages = 0;
++ high_memory = NULL;
++
++ /* this will put all low memory onto the freelists */
++ for_each_online_node(nid) {
++ pg_data_t *pgdat = NODE_DATA(nid);
++ unsigned long node_pages = 0;
++ void *node_high_memory;
++
++ num_physpages += pgdat->node_present_pages;
++
++ if (pgdat->node_spanned_pages != 0)
++ node_pages = free_all_bootmem_node(pgdat);
++
++ totalram_pages += node_pages;
++
++ for (i = 0; i < node_pages; i++)
++ if (PageReserved(pgdat->node_mem_map + i))
++ reservedpages++;
++
++ node_high_memory = (void *)((pgdat->node_start_pfn
++ + pgdat->node_spanned_pages)
++ << PAGE_SHIFT);
++ if (node_high_memory > high_memory)
++ high_memory = node_high_memory;
++ }
++
++ max_mapnr = MAP_NR(high_memory);
++
++ codesize = (unsigned long)_etext - (unsigned long)_text;
++ datasize = (unsigned long)_edata - (unsigned long)_data;
++ initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
++
++ printk ("Memory: %luk/%luk available (%dk kernel code, "
++ "%dk reserved, %dk data, %dk init)\n",
++ (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10),
++ totalram_pages << (PAGE_SHIFT - 10),
++ codesize >> 10,
++ reservedpages << (PAGE_SHIFT - 10),
++ datasize >> 10,
++ initsize >> 10);
++}
++
++static inline void free_area(unsigned long addr, unsigned long end, char *s)
++{
++ unsigned int size = (end - addr) >> 10;
++
++ for (; addr < end; addr += PAGE_SIZE) {
++ struct page *page = virt_to_page(addr);
++ ClearPageReserved(page);
++ init_page_count(page);
++ free_page(addr);
++ totalram_pages++;
++ }
++
++ if (size && s)
++ printk(KERN_INFO "Freeing %s memory: %dK (%lx - %lx)\n",
++ s, size, end - (size << 10), end);
++}
++
++void free_initmem(void)
++{
++ free_area((unsigned long)__init_begin, (unsigned long)__init_end,
++ "init");
++}
++
++#ifdef CONFIG_BLK_DEV_INITRD
++
++static int keep_initrd;
++
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++ if (!keep_initrd)
++ free_area(start, end, "initrd");
++}
++
++static int __init keepinitrd_setup(char *__unused)
++{
++ keep_initrd = 1;
++ return 1;
++}
++
++__setup("keepinitrd", keepinitrd_setup);
++#endif
+diff --git a/arch/avr32/mm/ioremap.c b/arch/avr32/mm/ioremap.c
+new file mode 100644
+index 0000000..3437c82
+--- /dev/null
++++ b/arch/avr32/mm/ioremap.c
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/vmalloc.h>
++#include <linux/module.h>
++#include <linux/io.h>
++
++#include <asm/pgtable.h>
++#include <asm/addrspace.h>
++
++/*
++ * Re-map an arbitrary physical address space into the kernel virtual
++ * address space. Needed when the kernel wants to access physical
++ * memory directly.
++ */
++void __iomem *__ioremap(unsigned long phys_addr, size_t size,
++ unsigned long flags)
++{
++ unsigned long addr;
++ struct vm_struct *area;
++ unsigned long offset, last_addr;
++ pgprot_t prot;
++
++ /*
++ * Check if we can simply use the P4 segment. This area is
++ * uncacheable, so if caching/buffering is requested, we can't
++ * use it.
++ */
++ if ((phys_addr >= P4SEG) && (flags == 0))
++ return (void __iomem *)phys_addr;
++
++ /* Don't allow wraparound or zero size */
++ last_addr = phys_addr + size - 1;
++ if (!size || last_addr < phys_addr)
++ return NULL;
++
++ /*
++ * XXX: When mapping regular RAM, we'd better make damn sure
++ * it's never used for anything else. But this is really the
++ * caller's responsibility...
++ */
++ if (PHYSADDR(P2SEGADDR(phys_addr)) == phys_addr)
++ return (void __iomem *)P2SEGADDR(phys_addr);
++
++ /* Mappings have to be page-aligned */
++ offset = phys_addr & ~PAGE_MASK;
++ phys_addr &= PAGE_MASK;
++ size = PAGE_ALIGN(last_addr + 1) - phys_addr;
++
++ prot = __pgprot(_PAGE_PRESENT | _PAGE_GLOBAL | _PAGE_RW | _PAGE_DIRTY
++ | _PAGE_ACCESSED | _PAGE_TYPE_SMALL | flags);
++
++ /*
++ * Ok, go for it..
++ */
++ area = get_vm_area(size, VM_IOREMAP);
++ if (!area)
++ return NULL;
++ area->phys_addr = phys_addr;
++ addr = (unsigned long )area->addr;
++ if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
++ vunmap((void *)addr);
++ return NULL;
++ }
++
++ return (void __iomem *)(offset + (char *)addr);
++}
++EXPORT_SYMBOL(__ioremap);
++
++void __iounmap(void __iomem *addr)
++{
++ struct vm_struct *p;
++
++ if ((unsigned long)addr >= P4SEG)
++ return;
++ if (PXSEG(addr) == P2SEG)
++ return;
++
++ p = remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
++ if (unlikely(!p)) {
++ printk (KERN_ERR "iounmap: bad address %p\n", addr);
++ return;
++ }
++
++ kfree (p);
++}
++EXPORT_SYMBOL(__iounmap);
+diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
+new file mode 100644
+index 0000000..7b07305
+--- /dev/null
++++ b/arch/avr32/mm/tlb.c
+@@ -0,0 +1,380 @@
++/*
++ * AVR32 TLB operations
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#include <linux/mm.h>
++
++#include <asm/mmu_context.h>
++
++#define _TLBEHI_I 0x100
++
++void show_dtlb_entry(unsigned int index)
++{
++ unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ mmucr_save = sysreg_read(MMUCR);
++ tlbehi_save = sysreg_read(TLBEHI);
++ mmucr = mmucr_save & 0x13;
++ mmucr |= index << 14;
++ sysreg_write(MMUCR, mmucr);
++
++ asm volatile("tlbr" : : : "memory");
++ cpu_sync_pipeline();
++
++ tlbehi = sysreg_read(TLBEHI);
++ tlbelo = sysreg_read(TLBELO);
++
++ printk("%2u: %c %c %02x %05x %05x %o %o %c %c %c %c\n",
++ index,
++ (tlbehi & 0x200)?'1':'0',
++ (tlbelo & 0x100)?'1':'0',
++ (tlbehi & 0xff),
++ (tlbehi >> 12), (tlbelo >> 12),
++ (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
++ (tlbelo & 0x200)?'1':'0',
++ (tlbelo & 0x080)?'1':'0',
++ (tlbelo & 0x001)?'1':'0',
++ (tlbelo & 0x002)?'1':'0');
++
++ sysreg_write(MMUCR, mmucr_save);
++ sysreg_write(TLBEHI, tlbehi_save);
++ cpu_sync_pipeline();
++ local_irq_restore(flags);
++}
++
++void dump_dtlb(void)
++{
++ unsigned int i;
++
++ printk("ID V G ASID VPN PFN AP SZ C B W D\n");
++ for (i = 0; i < 32; i++)
++ show_dtlb_entry(i);
++}
++
++static unsigned long last_mmucr;
++
++static inline void set_replacement_pointer(unsigned shift)
++{
++ unsigned long mmucr, mmucr_save;
++
++ mmucr = mmucr_save = sysreg_read(MMUCR);
++
++ /* Does this mapping already exist? */
++ __asm__ __volatile__(
++ " tlbs\n"
++ " mfsr %0, %1"
++ : "=r"(mmucr)
++ : "i"(SYSREG_MMUCR));
++
++ if (mmucr & SYSREG_BIT(MMUCR_N)) {
++ /* Not found -- pick a not-recently-accessed entry */
++ unsigned long rp;
++ unsigned long tlbar = sysreg_read(TLBARLO);
++
++ rp = 32 - fls(tlbar);
++ if (rp == 32) {
++ rp = 0;
++ sysreg_write(TLBARLO, -1L);
++ }
++
++ mmucr &= 0x13;
++ mmucr |= (rp << shift);
++
++ sysreg_write(MMUCR, mmucr);
++ }
++
++ last_mmucr = mmucr;
++}
++
++static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid)
++{
++ unsigned long vpn;
++
++ vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid;
++ sysreg_write(TLBEHI, vpn);
++ cpu_sync_pipeline();
++
++ set_replacement_pointer(14);
++
++ sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK);
++
++ /* Let's go */
++ asm volatile("nop\n\ttlbw" : : : "memory");
++ cpu_sync_pipeline();
++}
++
++void update_mmu_cache(struct vm_area_struct *vma,
++ unsigned long address, pte_t pte)
++{
++ unsigned long flags;
++
++ /* ptrace may call this routine */
++ if (vma && current->active_mm != vma->vm_mm)
++ return;
++
++ local_irq_save(flags);
++ update_dtlb(address, pte, get_asid());
++ local_irq_restore(flags);
++}
++
++void __flush_tlb_page(unsigned long asid, unsigned long page)
++{
++ unsigned long mmucr, tlbehi;
++
++ page |= asid;
++ sysreg_write(TLBEHI, page);
++ cpu_sync_pipeline();
++ asm volatile("tlbs");
++ mmucr = sysreg_read(MMUCR);
++
++ if (!(mmucr & SYSREG_BIT(MMUCR_N))) {
++ unsigned long tlbarlo;
++ unsigned long entry;
++
++ /* Clear the "valid" bit */
++ tlbehi = sysreg_read(TLBEHI);
++ tlbehi &= ~_TLBEHI_VALID;
++ sysreg_write(TLBEHI, tlbehi);
++ cpu_sync_pipeline();
++
++ /* mark the entry as "not accessed" */
++ entry = (mmucr >> 14) & 0x3f;
++ tlbarlo = sysreg_read(TLBARLO);
++ tlbarlo |= (0x80000000 >> entry);
++ sysreg_write(TLBARLO, tlbarlo);
++
++ /* update the entry with valid bit clear */
++ asm volatile("tlbw");
++ cpu_sync_pipeline();
++ }
++}
++
++void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
++{
++ if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) {
++ unsigned long flags, asid;
++ unsigned long saved_asid = MMU_NO_ASID;
++
++ asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
++ page &= PAGE_MASK;
++
++ local_irq_save(flags);
++ if (vma->vm_mm != current->mm) {
++ saved_asid = get_asid();
++ set_asid(asid);
++ }
++
++ __flush_tlb_page(asid, page);
++
++ if (saved_asid != MMU_NO_ASID)
++ set_asid(saved_asid);
++ local_irq_restore(flags);
++ }
++}
++
++void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end)
++{
++ struct mm_struct *mm = vma->vm_mm;
++
++ if (mm->context != NO_CONTEXT) {
++ unsigned long flags;
++ int size;
++
++ local_irq_save(flags);
++ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++ if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
++ mm->context = NO_CONTEXT;
++ if (mm == current->mm)
++ activate_context(mm);
++ } else {
++ unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK;
++ unsigned long saved_asid = MMU_NO_ASID;
++
++ start &= PAGE_MASK;
++ end += (PAGE_SIZE - 1);
++ end &= PAGE_MASK;
++ if (mm != current->mm) {
++ saved_asid = get_asid();
++ set_asid(asid);
++ }
++
++ while (start < end) {
++ __flush_tlb_page(asid, start);
++ start += PAGE_SIZE;
++ }
++ if (saved_asid != MMU_NO_ASID)
++ set_asid(saved_asid);
++ }
++ local_irq_restore(flags);
++ }
++}
++
++/*
++ * TODO: If this is only called for addresses > TASK_SIZE, we can probably
++ * skip the ASID stuff and just use the Global bit...
++ */
++void flush_tlb_kernel_range(unsigned long start, unsigned long end)
++{
++ unsigned long flags;
++ int size;
++
++ local_irq_save(flags);
++ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++ if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
++ flush_tlb_all();
++ } else {
++ unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK;
++ unsigned long saved_asid = get_asid();
++
++ start &= PAGE_MASK;
++ end += (PAGE_SIZE - 1);
++ end &= PAGE_MASK;
++ set_asid(asid);
++ while (start < end) {
++ __flush_tlb_page(asid, start);
++ start += PAGE_SIZE;
++ }
++ set_asid(saved_asid);
++ }
++ local_irq_restore(flags);
++}
++
++void flush_tlb_mm(struct mm_struct *mm)
++{
++ /* Invalidate all TLB entries of this process by getting a new ASID */
++ if (mm->context != NO_CONTEXT) {
++ unsigned long flags;
++
++ local_irq_save(flags);
++ mm->context = NO_CONTEXT;
++ if (mm == current->mm)
++ activate_context(mm);
++ local_irq_restore(flags);
++ }
++}
++
++void flush_tlb_all(void)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ sysreg_write(MMUCR, sysreg_read(MMUCR) | SYSREG_BIT(MMUCR_I));
++ local_irq_restore(flags);
++}
++
++#ifdef CONFIG_PROC_FS
++
++#include <linux/seq_file.h>
++#include <linux/proc_fs.h>
++#include <linux/init.h>
++
++static void *tlb_start(struct seq_file *tlb, loff_t *pos)
++{
++ static unsigned long tlb_index;
++
++ if (*pos >= 32)
++ return NULL;
++
++ tlb_index = 0;
++ return &tlb_index;
++}
++
++static void *tlb_next(struct seq_file *tlb, void *v, loff_t *pos)
++{
++ unsigned long *index = v;
++
++ if (*index >= 31)
++ return NULL;
++
++ ++*pos;
++ ++*index;
++ return index;
++}
++
++static void tlb_stop(struct seq_file *tlb, void *v)
++{
++
++}
++
++static int tlb_show(struct seq_file *tlb, void *v)
++{
++ unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
++ unsigned long flags;
++ unsigned long *index = v;
++
++ if (*index == 0)
++ seq_puts(tlb, "ID V G ASID VPN PFN AP SZ C B W D\n");
++
++ BUG_ON(*index >= 32);
++
++ local_irq_save(flags);
++ mmucr_save = sysreg_read(MMUCR);
++ tlbehi_save = sysreg_read(TLBEHI);
++ mmucr = mmucr_save & 0x13;
++ mmucr |= *index << 14;
++ sysreg_write(MMUCR, mmucr);
++
++ asm volatile("tlbr" : : : "memory");
++ cpu_sync_pipeline();
++
++ tlbehi = sysreg_read(TLBEHI);
++ tlbelo = sysreg_read(TLBELO);
++
++ sysreg_write(MMUCR, mmucr_save);
++ sysreg_write(TLBEHI, tlbehi_save);
++ cpu_sync_pipeline();
++ local_irq_restore(flags);
++
++ seq_printf(tlb, "%2lu: %c %c %02x %05x %05x %o %o %c %c %c %c\n",
++ *index,
++ (tlbehi & 0x200)?'1':'0',
++ (tlbelo & 0x100)?'1':'0',
++ (tlbehi & 0xff),
++ (tlbehi >> 12), (tlbelo >> 12),
++ (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
++ (tlbelo & 0x200)?'1':'0',
++ (tlbelo & 0x080)?'1':'0',
++ (tlbelo & 0x001)?'1':'0',
++ (tlbelo & 0x002)?'1':'0');
++
++ return 0;
++}
++
++static struct seq_operations tlb_ops = {
++ .start = tlb_start,
++ .next = tlb_next,
++ .stop = tlb_stop,
++ .show = tlb_show,
++};
++
++static int tlb_open(struct inode *inode, struct file *file)
++{
++ return seq_open(file, &tlb_ops);
++}
++
++static struct file_operations proc_tlb_operations = {
++ .open = tlb_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++static int __init proctlb_init(void)
++{
++ struct proc_dir_entry *entry;
++
++ entry = create_proc_entry("tlb", 0, NULL);
++ if (entry)
++ entry->proc_fops = &proc_tlb_operations;
++ return 0;
++}
++late_initcall(proctlb_init);
++#endif /* CONFIG_PROC_FS */
+diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
+index 8b50e84..734d5f3 100644
+--- a/arch/cris/arch-v10/drivers/Kconfig
++++ b/arch/cris/arch-v10/drivers/Kconfig
+@@ -550,7 +550,7 @@ config ETRAX_IDE
+ select BLK_DEV_IDEDMA
+ help
+ Enable this to get support for ATA/IDE.
+- You can't use paralell ports or SCSI ports
++ You can't use parallel ports or SCSI ports
+ at the same time.
+
+
+@@ -744,7 +744,7 @@ config ETRAX_PA_CHANGEABLE_BITS
+ default "FF"
+ help
+ This is a bitmask with information of what bits in PA that a user
+- can change change the value on using ioctl's.
++ can change the value on using ioctl's.
+ Bit set = changeable.
+ You probably want 00 here.
+
+diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
+index 9c22b76..ebacf14 100644
+--- a/arch/cris/arch-v10/kernel/time.c
++++ b/arch/cris/arch-v10/kernel/time.c
+@@ -227,7 +227,7 @@ timer_interrupt(int irq, void *dev_id, s
+
+ /* call the real timer interrupt handler */
+
+- do_timer(regs);
++ do_timer(1);
+
+ cris_do_profile(regs); /* Save profiling information */
+
+diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig
+index 22f0ddc..4f79d8e 100644
+--- a/arch/cris/arch-v32/Kconfig
++++ b/arch/cris/arch-v32/Kconfig
+@@ -162,7 +162,7 @@ config ETRAX_SDRAM_GRP1_CONFIG
+ depends on ETRAX_ARCH_V32
+ default "0"
+ help
+- SDRAM configuration for group 1. The defult value is 0
++ SDRAM configuration for group 1. The default value is 0
+ because group 1 is not used in the default configuration,
+ described in the help for SDRAM_GRP0_CONFIG.
+
+diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c
+index ba096eb..2449637 100644
+--- a/arch/cris/arch-v32/drivers/cryptocop.c
++++ b/arch/cris/arch-v32/drivers/cryptocop.c
+@@ -2051,7 +2051,6 @@ static void cryptocop_job_queue_close(vo
+ spin_lock_irqsave(&cryptocop_process_lock, process_flags);
+
+ /* Empty the job queue. */
+- spin_lock_irqsave(&cryptocop_process_lock, process_flags);
+ for (i = 0; i < cryptocop_prio_no_prios; i++){
+ if (!list_empty(&(cryptocop_job_queues[i].jobs))){
+ list_for_each_safe(node, tmp, &(cryptocop_job_queues[i].jobs)) {
+diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
+index 464ecae..2d0023f 100644
+--- a/arch/cris/arch-v32/kernel/smp.c
++++ b/arch/cris/arch-v32/kernel/smp.c
+@@ -28,6 +28,7 @@ spinlock_t cris_atomic_locks[] = { [0 ..
+
+ /* CPU masks */
+ cpumask_t cpu_online_map = CPU_MASK_NONE;
++EXPORT_SYMBOL(cpu_online_map);
+ cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+ EXPORT_SYMBOL(phys_cpu_present_map);
+
+diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
+index 50f3f93..be0a016 100644
+--- a/arch/cris/arch-v32/kernel/time.c
++++ b/arch/cris/arch-v32/kernel/time.c
+@@ -219,7 +219,7 @@ timer_interrupt(int irq, void *dev_id, s
+ return IRQ_HANDLED;
+
+ /* call the real timer interrupt handler */
+- do_timer(regs);
++ do_timer(1);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
+index 7af3d5d..ca8b45a 100644
+--- a/arch/cris/kernel/setup.c
++++ b/arch/cris/kernel/setup.c
+@@ -160,7 +160,7 @@ setup_arch(char **cmdline_p)
+ show_etrax_copyright();
+
+ /* Setup utsname */
+- strcpy(system_utsname.machine, cris_machine_name);
++ strcpy(init_utsname()->machine, cris_machine_name);
+ }
+
+ static void *c_start(struct seq_file *m, loff_t *pos)
+diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
+index 66ba889..0f9213c 100644
+--- a/arch/cris/kernel/time.c
++++ b/arch/cris/kernel/time.c
+@@ -37,7 +37,6 @@ int have_rtc; /* used to remember if we
+
+ #define TICK_SIZE tick
+
+-extern unsigned long wall_jiffies;
+ extern unsigned long loops_per_jiffy; /* init/main.c */
+ unsigned long loops_per_usec;
+
+@@ -58,11 +57,6 @@ void do_gettimeofday(struct timeval *tv)
+ local_irq_save(flags);
+ local_irq_disable();
+ usec = do_gettimeoffset();
+- {
+- unsigned long lost = jiffies - wall_jiffies;
+- if (lost)
+- usec += lost * (1000000 / HZ);
+- }
+
+ /*
+ * If time_adjust is negative then NTP is slowing the clock
+@@ -103,7 +97,6 @@ int do_settimeofday(struct timespec *tv)
+ * made, and then undo it!
+ */
+ nsec -= do_gettimeoffset() * NSEC_PER_USEC;
+- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c
+index 1780df3..8b0b934 100644
+--- a/arch/cris/mm/ioremap.c
++++ b/arch/cris/mm/ioremap.c
+@@ -10,93 +10,10 @@
+ */
+
+ #include <linux/vmalloc.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <asm/pgalloc.h>
+-#include <asm/cacheflush.h>
+-#include <asm/tlbflush.h>
+ #include <asm/arch/memmap.h>
+
+-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+- unsigned long phys_addr, pgprot_t prot)
+-{
+- unsigned long end;
+-
+- address &= ~PMD_MASK;
+- end = address + size;
+- if (end > PMD_SIZE)
+- end = PMD_SIZE;
+- if (address >= end)
+- BUG();
+- do {
+- if (!pte_none(*pte)) {
+- printk("remap_area_pte: page already exists\n");
+- BUG();
+- }
+- set_pte(pte, mk_pte_phys(phys_addr, prot));
+- address += PAGE_SIZE;
+- phys_addr += PAGE_SIZE;
+- pte++;
+- } while (address && (address < end));
+-}
+-
+-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+- unsigned long phys_addr, pgprot_t prot)
+-{
+- unsigned long end;
+-
+- address &= ~PGDIR_MASK;
+- end = address + size;
+- if (end > PGDIR_SIZE)
+- end = PGDIR_SIZE;
+- phys_addr -= address;
+- if (address >= end)
+- BUG();
+- do {
+- pte_t * pte = pte_alloc_kernel(pmd, address);
+- if (!pte)
+- return -ENOMEM;
+- remap_area_pte(pte, address, end - address, address + phys_addr, prot);
+- address = (address + PMD_SIZE) & PMD_MASK;
+- pmd++;
+- } while (address && (address < end));
+- return 0;
+-}
+-
+-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+- unsigned long size, pgprot_t prot)
+-{
+- int error;
+- pgd_t * dir;
+- unsigned long end = address + size;
+-
+- phys_addr -= address;
+- dir = pgd_offset(&init_mm, address);
+- flush_cache_all();
+- if (address >= end)
+- BUG();
+- do {
+- pud_t *pud;
+- pmd_t *pmd;
+-
+- error = -ENOMEM;
+- pud = pud_alloc(&init_mm, dir, address);
+- if (!pud)
+- break;
+- pmd = pmd_alloc(&init_mm, pud, address);
+-
+- if (!pmd)
+- break;
+- if (remap_area_pmd(pmd, address, end - address,
+- phys_addr + address, prot))
+- break;
+- error = 0;
+- address = (address + PGDIR_SIZE) & PGDIR_MASK;
+- dir++;
+- } while (address && (address < end));
+- flush_tlb_all();
+- return error;
+-}
+-
+ /*
+ * Generic mapping function (not visible outside):
+ */
+@@ -135,7 +52,8 @@ void __iomem * __ioremap_prot(unsigned l
+ if (!area)
+ return NULL;
+ addr = (void __iomem *)area->addr;
+- if (remap_area_pages((unsigned long) addr, phys_addr, size, prot)) {
++ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
++ phys_addr, prot)) {
+ vfree((void __force *)addr);
+ return NULL;
+ }
+diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
+index a601a17..cf1c446 100644
+--- a/arch/frv/Kconfig
++++ b/arch/frv/Kconfig
+@@ -27,7 +27,11 @@ config GENERIC_CALIBRATE_DELAY
+
+ config GENERIC_HARDIRQS
+ bool
+- default n
++ default y
++
++config GENERIC_HARDIRQS_NO__DO_IRQ
++ bool
++ default y
+
+ config GENERIC_TIME
+ bool
+@@ -82,6 +86,14 @@ config HIGHPTE
+ with a lot of RAM, this can be wasteful of precious low memory.
+ Setting this option will put user-space page tables in high memory.
+
++config LARGE_ALLOCS
++ bool "Allow allocating large blocks (> 1MB) of memory"
++ help
++ Allow the slab memory allocator to keep chains for very large memory
++ sizes - up to 32MB. You may need this if your system has a lot of
++ RAM, and you need to able to allocate very large contiguous chunks.
++ If unsure, say N.
++
+ source "mm/Kconfig"
+
+ choice
+@@ -251,6 +263,12 @@ config MB93091_NO_MB
+ endchoice
+ endif
+
++config FUJITSU_MB93493
++ bool "MB93493 Multimedia chip"
++ help
++ Select this option if the MB93493 multimedia chip is going to be
++ used.
++
+ choice
+ prompt "GP-Relative data support"
+ default GPREL_DATA_8
+diff --git a/arch/frv/Makefile b/arch/frv/Makefile
+index d163747..038e3a8 100644
+--- a/arch/frv/Makefile
++++ b/arch/frv/Makefile
+@@ -108,11 +108,8 @@ Image: vmlinux
+ bootstrap:
+ $(Q)$(MAKEBOOT) bootstrap
+
+-archmrproper:
+- $(Q)$(MAKE) $(build)=arch/frv/boot mrproper
+-
+ archclean:
+- $(Q)$(MAKE) $(build)=arch/frv/boot clean
++ $(Q)$(MAKE) $(clean)=arch/frv/boot
+
+ archdep: scripts/mkdep symlinks
+ $(Q)$(MAKE) $(build)=arch/frv/boot dep
+diff --git a/arch/frv/boot/Makefile b/arch/frv/boot/Makefile
+index 5dfc93f..dc6f038 100644
+--- a/arch/frv/boot/Makefile
++++ b/arch/frv/boot/Makefile
+@@ -8,6 +8,8 @@
+ # Copyright (C) 1995-2000 Russell King
+ #
+
++targets := Image zImage bootpImage
++
+ SYSTEM =$(TOPDIR)/$(LINUX)
+
+ ZTEXTADDR = 0x02080000
+@@ -66,7 +68,6 @@ zinstall: $(CONFIGURE) zImage
+ # miscellany
+ #
+ mrproper clean:
+- $(RM) Image zImage bootpImage
+ # @$(MAKE) -C compressed clean
+ # @$(MAKE) -C bootp clean
+
+diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile
+index 5a827b3..e8f73ed 100644
+--- a/arch/frv/kernel/Makefile
++++ b/arch/frv/kernel/Makefile
+@@ -8,17 +8,16 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o
+ extra-y:= head.o init_task.o vmlinux.lds
+
+ obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \
+- process.o traps.o ptrace.o signal.o dma.o \
++ kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
+ sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \
+- debug-stub.o irq.o irq-routing.o sleep.o uaccess.o
++ debug-stub.o irq.o sleep.o uaccess.o
+
+ obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o
+
+ obj-$(CONFIG_MB93091_VDK) += irq-mb93091.o
+-obj-$(CONFIG_MB93093_PDK) += irq-mb93093.o
+-obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o
+ obj-$(CONFIG_PM) += pm.o cmode.o
+ obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o
++obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o
+ obj-$(CONFIG_SYSCTL) += sysctl.o
+ obj-$(CONFIG_FUTEX) += futex.o
+ obj-$(CONFIG_MODULES) += module.o
+diff --git a/arch/frv/kernel/dma.c b/arch/frv/kernel/dma.c
+index f5de6cf..156184e 100644
+--- a/arch/frv/kernel/dma.c
++++ b/arch/frv/kernel/dma.c
+@@ -121,15 +121,14 @@ unsigned long frv_dma_inprogress;
+ /*
+ * DMA irq handler - determine channel involved, grab status and call real handler
+ */
+-static irqreturn_t dma_irq_handler(int irq, void *_channel, struct pt_regs *regs)
++static irqreturn_t dma_irq_handler(int irq, void *_channel)
+ {
+ struct frv_dma_channel *channel = _channel;
+
+ frv_clear_dma_inprogress(channel - frv_dma_channels);
+ return channel->handler(channel - frv_dma_channels,
+ __get_DMAC(channel->ioaddr, CSTR),
+- channel->data,
+- regs);
++ channel->data);
+
+ } /* end dma_irq_handler() */
+
+diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c
+index 1381abc..ad753c1 100644
+--- a/arch/frv/kernel/irq-mb93091.c
++++ b/arch/frv/kernel/irq-mb93091.c
+@@ -24,7 +24,6 @@
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+ #include <asm/irc-regs.h>
+-#include <asm/irq-routing.h>
+
+ #define __reg16(ADDR) (*(volatile unsigned short *)(ADDR))
+
+@@ -33,83 +32,131 @@
+ #define __get_IFR() ({ __reg16(0xffc0000c); })
+ #define __clr_IFR(M) do { __reg16(0xffc0000c) = ~(M); wmb(); } while(0)
+
+-static void frv_fpga_doirq(struct irq_source *source);
+-static void frv_fpga_control(struct irq_group *group, int irq, int on);
+
+-/*****************************************************************************/
+ /*
+- * FPGA IRQ multiplexor
++ * on-motherboard FPGA PIC operations
+ */
+-static struct irq_source frv_fpga[4] = {
+-#define __FPGA(X, M) \
+- [X] = { \
+- .muxname = "fpga."#X, \
+- .irqmask = M, \
+- .doirq = frv_fpga_doirq, \
+- }
++static void frv_fpga_mask(unsigned int irq)
++{
++ uint16_t imr = __get_IMR();
+
+- __FPGA(0, 0x0028),
+- __FPGA(1, 0x0050),
+- __FPGA(2, 0x1c00),
+- __FPGA(3, 0x6386),
+-};
++ imr |= 1 << (irq - IRQ_BASE_FPGA);
+
+-static struct irq_group frv_fpga_irqs = {
+- .first_irq = IRQ_BASE_FPGA,
+- .control = frv_fpga_control,
+- .sources = {
+- [ 1] = &frv_fpga[3],
+- [ 2] = &frv_fpga[3],
+- [ 3] = &frv_fpga[0],
+- [ 4] = &frv_fpga[1],
+- [ 5] = &frv_fpga[0],
+- [ 6] = &frv_fpga[1],
+- [ 7] = &frv_fpga[3],
+- [ 8] = &frv_fpga[3],
+- [ 9] = &frv_fpga[3],
+- [10] = &frv_fpga[2],
+- [11] = &frv_fpga[2],
+- [12] = &frv_fpga[2],
+- [13] = &frv_fpga[3],
+- [14] = &frv_fpga[3],
+- },
+-};
++ __set_IMR(imr);
++}
+
++static void frv_fpga_ack(unsigned int irq)
++{
++ __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
++}
+
+-static void frv_fpga_control(struct irq_group *group, int index, int on)
++static void frv_fpga_mask_ack(unsigned int irq)
+ {
+ uint16_t imr = __get_IMR();
+
+- if (on)
+- imr &= ~(1 << index);
+- else
+- imr |= 1 << index;
++ imr |= 1 << (irq - IRQ_BASE_FPGA);
++ __set_IMR(imr);
++
++ __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
++}
++
++static void frv_fpga_unmask(unsigned int irq)
++{
++ uint16_t imr = __get_IMR();
++
++ imr &= ~(1 << (irq - IRQ_BASE_FPGA));
+
+ __set_IMR(imr);
+ }
+
+-static void frv_fpga_doirq(struct irq_source *source)
++static struct irq_chip frv_fpga_pic = {
++ .name = "mb93091",
++ .ack = frv_fpga_ack,
++ .mask = frv_fpga_mask,
++ .mask_ack = frv_fpga_mask_ack,
++ .unmask = frv_fpga_unmask,
++};
++
++/*
++ * FPGA PIC interrupt handler
++ */
++static irqreturn_t fpga_interrupt(int irq, void *_mask)
+ {
+- uint16_t mask, imr;
++ uint16_t imr, mask = (unsigned long) _mask;
+
+ imr = __get_IMR();
+- mask = source->irqmask & ~imr & __get_IFR();
+- if (mask) {
+- __set_IMR(imr | mask);
+- __clr_IFR(mask);
+- distribute_irqs(&frv_fpga_irqs, mask);
+- __set_IMR(imr);
++ mask = mask & ~imr & __get_IFR();
++
++ /* poll all the triggered IRQs */
++ while (mask) {
++ int irq;
++
++ asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask));
++ irq = 31 - irq;
++ mask &= ~(1 << irq);
++
++ generic_handle_irq(IRQ_BASE_FPGA + irq);
+ }
++
++ return IRQ_HANDLED;
+ }
+
++/*
++ * define an interrupt action for each FPGA PIC output
++ * - use dev_id to indicate the FPGA PIC input to output mappings
++ */
++static struct irqaction fpga_irq[4] = {
++ [0] = {
++ .handler = fpga_interrupt,
++ .flags = IRQF_DISABLED | IRQF_SHARED,
++ .mask = CPU_MASK_NONE,
++ .name = "fpga.0",
++ .dev_id = (void *) 0x0028UL,
++ },
++ [1] = {
++ .handler = fpga_interrupt,
++ .flags = IRQF_DISABLED | IRQF_SHARED,
++ .mask = CPU_MASK_NONE,
++ .name = "fpga.1",
++ .dev_id = (void *) 0x0050UL,
++ },
++ [2] = {
++ .handler = fpga_interrupt,
++ .flags = IRQF_DISABLED | IRQF_SHARED,
++ .mask = CPU_MASK_NONE,
++ .name = "fpga.2",
++ .dev_id = (void *) 0x1c00UL,
++ },
++ [3] = {
++ .handler = fpga_interrupt,
++ .flags = IRQF_DISABLED | IRQF_SHARED,
++ .mask = CPU_MASK_NONE,
++ .name = "fpga.3",
++ .dev_id = (void *) 0x6386UL,
++ }
++};
++
++/*
++ * initialise the motherboard FPGA's PIC
++ */
+ void __init fpga_init(void)
+ {
++ int irq;
++
++ /* all PIC inputs are all set to be low-level driven, apart from the
++ * NMI button (15) which is fixed at falling-edge
++ */
+ __set_IMR(0x7ffe);
+ __clr_IFR(0x0000);
+
+- frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL0);
+- frv_irq_route_external(&frv_fpga[1], IRQ_CPU_EXTERNAL1);
+- frv_irq_route_external(&frv_fpga[2], IRQ_CPU_EXTERNAL2);
+- frv_irq_route_external(&frv_fpga[3], IRQ_CPU_EXTERNAL3);
+- frv_irq_set_group(&frv_fpga_irqs);
++ for (irq = IRQ_BASE_FPGA + 1; irq <= IRQ_BASE_FPGA + 14; irq++)
++ set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_level_irq);
++
++ set_irq_chip_and_handler(IRQ_FPGA_NMI, &frv_fpga_pic, handle_edge_irq);
++
++ /* the FPGA drives the first four external IRQ inputs on the CPU PIC */
++ setup_irq(IRQ_CPU_EXTERNAL0, &fpga_irq[0]);
++ setup_irq(IRQ_CPU_EXTERNAL1, &fpga_irq[1]);
++ setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[2]);
++ setup_irq(IRQ_CPU_EXTERNAL3, &fpga_irq[3]);
+ }
+diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c
+index 48b2a64..e0983f6 100644
+--- a/arch/frv/kernel/irq-mb93093.c
++++ b/arch/frv/kernel/irq-mb93093.c
+@@ -1,6 +1,6 @@
+ /* irq-mb93093.c: MB93093 FPGA interrupt handling
+ *
+- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -24,7 +24,6 @@
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+ #include <asm/irc-regs.h>
+-#include <asm/irq-routing.h>
+
+ #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR)))
+
+@@ -33,66 +32,102 @@
+ #define __get_IFR() ({ __reg16(0x02); })
+ #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0)
+
+-static void frv_fpga_doirq(struct irq_source *source);
+-static void frv_fpga_control(struct irq_group *group, int irq, int on);
+-
+-/*****************************************************************************/
+ /*
+- * FPGA IRQ multiplexor
++ * off-CPU FPGA PIC operations
+ */
+-static struct irq_source frv_fpga[4] = {
+-#define __FPGA(X, M) \
+- [X] = { \
+- .muxname = "fpga."#X, \
+- .irqmask = M, \
+- .doirq = frv_fpga_doirq, \
+- }
++static void frv_fpga_mask(unsigned int irq)
++{
++ uint16_t imr = __get_IMR();
+
+- __FPGA(0, 0x0700),
+-};
++ imr |= 1 << (irq - IRQ_BASE_FPGA);
++ __set_IMR(imr);
++}
+
+-static struct irq_group frv_fpga_irqs = {
+- .first_irq = IRQ_BASE_FPGA,
+- .control = frv_fpga_control,
+- .sources = {
+- [ 8] = &frv_fpga[0],
+- [ 9] = &frv_fpga[0],
+- [10] = &frv_fpga[0],
+- },
+-};
++static void frv_fpga_ack(unsigned int irq)
++{
++ __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
++}
++
++static void frv_fpga_mask_ack(unsigned int irq)
++{
++ uint16_t imr = __get_IMR();
+
++ imr |= 1 << (irq - IRQ_BASE_FPGA);
++ __set_IMR(imr);
++
++ __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
++}
+
+-static void frv_fpga_control(struct irq_group *group, int index, int on)
++static void frv_fpga_unmask(unsigned int irq)
+ {
+ uint16_t imr = __get_IMR();
+
+- if (on)
+- imr &= ~(1 << index);
+- else
+- imr |= 1 << index;
++ imr &= ~(1 << (irq - IRQ_BASE_FPGA));
+
+ __set_IMR(imr);
+ }
+
+-static void frv_fpga_doirq(struct irq_source *source)
++static struct irq_chip frv_fpga_pic = {
++ .name = "mb93093",
++ .ack = frv_fpga_ack,
++ .mask = frv_fpga_mask,
++ .mask_ack = frv_fpga_mask_ack,
++ .unmask = frv_fpga_unmask,
++ .end = frv_fpga_end,
++};
++
++/*
++ * FPGA PIC interrupt handler
++ */
++static irqreturn_t fpga_interrupt(int irq, void *_mask)
+ {
+- uint16_t mask, imr;
++ uint16_t imr, mask = (unsigned long) _mask;
+
+ imr = __get_IMR();
+- mask = source->irqmask & ~imr & __get_IFR();
+- if (mask) {
+- __set_IMR(imr | mask);
+- __clr_IFR(mask);
+- distribute_irqs(&frv_fpga_irqs, mask);
+- __set_IMR(imr);
++ mask = mask & ~imr & __get_IFR();
++
++ /* poll all the triggered IRQs */
++ while (mask) {
++ int irq;
++
++ asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask));
++ irq = 31 - irq;
++ mask &= ~(1 << irq);
++
++ generic_irq_handle(IRQ_BASE_FPGA + irq);
+ }
++
++ return IRQ_HANDLED;
+ }
+
++/*
++ * define an interrupt action for each FPGA PIC output
++ * - use dev_id to indicate the FPGA PIC input to output mappings
++ */
++static struct irqaction fpga_irq[1] = {
++ [0] = {
++ .handler = fpga_interrupt,
++ .flags = IRQF_DISABLED,
++ .mask = CPU_MASK_NONE,
++ .name = "fpga.0",
++ .dev_id = (void *) 0x0700UL,
++ }
++};
++
++/*
++ * initialise the motherboard FPGA's PIC
++ */
+ void __init fpga_init(void)
+ {
++ int irq;
++
++ /* all PIC inputs are all set to be edge triggered */
+ __set_IMR(0x0700);
+ __clr_IFR(0x0000);
+
+- frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL2);
+- frv_irq_set_group(&frv_fpga_irqs);
++ for (irq = IRQ_BASE_FPGA + 8; irq <= IRQ_BASE_FPGA + 10; irq++)
++ set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_edge_irq);
++
++ /* the FPGA drives external IRQ input #2 on the CPU PIC */
++ setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[0]);
+ }
+diff --git a/arch/frv/kernel/irq-mb93493.c b/arch/frv/kernel/irq-mb93493.c
+index 988d035..c157eef 100644
+--- a/arch/frv/kernel/irq-mb93493.c
++++ b/arch/frv/kernel/irq-mb93493.c
+@@ -1,6 +1,6 @@
+ /* irq-mb93493.c: MB93493 companion chip interrupt handler
+ *
+- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -24,84 +24,126 @@
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+ #include <asm/irc-regs.h>
+-#include <asm/irq-routing.h>
+ #include <asm/mb93493-irqs.h>
++#include <asm/mb93493-regs.h>
+
+-static void frv_mb93493_doirq(struct irq_source *source);
++#define IRQ_ROUTE_ONE(X) (X##_ROUTE << (X - IRQ_BASE_MB93493))
++
++#define IRQ_ROUTING \
++ (IRQ_ROUTE_ONE(IRQ_MB93493_VDC) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_VCC) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_OUT) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_I2C_0) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_I2C_1) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_USB) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_LOCAL_BUS) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_PCMCIA) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_GPIO) | \
++ IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_IN))
+
+-/*****************************************************************************/
+ /*
+- * MB93493 companion chip IRQ multiplexor
++ * daughter board PIC operations
++ * - there is no way to ACK interrupts in the MB93493 chip
+ */
+-static struct irq_source frv_mb93493[2] = {
+- [0] = {
+- .muxname = "mb93493.0",
+- .muxdata = __region_CS3 + 0x3d0,
+- .doirq = frv_mb93493_doirq,
+- .irqmask = 0x0000,
+- },
+- [1] = {
+- .muxname = "mb93493.1",
+- .muxdata = __region_CS3 + 0x3d4,
+- .doirq = frv_mb93493_doirq,
+- .irqmask = 0x0000,
+- },
+-};
+-
+-static void frv_mb93493_control(struct irq_group *group, int index, int on)
++static void frv_mb93493_mask(unsigned int irq)
+ {
+- struct irq_source *source;
+ uint32_t iqsr;
++ volatile void *piqsr;
+
+- if ((frv_mb93493[0].irqmask & (1 << index)))
+- source = &frv_mb93493[0];
++ if (IRQ_ROUTING & (1 << (irq - IRQ_BASE_MB93493)))
++ piqsr = __addr_MB93493_IQSR(1);
+ else
+- source = &frv_mb93493[1];
++ piqsr = __addr_MB93493_IQSR(0);
++
++ iqsr = readl(piqsr);
++ iqsr &= ~(1 << (irq - IRQ_BASE_MB93493 + 16));
++ writel(iqsr, piqsr);
++}
+
+- iqsr = readl(source->muxdata);
+- if (on)
+- iqsr |= 1 << (index + 16);
++static void frv_mb93493_ack(unsigned int irq)
++{
++}
++
++static void frv_mb93493_unmask(unsigned int irq)
++{
++ uint32_t iqsr;
++ volatile void *piqsr;
++
++ if (IRQ_ROUTING & (1 << (irq - IRQ_BASE_MB93493)))
++ piqsr = __addr_MB93493_IQSR(1);
+ else
+- iqsr &= ~(1 << (index + 16));
++ piqsr = __addr_MB93493_IQSR(0);
+
+- writel(iqsr, source->muxdata);
++ iqsr = readl(piqsr);
++ iqsr |= 1 << (irq - IRQ_BASE_MB93493 + 16);
++ writel(iqsr, piqsr);
+ }
+
+-static struct irq_group frv_mb93493_irqs = {
+- .first_irq = IRQ_BASE_MB93493,
+- .control = frv_mb93493_control,
++static struct irq_chip frv_mb93493_pic = {
++ .name = "mb93093",
++ .ack = frv_mb93493_ack,
++ .mask = frv_mb93493_mask,
++ .mask_ack = frv_mb93493_mask,
++ .unmask = frv_mb93493_unmask,
+ };
+
+-static void frv_mb93493_doirq(struct irq_source *source)
++/*
++ * MB93493 PIC interrupt handler
++ */
++static irqreturn_t mb93493_interrupt(int irq, void *_piqsr)
+ {
+- uint32_t mask = readl(source->muxdata);
+- mask = mask & (mask >> 16) & 0xffff;
++ volatile void *piqsr = _piqsr;
++ uint32_t iqsr;
+
+- if (mask)
+- distribute_irqs(&frv_mb93493_irqs, mask);
+-}
++ iqsr = readl(piqsr);
++ iqsr = iqsr & (iqsr >> 16) & 0xffff;
+
+-static void __init mb93493_irq_route(int irq, int source)
+-{
+- frv_mb93493[source].irqmask |= 1 << (irq - IRQ_BASE_MB93493);
+- frv_mb93493_irqs.sources[irq - IRQ_BASE_MB93493] = &frv_mb93493[source];
++ /* poll all the triggered IRQs */
++ while (iqsr) {
++ int irq;
++
++ asm("scan %1,gr0,%0" : "=r"(irq) : "r"(iqsr));
++ irq = 31 - irq;
++ iqsr &= ~(1 << irq);
++
++ generic_handle_irq(IRQ_BASE_MB93493 + irq);
++ }
++
++ return IRQ_HANDLED;
+ }
+
+-void __init route_mb93493_irqs(void)
++/*
++ * define an interrupt action for each MB93493 PIC output
++ * - use dev_id to indicate the MB93493 PIC input to output mappings
++ */
++static struct irqaction mb93493_irq[2] = {
++ [0] = {
++ .handler = mb93493_interrupt,
++ .flags = IRQF_DISABLED | IRQF_SHARED,
++ .mask = CPU_MASK_NONE,
++ .name = "mb93493.0",
++ .dev_id = (void *) __addr_MB93493_IQSR(0),
++ },
++ [1] = {
++ .handler = mb93493_interrupt,
++ .flags = IRQF_DISABLED | IRQF_SHARED,
++ .mask = CPU_MASK_NONE,
++ .name = "mb93493.1",
++ .dev_id = (void *) __addr_MB93493_IQSR(1),
++ }
++};
++
++/*
++ * initialise the motherboard MB93493's PIC
++ */
++void __init mb93493_init(void)
+ {
+- frv_irq_route_external(&frv_mb93493[0], IRQ_CPU_MB93493_0);
+- frv_irq_route_external(&frv_mb93493[1], IRQ_CPU_MB93493_1);
+-
+- frv_irq_set_group(&frv_mb93493_irqs);
+-
+- mb93493_irq_route(IRQ_MB93493_VDC, IRQ_MB93493_VDC_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_VCC, IRQ_MB93493_VCC_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_AUDIO_IN, IRQ_MB93493_AUDIO_IN_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_I2C_0, IRQ_MB93493_I2C_0_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_I2C_1, IRQ_MB93493_I2C_1_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_USB, IRQ_MB93493_USB_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_LOCAL_BUS, IRQ_MB93493_LOCAL_BUS_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_PCMCIA, IRQ_MB93493_PCMCIA_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_GPIO, IRQ_MB93493_GPIO_ROUTE);
+- mb93493_irq_route(IRQ_MB93493_AUDIO_OUT, IRQ_MB93493_AUDIO_OUT_ROUTE);
++ int irq;
++
++ for (irq = IRQ_BASE_MB93493 + 0; irq <= IRQ_BASE_MB93493 + 10; irq++)
++ set_irq_chip_and_handler(irq, &frv_mb93493_pic, handle_edge_irq);
++
++ /* the MB93493 drives external IRQ inputs on the CPU PIC */
++ setup_irq(IRQ_CPU_MB93493_0, &mb93493_irq[0]);
++ setup_irq(IRQ_CPU_MB93493_1, &mb93493_irq[1]);
+ }
+diff --git a/arch/frv/kernel/irq-routing.c b/arch/frv/kernel/irq-routing.c
+deleted file mode 100644
+index 53886ad..0000000
+--- a/arch/frv/kernel/irq-routing.c
++++ /dev/null
+@@ -1,291 +0,0 @@
+-/* irq-routing.c: IRQ routing
+- *
+- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+- * Written by David Howells (dhowells at 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/sched.h>
+-#include <linux/random.h>
+-#include <linux/init.h>
+-#include <linux/serial_reg.h>
+-#include <asm/io.h>
+-#include <asm/irq-routing.h>
+-#include <asm/irc-regs.h>
+-#include <asm/serial-regs.h>
+-#include <asm/dma.h>
+-
+-struct irq_level frv_irq_levels[16] = {
+- [0 ... 15] = {
+- .lock = SPIN_LOCK_UNLOCKED,
+- }
+-};
+-
+-struct irq_group *irq_groups[NR_IRQ_GROUPS];
+-
+-extern struct irq_group frv_cpu_irqs;
+-
+-void __init frv_irq_route(struct irq_source *source, int irqlevel)
+-{
+- source->level = &frv_irq_levels[irqlevel];
+- source->next = frv_irq_levels[irqlevel].sources;
+- frv_irq_levels[irqlevel].sources = source;
+-}
+-
+-void __init frv_irq_route_external(struct irq_source *source, int irq)
+-{
+- int irqlevel = 0;
+-
+- switch (irq) {
+- case IRQ_CPU_EXTERNAL0: irqlevel = IRQ_XIRQ0_LEVEL; break;
+- case IRQ_CPU_EXTERNAL1: irqlevel = IRQ_XIRQ1_LEVEL; break;
+- case IRQ_CPU_EXTERNAL2: irqlevel = IRQ_XIRQ2_LEVEL; break;
+- case IRQ_CPU_EXTERNAL3: irqlevel = IRQ_XIRQ3_LEVEL; break;
+- case IRQ_CPU_EXTERNAL4: irqlevel = IRQ_XIRQ4_LEVEL; break;
+- case IRQ_CPU_EXTERNAL5: irqlevel = IRQ_XIRQ5_LEVEL; break;
+- case IRQ_CPU_EXTERNAL6: irqlevel = IRQ_XIRQ6_LEVEL; break;
+- case IRQ_CPU_EXTERNAL7: irqlevel = IRQ_XIRQ7_LEVEL; break;
+- default: BUG();
+- }
+-
+- source->level = &frv_irq_levels[irqlevel];
+- source->next = frv_irq_levels[irqlevel].sources;
+- frv_irq_levels[irqlevel].sources = source;
+-}
+-
+-void __init frv_irq_set_group(struct irq_group *group)
+-{
+- irq_groups[group->first_irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP] = group;
+-}
+-
+-void distribute_irqs(struct irq_group *group, unsigned long irqmask)
+-{
+- struct irqaction *action;
+- int irq;
+-
+- while (irqmask) {
+- asm("scan %1,gr0,%0" : "=r"(irq) : "r"(irqmask));
+- if (irq < 0 || irq > 31)
+- asm volatile("break");
+- irq = 31 - irq;
+-
+- irqmask &= ~(1 << irq);
+- action = group->actions[irq];
+-
+- irq += group->first_irq;
+-
+- if (action) {
+- int status = 0;
+-
+-// if (!(action->flags & IRQF_DISABLED))
+-// local_irq_enable();
+-
+- do {
+- status |= action->flags;
+- action->handler(irq, action->dev_id, __frame);
+- action = action->next;
+- } while (action);
+-
+- if (status & IRQF_SAMPLE_RANDOM)
+- add_interrupt_randomness(irq);
+- local_irq_disable();
+- }
+- }
+-}
+-
+-/*****************************************************************************/
+-/*
+- * CPU UART interrupts
+- */
+-static void frv_cpuuart_doirq(struct irq_source *source)
+-{
+-// uint8_t iir = readb(source->muxdata + UART_IIR * 8);
+-// if ((iir & 0x0f) != UART_IIR_NO_INT)
+- distribute_irqs(&frv_cpu_irqs, source->irqmask);
+-}
+-
+-struct irq_source frv_cpuuart[2] = {
+-#define __CPUUART(X, A) \
+- [X] = { \
+- .muxname = "uart", \
+- .muxdata = (volatile void __iomem *)(unsigned long)A,\
+- .irqmask = 1 << IRQ_CPU_UART##X, \
+- .doirq = frv_cpuuart_doirq, \
+- }
+-
+- __CPUUART(0, UART0_BASE),
+- __CPUUART(1, UART1_BASE),
+-};
+-
+-/*****************************************************************************/
+-/*
+- * CPU DMA interrupts
+- */
+-static void frv_cpudma_doirq(struct irq_source *source)
+-{
+- uint32_t cstr = readl(source->muxdata + DMAC_CSTRx);
+- if (cstr & DMAC_CSTRx_INT)
+- distribute_irqs(&frv_cpu_irqs, source->irqmask);
+-}
+-
+-struct irq_source frv_cpudma[8] = {
+-#define __CPUDMA(X, A) \
+- [X] = { \
+- .muxname = "dma", \
+- .muxdata = (volatile void __iomem *)(unsigned long)A,\
+- .irqmask = 1 << IRQ_CPU_DMA##X, \
+- .doirq = frv_cpudma_doirq, \
+- }
+-
+- __CPUDMA(0, 0xfe000900),
+- __CPUDMA(1, 0xfe000980),
+- __CPUDMA(2, 0xfe000a00),
+- __CPUDMA(3, 0xfe000a80),
+- __CPUDMA(4, 0xfe001000),
+- __CPUDMA(5, 0xfe001080),
+- __CPUDMA(6, 0xfe001100),
+- __CPUDMA(7, 0xfe001180),
+-};
+-
+-/*****************************************************************************/
+-/*
+- * CPU timer interrupts - can't tell whether they've generated an interrupt or not
+- */
+-static void frv_cputimer_doirq(struct irq_source *source)
+-{
+- distribute_irqs(&frv_cpu_irqs, source->irqmask);
+-}
+-
+-struct irq_source frv_cputimer[3] = {
+-#define __CPUTIMER(X) \
+- [X] = { \
+- .muxname = "timer", \
+- .muxdata = NULL, \
+- .irqmask = 1 << IRQ_CPU_TIMER##X, \
+- .doirq = frv_cputimer_doirq, \
+- }
+-
+- __CPUTIMER(0),
+- __CPUTIMER(1),
+- __CPUTIMER(2),
+-};
+-
+-/*****************************************************************************/
+-/*
+- * external CPU interrupts - can't tell directly whether they've generated an interrupt or not
+- */
+-static void frv_cpuexternal_doirq(struct irq_source *source)
+-{
+- distribute_irqs(&frv_cpu_irqs, source->irqmask);
+-}
+-
+-struct irq_source frv_cpuexternal[8] = {
+-#define __CPUEXTERNAL(X) \
+- [X] = { \
+- .muxname = "ext", \
+- .muxdata = NULL, \
+- .irqmask = 1 << IRQ_CPU_EXTERNAL##X, \
+- .doirq = frv_cpuexternal_doirq, \
+- }
+-
+- __CPUEXTERNAL(0),
+- __CPUEXTERNAL(1),
+- __CPUEXTERNAL(2),
+- __CPUEXTERNAL(3),
+- __CPUEXTERNAL(4),
+- __CPUEXTERNAL(5),
+- __CPUEXTERNAL(6),
+- __CPUEXTERNAL(7),
+-};
+-
+-#define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16))
+-
+-struct irq_group frv_cpu_irqs = {
+- .sources = {
+- [IRQ_CPU_UART0] = &frv_cpuuart[0],
+- [IRQ_CPU_UART1] = &frv_cpuuart[1],
+- [IRQ_CPU_TIMER0] = &frv_cputimer[0],
+- [IRQ_CPU_TIMER1] = &frv_cputimer[1],
+- [IRQ_CPU_TIMER2] = &frv_cputimer[2],
+- [IRQ_CPU_DMA0] = &frv_cpudma[0],
+- [IRQ_CPU_DMA1] = &frv_cpudma[1],
+- [IRQ_CPU_DMA2] = &frv_cpudma[2],
+- [IRQ_CPU_DMA3] = &frv_cpudma[3],
+- [IRQ_CPU_DMA4] = &frv_cpudma[4],
+- [IRQ_CPU_DMA5] = &frv_cpudma[5],
+- [IRQ_CPU_DMA6] = &frv_cpudma[6],
+- [IRQ_CPU_DMA7] = &frv_cpudma[7],
+- [IRQ_CPU_EXTERNAL0] = &frv_cpuexternal[0],
+- [IRQ_CPU_EXTERNAL1] = &frv_cpuexternal[1],
+- [IRQ_CPU_EXTERNAL2] = &frv_cpuexternal[2],
+- [IRQ_CPU_EXTERNAL3] = &frv_cpuexternal[3],
+- [IRQ_CPU_EXTERNAL4] = &frv_cpuexternal[4],
+- [IRQ_CPU_EXTERNAL5] = &frv_cpuexternal[5],
+- [IRQ_CPU_EXTERNAL6] = &frv_cpuexternal[6],
+- [IRQ_CPU_EXTERNAL7] = &frv_cpuexternal[7],
+- },
+-};
+-
+-/*****************************************************************************/
+-/*
+- * route the CPU's interrupt sources
+- */
+-void __init route_cpu_irqs(void)
+-{
+- frv_irq_set_group(&frv_cpu_irqs);
+-
+- __set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 IRQ detect levels */
+- __set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 IRQ detect levels */
+-
+- /* route UART and error interrupts */
+- frv_irq_route(&frv_cpuuart[0], IRQ_UART0_LEVEL);
+- frv_irq_route(&frv_cpuuart[1], IRQ_UART1_LEVEL);
+-
+- set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL, IRQ_UART1_LEVEL, IRQ_UART0_LEVEL);
+-
+- /* route DMA channel interrupts */
+- frv_irq_route(&frv_cpudma[0], IRQ_DMA0_LEVEL);
+- frv_irq_route(&frv_cpudma[1], IRQ_DMA1_LEVEL);
+- frv_irq_route(&frv_cpudma[2], IRQ_DMA2_LEVEL);
+- frv_irq_route(&frv_cpudma[3], IRQ_DMA3_LEVEL);
+- frv_irq_route(&frv_cpudma[4], IRQ_DMA4_LEVEL);
+- frv_irq_route(&frv_cpudma[5], IRQ_DMA5_LEVEL);
+- frv_irq_route(&frv_cpudma[6], IRQ_DMA6_LEVEL);
+- frv_irq_route(&frv_cpudma[7], IRQ_DMA7_LEVEL);
+-
+- set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL, IRQ_DMA0_LEVEL);
+- set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL, IRQ_DMA4_LEVEL);
+-
+- /* route timer interrupts */
+- frv_irq_route(&frv_cputimer[0], IRQ_TIMER0_LEVEL);
+- frv_irq_route(&frv_cputimer[1], IRQ_TIMER1_LEVEL);
+- frv_irq_route(&frv_cputimer[2], IRQ_TIMER2_LEVEL);
+-
+- set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL);
+-
+- /* route external interrupts */
+- frv_irq_route(&frv_cpuexternal[0], IRQ_XIRQ0_LEVEL);
+- frv_irq_route(&frv_cpuexternal[1], IRQ_XIRQ1_LEVEL);
+- frv_irq_route(&frv_cpuexternal[2], IRQ_XIRQ2_LEVEL);
+- frv_irq_route(&frv_cpuexternal[3], IRQ_XIRQ3_LEVEL);
+- frv_irq_route(&frv_cpuexternal[4], IRQ_XIRQ4_LEVEL);
+- frv_irq_route(&frv_cpuexternal[5], IRQ_XIRQ5_LEVEL);
+- frv_irq_route(&frv_cpuexternal[6], IRQ_XIRQ6_LEVEL);
+- frv_irq_route(&frv_cpuexternal[7], IRQ_XIRQ7_LEVEL);
+-
+- set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL, IRQ_XIRQ4_LEVEL);
+- set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL, IRQ_XIRQ0_LEVEL);
+-
+-#if defined(CONFIG_MB93091_VDK)
+- __set_TM1(0x55550000); /* XIRQ7-0 all active low */
+-#elif defined(CONFIG_MB93093_PDK)
+- __set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */
+-#else
+-#error dont know external IRQ trigger levels for this setup
+-#endif
+-
+-} /* end route_cpu_irqs() */
+diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c
+index 0896701..87f360a 100644
+--- a/arch/frv/kernel/irq.c
++++ b/arch/frv/kernel/irq.c
+@@ -1,6 +1,6 @@
+ /* irq.c: FRV IRQ handling
+ *
+- * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
++ * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -9,13 +9,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-/*
+- * (mostly architecture independent, will move to kernel/irq.c in 2.5.)
+- *
+- * IRQs are in fact implemented a bit like signal handlers for the kernel.
+- * Naturally it's not a 1:1 relation, but there are similarities.
+- */
+-
+ #include <linux/ptrace.h>
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+@@ -43,19 +36,16 @@
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+ #include <asm/irc-regs.h>
+-#include <asm/irq-routing.h>
+ #include <asm/gdb-stub.h>
+
+-extern void __init fpga_init(void);
+-extern void __init route_mb93493_irqs(void);
+-
+-static void register_irq_proc (unsigned int irq);
++#define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16))
+
+-/*
+- * Special irq handlers.
+- */
++extern void __init fpga_init(void);
++#ifdef CONFIG_FUJITSU_MB93493
++extern void __init mb93493_init(void);
++#endif
+
+-irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) { return IRQ_HANDLED; }
++#define __reg16(ADDR) (*(volatile unsigned short *)(ADDR))
+
+ atomic_t irq_err_count;
+
+@@ -64,215 +54,86 @@ atomic_t irq_err_count;
+ */
+ int show_interrupts(struct seq_file *p, void *v)
+ {
+- struct irqaction *action;
+- struct irq_group *group;
++ int i = *(loff_t *) v, cpu;
++ struct irqaction * action;
+ unsigned long flags;
+- int level, grp, ix, i, j;
+-
+- i = *(loff_t *) v;
+-
+- switch (i) {
+- case 0:
+- seq_printf(p, " ");
+- for_each_online_cpu(j)
+- seq_printf(p, "CPU%d ",j);
+-
+- seq_putc(p, '\n');
+- break;
+
+- case 1 ... NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP:
+- local_irq_save(flags);
+-
+- grp = (i - 1) / NR_IRQ_ACTIONS_PER_GROUP;
+- group = irq_groups[grp];
+- if (!group)
+- goto skip;
+-
+- ix = (i - 1) % NR_IRQ_ACTIONS_PER_GROUP;
+- action = group->actions[ix];
+- if (!action)
+- goto skip;
+-
+- seq_printf(p, "%3d: ", i - 1);
+-
+-#ifndef CONFIG_SMP
+- seq_printf(p, "%10u ", kstat_irqs(i));
+-#else
+- for_each_online_cpu(j)
+- seq_printf(p, "%10u ", kstat_cpu(j).irqs[i - 1]);
+-#endif
+-
+- level = group->sources[ix]->level - frv_irq_levels;
+-
+- seq_printf(p, " %12s@%x", group->sources[ix]->muxname, level);
+- seq_printf(p, " %s", action->name);
+-
+- for (action = action->next; action; action = action->next)
+- seq_printf(p, ", %s", action->name);
++ if (i == 0) {
++ char cpuname[12];
+
++ seq_printf(p, " ");
++ for_each_present_cpu(cpu) {
++ sprintf(cpuname, "CPU%d", cpu);
++ seq_printf(p, " %10s", cpuname);
++ }
+ seq_putc(p, '\n');
+-skip:
+- local_irq_restore(flags);
+- break;
++ }
+
+- case NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP + 1:
+- seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+- break;
++ if (i < NR_IRQS) {
++ spin_lock_irqsave(&irq_desc[i].lock, flags);
++ action = irq_desc[i].action;
++ if (action) {
++ seq_printf(p, "%3d: ", i);
++ for_each_present_cpu(cpu)
++ seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
++ seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-");
++ seq_printf(p, " %s", action->name);
++ for (action = action->next;
++ action;
++ action = action->next)
++ seq_printf(p, ", %s", action->name);
++
++ seq_putc(p, '\n');
++ }
+
+- default:
+- break;
++ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
++ } else if (i == NR_IRQS) {
++ seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
+ }
+
+ return 0;
+ }
+
+-
+ /*
+- * Generic enable/disable code: this just calls
+- * down into the PIC-specific version for the actual
+- * hardware disable after having gotten the irq
+- * controller lock.
++ * on-CPU PIC operations
+ */
+-
+-/**
+- * disable_irq_nosync - disable an irq without waiting
+- * @irq: Interrupt to disable
+- *
+- * Disable the selected interrupt line. Disables and Enables are
+- * nested.
+- * Unlike disable_irq(), this function does not ensure existing
+- * instances of the IRQ handler have completed before returning.
+- *
+- * This function may be called from IRQ context.
+- */
+-
+-void disable_irq_nosync(unsigned int irq)
++static void frv_cpupic_ack(unsigned int irqlevel)
+ {
+- struct irq_source *source;
+- struct irq_group *group;
+- struct irq_level *level;
+- unsigned long flags;
+- int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1);
+-
+- group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP];
+- if (!group)
+- BUG();
+-
+- source = group->sources[idx];
+- if (!source)
+- BUG();
+-
+- level = source->level;
+-
+- spin_lock_irqsave(&level->lock, flags);
+-
+- if (group->control) {
+- if (!group->disable_cnt[idx]++)
+- group->control(group, idx, 0);
+- } else if (!level->disable_count++) {
+- __set_MASK(level - frv_irq_levels);
+- }
+-
+- spin_unlock_irqrestore(&level->lock, flags);
++ __clr_RC(irqlevel);
++ __clr_IRL();
+ }
+
+-EXPORT_SYMBOL(disable_irq_nosync);
+-
+-/**
+- * disable_irq - disable an irq and wait for completion
+- * @irq: Interrupt to disable
+- *
+- * Disable the selected interrupt line. Enables and Disables are
+- * nested.
+- * This function waits for any pending IRQ handlers for this interrupt
+- * to complete before returning. If you use this function while
+- * holding a resource the IRQ handler may need you will deadlock.
+- *
+- * This function may be called - with care - from IRQ context.
+- */
+-
+-void disable_irq(unsigned int irq)
++static void frv_cpupic_mask(unsigned int irqlevel)
+ {
+- disable_irq_nosync(irq);
+-
+-#ifdef CONFIG_SMP
+- if (!local_irq_count(smp_processor_id())) {
+- do {
+- barrier();
+- } while (irq_desc[irq].status & IRQ_INPROGRESS);
+- }
+-#endif
++ __set_MASK(irqlevel);
+ }
+
+-EXPORT_SYMBOL(disable_irq);
+-
+-/**
+- * enable_irq - enable handling of an irq
+- * @irq: Interrupt to enable
+- *
+- * Undoes the effect of one call to disable_irq(). If this
+- * matches the last disable, processing of interrupts on this
+- * IRQ line is re-enabled.
+- *
+- * This function may be called from IRQ context.
+- */
+-
+-void enable_irq(unsigned int irq)
++static void frv_cpupic_mask_ack(unsigned int irqlevel)
+ {
+- struct irq_source *source;
+- struct irq_group *group;
+- struct irq_level *level;
+- unsigned long flags;
+- int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1);
+- int count;
+-
+- group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP];
+- if (!group)
+- BUG();
+-
+- source = group->sources[idx];
+- if (!source)
+- BUG();
+-
+- level = source->level;
+-
+- spin_lock_irqsave(&level->lock, flags);
+-
+- if (group->control)
+- count = group->disable_cnt[idx];
+- else
+- count = level->disable_count;
+-
+- switch (count) {
+- case 1:
+- if (group->control) {
+- if (group->actions[idx])
+- group->control(group, idx, 1);
+- } else {
+- if (level->usage)
+- __clr_MASK(level - frv_irq_levels);
+- }
+- /* fall-through */
+-
+- default:
+- count--;
+- break;
+-
+- case 0:
+- printk("enable_irq(%u) unbalanced from %p\n", irq, __builtin_return_address(0));
+- }
++ __set_MASK(irqlevel);
++ __clr_RC(irqlevel);
++ __clr_IRL();
++}
+
+- if (group->control)
+- group->disable_cnt[idx] = count;
+- else
+- level->disable_count = count;
++static void frv_cpupic_unmask(unsigned int irqlevel)
++{
++ __clr_MASK(irqlevel);
++}
+
+- spin_unlock_irqrestore(&level->lock, flags);
++static void frv_cpupic_end(unsigned int irqlevel)
++{
++ __clr_MASK(irqlevel);
+ }
+
+-EXPORT_SYMBOL(enable_irq);
++static struct irq_chip frv_cpu_pic = {
++ .name = "cpu",
++ .ack = frv_cpupic_ack,
++ .mask = frv_cpupic_mask,
++ .mask_ack = frv_cpupic_mask_ack,
++ .unmask = frv_cpupic_unmask,
++ .end = frv_cpupic_end,
++};
+
+-/*****************************************************************************/
+ /*
+ * handles all normal device IRQ's
+ * - registers are referred to by the __frame variable (GR28)
+@@ -281,463 +142,65 @@ EXPORT_SYMBOL(enable_irq);
+ */
+ asmlinkage void do_IRQ(void)
+ {
+- struct irq_source *source;
+- int level, cpu;
+-
+ irq_enter();
+-
+- level = (__frame->tbr >> 4) & 0xf;
+- cpu = smp_processor_id();
+-
+- if ((unsigned long) __frame - (unsigned long) (current + 1) < 512)
+- BUG();
+-
+- __set_MASK(level);
+- __clr_RC(level);
+- __clr_IRL();
+-
+- kstat_this_cpu.irqs[level]++;
+-
+- for (source = frv_irq_levels[level].sources; source; source = source->next)
+- source->doirq(source);
+-
+- __clr_MASK(level);
+-
++ generic_handle_irq(__get_IRL());
+ irq_exit();
++}
+
+-} /* end do_IRQ() */
+-
+-/*****************************************************************************/
+ /*
+ * handles all NMIs when not co-opted by the debugger
+ * - registers are referred to by the __frame variable (GR28)
+ */
+ asmlinkage void do_NMI(void)
+ {
+-} /* end do_NMI() */
+-
+-/*****************************************************************************/
+-/**
+- * request_irq - allocate an interrupt line
+- * @irq: Interrupt line to allocate
+- * @handler: Function to be called when the IRQ occurs
+- * @irqflags: Interrupt type flags
+- * @devname: An ascii name for the claiming device
+- * @dev_id: A cookie passed back to the handler function
+- *
+- * This call allocates interrupt resources and enables the
+- * interrupt line and IRQ handling. From the point this
+- * call is made your handler function may be invoked. Since
+- * your handler function must clear any interrupt the board
+- * raises, you must take care both to initialise your hardware
+- * and to set up the interrupt handler in the right order.
+- *
+- * Dev_id must be globally unique. Normally the address of the
+- * device data structure is used as the cookie. Since the handler
+- * receives this value it makes sense to use it.
+- *
+- * If your interrupt is shared you must pass a non NULL dev_id
+- * as this is required when freeing the interrupt.
+- *
+- * Flags:
+- *
+- * IRQF_SHARED Interrupt is shared
+- *
+- * IRQF_DISABLED Disable local interrupts while processing
+- *
+- * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
+- *
+- */
+-
+-int request_irq(unsigned int irq,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+- unsigned long irqflags,
+- const char * devname,
+- void *dev_id)
+-{
+- int retval;
+- struct irqaction *action;
+-
+-#if 1
+- /*
+- * Sanity-check: shared interrupts should REALLY pass in
+- * a real dev-ID, otherwise we'll have trouble later trying
+- * to figure out which interrupt is which (messes up the
+- * interrupt freeing logic etc).
+- */
+- if (irqflags & IRQF_SHARED) {
+- if (!dev_id)
+- printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n",
+- devname, (&irq)[-1]);
+- }
+-#endif
+-
+- if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS)
+- return -EINVAL;
+- if (!handler)
+- return -EINVAL;
+-
+- action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+- if (!action)
+- return -ENOMEM;
+-
+- action->handler = handler;
+- action->flags = irqflags;
+- action->mask = CPU_MASK_NONE;
+- action->name = devname;
+- action->next = NULL;
+- action->dev_id = dev_id;
+-
+- retval = setup_irq(irq, action);
+- if (retval)
+- kfree(action);
+- return retval;
+-}
+-
+-EXPORT_SYMBOL(request_irq);
+-
+-/**
+- * free_irq - free an interrupt
+- * @irq: Interrupt line to free
+- * @dev_id: Device identity to free
+- *
+- * Remove an interrupt handler. The handler is removed and if the
+- * interrupt line is no longer in use by any driver it is disabled.
+- * On a shared IRQ the caller must ensure the interrupt is disabled
+- * on the card it drives before calling this function. The function
+- * does not return until any executing interrupts for this IRQ
+- * have completed.
+- *
+- * This function may be called from interrupt context.
+- *
+- * Bugs: Attempting to free an irq in a handler for the same irq hangs
+- * the machine.
+- */
+-
+-void free_irq(unsigned int irq, void *dev_id)
+-{
+- struct irq_source *source;
+- struct irq_group *group;
+- struct irq_level *level;
+- struct irqaction **p, **pp;
+- unsigned long flags;
+-
+- if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS)
+- return;
+-
+- group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP];
+- if (!group)
+- BUG();
+-
+- source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)];
+- if (!source)
+- BUG();
+-
+- level = source->level;
+- p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)];
+-
+- spin_lock_irqsave(&level->lock, flags);
+-
+- for (pp = p; *pp; pp = &(*pp)->next) {
+- struct irqaction *action = *pp;
+-
+- if (action->dev_id != dev_id)
+- continue;
+-
+- /* found it - remove from the list of entries */
+- *pp = action->next;
+-
+- level->usage--;
+-
+- if (p == pp && group->control)
+- group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 0);
+-
+- if (level->usage == 0)
+- __set_MASK(level - frv_irq_levels);
+-
+- spin_unlock_irqrestore(&level->lock,flags);
+-
+-#ifdef CONFIG_SMP
+- /* Wait to make sure it's not being used on another CPU */
+- while (desc->status & IRQ_INPROGRESS)
+- barrier();
+-#endif
+- kfree(action);
+- return;
+- }
+-}
+-
+-EXPORT_SYMBOL(free_irq);
+-
+-/*
+- * IRQ autodetection code..
+- *
+- * This depends on the fact that any interrupt that comes in on to an
+- * unassigned IRQ will cause GxICR_DETECT to be set
+- */
+-
+-static DECLARE_MUTEX(probe_sem);
+-
+-/**
+- * probe_irq_on - begin an interrupt autodetect
+- *
+- * Commence probing for an interrupt. The interrupts are scanned
+- * and a mask of potential interrupt lines is returned.
+- *
+- */
+-
+-unsigned long probe_irq_on(void)
+-{
+- down(&probe_sem);
+- return 0;
+ }
+
+-EXPORT_SYMBOL(probe_irq_on);
+-
+ /*
+- * Return a mask of triggered interrupts (this
+- * can handle only legacy ISA interrupts).
+- */
+-
+-/**
+- * probe_irq_mask - scan a bitmap of interrupt lines
+- * @val: mask of interrupts to consider
+- *
+- * Scan the ISA bus interrupt lines and return a bitmap of
+- * active interrupts. The interrupt probe logic state is then
+- * returned to its previous value.
+- *
+- * Note: we need to scan all the irq's even though we will
+- * only return ISA irq numbers - just so that we reset them
+- * all to a known state.
+- */
+-unsigned int probe_irq_mask(unsigned long xmask)
+-{
+- up(&probe_sem);
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(probe_irq_mask);
+-
+-/*
+- * Return the one interrupt that triggered (this can
+- * handle any interrupt source).
+- */
+-
+-/**
+- * probe_irq_off - end an interrupt autodetect
+- * @xmask: mask of potential interrupts (unused)
+- *
+- * Scans the unused interrupt lines and returns the line which
+- * appears to have triggered the interrupt. If no interrupt was
+- * found then zero is returned. If more than one interrupt is
+- * found then minus the first candidate is returned to indicate
+- * their is doubt.
+- *
+- * The interrupt probe logic state is returned to its previous
+- * value.
+- *
+- * BUGS: When used in a module (which arguably shouldnt happen)
+- * nothing prevents two IRQ probe callers from overlapping. The
+- * results of this are non-optimal.
++ * initialise the interrupt system
+ */
+-
+-int probe_irq_off(unsigned long xmask)
+-{
+- up(&probe_sem);
+- return -1;
+-}
+-
+-EXPORT_SYMBOL(probe_irq_off);
+-
+-/* this was setup_x86_irq but it seems pretty generic */
+-int setup_irq(unsigned int irq, struct irqaction *new)
+-{
+- struct irq_source *source;
+- struct irq_group *group;
+- struct irq_level *level;
+- struct irqaction **p, **pp;
+- unsigned long flags;
+-
+- group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP];
+- if (!group)
+- BUG();
+-
+- source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)];
+- if (!source)
+- BUG();
+-
+- level = source->level;
+-
+- p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)];
+-
+- /*
+- * Some drivers like serial.c use request_irq() heavily,
+- * so we have to be careful not to interfere with a
+- * running system.
+- */
+- if (new->flags & IRQF_SAMPLE_RANDOM) {
+- /*
+- * This function might sleep, we want to call it first,
+- * outside of the atomic block.
+- * Yes, this might clear the entropy pool if the wrong
+- * driver is attempted to be loaded, without actually
+- * installing a new handler, but is this really a problem,
+- * only the sysadmin is able to do this.
+- */
+- rand_initialize_irq(irq);
+- }
+-
+- /* must juggle the interrupt processing stuff with interrupts disabled */
+- spin_lock_irqsave(&level->lock, flags);
+-
+- /* can't share interrupts unless all parties agree to */
+- if (level->usage != 0 && !(level->flags & new->flags & IRQF_SHARED)) {
+- spin_unlock_irqrestore(&level->lock,flags);
+- return -EBUSY;
+- }
+-
+- /* add new interrupt at end of irq queue */
+- pp = p;
+- while (*pp)
+- pp = &(*pp)->next;
+-
+- *pp = new;
+-
+- level->usage++;
+- level->flags = new->flags;
+-
+- /* turn the interrupts on */
+- if (level->usage == 1)
+- __clr_MASK(level - frv_irq_levels);
+-
+- if (p == pp && group->control)
+- group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 1);
+-
+- spin_unlock_irqrestore(&level->lock, flags);
+- register_irq_proc(irq);
+- return 0;
+-}
+-
+-static struct proc_dir_entry * root_irq_dir;
+-static struct proc_dir_entry * irq_dir [NR_IRQS];
+-
+-#define HEX_DIGITS 8
+-
+-static unsigned int parse_hex_value (const char __user *buffer,
+- unsigned long count, unsigned long *ret)
+-{
+- unsigned char hexnum [HEX_DIGITS];
+- unsigned long value;
+- int i;
+-
+- if (!count)
+- return -EINVAL;
+- if (count > HEX_DIGITS)
+- count = HEX_DIGITS;
+- if (copy_from_user(hexnum, buffer, count))
+- return -EFAULT;
+-
+- /*
+- * Parse the first 8 characters as a hex string, any non-hex char
+- * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+- */
+- value = 0;
+-
+- for (i = 0; i < count; i++) {
+- unsigned int c = hexnum[i];
+-
+- switch (c) {
+- case '0' ... '9': c -= '0'; break;
+- case 'a' ... 'f': c -= 'a'-10; break;
+- case 'A' ... 'F': c -= 'A'-10; break;
+- default:
+- goto out;
+- }
+- value = (value << 4) | c;
+- }
+-out:
+- *ret = value;
+- return 0;
+-}
+-
+-
+-static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+- int count, int *eof, void *data)
+-{
+- unsigned long *mask = (unsigned long *) data;
+- if (count < HEX_DIGITS+1)
+- return -EINVAL;
+- return sprintf (page, "%08lx\n", *mask);
+-}
+-
+-static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
+- unsigned long count, void *data)
+-{
+- unsigned long *mask = (unsigned long *) data, full_count = count, err;
+- unsigned long new_value;
+-
+- show_state();
+- err = parse_hex_value(buffer, count, &new_value);
+- if (err)
+- return err;
+-
+- *mask = new_value;
+- return full_count;
+-}
+-
+-#define MAX_NAMELEN 10
+-
+-static void register_irq_proc (unsigned int irq)
+-{
+- char name [MAX_NAMELEN];
+-
+- if (!root_irq_dir || irq_dir[irq])
+- return;
+-
+- memset(name, 0, MAX_NAMELEN);
+- sprintf(name, "%d", irq);
+-
+- /* create /proc/irq/1234 */
+- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+-}
+-
+-unsigned long prof_cpu_mask = -1;
+-
+-void init_irq_proc (void)
++void __init init_IRQ(void)
+ {
+- struct proc_dir_entry *entry;
+- int i;
++ int level;
+
+- /* create /proc/irq */
+- root_irq_dir = proc_mkdir("irq", NULL);
++ for (level = 1; level <= 14; level++)
++ set_irq_chip_and_handler(level, &frv_cpu_pic,
++ handle_level_irq);
+
+- /* create /proc/irq/prof_cpu_mask */
+- entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+- if (!entry)
+- return;
++ set_irq_handler(IRQ_CPU_TIMER0, handle_edge_irq);
+
+- entry->nlink = 1;
+- entry->data = (void *)&prof_cpu_mask;
+- entry->read_proc = prof_cpu_mask_read_proc;
+- entry->write_proc = prof_cpu_mask_write_proc;
+-
+- /*
+- * Create entries for all existing IRQs.
++ /* set the trigger levels for internal interrupt sources
++ * - timers all falling-edge
++ * - ERR0 is rising-edge
++ * - all others are high-level
+ */
+- for (i = 0; i < NR_IRQS; i++)
+- register_irq_proc(i);
+-}
++ __set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 */
++ __set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 */
++
++ /* route internal interrupts */
++ set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL,
++ IRQ_DMA0_LEVEL);
++ set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL);
++ set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL,
++ IRQ_UART1_LEVEL, IRQ_UART0_LEVEL);
++ set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL,
++ IRQ_DMA4_LEVEL);
++
++ /* route external interrupts */
++ set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL,
++ IRQ_XIRQ4_LEVEL);
++ set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL,
++ IRQ_XIRQ0_LEVEL);
++
++#if defined(CONFIG_MB93091_VDK)
++ __set_TM1(0x55550000); /* XIRQ7-0 all active low */
++#elif defined(CONFIG_MB93093_PDK)
++ __set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */
++#else
++#error dont know external IRQ trigger levels for this setup
++#endif
+
+-/*****************************************************************************/
+-/*
+- * initialise the interrupt system
+- */
+-void __init init_IRQ(void)
+-{
+- route_cpu_irqs();
+ fpga_init();
+ #ifdef CONFIG_FUJITSU_MB93493
+- route_mb93493_irqs();
++ mb93493_init();
+ #endif
+-} /* end init_IRQ() */
++}
+diff --git a/arch/frv/kernel/kernel_execve.S b/arch/frv/kernel/kernel_execve.S
+new file mode 100644
+index 0000000..9b074a1
+--- /dev/null
++++ b/arch/frv/kernel/kernel_execve.S
+@@ -0,0 +1,33 @@
++/* in-kernel program execution
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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/linkage.h>
++#include <asm/unistd.h>
++
++###############################################################################
++#
++# Do a system call from kernel instead of calling sys_execve so we end up with
++# proper pt_regs.
++#
++# int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++#
++# On entry: GR8/GR9/GR10: arguments to function
++# On return: GR8: syscall return.
++#
++###############################################################################
++ .globl kernel_execve
++ .type kernel_execve, at function
++kernel_execve:
++ setlos __NR_execve,gr7
++ tira gr0,#0
++ bralr
++
++ .size kernel_execve,.-kernel_execve
+diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
+index af08ccd..a8c61da 100644
+--- a/arch/frv/kernel/setup.c
++++ b/arch/frv/kernel/setup.c
+@@ -31,7 +31,6 @@
+ #include <linux/serial_reg.h>
+
+ #include <asm/setup.h>
+-#include <asm/serial.h>
+ #include <asm/irq.h>
+ #include <asm/sections.h>
+ #include <asm/pgalloc.h>
+@@ -43,7 +42,6 @@
+ #include <asm/mb-regs.h>
+ #include <asm/mb93493-regs.h>
+ #include <asm/gdb-stub.h>
+-#include <asm/irq-routing.h>
+ #include <asm/io.h>
+
+ #ifdef CONFIG_BLK_DEV_INITRD
+diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c
+index 68a77fe..ed588d7 100644
+--- a/arch/frv/kernel/time.c
++++ b/arch/frv/kernel/time.c
+@@ -10,7 +10,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h> /* CONFIG_HEARTBEAT */
+ #include <linux/module.h>
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+@@ -26,7 +25,6 @@
+ #include <asm/timer-regs.h>
+ #include <asm/mb-regs.h>
+ #include <asm/mb86943a.h>
+-#include <asm/irq-routing.h>
+
+ #include <linux/timex.h>
+
+@@ -42,7 +40,7 @@ unsigned long __nongprelbss __dsu_clock_
+ unsigned long __nongprelbss __serial_clock_speed_HZ;
+ unsigned long __delay_loops_MHz;
+
+-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs *regs);
++static irqreturn_t timer_interrupt(int irq, void *dummy);
+
+ static struct irqaction timer_irq = {
+ timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL
+@@ -57,7 +55,7 @@ static inline int set_rtc_mmss(unsigned
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
++static irqreturn_t timer_interrupt(int irq, void *dummy)
+ {
+ /* last time the cmos clock got updated */
+ static long last_rtc_update = 0;
+@@ -71,9 +69,9 @@ static irqreturn_t timer_interrupt(int i
+ */
+ write_seqlock(&xtime_lock);
+
+- do_timer(regs);
+- update_process_times(user_mode(regs));
+- profile_tick(CPU_PROFILING, regs);
++ do_timer(1);
++ update_process_times(user_mode(get_irq_regs()));
++ profile_tick(CPU_PROFILING);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
+index f474534..9c1fb12 100644
+--- a/arch/frv/kernel/vmlinux.lds.S
++++ b/arch/frv/kernel/vmlinux.lds.S
+@@ -44,13 +44,7 @@ SECTIONS
+
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c
+index 2278c80..ba58752 100644
+--- a/arch/frv/mb93090-mb00/pci-irq.c
++++ b/arch/frv/mb93090-mb00/pci-irq.c
+@@ -15,7 +15,6 @@
+
+ #include <asm/io.h>
+ #include <asm/smp.h>
+-#include <asm/irq-routing.h>
+
+ #include "pci-frv.h"
+
+diff --git a/arch/frv/mm/init.c b/arch/frv/mm/init.c
+index b5b4286..3f3a0ed 100644
+--- a/arch/frv/mm/init.c
++++ b/arch/frv/mm/init.c
+@@ -98,7 +98,7 @@ void show_mem(void)
+ */
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+ /* allocate some pages for kernel housekeeping tasks */
+ empty_bad_page_table = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c
+index 1488b6a..1bfc77e 100644
+--- a/arch/h8300/kernel/ints.c
++++ b/arch/h8300/kernel/ints.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/h8300/platform/h8300h/ints.c
++ * linux/arch/h8300/kernel/ints.c
+ *
+ * Yoshinori Sato <ysato at users.sourceforge.jp>
+ *
+diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c
+index 0f61b7a..302a2df 100644
+--- a/arch/h8300/kernel/sys_h8300.c
++++ b/arch/h8300/kernel/sys_h8300.c
+@@ -25,6 +25,7 @@
+ #include <asm/cachectl.h>
+ #include <asm/traps.h>
+ #include <asm/ipc.h>
++#include <asm/unistd.h>
+
+ /*
+ * sys_pipe() is the normal C calling standard for creating
+@@ -280,3 +281,26 @@ asmlinkage void syscall_print(void *dumm
+ ((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0);
+ }
+ #endif
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register long res __asm__("er0");
++ register const char * _a __asm__("er1") = filename;
++ register void *_b __asm__("er2") = argv;
++ register void *_c __asm__("er3") = envp;
++ __asm__ __volatile__ ("mov.l %1,er0\n\t"
++ "trapa #0\n\t"
++ : "=r" (res)
++ : "g" (__NR_execve),
++ "g" (_a),
++ "g" (_b),
++ "g" (_c)
++ : "cc", "memory");
++ return res;
++}
++
++
+diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
+index 688a510..8abab3b 100644
+--- a/arch/h8300/kernel/time.c
++++ b/arch/h8300/kernel/time.c
+@@ -16,7 +16,6 @@
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+-#include <linux/config.h> /* CONFIG_HEARTBEAT */
+ #include <linux/errno.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+@@ -41,7 +40,7 @@ static void timer_interrupt(int irq, voi
+ /* may need to kick the hardware timer */
+ platform_timer_eoi();
+
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
+index 6406c38..756325d 100644
+--- a/arch/h8300/kernel/vmlinux.lds.S
++++ b/arch/h8300/kernel/vmlinux.lds.S
+@@ -118,13 +118,7 @@ SECTIONS
+ . = ALIGN(0x4) ;
+ ___setup_end = .;
+ ___initcall_start = .;
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ ___initcall_end = .;
+ ___con_initcall_start = .;
+ *(.con_initcall.init)
+diff --git a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
+index d3d40bd..e4f4199 100644
+--- a/arch/h8300/mm/init.c
++++ b/arch/h8300/mm/init.c
+@@ -138,7 +138,7 @@ void paging_init(void)
+ #endif
+
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+ zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT;
+ zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
+index b2751ea..8ff1c6f 100644
+--- a/arch/i386/Kconfig
++++ b/arch/i386/Kconfig
+@@ -166,7 +166,6 @@ config X86_VISWS
+
+ config X86_GENERICARCH
+ bool "Generic architecture (Summit, bigsmp, ES7000, default)"
+- depends on SMP
+ help
+ This option compiles in the Summit, bigsmp, ES7000, default subarchitectures.
+ It is intended for a generic binary kernel.
+@@ -263,7 +262,7 @@ source "kernel/Kconfig.preempt"
+
+ config X86_UP_APIC
+ bool "Local APIC support on uniprocessors"
+- depends on !SMP && !(X86_VISWS || X86_VOYAGER)
++ depends on !SMP && !(X86_VISWS || X86_VOYAGER || X86_GENERICARCH)
+ help
+ A local APIC (Advanced Programmable Interrupt Controller) is an
+ integrated interrupt controller in the CPU. If you have a single-CPU
+@@ -288,12 +287,12 @@ config X86_UP_IOAPIC
+
+ config X86_LOCAL_APIC
+ bool
+- depends on X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER)
++ depends on X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER) || X86_GENERICARCH
+ default y
+
+ config X86_IO_APIC
+ bool
+- depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER))
++ depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER)) || X86_GENERICARCH
+ default y
+
+ config X86_VISWS_APIC
+@@ -402,6 +401,7 @@ config X86_REBOOTFIXUPS
+
+ config MICROCODE
+ tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
++ select FW_LOADER
+ ---help---
+ If you say Y here and also to "/dev file system support" in the
+ 'File systems' section, you will be able to update the microcode on
+@@ -417,6 +417,11 @@ config MICROCODE
+ To compile this driver as a module, choose M here: the
+ module will be called microcode.
+
++config MICROCODE_OLD_INTERFACE
++ bool
++ depends on MICROCODE
++ default y
++
+ config X86_MSR
+ tristate "/dev/cpu/*/msr - Model-specific register support"
+ help
+@@ -494,7 +499,7 @@ config HIGHMEM64G
+ endchoice
+
+ choice
+- depends on EXPERIMENTAL && !X86_PAE
++ depends on EXPERIMENTAL
+ prompt "Memory split" if EMBEDDED
+ default VMSPLIT_3G
+ help
+@@ -516,6 +521,7 @@ choice
+ config VMSPLIT_3G
+ bool "3G/1G user/kernel split"
+ config VMSPLIT_3G_OPT
++ depends on !HIGHMEM
+ bool "3G/1G user/kernel split (for full 1G low memory)"
+ config VMSPLIT_2G
+ bool "2G/2G user/kernel split"
+@@ -598,12 +604,10 @@ config ARCH_SELECT_MEMORY_MODEL
+ def_bool y
+ depends on ARCH_SPARSEMEM_ENABLE
+
+-source "mm/Kconfig"
++config ARCH_POPULATES_NODE_MAP
++ def_bool y
+
+-config HAVE_ARCH_EARLY_PFN_TO_NID
+- bool
+- default y
+- depends on NUMA
++source "mm/Kconfig"
+
+ config HIGHPTE
+ bool "Allocate 3rd-level pagetables from highmem"
+@@ -678,7 +682,7 @@ config EFI
+ depends on ACPI
+ default n
+ ---help---
+- This enables the the kernel to boot on EFI platforms using
++ This enables the kernel to boot on EFI platforms using
+ system configuration information passed to it from the firmware.
+ This also enables the kernel to use any EFI runtime services that are
+ available (such as the EFI variable services).
+@@ -740,8 +744,7 @@ config SECCOMP
+ source kernel/Kconfig.hz
+
+ config KEXEC
+- bool "kexec system call (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ bool "kexec system call"
+ 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
+@@ -762,6 +765,13 @@ config CRASH_DUMP
+ depends on HIGHMEM
+ help
+ Generate crash dump after being started by kexec.
++ This should be normally only set in special crash dump kernels
++ which are loaded in the main kernel with kexec-tools into
++ a specially reserved region and then later executed after
++ a crash by kdump/kexec. The crash dump kernel must be compiled
++ to a memory address not used by the main kernel or BIOS using
++ PHYSICAL_START.
++ For more details see Documentation/kdump/kdump.txt
+
+ config PHYSICAL_START
+ hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+@@ -794,6 +804,7 @@ config HOTPLUG_CPU
+ config COMPAT_VDSO
+ bool "Compat VDSO support"
+ default y
++ depends on !PARAVIRT
+ help
+ Map the VDSO to the predictable old-style address too.
+ ---help---
+@@ -1131,7 +1142,7 @@ source "arch/i386/oprofile/Kconfig"
+
+ config KPROBES
+ bool "Kprobes (EXPERIMENTAL)"
+- depends on EXPERIMENTAL && MODULES
++ depends on KALLSYMS && EXPERIMENTAL && MODULES
+ help
+ Kprobes allows you to trap at almost any kernel address and
+ execute a callback function. register_kprobe() establishes
+diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
+index 21c9a4e..fc4f2ab 100644
+--- a/arch/i386/Kconfig.cpu
++++ b/arch/i386/Kconfig.cpu
+@@ -7,6 +7,7 @@ choice
+
+ config M386
+ bool "386"
++ depends on !UML
+ ---help---
+ This is the processor type of your CPU. This information is used for
+ optimizing purposes. In order to compile a kernel that can run on
+@@ -301,7 +302,7 @@ config X86_USE_PPRO_CHECKSUM
+
+ config X86_USE_3DNOW
+ bool
+- depends on MCYRIXIII || MK7 || MGEODE_LX
++ depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
+ default y
+
+ config X86_OOSTORE
+diff --git a/arch/i386/Makefile b/arch/i386/Makefile
+index 3e4adb1..0677908 100644
+--- a/arch/i386/Makefile
++++ b/arch/i386/Makefile
+@@ -42,10 +42,22 @@ cflags-$(CONFIG_REGPARM) += -mregparm=3
+ # temporary until string.h is fixed
+ cflags-y += -ffreestanding
+
++# this works around some issues with generating unwind tables in older gccs
++# newer gccs do it by default
++cflags-y += -maccumulate-outgoing-args
++
+ # Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
+ # a lot more stack due to the lack of sharing of stacklots:
+ CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then echo $(call cc-option,-fno-unit-at-a-time); fi ;)
+
++# do binutils support CFI?
++cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
++AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
++
++# is .cfi_signal_frame supported too?
++cflags-y += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,)
++AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,)
++
+ CFLAGS += $(cflags-y)
+
+ # Default subarch .c files
+diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
+index 4b84ea2..3432136 100644
+--- a/arch/i386/boot/edd.S
++++ b/arch/i386/boot/edd.S
+@@ -15,42 +15,95 @@
+ #include <asm/setup.h>
+
+ #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
++
++# It is assumed that %ds == INITSEG here
++
+ movb $0, (EDD_MBR_SIG_NR_BUF)
+ movb $0, (EDDNR)
+
+-# Check the command line for two options:
++# Check the command line for options:
+ # edd=of disables EDD completely (edd=off)
+ # edd=sk skips the MBR test (edd=skipmbr)
++# edd=on re-enables EDD (edd=on)
++
+ pushl %esi
+- cmpl $0, %cs:cmd_line_ptr
+- jz done_cl
++ movw $edd_mbr_sig_start, %di # Default to edd=on
++
+ movl %cs:(cmd_line_ptr), %esi
+-# ds:esi has the pointer to the command line now
+- movl $(COMMAND_LINE_SIZE-7), %ecx
+-# loop through kernel command line one byte at a time
+-cl_loop:
+- cmpl $EDD_CL_EQUALS, (%si)
++ andl %esi, %esi
++ jz old_cl # Old boot protocol?
++
++# Convert to a real-mode pointer in fs:si
++ movl %esi, %eax
++ shrl $4, %eax
++ movw %ax, %fs
++ andw $0xf, %si
++ jmp have_cl_pointer
++
++# Old-style boot protocol?
++old_cl:
++ push %ds # aka INITSEG
++ pop %fs
++
++ cmpw $0xa33f, (0x20)
++ jne done_cl # No command line at all?
++ movw (0x22), %si # Pointer relative to INITSEG
++
++# fs:si has the pointer to the command line now
++have_cl_pointer:
++
++# Loop through kernel command line one byte at a time. Just in
++# case the loader is buggy and failed to null-terminate the command line
++# terminate if we get close enough to the end of the segment that we
++# cannot fit "edd=XX"...
++cl_atspace:
++ cmpw $-5, %si # Watch for segment wraparound
++ jae done_cl
++ movl %fs:(%si), %eax
++ andb %al, %al # End of line?
++ jz done_cl
++ cmpl $EDD_CL_EQUALS, %eax
+ jz found_edd_equals
+- incl %esi
+- loop cl_loop
+- jmp done_cl
++ cmpb $0x20, %al # <= space consider whitespace
++ ja cl_skipword
++ incw %si
++ jmp cl_atspace
++
++cl_skipword:
++ cmpw $-5, %si # Watch for segment wraparound
++ jae done_cl
++ movb %fs:(%si), %al # End of string?
++ andb %al, %al
++ jz done_cl
++ cmpb $0x20, %al
++ jbe cl_atspace
++ incw %si
++ jmp cl_skipword
++
+ found_edd_equals:
+ # only looking at first two characters after equals
+- addl $4, %esi
+- cmpw $EDD_CL_OFF, (%si) # edd=of
+- jz do_edd_off
+- cmpw $EDD_CL_SKIP, (%si) # edd=sk
+- jz do_edd_skipmbr
+- jmp done_cl
++# late overrides early on the command line, so keep going after finding something
++ movw %fs:4(%si), %ax
++ cmpw $EDD_CL_OFF, %ax # edd=of
++ je do_edd_off
++ cmpw $EDD_CL_SKIP, %ax # edd=sk
++ je do_edd_skipmbr
++ cmpw $EDD_CL_ON, %ax # edd=on
++ je do_edd_on
++ jmp cl_skipword
+ do_edd_skipmbr:
+- popl %esi
+- jmp edd_start
++ movw $edd_start, %di
++ jmp cl_skipword
+ do_edd_off:
+- popl %esi
+- jmp edd_done
++ movw $edd_done, %di
++ jmp cl_skipword
++do_edd_on:
++ movw $edd_mbr_sig_start, %di
++ jmp cl_skipword
++
+ done_cl:
+ popl %esi
+-
++ jmpw *%di
+
+ # Read the first sector of each BIOS disk device and store the 4-byte signature
+ edd_mbr_sig_start:
+diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
+index d2b684c..3aec453 100644
+--- a/arch/i386/boot/setup.S
++++ b/arch/i386/boot/setup.S
+@@ -494,12 +494,12 @@ no_voyager:
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %ds
+- movw $0, (0x1ff) # default is no pointing device
++ movb $0, (0x1ff) # default is no pointing device
+ int $0x11 # int 0x11: equipment list
+ testb $0x04, %al # check if mouse installed
+ jz no_psmouse
+
+- movw $0xAA, (0x1ff) # device present
++ movb $0xAA, (0x1ff) # device present
+ no_psmouse:
+
+ #if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
+diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
+index 8c2a6fa..2c5b5cc 100644
+--- a/arch/i386/boot/video.S
++++ b/arch/i386/boot/video.S
+@@ -11,8 +11,6 @@
+ *
+ */
+
+-#include <linux/config.h> /* for CONFIG_VIDEO_* */
+-
+ /* Enable autodetection of SVGA adapters and modes. */
+ #undef CONFIG_VIDEO_SVGA
+
+diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile
+index 103c353..3fd19af 100644
+--- a/arch/i386/crypto/Makefile
++++ b/arch/i386/crypto/Makefile
+@@ -5,5 +5,8 @@
+ #
+
+ obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
++obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
+
+ aes-i586-y := aes-i586-asm.o aes.o
++twofish-i586-y := twofish-i586-asm.o twofish.o
++
+diff --git a/arch/i386/crypto/aes.c b/arch/i386/crypto/aes.c
+index d3806da..49aad93 100644
+--- a/arch/i386/crypto/aes.c
++++ b/arch/i386/crypto/aes.c
+@@ -379,12 +379,13 @@ static void gen_tabs(void)
+ }
+
+ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ int i;
+ u32 ss[8];
+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __le32 *key = (const __le32 *)in_key;
++ u32 *flags = &tfm->crt_flags;
+
+ /* encryption schedule */
+
+diff --git a/arch/i386/crypto/twofish-i586-asm.S b/arch/i386/crypto/twofish-i586-asm.S
+new file mode 100644
+index 0000000..39b98ed
+--- /dev/null
++++ b/arch/i386/crypto/twofish-i586-asm.S
+@@ -0,0 +1,335 @@
++/***************************************************************************
++* Copyright (C) 2006 by Joachim Fritschi, <jfritschi at freenet.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., *
++* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
++***************************************************************************/
++
++.file "twofish-i586-asm.S"
++.text
++
++#include <asm/asm-offsets.h>
++
++/* return adress at 0 */
++
++#define in_blk 12 /* input byte array address parameter*/
++#define out_blk 8 /* output byte array address parameter*/
++#define tfm 4 /* Twofish context structure */
++
++#define a_offset 0
++#define b_offset 4
++#define c_offset 8
++#define d_offset 12
++
++/* Structure of the crypto context struct*/
++
++#define s0 0 /* S0 Array 256 Words each */
++#define s1 1024 /* S1 Array */
++#define s2 2048 /* S2 Array */
++#define s3 3072 /* S3 Array */
++#define w 4096 /* 8 whitening keys (word) */
++#define k 4128 /* key 1-32 ( word ) */
++
++/* define a few register aliases to allow macro substitution */
++
++#define R0D %eax
++#define R0B %al
++#define R0H %ah
++
++#define R1D %ebx
++#define R1B %bl
++#define R1H %bh
++
++#define R2D %ecx
++#define R2B %cl
++#define R2H %ch
++
++#define R3D %edx
++#define R3B %dl
++#define R3H %dh
++
++
++/* performs input whitening */
++#define input_whitening(src,context,offset)\
++ xor w+offset(context), src;
++
++/* performs input whitening */
++#define output_whitening(src,context,offset)\
++ xor w+16+offset(context), src;
++
++/*
++ * a input register containing a (rotated 16)
++ * b input register containing b
++ * c input register containing c
++ * d input register containing d (already rol $1)
++ * operations on a and b are interleaved to increase performance
++ */
++#define encrypt_round(a,b,c,d,round)\
++ push d ## D;\
++ movzx b ## B, %edi;\
++ mov s1(%ebp,%edi,4),d ## D;\
++ movzx a ## B, %edi;\
++ mov s2(%ebp,%edi,4),%esi;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor s2(%ebp,%edi,4),d ## D;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s3(%ebp,%edi,4),%esi;\
++ movzx b ## B, %edi;\
++ xor s3(%ebp,%edi,4),d ## D;\
++ movzx a ## B, %edi;\
++ xor (%ebp,%edi,4), %esi;\
++ movzx b ## H, %edi;\
++ ror $15, b ## D;\
++ xor (%ebp,%edi,4), d ## D;\
++ movzx a ## H, %edi;\
++ xor s1(%ebp,%edi,4),%esi;\
++ pop %edi;\
++ add d ## D, %esi;\
++ add %esi, d ## D;\
++ add k+round(%ebp), %esi;\
++ xor %esi, c ## D;\
++ rol $15, c ## D;\
++ add k+4+round(%ebp),d ## D;\
++ xor %edi, d ## D;
++
++/*
++ * a input register containing a (rotated 16)
++ * b input register containing b
++ * c input register containing c
++ * d input register containing d (already rol $1)
++ * operations on a and b are interleaved to increase performance
++ * last round has different rotations for the output preparation
++ */
++#define encrypt_last_round(a,b,c,d,round)\
++ push d ## D;\
++ movzx b ## B, %edi;\
++ mov s1(%ebp,%edi,4),d ## D;\
++ movzx a ## B, %edi;\
++ mov s2(%ebp,%edi,4),%esi;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor s2(%ebp,%edi,4),d ## D;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s3(%ebp,%edi,4),%esi;\
++ movzx b ## B, %edi;\
++ xor s3(%ebp,%edi,4),d ## D;\
++ movzx a ## B, %edi;\
++ xor (%ebp,%edi,4), %esi;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor (%ebp,%edi,4), d ## D;\
++ movzx a ## H, %edi;\
++ xor s1(%ebp,%edi,4),%esi;\
++ pop %edi;\
++ add d ## D, %esi;\
++ add %esi, d ## D;\
++ add k+round(%ebp), %esi;\
++ xor %esi, c ## D;\
++ ror $1, c ## D;\
++ add k+4+round(%ebp),d ## D;\
++ xor %edi, d ## D;
++
++/*
++ * a input register containing a
++ * b input register containing b (rotated 16)
++ * c input register containing c
++ * d input register containing d (already rol $1)
++ * operations on a and b are interleaved to increase performance
++ */
++#define decrypt_round(a,b,c,d,round)\
++ push c ## D;\
++ movzx a ## B, %edi;\
++ mov (%ebp,%edi,4), c ## D;\
++ movzx b ## B, %edi;\
++ mov s3(%ebp,%edi,4),%esi;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s1(%ebp,%edi,4),c ## D;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor (%ebp,%edi,4), %esi;\
++ movzx a ## B, %edi;\
++ xor s2(%ebp,%edi,4),c ## D;\
++ movzx b ## B, %edi;\
++ xor s1(%ebp,%edi,4),%esi;\
++ movzx a ## H, %edi;\
++ ror $15, a ## D;\
++ xor s3(%ebp,%edi,4),c ## D;\
++ movzx b ## H, %edi;\
++ xor s2(%ebp,%edi,4),%esi;\
++ pop %edi;\
++ add %esi, c ## D;\
++ add c ## D, %esi;\
++ add k+round(%ebp), c ## D;\
++ xor %edi, c ## D;\
++ add k+4+round(%ebp),%esi;\
++ xor %esi, d ## D;\
++ rol $15, d ## D;
++
++/*
++ * a input register containing a
++ * b input register containing b (rotated 16)
++ * c input register containing c
++ * d input register containing d (already rol $1)
++ * operations on a and b are interleaved to increase performance
++ * last round has different rotations for the output preparation
++ */
++#define decrypt_last_round(a,b,c,d,round)\
++ push c ## D;\
++ movzx a ## B, %edi;\
++ mov (%ebp,%edi,4), c ## D;\
++ movzx b ## B, %edi;\
++ mov s3(%ebp,%edi,4),%esi;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s1(%ebp,%edi,4),c ## D;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor (%ebp,%edi,4), %esi;\
++ movzx a ## B, %edi;\
++ xor s2(%ebp,%edi,4),c ## D;\
++ movzx b ## B, %edi;\
++ xor s1(%ebp,%edi,4),%esi;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s3(%ebp,%edi,4),c ## D;\
++ movzx b ## H, %edi;\
++ xor s2(%ebp,%edi,4),%esi;\
++ pop %edi;\
++ add %esi, c ## D;\
++ add c ## D, %esi;\
++ add k+round(%ebp), c ## D;\
++ xor %edi, c ## D;\
++ add k+4+round(%ebp),%esi;\
++ xor %esi, d ## D;\
++ ror $1, d ## D;
++
++.align 4
++.global twofish_enc_blk
++.global twofish_dec_blk
++
++twofish_enc_blk:
++ push %ebp /* save registers according to calling convention*/
++ push %ebx
++ push %esi
++ push %edi
++
++ mov tfm + 16(%esp), %ebp /* abuse the base pointer: set new base bointer to the crypto tfm */
++ add $crypto_tfm_ctx_offset, %ebp /* ctx adress */
++ mov in_blk+16(%esp),%edi /* input adress in edi */
++
++ mov (%edi), %eax
++ mov b_offset(%edi), %ebx
++ mov c_offset(%edi), %ecx
++ mov d_offset(%edi), %edx
++ input_whitening(%eax,%ebp,a_offset)
++ ror $16, %eax
++ input_whitening(%ebx,%ebp,b_offset)
++ input_whitening(%ecx,%ebp,c_offset)
++ input_whitening(%edx,%ebp,d_offset)
++ rol $1, %edx
++
++ encrypt_round(R0,R1,R2,R3,0);
++ encrypt_round(R2,R3,R0,R1,8);
++ encrypt_round(R0,R1,R2,R3,2*8);
++ encrypt_round(R2,R3,R0,R1,3*8);
++ encrypt_round(R0,R1,R2,R3,4*8);
++ encrypt_round(R2,R3,R0,R1,5*8);
++ encrypt_round(R0,R1,R2,R3,6*8);
++ encrypt_round(R2,R3,R0,R1,7*8);
++ encrypt_round(R0,R1,R2,R3,8*8);
++ encrypt_round(R2,R3,R0,R1,9*8);
++ encrypt_round(R0,R1,R2,R3,10*8);
++ encrypt_round(R2,R3,R0,R1,11*8);
++ encrypt_round(R0,R1,R2,R3,12*8);
++ encrypt_round(R2,R3,R0,R1,13*8);
++ encrypt_round(R0,R1,R2,R3,14*8);
++ encrypt_last_round(R2,R3,R0,R1,15*8);
++
++ output_whitening(%eax,%ebp,c_offset)
++ output_whitening(%ebx,%ebp,d_offset)
++ output_whitening(%ecx,%ebp,a_offset)
++ output_whitening(%edx,%ebp,b_offset)
++ mov out_blk+16(%esp),%edi;
++ mov %eax, c_offset(%edi)
++ mov %ebx, d_offset(%edi)
++ mov %ecx, (%edi)
++ mov %edx, b_offset(%edi)
++
++ pop %edi
++ pop %esi
++ pop %ebx
++ pop %ebp
++ mov $1, %eax
++ ret
++
++twofish_dec_blk:
++ push %ebp /* save registers according to calling convention*/
++ push %ebx
++ push %esi
++ push %edi
++
++
++ mov tfm + 16(%esp), %ebp /* abuse the base pointer: set new base bointer to the crypto tfm */
++ add $crypto_tfm_ctx_offset, %ebp /* ctx adress */
++ mov in_blk+16(%esp),%edi /* input adress in edi */
++
++ mov (%edi), %eax
++ mov b_offset(%edi), %ebx
++ mov c_offset(%edi), %ecx
++ mov d_offset(%edi), %edx
++ output_whitening(%eax,%ebp,a_offset)
++ output_whitening(%ebx,%ebp,b_offset)
++ ror $16, %ebx
++ output_whitening(%ecx,%ebp,c_offset)
++ output_whitening(%edx,%ebp,d_offset)
++ rol $1, %ecx
++
++ decrypt_round(R0,R1,R2,R3,15*8);
++ decrypt_round(R2,R3,R0,R1,14*8);
++ decrypt_round(R0,R1,R2,R3,13*8);
++ decrypt_round(R2,R3,R0,R1,12*8);
++ decrypt_round(R0,R1,R2,R3,11*8);
++ decrypt_round(R2,R3,R0,R1,10*8);
++ decrypt_round(R0,R1,R2,R3,9*8);
++ decrypt_round(R2,R3,R0,R1,8*8);
++ decrypt_round(R0,R1,R2,R3,7*8);
++ decrypt_round(R2,R3,R0,R1,6*8);
++ decrypt_round(R0,R1,R2,R3,5*8);
++ decrypt_round(R2,R3,R0,R1,4*8);
++ decrypt_round(R0,R1,R2,R3,3*8);
++ decrypt_round(R2,R3,R0,R1,2*8);
++ decrypt_round(R0,R1,R2,R3,1*8);
++ decrypt_last_round(R2,R3,R0,R1,0);
++
++ input_whitening(%eax,%ebp,c_offset)
++ input_whitening(%ebx,%ebp,d_offset)
++ input_whitening(%ecx,%ebp,a_offset)
++ input_whitening(%edx,%ebp,b_offset)
++ mov out_blk+16(%esp),%edi;
++ mov %eax, c_offset(%edi)
++ mov %ebx, d_offset(%edi)
++ mov %ecx, (%edi)
++ mov %edx, b_offset(%edi)
++
++ pop %edi
++ pop %esi
++ pop %ebx
++ pop %ebp
++ mov $1, %eax
++ ret
+diff --git a/arch/i386/crypto/twofish.c b/arch/i386/crypto/twofish.c
+new file mode 100644
+index 0000000..e3004df
+--- /dev/null
++++ b/arch/i386/crypto/twofish.c
+@@ -0,0 +1,97 @@
++/*
++ * Glue Code for optimized 586 assembler version of TWOFISH
++ *
++ * Originally Twofish for GPG
++ * By Matthew Skala <mskala at ansuz.sooke.bc.ca>, July 26, 1998
++ * 256-bit key length added March 20, 1999
++ * Some modifications to reduce the text size by Werner Koch, April, 1998
++ * Ported to the kerneli patch by Marc Mutz <Marc at Mutz.com>
++ * Ported to CryptoAPI by Colin Slater <hoho at tacomeat.net>
++ *
++ * The original author has disclaimed all copyright interest in this
++ * code and thus put it in the public domain. The subsequent authors
++ * have put this under the GNU General Public License.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
++ * USA
++ *
++ * This code is a "clean room" implementation, written from the paper
++ * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
++ * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
++ * through http://www.counterpane.com/twofish.html
++ *
++ * For background information on multiplication in finite fields, used for
++ * the matrix operations in the key schedule, see the book _Contemporary
++ * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
++ * Third Edition.
++ */
++
++#include <crypto/twofish.h>
++#include <linux/crypto.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++
++
++asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
++asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
++
++static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
++{
++ twofish_enc_blk(tfm, dst, src);
++}
++
++static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
++{
++ twofish_dec_blk(tfm, dst, src);
++}
++
++static struct crypto_alg alg = {
++ .cra_name = "twofish",
++ .cra_driver_name = "twofish-i586",
++ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = TF_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct twofish_ctx),
++ .cra_alignmask = 3,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = TF_MIN_KEY_SIZE,
++ .cia_max_keysize = TF_MAX_KEY_SIZE,
++ .cia_setkey = twofish_setkey,
++ .cia_encrypt = twofish_encrypt,
++ .cia_decrypt = twofish_decrypt
++ }
++ }
++};
++
++static int __init init(void)
++{
++ return crypto_register_alg(&alg);
++}
++
++static void __exit fini(void)
++{
++ crypto_unregister_alg(&alg);
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION ("Twofish Cipher Algorithm, i586 asm optimized");
++MODULE_ALIAS("twofish");
+diff --git a/arch/i386/defconfig b/arch/i386/defconfig
+index 89ebb7a..97aacd6 100644
+--- a/arch/i386/defconfig
++++ b/arch/i386/defconfig
+@@ -1,41 +1,54 @@
+ #
+ # Automatically generated make config: don't edit
++# Linux kernel version: 2.6.19-rc2-git4
++# Sat Oct 21 03:38:56 2006
+ #
+ CONFIG_X86_32=y
++CONFIG_GENERIC_TIME=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_SEMAPHORE_SLEEPERS=y
+ CONFIG_X86=y
+ CONFIG_MMU=y
+ CONFIG_GENERIC_ISA_DMA=y
+ CONFIG_GENERIC_IOMAP=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+ CONFIG_DMI=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+ # General setup
+ #
+ CONFIG_LOCALVERSION=""
+-# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
+-# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
++# CONFIG_CPUSETS is not set
++# CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_UID16=y
+-CONFIG_VM86=y
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+ CONFIG_HOTPLUG=y
+ CONFIG_PRINTK=y
+@@ -45,11 +58,9 @@ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -60,41 +71,46 @@ CONFIG_BASE_SMALL=0
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+-CONFIG_OBSOLETE_MODPARM=y
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ # CONFIG_KMOD is not set
++CONFIG_STOP_MACHINE=y
+
+ #
+ # Block layer
+ #
+-# CONFIG_LBD is not set
++CONFIG_BLOCK=y
++CONFIG_LBD=y
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
+
+ #
+ # IO Schedulers
+ #
+ CONFIG_IOSCHED_NOOP=y
+-# CONFIG_IOSCHED_AS is not set
+-# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
+ CONFIG_IOSCHED_CFQ=y
+-# CONFIG_DEFAULT_AS is not set
++CONFIG_DEFAULT_AS=y
+ # CONFIG_DEFAULT_DEADLINE is not set
+-CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_CFQ is not set
+ # CONFIG_DEFAULT_NOOP is not set
+-CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+ #
+ # Processor type and features
+ #
+-CONFIG_X86_PC=y
++CONFIG_SMP=y
++# CONFIG_X86_PC is not set
+ # CONFIG_X86_ELAN is not set
+ # CONFIG_X86_VOYAGER is not set
+ # CONFIG_X86_NUMAQ is not set
+ # CONFIG_X86_SUMMIT is not set
+ # CONFIG_X86_BIGSMP is not set
+ # CONFIG_X86_VISWS is not set
+-# CONFIG_X86_GENERICARCH is not set
++CONFIG_X86_GENERICARCH=y
+ # CONFIG_X86_ES7000 is not set
++CONFIG_X86_CYCLONE_TIMER=y
+ # CONFIG_M386 is not set
+ # CONFIG_M486 is not set
+ # CONFIG_M586 is not set
+@@ -102,11 +118,11 @@ CONFIG_X86_PC=y
+ # CONFIG_M586MMX is not set
+ # CONFIG_M686 is not set
+ # CONFIG_MPENTIUMII is not set
+-# CONFIG_MPENTIUMIII is not set
++CONFIG_MPENTIUMIII=y
+ # CONFIG_MPENTIUMM is not set
+ # CONFIG_MPENTIUM4 is not set
+ # CONFIG_MK6 is not set
+-CONFIG_MK7=y
++# CONFIG_MK7 is not set
+ # CONFIG_MK8 is not set
+ # CONFIG_MCRUSOE is not set
+ # CONFIG_MEFFICEON is not set
+@@ -117,10 +133,10 @@ CONFIG_MK7=y
+ # CONFIG_MGEODE_LX is not set
+ # CONFIG_MCYRIXIII is not set
+ # CONFIG_MVIAC3_2 is not set
+-# CONFIG_X86_GENERIC is not set
++CONFIG_X86_GENERIC=y
+ CONFIG_X86_CMPXCHG=y
+ CONFIG_X86_XADD=y
+-CONFIG_X86_L1_CACHE_SHIFT=6
++CONFIG_X86_L1_CACHE_SHIFT=7
+ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_X86_WP_WORKS_OK=y
+@@ -131,26 +147,29 @@ CONFIG_X86_CMPXCHG64=y
+ CONFIG_X86_GOOD_APIC=y
+ CONFIG_X86_INTEL_USERCOPY=y
+ CONFIG_X86_USE_PPRO_CHECKSUM=y
+-CONFIG_X86_USE_3DNOW=y
+ CONFIG_X86_TSC=y
+-# CONFIG_HPET_TIMER is not set
+-# CONFIG_SMP is not set
+-CONFIG_PREEMPT_NONE=y
+-# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_HPET_TIMER=y
++CONFIG_HPET_EMULATE_RTC=y
++CONFIG_NR_CPUS=32
++CONFIG_SCHED_SMT=y
++CONFIG_SCHED_MC=y
++# CONFIG_PREEMPT_NONE is not set
++CONFIG_PREEMPT_VOLUNTARY=y
+ # CONFIG_PREEMPT is not set
+-CONFIG_X86_UP_APIC=y
+-CONFIG_X86_UP_IOAPIC=y
++CONFIG_PREEMPT_BKL=y
+ CONFIG_X86_LOCAL_APIC=y
+ CONFIG_X86_IO_APIC=y
+ CONFIG_X86_MCE=y
+ CONFIG_X86_MCE_NONFATAL=y
+-# CONFIG_X86_MCE_P4THERMAL is not set
++CONFIG_X86_MCE_P4THERMAL=y
++CONFIG_VM86=y
+ # CONFIG_TOSHIBA is not set
+ # CONFIG_I8K is not set
+ # CONFIG_X86_REBOOTFIXUPS is not set
+-# CONFIG_MICROCODE is not set
+-# CONFIG_X86_MSR is not set
+-# CONFIG_X86_CPUID is not set
++CONFIG_MICROCODE=y
++CONFIG_MICROCODE_OLD_INTERFACE=y
++CONFIG_X86_MSR=y
++CONFIG_X86_CPUID=y
+
+ #
+ # Firmware Drivers
+@@ -158,68 +177,69 @@ CONFIG_X86_MCE_NONFATAL=y
+ # CONFIG_EDD is not set
+ # CONFIG_DELL_RBU is not set
+ # CONFIG_DCDBAS is not set
+-CONFIG_NOHIGHMEM=y
+-# CONFIG_HIGHMEM4G is not set
++# CONFIG_NOHIGHMEM is not set
++CONFIG_HIGHMEM4G=y
+ # CONFIG_HIGHMEM64G is not set
+-CONFIG_VMSPLIT_3G=y
+-# CONFIG_VMSPLIT_3G_OPT is not set
+-# CONFIG_VMSPLIT_2G is not set
+-# CONFIG_VMSPLIT_1G is not set
+ CONFIG_PAGE_OFFSET=0xC0000000
+-CONFIG_ARCH_FLATMEM_ENABLE=y
+-CONFIG_ARCH_SPARSEMEM_ENABLE=y
+-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_HIGHMEM=y
++CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_STATIC=y
++# CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_RESOURCES_64BIT=y
++# CONFIG_HIGHPTE is not set
+ # CONFIG_MATH_EMULATION is not set
+ CONFIG_MTRR=y
+ # CONFIG_EFI is not set
++# CONFIG_IRQBALANCE is not set
+ CONFIG_REGPARM=y
+-# CONFIG_SECCOMP is not set
+-CONFIG_HZ_100=y
+-# CONFIG_HZ_250 is not set
++CONFIG_SECCOMP=y
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
+ # CONFIG_HZ_1000 is not set
+-CONFIG_HZ=100
++CONFIG_HZ=250
+ # CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
+ CONFIG_PHYSICAL_START=0x100000
+-CONFIG_DOUBLEFAULT=y
++# CONFIG_HOTPLUG_CPU is not set
++CONFIG_COMPAT_VDSO=y
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+
+ #
+ # Power management options (ACPI, APM)
+ #
+ CONFIG_PM=y
+-# CONFIG_PM_LEGACY is not set
++CONFIG_PM_LEGACY=y
+ # CONFIG_PM_DEBUG is not set
+-CONFIG_SOFTWARE_SUSPEND=y
+-CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SYSFS_DEPRECATED=y
+
+ #
+ # ACPI (Advanced Configuration and Power Interface) Support
+ #
+ CONFIG_ACPI=y
+-# CONFIG_ACPI_SLEEP is not set
+-# CONFIG_ACPI_AC is not set
+-# CONFIG_ACPI_BATTERY is not set
+-# CONFIG_ACPI_BUTTON is not set
++CONFIG_ACPI_AC=y
++CONFIG_ACPI_BATTERY=y
++CONFIG_ACPI_BUTTON=y
+ # CONFIG_ACPI_VIDEO is not set
+ # CONFIG_ACPI_HOTKEY is not set
+-# CONFIG_ACPI_FAN is not set
+-# CONFIG_ACPI_PROCESSOR is not set
++CONFIG_ACPI_FAN=y
++# CONFIG_ACPI_DOCK is not set
++CONFIG_ACPI_PROCESSOR=y
++CONFIG_ACPI_THERMAL=y
+ # CONFIG_ACPI_ASUS is not set
+ # CONFIG_ACPI_IBM is not set
+ # CONFIG_ACPI_TOSHIBA is not set
+-CONFIG_ACPI_BLACKLIST_YEAR=0
+-# CONFIG_ACPI_DEBUG is not set
++CONFIG_ACPI_BLACKLIST_YEAR=2001
++CONFIG_ACPI_DEBUG=y
+ CONFIG_ACPI_EC=y
+ CONFIG_ACPI_POWER=y
+ CONFIG_ACPI_SYSTEM=y
+-# CONFIG_X86_PM_TIMER is not set
++CONFIG_X86_PM_TIMER=y
+ # CONFIG_ACPI_CONTAINER is not set
+
+ #
+@@ -230,7 +250,41 @@ CONFIG_ACPI_SYSTEM=y
+ #
+ # CPU Frequency scaling
+ #
+-# CONFIG_CPU_FREQ is not set
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++CONFIG_CPU_FREQ_DEBUG=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# CPUFreq processor drivers
++#
++CONFIG_X86_ACPI_CPUFREQ=y
++# CONFIG_X86_POWERNOW_K6 is not set
++# CONFIG_X86_POWERNOW_K7 is not set
++CONFIG_X86_POWERNOW_K8=y
++CONFIG_X86_POWERNOW_K8_ACPI=y
++# CONFIG_X86_GX_SUSPMOD is not set
++# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
++# CONFIG_X86_SPEEDSTEP_ICH is not set
++# CONFIG_X86_SPEEDSTEP_SMI is not set
++# CONFIG_X86_P4_CLOCKMOD is not set
++# CONFIG_X86_CPUFREQ_NFORCE2 is not set
++# CONFIG_X86_LONGRUN is not set
++# CONFIG_X86_LONGHAUL is not set
++
++#
++# shared options
++#
++CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
++# CONFIG_X86_SPEEDSTEP_LIB is not set
+
+ #
+ # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+@@ -244,12 +298,15 @@ CONFIG_PCI_BIOS=y
+ CONFIG_PCI_DIRECT=y
+ CONFIG_PCI_MMCONFIG=y
+ # CONFIG_PCIEPORTBUS is not set
+-# CONFIG_PCI_MSI is not set
+-# CONFIG_PCI_LEGACY_PROC is not set
++CONFIG_PCI_MSI=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
++# CONFIG_PCI_DEBUG is not set
++# CONFIG_HT_IRQ is not set
+ CONFIG_ISA_DMA_API=y
+ # CONFIG_ISA is not set
+ # CONFIG_MCA is not set
+ # CONFIG_SCx200 is not set
++CONFIG_K8_NB=y
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+@@ -278,93 +335,56 @@ CONFIG_NET=y
+ #
+ # CONFIG_NETDEBUG is not set
+ CONFIG_PACKET=y
+-CONFIG_PACKET_MMAP=y
++# CONFIG_PACKET_MMAP is not set
+ CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+-# CONFIG_IP_MULTICAST is not set
++CONFIG_IP_MULTICAST=y
+ # CONFIG_IP_ADVANCED_ROUTER is not set
+ CONFIG_IP_FIB_HASH=y
+-# CONFIG_IP_PNP 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_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_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
+-# CONFIG_INET_DIAG is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
+-
+-#
+-# IP: Virtual Server Configuration
+-#
+-# CONFIG_IP_VS is not set
+-# CONFIG_IPV6 is not set
+-CONFIG_NETFILTER=y
+-# CONFIG_NETFILTER_DEBUG is not set
+-
+-#
+-# Core Netfilter Configuration
+-#
+-# CONFIG_NETFILTER_NETLINK is not set
+-CONFIG_NETFILTER_XTABLES=y
+-# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+-# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+-# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+-# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+-# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+-# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+-# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+-CONFIG_NETFILTER_XT_MATCH_MAC=y
+-# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+-# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+-# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+-# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+-CONFIG_NETFILTER_XT_MATCH_STATE=y
+-# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+-# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+-
+-#
+-# IP: Netfilter Configuration
+-#
+-CONFIG_IP_NF_CONNTRACK=y
+-# CONFIG_IP_NF_CT_ACCT is not set
+-# CONFIG_IP_NF_CONNTRACK_MARK is not set
+-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+-CONFIG_IP_NF_FTP=y
+-# CONFIG_IP_NF_IRC is not set
+-# CONFIG_IP_NF_NETBIOS_NS is not set
+-# CONFIG_IP_NF_TFTP is not set
+-# CONFIG_IP_NF_AMANDA is not set
+-# CONFIG_IP_NF_PPTP is not set
+-# CONFIG_IP_NF_QUEUE is not set
+-CONFIG_IP_NF_IPTABLES=y
+-# CONFIG_IP_NF_MATCH_IPRANGE is not set
+-# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+-# CONFIG_IP_NF_MATCH_TOS is not set
+-# CONFIG_IP_NF_MATCH_RECENT is not set
+-# CONFIG_IP_NF_MATCH_ECN is not set
+-# CONFIG_IP_NF_MATCH_DSCP is not set
+-# CONFIG_IP_NF_MATCH_AH_ESP is not set
+-# CONFIG_IP_NF_MATCH_TTL is not set
+-# CONFIG_IP_NF_MATCH_OWNER is not set
+-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+-CONFIG_IP_NF_FILTER=y
+-# CONFIG_IP_NF_TARGET_REJECT is not set
+-CONFIG_IP_NF_TARGET_LOG=y
+-# CONFIG_IP_NF_TARGET_ULOG is not set
+-# CONFIG_IP_NF_TARGET_TCPMSS is not set
+-# CONFIG_IP_NF_NAT is not set
+-# CONFIG_IP_NF_MANGLE is not set
+-# CONFIG_IP_NF_RAW is not set
+-# CONFIG_IP_NF_ARPTABLES is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++CONFIG_IPV6=y
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
+
+ #
+ # DCCP Configuration (EXPERIMENTAL)
+@@ -389,7 +409,6 @@ CONFIG_IP_NF_TARGET_LOG=y
+ # 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
+
+@@ -402,6 +421,7 @@ CONFIG_IP_NF_TARGET_LOG=y
+ # Network testing
+ #
+ # CONFIG_NET_PKTGEN is not set
++# CONFIG_NET_TCPPROBE is not set
+ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+@@ -416,7 +436,9 @@ CONFIG_IP_NF_TARGET_LOG=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++CONFIG_FW_LOADER=y
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -431,13 +453,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ #
+ # Parallel port support
+ #
+-CONFIG_PARPORT=y
+-CONFIG_PARPORT_PC=y
+-# CONFIG_PARPORT_SERIAL is not set
+-# CONFIG_PARPORT_PC_FIFO is not set
+-# CONFIG_PARPORT_PC_SUPERIO is not set
+-# CONFIG_PARPORT_GSC is not set
+-CONFIG_PARPORT_1284=y
++# CONFIG_PARPORT is not set
+
+ #
+ # Plug and Play support
+@@ -447,8 +463,7 @@ CONFIG_PARPORT_1284=y
+ #
+ # Block devices
+ #
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_PARIDE is not set
++CONFIG_BLK_DEV_FD=y
+ # CONFIG_BLK_CPQ_DA is not set
+ # CONFIG_BLK_CPQ_CISS_DA is not set
+ # CONFIG_BLK_DEV_DAC960 is not set
+@@ -459,12 +474,22 @@ CONFIG_BLK_DEV_LOOP=y
+ # CONFIG_BLK_DEV_NBD is not set
+ # CONFIG_BLK_DEV_SX8 is not set
+ # CONFIG_BLK_DEV_UB is not set
+-# CONFIG_BLK_DEV_RAM is not set
++CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+
+ #
++# Misc devices
++#
++# CONFIG_IBM_ASM is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
+@@ -476,7 +501,7 @@ CONFIG_BLK_DEV_IDE=y
+ # CONFIG_BLK_DEV_IDE_SATA is not set
+ # CONFIG_BLK_DEV_HD_IDE is not set
+ CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
++CONFIG_IDEDISK_MULTI_MODE=y
+ CONFIG_BLK_DEV_IDECD=y
+ # CONFIG_BLK_DEV_IDETAPE is not set
+ # CONFIG_BLK_DEV_IDEFLOPPY is not set
+@@ -486,10 +511,10 @@ CONFIG_BLK_DEV_IDECD=y
+ #
+ # IDE chipset support/bugfixes
+ #
+-# CONFIG_IDE_GENERIC is not set
++CONFIG_IDE_GENERIC=y
+ # CONFIG_BLK_DEV_CMD640 is not set
+ CONFIG_BLK_DEV_IDEPCI=y
+-CONFIG_IDEPCI_SHARE_IRQ=y
++# CONFIG_IDEPCI_SHARE_IRQ is not set
+ # CONFIG_BLK_DEV_OFFBOARD is not set
+ # CONFIG_BLK_DEV_GENERIC is not set
+ # CONFIG_BLK_DEV_OPTI621 is not set
+@@ -500,7 +525,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
+ # CONFIG_IDEDMA_ONLYDISK is not set
+ # CONFIG_BLK_DEV_AEC62XX is not set
+ # CONFIG_BLK_DEV_ALI15X3 is not set
+-# CONFIG_BLK_DEV_AMD74XX is not set
++CONFIG_BLK_DEV_AMD74XX=y
+ # CONFIG_BLK_DEV_ATIIXP is not set
+ # CONFIG_BLK_DEV_CMD64X is not set
+ # CONFIG_BLK_DEV_TRIFLEX is not set
+@@ -510,8 +535,9 @@ CONFIG_IDEDMA_PCI_AUTO=y
+ # CONFIG_BLK_DEV_CS5535 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+-# CONFIG_BLK_DEV_PIIX 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
+@@ -521,7 +547,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
+ # CONFIG_BLK_DEV_SIS5513 is not set
+ # CONFIG_BLK_DEV_SLC90E66 is not set
+ # CONFIG_BLK_DEV_TRM290 is not set
+-CONFIG_BLK_DEV_VIA82CXXX=y
++# CONFIG_BLK_DEV_VIA82CXXX is not set
+ # CONFIG_IDE_ARM is not set
+ CONFIG_BLK_DEV_IDEDMA=y
+ # CONFIG_IDEDMA_IVB is not set
+@@ -533,6 +559,7 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ # CONFIG_SCSI_PROC_FS is not set
+
+ #
+@@ -541,8 +568,9 @@ CONFIG_SCSI=y
+ CONFIG_BLK_DEV_SD=y
+ # CONFIG_CHR_DEV_ST is not set
+ # CONFIG_CHR_DEV_OSST is not set
+-# CONFIG_BLK_DEV_SR is not set
+-# CONFIG_CHR_DEV_SG is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
+ # CONFIG_CHR_DEV_SCH is not set
+
+ #
+@@ -553,29 +581,44 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+-# CONFIG_SCSI_SPI_ATTRS is not set
+-# CONFIG_SCSI_FC_ATTRS is not set
++CONFIG_SCSI_SPI_ATTRS=y
++CONFIG_SCSI_FC_ATTRS=y
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+ # CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+ #
+ # CONFIG_ISCSI_TCP is not set
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++CONFIG_BLK_DEV_3W_XXXX_RAID=y
+ # CONFIG_SCSI_3W_9XXX is not set
+ # CONFIG_SCSI_ACARD is not set
+ # CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
++CONFIG_SCSI_AIC7XXX=y
++CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
++CONFIG_AIC7XXX_RESET_DELAY_MS=5000
++CONFIG_AIC7XXX_DEBUG_ENABLE=y
++CONFIG_AIC7XXX_DEBUG_MASK=0
++CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
++CONFIG_SCSI_AIC79XX=y
++CONFIG_AIC79XX_CMDS_PER_DEVICE=32
++CONFIG_AIC79XX_RESET_DELAY_MS=4000
++# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
++# CONFIG_AIC79XX_DEBUG_ENABLE is not set
++CONFIG_AIC79XX_DEBUG_MASK=0
++# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
++# CONFIG_SCSI_AIC94XX is not set
+ # CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ADVANSYS is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_EATA is not set
+@@ -584,13 +627,12 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
+-# CONFIG_SCSI_PPA is not set
+-# CONFIG_SCSI_IMM is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+ # CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
+ # CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+@@ -598,22 +640,113 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++CONFIG_ATA=y
++CONFIG_SATA_AHCI=y
++CONFIG_SATA_SVW=y
++CONFIG_ATA_PIIX=y
++# CONFIG_SATA_MV is not set
++CONFIG_SATA_NV=y
++# CONFIG_PDC_ADMA is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++CONFIG_SATA_SIL=y
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++CONFIG_SATA_VIA=y
++# CONFIG_SATA_VITESSE is not set
++CONFIG_SATA_INTEL_COMBINED=y
++# CONFIG_PATA_ALI is not set
++# CONFIG_PATA_AMD is not set
++# CONFIG_PATA_ARTOP is not set
++# CONFIG_PATA_ATIIXP is not set
++# CONFIG_PATA_CMD64X is not set
++# CONFIG_PATA_CS5520 is not set
++# CONFIG_PATA_CS5530 is not set
++# CONFIG_PATA_CS5535 is not set
++# CONFIG_PATA_CYPRESS is not set
++# CONFIG_PATA_EFAR is not set
++# CONFIG_ATA_GENERIC is not set
++# CONFIG_PATA_HPT366 is not set
++# CONFIG_PATA_HPT37X is not set
++# CONFIG_PATA_HPT3X2N is not set
++# CONFIG_PATA_HPT3X3 is not set
++# CONFIG_PATA_IT821X is not set
++# CONFIG_PATA_JMICRON is not set
++# CONFIG_PATA_TRIFLEX is not set
++# CONFIG_PATA_MPIIX is not set
++# CONFIG_PATA_OLDPIIX is not set
++# CONFIG_PATA_NETCELL is not set
++# CONFIG_PATA_NS87410 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_OPTIDMA is not set
++# CONFIG_PATA_PDC_OLD is not set
++# CONFIG_PATA_RADISYS is not set
++# CONFIG_PATA_RZ1000 is not set
++# CONFIG_PATA_SC1200 is not set
++# CONFIG_PATA_SERVERWORKS is not set
++# CONFIG_PATA_PDC2027X is not set
++# CONFIG_PATA_SIL680 is not set
++# CONFIG_PATA_SIS is not set
++# CONFIG_PATA_VIA is not set
++# CONFIG_PATA_WINBOND is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+-# CONFIG_MD is not set
++CONFIG_MD=y
++# CONFIG_BLK_DEV_MD is not set
++CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
++# CONFIG_DM_CRYPT is not set
++# CONFIG_DM_SNAPSHOT is not set
++# CONFIG_DM_MIRROR is not set
++# CONFIG_DM_ZERO is not set
++# CONFIG_DM_MULTIPATH is not set
+
+ #
+ # Fusion MPT device support
+ #
+-# CONFIG_FUSION is not set
+-# CONFIG_FUSION_SPI is not set
++CONFIG_FUSION=y
++CONFIG_FUSION_SPI=y
+ # CONFIG_FUSION_FC is not set
+ # CONFIG_FUSION_SAS is not set
++CONFIG_FUSION_MAX_SGE=128
++# CONFIG_FUSION_CTL is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+ #
+-# CONFIG_IEEE1394 is not set
++CONFIG_IEEE1394=y
++
++#
++# Subsystem Options
++#
++# CONFIG_IEEE1394_VERBOSEDEBUG is not set
++# CONFIG_IEEE1394_OUI_DB is not set
++# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
++# CONFIG_IEEE1394_EXPORT_FULL_API is not set
++
++#
++# Device Drivers
++#
++
++#
++# Texas Instruments PCILynx requires I2C
++#
++CONFIG_IEEE1394_OHCI1394=y
++
++#
++# Protocol Drivers
++#
++# CONFIG_IEEE1394_VIDEO1394 is not set
++# CONFIG_IEEE1394_SBP2 is not set
++# CONFIG_IEEE1394_ETH1394 is not set
++# CONFIG_IEEE1394_DV1394 is not set
++CONFIG_IEEE1394_RAWIO=y
+
+ #
+ # I2O device support
+@@ -652,46 +785,63 @@ CONFIG_MII=y
+ #
+ # Tulip family network device support
+ #
+-# CONFIG_NET_TULIP is not set
++CONFIG_NET_TULIP=y
++# CONFIG_DE2104X is not set
++CONFIG_TULIP=y
++# CONFIG_TULIP_MWI is not set
++# CONFIG_TULIP_MMIO is not set
++# CONFIG_TULIP_NAPI is not set
++# CONFIG_DE4X5 is not set
++# CONFIG_WINBOND_840 is not set
++# CONFIG_DM9102 is not set
++# CONFIG_ULI526X 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_B44=y
++CONFIG_FORCEDETH=y
++# CONFIG_FORCEDETH_NAPI is not set
+ # CONFIG_DGRS is not set
+ # CONFIG_EEPRO100 is not set
+ CONFIG_E100=y
+ # CONFIG_FEALNX is not set
+ # CONFIG_NATSEMI is not set
+ # CONFIG_NE2K_PCI is not set
+-# CONFIG_8139CP is not set
+-# CONFIG_8139TOO is not set
++CONFIG_8139CP=y
++CONFIG_8139TOO=y
++# CONFIG_8139TOO_PIO is not set
++# CONFIG_8139TOO_TUNE_TWISTER is not set
++# CONFIG_8139TOO_8129 is not set
++# CONFIG_8139_OLD_RX_RESET is not set
+ # CONFIG_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
+-# CONFIG_NET_POCKET is not set
+
+ #
+ # Ethernet (1000 Mbit)
+ #
+ # CONFIG_ACENIC is not set
+ # CONFIG_DL2K is not set
+-# CONFIG_E1000 is not set
++CONFIG_E1000=y
++# CONFIG_E1000_NAPI is not set
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+ # CONFIG_NS83820 is not set
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+-# CONFIG_R8169 is not set
++CONFIG_R8169=y
++# CONFIG_R8169_NAPI is not set
+ # CONFIG_SIS190 is not set
+ # CONFIG_SKGE is not set
+-# CONFIG_SKY2 is not set
++CONFIG_SKY2=y
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+-# CONFIG_TIGON3 is not set
+-# CONFIG_BNX2 is not set
++CONFIG_TIGON3=y
++CONFIG_BNX2=y
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -699,6 +849,7 @@ CONFIG_E100=y
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -716,14 +867,15 @@ CONFIG_E100=y
+ # CONFIG_WAN is not set
+ # CONFIG_FDDI is not set
+ # CONFIG_HIPPI is not set
+-# CONFIG_PLIP is not set
+ # CONFIG_PPP is not set
+ # CONFIG_SLIP is not set
+ # CONFIG_NET_FC is not set
+ # CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
++CONFIG_NETCONSOLE=y
++CONFIG_NETPOLL=y
++# CONFIG_NETPOLL_RX is not set
++# CONFIG_NETPOLL_TRAP is not set
++CONFIG_NET_POLL_CONTROLLER=y
+
+ #
+ # ISDN subsystem
+@@ -739,14 +891,15 @@ CONFIG_E100=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+ #
+ CONFIG_INPUT_MOUSEDEV=y
+ CONFIG_INPUT_MOUSEDEV_PSAUX=y
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1280
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # CONFIG_INPUT_JOYDEV is not set
+ # CONFIG_INPUT_TSDEV is not set
+ CONFIG_INPUT_EVDEV=y
+@@ -761,6 +914,7 @@ CONFIG_KEYBOARD_ATKBD=y
+ # CONFIG_KEYBOARD_LKKBD is not set
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ # CONFIG_MOUSE_SERIAL is not set
+@@ -776,7 +930,6 @@ CONFIG_SERIO=y
+ CONFIG_SERIO_I8042=y
+ # CONFIG_SERIO_SERPORT is not set
+ # CONFIG_SERIO_CT82C710 is not set
+-# CONFIG_SERIO_PARKBD is not set
+ # CONFIG_SERIO_PCIPS2 is not set
+ CONFIG_SERIO_LIBPS2=y
+ # CONFIG_SERIO_RAW is not set
+@@ -788,14 +941,15 @@ CONFIG_SERIO_LIBPS2=y
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=y
+-# CONFIG_SERIAL_8250_CONSOLE is not set
+-# CONFIG_SERIAL_8250_ACPI is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
+ CONFIG_SERIAL_8250_NR_UARTS=4
+ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ # CONFIG_SERIAL_8250_EXTENDED is not set
+@@ -804,14 +958,11 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ # 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=y
+ CONFIG_LEGACY_PTY_COUNT=256
+-CONFIG_PRINTER=y
+-# CONFIG_LP_CONSOLE is not set
+-# CONFIG_PPDEV is not set
+-# CONFIG_TIPAR is not set
+
+ #
+ # IPMI
+@@ -822,8 +973,12 @@ CONFIG_PRINTER=y
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_HW_RANDOM is not set
+-CONFIG_NVRAM=y
++CONFIG_HW_RANDOM=y
++CONFIG_HW_RANDOM_INTEL=y
++CONFIG_HW_RANDOM_AMD=y
++CONFIG_HW_RANDOM_GEODE=y
++CONFIG_HW_RANDOM_VIA=y
++# CONFIG_NVRAM is not set
+ CONFIG_RTC=y
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -833,31 +988,28 @@ CONFIG_RTC=y
+ #
+ # Ftape, the floppy tape device driver
+ #
+-# CONFIG_FTAPE is not set
+ CONFIG_AGP=y
+ # CONFIG_AGP_ALI is not set
+ # CONFIG_AGP_ATI is not set
+ # CONFIG_AGP_AMD is not set
+-# CONFIG_AGP_AMD64 is not set
+-# CONFIG_AGP_INTEL is not set
++CONFIG_AGP_AMD64=y
++CONFIG_AGP_INTEL=y
+ # CONFIG_AGP_NVIDIA is not set
+ # CONFIG_AGP_SIS is not set
+ # CONFIG_AGP_SWORKS is not set
+-CONFIG_AGP_VIA=y
++# CONFIG_AGP_VIA is not set
+ # CONFIG_AGP_EFFICEON is not set
+-CONFIG_DRM=y
+-# CONFIG_DRM_TDFX is not set
+-# CONFIG_DRM_R128 is not set
+-CONFIG_DRM_RADEON=y
+-# CONFIG_DRM_MGA is not set
+-# CONFIG_DRM_SIS is not set
+-# CONFIG_DRM_VIA is not set
+-# CONFIG_DRM_SAVAGE is not set
++# CONFIG_DRM is not set
+ # CONFIG_MWAVE is not set
++# CONFIG_PC8736x_GPIO is not set
++# CONFIG_NSC_GPIO is not set
+ # CONFIG_CS5535_GPIO is not set
+-# CONFIG_RAW_DRIVER is not set
+-# CONFIG_HPET is not set
+-# CONFIG_HANGCHECK_TIMER is not set
++CONFIG_RAW_DRIVER=y
++CONFIG_MAX_RAW_DEVS=256
++CONFIG_HPET=y
++# CONFIG_HPET_RTC_IRQ is not set
++CONFIG_HPET_MMAP=y
++CONFIG_HANGCHECK_TIMER=y
+
+ #
+ # TPM devices
+@@ -868,59 +1020,7 @@ CONFIG_DRM_RADEON=y
+ #
+ # I2C support
+ #
+-CONFIG_I2C=y
+-CONFIG_I2C_CHARDEV=y
+-
+-#
+-# I2C Algorithms
+-#
+-CONFIG_I2C_ALGOBIT=y
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-# CONFIG_I2C_PIIX4 is not set
+-CONFIG_I2C_ISA=y
+-# CONFIG_I2C_NFORCE2 is not set
+-# CONFIG_I2C_PARPORT is not set
+-# CONFIG_I2C_PARPORT_LIGHT is not set
+-# CONFIG_I2C_PROSAVAGE is not set
+-# CONFIG_I2C_SAVAGE4 is not set
+-# CONFIG_SCx200_ACB is not set
+-# CONFIG_I2C_SIS5595 is not set
+-# CONFIG_I2C_SIS630 is not set
+-# CONFIG_I2C_SIS96X is not set
+-# CONFIG_I2C_STUB is not set
+-# CONFIG_I2C_VIA is not set
+-CONFIG_I2C_VIAPRO=y
+-# CONFIG_I2C_VOODOO3 is not set
+-# CONFIG_I2C_PCA_ISA is not set
+-
+-#
+-# Miscellaneous 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_RTC_X1205_I2C is not set
+-# CONFIG_I2C_DEBUG_CORE is not set
+-# CONFIG_I2C_DEBUG_ALGO is not set
+-# CONFIG_I2C_DEBUG_BUS is not set
+-# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_I2C is not set
+
+ #
+ # SPI support
+@@ -936,164 +1036,34 @@ CONFIG_I2C_VIAPRO=y
+ #
+ # Hardware Monitoring support
+ #
+-CONFIG_HWMON=y
+-CONFIG_HWMON_VID=y
+-# CONFIG_SENSORS_ADM1021 is not set
+-# 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_F71805F 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=y
+-# CONFIG_SENSORS_LM63 is not set
+-# CONFIG_SENSORS_LM75 is not set
+-# CONFIG_SENSORS_LM77 is not set
+-# CONFIG_SENSORS_LM78 is not set
+-# CONFIG_SENSORS_LM80 is not set
+-# CONFIG_SENSORS_LM83 is not set
+-# CONFIG_SENSORS_LM85 is not set
+-# CONFIG_SENSORS_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_SIS5595 is not set
+-# CONFIG_SENSORS_SMSC47M1 is not set
+-# CONFIG_SENSORS_SMSC47B397 is not set
+-# CONFIG_SENSORS_VIA686A is not set
+-# CONFIG_SENSORS_VT8231 is not set
+-# CONFIG_SENSORS_W83781D is not set
+-# CONFIG_SENSORS_W83792D is not set
+-# CONFIG_SENSORS_W83L785TS is not set
+-# CONFIG_SENSORS_W83627HF is not set
+-# CONFIG_SENSORS_W83627EHF is not set
+-# CONFIG_SENSORS_HDAPS is not set
+-# CONFIG_HWMON_DEBUG_CHIP is not set
+-
+-#
+-# Misc devices
+-#
+-# CONFIG_IBM_ASM is not set
+-
+-#
+-# Multimedia Capabilities Port drivers
+-#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
+
+ #
+ # Multimedia devices
+ #
+-CONFIG_VIDEO_DEV=y
+-
+-#
+-# Video For Linux
+-#
+-
+-#
+-# Video Adapters
+-#
+-# CONFIG_VIDEO_ADV_DEBUG is not set
+-# CONFIG_VIDEO_BT848 is not set
+-# CONFIG_VIDEO_BWQCAM is not set
+-# CONFIG_VIDEO_CQCAM is not set
+-# CONFIG_VIDEO_W9966 is not set
+-# CONFIG_VIDEO_CPIA is not set
+-# CONFIG_VIDEO_SAA5246A is not set
+-# CONFIG_VIDEO_SAA5249 is not set
+-# CONFIG_TUNER_3036 is not set
+-# CONFIG_VIDEO_STRADIS is not set
+-# CONFIG_VIDEO_ZORAN is not set
+-CONFIG_VIDEO_SAA7134=y
+-# CONFIG_VIDEO_SAA7134_ALSA is not set
+-# CONFIG_VIDEO_MXB is not set
+-# CONFIG_VIDEO_DPC is not set
+-# CONFIG_VIDEO_HEXIUM_ORION is not set
+-# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+-# CONFIG_VIDEO_CX88 is not set
+-# CONFIG_VIDEO_EM28XX is not set
+-# CONFIG_VIDEO_OVCAMCHIP is not set
+-# CONFIG_VIDEO_AUDIO_DECODER is not set
+-# CONFIG_VIDEO_DECODER is not set
+-
+-#
+-# Radio Adapters
+-#
+-# CONFIG_RADIO_GEMTEK_PCI is not set
+-# CONFIG_RADIO_MAXIRADIO is not set
+-# CONFIG_RADIO_MAESTRO is not set
++# CONFIG_VIDEO_DEV is not set
+
+ #
+ # Digital Video Broadcasting Devices
+ #
+ # CONFIG_DVB is not set
+-CONFIG_VIDEO_TUNER=y
+-CONFIG_VIDEO_BUF=y
+-CONFIG_VIDEO_IR=y
++# CONFIG_USB_DABUSB 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_MACMODES is not set
+-CONFIG_FB_MODE_HELPERS=y
+-# CONFIG_FB_TILEBLITTING is not set
+-# CONFIG_FB_CIRRUS is not set
+-# CONFIG_FB_PM2 is not set
+-# CONFIG_FB_CYBER2000 is not set
+-# CONFIG_FB_ARC is not set
+-# CONFIG_FB_ASILIANT is not set
+-# CONFIG_FB_IMSTT is not set
+-# CONFIG_FB_VGA16 is not set
+-# CONFIG_FB_VESA is not set
+-CONFIG_VIDEO_SELECT=y
+-# CONFIG_FB_HGA is not set
+-# CONFIG_FB_S1D13XXX is not set
+-# CONFIG_FB_NVIDIA is not set
+-# CONFIG_FB_RIVA is not set
+-# CONFIG_FB_I810 is not set
+-# CONFIG_FB_INTEL is not set
+-# CONFIG_FB_MATROX is not set
+-# CONFIG_FB_RADEON_OLD is not set
+-CONFIG_FB_RADEON=y
+-CONFIG_FB_RADEON_I2C=y
+-# CONFIG_FB_RADEON_DEBUG is not set
+-# CONFIG_FB_ATY128 is not set
+-# CONFIG_FB_ATY is not set
+-# CONFIG_FB_SAVAGE is not set
+-# CONFIG_FB_SIS is not set
+-# CONFIG_FB_NEOMAGIC is not set
+-# CONFIG_FB_KYRO is not set
+-# CONFIG_FB_3DFX is not set
+-# CONFIG_FB_VOODOO1 is not set
+-# CONFIG_FB_CYBLA is not set
+-# CONFIG_FB_TRIDENT is not set
+-# CONFIG_FB_GEODE is not set
+-# CONFIG_FB_VIRTUAL is not set
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB is not set
+
+ #
+ # Console display driver support
+ #
+ CONFIG_VGA_CONSOLE=y
++CONFIG_VGACON_SOFT_SCROLLBACK=y
++CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=128
++CONFIG_VIDEO_SELECT=y
+ CONFIG_DUMMY_CONSOLE=y
+-CONFIG_FRAMEBUFFER_CONSOLE=y
+-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+-# CONFIG_FONTS is not set
+-CONFIG_FONT_8x8=y
+-CONFIG_FONT_8x16=y
+-
+-#
+-# Logo configuration
+-#
+-# CONFIG_LOGO is not set
+ # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+@@ -1104,97 +1074,30 @@ CONFIG_SOUND=y
+ #
+ # Advanced Linux Sound Architecture
+ #
+-CONFIG_SND=y
+-CONFIG_SND_TIMER=y
+-CONFIG_SND_PCM=y
+-CONFIG_SND_RAWMIDI=y
+-CONFIG_SND_SEQUENCER=y
+-# CONFIG_SND_SEQ_DUMMY is not set
+-# CONFIG_SND_MIXER_OSS is not set
+-# CONFIG_SND_PCM_OSS is not set
+-# CONFIG_SND_SEQUENCER_OSS is not set
+-CONFIG_SND_RTCTIMER=y
+-CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+-# CONFIG_SND_DYNAMIC_MINORS is not set
+-# CONFIG_SND_SUPPORT_OLD_API is not set
+-# CONFIG_SND_VERBOSE_PRINTK is not set
+-# CONFIG_SND_DEBUG is not set
+-
+-#
+-# Generic devices
+-#
+-CONFIG_SND_MPU401_UART=y
+-CONFIG_SND_AC97_CODEC=y
+-CONFIG_SND_AC97_BUS=y
+-# CONFIG_SND_DUMMY is not set
+-# CONFIG_SND_VIRMIDI is not set
+-# CONFIG_SND_MTPAV is not set
+-# CONFIG_SND_SERIAL_U16550 is not set
+-# CONFIG_SND_MPU401 is not set
+-
+-#
+-# PCI devices
+-#
+-# CONFIG_SND_AD1889 is not set
+-# CONFIG_SND_ALS4000 is not set
+-# CONFIG_SND_ALI5451 is not set
+-# CONFIG_SND_ATIIXP is not set
+-# CONFIG_SND_ATIIXP_MODEM is not set
+-# CONFIG_SND_AU8810 is not set
+-# CONFIG_SND_AU8820 is not set
+-# CONFIG_SND_AU8830 is not set
+-# CONFIG_SND_AZT3328 is not set
+-# CONFIG_SND_BT87X is not set
+-# CONFIG_SND_CA0106 is not set
+-# CONFIG_SND_CMIPCI is not set
+-# CONFIG_SND_CS4281 is not set
+-# CONFIG_SND_CS46XX is not set
+-# CONFIG_SND_CS5535AUDIO is not set
+-# CONFIG_SND_EMU10K1 is not set
+-# CONFIG_SND_EMU10K1X is not set
+-# CONFIG_SND_ENS1370 is not set
+-# CONFIG_SND_ENS1371 is not set
+-# CONFIG_SND_ES1938 is not set
+-# CONFIG_SND_ES1968 is not set
+-# CONFIG_SND_FM801 is not set
+-# CONFIG_SND_HDA_INTEL is not set
+-# CONFIG_SND_HDSP is not set
+-# CONFIG_SND_HDSPM is not set
+-# CONFIG_SND_ICE1712 is not set
+-# CONFIG_SND_ICE1724 is not set
+-# CONFIG_SND_INTEL8X0 is not set
+-# CONFIG_SND_INTEL8X0M is not set
+-# CONFIG_SND_KORG1212 is not set
+-# CONFIG_SND_MAESTRO3 is not set
+-# CONFIG_SND_MIXART is not set
+-# CONFIG_SND_NM256 is not set
+-# CONFIG_SND_PCXHR is not set
+-# CONFIG_SND_RME32 is not set
+-# CONFIG_SND_RME96 is not set
+-# CONFIG_SND_RME9652 is not set
+-# CONFIG_SND_SONICVIBES is not set
+-# CONFIG_SND_TRIDENT is not set
+-CONFIG_SND_VIA82XX=y
+-# CONFIG_SND_VIA82XX_MODEM is not set
+-# CONFIG_SND_VX222 is not set
+-# CONFIG_SND_YMFPCI is not set
+-
+-#
+-# USB devices
+-#
+-# CONFIG_SND_USB_AUDIO is not set
+-# CONFIG_SND_USB_USX2Y is not set
++# CONFIG_SND is not set
+
+ #
+ # Open Sound System
+ #
+-# CONFIG_SOUND_PRIME is not set
++CONFIG_SOUND_PRIME=y
++CONFIG_OSS_OBSOLETE_DRIVER=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_ES1371 is not set
++CONFIG_SOUND_ICH=y
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
+
+ #
+ # USB support
+ #
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
+ CONFIG_USB=y
+ # CONFIG_USB_DEBUG is not set
+
+@@ -1213,17 +1116,19 @@ CONFIG_USB_DEVICEFS=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_EHCI_TT_NEWSCHED is not set
+ # CONFIG_USB_ISP116X_HCD is not set
+-# CONFIG_USB_OHCI_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
+
+ #
+ # USB Device Class drivers
+ #
+-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+ # CONFIG_USB_ACM is not set
+-# CONFIG_USB_PRINTER is not set
++CONFIG_USB_PRINTER=y
+
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+@@ -1243,26 +1148,23 @@ CONFIG_USB_STORAGE=y
+ # CONFIG_USB_STORAGE_SDDR55 is not set
+ # CONFIG_USB_STORAGE_JUMPSHOT is not set
+ # CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
+ # CONFIG_USB_LIBUSUAL is not set
+
+ #
+ # USB Input Devices
+ #
+-# CONFIG_USB_HID is not set
+-
+-#
+-# USB HID Boot Protocol drivers
+-#
+-# CONFIG_USB_KBD is not set
+-# CONFIG_USB_MOUSE is not set
++CONFIG_USB_HID=y
++CONFIG_USB_HIDINPUT=y
++# CONFIG_USB_HIDINPUT_POWERBOOK is not set
++# CONFIG_HID_FF is not set
++# CONFIG_USB_HIDDEV is not set
+ # CONFIG_USB_AIPTEK is not set
+ # CONFIG_USB_WACOM is not set
+ # CONFIG_USB_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_TOUCHSCREEN is not set
+ # CONFIG_USB_YEALINK is not set
+ # CONFIG_USB_XPAD is not set
+ # CONFIG_USB_ATI_REMOTE is not set
+@@ -1277,21 +1179,6 @@ CONFIG_USB_STORAGE=y
+ # CONFIG_USB_MICROTEK is not set
+
+ #
+-# USB Multimedia devices
+-#
+-# CONFIG_USB_DABUSB is not set
+-# CONFIG_USB_VICAM is not set
+-# CONFIG_USB_DSBR is not set
+-# CONFIG_USB_ET61X251 is not set
+-# CONFIG_USB_IBMCAM is not set
+-# CONFIG_USB_KONICAWC is not set
+-# CONFIG_USB_OV511 is not set
+-# 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
+ #
+ # CONFIG_USB_CATC is not set
+@@ -1299,12 +1186,11 @@ CONFIG_USB_STORAGE=y
+ # CONFIG_USB_PEGASUS is not set
+ # CONFIG_USB_RTL8150 is not set
+ # CONFIG_USB_USBNET is not set
+-# CONFIG_USB_MON is not set
++CONFIG_USB_MON=y
+
+ #
+ # USB port drivers
+ #
+-# CONFIG_USB_USS720 is not set
+
+ #
+ # USB Serial Converter support
+@@ -1316,17 +1202,21 @@ CONFIG_USB_STORAGE=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_SISUSBVGA is not set
+ # CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+ # CONFIG_USB_TEST is not set
+
+ #
+@@ -1344,56 +1234,99 @@ CONFIG_USB_STORAGE=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
+-# SN Devices
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+ #
++# CONFIG_EDAC is not set
+
+ #
+-# EDAC - error detection and reporting (RAS)
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
+ #
+-# CONFIG_EDAC is not set
+
+ #
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
++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 is not set
+-# CONFIG_REISERFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++CONFIG_EXT3_FS_POSIX_ACL=y
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4DEV_FS is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++CONFIG_REISERFS_FS=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++CONFIG_REISERFS_FS_XATTR=y
++CONFIG_REISERFS_FS_POSIX_ACL=y
++# CONFIG_REISERFS_FS_SECURITY is not set
+ # CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FS_POSIX_ACL=y
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+-# CONFIG_INOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
++CONFIG_AUTOFS4_FS=y
+ # CONFIG_FUSE_FS is not set
++CONFIG_GENERIC_ACL=y
+
+ #
+ # CD-ROM/DVD Filesystems
+ #
+ CONFIG_ISO9660_FS=y
+-CONFIG_JOLIET=y
+-CONFIG_ZISOFS=y
+-CONFIG_ZISOFS_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
+ # CONFIG_UDF_FS is not set
+
+ #
+ # DOS/FAT/NT Filesystems
+ #
+ CONFIG_FAT_FS=y
+-# CONFIG_MSDOS_FS is not set
++CONFIG_MSDOS_FS=y
+ CONFIG_VFAT_FS=y
+-CONFIG_FAT_DEFAULT_CODEPAGE=850
++CONFIG_FAT_DEFAULT_CODEPAGE=437
+ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ # CONFIG_NTFS_FS is not set
+
+@@ -1402,12 +1335,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+-# CONFIG_HUGETLBFS is not set
+-# CONFIG_HUGETLB_PAGE is not set
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+ # CONFIG_CONFIGFS_FS is not set
+
+ #
+@@ -1430,13 +1364,26 @@ CONFIG_RAMFS=y
+ #
+ # Network File Systems
+ #
+-# CONFIG_NFS_FS is not set
+-# CONFIG_NFSD is not set
++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=y
++CONFIG_NFSD_V3=y
++# CONFIG_NFSD_V3_ACL is not set
++# CONFIG_NFSD_V4 is not set
++CONFIG_NFSD_TCP=y
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=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=y
+-# CONFIG_CIFS_STATS is not set
+-# CONFIG_CIFS_XATTR is not set
+-# CONFIG_CIFS_EXPERIMENTAL 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
+@@ -1445,33 +1392,18 @@ CONFIG_CIFS=y
+ #
+ # 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_PARTITION_ADVANCED 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_KARMA_PARTITION is not set
+-# CONFIG_EFI_PARTITION is not set
+
+ #
+ # Native Language Support
+ #
+ CONFIG_NLS=y
+-CONFIG_NLS_DEFAULT="iso8859-15"
+-# CONFIG_NLS_CODEPAGE_437 is not set
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
+ # CONFIG_NLS_CODEPAGE_737 is not set
+ # CONFIG_NLS_CODEPAGE_775 is not set
+-CONFIG_NLS_CODEPAGE_850=y
++# 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
+@@ -1491,7 +1423,7 @@ CONFIG_NLS_CODEPAGE_850=y
+ # 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_ASCII=y
+ CONFIG_NLS_ISO8859_1=y
+ # CONFIG_NLS_ISO8859_2 is not set
+ # CONFIG_NLS_ISO8859_3 is not set
+@@ -1510,20 +1442,54 @@ CONFIG_NLS_UTF8=y
+ #
+ # Instrumentation Support
+ #
+-# CONFIG_PROFILING is not set
+-# CONFIG_KPROBES is not set
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=y
++CONFIG_KPROBES=y
+
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
+ CONFIG_MAGIC_SYSRQ=y
+-# CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
++CONFIG_UNUSED_SYMBOLS=y
++CONFIG_DEBUG_KERNEL=y
++CONFIG_LOG_BUF_SHIFT=18
++CONFIG_DETECT_SOFTLOCKUP=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
+ CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_FRAME_POINTER is not set
++CONFIG_UNWIND_INFO=y
++CONFIG_STACK_UNWIND=y
++# CONFIG_FORCED_INLINING is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
+ CONFIG_EARLY_PRINTK=y
++CONFIG_DEBUG_STACKOVERFLOW=y
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_RODATA is not set
++# CONFIG_4KSTACKS is not set
+ CONFIG_X86_FIND_SMP_CONFIG=y
+ CONFIG_X86_MPPARSE=y
++CONFIG_DOUBLEFAULT=y
+
+ #
+ # Security options
+@@ -1537,10 +1503,6 @@ CONFIG_X86_MPPARSE=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+@@ -1548,7 +1510,12 @@ CONFIG_X86_MPPARSE=y
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
++CONFIG_PLIST=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_X86_SMP=y
++CONFIG_X86_HT=y
+ CONFIG_X86_BIOS_REBOOT=y
++CONFIG_X86_TRAMPOLINE=y
+ CONFIG_KTIME_SCALAR=y
+diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
+index 5427a84..1a884b6 100644
+--- a/arch/i386/kernel/Makefile
++++ b/arch/i386/kernel/Makefile
+@@ -4,7 +4,7 @@
+
+ extra-y := head.o init_task.o vmlinux.lds
+
+-obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
++obj-y := process.o signal.o entry.o traps.o irq.o \
+ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
+ pci-dma.o i386_ksyms.o i387.o bootflag.o \
+ quirks.o i8237.o topology.o alternative.o i8253.o tsc.o
+@@ -81,4 +81,5 @@ $(obj)/vsyscall-syms.o: $(src)/vsyscall.
+ $(call if_changed,syscall)
+
+ k8-y += ../../x86_64/kernel/k8.o
++stacktrace-y += ../../x86_64/kernel/stacktrace.o
+
+diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile
+index 7e9ac99..7f7be01 100644
+--- a/arch/i386/kernel/acpi/Makefile
++++ b/arch/i386/kernel/acpi/Makefile
+@@ -1,5 +1,7 @@
+ obj-$(CONFIG_ACPI) += boot.o
++ifneq ($(CONFIG_PCI),)
+ obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
++endif
+ obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
+
+ ifneq ($(CONFIG_ACPI_PROCESSOR),)
+diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
+index ee003bc..22e4c46 100644
+--- a/arch/i386/kernel/acpi/boot.c
++++ b/arch/i386/kernel/acpi/boot.c
+@@ -26,9 +26,12 @@
+ #include <linux/init.h>
+ #include <linux/acpi.h>
+ #include <linux/efi.h>
++#include <linux/cpumask.h>
+ #include <linux/module.h>
+ #include <linux/dmi.h>
+ #include <linux/irq.h>
++#include <linux/bootmem.h>
++#include <linux/ioport.h>
+
+ #include <asm/pgtable.h>
+ #include <asm/io_apic.h>
+@@ -36,11 +39,17 @@
+ #include <asm/io.h>
+ #include <asm/mpspec.h>
+
+-#ifdef CONFIG_X86_64
++static int __initdata acpi_force = 0;
++
++#ifdef CONFIG_ACPI
++int acpi_disabled = 0;
++#else
++int acpi_disabled = 1;
++#endif
++EXPORT_SYMBOL(acpi_disabled);
+
+-extern void __init clustered_apic_check(void);
++#ifdef CONFIG_X86_64
+
+-extern int gsi_irq_sharing(int gsi);
+ #include <asm/proto.h>
+
+ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return 0; }
+@@ -53,8 +62,6 @@ static inline int acpi_madt_oem_check(ch
+ #include <mach_mpparse.h>
+ #endif /* CONFIG_X86_LOCAL_APIC */
+
+-static inline int gsi_irq_sharing(int gsi) { return gsi; }
+-
+ #endif /* X86 */
+
+ #define BAD_MADT_ENTRY(entry, end) ( \
+@@ -63,7 +70,7 @@ static inline int gsi_irq_sharing(int gs
+
+ #define PREFIX "ACPI: "
+
+-int acpi_noirq __initdata; /* skip ACPI IRQ initialization */
++int acpi_noirq; /* skip ACPI IRQ initialization */
+ int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */
+ int acpi_ht __initdata = 1; /* enable HT */
+
+@@ -325,7 +332,7 @@ acpi_parse_ioapic(acpi_table_entry_heade
+ /*
+ * Parse Interrupt Source Override for the ACPI SCI
+ */
+-static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
++static void acpi_sci_ioapic_setup(u32 bus_irq, u32 gsi, u16 polarity, u16 trigger)
+ {
+ if (trigger == 0) /* compatible SCI trigger is level */
+ trigger = 3;
+@@ -345,13 +352,13 @@ static void acpi_sci_ioapic_setup(u32 gs
+ * If GSI is < 16, this will update its flags,
+ * else it will create a new mp_irqs[] entry.
+ */
+- mp_override_legacy_irq(gsi, polarity, trigger, gsi);
++ mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
+
+ /*
+ * stash over-ride to indicate we've been here
+ * and for later update of acpi_fadt
+ */
+- acpi_sci_override_gsi = gsi;
++ acpi_sci_override_gsi = bus_irq;
+ return;
+ }
+
+@@ -369,7 +376,7 @@ acpi_parse_int_src_ovr(acpi_table_entry_
+ acpi_table_print_madt_entry(header);
+
+ if (intsrc->bus_irq == acpi_fadt.sci_int) {
+- acpi_sci_ioapic_setup(intsrc->global_irq,
++ acpi_sci_ioapic_setup(intsrc->bus_irq, intsrc->global_irq,
+ intsrc->flags.polarity,
+ intsrc->flags.trigger);
+ return 0;
+@@ -459,12 +466,7 @@ void __init acpi_pic_sci_set_trigger(uns
+
+ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
+ {
+-#ifdef CONFIG_X86_IO_APIC
+- if (use_pci_vector() && !platform_legacy_irq(gsi))
+- *irq = IO_APIC_VECTOR(gsi);
+- else
+-#endif
+- *irq = gsi_irq_sharing(gsi);
++ *irq = gsi;
+ return 0;
+ }
+
+@@ -506,16 +508,76 @@ EXPORT_SYMBOL(acpi_register_gsi);
+ #ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
+ {
+- /* TBD */
+- return -EINVAL;
++ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
++ union acpi_object *obj;
++ struct acpi_table_lapic *lapic;
++ cpumask_t tmp_map, new_map;
++ u8 physid;
++ int cpu;
++
++ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
++ return -EINVAL;
++
++ if (!buffer.length || !buffer.pointer)
++ return -EINVAL;
++
++ obj = buffer.pointer;
++ if (obj->type != ACPI_TYPE_BUFFER ||
++ obj->buffer.length < sizeof(*lapic)) {
++ kfree(buffer.pointer);
++ return -EINVAL;
++ }
++
++ lapic = (struct acpi_table_lapic *)obj->buffer.pointer;
++
++ if ((lapic->header.type != ACPI_MADT_LAPIC) ||
++ (!lapic->flags.enabled)) {
++ kfree(buffer.pointer);
++ return -EINVAL;
++ }
++
++ physid = lapic->id;
++
++ kfree(buffer.pointer);
++ buffer.length = ACPI_ALLOCATE_BUFFER;
++ buffer.pointer = NULL;
++
++ tmp_map = cpu_present_map;
++ mp_register_lapic(physid, lapic->flags.enabled);
++
++ /*
++ * If mp_register_lapic successfully generates a new logical cpu
++ * number, then the following will get us exactly what was mapped
++ */
++ cpus_andnot(new_map, cpu_present_map, tmp_map);
++ if (cpus_empty(new_map)) {
++ printk ("Unable to map lapic to logical cpu number\n");
++ return -EINVAL;
++ }
++
++ cpu = first_cpu(new_map);
++
++ *pcpu = cpu;
++ return 0;
+ }
+
+ EXPORT_SYMBOL(acpi_map_lsapic);
+
+ int acpi_unmap_lsapic(int cpu)
+ {
+- /* TBD */
+- return -EINVAL;
++ int i;
++
++ for_each_possible_cpu(i) {
++ if (x86_acpiid_to_apicid[i] == x86_cpu_to_apicid[cpu]) {
++ x86_acpiid_to_apicid[i] = -1;
++ break;
++ }
++ }
++ x86_cpu_to_apicid[cpu] = -1;
++ cpu_clear(cpu, cpu_present_map);
++ num_processors--;
++
++ return (0);
+ }
+
+ EXPORT_SYMBOL(acpi_unmap_lsapic);
+@@ -579,6 +641,8 @@ static int __init acpi_parse_sbf(unsigne
+ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
+ {
+ struct acpi_table_hpet *hpet_tbl;
++ struct resource *hpet_res;
++ resource_size_t res_start;
+
+ if (!phys || !size)
+ return -EINVAL;
+@@ -594,12 +658,26 @@ static int __init acpi_parse_hpet(unsign
+ "memory.\n");
+ return -1;
+ }
++
++#define HPET_RESOURCE_NAME_SIZE 9
++ hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
++ if (hpet_res) {
++ memset(hpet_res, 0, sizeof(*hpet_res));
++ hpet_res->name = (void *)&hpet_res[1];
++ hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++ snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE,
++ "HPET %u", hpet_tbl->number);
++ hpet_res->end = (1 * 1024) - 1;
++ }
++
+ #ifdef CONFIG_X86_64
+ vxtime.hpet_address = hpet_tbl->addr.addrl |
+ ((long)hpet_tbl->addr.addrh << 32);
+
+ printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
+ hpet_tbl->id, vxtime.hpet_address);
++
++ res_start = vxtime.hpet_address;
+ #else /* X86 */
+ {
+ extern unsigned long hpet_address;
+@@ -607,9 +685,17 @@ static int __init acpi_parse_hpet(unsign
+ hpet_address = hpet_tbl->addr.addrl;
+ printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
+ hpet_tbl->id, hpet_address);
++
++ res_start = hpet_address;
+ }
+ #endif /* X86 */
+
++ if (hpet_res) {
++ hpet_res->start = res_start;
++ hpet_res->end += res_start;
++ insert_resource(&iomem_resource, hpet_res);
++ }
++
+ return 0;
+ }
+ #else
+@@ -793,7 +879,7 @@ static int __init acpi_parse_madt_ioapic
+ * pretend we got one so we can set the SCI flags.
+ */
+ if (!acpi_sci_override_gsi)
+- acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
++ acpi_sci_ioapic_setup(acpi_fadt.sci_int, acpi_fadt.sci_int, 0, 0);
+
+ /* Fill in identity legacy mapings where no override */
+ mp_config_acpi_legacy_irqs();
+@@ -860,8 +946,6 @@ static void __init acpi_process_madt(voi
+ return;
+ }
+
+-extern int acpi_force;
+-
+ #ifdef __i386__
+
+ static int __init disable_acpi_irq(struct dmi_system_id *d)
+@@ -1163,3 +1247,75 @@ int __init acpi_boot_init(void)
+
+ return 0;
+ }
++
++static int __init parse_acpi(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
++
++ /* "acpi=off" disables both ACPI table parsing and interpreter */
++ if (strcmp(arg, "off") == 0) {
++ disable_acpi();
++ }
++ /* acpi=force to over-ride black-list */
++ else if (strcmp(arg, "force") == 0) {
++ acpi_force = 1;
++ acpi_ht = 1;
++ acpi_disabled = 0;
++ }
++ /* acpi=strict disables out-of-spec workarounds */
++ else if (strcmp(arg, "strict") == 0) {
++ acpi_strict = 1;
++ }
++ /* Limit ACPI just to boot-time to enable HT */
++ else if (strcmp(arg, "ht") == 0) {
++ if (!acpi_force)
++ disable_acpi();
++ acpi_ht = 1;
++ }
++ /* "acpi=noirq" disables ACPI interrupt routing */
++ else if (strcmp(arg, "noirq") == 0) {
++ acpi_noirq_set();
++ } else {
++ /* Core will printk when we return error. */
++ return -EINVAL;
++ }
++ return 0;
++}
++early_param("acpi", parse_acpi);
++
++/* FIXME: Using pci= for an ACPI parameter is a travesty. */
++static int __init parse_pci(char *arg)
++{
++ if (arg && strcmp(arg, "noacpi") == 0)
++ acpi_disable_pci();
++ return 0;
++}
++early_param("pci", parse_pci);
++
++#ifdef CONFIG_X86_IO_APIC
++static int __init parse_acpi_skip_timer_override(char *arg)
++{
++ acpi_skip_timer_override = 1;
++ return 0;
++}
++early_param("acpi_skip_timer_override", parse_acpi_skip_timer_override);
++#endif /* CONFIG_X86_IO_APIC */
++
++static int __init setup_acpi_sci(char *s)
++{
++ if (!s)
++ return -EINVAL;
++ if (!strcmp(s, "edge"))
++ acpi_sci_flags.trigger = 1;
++ else if (!strcmp(s, "level"))
++ acpi_sci_flags.trigger = 3;
++ else if (!strcmp(s, "high"))
++ acpi_sci_flags.polarity = 1;
++ else if (!strcmp(s, "low"))
++ acpi_sci_flags.polarity = 3;
++ else
++ return -EINVAL;
++ return 0;
++}
++early_param("acpi_sci", setup_acpi_sci);
+diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c
+index 25db49e..20563e5 100644
+--- a/arch/i386/kernel/acpi/cstate.c
++++ b/arch/i386/kernel/acpi/cstate.c
+@@ -10,6 +10,7 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/acpi.h>
++#include <linux/cpu.h>
+
+ #include <acpi/processor.h>
+ #include <asm/acpi.h>
+@@ -41,5 +42,124 @@ void acpi_processor_power_init_bm_check(
+ flags->bm_check = 1;
+ }
+ }
+-
+ EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
++
++/* The code below handles cstate entry with monitor-mwait pair on Intel*/
++
++struct cstate_entry_s {
++ struct {
++ unsigned int eax;
++ unsigned int ecx;
++ } states[ACPI_PROCESSOR_MAX_POWER];
++};
++static struct cstate_entry_s *cpu_cstate_entry; /* per CPU ptr */
++
++static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
++
++#define MWAIT_SUBSTATE_MASK (0xf)
++#define MWAIT_SUBSTATE_SIZE (4)
++
++#define CPUID_MWAIT_LEAF (5)
++#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
++#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
++
++#define MWAIT_ECX_INTERRUPT_BREAK (0x1)
++
++#define NATIVE_CSTATE_BEYOND_HALT (2)
++
++int acpi_processor_ffh_cstate_probe(unsigned int cpu,
++ struct acpi_processor_cx *cx, struct acpi_power_register *reg)
++{
++ struct cstate_entry_s *percpu_entry;
++ struct cpuinfo_x86 *c = cpu_data + cpu;
++
++ cpumask_t saved_mask;
++ int retval;
++ unsigned int eax, ebx, ecx, edx;
++ unsigned int edx_part;
++ unsigned int cstate_type; /* C-state type and not ACPI C-state type */
++ unsigned int num_cstate_subtype;
++
++ if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF )
++ return -1;
++
++ if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT)
++ return -1;
++
++ percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
++ percpu_entry->states[cx->index].eax = 0;
++ percpu_entry->states[cx->index].ecx = 0;
++
++ /* Make sure we are running on right CPU */
++ saved_mask = current->cpus_allowed;
++ retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
++ if (retval)
++ return -1;
++
++ cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
++
++ /* Check whether this particular cx_type (in CST) is supported or not */
++ cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1;
++ edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
++ num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
++
++ retval = 0;
++ if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
++ retval = -1;
++ goto out;
++ }
++
++ /* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
++ if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
++ !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
++ retval = -1;
++ goto out;
++ }
++ percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
++
++ /* Use the hint in CST */
++ percpu_entry->states[cx->index].eax = cx->address;
++
++ if (!mwait_supported[cstate_type]) {
++ mwait_supported[cstate_type] = 1;
++ printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d "
++ "state\n", cx->type);
++ }
++
++out:
++ set_cpus_allowed(current, saved_mask);
++ return retval;
++}
++EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
++
++void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
++{
++ unsigned int cpu = smp_processor_id();
++ struct cstate_entry_s *percpu_entry;
++
++ percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
++ mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
++ percpu_entry->states[cx->index].ecx);
++}
++EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
++
++static int __init ffh_cstate_init(void)
++{
++ struct cpuinfo_x86 *c = &boot_cpu_data;
++ if (c->x86_vendor != X86_VENDOR_INTEL)
++ return -1;
++
++ cpu_cstate_entry = alloc_percpu(struct cstate_entry_s);
++ return 0;
++}
++
++static void __exit ffh_cstate_exit(void)
++{
++ if (cpu_cstate_entry) {
++ free_percpu(cpu_cstate_entry);
++ cpu_cstate_entry = NULL;
++ }
++}
++
++arch_initcall(ffh_cstate_init);
++__exitcall(ffh_cstate_exit);
+diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
+index 1649a17..fe799b1 100644
+--- a/arch/i386/kernel/acpi/earlyquirk.c
++++ b/arch/i386/kernel/acpi/earlyquirk.c
+@@ -48,7 +48,11 @@ void __init check_acpi_pci(void)
+ int num, slot, func;
+
+ /* Assume the machine supports type 1. If not it will
+- always read ffffffff and should not have any side effect. */
++ always read ffffffff and should not have any side effect.
++ Actually a few buggy systems can machine check. Allow the user
++ to disable it by command line option at least -AK */
++ if (!early_pci_allowed())
++ return;
+
+ /* Poor man's PCI discovery */
+ for (num = 0; num < 32; num++) {
+diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
+index 28ab806..583c238 100644
+--- a/arch/i386/kernel/alternative.c
++++ b/arch/i386/kernel/alternative.c
+@@ -344,6 +344,7 @@ void alternatives_smp_switch(int smp)
+
+ void __init alternative_instructions(void)
+ {
++ unsigned long flags;
+ if (no_replacement) {
+ printk(KERN_INFO "(SMP-)alternatives turned off\n");
+ free_init_pages("SMP alternatives",
+@@ -351,6 +352,8 @@ void __init alternative_instructions(voi
+ (unsigned long)__smp_alt_end);
+ return;
+ }
++
++ local_irq_save(flags);
+ apply_alternatives(__alt_instructions, __alt_instructions_end);
+
+ /* switch to patch-once-at-boottime-only mode and free the
+@@ -386,4 +389,5 @@ void __init alternative_instructions(voi
+ alternatives_smp_switch(0);
+ }
+ #endif
++ local_irq_restore(flags);
+ }
+diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
+index 8c844d0..2fd4b7d 100644
+--- a/arch/i386/kernel/apic.c
++++ b/arch/i386/kernel/apic.c
+@@ -52,7 +52,18 @@ static cpumask_t timer_bcast_ipi;
+ /*
+ * Knob to control our willingness to enable the local APIC.
+ */
+-int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
++static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
++
++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;
++}
+
+ /*
+ * Debug level
+@@ -586,8 +597,7 @@ void __devinit setup_local_APIC(void)
+ printk("No ESR for 82489DX.\n");
+ }
+
+- if (nmi_watchdog == NMI_LOCAL_APIC)
+- setup_apic_nmi_watchdog();
++ setup_apic_nmi_watchdog(NULL);
+ apic_pm_activate();
+ }
+
+@@ -1183,11 +1193,11 @@ EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
+ * value into /proc/profile.
+ */
+
+-inline void smp_local_timer_interrupt(struct pt_regs * regs)
++inline void smp_local_timer_interrupt(void)
+ {
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ #ifdef CONFIG_SMP
+- update_process_times(user_mode_vm(regs));
++ update_process_times(user_mode_vm(get_irq_regs()));
+ #endif
+
+ /*
+@@ -1213,6 +1223,7 @@ inline void smp_local_timer_interrupt(st
+
+ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ int cpu = smp_processor_id();
+
+ /*
+@@ -1231,12 +1242,13 @@ fastcall void smp_apic_timer_interrupt(s
+ * interrupt lock, which is the WrongThing (tm) to do.
+ */
+ irq_enter();
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ #ifndef CONFIG_SMP
+-static void up_apic_timer_interrupt_call(struct pt_regs *regs)
++static void up_apic_timer_interrupt_call(void)
+ {
+ int cpu = smp_processor_id();
+
+@@ -1245,11 +1257,11 @@ static void up_apic_timer_interrupt_call
+ */
+ per_cpu(irq_stat, cpu).apic_timer_irqs++;
+
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ }
+ #endif
+
+-void smp_send_timer_broadcast_ipi(struct pt_regs *regs)
++void smp_send_timer_broadcast_ipi(void)
+ {
+ cpumask_t mask;
+
+@@ -1262,7 +1274,7 @@ void smp_send_timer_broadcast_ipi(struct
+ * We can directly call the apic timer interrupt handler
+ * in UP case. Minus all irq related functions
+ */
+- up_apic_timer_interrupt_call(regs);
++ up_apic_timer_interrupt_call();
+ #endif
+ }
+ }
+@@ -1373,3 +1385,18 @@ int __init APIC_init_uniprocessor (void)
+
+ return 0;
+ }
++
++static int __init parse_lapic(char *arg)
++{
++ lapic_enable();
++ return 0;
++}
++early_param("lapic", parse_lapic);
++
++static int __init parse_nolapic(char *arg)
++{
++ lapic_disable();
++ return 0;
++}
++early_param("nolapic", parse_nolapic);
++
+diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
+index 8591f2f..a60358f 100644
+--- a/arch/i386/kernel/apm.c
++++ b/arch/i386/kernel/apm.c
+@@ -198,7 +198,7 @@
+ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
+ *
+ * [This document is available from Microsoft at:
+- * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
++ * http://www.microsoft.com/whdc/archive/amp_12.mspx]
+ */
+
+ #include <linux/module.h>
+@@ -225,6 +225,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/dmi.h>
+ #include <linux/suspend.h>
++#include <linux/kthread.h>
+
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -402,8 +403,6 @@ static int realmode_power_off = 1;
+ #else
+ static int realmode_power_off;
+ #endif
+-static int exit_kapmd __read_mostly;
+-static int kapmd_running __read_mostly;
+ #ifdef CONFIG_APM_ALLOW_INTS
+ static int allow_ints = 1;
+ #else
+@@ -419,6 +418,8 @@ static const struct desc_struct bad_bios
+
+ static const char driver_version[] = "1.16ac"; /* no spaces */
+
++static struct task_struct *kapmd_task;
++
+ /*
+ * APM event names taken from the APM 1.2 specification. These are
+ * the message codes that the BIOS uses to tell us about events
+@@ -539,12 +540,31 @@ static inline void apm_restore_cpus(cpum
+ * Also, we KNOW that for the non error case of apm_bios_call, there
+ * is no useful data returned in the low order 8 bits of eax.
+ */
+-#define APM_DO_CLI \
+- if (apm_info.allow_ints) \
+- local_irq_enable(); \
+- else \
++
++static inline unsigned long __apm_irq_save(void)
++{
++ unsigned long flags;
++ local_save_flags(flags);
++ if (apm_info.allow_ints) {
++ if (irqs_disabled_flags(flags))
++ local_irq_enable();
++ } else
+ local_irq_disable();
+
++ return flags;
++}
++
++#define apm_irq_save(flags) \
++ do { flags = __apm_irq_save(); } while (0)
++
++static inline void apm_irq_restore(unsigned long flags)
++{
++ if (irqs_disabled_flags(flags))
++ local_irq_disable();
++ else if (irqs_disabled())
++ local_irq_enable();
++}
++
+ #ifdef APM_ZERO_SEGS
+ # define APM_DECL_SEGS \
+ unsigned int saved_fs; unsigned int saved_gs;
+@@ -595,12 +615,11 @@ static u8 apm_bios_call(u32 func, u32 eb
+ save_desc_40 = gdt[0x40 / 8];
+ gdt[0x40 / 8] = bad_bios_desc;
+
+- local_save_flags(flags);
+- APM_DO_CLI;
++ apm_irq_save(flags);
+ APM_DO_SAVE_SEGS;
+ apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi);
+ APM_DO_RESTORE_SEGS;
+- local_irq_restore(flags);
++ apm_irq_restore(flags);
+ gdt[0x40 / 8] = save_desc_40;
+ put_cpu();
+ apm_restore_cpus(cpus);
+@@ -639,12 +658,11 @@ static u8 apm_bios_call_simple(u32 func,
+ save_desc_40 = gdt[0x40 / 8];
+ gdt[0x40 / 8] = bad_bios_desc;
+
+- local_save_flags(flags);
+- APM_DO_CLI;
++ apm_irq_save(flags);
+ APM_DO_SAVE_SEGS;
+ error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax);
+ APM_DO_RESTORE_SEGS;
+- local_irq_restore(flags);
++ apm_irq_restore(flags);
+ gdt[0x40 / 8] = save_desc_40;
+ put_cpu();
+ apm_restore_cpus(cpus);
+@@ -1154,9 +1172,11 @@ out:
+
+ static void set_time(void)
+ {
++ struct timespec ts;
+ if (got_clock_diff) { /* Must know time zone in order to set clock */
+- xtime.tv_sec = get_cmos_time() + clock_cmos_diff;
+- xtime.tv_nsec = 0;
++ ts.tv_sec = get_cmos_time() + clock_cmos_diff;
++ ts.tv_nsec = 0;
++ do_settimeofday(&ts);
+ }
+ }
+
+@@ -1232,13 +1252,8 @@ static int suspend(int vetoable)
+ restore_processor_state();
+
+ local_irq_disable();
+- write_seqlock(&xtime_lock);
+- spin_lock(&i8253_lock);
+- reinit_timer();
+ set_time();
+-
+- spin_unlock(&i8253_lock);
+- write_sequnlock(&xtime_lock);
++ reinit_timer();
+
+ if (err == APM_NO_ERROR)
+ err = APM_SUCCESS;
+@@ -1365,9 +1380,7 @@ static void check_events(void)
+ ignore_bounce = 1;
+ if ((event != APM_NORMAL_RESUME)
+ || (ignore_normal_resume == 0)) {
+- write_seqlock_irq(&xtime_lock);
+ set_time();
+- write_sequnlock_irq(&xtime_lock);
+ device_resume();
+ pm_send_all(PM_RESUME, (void *)0);
+ queue_event(event, NULL);
+@@ -1383,9 +1396,7 @@ static void check_events(void)
+ break;
+
+ case APM_UPDATE_TIME:
+- write_seqlock_irq(&xtime_lock);
+ set_time();
+- write_sequnlock_irq(&xtime_lock);
+ break;
+
+ case APM_CRITICAL_SUSPEND:
+@@ -1430,7 +1441,7 @@ static void apm_mainloop(void)
+ set_current_state(TASK_INTERRUPTIBLE);
+ for (;;) {
+ schedule_timeout(APM_CHECK_TIMEOUT);
+- if (exit_kapmd)
++ if (kthread_should_stop())
+ break;
+ /*
+ * Ok, check all events, check for idle (and mark us sleeping
+@@ -1713,12 +1724,6 @@ static int apm(void *unused)
+ char * power_stat;
+ char * bat_stat;
+
+- kapmd_running = 1;
+-
+- daemonize("kapmd");
+-
+- current->flags |= PF_NOFREEZE;
+-
+ #ifdef CONFIG_SMP
+ /* 2002/08/01 - WT
+ * This is to avoid random crashes at boot time during initialization
+@@ -1828,7 +1833,6 @@ static int apm(void *unused)
+ console_blank_hook = NULL;
+ #endif
+ }
+- kapmd_running = 0;
+
+ return 0;
+ }
+@@ -2227,7 +2231,7 @@ static int __init apm_init(void)
+ {
+ struct proc_dir_entry *apm_proc;
+ struct desc_struct *gdt;
+- int ret;
++ int err;
+
+ dmi_check_system(apm_dmi_table);
+
+@@ -2336,11 +2340,17 @@ static int __init apm_init(void)
+ if (apm_proc)
+ apm_proc->owner = THIS_MODULE;
+
+- ret = kernel_thread(apm, NULL, CLONE_KERNEL | SIGCHLD);
+- if (ret < 0) {
+- printk(KERN_ERR "apm: disabled - Unable to start kernel thread.\n");
+- return -ENOMEM;
++ kapmd_task = kthread_create(apm, NULL, "kapmd");
++ if (IS_ERR(kapmd_task)) {
++ printk(KERN_ERR "apm: disabled - Unable to start kernel "
++ "thread.\n");
++ err = PTR_ERR(kapmd_task);
++ kapmd_task = NULL;
++ remove_proc_entry("apm", NULL);
++ return err;
+ }
++ kapmd_task->flags |= PF_NOFREEZE;
++ wake_up_process(kapmd_task);
+
+ if (num_online_cpus() > 1 && !smp ) {
+ printk(KERN_NOTICE
+@@ -2348,7 +2358,13 @@ static int __init apm_init(void)
+ return 0;
+ }
+
+- misc_register(&apm_device);
++ /*
++ * Note we don't actually care if the misc_device cannot be registered.
++ * this driver can do its job without it, even if userspace can't
++ * control it. just log the error
++ */
++ if (misc_register(&apm_device))
++ printk(KERN_WARNING "apm: Could not register misc device.\n");
+
+ if (HZ != 100)
+ idle_period = (idle_period * HZ) / 100;
+@@ -2384,9 +2400,10 @@ static void __exit apm_exit(void)
+ remove_proc_entry("apm", NULL);
+ if (power_off)
+ pm_power_off = NULL;
+- exit_kapmd = 1;
+- while (kapmd_running)
+- schedule();
++ if (kapmd_task) {
++ kthread_stop(kapmd_task);
++ kapmd_task = NULL;
++ }
+ #ifdef CONFIG_PM_LEGACY
+ pm_active = 0;
+ #endif
+diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
+index e6a2d6b..e475809 100644
+--- a/arch/i386/kernel/cpu/amd.c
++++ b/arch/i386/kernel/cpu/amd.c
+@@ -22,7 +22,7 @@
+ extern void vide(void);
+ __asm__(".align 4\nvide: ret");
+
+-static void __init init_amd(struct cpuinfo_x86 *c)
++static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+ {
+ u32 l, h;
+ int mbytes = num_physpages >> (20-PAGE_SHIFT);
+@@ -246,7 +246,7 @@ static void __init init_amd(struct cpuin
+ num_cache_leaves = 3;
+ }
+
+-static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
++static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+ {
+ /* AMD errata T13 (order #21922) */
+ if ((c->x86 == 6)) {
+@@ -259,7 +259,7 @@ static unsigned int amd_size_cache(struc
+ return size;
+ }
+
+-static struct cpu_dev amd_cpu_dev __initdata = {
++static struct cpu_dev amd_cpu_dev __cpuinitdata = {
+ .c_vendor = "AMD",
+ .c_ident = { "AuthenticAMD" },
+ .c_models = {
+@@ -275,7 +275,6 @@ static struct cpu_dev amd_cpu_dev __init
+ },
+ },
+ .c_init = init_amd,
+- .c_identify = generic_identify,
+ .c_size_cache = amd_size_cache,
+ };
+
+diff --git a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
+index bd75629..8c25047 100644
+--- a/arch/i386/kernel/cpu/centaur.c
++++ b/arch/i386/kernel/cpu/centaur.c
+@@ -9,7 +9,7 @@
+
+ #ifdef CONFIG_X86_OOSTORE
+
+-static u32 __init power2(u32 x)
++static u32 __cpuinit power2(u32 x)
+ {
+ u32 s=1;
+ while(s<=x)
+@@ -22,7 +22,7 @@ static u32 __init power2(u32 x)
+ * Set up an actual MCR
+ */
+
+-static void __init centaur_mcr_insert(int reg, u32 base, u32 size, int key)
++static void __cpuinit centaur_mcr_insert(int reg, u32 base, u32 size, int key)
+ {
+ u32 lo, hi;
+
+@@ -40,7 +40,7 @@ static void __init centaur_mcr_insert(in
+ * Shortcut: We know you can't put 4Gig of RAM on a winchip
+ */
+
+-static u32 __init ramtop(void) /* 16388 */
++static u32 __cpuinit ramtop(void) /* 16388 */
+ {
+ int i;
+ u32 top = 0;
+@@ -91,7 +91,7 @@ static u32 __init ramtop(void) /* 16388
+ * Compute a set of MCR's to give maximum coverage
+ */
+
+-static int __init centaur_mcr_compute(int nr, int key)
++static int __cpuinit centaur_mcr_compute(int nr, int key)
+ {
+ u32 mem = ramtop();
+ u32 root = power2(mem);
+@@ -166,7 +166,7 @@ static int __init centaur_mcr_compute(in
+ return ct;
+ }
+
+-static void __init centaur_create_optimal_mcr(void)
++static void __cpuinit centaur_create_optimal_mcr(void)
+ {
+ int i;
+ /*
+@@ -189,7 +189,7 @@ static void __init centaur_create_optima
+ wrmsr(MSR_IDT_MCR0+i, 0, 0);
+ }
+
+-static void __init winchip2_create_optimal_mcr(void)
++static void __cpuinit winchip2_create_optimal_mcr(void)
+ {
+ u32 lo, hi;
+ int i;
+@@ -227,7 +227,7 @@ static void __init winchip2_create_optim
+ * Handle the MCR key on the Winchip 2.
+ */
+
+-static void __init winchip2_unprotect_mcr(void)
++static void __cpuinit winchip2_unprotect_mcr(void)
+ {
+ u32 lo, hi;
+ u32 key;
+@@ -239,7 +239,7 @@ static void __init winchip2_unprotect_mc
+ wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+ }
+
+-static void __init winchip2_protect_mcr(void)
++static void __cpuinit winchip2_protect_mcr(void)
+ {
+ u32 lo, hi;
+
+@@ -257,7 +257,7 @@ static void __init winchip2_protect_mcr(
+ #define RNG_ENABLED (1 << 3)
+ #define RNG_ENABLE (1 << 6) /* MSR_VIA_RNG */
+
+-static void __init init_c3(struct cpuinfo_x86 *c)
++static void __cpuinit init_c3(struct cpuinfo_x86 *c)
+ {
+ u32 lo, hi;
+
+@@ -303,7 +303,7 @@ static void __init init_c3(struct cpuinf
+ display_cacheinfo(c);
+ }
+
+-static void __init init_centaur(struct cpuinfo_x86 *c)
++static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
+ {
+ enum {
+ ECX8=1<<1,
+@@ -442,7 +442,7 @@ static void __init init_centaur(struct c
+ }
+ }
+
+-static unsigned int centaur_size_cache(struct cpuinfo_x86 * c, unsigned int size)
++static unsigned int __cpuinit centaur_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+ {
+ /* VIA C3 CPUs (670-68F) need further shifting. */
+ if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8)))
+@@ -457,7 +457,7 @@ static unsigned int centaur_size_cache(s
+ return size;
+ }
+
+-static struct cpu_dev centaur_cpu_dev __initdata = {
++static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
+ .c_vendor = "Centaur",
+ .c_ident = { "CentaurHauls" },
+ .c_init = init_centaur,
+diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
+index 70c87de..d9f3e3c 100644
+--- a/arch/i386/kernel/cpu/common.c
++++ b/arch/i386/kernel/cpu/common.c
+@@ -36,7 +36,7 @@ struct cpu_dev * cpu_devs[X86_VENDOR_NUM
+
+ extern int disable_pse;
+
+-static void default_init(struct cpuinfo_x86 * c)
++static void __cpuinit default_init(struct cpuinfo_x86 * c)
+ {
+ /* Not much we can do here... */
+ /* Check if at least it has cpuid */
+@@ -49,7 +49,7 @@ static void default_init(struct cpuinfo_
+ }
+ }
+
+-static struct cpu_dev default_cpu = {
++static struct cpu_dev __cpuinitdata default_cpu = {
+ .c_init = default_init,
+ .c_vendor = "Unknown",
+ };
+@@ -184,7 +184,16 @@ static void __cpuinit get_cpu_vendor(str
+
+ static int __init x86_fxsr_setup(char * s)
+ {
++ /* Tell all the other CPU's to not use it... */
+ disable_x86_fxsr = 1;
++
++ /*
++ * ... and clear the bits early in the boot_cpu_data
++ * so that the bootup process doesn't try to do this
++ * either.
++ */
++ clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability);
++ clear_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability);
+ return 1;
+ }
+ __setup("nofxsr", x86_fxsr_setup);
+@@ -265,7 +274,7 @@ static void __init early_cpu_detect(void
+ }
+ }
+
+-void __cpuinit generic_identify(struct cpuinfo_x86 * c)
++static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
+ {
+ u32 tfms, xlvl;
+ int ebx;
+@@ -660,8 +669,7 @@ old_gdt:
+ */
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+- if (current->mm)
+- BUG();
++ BUG_ON(current->mm);
+ enter_lazy_tlb(&init_mm, current);
+
+ load_esp0(t, thread);
+@@ -675,7 +683,7 @@ old_gdt:
+ #endif
+
+ /* Clear %fs and %gs. */
+- asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
++ asm volatile ("movl %0, %%fs; movl %0, %%gs" : : "r" (0));
+
+ /* Clear all 6 debug registers: */
+ set_debugreg(0, 0);
+diff --git a/arch/i386/kernel/cpu/cpu.h b/arch/i386/kernel/cpu/cpu.h
+index 5a1d4f1..2f6432c 100644
+--- a/arch/i386/kernel/cpu/cpu.h
++++ b/arch/i386/kernel/cpu/cpu.h
+@@ -24,7 +24,5 @@ extern struct cpu_dev * cpu_devs [X86_VE
+ extern int get_model_name(struct cpuinfo_x86 *c);
+ extern void display_cacheinfo(struct cpuinfo_x86 *c);
+
+-extern void generic_identify(struct cpuinfo_x86 * c);
+-
+ extern void early_intel_workaround(struct cpuinfo_x86 *c);
+
+diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+index e6ea00e..57c880b 100644
+--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
++++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+@@ -32,6 +32,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/compiler.h>
+ #include <linux/sched.h> /* current */
++#include <linux/dmi.h>
+ #include <asm/io.h>
+ #include <asm/delay.h>
+ #include <asm/uaccess.h>
+@@ -387,6 +388,33 @@ static int acpi_cpufreq_early_init_acpi(
+ return acpi_processor_preregister_performance(acpi_perf_data);
+ }
+
++/*
++ * Some BIOSes do SW_ANY coordination internally, either set it up in hw
++ * or do it in BIOS firmware and won't inform about it to OS. If not
++ * detected, this has a side effect of making CPU run at a different speed
++ * than OS intended it to run at. Detect it and handle it cleanly.
++ */
++static int bios_with_sw_any_bug;
++
++static int sw_any_bug_found(struct dmi_system_id *d)
++{
++ bios_with_sw_any_bug = 1;
++ return 0;
++}
++
++static struct dmi_system_id sw_any_bug_dmi_table[] = {
++ {
++ .callback = sw_any_bug_found,
++ .ident = "Supermicro Server X6DLP",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
++ DMI_MATCH(DMI_BIOS_VERSION, "080010"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
++ },
++ },
++ { }
++};
++
+ static int
+ acpi_cpufreq_cpu_init (
+ struct cpufreq_policy *policy)
+@@ -422,8 +450,17 @@ acpi_cpufreq_cpu_init (
+ * coordination is required.
+ */
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
+- policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
++ policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
+ policy->cpus = perf->shared_cpu_map;
++ }
++
++#ifdef CONFIG_SMP
++ dmi_check_system(sw_any_bug_dmi_table);
++ if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
++ policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
++ policy->cpus = cpu_core_map[cpu];
++ }
++#endif
+
+ if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
+ acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
+@@ -560,7 +597,6 @@ static struct cpufreq_driver acpi_cpufre
+ .name = "acpi-cpufreq",
+ .owner = THIS_MODULE,
+ .attr = acpi_cpufreq_attr,
+- .flags = CPUFREQ_STICKY,
+ };
+
+
+@@ -571,7 +607,7 @@ acpi_cpufreq_init (void)
+
+ acpi_cpufreq_early_init_acpi();
+
+- return cpufreq_register_driver(&acpi_cpufreq_driver);
++ return cpufreq_register_driver(&acpi_cpufreq_driver);
+ }
+
+
+diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
+index 4f2c3ae..7233abe 100644
+--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
++++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
+@@ -27,6 +27,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/init.h>
+ #include <linux/cpufreq.h>
++#include <linux/pci.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
+
+@@ -52,18 +53,26 @@
+ #define CPU_NEHEMIAH 5
+
+ static int cpu_model;
+-static unsigned int numscales=16, numvscales;
++static unsigned int numscales=16;
+ static unsigned int fsb;
+-static int minvid, maxvid;
++
++static struct mV_pos *vrm_mV_table;
++static unsigned char *mV_vrm_table;
++struct f_msr {
++ unsigned char vrm;
++};
++static struct f_msr f_msr_table[32];
++
++static unsigned int highest_speed, lowest_speed; /* kHz */
+ static unsigned int minmult, maxmult;
+ static int can_scale_voltage;
+-static int vrmrev;
+ static struct acpi_processor *pr = NULL;
+ static struct acpi_processor_cx *cx = NULL;
++static int port22_en;
+
+ /* Module parameters */
+-static int dont_scale_voltage;
+-
++static int scale_voltage;
++static int ignore_latency;
+
+ #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
+
+@@ -71,7 +80,6 @@ static int dont_scale_voltage;
+ /* Clock ratios multiplied by 10 */
+ static int clock_ratio[32];
+ static int eblcr_table[32];
+-static int voltage_table[32];
+ static unsigned int highest_speed, lowest_speed; /* kHz */
+ static int longhaul_version;
+ static struct cpufreq_frequency_table *longhaul_table;
+@@ -124,10 +132,9 @@ static int longhaul_get_cpu_mult(void)
+
+ /* For processor with BCR2 MSR */
+
+-static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)
++static void do_longhaul1(unsigned int clock_ratio_index)
+ {
+ union msr_bcr2 bcr2;
+- u32 t;
+
+ rdmsrl(MSR_VIA_BCR2, bcr2.val);
+ /* Enable software clock multiplier */
+@@ -136,13 +143,11 @@ static void do_longhaul1(int cx_address,
+
+ /* Sync to timer tick */
+ safe_halt();
+- ACPI_FLUSH_CPU_CACHE();
+ /* Change frequency on next halt or sleep */
+ wrmsrl(MSR_VIA_BCR2, bcr2.val);
+- /* Invoke C3 */
+- inb(cx_address);
+- /* Dummy op - must do something useless after P_LVL3 read */
+- t = inl(acpi_fadt.xpm_tmr_blk.address);
++ /* Invoke transition */
++ ACPI_FLUSH_CPU_CACHE();
++ halt();
+
+ /* Disable software clock multiplier */
+ local_irq_disable();
+@@ -164,15 +169,26 @@ static void do_powersaver(int cx_address
+ longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
+ longhaul.bits.EnableSoftBusRatio = 1;
+
++ if (can_scale_voltage) {
++ longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
++ longhaul.bits.EnableSoftVID = 1;
++ }
++
+ /* Sync to timer tick */
+ safe_halt();
+- ACPI_FLUSH_CPU_CACHE();
+ /* Change frequency on next halt or sleep */
+ wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
+- /* Invoke C3 */
+- inb(cx_address);
+- /* Dummy op - must do something useless after P_LVL3 read */
+- t = inl(acpi_fadt.xpm_tmr_blk.address);
++ if (port22_en) {
++ ACPI_FLUSH_CPU_CACHE();
++ /* Invoke C1 */
++ halt();
++ } else {
++ ACPI_FLUSH_CPU_CACHE();
++ /* Invoke C3 */
++ inb(cx_address);
++ /* Dummy op - must do something useless after P_LVL3 read */
++ t = inl(acpi_fadt.xpm_tmr_blk.address);
++ }
+
+ /* Disable bus ratio bit */
+ local_irq_disable();
+@@ -227,10 +243,13 @@ static void longhaul_setstate(unsigned i
+ outb(0xFF,0xA1); /* Overkill */
+ outb(0xFE,0x21); /* TMR0 only */
+
+- /* Disable bus master arbitration */
+- if (pr->flags.bm_check) {
++ if (pr->flags.bm_control) {
++ /* Disable bus master arbitration */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
+ ACPI_MTX_DO_NOT_LOCK);
++ } else if (port22_en) {
++ /* Disable AGP and PCI arbiters */
++ outb(3, 0x22);
+ }
+
+ switch (longhaul_version) {
+@@ -244,7 +263,7 @@ static void longhaul_setstate(unsigned i
+ */
+ case TYPE_LONGHAUL_V1:
+ case TYPE_LONGHAUL_V2:
+- do_longhaul1(cx->address, clock_ratio_index);
++ do_longhaul1(clock_ratio_index);
+ break;
+
+ /*
+@@ -259,14 +278,20 @@ static void longhaul_setstate(unsigned i
+ * to work in practice.
+ */
+ case TYPE_POWERSAVER:
++ /* Don't allow wakeup */
++ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
++ ACPI_MTX_DO_NOT_LOCK);
+ do_powersaver(cx->address, clock_ratio_index);
+ break;
+ }
+
+- /* Enable bus master arbitration */
+- if (pr->flags.bm_check) {
++ if (pr->flags.bm_control) {
++ /* Enable bus master arbitration */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
+ ACPI_MTX_DO_NOT_LOCK);
++ } else if (port22_en) {
++ /* Enable arbiters */
++ outb(0, 0x22);
+ }
+
+ outb(pic2_mask,0xA1); /* restore mask */
+@@ -446,53 +471,57 @@ static int __init longhaul_get_ranges(vo
+ static void __init longhaul_setup_voltagescaling(void)
+ {
+ union msr_longhaul longhaul;
++ struct mV_pos minvid, maxvid;
++ unsigned int j, speed, pos, kHz_step, numvscales;
+
+- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+-
+- if (!(longhaul.bits.RevisionID & 1))
++ rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
++ if (!(longhaul.bits.RevisionID & 1)) {
++ printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");
+ return;
++ }
+
+- minvid = longhaul.bits.MinimumVID;
+- maxvid = longhaul.bits.MaximumVID;
+- vrmrev = longhaul.bits.VRMRev;
++ if (!longhaul.bits.VRMRev) {
++ printk (KERN_INFO PFX "VRM 8.5\n");
++ vrm_mV_table = &vrm85_mV[0];
++ mV_vrm_table = &mV_vrm85[0];
++ } else {
++ printk (KERN_INFO PFX "Mobile VRM\n");
++ vrm_mV_table = &mobilevrm_mV[0];
++ mV_vrm_table = &mV_mobilevrm[0];
++ }
++
++ minvid = vrm_mV_table[longhaul.bits.MinimumVID];
++ maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
++ numvscales = maxvid.pos - minvid.pos + 1;
++ kHz_step = (highest_speed - lowest_speed) / numvscales;
+
+- if (minvid == 0 || maxvid == 0) {
++ if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
+ printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
+ "Voltage scaling disabled.\n",
+- minvid/1000, minvid%1000, maxvid/1000, maxvid%1000);
++ minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
+ return;
+ }
+
+- if (minvid == maxvid) {
++ if (minvid.mV == maxvid.mV) {
+ printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
+ "both %d.%03d. Voltage scaling disabled\n",
+- maxvid/1000, maxvid%1000);
++ maxvid.mV/1000, maxvid.mV%1000);
+ return;
+ }
+
+- if (vrmrev==0) {
+- dprintk ("VRM 8.5\n");
+- memcpy (voltage_table, vrm85scales, sizeof(voltage_table));
+- numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;
+- } else {
+- dprintk ("Mobile VRM\n");
+- memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table));
+- numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5;
++ printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n",
++ maxvid.mV/1000, maxvid.mV%1000,
++ minvid.mV/1000, minvid.mV%1000,
++ numvscales);
++
++ j = 0;
++ while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
++ speed = longhaul_table[j].frequency;
++ pos = (speed - lowest_speed) / kHz_step + minvid.pos;
++ f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
++ j++;
+ }
+
+- /* Current voltage isn't readable at first, so we need to
+- set it to a known value. The spec says to use maxvid */
+- longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */
+- longhaul.bits.EnableSoftVID = 1;
+- longhaul.bits.SoftVID = maxvid;
+- wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+-
+- minvid = voltage_table[minvid];
+- maxvid = voltage_table[maxvid];
+-
+- dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
+- maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);
+-
+ can_scale_voltage = 1;
+ }
+
+@@ -540,21 +569,40 @@ static acpi_status longhaul_walk_callbac
+ return 1;
+ }
+
++/* VIA don't support PM2 reg, but have something similar */
++static int enable_arbiter_disable(void)
++{
++ struct pci_dev *dev;
++ int reg;
++ u8 pci_cmd;
++
++ /* Find PLE133 host bridge */
++ reg = 0x78;
++ dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
++ /* Find CLE266 host bridge */
++ if (dev == NULL) {
++ reg = 0x76;
++ dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL);
++ }
++ if (dev != NULL) {
++ /* Enable access to port 0x22 */
++ pci_read_config_byte(dev, reg, &pci_cmd);
++ if ( !(pci_cmd & 1<<7) ) {
++ pci_cmd |= 1<<7;
++ pci_write_config_byte(dev, reg, pci_cmd);
++ }
++ return 1;
++ }
++ return 0;
++}
++
+ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
+ {
+ struct cpuinfo_x86 *c = cpu_data;
+ char *cpuname=NULL;
+ int ret;
+
+- /* Check ACPI support for C3 state */
+- acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+- &longhaul_walk_callback, NULL, (void *)&pr);
+- if (pr == NULL) goto err_acpi;
+-
+- cx = &pr->power.states[ACPI_STATE_C3];
+- if (cx->address == 0 || cx->latency > 1000) goto err_acpi;
+-
+- /* Now check what we have on this motherboard */
++ /* Check what we have on this motherboard */
+ switch (c->x86_model) {
+ case 6:
+ cpu_model = CPU_SAMUEL;
+@@ -636,12 +684,41 @@ static int __init longhaul_cpu_init(stru
+ break;
+ };
+
++ /* Find ACPI data for processor */
++ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
++ &longhaul_walk_callback, NULL, (void *)&pr);
++ if (pr == NULL)
++ goto err_acpi;
++
++ if (longhaul_version == TYPE_POWERSAVER) {
++ /* Check ACPI support for C3 state */
++ cx = &pr->power.states[ACPI_STATE_C3];
++ if (cx->address > 0 &&
++ (cx->latency <= 1000 || ignore_latency != 0) ) {
++ goto print_support_type;
++ }
++ }
++ /* Check ACPI support for bus master arbiter disable */
++ if (!pr->flags.bm_control) {
++ if (enable_arbiter_disable()) {
++ port22_en = 1;
++ } else {
++ goto err_acpi;
++ }
++ }
++print_support_type:
++ if (!port22_en) {
++ printk (KERN_INFO PFX "Using ACPI support.\n");
++ } else {
++ printk (KERN_INFO PFX "Using northbridge support.\n");
++ }
++
+ ret = longhaul_get_ranges();
+ if (ret != 0)
+ return ret;
+
+ if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&
+- (dont_scale_voltage==0))
++ (scale_voltage != 0))
+ longhaul_setup_voltagescaling();
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+@@ -657,7 +734,7 @@ static int __init longhaul_cpu_init(stru
+ return 0;
+
+ err_acpi:
+- printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n");
++ printk(KERN_ERR PFX "No ACPI support. No VT8601 or VT8623 northbridge. Aborting.\n");
+ return -ENODEV;
+ }
+
+@@ -729,8 +806,10 @@ static void __exit longhaul_exit(void)
+ kfree(longhaul_table);
+ }
+
+-module_param (dont_scale_voltage, int, 0644);
+-MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor");
++module_param (scale_voltage, int, 0644);
++MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
++module_param(ignore_latency, int, 0644);
++MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test");
+
+ MODULE_AUTHOR ("Dave Jones <davej at codemonkey.org.uk>");
+ MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
+@@ -738,4 +817,3 @@ MODULE_LICENSE ("GPL");
+
+ late_initcall(longhaul_init);
+ module_exit(longhaul_exit);
+-
+diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/i386/kernel/cpu/cpufreq/longhaul.h
+index d3a95d7..bc4682a 100644
+--- a/arch/i386/kernel/cpu/cpufreq/longhaul.h
++++ b/arch/i386/kernel/cpu/cpufreq/longhaul.h
+@@ -450,17 +450,45 @@ static int __initdata nehemiah_c_eblcr[3
+ * Voltage scales. Div/Mod by 1000 to get actual voltage.
+ * Which scale to use depends on the VRM type in use.
+ */
+-static int __initdata vrm85scales[32] = {
+- 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700,
+- 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300,
+- 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725,
+- 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325,
++
++struct mV_pos {
++ unsigned short mV;
++ unsigned short pos;
++};
++
++static struct mV_pos __initdata vrm85_mV[32] = {
++ {1250, 8}, {1200, 6}, {1150, 4}, {1100, 2},
++ {1050, 0}, {1800, 30}, {1750, 28}, {1700, 26},
++ {1650, 24}, {1600, 22}, {1550, 20}, {1500, 18},
++ {1450, 16}, {1400, 14}, {1350, 12}, {1300, 10},
++ {1275, 9}, {1225, 7}, {1175, 5}, {1125, 3},
++ {1075, 1}, {1825, 31}, {1775, 29}, {1725, 27},
++ {1675, 25}, {1625, 23}, {1575, 21}, {1525, 19},
++ {1475, 17}, {1425, 15}, {1375, 13}, {1325, 11}
++};
++
++static unsigned char __initdata mV_vrm85[32] = {
++ 0x04, 0x14, 0x03, 0x13, 0x02, 0x12, 0x01, 0x11,
++ 0x00, 0x10, 0x0f, 0x1f, 0x0e, 0x1e, 0x0d, 0x1d,
++ 0x0c, 0x1c, 0x0b, 0x1b, 0x0a, 0x1a, 0x09, 0x19,
++ 0x08, 0x18, 0x07, 0x17, 0x06, 0x16, 0x05, 0x15
++};
++
++static struct mV_pos __initdata mobilevrm_mV[32] = {
++ {1750, 31}, {1700, 30}, {1650, 29}, {1600, 28},
++ {1550, 27}, {1500, 26}, {1450, 25}, {1400, 24},
++ {1350, 23}, {1300, 22}, {1250, 21}, {1200, 20},
++ {1150, 19}, {1100, 18}, {1050, 17}, {1000, 16},
++ {975, 15}, {950, 14}, {925, 13}, {900, 12},
++ {875, 11}, {850, 10}, {825, 9}, {800, 8},
++ {775, 7}, {750, 6}, {725, 5}, {700, 4},
++ {675, 3}, {650, 2}, {625, 1}, {600, 0}
+ };
+
+-static int __initdata mobilevrmscales[32] = {
+- 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
+- 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1,
+- 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
+- 1075, 1050, 1025, 1000, 975, 950, 925, -1,
++static unsigned char __initdata mV_mobilevrm[32] = {
++ 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
++ 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
++ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
++ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
+ };
+
+diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+index b77f135..e8993ba 100644
+--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
++++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+@@ -23,6 +23,7 @@
+
+ #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
+ #include <linux/acpi.h>
++#include <linux/dmi.h>
+ #include <acpi/processor.h>
+ #endif
+
+@@ -377,6 +378,35 @@ static int centrino_cpu_early_init_acpi(
+ return 0;
+ }
+
++
++/*
++ * Some BIOSes do SW_ANY coordination internally, either set it up in hw
++ * or do it in BIOS firmware and won't inform about it to OS. If not
++ * detected, this has a side effect of making CPU run at a different speed
++ * than OS intended it to run at. Detect it and handle it cleanly.
++ */
++static int bios_with_sw_any_bug;
++static int sw_any_bug_found(struct dmi_system_id *d)
++{
++ bios_with_sw_any_bug = 1;
++ return 0;
++}
++
++
++static struct dmi_system_id sw_any_bug_dmi_table[] = {
++ {
++ .callback = sw_any_bug_found,
++ .ident = "Supermicro Server X6DLP",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
++ DMI_MATCH(DMI_BIOS_VERSION, "080010"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
++ },
++ },
++ { }
++};
++
++
+ /*
+ * centrino_cpu_init_acpi - register with ACPI P-States library
+ *
+@@ -398,14 +428,24 @@ static int centrino_cpu_init_acpi(struct
+ dprintk(PFX "obtaining ACPI data failed\n");
+ return -EIO;
+ }
++
+ policy->shared_type = p->shared_type;
+ /*
+ * Will let policy->cpus know about dependency only when software
+ * coordination is required.
+ */
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
+- policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
++ policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
+ policy->cpus = p->shared_cpu_map;
++ }
++
++#ifdef CONFIG_SMP
++ dmi_check_system(sw_any_bug_dmi_table);
++ if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
++ policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
++ policy->cpus = cpu_core_map[cpu];
++ }
++#endif
+
+ /* verify the acpi_data */
+ if (p->state_count <= 1) {
+diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
+index f03b7f9..c0c3b59 100644
+--- a/arch/i386/kernel/cpu/cyrix.c
++++ b/arch/i386/kernel/cpu/cyrix.c
+@@ -12,7 +12,7 @@
+ /*
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ */
+-static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
++static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+ {
+ unsigned char ccr2, ccr3;
+ unsigned long flags;
+@@ -52,25 +52,25 @@ static void __init do_cyrix_devid(unsign
+ * Actually since bugs.h doesn't even reference this perhaps someone should
+ * fix the documentation ???
+ */
+-static unsigned char Cx86_dir0_msb __initdata = 0;
++static unsigned char Cx86_dir0_msb __cpuinitdata = 0;
+
+-static char Cx86_model[][9] __initdata = {
++static char Cx86_model[][9] __cpuinitdata = {
+ "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
+ "M II ", "Unknown"
+ };
+-static char Cx486_name[][5] __initdata = {
++static char Cx486_name[][5] __cpuinitdata = {
+ "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
+ "SRx2", "DRx2"
+ };
+-static char Cx486S_name[][4] __initdata = {
++static char Cx486S_name[][4] __cpuinitdata = {
+ "S", "S2", "Se", "S2e"
+ };
+-static char Cx486D_name[][4] __initdata = {
++static char Cx486D_name[][4] __cpuinitdata = {
+ "DX", "DX2", "?", "?", "?", "DX4"
+ };
+-static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
+-static char cyrix_model_mult1[] __initdata = "12??43";
+-static char cyrix_model_mult2[] __initdata = "12233445";
++static char Cx86_cb[] __cpuinitdata = "?.5x Core/Bus Clock";
++static char cyrix_model_mult1[] __cpuinitdata = "12??43";
++static char cyrix_model_mult2[] __cpuinitdata = "12233445";
+
+ /*
+ * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
+@@ -82,7 +82,7 @@ static char cyrix_model_mult2[] __initda
+
+ extern void calibrate_delay(void) __init;
+
+-static void __init check_cx686_slop(struct cpuinfo_x86 *c)
++static void __cpuinit check_cx686_slop(struct cpuinfo_x86 *c)
+ {
+ unsigned long flags;
+
+@@ -107,7 +107,7 @@ static void __init check_cx686_slop(stru
+ }
+
+
+-static void __init set_cx86_reorder(void)
++static void __cpuinit set_cx86_reorder(void)
+ {
+ u8 ccr3;
+
+@@ -122,7 +122,7 @@ static void __init set_cx86_reorder(void
+ setCx86(CX86_CCR3, ccr3);
+ }
+
+-static void __init set_cx86_memwb(void)
++static void __cpuinit set_cx86_memwb(void)
+ {
+ u32 cr0;
+
+@@ -137,7 +137,7 @@ static void __init set_cx86_memwb(void)
+ setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14 );
+ }
+
+-static void __init set_cx86_inc(void)
++static void __cpuinit set_cx86_inc(void)
+ {
+ unsigned char ccr3;
+
+@@ -158,7 +158,7 @@ static void __init set_cx86_inc(void)
+ * Configure later MediaGX and/or Geode processor.
+ */
+
+-static void __init geode_configure(void)
++static void __cpuinit geode_configure(void)
+ {
+ unsigned long flags;
+ u8 ccr3, ccr4;
+@@ -184,14 +184,14 @@ static void __init geode_configure(void)
+
+
+ #ifdef CONFIG_PCI
+-static struct pci_device_id __initdata cyrix_55x0[] = {
++static struct pci_device_id __cpuinitdata cyrix_55x0[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520) },
+ { },
+ };
+ #endif
+
+-static void __init init_cyrix(struct cpuinfo_x86 *c)
++static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
+ {
+ unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
+ char *buf = c->x86_model_id;
+@@ -346,7 +346,7 @@ static void __init init_cyrix(struct cpu
+ /*
+ * Handle National Semiconductor branded processors
+ */
+-static void __init init_nsc(struct cpuinfo_x86 *c)
++static void __cpuinit init_nsc(struct cpuinfo_x86 *c)
+ {
+ /* There may be GX1 processors in the wild that are branded
+ * NSC and not Cyrix.
+@@ -394,7 +394,7 @@ static inline int test_cyrix_52div(void)
+ return (unsigned char) (test >> 8) == 0x02;
+ }
+
+-static void cyrix_identify(struct cpuinfo_x86 * c)
++static void __cpuinit cyrix_identify(struct cpuinfo_x86 * c)
+ {
+ /* Detect Cyrix with disabled CPUID */
+ if ( c->x86 == 4 && test_cyrix_52div() ) {
+@@ -427,10 +427,9 @@ static void cyrix_identify(struct cpuinf
+ local_irq_restore(flags);
+ }
+ }
+- generic_identify(c);
+ }
+
+-static struct cpu_dev cyrix_cpu_dev __initdata = {
++static struct cpu_dev cyrix_cpu_dev __cpuinitdata = {
+ .c_vendor = "Cyrix",
+ .c_ident = { "CyrixInstead" },
+ .c_init = init_cyrix,
+@@ -453,11 +452,10 @@ static int __init cyrix_exit_cpu(void)
+
+ late_initcall(cyrix_exit_cpu);
+
+-static struct cpu_dev nsc_cpu_dev __initdata = {
++static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
+ .c_vendor = "NSC",
+ .c_ident = { "Geode by NSC" },
+ .c_init = init_nsc,
+- .c_identify = generic_identify,
+ };
+
+ int __init nsc_init_cpu(void)
+diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
+index 5a2e270..94a95aa 100644
+--- a/arch/i386/kernel/cpu/intel.c
++++ b/arch/i386/kernel/cpu/intel.c
+@@ -198,7 +198,7 @@ static void __cpuinit init_intel(struct
+ }
+
+
+-static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
++static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+ {
+ /* Intel PIII Tualatin. This comes in two flavours.
+ * One has 256kb of cache, the other 512. We have no way
+@@ -263,7 +263,6 @@ static struct cpu_dev intel_cpu_dev __cp
+ },
+ },
+ .c_init = init_intel,
+- .c_identify = generic_identify,
+ .c_size_cache = intel_size_cache,
+ };
+
+diff --git a/arch/i386/kernel/cpu/mcheck/Makefile b/arch/i386/kernel/cpu/mcheck/Makefile
+index 30808f3..f1ebe1c 100644
+--- a/arch/i386/kernel/cpu/mcheck/Makefile
++++ b/arch/i386/kernel/cpu/mcheck/Makefile
+@@ -1,2 +1,2 @@
+-obj-y = mce.o k7.o p4.o p5.o p6.o winchip.o
++obj-y = mce.o k7.o p4.o p5.o p6.o winchip.o therm_throt.o
+ obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o
+diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c
+index b95f1b3..504434a 100644
+--- a/arch/i386/kernel/cpu/mcheck/p4.c
++++ b/arch/i386/kernel/cpu/mcheck/p4.c
+@@ -13,6 +13,8 @@
+ #include <asm/msr.h>
+ #include <asm/apic.h>
+
++#include <asm/therm_throt.h>
++
+ #include "mce.h"
+
+ /* as supported by the P4/Xeon family */
+@@ -44,25 +46,12 @@ static void unexpected_thermal_interrupt
+ /* P4/Xeon Thermal transition interrupt handler */
+ static void intel_thermal_interrupt(struct pt_regs *regs)
+ {
+- u32 l, h;
+- unsigned int cpu = smp_processor_id();
+- static unsigned long next[NR_CPUS];
++ __u64 msr_val;
+
+ ack_APIC_irq();
+
+- if (time_after(next[cpu], jiffies))
+- return;
+-
+- next[cpu] = jiffies + HZ*5;
+- rdmsr(MSR_IA32_THERM_STATUS, l, h);
+- if (l & 0x1) {
+- printk(KERN_EMERG "CPU%d: Temperature above threshold\n", cpu);
+- printk(KERN_EMERG "CPU%d: Running in modulated clock mode\n",
+- cpu);
+- add_taint(TAINT_MACHINE_CHECK);
+- } else {
+- printk(KERN_INFO "CPU%d: Temperature/speed normal\n", cpu);
+- }
++ rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
++ therm_throt_process(msr_val & 0x1);
+ }
+
+ /* Thermal interrupt handler for this CPU setup */
+@@ -122,10 +111,13 @@ static void intel_init_thermal(struct cp
+
+ rdmsr (MSR_IA32_MISC_ENABLE, l, h);
+ wrmsr (MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+-
++
+ l = apic_read (APIC_LVTTHMR);
+ apic_write_around (APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+ printk (KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu);
++
++ /* enable thermal throttle processing */
++ atomic_set(&therm_throt_en, 1);
+ return;
+ }
+ #endif /* CONFIG_X86_MCE_P4THERMAL */
+diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c
+new file mode 100644
+index 0000000..2d8703b
+--- /dev/null
++++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c
+@@ -0,0 +1,183 @@
++/*
++ * linux/arch/i386/kerne/cpu/mcheck/therm_throt.c
++ *
++ * Thermal throttle event support code (such as syslog messaging and rate
++ * limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c).
++ * This allows consistent reporting of CPU thermal throttle events.
++ *
++ * Maintains a counter in /sys that keeps track of the number of thermal
++ * events, such that the user knows how bad the thermal problem might be
++ * (since the logging to syslog and mcelog is rate limited).
++ *
++ * Author: Dmitriy Zavin (dmitriyz at google.com)
++ *
++ * Credits: Adapted from Zwane Mwaikambo's original code in mce_intel.c.
++ * Inspired by Ross Biro's and Al Borchers' counter code.
++ */
++
++#include <linux/percpu.h>
++#include <linux/sysdev.h>
++#include <linux/cpu.h>
++#include <asm/cpu.h>
++#include <linux/notifier.h>
++#include <asm/therm_throt.h>
++
++/* How long to wait between reporting thermal events */
++#define CHECK_INTERVAL (300 * HZ)
++
++static DEFINE_PER_CPU(__u64, next_check) = INITIAL_JIFFIES;
++static DEFINE_PER_CPU(unsigned long, thermal_throttle_count);
++atomic_t therm_throt_en = ATOMIC_INIT(0);
++
++#ifdef CONFIG_SYSFS
++#define define_therm_throt_sysdev_one_ro(_name) \
++ static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
++
++#define define_therm_throt_sysdev_show_func(name) \
++static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev, \
++ char *buf) \
++{ \
++ unsigned int cpu = dev->id; \
++ ssize_t ret; \
++ \
++ preempt_disable(); /* CPU hotplug */ \
++ if (cpu_online(cpu)) \
++ ret = sprintf(buf, "%lu\n", \
++ per_cpu(thermal_throttle_##name, cpu)); \
++ else \
++ ret = 0; \
++ preempt_enable(); \
++ \
++ return ret; \
++}
++
++define_therm_throt_sysdev_show_func(count);
++define_therm_throt_sysdev_one_ro(count);
++
++static struct attribute *thermal_throttle_attrs[] = {
++ &attr_count.attr,
++ NULL
++};
++
++static struct attribute_group thermal_throttle_attr_group = {
++ .attrs = thermal_throttle_attrs,
++ .name = "thermal_throttle"
++};
++#endif /* CONFIG_SYSFS */
++
++/***
++ * therm_throt_process - Process thermal throttling event from interrupt
++ * @curr: Whether the condition is current or not (boolean), since the
++ * thermal interrupt normally gets called both when the thermal
++ * event begins and once the event has ended.
++ *
++ * This function is called by the thermal interrupt after the
++ * IRQ has been acknowledged.
++ *
++ * It will take care of rate limiting and printing messages to the syslog.
++ *
++ * Returns: 0 : Event should NOT be further logged, i.e. still in
++ * "timeout" from previous log message.
++ * 1 : Event should be logged further, and a message has been
++ * printed to the syslog.
++ */
++int therm_throt_process(int curr)
++{
++ unsigned int cpu = smp_processor_id();
++ __u64 tmp_jiffs = get_jiffies_64();
++
++ if (curr)
++ __get_cpu_var(thermal_throttle_count)++;
++
++ if (time_before64(tmp_jiffs, __get_cpu_var(next_check)))
++ return 0;
++
++ __get_cpu_var(next_check) = tmp_jiffs + CHECK_INTERVAL;
++
++ /* if we just entered the thermal event */
++ if (curr) {
++ printk(KERN_CRIT "CPU%d: Temperature above threshold, "
++ "cpu clock throttled (total events = %lu)\n", cpu,
++ __get_cpu_var(thermal_throttle_count));
++
++ add_taint(TAINT_MACHINE_CHECK);
++ } else {
++ printk(KERN_CRIT "CPU%d: Temperature/speed normal\n", cpu);
++ }
++
++ return 1;
++}
++
++#ifdef CONFIG_SYSFS
++/* Add/Remove thermal_throttle interface for CPU device */
++static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
++{
++ return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
++{
++ return sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
++}
++
++/* Mutex protecting device creation against CPU hotplug */
++static DEFINE_MUTEX(therm_cpu_lock);
++
++/* Get notified when a cpu comes on/off. Be hotplug friendly. */
++static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
++ unsigned long action,
++ void *hcpu)
++{
++ unsigned int cpu = (unsigned long)hcpu;
++ struct sys_device *sys_dev;
++ int err;
++
++ sys_dev = get_cpu_sysdev(cpu);
++ mutex_lock(&therm_cpu_lock);
++ switch (action) {
++ case CPU_ONLINE:
++ err = thermal_throttle_add_dev(sys_dev);
++ WARN_ON(err);
++ break;
++ case CPU_DEAD:
++ thermal_throttle_remove_dev(sys_dev);
++ break;
++ }
++ mutex_unlock(&therm_cpu_lock);
++ return NOTIFY_OK;
++}
++
++static struct notifier_block thermal_throttle_cpu_notifier =
++{
++ .notifier_call = thermal_throttle_cpu_callback,
++};
++#endif /* CONFIG_HOTPLUG_CPU */
++
++static __init int thermal_throttle_init_device(void)
++{
++ unsigned int cpu = 0;
++ int err;
++
++ if (!atomic_read(&therm_throt_en))
++ return 0;
++
++ register_hotcpu_notifier(&thermal_throttle_cpu_notifier);
++
++#ifdef CONFIG_HOTPLUG_CPU
++ mutex_lock(&therm_cpu_lock);
++#endif
++ /* connect live CPUs to sysfs */
++ for_each_online_cpu(cpu) {
++ err = thermal_throttle_add_dev(get_cpu_sysdev(cpu));
++ WARN_ON(err);
++ }
++#ifdef CONFIG_HOTPLUG_CPU
++ mutex_unlock(&therm_cpu_lock);
++#endif
++
++ return 0;
++}
++
++device_initcall(thermal_throttle_init_device);
++#endif /* CONFIG_SYSFS */
+diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
+index 169ac8e..0b61eed 100644
+--- a/arch/i386/kernel/cpu/mtrr/generic.c
++++ b/arch/i386/kernel/cpu/mtrr/generic.c
+@@ -243,7 +243,7 @@ static DEFINE_SPINLOCK(set_atomicity_loc
+ * has been called.
+ */
+
+-static void prepare_set(void)
++static void prepare_set(void) __acquires(set_atomicity_lock)
+ {
+ unsigned long cr0;
+
+@@ -274,7 +274,7 @@ static void prepare_set(void)
+ mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+ }
+
+-static void post_set(void)
++static void post_set(void) __releases(set_atomicity_lock)
+ {
+ /* Flush TLBs (no need to flush caches - they are disabled) */
+ __flush_tlb();
+diff --git a/arch/i386/kernel/cpu/nexgen.c b/arch/i386/kernel/cpu/nexgen.c
+index ad87fa5..8bf23cc 100644
+--- a/arch/i386/kernel/cpu/nexgen.c
++++ b/arch/i386/kernel/cpu/nexgen.c
+@@ -10,7 +10,7 @@
+ * to have CPUID. (Thanks to Herbert Oppmann)
+ */
+
+-static int __init deep_magic_nexgen_probe(void)
++static int __cpuinit deep_magic_nexgen_probe(void)
+ {
+ int ret;
+
+@@ -27,21 +27,20 @@ static int __init deep_magic_nexgen_prob
+ return ret;
+ }
+
+-static void __init init_nexgen(struct cpuinfo_x86 * c)
++static void __cpuinit init_nexgen(struct cpuinfo_x86 * c)
+ {
+ c->x86_cache_size = 256; /* A few had 1 MB... */
+ }
+
+-static void __init nexgen_identify(struct cpuinfo_x86 * c)
++static void __cpuinit nexgen_identify(struct cpuinfo_x86 * c)
+ {
+ /* Detect NexGen with old hypercode */
+ if ( deep_magic_nexgen_probe() ) {
+ strcpy(c->x86_vendor_id, "NexGenDriven");
+ }
+- generic_identify(c);
+ }
+
+-static struct cpu_dev nexgen_cpu_dev __initdata = {
++static struct cpu_dev nexgen_cpu_dev __cpuinitdata = {
+ .c_vendor = "Nexgen",
+ .c_ident = { "NexGenDriven" },
+ .c_models = {
+diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
+index f54a152..76aac08 100644
+--- a/arch/i386/kernel/cpu/proc.c
++++ b/arch/i386/kernel/cpu/proc.c
+@@ -46,8 +46,8 @@ static int show_cpuinfo(struct seq_file
+
+ /* Intel-defined (#2) */
+ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+- "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL,
+- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
++ NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* VIA/Cyrix/Centaur-defined */
+diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
+index d08d5a2..9317f74 100644
+--- a/arch/i386/kernel/cpu/rise.c
++++ b/arch/i386/kernel/cpu/rise.c
+@@ -5,7 +5,7 @@
+
+ #include "cpu.h"
+
+-static void __init init_rise(struct cpuinfo_x86 *c)
++static void __cpuinit init_rise(struct cpuinfo_x86 *c)
+ {
+ printk("CPU: Rise iDragon");
+ if (c->x86_model > 2)
+@@ -28,7 +28,7 @@ static void __init init_rise(struct cpui
+ set_bit(X86_FEATURE_CX8, c->x86_capability);
+ }
+
+-static struct cpu_dev rise_cpu_dev __initdata = {
++static struct cpu_dev rise_cpu_dev __cpuinitdata = {
+ .c_vendor = "Rise",
+ .c_ident = { "RiseRiseRise" },
+ .c_models = {
+diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
+index 7214c9b..4056fb7 100644
+--- a/arch/i386/kernel/cpu/transmeta.c
++++ b/arch/i386/kernel/cpu/transmeta.c
+@@ -5,7 +5,7 @@
+ #include <asm/msr.h>
+ #include "cpu.h"
+
+-static void __init init_transmeta(struct cpuinfo_x86 *c)
++static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
+ {
+ unsigned int cap_mask, uk, max, dummy;
+ unsigned int cms_rev1, cms_rev2;
+@@ -85,10 +85,9 @@ static void __init init_transmeta(struct
+ #endif
+ }
+
+-static void __init transmeta_identify(struct cpuinfo_x86 * c)
++static void __cpuinit transmeta_identify(struct cpuinfo_x86 * c)
+ {
+ u32 xlvl;
+- generic_identify(c);
+
+ /* Transmeta-defined flags: level 0x80860001 */
+ xlvl = cpuid_eax(0x80860000);
+@@ -98,7 +97,7 @@ static void __init transmeta_identify(st
+ }
+ }
+
+-static struct cpu_dev transmeta_cpu_dev __initdata = {
++static struct cpu_dev transmeta_cpu_dev __cpuinitdata = {
+ .c_vendor = "Transmeta",
+ .c_ident = { "GenuineTMx86", "TransmetaCPU" },
+ .c_init = init_transmeta,
+diff --git a/arch/i386/kernel/cpu/umc.c b/arch/i386/kernel/cpu/umc.c
+index 2cd988f..1bf3f87 100644
+--- a/arch/i386/kernel/cpu/umc.c
++++ b/arch/i386/kernel/cpu/umc.c
+@@ -5,12 +5,8 @@
+
+ /* UMC chips appear to be only either 386 or 486, so no special init takes place.
+ */
+-static void __init init_umc(struct cpuinfo_x86 * c)
+-{
+-
+-}
+
+-static struct cpu_dev umc_cpu_dev __initdata = {
++static struct cpu_dev umc_cpu_dev __cpuinitdata = {
+ .c_vendor = "UMC",
+ .c_ident = { "UMC UMC UMC" },
+ .c_models = {
+@@ -21,7 +17,6 @@ static struct cpu_dev umc_cpu_dev __init
+ }
+ },
+ },
+- .c_init = init_umc,
+ };
+
+ int __init umc_init_cpu(void)
+diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
+index 5b96f03..144b432 100644
+--- a/arch/i386/kernel/crash.c
++++ b/arch/i386/kernel/crash.c
+@@ -22,6 +22,9 @@
+ #include <asm/nmi.h>
+ #include <asm/hw_irq.h>
+ #include <asm/apic.h>
++#include <asm/kdebug.h>
++#include <asm/smp.h>
++
+ #include <mach_ipi.h>
+
+
+@@ -86,23 +89,32 @@ static void crash_save_self(struct pt_re
+ {
+ int cpu;
+
+- cpu = smp_processor_id();
++ cpu = safe_smp_processor_id();
+ crash_save_this_cpu(regs, cpu);
+ }
+
+ #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
+ static atomic_t waiting_for_crash_ipi;
+
+-static int crash_nmi_callback(struct pt_regs *regs, int cpu)
++static int crash_nmi_callback(struct notifier_block *self,
++ unsigned long val, void *data)
+ {
++ struct pt_regs *regs;
+ struct pt_regs fixed_regs;
++ int cpu;
++
++ if (val != DIE_NMI_IPI)
++ return NOTIFY_OK;
++
++ regs = ((struct die_args *)data)->regs;
++ cpu = raw_smp_processor_id();
+
+ /* 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;
++ return NOTIFY_STOP;
+ local_irq_disable();
+
+ if (!user_mode_vm(regs)) {
+@@ -122,16 +134,24 @@ static int crash_nmi_callback(struct pt_
+
+ static void smp_send_nmi_allbutself(void)
+ {
+- send_IPI_allbutself(NMI_VECTOR);
++ cpumask_t mask = cpu_online_map;
++ cpu_clear(safe_smp_processor_id(), mask);
++ if (!cpus_empty(mask))
++ send_IPI_mask(mask, NMI_VECTOR);
+ }
+
++static struct notifier_block crash_nmi_nb = {
++ .notifier_call = crash_nmi_callback,
++};
++
+ 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);
++ if (register_die_notifier(&crash_nmi_nb))
++ return; /* return what? */
+ /* Ensure the new callback function is set before sending
+ * out the NMI
+ */
+@@ -169,7 +189,7 @@ void machine_crash_shutdown(struct pt_re
+ local_irq_disable();
+
+ /* Make a note of crashing cpu. Will be used in NMI callback.*/
+- crashing_cpu = smp_processor_id();
++ crashing_cpu = safe_smp_processor_id();
+ nmi_shootdown_cpus();
+ lapic_shutdown();
+ #if defined(CONFIG_X86_IO_APIC)
+diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
+index fe15804..8b40648 100644
+--- a/arch/i386/kernel/efi.c
++++ b/arch/i386/kernel/efi.c
+@@ -65,7 +65,7 @@ static unsigned long efi_rt_eflags;
+ static DEFINE_SPINLOCK(efi_rt_lock);
+ static pgd_t efi_bak_pg_dir_pointer[2];
+
+-static void efi_call_phys_prelog(void)
++static void efi_call_phys_prelog(void) __acquires(efi_rt_lock)
+ {
+ unsigned long cr4;
+ unsigned long temp;
+@@ -109,7 +109,7 @@ static void efi_call_phys_prelog(void)
+ load_gdt(cpu_gdt_descr);
+ }
+
+-static void efi_call_phys_epilog(void)
++static void efi_call_phys_epilog(void) __releases(efi_rt_lock)
+ {
+ unsigned long cr4;
+ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
+@@ -498,8 +498,7 @@ void __init efi_enter_virtual_mode(void)
+ check_range_for_systab(md);
+ }
+
+- if (!efi.systab)
+- BUG();
++ BUG_ON(!efi.systab);
+
+ status = phys_efi_set_virtual_address_map(
+ memmap.desc_size * memmap.nr_map,
+diff --git a/arch/i386/kernel/efi_stub.S b/arch/i386/kernel/efi_stub.S
+index d3ee73a..ef00bb7 100644
+--- a/arch/i386/kernel/efi_stub.S
++++ b/arch/i386/kernel/efi_stub.S
+@@ -7,7 +7,6 @@
+
+ #include <linux/linkage.h>
+ #include <asm/page.h>
+-#include <asm/pgtable.h>
+
+ /*
+ * efi_call_phys(void *, ...) is a function with variable parameters.
+diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
+index 87f9f60..5a63d6f 100644
+--- a/arch/i386/kernel/entry.S
++++ b/arch/i386/kernel/entry.S
+@@ -76,8 +76,15 @@ DF_MASK = 0x00000400
+ NT_MASK = 0x00004000
+ VM_MASK = 0x00020000
+
++/* These are replaces for paravirtualization */
++#define DISABLE_INTERRUPTS cli
++#define ENABLE_INTERRUPTS sti
++#define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit
++#define INTERRUPT_RETURN iret
++#define GET_CR0_INTO_EAX movl %cr0, %eax
++
+ #ifdef CONFIG_PREEMPT
+-#define preempt_stop cli; TRACE_IRQS_OFF
++#define preempt_stop DISABLE_INTERRUPTS; TRACE_IRQS_OFF
+ #else
+ #define preempt_stop
+ #define resume_kernel restore_nocheck
+@@ -176,18 +183,21 @@ VM_MASK = 0x00020000
+
+ #define RING0_INT_FRAME \
+ CFI_STARTPROC simple;\
++ CFI_SIGNAL_FRAME;\
+ CFI_DEF_CFA esp, 3*4;\
+ /*CFI_OFFSET cs, -2*4;*/\
+ CFI_OFFSET eip, -3*4
+
+ #define RING0_EC_FRAME \
+ CFI_STARTPROC simple;\
++ CFI_SIGNAL_FRAME;\
+ CFI_DEF_CFA esp, 4*4;\
+ /*CFI_OFFSET cs, -2*4;*/\
+ CFI_OFFSET eip, -3*4
+
+ #define RING0_PTREGS_FRAME \
+ CFI_STARTPROC simple;\
++ CFI_SIGNAL_FRAME;\
+ CFI_DEF_CFA esp, OLDESP-EBX;\
+ /*CFI_OFFSET cs, CS-OLDESP;*/\
+ CFI_OFFSET eip, EIP-OLDESP;\
+@@ -233,10 +243,11 @@ ret_from_intr:
+ check_userspace:
+ movl EFLAGS(%esp), %eax # mix EFLAGS and CS
+ movb CS(%esp), %al
+- testl $(VM_MASK | 3), %eax
+- jz resume_kernel
++ andl $(VM_MASK | SEGMENT_RPL_MASK), %eax
++ cmpl $USER_RPL, %eax
++ jb resume_kernel # not returning to v8086 or userspace
+ ENTRY(resume_userspace)
+- cli # make sure we don't miss an interrupt
++ DISABLE_INTERRUPTS # make sure we don't miss an interrupt
+ # setting need_resched or sigpending
+ # between sampling and the iret
+ movl TI_flags(%ebp), %ecx
+@@ -247,7 +258,7 @@ ENTRY(resume_userspace)
+
+ #ifdef CONFIG_PREEMPT
+ ENTRY(resume_kernel)
+- cli
++ DISABLE_INTERRUPTS
+ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
+ jnz restore_nocheck
+ need_resched:
+@@ -267,6 +278,7 @@ need_resched:
+ # sysenter call handler stub
+ ENTRY(sysenter_entry)
+ CFI_STARTPROC simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA esp, 0
+ CFI_REGISTER esp, ebp
+ movl TSS_sysenter_esp0(%esp),%esp
+@@ -275,7 +287,7 @@ sysenter_past_esp:
+ * No need to follow this irqs on/off section: the syscall
+ * disabled irqs and here we enable it straight after entry:
+ */
+- sti
++ ENABLE_INTERRUPTS
+ pushl $(__USER_DS)
+ CFI_ADJUST_CFA_OFFSET 4
+ /*CFI_REL_OFFSET ss, 0*/
+@@ -320,7 +332,7 @@ sysenter_past_esp:
+ jae syscall_badsys
+ call *sys_call_table(,%eax,4)
+ movl %eax,EAX(%esp)
+- cli
++ DISABLE_INTERRUPTS
+ TRACE_IRQS_OFF
+ movl TI_flags(%ebp), %ecx
+ testw $_TIF_ALLWORK_MASK, %cx
+@@ -330,8 +342,7 @@ sysenter_past_esp:
+ movl OLDESP(%esp), %ecx
+ xorl %ebp,%ebp
+ TRACE_IRQS_ON
+- sti
+- sysexit
++ ENABLE_INTERRUPTS_SYSEXIT
+ CFI_ENDPROC
+
+
+@@ -356,7 +367,7 @@ syscall_call:
+ call *sys_call_table(,%eax,4)
+ movl %eax,EAX(%esp) # store the return value
+ syscall_exit:
+- cli # make sure we don't miss an interrupt
++ DISABLE_INTERRUPTS # make sure we don't miss an interrupt
+ # setting need_resched or sigpending
+ # between sampling and the iret
+ TRACE_IRQS_OFF
+@@ -371,8 +382,8 @@ restore_all:
+ # See comments in process.c:copy_thread() for details.
+ movb OLDSS(%esp), %ah
+ movb CS(%esp), %al
+- andl $(VM_MASK | (4 << 8) | 3), %eax
+- cmpl $((4 << 8) | 3), %eax
++ andl $(VM_MASK | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
++ cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
+ CFI_REMEMBER_STATE
+ je ldt_ss # returning to user-space with LDT SS
+ restore_nocheck:
+@@ -381,11 +392,11 @@ restore_nocheck_notrace:
+ RESTORE_REGS
+ addl $4, %esp
+ CFI_ADJUST_CFA_OFFSET -4
+-1: iret
++1: INTERRUPT_RETURN
+ .section .fixup,"ax"
+ iret_exc:
+ TRACE_IRQS_ON
+- sti
++ ENABLE_INTERRUPTS
+ pushl $0 # no error code
+ pushl $do_iret_error
+ jmp error_code
+@@ -409,7 +420,7 @@ ldt_ss:
+ * dosemu and wine happy. */
+ subl $8, %esp # reserve space for switch16 pointer
+ CFI_ADJUST_CFA_OFFSET 8
+- cli
++ DISABLE_INTERRUPTS
+ TRACE_IRQS_OFF
+ movl %esp, %eax
+ /* Set up the 16bit stack frame with switch32 pointer on top,
+@@ -419,7 +430,7 @@ ldt_ss:
+ TRACE_IRQS_IRET
+ RESTORE_REGS
+ lss 20+4(%esp), %esp # switch to 16bit stack
+-1: iret
++1: INTERRUPT_RETURN
+ .section __ex_table,"a"
+ .align 4
+ .long 1b,iret_exc
+@@ -434,7 +445,7 @@ work_pending:
+ jz work_notifysig
+ work_resched:
+ call schedule
+- cli # make sure we don't miss an interrupt
++ DISABLE_INTERRUPTS # make sure we don't miss an interrupt
+ # setting need_resched or sigpending
+ # between sampling and the iret
+ TRACE_IRQS_OFF
+@@ -490,7 +501,7 @@ syscall_exit_work:
+ testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
+ jz work_pending
+ TRACE_IRQS_ON
+- sti # could let do_syscall_trace() call
++ ENABLE_INTERRUPTS # could let do_syscall_trace() call
+ # schedule() instead
+ movl %esp, %eax
+ movl $1, %edx
+@@ -591,11 +602,9 @@ ENTRY(name) \
+ /* The include is where all of the SMP etc. interrupts come from */
+ #include "entry_arch.h"
+
+-ENTRY(divide_error)
+- RING0_INT_FRAME
+- pushl $0 # no error code
+- CFI_ADJUST_CFA_OFFSET 4
+- pushl $do_divide_error
++KPROBE_ENTRY(page_fault)
++ RING0_EC_FRAME
++ pushl $do_page_fault
+ CFI_ADJUST_CFA_OFFSET 4
+ ALIGN
+ error_code:
+@@ -645,6 +654,7 @@ error_code:
+ call *%edi
+ jmp ret_from_exception
+ CFI_ENDPROC
++KPROBE_END(page_fault)
+
+ ENTRY(coprocessor_error)
+ RING0_INT_FRAME
+@@ -669,7 +679,7 @@ ENTRY(device_not_available)
+ pushl $-1 # mark this as an int
+ CFI_ADJUST_CFA_OFFSET 4
+ SAVE_ALL
+- movl %cr0, %eax
++ GET_CR0_INTO_EAX
+ testl $0x4, %eax # EM (math emulation bit)
+ jne device_not_available_emulate
+ preempt_stop
+@@ -702,9 +712,15 @@ device_not_available_emulate:
+ jne ok; \
+ label: \
+ movl TSS_sysenter_esp0+offset(%esp),%esp; \
++ CFI_DEF_CFA esp, 0; \
++ CFI_UNDEFINED eip; \
+ pushfl; \
++ CFI_ADJUST_CFA_OFFSET 4; \
+ pushl $__KERNEL_CS; \
+- pushl $sysenter_past_esp
++ CFI_ADJUST_CFA_OFFSET 4; \
++ pushl $sysenter_past_esp; \
++ CFI_ADJUST_CFA_OFFSET 4; \
++ CFI_REL_OFFSET eip, 0
+
+ KPROBE_ENTRY(debug)
+ RING0_INT_FRAME
+@@ -720,7 +736,8 @@ debug_stack_correct:
+ call do_debug
+ jmp ret_from_exception
+ CFI_ENDPROC
+- .previous .text
++KPROBE_END(debug)
++
+ /*
+ * NMI is doubly nasty. It can happen _while_ we're handling
+ * a debug fault, and the debug fault hasn't yet been able to
+@@ -729,7 +746,7 @@ debug_stack_correct:
+ * check whether we got an NMI on the debug path where the debug
+ * fault happened on the sysenter path.
+ */
+-ENTRY(nmi)
++KPROBE_ENTRY(nmi)
+ RING0_INT_FRAME
+ pushl %eax
+ CFI_ADJUST_CFA_OFFSET 4
+@@ -754,6 +771,7 @@ ENTRY(nmi)
+ cmpl $sysenter_entry,12(%esp)
+ je nmi_debug_stack_check
+ nmi_stack_correct:
++ /* We have a RING0_INT_FRAME here */
+ pushl %eax
+ CFI_ADJUST_CFA_OFFSET 4
+ SAVE_ALL
+@@ -764,9 +782,12 @@ nmi_stack_correct:
+ CFI_ENDPROC
+
+ nmi_stack_fixup:
++ RING0_INT_FRAME
+ FIX_STACK(12,nmi_stack_correct, 1)
+ jmp nmi_stack_correct
++
+ nmi_debug_stack_check:
++ /* We have a RING0_INT_FRAME here */
+ cmpw $__KERNEL_CS,16(%esp)
+ jne nmi_stack_correct
+ cmpl $debug,(%esp)
+@@ -777,8 +798,10 @@ nmi_debug_stack_check:
+ jmp nmi_stack_correct
+
+ nmi_16bit_stack:
+- RING0_INT_FRAME
+- /* create the pointer to lss back */
++ /* We have a RING0_INT_FRAME here.
++ *
++ * create the pointer to lss back
++ */
+ pushl %ss
+ CFI_ADJUST_CFA_OFFSET 4
+ pushl %esp
+@@ -799,12 +822,13 @@ nmi_16bit_stack:
+ call do_nmi
+ RESTORE_REGS
+ lss 12+4(%esp), %esp # back to 16bit stack
+-1: iret
++1: INTERRUPT_RETURN
+ CFI_ENDPROC
+ .section __ex_table,"a"
+ .align 4
+ .long 1b,iret_exc
+ .previous
++KPROBE_END(nmi)
+
+ KPROBE_ENTRY(int3)
+ RING0_INT_FRAME
+@@ -816,7 +840,7 @@ KPROBE_ENTRY(int3)
+ call do_int3
+ jmp ret_from_exception
+ CFI_ENDPROC
+- .previous .text
++KPROBE_END(int3)
+
+ ENTRY(overflow)
+ RING0_INT_FRAME
+@@ -881,7 +905,7 @@ KPROBE_ENTRY(general_protection)
+ CFI_ADJUST_CFA_OFFSET 4
+ jmp error_code
+ CFI_ENDPROC
+- .previous .text
++KPROBE_END(general_protection)
+
+ ENTRY(alignment_check)
+ RING0_EC_FRAME
+@@ -890,13 +914,14 @@ ENTRY(alignment_check)
+ jmp error_code
+ CFI_ENDPROC
+
+-KPROBE_ENTRY(page_fault)
+- RING0_EC_FRAME
+- pushl $do_page_fault
++ENTRY(divide_error)
++ RING0_INT_FRAME
++ pushl $0 # no error code
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_divide_error
+ CFI_ADJUST_CFA_OFFSET 4
+ jmp error_code
+ CFI_ENDPROC
+- .previous .text
+
+ #ifdef CONFIG_X86_MCE
+ ENTRY(machine_check)
+@@ -949,6 +974,19 @@ ENTRY(arch_unwind_init_running)
+ ENDPROC(arch_unwind_init_running)
+ #endif
+
++ENTRY(kernel_thread_helper)
++ pushl $0 # fake return address for unwinder
++ CFI_STARTPROC
++ movl %edx,%eax
++ push %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ call *%ebx
++ push %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ call do_exit
++ CFI_ENDPROC
++ENDPROC(kernel_thread_helper)
++
+ .section .rodata,"a"
+ #include "syscall_table.S"
+
+diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
+index a6b8bd8..ca31f18 100644
+--- a/arch/i386/kernel/head.S
++++ b/arch/i386/kernel/head.S
+@@ -317,7 +317,7 @@ is386: movl $2,%ecx # set MP
+ movl %eax,%gs
+ lldt %ax
+ cld # gcc2 wants the direction flag cleared at all times
+- pushl %eax # fake return address
++ pushl $0 # fake return address for unwinder
+ #ifdef CONFIG_SMP
+ movb ready, %cl
+ movb $1, ready
+@@ -371,8 +371,65 @@ rp_sidt:
+ addl $8,%edi
+ dec %ecx
+ jne rp_sidt
++
++.macro set_early_handler handler,trapno
++ lea \handler,%edx
++ movl $(__KERNEL_CS << 16),%eax
++ movw %dx,%ax
++ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
++ lea idt_table,%edi
++ movl %eax,8*\trapno(%edi)
++ movl %edx,8*\trapno+4(%edi)
++.endm
++
++ set_early_handler handler=early_divide_err,trapno=0
++ set_early_handler handler=early_illegal_opcode,trapno=6
++ set_early_handler handler=early_protection_fault,trapno=13
++ set_early_handler handler=early_page_fault,trapno=14
++
+ ret
+
++early_divide_err:
++ xor %edx,%edx
++ pushl $0 /* fake errcode */
++ jmp early_fault
++
++early_illegal_opcode:
++ movl $6,%edx
++ pushl $0 /* fake errcode */
++ jmp early_fault
++
++early_protection_fault:
++ movl $13,%edx
++ jmp early_fault
++
++early_page_fault:
++ movl $14,%edx
++ jmp early_fault
++
++early_fault:
++ cld
++#ifdef CONFIG_PRINTK
++ movl $(__KERNEL_DS),%eax
++ movl %eax,%ds
++ movl %eax,%es
++ cmpl $2,early_recursion_flag
++ je hlt_loop
++ incl early_recursion_flag
++ movl %cr2,%eax
++ pushl %eax
++ pushl %edx /* trapno */
++ pushl $fault_msg
++#ifdef CONFIG_EARLY_PRINTK
++ call early_printk
++#else
++ call printk
++#endif
++#endif
++hlt_loop:
++ hlt
++ jmp hlt_loop
++
+ /* This is the default interrupt "handler" :-) */
+ ALIGN
+ ignore_int:
+@@ -386,6 +443,9 @@ ignore_int:
+ movl $(__KERNEL_DS),%eax
+ movl %eax,%ds
+ movl %eax,%es
++ cmpl $2,early_recursion_flag
++ je hlt_loop
++ incl early_recursion_flag
+ pushl 16(%esp)
+ pushl 24(%esp)
+ pushl 32(%esp)
+@@ -431,9 +491,16 @@ ENTRY(stack_start)
+
+ ready: .byte 0
+
++early_recursion_flag:
++ .long 0
++
+ int_msg:
+ .asciz "Unknown interrupt or fault at EIP %p %p %p\n"
+
++fault_msg:
++ .ascii "Int %d: CR2 %p err %p EIP %p CS %p flags %p\n"
++ .asciz "Stack: %p %p %p %p %p %p %p %p\n"
++
+ /*
+ * The IDT and GDT 'descriptors' are a strange 48-bit object
+ * only used by the lidt and lgdt instructions. They are not
+diff --git a/arch/i386/kernel/i8237.c b/arch/i386/kernel/i8237.c
+index c36d1c0..6f508e8 100644
+--- a/arch/i386/kernel/i8237.c
++++ b/arch/i386/kernel/i8237.c
+@@ -2,6 +2,11 @@
+ * i8237.c: 8237A DMA controller suspend functions.
+ *
+ * Written by Pierre Ossman, 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.
+ */
+
+ #include <linux/init.h>
+diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
+index 477b24d..9a0060b 100644
+--- a/arch/i386/kernel/i8253.c
++++ b/arch/i386/kernel/i8253.c
+@@ -109,7 +109,7 @@ static struct clocksource clocksource_pi
+
+ static int __init init_pit_clocksource(void)
+ {
+- if (num_possible_cpus() > 4) /* PIT does not scale! */
++ if (num_possible_cpus() > 1) /* PIT does not scale! */
+ return 0;
+
+ clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
+diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
+index d4756d1..62996cd 100644
+--- a/arch/i386/kernel/i8259.c
++++ b/arch/i386/kernel/i8259.c
+@@ -34,33 +34,15 @@
+ * moves to arch independent land
+ */
+
++static int i8259A_auto_eoi;
+ DEFINE_SPINLOCK(i8259A_lock);
+-
+-static void end_8259A_irq (unsigned int irq)
+-{
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+- irq_desc[irq].action)
+- enable_8259A_irq(irq);
+-}
+-
+-#define shutdown_8259A_irq disable_8259A_irq
+-
+ static void mask_and_ack_8259A(unsigned int);
+
+-unsigned int startup_8259A_irq(unsigned int irq)
+-{
+- enable_8259A_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static struct hw_interrupt_type i8259A_irq_type = {
+- .typename = "XT-PIC",
+- .startup = startup_8259A_irq,
+- .shutdown = shutdown_8259A_irq,
+- .enable = enable_8259A_irq,
+- .disable = disable_8259A_irq,
+- .ack = mask_and_ack_8259A,
+- .end = end_8259A_irq,
++static struct irq_chip i8259A_chip = {
++ .name = "XT-PIC",
++ .mask = disable_8259A_irq,
++ .unmask = enable_8259A_irq,
++ .mask_ack = mask_and_ack_8259A,
+ };
+
+ /*
+@@ -131,7 +113,8 @@ void make_8259A_irq(unsigned int irq)
+ {
+ disable_irq_nosync(irq);
+ io_apic_irqs &= ~(1<<irq);
+- irq_desc[irq].chip = &i8259A_irq_type;
++ set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
++ "XT");
+ enable_irq(irq);
+ }
+
+@@ -253,7 +236,7 @@ static void save_ELCR(char *trigger)
+
+ static int i8259A_resume(struct sys_device *dev)
+ {
+- init_8259A(0);
++ init_8259A(i8259A_auto_eoi);
+ restore_ELCR(irq_trigger);
+ return 0;
+ }
+@@ -301,6 +284,8 @@ void init_8259A(int auto_eoi)
+ {
+ unsigned long flags;
+
++ i8259A_auto_eoi = auto_eoi;
++
+ spin_lock_irqsave(&i8259A_lock, flags);
+
+ outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
+@@ -323,12 +308,12 @@ void init_8259A(int auto_eoi)
+ outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
+ if (auto_eoi)
+ /*
+- * in AEOI mode we just have to mask the interrupt
++ * In AEOI mode we just have to mask the interrupt
+ * when acking.
+ */
+- i8259A_irq_type.ack = disable_8259A_irq;
++ i8259A_chip.mask_ack = disable_8259A_irq;
+ else
+- i8259A_irq_type.ack = mask_and_ack_8259A;
++ i8259A_chip.mask_ack = mask_and_ack_8259A;
+
+ udelay(100); /* wait for 8259A to initialize */
+
+@@ -351,13 +336,13 @@ void init_8259A(int auto_eoi)
+ */
+
+
+-static irqreturn_t math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
++static irqreturn_t math_error_irq(int cpl, void *dev_id)
+ {
+ extern void math_error(void __user *);
+ outb(0,0xF0);
+ if (ignore_fpu_irq || !boot_cpu_data.hard_math)
+ return IRQ_NONE;
+- math_error((void __user *)regs->eip);
++ math_error((void __user *)get_irq_regs()->eip);
+ return IRQ_HANDLED;
+ }
+
+@@ -385,12 +370,13 @@ void __init init_ISA_irqs (void)
+ /*
+ * 16 old-style INTA-cycle interrupts:
+ */
+- irq_desc[i].chip = &i8259A_irq_type;
++ set_irq_chip_and_handler_name(i, &i8259A_chip,
++ handle_level_irq, "XT");
+ } else {
+ /*
+ * 'high' PCI IRQs filled in on demand
+ */
+- irq_desc[i].chip = &no_irq_type;
++ irq_desc[i].chip = &no_irq_chip;
+ }
+ }
+ }
+diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
+index 4fb32c5..507983c 100644
+--- a/arch/i386/kernel/io_apic.c
++++ b/arch/i386/kernel/io_apic.c
+@@ -31,6 +31,9 @@
+ #include <linux/acpi.h>
+ #include <linux/module.h>
+ #include <linux/sysdev.h>
++#include <linux/pci.h>
++#include <linux/msi.h>
++#include <linux/htirq.h>
+
+ #include <asm/io.h>
+ #include <asm/smp.h>
+@@ -38,8 +41,11 @@
+ #include <asm/timer.h>
+ #include <asm/i8259.h>
+ #include <asm/nmi.h>
++#include <asm/msidef.h>
++#include <asm/hypertransport.h>
+
+ #include <mach_apic.h>
++#include <mach_apicdef.h>
+
+ #include "io_ports.h"
+
+@@ -65,7 +71,7 @@ int sis_apic_bug = -1;
+ */
+ int nr_ioapic_registers[MAX_IO_APICS];
+
+-int disable_timer_pin_1 __initdata;
++static int disable_timer_pin_1 __initdata;
+
+ /*
+ * Rough estimation of how many shared IRQs there are, can
+@@ -85,13 +91,94 @@ static struct irq_pin_list {
+ int apic, pin, next;
+ } irq_2_pin[PIN_MAP_SIZE];
+
+-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
+-#ifdef CONFIG_PCI_MSI
+-#define vector_to_irq(vector) \
+- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
+-#else
+-#define vector_to_irq(vector) (vector)
+-#endif
++struct io_apic {
++ unsigned int index;
++ unsigned int unused[3];
++ unsigned int data;
++};
++
++static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
++{
++ return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
++ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK);
++}
++
++static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
++{
++ struct io_apic __iomem *io_apic = io_apic_base(apic);
++ writel(reg, &io_apic->index);
++ return readl(&io_apic->data);
++}
++
++static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
++{
++ struct io_apic __iomem *io_apic = io_apic_base(apic);
++ writel(reg, &io_apic->index);
++ writel(value, &io_apic->data);
++}
++
++/*
++ * Re-write a value: to be used for read-modify-write
++ * cycles where the read already set up the index register.
++ *
++ * Older SiS APIC requires we rewrite the index register
++ */
++static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
++{
++ volatile struct io_apic *io_apic = io_apic_base(apic);
++ if (sis_apic_bug)
++ writel(reg, &io_apic->index);
++ writel(value, &io_apic->data);
++}
++
++union entry_union {
++ struct { u32 w1, w2; };
++ struct IO_APIC_route_entry entry;
++};
++
++static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
++{
++ union entry_union eu;
++ unsigned long flags;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
++ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ return eu.entry;
++}
++
++/*
++ * When we write a new IO APIC routing entry, we need to write the high
++ * word first! If the mask bit in the low word is clear, we will enable
++ * the interrupt, and we need to make sure the entry is fully populated
++ * before that happens.
++ */
++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
++{
++ unsigned long flags;
++ union entry_union eu;
++ eu.entry = e;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11 + 2*pin, eu.w2);
++ io_apic_write(apic, 0x10 + 2*pin, eu.w1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++/*
++ * When we mask an IO APIC routing entry, we need to write the low
++ * word first, in order to set the mask bit before we change the
++ * high bits!
++ */
++static void ioapic_mask_entry(int apic, int pin)
++{
++ unsigned long flags;
++ union entry_union eu = { .entry.mask = 1 };
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x10 + 2*pin, eu.w1);
++ io_apic_write(apic, 0x11 + 2*pin, eu.w2);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
+
+ /*
+ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
+@@ -200,25 +287,16 @@ static void unmask_IO_APIC_irq (unsigned
+ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+ {
+ struct IO_APIC_route_entry entry;
+- unsigned long flags;
+
+ /* Check delivery_mode to be sure we're not clearing an SMI pin */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+- *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ entry = ioapic_read_entry(apic, pin);
+ if (entry.delivery_mode == dest_SMI)
+ return;
+
+ /*
+ * Disable it in the IO-APIC irq-routing table:
+ */
+- memset(&entry, 0, sizeof(entry));
+- entry.mask = 1;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_mask_entry(apic, pin);
+ }
+
+ static void clear_IO_APIC (void)
+@@ -258,7 +336,7 @@ static void set_ioapic_affinity_irq(unsi
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+- set_irq_info(irq, cpumask);
++ set_native_irq_info(irq, cpumask);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+
+@@ -1159,46 +1237,45 @@ static inline int IO_APIC_irq_trigger(in
+ /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
+ u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
+
+-int assign_irq_vector(int irq)
++static int __assign_irq_vector(int irq)
+ {
+ static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+- unsigned long flags;
+ int vector;
+
+- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
++ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+
+- spin_lock_irqsave(&vector_lock, flags);
++ if (irq_vector[irq] > 0)
++ return irq_vector[irq];
+
+- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+- spin_unlock_irqrestore(&vector_lock, flags);
+- return IO_APIC_VECTOR(irq);
+- }
+-next:
+ current_vector += 8;
+ if (current_vector == SYSCALL_VECTOR)
+- goto next;
++ current_vector += 8;
+
+ if (current_vector >= FIRST_SYSTEM_VECTOR) {
+ offset++;
+- if (!(offset%8)) {
+- spin_unlock_irqrestore(&vector_lock, flags);
++ if (!(offset % 8))
+ return -ENOSPC;
+- }
+ current_vector = FIRST_DEVICE_VECTOR + offset;
+ }
+
+ vector = current_vector;
+- vector_irq[vector] = irq;
+- if (irq != AUTO_ASSIGN)
+- IO_APIC_VECTOR(irq) = vector;
++ irq_vector[irq] = vector;
++
++ return vector;
++}
++
++static int assign_irq_vector(int irq)
++{
++ unsigned long flags;
++ int vector;
+
++ spin_lock_irqsave(&vector_lock, flags);
++ vector = __assign_irq_vector(irq);
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ return vector;
+ }
+-
+-static struct hw_interrupt_type ioapic_level_type;
+-static struct hw_interrupt_type ioapic_edge_type;
++static struct irq_chip ioapic_chip;
+
+ #define IOAPIC_AUTO -1
+ #define IOAPIC_EDGE 0
+@@ -1206,16 +1283,14 @@ static struct hw_interrupt_type ioapic_e
+
+ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+ {
+- unsigned idx;
+-
+- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+-
+ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
+ trigger == IOAPIC_LEVEL)
+- irq_desc[idx].chip = &ioapic_level_type;
++ set_irq_chip_and_handler_name(irq, &ioapic_chip,
++ handle_fasteoi_irq, "fasteoi");
+ else
+- irq_desc[idx].chip = &ioapic_edge_type;
+- set_intr_gate(vector, interrupt[idx]);
++ set_irq_chip_and_handler_name(irq, &ioapic_chip,
++ handle_edge_irq, "edge");
++ set_intr_gate(vector, interrupt[irq]);
+ }
+
+ static void __init setup_IO_APIC_irqs(void)
+@@ -1283,9 +1358,8 @@ static void __init setup_IO_APIC_irqs(vo
+ if (!apic && (irq < 16))
+ disable_8259A_irq(irq);
+ }
++ ioapic_write_entry(apic, pin, entry);
+ spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+ set_native_irq_info(irq, TARGET_CPUS);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+@@ -1301,7 +1375,6 @@ static void __init setup_IO_APIC_irqs(vo
+ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
+ {
+ struct IO_APIC_route_entry entry;
+- unsigned long flags;
+
+ memset(&entry,0,sizeof(entry));
+
+@@ -1326,15 +1399,13 @@ static void __init setup_ExtINT_IRQ0_pin
+ * The timer IRQ doesn't have to know that behind the
+ * scene we have a 8259A-master in AEOI mode ...
+ */
+- irq_desc[0].chip = &ioapic_edge_type;
++ irq_desc[0].chip = &ioapic_chip;
++ set_irq_handler(0, handle_edge_irq);
+
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_write_entry(apic, pin, entry);
+
+ enable_8259A_irq(0);
+ }
+@@ -1444,10 +1515,7 @@ void __init print_IO_APIC(void)
+ for (i = 0; i <= reg_01.bits.entries; i++) {
+ struct IO_APIC_route_entry entry;
+
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+- *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ entry = ioapic_read_entry(apic, i);
+
+ printk(KERN_DEBUG " %02x %03X %02X ",
+ i,
+@@ -1467,17 +1535,12 @@ void __init print_IO_APIC(void)
+ );
+ }
+ }
+- if (use_pci_vector())
+- printk(KERN_INFO "Using vector-based indexing\n");
+ printk(KERN_DEBUG "IRQ to pin mappings:\n");
+ for (i = 0; i < NR_IRQS; i++) {
+ struct irq_pin_list *entry = irq_2_pin + i;
+ if (entry->pin < 0)
+ continue;
+- if (use_pci_vector() && !platform_legacy_irq(i))
+- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+- else
+- printk(KERN_DEBUG "IRQ%d ", i);
++ printk(KERN_DEBUG "IRQ%d ", i);
+ for (;;) {
+ printk("-> %d:%d", entry->apic, entry->pin);
+ if (!entry->next)
+@@ -1666,10 +1729,7 @@ static void __init enable_IO_APIC(void)
+ /* See if any of the pins is in ExtINT mode */
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ struct IO_APIC_route_entry entry;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+- *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ entry = ioapic_read_entry(apic, pin);
+
+
+ /* If the interrupt line is enabled and in ExtInt mode
+@@ -1726,7 +1786,6 @@ void disable_IO_APIC(void)
+ */
+ if (ioapic_i8259.pin != -1) {
+ struct IO_APIC_route_entry entry;
+- unsigned long flags;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.mask = 0; /* Enabled */
+@@ -1743,12 +1802,7 @@ void disable_IO_APIC(void)
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin,
+- *(((int *)&entry)+1));
+- io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin,
+- *(((int *)&entry)+0));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
+ }
+ disconnect_bsp_APIC(ioapic_i8259.pin != -1);
+ }
+@@ -1913,6 +1967,8 @@ static int __init timer_irq_works(void)
+ */
+
+ /*
++ * Startup quirk:
++ *
+ * Starting up a edge-triggered IO-APIC interrupt is
+ * nasty - we need to make sure that we get the edge.
+ * If it is already asserted for some reason, we need
+@@ -1920,8 +1976,10 @@ static int __init timer_irq_works(void)
+ *
+ * This is not complete - we should be able to fake
+ * an edge even if it isn't on the 8259A...
++ *
++ * (We do this for level-triggered IRQs too - it cannot hurt.)
+ */
+-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
++static unsigned int startup_ioapic_irq(unsigned int irq)
+ {
+ int was_pending = 0;
+ unsigned long flags;
+@@ -1938,47 +1996,18 @@ static unsigned int startup_edge_ioapic_
+ return was_pending;
+ }
+
+-/*
+- * Once we have recorded IRQ_PENDING already, we can mask the
+- * interrupt for real. This prevents IRQ storms from unhandled
+- * devices.
+- */
+-static void ack_edge_ioapic_irq(unsigned int irq)
++static void ack_ioapic_irq(unsigned int irq)
+ {
+- move_irq(irq);
+- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
+- == (IRQ_PENDING | IRQ_DISABLED))
+- mask_IO_APIC_irq(irq);
++ move_native_irq(irq);
+ ack_APIC_irq();
+ }
+
+-/*
+- * Level triggered interrupts can just be masked,
+- * and shutting down and starting up the interrupt
+- * is the same as enabling and disabling them -- except
+- * with a startup need to return a "was pending" value.
+- *
+- * Level triggered interrupts are special because we
+- * do not touch any IO-APIC register while handling
+- * them. We ack the APIC in the end-IRQ handler, not
+- * in the start-IRQ-handler. Protection against reentrance
+- * from the same interrupt is still provided, both by the
+- * generic IRQ layer and by the fact that an unacked local
+- * APIC does not accept IRQs.
+- */
+-static unsigned int startup_level_ioapic_irq (unsigned int irq)
+-{
+- unmask_IO_APIC_irq(irq);
+-
+- return 0; /* don't check for pending */
+-}
+-
+-static void end_level_ioapic_irq (unsigned int irq)
++static void ack_ioapic_quirk_irq(unsigned int irq)
+ {
+ unsigned long v;
+ int i;
+
+- move_irq(irq);
++ move_native_irq(irq);
+ /*
+ * It appears there is an erratum which affects at least version 0x11
+ * of I/O APIC (that's the 82093AA and cores integrated into various
+@@ -1998,7 +2027,7 @@ static void end_level_ioapic_irq (unsign
+ * operation to prevent an edge-triggered interrupt escaping meanwhile.
+ * The idea is from Manfred Spraul. --macro
+ */
+- i = IO_APIC_VECTOR(irq);
++ i = irq_vector[irq];
+
+ v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+
+@@ -2013,105 +2042,26 @@ static void end_level_ioapic_irq (unsign
+ }
+ }
+
+-#ifdef CONFIG_PCI_MSI
+-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- return startup_edge_ioapic_irq(irq);
+-}
+-
+-static void ack_edge_ioapic_vector(unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- move_native_irq(vector);
+- ack_edge_ioapic_irq(irq);
+-}
+-
+-static unsigned int startup_level_ioapic_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- return startup_level_ioapic_irq (irq);
+-}
+-
+-static void end_level_ioapic_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- move_native_irq(vector);
+- end_level_ioapic_irq(irq);
+-}
+-
+-static void mask_IO_APIC_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- mask_IO_APIC_irq(irq);
+-}
+-
+-static void unmask_IO_APIC_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- unmask_IO_APIC_irq(irq);
+-}
+-
+-#ifdef CONFIG_SMP
+-static void set_ioapic_affinity_vector (unsigned int vector,
+- cpumask_t cpu_mask)
+-{
+- int irq = vector_to_irq(vector);
+-
+- set_native_irq_info(vector, cpu_mask);
+- set_ioapic_affinity_irq(irq, cpu_mask);
+-}
+-#endif
+-#endif
+-
+-static int ioapic_retrigger(unsigned int irq)
++static int ioapic_retrigger_irq(unsigned int irq)
+ {
+- send_IPI_self(IO_APIC_VECTOR(irq));
++ send_IPI_self(irq_vector[irq]);
+
+ return 1;
+ }
+
+-/*
+- * Level and edge triggered IO-APIC interrupts need different handling,
+- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
+- * handled with the level-triggered descriptor, but that one has slightly
+- * more overhead. Level-triggered interrupts cannot be handled with the
+- * edge-triggered handler, without risking IRQ storms and other ugly
+- * races.
+- */
+-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
+- .typename = "IO-APIC-edge",
+- .startup = startup_edge_ioapic,
+- .shutdown = shutdown_edge_ioapic,
+- .enable = enable_edge_ioapic,
+- .disable = disable_edge_ioapic,
+- .ack = ack_edge_ioapic,
+- .end = end_edge_ioapic,
++static struct irq_chip ioapic_chip __read_mostly = {
++ .name = "IO-APIC",
++ .startup = startup_ioapic_irq,
++ .mask = mask_IO_APIC_irq,
++ .unmask = unmask_IO_APIC_irq,
++ .ack = ack_ioapic_irq,
++ .eoi = ack_ioapic_quirk_irq,
+ #ifdef CONFIG_SMP
+- .set_affinity = set_ioapic_affinity,
++ .set_affinity = set_ioapic_affinity_irq,
+ #endif
+- .retrigger = ioapic_retrigger,
++ .retrigger = ioapic_retrigger_irq,
+ };
+
+-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
+- .typename = "IO-APIC-level",
+- .startup = startup_level_ioapic,
+- .shutdown = shutdown_level_ioapic,
+- .enable = enable_level_ioapic,
+- .disable = disable_level_ioapic,
+- .ack = mask_and_ack_level_ioapic,
+- .end = end_level_ioapic,
+-#ifdef CONFIG_SMP
+- .set_affinity = set_ioapic_affinity,
+-#endif
+- .retrigger = ioapic_retrigger,
+-};
+
+ static inline void init_IO_APIC_traps(void)
+ {
+@@ -2130,12 +2080,7 @@ static inline void init_IO_APIC_traps(vo
+ */
+ for (irq = 0; irq < NR_IRQS ; irq++) {
+ int tmp = irq;
+- if (use_pci_vector()) {
+- if (!platform_legacy_irq(tmp))
+- if ((tmp = vector_to_irq(tmp)) == -1)
+- continue;
+- }
+- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
++ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
+ /*
+ * Hmm.. We don't have an entry for this,
+ * so default to an old-fashioned 8259
+@@ -2145,20 +2090,21 @@ static inline void init_IO_APIC_traps(vo
+ make_8259A_irq(irq);
+ else
+ /* Strange. Oh, well.. */
+- irq_desc[irq].chip = &no_irq_type;
++ irq_desc[irq].chip = &no_irq_chip;
+ }
+ }
+ }
+
+-static void enable_lapic_irq (unsigned int irq)
+-{
+- unsigned long v;
++/*
++ * The local APIC irq-chip implementation:
++ */
+
+- v = apic_read(APIC_LVT0);
+- apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
++static void ack_apic(unsigned int irq)
++{
++ ack_APIC_irq();
+ }
+
+-static void disable_lapic_irq (unsigned int irq)
++static void mask_lapic_irq (unsigned int irq)
+ {
+ unsigned long v;
+
+@@ -2166,21 +2112,19 @@ static void disable_lapic_irq (unsigned
+ apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+ }
+
+-static void ack_lapic_irq (unsigned int irq)
++static void unmask_lapic_irq (unsigned int irq)
+ {
+- ack_APIC_irq();
+-}
++ unsigned long v;
+
+-static void end_lapic_irq (unsigned int i) { /* nothing */ }
++ v = apic_read(APIC_LVT0);
++ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
++}
+
+-static struct hw_interrupt_type lapic_irq_type __read_mostly = {
+- .typename = "local-APIC-edge",
+- .startup = NULL, /* startup_irq() not used for IRQ0 */
+- .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
+- .enable = enable_lapic_irq,
+- .disable = disable_lapic_irq,
+- .ack = ack_lapic_irq,
+- .end = end_lapic_irq
++static struct irq_chip lapic_chip __read_mostly = {
++ .name = "local-APIC-edge",
++ .mask = mask_lapic_irq,
++ .unmask = unmask_lapic_irq,
++ .eoi = ack_apic,
+ };
+
+ static void setup_nmi (void)
+@@ -2213,17 +2157,13 @@ static inline void unlock_ExtINT_logic(v
+ int apic, pin, i;
+ struct IO_APIC_route_entry entry0, entry1;
+ unsigned char save_control, save_freq_select;
+- unsigned long flags;
+
+ pin = find_isa_irq_pin(8, mp_INT);
+ apic = find_isa_irq_apic(8, mp_INT);
+ if (pin == -1)
+ return;
+
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+- *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ entry0 = ioapic_read_entry(apic, pin);
+ clear_IO_APIC_pin(apic, pin);
+
+ memset(&entry1, 0, sizeof(entry1));
+@@ -2236,10 +2176,7 @@ static inline void unlock_ExtINT_logic(v
+ entry1.trigger = 0;
+ entry1.vector = 0;
+
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
+- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_write_entry(apic, pin, entry1);
+
+ save_control = CMOS_READ(RTC_CONTROL);
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+@@ -2258,10 +2195,7 @@ static inline void unlock_ExtINT_logic(v
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ clear_IO_APIC_pin(apic, pin);
+
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
+- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_write_entry(apic, pin, entry0);
+ }
+
+ int timer_uses_ioapic_pin_0;
+@@ -2361,7 +2295,8 @@ static inline void check_timer(void)
+ printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
+
+ disable_8259A_irq(0);
+- irq_desc[0].chip = &lapic_irq_type;
++ set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq,
++ "fasteio");
+ apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
+ enable_8259A_irq(0);
+
+@@ -2461,17 +2396,12 @@ static int ioapic_suspend(struct sys_dev
+ {
+ struct IO_APIC_route_entry *entry;
+ struct sysfs_ioapic_data *data;
+- unsigned long flags;
+ int i;
+
+ data = container_of(dev, struct sysfs_ioapic_data, dev);
+ entry = data->entry;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
+- *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
+- *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
+- }
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++)
++ entry[i] = ioapic_read_entry(dev->id, i);
+
+ return 0;
+ }
+@@ -2493,11 +2423,9 @@ static int ioapic_resume(struct sys_devi
+ reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
+ io_apic_write(dev->id, 0, reg_00.raw);
+ }
+- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
+- io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
+- io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
+- }
+ spin_unlock_irqrestore(&ioapic_lock, flags);
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++)
++ ioapic_write_entry(dev->id, i, entry[i]);
+
+ return 0;
+ }
+@@ -2543,6 +2471,240 @@ static int __init ioapic_init_sysfs(void
+
+ device_initcall(ioapic_init_sysfs);
+
++/*
++ * Dynamic irq allocate and deallocation
++ */
++int create_irq(void)
++{
++ /* Allocate an unused irq */
++ int irq, new, vector;
++ unsigned long flags;
++
++ irq = -ENOSPC;
++ spin_lock_irqsave(&vector_lock, flags);
++ for (new = (NR_IRQS - 1); new >= 0; new--) {
++ if (platform_legacy_irq(new))
++ continue;
++ if (irq_vector[new] != 0)
++ continue;
++ vector = __assign_irq_vector(new);
++ if (likely(vector > 0))
++ irq = new;
++ break;
++ }
++ spin_unlock_irqrestore(&vector_lock, flags);
++
++ if (irq >= 0) {
++ set_intr_gate(vector, interrupt[irq]);
++ dynamic_irq_init(irq);
++ }
++ return irq;
++}
++
++void destroy_irq(unsigned int irq)
++{
++ unsigned long flags;
++
++ dynamic_irq_cleanup(irq);
++
++ spin_lock_irqsave(&vector_lock, flags);
++ irq_vector[irq] = 0;
++ spin_unlock_irqrestore(&vector_lock, flags);
++}
++
++/*
++ * MSI mesage composition
++ */
++#ifdef CONFIG_PCI_MSI
++static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
++{
++ int vector;
++ unsigned dest;
++
++ vector = assign_irq_vector(irq);
++ if (vector >= 0) {
++ dest = cpu_mask_to_apicid(TARGET_CPUS);
++
++ msg->address_hi = MSI_ADDR_BASE_HI;
++ msg->address_lo =
++ MSI_ADDR_BASE_LO |
++ ((INT_DEST_MODE == 0) ?
++ MSI_ADDR_DEST_MODE_PHYSICAL:
++ MSI_ADDR_DEST_MODE_LOGICAL) |
++ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
++ MSI_ADDR_REDIRECTION_CPU:
++ MSI_ADDR_REDIRECTION_LOWPRI) |
++ MSI_ADDR_DEST_ID(dest);
++
++ msg->data =
++ MSI_DATA_TRIGGER_EDGE |
++ MSI_DATA_LEVEL_ASSERT |
++ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
++ MSI_DATA_DELIVERY_FIXED:
++ MSI_DATA_DELIVERY_LOWPRI) |
++ MSI_DATA_VECTOR(vector);
++ }
++ return vector;
++}
++
++#ifdef CONFIG_SMP
++static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
++{
++ struct msi_msg msg;
++ unsigned int dest;
++ cpumask_t tmp;
++ int vector;
++
++ cpus_and(tmp, mask, cpu_online_map);
++ if (cpus_empty(tmp))
++ tmp = TARGET_CPUS;
++
++ vector = assign_irq_vector(irq);
++ if (vector < 0)
++ return;
++
++ dest = cpu_mask_to_apicid(mask);
++
++ read_msi_msg(irq, &msg);
++
++ msg.data &= ~MSI_DATA_VECTOR_MASK;
++ msg.data |= MSI_DATA_VECTOR(vector);
++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
++ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
++
++ write_msi_msg(irq, &msg);
++ set_native_irq_info(irq, mask);
++}
++#endif /* CONFIG_SMP */
++
++/*
++ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
++ * which implement the MSI or MSI-X Capability Structure.
++ */
++static struct irq_chip msi_chip = {
++ .name = "PCI-MSI",
++ .unmask = unmask_msi_irq,
++ .mask = mask_msi_irq,
++ .ack = ack_ioapic_irq,
++#ifdef CONFIG_SMP
++ .set_affinity = set_msi_irq_affinity,
++#endif
++ .retrigger = ioapic_retrigger_irq,
++};
++
++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
++{
++ struct msi_msg msg;
++ int ret;
++ ret = msi_compose_msg(dev, irq, &msg);
++ if (ret < 0)
++ return ret;
++
++ write_msi_msg(irq, &msg);
++
++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
++ "edge");
++
++ return 0;
++}
++
++void arch_teardown_msi_irq(unsigned int irq)
++{
++ return;
++}
++
++#endif /* CONFIG_PCI_MSI */
++
++/*
++ * Hypertransport interrupt support
++ */
++#ifdef CONFIG_HT_IRQ
++
++#ifdef CONFIG_SMP
++
++static void target_ht_irq(unsigned int irq, unsigned int dest)
++{
++ u32 low, high;
++ low = read_ht_irq_low(irq);
++ high = read_ht_irq_high(irq);
++
++ low &= ~(HT_IRQ_LOW_DEST_ID_MASK);
++ high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
++
++ low |= HT_IRQ_LOW_DEST_ID(dest);
++ high |= HT_IRQ_HIGH_DEST_ID(dest);
++
++ write_ht_irq_low(irq, low);
++ write_ht_irq_high(irq, high);
++}
++
++static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
++{
++ unsigned int dest;
++ cpumask_t tmp;
++
++ cpus_and(tmp, mask, cpu_online_map);
++ if (cpus_empty(tmp))
++ tmp = TARGET_CPUS;
++
++ cpus_and(mask, tmp, CPU_MASK_ALL);
++
++ dest = cpu_mask_to_apicid(mask);
++
++ target_ht_irq(irq, dest);
++ set_native_irq_info(irq, mask);
++}
++#endif
++
++static struct irq_chip ht_irq_chip = {
++ .name = "PCI-HT",
++ .mask = mask_ht_irq,
++ .unmask = unmask_ht_irq,
++ .ack = ack_ioapic_irq,
++#ifdef CONFIG_SMP
++ .set_affinity = set_ht_irq_affinity,
++#endif
++ .retrigger = ioapic_retrigger_irq,
++};
++
++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
++{
++ int vector;
++
++ vector = assign_irq_vector(irq);
++ if (vector >= 0) {
++ u32 low, high;
++ unsigned dest;
++ cpumask_t tmp;
++
++ cpus_clear(tmp);
++ cpu_set(vector >> 8, tmp);
++ dest = cpu_mask_to_apicid(tmp);
++
++ high = HT_IRQ_HIGH_DEST_ID(dest);
++
++ low = HT_IRQ_LOW_BASE |
++ HT_IRQ_LOW_DEST_ID(dest) |
++ HT_IRQ_LOW_VECTOR(vector) |
++ ((INT_DEST_MODE == 0) ?
++ HT_IRQ_LOW_DM_PHYSICAL :
++ HT_IRQ_LOW_DM_LOGICAL) |
++ HT_IRQ_LOW_RQEOI_EDGE |
++ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
++ HT_IRQ_LOW_MT_FIXED :
++ HT_IRQ_LOW_MT_ARBITRATED) |
++ HT_IRQ_LOW_IRQ_MASKED;
++
++ write_ht_irq_low(irq, low);
++ write_ht_irq_high(irq, high);
++
++ set_irq_chip_and_handler_name(irq, &ht_irq_chip,
++ handle_edge_irq, "edge");
++ }
++ return vector;
++}
++#endif /* CONFIG_HT_IRQ */
++
+ /* --------------------------------------------------------------------------
+ ACPI-based IOAPIC Configuration
+ -------------------------------------------------------------------------- */
+@@ -2694,13 +2856,34 @@ int io_apic_set_pci_routing (int ioapic,
+ if (!ioapic && (irq < 16))
+ disable_8259A_irq(irq);
+
++ ioapic_write_entry(ioapic, pin, entry);
+ spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
+- io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
++ set_native_irq_info(irq, TARGET_CPUS);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ return 0;
+ }
+
+ #endif /* CONFIG_ACPI */
++
++static int __init parse_disable_timer_pin_1(char *arg)
++{
++ disable_timer_pin_1 = 1;
++ return 0;
++}
++early_param("disable_timer_pin_1", parse_disable_timer_pin_1);
++
++static int __init parse_enable_timer_pin_1(char *arg)
++{
++ disable_timer_pin_1 = -1;
++ return 0;
++}
++early_param("enable_timer_pin_1", parse_enable_timer_pin_1);
++
++static int __init parse_noapic(char *arg)
++{
++ /* disable IO-APIC */
++ disable_ioapic_setup();
++ return 0;
++}
++early_param("noapic", parse_noapic);
+diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
+index 5fe547c..3201d42 100644
+--- a/arch/i386/kernel/irq.c
++++ b/arch/i386/kernel/irq.c
+@@ -53,8 +53,10 @@ static union irq_ctx *softirq_ctx[NR_CPU
+ */
+ fastcall unsigned int do_IRQ(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ /* high bit used in ret_from_ code */
+ int irq = ~regs->orig_eax;
++ struct irq_desc *desc = irq_desc + irq;
+ #ifdef CONFIG_4KSTACKS
+ union irq_ctx *curctx, *irqctx;
+ u32 *isp;
+@@ -66,6 +68,7 @@ fastcall unsigned int do_IRQ(struct pt_r
+ BUG();
+ }
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+ #ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* Debugging check for stack overflow: is there less than 1KB free? */
+@@ -110,19 +113,20 @@ fastcall unsigned int do_IRQ(struct pt_r
+ (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
+
+ asm volatile(
+- " xchgl %%ebx,%%esp \n"
+- " call __do_IRQ \n"
++ " xchgl %%ebx,%%esp \n"
++ " call *%%edi \n"
+ " movl %%ebx,%%esp \n"
+ : "=a" (arg1), "=d" (arg2), "=b" (ebx)
+- : "0" (irq), "1" (regs), "2" (isp)
+- : "memory", "cc", "ecx"
++ : "0" (irq), "1" (desc), "2" (isp),
++ "D" (desc->handle_irq)
++ : "memory", "cc"
+ );
+ } else
+ #endif
+- __do_IRQ(irq, regs);
++ desc->handle_irq(irq, desc);
+
+ irq_exit();
+-
++ set_irq_regs(old_regs);
+ return 1;
+ }
+
+@@ -253,7 +257,8 @@ int show_interrupts(struct seq_file *p,
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ #endif
+- seq_printf(p, " %14s", irq_desc[i].chip->typename);
++ seq_printf(p, " %8s", irq_desc[i].chip->name);
++ seq_printf(p, "-%-8s", irq_desc[i].name);
+ seq_printf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
+index afe6505..d98e44b 100644
+--- a/arch/i386/kernel/kprobes.c
++++ b/arch/i386/kernel/kprobes.c
+@@ -230,20 +230,20 @@ void __kprobes arch_prepare_kretprobe(st
+ struct pt_regs *regs)
+ {
+ unsigned long *sara = (unsigned long *)®s->esp;
+- struct kretprobe_instance *ri;
+
+- if ((ri = get_free_rp_inst(rp)) != NULL) {
+- ri->rp = rp;
+- ri->task = current;
++ 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;
+
+ /* Replace the return addr with trampoline addr */
+ *sara = (unsigned long) &kretprobe_trampoline;
+-
+- add_rp_inst(ri);
+- } else {
+- rp->nmissed++;
+- }
++ add_rp_inst(ri);
++ } else {
++ rp->nmissed++;
++ }
+ }
+
+ /*
+@@ -359,7 +359,7 @@ no_kprobe:
+ void __kprobes kretprobe_trampoline_holder(void)
+ {
+ asm volatile ( ".global kretprobe_trampoline\n"
+- "kretprobe_trampoline: \n"
++ "kretprobe_trampoline: \n"
+ " pushf\n"
+ /* skip cs, eip, orig_eax, es, ds */
+ " subl $20, %esp\n"
+@@ -395,14 +395,15 @@ no_kprobe:
+ */
+ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
+ {
+- struct kretprobe_instance *ri = NULL;
+- struct hlist_head *head;
+- struct hlist_node *node, *tmp;
++ struct kretprobe_instance *ri = NULL;
++ struct hlist_head *head, empty_rp;
++ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+
++ INIT_HLIST_HEAD(&empty_rp);
+ spin_lock_irqsave(&kretprobe_lock, flags);
+- head = kretprobe_inst_table_head(current);
++ head = kretprobe_inst_table_head(current);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+@@ -413,14 +414,14 @@ fastcall void *__kprobes trampoline_hand
+ * 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
++ * 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)
++ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+- continue;
++ continue;
+
+ if (ri->rp && ri->rp->handler){
+ __get_cpu_var(current_kprobe) = &ri->rp->kp;
+@@ -429,7 +430,7 @@ fastcall void *__kprobes trampoline_hand
+ }
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+- recycle_rp_inst(ri);
++ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+@@ -444,6 +445,10 @@ fastcall void *__kprobes trampoline_hand
+
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+
++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++ hlist_del(&ri->hlist);
++ kfree(ri);
++ }
+ return (void*)orig_ret_address;
+ }
+
+diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
+index 983f957..445211e 100644
+--- a/arch/i386/kernel/ldt.c
++++ b/arch/i386/kernel/ldt.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/kernel/ldt.c
++ * linux/arch/i386/kernel/ldt.c
+ *
+ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+ * Copyright (C) 1999 Ingo Molnar <mingo at redhat.com>
+diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c
+index 6b1ae6b..91966ba 100644
+--- a/arch/i386/kernel/machine_kexec.c
++++ b/arch/i386/kernel/machine_kexec.c
+@@ -9,6 +9,7 @@
+ #include <linux/mm.h>
+ #include <linux/kexec.h>
+ #include <linux/delay.h>
++#include <linux/init.h>
+ #include <asm/pgtable.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
+@@ -20,70 +21,13 @@
+ #include <asm/system.h>
+
+ #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);
+-}
++static u32 kexec_pgd[1024] PAGE_ALIGNED;
++#ifdef CONFIG_X86_PAE
++static u32 kexec_pmd0[1024] PAGE_ALIGNED;
++static u32 kexec_pmd1[1024] PAGE_ALIGNED;
+ #endif
++static u32 kexec_pte0[1024] PAGE_ALIGNED;
++static u32 kexec_pte1[1024] PAGE_ALIGNED;
+
+ static void set_idt(void *newidt, __u16 limit)
+ {
+@@ -127,16 +71,6 @@ static void load_segments(void)
+ #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;
+-
+-extern const unsigned char relocate_new_kernel[];
+-extern void relocate_new_kernel_end(void);
+-extern const unsigned int relocate_new_kernel_size;
+-
+ /*
+ * A architecture hook called to validate the
+ * proposed image and prepare the control pages
+@@ -169,25 +103,29 @@ void machine_kexec_cleanup(struct kimage
+ */
+ NORET_TYPE void machine_kexec(struct kimage *image)
+ {
+- unsigned long page_list;
+- unsigned long reboot_code_buffer;
+-
+- relocate_new_kernel_t rnk;
++ unsigned long page_list[PAGES_NR];
++ void *control_page;
+
+ /* 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);
++ control_page = page_address(image->control_code_page);
++ memcpy(control_page, relocate_kernel, PAGE_SIZE);
++
++ page_list[PA_CONTROL_PAGE] = __pa(control_page);
++ page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
++ page_list[PA_PGD] = __pa(kexec_pgd);
++ page_list[VA_PGD] = (unsigned long)kexec_pgd;
++#ifdef CONFIG_X86_PAE
++ page_list[PA_PMD_0] = __pa(kexec_pmd0);
++ page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
++ page_list[PA_PMD_1] = __pa(kexec_pmd1);
++ page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
++#endif
++ page_list[PA_PTE_0] = __pa(kexec_pte0);
++ page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
++ page_list[PA_PTE_1] = __pa(kexec_pte1);
++ page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
+
+ /* The segment registers are funny things, they have both a
+ * visible and an invisible part. Whenever the visible part is
+@@ -206,6 +144,28 @@ NORET_TYPE void machine_kexec(struct kim
+ 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);
++ relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
++ image->start, cpu_has_pae);
++}
++
++/* crashkernel=size at addr specifies the location to reserve for
++ * a crash kernel. By reserving this memory we guarantee
++ * that linux never sets it up as a DMA target.
++ * Useful for holding code to do something appropriate
++ * after a kernel panic.
++ */
++static int __init parse_crashkernel(char *arg)
++{
++ unsigned long size, base;
++ size = memparse(arg, &arg);
++ if (*arg == '@') {
++ base = memparse(arg+1, &arg);
++ /* FIXME: Do I want a sanity check
++ * to validate the memory range?
++ */
++ crashk_res.start = base;
++ crashk_res.end = base + size - 1;
++ }
++ return 0;
+ }
++early_param("crashkernel", parse_crashkernel);
+diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c
+index cd5456f..eb57a85 100644
+--- a/arch/i386/kernel/mca.c
++++ b/arch/i386/kernel/mca.c
+@@ -42,6 +42,7 @@
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/mca.h>
++#include <linux/kprobes.h>
+ #include <asm/system.h>
+ #include <asm/io.h>
+ #include <linux/proc_fs.h>
+@@ -414,7 +415,8 @@ subsys_initcall(mca_init);
+
+ /*--------------------------------------------------------------------*/
+
+-static void mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
++static __kprobes void
++mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
+ {
+ int slot = mca_dev->slot;
+
+@@ -444,7 +446,7 @@ static void mca_handle_nmi_device(struct
+
+ /*--------------------------------------------------------------------*/
+
+-static int mca_handle_nmi_callback(struct device *dev, void *data)
++static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data)
+ {
+ struct mca_device *mca_dev = to_mca_device(dev);
+ unsigned char pos5;
+@@ -462,7 +464,7 @@ static int mca_handle_nmi_callback(struc
+ return 0;
+ }
+
+-void mca_handle_nmi(void)
++void __kprobes mca_handle_nmi(void)
+ {
+ /* First try - scan the various adapters and see if a specific
+ * adapter was responsible for the error.
+diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
+index 40b44cc..c4d0291 100644
+--- a/arch/i386/kernel/microcode.c
++++ b/arch/i386/kernel/microcode.c
+@@ -2,6 +2,7 @@
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2000-2004 Tigran Aivazian
++ * 2006 Shaohua Li <shaohua.li at intel.com>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+@@ -82,6 +83,9 @@
+ #include <linux/spinlock.h>
+ #include <linux/mm.h>
+ #include <linux/mutex.h>
++#include <linux/cpu.h>
++#include <linux/firmware.h>
++#include <linux/platform_device.h>
+
+ #include <asm/msr.h>
+ #include <asm/uaccess.h>
+@@ -91,9 +95,6 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Mi
+ MODULE_AUTHOR("Tigran Aivazian <tigran at veritas.com>");
+ MODULE_LICENSE("GPL");
+
+-static int verbose;
+-module_param(verbose, int, 0644);
+-
+ #define MICROCODE_VERSION "1.14a"
+
+ #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
+@@ -120,55 +121,40 @@ static DEFINE_SPINLOCK(microcode_update_
+ /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+ static DEFINE_MUTEX(microcode_mutex);
+
+-static void __user *user_buffer; /* user area microcode data buffer */
+-static unsigned int user_buffer_size; /* it's size */
+-
+-typedef enum mc_error_code {
+- MC_SUCCESS = 0,
+- MC_IGNORED = 1,
+- MC_NOTFOUND = 2,
+- MC_MARKED = 3,
+- MC_ALLOCATED = 4,
+-} mc_error_code_t;
+-
+ static struct ucode_cpu_info {
++ int valid;
+ unsigned int sig;
+- unsigned int pf, orig_pf;
++ unsigned int pf;
+ unsigned int rev;
+- unsigned int cksum;
+- mc_error_code_t err;
+ microcode_t *mc;
+ } ucode_cpu_info[NR_CPUS];
+-
+-static int microcode_open (struct inode *unused1, struct file *unused2)
+-{
+- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+-}
+
+-static void collect_cpu_info (void *unused)
++static void collect_cpu_info(int cpu_num)
+ {
+- int cpu_num = smp_processor_id();
+ struct cpuinfo_x86 *c = cpu_data + cpu_num;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ unsigned int val[2];
+
+- uci->sig = uci->pf = uci->rev = uci->cksum = 0;
+- uci->err = MC_NOTFOUND;
++ /* We should bind the task to the CPU */
++ BUG_ON(raw_smp_processor_id() != cpu_num);
++ uci->pf = uci->rev = 0;
+ uci->mc = NULL;
++ uci->valid = 1;
+
+ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+ cpu_has(c, X86_FEATURE_IA64)) {
+- printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
++ printk(KERN_ERR "microcode: CPU%d not a capable Intel "
++ "processor\n", cpu_num);
++ uci->valid = 0;
+ return;
+- } else {
+- uci->sig = cpuid_eax(0x00000001);
++ }
+
+- if ((c->x86_model >= 5) || (c->x86 > 6)) {
+- /* get processor flags from MSR 0x17 */
+- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+- uci->pf = 1 << ((val[1] >> 18) & 7);
+- }
+- uci->orig_pf = uci->pf;
++ uci->sig = cpuid_eax(0x00000001);
++
++ if ((c->x86_model >= 5) || (c->x86 > 6)) {
++ /* get processor flags from MSR 0x17 */
++ rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
++ uci->pf = 1 << ((val[1] >> 18) & 7);
+ }
+
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+@@ -180,218 +166,159 @@ static void collect_cpu_info (void *unus
+ uci->sig, uci->pf, uci->rev);
+ }
+
+-static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_header, int sig, int pf, int cksum)
++static inline int microcode_update_match(int cpu_num,
++ microcode_header_t *mc_header, int sig, int pf)
+ {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+
+- pr_debug("Microcode Found.\n");
+- pr_debug(" Header Revision 0x%x\n", mc_header->hdrver);
+- pr_debug(" Loader Revision 0x%x\n", mc_header->ldrver);
+- pr_debug(" Revision 0x%x \n", mc_header->rev);
+- pr_debug(" Date %x/%x/%x\n",
+- ((mc_header->date >> 24 ) & 0xff),
+- ((mc_header->date >> 16 ) & 0xff),
+- (mc_header->date & 0xFFFF));
+- pr_debug(" Signature 0x%x\n", sig);
+- pr_debug(" Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x\n",
+- ((sig >> 12) & 0x3),
+- ((sig >> 8) & 0xf),
+- ((sig >> 4) & 0xf),
+- ((sig & 0xf)));
+- pr_debug(" Processor Flags 0x%x\n", pf);
+- pr_debug(" Checksum 0x%x\n", cksum);
+-
+- if (mc_header->rev < uci->rev) {
+- if (uci->err == MC_NOTFOUND) {
+- uci->err = MC_IGNORED;
+- uci->cksum = mc_header->rev;
+- } else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev)
+- uci->cksum = mc_header->rev;
+- } else if (mc_header->rev == uci->rev) {
+- if (uci->err < MC_MARKED) {
+- /* notify the caller of success on this cpu */
+- uci->err = MC_SUCCESS;
+- }
+- } else if (uci->err != MC_ALLOCATED || mc_header->rev > uci->mc->hdr.rev) {
+- pr_debug("microcode: CPU%d found a matching microcode update with "
+- " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
+- uci->cksum = cksum;
+- uci->pf = pf; /* keep the original mc pf for cksum calculation */
+- uci->err = MC_MARKED; /* found the match */
+- for_each_online_cpu(cpu_num) {
+- if (ucode_cpu_info + cpu_num != uci
+- && ucode_cpu_info[cpu_num].mc == uci->mc) {
+- uci->mc = NULL;
+- break;
+- }
+- }
+- if (uci->mc != NULL) {
+- vfree(uci->mc);
+- uci->mc = NULL;
+- }
+- }
+- return;
++ if (!sigmatch(sig, uci->sig, pf, uci->pf)
++ || mc_header->rev <= uci->rev)
++ return 0;
++ return 1;
+ }
+
+-static int find_matching_ucodes (void)
++static int microcode_sanity_check(void *mc)
+ {
+- int cursor = 0;
+- int error = 0;
+-
+- while (cursor + MC_HEADER_SIZE < user_buffer_size) {
+- microcode_header_t mc_header;
+- void *newmc = NULL;
+- int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size;
++ microcode_header_t *mc_header = mc;
++ struct extended_sigtable *ext_header = NULL;
++ struct extended_signature *ext_sig;
++ unsigned long total_size, data_size, ext_table_size;
++ int sum, orig_sum, ext_sigcount = 0, i;
++
++ total_size = get_totalsize(mc_header);
++ data_size = get_datasize(mc_header);
++ if (data_size + MC_HEADER_SIZE > total_size) {
++ printk(KERN_ERR "microcode: error! "
++ "Bad data size in microcode data file\n");
++ return -EINVAL;
++ }
+
+- if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) {
+- printk(KERN_ERR "microcode: error! Can not read user data\n");
+- error = -EFAULT;
+- goto out;
++ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
++ printk(KERN_ERR "microcode: error! "
++ "Unknown microcode update format\n");
++ return -EINVAL;
++ }
++ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
++ if (ext_table_size) {
++ if ((ext_table_size < EXT_HEADER_SIZE)
++ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
++ printk(KERN_ERR "microcode: error! "
++ "Small exttable size in microcode data file\n");
++ return -EINVAL;
+ }
+-
+- total_size = get_totalsize(&mc_header);
+- if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
+- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+- error = -EINVAL;
+- goto out;
++ ext_header = mc + MC_HEADER_SIZE + data_size;
++ if (ext_table_size != exttable_size(ext_header)) {
++ printk(KERN_ERR "microcode: error! "
++ "Bad exttable size in microcode data file\n");
++ return -EFAULT;
+ }
++ ext_sigcount = ext_header->count;
++ }
+
+- data_size = get_datasize(&mc_header);
+- if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) {
+- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+- error = -EINVAL;
+- goto out;
++ /* check extended table checksum */
++ if (ext_table_size) {
++ int ext_table_sum = 0;
++ int *ext_tablep = (int *)ext_header;
++
++ i = ext_table_size / DWSIZE;
++ while (i--)
++ ext_table_sum += ext_tablep[i];
++ if (ext_table_sum) {
++ printk(KERN_WARNING "microcode: aborting, "
++ "bad extended signature table checksum\n");
++ return -EINVAL;
+ }
++ }
+
+- if (mc_header.ldrver != 1 || mc_header.hdrver != 1) {
+- printk(KERN_ERR "microcode: error! Unknown microcode update format\n");
+- error = -EINVAL;
+- goto out;
++ /* calculate the checksum */
++ orig_sum = 0;
++ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
++ while (i--)
++ orig_sum += ((int *)mc)[i];
++ if (orig_sum) {
++ printk(KERN_ERR "microcode: aborting, bad checksum\n");
++ return -EINVAL;
++ }
++ if (!ext_table_size)
++ return 0;
++ /* check extended signature checksum */
++ for (i = 0; i < ext_sigcount; i++) {
++ ext_sig = (struct extended_signature *)((void *)ext_header
++ + EXT_HEADER_SIZE + EXT_SIGNATURE_SIZE * i);
++ sum = orig_sum
++ - (mc_header->sig + mc_header->pf + mc_header->cksum)
++ + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
++ if (sum) {
++ printk(KERN_ERR "microcode: aborting, bad checksum\n");
++ return -EINVAL;
+ }
++ }
++ return 0;
++}
+
+- for_each_online_cpu(cpu_num) {
+- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+-
+- if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf))
+- mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum);
+- }
++/*
++ * return 0 - no update found
++ * return 1 - found update
++ * return < 0 - error
++ */
++static int get_maching_microcode(void *mc, int cpu)
++{
++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
++ microcode_header_t *mc_header = mc;
++ struct extended_sigtable *ext_header;
++ unsigned long total_size = get_totalsize(mc_header);
++ int ext_sigcount, i;
++ struct extended_signature *ext_sig;
++ void *new_mc;
++
++ if (microcode_update_match(cpu, mc_header,
++ mc_header->sig, mc_header->pf))
++ goto find;
++
++ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
++ return 0;
++
++ ext_header = (struct extended_sigtable *)(mc +
++ get_datasize(mc_header) + MC_HEADER_SIZE);
++ ext_sigcount = ext_header->count;
++ ext_sig = (struct extended_signature *)((void *)ext_header
++ + EXT_HEADER_SIZE);
++ for (i = 0; i < ext_sigcount; i++) {
++ if (microcode_update_match(cpu, mc_header,
++ ext_sig->sig, ext_sig->pf))
++ goto find;
++ ext_sig++;
++ }
++ return 0;
++find:
++ pr_debug("microcode: CPU %d found a matching microcode update with"
++ " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
++ new_mc = vmalloc(total_size);
++ if (!new_mc) {
++ printk(KERN_ERR "microcode: error! Can not allocate memory\n");
++ return -ENOMEM;
++ }
+
+- ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+- if (ext_table_size) {
+- struct extended_sigtable ext_header;
+- struct extended_signature ext_sig;
+- int ext_sigcount;
++ /* free previous update file */
++ vfree(uci->mc);
+
+- if ((ext_table_size < EXT_HEADER_SIZE)
+- || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+- error = -EINVAL;
+- goto out;
+- }
+- if (copy_from_user(&ext_header, user_buffer + cursor
+- + MC_HEADER_SIZE + data_size, EXT_HEADER_SIZE)) {
+- printk(KERN_ERR "microcode: error! Can not read user data\n");
+- error = -EFAULT;
+- goto out;
+- }
+- if (ext_table_size != exttable_size(&ext_header)) {
+- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+- error = -EFAULT;
+- goto out;
+- }
+-
+- ext_sigcount = ext_header.count;
+-
+- for (i = 0; i < ext_sigcount; i++) {
+- if (copy_from_user(&ext_sig, user_buffer + cursor + MC_HEADER_SIZE + data_size + EXT_HEADER_SIZE
+- + EXT_SIGNATURE_SIZE * i, EXT_SIGNATURE_SIZE)) {
+- printk(KERN_ERR "microcode: error! Can not read user data\n");
+- error = -EFAULT;
+- goto out;
+- }
+- for_each_online_cpu(cpu_num) {
+- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+-
+- if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) {
+- mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum);
+- }
+- }
+- }
+- }
+- /* now check if any cpu has matched */
+- allocated_flag = 0;
+- sum = 0;
+- for_each_online_cpu(cpu_num) {
+- if (ucode_cpu_info[cpu_num].err == MC_MARKED) {
+- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+- if (!allocated_flag) {
+- allocated_flag = 1;
+- newmc = vmalloc(total_size);
+- if (!newmc) {
+- printk(KERN_ERR "microcode: error! Can not allocate memory\n");
+- error = -ENOMEM;
+- goto out;
+- }
+- if (copy_from_user(newmc + MC_HEADER_SIZE,
+- user_buffer + cursor + MC_HEADER_SIZE,
+- total_size - MC_HEADER_SIZE)) {
+- printk(KERN_ERR "microcode: error! Can not read user data\n");
+- vfree(newmc);
+- error = -EFAULT;
+- goto out;
+- }
+- memcpy(newmc, &mc_header, MC_HEADER_SIZE);
+- /* check extended table checksum */
+- if (ext_table_size) {
+- int ext_table_sum = 0;
+- int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size);
+- i = ext_table_size / DWSIZE;
+- while (i--) ext_table_sum += ext_tablep[i];
+- if (ext_table_sum) {
+- printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n");
+- vfree(newmc);
+- error = -EINVAL;
+- goto out;
+- }
+- }
+-
+- /* calculate the checksum */
+- i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+- while (i--) sum += ((int *)newmc)[i];
+- sum -= (mc_header.sig + mc_header.pf + mc_header.cksum);
+- }
+- ucode_cpu_info[cpu_num].mc = newmc;
+- ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */
+- if (sum + uci->sig + uci->pf + uci->cksum != 0) {
+- printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num);
+- error = -EINVAL;
+- goto out;
+- }
+- }
+- }
+- cursor += total_size; /* goto the next update patch */
+- } /* end of while */
+-out:
+- return error;
++ memcpy(new_mc, mc, total_size);
++ uci->mc = new_mc;
++ return 1;
+ }
+
+-static void do_update_one (void * unused)
++static void apply_microcode(int cpu)
+ {
+ unsigned long flags;
+ unsigned int val[2];
+- int cpu_num = smp_processor_id();
++ int cpu_num = raw_smp_processor_id();
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+
+- if (uci->mc == NULL) {
+- if (verbose) {
+- if (uci->err == MC_SUCCESS)
+- printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n",
+- cpu_num, uci->rev);
+- else
+- printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num);
+- }
++ /* We should bind the task to the CPU */
++ BUG_ON(cpu_num != cpu);
++
++ if (uci->mc == NULL)
+ return;
+- }
+
+ /* serialize access to the physical write to MSR 0x79 */
+ spin_lock_irqsave(µcode_update_lock, flags);
+@@ -408,68 +335,107 @@ static void do_update_one (void * unused
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+- /* notify the caller of success on this cpu */
+- uci->err = MC_SUCCESS;
+ spin_unlock_irqrestore(µcode_update_lock, flags);
+- printk(KERN_INFO "microcode: CPU%d updated from revision "
++ if (val[1] != uci->mc->hdr.rev) {
++ printk(KERN_ERR "microcode: CPU%d updated from revision "
++ "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
++ return;
++ }
++ pr_debug("microcode: CPU%d updated from revision "
+ "0x%x to 0x%x, date = %08x \n",
+ cpu_num, uci->rev, val[1], uci->mc->hdr.date);
+- return;
++ uci->rev = val[1];
+ }
+
+-static int do_microcode_update (void)
+-{
+- int i, error;
++#ifdef CONFIG_MICROCODE_OLD_INTERFACE
++static void __user *user_buffer; /* user area microcode data buffer */
++static unsigned int user_buffer_size; /* it's size */
+
+- if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) {
+- printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
+- error = -EIO;
+- goto out;
++static long get_next_ucode(void **mc, long offset)
++{
++ microcode_header_t mc_header;
++ unsigned long total_size;
++
++ /* No more data */
++ if (offset >= user_buffer_size)
++ return 0;
++ if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
++ printk(KERN_ERR "microcode: error! Can not read user data\n");
++ return -EFAULT;
+ }
+-
+- if ((error = find_matching_ucodes())) {
+- printk(KERN_ERR "microcode: Error in the microcode data\n");
+- goto out_free;
++ total_size = get_totalsize(&mc_header);
++ if (offset + total_size > user_buffer_size) {
++ printk(KERN_ERR "microcode: error! Bad total size in microcode "
++ "data file\n");
++ return -EINVAL;
+ }
+-
+- if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) {
+- printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
+- error = -EIO;
++ *mc = vmalloc(total_size);
++ if (!*mc)
++ return -ENOMEM;
++ if (copy_from_user(*mc, user_buffer + offset, total_size)) {
++ printk(KERN_ERR "microcode: error! Can not read user data\n");
++ vfree(*mc);
++ return -EFAULT;
+ }
++ return offset + total_size;
++}
++
++static int do_microcode_update (void)
++{
++ long cursor = 0;
++ int error = 0;
++ void *new_mc;
++ int cpu;
++ cpumask_t old;
++
++ old = current->cpus_allowed;
+
+-out_free:
+- for_each_online_cpu(i) {
+- if (ucode_cpu_info[i].mc) {
+- int j;
+- void *tmp = ucode_cpu_info[i].mc;
+- vfree(tmp);
+- for_each_online_cpu(j) {
+- if (ucode_cpu_info[j].mc == tmp)
+- ucode_cpu_info[j].mc = NULL;
+- }
++ while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
++ error = microcode_sanity_check(new_mc);
++ if (error)
++ goto out;
++ /*
++ * It's possible the data file has multiple matching ucode,
++ * lets keep searching till the latest version
++ */
++ for_each_online_cpu(cpu) {
++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
++
++ if (!uci->valid)
++ continue;
++ set_cpus_allowed(current, cpumask_of_cpu(cpu));
++ error = get_maching_microcode(new_mc, cpu);
++ if (error < 0)
++ goto out;
++ if (error == 1)
++ apply_microcode(cpu);
+ }
+- if (ucode_cpu_info[i].err == MC_IGNORED && verbose)
+- printk(KERN_WARNING "microcode: CPU%d not 'upgrading' to earlier revision"
+- " 0x%x (current=0x%x)\n", i, ucode_cpu_info[i].cksum, ucode_cpu_info[i].rev);
++ vfree(new_mc);
+ }
+ out:
++ if (cursor > 0)
++ vfree(new_mc);
++ if (cursor < 0)
++ error = cursor;
++ set_cpus_allowed(current, old);
+ return error;
+ }
+
++static int microcode_open (struct inode *unused1, struct file *unused2)
++{
++ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
++}
++
+ static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
+ {
+ ssize_t ret;
+
+- if (len < DEFAULT_UCODE_TOTALSIZE) {
+- printk(KERN_ERR "microcode: not enough data\n");
+- return -EINVAL;
+- }
+-
+ if ((len >> PAGE_SHIFT) > num_physpages) {
+ printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
+ return -EINVAL;
+ }
+
++ lock_cpu_hotplug();
+ mutex_lock(µcode_mutex);
+
+ user_buffer = (void __user *) buf;
+@@ -480,6 +446,7 @@ static ssize_t microcode_write (struct f
+ ret = (ssize_t)len;
+
+ mutex_unlock(µcode_mutex);
++ unlock_cpu_hotplug();
+
+ return ret;
+ }
+@@ -496,7 +463,7 @@ static struct miscdevice microcode_dev =
+ .fops = µcode_fops,
+ };
+
+-static int __init microcode_init (void)
++static int __init microcode_dev_init (void)
+ {
+ int error;
+
+@@ -508,6 +475,284 @@ static int __init microcode_init (void)
+ return error;
+ }
+
++ return 0;
++}
++
++static void __exit microcode_dev_exit (void)
++{
++ misc_deregister(µcode_dev);
++}
++
++MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
++#else
++#define microcode_dev_init() 0
++#define microcode_dev_exit() do { } while(0)
++#endif
++
++static long get_next_ucode_from_buffer(void **mc, void *buf,
++ unsigned long size, long offset)
++{
++ microcode_header_t *mc_header;
++ unsigned long total_size;
++
++ /* No more data */
++ if (offset >= size)
++ return 0;
++ mc_header = (microcode_header_t *)(buf + offset);
++ total_size = get_totalsize(mc_header);
++
++ if (offset + total_size > size) {
++ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
++ return -EINVAL;
++ }
++
++ *mc = vmalloc(total_size);
++ if (!*mc) {
++ printk(KERN_ERR "microcode: error! Can not allocate memory\n");
++ return -ENOMEM;
++ }
++ memcpy(*mc, buf + offset, total_size);
++ return offset + total_size;
++}
++
++/* fake device for request_firmware */
++static struct platform_device *microcode_pdev;
++
++static int cpu_request_microcode(int cpu)
++{
++ char name[30];
++ struct cpuinfo_x86 *c = cpu_data + cpu;
++ const struct firmware *firmware;
++ void *buf;
++ unsigned long size;
++ long offset = 0;
++ int error;
++ void *mc;
++
++ /* We should bind the task to the CPU */
++ BUG_ON(cpu != raw_smp_processor_id());
++ sprintf(name,"intel-ucode/%02x-%02x-%02x",
++ c->x86, c->x86_model, c->x86_mask);
++ error = request_firmware(&firmware, name, µcode_pdev->dev);
++ if (error) {
++ pr_debug("ucode data file %s load failed\n", name);
++ return error;
++ }
++ buf = (void *)firmware->data;
++ size = firmware->size;
++ while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
++ > 0) {
++ error = microcode_sanity_check(mc);
++ if (error)
++ break;
++ error = get_maching_microcode(mc, cpu);
++ if (error < 0)
++ break;
++ /*
++ * It's possible the data file has multiple matching ucode,
++ * lets keep searching till the latest version
++ */
++ if (error == 1) {
++ apply_microcode(cpu);
++ error = 0;
++ }
++ vfree(mc);
++ }
++ if (offset > 0)
++ vfree(mc);
++ if (offset < 0)
++ error = offset;
++ release_firmware(firmware);
++
++ return error;
++}
++
++static void microcode_init_cpu(int cpu)
++{
++ cpumask_t old;
++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
++
++ old = current->cpus_allowed;
++
++ set_cpus_allowed(current, cpumask_of_cpu(cpu));
++ mutex_lock(µcode_mutex);
++ collect_cpu_info(cpu);
++ if (uci->valid)
++ cpu_request_microcode(cpu);
++ mutex_unlock(µcode_mutex);
++ set_cpus_allowed(current, old);
++}
++
++static void microcode_fini_cpu(int cpu)
++{
++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
++
++ mutex_lock(µcode_mutex);
++ uci->valid = 0;
++ vfree(uci->mc);
++ uci->mc = NULL;
++ mutex_unlock(µcode_mutex);
++}
++
++static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz)
++{
++ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
++ char *end;
++ unsigned long val = simple_strtoul(buf, &end, 0);
++ int err = 0;
++ int cpu = dev->id;
++
++ if (end == buf)
++ return -EINVAL;
++ if (val == 1) {
++ cpumask_t old;
++
++ old = current->cpus_allowed;
++
++ lock_cpu_hotplug();
++ set_cpus_allowed(current, cpumask_of_cpu(cpu));
++
++ mutex_lock(µcode_mutex);
++ if (uci->valid)
++ err = cpu_request_microcode(cpu);
++ mutex_unlock(µcode_mutex);
++ unlock_cpu_hotplug();
++ set_cpus_allowed(current, old);
++ }
++ if (err)
++ return err;
++ return sz;
++}
++
++static ssize_t version_show(struct sys_device *dev, char *buf)
++{
++ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
++
++ return sprintf(buf, "0x%x\n", uci->rev);
++}
++
++static ssize_t pf_show(struct sys_device *dev, char *buf)
++{
++ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
++
++ return sprintf(buf, "0x%x\n", uci->pf);
++}
++
++static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
++static SYSDEV_ATTR(version, 0400, version_show, NULL);
++static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
++
++static struct attribute *mc_default_attrs[] = {
++ &attr_reload.attr,
++ &attr_version.attr,
++ &attr_processor_flags.attr,
++ NULL
++};
++
++static struct attribute_group mc_attr_group = {
++ .attrs = mc_default_attrs,
++ .name = "microcode",
++};
++
++static int mc_sysdev_add(struct sys_device *sys_dev)
++{
++ int err, cpu = sys_dev->id;
++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
++
++ if (!cpu_online(cpu))
++ return 0;
++
++ pr_debug("Microcode:CPU %d added\n", cpu);
++ memset(uci, 0, sizeof(*uci));
++
++ err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
++ if (err)
++ return err;
++
++ microcode_init_cpu(cpu);
++ return 0;
++}
++
++static int mc_sysdev_remove(struct sys_device *sys_dev)
++{
++ int cpu = sys_dev->id;
++
++ if (!cpu_online(cpu))
++ return 0;
++ pr_debug("Microcode:CPU %d removed\n", cpu);
++ microcode_fini_cpu(cpu);
++ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
++ return 0;
++}
++
++static int mc_sysdev_resume(struct sys_device *dev)
++{
++ int cpu = dev->id;
++
++ if (!cpu_online(cpu))
++ return 0;
++ pr_debug("Microcode:CPU %d resumed\n", cpu);
++ /* only CPU 0 will apply ucode here */
++ apply_microcode(0);
++ return 0;
++}
++
++static struct sysdev_driver mc_sysdev_driver = {
++ .add = mc_sysdev_add,
++ .remove = mc_sysdev_remove,
++ .resume = mc_sysdev_resume,
++};
++
++#ifdef CONFIG_HOTPLUG_CPU
++static __cpuinit int
++mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
++{
++ unsigned int cpu = (unsigned long)hcpu;
++ struct sys_device *sys_dev;
++
++ sys_dev = get_cpu_sysdev(cpu);
++ switch (action) {
++ case CPU_ONLINE:
++ case CPU_DOWN_FAILED:
++ mc_sysdev_add(sys_dev);
++ break;
++ case CPU_DOWN_PREPARE:
++ mc_sysdev_remove(sys_dev);
++ break;
++ }
++ return NOTIFY_OK;
++}
++
++static struct notifier_block mc_cpu_notifier = {
++ .notifier_call = mc_cpu_callback,
++};
++#endif
++
++static int __init microcode_init (void)
++{
++ int error;
++
++ error = microcode_dev_init();
++ if (error)
++ return error;
++ microcode_pdev = platform_device_register_simple("microcode", -1,
++ NULL, 0);
++ if (IS_ERR(microcode_pdev)) {
++ microcode_dev_exit();
++ return PTR_ERR(microcode_pdev);
++ }
++
++ lock_cpu_hotplug();
++ error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
++ unlock_cpu_hotplug();
++ if (error) {
++ microcode_dev_exit();
++ platform_device_unregister(microcode_pdev);
++ return error;
++ }
++
++ register_hotcpu_notifier(&mc_cpu_notifier);
++
+ printk(KERN_INFO
+ "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran at veritas.com>\n");
+ return 0;
+@@ -515,9 +760,16 @@ static int __init microcode_init (void)
+
+ static void __exit microcode_exit (void)
+ {
+- misc_deregister(µcode_dev);
++ microcode_dev_exit();
++
++ unregister_hotcpu_notifier(&mc_cpu_notifier);
++
++ lock_cpu_hotplug();
++ sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
++ unlock_cpu_hotplug();
++
++ platform_device_unregister(microcode_pdev);
+ }
+
+ module_init(microcode_init)
+ module_exit(microcode_exit)
+-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
+index a70b5fa..442aaf8 100644
+--- a/arch/i386/kernel/mpparse.c
++++ b/arch/i386/kernel/mpparse.c
+@@ -30,6 +30,7 @@
+ #include <asm/io_apic.h>
+
+ #include <mach_apic.h>
++#include <mach_apicdef.h>
+ #include <mach_mpparse.h>
+ #include <bios_ebda.h>
+
+@@ -68,7 +69,7 @@ unsigned int def_to_bigsmp = 0;
+ /* Processor that is doing the boot up */
+ unsigned int boot_cpu_physical_apicid = -1U;
+ /* Internal processor count */
+-static unsigned int __devinitdata num_processors;
++unsigned int __cpuinitdata num_processors;
+
+ /* Bitmask of physically existing CPUs */
+ physid_mask_t phys_cpu_present_map;
+@@ -228,12 +229,14 @@ static void __init MP_bus_info (struct m
+
+ mpc_oem_bus_info(m, str, translation_table[mpc_record]);
+
++#if MAX_MP_BUSSES < 256
+ if (m->mpc_busid >= MAX_MP_BUSSES) {
+ printk(KERN_WARNING "MP table busid value (%d) for bustype %s "
+ " is too large, max. supported is %d\n",
+ m->mpc_busid, str, MAX_MP_BUSSES - 1);
+ return;
+ }
++#endif
+
+ if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
+ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
+@@ -293,19 +296,6 @@ static void __init MP_lintsrc_info (stru
+ m->mpc_irqtype, m->mpc_irqflag & 3,
+ (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
+ m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
+- /*
+- * Well it seems all SMP boards in existence
+- * use ExtINT/LVT1 == LINT0 and
+- * NMI/LVT2 == LINT1 - the following check
+- * will show us if this assumptions is false.
+- * Until then we do not have to add baggage.
+- */
+- if ((m->mpc_irqtype == mp_ExtINT) &&
+- (m->mpc_destapiclint != 0))
+- BUG();
+- if ((m->mpc_irqtype == mp_NMI) &&
+- (m->mpc_destapiclint != 1))
+- BUG();
+ }
+
+ #ifdef CONFIG_X86_NUMAQ
+@@ -822,8 +812,7 @@ int es7000_plat;
+
+ #ifdef CONFIG_ACPI
+
+-void __init mp_register_lapic_address (
+- u64 address)
++void __init mp_register_lapic_address(u64 address)
+ {
+ mp_lapic_addr = (unsigned long) address;
+
+@@ -835,13 +824,10 @@ void __init mp_register_lapic_address (
+ Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid);
+ }
+
+-
+-void __devinit mp_register_lapic (
+- u8 id,
+- u8 enabled)
++void __devinit mp_register_lapic (u8 id, u8 enabled)
+ {
+ struct mpc_config_processor processor;
+- int boot_cpu = 0;
++ int boot_cpu = 0;
+
+ if (MAX_APICS - id <= 0) {
+ printk(KERN_WARNING "Processor #%d invalid (max %d)\n",
+@@ -878,11 +864,9 @@ static struct mp_ioapic_routing {
+ u32 pin_programmed[4];
+ } mp_ioapic_routing[MAX_IO_APICS];
+
+-
+-static int mp_find_ioapic (
+- int gsi)
++static int mp_find_ioapic (int gsi)
+ {
+- int i = 0;
++ int i = 0;
+
+ /* Find the IOAPIC that manages this GSI. */
+ for (i = 0; i < nr_ioapics; i++) {
+@@ -895,15 +879,11 @@ static int mp_find_ioapic (
+
+ return -1;
+ }
+-
+
+-void __init mp_register_ioapic (
+- u8 id,
+- u32 address,
+- u32 gsi_base)
++void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
+ {
+- int idx = 0;
+- int tmpid;
++ int idx = 0;
++ int tmpid;
+
+ if (nr_ioapics >= MAX_IO_APICS) {
+ printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
+@@ -949,16 +929,10 @@ void __init mp_register_ioapic (
+ mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
+ mp_ioapic_routing[idx].gsi_base,
+ mp_ioapic_routing[idx].gsi_end);
+-
+- return;
+ }
+
+-
+-void __init mp_override_legacy_irq (
+- u8 bus_irq,
+- u8 polarity,
+- u8 trigger,
+- u32 gsi)
++void __init
++mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
+ {
+ struct mpc_config_intsrc intsrc;
+ int ioapic = -1;
+@@ -996,15 +970,13 @@ void __init mp_override_legacy_irq (
+ mp_irqs[mp_irq_entries] = intsrc;
+ if (++mp_irq_entries == MAX_IRQ_SOURCES)
+ panic("Max # of irq sources exceeded!\n");
+-
+- return;
+ }
+
+ void __init mp_config_acpi_legacy_irqs (void)
+ {
+ struct mpc_config_intsrc intsrc;
+- int i = 0;
+- int ioapic = -1;
++ int i = 0;
++ int ioapic = -1;
+
+ /*
+ * Fabricate the legacy ISA bus (bus #31).
+@@ -1073,12 +1045,12 @@ void __init mp_config_acpi_legacy_irqs (
+
+ #define MAX_GSI_NUM 4096
+
+-int mp_register_gsi (u32 gsi, int triggering, int polarity)
++int mp_register_gsi(u32 gsi, int triggering, int polarity)
+ {
+- int ioapic = -1;
+- int ioapic_pin = 0;
+- int idx, bit = 0;
+- static int pci_irq = 16;
++ int ioapic = -1;
++ int ioapic_pin = 0;
++ int idx, bit = 0;
++ static int pci_irq = 16;
+ /*
+ * Mapping between Global System Interrups, which
+ * represent all possible interrupts, and IRQs
+diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
+index acb3514..eaafe23 100644
+--- a/arch/i386/kernel/nmi.c
++++ b/arch/i386/kernel/nmi.c
+@@ -13,7 +13,6 @@
+ * Mikael Pettersson : PM converted to driver model. Disable/enable API.
+ */
+
+-#include <linux/config.h>
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+ #include <linux/module.h>
+@@ -21,83 +20,177 @@
+ #include <linux/sysdev.h>
+ #include <linux/sysctl.h>
+ #include <linux/percpu.h>
++#include <linux/dmi.h>
++#include <linux/kprobes.h>
+
+ #include <asm/smp.h>
+ #include <asm/nmi.h>
++#include <asm/kdebug.h>
+ #include <asm/intel_arch_perfmon.h>
+
+ #include "mach_traps.h"
+
+-unsigned int nmi_watchdog = NMI_NONE;
+-extern int unknown_nmi_panic;
+-static unsigned int nmi_hz = HZ;
+-static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
+-static unsigned int nmi_p4_cccr_val;
+-extern void show_registers(struct pt_regs *regs);
++int unknown_nmi_panic;
++int nmi_watchdog_enabled;
+
+-/*
+- * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
+- * - it may be reserved by some other driver, or not
+- * - when not reserved by some other driver, it may be used for
+- * the NMI watchdog, or not
+- *
+- * This is maintained separately from nmi_active because the NMI
+- * watchdog may also be driven from the I/O APIC timer.
++/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
++ * evtsel_nmi_owner tracks the ownership of the event selection
++ * - different performance counters/ event selection may be reserved for
++ * different subsystems this reservation system just tries to coordinate
++ * things a little
+ */
+-static DEFINE_SPINLOCK(lapic_nmi_owner_lock);
+-static unsigned int lapic_nmi_owner;
+-#define LAPIC_NMI_WATCHDOG (1<<0)
+-#define LAPIC_NMI_RESERVED (1<<1)
++static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner);
++static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]);
++
++/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
++ * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
++ */
++#define NMI_MAX_COUNTER_BITS 66
+
+ /* nmi_active:
+- * +1: the lapic NMI watchdog is active, but can be disabled
+- * 0: the lapic NMI watchdog has not been set up, and cannot
++ * >0: the lapic NMI watchdog is active, but can be disabled
++ * <0: the lapic NMI watchdog has not been set up, and cannot
+ * be enabled
+- * -1: the lapic NMI watchdog is disabled, but can be enabled
++ * 0: the lapic NMI watchdog is disabled, but can be enabled
+ */
+-int nmi_active;
++atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+
+-#define K7_EVNTSEL_ENABLE (1 << 22)
+-#define K7_EVNTSEL_INT (1 << 20)
+-#define K7_EVNTSEL_OS (1 << 17)
+-#define K7_EVNTSEL_USR (1 << 16)
+-#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
+-#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
++unsigned int nmi_watchdog = NMI_DEFAULT;
++static unsigned int nmi_hz = HZ;
+
+-#define P6_EVNTSEL0_ENABLE (1 << 22)
+-#define P6_EVNTSEL_INT (1 << 20)
+-#define P6_EVNTSEL_OS (1 << 17)
+-#define P6_EVNTSEL_USR (1 << 16)
+-#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
+-#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
++struct nmi_watchdog_ctlblk {
++ int enabled;
++ u64 check_bit;
++ unsigned int cccr_msr;
++ unsigned int perfctr_msr; /* the MSR to reset in NMI handler */
++ unsigned int evntsel_msr; /* the MSR to select the events to handle */
++};
++static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+
+-#define MSR_P4_MISC_ENABLE 0x1A0
+-#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
+-#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
+-#define MSR_P4_PERFCTR0 0x300
+-#define MSR_P4_CCCR0 0x360
+-#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
+-#define P4_ESCR_OS (1<<3)
+-#define P4_ESCR_USR (1<<2)
+-#define P4_CCCR_OVF_PMI0 (1<<26)
+-#define P4_CCCR_OVF_PMI1 (1<<27)
+-#define P4_CCCR_THRESHOLD(N) ((N)<<20)
+-#define P4_CCCR_COMPLEMENT (1<<19)
+-#define P4_CCCR_COMPARE (1<<18)
+-#define P4_CCCR_REQUIRED (3<<16)
+-#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
+-#define P4_CCCR_ENABLE (1<<12)
+-/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+- CRU_ESCR0 (with any non-null event selector) through a complemented
+- max threshold. [IA32-Vol3, Section 14.9.9] */
+-#define MSR_P4_IQ_COUNTER0 0x30C
+-#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+-#define P4_NMI_IQ_CCCR0 \
+- (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)
++/* local prototypes */
++static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
+
+-#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
+-#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
++extern void show_registers(struct pt_regs *regs);
++extern int unknown_nmi_panic;
++
++/* converts an msr to an appropriate reservation bit */
++static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
++{
++ /* returns the bit offset of the performance counter register */
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ return (msr - MSR_K7_PERFCTR0);
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
++ return (msr - MSR_ARCH_PERFMON_PERFCTR0);
++
++ switch (boot_cpu_data.x86) {
++ case 6:
++ return (msr - MSR_P6_PERFCTR0);
++ case 15:
++ return (msr - MSR_P4_BPU_PERFCTR0);
++ }
++ }
++ return 0;
++}
++
++/* converts an msr to an appropriate reservation bit */
++static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
++{
++ /* returns the bit offset of the event selection register */
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ return (msr - MSR_K7_EVNTSEL0);
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
++ return (msr - MSR_ARCH_PERFMON_EVENTSEL0);
++
++ switch (boot_cpu_data.x86) {
++ case 6:
++ return (msr - MSR_P6_EVNTSEL0);
++ case 15:
++ return (msr - MSR_P4_BSU_ESCR0);
++ }
++ }
++ return 0;
++}
++
++/* checks for a bit availability (hack for oprofile) */
++int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
++{
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner)));
++}
++
++/* checks the an msr for availability */
++int avail_to_resrv_perfctr_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_perfctr_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner)));
++}
++
++int reserve_perfctr_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_perfctr_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ if (!test_and_set_bit(counter, &__get_cpu_var(perfctr_nmi_owner)))
++ return 1;
++ return 0;
++}
++
++void release_perfctr_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_perfctr_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ clear_bit(counter, &__get_cpu_var(perfctr_nmi_owner));
++}
++
++int reserve_evntsel_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_evntsel_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ if (!test_and_set_bit(counter, &__get_cpu_var(evntsel_nmi_owner)[0]))
++ return 1;
++ return 0;
++}
++
++void release_evntsel_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_evntsel_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ clear_bit(counter, &__get_cpu_var(evntsel_nmi_owner)[0]);
++}
++
++static __cpuinit inline int nmi_known_cpu(void)
++{
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6));
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
++ return 1;
++ else
++ return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6));
++ }
++ return 0;
++}
+
+ #ifdef CONFIG_SMP
+ /* The performance counters used by NMI_LOCAL_APIC don't trigger when
+@@ -125,7 +218,18 @@ static int __init check_nmi_watchdog(voi
+ unsigned int *prev_nmi_count;
+ int cpu;
+
+- if (nmi_watchdog == NMI_NONE)
++ /* Enable NMI watchdog for newer systems.
++ Probably safe on most older systems too, but let's be careful.
++ IBM ThinkPads use INT10 inside SMM and that allows early NMI inside SMM
++ which hangs the system. Disable watchdog for all thinkpads */
++ if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004 &&
++ !dmi_name_in_vendors("ThinkPad"))
++ nmi_watchdog = NMI_LOCAL_APIC;
++
++ if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT))
++ return 0;
++
++ if (!atomic_read(&nmi_active))
+ return 0;
+
+ prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
+@@ -149,25 +253,45 @@ static int __init check_nmi_watchdog(voi
+ if (!cpu_isset(cpu, cpu_callin_map))
+ continue;
+ #endif
++ if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled)
++ continue;
+ if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
+- endflag = 1;
+ printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
+ cpu,
+ prev_nmi_count[cpu],
+ nmi_count(cpu));
+- nmi_active = 0;
+- lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG;
+- kfree(prev_nmi_count);
+- return -1;
++ per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0;
++ atomic_dec(&nmi_active);
+ }
+ }
++ if (!atomic_read(&nmi_active)) {
++ kfree(prev_nmi_count);
++ atomic_set(&nmi_active, -1);
++ return -1;
++ }
+ endflag = 1;
+ printk("OK.\n");
+
+ /* now that we know it works we can reduce NMI frequency to
+ something more reasonable; makes a difference in some configs */
+- if (nmi_watchdog == NMI_LOCAL_APIC)
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
+ nmi_hz = 1;
++ /*
++ * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter
++ * are writable, with higher bits sign extending from bit 31.
++ * So, we can only program the counter with 31 bit values and
++ * 32nd bit should be 1, for 33.. to be 1.
++ * Find the appropriate nmi_hz
++ */
++ if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0 &&
++ ((u64)cpu_khz * 1000) > 0x7fffffffULL) {
++ u64 count = (u64)cpu_khz * 1000;
++ do_div(count, 0x7fffffffUL);
++ nmi_hz = count + 1;
++ }
++ }
+
+ kfree(prev_nmi_count);
+ return 0;
+@@ -181,124 +305,70 @@ static int __init setup_nmi_watchdog(cha
+
+ get_option(&str, &nmi);
+
+- if (nmi >= NMI_INVALID)
++ if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
+ return 0;
+- if (nmi == NMI_NONE)
+- nmi_watchdog = nmi;
+ /*
+ * If any other x86 CPU has a local APIC, then
+ * please test the NMI stuff there and send me the
+ * missing bits. Right now Intel P6/P4 and AMD K7 only.
+ */
+- if ((nmi == NMI_LOCAL_APIC) &&
+- (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+- (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
+- nmi_watchdog = nmi;
+- if ((nmi == NMI_LOCAL_APIC) &&
+- (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
+- (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
+- nmi_watchdog = nmi;
+- /*
+- * We can enable the IO-APIC watchdog
+- * unconditionally.
+- */
+- if (nmi == NMI_IO_APIC) {
+- nmi_active = 1;
+- nmi_watchdog = nmi;
+- }
++ if ((nmi == NMI_LOCAL_APIC) && (nmi_known_cpu() == 0))
++ return 0; /* no lapic support */
++ nmi_watchdog = nmi;
+ return 1;
+ }
+
+ __setup("nmi_watchdog=", setup_nmi_watchdog);
+
+-static void disable_intel_arch_watchdog(void);
+-
+ static void disable_lapic_nmi_watchdog(void)
+ {
+- if (nmi_active <= 0)
++ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
++
++ if (atomic_read(&nmi_active) <= 0)
+ return;
+- switch (boot_cpu_data.x86_vendor) {
+- case X86_VENDOR_AMD:
+- wrmsr(MSR_K7_EVNTSEL0, 0, 0);
+- break;
+- case X86_VENDOR_INTEL:
+- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+- disable_intel_arch_watchdog();
+- break;
+- }
+- switch (boot_cpu_data.x86) {
+- case 6:
+- if (boot_cpu_data.x86_model > 0xd)
+- break;
+
+- wrmsr(MSR_P6_EVNTSEL0, 0, 0);
+- break;
+- case 15:
+- if (boot_cpu_data.x86_model > 0x4)
+- break;
++ on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
+
+- wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+- wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+- break;
+- }
+- break;
+- }
+- nmi_active = -1;
+- /* tell do_nmi() and others that we're not active any more */
+- nmi_watchdog = 0;
++ BUG_ON(atomic_read(&nmi_active) != 0);
+ }
+
+ static void enable_lapic_nmi_watchdog(void)
+ {
+- if (nmi_active < 0) {
+- nmi_watchdog = NMI_LOCAL_APIC;
+- setup_apic_nmi_watchdog();
+- }
+-}
++ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+-int reserve_lapic_nmi(void)
+-{
+- unsigned int old_owner;
+-
+- spin_lock(&lapic_nmi_owner_lock);
+- old_owner = lapic_nmi_owner;
+- lapic_nmi_owner |= LAPIC_NMI_RESERVED;
+- spin_unlock(&lapic_nmi_owner_lock);
+- if (old_owner & LAPIC_NMI_RESERVED)
+- return -EBUSY;
+- if (old_owner & LAPIC_NMI_WATCHDOG)
+- disable_lapic_nmi_watchdog();
+- return 0;
+-}
++ /* are we already enabled */
++ if (atomic_read(&nmi_active) != 0)
++ return;
+
+-void release_lapic_nmi(void)
+-{
+- unsigned int new_owner;
++ /* are we lapic aware */
++ if (nmi_known_cpu() <= 0)
++ return;
+
+- spin_lock(&lapic_nmi_owner_lock);
+- new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
+- lapic_nmi_owner = new_owner;
+- spin_unlock(&lapic_nmi_owner_lock);
+- if (new_owner & LAPIC_NMI_WATCHDOG)
+- enable_lapic_nmi_watchdog();
++ on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
++ touch_nmi_watchdog();
+ }
+
+ void disable_timer_nmi_watchdog(void)
+ {
+- if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
++ BUG_ON(nmi_watchdog != NMI_IO_APIC);
++
++ if (atomic_read(&nmi_active) <= 0)
+ return;
+
+- unset_nmi_callback();
+- nmi_active = -1;
+- nmi_watchdog = NMI_NONE;
++ disable_irq(0);
++ on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
++
++ BUG_ON(atomic_read(&nmi_active) != 0);
+ }
+
+ void enable_timer_nmi_watchdog(void)
+ {
+- if (nmi_active < 0) {
+- nmi_watchdog = NMI_IO_APIC;
++ BUG_ON(nmi_watchdog != NMI_IO_APIC);
++
++ if (atomic_read(&nmi_active) == 0) {
+ touch_nmi_watchdog();
+- nmi_active = 1;
++ on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
++ enable_irq(0);
+ }
+ }
+
+@@ -308,15 +378,20 @@ static int nmi_pm_active; /* nmi_active
+
+ static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
+ {
+- nmi_pm_active = nmi_active;
+- disable_lapic_nmi_watchdog();
++ /* only CPU0 goes here, other CPUs should be offline */
++ nmi_pm_active = atomic_read(&nmi_active);
++ stop_apic_nmi_watchdog(NULL);
++ BUG_ON(atomic_read(&nmi_active) != 0);
+ return 0;
+ }
+
+ static int lapic_nmi_resume(struct sys_device *dev)
+ {
+- if (nmi_pm_active > 0)
+- enable_lapic_nmi_watchdog();
++ /* only CPU0 goes here, other CPUs should be offline */
++ if (nmi_pm_active > 0) {
++ setup_apic_nmi_watchdog(NULL);
++ touch_nmi_watchdog();
++ }
+ return 0;
+ }
+
+@@ -336,7 +411,13 @@ static int __init init_lapic_nmi_sysfs(v
+ {
+ int error;
+
+- if (nmi_active == 0 || nmi_watchdog != NMI_LOCAL_APIC)
++ /* should really be a BUG_ON but b/c this is an
++ * init call, it just doesn't work. -dcz
++ */
++ if (nmi_watchdog != NMI_LOCAL_APIC)
++ return 0;
++
++ if ( atomic_read(&nmi_active) < 0 )
+ return 0;
+
+ error = sysdev_class_register(&nmi_sysclass);
+@@ -354,138 +435,269 @@ late_initcall(init_lapic_nmi_sysfs);
+ * Original code written by Keith Owens.
+ */
+
+-static void clear_msr_range(unsigned int base, unsigned int n)
+-{
+- unsigned int i;
+-
+- for(i = 0; i < n; ++i)
+- wrmsr(base+i, 0, 0);
+-}
+-
+-static void write_watchdog_counter(const char *descr)
++static void write_watchdog_counter(unsigned int perfctr_msr, const char *descr)
+ {
+ u64 count = (u64)cpu_khz * 1000;
+
+ do_div(count, nmi_hz);
+ if(descr)
+ Dprintk("setting %s to -0x%08Lx\n", descr, count);
+- wrmsrl(nmi_perfctr_msr, 0 - count);
++ wrmsrl(perfctr_msr, 0 - count);
+ }
+
+-static void setup_k7_watchdog(void)
++/* Note that these events don't tick when the CPU idles. This means
++ the frequency varies with CPU load. */
++
++#define K7_EVNTSEL_ENABLE (1 << 22)
++#define K7_EVNTSEL_INT (1 << 20)
++#define K7_EVNTSEL_OS (1 << 17)
++#define K7_EVNTSEL_USR (1 << 16)
++#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
++#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
++
++static int setup_k7_watchdog(void)
+ {
++ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ perfctr_msr = MSR_K7_PERFCTR0;
++ evntsel_msr = MSR_K7_EVNTSEL0;
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
+
+- nmi_perfctr_msr = MSR_K7_PERFCTR0;
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
+
+- clear_msr_range(MSR_K7_EVNTSEL0, 4);
+- clear_msr_range(MSR_K7_PERFCTR0, 4);
++ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = K7_EVNTSEL_INT
+ | K7_EVNTSEL_OS
+ | K7_EVNTSEL_USR
+ | K7_NMI_EVENT;
+
+- wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
+- write_watchdog_counter("K7_PERFCTR0");
++ /* setup the timer */
++ wrmsr(evntsel_msr, evntsel, 0);
++ write_watchdog_counter(perfctr_msr, "K7_PERFCTR0");
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= K7_EVNTSEL_ENABLE;
+- wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
++ wrmsr(evntsel_msr, evntsel, 0);
++
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = 0; //unused
++ wd->check_bit = 1ULL<<63;
++ return 1;
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
++}
++
++static void stop_k7_watchdog(void)
++{
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ wrmsr(wd->evntsel_msr, 0, 0);
++
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
+ }
+
+-static void setup_p6_watchdog(void)
++#define P6_EVNTSEL0_ENABLE (1 << 22)
++#define P6_EVNTSEL_INT (1 << 20)
++#define P6_EVNTSEL_OS (1 << 17)
++#define P6_EVNTSEL_USR (1 << 16)
++#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
++#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
++
++static int setup_p6_watchdog(void)
+ {
++ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ perfctr_msr = MSR_P6_PERFCTR0;
++ evntsel_msr = MSR_P6_EVNTSEL0;
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
+
+- nmi_perfctr_msr = MSR_P6_PERFCTR0;
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
+
+- clear_msr_range(MSR_P6_EVNTSEL0, 2);
+- clear_msr_range(MSR_P6_PERFCTR0, 2);
++ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = P6_EVNTSEL_INT
+ | P6_EVNTSEL_OS
+ | P6_EVNTSEL_USR
+ | P6_NMI_EVENT;
+
+- wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+- write_watchdog_counter("P6_PERFCTR0");
++ /* setup the timer */
++ wrmsr(evntsel_msr, evntsel, 0);
++ write_watchdog_counter(perfctr_msr, "P6_PERFCTR0");
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= P6_EVNTSEL0_ENABLE;
+- wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
++ wrmsr(evntsel_msr, evntsel, 0);
++
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = 0; //unused
++ wd->check_bit = 1ULL<<39;
++ return 1;
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
++}
++
++static void stop_p6_watchdog(void)
++{
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ wrmsr(wd->evntsel_msr, 0, 0);
++
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
+ }
+
++/* Note that these events don't tick when the CPU idles. This means
++ the frequency varies with CPU load. */
++
++#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
++#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
++#define P4_ESCR_OS (1<<3)
++#define P4_ESCR_USR (1<<2)
++#define P4_CCCR_OVF_PMI0 (1<<26)
++#define P4_CCCR_OVF_PMI1 (1<<27)
++#define P4_CCCR_THRESHOLD(N) ((N)<<20)
++#define P4_CCCR_COMPLEMENT (1<<19)
++#define P4_CCCR_COMPARE (1<<18)
++#define P4_CCCR_REQUIRED (3<<16)
++#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
++#define P4_CCCR_ENABLE (1<<12)
++#define P4_CCCR_OVF (1<<31)
++/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
++ CRU_ESCR0 (with any non-null event selector) through a complemented
++ max threshold. [IA32-Vol3, Section 14.9.9] */
++
+ static int setup_p4_watchdog(void)
+ {
++ unsigned int perfctr_msr, evntsel_msr, cccr_msr;
++ unsigned int evntsel, cccr_val;
+ unsigned int misc_enable, dummy;
++ unsigned int ht_num;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+- rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
++ rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
+ if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+ return 0;
+
+- nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+- nmi_p4_cccr_val = P4_NMI_IQ_CCCR0;
+ #ifdef CONFIG_SMP
+- if (smp_num_siblings == 2)
+- nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1;
++ /* detect which hyperthread we are on */
++ if (smp_num_siblings == 2) {
++ unsigned int ebx, apicid;
++
++ ebx = cpuid_ebx(1);
++ apicid = (ebx >> 24) & 0xff;
++ ht_num = apicid & 1;
++ } else
+ #endif
++ ht_num = 0;
+
+- if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+- clear_msr_range(0x3F1, 2);
+- /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+- docs doesn't fully define it, so leave it alone for now. */
+- if (boot_cpu_data.x86_model >= 0x3) {
+- /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
+- clear_msr_range(0x3A0, 26);
+- clear_msr_range(0x3BC, 3);
++ /* performance counters are shared resources
++ * assign each hyperthread its own set
++ * (re-use the ESCR0 register, seems safe
++ * and keeps the cccr_val the same)
++ */
++ if (!ht_num) {
++ /* logical cpu 0 */
++ perfctr_msr = MSR_P4_IQ_PERFCTR0;
++ evntsel_msr = MSR_P4_CRU_ESCR0;
++ cccr_msr = MSR_P4_IQ_CCCR0;
++ cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
+ } else {
+- clear_msr_range(0x3A0, 31);
++ /* logical cpu 1 */
++ perfctr_msr = MSR_P4_IQ_PERFCTR1;
++ evntsel_msr = MSR_P4_CRU_ESCR0;
++ cccr_msr = MSR_P4_IQ_CCCR1;
++ cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4);
+ }
+- clear_msr_range(0x3C0, 6);
+- clear_msr_range(0x3C8, 6);
+- clear_msr_range(0x3E0, 2);
+- clear_msr_range(MSR_P4_CCCR0, 18);
+- clear_msr_range(MSR_P4_PERFCTR0, 18);
+-
+- wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+- wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+- write_watchdog_counter("P4_IQ_COUNTER0");
++
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
++
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
++
++ evntsel = P4_ESCR_EVENT_SELECT(0x3F)
++ | P4_ESCR_OS
++ | P4_ESCR_USR;
++
++ cccr_val |= P4_CCCR_THRESHOLD(15)
++ | P4_CCCR_COMPLEMENT
++ | P4_CCCR_COMPARE
++ | P4_CCCR_REQUIRED;
++
++ wrmsr(evntsel_msr, evntsel, 0);
++ wrmsr(cccr_msr, cccr_val, 0);
++ write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0");
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+- wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
++ cccr_val |= P4_CCCR_ENABLE;
++ wrmsr(cccr_msr, cccr_val, 0);
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = cccr_msr;
++ wd->check_bit = 1ULL<<39;
+ return 1;
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
+ }
+
+-static void disable_intel_arch_watchdog(void)
++static void stop_p4_watchdog(void)
+ {
+- unsigned ebx;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+- /*
+- * Check whether the Architectural PerfMon supports
+- * Unhalted Core Cycles Event or not.
+- * NOTE: Corresponding bit = 0 in ebp indicates event present.
+- */
+- ebx = cpuid_ebx(10);
+- if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+- wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
++ wrmsr(wd->cccr_msr, 0, 0);
++ wrmsr(wd->evntsel_msr, 0, 0);
++
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
+ }
+
++#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
++#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
++
+ static int setup_intel_arch_watchdog(void)
+ {
++ unsigned int ebx;
++ union cpuid10_eax eax;
++ unsigned int unused;
++ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+- unsigned ebx;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ /*
+ * Check whether the Architectural PerfMon supports
+ * Unhalted Core Cycles Event or not.
+- * NOTE: Corresponding bit = 0 in ebp indicates event present.
++ * NOTE: Corresponding bit = 0 in ebx indicates event present.
+ */
+- ebx = cpuid_ebx(10);
+- if ((ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+- return 0;
++ cpuid(10, &(eax.full), &ebx, &unused, &unused);
++ if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
++ (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
++ goto fail;
++
++ perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
++ evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0;
+
+- nmi_perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
+
+- clear_msr_range(MSR_ARCH_PERFMON_EVENTSEL0, 2);
+- clear_msr_range(MSR_ARCH_PERFMON_PERFCTR0, 2);
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
++
++ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = ARCH_PERFMON_EVENTSEL_INT
+ | ARCH_PERFMON_EVENTSEL_OS
+@@ -493,51 +705,145 @@ static int setup_intel_arch_watchdog(voi
+ | ARCH_PERFMON_NMI_EVENT_SEL
+ | ARCH_PERFMON_NMI_EVENT_UMASK;
+
+- wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
+- write_watchdog_counter("INTEL_ARCH_PERFCTR0");
++ /* setup the timer */
++ wrmsr(evntsel_msr, evntsel, 0);
++ write_watchdog_counter(perfctr_msr, "INTEL_ARCH_PERFCTR0");
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+- wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
++ wrmsr(evntsel_msr, evntsel, 0);
++
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = 0; //unused
++ wd->check_bit = 1ULL << (eax.split.bit_width - 1);
+ return 1;
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
+ }
+
+-void setup_apic_nmi_watchdog (void)
++static void stop_intel_arch_watchdog(void)
+ {
+- switch (boot_cpu_data.x86_vendor) {
+- case X86_VENDOR_AMD:
+- if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
+- return;
+- setup_k7_watchdog();
+- break;
+- case X86_VENDOR_INTEL:
+- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+- if (!setup_intel_arch_watchdog())
++ unsigned int ebx;
++ union cpuid10_eax eax;
++ unsigned int unused;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ /*
++ * Check whether the Architectural PerfMon supports
++ * Unhalted Core Cycles Event or not.
++ * NOTE: Corresponding bit = 0 in ebx indicates event present.
++ */
++ cpuid(10, &(eax.full), &ebx, &unused, &unused);
++ if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
++ (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
++ return;
++
++ wrmsr(wd->evntsel_msr, 0, 0);
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
++}
++
++void setup_apic_nmi_watchdog (void *unused)
++{
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ /* only support LOCAL and IO APICs for now */
++ if ((nmi_watchdog != NMI_LOCAL_APIC) &&
++ (nmi_watchdog != NMI_IO_APIC))
++ return;
++
++ if (wd->enabled == 1)
++ return;
++
++ /* cheap hack to support suspend/resume */
++ /* if cpu0 is not active neither should the other cpus */
++ if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
++ return;
++
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
+ return;
+- break;
+- }
+- switch (boot_cpu_data.x86) {
+- case 6:
+- if (boot_cpu_data.x86_model > 0xd)
++ if (!setup_k7_watchdog())
+ return;
+-
+- setup_p6_watchdog();
+ break;
+- case 15:
+- if (boot_cpu_data.x86_model > 0x4)
+- return;
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
++ if (!setup_intel_arch_watchdog())
++ return;
++ break;
++ }
++ switch (boot_cpu_data.x86) {
++ case 6:
++ if (boot_cpu_data.x86_model > 0xd)
++ return;
++
++ if (!setup_p6_watchdog())
++ return;
++ break;
++ case 15:
++ if (boot_cpu_data.x86_model > 0x4)
++ return;
+
+- if (!setup_p4_watchdog())
++ if (!setup_p4_watchdog())
++ return;
++ break;
++ default:
+ return;
++ }
+ break;
+ default:
+ return;
+ }
+- break;
+- default:
++ }
++ wd->enabled = 1;
++ atomic_inc(&nmi_active);
++}
++
++void stop_apic_nmi_watchdog(void *unused)
++{
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ /* only support LOCAL and IO APICs for now */
++ if ((nmi_watchdog != NMI_LOCAL_APIC) &&
++ (nmi_watchdog != NMI_IO_APIC))
++ return;
++
++ if (wd->enabled == 0)
+ return;
++
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ stop_k7_watchdog();
++ break;
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
++ stop_intel_arch_watchdog();
++ break;
++ }
++ switch (boot_cpu_data.x86) {
++ case 6:
++ if (boot_cpu_data.x86_model > 0xd)
++ break;
++ stop_p6_watchdog();
++ break;
++ case 15:
++ if (boot_cpu_data.x86_model > 0x4)
++ break;
++ stop_p4_watchdog();
++ break;
++ }
++ break;
++ default:
++ return;
++ }
+ }
+- lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
+- nmi_active = 1;
++ wd->enabled = 0;
++ atomic_dec(&nmi_active);
+ }
+
+ /*
+@@ -579,7 +885,7 @@ EXPORT_SYMBOL(touch_nmi_watchdog);
+
+ extern void die_nmi(struct pt_regs *, const char *msg);
+
+-void nmi_watchdog_tick (struct pt_regs * regs)
++__kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
+ {
+
+ /*
+@@ -588,11 +894,23 @@ void nmi_watchdog_tick (struct pt_regs *
+ * smp_processor_id().
+ */
+ unsigned int sum;
++ int touched = 0;
+ int cpu = smp_processor_id();
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++ u64 dummy;
++ int rc=0;
++
++ /* check for other users first */
++ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
++ == NOTIFY_STOP) {
++ rc = 1;
++ touched = 1;
++ }
+
+ sum = per_cpu(irq_stat, cpu).apic_timer_irqs;
+
+- if (last_irq_sums[cpu] == sum) {
++ /* if the apic timer isn't firing, this cpu isn't doing much */
++ if (!touched && last_irq_sums[cpu] == sum) {
+ /*
+ * Ayiee, looks like this CPU is stuck ...
+ * wait a few IRQs (5 seconds) before doing the oops ...
+@@ -607,27 +925,59 @@ void nmi_watchdog_tick (struct pt_regs *
+ last_irq_sums[cpu] = sum;
+ alert_counter[cpu] = 0;
+ }
+- if (nmi_perfctr_msr) {
+- if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+- /*
+- * P4 quirks:
+- * - An overflown perfctr will assert its interrupt
+- * until the OVF flag in its CCCR is cleared.
+- * - LVTPC is masked on interrupt and must be
+- * unmasked by the LVTPC handler.
++ /* see if the nmi watchdog went off */
++ if (wd->enabled) {
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ rdmsrl(wd->perfctr_msr, dummy);
++ if (dummy & wd->check_bit){
++ /* this wasn't a watchdog timer interrupt */
++ goto done;
++ }
++
++ /* only Intel P4 uses the cccr msr */
++ if (wd->cccr_msr != 0) {
++ /*
++ * P4 quirks:
++ * - An overflown perfctr will assert its interrupt
++ * until the OVF flag in its CCCR is cleared.
++ * - LVTPC is masked on interrupt and must be
++ * unmasked by the LVTPC handler.
++ */
++ rdmsrl(wd->cccr_msr, dummy);
++ dummy &= ~P4_CCCR_OVF;
++ wrmsrl(wd->cccr_msr, dummy);
++ apic_write(APIC_LVTPC, APIC_DM_NMI);
++ }
++ else if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
++ wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
++ /* P6 based Pentium M need to re-unmask
++ * the apic vector but it doesn't hurt
++ * other P6 variant.
++ * ArchPerfom/Core Duo also needs this */
++ apic_write(APIC_LVTPC, APIC_DM_NMI);
++ }
++ /* start the cycle over again */
++ write_watchdog_counter(wd->perfctr_msr, NULL);
++ rc = 1;
++ } else if (nmi_watchdog == NMI_IO_APIC) {
++ /* don't know how to accurately check for this.
++ * just assume it was a watchdog timer interrupt
++ * This matches the old behaviour.
+ */
+- wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
+- apic_write(APIC_LVTPC, APIC_DM_NMI);
++ rc = 1;
+ }
+- else if (nmi_perfctr_msr == MSR_P6_PERFCTR0 ||
+- nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
+- /* Only P6 based Pentium M need to re-unmask
+- * the apic vector but it doesn't hurt
+- * other P6 variant */
+- apic_write(APIC_LVTPC, APIC_DM_NMI);
+- }
+- write_watchdog_counter(NULL);
+ }
++done:
++ return rc;
++}
++
++int do_nmi_callback(struct pt_regs * regs, int cpu)
++{
++#ifdef CONFIG_SYSCTL
++ if (unknown_nmi_panic)
++ return unknown_nmi_panic_callback(regs, cpu);
++#endif
++ return 0;
+ }
+
+ #ifdef CONFIG_SYSCTL
+@@ -637,36 +987,46 @@ static int unknown_nmi_panic_callback(st
+ unsigned char reason = get_nmi_reason();
+ char buf[64];
+
+- if (!(reason & 0xc0)) {
+- sprintf(buf, "NMI received for unknown reason %02x\n", reason);
+- die_nmi(regs, buf);
+- }
++ sprintf(buf, "NMI received for unknown reason %02x\n", reason);
++ die_nmi(regs, buf);
+ return 0;
+ }
+
+ /*
+- * proc handler for /proc/sys/kernel/unknown_nmi_panic
++ * proc handler for /proc/sys/kernel/nmi
+ */
+-int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file,
++int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
+ void __user *buffer, size_t *length, loff_t *ppos)
+ {
+ int old_state;
+
+- old_state = unknown_nmi_panic;
++ nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
++ old_state = nmi_watchdog_enabled;
+ proc_dointvec(table, write, file, buffer, length, ppos);
+- if (!!old_state == !!unknown_nmi_panic)
++ if (!!old_state == !!nmi_watchdog_enabled)
+ return 0;
+
+- if (unknown_nmi_panic) {
+- if (reserve_lapic_nmi() < 0) {
+- unknown_nmi_panic = 0;
+- return -EBUSY;
+- } else {
+- set_nmi_callback(unknown_nmi_panic_callback);
+- }
++ if (atomic_read(&nmi_active) < 0) {
++ printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
++ return -EIO;
++ }
++
++ if (nmi_watchdog == NMI_DEFAULT) {
++ if (nmi_known_cpu() > 0)
++ nmi_watchdog = NMI_LOCAL_APIC;
++ else
++ nmi_watchdog = NMI_IO_APIC;
++ }
++
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ if (nmi_watchdog_enabled)
++ enable_lapic_nmi_watchdog();
++ else
++ disable_lapic_nmi_watchdog();
+ } else {
+- release_lapic_nmi();
+- unset_nmi_callback();
++ printk( KERN_WARNING
++ "NMI watchdog doesn't know what hardware to touch\n");
++ return -EIO;
+ }
+ return 0;
+ }
+@@ -675,7 +1035,11 @@ int proc_unknown_nmi_panic(ctl_table *ta
+
+ EXPORT_SYMBOL(nmi_active);
+ EXPORT_SYMBOL(nmi_watchdog);
+-EXPORT_SYMBOL(reserve_lapic_nmi);
+-EXPORT_SYMBOL(release_lapic_nmi);
++EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
++EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
++EXPORT_SYMBOL(reserve_perfctr_nmi);
++EXPORT_SYMBOL(release_perfctr_nmi);
++EXPORT_SYMBOL(reserve_evntsel_nmi);
++EXPORT_SYMBOL(release_evntsel_nmi);
+ EXPORT_SYMBOL(disable_timer_nmi_watchdog);
+ EXPORT_SYMBOL(enable_timer_nmi_watchdog);
+diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
+index 8657c73..1e1fa3e 100644
+--- a/arch/i386/kernel/process.c
++++ b/arch/i386/kernel/process.c
+@@ -37,6 +37,7 @@
+ #include <linux/kallsyms.h>
+ #include <linux/ptrace.h>
+ #include <linux/random.h>
++#include <linux/personality.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -235,20 +236,28 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
+ * We execute MONITOR against need_resched and enter optimized wait state
+ * through MWAIT. Whenever someone changes need_resched, we would be woken
+ * up from MWAIT (without an IPI).
++ *
++ * New with Core Duo processors, MWAIT can take some hints based on CPU
++ * capability.
+ */
+-static void mwait_idle(void)
++void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
+ {
+- local_irq_enable();
+-
+- while (!need_resched()) {
++ if (!need_resched()) {
+ __monitor((void *)¤t_thread_info()->flags, 0, 0);
+ smp_mb();
+- if (need_resched())
+- break;
+- __mwait(0, 0);
++ if (!need_resched())
++ __mwait(eax, ecx);
+ }
+ }
+
++/* Default MONITOR/MWAIT with no hints, used for default C1 state */
++static void mwait_idle(void)
++{
++ local_irq_enable();
++ while (!need_resched())
++ mwait_idle_with_hints(0, 0);
++}
++
+ void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
+ {
+ if (cpu_has(c, X86_FEATURE_MWAIT)) {
+@@ -296,9 +305,9 @@ void show_regs(struct pt_regs * regs)
+ if (user_mode_vm(regs))
+ printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
+ printk(" EFLAGS: %08lx %s (%s %.*s)\n",
+- regs->eflags, print_tainted(), system_utsname.release,
+- (int)strcspn(system_utsname.version, " "),
+- system_utsname.version);
++ regs->eflags, print_tainted(), init_utsname()->release,
++ (int)strcspn(init_utsname()->version, " "),
++ init_utsname()->version);
+ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+ regs->eax,regs->ebx,regs->ecx,regs->edx);
+ printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+@@ -320,15 +329,6 @@ void show_regs(struct pt_regs * regs)
+ * the "args".
+ */
+ extern void kernel_thread_helper(void);
+-__asm__(".section .text\n"
+- ".align 4\n"
+- "kernel_thread_helper:\n\t"
+- "movl %edx,%eax\n\t"
+- "pushl %edx\n\t"
+- "call *%ebx\n\t"
+- "pushl %eax\n\t"
+- "call do_exit\n"
+- ".previous");
+
+ /*
+ * Create a kernel thread
+@@ -346,7 +346,7 @@ int kernel_thread(int (*fn)(void *), voi
+ regs.xes = __USER_DS;
+ regs.orig_eax = -1;
+ regs.eip = (unsigned long) kernel_thread_helper;
+- regs.xcs = __KERNEL_CS;
++ regs.xcs = __KERNEL_CS | get_kernel_rpl();
+ regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
+
+ /* Ok, create the new process.. */
+@@ -433,13 +433,12 @@ int copy_thread(int nr, unsigned long cl
+
+ tsk = current;
+ if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
+- p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
++ p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
++ IO_BITMAP_BYTES, GFP_KERNEL);
+ if (!p->thread.io_bitmap_ptr) {
+ p->thread.io_bitmap_max = 0;
+ return -ENOMEM;
+ }
+- memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr,
+- IO_BITMAP_BYTES);
+ set_tsk_thread_flag(p, TIF_IO_BITMAP);
+ }
+
+@@ -905,7 +904,7 @@ asmlinkage int sys_get_thread_area(struc
+
+ unsigned long arch_align_stack(unsigned long sp)
+ {
+- if (randomize_va_space)
++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ sp -= get_random_int() % 8192;
+ return sp & ~0xf;
+ }
+diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
+index d3db03f..775f50e 100644
+--- a/arch/i386/kernel/ptrace.c
++++ b/arch/i386/kernel/ptrace.c
+@@ -185,17 +185,17 @@ static unsigned long convert_eip_to_line
+ return addr;
+ }
+
+-static inline int is_at_popf(struct task_struct *child, struct pt_regs *regs)
++static inline int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
+ {
+ int i, copied;
+- unsigned char opcode[16];
++ unsigned char opcode[15];
+ unsigned long addr = convert_eip_to_linear(child, regs);
+
+ copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
+ for (i = 0; i < copied; i++) {
+ switch (opcode[i]) {
+- /* popf */
+- case 0x9d:
++ /* popf and iret */
++ case 0x9d: case 0xcf:
+ return 1;
+ /* opcode and address size prefixes */
+ case 0x66: case 0x67:
+@@ -247,7 +247,7 @@ static void set_singlestep(struct task_s
+ * don't mark it as being "us" that set it, so that we
+ * won't clear it by hand later.
+ */
+- if (is_at_popf(child, regs))
++ if (is_setting_trap_flag(child, regs))
+ return;
+
+ child->ptrace |= PT_DTRACE;
+diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
+index 54cfeab..84278e0 100644
+--- a/arch/i386/kernel/reboot.c
++++ b/arch/i386/kernel/reboot.c
+@@ -145,14 +145,10 @@ real_mode_gdt_entries [3] =
+ 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */
+ };
+
+-static struct
+-{
+- unsigned short size __attribute__ ((packed));
+- unsigned long long * base __attribute__ ((packed));
+-}
+-real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
+-real_mode_idt = { 0x3ff, NULL },
+-no_idt = { 0, NULL };
++static struct Xgt_desc_struct
++real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
++real_mode_idt = { 0x3ff, 0 },
++no_idt = { 0, 0 };
+
+
+ /* This is 16-bit protected mode code to disable paging and the cache,
+diff --git a/arch/i386/kernel/relocate_kernel.S b/arch/i386/kernel/relocate_kernel.S
+index d312616..f151d6f 100644
+--- a/arch/i386/kernel/relocate_kernel.S
++++ b/arch/i386/kernel/relocate_kernel.S
+@@ -7,16 +7,138 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/page.h>
++#include <asm/kexec.h>
++
++/*
++ * Must be relocatable PIC code callable as a C function
++ */
++
++#define PTR(x) (x << 2)
++#define PAGE_ALIGNED (1 << PAGE_SHIFT)
++#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */
++#define PAE_PGD_ATTR 0x01 /* _PAGE_PRESENT */
++
++ .text
++ .align PAGE_ALIGNED
++ .globl relocate_kernel
++relocate_kernel:
++ movl 8(%esp), %ebp /* list of pages */
++
++#ifdef CONFIG_X86_PAE
++ /* map the control page at its virtual address */
++
++ movl PTR(VA_PGD)(%ebp), %edi
++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
++ andl $0xc0000000, %eax
++ shrl $27, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_PMD_0)(%ebp), %edx
++ orl $PAE_PGD_ATTR, %edx
++ movl %edx, (%eax)
++
++ movl PTR(VA_PMD_0)(%ebp), %edi
++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
++ andl $0x3fe00000, %eax
++ shrl $18, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_PTE_0)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++
++ movl PTR(VA_PTE_0)(%ebp), %edi
++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
++ andl $0x001ff000, %eax
++ shrl $9, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++
++ /* identity map the control page at its physical address */
++
++ movl PTR(VA_PGD)(%ebp), %edi
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
++ andl $0xc0000000, %eax
++ shrl $27, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_PMD_1)(%ebp), %edx
++ orl $PAE_PGD_ATTR, %edx
++ movl %edx, (%eax)
++
++ movl PTR(VA_PMD_1)(%ebp), %edi
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
++ andl $0x3fe00000, %eax
++ shrl $18, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_PTE_1)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++
++ movl PTR(VA_PTE_1)(%ebp), %edi
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
++ andl $0x001ff000, %eax
++ shrl $9, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++#else
++ /* map the control page at its virtual address */
++
++ movl PTR(VA_PGD)(%ebp), %edi
++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
++ andl $0xffc00000, %eax
++ shrl $20, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_PTE_0)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++
++ movl PTR(VA_PTE_0)(%ebp), %edi
++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
++ andl $0x003ff000, %eax
++ shrl $10, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++
++ /* identity map the control page at its physical address */
++
++ movl PTR(VA_PGD)(%ebp), %edi
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
++ andl $0xffc00000, %eax
++ shrl $20, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_PTE_1)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++
++ movl PTR(VA_PTE_1)(%ebp), %edi
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
++ andl $0x003ff000, %eax
++ shrl $10, %eax
++ addl %edi, %eax
++
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
++ orl $PAGE_ATTR, %edx
++ movl %edx, (%eax)
++#endif
+
+- /*
+- * 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 8(%esp), %ebp /* list of pages */
+ movl 12(%esp), %edx /* start address */
+ movl 16(%esp), %ecx /* cpu_has_pae */
+
+@@ -24,11 +146,26 @@ relocate_new_kernel:
+ pushl $0
+ popfl
+
+- /* set a new stack at the bottom of our page... */
+- lea 4096(%ebp), %esp
++ /* get physical address of control page now */
++ /* this is impossible after page table switch */
++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edi
+
+- /* store the parameters back on the stack */
+- pushl %edx /* store the start address */
++ /* switch to new set of page tables */
++ movl PTR(PA_PGD)(%ebp), %eax
++ movl %eax, %cr3
++
++ /* setup a new stack at the end of the physical control page */
++ lea 4096(%edi), %esp
++
++ /* jump to identity mapped page */
++ movl %edi, %eax
++ addl $(identity_mapped - relocate_kernel), %eax
++ pushl %eax
++ ret
++
++identity_mapped:
++ /* store the start address on the stack */
++ pushl %edx
+
+ /* Set cr0 to a known state:
+ * 31 0 == Paging disabled
+@@ -113,8 +250,3 @@ relocate_new_kernel:
+ 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/semaphore.c b/arch/i386/kernel/semaphore.c
+deleted file mode 100644
+index 98352c3..0000000
+--- a/arch/i386/kernel/semaphore.c
++++ /dev/null
+@@ -1,134 +0,0 @@
+-/*
+- * i386 semaphore implementation.
+- *
+- * (C) Copyright 1999 Linus Torvalds
+- *
+- * Portions Copyright 1999 Red Hat, Inc.
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
+- *
+- * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl at kvack.org>
+- */
+-#include <asm/semaphore.h>
+-
+-/*
+- * The semaphore operations have a special calling sequence that
+- * allow us to do a simpler in-line version of them. These routines
+- * need to convert that sequence back into the C sequence when
+- * there is contention on the semaphore.
+- *
+- * %eax contains the semaphore pointer on entry. Save the C-clobbered
+- * registers (%eax, %edx and %ecx) except %eax whish is either a return
+- * value or just clobbered..
+- */
+-asm(
+-".section .sched.text\n"
+-".align 4\n"
+-".globl __down_failed\n"
+-"__down_failed:\n\t"
+-#if defined(CONFIG_FRAME_POINTER)
+- "pushl %ebp\n\t"
+- "movl %esp,%ebp\n\t"
+-#endif
+- "pushl %edx\n\t"
+- "pushl %ecx\n\t"
+- "call __down\n\t"
+- "popl %ecx\n\t"
+- "popl %edx\n\t"
+-#if defined(CONFIG_FRAME_POINTER)
+- "movl %ebp,%esp\n\t"
+- "popl %ebp\n\t"
+-#endif
+- "ret"
+-);
+-
+-asm(
+-".section .sched.text\n"
+-".align 4\n"
+-".globl __down_failed_interruptible\n"
+-"__down_failed_interruptible:\n\t"
+-#if defined(CONFIG_FRAME_POINTER)
+- "pushl %ebp\n\t"
+- "movl %esp,%ebp\n\t"
+-#endif
+- "pushl %edx\n\t"
+- "pushl %ecx\n\t"
+- "call __down_interruptible\n\t"
+- "popl %ecx\n\t"
+- "popl %edx\n\t"
+-#if defined(CONFIG_FRAME_POINTER)
+- "movl %ebp,%esp\n\t"
+- "popl %ebp\n\t"
+-#endif
+- "ret"
+-);
+-
+-asm(
+-".section .sched.text\n"
+-".align 4\n"
+-".globl __down_failed_trylock\n"
+-"__down_failed_trylock:\n\t"
+-#if defined(CONFIG_FRAME_POINTER)
+- "pushl %ebp\n\t"
+- "movl %esp,%ebp\n\t"
+-#endif
+- "pushl %edx\n\t"
+- "pushl %ecx\n\t"
+- "call __down_trylock\n\t"
+- "popl %ecx\n\t"
+- "popl %edx\n\t"
+-#if defined(CONFIG_FRAME_POINTER)
+- "movl %ebp,%esp\n\t"
+- "popl %ebp\n\t"
+-#endif
+- "ret"
+-);
+-
+-asm(
+-".section .sched.text\n"
+-".align 4\n"
+-".globl __up_wakeup\n"
+-"__up_wakeup:\n\t"
+- "pushl %edx\n\t"
+- "pushl %ecx\n\t"
+- "call __up\n\t"
+- "popl %ecx\n\t"
+- "popl %edx\n\t"
+- "ret"
+-);
+-
+-/*
+- * rw spinlock fallbacks
+- */
+-#if defined(CONFIG_SMP)
+-asm(
+-".section .sched.text\n"
+-".align 4\n"
+-".globl __write_lock_failed\n"
+-"__write_lock_failed:\n\t"
+- LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ",(%eax)\n"
+-"1: rep; nop\n\t"
+- "cmpl $" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+- "jne 1b\n\t"
+- LOCK_PREFIX "subl $" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+- "jnz __write_lock_failed\n\t"
+- "ret"
+-);
+-
+-asm(
+-".section .sched.text\n"
+-".align 4\n"
+-".globl __read_lock_failed\n"
+-"__read_lock_failed:\n\t"
+- LOCK_PREFIX "incl (%eax)\n"
+-"1: rep; nop\n\t"
+- "cmpl $1,(%eax)\n\t"
+- "js 1b\n\t"
+- LOCK_PREFIX "decl (%eax)\n\t"
+- "js __read_lock_failed\n\t"
+- "ret"
+-);
+-#endif
+diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
+index f168220..141041d 100644
+--- a/arch/i386/kernel/setup.c
++++ b/arch/i386/kernel/setup.c
+@@ -53,6 +53,7 @@
+ #include <asm/apic.h>
+ #include <asm/e820.h>
+ #include <asm/mpspec.h>
++#include <asm/mmzone.h>
+ #include <asm/setup.h>
+ #include <asm/arch_hooks.h>
+ #include <asm/sections.h>
+@@ -89,18 +90,6 @@ EXPORT_SYMBOL(boot_cpu_data);
+
+ unsigned long mmu_cr4_features;
+
+-#ifdef CONFIG_ACPI
+- int acpi_disabled = 0;
+-#else
+- int acpi_disabled = 1;
+-#endif
+-EXPORT_SYMBOL(acpi_disabled);
+-
+-#ifdef CONFIG_ACPI
+-int __initdata acpi_force = 0;
+-extern acpi_interrupt_flags acpi_sci_flags;
+-#endif
+-
+ /* for MCA, but anyone else can use it if they want */
+ unsigned int machine_id;
+ #ifdef CONFIG_MCA
+@@ -148,7 +137,6 @@ EXPORT_SYMBOL(ist_info);
+ struct e820map e820;
+
+ extern void early_cpu_init(void);
+-extern void generic_apic_probe(char *);
+ extern int root_mountflags;
+
+ unsigned long saved_videomode;
+@@ -221,9 +209,6 @@ static struct resource adapter_rom_resou
+ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+ } };
+
+-#define ADAPTER_ROM_RESOURCES \
+- (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
+-
+ static struct resource video_rom_resource = {
+ .name = "Video ROM",
+ .start = 0xc0000,
+@@ -285,9 +270,6 @@ static struct resource standard_io_resou
+ .flags = IORESOURCE_BUSY | IORESOURCE_IO
+ } };
+
+-#define STANDARD_IO_RESOURCES \
+- (sizeof standard_io_resources / sizeof standard_io_resources[0])
+-
+ #define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+ static int __init romchecksum(unsigned char *rom, unsigned long length)
+@@ -344,7 +326,7 @@ static void __init probe_roms(void)
+ }
+
+ /* check for adapter roms on 2k boundaries */
+- for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
++ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
+ rom = isa_bus_to_virt(start);
+ if (!romsignature(rom))
+ continue;
+@@ -700,238 +682,150 @@ static inline void copy_edd(void)
+ }
+ #endif
+
+-static void __init parse_cmdline_early (char ** cmdline_p)
+-{
+- char c = ' ', *to = command_line, *from = saved_command_line;
+- int len = 0;
+- int userdef = 0;
++static int __initdata user_defined_memmap = 0;
+
+- /* Save unparsed command line copy for /proc/cmdline */
+- saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
++/*
++ * "mem=nopentium" disables the 4MB page tables.
++ * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
++ * to <mem>, overriding the bios size.
++ * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from
++ * <start> to <start>+<mem>, overriding the bios size.
++ *
++ * HPA tells me bootloaders need to parse mem=, so no new
++ * option should be mem= [also see Documentation/i386/boot.txt]
++ */
++static int __init parse_mem(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
+
+- for (;;) {
+- if (c != ' ')
+- goto next_char;
+- /*
+- * "mem=nopentium" disables the 4MB page tables.
+- * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
+- * to <mem>, overriding the bios size.
+- * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from
+- * <start> to <start>+<mem>, overriding the bios size.
+- *
+- * HPA tells me bootloaders need to parse mem=, so no new
+- * option should be mem= [also see Documentation/i386/boot.txt]
++ if (strcmp(arg, "nopentium") == 0) {
++ clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
++ disable_pse = 1;
++ } else {
++ /* If the user specifies memory size, we
++ * limit the BIOS-provided memory map to
++ * that size. exactmap can be used to specify
++ * the exact map. mem=number can be used to
++ * trim the existing memory map.
+ */
+- if (!memcmp(from, "mem=", 4)) {
+- if (to != command_line)
+- to--;
+- if (!memcmp(from+4, "nopentium", 9)) {
+- from += 9+4;
+- clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
+- disable_pse = 1;
+- } else {
+- /* If the user specifies memory size, we
+- * limit the BIOS-provided memory map to
+- * that size. exactmap can be used to specify
+- * the exact map. mem=number can be used to
+- * trim the existing memory map.
+- */
+- unsigned long long mem_size;
++ unsigned long long mem_size;
+
+- mem_size = memparse(from+4, &from);
+- limit_regions(mem_size);
+- userdef=1;
+- }
+- }
+-
+- else if (!memcmp(from, "memmap=", 7)) {
+- 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;
+- } else {
+- /* If the user specifies memory size, we
+- * limit the BIOS-provided memory map to
+- * that size. exactmap can be used to specify
+- * the exact map. mem=number can be used to
+- * trim the existing memory map.
+- */
+- unsigned long long start_at, mem_size;
+-
+- mem_size = memparse(from+7, &from);
+- if (*from == '@') {
+- start_at = memparse(from+1, &from);
+- add_memory_region(start_at, mem_size, E820_RAM);
+- } else if (*from == '#') {
+- start_at = memparse(from+1, &from);
+- add_memory_region(start_at, mem_size, E820_ACPI);
+- } else if (*from == '$') {
+- start_at = memparse(from+1, &from);
+- add_memory_region(start_at, mem_size, E820_RESERVED);
+- } else {
+- limit_regions(mem_size);
+- userdef=1;
+- }
+- }
+- }
+-
+- else if (!memcmp(from, "noexec=", 7))
+- noexec_setup(from + 7);
++ mem_size = memparse(arg, &arg);
++ limit_regions(mem_size);
++ user_defined_memmap = 1;
++ }
++ return 0;
++}
++early_param("mem", parse_mem);
+
++static int __init parse_memmap(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
+
+-#ifdef CONFIG_X86_SMP
+- /*
+- * If the BIOS enumerates physical processors before logical,
+- * maxcpus=N at enumeration-time can be used to disable HT.
++ if (strcmp(arg, "exactmap") == 0) {
++#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.
+ */
+- else if (!memcmp(from, "maxcpus=", 8)) {
+- extern unsigned int maxcpus;
+-
+- maxcpus = simple_strtoul(from + 8, NULL, 0);
+- }
++ find_max_pfn();
++ saved_max_pfn = max_pfn;
+ #endif
+-
+-#ifdef CONFIG_ACPI
+- /* "acpi=off" disables both ACPI table parsing and interpreter */
+- else if (!memcmp(from, "acpi=off", 8)) {
+- disable_acpi();
+- }
+-
+- /* acpi=force to over-ride black-list */
+- else if (!memcmp(from, "acpi=force", 10)) {
+- acpi_force = 1;
+- acpi_ht = 1;
+- acpi_disabled = 0;
+- }
+-
+- /* acpi=strict disables out-of-spec workarounds */
+- else if (!memcmp(from, "acpi=strict", 11)) {
+- acpi_strict = 1;
+- }
+-
+- /* Limit ACPI just to boot-time to enable HT */
+- else if (!memcmp(from, "acpi=ht", 7)) {
+- if (!acpi_force)
+- disable_acpi();
+- acpi_ht = 1;
+- }
+-
+- /* "pci=noacpi" disable ACPI IRQ routing and PCI scan */
+- else if (!memcmp(from, "pci=noacpi", 10)) {
+- acpi_disable_pci();
+- }
+- /* "acpi=noirq" disables ACPI interrupt routing */
+- else if (!memcmp(from, "acpi=noirq", 10)) {
+- acpi_noirq_set();
++ e820.nr_map = 0;
++ user_defined_memmap = 1;
++ } else {
++ /* If the user specifies memory size, we
++ * limit the BIOS-provided memory map to
++ * that size. exactmap can be used to specify
++ * the exact map. mem=number can be used to
++ * trim the existing memory map.
++ */
++ unsigned long long start_at, mem_size;
++
++ mem_size = memparse(arg, &arg);
++ if (*arg == '@') {
++ start_at = memparse(arg+1, &arg);
++ add_memory_region(start_at, mem_size, E820_RAM);
++ } else if (*arg == '#') {
++ start_at = memparse(arg+1, &arg);
++ add_memory_region(start_at, mem_size, E820_ACPI);
++ } else if (*arg == '$') {
++ start_at = memparse(arg+1, &arg);
++ add_memory_region(start_at, mem_size, E820_RESERVED);
++ } else {
++ limit_regions(mem_size);
++ user_defined_memmap = 1;
+ }
++ }
++ return 0;
++}
++early_param("memmap", parse_memmap);
+
+- else if (!memcmp(from, "acpi_sci=edge", 13))
+- acpi_sci_flags.trigger = 1;
+-
+- else if (!memcmp(from, "acpi_sci=level", 14))
+- acpi_sci_flags.trigger = 3;
+-
+- else if (!memcmp(from, "acpi_sci=high", 13))
+- acpi_sci_flags.polarity = 1;
++#ifdef CONFIG_PROC_VMCORE
++/* elfcorehdr= specifies the location of elf core header
++ * stored by the crashed kernel.
++ */
++static int __init parse_elfcorehdr(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
+
+- else if (!memcmp(from, "acpi_sci=low", 12))
+- acpi_sci_flags.polarity = 3;
++ elfcorehdr_addr = memparse(arg, &arg);
++ return 0;
++}
++early_param("elfcorehdr", parse_elfcorehdr);
++#endif /* CONFIG_PROC_VMCORE */
+
+-#ifdef CONFIG_X86_IO_APIC
+- else if (!memcmp(from, "acpi_skip_timer_override", 24))
+- acpi_skip_timer_override = 1;
++/*
++ * highmem=size forces highmem to be exactly 'size' bytes.
++ * This works even on boxes that have no highmem otherwise.
++ * This also works to reduce highmem size on bigger boxes.
++ */
++static int __init parse_highmem(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
+
+- if (!memcmp(from, "disable_timer_pin_1", 19))
+- disable_timer_pin_1 = 1;
+- if (!memcmp(from, "enable_timer_pin_1", 18))
+- disable_timer_pin_1 = -1;
++ highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT;
++ return 0;
++}
++early_param("highmem", parse_highmem);
+
+- /* disable IO-APIC */
+- else if (!memcmp(from, "noapic", 6))
+- disable_ioapic_setup();
+-#endif /* CONFIG_X86_IO_APIC */
+-#endif /* CONFIG_ACPI */
++/*
++ * vmalloc=size forces the vmalloc area to be exactly 'size'
++ * bytes. This can be used to increase (or decrease) the
++ * vmalloc area - the default is 128m.
++ */
++static int __init parse_vmalloc(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+- /* enable local APIC */
+- else if (!memcmp(from, "lapic", 5))
+- lapic_enable();
++ __VMALLOC_RESERVE = memparse(arg, &arg);
++ return 0;
++}
++early_param("vmalloc", parse_vmalloc);
+
+- /* disable local APIC */
+- else if (!memcmp(from, "nolapic", 6))
+- lapic_disable();
+-#endif /* CONFIG_X86_LOCAL_APIC */
++/*
++ * reservetop=size reserves a hole at the top of the kernel address space which
++ * a hypervisor can load into later. Needed for dynamically loaded hypervisors,
++ * so relocating the fixmap can be done before paging initialization.
++ */
++static int __init parse_reservetop(char *arg)
++{
++ unsigned long address;
+
+-#ifdef CONFIG_KEXEC
+- /* crashkernel=size at 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_PROC_VMCORE
+- /* 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
++ if (!arg)
++ return -EINVAL;
+
+- /*
+- * highmem=size forces highmem to be exactly 'size' bytes.
+- * This works even on boxes that have no highmem otherwise.
+- * This also works to reduce highmem size on bigger boxes.
+- */
+- else if (!memcmp(from, "highmem=", 8))
+- highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
+-
+- /*
+- * vmalloc=size forces the vmalloc area to be exactly 'size'
+- * bytes. This can be used to increase (or decrease) the
+- * vmalloc area - the default is 128m.
+- */
+- else if (!memcmp(from, "vmalloc=", 8))
+- __VMALLOC_RESERVE = memparse(from+8, &from);
+-
+- next_char:
+- c = *(from++);
+- if (!c)
+- break;
+- if (COMMAND_LINE_SIZE <= ++len)
+- break;
+- *(to++) = c;
+- }
+- *to = '\0';
+- *cmdline_p = command_line;
+- if (userdef) {
+- printk(KERN_INFO "user-defined physical RAM map:\n");
+- print_memory_map("user");
+- }
++ address = memparse(arg, &arg);
++ reserve_top_address(address);
++ return 0;
+ }
++early_param("reservetop", parse_reservetop);
+
+ /*
+ * Callback for efi_memory_walk.
+@@ -952,7 +846,7 @@ efi_find_max_pfn(unsigned long start, un
+ static int __init
+ efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg)
+ {
+- memory_present(0, start, end);
++ memory_present(0, PFN_UP(start), PFN_DOWN(end));
+ return 0;
+ }
+
+@@ -1170,6 +1064,14 @@ static unsigned long __init setup_memory
+ }
+ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+ pages_to_mb(highend_pfn - highstart_pfn));
++ num_physpages = highend_pfn;
++ high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
++#else
++ num_physpages = max_low_pfn;
++ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
++#endif
++#ifdef CONFIG_FLATMEM
++ max_mapnr = num_physpages;
+ #endif
+ printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+ pages_to_mb(max_low_pfn));
+@@ -1181,22 +1083,19 @@ static unsigned long __init setup_memory
+
+ void __init zone_sizes_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+- unsigned int max_dma, low;
+-
+- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+- low = max_low_pfn;
+-
+- if (low < max_dma)
+- zones_size[ZONE_DMA] = low;
+- else {
+- zones_size[ZONE_DMA] = max_dma;
+- zones_size[ZONE_NORMAL] = low - max_dma;
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] =
++ virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
++ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ #ifdef CONFIG_HIGHMEM
+- zones_size[ZONE_HIGHMEM] = highend_pfn - low;
++ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
++ add_active_range(0, 0, highend_pfn);
++#else
++ add_active_range(0, 0, max_low_pfn);
+ #endif
+- }
+- free_area_init(zones_size);
++
++ free_area_init_nodes(max_zone_pfns);
+ }
+ #else
+ extern unsigned long __init setup_memory(void);
+@@ -1258,7 +1157,7 @@ void __init setup_bootmem_allocator(void
+ */
+ find_smp_config();
+ #endif
+-
++ numa_kva_reserve();
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (LOADER_TYPE && INITRD_START) {
+ if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
+@@ -1366,7 +1265,7 @@ static int __init request_standard_resou
+ request_resource(&iomem_resource, &video_ram_resource);
+
+ /* request I/O space for devices used on all i[345]86 PCs */
+- for (i = 0; i < STANDARD_IO_RESOURCES; i++)
++ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
+ request_resource(&ioport_resource, &standard_io_resources[i]);
+ return 0;
+ }
+@@ -1499,17 +1398,15 @@ void __init setup_arch(char **cmdline_p)
+ data_resource.start = virt_to_phys(_etext);
+ data_resource.end = virt_to_phys(_edata)-1;
+
+- parse_cmdline_early(cmdline_p);
++ parse_early_param();
+
+-#ifdef CONFIG_EARLY_PRINTK
+- {
+- char *s = strstr(*cmdline_p, "earlyprintk=");
+- if (s) {
+- setup_early_printk(strchr(s, '=') + 1);
+- printk("early console enabled\n");
+- }
++ if (user_defined_memmap) {
++ printk(KERN_INFO "user-defined physical RAM map:\n");
++ print_memory_map("user");
+ }
+-#endif
++
++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE);
++ *cmdline_p = command_line;
+
+ max_low_pfn = setup_memory();
+
+@@ -1538,7 +1435,7 @@ void __init setup_arch(char **cmdline_p)
+ dmi_scan_machine();
+
+ #ifdef CONFIG_X86_GENERICARCH
+- generic_apic_probe(*cmdline_p);
++ generic_apic_probe();
+ #endif
+ if (efi_enabled)
+ efi_map_memmap();
+@@ -1550,9 +1447,11 @@ void __init setup_arch(char **cmdline_p)
+ acpi_boot_table_init();
+ #endif
+
++#ifdef CONFIG_PCI
+ #ifdef CONFIG_X86_IO_APIC
+ check_acpi_pci(); /* Checks more than just ACPI actually */
+ #endif
++#endif
+
+ #ifdef CONFIG_ACPI
+ acpi_boot_init();
+diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
+index c10789d..31e5c65 100644
+--- a/arch/i386/kernel/smp.c
++++ b/arch/i386/kernel/smp.c
+@@ -321,6 +321,7 @@ static inline void leave_mm (unsigned lo
+
+ fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ unsigned long cpu;
+
+ cpu = get_cpu();
+@@ -351,6 +352,7 @@ fastcall void smp_invalidate_interrupt(s
+ smp_mb__after_clear_bit();
+ out:
+ put_cpu_no_resched();
++ set_irq_regs(old_regs);
+ }
+
+ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+@@ -605,11 +607,14 @@ void smp_send_stop(void)
+ */
+ fastcall void smp_reschedule_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ ack_APIC_irq();
++ set_irq_regs(old_regs);
+ }
+
+ fastcall void smp_call_function_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ void (*func) (void *info) = call_data->func;
+ void *info = call_data->info;
+ int wait = call_data->wait;
+@@ -632,5 +637,99 @@ fastcall void smp_call_function_interrup
+ mb();
+ atomic_inc(&call_data->finished);
+ }
++ set_irq_regs(old_regs);
+ }
+
++/*
++ * this function sends a 'generic call function' IPI to one other CPU
++ * in the system.
++ *
++ * cpu is a standard Linux logical CPU number.
++ */
++static void
++__smp_call_function_single(int cpu, void (*func) (void *info), void *info,
++ int nonatomic, int wait)
++{
++ struct call_data_struct data;
++ int cpus = 1;
++
++ data.func = func;
++ data.info = info;
++ atomic_set(&data.started, 0);
++ data.wait = wait;
++ if (wait)
++ atomic_set(&data.finished, 0);
++
++ call_data = &data;
++ wmb();
++ /* Send a message to all other CPUs and wait for them to respond */
++ send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR);
++
++ /* Wait for response */
++ while (atomic_read(&data.started) != cpus)
++ cpu_relax();
++
++ if (!wait)
++ return;
++
++ while (atomic_read(&data.finished) != cpus)
++ cpu_relax();
++}
++
++/*
++ * smp_call_function_single - Run a function on another CPU
++ * @func: The function to run. This must be fast and non-blocking.
++ * @info: An arbitrary pointer to pass to the function.
++ * @nonatomic: Currently unused.
++ * @wait: If true, wait until function has completed on other CPUs.
++ *
++ * Retrurns 0 on success, else a negative status code.
++ *
++ * Does not return until the remote CPU is nearly ready to execute <func>
++ * or is or has executed.
++ */
++
++int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
++ int nonatomic, int wait)
++{
++ /* prevent preemption and reschedule on another processor */
++ int me = get_cpu();
++ if (cpu == me) {
++ WARN_ON(1);
++ put_cpu();
++ return -EBUSY;
++ }
++ spin_lock_bh(&call_lock);
++ __smp_call_function_single(cpu, func, info, nonatomic, wait);
++ spin_unlock_bh(&call_lock);
++ put_cpu();
++ return 0;
++}
++EXPORT_SYMBOL(smp_call_function_single);
++
++static int convert_apicid_to_cpu(int apic_id)
++{
++ int i;
++
++ for (i = 0; i < NR_CPUS; i++) {
++ if (x86_cpu_to_apicid[i] == apic_id)
++ return i;
++ }
++ return -1;
++}
++
++int safe_smp_processor_id(void)
++{
++ int apicid, cpuid;
++
++ if (!boot_cpu_has(X86_FEATURE_APIC))
++ return 0;
++
++ apicid = hard_smp_processor_id();
++ if (apicid == BAD_APICID)
++ return 0;
++
++ cpuid = convert_apicid_to_cpu(apicid);
++
++ return cpuid >= 0 ? cpuid : 0;
++}
+diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
+index f948419..4bb8b77 100644
+--- a/arch/i386/kernel/smpboot.c
++++ b/arch/i386/kernel/smpboot.c
+@@ -102,6 +102,8 @@ u8 x86_cpu_to_apicid[NR_CPUS] __read_mos
+ { [0 ... NR_CPUS-1] = 0xff };
+ EXPORT_SYMBOL(x86_cpu_to_apicid);
+
++u8 apicid_2_node[MAX_APICID];
++
+ /*
+ * Trampoline 80x86 program as an array.
+ */
+@@ -177,6 +179,9 @@ static void __devinit smp_store_cpu_info
+ */
+ if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
+
++ if (num_possible_cpus() == 1)
++ goto valid_k7;
++
+ /* Athlon 660/661 is valid. */
+ if ((c->x86_model==6) && ((c->x86_mask==0) || (c->x86_mask==1)))
+ goto valid_k7;
+@@ -607,6 +612,7 @@ extern struct {
+ /* which logical CPUs are on which nodes */
+ cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly =
+ { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
++EXPORT_SYMBOL(node_2_cpu_mask);
+ /* which node each logical CPU is on */
+ int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
+ EXPORT_SYMBOL(cpu_2_node);
+@@ -642,9 +648,13 @@ static void map_cpu_to_logical_apicid(vo
+ {
+ int cpu = smp_processor_id();
+ int apicid = logical_smp_processor_id();
++ int node = apicid_to_node(apicid);
++
++ if (!node_online(node))
++ node = first_online_node;
+
+ cpu_2_logical_apicid[cpu] = apicid;
+- map_cpu_to_node(cpu, apicid_to_node(apicid));
++ map_cpu_to_node(cpu, node);
+ }
+
+ static void unmap_cpu_to_logical_apicid(int cpu)
+@@ -947,6 +957,7 @@ static int __devinit do_boot_cpu(int api
+
+ irq_ctx_init(cpu);
+
++ x86_cpu_to_apicid[cpu] = apicid;
+ /*
+ * This grunge runs the startup process for
+ * the targeted processor.
+@@ -1051,7 +1062,7 @@ static void __cpuinit do_warm_boot_cpu(v
+
+ static int __cpuinit __smp_prepare_cpu(int cpu)
+ {
+- DECLARE_COMPLETION(done);
++ DECLARE_COMPLETION_ONSTACK(done);
+ struct warm_boot_cpu_info info;
+ struct work_struct task;
+ int apicid, ret;
+@@ -1372,7 +1383,8 @@ int __cpu_disable(void)
+ */
+ if (cpu == 0)
+ return -EBUSY;
+-
++ if (nmi_watchdog == NMI_LOCAL_APIC)
++ stop_apic_nmi_watchdog(NULL);
+ clear_local_APIC();
+ /* Allow any queued timer interrupts to get serviced */
+ local_irq_enable();
+@@ -1486,3 +1498,16 @@ void __init smp_intr_init(void)
+ /* IPI for generic function call */
+ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+ }
++
++/*
++ * If the BIOS enumerates physical processors before logical,
++ * maxcpus=N at enumeration-time can be used to disable HT.
++ */
++static int __init parse_maxcpus(char *arg)
++{
++ extern unsigned int maxcpus;
++
++ maxcpus = simple_strtoul(arg, NULL, 0);
++ return 0;
++}
++early_param("maxcpus", parse_maxcpus);
+diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
+index b1809c9..f7e735c 100644
+--- a/arch/i386/kernel/srat.c
++++ b/arch/i386/kernel/srat.c
+@@ -30,6 +30,7 @@
+ #include <linux/nodemask.h>
+ #include <asm/srat.h>
+ #include <asm/topology.h>
++#include <asm/smp.h>
+
+ /*
+ * proximity macros and definitions
+@@ -42,7 +43,7 @@
+ #define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8)
+ static u8 pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */
+
+-#define MAX_CHUNKS_PER_NODE 4
++#define MAX_CHUNKS_PER_NODE 3
+ #define MAXCHUNKS (MAX_CHUNKS_PER_NODE * MAX_NUMNODES)
+ struct node_memory_chunk_s {
+ unsigned long start_pfn;
+@@ -54,8 +55,7 @@ struct node_memory_chunk_s {
+ static struct node_memory_chunk_s node_memory_chunk[MAXCHUNKS];
+
+ static int num_memory_chunks; /* total number of memory chunks */
+-static int zholes_size_init;
+-static unsigned long zholes_size[MAX_NUMNODES * MAX_NR_ZONES];
++static u8 __initdata apicid_to_pxm[MAX_APICID];
+
+ extern void * boot_ioremap(unsigned long, unsigned long);
+
+@@ -71,6 +71,8 @@ static void __init parse_cpu_affinity_st
+ /* mark this node as "seen" in node bitmap */
+ BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain);
+
++ apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain;
++
+ printk("CPU 0x%02X in proximity domain 0x%02X\n",
+ cpu_affinity->apic_id, cpu_affinity->proximity_domain);
+ }
+@@ -135,50 +137,6 @@ static void __init parse_memory_affinity
+ "enabled and removable" : "enabled" ) );
+ }
+
+-#if MAX_NR_ZONES != 4
+-#error "MAX_NR_ZONES != 4, chunk_to_zone requires review"
+-#endif
+-/* Take a chunk of pages from page frame cstart to cend and count the number
+- * of pages in each zone, returned via zones[].
+- */
+-static __init void chunk_to_zones(unsigned long cstart, unsigned long cend,
+- unsigned long *zones)
+-{
+- unsigned long max_dma;
+- extern unsigned long max_low_pfn;
+-
+- int z;
+- unsigned long rend;
+-
+- /* FIXME: MAX_DMA_ADDRESS and max_low_pfn are trying to provide
+- * similarly scoped information and should be handled in a consistant
+- * manner.
+- */
+- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+-
+- /* Split the hole into the zones in which it falls. Repeatedly
+- * take the segment in which the remaining hole starts, round it
+- * to the end of that zone.
+- */
+- memset(zones, 0, MAX_NR_ZONES * sizeof(long));
+- while (cstart < cend) {
+- if (cstart < max_dma) {
+- z = ZONE_DMA;
+- rend = (cend < max_dma)? cend : max_dma;
+-
+- } else if (cstart < max_low_pfn) {
+- z = ZONE_NORMAL;
+- rend = (cend < max_low_pfn)? cend : max_low_pfn;
+-
+- } else {
+- z = ZONE_HIGHMEM;
+- rend = cend;
+- }
+- zones[z] += rend - cstart;
+- cstart = rend;
+- }
+-}
+-
+ /*
+ * The SRAT table always lists ascending addresses, so can always
+ * assume that the first "start" address that you see is the real
+@@ -223,7 +181,6 @@ static int __init acpi20_parse_srat(stru
+
+ memset(pxm_bitmap, 0, sizeof(pxm_bitmap)); /* init proximity domain bitmap */
+ memset(node_memory_chunk, 0, sizeof(node_memory_chunk));
+- memset(zholes_size, 0, sizeof(zholes_size));
+
+ num_memory_chunks = 0;
+ while (p < end) {
+@@ -282,11 +239,15 @@ static int __init acpi20_parse_srat(stru
+ printk("Number of logical nodes in system = %d\n", num_online_nodes());
+ printk("Number of memory chunks in system = %d\n", num_memory_chunks);
+
++ for (i = 0; i < MAX_APICID; i++)
++ apicid_2_node[i] = pxm_to_node(apicid_to_pxm[i]);
++
+ for (j = 0; j < num_memory_chunks; j++){
+ struct node_memory_chunk_s * chunk = &node_memory_chunk[j];
+ printk("chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
+ j, chunk->nid, chunk->start_pfn, chunk->end_pfn);
+ node_read_chunk(chunk->nid, chunk);
++ add_active_range(chunk->nid, chunk->start_pfn, chunk->end_pfn);
+ }
+
+ for_each_online_node(nid) {
+@@ -395,57 +356,7 @@ int __init get_memcfg_from_srat(void)
+ return acpi20_parse_srat((struct acpi_table_srat *)header);
+ }
+ out_err:
++ remove_all_active_ranges();
+ printk("failed to get NUMA memory information from SRAT table\n");
+ return 0;
+ }
+-
+-/* For each node run the memory list to determine whether there are
+- * any memory holes. For each hole determine which ZONE they fall
+- * into.
+- *
+- * NOTE#1: this requires knowledge of the zone boundries and so
+- * _cannot_ be performed before those are calculated in setup_memory.
+- *
+- * NOTE#2: we rely on the fact that the memory chunks are ordered by
+- * start pfn number during setup.
+- */
+-static void __init get_zholes_init(void)
+-{
+- int nid;
+- int c;
+- int first;
+- unsigned long end = 0;
+-
+- for_each_online_node(nid) {
+- first = 1;
+- for (c = 0; c < num_memory_chunks; c++){
+- if (node_memory_chunk[c].nid == nid) {
+- if (first) {
+- end = node_memory_chunk[c].end_pfn;
+- first = 0;
+-
+- } else {
+- /* Record any gap between this chunk
+- * and the previous chunk on this node
+- * against the zones it spans.
+- */
+- chunk_to_zones(end,
+- node_memory_chunk[c].start_pfn,
+- &zholes_size[nid * MAX_NR_ZONES]);
+- }
+- }
+- }
+- }
+-}
+-
+-unsigned long * __init get_zholes_size(int nid)
+-{
+- if (!zholes_size_init) {
+- zholes_size_init++;
+- get_zholes_init();
+- }
+- if (nid >= MAX_NUMNODES || !node_online(nid))
+- printk("%s: nid = %d is invalid/offline. num_online_nodes = %d",
+- __FUNCTION__, nid, num_online_nodes());
+- return &zholes_size[nid * MAX_NR_ZONES];
+-}
+diff --git a/arch/i386/kernel/stacktrace.c b/arch/i386/kernel/stacktrace.c
+deleted file mode 100644
+index e62a037..0000000
+--- a/arch/i386/kernel/stacktrace.c
++++ /dev/null
+@@ -1,98 +0,0 @@
+-/*
+- * arch/i386/kernel/stacktrace.c
+- *
+- * Stack trace management functions
+- *
+- * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo at redhat.com>
+- */
+-#include <linux/sched.h>
+-#include <linux/stacktrace.h>
+-
+-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+-{
+- return p > (void *)tinfo &&
+- p < (void *)tinfo + THREAD_SIZE - 3;
+-}
+-
+-/*
+- * Save stack-backtrace addresses into a stack_trace buffer:
+- */
+-static inline unsigned long
+-save_context_stack(struct stack_trace *trace, unsigned int skip,
+- struct thread_info *tinfo, unsigned long *stack,
+- unsigned long ebp)
+-{
+- unsigned long addr;
+-
+-#ifdef CONFIG_FRAME_POINTER
+- while (valid_stack_ptr(tinfo, (void *)ebp)) {
+- addr = *(unsigned long *)(ebp + 4);
+- if (!skip)
+- trace->entries[trace->nr_entries++] = addr;
+- else
+- skip--;
+- if (trace->nr_entries >= trace->max_entries)
+- break;
+- /*
+- * break out of recursive entries (such as
+- * end_of_stack_stop_unwind_function):
+- */
+- if (ebp == *(unsigned long *)ebp)
+- break;
+-
+- ebp = *(unsigned long *)ebp;
+- }
+-#else
+- while (valid_stack_ptr(tinfo, stack)) {
+- addr = *stack++;
+- if (__kernel_text_address(addr)) {
+- if (!skip)
+- trace->entries[trace->nr_entries++] = addr;
+- else
+- skip--;
+- if (trace->nr_entries >= trace->max_entries)
+- break;
+- }
+- }
+-#endif
+-
+- return ebp;
+-}
+-
+-/*
+- * Save stack-backtrace addresses into a stack_trace buffer.
+- * If all_contexts is set, all contexts (hardirq, softirq and process)
+- * are saved. If not set then only the current context is saved.
+- */
+-void save_stack_trace(struct stack_trace *trace,
+- struct task_struct *task, int all_contexts,
+- unsigned int skip)
+-{
+- unsigned long ebp;
+- unsigned long *stack = &ebp;
+-
+- WARN_ON(trace->nr_entries || !trace->max_entries);
+-
+- if (!task || task == current) {
+- /* Grab ebp right from our regs: */
+- asm ("movl %%ebp, %0" : "=r" (ebp));
+- } else {
+- /* ebp is the last reg pushed by switch_to(): */
+- ebp = *(unsigned long *) task->thread.esp;
+- }
+-
+- while (1) {
+- struct thread_info *context = (struct thread_info *)
+- ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+-
+- ebp = save_context_stack(trace, skip, context, stack, ebp);
+- stack = (unsigned long *)context->previous_esp;
+- if (!all_contexts || !stack ||
+- trace->nr_entries >= trace->max_entries)
+- break;
+- trace->entries[trace->nr_entries++] = ULONG_MAX;
+- if (trace->nr_entries >= trace->max_entries)
+- break;
+- }
+-}
+-
+diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
+index 8fdb1fb..4048397 100644
+--- a/arch/i386/kernel/sys_i386.c
++++ b/arch/i386/kernel/sys_i386.c
+@@ -21,6 +21,7 @@
+ #include <linux/utsname.h>
+
+ #include <asm/uaccess.h>
++#include <asm/unistd.h>
+ #include <asm/ipc.h>
+
+ /*
+@@ -210,7 +211,7 @@ asmlinkage int sys_uname(struct old_utsn
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+- err=copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ return err?-EFAULT:0;
+ }
+@@ -226,16 +227,21 @@ asmlinkage int sys_olduname(struct oldol
+
+ down_read(&uts_sem);
+
+- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+- error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+- error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+- error |= __put_user(0,name->release+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+- error |= __put_user(0,name->version+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+- error |= __put_user(0,name->machine+__OLD_UTS_LEN);
++ error = __copy_to_user(&name->sysname, &utsname()->sysname,
++ __OLD_UTS_LEN);
++ error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
++ __OLD_UTS_LEN);
++ error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->release, &utsname()->release,
++ __OLD_UTS_LEN);
++ error |= __put_user(0, name->release + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->version, &utsname()->version,
++ __OLD_UTS_LEN);
++ error |= __put_user(0, name->version + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->machine, &utsname()->machine,
++ __OLD_UTS_LEN);
++ error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+
+ up_read(&uts_sem);
+
+@@ -243,3 +249,17 @@ asmlinkage int sys_olduname(struct oldol
+
+ return error;
+ }
++
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ long __res;
++ asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
++ : "=a" (__res)
++ : "0" (__NR_execve),"ri" (filename),"c" (argv), "d" (envp) : "memory");
++ return __res;
++}
+diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
+index dd63d47..2697e92 100644
+--- a/arch/i386/kernel/syscall_table.S
++++ b/arch/i386/kernel/syscall_table.S
+@@ -317,3 +317,5 @@ ENTRY(sys_call_table)
+ .long sys_tee /* 315 */
+ .long sys_vmsplice
+ .long sys_move_pages
++ .long sys_getcpu
++ .long sys_epoll_pwait
+diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
+index edd00f6..78af572 100644
+--- a/arch/i386/kernel/time.c
++++ b/arch/i386/kernel/time.c
+@@ -76,8 +76,6 @@ int pit_latch_buggy; /* ext
+ unsigned int cpu_khz; /* Detected as we calibrate the TSC */
+ EXPORT_SYMBOL(cpu_khz);
+
+-extern unsigned long wall_jiffies;
+-
+ DEFINE_SPINLOCK(rtc_lock);
+ EXPORT_SYMBOL(rtc_lock);
+
+@@ -130,25 +128,40 @@ static int set_rtc_mmss(unsigned long no
+
+ int timer_ack;
+
+-#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
+ unsigned long profile_pc(struct pt_regs *regs)
+ {
+ unsigned long pc = instruction_pointer(regs);
+
+- if (!user_mode_vm(regs) && in_lock_functions(pc))
++#ifdef CONFIG_SMP
++ if (!user_mode_vm(regs) && in_lock_functions(pc)) {
++#ifdef CONFIG_FRAME_POINTER
+ return *(unsigned long *)(regs->ebp + 4);
+-
++#else
++ unsigned long *sp;
++ if ((regs->xcs & 3) == 0)
++ sp = (unsigned long *)®s->esp;
++ else
++ sp = (unsigned long *)regs->esp;
++ /* Return address is either directly at stack pointer
++ or above a saved eflags. Eflags has bits 22-31 zero,
++ kernel addresses don't. */
++ if (sp[0] >> 22)
++ return sp[0];
++ if (sp[1] >> 22)
++ return sp[1];
++#endif
++ }
++#endif
+ return pc;
+ }
+ EXPORT_SYMBOL(profile_pc);
+-#endif
+
+ /*
+ * This is the same as the above, except we _also_ save the current
+ * Time Stamp Counter value at the time of the timer interrupt, so that
+ * we later on can estimate the time of day more exactly.
+ */
+-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t timer_interrupt(int irq, void *dev_id)
+ {
+ /*
+ * Here we are in the timer irq handler. We just have irqs locally
+@@ -175,7 +188,7 @@ irqreturn_t timer_interrupt(int irq, voi
+ }
+ #endif
+
+- do_timer_interrupt_hook(regs);
++ do_timer_interrupt_hook();
+
+
+ if (MCA_bus) {
+@@ -188,15 +201,15 @@ irqreturn_t timer_interrupt(int irq, voi
+ high bit of the PPI port B (0x61). Note that some PS/2s,
+ notably the 55SX, work fine if this is removed. */
+
+- irq = inb_p( 0x61 ); /* read the current state */
+- outb_p( irq|0x80, 0x61 ); /* reset the IRQ */
++ u8 irq_v = inb_p( 0x61 ); /* read the current state */
++ outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */
+ }
+
+ write_sequnlock(&xtime_lock);
+
+ #ifdef CONFIG_X86_LOCAL_APIC
+ if (using_apic_timer)
+- smp_send_timer_broadcast_ipi(regs);
++ smp_send_timer_broadcast_ipi();
+ #endif
+
+ return IRQ_HANDLED;
+@@ -270,16 +283,19 @@ void notify_arch_cmos_timer(void)
+ mod_timer(&sync_cmos_timer, jiffies + 1);
+ }
+
+-static long clock_cmos_diff, sleep_start;
++static long clock_cmos_diff;
++static unsigned long sleep_start;
+
+ static int timer_suspend(struct sys_device *dev, pm_message_t state)
+ {
+ /*
+ * Estimate time zone so that set_time can update the clock
+ */
+- clock_cmos_diff = -get_cmos_time();
++ unsigned long ctime = get_cmos_time();
++
++ clock_cmos_diff = -ctime;
+ clock_cmos_diff += get_seconds();
+- sleep_start = get_cmos_time();
++ sleep_start = ctime;
+ return 0;
+ }
+
+@@ -287,20 +303,30 @@ static int timer_resume(struct sys_devic
+ {
+ unsigned long flags;
+ unsigned long sec;
+- unsigned long sleep_length;
+-
++ unsigned long ctime = get_cmos_time();
++ long sleep_length = (ctime - sleep_start) * HZ;
++ struct timespec ts;
++
++ if (sleep_length < 0) {
++ printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n");
++ /* The time after the resume must not be earlier than the time
++ * before the suspend or some nasty things will happen
++ */
++ sleep_length = 0;
++ ctime = sleep_start;
++ }
+ #ifdef CONFIG_HPET_TIMER
+ if (is_hpet_enabled())
+ hpet_reenable();
+ #endif
+ setup_pit_timer();
+- sec = get_cmos_time() + clock_cmos_diff;
+- sleep_length = (get_cmos_time() - sleep_start) * HZ;
++
++ sec = ctime + clock_cmos_diff;
++ ts.tv_sec = sec;
++ ts.tv_nsec = 0;
++ do_settimeofday(&ts);
+ write_seqlock_irqsave(&xtime_lock, flags);
+- xtime.tv_sec = sec;
+- xtime.tv_nsec = 0;
+ jiffies_64 += sleep_length;
+- wall_jiffies += sleep_length;
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ touch_softlockup_watchdog();
+ return 0;
+@@ -334,10 +360,11 @@ extern void (*late_time_init)(void);
+ /* Duplicate of time_init() below, with hpet_enable part added */
+ static void __init hpet_time_init(void)
+ {
+- xtime.tv_sec = get_cmos_time();
+- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+- set_normalized_timespec(&wall_to_monotonic,
+- -xtime.tv_sec, -xtime.tv_nsec);
++ struct timespec ts;
++ ts.tv_sec = get_cmos_time();
++ ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
++
++ do_settimeofday(&ts);
+
+ if ((hpet_enable() >= 0) && hpet_use_timer) {
+ printk("Using HPET for base-timer\n");
+@@ -349,6 +376,7 @@ static void __init hpet_time_init(void)
+
+ void __init time_init(void)
+ {
++ struct timespec ts;
+ #ifdef CONFIG_HPET_TIMER
+ if (is_hpet_capable()) {
+ /*
+@@ -359,10 +387,10 @@ void __init time_init(void)
+ return;
+ }
+ #endif
+- xtime.tv_sec = get_cmos_time();
+- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+- set_normalized_timespec(&wall_to_monotonic,
+- -xtime.tv_sec, -xtime.tv_nsec);
++ ts.tv_sec = get_cmos_time();
++ ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
++
++ do_settimeofday(&ts);
+
+ time_init_hook();
+ }
+diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c
+index 14a1376..1a2a979 100644
+--- a/arch/i386/kernel/time_hpet.c
++++ b/arch/i386/kernel/time_hpet.c
+@@ -301,23 +301,25 @@ int hpet_rtc_timer_init(void)
+ hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+ local_irq_save(flags);
++
+ cnt = hpet_readl(HPET_COUNTER);
+ cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
+ hpet_writel(cnt, HPET_T1_CMP);
+ hpet_t1_cmp = cnt;
+- local_irq_restore(flags);
+
+ cfg = hpet_readl(HPET_T1_CFG);
+ cfg &= ~HPET_TN_PERIODIC;
+ cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+ hpet_writel(cfg, HPET_T1_CFG);
+
++ local_irq_restore(flags);
++
+ return 1;
+ }
+
+ static void hpet_rtc_timer_reinit(void)
+ {
+- unsigned int cfg, cnt;
++ unsigned int cfg, cnt, ticks_per_int, lost_ints;
+
+ if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
+ cfg = hpet_readl(HPET_T1_CFG);
+@@ -332,10 +334,33 @@ static void hpet_rtc_timer_reinit(void)
+ hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+ /* It is more accurate to use the comparator value than current count.*/
+- cnt = hpet_t1_cmp;
+- cnt += hpet_tick*HZ/hpet_rtc_int_freq;
+- hpet_writel(cnt, HPET_T1_CMP);
+- hpet_t1_cmp = cnt;
++ ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
++ hpet_t1_cmp += ticks_per_int;
++ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
++
++ /*
++ * If the interrupt handler was delayed too long, the write above tries
++ * to schedule the next interrupt in the past and the hardware would
++ * not interrupt until the counter had wrapped around.
++ * So we have to check that the comparator wasn't set to a past time.
++ */
++ cnt = hpet_readl(HPET_COUNTER);
++ if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
++ lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
++ /* Make sure that, even with the time needed to execute
++ * this code, the next scheduled interrupt has been moved
++ * back to the future: */
++ lost_ints++;
++
++ hpet_t1_cmp += lost_ints * ticks_per_int;
++ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
++
++ if (PIE_on)
++ PIE_count += lost_ints;
++
++ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
++ hpet_rtc_int_freq);
++ }
+ }
+
+ /*
+@@ -416,7 +441,7 @@ int hpet_rtc_dropped_irq(void)
+ return 1;
+ }
+
+-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
+ {
+ struct rtc_time curr_time;
+ unsigned long rtc_int_flag = 0;
+@@ -455,7 +480,7 @@ irqreturn_t hpet_rtc_interrupt(int irq,
+ }
+ if (call_rtc_interrupt) {
+ rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
+- rtc_interrupt(rtc_int_flag, dev_id, regs);
++ rtc_interrupt(rtc_int_flag, dev_id);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/i386/kernel/topology.c b/arch/i386/kernel/topology.c
+index e2e281d..07d6da3 100644
+--- a/arch/i386/kernel/topology.c
++++ b/arch/i386/kernel/topology.c
+@@ -28,6 +28,7 @@
+ #include <linux/init.h>
+ #include <linux/smp.h>
+ #include <linux/nodemask.h>
++#include <linux/mmzone.h>
+ #include <asm/cpu.h>
+
+ static struct i386_cpu cpu_devices[NR_CPUS];
+@@ -55,34 +56,18 @@ EXPORT_SYMBOL(arch_register_cpu);
+ EXPORT_SYMBOL(arch_unregister_cpu);
+ #endif /*CONFIG_HOTPLUG_CPU*/
+
+-
+-
+-#ifdef CONFIG_NUMA
+-#include <linux/mmzone.h>
+-
+ static int __init topology_init(void)
+ {
+ int i;
+
++#ifdef CONFIG_NUMA
+ for_each_online_node(i)
+ register_one_node(i);
++#endif /* CONFIG_NUMA */
+
+ for_each_present_cpu(i)
+ arch_register_cpu(i);
+ return 0;
+ }
+
+-#else /* !CONFIG_NUMA */
+-
+-static int __init topology_init(void)
+-{
+- int i;
+-
+- for_each_present_cpu(i)
+- arch_register_cpu(i);
+- return 0;
+-}
+-
+-#endif /* CONFIG_NUMA */
+-
+ subsys_initcall(topology_init);
+diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
+index 7e9edaf..00489b7 100644
+--- a/arch/i386/kernel/traps.c
++++ b/arch/i386/kernel/traps.c
+@@ -28,6 +28,7 @@
+ #include <linux/kprobes.h>
+ #include <linux/kexec.h>
+ #include <linux/unwind.h>
++#include <linux/uaccess.h>
+
+ #ifdef CONFIG_EISA
+ #include <linux/ioport.h>
+@@ -40,7 +41,6 @@
+
+ #include <asm/processor.h>
+ #include <asm/system.h>
+-#include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/atomic.h>
+ #include <asm/debugreg.h>
+@@ -51,11 +51,14 @@
+ #include <asm/smp.h>
+ #include <asm/arch_hooks.h>
+ #include <asm/kdebug.h>
++#include <asm/stacktrace.h>
+
+ #include <linux/module.h>
+
+ #include "mach_traps.h"
+
++int panic_on_unrecovered_nmi;
++
+ asmlinkage int system_call(void);
+
+ struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
+@@ -118,26 +121,16 @@ static inline int valid_stack_ptr(struct
+ p < (void *)tinfo + THREAD_SIZE - 3;
+ }
+
+-/*
+- * Print one address/symbol entries per line.
+- */
+-static inline void print_addr_and_symbol(unsigned long addr, char *log_lvl)
+-{
+- printk(" [<%08lx>] ", addr);
+-
+- print_symbol("%s\n", addr);
+-}
+-
+ static inline unsigned long print_context_stack(struct thread_info *tinfo,
+ unsigned long *stack, unsigned long ebp,
+- char *log_lvl)
++ struct stacktrace_ops *ops, void *data)
+ {
+ unsigned long addr;
+
+ #ifdef CONFIG_FRAME_POINTER
+ while (valid_stack_ptr(tinfo, (void *)ebp)) {
+ addr = *(unsigned long *)(ebp + 4);
+- print_addr_and_symbol(addr, log_lvl);
++ ops->address(data, addr);
+ /*
+ * break out of recursive entries (such as
+ * end_of_stack_stop_unwind_function):
+@@ -150,30 +143,37 @@ static inline unsigned long print_contex
+ while (valid_stack_ptr(tinfo, stack)) {
+ addr = *stack++;
+ if (__kernel_text_address(addr))
+- print_addr_and_symbol(addr, log_lvl);
++ ops->address(data, addr);
+ }
+ #endif
+ return ebp;
+ }
+
++struct ops_and_data {
++ struct stacktrace_ops *ops;
++ void *data;
++};
++
+ static asmlinkage int
+-show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
++dump_trace_unwind(struct unwind_frame_info *info, void *data)
+ {
++ struct ops_and_data *oad = (struct ops_and_data *)data;
+ int n = 0;
+
+ while (unwind(info) == 0 && UNW_PC(info)) {
+ n++;
+- print_addr_and_symbol(UNW_PC(info), log_lvl);
++ oad->ops->address(oad->data, UNW_PC(info));
+ if (arch_unw_user_mode(info))
+ break;
+ }
+ return n;
+ }
+
+-static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *stack, char *log_lvl)
++void dump_trace(struct task_struct *task, struct pt_regs *regs,
++ unsigned long *stack,
++ struct stacktrace_ops *ops, void *data)
+ {
+- unsigned long ebp;
++ unsigned long ebp = 0;
+
+ if (!task)
+ task = current;
+@@ -181,54 +181,116 @@ static void show_trace_log_lvl(struct ta
+ if (call_trace >= 0) {
+ int unw_ret = 0;
+ struct unwind_frame_info info;
++ struct ops_and_data oad = { .ops = ops, .data = data };
+
+ if (regs) {
+ if (unwind_init_frame_info(&info, task, regs) == 0)
+- unw_ret = show_trace_unwind(&info, log_lvl);
++ unw_ret = dump_trace_unwind(&info, &oad);
+ } else if (task == current)
+- unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl);
++ unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad);
+ else {
+ if (unwind_init_blocked(&info, task) == 0)
+- unw_ret = show_trace_unwind(&info, log_lvl);
++ unw_ret = dump_trace_unwind(&info, &oad);
+ }
+ if (unw_ret > 0) {
+ if (call_trace == 1 && !arch_unw_user_mode(&info)) {
+- print_symbol("DWARF2 unwinder stuck at %s\n",
++ ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n",
+ UNW_PC(&info));
+ if (UNW_SP(&info) >= PAGE_OFFSET) {
+- printk("Leftover inexact backtrace:\n");
++ ops->warning(data, "Leftover inexact backtrace:\n");
+ stack = (void *)UNW_SP(&info);
++ if (!stack)
++ return;
++ ebp = UNW_FP(&info);
+ } else
+- printk("Full inexact backtrace again:\n");
++ ops->warning(data, "Full inexact backtrace again:\n");
+ } else if (call_trace >= 1)
+ return;
+ else
+- printk("Full inexact backtrace again:\n");
++ ops->warning(data, "Full inexact backtrace again:\n");
+ } else
+- printk("Inexact backtrace:\n");
++ ops->warning(data, "Inexact backtrace:\n");
++ }
++ if (!stack) {
++ unsigned long dummy;
++ stack = &dummy;
++ if (task && task != current)
++ stack = (unsigned long *)task->thread.esp;
+ }
+
+- if (task == current) {
+- /* Grab ebp right from our regs */
+- asm ("movl %%ebp, %0" : "=r" (ebp) : );
+- } else {
+- /* ebp is the last reg pushed by switch_to */
+- ebp = *(unsigned long *) task->thread.esp;
++#ifdef CONFIG_FRAME_POINTER
++ if (!ebp) {
++ if (task == current) {
++ /* Grab ebp right from our regs */
++ asm ("movl %%ebp, %0" : "=r" (ebp) : );
++ } else {
++ /* ebp is the last reg pushed by switch_to */
++ ebp = *(unsigned long *) task->thread.esp;
++ }
+ }
++#endif
+
+ while (1) {
+ struct thread_info *context;
+ context = (struct thread_info *)
+ ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+- ebp = print_context_stack(context, stack, ebp, log_lvl);
++ ebp = print_context_stack(context, stack, ebp, ops, data);
++ /* Should be after the line below, but somewhere
++ in early boot context comes out corrupted and we
++ can't reference it -AK */
++ if (ops->stack(data, "IRQ") < 0)
++ break;
+ stack = (unsigned long*)context->previous_esp;
+ if (!stack)
+ break;
+- printk("%s =======================\n", log_lvl);
+ }
+ }
++EXPORT_SYMBOL(dump_trace);
+
+-void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long * stack)
++static void
++print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
++{
++ printk(data);
++ print_symbol(msg, symbol);
++ printk("\n");
++}
++
++static void print_trace_warning(void *data, char *msg)
++{
++ printk("%s%s\n", (char *)data, msg);
++}
++
++static int print_trace_stack(void *data, char *name)
++{
++ return 0;
++}
++
++/*
++ * Print one address/symbol entries per line.
++ */
++static void print_trace_address(void *data, unsigned long addr)
++{
++ printk("%s [<%08lx>] ", (char *)data, addr);
++ print_symbol("%s\n", addr);
++}
++
++static struct stacktrace_ops print_trace_ops = {
++ .warning = print_trace_warning,
++ .warning_symbol = print_trace_warning_symbol,
++ .stack = print_trace_stack,
++ .address = print_trace_address,
++};
++
++static void
++show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
++ unsigned long * stack, char *log_lvl)
++{
++ dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
++ printk("%s =======================\n", log_lvl);
++}
++
++void show_trace(struct task_struct *task, struct pt_regs *regs,
++ unsigned long * stack)
+ {
+ show_trace_log_lvl(task, regs, stack, "");
+ }
+@@ -291,12 +353,13 @@ void show_registers(struct pt_regs *regs
+ ss = regs->xss & 0xffff;
+ }
+ print_modules();
+- printk(KERN_EMERG "CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\n"
+- "EFLAGS: %08lx (%s %.*s) \n",
++ printk(KERN_EMERG "CPU: %d\n"
++ KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n"
++ KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n",
+ smp_processor_id(), 0xffff & regs->xcs, regs->eip,
+- print_tainted(), regs->eflags, system_utsname.release,
+- (int)strcspn(system_utsname.version, " "),
+- system_utsname.version);
++ print_tainted(), regs->eflags, init_utsname()->release,
++ (int)strcspn(init_utsname()->version, " "),
++ init_utsname()->version);
+ print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip);
+ printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
+ regs->eax, regs->ebx, regs->ecx, regs->edx);
+@@ -313,6 +376,8 @@ void show_registers(struct pt_regs *regs
+ */
+ if (in_kernel) {
+ u8 __user *eip;
++ int code_bytes = 64;
++ unsigned char c;
+
+ printk("\n" KERN_EMERG "Stack: ");
+ show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG);
+@@ -320,9 +385,12 @@ void show_registers(struct pt_regs *regs
+ printk(KERN_EMERG "Code: ");
+
+ eip = (u8 __user *)regs->eip - 43;
+- for (i = 0; i < 64; i++, eip++) {
+- unsigned char c;
+-
++ if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
++ /* try starting at EIP */
++ eip = (u8 __user *)regs->eip;
++ code_bytes = 32;
++ }
++ for (i = 0; i < code_bytes; i++, eip++) {
+ if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
+ printk(" Bad EIP value.");
+ break;
+@@ -343,7 +411,7 @@ static void handle_BUG(struct pt_regs *r
+
+ if (eip < PAGE_OFFSET)
+ return;
+- if (__get_user(ud2, (unsigned short __user *)eip))
++ if (probe_kernel_address((unsigned short __user *)eip, ud2))
+ return;
+ if (ud2 != 0x0b0f)
+ return;
+@@ -356,7 +424,8 @@ static void handle_BUG(struct pt_regs *r
+ char *file;
+ char c;
+
+- if (__get_user(line, (unsigned short __user *)(eip + 2)))
++ if (probe_kernel_address((unsigned short __user *)(eip + 2),
++ line))
+ break;
+ if (__get_user(file, (char * __user *)(eip + 4)) ||
+ (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
+@@ -629,18 +698,24 @@ gp_in_kernel:
+ }
+ }
+
+-static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
++static __kprobes void
++mem_parity_error(unsigned char reason, struct pt_regs * regs)
+ {
+- printk(KERN_EMERG "Uhhuh. NMI received. Dazed and confused, but trying "
+- "to continue\n");
++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
++ "CPU %d.\n", reason, smp_processor_id());
+ printk(KERN_EMERG "You probably have a hardware problem with your RAM "
+ "chips\n");
++ if (panic_on_unrecovered_nmi)
++ panic("NMI: Not continuing");
++
++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+
+ /* Clear and disable the memory parity error line. */
+ clear_mem_error(reason);
+ }
+
+-static void io_check_error(unsigned char reason, struct pt_regs * regs)
++static __kprobes void
++io_check_error(unsigned char reason, struct pt_regs * regs)
+ {
+ unsigned long i;
+
+@@ -656,7 +731,8 @@ static void io_check_error(unsigned char
+ outb(reason, 0x61);
+ }
+
+-static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
++static __kprobes void
++unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+ {
+ #ifdef CONFIG_MCA
+ /* Might actually be able to figure out what the guilty party
+@@ -666,15 +742,18 @@ static void unknown_nmi_error(unsigned c
+ return;
+ }
+ #endif
+- printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
+- reason, smp_processor_id());
+- printk("Dazed and confused, but trying to continue\n");
+- printk("Do you have a strange power saving mode enabled?\n");
++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
++ "CPU %d.\n", reason, smp_processor_id());
++ printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
++ if (panic_on_unrecovered_nmi)
++ panic("NMI: Not continuing");
++
++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+ }
+
+ static DEFINE_SPINLOCK(nmi_print_lock);
+
+-void die_nmi (struct pt_regs *regs, const char *msg)
++void __kprobes die_nmi(struct pt_regs *regs, const char *msg)
+ {
+ if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) ==
+ NOTIFY_STOP)
+@@ -706,7 +785,7 @@ void die_nmi (struct pt_regs *regs, cons
+ do_exit(SIGSEGV);
+ }
+
+-static void default_do_nmi(struct pt_regs * regs)
++static __kprobes void default_do_nmi(struct pt_regs * regs)
+ {
+ unsigned char reason = 0;
+
+@@ -723,12 +802,12 @@ static void default_do_nmi(struct pt_reg
+ * Ok, so this is none of the documented NMI sources,
+ * so it must be the NMI watchdog.
+ */
+- if (nmi_watchdog) {
+- nmi_watchdog_tick(regs);
++ if (nmi_watchdog_tick(regs, reason))
+ return;
+- }
++ if (!do_nmi_callback(regs, smp_processor_id()))
+ #endif
+- unknown_nmi_error(reason, regs);
++ unknown_nmi_error(reason, regs);
++
+ return;
+ }
+ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+@@ -744,14 +823,7 @@ static void default_do_nmi(struct pt_reg
+ reassert_nmi();
+ }
+
+-static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
+-{
+- return 0;
+-}
+-
+-static nmi_callback_t nmi_callback = dummy_nmi_callback;
+-
+-fastcall void do_nmi(struct pt_regs * regs, long error_code)
++fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
+ {
+ int cpu;
+
+@@ -761,25 +833,11 @@ fastcall void do_nmi(struct pt_regs * re
+
+ ++nmi_count(cpu);
+
+- if (!rcu_dereference(nmi_callback)(regs, cpu))
+- default_do_nmi(regs);
++ default_do_nmi(regs);
+
+ nmi_exit();
+ }
+
+-void set_nmi_callback(nmi_callback_t callback)
+-{
+- vmalloc_sync_all();
+- rcu_assign_pointer(nmi_callback, callback);
+-}
+-EXPORT_SYMBOL_GPL(set_nmi_callback);
+-
+-void unset_nmi_callback(void)
+-{
+- nmi_callback = dummy_nmi_callback;
+-}
+-EXPORT_SYMBOL_GPL(unset_nmi_callback);
+-
+ #ifdef CONFIG_KPROBES
+ fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
+ {
+@@ -1119,20 +1177,6 @@ void __init trap_init_f00f_bug(void)
+ }
+ #endif
+
+-#define _set_gate(gate_addr,type,dpl,addr,seg) \
+-do { \
+- int __d0, __d1; \
+- __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+- "movw %4,%%dx\n\t" \
+- "movl %%eax,%0\n\t" \
+- "movl %%edx,%1" \
+- :"=m" (*((long *) (gate_addr))), \
+- "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+- :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+- "3" ((char *) (addr)),"2" ((seg) << 16)); \
+-} while (0)
+-
+-
+ /*
+ * This needs to use 'idt_table' rather than 'idt', and
+ * thus use the _nonmapped_ version of the IDT, as the
+@@ -1141,7 +1185,7 @@ do { \
+ */
+ void set_intr_gate(unsigned int n, void *addr)
+ {
+- _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
++ _set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS);
+ }
+
+ /*
+@@ -1149,22 +1193,22 @@ void set_intr_gate(unsigned int n, void
+ */
+ static inline void set_system_intr_gate(unsigned int n, void *addr)
+ {
+- _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);
++ _set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, addr, __KERNEL_CS);
+ }
+
+ static void __init set_trap_gate(unsigned int n, void *addr)
+ {
+- _set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
++ _set_gate(n, DESCTYPE_TRAP, addr, __KERNEL_CS);
+ }
+
+ static void __init set_system_gate(unsigned int n, void *addr)
+ {
+- _set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
++ _set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS);
+ }
+
+ static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
+ {
+- _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
++ _set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3));
+ }
+
+
+diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
+index 7e0d8da..fbc9582 100644
+--- a/arch/i386/kernel/tsc.c
++++ b/arch/i386/kernel/tsc.c
+@@ -192,7 +192,7 @@ int recalibrate_cpu_khz(void)
+
+ EXPORT_SYMBOL(recalibrate_cpu_khz);
+
+-void tsc_init(void)
++void __init tsc_init(void)
+ {
+ if (!cpu_has_tsc || tsc_disable)
+ return;
+@@ -349,8 +349,8 @@ static int tsc_update_callback(void)
+ int change = 0;
+
+ /* check to see if we should switch to the safe clocksource: */
+- if (clocksource_tsc.rating != 50 && check_tsc_unstable()) {
+- clocksource_tsc.rating = 50;
++ if (clocksource_tsc.rating != 0 && check_tsc_unstable()) {
++ clocksource_tsc.rating = 0;
+ clocksource_reselect();
+ change = 1;
+ }
+@@ -461,7 +461,7 @@ static int __init init_tsc_clocksource(v
+ clocksource_tsc.shift);
+ /* lower the rating if we already know its unstable: */
+ if (check_tsc_unstable())
+- clocksource_tsc.rating = 50;
++ clocksource_tsc.rating = 0;
+
+ init_timer(&verify_tsc_freq_timer);
+ verify_tsc_freq_timer.function = verify_tsc_freq;
+diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
+index 8355d8d..cbcd61d 100644
+--- a/arch/i386/kernel/vm86.c
++++ b/arch/i386/kernel/vm86.c
+@@ -714,7 +714,7 @@ static int irqbits;
+ | (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO) | (1 << SIGURG) \
+ | (1 << SIGUNUSED) )
+
+-static irqreturn_t irq_handler(int intno, void *dev_id, struct pt_regs * regs)
++static irqreturn_t irq_handler(int intno, void *dev_id)
+ {
+ int irq_bit;
+ unsigned long flags;
+diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
+index 2d4f138..adc1f23 100644
+--- a/arch/i386/kernel/vmlinux.lds.S
++++ b/arch/i386/kernel/vmlinux.lds.S
+@@ -13,6 +13,12 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386"
+ OUTPUT_ARCH(i386)
+ ENTRY(phys_startup_32)
+ jiffies = jiffies_64;
++
++PHDRS {
++ text PT_LOAD FLAGS(5); /* R_E */
++ data PT_LOAD FLAGS(7); /* RWE */
++ note PT_NOTE FLAGS(4); /* R__ */
++}
+ SECTIONS
+ {
+ . = __KERNEL_START;
+@@ -26,7 +32,7 @@ SECTIONS
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+- } = 0x9090
++ } :text = 0x9090
+
+ _etext = .; /* End of text section */
+
+@@ -48,7 +54,7 @@ SECTIONS
+ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
+ *(.data)
+ CONSTRUCTORS
+- }
++ } :data
+
+ . = ALIGN(4096);
+ __nosave_begin = .;
+@@ -120,13 +126,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+@@ -184,4 +184,6 @@ SECTIONS
+ STABS_DEBUG
+
+ DWARF_DEBUG
++
++ NOTES
+ }
+diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
+index 914933e..d86a548 100644
+--- a/arch/i386/lib/Makefile
++++ b/arch/i386/lib/Makefile
+@@ -4,6 +4,6 @@
+
+
+ lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \
+- bitops.o
++ bitops.o semaphore.o
+
+ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
+diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c
+index 3c0714c..f6edb11 100644
+--- a/arch/i386/lib/delay.c
++++ b/arch/i386/lib/delay.c
+@@ -11,7 +11,6 @@
+ */
+
+ #include <linux/module.h>
+-#include <linux/config.h>
+ #include <linux/sched.h>
+ #include <linux/delay.h>
+
+diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
+new file mode 100644
+index 0000000..c01eb39
+--- /dev/null
++++ b/arch/i386/lib/semaphore.S
+@@ -0,0 +1,219 @@
++/*
++ * i386 semaphore implementation.
++ *
++ * (C) Copyright 1999 Linus Torvalds
++ *
++ * Portions Copyright 1999 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl at kvack.org>
++ */
++
++#include <linux/linkage.h>
++#include <asm/rwlock.h>
++#include <asm/alternative-asm.i>
++#include <asm/frame.i>
++#include <asm/dwarf2.h>
++
++/*
++ * The semaphore operations have a special calling sequence that
++ * allow us to do a simpler in-line version of them. These routines
++ * need to convert that sequence back into the C sequence when
++ * there is contention on the semaphore.
++ *
++ * %eax contains the semaphore pointer on entry. Save the C-clobbered
++ * registers (%eax, %edx and %ecx) except %eax whish is either a return
++ * value or just clobbered..
++ */
++ .section .sched.text
++ENTRY(__down_failed)
++ CFI_STARTPROC
++ FRAME
++ pushl %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx,0
++ pushl %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ call __down
++ popl %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE ecx
++ popl %edx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE edx
++ ENDFRAME
++ ret
++ CFI_ENDPROC
++ END(__down_failed)
++
++ENTRY(__down_failed_interruptible)
++ CFI_STARTPROC
++ FRAME
++ pushl %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx,0
++ pushl %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ call __down_interruptible
++ popl %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE ecx
++ popl %edx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE edx
++ ENDFRAME
++ ret
++ CFI_ENDPROC
++ END(__down_failed_interruptible)
++
++ENTRY(__down_failed_trylock)
++ CFI_STARTPROC
++ FRAME
++ pushl %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx,0
++ pushl %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ call __down_trylock
++ popl %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE ecx
++ popl %edx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE edx
++ ENDFRAME
++ ret
++ CFI_ENDPROC
++ END(__down_failed_trylock)
++
++ENTRY(__up_wakeup)
++ CFI_STARTPROC
++ FRAME
++ pushl %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx,0
++ pushl %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ call __up
++ popl %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE ecx
++ popl %edx
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE edx
++ ENDFRAME
++ ret
++ CFI_ENDPROC
++ END(__up_wakeup)
++
++/*
++ * rw spinlock fallbacks
++ */
++#ifdef CONFIG_SMP
++ENTRY(__write_lock_failed)
++ CFI_STARTPROC simple
++ FRAME
++2: LOCK_PREFIX
++ addl $ RW_LOCK_BIAS,(%eax)
++1: rep; nop
++ cmpl $ RW_LOCK_BIAS,(%eax)
++ jne 1b
++ LOCK_PREFIX
++ subl $ RW_LOCK_BIAS,(%eax)
++ jnz 2b
++ ENDFRAME
++ ret
++ CFI_ENDPROC
++ END(__write_lock_failed)
++
++ENTRY(__read_lock_failed)
++ CFI_STARTPROC
++ FRAME
++2: LOCK_PREFIX
++ incl (%eax)
++1: rep; nop
++ cmpl $1,(%eax)
++ js 1b
++ LOCK_PREFIX
++ decl (%eax)
++ js 2b
++ ENDFRAME
++ ret
++ CFI_ENDPROC
++ END(__read_lock_failed)
++
++#endif
++
++#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
++
++/* Fix up special calling conventions */
++ENTRY(call_rwsem_down_read_failed)
++ CFI_STARTPROC
++ push %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ push %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx,0
++ call rwsem_down_read_failed
++ pop %edx
++ CFI_ADJUST_CFA_OFFSET -4
++ pop %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ ret
++ CFI_ENDPROC
++ END(call_rwsem_down_read_failed)
++
++ENTRY(call_rwsem_down_write_failed)
++ CFI_STARTPROC
++ push %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ calll rwsem_down_write_failed
++ pop %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ ret
++ CFI_ENDPROC
++ END(call_rwsem_down_write_failed)
++
++ENTRY(call_rwsem_wake)
++ CFI_STARTPROC
++ decw %dx /* do nothing if still outstanding active readers */
++ jnz 1f
++ push %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ call rwsem_wake
++ pop %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++1: ret
++ CFI_ENDPROC
++ END(call_rwsem_wake)
++
++/* Fix up special calling conventions */
++ENTRY(call_rwsem_downgrade_wake)
++ CFI_STARTPROC
++ push %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx,0
++ push %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx,0
++ call rwsem_downgrade_wake
++ pop %edx
++ CFI_ADJUST_CFA_OFFSET -4
++ pop %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ ret
++ CFI_ENDPROC
++ END(call_rwsem_downgrade_wake)
++
++#endif
+diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
+index efc7e7d..d22cfc9 100644
+--- a/arch/i386/lib/usercopy.c
++++ b/arch/i386/lib/usercopy.c
+@@ -9,6 +9,7 @@
+ #include <linux/highmem.h>
+ #include <linux/blkdev.h>
+ #include <linux/module.h>
++#include <linux/backing-dev.h>
+ #include <asm/uaccess.h>
+ #include <asm/mmx.h>
+
+@@ -179,7 +180,7 @@ __clear_user(void __user *to, unsigned l
+ EXPORT_SYMBOL(__clear_user);
+
+ /**
+- * strlen_user: - Get the size of a string in user space.
++ * strnlen_user: - Get the size of a string in user space.
+ * @s: The string to measure.
+ * @n: The maximum valid length
+ *
+@@ -739,9 +740,9 @@ survive:
+ retval = get_user_pages(current, current->mm,
+ (unsigned long )to, 1, 1, 0, &pg, NULL);
+
+- if (retval == -ENOMEM && current->pid == 1) {
++ if (retval == -ENOMEM && is_init(current)) {
+ up_read(¤t->mm->mmap_sem);
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ goto survive;
+ }
+
+diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
+index ef7a6e6..33d9f93 100644
+--- a/arch/i386/mach-generic/bigsmp.c
++++ b/arch/i386/mach-generic/bigsmp.c
+@@ -5,6 +5,7 @@
+ #define APIC_DEFINITION 1
+ #include <linux/threads.h>
+ #include <linux/cpumask.h>
++#include <asm/smp.h>
+ #include <asm/mpspec.h>
+ #include <asm/genapic.h>
+ #include <asm/fixmap.h>
+diff --git a/arch/i386/mach-generic/es7000.c b/arch/i386/mach-generic/es7000.c
+index 845cdd0..aa144d8 100644
+--- a/arch/i386/mach-generic/es7000.c
++++ b/arch/i386/mach-generic/es7000.c
+@@ -4,6 +4,7 @@
+ #define APIC_DEFINITION 1
+ #include <linux/threads.h>
+ #include <linux/cpumask.h>
++#include <asm/smp.h>
+ #include <asm/mpspec.h>
+ #include <asm/genapic.h>
+ #include <asm/fixmap.h>
+diff --git a/arch/i386/mach-generic/probe.c b/arch/i386/mach-generic/probe.c
+index bcd1bcf..94b1fd9 100644
+--- a/arch/i386/mach-generic/probe.c
++++ b/arch/i386/mach-generic/probe.c
+@@ -9,6 +9,7 @@
+ #include <linux/kernel.h>
+ #include <linux/ctype.h>
+ #include <linux/init.h>
++#include <linux/errno.h>
+ #include <asm/fixmap.h>
+ #include <asm/mpspec.h>
+ #include <asm/apicdef.h>
+@@ -29,7 +30,24 @@ struct genapic *apic_probe[] __initdata
+ NULL,
+ };
+
+-static int cmdline_apic;
++static int cmdline_apic __initdata;
++static int __init parse_apic(char *arg)
++{
++ int i;
++
++ if (!arg)
++ return -EINVAL;
++
++ for (i = 0; apic_probe[i]; i++) {
++ if (!strcmp(apic_probe[i]->name, arg)) {
++ genapic = apic_probe[i];
++ cmdline_apic = 1;
++ return 0;
++ }
++ }
++ return -ENOENT;
++}
++early_param("apic", parse_apic);
+
+ void __init generic_bigsmp_probe(void)
+ {
+@@ -48,40 +66,20 @@ void __init generic_bigsmp_probe(void)
+ }
+ }
+
+-void __init generic_apic_probe(char *command_line)
++void __init generic_apic_probe(void)
+ {
+- char *s;
+- int i;
+- int changed = 0;
+-
+- s = strstr(command_line, "apic=");
+- if (s && (s == command_line || isspace(s[-1]))) {
+- char *p = strchr(s, ' '), old;
+- if (!p)
+- p = strchr(s, '\0');
+- old = *p;
+- *p = 0;
+- for (i = 0; !changed && apic_probe[i]; i++) {
+- if (!strcmp(apic_probe[i]->name, s+5)) {
+- changed = 1;
++ if (!cmdline_apic) {
++ int i;
++ for (i = 0; apic_probe[i]; i++) {
++ if (apic_probe[i]->probe()) {
+ genapic = apic_probe[i];
++ break;
+ }
+ }
+- if (!changed)
+- printk(KERN_ERR "Unknown genapic `%s' specified.\n", s);
+- *p = old;
+- cmdline_apic = changed;
+- }
+- for (i = 0; !changed && apic_probe[i]; i++) {
+- if (apic_probe[i]->probe()) {
+- changed = 1;
+- genapic = apic_probe[i];
+- }
++ /* Not visible without early console */
++ if (!apic_probe[i])
++ panic("Didn't find an APIC driver");
+ }
+- /* Not visible without early console */
+- if (!changed)
+- panic("Didn't find an APIC driver");
+-
+ printk(KERN_INFO "Using APIC driver %s\n", genapic->name);
+ }
+
+@@ -119,7 +117,9 @@ int __init acpi_madt_oem_check(char *oem
+ return 0;
+ }
+
++#ifdef CONFIG_SMP
+ int hard_smp_processor_id(void)
+ {
+ return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID));
+ }
++#endif
+diff --git a/arch/i386/mach-generic/summit.c b/arch/i386/mach-generic/summit.c
+index b73501d..f7e5d66 100644
+--- a/arch/i386/mach-generic/summit.c
++++ b/arch/i386/mach-generic/summit.c
+@@ -4,6 +4,7 @@
+ #define APIC_DEFINITION 1
+ #include <linux/threads.h>
+ #include <linux/cpumask.h>
++#include <asm/smp.h>
+ #include <asm/mpspec.h>
+ #include <asm/genapic.h>
+ #include <asm/fixmap.h>
+diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c
+index 8285225..38c2b13 100644
+--- a/arch/i386/mach-visws/visws_apic.c
++++ b/arch/i386/mach-visws/visws_apic.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/i386/mach_visws/visws_apic.c
++ * linux/arch/i386/mach-visws/visws_apic.c
+ *
+ * Copyright (C) 1999 Bent Hagemark, Ingo Molnar
+ *
+@@ -122,7 +122,7 @@ static void end_cobalt_irq(unsigned int
+ spin_unlock_irqrestore(&cobalt_lock, flags);
+ }
+
+-static struct hw_interrupt_type cobalt_irq_type = {
++static struct irq_chip cobalt_irq_type = {
+ .typename = "Cobalt-APIC",
+ .startup = startup_cobalt_irq,
+ .shutdown = disable_cobalt_irq,
+@@ -159,7 +159,7 @@ static void end_piix4_master_irq(unsigne
+ spin_unlock_irqrestore(&cobalt_lock, flags);
+ }
+
+-static struct hw_interrupt_type piix4_master_irq_type = {
++static struct irq_chip piix4_master_irq_type = {
+ .typename = "PIIX4-master",
+ .startup = startup_piix4_master_irq,
+ .ack = ack_cobalt_irq,
+@@ -167,9 +167,8 @@ static struct hw_interrupt_type piix4_ma
+ };
+
+
+-static struct hw_interrupt_type piix4_virtual_irq_type = {
++static struct irq_chip piix4_virtual_irq_type = {
+ .typename = "PIIX4-virtual",
+- .startup = startup_8259A_irq,
+ .shutdown = disable_8259A_irq,
+ .enable = enable_8259A_irq,
+ .disable = disable_8259A_irq,
+@@ -191,7 +190,7 @@ static struct hw_interrupt_type piix4_vi
+ * enable_irq gets the right irq. This 'master' irq is never directly
+ * manipulated by any driver.
+ */
+-static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t piix4_master_intr(int irq, void *dev_id)
+ {
+ int realirq;
+ irq_desc_t *desc;
+@@ -244,7 +243,7 @@ static irqreturn_t piix4_master_intr(int
+ kstat_cpu(smp_processor_id()).irqs[realirq]++;
+
+ if (likely(desc->action != NULL))
+- handle_IRQ_event(realirq, regs, desc->action);
++ handle_IRQ_event(realirq, desc->action);
+
+ if (!(desc->status & IRQ_DISABLED))
+ enable_8259A_irq(realirq);
+diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c
+index 80b7f2f..8fe7e45 100644
+--- a/arch/i386/mach-voyager/voyager_basic.c
++++ b/arch/i386/mach-voyager/voyager_basic.c
+@@ -44,7 +44,7 @@ struct voyager_SUS *voyager_SUS = NULL;
+
+ #ifdef CONFIG_SMP
+ static void
+-voyager_dump(int dummy1, struct pt_regs *dummy2, struct tty_struct *dummy3)
++voyager_dump(int dummy1, struct tty_struct *dummy3)
+ {
+ /* get here via a sysrq */
+ voyager_smp_dump();
+@@ -87,7 +87,7 @@ voyager_detect(struct voyager_bios_info
+ }
+
+ void
+-voyager_system_interrupt(int cpl, void *dev_id, struct pt_regs *regs)
++voyager_system_interrupt(int cpl, void *dev_id)
+ {
+ printk("Voyager: detected system interrupt\n");
+ }
+@@ -166,7 +166,7 @@ voyager_memory_detect(int region, __u32
+ * off the timer tick to the SMP code, since the VIC doesn't have an
+ * internal timer (The QIC does, but that's another story). */
+ void
+-voyager_timer_interrupt(struct pt_regs *regs)
++voyager_timer_interrupt(void)
+ {
+ if((jiffies & 0x3ff) == 0) {
+
+@@ -202,7 +202,7 @@ voyager_timer_interrupt(struct pt_regs *
+ }
+ }
+ #ifdef CONFIG_SMP
+- smp_vic_timer_interrupt(regs);
++ smp_vic_timer_interrupt();
+ #endif
+ }
+
+diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
+index 6c86575..f3fea2a 100644
+--- a/arch/i386/mach-voyager/voyager_smp.c
++++ b/arch/i386/mach-voyager/voyager_smp.c
+@@ -85,8 +85,8 @@ static int ack_QIC_CPI(__u8 cpi);
+ static void ack_special_QIC_CPI(__u8 cpi);
+ static void ack_VIC_CPI(__u8 cpi);
+ static void send_CPI_allbutself(__u8 cpi);
+-static void enable_vic_irq(unsigned int irq);
+-static void disable_vic_irq(unsigned int irq);
++static void mask_vic_irq(unsigned int irq);
++static void unmask_vic_irq(unsigned int irq);
+ static unsigned int startup_vic_irq(unsigned int irq);
+ static void enable_local_vic_irq(unsigned int irq);
+ static void disable_local_vic_irq(unsigned int irq);
+@@ -99,6 +99,7 @@ static void do_boot_cpu(__u8 cpuid);
+ static void do_quad_bootstrap(void);
+
+ int hard_smp_processor_id(void);
++int safe_smp_processor_id(void);
+
+ /* Inline functions */
+ static inline void
+@@ -125,10 +126,10 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi)
+ }
+
+ static inline void
+-wrapper_smp_local_timer_interrupt(struct pt_regs *regs)
++wrapper_smp_local_timer_interrupt(void)
+ {
+ irq_enter();
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ irq_exit();
+ }
+
+@@ -204,15 +205,12 @@ ack_CPI(__u8 cpi)
+ /* The VIC IRQ descriptors -- these look almost identical to the
+ * 8259 IRQs except that masks and things must be kept per processor
+ */
+-static struct hw_interrupt_type vic_irq_type = {
+- .typename = "VIC-level",
+- .startup = startup_vic_irq,
+- .shutdown = disable_vic_irq,
+- .enable = enable_vic_irq,
+- .disable = disable_vic_irq,
+- .ack = before_handle_vic_irq,
+- .end = after_handle_vic_irq,
+- .set_affinity = set_vic_irq_affinity,
++static struct irq_chip vic_chip = {
++ .name = "VIC",
++ .startup = startup_vic_irq,
++ .mask = mask_vic_irq,
++ .unmask = unmask_vic_irq,
++ .set_affinity = set_vic_irq_affinity,
+ };
+
+ /* used to count up as CPUs are brought on line (starts at 0) */
+@@ -785,7 +783,7 @@ fastcall void
+ smp_vic_sys_interrupt(struct pt_regs *regs)
+ {
+ ack_CPI(VIC_SYS_INT);
+- printk("Voyager SYSTEM INTERRUPT\n");
++ printk("Voyager SYSTEM INTERRUPT\n");
+ }
+
+ /* Handle a voyager CMN_INT; These interrupts occur either because of
+@@ -1134,15 +1132,19 @@ EXPORT_SYMBOL(smp_call_function);
+ fastcall void
+ smp_apic_timer_interrupt(struct pt_regs *regs)
+ {
+- wrapper_smp_local_timer_interrupt(regs);
++ struct pt_regs *old_regs = set_irq_regs(regs);
++ wrapper_smp_local_timer_interrupt();
++ set_irq_regs(old_regs);
+ }
+
+ /* All of the QUAD interrupt GATES */
+ fastcall void
+ smp_qic_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ ack_QIC_CPI(QIC_TIMER_CPI);
+- wrapper_smp_local_timer_interrupt(regs);
++ wrapper_smp_local_timer_interrupt();
++ set_irq_regs(old_regs);
+ }
+
+ fastcall void
+@@ -1176,6 +1178,7 @@ smp_qic_call_function_interrupt(struct p
+ fastcall void
+ smp_vic_cpi_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ __u8 cpu = smp_processor_id();
+
+ if(is_cpu_quad())
+@@ -1184,7 +1187,7 @@ smp_vic_cpi_interrupt(struct pt_regs *re
+ ack_VIC_CPI(VIC_CPI_LEVEL0);
+
+ if(test_and_clear_bit(VIC_TIMER_CPI, &vic_cpi_mailbox[cpu]))
+- wrapper_smp_local_timer_interrupt(regs);
++ wrapper_smp_local_timer_interrupt();
+ if(test_and_clear_bit(VIC_INVALIDATE_CPI, &vic_cpi_mailbox[cpu]))
+ smp_invalidate_interrupt();
+ if(test_and_clear_bit(VIC_RESCHEDULE_CPI, &vic_cpi_mailbox[cpu]))
+@@ -1193,6 +1196,7 @@ smp_vic_cpi_interrupt(struct pt_regs *re
+ smp_enable_irq_interrupt();
+ if(test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu]))
+ smp_call_function_interrupt();
++ set_irq_regs(old_regs);
+ }
+
+ static void
+@@ -1247,6 +1251,12 @@ hard_smp_processor_id(void)
+ return 0;
+ }
+
++int
++safe_smp_processor_id(void)
++{
++ return hard_smp_processor_id();
++}
++
+ /* broadcast a halt to all other CPUs */
+ void
+ smp_send_stop(void)
+@@ -1257,10 +1267,10 @@ smp_send_stop(void)
+ /* this function is triggered in time.c when a clock tick fires
+ * we need to re-broadcast the tick to all CPUs */
+ void
+-smp_vic_timer_interrupt(struct pt_regs *regs)
++smp_vic_timer_interrupt(void)
+ {
+ send_CPI_allbutself(VIC_TIMER_CPI);
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ }
+
+ /* local (per CPU) timer interrupt. It does both profiling and
+@@ -1272,12 +1282,12 @@ smp_vic_timer_interrupt(struct pt_regs *
+ * value into /proc/profile.
+ */
+ void
+-smp_local_timer_interrupt(struct pt_regs * regs)
++smp_local_timer_interrupt(void)
+ {
+ int cpu = smp_processor_id();
+ long weight;
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ if (--per_cpu(prof_counter, cpu) <= 0) {
+ /*
+ * The multiplier may have changed since the last time we got
+@@ -1295,7 +1305,7 @@ smp_local_timer_interrupt(struct pt_regs
+ per_cpu(prof_counter, cpu);
+ }
+
+- update_process_times(user_mode_vm(regs));
++ update_process_times(user_mode_vm(get_irq_regs()));
+ }
+
+ if( ((1<<cpu) & voyager_extended_vic_processors) == 0)
+@@ -1382,6 +1392,17 @@ setup_profiling_timer(unsigned int multi
+ return 0;
+ }
+
++/* This is a bit of a mess, but forced on us by the genirq changes
++ * there's no genirq handler that really does what voyager wants
++ * so hack it up with the simple IRQ handler */
++static void fastcall
++handle_vic_irq(unsigned int irq, struct irq_desc *desc)
++{
++ before_handle_vic_irq(irq);
++ handle_simple_irq(irq, desc);
++ after_handle_vic_irq(irq);
++}
++
+
+ /* The CPIs are handled in the per cpu 8259s, so they must be
+ * enabled to be received: FIX: enabling the CPIs in the early
+@@ -1418,7 +1439,7 @@ smp_intr_init(void)
+ * This is for later: first 16 correspond to PC IRQs; next 16
+ * are Primary MC IRQs and final 16 are Secondary MC IRQs */
+ for(i = 0; i < 48; i++)
+- irq_desc[i].chip = &vic_irq_type;
++ set_irq_chip_and_handler(i, &vic_chip, handle_vic_irq);
+ }
+
+ /* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per
+@@ -1516,7 +1537,7 @@ ack_VIC_CPI(__u8 cpi)
+ static unsigned int
+ startup_vic_irq(unsigned int irq)
+ {
+- enable_vic_irq(irq);
++ unmask_vic_irq(irq);
+
+ return 0;
+ }
+@@ -1543,7 +1564,7 @@ startup_vic_irq(unsigned int irq)
+ * adjust their masks accordingly. */
+
+ static void
+-enable_vic_irq(unsigned int irq)
++unmask_vic_irq(unsigned int irq)
+ {
+ /* linux doesn't to processor-irq affinity, so enable on
+ * all CPUs we know about */
+@@ -1552,7 +1573,7 @@ enable_vic_irq(unsigned int irq)
+ __u32 processorList = 0;
+ unsigned long flags;
+
+- VDEBUG(("VOYAGER: enable_vic_irq(%d) CPU%d affinity 0x%lx\n",
++ VDEBUG(("VOYAGER: unmask_vic_irq(%d) CPU%d affinity 0x%lx\n",
+ irq, cpu, cpu_irq_affinity[cpu]));
+ spin_lock_irqsave(&vic_irq_lock, flags);
+ for_each_online_cpu(real_cpu) {
+@@ -1576,7 +1597,7 @@ enable_vic_irq(unsigned int irq)
+ }
+
+ static void
+-disable_vic_irq(unsigned int irq)
++mask_vic_irq(unsigned int irq)
+ {
+ /* lazy disable, do nothing */
+ }
+@@ -1804,7 +1825,7 @@ set_vic_irq_affinity(unsigned int irq, c
+ * disabled again as it comes in (voyager lazy disable). If
+ * the affinity map is tightened to disable the interrupt on a
+ * cpu, it will be pushed off when it comes in */
+- enable_vic_irq(irq);
++ unmask_vic_irq(irq);
+ }
+
+ static void
+diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c
+index 50f6de6..f398873 100644
+--- a/arch/i386/mach-voyager/voyager_thread.c
++++ b/arch/i386/mach-voyager/voyager_thread.c
+@@ -130,7 +130,6 @@ thread(void *unused)
+ init_timer(&wakeup_timer);
+
+ sigfillset(¤t->blocked);
+- current->signal->tty = NULL;
+
+ printk(KERN_NOTICE "Voyager starting monitor thread\n");
+
+diff --git a/arch/i386/mm/boot_ioremap.c b/arch/i386/mm/boot_ioremap.c
+index 5d44f4f..4de11f5 100644
+--- a/arch/i386/mm/boot_ioremap.c
++++ b/arch/i386/mm/boot_ioremap.c
+@@ -29,8 +29,11 @@
+ */
+
+ #define BOOT_PTE_PTRS (PTRS_PER_PTE*2)
+-#define boot_pte_index(address) \
+- (((address) >> PAGE_SHIFT) & (BOOT_PTE_PTRS - 1))
++
++static unsigned long boot_pte_index(unsigned long vaddr)
++{
++ return __pa(vaddr) >> PAGE_SHIFT;
++}
+
+ static inline boot_pte_t* boot_vaddr_to_pte(void *address)
+ {
+diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
+index 7c392dc..ddbdb03 100644
+--- a/arch/i386/mm/discontig.c
++++ b/arch/i386/mm/discontig.c
+@@ -117,7 +117,8 @@ void set_pmd_pfn(unsigned long vaddr, un
+
+ void *node_remap_end_vaddr[MAX_NUMNODES];
+ void *node_remap_alloc_vaddr[MAX_NUMNODES];
+-
++static unsigned long kva_start_pfn;
++static unsigned long kva_pages;
+ /*
+ * FLAT - support for basic PC memory model with discontig enabled, essentially
+ * a single node with all available processors in it with a flat
+@@ -152,23 +153,7 @@ static void __init find_max_pfn_node(int
+ */
+ if (node_start_pfn[nid] > max_pfn)
+ node_start_pfn[nid] = max_pfn;
+- if (node_start_pfn[nid] > node_end_pfn[nid])
+- BUG();
+-}
+-
+-/* Find the owning node for a pfn. */
+-int early_pfn_to_nid(unsigned long pfn)
+-{
+- int nid;
+-
+- for_each_node(nid) {
+- if (node_end_pfn[nid] == 0)
+- break;
+- if (node_start_pfn[nid] <= pfn && node_end_pfn[nid] >= pfn)
+- return nid;
+- }
+-
+- return 0;
++ BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]);
+ }
+
+ /*
+@@ -226,6 +211,8 @@ static unsigned long calculate_numa_rema
+ unsigned long pfn;
+
+ for_each_online_node(nid) {
++ unsigned old_end_pfn = node_end_pfn[nid];
++
+ /*
+ * The acpi/srat node info can show hot-add memroy zones
+ * where memory could be added but not currently present.
+@@ -275,6 +262,7 @@ static unsigned long calculate_numa_rema
+
+ node_end_pfn[nid] -= size;
+ node_remap_start_pfn[nid] = node_end_pfn[nid];
++ shrink_active_range(nid, old_end_pfn, node_end_pfn[nid]);
+ }
+ printk("Reserving total of %ld pages for numa KVA remap\n",
+ reserve_pages);
+@@ -286,7 +274,6 @@ unsigned long __init setup_memory(void)
+ {
+ int nid;
+ unsigned long system_start_pfn, system_max_low_pfn;
+- unsigned long reserve_pages;
+
+ /*
+ * When mapping a NUMA machine we allocate the node_mem_map arrays
+@@ -298,14 +285,23 @@ unsigned long __init setup_memory(void)
+ find_max_pfn();
+ get_memcfg_numa();
+
+- reserve_pages = calculate_numa_remap_pages();
++ kva_pages = calculate_numa_remap_pages();
+
+ /* partially used pages are not usable - thus round upwards */
+ system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end);
+
+- system_max_low_pfn = max_low_pfn = find_max_low_pfn() - reserve_pages;
+- printk("reserve_pages = %ld find_max_low_pfn() ~ %ld\n",
+- reserve_pages, max_low_pfn + reserve_pages);
++ kva_start_pfn = find_max_low_pfn() - kva_pages;
++
++#ifdef CONFIG_BLK_DEV_INITRD
++ /* Numa kva area is below the initrd */
++ if (LOADER_TYPE && INITRD_START)
++ kva_start_pfn = PFN_DOWN(INITRD_START) - kva_pages;
++#endif
++ kva_start_pfn -= kva_start_pfn & (PTRS_PER_PTE-1);
++
++ system_max_low_pfn = max_low_pfn = find_max_low_pfn();
++ printk("kva_start_pfn ~ %ld find_max_low_pfn() ~ %ld\n",
++ kva_start_pfn, max_low_pfn);
+ printk("max_pfn = %ld\n", max_pfn);
+ #ifdef CONFIG_HIGHMEM
+ highstart_pfn = highend_pfn = max_pfn;
+@@ -313,6 +309,11 @@ unsigned long __init setup_memory(void)
+ highstart_pfn = system_max_low_pfn;
+ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+ pages_to_mb(highend_pfn - highstart_pfn));
++ num_physpages = highend_pfn;
++ high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
++#else
++ num_physpages = system_max_low_pfn;
++ high_memory = (void *) __va(system_max_low_pfn * PAGE_SIZE - 1) + 1;
+ #endif
+ printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+ pages_to_mb(system_max_low_pfn));
+@@ -323,7 +324,7 @@ unsigned long __init setup_memory(void)
+ (ulong) pfn_to_kaddr(max_low_pfn));
+ for_each_online_node(nid) {
+ node_remap_start_vaddr[nid] = pfn_to_kaddr(
+- highstart_pfn + node_remap_offset[nid]);
++ kva_start_pfn + node_remap_offset[nid]);
+ /* Init the node remap allocator */
+ node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] +
+ (node_remap_size[nid] * PAGE_SIZE);
+@@ -338,7 +339,6 @@ unsigned long __init setup_memory(void)
+ }
+ printk("High memory starts at vaddr %08lx\n",
+ (ulong) pfn_to_kaddr(highstart_pfn));
+- vmalloc_earlyreserve = reserve_pages * PAGE_SIZE;
+ for_each_online_node(nid)
+ find_max_pfn_node(nid);
+
+@@ -348,48 +348,31 @@ unsigned long __init setup_memory(void)
+ return max_low_pfn;
+ }
+
++void __init numa_kva_reserve(void)
++{
++ reserve_bootmem(PFN_PHYS(kva_start_pfn),PFN_PHYS(kva_pages));
++}
++
+ void __init zone_sizes_init(void)
+ {
+ int nid;
+-
+-
+- for_each_online_node(nid) {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+- unsigned long *zholes_size;
+- unsigned int max_dma;
+-
+- unsigned long low = max_low_pfn;
+- unsigned long start = node_start_pfn[nid];
+- unsigned long high = node_end_pfn[nid];
+-
+- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+-
+- if (node_has_online_mem(nid)){
+- if (start > low) {
+-#ifdef CONFIG_HIGHMEM
+- BUG_ON(start > high);
+- zones_size[ZONE_HIGHMEM] = high - start;
+-#endif
+- } else {
+- if (low < max_dma)
+- zones_size[ZONE_DMA] = low;
+- else {
+- BUG_ON(max_dma > low);
+- BUG_ON(low > high);
+- zones_size[ZONE_DMA] = max_dma;
+- zones_size[ZONE_NORMAL] = low - max_dma;
+-#ifdef CONFIG_HIGHMEM
+- zones_size[ZONE_HIGHMEM] = high - low;
+-#endif
+- }
+- }
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] =
++ virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
++ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
++ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
++
++ /* If SRAT has not registered memory, register it now */
++ if (find_max_pfn_with_active_regions() == 0) {
++ for_each_online_node(nid) {
++ if (node_has_online_mem(nid))
++ add_active_range(nid, node_start_pfn[nid],
++ node_end_pfn[nid]);
+ }
+-
+- zholes_size = get_zholes_size(nid);
+-
+- free_area_init_node(nid, NODE_DATA(nid), zones_size, start,
+- zholes_size);
+ }
++
++ free_area_init_nodes(max_zone_pfns);
+ return;
+ }
+
+@@ -409,7 +392,7 @@ void __init set_highmem_pages_init(int b
+ zone_end_pfn = zone_start_pfn + zone->spanned_pages;
+
+ printk("Initializing %s for node %d (%08lx:%08lx)\n",
+- zone->name, zone->zone_pgdat->node_id,
++ zone->name, zone_to_nid(zone),
+ zone_start_pfn, zone_end_pfn);
+
+ for (node_pfn = zone_start_pfn; node_pfn < zone_end_pfn; node_pfn++) {
+diff --git a/arch/i386/mm/extable.c b/arch/i386/mm/extable.c
+index de03c54..0ce4f22 100644
+--- a/arch/i386/mm/extable.c
++++ b/arch/i386/mm/extable.c
+@@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs
+ const struct exception_table_entry *fixup;
+
+ #ifdef CONFIG_PNPBIOS
+- if (unlikely((regs->xcs & ~15) == (GDT_ENTRY_PNPBIOS_BASE << 3)))
++ if (unlikely(SEGMENT_IS_PNP_CODE(regs->xcs)))
+ {
+ extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
+ extern u32 pnp_bios_is_utter_crap;
+diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
+index f727946..2581575 100644
+--- a/arch/i386/mm/fault.c
++++ b/arch/i386/mm/fault.c
+@@ -27,21 +27,24 @@
+ #include <asm/uaccess.h>
+ #include <asm/desc.h>
+ #include <asm/kdebug.h>
++#include <asm/segment.h>
+
+ extern void die(const char *,struct pt_regs *,long);
+
+-#ifdef CONFIG_KPROBES
+-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++
+ int register_page_fault_notifier(struct notifier_block *nb)
+ {
+ vmalloc_sync_all();
+ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
+ }
++EXPORT_SYMBOL_GPL(register_page_fault_notifier);
+
+ int unregister_page_fault_notifier(struct notifier_block *nb)
+ {
+ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
+ }
++EXPORT_SYMBOL_GPL(unregister_page_fault_notifier);
+
+ static inline int notify_page_fault(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig)
+@@ -55,14 +58,6 @@ static inline int notify_page_fault(enum
+ };
+ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
+ }
+-#else
+-static inline int notify_page_fault(enum die_val val, const char *str,
+- struct pt_regs *regs, long err, int trap, int sig)
+-{
+- return NOTIFY_DONE;
+-}
+-#endif
+-
+
+ /*
+ * Unlock any spinlocks which will prevent us from getting the
+@@ -119,10 +114,10 @@ static inline unsigned long get_segment_
+ }
+
+ /* The standard kernel/user address space limit. */
+- *eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg;
++ *eip_limit = user_mode(regs) ? USER_DS.seg : KERNEL_DS.seg;
+
+ /* By far the most common cases. */
+- if (likely(seg == __USER_CS || seg == __KERNEL_CS))
++ if (likely(SEGMENT_IS_FLAT_CODE(seg)))
+ return eip;
+
+ /* Check the segment exists, is within the current LDT/GDT size,
+@@ -436,11 +431,7 @@ good_area:
+ write = 0;
+ switch (error_code & 3) {
+ default: /* 3: write, present */
+-#ifdef TEST_VERIFY_AREA
+- if (regs->cs == KERNEL_CS)
+- printk("WP fault at %08lx\n", regs->eip);
+-#endif
+- /* fall through */
++ /* fall through */
+ case 2: /* write, not present */
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+@@ -449,7 +440,7 @@ good_area:
+ case 1: /* read, present */
+ goto bad_area;
+ case 0: /* read, not present */
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ }
+
+@@ -598,7 +589,7 @@ no_context:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (tsk->pid == 1) {
++ if (is_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
+index b6eb4dc..f9f647c 100644
+--- a/arch/i386/mm/highmem.c
++++ b/arch/i386/mm/highmem.c
+@@ -38,23 +38,20 @@ void *kmap_atomic(struct page *page, enu
+
+ idx = type + KM_TYPE_NR*smp_processor_id();
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+-#ifdef CONFIG_DEBUG_HIGHMEM
+ if (!pte_none(*(kmap_pte-idx)))
+ BUG();
+-#endif
+ set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
+- __flush_tlb_one(vaddr);
+
+ return (void*) vaddr;
+ }
+
+ void kunmap_atomic(void *kvaddr, enum km_type type)
+ {
+-#ifdef CONFIG_DEBUG_HIGHMEM
+ unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+ enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+
+- if (vaddr < FIXADDR_START) { // FIXME
++#ifdef CONFIG_DEBUG_HIGHMEM
++ if (vaddr >= PAGE_OFFSET && vaddr < (unsigned long)high_memory) {
+ dec_preempt_count();
+ preempt_check_resched();
+ return;
+@@ -62,14 +59,14 @@ void kunmap_atomic(void *kvaddr, enum km
+
+ if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
+ BUG();
+-
++#endif
+ /*
+- * force other mappings to Oops if they'll try to access
+- * this pte without first remap it
++ * Force other mappings to Oops if they'll try to access this pte
++ * without first remap it. Keeping stale mappings around is a bad idea
++ * also, in case the page changes cacheability attributes or becomes
++ * a protected page in a hypervisor.
+ */
+- pte_clear(&init_mm, vaddr, kmap_pte-idx);
+- __flush_tlb_one(vaddr);
+-#endif
++ kpte_clear_flush(kmap_pte-idx, vaddr);
+
+ dec_preempt_count();
+ preempt_check_resched();
+@@ -88,7 +85,6 @@ void *kmap_atomic_pfn(unsigned long pfn,
+ 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;
+ }
+diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
+index 89e8486..1674161 100644
+--- a/arch/i386/mm/init.c
++++ b/arch/i386/mm/init.c
+@@ -435,16 +435,22 @@ u64 __supported_pte_mask __read_mostly =
+ * on Enable
+ * off Disable
+ */
+-void __init noexec_setup(const char *str)
++static int __init noexec_setup(char *str)
+ {
+- if (!strncmp(str, "on",2) && cpu_has_nx) {
+- __supported_pte_mask |= _PAGE_NX;
+- disable_nx = 0;
+- } else if (!strncmp(str,"off",3)) {
++ if (!str || !strcmp(str, "on")) {
++ if (cpu_has_nx) {
++ __supported_pte_mask |= _PAGE_NX;
++ disable_nx = 0;
++ }
++ } else if (!strcmp(str,"off")) {
+ disable_nx = 1;
+ __supported_pte_mask &= ~_PAGE_NX;
+- }
++ } else
++ return -EINVAL;
++
++ return 0;
+ }
++early_param("noexec", noexec_setup);
+
+ int nx_enabled = 0;
+ #ifdef CONFIG_X86_PAE
+@@ -487,6 +493,7 @@ int __init set_kernel_exec(unsigned long
+ pte->pte_high &= ~(1 << (_PAGE_BIT_NX - 32));
+ else
+ pte->pte_high |= 1 << (_PAGE_BIT_NX - 32);
++ pte_update_defer(&init_mm, vaddr, pte);
+ __flush_tlb_all();
+ out:
+ return ret;
+@@ -552,18 +559,6 @@ static void __init test_wp_bit(void)
+ }
+ }
+
+-static void __init set_max_mapnr_init(void)
+-{
+-#ifdef CONFIG_HIGHMEM
+- num_physpages = highend_pfn;
+-#else
+- num_physpages = max_low_pfn;
+-#endif
+-#ifdef CONFIG_FLATMEM
+- max_mapnr = num_physpages;
+-#endif
+-}
+-
+ static struct kcore_list kcore_mem, kcore_vmalloc;
+
+ void __init mem_init(void)
+@@ -574,8 +569,7 @@ void __init mem_init(void)
+ int bad_ppro;
+
+ #ifdef CONFIG_FLATMEM
+- if (!mem_map)
+- BUG();
++ BUG_ON(!mem_map);
+ #endif
+
+ bad_ppro = ppro_with_ram_bug();
+@@ -590,14 +584,6 @@ void __init mem_init(void)
+ }
+ #endif
+
+- set_max_mapnr_init();
+-
+-#ifdef CONFIG_HIGHMEM
+- high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
+-#else
+- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
+-#endif
+-
+ /* this will put all low memory onto the freelists */
+ totalram_pages += free_all_bootmem();
+
+@@ -629,6 +615,48 @@ void __init mem_init(void)
+ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
+ );
+
++#if 1 /* double-sanity-check paranoia */
++ printk("virtual kernel memory layout:\n"
++ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
++#ifdef CONFIG_HIGHMEM
++ " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
++#endif
++ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
++ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
++ " .init : 0x%08lx - 0x%08lx (%4ld kB)\n"
++ " .data : 0x%08lx - 0x%08lx (%4ld kB)\n"
++ " .text : 0x%08lx - 0x%08lx (%4ld kB)\n",
++ FIXADDR_START, FIXADDR_TOP,
++ (FIXADDR_TOP - FIXADDR_START) >> 10,
++
++#ifdef CONFIG_HIGHMEM
++ PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE,
++ (LAST_PKMAP*PAGE_SIZE) >> 10,
++#endif
++
++ VMALLOC_START, VMALLOC_END,
++ (VMALLOC_END - VMALLOC_START) >> 20,
++
++ (unsigned long)__va(0), (unsigned long)high_memory,
++ ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20,
++
++ (unsigned long)&__init_begin, (unsigned long)&__init_end,
++ ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10,
++
++ (unsigned long)&_etext, (unsigned long)&_edata,
++ ((unsigned long)&_edata - (unsigned long)&_etext) >> 10,
++
++ (unsigned long)&_text, (unsigned long)&_etext,
++ ((unsigned long)&_etext - (unsigned long)&_text) >> 10);
++
++#ifdef CONFIG_HIGHMEM
++ BUG_ON(PKMAP_BASE+LAST_PKMAP*PAGE_SIZE > FIXADDR_START);
++ BUG_ON(VMALLOC_END > PKMAP_BASE);
++#endif
++ BUG_ON(VMALLOC_START > VMALLOC_END);
++ BUG_ON((unsigned long)high_memory > VMALLOC_START);
++#endif /* double-sanity-check paranoia */
++
+ #ifdef CONFIG_X86_PAE
+ if (!cpu_has_pae)
+ panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!");
+@@ -657,7 +685,7 @@ void __init mem_init(void)
+ int arch_add_memory(int nid, u64 start, u64 size)
+ {
+ struct pglist_data *pgdata = &contig_page_data;
+- struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
++ struct zone *zone = pgdata->node_zones + ZONE_HIGHMEM;
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+
+diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
+index 247fde7..fff08ae 100644
+--- a/arch/i386/mm/ioremap.c
++++ b/arch/i386/mm/ioremap.c
+@@ -12,7 +12,7 @@
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/module.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <asm/fixmap.h>
+ #include <asm/cacheflush.h>
+ #include <asm/tlbflush.h>
+@@ -21,82 +21,6 @@
+ #define ISA_START_ADDRESS 0xa0000
+ #define ISA_END_ADDRESS 0x100000
+
+-static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
+- unsigned long end, unsigned long phys_addr, unsigned long flags)
+-{
+- pte_t *pte;
+- unsigned long pfn;
+-
+- pfn = phys_addr >> PAGE_SHIFT;
+- pte = pte_alloc_kernel(pmd, addr);
+- if (!pte)
+- return -ENOMEM;
+- do {
+- BUG_ON(!pte_none(*pte));
+- set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW |
+- _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+- pfn++;
+- } while (pte++, addr += PAGE_SIZE, addr != end);
+- return 0;
+-}
+-
+-static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
+- unsigned long end, unsigned long phys_addr, unsigned long flags)
+-{
+- pmd_t *pmd;
+- unsigned long next;
+-
+- phys_addr -= addr;
+- pmd = pmd_alloc(&init_mm, pud, addr);
+- if (!pmd)
+- return -ENOMEM;
+- do {
+- next = pmd_addr_end(addr, end);
+- if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, flags))
+- return -ENOMEM;
+- } while (pmd++, addr = next, addr != end);
+- return 0;
+-}
+-
+-static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
+- unsigned long end, unsigned long phys_addr, unsigned long flags)
+-{
+- pud_t *pud;
+- unsigned long next;
+-
+- phys_addr -= addr;
+- pud = pud_alloc(&init_mm, pgd, addr);
+- if (!pud)
+- return -ENOMEM;
+- do {
+- next = pud_addr_end(addr, end);
+- if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, flags))
+- return -ENOMEM;
+- } while (pud++, addr = next, addr != end);
+- return 0;
+-}
+-
+-static int ioremap_page_range(unsigned long addr,
+- unsigned long end, unsigned long phys_addr, unsigned long flags)
+-{
+- pgd_t *pgd;
+- unsigned long next;
+- int err;
+-
+- BUG_ON(addr >= end);
+- flush_cache_all();
+- phys_addr -= addr;
+- pgd = pgd_offset_k(addr);
+- do {
+- next = pgd_addr_end(addr, end);
+- err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, flags);
+- if (err)
+- break;
+- } while (pgd++, addr = next, addr != end);
+- flush_tlb_all();
+- return err;
+-}
+-
+ /*
+ * Generic mapping function (not visible outside):
+ */
+@@ -115,6 +39,7 @@ void __iomem * __ioremap(unsigned long p
+ void __iomem * addr;
+ struct vm_struct * area;
+ unsigned long offset, last_addr;
++ pgprot_t prot;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+@@ -142,6 +67,9 @@ void __iomem * __ioremap(unsigned long p
+ return NULL;
+ }
+
++ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY
++ | _PAGE_ACCESSED | flags);
++
+ /*
+ * Mappings have to be page-aligned
+ */
+@@ -158,7 +86,7 @@ void __iomem * __ioremap(unsigned long p
+ area->phys_addr = phys_addr;
+ addr = (void __iomem *) area->addr;
+ if (ioremap_page_range((unsigned long) addr,
+- (unsigned long) addr + size, phys_addr, flags)) {
++ (unsigned long) addr + size, phys_addr, prot)) {
+ vunmap((void __force *) addr);
+ return NULL;
+ }
+diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
+index bd98768..10126e3 100644
+--- a/arch/i386/mm/pgtable.c
++++ b/arch/i386/mm/pgtable.c
+@@ -12,6 +12,7 @@
+ #include <linux/slab.h>
+ #include <linux/pagemap.h>
+ #include <linux/spinlock.h>
++#include <linux/module.h>
+
+ #include <asm/system.h>
+ #include <asm/pgtable.h>
+@@ -60,7 +61,9 @@ void show_mem(void)
+ printk(KERN_INFO "%lu pages writeback\n",
+ global_page_state(NR_WRITEBACK));
+ printk(KERN_INFO "%lu pages mapped\n", global_page_state(NR_FILE_MAPPED));
+- printk(KERN_INFO "%lu pages slab\n", global_page_state(NR_SLAB));
++ printk(KERN_INFO "%lu pages slab\n",
++ global_page_state(NR_SLAB_RECLAIMABLE) +
++ global_page_state(NR_SLAB_UNRECLAIMABLE));
+ printk(KERN_INFO "%lu pages pagetables\n",
+ global_page_state(NR_PAGETABLE));
+ }
+@@ -137,6 +140,12 @@ void set_pmd_pfn(unsigned long vaddr, un
+ __flush_tlb_one(vaddr);
+ }
+
++static int fixmaps;
++#ifndef CONFIG_COMPAT_VDSO
++unsigned long __FIXADDR_TOP = 0xfffff000;
++EXPORT_SYMBOL(__FIXADDR_TOP);
++#endif
++
+ void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
+ {
+ unsigned long address = __fix_to_virt(idx);
+@@ -146,6 +155,25 @@ void __set_fixmap (enum fixed_addresses
+ return;
+ }
+ set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
++ fixmaps++;
++}
++
++/**
++ * reserve_top_address - reserves a hole in the top of kernel address space
++ * @reserve - size of hole to reserve
++ *
++ * Can be used to relocate the fixmap area and poke a hole in the top
++ * of kernel address space to make room for a hypervisor.
++ */
++void reserve_top_address(unsigned long reserve)
++{
++ BUG_ON(fixmaps > 0);
++#ifdef CONFIG_COMPAT_VDSO
++ BUG_ON(reserve != 0);
++#else
++ __FIXADDR_TOP = -reserve - PAGE_SIZE;
++ __VMALLOC_RESERVE += reserve;
++#endif
+ }
+
+ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
+index 5f8dc8a..3700eef 100644
+--- a/arch/i386/oprofile/nmi_int.c
++++ b/arch/i386/oprofile/nmi_int.c
+@@ -17,14 +17,15 @@
+ #include <asm/nmi.h>
+ #include <asm/msr.h>
+ #include <asm/apic.h>
++#include <asm/kdebug.h>
+
+ #include "op_counter.h"
+ #include "op_x86_model.h"
+-
++
+ static struct op_x86_model_spec const * model;
+ static struct op_msrs cpu_msrs[NR_CPUS];
+ static unsigned long saved_lvtpc[NR_CPUS];
+-
++
+ static int nmi_start(void);
+ static void nmi_stop(void);
+
+@@ -82,13 +83,24 @@ static void exit_driverfs(void)
+ #define exit_driverfs() do { } while (0)
+ #endif /* CONFIG_PM */
+
+-
+-static int nmi_callback(struct pt_regs * regs, int cpu)
++static int profile_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data)
+ {
+- return model->check_ctrs(regs, &cpu_msrs[cpu]);
++ struct die_args *args = (struct die_args *)data;
++ int ret = NOTIFY_DONE;
++ int cpu = smp_processor_id();
++
++ switch(val) {
++ case DIE_NMI:
++ if (model->check_ctrs(args->regs, &cpu_msrs[cpu]))
++ ret = NOTIFY_STOP;
++ break;
++ default:
++ break;
++ }
++ return ret;
+ }
+-
+-
++
+ static void nmi_cpu_save_registers(struct op_msrs * msrs)
+ {
+ unsigned int const nr_ctrs = model->num_counters;
+@@ -98,15 +110,19 @@ static void nmi_cpu_save_registers(struc
+ unsigned int i;
+
+ for (i = 0; i < nr_ctrs; ++i) {
+- rdmsr(counters[i].addr,
+- counters[i].saved.low,
+- counters[i].saved.high);
++ if (counters[i].addr){
++ rdmsr(counters[i].addr,
++ counters[i].saved.low,
++ counters[i].saved.high);
++ }
+ }
+
+ for (i = 0; i < nr_ctrls; ++i) {
+- rdmsr(controls[i].addr,
+- controls[i].saved.low,
+- controls[i].saved.high);
++ if (controls[i].addr){
++ rdmsr(controls[i].addr,
++ controls[i].saved.low,
++ controls[i].saved.high);
++ }
+ }
+ }
+
+@@ -170,27 +186,29 @@ static void nmi_cpu_setup(void * dummy)
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ }
+
++static struct notifier_block profile_exceptions_nb = {
++ .notifier_call = profile_exceptions_notify,
++ .next = NULL,
++ .priority = 0
++};
+
+ static int nmi_setup(void)
+ {
++ int err=0;
++
+ if (!allocate_msrs())
+ return -ENOMEM;
+
+- /* We walk a thin line between law and rape here.
+- * We need to be careful to install our NMI handler
+- * without actually triggering any NMIs as this will
+- * break the core code horrifically.
+- */
+- if (reserve_lapic_nmi() < 0) {
++ if ((err = register_die_notifier(&profile_exceptions_nb))){
+ free_msrs();
+- return -EBUSY;
++ return err;
+ }
++
+ /* We need to serialize save and setup for HT because the subset
+ * of msrs are distinct for save and setup operations
+ */
+ on_each_cpu(nmi_save_registers, NULL, 0, 1);
+ on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
+- set_nmi_callback(nmi_callback);
+ nmi_enabled = 1;
+ return 0;
+ }
+@@ -205,15 +223,19 @@ static void nmi_restore_registers(struct
+ unsigned int i;
+
+ for (i = 0; i < nr_ctrls; ++i) {
+- wrmsr(controls[i].addr,
+- controls[i].saved.low,
+- controls[i].saved.high);
++ if (controls[i].addr){
++ wrmsr(controls[i].addr,
++ controls[i].saved.low,
++ controls[i].saved.high);
++ }
+ }
+
+ for (i = 0; i < nr_ctrs; ++i) {
+- wrmsr(counters[i].addr,
+- counters[i].saved.low,
+- counters[i].saved.high);
++ if (counters[i].addr){
++ wrmsr(counters[i].addr,
++ counters[i].saved.low,
++ counters[i].saved.high);
++ }
+ }
+ }
+
+@@ -234,6 +256,7 @@ static void nmi_cpu_shutdown(void * dumm
+ apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
+ apic_write(APIC_LVTERR, v);
+ nmi_restore_registers(msrs);
++ model->shutdown(msrs);
+ }
+
+
+@@ -241,8 +264,7 @@ static void nmi_shutdown(void)
+ {
+ nmi_enabled = 0;
+ on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
+- unset_nmi_callback();
+- release_lapic_nmi();
++ unregister_die_notifier(&profile_exceptions_nb);
+ free_msrs();
+ }
+
+@@ -284,6 +306,14 @@ static int nmi_create_files(struct super
+ struct dentry * dir;
+ char buf[4];
+
++ /* quick little hack to _not_ expose a counter if it is not
++ * available for use. This should protect userspace app.
++ * NOTE: assumes 1:1 mapping here (that counters are organized
++ * sequentially in their struct assignment).
++ */
++ if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i)))
++ continue;
++
+ snprintf(buf, sizeof(buf), "%d", i);
+ dir = oprofilefs_mkdir(sb, root, buf);
+ oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
+diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
+index 930a112..abf0ba5 100644
+--- a/arch/i386/oprofile/nmi_timer_int.c
++++ b/arch/i386/oprofile/nmi_timer_int.c
+@@ -17,34 +17,49 @@
+ #include <asm/nmi.h>
+ #include <asm/apic.h>
+ #include <asm/ptrace.h>
++#include <asm/kdebug.h>
+
+-static int nmi_timer_callback(struct pt_regs * regs, int cpu)
++static int profile_timer_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data)
+ {
+- oprofile_add_sample(regs, 0);
+- return 1;
++ struct die_args *args = (struct die_args *)data;
++ int ret = NOTIFY_DONE;
++
++ switch(val) {
++ case DIE_NMI:
++ oprofile_add_sample(args->regs, 0);
++ ret = NOTIFY_STOP;
++ break;
++ default:
++ break;
++ }
++ return ret;
+ }
+
++static struct notifier_block profile_timer_exceptions_nb = {
++ .notifier_call = profile_timer_exceptions_notify,
++ .next = NULL,
++ .priority = 0
++};
++
+ static int timer_start(void)
+ {
+- disable_timer_nmi_watchdog();
+- set_nmi_callback(nmi_timer_callback);
++ if (register_die_notifier(&profile_timer_exceptions_nb))
++ return 1;
+ return 0;
+ }
+
+
+ static void timer_stop(void)
+ {
+- enable_timer_nmi_watchdog();
+- unset_nmi_callback();
++ unregister_die_notifier(&profile_timer_exceptions_nb);
+ synchronize_sched(); /* Allow already-started NMIs to complete. */
+ }
+
+
+ int __init op_nmi_timer_init(struct oprofile_operations * ops)
+ {
+- extern int nmi_active;
+-
+- if (nmi_active <= 0)
++ if ((nmi_watchdog != NMI_IO_APIC) || (atomic_read(&nmi_active) <= 0))
+ return -ENODEV;
+
+ ops->start = timer_start;
+diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c
+index 693bdea..3057a19 100644
+--- a/arch/i386/oprofile/op_model_athlon.c
++++ b/arch/i386/oprofile/op_model_athlon.c
+@@ -21,10 +21,12 @@
+ #define NUM_COUNTERS 4
+ #define NUM_CONTROLS 4
+
++#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
+ #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
+ #define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0)
+ #define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
++#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
+ #define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
+ #define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
+ #define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+@@ -40,15 +42,21 @@ static unsigned long reset_value[NUM_COU
+
+ static void athlon_fill_in_addresses(struct op_msrs * const msrs)
+ {
+- msrs->counters[0].addr = MSR_K7_PERFCTR0;
+- msrs->counters[1].addr = MSR_K7_PERFCTR1;
+- msrs->counters[2].addr = MSR_K7_PERFCTR2;
+- msrs->counters[3].addr = MSR_K7_PERFCTR3;
+-
+- msrs->controls[0].addr = MSR_K7_EVNTSEL0;
+- msrs->controls[1].addr = MSR_K7_EVNTSEL1;
+- msrs->controls[2].addr = MSR_K7_EVNTSEL2;
+- msrs->controls[3].addr = MSR_K7_EVNTSEL3;
++ int i;
++
++ for (i=0; i < NUM_COUNTERS; i++) {
++ if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
++ msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
++ else
++ msrs->counters[i].addr = 0;
++ }
++
++ for (i=0; i < NUM_CONTROLS; i++) {
++ if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
++ msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
++ else
++ msrs->controls[i].addr = 0;
++ }
+ }
+
+
+@@ -59,19 +67,23 @@ static void athlon_setup_ctrs(struct op_
+
+ /* clear all counters */
+ for (i = 0 ; i < NUM_CONTROLS; ++i) {
++ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
++ continue;
+ CTRL_READ(low, high, msrs, i);
+ CTRL_CLEAR(low);
+ CTRL_WRITE(low, high, msrs, i);
+ }
+-
++
+ /* avoid a false detection of ctr overflows in NMI handler */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
++ if (unlikely(!CTR_IS_RESERVED(msrs,i)))
++ continue;
+ CTR_WRITE(1, msrs, i);
+ }
+
+ /* enable active counters */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+- if (counter_config[i].enabled) {
++ if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
+ reset_value[i] = counter_config[i].count;
+
+ CTR_WRITE(counter_config[i].count, msrs, i);
+@@ -98,6 +110,8 @@ static int athlon_check_ctrs(struct pt_r
+ int i;
+
+ for (i = 0 ; i < NUM_COUNTERS; ++i) {
++ if (!reset_value[i])
++ continue;
+ CTR_READ(low, high, msrs, i);
+ if (CTR_OVERFLOWED(low)) {
+ oprofile_add_sample(regs, i);
+@@ -132,12 +146,27 @@ static void athlon_stop(struct op_msrs c
+ /* Subtle: stop on all counters to avoid race with
+ * setting our pm callback */
+ for (i = 0 ; i < NUM_COUNTERS ; ++i) {
++ if (!reset_value[i])
++ continue;
+ CTRL_READ(low, high, msrs, i);
+ CTRL_SET_INACTIVE(low);
+ CTRL_WRITE(low, high, msrs, i);
+ }
+ }
+
++static void athlon_shutdown(struct op_msrs const * const msrs)
++{
++ int i;
++
++ for (i = 0 ; i < NUM_COUNTERS ; ++i) {
++ if (CTR_IS_RESERVED(msrs,i))
++ release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
++ }
++ for (i = 0 ; i < NUM_CONTROLS ; ++i) {
++ if (CTRL_IS_RESERVED(msrs,i))
++ release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
++ }
++}
+
+ struct op_x86_model_spec const op_athlon_spec = {
+ .num_counters = NUM_COUNTERS,
+@@ -146,5 +175,6 @@ struct op_x86_model_spec const op_athlon
+ .setup_ctrs = &athlon_setup_ctrs,
+ .check_ctrs = &athlon_check_ctrs,
+ .start = &athlon_start,
+- .stop = &athlon_stop
++ .stop = &athlon_stop,
++ .shutdown = &athlon_shutdown
+ };
+diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c
+index 7c61d35..4792592 100644
+--- a/arch/i386/oprofile/op_model_p4.c
++++ b/arch/i386/oprofile/op_model_p4.c
+@@ -32,7 +32,7 @@
+ #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
+
+ static unsigned int num_counters = NUM_COUNTERS_NON_HT;
+-
++static unsigned int num_controls = NUM_CONTROLS_NON_HT;
+
+ /* this has to be checked dynamically since the
+ hyper-threadedness of a chip is discovered at
+@@ -40,8 +40,10 @@ static unsigned int num_counters = NUM_C
+ static inline void setup_num_counters(void)
+ {
+ #ifdef CONFIG_SMP
+- if (smp_num_siblings == 2)
++ if (smp_num_siblings == 2){
+ num_counters = NUM_COUNTERS_HT2;
++ num_controls = NUM_CONTROLS_HT2;
++ }
+ #endif
+ }
+
+@@ -97,15 +99,6 @@ static struct p4_counter_binding p4_coun
+
+ #define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
+
+-/* All cccr we don't use. */
+-static int p4_unused_cccr[NUM_UNUSED_CCCRS] = {
+- MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3,
+- MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3,
+- MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3,
+- MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR1,
+- MSR_P4_IQ_CCCR2, MSR_P4_IQ_CCCR3
+-};
+-
+ /* p4 event codes in libop/op_event.h are indices into this table. */
+
+ static struct p4_event_binding p4_events[NUM_EVENTS] = {
+@@ -372,6 +365,8 @@ static struct p4_event_binding p4_events
+ #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
+ #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
+
++#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
++#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
+ #define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
+ #define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
+ #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
+@@ -401,29 +396,34 @@ static unsigned long reset_value[NUM_COU
+ static void p4_fill_in_addresses(struct op_msrs * const msrs)
+ {
+ unsigned int i;
+- unsigned int addr, stag;
++ unsigned int addr, cccraddr, stag;
+
+ setup_num_counters();
+ stag = get_stagger();
+
+- /* the counter registers we pay attention to */
++ /* initialize some registers */
+ for (i = 0; i < num_counters; ++i) {
+- msrs->counters[i].addr =
+- p4_counters[VIRT_CTR(stag, i)].counter_address;
++ msrs->counters[i].addr = 0;
+ }
+-
+- /* FIXME: bad feeling, we don't save the 10 counters we don't use. */
+-
+- /* 18 CCCR registers */
+- for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
+- addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ for (i = 0; i < num_controls; ++i) {
++ msrs->controls[i].addr = 0;
+ }
+
++ /* the counter & cccr registers we pay attention to */
++ for (i = 0; i < num_counters; ++i) {
++ addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
++ cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
++ if (reserve_perfctr_nmi(addr)){
++ msrs->counters[i].addr = addr;
++ msrs->controls[i].addr = cccraddr;
++ }
++ }
++
+ /* 43 ESCR registers in three or four discontiguous group */
+ for (addr = MSR_P4_BSU_ESCR0 + stag;
+ addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ if (reserve_evntsel_nmi(addr))
++ msrs->controls[i].addr = addr;
+ }
+
+ /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
+@@ -431,47 +431,57 @@ static void p4_fill_in_addresses(struct
+ if (boot_cpu_data.x86_model >= 0x3) {
+ for (addr = MSR_P4_BSU_ESCR0 + stag;
+ addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ if (reserve_evntsel_nmi(addr))
++ msrs->controls[i].addr = addr;
+ }
+ } else {
+ for (addr = MSR_P4_IQ_ESCR0 + stag;
+ addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ if (reserve_evntsel_nmi(addr))
++ msrs->controls[i].addr = addr;
+ }
+ }
+
+ for (addr = MSR_P4_RAT_ESCR0 + stag;
+ addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ if (reserve_evntsel_nmi(addr))
++ msrs->controls[i].addr = addr;
+ }
+
+ for (addr = MSR_P4_MS_ESCR0 + stag;
+ addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ if (reserve_evntsel_nmi(addr))
++ msrs->controls[i].addr = addr;
+ }
+
+ for (addr = MSR_P4_IX_ESCR0 + stag;
+ addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
+- msrs->controls[i].addr = addr;
++ if (reserve_evntsel_nmi(addr))
++ msrs->controls[i].addr = addr;
+ }
+
+ /* there are 2 remaining non-contiguously located ESCRs */
+
+ if (num_counters == NUM_COUNTERS_NON_HT) {
+ /* standard non-HT CPUs handle both remaining ESCRs*/
+- msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
+- msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
++ if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
++ msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
++ if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
++ msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
+
+ } else if (stag == 0) {
+ /* HT CPUs give the first remainder to the even thread, as
+ the 32nd control register */
+- msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
++ if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
++ msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
+
+ } else {
+ /* and two copies of the second to the odd thread,
+ for the 22st and 23nd control registers */
+- msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
+- msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
++ if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
++ msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
++ msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
++ }
+ }
+ }
+
+@@ -544,7 +554,6 @@ static void p4_setup_ctrs(struct op_msrs
+ {
+ unsigned int i;
+ unsigned int low, high;
+- unsigned int addr;
+ unsigned int stag;
+
+ stag = get_stagger();
+@@ -557,59 +566,24 @@ static void p4_setup_ctrs(struct op_msrs
+
+ /* clear the cccrs we will use */
+ for (i = 0 ; i < num_counters ; i++) {
++ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
++ continue;
+ rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
+ CCCR_CLEAR(low);
+ CCCR_SET_REQUIRED_BITS(low);
+ wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
+ }
+
+- /* clear cccrs outside our concern */
+- for (i = stag ; i < NUM_UNUSED_CCCRS ; i += addr_increment()) {
+- rdmsr(p4_unused_cccr[i], low, high);
+- CCCR_CLEAR(low);
+- CCCR_SET_REQUIRED_BITS(low);
+- wrmsr(p4_unused_cccr[i], low, high);
+- }
+-
+ /* clear all escrs (including those outside our concern) */
+- for (addr = MSR_P4_BSU_ESCR0 + stag;
+- addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) {
+- wrmsr(addr, 0, 0);
+- }
+-
+- /* On older models clear also MSR_P4_IQ_ESCR0/1 */
+- if (boot_cpu_data.x86_model < 0x3) {
+- wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
+- wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
+- }
+-
+- for (addr = MSR_P4_RAT_ESCR0 + stag;
+- addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
+- wrmsr(addr, 0, 0);
+- }
+-
+- for (addr = MSR_P4_MS_ESCR0 + stag;
+- addr <= MSR_P4_TC_ESCR1; addr += addr_increment()){
+- wrmsr(addr, 0, 0);
+- }
+-
+- for (addr = MSR_P4_IX_ESCR0 + stag;
+- addr <= MSR_P4_CRU_ESCR3; addr += addr_increment()){
+- wrmsr(addr, 0, 0);
++ for (i = num_counters; i < num_controls; i++) {
++ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
++ continue;
++ wrmsr(msrs->controls[i].addr, 0, 0);
+ }
+
+- if (num_counters == NUM_COUNTERS_NON_HT) {
+- wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
+- wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
+- } else if (stag == 0) {
+- wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
+- } else {
+- wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
+- }
+-
+ /* setup all counters */
+ for (i = 0 ; i < num_counters ; ++i) {
+- if (counter_config[i].enabled) {
++ if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs,i))) {
+ reset_value[i] = counter_config[i].count;
+ pmc_setup_one_p4_counter(i);
+ CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
+@@ -696,12 +670,32 @@ static void p4_stop(struct op_msrs const
+ stag = get_stagger();
+
+ for (i = 0; i < num_counters; ++i) {
++ if (!reset_value[i])
++ continue;
+ CCCR_READ(low, high, VIRT_CTR(stag, i));
+ CCCR_SET_DISABLE(low);
+ CCCR_WRITE(low, high, VIRT_CTR(stag, i));
+ }
+ }
+
++static void p4_shutdown(struct op_msrs const * const msrs)
++{
++ int i;
++
++ for (i = 0 ; i < num_counters ; ++i) {
++ if (CTR_IS_RESERVED(msrs,i))
++ release_perfctr_nmi(msrs->counters[i].addr);
++ }
++ /* some of the control registers are specially reserved in
++ * conjunction with the counter registers (hence the starting offset).
++ * This saves a few bits.
++ */
++ for (i = num_counters ; i < num_controls ; ++i) {
++ if (CTRL_IS_RESERVED(msrs,i))
++ release_evntsel_nmi(msrs->controls[i].addr);
++ }
++}
++
+
+ #ifdef CONFIG_SMP
+ struct op_x86_model_spec const op_p4_ht2_spec = {
+@@ -711,7 +705,8 @@ struct op_x86_model_spec const op_p4_ht2
+ .setup_ctrs = &p4_setup_ctrs,
+ .check_ctrs = &p4_check_ctrs,
+ .start = &p4_start,
+- .stop = &p4_stop
++ .stop = &p4_stop,
++ .shutdown = &p4_shutdown
+ };
+ #endif
+
+@@ -722,5 +717,6 @@ struct op_x86_model_spec const op_p4_spe
+ .setup_ctrs = &p4_setup_ctrs,
+ .check_ctrs = &p4_check_ctrs,
+ .start = &p4_start,
+- .stop = &p4_stop
++ .stop = &p4_stop,
++ .shutdown = &p4_shutdown
+ };
+diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
+index 5c3ab4b..ca2447e 100644
+--- a/arch/i386/oprofile/op_model_ppro.c
++++ b/arch/i386/oprofile/op_model_ppro.c
+@@ -22,10 +22,12 @@
+ #define NUM_COUNTERS 2
+ #define NUM_CONTROLS 2
+
++#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
+ #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
+ #define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0)
+ #define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
++#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
+ #define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
+ #define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
+ #define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+@@ -41,11 +43,21 @@ static unsigned long reset_value[NUM_COU
+
+ static void ppro_fill_in_addresses(struct op_msrs * const msrs)
+ {
+- msrs->counters[0].addr = MSR_P6_PERFCTR0;
+- msrs->counters[1].addr = MSR_P6_PERFCTR1;
++ int i;
++
++ for (i=0; i < NUM_COUNTERS; i++) {
++ if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
++ msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
++ else
++ msrs->counters[i].addr = 0;
++ }
+
+- msrs->controls[0].addr = MSR_P6_EVNTSEL0;
+- msrs->controls[1].addr = MSR_P6_EVNTSEL1;
++ for (i=0; i < NUM_CONTROLS; i++) {
++ if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i))
++ msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
++ else
++ msrs->controls[i].addr = 0;
++ }
+ }
+
+
+@@ -56,6 +68,8 @@ static void ppro_setup_ctrs(struct op_ms
+
+ /* clear all counters */
+ for (i = 0 ; i < NUM_CONTROLS; ++i) {
++ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
++ continue;
+ CTRL_READ(low, high, msrs, i);
+ CTRL_CLEAR(low);
+ CTRL_WRITE(low, high, msrs, i);
+@@ -63,12 +77,14 @@ static void ppro_setup_ctrs(struct op_ms
+
+ /* avoid a false detection of ctr overflows in NMI handler */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
++ if (unlikely(!CTR_IS_RESERVED(msrs,i)))
++ continue;
+ CTR_WRITE(1, msrs, i);
+ }
+
+ /* enable active counters */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+- if (counter_config[i].enabled) {
++ if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
+ reset_value[i] = counter_config[i].count;
+
+ CTR_WRITE(counter_config[i].count, msrs, i);
+@@ -81,6 +97,8 @@ static void ppro_setup_ctrs(struct op_ms
+ CTRL_SET_UM(low, counter_config[i].unit_mask);
+ CTRL_SET_EVENT(low, counter_config[i].event);
+ CTRL_WRITE(low, high, msrs, i);
++ } else {
++ reset_value[i] = 0;
+ }
+ }
+ }
+@@ -93,6 +111,8 @@ static int ppro_check_ctrs(struct pt_reg
+ int i;
+
+ for (i = 0 ; i < NUM_COUNTERS; ++i) {
++ if (!reset_value[i])
++ continue;
+ CTR_READ(low, high, msrs, i);
+ if (CTR_OVERFLOWED(low)) {
+ oprofile_add_sample(regs, i);
+@@ -118,18 +138,44 @@ static int ppro_check_ctrs(struct pt_reg
+ static void ppro_start(struct op_msrs const * const msrs)
+ {
+ unsigned int low,high;
+- CTRL_READ(low, high, msrs, 0);
+- CTRL_SET_ACTIVE(low);
+- CTRL_WRITE(low, high, msrs, 0);
++ int i;
++
++ for (i = 0; i < NUM_COUNTERS; ++i) {
++ if (reset_value[i]) {
++ CTRL_READ(low, high, msrs, i);
++ CTRL_SET_ACTIVE(low);
++ CTRL_WRITE(low, high, msrs, i);
++ }
++ }
+ }
+
+
+ static void ppro_stop(struct op_msrs const * const msrs)
+ {
+ unsigned int low,high;
+- CTRL_READ(low, high, msrs, 0);
+- CTRL_SET_INACTIVE(low);
+- CTRL_WRITE(low, high, msrs, 0);
++ int i;
++
++ for (i = 0; i < NUM_COUNTERS; ++i) {
++ if (!reset_value[i])
++ continue;
++ CTRL_READ(low, high, msrs, i);
++ CTRL_SET_INACTIVE(low);
++ CTRL_WRITE(low, high, msrs, i);
++ }
++}
++
++static void ppro_shutdown(struct op_msrs const * const msrs)
++{
++ int i;
++
++ for (i = 0 ; i < NUM_COUNTERS ; ++i) {
++ if (CTR_IS_RESERVED(msrs,i))
++ release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
++ }
++ for (i = 0 ; i < NUM_CONTROLS ; ++i) {
++ if (CTRL_IS_RESERVED(msrs,i))
++ release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
++ }
+ }
+
+
+@@ -140,5 +186,6 @@ struct op_x86_model_spec const op_ppro_s
+ .setup_ctrs = &ppro_setup_ctrs,
+ .check_ctrs = &ppro_check_ctrs,
+ .start = &ppro_start,
+- .stop = &ppro_stop
++ .stop = &ppro_stop,
++ .shutdown = &ppro_shutdown
+ };
+diff --git a/arch/i386/oprofile/op_x86_model.h b/arch/i386/oprofile/op_x86_model.h
+index 123b7e9..abb1aa9 100644
+--- a/arch/i386/oprofile/op_x86_model.h
++++ b/arch/i386/oprofile/op_x86_model.h
+@@ -40,6 +40,7 @@ struct op_x86_model_spec {
+ struct op_msrs const * const msrs);
+ void (*start)(struct op_msrs const * const msrs);
+ void (*stop)(struct op_msrs const * const msrs);
++ void (*shutdown)(struct op_msrs const * const msrs);
+ };
+
+ extern struct op_x86_model_spec const op_ppro_spec;
+diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile
+index 62ad75c..1594d2f 100644
+--- a/arch/i386/pci/Makefile
++++ b/arch/i386/pci/Makefile
+@@ -11,4 +11,4 @@ pci-y += legacy.o irq.o
+ pci-$(CONFIG_X86_VISWS) := visws.o fixup.o
+ pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o
+
+-obj-y += $(pci-y) common.o
++obj-y += $(pci-y) common.o early.o
+diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
+index 0a362e3..cdfcf97 100644
+--- a/arch/i386/pci/common.c
++++ b/arch/i386/pci/common.c
+@@ -20,6 +20,7 @@
+ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
+ PCI_PROBE_MMCONF;
+
++int pci_bf_sort;
+ int pci_routeirq;
+ int pcibios_last_bus = -1;
+ unsigned long pirq_table_addr;
+@@ -118,6 +119,20 @@ void __devinit pcibios_fixup_bus(struct
+ }
+
+ /*
++ * Only use DMI information to set this if nothing was passed
++ * on the kernel command line (which was parsed earlier).
++ */
++
++static int __devinit set_bf_sort(struct dmi_system_id *d)
++{
++ if (pci_bf_sort == pci_bf_sort_default) {
++ pci_bf_sort = pci_dmi_bf;
++ printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident);
++ }
++ return 0;
++}
++
++/*
+ * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
+ */
+ #ifdef __i386__
+@@ -130,11 +145,11 @@ static int __devinit assign_all_busses(s
+ }
+ #endif
+
++static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
++#ifdef __i386__
+ /*
+ * Laptops which need pci=assign-busses to see Cardbus cards
+ */
+-static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
+-#ifdef __i386__
+ {
+ .callback = assign_all_busses,
+ .ident = "Samsung X20 Laptop",
+@@ -144,6 +159,38 @@ static struct dmi_system_id __devinitdat
+ },
+ },
+ #endif /* __i386__ */
++ {
++ .callback = set_bf_sort,
++ .ident = "Dell PowerEdge 1950",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"),
++ },
++ },
++ {
++ .callback = set_bf_sort,
++ .ident = "Dell PowerEdge 1955",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"),
++ },
++ },
++ {
++ .callback = set_bf_sort,
++ .ident = "Dell PowerEdge 2900",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"),
++ },
++ },
++ {
++ .callback = set_bf_sort,
++ .ident = "Dell PowerEdge 2950",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"),
++ },
++ },
+ {}
+ };
+
+@@ -189,6 +236,8 @@ static int __init pcibios_init(void)
+
+ pcibios_resource_survey();
+
++ if (pci_bf_sort >= pci_force_bf)
++ pci_sort_breadthfirst();
+ #ifdef CONFIG_PCI_BIOS
+ if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+ pcibios_sort();
+@@ -203,6 +252,12 @@ char * __devinit pcibios_setup(char *st
+ if (!strcmp(str, "off")) {
+ pci_probe = 0;
+ return NULL;
++ } else if (!strcmp(str, "bfsort")) {
++ pci_bf_sort = pci_force_bf;
++ return NULL;
++ } else if (!strcmp(str, "nobfsort")) {
++ pci_bf_sort = pci_force_nobf;
++ return NULL;
+ }
+ #ifdef CONFIG_PCI_BIOS
+ else if (!strcmp(str, "bios")) {
+@@ -242,6 +297,10 @@ char * __devinit pcibios_setup(char *st
+ acpi_noirq_set();
+ return NULL;
+ }
++ else if (!strcmp(str, "noearly")) {
++ pci_probe |= PCI_PROBE_NOEARLY;
++ return NULL;
++ }
+ #ifndef CONFIG_X86_VISWS
+ else if (!strcmp(str, "usepirqmask")) {
+ pci_probe |= PCI_USE_PIRQ_MASK;
+@@ -284,7 +343,6 @@ int pcibios_enable_device(struct pci_dev
+
+ void pcibios_disable_device (struct pci_dev *dev)
+ {
+- pcibios_disable_resources(dev);
+ if (pcibios_disable_irq)
+ pcibios_disable_irq(dev);
+ }
+diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
+index 5d81fb5..431c9a5 100644
+--- a/arch/i386/pci/direct.c
++++ b/arch/i386/pci/direct.c
+@@ -254,7 +254,18 @@ static int __init pci_check_type2(void)
+ return works;
+ }
+
+-void __init pci_direct_init(void)
++void __init pci_direct_init(int type)
++{
++ if (type == 0)
++ return;
++ printk(KERN_INFO "PCI: Using configuration type %d\n", type);
++ if (type == 1)
++ raw_pci_ops = &pci_direct_conf1;
++ else
++ raw_pci_ops = &pci_direct_conf2;
++}
++
++int __init pci_direct_probe(void)
+ {
+ struct resource *region, *region2;
+
+@@ -264,19 +275,16 @@ void __init pci_direct_init(void)
+ if (!region)
+ goto type2;
+
+- if (pci_check_type1()) {
+- printk(KERN_INFO "PCI: Using configuration type 1\n");
+- raw_pci_ops = &pci_direct_conf1;
+- return;
+- }
++ if (pci_check_type1())
++ return 1;
+ release_resource(region);
+
+ type2:
+ if ((pci_probe & PCI_PROBE_CONF2) == 0)
+- return;
++ return 0;
+ region = request_region(0xCF8, 4, "PCI conf2");
+ if (!region)
+- return;
++ return 0;
+ region2 = request_region(0xC000, 0x1000, "PCI conf2");
+ if (!region2)
+ goto fail2;
+@@ -284,10 +292,11 @@ void __init pci_direct_init(void)
+ if (pci_check_type2()) {
+ printk(KERN_INFO "PCI: Using configuration type 2\n");
+ raw_pci_ops = &pci_direct_conf2;
+- return;
++ return 2;
+ }
+
+ release_resource(region2);
+ fail2:
+ release_resource(region);
++ return 0;
+ }
+diff --git a/arch/i386/pci/early.c b/arch/i386/pci/early.c
+new file mode 100644
+index 0000000..713d6c8
+--- /dev/null
++++ b/arch/i386/pci/early.c
+@@ -0,0 +1,52 @@
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <asm/pci-direct.h>
++#include <asm/io.h>
++#include "pci.h"
++
++/* Direct PCI access. This is used for PCI accesses in early boot before
++ the PCI subsystem works. */
++
++#define PDprintk(x...)
++
++u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
++{
++ u32 v;
++ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
++ v = inl(0xcfc);
++ if (v != 0xffffffff)
++ PDprintk("%x reading 4 from %x: %x\n", slot, offset, v);
++ return v;
++}
++
++u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
++{
++ u8 v;
++ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
++ v = inb(0xcfc + (offset&3));
++ PDprintk("%x reading 1 from %x: %x\n", slot, offset, v);
++ return v;
++}
++
++u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
++{
++ u16 v;
++ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
++ v = inw(0xcfc + (offset&2));
++ PDprintk("%x reading 2 from %x: %x\n", slot, offset, v);
++ return v;
++}
++
++void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
++ u32 val)
++{
++ PDprintk("%x writing to %x: %x\n", slot, offset, val);
++ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
++ outl(val, 0xcfc);
++}
++
++int early_pci_allowed(void)
++{
++ return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) ==
++ PCI_PROBE_CONF1;
++}
+diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
+index 83c3645..c1949ff 100644
+--- a/arch/i386/pci/fixup.c
++++ b/arch/i386/pci/fixup.c
+@@ -348,8 +348,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
+ * From information provided by "Jon Smirl" <jonsmirl at gmail.com>
+ *
+ * The standard boot ROM sequence for an x86 machine uses the BIOS
+- * to select an initial video card for boot display. This boot video
+- * card will have it's BIOS copied to C0000 in system RAM.
++ * to select an initial video card for boot display. This boot video
++ * card will have it's BIOS copied to C0000 in system RAM.
+ * IORESOURCE_ROM_SHADOW is used to associate the boot video
+ * card with this copy. On laptops this copy has to be used since
+ * the main ROM may be compressed or combined with another image.
+@@ -371,7 +371,17 @@ static void __devinit pci_fixup_video(st
+ bus = pdev->bus;
+ while (bus) {
+ bridge = bus->self;
+- if (bridge) {
++
++ /*
++ * From information provided by
++ * "David Miller" <davem at davemloft.net>
++ * The bridge control register is valid for PCI header
++ * type BRIDGE, or CARDBUS. Host to PCI controllers use
++ * PCI header type NORMAL.
++ */
++ if (bridge
++ &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE)
++ ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) {
+ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
+ &config);
+ if (!(config & PCI_BRIDGE_CTL_VGA))
+@@ -393,7 +403,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI
+ * We pretend to bring them out of full D3 state, and restore the proper
+ * IRQ, PCI cache line size, and BARs, otherwise the device won't function
+ * properly. In some cases, the device will generate an interrupt on
+- * the wrong IRQ line, causing any devices sharing the the line it's
++ * the wrong IRQ line, causing any devices sharing the line it's
+ * *supposed* to use to be disabled by the kernel's IRQ debug code.
+ */
+ static u16 toshiba_line_size;
+diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
+index 10154a2..9858029 100644
+--- a/arch/i386/pci/i386.c
++++ b/arch/i386/pci/i386.c
+@@ -242,15 +242,6 @@ int pcibios_enable_resources(struct pci_
+ return 0;
+ }
+
+-void pcibios_disable_resources(struct pci_dev *dev)
+-{
+- u16 cmd;
+-
+- pci_read_config_word(dev, PCI_COMMAND, &cmd);
+- cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+- pci_write_config_word(dev, PCI_COMMAND, cmd);
+-}
+-
+ /*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain crappy BIOSes forget to set it properly.
+diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c
+index 51087a9..b21b6da 100644
+--- a/arch/i386/pci/init.c
++++ b/arch/i386/pci/init.c
+@@ -6,8 +6,13 @@
+ in the right sequence from here. */
+ static __init int pci_access_init(void)
+ {
++ int type = 0;
++
++#ifdef CONFIG_PCI_DIRECT
++ type = pci_direct_probe();
++#endif
+ #ifdef CONFIG_PCI_MMCONFIG
+- pci_mmcfg_init();
++ pci_mmcfg_init(type);
+ #endif
+ if (raw_pci_ops)
+ return 0;
+@@ -21,8 +26,12 @@ static __init int pci_access_init(void)
+ * fails.
+ */
+ #ifdef CONFIG_PCI_DIRECT
+- pci_direct_init();
++ pci_direct_init(type);
+ #endif
++ if (!raw_pci_ops)
++ printk(KERN_ERR
++ "PCI: Fatal: No config space access function found\n");
++
+ return 0;
+ }
+ arch_initcall(pci_access_init);
+diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
+index 4a8995c..dbc4aae 100644
+--- a/arch/i386/pci/irq.c
++++ b/arch/i386/pci/irq.c
+@@ -981,10 +981,6 @@ static void __init pcibios_fixup_irqs(vo
+ pci_name(bridge), 'A' + pin, irq);
+ }
+ if (irq >= 0) {
+- if (use_pci_vector() &&
+- !platform_legacy_irq(irq))
+- irq = IO_APIC_VECTOR(irq);
+-
+ printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
+ pci_name(dev), 'A' + pin, irq);
+ dev->irq = irq;
+@@ -1145,10 +1141,6 @@ static int pirq_enable_irq(struct pci_de
+ }
+ dev = temp_dev;
+ if (irq >= 0) {
+-#ifdef CONFIG_PCI_MSI
+- if (!platform_legacy_irq(irq))
+- irq = IO_APIC_VECTOR(irq);
+-#endif
+ printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
+ pci_name(dev), 'A' + pin, irq);
+ dev->irq = irq;
+@@ -1169,33 +1161,3 @@ static int pirq_enable_irq(struct pci_de
+ }
+ return 0;
+ }
+-
+-int pci_vector_resources(int last, int nr_released)
+-{
+- int count = nr_released;
+-
+- int next = last;
+- int offset = (last % 8);
+-
+- while (next < FIRST_SYSTEM_VECTOR) {
+- next += 8;
+-#ifdef CONFIG_X86_64
+- if (next == IA32_SYSCALL_VECTOR)
+- continue;
+-#else
+- if (next == SYSCALL_VECTOR)
+- continue;
+-#endif
+- count++;
+- if (next >= FIRST_SYSTEM_VECTOR) {
+- if (offset%8) {
+- next = FIRST_DEVICE_VECTOR + offset;
+- offset++;
+- continue;
+- }
+- count--;
+- }
+- }
+-
+- return count;
+-}
+diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
+index 972180f..d0c3da3 100644
+--- a/arch/i386/pci/mmconfig.c
++++ b/arch/i386/pci/mmconfig.c
+@@ -67,7 +67,10 @@ static u32 get_base_addr(unsigned int se
+ return 0;
+ }
+
+-static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
++/*
++ * This is always called under pci_config_lock
++ */
++static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
+ {
+ u32 dev_base = base | (bus << 20) | (devfn << 12);
+ if (dev_base != mmcfg_last_accessed_device) {
+@@ -151,6 +154,38 @@ static struct pci_raw_ops pci_mmcfg = {
+ .write = pci_mmcfg_write,
+ };
+
++
++static __init void pci_mmcfg_insert_resources(void)
++{
++#define PCI_MMCFG_RESOURCE_NAME_LEN 19
++ int i;
++ struct resource *res;
++ char *names;
++ unsigned num_buses;
++
++ res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
++ pci_mmcfg_config_num, GFP_KERNEL);
++
++ if (!res) {
++ printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
++ return;
++ }
++
++ names = (void *)&res[pci_mmcfg_config_num];
++ for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
++ num_buses = pci_mmcfg_config[i].end_bus_number -
++ pci_mmcfg_config[i].start_bus_number + 1;
++ res->name = names;
++ snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
++ pci_mmcfg_config[i].pci_segment_group_number);
++ res->start = pci_mmcfg_config[i].base_address;
++ res->end = res->start + (num_buses << 20) - 1;
++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++ insert_resource(&iomem_resource, res);
++ names += PCI_MMCFG_RESOURCE_NAME_LEN;
++ }
++}
++
+ /* K8 systems have some devices (typically in the builtin northbridge)
+ that are only accessible using type1
+ Normally this can be expressed in the MCFG by not listing them
+@@ -187,7 +222,9 @@ static __init void unreachable_devices(v
+ }
+ }
+
+-void __init pci_mmcfg_init(void)
++
++
++void __init pci_mmcfg_init(int type)
+ {
+ if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+ return;
+@@ -198,7 +235,9 @@ void __init pci_mmcfg_init(void)
+ (pci_mmcfg_config[0].base_address == 0))
+ return;
+
+- if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
++ /* Only do this check when type 1 works. If it doesn't work
++ assume we run on a Mac and always use MCFG */
++ if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
+ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+ E820_RESERVED)) {
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
+@@ -212,4 +251,5 @@ void __init pci_mmcfg_init(void)
+ pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+
+ unreachable_devices();
++ pci_mmcfg_insert_resources();
+ }
+diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
+index bf4e793..a0a2518 100644
+--- a/arch/i386/pci/pci.h
++++ b/arch/i386/pci/pci.h
+@@ -17,6 +17,7 @@
+ #define PCI_PROBE_CONF2 0x0004
+ #define PCI_PROBE_MMCONF 0x0008
+ #define PCI_PROBE_MASK 0x000f
++#define PCI_PROBE_NOEARLY 0x0010
+
+ #define PCI_NO_SORT 0x0100
+ #define PCI_BIOS_SORT 0x0200
+@@ -29,13 +30,19 @@
+ extern unsigned int pci_probe;
+ extern unsigned long pirq_table_addr;
+
++enum pci_bf_sort_state {
++ pci_bf_sort_default,
++ pci_force_nobf,
++ pci_force_bf,
++ pci_dmi_bf,
++};
++
+ /* pci-i386.c */
+
+ extern unsigned int pcibios_max_latency;
+
+ void pcibios_resource_survey(void);
+ int pcibios_enable_resources(struct pci_dev *, int);
+-void pcibios_disable_resources(struct pci_dev *);
+
+ /* pci-pc.c */
+
+@@ -81,7 +88,9 @@ extern int pci_conf1_write(unsigned int
+ extern int pci_conf1_read(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *value);
+
+-extern void pci_direct_init(void);
++extern int pci_direct_probe(void);
++extern void pci_direct_init(int type);
+ extern void pci_pcbios_init(void);
+-extern void pci_mmcfg_init(void);
++extern void pci_mmcfg_init(int type);
+ extern void pcibios_sort(void);
++
+diff --git a/arch/i386/power/swsusp.S b/arch/i386/power/swsusp.S
+index c893b89..8a2b50a 100644
+--- a/arch/i386/power/swsusp.S
++++ b/arch/i386/power/swsusp.S
+@@ -32,7 +32,7 @@ ENTRY(swsusp_arch_resume)
+ movl $swsusp_pg_dir-__PAGE_OFFSET, %ecx
+ movl %ecx, %cr3
+
+- movl pagedir_nosave, %edx
++ movl restore_pblist, %edx
+ .p2align 4,,7
+
+ copy_loop:
+diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
+index db274da..70f7eb9 100644
+--- a/arch/ia64/Kconfig
++++ b/arch/ia64/Kconfig
+@@ -66,15 +66,6 @@ config IA64_UNCACHED_ALLOCATOR
+ bool
+ select GENERIC_ALLOCATOR
+
+-config DMA_IS_DMA32
+- bool
+- default y
+-
+-config DMA_IS_NORMAL
+- bool
+- depends on IA64_SGI_SN2
+- default y
+-
+ config AUDIT_ARCH
+ bool
+ default y
+@@ -365,6 +356,9 @@ config NODES_SHIFT
+ MAX_NUMNODES will be 2^(This value).
+ If in doubt, use the default.
+
++config ARCH_POPULATES_NODE_MAP
++ def_bool y
++
+ # VIRTUAL_MEM_MAP and FLAT_NODE_MEM_MAP are functionally equivalent.
+ # VIRTUAL_MEM_MAP has been retained for historical reasons.
+ config VIRTUAL_MEM_MAP
+@@ -429,6 +423,14 @@ config IA64_PALINFO
+ config SGI_SN
+ def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
+
++config IA64_ESI
++ bool "ESI (Extensible SAL Interface) support"
++ help
++ If you say Y here, support is built into the kernel to
++ make ESI calls. ESI calls are used to support vendor-specific
++ firmware extensions, such as the ability to inject memory-errors
++ for test-purposes. If you're unsure, say N.
++
+ source "drivers/sn/Kconfig"
+
+ source "drivers/firmware/Kconfig"
+@@ -514,7 +516,7 @@ source "arch/ia64/oprofile/Kconfig"
+
+ config KPROBES
+ bool "Kprobes (EXPERIMENTAL)"
+- depends on EXPERIMENTAL && MODULES
++ depends on KALLSYMS && EXPERIMENTAL && MODULES
+ help
+ Kprobes allows you to trap at almost any kernel address and
+ execute a callback function. register_kprobe() establishes
+diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
+index 0f14a82..64e951d 100644
+--- a/arch/ia64/configs/sn2_defconfig
++++ b/arch/ia64/configs/sn2_defconfig
+@@ -1,8 +1,9 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.17-rc3
+-# Thu Apr 27 11:48:23 2006
++# Linux kernel version: 2.6.19-rc1
++# Mon Oct 9 10:53:59 2006
+ #
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+@@ -18,16 +19,22 @@ CONFIG_LOCALVERSION=""
+ # CONFIG_LOCALVERSION_AUTO is not set
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++CONFIG_TASKSTATS=y
++# CONFIG_TASK_DELAY_ACCT is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_CPUSETS=y
+ CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_TASK_XACCT=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ CONFIG_KALLSYMS_ALL=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -40,6 +47,8 @@ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -58,6 +67,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -89,7 +99,7 @@ CONFIG_EFI=y
+ CONFIG_GENERIC_IOMAP=y
+ CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+ CONFIG_IA64_UNCACHED_ALLOCATOR=y
+-CONFIG_DMA_IS_DMA32=y
++CONFIG_AUDIT_ARCH=y
+ # CONFIG_IA64_GENERIC is not set
+ # CONFIG_IA64_DIG is not set
+ # CONFIG_IA64_HP_ZX1 is not set
+@@ -116,6 +126,7 @@ CONFIG_FORCE_MAX_ZONEORDER=17
+ CONFIG_SMP=y
+ CONFIG_NR_CPUS=1024
+ # CONFIG_HOTPLUG_CPU is not set
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+ CONFIG_SCHED_SMT=y
+ CONFIG_PREEMPT=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+@@ -128,6 +139,7 @@ CONFIG_NEED_MULTIPLE_NODES=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
+ CONFIG_MIGRATION=y
++CONFIG_RESOURCES_64BIT=y
+ CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+ CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+@@ -135,15 +147,24 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
+ CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+ CONFIG_NUMA=y
+ CONFIG_NODES_SHIFT=10
++CONFIG_ARCH_POPULATES_NODE_MAP=y
+ CONFIG_VIRTUAL_MEM_MAP=y
+ CONFIG_HOLES_IN_ZONE=y
+ CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
++CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
+ CONFIG_IA32_SUPPORT=y
+ CONFIG_COMPAT=y
+ CONFIG_IA64_MCA_RECOVERY=y
+ CONFIG_PERFMON=y
+ CONFIG_IA64_PALINFO=y
+ CONFIG_SGI_SN=y
++# CONFIG_IA64_ESI is not set
++
++#
++# SN Devices
++#
++CONFIG_SGI_IOC4=y
++CONFIG_SGI_IOC3=y
+
+ #
+ # Firmware Drivers
+@@ -159,6 +180,7 @@ CONFIG_BINFMT_ELF=y
+ CONFIG_PM=y
+ # CONFIG_PM_LEGACY is not set
+ # CONFIG_PM_DEBUG is not set
++# CONFIG_PM_SYSFS_DEPRECATED is not set
+
+ #
+ # ACPI (Advanced Configuration and Power Interface) Support
+@@ -166,6 +188,7 @@ CONFIG_PM=y
+ CONFIG_ACPI=y
+ # CONFIG_ACPI_BUTTON is not set
+ # CONFIG_ACPI_FAN is not set
++# CONFIG_ACPI_DOCK is not set
+ # CONFIG_ACPI_PROCESSOR is not set
+ CONFIG_ACPI_NUMA=y
+ CONFIG_ACPI_BLACKLIST_YEAR=0
+@@ -185,7 +208,12 @@ CONFIG_ACPI_SYSTEM=y
+ #
+ CONFIG_PCI=y
+ CONFIG_PCI_DOMAINS=y
++CONFIG_PCIEPORTBUS=y
++CONFIG_HOTPLUG_PCI_PCIE=y
++# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
++CONFIG_PCIEAER=y
+ # CONFIG_PCI_MSI is not set
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ # CONFIG_PCI_DEBUG is not set
+
+ #
+@@ -215,6 +243,9 @@ CONFIG_NET=y
+ CONFIG_PACKET=y
+ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -231,19 +262,31 @@ CONFIG_SYN_COOKIES=y
+ # CONFIG_INET_IPCOMP is not set
+ # CONFIG_INET_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=m
+ CONFIG_INET_TCP_DIAG=m
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ CONFIG_IPV6=m
+ # CONFIG_IPV6_PRIVACY is not set
+ # CONFIG_IPV6_ROUTER_PREF is not set
+ # CONFIG_INET6_AH is not set
+ # CONFIG_INET6_ESP is not set
+ # CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+ # CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+ #
+@@ -269,7 +312,6 @@ CONFIG_IPV6=m
+ # 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
+
+@@ -298,6 +340,7 @@ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ CONFIG_FW_LOADER=y
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -335,6 +378,7 @@ CONFIG_BLK_DEV_NBD=m
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ CONFIG_ATA_OVER_ETH=m
+@@ -381,6 +425,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
+ # CONFIG_BLK_DEV_CS5530 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+ # CONFIG_BLK_DEV_PIIX is not set
+ # CONFIG_BLK_DEV_IT821X is not set
+@@ -404,6 +449,7 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -425,12 +471,14 @@ CONFIG_SCSI_CONSTANTS=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=y
+ CONFIG_SCSI_FC_ATTRS=y
+ CONFIG_SCSI_ISCSI_ATTRS=m
+ CONFIG_SCSI_SAS_ATTRS=y
++CONFIG_SCSI_SAS_LIBSAS=y
++# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
+
+ #
+ # SCSI low-level drivers
+@@ -443,46 +491,82 @@ CONFIG_ISCSI_TCP=m
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-CONFIG_SCSI_SATA=y
+-# CONFIG_SCSI_SATA_AHCI is not set
+-# CONFIG_SCSI_SATA_SVW is not set
+-# CONFIG_SCSI_ATA_PIIX is not set
+-# CONFIG_SCSI_SATA_MV is not set
+-# CONFIG_SCSI_SATA_NV is not set
+-# CONFIG_SCSI_PDC_ADMA is not set
+-# CONFIG_SCSI_SATA_QSTOR is not set
+-# CONFIG_SCSI_SATA_PROMISE is not set
+-# CONFIG_SCSI_SATA_SX4 is not set
+-# CONFIG_SCSI_SATA_SIL is not set
+-# CONFIG_SCSI_SATA_SIL24 is not set
+-# CONFIG_SCSI_SATA_SIS is not set
+-# CONFIG_SCSI_SATA_ULI is not set
+-# CONFIG_SCSI_SATA_VIA is not set
+-CONFIG_SCSI_SATA_VITESSE=y
++# CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+ # CONFIG_SCSI_IPR is not set
+ CONFIG_SCSI_QLOGIC_1280=y
+ CONFIG_SCSI_QLA_FC=y
+-CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE=y
+-# CONFIG_SCSI_QLA21XX is not set
+-CONFIG_SCSI_QLA22XX=y
+-CONFIG_SCSI_QLA2300=y
+-CONFIG_SCSI_QLA2322=y
+-# CONFIG_SCSI_QLA24XX is not set
++# CONFIG_SCSI_QLA_ISCSI 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
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++# CONFIG_SATA_SVW is not set
++# CONFIG_ATA_PIIX is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
++# CONFIG_PDC_ADMA is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++# CONFIG_SATA_SIL is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++CONFIG_SATA_VITESSE=y
++# CONFIG_PATA_ALI is not set
++# CONFIG_PATA_AMD is not set
++# CONFIG_PATA_ARTOP is not set
++# CONFIG_PATA_ATIIXP is not set
++# CONFIG_PATA_CMD64X is not set
++# CONFIG_PATA_CS5520 is not set
++# CONFIG_PATA_CS5530 is not set
++# CONFIG_PATA_CYPRESS is not set
++# CONFIG_PATA_EFAR is not set
++# CONFIG_ATA_GENERIC is not set
++# CONFIG_PATA_HPT366 is not set
++# CONFIG_PATA_HPT37X is not set
++# CONFIG_PATA_HPT3X2N is not set
++# CONFIG_PATA_HPT3X3 is not set
++# CONFIG_PATA_IT821X is not set
++# CONFIG_PATA_JMICRON is not set
++# CONFIG_PATA_TRIFLEX is not set
++# CONFIG_PATA_MPIIX is not set
++# CONFIG_PATA_OLDPIIX is not set
++# CONFIG_PATA_NETCELL is not set
++# CONFIG_PATA_NS87410 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_OPTIDMA is not set
++# CONFIG_PATA_PDC_OLD is not set
++# CONFIG_PATA_RADISYS is not set
++# CONFIG_PATA_RZ1000 is not set
++# CONFIG_PATA_SC1200 is not set
++# CONFIG_PATA_SERVERWORKS is not set
++# CONFIG_PATA_PDC2027X is not set
++# CONFIG_PATA_SIL680 is not set
++# CONFIG_PATA_SIS is not set
++# CONFIG_PATA_VIA is not set
++# CONFIG_PATA_WINBOND is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ CONFIG_MD=y
+@@ -491,12 +575,12 @@ CONFIG_MD_LINEAR=y
+ CONFIG_MD_RAID0=y
+ CONFIG_MD_RAID1=y
+ # CONFIG_MD_RAID10 is not set
+-CONFIG_MD_RAID5=y
++CONFIG_MD_RAID456=y
+ # CONFIG_MD_RAID5_RESHAPE is not set
+-# CONFIG_MD_RAID6 is not set
+ CONFIG_MD_MULTIPATH=y
+ # CONFIG_MD_FAULTY is not set
+ CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
+ CONFIG_DM_CRYPT=m
+ CONFIG_DM_SNAPSHOT=m
+ CONFIG_DM_MIRROR=m
+@@ -563,6 +647,7 @@ CONFIG_NETDEVICES=y
+ # CONFIG_SK98LIN is not set
+ CONFIG_TIGON3=y
+ # CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -571,6 +656,7 @@ CONFIG_CHELSIO_T1=m
+ # CONFIG_IXGB is not set
+ CONFIG_S2IO=m
+ # CONFIG_S2IO_NAPI is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -612,6 +698,7 @@ CONFIG_NET_POLL_CONTROLLER=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -646,6 +733,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ CONFIG_SERIAL_NONSTANDARD=y
+ # CONFIG_COMPUTONE is not set
+ # CONFIG_ROCKETPORT is not set
+@@ -659,10 +747,12 @@ CONFIG_SERIAL_NONSTANDARD=y
+ # CONFIG_N_HDLC is not set
+ # CONFIG_SPECIALIX is not set
+ # CONFIG_SX is not set
++# CONFIG_RIO is not set
+ # CONFIG_STALDRV is not set
+ CONFIG_SGI_SNSC=y
+ CONFIG_SGI_TIOCX=y
+ CONFIG_SGI_MBCS=m
++CONFIG_MSPEC=y
+
+ #
+ # Serial drivers
+@@ -701,6 +791,7 @@ CONFIG_EFI_RTC=y
+ # Ftape, the floppy tape device driver
+ #
+ CONFIG_AGP=y
++# CONFIG_AGP_SIS is not set
+ # CONFIG_AGP_VIA is not set
+ CONFIG_AGP_SGI_TIOCA=y
+ # CONFIG_DRM is not set
+@@ -730,7 +821,6 @@ CONFIG_MMTIMER=y
+ #
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -741,6 +831,7 @@ CONFIG_MMTIMER=y
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+@@ -756,6 +847,7 @@ CONFIG_MMTIMER=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
+
+ #
+@@ -764,6 +856,7 @@ CONFIG_MMTIMER=y
+ CONFIG_VGA_CONSOLE=y
+ # CONFIG_VGACON_SOFT_SCROLLBACK is not set
+ CONFIG_DUMMY_CONSOLE=y
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -794,6 +887,7 @@ CONFIG_USB=m
+ CONFIG_USB_EHCI_HCD=m
+ # CONFIG_USB_EHCI_SPLIT_ISO is not set
+ # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+ # CONFIG_USB_ISP116X_HCD is not set
+ CONFIG_USB_OHCI_HCD=m
+ # CONFIG_USB_OHCI_BIG_ENDIAN is not set
+@@ -843,6 +937,7 @@ CONFIG_USB_HIDINPUT=y
+ # CONFIG_USB_ATI_REMOTE2 is not set
+ # CONFIG_USB_KEYSPAN_REMOTE is not set
+ # CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+
+ #
+ # USB Imaging devices
+@@ -874,15 +969,18 @@ CONFIG_USB_MON=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_SISUSBVGA is not set
+ # CONFIG_USB_LD is not set
+
+@@ -919,18 +1017,15 @@ CONFIG_USB_MON=y
+ CONFIG_INFINIBAND=m
+ # CONFIG_INFINIBAND_USER_MAD is not set
+ CONFIG_INFINIBAND_USER_ACCESS=m
++CONFIG_INFINIBAND_ADDR_TRANS=y
+ CONFIG_INFINIBAND_MTHCA=m
+ CONFIG_INFINIBAND_MTHCA_DEBUG=y
++# CONFIG_INFINIBAND_AMSO1100 is not set
+ CONFIG_INFINIBAND_IPOIB=m
+ CONFIG_INFINIBAND_IPOIB_DEBUG=y
+ # CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
+ CONFIG_INFINIBAND_SRP=m
+-
+-#
+-# SN Devices
+-#
+-CONFIG_SGI_IOC4=y
+-CONFIG_SGI_IOC3=y
++# CONFIG_INFINIBAND_ISER is not set
+
+ #
+ # EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+@@ -942,6 +1037,19 @@ CONFIG_SGI_IOC3=y
+ # CONFIG_RTC_CLASS is not set
+
+ #
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+@@ -965,15 +1073,16 @@ CONFIG_REISERFS_FS_SECURITY=y
+ # CONFIG_JFS_FS is not set
+ CONFIG_FS_POSIX_ACL=y
+ CONFIG_XFS_FS=y
+-CONFIG_XFS_EXPORT=y
+ CONFIG_XFS_QUOTA=y
+ # CONFIG_XFS_SECURITY is not set
+ CONFIG_XFS_POSIX_ACL=y
+ CONFIG_XFS_RT=y
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ CONFIG_QUOTA=y
+ # CONFIG_QFMT_V1 is not set
+ # CONFIG_QFMT_V2 is not set
+@@ -1007,8 +1116,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+@@ -1046,7 +1157,7 @@ CONFIG_NFSD_V4=y
+ CONFIG_NFSD_TCP=y
+ CONFIG_LOCKD=m
+ CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
++CONFIG_EXPORTFS=m
+ CONFIG_NFS_COMMON=y
+ CONFIG_SUNRPC=m
+ CONFIG_SUNRPC_GSS=m
+@@ -1056,7 +1167,9 @@ CONFIG_SMB_FS=m
+ # CONFIG_SMB_NLS_DEFAULT is not set
+ CONFIG_CIFS=m
+ # CONFIG_CIFS_STATS is not set
++# CONFIG_CIFS_WEAK_PW_HASH is not set
+ # CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_CIFS_EXPERIMENTAL is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+@@ -1129,6 +1242,10 @@ CONFIG_NLS_ISO8859_1=y
+ CONFIG_NLS_UTF8=y
+
+ #
++# Distributed Lock Manager
++#
++
++#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+@@ -1138,9 +1255,11 @@ CONFIG_LIBCRC32C=m
+ CONFIG_ZLIB_INFLATE=m
+ CONFIG_ZLIB_DEFLATE=m
+ CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_PLIST=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_IRQ_PER_CPU=y
+
+ #
+ # Instrumentation Support
+@@ -1152,20 +1271,26 @@ CONFIG_GENERIC_PENDING_IRQ=y
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=20
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+-CONFIG_DEBUG_PREEMPT=y
+-# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ CONFIG_DEBUG_INFO=y
+ # CONFIG_DEBUG_FS is not set
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ CONFIG_FORCED_INLINING=y
+ # CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_IA64_GRANULE_16MB=y
+@@ -1186,6 +1311,10 @@ CONFIG_SYSVIPC_COMPAT=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -1195,6 +1324,8 @@ CONFIG_CRYPTO_SHA1=m
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=m
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
+index b5195be..424e925 100644
+--- a/arch/ia64/hp/sim/simeth.c
++++ b/arch/ia64/hp/sim/simeth.c
+@@ -54,7 +54,7 @@ static int simeth_close(struct net_devic
+ static int simeth_tx(struct sk_buff *skb, struct net_device *dev);
+ static int simeth_rx(struct net_device *dev);
+ static struct net_device_stats *simeth_get_stats(struct net_device *dev);
+-static irqreturn_t simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t simeth_interrupt(int irq, void *dev_id);
+ static void set_multicast_list(struct net_device *dev);
+ static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr);
+
+@@ -87,7 +87,7 @@ static int simeth_debug; /* set to 1 to
+ */
+ static struct notifier_block simeth_dev_notifier = {
+ simeth_device_event,
+- 0
++ NULL
+ };
+
+
+@@ -320,7 +320,7 @@ simeth_device_event(struct notifier_bloc
+ }
+
+ printk(KERN_INFO "simeth_device_event: %s ipaddr=0x%x\n",
+- dev->name, htonl(ifa->ifa_local));
++ dev->name, ntohl(ifa->ifa_local));
+
+ /*
+ * XXX Fix me
+@@ -331,7 +331,7 @@ simeth_device_event(struct notifier_bloc
+ local = dev->priv;
+ /* now do it for real */
+ r = event == NETDEV_UP ?
+- netdev_attach(local->simfd, dev->irq, htonl(ifa->ifa_local)):
++ netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)):
+ netdev_detach(local->simfd);
+
+ printk(KERN_INFO "simeth: netdev_attach/detach: event=%s ->%d\n",
+@@ -497,7 +497,7 @@ simeth_rx(struct net_device *dev)
+ * Interrupt handler (Yes, we can do it too !!!)
+ */
+ static irqreturn_t
+-simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++simeth_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+
+diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
+index 8f0a16a..bb87682 100644
+--- a/arch/ia64/hp/sim/simscsi.c
++++ b/arch/ia64/hp/sim/simscsi.c
+@@ -103,7 +103,7 @@ simscsi_interrupt (unsigned long val)
+
+ while ((sc = queue[rd].sc) != 0) {
+ atomic_dec(&num_reqs);
+- queue[rd].sc = 0;
++ queue[rd].sc = NULL;
+ if (DBG)
+ printk("simscsi_interrupt: done with %ld\n", sc->serial_number);
+ (*sc->scsi_done)(sc);
+diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
+index 0daacc2..caab986 100644
+--- a/arch/ia64/hp/sim/simserial.c
++++ b/arch/ia64/hp/sim/simserial.c
+@@ -92,7 +92,7 @@ static struct serial_uart_config uart_co
+ { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
+ { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+- { 0, 0}
++ { NULL, 0}
+ };
+
+ struct tty_driver *hp_simserial_driver;
+@@ -130,7 +130,7 @@ static void rs_start(struct tty_struct *
+ #endif
+ }
+
+-static void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
++static void receive_chars(struct tty_struct *tty)
+ {
+ unsigned char ch;
+ static unsigned char seen_esc = 0;
+@@ -152,7 +152,7 @@ static void receive_chars(struct tty_st
+ ch = ia64_ssc(0, 0, 0, 0,
+ SSC_GETCHAR);
+ while (!ch);
+- handle_sysrq(ch, regs, NULL);
++ handle_sysrq(ch, NULL);
+ }
+ #endif
+ seen_esc = 0;
+@@ -170,7 +170,7 @@ static void receive_chars(struct tty_st
+ /*
+ * This is the serial driver's interrupt routine for a single port
+ */
+-static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
+ {
+ struct async_struct * info;
+
+@@ -187,7 +187,7 @@ static irqreturn_t rs_interrupt_single(i
+ * pretty simple in our case, because we only get interrupts
+ * on inbound traffic
+ */
+- receive_chars(info->tty, regs);
++ receive_chars(info->tty);
+ return IRQ_HANDLED;
+ }
+
+@@ -555,7 +555,7 @@ static void shutdown(struct async_struct
+
+ if (info->xmit.buf) {
+ free_page((unsigned long) info->xmit.buf);
+- info->xmit.buf = 0;
++ info->xmit.buf = NULL;
+ }
+
+ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
+@@ -628,7 +628,7 @@ static void rs_close(struct tty_struct *
+ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty);
+ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
+ info->event = 0;
+- info->tty = 0;
++ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->close_delay)
+ schedule_timeout_interruptible(info->close_delay);
+@@ -668,7 +668,7 @@ static void rs_hangup(struct tty_struct
+ info->event = 0;
+ state->count = 0;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+- info->tty = 0;
++ info->tty = NULL;
+ wake_up_interruptible(&info->open_wait);
+ }
+
+@@ -714,7 +714,7 @@ startup(struct async_struct *info)
+ {
+ unsigned long flags;
+ int retval=0;
+- irqreturn_t (*handler)(int, void *, struct pt_regs *);
++ irq_handler_t handler;
+ struct serial_state *state= info->state;
+ unsigned long page;
+
+@@ -769,7 +769,7 @@ startup(struct async_struct *info)
+ /*
+ * Insert serial port into IRQ chain.
+ */
+- info->prev_port = 0;
++ info->prev_port = NULL;
+ info->next_port = IRQ_ports[state->irq];
+ if (info->next_port)
+ info->next_port->prev_port = info;
+@@ -940,7 +940,7 @@ static inline void show_serial_version(v
+ printk(KERN_INFO " no serial options enabled\n");
+ }
+
+-static struct tty_operations hp_ops = {
++static const struct tty_operations hp_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
+index 6aa3c51..9d6a3f2 100644
+--- a/arch/ia64/ia32/sys_ia32.c
++++ b/arch/ia64/ia32/sys_ia32.c
+@@ -125,6 +125,7 @@ sys32_execve (char __user *name, compat_
+
+ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
+ {
++ compat_ino_t ino;
+ int err;
+
+ if ((u64) stat->size > MAX_NON_LFS ||
+@@ -132,11 +133,15 @@ int cp_compat_stat(struct kstat *stat, s
+ !old_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+
++ ino = stat->ino;
++ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
++ return -EOVERFLOW;
++
+ if (clear_user(ubuf, sizeof(*ubuf)))
+ return -EFAULT;
+
+ err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
+- err |= __put_user(stat->ino, &ubuf->st_ino);
++ err |= __put_user(ino, &ubuf->st_ino);
+ err |= __put_user(stat->mode, &ubuf->st_mode);
+ err |= __put_user(stat->nlink, &ubuf->st_nlink);
+ err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
+@@ -1222,16 +1227,20 @@ struct readdir32_callback {
+ };
+
+ static int
+-filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
++filldir32 (void *__buf, const char *name, int namlen, loff_t offset, u64 ino,
+ unsigned int d_type)
+ {
+ struct compat_dirent __user * dirent;
+ struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+ int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4);
++ u32 d_ino;
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ buf->error = -EFAULT; /* only used if we fail.. */
+ dirent = buf->previous;
+ if (dirent)
+@@ -1239,7 +1248,7 @@ filldir32 (void *__buf, const char *name
+ return -EFAULT;
+ dirent = buf->current_dir;
+ buf->previous = dirent;
+- if (put_user(ino, &dirent->d_ino)
++ if (put_user(d_ino, &dirent->d_ino)
+ || put_user(reclen, &dirent->d_reclen)
+ || copy_to_user(dirent->d_name, name, namlen)
+ || put_user(0, dirent->d_name + namlen))
+@@ -1287,17 +1296,21 @@ out:
+ }
+
+ static int
+-fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
++fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, u64 ino,
+ unsigned int d_type)
+ {
+ struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
+ struct old_linux32_dirent __user * dirent;
++ u32 d_ino;
+
+ if (buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ buf->count++;
+ dirent = buf->dirent;
+- if (put_user(ino, &dirent->d_ino)
++ if (put_user(d_ino, &dirent->d_ino)
+ || put_user(offset, &dirent->d_offset)
+ || put_user(namlen, &dirent->d_namlen)
+ || copy_to_user(dirent->d_name, name, namlen)
+@@ -1942,7 +1955,7 @@ struct sysctl32 {
+ unsigned int __unused[4];
+ };
+
+-#ifdef CONFIG_SYSCTL
++#ifdef CONFIG_SYSCTL_SYSCALL
+ asmlinkage long
+ sys32_sysctl (struct sysctl32 __user *args)
+ {
+diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
+index ad8215a..cfa099b 100644
+--- a/arch/ia64/kernel/Makefile
++++ b/arch/ia64/kernel/Makefile
+@@ -30,8 +30,14 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_r
+ obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
+ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
+ obj-$(CONFIG_AUDIT) += audit.o
++obj-$(CONFIG_PCI_MSI) += msi_ia64.o
+ mca_recovery-y += mca_drv.o mca_drv_asm.o
+
++obj-$(CONFIG_IA64_ESI) += esi.o
++ifneq ($(CONFIG_IA64_ESI),)
++obj-y += esi_stub.o # must be in kernel proper
++endif
++
+ # The gate DSO image is built using a special linker script.
+ targets += gate.so gate-syms.o
+
+diff --git a/arch/ia64/kernel/acpi-processor.c b/arch/ia64/kernel/acpi-processor.c
+index e683630..4d4993a 100644
+--- a/arch/ia64/kernel/acpi-processor.c
++++ b/arch/ia64/kernel/acpi-processor.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/ia64/kernel/cpufreq/processor.c
++ * arch/ia64/kernel/acpi-processor.c
+ *
+ * Copyright (C) 2005 Intel Corporation
+ * Venkatesh Pallipadi <venkatesh.pallipadi at intel.com>
+diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
+index 0176556..73ef4a8 100644
+--- a/arch/ia64/kernel/acpi.c
++++ b/arch/ia64/kernel/acpi.c
+@@ -64,9 +64,6 @@ EXPORT_SYMBOL(pm_idle);
+ void (*pm_power_off) (void);
+ EXPORT_SYMBOL(pm_power_off);
+
+-unsigned char acpi_kbd_controller_present = 1;
+-unsigned char acpi_legacy_devices;
+-
+ unsigned int acpi_cpei_override;
+ unsigned int acpi_cpei_phys_cpuid;
+
+@@ -628,12 +625,6 @@ static int __init acpi_parse_fadt(unsign
+
+ fadt = (struct fadt_descriptor *)fadt_header;
+
+- if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
+- acpi_kbd_controller_present = 0;
+-
+- if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
+- acpi_legacy_devices = 1;
+-
+ acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
+ return 0;
+ }
+@@ -771,16 +762,19 @@ int acpi_map_cpu2node(acpi_handle handle
+ {
+ #ifdef CONFIG_ACPI_NUMA
+ int pxm_id;
++ int nid;
+
+ pxm_id = acpi_get_pxm(handle);
+-
+ /*
+- * Assuming that the container driver would have set the proximity
+- * domain and would have initialized pxm_to_node(pxm_id) && pxm_flag
++ * We don't have cpu-only-node hotadd. But if the system equips
++ * SRAT table, pxm is already found and node is ready.
++ * So, just pxm_to_nid(pxm) is OK.
++ * This code here is for the system which doesn't have full SRAT
++ * table for possible cpus.
+ */
+- node_cpuid[cpu].nid = (pxm_id < 0) ? 0 : pxm_to_node(pxm_id);
+-
++ nid = acpi_map_pxm_to_node(pxm_id);
+ node_cpuid[cpu].phys_id = physid;
++ node_cpuid[cpu].nid = nid;
+ #endif
+ return (0);
+ }
+diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
+index fef0657..3390b7c 100644
+--- a/arch/ia64/kernel/entry.S
++++ b/arch/ia64/kernel/entry.S
+@@ -1,5 +1,5 @@
+ /*
+- * ia64/kernel/entry.S
++ * arch/ia64/kernel/entry.S
+ *
+ * Kernel entry points.
+ *
+@@ -492,11 +492,11 @@ GLOBAL_ENTRY(prefetch_stack)
+ br.ret.sptk.many rp
+ END(prefetch_stack)
+
+-GLOBAL_ENTRY(execve)
++GLOBAL_ENTRY(kernel_execve)
+ mov r15=__NR_execve // put syscall number in place
+ break __BREAK_SYSCALL
+ br.ret.sptk.many rp
+-END(execve)
++END(kernel_execve)
+
+ GLOBAL_ENTRY(clone)
+ mov r15=__NR_clone // put syscall number in place
+@@ -1605,8 +1605,8 @@ sys_call_table:
+ data8 sys_ni_syscall // 1295 reserved for ppoll
+ data8 sys_unshare
+ data8 sys_splice
+- data8 sys_ni_syscall // reserved for set_robust_list
+- data8 sys_ni_syscall // reserved for get_robust_list
++ data8 sys_set_robust_list
++ data8 sys_get_robust_list
+ data8 sys_sync_file_range // 1300
+ data8 sys_tee
+ data8 sys_vmsplice
+diff --git a/arch/ia64/kernel/esi.c b/arch/ia64/kernel/esi.c
+new file mode 100644
+index 0000000..ebf4e98
+--- /dev/null
++++ b/arch/ia64/kernel/esi.c
+@@ -0,0 +1,205 @@
++/*
++ * Extensible SAL Interface (ESI) support routines.
++ *
++ * Copyright (C) 2006 Hewlett-Packard Co
++ * Alex Williamson <alex.williamson at hp.com>
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/string.h>
++
++#include <asm/esi.h>
++#include <asm/sal.h>
++
++MODULE_AUTHOR("Alex Williamson <alex.williamson at hp.com>");
++MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
++MODULE_LICENSE("GPL");
++
++#define MODULE_NAME "esi"
++
++#define ESI_TABLE_GUID \
++ EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3, \
++ 0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
++
++enum esi_systab_entry_type {
++ ESI_DESC_ENTRY_POINT = 0
++};
++
++/*
++ * Entry type: Size:
++ * 0 48
++ */
++#define ESI_DESC_SIZE(type) "\060"[(unsigned) (type)]
++
++typedef struct ia64_esi_desc_entry_point {
++ u8 type;
++ u8 reserved1[15];
++ u64 esi_proc;
++ u64 gp;
++ efi_guid_t guid;
++} ia64_esi_desc_entry_point_t;
++
++struct pdesc {
++ void *addr;
++ void *gp;
++};
++
++static struct ia64_sal_systab *esi_systab;
++
++static int __init esi_init (void)
++{
++ efi_config_table_t *config_tables;
++ struct ia64_sal_systab *systab;
++ unsigned long esi = 0;
++ char *p;
++ int i;
++
++ config_tables = __va(efi.systab->tables);
++
++ for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
++ if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
++ esi = config_tables[i].table;
++ break;
++ }
++ }
++
++ if (!esi)
++ return -ENODEV;;
++
++ systab = __va(esi);
++
++ if (strncmp(systab->signature, "ESIT", 4) != 0) {
++ printk(KERN_ERR "bad signature in ESI system table!");
++ return -ENODEV;
++ }
++
++ p = (char *) (systab + 1);
++ for (i = 0; i < systab->entry_count; i++) {
++ /*
++ * The first byte of each entry type contains the type
++ * descriptor.
++ */
++ switch (*p) {
++ case ESI_DESC_ENTRY_POINT:
++ break;
++ default:
++ printk(KERN_WARNING "Unkown table type %d found in "
++ "ESI table, ignoring rest of table\n", *p);
++ return -ENODEV;
++ }
++
++ p += ESI_DESC_SIZE(*p);
++ }
++
++ esi_systab = systab;
++ return 0;
++}
++
++
++int ia64_esi_call (efi_guid_t guid, struct ia64_sal_retval *isrvp,
++ enum esi_proc_type proc_type, u64 func,
++ u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6,
++ u64 arg7)
++{
++ struct ia64_fpreg fr[6];
++ unsigned long flags = 0;
++ int i;
++ char *p;
++
++ if (!esi_systab)
++ return -1;
++
++ p = (char *) (esi_systab + 1);
++ for (i = 0; i < esi_systab->entry_count; i++) {
++ if (*p == ESI_DESC_ENTRY_POINT) {
++ ia64_esi_desc_entry_point_t *esi = (void *)p;
++ if (!efi_guidcmp(guid, esi->guid)) {
++ ia64_sal_handler esi_proc;
++ struct pdesc pdesc;
++
++ pdesc.addr = __va(esi->esi_proc);
++ pdesc.gp = __va(esi->gp);
++
++ esi_proc = (ia64_sal_handler) &pdesc;
++
++ ia64_save_scratch_fpregs(fr);
++ if (proc_type == ESI_PROC_SERIALIZED)
++ spin_lock_irqsave(&sal_lock, flags);
++ else if (proc_type == ESI_PROC_MP_SAFE)
++ local_irq_save(flags);
++ else
++ preempt_disable();
++ *isrvp = (*esi_proc)(func, arg1, arg2, arg3,
++ arg4, arg5, arg6, arg7);
++ if (proc_type == ESI_PROC_SERIALIZED)
++ spin_unlock_irqrestore(&sal_lock,
++ flags);
++ else if (proc_type == ESI_PROC_MP_SAFE)
++ local_irq_restore(flags);
++ else
++ preempt_enable();
++ ia64_load_scratch_fpregs(fr);
++ return 0;
++ }
++ }
++ p += ESI_DESC_SIZE(*p);
++ }
++ return -1;
++}
++EXPORT_SYMBOL_GPL(ia64_esi_call);
++
++int ia64_esi_call_phys (efi_guid_t guid, struct ia64_sal_retval *isrvp,
++ u64 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4,
++ u64 arg5, u64 arg6, u64 arg7)
++{
++ struct ia64_fpreg fr[6];
++ unsigned long flags;
++ u64 esi_params[8];
++ char *p;
++ int i;
++
++ if (!esi_systab)
++ return -1;
++
++ p = (char *) (esi_systab + 1);
++ for (i = 0; i < esi_systab->entry_count; i++) {
++ if (*p == ESI_DESC_ENTRY_POINT) {
++ ia64_esi_desc_entry_point_t *esi = (void *)p;
++ if (!efi_guidcmp(guid, esi->guid)) {
++ ia64_sal_handler esi_proc;
++ struct pdesc pdesc;
++
++ pdesc.addr = (void *)esi->esi_proc;
++ pdesc.gp = (void *)esi->gp;
++
++ esi_proc = (ia64_sal_handler) &pdesc;
++
++ esi_params[0] = func;
++ esi_params[1] = arg1;
++ esi_params[2] = arg2;
++ esi_params[3] = arg3;
++ esi_params[4] = arg4;
++ esi_params[5] = arg5;
++ esi_params[6] = arg6;
++ esi_params[7] = arg7;
++ ia64_save_scratch_fpregs(fr);
++ spin_lock_irqsave(&sal_lock, flags);
++ *isrvp = esi_call_phys(esi_proc, esi_params);
++ spin_unlock_irqrestore(&sal_lock, flags);
++ ia64_load_scratch_fpregs(fr);
++ return 0;
++ }
++ }
++ p += ESI_DESC_SIZE(*p);
++ }
++ return -1;
++}
++EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
++
++static void __exit esi_exit (void)
++{
++}
++
++module_init(esi_init);
++module_exit(esi_exit); /* makes module removable... */
+diff --git a/arch/ia64/kernel/esi_stub.S b/arch/ia64/kernel/esi_stub.S
+new file mode 100644
+index 0000000..6b3d6c1
+--- /dev/null
++++ b/arch/ia64/kernel/esi_stub.S
+@@ -0,0 +1,96 @@
++/*
++ * ESI call stub.
++ *
++ * Copyright (C) 2005 Hewlett-Packard Co
++ * Alex Williamson <alex.williamson at hp.com>
++ *
++ * Based on EFI call stub by David Mosberger. The stub is virtually
++ * identical to the one for EFI phys-mode calls, except that ESI
++ * calls may have up to 8 arguments, so they get passed to this routine
++ * through memory.
++ *
++ * This stub allows us to make ESI calls in physical mode with interrupts
++ * turned off. ESI calls may not support calling from virtual mode.
++ *
++ * Google for "Extensible SAL specification" for a document describing the
++ * ESI standard.
++ */
++
++/*
++ * PSR settings as per SAL spec (Chapter 8 in the "IA-64 System
++ * Abstraction Layer Specification", revision 2.6e). Note that
++ * psr.dfl and psr.dfh MUST be cleared, despite what this manual says.
++ * Otherwise, SAL dies whenever it's trying to do an IA-32 BIOS call
++ * (the br.ia instruction fails unless psr.dfl and psr.dfh are
++ * cleared). Fortunately, SAL promises not to touch the floating
++ * point regs, so at least we don't have to save f2-f127.
++ */
++#define PSR_BITS_TO_CLEAR \
++ (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \
++ IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
++ IA64_PSR_DFL | IA64_PSR_DFH)
++
++#define PSR_BITS_TO_SET \
++ (IA64_PSR_BN)
++
++#include <asm/processor.h>
++#include <asm/asmmacro.h>
++
++/*
++ * Inputs:
++ * in0 = address of function descriptor of ESI routine to call
++ * in1 = address of array of ESI parameters
++ *
++ * Outputs:
++ * r8 = result returned by called function
++ */
++GLOBAL_ENTRY(esi_call_phys)
++ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
++ alloc loc1=ar.pfs,2,7,8,0
++ ld8 r2=[in0],8 // load ESI function's entry point
++ mov loc0=rp
++ .body
++ ;;
++ ld8 out0=[in1],8 // ESI params loaded from array
++ ;; // passing all as inputs doesn't work
++ ld8 out1=[in1],8
++ ;;
++ ld8 out2=[in1],8
++ ;;
++ ld8 out3=[in1],8
++ ;;
++ ld8 out4=[in1],8
++ ;;
++ ld8 out5=[in1],8
++ ;;
++ ld8 out6=[in1],8
++ ;;
++ ld8 out7=[in1]
++ mov loc2=gp // save global pointer
++ mov loc4=ar.rsc // save RSE configuration
++ mov ar.rsc=0 // put RSE in enforced lazy, LE mode
++ ;;
++ ld8 gp=[in0] // load ESI function's global pointer
++ movl r16=PSR_BITS_TO_CLEAR
++ mov loc3=psr // save processor status word
++ movl r17=PSR_BITS_TO_SET
++ ;;
++ or loc3=loc3,r17
++ mov b6=r2
++ ;;
++ andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared
++ br.call.sptk.many rp=ia64_switch_mode_phys
++.ret0: mov loc5=r19 // old ar.bsp
++ mov loc6=r20 // old sp
++ br.call.sptk.many rp=b6 // call the ESI function
++.ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode
++ mov r16=loc3 // save virtual mode psr
++ mov r19=loc5 // save virtual mode bspstore
++ mov r20=loc6 // save virtual mode sp
++ br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
++.ret2: mov ar.rsc=loc4 // restore RSE configuration
++ mov ar.pfs=loc1
++ mov rp=loc0
++ mov gp=loc2
++ br.ret.sptk.many rp
++END(esi_call_phys)
+diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
+index 3ead20f..879c181 100644
+--- a/arch/ia64/kernel/ia64_ksyms.c
++++ b/arch/ia64/kernel/ia64_ksyms.c
+@@ -105,5 +105,9 @@ EXPORT_SYMBOL(ia64_spinlock_contention);
+ # endif
+ #endif
+
++#if defined(CONFIG_IA64_ESI) || defined(CONFIG_IA64_ESI_MODULE)
++extern void esi_call_phys (void);
++EXPORT_SYMBOL_GPL(esi_call_phys);
++#endif
+ extern char ia64_ivt[];
+ EXPORT_SYMBOL(ia64_ivt);
+diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
+index 7852382..f07c086 100644
+--- a/arch/ia64/kernel/irq.c
++++ b/arch/ia64/kernel/irq.c
+@@ -194,8 +194,11 @@ void fixup_irqs(void)
+ */
+ for (irq=0; irq < NR_IRQS; irq++) {
+ if (vectors_in_migration[irq]) {
++ struct pt_regs *old_regs = set_irq_regs(NULL);
++
+ vectors_in_migration[irq]=0;
+- __do_IRQ(irq, NULL);
++ __do_IRQ(irq);
++ set_irq_regs(old_regs);
+ }
+ }
+
+diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
+index a041367..9c6dafa 100644
+--- a/arch/ia64/kernel/irq_ia64.c
++++ b/arch/ia64/kernel/irq_ia64.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/ia64/kernel/irq.c
++ * linux/arch/ia64/kernel/irq_ia64.c
+ *
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Stephane Eranian <eranian at hpl.hp.com>
+@@ -30,6 +30,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/threads.h>
+ #include <linux/bitops.h>
++#include <linux/irq.h>
+
+ #include <asm/delay.h>
+ #include <asm/intrinsics.h>
+@@ -105,6 +106,25 @@ reserve_irq_vector (int vector)
+ return test_and_set_bit(pos, ia64_vector_mask);
+ }
+
++/*
++ * Dynamic irq allocate and deallocation for MSI
++ */
++int create_irq(void)
++{
++ int vector = assign_irq_vector(AUTO_ASSIGN);
++
++ if (vector >= 0)
++ dynamic_irq_init(vector);
++
++ return vector;
++}
++
++void destroy_irq(unsigned int irq)
++{
++ dynamic_irq_cleanup(irq);
++ free_irq_vector(irq);
++}
++
+ #ifdef CONFIG_SMP
+ # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
+ #else
+@@ -118,6 +138,7 @@ reserve_irq_vector (int vector)
+ void
+ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ unsigned long saved_tpr;
+
+ #if IRQ_DEBUG
+@@ -159,11 +180,13 @@ ia64_handle_irq (ia64_vector vector, str
+ saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
+ ia64_srlz_d();
+ while (vector != IA64_SPURIOUS_INT_VECTOR) {
+- if (!IS_RESCHEDULE(vector)) {
++ if (unlikely(IS_RESCHEDULE(vector)))
++ kstat_this_cpu.irqs[vector]++;
++ else {
+ ia64_setreg(_IA64_REG_CR_TPR, vector);
+ ia64_srlz_d();
+
+- __do_IRQ(local_vector_to_irq(vector), regs);
++ __do_IRQ(local_vector_to_irq(vector));
+
+ /*
+ * Disable interrupts and send EOI:
+@@ -180,6 +203,7 @@ ia64_handle_irq (ia64_vector vector, str
+ * come through until ia64_eoi() has been done.
+ */
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ #ifdef CONFIG_HOTPLUG_CPU
+@@ -203,7 +227,11 @@ void ia64_process_pending_intr(void)
+ * Perform normal interrupt style processing
+ */
+ while (vector != IA64_SPURIOUS_INT_VECTOR) {
+- if (!IS_RESCHEDULE(vector)) {
++ if (unlikely(IS_RESCHEDULE(vector)))
++ kstat_this_cpu.irqs[vector]++;
++ else {
++ struct pt_regs *old_regs = set_irq_regs(NULL);
++
+ ia64_setreg(_IA64_REG_CR_TPR, vector);
+ ia64_srlz_d();
+
+@@ -214,7 +242,8 @@ void ia64_process_pending_intr(void)
+ * Probably could shared code.
+ */
+ vectors_in_migration[local_vector_to_irq(vector)]=0;
+- __do_IRQ(local_vector_to_irq(vector), NULL);
++ __do_IRQ(local_vector_to_irq(vector));
++ set_irq_regs(old_regs);
+
+ /*
+ * Disable interrupts and send EOI
+@@ -231,13 +260,24 @@ void ia64_process_pending_intr(void)
+
+
+ #ifdef CONFIG_SMP
+-extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t handle_IPI (int irq, void *dev_id);
++
++static irqreturn_t dummy_handler (int irq, void *dev_id)
++{
++ BUG();
++}
+
+ static struct irqaction ipi_irqaction = {
+ .handler = handle_IPI,
+ .flags = IRQF_DISABLED,
+ .name = "IPI"
+ };
++
++static struct irqaction resched_irqaction = {
++ .handler = dummy_handler,
++ .flags = SA_INTERRUPT,
++ .name = "resched"
++};
+ #endif
+
+ void
+@@ -262,6 +302,7 @@ init_IRQ (void)
+ register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
+ #ifdef CONFIG_SMP
+ register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
++ register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction);
+ #endif
+ #ifdef CONFIG_PERFMON
+ pfm_init_percpu();
+diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
+index 781960f..51217d6 100644
+--- a/arch/ia64/kernel/kprobes.c
++++ b/arch/ia64/kernel/kprobes.c
+@@ -90,7 +90,7 @@ static void __kprobes update_kprobe_inst
+ p->ainsn.target_br_reg = 0;
+
+ /* Check for Break instruction
+- * Bits 37:40 Major opcode to be zero
++ * Bits 37:40 Major opcode to be zero
+ * Bits 27:32 X6 to be zero
+ * Bits 32:35 X3 to be zero
+ */
+@@ -104,19 +104,19 @@ static void __kprobes update_kprobe_inst
+ switch (major_opcode) {
+ case INDIRECT_CALL_OPCODE:
+ p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+- p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+- break;
++ p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
++ break;
+ case IP_RELATIVE_PREDICT_OPCODE:
+ case IP_RELATIVE_BRANCH_OPCODE:
+ p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
+- break;
++ break;
+ case IP_RELATIVE_CALL_OPCODE:
+- p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
+- p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+- p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+- break;
++ p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
++ p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
++ p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
++ break;
+ }
+- } else if (bundle_encoding[template][slot] == X) {
++ } else if (bundle_encoding[template][slot] == X) {
+ switch (major_opcode) {
+ case LONG_CALL_OPCODE:
+ p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+@@ -136,10 +136,8 @@ static void __kprobes update_kprobe_inst
+ static int __kprobes unsupported_inst(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst,
+- struct kprobe *p)
++ unsigned long addr)
+ {
+- unsigned long addr = (unsigned long)p->addr;
+-
+ if (bundle_encoding[template][slot] == I) {
+ switch (major_opcode) {
+ case 0x0: //I_UNIT_MISC_OPCODE:
+@@ -217,7 +215,7 @@ static void __kprobes prepare_break_inst
+ struct kprobe *p)
+ {
+ unsigned long break_inst = BREAK_INST;
+- bundle_t *bundle = &p->ainsn.insn.bundle;
++ bundle_t *bundle = &p->opcode.bundle;
+
+ /*
+ * Copy the original kprobe_inst qualifying predicate(qp)
+@@ -260,18 +258,18 @@ static void __kprobes get_kprobe_inst(bu
+
+ switch (slot) {
+ case 0:
+- *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
+- *kprobe_inst = bundle->quad0.slot0;
+- break;
++ *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
++ *kprobe_inst = bundle->quad0.slot0;
++ break;
+ case 1:
+- *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
+- kprobe_inst_p0 = bundle->quad0.slot1_p0;
+- kprobe_inst_p1 = bundle->quad1.slot1_p1;
+- *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46));
++ *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
++ kprobe_inst_p0 = bundle->quad0.slot1_p0;
++ kprobe_inst_p1 = bundle->quad1.slot1_p1;
++ *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46));
+ break;
+ case 2:
+- *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
+- *kprobe_inst = bundle->quad1.slot2;
++ *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
++ *kprobe_inst = bundle->quad1.slot2;
+ break;
+ }
+ }
+@@ -292,11 +290,11 @@ static int __kprobes valid_kprobe_addr(i
+ return -EINVAL;
+ }
+
+- if (in_ivt_functions(addr)) {
+- printk(KERN_WARNING "Kprobes can't be inserted inside "
++ if (in_ivt_functions(addr)) {
++ printk(KERN_WARNING "Kprobes can't be inserted inside "
+ "IVT functions at 0x%lx\n", addr);
+- return -EINVAL;
+- }
++ return -EINVAL;
++ }
+
+ if (slot == 1 && bundle_encoding[template][1] != L) {
+ printk(KERN_WARNING "Inserting kprobes on slot #1 "
+@@ -340,12 +338,13 @@ static void kretprobe_trampoline(void)
+ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+ {
+ struct kretprobe_instance *ri = NULL;
+- struct hlist_head *head;
++ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address =
+ ((struct fnptr *)kretprobe_trampoline)->ip;
+
++ INIT_HLIST_HEAD(&empty_rp);
+ spin_lock_irqsave(&kretprobe_lock, flags);
+ head = kretprobe_inst_table_head(current);
+
+@@ -371,7 +370,7 @@ int __kprobes trampoline_probe_handler(s
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+- recycle_rp_inst(ri);
++ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+@@ -389,6 +388,10 @@ int __kprobes trampoline_probe_handler(s
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ preempt_enable_no_resched();
+
++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++ hlist_del(&ri->hlist);
++ kfree(ri);
++ }
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
+@@ -423,37 +426,34 @@ int __kprobes arch_prepare_kprobe(struct
+ unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
+ unsigned long kprobe_inst=0;
+ unsigned int slot = addr & 0xf, template, major_opcode = 0;
+- bundle_t *bundle = &p->ainsn.insn.bundle;
++ bundle_t *bundle;
+
+- memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t));
+- memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t));
+-
+- template = bundle->quad0.template;
++ bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
++ template = bundle->quad0.template;
+
+ if(valid_kprobe_addr(template, slot, addr))
+ return -EINVAL;
+
+ /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
+- if (slot == 1 && bundle_encoding[template][1] == L)
+- slot++;
++ if (slot == 1 && bundle_encoding[template][1] == L)
++ slot++;
+
+ /* Get kprobe_inst and major_opcode from the bundle */
+ get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
+
+- if (unsupported_inst(template, slot, major_opcode, kprobe_inst, p))
++ if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr))
+ return -EINVAL;
+
+- prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
+
+- return 0;
+-}
++ p->ainsn.insn = get_insn_slot();
++ if (!p->ainsn.insn)
++ return -ENOMEM;
++ memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
++ memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
+
+-void __kprobes flush_insn_slot(struct kprobe *p)
+-{
+- unsigned long arm_addr;
++ prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
+
+- arm_addr = ((unsigned long)&p->opcode.bundle) & ~0xFULL;
+- flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
++ return 0;
+ }
+
+ void __kprobes arch_arm_kprobe(struct kprobe *p)
+@@ -461,9 +461,10 @@ void __kprobes arch_arm_kprobe(struct kp
+ unsigned long addr = (unsigned long)p->addr;
+ unsigned long arm_addr = addr & ~0xFULL;
+
+- flush_insn_slot(p);
+- memcpy((char *)arm_addr, &p->ainsn.insn.bundle, sizeof(bundle_t));
+- flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
++ flush_icache_range((unsigned long)p->ainsn.insn,
++ (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
++ memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t));
++ flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
+ }
+
+ void __kprobes arch_disarm_kprobe(struct kprobe *p)
+@@ -471,11 +472,18 @@ void __kprobes arch_disarm_kprobe(struct
+ unsigned long addr = (unsigned long)p->addr;
+ unsigned long arm_addr = addr & ~0xFULL;
+
+- /* p->opcode contains the original unaltered bundle */
+- memcpy((char *) arm_addr, (char *) &p->opcode.bundle, sizeof(bundle_t));
+- flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
++ /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */
++ memcpy((char *) arm_addr, (char *) p->ainsn.insn,
++ sizeof(kprobe_opcode_t));
++ flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
+ }
+
++void __kprobes arch_remove_kprobe(struct kprobe *p)
++{
++ mutex_lock(&kprobe_mutex);
++ free_insn_slot(p->ainsn.insn);
++ mutex_unlock(&kprobe_mutex);
++}
+ /*
+ * We are resuming execution after a single step fault, so the pt_regs
+ * structure reflects the register state after we executed the instruction
+@@ -486,21 +494,22 @@ void __kprobes arch_disarm_kprobe(struct
+ */
+ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
+ {
+- unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
+- unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
+- unsigned long template;
+- int slot = ((unsigned long)p->addr & 0xf);
++ unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle);
++ unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
++ unsigned long template;
++ int slot = ((unsigned long)p->addr & 0xf);
+
+- template = p->opcode.bundle.quad0.template;
++ template = p->ainsn.insn->bundle.quad0.template;
+
+- if (slot == 1 && bundle_encoding[template][1] == L)
+- slot = 2;
++ if (slot == 1 && bundle_encoding[template][1] == L)
++ slot = 2;
+
+ if (p->ainsn.inst_flag) {
+
+ if (p->ainsn.inst_flag & INST_FLAG_FIX_RELATIVE_IP_ADDR) {
+ /* Fix relative IP address */
+- regs->cr_iip = (regs->cr_iip - bundle_addr) + resume_addr;
++ regs->cr_iip = (regs->cr_iip - bundle_addr) +
++ resume_addr;
+ }
+
+ if (p->ainsn.inst_flag & INST_FLAG_FIX_BRANCH_REG) {
+@@ -537,23 +546,23 @@ static void __kprobes resume_execution(s
+ }
+
+ if (slot == 2) {
+- if (regs->cr_iip == bundle_addr + 0x10) {
+- regs->cr_iip = resume_addr + 0x10;
+- }
+- } else {
+- if (regs->cr_iip == bundle_addr) {
+- regs->cr_iip = resume_addr;
+- }
++ if (regs->cr_iip == bundle_addr + 0x10) {
++ regs->cr_iip = resume_addr + 0x10;
++ }
++ } else {
++ if (regs->cr_iip == bundle_addr) {
++ regs->cr_iip = resume_addr;
++ }
+ }
+
+ turn_ss_off:
+- /* Turn off Single Step bit */
+- ia64_psr(regs)->ss = 0;
++ /* Turn off Single Step bit */
++ ia64_psr(regs)->ss = 0;
+ }
+
+ static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
+ {
+- unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
++ unsigned long bundle_addr = (unsigned long) &p->ainsn.insn->bundle;
+ unsigned long slot = (unsigned long)p->addr & 0xf;
+
+ /* single step inline if break instruction */
+@@ -584,7 +593,7 @@ static int __kprobes is_ia64_break_inst(
+
+ /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
+ if (slot == 1 && bundle_encoding[template][1] == L)
+- slot++;
++ slot++;
+
+ /* Get Kprobe probe instruction at given slot*/
+ get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);
+@@ -624,7 +633,7 @@ static int __kprobes pre_kprobes_handler
+ if (p) {
+ if ((kcb->kprobe_status == KPROBE_HIT_SS) &&
+ (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) {
+- ia64_psr(regs)->ss = 0;
++ ia64_psr(regs)->ss = 0;
+ goto no_kprobe;
+ }
+ /* We have reentered the pre_kprobe_handler(), since
+@@ -768,6 +777,12 @@ static int __kprobes kprobes_fault_handl
+ */
+ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+ return 1;
++ /*
++ * In case the user-specified fault handler returned
++ * zero, try to fix up.
++ */
++ if (ia64_done_with_exception(regs))
++ return 1;
+
+ /*
+ * Let ia64_do_page_fault() fix it.
+@@ -878,7 +893,7 @@ int __kprobes setjmp_pre_handler(struct
+ * fix the return address to our jprobe_inst_return() function
+ * in the jprobes.S file
+ */
+- regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip;
++ regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip;
+
+ return 1;
+ }
+diff --git a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
+index d4a546a..9620822 100644
+--- a/arch/ia64/kernel/machvec.c
++++ b/arch/ia64/kernel/machvec.c
+@@ -60,7 +60,7 @@ machvec_setup (char **arg)
+ EXPORT_SYMBOL(machvec_setup);
+
+ void
+-machvec_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
++machvec_timer_interrupt (int irq, void *dev_id)
+ {
+ }
+ EXPORT_SYMBOL(machvec_timer_interrupt);
+diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
+index 2fbe453..7cfa63a 100644
+--- a/arch/ia64/kernel/mca.c
++++ b/arch/ia64/kernel/mca.c
+@@ -54,6 +54,9 @@
+ *
+ * 2005-10-07 Keith Owens <kaos at sgi.com>
+ * Add notify_die() hooks.
++ *
++ * 2006-09-15 Hidetoshi Seto <seto.hidetoshi at jp.fujitsu.com>
++ * Add printing support for MCA/INIT.
+ */
+ #include <linux/types.h>
+ #include <linux/init.h>
+@@ -136,11 +139,175 @@ extern void salinfo_log_wakeup(int type,
+
+ static int mca_init __initdata;
+
++/*
++ * limited & delayed printing support for MCA/INIT handler
++ */
++
++#define mprintk(fmt...) ia64_mca_printk(fmt)
++
++#define MLOGBUF_SIZE (512+256*NR_CPUS)
++#define MLOGBUF_MSGMAX 256
++static char mlogbuf[MLOGBUF_SIZE];
++static DEFINE_SPINLOCK(mlogbuf_wlock); /* mca context only */
++static DEFINE_SPINLOCK(mlogbuf_rlock); /* normal context only */
++static unsigned long mlogbuf_start;
++static unsigned long mlogbuf_end;
++static unsigned int mlogbuf_finished = 0;
++static unsigned long mlogbuf_timestamp = 0;
++
++static int loglevel_save = -1;
++#define BREAK_LOGLEVEL(__console_loglevel) \
++ oops_in_progress = 1; \
++ if (loglevel_save < 0) \
++ loglevel_save = __console_loglevel; \
++ __console_loglevel = 15;
++
++#define RESTORE_LOGLEVEL(__console_loglevel) \
++ if (loglevel_save >= 0) { \
++ __console_loglevel = loglevel_save; \
++ loglevel_save = -1; \
++ } \
++ mlogbuf_finished = 0; \
++ oops_in_progress = 0;
++
++/*
++ * Push messages into buffer, print them later if not urgent.
++ */
++void ia64_mca_printk(const char *fmt, ...)
++{
++ va_list args;
++ int printed_len;
++ char temp_buf[MLOGBUF_MSGMAX];
++ char *p;
++
++ va_start(args, fmt);
++ printed_len = vscnprintf(temp_buf, sizeof(temp_buf), fmt, args);
++ va_end(args);
++
++ /* Copy the output into mlogbuf */
++ if (oops_in_progress) {
++ /* mlogbuf was abandoned, use printk directly instead. */
++ printk(temp_buf);
++ } else {
++ spin_lock(&mlogbuf_wlock);
++ for (p = temp_buf; *p; p++) {
++ unsigned long next = (mlogbuf_end + 1) % MLOGBUF_SIZE;
++ if (next != mlogbuf_start) {
++ mlogbuf[mlogbuf_end] = *p;
++ mlogbuf_end = next;
++ } else {
++ /* buffer full */
++ break;
++ }
++ }
++ mlogbuf[mlogbuf_end] = '\0';
++ spin_unlock(&mlogbuf_wlock);
++ }
++}
++EXPORT_SYMBOL(ia64_mca_printk);
++
++/*
++ * Print buffered messages.
++ * NOTE: call this after returning normal context. (ex. from salinfod)
++ */
++void ia64_mlogbuf_dump(void)
++{
++ char temp_buf[MLOGBUF_MSGMAX];
++ char *p;
++ unsigned long index;
++ unsigned long flags;
++ unsigned int printed_len;
++
++ /* Get output from mlogbuf */
++ while (mlogbuf_start != mlogbuf_end) {
++ temp_buf[0] = '\0';
++ p = temp_buf;
++ printed_len = 0;
++
++ spin_lock_irqsave(&mlogbuf_rlock, flags);
++
++ index = mlogbuf_start;
++ while (index != mlogbuf_end) {
++ *p = mlogbuf[index];
++ index = (index + 1) % MLOGBUF_SIZE;
++ if (!*p)
++ break;
++ p++;
++ if (++printed_len >= MLOGBUF_MSGMAX - 1)
++ break;
++ }
++ *p = '\0';
++ if (temp_buf[0])
++ printk(temp_buf);
++ mlogbuf_start = index;
++
++ mlogbuf_timestamp = 0;
++ spin_unlock_irqrestore(&mlogbuf_rlock, flags);
++ }
++}
++EXPORT_SYMBOL(ia64_mlogbuf_dump);
++
++/*
++ * Call this if system is going to down or if immediate flushing messages to
++ * console is required. (ex. recovery was failed, crash dump is going to be
++ * invoked, long-wait rendezvous etc.)
++ * NOTE: this should be called from monarch.
++ */
++static void ia64_mlogbuf_finish(int wait)
++{
++ BREAK_LOGLEVEL(console_loglevel);
++
++ spin_lock_init(&mlogbuf_rlock);
++ ia64_mlogbuf_dump();
++ printk(KERN_EMERG "mlogbuf_finish: printing switched to urgent mode, "
++ "MCA/INIT might be dodgy or fail.\n");
++
++ if (!wait)
++ return;
++
++ /* wait for console */
++ printk("Delaying for 5 seconds...\n");
++ udelay(5*1000000);
++
++ mlogbuf_finished = 1;
++}
++EXPORT_SYMBOL(ia64_mlogbuf_finish);
++
++/*
++ * Print buffered messages from INIT context.
++ */
++static void ia64_mlogbuf_dump_from_init(void)
++{
++ if (mlogbuf_finished)
++ return;
++
++ if (mlogbuf_timestamp && (mlogbuf_timestamp + 30*HZ > jiffies)) {
++ printk(KERN_ERR "INIT: mlogbuf_dump is interrupted by INIT "
++ " and the system seems to be messed up.\n");
++ ia64_mlogbuf_finish(0);
++ return;
++ }
++
++ if (!spin_trylock(&mlogbuf_rlock)) {
++ printk(KERN_ERR "INIT: mlogbuf_dump is interrupted by INIT. "
++ "Generated messages other than stack dump will be "
++ "buffered to mlogbuf and will be printed later.\n");
++ printk(KERN_ERR "INIT: If messages would not printed after "
++ "this INIT, wait 30sec and assert INIT again.\n");
++ if (!mlogbuf_timestamp)
++ mlogbuf_timestamp = jiffies;
++ return;
++ }
++ spin_unlock(&mlogbuf_rlock);
++ ia64_mlogbuf_dump();
++}
+
+ static void inline
+ ia64_mca_spin(const char *func)
+ {
+- printk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
++ if (monarch_cpu == smp_processor_id())
++ ia64_mlogbuf_finish(0);
++ mprintk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
+ while (1)
+ cpu_relax();
+ }
+@@ -221,7 +388,7 @@ ia64_log_get(int sal_info_type, u8 **buf
+ {
+ sal_log_record_header_t *log_buffer;
+ u64 total_len = 0;
+- int s;
++ unsigned long s;
+
+ IA64_LOG_LOCK(sal_info_type);
+
+@@ -332,7 +499,7 @@ int cpe_vector = -1;
+ int ia64_cpe_irq = -1;
+
+ static irqreturn_t
+-ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
++ia64_mca_cpe_int_handler (int cpe_irq, void *arg)
+ {
+ static unsigned long cpe_history[CPE_HISTORY_LENGTH];
+ static int index;
+@@ -344,9 +511,6 @@ ia64_mca_cpe_int_handler (int cpe_irq, v
+ /* SAL spec states this should run w/ interrupts enabled */
+ local_irq_enable();
+
+- /* Get the CPE error record and log it */
+- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
+-
+ spin_lock(&cpe_history_lock);
+ if (!cpe_poll_enabled && cpe_vector >= 0) {
+
+@@ -375,7 +539,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, v
+ mod_timer(&cpe_poll_timer, jiffies + MIN_CPE_POLL_INTERVAL);
+
+ /* lock already released, get out now */
+- return IRQ_HANDLED;
++ goto out;
+ } else {
+ cpe_history[index++] = now;
+ if (index == CPE_HISTORY_LENGTH)
+@@ -383,6 +547,10 @@ ia64_mca_cpe_int_handler (int cpe_irq, v
+ }
+ }
+ spin_unlock(&cpe_history_lock);
++out:
++ /* Get the CPE error record and log it */
++ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -576,7 +744,7 @@ ia64_mca_wakeup_all(void)
+ * Outputs : None
+ */
+ static irqreturn_t
+-ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
++ia64_mca_rendez_int_handler(int rendez_irq, void *arg)
+ {
+ unsigned long flags;
+ int cpu = smp_processor_id();
+@@ -585,8 +753,8 @@ ia64_mca_rendez_int_handler(int rendez_i
+
+ /* Mask all interrupts */
+ local_irq_save(flags);
+- if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, (long)&nd, 0, 0)
+- == NOTIFY_STOP)
++ if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", get_irq_regs(),
++ (long)&nd, 0, 0) == NOTIFY_STOP)
+ ia64_mca_spin(__FUNCTION__);
+
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
+@@ -595,16 +763,16 @@ ia64_mca_rendez_int_handler(int rendez_i
+ */
+ ia64_sal_mc_rendez();
+
+- if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, (long)&nd, 0, 0)
+- == NOTIFY_STOP)
++ if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", get_irq_regs(),
++ (long)&nd, 0, 0) == NOTIFY_STOP)
+ ia64_mca_spin(__FUNCTION__);
+
+ /* Wait for the monarch cpu to exit. */
+ while (monarch_cpu != -1)
+ cpu_relax(); /* spin until monarch leaves */
+
+- if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, (long)&nd, 0, 0)
+- == NOTIFY_STOP)
++ if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", get_irq_regs(),
++ (long)&nd, 0, 0) == NOTIFY_STOP)
+ ia64_mca_spin(__FUNCTION__);
+
+ /* Enable all interrupts */
+@@ -623,12 +791,11 @@ ia64_mca_rendez_int_handler(int rendez_i
+ *
+ * Inputs : wakeup_irq (Wakeup-interrupt bit)
+ * arg (Interrupt handler specific argument)
+- * ptregs (Exception frame at the time of the interrupt)
+ * Outputs : None
+ *
+ */
+ static irqreturn_t
+-ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
++ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg)
+ {
+ return IRQ_HANDLED;
+ }
+@@ -988,18 +1155,22 @@ ia64_wait_for_slaves(int monarch, const
+ }
+ if (!missing)
+ goto all_in;
+- printk(KERN_INFO "OS %s slave did not rendezvous on cpu", type);
++ /*
++ * Maybe slave(s) dead. Print buffered messages immediately.
++ */
++ ia64_mlogbuf_finish(0);
++ mprintk(KERN_INFO "OS %s slave did not rendezvous on cpu", type);
+ for_each_online_cpu(c) {
+ if (c == monarch)
+ continue;
+ if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE)
+- printk(" %d", c);
++ mprintk(" %d", c);
+ }
+- printk("\n");
++ mprintk("\n");
+ return;
+
+ all_in:
+- printk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type);
++ mprintk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type);
+ return;
+ }
+
+@@ -1027,10 +1198,8 @@ ia64_mca_handler(struct pt_regs *regs, s
+ struct ia64_mca_notify_die nd =
+ { .sos = sos, .monarch_cpu = &monarch_cpu };
+
+- oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */
+- console_loglevel = 15; /* make sure printks make it to console */
+- printk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d monarch=%ld\n",
+- sos->proc_state_param, cpu, sos->monarch);
++ mprintk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d "
++ "monarch=%ld\n", sos->proc_state_param, cpu, sos->monarch);
+
+ previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA");
+ monarch_cpu = cpu;
+@@ -1066,6 +1235,9 @@ ia64_mca_handler(struct pt_regs *regs, s
+ rh->severity = sal_log_severity_corrected;
+ ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA);
+ sos->os_status = IA64_MCA_CORRECTED;
++ } else {
++ /* Dump buffered message to console */
++ ia64_mlogbuf_finish(1);
+ }
+ if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover)
+ == NOTIFY_STOP)
+@@ -1088,13 +1260,12 @@ static DECLARE_WORK(cmc_enable_work, ia6
+ * Inputs
+ * interrupt number
+ * client data arg ptr
+- * saved registers ptr
+ *
+ * Outputs
+ * None
+ */
+ static irqreturn_t
+-ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
++ia64_mca_cmc_int_handler(int cmc_irq, void *arg)
+ {
+ static unsigned long cmc_history[CMC_HISTORY_LENGTH];
+ static int index;
+@@ -1106,9 +1277,6 @@ ia64_mca_cmc_int_handler(int cmc_irq, vo
+ /* SAL spec states this should run w/ interrupts enabled */
+ local_irq_enable();
+
+- /* Get the CMC error record and log it */
+- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
+-
+ spin_lock(&cmc_history_lock);
+ if (!cmc_polling_enabled) {
+ int i, count = 1; /* we know 1 happened now */
+@@ -1141,7 +1309,7 @@ ia64_mca_cmc_int_handler(int cmc_irq, vo
+ mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
+
+ /* lock already released, get out now */
+- return IRQ_HANDLED;
++ goto out;
+ } else {
+ cmc_history[index++] = now;
+ if (index == CMC_HISTORY_LENGTH)
+@@ -1149,6 +1317,10 @@ ia64_mca_cmc_int_handler(int cmc_irq, vo
+ }
+ }
+ spin_unlock(&cmc_history_lock);
++out:
++ /* Get the CMC error record and log it */
++ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -1162,12 +1334,11 @@ ia64_mca_cmc_int_handler(int cmc_irq, vo
+ * Inputs
+ * interrupt number
+ * client data arg ptr
+- * saved registers ptr
+ * Outputs
+ * handled
+ */
+ static irqreturn_t
+-ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs)
++ia64_mca_cmc_int_caller(int cmc_irq, void *arg)
+ {
+ static int start_count = -1;
+ unsigned int cpuid;
+@@ -1178,7 +1349,7 @@ ia64_mca_cmc_int_caller(int cmc_irq, voi
+ if (start_count == -1)
+ start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC);
+
+- ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs);
++ ia64_mca_cmc_int_handler(cmc_irq, arg);
+
+ for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
+
+@@ -1229,14 +1400,13 @@ ia64_mca_cmc_poll (unsigned long dummy)
+ * Inputs
+ * interrupt number
+ * client data arg ptr
+- * saved registers ptr
+ * Outputs
+ * handled
+ */
+ #ifdef CONFIG_ACPI
+
+ static irqreturn_t
+-ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
++ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
+ {
+ static int start_count = -1;
+ static int poll_time = MIN_CPE_POLL_INTERVAL;
+@@ -1248,7 +1418,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, voi
+ if (start_count == -1)
+ start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE);
+
+- ia64_mca_cpe_int_handler(cpe_irq, arg, ptregs);
++ ia64_mca_cpe_int_handler(cpe_irq, arg);
+
+ for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
+
+@@ -1305,6 +1475,15 @@ default_monarch_init_process(struct noti
+ struct task_struct *g, *t;
+ if (val != DIE_INIT_MONARCH_PROCESS)
+ return NOTIFY_DONE;
++
++ /*
++ * FIXME: mlogbuf will brim over with INIT stack dumps.
++ * To enable show_stack from INIT, we use oops_in_progress which should
++ * be used in real oops. This would cause something wrong after INIT.
++ */
++ BREAK_LOGLEVEL(console_loglevel);
++ ia64_mlogbuf_dump_from_init();
++
+ printk(KERN_ERR "Processes interrupted by INIT -");
+ for_each_online_cpu(c) {
+ struct ia64_sal_os_state *s;
+@@ -1326,6 +1505,8 @@ default_monarch_init_process(struct noti
+ } while_each_thread (g, t);
+ read_unlock(&tasklist_lock);
+ }
++ /* FIXME: This will not restore zapped printk locks. */
++ RESTORE_LOGLEVEL(console_loglevel);
+ return NOTIFY_DONE;
+ }
+
+@@ -1357,12 +1538,9 @@ ia64_init_handler(struct pt_regs *regs,
+ struct ia64_mca_notify_die nd =
+ { .sos = sos, .monarch_cpu = &monarch_cpu };
+
+- oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */
+- console_loglevel = 15; /* make sure printks make it to console */
+-
+ (void) notify_die(DIE_INIT_ENTER, "INIT", regs, (long)&nd, 0, 0);
+
+- printk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n",
++ mprintk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n",
+ sos->proc_state_param, cpu, sos->monarch);
+ salinfo_log_wakeup(SAL_INFO_TYPE_INIT, NULL, 0, 0);
+
+@@ -1375,7 +1553,7 @@ ia64_init_handler(struct pt_regs *regs,
+ * fix their proms and get their customers updated.
+ */
+ if (!sos->monarch && atomic_add_return(1, &slaves) == num_online_cpus()) {
+- printk(KERN_WARNING "%s: Promoting cpu %d to monarch.\n",
++ mprintk(KERN_WARNING "%s: Promoting cpu %d to monarch.\n",
+ __FUNCTION__, cpu);
+ atomic_dec(&slaves);
+ sos->monarch = 1;
+@@ -1387,7 +1565,7 @@ ia64_init_handler(struct pt_regs *regs,
+ * fix their proms and get their customers updated.
+ */
+ if (sos->monarch && atomic_add_return(1, &monarchs) > 1) {
+- printk(KERN_WARNING "%s: Demoting cpu %d to slave.\n",
++ mprintk(KERN_WARNING "%s: Demoting cpu %d to slave.\n",
+ __FUNCTION__, cpu);
+ atomic_dec(&monarchs);
+ sos->monarch = 0;
+@@ -1408,7 +1586,7 @@ ia64_init_handler(struct pt_regs *regs,
+ if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, (long)&nd, 0, 0)
+ == NOTIFY_STOP)
+ ia64_mca_spin(__FUNCTION__);
+- printk("Slave on cpu %d returning to normal service.\n", cpu);
++ mprintk("Slave on cpu %d returning to normal service.\n", cpu);
+ set_curr_task(cpu, previous_current);
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+ atomic_dec(&slaves);
+@@ -1426,7 +1604,7 @@ ia64_init_handler(struct pt_regs *regs,
+ * same serial line, the user will need some time to switch out of the BMC before
+ * the dump begins.
+ */
+- printk("Delaying for 5 seconds...\n");
++ mprintk("Delaying for 5 seconds...\n");
+ udelay(5*1000000);
+ ia64_wait_for_slaves(cpu, "INIT");
+ /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through
+@@ -1439,7 +1617,7 @@ ia64_init_handler(struct pt_regs *regs,
+ if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, (long)&nd, 0, 0)
+ == NOTIFY_STOP)
+ ia64_mca_spin(__FUNCTION__);
+- printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu);
++ mprintk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu);
+ atomic_dec(&monarchs);
+ set_curr_task(cpu, previous_current);
+ monarch_cpu = -1;
+diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
+index 9604749..c6b607c 100644
+--- a/arch/ia64/kernel/mca_asm.S
++++ b/arch/ia64/kernel/mca_asm.S
+@@ -1025,18 +1025,13 @@ ia64_old_stack:
+
+ ia64_set_kernel_registers:
+ add temp3=MCA_SP_OFFSET, r3
+- add temp4=MCA_SOS_OFFSET+SOS(OS_GP), r3
+ mov b0=r2 // save return address
+ GET_IA64_MCA_DATA(temp1)
+ ;;
+- add temp4=temp4, temp1 // &struct ia64_sal_os_state.os_gp
+ add r12=temp1, temp3 // kernel stack pointer on MCA/INIT stack
+ add r13=temp1, r3 // set current to start of MCA/INIT stack
+ add r20=temp1, r3 // physical start of MCA/INIT stack
+ ;;
+- ld8 r1=[temp4] // OS GP from SAL OS state
+- ;;
+- DATA_PA_TO_VA(r1,temp1)
+ DATA_PA_TO_VA(r12,temp2)
+ DATA_PA_TO_VA(r13,temp3)
+ ;;
+@@ -1067,6 +1062,10 @@ ia64_set_kernel_registers:
+ mov cr.itir=r18
+ mov cr.ifa=r13
+ mov r20=IA64_TR_CURRENT_STACK
++
++ movl r17=FPSR_DEFAULT
++ ;;
++ mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value
+ ;;
+ itr.d dtr[r20]=r21
+ ;;
+diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
+index 8db6e0c..afc1403 100644
+--- a/arch/ia64/kernel/mca_drv.c
++++ b/arch/ia64/kernel/mca_drv.c
+@@ -79,14 +79,30 @@ static int
+ fatal_mca(const char *fmt, ...)
+ {
+ va_list args;
++ char buf[256];
+
+ va_start(args, fmt);
+- vprintk(fmt, args);
++ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
++ ia64_mca_printk(KERN_ALERT "MCA: %s\n", buf);
+
+ return MCA_NOT_RECOVERED;
+ }
+
++static int
++mca_recovered(const char *fmt, ...)
++{
++ va_list args;
++ char buf[256];
++
++ va_start(args, fmt);
++ vsnprintf(buf, sizeof(buf), fmt, args);
++ va_end(args);
++ ia64_mca_printk(KERN_INFO "MCA: %s\n", buf);
++
++ return MCA_RECOVERED;
++}
++
+ /**
+ * mca_page_isolate - isolate a poisoned page in order not to use it later
+ * @paddr: poisoned memory location
+@@ -140,6 +156,7 @@ mca_page_isolate(unsigned long paddr)
+ void
+ mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr)
+ {
++ ia64_mlogbuf_dump();
+ printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "
+ "iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",
+ raw_smp_processor_id(), current->pid, current->uid,
+@@ -418,6 +435,50 @@ is_mca_global(peidx_table_t *peidx, pal_
+ }
+
+ /**
++ * get_target_identifier - Get the valid Cache or Bus check target identifier.
++ * @peidx: pointer of index of processor error section
++ *
++ * Return value:
++ * target address on Success / 0 on Failue
++ */
++static u64
++get_target_identifier(peidx_table_t *peidx)
++{
++ u64 target_address = 0;
++ sal_log_mod_error_info_t *smei;
++ pal_cache_check_info_t *pcci;
++ int i, level = 9;
++
++ /*
++ * Look through the cache checks for a valid target identifier
++ * If more than one valid target identifier, return the one
++ * with the lowest cache level.
++ */
++ for (i = 0; i < peidx_cache_check_num(peidx); i++) {
++ smei = (sal_log_mod_error_info_t *)peidx_cache_check(peidx, i);
++ if (smei->valid.target_identifier && smei->target_identifier) {
++ pcci = (pal_cache_check_info_t *)&(smei->check_info);
++ if (!target_address || (pcci->level < level)) {
++ target_address = smei->target_identifier;
++ level = pcci->level;
++ continue;
++ }
++ }
++ }
++ if (target_address)
++ return target_address;
++
++ /*
++ * Look at the bus check for a valid target identifier
++ */
++ smei = peidx_bus_check(peidx, 0);
++ if (smei && smei->valid.target_identifier)
++ return smei->target_identifier;
++
++ return 0;
++}
++
++/**
+ * recover_from_read_error - Try to recover the errors which type are "read"s.
+ * @slidx: pointer of index of SAL error record
+ * @peidx: pointer of index of processor error section
+@@ -433,14 +494,15 @@ recover_from_read_error(slidx_table_t *s
+ peidx_table_t *peidx, pal_bus_check_info_t *pbci,
+ struct ia64_sal_os_state *sos)
+ {
+- sal_log_mod_error_info_t *smei;
++ u64 target_identifier;
+ pal_min_state_area_t *pmsa;
+ struct ia64_psr *psr1, *psr2;
+ ia64_fptr_t *mca_hdlr_bh = (ia64_fptr_t*)mca_handler_bhhook;
+
+ /* Is target address valid? */
+- if (!pbci->tv)
+- return fatal_mca(KERN_ALERT "MCA: target address not valid\n");
++ target_identifier = get_target_identifier(peidx);
++ if (!target_identifier)
++ return fatal_mca("target address not valid");
+
+ /*
+ * cpu read or memory-mapped io read
+@@ -458,7 +520,7 @@ recover_from_read_error(slidx_table_t *s
+
+ /* Is minstate valid? */
+ if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate))
+- return fatal_mca(KERN_ALERT "MCA: minstate not valid\n");
++ return fatal_mca("minstate not valid");
+ psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr);
+ psr2 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_xpsr);
+
+@@ -470,35 +532,32 @@ recover_from_read_error(slidx_table_t *s
+ pmsa = sos->pal_min_state;
+ if (psr1->cpl != 0 ||
+ ((psr2->cpl != 0) && mca_recover_range(pmsa->pmsa_iip))) {
+- smei = peidx_bus_check(peidx, 0);
+- if (smei->valid.target_identifier) {
+- /*
+- * setup for resume to bottom half of MCA,
+- * "mca_handler_bhhook"
+- */
+- /* pass to bhhook as argument (gr8, ...) */
+- pmsa->pmsa_gr[8-1] = smei->target_identifier;
+- pmsa->pmsa_gr[9-1] = pmsa->pmsa_iip;
+- pmsa->pmsa_gr[10-1] = pmsa->pmsa_ipsr;
+- /* set interrupted return address (but no use) */
+- pmsa->pmsa_br0 = pmsa->pmsa_iip;
+- /* change resume address to bottom half */
+- pmsa->pmsa_iip = mca_hdlr_bh->fp;
+- pmsa->pmsa_gr[1-1] = mca_hdlr_bh->gp;
+- /* set cpl with kernel mode */
+- psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr;
+- psr2->cpl = 0;
+- psr2->ri = 0;
+- psr2->bn = 1;
+- psr2->i = 0;
+-
+- return MCA_RECOVERED;
+- }
+-
++ /*
++ * setup for resume to bottom half of MCA,
++ * "mca_handler_bhhook"
++ */
++ /* pass to bhhook as argument (gr8, ...) */
++ pmsa->pmsa_gr[8-1] = target_identifier;
++ pmsa->pmsa_gr[9-1] = pmsa->pmsa_iip;
++ pmsa->pmsa_gr[10-1] = pmsa->pmsa_ipsr;
++ /* set interrupted return address (but no use) */
++ pmsa->pmsa_br0 = pmsa->pmsa_iip;
++ /* change resume address to bottom half */
++ pmsa->pmsa_iip = mca_hdlr_bh->fp;
++ pmsa->pmsa_gr[1-1] = mca_hdlr_bh->gp;
++ /* set cpl with kernel mode */
++ psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr;
++ psr2->cpl = 0;
++ psr2->ri = 0;
++ psr2->bn = 1;
++ psr2->i = 0;
++
++ return mca_recovered("user memory corruption. "
++ "kill affected process - recovered.");
+ }
+
+- return fatal_mca(KERN_ALERT "MCA: kernel context not recovered,"
+- " iip 0x%lx\n", pmsa->pmsa_iip);
++ return fatal_mca("kernel context not recovered, iip 0x%lx\n",
++ pmsa->pmsa_iip);
+ }
+
+ /**
+@@ -584,13 +643,13 @@ recover_from_processor_error(int platfor
+ * The machine check is corrected.
+ */
+ if (psp->cm == 1)
+- return MCA_RECOVERED;
++ return mca_recovered("machine check is already corrected.");
+
+ /*
+ * The error was not contained. Software must be reset.
+ */
+ if (psp->us || psp->ci == 0)
+- return fatal_mca(KERN_ALERT "MCA: error not contained\n");
++ return fatal_mca("error not contained");
+
+ /*
+ * The cache check and bus check bits have four possible states
+@@ -601,22 +660,22 @@ recover_from_processor_error(int platfor
+ * 1 1 Memory error, attempt recovery
+ */
+ if (psp->bc == 0 || pbci == NULL)
+- return fatal_mca(KERN_ALERT "MCA: No bus check\n");
++ return fatal_mca("No bus check");
+
+ /*
+ * Sorry, we cannot handle so many.
+ */
+ if (peidx_bus_check_num(peidx) > 1)
+- return fatal_mca(KERN_ALERT "MCA: Too many bus checks\n");
++ return fatal_mca("Too many bus checks");
+ /*
+ * Well, here is only one bus error.
+ */
+ if (pbci->ib)
+- return fatal_mca(KERN_ALERT "MCA: Internal Bus error\n");
++ return fatal_mca("Internal Bus error");
+ if (pbci->cc)
+- return fatal_mca(KERN_ALERT "MCA: Cache-cache error\n");
++ return fatal_mca("Cache-cache error");
+ if (pbci->eb && pbci->bsi > 0)
+- return fatal_mca(KERN_ALERT "MCA: External bus check fatal status\n");
++ return fatal_mca("External bus check fatal status");
+
+ /*
+ * This is a local MCA and estimated as recoverble external bus error.
+@@ -628,7 +687,7 @@ recover_from_processor_error(int platfor
+ /*
+ * On account of strange SAL error record, we cannot recover.
+ */
+- return fatal_mca(KERN_ALERT "MCA: Strange SAL record\n");
++ return fatal_mca("Strange SAL record");
+ }
+
+ /**
+@@ -657,10 +716,10 @@ mca_try_to_recover(void *rec, struct ia6
+
+ /* Now, OS can recover when there is one processor error section */
+ if (n_proc_err > 1)
+- return fatal_mca(KERN_ALERT "MCA: Too Many Errors\n");
++ return fatal_mca("Too Many Errors");
+ else if (n_proc_err == 0)
+- /* Weird SAL record ... We need not to recover */
+- return fatal_mca(KERN_ALERT "MCA: Weird SAL record\n");
++ /* Weird SAL record ... We can't do anything */
++ return fatal_mca("Weird SAL record");
+
+ /* Make index of processor error section */
+ mca_make_peidx((sal_log_processor_info_t*)
+@@ -671,7 +730,7 @@ mca_try_to_recover(void *rec, struct ia6
+
+ /* Check whether MCA is global or not */
+ if (is_mca_global(&peidx, &pbci, sos))
+- return fatal_mca(KERN_ALERT "MCA: global MCA\n");
++ return fatal_mca("global MCA");
+
+ /* Try to recover a processor error */
+ return recover_from_processor_error(platform_err, &slidx, &peidx,
+diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h
+index 31a2e52..c85e943 100644
+--- a/arch/ia64/kernel/mca_drv.h
++++ b/arch/ia64/kernel/mca_drv.h
+@@ -118,3 +118,7 @@ struct mca_table_entry {
+
+ extern const struct mca_table_entry *search_mca_tables (unsigned long addr);
+ extern int mca_recover_range(unsigned long);
++extern void ia64_mca_printk(const char * fmt, ...)
++ __attribute__ ((format (printf, 1, 2)));
++extern void ia64_mlogbuf_dump(void);
++
+diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
+new file mode 100644
+index 0000000..822e59a
+--- /dev/null
++++ b/arch/ia64/kernel/msi_ia64.c
+@@ -0,0 +1,143 @@
++/*
++ * MSI hooks for standard x86 apic
++ */
++
++#include <linux/pci.h>
++#include <linux/irq.h>
++#include <linux/msi.h>
++#include <asm/smp.h>
++
++/*
++ * Shifts for APIC-based data
++ */
++
++#define MSI_DATA_VECTOR_SHIFT 0
++#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
++
++#define MSI_DATA_DELIVERY_SHIFT 8
++#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
++#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
++
++#define MSI_DATA_LEVEL_SHIFT 14
++#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
++#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
++
++#define MSI_DATA_TRIGGER_SHIFT 15
++#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
++#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
++
++/*
++ * Shift/mask fields for APIC-based bus address
++ */
++
++#define MSI_TARGET_CPU_SHIFT 4
++#define MSI_ADDR_HEADER 0xfee00000
++
++#define MSI_ADDR_DESTID_MASK 0xfff0000f
++#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
++
++#define MSI_ADDR_DESTMODE_SHIFT 2
++#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
++#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
++
++#define MSI_ADDR_REDIRECTION_SHIFT 3
++#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
++#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
++
++static struct irq_chip ia64_msi_chip;
++
++#ifdef CONFIG_SMP
++static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
++{
++ struct msi_msg msg;
++ u32 addr;
++
++ read_msi_msg(irq, &msg);
++
++ addr = msg.address_lo;
++ addr &= MSI_ADDR_DESTID_MASK;
++ addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
++ msg.address_lo = addr;
++
++ write_msi_msg(irq, &msg);
++ set_native_irq_info(irq, cpu_mask);
++}
++#endif /* CONFIG_SMP */
++
++int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
++{
++ struct msi_msg msg;
++ unsigned long dest_phys_id;
++ unsigned int vector;
++
++ dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
++ vector = irq;
++
++ msg.address_hi = 0;
++ msg.address_lo =
++ MSI_ADDR_HEADER |
++ MSI_ADDR_DESTMODE_PHYS |
++ MSI_ADDR_REDIRECTION_CPU |
++ MSI_ADDR_DESTID_CPU(dest_phys_id);
++
++ msg.data =
++ MSI_DATA_TRIGGER_EDGE |
++ MSI_DATA_LEVEL_ASSERT |
++ MSI_DATA_DELIVERY_FIXED |
++ MSI_DATA_VECTOR(vector);
++
++ write_msi_msg(irq, &msg);
++ set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
++
++ return 0;
++}
++
++void ia64_teardown_msi_irq(unsigned int irq)
++{
++ return; /* no-op */
++}
++
++static void ia64_ack_msi_irq(unsigned int irq)
++{
++ move_native_irq(irq);
++ ia64_eoi();
++}
++
++static int ia64_msi_retrigger_irq(unsigned int irq)
++{
++ unsigned int vector = irq;
++ ia64_resend_irq(vector);
++
++ return 1;
++}
++
++/*
++ * Generic ops used on most IA64 platforms.
++ */
++static struct irq_chip ia64_msi_chip = {
++ .name = "PCI-MSI",
++ .mask = mask_msi_irq,
++ .unmask = unmask_msi_irq,
++ .ack = ia64_ack_msi_irq,
++#ifdef CONFIG_SMP
++ .set_affinity = ia64_set_msi_irq_affinity,
++#endif
++ .retrigger = ia64_msi_retrigger_irq,
++};
++
++
++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
++{
++ if (platform_setup_msi_irq)
++ return platform_setup_msi_irq(irq, pdev);
++
++ return ia64_setup_msi_irq(irq, pdev);
++}
++
++void arch_teardown_msi_irq(unsigned int irq)
++{
++ if (platform_teardown_msi_irq)
++ return platform_teardown_msi_irq(irq);
++
++ return ia64_teardown_msi_irq(irq);
++}
+diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c
+index 1cc360c..a78b45f 100644
+--- a/arch/ia64/kernel/numa.c
++++ b/arch/ia64/kernel/numa.c
+@@ -28,6 +28,37 @@ u16 cpu_to_node_map[NR_CPUS] __cacheline
+ EXPORT_SYMBOL(cpu_to_node_map);
+
+ cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
++EXPORT_SYMBOL(node_to_cpu_mask);
++
++void __cpuinit map_cpu_to_node(int cpu, int nid)
++{
++ int oldnid;
++ if (nid < 0) { /* just initialize by zero */
++ cpu_to_node_map[cpu] = 0;
++ return;
++ }
++ /* sanity check first */
++ oldnid = cpu_to_node_map[cpu];
++ if (cpu_isset(cpu, node_to_cpu_mask[oldnid])) {
++ return; /* nothing to do */
++ }
++ /* we don't have cpu-driven node hot add yet...
++ In usual case, node is created from SRAT at boot time. */
++ if (!node_online(nid))
++ nid = first_online_node;
++ cpu_to_node_map[cpu] = nid;
++ cpu_set(cpu, node_to_cpu_mask[nid]);
++ return;
++}
++
++void __cpuinit unmap_cpu_from_node(int cpu, int nid)
++{
++ WARN_ON(!cpu_isset(cpu, node_to_cpu_mask[nid]));
++ WARN_ON(cpu_to_node_map[cpu] != nid);
++ cpu_to_node_map[cpu] = 0;
++ cpu_clear(cpu, node_to_cpu_mask[nid]);
++}
++
+
+ /**
+ * build_cpu_to_node_map - setup cpu to node and node to cpumask arrays
+@@ -49,8 +80,6 @@ void __init build_cpu_to_node_map(void)
+ 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]);
++ map_cpu_to_node(cpu, node);
+ }
+ }
+diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S
+index ebaf1e6..0b53344 100644
+--- a/arch/ia64/kernel/pal.S
++++ b/arch/ia64/kernel/pal.S
+@@ -21,11 +21,12 @@ pal_entry_point:
+ .text
+
+ /*
+- * Set the PAL entry point address. This could be written in C code, but we do it here
+- * to keep it all in one module (besides, it's so trivial that it's
++ * Set the PAL entry point address. This could be written in C code, but we
++ * do it here to keep it all in one module (besides, it's so trivial that it's
+ * not a big deal).
+ *
+- * in0 Address of the PAL entry point (text address, NOT a function descriptor).
++ * in0 Address of the PAL entry point (text address, NOT a function
++ * descriptor).
+ */
+ GLOBAL_ENTRY(ia64_pal_handler_init)
+ alloc r3=ar.pfs,1,0,0,0
+@@ -36,9 +37,9 @@ GLOBAL_ENTRY(ia64_pal_handler_init)
+ END(ia64_pal_handler_init)
+
+ /*
+- * Default PAL call handler. This needs to be coded in assembly because it uses
+- * the static calling convention, i.e., the RSE may not be used and calls are
+- * done via "br.cond" (not "br.call").
++ * Default PAL call handler. This needs to be coded in assembly because it
++ * uses the static calling convention, i.e., the RSE may not be used and
++ * calls are done via "br.cond" (not "br.call").
+ */
+ GLOBAL_ENTRY(ia64_pal_default_handler)
+ mov r8=-1
+@@ -50,12 +51,10 @@ END(ia64_pal_default_handler)
+ *
+ * in0 Index of PAL service
+ * in1 - in3 Remaining PAL arguments
+- * in4 1 ==> clear psr.ic, 0 ==> don't clear psr.ic
+- *
+ */
+ GLOBAL_ENTRY(ia64_pal_call_static)
+- .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
+- alloc loc1 = ar.pfs,5,5,0,0
++ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
++ alloc loc1 = ar.pfs,4,5,0,0
+ movl loc2 = pal_entry_point
+ 1: {
+ mov r28 = in0
+@@ -64,7 +63,6 @@ GLOBAL_ENTRY(ia64_pal_call_static)
+ }
+ ;;
+ ld8 loc2 = [loc2] // loc2 <- entry point
+- tbit.nz p6,p7 = in4, 0
+ adds r8 = 1f-1b,r8
+ mov loc4=ar.rsc // save RSE configuration
+ ;;
+@@ -74,13 +72,11 @@ GLOBAL_ENTRY(ia64_pal_call_static)
+ .body
+ mov r30 = in2
+
+-(p6) rsm psr.i | psr.ic
+ mov r31 = in3
+ mov b7 = loc2
+
+-(p7) rsm psr.i
++ rsm psr.i
+ ;;
+-(p6) srlz.i
+ mov rp = r8
+ br.cond.sptk.many b7
+ 1: mov psr.l = loc3
+@@ -96,8 +92,8 @@ END(ia64_pal_call_static)
+ * Make a PAL call using the stacked registers calling convention.
+ *
+ * Inputs:
+- * in0 Index of PAL service
+- * in2 - in3 Remaning PAL arguments
++ * in0 Index of PAL service
++ * in2 - in3 Remaining PAL arguments
+ */
+ GLOBAL_ENTRY(ia64_pal_call_stacked)
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
+@@ -131,18 +127,18 @@ END(ia64_pal_call_stacked)
+ * Make a physical mode PAL call using the static registers calling convention.
+ *
+ * Inputs:
+- * in0 Index of PAL service
+- * in2 - in3 Remaning PAL arguments
++ * in0 Index of PAL service
++ * in2 - in3 Remaining PAL arguments
+ *
+ * PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
+ * So we don't need to clear them.
+ */
+-#define PAL_PSR_BITS_TO_CLEAR \
+- (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT | \
+- IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
++#define PAL_PSR_BITS_TO_CLEAR \
++ (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT |\
++ IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
+ IA64_PSR_DFL | IA64_PSR_DFH)
+
+-#define PAL_PSR_BITS_TO_SET \
++#define PAL_PSR_BITS_TO_SET \
+ (IA64_PSR_BN)
+
+
+@@ -178,7 +174,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static)
+ ;;
+ andcm r16=loc3,r16 // removes bits to clear from psr
+ br.call.sptk.many rp=ia64_switch_mode_phys
+-.ret1: mov rp = r8 // install return address (physical)
++ mov rp = r8 // install return address (physical)
+ mov loc5 = r19
+ mov loc6 = r20
+ br.cond.sptk.many b7
+@@ -188,7 +184,6 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static)
+ mov r19=loc5
+ mov r20=loc6
+ br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
+-.ret2:
+ mov psr.l = loc3 // restore init PSR
+
+ mov ar.pfs = loc1
+@@ -203,8 +198,8 @@ END(ia64_pal_call_phys_static)
+ * Make a PAL call using the stacked registers in physical mode.
+ *
+ * Inputs:
+- * in0 Index of PAL service
+- * in2 - in3 Remaning PAL arguments
++ * in0 Index of PAL service
++ * in2 - in3 Remaining PAL arguments
+ */
+ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
+@@ -212,7 +207,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
+ movl loc2 = pal_entry_point
+ 1: {
+ mov r28 = in0 // copy procedure index
+- mov loc0 = rp // save rp
++ mov loc0 = rp // save rp
+ }
+ .body
+ ;;
+@@ -245,7 +240,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
+ mov r16=loc3 // r16= original psr
+ mov r19=loc5
+ mov r20=loc6
+- br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
++ br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
+
+ mov psr.l = loc3 // restore init PSR
+ mov ar.pfs = loc1
+@@ -257,10 +252,11 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
+ END(ia64_pal_call_phys_stacked)
+
+ /*
+- * Save scratch fp scratch regs which aren't saved in pt_regs already (fp10-fp15).
++ * Save scratch fp scratch regs which aren't saved in pt_regs already
++ * (fp10-fp15).
+ *
+- * NOTE: We need to do this since firmware (SAL and PAL) may use any of the scratch
+- * regs fp-low partition.
++ * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
++ * scratch regs fp-low partition.
+ *
+ * Inputs:
+ * in0 Address of stack storage for fp regs
+diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
+index 84a7e52..3aaede0 100644
+--- a/arch/ia64/kernel/perfmon.c
++++ b/arch/ia64/kernel/perfmon.c
+@@ -34,6 +34,7 @@
+ #include <linux/file.h>
+ #include <linux/poll.h>
+ #include <linux/vfs.h>
++#include <linux/smp.h>
+ #include <linux/pagemap.h>
+ #include <linux/mount.h>
+ #include <linux/bitops.h>
+@@ -62,6 +63,9 @@
+
+ #define PFM_INVALID_ACTIVATION (~0UL)
+
++#define PFM_NUM_PMC_REGS 64 /* PMC save area for ctxsw */
++#define PFM_NUM_PMD_REGS 64 /* PMD save area for ctxsw */
++
+ /*
+ * depth of message queue
+ */
+@@ -296,14 +300,17 @@ typedef struct pfm_context {
+ unsigned long ctx_reload_pmcs[4]; /* bitmask of force reload PMC on ctxsw in */
+ unsigned long ctx_used_monitors[4]; /* bitmask of monitor PMC being used */
+
+- unsigned long ctx_pmcs[IA64_NUM_PMC_REGS]; /* saved copies of PMC values */
++ unsigned long ctx_pmcs[PFM_NUM_PMC_REGS]; /* saved copies of PMC values */
+
+ unsigned int ctx_used_ibrs[1]; /* bitmask of used IBR (speedup ctxsw in) */
+ unsigned int ctx_used_dbrs[1]; /* bitmask of used DBR (speedup ctxsw in) */
+ unsigned long ctx_dbrs[IA64_NUM_DBG_REGS]; /* DBR values (cache) when not loaded */
+ unsigned long ctx_ibrs[IA64_NUM_DBG_REGS]; /* IBR values (cache) when not loaded */
+
+- pfm_counter_t ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */
++ pfm_counter_t ctx_pmds[PFM_NUM_PMD_REGS]; /* software state for PMDS */
++
++ unsigned long th_pmcs[PFM_NUM_PMC_REGS]; /* PMC thread save state */
++ unsigned long th_pmds[PFM_NUM_PMD_REGS]; /* PMD thread save state */
+
+ u64 ctx_saved_psr_up; /* only contains psr.up value */
+
+@@ -867,7 +874,6 @@ static void
+ pfm_mask_monitoring(struct task_struct *task)
+ {
+ pfm_context_t *ctx = PFM_GET_CTX(task);
+- struct thread_struct *th = &task->thread;
+ unsigned long mask, val, ovfl_mask;
+ int i;
+
+@@ -888,7 +894,7 @@ pfm_mask_monitoring(struct task_struct *
+ * So in both cases, the live register contains the owner's
+ * state. We can ONLY touch the PMU registers and NOT the PSR.
+ *
+- * As a consequence to this call, the thread->pmds[] array
++ * As a consequence to this call, the ctx->th_pmds[] array
+ * contains stale information which must be ignored
+ * when context is reloaded AND monitoring is active (see
+ * pfm_restart).
+@@ -923,9 +929,9 @@ pfm_mask_monitoring(struct task_struct *
+ mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
+ for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
+ if ((mask & 0x1) == 0UL) continue;
+- ia64_set_pmc(i, th->pmcs[i] & ~0xfUL);
+- th->pmcs[i] &= ~0xfUL;
+- DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, th->pmcs[i]));
++ ia64_set_pmc(i, ctx->th_pmcs[i] & ~0xfUL);
++ ctx->th_pmcs[i] &= ~0xfUL;
++ DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
+ }
+ /*
+ * make all of this visible
+@@ -942,7 +948,6 @@ static void
+ pfm_restore_monitoring(struct task_struct *task)
+ {
+ pfm_context_t *ctx = PFM_GET_CTX(task);
+- struct thread_struct *th = &task->thread;
+ unsigned long mask, ovfl_mask;
+ unsigned long psr, val;
+ int i, is_system;
+@@ -1008,9 +1013,9 @@ pfm_restore_monitoring(struct task_struc
+ mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
+ for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
+ if ((mask & 0x1) == 0UL) continue;
+- th->pmcs[i] = ctx->ctx_pmcs[i];
+- ia64_set_pmc(i, th->pmcs[i]);
+- DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i]));
++ ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
++ ia64_set_pmc(i, ctx->th_pmcs[i]);
++ DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, ctx->th_pmcs[i]));
+ }
+ ia64_srlz_d();
+
+@@ -1069,7 +1074,6 @@ pfm_restore_pmds(unsigned long *pmds, un
+ static inline void
+ pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
+ {
+- struct thread_struct *thread = &task->thread;
+ unsigned long ovfl_val = pmu_conf->ovfl_val;
+ unsigned long mask = ctx->ctx_all_pmds[0];
+ unsigned long val;
+@@ -1091,11 +1095,11 @@ pfm_copy_pmds(struct task_struct *task,
+ ctx->ctx_pmds[i].val = val & ~ovfl_val;
+ val &= ovfl_val;
+ }
+- thread->pmds[i] = val;
++ ctx->th_pmds[i] = val;
+
+ DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n",
+ i,
+- thread->pmds[i],
++ ctx->th_pmds[i],
+ ctx->ctx_pmds[i].val));
+ }
+ }
+@@ -1106,7 +1110,6 @@ pfm_copy_pmds(struct task_struct *task,
+ static inline void
+ pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx)
+ {
+- struct thread_struct *thread = &task->thread;
+ unsigned long mask = ctx->ctx_all_pmcs[0];
+ int i;
+
+@@ -1114,8 +1117,8 @@ pfm_copy_pmcs(struct task_struct *task,
+
+ for (i=0; mask; i++, mask>>=1) {
+ /* masking 0 with ovfl_val yields 0 */
+- thread->pmcs[i] = ctx->ctx_pmcs[i];
+- DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i]));
++ ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
++ DPRINT(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
+ }
+ }
+
+@@ -2859,7 +2862,6 @@ pfm_reset_regs(pfm_context_t *ctx, unsig
+ static int
+ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+ {
+- struct thread_struct *thread = NULL;
+ struct task_struct *task;
+ pfarg_reg_t *req = (pfarg_reg_t *)arg;
+ unsigned long value, pmc_pm;
+@@ -2880,7 +2882,6 @@ pfm_write_pmcs(pfm_context_t *ctx, void
+ if (state == PFM_CTX_ZOMBIE) return -EINVAL;
+
+ if (is_loaded) {
+- thread = &task->thread;
+ /*
+ * In system wide and when the context is loaded, access can only happen
+ * when the caller is running on the CPU being monitored by the session.
+@@ -3035,7 +3036,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void
+ *
+ * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs().
+ *
+- * The value in thread->pmcs[] may be modified on overflow, i.e., when
++ * The value in th_pmcs[] may be modified on overflow, i.e., when
+ * monitoring needs to be stopped.
+ */
+ if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum);
+@@ -3049,7 +3050,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void
+ /*
+ * write thread state
+ */
+- if (is_system == 0) thread->pmcs[cnum] = value;
++ if (is_system == 0) ctx->th_pmcs[cnum] = value;
+
+ /*
+ * write hardware register if we can
+@@ -3101,7 +3102,6 @@ error:
+ static int
+ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+ {
+- struct thread_struct *thread = NULL;
+ struct task_struct *task;
+ pfarg_reg_t *req = (pfarg_reg_t *)arg;
+ unsigned long value, hw_value, ovfl_mask;
+@@ -3125,7 +3125,6 @@ pfm_write_pmds(pfm_context_t *ctx, void
+ * the owner of the local PMU.
+ */
+ if (likely(is_loaded)) {
+- thread = &task->thread;
+ /*
+ * In system wide and when the context is loaded, access can only happen
+ * when the caller is running on the CPU being monitored by the session.
+@@ -3233,7 +3232,7 @@ pfm_write_pmds(pfm_context_t *ctx, void
+ /*
+ * write thread state
+ */
+- if (is_system == 0) thread->pmds[cnum] = hw_value;
++ if (is_system == 0) ctx->th_pmds[cnum] = hw_value;
+
+ /*
+ * write hardware register if we can
+@@ -3299,7 +3298,6 @@ abort_mission:
+ static int
+ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+ {
+- struct thread_struct *thread = NULL;
+ struct task_struct *task;
+ unsigned long val = 0UL, lval, ovfl_mask, sval;
+ pfarg_reg_t *req = (pfarg_reg_t *)arg;
+@@ -3323,7 +3321,6 @@ pfm_read_pmds(pfm_context_t *ctx, void *
+ if (state == PFM_CTX_ZOMBIE) return -EINVAL;
+
+ if (likely(is_loaded)) {
+- thread = &task->thread;
+ /*
+ * In system wide and when the context is loaded, access can only happen
+ * when the caller is running on the CPU being monitored by the session.
+@@ -3385,7 +3382,7 @@ pfm_read_pmds(pfm_context_t *ctx, void *
+ * if context is zombie, then task does not exist anymore.
+ * In this case, we use the full value saved in the context (pfm_flush_regs()).
+ */
+- val = is_loaded ? thread->pmds[cnum] : 0UL;
++ val = is_loaded ? ctx->th_pmds[cnum] : 0UL;
+ }
+ rd_func = pmu_conf->pmd_desc[cnum].read_check;
+
+@@ -4354,8 +4351,8 @@ pfm_context_load(pfm_context_t *ctx, voi
+ pfm_copy_pmds(task, ctx);
+ pfm_copy_pmcs(task, ctx);
+
+- pmcs_source = thread->pmcs;
+- pmds_source = thread->pmds;
++ pmcs_source = ctx->th_pmcs;
++ pmds_source = ctx->th_pmds;
+
+ /*
+ * always the case for system-wide
+@@ -5561,12 +5558,13 @@ report_spurious2:
+ }
+
+ static irqreturn_t
+-pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
++pfm_interrupt_handler(int irq, void *arg)
+ {
+ unsigned long start_cycles, total_cycles;
+ unsigned long min, max;
+ int this_cpu;
+ int ret;
++ struct pt_regs *regs = get_irq_regs();
+
+ this_cpu = get_cpu();
+ if (likely(!pfm_alt_intr_handler)) {
+@@ -5864,14 +5862,12 @@ void
+ pfm_save_regs(struct task_struct *task)
+ {
+ pfm_context_t *ctx;
+- struct thread_struct *t;
+ unsigned long flags;
+ u64 psr;
+
+
+ ctx = PFM_GET_CTX(task);
+ if (ctx == NULL) return;
+- t = &task->thread;
+
+ /*
+ * we always come here with interrupts ALREADY disabled by
+@@ -5929,19 +5925,19 @@ pfm_save_regs(struct task_struct *task)
+ * guarantee we will be schedule at that same
+ * CPU again.
+ */
+- pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]);
++ pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
+
+ /*
+ * save pmc0 ia64_srlz_d() done in pfm_save_pmds()
+ * we will need it on the restore path to check
+ * for pending overflow.
+ */
+- t->pmcs[0] = ia64_get_pmc(0);
++ ctx->th_pmcs[0] = ia64_get_pmc(0);
+
+ /*
+ * unfreeze PMU if had pending overflows
+ */
+- if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
++ if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
+
+ /*
+ * finally, allow context access.
+@@ -5986,7 +5982,6 @@ static void
+ pfm_lazy_save_regs (struct task_struct *task)
+ {
+ pfm_context_t *ctx;
+- struct thread_struct *t;
+ unsigned long flags;
+
+ { u64 psr = pfm_get_psr();
+@@ -5994,7 +5989,6 @@ pfm_lazy_save_regs (struct task_struct *
+ }
+
+ ctx = PFM_GET_CTX(task);
+- t = &task->thread;
+
+ /*
+ * we need to mask PMU overflow here to
+@@ -6019,19 +6013,19 @@ pfm_lazy_save_regs (struct task_struct *
+ /*
+ * save all the pmds we use
+ */
+- pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]);
++ pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
+
+ /*
+ * save pmc0 ia64_srlz_d() done in pfm_save_pmds()
+ * it is needed to check for pended overflow
+ * on the restore path
+ */
+- t->pmcs[0] = ia64_get_pmc(0);
++ ctx->th_pmcs[0] = ia64_get_pmc(0);
+
+ /*
+ * unfreeze PMU if had pending overflows
+ */
+- if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
++ if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
+
+ /*
+ * now get can unmask PMU interrupts, they will
+@@ -6050,7 +6044,6 @@ void
+ pfm_load_regs (struct task_struct *task)
+ {
+ pfm_context_t *ctx;
+- struct thread_struct *t;
+ unsigned long pmc_mask = 0UL, pmd_mask = 0UL;
+ unsigned long flags;
+ u64 psr, psr_up;
+@@ -6061,11 +6054,10 @@ pfm_load_regs (struct task_struct *task)
+
+ BUG_ON(GET_PMU_OWNER());
+
+- t = &task->thread;
+ /*
+ * possible on unload
+ */
+- if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) return;
++ if (unlikely((task->thread.flags & IA64_THREAD_PM_VALID) == 0)) return;
+
+ /*
+ * we always come here with interrupts ALREADY disabled by
+@@ -6147,21 +6139,21 @@ pfm_load_regs (struct task_struct *task)
+ *
+ * XXX: optimize here
+ */
+- if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask);
+- if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask);
++ if (pmd_mask) pfm_restore_pmds(ctx->th_pmds, pmd_mask);
++ if (pmc_mask) pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
+
+ /*
+ * check for pending overflow at the time the state
+ * was saved.
+ */
+- if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
++ if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
+ /*
+ * reload pmc0 with the overflow information
+ * On McKinley PMU, this will trigger a PMU interrupt
+ */
+- ia64_set_pmc(0, t->pmcs[0]);
++ ia64_set_pmc(0, ctx->th_pmcs[0]);
+ ia64_srlz_d();
+- t->pmcs[0] = 0UL;
++ ctx->th_pmcs[0] = 0UL;
+
+ /*
+ * will replay the PMU interrupt
+@@ -6214,7 +6206,6 @@ pfm_load_regs (struct task_struct *task)
+ void
+ pfm_load_regs (struct task_struct *task)
+ {
+- struct thread_struct *t;
+ pfm_context_t *ctx;
+ struct task_struct *owner;
+ unsigned long pmd_mask, pmc_mask;
+@@ -6223,7 +6214,6 @@ pfm_load_regs (struct task_struct *task)
+
+ owner = GET_PMU_OWNER();
+ ctx = PFM_GET_CTX(task);
+- t = &task->thread;
+ psr = pfm_get_psr();
+
+ BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP));
+@@ -6286,22 +6276,22 @@ pfm_load_regs (struct task_struct *task)
+ */
+ pmc_mask = ctx->ctx_all_pmcs[0];
+
+- pfm_restore_pmds(t->pmds, pmd_mask);
+- pfm_restore_pmcs(t->pmcs, pmc_mask);
++ pfm_restore_pmds(ctx->th_pmds, pmd_mask);
++ pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
+
+ /*
+ * check for pending overflow at the time the state
+ * was saved.
+ */
+- if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
++ if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
+ /*
+ * reload pmc0 with the overflow information
+ * On McKinley PMU, this will trigger a PMU interrupt
+ */
+- ia64_set_pmc(0, t->pmcs[0]);
++ ia64_set_pmc(0, ctx->th_pmcs[0]);
+ ia64_srlz_d();
+
+- t->pmcs[0] = 0UL;
++ ctx->th_pmcs[0] = 0UL;
+
+ /*
+ * will replay the PMU interrupt
+@@ -6376,11 +6366,11 @@ pfm_flush_pmds(struct task_struct *task,
+ */
+ pfm_unfreeze_pmu();
+ } else {
+- pmc0 = task->thread.pmcs[0];
++ pmc0 = ctx->th_pmcs[0];
+ /*
+ * clear whatever overflow status bits there were
+ */
+- task->thread.pmcs[0] = 0;
++ ctx->th_pmcs[0] = 0;
+ }
+ ovfl_val = pmu_conf->ovfl_val;
+ /*
+@@ -6401,7 +6391,7 @@ pfm_flush_pmds(struct task_struct *task,
+ /*
+ * can access PMU always true in system wide mode
+ */
+- val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i];
++ val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : ctx->th_pmds[i];
+
+ if (PMD_IS_COUNTING(i)) {
+ DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n",
+@@ -6433,7 +6423,7 @@ pfm_flush_pmds(struct task_struct *task,
+
+ DPRINT(("[%d] ctx_pmd[%d]=0x%lx pmd_val=0x%lx\n", task->pid, i, val, pmd_val));
+
+- if (is_self) task->thread.pmds[i] = pmd_val;
++ if (is_self) ctx->th_pmds[i] = pmd_val;
+
+ ctx->ctx_pmds[i].val = val;
+ }
+@@ -6677,7 +6667,7 @@ pfm_init(void)
+ ffz(pmu_conf->ovfl_val));
+
+ /* sanity check */
+- if (pmu_conf->num_pmds >= IA64_NUM_PMD_REGS || pmu_conf->num_pmcs >= IA64_NUM_PMC_REGS) {
++ if (pmu_conf->num_pmds >= PFM_NUM_PMD_REGS || pmu_conf->num_pmcs >= PFM_NUM_PMC_REGS) {
+ printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
+ pmu_conf = NULL;
+ return -1;
+@@ -6752,7 +6742,6 @@ void
+ dump_pmu_state(const char *from)
+ {
+ struct task_struct *task;
+- struct thread_struct *t;
+ struct pt_regs *regs;
+ pfm_context_t *ctx;
+ unsigned long psr, dcr, info, flags;
+@@ -6797,16 +6786,14 @@ dump_pmu_state(const char *from)
+ ia64_psr(regs)->up = 0;
+ ia64_psr(regs)->pp = 0;
+
+- t = ¤t->thread;
+-
+ for (i=1; PMC_IS_LAST(i) == 0; i++) {
+ if (PMC_IS_IMPL(i) == 0) continue;
+- printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, t->pmcs[i]);
++ printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, ctx->th_pmcs[i]);
+ }
+
+ for (i=1; PMD_IS_LAST(i) == 0; i++) {
+ if (PMD_IS_IMPL(i) == 0) continue;
+- printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, t->pmds[i]);
++ printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, ctx->th_pmds[i]);
+ }
+
+ if (ctx) {
+diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
+index ea914cc..51922b9 100644
+--- a/arch/ia64/kernel/process.c
++++ b/arch/ia64/kernel/process.c
+@@ -8,8 +8,6 @@
+ * 2005-10-07 Keith Owens <kaos at sgi.com>
+ * Add notify_die() hooks.
+ */
+-#define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */
+-
+ #include <linux/cpu.h>
+ #include <linux/pm.h>
+ #include <linux/elf.h>
+diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c
+index 642fdc7..20bad78 100644
+--- a/arch/ia64/kernel/sal.c
++++ b/arch/ia64/kernel/sal.c
+@@ -223,12 +223,13 @@ static void __init sal_desc_ap_wakeup(vo
+ */
+ static int sal_cache_flush_drops_interrupts;
+
+-static void __init
++void __init
+ check_sal_cache_flush (void)
+ {
+ unsigned long flags;
+ int cpu;
+- u64 vector;
++ u64 vector, cache_type = 3;
++ struct ia64_sal_retval isrv;
+
+ cpu = get_cpu();
+ local_irq_save(flags);
+@@ -243,7 +244,10 @@ check_sal_cache_flush (void)
+ while (!ia64_get_irr(IA64_TIMER_VECTOR))
+ cpu_relax();
+
+- ia64_sal_cache_flush(3);
++ SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0);
++
++ if (isrv.status)
++ printk(KERN_ERR "SAL_CAL_FLUSH failed with %ld\n", isrv.status);
+
+ if (ia64_get_irr(IA64_TIMER_VECTOR)) {
+ vector = ia64_get_ivr();
+@@ -331,7 +335,6 @@ ia64_sal_init (struct ia64_sal_systab *s
+ p += SAL_DESC_SIZE(*p);
+ }
+
+- check_sal_cache_flush();
+ }
+
+ int
+diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
+index 9065f0f..e63b8ca 100644
+--- a/arch/ia64/kernel/salinfo.c
++++ b/arch/ia64/kernel/salinfo.c
+@@ -266,6 +266,7 @@ salinfo_log_wakeup(int type, u8 *buffer,
+ /* Check for outstanding MCA/INIT records every minute (arbitrary) */
+ #define SALINFO_TIMER_DELAY (60*HZ)
+ static struct timer_list salinfo_timer;
++extern void ia64_mlogbuf_dump(void);
+
+ static void
+ salinfo_timeout_check(struct salinfo_data *data)
+@@ -283,6 +284,7 @@ salinfo_timeout_check(struct salinfo_dat
+ static void
+ salinfo_timeout (unsigned long arg)
+ {
++ ia64_mlogbuf_dump();
+ salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
+ salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
+ salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
+@@ -332,6 +334,8 @@ retry:
+ if (cpu == -1)
+ goto retry;
+
++ ia64_mlogbuf_dump();
++
+ /* for next read, start checking at next CPU */
+ data->cpu_check = cpu;
+ if (++data->cpu_check == NR_CPUS)
+diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
+index 7ad0d9c..d10404a 100644
+--- a/arch/ia64/kernel/setup.c
++++ b/arch/ia64/kernel/setup.c
+@@ -54,7 +54,6 @@
+ #include <asm/processor.h>
+ #include <asm/sal.h>
+ #include <asm/sections.h>
+-#include <asm/serial.h>
+ #include <asm/setup.h>
+ #include <asm/smp.h>
+ #include <asm/system.h>
+@@ -458,6 +457,8 @@ setup_arch (char **cmdline_p)
+ cpu_init(); /* initialize the bootstrap CPU */
+ mmu_context_init(); /* initialize context_id bitmap */
+
++ check_sal_cache_flush();
++
+ #ifdef CONFIG_ACPI
+ acpi_boot_init();
+ #endif
+@@ -509,7 +510,7 @@ show_cpuinfo (struct seq_file *m, void *
+ { 1UL << 1, "spontaneous deferral"},
+ { 1UL << 2, "16-byte atomic ops" }
+ };
+- char family[32], features[128], *cp, sep;
++ char features[128], *cp, sep;
+ struct cpuinfo_ia64 *c = v;
+ unsigned long mask;
+ unsigned long proc_freq;
+@@ -517,12 +518,6 @@ show_cpuinfo (struct seq_file *m, void *
+
+ mask = c->features;
+
+- switch (c->family) {
+- case 0x07: memcpy(family, "Itanium", 8); break;
+- case 0x1f: memcpy(family, "Itanium 2", 10); break;
+- default: sprintf(family, "%u", c->family); break;
+- }
+-
+ /* build the feature string: */
+ memcpy(features, " standard", 10);
+ cp = features;
+@@ -553,8 +548,9 @@ show_cpuinfo (struct seq_file *m, void *
+ "processor : %d\n"
+ "vendor : %s\n"
+ "arch : IA-64\n"
+- "family : %s\n"
++ "family : %u\n"
+ "model : %u\n"
++ "model name : %s\n"
+ "revision : %u\n"
+ "archrev : %u\n"
+ "features :%s\n" /* don't change this---it _is_ right! */
+@@ -563,7 +559,8 @@ show_cpuinfo (struct seq_file *m, void *
+ "cpu MHz : %lu.%06lu\n"
+ "itc MHz : %lu.%06lu\n"
+ "BogoMIPS : %lu.%02lu\n",
+- cpunum, c->vendor, family, c->model, c->revision, c->archrev,
++ cpunum, c->vendor, c->family, c->model,
++ c->model_name, c->revision, c->archrev,
+ features, c->ppn, c->number,
+ proc_freq / 1000, proc_freq % 1000,
+ c->itc_freq / 1000000, c->itc_freq % 1000000,
+@@ -611,6 +608,31 @@ struct seq_operations cpuinfo_op = {
+ .show = show_cpuinfo
+ };
+
++static char brandname[128];
++
++static char * __cpuinit
++get_model_name(__u8 family, __u8 model)
++{
++ char brand[128];
++
++ if (ia64_pal_get_brand_info(brand)) {
++ if (family == 0x7)
++ memcpy(brand, "Merced", 7);
++ else if (family == 0x1f) switch (model) {
++ case 0: memcpy(brand, "McKinley", 9); break;
++ case 1: memcpy(brand, "Madison", 8); break;
++ case 2: memcpy(brand, "Madison up to 9M cache", 23); break;
++ } else
++ memcpy(brand, "Unknown", 8);
++ }
++ if (brandname[0] == '\0')
++ return strcpy(brandname, brand);
++ else if (strcmp(brandname, brand) == 0)
++ return brandname;
++ else
++ return kstrdup(brand, GFP_KERNEL);
++}
++
+ static void __cpuinit
+ identify_cpu (struct cpuinfo_ia64 *c)
+ {
+@@ -640,7 +662,6 @@ identify_cpu (struct cpuinfo_ia64 *c)
+ pal_status_t status;
+ unsigned long impl_va_msb = 50, phys_addr_size = 44; /* Itanium defaults */
+ int i;
+-
+ for (i = 0; i < 5; ++i)
+ cpuid.bits[i] = ia64_get_cpuid(i);
+
+@@ -663,6 +684,7 @@ identify_cpu (struct cpuinfo_ia64 *c)
+ c->family = cpuid.field.family;
+ c->archrev = cpuid.field.archrev;
+ c->features = cpuid.field.features;
++ c->model_name = get_model_name(c->family, c->model);
+
+ status = ia64_pal_vm_summary(&vm1, &vm2);
+ if (status == PAL_STATUS_SUCCESS) {
+diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
+index 657ac99..6ab95ce 100644
+--- a/arch/ia64/kernel/smp.c
++++ b/arch/ia64/kernel/smp.c
+@@ -108,7 +108,7 @@ cpu_die(void)
+ }
+
+ irqreturn_t
+-handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
++handle_IPI (int irq, void *dev_id)
+ {
+ int this_cpu = get_cpu();
+ unsigned long *pending_ipis = &__ia64_per_cpu_var(ipi_operation);
+@@ -328,10 +328,14 @@ int
+ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait)
+ {
+ struct call_data_struct data;
+- int cpus = num_online_cpus()-1;
++ int cpus;
+
+- if (!cpus)
++ 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());
+@@ -343,8 +347,6 @@ smp_call_function (void (*func) (void *i
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+- spin_lock(&call_lock);
+-
+ call_data = &data;
+ mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */
+ send_IPI_allbutself(IPI_CALL_FUNC);
+diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
+index 6203ed4..f7d7f56 100644
+--- a/arch/ia64/kernel/smpboot.c
++++ b/arch/ia64/kernel/smpboot.c
+@@ -879,3 +879,27 @@ identify_siblings(struct cpuinfo_ia64 *c
+ c->core_id = info.log1_cid;
+ c->thread_id = info.log1_tid;
+ }
++
++/*
++ * returns non zero, if multi-threading is enabled
++ * on at least one physical package. Due to hotplug cpu
++ * and (maxcpus=), all threads may not necessarily be enabled
++ * even though the processor supports multi-threading.
++ */
++int is_multithreading_enabled(void)
++{
++ int i, j;
++
++ for_each_present_cpu(i) {
++ for_each_present_cpu(j) {
++ if (j == i)
++ continue;
++ if ((cpu_data(j)->socket_id == cpu_data(i)->socket_id)) {
++ if (cpu_data(j)->core_id == cpu_data(i)->core_id)
++ return 1;
++ }
++ }
++ }
++ return 0;
++}
++EXPORT_SYMBOL_GPL(is_multithreading_enabled);
+diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
+index 6928ef0..39e0cd3 100644
+--- a/arch/ia64/kernel/time.c
++++ b/arch/ia64/kernel/time.c
+@@ -29,8 +29,6 @@
+ #include <asm/sections.h>
+ #include <asm/system.h>
+
+-extern unsigned long wall_jiffies;
+-
+ volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
+
+ #ifdef CONFIG_IA64_DEBUG_IRQ
+@@ -47,7 +45,7 @@ static struct time_interpolator itc_inte
+ };
+
+ static irqreturn_t
+-timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
++timer_interrupt (int irq, void *dev_id)
+ {
+ unsigned long new_itm;
+
+@@ -55,7 +53,7 @@ timer_interrupt (int irq, void *dev_id,
+ return IRQ_HANDLED;
+ }
+
+- platform_timer_interrupt(irq, dev_id, regs);
++ platform_timer_interrupt(irq, dev_id);
+
+ new_itm = local_cpu_data->itm_next;
+
+@@ -63,10 +61,10 @@ timer_interrupt (int irq, void *dev_id,
+ printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
+ ia64_get_itc(), new_itm);
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+
+ while (1) {
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+
+ new_itm += local_cpu_data->itm_delta;
+
+@@ -78,7 +76,7 @@ timer_interrupt (int irq, void *dev_id,
+ * xtime_lock.
+ */
+ write_seqlock(&xtime_lock);
+- do_timer(regs);
++ do_timer(1);
+ local_cpu_data->itm_next = new_itm;
+ write_sequnlock(&xtime_lock);
+ } else
+@@ -86,6 +84,12 @@ timer_interrupt (int irq, void *dev_id,
+
+ if (time_after(new_itm, ia64_get_itc()))
+ break;
++
++ /*
++ * Allow IPIs to interrupt the timer loop.
++ */
++ local_irq_enable();
++ local_irq_disable();
+ }
+
+ do {
+diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
+index f648c61..5629b45 100644
+--- a/arch/ia64/kernel/topology.c
++++ b/arch/ia64/kernel/topology.c
+@@ -36,6 +36,7 @@ int arch_register_cpu(int num)
+ */
+ if (!can_cpei_retarget() && is_cpu_cpei_target(num))
+ sysfs_cpus[num].cpu.no_control = 1;
++ map_cpu_to_node(num, node_cpuid[num].nid);
+ #endif
+
+ return register_cpu(&sysfs_cpus[num].cpu, num);
+@@ -45,7 +46,8 @@ int arch_register_cpu(int num)
+
+ void arch_unregister_cpu(int num)
+ {
+- return unregister_cpu(&sysfs_cpus[num].cpu);
++ unregister_cpu(&sysfs_cpus[num].cpu);
++ unmap_cpu_from_node(num, cpu_to_node(num));
+ }
+ EXPORT_SYMBOL(arch_register_cpu);
+ EXPORT_SYMBOL(arch_unregister_cpu);
+diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
+index 4c73a67..c58e933 100644
+--- a/arch/ia64/kernel/uncached.c
++++ b/arch/ia64/kernel/uncached.c
+@@ -98,7 +98,7 @@ static int uncached_add_chunk(struct unc
+
+ /* attempt to allocate a granule's worth of cached memory pages */
+
+- page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO,
++ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ IA64_GRANULE_SHIFT-PAGE_SHIFT);
+ if (!page) {
+ mutex_unlock(&uc_pool->add_chunk_mutex);
+diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
+index 5b0d5f6..d6083a0 100644
+--- a/arch/ia64/kernel/vmlinux.lds.S
++++ b/arch/ia64/kernel/vmlinux.lds.S
+@@ -128,13 +128,7 @@ SECTIONS
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET)
+ {
+ __initcall_start = .;
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ __initcall_end = .;
+ }
+
+@@ -184,7 +178,9 @@ SECTIONS
+ *(.data.gate)
+ __stop_gate_section = .;
+ }
+- . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose kernel data */
++ . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose
++ * kernel data
++ */
+
+ .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET)
+ { *(.data.read_mostly) }
+@@ -202,7 +198,9 @@ SECTIONS
+ *(.data.percpu)
+ __per_cpu_end = .;
+ }
+- . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */
++ . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits
++ * into percpu page size
++ */
+
+ data : { } :data
+ .data : AT(ADDR(.data) - LOAD_OFFSET)
+diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
+index e004143..82deaa3 100644
+--- a/arch/ia64/mm/contig.c
++++ b/arch/ia64/mm/contig.c
+@@ -26,7 +26,6 @@
+ #include <asm/mca.h>
+
+ #ifdef CONFIG_VIRTUAL_MEM_MAP
+-static unsigned long num_dma_physpages;
+ static unsigned long max_gap;
+ #endif
+
+@@ -41,10 +40,11 @@ show_mem (void)
+ int i, total = 0, reserved = 0;
+ int shared = 0, cached = 0;
+
+- 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));
+ i = max_mapnr;
+ for (i = 0; i < max_mapnr; i++) {
+ if (!pfn_valid(i)) {
+@@ -63,12 +63,12 @@ show_mem (void)
+ else if (page_count(mem_map + i))
+ 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("%ld pages in page table cache\n",
+- pgtable_quicklist_total_size());
++ printk(KERN_INFO "%d pages of RAM\n", total);
++ 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);
++ printk(KERN_INFO "%ld pages in page table cache\n",
++ pgtable_quicklist_total_size());
+ }
+
+ /* physical address where the bootmem map is located */
+@@ -218,18 +218,6 @@ count_pages (u64 start, u64 end, void *a
+ return 0;
+ }
+
+-#ifdef CONFIG_VIRTUAL_MEM_MAP
+-static int
+-count_dma_pages (u64 start, u64 end, void *arg)
+-{
+- unsigned long *count = arg;
+-
+- if (start < MAX_DMA_ADDRESS)
+- *count += (min(end, MAX_DMA_ADDRESS) - start) >> PAGE_SHIFT;
+- return 0;
+-}
+-#endif
+-
+ /*
+ * Set up the page tables.
+ */
+@@ -238,45 +226,23 @@ void __init
+ paging_init (void)
+ {
+ unsigned long max_dma;
+- unsigned long zones_size[MAX_NR_ZONES];
+-#ifdef CONFIG_VIRTUAL_MEM_MAP
+- unsigned long zholes_size[MAX_NR_ZONES];
+-#endif
+-
+- /* initialize mem_map[] */
+-
+- memset(zones_size, 0, sizeof(zones_size));
++ unsigned long nid = 0;
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+ num_physpages = 0;
+ efi_memmap_walk(count_pages, &num_physpages);
+
+ max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] = max_dma;
++ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+
+ #ifdef CONFIG_VIRTUAL_MEM_MAP
+- memset(zholes_size, 0, sizeof(zholes_size));
+-
+- num_dma_physpages = 0;
+- efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+-
+- if (max_low_pfn < max_dma) {
+- zones_size[ZONE_DMA] = max_low_pfn;
+- zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+- } else {
+- zones_size[ZONE_DMA] = max_dma;
+- zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+- if (num_physpages > num_dma_physpages) {
+- zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+- zholes_size[ZONE_NORMAL] =
+- ((max_low_pfn - max_dma) -
+- (num_physpages - num_dma_physpages));
+- }
+- }
+-
++ efi_memmap_walk(register_active_ranges, &nid);
+ efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
+ if (max_gap < LARGE_GAP) {
+ vmem_map = (struct page *) 0;
+- free_area_init_node(0, NODE_DATA(0), zones_size, 0,
+- zholes_size);
++ free_area_init_nodes(max_zone_pfns);
+ } else {
+ unsigned long map_size;
+
+@@ -288,20 +254,19 @@ paging_init (void)
+ vmem_map = (struct page *) vmalloc_end;
+ efi_memmap_walk(create_mem_map_page_table, NULL);
+
+- NODE_DATA(0)->node_mem_map = vmem_map;
+- free_area_init_node(0, NODE_DATA(0), zones_size,
+- 0, zholes_size);
++ /*
++ * alloc_node_mem_map makes an adjustment for mem_map
++ * which isn't compatible with vmem_map.
++ */
++ NODE_DATA(0)->node_mem_map = vmem_map +
++ find_min_pfn_with_active_regions();
++ free_area_init_nodes(max_zone_pfns);
+
+ printk("Virtual mem_map starts at 0x%p\n", mem_map);
+ }
+ #else /* !CONFIG_VIRTUAL_MEM_MAP */
+- if (max_low_pfn < max_dma)
+- zones_size[ZONE_DMA] = max_low_pfn;
+- else {
+- zones_size[ZONE_DMA] = max_dma;
+- zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+- }
+- free_area_init(zones_size);
++ add_active_range(0, 0, max_low_pfn);
++ free_area_init_nodes(max_zone_pfns);
+ #endif /* !CONFIG_VIRTUAL_MEM_MAP */
+ zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
+ }
+diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
+index d260bff..96722cb 100644
+--- a/arch/ia64/mm/discontig.c
++++ b/arch/ia64/mm/discontig.c
+@@ -547,15 +547,16 @@ void show_mem(void)
+ unsigned long total_present = 0;
+ pg_data_t *pgdat;
+
+- 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));
++ printk(KERN_INFO "Node memory in pages:\n");
+ for_each_online_pgdat(pgdat) {
+ unsigned long present;
+ unsigned long flags;
+ int shared = 0, cached = 0, reserved = 0;
+
+- printk("Node ID: %d\n", pgdat->node_id);
+ pgdat_resize_lock(pgdat, &flags);
+ present = pgdat->node_present_pages;
+ for(i = 0; i < pgdat->node_spanned_pages; i++) {
+@@ -579,18 +580,17 @@ void show_mem(void)
+ total_reserved += reserved;
+ total_cached += cached;
+ total_shared += shared;
+- printk("\t%ld pages of RAM\n", present);
+- printk("\t%d reserved pages\n", reserved);
+- printk("\t%d pages shared\n", shared);
+- printk("\t%d pages swap cached\n", cached);
++ printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, "
++ "shrd: %10d, swpd: %10d\n", pgdat->node_id,
++ present, reserved, shared, cached);
+ }
+- printk("%ld pages of RAM\n", total_present);
+- printk("%d reserved pages\n", total_reserved);
+- printk("%d pages shared\n", total_shared);
+- printk("%d pages swap cached\n", total_cached);
+- printk("Total of %ld pages in page table cache\n",
+- pgtable_quicklist_total_size());
+- printk("%d free buffer pages\n", nr_free_buffer_pages());
++ printk(KERN_INFO "%ld pages of RAM\n", total_present);
++ printk(KERN_INFO "%d reserved pages\n", total_reserved);
++ printk(KERN_INFO "%d pages shared\n", total_shared);
++ printk(KERN_INFO "%d pages swap cached\n", total_cached);
++ printk(KERN_INFO "Total of %ld pages in page table cache\n",
++ pgtable_quicklist_total_size());
++ printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
+ }
+
+ /**
+@@ -654,6 +654,7 @@ static __init int count_node_pages(unsig
+ {
+ unsigned long end = start + len;
+
++ add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT);
+ mem_data[node].num_physpages += len >> PAGE_SHIFT;
+ if (start <= __pa(MAX_DMA_ADDRESS))
+ mem_data[node].num_dma_physpages +=
+@@ -678,10 +679,10 @@ static __init int count_node_pages(unsig
+ void __init paging_init(void)
+ {
+ unsigned long max_dma;
+- unsigned long zones_size[MAX_NR_ZONES];
+- unsigned long zholes_size[MAX_NR_ZONES];
+ unsigned long pfn_offset = 0;
++ unsigned long max_pfn = 0;
+ int node;
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+ max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+
+@@ -698,47 +699,21 @@ void __init paging_init(void)
+ #endif
+
+ for_each_online_node(node) {
+- memset(zones_size, 0, sizeof(zones_size));
+- memset(zholes_size, 0, sizeof(zholes_size));
+-
+ num_physpages += mem_data[node].num_physpages;
+-
+- if (mem_data[node].min_pfn >= max_dma) {
+- /* All of this node's memory is above ZONE_DMA */
+- zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+- mem_data[node].min_pfn;
+- zholes_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+- mem_data[node].min_pfn -
+- mem_data[node].num_physpages;
+- } else if (mem_data[node].max_pfn < max_dma) {
+- /* All of this node's memory is in ZONE_DMA */
+- zones_size[ZONE_DMA] = mem_data[node].max_pfn -
+- mem_data[node].min_pfn;
+- zholes_size[ZONE_DMA] = mem_data[node].max_pfn -
+- mem_data[node].min_pfn -
+- mem_data[node].num_dma_physpages;
+- } else {
+- /* This node has memory in both zones */
+- zones_size[ZONE_DMA] = max_dma -
+- mem_data[node].min_pfn;
+- zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] -
+- mem_data[node].num_dma_physpages;
+- zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+- max_dma;
+- zholes_size[ZONE_NORMAL] = zones_size[ZONE_NORMAL] -
+- (mem_data[node].num_physpages -
+- mem_data[node].num_dma_physpages);
+- }
+-
+ pfn_offset = mem_data[node].min_pfn;
+
+ #ifdef CONFIG_VIRTUAL_MEM_MAP
+ NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset;
+ #endif
+- free_area_init_node(node, NODE_DATA(node), zones_size,
+- pfn_offset, zholes_size);
++ if (mem_data[node].max_pfn > max_pfn)
++ max_pfn = mem_data[node].max_pfn;
+ }
+
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] = max_dma;
++ max_zone_pfns[ZONE_NORMAL] = max_pfn;
++ free_area_init_nodes(max_zone_pfns);
++
+ zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
+ }
+
+diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
+index 14ef7cc..59f3ab9 100644
+--- a/arch/ia64/mm/fault.c
++++ b/arch/ia64/mm/fault.c
+@@ -146,9 +146,11 @@ ia64_do_page_fault (unsigned long addres
+ # error File is out of sync with <linux/mm.h>. Please update.
+ # endif
+
++ if (((isr >> IA64_ISR_R_BIT) & 1UL) && (!(vma->vm_flags & (VM_READ | VM_WRITE))))
++ goto bad_area;
++
+ mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT)
+- | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT)
+- | (((isr >> IA64_ISR_R_BIT) & 1UL) << VM_READ_BIT));
++ | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT));
+
+ if ((vma->vm_flags & mask) != mask)
+ goto bad_area;
+@@ -278,7 +280,7 @@ ia64_do_page_fault (unsigned long addres
+
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
+index 30617cc..ff87a5c 100644
+--- a/arch/ia64/mm/init.c
++++ b/arch/ia64/mm/init.c
+@@ -593,6 +593,18 @@ find_largest_hole (u64 start, u64 end, v
+ last_end = end;
+ return 0;
+ }
++
++int __init
++register_active_ranges(u64 start, u64 end, void *nid)
++{
++ BUG_ON(nid == NULL);
++ BUG_ON(*(unsigned long *)nid >= MAX_NUMNODES);
++
++ add_active_range(*(unsigned long *)nid,
++ __pa(start) >> PAGE_SHIFT,
++ __pa(end) >> PAGE_SHIFT);
++ return 0;
++}
+ #endif /* CONFIG_VIRTUAL_MEM_MAP */
+
+ static int __init
+diff --git a/arch/ia64/mm/numa.c b/arch/ia64/mm/numa.c
+index 64e4c21..7807fc5 100644
+--- a/arch/ia64/mm/numa.c
++++ b/arch/ia64/mm/numa.c
+@@ -16,6 +16,7 @@
+ #include <linux/node.h>
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
++#include <linux/module.h>
+ #include <asm/mmzone.h>
+ #include <asm/numa.h>
+
+@@ -69,4 +70,21 @@ int early_pfn_to_nid(unsigned long pfn)
+
+ return 0;
+ }
++
++#ifdef CONFIG_MEMORY_HOTPLUG
++/*
++ * SRAT information is stored in node_memblk[], then we can use SRAT
++ * information at memory-hot-add if necessary.
++ */
++
++int memory_add_physaddr_to_nid(u64 addr)
++{
++ int nid = paddr_to_nid(addr);
++ if (nid < 0)
++ return 0;
++ return nid;
++}
++
++EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
++#endif
+ #endif
+diff --git a/arch/ia64/pci/Makefile b/arch/ia64/pci/Makefile
+index e66889e..fb14dc5 100644
+--- a/arch/ia64/pci/Makefile
++++ b/arch/ia64/pci/Makefile
+@@ -1,4 +1,4 @@
+ #
+ # Makefile for the ia64-specific parts of the pci bus
+ #
+-obj-y := pci.o
++obj-y := pci.o fixup.o
+diff --git a/arch/ia64/pci/fixup.c b/arch/ia64/pci/fixup.c
+new file mode 100644
+index 0000000..245dc1f
+--- /dev/null
++++ b/arch/ia64/pci/fixup.c
+@@ -0,0 +1,69 @@
++/*
++ * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
++ * Derived from fixup.c of i386 tree.
++ */
++
++#include <linux/pci.h>
++#include <linux/init.h>
++
++#include <asm/machvec.h>
++
++/*
++ * Fixup to mark boot BIOS video selected by BIOS before it changes
++ *
++ * From information provided by "Jon Smirl" <jonsmirl at gmail.com>
++ *
++ * The standard boot ROM sequence for an x86 machine uses the BIOS
++ * to select an initial video card for boot display. This boot video
++ * card will have it's BIOS copied to C0000 in system RAM.
++ * IORESOURCE_ROM_SHADOW is used to associate the boot video
++ * card with this copy. On laptops this copy has to be used since
++ * the main ROM may be compressed or combined with another image.
++ * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
++ * is marked here since the boot video device will be the only enabled
++ * video device at this point.
++ */
++
++static void __devinit pci_fixup_video(struct pci_dev *pdev)
++{
++ struct pci_dev *bridge;
++ struct pci_bus *bus;
++ u16 config;
++
++ if ((strcmp(platform_name, "dig") != 0)
++ && (strcmp(platform_name, "hpzx1") != 0))
++ return;
++ /* Maybe, this machine supports legacy memory map. */
++
++ if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
++ return;
++
++ /* Is VGA routed to us? */
++ bus = pdev->bus;
++ while (bus) {
++ bridge = bus->self;
++
++ /*
++ * From information provided by
++ * "David Miller" <davem at davemloft.net>
++ * The bridge control register is valid for PCI header
++ * type BRIDGE, or CARDBUS. Host to PCI controllers use
++ * PCI header type NORMAL.
++ */
++ if (bridge
++ &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE)
++ ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) {
++ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
++ &config);
++ if (!(config & PCI_BRIDGE_CTL_VGA))
++ return;
++ }
++ bus = bus->parent;
++ }
++ pci_read_config_word(pdev, PCI_COMMAND, &config);
++ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
++ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
++ printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
++ }
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
+index 60b45e7..b30be7c 100644
+--- a/arch/ia64/pci/pci.c
++++ b/arch/ia64/pci/pci.c
+@@ -562,7 +562,8 @@ pcibios_enable_device (struct pci_dev *d
+ void
+ pcibios_disable_device (struct pci_dev *dev)
+ {
+- acpi_pci_irq_disable(dev);
++ if (dev->is_enabled)
++ acpi_pci_irq_disable(dev);
+ }
+
+ void
+@@ -809,12 +810,3 @@ pcibios_prep_mwi (struct pci_dev *dev)
+ }
+ return rc;
+ }
+-
+-int pci_vector_resources(int last, int nr_released)
+-{
+- int count = nr_released;
+-
+- count += (IA64_LAST_DEVICE_VECTOR - last);
+-
+- return count;
+-}
+diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile
+index ab9c48c..2d78f34 100644
+--- a/arch/ia64/sn/kernel/Makefile
++++ b/arch/ia64/sn/kernel/Makefile
+@@ -19,3 +19,4 @@ xp-y := xp_main.o xp_nofault.o
+ obj-$(CONFIG_IA64_SGI_SN_XP) += xpc.o
+ xpc-y := xpc_main.o xpc_channel.o xpc_partition.o
+ obj-$(CONFIG_IA64_SGI_SN_XP) += xpnet.o
++obj-$(CONFIG_PCI_MSI) += msi_sn.o
+diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c
+index 27dee45..7f73ad4 100644
+--- a/arch/ia64/sn/kernel/bte.c
++++ b/arch/ia64/sn/kernel/bte.c
+@@ -277,8 +277,7 @@ bte_result_t bte_unaligned_copy(u64 src,
+ }
+
+ /* temporary buffer used during unaligned transfers */
+- bteBlock_unaligned = kmalloc(len + 3 * L1_CACHE_BYTES,
+- GFP_KERNEL | GFP_DMA);
++ bteBlock_unaligned = kmalloc(len + 3 * L1_CACHE_BYTES, GFP_KERNEL);
+ if (bteBlock_unaligned == NULL) {
+ return BTEFAIL_NOTAVAIL;
+ }
+diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
+index 96fb81e..abca6bd 100644
+--- a/arch/ia64/sn/kernel/huberror.c
++++ b/arch/ia64/sn/kernel/huberror.c
+@@ -22,7 +22,7 @@
+ void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
+ extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
+ int);
+-static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep)
++static irqreturn_t hub_eint_handler(int irq, void *arg)
+ {
+ struct hubdev_info *hubdev_info;
+ struct ia64_sal_retval ret_stuff;
+@@ -178,7 +178,7 @@ void hubiio_crb_error_handler(struct hub
+ */
+ void hub_error_init(struct hubdev_info *hubdev_info)
+ {
+- if (request_irq(SGI_II_ERROR, (void *)hub_eint_handler, IRQF_SHARED,
++ if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED,
+ "SN_hub_error", (void *)hubdev_info))
+ printk("hub_error_init: Failed to request_irq for 0x%p\n",
+ hubdev_info);
+diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
+new file mode 100644
+index 0000000..6ffd1f8
+--- /dev/null
++++ b/arch/ia64/sn/kernel/msi_sn.c
+@@ -0,0 +1,230 @@
++/*
++ * 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) 2006 Silicon Graphics, Inc. All Rights Reserved.
++ */
++
++#include <linux/types.h>
++#include <linux/irq.h>
++#include <linux/pci.h>
++#include <linux/cpumask.h>
++#include <linux/msi.h>
++
++#include <asm/sn/addrs.h>
++#include <asm/sn/intr.h>
++#include <asm/sn/pcibus_provider_defs.h>
++#include <asm/sn/pcidev.h>
++#include <asm/sn/nodepda.h>
++
++struct sn_msi_info {
++ u64 pci_addr;
++ struct sn_irq_info *sn_irq_info;
++};
++
++static struct sn_msi_info sn_msi_info[NR_IRQS];
++
++static struct irq_chip sn_msi_chip;
++
++void sn_teardown_msi_irq(unsigned int irq)
++{
++ nasid_t nasid;
++ int widget;
++ struct pci_dev *pdev;
++ struct pcidev_info *sn_pdev;
++ struct sn_irq_info *sn_irq_info;
++ struct pcibus_bussoft *bussoft;
++ struct sn_pcibus_provider *provider;
++
++ sn_irq_info = sn_msi_info[irq].sn_irq_info;
++ if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
++ return;
++
++ sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
++ pdev = sn_pdev->pdi_linux_pcidev;
++ provider = SN_PCIDEV_BUSPROVIDER(pdev);
++
++ (*provider->dma_unmap)(pdev,
++ sn_msi_info[irq].pci_addr,
++ PCI_DMA_FROMDEVICE);
++ sn_msi_info[irq].pci_addr = 0;
++
++ bussoft = SN_PCIDEV_BUSSOFT(pdev);
++ nasid = NASID_GET(bussoft->bs_base);
++ widget = (nasid & 1) ?
++ TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
++ SWIN_WIDGETNUM(bussoft->bs_base);
++
++ sn_intr_free(nasid, widget, sn_irq_info);
++ sn_msi_info[irq].sn_irq_info = NULL;
++
++ return;
++}
++
++int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
++{
++ struct msi_msg msg;
++ struct msi_desc *entry;
++ int widget;
++ int status;
++ nasid_t nasid;
++ u64 bus_addr;
++ struct sn_irq_info *sn_irq_info;
++ struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
++ struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
++
++ entry = get_irq_data(irq);
++ if (!entry->msi_attrib.is_64)
++ return -EINVAL;
++
++ if (bussoft == NULL)
++ return -EINVAL;
++
++ if (provider == NULL || provider->dma_map_consistent == NULL)
++ return -EINVAL;
++
++ /*
++ * Set up the vector plumbing. Let the prom (via sn_intr_alloc)
++ * decide which cpu to direct this msi at by default.
++ */
++
++ nasid = NASID_GET(bussoft->bs_base);
++ widget = (nasid & 1) ?
++ TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
++ SWIN_WIDGETNUM(bussoft->bs_base);
++
++ sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
++ if (! sn_irq_info)
++ return -ENOMEM;
++
++ status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
++ if (status) {
++ kfree(sn_irq_info);
++ return -ENOMEM;
++ }
++
++ sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */
++ sn_irq_fixup(pdev, sn_irq_info);
++
++ /* Prom probably should fill these in, but doesn't ... */
++ sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
++ sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
++
++ /*
++ * Map the xio address into bus space
++ */
++ bus_addr = (*provider->dma_map_consistent)(pdev,
++ sn_irq_info->irq_xtalkaddr,
++ sizeof(sn_irq_info->irq_xtalkaddr),
++ SN_DMA_MSI|SN_DMA_ADDR_XIO);
++ if (! bus_addr) {
++ sn_intr_free(nasid, widget, sn_irq_info);
++ kfree(sn_irq_info);
++ return -ENOMEM;
++ }
++
++ sn_msi_info[irq].sn_irq_info = sn_irq_info;
++ sn_msi_info[irq].pci_addr = bus_addr;
++
++ msg.address_hi = (u32)(bus_addr >> 32);
++ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
++
++ /*
++ * In the SN platform, bit 16 is a "send vector" bit which
++ * must be present in order to move the vector through the system.
++ */
++ msg.data = 0x100 + irq;
++
++#ifdef CONFIG_SMP
++ set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
++#endif
++
++ write_msi_msg(irq, &msg);
++ set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
++
++ return 0;
++}
++
++#ifdef CONFIG_SMP
++static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
++{
++ struct msi_msg msg;
++ int slice;
++ nasid_t nasid;
++ u64 bus_addr;
++ struct pci_dev *pdev;
++ struct pcidev_info *sn_pdev;
++ struct sn_irq_info *sn_irq_info;
++ struct sn_irq_info *new_irq_info;
++ struct sn_pcibus_provider *provider;
++ unsigned int cpu;
++
++ cpu = first_cpu(cpu_mask);
++ sn_irq_info = sn_msi_info[irq].sn_irq_info;
++ if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
++ return;
++
++ /*
++ * Release XIO resources for the old MSI PCI address
++ */
++
++ read_msi_msg(irq, &msg);
++ sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
++ pdev = sn_pdev->pdi_linux_pcidev;
++ provider = SN_PCIDEV_BUSPROVIDER(pdev);
++
++ bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
++ (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
++ sn_msi_info[irq].pci_addr = 0;
++
++ nasid = cpuid_to_nasid(cpu);
++ slice = cpuid_to_slice(cpu);
++
++ new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
++ sn_msi_info[irq].sn_irq_info = new_irq_info;
++ if (new_irq_info == NULL)
++ return;
++
++ /*
++ * Map the xio address into bus space
++ */
++
++ bus_addr = (*provider->dma_map_consistent)(pdev,
++ new_irq_info->irq_xtalkaddr,
++ sizeof(new_irq_info->irq_xtalkaddr),
++ SN_DMA_MSI|SN_DMA_ADDR_XIO);
++
++ sn_msi_info[irq].pci_addr = bus_addr;
++ msg.address_hi = (u32)(bus_addr >> 32);
++ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
++
++ write_msi_msg(irq, &msg);
++ set_native_irq_info(irq, cpu_mask);
++}
++#endif /* CONFIG_SMP */
++
++static void sn_ack_msi_irq(unsigned int irq)
++{
++ move_native_irq(irq);
++ ia64_eoi();
++}
++
++static int sn_msi_retrigger_irq(unsigned int irq)
++{
++ unsigned int vector = irq;
++ ia64_resend_irq(vector);
++
++ return 1;
++}
++
++static struct irq_chip sn_msi_chip = {
++ .name = "PCI-MSI",
++ .mask = mask_msi_irq,
++ .unmask = unmask_msi_irq,
++ .ack = sn_ack_msi_irq,
++#ifdef CONFIG_SMP
++ .set_affinity = sn_set_msi_irq_affinity,
++#endif
++ .retrigger = sn_msi_retrigger_irq,
++};
+diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
+index 5f2dcba..7a2d824 100644
+--- a/arch/ia64/sn/kernel/setup.c
++++ b/arch/ia64/sn/kernel/setup.c
+@@ -65,7 +65,6 @@ extern void sn_timer_init(void);
+ extern unsigned long last_time_offset;
+ extern void (*ia64_mark_idle) (int);
+ extern void snidle(int);
+-extern unsigned char acpi_kbd_controller_present;
+ extern unsigned long long (*ia64_printk_clock)(void);
+
+ unsigned long sn_rtc_cycles_per_second;
+@@ -452,17 +451,6 @@ void __init sn_setup(char **cmdline_p)
+
+ ia64_printk_clock = ia64_sn2_printk_clock;
+
+- /*
+- * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard
+- * support here so we don't have to listen to failed keyboard probe
+- * messages.
+- */
+- if (is_shub1() && 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", version >> 8, version & 0x00FF);
+
+ /*
+diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+index 9a8a293..462ea17 100644
+--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
++++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+@@ -32,9 +32,10 @@
+ #include <linux/cpumask.h>
+ #include <linux/smp_lock.h>
+ #include <linux/nodemask.h>
++#include <linux/smp.h>
++
+ #include <asm/processor.h>
+ #include <asm/topology.h>
+-#include <asm/smp.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
+ #include <asm/sal.h>
+@@ -422,7 +423,7 @@ static int sn_topology_show(struct seq_f
+ "coherency_domain %d, "
+ "region_size %d\n",
+
+- partid, system_utsname.nodename,
++ partid, utsname()->nodename,
+ shubtype ? "shub2" : "shub1",
+ (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
+ system_size, sharing_size, coher, region_size);
+diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
+index fa7f699..103d6ea 100644
+--- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c
++++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
+@@ -36,7 +36,7 @@ extern irqreturn_t timer_interrupt(int i
+
+ #define SN_LB_INT_WAR_INTERVAL 100
+
+-void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++void sn_timer_interrupt(int irq, void *dev_id)
+ {
+ /* LED blinking */
+ if (!pda->hb_count--) {
+diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
+index 4d026f9..fa96dfc 100644
+--- a/arch/ia64/sn/kernel/xpc_main.c
++++ b/arch/ia64/sn/kernel/xpc_main.c
+@@ -222,7 +222,7 @@ xpc_timeout_partition_disengage_request(
+ * Notify the heartbeat check thread that an IRQ has been received.
+ */
+ static irqreturn_t
+-xpc_act_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs)
++xpc_act_IRQ_handler(int irq, void *dev_id)
+ {
+ atomic_inc(&xpc_act_IRQ_rcvd);
+ wake_up_interruptible(&xpc_act_IRQ_wq);
+@@ -607,12 +607,9 @@ xpc_activate_partition(struct xpc_partit
+ * irq - Interrupt ReQuest number. NOT USED.
+ *
+ * dev_id - partid of IPI's potential sender.
+- *
+- * regs - processor's context before the processor entered
+- * interrupt code. NOT USED.
+ */
+ irqreturn_t
+-xpc_notify_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs)
++xpc_notify_IRQ_handler(int irq, void *dev_id)
+ {
+ partid_t partid = (partid_t) (u64) dev_id;
+ struct xpc_partition *part = &xpc_partitions[partid];
+diff --git a/arch/ia64/sn/kernel/xpnet.c b/arch/ia64/sn/kernel/xpnet.c
+index 007703c..c8173db 100644
+--- a/arch/ia64/sn/kernel/xpnet.c
++++ b/arch/ia64/sn/kernel/xpnet.c
+@@ -225,7 +225,7 @@ xpnet_receive(partid_t partid, int chann
+ skb_put(skb, (msg->size - msg->leadin_ignore - msg->tailout_ignore));
+
+ /*
+- * Move the data over from the the other side.
++ * Move the data over from the other side.
+ */
+ if ((XPNET_VERSION_MINOR(msg->version) == 1) &&
+ (msg->embedded_bytes != 0)) {
+diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
+index 1f0253b..935029f 100644
+--- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c
++++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
+@@ -126,7 +126,7 @@ int pcibr_ate_alloc(struct pcibus_info *
+ * Setup an Address Translation Entry as specified. Use either the Bridge
+ * internal maps or the external map RAM, as appropriate.
+ */
+-static inline u64 *pcibr_ate_addr(struct pcibus_info *pcibus_info,
++static inline u64 __iomem *pcibr_ate_addr(struct pcibus_info *pcibus_info,
+ int ate_index)
+ {
+ if (ate_index < pcibus_info->pbi_int_ate_size) {
+@@ -160,7 +160,7 @@ void pcibr_ate_free(struct pcibus_info *
+
+ volatile u64 ate;
+ int count;
+- u64 flags;
++ unsigned long flags;
+
+ if (pcibr_invalidate_ate) {
+ /* For debugging purposes, clear the valid bit in the ATE */
+diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+index a86c7b9..1ee977f 100644
+--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
++++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+@@ -237,7 +237,7 @@ void sn_dma_flush(u64 addr)
+ int is_tio;
+ int wid_num;
+ int i, j;
+- u64 flags;
++ unsigned long flags;
+ u64 itte;
+ struct hubdev_info *hubinfo;
+ struct sn_flush_device_kernel *p;
+diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+index 838c93c..27dd7df 100644
+--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
++++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+@@ -95,7 +95,7 @@ u16 sn_ioboard_to_pci_bus(struct pci_bus
+ * bridge sends an error interrupt.
+ */
+ static irqreturn_t
+-pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *regs)
++pcibr_error_intr_handler(int irq, void *arg)
+ {
+ struct pcibus_info *soft = (struct pcibus_info *)arg;
+
+@@ -138,7 +138,7 @@ pcibr_bus_fixup(struct pcibus_bussoft *p
+ /*
+ * register the bridge's error interrupt handler
+ */
+- if (request_irq(SGI_PCIASIC_ERROR, (void *)pcibr_error_intr_handler,
++ if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler,
+ IRQF_SHARED, "PCIBR error", (void *)(soft))) {
+ printk(KERN_WARNING
+ "pcibr cannot allocate interrupt for error handler\n");
+diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
+index c36b0f5..8a2cb4e 100644
+--- a/arch/ia64/sn/pci/tioca_provider.c
++++ b/arch/ia64/sn/pci/tioca_provider.c
+@@ -550,13 +550,12 @@ tioca_dma_map(struct pci_dev *pdev, u64
+ * tioca_error_intr_handler - SGI TIO CA error interrupt handler
+ * @irq: unused
+ * @arg: pointer to tioca_common struct for the given CA
+- * @pt: unused
+ *
+ * Handle a CA error interrupt. Simply a wrapper around a SAL call which
+ * defers processing to the SGI prom.
+ */
+ static irqreturn_t
+-tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
++tioca_error_intr_handler(int irq, void *arg)
+ {
+ struct tioca_common *soft = arg;
+ struct ia64_sal_retval ret_stuff;
+diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
+index af7171a..46e16dc 100644
+--- a/arch/ia64/sn/pci/tioce_provider.c
++++ b/arch/ia64/sn/pci/tioce_provider.c
+@@ -53,7 +53,7 @@
+ */
+
+ static void inline
+-tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr)
++tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr)
+ {
+ u64 mmr_base;
+ u64 mmr_offset;
+@@ -62,7 +62,7 @@ tioce_mmr_war_pre(struct tioce_kernel *k
+ return;
+
+ mmr_base = kern->ce_common->ce_pcibus.bs_base;
+- mmr_offset = (u64)mmr_addr - mmr_base;
++ mmr_offset = (unsigned long)mmr_addr - mmr_base;
+
+ if (mmr_offset < 0x45000) {
+ u64 mmr_war_offset;
+@@ -79,7 +79,7 @@ tioce_mmr_war_pre(struct tioce_kernel *k
+ }
+
+ static void inline
+-tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr)
++tioce_mmr_war_post(struct tioce_kernel *kern, void __iomem *mmr_addr)
+ {
+ u64 mmr_base;
+ u64 mmr_offset;
+@@ -88,7 +88,7 @@ tioce_mmr_war_post(struct tioce_kernel *
+ return;
+
+ mmr_base = kern->ce_common->ce_pcibus.bs_base;
+- mmr_offset = (u64)mmr_addr - mmr_base;
++ mmr_offset = (unsigned long)mmr_addr - mmr_base;
+
+ if (mmr_offset < 0x45000) {
+ if (mmr_offset == 0x100)
+@@ -223,7 +223,7 @@ tioce_dma_d64(unsigned long ct_addr, int
+ * @pci_dev.
+ */
+ static inline void
+-pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
++pcidev_to_tioce(struct pci_dev *pdev, struct tioce __iomem **base,
+ struct tioce_kernel **kernel, int *port)
+ {
+ struct pcidev_info *pcidev_info;
+@@ -235,7 +235,7 @@ pcidev_to_tioce(struct pci_dev *pdev, st
+ ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private;
+
+ if (base)
+- *base = (struct tioce *)ce_common->ce_pcibus.bs_base;
++ *base = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
+ if (kernel)
+ *kernel = ce_kernel;
+
+@@ -275,13 +275,13 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ u64 pagesize;
+ int msi_capable, msi_wanted;
+ u64 *ate_shadow;
+- u64 *ate_reg;
++ u64 __iomem *ate_reg;
+ u64 addr;
+- struct tioce *ce_mmr;
++ struct tioce __iomem *ce_mmr;
+ u64 bus_base;
+ struct tioce_dmamap *map;
+
+- ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
++ ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base;
+
+ switch (type) {
+ case TIOCE_ATE_M32:
+@@ -386,7 +386,7 @@ tioce_dma_d32(struct pci_dev *pdev, u64
+ {
+ int dma_ok;
+ int port;
+- struct tioce *ce_mmr;
++ struct tioce __iomem *ce_mmr;
+ struct tioce_kernel *ce_kern;
+ u64 ct_upper;
+ u64 ct_lower;
+@@ -461,7 +461,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dm
+ int i;
+ int port;
+ struct tioce_kernel *ce_kern;
+- struct tioce *ce_mmr;
++ struct tioce __iomem *ce_mmr;
+ unsigned long flags;
+
+ bus_addr = tioce_dma_barrier(bus_addr, 0);
+@@ -666,12 +666,11 @@ tioce_dma_consistent(struct pci_dev *pde
+ * tioce_error_intr_handler - SGI TIO CE error interrupt handler
+ * @irq: unused
+ * @arg: pointer to tioce_common struct for the given CE
+- * @pt: unused
+ *
+ * Handle a CE error interrupt. Simply a wrapper around a SAL call which
+ * defers processing to the SGI prom.
+ */ static irqreturn_t
+-tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
++tioce_error_intr_handler(int irq, void *arg)
+ {
+ struct tioce_common *soft = arg;
+ struct ia64_sal_retval ret_stuff;
+@@ -701,9 +700,9 @@ static void
+ tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit)
+ {
+ int ate_index, last_ate, ps;
+- struct tioce *ce_mmr;
++ struct tioce __iomem *ce_mmr;
+
+- ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
++ ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base;
+ ps = ce_kern->ce_ate3240_pagesize;
+ ate_index = ATE_PAGE(base, ps);
+ last_ate = ate_index + ATE_NPAGES(base, limit-base+1, ps) - 1;
+@@ -737,7 +736,7 @@ tioce_kern_init(struct tioce_common *tio
+ int dev;
+ u32 tmp;
+ unsigned int seg, bus;
+- struct tioce *tioce_mmr;
++ struct tioce __iomem *tioce_mmr;
+ struct tioce_kernel *tioce_kern;
+
+ tioce_kern = kzalloc(sizeof(struct tioce_kernel), GFP_KERNEL);
+@@ -768,7 +767,7 @@ tioce_kern_init(struct tioce_common *tio
+ * the ate's.
+ */
+
+- tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
++ tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base;
+ tioce_mmr_clri(tioce_kern, &tioce_mmr->ce_ure_page_map,
+ CE_URE_PAGESIZE_MASK);
+ tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_ure_page_map,
+@@ -859,7 +858,7 @@ tioce_force_interrupt(struct sn_irq_info
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce_kernel *ce_kern;
+- struct tioce *ce_mmr;
++ struct tioce __iomem *ce_mmr;
+ u64 force_int_val;
+
+ if (!sn_irq_info->irq_bridge)
+@@ -873,7 +872,7 @@ tioce_force_interrupt(struct sn_irq_info
+ return;
+
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+- ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
++ ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
+ ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private;
+
+ /*
+@@ -954,7 +953,7 @@ tioce_target_interrupt(struct sn_irq_inf
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce_kernel *ce_kern;
+- struct tioce *ce_mmr;
++ struct tioce __iomem *ce_mmr;
+ int bit;
+ u64 vector;
+
+@@ -963,7 +962,7 @@ tioce_target_interrupt(struct sn_irq_inf
+ return;
+
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+- ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
++ ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
+ ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private;
+
+ bit = sn_irq_info->irq_int_bit;
+@@ -995,7 +994,7 @@ tioce_bus_fixup(struct pcibus_bussoft *p
+ cnodeid_t my_cnode, mem_cnode;
+ struct tioce_common *tioce_common;
+ struct tioce_kernel *tioce_kern;
+- struct tioce *tioce_mmr;
++ struct tioce __iomem *tioce_mmr;
+
+ /*
+ * Allocate kernel bus soft and copy from prom.
+@@ -1019,7 +1018,7 @@ tioce_bus_fixup(struct pcibus_bussoft *p
+ * interrupt handler.
+ */
+
+- tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
++ tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base;
+ tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL);
+ tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias,
+ ~0ULL);
+diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c
+index 3841861..f8d8650 100644
+--- a/arch/m32r/kernel/irq.c
++++ b/arch/m32r/kernel/irq.c
+@@ -77,13 +77,16 @@ skip:
+ */
+ asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+
+ #ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* FIXME M32R */
+ #endif
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+ irq_exit();
++ set_irq_regs(old_regs);
+
+ return 1;
+ }
+diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c
+index 3f35ab3..0e7778b 100644
+--- a/arch/m32r/kernel/setup.c
++++ b/arch/m32r/kernel/setup.c
+@@ -369,10 +369,10 @@ static void c_stop(struct seq_file *m, v
+ }
+
+ struct seq_operations cpuinfo_op = {
+- start: c_start,
+- next: c_next,
+- stop: c_stop,
+- show: show_cpuinfo,
++ .start = c_start,
++ .next = c_next,
++ .stop = c_stop,
++ .show = show_cpuinfo,
+ };
+ #endif /* CONFIG_PROC_FS */
+
+diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c
+index 67dbbdc..6b2d77d 100644
+--- a/arch/m32r/kernel/setup_mappi.c
++++ b/arch/m32r/kernel/setup_mappi.c
+@@ -86,7 +86,7 @@ void __init init_IRQ(void)
+ /* INT0 : LAN controller (RTL8019AS) */
+ irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_INT0].action = 0;
++ irq_desc[M32R_IRQ_INT0].action = NULL;
+ irq_desc[M32R_IRQ_INT0].depth = 1;
+ icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+ disable_mappi_irq(M32R_IRQ_INT0);
+@@ -95,7 +95,7 @@ void __init init_IRQ(void)
+ /* MFT2 : system timer */
+ irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_MFT2].action = 0;
++ irq_desc[M32R_IRQ_MFT2].action = NULL;
+ irq_desc[M32R_IRQ_MFT2].depth = 1;
+ icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+ disable_mappi_irq(M32R_IRQ_MFT2);
+@@ -104,7 +104,7 @@ void __init init_IRQ(void)
+ /* SIO0_R : uart receive data */
+ irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_SIO0_R].action = 0;
++ irq_desc[M32R_IRQ_SIO0_R].action = NULL;
+ irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+ disable_mappi_irq(M32R_IRQ_SIO0_R);
+@@ -112,7 +112,7 @@ void __init init_IRQ(void)
+ /* SIO0_S : uart send data */
+ irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_SIO0_S].action = 0;
++ irq_desc[M32R_IRQ_SIO0_S].action = NULL;
+ irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+ disable_mappi_irq(M32R_IRQ_SIO0_S);
+@@ -120,7 +120,7 @@ void __init init_IRQ(void)
+ /* SIO1_R : uart receive data */
+ irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_SIO1_R].action = 0;
++ irq_desc[M32R_IRQ_SIO1_R].action = NULL;
+ irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+ disable_mappi_irq(M32R_IRQ_SIO1_R);
+@@ -128,7 +128,7 @@ void __init init_IRQ(void)
+ /* SIO1_S : uart send data */
+ irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_SIO1_S].action = 0;
++ irq_desc[M32R_IRQ_SIO1_S].action = NULL;
+ irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+ disable_mappi_irq(M32R_IRQ_SIO1_S);
+@@ -138,7 +138,7 @@ void __init init_IRQ(void)
+ /* INT1 : pccard0 interrupt */
+ irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_INT1].action = 0;
++ irq_desc[M32R_IRQ_INT1].action = NULL;
+ irq_desc[M32R_IRQ_INT1].depth = 1;
+ icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
+ disable_mappi_irq(M32R_IRQ_INT1);
+@@ -146,7 +146,7 @@ void __init init_IRQ(void)
+ /* INT2 : pccard1 interrupt */
+ irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type;
+- irq_desc[M32R_IRQ_INT2].action = 0;
++ irq_desc[M32R_IRQ_INT2].action = NULL;
+ irq_desc[M32R_IRQ_INT2].depth = 1;
+ icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
+ disable_mappi_irq(M32R_IRQ_INT2);
+diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
+index a9174ef..b60cea4 100644
+--- a/arch/m32r/kernel/signal.c
++++ b/arch/m32r/kernel/signal.c
+@@ -33,7 +33,7 @@
+ int do_signal(struct pt_regs *, sigset_t *);
+
+ asmlinkage int
+-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
++sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
+ unsigned long r2, unsigned long r3, unsigned long r4,
+ unsigned long r5, unsigned long r6, struct pt_regs *regs)
+ {
+@@ -78,8 +78,8 @@ sys_sigaltstack(const stack_t __user *us
+ struct rt_sigframe
+ {
+ int sig;
+- struct siginfo *pinfo;
+- void *puc;
++ struct siginfo __user *pinfo;
++ void __user *puc;
+ struct siginfo info;
+ struct ucontext uc;
+ // struct _fpstate fpstate;
+diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
+index 8b1f6eb..3601291 100644
+--- a/arch/m32r/kernel/smp.c
++++ b/arch/m32r/kernel/smp.c
+@@ -101,7 +101,7 @@ void smp_call_function_interrupt(void);
+
+ void smp_send_timer(void);
+ void smp_ipi_timer_interrupt(struct pt_regs *);
+-void smp_local_timer_interrupt(struct pt_regs *);
++void smp_local_timer_interrupt(void);
+
+ void send_IPI_allbutself(int, int);
+ static void send_IPI_mask(cpumask_t, int, int);
+@@ -231,7 +231,7 @@ void smp_flush_tlb_all(void)
+ local_irq_save(flags);
+ __flush_tlb_all();
+ local_irq_restore(flags);
+- smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
++ smp_call_function(flush_tlb_all_ipi, NULL, 1, 1);
+ preempt_enable();
+ }
+
+@@ -734,9 +734,12 @@ void smp_send_timer(void)
+ *==========================================================================*/
+ void smp_ipi_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ /*==========================================================================*
+@@ -762,9 +765,9 @@ void smp_ipi_timer_interrupt(struct pt_r
+ * ---------- --- --------------------------------------------------------
+ * 2003-06-24 hy use per_cpu structure.
+ *==========================================================================*/
+-void smp_local_timer_interrupt(struct pt_regs *regs)
++void smp_local_timer_interrupt(void)
+ {
+- int user = user_mode(regs);
++ int user = user_mode(get_irq_regs());
+ int cpu_id = smp_processor_id();
+
+ /*
+@@ -774,7 +777,7 @@ void smp_local_timer_interrupt(struct pt
+ * useful with a profiling multiplier != 1
+ */
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+
+ if (--per_cpu(prof_counter, cpu_id) <= 0) {
+ /*
+diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
+index a9cea32..b4e7bcb 100644
+--- a/arch/m32r/kernel/sys_m32r.c
++++ b/arch/m32r/kernel/sys_m32r.c
+@@ -25,11 +25,13 @@
+ #include <asm/cachectl.h>
+ #include <asm/cacheflush.h>
+ #include <asm/ipc.h>
++#include <asm/syscall.h>
++#include <asm/unistd.h>
+
+ /*
+ * sys_tas() - test-and-set
+ */
+-asmlinkage int sys_tas(int *addr)
++asmlinkage int sys_tas(int __user *addr)
+ {
+ int oldval;
+
+@@ -88,7 +90,7 @@ sys_pipe(unsigned long r0, unsigned long
+
+ error = do_pipe(fd);
+ if (!error) {
+- if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int)))
++ if (copy_to_user((void __user *)r0, fd, 2*sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+@@ -199,13 +201,13 @@ asmlinkage int sys_ipc(uint call, int fi
+ }
+ }
+
+-asmlinkage int sys_uname(struct old_utsname * name)
++asmlinkage int sys_uname(struct old_utsname __user * name)
+ {
+ int err;
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+- err=copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ return err?-EFAULT:0;
+ }
+@@ -223,3 +225,21 @@ asmlinkage int sys_cachectl(char *addr,
+ return -ENOSYS;
+ }
+
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register long __scno __asm__ ("r7") = __NR_execve;
++ register long __arg3 __asm__ ("r2") = (long)(envp);
++ register long __arg2 __asm__ ("r1") = (long)(argv);
++ register long __res __asm__ ("r0") = (long)(filename);
++ __asm__ __volatile__ (
++ "trap #" SYSCALL_VECTOR "|| nop"
++ : "=r" (__res)
++ : "r" (__scno), "0" (__res), "r" (__arg2),
++ "r" (__arg3)
++ : "memory");
++ return __res;
++}
+diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c
+index ded0be0..a090382 100644
+--- a/arch/m32r/kernel/time.c
++++ b/arch/m32r/kernel/time.c
+@@ -35,10 +35,9 @@
+
+ #ifdef CONFIG_SMP
+ extern void send_IPI_allbutself(int, int);
+-extern void smp_local_timer_interrupt(struct pt_regs *);
++extern void smp_local_timer_interrupt(void);
+ #endif
+
+-extern unsigned long wall_jiffies;
+ #define TICK_SIZE (tick_nsec / 1000)
+
+ /*
+@@ -108,24 +107,17 @@ void do_gettimeofday(struct timeval *tv)
+ unsigned long max_ntp_tick = tick_usec - tickadj;
+
+ do {
+- unsigned long lost;
+-
+ seq = read_seqbegin(&xtime_lock);
+
+ usec = do_gettimeoffset();
+- lost = jiffies - wall_jiffies;
+
+ /*
+ * If time_adjust is negative then NTP is slowing the clock
+ * so make sure not to go into next possible interval.
+ * Better to lose some accuracy than have time go backwards..
+ */
+- if (unlikely(time_adjust < 0)) {
++ if (unlikely(time_adjust < 0))
+ usec = min(usec, max_ntp_tick);
+- if (lost)
+- usec += lost * max_ntp_tick;
+- } else if (unlikely(lost))
+- usec += lost * tick_usec;
+
+ sec = xtime.tv_sec;
+ usec += (xtime.tv_nsec / 1000);
+@@ -158,7 +150,6 @@ int do_settimeofday(struct timespec *tv)
+ * made, and then undo it!
+ */
+ nsec -= do_gettimeoffset() * NSEC_PER_USEC;
+- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+@@ -197,15 +188,15 @@ static long last_rtc_update = 0;
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t timer_interrupt(int irq, void *dev_id)
+ {
+ #ifndef CONFIG_SMP
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ #endif
+- do_timer(regs);
++ do_timer(1);
+
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ /*
+ * If we have an externally synchronized Linux clock, then update
+@@ -230,7 +221,7 @@ irqreturn_t timer_interrupt(int irq, voi
+ a hack, so don't look closely for now.. */
+
+ #ifdef CONFIG_SMP
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ smp_send_timer();
+ #endif
+
+diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
+index c1daf2c..97e0b1c 100644
+--- a/arch/m32r/kernel/traps.c
++++ b/arch/m32r/kernel/traps.c
+@@ -268,7 +268,7 @@ static __inline__ void do_trap(int trapn
+ #define DO_ERROR(trapnr, signr, str, name) \
+ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+ { \
+- do_trap(trapnr, signr, 0, regs, error_code, NULL); \
++ do_trap(trapnr, signr, NULL, regs, error_code, NULL); \
+ }
+
+ #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
+index 13c7bb6..358b9ce 100644
+--- a/arch/m32r/kernel/vmlinux.lds.S
++++ b/arch/m32r/kernel/vmlinux.lds.S
+@@ -83,13 +83,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
+index dc18a33..8d5f551 100644
+--- a/arch/m32r/mm/fault.c
++++ b/arch/m32r/mm/fault.c
+@@ -299,7 +299,7 @@ no_context:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (tsk->pid == 1) {
++ if (is_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
+index b71348f..bbd97c8 100644
+--- a/arch/m32r/mm/init.c
++++ b/arch/m32r/mm/init.c
+@@ -100,7 +100,7 @@ void free_initrd_mem(unsigned long, unsi
+ #ifndef CONFIG_DISCONTIGMEM
+ unsigned long __init zone_sizes_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+ unsigned long max_dma;
+ unsigned long low;
+ unsigned long start_pfn;
+diff --git a/arch/m32r/mm/ioremap.c b/arch/m32r/mm/ioremap.c
+index a151849..5152c4e 100644
+--- a/arch/m32r/mm/ioremap.c
++++ b/arch/m32r/mm/ioremap.c
+@@ -20,92 +20,8 @@
+ #include <asm/byteorder.h>
+
+ #include <linux/vmalloc.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <asm/pgalloc.h>
+-#include <asm/cacheflush.h>
+-#include <asm/tlbflush.h>
+-
+-static inline void
+-remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+- unsigned long pfn;
+- pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
+- | _PAGE_WRITE | flags);
+-
+- address &= ~PMD_MASK;
+- end = address + size;
+- if (end > PMD_SIZE)
+- end = PMD_SIZE;
+- if (address >= end)
+- BUG();
+- pfn = phys_addr >> PAGE_SHIFT;
+- do {
+- if (!pte_none(*pte)) {
+- printk("remap_area_pte: page already exists\n");
+- BUG();
+- }
+- set_pte(pte, pfn_pte(pfn, pgprot));
+- address += PAGE_SIZE;
+- pfn++;
+- pte++;
+- } while (address && (address < end));
+-}
+-
+-static inline int
+-remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+-
+- address &= ~PGDIR_MASK;
+- end = address + size;
+- if (end > PGDIR_SIZE)
+- end = PGDIR_SIZE;
+- phys_addr -= address;
+- if (address >= end)
+- BUG();
+- do {
+- pte_t * pte = pte_alloc_kernel(pmd, address);
+- if (!pte)
+- return -ENOMEM;
+- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+- address = (address + PMD_SIZE) & PMD_MASK;
+- pmd++;
+- } while (address && (address < end));
+- return 0;
+-}
+-
+-static int
+-remap_area_pages(unsigned long address, unsigned long phys_addr,
+- unsigned long size, unsigned long flags)
+-{
+- int error;
+- pgd_t * dir;
+- unsigned long end = address + size;
+-
+- phys_addr -= address;
+- dir = pgd_offset(&init_mm, address);
+- flush_cache_all();
+- if (address >= end)
+- BUG();
+- do {
+- pmd_t *pmd;
+- pmd = pmd_alloc(&init_mm, dir, address);
+- error = -ENOMEM;
+- if (!pmd)
+- break;
+- if (remap_area_pmd(pmd, address, end - address,
+- phys_addr + address, flags))
+- break;
+- error = 0;
+- address = (address + PGDIR_SIZE) & PGDIR_MASK;
+- dir++;
+- } while (address && (address < end));
+- flush_tlb_all();
+- return error;
+-}
+
+ /*
+ * Generic mapping function (not visible outside):
+@@ -129,6 +45,7 @@ __ioremap(unsigned long phys_addr, unsig
+ void __iomem * addr;
+ struct vm_struct * area;
+ unsigned long offset, last_addr;
++ pgprot_t pgprot;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+@@ -157,6 +74,9 @@ __ioremap(unsigned long phys_addr, unsig
+ return NULL;
+ }
+
++ pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
++ | _PAGE_WRITE | flags);
++
+ /*
+ * Mappings have to be page-aligned
+ */
+@@ -172,7 +92,8 @@ __ioremap(unsigned long phys_addr, unsig
+ return NULL;
+ area->phys_addr = phys_addr;
+ addr = (void __iomem *) area->addr;
+- if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) {
++ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
++ phys_addr, pgprot)) {
+ vunmap((void __force *) addr);
+ return NULL;
+ }
+diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S
+index 0c28f11..9a4d40b 100644
+--- a/arch/m32r/mm/mmu.S
++++ b/arch/m32r/mm/mmu.S
+@@ -6,7 +6,6 @@
+
+ /* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */
+
+-#include <linux/config.h> /* CONFIG_MMU */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+ #include <asm/smp.h>
+diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
+index 805b81f..7bc1446 100644
+--- a/arch/m68k/Kconfig
++++ b/arch/m68k/Kconfig
+@@ -600,7 +600,7 @@ config MVME147_SCC
+
+ config SERIAL167
+ bool "CD2401 support for MVME166/7 serial ports"
+- depends on MVME16x && BROKEN
++ depends on MVME16x
+ help
+ This is the driver for the serial ports on the Motorola MVME166,
+ 167, and 172 boards. Everyone using one of these boards should say
+diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
+index 96c79d8..28d95cf 100644
+--- a/arch/m68k/amiga/amiints.c
++++ b/arch/m68k/amiga/amiints.c
+@@ -47,10 +47,10 @@
+
+ static void amiga_enable_irq(unsigned int irq);
+ static void amiga_disable_irq(unsigned int irq);
+-static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp);
+-static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp);
+-static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp);
+-static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp);
++static irqreturn_t ami_int1(int irq, void *dev_id);
++static irqreturn_t ami_int3(int irq, void *dev_id);
++static irqreturn_t ami_int4(int irq, void *dev_id);
++static irqreturn_t ami_int5(int irq, void *dev_id);
+
+ static struct irq_controller amiga_irq_controller = {
+ .name = "amiga",
+@@ -113,98 +113,98 @@ static void amiga_disable_irq(unsigned i
+ * The builtin Amiga hardware interrupt handlers.
+ */
+
+-static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t ami_int1(int irq, void *dev_id)
+ {
+ unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+ /* if serial transmit buffer empty, interrupt */
+ if (ints & IF_TBE) {
+ amiga_custom.intreq = IF_TBE;
+- m68k_handle_int(IRQ_AMIGA_TBE, fp);
++ m68k_handle_int(IRQ_AMIGA_TBE);
+ }
+
+ /* if floppy disk transfer complete, interrupt */
+ if (ints & IF_DSKBLK) {
+ amiga_custom.intreq = IF_DSKBLK;
+- m68k_handle_int(IRQ_AMIGA_DSKBLK, fp);
++ m68k_handle_int(IRQ_AMIGA_DSKBLK);
+ }
+
+ /* if software interrupt set, interrupt */
+ if (ints & IF_SOFT) {
+ amiga_custom.intreq = IF_SOFT;
+- m68k_handle_int(IRQ_AMIGA_SOFT, fp);
++ m68k_handle_int(IRQ_AMIGA_SOFT);
+ }
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t ami_int3(int irq, void *dev_id)
+ {
+ unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+ /* if a blitter interrupt */
+ if (ints & IF_BLIT) {
+ amiga_custom.intreq = IF_BLIT;
+- m68k_handle_int(IRQ_AMIGA_BLIT, fp);
++ m68k_handle_int(IRQ_AMIGA_BLIT);
+ }
+
+ /* if a copper interrupt */
+ if (ints & IF_COPER) {
+ amiga_custom.intreq = IF_COPER;
+- m68k_handle_int(IRQ_AMIGA_COPPER, fp);
++ m68k_handle_int(IRQ_AMIGA_COPPER);
+ }
+
+ /* if a vertical blank interrupt */
+ if (ints & IF_VERTB) {
+ amiga_custom.intreq = IF_VERTB;
+- m68k_handle_int(IRQ_AMIGA_VERTB, fp);
++ m68k_handle_int(IRQ_AMIGA_VERTB);
+ }
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t ami_int4(int irq, void *dev_id)
+ {
+ unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+ /* if audio 0 interrupt */
+ if (ints & IF_AUD0) {
+ amiga_custom.intreq = IF_AUD0;
+- m68k_handle_int(IRQ_AMIGA_AUD0, fp);
++ m68k_handle_int(IRQ_AMIGA_AUD0);
+ }
+
+ /* if audio 1 interrupt */
+ if (ints & IF_AUD1) {
+ amiga_custom.intreq = IF_AUD1;
+- m68k_handle_int(IRQ_AMIGA_AUD1, fp);
++ m68k_handle_int(IRQ_AMIGA_AUD1);
+ }
+
+ /* if audio 2 interrupt */
+ if (ints & IF_AUD2) {
+ amiga_custom.intreq = IF_AUD2;
+- m68k_handle_int(IRQ_AMIGA_AUD2, fp);
++ m68k_handle_int(IRQ_AMIGA_AUD2);
+ }
+
+ /* if audio 3 interrupt */
+ if (ints & IF_AUD3) {
+ amiga_custom.intreq = IF_AUD3;
+- m68k_handle_int(IRQ_AMIGA_AUD3, fp);
++ m68k_handle_int(IRQ_AMIGA_AUD3);
+ }
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t ami_int5(int irq, void *dev_id)
+ {
+ unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+ /* if serial receive buffer full interrupt */
+ if (ints & IF_RBF) {
+ /* acknowledge of IF_RBF must be done by the serial interrupt */
+- m68k_handle_int(IRQ_AMIGA_RBF, fp);
++ m68k_handle_int(IRQ_AMIGA_RBF);
+ }
+
+ /* if a disk sync interrupt */
+ if (ints & IF_DSKSYN) {
+ amiga_custom.intreq = IF_DSKSYN;
+- m68k_handle_int(IRQ_AMIGA_DSKSYN, fp);
++ m68k_handle_int(IRQ_AMIGA_DSKSYN);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
+index dbad300..7a20058 100644
+--- a/arch/m68k/amiga/cia.c
++++ b/arch/m68k/amiga/cia.c
+@@ -82,7 +82,7 @@ unsigned char cia_able_irq(struct ciabas
+ return old;
+ }
+
+-static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t cia_handler(int irq, void *dev_id)
+ {
+ struct ciabase *base = (struct ciabase *)dev_id;
+ int mach_irq;
+@@ -93,7 +93,7 @@ static irqreturn_t cia_handler(int irq,
+ amiga_custom.intreq = base->int_mask;
+ for (; ints; mach_irq++, ints >>= 1) {
+ if (ints & 1)
+- m68k_handle_int(mach_irq, fp);
++ m68k_handle_int(mach_irq);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
+index 092e50d..3204f41 100644
+--- a/arch/m68k/amiga/config.c
++++ b/arch/m68k/amiga/config.c
+@@ -83,7 +83,7 @@ static char amiga_model_name[13] = "Amig
+
+ extern char m68k_debug_device[];
+
+-static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++static void amiga_sched_init(irq_handler_t handler);
+ /* amiga specific irq functions */
+ extern void amiga_init_IRQ (void);
+ static void amiga_get_model(char *model);
+@@ -487,8 +487,7 @@ void __init config_amiga(void)
+
+ static unsigned short jiffy_ticks;
+
+-static void __init amiga_sched_init(irqreturn_t (*timer_routine)(int, void *,
+- struct pt_regs *))
++static void __init amiga_sched_init(irq_handler_t timer_routine)
+ {
+ static struct resource sched_res = {
+ .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
+diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
+index 6f45815..cb8e760 100644
+--- a/arch/m68k/apollo/config.c
++++ b/arch/m68k/apollo/config.c
+@@ -25,7 +25,7 @@ u_long cpuctrl_physaddr;
+ u_long timer_physaddr;
+ u_long apollo_model;
+
+-extern void dn_sched_init(irqreturn_t (*handler)(int,void *,struct pt_regs *));
++extern void dn_sched_init(irq_handler_t handler);
+ extern void dn_init_IRQ(void);
+ extern unsigned long dn_gettimeoffset(void);
+ extern int dn_dummy_hwclk(int, struct rtc_time *);
+@@ -38,7 +38,7 @@ extern irqreturn_t dn_process_int(int ir
+ #ifdef CONFIG_HEARTBEAT
+ static void dn_heartbeat(int on);
+ #endif
+-static irqreturn_t dn_timer_int(int irq,void *, struct pt_regs *);
++static irqreturn_t dn_timer_int(int irq,void *);
+ static void dn_get_model(char *model);
+ static const char *apollo_models[] = {
+ [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)",
+@@ -174,13 +174,13 @@ void config_apollo(void) {
+
+ }
+
+-irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp)
++irqreturn_t dn_timer_int(int irq, void *dev_id)
+ {
+- irqreturn_t (*timer_handler)(int, void *, struct pt_regs *) = dev_id;
++ irq_handler_t timer_handler = dev_id;
+
+ volatile unsigned char x;
+
+- timer_handler(irq, dev_id, fp);
++ timer_handler(irq, dev_id);
+
+ x=*(volatile unsigned char *)(timer+3);
+ x=*(volatile unsigned char *)(timer+5);
+@@ -188,8 +188,8 @@ irqreturn_t dn_timer_int(int irq, void *
+ return IRQ_HANDLED;
+ }
+
+-void dn_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) {
+-
++void dn_sched_init(irq_handler_t timer_routine)
++{
+ /* program timer 1 */
+ *(volatile unsigned char *)(timer+3)=0x01;
+ *(volatile unsigned char *)(timer+1)=0x40;
+diff --git a/arch/m68k/apollo/dma.c b/arch/m68k/apollo/dma.c
+deleted file mode 100644
+index aed8be1..0000000
+--- a/arch/m68k/apollo/dma.c
++++ /dev/null
+@@ -1,50 +0,0 @@
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/kd.h>
+-#include <linux/tty.h>
+-#include <linux/console.h>
+-
+-#include <asm/setup.h>
+-#include <asm/bootinfo.h>
+-#include <asm/system.h>
+-#include <asm/pgtable.h>
+-#include <asm/apollodma.h>
+-#include <asm/io.h>
+-
+-/* note only works for 16 Bit 1 page DMA's */
+-
+-static unsigned short next_free_xlat_entry=0;
+-
+-unsigned short dma_map_page(unsigned long phys_addr,int count,int type) {
+-
+- unsigned long page_aligned_addr=phys_addr & (~((1<<12)-1));
+- unsigned short start_map_addr=page_aligned_addr >> 10;
+- unsigned short free_xlat_entry, *xlat_map_entry;
+- int i;
+-
+- free_xlat_entry=next_free_xlat_entry;
+- for(i=0,xlat_map_entry=addr_xlat_map+(free_xlat_entry<<2);i<8;i++,xlat_map_entry++) {
+-#if 0
+- printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i);
+-#endif
+- out_be16(xlat_map_entry, start_map_addr+i);
+- }
+-
+- next_free_xlat_entry+=2;
+- if(next_free_xlat_entry>125)
+- next_free_xlat_entry=0;
+-
+-#if 0
+- printk("next_free_xlat_entry: %d\n",next_free_xlat_entry);
+-#endif
+-
+- return free_xlat_entry<<10;
+-}
+-
+-void dma_unmap_page(unsigned short dma_addr) {
+-
+- return ;
+-
+-}
+-
+diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
+index 9fe0780..4274af1 100644
+--- a/arch/m68k/apollo/dn_ints.c
++++ b/arch/m68k/apollo/dn_ints.c
+@@ -6,7 +6,7 @@
+
+ void dn_process_int(unsigned int irq, struct pt_regs *fp)
+ {
+- m68k_handle_int(irq, fp);
++ __m68k_handle_int(irq, fp);
+
+ *(volatile unsigned char *)(pica)=0x20;
+ *(volatile unsigned char *)(picb)=0x20;
+diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
+index ece13cb..7f81264 100644
+--- a/arch/m68k/atari/ataints.c
++++ b/arch/m68k/atari/ataints.c
+@@ -332,6 +332,9 @@ static void atari_shutdown_irq(unsigned
+ atari_disable_irq(irq);
+ atari_turnoff_irq(irq);
+ m68k_irq_shutdown(irq);
++
++ if (irq == IRQ_AUTO_4)
++ vectors[VEC_INT4] = falcon_hblhandler;
+ }
+
+ static struct irq_controller atari_irq_controller = {
+@@ -356,7 +359,7 @@ static struct irq_controller atari_irq_c
+
+ void __init atari_init_IRQ(void)
+ {
+- m68k_setup_user_interrupt(VEC_USER, 192, NULL);
++ m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL);
+ m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
+
+ /* Initialize the MFP(s) */
+@@ -403,8 +406,10 @@ void __init atari_init_IRQ(void)
+ * gets overruns)
+ */
+
+- if (!MACH_IS_HADES)
++ if (!MACH_IS_HADES) {
+ vectors[VEC_INT2] = falcon_hblhandler;
++ vectors[VEC_INT4] = falcon_hblhandler;
++ }
+ }
+
+ if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
+diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
+index b207925..ca5cd43 100644
+--- a/arch/m68k/atari/config.c
++++ b/arch/m68k/atari/config.c
+@@ -62,7 +62,7 @@ static void atari_heartbeat( int on );
+ #endif
+
+ /* atari specific timer functions (in time.c) */
+-extern void atari_sched_init(irqreturn_t (*)(int, void *, struct pt_regs *));
++extern void atari_sched_init(irq_handler_t );
+ extern unsigned long atari_gettimeoffset (void);
+ extern int atari_mste_hwclk (int, struct rtc_time *);
+ extern int atari_tt_hwclk (int, struct rtc_time *);
+diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
+index 288f5e6..d64b580 100644
+--- a/arch/m68k/atari/stdma.c
++++ b/arch/m68k/atari/stdma.c
+@@ -44,7 +44,7 @@
+
+ static int stdma_locked; /* the semaphore */
+ /* int func to be called */
+-static irqreturn_t (*stdma_isr)(int, void *, struct pt_regs *);
++static irq_handler_t stdma_isr;
+ static void *stdma_isr_data; /* data passed to isr */
+ static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */
+
+@@ -53,7 +53,7 @@ static DECLARE_WAIT_QUEUE_HEAD(stdma_wai
+
+ /***************************** Prototypes *****************************/
+
+-static irqreturn_t stdma_int (int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t stdma_int (int irq, void *dummy);
+
+ /************************* End of Prototypes **************************/
+
+@@ -75,8 +75,7 @@ static irqreturn_t stdma_int (int irq, v
+ *
+ */
+
+-void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *),
+- void *data)
++void stdma_lock(irq_handler_t handler, void *data)
+ {
+ unsigned long flags;
+
+@@ -188,9 +187,9 @@ void __init stdma_init(void)
+ *
+ */
+
+-static irqreturn_t stdma_int(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t stdma_int(int irq, void *dummy)
+ {
+ if (stdma_isr)
+- (*stdma_isr)(irq, stdma_isr_data, fp);
++ (*stdma_isr)(irq, stdma_isr_data);
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
+index e79bbc9..e0d3c8b 100644
+--- a/arch/m68k/atari/time.c
++++ b/arch/m68k/atari/time.c
+@@ -16,11 +16,12 @@
+ #include <linux/init.h>
+ #include <linux/rtc.h>
+ #include <linux/bcd.h>
++#include <linux/delay.h>
+
+ #include <asm/atariints.h>
+
+ void __init
+-atari_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
++atari_sched_init(irq_handler_t timer_routine)
+ {
+ /* set Timer C data Register */
+ mfp.tim_dt_c = INT_TICKS;
+@@ -212,8 +213,12 @@ int atari_tt_hwclk( int op, struct rtc_t
+ * additionally the RTC_SET bit is set to prevent an update cycle.
+ */
+
+- while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP )
+- schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
++ while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
++ if (in_atomic() || irqs_disabled())
++ mdelay(1);
++ else
++ schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
++ }
+
+ local_irq_save(flags);
+ RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
+diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
+index d1e916a..896ae3d 100644
+--- a/arch/m68k/bvme6000/config.c
++++ b/arch/m68k/bvme6000/config.c
+@@ -38,7 +38,7 @@
+
+ static void bvme6000_get_model(char *model);
+ static int bvme6000_get_hardware_list(char *buffer);
+-extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void bvme6000_sched_init(irq_handler_t handler);
+ extern unsigned long bvme6000_gettimeoffset (void);
+ extern int bvme6000_hwclk (int, struct rtc_time *);
+ extern int bvme6000_set_clock_mmss (unsigned long);
+@@ -52,7 +52,7 @@ static unsigned char bin2bcd (unsigned c
+ /* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via bvme6000_process_int() */
+
+-static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *);
++static irq_handler_t tick_handler;
+
+
+ int bvme6000_parse_bootinfo(const struct bi_record *bi)
+@@ -154,7 +154,7 @@ void __init config_bvme6000(void)
+ }
+
+
+-irqreturn_t bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
++irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
+ {
+ unsigned long *new = (unsigned long *)vectors;
+ unsigned long *old = (unsigned long *)0xf8000000;
+@@ -171,14 +171,14 @@ irqreturn_t bvme6000_abort_int (int irq,
+ }
+
+
+-static irqreturn_t bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
+ {
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+
+ rtc->msr = msr | 0x20; /* Ack the interrupt */
+
+- return tick_handler(irq, dev_id, fp);
++ return tick_handler(irq, dev_id);
+ }
+
+ /*
+@@ -190,7 +190,7 @@ static irqreturn_t bvme6000_timer_int (i
+ * so divide by 8 to get the microsecond result.
+ */
+
+-void bvme6000_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
++void bvme6000_sched_init (irq_handler_t timer_routine)
+ {
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
+index 7df0566..dd7c8a2 100644
+--- a/arch/m68k/hp300/time.c
++++ b/arch/m68k/hp300/time.c
+@@ -36,15 +36,15 @@
+
+ #define INTVAL ((10000 / 4) - 1)
+
+-static irqreturn_t hp300_tick(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hp300_tick(int irq, void *dev_id)
+ {
+ unsigned long tmp;
+- irqreturn_t (*vector)(int, void *, struct pt_regs *) = dev_id;
++ irq_handler_t vector = dev_id;
+ in_8(CLOCKBASE + CLKSR);
+ asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
+ /* Turn off the network and SCSI leds */
+ blinken_leds(0, 0xe0);
+- return vector(irq, NULL, regs);
++ return vector(irq, NULL);
+ }
+
+ unsigned long hp300_gettimeoffset(void)
+@@ -63,7 +63,7 @@ unsigned long hp300_gettimeoffset(void)
+ return (USECS_PER_JIFFY * ticks) / INTVAL;
+ }
+
+-void __init hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
++void __init hp300_sched_init(irq_handler_t vector)
+ {
+ out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */
+ out_8(CLOCKBASE + CLKCR1, 0x1); /* reset */
+diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h
+index 8ef9987..f5b3d09 100644
+--- a/arch/m68k/hp300/time.h
++++ b/arch/m68k/hp300/time.h
+@@ -1,4 +1,4 @@
+-extern void hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *));
++extern void hp300_sched_init(irq_handler_t vector);
+ extern unsigned long hp300_gettimeoffset (void);
+
+
+diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
+index dae6097..1c9ecaa 100644
+--- a/arch/m68k/kernel/Makefile
++++ b/arch/m68k/kernel/Makefile
+@@ -9,10 +9,11 @@ else
+ endif
+ extra-y += vmlinux.lds
+
+-obj-y := entry.o process.o traps.o ints.o dma.o signal.o ptrace.o \
++obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \
+ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
+
+ obj-$(CONFIG_PCI) += bios32.o
+ obj-$(CONFIG_MODULES) += module.o
++obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
+
+ EXTRA_AFLAGS := -traditional
+diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
+index fc449f8..9d4e4b5 100644
+--- a/arch/m68k/kernel/dma.c
++++ b/arch/m68k/kernel/dma.c
+@@ -15,7 +15,7 @@
+ #include <asm/scatterlist.h>
+
+ void *dma_alloc_coherent(struct device *dev, size_t size,
+- dma_addr_t *handle, int flag)
++ dma_addr_t *handle, gfp_t flag)
+ {
+ struct page *page, **map;
+ pgprot_t pgprot;
+@@ -51,7 +51,7 @@ void *dma_alloc_coherent(struct device *
+ pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
+ else
+ pgprot_val(pgprot) |= _PAGE_NOCACHE030;
+- addr = vmap(map, size, flag, pgprot);
++ addr = vmap(map, size, VM_MAP, pgprot);
+ kfree(map);
+
+ return addr;
+diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
+index 9083c8b..222ce42 100644
+--- a/arch/m68k/kernel/entry.S
++++ b/arch/m68k/kernel/entry.S
+@@ -205,7 +205,7 @@ ENTRY(auto_inthandler)
+ movel %sp,%sp at -
+ movel %d0,%sp at - | put vector # on stack
+ auto_irqhandler_fixup = . + 2
+- jsr m68k_handle_int | process the IRQ
++ jsr __m68k_handle_int | process the IRQ
+ addql #8,%sp | pop parameters off stack
+
+ ret_from_interrupt:
+@@ -239,7 +239,7 @@ user_irqvec_fixup = . + 2
+ movel %sp,%sp at -
+ movel %d0,%sp at - | put vector # on stack
+ user_irqhandler_fixup = . + 2
+- jsr m68k_handle_int | process the IRQ
++ jsr __m68k_handle_int | process the IRQ
+ addql #8,%sp | pop parameters off stack
+
+ subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+@@ -706,4 +706,33 @@ sys_call_table:
+ .long sys_add_key
+ .long sys_request_key /* 280 */
+ .long sys_keyctl
++ .long sys_ioprio_set
++ .long sys_ioprio_get
++ .long sys_inotify_init
++ .long sys_inotify_add_watch /* 285 */
++ .long sys_inotify_rm_watch
++ .long sys_migrate_pages
++ .long sys_openat
++ .long sys_mkdirat
++ .long sys_mknodat /* 290 */
++ .long sys_fchownat
++ .long sys_futimesat
++ .long sys_fstatat64
++ .long sys_unlinkat
++ .long sys_renameat /* 295 */
++ .long sys_linkat
++ .long sys_symlinkat
++ .long sys_readlinkat
++ .long sys_fchmodat
++ .long sys_faccessat /* 300 */
++ .long sys_ni_syscall /* Reserved for pselect6 */
++ .long sys_ni_syscall /* Reserved for ppoll */
++ .long sys_unshare
++ .long sys_set_robust_list
++ .long sys_get_robust_list /* 305 */
++ .long sys_splice
++ .long sys_sync_file_range
++ .long sys_tee
++ .long sys_vmsplice
++ .long sys_move_pages /* 310 */
+
+diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
+index b33e37f..84aceca 100644
+--- a/arch/m68k/kernel/ints.c
++++ b/arch/m68k/kernel/ints.c
+@@ -39,6 +39,7 @@
+ #include <asm/page.h>
+ #include <asm/machdep.h>
+ #include <asm/cacheflush.h>
++#include <asm/irq_regs.h>
+
+ #ifdef CONFIG_Q40
+ #include <asm/q40ints.h>
+@@ -104,7 +105,7 @@ void __init init_IRQ(void)
+ * @handler: called from auto vector interrupts
+ *
+ * setup the handler to be called from auto vector interrupts instead of the
+- * standard m68k_handle_int(), it will be called with irq numbers in the range
++ * standard __m68k_handle_int(), it will be called with irq numbers in the range
+ * from IRQ_AUTO_1 - IRQ_AUTO_7.
+ */
+ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
+@@ -123,7 +124,7 @@ void __init m68k_setup_auto_interrupt(vo
+ * setup user vector interrupts, this includes activating the specified range
+ * of interrupts, only then these interrupts can be requested (note: this is
+ * different from auto vector interrupts). An optional handler can be installed
+- * to be called instead of the default m68k_handle_int(), it will be called
++ * to be called instead of the default __m68k_handle_int(), it will be called
+ * with irq numbers starting from IRQ_USER.
+ */
+ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+@@ -131,6 +132,7 @@ void __init m68k_setup_user_interrupt(un
+ {
+ int i;
+
++ BUG_ON(IRQ_USER + cnt >= NR_IRQS);
+ m68k_first_user_vec = vec;
+ for (i = 0; i < cnt; i++)
+ irq_controller[IRQ_USER + i] = &user_irq_controller;
+@@ -215,7 +217,7 @@ int setup_irq(unsigned int irq, struct i
+ }
+
+ int request_irq(unsigned int irq,
+- irqreturn_t (*handler) (int, void *, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long flags, const char *devname, void *dev_id)
+ {
+ struct irq_node *node;
+@@ -379,18 +381,25 @@ unsigned int irq_canonicalize(unsigned i
+
+ EXPORT_SYMBOL(irq_canonicalize);
+
+-asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs)
++asmlinkage void m68k_handle_int(unsigned int irq)
+ {
+ struct irq_node *node;
+-
+ kstat_cpu(0).irqs[irq]++;
+ node = irq_list[irq];
+ do {
+- node->handler(irq, node->dev_id, regs);
++ node->handler(irq, node->dev_id);
+ node = node->next;
+ } while (node);
+ }
+
++asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs)
++{
++ struct pt_regs *old_regs;
++ old_regs = set_irq_regs(regs);
++ m68k_handle_int(irq);
++ set_irq_regs(old_regs);
++}
++
+ asmlinkage void handle_badint(struct pt_regs *regs)
+ {
+ kstat_cpu(0).irqs[0]++;
+diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
+index aff26a5..6fc69c7 100644
+--- a/arch/m68k/kernel/m68k_ksyms.c
++++ b/arch/m68k/kernel/m68k_ksyms.c
+@@ -1,65 +1,10 @@
+ #include <linux/module.h>
+-#include <linux/linkage.h>
+-#include <linux/sched.h>
+-#include <linux/string.h>
+-#include <linux/mm.h>
+-#include <linux/user.h>
+-#include <linux/elfcore.h>
+-#include <linux/in6.h>
+-#include <linux/interrupt.h>
+-
+-#include <asm/setup.h>
+-#include <asm/machdep.h>
+-#include <asm/pgalloc.h>
+-#include <asm/irq.h>
+-#include <asm/io.h>
+ #include <asm/semaphore.h>
+-#include <asm/checksum.h>
+
+ asmlinkage long long __ashldi3 (long long, int);
+ asmlinkage long long __ashrdi3 (long long, int);
+ asmlinkage long long __lshrdi3 (long long, int);
+ asmlinkage long long __muldi3 (long long, long long);
+-extern char m68k_debug_device[];
+-
+-/* platform dependent support */
+-
+-EXPORT_SYMBOL(m68k_machtype);
+-EXPORT_SYMBOL(m68k_cputype);
+-EXPORT_SYMBOL(m68k_is040or060);
+-EXPORT_SYMBOL(m68k_realnum_memory);
+-EXPORT_SYMBOL(m68k_memory);
+-#ifndef CONFIG_SUN3
+-EXPORT_SYMBOL(cache_push);
+-EXPORT_SYMBOL(cache_clear);
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-EXPORT_SYMBOL(mm_vtop);
+-EXPORT_SYMBOL(mm_ptov);
+-EXPORT_SYMBOL(mm_end_of_chunk);
+-#else
+-EXPORT_SYMBOL(m68k_memoffset);
+-#endif /* !CONFIG_SINGLE_MEMORY_CHUNK */
+-EXPORT_SYMBOL(__ioremap);
+-EXPORT_SYMBOL(iounmap);
+-EXPORT_SYMBOL(kernel_set_cachemode);
+-#endif /* !CONFIG_SUN3 */
+-EXPORT_SYMBOL(m68k_debug_device);
+-EXPORT_SYMBOL(mach_hwclk);
+-EXPORT_SYMBOL(mach_get_ss);
+-EXPORT_SYMBOL(mach_get_rtc_pll);
+-EXPORT_SYMBOL(mach_set_rtc_pll);
+-#ifdef CONFIG_INPUT_M68K_BEEP_MODULE
+-EXPORT_SYMBOL(mach_beep);
+-#endif
+-EXPORT_SYMBOL(dump_fpu);
+-EXPORT_SYMBOL(dump_thread);
+-EXPORT_SYMBOL(strnlen);
+-EXPORT_SYMBOL(strrchr);
+-EXPORT_SYMBOL(strstr);
+-EXPORT_SYMBOL(kernel_thread);
+-#ifdef CONFIG_VME
+-EXPORT_SYMBOL(vme_brdtype);
+-#endif
+
+ /* The following are special because they're not called
+ explicitly (the C compiler generates them). Fortunately,
+diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
+index 45a4664..99fc122 100644
+--- a/arch/m68k/kernel/process.c
++++ b/arch/m68k/kernel/process.c
+@@ -187,6 +187,7 @@ int kernel_thread(int (*fn)(void *), voi
+ set_fs (fs);
+ return pid;
+ }
++EXPORT_SYMBOL(kernel_thread);
+
+ void flush_thread(void)
+ {
+@@ -221,13 +222,13 @@ asmlinkage int m68k_clone(struct pt_regs
+ {
+ unsigned long clone_flags;
+ unsigned long newsp;
+- int *parent_tidptr, *child_tidptr;
++ int __user *parent_tidptr, *child_tidptr;
+
+ /* syscall2 puts clone_flags in d1 and usp in d2 */
+ clone_flags = regs->d1;
+ newsp = regs->d2;
+- parent_tidptr = (int *)regs->d3;
+- child_tidptr = (int *)regs->d4;
++ parent_tidptr = (int __user *)regs->d3;
++ child_tidptr = (int __user *)regs->d4;
+ if (!newsp)
+ newsp = rdusp();
+ return do_fork(clone_flags, newsp, regs, 0,
+@@ -311,6 +312,7 @@ int dump_fpu (struct pt_regs *regs, stru
+ : "memory");
+ return 1;
+ }
++EXPORT_SYMBOL(dump_fpu);
+
+ /*
+ * fill in the user structure for a core dump..
+@@ -357,11 +359,12 @@ void dump_thread(struct pt_regs * regs,
+ /* dump floating point stuff */
+ dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp);
+ }
++EXPORT_SYMBOL(dump_thread);
+
+ /*
+ * sys_execve() executes a new program.
+ */
+-asmlinkage int sys_execve(char *name, char **argv, char **envp)
++asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
+ {
+ int error;
+ char * filename;
+diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
+index f2d7ee0..9af3ee0 100644
+--- a/arch/m68k/kernel/setup.c
++++ b/arch/m68k/kernel/setup.c
+@@ -42,29 +42,39 @@
+
+ unsigned long m68k_machtype;
+ unsigned long m68k_cputype;
++EXPORT_SYMBOL(m68k_machtype);
++EXPORT_SYMBOL(m68k_cputype);
+ unsigned long m68k_fputype;
+ unsigned long m68k_mmutype;
+ #ifdef CONFIG_VME
+ unsigned long vme_brdtype;
++EXPORT_SYMBOL(vme_brdtype);
+ #endif
+
+ int m68k_is040or060;
++EXPORT_SYMBOL(m68k_is040or060);
+
+ extern int end;
+ extern unsigned long availmem;
+
+ int m68k_num_memory;
+ int m68k_realnum_memory;
++EXPORT_SYMBOL(m68k_realnum_memory);
++#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+ unsigned long m68k_memoffset;
++EXPORT_SYMBOL(m68k_memoffset);
++#endif
+ struct mem_info m68k_memory[NUM_MEMINFO];
++EXPORT_SYMBOL(m68k_memory);
+
+ static struct mem_info m68k_ramdisk;
+
+ static char m68k_command_line[CL_SIZE];
+
+ char m68k_debug_device[6] = "";
++EXPORT_SYMBOL(m68k_debug_device);
+
+-void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
++void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
+ /* machine dependent irq functions */
+ void (*mach_init_IRQ) (void) __initdata = NULL;
+ void (*mach_get_model) (char *model);
+@@ -72,10 +82,14 @@ int (*mach_get_hardware_list) (char *buf
+ /* machine dependent timer functions */
+ unsigned long (*mach_gettimeoffset) (void);
+ int (*mach_hwclk) (int, struct rtc_time*);
++EXPORT_SYMBOL(mach_hwclk);
+ int (*mach_set_clock_mmss) (unsigned long);
+ unsigned int (*mach_get_ss)(void);
+ int (*mach_get_rtc_pll)(struct rtc_pll_info *);
+ int (*mach_set_rtc_pll)(struct rtc_pll_info *);
++EXPORT_SYMBOL(mach_get_ss);
++EXPORT_SYMBOL(mach_get_rtc_pll);
++EXPORT_SYMBOL(mach_set_rtc_pll);
+ void (*mach_reset)( void );
+ void (*mach_halt)( void );
+ void (*mach_power_off)( void );
+@@ -89,6 +103,7 @@ void (*mach_l2_flush) (int);
+ #endif
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+ void (*mach_beep)(unsigned int, unsigned int);
++EXPORT_SYMBOL(mach_beep);
+ #endif
+ #if defined(CONFIG_ISA) && defined(MULTI_ISA)
+ int isa_type;
+diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
+index 143c552..90238a8 100644
+--- a/arch/m68k/kernel/sys_m68k.c
++++ b/arch/m68k/kernel/sys_m68k.c
+@@ -27,6 +27,7 @@
+ #include <asm/traps.h>
+ #include <asm/ipc.h>
+ #include <asm/page.h>
++#include <asm/unistd.h>
+
+ /*
+ * sys_pipe() is the normal C calling standard for creating
+@@ -663,3 +664,18 @@ asmlinkage int sys_getpagesize(void)
+ {
+ return PAGE_SIZE;
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register long __res asm ("%d0") = __NR_execve;
++ register long __a asm ("%d1") = (long)(filename);
++ register long __b asm ("%d2") = (long)(argv);
++ register long __c asm ("%d3") = (long)(envp);
++ asm volatile ("trap #0" : "+d" (__res)
++ : "d" (__a), "d" (__b), "d" (__c));
++ return __res;
++}
+diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
+index 98e4b1a..2a599c3 100644
+--- a/arch/m68k/kernel/time.c
++++ b/arch/m68k/kernel/time.c
+@@ -10,7 +10,6 @@
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+-#include <linux/config.h> /* CONFIG_HEARTBEAT */
+ #include <linux/errno.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+@@ -22,6 +21,7 @@
+
+ #include <asm/machdep.h>
+ #include <asm/io.h>
++#include <asm/irq_regs.h>
+
+ #include <linux/time.h>
+ #include <linux/timex.h>
+@@ -38,13 +38,13 @@ static inline int set_rtc_mmss(unsigned
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
++static irqreturn_t timer_interrupt(int irq, void *dummy)
+ {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+
+ #ifdef CONFIG_HEARTBEAT
+ /* use power LED as a heartbeat instead -- much more useful
+@@ -96,31 +96,23 @@ void time_init(void)
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+- extern unsigned long wall_jiffies;
+ unsigned long seq;
+- unsigned long usec, sec, lost;
++ unsigned long usec, sec;
+ unsigned long max_ntp_tick = tick_usec - tickadj;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+
+ usec = mach_gettimeoffset();
+- lost = jiffies - wall_jiffies;
+
+ /*
+ * If time_adjust is negative then NTP is slowing the clock
+ * so make sure not to go into next possible interval.
+ * Better to lose some accuracy than have time go backwards..
+ */
+- if (unlikely(time_adjust < 0)) {
++ if (unlikely(time_adjust < 0))
+ usec = min(usec, max_ntp_tick);
+
+- if (lost)
+- usec += lost * max_ntp_tick;
+- }
+- else if (unlikely(lost))
+- usec += lost * tick_usec;
+-
+ sec = xtime.tv_sec;
+ usec += xtime.tv_nsec/1000;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+@@ -141,7 +133,6 @@ int do_settimeofday(struct timespec *tv)
+ {
+ time_t wtm_sec, sec = tv->tv_sec;
+ long wtm_nsec, nsec = tv->tv_nsec;
+- extern unsigned long wall_jiffies;
+
+ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+ return -EINVAL;
+@@ -153,8 +144,7 @@ int do_settimeofday(struct timespec *tv)
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+- nsec -= 1000 * (mach_gettimeoffset() +
+- (jiffies - wall_jiffies) * (1000000 / HZ));
++ nsec -= 1000 * mach_gettimeoffset();
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
+index 4569406..759fa24 100644
+--- a/arch/m68k/kernel/traps.c
++++ b/arch/m68k/kernel/traps.c
+@@ -326,13 +326,13 @@ static inline int do_040writeback1(unsig
+
+ switch (wbs & WBSIZ_040) {
+ case BA_SIZE_BYTE:
+- res = put_user(wbd & 0xff, (char *)wba);
++ res = put_user(wbd & 0xff, (char __user *)wba);
+ break;
+ case BA_SIZE_WORD:
+- res = put_user(wbd & 0xffff, (short *)wba);
++ res = put_user(wbd & 0xffff, (short __user *)wba);
+ break;
+ case BA_SIZE_LONG:
+- res = put_user(wbd, (int *)wba);
++ res = put_user(wbd, (int __user *)wba);
+ break;
+ }
+
+diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
+index 69d1d3d..d279445 100644
+--- a/arch/m68k/kernel/vmlinux-std.lds
++++ b/arch/m68k/kernel/vmlinux-std.lds
+@@ -54,13 +54,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
+index 65cc39c..2550b4a 100644
+--- a/arch/m68k/kernel/vmlinux-sun3.lds
++++ b/arch/m68k/kernel/vmlinux-sun3.lds
+@@ -48,13 +48,7 @@ __init_begin = .;
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
+index b92b89e..891e134 100644
+--- a/arch/m68k/lib/string.c
++++ b/arch/m68k/lib/string.c
+@@ -1,6 +1,19 @@
++/*
++ * 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.
++ */
++
++#define __IN_STRING_C
+
+-#include <linux/types.h>
+ #include <linux/module.h>
++#include <linux/string.h>
++
++char *strcpy(char *dest, const char *src)
++{
++ return __kernel_strcpy(dest, src);
++}
++EXPORT_SYMBOL(strcpy);
+
+ void *memset(void *s, int c, size_t count)
+ {
+diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c
+index 1bc188c..865f9fb 100644
+--- a/arch/m68k/lib/uaccess.c
++++ b/arch/m68k/lib/uaccess.c
+@@ -84,7 +84,7 @@ unsigned long __generic_copy_to_user(voi
+ " .even\n"
+ "20: lsl.l #2,%0\n"
+ "50: add.l %5,%0\n"
+- " jra 7b\n"
++ " jra 8b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
+index 6eaa881..a1c7ec7 100644
+--- a/arch/m68k/mac/baboon.c
++++ b/arch/m68k/mac/baboon.c
+@@ -25,7 +25,7 @@
+ int baboon_present,baboon_active;
+ volatile struct baboon *baboon;
+
+-irqreturn_t baboon_irq(int, void *, struct pt_regs *);
++irqreturn_t baboon_irq(int, void *);
+
+ #if 0
+ extern int macide_ack_intr(struct ata_channel *);
+@@ -64,7 +64,7 @@ void __init baboon_register_interrupts(v
+ * Baboon interrupt handler. This works a lot like a VIA.
+ */
+
+-irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t baboon_irq(int irq, void *dev_id)
+ {
+ int irq_bit,i;
+ unsigned char events;
+@@ -81,7 +81,7 @@ irqreturn_t baboon_irq(int irq, void *de
+ for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit/* & baboon_active*/) {
+ baboon_active &= ~irq_bit;
+- m68k_handle_int(IRQ_BABOON_0 + i, regs);
++ m68k_handle_int(IRQ_BABOON_0 + i);
+ baboon_active |= irq_bit;
+ baboon->mb_ifr &= ~irq_bit;
+ }
+diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
+index 85dda10..562b38d 100644
+--- a/arch/m68k/mac/config.c
++++ b/arch/m68k/mac/config.c
+@@ -72,7 +72,7 @@ extern int show_mac_interrupts(struct se
+ extern void iop_preinit(void);
+ extern void iop_init(void);
+ extern void via_init(void);
+-extern void via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *));
++extern void via_init_clock(irq_handler_t func);
+ extern void via_flush_cache(void);
+ extern void oss_init(void);
+ extern void psc_init(void);
+@@ -88,7 +88,7 @@ extern void mac_debugging_long(int, long
+
+ static void mac_get_model(char *str);
+
+-static void mac_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
++static void mac_sched_init(irq_handler_t vector)
+ {
+ via_init_clock(vector);
+ }
+diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
+index bc657b1..0cea21f 100644
+--- a/arch/m68k/mac/iop.c
++++ b/arch/m68k/mac/iop.c
+@@ -132,7 +132,7 @@ static int iop_get_proc_info(char *, cha
+
+ struct listener {
+ const char *devname;
+- void (*handler)(struct iop_msg *, struct pt_regs *);
++ void (*handler)(struct iop_msg *);
+ };
+
+ /*
+@@ -152,7 +152,7 @@ static struct iop_msg iop_msg_pool[NUM_I
+ static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN];
+ static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN];
+
+-irqreturn_t iop_ism_irq(int, void *, struct pt_regs *);
++irqreturn_t iop_ism_irq(int, void *);
+
+ extern void oss_irq_enable(int);
+
+@@ -342,7 +342,7 @@ void __init iop_register_interrupts(void
+ */
+
+ int iop_listen(uint iop_num, uint chan,
+- void (*handler)(struct iop_msg *, struct pt_regs *),
++ void (*handler)(struct iop_msg *),
+ const char *devname)
+ {
+ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
+@@ -407,7 +407,7 @@ static void iop_do_send(struct iop_msg *
+ * has gone into the IOP_MSG_COMPLETE state.
+ */
+
+-static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
++static void iop_handle_send(uint iop_num, uint chan)
+ {
+ volatile struct mac_iop *iop = iop_base[iop_num];
+ struct iop_msg *msg,*msg2;
+@@ -426,7 +426,7 @@ static void iop_handle_send(uint iop_num
+ for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+ msg->reply[i] = iop_readb(iop, offset);
+ }
+- if (msg->handler) (*msg->handler)(msg, regs);
++ if (msg->handler) (*msg->handler)(msg);
+ msg2 = msg;
+ msg = msg->next;
+ iop_free_msg(msg2);
+@@ -440,7 +440,7 @@ static void iop_handle_send(uint iop_num
+ * gone into the IOP_MSG_NEW state.
+ */
+
+-static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
++static void iop_handle_recv(uint iop_num, uint chan)
+ {
+ volatile struct mac_iop *iop = iop_base[iop_num];
+ int i,offset;
+@@ -468,7 +468,7 @@ static void iop_handle_recv(uint iop_num
+ /* the message ourselves to avoid possible stalls. */
+
+ if (msg->handler) {
+- (*msg->handler)(msg, regs);
++ (*msg->handler)(msg);
+ } else {
+ #ifdef DEBUG_IOP
+ printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan);
+@@ -492,7 +492,7 @@ static void iop_handle_recv(uint iop_num
+
+ int iop_send_message(uint iop_num, uint chan, void *privdata,
+ uint msg_len, __u8 *msg_data,
+- void (*handler)(struct iop_msg *, struct pt_regs *))
++ void (*handler)(struct iop_msg *))
+ {
+ struct iop_msg *msg, *q;
+
+@@ -584,7 +584,7 @@ __u8 *iop_compare_code(uint iop_num, __u
+ * Handle an ISM IOP interrupt
+ */
+
+-irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t iop_ism_irq(int irq, void *dev_id)
+ {
+ uint iop_num = (uint) dev_id;
+ volatile struct mac_iop *iop = iop_base[iop_num];
+@@ -608,7 +608,7 @@ irqreturn_t iop_ism_irq(int irq, void *d
+ printk(" %02X", state);
+ #endif
+ if (state == IOP_MSG_COMPLETE) {
+- iop_handle_send(iop_num, i, regs);
++ iop_handle_send(iop_num, i);
+ }
+ }
+ #ifdef DEBUG_IOP
+@@ -628,7 +628,7 @@ irqreturn_t iop_ism_irq(int irq, void *d
+ printk(" %02X", state);
+ #endif
+ if (state == IOP_MSG_NEW) {
+- iop_handle_recv(iop_num, i, regs);
++ iop_handle_recv(iop_num, i);
+ }
+ }
+ #ifdef DEBUG_IOP
+diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
+index 694b14b..f6fcd75 100644
+--- a/arch/m68k/mac/macints.c
++++ b/arch/m68k/mac/macints.c
+@@ -133,6 +133,7 @@
+ #include <asm/hwtest.h>
+ #include <asm/errno.h>
+ #include <asm/macints.h>
++#include <asm/irq_regs.h>
+
+ #define DEBUG_SPURIOUS
+ #define SHUTUP_SONIC
+@@ -208,8 +209,8 @@ static void scc_irq_disable(unsigned int
+ * console_loglevel determines NMI handler function
+ */
+
+-irqreturn_t mac_nmi_handler(int, void *, struct pt_regs *);
+-irqreturn_t mac_debug_handler(int, void *, struct pt_regs *);
++irqreturn_t mac_nmi_handler(int, void *);
++irqreturn_t mac_debug_handler(int, void *);
+
+ /* #define DEBUG_MACINTS */
+
+@@ -393,7 +394,7 @@ int mac_irq_pending(unsigned int irq)
+
+ static int num_debug[8];
+
+-irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t mac_debug_handler(int irq, void *dev_id)
+ {
+ if (num_debug[irq] < 10) {
+ printk("DEBUG: Unexpected IRQ %d\n", irq);
+@@ -405,7 +406,7 @@ irqreturn_t mac_debug_handler(int irq, v
+ static int in_nmi;
+ static volatile int nmi_hold;
+
+-irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
++irqreturn_t mac_nmi_handler(int irq, void *dev_id)
+ {
+ int i;
+ /*
+@@ -432,6 +433,7 @@ irqreturn_t mac_nmi_handler(int irq, voi
+
+ if (console_loglevel >= 8) {
+ #if 0
++ struct pt_regs *fp = get_irq_regs();
+ show_state();
+ printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
+ printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+@@ -479,7 +481,7 @@ static void scc_irq_disable(unsigned int
+ * here is cleaner than hacking it into drivers/char/macserial.c.
+ */
+
+-void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
++void mac_scc_dispatch(int irq, void *dev_id)
+ {
+ volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2;
+ unsigned char reg;
+@@ -504,7 +506,7 @@ void mac_scc_dispatch(int irq, void *dev
+ /* pretty much kill the system. */
+
+ if (reg & 0x38)
+- m68k_handle_int(IRQ_SCCA, regs);
++ m68k_handle_int(IRQ_SCCA);
+ if (reg & 0x07)
+- m68k_handle_int(IRQ_SCCB, regs);
++ m68k_handle_int(IRQ_SCCB);
+ }
+diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
+index 63e0436..6369081 100644
+--- a/arch/m68k/mac/oss.c
++++ b/arch/m68k/mac/oss.c
+@@ -30,11 +30,11 @@
+ int oss_present;
+ volatile struct mac_oss *oss;
+
+-irqreturn_t oss_irq(int, void *, struct pt_regs *);
+-irqreturn_t oss_nubus_irq(int, void *, struct pt_regs *);
++irqreturn_t oss_irq(int, void *);
++irqreturn_t oss_nubus_irq(int, void *);
+
+-extern irqreturn_t via1_irq(int, void *, struct pt_regs *);
+-extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
++extern irqreturn_t via1_irq(int, void *);
++extern irqreturn_t mac_scc_dispatch(int, void *);
+
+ /*
+ * Initialize the OSS
+@@ -92,7 +92,7 @@ void __init oss_nubus_init(void)
+ * and SCSI; everything else is routed to its own autovector IRQ.
+ */
+
+-irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t oss_irq(int irq, void *dev_id)
+ {
+ int events;
+
+@@ -113,7 +113,7 @@ irqreturn_t oss_irq(int irq, void *dev_i
+ oss->irq_pending &= ~OSS_IP_SOUND;
+ } else if (events & OSS_IP_SCSI) {
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+- m68k_handle_int(IRQ_MAC_SCSI, regs);
++ m68k_handle_int(IRQ_MAC_SCSI);
+ oss->irq_pending &= ~OSS_IP_SCSI;
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+ } else {
+@@ -128,7 +128,7 @@ irqreturn_t oss_irq(int irq, void *dev_i
+ * Unlike the VIA/RBV this is on its own autovector interrupt level.
+ */
+
+-irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t oss_nubus_irq(int irq, void *dev_id)
+ {
+ int events, irq_bit, i;
+
+@@ -146,7 +146,7 @@ irqreturn_t oss_nubus_irq(int irq, void
+ for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+- m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
++ m68k_handle_int(NUBUS_SOURCE_BASE + i);
+ oss->irq_pending &= ~irq_bit;
+ oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+ }
+diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
+index e262180..15378a5 100644
+--- a/arch/m68k/mac/psc.c
++++ b/arch/m68k/mac/psc.c
+@@ -30,7 +30,7 @@
+ int psc_present;
+ volatile __u8 *psc;
+
+-irqreturn_t psc_irq(int, void *, struct pt_regs *);
++irqreturn_t psc_irq(int, void *);
+
+ /*
+ * Debugging dump, used in various places to see what's going on.
+@@ -127,7 +127,7 @@ void __init psc_register_interrupts(void
+ * PSC interrupt handler. It's a lot like the VIA interrupt handler.
+ */
+
+-irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t psc_irq(int irq, void *dev_id)
+ {
+ int pIFR = pIFRbase + ((int) dev_id);
+ int pIER = pIERbase + ((int) dev_id);
+@@ -149,7 +149,7 @@ irqreturn_t psc_irq(int irq, void *dev_i
+ for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ psc_write_byte(pIER, irq_bit);
+- m68k_handle_int(base_irq + i, regs);
++ m68k_handle_int(base_irq + i);
+ psc_write_byte(pIFR, irq_bit);
+ psc_write_byte(pIER, irq_bit | 0x80);
+ }
+diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
+index c4aa345..e27735b 100644
+--- a/arch/m68k/mac/via.c
++++ b/arch/m68k/mac/via.c
+@@ -63,14 +63,14 @@ static int gIER,gIFR,gBufA,gBufB;
+ static int nubus_active;
+
+ void via_debug_dump(void);
+-irqreturn_t via1_irq(int, void *, struct pt_regs *);
+-irqreturn_t via2_irq(int, void *, struct pt_regs *);
+-irqreturn_t via_nubus_irq(int, void *, struct pt_regs *);
++irqreturn_t via1_irq(int, void *);
++irqreturn_t via2_irq(int, void *);
++irqreturn_t via_nubus_irq(int, void *);
+ void via_irq_enable(int irq);
+ void via_irq_disable(int irq);
+ void via_irq_clear(int irq);
+
+-extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
++extern irqreturn_t mac_scc_dispatch(int, void *);
+ extern int oss_present;
+
+ /*
+@@ -235,7 +235,7 @@ void __init via_init(void)
+ * Start the 100 Hz clock
+ */
+
+-void __init via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *))
++void __init via_init_clock(irq_handler_t func)
+ {
+ via1[vACR] |= 0x40;
+ via1[vT1LL] = MAC_CLOCK_LOW;
+@@ -412,7 +412,7 @@ void __init via_nubus_init(void)
+ * the machspec interrupt number after clearing the interrupt.
+ */
+
+-irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t via1_irq(int irq, void *dev_id)
+ {
+ int irq_bit, i;
+ unsigned char events, mask;
+@@ -424,7 +424,7 @@ irqreturn_t via1_irq(int irq, void *dev_
+ for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+ if (events & irq_bit) {
+ via1[vIER] = irq_bit;
+- m68k_handle_int(VIA1_SOURCE_BASE + i, regs);
++ m68k_handle_int(VIA1_SOURCE_BASE + i);
+ via1[vIFR] = irq_bit;
+ via1[vIER] = irq_bit | 0x80;
+ }
+@@ -439,14 +439,14 @@ irqreturn_t via1_irq(int irq, void *dev_
+ /* No, it won't be set. that's why we're doing this. */
+ via_irq_disable(IRQ_MAC_NUBUS);
+ via_irq_clear(IRQ_MAC_NUBUS);
+- m68k_handle_int(IRQ_MAC_NUBUS, regs);
++ m68k_handle_int(IRQ_MAC_NUBUS);
+ via_irq_enable(IRQ_MAC_NUBUS);
+ }
+ #endif
+ return IRQ_HANDLED;
+ }
+
+-irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t via2_irq(int irq, void *dev_id)
+ {
+ int irq_bit, i;
+ unsigned char events, mask;
+@@ -459,7 +459,7 @@ irqreturn_t via2_irq(int irq, void *dev_
+ if (events & irq_bit) {
+ via2[gIER] = irq_bit;
+ via2[gIFR] = irq_bit | rbv_clear;
+- m68k_handle_int(VIA2_SOURCE_BASE + i, regs);
++ m68k_handle_int(VIA2_SOURCE_BASE + i);
+ via2[gIER] = irq_bit | 0x80;
+ }
+ return IRQ_HANDLED;
+@@ -470,7 +470,7 @@ irqreturn_t via2_irq(int irq, void *dev_
+ * VIA2 dispatcher as a fast interrupt handler.
+ */
+
+-irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t via_nubus_irq(int irq, void *dev_id)
+ {
+ int irq_bit, i;
+ unsigned char events;
+@@ -481,7 +481,7 @@ irqreturn_t via_nubus_irq(int irq, void
+ for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ via_irq_disable(NUBUS_SOURCE_BASE + i);
+- m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
++ m68k_handle_int(NUBUS_SOURCE_BASE + i);
+ via_irq_enable(NUBUS_SOURCE_BASE + i);
+ }
+ }
+diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
+index aec1527..911f2ce 100644
+--- a/arch/m68k/mm/fault.c
++++ b/arch/m68k/mm/fault.c
+@@ -144,7 +144,7 @@ good_area:
+ case 1: /* read, present */
+ goto acc_err;
+ case 0: /* read, not present */
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto acc_err;
+ }
+
+@@ -181,7 +181,7 @@ good_area:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
+index f46f049..b54ef17 100644
+--- a/arch/m68k/mm/kmap.c
++++ b/arch/m68k/mm/kmap.c
+@@ -7,6 +7,7 @@
+ * used by other architectures /Roman Zippel
+ */
+
++#include <linux/module.h>
+ #include <linux/mm.h>
+ #include <linux/kernel.h>
+ #include <linux/string.h>
+@@ -219,6 +220,7 @@ void __iomem *__ioremap(unsigned long ph
+
+ return (void __iomem *)retaddr;
+ }
++EXPORT_SYMBOL(__ioremap);
+
+ /*
+ * Unmap a ioremap()ed region again
+@@ -234,6 +236,7 @@ void iounmap(void __iomem *addr)
+ free_io_area((__force void *)addr);
+ #endif
+ }
++EXPORT_SYMBOL(iounmap);
+
+ /*
+ * __iounmap unmaps nearly everything, so be careful
+@@ -360,3 +363,4 @@ void kernel_set_cachemode(void *addr, un
+
+ flush_tlb_all();
+ }
++EXPORT_SYMBOL(kernel_set_cachemode);
+diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
+index a0c095e..0f88812 100644
+--- a/arch/m68k/mm/memory.c
++++ b/arch/m68k/mm/memory.c
+@@ -4,6 +4,7 @@
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
++#include <linux/module.h>
+ #include <linux/mm.h>
+ #include <linux/kernel.h>
+ #include <linux/string.h>
+@@ -157,9 +158,8 @@ unsigned long mm_vtop(unsigned long vadd
+
+ return -1;
+ }
+-#endif
++EXPORT_SYMBOL(mm_vtop);
+
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+ unsigned long mm_ptov (unsigned long paddr)
+ {
+ int i = 0;
+@@ -185,6 +185,7 @@ unsigned long mm_ptov (unsigned long pad
+ #endif
+ return -1;
+ }
++EXPORT_SYMBOL(mm_ptov);
+ #endif
+
+ /* invalidate page in both caches */
+@@ -298,6 +299,7 @@ void cache_clear (unsigned long paddr, i
+ mach_l2_flush(0);
+ #endif
+ }
++EXPORT_SYMBOL(cache_clear); /* probably can be unexported */
+
+
+ /*
+@@ -350,6 +352,7 @@ void cache_push (unsigned long paddr, in
+ mach_l2_flush(1);
+ #endif
+ }
++EXPORT_SYMBOL(cache_push); /* probably can be unexported */
+
+ #ifndef CONFIG_SINGLE_MEMORY_CHUNK
+ int mm_end_of_chunk (unsigned long addr, int len)
+@@ -361,4 +364,5 @@ int mm_end_of_chunk (unsigned long addr,
+ return 1;
+ return 0;
+ }
++EXPORT_SYMBOL(mm_end_of_chunk);
+ #endif
+diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
+index 49015e3..afcccdc 100644
+--- a/arch/m68k/mm/motorola.c
++++ b/arch/m68k/mm/motorola.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/m68k/motorola.c
++ * linux/arch/m68k/mm/motorola.c
+ *
+ * Routines specific to the Motorola MMU, originally from:
+ * linux/arch/m68k/init.c
+diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c
+index 7f0d86f..1af24cb 100644
+--- a/arch/m68k/mm/sun3kmap.c
++++ b/arch/m68k/mm/sun3kmap.c
+@@ -8,6 +8,7 @@
+ * for more details.
+ */
+
++#include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+@@ -59,7 +60,7 @@ static inline void do_pmeg_mapin(unsigne
+ }
+ }
+
+-void *sun3_ioremap(unsigned long phys, unsigned long size,
++void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
+ unsigned long type)
+ {
+ struct vm_struct *area;
+@@ -101,22 +102,24 @@ void *sun3_ioremap(unsigned long phys, u
+ virt += seg_pages * PAGE_SIZE;
+ }
+
+- return (void *)ret;
++ return (void __iomem *)ret;
+
+ }
+
+
+-void *__ioremap(unsigned long phys, unsigned long size, int cache)
++void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
+ {
+
+ return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO);
+
+ }
++EXPORT_SYMBOL(__ioremap);
+
+-void iounmap(void *addr)
++void iounmap(void __iomem *addr)
+ {
+ vfree((void *)(PAGE_MASK & (unsigned long)addr));
+ }
++EXPORT_SYMBOL(iounmap);
+
+ /* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val,
+ * trapping the potential read fault. Returns 0 if the access faulted,
+diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
+index 0cd0e5b..4a7df9c 100644
+--- a/arch/m68k/mvme147/config.c
++++ b/arch/m68k/mvme147/config.c
+@@ -38,7 +38,7 @@
+
+ static void mvme147_get_model(char *model);
+ static int mvme147_get_hardware_list(char *buffer);
+-extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void mvme147_sched_init(irq_handler_t handler);
+ extern unsigned long mvme147_gettimeoffset (void);
+ extern int mvme147_hwclk (int, struct rtc_time *);
+ extern int mvme147_set_clock_mmss (unsigned long);
+@@ -51,7 +51,7 @@ static int bcd2int (unsigned char b);
+ /* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme147_process_int() */
+
+-irqreturn_t (*tick_handler)(int, void *, struct pt_regs *);
++irq_handler_t tick_handler;
+
+
+ int mvme147_parse_bootinfo(const struct bi_record *bi)
+@@ -114,15 +114,15 @@ void __init config_mvme147(void)
+
+ /* Using pcc tick timer 1 */
+
+-static irqreturn_t mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
+ {
+ m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
+ m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+- return tick_handler(irq, dev_id, fp);
++ return tick_handler(irq, dev_id);
+ }
+
+
+-void mvme147_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
++void mvme147_sched_init (irq_handler_t timer_routine)
+ {
+ tick_handler = timer_routine;
+ request_irq (PCC_IRQ_TIMER1, mvme147_timer_int,
+diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
+index ce2727e..c829ebb 100644
+--- a/arch/m68k/mvme16x/config.c
++++ b/arch/m68k/mvme16x/config.c
+@@ -42,7 +42,7 @@ static MK48T08ptr_t volatile rtc = (MK48
+
+ static void mvme16x_get_model(char *model);
+ static int mvme16x_get_hardware_list(char *buffer);
+-extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void mvme16x_sched_init(irq_handler_t handler);
+ extern unsigned long mvme16x_gettimeoffset (void);
+ extern int mvme16x_hwclk (int, struct rtc_time *);
+ extern int mvme16x_set_clock_mmss (unsigned long);
+@@ -54,7 +54,7 @@ int bcd2int (unsigned char b);
+ /* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme16x_process_int() */
+
+-static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *);
++static irq_handler_t tick_handler;
+
+
+ unsigned short mvme16x_config;
+@@ -190,7 +190,7 @@ void __init config_mvme16x(void)
+ }
+ }
+
+-static irqreturn_t mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t mvme16x_abort_int (int irq, void *dev_id)
+ {
+ p_bdid p = &mvme_bdid;
+ unsigned long *new = (unsigned long *)vectors;
+@@ -218,13 +218,13 @@ static irqreturn_t mvme16x_abort_int (in
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
+ {
+ *(volatile unsigned char *)0xfff4201b |= 8;
+- return tick_handler(irq, dev_id, fp);
++ return tick_handler(irq, dev_id);
+ }
+
+-void mvme16x_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
++void mvme16x_sched_init (irq_handler_t timer_routine)
+ {
+ p_bdid p = &mvme_bdid;
+ int irq;
+diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
+index 9a18278..92f873c 100644
+--- a/arch/m68k/q40/config.c
++++ b/arch/m68k/q40/config.c
+@@ -39,7 +39,7 @@ extern irqreturn_t q40_process_int (int
+ extern void q40_init_IRQ (void);
+ static void q40_get_model(char *model);
+ static int q40_get_hardware_list(char *buffer);
+-extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void q40_sched_init(irq_handler_t handler);
+
+ extern unsigned long q40_gettimeoffset (void);
+ extern int q40_hwclk (int, struct rtc_time *);
+diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
+index 472f41c..31cc07d 100644
+--- a/arch/m68k/q40/q40ints.c
++++ b/arch/m68k/q40/q40ints.c
+@@ -125,9 +125,9 @@ void q40_mksound(unsigned int hz, unsign
+ sound_ticks = ticks << 1;
+ }
+
+-static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *);
++static irq_handler_t q40_timer_routine;
+
+-static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
++static irqreturn_t q40_timer_int (int irq, void * dev)
+ {
+ ql_ticks = ql_ticks ? 0 : 1;
+ if (sound_ticks) {
+@@ -138,11 +138,11 @@ static irqreturn_t q40_timer_int (int ir
+ }
+
+ if (!ql_ticks)
+- q40_timer_routine(irq, dev, regs);
++ q40_timer_routine(irq, dev);
+ return IRQ_HANDLED;
+ }
+
+-void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
++void q40_sched_init (irq_handler_t timer_routine)
+ {
+ int timer_irq;
+
+@@ -218,11 +218,11 @@ static void q40_irq_handler(unsigned int
+ switch (irq) {
+ case 4:
+ case 6:
+- m68k_handle_int(Q40_IRQ_SAMPLE, fp);
++ __m68k_handle_int(Q40_IRQ_SAMPLE, fp);
+ return;
+ }
+ if (mir & Q40_IRQ_FRAME_MASK) {
+- m68k_handle_int(Q40_IRQ_FRAME, fp);
++ __m68k_handle_int(Q40_IRQ_FRAME, fp);
+ master_outb(-1, FRAME_CLEAR_REG);
+ }
+ if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
+@@ -257,7 +257,7 @@ static void q40_irq_handler(unsigned int
+ goto iirq;
+ }
+ q40_state[irq] |= IRQ_INPROGRESS;
+- m68k_handle_int(irq, fp);
++ __m68k_handle_int(irq, fp);
+ q40_state[irq] &= ~IRQ_INPROGRESS;
+
+ /* naively enable everything, if that fails than */
+@@ -288,7 +288,7 @@ static void q40_irq_handler(unsigned int
+ mir = master_inb(IIRQ_REG);
+ /* should test whether keyboard irq is really enabled, doing it in defhand */
+ if (mir & Q40_IRQ_KEYB_MASK)
+- m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
++ __m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
+
+ return;
+ }
+diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile
+index 4d4f069..be1a847 100644
+--- a/arch/m68k/sun3/Makefile
++++ b/arch/m68k/sun3/Makefile
+@@ -2,6 +2,6 @@
+ # Makefile for Linux arch/m68k/sun3 source directory
+ #
+
+-obj-y := sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o
++obj-y := sun3ints.o sun3dvma.o sbus.o idprom.o
+
+ obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o
+diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
+index d09d03b..4851b84 100644
+--- a/arch/m68k/sun3/config.c
++++ b/arch/m68k/sun3/config.c
+@@ -35,7 +35,7 @@ extern char _text, _end;
+ char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
+
+ extern unsigned long sun3_gettimeoffset(void);
+-extern void sun3_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void sun3_sched_init(irq_handler_t handler);
+ extern void sun3_get_model (char* model);
+ extern void idprom_init (void);
+ extern int sun3_hwclk(int set, struct rtc_time *t);
+@@ -162,7 +162,7 @@ void __init config_sun3(void)
+ sun3_bootmem_alloc(memory_start, memory_end);
+ }
+
+-void __init sun3_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
++void __init sun3_sched_init(irq_handler_t timer_routine)
+ {
+ sun3_disable_interrupts();
+ intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE);
+diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c
+index 02c1fee..dca6ab6 100644
+--- a/arch/m68k/sun3/idprom.c
++++ b/arch/m68k/sun3/idprom.c
+@@ -6,6 +6,7 @@
+ * Sun3/3x models added by David Monro (davidm at psrg.cs.usyd.edu.au)
+ */
+
++#include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+@@ -16,6 +17,8 @@
+ #include <asm/machines.h> /* Fun with Sun released architectures. */
+
+ struct idprom *idprom;
++EXPORT_SYMBOL(idprom);
++
+ static struct idprom idprom_buffer;
+
+ /* Here is the master table of Sun machines which use some implementation
+diff --git a/arch/m68k/sun3/sun3_ksyms.c b/arch/m68k/sun3/sun3_ksyms.c
+deleted file mode 100644
+index 43e5a9a..0000000
+--- a/arch/m68k/sun3/sun3_ksyms.c
++++ /dev/null
+@@ -1,13 +0,0 @@
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <asm/dvma.h>
+-#include <asm/idprom.h>
+-
+-/*
+- * Add things here when you find the need for it.
+- */
+-EXPORT_SYMBOL(dvma_map_align);
+-EXPORT_SYMBOL(dvma_unmap);
+-EXPORT_SYMBOL(dvma_malloc_align);
+-EXPORT_SYMBOL(dvma_free);
+-EXPORT_SYMBOL(idprom);
+diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c
+index 6c26522..8709677 100644
+--- a/arch/m68k/sun3/sun3dvma.c
++++ b/arch/m68k/sun3/sun3dvma.c
+@@ -1,11 +1,12 @@
+ /*
+- * linux/arch/m68k/mm/sun3dvma.c
++ * linux/arch/m68k/sun3/sun3dvma.c
+ *
+ * Copyright (C) 2000 Sam Creasey
+ *
+ * Contains common routines for sun3/sun3x DVMA management.
+ */
+
++#include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+ #include <linux/list.h>
+@@ -312,6 +313,7 @@ inline unsigned long dvma_map_align(unsi
+ BUG();
+ return 0;
+ }
++EXPORT_SYMBOL(dvma_map_align);
+
+ void dvma_unmap(void *baddr)
+ {
+@@ -327,7 +329,7 @@ void dvma_unmap(void *baddr)
+ return;
+
+ }
+-
++EXPORT_SYMBOL(dvma_unmap);
+
+ void *dvma_malloc_align(unsigned long len, unsigned long align)
+ {
+@@ -367,6 +369,7 @@ void *dvma_malloc_align(unsigned long le
+ return (void *)vaddr;
+
+ }
++EXPORT_SYMBOL(dvma_malloc_align);
+
+ void dvma_free(void *vaddr)
+ {
+@@ -374,3 +377,4 @@ void dvma_free(void *vaddr)
+ return;
+
+ }
++EXPORT_SYMBOL(dvma_free);
+diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
+index f18b9d3..baf74e8 100644
+--- a/arch/m68k/sun3/sun3ints.c
++++ b/arch/m68k/sun3/sun3ints.c
+@@ -15,6 +15,7 @@
+ #include <asm/intersil.h>
+ #include <asm/oplib.h>
+ #include <asm/sun3ints.h>
++#include <asm/irq_regs.h>
+ #include <linux/seq_file.h>
+
+ extern void sun3_leds (unsigned char);
+@@ -48,7 +49,7 @@ void sun3_disable_irq(unsigned int irq)
+ *sun3_intreg &= ~(1 << irq);
+ }
+
+-static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t sun3_int7(int irq, void *dev_id)
+ {
+ *sun3_intreg |= (1 << irq);
+ if (!(kstat_cpu(0).irqs[irq] % 2000))
+@@ -56,7 +57,7 @@ static irqreturn_t sun3_int7(int irq, vo
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t sun3_int5(int irq, void *dev_id)
+ {
+ #ifdef CONFIG_SUN3
+ intersil_clear();
+@@ -65,16 +66,16 @@ static irqreturn_t sun3_int5(int irq, vo
+ #ifdef CONFIG_SUN3
+ intersil_clear();
+ #endif
+- do_timer(fp);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(fp));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ if (!(kstat_cpu(0).irqs[irq] % 20))
+ sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sun3_vec255(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t sun3_vec255(int irq, void *dev_id)
+ {
+ // intersil_clear();
+ return IRQ_HANDLED;
+@@ -84,7 +85,7 @@ static void sun3_inthandle(unsigned int
+ {
+ *sun3_intreg &= ~(1 << irq);
+
+- m68k_handle_int(irq, fp);
++ __m68k_handle_int(irq, fp);
+ }
+
+ static struct irq_controller sun3_irq_controller = {
+diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
+index 6f4204f..f5eaafb 100644
+--- a/arch/m68k/sun3x/time.c
++++ b/arch/m68k/sun3x/time.c
+@@ -90,7 +90,7 @@ static void sun3x_timer_tick(int irq, vo
+ }
+ #endif
+
+-void __init sun3x_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
++void __init sun3x_sched_init(irq_handler_t vector)
+ {
+
+ sun3_disable_interrupts();
+diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
+index e7e43b4..6909e12 100644
+--- a/arch/m68k/sun3x/time.h
++++ b/arch/m68k/sun3x/time.h
+@@ -3,7 +3,7 @@
+
+ extern int sun3x_hwclk(int set, struct rtc_time *t);
+ unsigned long sun3x_gettimeoffset (void);
+-void sun3x_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *));
++void sun3x_sched_init(irq_handler_t vector);
+
+ struct mostek_dt {
+ volatile unsigned char csr;
+diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
+index e767f2d..6d920d4 100644
+--- a/arch/m68knommu/Kconfig
++++ b/arch/m68knommu/Kconfig
+@@ -161,8 +161,8 @@ config CLOCK_FREQ
+ frequency, it may or may not be the same as the external clock
+ crystal fitted to your board. Some processors have an internal
+ PLL and can have their frequency programmed at run time, others
+- use internal dividers. In gernal the kernel won't setup a PLL
+- if it is fitted (there are some expections). This value will be
++ use internal dividers. In general the kernel won't setup a PLL
++ if it is fitted (there are some exceptions). This value will be
+ specific to the exact CPU that you are using.
+
+ config CLOCK_DIV
+@@ -495,7 +495,7 @@ config VECTORBASE
+ hex "Address of the base of system vectors"
+ default "0"
+ help
+- Define the address of the the system vectors. Commonly this is
++ Define the address of the system vectors. Commonly this is
+ put at the start of RAM, but it doesn't have to be. On ColdFire
+ platforms this address is programmed into the VBR register, thus
+ actually setting the address to use.
+diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c
+index d87e1e0..c3494b8 100644
+--- a/arch/m68knommu/kernel/sys_m68k.c
++++ b/arch/m68knommu/kernel/sys_m68k.c
+@@ -26,6 +26,7 @@
+ #include <asm/traps.h>
+ #include <asm/ipc.h>
+ #include <asm/cacheflush.h>
++#include <asm/unistd.h>
+
+ /*
+ * sys_pipe() is the normal C calling standard for creating
+@@ -206,3 +207,17 @@ asmlinkage int sys_getpagesize(void)
+ return PAGE_SIZE;
+ }
+
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register long __res asm ("%d0") = __NR_execve;
++ register long __a asm ("%d1") = (long)(filename);
++ register long __b asm ("%d2") = (long)(argv);
++ register long __c asm ("%d3") = (long)(envp);
++ asm volatile ("trap #0" : "+d" (__res)
++ : "d" (__a), "d" (__b), "d" (__c));
++ return __res;
++}
+diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
+index 617e43e..4603f4f 100644
+--- a/arch/m68knommu/kernel/syscalltable.S
++++ b/arch/m68knommu/kernel/syscalltable.S
+@@ -296,10 +296,39 @@ ENTRY(sys_call_table)
+ .long sys_mq_notify /* 275 */
+ .long sys_mq_getsetattr
+ .long sys_waitid
+- .long sys_ni_syscall /* sys_setaltroot */
+- .long sys_ni_syscall /* sys_add_key */
+- .long sys_ni_syscall /* 280 */ /* sys_request_key */
+- .long sys_ni_syscall /* sys_keyctl */
++ .long sys_ni_syscall /* for sys_vserver */
++ .long sys_add_key
++ .long sys_request_key /* 280 */
++ .long sys_keyctl
++ .long sys_ioprio_set
++ .long sys_ioprio_get
++ .long sys_inotify_init
++ .long sys_inotify_add_watch /* 285 */
++ .long sys_inotify_rm_watch
++ .long sys_migrate_pages
++ .long sys_openat
++ .long sys_mkdirat
++ .long sys_mknodat /* 290 */
++ .long sys_fchownat
++ .long sys_futimesat
++ .long sys_fstatat64
++ .long sys_unlinkat
++ .long sys_renameat /* 295 */
++ .long sys_linkat
++ .long sys_symlinkat
++ .long sys_readlinkat
++ .long sys_fchmodat
++ .long sys_faccessat /* 300 */
++ .long sys_ni_syscall /* Reserved for pselect6 */
++ .long sys_ni_syscall /* Reserved for ppoll */
++ .long sys_unshare
++ .long sys_set_robust_list
++ .long sys_get_robust_list /* 305 */
++ .long sys_splice
++ .long sys_sync_file_range
++ .long sys_tee
++ .long sys_vmsplice
++ .long sys_move_pages /* 310 */
+
+ .rept NR_syscalls-(.-sys_call_table)/4
+ .long sys_ni_syscall
+diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
+index 1db9872..c5667bd 100644
+--- a/arch/m68knommu/kernel/time.c
++++ b/arch/m68knommu/kernel/time.c
+@@ -26,8 +26,6 @@
+
+ #define TICK_SIZE (tick_nsec / 1000)
+
+-extern unsigned long wall_jiffies;
+-
+
+ static inline int set_rtc_mmss(unsigned long nowtime)
+ {
+@@ -51,7 +49,7 @@ static irqreturn_t timer_interrupt(int i
+
+ write_seqlock(&xtime_lock);
+
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+@@ -124,15 +122,12 @@ void time_init(void)
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+- unsigned long lost, seq;
++ unsigned long seq;
+ unsigned long usec, sec;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = mach_gettimeoffset ? mach_gettimeoffset() : 0;
+- lost = jiffies - wall_jiffies;
+- if (lost)
+- usec += lost * (1000000 / HZ);
+ sec = xtime.tv_sec;
+ usec += (xtime.tv_nsec / 1000);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
+index ccd2ceb..58afa8b 100644
+--- a/arch/m68knommu/kernel/vmlinux.lds.S
++++ b/arch/m68knommu/kernel/vmlinux.lds.S
+@@ -140,13 +140,7 @@ SECTIONS {
+ *(.init.setup)
+ __setup_end = .;
+ __initcall_start = .;
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ __initcall_end = .;
+ __con_initcall_start = .;
+ *(.con_initcall.init)
+diff --git a/arch/m68knommu/mm/init.c b/arch/m68knommu/mm/init.c
+index e4c233e..06e538d 100644
+--- a/arch/m68knommu/mm/init.c
++++ b/arch/m68knommu/mm/init.c
+@@ -136,7 +136,7 @@ void paging_init(void)
+ #endif
+
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+ zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT;
+ zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
+index ceef9bc..c7d6ad5 100644
+--- a/arch/m68knommu/platform/532x/config.c
++++ b/arch/m68knommu/platform/532x/config.c
+@@ -17,7 +17,6 @@
+
+ /***************************************************************************/
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/param.h>
+diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68knommu/platform/68328/head-pilot.S
+index 9e07faa..aecff53 100644
+--- a/arch/m68knommu/platform/68328/head-pilot.S
++++ b/arch/m68knommu/platform/68328/head-pilot.S
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/m68knommu/platform/68328/head-rom.S
++ * linux/arch/m68knommu/platform/68328/head-pilot.S
+ * - A startup file for the MC68328
+ *
+ * Copyright (C) 1998 D. Jeff Dionne <jeff at ryeham.ee.ryerson.ca>,
+diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S
+index 3e7fe1e..3108446 100644
+--- a/arch/m68knommu/platform/68328/romvec.S
++++ b/arch/m68knommu/platform/68328/romvec.S
+@@ -10,8 +10,6 @@
+ * Copyright 2006 Greg Ungerer <gerg at snapgear.com>
+ */
+
+-#include <linux/config.h>
+-
+ .global _start
+ .global _buserr
+ .global trap
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index 330f6ab..1443024 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -126,7 +126,7 @@ config BASLER_EXCITE
+ select IRQ_CPU
+ select IRQ_CPU_RM7K
+ select IRQ_CPU_RM9K
+- select SERIAL_RM9000
++ select MIPS_RM9122
+ select SYS_HAS_CPU_RM9000
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
+@@ -203,59 +203,6 @@ config MIPS_EV64120
+ <http://www.marvell.com/>. Say Y here if you wish to build a
+ kernel for this platform.
+
+-config MIPS_EV96100
+- bool "Galileo EV96100 Evaluation board (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
+- select DMA_NONCOHERENT
+- select HW_HAS_PCI
+- select IRQ_CPU
+- select MIPS_GT96100
+- select RM7000_CPU_SCACHE
+- select SWAP_IO_SPACE
+- select SYS_HAS_CPU_R5000
+- select SYS_HAS_CPU_RM7000
+- select SYS_SUPPORTS_32BIT_KERNEL
+- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+- select SYS_SUPPORTS_BIG_ENDIAN
+- help
+- This is an evaluation board based on the Galileo GT-96100 LAN/WAN
+- communications controllers containing a MIPS R5000 compatible core
+- running at 83MHz. Their website is <http://www.marvell.com/>. Say Y
+- here if you wish to build a kernel for this platform.
+-
+-config MIPS_IVR
+- bool "Globespan IVR board"
+- select DMA_NONCOHERENT
+- select HW_HAS_PCI
+- select ITE_BOARD_GEN
+- select SYS_HAS_CPU_NEVADA
+- select SYS_SUPPORTS_32BIT_KERNEL
+- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+- select SYS_SUPPORTS_LITTLE_ENDIAN
+- help
+- This is an evaluation board built by Globespan to showcase thir
+- iVR (Internet Video Recorder) design. It utilizes a QED RM5231
+- R5000 MIPS core. More information can be found out their website
+- located at <http://www.globespan.net/>. Say Y here if you wish to
+- build a kernel for this platform.
+-
+-config MIPS_ITE8172
+- bool "ITE 8172G board"
+- select DMA_NONCOHERENT
+- select HW_HAS_PCI
+- select ITE_BOARD_GEN
+- select SYS_HAS_CPU_R5432
+- select SYS_HAS_CPU_NEVADA
+- select SYS_SUPPORTS_32BIT_KERNEL
+- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+- select SYS_SUPPORTS_LITTLE_ENDIAN
+- help
+- Ths is an evaluation board made by ITE <http://www.ite.com.tw/>
+- with ATX form factor that utilizes a MIPS R5000 to work with its
+- ITE8172G companion internet appliance chip. The MIPS core can be
+- either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build
+- a kernel for this platform.
+-
+ config MACH_JAZZ
+ bool "Jazz family of machines"
+ select ARC
+@@ -478,9 +425,8 @@ config MOMENCO_OCELOT_G
+ select SWAP_IO_SPACE
+ select SYS_HAS_CPU_RM7000
+ select SYS_SUPPORTS_32BIT_KERNEL
+- select SYS_SUPPORTS_64BIT_KERNEL
++ select SYS_SUPPORTS_64BIT_KERNEL if BROKEN
+ select SYS_SUPPORTS_BIG_ENDIAN
+- select ARCH_SPARSEMEM_ENABLE
+ help
+ The Ocelot is a MIPS-based Single Board Computer (SBC) made by
+ Momentum Computer <http://www.momenco.com/>.
+@@ -493,13 +439,11 @@ config MIPS_XXS1500
+
+ config PNX8550_V2PCI
+ bool "Philips PNX8550 based Viper2-PCI board"
+- depends on BROKEN
+ select PNX8550
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+ config PNX8550_JBS
+ bool "Philips PNX8550 based JBS board"
+- depends on BROKEN
+ select PNX8550
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+@@ -557,6 +501,7 @@ config QEMU
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
++ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select ARCH_SPARSEMEM_ENABLE
+ help
+ Qemu is a software emulator which among other architectures also
+@@ -614,6 +559,7 @@ config SGI_IP27
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_NUMA
++ select SYS_SUPPORTS_SMP
+ help
+ This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
+ workstations. To compile a Linux kernel that runs on these, say Y
+@@ -823,7 +769,6 @@ endchoice
+ source "arch/mips/ddb5xxx/Kconfig"
+ source "arch/mips/gt64120/ev64120/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+-source "arch/mips/ite-boards/Kconfig"
+ source "arch/mips/lasat/Kconfig"
+ source "arch/mips/momentum/Kconfig"
+ source "arch/mips/pmc-sierra/Kconfig"
+@@ -856,6 +801,10 @@ config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
++config GENERIC_TIME
++ bool
++ default y
++
+ config SCHED_NO_NO_OMIT_FRAME_POINTER
+ bool
+ default y
+@@ -974,10 +923,13 @@ config MIPS_TX3927
+ bool
+ select HAS_TXX9_SERIAL
+
+-config PCI_MARVELL
++config MIPS_RM9122
+ bool
++ select SERIAL_RM9000
++ select GPI_RM9000
++ select WDT_RM9000
+
+-config ITE_BOARD_GEN
++config PCI_MARVELL
+ bool
+
+ config SOC_AU1000
+@@ -1024,6 +976,15 @@ config EMMA2RH
+ depends on MARKEINS
+ default y
+
++config SERIAL_RM9000
++ bool
++
++config GPI_RM9000
++ bool
++
++config WDT_RM9000
++ bool
++
+ #
+ # Unfortunately not all GT64120 systems run the chip at the same clock.
+ # As the user for the clock rate and try to minimize the available options.
+@@ -1049,25 +1010,6 @@ endchoice
+ config ARC32
+ bool
+
+-config AU1X00_USB_DEVICE
+- bool
+- depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000
+- default n
+-
+-config MIPS_GT96100
+- bool
+- select MIPS_GT64120
+-
+-config IT8172_CIR
+- bool
+- depends on MIPS_ITE8172 || MIPS_IVR
+- default y
+-
+-config IT8712
+- bool
+- depends on MIPS_ITE8172
+- default y
+-
+ config BOOT_ELF32
+ bool
+
+@@ -1518,29 +1460,31 @@ config MIPS_MT_DISABLED
+ the option of an MT-enabled processor this option will be the only
+ option in this menu.
+
+-config MIPS_MT_SMTC
+- bool "SMTC: Use all TCs on all VPEs for SMP"
+- depends on CPU_MIPS32_R2
+- #depends on CPU_MIPS64_R2 # once there is hardware ...
++config MIPS_MT_SMP
++ bool "Use 1 TC on each available VPE for SMP"
+ depends on SYS_SUPPORTS_MULTITHREADING
+ select CPU_MIPSR2_IRQ_VI
+ select CPU_MIPSR2_SRS
+ select MIPS_MT
+ select SMP
++ select SYS_SUPPORTS_SMP
+ help
+- This is a kernel model which is known a SMTC or lately has been
+- marketesed into SMVP.
++ This is a kernel model which is also known a VSMP or lately
++ has been marketesed into SMVP.
+
+-config MIPS_MT_SMP
+- bool "Use 1 TC on each available VPE for SMP"
++config MIPS_MT_SMTC
++ bool "SMTC: Use all TCs on all VPEs for SMP"
++ depends on CPU_MIPS32_R2
++ #depends on CPU_MIPS64_R2 # once there is hardware ...
+ depends on SYS_SUPPORTS_MULTITHREADING
+ select CPU_MIPSR2_IRQ_VI
+ select CPU_MIPSR2_SRS
+ select MIPS_MT
+ select SMP
++ select SYS_SUPPORTS_SMP
+ help
+- This is a kernel model which is also known a VSMP or lately
+- has been marketesed into SMVP.
++ This is a kernel model which is known a SMTC or lately has been
++ marketesed into SMVP.
+
+ config MIPS_VPE_LOADER
+ bool "VPE loader support."
+@@ -1649,9 +1593,7 @@ config GENERIC_IRQ_PROBE
+ default y
+
+ config IRQ_PER_CPU
+- depends on SMP
+ bool
+- default y
+
+ #
+ # - Highmem only makes sense for the 32-bit kernel.
+@@ -1691,9 +1633,6 @@ config ARCH_DISCONTIGMEM_ENABLE
+
+ config ARCH_SPARSEMEM_ENABLE
+ bool
+-
+-config ARCH_SPARSEMEM_ENABLE
+- bool
+ select SPARSEMEM_STATIC
+
+ config NUMA
+@@ -1719,6 +1658,7 @@ source "mm/Kconfig"
+ config SMP
+ bool "Multi-Processing support"
+ depends on SYS_SUPPORTS_SMP
++ select IRQ_PER_CPU
+ help
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, like most personal computers, say N. If
+@@ -1747,6 +1687,7 @@ config NR_CPUS
+ depends on SMP
+ default "64" if SGI_IP27
+ default "2"
++ default "8" if MIPS_MT_SMTC
+ help
+ This allows you to specify the maximum number of CPUs which this
+ kernel will support. The maximum supported value is 32 for 32-bit
+@@ -1849,6 +1790,14 @@ config RWSEM_GENERIC_SPINLOCK
+ bool
+ default y
+
++config LOCKDEP_SUPPORT
++ bool
++ default y
++
++config STACKTRACE_SUPPORT
++ bool
++ default y
++
+ source "init/Kconfig"
+
+ menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)"
+diff --git a/arch/mips/Makefile b/arch/mips/Makefile
+index d333ce4..d580d46 100644
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -63,7 +63,9 @@ cflags-y += -mabi=64
+ ifdef CONFIG_BUILD_ELF64
+ cflags-y += $(call cc-option,-mno-explicit-relocs)
+ else
+-cflags-y += $(call cc-option,-msym32)
++# -msym32 can not be used for modules since they are loaded into XKSEG
++CFLAGS_MODULE += $(call cc-option,-mno-explicit-relocs)
++CFLAGS_KERNEL += $(call cc-option,-msym32)
+ endif
+ endif
+
+@@ -91,8 +93,17 @@ cflags-y += -ffreestanding
+ # carefully avoid to add it redundantly because gcc 3.3/3.4 complains
+ # when fed the toolchain default!
+ #
+-cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB -D__MIPSEB__)
+-cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL -D__MIPSEL__)
++# Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of
++# 2006-10-10 don't properly change the the predefined symbols if -EB / -EL
++# are used, so we kludge that here. A bug has been filed at
++# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413.
++#
++undef-all += -UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__
++undef-all += -UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__
++predef-be += -DMIPSEB -D_MIPSEB -D__MIPSEB -D__MIPSEB__
++predef-le += -DMIPSEL -D_MIPSEL -D__MIPSEL -D__MIPSEL__
++cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB $(undef-all) $(predef-be))
++cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le))
+
+ cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \
+ -fno-omit-frame-pointer
+@@ -280,13 +291,6 @@ cflags-$(CONFIG_MIPS_EV64120) += -Iinclu
+ load-$(CONFIG_MIPS_EV64120) += 0xffffffff80100000
+
+ #
+-# Galileo EV96100 Board
+-#
+-core-$(CONFIG_MIPS_EV96100) += arch/mips/galileo-boards/ev96100/
+-cflags-$(CONFIG_MIPS_EV96100) += -Iinclude/asm-mips/mach-ev96100
+-load-$(CONFIG_MIPS_EV96100) += 0xffffffff80100000
+-
+-#
+ # Wind River PPMC Board (4KC + GT64120)
+ #
+ core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/
+@@ -294,19 +298,6 @@ cflags-$(CONFIG_WR_PPMC) += -Iinclude/a
+ load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
+
+ #
+-# Globespan IVR eval board with QED 5231 CPU
+-#
+-core-$(CONFIG_ITE_BOARD_GEN) += arch/mips/ite-boards/generic/
+-core-$(CONFIG_MIPS_IVR) += arch/mips/ite-boards/ivr/
+-load-$(CONFIG_MIPS_IVR) += 0xffffffff80100000
+-
+-#
+-# ITE 8172 eval board with QED 5231 CPU
+-#
+-core-$(CONFIG_MIPS_ITE8172) += arch/mips/ite-boards/qed-4n-s01b/
+-load-$(CONFIG_MIPS_ITE8172) += 0xffffffff80100000
+-
+-#
+ # For all MIPS, Inc. eval boards
+ #
+ core-$(CONFIG_MIPS_BOARDS_GEN) += arch/mips/mips-boards/generic/
+@@ -330,6 +321,7 @@ load-$(CONFIG_MIPS_MALTA) += 0xffffffff8
+ # MIPS SEAD board
+ #
+ core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/
++cflags-$(CONFIG_MIPS_SEAD) += -Iinclude/asm-mips/mach-mips
+ load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000
+
+ #
+diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
+index bf682f5..4c35525 100644
+--- a/arch/mips/au1000/common/Makefile
++++ b/arch/mips/au1000/common/Makefile
+@@ -10,6 +10,5 @@ obj-y += prom.o irq.o puts.o time.o rese
+ au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
+ sleeper.o cputable.o dma.o dbdma.o gpio.o
+
+-obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
+ obj-$(CONFIG_KGDB) += dbg_io.o
+ obj-$(CONFIG_PCI) += pci.o
+diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
+index 98244d5..626de44 100644
+--- a/arch/mips/au1000/common/dbdma.c
++++ b/arch/mips/au1000/common/dbdma.c
+@@ -230,7 +230,7 @@ EXPORT_SYMBOL(au1xxx_ddma_add_device);
+ */
+ u32
+ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
+- void (*callback)(int, void *, struct pt_regs *), void *callparam)
++ void (*callback)(int, void *), void *callparam)
+ {
+ unsigned long flags;
+ u32 used, chan, rv;
+@@ -248,8 +248,10 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 d
+ au1xxx_dbdma_init();
+ dbdma_initialized = 1;
+
+- if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
+- if ((dtp = find_dbdev_id(destid)) == NULL) return 0;
++ if ((stp = find_dbdev_id(srcid)) == NULL)
++ return 0;
++ if ((dtp = find_dbdev_id(destid)) == NULL)
++ return 0;
+
+ used = 0;
+ rv = 0;
+@@ -847,7 +849,7 @@ au1xxx_dbdma_chan_free(u32 chanid)
+ EXPORT_SYMBOL(au1xxx_dbdma_chan_free);
+
+ static irqreturn_t
+-dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++dbdma_interrupt(int irq, void *dev_id)
+ {
+ u32 intstat;
+ u32 chan_index;
+@@ -869,7 +871,7 @@ dbdma_interrupt(int irq, void *dev_id, s
+ au_sync();
+
+ if (ctp->chan_callback)
+- (ctp->chan_callback)(irq, ctp->chan_callparam, regs);
++ (ctp->chan_callback)(irq, ctp->chan_callparam);
+
+ ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
+ return IRQ_RETVAL(1);
+diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c
+index fb7c47c..c78260d 100644
+--- a/arch/mips/au1000/common/dma.c
++++ b/arch/mips/au1000/common/dma.c
+@@ -160,7 +160,7 @@ void dump_au1000_dma_channel(unsigned in
+ * Requests the DMA done IRQ if irqhandler != NULL.
+ */
+ int request_au1000_dma(int dev_id, const char *dev_str,
+- irqreturn_t (*irqhandler)(int, void *, struct pt_regs *),
++ irq_handler_t irqhandler,
+ unsigned long irqflags,
+ void *irq_dev_id)
+ {
+diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
+index 316722e..2abe132 100644
+--- a/arch/mips/au1000/common/irq.c
++++ b/arch/mips/au1000/common/irq.c
+@@ -67,7 +67,7 @@
+
+ extern void set_debug_traps(void);
+ extern irq_cpustat_t irq_stat [NR_CPUS];
+-extern void mips_timer_interrupt(struct pt_regs *regs);
++extern void mips_timer_interrupt(void);
+
+ static void setup_local_irq(unsigned int irq, int type, int int_req);
+ static unsigned int startup_irq(unsigned int irq);
+@@ -81,10 +81,6 @@ inline void local_disable_irq(unsigned i
+
+ void (*board_init_irq)(void);
+
+-#ifdef CONFIG_PM
+-extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
+-#endif
+-
+ static DEFINE_SPINLOCK(irq_lock);
+
+
+@@ -292,7 +288,7 @@ static struct irq_chip level_irq_type =
+ };
+
+ #ifdef CONFIG_PM
+-void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *))
++void startup_match20_interrupt(irq_handler_t handler)
+ {
+ struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT];
+
+@@ -501,14 +497,15 @@ void __init arch_init_irq(void)
+ * intcX_reqX_irqdispatch().
+ */
+
+-void intc0_req0_irqdispatch(struct pt_regs *regs)
++static void intc0_req0_irqdispatch(void)
+ {
+ int irq = 0;
+ static unsigned long intc0_req0 = 0;
+
+ intc0_req0 |= au_readl(IC0_REQ0INT);
+
+- if (!intc0_req0) return;
++ if (!intc0_req0)
++ return;
+ #ifdef AU1000_USB_DEV_REQ_INT
+ /*
+ * Because of the tight timing of SETUP token to reply
+@@ -517,28 +514,29 @@ void intc0_req0_irqdispatch(struct pt_re
+ */
+ if ((intc0_req0 & (1<<AU1000_USB_DEV_REQ_INT))) {
+ intc0_req0 &= ~(1<<AU1000_USB_DEV_REQ_INT);
+- do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
++ do_IRQ(AU1000_USB_DEV_REQ_INT);
+ return;
+ }
+ #endif
+ irq = au_ffs(intc0_req0) - 1;
+ intc0_req0 &= ~(1<<irq);
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+
+-void intc0_req1_irqdispatch(struct pt_regs *regs)
++static void intc0_req1_irqdispatch(void)
+ {
+ int irq = 0;
+ static unsigned long intc0_req1 = 0;
+
+ intc0_req1 |= au_readl(IC0_REQ1INT);
+
+- if (!intc0_req1) return;
++ if (!intc0_req1)
++ return;
+
+ irq = au_ffs(intc0_req1) - 1;
+ intc0_req1 &= ~(1<<irq);
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+
+@@ -546,35 +544,37 @@ void intc0_req1_irqdispatch(struct pt_re
+ * Interrupt Controller 1:
+ * interrupts 32 - 63
+ */
+-void intc1_req0_irqdispatch(struct pt_regs *regs)
++static void intc1_req0_irqdispatch(void)
+ {
+ int irq = 0;
+ static unsigned long intc1_req0 = 0;
+
+ intc1_req0 |= au_readl(IC1_REQ0INT);
+
+- if (!intc1_req0) return;
++ if (!intc1_req0)
++ return;
+
+ irq = au_ffs(intc1_req0) - 1;
+ intc1_req0 &= ~(1<<irq);
+ irq += 32;
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+
+-void intc1_req1_irqdispatch(struct pt_regs *regs)
++static void intc1_req1_irqdispatch(void)
+ {
+ int irq = 0;
+ static unsigned long intc1_req1 = 0;
+
+ intc1_req1 |= au_readl(IC1_REQ1INT);
+
+- if (!intc1_req1) return;
++ if (!intc1_req1)
++ return;
+
+ irq = au_ffs(intc1_req1) - 1;
+ intc1_req1 &= ~(1<<irq);
+ irq += 32;
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+ #ifdef CONFIG_PM
+@@ -660,20 +660,20 @@ restore_au1xxx_intctl(void)
+ }
+ #endif /* CONFIG_PM */
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+
+ if (pending & CAUSEF_IP7)
+- mips_timer_interrupt(regs);
++ mips_timer_interrupt();
+ else if (pending & CAUSEF_IP2)
+- intc0_req0_irqdispatch(regs);
++ intc0_req0_irqdispatch();
+ else if (pending & CAUSEF_IP3)
+- intc0_req1_irqdispatch(regs);
++ intc0_req1_irqdispatch();
+ else if (pending & CAUSEF_IP4)
+- intc1_req0_irqdispatch(regs);
++ intc1_req0_irqdispatch();
+ else if (pending & CAUSEF_IP5)
+- intc1_req1_irqdispatch(regs);
++ intc1_req1_irqdispatch();
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c
+index b4b010a..6fce60a 100644
+--- a/arch/mips/au1000/common/prom.c
++++ b/arch/mips/au1000/common/prom.c
+@@ -47,7 +47,7 @@ extern int prom_argc;
+ extern char **prom_argv, **prom_envp;
+
+
+-char * prom_getcmdline(void)
++char * __init_or_module prom_getcmdline(void)
+ {
+ return &(arcs_cmdline[0]);
+ }
+diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
+index 377ae0d..919172d 100644
+--- a/arch/mips/au1000/common/setup.c
++++ b/arch/mips/au1000/common/setup.c
+@@ -43,7 +43,7 @@
+ #include <asm/mach-au1x00/au1000.h>
+ #include <asm/time.h>
+
+-extern char * __init prom_getcmdline(void);
++extern char * prom_getcmdline(void);
+ extern void __init board_setup(void);
+ extern void au1000_restart(char *);
+ extern void au1000_halt(void);
+diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
+index 7fbea1b..fa1c62f 100644
+--- a/arch/mips/au1000/common/time.c
++++ b/arch/mips/au1000/common/time.c
+@@ -41,7 +41,6 @@
+
+ #include <asm/compiler.h>
+ #include <asm/mipsregs.h>
+-#include <asm/ptrace.h>
+ #include <asm/time.h>
+ #include <asm/div64.h>
+ #include <asm/mach-au1x00/au1000.h>
+@@ -54,15 +53,12 @@ static unsigned long r4k_cur; /* What
+ int no_au1xxx_32khz;
+ extern int allow_au1k_wait; /* default off for CP0 Counter */
+
+-/* Cycle counter value at the previous timer interrupt.. */
+-static unsigned int timerhi = 0, timerlo = 0;
+-
+ #ifdef CONFIG_PM
+ #if HZ < 100 || HZ > 1000
+ #error "unsupported HZ value! Must be in [100,1000]"
+ #endif
+ #define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */
+-extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void startup_match20_interrupt(irq_handler_t handler);
+ static unsigned long last_pc0, last_match20;
+ #endif
+
+@@ -79,10 +75,10 @@ static inline void ack_r4ktimer(unsigned
+ * is provably more robust.
+ */
+ unsigned long wtimer;
+-void mips_timer_interrupt(struct pt_regs *regs)
++
++void mips_timer_interrupt(void)
+ {
+ int irq = 63;
+- unsigned long count;
+
+ irq_enter();
+ kstat_this_cpu.irqs[irq]++;
+@@ -91,14 +87,10 @@ void mips_timer_interrupt(struct pt_regs
+ goto null;
+
+ do {
+- count = read_c0_count();
+- timerhi += (count < timerlo); /* Wrap around */
+- timerlo = count;
+-
+ kstat_this_cpu.irqs[irq]++;
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ r4k_cur += r4k_offset;
+ ack_r4ktimer(r4k_cur);
+@@ -115,7 +107,7 @@ null:
+ }
+
+ #ifdef CONFIG_PM
+-irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t counter0_irq(int irq, void *dev_id)
+ {
+ unsigned long pc0;
+ int time_elapsed;
+@@ -137,9 +129,9 @@ irqreturn_t counter0_irq(int irq, void *
+ }
+
+ while (time_elapsed > 0) {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ time_elapsed -= MATCH20_INC;
+ last_match20 += MATCH20_INC;
+@@ -156,9 +148,9 @@ irqreturn_t counter0_irq(int irq, void *
+
+ if (jiffie_drift >= 999) {
+ jiffie_drift -= 999;
+- do_timer(regs); /* increment jiffies by one */
++ do_timer(1); /* increment jiffies by one */
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ }
+
+@@ -231,7 +223,6 @@ wakeup_counter0_set(int ticks)
+ */
+ unsigned long cal_r4koff(void)
+ {
+- unsigned long count;
+ unsigned long cpu_speed;
+ unsigned long flags;
+ unsigned long counter;
+@@ -258,7 +249,7 @@ unsigned long cal_r4koff(void)
+
+ #if defined(CONFIG_AU1000_USE32K)
+ {
+- unsigned long start, end;
++ unsigned long start, end, count;
+
+ start = au_readl(SYS_RTCREAD);
+ start += 2;
+@@ -282,7 +273,6 @@ unsigned long cal_r4koff(void)
+ #else
+ cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
+ AU1000_SRC_CLK;
+- count = cpu_speed / 2;
+ #endif
+ }
+ else {
+@@ -291,98 +281,15 @@ unsigned long cal_r4koff(void)
+ * NOTE: some old silicon doesn't allow reading the PLL.
+ */
+ cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
+- count = cpu_speed / 2;
+ no_au1xxx_32khz = 1;
+ }
+- mips_hpt_frequency = count;
++ mips_hpt_frequency = cpu_speed;
+ // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16)
+ set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
+ spin_unlock_irqrestore(&time_lock, flags);
+ return (cpu_speed / HZ);
+ }
+
+-/* This is for machines which generate the exact clock. */
+-#define USECS_PER_JIFFY (1000000/HZ)
+-#define USECS_PER_JIFFY_FRAC (0x100000000LL*1000000/HZ&0xffffffff)
+-
+-static unsigned long
+-div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
+-{
+- unsigned long r0;
+- do_div64_32(r0, v1, v2, v3);
+- return r0;
+-}
+-
+-static unsigned long do_fast_cp0_gettimeoffset(void)
+-{
+- u32 count;
+- unsigned long res, tmp;
+- unsigned long r0;
+-
+- /* Last jiffy when do_fast_gettimeoffset() was called. */
+- static unsigned long last_jiffies=0;
+- unsigned long quotient;
+-
+- /*
+- * Cached "1/(clocks per usec)*2^32" value.
+- * It has to be recalculated once each jiffy.
+- */
+- static unsigned long cached_quotient=0;
+-
+- tmp = jiffies;
+-
+- quotient = cached_quotient;
+-
+- if (tmp && last_jiffies != tmp) {
+- last_jiffies = tmp;
+- if (last_jiffies != 0) {
+- r0 = div64_32(timerhi, timerlo, tmp);
+- quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0);
+- cached_quotient = quotient;
+- }
+- }
+-
+- /* Get last timer tick in absolute kernel time */
+- count = read_c0_count();
+-
+- /* .. relative to previous jiffy (32 bits is enough) */
+- count -= timerlo;
+-
+- __asm__("multu\t%1,%2\n\t"
+- "mfhi\t%0"
+- : "=r" (res)
+- : "r" (count), "r" (quotient)
+- : "hi", "lo", GCC_REG_ACCUM);
+-
+- /*
+- * Due to possible jiffies inconsistencies, we need to check
+- * the result so that we'll get a timer that is monotonic.
+- */
+- if (res >= USECS_PER_JIFFY)
+- res = USECS_PER_JIFFY-1;
+-
+- return res;
+-}
+-
+-#ifdef CONFIG_PM
+-static unsigned long do_fast_pm_gettimeoffset(void)
+-{
+- unsigned long pc0;
+- unsigned long offset;
+-
+- pc0 = au_readl(SYS_TOYREAD);
+- au_sync();
+- offset = pc0 - last_pc0;
+- if (offset > 2*MATCH20_INC) {
+- printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
+- (unsigned)offset, (unsigned)last_pc0,
+- (unsigned)last_match20, (unsigned)pc0);
+- }
+- offset = (unsigned long)((offset * 305) / 10);
+- return offset;
+-}
+-#endif
+-
+ void __init plat_timer_setup(struct irqaction *irq)
+ {
+ unsigned int est_freq;
+@@ -420,7 +327,6 @@ void __init plat_timer_setup(struct irqa
+ unsigned int c0_status;
+
+ printk("WARNING: no 32KHz clock found.\n");
+- do_gettimeoffset = do_fast_cp0_gettimeoffset;
+
+ /* Ensure we get CPO_COUNTER interrupts.
+ */
+@@ -445,19 +351,11 @@ void __init plat_timer_setup(struct irqa
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
+ startup_match20_interrupt(counter0_irq);
+
+- do_gettimeoffset = do_fast_pm_gettimeoffset;
+-
+ /* We can use the real 'wait' instruction.
+ */
+ allow_au1k_wait = 1;
+ }
+
+-#else
+- /* We have to do this here instead of in timer_init because
+- * the generic code in arch/mips/kernel/time.c will write
+- * over our function pointer.
+- */
+- do_gettimeoffset = do_fast_cp0_gettimeoffset;
+ #endif
+ }
+
+diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c
+deleted file mode 100644
+index 63bcb3a..0000000
+--- a/arch/mips/au1000/common/usbdev.c
++++ /dev/null
+@@ -1,1555 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * Au1000 USB Device-Side (device layer)
+- *
+- * Copyright 2001-2002 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at 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.
+- *
+- * 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/kernel.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/signal.h>
+-#include <linux/errno.h>
+-#include <linux/poll.h>
+-#include <linux/init.h>
+-#include <linux/slab.h>
+-#include <linux/fcntl.h>
+-#include <linux/module.h>
+-#include <linux/spinlock.h>
+-#include <linux/list.h>
+-#include <linux/smp_lock.h>
+-#define DEBUG
+-#include <linux/usb.h>
+-
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/irq.h>
+-#include <asm/mipsregs.h>
+-#include <asm/au1000.h>
+-#include <asm/au1000_dma.h>
+-#include <asm/au1000_usbdev.h>
+-
+-#ifdef DEBUG
+-#undef VDEBUG
+-#ifdef VDEBUG
+-#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg)
+-#else
+-#define vdbg(fmt, arg...) do {} while (0)
+-#endif
+-#else
+-#define vdbg(fmt, arg...) do {} while (0)
+-#endif
+-
+-#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
+-
+-#define EP_FIFO_DEPTH 8
+-
+-typedef enum {
+- SETUP_STAGE = 0,
+- DATA_STAGE,
+- STATUS_STAGE
+-} ep0_stage_t;
+-
+-typedef struct {
+- int read_fifo;
+- int write_fifo;
+- int ctrl_stat;
+- int read_fifo_status;
+- int write_fifo_status;
+-} endpoint_reg_t;
+-
+-typedef struct {
+- usbdev_pkt_t *head;
+- usbdev_pkt_t *tail;
+- int count;
+-} pkt_list_t;
+-
+-typedef struct {
+- int active;
+- struct usb_endpoint_descriptor *desc;
+- endpoint_reg_t *reg;
+- /* Only one of these are used, unless this is the control ep */
+- pkt_list_t inlist;
+- pkt_list_t outlist;
+- unsigned int indma, outdma; /* DMA channel numbers for IN, OUT */
+- /* following are extracted from endpoint descriptor for easy access */
+- int max_pkt_size;
+- int type;
+- int direction;
+- /* WE assign endpoint addresses! */
+- int address;
+- spinlock_t lock;
+-} endpoint_t;
+-
+-
+-static struct usb_dev {
+- endpoint_t ep[6];
+- ep0_stage_t ep0_stage;
+-
+- struct usb_device_descriptor * dev_desc;
+- struct usb_interface_descriptor* if_desc;
+- struct usb_config_descriptor * conf_desc;
+- u8 * full_conf_desc;
+- struct usb_string_descriptor * str_desc[6];
+-
+- /* callback to function layer */
+- void (*func_cb)(usbdev_cb_type_t type, unsigned long arg,
+- void *cb_data);
+- void* cb_data;
+-
+- usbdev_state_t state; // device state
+- int suspended; // suspended flag
+- int address; // device address
+- int interface;
+- int num_ep;
+- u8 alternate_setting;
+- u8 configuration; // configuration value
+- int remote_wakeup_en;
+-} usbdev;
+-
+-
+-static endpoint_reg_t ep_reg[] = {
+- // FIFO's 0 and 1 are EP0 default control
+- {USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT },
+- {0},
+- // FIFO 2 is EP2, IN
+- { -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT },
+- // FIFO 3 is EP3, IN
+- { -1, USBD_EP3WR, USBD_EP3CS, -1, USBD_EP3WRSTAT },
+- // FIFO 4 is EP4, OUT
+- {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP4RDSTAT, -1 },
+- // FIFO 5 is EP5, OUT
+- {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1 }
+-};
+-
+-static struct {
+- unsigned int id;
+- const char *str;
+-} ep_dma_id[] = {
+- { DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" },
+- { DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" },
+- { DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" },
+- { DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" },
+- { DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" },
+- { DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" }
+-};
+-
+-#define DIR_OUT 0
+-#define DIR_IN (1<<3)
+-
+-#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL
+-#define BULK_EP USB_ENDPOINT_XFER_BULK
+-
+-static inline endpoint_t *
+-epaddr_to_ep(struct usb_dev* dev, int ep_addr)
+-{
+- if (ep_addr >= 0 && ep_addr < 2)
+- return &dev->ep[0];
+- if (ep_addr < 6)
+- return &dev->ep[ep_addr];
+- return NULL;
+-}
+-
+-static const char* std_req_name[] = {
+- "GET_STATUS",
+- "CLEAR_FEATURE",
+- "RESERVED",
+- "SET_FEATURE",
+- "RESERVED",
+- "SET_ADDRESS",
+- "GET_DESCRIPTOR",
+- "SET_DESCRIPTOR",
+- "GET_CONFIGURATION",
+- "SET_CONFIGURATION",
+- "GET_INTERFACE",
+- "SET_INTERFACE",
+- "SYNCH_FRAME"
+-};
+-
+-static inline const char*
+-get_std_req_name(int req)
+-{
+- return (req >= 0 && req <= 12) ? std_req_name[req] : "UNKNOWN";
+-}
+-
+-#if 0
+-static void
+-dump_setup(struct usb_ctrlrequest* s)
+-{
+- dbg("%s: requesttype=%d", __FUNCTION__, s->requesttype);
+- dbg("%s: request=%d %s", __FUNCTION__, s->request,
+- get_std_req_name(s->request));
+- dbg("%s: value=0x%04x", __FUNCTION__, s->wValue);
+- dbg("%s: index=%d", __FUNCTION__, s->index);
+- dbg("%s: length=%d", __FUNCTION__, s->length);
+-}
+-#endif
+-
+-static inline usbdev_pkt_t *
+-alloc_packet(endpoint_t * ep, int data_size, void* data)
+-{
+- usbdev_pkt_t* pkt = kmalloc(sizeof(usbdev_pkt_t) + data_size,
+- ALLOC_FLAGS);
+- if (!pkt)
+- return NULL;
+- pkt->ep_addr = ep->address;
+- pkt->size = data_size;
+- pkt->status = 0;
+- pkt->next = NULL;
+- if (data)
+- memcpy(pkt->payload, data, data_size);
+-
+- return pkt;
+-}
+-
+-
+-/*
+- * Link a packet to the tail of the enpoint's packet list.
+- * EP spinlock must be held when calling.
+- */
+-static void
+-link_tail(endpoint_t * ep, pkt_list_t * list, usbdev_pkt_t * pkt)
+-{
+- if (!list->tail) {
+- list->head = list->tail = pkt;
+- list->count = 1;
+- } else {
+- list->tail->next = pkt;
+- list->tail = pkt;
+- list->count++;
+- }
+-}
+-
+-/*
+- * Unlink and return a packet from the head of the given packet
+- * list. It is the responsibility of the caller to free the packet.
+- * EP spinlock must be held when calling.
+- */
+-static usbdev_pkt_t *
+-unlink_head(pkt_list_t * list)
+-{
+- usbdev_pkt_t *pkt;
+-
+- pkt = list->head;
+- if (!pkt || !list->count) {
+- return NULL;
+- }
+-
+- list->head = pkt->next;
+- if (!list->head) {
+- list->head = list->tail = NULL;
+- list->count = 0;
+- } else
+- list->count--;
+-
+- return pkt;
+-}
+-
+-/*
+- * Create and attach a new packet to the tail of the enpoint's
+- * packet list. EP spinlock must be held when calling.
+- */
+-static usbdev_pkt_t *
+-add_packet(endpoint_t * ep, pkt_list_t * list, int size)
+-{
+- usbdev_pkt_t *pkt = alloc_packet(ep, size, NULL);
+- if (!pkt)
+- return NULL;
+-
+- link_tail(ep, list, pkt);
+- return pkt;
+-}
+-
+-
+-/*
+- * Unlink and free a packet from the head of the enpoint's
+- * packet list. EP spinlock must be held when calling.
+- */
+-static inline void
+-free_packet(pkt_list_t * list)
+-{
+- kfree(unlink_head(list));
+-}
+-
+-/* EP spinlock must be held when calling. */
+-static inline void
+-flush_pkt_list(pkt_list_t * list)
+-{
+- while (list->count)
+- free_packet(list);
+-}
+-
+-/* EP spinlock must be held when calling */
+-static inline void
+-flush_write_fifo(endpoint_t * ep)
+-{
+- if (ep->reg->write_fifo_status >= 0) {
+- au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
+- USBDEV_FSTAT_OF,
+- ep->reg->write_fifo_status);
+- //udelay(100);
+- //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
+- // ep->reg->write_fifo_status);
+- }
+-}
+-
+-/* EP spinlock must be held when calling */
+-static inline void
+-flush_read_fifo(endpoint_t * ep)
+-{
+- if (ep->reg->read_fifo_status >= 0) {
+- au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
+- USBDEV_FSTAT_OF,
+- ep->reg->read_fifo_status);
+- //udelay(100);
+- //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
+- // ep->reg->read_fifo_status);
+- }
+-}
+-
+-
+-/* EP spinlock must be held when calling. */
+-static void
+-endpoint_flush(endpoint_t * ep)
+-{
+- // First, flush all packets
+- flush_pkt_list(&ep->inlist);
+- flush_pkt_list(&ep->outlist);
+-
+- // Now flush the endpoint's h/w FIFO(s)
+- flush_write_fifo(ep);
+- flush_read_fifo(ep);
+-}
+-
+-/* EP spinlock must be held when calling. */
+-static void
+-endpoint_stall(endpoint_t * ep)
+-{
+- u32 cs;
+-
+- warn("%s", __FUNCTION__);
+-
+- cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
+- au_writel(cs, ep->reg->ctrl_stat);
+-}
+-
+-/* EP spinlock must be held when calling. */
+-static void
+-endpoint_unstall(endpoint_t * ep)
+-{
+- u32 cs;
+-
+- warn("%s", __FUNCTION__);
+-
+- cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
+- au_writel(cs, ep->reg->ctrl_stat);
+-}
+-
+-static void
+-endpoint_reset_datatoggle(endpoint_t * ep)
+-{
+- // FIXME: is this possible?
+-}
+-
+-
+-/* EP spinlock must be held when calling. */
+-static int
+-endpoint_fifo_read(endpoint_t * ep)
+-{
+- int read_count = 0;
+- u8 *bufptr;
+- usbdev_pkt_t *pkt = ep->outlist.tail;
+-
+- if (!pkt)
+- return -EINVAL;
+-
+- bufptr = &pkt->payload[pkt->size];
+- while (au_readl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) {
+- *bufptr++ = au_readl(ep->reg->read_fifo) & 0xff;
+- read_count++;
+- pkt->size++;
+- }
+-
+- return read_count;
+-}
+-
+-#if 0
+-/* EP spinlock must be held when calling. */
+-static int
+-endpoint_fifo_write(endpoint_t * ep, int index)
+-{
+- int write_count = 0;
+- u8 *bufptr;
+- usbdev_pkt_t *pkt = ep->inlist.head;
+-
+- if (!pkt)
+- return -EINVAL;
+-
+- bufptr = &pkt->payload[index];
+- while ((au_readl(ep->reg->write_fifo_status) &
+- USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) {
+- if (bufptr < pkt->payload + pkt->size) {
+- au_writel(*bufptr++, ep->reg->write_fifo);
+- write_count++;
+- } else {
+- break;
+- }
+- }
+-
+- return write_count;
+-}
+-#endif
+-
+-/*
+- * This routine is called to restart transmission of a packet.
+- * The endpoint's TSIZE must be set to the new packet's size,
+- * and DMA to the write FIFO needs to be restarted.
+- * EP spinlock must be held when calling.
+- */
+-static void
+-kickstart_send_packet(endpoint_t * ep)
+-{
+- u32 cs;
+- usbdev_pkt_t *pkt = ep->inlist.head;
+-
+- vdbg("%s: ep%d, pkt=%p", __FUNCTION__, ep->address, pkt);
+-
+- if (!pkt) {
+- err("%s: head=NULL! list->count=%d", __FUNCTION__,
+- ep->inlist.count);
+- return;
+- }
+-
+- dma_cache_wback_inv((unsigned long)pkt->payload, pkt->size);
+-
+- /*
+- * make sure FIFO is empty
+- */
+- flush_write_fifo(ep);
+-
+- cs = au_readl(ep->reg->ctrl_stat) & USBDEV_CS_STALL;
+- cs |= (pkt->size << USBDEV_CS_TSIZE_BIT);
+- au_writel(cs, ep->reg->ctrl_stat);
+-
+- if (get_dma_active_buffer(ep->indma) == 1) {
+- set_dma_count1(ep->indma, pkt->size);
+- set_dma_addr1(ep->indma, virt_to_phys(pkt->payload));
+- enable_dma_buffer1(ep->indma); // reenable
+- } else {
+- set_dma_count0(ep->indma, pkt->size);
+- set_dma_addr0(ep->indma, virt_to_phys(pkt->payload));
+- enable_dma_buffer0(ep->indma); // reenable
+- }
+- if (dma_halted(ep->indma))
+- start_dma(ep->indma);
+-}
+-
+-
+-/*
+- * This routine is called when a packet in the inlist has been
+- * completed. Frees the completed packet and starts sending the
+- * next. EP spinlock must be held when calling.
+- */
+-static usbdev_pkt_t *
+-send_packet_complete(endpoint_t * ep)
+-{
+- usbdev_pkt_t *pkt = unlink_head(&ep->inlist);
+-
+- if (pkt) {
+- pkt->status =
+- (au_readl(ep->reg->ctrl_stat) & USBDEV_CS_NAK) ?
+- PKT_STATUS_NAK : PKT_STATUS_ACK;
+-
+- vdbg("%s: ep%d, %s pkt=%p, list count=%d", __FUNCTION__,
+- ep->address, (pkt->status & PKT_STATUS_NAK) ?
+- "NAK" : "ACK", pkt, ep->inlist.count);
+- }
+-
+- /*
+- * The write fifo should already be drained if things are
+- * working right, but flush it anyway just in case.
+- */
+- flush_write_fifo(ep);
+-
+- // begin transmitting next packet in the inlist
+- if (ep->inlist.count) {
+- kickstart_send_packet(ep);
+- }
+-
+- return pkt;
+-}
+-
+-/*
+- * Add a new packet to the tail of the given ep's packet
+- * inlist. The transmit complete interrupt frees packets from
+- * the head of this list. EP spinlock must be held when calling.
+- */
+-static int
+-send_packet(struct usb_dev* dev, usbdev_pkt_t *pkt, int async)
+-{
+- pkt_list_t *list;
+- endpoint_t* ep;
+-
+- if (!pkt || !(ep = epaddr_to_ep(dev, pkt->ep_addr)))
+- return -EINVAL;
+-
+- if (!pkt->size)
+- return 0;
+-
+- list = &ep->inlist;
+-
+- if (!async && list->count) {
+- halt_dma(ep->indma);
+- flush_pkt_list(list);
+- }
+-
+- link_tail(ep, list, pkt);
+-
+- vdbg("%s: ep%d, pkt=%p, size=%d, list count=%d", __FUNCTION__,
+- ep->address, pkt, pkt->size, list->count);
+-
+- if (list->count == 1) {
+- /*
+- * if the packet count is one, it means the list was empty,
+- * and no more data will go out this ep until we kick-start
+- * it again.
+- */
+- kickstart_send_packet(ep);
+- }
+-
+- return pkt->size;
+-}
+-
+-/*
+- * This routine is called to restart reception of a packet.
+- * EP spinlock must be held when calling.
+- */
+-static void
+-kickstart_receive_packet(endpoint_t * ep)
+-{
+- usbdev_pkt_t *pkt;
+-
+- // get and link a new packet for next reception
+- if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) {
+- err("%s: could not alloc new packet", __FUNCTION__);
+- return;
+- }
+-
+- if (get_dma_active_buffer(ep->outdma) == 1) {
+- clear_dma_done1(ep->outdma);
+- set_dma_count1(ep->outdma, ep->max_pkt_size);
+- set_dma_count0(ep->outdma, 0);
+- set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload));
+- enable_dma_buffer1(ep->outdma); // reenable
+- } else {
+- clear_dma_done0(ep->outdma);
+- set_dma_count0(ep->outdma, ep->max_pkt_size);
+- set_dma_count1(ep->outdma, 0);
+- set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload));
+- enable_dma_buffer0(ep->outdma); // reenable
+- }
+- if (dma_halted(ep->outdma))
+- start_dma(ep->outdma);
+-}
+-
+-
+-/*
+- * This routine is called when a packet in the outlist has been
+- * completed (received) and we need to prepare for a new packet
+- * to be received. Halts DMA and computes the packet size from the
+- * remaining DMA counter. Then prepares a new packet for reception
+- * and restarts DMA. FIXME: what if another packet comes in
+- * on top of the completed packet? Counter would be wrong.
+- * EP spinlock must be held when calling.
+- */
+-static usbdev_pkt_t *
+-receive_packet_complete(endpoint_t * ep)
+-{
+- usbdev_pkt_t *pkt = ep->outlist.tail;
+- u32 cs;
+-
+- halt_dma(ep->outdma);
+-
+- cs = au_readl(ep->reg->ctrl_stat);
+-
+- if (!pkt)
+- return NULL;
+-
+- pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma);
+- if (pkt->size)
+- dma_cache_inv((unsigned long)pkt->payload, pkt->size);
+- /*
+- * need to pull out any remaining bytes in the FIFO.
+- */
+- endpoint_fifo_read(ep);
+- /*
+- * should be drained now, but flush anyway just in case.
+- */
+- flush_read_fifo(ep);
+-
+- pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK;
+- if (ep->address == 0 && (cs & USBDEV_CS_SU))
+- pkt->status |= PKT_STATUS_SU;
+-
+- vdbg("%s: ep%d, %s pkt=%p, size=%d", __FUNCTION__,
+- ep->address, (pkt->status & PKT_STATUS_NAK) ?
+- "NAK" : "ACK", pkt, pkt->size);
+-
+- kickstart_receive_packet(ep);
+-
+- return pkt;
+-}
+-
+-
+-/*
+- ****************************************************************************
+- * Here starts the standard device request handlers. They are
+- * all called by do_setup() via a table of function pointers.
+- ****************************************************************************
+- */
+-
+-static ep0_stage_t
+-do_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- switch (setup->bRequestType) {
+- case 0x80: // Device
+- // FIXME: send device status
+- break;
+- case 0x81: // Interface
+- // FIXME: send interface status
+- break;
+- case 0x82: // End Point
+- // FIXME: send endpoint status
+- break;
+- default:
+- // Invalid Command
+- endpoint_stall(&dev->ep[0]); // Stall End Point 0
+- break;
+- }
+-
+- return STATUS_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- switch (setup->bRequestType) {
+- case 0x00: // Device
+- if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
+- dev->remote_wakeup_en = 0;
+- else
+- endpoint_stall(&dev->ep[0]);
+- break;
+- case 0x02: // End Point
+- if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
+- endpoint_t *ep =
+- epaddr_to_ep(dev,
+- le16_to_cpu(setup->wIndex) & 0xff);
+-
+- endpoint_unstall(ep);
+- endpoint_reset_datatoggle(ep);
+- } else
+- endpoint_stall(&dev->ep[0]);
+- break;
+- }
+-
+- return SETUP_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- // Invalid request, stall End Point 0
+- endpoint_stall(&dev->ep[0]);
+- return SETUP_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- switch (setup->bRequestType) {
+- case 0x00: // Device
+- if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
+- dev->remote_wakeup_en = 1;
+- else
+- endpoint_stall(&dev->ep[0]);
+- break;
+- case 0x02: // End Point
+- if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
+- endpoint_t *ep =
+- epaddr_to_ep(dev,
+- le16_to_cpu(setup->wIndex) & 0xff);
+-
+- endpoint_stall(ep);
+- } else
+- endpoint_stall(&dev->ep[0]);
+- break;
+- }
+-
+- return SETUP_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- int new_state = dev->state;
+- int new_addr = le16_to_cpu(setup->wValue);
+-
+- dbg("%s: our address=%d", __FUNCTION__, new_addr);
+-
+- if (new_addr > 127) {
+- // usb spec doesn't tell us what to do, so just go to
+- // default state
+- new_state = DEFAULT;
+- dev->address = 0;
+- } else if (dev->address != new_addr) {
+- dev->address = new_addr;
+- new_state = ADDRESS;
+- }
+-
+- if (dev->state != new_state) {
+- dev->state = new_state;
+- /* inform function layer of usbdev state change */
+- dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
+- }
+-
+- return SETUP_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- int strnum, desc_len = le16_to_cpu(setup->wLength);
+-
+- switch (le16_to_cpu(setup->wValue) >> 8) {
+- case USB_DT_DEVICE:
+- // send device descriptor!
+- desc_len = desc_len > dev->dev_desc->bLength ?
+- dev->dev_desc->bLength : desc_len;
+- dbg("sending device desc, size=%d", desc_len);
+- send_packet(dev, alloc_packet(&dev->ep[0], desc_len,
+- dev->dev_desc), 0);
+- break;
+- case USB_DT_CONFIG:
+- // If the config descr index in low-byte of
+- // setup->wValue is valid, send config descr,
+- // otherwise stall ep0.
+- if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
+- // send config descriptor!
+- if (desc_len <= USB_DT_CONFIG_SIZE) {
+- dbg("sending partial config desc, size=%d",
+- desc_len);
+- send_packet(dev,
+- alloc_packet(&dev->ep[0],
+- desc_len,
+- dev->conf_desc),
+- 0);
+- } else {
+- int len = le16_to_cpu(dev->conf_desc->wTotalLength);
+- dbg("sending whole config desc,"
+- " size=%d, our size=%d", desc_len, len);
+- desc_len = desc_len > len ? len : desc_len;
+- send_packet(dev,
+- alloc_packet(&dev->ep[0],
+- desc_len,
+- dev->full_conf_desc),
+- 0);
+- }
+- } else
+- endpoint_stall(&dev->ep[0]);
+- break;
+- case USB_DT_STRING:
+- // If the string descr index in low-byte of setup->wValue
+- // is valid, send string descr, otherwise stall ep0.
+- strnum = le16_to_cpu(setup->wValue) & 0xff;
+- if (strnum >= 0 && strnum < 6) {
+- struct usb_string_descriptor *desc =
+- dev->str_desc[strnum];
+- desc_len = desc_len > desc->bLength ?
+- desc->bLength : desc_len;
+- dbg("sending string desc %d", strnum);
+- send_packet(dev,
+- alloc_packet(&dev->ep[0], desc_len,
+- desc), 0);
+- } else
+- endpoint_stall(&dev->ep[0]);
+- break;
+- default:
+- // Invalid request
+- err("invalid get desc=%d, stalled",
+- le16_to_cpu(setup->wValue) >> 8);
+- endpoint_stall(&dev->ep[0]); // Stall endpoint 0
+- break;
+- }
+-
+- return STATUS_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- // TODO: implement
+- // there will be an OUT data stage (the descriptor to set)
+- return DATA_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- // send dev->configuration
+- dbg("sending config");
+- send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration),
+- 0);
+- return STATUS_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- // set active config to low-byte of setup->wValue
+- dev->configuration = le16_to_cpu(setup->wValue) & 0xff;
+- dbg("set config, config=%d", dev->configuration);
+- if (!dev->configuration && dev->state > DEFAULT) {
+- dev->state = ADDRESS;
+- /* inform function layer of usbdev state change */
+- dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
+- } else if (dev->configuration == 1) {
+- dev->state = CONFIGURED;
+- /* inform function layer of usbdev state change */
+- dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
+- } else {
+- // FIXME: "respond with request error" - how?
+- }
+-
+- return SETUP_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- // interface must be zero.
+- if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) {
+- // FIXME: respond with "request error". how?
+- } else if (dev->state == CONFIGURED) {
+- // send dev->alternate_setting
+- dbg("sending alt setting");
+- send_packet(dev, alloc_packet(&dev->ep[0], 1,
+- &dev->alternate_setting), 0);
+- }
+-
+- return STATUS_STAGE;
+-
+-}
+-
+-static ep0_stage_t
+-do_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- if (dev->state == ADDRESS) {
+- // FIXME: respond with "request error". how?
+- } else if (dev->state == CONFIGURED) {
+- dev->interface = le16_to_cpu(setup->wIndex) & 0xff;
+- dev->alternate_setting =
+- le16_to_cpu(setup->wValue) & 0xff;
+- // interface and alternate_setting must be zero
+- if (dev->interface || dev->alternate_setting) {
+- // FIXME: respond with "request error". how?
+- }
+- }
+-
+- return SETUP_STAGE;
+-}
+-
+-static ep0_stage_t
+-do_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- // TODO
+- return SETUP_STAGE;
+-}
+-
+-typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev,
+- struct usb_ctrlrequest* setup);
+-
+-
+-/* Table of the standard device request handlers */
+-static const req_method_t req_method[] = {
+- do_get_status,
+- do_clear_feature,
+- do_reserved,
+- do_set_feature,
+- do_reserved,
+- do_set_address,
+- do_get_descriptor,
+- do_set_descriptor,
+- do_get_configuration,
+- do_set_configuration,
+- do_get_interface,
+- do_set_interface,
+- do_synch_frame
+-};
+-
+-
+-// SETUP packet request dispatcher
+-static void
+-do_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup)
+-{
+- req_method_t m;
+-
+- dbg("%s: req %d %s", __FUNCTION__, setup->bRequestType,
+- get_std_req_name(setup->bRequestType));
+-
+- if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
+- (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) {
+- err("%s: invalid requesttype 0x%02x", __FUNCTION__,
+- setup->bRequestType);
+- return;
+- }
+-
+- if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength)
+- dbg("%s: OUT phase! length=%d", __FUNCTION__, setup->wLength);
+-
+- if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t))
+- m = req_method[setup->bRequestType];
+- else
+- m = do_reserved;
+-
+- dev->ep0_stage = (*m)(dev, setup);
+-}
+-
+-/*
+- * A SETUP, DATA0, or DATA1 packet has been received
+- * on the default control endpoint's fifo.
+- */
+-static void
+-process_ep0_receive (struct usb_dev* dev)
+-{
+- endpoint_t *ep0 = &dev->ep[0];
+- usbdev_pkt_t *pkt;
+-
+- spin_lock(&ep0->lock);
+-
+- // complete packet and prepare a new packet
+- pkt = receive_packet_complete(ep0);
+- if (!pkt) {
+- // FIXME: should put a warn/err here.
+- spin_unlock(&ep0->lock);
+- return;
+- }
+-
+- // unlink immediately from endpoint.
+- unlink_head(&ep0->outlist);
+-
+- // override current stage if h/w says it's a setup packet
+- if (pkt->status & PKT_STATUS_SU)
+- dev->ep0_stage = SETUP_STAGE;
+-
+- switch (dev->ep0_stage) {
+- case SETUP_STAGE:
+- vdbg("SU bit is %s in setup stage",
+- (pkt->status & PKT_STATUS_SU) ? "set" : "not set");
+-
+- if (pkt->size == sizeof(struct usb_ctrlrequest)) {
+-#ifdef VDEBUG
+- if (pkt->status & PKT_STATUS_ACK)
+- vdbg("received SETUP");
+- else
+- vdbg("received NAK SETUP");
+-#endif
+- do_setup(dev, (struct usb_ctrlrequest*)pkt->payload);
+- } else
+- err("%s: wrong size SETUP received", __FUNCTION__);
+- break;
+- case DATA_STAGE:
+- /*
+- * this setup has an OUT data stage. Of the standard
+- * device requests, only set_descriptor has this stage,
+- * so this packet is that descriptor. TODO: drop it for
+- * now, set_descriptor not implemented.
+- *
+- * Need to place a byte in the write FIFO here, to prepare
+- * to send a zero-length DATA ack packet to the host in the
+- * STATUS stage.
+- */
+- au_writel(0, ep0->reg->write_fifo);
+- dbg("received OUT stage DATAx on EP0, size=%d", pkt->size);
+- dev->ep0_stage = SETUP_STAGE;
+- break;
+- case STATUS_STAGE:
+- // this setup had an IN data stage, and host is ACK'ing
+- // the packet we sent during that stage.
+- if (pkt->size != 0)
+- warn("received non-zero ACK on EP0??");
+-#ifdef VDEBUG
+- else
+- vdbg("received ACK on EP0");
+-#endif
+- dev->ep0_stage = SETUP_STAGE;
+- break;
+- }
+-
+- spin_unlock(&ep0->lock);
+- // we're done processing the packet, free it
+- kfree(pkt);
+-}
+-
+-
+-/*
+- * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5)
+- */
+-static void
+-process_ep_receive (struct usb_dev* dev, endpoint_t *ep)
+-{
+- usbdev_pkt_t *pkt;
+-
+- spin_lock(&ep->lock);
+- pkt = receive_packet_complete(ep);
+- spin_unlock(&ep->lock);
+-
+- dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data);
+-}
+-
+-
+-
+-/* This ISR handles the receive complete and suspend events */
+-static void
+-req_sus_intr (int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct usb_dev *dev = (struct usb_dev *) dev_id;
+- u32 status;
+-
+- status = au_readl(USBD_INTSTAT);
+- au_writel(status, USBD_INTSTAT); // ack'em
+-
+- if (status & (1<<0))
+- process_ep0_receive(dev);
+- if (status & (1<<4))
+- process_ep_receive(dev, &dev->ep[4]);
+- if (status & (1<<5))
+- process_ep_receive(dev, &dev->ep[5]);
+-}
+-
+-
+-/* This ISR handles the DMA done events on EP0 */
+-static void
+-dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct usb_dev *dev = (struct usb_dev *) dev_id;
+- usbdev_pkt_t* pkt;
+- endpoint_t *ep0 = &dev->ep[0];
+- u32 cs0, buff_done;
+-
+- spin_lock(&ep0->lock);
+- cs0 = au_readl(ep0->reg->ctrl_stat);
+-
+- // first check packet transmit done
+- if ((buff_done = get_dma_buffer_done(ep0->indma)) != 0) {
+- // transmitted a DATAx packet during DATA stage
+- // on control endpoint 0
+- // clear DMA done bit
+- if (buff_done & DMA_D0)
+- clear_dma_done0(ep0->indma);
+- if (buff_done & DMA_D1)
+- clear_dma_done1(ep0->indma);
+-
+- pkt = send_packet_complete(ep0);
+- kfree(pkt);
+- }
+-
+- /*
+- * Now check packet receive done. Shouldn't get these,
+- * the receive packet complete intr should happen
+- * before the DMA done intr occurs.
+- */
+- if ((buff_done = get_dma_buffer_done(ep0->outdma)) != 0) {
+- // clear DMA done bit
+- if (buff_done & DMA_D0)
+- clear_dma_done0(ep0->outdma);
+- if (buff_done & DMA_D1)
+- clear_dma_done1(ep0->outdma);
+-
+- //process_ep0_receive(dev);
+- }
+-
+- spin_unlock(&ep0->lock);
+-}
+-
+-/* This ISR handles the DMA done events on endpoints 2,3,4,5 */
+-static void
+-dma_done_ep_intr(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct usb_dev *dev = (struct usb_dev *) dev_id;
+- int i;
+-
+- for (i = 2; i < 6; i++) {
+- u32 buff_done;
+- usbdev_pkt_t* pkt;
+- endpoint_t *ep = &dev->ep[i];
+-
+- if (!ep->active) continue;
+-
+- spin_lock(&ep->lock);
+-
+- if (ep->direction == USB_DIR_IN) {
+- buff_done = get_dma_buffer_done(ep->indma);
+- if (buff_done != 0) {
+- // transmitted a DATAx pkt on the IN ep
+- // clear DMA done bit
+- if (buff_done & DMA_D0)
+- clear_dma_done0(ep->indma);
+- if (buff_done & DMA_D1)
+- clear_dma_done1(ep->indma);
+-
+- pkt = send_packet_complete(ep);
+-
+- spin_unlock(&ep->lock);
+- dev->func_cb(CB_PKT_COMPLETE,
+- (unsigned long)pkt,
+- dev->cb_data);
+- spin_lock(&ep->lock);
+- }
+- } else {
+- /*
+- * Check packet receive done (OUT ep). Shouldn't get
+- * these, the rx packet complete intr should happen
+- * before the DMA done intr occurs.
+- */
+- buff_done = get_dma_buffer_done(ep->outdma);
+- if (buff_done != 0) {
+- // received a DATAx pkt on the OUT ep
+- // clear DMA done bit
+- if (buff_done & DMA_D0)
+- clear_dma_done0(ep->outdma);
+- if (buff_done & DMA_D1)
+- clear_dma_done1(ep->outdma);
+-
+- //process_ep_receive(dev, ep);
+- }
+- }
+-
+- spin_unlock(&ep->lock);
+- }
+-}
+-
+-
+-/***************************************************************************
+- * Here begins the external interface functions
+- ***************************************************************************
+- */
+-
+-/*
+- * allocate a new packet
+- */
+-int
+-usbdev_alloc_packet(int ep_addr, int data_size, usbdev_pkt_t** pkt)
+-{
+- endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
+- usbdev_pkt_t* lpkt = NULL;
+-
+- if (!ep || !ep->active || ep->address < 2)
+- return -ENODEV;
+- if (data_size > ep->max_pkt_size)
+- return -EINVAL;
+-
+- lpkt = *pkt = alloc_packet(ep, data_size, NULL);
+- if (!lpkt)
+- return -ENOMEM;
+- return 0;
+-}
+-
+-
+-/*
+- * packet send
+- */
+-int
+-usbdev_send_packet(int ep_addr, usbdev_pkt_t * pkt)
+-{
+- unsigned long flags;
+- int count;
+- endpoint_t * ep;
+-
+- if (!pkt || !(ep = epaddr_to_ep(&usbdev, pkt->ep_addr)) ||
+- !ep->active || ep->address < 2)
+- return -ENODEV;
+- if (ep->direction != USB_DIR_IN)
+- return -EINVAL;
+-
+- spin_lock_irqsave(&ep->lock, flags);
+- count = send_packet(&usbdev, pkt, 1);
+- spin_unlock_irqrestore(&ep->lock, flags);
+-
+- return count;
+-}
+-
+-/*
+- * packet receive
+- */
+-int
+-usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt)
+-{
+- unsigned long flags;
+- usbdev_pkt_t* lpkt = NULL;
+- endpoint_t *ep = epaddr_to_ep(&usbdev, ep_addr);
+-
+- if (!ep || !ep->active || ep->address < 2)
+- return -ENODEV;
+- if (ep->direction != USB_DIR_OUT)
+- return -EINVAL;
+-
+- spin_lock_irqsave(&ep->lock, flags);
+- if (ep->outlist.count > 1)
+- lpkt = unlink_head(&ep->outlist);
+- spin_unlock_irqrestore(&ep->lock, flags);
+-
+- if (!lpkt) {
+- /* no packet available */
+- *pkt = NULL;
+- return -ENODATA;
+- }
+-
+- *pkt = lpkt;
+-
+- return lpkt->size;
+-}
+-
+-
+-/*
+- * return total queued byte count on the endpoint.
+- */
+-int
+-usbdev_get_byte_count(int ep_addr)
+-{
+- unsigned long flags;
+- pkt_list_t *list;
+- usbdev_pkt_t *scan;
+- int count = 0;
+- endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
+-
+- if (!ep || !ep->active || ep->address < 2)
+- return -ENODEV;
+-
+- if (ep->direction == USB_DIR_IN) {
+- list = &ep->inlist;
+-
+- spin_lock_irqsave(&ep->lock, flags);
+- for (scan = list->head; scan; scan = scan->next)
+- count += scan->size;
+- spin_unlock_irqrestore(&ep->lock, flags);
+- } else {
+- list = &ep->outlist;
+-
+- spin_lock_irqsave(&ep->lock, flags);
+- if (list->count > 1) {
+- for (scan = list->head; scan != list->tail;
+- scan = scan->next)
+- count += scan->size;
+- }
+- spin_unlock_irqrestore(&ep->lock, flags);
+- }
+-
+- return count;
+-}
+-
+-
+-void
+-usbdev_exit(void)
+-{
+- endpoint_t *ep;
+- int i;
+-
+- au_writel(0, USBD_INTEN); // disable usb dev ints
+- au_writel(0, USBD_ENABLE); // disable usb dev
+-
+- free_irq(AU1000_USB_DEV_REQ_INT, &usbdev);
+- free_irq(AU1000_USB_DEV_SUS_INT, &usbdev);
+-
+- // free all control endpoint resources
+- ep = &usbdev.ep[0];
+- free_au1000_dma(ep->indma);
+- free_au1000_dma(ep->outdma);
+- endpoint_flush(ep);
+-
+- // free ep resources
+- for (i = 2; i < 6; i++) {
+- ep = &usbdev.ep[i];
+- if (!ep->active) continue;
+-
+- if (ep->direction == USB_DIR_IN) {
+- free_au1000_dma(ep->indma);
+- } else {
+- free_au1000_dma(ep->outdma);
+- }
+- endpoint_flush(ep);
+- }
+-
+- kfree(usbdev.full_conf_desc);
+-}
+-
+-int
+-usbdev_init(struct usb_device_descriptor* dev_desc,
+- struct usb_config_descriptor* config_desc,
+- struct usb_interface_descriptor* if_desc,
+- struct usb_endpoint_descriptor* ep_desc,
+- struct usb_string_descriptor* str_desc[],
+- void (*cb)(usbdev_cb_type_t, unsigned long, void *),
+- void* cb_data)
+-{
+- endpoint_t *ep0;
+- int i, ret=0;
+- u8* fcd;
+-
+- if (dev_desc->bNumConfigurations > 1 ||
+- config_desc->bNumInterfaces > 1 ||
+- if_desc->bNumEndpoints > 4) {
+- err("Only one config, one i/f, and no more "
+- "than 4 ep's allowed");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- if (!cb) {
+- err("Function-layer callback required");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- if (dev_desc->bMaxPacketSize0 != USBDEV_EP0_MAX_PACKET_SIZE) {
+- warn("EP0 Max Packet size must be %d",
+- USBDEV_EP0_MAX_PACKET_SIZE);
+- dev_desc->bMaxPacketSize0 = USBDEV_EP0_MAX_PACKET_SIZE;
+- }
+-
+- memset(&usbdev, 0, sizeof(struct usb_dev));
+-
+- usbdev.state = DEFAULT;
+- usbdev.dev_desc = dev_desc;
+- usbdev.if_desc = if_desc;
+- usbdev.conf_desc = config_desc;
+- for (i=0; i<6; i++)
+- usbdev.str_desc[i] = str_desc[i];
+- usbdev.func_cb = cb;
+- usbdev.cb_data = cb_data;
+-
+- /* Initialize default control endpoint */
+- ep0 = &usbdev.ep[0];
+- ep0->active = 1;
+- ep0->type = CONTROL_EP;
+- ep0->max_pkt_size = USBDEV_EP0_MAX_PACKET_SIZE;
+- spin_lock_init(&ep0->lock);
+- ep0->desc = NULL; // ep0 has no descriptor
+- ep0->address = 0;
+- ep0->direction = 0;
+- ep0->reg = &ep_reg[0];
+-
+- /* Initialize the other requested endpoints */
+- for (i = 0; i < if_desc->bNumEndpoints; i++) {
+- struct usb_endpoint_descriptor* epd = &ep_desc[i];
+- endpoint_t *ep;
+-
+- if ((epd->bEndpointAddress & 0x80) == USB_DIR_IN) {
+- ep = &usbdev.ep[2];
+- ep->address = 2;
+- if (ep->active) {
+- ep = &usbdev.ep[3];
+- ep->address = 3;
+- if (ep->active) {
+- err("too many IN ep's requested");
+- ret = -ENODEV;
+- goto out;
+- }
+- }
+- } else {
+- ep = &usbdev.ep[4];
+- ep->address = 4;
+- if (ep->active) {
+- ep = &usbdev.ep[5];
+- ep->address = 5;
+- if (ep->active) {
+- err("too many OUT ep's requested");
+- ret = -ENODEV;
+- goto out;
+- }
+- }
+- }
+-
+- ep->active = 1;
+- epd->bEndpointAddress &= ~0x0f;
+- epd->bEndpointAddress |= (u8)ep->address;
+- ep->direction = epd->bEndpointAddress & 0x80;
+- ep->type = epd->bmAttributes & 0x03;
+- ep->max_pkt_size = le16_to_cpu(epd->wMaxPacketSize);
+- spin_lock_init(&ep->lock);
+- ep->desc = epd;
+- ep->reg = &ep_reg[ep->address];
+- }
+-
+- /*
+- * initialize the full config descriptor
+- */
+- usbdev.full_conf_desc = fcd = kmalloc(le16_to_cpu(config_desc->wTotalLength),
+- ALLOC_FLAGS);
+- if (!fcd) {
+- err("failed to alloc full config descriptor");
+- ret = -ENOMEM;
+- goto out;
+- }
+-
+- memcpy(fcd, config_desc, USB_DT_CONFIG_SIZE);
+- fcd += USB_DT_CONFIG_SIZE;
+- memcpy(fcd, if_desc, USB_DT_INTERFACE_SIZE);
+- fcd += USB_DT_INTERFACE_SIZE;
+- for (i = 0; i < if_desc->bNumEndpoints; i++) {
+- memcpy(fcd, &ep_desc[i], USB_DT_ENDPOINT_SIZE);
+- fcd += USB_DT_ENDPOINT_SIZE;
+- }
+-
+- /* Now we're ready to enable the controller */
+- au_writel(0x0002, USBD_ENABLE);
+- udelay(100);
+- au_writel(0x0003, USBD_ENABLE);
+- udelay(100);
+-
+- /* build and send config table based on ep descriptors */
+- for (i = 0; i < 6; i++) {
+- endpoint_t *ep;
+- if (i == 1)
+- continue; // skip dummy ep
+- ep = &usbdev.ep[i];
+- if (ep->active) {
+- au_writel((ep->address << 4) | 0x04, USBD_CONFIG);
+- au_writel(((ep->max_pkt_size & 0x380) >> 7) |
+- (ep->direction >> 4) | (ep->type << 4),
+- USBD_CONFIG);
+- au_writel((ep->max_pkt_size & 0x7f) << 1, USBD_CONFIG);
+- au_writel(0x00, USBD_CONFIG);
+- au_writel(ep->address, USBD_CONFIG);
+- } else {
+- u8 dir = (i==2 || i==3) ? DIR_IN : DIR_OUT;
+- au_writel((i << 4) | 0x04, USBD_CONFIG);
+- au_writel(((16 & 0x380) >> 7) | dir |
+- (BULK_EP << 4), USBD_CONFIG);
+- au_writel((16 & 0x7f) << 1, USBD_CONFIG);
+- au_writel(0x00, USBD_CONFIG);
+- au_writel(i, USBD_CONFIG);
+- }
+- }
+-
+- /*
+- * Enable Receive FIFO Complete interrupts only. Transmit
+- * complete is being handled by the DMA done interrupts.
+- */
+- au_writel(0x31, USBD_INTEN);
+-
+- /*
+- * Controller is now enabled, request DMA and IRQ
+- * resources.
+- */
+-
+- /* request the USB device transfer complete interrupt */
+- if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, IRQF_DISABLED,
+- "USBdev req", &usbdev)) {
+- err("Can't get device request intr");
+- ret = -ENXIO;
+- goto out;
+- }
+- /* request the USB device suspend interrupt */
+- if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, IRQF_DISABLED,
+- "USBdev sus", &usbdev)) {
+- err("Can't get device suspend intr");
+- ret = -ENXIO;
+- goto out;
+- }
+-
+- /* Request EP0 DMA and IRQ */
+- if ((ep0->indma = request_au1000_dma(ep_dma_id[0].id,
+- ep_dma_id[0].str,
+- dma_done_ep0_intr,
+- IRQF_DISABLED,
+- &usbdev)) < 0) {
+- err("Can't get %s DMA", ep_dma_id[0].str);
+- ret = -ENXIO;
+- goto out;
+- }
+- if ((ep0->outdma = request_au1000_dma(ep_dma_id[1].id,
+- ep_dma_id[1].str,
+- NULL, 0, NULL)) < 0) {
+- err("Can't get %s DMA", ep_dma_id[1].str);
+- ret = -ENXIO;
+- goto out;
+- }
+-
+- // Flush the ep0 buffers and FIFOs
+- endpoint_flush(ep0);
+- // start packet reception on ep0
+- kickstart_receive_packet(ep0);
+-
+- /* Request DMA and IRQ for the other endpoints */
+- for (i = 2; i < 6; i++) {
+- endpoint_t *ep = &usbdev.ep[i];
+- if (!ep->active)
+- continue;
+-
+- // Flush the endpoint buffers and FIFOs
+- endpoint_flush(ep);
+-
+- if (ep->direction == USB_DIR_IN) {
+- ep->indma =
+- request_au1000_dma(ep_dma_id[ep->address].id,
+- ep_dma_id[ep->address].str,
+- dma_done_ep_intr,
+- IRQF_DISABLED,
+- &usbdev);
+- if (ep->indma < 0) {
+- err("Can't get %s DMA",
+- ep_dma_id[ep->address].str);
+- ret = -ENXIO;
+- goto out;
+- }
+- } else {
+- ep->outdma =
+- request_au1000_dma(ep_dma_id[ep->address].id,
+- ep_dma_id[ep->address].str,
+- NULL, 0, NULL);
+- if (ep->outdma < 0) {
+- err("Can't get %s DMA",
+- ep_dma_id[ep->address].str);
+- ret = -ENXIO;
+- goto out;
+- }
+-
+- // start packet reception on OUT endpoint
+- kickstart_receive_packet(ep);
+- }
+- }
+-
+- out:
+- if (ret)
+- usbdev_exit();
+- return ret;
+-}
+-
+-EXPORT_SYMBOL(usbdev_init);
+-EXPORT_SYMBOL(usbdev_exit);
+-EXPORT_SYMBOL(usbdev_alloc_packet);
+-EXPORT_SYMBOL(usbdev_receive_packet);
+-EXPORT_SYMBOL(usbdev_send_packet);
+-EXPORT_SYMBOL(usbdev_get_byte_count);
+diff --git a/arch/mips/au1000/db1x00/Makefile b/arch/mips/au1000/db1x00/Makefile
+index 4c7d763..51d62bd 100644
+--- a/arch/mips/au1000/db1x00/Makefile
++++ b/arch/mips/au1000/db1x00/Makefile
+@@ -6,4 +6,3 @@
+ # Makefile for the Alchemy Semiconductor Db1x00 board.
+
+ lib-y := init.o board_setup.o irqmap.o
+-obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o
+diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c
+index 7a79293..8b08edb 100644
+--- a/arch/mips/au1000/db1x00/board_setup.c
++++ b/arch/mips/au1000/db1x00/board_setup.c
+@@ -58,11 +58,6 @@ void __init board_setup(void)
+
+ pin_func = 0;
+ /* not valid for 1550 */
+-#ifdef CONFIG_AU1X00_USB_DEVICE
+- // 2nd USB port is USB device
+- pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+- au_writel(pin_func, SYS_PINFUNC);
+-#endif
+
+ #if defined(CONFIG_IRDA) && (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100))
+ /* set IRFIRSEL instead of GPIO15 */
+diff --git a/arch/mips/au1000/db1x00/mirage_ts.c b/arch/mips/au1000/db1x00/mirage_ts.c
+deleted file mode 100644
+index 0942dcf..0000000
+--- a/arch/mips/au1000/db1x00/mirage_ts.c
++++ /dev/null
+@@ -1,260 +0,0 @@
+-/*
+- * linux/arch/mips/au1000/db1x00/mirage_ts.c
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Glue between Mirage board-specific touchscreen pieces
+- * and generic Wolfson Codec touchscreen support.
+- *
+- * Based on pb1100_ts.c used in Hydrogen II.
+- *
+- * Copyright (c) 2003 Embedded Edge, LLC
+- * dan at embeddededge.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 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/types.h>
+-#include <linux/module.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/fs.h>
+-#include <linux/poll.h>
+-#include <linux/proc_fs.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+-#include <linux/wait.h>
+-
+-#include <asm/segment.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-#include <asm/delay.h>
+-#include <asm/au1000.h>
+-
+-/*
+- * Imported interface to Wolfson Codec driver.
+- */
+-extern void *wm97xx_ts_get_handle(int which);
+-extern int wm97xx_ts_ready(void* ts_handle);
+-extern void wm97xx_ts_set_cal(void* ts_handle, int xscale, int xtrans, int yscale, int ytrans);
+-extern u16 wm97xx_ts_get_ac97(void* ts_handle, u8 reg);
+-extern void wm97xx_ts_set_ac97(void* ts_handle, u8 reg, u16 val);
+-extern int wm97xx_ts_read_data(void* ts_handle, long* x, long* y, long* pressure);
+-extern void wm97xx_ts_send_data(void* ts_handle, long x, long y, long z);
+-
+-int wm97xx_comodule_present = 1;
+-
+-
+-#define TS_NAME "mirage_ts"
+-
+-#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
+-#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
+-#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
+-#define DPRINTK(format, arg...) printk("%s: " format "\n", __FUNCTION__ , ## arg)
+-
+-
+-#define PEN_DOWN_IRQ AU1000_GPIO_7
+-
+-static struct task_struct *ts_task = 0;
+-static DECLARE_COMPLETION(ts_complete);
+-static DECLARE_WAIT_QUEUE_HEAD(pendown_wait);
+-
+-#ifdef CONFIG_WM97XX_FIVEWIRETS
+-static int release_pressure = 1;
+-#else
+-static int release_pressure = 50;
+-#endif
+-
+-typedef struct {
+- long x;
+- long y;
+-} DOWN_EVENT;
+-
+-#define SAMPLE_RATE 50 /* samples per second */
+-#define PEN_DEBOUNCE 5 /* samples for settling - fn of SAMPLE_RATE */
+-#define PEN_UP_TIMEOUT 10 /* in seconds */
+-#define PEN_UP_SETTLE 5 /* samples per second */
+-
+-static struct {
+- int xscale;
+- int xtrans;
+- int yscale;
+- int ytrans;
+-} mirage_ts_cal =
+-{
+-#if 0
+- .xscale = 84,
+- .xtrans = -157,
+- .yscale = 66,
+- .ytrans = -150,
+-#else
+- .xscale = 84,
+- .xtrans = -150,
+- .yscale = 66,
+- .ytrans = -146,
+-#endif
+-};
+-
+-
+-static void pendown_irq(int irqnr, void *devid, struct pt_regs *regs)
+-{
+-//DPRINTK("got one 0x%x", au_readl(SYS_PINSTATERD));
+- wake_up(&pendown_wait);
+-}
+-
+-static int ts_thread(void *id)
+-{
+- static int pen_was_down = 0;
+- static DOWN_EVENT pen_xy;
+- long x, y, z;
+- void *ts; /* handle */
+- struct task_struct *tsk = current;
+- int timeout = HZ / SAMPLE_RATE;
+-
+- ts_task = tsk;
+-
+- daemonize();
+- tsk->tty = NULL;
+- tsk->policy = SCHED_FIFO;
+- tsk->rt_priority = 1;
+- strcpy(tsk->comm, "touchscreen");
+-
+- /* only want to receive SIGKILL */
+- spin_lock_irq(&tsk->sigmask_lock);
+- siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
+- recalc_sigpending(tsk);
+- spin_unlock_irq(&tsk->sigmask_lock);
+-
+- /* get handle for codec */
+- ts = wm97xx_ts_get_handle(0);
+-
+- /* proceed only after everybody is ready */
+- wait_event_timeout(pendown_wait, wm97xx_ts_ready(ts), HZ/4);
+-
+- /* board-specific calibration */
+- wm97xx_ts_set_cal(ts,
+- mirage_ts_cal.xscale,
+- mirage_ts_cal.xtrans,
+- mirage_ts_cal.yscale,
+- mirage_ts_cal.ytrans);
+-
+- /* route Wolfson pendown interrupts to our GPIO */
+- au_sync();
+- wm97xx_ts_set_ac97(ts, 0x4c, wm97xx_ts_get_ac97(ts, 0x4c) & ~0x0008);
+- au_sync();
+- wm97xx_ts_set_ac97(ts, 0x56, wm97xx_ts_get_ac97(ts, 0x56) & ~0x0008);
+- au_sync();
+- wm97xx_ts_set_ac97(ts, 0x52, wm97xx_ts_get_ac97(ts, 0x52) | 0x2008);
+- au_sync();
+-
+- for (;;) {
+- interruptible_sleep_on_timeout(&pendown_wait, timeout);
+- disable_irq(PEN_DOWN_IRQ);
+- if (signal_pending(tsk)) {
+- break;
+- }
+-
+- /* read codec */
+- if (!wm97xx_ts_read_data(ts, &x, &y, &z))
+- z = 0; /* treat no-data and pen-up the same */
+-
+- if (signal_pending(tsk)) {
+- break;
+- }
+-
+- if (z >= release_pressure) {
+- y = ~y; /* top to bottom */
+- if (pen_was_down > 1 /*&& pen_was_down < PEN_DEBOUNCE*/) {//THXXX
+- /* bounce ? */
+- x = pen_xy.x;
+- y = pen_xy.y;
+- --pen_was_down;
+- } else if (pen_was_down <= 1) {
+- pen_xy.x = x;
+- pen_xy.y = y;
+- if (pen_was_down)
+- wm97xx_ts_send_data(ts, x, y, z);
+- pen_was_down = PEN_DEBOUNCE;
+- }
+- //wm97xx_ts_send_data(ts, x, y, z);
+- timeout = HZ / SAMPLE_RATE;
+- } else {
+- if (pen_was_down) {
+- if (--pen_was_down)
+- z = release_pressure;
+- else //THXXX
+- wm97xx_ts_send_data(ts, pen_xy.x, pen_xy.y, z);
+- }
+- /* The pendown signal takes some time to settle after
+- * reading the pen pressure so wait a little
+- * before enabling the pen.
+- */
+- if (! pen_was_down) {
+-// interruptible_sleep_on_timeout(&pendown_wait, HZ / PEN_UP_SETTLE);
+- timeout = HZ * PEN_UP_TIMEOUT;
+- }
+- }
+- enable_irq(PEN_DOWN_IRQ);
+- }
+- enable_irq(PEN_DOWN_IRQ);
+- ts_task = NULL;
+- complete(&ts_complete);
+- return 0;
+-}
+-
+-static int __init ts_mirage_init(void)
+-{
+- int ret;
+-
+- /* pen down signal is connected to GPIO 7 */
+-
+- ret = request_irq(PEN_DOWN_IRQ, pendown_irq, 0, "ts-pendown", NULL);
+- if (ret) {
+- err("unable to get pendown irq%d: [%d]", PEN_DOWN_IRQ, ret);
+- return ret;
+- }
+-
+- lock_kernel();
+- ret = kernel_thread(ts_thread, NULL, CLONE_FS | CLONE_FILES);
+- if (ret < 0) {
+- unlock_kernel();
+- return ret;
+- }
+- unlock_kernel();
+-
+- info("Mirage touchscreen IRQ initialized.");
+-
+- return 0;
+-}
+-
+-static void __exit ts_mirage_exit(void)
+-{
+- if (ts_task) {
+- send_sig(SIGKILL, ts_task, 1);
+- wait_for_completion(&ts_complete);
+- }
+-
+- free_irq(PEN_DOWN_IRQ, NULL);
+-}
+-
+-module_init(ts_mirage_init);
+-module_exit(ts_mirage_exit);
+-
+diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c
+index e917e54..13f9bf5 100644
+--- a/arch/mips/au1000/mtx-1/board_setup.c
++++ b/arch/mips/au1000/mtx-1/board_setup.c
+@@ -51,15 +51,11 @@ void board_reset (void)
+
+ void __init board_setup(void)
+ {
+-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+-#ifdef CONFIG_AU1X00_USB_DEVICE
+- // 2nd USB port is USB device
+- au_writel(au_readl(SYS_PINFUNC) & (u32)(~0x8000), SYS_PINFUNC);
+-#endif
++#ifdef CONFIG_USB_OHCI
+ // enable USB power switch
+ au_writel( au_readl(GPIO2_DIR) | 0x10, GPIO2_DIR );
+ au_writel( 0x100000, GPIO2_OUTPUT );
+-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#endif // defined (CONFIG_USB_OHCI)
+
+ #ifdef CONFIG_PCI
+ #if defined(__MIPSEB__)
+diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c
+index 1cf18e1..824cfaf 100644
+--- a/arch/mips/au1000/pb1000/board_setup.c
++++ b/arch/mips/au1000/pb1000/board_setup.c
+@@ -54,7 +54,7 @@ void __init board_setup(void)
+ au_writel(0, SYS_PINSTATERD);
+ udelay(100);
+
+-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#ifdef CONFIG_USB_OHCI
+ /* zero and disable FREQ2 */
+ sys_freqctrl = au_readl(SYS_FREQCTRL0);
+ sys_freqctrl &= ~0xFFF00000;
+@@ -105,22 +105,18 @@ void __init board_setup(void)
+ #ifdef CONFIG_USB_OHCI
+ sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
+ #endif
+-#ifdef CONFIG_AU1X00_USB_DEVICE
+- sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
+-#endif
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+ // configure pins GPIO[14:9] as GPIO
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080);
+
+-#ifndef CONFIG_AU1X00_USB_DEVICE
+ // 2nd USB port is USB host
+ pin_func |= 0x8000;
+-#endif
++
+ au_writel(pin_func, SYS_PINFUNC);
+ au_writel(0x2800, SYS_TRIOUTCLR);
+ au_writel(0x0030, SYS_OUTPUTCLR);
+-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#endif // defined (CONFIG_USB_OHCI)
+
+ // make gpio 15 an input (for interrupt line)
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x100);
+diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c
+index db27b93..2d1533f 100644
+--- a/arch/mips/au1000/pb1100/board_setup.c
++++ b/arch/mips/au1000/pb1100/board_setup.c
+@@ -55,7 +55,7 @@ void __init board_setup(void)
+ au_writel(0, SYS_PININPUTEN);
+ udelay(100);
+
+-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#ifdef CONFIG_USB_OHCI
+ // configure pins GPIO[14:9] as GPIO
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
+
+@@ -92,12 +92,10 @@ void __init board_setup(void)
+
+ // get USB Functionality pin state (device vs host drive pins)
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+-#ifndef CONFIG_AU1X00_USB_DEVICE
+ // 2nd USB port is USB host
+ pin_func |= 0x8000;
+-#endif
+ au_writel(pin_func, SYS_PINFUNC);
+-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#endif // defined (CONFIG_USB_OHCI)
+
+ /* Enable sys bus clock divider when IDLE state or no bus activity. */
+ au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
+diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
+index f66779f..91983ba 100644
+--- a/arch/mips/au1000/pb1200/irqmap.c
++++ b/arch/mips/au1000/pb1200/irqmap.c
+@@ -65,7 +65,7 @@ int __initdata au1xxx_nr_irqs = ARRAY_SI
+ */
+ static volatile int pb1200_cascade_en=0;
+
+-irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t pb1200_cascade_handler( int irq, void *dev_id)
+ {
+ unsigned short bisr = bcsr->int_status;
+ int extirq_nr = 0;
+@@ -76,8 +76,9 @@ irqreturn_t pb1200_cascade_handler( int
+ {
+ extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr);
+ /* Ack and dispatch IRQ */
+- do_IRQ(extirq_nr,regs);
++ do_IRQ(extirq_nr);
+ }
++
+ return IRQ_RETVAL(1);
+ }
+
+diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c
+index 1a9a293..0ffdb4f 100644
+--- a/arch/mips/au1000/pb1500/board_setup.c
++++ b/arch/mips/au1000/pb1500/board_setup.c
+@@ -56,7 +56,7 @@ void __init board_setup(void)
+ au_writel(0, SYS_PINSTATERD);
+ udelay(100);
+
+-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#ifdef CONFIG_USB_OHCI
+
+ /* GPIO201 is input for PCMCIA card detect */
+ /* GPIO203 is input for PCMCIA interrupt request */
+@@ -88,19 +88,14 @@ void __init board_setup(void)
+ #ifdef CONFIG_USB_OHCI
+ sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
+ #endif
+-#ifdef CONFIG_AU1X00_USB_DEVICE
+- sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
+-#endif
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+-#ifndef CONFIG_AU1X00_USB_DEVICE
+ // 2nd USB port is USB host
+ pin_func |= 0x8000;
+-#endif
+ au_writel(pin_func, SYS_PINFUNC);
+-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#endif // defined (CONFIG_USB_OHCI)
+
+
+
+diff --git a/arch/mips/basler/excite/excite_dbg_io.c b/arch/mips/basler/excite/excite_dbg_io.c
+index c04505a..d289e3a 100644
+--- a/arch/mips/basler/excite/excite_dbg_io.c
++++ b/arch/mips/basler/excite/excite_dbg_io.c
+@@ -112,7 +112,7 @@ int putDebugChar(int data)
+ }
+
+ /* KGDB interrupt handler */
+-asmlinkage void excite_kgdb_inthdl(struct pt_regs *regs)
++asmlinkage void excite_kgdb_inthdl(void)
+ {
+ if (unlikely(
+ ((titan_readl(UAIIR) & 0x7) == 4)
+diff --git a/arch/mips/basler/excite/excite_device.c b/arch/mips/basler/excite/excite_device.c
+index bbb4ea4..cc1ce77 100644
+--- a/arch/mips/basler/excite/excite_device.c
++++ b/arch/mips/basler/excite/excite_device.c
+@@ -68,7 +68,7 @@ enum {
+
+
+ static struct resource
+- excite_ctr_resource = {
++ excite_ctr_resource __attribute__((unused)) = {
+ .name = "GPI counters",
+ .start = 0,
+ .end = 5,
+@@ -77,7 +77,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_gpislice_resource = {
++ excite_gpislice_resource __attribute__((unused)) = {
+ .name = "GPI slices",
+ .start = 0,
+ .end = 1,
+@@ -86,7 +86,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_mdio_channel_resource = {
++ excite_mdio_channel_resource __attribute__((unused)) = {
+ .name = "MDIO channels",
+ .start = 0,
+ .end = 1,
+@@ -95,7 +95,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_fifomem_resource = {
++ excite_fifomem_resource __attribute__((unused)) = {
+ .name = "FIFO memory",
+ .start = 0,
+ .end = 767,
+@@ -104,7 +104,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_scram_resource = {
++ excite_scram_resource __attribute__((unused)) = {
+ .name = "Scratch RAM",
+ .start = EXCITE_PHYS_SCRAM,
+ .end = EXCITE_PHYS_SCRAM + EXCITE_SIZE_SCRAM - 1,
+@@ -113,7 +113,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_fpga_resource = {
++ excite_fpga_resource __attribute__((unused)) = {
+ .name = "System FPGA",
+ .start = EXCITE_PHYS_FPGA,
+ .end = EXCITE_PHYS_FPGA + EXCITE_SIZE_FPGA - 1,
+@@ -122,7 +122,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_nand_resource = {
++ excite_nand_resource __attribute__((unused)) = {
+ .name = "NAND flash control",
+ .start = EXCITE_PHYS_NAND,
+ .end = EXCITE_PHYS_NAND + EXCITE_SIZE_NAND - 1,
+@@ -131,7 +131,7 @@ static struct resource
+ .sibling = NULL,
+ .child = NULL
+ },
+- excite_titan_resource = {
++ excite_titan_resource __attribute__((unused)) = {
+ .name = "TITAN registers",
+ .start = EXCITE_PHYS_TITAN,
+ .end = EXCITE_PHYS_TITAN + EXCITE_SIZE_TITAN - 1,
+diff --git a/arch/mips/basler/excite/excite_flashtest.c b/arch/mips/basler/excite/excite_flashtest.c
+deleted file mode 100644
+index f0024a8..0000000
+--- a/arch/mips/basler/excite/excite_flashtest.c
++++ /dev/null
+@@ -1,294 +0,0 @@
+-/*
+-* Copyright (C) 2005 by Basler Vision Technologies AG
+-* Author: Thies Moeller <thies.moeller at baslerweb.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/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/delay.h>
+-#include <linux/err.h>
+-#include <linux/kernel.h>
+-
+-#include <excite.h>
+-
+-#include <asm/io.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/nand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <asm/rm9k-ocd.h> // for ocd_write
+-#include <linux/workqueue.h> // for queue
+-
+-#include "excite_nandflash.h"
+-#include "nandflash.h"
+-
+-#define PFX "excite flashtest: "
+-typedef void __iomem *io_reg_t;
+-
+-#define io_readb(__a__) __raw_readb((__a__))
+-#define io_writeb(__v__, __a__) __raw_writeb((__v__), (__a__))
+-
+-
+-
+-static inline const struct resource *excite_nandflash_get_resource(
+- struct platform_device *d, unsigned long flags, const char *basename)
+-{
+- const char fmt[] = "%s_%u";
+- char buf[80];
+-
+- if (unlikely(snprintf(buf, sizeof buf, fmt, basename, d->id) >= sizeof buf))
+- return NULL;
+-
+- return platform_get_resource_byname(d, flags, buf);
+-}
+-
+-static inline io_reg_t
+-excite_nandflash_map_regs(struct platform_device *d, const char *basename)
+-{
+- void *result = NULL;
+- const struct resource *const r =
+- excite_nandflash_get_resource(d, IORESOURCE_MEM, basename);
+- if (r)
+- result = ioremap_nocache(r->start, r->end + 1 - r->start);
+- return result;
+-}
+-
+-/* controller and mtd information */
+-
+-struct excite_nandflash_drvdata {
+- struct mtd_info board_mtd;
+- struct nand_chip board_chip;
+- io_reg_t regs;
+-};
+-
+-
+-/* command and control functions */
+-static void excite_nandflash_hwcontrol(struct mtd_info *mtd, int cmd)
+-{
+- struct nand_chip *this = mtd->priv;
+- io_reg_t regs = container_of(mtd,struct excite_nandflash_drvdata,board_mtd)->regs;
+-
+- switch (cmd) {
+- /* Select the command latch */
+- case NAND_CTL_SETCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_CMD;
+- break;
+- /* Deselect the command latch */
+- case NAND_CTL_CLRCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA;
+- break;
+- /* Select the address latch */
+- case NAND_CTL_SETALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_ADDR;
+- break;
+- /* Deselect the address latch */
+- case NAND_CTL_CLRALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA;
+- break;
+- /* Select the chip -- not used */
+- case NAND_CTL_SETNCE:
+- break;
+- /* Deselect the chip -- not used */
+- case NAND_CTL_CLRNCE:
+- break;
+- }
+-
+- this->IO_ADDR_R = this->IO_ADDR_W;
+-}
+-
+-/* excite_nandflash_devready()
+- *
+- * returns 0 if the nand is busy, 1 if it is ready
+- */
+-static int excite_nandflash_devready(struct mtd_info *mtd)
+-{
+- struct excite_nandflash_drvdata *drvdata =
+- container_of(mtd, struct excite_nandflash_drvdata, board_mtd);
+-
+- return io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS);
+-}
+-
+-/* device management functions */
+-
+-/* excite_nandflash_remove
+- *
+- * called by device layer to remove the driver
+- * the binding to the mtd and all allocated
+- * resources are released
+- */
+-static int excite_nandflash_remove(struct device *dev)
+-{
+- struct excite_nandflash_drvdata *this = dev_get_drvdata(dev);
+-
+- pr_info(PFX "remove");
+-
+- dev_set_drvdata(dev, NULL);
+-
+- if (this == NULL) {
+- pr_debug(PFX "call remove without private data!!");
+- return 0;
+- }
+-
+-
+- /* free the common resources */
+- if (this->regs != NULL) {
+- iounmap(this->regs);
+- this->regs = NULL;
+- }
+-
+- kfree(this);
+-
+- return 0;
+-}
+-
+-static int elapsed;
+-
+-void my_workqueue_handler(void *arg)
+-{
+- elapsed = 1;
+-}
+-
+-DECLARE_WORK(sigElapsed, my_workqueue_handler, 0);
+-
+-
+-/* excite_nandflash_probe
+- *
+- * called by device layer when it finds a device matching
+- * one our driver can handled. This code checks to see if
+- * it can allocate all necessary resources then calls the
+- * nand layer to look for devices
+-*/
+-static int excite_nandflash_probe(struct device *dev)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+-
+- struct excite_nandflash_drvdata *drvdata; /* private driver data */
+- struct nand_chip *board_chip; /* private flash chip data */
+- struct mtd_info *board_mtd; /* mtd info for this board */
+-
+- int err = 0;
+- int count = 0;
+- struct timeval tv,endtv;
+- unsigned int dt;
+-
+- pr_info(PFX "probe dev: (%p)\n", dev);
+-
+- pr_info(PFX "adjust LB timing\n");
+- ocd_writel(0x00000330, LDP2);
+-
+- drvdata = kmalloc(sizeof(*drvdata), GFP_KERNEL);
+- if (unlikely(!drvdata)) {
+- printk(KERN_ERR PFX "no memory for drvdata\n");
+- err = -ENOMEM;
+- goto mem_error;
+- }
+-
+- /* Initialize structures */
+- memset(drvdata, 0, sizeof(*drvdata));
+-
+- /* bind private data into driver */
+- dev_set_drvdata(dev, drvdata);
+-
+- /* allocate and map the resource */
+- drvdata->regs =
+- excite_nandflash_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS);
+-
+- if (unlikely(!drvdata->regs)) {
+- printk(KERN_ERR PFX "cannot reserve register region\n");
+- err = -ENXIO;
+- goto io_error;
+- }
+-
+- /* initialise our chip */
+- board_chip = &drvdata->board_chip;
+-
+- board_chip->IO_ADDR_R = drvdata->regs + EXCITE_NANDFLASH_DATA;
+- board_chip->IO_ADDR_W = drvdata->regs + EXCITE_NANDFLASH_DATA;
+-
+- board_chip->hwcontrol = excite_nandflash_hwcontrol;
+- board_chip->dev_ready = excite_nandflash_devready;
+-
+- board_chip->chip_delay = 25;
+- #if 0
+- /* TODO: speedup the initial scan */
+- board_chip->options = NAND_USE_FLASH_BBT;
+- #endif
+- board_chip->eccmode = NAND_ECC_SOFT;
+-
+- /* link chip to mtd */
+- board_mtd = &drvdata->board_mtd;
+- board_mtd->priv = board_chip;
+-
+-
+- pr_info(PFX "FlashTest\n");
+- elapsed = 0;
+-/* schedule_delayed_work(&sigElapsed, 1*HZ);
+- while (!elapsed) {
+- io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS);
+- count++;
+- }
+- pr_info(PFX "reads in 1 sec --> %d\n",count);
+-*/
+- do_gettimeofday(&tv);
+- for (count = 0 ; count < 1000000; count ++) {
+- io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS);
+- }
+- do_gettimeofday(&endtv);
+- dt = (endtv.tv_sec - tv.tv_sec) * 1000000 + endtv.tv_usec - tv.tv_usec;
+- pr_info(PFX "%8d us timeval\n",dt);
+- pr_info(PFX "EndFlashTest\n");
+-
+-/* return with error to unload everything
+-*/
+-io_error:
+- iounmap(drvdata->regs);
+-
+-mem_error:
+- kfree(drvdata);
+-
+- if (err == 0)
+- err = -EINVAL;
+- return err;
+-}
+-
+-static struct device_driver excite_nandflash_driver = {
+- .name = "excite_nand",
+- .bus = &platform_bus_type,
+- .probe = excite_nandflash_probe,
+- .remove = excite_nandflash_remove,
+-};
+-
+-static int __init excite_nandflash_init(void)
+-{
+- pr_info(PFX "register Driver (Rev: $Revision:$)\n");
+- return driver_register(&excite_nandflash_driver);
+-}
+-
+-static void __exit excite_nandflash_exit(void)
+-{
+- driver_unregister(&excite_nandflash_driver);
+- pr_info(PFX "Driver unregistered");
+-}
+-
+-module_init(excite_nandflash_init);
+-module_exit(excite_nandflash_exit);
+-
+-MODULE_AUTHOR("Thies Moeller <thies.moeller at baslerweb.com>");
+-MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver");
+-MODULE_LICENSE("GPL");
+diff --git a/arch/mips/basler/excite/excite_fpga.h b/arch/mips/basler/excite/excite_fpga.h
+deleted file mode 100644
+index 38fcda7..0000000
+--- a/arch/mips/basler/excite/excite_fpga.h
++++ /dev/null
+@@ -1,80 +0,0 @@
+-#ifndef EXCITE_FPGA_H_INCLUDED
+-#define EXCITE_FPGA_H_INCLUDED
+-
+-
+-/**
+- * Adress alignment of the individual FPGA bytes.
+- * The address arrangement of the individual bytes of the FPGA is two
+- * byte aligned at the embedded MK2 platform.
+- */
+-#ifdef EXCITE_CCI_FPGA_MK2
+-typedef unsigned char excite_cci_fpga_align_t __attribute__ ((aligned(2)));
+-#else
+-typedef unsigned char excite_cci_fpga_align_t;
+-#endif
+-
+-
+-/**
+- * Size of Dual Ported RAM.
+- */
+-#define EXCITE_DPR_SIZE 263
+-
+-
+-/**
+- * Size of Reserved Status Fields in Dual Ported RAM.
+- */
+-#define EXCITE_DPR_STATUS_SIZE 7
+-
+-
+-
+-/**
+- * FPGA.
+- * Hardware register layout of the FPGA interface. The FPGA must accessed
+- * byte wise solely.
+- * @see EXCITE_CCI_DPR_MK2
+- */
+-typedef struct excite_fpga {
+-
+- /**
+- * Dual Ported RAM.
+- */
+- excite_cci_fpga_align_t dpr[EXCITE_DPR_SIZE];
+-
+- /**
+- * Status.
+- */
+- excite_cci_fpga_align_t status[EXCITE_DPR_STATUS_SIZE];
+-
+-#ifdef EXCITE_CCI_FPGA_MK2
+- /**
+- * RM9000 Interrupt.
+- * Write access initiates interrupt at the RM9000 (MIPS) processor of the eXcite.
+- */
+- excite_cci_fpga_align_t rm9k_int;
+-#else
+- /**
+- * MK2 Interrupt.
+- * Write access initiates interrupt at the ARM processor of the MK2.
+- */
+- excite_cci_fpga_align_t mk2_int;
+-
+- excite_cci_fpga_align_t gap[0x1000-0x10f];
+-
+- /**
+- * IRQ Source/Acknowledge.
+- */
+- excite_cci_fpga_align_t rm9k_irq_src;
+-
+- /**
+- * IRQ Mask.
+- * Set bits enable the related interrupt.
+- */
+- excite_cci_fpga_align_t rm9k_irq_mask;
+-#endif
+-
+-
+-} excite_fpga;
+-
+-
+-
+-#endif /* ndef EXCITE_FPGA_H_INCLUDED */
+diff --git a/arch/mips/basler/excite/excite_iodev.c b/arch/mips/basler/excite/excite_iodev.c
+index 10bbb8c..6af0b21 100644
+--- a/arch/mips/basler/excite/excite_iodev.c
++++ b/arch/mips/basler/excite/excite_iodev.c
+@@ -38,7 +38,7 @@ static int iodev_open(struct inode *, st
+ static int iodev_release(struct inode *, struct file *);
+ static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *);
+ static unsigned int iodev_poll(struct file *, struct poll_table_struct *);
+-static irqreturn_t iodev_irqhdl(int, void *, struct pt_regs *);
++static irqreturn_t iodev_irqhdl(int, void *);
+
+
+
+@@ -108,16 +108,12 @@ static int __exit iodev_remove(struct de
+ return misc_deregister(&miscdev);
+ }
+
+-
+-
+ static int iodev_open(struct inode *i, struct file *f)
+ {
+ return request_irq(iodev_irq, iodev_irqhdl, IRQF_DISABLED,
+ iodev_name, &miscdev);
+ }
+
+-
+-
+ static int iodev_release(struct inode *i, struct file *f)
+ {
+ free_irq(iodev_irq, &miscdev);
+@@ -148,17 +144,13 @@ static unsigned int iodev_poll(struct fi
+ return POLLOUT | POLLWRNORM;
+ }
+
+-
+-
+-
+-static irqreturn_t iodev_irqhdl(int irq, void *ctxt, struct pt_regs *regs)
++static irqreturn_t iodev_irqhdl(int irq, void *ctxt)
+ {
+ wake_up(&wq);
++
+ return IRQ_HANDLED;
+ }
+
+-
+-
+ static int __init iodev_init_module(void)
+ {
+ return driver_register(&iodev_driver);
+diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c
+index 511ad87..2e2061a 100644
+--- a/arch/mips/basler/excite/excite_irq.c
++++ b/arch/mips/basler/excite/excite_irq.c
+@@ -56,7 +56,7 @@ void __init arch_init_irq(void)
+ #endif
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ const u32
+ interrupts = read_c0_cause() >> 8,
+@@ -67,7 +67,7 @@ asmlinkage void plat_irq_dispatch(struct
+
+ /* process timer interrupt */
+ if (pending & (1 << TIMER_IRQ)) {
+- do_IRQ(TIMER_IRQ, regs);
++ do_IRQ(TIMER_IRQ);
+ return;
+ }
+
+@@ -80,7 +80,7 @@ asmlinkage void plat_irq_dispatch(struct
+ #else
+ if (pending & (1 << USB_IRQ)) {
+ #endif
+- do_IRQ(USB_IRQ, regs);
++ do_IRQ(USB_IRQ);
+ return;
+ }
+
+@@ -91,9 +91,9 @@ asmlinkage void plat_irq_dispatch(struct
+ if ((pending & (1 << TITAN_IRQ)) && msgint) {
+ ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10));
+ #if defined(CONFIG_KGDB)
+- excite_kgdb_inthdl(regs);
++ excite_kgdb_inthdl();
+ #endif
+- do_IRQ(TITAN_IRQ, regs);
++ do_IRQ(TITAN_IRQ);
+ return;
+ }
+
+@@ -102,7 +102,7 @@ asmlinkage void plat_irq_dispatch(struct
+ msgintmask = ocd_readl(INTP0Mask0 + (FPGA0_MSGINT / 0x20 * 0x10));
+ msgint = msgintflags & msgintmask & (0x1 << (FPGA0_MSGINT % 0x20));
+ if ((pending & (1 << FPGA0_IRQ)) && msgint) {
+- do_IRQ(FPGA0_IRQ, regs);
++ do_IRQ(FPGA0_IRQ);
+ return;
+ }
+
+@@ -111,7 +111,7 @@ asmlinkage void plat_irq_dispatch(struct
+ msgintmask = ocd_readl(INTP0Mask0 + (FPGA1_MSGINT / 0x20 * 0x10));
+ msgint = msgintflags & msgintmask & (0x1 << (FPGA1_MSGINT % 0x20));
+ if ((pending & (1 << FPGA1_IRQ)) && msgint) {
+- do_IRQ(FPGA1_IRQ, regs);
++ do_IRQ(FPGA1_IRQ);
+ return;
+ }
+
+@@ -120,10 +120,10 @@ asmlinkage void plat_irq_dispatch(struct
+ msgintmask = ocd_readl(INTP0Mask0 + (PHY_MSGINT / 0x20 * 0x10));
+ msgint = msgintflags & msgintmask & (0x1 << (PHY_MSGINT % 0x20));
+ if ((pending & (1 << PHY_IRQ)) && msgint) {
+- do_IRQ(PHY_IRQ, regs);
++ do_IRQ(PHY_IRQ);
+ return;
+ }
+
+ /* Process spurious interrupts */
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
+index 0b75f4f..82e569d 100644
+--- a/arch/mips/cobalt/irq.c
++++ b/arch/mips/cobalt/irq.c
+@@ -16,7 +16,6 @@
+ #include <asm/i8259.h>
+ #include <asm/irq_cpu.h>
+ #include <asm/gt64120.h>
+-#include <asm/ptrace.h>
+
+ #include <asm/mach-cobalt/cobalt.h>
+
+@@ -42,7 +41,7 @@
+ * 15 - IDE1
+ */
+
+-static inline void galileo_irq(struct pt_regs *regs)
++static inline void galileo_irq(void)
+ {
+ unsigned int mask, pending, devfn;
+
+@@ -52,7 +51,7 @@ static inline void galileo_irq(struct pt
+ if (pending & GALILEO_INTR_T0EXP) {
+
+ GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS);
+- do_IRQ(COBALT_GALILEO_IRQ, regs);
++ do_IRQ(COBALT_GALILEO_IRQ);
+
+ } else if (pending & GALILEO_INTR_RETRY_CTR) {
+
+@@ -68,44 +67,31 @@ static inline void galileo_irq(struct pt
+ }
+ }
+
+-static inline void via_pic_irq(struct pt_regs *regs)
++static inline void via_pic_irq(void)
+ {
+ int irq;
+
+ irq = i8259_irq();
+ if (irq >= 0)
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+- unsigned pending;
+-
+- pending = read_c0_status() & read_c0_cause();
+-
+- if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */
+-
+- galileo_irq(regs);
+-
+- else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */
+-
+- via_pic_irq(regs);
+-
+- else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */
+-
+- do_IRQ(COBALT_CPU_IRQ + 3, regs);
+-
+- else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */
+-
+- do_IRQ(COBALT_CPU_IRQ + 4, regs);
+-
+- else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */
+-
+- do_IRQ(COBALT_CPU_IRQ + 5, regs);
+-
+- else if (pending & CAUSEF_IP7) /* IRQ 23 */
+-
+- do_IRQ(COBALT_CPU_IRQ + 7, regs);
++ unsigned pending = read_c0_status() & read_c0_cause();
++
++ if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */
++ galileo_irq();
++ else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */
++ via_pic_irq();
++ else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */
++ do_IRQ(COBALT_CPU_IRQ + 3);
++ else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */
++ do_IRQ(COBALT_CPU_IRQ + 4);
++ else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */
++ do_IRQ(COBALT_CPU_IRQ + 5);
++ else if (pending & CAUSEF_IP7) /* IRQ 23 */
++ do_IRQ(COBALT_CPU_IRQ + 7);
+ }
+
+ static struct irqaction irq_via = {
+diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
+index c01a017..bf9dc72 100644
+--- a/arch/mips/cobalt/setup.c
++++ b/arch/mips/cobalt/setup.c
+@@ -23,7 +23,6 @@
+ #include <asm/processor.h>
+ #include <asm/reboot.h>
+ #include <asm/gt64120.h>
+-#include <asm/serial.h>
+
+ #include <asm/mach-cobalt/cobalt.h>
+
+@@ -51,8 +50,8 @@ const char *get_system_type(void)
+
+ void __init plat_timer_setup(struct irqaction *irq)
+ {
+- /* Load timer value for 1KHz (TCLK is 50MHz) */
+- GALILEO_OUTL(50*1000*1000 / 1000, GT_TC0_OFS);
++ /* Load timer value for HZ (TCLK is 50MHz) */
++ GALILEO_OUTL(50*1000*1000 / HZ, GT_TC0_OFS);
+
+ /* Enable timer */
+ GALILEO_OUTL(GALILEO_ENTC0 | GALILEO_SELTC0, GT_TC_CONTROL_OFS);
+diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig
+index 5427406..35931be 100644
+--- a/arch/mips/configs/atlas_defconfig
++++ b/arch/mips/configs/atlas_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -162,6 +161,8 @@ CONFIG_HZ=100
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1193,7 +1194,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -1305,6 +1306,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
+index 887fd95..ba3bf73 100644
+--- a/arch/mips/configs/bigsur_defconfig
++++ b/arch/mips/configs/bigsur_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:02:58 2006
++# Linux kernel version: 2.6.19-rc1
++# Wed Oct 11 01:41:41 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,9 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+ # CONFIG_LASAT is not set
+ # CONFIG_MIPS_ATLAS is not set
+@@ -84,6 +81,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
+ CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+ CONFIG_DMA_COHERENT=y
+ CONFIG_CPU_BIG_ENDIAN=y
+@@ -133,8 +131,8 @@ CONFIG_PAGE_SIZE_4KB=y
+ # CONFIG_PAGE_SIZE_64KB is not set
+ # CONFIG_SIBYTE_DMA_PAGEOPS is not set
+ CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_MT_SMP is not set
++# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_VPE_LOADER is not set
+ CONFIG_CPU_HAS_LLSC=y
+ CONFIG_CPU_HAS_SYNC=y
+@@ -168,6 +166,8 @@ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
+ # CONFIG_PREEMPT_BKL is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -184,9 +184,11 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+@@ -194,7 +196,9 @@ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -203,12 +207,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -227,6 +231,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -248,18 +253,17 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ CONFIG_HW_HAS_PCI=y
+ CONFIG_PCI=y
+ CONFIG_PCI_DOMAINS=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ CONFIG_PCI_DEBUG=y
+ CONFIG_MMU=y
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+ #
+-# CONFIG_PCCARD is not set
+
+ #
+ # PCI Hotplug Support
+ #
+-# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -270,7 +274,7 @@ CONFIG_BINFMT_ELF=y
+ CONFIG_MIPS32_COMPAT=y
+ CONFIG_COMPAT=y
+ CONFIG_MIPS32_O32=y
+-# CONFIG_MIPS32_N32 is not set
++CONFIG_MIPS32_N32=y
+ CONFIG_BINFMT_ELF32=y
+
+ #
+@@ -287,6 +291,7 @@ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
+ CONFIG_NET_KEY=y
+ CONFIG_INET=y
+ # CONFIG_IP_MULTICAST is not set
+@@ -307,10 +312,12 @@ CONFIG_IP_PNP_BOOTP=y
+ # CONFIG_INET_TUNNEL is not set
+ CONFIG_INET_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_IPV6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+@@ -340,7 +347,6 @@ CONFIG_NETWORK_SECMARK=y
+ # 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
+
+@@ -367,7 +373,6 @@ CONFIG_NETWORK_SECMARK=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+ # CONFIG_DEBUG_DRIVER is not set
+ # CONFIG_SYS_HYPERVISOR is not set
+
+@@ -403,7 +408,7 @@ CONFIG_BLK_DEV_LOOP=m
+ CONFIG_BLK_DEV_NBD=m
+ # CONFIG_BLK_DEV_SX8 is not set
+ # CONFIG_BLK_DEV_RAM is not set
+-# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+
+@@ -411,6 +416,7 @@ CONFIG_BLK_DEV_NBD=m
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
+ CONFIG_BLK_DEV_IDE=y
+
+ #
+@@ -428,10 +434,40 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
+ # IDE chipset support/bugfixes
+ #
+ CONFIG_IDE_GENERIC=y
+-# CONFIG_BLK_DEV_IDEPCI is not set
++CONFIG_BLK_DEV_IDEPCI=y
++# CONFIG_IDEPCI_SHARE_IRQ is not set
++# CONFIG_BLK_DEV_OFFBOARD is not set
++CONFIG_BLK_DEV_GENERIC=y
++# CONFIG_BLK_DEV_OPTI621 is not set
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
++# CONFIG_IDEDMA_PCI_AUTO is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++CONFIG_BLK_DEV_CMD64X=y
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5520 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON 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
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
+ # CONFIG_BLK_DEV_IDE_SWARM is not set
+ # CONFIG_IDE_ARM is not set
+-# CONFIG_BLK_DEV_IDEDMA is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_IVB is not set
+ # CONFIG_IDEDMA_AUTO is not set
+ # CONFIG_BLK_DEV_HD is not set
+
+@@ -440,6 +476,12 @@ CONFIG_IDE_GENERIC=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -515,6 +557,7 @@ CONFIG_NET_SB1250_MAC=y
+ # CONFIG_SK98LIN is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -649,7 +692,6 @@ CONFIG_I2C_CHARDEV=y
+ # CONFIG_I2C_ALGOBIT is not set
+ # CONFIG_I2C_ALGOPCF is not set
+ # CONFIG_I2C_ALGOPCA is not set
+-CONFIG_I2C_ALGO_SIBYTE=y
+
+ #
+ # I2C Hardware Bus support
+@@ -711,12 +753,12 @@ CONFIG_I2C_DEBUG_CHIP=y
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -728,6 +770,7 @@ CONFIG_VIDEO_V4L2=y
+ #
+ # CONFIG_FIRMWARE_EDID is not set
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -810,6 +853,7 @@ CONFIG_FS_MBCACHE=y
+ # CONFIG_JFS_FS is not set
+ CONFIG_FS_POSIX_ACL=y
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -839,8 +883,10 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -850,6 +896,7 @@ CONFIG_RAMFS=y
+ #
+ # CONFIG_ADFS_FS is not set
+ # CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_FS is not set
+ # CONFIG_HFS_FS is not set
+ # CONFIG_HFSPLUS_FS is not set
+ # CONFIG_BEFS_FS is not set
+@@ -880,7 +927,6 @@ CONFIG_SUNRPC=y
+ # CONFIG_RPCSEC_GSS_SPKM3 is not set
+ # CONFIG_SMB_FS is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -898,6 +944,10 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_NLS is not set
+
+ #
++# Distributed Lock Manager
++#
++
++#
+ # Profiling support
+ #
+ # CONFIG_PROFILING is not set
+@@ -905,7 +955,9 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
+-CONFIG_PRINTK_TIME=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+@@ -918,12 +970,15 @@ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_DEBUG_SPINLOCK is not set
+ CONFIG_DEBUG_MUTEXES=y
+ # CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+ # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ CONFIG_FORCED_INLINING=y
+ # CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_CROSSCOMPILE=y
+@@ -944,6 +999,10 @@ CONFIG_KEYS_DEBUG_PROC_KEYS=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ CONFIG_CRYPTO_NULL=y
+ CONFIG_CRYPTO_MD4=y
+@@ -953,9 +1012,12 @@ CONFIG_CRYPTO_SHA256=y
+ CONFIG_CRYPTO_SHA512=y
+ CONFIG_CRYPTO_WP512=m
+ CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=y
+ CONFIG_CRYPTO_BLOWFISH=y
+ CONFIG_CRYPTO_TWOFISH=y
++CONFIG_CRYPTO_TWOFISH_COMMON=y
+ CONFIG_CRYPTO_SERPENT=y
+ CONFIG_CRYPTO_AES=m
+ # CONFIG_CRYPTO_CAST5 is not set
+diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
+index a01344f..e535812 100644
+--- a/arch/mips/configs/capcella_defconfig
++++ b/arch/mips/configs/capcella_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -150,6 +149,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -892,6 +893,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
+index c956824..adf1e8c 100644
+--- a/arch/mips/configs/cobalt_defconfig
++++ b/arch/mips/configs/cobalt_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ CONFIG_MIPS_COBALT=y
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -147,6 +146,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -828,7 +829,7 @@ CONFIG_FUSE_FS=y
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -890,6 +891,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
+index c2f33d3..4fd29ff 100644
+--- a/arch/mips/configs/db1000_defconfig
++++ b/arch/mips/configs/db1000_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1000=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1007,6 +1008,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
+index 8c44d16..025b960 100644
+--- a/arch/mips/configs/db1100_defconfig
++++ b/arch/mips/configs/db1100_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1100=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1007,6 +1008,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
+index c13768e..80c9dd9 100644
+--- a/arch/mips/configs/db1200_defconfig
++++ b/arch/mips/configs/db1200_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1200=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1088,6 +1089,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
+index 8aea73f..6caa90b 100644
+--- a/arch/mips/configs/db1500_defconfig
++++ b/arch/mips/configs/db1500_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1500=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -150,6 +149,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1291,6 +1292,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
+index 90ccb73..c6cae86 100644
+--- a/arch/mips/configs/db1550_defconfig
++++ b/arch/mips/configs/db1550_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1550=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -149,6 +148,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1112,6 +1113,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig
+index b598cf0..72f2400 100644
+--- a/arch/mips/configs/ddb5477_defconfig
++++ b/arch/mips/configs/ddb5477_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -147,6 +146,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -853,6 +854,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
+index 597150b..fe1387e 100644
+--- a/arch/mips/configs/decstation_defconfig
++++ b/arch/mips/configs/decstation_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:01 2006
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:57:53 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ CONFIG_MACH_DECSTATION=y
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=128
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -166,27 +167,28 @@ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+-CONFIG_RELAY=y
++# CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+ # CONFIG_HOTPLUG is not set
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -204,6 +206,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+ # CONFIG_LSF is not set
+@@ -230,7 +233,6 @@ CONFIG_MMU=y
+ #
+ # PCCARD (PCMCIA/CardBus) support
+ #
+-# CONFIG_PCCARD is not set
+
+ #
+ # PCI Hotplug Support
+@@ -257,9 +259,10 @@ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
+-# CONFIG_NET_KEY is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++CONFIG_NET_KEY=m
+ CONFIG_INET=y
+-# CONFIG_IP_MULTICAST is not set
++CONFIG_IP_MULTICAST=y
+ # CONFIG_IP_ADVANCED_ROUTER is not set
+ CONFIG_IP_FIB_HASH=y
+ CONFIG_IP_PNP=y
+@@ -268,22 +271,37 @@ CONFIG_IP_PNP_BOOTP=y
+ # CONFIG_IP_PNP_RARP is not set
+ # CONFIG_NET_IPIP is not set
+ # CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
+ # CONFIG_ARPD is not set
+-# CONFIG_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_XFRM_TUNNEL is not set
+-# CONFIG_INET_TUNNEL is not set
++CONFIG_SYN_COOKIES=y
++CONFIG_INET_AH=m
++CONFIG_INET_ESP=m
++CONFIG_INET_IPCOMP=m
++CONFIG_INET_XFRM_TUNNEL=m
++CONFIG_INET_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
+-# CONFIG_IPV6 is not set
+-# CONFIG_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++CONFIG_IPV6=m
++CONFIG_IPV6_PRIVACY=y
++CONFIG_IPV6_ROUTER_PREF=y
++CONFIG_IPV6_ROUTE_INFO=y
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++CONFIG_IPV6_MIP6=y
++CONFIG_INET6_XFRM_TUNNEL=m
++CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
++# CONFIG_IPV6_TUNNEL is not set
++CONFIG_IPV6_SUBTREES=y
++CONFIG_IPV6_MULTIPLE_TABLES=y
+ CONFIG_NETWORK_SECMARK=y
+ # CONFIG_NETFILTER is not set
+
+@@ -303,14 +321,13 @@ CONFIG_NETWORK_SECMARK=y
+ # CONFIG_TIPC is not set
+ # CONFIG_ATM is not set
+ # CONFIG_BRIDGE is not set
+-# CONFIG_VLAN_8021Q is not set
++CONFIG_VLAN_8021Q=m
+ # 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
+
+@@ -326,13 +343,8 @@ CONFIG_NETWORK_SECMARK=y
+ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+-CONFIG_IEEE80211=m
+-# CONFIG_IEEE80211_DEBUG is not set
+-CONFIG_IEEE80211_CRYPT_WEP=m
+-CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_SOFTMAC=m
+-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+-CONFIG_WIRELESS_EXT=y
++# CONFIG_IEEE80211 is not set
++CONFIG_FIB_RULES=y
+
+ #
+ # Device Drivers
+@@ -343,8 +355,6 @@ CONFIG_WIRELESS_EXT=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+-# CONFIG_DEBUG_DRIVER is not set
+ # CONFIG_SYS_HYPERVISOR is not set
+
+ #
+@@ -386,8 +396,9 @@ CONFIG_BLK_DEV_LOOP=m
+ #
+ # SCSI device support
+ #
+-CONFIG_RAID_ATTRS=m
++# CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++# CONFIG_SCSI_NETLINK is not set
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -409,12 +420,13 @@ CONFIG_SCSI_CONSTANTS=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=m
+ # CONFIG_SCSI_FC_ATTRS is not set
+ CONFIG_SCSI_ISCSI_ATTRS=m
+ CONFIG_SCSI_SAS_ATTRS=m
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+@@ -422,10 +434,14 @@ CONFIG_SCSI_SAS_ATTRS=m
+ CONFIG_ISCSI_TCP=m
+ CONFIG_SCSI_DECNCR=y
+ # CONFIG_SCSI_DECSII is not set
+-# CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ # CONFIG_MD is not set
+@@ -455,18 +471,7 @@ CONFIG_NETDEVICES=y
+ #
+ # PHY device support
+ #
+-CONFIG_PHYLIB=m
+-
+-#
+-# MII PHY device drivers
+-#
+-CONFIG_MARVELL_PHY=m
+-CONFIG_DAVICOM_PHY=m
+-CONFIG_QSEMI_PHY=m
+-CONFIG_LXT_PHY=m
+-CONFIG_CICADA_PHY=m
+-CONFIG_VITESSE_PHY=m
+-CONFIG_SMSC_PHY=m
++# CONFIG_PHYLIB is not set
+
+ #
+ # Ethernet (10 or 100Mbit)
+@@ -711,7 +716,12 @@ 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 is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++CONFIG_EXT3_FS_POSIX_ACL=y
++CONFIG_EXT3_FS_SECURITY=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+@@ -746,11 +756,13 @@ CONFIG_FUSE_FS=m
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_CONFIGFS_FS is not set
++CONFIG_CONFIGFS_FS=y
+
+ #
+ # Miscellaneous filesystems
+@@ -768,7 +780,7 @@ CONFIG_RAMFS=y
+ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ CONFIG_UFS_FS=y
+-# CONFIG_UFS_FS_WRITE is not set
++CONFIG_UFS_FS_WRITE=y
+ # CONFIG_UFS_DEBUG is not set
+
+ #
+@@ -776,24 +788,25 @@ CONFIG_UFS_FS=y
+ #
+ CONFIG_NFS_FS=y
+ CONFIG_NFS_V3=y
+-# CONFIG_NFS_V3_ACL is not set
++CONFIG_NFS_V3_ACL=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_NFS_ACL_SUPPORT=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_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+ # CONFIG_9P_FS is not set
++CONFIG_GENERIC_ACL=y
+
+ #
+ # Partition Types
+@@ -829,45 +842,31 @@ CONFIG_ULTRIX_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+-CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_KERNEL 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_RT_MUTEXES is not set
+-# CONFIG_RT_MUTEX_TESTER is not set
+-# CONFIG_DEBUG_SPINLOCK is not set
+-CONFIG_DEBUG_MUTEXES=y
+-# CONFIG_DEBUG_RWSEMS is not set
+-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+-# CONFIG_DEBUG_KOBJECT is not set
+-# CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+-# CONFIG_DEBUG_VM is not set
+-CONFIG_FORCED_INLINING=y
+-# CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_CROSSCOMPILE=y
+ CONFIG_CMDLINE=""
+-# CONFIG_DEBUG_STACK_USAGE is not set
+-# CONFIG_KGDB is not set
+-# CONFIG_RUNTIME_DEBUG is not set
+-# CONFIG_MIPS_UNCACHED is not set
+
+ #
+ # Security options
+ #
+-CONFIG_KEYS=y
+-CONFIG_KEYS_DEBUG_PROC_KEYS=y
++# CONFIG_KEYS is not set
+ # CONFIG_SECURITY is not set
+
+ #
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ CONFIG_CRYPTO_NULL=m
+ CONFIG_CRYPTO_MD4=m
+@@ -877,9 +876,12 @@ CONFIG_CRYPTO_SHA256=m
+ CONFIG_CRYPTO_SHA512=m
+ CONFIG_CRYPTO_WP512=m
+ CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=m
+ CONFIG_CRYPTO_BLOWFISH=m
+ CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
+ CONFIG_CRYPTO_SERPENT=m
+ CONFIG_CRYPTO_AES=m
+ CONFIG_CRYPTO_CAST5=m
+@@ -901,7 +903,7 @@ CONFIG_CRYPTO_CRC32C=m
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+-CONFIG_CRC16=m
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ CONFIG_LIBCRC32C=m
+ CONFIG_ZLIB_INFLATE=m
+diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
+index fa2996b..6133c28 100644
+--- a/arch/mips/configs/e55_defconfig
++++ b/arch/mips/configs/e55_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:02 2006
++# Linux kernel version: 2.6.18-rc2
++# Tue Jul 25 23:15:03 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -227,7 +228,6 @@ CONFIG_MMU=y
+ #
+ # PCCARD (PCMCIA/CardBus) support
+ #
+-# CONFIG_PCCARD is not set
+
+ #
+ # PCI Hotplug Support
+@@ -254,7 +254,6 @@ CONFIG_TRAD_SIGNALS=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+ # CONFIG_SYS_HYPERVISOR is not set
+
+ #
+@@ -284,6 +283,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ CONFIG_BLK_DEV_RAM=m
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_BLK_DEV_INITRD is not set
+ # CONFIG_CDROM_PKTCDVD is not set
+
+@@ -643,6 +643,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -650,7 +651,7 @@ CONFIG_MSDOS_PARTITION=y
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_DEBUG_FS is not set
+ CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE="console=ttyVR0,19200 mem=8M"
++CONFIG_CMDLINE="console=ttyVR0,19200 ide0=0x1f0,0x3f6,40 mem=8M"
+
+ #
+ # Security options
+diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig
+index 375b2ac..a484b7d 100644
+--- a/arch/mips/configs/emma2rh_defconfig
++++ b/arch/mips/configs/emma2rh_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=1000
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ CONFIG_PREEMPT=y
+ CONFIG_PREEMPT_BKL=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1181,6 +1182,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig
+index b0afc11..21bfcde 100644
+--- a/arch/mips/configs/ev64120_defconfig
++++ b/arch/mips/configs/ev64120_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ CONFIG_MIPS_EV64120=y
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -149,6 +148,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -843,6 +844,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig
+deleted file mode 100644
+index 0bdc10f..0000000
+--- a/arch/mips/configs/ev96100_defconfig
++++ /dev/null
+@@ -1,850 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:05 2006
+-#
+-CONFIG_MIPS=y
+-
+-#
+-# Machine selection
+-#
+-# CONFIG_MIPS_MTX1 is not set
+-# CONFIG_MIPS_BOSPORUS is not set
+-# CONFIG_MIPS_PB1000 is not set
+-# CONFIG_MIPS_PB1100 is not set
+-# CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_PB1550 is not set
+-# CONFIG_MIPS_PB1200 is not set
+-# CONFIG_MIPS_DB1000 is not set
+-# CONFIG_MIPS_DB1100 is not set
+-# CONFIG_MIPS_DB1500 is not set
+-# CONFIG_MIPS_DB1550 is not set
+-# CONFIG_MIPS_DB1200 is not set
+-# CONFIG_MIPS_MIRAGE is not set
+-# CONFIG_BASLER_EXCITE is not set
+-# CONFIG_MIPS_COBALT is not set
+-# CONFIG_MACH_DECSTATION is not set
+-# CONFIG_MIPS_EV64120 is not set
+-CONFIG_MIPS_EV96100=y
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+-# CONFIG_MACH_JAZZ is not set
+-# CONFIG_LASAT is not set
+-# CONFIG_MIPS_ATLAS is not set
+-# CONFIG_MIPS_MALTA is not set
+-# CONFIG_MIPS_SEAD is not set
+-# CONFIG_WR_PPMC is not set
+-# CONFIG_MIPS_SIM is not set
+-# CONFIG_MOMENCO_JAGUAR_ATX is not set
+-# CONFIG_MOMENCO_OCELOT is not set
+-# CONFIG_MOMENCO_OCELOT_3 is not set
+-# CONFIG_MOMENCO_OCELOT_C is not set
+-# CONFIG_MOMENCO_OCELOT_G is not set
+-# CONFIG_MIPS_XXS1500 is not set
+-# CONFIG_PNX8550_V2PCI is not set
+-# CONFIG_PNX8550_JBS is not set
+-# CONFIG_DDB5477 is not set
+-# CONFIG_MACH_VR41XX is not set
+-# CONFIG_PMC_YOSEMITE is not set
+-# CONFIG_QEMU is not set
+-# CONFIG_MARKEINS is not set
+-# CONFIG_SGI_IP22 is not set
+-# CONFIG_SGI_IP27 is not set
+-# CONFIG_SGI_IP32 is not set
+-# CONFIG_SIBYTE_BIGSUR is not set
+-# CONFIG_SIBYTE_SWARM is not set
+-# CONFIG_SIBYTE_SENTOSA is not set
+-# CONFIG_SIBYTE_RHONE is not set
+-# CONFIG_SIBYTE_CARMEL is not set
+-# CONFIG_SIBYTE_PTSWARM is not set
+-# CONFIG_SIBYTE_LITTLESUR is not set
+-# CONFIG_SIBYTE_CRHINE is not set
+-# CONFIG_SIBYTE_CRHONE is not set
+-# CONFIG_SNI_RM200_PCI is not set
+-# CONFIG_TOSHIBA_JMR3927 is not set
+-# CONFIG_TOSHIBA_RBTX4927 is not set
+-# CONFIG_TOSHIBA_RBTX4938 is not set
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+-CONFIG_DMA_NONCOHERENT=y
+-CONFIG_DMA_NEED_PCI_MAP_STATE=y
+-CONFIG_CPU_BIG_ENDIAN=y
+-# CONFIG_CPU_LITTLE_ENDIAN is not set
+-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+-CONFIG_IRQ_CPU=y
+-CONFIG_MIPS_GT64120=y
+-CONFIG_SWAP_IO_SPACE=y
+-CONFIG_MIPS_GT96100=y
+-CONFIG_MIPS_L1_CACHE_SHIFT=5
+-
+-#
+-# CPU selection
+-#
+-# CONFIG_CPU_MIPS32_R1 is not set
+-# CONFIG_CPU_MIPS32_R2 is not set
+-# CONFIG_CPU_MIPS64_R1 is not set
+-# CONFIG_CPU_MIPS64_R2 is not set
+-# CONFIG_CPU_R3000 is not set
+-# CONFIG_CPU_TX39XX is not set
+-# CONFIG_CPU_VR41XX is not set
+-# CONFIG_CPU_R4300 is not set
+-# CONFIG_CPU_R4X00 is not set
+-# CONFIG_CPU_TX49XX is not set
+-# CONFIG_CPU_R5000 is not set
+-# CONFIG_CPU_R5432 is not set
+-# CONFIG_CPU_R6000 is not set
+-# CONFIG_CPU_NEVADA is not set
+-# CONFIG_CPU_R8000 is not set
+-# CONFIG_CPU_R10000 is not set
+-CONFIG_CPU_RM7000=y
+-# CONFIG_CPU_RM9000 is not set
+-# CONFIG_CPU_SB1 is not set
+-CONFIG_SYS_HAS_CPU_R5000=y
+-CONFIG_SYS_HAS_CPU_RM7000=y
+-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+-
+-#
+-# Kernel type
+-#
+-CONFIG_32BIT=y
+-# CONFIG_64BIT is not set
+-CONFIG_PAGE_SIZE_4KB=y
+-# CONFIG_PAGE_SIZE_8KB is not set
+-# CONFIG_PAGE_SIZE_16KB is not set
+-# CONFIG_PAGE_SIZE_64KB is not set
+-CONFIG_BOARD_SCACHE=y
+-CONFIG_RM7000_CPU_SCACHE=y
+-CONFIG_CPU_HAS_PREFETCH=y
+-CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+-# CONFIG_MIPS_MT_SMP is not set
+-# CONFIG_MIPS_VPE_LOADER is not set
+-# CONFIG_64BIT_PHYS_ADDR is not set
+-CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_SYNC=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_CPU_SUPPORTS_HIGHMEM=y
+-CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-# CONFIG_HZ_48 is not set
+-# CONFIG_HZ_100 is not set
+-# CONFIG_HZ_128 is not set
+-# CONFIG_HZ_250 is not set
+-# CONFIG_HZ_256 is not set
+-CONFIG_HZ_1000=y
+-# CONFIG_HZ_1024 is not set
+-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+-CONFIG_HZ=1000
+-CONFIG_PREEMPT_NONE=y
+-# CONFIG_PREEMPT_VOLUNTARY is not set
+-# CONFIG_PREEMPT is not set
+-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
+-CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+-CONFIG_LOCALVERSION=""
+-CONFIG_LOCALVERSION_AUTO=y
+-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_IKCONFIG is not set
+-CONFIG_RELAY=y
+-CONFIG_INITRAMFS_SOURCE=""
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+-CONFIG_EMBEDDED=y
+-CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+-# CONFIG_HOTPLUG is not set
+-CONFIG_PRINTK=y
+-CONFIG_BUG=y
+-CONFIG_ELF_CORE=y
+-CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-CONFIG_SHMEM=y
+-CONFIG_SLAB=y
+-CONFIG_VM_EVENT_COUNTERS=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_SLOB is not set
+-
+-#
+-# Loadable module support
+-#
+-CONFIG_MODULES=y
+-CONFIG_MODULE_UNLOAD=y
+-# CONFIG_MODULE_FORCE_UNLOAD is not set
+-CONFIG_MODVERSIONS=y
+-CONFIG_MODULE_SRCVERSION_ALL=y
+-# CONFIG_KMOD is not set
+-
+-#
+-# Block layer
+-#
+-# CONFIG_LBD is not set
+-# CONFIG_BLK_DEV_IO_TRACE is not set
+-# CONFIG_LSF is not set
+-
+-#
+-# IO Schedulers
+-#
+-CONFIG_IOSCHED_NOOP=y
+-CONFIG_IOSCHED_AS=y
+-CONFIG_IOSCHED_DEADLINE=y
+-CONFIG_IOSCHED_CFQ=y
+-CONFIG_DEFAULT_AS=y
+-# CONFIG_DEFAULT_DEADLINE is not set
+-# CONFIG_DEFAULT_CFQ is not set
+-# CONFIG_DEFAULT_NOOP is not set
+-CONFIG_DEFAULT_IOSCHED="anticipatory"
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+-#
+-CONFIG_HW_HAS_PCI=y
+-# CONFIG_PCI is not set
+-CONFIG_MMU=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PCI Hotplug Support
+-#
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_MISC is not set
+-CONFIG_TRAD_SIGNALS=y
+-
+-#
+-# Networking
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-# CONFIG_NETDEBUG is not set
+-# CONFIG_PACKET is not set
+-CONFIG_UNIX=y
+-CONFIG_XFRM=y
+-CONFIG_XFRM_USER=m
+-CONFIG_NET_KEY=y
+-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 is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_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_XFRM_TUNNEL is not set
+-# CONFIG_INET_TUNNEL is not set
+-CONFIG_INET_XFRM_MODE_TRANSPORT=m
+-CONFIG_INET_XFRM_MODE_TUNNEL=m
+-CONFIG_INET_DIAG=y
+-CONFIG_INET_TCP_DIAG=y
+-# CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
+-# CONFIG_IPV6 is not set
+-# CONFIG_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
+-CONFIG_NETWORK_SECMARK=y
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# DCCP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_DCCP is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_SCTP is not set
+-
+-#
+-# TIPC Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_TIPC 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
+-
+-#
+-# Network testing
+-#
+-# CONFIG_NET_PKTGEN is not set
+-# CONFIG_HAMRADIO is not set
+-# CONFIG_IRDA is not set
+-# CONFIG_BT is not set
+-CONFIG_IEEE80211=m
+-# CONFIG_IEEE80211_DEBUG is not set
+-CONFIG_IEEE80211_CRYPT_WEP=m
+-CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_SOFTMAC=m
+-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+-CONFIG_WIRELESS_EXT=y
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+-# CONFIG_SYS_HYPERVISOR is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+-CONFIG_CONNECTOR=m
+-
+-#
+-# 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_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_INITRD is not set
+-CONFIG_CDROM_PKTCDVD=m
+-CONFIG_CDROM_PKTCDVD_BUFFERS=8
+-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+-CONFIG_ATA_OVER_ETH=m
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-# CONFIG_IDE is not set
+-
+-#
+-# SCSI device support
+-#
+-CONFIG_RAID_ATTRS=m
+-# 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
+-#
+-
+-#
+-# I2O device support
+-#
+-
+-#
+-# Network device support
+-#
+-CONFIG_NETDEVICES=y
+-# CONFIG_DUMMY is not set
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-# CONFIG_TUN is not set
+-
+-#
+-# PHY device support
+-#
+-CONFIG_PHYLIB=m
+-
+-#
+-# MII PHY device drivers
+-#
+-CONFIG_MARVELL_PHY=m
+-CONFIG_DAVICOM_PHY=m
+-CONFIG_QSEMI_PHY=m
+-CONFIG_LXT_PHY=m
+-CONFIG_CICADA_PHY=m
+-CONFIG_VITESSE_PHY=m
+-CONFIG_SMSC_PHY=m
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-CONFIG_NET_ETHERNET=y
+-# CONFIG_MII is not set
+-CONFIG_MIPS_GT96100ETH=y
+-# CONFIG_DM9000 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
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-
+-#
+-# Userland interfaces
+-#
+-CONFIG_INPUT_MOUSEDEV=y
+-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input 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
+-
+-#
+-# Hardware I/O ports
+-#
+-CONFIG_SERIO=y
+-# CONFIG_SERIO_I8042 is not set
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_LIBPS2 is not set
+-CONFIG_SERIO_RAW=m
+-# CONFIG_GAMEPORT is not set
+-
+-#
+-# Character devices
+-#
+-CONFIG_VT=y
+-CONFIG_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-CONFIG_VT_HW_CONSOLE_BINDING=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_RUNTIME_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_HW_RANDOM is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
+-# CONFIG_DTLK is not set
+-# CONFIG_R3964 is not set
+-
+-#
+-# Ftape, the floppy tape device driver
+-#
+-# CONFIG_RAW_DRIVER is not set
+-
+-#
+-# TPM devices
+-#
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+-
+-#
+-# I2C support
+-#
+-# CONFIG_I2C is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
+-
+-#
+-# Dallas's 1-wire bus
+-#
+-# CONFIG_W1 is not set
+-
+-#
+-# Hardware Monitoring support
+-#
+-# CONFIG_HWMON is not set
+-# CONFIG_HWMON_VID is not set
+-
+-#
+-# Misc devices
+-#
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+-
+-#
+-# Digital Video Broadcasting Devices
+-#
+-# CONFIG_DVB is not set
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_FIRMWARE_EDID is not set
+-# CONFIG_FB is not set
+-
+-#
+-# Console display driver support
+-#
+-# CONFIG_VGA_CONSOLE is not set
+-CONFIG_DUMMY_CONSOLE=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
+-# CONFIG_USB_ARCH_HAS_HCD is not set
+-# CONFIG_USB_ARCH_HAS_OHCI is not set
+-# CONFIG_USB_ARCH_HAS_EHCI is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-
+-#
+-# MMC/SD Card support
+-#
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
+-
+-#
+-# LED drivers
+-#
+-
+-#
+-# LED Triggers
+-#
+-
+-#
+-# InfiniBand support
+-#
+-
+-#
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+-#
+-
+-#
+-# Real Time Clock
+-#
+-# CONFIG_RTC_CLASS is not set
+-
+-#
+-# DMA Engine support
+-#
+-# CONFIG_DMA_ENGINE is not set
+-
+-#
+-# DMA Clients
+-#
+-
+-#
+-# DMA Devices
+-#
+-
+-#
+-# File systems
+-#
+-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_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-# CONFIG_XFS_FS is not set
+-# CONFIG_OCFS2_FS is not set
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-CONFIG_FUSE_FS=m
+-
+-#
+-# 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_TMPFS is not set
+-# CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-# CONFIG_CONFIGFS_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_CIFS_DEBUG2 is not set
+-# 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
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-# CONFIG_MAGIC_SYSRQ is not set
+-# CONFIG_UNUSED_SYMBOLS is not set
+-# CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_DEBUG_FS is not set
+-CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE=""
+-
+-#
+-# Security options
+-#
+-CONFIG_KEYS=y
+-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+-# CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-CONFIG_CRYPTO=y
+-CONFIG_CRYPTO_HMAC=y
+-CONFIG_CRYPTO_NULL=m
+-CONFIG_CRYPTO_MD4=m
+-CONFIG_CRYPTO_MD5=m
+-CONFIG_CRYPTO_SHA1=m
+-CONFIG_CRYPTO_SHA256=m
+-CONFIG_CRYPTO_SHA512=m
+-CONFIG_CRYPTO_WP512=m
+-CONFIG_CRYPTO_TGR192=m
+-CONFIG_CRYPTO_DES=m
+-CONFIG_CRYPTO_BLOWFISH=m
+-CONFIG_CRYPTO_TWOFISH=m
+-CONFIG_CRYPTO_SERPENT=m
+-CONFIG_CRYPTO_AES=m
+-CONFIG_CRYPTO_CAST5=m
+-CONFIG_CRYPTO_CAST6=m
+-CONFIG_CRYPTO_TEA=m
+-CONFIG_CRYPTO_ARC4=m
+-CONFIG_CRYPTO_KHAZAD=m
+-CONFIG_CRYPTO_ANUBIS=m
+-CONFIG_CRYPTO_DEFLATE=m
+-CONFIG_CRYPTO_MICHAEL_MIC=m
+-CONFIG_CRYPTO_CRC32C=m
+-# CONFIG_CRYPTO_TEST is not set
+-
+-#
+-# Hardware crypto devices
+-#
+-
+-#
+-# Library routines
+-#
+-# CONFIG_CRC_CCITT is not set
+-CONFIG_CRC16=m
+-CONFIG_CRC32=m
+-CONFIG_LIBCRC32C=m
+-CONFIG_ZLIB_INFLATE=m
+-CONFIG_ZLIB_DEFLATE=m
+-CONFIG_PLIST=y
+diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig
+index 045ebd0..1a5b06c 100644
+--- a/arch/mips/configs/excite_defconfig
++++ b/arch/mips/configs/excite_defconfig
+@@ -26,7 +26,6 @@ CONFIG_BASLER_EXCITE=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -150,6 +149,8 @@ CONFIG_HZ=1000
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ CONFIG_PREEMPT=y
+ CONFIG_PREEMPT_BKL=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1185,6 +1186,7 @@ CONFIG_NLS_ISO8859_1=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
+index ef16d1f..21d53e0 100644
+--- a/arch/mips/configs/ip22_defconfig
++++ b/arch/mips/configs/ip22_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -154,6 +153,8 @@ CONFIG_HZ=1000
+ # CONFIG_PREEMPT_NONE is not set
+ CONFIG_PREEMPT_VOLUNTARY=y
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1013,7 +1014,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -1148,6 +1149,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
+index 4bf1ee7..e3e94c7 100644
+--- a/arch/mips/configs/ip27_defconfig
++++ b/arch/mips/configs/ip27_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -163,6 +162,8 @@ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT is not set
+ CONFIG_PREEMPT_BKL=y
+ # CONFIG_MIPS_INSANE_LARGE is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -900,7 +901,7 @@ CONFIG_FUSE_FS=m
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -981,6 +982,7 @@ CONFIG_SGI_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
+index f83dc09..b4ab2be 100644
+--- a/arch/mips/configs/ip32_defconfig
++++ b/arch/mips/configs/ip32_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -154,6 +153,8 @@ CONFIG_HZ=1000
+ # CONFIG_PREEMPT_NONE is not set
+ CONFIG_PREEMPT_VOLUNTARY=y
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -923,6 +924,7 @@ CONFIG_SGI_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig
+deleted file mode 100644
+index a91d72a..0000000
+--- a/arch/mips/configs/it8172_defconfig
++++ /dev/null
+@@ -1,962 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:11 2006
+-#
+-CONFIG_MIPS=y
+-
+-#
+-# Machine selection
+-#
+-# CONFIG_MIPS_MTX1 is not set
+-# CONFIG_MIPS_BOSPORUS is not set
+-# CONFIG_MIPS_PB1000 is not set
+-# CONFIG_MIPS_PB1100 is not set
+-# CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_PB1550 is not set
+-# CONFIG_MIPS_PB1200 is not set
+-# CONFIG_MIPS_DB1000 is not set
+-# CONFIG_MIPS_DB1100 is not set
+-# CONFIG_MIPS_DB1500 is not set
+-# CONFIG_MIPS_DB1550 is not set
+-# CONFIG_MIPS_DB1200 is not set
+-# CONFIG_MIPS_MIRAGE is not set
+-# CONFIG_BASLER_EXCITE is not set
+-# CONFIG_MIPS_COBALT is not set
+-# CONFIG_MACH_DECSTATION is not set
+-# CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-CONFIG_MIPS_ITE8172=y
+-# CONFIG_MACH_JAZZ is not set
+-# CONFIG_LASAT is not set
+-# CONFIG_MIPS_ATLAS is not set
+-# CONFIG_MIPS_MALTA is not set
+-# CONFIG_MIPS_SEAD is not set
+-# CONFIG_WR_PPMC is not set
+-# CONFIG_MIPS_SIM is not set
+-# CONFIG_MOMENCO_JAGUAR_ATX is not set
+-# CONFIG_MOMENCO_OCELOT is not set
+-# CONFIG_MOMENCO_OCELOT_3 is not set
+-# CONFIG_MOMENCO_OCELOT_C is not set
+-# CONFIG_MOMENCO_OCELOT_G is not set
+-# CONFIG_MIPS_XXS1500 is not set
+-# CONFIG_PNX8550_V2PCI is not set
+-# CONFIG_PNX8550_JBS is not set
+-# CONFIG_DDB5477 is not set
+-# CONFIG_MACH_VR41XX is not set
+-# CONFIG_PMC_YOSEMITE is not set
+-# CONFIG_QEMU is not set
+-# CONFIG_MARKEINS is not set
+-# CONFIG_SGI_IP22 is not set
+-# CONFIG_SGI_IP27 is not set
+-# CONFIG_SGI_IP32 is not set
+-# CONFIG_SIBYTE_BIGSUR is not set
+-# CONFIG_SIBYTE_SWARM is not set
+-# CONFIG_SIBYTE_SENTOSA is not set
+-# CONFIG_SIBYTE_RHONE is not set
+-# CONFIG_SIBYTE_CARMEL is not set
+-# CONFIG_SIBYTE_PTSWARM is not set
+-# CONFIG_SIBYTE_LITTLESUR is not set
+-# CONFIG_SIBYTE_CRHINE is not set
+-# CONFIG_SIBYTE_CRHONE is not set
+-# CONFIG_SNI_RM200_PCI is not set
+-# CONFIG_TOSHIBA_JMR3927 is not set
+-# CONFIG_TOSHIBA_RBTX4927 is not set
+-# CONFIG_TOSHIBA_RBTX4938 is not set
+-# CONFIG_IT8172_REVC is not set
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+-CONFIG_DMA_NONCOHERENT=y
+-CONFIG_DMA_NEED_PCI_MAP_STATE=y
+-# CONFIG_CPU_BIG_ENDIAN is not set
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+-CONFIG_ITE_BOARD_GEN=y
+-CONFIG_IT8172_CIR=y
+-CONFIG_IT8712=y
+-CONFIG_MIPS_L1_CACHE_SHIFT=5
+-
+-#
+-# CPU selection
+-#
+-# CONFIG_CPU_MIPS32_R1 is not set
+-# CONFIG_CPU_MIPS32_R2 is not set
+-# CONFIG_CPU_MIPS64_R1 is not set
+-# CONFIG_CPU_MIPS64_R2 is not set
+-# CONFIG_CPU_R3000 is not set
+-# CONFIG_CPU_TX39XX is not set
+-# CONFIG_CPU_VR41XX is not set
+-# CONFIG_CPU_R4300 is not set
+-# CONFIG_CPU_R4X00 is not set
+-# CONFIG_CPU_TX49XX is not set
+-# CONFIG_CPU_R5000 is not set
+-# CONFIG_CPU_R5432 is not set
+-# CONFIG_CPU_R6000 is not set
+-CONFIG_CPU_NEVADA=y
+-# CONFIG_CPU_R8000 is not set
+-# CONFIG_CPU_R10000 is not set
+-# CONFIG_CPU_RM7000 is not set
+-# CONFIG_CPU_RM9000 is not set
+-# CONFIG_CPU_SB1 is not set
+-CONFIG_SYS_HAS_CPU_R5432=y
+-CONFIG_SYS_HAS_CPU_NEVADA=y
+-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+-
+-#
+-# Kernel type
+-#
+-CONFIG_32BIT=y
+-# CONFIG_64BIT is not set
+-CONFIG_PAGE_SIZE_4KB=y
+-# CONFIG_PAGE_SIZE_8KB is not set
+-# CONFIG_PAGE_SIZE_16KB is not set
+-# CONFIG_PAGE_SIZE_64KB is not set
+-CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+-# CONFIG_MIPS_MT_SMP is not set
+-# CONFIG_MIPS_VPE_LOADER is not set
+-CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_SYNC=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-# CONFIG_HZ_48 is not set
+-# CONFIG_HZ_100 is not set
+-# CONFIG_HZ_128 is not set
+-# CONFIG_HZ_250 is not set
+-# CONFIG_HZ_256 is not set
+-CONFIG_HZ_1000=y
+-# CONFIG_HZ_1024 is not set
+-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+-CONFIG_HZ=1000
+-CONFIG_PREEMPT_NONE=y
+-# CONFIG_PREEMPT_VOLUNTARY is not set
+-# CONFIG_PREEMPT is not set
+-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
+-CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+-CONFIG_LOCALVERSION=""
+-CONFIG_LOCALVERSION_AUTO=y
+-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_IKCONFIG is not set
+-CONFIG_RELAY=y
+-CONFIG_INITRAMFS_SOURCE=""
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+-CONFIG_EMBEDDED=y
+-CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+-# CONFIG_HOTPLUG is not set
+-CONFIG_PRINTK=y
+-CONFIG_BUG=y
+-CONFIG_ELF_CORE=y
+-CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-CONFIG_SHMEM=y
+-CONFIG_SLAB=y
+-CONFIG_VM_EVENT_COUNTERS=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_SLOB is not set
+-
+-#
+-# Loadable module support
+-#
+-CONFIG_MODULES=y
+-CONFIG_MODULE_UNLOAD=y
+-# CONFIG_MODULE_FORCE_UNLOAD is not set
+-CONFIG_MODVERSIONS=y
+-CONFIG_MODULE_SRCVERSION_ALL=y
+-CONFIG_KMOD=y
+-
+-#
+-# Block layer
+-#
+-# CONFIG_LBD is not set
+-# CONFIG_BLK_DEV_IO_TRACE is not set
+-# CONFIG_LSF is not set
+-
+-#
+-# IO Schedulers
+-#
+-CONFIG_IOSCHED_NOOP=y
+-CONFIG_IOSCHED_AS=y
+-CONFIG_IOSCHED_DEADLINE=y
+-CONFIG_IOSCHED_CFQ=y
+-CONFIG_DEFAULT_AS=y
+-# CONFIG_DEFAULT_DEADLINE is not set
+-# CONFIG_DEFAULT_CFQ is not set
+-# CONFIG_DEFAULT_NOOP is not set
+-CONFIG_DEFAULT_IOSCHED="anticipatory"
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+-#
+-CONFIG_HW_HAS_PCI=y
+-# CONFIG_PCI is not set
+-CONFIG_MMU=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PCI Hotplug Support
+-#
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_MISC is not set
+-CONFIG_TRAD_SIGNALS=y
+-
+-#
+-# Networking
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-# CONFIG_NETDEBUG is not set
+-CONFIG_PACKET=y
+-CONFIG_PACKET_MMAP=y
+-CONFIG_UNIX=y
+-CONFIG_XFRM=y
+-CONFIG_XFRM_USER=m
+-CONFIG_NET_KEY=y
+-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 is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_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_XFRM_TUNNEL is not set
+-# CONFIG_INET_TUNNEL is not set
+-CONFIG_INET_XFRM_MODE_TRANSPORT=m
+-CONFIG_INET_XFRM_MODE_TUNNEL=m
+-CONFIG_INET_DIAG=y
+-CONFIG_INET_TCP_DIAG=y
+-# CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
+-# CONFIG_IPV6 is not set
+-# CONFIG_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
+-CONFIG_NETWORK_SECMARK=y
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# DCCP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_DCCP is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_SCTP is not set
+-
+-#
+-# TIPC Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_TIPC 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
+-
+-#
+-# Network testing
+-#
+-# CONFIG_NET_PKTGEN is not set
+-# CONFIG_HAMRADIO is not set
+-# CONFIG_IRDA is not set
+-# CONFIG_BT is not set
+-CONFIG_IEEE80211=m
+-# CONFIG_IEEE80211_DEBUG is not set
+-CONFIG_IEEE80211_CRYPT_WEP=m
+-CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_SOFTMAC=m
+-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+-CONFIG_WIRELESS_EXT=y
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+-# CONFIG_SYS_HYPERVISOR is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+-CONFIG_CONNECTOR=m
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-CONFIG_MTD=y
+-# CONFIG_MTD_DEBUG is not set
+-# CONFIG_MTD_CONCAT is not set
+-# CONFIG_MTD_PARTITIONS is not set
+-
+-#
+-# User Modules And Translation Layers
+-#
+-CONFIG_MTD_CHAR=y
+-# CONFIG_MTD_BLOCK is not set
+-# CONFIG_MTD_BLOCK_RO is not set
+-# CONFIG_FTL is not set
+-# CONFIG_NFTL is not set
+-# CONFIG_INFTL is not set
+-# CONFIG_RFD_FTL is not set
+-
+-#
+-# RAM/ROM/Flash chip drivers
+-#
+-CONFIG_MTD_CFI=y
+-# CONFIG_MTD_JEDECPROBE is not set
+-CONFIG_MTD_GEN_PROBE=y
+-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+-CONFIG_MTD_MAP_BANK_WIDTH_1=y
+-CONFIG_MTD_MAP_BANK_WIDTH_2=y
+-CONFIG_MTD_MAP_BANK_WIDTH_4=y
+-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+-CONFIG_MTD_CFI_I1=y
+-CONFIG_MTD_CFI_I2=y
+-# CONFIG_MTD_CFI_I4 is not set
+-# CONFIG_MTD_CFI_I8 is not set
+-CONFIG_MTD_CFI_INTELEXT=y
+-# CONFIG_MTD_CFI_AMDSTD is not set
+-# CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_CFI_UTIL=y
+-# CONFIG_MTD_RAM is not set
+-# CONFIG_MTD_ROM is not set
+-# CONFIG_MTD_ABSENT is not set
+-# CONFIG_MTD_OBSOLETE_CHIPS is not set
+-
+-#
+-# Mapping drivers for chip access
+-#
+-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+-CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=0x8000000
+-CONFIG_MTD_PHYSMAP_LEN=0x2000000
+-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+-# CONFIG_MTD_PLATRAM is not set
+-
+-#
+-# Self-contained MTD device drivers
+-#
+-# CONFIG_MTD_SLRAM is not set
+-# CONFIG_MTD_PHRAM is not set
+-# CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLOCK2MTD is not set
+-
+-#
+-# Disk-On-Chip Device Drivers
+-#
+-# CONFIG_MTD_DOC2000 is not set
+-# CONFIG_MTD_DOC2001 is not set
+-# CONFIG_MTD_DOC2001PLUS is not set
+-
+-#
+-# NAND Flash Device Drivers
+-#
+-# CONFIG_MTD_NAND is not set
+-
+-#
+-# OneNAND Flash Device Drivers
+-#
+-# CONFIG_MTD_ONENAND is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# 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_INITRD is not set
+-CONFIG_CDROM_PKTCDVD=m
+-CONFIG_CDROM_PKTCDVD_BUFFERS=8
+-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+-CONFIG_ATA_OVER_ETH=m
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-CONFIG_IDE=y
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/ide.txt for help/info on IDE drives
+-#
+-# CONFIG_BLK_DEV_IDE_SATA is not set
+-CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
+-# CONFIG_BLK_DEV_IDECD 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_BLK_DEV_IDEDMA is not set
+-# CONFIG_IDEDMA_AUTO is not set
+-# CONFIG_BLK_DEV_HD is not set
+-
+-#
+-# SCSI device support
+-#
+-CONFIG_RAID_ATTRS=m
+-# 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
+-#
+-
+-#
+-# I2O device support
+-#
+-
+-#
+-# Network device support
+-#
+-CONFIG_NETDEVICES=y
+-# CONFIG_DUMMY is not set
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-# CONFIG_TUN is not set
+-
+-#
+-# PHY device support
+-#
+-CONFIG_PHYLIB=m
+-
+-#
+-# MII PHY device drivers
+-#
+-CONFIG_MARVELL_PHY=m
+-CONFIG_DAVICOM_PHY=m
+-CONFIG_QSEMI_PHY=m
+-CONFIG_LXT_PHY=m
+-CONFIG_CICADA_PHY=m
+-CONFIG_VITESSE_PHY=m
+-CONFIG_SMSC_PHY=m
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-CONFIG_NET_ETHERNET=y
+-# CONFIG_MII is not set
+-# CONFIG_DM9000 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
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-
+-#
+-# Userland interfaces
+-#
+-CONFIG_INPUT_MOUSEDEV=y
+-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input 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
+-
+-#
+-# Hardware I/O ports
+-#
+-CONFIG_SERIO=y
+-# CONFIG_SERIO_I8042 is not set
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_LIBPS2 is not set
+-CONFIG_SERIO_RAW=m
+-# CONFIG_GAMEPORT is not set
+-
+-#
+-# Character devices
+-#
+-CONFIG_VT=y
+-CONFIG_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-CONFIG_VT_HW_CONSOLE_BINDING=y
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_QTRONIX_KEYBOARD is not set
+-# CONFIG_IT8172_SCR0 is not set
+-# CONFIG_IT8172_SCR1 is not set
+-# CONFIG_ITE_GPIO is not set
+-
+-#
+-# Serial drivers
+-#
+-CONFIG_SERIAL_8250=y
+-CONFIG_SERIAL_8250_CONSOLE=y
+-CONFIG_SERIAL_8250_NR_UARTS=4
+-CONFIG_SERIAL_8250_RUNTIME_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_HW_RANDOM is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
+-# CONFIG_DTLK is not set
+-# CONFIG_R3964 is not set
+-
+-#
+-# Ftape, the floppy tape device driver
+-#
+-# CONFIG_RAW_DRIVER is not set
+-
+-#
+-# TPM devices
+-#
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+-
+-#
+-# I2C support
+-#
+-# CONFIG_I2C is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
+-
+-#
+-# Dallas's 1-wire bus
+-#
+-# CONFIG_W1 is not set
+-
+-#
+-# Hardware Monitoring support
+-#
+-# CONFIG_HWMON is not set
+-# CONFIG_HWMON_VID is not set
+-
+-#
+-# Misc devices
+-#
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+-
+-#
+-# Digital Video Broadcasting Devices
+-#
+-# CONFIG_DVB is not set
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_FIRMWARE_EDID is not set
+-# CONFIG_FB is not set
+-
+-#
+-# Console display driver support
+-#
+-# CONFIG_VGA_CONSOLE is not set
+-CONFIG_DUMMY_CONSOLE=y
+-
+-#
+-# Sound
+-#
+-CONFIG_SOUND=y
+-
+-#
+-# Advanced Linux Sound Architecture
+-#
+-# CONFIG_SND is not set
+-
+-#
+-# Open Sound System
+-#
+-CONFIG_SOUND_PRIME=y
+-CONFIG_SOUND_IT8172=y
+-# CONFIG_SOUND_MSNDCLAS is not set
+-# CONFIG_SOUND_MSNDPIN is not set
+-
+-#
+-# USB support
+-#
+-# CONFIG_USB_ARCH_HAS_HCD is not set
+-# CONFIG_USB_ARCH_HAS_OHCI is not set
+-# CONFIG_USB_ARCH_HAS_EHCI is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-
+-#
+-# MMC/SD Card support
+-#
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
+-
+-#
+-# LED drivers
+-#
+-
+-#
+-# LED Triggers
+-#
+-
+-#
+-# InfiniBand support
+-#
+-
+-#
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+-#
+-
+-#
+-# Real Time Clock
+-#
+-# CONFIG_RTC_CLASS is not set
+-
+-#
+-# DMA Engine support
+-#
+-# CONFIG_DMA_ENGINE is not set
+-
+-#
+-# DMA Clients
+-#
+-
+-#
+-# DMA Devices
+-#
+-
+-#
+-# File systems
+-#
+-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_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-# CONFIG_XFS_FS is not set
+-# CONFIG_OCFS2_FS is not set
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-CONFIG_FUSE_FS=m
+-
+-#
+-# 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_TMPFS is not set
+-# CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-# CONFIG_CONFIGFS_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_JFFS_FS is not set
+-# CONFIG_JFFS2_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_CIFS_DEBUG2 is not set
+-# 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
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-# CONFIG_MAGIC_SYSRQ is not set
+-# CONFIG_UNUSED_SYMBOLS is not set
+-# CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_DEBUG_FS is not set
+-CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE=""
+-
+-#
+-# Security options
+-#
+-CONFIG_KEYS=y
+-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+-# CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-CONFIG_CRYPTO=y
+-CONFIG_CRYPTO_HMAC=y
+-CONFIG_CRYPTO_NULL=m
+-CONFIG_CRYPTO_MD4=m
+-CONFIG_CRYPTO_MD5=m
+-CONFIG_CRYPTO_SHA1=m
+-CONFIG_CRYPTO_SHA256=m
+-CONFIG_CRYPTO_SHA512=m
+-CONFIG_CRYPTO_WP512=m
+-CONFIG_CRYPTO_TGR192=m
+-CONFIG_CRYPTO_DES=m
+-CONFIG_CRYPTO_BLOWFISH=m
+-CONFIG_CRYPTO_TWOFISH=m
+-CONFIG_CRYPTO_SERPENT=m
+-CONFIG_CRYPTO_AES=m
+-CONFIG_CRYPTO_CAST5=m
+-CONFIG_CRYPTO_CAST6=m
+-CONFIG_CRYPTO_TEA=m
+-CONFIG_CRYPTO_ARC4=m
+-CONFIG_CRYPTO_KHAZAD=m
+-CONFIG_CRYPTO_ANUBIS=m
+-CONFIG_CRYPTO_DEFLATE=m
+-CONFIG_CRYPTO_MICHAEL_MIC=m
+-CONFIG_CRYPTO_CRC32C=m
+-# CONFIG_CRYPTO_TEST is not set
+-
+-#
+-# Hardware crypto devices
+-#
+-
+-#
+-# Library routines
+-#
+-# CONFIG_CRC_CCITT is not set
+-CONFIG_CRC16=m
+-CONFIG_CRC32=m
+-CONFIG_LIBCRC32C=m
+-CONFIG_ZLIB_INFLATE=m
+-CONFIG_ZLIB_DEFLATE=m
+-CONFIG_PLIST=y
+diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig
+deleted file mode 100644
+index cebc672..0000000
+--- a/arch/mips/configs/ivr_defconfig
++++ /dev/null
+@@ -1,918 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:12 2006
+-#
+-CONFIG_MIPS=y
+-
+-#
+-# Machine selection
+-#
+-# CONFIG_MIPS_MTX1 is not set
+-# CONFIG_MIPS_BOSPORUS is not set
+-# CONFIG_MIPS_PB1000 is not set
+-# CONFIG_MIPS_PB1100 is not set
+-# CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_PB1550 is not set
+-# CONFIG_MIPS_PB1200 is not set
+-# CONFIG_MIPS_DB1000 is not set
+-# CONFIG_MIPS_DB1100 is not set
+-# CONFIG_MIPS_DB1500 is not set
+-# CONFIG_MIPS_DB1550 is not set
+-# CONFIG_MIPS_DB1200 is not set
+-# CONFIG_MIPS_MIRAGE is not set
+-# CONFIG_BASLER_EXCITE is not set
+-# CONFIG_MIPS_COBALT is not set
+-# CONFIG_MACH_DECSTATION is not set
+-# CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-CONFIG_MIPS_IVR=y
+-# CONFIG_MIPS_ITE8172 is not set
+-# CONFIG_MACH_JAZZ is not set
+-# CONFIG_LASAT is not set
+-# CONFIG_MIPS_ATLAS is not set
+-# CONFIG_MIPS_MALTA is not set
+-# CONFIG_MIPS_SEAD is not set
+-# CONFIG_WR_PPMC is not set
+-# CONFIG_MIPS_SIM is not set
+-# CONFIG_MOMENCO_JAGUAR_ATX is not set
+-# CONFIG_MOMENCO_OCELOT is not set
+-# CONFIG_MOMENCO_OCELOT_3 is not set
+-# CONFIG_MOMENCO_OCELOT_C is not set
+-# CONFIG_MOMENCO_OCELOT_G is not set
+-# CONFIG_MIPS_XXS1500 is not set
+-# CONFIG_PNX8550_V2PCI is not set
+-# CONFIG_PNX8550_JBS is not set
+-# CONFIG_DDB5477 is not set
+-# CONFIG_MACH_VR41XX is not set
+-# CONFIG_PMC_YOSEMITE is not set
+-# CONFIG_QEMU is not set
+-# CONFIG_MARKEINS is not set
+-# CONFIG_SGI_IP22 is not set
+-# CONFIG_SGI_IP27 is not set
+-# CONFIG_SGI_IP32 is not set
+-# CONFIG_SIBYTE_BIGSUR is not set
+-# CONFIG_SIBYTE_SWARM is not set
+-# CONFIG_SIBYTE_SENTOSA is not set
+-# CONFIG_SIBYTE_RHONE is not set
+-# CONFIG_SIBYTE_CARMEL is not set
+-# CONFIG_SIBYTE_PTSWARM is not set
+-# CONFIG_SIBYTE_LITTLESUR is not set
+-# CONFIG_SIBYTE_CRHINE is not set
+-# CONFIG_SIBYTE_CRHONE is not set
+-# CONFIG_SNI_RM200_PCI is not set
+-# CONFIG_TOSHIBA_JMR3927 is not set
+-# CONFIG_TOSHIBA_RBTX4927 is not set
+-# CONFIG_TOSHIBA_RBTX4938 is not set
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+-CONFIG_DMA_NONCOHERENT=y
+-CONFIG_DMA_NEED_PCI_MAP_STATE=y
+-# CONFIG_CPU_BIG_ENDIAN is not set
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+-CONFIG_ITE_BOARD_GEN=y
+-CONFIG_IT8172_CIR=y
+-CONFIG_MIPS_L1_CACHE_SHIFT=5
+-
+-#
+-# CPU selection
+-#
+-# CONFIG_CPU_MIPS32_R1 is not set
+-# CONFIG_CPU_MIPS32_R2 is not set
+-# CONFIG_CPU_MIPS64_R1 is not set
+-# CONFIG_CPU_MIPS64_R2 is not set
+-# CONFIG_CPU_R3000 is not set
+-# CONFIG_CPU_TX39XX is not set
+-# CONFIG_CPU_VR41XX is not set
+-# CONFIG_CPU_R4300 is not set
+-# CONFIG_CPU_R4X00 is not set
+-# CONFIG_CPU_TX49XX is not set
+-# CONFIG_CPU_R5000 is not set
+-# CONFIG_CPU_R5432 is not set
+-# CONFIG_CPU_R6000 is not set
+-CONFIG_CPU_NEVADA=y
+-# CONFIG_CPU_R8000 is not set
+-# CONFIG_CPU_R10000 is not set
+-# CONFIG_CPU_RM7000 is not set
+-# CONFIG_CPU_RM9000 is not set
+-# CONFIG_CPU_SB1 is not set
+-CONFIG_SYS_HAS_CPU_NEVADA=y
+-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+-
+-#
+-# Kernel type
+-#
+-CONFIG_32BIT=y
+-# CONFIG_64BIT is not set
+-CONFIG_PAGE_SIZE_4KB=y
+-# CONFIG_PAGE_SIZE_8KB is not set
+-# CONFIG_PAGE_SIZE_16KB is not set
+-# CONFIG_PAGE_SIZE_64KB is not set
+-CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+-# CONFIG_MIPS_MT_SMP is not set
+-# CONFIG_MIPS_VPE_LOADER is not set
+-CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_SYNC=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-# CONFIG_HZ_48 is not set
+-# CONFIG_HZ_100 is not set
+-# CONFIG_HZ_128 is not set
+-# CONFIG_HZ_250 is not set
+-# CONFIG_HZ_256 is not set
+-CONFIG_HZ_1000=y
+-# CONFIG_HZ_1024 is not set
+-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+-CONFIG_HZ=1000
+-CONFIG_PREEMPT_NONE=y
+-# CONFIG_PREEMPT_VOLUNTARY is not set
+-# CONFIG_PREEMPT is not set
+-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
+-CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+-CONFIG_LOCALVERSION=""
+-CONFIG_LOCALVERSION_AUTO=y
+-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_IKCONFIG is not set
+-CONFIG_RELAY=y
+-CONFIG_INITRAMFS_SOURCE=""
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+-CONFIG_EMBEDDED=y
+-CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+-CONFIG_HOTPLUG=y
+-CONFIG_PRINTK=y
+-CONFIG_BUG=y
+-CONFIG_ELF_CORE=y
+-CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-CONFIG_SHMEM=y
+-CONFIG_SLAB=y
+-CONFIG_VM_EVENT_COUNTERS=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_SLOB is not set
+-
+-#
+-# Loadable module support
+-#
+-CONFIG_MODULES=y
+-CONFIG_MODULE_UNLOAD=y
+-# CONFIG_MODULE_FORCE_UNLOAD is not set
+-CONFIG_MODVERSIONS=y
+-CONFIG_MODULE_SRCVERSION_ALL=y
+-CONFIG_KMOD=y
+-
+-#
+-# Block layer
+-#
+-# CONFIG_LBD is not set
+-# CONFIG_BLK_DEV_IO_TRACE is not set
+-# CONFIG_LSF is not set
+-
+-#
+-# IO Schedulers
+-#
+-CONFIG_IOSCHED_NOOP=y
+-CONFIG_IOSCHED_AS=y
+-CONFIG_IOSCHED_DEADLINE=y
+-CONFIG_IOSCHED_CFQ=y
+-CONFIG_DEFAULT_AS=y
+-# CONFIG_DEFAULT_DEADLINE is not set
+-# CONFIG_DEFAULT_CFQ is not set
+-# CONFIG_DEFAULT_NOOP is not set
+-CONFIG_DEFAULT_IOSCHED="anticipatory"
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+-#
+-CONFIG_HW_HAS_PCI=y
+-CONFIG_PCI=y
+-CONFIG_MMU=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PCI Hotplug Support
+-#
+-# CONFIG_HOTPLUG_PCI is not set
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_MISC is not set
+-CONFIG_TRAD_SIGNALS=y
+-
+-#
+-# Networking
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-# CONFIG_NETDEBUG is not set
+-CONFIG_PACKET=y
+-CONFIG_PACKET_MMAP=y
+-CONFIG_UNIX=y
+-CONFIG_XFRM=y
+-CONFIG_XFRM_USER=m
+-CONFIG_NET_KEY=y
+-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 is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_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_XFRM_TUNNEL is not set
+-# CONFIG_INET_TUNNEL is not set
+-CONFIG_INET_XFRM_MODE_TRANSPORT=m
+-CONFIG_INET_XFRM_MODE_TUNNEL=m
+-CONFIG_INET_DIAG=y
+-CONFIG_INET_TCP_DIAG=y
+-# CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
+-# CONFIG_IPV6 is not set
+-# CONFIG_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
+-CONFIG_NETWORK_SECMARK=y
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# DCCP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_DCCP is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_SCTP is not set
+-
+-#
+-# TIPC Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_TIPC 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
+-
+-#
+-# Network testing
+-#
+-# CONFIG_NET_PKTGEN is not set
+-# CONFIG_HAMRADIO is not set
+-# CONFIG_IRDA is not set
+-# CONFIG_BT is not set
+-CONFIG_IEEE80211=m
+-# CONFIG_IEEE80211_DEBUG is not set
+-CONFIG_IEEE80211_CRYPT_WEP=m
+-CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_SOFTMAC=m
+-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+-CONFIG_WIRELESS_EXT=y
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-CONFIG_FW_LOADER=m
+-# CONFIG_SYS_HYPERVISOR is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+-CONFIG_CONNECTOR=m
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-# CONFIG_MTD is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_CPQ_DA is not set
+-# CONFIG_BLK_CPQ_CISS_DA is not set
+-# CONFIG_BLK_DEV_DAC960 is not set
+-# CONFIG_BLK_DEV_UMEM is not set
+-# CONFIG_BLK_DEV_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_INITRD is not set
+-CONFIG_CDROM_PKTCDVD=m
+-CONFIG_CDROM_PKTCDVD_BUFFERS=8
+-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+-CONFIG_ATA_OVER_ETH=m
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-CONFIG_IDE=y
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/ide.txt for help/info on IDE drives
+-#
+-# CONFIG_BLK_DEV_IDE_SATA is not set
+-CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
+-# CONFIG_BLK_DEV_IDECD 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_BLK_DEV_IDEPCI is not set
+-# CONFIG_IDE_ARM is not set
+-# CONFIG_BLK_DEV_IDEDMA is not set
+-# CONFIG_IDEDMA_AUTO is not set
+-# CONFIG_BLK_DEV_HD is not set
+-
+-#
+-# SCSI device support
+-#
+-CONFIG_RAID_ATTRS=m
+-# 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
+-
+-#
+-# Network device support
+-#
+-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
+-
+-#
+-# PHY device support
+-#
+-CONFIG_PHYLIB=m
+-
+-#
+-# MII PHY device drivers
+-#
+-CONFIG_MARVELL_PHY=m
+-CONFIG_DAVICOM_PHY=m
+-CONFIG_QSEMI_PHY=m
+-CONFIG_LXT_PHY=m
+-CONFIG_CICADA_PHY=m
+-CONFIG_VITESSE_PHY=m
+-CONFIG_SMSC_PHY=m
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-CONFIG_NET_ETHERNET=y
+-# CONFIG_MII is not set
+-# CONFIG_HAPPYMEAL is not set
+-# CONFIG_SUNGEM is not set
+-# CONFIG_CASSINI is not set
+-# CONFIG_NET_VENDOR_3COM is not set
+-# CONFIG_DM9000 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_SIS190 is not set
+-# CONFIG_SKGE is not set
+-# CONFIG_SKY2 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_TIGON3 is not set
+-# CONFIG_BNX2 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_CHELSIO_T1 is not set
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-# CONFIG_MYRI10GE 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
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-
+-#
+-# Userland interfaces
+-#
+-CONFIG_INPUT_MOUSEDEV=y
+-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input 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
+-
+-#
+-# Hardware I/O ports
+-#
+-CONFIG_SERIO=y
+-# CONFIG_SERIO_I8042 is not set
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_PCIPS2 is not set
+-# CONFIG_SERIO_LIBPS2 is not set
+-CONFIG_SERIO_RAW=m
+-# CONFIG_GAMEPORT is not set
+-
+-#
+-# Character devices
+-#
+-CONFIG_VT=y
+-CONFIG_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-CONFIG_VT_HW_CONSOLE_BINDING=y
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-CONFIG_QTRONIX_KEYBOARD=y
+-CONFIG_IT8172_SCR0=y
+-CONFIG_IT8172_SCR1=y
+-
+-#
+-# Serial drivers
+-#
+-CONFIG_SERIAL_8250=y
+-CONFIG_SERIAL_8250_CONSOLE=y
+-CONFIG_SERIAL_8250_PCI=y
+-CONFIG_SERIAL_8250_NR_UARTS=4
+-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+-# CONFIG_SERIAL_8250_EXTENDED 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=y
+-CONFIG_LEGACY_PTY_COUNT=256
+-
+-#
+-# IPMI
+-#
+-# CONFIG_IPMI_HANDLER is not set
+-
+-#
+-# Watchdog Cards
+-#
+-# CONFIG_WATCHDOG is not set
+-# CONFIG_HW_RANDOM is not set
+-CONFIG_RTC=y
+-# 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
+-# CONFIG_TELCLOCK is not set
+-
+-#
+-# I2C support
+-#
+-# CONFIG_I2C is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
+-
+-#
+-# Dallas's 1-wire bus
+-#
+-# CONFIG_W1 is not set
+-
+-#
+-# Hardware Monitoring support
+-#
+-# CONFIG_HWMON is not set
+-# CONFIG_HWMON_VID is not set
+-
+-#
+-# Misc devices
+-#
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+-
+-#
+-# Digital Video Broadcasting Devices
+-#
+-# CONFIG_DVB is not set
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_FIRMWARE_EDID is not set
+-# CONFIG_FB is not set
+-
+-#
+-# Console display driver support
+-#
+-# CONFIG_VGA_CONSOLE is not set
+-CONFIG_DUMMY_CONSOLE=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
+-CONFIG_USB_ARCH_HAS_HCD=y
+-CONFIG_USB_ARCH_HAS_OHCI=y
+-CONFIG_USB_ARCH_HAS_EHCI=y
+-# CONFIG_USB is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-
+-#
+-# MMC/SD Card support
+-#
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
+-
+-#
+-# LED drivers
+-#
+-
+-#
+-# LED Triggers
+-#
+-
+-#
+-# InfiniBand support
+-#
+-# CONFIG_INFINIBAND is not set
+-
+-#
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+-#
+-
+-#
+-# Real Time Clock
+-#
+-# CONFIG_RTC_CLASS is not set
+-
+-#
+-# DMA Engine support
+-#
+-# CONFIG_DMA_ENGINE is not set
+-
+-#
+-# DMA Clients
+-#
+-
+-#
+-# DMA Devices
+-#
+-
+-#
+-# File systems
+-#
+-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_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-# CONFIG_XFS_FS is not set
+-# CONFIG_OCFS2_FS is not set
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-CONFIG_FUSE_FS=m
+-
+-#
+-# 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_TMPFS is not set
+-# CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-# CONFIG_CONFIGFS_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_CIFS_DEBUG2 is not set
+-# 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
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-# CONFIG_MAGIC_SYSRQ is not set
+-# CONFIG_UNUSED_SYMBOLS is not set
+-# CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_DEBUG_FS is not set
+-CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE=""
+-
+-#
+-# Security options
+-#
+-CONFIG_KEYS=y
+-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+-# CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-CONFIG_CRYPTO=y
+-CONFIG_CRYPTO_HMAC=y
+-CONFIG_CRYPTO_NULL=m
+-CONFIG_CRYPTO_MD4=m
+-CONFIG_CRYPTO_MD5=m
+-CONFIG_CRYPTO_SHA1=m
+-CONFIG_CRYPTO_SHA256=m
+-CONFIG_CRYPTO_SHA512=m
+-CONFIG_CRYPTO_WP512=m
+-CONFIG_CRYPTO_TGR192=m
+-CONFIG_CRYPTO_DES=m
+-CONFIG_CRYPTO_BLOWFISH=m
+-CONFIG_CRYPTO_TWOFISH=m
+-CONFIG_CRYPTO_SERPENT=m
+-CONFIG_CRYPTO_AES=m
+-CONFIG_CRYPTO_CAST5=m
+-CONFIG_CRYPTO_CAST6=m
+-CONFIG_CRYPTO_TEA=m
+-CONFIG_CRYPTO_ARC4=m
+-CONFIG_CRYPTO_KHAZAD=m
+-CONFIG_CRYPTO_ANUBIS=m
+-CONFIG_CRYPTO_DEFLATE=m
+-CONFIG_CRYPTO_MICHAEL_MIC=m
+-CONFIG_CRYPTO_CRC32C=m
+-# CONFIG_CRYPTO_TEST is not set
+-
+-#
+-# Hardware crypto devices
+-#
+-
+-#
+-# Library routines
+-#
+-# CONFIG_CRC_CCITT is not set
+-CONFIG_CRC16=m
+-CONFIG_CRC32=m
+-CONFIG_LIBCRC32C=m
+-CONFIG_ZLIB_INFLATE=m
+-CONFIG_ZLIB_DEFLATE=m
+-CONFIG_PLIST=y
+diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig
+index 5d9eb11..9d4d17a 100644
+--- a/arch/mips/configs/jaguar-atx_defconfig
++++ b/arch/mips/configs/jaguar-atx_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -154,6 +153,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -731,7 +732,7 @@ CONFIG_FUSE_FS=m
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+
+@@ -776,6 +777,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig
+new file mode 100644
+index 0000000..382083e
+--- /dev/null
++++ b/arch/mips/configs/jazz_defconfig
+@@ -0,0 +1,1404 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.19-rc1
++# Sun Oct 8 19:03:07 2006
++#
++CONFIG_MIPS=y
++
++#
++# Machine selection
++#
++# CONFIG_MIPS_MTX1 is not set
++# CONFIG_MIPS_BOSPORUS is not set
++# CONFIG_MIPS_PB1000 is not set
++# CONFIG_MIPS_PB1100 is not set
++# CONFIG_MIPS_PB1500 is not set
++# CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_PB1200 is not set
++# CONFIG_MIPS_DB1000 is not set
++# CONFIG_MIPS_DB1100 is not set
++# CONFIG_MIPS_DB1500 is not set
++# CONFIG_MIPS_DB1550 is not set
++# CONFIG_MIPS_DB1200 is not set
++# CONFIG_MIPS_MIRAGE is not set
++# CONFIG_BASLER_EXCITE is not set
++# CONFIG_MIPS_COBALT is not set
++# CONFIG_MACH_DECSTATION is not set
++# CONFIG_MIPS_EV64120 is not set
++CONFIG_MACH_JAZZ=y
++# CONFIG_LASAT is not set
++# CONFIG_MIPS_ATLAS is not set
++# CONFIG_MIPS_MALTA is not set
++# CONFIG_MIPS_SEAD is not set
++# CONFIG_WR_PPMC is not set
++# CONFIG_MIPS_SIM is not set
++# CONFIG_MOMENCO_JAGUAR_ATX is not set
++# CONFIG_MOMENCO_OCELOT is not set
++# CONFIG_MOMENCO_OCELOT_3 is not set
++# CONFIG_MOMENCO_OCELOT_C is not set
++# CONFIG_MOMENCO_OCELOT_G is not set
++# CONFIG_MIPS_XXS1500 is not set
++# CONFIG_PNX8550_V2PCI is not set
++# CONFIG_PNX8550_JBS is not set
++# CONFIG_DDB5477 is not set
++# CONFIG_MACH_VR41XX is not set
++# CONFIG_PMC_YOSEMITE is not set
++# CONFIG_QEMU is not set
++# CONFIG_MARKEINS is not set
++# CONFIG_SGI_IP22 is not set
++# CONFIG_SGI_IP27 is not set
++# CONFIG_SGI_IP32 is not set
++# CONFIG_SIBYTE_BIGSUR is not set
++# CONFIG_SIBYTE_SWARM is not set
++# CONFIG_SIBYTE_SENTOSA is not set
++# CONFIG_SIBYTE_RHONE is not set
++# CONFIG_SIBYTE_CARMEL is not set
++# CONFIG_SIBYTE_PTSWARM is not set
++# CONFIG_SIBYTE_LITTLESUR is not set
++# CONFIG_SIBYTE_CRHINE is not set
++# CONFIG_SIBYTE_CRHONE is not set
++# CONFIG_SNI_RM200_PCI is not set
++# CONFIG_TOSHIBA_JMR3927 is not set
++# CONFIG_TOSHIBA_RBTX4927 is not set
++# CONFIG_TOSHIBA_RBTX4938 is not set
++# CONFIG_ACER_PICA_61 is not set
++# CONFIG_MIPS_MAGNUM_4000 is not set
++CONFIG_OLIVETTI_M700=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
++CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
++CONFIG_ARC=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_DMA_NONCOHERENT=y
++CONFIG_DMA_NEED_PCI_MAP_STATE=y
++CONFIG_GENERIC_ISA_DMA=y
++CONFIG_I8259=y
++# CONFIG_CPU_BIG_ENDIAN is not set
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
++CONFIG_ARC32=y
++CONFIG_MIPS_L1_CACHE_SHIFT=5
++CONFIG_ARC_MEMORY=y
++CONFIG_ARC_PROMLIB=y
++
++#
++# CPU selection
++#
++# CONFIG_CPU_MIPS32_R1 is not set
++# CONFIG_CPU_MIPS32_R2 is not set
++# CONFIG_CPU_MIPS64_R1 is not set
++# CONFIG_CPU_MIPS64_R2 is not set
++# CONFIG_CPU_R3000 is not set
++# CONFIG_CPU_TX39XX is not set
++# CONFIG_CPU_VR41XX is not set
++# CONFIG_CPU_R4300 is not set
++CONFIG_CPU_R4X00=y
++# CONFIG_CPU_TX49XX is not set
++# CONFIG_CPU_R5000 is not set
++# CONFIG_CPU_R5432 is not set
++# CONFIG_CPU_R6000 is not set
++# CONFIG_CPU_NEVADA is not set
++# CONFIG_CPU_R8000 is not set
++# CONFIG_CPU_R10000 is not set
++# CONFIG_CPU_RM7000 is not set
++# CONFIG_CPU_RM9000 is not set
++# CONFIG_CPU_SB1 is not set
++CONFIG_SYS_HAS_CPU_R4X00=y
++CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
++CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
++CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
++CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
++
++#
++# Kernel type
++#
++CONFIG_32BIT=y
++# CONFIG_64BIT is not set
++CONFIG_PAGE_SIZE_4KB=y
++# CONFIG_PAGE_SIZE_8KB is not set
++# CONFIG_PAGE_SIZE_16KB is not set
++# CONFIG_PAGE_SIZE_64KB is not set
++CONFIG_MIPS_MT_DISABLED=y
++# CONFIG_MIPS_MT_SMP is not set
++# CONFIG_MIPS_MT_SMTC is not set
++# CONFIG_MIPS_VPE_LOADER is not set
++# CONFIG_64BIT_PHYS_ADDR is not set
++CONFIG_CPU_HAS_LLSC=y
++CONFIG_CPU_HAS_SYNC=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_HZ_48 is not set
++CONFIG_HZ_100=y
++# CONFIG_HZ_128 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_256 is not set
++# CONFIG_HZ_1000 is not set
++# CONFIG_HZ_1024 is not set
++CONFIG_SYS_SUPPORTS_100HZ=y
++CONFIG_HZ=100
++# CONFIG_PREEMPT_NONE is not set
++CONFIG_PREEMPT_VOLUNTARY=y
++# CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_RELAY=y
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++CONFIG_MODVERSIONS=y
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# Bus options (PCI, PCMCIA, EISA, ISA, TC)
++#
++CONFIG_ISA=y
++CONFIG_MMU=y
++CONFIG_I8253=y
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=m
++CONFIG_TRAD_SIGNALS=y
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=m
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++CONFIG_NET_KEY=m
++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=m
++CONFIG_NET_IPGRE=m
++CONFIG_NET_IPGRE_BROADCAST=y
++CONFIG_IP_MROUTE=y
++CONFIG_IP_PIMSM_V1=y
++CONFIG_IP_PIMSM_V2=y
++# 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_XFRM_TUNNEL is not set
++CONFIG_INET_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++CONFIG_IPV6=m
++CONFIG_IPV6_PRIVACY=y
++CONFIG_IPV6_ROUTER_PREF=y
++CONFIG_IPV6_ROUTE_INFO=y
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++# CONFIG_IPV6_MIP6 is not set
++CONFIG_INET6_XFRM_TUNNEL=m
++CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_TUNNEL=m
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++CONFIG_NETWORK_SECMARK=y
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_BRIDGE_NETFILTER=y
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=m
++CONFIG_NETFILTER_NETLINK_QUEUE=m
++CONFIG_NETFILTER_NETLINK_LOG=m
++CONFIG_NETFILTER_XTABLES=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_TARGET_SECMARK=m
++# CONFIG_NETFILTER_XT_TARGET_CONNSECMARK is not set
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_SCTP=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_IP_NF_CONNTRACK=m
++# CONFIG_IP_NF_CT_ACCT is not set
++CONFIG_IP_NF_CONNTRACK_MARK=y
++CONFIG_IP_NF_CONNTRACK_SECMARK=y
++CONFIG_IP_NF_CONNTRACK_EVENTS=y
++CONFIG_IP_NF_CONNTRACK_NETLINK=m
++CONFIG_IP_NF_CT_PROTO_SCTP=m
++CONFIG_IP_NF_FTP=m
++CONFIG_IP_NF_IRC=m
++# CONFIG_IP_NF_NETBIOS_NS is not set
++CONFIG_IP_NF_TFTP=m
++CONFIG_IP_NF_AMANDA=m
++CONFIG_IP_NF_PPTP=m
++CONFIG_IP_NF_H323=m
++CONFIG_IP_NF_SIP=m
++CONFIG_IP_NF_QUEUE=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_IPRANGE=m
++CONFIG_IP_NF_MATCH_TOS=m
++CONFIG_IP_NF_MATCH_RECENT=m
++CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_AH=m
++CONFIG_IP_NF_MATCH_TTL=m
++CONFIG_IP_NF_MATCH_OWNER=m
++CONFIG_IP_NF_MATCH_ADDRTYPE=m
++CONFIG_IP_NF_MATCH_HASHLIMIT=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_TARGET_LOG=m
++CONFIG_IP_NF_TARGET_ULOG=m
++CONFIG_IP_NF_TARGET_TCPMSS=m
++CONFIG_IP_NF_NAT=m
++CONFIG_IP_NF_NAT_NEEDED=y
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_IP_NF_TARGET_NETMAP=m
++CONFIG_IP_NF_TARGET_SAME=m
++CONFIG_IP_NF_NAT_SNMP_BASIC=m
++CONFIG_IP_NF_NAT_IRC=m
++CONFIG_IP_NF_NAT_FTP=m
++CONFIG_IP_NF_NAT_TFTP=m
++CONFIG_IP_NF_NAT_AMANDA=m
++CONFIG_IP_NF_NAT_PPTP=m
++CONFIG_IP_NF_NAT_H323=m
++CONFIG_IP_NF_NAT_SIP=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_TARGET_TOS=m
++CONFIG_IP_NF_TARGET_ECN=m
++CONFIG_IP_NF_TARGET_TTL=m
++CONFIG_IP_NF_TARGET_CLUSTERIP=m
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_IP_NF_ARPFILTER=m
++CONFIG_IP_NF_ARP_MANGLE=m
++
++#
++# IPv6: Netfilter Configuration (EXPERIMENTAL)
++#
++CONFIG_IP6_NF_QUEUE=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_HL=m
++CONFIG_IP6_NF_MATCH_OWNER=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_LOG=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_TARGET_HL=m
++CONFIG_IP6_NF_RAW=m
++
++#
++# DECnet: Netfilter Configuration
++#
++CONFIG_DECNET_NF_GRABULATOR=m
++
++#
++# Bridge: Netfilter Configuration
++#
++CONFIG_BRIDGE_NF_EBTABLES=m
++CONFIG_BRIDGE_EBT_BROUTE=m
++CONFIG_BRIDGE_EBT_T_FILTER=m
++CONFIG_BRIDGE_EBT_T_NAT=m
++CONFIG_BRIDGE_EBT_802_3=m
++CONFIG_BRIDGE_EBT_AMONG=m
++CONFIG_BRIDGE_EBT_ARP=m
++CONFIG_BRIDGE_EBT_IP=m
++CONFIG_BRIDGE_EBT_LIMIT=m
++CONFIG_BRIDGE_EBT_MARK=m
++CONFIG_BRIDGE_EBT_PKTTYPE=m
++CONFIG_BRIDGE_EBT_STP=m
++CONFIG_BRIDGE_EBT_VLAN=m
++CONFIG_BRIDGE_EBT_ARPREPLY=m
++CONFIG_BRIDGE_EBT_DNAT=m
++CONFIG_BRIDGE_EBT_MARK_T=m
++CONFIG_BRIDGE_EBT_REDIRECT=m
++CONFIG_BRIDGE_EBT_SNAT=m
++CONFIG_BRIDGE_EBT_LOG=m
++CONFIG_BRIDGE_EBT_ULOG=m
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++CONFIG_BRIDGE=m
++# CONFIG_VLAN_8021Q is not set
++CONFIG_DECNET=m
++# CONFIG_DECNET_ROUTER is not set
++CONFIG_LLC=m
++# 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_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
++
++#
++# Queueing/Scheduling
++#
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++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=m
++CONFIG_NET_SCH_INGRESS=m
++
++#
++# Classification
++#
++CONFIG_NET_CLS=y
++CONFIG_NET_CLS_BASIC=m
++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_CLS_U32_MARK is not set
++CONFIG_NET_CLS_RSVP=m
++CONFIG_NET_CLS_RSVP6=m
++# CONFIG_NET_EMATCH is not set
++# CONFIG_NET_CLS_ACT is not set
++CONFIG_NET_CLS_POLICE=y
++# CONFIG_NET_CLS_IND is not set
++CONFIG_NET_ESTIMATOR=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++CONFIG_HAMRADIO=y
++
++#
++# Packet Radio protocols
++#
++CONFIG_AX25=m
++CONFIG_AX25_DAMA_SLAVE=y
++CONFIG_NETROM=m
++CONFIG_ROSE=m
++
++#
++# AX.25 network device drivers
++#
++CONFIG_MKISS=m
++CONFIG_6PACK=m
++CONFIG_BPQETHER=m
++# CONFIG_BAYCOM_SER_FDX is not set
++# CONFIG_BAYCOM_SER_HDX is not set
++# CONFIG_BAYCOM_PAR is not set
++# CONFIG_BAYCOM_EPP is not set
++# CONFIG_YAM is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++CONFIG_IEEE80211_CRYPT_CCMP=m
++CONFIG_IEEE80211_SOFTMAC=m
++# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
++CONFIG_WIRELESS_EXT=y
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++CONFIG_CONNECTOR=m
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Parallel port support
++#
++CONFIG_PARPORT=m
++CONFIG_PARPORT_PC=m
++# CONFIG_PARPORT_PC_FIFO is not set
++# CONFIG_PARPORT_PC_SUPERIO is not set
++# CONFIG_PARPORT_GSC is not set
++# CONFIG_PARPORT_AX88796 is not set
++CONFIG_PARPORT_1284=y
++
++#
++# Plug and Play support
++#
++# CONFIG_PNP is not set
++
++#
++# Block devices
++#
++CONFIG_BLK_DEV_FD=m
++CONFIG_PARIDE=m
++CONFIG_PARIDE_PARPORT=m
++
++#
++# Parallel IDE high-level drivers
++#
++CONFIG_PARIDE_PD=m
++CONFIG_PARIDE_PCD=m
++CONFIG_PARIDE_PF=m
++CONFIG_PARIDE_PT=m
++CONFIG_PARIDE_PG=m
++
++#
++# Parallel IDE protocol modules
++#
++CONFIG_PARIDE_ATEN=m
++CONFIG_PARIDE_BPCK=m
++CONFIG_PARIDE_BPCK6=m
++CONFIG_PARIDE_COMM=m
++CONFIG_PARIDE_DSTR=m
++CONFIG_PARIDE_FIT2=m
++CONFIG_PARIDE_FIT3=m
++CONFIG_PARIDE_EPAT=m
++# CONFIG_PARIDE_EPATC8 is not set
++CONFIG_PARIDE_EPIA=m
++CONFIG_PARIDE_FRIQ=m
++CONFIG_PARIDE_FRPW=m
++CONFIG_PARIDE_KBIC=m
++CONFIG_PARIDE_KTTI=m
++CONFIG_PARIDE_ON20=m
++CONFIG_PARIDE_ON26=m
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=m
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_NBD=m
++CONFIG_BLK_DEV_RAM=m
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CDROM_PKTCDVD=m
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++CONFIG_ATA_OVER_ETH=m
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_RAID_ATTRS=m
++CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++CONFIG_CHR_DEV_ST=m
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=m
++CONFIG_BLK_DEV_SR_VENDOR=y
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_MULTI_LUN is not set
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transports
++#
++CONFIG_SCSI_SPI_ATTRS=y
++CONFIG_SCSI_FC_ATTRS=y
++CONFIG_SCSI_ISCSI_ATTRS=m
++CONFIG_SCSI_SAS_ATTRS=m
++# CONFIG_SCSI_SAS_LIBSAS is not set
++
++#
++# SCSI low-level drivers
++#
++CONFIG_ISCSI_TCP=m
++# CONFIG_SCSI_AHA152X is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_IN2000 is not set
++# CONFIG_SCSI_DTC3280 is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_GENERIC_NCR5380 is not set
++# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
++CONFIG_SCSI_PPA=m
++CONFIG_SCSI_IMM=m
++# CONFIG_SCSI_IZIP_EPP16 is not set
++# CONFIG_SCSI_IZIP_SLOW_CTR is not set
++# CONFIG_SCSI_NCR53C406A is not set
++# CONFIG_SCSI_PAS16 is not set
++# CONFIG_SCSI_PSI240I is not set
++# CONFIG_SCSI_QLOGIC_FAS is not set
++# CONFIG_SCSI_SYM53C416 is not set
++# CONFIG_SCSI_T128 is not set
++# CONFIG_SCSI_DEBUG is not set
++CONFIG_JAZZ_ESP=y
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
++# Old CD-ROM drivers (not SCSI, not IDE)
++#
++# CONFIG_CD_NO_IDESCSI is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++CONFIG_MD=y
++CONFIG_BLK_DEV_MD=m
++CONFIG_MD_LINEAR=m
++CONFIG_MD_RAID0=m
++CONFIG_MD_RAID1=m
++CONFIG_MD_RAID10=m
++CONFIG_MD_RAID456=m
++CONFIG_MD_RAID5_RESHAPE=y
++CONFIG_MD_MULTIPATH=m
++CONFIG_MD_FAULTY=m
++CONFIG_BLK_DEV_DM=m
++# CONFIG_DM_DEBUG is not set
++# CONFIG_DM_CRYPT is not set
++CONFIG_DM_SNAPSHOT=m
++CONFIG_DM_MIRROR=m
++CONFIG_DM_ZERO=m
++CONFIG_DM_MULTIPATH=m
++CONFIG_DM_MULTIPATH_EMC=m
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++CONFIG_DUMMY=m
++CONFIG_BONDING=m
++CONFIG_EQUALIZER=m
++CONFIG_TUN=m
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++
++#
++# PHY device support
++#
++CONFIG_PHYLIB=m
++
++#
++# MII PHY device drivers
++#
++CONFIG_MARVELL_PHY=m
++CONFIG_DAVICOM_PHY=m
++CONFIG_QSEMI_PHY=m
++CONFIG_LXT_PHY=m
++CONFIG_CICADA_PHY=m
++CONFIG_VITESSE_PHY=m
++CONFIG_SMSC_PHY=m
++# CONFIG_FIXED_PHY is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++CONFIG_MIPS_JAZZ_SONIC=y
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_DM9000 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=y
++# CONFIG_E2100 is not set
++# CONFIG_EWRK3 is not set
++# CONFIG_EEXPRESS is not set
++# CONFIG_EEXPRESS_PRO is not set
++# CONFIG_HPLAN_PLUS is not set
++# CONFIG_HPLAN is not set
++# CONFIG_LP486E is not set
++# CONFIG_ETH16I is not set
++CONFIG_NE2000=m
++# CONFIG_SEEQ8005 is not set
++CONFIG_NET_PCI=y
++# CONFIG_AC3200 is not set
++# CONFIG_APRICOT is not set
++# CONFIG_CS89x0 is not set
++# CONFIG_LAN_SAA9730 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 is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++CONFIG_PLIP=m
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=m
++
++#
++# 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_KEYBOARD_STOWAWAY 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_I8042=y
++CONFIG_SERIO_SERPORT=y
++CONFIG_SERIO_PARKBD=m
++CONFIG_SERIO_LIBPS2=y
++CONFIG_SERIO_RAW=m
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=m
++CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
++CONFIG_SERIAL_8250_EXTENDED=y
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++CONFIG_SERIAL_8250_SHARE_IRQ=y
++CONFIG_SERIAL_8250_DETECT_IRQ=y
++CONFIG_SERIAL_8250_RSA=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=m
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++CONFIG_PRINTER=m
++# CONFIG_LP_CONSOLE is not set
++CONFIG_PPDEV=m
++CONFIG_TIPAR=m
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
++CONFIG_RTC=m
++# CONFIG_GEN_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++CONFIG_W1=m
++CONFIG_W1_CON=y
++
++#
++# 1-wire Bus Masters
++#
++
++#
++# 1-wire Slaves
++#
++# CONFIG_W1_SLAVE_THERM is not set
++# CONFIG_W1_SLAVE_SMEM is not set
++# CONFIG_W1_SLAVE_DS2433 is not set
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
++
++#
++# Misc devices
++#
++# CONFIG_TIFM_CORE is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB is not set
++
++#
++# Console display driver support
++#
++CONFIG_VGA_CONSOLE=y
++# CONFIG_VGACON_SOFT_SCROLLBACK is not set
++# CONFIG_MDA_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
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=m
++# CONFIG_EXT2_FS_XATTR 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
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++CONFIG_REISERFS_FS=m
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++CONFIG_REISERFS_FS_XATTR=y
++CONFIG_REISERFS_FS_POSIX_ACL=y
++CONFIG_REISERFS_FS_SECURITY=y
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_XFS_FS=m
++CONFIG_XFS_QUOTA=y
++CONFIG_XFS_SECURITY=y
++# CONFIG_XFS_POSIX_ACL is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_MINIX_FS=m
++CONFIG_ROMFS_FS=m
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_QUOTACTL=y
++CONFIG_DNOTIFY=y
++CONFIG_AUTOFS_FS=m
++CONFIG_AUTOFS4_FS=m
++CONFIG_FUSE_FS=m
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=m
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++CONFIG_ZISOFS_FS=m
++CONFIG_UDF_FS=m
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_VFAT_FS=m
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++CONFIG_NTFS_FS=m
++# CONFIG_NTFS_DEBUG is not set
++# CONFIG_NTFS_RW is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++CONFIG_ADFS_FS=m
++# CONFIG_ADFS_FS_RW is not set
++CONFIG_AFFS_FS=m
++# CONFIG_ECRYPT_FS is not set
++CONFIG_HFS_FS=m
++# CONFIG_HFSPLUS_FS is not set
++CONFIG_BEFS_FS=m
++# CONFIG_BEFS_DEBUG is not set
++CONFIG_BFS_FS=m
++CONFIG_EFS_FS=m
++CONFIG_CRAMFS=m
++CONFIG_VXFS_FS=m
++CONFIG_HPFS_FS=m
++CONFIG_QNX4FS_FS=m
++CONFIG_SYSV_FS=m
++CONFIG_UFS_FS=m
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_UFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++CONFIG_NFS_FS=m
++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=m
++CONFIG_NFSD_V3=y
++# CONFIG_NFSD_V3_ACL is not set
++# CONFIG_NFSD_V4 is not set
++CONFIG_NFSD_TCP=y
++CONFIG_LOCKD=m
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=m
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=m
++CONFIG_SUNRPC_GSS=m
++CONFIG_RPCSEC_GSS_KRB5=m
++CONFIG_RPCSEC_GSS_SPKM3=m
++CONFIG_SMB_FS=m
++# CONFIG_SMB_NLS_DEFAULT is not set
++CONFIG_CIFS=m
++# CONFIG_CIFS_STATS is not set
++# CONFIG_CIFS_WEAK_PW_HASH is not set
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_CIFS_EXPERIMENTAL is not set
++CONFIG_NCP_FS=m
++CONFIG_NCPFS_PACKET_SIGNING=y
++CONFIG_NCPFS_IOCTL_LOCKING=y
++CONFIG_NCPFS_STRONG=y
++CONFIG_NCPFS_NFS_NS=y
++CONFIG_NCPFS_OS2_NS=y
++CONFIG_NCPFS_SMALLDOS=y
++CONFIG_NCPFS_NLS=y
++CONFIG_NCPFS_EXTRAS=y
++CONFIG_CODA_FS=m
++CONFIG_CODA_FS_OLD_API=y
++CONFIG_AFS_FS=m
++CONFIG_RXRPC=m
++# CONFIG_9P_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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++CONFIG_NLS=m
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++CONFIG_NLS_CODEPAGE_737=m
++CONFIG_NLS_CODEPAGE_775=m
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++CONFIG_NLS_CODEPAGE_855=m
++CONFIG_NLS_CODEPAGE_857=m
++CONFIG_NLS_CODEPAGE_860=m
++CONFIG_NLS_CODEPAGE_861=m
++CONFIG_NLS_CODEPAGE_862=m
++CONFIG_NLS_CODEPAGE_863=m
++CONFIG_NLS_CODEPAGE_864=m
++CONFIG_NLS_CODEPAGE_865=m
++CONFIG_NLS_CODEPAGE_866=m
++CONFIG_NLS_CODEPAGE_869=m
++CONFIG_NLS_CODEPAGE_936=m
++CONFIG_NLS_CODEPAGE_950=m
++CONFIG_NLS_CODEPAGE_932=m
++CONFIG_NLS_CODEPAGE_949=m
++CONFIG_NLS_CODEPAGE_874=m
++CONFIG_NLS_ISO8859_8=m
++CONFIG_NLS_CODEPAGE_1250=m
++CONFIG_NLS_CODEPAGE_1251=m
++CONFIG_NLS_ASCII=m
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++CONFIG_NLS_ISO8859_5=m
++CONFIG_NLS_ISO8859_6=m
++CONFIG_NLS_ISO8859_7=m
++CONFIG_NLS_ISO8859_9=m
++CONFIG_NLS_ISO8859_13=m
++CONFIG_NLS_ISO8859_14=m
++CONFIG_NLS_ISO8859_15=m
++CONFIG_NLS_KOI8_R=m
++CONFIG_NLS_KOI8_U=m
++CONFIG_NLS_UTF8=m
++
++#
++# Distributed Lock Manager
++#
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_FS is not set
++CONFIG_CROSSCOMPILE=y
++CONFIG_CMDLINE=""
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++CONFIG_KEYS_DEBUG_PROC_KEYS=y
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_HMAC=y
++CONFIG_CRYPTO_NULL=m
++CONFIG_CRYPTO_MD4=m
++CONFIG_CRYPTO_MD5=m
++CONFIG_CRYPTO_SHA1=m
++CONFIG_CRYPTO_SHA256=m
++CONFIG_CRYPTO_SHA512=m
++CONFIG_CRYPTO_WP512=m
++CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
++CONFIG_CRYPTO_DES=m
++CONFIG_CRYPTO_BLOWFISH=m
++CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
++CONFIG_CRYPTO_SERPENT=m
++CONFIG_CRYPTO_AES=m
++CONFIG_CRYPTO_CAST5=m
++CONFIG_CRYPTO_CAST6=m
++CONFIG_CRYPTO_TEA=m
++CONFIG_CRYPTO_ARC4=m
++CONFIG_CRYPTO_KHAZAD=m
++CONFIG_CRYPTO_ANUBIS=m
++CONFIG_CRYPTO_DEFLATE=m
++CONFIG_CRYPTO_MICHAEL_MIC=m
++CONFIG_CRYPTO_CRC32C=m
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Hardware crypto devices
++#
++
++#
++# Library routines
++#
++CONFIG_CRC_CCITT=m
++CONFIG_CRC16=m
++CONFIG_CRC32=y
++CONFIG_LIBCRC32C=m
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_TEXTSEARCH_BM=m
++CONFIG_TEXTSEARCH_FSM=m
++CONFIG_PLIST=y
+diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
+index be45a90..d037466 100644
+--- a/arch/mips/configs/jmr3927_defconfig
++++ b/arch/mips/configs/jmr3927_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -144,6 +143,8 @@ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
+ CONFIG_RTC_DS1742=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -873,6 +874,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig
+index 64dc9f4..1db8249 100644
+--- a/arch/mips/configs/lasat200_defconfig
++++ b/arch/mips/configs/lasat200_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -152,6 +151,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -905,7 +906,7 @@ CONFIG_FUSE_FS=m
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -971,6 +972,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
+index 2690baf..101e803 100644
+--- a/arch/mips/configs/malta_defconfig
++++ b/arch/mips/configs/malta_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:13 2006
++# Linux kernel version: 2.6.19-rc1
++# Fri Oct 6 17:34:55 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,9 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+ # CONFIG_LASAT is not set
+ # CONFIG_MIPS_ATLAS is not set
+@@ -68,6 +65,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
+ CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+ CONFIG_DMA_NONCOHERENT=y
+@@ -135,19 +133,19 @@ CONFIG_MIPS_CPU_SCACHE=y
+ CONFIG_CPU_HAS_PREFETCH=y
+ # CONFIG_MIPS_MT_DISABLED is not set
+ # CONFIG_MIPS_MT_SMTC is not set
+-# CONFIG_MIPS_MT_SMP is not set
+-CONFIG_MIPS_VPE_LOADER=y
++CONFIG_MIPS_MT_SMP=y
++# CONFIG_MIPS_VPE_LOADER is not set
+ CONFIG_MIPS_MT=y
+ CONFIG_SYS_SUPPORTS_MULTITHREADING=y
+ CONFIG_MIPS_MT_FPAFF=y
+-CONFIG_MIPS_VPE_LOADER_TOM=y
+-CONFIG_MIPS_VPE_APSP_API=y
+-CONFIG_MIPS_APSP_KSPD=y
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ CONFIG_CPU_HAS_LLSC=y
++CONFIG_CPU_MIPSR2_IRQ_VI=y
++CONFIG_CPU_MIPSR2_SRS=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_IRQ_PER_CPU=y
+ CONFIG_CPU_SUPPORTS_HIGHMEM=y
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+@@ -159,6 +157,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
+ # CONFIG_RESOURCES_64BIT is not set
++CONFIG_SMP=y
++CONFIG_SYS_SUPPORTS_SMP=y
++CONFIG_NR_CPUS=2
+ # CONFIG_HZ_48 is not set
+ CONFIG_HZ_100=y
+ # CONFIG_HZ_128 is not set
+@@ -171,13 +172,16 @@ CONFIG_HZ=100
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_PREEMPT_BKL=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+@@ -187,15 +191,20 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
++# CONFIG_CPUSETS is not set
+ CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+ CONFIG_HOTPLUG=y
+@@ -203,12 +212,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -222,10 +231,12 @@ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODVERSIONS=y
+ CONFIG_MODULE_SRCVERSION_ALL=y
+ CONFIG_KMOD=y
++CONFIG_STOP_MACHINE=y
+
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+ # CONFIG_LSF is not set
+@@ -248,6 +259,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ #
+ CONFIG_HW_HAS_PCI=y
+ CONFIG_PCI=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ CONFIG_MMU=y
+
+ #
+@@ -281,6 +293,7 @@ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
+ CONFIG_NET_KEY=y
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -312,10 +325,12 @@ CONFIG_INET_XFRM_TUNNEL=m
+ CONFIG_INET_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+
+ #
+ # IP: Virtual Server Configuration
+@@ -357,11 +372,16 @@ CONFIG_IPV6_ROUTE_INFO=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
++# CONFIG_IPV6_MIP6 is not set
+ CONFIG_INET6_XFRM_TUNNEL=m
+ CONFIG_INET6_TUNNEL=m
+ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+ CONFIG_IPV6_TUNNEL=m
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
+ CONFIG_NETWORK_SECMARK=y
+ CONFIG_NETFILTER=y
+ # CONFIG_NETFILTER_DEBUG is not set
+@@ -376,6 +396,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
+ CONFIG_NETFILTER_XTABLES=m
+ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+ CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+ CONFIG_NETFILTER_XT_TARGET_MARK=m
+ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+ CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+@@ -386,6 +407,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+ CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+ CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+ CONFIG_NETFILTER_XT_MATCH_DCCP=m
++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+ CONFIG_NETFILTER_XT_MATCH_ESP=m
+ CONFIG_NETFILTER_XT_MATCH_HELPER=m
+ CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+@@ -428,7 +450,6 @@ CONFIG_IP_NF_MATCH_IPRANGE=m
+ CONFIG_IP_NF_MATCH_TOS=m
+ CONFIG_IP_NF_MATCH_RECENT=m
+ CONFIG_IP_NF_MATCH_ECN=m
+-CONFIG_IP_NF_MATCH_DSCP=m
+ CONFIG_IP_NF_MATCH_AH=m
+ CONFIG_IP_NF_MATCH_TTL=m
+ CONFIG_IP_NF_MATCH_OWNER=m
+@@ -456,7 +477,6 @@ CONFIG_IP_NF_NAT_SIP=m
+ CONFIG_IP_NF_MANGLE=m
+ CONFIG_IP_NF_TARGET_TOS=m
+ CONFIG_IP_NF_TARGET_ECN=m
+-CONFIG_IP_NF_TARGET_DSCP=m
+ CONFIG_IP_NF_TARGET_TTL=m
+ CONFIG_IP_NF_TARGET_CLUSTERIP=m
+ CONFIG_IP_NF_RAW=m
+@@ -535,13 +555,12 @@ CONFIG_LLC=m
+ # CONFIG_LLC2 is not set
+ # CONFIG_IPX is not set
+ CONFIG_ATALK=m
+-CONFIG_DEV_APPLETALK=y
++CONFIG_DEV_APPLETALK=m
+ CONFIG_IPDDP=m
+ CONFIG_IPDDP_ENCAP=y
+ CONFIG_IPDDP_DECAP=y
+ # CONFIG_X25 is not set
+ # CONFIG_LAPB is not set
+-CONFIG_NET_DIVERT=y
+ # CONFIG_ECONET is not set
+ # CONFIG_WAN_ROUTER is not set
+
+@@ -603,6 +622,7 @@ CONFIG_IEEE80211_CRYPT_CCMP=m
+ CONFIG_IEEE80211_SOFTMAC=m
+ # CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+ CONFIG_WIRELESS_EXT=y
++CONFIG_FIB_RULES=y
+
+ #
+ # Device Drivers
+@@ -651,6 +671,7 @@ CONFIG_BLK_DEV_NBD=m
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_BLK_DEV_INITRD is not set
+ CONFIG_CDROM_PKTCDVD=m
+ CONFIG_CDROM_PKTCDVD_BUFFERS=8
+@@ -661,6 +682,7 @@ CONFIG_ATA_OVER_ETH=m
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
+ CONFIG_BLK_DEV_IDE=y
+
+ #
+@@ -698,6 +720,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
+ # CONFIG_BLK_DEV_CS5530 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+ CONFIG_BLK_DEV_PIIX=y
+ # CONFIG_BLK_DEV_IT821X is not set
+@@ -720,6 +743,7 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ CONFIG_RAID_ATTRS=m
+ CONFIG_SCSI=m
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -741,12 +765,13 @@ CONFIG_SCSI_CONSTANTS=y
+ CONFIG_SCSI_LOGGING=y
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=m
+ CONFIG_SCSI_FC_ATTRS=m
+ CONFIG_SCSI_ISCSI_ATTRS=m
+ CONFIG_SCSI_SAS_ATTRS=m
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+@@ -764,21 +789,23 @@ CONFIG_AIC7XXX_DEBUG_MASK=0
+ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
+ # CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
+ # CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+@@ -786,6 +813,11 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ CONFIG_MD=y
+@@ -799,6 +831,7 @@ CONFIG_MD_RAID5_RESHAPE=y
+ CONFIG_MD_MULTIPATH=m
+ CONFIG_MD_FAULTY=m
+ CONFIG_BLK_DEV_DM=m
++# CONFIG_DM_DEBUG is not set
+ CONFIG_DM_CRYPT=m
+ CONFIG_DM_SNAPSHOT=m
+ CONFIG_DM_MIRROR=m
+@@ -853,6 +886,7 @@ CONFIG_LXT_PHY=m
+ CONFIG_CICADA_PHY=m
+ CONFIG_VITESSE_PHY=m
+ CONFIG_SMSC_PHY=m
++# CONFIG_FIXED_PHY is not set
+
+ #
+ # Ethernet (10 or 100Mbit)
+@@ -872,6 +906,7 @@ CONFIG_MII=y
+ # CONFIG_HP100 is not set
+ CONFIG_NET_PCI=y
+ CONFIG_PCNET32=y
++# CONFIG_PCNET32_NAPI is not set
+ # CONFIG_AMD8111_ETH is not set
+ # CONFIG_ADAPTEC_STARFIRE is not set
+ # CONFIG_B44 is not set
+@@ -908,6 +943,7 @@ CONFIG_PCNET32=y
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -955,6 +991,7 @@ CONFIG_PCNET32=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -1069,12 +1106,12 @@ CONFIG_RTC=y
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -1092,6 +1129,7 @@ CONFIG_VIDEO_V4L2=y
+ #
+ # CONFIG_VGA_CONSOLE is not set
+ CONFIG_DUMMY_CONSOLE=y
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -1190,6 +1228,7 @@ CONFIG_XFS_QUOTA=y
+ CONFIG_XFS_SECURITY=y
+ CONFIG_XFS_POSIX_ACL=y
+ # CONFIG_XFS_RT is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ CONFIG_MINIX_FS=m
+ CONFIG_ROMFS_FS=m
+@@ -1229,8 +1268,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -1278,7 +1319,6 @@ CONFIG_SUNRPC=y
+ # CONFIG_RPCSEC_GSS_SPKM3 is not set
+ # CONFIG_SMB_FS is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -1335,6 +1375,11 @@ CONFIG_NLS_KOI8_U=m
+ CONFIG_NLS_UTF8=m
+
+ #
++# Distributed Lock Manager
++#
++# CONFIG_DLM is not set
++
++#
+ # Profiling support
+ #
+ # CONFIG_PROFILING is not set
+@@ -1342,11 +1387,13 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
++CONFIG_LOG_BUF_SHIFT=15
+ # CONFIG_DEBUG_FS is not set
+ CONFIG_CROSSCOMPILE=y
+ CONFIG_CMDLINE=""
+@@ -1361,6 +1408,10 @@ CONFIG_CMDLINE=""
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ CONFIG_CRYPTO_NULL=m
+ CONFIG_CRYPTO_MD4=m
+@@ -1370,9 +1421,12 @@ CONFIG_CRYPTO_SHA256=m
+ CONFIG_CRYPTO_SHA512=m
+ CONFIG_CRYPTO_WP512=m
+ CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=m
+ CONFIG_CRYPTO_BLOWFISH=m
+ CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
+ CONFIG_CRYPTO_SERPENT=m
+ CONFIG_CRYPTO_AES=m
+ CONFIG_CRYPTO_CAST5=m
+diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig
+index c298979..a3cbd23 100644
+--- a/arch/mips/configs/mipssim_defconfig
++++ b/arch/mips/configs/mipssim_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -149,6 +148,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -800,6 +801,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
+index 938b38a..6570b47 100644
+--- a/arch/mips/configs/mpc30x_defconfig
++++ b/arch/mips/configs/mpc30x_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:15 2006
++# Linux kernel version: 2.6.18-rc2
++# Tue Jul 25 23:16:46 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -71,7 +70,6 @@ CONFIG_MACH_VR41XX=y
+ CONFIG_VICTOR_MPC30X=y
+ # CONFIG_ZAO_CAPCELLA is not set
+ CONFIG_PCI_VR41XX=y
+-CONFIG_VRC4173=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+ CONFIG_GENERIC_HWEIGHT=y
+@@ -150,6 +148,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -168,6 +168,7 @@ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
+ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+@@ -841,7 +842,7 @@ CONFIG_USB_PEGASUS=m
+ # CONFIG_USB_LEGOTOWER is not set
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
+-# CONFIG_USB_CY7C63 is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+ # CONFIG_USB_PHIDGETKIT is not set
+ # CONFIG_USB_PHIDGETSERVO is not set
+@@ -982,7 +983,6 @@ CONFIG_SUNRPC=y
+ # CONFIG_RPCSEC_GSS_SPKM3 is not set
+ # CONFIG_SMB_FS is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -1007,6 +1007,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -1014,7 +1015,7 @@ CONFIG_MSDOS_PARTITION=y
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_DEBUG_FS is not set
+ CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE="mem=32M console=ttyVR0,19200"
++CONFIG_CMDLINE="mem=32M console=ttyVR0,19200 ide0=0x170,0x376,73"
+
+ #
+ # Security options
+diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
+index ec5758f..440d65f 100644
+--- a/arch/mips/configs/ocelot_3_defconfig
++++ b/arch/mips/configs/ocelot_3_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -154,6 +153,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1092,6 +1093,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig
+index 0d33d87..c2c7ae7 100644
+--- a/arch/mips/configs/ocelot_c_defconfig
++++ b/arch/mips/configs/ocelot_c_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -151,6 +150,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -774,7 +775,7 @@ CONFIG_FUSE_FS=y
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -840,6 +841,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig
+index 4b99910..67efe27 100644
+--- a/arch/mips/configs/ocelot_defconfig
++++ b/arch/mips/configs/ocelot_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -155,6 +154,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -723,7 +724,7 @@ CONFIG_FUSE_FS=y
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -789,6 +790,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig
+index 827b344..a10f34d 100644
+--- a/arch/mips/configs/ocelot_g_defconfig
++++ b/arch/mips/configs/ocelot_g_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -154,6 +153,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -777,7 +778,7 @@ CONFIG_FUSE_FS=y
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -843,6 +844,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
+index 9ed60fe..9e672f6 100644
+--- a/arch/mips/configs/pb1100_defconfig
++++ b/arch/mips/configs/pb1100_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_PB1100=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -77,7 +76,6 @@ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+ CONFIG_SOC_AU1100=y
+ CONFIG_SOC_AU1X00=y
+ CONFIG_SWAP_IO_SPACE=y
+-# CONFIG_AU1X00_USB_DEVICE is not set
+ CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+ #
+@@ -150,6 +148,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1001,6 +1001,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
+index 6774254..d0c0f4a 100644
+--- a/arch/mips/configs/pb1500_defconfig
++++ b/arch/mips/configs/pb1500_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_PB1500=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -76,7 +75,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y
+ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+ CONFIG_SOC_AU1500=y
+ CONFIG_SOC_AU1X00=y
+-# CONFIG_AU1X00_USB_DEVICE is not set
+ CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+ #
+@@ -149,6 +147,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1107,6 +1107,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
+index 1afe5bf..3db7427 100644
+--- a/arch/mips/configs/pb1550_defconfig
++++ b/arch/mips/configs/pb1550_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS_PB1550=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -149,6 +148,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1099,6 +1100,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig
+index ac616c8..280a800 100644
+--- a/arch/mips/configs/pnx8550-jbs_defconfig
++++ b/arch/mips/configs/pnx8550-jbs_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:18 2006
++# Linux kernel version: 2.6.19-rc2
++# Sat Oct 14 23:01:16 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,9 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+ # CONFIG_LASAT is not set
+ # CONFIG_MIPS_ATLAS is not set
+@@ -42,13 +39,13 @@ CONFIG_MIPS=y
+ # CONFIG_MOMENCO_OCELOT_G is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_PNX8550_V2PCI is not set
+-# CONFIG_PNX8550_JBS is not set
++CONFIG_PNX8550_JBS=y
+ # CONFIG_DDB5477 is not set
+ # CONFIG_MACH_VR41XX is not set
+ # CONFIG_PMC_YOSEMITE is not set
+ # CONFIG_QEMU is not set
+ # CONFIG_MARKEINS is not set
+-CONFIG_SGI_IP22=y
++# CONFIG_SGI_IP22 is not set
+ # CONFIG_SGI_IP27 is not set
+ # CONFIG_SGI_IP32 is not set
+ # CONFIG_SIBYTE_BIGSUR is not set
+@@ -68,25 +65,21 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
+ CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+-CONFIG_ARC=y
+ CONFIG_DMA_NONCOHERENT=y
+ CONFIG_DMA_NEED_PCI_MAP_STATE=y
+-CONFIG_CPU_BIG_ENDIAN=y
+-# CONFIG_CPU_LITTLE_ENDIAN is not set
+-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+-CONFIG_IRQ_CPU=y
+-CONFIG_SWAP_IO_SPACE=y
+-CONFIG_ARC32=y
+-CONFIG_BOOT_ELF32=y
++# CONFIG_CPU_BIG_ENDIAN is not set
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
++CONFIG_PNX8550=y
++CONFIG_SOC_PNX8550=y
+ CONFIG_MIPS_L1_CACHE_SHIFT=5
+-# CONFIG_ARC_CONSOLE is not set
+-CONFIG_ARC_PROMLIB=y
+
+ #
+ # CPU selection
+ #
+-# CONFIG_CPU_MIPS32_R1 is not set
++CONFIG_CPU_MIPS32_R1=y
+ # CONFIG_CPU_MIPS32_R2 is not set
+ # CONFIG_CPU_MIPS64_R1 is not set
+ # CONFIG_CPU_MIPS64_R2 is not set
+@@ -94,7 +87,7 @@ CONFIG_ARC_PROMLIB=y
+ # CONFIG_CPU_TX39XX is not set
+ # CONFIG_CPU_VR41XX is not set
+ # CONFIG_CPU_R4300 is not set
+-CONFIG_CPU_R4X00=y
++# CONFIG_CPU_R4X00 is not set
+ # CONFIG_CPU_TX49XX is not set
+ # CONFIG_CPU_R5000 is not set
+ # CONFIG_CPU_R5432 is not set
+@@ -105,12 +98,11 @@ CONFIG_CPU_R4X00=y
+ # CONFIG_CPU_RM7000 is not set
+ # CONFIG_CPU_RM9000 is not set
+ # CONFIG_CPU_SB1 is not set
+-CONFIG_SYS_HAS_CPU_R4X00=y
+-CONFIG_SYS_HAS_CPU_R5000=y
++CONFIG_SYS_HAS_CPU_MIPS32_R1=y
++CONFIG_CPU_MIPS32=y
++CONFIG_CPU_MIPSR1=y
+ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+ CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+ #
+ # Kernel type
+@@ -121,17 +113,17 @@ CONFIG_PAGE_SIZE_4KB=y
+ # CONFIG_PAGE_SIZE_8KB is not set
+ # CONFIG_PAGE_SIZE_16KB is not set
+ # CONFIG_PAGE_SIZE_64KB is not set
+-CONFIG_BOARD_SCACHE=y
+-CONFIG_IP22_CPU_SCACHE=y
++CONFIG_CPU_HAS_PREFETCH=y
+ CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_MT_SMP is not set
++# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_VPE_LOADER is not set
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ CONFIG_CPU_HAS_LLSC=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_CPU_SUPPORTS_HIGHMEM=y
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+ CONFIG_FLATMEM_MANUAL=y
+@@ -145,15 +137,17 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
+ # CONFIG_HZ_48 is not set
+ # CONFIG_HZ_100 is not set
+ # CONFIG_HZ_128 is not set
+-# CONFIG_HZ_250 is not set
++CONFIG_HZ_250=y
+ # CONFIG_HZ_256 is not set
+-CONFIG_HZ_1000=y
++# CONFIG_HZ_1000 is not set
+ # CONFIG_HZ_1024 is not set
+ CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+-CONFIG_HZ=1000
++CONFIG_HZ=250
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -170,16 +164,20 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -188,12 +186,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -210,6 +208,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+ # CONFIG_LSF is not set
+@@ -230,8 +229,10 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ #
+ # Bus options (PCI, PCMCIA, EISA, ISA, TC)
+ #
+-CONFIG_HW_HAS_EISA=y
+-# CONFIG_EISA is not set
++CONFIG_HW_HAS_PCI=y
++CONFIG_PCI=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
++# CONFIG_PCI_DEBUG is not set
+ CONFIG_MMU=y
+
+ #
+@@ -242,6 +243,7 @@ CONFIG_MMU=y
+ #
+ # PCI Hotplug Support
+ #
++# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -264,6 +266,7 @@ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ # CONFIG_IP_MULTICAST is not set
+@@ -282,16 +285,18 @@ CONFIG_IP_PNP_BOOTP=y
+ # CONFIG_INET_IPCOMP is not set
+ # CONFIG_INET_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
+-CONFIG_INET_XFRM_MODE_TRANSPORT=m
+-CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_IPV6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+-CONFIG_NETWORK_SECMARK=y
++# CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+ #
+@@ -317,7 +322,6 @@ CONFIG_NETWORK_SECMARK=y
+ # 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
+
+@@ -370,13 +374,20 @@ CONFIG_FW_LOADER=y
+ #
+ # Block devices
+ #
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
+ # CONFIG_BLK_DEV_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_SX8 is not set
++# CONFIG_BLK_DEV_UB is not set
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+@@ -385,6 +396,7 @@ CONFIG_BLK_DEV_INITRD=y
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
+ CONFIG_BLK_DEV_IDE=y
+
+ #
+@@ -403,8 +415,39 @@ CONFIG_BLK_DEV_IDESCSI=y
+ # IDE chipset support/bugfixes
+ #
+ CONFIG_IDE_GENERIC=y
++CONFIG_BLK_DEV_IDEPCI=y
++CONFIG_IDEPCI_SHARE_IRQ=y
++CONFIG_BLK_DEV_OFFBOARD=y
++CONFIG_BLK_DEV_GENERIC=y
++# CONFIG_BLK_DEV_OPTI621 is not set
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
++# CONFIG_IDEDMA_PCI_AUTO is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++# CONFIG_BLK_DEV_CMD64X is not set
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5520 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++CONFIG_BLK_DEV_HPT366=y
++# CONFIG_BLK_DEV_JMICRON 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
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
+ # CONFIG_IDE_ARM is not set
+-# CONFIG_BLK_DEV_IDEDMA is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_IVB is not set
+ # CONFIG_IDEDMA_AUTO is not set
+ # CONFIG_BLK_DEV_HD is not set
+
+@@ -413,6 +456,7 @@ CONFIG_IDE_GENERIC=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -433,22 +477,54 @@ CONFIG_SCSI_CONSTANTS=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ CONFIG_SCSI_FC_ATTRS=y
+ CONFIG_SCSI_ISCSI_ATTRS=m
+ # CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+ #
+ CONFIG_ISCSI_TCP=m
+-# CONFIG_SGIWD93_SCSI is not set
+-# CONFIG_SCSI_SATA is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ # CONFIG_MD is not set
+@@ -457,14 +533,19 @@ CONFIG_ISCSI_TCP=m
+ # Fusion MPT device support
+ #
+ # CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+ #
++# CONFIG_IEEE1394 is not set
+
+ #
+ # I2O device support
+ #
++# CONFIG_I2O is not set
+
+ #
+ # Network device support
+@@ -476,6 +557,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_TUN is not set
+
+ #
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++
++#
+ # PHY device support
+ #
+ # CONFIG_PHYLIB is not set
+@@ -485,20 +571,73 @@ CONFIG_NETDEVICES=y
+ #
+ CONFIG_NET_ETHERNET=y
+ CONFIG_MII=y
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_DM9000 is not set
+-# CONFIG_SGISEEQ 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 is not set
++# CONFIG_8139CP is not set
++CONFIG_8139TOO=y
++# CONFIG_8139TOO_PIO is not set
++CONFIG_8139TOO_TUNE_TWISTER=y
++CONFIG_8139TOO_8129=y
++# CONFIG_8139_OLD_RX_RESET 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
++# CONFIG_LAN_SAA9730 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_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+ #
++# CONFIG_TR is not set
+
+ #
+ # Wireless LAN (non-hamradio)
+@@ -509,8 +648,11 @@ CONFIG_MII=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_NET_FC is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
+ # CONFIG_NETPOLL is not set
+@@ -530,6 +672,7 @@ CONFIG_MII=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -555,6 +698,7 @@ CONFIG_INPUT=y
+ CONFIG_SERIO=y
+ # CONFIG_SERIO_I8042 is not set
+ # CONFIG_SERIO_SERPORT is not set
++# CONFIG_SERIO_PCIPS2 is not set
+ CONFIG_SERIO_LIBPS2=y
+ # CONFIG_SERIO_RAW is not set
+ # CONFIG_GAMEPORT is not set
+@@ -565,7 +709,7 @@ CONFIG_SERIO_LIBPS2=y
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
+-CONFIG_VT_HW_CONSOLE_BINDING=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -576,7 +720,8 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
+ #
+ # Non-8250 serial port support
+ #
+-# CONFIG_SERIAL_IP22_ZILOG is not set
++# CONFIG_SERIAL_IP3106 is not set
++# CONFIG_SERIAL_JSM is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+@@ -590,16 +735,17 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_HW_RANDOM is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_RTC is not set
+-# CONFIG_SGI_DS1286 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
+
+ #
+@@ -630,35 +776,37 @@ CONFIG_HWMON=y
+ # CONFIG_HWMON_VID is not set
+ # CONFIG_SENSORS_ABITUGURU is not set
+ # CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+ #
+ # CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
+
+ #
+ # Graphics support
+ #
+-# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
+
+ #
+ # Console display driver support
+ #
+ # CONFIG_VGA_CONSOLE is not set
+-# CONFIG_SGI_NEWPORT_CONSOLE is not set
+ CONFIG_DUMMY_CONSOLE=y
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -668,15 +816,131 @@ CONFIG_DUMMY_CONSOLE=y
+ #
+ # USB support
+ #
+-# CONFIG_USB_ARCH_HAS_HCD is not set
+-# CONFIG_USB_ARCH_HAS_OHCI is not set
+-# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_EHCI_HCD 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 is not set
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
+
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
++# may also be needed; see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++CONFIG_USB_STORAGE_DATAFAB=y
++CONFIG_USB_STORAGE_FREECOM=y
++CONFIG_USB_STORAGE_ISD200=y
++CONFIG_USB_STORAGE_DPCM=y
++CONFIG_USB_STORAGE_USBAT=y
++CONFIG_USB_STORAGE_SDDR09=y
++CONFIG_USB_STORAGE_SDDR55=y
++CONFIG_USB_STORAGE_JUMPSHOT=y
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Input Devices
++#
++# CONFIG_USB_HID is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++
++#
++# USB DSL modem support
++#
++
++#
+ # USB Gadget Support
+ #
+ # CONFIG_USB_GADGET is not set
+@@ -702,6 +966,7 @@ CONFIG_DUMMY_CONSOLE=y
+ #
+ # InfiniBand support
+ #
++# CONFIG_INFINIBAND is not set
+
+ #
+ # EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+@@ -732,10 +997,12 @@ 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_EXT4DEV_FS is not set
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+ # CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -768,8 +1035,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ # CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -812,7 +1081,6 @@ CONFIG_SUNRPC=y
+ # CONFIG_RPCSEC_GSS_SPKM3 is not set
+ # CONFIG_SMB_FS is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -823,7 +1091,6 @@ CONFIG_SUNRPC=y
+ #
+ # CONFIG_PARTITION_ADVANCED is not set
+ CONFIG_MSDOS_PARTITION=y
+-CONFIG_SGI_PARTITION=y
+
+ #
+ # Native Language Support
+@@ -877,7 +1144,9 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+@@ -891,13 +1160,17 @@ CONFIG_DEBUG_SLAB=y
+ # CONFIG_DEBUG_SPINLOCK is not set
+ CONFIG_DEBUG_MUTEXES=y
+ # CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+ # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ CONFIG_FORCED_INLINING=y
++# CONFIG_HEADERS_CHECK is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_CROSSCOMPILE=y
+ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
+@@ -916,6 +1189,9 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kg
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
+ # CONFIG_CRYPTO_HMAC is not set
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -925,6 +1201,8 @@ CONFIG_CRYPTO_MD5=m
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ # CONFIG_CRYPTO_DES is not set
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig
+index a8eb51b..64b9fbf 100644
+--- a/arch/mips/configs/pnx8550-v2pci_defconfig
++++ b/arch/mips/configs/pnx8550-v2pci_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:18 2006
++# Linux kernel version: 2.6.19-rc2
++# Sat Oct 14 23:12:15 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,9 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+ # CONFIG_LASAT is not set
+ # CONFIG_MIPS_ATLAS is not set
+@@ -41,14 +38,14 @@ CONFIG_MIPS=y
+ # CONFIG_MOMENCO_OCELOT_C is not set
+ # CONFIG_MOMENCO_OCELOT_G is not set
+ # CONFIG_MIPS_XXS1500 is not set
+-# CONFIG_PNX8550_V2PCI is not set
++CONFIG_PNX8550_V2PCI=y
+ # CONFIG_PNX8550_JBS is not set
+ # CONFIG_DDB5477 is not set
+ # CONFIG_MACH_VR41XX is not set
+ # CONFIG_PMC_YOSEMITE is not set
+ # CONFIG_QEMU is not set
+ # CONFIG_MARKEINS is not set
+-CONFIG_SGI_IP22=y
++# CONFIG_SGI_IP22 is not set
+ # CONFIG_SGI_IP27 is not set
+ # CONFIG_SGI_IP32 is not set
+ # CONFIG_SIBYTE_BIGSUR is not set
+@@ -68,25 +65,21 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
+ CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+-CONFIG_ARC=y
+ CONFIG_DMA_NONCOHERENT=y
+ CONFIG_DMA_NEED_PCI_MAP_STATE=y
+-CONFIG_CPU_BIG_ENDIAN=y
+-# CONFIG_CPU_LITTLE_ENDIAN is not set
+-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+-CONFIG_IRQ_CPU=y
+-CONFIG_SWAP_IO_SPACE=y
+-CONFIG_ARC32=y
+-CONFIG_BOOT_ELF32=y
++# CONFIG_CPU_BIG_ENDIAN is not set
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
++CONFIG_PNX8550=y
++CONFIG_SOC_PNX8550=y
+ CONFIG_MIPS_L1_CACHE_SHIFT=5
+-# CONFIG_ARC_CONSOLE is not set
+-CONFIG_ARC_PROMLIB=y
+
+ #
+ # CPU selection
+ #
+-# CONFIG_CPU_MIPS32_R1 is not set
++CONFIG_CPU_MIPS32_R1=y
+ # CONFIG_CPU_MIPS32_R2 is not set
+ # CONFIG_CPU_MIPS64_R1 is not set
+ # CONFIG_CPU_MIPS64_R2 is not set
+@@ -94,7 +87,7 @@ CONFIG_ARC_PROMLIB=y
+ # CONFIG_CPU_TX39XX is not set
+ # CONFIG_CPU_VR41XX is not set
+ # CONFIG_CPU_R4300 is not set
+-CONFIG_CPU_R4X00=y
++# CONFIG_CPU_R4X00 is not set
+ # CONFIG_CPU_TX49XX is not set
+ # CONFIG_CPU_R5000 is not set
+ # CONFIG_CPU_R5432 is not set
+@@ -105,12 +98,11 @@ CONFIG_CPU_R4X00=y
+ # CONFIG_CPU_RM7000 is not set
+ # CONFIG_CPU_RM9000 is not set
+ # CONFIG_CPU_SB1 is not set
+-CONFIG_SYS_HAS_CPU_R4X00=y
+-CONFIG_SYS_HAS_CPU_R5000=y
++CONFIG_SYS_HAS_CPU_MIPS32_R1=y
++CONFIG_CPU_MIPS32=y
++CONFIG_CPU_MIPSR1=y
+ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+ CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+ #
+ # Kernel type
+@@ -121,17 +113,17 @@ CONFIG_PAGE_SIZE_4KB=y
+ # CONFIG_PAGE_SIZE_8KB is not set
+ # CONFIG_PAGE_SIZE_16KB is not set
+ # CONFIG_PAGE_SIZE_64KB is not set
+-CONFIG_BOARD_SCACHE=y
+-CONFIG_IP22_CPU_SCACHE=y
++CONFIG_CPU_HAS_PREFETCH=y
+ CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_MT_SMP is not set
++# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_VPE_LOADER is not set
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ CONFIG_CPU_HAS_LLSC=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_CPU_SUPPORTS_HIGHMEM=y
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+ CONFIG_FLATMEM_MANUAL=y
+@@ -145,15 +137,17 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
+ # CONFIG_HZ_48 is not set
+ # CONFIG_HZ_100 is not set
+ # CONFIG_HZ_128 is not set
+-# CONFIG_HZ_250 is not set
++CONFIG_HZ_250=y
+ # CONFIG_HZ_256 is not set
+-CONFIG_HZ_1000=y
++# CONFIG_HZ_1000 is not set
+ # CONFIG_HZ_1024 is not set
+ CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+-CONFIG_HZ=1000
++CONFIG_HZ=250
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -170,16 +164,20 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+ CONFIG_HOTPLUG=y
+@@ -187,12 +185,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -209,6 +207,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+ # CONFIG_LSF is not set
+@@ -229,8 +228,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ #
+ # Bus options (PCI, PCMCIA, EISA, ISA, TC)
+ #
+-CONFIG_HW_HAS_EISA=y
+-# CONFIG_EISA is not set
++CONFIG_HW_HAS_PCI=y
++CONFIG_PCI=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ CONFIG_MMU=y
+
+ #
+@@ -241,6 +241,7 @@ CONFIG_MMU=y
+ #
+ # PCI Hotplug Support
+ #
++# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -263,6 +264,7 @@ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ # CONFIG_IP_MULTICAST is not set
+@@ -281,12 +283,14 @@ CONFIG_IP_PNP=y
+ # CONFIG_INET_IPCOMP is not set
+ # CONFIG_INET_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
+-CONFIG_INET_XFRM_MODE_TRANSPORT=m
+-CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+
+ #
+ # IP: Virtual Server Configuration
+@@ -299,12 +303,18 @@ CONFIG_IPV6_ROUTE_INFO=y
+ # CONFIG_INET6_AH is not set
+ # CONFIG_INET6_ESP is not set
+ # CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=m
+ # CONFIG_IPV6_TUNNEL is not set
+-CONFIG_NETWORK_SECMARK=y
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_NETWORK_SECMARK is not set
+ CONFIG_NETFILTER=y
+ # CONFIG_NETFILTER_DEBUG is not set
+
+@@ -317,9 +327,9 @@ CONFIG_NETFILTER_XTABLES=m
+ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+ CONFIG_NETFILTER_XT_TARGET_MARK=m
+ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+-CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+ CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+ CONFIG_NETFILTER_XT_MATCH_DCCP=m
++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+ CONFIG_NETFILTER_XT_MATCH_ESP=m
+ CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+ CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+@@ -328,10 +338,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=m
+ # CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+ CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+ CONFIG_NETFILTER_XT_MATCH_REALM=m
+ CONFIG_NETFILTER_XT_MATCH_SCTP=m
+-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+ CONFIG_NETFILTER_XT_MATCH_STRING=m
+ CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+@@ -372,7 +382,6 @@ CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+ # 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
+
+@@ -425,13 +434,20 @@ CONFIG_FW_LOADER=y
+ #
+ # Block devices
+ #
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
+ # CONFIG_BLK_DEV_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_SX8 is not set
++# CONFIG_BLK_DEV_UB is not set
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+@@ -440,6 +456,7 @@ CONFIG_BLK_DEV_INITRD=y
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
+ CONFIG_BLK_DEV_IDE=y
+
+ #
+@@ -458,9 +475,41 @@ CONFIG_IDEDISK_MULTI_MODE=y
+ # IDE chipset support/bugfixes
+ #
+ CONFIG_IDE_GENERIC=y
++CONFIG_BLK_DEV_IDEPCI=y
++CONFIG_IDEPCI_SHARE_IRQ=y
++# CONFIG_BLK_DEV_OFFBOARD is not set
++# CONFIG_BLK_DEV_GENERIC is not set
++# CONFIG_BLK_DEV_OPTI621 is not set
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
++CONFIG_IDEDMA_PCI_AUTO=y
++# CONFIG_IDEDMA_ONLYDISK is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++CONFIG_BLK_DEV_CMD64X=y
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5520 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON 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
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
+ # CONFIG_IDE_ARM is not set
+-# CONFIG_BLK_DEV_IDEDMA is not set
+-# CONFIG_IDEDMA_AUTO is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_IVB is not set
++CONFIG_IDEDMA_AUTO=y
+ # CONFIG_BLK_DEV_HD is not set
+
+ #
+@@ -468,6 +517,7 @@ CONFIG_IDE_GENERIC=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -488,22 +538,59 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=m
+ CONFIG_SCSI_FC_ATTRS=y
+ CONFIG_SCSI_ISCSI_ATTRS=m
+ # CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+ #
+ CONFIG_ISCSI_TCP=m
+-# CONFIG_SGIWD93_SCSI is not set
+-# CONFIG_SCSI_SATA is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++CONFIG_SCSI_AIC7XXX=m
++CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
++CONFIG_AIC7XXX_RESET_DELAY_MS=15000
++# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
++CONFIG_AIC7XXX_DEBUG_MASK=0
++# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ # CONFIG_MD is not set
+@@ -512,14 +599,19 @@ CONFIG_ISCSI_TCP=m
+ # Fusion MPT device support
+ #
+ # CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+ #
++# CONFIG_IEEE1394 is not set
+
+ #
+ # I2O device support
+ #
++# CONFIG_I2O is not set
+
+ #
+ # Network device support
+@@ -531,6 +623,11 @@ CONFIG_NETDEVICES=y
+ CONFIG_TUN=m
+
+ #
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++
++#
+ # PHY device support
+ #
+ # CONFIG_PHYLIB is not set
+@@ -540,20 +637,73 @@ CONFIG_TUN=m
+ #
+ CONFIG_NET_ETHERNET=y
+ CONFIG_MII=y
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_DM9000 is not set
+-# CONFIG_SGISEEQ 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=y
++# CONFIG_NE2K_PCI is not set
++# CONFIG_8139CP is not set
++CONFIG_8139TOO=y
++# CONFIG_8139TOO_PIO is not set
++# CONFIG_8139TOO_TUNE_TWISTER is not set
++# CONFIG_8139TOO_8129 is not set
++# CONFIG_8139_OLD_RX_RESET is not set
++# CONFIG_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
++# CONFIG_LAN_SAA9730 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_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+ #
++# CONFIG_TR is not set
+
+ #
+ # Wireless LAN (non-hamradio)
+@@ -564,6 +714,8 @@ CONFIG_MII=y
+ # Wan interfaces
+ #
+ # CONFIG_WAN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
+ CONFIG_PPP=m
+ # CONFIG_PPP_MULTILINK is not set
+ # CONFIG_PPP_FILTER is not set
+@@ -574,6 +726,8 @@ CONFIG_PPP_DEFLATE=m
+ CONFIG_PPP_MPPE=m
+ # CONFIG_PPPOE is not set
+ # CONFIG_SLIP is not set
++CONFIG_SLHC=m
++# CONFIG_NET_FC is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
+ # CONFIG_NETPOLL is not set
+@@ -593,6 +747,7 @@ CONFIG_PPP_MPPE=m
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -615,6 +770,7 @@ CONFIG_KEYBOARD_ATKBD=y
+ # CONFIG_KEYBOARD_LKKBD is not set
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ # CONFIG_MOUSE_SERIAL is not set
+@@ -629,6 +785,7 @@ CONFIG_MOUSE_PS2=y
+ CONFIG_SERIO=y
+ CONFIG_SERIO_I8042=y
+ CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_PCIPS2 is not set
+ CONFIG_SERIO_LIBPS2=y
+ # CONFIG_SERIO_RAW is not set
+ # CONFIG_GAMEPORT is not set
+@@ -639,7 +796,7 @@ CONFIG_SERIO_LIBPS2=y
+ CONFIG_VT=y
+ # CONFIG_VT_CONSOLE is not set
+ CONFIG_HW_CONSOLE=y
+-CONFIG_VT_HW_CONSOLE_BINDING=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ CONFIG_SERIAL_NONSTANDARD=y
+ # CONFIG_COMPUTONE is not set
+ # CONFIG_ROCKETPORT is not set
+@@ -649,6 +806,7 @@ CONFIG_SERIAL_NONSTANDARD=y
+ # CONFIG_MOXA_SMARTIO is not set
+ # CONFIG_ISI is not set
+ # CONFIG_SYNCLINKMP is not set
++# CONFIG_SYNCLINK_GT is not set
+ # CONFIG_N_HDLC is not set
+ # CONFIG_RISCOM8 is not set
+ # CONFIG_SPECIALIX is not set
+@@ -664,7 +822,8 @@ CONFIG_SERIAL_NONSTANDARD=y
+ #
+ # Non-8250 serial port support
+ #
+-# CONFIG_SERIAL_IP22_ZILOG is not set
++# CONFIG_SERIAL_IP3106 is not set
++# CONFIG_SERIAL_JSM is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+@@ -678,16 +837,17 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_HW_RANDOM is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_RTC is not set
+-# CONFIG_SGI_DS1286 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
+
+ #
+@@ -708,14 +868,30 @@ CONFIG_I2C_CHARDEV=m
+ CONFIG_I2C_ALGOBIT=m
+ # CONFIG_I2C_ALGOPCF is not set
+ # CONFIG_I2C_ALGOPCA is not set
+-# CONFIG_I2C_ALGO_SGI is not set
+
+ #
+ # I2C Hardware Bus support
+ #
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_I810 is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
+ # CONFIG_I2C_OCORES is not set
+ # CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_PROSAVAGE is not set
++# CONFIG_I2C_SAVAGE4 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
+ # CONFIG_I2C_PCA_ISA is not set
+
+ #
+@@ -775,9 +951,13 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_LM92 is not set
+ # CONFIG_SENSORS_MAX1619 is not set
+ # CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_SIS5595 is not set
+ # CONFIG_SENSORS_SMSC47M1 is not set
+ # CONFIG_SENSORS_SMSC47M192 is not set
+ # CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_VT8231 is not set
+ # CONFIG_SENSORS_W83781D is not set
+ # CONFIG_SENSORS_W83791D is not set
+ # CONFIG_SENSORS_W83792D is not set
+@@ -789,23 +969,25 @@ CONFIG_HWMON=y
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+ #
+ # CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
+
+ #
+ # Graphics support
+ #
+-# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FIRMWARE_EDID=y
+ CONFIG_FB=y
++# CONFIG_FB_DDC is not set
+ # CONFIG_FB_CFB_FILLRECT is not set
+ # CONFIG_FB_CFB_COPYAREA is not set
+ # CONFIG_FB_CFB_IMAGEBLIT is not set
+@@ -813,14 +995,32 @@ CONFIG_FB=y
+ # CONFIG_FB_BACKLIGHT is not set
+ # CONFIG_FB_MODE_HELPERS is not set
+ # CONFIG_FB_TILEBLITTING is not set
++# CONFIG_FB_CIRRUS is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
+ # CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_SAVAGE is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_KYRO is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_SMIVGX is not set
++# CONFIG_FB_TRIDENT is not set
+ # CONFIG_FB_VIRTUAL is not set
+
+ #
+ # Console display driver support
+ #
+ # CONFIG_VGA_CONSOLE is not set
+-# CONFIG_SGI_NEWPORT_CONSOLE is not set
+ CONFIG_DUMMY_CONSOLE=y
+ # CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+@@ -838,15 +1038,129 @@ CONFIG_DUMMY_CONSOLE=y
+ #
+ # USB support
+ #
+-# CONFIG_USB_ARCH_HAS_HCD is not set
+-# CONFIG_USB_ARCH_HAS_OHCI is not set
+-# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_EHCI_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_UHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
+
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
++# may also be needed; see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_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
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++CONFIG_USB_HIDINPUT=y
++# CONFIG_USB_HIDINPUT_POWERBOOK is not set
++# CONFIG_HID_FF is not set
++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_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TEST is not set
++
++#
++# USB DSL modem support
++#
++
++#
+ # USB Gadget Support
+ #
+ # CONFIG_USB_GADGET is not set
+@@ -872,6 +1186,7 @@ CONFIG_DUMMY_CONSOLE=y
+ #
+ # InfiniBand support
+ #
++# CONFIG_INFINIBAND is not set
+
+ #
+ # EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+@@ -905,6 +1220,7 @@ 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_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+@@ -916,6 +1232,7 @@ CONFIG_XFS_FS=m
+ # CONFIG_XFS_SECURITY is not set
+ # CONFIG_XFS_POSIX_ACL is not set
+ # CONFIG_XFS_RT is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -948,8 +1265,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ # CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -993,7 +1312,6 @@ CONFIG_SUNRPC=y
+ CONFIG_SMB_FS=m
+ # CONFIG_SMB_NLS_DEFAULT is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -1004,7 +1322,6 @@ CONFIG_SMB_FS=m
+ #
+ # CONFIG_PARTITION_ADVANCED is not set
+ CONFIG_MSDOS_PARTITION=y
+-CONFIG_SGI_PARTITION=y
+
+ #
+ # Native Language Support
+@@ -1058,12 +1375,15 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
+ CONFIG_CROSSCOMPILE=y
+ CONFIG_CMDLINE=""
+
+@@ -1077,6 +1397,9 @@ CONFIG_CMDLINE=""
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
+ # CONFIG_CRYPTO_HMAC is not set
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -1086,6 +1409,8 @@ CONFIG_CRYPTO_SHA1=m
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ # CONFIG_CRYPTO_DES is not set
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig
+index 6a63a11..9b0dab8 100644
+--- a/arch/mips/configs/qemu_defconfig
++++ b/arch/mips/configs/qemu_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -146,6 +145,8 @@ CONFIG_HZ=100
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -687,7 +688,7 @@ CONFIG_FUSE_FS=y
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+
+@@ -734,6 +735,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
+index 6779f44..dd02960 100644
+--- a/arch/mips/configs/rbhma4500_defconfig
++++ b/arch/mips/configs/rbhma4500_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -156,6 +155,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1336,6 +1337,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
+index b7826d3..d8a498d 100644
+--- a/arch/mips/configs/rm200_defconfig
++++ b/arch/mips/configs/rm200_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -159,6 +158,8 @@ CONFIG_HZ=1000
+ # CONFIG_PREEMPT_NONE is not set
+ CONFIG_PREEMPT_VOLUNTARY=y
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1442,7 +1443,7 @@ CONFIG_NTFS_FS=m
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -1585,6 +1586,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
+index 625c1c6..805a4fe 100644
+--- a/arch/mips/configs/sb1250-swarm_defconfig
++++ b/arch/mips/configs/sb1250-swarm_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -172,6 +171,8 @@ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
+ CONFIG_PREEMPT_BKL=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -874,6 +875,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig
+index 4401b60..6fcb656 100644
+--- a/arch/mips/configs/sead_defconfig
++++ b/arch/mips/configs/sead_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -152,6 +151,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -582,6 +583,7 @@ CONFIG_PARTITION_ADVANCED=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
+index 2ba4e25..dc312f1 100644
+--- a/arch/mips/configs/tb0226_defconfig
++++ b/arch/mips/configs/tb0226_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -152,6 +151,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1060,6 +1061,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig
+index fc8a407..85615d9 100644
+--- a/arch/mips/configs/tb0229_defconfig
++++ b/arch/mips/configs/tb0229_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -152,6 +151,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -969,6 +970,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
+index effcb63..f7e8194 100644
+--- a/arch/mips/configs/tb0287_defconfig
++++ b/arch/mips/configs/tb0287_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:21 2006
++# Linux kernel version: 2.6.19-rc2
++# Wed Oct 18 12:57:11 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,9 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+ # CONFIG_LASAT is not set
+ # CONFIG_MIPS_ATLAS is not set
+@@ -73,11 +70,11 @@ CONFIG_TANBAC_TB0287=y
+ # CONFIG_VICTOR_MPC30X is not set
+ # CONFIG_ZAO_CAPCELLA is not set
+ CONFIG_PCI_VR41XX=y
+-# CONFIG_VRC4173 is not set
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
+ CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+ CONFIG_DMA_NONCOHERENT=y
+ CONFIG_DMA_NEED_PCI_MAP_STATE=y
+@@ -124,8 +121,8 @@ CONFIG_PAGE_SIZE_4KB=y
+ # CONFIG_PAGE_SIZE_16KB is not set
+ # CONFIG_PAGE_SIZE_64KB is not set
+ CONFIG_MIPS_MT_DISABLED=y
+-# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_MT_SMP is not set
++# CONFIG_MIPS_MT_SMTC is not set
+ # CONFIG_MIPS_VPE_LOADER is not set
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+@@ -152,6 +149,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -168,15 +167,19 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+ # CONFIG_HOTPLUG is not set
+@@ -184,12 +187,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -207,6 +210,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+ # CONFIG_LSF is not set
+@@ -229,17 +233,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ #
+ CONFIG_HW_HAS_PCI=y
+ CONFIG_PCI=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ CONFIG_MMU=y
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+ #
+-# CONFIG_PCCARD is not set
+
+ #
+ # PCI Hotplug Support
+ #
+-# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -262,6 +265,7 @@ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -290,13 +294,10 @@ CONFIG_SYN_COOKIES=y
+ CONFIG_INET_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ CONFIG_TCP_CONG_ADVANCED=y
+-
+-#
+-# TCP congestion control
+-#
+ CONFIG_TCP_CONG_BIC=y
+ CONFIG_TCP_CONG_CUBIC=m
+ CONFIG_TCP_CONG_WESTWOOD=m
+@@ -307,7 +308,13 @@ CONFIG_TCP_CONG_HTCP=m
+ # CONFIG_TCP_CONG_SCALABLE is not set
+ # CONFIG_TCP_CONG_LP is not set
+ # CONFIG_TCP_CONG_VENO is not set
+-# CONFIG_TCP_CONG_COMPOUND is not set
++CONFIG_DEFAULT_BIC=y
++# CONFIG_DEFAULT_CUBIC is not set
++# CONFIG_DEFAULT_HTCP is not set
++# CONFIG_DEFAULT_VEGAS is not set
++# CONFIG_DEFAULT_WESTWOOD is not set
++# CONFIG_DEFAULT_RENO is not set
++CONFIG_DEFAULT_TCP_CONG="bic"
+ # CONFIG_IPV6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+@@ -337,7 +344,6 @@ CONFIG_NETWORK_SECMARK=y
+ # 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
+
+@@ -354,6 +360,7 @@ CONFIG_NETWORK_SECMARK=y
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_IEEE80211 is not set
++CONFIG_FIB_RULES=y
+
+ #
+ # Device Drivers
+@@ -364,7 +371,6 @@ CONFIG_NETWORK_SECMARK=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+ # CONFIG_SYS_HYPERVISOR is not set
+
+ #
+@@ -402,6 +408,7 @@ CONFIG_BLK_DEV_NBD=m
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_BLK_DEV_INITRD is not set
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+@@ -409,65 +416,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
+ #
+ # ATA/ATAPI/MFM/RLL support
+ #
+-CONFIG_IDE=y
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/ide.txt for help/info on IDE drives
+-#
+-# CONFIG_BLK_DEV_IDE_SATA is not set
+-CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
+-# CONFIG_BLK_DEV_IDECD is not set
+-# CONFIG_BLK_DEV_IDETAPE is not set
+-# CONFIG_BLK_DEV_IDEFLOPPY is not set
+-# CONFIG_BLK_DEV_IDESCSI is not set
+-# CONFIG_IDE_TASK_IOCTL is not set
+-
+-#
+-# IDE chipset support/bugfixes
+-#
+-CONFIG_IDE_GENERIC=y
+-CONFIG_BLK_DEV_IDEPCI=y
+-# CONFIG_IDEPCI_SHARE_IRQ is not set
+-# CONFIG_BLK_DEV_OFFBOARD is not set
+-# CONFIG_BLK_DEV_GENERIC is not set
+-# CONFIG_BLK_DEV_OPTI621 is not set
+-CONFIG_BLK_DEV_IDEDMA_PCI=y
+-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+-# CONFIG_IDEDMA_PCI_AUTO is not set
+-# CONFIG_BLK_DEV_AEC62XX is not set
+-# CONFIG_BLK_DEV_ALI15X3 is not set
+-# CONFIG_BLK_DEV_AMD74XX is not set
+-# CONFIG_BLK_DEV_CMD64X is not set
+-# CONFIG_BLK_DEV_TRIFLEX is not set
+-# CONFIG_BLK_DEV_CY82C693 is not set
+-# CONFIG_BLK_DEV_CS5520 is not set
+-# CONFIG_BLK_DEV_CS5530 is not set
+-# CONFIG_BLK_DEV_HPT34X is not set
+-# CONFIG_BLK_DEV_HPT366 is not set
+-# CONFIG_BLK_DEV_SC1200 is not set
+-# CONFIG_BLK_DEV_PIIX 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
+-# CONFIG_BLK_DEV_SVWKS is not set
+-CONFIG_BLK_DEV_SIIMAGE=y
+-# CONFIG_BLK_DEV_SLC90E66 is not set
+-# CONFIG_BLK_DEV_TRM290 is not set
+-# CONFIG_BLK_DEV_VIA82CXXX is not set
+-# CONFIG_IDE_ARM is not set
+-CONFIG_BLK_DEV_IDEDMA=y
+-# CONFIG_IDEDMA_IVB is not set
+-# CONFIG_IDEDMA_AUTO is not set
+-# CONFIG_BLK_DEV_HD is not set
++# CONFIG_IDE is not set
+
+ #
+ # SCSI device support
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++# CONFIG_SCSI_NETLINK is not set
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -488,12 +444,13 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ # CONFIG_SCSI_FC_ATTRS is not set
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+ # CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+@@ -506,21 +463,24 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
+ # CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+ # CONFIG_SCSI_IPR is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
+ # CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+@@ -528,6 +488,59 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++# CONFIG_SATA_SVW is not set
++# CONFIG_ATA_PIIX is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
++# CONFIG_PDC_ADMA is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++# CONFIG_SATA_SIL is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
++# CONFIG_PATA_ALI is not set
++# CONFIG_PATA_AMD is not set
++# CONFIG_PATA_ARTOP is not set
++# CONFIG_PATA_ATIIXP is not set
++# CONFIG_PATA_CMD64X is not set
++# CONFIG_PATA_CS5520 is not set
++# CONFIG_PATA_CS5530 is not set
++# CONFIG_PATA_CYPRESS is not set
++# CONFIG_PATA_EFAR is not set
++# CONFIG_ATA_GENERIC is not set
++# CONFIG_PATA_HPT366 is not set
++# CONFIG_PATA_HPT37X is not set
++# CONFIG_PATA_HPT3X2N is not set
++# CONFIG_PATA_HPT3X3 is not set
++# CONFIG_PATA_IT821X is not set
++# CONFIG_PATA_JMICRON is not set
++# CONFIG_PATA_TRIFLEX is not set
++# CONFIG_PATA_MPIIX is not set
++# CONFIG_PATA_OLDPIIX is not set
++# CONFIG_PATA_NETCELL is not set
++# CONFIG_PATA_NS87410 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_OPTIDMA is not set
++# CONFIG_PATA_PDC_OLD is not set
++# CONFIG_PATA_RADISYS is not set
++# CONFIG_PATA_RZ1000 is not set
++# CONFIG_PATA_SC1200 is not set
++# CONFIG_PATA_SERVERWORKS is not set
++# CONFIG_PATA_PDC2027X is not set
++CONFIG_PATA_SIL680=y
++# CONFIG_PATA_SIS is not set
++# CONFIG_PATA_VIA is not set
++# CONFIG_PATA_WINBOND is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ # CONFIG_MD is not set
+@@ -631,6 +644,7 @@ CONFIG_R8169=y
+ # CONFIG_SK98LIN is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -678,6 +692,7 @@ CONFIG_R8169=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -757,7 +772,6 @@ CONFIG_GPIO_VR41XX=y
+ # TPM devices
+ #
+ # CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+
+ #
+ # I2C support
+@@ -783,12 +797,12 @@ CONFIG_GPIO_VR41XX=y
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -896,13 +910,13 @@ CONFIG_USB_STORAGE=m
+ # CONFIG_USB_STORAGE_DEBUG is not set
+ # CONFIG_USB_STORAGE_DATAFAB is not set
+ # CONFIG_USB_STORAGE_FREECOM is not set
+-# CONFIG_USB_STORAGE_ISD200 is not set
+ # CONFIG_USB_STORAGE_DPCM is not set
+ # CONFIG_USB_STORAGE_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
+ # CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
+ # CONFIG_USB_LIBUSUAL is not set
+
+ #
+@@ -931,6 +945,7 @@ CONFIG_USB_HIDINPUT=y
+ # CONFIG_USB_ATI_REMOTE2 is not set
+ # CONFIG_USB_KEYSPAN_REMOTE is not set
+ # CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+
+ #
+ # USB Imaging devices
+@@ -962,16 +977,17 @@ CONFIG_USB_MON=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
+-# CONFIG_USB_CY7C63 is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
+ # CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_SISUSBVGA is not set
+ # CONFIG_USB_LD is not set
+@@ -1040,6 +1056,7 @@ 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_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+@@ -1051,6 +1068,7 @@ CONFIG_XFS_QUOTA=y
+ # CONFIG_XFS_SECURITY is not set
+ CONFIG_XFS_POSIX_ACL=y
+ # CONFIG_XFS_RT is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ CONFIG_ROMFS_FS=m
+@@ -1081,8 +1099,10 @@ CONFIG_AUTOFS4_FS=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -1122,7 +1142,6 @@ CONFIG_SUNRPC=y
+ # CONFIG_RPCSEC_GSS_SPKM3 is not set
+ # CONFIG_SMB_FS is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -1147,12 +1166,15 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
+ CONFIG_CROSSCOMPILE=y
+ CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
+
+@@ -1168,10 +1190,6 @@ CONFIG_CMDLINE="mem=64M console=ttyVR0,1
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
+index 4891d02..863f6a7 100644
+--- a/arch/mips/configs/workpad_defconfig
++++ b/arch/mips/configs/workpad_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 10:04:21 2006
++# Linux kernel version: 2.6.18-rc2
++# Tue Jul 25 23:13:04 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -148,6 +147,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -166,6 +167,7 @@ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
+ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+@@ -379,6 +381,7 @@ CONFIG_CONNECTOR=m
+ CONFIG_BLK_DEV_RAM=m
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_BLK_DEV_INITRD is not set
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+@@ -855,7 +858,6 @@ CONFIG_SUNRPC=y
+ # CONFIG_RPCSEC_GSS_SPKM3 is not set
+ # CONFIG_SMB_FS is not set
+ # CONFIG_CIFS is not set
+-# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -880,6 +882,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -887,7 +890,7 @@ CONFIG_MSDOS_PARTITION=y
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_DEBUG_FS is not set
+ CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE="console=ttyVR0,19200 mem=16M"
++CONFIG_CMDLINE="console=ttyVR0,19200 ide0=0x170,0x376,49 mem=16M"
+
+ #
+ # Security options
+diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig
+index 3e4b16b..c10267d 100644
+--- a/arch/mips/configs/wrppmc_defconfig
++++ b/arch/mips/configs/wrppmc_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -156,6 +155,8 @@ CONFIG_HZ=1000
+ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -830,6 +831,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
+index 3a68d8a..4d3c132 100644
+--- a/arch/mips/configs/yosemite_defconfig
++++ b/arch/mips/configs/yosemite_defconfig
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -153,6 +152,8 @@ CONFIG_PREEMPT_NONE=y
+ # CONFIG_PREEMPT_VOLUNTARY is not set
+ # CONFIG_PREEMPT is not set
+ CONFIG_PREEMPT_BKL=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -761,6 +762,7 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
+index 513fc67..a8bd2e6 100644
+--- a/arch/mips/ddb5xxx/ddb5477/irq.c
++++ b/arch/mips/ddb5xxx/ddb5477/irq.c
+@@ -153,8 +153,7 @@ u8 i8259_interrupt_ack(void)
+ * the first level int-handler will jump here if it is a vrc5477 irq
+ */
+ #define NUM_5477_IRQS 32
+-static void
+-vrc5477_irq_dispatch(struct pt_regs *regs)
++static void vrc5477_irq_dispatch(void)
+ {
+ u32 intStatus;
+ u32 bitmask;
+@@ -178,7 +177,7 @@ vrc5477_irq_dispatch(struct pt_regs *reg
+ /* check for i8259 interrupts */
+ if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
+ int i8259_irq = i8259_interrupt_ack();
+- do_IRQ(I8259_IRQ_BASE + i8259_irq, regs);
++ do_IRQ(I8259_IRQ_BASE + i8259_irq);
+ return;
+ }
+ }
+@@ -186,7 +185,7 @@ vrc5477_irq_dispatch(struct pt_regs *reg
+ for (i=0, bitmask=1; i<= NUM_5477_IRQS; bitmask <<=1, i++) {
+ /* do we need to "and" with the int mask? */
+ if (intStatus & bitmask) {
+- do_IRQ(VRC5477_IRQ_BASE + i, regs);
++ do_IRQ(VRC5477_IRQ_BASE + i);
+ return;
+ }
+ }
+@@ -194,18 +193,18 @@ vrc5477_irq_dispatch(struct pt_regs *reg
+
+ #define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6)
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP7)
+- do_IRQ(CPU_IRQ_BASE + 7, regs);
++ do_IRQ(CPU_IRQ_BASE + 7);
+ else if (pending & VR5477INTS)
+- vrc5477_irq_dispatch(regs);
++ vrc5477_irq_dispatch();
+ else if (pending & STATUSF_IP0)
+- do_IRQ(CPU_IRQ_BASE, regs);
++ do_IRQ(CPU_IRQ_BASE);
+ else if (pending & STATUSF_IP1)
+- do_IRQ(CPU_IRQ_BASE + 1, regs);
++ do_IRQ(CPU_IRQ_BASE + 1);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+diff --git a/arch/mips/dec/boot/Makefile b/arch/mips/dec/boot/Makefile
+deleted file mode 100644
+index bcea416..0000000
+--- a/arch/mips/dec/boot/Makefile
++++ /dev/null
+@@ -1,12 +0,0 @@
+-#
+-# Makefile for the DECstation family specific parts of the kernel
+-#
+-
+-netboot: all
+- $(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \
+- dec_boot.o ramdisk.img -o nbImage
+-
+-obj-y := decstation.o
+-
+-clean:
+- rm -f nbImage
+diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c
+deleted file mode 100644
+index 4db8bac..0000000
+--- a/arch/mips/dec/boot/decstation.c
++++ /dev/null
+@@ -1,84 +0,0 @@
+-/*
+- * arch/mips/dec/decstation.c
+- */
+-#include <asm/sections.h>
+-
+-#define RELOC
+-#define INITRD
+-#define DEBUG_BOOT
+-
+-/*
+- * Magic number indicating REX PROM available on DECSTATION.
+- */
+-#define REX_PROM_MAGIC 0x30464354
+-
+-#define REX_PROM_CLEARCACHE 0x7c/4
+-#define REX_PROM_PRINTF 0x30/4
+-
+-#define VEC_RESET 0xBFC00000 /* Prom base address */
+-#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */
+-#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17)
+-
+-#define PARAM (k_start + 0x2000)
+-
+-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
+-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
+-
+-extern int _ftext; /* begin and end of kernel image */
+-extern void kernel_entry(int, char **, unsigned long, int *);
+-
+-void * memcpy(void * dest, const void *src, unsigned int count)
+-{
+- unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src;
+-
+- count >>= 2;
+- while (count--)
+- *tmp++ = *s++;
+-
+- return dest;
+-}
+-
+-void dec_entry(int argc, char **argv,
+- unsigned long magic, int *prom_vec)
+-{
+- void (*rex_clear_cache)(void);
+- int (*prom_printf)(char *, ...);
+- unsigned long k_start, len;
+-
+- /*
+- * The DS5100 leaves cpu with BEV enabled, clear it.
+- */
+- asm( "lui\t$8,0x3000\n\t"
+- "mtc0\t$8,$12\n\t"
+- ".section\t.sdata\n\t"
+- ".section\t.sbss\n\t"
+- ".section\t.text"
+- : : : "$8");
+-
+-#ifdef DEBUG_BOOT
+- if (magic == REX_PROM_MAGIC) {
+- prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
+- } else {
+- prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
+- }
+- prom_printf("Launching kernel...\n");
+-#endif
+-
+- k_start = (unsigned long) (&kernel_entry) & 0xffff0000;
+-
+-#ifdef RELOC
+- /*
+- * Now copy kernel image to its destination.
+- */
+- len = ((unsigned long) (&_end) - k_start);
+- memcpy((void *)k_start, &_ftext, len);
+-#endif
+-
+- if (magic == REX_PROM_MAGIC) {
+- rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
+- rex_clear_cache();
+- }
+-
+- kernel_entry(argc, argv, magic, prom_vec);
+-}
+diff --git a/arch/mips/dec/boot/ld.ecoff b/arch/mips/dec/boot/ld.ecoff
+deleted file mode 100644
+index aaa633d..0000000
+--- a/arch/mips/dec/boot/ld.ecoff
++++ /dev/null
+@@ -1,43 +0,0 @@
+-OUTPUT_FORMAT("ecoff-littlemips")
+-OUTPUT_ARCH(mips)
+-ENTRY(dec_entry)
+-SECTIONS
+-{
+- . = 0x80200000;
+-
+- .text :
+- {
+- _ftext = .;
+- *(.text)
+- *(.fixup)
+- }
+- .rdata :
+- {
+- *(.rodata .rodata.* .rdata)
+- }
+- .data :
+- {
+- . = ALIGN(0x1000);
+- ramdisk.img (.data)
+- *(.data)
+- }
+- .sdata :
+- {
+- *(.sdata)
+- }
+- _gp = .;
+- .sbss :
+- {
+- *(.sbss)
+- *(.scommon)
+- }
+- .bss :
+- {
+- *(.dynbss)
+- *(.bss)
+- *(COMMON)
+- }
+- /DISCARD/ : {
+- *(.reginfo .mdebug .note)
+- }
+-}
+diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c
+index cc24c5e..3e374d0 100644
+--- a/arch/mips/dec/ecc-berr.c
++++ b/arch/mips/dec/ecc-berr.c
+@@ -24,6 +24,7 @@
+ #include <asm/addrspace.h>
+ #include <asm/bootinfo.h>
+ #include <asm/cpu.h>
++#include <asm/irq_regs.h>
+ #include <asm/processor.h>
+ #include <asm/system.h>
+ #include <asm/traps.h>
+@@ -200,8 +201,10 @@ int dec_ecc_be_handler(struct pt_regs *r
+ return dec_ecc_be_backend(regs, is_fixup, 0);
+ }
+
+-irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id)
+ {
++ struct pt_regs *regs = get_irq_regs();
++
+ int action = dec_ecc_be_backend(regs, 0, 1);
+
+ if (action == MIPS_BE_DISCARD)
+diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
+index 455a65b..31dd47d 100644
+--- a/arch/mips/dec/int-handler.S
++++ b/arch/mips/dec/int-handler.S
+@@ -264,10 +264,10 @@
+ srlv t3,t1,t2
+
+ handle_it:
+- jal do_IRQ
+- move a1,sp
+-
+- j ret_from_irq
++ LONG_L s0, TI_REGS($28)
++ LONG_S sp, TI_REGS($28)
++ PTR_LA ra, ret_from_irq
++ j do_IRQ
+ nop
+
+ #ifdef CONFIG_32BIT
+@@ -277,9 +277,8 @@ fpu:
+ #endif
+
+ spurious:
+- jal spurious_interrupt
+- nop
+- j ret_from_irq
++ PTR_LA ra, _ret_from_irq
++ j spurious_interrupt
+ nop
+ END(plat_irq_dispatch)
+
+diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c
+index b9271db..f19b461 100644
+--- a/arch/mips/dec/kn01-berr.c
++++ b/arch/mips/dec/kn01-berr.c
+@@ -150,10 +150,10 @@ int dec_kn01_be_handler(struct pt_regs *
+ return dec_kn01_be_backend(regs, is_fixup, 0);
+ }
+
+-irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id)
+ {
+ volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
++ struct pt_regs *regs = get_irq_regs();
+ int action;
+
+ if (!(*csr & KN01_CSR_MEMERR))
+diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c
+index 6cd3f94..7a053aa 100644
+--- a/arch/mips/dec/kn02xa-berr.c
++++ b/arch/mips/dec/kn02xa-berr.c
+@@ -21,6 +21,8 @@
+ #include <linux/types.h>
+
+ #include <asm/addrspace.h>
++#include <asm/irq_regs.h>
++#include <asm/ptrace.h>
+ #include <asm/system.h>
+ #include <asm/traps.h>
+
+@@ -104,9 +106,9 @@ int dec_kn02xa_be_handler(struct pt_regs
+ return dec_kn02xa_be_backend(regs, is_fixup, 0);
+ }
+
+-irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id)
+ {
++ struct pt_regs *regs = get_irq_regs();
+ int action = dec_kn02xa_be_backend(regs, 0, 1);
+
+ if (action == MIPS_BE_DISCARD)
+diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S
+index 0dd56db..e523454 100644
+--- a/arch/mips/dec/prom/call_o32.S
++++ b/arch/mips/dec/prom/call_o32.S
+@@ -1,5 +1,5 @@
+ /*
+- * arch/mips/dec/call_o32.S
++ * arch/mips/dec/prom/call_o32.S
+ *
+ * O32 interface for the 64 (or N32) ABI.
+ *
+diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c
+index f78c6da..5639722 100644
+--- a/arch/mips/dec/reset.c
++++ b/arch/mips/dec/reset.c
+@@ -8,7 +8,6 @@
+ #include <linux/linkage.h>
+
+ #include <asm/addrspace.h>
+-#include <asm/ptrace.h>
+
+ typedef void ATTRIB_NORET (* noret_func_t)(void);
+
+@@ -35,7 +34,7 @@ void ATTRIB_NORET dec_machine_power_off(
+ back_to_prom();
+ }
+
+-irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t dec_intr_halt(int irq, void *dev_id)
+ {
+ dec_machine_halt();
+ }
+diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
+index d43241c..6b7481e 100644
+--- a/arch/mips/dec/setup.c
++++ b/arch/mips/dec/setup.c
+@@ -46,7 +46,7 @@
+ extern void dec_machine_restart(char *command);
+ extern void dec_machine_halt(void);
+ extern void dec_machine_power_off(void);
+-extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t dec_intr_halt(int irq, void *dev_id);
+
+ unsigned long dec_kn_slot_base, dec_kn_slot_size;
+
+diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
+index 5729474..69e424e 100644
+--- a/arch/mips/dec/time.c
++++ b/arch/mips/dec/time.c
+@@ -160,11 +160,6 @@ static unsigned int dec_ioasic_hpt_read(
+ return ioasic_read(IO_REG_FCTR);
+ }
+
+-static void dec_ioasic_hpt_init(unsigned int count)
+-{
+- ioasic_write(IO_REG_FCTR, ioasic_read(IO_REG_FCTR) - count);
+-}
+-
+
+ void __init dec_time_init(void)
+ {
+@@ -174,18 +169,14 @@ void __init dec_time_init(void)
+ mips_timer_state = dec_timer_state;
+ mips_timer_ack = dec_timer_ack;
+
+- if (!cpu_has_counter && IOASIC) {
++ if (!cpu_has_counter && IOASIC)
+ /* For pre-R4k systems we use the I/O ASIC's counter. */
+ mips_hpt_read = dec_ioasic_hpt_read;
+- mips_hpt_init = dec_ioasic_hpt_init;
+- }
+
+ /* Set up the rate of periodic DS1287 interrupts. */
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A);
+ }
+
+-EXPORT_SYMBOL(do_settimeofday);
+-
+ void __init plat_timer_setup(struct irqaction *irq)
+ {
+ setup_irq(dec_interrupt[DEC_IRQ_RTC], irq);
+diff --git a/arch/mips/defconfig b/arch/mips/defconfig
+index fff6fcc..21d53e0 100644
+--- a/arch/mips/defconfig
++++ b/arch/mips/defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+ # Linux kernel version: 2.6.18-rc1
+-# Thu Jul 6 09:49:33 2006
++# Thu Jul 6 10:04:10 2006
+ #
+ CONFIG_MIPS=y
+
+@@ -25,7 +25,6 @@ CONFIG_MIPS=y
+ # CONFIG_MIPS_COBALT is not set
+ # CONFIG_MACH_DECSTATION is not set
+ # CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+ # CONFIG_MIPS_IVR is not set
+ # CONFIG_MIPS_ITE8172 is not set
+ # CONFIG_MACH_JAZZ is not set
+@@ -154,6 +153,8 @@ CONFIG_HZ=1000
+ # CONFIG_PREEMPT_NONE is not set
+ CONFIG_PREEMPT_VOLUNTARY=y
+ # CONFIG_PREEMPT is not set
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -1013,7 +1014,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+-# CONFIG_TMPFS is not set
++CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -1148,6 +1149,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # Kernel hacking
+ #
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+diff --git a/arch/mips/emma2rh/common/irq.c b/arch/mips/emma2rh/common/irq.c
+index 3af5769..c191b3e 100644
+--- a/arch/mips/emma2rh/common/irq.c
++++ b/arch/mips/emma2rh/common/irq.c
+@@ -39,7 +39,7 @@
+ /*
+ * the first level int-handler will jump here if it is a emma2rh irq
+ */
+-asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
++void emma2rh_irq_dispatch(void)
+ {
+ u32 intStatus;
+ u32 bitmask;
+@@ -56,7 +56,7 @@ asmlinkage void emma2rh_irq_dispatch(str
+ & emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN);
+ for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
+ if (swIntStatus & bitmask) {
+- do_IRQ(EMMA2RH_SW_IRQ_BASE + i, regs);
++ do_IRQ(EMMA2RH_SW_IRQ_BASE + i);
+ return;
+ }
+ }
+@@ -65,7 +65,7 @@ asmlinkage void emma2rh_irq_dispatch(str
+
+ for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
+ if (intStatus & bitmask) {
+- do_IRQ(EMMA2RH_IRQ_BASE + i, regs);
++ do_IRQ(EMMA2RH_IRQ_BASE + i);
+ return;
+ }
+ }
+@@ -81,7 +81,7 @@ asmlinkage void emma2rh_irq_dispatch(str
+ & emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
+ for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
+ if (gpioIntStatus & bitmask) {
+- do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i, regs);
++ do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i);
+ return;
+ }
+ }
+@@ -90,7 +90,7 @@ asmlinkage void emma2rh_irq_dispatch(str
+
+ for (i = 32, bitmask = 1; i < 64; i++, bitmask <<= 1) {
+ if (intStatus & bitmask) {
+- do_IRQ(EMMA2RH_IRQ_BASE + i, regs);
++ do_IRQ(EMMA2RH_IRQ_BASE + i);
+ return;
+ }
+ }
+@@ -100,7 +100,7 @@ asmlinkage void emma2rh_irq_dispatch(str
+
+ for (i = 64, bitmask = 1; i < 96; i++, bitmask <<= 1) {
+ if (intStatus & bitmask) {
+- do_IRQ(EMMA2RH_IRQ_BASE + i, regs);
++ do_IRQ(EMMA2RH_IRQ_BASE + i);
+ return;
+ }
+ }
+diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c
+index 7c93086..197ed4c 100644
+--- a/arch/mips/emma2rh/common/irq_emma2rh.c
++++ b/arch/mips/emma2rh/common/irq_emma2rh.c
+@@ -97,7 +97,7 @@ void emma2rh_irq_init(u32 irq_base)
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+- irq_desc[i].handler = &emma2rh_irq_controller;
++ irq_desc[i].chip = &emma2rh_irq_controller;
+ }
+
+ emma2rh_irq_base = irq_base;
+diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c
+index 2a736be..c93369c 100644
+--- a/arch/mips/emma2rh/markeins/irq.c
++++ b/arch/mips/emma2rh/markeins/irq.c
+@@ -57,7 +57,7 @@
+ extern void emma2rh_sw_irq_init(u32 base);
+ extern void emma2rh_gpio_irq_init(u32 base);
+ extern void emma2rh_irq_init(u32 base);
+-extern asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs);
++extern void emma2rh_irq_dispatch(void);
+
+ static struct irqaction irq_cascade = {
+ .handler = no_action,
+@@ -114,20 +114,20 @@ void __init arch_init_irq(void)
+ setup_irq(CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP7)
+- do_IRQ(CPU_IRQ_BASE + 7, regs);
++ do_IRQ(CPU_IRQ_BASE + 7);
+ else if (pending & STATUSF_IP2)
+- emma2rh_irq_dispatch(regs);
++ emma2rh_irq_dispatch();
+ else if (pending & STATUSF_IP1)
+- do_IRQ(CPU_IRQ_BASE + 1, regs);
++ do_IRQ(CPU_IRQ_BASE + 1);
+ else if (pending & STATUSF_IP0)
+- do_IRQ(CPU_IRQ_BASE + 0, regs);
++ do_IRQ(CPU_IRQ_BASE + 0);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+
+diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c
+index f23ae9f..0b36eb0 100644
+--- a/arch/mips/emma2rh/markeins/irq_markeins.c
++++ b/arch/mips/emma2rh/markeins/irq_markeins.c
+@@ -86,7 +86,7 @@ void emma2rh_sw_irq_init(u32 irq_base)
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 2;
+- irq_desc[i].handler = &emma2rh_sw_irq_controller;
++ irq_desc[i].chip = &emma2rh_sw_irq_controller;
+ }
+
+ emma2rh_sw_irq_base = irq_base;
+@@ -166,7 +166,7 @@ void emma2rh_gpio_irq_init(u32 irq_base)
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 2;
+- irq_desc[i].handler = &emma2rh_gpio_irq_controller;
++ irq_desc[i].chip = &emma2rh_gpio_irq_controller;
+ }
+
+ emma2rh_gpio_irq_base = irq_base;
+diff --git a/arch/mips/emma2rh/markeins/platform.c b/arch/mips/emma2rh/markeins/platform.c
+index 15cc61d..1156770 100644
+--- a/arch/mips/emma2rh/markeins/platform.c
++++ b/arch/mips/emma2rh/markeins/platform.c
+@@ -44,18 +44,45 @@
+ #define I2C_EMMA2RH "emma2rh-iic" /* must be in sync with IIC driver */
+
+ static struct resource i2c_emma_resources_0[] = {
+- { NULL, EMMA2RH_IRQ_PIIC0, EMMA2RH_IRQ_PIIC0, IORESOURCE_IRQ },
+- { NULL, KSEG1ADDR(EMMA2RH_PIIC0_BASE), KSEG1ADDR(EMMA2RH_PIIC0_BASE + 0x1000), 0 },
++ {
++ .name = NULL,
++ .start = EMMA2RH_IRQ_PIIC0,
++ .end = EMMA2RH_IRQ_PIIC0,
++ .flags = IORESOURCE_IRQ
++ }, {
++ .name = NULL,
++ .start = EMMA2RH_PIIC0_BASE,
++ .end = EMMA2RH_PIIC0_BASE + 0x1000,
++ .flags = 0
++ },
+ };
+
+ struct resource i2c_emma_resources_1[] = {
+- { NULL, EMMA2RH_IRQ_PIIC1, EMMA2RH_IRQ_PIIC1, IORESOURCE_IRQ },
+- { NULL, KSEG1ADDR(EMMA2RH_PIIC1_BASE), KSEG1ADDR(EMMA2RH_PIIC1_BASE + 0x1000), 0 },
++ {
++ .name = NULL,
++ .start = EMMA2RH_IRQ_PIIC1,
++ .end = EMMA2RH_IRQ_PIIC1,
++ .flags = IORESOURCE_IRQ
++ }, {
++ .name = NULL,
++ .start = EMMA2RH_PIIC1_BASE,
++ .end = EMMA2RH_PIIC1_BASE + 0x1000,
++ .flags = 0
++ },
+ };
+
+ struct resource i2c_emma_resources_2[] = {
+- { NULL, EMMA2RH_IRQ_PIIC2, EMMA2RH_IRQ_PIIC2, IORESOURCE_IRQ },
+- { NULL, KSEG1ADDR(EMMA2RH_PIIC2_BASE), KSEG1ADDR(EMMA2RH_PIIC2_BASE + 0x1000), 0 },
++ {
++ .name = NULL,
++ .start = EMMA2RH_IRQ_PIIC2,
++ .end = EMMA2RH_IRQ_PIIC2,
++ .flags = IORESOURCE_IRQ
++ }, {
++ .name = NULL,
++ .start = EMMA2RH_PIIC2_BASE,
++ .end = EMMA2RH_PIIC2_BASE + 0x1000,
++ .flags = 0
++ },
+ };
+
+ struct platform_device i2c_emma_devices[] = {
+@@ -83,32 +110,29 @@ struct platform_device i2c_emma_devices[
+ #define EMMA2RH_SERIAL_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
+
+ static struct plat_serial8250_port platform_serial_ports[] = {
+- [0] = {
+- .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3),
+- .irq = EMMA2RH_IRQ_PFUR0,
+- .uartclk = EMMA2RH_SERIAL_CLOCK,
+- .regshift = 4,
+- .iotype = UPIO_MEM,
+- .flags = EMMA2RH_SERIAL_FLAGS,
+- },
+- [1] = {
+- .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3),
+- .irq = EMMA2RH_IRQ_PFUR1,
+- .uartclk = EMMA2RH_SERIAL_CLOCK,
+- .regshift = 4,
+- .iotype = UPIO_MEM,
+- .flags = EMMA2RH_SERIAL_FLAGS,
+- },
+- [2] = {
+- .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR2_BASE + 3),
+- .irq = EMMA2RH_IRQ_PFUR2,
+- .uartclk = EMMA2RH_SERIAL_CLOCK,
+- .regshift = 4,
+- .iotype = UPIO_MEM,
+- .flags = EMMA2RH_SERIAL_FLAGS,
+- },
+- [3] = {
+- .flags = 0,
++ [0] = {
++ .membase= (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3),
++ .irq = EMMA2RH_IRQ_PFUR0,
++ .uartclk = EMMA2RH_SERIAL_CLOCK,
++ .regshift = 4,
++ .iotype = UPIO_MEM,
++ .flags = EMMA2RH_SERIAL_FLAGS,
++ }, [1] = {
++ .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3),
++ .irq = EMMA2RH_IRQ_PFUR1,
++ .uartclk = EMMA2RH_SERIAL_CLOCK,
++ .regshift = 4,
++ .iotype = UPIO_MEM,
++ .flags = EMMA2RH_SERIAL_FLAGS,
++ }, [2] = {
++ .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR2_BASE + 3),
++ .irq = EMMA2RH_IRQ_PFUR2,
++ .uartclk = EMMA2RH_SERIAL_CLOCK,
++ .regshift = 4,
++ .iotype = UPIO_MEM,
++ .flags = EMMA2RH_SERIAL_FLAGS,
++ }, [3] = {
++ .flags = 0,
+ },
+ };
+
+diff --git a/arch/mips/galileo-boards/ev96100/Makefile b/arch/mips/galileo-boards/ev96100/Makefile
+deleted file mode 100644
+index cd868ec..0000000
+--- a/arch/mips/galileo-boards/ev96100/Makefile
++++ /dev/null
+@@ -1,9 +0,0 @@
+-#
+-# Copyright 2000 MontaVista Software Inc.
+-# Author: MontaVista Software, Inc.
+-# ppopov at mvista.com or source at mvista.com
+-#
+-# Makefile for the Galileo EV96100 board.
+-#
+-
+-obj-y += init.o irq.o puts.o reset.o time.o setup.o
+diff --git a/arch/mips/galileo-boards/ev96100/init.c b/arch/mips/galileo-boards/ev96100/init.c
+deleted file mode 100644
+index a01fe9b..0000000
+--- a/arch/mips/galileo-boards/ev96100/init.c
++++ /dev/null
+@@ -1,173 +0,0 @@
+-/*
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/generic/generic.c
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/init.h>
+-#include <linux/mm.h>
+-#include <linux/sched.h>
+-#include <linux/bootmem.h>
+-#include <linux/string.h>
+-#include <linux/kernel.h>
+-
+-#include <asm/addrspace.h>
+-#include <asm/bootinfo.h>
+-#include <asm/gt64120.h>
+-
+-
+-/* Environment variable */
+-
+-typedef struct {
+- char *name;
+- char *val;
+-} t_env_var;
+-
+-int prom_argc;
+-char **prom_argv, **prom_envp;
+-
+-int init_debug = 0;
+-
+-char * __init prom_getcmdline(void)
+-{
+- return &(arcs_cmdline[0]);
+-}
+-
+-unsigned long __init prom_free_prom_memory(void)
+-{
+- return 0;
+-}
+-
+-void __init prom_init_cmdline(void)
+-{
+- char *cp;
+- int actr;
+-
+- actr = 1; /* Always ignore argv[0] */
+-
+- cp = &(arcs_cmdline[0]);
+- while(actr < prom_argc) {
+- strcpy(cp, prom_argv[actr]);
+- cp += strlen(prom_argv[actr]);
+- *cp++ = ' ';
+- actr++;
+- }
+- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+- --cp;
+- *cp = '\0';
+-}
+-
+-char *prom_getenv(char *envname)
+-{
+- /*
+- * Return a pointer to the given environment variable.
+- */
+-
+- t_env_var *env = (t_env_var *) prom_envp;
+- int i;
+-
+- i = strlen(envname);
+-
+- while (env->name) {
+- if (strncmp(envname, env->name, i) == 0) {
+- return (env->val);
+- }
+- env++;
+- }
+- return (NULL);
+-}
+-
+-static inline unsigned char str2hexnum(unsigned char c)
+-{
+- if (c >= '0' && c <= '9')
+- return c - '0';
+- if (c >= 'a' && c <= 'f')
+- return c - 'a' + 10;
+- return 0; /* foo */
+-}
+-
+-static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+-{
+- int i;
+-
+- for (i = 0; i < 6; i++) {
+- unsigned char num;
+-
+- if ((*str == '.') || (*str == ':'))
+- str++;
+- num = str2hexnum(*str++) << 4;
+- num |= (str2hexnum(*str++));
+- ea[i] = num;
+- }
+-}
+-
+-int get_ethernet_addr(char *ethernet_addr)
+-{
+- char *ethaddr_str;
+-
+- ethaddr_str = prom_getenv("ethaddr");
+- if (!ethaddr_str) {
+- printk("ethaddr not set in boot prom\n");
+- return -1;
+- }
+- str2eaddr(ethernet_addr, ethaddr_str);
+-
+- if (init_debug > 1) {
+- int i;
+- printk("get_ethernet_addr: ");
+- for (i = 0; i < 5; i++)
+- printk("%02x:",
+- (unsigned char) *(ethernet_addr + i));
+- printk("%02x\n", *(ethernet_addr + i));
+- }
+-
+- return 0;
+-}
+-
+-const char *get_system_type(void)
+-{
+- return "Galileo EV96100";
+-}
+-
+-void __init prom_init(void)
+-{
+- volatile unsigned char *uart;
+- char ppbuf[8];
+-
+- prom_argc = fw_arg0;
+- prom_argv = (char **) fw_arg1;
+- prom_envp = (char **) fw_arg2;
+-
+- mips_machgroup = MACH_GROUP_GALILEO;
+- mips_machtype = MACH_EV96100;
+-
+- prom_init_cmdline();
+-
+- /* 32 MB upgradable */
+- add_memory_region(0, 32 << 20, BOOT_MEM_RAM);
+-}
+diff --git a/arch/mips/galileo-boards/ev96100/irq.c b/arch/mips/galileo-boards/ev96100/irq.c
+deleted file mode 100644
+index ee5d672..0000000
+--- a/arch/mips/galileo-boards/ev96100/irq.c
++++ /dev/null
+@@ -1,77 +0,0 @@
+-/*
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/atlas/atlas_int.c.
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/errno.h>
+-#include <linux/init.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/irq.h>
+-#include <linux/module.h>
+-#include <linux/signal.h>
+-#include <linux/sched.h>
+-#include <linux/types.h>
+-#include <linux/interrupt.h>
+-#include <asm/irq_cpu.h>
+-
+-static inline unsigned int ffz8(unsigned int word)
+-{
+- unsigned long k;
+-
+- k = 7;
+- if (word & 0x0fUL) { k -= 4; word <<= 4; }
+- if (word & 0x30UL) { k -= 2; word <<= 2; }
+- if (word & 0x40UL) { k -= 1; }
+-
+- return k;
+-}
+-
+-extern void mips_timer_interrupt(struct pt_regs *regs);
+-
+-asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs)
+-{
+- do_IRQ(ffz8(pending >> 8), regs);
+-}
+-
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+-{
+- unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+-
+- if (pending & CAUSEF_IP7)
+- mips_timer_interrupt(regs);
+- else if (pending)
+- ev96100_cpu_irq(pending, regs);
+- else
+- spurious_interrupt(regs);
+-}
+-
+-void __init arch_init_irq(void)
+-{
+- mips_cpu_irq_init(0);
+-}
+diff --git a/arch/mips/galileo-boards/ev96100/puts.c b/arch/mips/galileo-boards/ev96100/puts.c
+deleted file mode 100644
+index 49dc6d1..0000000
+--- a/arch/mips/galileo-boards/ev96100/puts.c
++++ /dev/null
+@@ -1,138 +0,0 @@
+-
+-/*
+- * Debug routines which directly access the uart.
+- */
+-
+-#include <linux/types.h>
+-#include <asm/gt64120.h>
+-
+-
+-//#define SERIAL_BASE EV96100_UART0_REGS_BASE
+-#define SERIAL_BASE 0xBD000020
+-#define NS16550_BASE SERIAL_BASE
+-
+-#define SERA_CMD 0x0D
+-#define SERA_DATA 0x08
+-//#define SERB_CMD 0x05
+-#define SERB_CMD 20
+-#define SERB_DATA 0x00
+-#define TX_BUSY 0x20
+-
+-#define TIMEOUT 0xffff
+-#undef SLOW_DOWN
+-
+-static const char digits[16] = "0123456789abcdef";
+-static volatile unsigned char *const com1 = (unsigned char *) SERIAL_BASE;
+-
+-
+-#ifdef SLOW_DOWN
+-static inline void slow_down()
+-{
+- int k;
+- for (k = 0; k < 10000; k++);
+-}
+-#else
+-#define slow_down()
+-#endif
+-
+-void putch(const unsigned char c)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- do {
+- ch = com1[SERB_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SERB_DATA] = c;
+-}
+-
+-void putchar(const unsigned char c)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- do {
+- ch = com1[SERB_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SERB_DATA] = c;
+-}
+-
+-void puts(unsigned char *cp)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- while (*cp) {
+- do {
+- ch = com1[SERB_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SERB_DATA] = *cp++;
+- }
+- putch('\r');
+- putch('\n');
+-}
+-
+-void fputs(unsigned char *cp)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- while (*cp) {
+-
+- do {
+- ch = com1[SERB_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SERB_DATA] = *cp++;
+- }
+-}
+-
+-
+-void put64(uint64_t ul)
+-{
+- int cnt;
+- unsigned ch;
+-
+- cnt = 16; /* 16 nibbles in a 64 bit long */
+- putch('0');
+- putch('x');
+- do {
+- cnt--;
+- ch = (unsigned char) (ul >> cnt * 4) & 0x0F;
+- putch(digits[ch]);
+- } while (cnt > 0);
+-}
+-
+-void put32(unsigned u)
+-{
+- int cnt;
+- unsigned ch;
+-
+- cnt = 8; /* 8 nibbles in a 32 bit long */
+- putch('0');
+- putch('x');
+- do {
+- cnt--;
+- ch = (unsigned char) (u >> cnt * 4) & 0x0F;
+- putch(digits[ch]);
+- } while (cnt > 0);
+-}
+diff --git a/arch/mips/galileo-boards/ev96100/reset.c b/arch/mips/galileo-boards/ev96100/reset.c
+deleted file mode 100644
+index 5ef9b7f..0000000
+--- a/arch/mips/galileo-boards/ev96100/reset.c
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * Galileo EV96100 reset routines.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/generic/reset.c
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/sched.h>
+-#include <linux/mm.h>
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/processor.h>
+-#include <asm/reboot.h>
+-#include <asm/system.h>
+-#include <asm/gt64120.h>
+-
+-static void mips_machine_restart(char *command);
+-static void mips_machine_halt(void);
+-
+-static void mips_machine_restart(char *command)
+-{
+- set_c0_status(ST0_BEV | ST0_ERL);
+- change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+- flush_cache_all();
+- write_c0_wired(0);
+- __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+- while (1);
+-}
+-
+-static void mips_machine_halt(void)
+-{
+- printk(KERN_NOTICE "You can safely turn off the power\n");
+- while (1)
+- __asm__(".set\tmips3\n\t"
+- "wait\n\t"
+- ".set\tmips0");
+-}
+-
+-void mips_reboot_setup(void)
+-{
+- _machine_restart = mips_machine_restart;
+- _machine_halt = mips_machine_halt;
+-}
+diff --git a/arch/mips/galileo-boards/ev96100/setup.c b/arch/mips/galileo-boards/ev96100/setup.c
+deleted file mode 100644
+index 639ad55..0000000
+--- a/arch/mips/galileo-boards/ev96100/setup.c
++++ /dev/null
+@@ -1,159 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * Galileo EV96100 setup.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/atlas/atlas_setup.c.
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/init.h>
+-#include <linux/sched.h>
+-#include <linux/ioport.h>
+-#include <linux/string.h>
+-#include <linux/ctype.h>
+-#include <linux/pci.h>
+-
+-#include <asm/cpu.h>
+-#include <asm/bootinfo.h>
+-#include <asm/mipsregs.h>
+-#include <asm/irq.h>
+-#include <asm/delay.h>
+-#include <asm/gt64120.h>
+-#include <asm/galileo-boards/ev96100int.h>
+-
+-
+-extern char *__init prom_getcmdline(void);
+-
+-extern void mips_reboot_setup(void);
+-
+-unsigned char mac_0_1[12];
+-
+-void __init plat_mem_setup(void)
+-{
+- unsigned int config = read_c0_config();
+- unsigned int status = read_c0_status();
+- unsigned int info = read_c0_info();
+- u32 tmp;
+-
+- char *argptr;
+-
+- clear_c0_status(ST0_FR);
+-
+- if (config & 0x8)
+- printk("Secondary cache is enabled\n");
+- else
+- printk("Secondary cache is disabled\n");
+-
+- if (status & (1 << 27))
+- printk("User-mode cache ops enabled\n");
+- else
+- printk("User-mode cache ops disabled\n");
+-
+- printk("CP0 info reg: %x\n", (unsigned) info);
+- if (info & (1 << 28))
+- printk("burst mode Scache RAMS\n");
+- else
+- printk("pipelined Scache RAMS\n");
+-
+- if (info & 0x1)
+- printk("Atomic Enable is set\n");
+-
+- argptr = prom_getcmdline();
+-#ifdef CONFIG_SERIAL_CONSOLE
+- if (strstr(argptr, "console=") == NULL) {
+- argptr = prom_getcmdline();
+- strcat(argptr, " console=ttyS0,115200");
+- }
+-#endif
+-
+- mips_reboot_setup();
+-
+- set_io_port_base(KSEG1);
+- ioport_resource.start = GT_PCI_IO_BASE;
+- ioport_resource.end = GT_PCI_IO_BASE + 0x01ffffff;
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+- ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+-#endif
+-
+-
+- /*
+- * Setup GT controller master bit so we can do config cycles
+- */
+-
+- /* Clear cause register bits */
+- GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+- GT_INTRCAUSE_TARABORT0_BIT));
+- /* Setup address */
+- GT_WRITE(GT_PCI0_CFGADDR_OFS,
+- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+- ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+- GT_PCI0_CFGADDR_CONFIGEN_BIT);
+-
+- udelay(2);
+- tmp = GT_READ(GT_PCI0_CFGDATA_OFS);
+-
+- tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+- PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+- GT_WRITE(GT_PCI0_CFGADDR_OFS,
+- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+- ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+- GT_PCI0_CFGADDR_CONFIGEN_BIT);
+- udelay(2);
+- GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp);
+-
+- /* Setup address */
+- GT_WRITE(GT_PCI0_CFGADDR_OFS,
+- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+- ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+- GT_PCI0_CFGADDR_CONFIGEN_BIT);
+-
+- udelay(2);
+- tmp = GT_READ(GT_PCI0_CFGDATA_OFS);
+-}
+-
+-unsigned short get_gt_devid(void)
+-{
+- u32 gt_devid;
+-
+- /* Figure out if this is a gt96100 or gt96100A */
+- GT_WRITE(GT_PCI0_CFGADDR_OFS,
+- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+- ((PCI_VENDOR_ID / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+- GT_PCI0_CFGADDR_CONFIGEN_BIT);
+-
+- udelay(4);
+- gt_devid = GT_READ(GT_PCI0_CFGDATA_OFS);
+-
+- return gt_devid >> 16;
+-}
+diff --git a/arch/mips/galileo-boards/ev96100/time.c b/arch/mips/galileo-boards/ev96100/time.c
+deleted file mode 100644
+index 8cbe842..0000000
+--- a/arch/mips/galileo-boards/ev96100/time.c
++++ /dev/null
+@@ -1,88 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * Galileo EV96100 rtc routines.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/atlas/atlas_rtc.c.
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/init.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/module.h>
+-#include <linux/sched.h>
+-#include <linux/spinlock.h>
+-#include <linux/timex.h>
+-
+-#include <asm/mipsregs.h>
+-#include <asm/ptrace.h>
+-#include <asm/time.h>
+-
+-
+-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+-
+-extern volatile unsigned long wall_jiffies;
+-unsigned long missed_heart_beats = 0;
+-
+-static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+-static unsigned long r4k_cur; /* What counter should be at next timer irq */
+-
+-static inline void ack_r4ktimer(unsigned long newval)
+-{
+- write_c0_compare(newval);
+-}
+-
+-/*
+- * There are a lot of conceptually broken versions of the MIPS timer interrupt
+- * handler floating around. This one is rather different, but the algorithm
+- * is probably more robust.
+- */
+-void mips_timer_interrupt(struct pt_regs *regs)
+-{
+- int irq = 7; /* FIX ME */
+-
+- if (r4k_offset == 0) {
+- goto null;
+- }
+-
+- do {
+- kstat_this_cpu.irqs[irq]++;
+- do_timer(regs);
+-#ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
+-#endif
+- r4k_cur += r4k_offset;
+- ack_r4ktimer(r4k_cur);
+-
+- } while (((unsigned long)read_c0_count()
+- - r4k_cur) < 0x7fffffff);
+- return;
+-
+-null:
+- ack_r4ktimer(0);
+-}
+diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c
+index d837b26..c47eeb7 100644
+--- a/arch/mips/gt64120/common/time.c
++++ b/arch/mips/gt64120/common/time.c
+@@ -10,7 +10,7 @@
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/kernel_stat.h>
+-#include <asm/ptrace.h>
++#include <asm/irq_regs.h>
+ #include <asm/gt64120.h>
+
+ /*
+@@ -19,7 +19,7 @@
+ * differently than other MIPS interrupts.
+ */
+
+-static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t gt64120_irq(int irq, void *dev_id)
+ {
+ unsigned int irq_src, int_high_src, irq_src_mask, int_high_src_mask;
+ int handled = 0;
+@@ -34,14 +34,16 @@ static void gt64120_irq(int irq, void *d
+ if (irq_src & 0x00000800) { /* Check for timer interrupt */
+ handled = 1;
+ irq_src &= ~0x00000800;
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ }
+
+ GT_WRITE(GT_INTRCAUSE_OFS, 0);
+ GT_WRITE(GT_HINTRCAUSE_OFS, 0);
++
++ return IRQ_HANDLED;
+ }
+
+ /*
+@@ -62,14 +64,14 @@ static void gt64120_irq(int irq, void *d
+ * as *irq (=irq0 in ../kernel/time.c). We will do our own timer interrupt
+ * handling.
+ */
+-void gt64120_time_init(void)
++void __init plat_timer_setup(struct irqaction *irq)
+ {
+ static struct irqaction timer;
+
+ /* Disable timer first */
+ GT_WRITE(GT_TC_CONTROL_OFS, 0);
+ /* Load timer value for 100 Hz */
+- GT_WRITE(GT_TC3_OFS, Sys_clock / 100);
++ GT_WRITE(GT_TC3_OFS, Sys_clock / HZ);
+
+ /*
+ * Create the IRQ structure entry for the timer. Since we're too early
+diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c
+index 5d939ac..ed4d82b 100644
+--- a/arch/mips/gt64120/ev64120/irq.c
++++ b/arch/mips/gt64120/ev64120/irq.c
+@@ -46,22 +46,22 @@
+ #include <asm/system.h>
+ #include <asm/gt64120.h>
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP4) /* int2 hardware line (timer) */
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ else if (pending & STATUSF_IP2) /* int0 hardware line */
+- do_IRQ(GT_INTA, regs);
++ do_IRQ(GT_INTA);
+ else if (pending & STATUSF_IP5) /* int3 hardware line */
+- do_IRQ(GT_INTD, regs);
++ do_IRQ(GT_INTD);
+ else if (pending & STATUSF_IP6) /* int4 hardware line */
+- do_IRQ(6, regs);
++ do_IRQ(6);
+ else if (pending & STATUSF_IP7) /* compare int */
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ static void disable_ev64120_irq(unsigned int irq_nr)
+diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c
+index 4236da3..99c8d42 100644
+--- a/arch/mips/gt64120/ev64120/setup.c
++++ b/arch/mips/gt64120/ev64120/setup.c
+@@ -42,7 +42,6 @@
+ #include <asm/irq.h>
+ #include <asm/pci.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/time.h>
+ #include <asm/reboot.h>
+ #include <asm/traps.h>
+@@ -69,7 +68,6 @@ unsigned long __init prom_free_prom_memo
+ * Initializes basic routines and structures pointers, memory size (as
+ * given by the bios and saves the command line.
+ */
+-extern void gt64120_time_init(void);
+
+ void __init plat_mem_setup(void)
+ {
+@@ -77,7 +75,6 @@ void __init plat_mem_setup(void)
+ _machine_halt = galileo_machine_halt;
+ pm_power_off = galileo_machine_power_off;
+
+- board_time_init = gt64120_time_init;
+ set_io_port_base(KSEG1);
+ }
+
+diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
+index 885f67f..d929440 100644
+--- a/arch/mips/gt64120/momenco_ocelot/irq.c
++++ b/arch/mips/gt64120/momenco_ocelot/irq.c
+@@ -48,22 +48,22 @@
+ #include <asm/mipsregs.h>
+ #include <asm/system.h>
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP2) /* int0 hardware line */
+- do_IRQ(2, regs);
++ do_IRQ(2);
+ else if (pending & STATUSF_IP3) /* int1 hardware line */
+- do_IRQ(3, regs);
++ do_IRQ(3);
+ else if (pending & STATUSF_IP4) /* int2 hardware line */
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ else if (pending & STATUSF_IP5) /* int3 hardware line */
+- do_IRQ(5, regs);
++ do_IRQ(5);
+ else if (pending & STATUSF_IP6) /* int4 hardware line */
+- do_IRQ(6, regs);
++ do_IRQ(6);
+ else if (pending & STATUSF_IP7) /* cpu timer */
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ else {
+ /*
+ * Now look at the extended interrupts
+@@ -71,13 +71,13 @@ asmlinkage void plat_irq_dispatch(struct
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+
+ if (pending & STATUSF_IP8) /* int6 hardware line */
+- do_IRQ(8, regs);
++ do_IRQ(8);
+ else if (pending & STATUSF_IP9) /* int7 hardware line */
+- do_IRQ(9, regs);
++ do_IRQ(9);
+ else if (pending & STATUSF_IP10) /* int8 hardware line */
+- do_IRQ(10, regs);
++ do_IRQ(10);
+ else if (pending & STATUSF_IP11) /* int9 hardware line */
+- do_IRQ(11, regs);
++ do_IRQ(11);
+ }
+ }
+
+diff --git a/arch/mips/gt64120/momenco_ocelot/setup.c b/arch/mips/gt64120/momenco_ocelot/setup.c
+index 9804642..94f94eb 100644
+--- a/arch/mips/gt64120/momenco_ocelot/setup.c
++++ b/arch/mips/gt64120/momenco_ocelot/setup.c
+@@ -56,7 +56,6 @@
+ #include <asm/irq.h>
+ #include <asm/pci.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/traps.h>
+ #include <linux/bootmem.h>
+@@ -71,7 +70,6 @@ extern void momenco_ocelot_restart(char
+ extern void momenco_ocelot_halt(void);
+ extern void momenco_ocelot_power_off(void);
+
+-extern void gt64120_time_init(void);
+ extern void momenco_ocelot_irq_setup(void);
+
+ static char reset_reason;
+@@ -157,8 +155,6 @@ void __init plat_mem_setup(void)
+ void (*l3func)(unsigned long)=KSEG1ADDR(&setup_l3cache);
+ unsigned int tmpword;
+
+- board_time_init = gt64120_time_init;
+-
+ _machine_restart = momenco_ocelot_restart;
+ _machine_halt = momenco_ocelot_halt;
+ pm_power_off = momenco_ocelot_power_off;
+diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c
+index 8d75a43..eedfc24 100644
+--- a/arch/mips/gt64120/wrppmc/irq.c
++++ b/arch/mips/gt64120/wrppmc/irq.c
+@@ -30,18 +30,18 @@
+ #include <asm/irq_cpu.h>
+ #include <asm/gt64120.h>
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP7)
+- do_IRQ(WRPPMC_MIPS_TIMER_IRQ, regs); /* CPU Compare/Count internal timer */
++ do_IRQ(WRPPMC_MIPS_TIMER_IRQ); /* CPU Compare/Count internal timer */
+ else if (pending & STATUSF_IP6)
+- do_IRQ(WRPPMC_UART16550_IRQ, regs); /* UART 16550 port */
++ do_IRQ(WRPPMC_UART16550_IRQ); /* UART 16550 port */
+ else if (pending & STATUSF_IP3)
+- do_IRQ(WRPPMC_PCI_INTA_IRQ, regs); /* PCI INT_A */
++ do_IRQ(WRPPMC_PCI_INTA_IRQ); /* PCI INT_A */
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ /**
+diff --git a/arch/mips/ite-boards/Kconfig b/arch/mips/ite-boards/Kconfig
+deleted file mode 100644
+index a6d59ad..0000000
+--- a/arch/mips/ite-boards/Kconfig
++++ /dev/null
+@@ -1,8 +0,0 @@
+-config IT8172_REVC
+- bool "Support for older IT8172 (Rev C)"
+- depends on MIPS_ITE8172
+- help
+- Say Y here to support the older, Revision C version of the Integrated
+- Technology Express, Inc. ITE8172 SBC. Vendor page at
+- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
+- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+diff --git a/arch/mips/ite-boards/generic/Makefile b/arch/mips/ite-boards/generic/Makefile
+deleted file mode 100644
+index 6343153..0000000
+--- a/arch/mips/ite-boards/generic/Makefile
++++ /dev/null
+@@ -1,15 +0,0 @@
+-#
+-# Copyright 2000 MontaVista Software Inc.
+-# Author: MontaVista Software, Inc.
+-# ppopov at mvista.com or source at mvista.com
+-#
+-# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
+-#
+-
+-obj-y += it8172_setup.o irq.o pmon_prom.o \
+- time.o lpc.o puts.o reset.o
+-
+-obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o
+-obj-$(CONFIG_KGDB) += dbg_io.o
+-
+-EXTRA_AFLAGS := $(CFLAGS)
+diff --git a/arch/mips/ite-boards/generic/dbg_io.c b/arch/mips/ite-boards/generic/dbg_io.c
+deleted file mode 100644
+index 8e9cd8a..0000000
+--- a/arch/mips/ite-boards/generic/dbg_io.c
++++ /dev/null
+@@ -1,124 +0,0 @@
+-
+-
+-#ifdef CONFIG_KGDB
+-
+-/* --- CONFIG --- */
+-
+-/* we need uint32 uint8 */
+-/* #include "types.h" */
+-typedef unsigned char uint8;
+-typedef unsigned int uint32;
+-
+-/* --- END OF CONFIG --- */
+-
+-#define UART16550_BAUD_2400 2400
+-#define UART16550_BAUD_4800 4800
+-#define UART16550_BAUD_9600 9600
+-#define UART16550_BAUD_19200 19200
+-#define UART16550_BAUD_38400 38400
+-#define UART16550_BAUD_57600 57600
+-#define UART16550_BAUD_115200 115200
+-
+-#define UART16550_PARITY_NONE 0
+-#define UART16550_PARITY_ODD 0x08
+-#define UART16550_PARITY_EVEN 0x18
+-#define UART16550_PARITY_MARK 0x28
+-#define UART16550_PARITY_SPACE 0x38
+-
+-#define UART16550_DATA_5BIT 0x0
+-#define UART16550_DATA_6BIT 0x1
+-#define UART16550_DATA_7BIT 0x2
+-#define UART16550_DATA_8BIT 0x3
+-
+-#define UART16550_STOP_1BIT 0x0
+-#define UART16550_STOP_2BIT 0x4
+-
+-/* ----------------------------------------------------- */
+-
+-/* === CONFIG === */
+-
+-/* [stevel] we use the IT8712 serial port for kgdb */
+-#define DEBUG_BASE 0xB40003F8 /* 8712 serial port 1 base address */
+-#define MAX_BAUD 115200
+-
+-/* === END OF CONFIG === */
+-
+-/* register offset */
+-#define OFS_RCV_BUFFER 0
+-#define OFS_TRANS_HOLD 0
+-#define OFS_SEND_BUFFER 0
+-#define OFS_INTR_ENABLE 1
+-#define OFS_INTR_ID 2
+-#define OFS_DATA_FORMAT 3
+-#define OFS_LINE_CONTROL 3
+-#define OFS_MODEM_CONTROL 4
+-#define OFS_RS232_OUTPUT 4
+-#define OFS_LINE_STATUS 5
+-#define OFS_MODEM_STATUS 6
+-#define OFS_RS232_INPUT 6
+-#define OFS_SCRATCH_PAD 7
+-
+-#define OFS_DIVISOR_LSB 0
+-#define OFS_DIVISOR_MSB 1
+-
+-
+-/* memory-mapped read/write of the port */
+-#define UART16550_READ(y) (*((volatile uint8*)(DEBUG_BASE + y)))
+-#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z)
+-
+-void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+-{
+- /* disable interrupts */
+- UART16550_WRITE(OFS_INTR_ENABLE, 0);
+-
+- /* set up baud rate */
+- {
+- uint32 divisor;
+-
+- /* set DIAB bit */
+- UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+-
+- /* set divisor */
+- divisor = MAX_BAUD / baud;
+- UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+- UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
+-
+- /* clear DIAB bit */
+- UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+- }
+-
+- /* set data format */
+- UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+-}
+-
+-static int remoteDebugInitialized = 0;
+-
+-uint8 getDebugChar(void)
+-{
+- if (!remoteDebugInitialized) {
+- remoteDebugInitialized = 1;
+- debugInit(UART16550_BAUD_115200,
+- UART16550_DATA_8BIT,
+- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+- }
+-
+- while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+- return UART16550_READ(OFS_RCV_BUFFER);
+-}
+-
+-
+-int putDebugChar(uint8 byte)
+-{
+- if (!remoteDebugInitialized) {
+- remoteDebugInitialized = 1;
+- debugInit(UART16550_BAUD_115200,
+- UART16550_DATA_8BIT,
+- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+- }
+-
+- while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
+- UART16550_WRITE(OFS_SEND_BUFFER, byte);
+- return 1;
+-}
+-
+-#endif
+diff --git a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c
+deleted file mode 100644
+index cb59ca4..0000000
+--- a/arch/mips/ite-boards/generic/irq.c
++++ /dev/null
+@@ -1,308 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * ITE 8172G interrupt/setup routines.
+- *
+- * Copyright 2000,2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * Part of this file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/atlas/atlas_int.c.
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/errno.h>
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/module.h>
+-#include <linux/signal.h>
+-#include <linux/sched.h>
+-#include <linux/types.h>
+-#include <linux/interrupt.h>
+-#include <linux/ioport.h>
+-#include <linux/timex.h>
+-#include <linux/slab.h>
+-#include <linux/random.h>
+-#include <linux/serial_reg.h>
+-#include <linux/bitops.h>
+-
+-#include <asm/bootinfo.h>
+-#include <asm/io.h>
+-#include <asm/mipsregs.h>
+-#include <asm/system.h>
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_int.h>
+-#include <asm/it8172/it8172_dbg.h>
+-
+-/* revisit */
+-#define EXT_IRQ0_TO_IP 2 /* IP 2 */
+-#define EXT_IRQ5_TO_IP 7 /* IP 7 */
+-
+-#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
+-
+-extern void set_debug_traps(void);
+-extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
+-
+-struct it8172_intc_regs volatile *it8172_hw0_icregs =
+- (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
+-
+-static void disable_it8172_irq(unsigned int irq_nr)
+-{
+- if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
+- /* LPC interrupt */
+- it8172_hw0_icregs->lpc_mask |=
+- (1 << (irq_nr - IT8172_LPC_IRQ_BASE));
+- } else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
+- /* Local Bus interrupt */
+- it8172_hw0_icregs->lb_mask |=
+- (1 << (irq_nr - IT8172_LB_IRQ_BASE));
+- } else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
+- /* PCI and other interrupts */
+- it8172_hw0_icregs->pci_mask |=
+- (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
+- } else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
+- /* NMI interrupts */
+- it8172_hw0_icregs->nmi_mask |=
+- (1 << (irq_nr - IT8172_NMI_IRQ_BASE));
+- } else {
+- panic("disable_it8172_irq: bad irq %d", irq_nr);
+- }
+-}
+-
+-static void enable_it8172_irq(unsigned int irq_nr)
+-{
+- if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
+- /* LPC interrupt */
+- it8172_hw0_icregs->lpc_mask &=
+- ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE));
+- }
+- else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
+- /* Local Bus interrupt */
+- it8172_hw0_icregs->lb_mask &=
+- ~(1 << (irq_nr - IT8172_LB_IRQ_BASE));
+- }
+- else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
+- /* PCI and other interrupts */
+- it8172_hw0_icregs->pci_mask &=
+- ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
+- }
+- else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
+- /* NMI interrupts */
+- it8172_hw0_icregs->nmi_mask &=
+- ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE));
+- }
+- else {
+- panic("enable_it8172_irq: bad irq %d", irq_nr);
+- }
+-}
+-
+-static unsigned int startup_ite_irq(unsigned int irq)
+-{
+- enable_it8172_irq(irq);
+- return 0;
+-}
+-
+-#define shutdown_ite_irq disable_it8172_irq
+-#define mask_and_ack_ite_irq disable_it8172_irq
+-
+-static void end_ite_irq(unsigned int irq)
+-{
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+- enable_it8172_irq(irq);
+-}
+-
+-static struct irq_chip it8172_irq_type = {
+- .typename = "ITE8172",
+- .startup = startup_ite_irq,
+- .shutdown = shutdown_ite_irq,
+- .enable = enable_it8172_irq,
+- .disable = disable_it8172_irq,
+- .ack = mask_and_ack_ite_irq,
+- .end = end_ite_irq,
+-};
+-
+-
+-static void enable_none(unsigned int irq) { }
+-static unsigned int startup_none(unsigned int irq) { return 0; }
+-static void disable_none(unsigned int irq) { }
+-static void ack_none(unsigned int irq) { }
+-
+-/* startup is the same as "enable", shutdown is same as "disable" */
+-#define shutdown_none disable_none
+-#define end_none enable_none
+-
+-static struct irq_chip cp0_irq_type = {
+- .typename = "CP0 Count",
+- .startup = startup_none,
+- .shutdown = shutdown_none,
+- .enable = enable_none,
+- .disable = disable_none,
+- .ack = ack_none,
+- .end = end_none
+-};
+-
+-void enable_cpu_timer(void)
+-{
+- unsigned long flags;
+-
+- local_irq_save(flags);
+- set_c0_status(0x100 << EXT_IRQ5_TO_IP);
+- local_irq_restore(flags);
+-}
+-
+-void __init arch_init_irq(void)
+-{
+- int i;
+- unsigned long flags;
+-
+- /* mask all interrupts */
+- it8172_hw0_icregs->lb_mask = 0xffff;
+- it8172_hw0_icregs->lpc_mask = 0xffff;
+- it8172_hw0_icregs->pci_mask = 0xffff;
+- it8172_hw0_icregs->nmi_mask = 0xffff;
+-
+- /* make all interrupts level triggered */
+- it8172_hw0_icregs->lb_trigger = 0;
+- it8172_hw0_icregs->lpc_trigger = 0;
+- it8172_hw0_icregs->pci_trigger = 0;
+- it8172_hw0_icregs->nmi_trigger = 0;
+-
+- /* active level setting */
+- /* uart, keyboard, and mouse are active high */
+- it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000);
+- it8172_hw0_icregs->lb_level |= 0x20;
+-
+- /* keyboard and mouse are edge triggered */
+- it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000);
+-
+-
+-#if 0
+- // Enable this piece of code to make internal USB interrupt
+- // edge triggered.
+- it8172_hw0_icregs->pci_trigger |=
+- (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
+- it8172_hw0_icregs->pci_level &=
+- ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
+-#endif
+-
+- for (i = 0; i <= IT8172_LAST_IRQ; i++) {
+- irq_desc[i].chip = &it8172_irq_type;
+- spin_lock_init(&irq_desc[i].lock);
+- }
+- irq_desc[MIPS_CPU_TIMER_IRQ].chip = &cp0_irq_type;
+- set_c0_status(ALLINTS_NOTIMER);
+-}
+-
+-void mips_spurious_interrupt(struct pt_regs *regs)
+-{
+-#if 1
+- return;
+-#else
+- unsigned long status, cause;
+-
+- printk("got spurious interrupt\n");
+- status = read_c0_status();
+- cause = read_c0_cause();
+- printk("status %x cause %x\n", status, cause);
+- printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr);
+-#endif
+-}
+-
+-void it8172_hw0_irqdispatch(struct pt_regs *regs)
+-{
+- int irq;
+- unsigned short intstatus = 0, status = 0;
+-
+- intstatus = it8172_hw0_icregs->intstatus;
+- if (intstatus & 0x8) {
+- panic("Got NMI interrupt");
+- } else if (intstatus & 0x4) {
+- /* PCI interrupt */
+- irq = 0;
+- status |= it8172_hw0_icregs->pci_req;
+- while (!(status & 0x1)) {
+- irq++;
+- status >>= 1;
+- }
+- irq += IT8172_PCI_DEV_IRQ_BASE;
+- } else if (intstatus & 0x1) {
+- /* Local Bus interrupt */
+- irq = 0;
+- status |= it8172_hw0_icregs->lb_req;
+- while (!(status & 0x1)) {
+- irq++;
+- status >>= 1;
+- }
+- irq += IT8172_LB_IRQ_BASE;
+- } else if (intstatus & 0x2) {
+- /* LPC interrupt */
+- /* Since some lpc interrupts are edge triggered,
+- * we could lose an interrupt this way because
+- * we acknowledge all ints at onces. Revisit.
+- */
+- status |= it8172_hw0_icregs->lpc_req;
+- it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */
+- irq = 0;
+- while (!(status & 0x1)) {
+- irq++;
+- status >>= 1;
+- }
+- irq += IT8172_LPC_IRQ_BASE;
+- } else
+- return;
+-
+- do_IRQ(irq, regs);
+-}
+-
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+-{
+- unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+-
+- if (!pending)
+- mips_spurious_interrupt(regs);
+- else if (pending & CAUSEF_IP7)
+- ll_timer_interrupt(127, regs);
+- else if (pending & CAUSEF_IP2)
+- it8172_hw0_irqdispatch(regs);
+-}
+-
+-void show_pending_irqs(void)
+-{
+- fputs("intstatus: ");
+- put32(it8172_hw0_icregs->intstatus);
+- puts("");
+-
+- fputs("pci_req: ");
+- put32(it8172_hw0_icregs->pci_req);
+- puts("");
+-
+- fputs("lb_req: ");
+- put32(it8172_hw0_icregs->lb_req);
+- puts("");
+-
+- fputs("lpc_req: ");
+- put32(it8172_hw0_icregs->lpc_req);
+- puts("");
+-}
+diff --git a/arch/mips/ite-boards/generic/it8172_cir.c b/arch/mips/ite-boards/generic/it8172_cir.c
+deleted file mode 100644
+index bfc25ad..0000000
+--- a/arch/mips/ite-boards/generic/it8172_cir.c
++++ /dev/null
+@@ -1,170 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * IT8172 Consumer IR port generic routines.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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.
+- */
+-
+-
+-#ifdef CONFIG_IT8172_CIR
+-
+-#include <linux/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_cir.h>
+-
+-
+-volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = {
+- (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)),
+- (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))};
+-
+-
+-/*
+- * Initialize Consumer IR Port.
+- */
+-int cir_port_init(struct cir_port *cir)
+-{
+- int port = cir->port;
+- unsigned char data;
+-
+- /* set baud rate */
+- cir_regs[port]->bdlr = cir->baud_rate & 0xff;
+- cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff;
+-
+- /* set receiver control register */
+- cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr));
+-
+- /* set carrier frequency register */
+- cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs));
+-
+- /* set fifo threshold */
+- data = cir_regs[port]->mstcr & 0xf3;
+- data |= CIR_SET_FIFO_TL(cir->fifo_tl);
+- cir_regs[port]->mstcr = data;
+-
+- clear_fifo(cir);
+- enable_receiver(cir);
+- disable_rx_demodulation(cir);
+-
+- set_rx_active(cir);
+- int_enable(cir);
+- rx_int_enable(cir);
+-
+- return 0;
+-}
+-
+-
+-void clear_fifo(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR;
+-}
+-
+-void enable_receiver(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->rcr |= CIR_RXEN;
+-}
+-
+-void disable_receiver(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->rcr &= ~CIR_RXEN;
+-}
+-
+-void enable_rx_demodulation(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->rcr |= CIR_RXEND;
+-}
+-
+-void disable_rx_demodulation(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->rcr &= ~CIR_RXEND;
+-}
+-
+-void set_rx_active(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->rcr |= CIR_RXACT;
+-}
+-
+-void int_enable(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->ier |= CIR_IEC;
+-}
+-
+-void rx_int_enable(struct cir_port *cir)
+-{
+- cir_regs[cir->port]->ier |= CIR_RDAIE;
+-}
+-
+-void dump_regs(struct cir_port *cir)
+-{
+- printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n",
+- cir_regs[cir->port]->mstcr,
+- cir_regs[cir->port]->ier,
+- cir_regs[cir->port]->iir,
+- cir_regs[cir->port]->cfr,
+- cir_regs[cir->port]->rcr,
+- cir_regs[cir->port]->tcr,
+- cir_regs[cir->port]->tfsr,
+- cir_regs[cir->port]->rfsr);
+-
+- while (cir_regs[cir->port]->iir & CIR_RDAI) {
+- printk("data %x\n", cir_regs[cir->port]->dr);
+- }
+-}
+-
+-void dump_reg_addr(struct cir_port *cir)
+-{
+- printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n",
+- (unsigned)&cir_regs[cir->port]->dr,
+- (unsigned)&cir_regs[cir->port]->mstcr,
+- (unsigned)&cir_regs[cir->port]->ier,
+- (unsigned)&cir_regs[cir->port]->iir,
+- (unsigned)&cir_regs[cir->port]->cfr,
+- (unsigned)&cir_regs[cir->port]->rcr,
+- (unsigned)&cir_regs[cir->port]->tcr,
+- (unsigned)&cir_regs[cir->port]->bdlr,
+- (unsigned)&cir_regs[cir->port]->bdhr,
+- (unsigned)&cir_regs[cir->port]->tfsr,
+- (unsigned)&cir_regs[cir->port]->rfsr);
+-}
+-
+-int cir_get_rx_count(struct cir_port *cir)
+-{
+- return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK;
+-}
+-
+-char cir_read_data(struct cir_port *cir)
+-{
+- return cir_regs[cir->port]->dr;
+-}
+-
+-char get_int_status(struct cir_port *cir)
+-{
+- return cir_regs[cir->port]->iir;
+-}
+-#endif
+diff --git a/arch/mips/ite-boards/generic/it8172_setup.c b/arch/mips/ite-boards/generic/it8172_setup.c
+deleted file mode 100644
+index 07faf3c..0000000
+--- a/arch/mips/ite-boards/generic/it8172_setup.c
++++ /dev/null
+@@ -1,352 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * IT8172/QED5231 board setup.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/init.h>
+-#include <linux/sched.h>
+-#include <linux/ioport.h>
+-#include <linux/irq.h>
+-#include <linux/serial_reg.h>
+-#include <linux/major.h>
+-#include <linux/kdev_t.h>
+-#include <linux/root_dev.h>
+-#include <linux/pm.h>
+-
+-#include <asm/cpu.h>
+-#include <asm/time.h>
+-#include <asm/io.h>
+-#include <asm/bootinfo.h>
+-#include <asm/irq.h>
+-#include <asm/mipsregs.h>
+-#include <asm/reboot.h>
+-#include <asm/traps.h>
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8712.h>
+-
+-extern struct resource ioport_resource;
+-#ifdef CONFIG_SERIO_I8042
+-int init_8712_keyboard(void);
+-#endif
+-
+-extern int SearchIT8712(void);
+-extern void InitLPCInterface(void);
+-extern char * __init prom_getcmdline(void);
+-extern void it8172_restart(char *command);
+-extern void it8172_halt(void);
+-extern void it8172_power_off(void);
+-
+-extern void it8172_time_init(void);
+-
+-#ifdef CONFIG_IT8172_REVC
+-struct {
+- struct resource ram;
+- struct resource pci_mem;
+- struct resource pci_io;
+- struct resource flash;
+- struct resource boot;
+-} it8172_resources = {
+- {
+- .start = 0, /* to be initted */
+- .end = 0,
+- .name = "RAM",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x10000000,
+- .end = 0x13FFFFFF,
+- .name = "PCI Mem",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x14000000,
+- .end = 0x17FFFFFF
+- .name = "PCI I/O",
+- }, {
+- .start = 0x08000000,
+- .end = 0x0CFFFFFF
+- .name = "Flash",
+- }, {
+- .start = 0x1FC00000,
+- .end = 0x1FFFFFFF
+- .name = "Boot ROM",
+- }
+-};
+-#else
+-struct {
+- struct resource ram;
+- struct resource pci_mem0;
+- struct resource pci_mem1;
+- struct resource pci_io;
+- struct resource pci_mem2;
+- struct resource pci_mem3;
+- struct resource flash;
+- struct resource boot;
+-} it8172_resources = {
+- {
+- .start = 0, /* to be initted */
+- .end = 0,
+- .name = "RAM",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x0C000000,
+- .end = 0x0FFFFFFF,
+- .name = "PCI Mem0",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x10000000,
+- .end = 0x13FFFFFF,
+- .name = "PCI Mem1",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x14000000,
+- .end = 0x17FFFFFF
+- .name = "PCI I/O",
+- }, {
+- .start = 0x1A000000,
+- .end = 0x1BFFFFFF,
+- .name = "PCI Mem2",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x1C000000,
+- .end = 0x1FBFFFFF,
+- .name = "PCI Mem3",
+- .flags = IORESOURCE_MEM
+- }, {
+- .start = 0x08000000,
+- .end = 0x0CFFFFFF
+- .name = "Flash",
+- }, {
+- .start = 0x1FC00000,
+- .end = 0x1FFFFFFF
+- .name = "Boot ROM",
+- }
+-};
+-#endif
+-
+-
+-void __init it8172_init_ram_resource(unsigned long memsize)
+-{
+- it8172_resources.ram.end = memsize;
+-}
+-
+-void __init plat_mem_setup(void)
+-{
+- unsigned short dsr;
+- char *argptr;
+-
+- argptr = prom_getcmdline();
+-#ifdef CONFIG_SERIAL_CONSOLE
+- if ((argptr = strstr(argptr, "console=")) == NULL) {
+- argptr = prom_getcmdline();
+- strcat(argptr, " console=ttyS0,115200");
+- }
+-#endif
+-
+- clear_c0_status(ST0_FR);
+-
+- board_time_init = it8172_time_init;
+-
+- _machine_restart = it8172_restart;
+- _machine_halt = it8172_halt;
+- pm_power_off = it8172_power_off;
+-
+- /*
+- * IO/MEM resources.
+- *
+- * revisit this area.
+- */
+- set_io_port_base(KSEG1);
+- ioport_resource.start = it8172_resources.pci_io.start;
+- ioport_resource.end = it8172_resources.pci_io.end;
+-#ifdef CONFIG_IT8172_REVC
+- iomem_resource.start = it8172_resources.pci_mem.start;
+- iomem_resource.end = it8172_resources.pci_mem.end;
+-#else
+- iomem_resource.start = it8172_resources.pci_mem0.start;
+- iomem_resource.end = it8172_resources.pci_mem3.end;
+-#endif
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+- ROOT_DEV = Root_RAM0;
+-#endif
+-
+- /*
+- * Pull enabled devices out of standby
+- */
+- IT_IO_READ16(IT_PM_DSR, dsr);
+-
+- /*
+- * Fixme: This breaks when these drivers are modules!!!
+- */
+-#ifdef CONFIG_SOUND_IT8172
+- dsr &= ~IT_PM_DSR_ACSB;
+-#else
+- dsr |= IT_PM_DSR_ACSB;
+-#endif
+-#ifdef CONFIG_BLK_DEV_IT8172
+- dsr &= ~IT_PM_DSR_IDESB;
+-#else
+- dsr |= IT_PM_DSR_IDESB;
+-#endif
+- IT_IO_WRITE16(IT_PM_DSR, dsr);
+-
+- InitLPCInterface();
+-
+-#ifdef CONFIG_MIPS_ITE8172
+- if (SearchIT8712()) {
+- printk("Found IT8712 Super IO\n");
+- /* enable IT8712 serial port */
+- LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */
+- LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */
+-#ifdef CONFIG_SERIO_I8042
+- if (init_8712_keyboard()) {
+- printk("Unable to initialize keyboard\n");
+- LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */
+- } else {
+- LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */
+- LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2);
+- LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3);
+-
+- LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */
+-
+- LPCSetConfig(0x4, 0x30, 0x1);
+- LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80);
+-
+- if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) ||
+- (LPCGetConfig(LDN_MOUSE, 0x30) == 0))
+- printk("Error: keyboard or mouse not enabled\n");
+-
+- }
+-#endif
+- }
+- else {
+- printk("IT8712 Super IO not found\n");
+- }
+-#endif
+-
+-#ifdef CONFIG_IT8172_CIR
+- {
+- unsigned long data;
+- //printk("Enabling CIR0\n");
+- IT_IO_READ16(IT_PM_DSR, data);
+- data &= ~IT_PM_DSR_CIR0SB;
+- IT_IO_WRITE16(IT_PM_DSR, data);
+- //printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data));
+- }
+-#endif
+-#ifdef CONFIG_IT8172_SCR0
+- {
+- unsigned i;
+- /* Enable Smart Card Reader 0 */
+- /* First power it up */
+- IT_IO_READ16(IT_PM_DSR, i);
+- i &= ~IT_PM_DSR_SCR0SB;
+- IT_IO_WRITE16(IT_PM_DSR, i);
+- /* Then initialize its registers */
+- outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT
+- |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
+- |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
+- |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
+- |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT),
+- IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR);
+- outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
+- IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR);
+- }
+-#endif /* CONFIG_IT8172_SCR0 */
+-#ifdef CONFIG_IT8172_SCR1
+- {
+- unsigned i;
+- /* Enable Smart Card Reader 1 */
+- /* First power it up */
+- IT_IO_READ16(IT_PM_DSR, i);
+- i &= ~IT_PM_DSR_SCR1SB;
+- IT_IO_WRITE16(IT_PM_DSR, i);
+- /* Then initialize its registers */
+- outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT
+- |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
+- |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
+- |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
+- |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT),
+- IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR);
+- outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
+- IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR);
+- }
+-#endif /* CONFIG_IT8172_SCR1 */
+-}
+-
+-#ifdef CONFIG_SERIO_I8042
+-/*
+- * According to the ITE Special BIOS Note for waking up the
+- * keyboard controller...
+- */
+-static int init_8712_keyboard(void)
+-{
+- unsigned int cmd_port = 0x14000064;
+- unsigned int data_port = 0x14000060;
+- ^^^^^^^^^^^
+- Somebody here doesn't grok the concept of io ports.
+-
+- unsigned char data;
+- int i;
+-
+- outb(0xaa, cmd_port); /* send self-test cmd */
+- i = 0;
+- while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */
+- i++;
+- if (i > 0xffffff)
+- return 1;
+- }
+-
+- data = inb(data_port);
+- outb(0xcb, cmd_port); /* set ps2 mode */
+- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+- i++;
+- if (i > 0xffffff)
+- return 1;
+- }
+- outb(0x01, data_port);
+- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+- i++;
+- if (i > 0xffffff)
+- return 1;
+- }
+-
+- outb(0x60, cmd_port); /* write 8042 command byte */
+- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+- i++;
+- if (i > 0xffffff)
+- return 1;
+- }
+- outb(0x45, data_port); /* at interface, keyboard enabled, system flag */
+- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+- i++;
+- if (i > 0xffffff)
+- return 1;
+- }
+-
+- outb(0xae, cmd_port); /* enable interface */
+- return 0;
+-}
+-#endif
+diff --git a/arch/mips/ite-boards/generic/lpc.c b/arch/mips/ite-boards/generic/lpc.c
+deleted file mode 100644
+index cc7584f..0000000
+--- a/arch/mips/ite-boards/generic/lpc.c
++++ /dev/null
+@@ -1,144 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * ITE Semi IT8712 Super I/O functions.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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 <asm/io.h>
+-#include <asm/types.h>
+-#include <asm/it8712.h>
+-#include <asm/it8172/it8172.h>
+-
+-#ifndef TRUE
+-#define TRUE 1
+-#endif
+-
+-#ifndef FALSE
+-#define FALSE 0
+-#endif
+-
+-void LPCEnterMBPnP(void)
+-{
+- int i;
+- unsigned char key[4] = {0x87, 0x01, 0x55, 0x55};
+-
+- for (i = 0; i<4; i++)
+- outb(key[i], LPC_KEY_ADDR);
+-
+-}
+-
+-void LPCExitMBPnP(void)
+-{
+- outb(0x02, LPC_KEY_ADDR);
+- outb(0x02, LPC_DATA_ADDR);
+-}
+-
+-void LPCSetConfig(char LdnNumber, char Index, char data)
+-{
+- LPCEnterMBPnP(); // Enter IT8712 MB PnP mode
+- outb(0x07, LPC_KEY_ADDR);
+- outb(LdnNumber, LPC_DATA_ADDR);
+- outb(Index, LPC_KEY_ADDR);
+- outb(data, LPC_DATA_ADDR);
+- LPCExitMBPnP();
+-}
+-
+-char LPCGetConfig(char LdnNumber, char Index)
+-{
+- char rtn;
+-
+- LPCEnterMBPnP(); // Enter IT8712 MB PnP mode
+- outb(0x07, LPC_KEY_ADDR);
+- outb(LdnNumber, LPC_DATA_ADDR);
+- outb(Index, LPC_KEY_ADDR);
+- rtn = inb(LPC_DATA_ADDR);
+- LPCExitMBPnP();
+- return rtn;
+-}
+-
+-int SearchIT8712(void)
+-{
+- unsigned char Id1, Id2;
+- unsigned short Id;
+-
+- LPCEnterMBPnP();
+- outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */
+- Id1 = inb(LPC_DATA_ADDR);
+- outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */
+- Id2 = inb(LPC_DATA_ADDR);
+- Id = (Id1 << 8) | Id2;
+- LPCExitMBPnP();
+- if (Id == 0x8712)
+- return TRUE;
+- else
+- return FALSE;
+-}
+-
+-void InitLPCInterface(void)
+-{
+- unsigned char bus, dev_fn;
+- unsigned long data;
+-
+- bus = 0;
+- dev_fn = 1<<3 | 4;
+-
+-
+- /* pci cmd, SERR# Enable */
+- IT_WRITE(IT_CONFADDR,
+- (bus << IT_BUSNUM_SHF) |
+- (dev_fn << IT_FUNCNUM_SHF) |
+- ((0x4 / 4) << IT_REGNUM_SHF));
+- IT_READ(IT_CONFDATA, data);
+- data |= 0x0100;
+- IT_WRITE(IT_CONFADDR,
+- (bus << IT_BUSNUM_SHF) |
+- (dev_fn << IT_FUNCNUM_SHF) |
+- ((0x4 / 4) << IT_REGNUM_SHF));
+- IT_WRITE(IT_CONFDATA, data);
+-
+- /* setup serial irq control register */
+- IT_WRITE(IT_CONFADDR,
+- (bus << IT_BUSNUM_SHF) |
+- (dev_fn << IT_FUNCNUM_SHF) |
+- ((0x48 / 4) << IT_REGNUM_SHF));
+- IT_READ(IT_CONFDATA, data);
+- data = (data & 0xffff00ff) | 0xc400;
+- IT_WRITE(IT_CONFADDR,
+- (bus << IT_BUSNUM_SHF) |
+- (dev_fn << IT_FUNCNUM_SHF) |
+- ((0x48 / 4) << IT_REGNUM_SHF));
+- IT_WRITE(IT_CONFDATA, data);
+-
+-
+- /* Enable I/O Space Subtractive Decode */
+- /* default 0x4C is 0x3f220000 */
+- IT_WRITE(IT_CONFADDR,
+- (bus << IT_BUSNUM_SHF) |
+- (dev_fn << IT_FUNCNUM_SHF) |
+- ((0x4C / 4) << IT_REGNUM_SHF));
+- IT_WRITE(IT_CONFDATA, 0x3f2200f3);
+-}
+diff --git a/arch/mips/ite-boards/generic/pmon_prom.c b/arch/mips/ite-boards/generic/pmon_prom.c
+deleted file mode 100644
+index 7d0a79b..0000000
+--- a/arch/mips/ite-boards/generic/pmon_prom.c
++++ /dev/null
+@@ -1,135 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * PROM library initialisation code, assuming a version of
+- * pmon is the boot code.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/xx files.
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/kernel.h>
+-#include <linux/init.h>
+-#include <linux/string.h>
+-
+-#include <asm/bootinfo.h>
+-
+-extern int prom_argc;
+-extern char **prom_argv, **prom_envp;
+-
+-typedef struct
+-{
+- char *name;
+-/* char *val; */
+-}t_env_var;
+-
+-
+-char * __init prom_getcmdline(void)
+-{
+- return &(arcs_cmdline[0]);
+-}
+-
+-void __init prom_init_cmdline(void)
+-{
+- char *cp;
+- int actr;
+-
+- actr = 1; /* Always ignore argv[0] */
+-
+- cp = &(arcs_cmdline[0]);
+- while(actr < prom_argc) {
+- strcpy(cp, prom_argv[actr]);
+- cp += strlen(prom_argv[actr]);
+- *cp++ = ' ';
+- actr++;
+- }
+- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+- --cp;
+- *cp = '\0';
+-
+-}
+-
+-
+-char *prom_getenv(char *envname)
+-{
+- /*
+- * Return a pointer to the given environment variable.
+- * Environment variables are stored in the form of "memsize=64".
+- */
+-
+- t_env_var *env = (t_env_var *)prom_envp;
+- int i;
+-
+- i = strlen(envname);
+-
+- while(env->name) {
+- if(strncmp(envname, env->name, i) == 0) {
+- return(env->name + strlen(envname) + 1);
+- }
+- env++;
+- }
+- return(NULL);
+-}
+-
+-static inline unsigned char str2hexnum(unsigned char c)
+-{
+- if(c >= '0' && c <= '9')
+- return c - '0';
+- if(c >= 'a' && c <= 'f')
+- return c - 'a' + 10;
+- return 0; /* foo */
+-}
+-
+-unsigned long __init prom_free_prom_memory(void)
+-{
+- return 0;
+-}
+-
+-unsigned long __init prom_get_memsize(void)
+-{
+- char *memsize_str;
+- unsigned int memsize;
+-
+- memsize_str = prom_getenv("memsize");
+- if (!memsize_str) {
+-#ifdef CONFIG_MIPS_ITE8172
+- memsize = 32;
+-#elif defined(CONFIG_MIPS_IVR)
+- memsize = 64;
+-#else
+- memsize = 8;
+-#endif
+- printk("memsize unknown: setting to %dMB\n", memsize);
+- } else {
+- printk("memsize: %s\n", memsize_str);
+- memsize = simple_strtol(memsize_str, NULL, 0);
+- }
+- return memsize;
+-}
+diff --git a/arch/mips/ite-boards/generic/puts.c b/arch/mips/ite-boards/generic/puts.c
+deleted file mode 100644
+index 20b02df..0000000
+--- a/arch/mips/ite-boards/generic/puts.c
++++ /dev/null
+@@ -1,139 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Low level uart routines to directly access a 16550 uart.
+- *
+- * Copyright 2000,2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/types.h>
+-
+-#define SERIAL_BASE 0xB4011800 /* it8172 */
+-#define SER_CMD 5
+-#define SER_DATA 0x00
+-#define TX_BUSY 0x20
+-
+-#define TIMEOUT 0xffff
+-#undef SLOW_DOWN
+-
+-static const char digits[16] = "0123456789abcdef";
+-static volatile unsigned char *const com1 = (unsigned char *) SERIAL_BASE;
+-
+-
+-#ifdef SLOW_DOWN
+-static inline void slow_down()
+-{
+- int k;
+- for (k = 0; k < 10000; k++);
+-}
+-#else
+-#define slow_down()
+-#endif
+-
+-void putch(const unsigned char c)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- do {
+- ch = com1[SER_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SER_DATA] = c;
+-}
+-
+-void puts(unsigned char *cp)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- while (*cp) {
+- do {
+- ch = com1[SER_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SER_DATA] = *cp++;
+- }
+- putch('\r');
+- putch('\n');
+-}
+-
+-void fputs(unsigned char *cp)
+-{
+- unsigned char ch;
+- int i = 0;
+-
+- while (*cp) {
+-
+- do {
+- ch = com1[SER_CMD];
+- slow_down();
+- i++;
+- if (i > TIMEOUT) {
+- break;
+- }
+- } while (0 == (ch & TX_BUSY));
+- com1[SER_DATA] = *cp++;
+- }
+-}
+-
+-
+-void put64(uint64_t ul)
+-{
+- int cnt;
+- unsigned ch;
+-
+- cnt = 16; /* 16 nibbles in a 64 bit long */
+- putch('0');
+- putch('x');
+- do {
+- cnt--;
+- ch = (unsigned char) (ul >> cnt * 4) & 0x0F;
+- putch(digits[ch]);
+- } while (cnt > 0);
+-}
+-
+-void put32(unsigned u)
+-{
+- int cnt;
+- unsigned ch;
+-
+- cnt = 8; /* 8 nibbles in a 32 bit long */
+- putch('0');
+- putch('x');
+- do {
+- cnt--;
+- ch = (unsigned char) (u >> cnt * 4) & 0x0F;
+- putch(digits[ch]);
+- } while (cnt > 0);
+-}
+diff --git a/arch/mips/ite-boards/generic/reset.c b/arch/mips/ite-boards/generic/reset.c
+deleted file mode 100644
+index 03bd5ba..0000000
+--- a/arch/mips/ite-boards/generic/reset.c
++++ /dev/null
+@@ -1,60 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * ITE 8172 reset routines.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/sched.h>
+-#include <linux/mm.h>
+-#include <asm/cacheflush.h>
+-#include <asm/io.h>
+-#include <asm/processor.h>
+-#include <asm/reboot.h>
+-#include <asm/system.h>
+-
+-void it8172_restart()
+-{
+- set_c0_status(ST0_BEV | ST0_ERL);
+- change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+- flush_cache_all();
+- write_c0_wired(0);
+- __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+-}
+-
+-void it8172_halt(void)
+-{
+- printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+- while (1)
+- __asm__(".set\tmips3\n\t"
+- "wait\n\t"
+- ".set\tmips0");
+-}
+-
+-void it8172_power_off(void)
+-{
+- it8172_halt();
+-}
+diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c
+deleted file mode 100644
+index 3dc5556..0000000
+--- a/arch/mips/ite-boards/generic/time.c
++++ /dev/null
+@@ -1,249 +0,0 @@
+-/*
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+- *
+- * Copyright (C) 2003 MontaVista Software Inc.
+- * Author: Jun Sun, jsun at mvista.com or jsun at junsun.net
+- *
+- * ########################################################################
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+- * for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+- *
+- * ########################################################################
+- *
+- * Setting up the clock on the MIPS boards.
+- */
+-#include <linux/init.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/sched.h>
+-#include <linux/time.h>
+-#include <linux/spinlock.h>
+-#include <linux/mc146818rtc.h>
+-
+-#include <asm/time.h>
+-#include <asm/mipsregs.h>
+-#include <asm/ptrace.h>
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_int.h>
+-#include <asm/debug.h>
+-
+-#define IT8172_RTC_ADR_REG (IT8172_PCI_IO_BASE + IT_RTC_BASE)
+-#define IT8172_RTC_DAT_REG (IT8172_RTC_ADR_REG + 1)
+-#define IT8172_RTC_CENTURY_REG (IT8172_PCI_IO_BASE + IT_RTC_CENTURY)
+-
+-static volatile char *rtc_adr_reg = (char*)KSEG1ADDR(IT8172_RTC_ADR_REG);
+-static volatile char *rtc_dat_reg = (char*)KSEG1ADDR(IT8172_RTC_DAT_REG);
+-static volatile char *rtc_century_reg = (char*)KSEG1ADDR(IT8172_RTC_CENTURY_REG);
+-
+-unsigned char it8172_rtc_read_data(unsigned long addr)
+-{
+- unsigned char retval;
+-
+- *rtc_adr_reg = addr;
+- retval = *rtc_dat_reg;
+- return retval;
+-}
+-
+-void it8172_rtc_write_data(unsigned char data, unsigned long addr)
+-{
+- *rtc_adr_reg = addr;
+- *rtc_dat_reg = data;
+-}
+-
+-#undef CMOS_READ
+-#undef CMOS_WRITE
+-#define CMOS_READ(addr) it8172_rtc_read_data(addr)
+-#define CMOS_WRITE(data, addr) it8172_rtc_write_data(data, addr)
+-
+-static unsigned char saved_control; /* remember rtc control reg */
+-static inline int rtc_24h(void) { return saved_control & RTC_24H; }
+-static inline int rtc_dm_binary(void) { return saved_control & RTC_DM_BINARY; }
+-
+-static inline unsigned char
+-bin_to_hw(unsigned char c)
+-{
+- if (rtc_dm_binary())
+- return c;
+- else
+- return ((c/10) << 4) + (c%10);
+-}
+-
+-static inline unsigned char
+-hw_to_bin(unsigned char c)
+-{
+- if (rtc_dm_binary())
+- return c;
+- else
+- return (c>>4)*10 + (c &0xf);
+-}
+-
+-/* 0x80 bit indicates pm in 12-hour format */
+-static inline unsigned char
+-hour_bin_to_hw(unsigned char c)
+-{
+- if (rtc_24h())
+- return bin_to_hw(c);
+- if (c >= 12)
+- return 0x80 | bin_to_hw((c==12)?12:c-12); /* 12 is 12pm */
+- else
+- return bin_to_hw((c==0)?12:c); /* 0 is 12 AM, not 0 am */
+-}
+-
+-static inline unsigned char
+-hour_hw_to_bin(unsigned char c)
+-{
+- unsigned char tmp = hw_to_bin(c&0x3f);
+- if (rtc_24h())
+- return tmp;
+- if (c & 0x80)
+- return (tmp==12)?12:tmp+12; /* 12pm is 12, not 24 */
+- else
+- return (tmp==12)?0:tmp; /* 12am is 0 */
+-}
+-
+-static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+-static unsigned long r4k_cur; /* What counter should be at next timer irq */
+-extern unsigned int mips_hpt_frequency;
+-
+-/*
+- * Figure out the r4k offset, the amount to increment the compare
+- * register for each time tick.
+- * Use the RTC to calculate offset.
+- */
+-static unsigned long __init cal_r4koff(void)
+-{
+- unsigned int flags;
+-
+- local_irq_save(flags);
+-
+- /* Start counter exactly on falling edge of update flag */
+- while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+- while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+-
+- /* Start r4k counter. */
+- write_c0_count(0);
+-
+- /* Read counter exactly on falling edge of update flag */
+- while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+- while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+-
+- mips_hpt_frequency = read_c0_count();
+-
+- /* restore interrupts */
+- local_irq_restore(flags);
+-
+- return (mips_hpt_frequency / HZ);
+-}
+-
+-static unsigned long
+-it8172_rtc_get_time(void)
+-{
+- unsigned int year, mon, day, hour, min, sec;
+- unsigned int flags;
+-
+- /* avoid update-in-progress. */
+- for (;;) {
+- local_irq_save(flags);
+- if (! (CMOS_READ(RTC_REG_A) & RTC_UIP))
+- break;
+- /* don't hold intr closed all the time */
+- local_irq_restore(flags);
+- }
+-
+- /* Read regs. */
+- sec = hw_to_bin(CMOS_READ(RTC_SECONDS));
+- min = hw_to_bin(CMOS_READ(RTC_MINUTES));
+- hour = hour_hw_to_bin(CMOS_READ(RTC_HOURS));
+- day = hw_to_bin(CMOS_READ(RTC_DAY_OF_MONTH));
+- mon = hw_to_bin(CMOS_READ(RTC_MONTH));
+- year = hw_to_bin(CMOS_READ(RTC_YEAR)) +
+- hw_to_bin(*rtc_century_reg) * 100;
+-
+- /* restore interrupts */
+- local_irq_restore(flags);
+-
+- return mktime(year, mon, day, hour, min, sec);
+-}
+-
+-static int
+-it8172_rtc_set_time(unsigned long t)
+-{
+- struct rtc_time tm;
+- unsigned int flags;
+-
+- /* convert */
+- to_tm(t, &tm);
+-
+- /* avoid update-in-progress. */
+- for (;;) {
+- local_irq_save(flags);
+- if (! (CMOS_READ(RTC_REG_A) & RTC_UIP))
+- break;
+- /* don't hold intr closed all the time */
+- local_irq_restore(flags);
+- }
+-
+- *rtc_century_reg = bin_to_hw(tm.tm_year/100);
+- CMOS_WRITE(bin_to_hw(tm.tm_sec), RTC_SECONDS);
+- CMOS_WRITE(bin_to_hw(tm.tm_min), RTC_MINUTES);
+- CMOS_WRITE(hour_bin_to_hw(tm.tm_hour), RTC_HOURS);
+- CMOS_WRITE(bin_to_hw(tm.tm_mday), RTC_DAY_OF_MONTH);
+- CMOS_WRITE(bin_to_hw(tm.tm_mon+1), RTC_MONTH); /* tm_mon starts from 0 */
+- CMOS_WRITE(bin_to_hw(tm.tm_year%100), RTC_YEAR);
+-
+- /* restore interrupts */
+- local_irq_restore(flags);
+-
+- return 0;
+-}
+-
+-void __init it8172_time_init(void)
+-{
+- unsigned int est_freq, flags;
+-
+- local_irq_save(flags);
+-
+- saved_control = CMOS_READ(RTC_CONTROL);
+-
+- printk("calculating r4koff... ");
+- r4k_offset = cal_r4koff();
+- printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+-
+- est_freq = 2*r4k_offset*HZ;
+- est_freq += 5000; /* round */
+- est_freq -= est_freq%10000;
+- printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+- (est_freq%1000000)*100/1000000);
+-
+- local_irq_restore(flags);
+-
+- rtc_mips_get_time = it8172_rtc_get_time;
+- rtc_mips_set_time = it8172_rtc_set_time;
+-}
+-
+-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+-
+-void __init plat_timer_setup(struct irqaction *irq)
+-{
+- puts("timer_setup\n");
+- put32(NR_IRQS);
+- puts("");
+- /* we are using the cpu counter for timer interrupts */
+- setup_irq(MIPS_CPU_TIMER_IRQ, irq);
+-
+- /* to generate the first timer interrupt */
+- r4k_cur = (read_c0_count() + r4k_offset);
+- write_c0_compare(r4k_cur);
+- set_c0_status(ALLINTS);
+-}
+diff --git a/arch/mips/ite-boards/ivr/Makefile b/arch/mips/ite-boards/ivr/Makefile
+deleted file mode 100644
+index e4fa604..0000000
+--- a/arch/mips/ite-boards/ivr/Makefile
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#
+-# Copyright 2000 MontaVista Software Inc.
+-# Author: MontaVista Software, Inc.
+-# ppopov at mvista.com or source at mvista.com
+-#
+-# Makefile for the Globespan IVR board,
+-# board-specific files.
+-#
+-
+-obj-y += init.o
+diff --git a/arch/mips/ite-boards/ivr/README b/arch/mips/ite-boards/ivr/README
+deleted file mode 100644
+index aa7d8db..0000000
+--- a/arch/mips/ite-boards/ivr/README
++++ /dev/null
+@@ -1,3 +0,0 @@
+-This is not really a board made by ITE Semi, but it's very
+-similar to the ITE QED-4N-S01B board. The IVR board is made
+-by Globespan and it's a reference board for the PVR chip.
+diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c
+deleted file mode 100644
+index 05cf921..0000000
+--- a/arch/mips/ite-boards/ivr/init.c
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * IVR board setup.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/init.h>
+-#include <linux/mm.h>
+-#include <linux/sched.h>
+-#include <linux/bootmem.h>
+-#include <asm/addrspace.h>
+-#include <asm/bootinfo.h>
+-#include <linux/string.h>
+-#include <linux/kernel.h>
+-#include <asm/sections.h>
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_dbg.h>
+-
+-int prom_argc;
+-char **prom_argv, **prom_envp;
+-
+-extern void __init prom_init_cmdline(void);
+-extern unsigned long __init prom_get_memsize(void);
+-extern void __init it8172_init_ram_resource(unsigned long memsize);
+-
+-const char *get_system_type(void)
+-{
+- return "Globespan IVR";
+-}
+-
+-void __init prom_init(void)
+-{
+- unsigned long mem_size;
+- unsigned long pcicr;
+-
+- prom_argc = fw_arg0;
+- prom_argv = (char **) fw_arg1;
+- prom_envp = (int *) fw_arg3;
+-
+- mips_machgroup = MACH_GROUP_GLOBESPAN;
+- mips_machtype = MACH_IVR; /* Globespan's iTVC15 reference board */
+-
+- prom_init_cmdline();
+-
+- /* pmon does not set memsize */
+- mem_size = prom_get_memsize();
+- mem_size = mem_size << 20;
+-
+- /*
+- * make the entire physical memory visible to pci bus masters
+- */
+- IT_READ(IT_MC_PCICR, pcicr);
+- pcicr &= ~0x1f;
+- pcicr |= (mem_size - 1) >> 22;
+- IT_WRITE(IT_MC_PCICR, pcicr);
+-
+- it8172_init_ram_resource(mem_size);
+- add_memory_region(0, mem_size, BOOT_MEM_RAM);
+-}
+diff --git a/arch/mips/ite-boards/qed-4n-s01b/Makefile b/arch/mips/ite-boards/qed-4n-s01b/Makefile
+deleted file mode 100644
+index bb9972a..0000000
+--- a/arch/mips/ite-boards/qed-4n-s01b/Makefile
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#
+-# Copyright 2000 MontaVista Software Inc.
+-# Author: MontaVista Software, Inc.
+-# ppopov at mvista.com or source at mvista.com
+-#
+-# Makefile for the ITE 8172 (qed-4n-s01b) board, board
+-# specific files.
+-#
+-
+-obj-y := init.o
+diff --git a/arch/mips/ite-boards/qed-4n-s01b/README b/arch/mips/ite-boards/qed-4n-s01b/README
+deleted file mode 100644
+index fb4b519..0000000
+--- a/arch/mips/ite-boards/qed-4n-s01b/README
++++ /dev/null
+@@ -1,2 +0,0 @@
+-This is an ITE (www.iteusa.com) eval board for the ITE 8172G
+-system controller, with a QED 5231 CPU.
+diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c
+deleted file mode 100644
+index ea2a754..0000000
+--- a/arch/mips/ite-boards/qed-4n-s01b/init.c
++++ /dev/null
+@@ -1,82 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * IT8172/QED5231 board setup.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/init.h>
+-#include <linux/mm.h>
+-#include <linux/sched.h>
+-#include <linux/bootmem.h>
+-#include <asm/addrspace.h>
+-#include <asm/bootinfo.h>
+-#include <linux/string.h>
+-#include <linux/kernel.h>
+-#include <asm/sections.h>
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_dbg.h>
+-
+-int prom_argc;
+-char **prom_argv, **prom_envp;
+-
+-extern void __init prom_init_cmdline(void);
+-extern unsigned long __init prom_get_memsize(void);
+-extern void __init it8172_init_ram_resource(unsigned long memsize);
+-
+-const char *get_system_type(void)
+-{
+- return "ITE QED-4N-S01B";
+-}
+-
+-void __init prom_init(void)
+-{
+- unsigned long mem_size;
+- unsigned long pcicr;
+-
+- prom_argc = fw_arg0;
+- prom_argv = (char **) fw_arg1;
+- prom_envp = (int *) fw_arg3;
+-
+- mips_machgroup = MACH_GROUP_ITE;
+- mips_machtype = MACH_QED_4N_S01B; /* ITE board name/number */
+-
+- prom_init_cmdline();
+- mem_size = prom_get_memsize();
+-
+- printk("Memory size: %dMB\n", (unsigned)mem_size);
+-
+- mem_size <<= 20; /* MB */
+-
+- /*
+- * make the entire physical memory visible to pci bus masters
+- */
+- IT_READ(IT_MC_PCICR, pcicr);
+- pcicr &= ~0x1f;
+- pcicr |= (mem_size - 1) >> 22;
+- IT_WRITE(IT_MC_PCICR, pcicr);
+-
+- it8172_init_ram_resource(mem_size);
+- add_memory_region(0, mem_size, BOOT_MEM_RAM);
+-}
+diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
+index eef0509..d5bd6b3 100644
+--- a/arch/mips/jazz/irq.c
++++ b/arch/mips/jazz/irq.c
+@@ -94,26 +94,26 @@ void __init arch_init_irq(void)
+ change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
+ }
+
+-static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
++static void loc_call(unsigned int irq, unsigned int mask)
+ {
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+ r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+ r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
+ }
+
+-static void ll_local_dev(struct pt_regs *regs)
++static void ll_local_dev(void)
+ {
+ switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
+ case 0:
+ panic("Unimplemented loc_no_irq handler");
+ break;
+ case 4:
+- loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
++ loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_PARALLEL);
+ break;
+ case 8:
+- loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
++ loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_FLOPPY);
+ break;
+ case 12:
+ panic("Unimplemented loc_sound handler");
+@@ -122,27 +122,27 @@ static void ll_local_dev(struct pt_regs
+ panic("Unimplemented loc_video handler");
+ break;
+ case 20:
+- loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
++ loc_call(JAZZ_ETHERNET_IRQ, JAZZ_IE_ETHERNET);
+ break;
+ case 24:
+- loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
++ loc_call(JAZZ_SCSI_IRQ, JAZZ_IE_SCSI);
+ break;
+ case 28:
+- loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
++ loc_call(JAZZ_KEYBOARD_IRQ, JAZZ_IE_KEYBOARD);
+ break;
+ case 32:
+- loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
++ loc_call(JAZZ_MOUSE_IRQ, JAZZ_IE_MOUSE);
+ break;
+ case 36:
+- loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
++ loc_call(JAZZ_SERIAL1_IRQ, JAZZ_IE_SERIAL1);
+ break;
+ case 40:
+- loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
++ loc_call(JAZZ_SERIAL2_IRQ, JAZZ_IE_SERIAL2);
+ break;
+ }
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+@@ -150,13 +150,13 @@ asmlinkage void plat_irq_dispatch(struct
+ write_c0_compare(0);
+ else if (pending & IE_IRQ4) {
+ r4030_read_reg32(JAZZ_TIMER_REGISTER);
+- do_IRQ(JAZZ_TIMER_IRQ, regs);
++ do_IRQ(JAZZ_TIMER_IRQ);
+ } else if (pending & IE_IRQ3)
+ panic("Unimplemented ISA NMI handler");
+ else if (pending & IE_IRQ2)
+- do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
++ do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK));
+ else if (pending & IE_IRQ1) {
+- ll_local_dev(regs);
++ ll_local_dev();
+ } else if (unlikely(pending & IE_IRQ0))
+ panic("Unimplemented local_dma handler");
+ else if (pending & IE_SW1) {
+diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c
+index 487a9ea..d848f1a 100644
+--- a/arch/mips/jazz/setup.c
++++ b/arch/mips/jazz/setup.c
+@@ -19,12 +19,12 @@
+ #include <linux/fb.h>
+ #include <linux/ide.h>
+ #include <linux/pm.h>
++#include <linux/screen_info.h>
+
+ #include <asm/bootinfo.h>
+ #include <asm/irq.h>
+ #include <asm/jazz.h>
+ #include <asm/jazzdma.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/io.h>
+ #include <asm/pgtable.h>
+@@ -37,7 +37,7 @@ extern void jazz_machine_restart(char *c
+ extern void jazz_machine_halt(void);
+ extern void jazz_machine_power_off(void);
+
+-void __init plat_time_init(struct irqaction *irq)
++void __init plat_timer_setup(struct irqaction *irq)
+ {
+ /* set the clock to 100 Hz */
+ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
+@@ -45,10 +45,27 @@ void __init plat_time_init(struct irqact
+ }
+
+ static struct resource jazz_io_resources[] = {
+- { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+- { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+- { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+- { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
++ {
++ .start = 0x00,
++ .end = 0x1f,
++ .name = "dma1",
++ .flags = IORESOURCE_BUSY
++ }, {
++ .start = 0x40,
++ .end = 0x5f,
++ .name = "timer",
++ .end = IORESOURCE_BUSY
++ }, {
++ .start = 0x80,
++ .end = 0x8f,
++ .name = "dma page reg",
++ .flags = IORESOURCE_BUSY
++ }, {
++ .start = 0xc0,
++ .end = 0xdf,
++ .name = "dma2",
++ .flags = IORESOURCE_BUSY
++ }
+ };
+
+ void __init plat_mem_setup(void)
+@@ -81,8 +98,6 @@ void __init plat_mem_setup(void)
+ _machine_halt = jazz_machine_halt;
+ pm_power_off = jazz_machine_power_off;
+
+-#warning "Somebody should check if screen_info is ok for Jazz."
+-
+ screen_info = (struct screen_info) {
+ 0, 0, /* orig-x, orig-y */
+ 0, /* unused */
+diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
+index 7221744..de4a238 100644
+--- a/arch/mips/jmr3927/rbhma3100/irq.c
++++ b/arch/mips/jmr3927/rbhma3100/irq.c
+@@ -46,6 +46,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/bitops.h>
+
++#include <asm/irq_regs.h>
+ #include <asm/io.h>
+ #include <asm/mipsregs.h>
+ #include <asm/system.h>
+@@ -239,45 +240,83 @@ struct tb_irq_space jmr3927_ioc_irqspace
+ .space_id = 0,
+ can_share : 1
+ };
++
+ struct tb_irq_space jmr3927_irc_irqspace = {
+- .next = NULL,
+- .start_irqno = JMR3927_IRQ_IRC,
+- nr_irqs : JMR3927_NR_IRQ_IRC,
+- .mask_func = mask_irq_irc,
+- .unmask_func = unmask_irq_irc,
+- .name = "on-chip",
+- .space_id = 0,
+- can_share : 0
++ .next = NULL,
++ .start_irqno = JMR3927_IRQ_IRC,
++ .nr_irqs = JMR3927_NR_IRQ_IRC,
++ .mask_func = mask_irq_irc,
++ .unmask_func = unmask_irq_irc,
++ .name = "on-chip",
++ .space_id = 0,
++ .can_share = 0
+ };
+
+-void jmr3927_spurious(struct pt_regs *regs)
++
++#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
++static int tx_branch_likely_bug_count = 0;
++static int have_tx_branch_likely_bug = 0;
++
++static void tx_branch_likely_bug_fixup(void)
++{
++ struct pt_regs *regs = get_irq_regs();
++
++ /* TX39/49-BUG: Under this condition, the insn in delay slot
++ of the branch likely insn is executed (not nullified) even
++ the branch condition is false. */
++ if (!have_tx_branch_likely_bug)
++ return;
++ if ((regs->cp0_epc & 0xfff) == 0xffc &&
++ KSEGX(regs->cp0_epc) != KSEG0 &&
++ KSEGX(regs->cp0_epc) != KSEG1) {
++ unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4);
++ /* beql,bnel,blezl,bgtzl */
++ /* bltzl,bgezl,blezall,bgezall */
++ /* bczfl, bcztl */
++ if ((insn & 0xf0000000) == 0x50000000 ||
++ (insn & 0xfc0e0000) == 0x04020000 ||
++ (insn & 0xf3fe0000) == 0x41020000) {
++ regs->cp0_epc -= 4;
++ tx_branch_likely_bug_count++;
++ printk(KERN_INFO
++ "fix branch-likery bug in %s (insn %08x)\n",
++ current->comm, insn);
++ }
++ }
++}
++#endif
++
++static void jmr3927_spurious(void)
+ {
++ struct pt_regs * regs = get_irq_regs();
++
+ #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
+- tx_branch_likely_bug_fixup(regs);
++ tx_branch_likely_bug_fixup();
+ #endif
+ printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n",
+ regs->cp0_cause, regs->cp0_epc, regs->regs[31]);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
++ struct pt_regs * regs = get_irq_regs();
+ int irq;
+
+ #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
+- tx_branch_likely_bug_fixup(regs);
++ tx_branch_likely_bug_fixup();
+ #endif
+ if ((regs->cp0_cause & CAUSEF_IP7) == 0) {
+ #if 0
+- jmr3927_spurious(regs);
++ jmr3927_spurious();
+ #endif
+ return;
+ }
+ irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f;
+
+- do_IRQ(irq + JMR3927_IRQ_IRC, regs);
++ do_IRQ(irq + JMR3927_IRQ_IRC);
+ }
+
+-static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id)
+ {
+ unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR);
+ int i;
+@@ -285,7 +324,7 @@ static irqreturn_t jmr3927_ioc_interrupt
+ for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) {
+ if (istat & (1 << i)) {
+ irq = JMR3927_IRQ_IOC + i;
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+ }
+ return IRQ_HANDLED;
+@@ -295,7 +334,7 @@ static struct irqaction ioc_action = {
+ jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL,
+ };
+
+-static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id)
+ {
+ unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR);
+ int i;
+@@ -303,7 +342,7 @@ static irqreturn_t jmr3927_isac_interrup
+ for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) {
+ if (istat & (1 << i)) {
+ irq = JMR3927_IRQ_ISAC + i;
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+ }
+ return IRQ_HANDLED;
+@@ -314,7 +353,7 @@ static struct irqaction isac_action = {
+ };
+
+
+-static irqreturn_t jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id)
+ {
+ printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq);
+
+@@ -324,7 +363,7 @@ static struct irqaction isaerr_action =
+ jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL,
+ };
+
+-static irqreturn_t jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id)
+ {
+ printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq);
+ printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
+@@ -439,33 +478,3 @@ void jmr3927_irq_init(u32 irq_base)
+
+ jmr3927_irq_base = irq_base;
+ }
+-
+-#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
+-static int tx_branch_likely_bug_count = 0;
+-static int have_tx_branch_likely_bug = 0;
+-void tx_branch_likely_bug_fixup(struct pt_regs *regs)
+-{
+- /* TX39/49-BUG: Under this condition, the insn in delay slot
+- of the branch likely insn is executed (not nullified) even
+- the branch condition is false. */
+- if (!have_tx_branch_likely_bug)
+- return;
+- if ((regs->cp0_epc & 0xfff) == 0xffc &&
+- KSEGX(regs->cp0_epc) != KSEG0 &&
+- KSEGX(regs->cp0_epc) != KSEG1) {
+- unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4);
+- /* beql,bnel,blezl,bgtzl */
+- /* bltzl,bgezl,blezall,bgezall */
+- /* bczfl, bcztl */
+- if ((insn & 0xf0000000) == 0x50000000 ||
+- (insn & 0xfc0e0000) == 0x04020000 ||
+- (insn & 0xf3fe0000) == 0x41020000) {
+- regs->cp0_epc -= 4;
+- tx_branch_likely_bug_count++;
+- printk(KERN_INFO
+- "fix branch-likery bug in %s (insn %08x)\n",
+- current->comm, insn);
+- }
+- }
+-}
+-#endif
+diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c
+index 0254340..16e5dfe 100644
+--- a/arch/mips/jmr3927/rbhma3100/setup.c
++++ b/arch/mips/jmr3927/rbhma3100/setup.c
+@@ -170,12 +170,20 @@ static void jmr3927_machine_power_off(vo
+ while (1);
+ }
+
++static unsigned int jmr3927_hpt_read(void)
++{
++ /* We assume this function is called xtime_lock held. */
++ return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr;
++}
++
+ #define USE_RTC_DS1742
+ #ifdef USE_RTC_DS1742
+ extern void rtc_ds1742_init(unsigned long base);
+ #endif
+ static void __init jmr3927_time_init(void)
+ {
++ mips_hpt_read = jmr3927_hpt_read;
++ mips_hpt_frequency = JMR3927_TIMER_CLK;
+ #ifdef USE_RTC_DS1742
+ if (jmr3927_have_nvram()) {
+ rtc_ds1742_init(JMR3927_IOC_NVRAMB_ADDR);
+@@ -183,12 +191,8 @@ static void __init jmr3927_time_init(voi
+ #endif
+ }
+
+-unsigned long jmr3927_do_gettimeoffset(void);
+-
+ void __init plat_timer_setup(struct irqaction *irq)
+ {
+- do_gettimeoffset = jmr3927_do_gettimeoffset;
+-
+ jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ;
+ jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE;
+ jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD;
+@@ -200,34 +204,6 @@ void __init plat_timer_setup(struct irqa
+
+ #define USECS_PER_JIFFY (1000000/HZ)
+
+-unsigned long jmr3927_do_gettimeoffset(void)
+-{
+- unsigned long count;
+- unsigned long res = 0;
+-
+- /* MUST read TRR before TISR. */
+- count = jmr3927_tmrptr->trr;
+-
+- if (jmr3927_tmrptr->tisr & TXx927_TMTISR_TIIS) {
+- /* timer interrupt is pending. use Max value. */
+- res = USECS_PER_JIFFY - 1;
+- } else {
+- /* convert to usec */
+- /* res = count / (JMR3927_TIMER_CLK / 1000000); */
+- res = (count << 7) / ((JMR3927_TIMER_CLK << 7) / 1000000);
+-
+- /*
+- * Due to possible jiffies inconsistencies, we need to check
+- * the result so that we'll get a timer that is monotonic.
+- */
+- if (res >= USECS_PER_JIFFY)
+- res = USECS_PER_JIFFY-1;
+- }
+-
+- return res;
+-}
+-
+-
+ //#undef DO_WRITE_THROUGH
+ #define DO_WRITE_THROUGH
+ #define DO_ENABLE_CACHE
+diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
+index 881c467..cd9cec9 100644
+--- a/arch/mips/kernel/Makefile
++++ b/arch/mips/kernel/Makefile
+@@ -11,6 +11,7 @@ obj-y += cpu-probe.o branch.o entry.o g
+ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
+ irix5sys.o sysirix.o
+
++obj-$(CONFIG_STACKTRACE) += stacktrace.o
+ obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
+
+ obj-$(CONFIG_APM) += apm.o
+diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
+index ec28077..ff88b06 100644
+--- a/arch/mips/kernel/asm-offsets.c
++++ b/arch/mips/kernel/asm-offsets.c
+@@ -22,7 +22,7 @@
+ #define offset(string, ptr, member) \
+ __asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
+ #define constant(string, member) \
+- __asm__("\n@@@" string "%x0" : : "ri" (member))
++ __asm__("\n@@@" string "%X0" : : "ri" (member))
+ #define size(string, size) \
+ __asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
+ #define linefeed text("")
+@@ -93,11 +93,12 @@ void output_thread_info_defines(void)
+ offset("#define TI_TASK ", struct thread_info, task);
+ offset("#define TI_EXEC_DOMAIN ", struct thread_info, exec_domain);
+ offset("#define TI_FLAGS ", struct thread_info, flags);
++ offset("#define TI_TP_VALUE ", struct thread_info, tp_value);
+ offset("#define TI_CPU ", struct thread_info, cpu);
+ offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count);
+ offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit);
+ offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block);
+- offset("#define TI_TP_VALUE ", struct thread_info, tp_value);
++ offset("#define TI_REGS ", struct thread_info, regs);
+ constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER);
+ constant("#define _THREAD_SIZE ", THREAD_SIZE);
+ constant("#define _THREAD_MASK ", THREAD_MASK);
+diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
+index aa2caa6..8485af3 100644
+--- a/arch/mips/kernel/cpu-probe.c
++++ b/arch/mips/kernel/cpu-probe.c
+@@ -38,15 +38,40 @@ static void r3081_wait(void)
+
+ static void r39xx_wait(void)
+ {
+- unsigned long cfg = read_c0_conf();
+- write_c0_conf(cfg | TX39_CONF_HALT);
++ local_irq_disable();
++ if (!need_resched())
++ write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
++ local_irq_enable();
+ }
+
++/*
++ * There is a race when WAIT instruction executed with interrupt
++ * enabled.
++ * But it is implementation-dependent wheter the pipelie restarts when
++ * a non-enabled interrupt is requested.
++ */
+ static void r4k_wait(void)
+ {
+- __asm__(".set\tmips3\n\t"
+- "wait\n\t"
+- ".set\tmips0");
++ __asm__(" .set mips3 \n"
++ " wait \n"
++ " .set mips0 \n");
++}
++
++/*
++ * This variant is preferable as it allows testing need_resched and going to
++ * sleep depending on the outcome atomically. Unfortunately the "It is
++ * implementation-dependent whether the pipeline restarts when a non-enabled
++ * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
++ * using this version a gamble.
++ */
++static void r4k_wait_irqoff(void)
++{
++ local_irq_disable();
++ if (!need_resched())
++ __asm__(" .set mips3 \n"
++ " wait \n"
++ " .set mips0 \n");
++ local_irq_enable();
+ }
+
+ /* The Au1xxx wait is available only if using 32khz counter or
+@@ -56,17 +81,17 @@ int allow_au1k_wait;
+ static void au1k_wait(void)
+ {
+ /* using the wait instruction makes CP0 counter unusable */
+- __asm__(".set mips3\n\t"
+- "cache 0x14, 0(%0)\n\t"
+- "cache 0x14, 32(%0)\n\t"
+- "sync\n\t"
+- "nop\n\t"
+- "wait\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- ".set mips0\n\t"
++ __asm__(" .set mips3 \n"
++ " cache 0x14, 0(%0) \n"
++ " cache 0x14, 32(%0) \n"
++ " sync \n"
++ " nop \n"
++ " wait \n"
++ " nop \n"
++ " nop \n"
++ " nop \n"
++ " nop \n"
++ " .set mips0 \n"
+ : : "r" (au1k_wait));
+ }
+
+@@ -110,8 +135,6 @@ static inline void check_wait(void)
+ case CPU_R5000:
+ case CPU_NEVADA:
+ case CPU_RM7000:
+- case CPU_RM9000:
+- case CPU_TX49XX:
+ case CPU_4KC:
+ case CPU_4KEC:
+ case CPU_4KSC:
+@@ -125,6 +148,10 @@ static inline void check_wait(void)
+ cpu_wait = r4k_wait;
+ printk(" available.\n");
+ break;
++ case CPU_TX49XX:
++ cpu_wait = r4k_wait_irqoff;
++ printk(" available.\n");
++ break;
+ case CPU_AU1000:
+ case CPU_AU1100:
+ case CPU_AU1500:
+@@ -136,6 +163,14 @@ static inline void check_wait(void)
+ } else
+ printk(" unavailable.\n");
+ break;
++ case CPU_RM9000:
++ if ((c->processor_id & 0x00ff) >= 0x40) {
++ cpu_wait = r4k_wait;
++ printk(" available.\n");
++ } else {
++ printk(" unavailable.\n");
++ }
++ break;
+ default:
+ printk(" unavailable.\n");
+ break;
+diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
+index 766655f..f10b6a1 100644
+--- a/arch/mips/kernel/entry.S
++++ b/arch/mips/kernel/entry.S
+@@ -20,10 +20,7 @@
+ #include <asm/mipsmtregs.h>
+ #endif
+
+-#ifdef CONFIG_PREEMPT
+- .macro preempt_stop
+- .endm
+-#else
++#ifndef CONFIG_PREEMPT
+ .macro preempt_stop
+ local_irq_disable
+ .endm
+@@ -32,9 +29,16 @@
+
+ .text
+ .align 5
++FEXPORT(ret_from_irq)
++ LONG_S s0, TI_REGS($28)
++#ifdef CONFIG_PREEMPT
++FEXPORT(ret_from_exception)
++#else
++ b _ret_from_irq
+ FEXPORT(ret_from_exception)
+ preempt_stop
+-FEXPORT(ret_from_irq)
++#endif
++FEXPORT(_ret_from_irq)
+ LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
+ andi t0, t0, KU_USER
+ beqz t0, resume_kernel
+@@ -79,8 +83,10 @@ FEXPORT(syscall_exit)
+ FEXPORT(restore_all) # restore full frame
+ #ifdef CONFIG_MIPS_MT_SMTC
+ /* Detect and execute deferred IPI "interrupts" */
+- move a0,sp
++ LONG_L s0, TI_REGS($28)
++ LONG_S sp, TI_REGS($28)
+ jal deferred_smtc_ipi
++ LONG_S s0, TI_REGS($28)
+ /* Re-arm any temporarily masked interrupts not explicitly "acked" */
+ mfc0 v0, CP0_TCSTATUS
+ ori v1, v0, TCSTATUS_IXMT
+diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
+index 37fda3d..5baca16 100644
+--- a/arch/mips/kernel/genex.S
++++ b/arch/mips/kernel/genex.S
+@@ -131,8 +131,9 @@ NESTED(handle_int, PT_SIZE, sp)
+ CLI
+ TRACE_IRQS_OFF
+
++ LONG_L s0, TI_REGS($28)
++ LONG_S sp, TI_REGS($28)
+ PTR_LA ra, ret_from_irq
+- move a0, sp
+ j plat_irq_dispatch
+ END(handle_int)
+
+@@ -219,9 +220,11 @@ NESTED(except_vec_vi_handler, 0, sp)
+ #endif /* CONFIG_MIPS_MT_SMTC */
+ CLI
+ TRACE_IRQS_OFF
+- move a0, sp
+- jalr v0
+- j ret_from_irq
++
++ LONG_L s0, TI_REGS($28)
++ LONG_S sp, TI_REGS($28)
++ PTR_LA ra, ret_from_irq
++ jr v0
+ END(except_vec_vi_handler)
+
+ /*
+@@ -349,8 +352,8 @@ NESTED(nmi_handler, PT_SIZE, sp)
+ .set at
+ __BUILD_\verbose \exception
+ move a0, sp
+- jal do_\handler
+- j ret_from_exception
++ PTR_LA ra, ret_from_exception
++ j do_\handler
+ END(handle_\exception)
+ .endm
+
+diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
+index 8c6db0f..ddc1b71 100644
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -189,7 +189,8 @@ NESTED(kernel_entry, 16, sp) # kernel
+
+ MTC0 zero, CP0_CONTEXT # clear context register
+ PTR_LA $28, init_thread_union
+- PTR_ADDIU sp, $28, _THREAD_SIZE - 32
++ PTR_LI sp, _THREAD_SIZE - 32
++ PTR_ADDU sp, $28
+ set_saved_sp sp, t0, t1
+ PTR_SUBU sp, 4 * SZREG # init stack pointer
+
+diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
+index ea36c8e..48e3418 100644
+--- a/arch/mips/kernel/i8259.c
++++ b/arch/mips/kernel/i8259.c
+@@ -302,11 +302,11 @@ static struct irqaction irq2 = {
+ };
+
+ static struct resource pic1_io_resource = {
+- .name = "pic1", .start = 0x20, .end = 0x3f, .flags = IORESOURCE_BUSY
++ .name = "pic1", .start = 0x20, .end = 0x21, .flags = IORESOURCE_BUSY
+ };
+
+ static struct resource pic2_io_resource = {
+- .name = "pic2", .start = 0xa0, .end = 0xbf, .flags = IORESOURCE_BUSY
++ .name = "pic2", .start = 0xa0, .end = 0xa1, .flags = IORESOURCE_BUSY
+ };
+
+ /*
+diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
+index 676e868..2132485 100644
+--- a/arch/mips/kernel/irixsig.c
++++ b/arch/mips/kernel/irixsig.c
+@@ -17,6 +17,7 @@
+
+ #include <asm/ptrace.h>
+ #include <asm/uaccess.h>
++#include <asm/unistd.h>
+
+ #undef DEBUG_SIG
+
+@@ -172,11 +173,12 @@ static inline int handle_signal(unsigned
+ return ret;
+ }
+
+-asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
++void do_irix_signal(struct pt_regs *regs)
+ {
+ struct k_sigaction ka;
+ siginfo_t info;
+ int signr;
++ sigset_t *oldset;
+
+ /*
+ * We want the common case to go fast, which is why we may in certain
+@@ -184,19 +186,28 @@ asmlinkage int do_irix_signal(sigset_t *
+ * if so.
+ */
+ if (!user_mode(regs))
+- return 1;
++ return;
+
+- if (try_to_freeze())
+- goto no_signal;
+-
+- if (!oldset)
++ if (test_thread_flag(TIF_RESTORE_SIGMASK))
++ oldset = ¤t->saved_sigmask;
++ else
+ oldset = ¤t->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+- if (signr > 0)
+- return handle_signal(signr, &info, &ka, oldset, regs);
++ if (signr > 0) {
++ /* Whee! Actually deliver the signal. */
++ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
++ /* a signal was successfully delivered; the saved
++ * sigmask will have been stored in the signal frame,
++ * and will be restored by sigreturn, so we can simply
++ * clear the TIF_RESTORE_SIGMASK flag */
++ if (test_thread_flag(TIF_RESTORE_SIGMASK))
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ }
++
++ return;
++ }
+
+-no_signal:
+ /*
+ * Who's code doesn't conform to the restartable syscall convention
+ * dies here!!! The li instruction, a single machine instruction,
+@@ -208,8 +219,22 @@ no_signal:
+ regs->regs[2] == ERESTARTNOINTR) {
+ regs->cp0_epc -= 8;
+ }
++ if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
++ regs->regs[2] = __NR_restart_syscall;
++ regs->regs[7] = regs->regs[26];
++ regs->cp0_epc -= 4;
++ }
++ regs->regs[0] = 0; /* Don't deal with this again. */
++ }
++
++ /*
++ * If there's no signal to deliver, we just put the saved sigmask
++ * back
++ */
++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+ }
+- return 0;
+ }
+
+ asmlinkage void
+@@ -298,6 +323,9 @@ struct sigact_irix5 {
+ int _unused0[2];
+ };
+
++#define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility:
++ set only the low 32 bit of the sigset. */
++
+ #ifdef DEBUG_SIG
+ static inline void dump_sigact_irix5(struct sigact_irix5 *p)
+ {
+@@ -413,7 +441,7 @@ asmlinkage int irix_sigprocmask(int how,
+
+ asmlinkage int irix_sigsuspend(struct pt_regs *regs)
+ {
+- sigset_t saveset, newset;
++ sigset_t newset;
+ sigset_t __user *uset;
+
+ uset = (sigset_t __user *) regs->regs[4];
+@@ -422,18 +450,15 @@ asmlinkage int irix_sigsuspend(struct pt
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(¤t->sighand->siglock);
+- saveset = current->blocked;
++ current->saved_sigmask = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+
+- regs->regs[2] = -EINTR;
+- while (1) {
+- current->state = TASK_INTERRUPTIBLE;
+- schedule();
+- if (do_irix_signal(&saveset, regs))
+- return -EINTR;
+- }
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ set_thread_flag(TIF_RESTORE_SIGMASK);
++ return -ERESTARTNOHAND;
+ }
+
+ /* hate hate hate... */
+diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
+index 63dfeb4..650a80c 100644
+--- a/arch/mips/kernel/irq-msc01.c
++++ b/arch/mips/kernel/irq-msc01.c
+@@ -1,16 +1,17 @@
+ /*
+- * Copyright (c) 2004 MIPS Inc
+- * Author: chris at mips.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.
++ *
++ * Copyright (c) 2004 MIPS Inc
++ * Author: chris at mips.com
++ *
++ * Copyright (C) 2004, 06 Ralf Baechle <ralf at linux-mips.org>
+ */
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/kernel.h>
+-#include <asm/ptrace.h>
+ #include <linux/sched.h>
+ #include <linux/kernel_stat.h>
+ #include <asm/io.h>
+@@ -115,14 +116,14 @@ static void end_msc_irq(unsigned int irq
+ /*
+ * Interrupt handler for interrupts coming from SOC-it.
+ */
+-void ll_msc_irq(struct pt_regs *regs)
++void ll_msc_irq(void)
+ {
+ unsigned int irq;
+
+ /* read the interrupt vector register */
+ MSCIC_READ(MSC01_IC_VEC, irq);
+ if (irq < 64)
+- do_IRQ(irq + irq_base, regs);
++ do_IRQ(irq + irq_base);
+ else {
+ /* Ignore spurious interrupt */
+ }
+diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c
+index b117e64..37d1062 100644
+--- a/arch/mips/kernel/irq-mv6434x.c
++++ b/arch/mips/kernel/irq-mv6434x.c
+@@ -1,7 +1,7 @@
+ /*
+ * Copyright 2002 Momentum Computer
+ * Author: mdharm at momenco.com
+- * Copyright (C) 2004 Ralf Baechle <ralf at linux-mips.org>
++ * Copyright (C) 2004, 06 Ralf Baechle <ralf at linux-mips.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 the
+@@ -15,7 +15,6 @@
+ #include <linux/mv643xx.h>
+ #include <linux/sched.h>
+
+-#include <asm/ptrace.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/marvell.h>
+@@ -113,7 +112,7 @@ static void end_mv64340_irq(unsigned int
+ * Interrupt handler for interrupts coming from the Marvell chip.
+ * It could be built in ethernet ports etc...
+ */
+-void ll_mv64340_irq(struct pt_regs *regs)
++void ll_mv64340_irq(void)
+ {
+ unsigned int irq_src_low, irq_src_high;
+ unsigned int irq_mask_low, irq_mask_high;
+@@ -129,9 +128,9 @@ void ll_mv64340_irq(struct pt_regs *regs
+ irq_src_high &= irq_mask_high;
+
+ if (irq_src_low)
+- do_IRQ(ls1bit32(irq_src_low) + irq_base, regs);
++ do_IRQ(ls1bit32(irq_src_low) + irq_base);
+ else
+- do_IRQ(ls1bit32(irq_src_high) + irq_base + 32, regs);
++ do_IRQ(ls1bit32(irq_src_high) + irq_base + 32);
+ }
+
+ #define shutdown_mv64340_irq disable_mv64340_irq
+diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
+index d955aae..9b0e49d 100644
+--- a/arch/mips/kernel/irq.c
++++ b/arch/mips/kernel/irq.c
+@@ -26,6 +26,48 @@
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+
++static unsigned long irq_map[NR_IRQS / BITS_PER_LONG];
++
++int __devinit allocate_irqno(void)
++{
++ int irq;
++
++again:
++ irq = find_first_zero_bit(irq_map, NR_IRQS);
++
++ if (irq >= NR_IRQS)
++ return -ENOSPC;
++
++ if (test_and_set_bit(irq, irq_map))
++ goto again;
++
++ return irq;
++}
++
++EXPORT_SYMBOL_GPL(allocate_irqno);
++
++/*
++ * Allocate the 16 legacy interrupts for i8259 devices. This happens early
++ * in the kernel initialization so treating allocation failure as BUG() is
++ * ok.
++ */
++void __init alloc_legacy_irqno(void)
++{
++ int i;
++
++ for (i = 0; i <= 16; i++)
++ BUG_ON(test_and_set_bit(i, irq_map));
++}
++
++void __devinit free_irqno(unsigned int irq)
++{
++ smp_mb__before_clear_bit();
++ clear_bit(irq, irq_map);
++ smp_mb__after_clear_bit();
++}
++
++EXPORT_SYMBOL_GPL(free_irqno);
++
+ /*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+@@ -53,12 +95,12 @@ unsigned long irq_hwmask[NR_IRQS];
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+-asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs)
++asmlinkage unsigned int do_IRQ(unsigned int irq)
+ {
+ irq_enter();
+
+ __DO_IRQ_SMTC_HOOK();
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+
+ irq_exit();
+
+@@ -110,7 +152,7 @@ skip:
+ return 0;
+ }
+
+-asmlinkage void spurious_interrupt(struct pt_regs *regs)
++asmlinkage void spurious_interrupt(void)
+ {
+ atomic_inc(&irq_err_count);
+ }
+diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
+index 450ac59..7a3ebbe 100644
+--- a/arch/mips/kernel/linux32.c
++++ b/arch/mips/kernel/linux32.c
+@@ -77,6 +77,8 @@ int cp_compat_stat(struct kstat *stat, s
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.st_dev = new_encode_dev(stat->dev);
+ tmp.st_ino = stat->ino;
++ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
++ return -EOVERFLOW;
+ tmp.st_mode = stat->mode;
+ tmp.st_nlink = stat->nlink;
+ SET_UID(tmp.st_uid, stat->uid);
+@@ -991,7 +993,7 @@ struct sysctl_args32
+ unsigned int __unused[4];
+ };
+
+-#ifdef CONFIG_SYSCTL
++#ifdef CONFIG_SYSCTL_SYSCALL
+
+ asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
+ {
+@@ -1032,14 +1034,14 @@ asmlinkage long sys32_sysctl(struct sysc
+ return error;
+ }
+
+-#endif /* CONFIG_SYSCTL */
++#endif /* CONFIG_SYSCTL_SYSCALL */
+
+ asmlinkage long sys32_newuname(struct new_utsname __user * name)
+ {
+ int ret = 0;
+
+ down_read(&uts_sem);
+- if (copy_to_user(name,&system_utsname,sizeof *name))
++ if (copy_to_user(name, utsname(), sizeof *name))
+ ret = -EFAULT;
+ up_read(&uts_sem);
+
+@@ -1053,7 +1055,9 @@ asmlinkage long sys32_newuname(struct ne
+ asmlinkage int sys32_personality(unsigned long personality)
+ {
+ int ret;
+- if (current->personality == PER_LINUX32 && personality == PER_LINUX)
++ personality &= 0xffffffff;
++ if (personality(current->personality) == PER_LINUX32 &&
++ personality == PER_LINUX)
+ personality = PER_LINUX32;
+ ret = sys_personality(personality);
+ if (ret == PER_LINUX32)
+@@ -1296,9 +1300,3 @@ _sys32_clone(nabi_no_regargs struct pt_r
+ return do_fork(clone_flags, newsp, ®s, 0,
+ parent_tidptr, child_tidptr);
+ }
+-
+-extern asmlinkage void sys_set_thread_area(u32 addr);
+-asmlinkage void sys32_set_thread_area(u32 addr)
+-{
+- sys_set_thread_area(AA(addr));
+-}
+diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
+index d8beef1..4ed37ba 100644
+--- a/arch/mips/kernel/proc.c
++++ b/arch/mips/kernel/proc.c
+@@ -89,9 +89,9 @@ static const char *cpu_name[] = {
+
+ static int show_cpuinfo(struct seq_file *m, void *v)
+ {
+- unsigned int version = current_cpu_data.processor_id;
+- unsigned int fp_vers = current_cpu_data.fpu_id;
+ unsigned long n = (unsigned long) v - 1;
++ unsigned int version = cpu_data[n].processor_id;
++ unsigned int fp_vers = cpu_data[n].fpu_id;
+ char fmt [64];
+
+ #ifdef CONFIG_SMP
+@@ -107,9 +107,9 @@ static int show_cpuinfo(struct seq_file
+
+ seq_printf(m, "processor\t\t: %ld\n", n);
+ sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
+- cpu_has_fpu ? " FPU V%d.%d" : "");
+- seq_printf(m, fmt, cpu_name[current_cpu_data.cputype <= CPU_LAST ?
+- current_cpu_data.cputype : CPU_UNKNOWN],
++ cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : "");
++ seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ?
++ cpu_data[n].cputype : CPU_UNKNOWN],
+ (version >> 4) & 0x0f, version & 0x0f,
+ (fp_vers >> 4) & 0x0f, fp_vers & 0x0f);
+ seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n",
+@@ -118,7 +118,7 @@ static int show_cpuinfo(struct seq_file
+ seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no");
+ seq_printf(m, "microsecond timers\t: %s\n",
+ cpu_has_counter ? "yes" : "no");
+- seq_printf(m, "tlb_entries\t\t: %d\n", current_cpu_data.tlbsize);
++ seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize);
+ seq_printf(m, "extra interrupt vector\t: %s\n",
+ cpu_has_divec ? "yes" : "no");
+ seq_printf(m, "hardware watchpoint\t: %s\n",
+diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
+index 7ab67f7..ec8209f 100644
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -40,6 +40,7 @@
+ #include <asm/elf.h>
+ #include <asm/isadep.h>
+ #include <asm/inst.h>
++#include <asm/stacktrace.h>
+ #ifdef CONFIG_MIPS_MT_SMTC
+ #include <asm/mipsmtregs.h>
+ extern void smtc_idle_loop_hook(void);
+@@ -114,7 +115,7 @@ void start_thread(struct pt_regs * regs,
+ status |= KU_USER;
+ regs->cp0_status = status;
+ clear_used_math();
+- lose_fpu();
++ clear_fpu_owner();
+ if (cpu_has_dsp)
+ __init_dsp();
+ regs->cp0_epc = pc;
+@@ -273,104 +274,105 @@ long kernel_thread(int (*fn)(void *), vo
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);
+ }
+
+-static struct mips_frame_info {
+- void *func;
+- unsigned long func_size;
+- int frame_size;
+- int pc_offset;
+-} *schedule_frame, mfinfo[64];
+-static int mfinfo_num;
++/*
++ *
++ */
++struct mips_frame_info {
++ void *func;
++ unsigned long func_size;
++ int frame_size;
++ int pc_offset;
++};
+
+-static int __init get_frame_info(struct mips_frame_info *info)
++static inline int is_ra_save_ins(union mips_instruction *ip)
+ {
+- int i;
+- void *func = info->func;
+- union mips_instruction *ip = (union mips_instruction *)func;
++ /* sw / sd $ra, offset($sp) */
++ return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
++ ip->i_format.rs == 29 &&
++ ip->i_format.rt == 31;
++}
++
++static inline int is_jal_jalr_jr_ins(union mips_instruction *ip)
++{
++ if (ip->j_format.opcode == jal_op)
++ return 1;
++ if (ip->r_format.opcode != spec_op)
++ return 0;
++ return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
++}
++
++static inline int is_sp_move_ins(union mips_instruction *ip)
++{
++ /* addiu/daddiu sp,sp,-imm */
++ if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
++ return 0;
++ if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
++ return 1;
++ return 0;
++}
++
++static int get_frame_info(struct mips_frame_info *info)
++{
++ union mips_instruction *ip = info->func;
++ unsigned max_insns = info->func_size / sizeof(union mips_instruction);
++ unsigned i;
++
+ info->pc_offset = -1;
+ info->frame_size = 0;
+- for (i = 0; i < 128; i++, ip++) {
+- /* if jal, jalr, jr, stop. */
+- if (ip->j_format.opcode == jal_op ||
+- (ip->r_format.opcode == spec_op &&
+- (ip->r_format.func == jalr_op ||
+- ip->r_format.func == jr_op)))
+- break;
+
+- if (info->func_size && i >= info->func_size / 4)
++ if (!ip)
++ goto err;
++
++ if (max_insns == 0)
++ max_insns = 128U; /* unknown function size */
++ max_insns = min(128U, max_insns);
++
++ for (i = 0; i < max_insns; i++, ip++) {
++
++ if (is_jal_jalr_jr_ins(ip))
+ break;
+- if (
+-#ifdef CONFIG_32BIT
+- ip->i_format.opcode == addiu_op &&
+-#endif
+-#ifdef CONFIG_64BIT
+- ip->i_format.opcode == daddiu_op &&
+-#endif
+- ip->i_format.rs == 29 &&
+- ip->i_format.rt == 29) {
+- /* addiu/daddiu sp,sp,-imm */
+- if (info->frame_size)
+- continue;
+- info->frame_size = - ip->i_format.simmediate;
++ if (!info->frame_size) {
++ if (is_sp_move_ins(ip))
++ info->frame_size = - ip->i_format.simmediate;
++ continue;
+ }
+-
+- if (
+-#ifdef CONFIG_32BIT
+- ip->i_format.opcode == sw_op &&
+-#endif
+-#ifdef CONFIG_64BIT
+- ip->i_format.opcode == sd_op &&
+-#endif
+- ip->i_format.rs == 29 &&
+- ip->i_format.rt == 31) {
+- /* sw / sd $ra, offset($sp) */
+- if (info->pc_offset != -1)
+- continue;
++ if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
+ info->pc_offset =
+ ip->i_format.simmediate / sizeof(long);
++ break;
+ }
+ }
+- if (info->pc_offset == -1 || info->frame_size == 0) {
+- if (func == schedule)
+- printk("Can't analyze prologue code at %p\n", func);
+- info->pc_offset = -1;
+- info->frame_size = 0;
+- }
+-
+- return 0;
++ if (info->frame_size && info->pc_offset >= 0) /* nested */
++ return 0;
++ if (info->pc_offset < 0) /* leaf */
++ return 1;
++ /* prologue seems boggus... */
++err:
++ return -1;
+ }
+
++static struct mips_frame_info schedule_mfi __read_mostly;
++
+ static int __init frame_info_init(void)
+ {
+- int i;
++ unsigned long size = 0;
+ #ifdef CONFIG_KALLSYMS
+- char *modname;
+- char namebuf[KSYM_NAME_LEN + 1];
+- unsigned long start, size, ofs;
+- extern char __sched_text_start[], __sched_text_end[];
+- extern char __lock_text_start[], __lock_text_end[];
+-
+- start = (unsigned long)__sched_text_start;
+- for (i = 0; i < ARRAY_SIZE(mfinfo); i++) {
+- if (start == (unsigned long)schedule)
+- schedule_frame = &mfinfo[i];
+- if (!kallsyms_lookup(start, &size, &ofs, &modname, namebuf))
+- break;
+- mfinfo[i].func = (void *)(start + ofs);
+- mfinfo[i].func_size = size;
+- start += size - ofs;
+- if (start >= (unsigned long)__lock_text_end)
+- break;
+- if (start == (unsigned long)__sched_text_end)
+- start = (unsigned long)__lock_text_start;
+- }
+-#else
+- mfinfo[0].func = schedule;
+- schedule_frame = &mfinfo[0];
++ unsigned long ofs;
++
++ kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs);
+ #endif
+- for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++)
+- get_frame_info(&mfinfo[i]);
++ schedule_mfi.func = schedule;
++ schedule_mfi.func_size = size;
++
++ get_frame_info(&schedule_mfi);
++
++ /*
++ * Without schedule() frame info, result given by
++ * thread_saved_pc() and get_wchan() are not reliable.
++ */
++ if (schedule_mfi.pc_offset < 0)
++ printk("Can't analyze schedule() prologue at %p\n", schedule);
+
+- mfinfo_num = i;
+ return 0;
+ }
+
+@@ -386,54 +388,110 @@ unsigned long thread_saved_pc(struct tas
+ /* New born processes are a special case */
+ if (t->reg31 == (unsigned long) ret_from_fork)
+ return t->reg31;
+-
+- if (!schedule_frame || schedule_frame->pc_offset < 0)
++ if (schedule_mfi.pc_offset < 0)
+ return 0;
+- return ((unsigned long *)t->reg29)[schedule_frame->pc_offset];
++ return ((unsigned long *)t->reg29)[schedule_mfi.pc_offset];
+ }
+
+-/* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */
+-unsigned long get_wchan(struct task_struct *p)
++
++#ifdef CONFIG_KALLSYMS
++/* used by show_backtrace() */
++unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
++ unsigned long pc, unsigned long *ra)
+ {
+ unsigned long stack_page;
+- unsigned long pc;
+-#ifdef CONFIG_KALLSYMS
+- unsigned long frame;
+-#endif
++ struct mips_frame_info info;
++ unsigned long size, ofs;
++ int leaf;
++ extern void ret_from_irq(void);
++ extern void ret_from_exception(void);
++
++ stack_page = (unsigned long)task_stack_page(task);
++ if (!stack_page)
++ return 0;
+
+- if (!p || p == current || p->state == TASK_RUNNING)
++ /*
++ * If we reached the bottom of interrupt context,
++ * return saved pc in pt_regs.
++ */
++ if (pc == (unsigned long)ret_from_irq ||
++ pc == (unsigned long)ret_from_exception) {
++ struct pt_regs *regs;
++ if (*sp >= stack_page &&
++ *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) {
++ regs = (struct pt_regs *)*sp;
++ pc = regs->cp0_epc;
++ if (__kernel_text_address(pc)) {
++ *sp = regs->regs[29];
++ *ra = regs->regs[31];
++ return pc;
++ }
++ }
++ return 0;
++ }
++ if (!kallsyms_lookup_size_offset(pc, &size, &ofs))
++ return 0;
++ /*
++ * Return ra if an exception occured at the first instruction
++ */
++ if (unlikely(ofs == 0)) {
++ pc = *ra;
++ *ra = 0;
++ return pc;
++ }
++
++ info.func = (void *)(pc - ofs);
++ info.func_size = ofs; /* analyze from start to ofs */
++ leaf = get_frame_info(&info);
++ if (leaf < 0)
+ return 0;
+
+- stack_page = (unsigned long)task_stack_page(p);
+- if (!stack_page || !mfinfo_num)
++ if (*sp < stack_page ||
++ *sp + info.frame_size > stack_page + THREAD_SIZE - 32)
+ return 0;
+
+- pc = thread_saved_pc(p);
++ if (leaf)
++ /*
++ * For some extreme cases, get_frame_info() can
++ * consider wrongly a nested function as a leaf
++ * one. In that cases avoid to return always the
++ * same value.
++ */
++ pc = pc != *ra ? *ra : 0;
++ else
++ pc = ((unsigned long *)(*sp))[info.pc_offset];
++
++ *sp += info.frame_size;
++ *ra = 0;
++ return __kernel_text_address(pc) ? pc : 0;
++}
++#endif
++
++/*
++ * get_wchan - a maintenance nightmare^W^Wpain in the ass ...
++ */
++unsigned long get_wchan(struct task_struct *task)
++{
++ unsigned long pc = 0;
+ #ifdef CONFIG_KALLSYMS
+- if (!in_sched_functions(pc))
+- return pc;
++ unsigned long sp;
++ unsigned long ra = 0;
++#endif
+
+- frame = p->thread.reg29 + schedule_frame->frame_size;
+- do {
+- int i;
++ if (!task || task == current || task->state == TASK_RUNNING)
++ goto out;
++ if (!task_stack_page(task))
++ goto out;
+
+- if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32)
+- return 0;
++ pc = thread_saved_pc(task);
+
+- for (i = mfinfo_num - 1; i >= 0; i--) {
+- if (pc >= (unsigned long) mfinfo[i].func)
+- break;
+- }
+- if (i < 0)
+- break;
++#ifdef CONFIG_KALLSYMS
++ sp = task->thread.reg29 + schedule_mfi.frame_size;
+
+- pc = ((unsigned long *)frame)[mfinfo[i].pc_offset];
+- if (!mfinfo[i].frame_size)
+- break;
+- frame += mfinfo[i].frame_size;
+- } while (in_sched_functions(pc));
++ while (in_sched_functions(pc))
++ pc = unwind_stack(task, &sp, pc, &ra);
+ #endif
+
++out:
+ return pc;
+ }
+-
+diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
+index 362d172..258d74f 100644
+--- a/arch/mips/kernel/ptrace.c
++++ b/arch/mips/kernel/ptrace.c
+@@ -106,6 +106,7 @@ int ptrace_setregs (struct task_struct *
+ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
+ {
+ int i;
++ unsigned int tmp;
+
+ if (!access_ok(VERIFY_WRITE, data, 33 * 8))
+ return -EIO;
+@@ -121,10 +122,10 @@ int ptrace_getfpregs (struct task_struct
+
+ __put_user (child->thread.fpu.fcr31, data + 64);
+
++ preempt_disable();
+ if (cpu_has_fpu) {
+- unsigned int flags, tmp;
++ unsigned int flags;
+
+- preempt_disable();
+ if (cpu_has_mipsmt) {
+ unsigned int vpflags = dvpe();
+ flags = read_c0_status();
+@@ -138,11 +139,11 @@ int ptrace_getfpregs (struct task_struct
+ __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
+ write_c0_status(flags);
+ }
+- preempt_enable();
+- __put_user (tmp, data + 65);
+ } else {
+- __put_user ((__u32) 0, data + 65);
++ tmp = 0;
+ }
++ preempt_enable();
++ __put_user (tmp, data + 65);
+
+ return 0;
+ }
+@@ -245,16 +246,17 @@ long arch_ptrace(struct task_struct *chi
+ unsigned int mtflags;
+ #endif /* CONFIG_MIPS_MT_SMTC */
+
+- if (!cpu_has_fpu)
++ preempt_disable();
++ if (!cpu_has_fpu) {
++ preempt_enable();
+ break;
++ }
+
+ #ifdef CONFIG_MIPS_MT_SMTC
+ /* Read-modify-write of Status must be atomic */
+ local_irq_save(irqflags);
+ mtflags = dmt();
+ #endif /* CONFIG_MIPS_MT_SMTC */
+-
+- preempt_disable();
+ if (cpu_has_mipsmt) {
+ unsigned int vpflags = dvpe();
+ flags = read_c0_status();
+diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
+index f40ecd8..d9a39c1 100644
+--- a/arch/mips/kernel/ptrace32.c
++++ b/arch/mips/kernel/ptrace32.c
+@@ -175,7 +175,9 @@ asmlinkage int sys32_ptrace(int request,
+ unsigned int mtflags;
+ #endif /* CONFIG_MIPS_MT_SMTC */
+
++ preempt_disable();
+ if (!cpu_has_fpu) {
++ preempt_enable();
+ tmp = 0;
+ break;
+ }
+@@ -186,7 +188,6 @@ asmlinkage int sys32_ptrace(int request,
+ mtflags = dmt();
+ #endif /* CONFIG_MIPS_MT_SMTC */
+
+- preempt_disable();
+ if (cpu_has_mipsmt) {
+ unsigned int vpflags = dvpe();
+ flags = read_c0_status();
+diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
+index d5c8b82..cc566cf 100644
+--- a/arch/mips/kernel/r4k_switch.S
++++ b/arch/mips/kernel/r4k_switch.S
+@@ -85,7 +85,12 @@
+ move $28, a2
+ cpu_restore_nonscratch a1
+
++#if (_THREAD_SIZE - 32) < 0x10000
+ PTR_ADDIU t0, $28, _THREAD_SIZE - 32
++#else
++ PTR_LI t0, _THREAD_SIZE - 32
++ PTR_ADDU t0, $28
++#endif
+ set_saved_sp t0, t1, t2
+ #ifdef CONFIG_MIPS_MT_SMTC
+ /* Read-modify-writes of Status must be atomic on a VPE */
+diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
+index cdab1b2..8c8c832 100644
+--- a/arch/mips/kernel/rtlx.c
++++ b/arch/mips/kernel/rtlx.c
+@@ -61,16 +61,16 @@ static int sp_stopping = 0;
+
+ extern void *vpe_get_shared(int index);
+
+-static void rtlx_dispatch(struct pt_regs *regs)
++static void rtlx_dispatch(void)
+ {
+- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
++ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ);
+ }
+
+
+ /* Interrupt handler may be called before rtlx_init has otherwise had
+ a chance to run.
+ */
+-static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
+ {
+ int i;
+
+diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
+index ba1bcd8..a95f37d 100644
+--- a/arch/mips/kernel/scall32-o32.S
++++ b/arch/mips/kernel/scall32-o32.S
+@@ -28,18 +28,7 @@
+ NESTED(handle_sys, PT_SIZE, sp)
+ .set noat
+ SAVE_SOME
+-#ifdef CONFIG_TRACE_IRQFLAGS
+- TRACE_IRQS_ON
+-#ifdef CONFIG_64BIT
+- LONG_L $8, PT_R8(sp)
+- LONG_L $9, PT_R9(sp)
+-#endif
+- LONG_L $7, PT_R7(sp)
+- LONG_L $6, PT_R6(sp)
+- LONG_L $5, PT_R5(sp)
+- LONG_L $4, PT_R4(sp)
+- LONG_L $2, PT_R2(sp)
+-#endif
++ TRACE_IRQS_ON_RELOAD
+ STI
+ .set at
+
+@@ -662,6 +651,11 @@ einval: li v0, -EINVAL
+ sys sys_tee 4
+ sys sys_vmsplice 4
+ sys sys_move_pages 6
++ sys sys_set_robust_list 2
++ sys sys_get_robust_list 3 /* 4310 */
++ sys sys_ni_syscall 0
++ sys sys_getcpu 3
++ sys sys_epoll_pwait 6
+ .endm
+
+ /* We pre-compute the number of _instruction_ bytes needed to
+diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
+index 939e172..8fb0f60 100644
+--- a/arch/mips/kernel/scall64-64.S
++++ b/arch/mips/kernel/scall64-64.S
+@@ -34,7 +34,7 @@ NESTED(handle_sys64, PT_SIZE, sp)
+ */
+ .set noat
+ SAVE_SOME
+- TRACE_IRQS_ON
++ TRACE_IRQS_ON_RELOAD
+ STI
+ .set at
+ #endif
+@@ -466,3 +466,8 @@ sys_call_table:
+ PTR sys_tee /* 5265 */
+ PTR sys_vmsplice
+ PTR sys_move_pages
++ PTR sys_set_robust_list
++ PTR sys_get_robust_list
++ PTR sys_ni_syscall /* 5270 */
++ PTR sys_getcpu
++ PTR sys_epoll_pwait
+diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
+index 98abbc5..0da5ca2 100644
+--- a/arch/mips/kernel/scall64-n32.S
++++ b/arch/mips/kernel/scall64-n32.S
+@@ -33,7 +33,7 @@ NESTED(handle_sysn32, PT_SIZE, sp)
+ #ifndef CONFIG_MIPS32_O32
+ .set noat
+ SAVE_SOME
+- TRACE_IRQS_ON
++ TRACE_IRQS_ON_RELOAD
+ STI
+ .set at
+ #endif
+@@ -247,7 +247,7 @@ EXPORT(sysn32_call_table)
+ PTR sys_capset
+ PTR sys32_rt_sigpending /* 6125 */
+ PTR compat_sys_rt_sigtimedwait
+- PTR sys_rt_sigqueueinfo
++ PTR sys32_rt_sigqueueinfo
+ PTR sysn32_rt_sigsuspend
+ PTR sys32_sigaltstack
+ PTR compat_sys_utime /* 6130 */
+@@ -280,7 +280,7 @@ EXPORT(sysn32_call_table)
+ PTR sys_sync
+ PTR sys_acct
+ PTR sys32_settimeofday
+- PTR sys_mount /* 6160 */
++ PTR compat_sys_mount /* 6160 */
+ PTR sys_umount
+ PTR sys_swapon
+ PTR sys_swapoff
+@@ -390,5 +390,10 @@ EXPORT(sysn32_call_table)
+ PTR sys_splice
+ PTR sys_sync_file_range
+ PTR sys_tee
+- PTR sys_vmsplice /* 6271 */
++ PTR sys_vmsplice /* 6270 */
+ PTR sys_move_pages
++ PTR compat_sys_set_robust_list
++ PTR compat_sys_get_robust_list
++ PTR sys_ni_syscall
++ PTR sys_getcpu
++ PTR sys_epoll_pwait
+diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
+index 505c9ee..b9d00ca 100644
+--- a/arch/mips/kernel/scall64-o32.S
++++ b/arch/mips/kernel/scall64-o32.S
+@@ -28,7 +28,7 @@
+ NESTED(handle_sys, PT_SIZE, sp)
+ .set noat
+ SAVE_SOME
+- TRACE_IRQS_ON
++ TRACE_IRQS_ON_RELOAD
+ STI
+ .set at
+ ld t1, PT_EPC(sp) # skip syscall on return
+@@ -226,7 +226,7 @@ sys_call_table:
+ PTR sys_ni_syscall /* was sys_stat */
+ PTR sys_lseek
+ PTR sys_getpid /* 4020 */
+- PTR sys_mount
++ PTR compat_sys_mount
+ PTR sys_oldumount
+ PTR sys_setuid
+ PTR sys_getuid
+@@ -498,7 +498,7 @@ sys_call_table:
+ PTR sys_mknodat /* 4290 */
+ PTR sys_fchownat
+ PTR compat_sys_futimesat
+- PTR compat_sys_newfstatat
++ PTR sys_newfstatat
+ PTR sys_unlinkat
+ PTR sys_renameat /* 4295 */
+ PTR sys_linkat
+@@ -514,4 +514,9 @@ sys_call_table:
+ PTR sys_tee
+ PTR sys_vmsplice
+ PTR compat_sys_move_pages
++ PTR compat_sys_set_robust_list
++ PTR compat_sys_get_robust_list /* 4310 */
++ PTR sys_ni_syscall
++ PTR sys_getcpu
++ PTR sys_epoll_pwait
+ .size sys_call_table,.-sys_call_table
+diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
+index 8c2b596..8f6e896 100644
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -10,29 +10,15 @@
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2000 2001, 2002 Maciej W. Rozycki
+ */
+-#include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+ #include <linux/module.h>
+-#include <linux/stddef.h>
+-#include <linux/string.h>
+-#include <linux/unistd.h>
+-#include <linux/slab.h>
+-#include <linux/user.h>
+-#include <linux/utsname.h>
+-#include <linux/a.out.h>
+ #include <linux/screen_info.h>
+ #include <linux/bootmem.h>
+ #include <linux/initrd.h>
+-#include <linux/major.h>
+-#include <linux/kdev_t.h>
+ #include <linux/root_dev.h>
+ #include <linux/highmem.h>
+ #include <linux/console.h>
+-#include <linux/mmzone.h>
+ #include <linux/pfn.h>
+
+ #include <asm/addrspace.h>
+@@ -96,6 +82,12 @@ void __init add_memory_region(phys_t sta
+ int x = boot_mem_map.nr_map;
+ struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1;
+
++ /* Sanity check */
++ if (start + size < start) {
++ printk("Trying to add an invalid memory region, skipped\n");
++ return;
++ }
++
+ /*
+ * Try to merge with previous entry if any. This is far less than
+ * perfect but is sufficient for most real world cases.
+@@ -143,167 +135,136 @@ static void __init print_memory_map(void
+ }
+ }
+
+-static inline void parse_cmdline_early(void)
++/*
++ * Manage initrd
++ */
++#ifdef CONFIG_BLK_DEV_INITRD
++
++static int __init rd_start_early(char *p)
+ {
+- char c = ' ', *to = command_line, *from = saved_command_line;
+- unsigned long start_at, mem_size;
+- int len = 0;
+- int usermem = 0;
++ unsigned long start = memparse(p, &p);
+
+- printk("Determined physical RAM map:\n");
+- print_memory_map();
++#ifdef CONFIG_64BIT
++ /* HACK: Guess if the sign extension was forgotten */
++ if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
++ start |= 0xffffffff00000000UL;
++#endif
++ initrd_start = start;
++ initrd_end += start;
+
+- for (;;) {
+- /*
+- * "mem=XXX[kKmM]" defines a memory region from
+- * 0 to <XXX>, overriding the determined size.
+- * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from
+- * <YYY> to <YYY>+<XXX>, overriding the determined size.
+- */
+- if (c == ' ' && !memcmp(from, "mem=", 4)) {
+- if (to != command_line)
+- to--;
+- /*
+- * If a user specifies memory size, we
+- * blow away any automatically generated
+- * size.
+- */
+- if (usermem == 0) {
+- boot_mem_map.nr_map = 0;
+- usermem = 1;
+- }
+- mem_size = memparse(from + 4, &from);
+- if (*from == '@')
+- start_at = memparse(from + 1, &from);
+- else
+- start_at = 0;
+- add_memory_region(start_at, mem_size, BOOT_MEM_RAM);
+- }
+- c = *(from++);
+- if (!c)
+- break;
+- if (CL_SIZE <= ++len)
+- break;
+- *(to++) = c;
+- }
+- *to = '\0';
++ return 0;
++}
++early_param("rd_start", rd_start_early);
+
+- if (usermem) {
+- printk("User-defined physical RAM map:\n");
+- print_memory_map();
+- }
++static int __init rd_size_early(char *p)
++{
++ initrd_end += memparse(p, &p);
++
++ return 0;
+ }
++early_param("rd_size", rd_size_early);
+
+-static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_end)
++static unsigned long __init init_initrd(void)
+ {
++ unsigned long tmp, end, size;
++ u32 *initrd_header;
++
++ ROOT_DEV = Root_RAM0;
++
+ /*
+- * "rd_start=0xNNNNNNNN" defines the memory address of an initrd
+- * "rd_size=0xNN" it's size
++ * Board specific code or command line parser should have
++ * already set up initrd_start and initrd_end. In these cases
++ * perfom sanity checks and use them if all looks good.
+ */
+- unsigned long start = 0;
+- unsigned long size = 0;
+- unsigned long end;
+- char cmd_line[CL_SIZE];
+- char *start_str;
+- char *size_str;
+- char *tmp;
+-
+- strcpy(cmd_line, command_line);
+- *command_line = 0;
+- tmp = cmd_line;
+- /* Ignore "rd_start=" strings in other parameters. */
+- start_str = strstr(cmd_line, "rd_start=");
+- if (start_str && start_str != cmd_line && *(start_str - 1) != ' ')
+- start_str = strstr(start_str, " rd_start=");
+- while (start_str) {
+- if (start_str != cmd_line)
+- strncat(command_line, tmp, start_str - tmp);
+- start = memparse(start_str + 9, &start_str);
+- tmp = start_str + 1;
+- start_str = strstr(start_str, " rd_start=");
++ size = initrd_end - initrd_start;
++ if (initrd_end == 0 || size == 0) {
++ initrd_start = 0;
++ initrd_end = 0;
++ } else
++ return initrd_end;
++
++ end = (unsigned long)&_end;
++ tmp = PAGE_ALIGN(end) - sizeof(u32) * 2;
++ if (tmp < end)
++ tmp += PAGE_SIZE;
++
++ initrd_header = (u32 *)tmp;
++ if (initrd_header[0] == 0x494E5244) {
++ initrd_start = (unsigned long)&initrd_header[2];
++ initrd_end = initrd_start + initrd_header[1];
+ }
+- if (*tmp)
+- strcat(command_line, tmp);
+-
+- strcpy(cmd_line, command_line);
+- *command_line = 0;
+- tmp = cmd_line;
+- /* Ignore "rd_size" strings in other parameters. */
+- size_str = strstr(cmd_line, "rd_size=");
+- if (size_str && size_str != cmd_line && *(size_str - 1) != ' ')
+- size_str = strstr(size_str, " rd_size=");
+- while (size_str) {
+- if (size_str != cmd_line)
+- strncat(command_line, tmp, size_str - tmp);
+- size = memparse(size_str + 8, &size_str);
+- tmp = size_str + 1;
+- size_str = strstr(size_str, " rd_size=");
+- }
+- if (*tmp)
+- strcat(command_line, tmp);
++ return initrd_end;
++}
+
+-#ifdef CONFIG_64BIT
+- /* HACK: Guess if the sign extension was forgotten */
+- if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
+- start |= 0xffffffff00000000UL;
+-#endif
++static void __init finalize_initrd(void)
++{
++ unsigned long size = initrd_end - initrd_start;
+
+- end = start + size;
+- if (start && end) {
+- *rd_start = start;
+- *rd_end = end;
+- return 1;
++ if (size == 0) {
++ printk(KERN_INFO "Initrd not found or empty");
++ goto disable;
++ }
++ if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
++ printk("Initrd extends beyond end of memory");
++ goto disable;
+ }
++
++ reserve_bootmem(CPHYSADDR(initrd_start), size);
++ initrd_below_start_ok = 1;
++
++ printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n",
++ initrd_start, size);
++ return;
++disable:
++ printk(" - disabling initrd\n");
++ initrd_start = 0;
++ initrd_end = 0;
++}
++
++#else /* !CONFIG_BLK_DEV_INITRD */
++
++static unsigned long __init init_initrd(void)
++{
+ return 0;
+ }
+
+-#define MAXMEM HIGHMEM_START
+-#define MAXMEM_PFN PFN_DOWN(MAXMEM)
++#define finalize_initrd() do {} while (0)
+
+-static inline void bootmem_init(void)
++#endif
++
++/*
++ * Initialize the bootmem allocator. It also setup initrd related data
++ * if needed.
++ */
++#ifdef CONFIG_SGI_IP27
++
++static void __init bootmem_init(void)
+ {
+- unsigned long start_pfn;
+- unsigned long reserved_end = (unsigned long)&_end;
+-#ifndef CONFIG_SGI_IP27
+- unsigned long first_usable_pfn;
++ init_initrd();
++ finalize_initrd();
++}
++
++#else /* !CONFIG_SGI_IP27 */
++
++static void __init bootmem_init(void)
++{
++ unsigned long reserved_end;
++ unsigned long highest = 0;
++ unsigned long mapstart = -1UL;
+ unsigned long bootmap_size;
+ int i;
+-#endif
+-#ifdef CONFIG_BLK_DEV_INITRD
+- int initrd_reserve_bootmem = 0;
+-
+- /* Board specific code should have set up initrd_start and initrd_end */
+- ROOT_DEV = Root_RAM0;
+- if (parse_rd_cmdline(&initrd_start, &initrd_end)) {
+- reserved_end = max(reserved_end, initrd_end);
+- initrd_reserve_bootmem = 1;
+- } else {
+- unsigned long tmp;
+- u32 *initrd_header;
+-
+- tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - sizeof(u32) * 2;
+- if (tmp < reserved_end)
+- tmp += PAGE_SIZE;
+- initrd_header = (u32 *)tmp;
+- if (initrd_header[0] == 0x494E5244) {
+- initrd_start = (unsigned long)&initrd_header[2];
+- initrd_end = initrd_start + initrd_header[1];
+- reserved_end = max(reserved_end, initrd_end);
+- initrd_reserve_bootmem = 1;
+- }
+- }
+-#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /*
+- * Partially used pages are not usable - thus
+- * we are rounding upwards.
++ * Init any data related to initrd. It's a nop if INITRD is
++ * not selected. Once that done we can determine the low bound
++ * of usable memory.
+ */
+- start_pfn = PFN_UP(CPHYSADDR(reserved_end));
++ reserved_end = init_initrd();
++ reserved_end = PFN_UP(CPHYSADDR(max(reserved_end, (unsigned long)&_end)));
+
+-#ifndef CONFIG_SGI_IP27
+- /* Find the highest page frame number we have available. */
+- max_pfn = 0;
+- first_usable_pfn = -1UL;
++ /*
++ * Find the highest page frame number we have available.
++ */
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ unsigned long start, end;
+
+@@ -312,56 +273,38 @@ static inline void bootmem_init(void)
+
+ start = PFN_UP(boot_mem_map.map[i].addr);
+ end = PFN_DOWN(boot_mem_map.map[i].addr
+- + boot_mem_map.map[i].size);
++ + boot_mem_map.map[i].size);
+
+- if (start >= end)
++ if (end > highest)
++ highest = end;
++ if (end <= reserved_end)
+ continue;
+- if (end > max_pfn)
+- max_pfn = end;
+- if (start < first_usable_pfn) {
+- if (start > start_pfn) {
+- first_usable_pfn = start;
+- } else if (end > start_pfn) {
+- first_usable_pfn = start_pfn;
+- }
+- }
++ if (start >= mapstart)
++ continue;
++ mapstart = max(reserved_end, start);
+ }
+
+ /*
+ * Determine low and high memory ranges
+ */
+- max_low_pfn = max_pfn;
+- if (max_low_pfn > MAXMEM_PFN) {
+- max_low_pfn = MAXMEM_PFN;
+-#ifndef CONFIG_HIGHMEM
+- /* Maximum memory usable is what is directly addressable */
+- printk(KERN_WARNING "Warning only %ldMB will be used.\n",
+- MAXMEM >> 20);
+- printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
++ if (highest > PFN_DOWN(HIGHMEM_START)) {
++#ifdef CONFIG_HIGHMEM
++ highstart_pfn = PFN_DOWN(HIGHMEM_START);
++ highend_pfn = highest;
+ #endif
++ highest = PFN_DOWN(HIGHMEM_START);
+ }
+
+-#ifdef CONFIG_HIGHMEM
+ /*
+- * Crude, we really should make a better attempt at detecting
+- * highstart_pfn
++ * Initialize the boot-time allocator with low memory only.
+ */
+- highstart_pfn = highend_pfn = max_pfn;
+- if (max_pfn > MAXMEM_PFN) {
+- highstart_pfn = MAXMEM_PFN;
+- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+- (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT));
+- }
+-#endif
+-
+- /* Initialize the boot-time allocator with low memory only. */
+- bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn);
++ bootmap_size = init_bootmem(mapstart, highest);
+
+ /*
+ * Register fully available low RAM pages with the bootmem allocator.
+ */
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+- unsigned long curr_pfn, last_pfn, size;
++ unsigned long start, end, size;
+
+ /*
+ * Reserve usable memory.
+@@ -369,85 +312,50 @@ static inline void bootmem_init(void)
+ if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+ continue;
+
+- /*
+- * We are rounding up the start address of usable memory:
+- */
+- curr_pfn = PFN_UP(boot_mem_map.map[i].addr);
+- if (curr_pfn >= max_low_pfn)
+- continue;
+- if (curr_pfn < start_pfn)
+- curr_pfn = start_pfn;
+-
+- /*
+- * ... and at the end of the usable range downwards:
+- */
+- last_pfn = PFN_DOWN(boot_mem_map.map[i].addr
++ start = PFN_UP(boot_mem_map.map[i].addr);
++ end = PFN_DOWN(boot_mem_map.map[i].addr
+ + boot_mem_map.map[i].size);
+-
+- if (last_pfn > max_low_pfn)
+- last_pfn = max_low_pfn;
+-
+ /*
+- * Only register lowmem part of lowmem segment with bootmem.
++ * We are rounding up the start address of usable memory
++ * and at the end of the usable range downwards.
+ */
+- size = last_pfn - curr_pfn;
+- if (curr_pfn > PFN_DOWN(HIGHMEM_START))
+- continue;
+- if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START))
+- size = PFN_DOWN(HIGHMEM_START) - curr_pfn;
+- if (!size)
++ if (start >= max_low_pfn)
+ continue;
++ if (start < reserved_end)
++ start = reserved_end;
++ if (end > max_low_pfn)
++ end = max_low_pfn;
+
+ /*
+- * ... finally, did all the rounding and playing
+- * around just make the area go away?
++ * ... finally, is the area going away?
+ */
+- if (last_pfn <= curr_pfn)
++ if (end <= start)
+ continue;
++ size = end - start;
+
+ /* Register lowmem ranges */
+- free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
+- memory_present(0, curr_pfn, curr_pfn + size - 1);
++ free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
++ memory_present(0, start, end);
+ }
+
+- /* Reserve the bootmap memory. */
+- reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size);
+-#endif /* CONFIG_SGI_IP27 */
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+- initrd_below_start_ok = 1;
+- if (initrd_start) {
+- unsigned long initrd_size = ((unsigned char *)initrd_end) -
+- ((unsigned char *)initrd_start);
+- const int width = sizeof(long) * 2;
+-
+- printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
+- (void *)initrd_start, initrd_size);
+-
+- if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
+- printk("initrd extends beyond end of memory "
+- "(0x%0*Lx > 0x%0*Lx)\ndisabling initrd\n",
+- width,
+- (unsigned long long) CPHYSADDR(initrd_end),
+- width,
+- (unsigned long long) PFN_PHYS(max_low_pfn));
+- initrd_start = initrd_end = 0;
+- initrd_reserve_bootmem = 0;
+- }
++ /*
++ * Reserve the bootmap memory.
++ */
++ reserve_bootmem(PFN_PHYS(mapstart), bootmap_size);
+
+- if (initrd_reserve_bootmem)
+- reserve_bootmem(CPHYSADDR(initrd_start), initrd_size);
+- }
+-#endif /* CONFIG_BLK_DEV_INITRD */
++ /*
++ * Reserve initrd memory if needed.
++ */
++ finalize_initrd();
+ }
+
++#endif /* CONFIG_SGI_IP27 */
++
+ /*
+ * arch_mem_init - initialize memory managment subsystem
+ *
+ * o plat_mem_setup() detects the memory configuration and will record detected
+ * memory areas using add_memory_region.
+- * o parse_cmdline_early() parses the command line for mem= options which,
+- * iff detected, will override the results of the automatic detection.
+ *
+ * At this stage the memory configuration of the system is known to the
+ * kernel but generic memory managment system is still entirely uninitialized.
+@@ -465,25 +373,59 @@ static inline void bootmem_init(void)
+ * initialization hook for anything else was introduced.
+ */
+
+-extern void plat_mem_setup(void);
++static int usermem __initdata = 0;
++
++static int __init early_parse_mem(char *p)
++{
++ unsigned long start, size;
++
++ /*
++ * If a user specifies memory size, we
++ * blow away any automatically generated
++ * size.
++ */
++ if (usermem == 0) {
++ boot_mem_map.nr_map = 0;
++ usermem = 1;
++ }
++ start = 0;
++ size = memparse(p, &p);
++ if (*p == '@')
++ start = memparse(p + 1, &p);
++
++ add_memory_region(start, size, BOOT_MEM_RAM);
++ return 0;
++}
++early_param("mem", early_parse_mem);
+
+ static void __init arch_mem_init(char **cmdline_p)
+ {
++ extern void plat_mem_setup(void);
++
+ /* call board setup routine */
+ plat_mem_setup();
+
++ printk("Determined physical RAM map:\n");
++ print_memory_map();
++
+ strlcpy(command_line, arcs_cmdline, sizeof(command_line));
+ strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+
+ *cmdline_p = command_line;
+
+- parse_cmdline_early();
++ parse_early_param();
++
++ if (usermem) {
++ printk("User-defined physical RAM map:\n");
++ print_memory_map();
++ }
++
+ bootmem_init();
+ sparse_init();
+ paging_init();
+ }
+
+-static inline void resource_init(void)
++static void __init resource_init(void)
+ {
+ int i;
+
+@@ -504,10 +446,10 @@ static inline void resource_init(void)
+
+ start = boot_mem_map.map[i].addr;
+ end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
+- if (start >= MAXMEM)
++ if (start >= HIGHMEM_START)
+ continue;
+- if (end >= MAXMEM)
+- end = MAXMEM - 1;
++ if (end >= HIGHMEM_START)
++ end = HIGHMEM_START - 1;
+
+ res = alloc_bootmem(sizeof(struct resource));
+ switch (boot_mem_map.map[i].type) {
+@@ -536,9 +478,6 @@ static inline void resource_init(void)
+ }
+ }
+
+-#undef MAXMEM
+-#undef MAXMEM_PFN
+-
+ void __init setup_arch(char **cmdline_p)
+ {
+ cpu_probe();
+diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
+index 6b4d9be..b9d358e 100644
+--- a/arch/mips/kernel/signal.c
++++ b/arch/mips/kernel/signal.c
+@@ -424,15 +424,11 @@ void do_signal(struct pt_regs *regs)
+ if (!user_mode(regs))
+ return;
+
+- if (try_to_freeze())
+- goto no_signal;
+-
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
+ oldset = ¤t->blocked;
+
+-
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+@@ -446,9 +442,10 @@ void do_signal(struct pt_regs *regs)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
++
++ return;
+ }
+
+-no_signal:
+ /*
+ * Who's code doesn't conform to the restartable syscall convention
+ * dies here!!! The li instruction, a single machine instruction,
+@@ -466,6 +463,7 @@ no_signal:
+ regs->regs[7] = regs->regs[26];
+ regs->cp0_epc -= 4;
+ }
++ regs->regs[0] = 0; /* Don't deal with this again. */
+ }
+
+ /*
+diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
+index f32a229..c86a5dd 100644
+--- a/arch/mips/kernel/signal32.c
++++ b/arch/mips/kernel/signal32.c
+@@ -815,9 +815,6 @@ void do_signal32(struct pt_regs *regs)
+ if (!user_mode(regs))
+ return;
+
+- if (try_to_freeze())
+- goto no_signal;
+-
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
+@@ -836,9 +833,10 @@ void do_signal32(struct pt_regs *regs)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
++
++ return;
+ }
+
+-no_signal:
+ /*
+ * Who's code doesn't conform to the restartable syscall convention
+ * dies here!!! The li instruction, a single machine instruction,
+@@ -856,6 +854,7 @@ no_signal:
+ regs->regs[7] = regs->regs[26];
+ regs->cp0_epc -= 4;
+ }
++ regs->regs[0] = 0; /* Don't deal with this again. */
+ }
+
+ /*
+diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
+index 93429a4..2ac19a6 100644
+--- a/arch/mips/kernel/smp-mt.c
++++ b/arch/mips/kernel/smp-mt.c
+@@ -106,22 +106,22 @@ void __init sanitize_tlb_entries(void)
+ clear_c0_mvpcontrol(MVPCONTROL_VPC);
+ }
+
+-static void ipi_resched_dispatch (struct pt_regs *regs)
++static void ipi_resched_dispatch(void)
+ {
+- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ, regs);
++ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
+ }
+
+-static void ipi_call_dispatch (struct pt_regs *regs)
++static void ipi_call_dispatch(void)
+ {
+- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ, regs);
++ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ);
+ }
+
+-irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
+ {
+ return IRQ_HANDLED;
+ }
+
+-irqreturn_t ipi_call_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
+ {
+ smp_call_function_interrupt();
+
+@@ -140,15 +140,90 @@ static struct irqaction irq_call = {
+ .name = "IPI_call"
+ };
+
++static void __init smp_copy_vpe_config(void)
++{
++ write_vpe_c0_status(
++ (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
++
++ /* set config to be the same as vpe0, particularly kseg0 coherency alg */
++ write_vpe_c0_config( read_c0_config());
++
++ /* make sure there are no software interrupts pending */
++ write_vpe_c0_cause(0);
++
++ /* Propagate Config7 */
++ write_vpe_c0_config7(read_c0_config7());
++
++ write_vpe_c0_count(read_c0_count());
++}
++
++static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
++ unsigned int ncpu)
++{
++ if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
++ return ncpu;
++
++ /* Deactivate all but VPE 0 */
++ if (tc != 0) {
++ unsigned long tmp = read_vpe_c0_vpeconf0();
++
++ tmp &= ~VPECONF0_VPA;
++
++ /* master VPE */
++ tmp |= VPECONF0_MVP;
++ write_vpe_c0_vpeconf0(tmp);
++
++ /* Record this as available CPU */
++ cpu_set(tc, phys_cpu_present_map);
++ __cpu_number_map[tc] = ++ncpu;
++ __cpu_logical_map[ncpu] = tc;
++ }
++
++ /* Disable multi-threading with TC's */
++ write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
++
++ if (tc != 0)
++ smp_copy_vpe_config();
++
++ return ncpu;
++}
++
++static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0)
++{
++ unsigned long tmp;
++
++ if (!tc)
++ return;
++
++ /* bind a TC to each VPE, May as well put all excess TC's
++ on the last VPE */
++ if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1))
++ write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT));
++ else {
++ write_tc_c0_tcbind(read_tc_c0_tcbind() | tc);
++
++ /* and set XTC */
++ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT));
++ }
++
++ tmp = read_tc_c0_tcstatus();
++
++ /* mark not allocated and not dynamically allocatable */
++ tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
++ tmp |= TCSTATUS_IXMT; /* interrupt exempt */
++ write_tc_c0_tcstatus(tmp);
++
++ write_tc_c0_tchalt(TCHALT_H);
++}
++
+ /*
+ * Common setup before any secondaries are started
+ * Make sure all CPU's are in a sensible state before we boot any of the
+ * secondarys
+ */
+-void plat_smp_setup(void)
++void __init plat_smp_setup(void)
+ {
+- unsigned long val;
+- int i, num;
++ unsigned int mvpconf0, ntc, tc, ncpu = 0;
+
+ #ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+@@ -167,75 +242,16 @@ void plat_smp_setup(void)
+ /* Put MVPE's into 'configuration state' */
+ set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+- val = read_c0_mvpconf0();
++ mvpconf0 = read_c0_mvpconf0();
++ ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT;
+
+ /* we'll always have more TC's than VPE's, so loop setting everything
+ to a sensible state */
+- for (i = 0, num = 0; i <= ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT); i++) {
+- settc(i);
+-
+- /* VPE's */
+- if (i <= ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) {
+-
+- /* deactivate all but vpe0 */
+- if (i != 0) {
+- unsigned long tmp = read_vpe_c0_vpeconf0();
+-
+- tmp &= ~VPECONF0_VPA;
+-
+- /* master VPE */
+- tmp |= VPECONF0_MVP;
+- write_vpe_c0_vpeconf0(tmp);
+-
+- /* Record this as available CPU */
+- cpu_set(i, phys_cpu_present_map);
+- __cpu_number_map[i] = ++num;
+- __cpu_logical_map[num] = i;
+- }
+-
+- /* disable multi-threading with TC's */
+- write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
+-
+- if (i != 0) {
+- write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
++ for (tc = 0; tc <= ntc; tc++) {
++ settc(tc);
+
+- /* set config to be the same as vpe0, particularly kseg0 coherency alg */
+- write_vpe_c0_config( read_c0_config());
+-
+- /* make sure there are no software interrupts pending */
+- write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0));
+-
+- /* Propagate Config7 */
+- write_vpe_c0_config7(read_c0_config7());
+- }
+-
+- }
+-
+- /* TC's */
+-
+- if (i != 0) {
+- unsigned long tmp;
+-
+- /* bind a TC to each VPE, May as well put all excess TC's
+- on the last VPE */
+- if ( i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1) )
+- write_tc_c0_tcbind(read_tc_c0_tcbind() | ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) );
+- else {
+- write_tc_c0_tcbind( read_tc_c0_tcbind() | i);
+-
+- /* and set XTC */
+- write_vpe_c0_vpeconf0( read_vpe_c0_vpeconf0() | (i << VPECONF0_XTC_SHIFT));
+- }
+-
+- tmp = read_tc_c0_tcstatus();
+-
+- /* mark not allocated and not dynamically allocatable */
+- tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
+- tmp |= TCSTATUS_IXMT; /* interrupt exempt */
+- write_tc_c0_tcstatus(tmp);
+-
+- write_tc_c0_tchalt(TCHALT_H);
+- }
++ smp_tc_init(tc, mvpconf0);
++ ncpu = smp_vpe_init(tc, mvpconf0, ncpu);
+ }
+
+ /* Release config state */
+@@ -243,15 +259,15 @@ void plat_smp_setup(void)
+
+ /* We'll wait until starting the secondaries before starting MVPE */
+
+- printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
++ printk(KERN_INFO "Detected %i available secondary CPU(s)\n", ncpu);
+ }
+
+ void __init plat_prepare_cpus(unsigned int max_cpus)
+ {
+ /* set up ipi interrupts */
+ if (cpu_has_vint) {
+- set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
+- set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
++ set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
++ set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
+ }
+
+ cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
+diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
+index 2218958..db80957 100644
+--- a/arch/mips/kernel/smp.c
++++ b/arch/mips/kernel/smp.c
+@@ -310,7 +310,7 @@ static void flush_tlb_all_ipi(void *info
+
+ void flush_tlb_all(void)
+ {
+- on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
++ on_each_cpu(flush_tlb_all_ipi, NULL, 1, 1);
+ }
+
+ static void flush_tlb_mm_ipi(void *mm)
+@@ -467,14 +467,18 @@ static DEFINE_PER_CPU(struct cpu, cpu_de
+
+ static int __init topology_init(void)
+ {
+- int cpu;
+- int ret;
++ int i, ret;
+
+- for_each_present_cpu(cpu) {
+- ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
++#ifdef CONFIG_NUMA
++ for_each_online_node(i)
++ register_one_node(i);
++#endif /* CONFIG_NUMA */
++
++ for_each_present_cpu(i) {
++ ret = register_cpu(&per_cpu(cpu_devices, i), i);
+ if (ret)
+ printk(KERN_WARNING "topology_init: register_cpu %d "
+- "failed (%d)\n", cpu, ret);
++ "failed (%d)\n", i, ret);
+ }
+
+ return 0;
+diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S
+index 4cc3dea..921207c 100644
+--- a/arch/mips/kernel/smtc-asm.S
++++ b/arch/mips/kernel/smtc-asm.S
+@@ -8,7 +8,7 @@
+ #include <asm/regdef.h>
+ #include <asm/asmmacro.h>
+ #include <asm/stackframe.h>
+-#include <asm/stackframe.h>
++#include <asm/irqflags.h>
+
+ /*
+ * "Software Interrupt" linkage.
+@@ -97,15 +97,14 @@ FEXPORT(__smtc_ipi_vector)
+ SAVE_ALL
+ CLI
+ TRACE_IRQS_OFF
+- move a0,sp
+ /* Function to be invoked passed stack pad slot 5 */
+ lw t0,PT_PADSLOT5(sp)
+ /* Argument from sender passed in stack pad slot 4 */
+- lw a1,PT_PADSLOT4(sp)
+- jalr t0
+- nop
+- j ret_from_irq
+- nop
++ lw a0,PT_PADSLOT4(sp)
++ LONG_L s0, TI_REGS($28)
++ LONG_S sp, TI_REGS($28)
++ PTR_LA ra, ret_from_irq
++ jr t0
+
+ /*
+ * Called from idle loop to provoke processing of queued IPIs
+@@ -122,7 +121,10 @@ LEAF(self_ipi)
+ subu t1,sp,PT_SIZE
+ sw ra,PT_EPC(t1)
+ sw a0,PT_PADSLOT4(t1)
++ LONG_L s0, TI_REGS($28)
++ LONG_S sp, TI_REGS($28)
+ la t2,ipi_decode
++ LONG_S s0, TI_REGS($28)
+ sw t2,PT_PADSLOT5(t1)
+ /* Save pre-disable value of TCStatus */
+ sw t0,PT_TCSTATUS(t1)
+diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
+index 604bcc5..3b78caf 100644
+--- a/arch/mips/kernel/smtc.c
++++ b/arch/mips/kernel/smtc.c
+@@ -82,7 +82,7 @@ struct smtc_ipi_q freeIPIq;
+
+ /* Forward declarations */
+
+-void ipi_decode(struct pt_regs *, struct smtc_ipi *);
++void ipi_decode(struct smtc_ipi *);
+ void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
+ void setup_cross_vpe_interrupts(void);
+ void init_smtc_stats(void);
+@@ -476,6 +476,7 @@ void mipsmt_prepare_cpus(void)
+ write_vpe_c0_compare(0);
+ /* Propagate Config7 */
+ write_vpe_c0_config7(read_c0_config7());
++ write_vpe_c0_count(read_c0_count());
+ }
+ /* enable multi-threading within VPE */
+ write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() | VPECONTROL_TE);
+@@ -820,19 +821,19 @@ void post_direct_ipi(int cpu, struct smt
+ write_tc_c0_tcrestart(__smtc_ipi_vector);
+ }
+
+-void ipi_resched_interrupt(struct pt_regs *regs)
++static void ipi_resched_interrupt(void)
+ {
+ /* Return from interrupt should be enough to cause scheduler check */
+ }
+
+
+-void ipi_call_interrupt(struct pt_regs *regs)
++static void ipi_call_interrupt(void)
+ {
+ /* Invoke generic function invocation code in smp.c */
+ smp_call_function_interrupt();
+ }
+
+-void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi)
++void ipi_decode(struct smtc_ipi *pipi)
+ {
+ void *arg_copy = pipi->arg;
+ int type_copy = pipi->type;
+@@ -846,15 +847,15 @@ void ipi_decode(struct pt_regs *regs, st
+ #ifdef SMTC_IDLE_HOOK_DEBUG
+ clock_hang_reported[dest_copy] = 0;
+ #endif /* SMTC_IDLE_HOOK_DEBUG */
+- local_timer_interrupt(0, NULL, regs);
++ local_timer_interrupt(0, NULL);
+ break;
+ case LINUX_SMP_IPI:
+ switch ((int)arg_copy) {
+ case SMP_RESCHEDULE_YOURSELF:
+- ipi_resched_interrupt(regs);
++ ipi_resched_interrupt();
+ break;
+ case SMP_CALL_FUNCTION:
+- ipi_call_interrupt(regs);
++ ipi_call_interrupt();
+ break;
+ default:
+ printk("Impossible SMTC IPI Argument 0x%x\n",
+@@ -868,7 +869,7 @@ void ipi_decode(struct pt_regs *regs, st
+ }
+ }
+
+-void deferred_smtc_ipi(struct pt_regs *regs)
++void deferred_smtc_ipi(void)
+ {
+ struct smtc_ipi *pipi;
+ unsigned long flags;
+@@ -883,7 +884,7 @@ void deferred_smtc_ipi(struct pt_regs *r
+ while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) {
+ /* ipi_decode() should be called with interrupts off */
+ local_irq_save(flags);
+- ipi_decode(regs, pipi);
++ ipi_decode(pipi);
+ local_irq_restore(flags);
+ }
+ }
+@@ -917,7 +918,7 @@ void smtc_timer_broadcast(int vpe)
+
+ static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
+
+-static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs)
++static irqreturn_t ipi_interrupt(int irq, void *dev_idm)
+ {
+ int my_vpe = cpu_data[smp_processor_id()].vpe_id;
+ int my_tc = cpu_data[smp_processor_id()].tc_id;
+@@ -978,7 +979,7 @@ static irqreturn_t ipi_interrupt(int irq
+ * with interrupts off
+ */
+ local_irq_save(flags);
+- ipi_decode(regs, pipi);
++ ipi_decode(pipi);
+ local_irq_restore(flags);
+ }
+ }
+@@ -987,9 +988,9 @@ static irqreturn_t ipi_interrupt(int irq
+ return IRQ_HANDLED;
+ }
+
+-static void ipi_irq_dispatch(struct pt_regs *regs)
++static void ipi_irq_dispatch(void)
+ {
+- do_IRQ(cpu_ipi_irq, regs);
++ do_IRQ(cpu_ipi_irq);
+ }
+
+ static struct irqaction irq_ipi;
+diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
+new file mode 100644
+index 0000000..a586aba
+--- /dev/null
++++ b/arch/mips/kernel/stacktrace.c
+@@ -0,0 +1,85 @@
++/*
++ * arch/mips/kernel/stacktrace.c
++ *
++ * Stack trace management functions
++ *
++ * Copyright (C) 2006 Atsushi Nemoto <anemo at mba.ocn.ne.jp>
++ */
++#include <linux/sched.h>
++#include <linux/stacktrace.h>
++#include <asm/stacktrace.h>
++
++/*
++ * Save stack-backtrace addresses into a stack_trace buffer:
++ */
++static void save_raw_context_stack(struct stack_trace *trace,
++ unsigned long reg29)
++{
++ unsigned long *sp = (unsigned long *)reg29;
++ unsigned long addr;
++
++ while (!kstack_end(sp)) {
++ addr = *sp++;
++ if (__kernel_text_address(addr)) {
++ if (trace->skip > 0)
++ trace->skip--;
++ else
++ trace->entries[trace->nr_entries++] = addr;
++ if (trace->nr_entries >= trace->max_entries)
++ break;
++ }
++ }
++}
++
++static void save_context_stack(struct stack_trace *trace,
++ struct task_struct *task, struct pt_regs *regs)
++{
++ unsigned long sp = regs->regs[29];
++#ifdef CONFIG_KALLSYMS
++ unsigned long ra = regs->regs[31];
++ unsigned long pc = regs->cp0_epc;
++
++ if (raw_show_trace || !__kernel_text_address(pc)) {
++ unsigned long stack_page =
++ (unsigned long)task_stack_page(task);
++ if (stack_page && sp >= stack_page &&
++ sp <= stack_page + THREAD_SIZE - 32)
++ save_raw_context_stack(trace, sp);
++ return;
++ }
++ do {
++ if (trace->skip > 0)
++ trace->skip--;
++ else
++ trace->entries[trace->nr_entries++] = pc;
++ if (trace->nr_entries >= trace->max_entries)
++ break;
++ pc = unwind_stack(task, &sp, pc, &ra);
++ } while (pc);
++#else
++ save_raw_context_stack(trace, sp);
++#endif
++}
++
++/*
++ * Save stack-backtrace addresses into a stack_trace buffer.
++ */
++void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
++{
++ struct pt_regs dummyregs;
++ struct pt_regs *regs = &dummyregs;
++
++ WARN_ON(trace->nr_entries || !trace->max_entries);
++
++ if (task && task != current) {
++ regs->regs[29] = task->thread.reg29;
++ regs->regs[31] = 0;
++ regs->cp0_epc = task->thread.reg31;
++ } else {
++ if (!task)
++ task = current;
++ prepare_frametrace(regs);
++ }
++
++ save_context_stack(trace, task, regs);
++}
+diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
+index 0721314..26e1a7e 100644
+--- a/arch/mips/kernel/syscall.c
++++ b/arch/mips/kernel/syscall.c
+@@ -231,7 +231,7 @@ out:
+ */
+ asmlinkage int sys_uname(struct old_utsname __user * name)
+ {
+- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
++ if (name && !copy_to_user(name, utsname(), sizeof (*name)))
+ return 0;
+ return -EFAULT;
+ }
+@@ -248,22 +248,27 @@ asmlinkage int sys_olduname(struct oldol
+ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+ return -EFAULT;
+
+- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+- error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+- error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+- error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+- error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+- error -= __put_user(0,name->release+__OLD_UTS_LEN);
+- error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+- error -= __put_user(0,name->version+__OLD_UTS_LEN);
+- error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+- error = __put_user(0,name->machine+__OLD_UTS_LEN);
++ error = __copy_to_user(&name->sysname, &utsname()->sysname,
++ __OLD_UTS_LEN);
++ error -= __put_user(0, name->sysname + __OLD_UTS_LEN);
++ error -= __copy_to_user(&name->nodename, &utsname()->nodename,
++ __OLD_UTS_LEN);
++ error -= __put_user(0, name->nodename + __OLD_UTS_LEN);
++ error -= __copy_to_user(&name->release, &utsname()->release,
++ __OLD_UTS_LEN);
++ error -= __put_user(0, name->release + __OLD_UTS_LEN);
++ error -= __copy_to_user(&name->version, &utsname()->version,
++ __OLD_UTS_LEN);
++ error -= __put_user(0, name->version + __OLD_UTS_LEN);
++ error -= __copy_to_user(&name->machine, &utsname()->machine,
++ __OLD_UTS_LEN);
++ error = __put_user(0, name->machine + __OLD_UTS_LEN);
+ error = error ? -EFAULT : 0;
+
+ return error;
+ }
+
+-void sys_set_thread_area(unsigned long addr)
++asmlinkage int sys_set_thread_area(unsigned long addr)
+ {
+ struct thread_info *ti = task_thread_info(current);
+
+@@ -271,6 +276,8 @@ void sys_set_thread_area(unsigned long a
+
+ /* If some future MIPS implementation has this register in hardware,
+ * we will need to update it here (and in context switches). */
++
++ return 0;
+ }
+
+ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
+@@ -399,3 +406,32 @@ asmlinkage void bad_stack(void)
+ {
+ do_exit(SIGSEGV);
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register unsigned long __a0 asm("$4") = (unsigned long) filename;
++ register unsigned long __a1 asm("$5") = (unsigned long) argv;
++ register unsigned long __a2 asm("$6") = (unsigned long) envp;
++ register unsigned long __a3 asm("$7");
++ unsigned long __v0;
++
++ __asm__ volatile (" \n"
++ " .set noreorder \n"
++ " li $2, %5 # __NR_execve \n"
++ " syscall \n"
++ " move %0, $2 \n"
++ " .set reorder \n"
++ : "=&r" (__v0), "=r" (__a3)
++ : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
++ : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
++ "memory");
++
++ if (__a3 == 0)
++ return __v0;
++
++ return -__v0;
++}
+diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
+index 1137dd6..93c74fe 100644
+--- a/arch/mips/kernel/sysirix.c
++++ b/arch/mips/kernel/sysirix.c
+@@ -884,7 +884,7 @@ asmlinkage int irix_getdomainname(char _
+ down_read(&uts_sem);
+ if (len > __NEW_UTS_LEN)
+ len = __NEW_UTS_LEN;
+- err = copy_to_user(name, system_utsname.domainname, len) ? -EFAULT : 0;
++ err = copy_to_user(name, utsname()->domainname, len) ? -EFAULT : 0;
+ up_read(&uts_sem);
+
+ return err;
+@@ -1127,11 +1127,11 @@ struct iuname {
+ asmlinkage int irix_uname(struct iuname __user *buf)
+ {
+ down_read(&uts_sem);
+- if (copy_from_user(system_utsname.sysname, buf->sysname, 65)
+- || copy_from_user(system_utsname.nodename, buf->nodename, 65)
+- || copy_from_user(system_utsname.release, buf->release, 65)
+- || copy_from_user(system_utsname.version, buf->version, 65)
+- || copy_from_user(system_utsname.machine, buf->machine, 65)) {
++ if (copy_from_user(utsname()->sysname, buf->sysname, 65)
++ || copy_from_user(utsname()->nodename, buf->nodename, 65)
++ || copy_from_user(utsname()->release, buf->release, 65)
++ || copy_from_user(utsname()->version, buf->version, 65)
++ || copy_from_user(utsname()->machine, buf->machine, 65)) {
+ return -EFAULT;
+ }
+ up_read(&uts_sem);
+@@ -1739,12 +1739,13 @@ struct irix_dirent32_callback {
+ #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
+
+ static int irix_filldir32(void *__buf, const char *name,
+- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
++ int namlen, loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct irix_dirent32 __user *dirent;
+ struct irix_dirent32_callback *buf = __buf;
+ unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
+ int err = 0;
++ u32 d_ino;
+
+ #ifdef DEBUG_GETDENTS
+ printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
+@@ -1753,12 +1754,15 @@ static int irix_filldir32(void *__buf, c
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent)
+ err = __put_user(offset, &dirent->d_off);
+ dirent = buf->current_dir;
+ err |= __put_user(dirent, &buf->previous);
+- err |= __put_user(ino, &dirent->d_ino);
++ err |= __put_user(d_ino, &dirent->d_ino);
+ err |= __put_user(reclen, &dirent->d_reclen);
+ err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0;
+ err |= __put_user(0, &dirent->d_name[namlen]);
+@@ -1837,7 +1841,7 @@ struct irix_dirent64_callback {
+ #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+ static int irix_filldir64(void *__buf, const char *name,
+- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
++ int namlen, loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct irix_dirent64 __user *dirent;
+ struct irix_dirent64_callback * buf = __buf;
+diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
+index 170cb67..e535f86 100644
+--- a/arch/mips/kernel/time.c
++++ b/arch/mips/kernel/time.c
+@@ -11,6 +11,7 @@
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
++#include <linux/clocksource.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -47,8 +48,6 @@
+ /*
+ * forward reference
+ */
+-extern volatile unsigned long wall_jiffies;
+-
+ DEFINE_SPINLOCK(rtc_lock);
+
+ /*
+@@ -69,15 +68,9 @@ int (*rtc_mips_set_time)(unsigned long)
+ int (*rtc_mips_set_mmss)(unsigned long);
+
+
+-/* usecs per counter cycle, shifted to left by 32 bits */
+-static unsigned int sll32_usecs_per_cycle;
+-
+ /* how many counter cycles in a jiffy */
+ static unsigned long cycles_per_jiffy __read_mostly;
+
+-/* Cycle counter value at the previous timer interrupt.. */
+-static unsigned int timerhi, timerlo;
+-
+ /* expirelo is the count value for next CPU timer interrupt */
+ static unsigned int expirelo;
+
+@@ -95,7 +88,7 @@ static unsigned int null_hpt_read(void)
+ return 0;
+ }
+
+-static void null_hpt_init(unsigned int count)
++static void __init null_hpt_init(void)
+ {
+ /* nothing */
+ }
+@@ -130,268 +123,18 @@ static unsigned int c0_hpt_read(void)
+ return read_c0_count();
+ }
+
+-/* For use solely as a high precision timer. */
+-static void c0_hpt_init(unsigned int count)
+-{
+- write_c0_count(read_c0_count() - count);
+-}
+-
+ /* For use both as a high precision timer and an interrupt source. */
+-static void c0_hpt_timer_init(unsigned int count)
++static void __init c0_hpt_timer_init(void)
+ {
+- count = read_c0_count() - count;
+- expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
+- write_c0_count(expirelo - cycles_per_jiffy);
++ expirelo = read_c0_count() + cycles_per_jiffy;
+ write_c0_compare(expirelo);
+- write_c0_count(count);
+ }
+
+ int (*mips_timer_state)(void);
+ void (*mips_timer_ack)(void);
+ unsigned int (*mips_hpt_read)(void);
+-void (*mips_hpt_init)(unsigned int);
+-
+-
+-/*
+- * This version of gettimeofday has microsecond resolution and better than
+- * microsecond precision on fast machines with cycle counter.
+- */
+-void do_gettimeofday(struct timeval *tv)
+-{
+- unsigned long seq;
+- unsigned long lost;
+- unsigned long usec, sec;
+- unsigned long max_ntp_tick;
+-
+- do {
+- seq = read_seqbegin(&xtime_lock);
+-
+- usec = do_gettimeoffset();
+-
+- lost = jiffies - wall_jiffies;
+-
+- /*
+- * If time_adjust is negative then NTP is slowing the clock
+- * so make sure not to go into next possible interval.
+- * Better to lose some accuracy than have time go backwards..
+- */
+- if (unlikely(time_adjust < 0)) {
+- max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;
+- usec = min(usec, max_ntp_tick);
+-
+- if (lost)
+- usec += lost * max_ntp_tick;
+- } else if (unlikely(lost))
+- usec += lost * (USEC_PER_SEC / HZ);
+-
+- sec = xtime.tv_sec;
+- usec += (xtime.tv_nsec / 1000);
+-
+- } while (read_seqretry(&xtime_lock, seq));
+-
+- while (usec >= 1000000) {
+- usec -= 1000000;
+- sec++;
+- }
+-
+- tv->tv_sec = sec;
+- tv->tv_usec = usec;
+-}
+-
+-EXPORT_SYMBOL(do_gettimeofday);
+-
+-int do_settimeofday(struct timespec *tv)
+-{
+- time_t wtm_sec, sec = tv->tv_sec;
+- long wtm_nsec, nsec = tv->tv_nsec;
+-
+- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+- return -EINVAL;
+-
+- write_seqlock_irq(&xtime_lock);
+-
+- /*
+- * This is revolting. We need to set "xtime" correctly. However,
+- * the value in this location is the value at the most recent update
+- * of wall time. Discover what correction gettimeofday() would have
+- * made, and then undo it!
+- */
+- nsec -= do_gettimeoffset() * NSEC_PER_USEC;
+- nsec -= (jiffies - wall_jiffies) * tick_nsec;
+-
+- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+-
+- set_normalized_timespec(&xtime, sec, nsec);
+- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+-
+- ntp_clear();
+- write_sequnlock_irq(&xtime_lock);
+- clock_was_set();
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(do_settimeofday);
+-
+-/*
+- * Gettimeoffset routines. These routines returns the time duration
+- * since last timer interrupt in usecs.
+- *
+- * If the exact CPU counter frequency is known, use fixed_rate_gettimeoffset.
+- * Otherwise use calibrate_gettimeoffset()
+- *
+- * If the CPU does not have the counter register, you can either supply
+- * your own gettimeoffset() routine, or use null_gettimeoffset(), which
+- * gives the same resolution as HZ.
+- */
+-
+-static unsigned long null_gettimeoffset(void)
+-{
+- return 0;
+-}
+-
+-
+-/* The function pointer to one of the gettimeoffset funcs. */
+-unsigned long (*do_gettimeoffset)(void) = null_gettimeoffset;
+-
+-
+-static unsigned long fixed_rate_gettimeoffset(void)
+-{
+- u32 count;
+- unsigned long res;
+-
+- /* Get last timer tick in absolute kernel time */
+- count = mips_hpt_read();
+-
+- /* .. relative to previous jiffy (32 bits is enough) */
+- count -= timerlo;
+-
+- __asm__("multu %1,%2"
+- : "=h" (res)
+- : "r" (count), "r" (sll32_usecs_per_cycle)
+- : "lo", GCC_REG_ACCUM);
+-
+- /*
+- * Due to possible jiffies inconsistencies, we need to check
+- * the result so that we'll get a timer that is monotonic.
+- */
+- if (res >= USECS_PER_JIFFY)
+- res = USECS_PER_JIFFY - 1;
+-
+- return res;
+-}
+-
+-
+-/*
+- * Cached "1/(clocks per usec) * 2^32" value.
+- * It has to be recalculated once each jiffy.
+- */
+-static unsigned long cached_quotient;
+-
+-/* Last jiffy when calibrate_divXX_gettimeoffset() was called. */
+-static unsigned long last_jiffies;
+-
+-/*
+- * This is moved from dec/time.c:do_ioasic_gettimeoffset() by Maciej.
+- */
+-static unsigned long calibrate_div32_gettimeoffset(void)
+-{
+- u32 count;
+- unsigned long res, tmp;
+- unsigned long quotient;
+-
+- tmp = jiffies;
+-
+- quotient = cached_quotient;
+-
+- if (last_jiffies != tmp) {
+- last_jiffies = tmp;
+- if (last_jiffies != 0) {
+- unsigned long r0;
+- do_div64_32(r0, timerhi, timerlo, tmp);
+- do_div64_32(quotient, USECS_PER_JIFFY,
+- USECS_PER_JIFFY_FRAC, r0);
+- cached_quotient = quotient;
+- }
+- }
+-
+- /* Get last timer tick in absolute kernel time */
+- count = mips_hpt_read();
+-
+- /* .. relative to previous jiffy (32 bits is enough) */
+- count -= timerlo;
+-
+- __asm__("multu %1,%2"
+- : "=h" (res)
+- : "r" (count), "r" (quotient)
+- : "lo", GCC_REG_ACCUM);
+-
+- /*
+- * Due to possible jiffies inconsistencies, we need to check
+- * the result so that we'll get a timer that is monotonic.
+- */
+- if (res >= USECS_PER_JIFFY)
+- res = USECS_PER_JIFFY - 1;
+-
+- return res;
+-}
+-
+-static unsigned long calibrate_div64_gettimeoffset(void)
+-{
+- u32 count;
+- unsigned long res, tmp;
+- unsigned long quotient;
+-
+- tmp = jiffies;
+-
+- quotient = cached_quotient;
+-
+- if (last_jiffies != tmp) {
+- last_jiffies = tmp;
+- if (last_jiffies) {
+- unsigned long r0;
+- __asm__(".set push\n\t"
+- ".set mips3\n\t"
+- "lwu %0,%3\n\t"
+- "dsll32 %1,%2,0\n\t"
+- "or %1,%1,%0\n\t"
+- "ddivu $0,%1,%4\n\t"
+- "mflo %1\n\t"
+- "dsll32 %0,%5,0\n\t"
+- "or %0,%0,%6\n\t"
+- "ddivu $0,%0,%1\n\t"
+- "mflo %0\n\t"
+- ".set pop"
+- : "=&r" (quotient), "=&r" (r0)
+- : "r" (timerhi), "m" (timerlo),
+- "r" (tmp), "r" (USECS_PER_JIFFY),
+- "r" (USECS_PER_JIFFY_FRAC)
+- : "hi", "lo", GCC_REG_ACCUM);
+- cached_quotient = quotient;
+- }
+- }
+-
+- /* Get last timer tick in absolute kernel time */
+- count = mips_hpt_read();
+-
+- /* .. relative to previous jiffy (32 bits is enough) */
+- count -= timerlo;
+-
+- __asm__("multu %1,%2"
+- : "=h" (res)
+- : "r" (count), "r" (quotient)
+- : "lo", GCC_REG_ACCUM);
+-
+- /*
+- * Due to possible jiffies inconsistencies, we need to check
+- * the result so that we'll get a timer that is monotonic.
+- */
+- if (res >= USECS_PER_JIFFY)
+- res = USECS_PER_JIFFY - 1;
+-
+- return res;
+-}
+-
++void (*mips_hpt_init)(void) __initdata = null_hpt_init;
++unsigned int mips_hpt_mask = 0xffffffff;
+
+ /* last time when xtime and rtc are sync'ed up */
+ static long last_rtc_update;
+@@ -406,35 +149,26 @@ static long last_rtc_update;
+ * a broadcasted inter-processor interrupt which itself is triggered
+ * by the global timer interrupt.
+ */
+-void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++void local_timer_interrupt(int irq, void *dev_id)
+ {
+- if (current->pid)
+- profile_tick(CPU_PROFILING, regs);
+- update_process_times(user_mode(regs));
++ profile_tick(CPU_PROFILING);
++ update_process_times(user_mode(get_irq_regs()));
+ }
+
+ /*
+ * High-level timer interrupt service routines. This function
+ * is set as irqaction->handler and is invoked through do_IRQ.
+ */
+-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t timer_interrupt(int irq, void *dev_id)
+ {
+- unsigned long j;
+- unsigned int count;
+-
+ write_seqlock(&xtime_lock);
+
+- count = mips_hpt_read();
+ mips_timer_ack();
+
+- /* Update timerhi/timerlo for intra-jiffy calibration. */
+- timerhi += count < timerlo; /* Wrap around */
+- timerlo = count;
+-
+ /*
+ * call the generic timer interrupt handling
+ */
+- do_timer(regs);
++ do_timer(1);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+@@ -453,47 +187,6 @@ irqreturn_t timer_interrupt(int irq, voi
+ }
+ }
+
+- /*
+- * If jiffies has overflown in this timer_interrupt, we must
+- * update the timer[hi]/[lo] to make fast gettimeoffset funcs
+- * quotient calc still valid. -arca
+- *
+- * The first timer interrupt comes late as interrupts are
+- * enabled long after timers are initialized. Therefore the
+- * high precision timer is fast, leading to wrong gettimeoffset()
+- * calculations. We deal with it by setting it based on the
+- * number of its ticks between the second and the third interrupt.
+- * That is still somewhat imprecise, but it's a good estimate.
+- * --macro
+- */
+- j = jiffies;
+- if (j < 4) {
+- static unsigned int prev_count;
+- static int hpt_initialized;
+-
+- switch (j) {
+- case 0:
+- timerhi = timerlo = 0;
+- mips_hpt_init(count);
+- break;
+- case 2:
+- prev_count = count;
+- break;
+- case 3:
+- if (!hpt_initialized) {
+- unsigned int c3 = 3 * (count - prev_count);
+-
+- timerhi = 0;
+- timerlo = c3;
+- mips_hpt_init(count - c3);
+- hpt_initialized = 1;
+- }
+- break;
+- default:
+- break;
+- }
+- }
+-
+ write_sequnlock(&xtime_lock);
+
+ /*
+@@ -503,22 +196,22 @@ irqreturn_t timer_interrupt(int irq, voi
+ * In SMP mode, local_timer_interrupt() is invoked by appropriate
+ * low-level local timer interrupt handler.
+ */
+- local_timer_interrupt(irq, dev_id, regs);
++ local_timer_interrupt(irq, dev_id);
+
+ return IRQ_HANDLED;
+ }
+
+-int null_perf_irq(struct pt_regs *regs)
++int null_perf_irq(void)
+ {
+ return 0;
+ }
+
+-int (*perf_irq)(struct pt_regs *regs) = null_perf_irq;
++int (*perf_irq)(void) = null_perf_irq;
+
+ EXPORT_SYMBOL(null_perf_irq);
+ EXPORT_SYMBOL(perf_irq);
+
+-asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs)
++asmlinkage void ll_timer_interrupt(int irq)
+ {
+ int r2 = cpu_has_mips_r2;
+
+@@ -532,25 +225,25 @@ asmlinkage void ll_timer_interrupt(int i
+ * performance counter interrupt handler anyway.
+ */
+ if (!r2 || (read_c0_cause() & (1 << 26)))
+- if (perf_irq(regs))
++ if (perf_irq())
+ goto out;
+
+ /* we keep interrupt disabled all the time */
+ if (!r2 || (read_c0_cause() & (1 << 30)))
+- timer_interrupt(irq, NULL, regs);
++ timer_interrupt(irq, NULL);
+
+ out:
+ irq_exit();
+ }
+
+-asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs)
++asmlinkage void ll_local_timer_interrupt(int irq)
+ {
+ irq_enter();
+ if (smp_processor_id() != 0)
+ kstat_this_cpu.irqs[irq]++;
+
+ /* we keep interrupt disabled all the time */
+- local_timer_interrupt(irq, NULL, regs);
++ local_timer_interrupt(irq, NULL);
+
+ irq_exit();
+ }
+@@ -561,12 +254,11 @@ asmlinkage void ll_local_timer_interrupt
+ * 1) board_time_init() -
+ * a) (optional) set up RTC routines,
+ * b) (optional) calibrate and set the mips_hpt_frequency
+- * (only needed if you intended to use fixed_rate_gettimeoffset
+- * or use cpu counter as timer interrupt source)
++ * (only needed if you intended to use cpu counter as timer interrupt
++ * source)
+ * 2) setup xtime based on rtc_mips_get_time().
+- * 3) choose a appropriate gettimeoffset routine.
+- * 4) calculate a couple of cached variables for later usage
+- * 5) plat_timer_setup() -
++ * 3) calculate a couple of cached variables for later usage
++ * 4) plat_timer_setup() -
+ * a) (optional) over-write any choices made above by time_init().
+ * b) machine specific code should setup the timer irqaction.
+ * c) enable the timer interrupt
+@@ -618,13 +310,48 @@ static unsigned int __init calibrate_hpt
+ } while (--i);
+ hpt_end = mips_hpt_read();
+
+- hpt_count = hpt_end - hpt_start;
++ hpt_count = (hpt_end - hpt_start) & mips_hpt_mask;
+ hz = HZ;
+ frequency = (u64)hpt_count * (u64)hz;
+
+ return frequency >> log_2_loops;
+ }
+
++static cycle_t read_mips_hpt(void)
++{
++ return (cycle_t)mips_hpt_read();
++}
++
++static struct clocksource clocksource_mips = {
++ .name = "MIPS",
++ .read = read_mips_hpt,
++ .is_continuous = 1,
++};
++
++static void __init init_mips_clocksource(void)
++{
++ u64 temp;
++ u32 shift;
++
++ if (!mips_hpt_frequency || mips_hpt_read == null_hpt_read)
++ return;
++
++ /* Calclate a somewhat reasonable rating value */
++ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
++ /* Find a shift value */
++ for (shift = 32; shift > 0; shift--) {
++ temp = (u64) NSEC_PER_SEC << shift;
++ do_div(temp, mips_hpt_frequency);
++ if ((temp >> 32) == 0)
++ break;
++ }
++ clocksource_mips.shift = shift;
++ clocksource_mips.mult = (u32)temp;
++ clocksource_mips.mask = mips_hpt_mask;
++
++ clocksource_register(&clocksource_mips);
++}
++
+ void __init time_init(void)
+ {
+ if (board_time_init)
+@@ -640,41 +367,21 @@ void __init time_init(void)
+ -xtime.tv_sec, -xtime.tv_nsec);
+
+ /* Choose appropriate high precision timer routines. */
+- if (!cpu_has_counter && !mips_hpt_read) {
++ if (!cpu_has_counter && !mips_hpt_read)
+ /* No high precision timer -- sorry. */
+ mips_hpt_read = null_hpt_read;
+- mips_hpt_init = null_hpt_init;
+- } else if (!mips_hpt_frequency && !mips_timer_state) {
++ else if (!mips_hpt_frequency && !mips_timer_state) {
+ /* A high precision timer of unknown frequency. */
+- if (!mips_hpt_read) {
++ if (!mips_hpt_read)
+ /* No external high precision timer -- use R4k. */
+ mips_hpt_read = c0_hpt_read;
+- mips_hpt_init = c0_hpt_init;
+- }
+-
+- if (cpu_has_mips32r1 || cpu_has_mips32r2 ||
+- (current_cpu_data.isa_level == MIPS_CPU_ISA_I) ||
+- (current_cpu_data.isa_level == MIPS_CPU_ISA_II))
+- /*
+- * We need to calibrate the counter but we don't have
+- * 64-bit division.
+- */
+- do_gettimeoffset = calibrate_div32_gettimeoffset;
+- else
+- /*
+- * We need to calibrate the counter but we *do* have
+- * 64-bit division.
+- */
+- do_gettimeoffset = calibrate_div64_gettimeoffset;
+ } else {
+ /* We know counter frequency. Or we can get it. */
+ if (!mips_hpt_read) {
+ /* No external high precision timer -- use R4k. */
+ mips_hpt_read = c0_hpt_read;
+
+- if (mips_timer_state)
+- mips_hpt_init = c0_hpt_init;
+- else {
++ if (!mips_timer_state) {
+ /* No external timer interrupt -- use R4k. */
+ mips_hpt_init = c0_hpt_timer_init;
+ mips_timer_ack = c0_timer_ack;
+@@ -683,16 +390,9 @@ void __init time_init(void)
+ if (!mips_hpt_frequency)
+ mips_hpt_frequency = calibrate_hpt();
+
+- do_gettimeoffset = fixed_rate_gettimeoffset;
+-
+ /* Calculate cache parameters. */
+ cycles_per_jiffy = (mips_hpt_frequency + HZ / 2) / HZ;
+
+- /* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */
+- do_div64_32(sll32_usecs_per_cycle,
+- 1000000, mips_hpt_frequency / 2,
+- mips_hpt_frequency);
+-
+ /* Report the high precision timer rate for a reference. */
+ printk("Using %u.%03u MHz high precision timer.\n",
+ ((mips_hpt_frequency + 500) / 1000) / 1000,
+@@ -704,7 +404,7 @@ void __init time_init(void)
+ mips_timer_ack = null_timer_ack;
+
+ /* This sets up the high precision timer for the first interrupt. */
+- mips_hpt_init(mips_hpt_read());
++ mips_hpt_init();
+
+ /*
+ * Call board specific timer interrupt setup.
+@@ -718,6 +418,8 @@ void __init time_init(void)
+ * is not invoked accidentally.
+ */
+ plat_timer_setup(&timer_irqaction);
++
++ init_mips_clocksource();
+ }
+
+ #define FEBRUARY 2
+diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
+index 954a198..9fda1b8 100644
+--- a/arch/mips/kernel/traps.c
++++ b/arch/mips/kernel/traps.c
+@@ -20,6 +20,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/kallsyms.h>
+ #include <linux/bootmem.h>
++#include <linux/interrupt.h>
+
+ #include <asm/bootinfo.h>
+ #include <asm/branch.h>
+@@ -40,6 +41,7 @@
+ #include <asm/mmu_context.h>
+ #include <asm/watch.h>
+ #include <asm/types.h>
++#include <asm/stacktrace.h>
+
+ extern asmlinkage void handle_int(void);
+ extern asmlinkage void handle_tlbm(void);
+@@ -64,7 +66,7 @@ extern asmlinkage void handle_mcheck(voi
+ extern asmlinkage void handle_reserved(void);
+
+ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
+- struct mips_fpu_struct *ctx);
++ struct mips_fpu_struct *ctx, int has_fpu);
+
+ void (*board_be_init)(void);
+ int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
+@@ -72,28 +74,62 @@ void (*board_nmi_handler_setup)(void);
+ void (*board_ejtag_handler_setup)(void);
+ void (*board_bind_eic_interrupt)(int irq, int regset);
+
+-/*
+- * These constant is for searching for possible module text segments.
+- * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
+- */
+-#define MODULE_RANGE (8*1024*1024)
++
++static void show_raw_backtrace(unsigned long reg29)
++{
++ unsigned long *sp = (unsigned long *)reg29;
++ unsigned long addr;
++
++ printk("Call Trace:");
++#ifdef CONFIG_KALLSYMS
++ printk("\n");
++#endif
++ while (!kstack_end(sp)) {
++ addr = *sp++;
++ if (__kernel_text_address(addr))
++ print_ip_sym(addr);
++ }
++ printk("\n");
++}
++
++#ifdef CONFIG_KALLSYMS
++int raw_show_trace;
++static int __init set_raw_show_trace(char *str)
++{
++ raw_show_trace = 1;
++ return 1;
++}
++__setup("raw_show_trace", set_raw_show_trace);
++#endif
++
++static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
++{
++ unsigned long sp = regs->regs[29];
++ unsigned long ra = regs->regs[31];
++ unsigned long pc = regs->cp0_epc;
++
++ if (raw_show_trace || !__kernel_text_address(pc)) {
++ show_raw_backtrace(sp);
++ return;
++ }
++ printk("Call Trace:\n");
++ do {
++ print_ip_sym(pc);
++ pc = unwind_stack(task, &sp, pc, &ra);
++ } while (pc);
++ printk("\n");
++}
+
+ /*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+-void show_stack(struct task_struct *task, unsigned long *sp)
++static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
+ {
+ const int field = 2 * sizeof(unsigned long);
+ long stackdata;
+ int i;
+-
+- if (!sp) {
+- if (task && task != current)
+- sp = (unsigned long *) task->thread.reg29;
+- else
+- sp = (unsigned long *) &sp;
+- }
++ unsigned long *sp = (unsigned long *)regs->regs[29];
+
+ printk("Stack :");
+ i = 0;
+@@ -114,32 +150,26 @@ void show_stack(struct task_struct *task
+ i++;
+ }
+ printk("\n");
++ show_backtrace(task, regs);
+ }
+
+-void show_trace(struct task_struct *task, unsigned long *stack)
++void show_stack(struct task_struct *task, unsigned long *sp)
+ {
+- const int field = 2 * sizeof(unsigned long);
+- unsigned long addr;
+-
+- if (!stack) {
+- if (task && task != current)
+- stack = (unsigned long *) task->thread.reg29;
+- else
+- stack = (unsigned long *) &stack;
+- }
+-
+- printk("Call Trace:");
+-#ifdef CONFIG_KALLSYMS
+- printk("\n");
+-#endif
+- while (!kstack_end(stack)) {
+- addr = *stack++;
+- if (__kernel_text_address(addr)) {
+- printk(" [<%0*lx>] ", field, addr);
+- print_symbol("%s\n", addr);
++ struct pt_regs regs;
++ if (sp) {
++ regs.regs[29] = (unsigned long)sp;
++ regs.regs[31] = 0;
++ regs.cp0_epc = 0;
++ } else {
++ if (task && task != current) {
++ regs.regs[29] = task->thread.reg29;
++ regs.regs[31] = 0;
++ regs.cp0_epc = task->thread.reg31;
++ } else {
++ prepare_frametrace(®s);
+ }
+ }
+- printk("\n");
++ show_stacktrace(task, ®s);
+ }
+
+ /*
+@@ -147,9 +177,10 @@ void show_trace(struct task_struct *task
+ */
+ void dump_stack(void)
+ {
+- unsigned long stack;
++ struct pt_regs regs;
+
+- show_trace(current, &stack);
++ prepare_frametrace(®s);
++ show_backtrace(current, ®s);
+ }
+
+ EXPORT_SYMBOL(dump_stack);
+@@ -268,8 +299,7 @@ void show_registers(struct pt_regs *regs
+ print_modules();
+ printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
+ current->comm, current->pid, current_thread_info(), current);
+- show_stack(current, (long *) regs->regs[29]);
+- show_trace(current, (long *) regs->regs[29]);
++ show_stacktrace(current, regs);
+ show_code((unsigned int *) regs->cp0_epc);
+ printk("\n");
+ }
+@@ -292,6 +322,16 @@ NORET_TYPE void ATTRIB_NORET die(const c
+ printk("%s[#%d]:\n", str, ++die_counter);
+ show_registers(regs);
+ 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(SIGSEGV);
+ }
+
+@@ -601,7 +641,7 @@ asmlinkage void do_fpe(struct pt_regs *r
+ preempt_enable();
+
+ /* Run the emulator */
+- sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu);
++ sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1);
+
+ preempt_disable();
+
+@@ -751,11 +791,13 @@ asmlinkage void do_cpu(struct pt_regs *r
+ set_used_math();
+ }
+
+- preempt_enable();
+-
+- if (!cpu_has_fpu) {
+- int sig = fpu_emulator_cop1Handler(regs,
+- ¤t->thread.fpu);
++ if (cpu_has_fpu) {
++ preempt_enable();
++ } else {
++ int sig;
++ preempt_enable();
++ sig = fpu_emulator_cop1Handler(regs,
++ ¤t->thread.fpu, 0);
+ if (sig)
+ force_sig(sig, current);
+ #ifdef CONFIG_MIPS_MT_FPAFF
+@@ -1069,7 +1111,7 @@ static struct shadow_registers {
+ static void mips_srs_init(void)
+ {
+ shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
+- printk(KERN_INFO "%d MIPSR2 register sets available\n",
++ printk(KERN_INFO "%ld MIPSR2 register sets available\n",
+ shadow_registers.sr_supported);
+ shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */
+ }
+diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
+index 0bb9cd8..79f0317 100644
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -50,6 +50,16 @@ SECTIONS
+ /* writeable */
+ .data : { /* Data */
+ . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */
++ /*
++ * This ALIGN is needed as a workaround for a bug a gcc bug upto 4.1 which
++ * limits the maximum alignment to at most 32kB and results in the following
++ * warning:
++ *
++ * CC arch/mips/kernel/init_task.o
++ * arch/mips/kernel/init_task.c:30: warning: alignment of âinit_thread_unionâ
++ * is greater than maximum object file alignment. Using 32768
++ */
++ . = ALIGN(_PAGE_SIZE);
+ *(.data.init_task)
+
+ *(.data)
+@@ -91,13 +101,7 @@ SECTIONS
+
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+
+diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
+index 9ee0ec2..51ddd21 100644
+--- a/arch/mips/kernel/vpe.c
++++ b/arch/mips/kernel/vpe.c
+@@ -768,10 +768,16 @@ int vpe_run(struct vpe * v)
+ */
+ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor);
+
++ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
++
++ back_to_back_c0_hazard();
++
+ /* Set up the XTC bit in vpeconf0 to point at our tc */
+ write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
+ | (t->index << VPECONF0_XTC_SHIFT));
+
++ back_to_back_c0_hazard();
++
+ /* enable this VPE */
+ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+
+diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
+index 456be8f..a144a00 100644
+--- a/arch/mips/lasat/interrupt.c
++++ b/arch/mips/lasat/interrupt.c
+@@ -108,14 +108,14 @@ static unsigned long get_int_status_200(
+ return int_status;
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned long int_status;
+ unsigned int cause = read_c0_cause();
+ int irq;
+
+ if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */
+- ll_timer_interrupt(7, regs);
++ ll_timer_interrupt(7);
+ return;
+ }
+
+@@ -125,7 +125,7 @@ asmlinkage void plat_irq_dispatch(struct
+ if (int_status) {
+ irq = ls1bit32(int_status);
+
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+ }
+
+diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
+index 0ffc43c..14c5516 100644
+--- a/arch/mips/lasat/setup.c
++++ b/arch/mips/lasat/setup.c
+@@ -34,7 +34,6 @@
+ #include <asm/cpu.h>
+ #include <asm/bootinfo.h>
+ #include <asm/irq.h>
+-#include <asm/serial.h>
+ #include <asm/lasat/lasat.h>
+ #include <asm/lasat/serial.h>
+
+diff --git a/arch/mips/lib-64/dump_tlb.c b/arch/mips/lib-64/dump_tlb.c
+index be8261b..594df1a 100644
+--- a/arch/mips/lib-64/dump_tlb.c
++++ b/arch/mips/lib-64/dump_tlb.c
+@@ -149,7 +149,7 @@ void dump_list_process(struct task_struc
+ printk("Addr == %08lx\n", addr);
+ printk("tasks->mm.pgd == %08lx\n", (unsigned long) t->mm->pgd);
+
+- page_dir = pgd_offset(t->mm, 0);
++ page_dir = pgd_offset(t->mm, 0UL);
+ printk("page_dir == %016lx\n", (unsigned long) page_dir);
+
+ pgd = pgd_offset(t->mm, addr);
+@@ -184,13 +184,13 @@ void dump_list_current(void *address)
+ dump_list_process(current, address);
+ }
+
+-unsigned int vtop(void *address)
++unsigned long vtop(void *address)
+ {
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+- unsigned int addr, paddr;
++ unsigned long addr, paddr;
+
+ addr = (unsigned long) address;
+ pgd = pgd_offset(current->mm, addr);
+diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
+index 3f0d5d2..80531b3 100644
+--- a/arch/mips/math-emu/cp1emu.c
++++ b/arch/mips/math-emu/cp1emu.c
+@@ -38,8 +38,6 @@
+
+ #include <asm/inst.h>
+ #include <asm/bootinfo.h>
+-#include <asm/cpu.h>
+-#include <asm/cpu-features.h>
+ #include <asm/processor.h>
+ #include <asm/ptrace.h>
+ #include <asm/signal.h>
+@@ -1233,7 +1231,8 @@ static int fpu_emu(struct pt_regs *xcp,
+ return 0;
+ }
+
+-int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
++int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
++ int has_fpu)
+ {
+ unsigned long oldepc, prevepc;
+ mips_instruction insn;
+@@ -1263,7 +1262,7 @@ int fpu_emulator_cop1Handler(struct pt_r
+ ieee754_csr.rm = mips_rm[ieee754_csr.rm];
+ }
+
+- if (cpu_has_fpu)
++ if (has_fpu)
+ break;
+ if (sig)
+ break;
+diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
+index fb25e03..be624b8 100644
+--- a/arch/mips/mips-boards/atlas/atlas_int.c
++++ b/arch/mips/mips-boards/atlas/atlas_int.c
+@@ -1,6 +1,8 @@
+ /*
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++ * Copyright (C) 1999, 2000, 2006 MIPS Technologies, Inc.
++ * All rights reserved.
++ * Authors: Carsten Langgaard <carstenl at mips.com>
++ * Maciej W. Rozycki <macro at mips.com>
+ *
+ * ########################################################################
+ *
+@@ -25,17 +27,20 @@
+ */
+ #include <linux/compiler.h>
+ #include <linux/init.h>
++#include <linux/irq.h>
+ #include <linux/sched.h>
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+ #include <linux/kernel_stat.h>
+
+-#include <asm/irq.h>
++#include <asm/gdb-stub.h>
+ #include <asm/io.h>
++#include <asm/irq_cpu.h>
++#include <asm/msc01_ic.h>
++
+ #include <asm/mips-boards/atlas.h>
+ #include <asm/mips-boards/atlasint.h>
+-#include <asm/gdb-stub.h>
+-
++#include <asm/mips-boards/generic.h>
+
+ static struct atlas_ictrl_regs *atlas_hw0_icregs;
+
+@@ -47,13 +52,13 @@ static struct atlas_ictrl_regs *atlas_hw
+
+ void disable_atlas_irq(unsigned int irq_nr)
+ {
+- atlas_hw0_icregs->intrsten = (1 << (irq_nr-ATLASINT_BASE));
++ atlas_hw0_icregs->intrsten = 1 << (irq_nr - ATLAS_INT_BASE);
+ iob();
+ }
+
+ void enable_atlas_irq(unsigned int irq_nr)
+ {
+- atlas_hw0_icregs->intseten = (1 << (irq_nr-ATLASINT_BASE));
++ atlas_hw0_icregs->intseten = 1 << (irq_nr - ATLAS_INT_BASE);
+ iob();
+ }
+
+@@ -96,7 +101,7 @@ static inline int ls1bit32(unsigned int
+ return b;
+ }
+
+-static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
++static inline void atlas_hw0_irqdispatch(void)
+ {
+ unsigned long int_status;
+ int irq;
+@@ -107,11 +112,11 @@ static inline void atlas_hw0_irqdispatch
+ if (unlikely(int_status == 0))
+ return;
+
+- irq = ATLASINT_BASE + ls1bit32(int_status);
++ irq = ATLAS_INT_BASE + ls1bit32(int_status);
+
+ DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq);
+
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+ static inline int clz(unsigned long x)
+@@ -161,15 +166,14 @@ static inline unsigned int irq_ffs(unsig
+ }
+
+ /*
+- * IRQs on the Atlas board look basically (barring software IRQs which we
+- * don't use at all and all external interrupt sources are combined together
+- * on hardware interrupt 0 (MIPS IRQ 2)) like:
++ * IRQs on the Atlas board look basically like (all external interrupt
++ * sources are combined together on hardware interrupt 0 (MIPS IRQ 2)):
+ *
+- * MIPS IRQ Source
++ * MIPS IRQ Source
+ * -------- ------
+- * 0 Software (ignored)
+- * 1 Software (ignored)
+- * 2 Combined hardware interrupt (hw0)
++ * 0 Software 0 (reschedule IPI on MT)
++ * 1 Software 1 (remote call IPI on MT)
++ * 2 Combined Atlas hardware interrupt (hw0)
+ * 3 Hardware (ignored)
+ * 4 Hardware (ignored)
+ * 5 Hardware (ignored)
+@@ -179,12 +183,12 @@ static inline unsigned int irq_ffs(unsig
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+- * Lowest ---- Combined hardware interrupt
++ * Lowest ---- Software 0
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+@@ -192,18 +196,20 @@ asmlinkage void plat_irq_dispatch(struct
+ irq = irq_ffs(pending);
+
+ if (irq == MIPSCPU_INT_ATLAS)
+- atlas_hw0_irqdispatch(regs);
+- else if (irq > 0)
+- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
++ atlas_hw0_irqdispatch();
++ else if (irq >= 0)
++ do_IRQ(MIPSCPU_INT_BASE + irq);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+-void __init arch_init_irq(void)
++static inline void init_atlas_irqs (int base)
+ {
+ int i;
+
+- atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *));
++ atlas_hw0_icregs = (struct atlas_ictrl_regs *)
++ ioremap(ATLAS_ICTRL_REGS_BASE,
++ sizeof(struct atlas_ictrl_regs *));
+
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+@@ -211,7 +217,7 @@ void __init arch_init_irq(void)
+ */
+ atlas_hw0_icregs->intrsten = 0xffffffff;
+
+- for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) {
++ for (i = ATLAS_INT_BASE; i <= ATLAS_INT_END; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+@@ -219,3 +225,62 @@ void __init arch_init_irq(void)
+ spin_lock_init(&irq_desc[i].lock);
+ }
+ }
++
++static struct irqaction atlasirq = {
++ .handler = no_action,
++ .name = "Atlas cascade"
++};
++
++msc_irqmap_t __initdata msc_irqmap[] = {
++ {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
++ {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
++};
++int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap);
++
++msc_irqmap_t __initdata msc_eicirqmap[] = {
++ {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
++ {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
++ {MSC01E_INT_ATLAS, MSC01_IRQ_LEVEL, 0},
++ {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0},
++ {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0},
++ {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
++ {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
++};
++int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap);
++
++void __init arch_init_irq(void)
++{
++ init_atlas_irqs(ATLAS_INT_BASE);
++
++ if (!cpu_has_veic)
++ mips_cpu_irq_init(MIPSCPU_INT_BASE);
++
++ switch(mips_revision_corid) {
++ case MIPS_REVISION_CORID_CORE_MSC:
++ case MIPS_REVISION_CORID_CORE_FPGA2:
++ case MIPS_REVISION_CORID_CORE_FPGA3:
++ case MIPS_REVISION_CORID_CORE_24K:
++ case MIPS_REVISION_CORID_CORE_EMUL_MSC:
++ if (cpu_has_veic)
++ init_msc_irqs (MSC01E_INT_BASE,
++ msc_eicirqmap, msc_nr_eicirqs);
++ else
++ init_msc_irqs (MSC01C_INT_BASE,
++ msc_irqmap, msc_nr_irqs);
++ }
++
++
++ if (cpu_has_veic) {
++ set_vi_handler (MSC01E_INT_ATLAS, atlas_hw0_irqdispatch);
++ setup_irq (MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq);
++ } else if (cpu_has_vint) {
++ set_vi_handler (MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch);
++#ifdef CONFIG_MIPS_MT_SMTC
++ setup_irq_smtc (MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS,
++ &atlasirq, (0x100 << MIPSCPU_INT_ATLAS));
++#else /* Not SMTC */
++ setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq);
++#endif /* CONFIG_MIPS_MT_SMTC */
++ } else
++ setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq);
++}
+diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
+index 9871a91..0c6b0ce 100644
+--- a/arch/mips/mips-boards/atlas/atlas_setup.c
++++ b/arch/mips/mips-boards/atlas/atlas_setup.c
+@@ -77,7 +77,7 @@ static void __init serial_init(void)
+ #else
+ s.iobase = ATLAS_UART_REGS_BASE+3;
+ #endif
+- s.irq = ATLASINT_UART;
++ s.irq = ATLAS_INT_UART;
+ s.uartclk = ATLAS_BASE_BAUD * 16;
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ;
+ s.iotype = UPIO_PORT;
+diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
+index be80c5d..eeed944 100644
+--- a/arch/mips/mips-boards/generic/memory.c
++++ b/arch/mips/mips-boards/generic/memory.c
+@@ -176,7 +176,7 @@ unsigned long __init prom_free_prom_memo
+ if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
+ continue;
+
+- addr = boot_mem_map.map[i].addr;
++ addr = PAGE_ALIGN(boot_mem_map.map[i].addr);
+ while (addr < boot_mem_map.map[i].addr
+ + boot_mem_map.map[i].size) {
+ ClearPageReserved(virt_to_page(__va(addr)));
+diff --git a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c
+index 9337f6c..3192a14 100644
+--- a/arch/mips/mips-boards/generic/pci.c
++++ b/arch/mips/mips-boards/generic/pci.c
+@@ -90,7 +90,7 @@ static struct pci_controller msc_control
+ void __init mips_pcibios_init(void)
+ {
+ struct pci_controller *controller;
+- unsigned long start, end, map, start1, end1, map1, map2, map3, mask;
++ resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
+
+ switch (mips_revision_corid) {
+ case MIPS_REVISION_CORID_QED_RM5261:
+diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
+index 557bf96..d817c60 100644
+--- a/arch/mips/mips-boards/generic/time.c
++++ b/arch/mips/mips-boards/generic/time.c
+@@ -30,7 +30,6 @@
+
+ #include <asm/mipsregs.h>
+ #include <asm/mipsmtregs.h>
+-#include <asm/ptrace.h>
+ #include <asm/hardirq.h>
+ #include <asm/irq.h>
+ #include <asm/div64.h>
+@@ -41,8 +40,13 @@
+
+ #include <asm/mips-boards/generic.h>
+ #include <asm/mips-boards/prom.h>
++
++#ifdef CONFIG_MIPS_ATLAS
++#include <asm/mips-boards/atlasint.h>
++#endif
++#ifdef CONFIG_MIPS_MALTA
+ #include <asm/mips-boards/maltaint.h>
+-#include <asm/mc146818-time.h>
++#endif
+
+ unsigned long cpu_khz;
+
+@@ -77,25 +81,24 @@ static inline void scroll_display_messag
+ }
+ }
+
+-static void mips_timer_dispatch (struct pt_regs *regs)
++static void mips_timer_dispatch(void)
+ {
+- do_IRQ (mips_cpu_timer_irq, regs);
++ do_IRQ(mips_cpu_timer_irq);
+ }
+
+ /*
+ * Redeclare until I get around mopping the timer code insanity on MIPS.
+ */
+-extern int null_perf_irq(struct pt_regs *regs);
++extern int null_perf_irq(void);
+
+-extern int (*perf_irq)(struct pt_regs *regs);
++extern int (*perf_irq)(void);
+
+-irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t mips_timer_interrupt(int irq, void *dev_id)
+ {
+ int cpu = smp_processor_id();
+- int r2 = cpu_has_mips_r2;
+
+ #ifdef CONFIG_MIPS_MT_SMTC
+- /*
++ /*
+ * In an SMTC system, one Count/Compare set exists per VPE.
+ * Which TC within a VPE gets the interrupt is essentially
+ * random - we only know that it shouldn't be one with
+@@ -108,29 +111,46 @@ irqreturn_t mips_timer_interrupt(int irq
+ * the general MIPS timer_interrupt routine.
+ */
+
++ int vpflags;
++
+ /*
+- * DVPE is necessary so long as cross-VPE interrupts
+- * are done via read-modify-write of Cause register.
++ * We could be here due to timer interrupt,
++ * perf counter overflow, or both.
+ */
+- int vpflags = dvpe();
+- write_c0_compare (read_c0_count() - 1);
+- clear_c0_cause(CPUCTR_IMASKBIT);
+- evpe(vpflags);
++ if (read_c0_cause() & (1 << 26))
++ perf_irq();
+
+- if (cpu_data[cpu].vpe_id == 0) {
+- timer_interrupt(irq, dev_id, regs);
+- scroll_display_message();
+- } else
+- write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
+- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+-
+- if (cpu != 0)
++ if (read_c0_cause() & (1 << 30)) {
++ /* If timer interrupt, make it de-assert */
++ write_c0_compare (read_c0_count() - 1);
+ /*
+- * Other CPUs should do profiling and process accounting
++ * DVPE is necessary so long as cross-VPE interrupts
++ * are done via read-modify-write of Cause register.
+ */
+- local_timer_interrupt(irq, dev_id, regs);
+-
++ vpflags = dvpe();
++ clear_c0_cause(CPUCTR_IMASKBIT);
++ evpe(vpflags);
++ /*
++ * There are things we only want to do once per tick
++ * in an "MP" system. One TC of each VPE will take
++ * the actual timer interrupt. The others will get
++ * timer broadcast IPIs. We use whoever it is that takes
++ * the tick on VPE 0 to run the full timer_interrupt().
++ */
++ if (cpu_data[cpu].vpe_id == 0) {
++ timer_interrupt(irq, NULL);
++ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
++ scroll_display_message();
++ } else {
++ write_c0_compare(read_c0_count() +
++ (mips_hpt_frequency/HZ));
++ local_timer_interrupt(irq, dev_id);
++ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
++ }
++ }
+ #else /* CONFIG_MIPS_MT_SMTC */
++ int r2 = cpu_has_mips_r2;
++
+ if (cpu == 0) {
+ /*
+ * CPU 0 handles the global timer interrupt job and process
+@@ -138,12 +158,12 @@ irqreturn_t mips_timer_interrupt(int irq
+ * timer int.
+ */
+ if (!r2 || (read_c0_cause() & (1 << 26)))
+- if (perf_irq(regs))
++ if (perf_irq())
+ goto out;
+
+ /* we keep interrupt disabled all the time */
+ if (!r2 || (read_c0_cause() & (1 << 30)))
+- timer_interrupt(irq, NULL, regs);
++ timer_interrupt(irq, NULL);
+
+ scroll_display_message();
+ } else {
+@@ -159,16 +179,15 @@ irqreturn_t mips_timer_interrupt(int irq
+ /*
+ * Other CPUs should do profiling and process accounting
+ */
+- local_timer_interrupt(irq, dev_id, regs);
++ local_timer_interrupt(irq, dev_id);
+ }
+-#endif /* CONFIG_MIPS_MT_SMTC */
+-
+ out:
++#endif /* CONFIG_MIPS_MT_SMTC */
+ return IRQ_HANDLED;
+ }
+
+ /*
+- * Estimate CPU frequency. Sets mips_counter_frequency as a side-effect
++ * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
+ */
+ static unsigned int __init estimate_cpu_frequency(void)
+ {
+@@ -189,7 +208,8 @@ static unsigned int __init estimate_cpu_
+ count = 6000000;
+ #endif
+ #if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA)
+- unsigned int flags;
++ unsigned long flags;
++ unsigned int start;
+
+ local_irq_save(flags);
+
+@@ -198,13 +218,13 @@ static unsigned int __init estimate_cpu_
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ /* Start r4k counter. */
+- write_c0_count(0);
++ start = read_c0_count();
+
+ /* Read counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+- count = read_c0_count();
++ count = read_c0_count() - start;
+
+ /* restore interrupts */
+ local_irq_restore(flags);
+diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
+index 7cc0ba4..90ad5bf 100644
+--- a/arch/mips/mips-boards/malta/malta_int.c
++++ b/arch/mips/mips-boards/malta/malta_int.c
+@@ -32,6 +32,7 @@
+ #include <asm/i8259.h>
+ #include <asm/irq_cpu.h>
+ #include <asm/io.h>
++#include <asm/irq_regs.h>
+ #include <asm/mips-boards/malta.h>
+ #include <asm/mips-boards/maltaint.h>
+ #include <asm/mips-boards/piix4.h>
+@@ -114,7 +115,7 @@ static inline int get_int(void)
+ return irq;
+ }
+
+-static void malta_hw0_irqdispatch(struct pt_regs *regs)
++static void malta_hw0_irqdispatch(void)
+ {
+ int irq;
+
+@@ -123,17 +124,21 @@ static void malta_hw0_irqdispatch(struct
+ return; /* interrupt has already been cleared */
+ }
+
+- do_IRQ(MALTA_INT_BASE+irq, regs);
++ do_IRQ(MALTA_INT_BASE + irq);
+ }
+
+-void corehi_irqdispatch(struct pt_regs *regs)
++static void corehi_irqdispatch(void)
+ {
++ unsigned int intedge, intsteer, pcicmd, pcibadaddr;
++ unsigned int pcimstat, intisr, inten, intpol;
+ unsigned int intrcause,datalo,datahi;
+- unsigned int pcimstat, intisr, inten, intpol, intedge, intsteer, pcicmd, pcibadaddr;
++ struct pt_regs *regs = get_irq_regs();
+
+ printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n");
+- printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n"
+-, regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr);
++ printk("epc : %08lx\nStatus: %08lx\n"
++ "Cause : %08lx\nbadVaddr : %08lx\n",
++ regs->cp0_epc, regs->cp0_status,
++ regs->cp0_cause, regs->cp0_badvaddr);
+
+ /* Read all the registers and then print them as there is a
+ problem with interspersed printk's upsetting the Bonito controller.
+@@ -146,7 +151,7 @@ void corehi_irqdispatch(struct pt_regs *
+ case MIPS_REVISION_CORID_CORE_FPGA3:
+ case MIPS_REVISION_CORID_CORE_24K:
+ case MIPS_REVISION_CORID_CORE_EMUL_MSC:
+- ll_msc_irq(regs);
++ ll_msc_irq();
+ break;
+ case MIPS_REVISION_CORID_QED_RM5261:
+ case MIPS_REVISION_CORID_CORE_LV:
+@@ -208,23 +213,23 @@ static inline unsigned int irq_ffs(unsig
+ unsigned int a0 = 7;
+ unsigned int t0;
+
+- t0 = s0 & 0xf000;
++ t0 = pending & 0xf000;
+ t0 = t0 < 1;
+ t0 = t0 << 2;
+ a0 = a0 - t0;
+- s0 = s0 << t0;
++ pending = pending << t0;
+
+- t0 = s0 & 0xc000;
++ t0 = pending & 0xc000;
+ t0 = t0 < 1;
+ t0 = t0 << 1;
+ a0 = a0 - t0;
+- s0 = s0 << t0;
++ pending = pending << t0;
+
+- t0 = s0 & 0x8000;
++ t0 = pending & 0x8000;
+ t0 = t0 < 1;
+ //t0 = t0 << 2;
+ a0 = a0 - t0;
+- //s0 = s0 << t0;
++ //pending = pending << t0;
+
+ return a0;
+ #endif
+@@ -255,7 +260,7 @@ static inline unsigned int irq_ffs(unsig
+ * another exception, big deal.
+ */
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+@@ -263,11 +268,11 @@ asmlinkage void plat_irq_dispatch(struct
+ irq = irq_ffs(pending);
+
+ if (irq == MIPSCPU_INT_I8259A)
+- malta_hw0_irqdispatch(regs);
++ malta_hw0_irqdispatch();
+ else if (irq > 0)
+- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
++ do_IRQ(MIPSCPU_INT_BASE + irq);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ static struct irqaction i8259irq = {
+diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c
+index 9168d93..f445fcd 100644
+--- a/arch/mips/mips-boards/sead/sead_int.c
++++ b/arch/mips/mips-boards/sead/sead_int.c
+@@ -98,7 +98,7 @@ static inline unsigned int irq_ffs(unsig
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+@@ -106,7 +106,7 @@ asmlinkage void plat_irq_dispatch(struct
+ irq = irq_ffs(pending);
+
+ if (irq >= 0)
+- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
++ do_IRQ(MIPSCPU_INT_BASE + irq);
+ else
+ spurious_interrupt(regs);
+ }
+diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
+index 2c15c8e..2ce449d 100644
+--- a/arch/mips/mips-boards/sim/sim_int.c
++++ b/arch/mips/mips-boards/sim/sim_int.c
+@@ -71,12 +71,7 @@ static inline unsigned int irq_ffs(unsig
+ #endif
+ }
+
+-static inline void sim_hw0_irqdispatch(struct pt_regs *regs)
+-{
+- do_IRQ(2, regs);
+-}
+-
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+@@ -84,9 +79,9 @@ asmlinkage void plat_irq_dispatch(struct
+ irq = irq_ffs(pending);
+
+ if (irq > 0)
+- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
++ do_IRQ(MIPSCPU_INT_BASE + irq);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ void __init arch_init_irq(void)
+diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c
+index 230929e..24a4ed0 100644
+--- a/arch/mips/mips-boards/sim/sim_time.c
++++ b/arch/mips/mips-boards/sim/sim_time.c
+@@ -15,7 +15,6 @@
+ #include <linux/mc146818rtc.h>
+ #include <linux/timex.h>
+ #include <asm/mipsregs.h>
+-#include <asm/ptrace.h>
+ #include <asm/hardirq.h>
+ #include <asm/irq.h>
+ #include <asm/div64.h>
+@@ -33,7 +32,7 @@
+
+ unsigned long cpu_khz;
+
+-irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t sim_timer_interrupt(int irq, void *dev_id)
+ {
+ #ifdef CONFIG_SMP
+ int cpu = smp_processor_id();
+@@ -44,7 +43,7 @@ irqreturn_t sim_timer_interrupt(int irq,
+ */
+ #ifndef CONFIG_MIPS_MT_SMTC
+ if (cpu == 0) {
+- timer_interrupt(irq, dev_id, regs);
++ timer_interrupt(irq, dev_id);
+ }
+ else {
+ /* Everyone else needs to reset the timer int here as
+@@ -84,7 +83,7 @@ irqreturn_t sim_timer_interrupt(int irq,
+ irq_enable_hazard();
+ evpe(vpflags);
+
+- if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id, regs);
++ if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id);
+ else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+
+@@ -93,17 +92,17 @@ irqreturn_t sim_timer_interrupt(int irq,
+ /*
+ * every CPU should do profiling and process accounting
+ */
+- local_timer_interrupt (irq, dev_id, regs);
++ local_timer_interrupt (irq, dev_id);
+ return IRQ_HANDLED;
+ #else
+- return timer_interrupt (irq, dev_id, regs);
++ return timer_interrupt (irq, dev_id);
+ #endif
+ }
+
+
+
+ /*
+- * Estimate CPU frequency. Sets mips_counter_frequency as a side-effect
++ * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
+ */
+ static unsigned int __init estimate_cpu_frequency(void)
+ {
+@@ -177,9 +176,9 @@ void __init sim_time_init(void)
+
+ static int mips_cpu_timer_irq;
+
+-static void mips_timer_dispatch (struct pt_regs *regs)
++static void mips_timer_dispatch(void)
+ {
+- do_IRQ (mips_cpu_timer_irq, regs);
++ do_IRQ(mips_cpu_timer_irq);
+ }
+
+
+diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
+index bb041a2..d1af42c 100644
+--- a/arch/mips/mm/c-r3k.c
++++ b/arch/mips/mm/c-r3k.c
+@@ -268,26 +268,6 @@ static void r3k_flush_data_cache_page(un
+ {
+ }
+
+-static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+-{
+- struct mm_struct *mm = vma->vm_mm;
+- unsigned long physpage;
+-
+- if (cpu_context(smp_processor_id(), mm) == 0)
+- return;
+-
+- if (!(vma->vm_flags & VM_EXEC))
+- return;
+-
+-#ifdef DEBUG_CACHE
+- printk("cpage[%d,%08lx]", cpu_context(smp_processor_id(), mm), page);
+-#endif
+-
+- physpage = (unsigned long) page_address(page);
+- if (physpage)
+- r3k_flush_icache_range(physpage, physpage + PAGE_SIZE);
+-}
+-
+ static void r3k_flush_cache_sigtramp(unsigned long addr)
+ {
+ unsigned long flags;
+@@ -335,7 +315,6 @@ void __init r3k_cache_init(void)
+ flush_cache_mm = r3k_flush_cache_mm;
+ flush_cache_range = r3k_flush_cache_range;
+ flush_cache_page = r3k_flush_cache_page;
+- flush_icache_page = r3k_flush_icache_page;
+ flush_icache_range = r3k_flush_icache_range;
+
+ flush_cache_sigtramp = r3k_flush_cache_sigtramp;
+diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
+index 069803f..cc895da 100644
+--- a/arch/mips/mm/c-r4k.c
++++ b/arch/mips/mm/c-r4k.c
+@@ -89,7 +89,7 @@ static inline void r4k_blast_dcache_page
+ blast_dcache32_page(addr);
+ }
+
+-static inline void r4k_blast_dcache_page_setup(void)
++static void __init r4k_blast_dcache_page_setup(void)
+ {
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+@@ -103,7 +103,7 @@ static inline void r4k_blast_dcache_page
+
+ static void (* r4k_blast_dcache_page_indexed)(unsigned long addr);
+
+-static inline void r4k_blast_dcache_page_indexed_setup(void)
++static void __init r4k_blast_dcache_page_indexed_setup(void)
+ {
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+@@ -117,7 +117,7 @@ static inline void r4k_blast_dcache_page
+
+ static void (* r4k_blast_dcache)(void);
+
+-static inline void r4k_blast_dcache_setup(void)
++static void __init r4k_blast_dcache_setup(void)
+ {
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+@@ -202,7 +202,7 @@ static inline void tx49_blast_icache32_p
+
+ static void (* r4k_blast_icache_page)(unsigned long addr);
+
+-static inline void r4k_blast_icache_page_setup(void)
++static void __init r4k_blast_icache_page_setup(void)
+ {
+ unsigned long ic_lsize = cpu_icache_line_size();
+
+@@ -219,7 +219,7 @@ static inline void r4k_blast_icache_page
+
+ static void (* r4k_blast_icache_page_indexed)(unsigned long addr);
+
+-static inline void r4k_blast_icache_page_indexed_setup(void)
++static void __init r4k_blast_icache_page_indexed_setup(void)
+ {
+ unsigned long ic_lsize = cpu_icache_line_size();
+
+@@ -243,7 +243,7 @@ static inline void r4k_blast_icache_page
+
+ static void (* r4k_blast_icache)(void);
+
+-static inline void r4k_blast_icache_setup(void)
++static void __init r4k_blast_icache_setup(void)
+ {
+ unsigned long ic_lsize = cpu_icache_line_size();
+
+@@ -264,7 +264,7 @@ static inline void r4k_blast_icache_setu
+
+ static void (* r4k_blast_scache_page)(unsigned long addr);
+
+-static inline void r4k_blast_scache_page_setup(void)
++static void __init r4k_blast_scache_page_setup(void)
+ {
+ unsigned long sc_lsize = cpu_scache_line_size();
+
+@@ -282,7 +282,7 @@ static inline void r4k_blast_scache_page
+
+ static void (* r4k_blast_scache_page_indexed)(unsigned long addr);
+
+-static inline void r4k_blast_scache_page_indexed_setup(void)
++static void __init r4k_blast_scache_page_indexed_setup(void)
+ {
+ unsigned long sc_lsize = cpu_scache_line_size();
+
+@@ -300,7 +300,7 @@ static inline void r4k_blast_scache_page
+
+ static void (* r4k_blast_scache)(void);
+
+-static inline void r4k_blast_scache_setup(void)
++static void __init r4k_blast_scache_setup(void)
+ {
+ unsigned long sc_lsize = cpu_scache_line_size();
+
+@@ -475,7 +475,7 @@ static inline void local_r4k_flush_cache
+ }
+ }
+ if (exec) {
+- if (cpu_has_vtag_icache) {
++ if (cpu_has_vtag_icache && mm == current->active_mm) {
+ int cpu = smp_processor_id();
+
+ if (cpu_context(cpu, mm) != 0)
+@@ -551,82 +551,6 @@ static void r4k_flush_icache_range(unsig
+ instruction_hazard();
+ }
+
+-/*
+- * Ok, this seriously sucks. We use them to flush a user page but don't
+- * know the virtual address, so we have to blast away the whole icache
+- * which is significantly more expensive than the real thing. Otoh we at
+- * least know the kernel address of the page so we can flush it
+- * selectivly.
+- */
+-
+-struct flush_icache_page_args {
+- struct vm_area_struct *vma;
+- struct page *page;
+-};
+-
+-static inline void local_r4k_flush_icache_page(void *args)
+-{
+- struct flush_icache_page_args *fip_args = args;
+- struct vm_area_struct *vma = fip_args->vma;
+- struct page *page = fip_args->page;
+-
+- /*
+- * Tricky ... Because we don't know the virtual address we've got the
+- * choice of either invalidating the entire primary and secondary
+- * caches or invalidating the secondary caches also. With the subset
+- * enforcment on R4000SC, R4400SC, R10000 and R12000 invalidating the
+- * secondary cache will result in any entries in the primary caches
+- * also getting invalidated which hopefully is a bit more economical.
+- */
+- if (cpu_has_inclusive_pcaches) {
+- unsigned long addr = (unsigned long) page_address(page);
+-
+- r4k_blast_scache_page(addr);
+- ClearPageDcacheDirty(page);
+-
+- return;
+- }
+-
+- if (!cpu_has_ic_fills_f_dc) {
+- unsigned long addr = (unsigned long) page_address(page);
+- r4k_blast_dcache_page(addr);
+- if (!cpu_icache_snoops_remote_store)
+- r4k_blast_scache_page(addr);
+- ClearPageDcacheDirty(page);
+- }
+-
+- /*
+- * We're not sure of the virtual address(es) involved here, so
+- * we have to flush the entire I-cache.
+- */
+- if (cpu_has_vtag_icache) {
+- int cpu = smp_processor_id();
+-
+- if (cpu_context(cpu, vma->vm_mm) != 0)
+- drop_mmu_context(vma->vm_mm, cpu);
+- } else
+- r4k_blast_icache();
+-}
+-
+-static void r4k_flush_icache_page(struct vm_area_struct *vma,
+- struct page *page)
+-{
+- struct flush_icache_page_args args;
+-
+- /*
+- * If there's no context yet, or the page isn't executable, no I-cache
+- * flush is needed.
+- */
+- if (!(vma->vm_flags & VM_EXEC))
+- return;
+-
+- args.vma = vma;
+- args.page = page;
+-
+- r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1);
+-}
+-
+-
+ #ifdef CONFIG_DMA_NONCOHERENT
+
+ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
+@@ -1221,7 +1145,7 @@ void au1x00_fixup_config_od(void)
+ }
+ }
+
+-static inline void coherency_setup(void)
++static void __init coherency_setup(void)
+ {
+ change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
+
+@@ -1242,7 +1166,7 @@ static inline void coherency_setup(void)
+ clear_c0_config(CONF_CU);
+ break;
+ /*
+- * We need to catch the ealry Alchemy SOCs with
++ * We need to catch the early Alchemy SOCs with
+ * the write-only co_config.od bit and set it back to one...
+ */
+ case CPU_AU1000: /* rev. DA, HA, HB */
+@@ -1291,7 +1215,6 @@ void __init r4k_cache_init(void)
+ __flush_cache_all = r4k___flush_cache_all;
+ flush_cache_mm = r4k_flush_cache_mm;
+ flush_cache_page = r4k_flush_cache_page;
+- flush_icache_page = r4k_flush_icache_page;
+ flush_cache_range = r4k_flush_cache_range;
+
+ flush_cache_sigtramp = r4k_flush_cache_sigtramp;
+diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
+index 2d71efb..d0ddb4a 100644
+--- a/arch/mips/mm/c-sb1.c
++++ b/arch/mips/mm/c-sb1.c
+@@ -49,6 +49,15 @@ static unsigned short dcache_sets;
+ static unsigned int icache_range_cutoff;
+ static unsigned int dcache_range_cutoff;
+
++static inline void sb1_on_each_cpu(void (*func) (void *info), void *info,
++ int retry, int wait)
++{
++ preempt_disable();
++ smp_call_function(func, info, retry, wait);
++ func(info);
++ preempt_enable();
++}
++
+ /*
+ * The dcache is fully coherent to the system, with one
+ * big caveat: the instruction stream. In other words,
+@@ -155,6 +164,26 @@ static inline void __sb1_flush_icache_al
+ }
+
+ /*
++ * Invalidate a range of the icache. The addresses are virtual, and
++ * the cache is virtually indexed and tagged. However, we don't
++ * necessarily have the right ASID context, so use index ops instead
++ * of hit ops.
++ */
++static inline void __sb1_flush_icache_range(unsigned long start,
++ unsigned long end)
++{
++ start &= ~(icache_line_size - 1);
++ end = (end + icache_line_size - 1) & ~(icache_line_size - 1);
++
++ while (start != end) {
++ cache_set_op(Index_Invalidate_I, start & icache_index_mask);
++ start += icache_line_size;
++ }
++ mispredict();
++ sync();
++}
++
++/*
+ * Flush the icache for a given physical page. Need to writeback the
+ * dcache first, then invalidate the icache. If the page isn't
+ * executable, nothing is required.
+@@ -173,8 +202,11 @@ static void local_sb1_flush_cache_page(s
+ /*
+ * Bumping the ASID is probably cheaper than the flush ...
+ */
+- if (cpu_context(cpu, vma->vm_mm) != 0)
+- drop_mmu_context(vma->vm_mm, cpu);
++ if (vma->vm_mm == current->active_mm) {
++ if (cpu_context(cpu, vma->vm_mm) != 0)
++ drop_mmu_context(vma->vm_mm, cpu);
++ } else
++ __sb1_flush_icache_range(addr, addr + PAGE_SIZE);
+ }
+
+ #ifdef CONFIG_SMP
+@@ -203,33 +235,13 @@ static void sb1_flush_cache_page(struct
+ args.vma = vma;
+ args.addr = addr;
+ args.pfn = pfn;
+- on_each_cpu(sb1_flush_cache_page_ipi, (void *) &args, 1, 1);
++ sb1_on_each_cpu(sb1_flush_cache_page_ipi, (void *) &args, 1, 1);
+ }
+ #else
+ void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
+ __attribute__((alias("local_sb1_flush_cache_page")));
+ #endif
+
+-/*
+- * Invalidate a range of the icache. The addresses are virtual, and
+- * the cache is virtually indexed and tagged. However, we don't
+- * necessarily have the right ASID context, so use index ops instead
+- * of hit ops.
+- */
+-static inline void __sb1_flush_icache_range(unsigned long start,
+- unsigned long end)
+-{
+- start &= ~(icache_line_size - 1);
+- end = (end + icache_line_size - 1) & ~(icache_line_size - 1);
+-
+- while (start != end) {
+- cache_set_op(Index_Invalidate_I, start & icache_index_mask);
+- start += icache_line_size;
+- }
+- mispredict();
+- sync();
+-}
+-
+
+ /*
+ * Invalidate all caches on this CPU
+@@ -246,7 +258,7 @@ void sb1___flush_cache_all_ipi(void *ign
+
+ static void sb1___flush_cache_all(void)
+ {
+- on_each_cpu(sb1___flush_cache_all_ipi, 0, 1, 1);
++ sb1_on_each_cpu(sb1___flush_cache_all_ipi, 0, 1, 1);
+ }
+ #else
+ void sb1___flush_cache_all(void)
+@@ -296,7 +308,7 @@ void sb1_flush_icache_range(unsigned lon
+
+ args.start = start;
+ args.end = end;
+- on_each_cpu(sb1_flush_icache_range_ipi, &args, 1, 1);
++ sb1_on_each_cpu(sb1_flush_icache_range_ipi, &args, 1, 1);
+ }
+ #else
+ void sb1_flush_icache_range(unsigned long start, unsigned long end)
+@@ -304,63 +316,6 @@ void sb1_flush_icache_range(unsigned lon
+ #endif
+
+ /*
+- * Flush the icache for a given physical page. Need to writeback the
+- * dcache first, then invalidate the icache. If the page isn't
+- * executable, nothing is required.
+- */
+-static void local_sb1_flush_icache_page(struct vm_area_struct *vma,
+- struct page *page)
+-{
+- unsigned long start;
+- int cpu = smp_processor_id();
+-
+-#ifndef CONFIG_SMP
+- if (!(vma->vm_flags & VM_EXEC))
+- return;
+-#endif
+-
+- /* Need to writeback any dirty data for that page, we have the PA */
+- start = (unsigned long)(page-mem_map) << PAGE_SHIFT;
+- __sb1_writeback_inv_dcache_phys_range(start, start + PAGE_SIZE);
+- /*
+- * If there's a context, bump the ASID (cheaper than a flush,
+- * since we don't know VAs!)
+- */
+- if (cpu_context(cpu, vma->vm_mm) != 0) {
+- drop_mmu_context(vma->vm_mm, cpu);
+- }
+-}
+-
+-#ifdef CONFIG_SMP
+-struct flush_icache_page_args {
+- struct vm_area_struct *vma;
+- struct page *page;
+-};
+-
+-static void sb1_flush_icache_page_ipi(void *info)
+-{
+- struct flush_icache_page_args *args = info;
+- local_sb1_flush_icache_page(args->vma, args->page);
+-}
+-
+-/* Dirty dcache could be on another CPU, so do the IPIs */
+-static void sb1_flush_icache_page(struct vm_area_struct *vma,
+- struct page *page)
+-{
+- struct flush_icache_page_args args;
+-
+- if (!(vma->vm_flags & VM_EXEC))
+- return;
+- args.vma = vma;
+- args.page = page;
+- on_each_cpu(sb1_flush_icache_page_ipi, (void *) &args, 1, 1);
+-}
+-#else
+-void sb1_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+- __attribute__((alias("local_sb1_flush_icache_page")));
+-#endif
+-
+-/*
+ * A signal trampoline must fit into a single cacheline.
+ */
+ static void local_sb1_flush_cache_sigtramp(unsigned long addr)
+@@ -380,7 +335,7 @@ static void sb1_flush_cache_sigtramp_ipi
+
+ static void sb1_flush_cache_sigtramp(unsigned long addr)
+ {
+- on_each_cpu(sb1_flush_cache_sigtramp_ipi, (void *) addr, 1, 1);
++ sb1_on_each_cpu(sb1_flush_cache_sigtramp_ipi, (void *) addr, 1, 1);
+ }
+ #else
+ void sb1_flush_cache_sigtramp(unsigned long addr)
+@@ -498,7 +453,6 @@ static __init void probe_cache_sizes(voi
+ void sb1_cache_init(void)
+ {
+ extern char except_vec2_sb1;
+- extern char handle_vec2_sb1;
+
+ /* Special cache error handler for SB1 */
+ set_uncached_handler (0x100, &except_vec2_sb1, 0x80);
+@@ -520,7 +474,6 @@ void sb1_cache_init(void)
+
+ /* These routines are for Icache coherence with the Dcache */
+ flush_icache_range = sb1_flush_icache_range;
+- flush_icache_page = sb1_flush_icache_page;
+ flush_icache_all = __sb1_flush_icache_all; /* local only */
+
+ /* This implies an Icache flush too, so can't be nop'ed */
+@@ -552,5 +505,5 @@ void sb1_cache_init(void)
+ :
+ : "memory");
+
+- flush_cache_all();
++ local_sb1___flush_cache_all();
+ }
+diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
+index 5dfc9b1..f32ebde 100644
+--- a/arch/mips/mm/c-tx39.c
++++ b/arch/mips/mm/c-tx39.c
+@@ -248,33 +248,6 @@ static void tx39_flush_icache_range(unsi
+ }
+ }
+
+-/*
+- * Ok, this seriously sucks. We use them to flush a user page but don't
+- * know the virtual address, so we have to blast away the whole icache
+- * which is significantly more expensive than the real thing. Otoh we at
+- * least know the kernel address of the page so we can flush it
+- * selectivly.
+- */
+-static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+-{
+- unsigned long addr;
+- /*
+- * If there's no context yet, or the page isn't executable, no icache
+- * flush is needed.
+- */
+- if (!(vma->vm_flags & VM_EXEC))
+- return;
+-
+- addr = (unsigned long) page_address(page);
+- tx39_blast_dcache_page(addr);
+-
+- /*
+- * We're not sure of the virtual address(es) involved here, so
+- * we have to flush the entire I-cache.
+- */
+- tx39_blast_icache();
+-}
+-
+ static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size)
+ {
+ unsigned long end;
+@@ -382,7 +355,6 @@ void __init tx39_cache_init(void)
+ flush_cache_mm = (void *) tx39h_flush_icache_all;
+ flush_cache_range = (void *) tx39h_flush_icache_all;
+ flush_cache_page = (void *) tx39h_flush_icache_all;
+- flush_icache_page = (void *) tx39h_flush_icache_all;
+ flush_icache_range = (void *) tx39h_flush_icache_all;
+
+ flush_cache_sigtramp = (void *) tx39h_flush_icache_all;
+@@ -408,7 +380,6 @@ void __init tx39_cache_init(void)
+ flush_cache_mm = tx39_flush_cache_mm;
+ flush_cache_range = tx39_flush_cache_range;
+ flush_cache_page = tx39_flush_cache_page;
+- flush_icache_page = tx39_flush_icache_page;
+ flush_icache_range = tx39_flush_icache_range;
+
+ flush_cache_sigtramp = tx39_flush_cache_sigtramp;
+diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
+index ddd3a2d..caf807d 100644
+--- a/arch/mips/mm/cache.c
++++ b/arch/mips/mm/cache.c
+@@ -25,7 +25,6 @@ void (*flush_cache_range)(struct vm_area
+ void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
+ unsigned long pfn);
+ void (*flush_icache_range)(unsigned long start, unsigned long end);
+-void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page);
+
+ /* MIPS specific cache operations */
+ void (*flush_cache_sigtramp)(unsigned long addr);
+@@ -70,6 +69,8 @@ void __flush_dcache_page(struct page *pa
+ struct address_space *mapping = page_mapping(page);
+ unsigned long addr;
+
++ if (PageHighMem(page))
++ return;
+ if (mapping && !mapping_mapped(mapping)) {
+ SetPageDcacheDirty(page);
+ return;
+@@ -91,16 +92,16 @@ void __update_cache(struct vm_area_struc
+ {
+ struct page *page;
+ unsigned long pfn, addr;
++ int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
+
+ pfn = pte_pfn(pte);
+- if (pfn_valid(pfn) && (page = pfn_to_page(pfn), page_mapping(page)) &&
+- Page_dcache_dirty(page)) {
+- if (pages_do_alias((unsigned long)page_address(page),
+- address & PAGE_MASK)) {
+- addr = (unsigned long) page_address(page);
++ if (unlikely(!pfn_valid(pfn)))
++ return;
++ page = pfn_to_page(pfn);
++ if (page_mapping(page) && Page_dcache_dirty(page)) {
++ addr = (unsigned long) page_address(page);
++ if (exec || pages_do_alias(addr, address & PAGE_MASK))
+ flush_data_cache_page(addr);
+- }
+-
+ ClearPageDcacheDirty(page);
+ }
+ }
+diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
+index e3a6172..8423d85 100644
+--- a/arch/mips/mm/fault.c
++++ b/arch/mips/mm/fault.c
+@@ -89,7 +89,7 @@ good_area:
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
+ goto bad_area;
+ }
+
+@@ -171,7 +171,7 @@ no_context:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (tsk->pid == 1) {
++ if (is_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
+index c52497b..2de4d3c 100644
+--- a/arch/mips/mm/init.c
++++ b/arch/mips/mm/init.c
+@@ -30,11 +30,34 @@
+ #include <asm/cachectl.h>
+ #include <asm/cpu.h>
+ #include <asm/dma.h>
++#include <asm/kmap_types.h>
+ #include <asm/mmu_context.h>
+ #include <asm/sections.h>
+ #include <asm/pgtable.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlb.h>
++#include <asm/fixmap.h>
++
++/* Atomicity and interruptability */
++#ifdef CONFIG_MIPS_MT_SMTC
++
++#include <asm/mipsmtregs.h>
++
++#define ENTER_CRITICAL(flags) \
++ { \
++ unsigned int mvpflags; \
++ local_irq_save(flags);\
++ mvpflags = dvpe()
++#define EXIT_CRITICAL(flags) \
++ evpe(mvpflags); \
++ local_irq_restore(flags); \
++ }
++#else
++
++#define ENTER_CRITICAL(flags) local_irq_save(flags)
++#define EXIT_CRITICAL(flags) local_irq_restore(flags)
++
++#endif /* CONFIG_MIPS_MT_SMTC */
+
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+@@ -80,13 +103,142 @@ unsigned long setup_zero_pages(void)
+ return 1UL << order;
+ }
+
+-#ifdef CONFIG_HIGHMEM
+-pte_t *kmap_pte;
+-pgprot_t kmap_prot;
++/*
++ * These are almost like kmap_atomic / kunmap_atmic except they take an
++ * additional address argument as the hint.
++ */
+
+ #define kmap_get_fixmap_pte(vaddr) \
+ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr))
+
++#ifdef CONFIG_MIPS_MT_SMTC
++static pte_t *kmap_coherent_pte;
++static void __init kmap_coherent_init(void)
++{
++ unsigned long vaddr;
++
++ /* cache the first coherent kmap pte */
++ vaddr = __fix_to_virt(FIX_CMAP_BEGIN);
++ kmap_coherent_pte = kmap_get_fixmap_pte(vaddr);
++}
++#else
++static inline void kmap_coherent_init(void) {}
++#endif
++
++static inline void *kmap_coherent(struct page *page, unsigned long addr)
++{
++ enum fixed_addresses idx;
++ unsigned long vaddr, flags, entrylo;
++ unsigned long old_ctx;
++ pte_t pte;
++ int tlbidx;
++
++ inc_preempt_count();
++ idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
++#ifdef CONFIG_MIPS_MT_SMTC
++ idx += FIX_N_COLOURS * smp_processor_id();
++#endif
++ vaddr = __fix_to_virt(FIX_CMAP_END - idx);
++ pte = mk_pte(page, PAGE_KERNEL);
++#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
++ entrylo = pte.pte_high;
++#else
++ entrylo = pte_val(pte) >> 6;
++#endif
++
++ ENTER_CRITICAL(flags);
++ old_ctx = read_c0_entryhi();
++ write_c0_entryhi(vaddr & (PAGE_MASK << 1));
++ write_c0_entrylo0(entrylo);
++ write_c0_entrylo1(entrylo);
++#ifdef CONFIG_MIPS_MT_SMTC
++ set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte);
++ /* preload TLB instead of local_flush_tlb_one() */
++ mtc0_tlbw_hazard();
++ tlb_probe();
++ tlb_probe_hazard();
++ tlbidx = read_c0_index();
++ mtc0_tlbw_hazard();
++ if (tlbidx < 0)
++ tlb_write_random();
++ else
++ tlb_write_indexed();
++#else
++ tlbidx = read_c0_wired();
++ write_c0_wired(tlbidx + 1);
++ write_c0_index(tlbidx);
++ mtc0_tlbw_hazard();
++ tlb_write_indexed();
++#endif
++ tlbw_use_hazard();
++ write_c0_entryhi(old_ctx);
++ EXIT_CRITICAL(flags);
++
++ return (void*) vaddr;
++}
++
++#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
++
++static inline void kunmap_coherent(struct page *page)
++{
++#ifndef CONFIG_MIPS_MT_SMTC
++ unsigned int wired;
++ unsigned long flags, old_ctx;
++
++ ENTER_CRITICAL(flags);
++ old_ctx = read_c0_entryhi();
++ wired = read_c0_wired() - 1;
++ write_c0_wired(wired);
++ write_c0_index(wired);
++ write_c0_entryhi(UNIQUE_ENTRYHI(wired));
++ write_c0_entrylo0(0);
++ write_c0_entrylo1(0);
++ mtc0_tlbw_hazard();
++ tlb_write_indexed();
++ tlbw_use_hazard();
++ write_c0_entryhi(old_ctx);
++ EXIT_CRITICAL(flags);
++#endif
++ dec_preempt_count();
++ preempt_check_resched();
++}
++
++void copy_to_user_page(struct vm_area_struct *vma,
++ struct page *page, unsigned long vaddr, void *dst, const void *src,
++ unsigned long len)
++{
++ if (cpu_has_dc_aliases) {
++ void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
++ memcpy(vto, src, len);
++ kunmap_coherent(page);
++ } else
++ memcpy(dst, src, len);
++ if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc)
++ flush_cache_page(vma, vaddr, page_to_pfn(page));
++}
++
++EXPORT_SYMBOL(copy_to_user_page);
++
++void copy_from_user_page(struct vm_area_struct *vma,
++ struct page *page, unsigned long vaddr, void *dst, const void *src,
++ unsigned long len)
++{
++ if (cpu_has_dc_aliases) {
++ void *vfrom =
++ kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
++ memcpy(dst, vfrom, len);
++ kunmap_coherent(page);
++ } else
++ memcpy(dst, src, len);
++}
++
++EXPORT_SYMBOL(copy_from_user_page);
++
++
++#ifdef CONFIG_HIGHMEM
++pte_t *kmap_pte;
++pgprot_t kmap_prot;
++
+ static void __init kmap_init(void)
+ {
+ unsigned long kmap_vstart;
+@@ -97,11 +249,12 @@ static void __init kmap_init(void)
+
+ kmap_prot = PAGE_KERNEL;
+ }
++#endif /* CONFIG_HIGHMEM */
+
+-#ifdef CONFIG_32BIT
+ void __init fixrange_init(unsigned long start, unsigned long end,
+ pgd_t *pgd_base)
+ {
++#if defined(CONFIG_HIGHMEM) || defined(CONFIG_MIPS_MT_SMTC)
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+@@ -122,7 +275,7 @@ void __init fixrange_init(unsigned long
+ for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
+ if (pmd_none(*pmd)) {
+ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+- set_pmd(pmd, __pmd(pte));
++ set_pmd(pmd, __pmd((unsigned long)pte));
+ if (pte != pte_offset_kernel(pmd, 0))
+ BUG();
+ }
+@@ -132,9 +285,8 @@ void __init fixrange_init(unsigned long
+ }
+ j = 0;
+ }
++#endif
+ }
+-#endif /* CONFIG_32BIT */
+-#endif /* CONFIG_HIGHMEM */
+
+ #ifndef CONFIG_NEED_MULTIPLE_NODES
+ extern void pagetable_init(void);
+@@ -163,10 +315,10 @@ static int __init page_is_ram(unsigned l
+
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[] = { [0 ... MAX_NR_ZONES - 1] = 0 };
++ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+ unsigned long max_dma, high, low;
+ #ifndef CONFIG_FLATMEM
+- unsigned long zholes_size[] = { [0 ... MAX_NR_ZONES - 1] = 0 };
++ unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
+ unsigned long i, j, pfn;
+ #endif
+
+@@ -175,6 +327,7 @@ void __init paging_init(void)
+ #ifdef CONFIG_HIGHMEM
+ kmap_init();
+ #endif
++ kmap_coherent_init();
+
+ max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+ low = max_low_pfn;
+diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c
+index 3101d1d..cea7d0e 100644
+--- a/arch/mips/mm/ioremap.c
++++ b/arch/mips/mm/ioremap.c
+@@ -176,7 +176,7 @@ void __iomem * __ioremap(phys_t phys_add
+
+ #define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1)
+
+-void __iounmap(volatile void __iomem *addr)
++void __iounmap(const volatile void __iomem *addr)
+ {
+ struct vm_struct *p;
+
+diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c
+index b7c7492..d41fc58 100644
+--- a/arch/mips/mm/pg-r4k.c
++++ b/arch/mips/mm/pg-r4k.c
+@@ -270,6 +270,20 @@ static inline void build_addiu_a2_a0(uns
+ emit_instruction(mi);
+ }
+
++static inline void build_addiu_a2(unsigned long offset)
++{
++ union mips_instruction mi;
++
++ BUG_ON(offset > 0x7fff);
++
++ mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
++ mi.i_format.rs = 6; /* $a2 */
++ mi.i_format.rt = 6; /* $a2 */
++ mi.i_format.simmediate = offset;
++
++ emit_instruction(mi);
++}
++
+ static inline void build_addiu_a1(unsigned long offset)
+ {
+ union mips_instruction mi;
+@@ -333,6 +347,7 @@ static inline void build_jr_ra(void)
+ void __init build_clear_page(void)
+ {
+ unsigned int loop_start;
++ unsigned long off;
+
+ epc = (unsigned int *) &clear_page_array;
+ instruction_pending = 0;
+@@ -369,7 +384,12 @@ void __init build_clear_page(void)
+ }
+ }
+
+- build_addiu_a2_a0(PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0));
++ off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0);
++ if (off > 0x7fff) {
++ build_addiu_a2_a0(off >> 1);
++ build_addiu_a2(off >> 1);
++ } else
++ build_addiu_a2_a0(off);
+
+ if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
+ build_insn_word(0x3c01a000); /* lui $at, 0xa000 */
+@@ -420,12 +440,18 @@ dest = label();
+ void __init build_copy_page(void)
+ {
+ unsigned int loop_start;
++ unsigned long off;
+
+ epc = (unsigned int *) ©_page_array;
+ store_offset = load_offset = 0;
+ instruction_pending = 0;
+
+- build_addiu_a2_a0(PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0));
++ off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0);
++ if (off > 0x7fff) {
++ build_addiu_a2_a0(off >> 1);
++ build_addiu_a2(off >> 1);
++ } else
++ build_addiu_a2_a0(off);
+
+ if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
+ build_insn_word(0x3c01a000); /* lui $at, 0xa000 */
+diff --git a/arch/mips/mm/pgtable-32.c b/arch/mips/mm/pgtable-32.c
+index 4bdaa05..4a61e62 100644
+--- a/arch/mips/mm/pgtable-32.c
++++ b/arch/mips/mm/pgtable-32.c
+@@ -31,9 +31,10 @@ void pgd_init(unsigned long page)
+
+ void __init pagetable_init(void)
+ {
+-#ifdef CONFIG_HIGHMEM
+ unsigned long vaddr;
+- pgd_t *pgd, *pgd_base;
++ pgd_t *pgd_base;
++#ifdef CONFIG_HIGHMEM
++ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+@@ -44,7 +45,6 @@ void __init pagetable_init(void)
+ pgd_init((unsigned long)swapper_pg_dir
+ + sizeof(pgd_t) * USER_PTRS_PER_PGD);
+
+-#ifdef CONFIG_HIGHMEM
+ pgd_base = swapper_pg_dir;
+
+ /*
+@@ -53,6 +53,7 @@ void __init pagetable_init(void)
+ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+ fixrange_init(vaddr, 0, pgd_base);
+
++#ifdef CONFIG_HIGHMEM
+ /*
+ * Permanent kmaps:
+ */
+diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c
+index 44b5e97..8d600d3 100644
+--- a/arch/mips/mm/pgtable-64.c
++++ b/arch/mips/mm/pgtable-64.c
+@@ -8,6 +8,7 @@
+ */
+ #include <linux/init.h>
+ #include <linux/mm.h>
++#include <asm/fixmap.h>
+ #include <asm/pgtable.h>
+
+ void pgd_init(unsigned long page)
+@@ -52,7 +53,17 @@ void pmd_init(unsigned long addr, unsign
+
+ void __init pagetable_init(void)
+ {
++ unsigned long vaddr;
++ pgd_t *pgd_base;
++
+ /* Initialize the entire pgd. */
+ pgd_init((unsigned long)swapper_pg_dir);
+ pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
++
++ pgd_base = swapper_pg_dir;
++ /*
++ * Fixed mappings:
++ */
++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
++ fixrange_init(vaddr, 0, pgd_base);
+ }
+diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
+index 2cde1b7..2e0e21e 100644
+--- a/arch/mips/mm/tlb-r4k.c
++++ b/arch/mips/mm/tlb-r4k.c
+@@ -26,11 +26,6 @@ extern void build_tlb_refill_handler(voi
+ */
+ #define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
+
+-/* CP0 hazard avoidance. */
+-#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+- "nop; nop; nop; nop; nop; nop;\n\t" \
+- ".set reorder\n\t")
+-
+ /* Atomicity and interruptability */
+ #ifdef CONFIG_MIPS_MT_SMTC
+
+@@ -126,7 +121,7 @@ void local_flush_tlb_range(struct vm_are
+ start += (PAGE_SIZE << 1);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+- BARRIER;
++ tlb_probe_hazard();
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+@@ -168,7 +163,7 @@ void local_flush_tlb_kernel_range(unsign
+ start += (PAGE_SIZE << 1);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+- BARRIER;
++ tlb_probe_hazard();
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+@@ -202,7 +197,7 @@ void local_flush_tlb_page(struct vm_area
+ write_c0_entryhi(page | newpid);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+- BARRIER;
++ tlb_probe_hazard();
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+@@ -235,7 +230,7 @@ void local_flush_tlb_one(unsigned long p
+ write_c0_entryhi(page);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+- BARRIER;
++ tlb_probe_hazard();
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+@@ -279,7 +274,7 @@ void __update_tlb(struct vm_area_struct
+ pgdp = pgd_offset(vma->vm_mm, address);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+- BARRIER;
++ tlb_probe_hazard();
+ pudp = pud_offset(pgdp, address);
+ pmdp = pmd_offset(pudp, address);
+ idx = read_c0_index();
+@@ -320,7 +315,7 @@ static void r4k_update_mmu_cache_hwbug(s
+ pgdp = pgd_offset(vma->vm_mm, address);
+ mtc0_tlbw_hazard();
+ tlb_probe();
+- BARRIER;
++ tlb_probe_hazard();
+ pmdp = pmd_offset(pgdp, address);
+ idx = read_c0_index();
+ ptep = pte_offset_map(pmdp, address);
+@@ -351,7 +346,7 @@ void __init add_wired_entry(unsigned lon
+ wired = read_c0_wired();
+ write_c0_wired(wired + 1);
+ write_c0_index(wired);
+- BARRIER;
++ tlbw_use_hazard(); /* What is the hazard here? */
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+@@ -361,7 +356,7 @@ void __init add_wired_entry(unsigned lon
+ tlbw_use_hazard();
+
+ write_c0_entryhi(old_ctx);
+- BARRIER;
++ tlbw_use_hazard(); /* What is the hazard here? */
+ write_c0_pagemask(old_pagemask);
+ local_flush_tlb_all();
+ EXIT_CRITICAL(flags);
+diff --git a/arch/mips/mm/tlbex-fault.S b/arch/mips/mm/tlbex-fault.S
+index 9e7f417..e99eaa1 100644
+--- a/arch/mips/mm/tlbex-fault.S
++++ b/arch/mips/mm/tlbex-fault.S
+@@ -19,8 +19,8 @@
+ move a0, sp
+ REG_S a2, PT_BVADDR(sp)
+ li a1, \write
+- jal do_page_fault
+- j ret_from_exception
++ PTR_LA ra, ret_from_exception
++ j do_page_fault
+ END(tlb_do_page_fault_\write)
+ .endm
+
+diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
+index 375e099..fec318a 100644
+--- a/arch/mips/mm/tlbex.c
++++ b/arch/mips/mm/tlbex.c
+@@ -102,7 +102,7 @@ enum opcode {
+ insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
+ insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
+ insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
+- insn_dsll, insn_dsll32, insn_dsra, insn_dsrl,
++ insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
+ insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
+ insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
+ insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
+@@ -145,6 +145,7 @@ static __initdata struct insn insn_table
+ { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
+ { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
+ { insn_dsrl, M(spec_op,0,0,0,0,dsrl_op), RT | RD | RE },
++ { insn_dsrl32, M(spec_op,0,0,0,0,dsrl32_op), RT | RD | RE },
+ { insn_dsubu, M(spec_op,0,0,0,0,dsubu_op), RS | RT | RD },
+ { insn_eret, M(cop0_op,cop_op,0,0,0,eret_op), 0 },
+ { insn_j, M(j_op,0,0,0,0,0), JIMM },
+@@ -385,6 +386,7 @@ I_u2u1u3(_dsll);
+ I_u2u1u3(_dsll32);
+ I_u2u1u3(_dsra);
+ I_u2u1u3(_dsrl);
++I_u2u1u3(_dsrl32);
+ I_u3u1u2(_dsubu);
+ I_0(_eret);
+ I_u1(_j);
+@@ -996,7 +998,12 @@ build_get_pmde64(u32 **p, struct label *
+ #endif
+
+ l_vmalloc_done(l, *p);
+- i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3); /* get pgd offset in bytes */
++
++ if (PGDIR_SHIFT - 3 < 32) /* get pgd offset in bytes */
++ i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
++ else
++ i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
++
+ i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
+ i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
+ i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+@@ -1073,7 +1080,7 @@ build_get_pgde32(u32 **p, unsigned int t
+
+ static __init void build_adjust_context(u32 **p, unsigned int ctx)
+ {
+- unsigned int shift = 4 - (PTE_T_LOG2 + 1);
++ unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12;
+ unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1);
+
+ switch (current_cpu_data.cputype) {
+@@ -1211,7 +1218,7 @@ static void __init build_r4000_tlb_refil
+ * Overflow check: For the 64bit handler, we need at least one
+ * free instruction slot for the wrap-around branch. In worst
+ * case, if the intended insertion point is a delay slot, we
+- * need three, with the the second nop'ed and the third being
++ * need three, with the second nop'ed and the third being
+ * unused.
+ */
+ #ifdef CONFIG_32BIT
+diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
+index f906746..2efb25a 100644
+--- a/arch/mips/momentum/jaguar_atx/irq.c
++++ b/arch/mips/momentum/jaguar_atx/irq.c
+@@ -40,33 +40,33 @@
+ #include <asm/mipsregs.h>
+ #include <asm/time.h>
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP0)
+- do_IRQ(0, regs);
++ do_IRQ(0);
+ else if (pending & STATUSF_IP1)
+- do_IRQ(1, regs);
++ do_IRQ(1);
+ else if (pending & STATUSF_IP2)
+- do_IRQ(2, regs);
++ do_IRQ(2);
+ else if (pending & STATUSF_IP3)
+- do_IRQ(3, regs);
++ do_IRQ(3);
+ else if (pending & STATUSF_IP4)
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ else if (pending & STATUSF_IP5)
+- do_IRQ(5, regs);
++ do_IRQ(5);
+ else if (pending & STATUSF_IP6)
+- do_IRQ(6, regs);
++ do_IRQ(6);
+ else if (pending & STATUSF_IP7)
+- ll_timer_interrupt(7, regs);
++ ll_timer_interrupt(7);
+ else {
+ /*
+ * Now look at the extended interrupts
+ */
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+ if (pending & STATUSF_IP8)
+- ll_mv64340_irq(regs);
++ ll_mv64340_irq();
+ }
+ }
+
+diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
+index e6fe299..5a51014 100644
+--- a/arch/mips/momentum/jaguar_atx/setup.c
++++ b/arch/mips/momentum/jaguar_atx/setup.c
+@@ -62,7 +62,6 @@
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/tlbflush.h>
+
+diff --git a/arch/mips/momentum/ocelot_3/Makefile b/arch/mips/momentum/ocelot_3/Makefile
+index 8bcea64..d5a090a 100644
+--- a/arch/mips/momentum/ocelot_3/Makefile
++++ b/arch/mips/momentum/ocelot_3/Makefile
+@@ -5,4 +5,4 @@
+ # removes any old dependencies. DON'T put your own dependencies here
+ # unless it's something special (ie not a .c file).
+ #
+-obj-y += irq.o prom.o reset.o setup.o
++obj-y += irq.o platform.o prom.o reset.o setup.o
+diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
+index 793782a..cea0e5d 100644
+--- a/arch/mips/momentum/ocelot_3/irq.c
++++ b/arch/mips/momentum/ocelot_3/irq.c
+@@ -75,26 +75,26 @@ void __init arch_init_irq(void)
+
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP0)
+- do_IRQ(0, regs);
++ do_IRQ(0);
+ else if (pending & STATUSF_IP1)
+- do_IRQ(1, regs);
++ do_IRQ(1);
+ else if (pending & STATUSF_IP2)
+- do_IRQ(2, regs);
++ do_IRQ(2);
+ else if (pending & STATUSF_IP3)
+- do_IRQ(3, regs);
++ do_IRQ(3);
+ else if (pending & STATUSF_IP4)
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ else if (pending & STATUSF_IP5)
+- do_IRQ(5, regs);
++ do_IRQ(5);
+ else if (pending & STATUSF_IP6)
+- do_IRQ(6, regs);
++ do_IRQ(6);
+ else if (pending & STATUSF_IP7)
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ else {
+ /*
+ * Now look at the extended interrupts
+@@ -102,8 +102,8 @@ asmlinkage void plat_irq_dispatch(struct
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+
+ if (pending & STATUSF_IP8)
+- ll_mv64340_irq(regs);
++ ll_mv64340_irq();
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+ }
+diff --git a/arch/mips/momentum/ocelot_3/ocelot_3_fpga.h b/arch/mips/momentum/ocelot_3/ocelot_3_fpga.h
+index 227e429..5710a90 100644
+--- a/arch/mips/momentum/ocelot_3/ocelot_3_fpga.h
++++ b/arch/mips/momentum/ocelot_3/ocelot_3_fpga.h
+@@ -51,7 +51,9 @@
+
+ extern unsigned long ocelot_fpga_base;
+
+-#define OCELOT_FPGA_WRITE(x, y) writeb(x, ocelot_fpga_base + OCELOT_3_REG_##y)
+-#define OCELOT_FPGA_READ(x) readb(ocelot_fpga_base + OCELOT_3_REG_##x)
++#define __FPGA_REG_TO_ADDR(reg) \
++ ((void *) ocelot_fpga_base + OCELOT_3_REG_##reg)
++#define OCELOT_FPGA_WRITE(x, reg) writeb(x, __FPGA_REG_TO_ADDR(reg))
++#define OCELOT_FPGA_READ(reg) readb(__FPGA_REG_TO_ADDR(reg))
+
+ #endif
+diff --git a/arch/mips/momentum/ocelot_3/platform.c b/arch/mips/momentum/ocelot_3/platform.c
+new file mode 100644
+index 0000000..eefe584
+--- /dev/null
++++ b/arch/mips/momentum/ocelot_3/platform.c
+@@ -0,0 +1,235 @@
++#include <linux/delay.h>
++#include <linux/if_ether.h>
++#include <linux/ioport.h>
++#include <linux/mv643xx.h>
++#include <linux/platform_device.h>
++
++#include "ocelot_3_fpga.h"
++
++#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
++
++static struct resource mv643xx_eth_shared_resources[] = {
++ [0] = {
++ .name = "ethernet shared base",
++ .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
++ .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
++ MV643XX_ETH_SHARED_REGS_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device mv643xx_eth_shared_device = {
++ .name = MV643XX_ETH_SHARED_NAME,
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources),
++ .resource = mv643xx_eth_shared_resources,
++};
++
++#define MV_SRAM_BASE 0xfe000000UL
++#define MV_SRAM_SIZE (256 * 1024)
++
++#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4)
++#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4)
++
++#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE
++#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2))
++
++#define MV64x60_IRQ_ETH_0 48
++#define MV64x60_IRQ_ETH_1 49
++#define MV64x60_IRQ_ETH_2 50
++
++#ifdef CONFIG_MV643XX_ETH_0
++
++static struct resource mv64x60_eth0_resources[] = {
++ [0] = {
++ .name = "eth0 irq",
++ .start = MV64x60_IRQ_ETH_0,
++ .end = MV64x60_IRQ_ETH_0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static char eth0_mac_addr[ETH_ALEN];
++
++static struct mv643xx_eth_platform_data eth0_pd = {
++ .mac_addr = eth0_mac_addr,
++
++ .tx_sram_addr = MV_SRAM_BASE_ETH0,
++ .tx_sram_size = MV_SRAM_TXRING_SIZE,
++ .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
++
++ .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
++ .rx_sram_size = MV_SRAM_RXRING_SIZE,
++ .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
++};
++
++static struct platform_device eth0_device = {
++ .name = MV643XX_ETH_NAME,
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mv64x60_eth0_resources),
++ .resource = mv64x60_eth0_resources,
++ .dev = {
++ .platform_data = ð0_pd,
++ },
++};
++#endif /* CONFIG_MV643XX_ETH_0 */
++
++#ifdef CONFIG_MV643XX_ETH_1
++
++static struct resource mv64x60_eth1_resources[] = {
++ [0] = {
++ .name = "eth1 irq",
++ .start = MV64x60_IRQ_ETH_1,
++ .end = MV64x60_IRQ_ETH_1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static char eth1_mac_addr[ETH_ALEN];
++
++static struct mv643xx_eth_platform_data eth1_pd = {
++ .mac_addr = eth1_mac_addr,
++
++ .tx_sram_addr = MV_SRAM_BASE_ETH1,
++ .tx_sram_size = MV_SRAM_TXRING_SIZE,
++ .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
++
++ .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
++ .rx_sram_size = MV_SRAM_RXRING_SIZE,
++ .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
++};
++
++static struct platform_device eth1_device = {
++ .name = MV643XX_ETH_NAME,
++ .id = 1,
++ .num_resources = ARRAY_SIZE(mv64x60_eth1_resources),
++ .resource = mv64x60_eth1_resources,
++ .dev = {
++ .platform_data = ð1_pd,
++ },
++};
++#endif /* CONFIG_MV643XX_ETH_1 */
++
++#ifdef CONFIG_MV643XX_ETH_2
++
++static struct resource mv64x60_eth2_resources[] = {
++ [0] = {
++ .name = "eth2 irq",
++ .start = MV64x60_IRQ_ETH_2,
++ .end = MV64x60_IRQ_ETH_2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static char eth2_mac_addr[ETH_ALEN];
++
++static struct mv643xx_eth_platform_data eth2_pd = {
++ .mac_addr = eth2_mac_addr,
++};
++
++static struct platform_device eth2_device = {
++ .name = MV643XX_ETH_NAME,
++ .id = 1,
++ .num_resources = ARRAY_SIZE(mv64x60_eth2_resources),
++ .resource = mv64x60_eth2_resources,
++ .dev = {
++ .platform_data = ð2_pd,
++ },
++};
++#endif /* CONFIG_MV643XX_ETH_2 */
++
++static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
++ &mv643xx_eth_shared_device,
++#ifdef CONFIG_MV643XX_ETH_0
++ ð0_device,
++#endif
++#ifdef CONFIG_MV643XX_ETH_1
++ ð1_device,
++#endif
++#ifdef CONFIG_MV643XX_ETH_2
++ ð2_device,
++#endif
++};
++
++static u8 __init exchange_bit(u8 val, u8 cs)
++{
++ /* place the data */
++ OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
++ udelay(1);
++
++ /* turn the clock on */
++ OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
++ udelay(1);
++
++ /* turn the clock off and read-strobe */
++ OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
++
++ /* return the data */
++ return (OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
++}
++
++static void __init get_mac(char dest[6])
++{
++ u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++ int i,j;
++
++ for (i = 0; i < 12; i++)
++ exchange_bit(read_opcode[i], 1);
++
++ for (j = 0; j < 6; j++) {
++ dest[j] = 0;
++ for (i = 0; i < 8; i++) {
++ dest[j] <<= 1;
++ dest[j] |= exchange_bit(0, 1);
++ }
++ }
++
++ /* turn off CS */
++ exchange_bit(0,0);
++}
++
++/*
++ * Copy and increment ethernet MAC address by a small value.
++ *
++ * This is useful for systems where the only one MAC address is stored in
++ * non-volatile memory for multiple ports.
++ */
++static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
++ unsigned int add)
++{
++ int i;
++
++ BUG_ON(add >= 256);
++
++ for (i = ETH_ALEN; i >= 0; i--) {
++ dst[i] = src[i] + add;
++ add = dst[i] < src[i]; /* compute carry */
++ }
++
++ WARN_ON(add);
++}
++
++static int __init mv643xx_eth_add_pds(void)
++{
++ unsigned char mac[ETH_ALEN];
++ int ret;
++
++ get_mac(mac);
++#ifdef CONFIG_MV643XX_ETH_0
++ eth_mac_add(eth1_mac_addr, mac, 0);
++#endif
++#ifdef CONFIG_MV643XX_ETH_1
++ eth_mac_add(eth1_mac_addr, mac, 1);
++#endif
++#ifdef CONFIG_MV643XX_ETH_2
++ eth_mac_add(eth2_mac_addr, mac, 2);
++#endif
++ ret = platform_add_devices(mv643xx_eth_pd_devs,
++ ARRAY_SIZE(mv643xx_eth_pd_devs));
++
++ return ret;
++}
++
++device_initcall(mv643xx_eth_add_pds);
++
++#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
+diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c
+index 296d945..6ce9b7f 100644
+--- a/arch/mips/momentum/ocelot_3/prom.c
++++ b/arch/mips/momentum/ocelot_3/prom.c
+@@ -34,64 +34,11 @@ struct callvectors* debug_vectors;
+ extern unsigned long marvell_base;
+ extern unsigned long cpu_clock;
+
+-#ifdef CONFIG_MV643XX_ETH
+-extern unsigned char prom_mac_addr_base[6];
+-#endif
+-
+ const char *get_system_type(void)
+ {
+ return "Momentum Ocelot-3";
+ }
+
+-#ifdef CONFIG_MV643XX_ETH
+-void burn_clocks(void)
+-{
+- int i;
+-
+- /* this loop should burn at least 1us -- this should be plenty */
+- for (i = 0; i < 0x10000; i++)
+- ;
+-}
+-
+-u8 exchange_bit(u8 val, u8 cs)
+-{
+- /* place the data */
+- OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
+- burn_clocks();
+-
+- /* turn the clock on */
+- OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
+- burn_clocks();
+-
+- /* turn the clock off and read-strobe */
+- OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
+-
+- /* return the data */
+- return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
+-}
+-
+-void get_mac(char dest[6])
+-{
+- u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+- int i,j;
+-
+- for (i = 0; i < 12; i++)
+- exchange_bit(read_opcode[i], 1);
+-
+- for (j = 0; j < 6; j++) {
+- dest[j] = 0;
+- for (i = 0; i < 8; i++) {
+- dest[j] <<= 1;
+- dest[j] |= exchange_bit(0, 1);
+- }
+- }
+-
+- /* turn off CS */
+- exchange_bit(0,0);
+-}
+-#endif
+-
+-
+ #ifdef CONFIG_64BIT
+
+ unsigned long signext(unsigned long addr)
+@@ -228,11 +175,6 @@ void __init prom_init(void)
+ mips_machgroup = MACH_GROUP_MOMENCO;
+ mips_machtype = MACH_MOMENCO_OCELOT_3;
+
+-#ifdef CONFIG_MV643XX_ETH
+- /* get the base MAC address for on-board ethernet ports */
+- get_mac(prom_mac_addr_base);
+-#endif
+-
+ #ifndef CONFIG_64BIT
+ debug_vectors->printf("Booting Linux kernel...\n");
+ #endif
+diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
+index 435d078..ff0829f 100644
+--- a/arch/mips/momentum/ocelot_3/setup.c
++++ b/arch/mips/momentum/ocelot_3/setup.c
+@@ -4,7 +4,7 @@
+ * BRIEF MODULE DESCRIPTION
+ * Momentum Computer Ocelot-3 board dependent boot routines
+ *
+- * Copyright (C) 1996, 1997, 01, 05 Ralf Baechle
++ * Copyright (C) 1996, 1997, 01, 05 - 06 Ralf Baechle
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2002 Momentum Computer
+@@ -67,7 +67,6 @@
+ #include <asm/irq.h>
+ #include <asm/pci.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/mc146818rtc.h>
+ #include <asm/tlbflush.h>
+diff --git a/arch/mips/momentum/ocelot_c/Makefile b/arch/mips/momentum/ocelot_c/Makefile
+index 94802b4..d69161a 100644
+--- a/arch/mips/momentum/ocelot_c/Makefile
++++ b/arch/mips/momentum/ocelot_c/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for Momentum Computer's Ocelot-C and -CS boards.
+ #
+
+-obj-y += cpci-irq.o irq.o prom.o reset.o \
++obj-y += cpci-irq.o irq.o platform.o prom.o reset.o \
+ setup.o uart-irq.o
+
+ obj-$(CONFIG_KGDB) += dbg_io.o
+diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c
+index a5dc230..47e3fa3 100644
+--- a/arch/mips/momentum/ocelot_c/cpci-irq.c
++++ b/arch/mips/momentum/ocelot_c/cpci-irq.c
+@@ -21,7 +21,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <linux/kernel.h>
+-#include <asm/ptrace.h>
+ #include <linux/sched.h>
+ #include <linux/kernel_stat.h>
+ #include <asm/io.h>
+@@ -112,7 +111,7 @@ static void end_cpci_irq(unsigned int ir
+ * Interrupt handler for interrupts coming from the FPGA chip.
+ * It could be built in ethernet ports etc...
+ */
+-void ll_cpci_irq(struct pt_regs *regs)
++void ll_cpci_irq(void)
+ {
+ unsigned int irq_src, irq_mask;
+
+@@ -123,7 +122,7 @@ void ll_cpci_irq(struct pt_regs *regs)
+ /* mask for just the interrupts we want */
+ irq_src &= ~irq_mask;
+
+- do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE, regs);
++ do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE);
+ }
+
+ #define shutdown_cpci_irq disable_cpci_irq
+diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c
+index 9d44ae1..ea65223 100644
+--- a/arch/mips/momentum/ocelot_c/irq.c
++++ b/arch/mips/momentum/ocelot_c/irq.c
+@@ -59,31 +59,31 @@ static struct irqaction cascade_mv64340
+ no_action, IRQF_DISABLED, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL
+ };
+
+-extern void ll_uart_irq(struct pt_regs *regs);
+-extern void ll_cpci_irq(struct pt_regs *regs);
++extern void ll_uart_irq(void);
++extern void ll_cpci_irq(void);
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP0)
+- do_IRQ(0, regs);
++ do_IRQ(0);
+ else if (pending & STATUSF_IP1)
+- do_IRQ(1, regs);
++ do_IRQ(1);
+ else if (pending & STATUSF_IP2)
+- do_IRQ(2, regs);
++ do_IRQ(2);
+ else if (pending & STATUSF_IP3)
+- ll_uart_irq(regs);
++ ll_uart_irq();
+ else if (pending & STATUSF_IP4)
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ else if (pending & STATUSF_IP5)
+- ll_cpci_irq(regs);
++ ll_cpci_irq();
+ else if (pending & STATUSF_IP6)
+- ll_mv64340_irq(regs);
++ ll_mv64340_irq();
+ else if (pending & STATUSF_IP7)
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ void __init arch_init_irq(void)
+diff --git a/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h b/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
+index 7228cd1..f0f5581 100644
+--- a/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
++++ b/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
+@@ -53,7 +53,9 @@
+ #define OCELOT_C_REG_INTSET 0xe
+ #define OCELOT_C_REG_INTCLR 0xf
+
+-#define OCELOT_FPGA_WRITE(x, y) writeb(x, OCELOT_C_CS0_ADDR + OCELOT_C_REG_##y)
+-#define OCELOT_FPGA_READ(x) readb(OCELOT_C_CS0_ADDR + OCELOT_C_REG_##x)
++#define __FPGA_REG_TO_ADDR(reg) \
++ ((void *) OCELOT_C_CS0_ADDR + OCELOT_C_REG_##reg)
++#define OCELOT_FPGA_WRITE(x, reg) writeb(x, __FPGA_REG_TO_ADDR(reg))
++#define OCELOT_FPGA_READ(reg) readb(__FPGA_REG_TO_ADDR(reg))
+
+ #endif
+diff --git a/arch/mips/momentum/ocelot_c/platform.c b/arch/mips/momentum/ocelot_c/platform.c
+new file mode 100644
+index 0000000..6c495b2
+--- /dev/null
++++ b/arch/mips/momentum/ocelot_c/platform.c
+@@ -0,0 +1,201 @@
++#include <linux/delay.h>
++#include <linux/if_ether.h>
++#include <linux/ioport.h>
++#include <linux/mv643xx.h>
++#include <linux/platform_device.h>
++
++#include "ocelot_c_fpga.h"
++
++#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
++
++static struct resource mv643xx_eth_shared_resources[] = {
++ [0] = {
++ .name = "ethernet shared base",
++ .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
++ .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
++ MV643XX_ETH_SHARED_REGS_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device mv643xx_eth_shared_device = {
++ .name = MV643XX_ETH_SHARED_NAME,
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources),
++ .resource = mv643xx_eth_shared_resources,
++};
++
++#define MV_SRAM_BASE 0xfe000000UL
++#define MV_SRAM_SIZE (256 * 1024)
++
++#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4)
++#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4)
++
++#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE
++#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2))
++
++#define MV64x60_IRQ_ETH_0 48
++#define MV64x60_IRQ_ETH_1 49
++
++#ifdef CONFIG_MV643XX_ETH_0
++
++static struct resource mv64x60_eth0_resources[] = {
++ [0] = {
++ .name = "eth0 irq",
++ .start = MV64x60_IRQ_ETH_0,
++ .end = MV64x60_IRQ_ETH_0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static char eth0_mac_addr[ETH_ALEN];
++
++static struct mv643xx_eth_platform_data eth0_pd = {
++ .mac_addr = eth0_mac_addr,
++
++ .tx_sram_addr = MV_SRAM_BASE_ETH0,
++ .tx_sram_size = MV_SRAM_TXRING_SIZE,
++ .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
++
++ .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
++ .rx_sram_size = MV_SRAM_RXRING_SIZE,
++ .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
++};
++
++static struct platform_device eth0_device = {
++ .name = MV643XX_ETH_NAME,
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mv64x60_eth0_resources),
++ .resource = mv64x60_eth0_resources,
++ .dev = {
++ .platform_data = ð0_pd,
++ },
++};
++#endif /* CONFIG_MV643XX_ETH_0 */
++
++#ifdef CONFIG_MV643XX_ETH_1
++
++static struct resource mv64x60_eth1_resources[] = {
++ [0] = {
++ .name = "eth1 irq",
++ .start = MV64x60_IRQ_ETH_1,
++ .end = MV64x60_IRQ_ETH_1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static char eth1_mac_addr[ETH_ALEN];
++
++static struct mv643xx_eth_platform_data eth1_pd = {
++ .mac_addr = eth1_mac_addr,
++
++ .tx_sram_addr = MV_SRAM_BASE_ETH1,
++ .tx_sram_size = MV_SRAM_TXRING_SIZE,
++ .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
++
++ .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
++ .rx_sram_size = MV_SRAM_RXRING_SIZE,
++ .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
++};
++
++static struct platform_device eth1_device = {
++ .name = MV643XX_ETH_NAME,
++ .id = 1,
++ .num_resources = ARRAY_SIZE(mv64x60_eth1_resources),
++ .resource = mv64x60_eth1_resources,
++ .dev = {
++ .platform_data = ð1_pd,
++ },
++};
++#endif /* CONFIG_MV643XX_ETH_1 */
++
++static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
++ &mv643xx_eth_shared_device,
++#ifdef CONFIG_MV643XX_ETH_0
++ ð0_device,
++#endif
++#ifdef CONFIG_MV643XX_ETH_1
++ ð1_device,
++#endif
++ /* The third port is not wired up on the Ocelot C */
++};
++
++static u8 __init exchange_bit(u8 val, u8 cs)
++{
++ /* place the data */
++ OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
++ udelay(1);
++
++ /* turn the clock on */
++ OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
++ udelay(1);
++
++ /* turn the clock off and read-strobe */
++ OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
++
++ /* return the data */
++ return (OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
++}
++
++static void __init get_mac(char dest[6])
++{
++ u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++ int i,j;
++
++ for (i = 0; i < 12; i++)
++ exchange_bit(read_opcode[i], 1);
++
++ for (j = 0; j < 6; j++) {
++ dest[j] = 0;
++ for (i = 0; i < 8; i++) {
++ dest[j] <<= 1;
++ dest[j] |= exchange_bit(0, 1);
++ }
++ }
++
++ /* turn off CS */
++ exchange_bit(0,0);
++}
++
++/*
++ * Copy and increment ethernet MAC address by a small value.
++ *
++ * This is useful for systems where the only one MAC address is stored in
++ * non-volatile memory for multiple ports.
++ */
++static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
++ unsigned int add)
++{
++ int i;
++
++ BUG_ON(add >= 256);
++
++ for (i = ETH_ALEN; i >= 0; i--) {
++ dst[i] = src[i] + add;
++ add = dst[i] < src[i]; /* compute carry */
++ }
++
++ WARN_ON(add);
++}
++
++static int __init mv643xx_eth_add_pds(void)
++{
++ unsigned char mac[ETH_ALEN];
++ int ret;
++
++ get_mac(mac);
++#ifdef CONFIG_MV643XX_ETH_0
++ eth_mac_add(eth1_mac_addr, mac, 0);
++#endif
++#ifdef CONFIG_MV643XX_ETH_1
++ eth_mac_add(eth1_mac_addr, mac, 1);
++#endif
++ ret = platform_add_devices(mv643xx_eth_pd_devs,
++ ARRAY_SIZE(mv643xx_eth_pd_devs));
++
++ return ret;
++}
++
++device_initcall(mv643xx_eth_add_pds);
++
++#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
+diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c
+index 4c50a14..d0b77e1 100644
+--- a/arch/mips/momentum/ocelot_c/prom.c
++++ b/arch/mips/momentum/ocelot_c/prom.c
+@@ -29,11 +29,7 @@
+ struct callvectors* debug_vectors;
+
+ extern unsigned long marvell_base;
+-extern unsigned long cpu_clock;
+-
+-#ifdef CONFIG_MV643XX_ETH
+-extern unsigned char prom_mac_addr_base[6];
+-#endif
++extern unsigned int cpu_clock;
+
+ const char *get_system_type(void)
+ {
+@@ -44,55 +40,6 @@ const char *get_system_type(void)
+ #endif
+ }
+
+-#ifdef CONFIG_MV643XX_ETH
+-static void burn_clocks(void)
+-{
+- int i;
+-
+- /* this loop should burn at least 1us -- this should be plenty */
+- for (i = 0; i < 0x10000; i++)
+- ;
+-}
+-
+-static u8 exchange_bit(u8 val, u8 cs)
+-{
+- /* place the data */
+- OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
+- burn_clocks();
+-
+- /* turn the clock on */
+- OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
+- burn_clocks();
+-
+- /* turn the clock off and read-strobe */
+- OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
+-
+- /* return the data */
+- return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
+-}
+-
+-void get_mac(char dest[6])
+-{
+- u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+- int i,j;
+-
+- for (i = 0; i < 12; i++)
+- exchange_bit(read_opcode[i], 1);
+-
+- for (j = 0; j < 6; j++) {
+- dest[j] = 0;
+- for (i = 0; i < 8; i++) {
+- dest[j] <<= 1;
+- dest[j] |= exchange_bit(0, 1);
+- }
+- }
+-
+- /* turn off CS */
+- exchange_bit(0,0);
+-}
+-#endif
+-
+-
+ #ifdef CONFIG_64BIT
+
+ unsigned long signext(unsigned long addr)
+@@ -226,11 +173,6 @@ void __init prom_init(void)
+ mips_machgroup = MACH_GROUP_MOMENCO;
+ mips_machtype = MACH_MOMENCO_OCELOT_C;
+
+-#ifdef CONFIG_MV643XX_ETH
+- /* get the base MAC address for on-board ethernet ports */
+- get_mac(prom_mac_addr_base);
+-#endif
+-
+ #ifndef CONFIG_64BIT
+ debug_vectors->printf("Booting Linux kernel...\n");
+ #endif
+diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c
+index 36f570e..0b6b233 100644
+--- a/arch/mips/momentum/ocelot_c/setup.c
++++ b/arch/mips/momentum/ocelot_c/setup.c
+@@ -62,7 +62,6 @@
+ #include <asm/irq.h>
+ #include <asm/pci.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/marvell.h>
+ #include <linux/bootmem.h>
+@@ -70,8 +69,7 @@
+ #include "ocelot_c_fpga.h"
+
+ unsigned long marvell_base;
+-extern unsigned long mv64340_sram_base;
+-unsigned long cpu_clock;
++unsigned int cpu_clock;
+
+ /* These functions are used for rebooting or halting the machine*/
+ extern void momenco_ocelot_restart(char *command);
+@@ -120,7 +118,6 @@ void PMON_v2_setup(void)
+ add_wired_entry(ENTRYLO(0xfe000000), ENTRYLO(0xff000000), 0xfffffffffe000000, PM_16M);
+
+ marvell_base = 0xfffffffff4000000;
+- mv64340_sram_base = 0xfffffffffe000000;
+ #else
+ /* marvell and extra space */
+ add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), 0xf4000000, PM_64K);
+@@ -130,7 +127,6 @@ void PMON_v2_setup(void)
+ add_wired_entry(ENTRYLO(0xfe000000), ENTRYLO(0xff000000), 0xfe000000, PM_16M);
+
+ marvell_base = 0xf4000000;
+- mv64340_sram_base = 0xfe000000;
+ #endif
+ }
+
+@@ -347,22 +343,20 @@ void __init plat_mem_setup(void)
+ }
+ }
+
+-#ifndef CONFIG_64BIT
+-/* This needs to be one of the first initcalls, because no I/O port access
+- can work before this */
++/*
++ * This needs to be one of the first initcalls, because no I/O port access
++ * can work before this
++ */
+ static int io_base_ioremap(void)
+ {
+- /* we're mapping PCI accesses from 0xc0000000 to 0xf0000000 */
+- void *io_remap_range = ioremap(0xc0000000, 0x30000000);
++ void __iomem * io_remap_range = ioremap(0xc0000000UL, 0x10000);
+
+- if (!io_remap_range) {
++ if (!io_remap_range)
+ panic("Could not ioremap I/O port range");
+- }
+- printk("io_remap_range set at 0x%08x\n", (uint32_t)io_remap_range);
+- set_io_port_base(io_remap_range - 0xc0000000);
++
++ set_io_port_base((unsigned long) io_remap_range);
+
+ return 0;
+ }
+
+ module_init(io_base_ioremap);
+-#endif
+diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c
+index 9f33d8f..510257d 100644
+--- a/arch/mips/momentum/ocelot_c/uart-irq.c
++++ b/arch/mips/momentum/ocelot_c/uart-irq.c
+@@ -16,7 +16,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <linux/kernel.h>
+-#include <asm/ptrace.h>
+ #include <linux/sched.h>
+ #include <linux/kernel_stat.h>
+ #include <asm/io.h>
+@@ -105,7 +104,7 @@ static void end_uart_irq(unsigned int ir
+ /*
+ * Interrupt handler for interrupts coming from the FPGA chip.
+ */
+-void ll_uart_irq(struct pt_regs *regs)
++void ll_uart_irq(void)
+ {
+ unsigned int irq_src, irq_mask;
+
+@@ -116,7 +115,7 @@ void ll_uart_irq(struct pt_regs *regs)
+ /* mask for just the interrupts we want */
+ irq_src &= ~irq_mask;
+
+- do_IRQ(ls1bit8(irq_src) + 74, regs);
++ do_IRQ(ls1bit8(irq_src) + 74);
+ }
+
+ #define shutdown_uart_irq disable_uart_irq
+diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c
+index 9fb2493..e5576bd 100644
+--- a/arch/mips/momentum/ocelot_g/gt-irq.c
++++ b/arch/mips/momentum/ocelot_g/gt-irq.c
+@@ -14,7 +14,6 @@
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/kernel.h>
+-#include <asm/ptrace.h>
+ #include <linux/sched.h>
+ #include <linux/kernel_stat.h>
+ #include <asm/gt64240.h>
+@@ -28,7 +27,7 @@ unsigned long bus_clock;
+ * be handled and ack'ed differently than other MIPS interrupts.
+ */
+
+-#if CURRENTLY_UNUSED
++#if 0
+
+ struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH];
+ void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr);
+@@ -96,7 +95,7 @@ int disable_galileo_irq(int int_cause, i
+ return 0;
+ return 1;
+ }
+-#endif /* UNUSED */
++#endif /* 0 */
+
+ /*
+ * Interrupt handler for interrupts coming from the Galileo chip via P0_INT#.
+@@ -108,7 +107,7 @@ int disable_galileo_irq(int int_cause, i
+ * we keep this particular structure in the function.
+ */
+
+-static irqreturn_t gt64240_p0int_irq(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t gt64240_p0int_irq(int irq, void *dev)
+ {
+ uint32_t irq_src, irq_src_mask;
+ int handled;
+@@ -133,9 +132,9 @@ static irqreturn_t gt64240_p0int_irq(int
+ MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);
+
+ /* handle the timer call */
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ }
+
+@@ -197,7 +196,7 @@ void gt64240_time_init(void)
+
+ void gt64240_irq_init(void)
+ {
+-#if CURRENTLY_UNUSED
++#if 0
+ int i, j;
+
+ /* Reset irq handlers pointers to NULL */
+@@ -209,5 +208,5 @@ void gt64240_irq_init(void)
+ irq_handlers[i][j].data = NULL;
+ }
+ }
+-#endif
++#endif /* 0 */
+ }
+diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
+index 7a4a419..da46524 100644
+--- a/arch/mips/momentum/ocelot_g/irq.c
++++ b/arch/mips/momentum/ocelot_g/irq.c
+@@ -48,22 +48,22 @@
+ #include <asm/mipsregs.h>
+ #include <asm/system.h>
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP2)
+- do_IRQ(2, regs);
++ do_IRQ(2);
+ else if (pending & STATUSF_IP3)
+- do_IRQ(3, regs);
++ do_IRQ(3);
+ else if (pending & STATUSF_IP4)
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ else if (pending & STATUSF_IP5)
+- do_IRQ(5, regs);
++ do_IRQ(5);
+ else if (pending & STATUSF_IP6)
+- do_IRQ(6, regs);
++ do_IRQ(6);
+ else if (pending & STATUSF_IP7)
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ else {
+ /*
+ * Now look at the extended interrupts
+@@ -71,15 +71,15 @@ asmlinkage void plat_irq_dispatch(struct
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+
+ if (pending & STATUSF_IP8)
+- do_IRQ(8, regs);
++ do_IRQ(8);
+ else if (pending & STATUSF_IP9)
+- do_IRQ(9, regs);
++ do_IRQ(9);
+ else if (pending & STATUSF_IP10)
+- do_IRQ(10, regs);
++ do_IRQ(10);
+ else if (pending & STATUSF_IP11)
+- do_IRQ(11, regs);
++ do_IRQ(11);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+ }
+
+diff --git a/arch/mips/momentum/ocelot_g/ocelot_pld.h b/arch/mips/momentum/ocelot_g/ocelot_pld.h
+index fcb8275..95e0534 100644
+--- a/arch/mips/momentum/ocelot_g/ocelot_pld.h
++++ b/arch/mips/momentum/ocelot_g/ocelot_pld.h
+@@ -23,8 +23,8 @@
+ #define OCELOT_REG_INTSET (12)
+ #define OCELOT_REG_INTCLR (13)
+
+-#define OCELOT_PLD_WRITE(x, y) writeb(x, OCELOT_CS0_ADDR + OCELOT_REG_##y)
+-#define OCELOT_PLD_READ(x) readb(OCELOT_CS0_ADDR + OCELOT_REG_##x)
+-
++#define __PLD_REG_TO_ADDR(reg) ((void *) OCELOT_CS0_ADDR + OCELOT_REG_##reg)
++#define OCELOT_PLD_WRITE(x, reg) writeb(x, __PLD_REG_TO_ADDR(reg))
++#define OCELOT_PLD_READ(reg) readb(__PLD_REG_TO_ADDR(reg))
+
+ #endif /* __MOMENCO_OCELOT_PLD_H__ */
+diff --git a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c
+index c580b1d..d288f7b 100644
+--- a/arch/mips/momentum/ocelot_g/setup.c
++++ b/arch/mips/momentum/ocelot_g/setup.c
+@@ -57,8 +57,8 @@
+ #include <asm/gt64240.h>
+ #include <asm/irq.h>
+ #include <asm/pci.h>
++#include <asm/pgtable.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <linux/bootmem.h>
+
+@@ -161,6 +161,10 @@ static void __init setup_l3cache(unsigne
+ printk("Done\n");
+ }
+
++void __init plat_timer_setup(struct irqaction *irq)
++{
++}
++
+ void __init plat_mem_setup(void)
+ {
+ void (*l3func)(unsigned long) = (void *) KSEG1ADDR(setup_l3cache);
+diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h
+index 5cfce7d..fa6b4aa 100644
+--- a/arch/mips/oprofile/op_impl.h
++++ b/arch/mips/oprofile/op_impl.h
+@@ -10,10 +10,8 @@
+ #ifndef OP_IMPL_H
+ #define OP_IMPL_H 1
+
+-struct pt_regs;
+-
+-extern int null_perf_irq(struct pt_regs *regs);
+-extern int (*perf_irq)(struct pt_regs *regs);
++extern int null_perf_irq(void);
++extern int (*perf_irq)(void);
+
+ /* Per-counter configuration as set via oprofilefs. */
+ struct op_counter_config {
+diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
+index a175d67..1fb240c 100644
+--- a/arch/mips/oprofile/op_model_mipsxx.c
++++ b/arch/mips/oprofile/op_model_mipsxx.c
+@@ -3,12 +3,13 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 2004, 2005 by Ralf Baechle
++ * Copyright (C) 2004, 05, 06 by Ralf Baechle
+ * Copyright (C) 2005 by MIPS Technologies, Inc.
+ */
+ #include <linux/oprofile.h>
+ #include <linux/interrupt.h>
+ #include <linux/smp.h>
++#include <asm/irq_regs.h>
+
+ #include "op_impl.h"
+
+@@ -30,16 +31,18 @@
+ #define M_COUNTER_OVERFLOW (1UL << 31)
+
+ #ifdef CONFIG_MIPS_MT_SMP
+-#define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id()))
++#define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id()))
++#define vpe_id() smp_processor_id()
+ #else
+-#define WHAT 0
++#define WHAT 0
++#define vpe_id() smp_processor_id()
+ #endif
+
+ #define __define_perf_accessors(r, n, np) \
+ \
+ static inline unsigned int r_c0_ ## r ## n(void) \
+ { \
+- unsigned int cpu = smp_processor_id(); \
++ unsigned int cpu = vpe_id(); \
+ \
+ switch (cpu) { \
+ case 0: \
+@@ -54,7 +57,7 @@ static inline unsigned int r_c0_ ## r ##
+ \
+ static inline void w_c0_ ## r ## n(unsigned int value) \
+ { \
+- unsigned int cpu = smp_processor_id(); \
++ unsigned int cpu = vpe_id(); \
+ \
+ switch (cpu) { \
+ case 0: \
+@@ -170,7 +173,7 @@ static void mipsxx_cpu_stop(void *args)
+ }
+ }
+
+-static int mipsxx_perfcount_handler(struct pt_regs *regs)
++static int mipsxx_perfcount_handler(void)
+ {
+ unsigned int counters = op_model_mipsxx_ops.num_counters;
+ unsigned int control;
+@@ -184,7 +187,7 @@ static int mipsxx_perfcount_handler(stru
+ counter = r_c0_perfcntr ## n(); \
+ if ((control & M_PERFCTL_INTERRUPT_ENABLE) && \
+ (counter & M_COUNTER_OVERFLOW)) { \
+- oprofile_add_sample(regs, n); \
++ oprofile_add_sample(get_irq_regs(), n); \
+ w_c0_perfcntr ## n(reg.counter[n]); \
+ handled = 1; \
+ }
+@@ -217,7 +220,7 @@ static inline int n_counters(void)
+ {
+ int counters = __n_counters();
+
+-#ifndef CONFIG_SMP
++#ifdef CONFIG_MIPS_MT_SMP
+ if (current_cpu_data.cputype == CPU_34K)
+ return counters >> 1;
+ #endif
+diff --git a/arch/mips/oprofile/op_model_rm9000.c b/arch/mips/oprofile/op_model_rm9000.c
+index b7063fe..7dc9bf6 100644
+--- a/arch/mips/oprofile/op_model_rm9000.c
++++ b/arch/mips/oprofile/op_model_rm9000.c
+@@ -80,8 +80,7 @@ static void rm9000_cpu_stop(void *args)
+ write_c0_perfcontrol(0);
+ }
+
+-static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id,
+- struct pt_regs *regs)
++static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id)
+ {
+ unsigned int control = read_c0_perfcontrol();
+ uint32_t counter1, counter2;
+diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
+index 35d5927..70cb55b 100644
+--- a/arch/mips/pci/Makefile
++++ b/arch/mips/pci/Makefile
+@@ -7,11 +7,9 @@ obj-y += pci.o
+ #
+ # PCI bus host bridge specific code
+ #
+-obj-$(CONFIG_ITE_BOARD_GEN) += ops-it8172.o
+ obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o
+ obj-$(CONFIG_MIPS_GT64111) += ops-gt64111.o
+ obj-$(CONFIG_MIPS_GT64120) += ops-gt64120.o
+-obj-$(CONFIG_MIPS_GT96100) += ops-gt96100.o
+ obj-$(CONFIG_PCI_MARVELL) += ops-marvell.o
+ obj-$(CONFIG_MIPS_MSC) += ops-msc.o
+ obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o
+@@ -28,10 +26,7 @@ obj-$(CONFIG_DDB5477) += fixup-ddb5477.
+ obj-$(CONFIG_LASAT) += pci-lasat.o
+ obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o
+ obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
+-obj-$(CONFIG_MIPS_EV96100) += fixup-ev64120.o
+-obj-$(CONFIG_MIPS_EV96100) += fixup-ev96100.o pci-ev96100.o
+-obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o
+-obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o
++obj-$(CONFIG_MIPS_EV64120) += pci-ev64120.o
+ obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o
+ obj-$(CONFIG_SOC_AU1550) += fixup-au1000.o ops-au1000.o
+ obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o
+diff --git a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c
+index 439510a..c6cd6e9 100644
+--- a/arch/mips/pci/fixup-atlas.c
++++ b/arch/mips/pci/fixup-atlas.c
+@@ -21,16 +21,16 @@
+
+ #include <asm/mips-boards/atlasint.h>
+
+-#define PCIA ATLASINT_PCIA
+-#define PCIB ATLASINT_PCIB
+-#define PCIC ATLASINT_PCIC
+-#define PCID ATLASINT_PCID
+-#define INTA ATLASINT_INTA
+-#define INTB ATLASINT_INTB
+-#define ETH ATLASINT_ETH
+-#define INTC ATLASINT_INTC
+-#define SCSI ATLASINT_SCSI
+-#define INTD ATLASINT_INTD
++#define PCIA ATLAS_INT_PCIA
++#define PCIB ATLAS_INT_PCIB
++#define PCIC ATLAS_INT_PCIC
++#define PCID ATLAS_INT_PCID
++#define INTA ATLAS_INT_INTA
++#define INTB ATLAS_INT_INTB
++#define ETH ATLAS_INT_ETH
++#define INTC ATLAS_INT_INTC
++#define SCSI ATLAS_INT_SCSI
++#define INTD ATLAS_INT_INTD
+
+ static char irq_tab[][5] __initdata = {
+ /* INTA INTB INTC INTD */
+diff --git a/arch/mips/pci/fixup-ev64120.c b/arch/mips/pci/fixup-ev64120.c
+deleted file mode 100644
+index 8dbb90d..0000000
+--- a/arch/mips/pci/fixup-ev64120.c
++++ /dev/null
+@@ -1,34 +0,0 @@
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-
+-int pci_range_ck(unsigned char bus, unsigned char dev)
+-{
+- if (((bus == 0) || (bus == 1)) && (dev >= 6) && (dev <= 8))
+- return 0;
+-
+- return -1;
+-}
+-
+-/*
+- * After detecting all agents over the PCI , this function is called
+- * in order to give an interrupt number for each PCI device starting
+- * from IRQ 20. It does also enables master for each device.
+- */
+-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+-{
+- unsigned int irq = 20;
+- struct pci_bus *current_bus = bus;
+- struct pci_dev *dev;
+- struct list_head *devices_link;
+-
+- list_for_each(devices_link, &(current_bus->devices)) {
+- dev = pci_dev_b(devices_link);
+- if (dev != NULL) {
+- dev->irq = irq++;
+-
+- /* Assign an interrupt number for the device */
+- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+- pcibios_set_master(dev);
+- }
+- }
+-}
+diff --git a/arch/mips/pci/fixup-ev96100.c b/arch/mips/pci/fixup-ev96100.c
+deleted file mode 100644
+index e2bc977..0000000
+--- a/arch/mips/pci/fixup-ev96100.c
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * EV96100 Board specific pci fixups.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/init.h>
+-#include <linux/types.h>
+-#include <linux/pci.h>
+-
+-static char irq_tab_ev96100[][5] __initdata = {
+- [8] = { 0, 5, 5, 5, 5 },
+- [9] = { 0, 2, 2, 2, 2 }
+-};
+-
+-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- return irq_tab_ev96100[slot][pin];
+-}
+-
+-/* Do platform specific device initialization at pci_enable_device() time */
+-int pcibios_plat_dev_init(struct pci_dev *dev)
+-{
+- return 0;
+-}
+diff --git a/arch/mips/pci/fixup-ite8172g.c b/arch/mips/pci/fixup-ite8172g.c
+deleted file mode 100644
+index 2290ea4..0000000
+--- a/arch/mips/pci/fixup-ite8172g.c
++++ /dev/null
+@@ -1,80 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * Board specific pci fixups.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_pci.h>
+-#include <asm/it8172/it8172_int.h>
+-
+-/*
+- * Shortcuts
+- */
+-#define INTA IT8172_PCI_INTA_IRQ
+-#define INTB IT8172_PCI_INTB_IRQ
+-#define INTC IT8172_PCI_INTC_IRQ
+-#define INTD IT8172_PCI_INTD_IRQ
+-
+-static const int internal_func_irqs[7] __initdata = {
+- IT8172_AC97_IRQ,
+- IT8172_DMA_IRQ,
+- IT8172_CDMA_IRQ,
+- IT8172_USB_IRQ,
+- IT8172_BRIDGE_MASTER_IRQ,
+- IT8172_IDE_IRQ,
+- IT8172_MC68K_IRQ
+-};
+-
+-static char irq_tab_ite8172g[][5] __initdata = {
+- [0x10] = { 0, INTA, INTB, INTC, INTD },
+- [0x11] = { 0, INTA, INTB, INTC, INTD },
+- [0x12] = { 0, INTB, INTC, INTD, INTA },
+- [0x13] = { 0, INTC, INTD, INTA, INTB },
+- [0x14] = { 0, INTD, INTA, INTB, INTC },
+-};
+-
+-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- /*
+- * Internal device 1 is actually 7 different internal devices on the
+- * IT8172G (a multifunction device).
+- */
+- if (slot == 1)
+- return internal_func_irqs[PCI_FUNC(dev->devfn)];
+-
+- return irq_tab_ite8172g[slot][pin];
+-}
+-
+-/* Do platform specific device initialization at pci_enable_device() time */
+-int pcibios_plat_dev_init(struct pci_dev *dev)
+-{
+- return 0;
+-}
+diff --git a/arch/mips/pci/fixup-ivr.c b/arch/mips/pci/fixup-ivr.c
+deleted file mode 100644
+index 0c7c164..0000000
+--- a/arch/mips/pci/fixup-ivr.c
++++ /dev/null
+@@ -1,75 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Globespan IVR board-specific pci fixups.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_pci.h>
+-#include <asm/it8172/it8172_int.h>
+-
+-/*
+- * Shortcuts
+- */
+-#define INTA IT8172_PCI_INTA_IRQ
+-#define INTB IT8172_PCI_INTB_IRQ
+-#define INTC IT8172_PCI_INTC_IRQ
+-#define INTD IT8172_PCI_INTD_IRQ
+-
+-static const int internal_func_irqs[7] __initdata = {
+- IT8172_AC97_IRQ,
+- IT8172_DMA_IRQ,
+- IT8172_CDMA_IRQ,
+- IT8172_USB_IRQ,
+- IT8172_BRIDGE_MASTER_IRQ,
+- IT8172_IDE_IRQ,
+- IT8172_MC68K_IRQ
+-};
+-
+-static char irq_tab_ivr[][5] __initdata = {
+- [0x11] = { INTC, INTC, INTD, INTA, INTB }, /* Realtek RTL-8139 */
+- [0x12] = { INTB, INTB, INTB, INTC, INTC }, /* IVR slot */
+- [0x13] = { INTA, INTA, INTB, INTC, INTD } /* Expansion slot */
+-};
+-
+-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- if (slot == 1)
+- return internal_func_irqs[PCI_FUNC(dev->devfn)];
+-
+- return irq_tab_ivr[slot][pin];
+-}
+-
+-/* Do platform specific device initialization at pci_enable_device() time */
+-int pcibios_plat_dev_init(struct pci_dev *dev)
+-{
+- return 0;
+-}
+diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
+index 13791b7..7a74448 100644
+--- a/arch/mips/pci/fixup-sb1250.c
++++ b/arch/mips/pci/fixup-sb1250.c
+@@ -1,7 +1,7 @@
+ /*
+ * arch/mips/pci/fixup-sb1250.c
+ *
+- * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
++ * Copyright (C) 2004, 2006 MIPS Technologies, Inc. All rights reserved.
+ * Author: Maciej W. Rozycki <macro at mips.com>
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -14,6 +14,17 @@
+ #include <linux/pci.h>
+
+ /*
++ * Set the the BCM1250, etc. PCI host bridge's TRDY timeout
++ * to the finite max.
++ */
++static void __init quirk_sb1250_pci(struct pci_dev *dev)
++{
++ pci_write_config_byte(dev, 0x40, 0xff);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
++ quirk_sb1250_pci);
++
++/*
+ * The BCM1250, etc. PCI/HT bridge reports as a host bridge.
+ */
+ static void __init quirk_sb1250_ht(struct pci_dev *dev)
+@@ -22,3 +33,13 @@ static void __init quirk_sb1250_ht(struc
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
+ quirk_sb1250_ht);
++
++/*
++ * Set the the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
++ */
++static void __init quirk_sp1011(struct pci_dev *dev)
++{
++ pci_write_config_byte(dev, 0x64, 0xff);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIPACKETS, PCI_DEVICE_ID_SP1011,
++ quirk_sp1011);
+diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c
+index 8e01d0c..597b897 100644
+--- a/arch/mips/pci/fixup-vr4133.c
++++ b/arch/mips/pci/fixup-vr4133.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/mips/vr41xx/nec-cmbvr4133/pci_fixup.c
++ * arch/mips/pci/fixup-vr4133.c
+ *
+ * The NEC CMB-VR4133 Board specific PCI fixups.
+ *
+diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c
+index 0c0c1e6..8ae4648 100644
+--- a/arch/mips/pci/ops-au1000.c
++++ b/arch/mips/pci/ops-au1000.c
+@@ -110,7 +110,7 @@ static int config_access(unsigned char a
+ if (first_cfg) {
+ /* reserve a wired entry for pci config accesses */
+ first_cfg = 0;
+- pci_cfg_vm = get_vm_area(0x2000, 0);
++ pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP);
+ if (!pci_cfg_vm)
+ panic (KERN_ERR "PCI unable to get vm area\n");
+ pci_cfg_wired_entry = read_c0_wired();
+diff --git a/arch/mips/pci/ops-gt96100.c b/arch/mips/pci/ops-gt96100.c
+deleted file mode 100644
+index 9e4ea66..0000000
+--- a/arch/mips/pci/ops-gt96100.c
++++ /dev/null
+@@ -1,169 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Galileo EV96100 board specific pci support.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * This file was derived from Carsten Langgaard's
+- * arch/mips/mips-boards/generic/pci.c
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 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/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-
+-#include <asm/delay.h>
+-#include <asm/gt64120.h>
+-#include <asm/galileo-boards/ev96100.h>
+-
+-#define PCI_ACCESS_READ 0
+-#define PCI_ACCESS_WRITE 1
+-
+-static int static gt96100_config_access(unsigned char access_type,
+- struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
+-{
+- unsigned char bus = bus->number;
+- u32 intr;
+-
+- /*
+- * Because of a bug in the galileo (for slot 31).
+- */
+- if (bus == 0 && devfn >= PCI_DEVFN(31, 0))
+- return PCIBIOS_DEVICE_NOT_FOUND;
+-
+- /* Clear cause register bits */
+- GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+- GT_INTRCAUSE_TARABORT0_BIT));
+-
+- /* Setup address */
+- GT_WRITE(GT_PCI0_CFGADDR_OFS,
+- (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+- (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+- ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+- GT_PCI0_CFGADDR_CONFIGEN_BIT);
+- udelay(2);
+-
+-
+- if (access_type == PCI_ACCESS_WRITE) {
+- if (devfn != 0)
+- *data = le32_to_cpu(*data);
+- GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+- } else {
+- *data = GT_READ(GT_PCI0_CFGDATA_OFS);
+- if (devfn != 0)
+- *data = le32_to_cpu(*data);
+- }
+-
+- udelay(2);
+-
+- /* Check for master or target abort */
+- intr = GT_READ(GT_INTRCAUSE_OFS);
+-
+- if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
+- /* Error occured */
+-
+- /* Clear bits */
+- GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+- GT_INTRCAUSE_TARABORT0_BIT));
+- return -1;
+- }
+- return 0;
+-}
+-
+-/*
+- * We can't address 8 and 16 bit words directly. Instead we have to
+- * read/write a 32bit word and mask/modify the data we actually want.
+- */
+-static int gt96100_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+- int where, int size, u32 * val)
+-{
+- u32 data = 0;
+-
+- if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+- return PCIBIOS_DEVICE_NOT_FOUND;
+-
+- switch (size) {
+- case 1:
+- *val = (data >> ((where & 3) << 3)) & 0xff;
+- break;
+-
+- case 2:
+- *val = (data >> ((where & 3) << 3)) & 0xffff;
+- break;
+-
+- case 4:
+- *val = data;
+- break;
+- }
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int gt96100_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+- int where, int size, u32 val)
+-{
+- u32 data = 0;
+-
+- switch (size) {
+- case 1:
+- if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+- return -1;
+-
+- data = (data & ~(0xff << ((where & 3) << 3))) |
+- (val << ((where & 3) << 3));
+-
+- if (gt96100_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+- return -1;
+-
+- return PCIBIOS_SUCCESSFUL;
+-
+- case 2:
+- if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+- return -1;
+-
+- data = (data & ~(0xffff << ((where & 3) << 3))) |
+- (val << ((where & 3) << 3));
+-
+- if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+- return -1;
+-
+-
+- return PCIBIOS_SUCCESSFUL;
+-
+- case 4:
+- if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+- return -1;
+-
+- return PCIBIOS_SUCCESSFUL;
+- }
+-}
+-
+-struct pci_ops gt96100_pci_ops = {
+- .read = gt96100_pcibios_read,
+- .write = gt96100_pcibios_write
+-};
+diff --git a/arch/mips/pci/ops-it8172.c b/arch/mips/pci/ops-it8172.c
+deleted file mode 100644
+index ba83285..0000000
+--- a/arch/mips/pci/ops-it8172.c
++++ /dev/null
+@@ -1,213 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * IT8172 system controller specific pci support.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * Copyright (C) 2004 by Ralf Baechle (ralf at linux-mips.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 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/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_pci.h>
+-
+-#define PCI_ACCESS_READ 0
+-#define PCI_ACCESS_WRITE 1
+-
+-#undef DEBUG
+-#ifdef DEBUG
+-#define DBG(x...) printk(x)
+-#else
+-#define DBG(x...)
+-#endif
+-
+-static struct resource pci_mem_resource_1;
+-
+-static struct resource pci_io_resource = {
+- .start = 0x14018000,
+- .end = 0x17FFFFFF,
+- .name = "io pci IO space",
+- .flags = IORESOURCE_IO
+-};
+-
+-static struct resource pci_mem_resource_0 = {
+- .start = 0x10101000,
+- .end = 0x13FFFFFF,
+- .name = "ext pci memory space 0/1",
+- .flags = IORESOURCE_MEM,
+- .parent = &pci_mem_resource_0,
+- .sibling = NULL,
+- .child = &pci_mem_resource_1
+-};
+-
+-static struct resource pci_mem_resource_1 = {
+- .start = 0x1A000000,
+- .end = 0x1FBFFFFF,
+- .name = "ext pci memory space 2/3",
+- .flags = IORESOURCE_MEM,
+- .parent = &pci_mem_resource_0
+-};
+-
+-extern struct pci_ops it8172_pci_ops;
+-
+-struct pci_controller it8172_controller = {
+- .pci_ops = &it8172_pci_ops,
+- .io_resource = &pci_io_resource,
+- .mem_resource = &pci_mem_resource_0,
+-};
+-
+-static int it8172_pcibios_config_access(unsigned char access_type,
+- struct pci_bus *bus,
+- unsigned int devfn, int where,
+- u32 * data)
+-{
+- /*
+- * config cycles are on 4 byte boundary only
+- */
+-
+- /* Setup address */
+- IT_WRITE(IT_CONFADDR, (bus->number << IT_BUSNUM_SHF) |
+- (devfn << IT_FUNCNUM_SHF) | (where & ~0x3));
+-
+- if (access_type == PCI_ACCESS_WRITE) {
+- IT_WRITE(IT_CONFDATA, *data);
+- } else {
+- IT_READ(IT_CONFDATA, *data);
+- }
+-
+- /*
+- * Revisit: check for master or target abort.
+- */
+- return 0;
+-}
+-
+-
+-/*
+- * We can't address 8 and 16 bit words directly. Instead we have to
+- * read/write a 32bit word and mask/modify the data we actually want.
+- */
+-static write_config(struct pci_bus *bus, unsigned int devfn, int where,
+- int size, u32 val)
+-{
+- u32 data = 0;
+-
+- switch (size) {
+- case 1:
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_READ, dev, where, &data))
+- return -1;
+-
+- *val = (data >> ((where & 3) << 3)) & 0xff;
+-
+- return PCIBIOS_SUCCESSFUL;
+-
+- case 2:
+-
+- if (where & 1)
+- return PCIBIOS_BAD_REGISTER_NUMBER;
+-
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_READ, dev, where, &data))
+- return -1;
+-
+- *val = (data >> ((where & 3) << 3)) & 0xffff;
+- DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n",
+- dev->bus->number, dev->devfn, where, *val);
+-
+- return PCIBIOS_SUCCESSFUL;
+-
+- case 4:
+-
+- if (where & 3)
+- return PCIBIOS_BAD_REGISTER_NUMBER;
+-
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_READ, dev, where, &data))
+- return -1;
+-
+- *val = data;
+-
+- return PCIBIOS_SUCCESSFUL;
+- }
+-}
+-
+-
+-static write_config(struct pci_bus *bus, unsigned int devfn, int where,
+- int size, u32 val)
+-{
+- u32 data = 0;
+-
+- switch (size) {
+- case 1:
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_READ, dev, where, &data))
+- return -1;
+-
+- data = (data & ~(0xff << ((where & 3) << 3))) |
+- (val << ((where & 3) << 3));
+-
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_WRITE, dev, where, &data))
+- return -1;
+-
+- return PCIBIOS_SUCCESSFUL;
+-
+- case 2:
+- if (where & 1)
+- return PCIBIOS_BAD_REGISTER_NUMBER;
+-
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_READ, dev, where, &data))
+- eturn - 1;
+-
+- data = (data & ~(0xffff << ((where & 3) << 3))) |
+- (val << ((where & 3) << 3));
+-
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_WRITE, dev, where, &data))
+- return -1;
+-
+- return PCIBIOS_SUCCESSFUL;
+-
+- case 4:
+- if (where & 3)
+- return PCIBIOS_BAD_REGISTER_NUMBER;
+-
+- if (it8172_pcibios_config_access
+- (PCI_ACCESS_WRITE, dev, where, &val))
+- return -1;
+-
+- return PCIBIOS_SUCCESSFUL;
+- }
+-}
+-
+-struct pci_ops it8172_pci_ops = {
+- .read = read_config,
+- .write = write_config,
+-};
+diff --git a/arch/mips/pci/pci-ev64120.c b/arch/mips/pci/pci-ev64120.c
+new file mode 100644
+index 0000000..9cd859e
+--- /dev/null
++++ b/arch/mips/pci/pci-ev64120.c
+@@ -0,0 +1,21 @@
++#include <linux/pci.h>
++
++int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq;
++
++ if (!pin)
++ return 0;
++
++ irq = allocate_irqno();
++ if (irq < 0)
++ return 0;
++
++ return irq;
++}
++
++/* Do platform specific device initialization at pci_enable_device() time */
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++ return 0;
++}
+diff --git a/arch/mips/pci/pci-ev96100.c b/arch/mips/pci/pci-ev96100.c
+deleted file mode 100644
+index f9457ea..0000000
+--- a/arch/mips/pci/pci-ev96100.c
++++ /dev/null
+@@ -1,63 +0,0 @@
+-/*
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+- *
+- * Copyright (C) 2004 by Ralf Baechle (ralf at linux-mips.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 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/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-
+-static struct resource pci_io_resource = {
+- .name = "io pci IO space",
+- .start = 0x10000000,
+- .end = 0x11ffffff,
+- .flags = IORESOURCE_IO
+-};
+-
+-static struct resource pci_mem_resource = {
+- .name = "ext pci memory space",
+- .start = 0x12000000,
+- .end = 0x13ffffff,
+- .flags = IORESOURCE_MEM
+-};
+-
+-extern struct pci_ops gt96100_pci_ops;
+-
+-struct pci_controller ev96100_controller = {
+- .pci_ops = >96100_pci_ops,
+- .io_resource = &pci_io_resource,
+- .mem_resource = &pci_mem_resource,
+-};
+-
+-static void ev96100_pci_init(void)
+-{
+- register_pci_controller(&ev96100_controller);
+-}
+-
+-arch_initcall(ev96100_pci_init);
+diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
+index 80eb9af..405ce01 100644
+--- a/arch/mips/pci/pci-ip27.c
++++ b/arch/mips/pci/pci-ip27.c
+@@ -16,8 +16,6 @@
+ #include <asm/sn/intr.h>
+ #include <asm/sn/sn0/hub.h>
+
+-extern unsigned int allocate_irqno(void);
+-
+ /*
+ * Max #PCI busses we can handle; ie, max #PCI bridges.
+ */
+diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c
+index 17c7932..618ea7d 100644
+--- a/arch/mips/pci/pci-ip32.c
++++ b/arch/mips/pci/pci-ip32.c
+@@ -22,7 +22,7 @@
+ * registered on the bridge error irq. It's conceivable that some of these
+ * conditions warrant a panic. Anybody care to say which ones?
+ */
+-static irqreturn_t macepci_error(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t macepci_error(int irq, void *dev)
+ {
+ char s;
+ unsigned int flags = mace->pci.error;
+diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
+index 099679a..7106116 100644
+--- a/arch/mips/philips/pnx8550/common/int.c
++++ b/arch/mips/philips/pnx8550/common/int.c
+@@ -23,6 +23,7 @@
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
++#include <linux/compiler.h>
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <linux/sched.h>
+@@ -52,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOT
+ 1 // 70
+ };
+
+-static void hw0_irqdispatch(int irq, struct pt_regs *regs)
++static void hw0_irqdispatch(int irq)
+ {
+ /* find out which interrupt */
+ irq = PNX8550_GIC_VECTOR_0 >> 3;
+@@ -61,42 +62,39 @@ static void hw0_irqdispatch(int irq, str
+ printk("hw0_irqdispatch: irq 0, spurious interrupt?\n");
+ return;
+ }
+- do_IRQ(PNX8550_INT_GIC_MIN + irq, regs);
++ do_IRQ(PNX8550_INT_GIC_MIN + irq);
+ }
+
+
+-static void timer_irqdispatch(int irq, struct pt_regs *regs)
++static void timer_irqdispatch(int irq)
+ {
+ irq = (0x01c0 & read_c0_config7()) >> 6;
+
+- if (irq == 0) {
++ if (unlikely(irq == 0)) {
+ printk("timer_irqdispatch: irq 0, spurious interrupt?\n");
+ return;
+ }
+
+- if (irq & 0x1) {
+- do_IRQ(PNX8550_INT_TIMER1, regs);
+- }
+- if (irq & 0x2) {
+- do_IRQ(PNX8550_INT_TIMER2, regs);
+- }
+- if (irq & 0x4) {
+- do_IRQ(PNX8550_INT_TIMER3, regs);
+- }
++ if (irq & 0x1)
++ do_IRQ(PNX8550_INT_TIMER1);
++ if (irq & 0x2)
++ do_IRQ(PNX8550_INT_TIMER2);
++ if (irq & 0x4)
++ do_IRQ(PNX8550_INT_TIMER3);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP2)
+- do_IRQ(2, regs);
++ hw0_irqdispatch(2);
+ else if (pending & STATUSF_IP7) {
+ if (read_c0_config7() & 0x01c0)
+- timer_irqdispatch(7, regs);
++ timer_irqdispatch(7);
+ }
+
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
+diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/philips/pnx8550/common/platform.c
+index 5436b4b..d43f56e 100644
+--- a/arch/mips/philips/pnx8550/common/platform.c
++++ b/arch/mips/philips/pnx8550/common/platform.c
+@@ -17,15 +17,13 @@
+ #include <linux/init.h>
+ #include <linux/resource.h>
+ #include <linux/serial.h>
+-#include <linux/serial_ip3106.h>
++#include <linux/serial_pnx8xxx.h>
+ #include <linux/platform_device.h>
+
+ #include <int.h>
+ #include <usb.h>
+ #include <uart.h>
+
+-extern struct uart_ops ip3106_pops;
+-
+ static struct resource pnx8550_usb_ohci_resources[] = {
+ [0] = {
+ .start = PNX8550_USB_OHCI_OP_BASE,
+@@ -63,31 +61,29 @@ static struct resource pnx8550_uart_reso
+ },
+ };
+
+-struct ip3106_port ip3106_ports[] = {
++struct pnx8xxx_port pnx8xxx_ports[] = {
+ [0] = {
+ .port = {
+- .type = PORT_IP3106,
++ .type = PORT_PNX8XXX,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)PNX8550_UART_PORT0,
+ .mapbase = PNX8550_UART_PORT0,
+ .irq = PNX8550_UART_INT(0),
+ .uartclk = 3692300,
+ .fifosize = 16,
+- .ops = &ip3106_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 0,
+ },
+ },
+ [1] = {
+ .port = {
+- .type = PORT_IP3106,
++ .type = PORT_PNX8XXX,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)PNX8550_UART_PORT1,
+ .mapbase = PNX8550_UART_PORT1,
+ .irq = PNX8550_UART_INT(1),
+ .uartclk = 3692300,
+ .fifosize = 16,
+- .ops = &ip3106_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 1,
+ },
+@@ -111,12 +107,12 @@ static struct platform_device pnx8550_us
+ };
+
+ static struct platform_device pnx8550_uart_device = {
+- .name = "ip3106-uart",
++ .name = "pnx8xxx-uart",
+ .id = -1,
+ .dev = {
+ .dma_mask = &uart_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+- .platform_data = ip3106_ports,
++ .platform_data = pnx8xxx_ports,
+ },
+ .num_resources = ARRAY_SIZE(pnx8550_uart_resources),
+ .resource = pnx8550_uart_resources,
+diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c
+index 70aac97..f8952c1 100644
+--- a/arch/mips/philips/pnx8550/common/prom.c
++++ b/arch/mips/philips/pnx8550/common/prom.c
+@@ -13,7 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/string.h>
+-#include <linux/serial_ip3106.h>
++#include <linux/serial_pnx8xxx.h>
+
+ #include <asm/bootinfo.h>
+ #include <uart.h>
+@@ -126,7 +126,7 @@ void prom_putchar(char c)
+ {
+ if (pnx8550_console_port != -1) {
+ /* Wait until FIFO not full */
+- while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & IP3106_UART_FIFO_TXFIFO) >> 16) >= 16)
++ while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & PNX8XXX_UART_FIFO_TXFIFO) >> 16) >= 16)
+ ;
+ /* Send one char */
+ ip3106_fifo(UART_BASE, pnx8550_console_port) = c;
+diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c
+index 36b0c8b..e62123c 100644
+--- a/arch/mips/philips/pnx8550/common/setup.c
++++ b/arch/mips/philips/pnx8550/common/setup.c
+@@ -24,7 +24,7 @@
+ #include <linux/mm.h>
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+-#include <linux/serial_ip3106.h>
++#include <linux/serial_pnx8xxx.h>
+ #include <linux/pm.h>
+
+ #include <asm/cpu.h>
+@@ -56,7 +56,7 @@ extern char *prom_getcmdline(void);
+
+ struct resource standard_io_resources[] = {
+ {
+- .start = .0x00,
++ .start = 0x00,
+ .end = 0x1f,
+ .name = "dma1",
+ .flags = IORESOURCE_BUSY
+@@ -144,7 +144,7 @@ void __init plat_mem_setup(void)
+ /* We must initialize the UART (console) before prom_printf */
+ /* Set LCR to 8-bit and BAUD to 38400 (no 5) */
+ ip3106_lcr(UART_BASE, pnx8550_console_port) =
+- IP3106_UART_LCR_8BIT;
++ PNX8XXX_UART_LCR_8BIT;
+ ip3106_baud(UART_BASE, pnx8550_console_port) = 5;
+ }
+
+diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/philips/pnx8550/common/time.c
+index 0af655b..65c440e 100644
+--- a/arch/mips/philips/pnx8550/common/time.c
++++ b/arch/mips/philips/pnx8550/common/time.c
+@@ -41,8 +41,8 @@ extern unsigned int mips_hpt_frequency;
+ * 1) board_time_init() -
+ * a) (optional) set up RTC routines,
+ * b) (optional) calibrate and set the mips_hpt_frequency
+- * (only needed if you intended to use fixed_rate_gettimeoffset
+- * or use cpu counter as timer interrupt source)
++ * (only needed if you intended to use cpu counter as timer interrupt
++ * source)
+ */
+
+ void pnx8550_time_init(void)
+diff --git a/arch/mips/pmc-sierra/yosemite/i2c-yosemite.c b/arch/mips/pmc-sierra/yosemite/i2c-yosemite.c
+index 416da22..85b14c7 100644
+--- a/arch/mips/pmc-sierra/yosemite/i2c-yosemite.c
++++ b/arch/mips/pmc-sierra/yosemite/i2c-yosemite.c
+@@ -74,7 +74,7 @@ static int titan_i2c_poll(void)
+ int titan_i2c_xfer(unsigned int slave_addr, titan_i2c_command * cmd,
+ int size, unsigned int *addr)
+ {
+- int loop = 0, bytes, i;
++ int loop, bytes = 0, i;
+ unsigned int *write_data, data, *read_data;
+ unsigned long reg_val, val;
+
+diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
+index b91d0aa..adb0485 100644
+--- a/arch/mips/pmc-sierra/yosemite/irq.c
++++ b/arch/mips/pmc-sierra/yosemite/irq.c
+@@ -56,15 +56,13 @@
+ #define HYPERTRANSPORT_INTC 0x7a /* INTC# */
+ #define HYPERTRANSPORT_INTD 0x7b /* INTD# */
+
+-extern void jaguar_mailbox_irq(struct pt_regs *);
+-
+ /*
+ * Handle hypertransport & SMP interrupts. The interrupt lines are scarce.
+ * For interprocessor interrupts, the best thing to do is to use the INTMSG
+ * register. We use the same external interrupt line, i.e. INTB3 and monitor
+ * another status bit
+ */
+-asmlinkage void ll_ht_smp_irq_handler(int irq, struct pt_regs *regs)
++static void ll_ht_smp_irq_handler(int irq)
+ {
+ u32 status = OCD_READ(RM9000x2_OCD_INTP0STATUS4);
+
+@@ -107,50 +105,35 @@ asmlinkage void ll_ht_smp_irq_handler(in
+ }
+ #endif /* CONFIG_HT_LEVEL_TRIGGER */
+
+- do_IRQ(irq, regs);
+-}
+-
+-asmlinkage void do_extended_irq(struct pt_regs *regs)
+-{
+- unsigned int intcontrol = read_c0_intcontrol();
+- unsigned int cause = read_c0_cause();
+- unsigned int status = read_c0_status();
+- unsigned int pending_sr, pending_ic;
+-
+- pending_sr = status & cause & 0xff00;
+- pending_ic = (cause >> 8) & intcontrol & 0xff00;
+-
+- if (pending_ic & (1 << 13))
+- do_IRQ(13, regs);
+-
++ do_IRQ(irq);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int cause = read_c0_cause();
+ unsigned int status = read_c0_status();
+ unsigned int pending = cause & status;
+
+ if (pending & STATUSF_IP7) {
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ } else if (pending & STATUSF_IP2) {
+ #ifdef CONFIG_HYPERTRANSPORT
+- ll_ht_smp_irq_handler(2, regs);
++ ll_ht_smp_irq_handler(2);
+ #else
+- do_IRQ(2, regs);
++ do_IRQ(2);
+ #endif
+ } else if (pending & STATUSF_IP3) {
+- do_IRQ(3, regs);
++ do_IRQ(3);
+ } else if (pending & STATUSF_IP4) {
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ } else if (pending & STATUSF_IP5) {
+ #ifdef CONFIG_SMP
+- titan_mailbox_irq(regs);
++ titan_mailbox_irq();
+ #else
+- do_IRQ(5, regs);
++ do_IRQ(5);
+ #endif
+ } else if (pending & STATUSF_IP6) {
+- do_IRQ(4, regs);
++ do_IRQ(4);
+ }
+ }
+
+@@ -178,18 +161,3 @@ void __init arch_init_irq(void)
+ register_gdb_console();
+ #endif
+ }
+-
+-#ifdef CONFIG_KGDB
+-/*
+- * The 16550 DUART has two ports, but is allocated one IRQ
+- * for the serial console. Hence, a generic framework for
+- * serial IRQ routing in place. Currently, just calls the
+- * do_IRQ fuction. But, going in the future, need to check
+- * DUART registers for channel A and B, then decide the
+- * appropriate action
+- */
+-asmlinkage void yosemite_kgdb_irq(int irq, struct pt_regs *regs)
+-{
+- do_IRQ(irq, regs);
+-}
+-#endif
+diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
+index 0a6ee8e..1b9b0d3 100644
+--- a/arch/mips/pmc-sierra/yosemite/setup.c
++++ b/arch/mips/pmc-sierra/yosemite/setup.c
+@@ -46,7 +46,6 @@
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/serial.h>
+ #include <asm/titan_dep.h>
+diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c
+index c197311..3cc0436 100644
+--- a/arch/mips/pmc-sierra/yosemite/smp.c
++++ b/arch/mips/pmc-sierra/yosemite/smp.c
+@@ -3,9 +3,7 @@
+
+ #include <asm/pmon.h>
+ #include <asm/titan_dep.h>
+-
+-extern unsigned int (*mips_hpt_read)(void);
+-extern void (*mips_hpt_init)(unsigned int);
++#include <asm/time.h>
+
+ #define LAUNCHSTACK_SIZE 256
+
+@@ -101,7 +99,7 @@ void prom_cpus_done(void)
+ */
+ void prom_init_secondary(void)
+ {
+- mips_hpt_init(mips_hpt_read());
++ mips_hpt_init();
+
+ set_c0_status(ST0_CO | ST0_IE | ST0_IM);
+ }
+@@ -110,7 +108,7 @@ void prom_smp_finish(void)
+ {
+ }
+
+-asmlinkage void titan_mailbox_irq(struct pt_regs *regs)
++asmlinkage void titan_mailbox_irq(void)
+ {
+ int cpu = smp_processor_id();
+ unsigned long status;
+diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
+index 3352374..f5ea2fe 100644
+--- a/arch/mips/qemu/q-irq.c
++++ b/arch/mips/qemu/q-irq.c
+@@ -9,19 +9,19 @@
+
+ extern asmlinkage void qemu_handle_int(void);
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & 0x8000) {
+- ll_timer_interrupt(Q_COUNT_COMPARE_IRQ, regs);
++ ll_timer_interrupt(Q_COUNT_COMPARE_IRQ);
+ return;
+ }
+ if (pending & 0x0400) {
+ int irq = i8259_irq();
+
+ if (likely(irq >= 0))
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+
+ return;
+ }
+diff --git a/arch/mips/sgi-ip22/ip22-berr.c b/arch/mips/sgi-ip22/ip22-berr.c
+index a28dc78..de6a0cc 100644
+--- a/arch/mips/sgi-ip22/ip22-berr.c
++++ b/arch/mips/sgi-ip22/ip22-berr.c
+@@ -12,6 +12,7 @@
+ #include <asm/system.h>
+ #include <asm/traps.h>
+ #include <asm/branch.h>
++#include <asm/irq_regs.h>
+ #include <asm/sgi/mc.h>
+ #include <asm/sgi/hpc3.h>
+ #include <asm/sgi/ioc.h>
+@@ -85,9 +86,10 @@ static void print_buserr(void)
+ * and then clear the interrupt when this happens.
+ */
+
+-void ip22_be_interrupt(int irq, struct pt_regs *regs)
++void ip22_be_interrupt(int irq)
+ {
+ const int field = 2 * sizeof(unsigned long);
++ const struct pt_regs *regs = get_irq_regs();
+
+ save_and_clear_buserr();
+ print_buserr();
+diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c
+index ee0514a..0d18ed4 100644
+--- a/arch/mips/sgi-ip22/ip22-eisa.c
++++ b/arch/mips/sgi-ip22/ip22-eisa.c
+@@ -70,7 +70,7 @@ static char __init *decode_eisa_sig(unsi
+ return sig_str;
+ }
+
+-static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ip22_eisa_intr(int irq, void *dev_id)
+ {
+ u8 eisa_irq;
+ u8 dma1, dma2;
+@@ -80,7 +80,7 @@ static irqreturn_t ip22_eisa_intr(int ir
+ dma2 = inb(EISA_DMA2_STATUS);
+
+ if (eisa_irq < EISA_MAX_IRQ) {
+- do_IRQ(eisa_irq, regs);
++ do_IRQ(eisa_irq);
+ return IRQ_HANDLED;
+ }
+
+@@ -89,6 +89,7 @@ static irqreturn_t ip22_eisa_intr(int ir
+
+ outb(0x20, EISA_INT2_CTRL);
+ outb(0x20, EISA_INT1_CTRL);
++
+ return IRQ_NONE;
+ }
+
+diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
+index f66026e..af51889 100644
+--- a/arch/mips/sgi-ip22/ip22-int.c
++++ b/arch/mips/sgi-ip22/ip22-int.c
+@@ -222,7 +222,7 @@ static struct irq_chip ip22_local3_irq_t
+ .end = end_local3_irq,
+ };
+
+-static void indy_local0_irqdispatch(struct pt_regs *regs)
++static void indy_local0_irqdispatch(void)
+ {
+ u8 mask = sgint->istat0 & sgint->imask0;
+ u8 mask2;
+@@ -236,11 +236,10 @@ static void indy_local0_irqdispatch(stru
+
+ /* if irq == 0, then the interrupt has already been cleared */
+ if (irq)
+- do_IRQ(irq, regs);
+- return;
++ do_IRQ(irq);
+ }
+
+-static void indy_local1_irqdispatch(struct pt_regs *regs)
++static void indy_local1_irqdispatch(void)
+ {
+ u8 mask = sgint->istat1 & sgint->imask1;
+ u8 mask2;
+@@ -254,19 +253,18 @@ static void indy_local1_irqdispatch(stru
+
+ /* if irq == 0, then the interrupt has already been cleared */
+ if (irq)
+- do_IRQ(irq, regs);
+- return;
++ do_IRQ(irq);
+ }
+
+-extern void ip22_be_interrupt(int irq, struct pt_regs *regs);
++extern void ip22_be_interrupt(int irq);
+
+-static void indy_buserror_irq(struct pt_regs *regs)
++static void indy_buserror_irq(void)
+ {
+ int irq = SGI_BUSERR_IRQ;
+
+ irq_enter();
+ kstat_this_cpu.irqs[irq]++;
+- ip22_be_interrupt(irq, regs);
++ ip22_be_interrupt(irq);
+ irq_exit();
+ }
+
+@@ -305,8 +303,8 @@ static struct irqaction map1_cascade = {
+ #define SGI_INTERRUPTS SGINT_LOCAL3
+ #endif
+
+-extern void indy_r4k_timer_interrupt(struct pt_regs *regs);
+-extern void indy_8254timer_irq(struct pt_regs *regs);
++extern void indy_r4k_timer_interrupt(void);
++extern void indy_8254timer_irq(void);
+
+ /*
+ * IRQs on the INDY look basically (barring software IRQs which we don't use
+@@ -336,7 +334,7 @@ extern void indy_8254timer_irq(struct pt
+ * another exception, big deal.
+ */
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause();
+
+@@ -344,15 +342,15 @@ asmlinkage void plat_irq_dispatch(struct
+ * First we check for r4k counter/timer IRQ.
+ */
+ if (pending & CAUSEF_IP7)
+- indy_r4k_timer_interrupt(regs);
++ indy_r4k_timer_interrupt();
+ else if (pending & CAUSEF_IP2)
+- indy_local0_irqdispatch(regs);
++ indy_local0_irqdispatch();
+ else if (pending & CAUSEF_IP3)
+- indy_local1_irqdispatch(regs);
++ indy_local1_irqdispatch();
+ else if (pending & CAUSEF_IP6)
+- indy_buserror_irq(regs);
++ indy_buserror_irq();
+ else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
+- indy_8254timer_irq(regs);
++ indy_8254timer_irq();
+ }
+
+ extern void mips_cpu_irq_init(unsigned int irq_base);
+diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
+index 8134220..66df5ac 100644
+--- a/arch/mips/sgi-ip22/ip22-reset.c
++++ b/arch/mips/sgi-ip22/ip22-reset.c
+@@ -123,7 +123,8 @@ static inline void power_button(void)
+ if (machine_state & MACHINE_PANICED)
+ return;
+
+- if ((machine_state & MACHINE_SHUTTING_DOWN) || kill_proc(1,SIGINT,1)) {
++ if ((machine_state & MACHINE_SHUTTING_DOWN) ||
++ kill_cad_pid(SIGINT, 1)) {
+ /* No init process or button pressed twice. */
+ sgi_machine_power_off();
+ }
+@@ -168,7 +169,7 @@ static inline void volume_down_button(un
+ }
+ }
+
+-static irqreturn_t panel_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t panel_int(int irq, void *dev_id)
+ {
+ unsigned int buttons;
+
+diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
+index 0e06189..2055547 100644
+--- a/arch/mips/sgi-ip22/ip22-time.c
++++ b/arch/mips/sgi-ip22/ip22-time.c
+@@ -175,7 +175,7 @@ static __init void indy_time_init(void)
+ }
+
+ /* Generic SGI handler for (spurious) 8254 interrupts */
+-void indy_8254timer_irq(struct pt_regs *regs)
++void indy_8254timer_irq(void)
+ {
+ int irq = SGI_8254_0_IRQ;
+ ULONG cnt;
+@@ -189,13 +189,13 @@ void indy_8254timer_irq(struct pt_regs *
+ irq_exit();
+ }
+
+-void indy_r4k_timer_interrupt(struct pt_regs *regs)
++void indy_r4k_timer_interrupt(void)
+ {
+ int irq = SGI_TIMER_IRQ;
+
+ irq_enter();
+ kstat_this_cpu.irqs[irq]++;
+- timer_interrupt(irq, NULL, regs);
++ timer_interrupt(irq, NULL);
+ irq_exit();
+ }
+
+diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
+index 24a8537..270ecd3 100644
+--- a/arch/mips/sgi-ip27/ip27-irq.c
++++ b/arch/mips/sgi-ip27/ip27-irq.c
+@@ -30,7 +30,6 @@
+ #include <asm/mipsregs.h>
+ #include <asm/system.h>
+
+-#include <asm/ptrace.h>
+ #include <asm/processor.h>
+ #include <asm/pci/bridge.h>
+ #include <asm/sn/addrs.h>
+@@ -129,7 +128,7 @@ static int ms1bit(unsigned long x)
+ * Kanoj 05.13.00
+ */
+
+-static void ip27_do_irq_mask0(struct pt_regs *regs)
++static void ip27_do_irq_mask0(void)
+ {
+ int irq, swlevel;
+ hubreg_t pend0, mask0;
+@@ -164,13 +163,13 @@ static void ip27_do_irq_mask0(struct pt_
+ struct slice_data *si = cpu_data[cpu].data;
+
+ irq = si->level_to_irq[swlevel];
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+ LOCAL_HUB_L(PI_INT_PEND0);
+ }
+
+-static void ip27_do_irq_mask1(struct pt_regs *regs)
++static void ip27_do_irq_mask1(void)
+ {
+ int irq, swlevel;
+ hubreg_t pend1, mask1;
+@@ -190,17 +189,17 @@ static void ip27_do_irq_mask1(struct pt_
+ /* "map" swlevel to irq */
+ irq = si->level_to_irq[swlevel];
+ LOCAL_HUB_CLR_INTR(swlevel);
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+
+ LOCAL_HUB_L(PI_INT_PEND1);
+ }
+
+-static void ip27_prof_timer(struct pt_regs *regs)
++static void ip27_prof_timer(void)
+ {
+ panic("CPU %d got a profiling interrupt", smp_processor_id());
+ }
+
+-static void ip27_hub_error(struct pt_regs *regs)
++static void ip27_hub_error(void)
+ {
+ panic("CPU %d got a hub error interrupt", smp_processor_id());
+ }
+@@ -355,29 +354,6 @@ static struct irq_chip bridge_irq_type =
+ .end = end_bridge_irq,
+ };
+
+-static unsigned long irq_map[NR_IRQS / BITS_PER_LONG];
+-
+-int allocate_irqno(void)
+-{
+- int irq;
+-
+-again:
+- irq = find_first_zero_bit(irq_map, NR_IRQS);
+-
+- if (irq >= NR_IRQS)
+- return -ENOSPC;
+-
+- if (test_and_set_bit(irq, irq_map))
+- goto again;
+-
+- return irq;
+-}
+-
+-void free_irqno(unsigned int irq)
+-{
+- clear_bit(irq, irq_map);
+-}
+-
+ void __devinit register_bridge_irq(unsigned int irq)
+ {
+ irq_desc[irq].status = IRQ_DISABLED;
+@@ -418,22 +394,22 @@ int __devinit request_bridge_irq(struct
+ return irq;
+ }
+
+-extern void ip27_rt_timer_interrupt(struct pt_regs *regs);
++extern void ip27_rt_timer_interrupt(void);
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned long pending = read_c0_cause() & read_c0_status();
+
+ if (pending & CAUSEF_IP4)
+- ip27_rt_timer_interrupt(regs);
++ ip27_rt_timer_interrupt();
+ else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
+- ip27_do_irq_mask0(regs);
++ ip27_do_irq_mask0();
+ else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
+- ip27_do_irq_mask1(regs);
++ ip27_do_irq_mask1();
+ else if (pending & CAUSEF_IP5)
+- ip27_prof_timer(regs);
++ ip27_prof_timer();
+ else if (pending & CAUSEF_IP6)
+- ip27_hub_error(regs);
++ ip27_hub_error();
+ }
+
+ void __init arch_init_irq(void)
+diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c
+index d777b7d..f9f404a 100644
+--- a/arch/mips/sgi-ip27/ip27-klnuma.c
++++ b/arch/mips/sgi-ip27/ip27-klnuma.c
+@@ -26,7 +26,7 @@ static cpumask_t ktext_repmask;
+ * kernel. For example, we should never put a copy on a headless node,
+ * and we should respect the topology of the machine.
+ */
+-void __init setup_replication_mask()
++void __init setup_replication_mask(void)
+ {
+ cnodeid_t cnode;
+
+diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
+index efe6971..16e5682 100644
+--- a/arch/mips/sgi-ip27/ip27-memory.c
++++ b/arch/mips/sgi-ip27/ip27-memory.c
+@@ -19,6 +19,7 @@
+ #include <linux/swap.h>
+ #include <linux/bootmem.h>
+ #include <linux/pfn.h>
++#include <linux/highmem.h>
+ #include <asm/page.h>
+ #include <asm/sections.h>
+
+@@ -508,7 +509,7 @@ extern unsigned long setup_zero_pages(vo
+
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+ unsigned node;
+
+ pagetable_init();
+diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
+index b029ba7..5e82a26 100644
+--- a/arch/mips/sgi-ip27/ip27-timer.c
++++ b/arch/mips/sgi-ip27/ip27-timer.c
+@@ -42,8 +42,6 @@
+ static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */
+ static long last_rtc_update; /* Last time the rtc clock got updated */
+
+-extern volatile unsigned long wall_jiffies;
+-
+ #if 0
+ static int set_rtc_mmss(unsigned long nowtime)
+ {
+@@ -91,7 +89,7 @@ static int set_rtc_mmss(unsigned long no
+
+ static unsigned int rt_timer_irq;
+
+-void ip27_rt_timer_interrupt(struct pt_regs *regs)
++void ip27_rt_timer_interrupt(void)
+ {
+ int cpu = smp_processor_id();
+ int cpuA = cputoslice(cpu) == 0;
+@@ -111,9 +109,9 @@ again:
+ kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */
+
+ if (cpu == 0)
+- do_timer(regs);
++ do_timer(1);
+
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+@@ -136,13 +134,6 @@ again:
+ irq_exit();
+ }
+
+-unsigned long ip27_do_gettimeoffset(void)
+-{
+- unsigned long ct_cur1;
+- ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY;
+- return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000;
+-}
+-
+ /* Includes for ioc3_init(). */
+ #include <asm/sn/types.h>
+ #include <asm/sn/sn0/addrs.h>
+@@ -223,8 +214,6 @@ static struct irqaction rt_irqaction = {
+ .name = "timer"
+ };
+
+-extern int allocate_irqno(void);
+-
+ void __init plat_timer_setup(struct irqaction *irq)
+ {
+ int irqno = allocate_irqno();
+@@ -250,12 +239,17 @@ void __init plat_timer_setup(struct irqa
+ setup_irq(irqno, &rt_irqaction);
+ }
+
++static unsigned int ip27_hpt_read(void)
++{
++ return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
++}
++
+ void __init ip27_time_init(void)
+ {
++ mips_hpt_read = ip27_hpt_read;
++ mips_hpt_frequency = CYCLES_PER_SEC;
+ xtime.tv_sec = get_m48t35_time();
+ xtime.tv_nsec = 0;
+-
+- do_gettimeoffset = ip27_do_gettimeoffset;
+ }
+
+ void __init cpu_time_init(void)
+diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c
+index 41b5eca..bff5087 100644
+--- a/arch/mips/sgi-ip32/crime.c
++++ b/arch/mips/sgi-ip32/crime.c
+@@ -14,7 +14,6 @@
+ #include <asm/bootinfo.h>
+ #include <asm/io.h>
+ #include <asm/mipsregs.h>
+-#include <asm/ptrace.h>
+ #include <asm/page.h>
+ #include <asm/ip32/crime.h>
+ #include <asm/ip32/mace.h>
+@@ -40,8 +39,7 @@ void __init crime_init(void)
+ id, rev, field, (unsigned long) CRIME_BASE);
+ }
+
+-irqreturn_t
+-crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id)
+ {
+ unsigned long stat, addr;
+ int fatal = 0;
+@@ -92,8 +90,7 @@ crime_memerr_intr (unsigned int irq, voi
+ return IRQ_HANDLED;
+ }
+
+-irqreturn_t
+-crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id)
+ {
+ unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
+ unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
+diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
+index c64a820..c9acadd 100644
+--- a/arch/mips/sgi-ip32/ip32-irq.c
++++ b/arch/mips/sgi-ip32/ip32-irq.c
+@@ -120,10 +120,8 @@ static void inline flush_mace_bus(void)
+ static DEFINE_SPINLOCK(ip32_irq_lock);
+
+ /* Some initial interrupts to set up */
+-extern irqreturn_t crime_memerr_intr (int irq, void *dev_id,
+- struct pt_regs *regs);
+-extern irqreturn_t crime_cpuerr_intr (int irq, void *dev_id,
+- struct pt_regs *regs);
++extern irqreturn_t crime_memerr_intr(int irq, void *dev_id);
++extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
+
+ struct irqaction memerr_irq = { crime_memerr_intr, IRQF_DISABLED,
+ CPU_MASK_NONE, "CRIME memory error", NULL, NULL };
+@@ -479,7 +477,7 @@ static struct irq_chip ip32_mace_interru
+ .end = end_mace_irq,
+ };
+
+-static void ip32_unknown_interrupt(struct pt_regs *regs)
++static void ip32_unknown_interrupt(void)
+ {
+ printk ("Unknown interrupt occurred!\n");
+ printk ("cp0_status: %08x\n", read_c0_status());
+@@ -492,7 +490,7 @@ static void ip32_unknown_interrupt(struc
+ printk ("MACE PCI control register: %08x\n", mace->pci.control);
+
+ printk("Register dump:\n");
+- show_regs(regs);
++ show_regs(get_irq_regs());
+
+ printk("Please mail this report to linux-mips at linux-mips.org\n");
+ printk("Spinning...");
+@@ -501,7 +499,7 @@ static void ip32_unknown_interrupt(struc
+
+ /* CRIME 1.1 appears to deliver all interrupts to this one pin. */
+ /* change this to loop over all edge-triggered irqs, exception masked out ones */
+-static void ip32_irq0(struct pt_regs *regs)
++static void ip32_irq0(void)
+ {
+ uint64_t crime_int;
+ int irq = 0;
+@@ -516,50 +514,50 @@ static void ip32_irq0(struct pt_regs *re
+ }
+ irq++;
+ DBG("*irq %u*\n", irq);
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+-static void ip32_irq1(struct pt_regs *regs)
++static void ip32_irq1(void)
+ {
+- ip32_unknown_interrupt(regs);
++ ip32_unknown_interrupt();
+ }
+
+-static void ip32_irq2(struct pt_regs *regs)
++static void ip32_irq2(void)
+ {
+- ip32_unknown_interrupt(regs);
++ ip32_unknown_interrupt();
+ }
+
+-static void ip32_irq3(struct pt_regs *regs)
++static void ip32_irq3(void)
+ {
+- ip32_unknown_interrupt(regs);
++ ip32_unknown_interrupt();
+ }
+
+-static void ip32_irq4(struct pt_regs *regs)
++static void ip32_irq4(void)
+ {
+- ip32_unknown_interrupt(regs);
++ ip32_unknown_interrupt();
+ }
+
+-static void ip32_irq5(struct pt_regs *regs)
++static void ip32_irq5(void)
+ {
+- ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
++ ll_timer_interrupt(IP32_R4K_TIMER_IRQ);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause();
+
+ if (likely(pending & IE_IRQ0))
+- ip32_irq0(regs);
++ ip32_irq0();
+ else if (unlikely(pending & IE_IRQ1))
+- ip32_irq1(regs);
++ ip32_irq1();
+ else if (unlikely(pending & IE_IRQ2))
+- ip32_irq2(regs);
++ ip32_irq2();
+ else if (unlikely(pending & IE_IRQ3))
+- ip32_irq3(regs);
++ ip32_irq3();
+ else if (unlikely(pending & IE_IRQ4))
+- ip32_irq4(regs);
++ ip32_irq4();
+ else if (likely(pending & IE_IRQ5))
+- ip32_irq5(regs);
++ ip32_irq5();
+ }
+
+ void __init arch_init_irq(void)
+diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
+index 79ddb46..db80844 100644
+--- a/arch/mips/sgi-ip32/ip32-reset.c
++++ b/arch/mips/sgi-ip32/ip32-reset.c
+@@ -120,7 +120,7 @@ static inline void ip32_power_button(voi
+ if (has_panicked)
+ return;
+
+- if (shuting_down || kill_proc(1, SIGINT, 1)) {
++ if (shuting_down || kill_cad_pid(SIGINT, 1)) {
+ /* No init process or button pressed twice. */
+ ip32_machine_power_off();
+ }
+@@ -135,7 +135,7 @@ static inline void ip32_power_button(voi
+ add_timer(&power_timer);
+ }
+
+-static irqreturn_t ip32_rtc_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ip32_rtc_int(int irq, void *dev_id)
+ {
+ volatile unsigned char reg_c;
+
+diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
+index ed325f0..8b1f414 100644
+--- a/arch/mips/sibyte/bcm1480/irq.c
++++ b/arch/mips/sibyte/bcm1480/irq.c
+@@ -25,9 +25,9 @@
+ #include <linux/kernel_stat.h>
+
+ #include <asm/errno.h>
++#include <asm/irq_regs.h>
+ #include <asm/signal.h>
+ #include <asm/system.h>
+-#include <asm/ptrace.h>
+ #include <asm/io.h>
+
+ #include <asm/sibyte/bcm1480_regs.h>
+@@ -284,8 +284,7 @@ void __init init_bcm1480_irqs(void)
+ }
+
+
+-static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id)
+ {
+ return IRQ_NONE;
+ }
+@@ -453,7 +452,7 @@ void __init arch_init_irq(void)
+ #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
+ #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
+
+-void bcm1480_kgdb_interrupt(struct pt_regs *regs)
++static void bcm1480_kgdb_interrupt(void)
+ {
+ /*
+ * Clear break-change status (allow some time for the remote
+@@ -464,31 +463,15 @@ void bcm1480_kgdb_interrupt(struct pt_re
+ mdelay(500);
+ duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
+ M_DUART_RX_EN | M_DUART_TX_EN);
+- set_async_breakpoint(®s->cp0_epc);
++ set_async_breakpoint(&get_irq_regs()->cp0_epc);
+ }
+
+ #endif /* CONFIG_KGDB */
+
+-static inline int dclz(unsigned long long x)
+-{
+- int lz;
+-
+- __asm__ (
+- " .set push \n"
+- " .set mips64 \n"
+- " dclz %0, %1 \n"
+- " .set pop \n"
+- : "=r" (lz)
+- : "r" (x));
+-
+- return lz;
+-}
+-
+-extern void bcm1480_timer_interrupt(struct pt_regs *regs);
+-extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
+-extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
++extern void bcm1480_timer_interrupt(void);
++extern void bcm1480_mailbox_interrupt(void);
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending;
+
+@@ -497,25 +480,25 @@ asmlinkage void plat_irq_dispatch(struct
+ write_c0_compare(read_c0_count());
+ #endif
+
+- pending = read_c0_cause();
++ pending = read_c0_cause() & read_c0_status();
+
+ #ifdef CONFIG_SIBYTE_BCM1480_PROF
+ if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
+- sbprof_cpu_intr(exception_epc(regs));
++ sbprof_cpu_intr();
+ else
+ #endif
+
+ if (pending & CAUSEF_IP4)
+- bcm1480_timer_interrupt(regs);
++ bcm1480_timer_interrupt();
+
+ #ifdef CONFIG_SMP
+ else if (pending & CAUSEF_IP3)
+- bcm1480_mailbox_interrupt(regs);
++ bcm1480_mailbox_interrupt();
+ #endif
+
+ #ifdef CONFIG_KGDB
+ else if (pending & CAUSEF_IP6)
+- bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */
++ bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */
+ #endif
+
+ else if (pending & CAUSEF_IP2) {
+@@ -536,9 +519,9 @@ asmlinkage void plat_irq_dispatch(struct
+
+ if (mask_h) {
+ if (mask_h ^ 1)
+- do_IRQ(63 - dclz(mask_h), regs);
++ do_IRQ(fls64(mask_h) - 1);
+ else
+- do_IRQ(127 - dclz(mask_l), regs);
++ do_IRQ(63 + fls64(mask_l));
+ }
+ }
+ }
+diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
+index 584a4b3..bf32827 100644
+--- a/arch/mips/sibyte/bcm1480/smp.c
++++ b/arch/mips/sibyte/bcm1480/smp.c
+@@ -34,21 +34,21 @@ extern void smp_call_function_interrupt(
+ * independent of board/firmware
+ */
+
+-static void *mailbox_0_set_regs[] = {
++static volatile void *mailbox_0_set_regs[] = {
+ IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+ IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+ IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+ IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+ };
+
+-static void *mailbox_0_clear_regs[] = {
++static volatile void *mailbox_0_clear_regs[] = {
+ IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+ IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+ IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+ IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+ };
+
+-static void *mailbox_0_regs[] = {
++static volatile void *mailbox_0_regs[] = {
+ IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+ IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+ IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+@@ -88,7 +88,7 @@ void core_send_ipi(int cpu, unsigned int
+ __raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
+ }
+
+-void bcm1480_mailbox_interrupt(struct pt_regs *regs)
++void bcm1480_mailbox_interrupt(void)
+ {
+ int cpu = smp_processor_id();
+ unsigned int action;
+diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c
+index 7e088f6..e136bde 100644
+--- a/arch/mips/sibyte/bcm1480/time.c
++++ b/arch/mips/sibyte/bcm1480/time.c
+@@ -31,7 +31,6 @@
+ #include <linux/kernel_stat.h>
+
+ #include <asm/irq.h>
+-#include <asm/ptrace.h>
+ #include <asm/addrspace.h>
+ #include <asm/time.h>
+ #include <asm/io.h>
+@@ -48,6 +47,12 @@
+ #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1
+ #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2
+
++#ifdef CONFIG_SIMULATION
++#define BCM1480_HPT_VALUE 50000
++#else
++#define BCM1480_HPT_VALUE 1000000
++#endif
++
+ extern int bcm1480_steal_irq(int irq);
+
+ void bcm1480_time_init(void)
+@@ -60,11 +65,6 @@ void bcm1480_time_init(void)
+ BUG();
+ }
+
+- if (!cpu) {
+- /* Use our own gettimeoffset() routine */
+- do_gettimeoffset = bcm1480_gettimeoffset;
+- }
+-
+ bcm1480_mask_irq(cpu, irq);
+
+ /* Map the timer interrupt to ip[4] of this cpu */
+@@ -75,11 +75,7 @@ void bcm1480_time_init(void)
+ /* Disable the timer and set up the count */
+ __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
+ __raw_writeq(
+-#ifndef CONFIG_SIMULATION
+- 1000000/HZ
+-#else
+- 50000/HZ
+-#endif
++ BCM1480_HPT_VALUE/HZ
+ , IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)));
+
+ /* Set the timer running */
+@@ -100,10 +96,10 @@ void bcm1480_time_init(void)
+
+ #include <asm/sibyte/sb1250.h>
+
+-void bcm1480_timer_interrupt(struct pt_regs *regs)
++void bcm1480_timer_interrupt(void)
+ {
+ int cpu = smp_processor_id();
+- int irq = K_BCM1480_INT_TIMER_0+cpu;
++ int irq = K_BCM1480_INT_TIMER_0 + cpu;
+
+ /* Reset the timer */
+ __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
+@@ -113,26 +109,26 @@ void bcm1480_timer_interrupt(struct pt_r
+ /*
+ * CPU 0 handles the global timer interrupt job
+ */
+- ll_timer_interrupt(irq, regs);
++ ll_timer_interrupt(irq);
+ }
+ else {
+ /*
+ * other CPUs should just do profiling and process accounting
+ */
+- ll_local_timer_interrupt(irq, regs);
++ ll_local_timer_interrupt(irq);
+ }
+ }
+
+-/*
+- * We use our own do_gettimeoffset() instead of the generic one,
+- * because the generic one does not work for SMP case.
+- * In addition, since we use general timer 0 for system time,
+- * we can get accurate intra-jiffy offset without calibration.
+- */
+-unsigned long bcm1480_gettimeoffset(void)
++static unsigned int bcm1480_hpt_read(void)
+ {
++ /* We assume this function is called xtime_lock held. */
+ unsigned long count =
+ __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT)));
++ return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count;
++}
+
+- return 1000000/HZ - count;
++void __init bcm1480_hpt_setup(void)
++{
++ mips_hpt_read = bcm1480_hpt_read;
++ mips_hpt_frequency = BCM1480_HPT_VALUE;
+ }
+diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
+index 992e0d8..d1a906e 100644
+--- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
++++ b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
+@@ -88,7 +88,7 @@ static void arm_tb(void)
+ sbp.tb_armed = 1;
+ }
+
+-static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
+ {
+ int i;
+ DBG(printk(DEVNAME ": tb_intr\n"));
+@@ -138,7 +138,7 @@ static irqreturn_t sbprof_tb_intr(int ir
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sbprof_pc_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
+ {
+ printk(DEVNAME ": unexpected pc_intr");
+ return IRQ_NONE;
+diff --git a/arch/mips/sibyte/sb1250/bus_watcher.c b/arch/mips/sibyte/sb1250/bus_watcher.c
+index bb90649..45274bd 100644
+--- a/arch/mips/sibyte/sb1250/bus_watcher.c
++++ b/arch/mips/sibyte/sb1250/bus_watcher.c
+@@ -171,7 +171,7 @@ static void create_proc_decoder(struct b
+ * notes: possible re-entry due to multiple sources
+ * should check/indicate saturation
+ */
+-static irqreturn_t sibyte_bw_int(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t sibyte_bw_int(int irq, void *data)
+ {
+ struct bw_stats_struct *stats = data;
+ unsigned long cntr;
+diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
+index 1de71ad..d5d2677 100644
+--- a/arch/mips/sibyte/sb1250/irq.c
++++ b/arch/mips/sibyte/sb1250/irq.c
+@@ -28,7 +28,6 @@
+ #include <asm/errno.h>
+ #include <asm/signal.h>
+ #include <asm/system.h>
+-#include <asm/ptrace.h>
+ #include <asm/io.h>
+
+ #include <asm/sibyte/sb1250_regs.h>
+@@ -254,8 +253,7 @@ void __init init_sb1250_irqs(void)
+ }
+
+
+-static irqreturn_t sb1250_dummy_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t sb1250_dummy_handler(int irq, void *dev_id)
+ {
+ return IRQ_NONE;
+ }
+@@ -403,7 +401,7 @@ void __init arch_init_irq(void)
+ #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
+ #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
+
+-static void sb1250_kgdb_interrupt(struct pt_regs *regs)
++static void sb1250_kgdb_interrupt(void)
+ {
+ /*
+ * Clear break-change status (allow some time for the remote
+@@ -414,31 +412,15 @@ static void sb1250_kgdb_interrupt(struct
+ mdelay(500);
+ duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
+ M_DUART_RX_EN | M_DUART_TX_EN);
+- set_async_breakpoint(®s->cp0_epc);
++ set_async_breakpoint(&get_irq_regs()->cp0_epc);
+ }
+
+ #endif /* CONFIG_KGDB */
+
+-static inline int dclz(unsigned long long x)
+-{
+- int lz;
+-
+- __asm__ (
+- " .set push \n"
+- " .set mips64 \n"
+- " dclz %0, %1 \n"
+- " .set pop \n"
+- : "=r" (lz)
+- : "r" (x));
+-
+- return lz;
+-}
+-
+-extern void sb1250_timer_interrupt(struct pt_regs *regs);
+-extern void sb1250_mailbox_interrupt(struct pt_regs *regs);
+-extern void sb1250_kgdb_interrupt(struct pt_regs *regs);
++extern void sb1250_timer_interrupt(void);
++extern void sb1250_mailbox_interrupt(void);
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending;
+
+@@ -457,25 +439,25 @@ asmlinkage void plat_irq_dispatch(struct
+ * blasting the high 32 bits.
+ */
+
+- pending = read_c0_cause();
++ pending = read_c0_cause() & read_c0_status();
+
+ #ifdef CONFIG_SIBYTE_SB1250_PROF
+ if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
+- sbprof_cpu_intr(exception_epc(regs));
++ sbprof_cpu_intr();
+ else
+ #endif
+
+ if (pending & CAUSEF_IP4)
+- sb1250_timer_interrupt(regs);
++ sb1250_timer_interrupt();
+
+ #ifdef CONFIG_SMP
+ else if (pending & CAUSEF_IP3)
+- sb1250_mailbox_interrupt(regs);
++ sb1250_mailbox_interrupt();
+ #endif
+
+ #ifdef CONFIG_KGDB
+ else if (pending & CAUSEF_IP6) /* KGDB (uart 1) */
+- sb1250_kgdb_interrupt(regs);
++ sb1250_kgdb_interrupt();
+ #endif
+
+ else if (pending & CAUSEF_IP2) {
+@@ -490,6 +472,9 @@ asmlinkage void plat_irq_dispatch(struct
+ mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
+ R_IMR_INTERRUPT_STATUS_BASE)));
+ if (mask)
+- do_IRQ(63 - dclz(mask), regs);
+- }
++ do_IRQ(fls64(mask) - 1);
++ else
++ spurious_interrupt();
++ } else
++ spurious_interrupt();
+ }
+diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
+index f859db0..c38e1f3 100644
+--- a/arch/mips/sibyte/sb1250/smp.c
++++ b/arch/mips/sibyte/sb1250/smp.c
+@@ -76,7 +76,7 @@ void core_send_ipi(int cpu, unsigned int
+ __raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]);
+ }
+
+-void sb1250_mailbox_interrupt(struct pt_regs *regs)
++void sb1250_mailbox_interrupt(void)
+ {
+ int cpu = smp_processor_id();
+ unsigned int action;
+diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
+index 4b669dc..bcb74f2 100644
+--- a/arch/mips/sibyte/sb1250/time.c
++++ b/arch/mips/sibyte/sb1250/time.c
+@@ -31,7 +31,6 @@
+ #include <linux/kernel_stat.h>
+
+ #include <asm/irq.h>
+-#include <asm/ptrace.h>
+ #include <asm/addrspace.h>
+ #include <asm/time.h>
+ #include <asm/io.h>
+@@ -48,15 +47,11 @@
+
+ #define SB1250_HPT_NUM 3
+ #define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */
+-#define SB1250_HPT_SHIFT ((sizeof(unsigned int)*8)-V_SCD_TIMER_WIDTH)
+
+
+ extern int sb1250_steal_irq(int irq);
+
+ static unsigned int sb1250_hpt_read(void);
+-static void sb1250_hpt_init(unsigned int);
+-
+-static unsigned int hpt_offset;
+
+ void __init sb1250_hpt_setup(void)
+ {
+@@ -70,13 +65,9 @@ void __init sb1250_hpt_setup(void)
+ __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
+ IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
+
+- /*
+- * we need to fill 32 bits, so just use the upper 23 bits and pretend
+- * the timer is going 512Mhz instead of 1Mhz
+- */
+- mips_hpt_frequency = V_SCD_TIMER_FREQ << SB1250_HPT_SHIFT;
+- mips_hpt_init = sb1250_hpt_init;
++ mips_hpt_frequency = V_SCD_TIMER_FREQ;
+ mips_hpt_read = sb1250_hpt_read;
++ mips_hpt_mask = M_SCD_TIMER_INIT;
+ }
+ }
+
+@@ -125,7 +116,7 @@ void sb1250_time_init(void)
+ */
+ }
+
+-void sb1250_timer_interrupt(struct pt_regs *regs)
++void sb1250_timer_interrupt(void)
+ {
+ int cpu = smp_processor_id();
+ int irq = K_INT_TIMER_0 + cpu;
+@@ -138,23 +129,19 @@ void sb1250_timer_interrupt(struct pt_re
+ /*
+ * CPU 0 handles the global timer interrupt job
+ */
+- ll_timer_interrupt(irq, regs);
++ ll_timer_interrupt(irq);
+ }
+ else {
+ /*
+ * other CPUs should just do profiling and process accounting
+ */
+- ll_local_timer_interrupt(irq, regs);
++ ll_local_timer_interrupt(irq);
+ }
+ }
+
+ /*
+ * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over
+- * again. There's no easy way to set to a specific value so store init value
+- * in hpt_offset and subtract each time.
+- *
+- * Note: Timer isn't full 32bits so shift it into the upper part making
+- * it appear to run at a higher frequency.
++ * again.
+ */
+ static unsigned int sb1250_hpt_read(void)
+ {
+@@ -162,13 +149,5 @@ static unsigned int sb1250_hpt_read(void
+
+ count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT))));
+
+- count = (SB1250_HPT_VALUE - count) << SB1250_HPT_SHIFT;
+-
+- return count - hpt_offset;
+-}
+-
+-static void sb1250_hpt_init(unsigned int count)
+-{
+- hpt_offset = count;
+- return;
++ return SB1250_HPT_VALUE - count;
+ }
+diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
+index cda165f..48fb74a 100644
+--- a/arch/mips/sni/irq.c
++++ b/arch/mips/sni/irq.c
+@@ -69,20 +69,20 @@ static struct irq_chip pciasic_irq_type
+ * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
+ * button interrupts. Later ...
+ */
+-static void pciasic_hwint0(struct pt_regs *regs)
++static void pciasic_hwint0(void)
+ {
+ panic("Received int0 but no handler yet ...");
+ }
+
+ /* This interrupt was used for the com1 console on the first prototypes. */
+-static void pciasic_hwint2(struct pt_regs *regs)
++static void pciasic_hwint2(void)
+ {
+ /* I think this shouldn't happen on production machines. */
+ panic("hwint2 and no handler yet");
+ }
+
+ /* hwint5 is the r4k count / compare interrupt */
+-static void pciasic_hwint5(struct pt_regs *regs)
++static void pciasic_hwint5(void)
+ {
+ panic("hwint5 and no handler yet");
+ }
+@@ -103,7 +103,7 @@ static unsigned int ls1bit8(unsigned int
+ *
+ * The EISA_INT bit in CSITPEND is high active, all others are low active.
+ */
+-static void pciasic_hwint1(struct pt_regs *regs)
++static void pciasic_hwint1(void)
+ {
+ u8 pend = *(volatile char *)PCIMT_CSITPEND;
+ unsigned long flags;
+@@ -119,13 +119,13 @@ static void pciasic_hwint1(struct pt_reg
+ if (unlikely(irq < 0))
+ return;
+
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+ if (!(pend & IT_SCSI)) {
+ flags = read_c0_status();
+ clear_c0_status(ST0_IM);
+- do_IRQ(PCIMT_IRQ_SCSI, regs);
++ do_IRQ(PCIMT_IRQ_SCSI);
+ write_c0_status(flags);
+ }
+ }
+@@ -133,7 +133,7 @@ static void pciasic_hwint1(struct pt_reg
+ /*
+ * hwint 3 should deal with the PCI A - D interrupts,
+ */
+-static void pciasic_hwint3(struct pt_regs *regs)
++static void pciasic_hwint3(void)
+ {
+ u8 pend = *(volatile char *)PCIMT_CSITPEND;
+ int irq;
+@@ -141,21 +141,21 @@ static void pciasic_hwint3(struct pt_reg
+ pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
+ clear_c0_status(IE_IRQ3);
+ irq = PCIMT_IRQ_INT2 + ls1bit8(pend);
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ set_c0_status(IE_IRQ3);
+ }
+
+ /*
+ * hwint 4 is used for only the onboard PCnet 32.
+ */
+-static void pciasic_hwint4(struct pt_regs *regs)
++static void pciasic_hwint4(void)
+ {
+ clear_c0_status(IE_IRQ4);
+- do_IRQ(PCIMT_IRQ_ETHERNET, regs);
++ do_IRQ(PCIMT_IRQ_ETHERNET);
+ set_c0_status(IE_IRQ4);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+ static unsigned char led_cache;
+@@ -163,17 +163,17 @@ asmlinkage void plat_irq_dispatch(struct
+ *(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
+
+ if (pending & 0x0800)
+- pciasic_hwint1(regs);
++ pciasic_hwint1();
+ else if (pending & 0x4000)
+- pciasic_hwint4(regs);
++ pciasic_hwint4();
+ else if (pending & 0x2000)
+- pciasic_hwint3(regs);
++ pciasic_hwint3();
+ else if (pending & 0x1000)
+- pciasic_hwint2(regs);
++ pciasic_hwint2();
+ else if (pending & 0x8000)
+- pciasic_hwint5(regs);
++ pciasic_hwint5();
+ else if (pending & 0x0400)
+- pciasic_hwint0(regs);
++ pciasic_hwint0();
+ }
+
+ void __init init_pciasic(void)
+diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
+index 4e98feb..afeb7f1 100644
+--- a/arch/mips/sni/setup.c
++++ b/arch/mips/sni/setup.c
+@@ -31,7 +31,6 @@
+ #include <asm/irq.h>
+ #include <asm/mc146818-time.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/sni.h>
+ #include <asm/time.h>
+diff --git a/arch/mips/tx4927/common/smsc_fdc37m81x.c b/arch/mips/tx4927/common/smsc_fdc37m81x.c
+new file mode 100644
+index 0000000..33f517b
+--- /dev/null
++++ b/arch/mips/tx4927/common/smsc_fdc37m81x.c
+@@ -0,0 +1,172 @@
++/*
++ * Interface for smsc fdc48m81x Super IO chip
++ *
++ * Author: MontaVista Software, Inc. source at mvista.com
++ *
++ * 2001-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.
++ *
++ * Copyright 2004 (c) MontaVista Software, Inc.
++ */
++#include <linux/init.h>
++#include <linux/types.h>
++#include <asm/io.h>
++#include <asm/tx4927/smsc_fdc37m81x.h>
++
++#define DEBUG
++
++/* Common Registers */
++#define SMSC_FDC37M81X_CONFIG_INDEX 0x00
++#define SMSC_FDC37M81X_CONFIG_DATA 0x01
++#define SMSC_FDC37M81X_CONF 0x02
++#define SMSC_FDC37M81X_INDEX 0x03
++#define SMSC_FDC37M81X_DNUM 0x07
++#define SMSC_FDC37M81X_DID 0x20
++#define SMSC_FDC37M81X_DREV 0x21
++#define SMSC_FDC37M81X_PCNT 0x22
++#define SMSC_FDC37M81X_PMGT 0x23
++#define SMSC_FDC37M81X_OSC 0x24
++#define SMSC_FDC37M81X_CONFPA0 0x26
++#define SMSC_FDC37M81X_CONFPA1 0x27
++#define SMSC_FDC37M81X_TEST4 0x2B
++#define SMSC_FDC37M81X_TEST5 0x2C
++#define SMSC_FDC37M81X_TEST1 0x2D
++#define SMSC_FDC37M81X_TEST2 0x2E
++#define SMSC_FDC37M81X_TEST3 0x2F
++
++/* Logical device numbers */
++#define SMSC_FDC37M81X_FDD 0x00
++#define SMSC_FDC37M81X_SERIAL1 0x04
++#define SMSC_FDC37M81X_SERIAL2 0x05
++#define SMSC_FDC37M81X_KBD 0x07
++
++/* Logical device Config Registers */
++#define SMSC_FDC37M81X_ACTIVE 0x30
++#define SMSC_FDC37M81X_BASEADDR0 0x60
++#define SMSC_FDC37M81X_BASEADDR1 0x61
++#define SMSC_FDC37M81X_INT 0x70
++#define SMSC_FDC37M81X_INT2 0x72
++#define SMSC_FDC37M81X_MODE 0xF0
++
++/* Chip Config Values */
++#define SMSC_FDC37M81X_CONFIG_ENTER 0x55
++#define SMSC_FDC37M81X_CONFIG_EXIT 0xaa
++#define SMSC_FDC37M81X_CHIP_ID 0x4d
++
++static unsigned long g_smsc_fdc37m81x_base = 0;
++
++static inline unsigned char smsc_fdc37m81x_rd(unsigned char index)
++{
++ outb(index, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
++
++ return inb(g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_DATA);
++}
++
++static inline void smsc_dc37m81x_wr(unsigned char index, unsigned char data)
++{
++ outb(index, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
++ outb(data, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_DATA);
++}
++
++void smsc_fdc37m81x_config_beg(void)
++{
++ if (g_smsc_fdc37m81x_base) {
++ outb(SMSC_FDC37M81X_CONFIG_ENTER,
++ g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
++ }
++}
++
++void smsc_fdc37m81x_config_end(void)
++{
++ if (g_smsc_fdc37m81x_base)
++ outb(SMSC_FDC37M81X_CONFIG_EXIT,
++ g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
++}
++
++u8 smsc_fdc37m81x_config_get(u8 reg)
++{
++ u8 val = 0;
++
++ if (g_smsc_fdc37m81x_base)
++ val = smsc_fdc37m81x_rd(reg);
++
++ return val;
++}
++
++void smsc_fdc37m81x_config_set(u8 reg, u8 val)
++{
++ if (g_smsc_fdc37m81x_base)
++ smsc_dc37m81x_wr(reg, val);
++}
++
++unsigned long __init smsc_fdc37m81x_init(unsigned long port)
++{
++ const int field = sizeof(unsigned long) * 2;
++ u8 chip_id;
++
++ if (g_smsc_fdc37m81x_base)
++ printk("smsc_fdc37m81x_init() stepping on old base=0x%0*lx\n",
++ field, g_smsc_fdc37m81x_base);
++
++ g_smsc_fdc37m81x_base = port;
++
++ smsc_fdc37m81x_config_beg();
++
++ chip_id = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DID);
++ if (chip_id == SMSC_FDC37M81X_CHIP_ID)
++ smsc_fdc37m81x_config_end();
++ else {
++ printk("smsc_fdc37m81x_init() unknow chip id 0x%02x\n",
++ chip_id);
++ g_smsc_fdc37m81x_base = 0;
++ }
++
++ return g_smsc_fdc37m81x_base;
++}
++
++#ifdef DEBUG
++void smsc_fdc37m81x_config_dump_one(char *key, u8 dev, u8 reg)
++{
++ printk("%s: dev=0x%02x reg=0x%02x val=0x%02x\n", key, dev, reg,
++ smsc_fdc37m81x_rd(reg));
++}
++
++void smsc_fdc37m81x_config_dump(void)
++{
++ u8 orig;
++ char *fname = "smsc_fdc37m81x_config_dump()";
++
++ smsc_fdc37m81x_config_beg();
++
++ orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM);
++
++ printk("%s: common\n", fname);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
++ SMSC_FDC37M81X_DNUM);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
++ SMSC_FDC37M81X_DID);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
++ SMSC_FDC37M81X_DREV);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
++ SMSC_FDC37M81X_PCNT);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
++ SMSC_FDC37M81X_PMGT);
++
++ printk("%s: keyboard\n", fname);
++ smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
++ SMSC_FDC37M81X_ACTIVE);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
++ SMSC_FDC37M81X_INT);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
++ SMSC_FDC37M81X_INT2);
++ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
++ SMSC_FDC37M81X_LDCR_F0);
++
++ smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, orig);
++
++ smsc_fdc37m81x_config_end();
++}
++#endif
+diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c
+index cd176f6..8266a88 100644
+--- a/arch/mips/tx4927/common/tx4927_irq.c
++++ b/arch/mips/tx4927/common/tx4927_irq.c
+@@ -576,24 +576,24 @@ static int tx4927_irq_nested(void)
+ return (sw_irq);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP7) /* cpu timer */
+- do_IRQ(TX4927_IRQ_CPU_TIMER, regs);
++ do_IRQ(TX4927_IRQ_CPU_TIMER);
+ else if (pending & STATUSF_IP2) { /* tx4927 pic */
+ unsigned int irq = tx4927_irq_nested();
+
+ if (unlikely(irq == 0)) {
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ return;
+ }
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ } else if (pending & STATUSF_IP0) /* user line 0 */
+- do_IRQ(TX4927_IRQ_USER0, regs);
++ do_IRQ(TX4927_IRQ_USER0);
+ else if (pending & STATUSF_IP1) /* user line 1 */
+- do_IRQ(TX4927_IRQ_USER1, regs);
++ do_IRQ(TX4927_IRQ_USER1);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c
+index 3ace403..941c441 100644
+--- a/arch/mips/tx4927/common/tx4927_setup.c
++++ b/arch/mips/tx4927/common/tx4927_setup.c
+@@ -53,19 +53,9 @@ void __init tx4927_time_init(void);
+ void dump_cp0(char *key);
+
+
+-void (*__wbflush) (void);
+-
+-static void tx4927_write_buffer_flush(void)
+-{
+- __asm__ __volatile__
+- ("sync\n\t" "nop\n\t" "loop: bc0f loop\n\t" "nop\n\t");
+-}
+-
+-
+ void __init plat_mem_setup(void)
+ {
+ board_time_init = tx4927_time_init;
+- __wbflush = tx4927_write_buffer_flush;
+
+ #ifdef CONFIG_TOSHIBA_RBTX4927
+ {
+@@ -122,8 +112,6 @@ void print_cp0(char *key, int num, char
+ return;
+ }
+
+-indent: Standard input:25: Error:Unexpected end of file
+-
+ void
+ dump_cp0(char *key)
+ {
+diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+index b0f021f..0c3c3f6 100644
+--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
++++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+@@ -127,9 +127,9 @@ JP7 is not bus master -- do NOT use -- o
+ #include <asm/irq.h>
+ #include <asm/pci.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
++#include <asm/wbflush.h>
+ #include <linux/bootmem.h>
+ #include <linux/blkdev.h>
+ #ifdef CONFIG_RTC_DS1742
+diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+index f0d70c4..735cb87 100644
+--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
++++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+@@ -58,8 +58,8 @@
+ #include <asm/page.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/irq_regs.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+ #include <linux/bootmem.h>
+@@ -160,8 +160,7 @@ int tx4927_pci66 = 0; /* 0:auto */
+ char *toshiba_name = "";
+
+ #ifdef CONFIG_PCI
+-static void tx4927_pcierr_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static void tx4927_pcierr_interrupt(int irq, void *dev_id)
+ {
+ #ifdef CONFIG_BLK_DEV_IDEPCI
+ /* ignore MasterAbort for ide probing... */
+@@ -185,7 +184,7 @@ static void tx4927_pcierr_interrupt(int
+ (unsigned long) tx4927_ccfgptr->ccfg,
+ (unsigned long) (tx4927_ccfgptr->tear >> 32),
+ (unsigned long) tx4927_ccfgptr->tear);
+- show_regs(regs);
++ show_regs(get_irq_regs());
+ }
+
+ void __init toshiba_rbtx4927_pci_irq_init(void)
+diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c
+index dc30d66..77fe245 100644
+--- a/arch/mips/tx4938/common/irq.c
++++ b/arch/mips/tx4938/common/irq.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/mps/tx4938/common/irq.c
++ * linux/arch/mips/tx4938/common/irq.c
+ *
+ * Common tx4938 irq handler
+ * Copyright (C) 2000-2001 Toshiba Corporation
+@@ -30,6 +30,7 @@
+ #include <asm/irq.h>
+ #include <asm/mipsregs.h>
+ #include <asm/system.h>
++#include <asm/wbflush.h>
+ #include <asm/tx4938/rbtx4938.h>
+
+ /**********************************************************************************/
+@@ -104,8 +105,6 @@ tx4938_irq_cp0_init(void)
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &tx4938_irq_cp0_type;
+ }
+-
+- return;
+ }
+
+ static unsigned int
+@@ -113,7 +112,7 @@ tx4938_irq_cp0_startup(unsigned int irq)
+ {
+ tx4938_irq_cp0_enable(irq);
+
+- return (0);
++ return 0;
+ }
+
+ static void
+@@ -144,16 +143,12 @@ tx4938_irq_cp0_disable(unsigned int irq)
+ clear_c0_status(tx4938_irq_cp0_mask(irq));
+
+ spin_unlock_irqrestore(&tx4938_cp0_lock, flags);
+-
+- return;
+ }
+
+ static void
+ tx4938_irq_cp0_mask_and_ack(unsigned int irq)
+ {
+ tx4938_irq_cp0_disable(irq);
+-
+- return;
+ }
+
+ static void
+@@ -162,8 +157,6 @@ tx4938_irq_cp0_end(unsigned int irq)
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ tx4938_irq_cp0_enable(irq);
+ }
+-
+- return;
+ }
+
+ /**********************************************************************************/
+@@ -227,7 +220,7 @@ tx4938_irq_pic_addr(int irq)
+ }
+ }
+
+- return (0);
++ return 0;
+ }
+
+ u32
+@@ -278,7 +271,7 @@ tx4938_irq_pic_mask(int irq)
+ return (0x00000007);
+ }
+ }
+- return (0x00000000);
++ return 0x00000000;
+ }
+
+ static void
+@@ -292,8 +285,6 @@ tx4938_irq_pic_modify(unsigned pic_reg,
+ TX4938_WR(pic_reg, val);
+ mmiowb();
+ TX4938_RD(pic_reg);
+-
+- return;
+ }
+
+ static void __init
+@@ -317,8 +308,6 @@ tx4938_irq_pic_init(void)
+ TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */
+
+ spin_unlock_irqrestore(&tx4938_pic_lock, flags);
+-
+- return;
+ }
+
+ static unsigned int
+@@ -326,15 +315,13 @@ tx4938_irq_pic_startup(unsigned int irq)
+ {
+ tx4938_irq_pic_enable(irq);
+
+- return (0);
++ return 0;
+ }
+
+ static void
+ tx4938_irq_pic_shutdown(unsigned int irq)
+ {
+ tx4938_irq_pic_disable(irq);
+-
+- return;
+ }
+
+ static void
+@@ -348,8 +335,6 @@ tx4938_irq_pic_enable(unsigned int irq)
+ tx4938_irq_pic_mask(irq));
+
+ spin_unlock_irqrestore(&tx4938_pic_lock, flags);
+-
+- return;
+ }
+
+ static void
+@@ -363,16 +348,12 @@ tx4938_irq_pic_disable(unsigned int irq)
+ tx4938_irq_pic_mask(irq), 0);
+
+ spin_unlock_irqrestore(&tx4938_pic_lock, flags);
+-
+- return;
+ }
+
+ static void
+ tx4938_irq_pic_mask_and_ack(unsigned int irq)
+ {
+ tx4938_irq_pic_disable(irq);
+-
+- return;
+ }
+
+ static void
+@@ -381,8 +362,6 @@ tx4938_irq_pic_end(unsigned int irq)
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ tx4938_irq_pic_enable(irq);
+ }
+-
+- return;
+ }
+
+ /**********************************************************************************/
+@@ -394,8 +373,6 @@ tx4938_irq_init(void)
+ {
+ tx4938_irq_cp0_init();
+ tx4938_irq_pic_init();
+-
+- return;
+ }
+
+ int
+@@ -417,23 +394,23 @@ tx4938_irq_nested(void)
+ }
+
+ wbflush();
+- return (sw_irq);
++ return sw_irq;
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP7)
+- do_IRQ(TX4938_IRQ_CPU_TIMER, regs);
++ do_IRQ(TX4938_IRQ_CPU_TIMER);
+ else if (pending & STATUSF_IP2) {
+ int irq = tx4938_irq_nested();
+ if (irq)
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ } else if (pending & STATUSF_IP1)
+- do_IRQ(TX4938_IRQ_USER1, regs);
++ do_IRQ(TX4938_IRQ_USER1);
+ else if (pending & STATUSF_IP0)
+- do_IRQ(TX4938_IRQ_USER0, regs);
++ do_IRQ(TX4938_IRQ_USER0);
+ }
+diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c
+index 71859c4..f415a1f 100644
+--- a/arch/mips/tx4938/common/setup.c
++++ b/arch/mips/tx4938/common/setup.c
+@@ -41,29 +41,10 @@ void __init tx4938_setup(void);
+ void __init tx4938_time_init(void);
+ void dump_cp0(char *key);
+
+-void (*__wbflush) (void);
+-
+-static void
+-tx4938_write_buffer_flush(void)
+-{
+- mmiowb();
+-
+- __asm__ __volatile__(
+- ".set push\n\t"
+- ".set noreorder\n\t"
+- "lw $0,%0\n\t"
+- "nop\n\t"
+- ".set pop"
+- : /* no output */
+- : "m" (*(int *)KSEG1)
+- : "memory");
+-}
+-
+ void __init
+ plat_mem_setup(void)
+ {
+ board_time_init = tx4938_time_init;
+- __wbflush = tx4938_write_buffer_flush;
+ toshiba_rbtx4938_setup();
+ }
+
+diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+index 83f2750..102e473 100644
+--- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c
++++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+@@ -81,9 +81,9 @@ IRQ Device
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/processor.h>
+-#include <asm/ptrace.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
++#include <asm/wbflush.h>
+ #include <linux/bootmem.h>
+ #include <asm/tx4938/rbtx4938.h>
+
+diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
+index fae3136..08b20cd 100644
+--- a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
++++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
+@@ -35,14 +35,19 @@ void __init txx9_spi_init(unsigned long
+ }
+
+ static DECLARE_WAIT_QUEUE_HEAD(txx9_spi_wait);
+-static void txx9_spi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++
++static irqreturn_t txx9_spi_interrupt(int irq, void *dev_id)
+ {
+ /* disable rx intr */
+ tx4938_spiptr->cr0 &= ~TXx9_SPCR0_RBSIE;
+ wake_up(&txx9_spi_wait);
++
++ return IRQ_HANDLED;
+ }
++
+ static struct irqaction txx9_spi_action = {
+- txx9_spi_interrupt, 0, 0, "spi", NULL, NULL,
++ .handler = txx9_spi_interrupt,
++ .name = "spi",
+ };
+
+ void __init txx9_spi_irqinit(int irc_irq)
+diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c
+index 7a5c31d..c215c0d 100644
+--- a/arch/mips/vr41xx/common/icu.c
++++ b/arch/mips/vr41xx/common/icu.c
+@@ -635,7 +635,7 @@ int vr41xx_set_intassign(unsigned int ir
+
+ EXPORT_SYMBOL(vr41xx_set_intassign);
+
+-static int icu_get_irq(unsigned int irq, struct pt_regs *regs)
++static int icu_get_irq(unsigned int irq)
+ {
+ uint16_t pend1, pend2;
+ uint16_t mask1, mask2;
+diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
+index 4733c53..397ba94 100644
+--- a/arch/mips/vr41xx/common/irq.c
++++ b/arch/mips/vr41xx/common/irq.c
+@@ -25,7 +25,7 @@
+ #include <asm/vr41xx/irq.h>
+
+ typedef struct irq_cascade {
+- int (*get_irq)(unsigned int, struct pt_regs *);
++ int (*get_irq)(unsigned int);
+ } irq_cascade_t;
+
+ static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
+@@ -36,7 +36,7 @@ static struct irqaction cascade_irqactio
+ .name = "cascade",
+ };
+
+-int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *))
++int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int))
+ {
+ int retval = 0;
+
+@@ -59,7 +59,7 @@ int cascade_irq(unsigned int irq, int (*
+
+ EXPORT_SYMBOL_GPL(cascade_irq);
+
+-static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
++static void irq_dispatch(unsigned int irq)
+ {
+ irq_cascade_t *cascade;
+ struct irq_desc *desc;
+@@ -74,39 +74,39 @@ static void irq_dispatch(unsigned int ir
+ unsigned int source_irq = irq;
+ desc = irq_desc + source_irq;
+ desc->chip->ack(source_irq);
+- irq = cascade->get_irq(irq, regs);
++ irq = cascade->get_irq(irq);
+ if (irq < 0)
+ atomic_inc(&irq_err_count);
+ else
+- irq_dispatch(irq, regs);
++ irq_dispatch(irq);
+ desc->chip->end(source_irq);
+ } else
+- do_IRQ(irq, regs);
++ do_IRQ(irq);
+ }
+
+-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++asmlinkage void plat_irq_dispatch(void)
+ {
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+ if (pending & CAUSEF_IP7)
+- do_IRQ(7, regs);
++ do_IRQ(7);
+ else if (pending & 0x7800) {
+ if (pending & CAUSEF_IP3)
+- irq_dispatch(3, regs);
++ irq_dispatch(3);
+ else if (pending & CAUSEF_IP4)
+- irq_dispatch(4, regs);
++ irq_dispatch(4);
+ else if (pending & CAUSEF_IP5)
+- irq_dispatch(5, regs);
++ irq_dispatch(5);
+ else if (pending & CAUSEF_IP6)
+- irq_dispatch(6, regs);
++ irq_dispatch(6);
+ } else if (pending & CAUSEF_IP2)
+- irq_dispatch(2, regs);
++ irq_dispatch(2);
+ else if (pending & CAUSEF_IP0)
+- do_IRQ(0, regs);
++ do_IRQ(0);
+ else if (pending & CAUSEF_IP1)
+- do_IRQ(1, regs);
++ do_IRQ(1);
+ else
+- spurious_interrupt(regs);
++ spurious_interrupt();
+ }
+
+ void __init arch_init_irq(void)
+diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
+index 6dd0ea8..d210123 100644
+--- a/arch/parisc/Kconfig
++++ b/arch/parisc/Kconfig
+@@ -127,7 +127,7 @@ config PA11
+
+ config PREFETCH
+ def_bool y
+- depends on PA8X00
++ depends on PA8X00 || PA7200
+
+ config 64BIT
+ bool "64-bit kernel"
+diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
+index d7c80ed..4204cd1 100644
+--- a/arch/parisc/hpux/fs.c
++++ b/arch/parisc/hpux/fs.c
+@@ -73,26 +73,30 @@ struct getdents_callback {
+ #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
+- ino_t ino, unsigned d_type)
++ u64 ino, unsigned d_type)
+ {
+ struct hpux_dirent * dirent;
+ struct getdents_callback * buf = (struct getdents_callback *) __buf;
++ ino_t d_ino;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->current_dir;
+ buf->previous = dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(reclen, &dirent->d_reclen);
+ put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+- ((char *) dirent) += reclen;
++ dirent = (void __user *)dirent + reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c
+index cb69727..2e2dc4f 100644
+--- a/arch/parisc/hpux/sys_hpux.c
++++ b/arch/parisc/hpux/sys_hpux.c
+@@ -266,16 +266,21 @@ static int hpux_uname(struct hpux_utsnam
+
+ down_read(&uts_sem);
+
+- error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1);
+- error |= __put_user(0,name->sysname+HPUX_UTSLEN-1);
+- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1);
+- error |= __put_user(0,name->nodename+HPUX_UTSLEN-1);
+- error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1);
+- error |= __put_user(0,name->release+HPUX_UTSLEN-1);
+- error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1);
+- error |= __put_user(0,name->version+HPUX_UTSLEN-1);
+- error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1);
+- error |= __put_user(0,name->machine+HPUX_UTSLEN-1);
++ error = __copy_to_user(&name->sysname, &utsname()->sysname,
++ HPUX_UTSLEN - 1);
++ error |= __put_user(0, name->sysname + HPUX_UTSLEN - 1);
++ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
++ HPUX_UTSLEN - 1);
++ error |= __put_user(0, name->nodename + HPUX_UTSLEN - 1);
++ error |= __copy_to_user(&name->release, &utsname()->release,
++ HPUX_UTSLEN - 1);
++ error |= __put_user(0, name->release + HPUX_UTSLEN - 1);
++ error |= __copy_to_user(&name->version, &utsname()->version,
++ HPUX_UTSLEN - 1);
++ error |= __put_user(0, name->version + HPUX_UTSLEN - 1);
++ error |= __copy_to_user(&name->machine, &utsname()->machine,
++ HPUX_UTSLEN - 1);
++ error |= __put_user(0, name->machine + HPUX_UTSLEN - 1);
+
+ up_read(&uts_sem);
+
+@@ -373,8 +378,8 @@ int hpux_utssys(char *ubuf, int n, int t
+ /* TODO: print a warning about using this? */
+ down_write(&uts_sem);
+ error = -EFAULT;
+- if (!copy_from_user(system_utsname.sysname, ubuf, len)) {
+- system_utsname.sysname[len] = 0;
++ if (!copy_from_user(utsname()->sysname, ubuf, len)) {
++ utsname()->sysname[len] = 0;
+ error = 0;
+ }
+ up_write(&uts_sem);
+@@ -400,8 +405,8 @@ int hpux_utssys(char *ubuf, int n, int t
+ /* TODO: print a warning about this? */
+ down_write(&uts_sem);
+ error = -EFAULT;
+- if (!copy_from_user(system_utsname.release, ubuf, len)) {
+- system_utsname.release[len] = 0;
++ if (!copy_from_user(utsname()->release, ubuf, len)) {
++ utsname()->release[len] = 0;
+ error = 0;
+ }
+ up_write(&uts_sem);
+@@ -422,13 +427,13 @@ int hpux_getdomainname(char *name, int l
+
+ down_read(&uts_sem);
+
+- nlen = strlen(system_utsname.domainname) + 1;
++ nlen = strlen(utsname()->domainname) + 1;
+
+ if (nlen < len)
+ len = nlen;
+ if(len > __NEW_UTS_LEN)
+ goto done;
+- if(copy_to_user(name, system_utsname.domainname, len))
++ if(copy_to_user(name, utsname()->domainname, len))
+ goto done;
+ err = 0;
+ done:
+diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
+index d1833f1..1e64e7b 100644
+--- a/arch/parisc/kernel/binfmt_elf32.c
++++ b/arch/parisc/kernel/binfmt_elf32.c
+@@ -87,7 +87,7 @@ struct elf_prpsinfo32
+ */
+
+ #define SET_PERSONALITY(ex, ibcs2) \
+- current->personality = PER_LINUX32; \
++ set_thread_flag(TIF_32BIT); \
+ current->thread.map_base = DEFAULT_MAP_BASE32; \
+ current->thread.task_size = DEFAULT_TASK_SIZE32 \
+
+@@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_
+ }
+
+ #include "../../../fs/binfmt_elf.c"
+-
+-/* Set up a separate execution domain for ELF32 binaries running
+- * on an ELF64 kernel */
+-
+-static struct exec_domain parisc32_exec_domain = {
+- .name = "Linux/ELF32",
+- .pers_low = PER_LINUX32,
+- .pers_high = PER_LINUX32,
+-};
+-
+-static int __init parisc32_exec_init(void)
+-{
+- /* steal the identity signal mappings from the default domain */
+- parisc32_exec_domain.signal_map = default_exec_domain.signal_map;
+- parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
+-
+- register_exec_domain(&parisc32_exec_domain);
+-
+- return 0;
+-}
+-
+-__initcall(parisc32_exec_init);
+diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
+index bc7c4a4..0be51e9 100644
+--- a/arch/parisc/kernel/cache.c
++++ b/arch/parisc/kernel/cache.c
+@@ -35,15 +35,12 @@ int icache_stride __read_mostly;
+ EXPORT_SYMBOL(dcache_stride);
+
+
+-#if defined(CONFIG_SMP)
+ /* On some machines (e.g. ones with the Merced bus), there can be
+ * only a single PxTLB broadcast at a time; this must be guaranteed
+ * by software. We put a spinlock around all TLB flushes to
+ * ensure this.
+ */
+ DEFINE_SPINLOCK(pa_tlb_lock);
+-EXPORT_SYMBOL(pa_tlb_lock);
+-#endif
+
+ struct pdc_cache_info cache_info __read_mostly;
+ #ifndef CONFIG_PA20
+@@ -91,7 +88,8 @@ update_mmu_cache(struct vm_area_struct *
+
+ flush_kernel_dcache_page(page);
+ clear_bit(PG_dcache_dirty, &page->flags);
+- }
++ } else if (parisc_requires_coherency())
++ flush_kernel_dcache_page(page);
+ }
+
+ void
+@@ -370,3 +368,45 @@ void parisc_setup_cache_timing(void)
+
+ printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
+ }
++
++extern void purge_kernel_dcache_page(unsigned long);
++extern void clear_user_page_asm(void *page, unsigned long vaddr);
++
++void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
++{
++ purge_kernel_dcache_page((unsigned long)page);
++ purge_tlb_start();
++ pdtlb_kernel(page);
++ purge_tlb_end();
++ clear_user_page_asm(page, vaddr);
++}
++EXPORT_SYMBOL(clear_user_page);
++
++void flush_kernel_dcache_page_addr(void *addr)
++{
++ flush_kernel_dcache_page_asm(addr);
++ purge_tlb_start();
++ pdtlb_kernel(addr);
++ purge_tlb_end();
++}
++EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
++
++void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
++ struct page *pg)
++{
++ /* no coherency needed (all in kmap/kunmap) */
++ copy_user_page_asm(vto, vfrom);
++ if (!parisc_requires_coherency())
++ flush_kernel_dcache_page_asm(vto);
++}
++EXPORT_SYMBOL(copy_user_page);
++
++#ifdef CONFIG_PA8X00
++
++void kunmap_parisc(void *addr)
++{
++ if (parisc_requires_coherency())
++ flush_kernel_dcache_page_addr(addr);
++}
++EXPORT_SYMBOL(kunmap_parisc);
++#endif
+diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
+index 3d569a4..d6c486e 100644
+--- a/arch/parisc/kernel/drivers.c
++++ b/arch/parisc/kernel/drivers.c
+@@ -424,7 +424,10 @@ struct parisc_device * create_tree_node(
+ /* make the generic dma mask a pointer to the parisc one */
+ dev->dev.dma_mask = &dev->dma_mask;
+ dev->dev.coherent_dma_mask = dev->dma_mask;
+- device_register(&dev->dev);
++ if (device_register(&dev->dev)) {
++ kfree(dev);
++ return NULL;
++ }
+
+ return dev;
+ }
+@@ -850,8 +853,10 @@ static void print_parisc_device(struct p
+ */
+ void init_parisc_bus(void)
+ {
+- bus_register(&parisc_bus_type);
+- device_register(&root);
++ if (bus_register(&parisc_bus_type))
++ panic("Could not register PA-RISC bus type\n");
++ if (device_register(&root))
++ panic("Could not register PA-RISC root device\n");
+ get_device(&root);
+ }
+
+diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
+index 95c1b8e..340b5e8 100644
+--- a/arch/parisc/kernel/entry.S
++++ b/arch/parisc/kernel/entry.S
+@@ -30,6 +30,7 @@
+
+
+ #include <asm/psw.h>
++#include <asm/cache.h> /* for L1_CACHE_SHIFT */
+ #include <asm/assembly.h> /* for LDREG/STREG defines */
+ #include <asm/pgtable.h>
+ #include <asm/signal.h>
+@@ -478,11 +479,7 @@
+ bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
+ DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
+ copy \pmd,%r9
+-#ifdef CONFIG_64BIT
+- shld %r9,PxD_VALUE_SHIFT,\pmd
+-#else
+- shlw %r9,PxD_VALUE_SHIFT,\pmd
+-#endif
++ SHLREG %r9,PxD_VALUE_SHIFT,\pmd
+ EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
+ DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
+ shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
+@@ -941,8 +938,8 @@ syscall_exit_rfi:
+ * to "proper" values now (otherwise we'll wind up restoring
+ * whatever was last stored in the task structure, which might
+ * be inconsistent if an interrupt occured while on the gateway
+- * page) Note that we may be "trashing" values the user put in
+- * them, but we don't support the the user changing them.
++ * page). Note that we may be "trashing" values the user put in
++ * them, but we don't support the user changing them.
+ */
+
+ STREG %r0,PT_SR2(%r16)
+@@ -970,11 +967,7 @@ intr_return:
+ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
+ ** irq_stat[] is defined using ____cacheline_aligned.
+ */
+-#ifdef CONFIG_64BIT
+- shld %r1, 6, %r20
+-#else
+- shlw %r1, 5, %r20
+-#endif
++ SHLREG %r1,L1_CACHE_SHIFT,%r20
+ add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
+ #endif /* CONFIG_SMP */
+
+@@ -1076,7 +1069,7 @@ intr_do_preempt:
+ BL preempt_schedule_irq, %r2
+ nop
+
+- b intr_restore /* ssm PSW_SM_I done by intr_restore */
++ b,n intr_restore /* ssm PSW_SM_I done by intr_restore */
+ #endif /* CONFIG_PREEMPT */
+
+ .import do_signal,code
+@@ -2115,11 +2108,7 @@ syscall_check_bh:
+ ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
+
+ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
+-#ifdef CONFIG_64BIT
+- shld %r26, 6, %r20
+-#else
+- shlw %r26, 5, %r20
+-#endif
++ SHLREG %r26,L1_CACHE_SHIFT,%r20
+ add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
+ #endif /* CONFIG_SMP */
+
+diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
+index 4398d2a..9158b70 100644
+--- a/arch/parisc/kernel/firmware.c
++++ b/arch/parisc/kernel/firmware.c
+@@ -160,13 +160,14 @@ void __init set_firmware_width(void)
+ {
+ #ifdef __LP64__
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ if(pdc_result[0] != NARROW_FIRMWARE)
+ parisc_narrow_firmware = 0;
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+ #endif
+ }
+
+@@ -196,10 +197,11 @@ void pdc_emergency_unlock(void)
+ int pdc_add_valid(unsigned long address)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -216,15 +218,16 @@ EXPORT_SYMBOL(pdc_add_valid);
+ int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ memcpy(&pdc_result, chassis_info, sizeof(*chassis_info));
+ memcpy(&pdc_result2, led_info, len);
+ retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO,
+ __pa(pdc_result), __pa(pdc_result2), len);
+ memcpy(chassis_info, pdc_result, sizeof(*chassis_info));
+ memcpy(led_info, pdc_result2, len);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -239,13 +242,14 @@ int __init pdc_chassis_info(struct pdc_c
+ int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
+ {
+ int retval = 0;
++ unsigned long flags;
+
+ if (!is_pdc_pat())
+ return -1;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -258,10 +262,11 @@ int pdc_pat_chassis_send_log(unsigned lo
+ int pdc_chassis_disp(unsigned long disp)
+ {
+ int retval = 0;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -273,11 +278,12 @@ int pdc_chassis_disp(unsigned long disp)
+ int pdc_chassis_warn(unsigned long *warn)
+ {
+ int retval = 0;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result));
+ *warn = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -292,15 +298,16 @@ int pdc_chassis_warn(unsigned long *warn
+ int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
+ convert_to_wide(pdc_result);
+ pdc_coproc_info->ccr_functional = pdc_result[0];
+ pdc_coproc_info->ccr_present = pdc_result[1];
+ pdc_coproc_info->revision = pdc_result[17];
+ pdc_coproc_info->model = pdc_result[18];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -320,14 +327,15 @@ int pdc_iodc_read(unsigned long *actcnt,
+ void *iodc_data, unsigned int iodc_data_size)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa,
+ index, __pa(pdc_result2), iodc_data_size);
+ convert_to_wide(pdc_result);
+ *actcnt = pdc_result[0];
+ memcpy(iodc_data, pdc_result2, iodc_data_size);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -346,14 +354,15 @@ int pdc_system_map_find_mods(struct pdc_
+ struct pdc_module_path *mod_path, long mod_index)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),
+ __pa(pdc_result2), mod_index);
+ convert_to_wide(pdc_result);
+ memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
+ memcpy(mod_path, pdc_result2, sizeof(*mod_path));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr);
+ return retval;
+@@ -372,13 +381,14 @@ int pdc_system_map_find_addrs(struct pdc
+ long mod_index, long addr_index)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result),
+ mod_index, addr_index);
+ convert_to_wide(pdc_result);
+ memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr);
+ return retval;
+@@ -393,12 +403,13 @@ int pdc_system_map_find_addrs(struct pdc
+ int pdc_model_info(struct pdc_model *model)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(model, pdc_result, sizeof(*model));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -414,8 +425,9 @@ int pdc_model_info(struct pdc_model *mod
+ int pdc_model_sysmodel(char *name)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result),
+ OS_ID_HPUX, __pa(name));
+ convert_to_wide(pdc_result);
+@@ -425,7 +437,7 @@ int pdc_model_sysmodel(char *name)
+ } else {
+ name[0] = 0;
+ }
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -443,12 +455,13 @@ int pdc_model_sysmodel(char *name)
+ int pdc_model_versions(unsigned long *versions, int id)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id);
+ convert_to_wide(pdc_result);
+ *versions = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -463,13 +476,14 @@ int pdc_model_versions(unsigned long *ve
+ int pdc_model_cpuid(unsigned long *cpu_id)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ *cpu_id = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -484,13 +498,14 @@ int pdc_model_cpuid(unsigned long *cpu_i
+ int pdc_model_capabilities(unsigned long *capabilities)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ *capabilities = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -504,12 +519,13 @@ int pdc_model_capabilities(unsigned long
+ int pdc_cache_info(struct pdc_cache_info *cache_info)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(cache_info, pdc_result, sizeof(*cache_info));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -523,13 +539,14 @@ int pdc_cache_info(struct pdc_cache_info
+ int pdc_spaceid_bits(unsigned long *space_bits)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0;
+ retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ *space_bits = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -544,11 +561,12 @@ int pdc_spaceid_bits(unsigned long *spac
+ int pdc_btlb_info(struct pdc_btlb_info *btlb)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0);
+ memcpy(btlb, pdc_result, sizeof(*btlb));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ if(retval < 0) {
+ btlb->max_size = 0;
+@@ -572,13 +590,14 @@ int pdc_mem_map_hpa(struct pdc_memory_ma
+ struct pdc_module_path *mod_path)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ memcpy(pdc_result2, mod_path, sizeof(*mod_path));
+ retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result),
+ __pa(pdc_result2));
+ memcpy(address, pdc_result, sizeof(*address));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -594,8 +613,9 @@ int pdc_mem_map_hpa(struct pdc_memory_ma
+ int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
+ __pa(pdc_result), hpa);
+ if (retval < 0) {
+@@ -604,7 +624,7 @@ int pdc_lan_station_id(char *lan_addr, u
+ } else {
+ memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE);
+ }
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -623,13 +643,14 @@ EXPORT_SYMBOL(pdc_lan_station_id);
+ int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_READ, staddr,
+ __pa(pdc_result), count);
+ convert_to_wide(pdc_result);
+ memcpy(memaddr, pdc_result, count);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -648,13 +669,14 @@ EXPORT_SYMBOL(pdc_stable_read);
+ int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ memcpy(pdc_result, memaddr, count);
+ convert_to_wide(pdc_result);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_WRITE, staddr,
+ __pa(pdc_result), count);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -672,11 +694,12 @@ EXPORT_SYMBOL(pdc_stable_write);
+ int pdc_stable_get_size(unsigned long *size)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_RETURN_SIZE, __pa(pdc_result));
+ *size = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -691,10 +714,11 @@ EXPORT_SYMBOL(pdc_stable_get_size);
+ int pdc_stable_verify_contents(void)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_VERIFY_CONTENTS);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -709,10 +733,11 @@ EXPORT_SYMBOL(pdc_stable_verify_contents
+ int pdc_stable_initialize(void)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_INITIALIZE);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -735,8 +760,9 @@ EXPORT_SYMBOL(pdc_stable_initialize);
+ int pdc_get_initiator(struct hardware_path *hwpath, struct pdc_initiator *initiator)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+
+ /* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
+ #define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
+@@ -776,7 +802,8 @@ int pdc_get_initiator(struct hardware_pa
+ }
+
+ out:
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
++
+ return (retval >= PDC_OK);
+ }
+ EXPORT_SYMBOL(pdc_get_initiator);
+@@ -794,13 +821,14 @@ EXPORT_SYMBOL(pdc_get_initiator);
+ int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE,
+ __pa(pdc_result), hpa);
+ convert_to_wide(pdc_result);
+ *num_entries = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -817,14 +845,15 @@ int pdc_pci_irt_size(unsigned long *num_
+ int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
+ {
+ int retval;
++ unsigned long flags;
+
+ BUG_ON((unsigned long)tbl & 0x7);
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = num_entries;
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
+ __pa(pdc_result), hpa, __pa(tbl));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -842,12 +871,15 @@ int pdc_pci_irt(unsigned long num_entrie
+ unsigned int pdc_pci_config_read(void *hpa, unsigned long cfg_addr)
+ {
+ int retval;
+- spin_lock_irq(&pdc_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0;
+ pdc_result[1] = 0;
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_READ_CONFIG,
+ __pa(pdc_result), hpa, cfg_addr&~3UL, 4UL);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
++
+ return retval ? ~0 : (unsigned int) pdc_result[0];
+ }
+
+@@ -863,12 +895,15 @@ unsigned int pdc_pci_config_read(void *h
+ void pdc_pci_config_write(void *hpa, unsigned long cfg_addr, unsigned int val)
+ {
+ int retval;
+- spin_lock_irq(&pdc_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0;
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_WRITE_CONFIG,
+ __pa(pdc_result), hpa,
+ cfg_addr&~3UL, 4UL, (unsigned long) val);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
++
+ return retval;
+ }
+ #endif /* UNTESTED CODE */
+@@ -882,12 +917,13 @@ void pdc_pci_config_write(void *hpa, uns
+ int pdc_tod_read(struct pdc_tod *tod)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(tod, pdc_result, sizeof(*tod));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -903,10 +939,11 @@ EXPORT_SYMBOL(pdc_tod_read);
+ int pdc_tod_set(unsigned long sec, unsigned long usec)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -917,13 +954,14 @@ int pdc_mem_mem_table(struct pdc_memory_
+ struct pdc_memory_table *tbl, unsigned long entries)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries);
+ convert_to_wide(pdc_result);
+ memcpy(r_addr, pdc_result, sizeof(*r_addr));
+ memcpy(tbl, pdc_result2, entries * sizeof(*tbl));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -936,11 +974,12 @@ int pdc_mem_mem_table(struct pdc_memory_
+ int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET,
+ PDC_FIRM_TEST_MAGIC, ftc_bitmap);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -953,10 +992,11 @@ int pdc_do_firm_test_reset(unsigned long
+ int pdc_do_reset(void)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -970,16 +1010,17 @@ int pdc_do_reset(void)
+ int __init pdc_soft_power_info(unsigned long *power_reg)
+ {
+ int retval;
++ unsigned long flags;
+
+ *power_reg = (unsigned long) (-1);
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0);
+ if (retval == PDC_OK) {
+ convert_to_wide(pdc_result);
+ *power_reg = f_extend(pdc_result[0]);
+ }
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -998,9 +1039,12 @@ int __init pdc_soft_power_info(unsigned
+ int pdc_soft_power_button(int sw_control)
+ {
+ int retval;
+- spin_lock_irq(&pdc_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
++
+ return retval;
+ }
+
+@@ -1011,9 +1055,11 @@ int pdc_soft_power_button(int sw_control
+ */
+ void pdc_io_reset(void)
+ {
+- spin_lock_irq(&pdc_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&pdc_lock, flags);
+ mem_pdc_call(PDC_IO, PDC_IO_RESET, 0);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+ }
+
+ /*
+@@ -1027,9 +1073,11 @@ void pdc_io_reset(void)
+ */
+ void pdc_io_reset_devices(void)
+ {
+- spin_lock_irq(&pdc_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&pdc_lock, flags);
+ mem_pdc_call(PDC_IO, PDC_IO_RESET_DEVICES, 0);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+ }
+
+
+@@ -1049,7 +1097,7 @@ void pdc_iodc_putc(unsigned char c)
+ static int __attribute__((aligned(8))) iodc_retbuf[32];
+ static char __attribute__((aligned(64))) iodc_dbuf[4096];
+ unsigned int n;
+- unsigned int flags;
++ unsigned long flags;
+
+ switch (c) {
+ case '\n':
+@@ -1088,7 +1136,8 @@ void pdc_iodc_putc(unsigned char c)
+ */
+ void pdc_iodc_outc(unsigned char c)
+ {
+- unsigned int n, flags;
++ unsigned int n;
++ unsigned long flags;
+
+ /* fill buffer with one caracter and print it */
+ static int __attribute__((aligned(8))) iodc_retbuf[32];
+@@ -1113,7 +1162,7 @@ void pdc_iodc_outc(unsigned char c)
+ */
+ int pdc_iodc_getc(void)
+ {
+- unsigned int flags;
++ unsigned long flags;
+ static int __attribute__((aligned(8))) iodc_retbuf[32];
+ static char __attribute__((aligned(64))) iodc_dbuf[4096];
+ int ch;
+@@ -1145,10 +1194,11 @@ int pdc_sti_call(unsigned long func, uns
+ unsigned long glob_cfg)
+ {
+ int retval;
++ unsigned long irqflags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, irqflags);
+ retval = real32_call(func, flags, inptr, outputr, glob_cfg);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, irqflags);
+
+ return retval;
+ }
+@@ -1165,11 +1215,12 @@ EXPORT_SYMBOL(pdc_sti_call);
+ int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result));
+ memcpy(cell_info, pdc_result, sizeof(*cell_info));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1189,16 +1240,17 @@ int pdc_pat_cell_module(unsigned long *a
+ unsigned long view_type, void *mem_addr)
+ {
+ int retval;
++ unsigned long flags;
+ static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8)));
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result),
+ ploc, mod, view_type, __pa(&result));
+ if(!retval) {
+ *actcnt = pdc_result[0];
+ memcpy(mem_addr, &result, *actcnt);
+ }
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1213,12 +1265,13 @@ int pdc_pat_cell_module(unsigned long *a
+ int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
+ __pa(&pdc_result), hpa);
+ memcpy(cpu_info, pdc_result, sizeof(*cpu_info));
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1234,12 +1287,13 @@ int pdc_pat_cpu_get_number(struct pdc_pa
+ int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE,
+ __pa(pdc_result), cell_num);
+ *num_entries = pdc_result[0];
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1254,11 +1308,12 @@ int pdc_pat_get_irt_size(unsigned long *
+ int pdc_pat_get_irt(void *r_addr, unsigned long cell_num)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE,
+ __pa(r_addr), cell_num);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1275,13 +1330,14 @@ int pdc_pat_pd_get_addr_map(unsigned lon
+ unsigned long count, unsigned long offset)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result),
+ __pa(pdc_result2), count, offset);
+ *actual_len = pdc_result[0];
+ memcpy(mem_addr, pdc_result2, *actual_len);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1296,7 +1352,9 @@ int pdc_pat_pd_get_addr_map(unsigned lon
+ int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr)
+ {
+ int retval;
+- spin_lock_irq(&pdc_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_READ,
+ __pa(pdc_result), pci_addr, pci_size);
+ switch(pci_size) {
+@@ -1304,7 +1362,7 @@ int pdc_pat_io_pci_cfg_read(unsigned lon
+ case 2: *(u16 *)mem_addr = (u16) pdc_result[0];
+ case 4: *(u32 *)mem_addr = (u32) pdc_result[0];
+ }
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+@@ -1320,11 +1378,12 @@ int pdc_pat_io_pci_cfg_read(unsigned lon
+ int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val)
+ {
+ int retval;
++ unsigned long flags;
+
+- spin_lock_irq(&pdc_lock);
++ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_WRITE,
+ pci_addr, pci_size, val);
+- spin_unlock_irq(&pdc_lock);
++ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+ }
+diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
+index 3058bff..18ba4cb 100644
+--- a/arch/parisc/kernel/hardware.c
++++ b/arch/parisc/kernel/hardware.c
+@@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_li
+ {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
+ {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
+ {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
++ {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"},
+ {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
+ {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
+ {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
+@@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_li
+ {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"},
+ {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"},
+ {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"},
++ {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"},
+ {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"},
+ {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"},
++ {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"},
+ {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"},
+ {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"},
+ {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"},
+diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
+index 3e79e62..eaad232 100644
+--- a/arch/parisc/kernel/head.S
++++ b/arch/parisc/kernel/head.S
+@@ -12,8 +12,6 @@
+ * Initial Version 04-23-1999 by Helge Deller <deller at gmx.de>
+ */
+
+-#include <linux/config.h> /* for CONFIG_SMP */
+-
+ #include <asm/asm-offsets.h>
+ #include <asm/psw.h>
+ #include <asm/pdc.h>
+diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
+index 5b8803c..b39c5b9 100644
+--- a/arch/parisc/kernel/irq.c
++++ b/arch/parisc/kernel/irq.c
+@@ -35,8 +35,8 @@
+
+ #undef PARISC_IRQ_CR16_COUNTS
+
+-extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
+-extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
++extern irqreturn_t timer_interrupt(int, void *);
++extern irqreturn_t ipi_interrupt(int, void *);
+
+ #define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq))
+
+@@ -45,6 +45,17 @@ extern irqreturn_t ipi_interrupt(int, vo
+ */
+ static volatile unsigned long cpu_eiem = 0;
+
++/*
++** ack bitmap ... habitually set to 1, but reset to zero
++** between ->ack() and ->end() of the interrupt to prevent
++** re-interruption of a processing interrupt.
++*/
++static volatile unsigned long global_ack_eiem = ~0UL;
++/*
++** Local bitmap, same as above but for per-cpu interrupts
++*/
++static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
++
+ static void cpu_disable_irq(unsigned int irq)
+ {
+ unsigned long eirr_bit = EIEM_MASK(irq);
+@@ -62,13 +73,6 @@ static void cpu_enable_irq(unsigned int
+
+ cpu_eiem |= eirr_bit;
+
+- /* FIXME: while our interrupts aren't nested, we cannot reset
+- * the eiem mask if we're already in an interrupt. Once we
+- * implement nested interrupts, this can go away
+- */
+- if (!in_interrupt())
+- set_eiem(cpu_eiem);
+-
+ /* This is just a simple NOP IPI. But what it does is cause
+ * all the other CPUs to do a set_eiem(cpu_eiem) at the end
+ * of the interrupt handler */
+@@ -84,13 +88,45 @@ static unsigned int cpu_startup_irq(unsi
+ void no_ack_irq(unsigned int irq) { }
+ void no_end_irq(unsigned int irq) { }
+
++void cpu_ack_irq(unsigned int irq)
++{
++ unsigned long mask = EIEM_MASK(irq);
++ int cpu = smp_processor_id();
++
++ /* Clear in EIEM so we can no longer process */
++ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
++ per_cpu(local_ack_eiem, cpu) &= ~mask;
++ else
++ global_ack_eiem &= ~mask;
++
++ /* disable the interrupt */
++ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
++ /* and now ack it */
++ mtctl(mask, 23);
++}
++
++void cpu_end_irq(unsigned int irq)
++{
++ unsigned long mask = EIEM_MASK(irq);
++ int cpu = smp_processor_id();
++
++ /* set it in the eiems---it's no longer in process */
++ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
++ per_cpu(local_ack_eiem, cpu) |= mask;
++ else
++ global_ack_eiem |= mask;
++
++ /* enable the interrupt */
++ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
++}
++
+ #ifdef CONFIG_SMP
+ int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
+ {
+ int cpu_dest;
+
+ /* timer and ipi have to always be received on all CPUs */
+- if (irq == TIMER_IRQ || irq == IPI_IRQ) {
++ if (CHECK_IRQ_PER_CPU(irq)) {
+ /* Bad linux design decision. The mask has already
+ * been set; we must reset it */
+ irq_desc[irq].affinity = CPU_MASK_ALL;
+@@ -119,8 +155,8 @@ static struct hw_interrupt_type cpu_inte
+ .shutdown = cpu_disable_irq,
+ .enable = cpu_enable_irq,
+ .disable = cpu_disable_irq,
+- .ack = no_ack_irq,
+- .end = no_end_irq,
++ .ack = cpu_ack_irq,
++ .end = cpu_end_irq,
+ #ifdef CONFIG_SMP
+ .set_affinity = cpu_set_affinity_irq,
+ #endif
+@@ -209,7 +245,7 @@ int show_interrupts(struct seq_file *p,
+ ** Then use that to get the Transaction address and data.
+ */
+
+-int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
++int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
+ {
+ if (irq_desc[irq].action)
+ return -EBUSY;
+@@ -298,82 +334,72 @@ unsigned int txn_alloc_data(unsigned int
+ return virt_irq - CPU_IRQ_BASE;
+ }
+
++static inline int eirr_to_irq(unsigned long eirr)
++{
++#ifdef CONFIG_64BIT
++ int bit = fls64(eirr);
++#else
++ int bit = fls(eirr);
++#endif
++ return (BITS_PER_LONG - bit) + TIMER_IRQ;
++}
++
+ /* ONLY called from entry.S:intr_extint() */
+ void do_cpu_irq_mask(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ unsigned long eirr_val;
+-
+- irq_enter();
+-
+- /*
+- * Don't allow TIMER or IPI nested interrupts.
+- * Allowing any single interrupt to nest can lead to that CPU
+- * handling interrupts with all enabled interrupts unmasked.
+- */
+- set_eiem(0UL);
+-
+- /* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
+- * 2) We loop here on EIRR contents in order to avoid
+- * nested interrupts or having to take another interrupt
+- * when we could have just handled it right away.
+- */
+- for (;;) {
+- unsigned long bit = (1UL << (BITS_PER_LONG - 1));
+- unsigned int irq;
+- eirr_val = mfctl(23) & cpu_eiem;
+- if (!eirr_val)
+- break;
+-
+- mtctl(eirr_val, 23); /* reset bits we are going to process */
+-
+- /* Work our way from MSb to LSb...same order we alloc EIRs */
+- for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
++ int irq, cpu = smp_processor_id();
+ #ifdef CONFIG_SMP
+- cpumask_t dest = irq_desc[irq].affinity;
++ cpumask_t dest;
+ #endif
+- if (!(bit & eirr_val))
+- continue;
+
+- /* clear bit in mask - can exit loop sooner */
+- eirr_val &= ~bit;
++ old_regs = set_irq_regs(regs);
++ local_irq_disable();
++ irq_enter();
+
+-#ifdef CONFIG_SMP
+- /* FIXME: because generic set affinity mucks
+- * with the affinity before sending it to us
+- * we can get the situation where the affinity is
+- * wrong for our CPU type interrupts */
+- if (irq != TIMER_IRQ && irq != IPI_IRQ &&
+- !cpu_isset(smp_processor_id(), dest)) {
+- int cpu = first_cpu(dest);
+-
+- printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
+- irq, smp_processor_id(), cpu);
+- gsc_writel(irq + CPU_IRQ_BASE,
+- cpu_data[cpu].hpa);
+- continue;
+- }
+-#endif
++ eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem &
++ per_cpu(local_ack_eiem, cpu);
++ if (!eirr_val)
++ goto set_out;
++ irq = eirr_to_irq(eirr_val);
+
+- __do_IRQ(irq, regs);
+- }
++#ifdef CONFIG_SMP
++ dest = irq_desc[irq].affinity;
++ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
++ !cpu_isset(smp_processor_id(), dest)) {
++ int cpu = first_cpu(dest);
++
++ printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
++ irq, smp_processor_id(), cpu);
++ gsc_writel(irq + CPU_IRQ_BASE,
++ cpu_data[cpu].hpa);
++ goto set_out;
+ }
++#endif
++ __do_IRQ(irq);
+
+- set_eiem(cpu_eiem); /* restore original mask */
++ out:
+ irq_exit();
+-}
++ set_irq_regs(old_regs);
++ return;
+
++ set_out:
++ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
++ goto out;
++}
+
+ static struct irqaction timer_action = {
+ .handler = timer_interrupt,
+ .name = "timer",
+- .flags = IRQF_DISABLED,
++ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
+ };
+
+ #ifdef CONFIG_SMP
+ static struct irqaction ipi_action = {
+ .handler = ipi_interrupt,
+ .name = "IPI",
+- .flags = IRQF_DISABLED,
++ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ };
+ #endif
+
+diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
+index aee3118..f50b982 100644
+--- a/arch/parisc/kernel/module.c
++++ b/arch/parisc/kernel/module.c
+@@ -27,7 +27,7 @@
+ * - SEGREL32 handling
+ * We are not doing SEGREL32 handling correctly. According to the ABI, we
+ * should do a value offset, like this:
+- * if (is_init(me, (void *)val))
++ * if (in_init(me, (void *)val))
+ * val -= (uint32_t)me->module_init;
+ * else
+ * val -= (uint32_t)me->module_core;
+@@ -72,27 +72,27 @@
+
+ /* three functions to determine where in the module core
+ * or init pieces the location is */
+-static inline int is_init(struct module *me, void *loc)
++static inline int in_init(struct module *me, void *loc)
+ {
+ return (loc >= me->module_init &&
+ loc <= (me->module_init + me->init_size));
+ }
+
+-static inline int is_core(struct module *me, void *loc)
++static inline int in_core(struct module *me, void *loc)
+ {
+ return (loc >= me->module_core &&
+ loc <= (me->module_core + me->core_size));
+ }
+
+-static inline int is_local(struct module *me, void *loc)
++static inline int in_local(struct module *me, void *loc)
+ {
+- return is_init(me, loc) || is_core(me, loc);
++ return in_init(me, loc) || in_core(me, loc);
+ }
+
+-static inline int is_local_section(struct module *me, void *loc, void *dot)
++static inline int in_local_section(struct module *me, void *loc, void *dot)
+ {
+- return (is_init(me, loc) && is_init(me, dot)) ||
+- (is_core(me, loc) && is_core(me, dot));
++ return (in_init(me, loc) && in_init(me, dot)) ||
++ (in_core(me, loc) && in_core(me, dot));
+ }
+
+
+@@ -566,14 +566,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs
+ break;
+ case R_PARISC_PCREL17F:
+ /* 17-bit PC relative address */
+- val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
++ val = get_stub(me, val, addend, ELF_STUB_GOT, in_init(me, loc));
+ val = (val - dot - 8)/4;
+ CHECK_RELOC(val, 17)
+ *loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
+ break;
+ case R_PARISC_PCREL22F:
+ /* 22-bit PC relative address; only defined for pa20 */
+- val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
++ val = get_stub(me, val, addend, ELF_STUB_GOT, in_init(me, loc));
+ DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n",
+ strtab + sym->st_name, (unsigned long)loc, addend,
+ val)
+@@ -670,9 +670,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs
+ strtab + sym->st_name,
+ loc, val);
+ /* can we reach it locally? */
+- if(!is_local_section(me, (void *)val, (void *)dot)) {
++ if(!in_local_section(me, (void *)val, (void *)dot)) {
+
+- if (is_local(me, (void *)val))
++ if (in_local(me, (void *)val))
+ /* this is the case where the
+ * symbol is local to the
+ * module, but in a different
+@@ -680,14 +680,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs
+ * in case it's more than 22
+ * bits away */
+ val = get_stub(me, val, addend, ELF_STUB_DIRECT,
+- is_init(me, loc));
++ in_init(me, loc));
+ else if (strncmp(strtab + sym->st_name, "$$", 2)
+ == 0)
+ val = get_stub(me, val, addend, ELF_STUB_MILLI,
+- is_init(me, loc));
++ in_init(me, loc));
+ else
+ val = get_stub(me, val, addend, ELF_STUB_GOT,
+- is_init(me, loc));
++ in_init(me, loc));
+ }
+ DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n",
+ strtab + sym->st_name, loc, sym->st_value,
+@@ -720,7 +720,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs
+ break;
+ case R_PARISC_FPTR64:
+ /* 64-bit function address */
+- if(is_local(me, (void *)(val + addend))) {
++ if(in_local(me, (void *)(val + addend))) {
+ *loc64 = get_fdesc(me, val+addend);
+ DEBUGP("FDESC for %s at %p points to %lx\n",
+ strtab + sym->st_name, *loc64,
+diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
+index 6d57553..8f6a0b3 100644
+--- a/arch/parisc/kernel/parisc_ksyms.c
++++ b/arch/parisc/kernel/parisc_ksyms.c
+@@ -69,10 +69,6 @@ EXPORT_SYMBOL(memcpy_toio);
+ EXPORT_SYMBOL(memcpy_fromio);
+ EXPORT_SYMBOL(memset_io);
+
+-#include <asm/unistd.h>
+-EXPORT_SYMBOL(sys_lseek);
+-EXPORT_SYMBOL(sys_write);
+-
+ #include <asm/semaphore.h>
+ EXPORT_SYMBOL(__up);
+ EXPORT_SYMBOL(__down_interruptible);
+diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
+index d3b8fc5..199887a 100644
+--- a/arch/parisc/kernel/pci.c
++++ b/arch/parisc/kernel/pci.c
+@@ -290,7 +290,7 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
+ void pcibios_align_resource(void *data, struct resource *res,
+ resource_size_t size, resource_size_t alignment)
+ {
+- unsigned long mask, align;
++ resource_size_t mask, align;
+
+ DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
+ pci_name(((struct pci_dev *) data)),
+diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
+index 0b485ef..2f9f9df 100644
+--- a/arch/parisc/kernel/process.c
++++ b/arch/parisc/kernel/process.c
+@@ -368,7 +368,14 @@ out:
+ return error;
+ }
+
+-unsigned long
++extern int __execve(const char *filename, char *const argv[],
++ char *const envp[], struct task_struct *task);
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ return __execve(filename, argv, envp, current);
++}
++
++unsigned long
+ get_wchan(struct task_struct *p)
+ {
+ struct unwind_frame_info info;
+diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
+index 99d7fca..fb81e56 100644
+--- a/arch/parisc/kernel/processor.c
++++ b/arch/parisc/kernel/processor.c
+@@ -143,8 +143,9 @@ static int __init processor_probe(struct
+ p = &cpu_data[cpuid];
+ boot_cpu_data.cpu_count++;
+
+- /* initialize counters */
+- memset(p, 0, sizeof(struct cpuinfo_parisc));
++ /* initialize counters - CPU 0 gets it_value set in time_init() */
++ if (cpuid)
++ memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+ p->loops_per_jiffy = loops_per_jiffy;
+ p->dev = dev; /* Save IODC data in case we need it */
+diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
+index bb83880..ee6653e 100644
+--- a/arch/parisc/kernel/signal.c
++++ b/arch/parisc/kernel/signal.c
+@@ -26,7 +26,6 @@
+ #include <linux/stddef.h>
+ #include <linux/compat.h>
+ #include <linux/elf.h>
+-#include <linux/personality.h>
+ #include <asm/ucontext.h>
+ #include <asm/rt_sigframe.h>
+ #include <asm/uaccess.h>
+@@ -433,13 +432,13 @@ setup_rt_frame(int sig, struct k_sigacti
+ if (in_syscall) {
+ regs->gr[31] = haddr;
+ #ifdef __LP64__
+- if (personality(current->personality) == PER_LINUX)
++ if (!test_thread_flag(TIF_32BIT))
+ sigframe_size |= 1;
+ #endif
+ } else {
+ unsigned long psw = USER_PSW;
+ #ifdef __LP64__
+- if (personality(current->personality) == PER_LINUX)
++ if (!test_thread_flag(TIF_32BIT))
+ psw |= PSW_W;
+ #endif
+
+diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
+index 98e4095..4a23a97 100644
+--- a/arch/parisc/kernel/smp.c
++++ b/arch/parisc/kernel/smp.c
+@@ -154,7 +154,7 @@ halt_processor(void)
+
+
+ irqreturn_t
+-ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++ipi_interrupt(int irq, void *dev_id)
+ {
+ int this_cpu = smp_processor_id();
+ struct cpuinfo_parisc *p = &cpu_data[this_cpu];
+@@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, str
+ this_cpu, which);
+ return IRQ_NONE;
+ } /* Switch */
++ /* let in any pending interrupts */
++ local_irq_enable();
++ local_irq_disable();
+ } /* while (ops) */
+ }
+ return IRQ_HANDLED;
+@@ -411,27 +414,15 @@ smp_flush_tlb_all(void)
+ on_each_cpu(flush_tlb_all_local, NULL, 1, 1);
+ }
+
+-
+-void
+-smp_do_timer(struct pt_regs *regs)
+-{
+- int cpu = smp_processor_id();
+- struct cpuinfo_parisc *data = &cpu_data[cpu];
+-
+- if (!--data->prof_counter) {
+- data->prof_counter = data->prof_multiplier;
+- update_process_times(user_mode(regs));
+- }
+-}
+-
+ /*
+ * Called by secondaries to update state and initialize CPU registers.
+ */
+ static void __init
+ smp_cpu_init(int cpunum)
+ {
+- extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */
++ extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */
+ extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */
++ extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
+
+ /* Set modes and Enable floating point coprocessor */
+ (void) init_per_cpu(cpunum);
+@@ -457,6 +448,7 @@ smp_cpu_init(int cpunum)
+ enter_lazy_tlb(&init_mm, current);
+
+ init_IRQ(); /* make sure no IRQ's are enabled or pending */
++ start_cpu_itimer();
+ }
+
+
+diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
+index 8b5df98..512642d 100644
+--- a/arch/parisc/kernel/sys_parisc.c
++++ b/arch/parisc/kernel/sys_parisc.c
+@@ -31,6 +31,8 @@
+ #include <linux/shm.h>
+ #include <linux/smp_lock.h>
+ #include <linux/syscalls.h>
++#include <linux/utsname.h>
++#include <linux/personality.h>
+
+ int sys_pipe(int __user *fildes)
+ {
+@@ -248,3 +250,33 @@ asmlinkage int sys_free_hugepages(unsign
+ {
+ return -EINVAL;
+ }
++
++long parisc_personality(unsigned long personality)
++{
++ long err;
++
++ if (personality(current->personality) == PER_LINUX32
++ && personality == PER_LINUX)
++ personality = PER_LINUX32;
++
++ err = sys_personality(personality);
++ if (err == PER_LINUX32)
++ err = PER_LINUX;
++
++ return err;
++}
++
++long parisc_newuname(struct new_utsname __user *name)
++{
++ int err = sys_newuname(name);
++
++#ifdef CONFIG_COMPAT
++ if (!err && personality(current->personality) == PER_LINUX32) {
++ if (__put_user(0, name->machine + 6) ||
++ __put_user(0, name->machine + 7))
++ err = -EFAULT;
++ }
++#endif
++
++ return err;
++}
+diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
+index b748698..29be437 100644
+--- a/arch/parisc/kernel/sys_parisc32.c
++++ b/arch/parisc/kernel/sys_parisc32.c
+@@ -111,13 +111,14 @@ struct __sysctl_args32 {
+
+ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
+ {
++#ifndef CONFIG_SYSCTL_SYSCALL
++ return -ENOSYS;
++#else
+ struct __sysctl_args32 tmp;
+ int error;
+ unsigned int oldlen32;
+- size_t oldlen, *oldlenp = NULL;
++ size_t oldlen, __user *oldlenp = NULL;
+ unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7;
+- extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
+- void *newval, size_t newlen);
+
+ DBG(("sysctl32(%p)\n", args));
+
+@@ -144,8 +145,9 @@ asmlinkage long sys32_sysctl(struct __sy
+ }
+
+ lock_kernel();
+- error = do_sysctl((int *)(u64)tmp.name, tmp.nlen, (void *)(u64)tmp.oldval,
+- oldlenp, (void *)(u64)tmp.newval, tmp.newlen);
++ error = do_sysctl((int __user *)(u64)tmp.name, tmp.nlen,
++ (void __user *)(u64)tmp.oldval, oldlenp,
++ (void __user *)(u64)tmp.newval, tmp.newlen);
+ unlock_kernel();
+ if (oldlenp) {
+ if (!error) {
+@@ -157,10 +159,11 @@ asmlinkage long sys32_sysctl(struct __sy
+ error = -EFAULT;
+ }
+ }
+- if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused)))
++ if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
+ error = -EFAULT;
+ }
+ return error;
++#endif
+ }
+
+ #endif /* CONFIG_SYSCTL */
+@@ -237,14 +240,19 @@ int sys32_settimeofday(struct compat_tim
+
+ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
+ {
++ compat_ino_t ino;
+ int err;
+
+ if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
+ !new_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+
++ ino = stat->ino;
++ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
++ return -EOVERFLOW;
++
+ err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
+- err |= put_user(stat->ino, &statbuf->st_ino);
++ err |= put_user(ino, &statbuf->st_ino);
+ err |= put_user(stat->mode, &statbuf->st_mode);
+ err |= put_user(stat->nlink, &statbuf->st_nlink);
+ err |= put_user(0, &statbuf->st_reserved1);
+@@ -305,23 +313,26 @@ struct readdir32_callback {
+
+ #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
+ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
+-static int
+-filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+- unsigned int d_type)
++static int filldir32 (void *__buf, const char *name, int namlen,
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct linux32_dirent __user * dirent;
+ struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
++ u32 d_ino;
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->current_dir;
+ buf->previous = dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(reclen, &dirent->d_reclen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+@@ -365,18 +376,21 @@ out:
+ return error;
+ }
+
+-static int
+-fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
+- unsigned int d_type)
++static int fillonedir32(void * __buf, const char * name, int namlen,
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
+ struct old_linux32_dirent __user * dirent;
++ u32 d_ino;
+
+ if (buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ buf->count++;
+ dirent = buf->dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(offset, &dirent->d_offset);
+ put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
+index 9670a89..a058004 100644
+--- a/arch/parisc/kernel/syscall.S
++++ b/arch/parisc/kernel/syscall.S
+@@ -6,7 +6,6 @@
+ * thanks to Philipp Rumpf, Mike Shaver and various others
+ * sorry about the wall, puffin..
+ */
+-#include <linux/config.h> /* for CONFIG_SMP */
+
+ #include <asm/asm-offsets.h>
+ #include <asm/unistd.h>
+diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
+index e27b432..701d66a 100644
+--- a/arch/parisc/kernel/syscall_table.S
++++ b/arch/parisc/kernel/syscall_table.S
+@@ -132,7 +132,7 @@
+ ENTRY_SAME(socketpair)
+ ENTRY_SAME(setpgid)
+ ENTRY_SAME(send)
+- ENTRY_SAME(newuname)
++ ENTRY_OURS(newuname)
+ ENTRY_SAME(umask) /* 60 */
+ ENTRY_SAME(chroot)
+ ENTRY_SAME(ustat)
+@@ -221,7 +221,7 @@
+ ENTRY_SAME(fchdir)
+ ENTRY_SAME(bdflush)
+ ENTRY_SAME(sysfs) /* 135 */
+- ENTRY_SAME(personality)
++ ENTRY_OURS(personality)
+ ENTRY_SAME(ni_syscall) /* for afs_syscall */
+ ENTRY_SAME(setfsuid)
+ ENTRY_SAME(setfsgid)
+diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
+index 5facc9b..bad7d1e 100644
+--- a/arch/parisc/kernel/time.c
++++ b/arch/parisc/kernel/time.c
+@@ -32,58 +32,121 @@
+
+ #include <linux/timex.h>
+
+-/* xtime and wall_jiffies keep wall-clock time */
+-extern unsigned long wall_jiffies;
++static unsigned long clocktick __read_mostly; /* timer cycles per tick */
+
+-static long clocktick __read_mostly; /* timer cycles per tick */
+-static long halftick __read_mostly;
++/*
++ * We keep time on PA-RISC Linux by using the Interval Timer which is
++ * a pair of registers; one is read-only and one is write-only; both
++ * accessed through CR16. The read-only register is 32 or 64 bits wide,
++ * and increments by 1 every CPU clock tick. The architecture only
++ * guarantees us a rate between 0.5 and 2, but all implementations use a
++ * rate of 1. The write-only register is 32-bits wide. When the lowest
++ * 32 bits of the read-only register compare equal to the write-only
++ * register, it raises a maskable external interrupt. Each processor has
++ * an Interval Timer of its own and they are not synchronised.
++ *
++ * We want to generate an interrupt every 1/HZ seconds. So we program
++ * CR16 to interrupt every @clocktick cycles. The it_value in cpu_data
++ * is programmed with the intended time of the next tick. We can be
++ * held off for an arbitrarily long period of time by interrupts being
++ * disabled, so we may miss one or more ticks.
++ */
++irqreturn_t timer_interrupt(int irq, void *dev_id)
++{
++ unsigned long now;
++ unsigned long next_tick;
++ unsigned long cycles_elapsed, ticks_elapsed;
++ unsigned long cycles_remainder;
++ unsigned int cpu = smp_processor_id();
++ struct cpuinfo_parisc *cpuinfo = &cpu_data[cpu];
+
+-#ifdef CONFIG_SMP
+-extern void smp_do_timer(struct pt_regs *regs);
+-#endif
++ /* gcc can optimize for "read-only" case with a local clocktick */
++ unsigned long cpt = clocktick;
+
+-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- long now;
+- long next_tick;
+- int nticks;
+- int cpu = smp_processor_id();
++ profile_tick(CPU_PROFILING);
+
+- profile_tick(CPU_PROFILING, regs);
++ /* Initialize next_tick to the expected tick time. */
++ next_tick = cpuinfo->it_value;
+
++ /* Get current interval timer.
++ * CR16 reads as 64 bits in CPU wide mode.
++ * CR16 reads as 32 bits in CPU narrow mode.
++ */
+ now = mfctl(16);
+- /* initialize next_tick to time at last clocktick */
+- next_tick = cpu_data[cpu].it_value;
+
+- /* since time passes between the interrupt and the mfctl()
+- * above, it is never true that last_tick + clocktick == now. If we
+- * never miss a clocktick, we could set next_tick = last_tick + clocktick
+- * but maybe we'll miss ticks, hence the loop.
++ cycles_elapsed = now - next_tick;
++
++ if ((cycles_elapsed >> 5) < cpt) {
++ /* use "cheap" math (add/subtract) instead
++ * of the more expensive div/mul method
++ */
++ cycles_remainder = cycles_elapsed;
++ ticks_elapsed = 1;
++ while (cycles_remainder > cpt) {
++ cycles_remainder -= cpt;
++ ticks_elapsed++;
++ }
++ } else {
++ cycles_remainder = cycles_elapsed % cpt;
++ ticks_elapsed = 1 + cycles_elapsed / cpt;
++ }
++
++ /* Can we differentiate between "early CR16" (aka Scenario 1) and
++ * "long delay" (aka Scenario 3)? I don't think so.
+ *
+- * Variables are *signed*.
++ * We expected timer_interrupt to be delivered at least a few hundred
++ * cycles after the IT fires. But it's arbitrary how much time passes
++ * before we call it "late". I've picked one second.
+ */
+-
+- nticks = 0;
+- while((next_tick - now) < halftick) {
+- next_tick += clocktick;
+- nticks++;
++ if (ticks_elapsed > HZ) {
++ /* Scenario 3: very long delay? bad in any case */
++ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
++ " cycles %lX rem %lX "
++ " next/now %lX/%lX\n",
++ cpu,
++ cycles_elapsed, cycles_remainder,
++ next_tick, now );
+ }
++
++ /* convert from "division remainder" to "remainder of clock tick" */
++ cycles_remainder = cpt - cycles_remainder;
++
++ /* Determine when (in CR16 cycles) next IT interrupt will fire.
++ * We want IT to fire modulo clocktick even if we miss/skip some.
++ * But those interrupts don't in fact get delivered that regularly.
++ */
++ next_tick = now + cycles_remainder;
++
++ cpuinfo->it_value = next_tick;
++
++ /* Skip one clocktick on purpose if we are likely to miss next_tick.
++ * We want to avoid the new next_tick being less than CR16.
++ * If that happened, itimer wouldn't fire until CR16 wrapped.
++ * We'll catch the tick we missed on the tick after that.
++ */
++ if (!(cycles_remainder >> 13))
++ next_tick += cpt;
++
++ /* Program the IT when to deliver the next interrupt. */
++ /* Only bottom 32-bits of next_tick are written to cr16. */
+ mtctl(next_tick, 16);
+- cpu_data[cpu].it_value = next_tick;
+
+- while (nticks--) {
+-#ifdef CONFIG_SMP
+- smp_do_timer(regs);
+-#else
+- update_process_times(user_mode(regs));
+-#endif
+- if (cpu == 0) {
+- write_seqlock(&xtime_lock);
+- do_timer(regs);
+- write_sequnlock(&xtime_lock);
+- }
++
++ /* Done mucking with unreliable delivery of interrupts.
++ * Go do system house keeping.
++ */
++
++ if (!--cpuinfo->prof_counter) {
++ cpuinfo->prof_counter = cpuinfo->prof_multiplier;
++ update_process_times(user_mode(get_irq_regs()));
+ }
+-
++
++ if (cpu == 0) {
++ write_seqlock(&xtime_lock);
++ do_timer(ticks_elapsed);
++ write_sequnlock(&xtime_lock);
++ }
++
+ /* check soft power switch status */
+ if (cpu == 0 && !atomic_read(&power_tasklet.count))
+ tasklet_schedule(&power_tasklet);
+@@ -109,14 +172,12 @@ unsigned long profile_pc(struct pt_regs
+ EXPORT_SYMBOL(profile_pc);
+
+
+-/*** converted from ia64 ***/
+ /*
+ * Return the number of micro-seconds that elapsed since the last
+- * update to wall time (aka xtime aka wall_jiffies). The xtime_lock
++ * update to wall time (aka xtime). The xtime_lock
+ * must be at least read-locked when calling this routine.
+ */
+-static inline unsigned long
+-gettimeoffset (void)
++static inline unsigned long gettimeoffset (void)
+ {
+ #ifndef CONFIG_SMP
+ /*
+@@ -124,21 +185,44 @@ gettimeoffset (void)
+ * Once parisc-linux learns the cr16 difference between processors,
+ * this could be made to work.
+ */
+- long last_tick;
+- long elapsed_cycles;
+-
+- /* it_value is the intended time of the next tick */
+- last_tick = cpu_data[smp_processor_id()].it_value;
+-
+- /* Subtract one tick and account for possible difference between
+- * when we expected the tick and when it actually arrived.
+- * (aka wall vs real)
+- */
+- last_tick -= clocktick * (jiffies - wall_jiffies + 1);
+- elapsed_cycles = mfctl(16) - last_tick;
++ unsigned long now;
++ unsigned long prev_tick;
++ unsigned long next_tick;
++ unsigned long elapsed_cycles;
++ unsigned long usec;
++ unsigned long cpuid = smp_processor_id();
++ unsigned long cpt = clocktick;
++
++ next_tick = cpu_data[cpuid].it_value;
++ now = mfctl(16); /* Read the hardware interval timer. */
++
++ prev_tick = next_tick - cpt;
++
++ /* Assume Scenario 1: "now" is later than prev_tick. */
++ elapsed_cycles = now - prev_tick;
++
++/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
++#if HZ == 1000
++ if (elapsed_cycles > (cpt << 10) )
++#elif HZ == 250
++ if (elapsed_cycles > (cpt << 8) )
++#elif HZ == 100
++ if (elapsed_cycles > (cpt << 7) )
++#else
++#warn WTF is HZ set to anyway?
++ if (elapsed_cycles > (HZ * cpt) )
++#endif
++ {
++ /* Scenario 3: clock ticks are missing. */
++ printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
++ " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n",
++ cpuid, elapsed_cycles / cpt,
++ elapsed_cycles, prev_tick, now, next_tick, cpt);
++ }
+
+- /* the precision of this math could be improved */
+- return elapsed_cycles / (PAGE0->mem_10msec / 10000);
++ /* FIXME: Can we improve the precision? Not with PAGE0. */
++ usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec;
++ return usec;
+ #else
+ return 0;
+ #endif
+@@ -149,6 +233,7 @@ do_gettimeofday (struct timeval *tv)
+ {
+ unsigned long flags, seq, usec, sec;
+
++ /* Hold xtime_lock and adjust timeval. */
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = gettimeoffset();
+@@ -156,25 +241,13 @@ do_gettimeofday (struct timeval *tv)
+ usec += (xtime.tv_nsec / 1000);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+- if (unlikely(usec > LONG_MAX)) {
+- /* This can happen if the gettimeoffset adjustment is
+- * negative and xtime.tv_nsec is smaller than the
+- * adjustment */
+- printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
+- usec += USEC_PER_SEC;
+- --sec;
+- /* This should never happen, it means the negative
+- * time adjustment was more than a second, so there's
+- * something seriously wrong */
+- BUG_ON(usec > LONG_MAX);
+- }
+-
+-
++ /* Move adjusted usec's into sec's. */
+ while (usec >= USEC_PER_SEC) {
+ usec -= USEC_PER_SEC;
+ ++sec;
+ }
+
++ /* Return adjusted result. */
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+ }
+@@ -226,30 +299,33 @@ unsigned long long sched_clock(void)
+ }
+
+
++void __init start_cpu_itimer(void)
++{
++ unsigned int cpu = smp_processor_id();
++ unsigned long next_tick = mfctl(16) + clocktick;
++
++ mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */
++
++ cpu_data[cpu].it_value = next_tick;
++}
++
+ void __init time_init(void)
+ {
+- unsigned long next_tick;
+ static struct pdc_tod tod_data;
+
+ clocktick = (100 * PAGE0->mem_10msec) / HZ;
+- halftick = clocktick / 2;
+-
+- /* Setup clock interrupt timing */
+
+- next_tick = mfctl(16);
+- next_tick += clocktick;
+- cpu_data[smp_processor_id()].it_value = next_tick;
++ start_cpu_itimer(); /* get CPU 0 started */
+
+- /* kick off Itimer (CR16) */
+- mtctl(next_tick, 16);
++ if (pdc_tod_read(&tod_data) == 0) {
++ unsigned long flags;
+
+- if(pdc_tod_read(&tod_data) == 0) {
+- write_seqlock_irq(&xtime_lock);
++ write_seqlock_irqsave(&xtime_lock, flags);
+ xtime.tv_sec = tod_data.tod_sec;
+ xtime.tv_nsec = tod_data.tod_usec * 1000;
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+- write_sequnlock_irq(&xtime_lock);
++ write_sequnlock_irqrestore(&xtime_lock, flags);
+ } else {
+ printk(KERN_ERR "Error reading tod clock\n");
+ xtime.tv_sec = 0;
+diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
+index 77b28cb..65cd6ca 100644
+--- a/arch/parisc/kernel/traps.c
++++ b/arch/parisc/kernel/traps.c
+@@ -16,6 +16,7 @@
+ #include <linux/errno.h>
+ #include <linux/ptrace.h>
+ #include <linux/timer.h>
++#include <linux/delay.h>
+ #include <linux/mm.h>
+ #include <linux/module.h>
+ #include <linux/smp.h>
+@@ -245,6 +246,15 @@ void die_if_kernel(char *str, struct pt_
+ current->comm, current->pid, str, err);
+ show_regs(regs);
+
++ 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");
++ }
++
+ /* Wot's wrong wif bein' racy? */
+ if (current->thread.flags & PARISC_KERNEL_DEATH) {
+ printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
+diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
+index b3677fc..7b943b4 100644
+--- a/arch/parisc/kernel/vmlinux.lds.S
++++ b/arch/parisc/kernel/vmlinux.lds.S
+@@ -153,13 +153,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
+index f2b96f1..0667f2b 100644
+--- a/arch/parisc/mm/init.c
++++ b/arch/parisc/mm/init.c
+@@ -31,10 +31,7 @@
+
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+-extern char _text; /* start of kernel code, defined by linker */
+ extern int data_start;
+-extern char _end; /* end of BSS, defined by linker */
+-extern char __init_begin, __init_end;
+
+ #ifdef CONFIG_DISCONTIGMEM
+ struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
+@@ -319,8 +316,8 @@ static void __init setup_bootmem(void)
+
+ reserve_bootmem_node(NODE_DATA(0), 0UL,
+ (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
+- reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
+- (unsigned long)(&_end - &_text));
++ reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
++ (unsigned long)(_end - _text));
+ reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
+ ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
+
+@@ -355,8 +352,8 @@ static void __init setup_bootmem(void)
+ #endif
+
+ data_resource.start = virt_to_phys(&data_start);
+- data_resource.end = virt_to_phys(&_end)-1;
+- code_resource.start = virt_to_phys(&_text);
++ data_resource.end = virt_to_phys(_end) - 1;
++ code_resource.start = virt_to_phys(_text);
+ code_resource.end = virt_to_phys(&data_start)-1;
+
+ /* We don't know which region the kernel will be in, so try
+@@ -385,12 +382,12 @@ void free_initmem(void)
+ */
+ local_irq_disable();
+
+- memset(&__init_begin, 0x00,
+- (unsigned long)&__init_end - (unsigned long)&__init_begin);
++ memset(__init_begin, 0x00,
++ (unsigned long)__init_end - (unsigned long)__init_begin);
+
+ flush_data_cache();
+ asm volatile("sync" : : );
+- flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
++ flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
+ asm volatile("sync" : : );
+
+ local_irq_enable();
+@@ -398,8 +395,8 @@ void free_initmem(void)
+
+ /* align __init_begin and __init_end to page size,
+ ignoring linker script where we might have tried to save RAM */
+- init_begin = PAGE_ALIGN((unsigned long)(&__init_begin));
+- init_end = PAGE_ALIGN((unsigned long)(&__init_end));
++ init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
++ init_end = PAGE_ALIGN((unsigned long)(__init_end));
+ for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+@@ -551,7 +548,7 @@ void show_mem(void)
+
+ printk("Zone list for zone %d on node %d: ", j, i);
+ for (k = 0; zl->zones[k] != NULL; k++)
+- printk("[%d/%s] ", zl->zones[k]->zone_pgdat->node_id, zl->zones[k]->name);
++ printk("[%d/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name);
+ printk("\n");
+ }
+ }
+@@ -578,7 +575,7 @@ static void __init map_pages(unsigned lo
+ extern const unsigned long fault_vector_20;
+ extern void * const linux_gateway_page;
+
+- ro_start = __pa((unsigned long)&_text);
++ ro_start = __pa((unsigned long)_text);
+ ro_end = __pa((unsigned long)&data_start);
+ fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
+ gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
+@@ -809,7 +806,7 @@ void __init paging_init(void)
+ flush_tlb_all_local(NULL);
+
+ for (i = 0; i < npmem_ranges; i++) {
+- unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0 };
++ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+
+ /* We have an IOMMU, so all memory can go into a single
+ ZONE_DMA zone. */
+diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
+index 2738456..47a1d2a 100644
+--- a/arch/parisc/mm/ioremap.c
++++ b/arch/parisc/mm/ioremap.c
+@@ -188,7 +188,7 @@ void __iomem * __ioremap(unsigned long p
+ }
+ EXPORT_SYMBOL(__ioremap);
+
+-void iounmap(void __iomem *addr)
++void iounmap(const volatile void __iomem *addr)
+ {
+ if (addr > high_memory)
+ return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 694b0c6..2bd9b7f 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -338,10 +338,6 @@ config PPC_MULTIPLATFORM
+ RS/6000 machine, an Apple machine, or a PReP, CHRP,
+ Maple or Cell-based machine.
+
+-config PPC_ISERIES
+- bool "IBM Legacy iSeries"
+- depends on PPC64
+-
+ config EMBEDDED6xx
+ bool "Embedded 6xx/7xx/7xxx-based board"
+ depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
+@@ -355,6 +351,16 @@ config APUS
+ <http://linux-apus.sourceforge.net/>.
+ endchoice
+
++config QUICC_ENGINE
++ bool
++ depends on PPC_MPC836x || PPC_MPC832x
++ default y
++ help
++ The QUICC Engine (QE) is a new generation of communications
++ coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
++ Selecting this option means that you wish to build a kernel
++ for a machine with a QE coprocessor.
++
+ config PPC_PSERIES
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "IBM pSeries & new (POWER5-based) iSeries"
+@@ -365,6 +371,10 @@ config PPC_PSERIES
+ select PPC_UDBG_16550
+ default y
+
++config PPC_ISERIES
++ bool "IBM Legacy iSeries"
++ depends on PPC_MULTIPLATFORM && PPC64
++
+ config PPC_CHRP
+ bool "Common Hardware Reference Platform (CHRP) based machines"
+ depends on PPC_MULTIPLATFORM && PPC32
+@@ -417,6 +427,17 @@ config PPC_MAPLE
+ This option enables support for the Maple 970FX Evaluation Board.
+ For more informations, refer to <http://www.970eval.com>
+
++config PPC_PASEMI
++ depends on PPC_MULTIPLATFORM && PPC64
++ bool "PA Semi SoC-based platforms"
++ default n
++ select MPIC
++ select PPC_UDBG_16550
++ select GENERIC_TBSYNC
++ help
++ This option enables support for PA Semi's PWRficient line
++ of SoC processors, including PA6T-1682M
++
+ config PPC_CELL
+ bool
+ default n
+@@ -436,7 +457,8 @@ config PPC_IBM_CELL_BLADE
+ select UDBG_RTAS_CONSOLE
+
+ config UDBG_RTAS_CONSOLE
+- bool
++ bool "RTAS based debug console"
++ depends on PPC_RTAS
+ default n
+
+ config XICS
+@@ -582,6 +604,7 @@ endmenu
+
+ source arch/powerpc/platforms/embedded6xx/Kconfig
+ source arch/powerpc/platforms/4xx/Kconfig
++source arch/powerpc/platforms/82xx/Kconfig
+ source arch/powerpc/platforms/83xx/Kconfig
+ source arch/powerpc/platforms/85xx/Kconfig
+ source arch/powerpc/platforms/86xx/Kconfig
+@@ -719,16 +742,24 @@ config ARCH_SPARSEMEM_DEFAULT
+ def_bool y
+ depends on SMP && PPC_PSERIES
+
+-source "mm/Kconfig"
+-
+-config HAVE_ARCH_EARLY_PFN_TO_NID
++config ARCH_POPULATES_NODE_MAP
+ def_bool y
+- depends on NEED_MULTIPLE_NODES
++
++source "mm/Kconfig"
+
+ config ARCH_MEMORY_PROBE
+ def_bool y
+ depends on MEMORY_HOTPLUG
+
++# Some NUMA nodes have memory ranges that span
++# other nodes. Even though a pfn is valid and
++# between a node's start and end pfns, it may not
++# reside on that node. See memmap_init_zone()
++# for details.
++config NODES_SPAN_OTHER_NODES
++ def_bool y
++ depends on NEED_MULTIPLE_NODES
++
+ config PPC_64K_PAGES
+ bool "64k page size"
+ depends on PPC64
+@@ -991,7 +1022,7 @@ config CONSISTENT_START_BOOL
+ depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+ help
+ This option allows you to set the base virtual address
+- of the the consistent memory pool. This pool of virtual
++ of the consistent memory pool. This pool of virtual
+ memory is used to make consistent memory allocations.
+
+ config CONSISTENT_START
+@@ -1002,7 +1033,7 @@ config CONSISTENT_SIZE_BOOL
+ bool "Set custom consistent memory pool size"
+ depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+ help
+- This option allows you to set the size of the the
++ This option allows you to set the size of the
+ consistent memory pool. This pool of virtual memory
+ is used to make consistent memory allocations.
+
+@@ -1047,6 +1078,8 @@ source "fs/Kconfig"
+
+ # XXX source "arch/ppc/8260_io/Kconfig"
+
++source "arch/powerpc/sysdev/qe_lib/Kconfig"
++
+ source "arch/powerpc/platforms/iseries/Kconfig"
+
+ source "lib/Kconfig"
+@@ -1058,7 +1091,7 @@ source "arch/powerpc/oprofile/Kconfig"
+
+ config KPROBES
+ bool "Kprobes (EXPERIMENTAL)"
+- depends on PPC64 && EXPERIMENTAL && MODULES
++ depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES
+ help
+ Kprobes allows you to trap at almost any kernel address and
+ execute a callback function. register_kprobe() establishes
+diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
+index e29ef77..5ad149b 100644
+--- a/arch/powerpc/Kconfig.debug
++++ b/arch/powerpc/Kconfig.debug
+@@ -18,6 +18,20 @@ config DEBUG_STACK_USAGE
+
+ This option will slow down process creation somewhat.
+
++config HCALL_STATS
++ bool "Hypervisor call instrumentation"
++ depends on PPC_PSERIES && DEBUG_FS
++ help
++ Adds code to keep track of the number of hypervisor calls made and
++ the amount of time spent in hypervisor callsr. Wall time spent in
++ each call is always calculated, and if available CPU cycles spent
++ are also calculated. A directory named hcall_inst is added at the
++ root of the debugfs filesystem. Within the hcall_inst directory
++ are files that contain CPU specific call statistics.
++
++ This option will add a small amount of overhead to all hypervisor
++ calls.
++
+ config DEBUGGER
+ bool "Enable debugger hooks"
+ depends on DEBUG_KERNEL
+@@ -74,6 +88,8 @@ config XMON
+ very early during boot. 'xmon=on' will just enable the xmon
+ debugger hooks. 'xmon=off' will disable the debugger hooks
+ if CONFIG_XMON_DEFAULT is set.
++ xmon will print a backtrace on the very first invocation.
++ 'xmon=nobt' will disable this autobacktrace.
+
+ config XMON_DEFAULT
+ bool "Enable xmon by default"
+diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
+index 01667d1..a00fe72 100644
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -20,6 +20,7 @@ CROSS32_COMPILE ?=
+ CROSS32CC := $(CROSS32_COMPILE)gcc
+ CROSS32AS := $(CROSS32_COMPILE)as
+ CROSS32LD := $(CROSS32_COMPILE)ld
++CROSS32AR := $(CROSS32_COMPILE)ar
+ CROSS32OBJCOPY := $(CROSS32_COMPILE)objcopy
+
+ ifeq ($(HAS_BIARCH),y)
+@@ -28,10 +29,11 @@ CROSS32CC := $(CC) -m32
+ CROSS32AS := $(AS) -a32
+ CROSS32LD := $(LD) -m elf32ppc
+ CROSS32OBJCOPY := $(OBJCOPY)
++CROSS32AR := $(AR)
+ endif
+ endif
+
+-export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY
++export CROSS32CC CROSS32AS CROSS32LD CROSS32AR CROSS32OBJCOPY
+
+ KBUILD_DEFCONFIG := $(shell uname -m)_defconfig
+
+@@ -146,7 +148,7 @@ all: $(KBUILD_IMAGE)
+
+ CPPFLAGS_vmlinux.lds := -Upowerpc
+
+-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin
++BOOT_TARGETS = zImage zImage.initrd uImage
+
+ PHONY += $(BOOT_TARGETS)
+
+diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
+index d961bfe..4b2be61 100644
+--- a/arch/powerpc/boot/Makefile
++++ b/arch/powerpc/boot/Makefile
+@@ -20,28 +20,34 @@
+ # CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
+ # in the toplevel makefile.
+
++all: $(obj)/zImage
+
+ HOSTCC := gcc
+ BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
+ $(shell $(CROSS32CC) -print-file-name=include) -fPIC
+ BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
+-OBJCOPYFLAGS := contents,alloc,load,readonly,data
+-OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
+-OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
++
++ifeq ($(call cc-option-yn, -fstack-protector),y)
++BOOTCFLAGS += -fno-stack-protector
++endif
++
++BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
+
+ zlib := inffast.c inflate.c inftrees.c
+ zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
+ zliblinuxheader := zlib.h zconf.h zutil.h
+
+-$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
+-#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
++$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
++ $(addprefix $(obj)/,$(zlibheader))
++
++src-wlib := string.S stdio.c main.c div64.S $(zlib)
++src-plat := of.c
++src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
+
+-src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
+-src-boot += $(zlib)
+ src-boot := $(addprefix $(obj)/, $(src-boot))
+ obj-boot := $(addsuffix .o, $(basename $(src-boot)))
+-
+-BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
++obj-wlib := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-wlib))))
++obj-plat := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-plat))))
+
+ quiet_cmd_copy_zlib = COPY $@
+ cmd_copy_zlib = sed "s at __attribute_used__@@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
+@@ -61,8 +67,14 @@ $(addprefix $(obj)/,$(zlibheader)): $(ob
+ $(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
+ $(call cmd,copy_zliblinuxheader)
+
+-clean-files := $(zlib) $(zlibheader) $(zliblinuxheader)
++$(obj)/empty.c:
++ @touch $@
++
++$(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S
++ @cp $< $@
+
++clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
++ $(obj)/empty.c
+
+ quiet_cmd_bootcc = BOOTCC $@
+ cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
+@@ -70,146 +82,97 @@ quiet_cmd_bootcc = BOOTCC $@
+ quiet_cmd_bootas = BOOTAS $@
+ cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
+
+-quiet_cmd_bootld = BOOTLD $@
+- cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
++quiet_cmd_bootar = BOOTAR $@
++ cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $^; mv $@.$$$$ $@
+
+ $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
+ $(call if_changed_dep,bootcc)
+ $(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
+ $(call if_changed_dep,bootas)
+
+-#-----------------------------------------------------------
+-# ELF sections within the zImage bootloader/wrapper
+-#-----------------------------------------------------------
+-required := vmlinux.strip
+-initrd := initrd
++$(obj)/wrapper.a: $(obj-wlib)
++ $(call cmd,bootar)
+
+-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 := addnote addRamDisk hack-coff
+
+-hostprogs-y := addnote addRamDisk hack-coff
++extra-y := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
++ $(obj)/zImage.lds $(obj)/zImage.coff.lds
+
+-targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
+- zImage.coff zImage.initrd.coff miboot.image miboot.initrd.image \
+- $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
+- $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
+- $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
+- vmlinux.initrd dummy.o
+-extra-y := initrd.o
++wrapper :=$(srctree)/$(src)/wrapper
++wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff)
+
+-quiet_cmd_ramdisk = RAMDISK $@
+- cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@
++#############
++# Bits for building various flavours of zImage
+
+-quiet_cmd_stripvm = STRIP $@
+- cmd_stripvm = $(STRIP) -s -R .comment $< -o $@
++ifneq ($(CROSS32_COMPILE),)
++CROSSWRAP := -C "$(CROSS32_COMPILE)"
++else
++ifneq ($(CROSS_COMPILE),)
++CROSSWRAP := -C "$(CROSS_COMPILE)"
++endif
++endif
+
+-vmlinux.strip: vmlinux
+- $(call if_changed,stripvm)
+-$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz
+- $(call if_changed,ramdisk)
++quiet_cmd_wrap = WRAP $@
++ cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
++quiet_cmd_wrap_initrd = WRAP $@
++ cmd_wrap_initrd =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
++ -i $(obj)/ramdisk.image.gz vmlinux
+
+-quiet_cmd_addsection = ADDSEC $@
+- cmd_addsection = $(CROSS32OBJCOPY) $@ \
+- --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \
+- --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS)
++$(obj)/zImage.chrp: vmlinux $(wrapperbits)
++ $(call cmd,wrap,chrp)
+
+-quiet_cmd_addnote = ADDNOTE $@
+- cmd_addnote = $(obj)/addnote $@
++$(obj)/zImage.initrd.chrp: vmlinux $(wrapperbits)
++ $(call cmd,wrap_initrd,chrp)
+
+-quiet_cmd_gen-miboot = GEN $@
+- cmd_gen-miboot = $(OBJCOPY) $(OBJCOPY_MIB_ARGS) \
+- --add-section=$1=$(word 2, $^) $< $@
++$(obj)/zImage.pseries: vmlinux $(wrapperbits)
++ $(call cmd,wrap,pseries)
+
+-quiet_cmd_gencoff = COFF $@
+- cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
+- $(obj)/hack-coff $@
++$(obj)/zImage.initrd.pseries: vmlinux $(wrapperbits)
++ $(call cmd,wrap_initrd,pseries)
+
+-$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
+- $(call if_changed,gzip)
++$(obj)/zImage.pmac: vmlinux $(wrapperbits)
++ $(call cmd,wrap,pmac)
+
+-$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz
+- cp -f $(obj)/ramdisk.image.gz $@
++$(obj)/zImage.initrd.pmac: vmlinux $(wrapperbits)
++ $(call cmd,wrap_initrd,pmac)
+
+-$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz
+- @touch $@
++$(obj)/zImage.coff: vmlinux $(wrapperbits)
++ $(call cmd,wrap,pmaccoff)
+
+-$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
+- $(call if_changed_dep,bootcc)
+- $(call cmd,addsection)
++$(obj)/zImage.initrd.coff: vmlinux $(wrapperbits)
++ $(call cmd,wrap_initrd,pmaccoff)
++
++$(obj)/zImage.miboot: vmlinux $(wrapperbits)
++ $(call cmd,wrap,miboot)
++
++$(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
++ $(call cmd,wrap_initrd,miboot)
+
+-$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
+-$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
+- $(call cmd,bootld,$(obj-boot),zImage.lds)
++$(obj)/uImage: vmlinux $(wrapperbits)
++ $(call cmd,wrap,uboot)
+
+-$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: obj-boot += $(call obj-sec, $(required) $(initrd))
+-$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
+- $(call cmd,bootld,$(obj-boot),zImage.lds)
++image-$(CONFIG_PPC_PSERIES) += zImage.pseries
++image-$(CONFIG_PPC_MAPLE) += zImage.pseries
++image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
++image-$(CONFIG_PPC_CHRP) += zImage.chrp
++image-$(CONFIG_PPC_PMAC) += zImage.pmac
++image-$(CONFIG_DEFAULT_UIMAGE) += uImage
+
+ # For 32-bit powermacs, build the COFF and miboot images
+ # as well as the ELF images.
+-coffimage-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.coff
+-coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.initrd.coff
+-mibootimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.image
+-mibrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.initrd.image
+-
+-$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y) \
+- $(mibootimg-y-y)
+- @cp -f $< $@
+- $(call if_changed,addnote)
+-
+-$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote \
+- $(coffrdimg-y-y) $(mibrdimg-y-y)
+- @cp -f $< $@
+- $(call if_changed,addnote)
+-
+-$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) \
+- $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+- $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+- $(call cmd,gencoff)
+-
+-$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
+- $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+- $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+- $(call cmd,gencoff)
+-
+-$(obj)/miboot.image: $(obj)/dummy.o $(obj)/vmlinux.gz
+- $(call cmd,gen-miboot,image)
+-
+-$(obj)/miboot.initrd.image: $(obj)/miboot.image $(images)/ramdisk.image.gz
+- $(call cmd,gen-miboot,initrd)
+-
+-#-----------------------------------------------------------
+-# build u-boot images
+-#-----------------------------------------------------------
+-quiet_cmd_mygzip = GZIP $@
+-cmd_mygzip = gzip -f -9 < $< > $@.$$$$ && mv $@.$$$$ $@
+-
+-quiet_cmd_objbin = OBJCOPY $@
+- cmd_objbin = $(OBJCOPY) -O binary $< $@
+-
+-quiet_cmd_uimage = UIMAGE $@
+- cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \
+- -C gzip -a 00000000 -e 00000000 -n 'Linux-$(KERNELRELEASE)' \
+- -d $< $@
+-
+-MKIMAGE := $(srctree)/scripts/mkuboot.sh
+-targets += uImage
+-extra-y += vmlinux.bin vmlinux.gz
+-
+-$(obj)/vmlinux.bin: vmlinux FORCE
+- $(call if_changed,objbin)
+-
+-$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+- $(call if_changed,mygzip)
+-
+-$(obj)/uImage: $(obj)/vmlinux.gz
+- $(Q)rm -f $@
+- $(call cmd,uimage)
+- @echo -n ' Image: $@ '
+- @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
+-
+-install: $(CONFIGURE) $(BOOTIMAGE)
+- sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
+-
+-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
++ifeq ($(CONFIG_PPC32),y)
++image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
++endif
++
++initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y))
++
++$(obj)/zImage: $(addprefix $(obj)/, $(image-y))
++ @rm -f $@; ln $< $@
++$(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y))
++ @rm -f $@; ln $< $@
++
++install: $(CONFIGURE) $(image-y)
++ sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $<
++
++clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz)
++clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz)
+diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
+new file mode 100644
+index 0000000..34efdd0
+--- /dev/null
++++ b/arch/powerpc/boot/dts/mpc8272ads.dts
+@@ -0,0 +1,223 @@
++/*
++ * MPC8272 ADS Device Tree Source
++ *
++ * Copyright 2005 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.
++ */
++
++/ {
++ model = "MPC8272ADS";
++ compatible = "MPC8260ADS";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ linux,phandle = <100>;
++
++ cpus {
++ #cpus = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ linux,phandle = <200>;
++
++ PowerPC,8272 at 0 {
++ device_type = "cpu";
++ reg = <0>;
++ d-cache-line-size = <20>; // 32 bytes
++ i-cache-line-size = <20>; // 32 bytes
++ d-cache-size = <4000>; // L1, 16K
++ i-cache-size = <4000>; // L1, 16K
++ timebase-frequency = <0>;
++ bus-frequency = <0>;
++ clock-frequency = <0>;
++ 32-bit;
++ linux,phandle = <201>;
++ linux,boot-cpu;
++ };
++ };
++
++ interrupt-controller at f8200000 {
++ linux,phandle = <f8200000>;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ reg = <f8200000 f8200004>;
++ built-in;
++ device_type = "pci-pic";
++ };
++ memory {
++ device_type = "memory";
++ linux,phandle = <300>;
++ reg = <00000000 4000000 f4500000 00000020>;
++ };
++
++ soc8272 at f0000000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "soc";
++ ranges = < 0 0 2 00000000 f0000000 00053000>;
++ reg = <f0000000 0>;
++
++ mdio at 0 {
++ device_type = "mdio";
++ compatible = "fs_enet";
++ reg = <0 0>;
++ linux,phandle = <24520>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ ethernet-phy at 0 {
++ linux,phandle = <2452000>;
++ interrupt-parent = <10c00>;
++ interrupts = <19 1>;
++ reg = <0>;
++ bitbang = [ 12 12 13 02 02 01 ];
++ device_type = "ethernet-phy";
++ };
++ ethernet-phy at 1 {
++ linux,phandle = <2452001>;
++ interrupt-parent = <10c00>;
++ interrupts = <19 1>;
++ bitbang = [ 12 12 13 02 02 01 ];
++ reg = <3>;
++ device_type = "ethernet-phy";
++ };
++ };
++
++ ethernet at 24000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ device_type = "network";
++ device-id = <2>;
++ compatible = "fs_enet";
++ model = "FCC";
++ reg = <11300 20 8400 100 11380 30>;
++ mac-address = [ 00 11 2F 99 43 54 ];
++ interrupts = <20 2>;
++ interrupt-parent = <10c00>;
++ phy-handle = <2452000>;
++ rx-clock = <13>;
++ tx-clock = <12>;
++ };
++
++ ethernet at 25000 {
++ device_type = "network";
++ device-id = <3>;
++ compatible = "fs_enet";
++ model = "FCC";
++ reg = <11320 20 8500 100 113b0 30>;
++ mac-address = [ 00 11 2F 99 44 54 ];
++ interrupts = <21 2>;
++ interrupt-parent = <10c00>;
++ phy-handle = <2452001>;
++ rx-clock = <17>;
++ tx-clock = <18>;
++ };
++
++ cpm at f0000000 {
++ linux,phandle = <f0000000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "cpm";
++ model = "CPM2";
++ ranges = <00000000 00000000 3ffff>;
++ reg = <10d80 3280>;
++ command-proc = <119c0>;
++ brg-frequency = <17D7840>;
++ cpm_clk = <BEBC200>;
++
++ scc at 11a00 {
++ device_type = "serial";
++ compatible = "cpm_uart";
++ model = "SCC";
++ device-id = <2>;
++ reg = <11a00 20 8000 100>;
++ current-speed = <1c200>;
++ interrupts = <28 2>;
++ interrupt-parent = <10c00>;
++ clock-setup = <0 00ffffff>;
++ rx-clock = <1>;
++ tx-clock = <1>;
++ };
++
++ scc at 11a60 {
++ device_type = "serial";
++ compatible = "cpm_uart";
++ model = "SCC";
++ device-id = <5>;
++ reg = <11a60 20 8300 100>;
++ current-speed = <1c200>;
++ interrupts = <2b 2>;
++ interrupt-parent = <10c00>;
++ clock-setup = <1b ffffff00>;
++ rx-clock = <4>;
++ tx-clock = <4>;
++ };
++
++ };
++ interrupt-controller at 10c00 {
++ linux,phandle = <10c00>;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ reg = <10c00 80>;
++ built-in;
++ device_type = "cpm-pic";
++ compatible = "CPM2";
++ };
++ pci at 0500 {
++ linux,phandle = <0500>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ #address-cells = <3>;
++ compatible = "8272";
++ device_type = "pci";
++ reg = <10430 4dc>;
++ clock-frequency = <3f940aa>;
++ interrupt-map-mask = <f800 0 0 7>;
++ interrupt-map = <
++
++ /* IDSEL 0x16 */
++ b000 0 0 1 f8200000 40 0
++ b000 0 0 2 f8200000 41 0
++ b000 0 0 3 f8200000 42 0
++ b000 0 0 4 f8200000 43 0
++
++ /* IDSEL 0x17 */
++ b800 0 0 1 f8200000 43 0
++ b800 0 0 2 f8200000 40 0
++ b800 0 0 3 f8200000 41 0
++ b800 0 0 4 f8200000 42 0
++
++ /* IDSEL 0x18 */
++ c000 0 0 1 f8200000 42 0
++ c000 0 0 2 f8200000 43 0
++ c000 0 0 3 f8200000 40 0
++ c000 0 0 4 f8200000 41 0>;
++ interrupt-parent = <10c00>;
++ interrupts = <14 3>;
++ bus-range = <0 0>;
++ ranges = <02000000 0 80000000 80000000 0 40000000
++ 01000000 0 00000000 f6000000 0 02000000>;
++ };
++
++/* May need to remove if on a part without crypto engine */
++ crypto at 30000 {
++ device_type = "crypto";
++ model = "SEC2";
++ compatible = "talitos";
++ reg = <30000 10000>;
++ interrupts = <b 0>;
++ interrupt-parent = <10c00>;
++ num-channels = <4>;
++ channel-fifo-len = <18>;
++ exec-units-mask = <0000007e>;
++/* desc mask is for rev1.x, we need runtime fixup for >=2.x */
++ descriptor-types-mask = <01010ebf>;
++ };
++
++ };
++};
+diff --git a/arch/powerpc/boot/dts/mpc8349emds.dts b/arch/powerpc/boot/dts/mpc8349emds.dts
+index 12f5dbf..efceb34 100644
+--- a/arch/powerpc/boot/dts/mpc8349emds.dts
++++ b/arch/powerpc/boot/dts/mpc8349emds.dts
+@@ -214,10 +214,10 @@
+ b800 0 0 4 700 15 8
+
+ /* IDSEL 0x18 */
+- b000 0 0 1 700 15 8
+- b000 0 0 2 700 16 8
+- b000 0 0 3 700 17 8
+- b000 0 0 4 700 14 8>;
++ c000 0 0 1 700 15 8
++ c000 0 0 2 700 16 8
++ c000 0 0 3 700 17 8
++ c000 0 0 4 700 14 8>;
+ interrupt-parent = <700>;
+ interrupts = <42 8>;
+ bus-range = <0 0>;
+@@ -274,10 +274,10 @@
+ b800 0 0 4 700 15 8
+
+ /* IDSEL 0x18 */
+- b000 0 0 1 700 15 8
+- b000 0 0 2 700 16 8
+- b000 0 0 3 700 17 8
+- b000 0 0 4 700 14 8>;
++ c000 0 0 1 700 15 8
++ c000 0 0 2 700 16 8
++ c000 0 0 3 700 17 8
++ c000 0 0 4 700 14 8>;
+ interrupt-parent = <700>;
+ interrupts = <42 8>;
+ bus-range = <0 0>;
+diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
+new file mode 100644
+index 0000000..27807fc
+--- /dev/null
++++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
+@@ -0,0 +1,246 @@
++/*
++ * MPC8349E-mITX Device Tree Source
++ *
++ * Copyright 2006 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.
++ */
++/ {
++ model = "MPC8349EMITX";
++ compatible = "MPC834xMITX";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ cpus {
++ #cpus = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ PowerPC,8349 at 0 {
++ device_type = "cpu";
++ reg = <0>;
++ d-cache-line-size = <20>;
++ i-cache-line-size = <20>;
++ d-cache-size = <8000>;
++ i-cache-size = <8000>;
++ timebase-frequency = <0>; // from bootloader
++ bus-frequency = <0>; // from bootloader
++ clock-frequency = <0>; // from bootloader
++ 32-bit;
++ };
++ };
++
++ memory {
++ device_type = "memory";
++ reg = <00000000 10000000>;
++ };
++
++ soc8349 at e0000000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "soc";
++ ranges = <0 e0000000 00100000>;
++ reg = <e0000000 00000200>;
++ bus-frequency = <0>; // from bootloader
++
++ wdt at 200 {
++ device_type = "watchdog";
++ compatible = "mpc83xx_wdt";
++ reg = <200 100>;
++ };
++
++ i2c at 3000 {
++ device_type = "i2c";
++ compatible = "fsl-i2c";
++ reg = <3000 100>;
++ interrupts = <e 8>;
++ interrupt-parent = <700>;
++ dfsrr;
++ };
++
++ i2c at 3100 {
++ device_type = "i2c";
++ compatible = "fsl-i2c";
++ reg = <3100 100>;
++ interrupts = <f 8>;
++ interrupt-parent = <700>;
++ dfsrr;
++ };
++
++ spi at 7000 {
++ device_type = "spi";
++ compatible = "mpc83xx_spi";
++ reg = <7000 1000>;
++ interrupts = <10 8>;
++ interrupt-parent = <700>;
++ mode = <0>;
++ };
++
++ usb at 22000 {
++ device_type = "usb";
++ compatible = "fsl-usb2-mph";
++ reg = <22000 1000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ interrupt-parent = <700>;
++ interrupts = <27 2>;
++ phy_type = "ulpi";
++ port1;
++ };
++
++ usb at 23000 {
++ device_type = "usb";
++ compatible = "fsl-usb2-dr";
++ reg = <23000 1000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ interrupt-parent = <700>;
++ interrupts = <26 2>;
++ phy_type = "ulpi";
++ };
++
++ mdio at 24520 {
++ device_type = "mdio";
++ compatible = "gianfar";
++ reg = <24520 20>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ linux,phandle = <24520>;
++
++ /* Vitesse 8201 */
++ ethernet-phy at 1c {
++ linux,phandle = <245201c>;
++ interrupt-parent = <700>;
++ interrupts = <12 2>;
++ reg = <1c>;
++ device_type = "ethernet-phy";
++ };
++
++ /* Vitesse 7385 */
++ ethernet-phy at 1f {
++ linux,phandle = <245201f>;
++ interrupt-parent = <700>;
++ interrupts = <12 2>;
++ reg = <1f>;
++ device_type = "ethernet-phy";
++ };
++ };
++
++ ethernet at 24000 {
++ device_type = "network";
++ model = "TSEC";
++ compatible = "gianfar";
++ reg = <24000 1000>;
++ address = [ 00 00 00 00 00 00 ];
++ local-mac-address = [ 00 00 00 00 00 00 ];
++ interrupts = <20 8 21 8 22 8>;
++ interrupt-parent = <700>;
++ phy-handle = <245201c>;
++ };
++
++ ethernet at 25000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ device_type = "network";
++ model = "TSEC";
++ compatible = "gianfar";
++ reg = <25000 1000>;
++ address = [ 00 00 00 00 00 00 ];
++ local-mac-address = [ 00 00 00 00 00 00 ];
++ interrupts = <23 8 24 8 25 8>;
++ interrupt-parent = <700>;
++ phy-handle = <245201f>;
++ };
++
++ serial at 4500 {
++ device_type = "serial";
++ compatible = "ns16550";
++ reg = <4500 100>;
++ clock-frequency = <0>; // from bootloader
++ interrupts = <9 8>;
++ interrupt-parent = <700>;
++ };
++
++ serial at 4600 {
++ device_type = "serial";
++ compatible = "ns16550";
++ reg = <4600 100>;
++ clock-frequency = <0>; // from bootloader
++ interrupts = <a 8>;
++ interrupt-parent = <700>;
++ };
++
++ pci at 8500 {
++ interrupt-map-mask = <f800 0 0 7>;
++ interrupt-map = <
++ /* IDSEL 0x10 - SATA */
++ 8000 0 0 1 700 16 8 /* SATA_INTA */
++ >;
++ interrupt-parent = <700>;
++ interrupts = <42 8>;
++ bus-range = <0 0>;
++ ranges = <42000000 0 80000000 80000000 0 10000000
++ 02000000 0 90000000 90000000 0 10000000
++ 01000000 0 00000000 e2000000 0 01000000>;
++ clock-frequency = <3f940aa>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ #address-cells = <3>;
++ reg = <8500 100>;
++ compatible = "83xx";
++ device_type = "pci";
++ };
++
++ pci at 8600 {
++ interrupt-map-mask = <f800 0 0 7>;
++ interrupt-map = <
++ /* IDSEL 0x0E - MiniPCI Slot */
++ 7000 0 0 1 700 15 8 /* PCI_INTA */
++
++ /* IDSEL 0x0F - PCI Slot */
++ 7800 0 0 1 700 14 8 /* PCI_INTA */
++ 7800 0 0 2 700 15 8 /* PCI_INTB */
++ >;
++ interrupt-parent = <700>;
++ interrupts = <43 8>;
++ bus-range = <1 1>;
++ ranges = <42000000 0 a0000000 a0000000 0 10000000
++ 02000000 0 b0000000 b0000000 0 10000000
++ 01000000 0 00000000 e3000000 0 01000000>;
++ clock-frequency = <3f940aa>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ #address-cells = <3>;
++ reg = <8600 100>;
++ compatible = "83xx";
++ device_type = "pci";
++ };
++
++ crypto at 30000 {
++ device_type = "crypto";
++ model = "SEC2";
++ compatible = "talitos";
++ reg = <30000 10000>;
++ interrupts = <b 8>;
++ interrupt-parent = <700>;
++ num-channels = <4>;
++ channel-fifo-len = <18>;
++ exec-units-mask = <0000007e>;
++ descriptor-types-mask = <01010ebf>;
++ };
++
++ pic at 700 {
++ linux,phandle = <700>;
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ reg = <700 100>;
++ built-in;
++ device_type = "ipic";
++ };
++ };
++};
+diff --git a/arch/powerpc/boot/dts/mpc8360emds.dts b/arch/powerpc/boot/dts/mpc8360emds.dts
+new file mode 100644
+index 0000000..9022192
+--- /dev/null
++++ b/arch/powerpc/boot/dts/mpc8360emds.dts
+@@ -0,0 +1,375 @@
++/*
++ * MPC8360E EMDS Device Tree Source
++ *
++ * Copyright 2006 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.
++ */
++
++
++/*
++/memreserve/ 00000000 1000000;
++*/
++
++/ {
++ model = "MPC8360EPB";
++ compatible = "MPC83xx";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ linux,phandle = <100>;
++
++ cpus {
++ #cpus = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ linux,phandle = <200>;
++
++ PowerPC,8360 at 0 {
++ device_type = "cpu";
++ reg = <0>;
++ d-cache-line-size = <20>; // 32 bytes
++ i-cache-line-size = <20>; // 32 bytes
++ d-cache-size = <8000>; // L1, 32K
++ i-cache-size = <8000>; // L1, 32K
++ timebase-frequency = <3EF1480>;
++ bus-frequency = <FBC5200>;
++ clock-frequency = <1F78A400>;
++ 32-bit;
++ linux,phandle = <201>;
++ linux,boot-cpu;
++ };
++ };
++
++ memory {
++ device_type = "memory";
++ linux,phandle = <300>;
++ reg = <00000000 10000000>;
++ };
++
++ bcsr at f8000000 {
++ device_type = "board-control";
++ reg = <f8000000 8000>;
++ };
++
++ soc8360 at e0000000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "soc";
++ ranges = <0 e0000000 00100000>;
++ reg = <e0000000 00000200>;
++ bus-frequency = <FBC5200>;
++
++ wdt at 200 {
++ device_type = "watchdog";
++ compatible = "mpc83xx_wdt";
++ reg = <200 100>;
++ };
++
++ i2c at 3000 {
++ device_type = "i2c";
++ compatible = "fsl-i2c";
++ reg = <3000 100>;
++ interrupts = <e 8>;
++ interrupt-parent = <700>;
++ dfsrr;
++ };
++
++ i2c at 3100 {
++ device_type = "i2c";
++ compatible = "fsl-i2c";
++ reg = <3100 100>;
++ interrupts = <f 8>;
++ interrupt-parent = <700>;
++ dfsrr;
++ };
++
++ serial at 4500 {
++ device_type = "serial";
++ compatible = "ns16550";
++ reg = <4500 100>;
++ clock-frequency = <FBC5200>;
++ interrupts = <9 8>;
++ interrupt-parent = <700>;
++ };
++
++ serial at 4600 {
++ device_type = "serial";
++ compatible = "ns16550";
++ reg = <4600 100>;
++ clock-frequency = <FBC5200>;
++ interrupts = <a 8>;
++ interrupt-parent = <700>;
++ };
++
++ crypto at 30000 {
++ device_type = "crypto";
++ model = "SEC2";
++ compatible = "talitos";
++ reg = <30000 10000>;
++ interrupts = <b 8>;
++ interrupt-parent = <700>;
++ num-channels = <4>;
++ channel-fifo-len = <18>;
++ exec-units-mask = <0000007e>;
++ /* desc mask is for rev1.x, we need runtime fixup for >=2.x */
++ descriptor-types-mask = <01010ebf>;
++ };
++
++ pci at 8500 {
++ linux,phandle = <8500>;
++ interrupt-map-mask = <f800 0 0 7>;
++ interrupt-map = <
++
++ /* IDSEL 0x11 AD17 */
++ 8800 0 0 1 700 14 8
++ 8800 0 0 2 700 15 8
++ 8800 0 0 3 700 16 8
++ 8800 0 0 4 700 17 8
++
++ /* IDSEL 0x12 AD18 */
++ 9000 0 0 1 700 16 8
++ 9000 0 0 2 700 17 8
++ 9000 0 0 3 700 14 8
++ 9000 0 0 4 700 15 8
++
++ /* IDSEL 0x13 AD19 */
++ 9800 0 0 1 700 17 8
++ 9800 0 0 2 700 14 8
++ 9800 0 0 3 700 15 8
++ 9800 0 0 4 700 16 8
++
++ /* IDSEL 0x15 AD21*/
++ a800 0 0 1 700 14 8
++ a800 0 0 2 700 15 8
++ a800 0 0 3 700 16 8
++ a800 0 0 4 700 17 8
++
++ /* IDSEL 0x16 AD22*/
++ b000 0 0 1 700 17 8
++ b000 0 0 2 700 14 8
++ b000 0 0 3 700 15 8
++ b000 0 0 4 700 16 8
++
++ /* IDSEL 0x17 AD23*/
++ b800 0 0 1 700 16 8
++ b800 0 0 2 700 17 8
++ b800 0 0 3 700 14 8
++ b800 0 0 4 700 15 8
++
++ /* IDSEL 0x18 AD24*/
++ c000 0 0 1 700 15 8
++ c000 0 0 2 700 16 8
++ c000 0 0 3 700 17 8
++ c000 0 0 4 700 14 8>;
++ interrupt-parent = <700>;
++ interrupts = <42 8>;
++ bus-range = <0 0>;
++ ranges = <02000000 0 a0000000 a0000000 0 10000000
++ 42000000 0 80000000 80000000 0 10000000
++ 01000000 0 00000000 e2000000 0 00100000>;
++ clock-frequency = <3f940aa>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ #address-cells = <3>;
++ reg = <8500 100>;
++ compatible = "83xx";
++ device_type = "pci";
++ };
++
++ pic at 700 {
++ linux,phandle = <700>;
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ reg = <700 100>;
++ built-in;
++ device_type = "ipic";
++ };
++
++ par_io at 1400 {
++ reg = <1400 100>;
++ device_type = "par_io";
++ num-ports = <7>;
++
++ ucc_pin at 01 {
++ linux,phandle = <140001>;
++ pio-map = <
++ /* port pin dir open_drain assignment has_irq */
++ 0 3 1 0 1 0 /* TxD0 */
++ 0 4 1 0 1 0 /* TxD1 */
++ 0 5 1 0 1 0 /* TxD2 */
++ 0 6 1 0 1 0 /* TxD3 */
++ 1 6 1 0 3 0 /* TxD4 */
++ 1 7 1 0 1 0 /* TxD5 */
++ 1 9 1 0 2 0 /* TxD6 */
++ 1 a 1 0 2 0 /* TxD7 */
++ 0 9 2 0 1 0 /* RxD0 */
++ 0 a 2 0 1 0 /* RxD1 */
++ 0 b 2 0 1 0 /* RxD2 */
++ 0 c 2 0 1 0 /* RxD3 */
++ 0 d 2 0 1 0 /* RxD4 */
++ 1 1 2 0 2 0 /* RxD5 */
++ 1 0 2 0 2 0 /* RxD6 */
++ 1 4 2 0 2 0 /* RxD7 */
++ 0 7 1 0 1 0 /* TX_EN */
++ 0 8 1 0 1 0 /* TX_ER */
++ 0 f 2 0 1 0 /* RX_DV */
++ 0 10 2 0 1 0 /* RX_ER */
++ 0 0 2 0 1 0 /* RX_CLK */
++ 2 9 1 0 3 0 /* GTX_CLK - CLK10 */
++ 2 8 2 0 1 0>; /* GTX125 - CLK9 */
++ };
++ ucc_pin at 02 {
++ linux,phandle = <140002>;
++ pio-map = <
++ /* port pin dir open_drain assignment has_irq */
++ 0 11 1 0 1 0 /* TxD0 */
++ 0 12 1 0 1 0 /* TxD1 */
++ 0 13 1 0 1 0 /* TxD2 */
++ 0 14 1 0 1 0 /* TxD3 */
++ 1 2 1 0 1 0 /* TxD4 */
++ 1 3 1 0 2 0 /* TxD5 */
++ 1 5 1 0 3 0 /* TxD6 */
++ 1 8 1 0 3 0 /* TxD7 */
++ 0 17 2 0 1 0 /* RxD0 */
++ 0 18 2 0 1 0 /* RxD1 */
++ 0 19 2 0 1 0 /* RxD2 */
++ 0 1a 2 0 1 0 /* RxD3 */
++ 0 1b 2 0 1 0 /* RxD4 */
++ 1 c 2 0 2 0 /* RxD5 */
++ 1 d 2 0 3 0 /* RxD6 */
++ 1 b 2 0 2 0 /* RxD7 */
++ 0 15 1 0 1 0 /* TX_EN */
++ 0 16 1 0 1 0 /* TX_ER */
++ 0 1d 2 0 1 0 /* RX_DV */
++ 0 1e 2 0 1 0 /* RX_ER */
++ 0 1f 2 0 1 0 /* RX_CLK */
++ 2 2 1 0 2 0 /* GTX_CLK - CLK10 */
++ 2 3 2 0 1 0 /* GTX125 - CLK4 */
++ 0 1 3 0 2 0 /* MDIO */
++ 0 2 1 0 1 0>; /* MDC */
++ };
++
++ };
++ };
++
++ qe at e0100000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ device_type = "qe";
++ model = "QE";
++ ranges = <0 e0100000 00100000>;
++ reg = <e0100000 480>;
++ brg-frequency = <0>;
++ bus-frequency = <179A7B00>;
++
++ muram at 10000 {
++ device_type = "muram";
++ ranges = <0 00010000 0000c000>;
++
++ data-only at 0{
++ reg = <0 c000>;
++ };
++ };
++
++ spi at 4c0 {
++ device_type = "spi";
++ compatible = "fsl_spi";
++ reg = <4c0 40>;
++ interrupts = <2>;
++ interrupt-parent = <80>;
++ mode = "cpu";
++ };
++
++ spi at 500 {
++ device_type = "spi";
++ compatible = "fsl_spi";
++ reg = <500 40>;
++ interrupts = <1>;
++ interrupt-parent = <80>;
++ mode = "cpu";
++ };
++
++ usb at 6c0 {
++ device_type = "usb";
++ compatible = "qe_udc";
++ reg = <6c0 40 8B00 100>;
++ interrupts = <b>;
++ interrupt-parent = <80>;
++ mode = "slave";
++ };
++
++ ucc at 2000 {
++ device_type = "network";
++ compatible = "ucc_geth";
++ model = "UCC";
++ device-id = <1>;
++ reg = <2000 200>;
++ interrupts = <20>;
++ interrupt-parent = <80>;
++ mac-address = [ 00 04 9f 00 23 23 ];
++ rx-clock = <0>;
++ tx-clock = <19>;
++ phy-handle = <212000>;
++ pio-handle = <140001>;
++ };
++
++ ucc at 3000 {
++ device_type = "network";
++ compatible = "ucc_geth";
++ model = "UCC";
++ device-id = <2>;
++ reg = <3000 200>;
++ interrupts = <21>;
++ interrupt-parent = <80>;
++ mac-address = [ 00 11 22 33 44 55 ];
++ rx-clock = <0>;
++ tx-clock = <14>;
++ phy-handle = <212001>;
++ pio-handle = <140002>;
++ };
++
++ mdio at 2120 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2120 18>;
++ device_type = "mdio";
++ compatible = "ucc_geth_phy";
++
++ ethernet-phy at 00 {
++ linux,phandle = <212000>;
++ interrupt-parent = <700>;
++ interrupts = <11 2>;
++ reg = <0>;
++ device_type = "ethernet-phy";
++ interface = <6>; //ENET_1000_GMII
++ };
++ ethernet-phy at 01 {
++ linux,phandle = <212001>;
++ interrupt-parent = <700>;
++ interrupts = <12 2>;
++ reg = <1>;
++ device_type = "ethernet-phy";
++ interface = <6>;
++ };
++ };
++
++ qeic at 80 {
++ linux,phandle = <80>;
++ interrupt-controller;
++ device_type = "qeic";
++ #address-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <80 80>;
++ built-in;
++ big-endian;
++ interrupts = <20 8 21 8>; //high:32 low:33
++ interrupt-parent = <700>;
++ };
++
++ };
++};
+diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
+new file mode 100644
+index 0000000..2b16848
+--- /dev/null
++++ b/arch/powerpc/boot/dts/mpc8560ads.dts
+@@ -0,0 +1,302 @@
++/*
++ * MPC8560 ADS Device Tree Source
++ *
++ * Copyright 2006 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.
++ */
++
++
++/ {
++ model = "MPC8560ADS";
++ compatible = "MPC85xxADS";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ linux,phandle = <100>;
++
++ cpus {
++ #cpus = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ linux,phandle = <200>;
++
++ PowerPC,8560 at 0 {
++ device_type = "cpu";
++ reg = <0>;
++ d-cache-line-size = <20>; // 32 bytes
++ i-cache-line-size = <20>; // 32 bytes
++ d-cache-size = <8000>; // L1, 32K
++ i-cache-size = <8000>; // L1, 32K
++ timebase-frequency = <04ead9a0>;
++ bus-frequency = <13ab6680>;
++ clock-frequency = <312c8040>;
++ 32-bit;
++ linux,phandle = <201>;
++ linux,boot-cpu;
++ };
++ };
++
++ memory {
++ device_type = "memory";
++ linux,phandle = <300>;
++ reg = <00000000 10000000>;
++ };
++
++ soc8560 at e0000000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "soc";
++ ranges = <0 e0000000 00100000>;
++ reg = <e0000000 00000200>;
++ bus-frequency = <13ab6680>;
++
++ mdio at 24520 {
++ device_type = "mdio";
++ compatible = "gianfar";
++ reg = <24520 20>;
++ linux,phandle = <24520>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ ethernet-phy at 0 {
++ linux,phandle = <2452000>;
++ interrupt-parent = <40000>;
++ interrupts = <35 1>;
++ reg = <0>;
++ device_type = "ethernet-phy";
++ };
++ ethernet-phy at 1 {
++ linux,phandle = <2452001>;
++ interrupt-parent = <40000>;
++ interrupts = <35 1>;
++ reg = <1>;
++ device_type = "ethernet-phy";
++ };
++ ethernet-phy at 2 {
++ linux,phandle = <2452002>;
++ interrupt-parent = <40000>;
++ interrupts = <37 1>;
++ reg = <2>;
++ device_type = "ethernet-phy";
++ };
++ ethernet-phy at 3 {
++ linux,phandle = <2452003>;
++ interrupt-parent = <40000>;
++ interrupts = <37 1>;
++ reg = <3>;
++ device_type = "ethernet-phy";
++ };
++ };
++
++ ethernet at 24000 {
++ device_type = "network";
++ model = "TSEC";
++ compatible = "gianfar";
++ reg = <24000 1000>;
++ address = [ 00 00 0C 00 00 FD ];
++ interrupts = <d 2 e 2 12 2>;
++ interrupt-parent = <40000>;
++ phy-handle = <2452000>;
++ };
++
++ ethernet at 25000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ device_type = "network";
++ model = "TSEC";
++ compatible = "gianfar";
++ reg = <25000 1000>;
++ address = [ 00 00 0C 00 01 FD ];
++ interrupts = <13 2 14 2 18 2>;
++ interrupt-parent = <40000>;
++ phy-handle = <2452001>;
++ };
++
++ pci at 8000 {
++ linux,phandle = <8000>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ #address-cells = <3>;
++ compatible = "85xx";
++ device_type = "pci";
++ reg = <8000 400>;
++ clock-frequency = <3f940aa>;
++ interrupt-map-mask = <f800 0 0 7>;
++ interrupt-map = <
++
++ /* IDSEL 0x2 */
++ 1000 0 0 1 40000 31 1
++ 1000 0 0 2 40000 32 1
++ 1000 0 0 3 40000 33 1
++ 1000 0 0 4 40000 34 1
++
++ /* IDSEL 0x3 */
++ 1800 0 0 1 40000 34 1
++ 1800 0 0 2 40000 31 1
++ 1800 0 0 3 40000 32 1
++ 1800 0 0 4 40000 33 1
++
++ /* IDSEL 0x4 */
++ 2000 0 0 1 40000 33 1
++ 2000 0 0 2 40000 34 1
++ 2000 0 0 3 40000 31 1
++ 2000 0 0 4 40000 32 1
++
++ /* IDSEL 0x5 */
++ 2800 0 0 1 40000 32 1
++ 2800 0 0 2 40000 33 1
++ 2800 0 0 3 40000 34 1
++ 2800 0 0 4 40000 31 1
++
++ /* IDSEL 12 */
++ 6000 0 0 1 40000 31 1
++ 6000 0 0 2 40000 32 1
++ 6000 0 0 3 40000 33 1
++ 6000 0 0 4 40000 34 1
++
++ /* IDSEL 13 */
++ 6800 0 0 1 40000 34 1
++ 6800 0 0 2 40000 31 1
++ 6800 0 0 3 40000 32 1
++ 6800 0 0 4 40000 33 1
++
++ /* IDSEL 14*/
++ 7000 0 0 1 40000 33 1
++ 7000 0 0 2 40000 34 1
++ 7000 0 0 3 40000 31 1
++ 7000 0 0 4 40000 32 1
++
++ /* IDSEL 15 */
++ 7800 0 0 1 40000 32 1
++ 7800 0 0 2 40000 33 1
++ 7800 0 0 3 40000 34 1
++ 7800 0 0 4 40000 31 1
++
++ /* IDSEL 18 */
++ 9000 0 0 1 40000 31 1
++ 9000 0 0 2 40000 32 1
++ 9000 0 0 3 40000 33 1
++ 9000 0 0 4 40000 34 1
++
++ /* IDSEL 19 */
++ 9800 0 0 1 40000 34 1
++ 9800 0 0 2 40000 31 1
++ 9800 0 0 3 40000 32 1
++ 9800 0 0 4 40000 33 1
++
++ /* IDSEL 20 */
++ a000 0 0 1 40000 33 1
++ a000 0 0 2 40000 34 1
++ a000 0 0 3 40000 31 1
++ a000 0 0 4 40000 32 1
++
++ /* IDSEL 21 */
++ a800 0 0 1 40000 32 1
++ a800 0 0 2 40000 33 1
++ a800 0 0 3 40000 34 1
++ a800 0 0 4 40000 31 1>;
++
++ interrupt-parent = <40000>;
++ interrupts = <42 0>;
++ bus-range = <0 0>;
++ ranges = <02000000 0 80000000 80000000 0 20000000
++ 01000000 0 00000000 e2000000 0 01000000>;
++ };
++
++ pic at 40000 {
++ linux,phandle = <40000>;
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ reg = <40000 20100>;
++ built-in;
++ device_type = "open-pic";
++ };
++
++ cpm at e0000000 {
++ linux,phandle = <e0000000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ device_type = "cpm";
++ model = "CPM2";
++ ranges = <0 0 c0000>;
++ reg = <80000 40000>;
++ command-proc = <919c0>;
++ brg-frequency = <9d5b340>;
++
++ pic at 90c00 {
++ linux,phandle = <90c00>;
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ interrupts = <1e 0>;
++ interrupt-parent = <40000>;
++ reg = <90c00 80>;
++ built-in;
++ device_type = "cpm-pic";
++ };
++
++ scc at 91a00 {
++ device_type = "serial";
++ compatible = "cpm_uart";
++ model = "SCC";
++ device-id = <1>;
++ reg = <91a00 20 88000 100>;
++ clock-setup = <00ffffff 0>;
++ rx-clock = <1>;
++ tx-clock = <1>;
++ current-speed = <1c200>;
++ interrupts = <64 1>;
++ interrupt-parent = <90c00>;
++ };
++
++ scc at 91a20 {
++ device_type = "serial";
++ compatible = "cpm_uart";
++ model = "SCC";
++ device-id = <2>;
++ reg = <91a20 20 88100 100>;
++ clock-setup = <ff00ffff 90000>;
++ rx-clock = <2>;
++ tx-clock = <2>;
++ current-speed = <1c200>;
++ interrupts = <65 1>;
++ interrupt-parent = <90c00>;
++ };
++
++ fcc at 91320 {
++ device_type = "network";
++ compatible = "fs_enet";
++ model = "FCC";
++ device-id = <2>;
++ reg = <91320 20 88500 100 913a0 30>;
++ mac-address = [ 00 00 0C 00 02 FD ];
++ clock-setup = <ff00ffff 250000>;
++ rx-clock = <15>;
++ tx-clock = <16>;
++ interrupts = <5d 1>;
++ interrupt-parent = <90c00>;
++ phy-handle = <2452002>;
++ };
++
++ fcc at 91340 {
++ device_type = "network";
++ compatible = "fs_enet";
++ model = "FCC";
++ device-id = <3>;
++ reg = <91340 20 88600 100 913d0 30>;
++ mac-address = [ 00 00 0C 00 03 FD ];
++ clock-setup = <ffff00ff 3700>;
++ rx-clock = <17>;
++ tx-clock = <18>;
++ interrupts = <5e 1>;
++ interrupt-parent = <90c00>;
++ phy-handle = <2452003>;
++ };
++ };
++ };
++};
+diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h
+new file mode 100644
+index 0000000..761c8dc
+--- /dev/null
++++ b/arch/powerpc/boot/flatdevtree.h
+@@ -0,0 +1,46 @@
++/*
++ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++ */
++
++#ifndef FLATDEVTREE_H
++#define FLATDEVTREE_H
++
++#include "types.h"
++
++/* Definitions used by the flattened device tree */
++#define OF_DT_HEADER 0xd00dfeed /* marker */
++#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
++#define OF_DT_END_NODE 0x2 /* End node */
++#define OF_DT_PROP 0x3 /* Property: name off, size, content */
++#define OF_DT_NOP 0x4 /* nop */
++#define OF_DT_END 0x9
++
++#define OF_DT_VERSION 0x10
++
++struct boot_param_header {
++ u32 magic; /* magic word OF_DT_HEADER */
++ u32 totalsize; /* total size of DT block */
++ u32 off_dt_struct; /* offset to structure */
++ u32 off_dt_strings; /* offset to strings */
++ u32 off_mem_rsvmap; /* offset to memory reserve map */
++ u32 version; /* format version */
++ u32 last_comp_version; /* last compatible version */
++ /* version 2 fields below */
++ u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
++ /* version 3 fields below */
++ u32 dt_strings_size; /* size of the DT strings block */
++};
++
++#endif /* FLATDEVTREE_H */
+diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
+index b66634c..d719bb9 100644
+--- a/arch/powerpc/boot/main.c
++++ b/arch/powerpc/boot/main.c
+@@ -14,17 +14,12 @@
+ #include "page.h"
+ #include "string.h"
+ #include "stdio.h"
+-#include "prom.h"
+ #include "zlib.h"
++#include "ops.h"
++#include "flatdevtree.h"
+
+ extern void flush_cache(void *, unsigned long);
+
+-
+-/* Value picked to match that used by yaboot */
+-#define PROG_START 0x01400000 /* only used on 64-bit systems */
+-#define RAM_END (512<<20) /* Fixme: use OF */
+-#define ONE_MB 0x100000
+-
+ extern char _start[];
+ extern char __bss_start[];
+ extern char _end[];
+@@ -33,14 +28,6 @@ extern char _vmlinux_end[];
+ extern char _initrd_start[];
+ extern char _initrd_end[];
+
+-/* A buffer that may be edited by tools operating on a zImage binary so as to
+- * edit the command line passed to vmlinux (by setting /chosen/bootargs).
+- * The buffer is put in it's own section so that tools may locate it easier.
+- */
+-static char builtin_cmdline[512]
+- __attribute__((section("__builtin_cmdline")));
+-
+-
+ struct addr_range {
+ unsigned long addr;
+ unsigned long size;
+@@ -51,21 +38,16 @@ static struct addr_range vmlinuz;
+ static struct addr_range initrd;
+
+ static unsigned long elfoffset;
++static int is_64bit;
+
+-static char scratch[46912]; /* scratch space for gunzip, from zlib_inflate_workspacesize() */
++/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
++static char scratch[46912];
+ static char elfheader[256];
+
+-
+-typedef void (*kernel_entry_t)( unsigned long,
+- unsigned long,
+- void *,
+- void *);
+-
++typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
+
+ #undef DEBUG
+
+-static unsigned long claim_base;
+-
+ #define HEAD_CRC 2
+ #define EXTRA_FIELD 4
+ #define ORIG_NAME 8
+@@ -123,24 +105,6 @@ static void gunzip(void *dst, int dstlen
+ zlib_inflateEnd(&s);
+ }
+
+-static unsigned long try_claim(unsigned long size)
+-{
+- unsigned long addr = 0;
+-
+- for(; claim_base < RAM_END; claim_base += ONE_MB) {
+-#ifdef DEBUG
+- printf(" trying: 0x%08lx\n\r", claim_base);
+-#endif
+- addr = (unsigned long)claim(claim_base, size, 0);
+- if ((void *)addr != (void *)-1)
+- break;
+- }
+- if (addr == 0)
+- return 0;
+- claim_base = PAGE_ALIGN(claim_base + size);
+- return addr;
+-}
+-
+ static int is_elf64(void *hdr)
+ {
+ Elf64_Ehdr *elf64 = hdr;
+@@ -169,16 +133,7 @@ static int is_elf64(void *hdr)
+ vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
+ vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
+
+-#if defined(PROG_START)
+- /*
+- * Maintain a "magic" minimum address. This keeps some older
+- * firmware platforms running.
+- */
+-
+- if (claim_base < PROG_START)
+- claim_base = PROG_START;
+-#endif
+-
++ is_64bit = 1;
+ return 1;
+ }
+
+@@ -212,47 +167,9 @@ static int is_elf32(void *hdr)
+ return 1;
+ }
+
+-void export_cmdline(void* chosen_handle)
+-{
+- int len;
+- char cmdline[2] = { 0, 0 };
+-
+- if (builtin_cmdline[0] == 0)
+- return;
+-
+- len = getprop(chosen_handle, "bootargs", cmdline, sizeof(cmdline));
+- if (len > 0 && cmdline[0] != 0)
+- return;
+-
+- setprop(chosen_handle, "bootargs", builtin_cmdline,
+- strlen(builtin_cmdline) + 1);
+-}
+-
+-
+-void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
++static void prep_kernel(unsigned long *a1, unsigned long *a2)
+ {
+ int len;
+- kernel_entry_t kernel_entry;
+-
+- memset(__bss_start, 0, _end - __bss_start);
+-
+- prom = (int (*)(void *)) promptr;
+- chosen_handle = finddevice("/chosen");
+- if (chosen_handle == (void *) -1)
+- exit();
+- if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+- exit();
+-
+- printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
+-
+- /*
+- * The first available claim_base must be above the end of the
+- * the loaded kernel wrapper file (_start to _end includes the
+- * initrd image if it is present) and rounded up to a nice
+- * 1 MB boundary for good measure.
+- */
+-
+- claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
+
+ vmlinuz.addr = (unsigned long)_vmlinux_start;
+ vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
+@@ -263,43 +180,51 @@ void start(unsigned long a1, unsigned lo
+ gunzip(elfheader, sizeof(elfheader),
+ (unsigned char *)vmlinuz.addr, &len);
+ } else
+- memcpy(elfheader, (const void *)vmlinuz.addr, sizeof(elfheader));
++ memcpy(elfheader, (const void *)vmlinuz.addr,
++ sizeof(elfheader));
+
+ if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
+ printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
+ exit();
+ }
++ if (platform_ops.image_hdr)
++ platform_ops.image_hdr(elfheader);
+
+- /* We need to claim the memsize plus the file offset since gzip
++ /* We need to alloc the memsize plus the file offset since gzip
+ * will expand the header (file offset), then the kernel, then
+ * possible rubbish we don't care about. But the kernel bss must
+ * be claimed (it will be zero'd by the kernel itself)
+ */
+ printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
+- vmlinux.addr = try_claim(vmlinux.memsize);
++ vmlinux.addr = (unsigned long)malloc(vmlinux.memsize);
+ if (vmlinux.addr == 0) {
+ printf("Can't allocate memory for kernel image !\n\r");
+ exit();
+ }
+
+ /*
+- * Now we try to claim memory for the initrd (and copy it there)
++ * Now we try to alloc memory for the initrd (and copy it there)
+ */
+ initrd.size = (unsigned long)(_initrd_end - _initrd_start);
+ initrd.memsize = initrd.size;
+ if ( initrd.size > 0 ) {
+- printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size);
+- initrd.addr = try_claim(initrd.size);
++ printf("Allocating 0x%lx bytes for initrd ...\n\r",
++ initrd.size);
++ initrd.addr = (unsigned long)malloc((u32)initrd.size);
+ if (initrd.addr == 0) {
+- printf("Can't allocate memory for initial ramdisk !\n\r");
++ printf("Can't allocate memory for initial "
++ "ramdisk !\n\r");
+ exit();
+ }
+- a1 = initrd.addr;
+- a2 = initrd.size;
+- printf("initial ramdisk moving 0x%lx <- 0x%lx (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", *((unsigned long *)initrd.addr));
++ *a1 = initrd.addr;
++ *a2 = initrd.size;
++ 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",
++ *((unsigned long *)initrd.addr));
+ }
+
+ /* Eventually gunzip the kernel */
+@@ -311,11 +236,10 @@ void start(unsigned long a1, unsigned lo
+ (unsigned char *)vmlinuz.addr, &len);
+ printf("done 0x%lx bytes\n\r", len);
+ } else {
+- memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
++ memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,
++ vmlinuz.size);
+ }
+
+- export_cmdline(chosen_handle);
+-
+ /* Skip over the ELF header */
+ #ifdef DEBUG
+ printf("... skipping 0x%lx bytes of ELF header\n\r",
+@@ -324,23 +248,107 @@ void start(unsigned long a1, unsigned lo
+ vmlinux.addr += elfoffset;
+
+ flush_cache((void *)vmlinux.addr, vmlinux.size);
++}
+
+- kernel_entry = (kernel_entry_t)vmlinux.addr;
+-#ifdef DEBUG
+- printf( "kernel:\n\r"
+- " entry addr = 0x%lx\n\r"
+- " a1 = 0x%lx,\n\r"
+- " a2 = 0x%lx,\n\r"
+- " prom = 0x%lx,\n\r"
+- " bi_recs = 0x%lx,\n\r",
+- (unsigned long)kernel_entry, a1, a2,
+- (unsigned long)prom, NULL);
+-#endif
++void __attribute__ ((weak)) ft_init(void *dt_blob)
++{
++}
+
+- kernel_entry(a1, a2, prom, NULL);
++/* A buffer that may be edited by tools operating on a zImage binary so as to
++ * edit the command line passed to vmlinux (by setting /chosen/bootargs).
++ * The buffer is put in it's own section so that tools may locate it easier.
++ */
++static char builtin_cmdline[COMMAND_LINE_SIZE]
++ __attribute__((__section__("__builtin_cmdline")));
+
+- printf("Error: Linux kernel returned to zImage bootloader!\n\r");
++static void get_cmdline(char *buf, int size)
++{
++ void *devp;
++ int len = strlen(builtin_cmdline);
+
+- exit();
++ buf[0] = '\0';
++
++ if (len > 0) { /* builtin_cmdline overrides dt's /chosen/bootargs */
++ len = min(len, size-1);
++ strncpy(buf, builtin_cmdline, len);
++ buf[len] = '\0';
++ }
++ else if ((devp = finddevice("/chosen")))
++ getprop(devp, "bootargs", buf, size);
++}
++
++static void set_cmdline(char *buf)
++{
++ void *devp;
++
++ if ((devp = finddevice("/chosen")))
++ setprop(devp, "bootargs", buf, strlen(buf) + 1);
+ }
+
++/* Section where ft can be tacked on after zImage is built */
++union blobspace {
++ struct boot_param_header hdr;
++ char space[8*1024];
++} dt_blob __attribute__((__section__("__builtin_ft")));
++
++struct platform_ops platform_ops;
++struct dt_ops dt_ops;
++struct console_ops console_ops;
++
++void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
++{
++ int have_dt = 0;
++ kernel_entry_t kentry;
++ char cmdline[COMMAND_LINE_SIZE];
++
++ memset(__bss_start, 0, _end - __bss_start);
++ memset(&platform_ops, 0, sizeof(platform_ops));
++ memset(&dt_ops, 0, sizeof(dt_ops));
++ memset(&console_ops, 0, sizeof(console_ops));
++
++ /* Override the dt_ops and device tree if there was an flat dev
++ * tree attached to the zImage.
++ */
++ if (dt_blob.hdr.magic == OF_DT_HEADER) {
++ have_dt = 1;
++ ft_init(&dt_blob);
++ }
++
++ if (platform_init(promptr))
++ exit();
++ if (console_ops.open && (console_ops.open() < 0))
++ exit();
++ if (platform_ops.fixups)
++ platform_ops.fixups();
++
++ printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r",
++ _start, sp);
++
++ prep_kernel(&a1, &a2);
++
++ /* If cmdline came from zimage wrapper or if we can edit the one
++ * in the dt, print it out and edit it, if possible.
++ */
++ if ((strlen(builtin_cmdline) > 0) || console_ops.edit_cmdline) {
++ get_cmdline(cmdline, COMMAND_LINE_SIZE);
++ printf("\n\rLinux/PowerPC load: %s", cmdline);
++ if (console_ops.edit_cmdline)
++ console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
++ printf("\n\r");
++ set_cmdline(cmdline);
++ }
++
++ if (console_ops.close)
++ console_ops.close();
++
++ kentry = (kernel_entry_t) vmlinux.addr;
++ if (have_dt)
++ kentry(dt_ops.ft_addr(), 0, NULL);
++ else
++ /* XXX initrd addr/size should be passed in properties */
++ kentry(a1, a2, promptr);
++
++ /* console closed so printf below may not work */
++ printf("Error: Linux kernel returned to zImage boot wrapper!\n\r");
++ exit();
++}
+diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
+new file mode 100644
+index 0000000..3a71845
+--- /dev/null
++++ b/arch/powerpc/boot/of.c
+@@ -0,0 +1,280 @@
++/*
++ * Copyright (C) Paul Mackerras 1997.
++ *
++ * 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 <stdarg.h>
++#include <stddef.h>
++#include "types.h"
++#include "elf.h"
++#include "string.h"
++#include "stdio.h"
++#include "page.h"
++#include "ops.h"
++
++typedef void *ihandle;
++typedef void *phandle;
++
++extern char _end[];
++
++/* Value picked to match that used by yaboot */
++#define PROG_START 0x01400000 /* only used on 64-bit systems */
++#define RAM_END (512<<20) /* Fixme: use OF */
++#define ONE_MB 0x100000
++
++int (*prom) (void *);
++
++
++static unsigned long claim_base;
++
++static int call_prom(const char *service, int nargs, int nret, ...)
++{
++ int i;
++ struct prom_args {
++ const char *service;
++ int nargs;
++ int nret;
++ unsigned int args[12];
++ } args;
++ va_list list;
++
++ args.service = service;
++ args.nargs = nargs;
++ args.nret = nret;
++
++ va_start(list, nret);
++ for (i = 0; i < nargs; i++)
++ args.args[i] = va_arg(list, unsigned int);
++ va_end(list);
++
++ for (i = 0; i < nret; i++)
++ args.args[nargs+i] = 0;
++
++ if (prom(&args) < 0)
++ return -1;
++
++ return (nret > 0)? args.args[nargs]: 0;
++}
++
++static int call_prom_ret(const char *service, int nargs, int nret,
++ unsigned int *rets, ...)
++{
++ int i;
++ struct prom_args {
++ const char *service;
++ int nargs;
++ int nret;
++ unsigned int args[12];
++ } args;
++ va_list list;
++
++ args.service = service;
++ args.nargs = nargs;
++ args.nret = nret;
++
++ va_start(list, rets);
++ for (i = 0; i < nargs; i++)
++ args.args[i] = va_arg(list, unsigned int);
++ va_end(list);
++
++ for (i = 0; i < nret; i++)
++ args.args[nargs+i] = 0;
++
++ if (prom(&args) < 0)
++ return -1;
++
++ if (rets != (void *) 0)
++ for (i = 1; i < nret; ++i)
++ rets[i-1] = args.args[nargs+i];
++
++ return (nret > 0)? args.args[nargs]: 0;
++}
++
++/*
++ * Older OF's require that when claiming a specific range of addresses,
++ * we claim the physical space in the /memory node and the virtual
++ * space in the chosen mmu node, and then do a map operation to
++ * map virtual to physical.
++ */
++static int need_map = -1;
++static ihandle chosen_mmu;
++static phandle memory;
++
++/* returns true if s2 is a prefix of s1 */
++static int string_match(const char *s1, const char *s2)
++{
++ for (; *s2; ++s2)
++ if (*s1++ != *s2)
++ return 0;
++ return 1;
++}
++
++static int check_of_version(void)
++{
++ phandle oprom, chosen;
++ char version[64];
++
++ oprom = finddevice("/openprom");
++ if (oprom == (phandle) -1)
++ return 0;
++ if (getprop(oprom, "model", version, sizeof(version)) <= 0)
++ return 0;
++ version[sizeof(version)-1] = 0;
++ printf("OF version = '%s'\r\n", version);
++ if (!string_match(version, "Open Firmware, 1.")
++ && !string_match(version, "FirmWorks,3."))
++ return 0;
++ chosen = finddevice("/chosen");
++ if (chosen == (phandle) -1) {
++ chosen = finddevice("/chosen at 0");
++ if (chosen == (phandle) -1) {
++ printf("no chosen\n");
++ return 0;
++ }
++ }
++ if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
++ printf("no mmu\n");
++ return 0;
++ }
++ memory = (ihandle) call_prom("open", 1, 1, "/memory");
++ if (memory == (ihandle) -1) {
++ memory = (ihandle) call_prom("open", 1, 1, "/memory at 0");
++ if (memory == (ihandle) -1) {
++ printf("no memory node\n");
++ return 0;
++ }
++ }
++ printf("old OF detected\r\n");
++ return 1;
++}
++
++static void *claim(unsigned long virt, unsigned long size, unsigned long align)
++{
++ int ret;
++ unsigned int result;
++
++ if (need_map < 0)
++ need_map = check_of_version();
++ if (align || !need_map)
++ return (void *) call_prom("claim", 3, 1, virt, size, align);
++
++ ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
++ align, size, virt);
++ if (ret != 0 || result == -1)
++ return (void *) -1;
++ ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
++ align, size, virt);
++ /* 0x12 == coherent + read/write */
++ ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
++ 0x12, size, virt, virt);
++ return (void *) virt;
++}
++
++static void *of_try_claim(u32 size)
++{
++ unsigned long addr = 0;
++
++ if (claim_base == 0)
++ claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
++
++ for(; claim_base < RAM_END; claim_base += ONE_MB) {
++#ifdef DEBUG
++ printf(" trying: 0x%08lx\n\r", claim_base);
++#endif
++ addr = (unsigned long)claim(claim_base, size, 0);
++ if ((void *)addr != (void *)-1)
++ break;
++ }
++ if (addr == 0)
++ return NULL;
++ claim_base = PAGE_ALIGN(claim_base + size);
++ return (void *)addr;
++}
++
++static void of_image_hdr(const void *hdr)
++{
++ const Elf64_Ehdr *elf64 = hdr;
++
++ if (elf64->e_ident[EI_CLASS] == ELFCLASS64) {
++ /*
++ * Maintain a "magic" minimum address. This keeps some older
++ * firmware platforms running.
++ */
++ if (claim_base < PROG_START)
++ claim_base = PROG_START;
++ }
++}
++
++static void of_exit(void)
++{
++ call_prom("exit", 0, 0);
++}
++
++/*
++ * OF device tree routines
++ */
++static void *of_finddevice(const char *name)
++{
++ return (phandle) call_prom("finddevice", 1, 1, name);
++}
++
++static int of_getprop(const void *phandle, const char *name, void *buf,
++ const int buflen)
++{
++ return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
++}
++
++static int of_setprop(const void *phandle, const char *name, const void *buf,
++ const int buflen)
++{
++ return call_prom("setprop", 4, 1, phandle, name, buf, buflen);
++}
++
++/*
++ * OF console routines
++ */
++static void *of_stdout_handle;
++
++static int of_console_open(void)
++{
++ void *devp;
++
++ if (((devp = finddevice("/chosen")) != NULL)
++ && (getprop(devp, "stdout", &of_stdout_handle,
++ sizeof(of_stdout_handle))
++ == sizeof(of_stdout_handle)))
++ return 0;
++
++ return -1;
++}
++
++static void of_console_write(char *buf, int len)
++{
++ call_prom("write", 3, 1, of_stdout_handle, buf, len);
++}
++
++int platform_init(void *promptr)
++{
++ platform_ops.fixups = NULL;
++ platform_ops.image_hdr = of_image_hdr;
++ platform_ops.malloc = of_try_claim;
++ platform_ops.free = NULL;
++ platform_ops.exit = of_exit;
++
++ dt_ops.finddevice = of_finddevice;
++ dt_ops.getprop = of_getprop;
++ dt_ops.setprop = of_setprop;
++ dt_ops.translate_addr = NULL;
++
++ console_ops.open = of_console_open;
++ console_ops.write = of_console_write;
++ console_ops.edit_cmdline = NULL;
++ console_ops.close = NULL;
++ console_ops.data = NULL;
++
++ prom = (int (*)(void *))promptr;
++ return 0;
++}
+diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
+new file mode 100644
+index 0000000..135eb4b
+--- /dev/null
++++ b/arch/powerpc/boot/ops.h
+@@ -0,0 +1,100 @@
++/*
++ * Global definition of all the bootwrapper operations.
++ *
++ * Author: Mark A. Greer <mgreer at mvista.com>
++ *
++ * 2006 (c) MontaVista Software, Inc. This file is licensed under
++ * the terms of the GNU General Public License version 2. This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++#ifndef _PPC_BOOT_OPS_H_
++#define _PPC_BOOT_OPS_H_
++
++#include "types.h"
++
++#define COMMAND_LINE_SIZE 512
++#define MAX_PATH_LEN 256
++#define MAX_PROP_LEN 256 /* What should this be? */
++
++/* Platform specific operations */
++struct platform_ops {
++ void (*fixups)(void);
++ void (*image_hdr)(const void *);
++ void * (*malloc)(u32 size);
++ void (*free)(void *ptr, u32 size);
++ void (*exit)(void);
++};
++extern struct platform_ops platform_ops;
++
++/* Device Tree operations */
++struct dt_ops {
++ void * (*finddevice)(const char *name);
++ int (*getprop)(const void *node, const char *name, void *buf,
++ const int buflen);
++ int (*setprop)(const void *node, const char *name,
++ const void *buf, const int buflen);
++ u64 (*translate_addr)(const char *path, const u32 *in_addr,
++ const u32 addr_len);
++ unsigned long (*ft_addr)(void);
++};
++extern struct dt_ops dt_ops;
++
++/* Console operations */
++struct console_ops {
++ int (*open)(void);
++ void (*write)(char *buf, int len);
++ void (*edit_cmdline)(char *buf, int len);
++ void (*close)(void);
++ void *data;
++};
++extern struct console_ops console_ops;
++
++/* Serial console operations */
++struct serial_console_data {
++ int (*open)(void);
++ void (*putc)(unsigned char c);
++ unsigned char (*getc)(void);
++ u8 (*tstc)(void);
++ void (*close)(void);
++};
++
++extern int platform_init(void *promptr);
++extern void simple_alloc_init(void);
++extern void ft_init(void *dt_blob);
++extern int serial_console_init(void);
++
++static inline void *finddevice(const char *name)
++{
++ return (dt_ops.finddevice) ? dt_ops.finddevice(name) : NULL;
++}
++
++static inline int getprop(void *devp, const char *name, void *buf, int buflen)
++{
++ return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1;
++}
++
++static inline int setprop(void *devp, const char *name, void *buf, int buflen)
++{
++ return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1;
++}
++
++static inline void *malloc(u32 size)
++{
++ return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL;
++}
++
++static inline void free(void *ptr, u32 size)
++{
++ if (platform_ops.free)
++ platform_ops.free(ptr, size);
++}
++
++static inline void exit(void)
++{
++ if (platform_ops.exit)
++ platform_ops.exit();
++ for(;;);
++}
++
++#endif /* _PPC_BOOT_OPS_H_ */
+diff --git a/arch/powerpc/boot/prom.c b/arch/powerpc/boot/prom.c
+deleted file mode 100644
+index fa00577..0000000
+--- a/arch/powerpc/boot/prom.c
++++ /dev/null
+@@ -1,165 +0,0 @@
+-/*
+- * Copyright (C) Paul Mackerras 1997.
+- *
+- * 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 <stdarg.h>
+-#include <stddef.h>
+-#include "string.h"
+-#include "stdio.h"
+-#include "prom.h"
+-
+-int (*prom)(void *);
+-phandle chosen_handle;
+-ihandle stdout;
+-
+-int call_prom(const char *service, int nargs, int nret, ...)
+-{
+- int i;
+- struct prom_args {
+- const char *service;
+- int nargs;
+- int nret;
+- unsigned int args[12];
+- } args;
+- va_list list;
+-
+- args.service = service;
+- args.nargs = nargs;
+- args.nret = nret;
+-
+- va_start(list, nret);
+- for (i = 0; i < nargs; i++)
+- args.args[i] = va_arg(list, unsigned int);
+- va_end(list);
+-
+- for (i = 0; i < nret; i++)
+- args.args[nargs+i] = 0;
+-
+- if (prom(&args) < 0)
+- return -1;
+-
+- return (nret > 0)? args.args[nargs]: 0;
+-}
+-
+-int call_prom_ret(const char *service, int nargs, int nret,
+- unsigned int *rets, ...)
+-{
+- int i;
+- struct prom_args {
+- const char *service;
+- int nargs;
+- int nret;
+- unsigned int args[12];
+- } args;
+- va_list list;
+-
+- args.service = service;
+- args.nargs = nargs;
+- args.nret = nret;
+-
+- va_start(list, rets);
+- for (i = 0; i < nargs; i++)
+- args.args[i] = va_arg(list, unsigned int);
+- va_end(list);
+-
+- for (i = 0; i < nret; i++)
+- args.args[nargs+i] = 0;
+-
+- if (prom(&args) < 0)
+- return -1;
+-
+- if (rets != (void *) 0)
+- for (i = 1; i < nret; ++i)
+- rets[i-1] = args.args[nargs+i];
+-
+- return (nret > 0)? args.args[nargs]: 0;
+-}
+-
+-int write(void *handle, void *ptr, int nb)
+-{
+- return call_prom("write", 3, 1, handle, ptr, nb);
+-}
+-
+-/*
+- * Older OF's require that when claiming a specific range of addresses,
+- * we claim the physical space in the /memory node and the virtual
+- * space in the chosen mmu node, and then do a map operation to
+- * map virtual to physical.
+- */
+-static int need_map = -1;
+-static ihandle chosen_mmu;
+-static phandle memory;
+-
+-/* returns true if s2 is a prefix of s1 */
+-static int string_match(const char *s1, const char *s2)
+-{
+- for (; *s2; ++s2)
+- if (*s1++ != *s2)
+- return 0;
+- return 1;
+-}
+-
+-static int check_of_version(void)
+-{
+- phandle oprom, chosen;
+- char version[64];
+-
+- oprom = finddevice("/openprom");
+- if (oprom == (phandle) -1)
+- return 0;
+- if (getprop(oprom, "model", version, sizeof(version)) <= 0)
+- return 0;
+- version[sizeof(version)-1] = 0;
+- printf("OF version = '%s'\r\n", version);
+- if (!string_match(version, "Open Firmware, 1.")
+- && !string_match(version, "FirmWorks,3."))
+- return 0;
+- chosen = finddevice("/chosen");
+- if (chosen == (phandle) -1) {
+- chosen = finddevice("/chosen at 0");
+- if (chosen == (phandle) -1) {
+- printf("no chosen\n");
+- return 0;
+- }
+- }
+- if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+- printf("no mmu\n");
+- return 0;
+- }
+- memory = (ihandle) call_prom("open", 1, 1, "/memory");
+- if (memory == (ihandle) -1) {
+- memory = (ihandle) call_prom("open", 1, 1, "/memory at 0");
+- if (memory == (ihandle) -1) {
+- printf("no memory node\n");
+- return 0;
+- }
+- }
+- printf("old OF detected\r\n");
+- return 1;
+-}
+-
+-void *claim(unsigned long virt, unsigned long size, unsigned long align)
+-{
+- int ret;
+- unsigned int result;
+-
+- if (need_map < 0)
+- need_map = check_of_version();
+- if (align || !need_map)
+- return (void *) call_prom("claim", 3, 1, virt, size, align);
+-
+- ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
+- align, size, virt);
+- if (ret != 0 || result == -1)
+- return (void *) -1;
+- ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
+- align, size, virt);
+- /* 0x12 == coherent + read/write */
+- ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
+- 0x12, size, virt, virt);
+- return (void *) virt;
+-}
+diff --git a/arch/powerpc/boot/prom.h b/arch/powerpc/boot/prom.h
+deleted file mode 100644
+index a57b184..0000000
+--- a/arch/powerpc/boot/prom.h
++++ /dev/null
+@@ -1,41 +0,0 @@
+-#ifndef _PPC_BOOT_PROM_H_
+-#define _PPC_BOOT_PROM_H_
+-
+-typedef void *phandle;
+-typedef void *ihandle;
+-
+-extern int (*prom) (void *);
+-extern phandle chosen_handle;
+-extern ihandle stdout;
+-
+-int call_prom(const char *service, int nargs, int nret, ...);
+-int call_prom_ret(const char *service, int nargs, int nret,
+- unsigned int *rets, ...);
+-
+-extern int write(void *handle, void *ptr, int nb);
+-extern void *claim(unsigned long virt, unsigned long size, unsigned long aln);
+-
+-static inline void exit(void)
+-{
+- call_prom("exit", 0, 0);
+-}
+-
+-static inline phandle finddevice(const char *name)
+-{
+- return (phandle) call_prom("finddevice", 1, 1, name);
+-}
+-
+-static inline int getprop(void *phandle, const char *name,
+- void *buf, int buflen)
+-{
+- return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
+-}
+-
+-
+-static inline int setprop(void *phandle, const char *name,
+- void *buf, int buflen)
+-{
+- return call_prom("setprop", 4, 1, phandle, name, buf, buflen);
+-}
+-
+-#endif /* _PPC_BOOT_PROM_H_ */
+diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
+index b5aa522..6d5f638 100644
+--- a/arch/powerpc/boot/stdio.c
++++ b/arch/powerpc/boot/stdio.c
+@@ -10,7 +10,7 @@
+ #include <stddef.h>
+ #include "string.h"
+ #include "stdio.h"
+-#include "prom.h"
++#include "ops.h"
+
+ size_t strnlen(const char * s, size_t count)
+ {
+@@ -320,6 +320,6 @@ printf(const char *fmt, ...)
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+- write(stdout, sprint_buf, n);
++ console_ops.write(sprint_buf, n);
+ return n;
+ }
+diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
+index eb9e16c..73b8a91 100644
+--- a/arch/powerpc/boot/stdio.h
++++ b/arch/powerpc/boot/stdio.h
+@@ -1,8 +1,16 @@
+ #ifndef _PPC_BOOT_STDIO_H_
+ #define _PPC_BOOT_STDIO_H_
+
++#include <stdarg.h>
++
++#define ENOMEM 12 /* Out of Memory */
++#define EINVAL 22 /* Invalid argument */
++#define ENOSPC 28 /* No space left on device */
++
+ extern int printf(const char *fmt, ...);
+
++#define fprintf(fmt, args...) printf(args)
++
+ extern int sprintf(char *buf, const char *fmt, ...);
+
+ extern int vsprintf(char *buf, const char *fmt, va_list args);
+diff --git a/arch/powerpc/boot/types.h b/arch/powerpc/boot/types.h
+new file mode 100644
+index 0000000..79d26e7
+--- /dev/null
++++ b/arch/powerpc/boot/types.h
+@@ -0,0 +1,23 @@
++#ifndef _TYPES_H_
++#define _TYPES_H_
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++typedef unsigned char u8;
++typedef unsigned short u16;
++typedef unsigned int u32;
++typedef unsigned long long u64;
++
++#define min(x,y) ({ \
++ typeof(x) _x = (x); \
++ typeof(y) _y = (y); \
++ (void) (&_x == &_y); \
++ _x < _y ? _x : _y; })
++
++#define max(x,y) ({ \
++ typeof(x) _x = (x); \
++ typeof(y) _y = (y); \
++ (void) (&_x == &_y); \
++ _x > _y ? _x : _y; })
++
++#endif /* _TYPES_H_ */
+diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
+new file mode 100755
+index 0000000..eab7318
+--- /dev/null
++++ b/arch/powerpc/boot/wrapper
+@@ -0,0 +1,204 @@
++#!/bin/sh
++
++# Copyright (C) 2006 Paul Mackerras, IBM Corporation <paulus at samba.org>
++# This program may be used under the terms of version 2 of the GNU
++# General Public License.
++
++# This script takes a kernel binary and optionally an initrd image
++# and/or a device-tree blob, and creates a bootable zImage for a
++# given platform.
++
++# Options:
++# -o zImage specify output file
++# -p platform specify platform (links in $platform.o)
++# -i initrd specify initrd file
++# -d devtree specify device-tree blob
++# -s tree.dts specify device-tree source file (needs dtc installed)
++# -c cache $kernel.strip.gz (use if present & newer, else make)
++# -C prefix specify command prefix for cross-building tools
++# (strip, objcopy, ld)
++# -D dir specify directory containing data files used by script
++# (default ./arch/powerpc/boot)
++# -W dir specify working directory for temporary files (default .)
++
++# defaults
++kernel=
++ofile=zImage
++platform=of
++initrd=
++dtb=
++dts=
++cacheit=
++
++# cross-compilation prefix
++CROSS=
++
++# directory for object and other files used by this script
++object=arch/powerpc/boot
++
++# directory for working files
++tmpdir=.
++
++usage() {
++ echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2
++ echo ' [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2
++ echo ' [-D datadir] [-W workingdir] [vmlinux]' >&2
++ exit 1
++}
++
++while [ "$#" -gt 0 ]; do
++ case "$1" in
++ -o)
++ shift
++ [ "$#" -gt 0 ] || usage
++ ofile="$1"
++ ;;
++ -p)
++ shift
++ [ "$#" -gt 0 ] || usage
++ platform="$1"
++ ;;
++ -i)
++ shift
++ [ "$#" -gt 0 ] || usage
++ initrd="$1"
++ ;;
++ -d)
++ shift
++ [ "$#" -gt 0 ] || usage
++ dtb="$1"
++ ;;
++ -s)
++ shift
++ [ "$#" -gt 0 ] || usage
++ dts="$1"
++ ;;
++ -c)
++ cacheit=y
++ ;;
++ -C)
++ shift
++ [ "$#" -gt 0 ] || usage
++ CROSS="$1"
++ ;;
++ -D)
++ shift
++ [ "$#" -gt 0 ] || usage
++ object="$1"
++ ;;
++ -W)
++ shift
++ [ "$#" -gt 0 ] || usage
++ tmpdir="$1"
++ ;;
++ -?)
++ usage
++ ;;
++ *)
++ [ -z "$kernel" ] || usage
++ kernel="$1"
++ ;;
++ esac
++ shift
++done
++
++if [ -n "$dts" ]; then
++ if [ -z "$dtb" ]; then
++ dtb="$platform.dtb"
++ fi
++ dtc -O dtb -o "$dtb" -b 0 -V 16 "$dts" || exit 1
++fi
++
++if [ -z "$kernel" ]; then
++ kernel=vmlinux
++fi
++
++platformo=$object/"$platform".o
++lds=$object/zImage.lds
++ext=strip
++objflags=-S
++tmp=$tmpdir/zImage.$$.o
++ksection=.kernel:vmlinux.strip
++isection=.kernel:initrd
++
++case "$platform" in
++pmac|pseries|chrp)
++ platformo=$object/of.o
++ ;;
++pmaccoff)
++ platformo=$object/of.o
++ lds=$object/zImage.coff.lds
++ ;;
++miboot|uboot)
++ # miboot and U-boot want just the bare bits, not an ELF binary
++ ext=bin
++ objflags="-O binary"
++ tmp="$ofile"
++ ksection=image
++ isection=initrd
++ ;;
++esac
++
++vmz="$tmpdir/`basename \"$kernel\"`.$ext"
++if [ -z "$cacheit" -o ! -f "$vmz.gz" -o "$vmz.gz" -ot "$kernel" ]; then
++ ${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
++ gzip -f -9 "$vmz.$$"
++ if [ -n "$cacheit" ]; then
++ mv -f "$vmz.$$.gz" "$vmz.gz"
++ else
++ vmz="$vmz.$$"
++ fi
++fi
++
++case "$platform" in
++uboot)
++ rm -f "$ofile"
++ version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
++ cut -d' ' -f3`
++ if [ -n "$version" ]; then
++ version="-n Linux-$version"
++ fi
++ mkimage -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \
++ $version -d "$vmz.gz" "$ofile"
++ if [ -z "$cacheit" ]; then
++ rm -f $vmz.gz
++ fi
++ exit 0
++ ;;
++esac
++
++addsec() {
++ ${CROSS}objcopy $4 $1 \
++ --add-section=$3="$2" \
++ --set-section-flags=$3=contents,alloc,load,readonly,data
++}
++
++addsec $tmp "$vmz.gz" $ksection $object/empty.o
++if [ -z "$cacheit" ]; then
++ rm -f "$vmz.gz"
++fi
++
++if [ -n "$initrd" ]; then
++ addsec $tmp "$initrd" initrd
++fi
++
++if [ -n "$dtb" ]; then
++ addsec $tmp "$dtb" dtb
++fi
++
++if [ "$platform" != "miboot" ]; then
++ ${CROSS}ld -m elf32ppc -T $lds -o "$ofile" \
++ $object/crt0.o $platformo $tmp $object/wrapper.a
++ rm $tmp
++fi
++
++# post-processing needed for some platforms
++case "$platform" in
++pseries|chrp)
++ $object/addnote "$ofile"
++ ;;
++pmaccoff)
++ ${CROSS}objcopy -O aixcoff-rs6000 --set-start 0x500000 "$ofile"
++ $object/hack-coff "$ofile"
++ ;;
++esac
+diff --git a/arch/powerpc/boot/zImage.coff.lds b/arch/powerpc/boot/zImage.coff.lds
+deleted file mode 100644
+index 6016251..0000000
+--- a/arch/powerpc/boot/zImage.coff.lds
++++ /dev/null
+@@ -1,46 +0,0 @@
+-OUTPUT_ARCH(powerpc:common)
+-ENTRY(_start)
+-SECTIONS
+-{
+- . = (5*1024*1024);
+- _start = .;
+- .text :
+- {
+- *(.text)
+- *(.fixup)
+- }
+- _etext = .;
+- . = ALIGN(4096);
+- .data :
+- {
+- *(.rodata*)
+- *(.data*)
+- *(.sdata*)
+- __got2_start = .;
+- *(.got2)
+- __got2_end = .;
+-
+- _vmlinux_start = .;
+- *(.kernel:vmlinux.strip)
+- _vmlinux_end = .;
+-
+- _initrd_start = .;
+- *(.kernel:initrd)
+- _initrd_end = .;
+- }
+-
+- . = ALIGN(4096);
+- _edata = .;
+- __bss_start = .;
+- .bss :
+- {
+- *(.sbss)
+- *(.bss)
+- }
+- _end = . ;
+-
+- /DISCARD/ :
+- {
+- *(.comment)
+- }
+-}
+diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S
+new file mode 100644
+index 0000000..05f3238
+--- /dev/null
++++ b/arch/powerpc/boot/zImage.coff.lds.S
+@@ -0,0 +1,47 @@
++OUTPUT_ARCH(powerpc:common)
++ENTRY(_start)
++SECTIONS
++{
++ . = (5*1024*1024);
++ _start = .;
++ .text :
++ {
++ *(.text)
++ *(.fixup)
++ }
++ _etext = .;
++ . = ALIGN(4096);
++ .data :
++ {
++ *(.rodata*)
++ *(.data*)
++ *(__builtin_*)
++ *(.sdata*)
++ __got2_start = .;
++ *(.got2)
++ __got2_end = .;
++
++ _vmlinux_start = .;
++ *(.kernel:vmlinux.strip)
++ _vmlinux_end = .;
++
++ _initrd_start = .;
++ *(.kernel:initrd)
++ _initrd_end = .;
++ }
++
++ . = ALIGN(4096);
++ _edata = .;
++ __bss_start = .;
++ .bss :
++ {
++ *(.sbss)
++ *(.bss)
++ }
++ _end = . ;
++
++ /DISCARD/ :
++ {
++ *(.comment)
++ }
++}
+diff --git a/arch/powerpc/boot/zImage.lds b/arch/powerpc/boot/zImage.lds
+deleted file mode 100644
+index 4b6bb3f..0000000
+--- a/arch/powerpc/boot/zImage.lds
++++ /dev/null
+@@ -1,46 +0,0 @@
+-OUTPUT_ARCH(powerpc:common)
+-ENTRY(_zimage_start)
+-SECTIONS
+-{
+- . = (4*1024*1024);
+- _start = .;
+- .text :
+- {
+- *(.text)
+- *(.fixup)
+- }
+- _etext = .;
+- . = ALIGN(4096);
+- .data :
+- {
+- *(.rodata*)
+- *(.data*)
+- *(.sdata*)
+- __got2_start = .;
+- *(.got2)
+- __got2_end = .;
+- }
+-
+- . = ALIGN(4096);
+- _vmlinux_start = .;
+- .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
+- _vmlinux_end = .;
+-
+- . = ALIGN(4096);
+- _initrd_start = .;
+- .kernel:initrd : { *(.kernel:initrd) }
+- _initrd_end = .;
+-
+- . = ALIGN(4096);
+- _edata = .;
+-
+- . = ALIGN(4096);
+- __bss_start = .;
+- .bss :
+- {
+- *(.sbss)
+- *(.bss)
+- }
+- . = ALIGN(4096);
+- _end = . ;
+-}
+diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
+new file mode 100644
+index 0000000..4b6bb3f
+--- /dev/null
++++ b/arch/powerpc/boot/zImage.lds.S
+@@ -0,0 +1,46 @@
++OUTPUT_ARCH(powerpc:common)
++ENTRY(_zimage_start)
++SECTIONS
++{
++ . = (4*1024*1024);
++ _start = .;
++ .text :
++ {
++ *(.text)
++ *(.fixup)
++ }
++ _etext = .;
++ . = ALIGN(4096);
++ .data :
++ {
++ *(.rodata*)
++ *(.data*)
++ *(.sdata*)
++ __got2_start = .;
++ *(.got2)
++ __got2_end = .;
++ }
++
++ . = ALIGN(4096);
++ _vmlinux_start = .;
++ .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
++ _vmlinux_end = .;
++
++ . = ALIGN(4096);
++ _initrd_start = .;
++ .kernel:initrd : { *(.kernel:initrd) }
++ _initrd_end = .;
++
++ . = ALIGN(4096);
++ _edata = .;
++
++ . = ALIGN(4096);
++ __bss_start = .;
++ .bss :
++ {
++ *(.sbss)
++ *(.bss)
++ }
++ . = ALIGN(4096);
++ _end = . ;
++}
+diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
+index 6fd9e7a..0aba06d 100644
+--- a/arch/powerpc/configs/cell_defconfig
++++ b/arch/powerpc/configs/cell_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc6
+-# Sun Sep 10 10:20:32 2006
++# Linux kernel version: 2.6.18
++# Wed Oct 4 15:30:50 2006
+ #
+ CONFIG_PPC64=y
+ CONFIG_64BIT=y
+@@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+ CONFIG_PPC_OF=y
+ CONFIG_PPC_UDBG_16550=y
+ # CONFIG_GENERIC_TBSYNC is not set
++CONFIG_AUDIT_ARCH=y
+ # CONFIG_DEFAULT_UIMAGE is not set
+
+ #
+@@ -52,10 +53,11 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+@@ -63,7 +65,9 @@ CONFIG_CPUSETS=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -72,12 +76,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -96,6 +100,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -115,12 +120,13 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ # Platform support
+ #
+ CONFIG_PPC_MULTIPLATFORM=y
+-# CONFIG_PPC_ISERIES is not set
+ # CONFIG_EMBEDDED6xx is not set
+ # CONFIG_APUS is not set
+ # CONFIG_PPC_PSERIES is not set
++# CONFIG_PPC_ISERIES is not set
+ # CONFIG_PPC_PMAC is not set
+ # CONFIG_PPC_MAPLE is not set
++# CONFIG_PPC_PASEMI is not set
+ CONFIG_PPC_CELL=y
+ CONFIG_PPC_CELL_NATIVE=y
+ CONFIG_PPC_IBM_CELL_BLADE=y
+@@ -142,7 +148,6 @@ CONFIG_MMIO_NVRAM=y
+ #
+ CONFIG_SPU_FS=m
+ CONFIG_SPU_BASE=y
+-CONFIG_SPUFS_MMAP=y
+ CONFIG_CBE_RAS=y
+
+ #
+@@ -158,7 +163,7 @@ CONFIG_PREEMPT_NONE=y
+ CONFIG_PREEMPT_BKL=y
+ CONFIG_BINFMT_ELF=y
+ CONFIG_BINFMT_MISC=m
+-CONFIG_FORCE_MAX_ZONEORDER=13
++CONFIG_FORCE_MAX_ZONEORDER=9
+ # CONFIG_IOMMU_VMERGE is not set
+ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+ CONFIG_KEXEC=y
+@@ -168,6 +173,7 @@ CONFIG_NUMA=y
+ CONFIG_NODES_SHIFT=4
+ CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+ CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_POPULATES_NODE_MAP=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+ # CONFIG_FLATMEM_MANUAL is not set
+ # CONFIG_DISCONTIGMEM_MANUAL is not set
+@@ -178,12 +184,12 @@ CONFIG_HAVE_MEMORY_PRESENT=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPARSEMEM_EXTREME=y
+ CONFIG_MEMORY_HOTPLUG=y
++CONFIG_MEMORY_HOTPLUG_SPARSE=y
+ CONFIG_SPLIT_PTLOCK_CPUS=4
+ CONFIG_MIGRATION=y
+ CONFIG_RESOURCES_64BIT=y
+-CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+ CONFIG_ARCH_MEMORY_PROBE=y
+-# CONFIG_PPC_64K_PAGES is not set
++CONFIG_PPC_64K_PAGES=y
+ CONFIG_SCHED_SMT=y
+ CONFIG_PROC_DEVICETREE=y
+ # CONFIG_CMDLINE_BOOL is not set
+@@ -201,6 +207,7 @@ CONFIG_GENERIC_ISA_DMA=y
+ CONFIG_PCI=y
+ CONFIG_PCI_DOMAINS=y
+ CONFIG_PCIEPORTBUS=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ # CONFIG_PCI_DEBUG is not set
+
+ #
+@@ -228,6 +235,7 @@ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -246,10 +254,12 @@ CONFIG_SYN_COOKIES=y
+ CONFIG_INET_TUNNEL=y
+ CONFIG_INET_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET_XFRM_MODE_TUNNEL=y
++# CONFIG_INET_XFRM_MODE_BEET is not set
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+
+ #
+ # IP: Virtual Server Configuration
+@@ -261,11 +271,17 @@ CONFIG_IPV6=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
++# CONFIG_IPV6_MIP6 is not set
+ CONFIG_INET6_XFRM_TUNNEL=m
+ CONFIG_INET6_TUNNEL=m
+ CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET6_XFRM_MODE_TUNNEL=y
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++# CONFIG_IPV6_SIT is not set
+ CONFIG_IPV6_TUNNEL=m
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
+ # CONFIG_NETWORK_SECMARK is not set
+ CONFIG_NETFILTER=y
+ # CONFIG_NETFILTER_DEBUG is not set
+@@ -322,7 +338,6 @@ CONFIG_IP_NF_QUEUE=m
+ # 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
+
+@@ -394,6 +409,12 @@ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_ATA_OVER_ETH is not set
+
+ #
++# Misc devices
++#
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
+@@ -434,6 +455,7 @@ CONFIG_BLK_DEV_AEC62XX=y
+ # CONFIG_BLK_DEV_CS5530 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+ # CONFIG_BLK_DEV_PIIX is not set
+ # CONFIG_BLK_DEV_IT821X is not set
+@@ -456,6 +478,12 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -470,6 +498,7 @@ CONFIG_MD_RAID1=m
+ # CONFIG_MD_MULTIPATH is not set
+ # CONFIG_MD_FAULTY is not set
+ CONFIG_BLK_DEV_DM=m
++# CONFIG_DM_DEBUG is not set
+ CONFIG_DM_CRYPT=m
+ CONFIG_DM_SNAPSHOT=m
+ CONFIG_DM_MIRROR=m
+@@ -504,7 +533,7 @@ CONFIG_NETDEVICES=y
+ # CONFIG_DUMMY is not set
+ CONFIG_BONDING=y
+ # CONFIG_EQUALIZER is not set
+-# CONFIG_TUN is not set
++CONFIG_TUN=y
+
+ #
+ # ARCnet devices
+@@ -552,7 +581,7 @@ CONFIG_SKGE=m
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
+ CONFIG_SPIDER_NET=m
+-# CONFIG_MV643XX_ETH is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -599,6 +628,7 @@ CONFIG_SPIDER_NET=m
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -717,7 +747,6 @@ CONFIG_GEN_RTC=y
+ # TPM devices
+ #
+ # CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+
+ #
+ # I2C support
+@@ -781,6 +810,7 @@ CONFIG_I2C_ALGOBIT=y
+ #
+ # Dallas's 1-wire bus
+ #
++# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -789,14 +819,9 @@ CONFIG_I2C_ALGOBIT=y
+ # CONFIG_HWMON_VID is not set
+
+ #
+-# Misc devices
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -865,6 +890,7 @@ CONFIG_INFINIBAND_USER_ACCESS=m
+ CONFIG_INFINIBAND_ADDR_TRANS=y
+ CONFIG_INFINIBAND_MTHCA=m
+ CONFIG_INFINIBAND_MTHCA_DEBUG=y
++# CONFIG_INFINIBAND_AMSO1100 is not set
+ CONFIG_INFINIBAND_IPOIB=m
+ CONFIG_INFINIBAND_IPOIB_DEBUG=y
+ CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
+@@ -901,6 +927,7 @@ 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_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+@@ -908,6 +935,7 @@ CONFIG_FS_MBCACHE=y
+ # CONFIG_JFS_FS is not set
+ CONFIG_FS_POSIX_ACL=y
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -916,7 +944,7 @@ CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
++CONFIG_AUTOFS4_FS=m
+ # CONFIG_FUSE_FS is not set
+
+ #
+@@ -943,8 +971,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+@@ -1084,6 +1114,7 @@ CONFIG_PLIST=y
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+@@ -1102,7 +1133,9 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
+ # CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ # CONFIG_FORCED_INLINING is not set
++# CONFIG_HEADERS_CHECK is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
+ # CONFIG_DEBUG_STACKOVERFLOW is not set
+ # CONFIG_DEBUG_STACK_USAGE is not set
+@@ -1123,6 +1156,10 @@ CONFIG_IRQSTACKS=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++# CONFIG_CRYPTO_MANAGER is not set
+ CONFIG_CRYPTO_HMAC=y
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -1132,6 +1169,8 @@ CONFIG_CRYPTO_SHA1=m
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=m
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+diff --git a/arch/powerpc/configs/chrp32_defconfig b/arch/powerpc/configs/chrp32_defconfig
+index bbf2b5f..fee72f8 100644
+--- a/arch/powerpc/configs/chrp32_defconfig
++++ b/arch/powerpc/configs/chrp32_defconfig
+@@ -492,7 +492,7 @@ CONFIG_SCSI_SPI_ATTRS=y
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
++# CONFIG_ATA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
+index 4b9c2ed..92d0a9d 100644
+--- a/arch/powerpc/configs/g5_defconfig
++++ b/arch/powerpc/configs/g5_defconfig
+@@ -490,23 +490,23 @@ CONFIG_SCSI_SPI_ATTRS=y
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-CONFIG_SCSI_SATA=y
+-# CONFIG_SCSI_SATA_AHCI is not set
+-CONFIG_SCSI_SATA_SVW=y
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++CONFIG_SATA_SVW=y
+ # CONFIG_SCSI_ATA_PIIX is not set
+-# CONFIG_SCSI_SATA_MV is not set
+-# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
+ # CONFIG_SCSI_PDC_ADMA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+-# CONFIG_SCSI_SATA_QSTOR is not set
+-# CONFIG_SCSI_SATA_PROMISE is not set
+-# CONFIG_SCSI_SATA_SX4 is not set
+-# CONFIG_SCSI_SATA_SIL is not set
+-# CONFIG_SCSI_SATA_SIL24 is not set
+-# CONFIG_SCSI_SATA_SIS is not set
+-# CONFIG_SCSI_SATA_ULI is not set
+-# CONFIG_SCSI_SATA_VIA is not set
+-# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++# CONFIG_SATA_SIL is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_EATA is not set
+diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig
+index eb0885e..b500550 100644
+--- a/arch/powerpc/configs/iseries_defconfig
++++ b/arch/powerpc/configs/iseries_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc6
+-# Sun Sep 10 10:22:57 2006
++# Linux kernel version: 2.6.19-rc1
++# Fri Oct 6 13:25:04 2006
+ #
+ CONFIG_PPC64=y
+ CONFIG_64BIT=y
+@@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+ CONFIG_PPC_OF=y
+ # CONFIG_PPC_UDBG_16550 is not set
+ # CONFIG_GENERIC_TBSYNC is not set
++CONFIG_AUDIT_ARCH=y
+ # CONFIG_DEFAULT_UIMAGE is not set
+
+ #
+@@ -52,10 +53,11 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
++# CONFIG_UTS_NS is not set
+ CONFIG_AUDIT=y
+ CONFIG_AUDITSYSCALL=y
+ CONFIG_IKCONFIG=y
+@@ -64,7 +66,9 @@ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -73,12 +77,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -97,6 +101,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -115,13 +120,18 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ #
+ # Platform support
+ #
+-# CONFIG_PPC_MULTIPLATFORM is not set
+-CONFIG_PPC_ISERIES=y
++CONFIG_PPC_MULTIPLATFORM=y
+ # CONFIG_EMBEDDED6xx is not set
+ # CONFIG_APUS is not set
++# CONFIG_PPC_PSERIES is not set
++CONFIG_PPC_ISERIES=y
++# CONFIG_PPC_PMAC is not set
++# CONFIG_PPC_MAPLE is not set
++# CONFIG_PPC_PASEMI is not set
+ # CONFIG_PPC_CELL is not set
+ # CONFIG_PPC_CELL_NATIVE is not set
+-# CONFIG_UDBG_RTAS_CONSOLE is not set
++# CONFIG_PPC_IBM_CELL_BLADE is not set
++# CONFIG_U3_DART is not set
+ # CONFIG_PPC_RTAS is not set
+ # CONFIG_MMIO_NVRAM is not set
+ CONFIG_IBMVIO=y
+@@ -147,12 +157,15 @@ CONFIG_BINFMT_ELF=y
+ CONFIG_FORCE_MAX_ZONEORDER=13
+ CONFIG_IOMMU_VMERGE=y
+ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
+ CONFIG_IRQ_ALL_CPUS=y
+ CONFIG_LPARCFG=y
+ # CONFIG_NUMA is not set
+ CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_POPULATES_NODE_MAP=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+ CONFIG_FLATMEM_MANUAL=y
+ # CONFIG_DISCONTIGMEM_MANUAL is not set
+@@ -179,6 +192,7 @@ CONFIG_GENERIC_ISA_DMA=y
+ CONFIG_PCI=y
+ CONFIG_PCI_DOMAINS=y
+ # CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ # CONFIG_PCI_DEBUG is not set
+
+ #
+@@ -206,6 +220,7 @@ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ CONFIG_XFRM_USER=m
++CONFIG_XFRM_SUB_POLICY=y
+ CONFIG_NET_KEY=m
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -224,10 +239,12 @@ CONFIG_INET_XFRM_TUNNEL=m
+ CONFIG_INET_TUNNEL=y
+ CONFIG_INET_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=m
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+
+ #
+ # IP: Virtual Server Configuration
+@@ -247,6 +264,7 @@ CONFIG_NETFILTER=y
+ CONFIG_NETFILTER_XTABLES=m
+ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+ CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++CONFIG_NETFILTER_XT_TARGET_DSCP=m
+ CONFIG_NETFILTER_XT_TARGET_MARK=m
+ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+ CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+@@ -255,6 +273,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+ CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+ CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+ # CONFIG_NETFILTER_XT_MATCH_DCCP is not set
++CONFIG_NETFILTER_XT_MATCH_DSCP=m
+ # CONFIG_NETFILTER_XT_MATCH_ESP is not set
+ CONFIG_NETFILTER_XT_MATCH_HELPER=m
+ CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+@@ -294,7 +313,6 @@ CONFIG_IP_NF_MATCH_IPRANGE=m
+ CONFIG_IP_NF_MATCH_TOS=m
+ CONFIG_IP_NF_MATCH_RECENT=m
+ CONFIG_IP_NF_MATCH_ECN=m
+-CONFIG_IP_NF_MATCH_DSCP=m
+ # CONFIG_IP_NF_MATCH_AH is not set
+ CONFIG_IP_NF_MATCH_TTL=m
+ CONFIG_IP_NF_MATCH_OWNER=m
+@@ -319,7 +337,6 @@ CONFIG_IP_NF_NAT_AMANDA=m
+ CONFIG_IP_NF_MANGLE=m
+ CONFIG_IP_NF_TARGET_TOS=m
+ CONFIG_IP_NF_TARGET_ECN=m
+-CONFIG_IP_NF_TARGET_DSCP=m
+ CONFIG_IP_NF_TARGET_TTL=m
+ CONFIG_IP_NF_TARGET_CLUSTERIP=m
+ CONFIG_IP_NF_RAW=m
+@@ -351,7 +368,6 @@ CONFIG_LLC=y
+ # 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
+
+@@ -433,6 +449,7 @@ CONFIG_BLK_DEV_INITRD=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -454,12 +471,14 @@ CONFIG_SCSI_CONSTANTS=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=y
+ CONFIG_SCSI_FC_ATTRS=y
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+-# CONFIG_SCSI_SAS_ATTRS is not set
++CONFIG_SCSI_SAS_ATTRS=m
++CONFIG_SCSI_SAS_LIBSAS=m
++CONFIG_SCSI_SAS_LIBSAS_DEBUG=y
+
+ #
+ # SCSI low-level drivers
+@@ -472,10 +491,11 @@ CONFIG_SCSI_FC_ATTRS=y
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+@@ -486,16 +506,22 @@ CONFIG_SCSI_FC_ATTRS=y
+ CONFIG_SCSI_IBMVSCSI=m
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI 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
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ CONFIG_MD=y
+@@ -508,6 +534,7 @@ CONFIG_MD_RAID10=m
+ CONFIG_MD_MULTIPATH=m
+ CONFIG_MD_FAULTY=m
+ CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
+ CONFIG_DM_CRYPT=m
+ CONFIG_DM_SNAPSHOT=m
+ CONFIG_DM_MIRROR=m
+@@ -573,6 +600,7 @@ CONFIG_MII=y
+ # CONFIG_HP100 is not set
+ CONFIG_NET_PCI=y
+ CONFIG_PCNET32=y
++CONFIG_PCNET32_NAPI=y
+ # CONFIG_AMD8111_ETH is not set
+ # CONFIG_ADAPTEC_STARFIRE is not set
+ # CONFIG_B44 is not set
+@@ -610,6 +638,7 @@ CONFIG_E1000=m
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -649,6 +678,7 @@ CONFIG_PPP_BSDCOMP=m
+ # CONFIG_PPP_MPPE is not set
+ CONFIG_PPPOE=m
+ # CONFIG_SLIP is not set
++CONFIG_SLHC=m
+ # CONFIG_NET_FC is not set
+ # CONFIG_SHAPER is not set
+ CONFIG_NETCONSOLE=y
+@@ -671,6 +701,7 @@ CONFIG_NET_POLL_CONTROLLER=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -774,12 +805,12 @@ CONFIG_MAX_RAW_DEVS=256
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -893,6 +924,9 @@ CONFIG_XFS_FS=m
+ CONFIG_XFS_SECURITY=y
+ CONFIG_XFS_POSIX_ACL=y
+ # CONFIG_XFS_RT is not set
++CONFIG_GFS2_FS=m
++CONFIG_GFS2_FS_LOCKING_NOLOCK=m
++CONFIG_GFS2_FS_LOCKING_DLM=m
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -929,12 +963,14 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_CONFIGFS_FS is not set
++CONFIG_CONFIGFS_FS=m
+
+ #
+ # Miscellaneous filesystems
+@@ -988,6 +1024,7 @@ CONFIG_CIFS_POSIX=y
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+ # CONFIG_9P_FS is not set
++CONFIG_GENERIC_ACL=y
+
+ #
+ # Partition Types
+@@ -1040,6 +1077,12 @@ CONFIG_NLS_ISO8859_1=y
+ # CONFIG_NLS_UTF8 is not set
+
+ #
++# Distributed Lock Manager
++#
++CONFIG_DLM=m
++# CONFIG_DLM_DEBUG is not set
++
++#
+ # iSeries device drivers
+ #
+ CONFIG_VIOCONS=y
+@@ -1073,6 +1116,7 @@ CONFIG_PLIST=y
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+@@ -1091,6 +1135,7 @@ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ # CONFIG_FORCED_INLINING is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_DEBUG_STACKOVERFLOW=y
+@@ -1109,6 +1154,10 @@ CONFIG_IRQSTACKS=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ CONFIG_CRYPTO_NULL=m
+ CONFIG_CRYPTO_MD4=m
+@@ -1118,9 +1167,12 @@ CONFIG_CRYPTO_SHA256=m
+ CONFIG_CRYPTO_SHA512=m
+ CONFIG_CRYPTO_WP512=m
+ CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=y
+ CONFIG_CRYPTO_BLOWFISH=m
+ CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
+ CONFIG_CRYPTO_SERPENT=m
+ CONFIG_CRYPTO_AES=m
+ CONFIG_CRYPTO_CAST5=m
+diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
+index 2860be1..ae96a5b 100644
+--- a/arch/powerpc/configs/maple_defconfig
++++ b/arch/powerpc/configs/maple_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc6
+-# Sun Sep 10 10:24:55 2006
++# Linux kernel version: 2.6.18
++# Mon Oct 9 11:59:34 2006
+ #
+ CONFIG_PPC64=y
+ CONFIG_64BIT=y
+@@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+ CONFIG_PPC_OF=y
+ CONFIG_PPC_UDBG_16550=y
+ CONFIG_GENERIC_TBSYNC=y
++CONFIG_AUDIT_ARCH=y
+ # CONFIG_DEFAULT_UIMAGE is not set
+
+ #
+@@ -34,7 +35,7 @@ CONFIG_PPC_FPU=y
+ CONFIG_PPC_STD_MMU=y
+ CONFIG_VIRT_CPU_ACCOUNTING=y
+ CONFIG_SMP=y
+-CONFIG_NR_CPUS=2
++CONFIG_NR_CPUS=4
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -51,10 +52,11 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+@@ -62,7 +64,9 @@ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ CONFIG_KALLSYMS_ALL=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -71,12 +75,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -95,6 +99,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -114,16 +119,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ # Platform support
+ #
+ CONFIG_PPC_MULTIPLATFORM=y
+-# CONFIG_PPC_ISERIES is not set
+ # CONFIG_EMBEDDED6xx is not set
+ # CONFIG_APUS is not set
+ # CONFIG_PPC_PSERIES is not set
++# CONFIG_PPC_ISERIES is not set
+ # CONFIG_PPC_PMAC is not set
+ CONFIG_PPC_MAPLE=y
++# CONFIG_PPC_PASEMI is not set
+ # CONFIG_PPC_CELL is not set
+ # CONFIG_PPC_CELL_NATIVE is not set
+ # CONFIG_PPC_IBM_CELL_BLADE is not set
+-# CONFIG_UDBG_RTAS_CONSOLE is not set
+ CONFIG_U3_DART=y
+ # CONFIG_PPC_RTAS is not set
+ # CONFIG_MMIO_NVRAM is not set
+@@ -157,6 +162,7 @@ CONFIG_IRQ_ALL_CPUS=y
+ CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_POPULATES_NODE_MAP=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+ CONFIG_FLATMEM_MANUAL=y
+ # CONFIG_DISCONTIGMEM_MANUAL is not set
+@@ -184,6 +190,7 @@ CONFIG_GENERIC_ISA_DMA=y
+ CONFIG_PCI=y
+ CONFIG_PCI_DOMAINS=y
+ # CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ # CONFIG_PCI_DEBUG is not set
+
+ #
+@@ -211,6 +218,7 @@ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -232,10 +240,12 @@ CONFIG_IP_PNP_DHCP=y
+ # CONFIG_INET_TUNNEL is not set
+ CONFIG_INET_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_IPV6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+@@ -265,7 +275,6 @@ CONFIG_TCP_CONG_BIC=y
+ # 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
+
+@@ -377,6 +386,7 @@ CONFIG_BLK_DEV_AMD74XX=y
+ # CONFIG_BLK_DEV_CS5530 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+ # CONFIG_BLK_DEV_PIIX is not set
+ # CONFIG_BLK_DEV_IT821X is not set
+@@ -399,6 +409,12 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -496,9 +512,9 @@ CONFIG_E1000=y
+ # CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+-# CONFIG_TIGON3 is not set
++CONFIG_TIGON3=y
+ # CONFIG_BNX2 is not set
+-# CONFIG_MV643XX_ETH is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -545,6 +561,7 @@ CONFIG_E1000=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -704,6 +721,7 @@ CONFIG_I2C_AMD8111=y
+ #
+ # Misc devices
+ #
++# CONFIG_TIFM_CORE is not set
+
+ #
+ # Multimedia devices
+@@ -779,7 +797,6 @@ CONFIG_USB_UHCI_HCD=y
+ #
+ # may also be needed; see USB_STORAGE Help for more information
+ #
+-# CONFIG_USB_STORAGE is not set
+ # CONFIG_USB_LIBUSUAL is not set
+
+ #
+@@ -802,6 +819,7 @@ CONFIG_USB_HIDINPUT=y
+ # CONFIG_USB_ATI_REMOTE2 is not set
+ # CONFIG_USB_KEYSPAN_REMOTE is not set
+ # CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+
+ #
+ # USB Imaging devices
+@@ -828,6 +846,7 @@ CONFIG_USB_MON=y
+ CONFIG_USB_SERIAL=y
+ # CONFIG_USB_SERIAL_CONSOLE is not set
+ CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
+ # CONFIG_USB_SERIAL_AIRPRIME is not set
+ # CONFIG_USB_SERIAL_ARK3116 is not set
+ # CONFIG_USB_SERIAL_BELKIN is not set
+@@ -862,6 +881,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+ # CONFIG_USB_SERIAL_KLSI is not set
+ # CONFIG_USB_SERIAL_KOBIL_SCT is not set
+ # CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
+ # CONFIG_USB_SERIAL_NAVMAN is not set
+ # CONFIG_USB_SERIAL_PL2303 is not set
+ # CONFIG_USB_SERIAL_HP4X is not set
+@@ -879,6 +899,7 @@ CONFIG_USB_EZUSB=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+@@ -886,9 +907,9 @@ CONFIG_USB_EZUSB=y
+ # CONFIG_USB_LED is not set
+ # CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
+ # CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_SISUSBVGA is not set
+ # CONFIG_USB_LD is not set
+@@ -995,8 +1016,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+@@ -1129,6 +1152,7 @@ CONFIG_PLIST=y
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+@@ -1148,6 +1172,7 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
+ # CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ # CONFIG_FORCED_INLINING is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
+ CONFIG_DEBUG_STACKOVERFLOW=y
+@@ -1169,6 +1194,9 @@ CONFIG_BOOTX_TEXT=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
+ # CONFIG_CRYPTO_HMAC is not set
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -1178,6 +1206,8 @@ CONFIG_CRYPTO_MD5=y
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig
+index 719fba4..d1811e7 100644
+--- a/arch/powerpc/configs/mpc7448_hpc2_defconfig
++++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig
+@@ -413,23 +413,23 @@ CONFIG_BLK_DEV_SD=y
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-CONFIG_SCSI_SATA=y
+-# CONFIG_SCSI_SATA_AHCI is not set
+-# CONFIG_SCSI_SATA_SVW is not set
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++# CONFIG_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+-CONFIG_SCSI_SATA_MV=y
+-# CONFIG_SCSI_SATA_NV is not set
++CONFIG_SATA_MV=y
++# CONFIG_SATA_NV is not set
+ # CONFIG_SCSI_PDC_ADMA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+-# CONFIG_SCSI_SATA_QSTOR is not set
+-# CONFIG_SCSI_SATA_PROMISE is not set
+-# CONFIG_SCSI_SATA_SX4 is not set
+-# CONFIG_SCSI_SATA_SIL is not set
+-# CONFIG_SCSI_SATA_SIL24 is not set
+-# CONFIG_SCSI_SATA_SIS is not set
+-# CONFIG_SCSI_SATA_ULI is not set
+-# CONFIG_SCSI_SATA_VIA is not set
+-# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++# CONFIG_SATA_SIL is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_EATA is not set
+diff --git a/arch/powerpc/configs/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig
+index 8da6a47..0561b73 100644
+--- a/arch/powerpc/configs/mpc834x_itx_defconfig
++++ b/arch/powerpc/configs/mpc834x_itx_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc6
+-# Sun Sep 10 10:28:05 2006
++# Linux kernel version: 2.6.18
++# Mon Sep 25 19:41:14 2006
+ #
+ # CONFIG_PPC64 is not set
+ CONFIG_PPC32=y
+@@ -21,6 +21,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+ CONFIG_PPC_OF=y
+ CONFIG_PPC_UDBG_16550=y
+ # CONFIG_GENERIC_TBSYNC is not set
++CONFIG_AUDIT_ARCH=y
+ CONFIG_DEFAULT_UIMAGE=y
+
+ #
+@@ -61,25 +62,25 @@ CONFIG_SYSVIPC=y
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
++CONFIG_SYSCTL=y
+ # CONFIG_KALLSYMS is not set
+ CONFIG_HOTPLUG=y
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ # CONFIG_EPOLL is not set
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -259,7 +260,6 @@ CONFIG_TCP_CONG_BIC=y
+ # 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
+
+@@ -313,6 +313,7 @@ CONFIG_MTD_CHAR=y
+ # CONFIG_NFTL is not set
+ # CONFIG_INFTL is not set
+ # CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
+
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -464,23 +465,23 @@ CONFIG_SCSI_SPI_ATTRS=y
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-CONFIG_SCSI_SATA=y
+-# CONFIG_SCSI_SATA_AHCI is not set
+-# CONFIG_SCSI_SATA_SVW is not set
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++# CONFIG_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+-# CONFIG_SCSI_SATA_MV is not set
+-# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
+ # CONFIG_SCSI_PDC_ADMA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+-# CONFIG_SCSI_SATA_QSTOR is not set
+-# CONFIG_SCSI_SATA_PROMISE is not set
+-# CONFIG_SCSI_SATA_SX4 is not set
+-CONFIG_SCSI_SATA_SIL=y
+-# CONFIG_SCSI_SATA_SIL24 is not set
+-# CONFIG_SCSI_SATA_SIS is not set
+-# CONFIG_SCSI_SATA_ULI is not set
+-# CONFIG_SCSI_SATA_VIA is not set
+-# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++CONFIG_SATA_SIL=y
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_EATA is not set
+@@ -1247,7 +1248,7 @@ CONFIG_PARTITION_ADVANCED=y
+ # CONFIG_AMIGA_PARTITION is not set
+ # CONFIG_ATARI_PARTITION is not set
+ # CONFIG_MAC_PARTITION is not set
+-# CONFIG_MSDOS_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
+ # CONFIG_LDM_PARTITION is not set
+ # CONFIG_SGI_PARTITION is not set
+ # CONFIG_ULTRIX_PARTITION is not set
+@@ -1277,11 +1278,11 @@ CONFIG_PLIST=y
+ #
+ # Kernel hacking
+ #
+-CONFIG_PRINTK_TIME=y
++# CONFIG_PRINTK_TIME is not set
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+-CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_BUF_SHIFT=14
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+@@ -1293,15 +1294,15 @@ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+ # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+-CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+ # CONFIG_DEBUG_VM is not set
+ CONFIG_FORCED_INLINING=y
+ # CONFIG_RCU_TORTURE_TEST is not set
+ # CONFIG_DEBUGGER is not set
+ # CONFIG_BDI_SWITCH is not set
+-CONFIG_BOOTX_TEXT=y
+-CONFIG_SERIAL_TEXT_DEBUG=y
++# CONFIG_BOOTX_TEXT is not set
++# CONFIG_SERIAL_TEXT_DEBUG is not set
+ # CONFIG_PPC_EARLY_DEBUG is not set
+
+ #
+@@ -1314,6 +1315,8 @@ CONFIG_SERIAL_TEXT_DEBUG=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++# CONFIG_CRYPTO_MANAGER is not set
+ # CONFIG_CRYPTO_HMAC is not set
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -1323,6 +1326,8 @@ CONFIG_CRYPTO_MD5=y
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_CBC is not set
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig
+new file mode 100644
+index 0000000..c070341
+--- /dev/null
++++ b/arch/powerpc/configs/mpc8360emds_defconfig
+@@ -0,0 +1,1018 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18
++# Thu Sep 21 18:14:27 2006
++#
++# CONFIG_PPC64 is not set
++CONFIG_PPC32=y
++CONFIG_PPC_MERGE=y
++CONFIG_MMU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_PPC=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_GENERIC_NVRAM=y
++CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_PPC_OF=y
++CONFIG_PPC_UDBG_16550=y
++# CONFIG_GENERIC_TBSYNC is not set
++CONFIG_AUDIT_ARCH=y
++CONFIG_DEFAULT_UIMAGE=y
++
++#
++# Processor support
++#
++# CONFIG_CLASSIC32 is not set
++# CONFIG_PPC_52xx is not set
++# CONFIG_PPC_82xx is not set
++CONFIG_PPC_83xx=y
++# CONFIG_PPC_85xx is not set
++# CONFIG_PPC_86xx is not set
++# CONFIG_40x is not set
++# CONFIG_44x is not set
++# CONFIG_8xx is not set
++# CONFIG_E200 is not set
++CONFIG_6xx=y
++CONFIG_83xx=y
++CONFIG_PPC_FPU=y
++CONFIG_PPC_STD_MMU=y
++CONFIG_PPC_STD_MMU_32=y
++# CONFIG_SMP is not set
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_EMBEDDED=y
++CONFIG_SYSCTL=y
++# CONFIG_KALLSYMS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++# CONFIG_EPOLL is not set
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++
++#
++# Block layer
++#
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++CONFIG_QUICC_ENGINE=y
++CONFIG_PPC_GEN550=y
++# CONFIG_WANT_EARLY_SERIAL is not set
++
++#
++# Platform support
++#
++# CONFIG_MPC834x_SYS is not set
++# CONFIG_MPC834x_ITX is not set
++CONFIG_MPC8360E_PB=y
++CONFIG_PPC_MPC836x=y
++# CONFIG_MPIC is not set
++
++#
++# Kernel options
++#
++# CONFIG_HIGHMEM is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_PROC_DEVICETREE=y
++# CONFIG_CMDLINE_BOOL is not set
++# CONFIG_PM is not set
++CONFIG_SECCOMP=y
++CONFIG_ISA_DMA_API=y
++
++#
++# Bus options
++#
++CONFIG_GENERIC_ISA_DMA=y
++# CONFIG_MPIC_WEIRD is not set
++# CONFIG_PPC_I8259 is not set
++CONFIG_PPC_INDIRECT_PCI=y
++CONFIG_FSL_SOC=y
++CONFIG_PCI=y
++CONFIG_PCI_DOMAINS=y
++# CONFIG_PCIEPORTBUS is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++# CONFIG_HOTPLUG_PCI 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_BOOT_LOAD=0x00800000
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# 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=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_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_BIC=y
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_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=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=32768
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transport Attributes
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_BUSLOGIC is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_EATA 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
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_IPR is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++
++#
++# Macintosh device drivers
++#
++# CONFIG_WINDFARM is not set
++
++#
++# Network device support
++#
++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
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB 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_CASSINI 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_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_GIANFAR is not set
++CONFIG_UCC_GETH=y
++# CONFIG_UGETH_NAPI is not set
++# CONFIG_UGETH_MAGIC_PACKET is not set
++# CONFIG_UGETH_FILTERING is not set
++# CONFIG_UGETH_TX_ON_DEMOND is not set
++
++#
++# Ethernet (10000 Mbit)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER 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 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
++
++#
++# 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_PCI=y
++CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
++# CONFIG_SERIAL_8250_EXTENDED 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=y
++CONFIG_LEGACY_PTY_COUNT=256
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_83xx_WDT=y
++
++#
++# PCI-based Watchdog Cards
++#
++# CONFIG_PCIPCWATCHDOG is not set
++# CONFIG_WDTPCI is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_NVRAM is not set
++CONFIG_GEN_RTC=y
++# CONFIG_GEN_RTC_X 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_AGP is not set
++# CONFIG_DRM is not set
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=y
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_I810 is not set
++# CONFIG_I2C_PIIX4 is not set
++CONFIG_I2C_MPC=y
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_PROSAVAGE is not set
++# CONFIG_I2C_SAVAGE4 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
++# CONFIG_I2C_PCA_ISA is not set
++
++#
++# Miscellaneous 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_M41T00 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
++# CONFIG_I2C_DEBUG_CHIP is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# 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_F71805F 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
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_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_SIS5595 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB 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=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++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=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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=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
++# 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
++# CONFIG_9P_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 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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# QE Options
++#
++# CONFIG_UCC_SLOW is not set
++CONFIG_UCC_FAST=y
++CONFIG_UCC=y
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++
++#
++# Instrumentation Support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_FS is not set
++# CONFIG_BOOTX_TEXT is not set
++# CONFIG_SERIAL_TEXT_DEBUG is not set
++# CONFIG_PPC_EARLY_DEBUG is not set
++
++#
++# 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/powerpc/configs/mpc8560_ads_defconfig b/arch/powerpc/configs/mpc8560_ads_defconfig
+new file mode 100644
+index 0000000..ddc2a7b
+--- /dev/null
++++ b/arch/powerpc/configs/mpc8560_ads_defconfig
+@@ -0,0 +1,854 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18-rc4
++# Fri Aug 11 16:45:05 2006
++#
++# CONFIG_PPC64 is not set
++CONFIG_PPC32=y
++CONFIG_PPC_MERGE=y
++CONFIG_MMU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_PPC=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_GENERIC_NVRAM=y
++CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_PPC_OF=y
++# CONFIG_PPC_UDBG_16550 is not set
++# CONFIG_GENERIC_TBSYNC is not set
++CONFIG_DEFAULT_UIMAGE=y
++
++#
++# Processor support
++#
++# CONFIG_CLASSIC32 is not set
++# CONFIG_PPC_52xx is not set
++# CONFIG_PPC_82xx is not set
++# CONFIG_PPC_83xx is not set
++CONFIG_PPC_85xx=y
++# CONFIG_PPC_86xx is not set
++# CONFIG_40x is not set
++# CONFIG_44x is not set
++# CONFIG_8xx is not set
++# CONFIG_E200 is not set
++CONFIG_85xx=y
++CONFIG_E500=y
++CONFIG_BOOKE=y
++CONFIG_FSL_BOOKE=y
++# CONFIG_PHYS_64BIT is not set
++CONFIG_SPE=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++CONFIG_SYSCTL=y
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_EMBEDDED=y
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++# CONFIG_MODULES is not set
++
++#
++# Block layer
++#
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++CONFIG_MPIC=y
++CONFIG_CPM2=y
++# CONFIG_WANT_EARLY_SERIAL is not set
++
++#
++# Platform support
++#
++# CONFIG_MPC8540_ADS is not set
++CONFIG_MPC8560_ADS=y
++# CONFIG_MPC85xx_CDS is not set
++CONFIG_MPC8560=y
++CONFIG_PPC_INDIRECT_PCI_BE=y
++
++#
++# Kernel options
++#
++# CONFIG_HIGHMEM is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=y
++# CONFIG_MATH_EMULATION is not set
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++# CONFIG_PC_KEYBOARD is not set
++CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PROC_DEVICETREE is not set
++# CONFIG_CMDLINE_BOOL is not set
++# CONFIG_PM is not set
++# CONFIG_SOFTWARE_SUSPEND is not set
++# CONFIG_SECCOMP is not set
++CONFIG_ISA_DMA_API=y
++
++#
++# Bus options
++#
++# CONFIG_PPC_I8259 is not set
++CONFIG_PPC_INDIRECT_PCI=y
++CONFIG_FSL_SOC=y
++CONFIG_PCI=y
++CONFIG_PCI_DOMAINS=y
++# CONFIG_PCIEPORTBUS is not set
++CONFIG_PCI_DEBUG=y
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++# CONFIG_HOTPLUG_PCI 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_BOOT_LOAD=0x00800000
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# 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=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_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_BIC=y
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_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=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=32768
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# 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
++
++#
++# Macintosh device drivers
++#
++# CONFIG_WINDFARM is not set
++
++#
++# Network device support
++#
++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
++
++#
++# PHY device support
++#
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++CONFIG_MARVELL_PHY=y
++CONFIG_DAVICOM_PHY=y
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_FIXED_PHY 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_CASSINI 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
++CONFIG_FS_ENET=y
++# CONFIG_FS_ENET_HAS_SCC is not set
++CONFIG_FS_ENET_HAS_FCC=y
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++CONFIG_E1000=y
++CONFIG_E1000_NAPI=y
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++CONFIG_GIANFAR=y
++CONFIG_GFAR_NAPI=y
++
++#
++# Ethernet (10000 Mbit)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE 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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER 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 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
++
++#
++# 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=y
++CONFIG_SERIAL_CPM_SCC2=y
++# CONFIG_SERIAL_CPM_SCC3 is not set
++# CONFIG_SERIAL_CPM_SCC4 is not set
++# CONFIG_SERIAL_CPM_SMC1 is not set
++# CONFIG_SERIAL_CPM_SMC2 is not set
++# CONFIG_SERIAL_JSM is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++# CONFIG_BRIQ_PANEL is not set
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_NVRAM is not set
++CONFIG_GEN_RTC=y
++# CONFIG_GEN_RTC_X 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_AGP is not set
++# CONFIG_DRM is not set
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB 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=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++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=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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
++# CONFIG_9P_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 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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++
++#
++# Instrumentation Support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS 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_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_UNWIND_INFO is not set
++CONFIG_FORCED_INLINING=y
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_DEBUGGER is not set
++# CONFIG_KGDB_CONSOLE is not set
++# CONFIG_BDI_SWITCH is not set
++# CONFIG_BOOTX_TEXT is not set
++# CONFIG_PPC_EARLY_DEBUG 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
++#
+diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
+index 6861dde..765c8bb 100644
+--- a/arch/powerpc/configs/pmac32_defconfig
++++ b/arch/powerpc/configs/pmac32_defconfig
+@@ -682,7 +682,7 @@ CONFIG_SCSI_AIC7XXX_OLD=m
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
++# CONFIG_ATA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+@@ -1826,7 +1826,7 @@ CONFIG_OPROFILE=y
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
+-# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=14
+diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
+index 7517d0c..be11df7 100644
+--- a/arch/powerpc/configs/ppc64_defconfig
++++ b/arch/powerpc/configs/ppc64_defconfig
+@@ -520,23 +520,23 @@ CONFIG_SCSI_ISCSI_ATTRS=m
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-CONFIG_SCSI_SATA=y
+-# CONFIG_SCSI_SATA_AHCI is not set
+-CONFIG_SCSI_SATA_SVW=y
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++CONFIG_SATA_SVW=y
+ # CONFIG_SCSI_ATA_PIIX is not set
+-# CONFIG_SCSI_SATA_MV is not set
+-# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
+ # CONFIG_SCSI_PDC_ADMA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+-# CONFIG_SCSI_SATA_QSTOR is not set
+-# CONFIG_SCSI_SATA_PROMISE is not set
+-# CONFIG_SCSI_SATA_SX4 is not set
+-# CONFIG_SCSI_SATA_SIL is not set
+-# CONFIG_SCSI_SATA_SIL24 is not set
+-# CONFIG_SCSI_SATA_SIS is not set
+-# CONFIG_SCSI_SATA_ULI is not set
+-# CONFIG_SCSI_SATA_VIA is not set
+-# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++# CONFIG_SATA_SIL is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_EATA is not set
+diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
+index a8cdf31..d2833c1 100644
+--- a/arch/powerpc/configs/pseries_defconfig
++++ b/arch/powerpc/configs/pseries_defconfig
+@@ -184,6 +184,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
+ CONFIG_MIGRATION=y
+ CONFIG_RESOURCES_64BIT=y
+ CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
++CONFIG_NODES_SPAN_OTHER_NODES=y
+ # CONFIG_PPC_64K_PAGES is not set
+ CONFIG_SCHED_SMT=y
+ CONFIG_PROC_DEVICETREE=y
+@@ -506,7 +507,7 @@ CONFIG_SCSI_SAS_ATTRS=m
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
++CONFIG_ATA=y
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
+index 7d32ad0..7af23c4 100644
+--- a/arch/powerpc/kernel/Makefile
++++ b/arch/powerpc/kernel/Makefile
+@@ -16,7 +16,7 @@ obj-y := semaphore.o cputable.o ptrac
+ obj-y += vdso32/
+ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
+ signal_64.o ptrace32.o \
+- paca.o cpu_setup_power4.o \
++ paca.o cpu_setup_ppc970.o \
+ firmware.o sysfs.o
+ obj-$(CONFIG_PPC64) += vdso64/
+ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
+@@ -38,7 +38,6 @@ obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6x
+ obj-$(CONFIG_TAU) += tau_6xx.o
+ obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
+ obj32-$(CONFIG_MODULES) += module_32.o
+-obj-$(CONFIG_E500) += perfmon_fsl_booke.o
+
+ ifeq ($(CONFIG_PPC_MERGE),y)
+
+@@ -51,7 +50,7 @@ extra-$(CONFIG_8xx) := head_8xx.o
+ extra-y += vmlinux.lds
+
+ obj-y += time.o prom.o traps.o setup-common.o \
+- udbg.o misc.o
++ udbg.o misc.o io.o
+ obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o
+ obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o
+ obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
+diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
+index 7ee8496..d06f378 100644
+--- a/arch/powerpc/kernel/asm-offsets.c
++++ b/arch/powerpc/kernel/asm-offsets.c
+@@ -40,9 +40,10 @@
+ #ifdef CONFIG_PPC64
+ #include <asm/paca.h>
+ #include <asm/lppaca.h>
+-#include <asm/iseries/hv_lp_event.h>
+ #include <asm/cache.h>
+ #include <asm/compat.h>
++#include <asm/mmu.h>
++#include <asm/hvcall.h>
+ #endif
+
+ #define DEFINE(sym, val) \
+@@ -136,11 +137,18 @@ int main(void)
+ DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr));
+ DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
+ DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
++ DEFINE(PACA_SLBSHADOWPTR, offsetof(struct paca_struct, slb_shadow_ptr));
++ DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
+
++ DEFINE(SLBSHADOW_STACKVSID,
++ offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
++ DEFINE(SLBSHADOW_STACKESID,
++ offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
+ DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
+ DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
+ DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
+ DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
++ DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
+ #endif /* CONFIG_PPC64 */
+
+ /* RTAS */
+@@ -159,6 +167,12 @@ int main(void)
+ /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
+ DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
+ DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
++
++ /* hcall statistics */
++ DEFINE(HCALL_STAT_SIZE, sizeof(struct hcall_stats));
++ DEFINE(HCALL_STAT_CALLS, offsetof(struct hcall_stats, num_calls));
++ DEFINE(HCALL_STAT_TB, offsetof(struct hcall_stats, tb_total));
++ DEFINE(HCALL_STAT_PURR, offsetof(struct hcall_stats, purr_total));
+ #endif /* CONFIG_PPC64 */
+ DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+ DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+@@ -240,6 +254,7 @@ int main(void)
+ DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
+ DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
+ DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
++ DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
+
+ #ifndef CONFIG_PPC64
+ DEFINE(pbe_address, offsetof(struct pbe, address));
+diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
+index f4e5e14..93f21aa 100644
+--- a/arch/powerpc/kernel/btext.c
++++ b/arch/powerpc/kernel/btext.c
+@@ -158,35 +158,35 @@ int btext_initialize(struct device_node
+ {
+ unsigned int width, height, depth, pitch;
+ unsigned long address = 0;
+- u32 *prop;
++ const u32 *prop;
+
+- prop = (u32 *)get_property(np, "linux,bootx-width", NULL);
++ prop = get_property(np, "linux,bootx-width", NULL);
+ if (prop == NULL)
+- prop = (u32 *)get_property(np, "width", NULL);
++ prop = get_property(np, "width", NULL);
+ if (prop == NULL)
+ return -EINVAL;
+ width = *prop;
+- prop = (u32 *)get_property(np, "linux,bootx-height", NULL);
++ prop = get_property(np, "linux,bootx-height", NULL);
+ if (prop == NULL)
+- prop = (u32 *)get_property(np, "height", NULL);
++ prop = get_property(np, "height", NULL);
+ if (prop == NULL)
+ return -EINVAL;
+ height = *prop;
+- prop = (u32 *)get_property(np, "linux,bootx-depth", NULL);
++ prop = get_property(np, "linux,bootx-depth", NULL);
+ if (prop == NULL)
+- prop = (u32 *)get_property(np, "depth", NULL);
++ prop = get_property(np, "depth", NULL);
+ if (prop == NULL)
+ return -EINVAL;
+ depth = *prop;
+ pitch = width * ((depth + 7) / 8);
+- prop = (u32 *)get_property(np, "linux,bootx-linebytes", NULL);
++ prop = get_property(np, "linux,bootx-linebytes", NULL);
+ if (prop == NULL)
+- prop = (u32 *)get_property(np, "linebytes", NULL);
+- if (prop)
++ prop = get_property(np, "linebytes", NULL);
++ if (prop && *prop != 0xffffffffu)
+ pitch = *prop;
+ if (pitch == 1)
+ pitch = 0x1000;
+- prop = (u32 *)get_property(np, "address", NULL);
++ prop = get_property(np, "address", NULL);
+ if (prop)
+ address = *prop;
+
+@@ -214,11 +214,11 @@ int btext_initialize(struct device_node
+
+ int __init btext_find_display(int allow_nonstdout)
+ {
+- char *name;
++ const char *name;
+ struct device_node *np = NULL;
+ int rc = -ENODEV;
+
+- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
++ name = get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name != NULL) {
+ np = of_find_node_by_path(name);
+ if (np != NULL) {
+diff --git a/arch/powerpc/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_power4.S
+deleted file mode 100644
+index 76e97aa..0000000
+--- a/arch/powerpc/kernel/cpu_setup_power4.S
++++ /dev/null
+@@ -1,227 +0,0 @@
+-/*
+- * This file contains low level CPU setup functions.
+- * Copyright (C) 2003 Benjamin Herrenschmidt (benh at kernel.crashing.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 the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
+- *
+- */
+-
+-#include <asm/processor.h>
+-#include <asm/page.h>
+-#include <asm/cputable.h>
+-#include <asm/ppc_asm.h>
+-#include <asm/asm-offsets.h>
+-#include <asm/cache.h>
+-
+-_GLOBAL(__970_cpu_preinit)
+- /*
+- * Do nothing if not running in HV mode
+- */
+- mfmsr r0
+- rldicl. r0,r0,4,63
+- beqlr
+-
+- /*
+- * Deal only with PPC970 and PPC970FX.
+- */
+- mfspr r0,SPRN_PVR
+- srwi r0,r0,16
+- cmpwi r0,0x39
+- beq 1f
+- cmpwi r0,0x3c
+- beq 1f
+- cmpwi r0,0x44
+- bnelr
+-1:
+-
+- /* Make sure HID4:rm_ci is off before MMU is turned off, that large
+- * pages are enabled with HID4:61 and clear HID5:DCBZ_size and
+- * HID5:DCBZ32_ill
+- */
+- li r0,0
+- mfspr r3,SPRN_HID4
+- rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */
+- rldimi r3,r0,2,61 /* clear bit 61 (lg_pg_en) */
+- sync
+- mtspr SPRN_HID4,r3
+- isync
+- sync
+- mfspr r3,SPRN_HID5
+- rldimi r3,r0,6,56 /* clear bits 56 & 57 (DCBZ*) */
+- sync
+- mtspr SPRN_HID5,r3
+- isync
+- sync
+-
+- /* Setup some basic HID1 features */
+- mfspr r0,SPRN_HID1
+- li r3,0x1200 /* enable i-fetch cacheability */
+- sldi r3,r3,44 /* and prefetch */
+- or r0,r0,r3
+- mtspr SPRN_HID1,r0
+- mtspr SPRN_HID1,r0
+- isync
+-
+- /* Clear HIOR */
+- li r0,0
+- sync
+- mtspr SPRN_HIOR,0 /* Clear interrupt prefix */
+- isync
+- blr
+-
+-_GLOBAL(__setup_cpu_ppc970)
+- mfspr r0,SPRN_HID0
+- li r11,5 /* clear DOZE and SLEEP */
+- rldimi r0,r11,52,8 /* set NAP and DPM */
+- li r11,0
+- rldimi r0,r11,32,31 /* clear EN_ATTN */
+- mtspr SPRN_HID0,r0
+- mfspr r0,SPRN_HID0
+- mfspr r0,SPRN_HID0
+- mfspr r0,SPRN_HID0
+- mfspr r0,SPRN_HID0
+- mfspr r0,SPRN_HID0
+- mfspr r0,SPRN_HID0
+- sync
+- isync
+- blr
+-
+-/* Definitions for the table use to save CPU states */
+-#define CS_HID0 0
+-#define CS_HID1 8
+-#define CS_HID4 16
+-#define CS_HID5 24
+-#define CS_SIZE 32
+-
+- .data
+- .balign L1_CACHE_BYTES,0
+-cpu_state_storage:
+- .space CS_SIZE
+- .balign L1_CACHE_BYTES,0
+- .text
+-
+-/* Called in normal context to backup CPU 0 state. This
+- * does not include cache settings. This function is also
+- * called for machine sleep. This does not include the MMU
+- * setup, BATs, etc... but rather the "special" registers
+- * like HID0, HID1, HID4, etc...
+- */
+-_GLOBAL(__save_cpu_setup)
+- /* Some CR fields are volatile, we back it up all */
+- mfcr r7
+-
+- /* Get storage ptr */
+- LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+-
+- /* We only deal with 970 for now */
+- mfspr r0,SPRN_PVR
+- srwi r0,r0,16
+- cmpwi r0,0x39
+- beq 1f
+- cmpwi r0,0x3c
+- beq 1f
+- cmpwi r0,0x44
+- bne 2f
+-
+-1: /* skip if not running in HV mode */
+- mfmsr r0
+- rldicl. r0,r0,4,63
+- beq 2f
+-
+- /* Save HID0,1,4 and 5 */
+- mfspr r3,SPRN_HID0
+- std r3,CS_HID0(r5)
+- mfspr r3,SPRN_HID1
+- std r3,CS_HID1(r5)
+- mfspr r3,SPRN_HID4
+- std r3,CS_HID4(r5)
+- mfspr r3,SPRN_HID5
+- std r3,CS_HID5(r5)
+-
+-2:
+- mtcr r7
+- blr
+-
+-/* Called with no MMU context (typically MSR:IR/DR off) to
+- * restore CPU state as backed up by the previous
+- * function. This does not include cache setting
+- */
+-_GLOBAL(__restore_cpu_setup)
+- /* Get storage ptr (FIXME when using anton reloc as we
+- * are running with translation disabled here
+- */
+- LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+-
+- /* We only deal with 970 for now */
+- mfspr r0,SPRN_PVR
+- srwi r0,r0,16
+- cmpwi r0,0x39
+- beq 1f
+- cmpwi r0,0x3c
+- beq 1f
+- cmpwi r0,0x44
+- bnelr
+-
+-1: /* skip if not running in HV mode */
+- mfmsr r0
+- rldicl. r0,r0,4,63
+- beqlr
+-
+- /* Before accessing memory, we make sure rm_ci is clear */
+- li r0,0
+- mfspr r3,SPRN_HID4
+- rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */
+- sync
+- mtspr SPRN_HID4,r3
+- isync
+- sync
+-
+- /* Clear interrupt prefix */
+- li r0,0
+- sync
+- mtspr SPRN_HIOR,0
+- isync
+-
+- /* Restore HID0 */
+- ld r3,CS_HID0(r5)
+- sync
+- isync
+- mtspr SPRN_HID0,r3
+- mfspr r3,SPRN_HID0
+- mfspr r3,SPRN_HID0
+- mfspr r3,SPRN_HID0
+- mfspr r3,SPRN_HID0
+- mfspr r3,SPRN_HID0
+- mfspr r3,SPRN_HID0
+- sync
+- isync
+-
+- /* Restore HID1 */
+- ld r3,CS_HID1(r5)
+- sync
+- isync
+- mtspr SPRN_HID1,r3
+- mtspr SPRN_HID1,r3
+- sync
+- isync
+-
+- /* Restore HID4 */
+- ld r3,CS_HID4(r5)
+- sync
+- isync
+- mtspr SPRN_HID4,r3
+- sync
+- isync
+-
+- /* Restore HID5 */
+- ld r3,CS_HID5(r5)
+- sync
+- isync
+- mtspr SPRN_HID5,r3
+- sync
+- isync
+- blr
+-
+diff --git a/arch/powerpc/kernel/cpu_setup_ppc970.S b/arch/powerpc/kernel/cpu_setup_ppc970.S
+new file mode 100644
+index 0000000..6525948
+--- /dev/null
++++ b/arch/powerpc/kernel/cpu_setup_ppc970.S
+@@ -0,0 +1,176 @@
++/*
++ * This file contains low level CPU setup functions.
++ * Copyright (C) 2003 Benjamin Herrenschmidt (benh at kernel.crashing.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 the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ */
++
++#include <asm/processor.h>
++#include <asm/page.h>
++#include <asm/cputable.h>
++#include <asm/ppc_asm.h>
++#include <asm/asm-offsets.h>
++#include <asm/cache.h>
++
++_GLOBAL(__cpu_preinit_ppc970)
++ /* Do nothing if not running in HV mode */
++ mfmsr r0
++ rldicl. r0,r0,4,63
++ beqlr
++
++ /* Make sure HID4:rm_ci is off before MMU is turned off, that large
++ * pages are enabled with HID4:61 and clear HID5:DCBZ_size and
++ * HID5:DCBZ32_ill
++ */
++ li r0,0
++ mfspr r3,SPRN_HID4
++ rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */
++ rldimi r3,r0,2,61 /* clear bit 61 (lg_pg_en) */
++ sync
++ mtspr SPRN_HID4,r3
++ isync
++ sync
++ mfspr r3,SPRN_HID5
++ rldimi r3,r0,6,56 /* clear bits 56 & 57 (DCBZ*) */
++ sync
++ mtspr SPRN_HID5,r3
++ isync
++ sync
++
++ /* Setup some basic HID1 features */
++ mfspr r0,SPRN_HID1
++ li r3,0x1200 /* enable i-fetch cacheability */
++ sldi r3,r3,44 /* and prefetch */
++ or r0,r0,r3
++ mtspr SPRN_HID1,r0
++ mtspr SPRN_HID1,r0
++ isync
++
++ /* Clear HIOR */
++ li r0,0
++ sync
++ mtspr SPRN_HIOR,0 /* Clear interrupt prefix */
++ isync
++ blr
++
++/* Definitions for the table use to save CPU states */
++#define CS_HID0 0
++#define CS_HID1 8
++#define CS_HID4 16
++#define CS_HID5 24
++#define CS_SIZE 32
++
++ .data
++ .balign L1_CACHE_BYTES,0
++cpu_state_storage:
++ .space CS_SIZE
++ .balign L1_CACHE_BYTES,0
++ .text
++
++
++_GLOBAL(__setup_cpu_ppc970)
++ /* Do nothing if not running in HV mode */
++ mfmsr r0
++ rldicl. r0,r0,4,63
++ beqlr
++
++ mfspr r0,SPRN_HID0
++ li r11,5 /* clear DOZE and SLEEP */
++ rldimi r0,r11,52,8 /* set NAP and DPM */
++ li r11,0
++ rldimi r0,r11,32,31 /* clear EN_ATTN */
++ mtspr SPRN_HID0,r0
++ mfspr r0,SPRN_HID0
++ mfspr r0,SPRN_HID0
++ mfspr r0,SPRN_HID0
++ mfspr r0,SPRN_HID0
++ mfspr r0,SPRN_HID0
++ mfspr r0,SPRN_HID0
++ sync
++ isync
++
++ /* Save away cpu state */
++ LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
++
++ /* Save HID0,1,4 and 5 */
++ mfspr r3,SPRN_HID0
++ std r3,CS_HID0(r5)
++ mfspr r3,SPRN_HID1
++ std r3,CS_HID1(r5)
++ mfspr r3,SPRN_HID4
++ std r3,CS_HID4(r5)
++ mfspr r3,SPRN_HID5
++ std r3,CS_HID5(r5)
++
++ blr
++
++/* Called with no MMU context (typically MSR:IR/DR off) to
++ * restore CPU state as backed up by the previous
++ * function. This does not include cache setting
++ */
++_GLOBAL(__restore_cpu_ppc970)
++ /* Do nothing if not running in HV mode */
++ mfmsr r0
++ rldicl. r0,r0,4,63
++ beqlr
++
++ LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
++ /* Before accessing memory, we make sure rm_ci is clear */
++ li r0,0
++ mfspr r3,SPRN_HID4
++ rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */
++ sync
++ mtspr SPRN_HID4,r3
++ isync
++ sync
++
++ /* Clear interrupt prefix */
++ li r0,0
++ sync
++ mtspr SPRN_HIOR,0
++ isync
++
++ /* Restore HID0 */
++ ld r3,CS_HID0(r5)
++ sync
++ isync
++ mtspr SPRN_HID0,r3
++ mfspr r3,SPRN_HID0
++ mfspr r3,SPRN_HID0
++ mfspr r3,SPRN_HID0
++ mfspr r3,SPRN_HID0
++ mfspr r3,SPRN_HID0
++ mfspr r3,SPRN_HID0
++ sync
++ isync
++
++ /* Restore HID1 */
++ ld r3,CS_HID1(r5)
++ sync
++ isync
++ mtspr SPRN_HID1,r3
++ mtspr SPRN_HID1,r3
++ sync
++ isync
++
++ /* Restore HID4 */
++ ld r3,CS_HID4(r5)
++ sync
++ isync
++ mtspr SPRN_HID4,r3
++ sync
++ isync
++
++ /* Restore HID5 */
++ ld r3,CS_HID5(r5)
++ sync
++ isync
++ mtspr SPRN_HID5,r3
++ sync
++ isync
++ blr
++
+diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
+index 272e436..bfd499e 100644
+--- a/arch/powerpc/kernel/cputable.c
++++ b/arch/powerpc/kernel/cputable.c
+@@ -18,6 +18,7 @@
+
+ #include <asm/oprofile_impl.h>
+ #include <asm/cputable.h>
++#include <asm/prom.h> /* for PTRRELOC on ARCH=ppc */
+
+ struct cpu_spec* cur_cpu_spec = NULL;
+ EXPORT_SYMBOL(cur_cpu_spec);
+@@ -39,7 +40,10 @@ extern void __setup_cpu_7400(unsigned lo
+ extern void __setup_cpu_7410(unsigned long offset, struct cpu_spec* spec);
+ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec);
+ #endif /* CONFIG_PPC32 */
++#ifdef CONFIG_PPC64
+ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
++extern void __restore_cpu_ppc970(void);
++#endif /* CONFIG_PPC64 */
+
+ /* This table only contains "desktop" CPUs, it need to be filled with embedded
+ * ones as well...
+@@ -55,6 +59,9 @@ extern void __setup_cpu_ppc970(unsigned
+ #define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\
+ PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \
+ PPC_FEATURE_TRUE_LE)
++#define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
++ PPC_FEATURE_TRUE_LE | \
++ PPC_FEATURE_HAS_ALTIVEC_COMP)
+ #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
+ PPC_FEATURE_BOOKE)
+
+@@ -67,7 +74,7 @@ extern void __setup_cpu_ppc970(unsigned
+ #define PPC_FEATURE_SPE_COMP 0
+ #endif
+
+-struct cpu_spec cpu_specs[] = {
++static struct cpu_spec cpu_specs[] = {
+ #ifdef CONFIG_PPC64
+ { /* Power3 */
+ .pvr_mask = 0xffff0000,
+@@ -184,6 +191,7 @@ struct cpu_spec cpu_specs[] = {
+ .dcache_bsize = 128,
+ .num_pmcs = 8,
+ .cpu_setup = __setup_cpu_ppc970,
++ .cpu_restore = __restore_cpu_ppc970,
+ .oprofile_cpu_type = "ppc64/970",
+ .oprofile_type = PPC_OPROFILE_POWER4,
+ .platform = "ppc970",
+@@ -199,6 +207,7 @@ struct cpu_spec cpu_specs[] = {
+ .dcache_bsize = 128,
+ .num_pmcs = 8,
+ .cpu_setup = __setup_cpu_ppc970,
++ .cpu_restore = __restore_cpu_ppc970,
+ .oprofile_cpu_type = "ppc64/970",
+ .oprofile_type = PPC_OPROFILE_POWER4,
+ .platform = "ppc970",
+@@ -214,6 +223,22 @@ struct cpu_spec cpu_specs[] = {
+ .dcache_bsize = 128,
+ .num_pmcs = 8,
+ .cpu_setup = __setup_cpu_ppc970,
++ .cpu_restore = __restore_cpu_ppc970,
++ .oprofile_cpu_type = "ppc64/970",
++ .oprofile_type = PPC_OPROFILE_POWER4,
++ .platform = "ppc970",
++ },
++ { /* PPC970GX */
++ .pvr_mask = 0xffff0000,
++ .pvr_value = 0x00450000,
++ .cpu_name = "PPC970GX",
++ .cpu_features = CPU_FTRS_PPC970,
++ .cpu_user_features = COMMON_USER_POWER4 |
++ PPC_FEATURE_HAS_ALTIVEC_COMP,
++ .icache_bsize = 128,
++ .dcache_bsize = 128,
++ .num_pmcs = 8,
++ .cpu_setup = __setup_cpu_ppc970,
+ .oprofile_cpu_type = "ppc64/970",
+ .oprofile_type = PPC_OPROFILE_POWER4,
+ .platform = "ppc970",
+@@ -259,7 +284,7 @@ struct cpu_spec cpu_specs[] = {
+ .cpu_user_features = COMMON_USER_POWER6,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+- .num_pmcs = 8,
++ .num_pmcs = 6,
+ .oprofile_cpu_type = "ppc64/power6",
+ .oprofile_type = PPC_OPROFILE_POWER4,
+ .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
+@@ -280,6 +305,17 @@ struct cpu_spec cpu_specs[] = {
+ .dcache_bsize = 128,
+ .platform = "ppc-cell-be",
+ },
++ { /* PA Semi PA6T */
++ .pvr_mask = 0x7fff0000,
++ .pvr_value = 0x00900000,
++ .cpu_name = "PA6T",
++ .cpu_features = CPU_FTRS_PA6T,
++ .cpu_user_features = COMMON_USER_PA6T,
++ .icache_bsize = 64,
++ .dcache_bsize = 64,
++ .num_pmcs = 6,
++ .platform = "pa6t",
++ },
+ { /* default match */
+ .pvr_mask = 0x00000000,
+ .pvr_value = 0x00000000,
+@@ -743,10 +779,10 @@ struct cpu_spec cpu_specs[] = {
+ .cpu_setup = __setup_cpu_603,
+ .platform = "ppc603",
+ },
+- { /* e300 (a 603e core, plus some) on 83xx */
++ { /* e300c1 (a 603e core, plus some) on 83xx */
+ .pvr_mask = 0x7fff0000,
+ .pvr_value = 0x00830000,
+- .cpu_name = "e300",
++ .cpu_name = "e300c1",
+ .cpu_features = CPU_FTRS_E300,
+ .cpu_user_features = COMMON_USER,
+ .icache_bsize = 32,
+@@ -754,6 +790,17 @@ struct cpu_spec cpu_specs[] = {
+ .cpu_setup = __setup_cpu_603,
+ .platform = "ppc603",
+ },
++ { /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */
++ .pvr_mask = 0x7fff0000,
++ .pvr_value = 0x00840000,
++ .cpu_name = "e300c2",
++ .cpu_features = CPU_FTRS_E300,
++ .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
++ .icache_bsize = 32,
++ .dcache_bsize = 32,
++ .cpu_setup = __setup_cpu_603,
++ .platform = "ppc603",
++ },
+ { /* default match, we assume split I/D cache & TB (non-601)... */
+ .pvr_mask = 0x00000000,
+ .pvr_value = 0x00000000,
+@@ -929,6 +976,7 @@ struct cpu_spec cpu_specs[] = {
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
++ .platform = "ppc405",
+ },
+ { /* 405EP */
+ .pvr_mask = 0xffff0000,
+@@ -1120,3 +1168,71 @@ struct cpu_spec cpu_specs[] = {
+ #endif /* !CLASSIC_PPC */
+ #endif /* CONFIG_PPC32 */
+ };
++
++struct cpu_spec *identify_cpu(unsigned long offset)
++{
++ struct cpu_spec *s = cpu_specs;
++ struct cpu_spec **cur = &cur_cpu_spec;
++ unsigned int pvr = mfspr(SPRN_PVR);
++ int i;
++
++ s = PTRRELOC(s);
++ cur = PTRRELOC(cur);
++
++ if (*cur != NULL)
++ return PTRRELOC(*cur);
++
++ for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++)
++ if ((pvr & s->pvr_mask) == s->pvr_value) {
++ *cur = cpu_specs + i;
++#ifdef CONFIG_PPC64
++ /* ppc64 expects identify_cpu to also call setup_cpu
++ * for that processor. I will consolidate that at a
++ * later time, for now, just use our friend #ifdef.
++ * we also don't need to PTRRELOC the function pointer
++ * on ppc64 as we are running at 0 in real mode.
++ */
++ if (s->cpu_setup) {
++ s->cpu_setup(offset, s);
++ }
++#endif /* CONFIG_PPC64 */
++ return s;
++ }
++ BUG();
++ return NULL;
++}
++
++void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
++{
++ struct fixup_entry {
++ unsigned long mask;
++ unsigned long value;
++ long start_off;
++ long end_off;
++ } *fcur, *fend;
++
++ fcur = fixup_start;
++ fend = fixup_end;
++
++ for (; fcur < fend; fcur++) {
++ unsigned int *pstart, *pend, *p;
++
++ if ((value & fcur->mask) == fcur->value)
++ continue;
++
++ /* These PTRRELOCs will disappear once the new scheme for
++ * modules and vdso is implemented
++ */
++ pstart = ((unsigned int *)fcur) + (fcur->start_off / 4);
++ pend = ((unsigned int *)fcur) + (fcur->end_off / 4);
++
++ for (p = pstart; p < pend; p++) {
++ *p = 0x60000000u;
++ asm volatile ("dcbst 0, %0" : : "r" (p));
++ }
++ asm volatile ("sync" : : : "memory");
++ for (p = pstart; p < pend; p++)
++ asm volatile ("icbi 0,%0" : : "r" (p));
++ asm volatile ("sync; isync" : : : "memory");
++ }
++}
+diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
+index 371973b..2f6f5a7 100644
+--- a/arch/powerpc/kernel/crash_dump.c
++++ b/arch/powerpc/kernel/crash_dump.c
+@@ -80,7 +80,7 @@ static int __init parse_savemaxmem(char
+ }
+ __setup("savemaxmem=", parse_savemaxmem);
+
+-/*
++/**
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c
+index 36aaa76..6c168f6 100644
+--- a/arch/powerpc/kernel/dma_64.c
++++ b/arch/powerpc/kernel/dma_64.c
+@@ -35,10 +35,9 @@ int dma_supported(struct device *dev, u6
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- return dma_ops->dma_supported(dev, mask);
+- BUG();
+- return 0;
++ BUG_ON(!dma_ops);
++
++ return dma_ops->dma_supported(dev, mask);
+ }
+ EXPORT_SYMBOL(dma_supported);
+
+@@ -66,10 +65,9 @@ void *dma_alloc_coherent(struct device *
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+- BUG();
+- return NULL;
++ BUG_ON(!dma_ops);
++
++ return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+ }
+ EXPORT_SYMBOL(dma_alloc_coherent);
+
+@@ -78,10 +76,9 @@ void dma_free_coherent(struct device *de
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+- else
+- BUG();
++ BUG_ON(!dma_ops);
++
++ dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ }
+ EXPORT_SYMBOL(dma_free_coherent);
+
+@@ -90,10 +87,9 @@ dma_addr_t dma_map_single(struct device
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- return dma_ops->map_single(dev, cpu_addr, size, direction);
+- BUG();
+- return (dma_addr_t)0;
++ BUG_ON(!dma_ops);
++
++ return dma_ops->map_single(dev, cpu_addr, size, direction);
+ }
+ EXPORT_SYMBOL(dma_map_single);
+
+@@ -102,10 +98,9 @@ void dma_unmap_single(struct device *dev
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- dma_ops->unmap_single(dev, dma_addr, size, direction);
+- else
+- BUG();
++ BUG_ON(!dma_ops);
++
++ dma_ops->unmap_single(dev, dma_addr, size, direction);
+ }
+ EXPORT_SYMBOL(dma_unmap_single);
+
+@@ -115,11 +110,10 @@ dma_addr_t dma_map_page(struct device *d
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- return dma_ops->map_single(dev,
+- (page_address(page) + offset), size, direction);
+- BUG();
+- return (dma_addr_t)0;
++ BUG_ON(!dma_ops);
++
++ return dma_ops->map_single(dev, page_address(page) + offset, size,
++ direction);
+ }
+ EXPORT_SYMBOL(dma_map_page);
+
+@@ -128,10 +122,9 @@ void dma_unmap_page(struct device *dev,
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- dma_ops->unmap_single(dev, dma_address, size, direction);
+- else
+- BUG();
++ BUG_ON(!dma_ops);
++
++ dma_ops->unmap_single(dev, dma_address, size, direction);
+ }
+ EXPORT_SYMBOL(dma_unmap_page);
+
+@@ -140,10 +133,9 @@ int dma_map_sg(struct device *dev, struc
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- return dma_ops->map_sg(dev, sg, nents, direction);
+- BUG();
+- return 0;
++ BUG_ON(!dma_ops);
++
++ return dma_ops->map_sg(dev, sg, nents, direction);
+ }
+ EXPORT_SYMBOL(dma_map_sg);
+
+@@ -152,9 +144,8 @@ void dma_unmap_sg(struct device *dev, st
+ {
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+- if (dma_ops)
+- dma_ops->unmap_sg(dev, sg, nhwentries, direction);
+- else
+- BUG();
++ BUG_ON(!dma_ops);
++
++ dma_ops->unmap_sg(dev, sg, nhwentries, direction);
+ }
+ EXPORT_SYMBOL(dma_unmap_sg);
+diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
+index 54d9f5c..748e74f 100644
+--- a/arch/powerpc/kernel/entry_64.S
++++ b/arch/powerpc/kernel/entry_64.S
+@@ -27,10 +27,7 @@
+ #include <asm/ppc_asm.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/cputable.h>
+-
+-#ifdef CONFIG_PPC_ISERIES
+-#define DO_SOFT_DISABLE
+-#endif
++#include <asm/firmware.h>
+
+ /*
+ * System calls.
+@@ -91,6 +88,7 @@ system_call_common:
+ ld r11,exception_marker at toc(r2)
+ std r11,-16(r9) /* "regshere" marker */
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ /* Hack for handling interrupts when soft-enabling on iSeries */
+ cmpdi cr1,r0,0x5555 /* syscall 0x5555 */
+ andi. r10,r12,MSR_PR /* from kernel */
+@@ -98,6 +96,7 @@ system_call_common:
+ beq hardware_interrupt_entry
+ lbz r10,PACAPROCENABLED(r13)
+ std r10,SOFTE(r1)
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif
+ mfmsr r11
+ ori r11,r11,MSR_EE
+@@ -375,6 +374,14 @@ BEGIN_FTR_SECTION
+ ld r7,KSP_VSID(r4) /* Get new stack's VSID */
+ oris r0,r6,(SLB_ESID_V)@h
+ ori r0,r0,(SLB_NUM_BOLTED-1)@l
++
++ /* Update the last bolted SLB */
++ ld r9,PACA_SLBSHADOWPTR(r13)
++ li r12,0
++ std r12,SLBSHADOW_STACKESID(r9) /* Clear ESID */
++ std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */
++ std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */
++
+ slbie r6
+ slbie r6 /* Workaround POWER5 < DD2.1 issue */
+ slbmte r7,r0
+@@ -454,6 +461,7 @@ _GLOBAL(ret_from_except_lite)
+
+ restore:
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ ld r5,SOFTE(r1)
+ cmpdi 0,r5,0
+ beq 4f
+@@ -472,6 +480,7 @@ restore:
+ b .ret_from_except_lite /* loop back and handle more */
+
+ 4: stb r5,PACAPROCENABLED(r13)
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif
+
+ ld r3,_MSR(r1)
+@@ -530,18 +539,23 @@ do_work:
+ lwz r8,TI_PREEMPT(r9)
+ cmpwi cr1,r8,0
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ ld r0,SOFTE(r1)
+ cmpdi r0,0
+-#else
+- andi. r0,r3,MSR_EE
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif
++BEGIN_FW_FTR_SECTION
++ andi. r0,r3,MSR_EE
++END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
+ crandc eq,cr1*4+eq,eq
+ bne restore
+ /* here we are preempting the current task */
+ 1:
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ li r0,1
+ stb r0,PACAPROCENABLED(r13)
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif
+ ori r10,r10,MSR_EE
+ mtmsrd r10,1 /* reenable interrupts */
+diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
+index 6ff3cf5..e720729 100644
+--- a/arch/powerpc/kernel/head_64.S
++++ b/arch/powerpc/kernel/head_64.S
+@@ -33,6 +33,7 @@
+ #include <asm/hvcall.h>
+ #include <asm/iseries/lpar_map.h>
+ #include <asm/thread_info.h>
++#include <asm/firmware.h>
+
+ #ifdef CONFIG_PPC_ISERIES
+ #define DO_SOFT_DISABLE
+@@ -132,7 +133,7 @@ _GLOBAL(__secondary_hold)
+ bne 100b
+
+ #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
+- LOAD_REG_IMMEDIATE(r4, .pSeries_secondary_smp_init)
++ LOAD_REG_IMMEDIATE(r4, .generic_secondary_smp_init)
+ mtctr r4
+ mr r3,r24
+ bctr
+@@ -365,19 +366,28 @@ label##_iSeries: \
+
+ #ifdef DO_SOFT_DISABLE
+ #define DISABLE_INTS \
++BEGIN_FW_FTR_SECTION; \
+ lbz r10,PACAPROCENABLED(r13); \
+ li r11,0; \
+ std r10,SOFTE(r1); \
+ mfmsr r10; \
+ stb r11,PACAPROCENABLED(r13); \
+ ori r10,r10,MSR_EE; \
+- mtmsrd r10,1
++ mtmsrd r10,1; \
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+
+ #define ENABLE_INTS \
++BEGIN_FW_FTR_SECTION; \
+ lbz r10,PACAPROCENABLED(r13); \
+ mfmsr r11; \
+ std r10,SOFTE(r1); \
+ ori r11,r11,MSR_EE; \
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \
++BEGIN_FW_FTR_SECTION; \
++ ld r12,_MSR(r1); \
++ mfmsr r11; \
++ rlwimi r11,r12,0,MSR_EE; \
++END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \
+ mtmsrd r11,1
+
+ #else /* hard enable/disable interrupts */
+@@ -477,7 +487,7 @@ BEGIN_FTR_SECTION
+ rlwimi r13,r12,16,0x20
+ mfcr r12
+ cmpwi r13,0x2c
+- beq .do_stab_bolted_pSeries
++ beq do_stab_bolted_pSeries
+ mtcrf 0x80,r12
+ mfspr r12,SPRN_SPRG2
+ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+@@ -590,7 +600,7 @@ system_call_pSeries:
+ STD_EXCEPTION_PSERIES(., performance_monitor)
+
+ .align 7
+-_GLOBAL(do_stab_bolted_pSeries)
++do_stab_bolted_pSeries:
+ mtcrf 0x80,r12
+ mfspr r12,SPRN_SPRG2
+ EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
+@@ -1036,7 +1046,7 @@ slb_miss_fault:
+ li r5,0
+ std r4,_DAR(r1)
+ std r5,_DSISR(r1)
+- b .handle_page_fault
++ b handle_page_fault
+
+ unrecov_user_slb:
+ EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN)
+@@ -1071,8 +1081,10 @@ _GLOBAL(slb_miss_realmode)
+ ld r3,PACA_EXSLB+EX_R3(r13)
+ lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ ld r11,PACALPPACAPTR(r13)
+ ld r11,LPPACASRR0(r11) /* get SRR0 value */
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif /* CONFIG_PPC_ISERIES */
+
+ mtlr r10
+@@ -1087,8 +1099,10 @@ _GLOBAL(slb_miss_realmode)
+ .machine pop
+
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ mtspr SPRN_SRR0,r11
+ mtspr SPRN_SRR1,r12
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif /* CONFIG_PPC_ISERIES */
+ ld r9,PACA_EXSLB+EX_R9(r13)
+ ld r10,PACA_EXSLB+EX_R10(r13)
+@@ -1160,12 +1174,13 @@ program_check_common:
+ .globl fp_unavailable_common
+ fp_unavailable_common:
+ EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
+- bne .load_up_fpu /* if from user, just load it up */
++ bne 1f /* if from user, just load it up */
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ ENABLE_INTS
+ bl .kernel_fp_unavailable_exception
+ BUG_OPCODE
++1: b .load_up_fpu
+
+ .align 7
+ .globl altivec_unavailable_common
+@@ -1265,10 +1280,10 @@ _GLOBAL(do_hash_page)
+ std r4,_DSISR(r1)
+
+ andis. r0,r4,0xa450 /* weird error? */
+- bne- .handle_page_fault /* if not, try to insert a HPTE */
++ bne- handle_page_fault /* if not, try to insert a HPTE */
+ BEGIN_FTR_SECTION
+ andis. r0,r4,0x0020 /* Is it a segment table fault? */
+- bne- .do_ste_alloc /* If so handle it */
++ bne- do_ste_alloc /* If so handle it */
+ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+
+ /*
+@@ -1301,6 +1316,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+ cmpdi r3,0 /* see if hash_page succeeded */
+
+ #ifdef DO_SOFT_DISABLE
++BEGIN_FW_FTR_SECTION
+ /*
+ * If we had interrupts soft-enabled at the point where the
+ * DSI/ISI occurred, and an interrupt came in during hash_page,
+@@ -1309,7 +1325,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+ * because ret_from_except_lite will check for and handle pending
+ * interrupts if necessary.
+ */
+- beq .ret_from_except_lite
++ beq 13f
+ /* For a hash failure, we don't bother re-enabling interrupts */
+ ble- 12f
+
+@@ -1321,22 +1337,24 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+ ld r3,SOFTE(r1)
+ bl .local_irq_restore
+ b 11f
+-#else
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
++#endif
++BEGIN_FW_FTR_SECTION
+ beq fast_exception_return /* Return from exception on success */
+ ble- 12f /* Failure return from hash_page */
+
+ /* fall through */
+-#endif
++END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
+
+ /* Here we have a page fault that hash_page can't handle. */
+-_GLOBAL(handle_page_fault)
++handle_page_fault:
+ ENABLE_INTS
+ 11: ld r4,_DAR(r1)
+ ld r5,_DSISR(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .do_page_fault
+ cmpdi r3,0
+- beq+ .ret_from_except_lite
++ beq+ 13f
+ bl .save_nvgprs
+ mr r5,r3
+ addi r3,r1,STACK_FRAME_OVERHEAD
+@@ -1353,12 +1371,14 @@ _GLOBAL(handle_page_fault)
+ bl .low_hash_fault
+ b .ret_from_except
+
++13: b .ret_from_except_lite
++
+ /* here we have a segment miss */
+-_GLOBAL(do_ste_alloc)
++do_ste_alloc:
+ bl .ste_allocate /* try to insert stab entry */
+ cmpdi r3,0
+- beq+ fast_exception_return
+- b .handle_page_fault
++ bne- handle_page_fault
++ b fast_exception_return
+
+ /*
+ * r13 points to the PACA, r9 contains the saved CR,
+@@ -1484,19 +1504,17 @@ fwnmi_data_area:
+ . = 0x8000
+
+ /*
+- * On pSeries, secondary processors spin in the following code.
++ * On pSeries and most other platforms, secondary processors spin
++ * in the following code.
+ * At entry, r3 = this processor's number (physical cpu id)
+ */
+-_GLOBAL(pSeries_secondary_smp_init)
++_GLOBAL(generic_secondary_smp_init)
+ mr r24,r3
+
+ /* turn on 64-bit mode */
+ bl .enable_64b_mode
+ isync
+
+- /* Copy some CPU settings from CPU 0 */
+- bl .__restore_cpu_setup
+-
+ /* Set up a paca value for this processor. Since we have the
+ * physical cpu id in r24, we need to search the pacas to find
+ * which logical id maps to our physical one.
+@@ -1522,15 +1540,28 @@ _GLOBAL(pSeries_secondary_smp_init)
+ /* start. */
+ sync
+
+- /* Create a temp kernel stack for use before relocation is on. */
++#ifndef CONFIG_SMP
++ b 3b /* Never go on non-SMP */
++#else
++ cmpwi 0,r23,0
++ beq 3b /* Loop until told to go */
++
++ /* See if we need to call a cpu state restore handler */
++ LOAD_REG_IMMEDIATE(r23, cur_cpu_spec)
++ ld r23,0(r23)
++ ld r23,CPU_SPEC_RESTORE(r23)
++ cmpdi 0,r23,0
++ beq 4f
++ ld r23,0(r23)
++ mtctr r23
++ bctrl
++
++4: /* Create a temp kernel stack for use before relocation is on. */
+ ld r1,PACAEMERGSP(r13)
+ subi r1,r1,STACK_FRAME_OVERHEAD
+
+- cmpwi 0,r23,0
+-#ifdef CONFIG_SMP
+- bne .__secondary_start
++ b .__secondary_start
+ #endif
+- b 3b /* Loop until told to go */
+
+ #ifdef CONFIG_PPC_ISERIES
+ _STATIC(__start_initialization_iSeries)
+@@ -1552,11 +1583,6 @@ _STATIC(__start_initialization_iSeries)
+ li r0,0
+ stdu r0,-STACK_FRAME_OVERHEAD(r1)
+
+- LOAD_REG_IMMEDIATE(r3,cpu_specs)
+- LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
+- li r5,0
+- bl .identify_cpu
+-
+ LOAD_REG_IMMEDIATE(r2,__toc_start)
+ addi r2,r2,0x4000
+ addi r2,r2,0x4000
+@@ -1611,7 +1637,18 @@ _GLOBAL(__start_initialization_multiplat
+ bl .enable_64b_mode
+
+ /* Setup some critical 970 SPRs before switching MMU off */
+- bl .__970_cpu_preinit
++ mfspr r0,SPRN_PVR
++ srwi r0,r0,16
++ cmpwi r0,0x39 /* 970 */
++ beq 1f
++ cmpwi r0,0x3c /* 970FX */
++ beq 1f
++ cmpwi r0,0x44 /* 970MP */
++ beq 1f
++ cmpwi r0,0x45 /* 970GX */
++ bne 2f
++1: bl .__cpu_preinit_ppc970
++2:
+
+ /* Switch off MMU if not already */
+ LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
+@@ -1728,7 +1765,7 @@ _STATIC(__after_prom_start)
+ _GLOBAL(copy_and_flush)
+ addi r5,r5,-8
+ addi r6,r6,-8
+-4: li r0,16 /* Use the least common */
++4: li r0,8 /* Use the smallest common */
+ /* denominator cache line */
+ /* size. This results in */
+ /* extra cache line flushes */
+@@ -1782,7 +1819,7 @@ _GLOBAL(pmac_secondary_start)
+ isync
+
+ /* Copy some CPU settings from CPU 0 */
+- bl .__restore_cpu_setup
++ bl .__restore_cpu_ppc970
+
+ /* pSeries do that early though I don't think we really need it */
+ mfmsr r3
+@@ -1841,7 +1878,9 @@ _GLOBAL(__secondary_start)
+ LOAD_REG_ADDR(r3, .start_secondary_prolog)
+ LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
+ #ifdef DO_SOFT_DISABLE
++BEGIN_FW_FTR_SECTION
+ ori r4,r4,MSR_EE
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif
+ mtspr SPRN_SRR0,r3
+ mtspr SPRN_SRR1,r4
+@@ -1925,19 +1964,6 @@ _STATIC(start_here_multiplatform)
+ addi r2,r2,0x4000
+ add r2,r2,r26
+
+- LOAD_REG_IMMEDIATE(r3, cpu_specs)
+- add r3,r3,r26
+- LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
+- add r4,r4,r26
+- mr r5,r26
+- bl .identify_cpu
+-
+- /* Save some low level config HIDs of CPU0 to be copied to
+- * other CPUs later on, or used for suspend/resume
+- */
+- bl .__save_cpu_setup
+- sync
+-
+ /* Do very early kernel initializations, including initial hash table,
+ * stab and slb setup before we turn on relocation. */
+
+@@ -1967,12 +1993,6 @@ _STATIC(start_here_common)
+ li r0,0
+ stdu r0,-STACK_FRAME_OVERHEAD(r1)
+
+- /* Apply the CPUs-specific fixups (nop out sections not relevant
+- * to this CPU
+- */
+- li r3,0
+- bl .do_cpu_ftr_fixups
+-
+ /* ptr to current */
+ LOAD_REG_IMMEDIATE(r4, init_task)
+ std r4,PACACURRENT(r13)
+@@ -1986,11 +2006,13 @@ _STATIC(start_here_common)
+ /* Load up the kernel context */
+ 5:
+ #ifdef DO_SOFT_DISABLE
++BEGIN_FW_FTR_SECTION
+ li r5,0
+ stb r5,PACAPROCENABLED(r13) /* Soft Disabled */
+ mfmsr r5
+ ori r5,r5,MSR_EE /* Hard Enabled */
+ mtmsrd r5
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif
+
+ bl .start_kernel
+diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
+index 68e5ab0..39db7a3 100644
+--- a/arch/powerpc/kernel/ibmebus.c
++++ b/arch/powerpc/kernel/ibmebus.c
+@@ -167,7 +167,7 @@ static DEVICE_ATTR(name, S_IRUSR | S_IRG
+ NULL);
+
+ static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+- struct ibmebus_dev *dev, char *name)
++ struct ibmebus_dev *dev, const char *name)
+ {
+ int err = 0;
+
+@@ -194,10 +194,10 @@ static struct ibmebus_dev* __devinit ibm
+ struct device_node *dn)
+ {
+ struct ibmebus_dev *dev;
+- char *loc_code;
++ const char *loc_code;
+ int length;
+
+- loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
++ loc_code = get_property(dn, "ibm,loc-code", NULL);
+ if (!loc_code) {
+ printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
+ __FUNCTION__, dn->name ? dn->name : "<unknown>");
+@@ -319,7 +319,7 @@ EXPORT_SYMBOL(ibmebus_unregister_driver)
+
+ int ibmebus_request_irq(struct ibmebus_dev *dev,
+ u32 ist,
+- irqreturn_t (*handler)(int, void*, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irq_flags, const char * devname,
+ void *dev_id)
+ {
+diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c
+new file mode 100644
+index 0000000..e981806
+--- /dev/null
++++ b/arch/powerpc/kernel/io.c
+@@ -0,0 +1,131 @@
++/*
++ * I/O string operations
++ * Copyright (C) 1995-1996 Gary Thomas (gdt at linuxppc.org)
++ * Copyright (C) 2006 IBM Corporation
++ *
++ * Largely rewritten by Cort Dougan (cort at cs.nmt.edu)
++ * and Paul Mackerras.
++ *
++ * Adapted for iSeries by Mike Corrigan (mikejc at us.ibm.com)
++ * PPC64 updates by Dave Engebretsen (engebret at us.ibm.com)
++ *
++ * Rewritten in C by Stephen Rothwell.
++ *
++ * 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/types.h>
++#include <linux/compiler.h>
++#include <linux/module.h>
++
++#include <asm/io.h>
++#include <asm/firmware.h>
++#include <asm/bug.h>
++
++void _insb(volatile u8 __iomem *port, void *buf, long count)
++{
++ u8 *tbuf = buf;
++ u8 tmp;
++
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ if (unlikely(count <= 0))
++ return;
++ asm volatile("sync");
++ do {
++ tmp = *port;
++ asm volatile("eieio");
++ *tbuf++ = tmp;
++ } while (--count != 0);
++ asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
++}
++EXPORT_SYMBOL(_insb);
++
++void _outsb(volatile u8 __iomem *port, const void *buf, long count)
++{
++ const u8 *tbuf = buf;
++
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ if (unlikely(count <= 0))
++ return;
++ asm volatile("sync");
++ do {
++ *port = *tbuf++;
++ } while (--count != 0);
++ asm volatile("sync");
++}
++EXPORT_SYMBOL(_outsb);
++
++void _insw_ns(volatile u16 __iomem *port, void *buf, long count)
++{
++ u16 *tbuf = buf;
++ u16 tmp;
++
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ if (unlikely(count <= 0))
++ return;
++ asm volatile("sync");
++ do {
++ tmp = *port;
++ asm volatile("eieio");
++ *tbuf++ = tmp;
++ } while (--count != 0);
++ asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
++}
++EXPORT_SYMBOL(_insw_ns);
++
++void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count)
++{
++ const u16 *tbuf = buf;
++
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ if (unlikely(count <= 0))
++ return;
++ asm volatile("sync");
++ do {
++ *port = *tbuf++;
++ } while (--count != 0);
++ asm volatile("sync");
++}
++EXPORT_SYMBOL(_outsw_ns);
++
++void _insl_ns(volatile u32 __iomem *port, void *buf, long count)
++{
++ u32 *tbuf = buf;
++ u32 tmp;
++
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ if (unlikely(count <= 0))
++ return;
++ asm volatile("sync");
++ do {
++ tmp = *port;
++ asm volatile("eieio");
++ *tbuf++ = tmp;
++ } while (--count != 0);
++ asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
++}
++EXPORT_SYMBOL(_insl_ns);
++
++void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count)
++{
++ const u32 *tbuf = buf;
++
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ if (unlikely(count <= 0))
++ return;
++ asm volatile("sync");
++ do {
++ *port = *tbuf++;
++ } while (--count != 0);
++ asm volatile("sync");
++}
++EXPORT_SYMBOL(_outsl_ns);
+diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
+index ba06940..ba6b725 100644
+--- a/arch/powerpc/kernel/iommu.c
++++ b/arch/powerpc/kernel/iommu.c
+@@ -47,6 +47,17 @@ static int novmerge = 0;
+ static int novmerge = 1;
+ #endif
+
++static inline unsigned long iommu_num_pages(unsigned long vaddr,
++ unsigned long slen)
++{
++ unsigned long npages;
++
++ npages = IOMMU_PAGE_ALIGN(vaddr + slen) - (vaddr & IOMMU_PAGE_MASK);
++ npages >>= IOMMU_PAGE_SHIFT;
++
++ return npages;
++}
++
+ static int __init setup_iommu(char *str)
+ {
+ if (!strcmp(str, "novmerge"))
+@@ -75,7 +86,7 @@ static unsigned long iommu_range_alloc(s
+ /* This allocator was derived from x86_64's bit string search */
+
+ /* Sanity check */
+- if (unlikely(npages) == 0) {
++ if (unlikely(npages == 0)) {
+ if (printk_ratelimit())
+ WARN_ON(1);
+ return DMA_ERROR_CODE;
+@@ -178,10 +189,10 @@ static dma_addr_t iommu_alloc(struct iom
+ }
+
+ entry += tbl->it_offset; /* Offset into real TCE table */
+- ret = entry << PAGE_SHIFT; /* Set the return dma address */
++ ret = entry << IOMMU_PAGE_SHIFT; /* Set the return dma address */
+
+ /* Put the TCEs in the HW table */
+- ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & PAGE_MASK,
++ ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & IOMMU_PAGE_MASK,
+ direction);
+
+
+@@ -203,7 +214,7 @@ static void __iommu_free(struct iommu_ta
+ unsigned long entry, free_entry;
+ unsigned long i;
+
+- entry = dma_addr >> PAGE_SHIFT;
++ entry = dma_addr >> IOMMU_PAGE_SHIFT;
+ free_entry = entry - tbl->it_offset;
+
+ if (((free_entry + npages) > tbl->it_size) ||
+@@ -270,7 +281,7 @@ int iommu_map_sg(struct device *dev, str
+ /* Init first segment length for backout at failure */
+ outs->dma_length = 0;
+
+- DBG("mapping %d elements:\n", nelems);
++ DBG("sg mapping %d elements:\n", nelems);
+
+ spin_lock_irqsave(&(tbl->it_lock), flags);
+
+@@ -285,9 +296,8 @@ int iommu_map_sg(struct device *dev, str
+ }
+ /* Allocate iommu entries for that segment */
+ vaddr = (unsigned long)page_address(s->page) + s->offset;
+- npages = PAGE_ALIGN(vaddr + slen) - (vaddr & PAGE_MASK);
+- npages >>= PAGE_SHIFT;
+- entry = iommu_range_alloc(tbl, npages, &handle, mask >> PAGE_SHIFT, 0);
++ npages = iommu_num_pages(vaddr, slen);
++ entry = iommu_range_alloc(tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, 0);
+
+ DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen);
+
+@@ -301,14 +311,14 @@ int iommu_map_sg(struct device *dev, str
+
+ /* Convert entry to a dma_addr_t */
+ entry += tbl->it_offset;
+- dma_addr = entry << PAGE_SHIFT;
+- dma_addr |= s->offset;
++ dma_addr = entry << IOMMU_PAGE_SHIFT;
++ dma_addr |= (s->offset & ~IOMMU_PAGE_MASK);
+
+- DBG(" - %lx pages, entry: %lx, dma_addr: %lx\n",
++ DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n",
+ npages, entry, dma_addr);
+
+ /* Insert into HW table */
+- ppc_md.tce_build(tbl, entry, npages, vaddr & PAGE_MASK, direction);
++ ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction);
+
+ /* If we are in an open segment, try merging */
+ if (segstart != s) {
+@@ -323,7 +333,7 @@ int iommu_map_sg(struct device *dev, str
+ DBG(" can't merge, new segment.\n");
+ } else {
+ outs->dma_length += s->length;
+- DBG(" merged, new len: %lx\n", outs->dma_length);
++ DBG(" merged, new len: %ux\n", outs->dma_length);
+ }
+ }
+
+@@ -367,9 +377,8 @@ int iommu_map_sg(struct device *dev, str
+ if (s->dma_length != 0) {
+ unsigned long vaddr, npages;
+
+- vaddr = s->dma_address & PAGE_MASK;
+- npages = (PAGE_ALIGN(s->dma_address + s->dma_length) - vaddr)
+- >> PAGE_SHIFT;
++ vaddr = s->dma_address & IOMMU_PAGE_MASK;
++ npages = iommu_num_pages(s->dma_address, s->dma_length);
+ __iommu_free(tbl, vaddr, npages);
+ s->dma_address = DMA_ERROR_CODE;
+ s->dma_length = 0;
+@@ -398,8 +407,7 @@ void iommu_unmap_sg(struct iommu_table *
+
+ if (sglist->dma_length == 0)
+ break;
+- npages = (PAGE_ALIGN(dma_handle + sglist->dma_length)
+- - (dma_handle & PAGE_MASK)) >> PAGE_SHIFT;
++ npages = iommu_num_pages(dma_handle,sglist->dma_length);
+ __iommu_free(tbl, dma_handle, npages);
+ sglist++;
+ }
+@@ -532,12 +540,11 @@ dma_addr_t iommu_map_single(struct iommu
+ BUG_ON(direction == DMA_NONE);
+
+ uaddr = (unsigned long)vaddr;
+- npages = PAGE_ALIGN(uaddr + size) - (uaddr & PAGE_MASK);
+- npages >>= PAGE_SHIFT;
++ npages = iommu_num_pages(uaddr, size);
+
+ if (tbl) {
+ dma_handle = iommu_alloc(tbl, vaddr, npages, direction,
+- mask >> PAGE_SHIFT, 0);
++ mask >> IOMMU_PAGE_SHIFT, 0);
+ if (dma_handle == DMA_ERROR_CODE) {
+ if (printk_ratelimit()) {
+ printk(KERN_INFO "iommu_alloc failed, "
+@@ -545,7 +552,7 @@ dma_addr_t iommu_map_single(struct iommu
+ tbl, vaddr, npages);
+ }
+ } else
+- dma_handle |= (uaddr & ~PAGE_MASK);
++ dma_handle |= (uaddr & ~IOMMU_PAGE_MASK);
+ }
+
+ return dma_handle;
+@@ -554,11 +561,14 @@ dma_addr_t iommu_map_single(struct iommu
+ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+ {
++ unsigned int npages;
++
+ BUG_ON(direction == DMA_NONE);
+
+- if (tbl)
+- iommu_free(tbl, dma_handle, (PAGE_ALIGN(dma_handle + size) -
+- (dma_handle & PAGE_MASK)) >> PAGE_SHIFT);
++ if (tbl) {
++ npages = iommu_num_pages(dma_handle, size);
++ iommu_free(tbl, dma_handle, npages);
++ }
+ }
+
+ /* Allocates a contiguous real buffer and creates mappings over it.
+@@ -570,11 +580,11 @@ void *iommu_alloc_coherent(struct iommu_
+ {
+ void *ret = NULL;
+ dma_addr_t mapping;
+- unsigned int npages, order;
++ unsigned int order;
++ unsigned int nio_pages, io_order;
+ struct page *page;
+
+ size = PAGE_ALIGN(size);
+- npages = size >> PAGE_SHIFT;
+ order = get_order(size);
+
+ /*
+@@ -598,8 +608,10 @@ void *iommu_alloc_coherent(struct iommu_
+ memset(ret, 0, size);
+
+ /* Set up tces to cover the allocated range */
+- mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL,
+- mask >> PAGE_SHIFT, order);
++ nio_pages = size >> IOMMU_PAGE_SHIFT;
++ io_order = get_iommu_order(size);
++ mapping = iommu_alloc(tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
++ mask >> IOMMU_PAGE_SHIFT, io_order);
+ if (mapping == DMA_ERROR_CODE) {
+ free_pages((unsigned long)ret, order);
+ return NULL;
+@@ -611,12 +623,13 @@ void *iommu_alloc_coherent(struct iommu_
+ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+ {
+- unsigned int npages;
+-
+ if (tbl) {
++ unsigned int nio_pages;
++
++ size = PAGE_ALIGN(size);
++ nio_pages = size >> IOMMU_PAGE_SHIFT;
++ iommu_free(tbl, dma_handle, nio_pages);
+ size = PAGE_ALIGN(size);
+- npages = size >> PAGE_SHIFT;
+- iommu_free(tbl, dma_handle, npages);
+ free_pages((unsigned long)vaddr, get_order(size));
+ }
+ }
+diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
+index 12c5971..5e37bf1 100644
+--- a/arch/powerpc/kernel/irq.c
++++ b/arch/powerpc/kernel/irq.c
+@@ -52,6 +52,7 @@
+ #include <linux/radix-tree.h>
+ #include <linux/mutex.h>
+ #include <linux/bootmem.h>
++#include <linux/pci.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -186,6 +187,7 @@ void fixup_irqs(cpumask_t map)
+
+ void do_IRQ(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
+ unsigned int irq;
+ #ifdef CONFIG_IRQSTACKS
+ struct thread_info *curtp, *irqtp;
+@@ -215,7 +217,7 @@ void do_IRQ(struct pt_regs *regs)
+ * The value -2 is for buggy hardware and means that this IRQ
+ * has already been handled. -- Tom
+ */
+- irq = ppc_md.get_irq(regs);
++ irq = ppc_md.get_irq();
+
+ if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
+ #ifdef CONFIG_IRQSTACKS
+@@ -229,18 +231,19 @@ void do_IRQ(struct pt_regs *regs)
+ handler = &__do_IRQ;
+ irqtp->task = curtp->task;
+ irqtp->flags = 0;
+- call_handle_irq(irq, desc, regs, irqtp, handler);
++ call_handle_irq(irq, desc, irqtp, handler);
+ irqtp->task = NULL;
+ if (irqtp->flags)
+ set_bits(irqtp->flags, &curtp->flags);
+ } else
+ #endif
+- generic_handle_irq(irq, regs);
++ generic_handle_irq(irq);
+ } else if (irq != NO_IRQ_IGNORE)
+ /* That's not SMP safe ... but who cares ? */
+ ppc_spurious_interrupts++;
+
+ irq_exit();
++ set_irq_regs(old_regs);
+
+ #ifdef CONFIG_PPC_ISERIES
+ if (get_lppaca()->int_dword.fields.decr_int) {
+@@ -569,8 +572,8 @@ unsigned int irq_create_mapping(struct i
+ }
+ EXPORT_SYMBOL_GPL(irq_create_mapping);
+
+-extern unsigned int irq_create_of_mapping(struct device_node *controller,
+- u32 *intspec, unsigned int intsize)
++unsigned int irq_create_of_mapping(struct device_node *controller,
++ u32 *intspec, unsigned int intsize)
+ {
+ struct irq_host *host;
+ irq_hw_number_t hwirq;
+@@ -776,7 +779,6 @@ unsigned int irq_alloc_virt(struct irq_h
+ {
+ unsigned long flags;
+ unsigned int i, j, found = NO_IRQ;
+- unsigned int limit = irq_virq_count - count;
+
+ if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
+ return NO_IRQ;
+@@ -793,14 +795,16 @@ unsigned int irq_alloc_virt(struct irq_h
+ /* Look for count consecutive numbers in the allocatable
+ * (non-legacy) space
+ */
+- for (i = NUM_ISA_INTERRUPTS; i <= limit; ) {
+- for (j = i; j < (i + count); j++)
+- if (irq_map[j].host != NULL) {
+- i = j + 1;
+- continue;
+- }
+- found = i;
+- break;
++ for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
++ if (irq_map[i].host != NULL)
++ j = 0;
++ else
++ j++;
++
++ if (j == count) {
++ found = i - count + 1;
++ break;
++ }
+ }
+ if (found == NO_IRQ) {
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+@@ -875,12 +879,14 @@ int pci_enable_msi(struct pci_dev * pdev
+ else
+ return -1;
+ }
++EXPORT_SYMBOL(pci_enable_msi);
+
+ void pci_disable_msi(struct pci_dev * pdev)
+ {
+ if (ppc_md.disable_msi)
+ ppc_md.disable_msi(pdev);
+ }
++EXPORT_SYMBOL(pci_disable_msi);
+
+ void pci_scan_msi_device(struct pci_dev *dev) {}
+ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
+@@ -888,6 +894,8 @@ void pci_disable_msix(struct pci_dev *de
+ void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+ void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
+ void pci_no_msi(void) {}
++EXPORT_SYMBOL(pci_enable_msix);
++EXPORT_SYMBOL(pci_disable_msix);
+
+ #endif
+
+diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
+index cd65c36..7b8d12b 100644
+--- a/arch/powerpc/kernel/kprobes.c
++++ b/arch/powerpc/kernel/kprobes.c
+@@ -259,14 +259,15 @@ void kretprobe_trampoline_holder(void)
+ */
+ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+ {
+- struct kretprobe_instance *ri = NULL;
+- struct hlist_head *head;
+- struct hlist_node *node, *tmp;
++ struct kretprobe_instance *ri = NULL;
++ struct hlist_head *head, empty_rp;
++ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+
++ INIT_HLIST_HEAD(&empty_rp);
+ spin_lock_irqsave(&kretprobe_lock, flags);
+- head = kretprobe_inst_table_head(current);
++ head = kretprobe_inst_table_head(current);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+@@ -277,20 +278,20 @@ int __kprobes trampoline_probe_handler(s
+ * 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
++ * 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)
++ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+- continue;
++ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+- recycle_rp_inst(ri);
++ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+@@ -308,12 +309,16 @@ int __kprobes trampoline_probe_handler(s
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ preempt_enable_no_resched();
+
+- /*
+- * By returning a non-zero value, we are telling
+- * kprobe_handler() that we don't want the post_handler
+- * to run (and have re-enabled preemption)
+- */
+- return 1;
++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++ hlist_del(&ri->hlist);
++ kfree(ri);
++ }
++ /*
++ * By returning a non-zero value, we are telling
++ * kprobe_handler() that we don't want the post_handler
++ * to run (and have re-enabled preemption)
++ */
++ return 1;
+ }
+
+ /*
+diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
+index 40a3929..5e6ddfa 100644
+--- a/arch/powerpc/kernel/legacy_serial.c
++++ b/arch/powerpc/kernel/legacy_serial.c
+@@ -39,16 +39,17 @@ static int __init add_legacy_port(struct
+ phys_addr_t taddr, unsigned long irq,
+ upf_t flags, int irq_check_parent)
+ {
+- u32 *clk, *spd, clock = BASE_BAUD * 16;
++ const u32 *clk, *spd;
++ u32 clock = BASE_BAUD * 16;
+ int index;
+
+ /* get clock freq. if present */
+- clk = (u32 *)get_property(np, "clock-frequency", NULL);
++ clk = get_property(np, "clock-frequency", NULL);
+ if (clk && *clk)
+ clock = *clk;
+
+ /* get default speed if present */
+- spd = (u32 *)get_property(np, "current-speed", NULL);
++ spd = get_property(np, "current-speed", NULL);
+
+ /* If we have a location index, then try to use it */
+ if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
+@@ -113,7 +114,7 @@ static int __init add_legacy_soc_port(st
+ struct device_node *soc_dev)
+ {
+ u64 addr;
+- u32 *addrp;
++ const u32 *addrp;
+ upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ struct device_node *tsi = of_get_parent(np);
+
+@@ -144,15 +145,15 @@ static int __init add_legacy_soc_port(st
+ static int __init add_legacy_isa_port(struct device_node *np,
+ struct device_node *isa_brg)
+ {
+- u32 *reg;
+- char *typep;
++ const u32 *reg;
++ const char *typep;
+ int index = -1;
+ u64 taddr;
+
+ DBG(" -> add_legacy_isa_port(%s)\n", np->full_name);
+
+ /* Get the ISA port number */
+- reg = (u32 *)get_property(np, "reg", NULL);
++ reg = get_property(np, "reg", NULL);
+ if (reg == NULL)
+ return -1;
+
+@@ -163,7 +164,7 @@ static int __init add_legacy_isa_port(st
+ /* Now look for an "ibm,aix-loc" property that gives us ordering
+ * if any...
+ */
+- typep = (char *)get_property(np, "ibm,aix-loc", NULL);
++ typep = get_property(np, "ibm,aix-loc", NULL);
+
+ /* If we have a location index, then use it */
+ if (typep && *typep == 'S')
+@@ -188,7 +189,7 @@ static int __init add_legacy_pci_port(st
+ struct device_node *pci_dev)
+ {
+ u64 addr, base;
+- u32 *addrp;
++ const u32 *addrp;
+ unsigned int flags;
+ int iotype, index = -1, lindex = 0;
+
+@@ -227,7 +228,7 @@ static int __init add_legacy_pci_port(st
+ * we get to their "reg" property
+ */
+ if (np != pci_dev) {
+- u32 *reg = (u32 *)get_property(np, "reg", NULL);
++ const u32 *reg = get_property(np, "reg", NULL);
+ if (reg && (*reg < 4))
+ index = lindex = *reg;
+ }
+@@ -285,13 +286,13 @@ static void __init setup_legacy_serial_c
+ void __init find_legacy_serial_ports(void)
+ {
+ struct device_node *np, *stdout = NULL;
+- char *path;
++ const char *path;
+ int index;
+
+ DBG(" -> find_legacy_serial_port()\n");
+
+ /* Now find out if one of these is out firmware console */
+- path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
++ path = get_property(of_chosen, "linux,stdout-path", NULL);
+ if (path != NULL) {
+ stdout = of_find_node_by_path(path);
+ if (stdout)
+@@ -491,8 +492,8 @@ static int __init check_legacy_serial_co
+ {
+ struct device_node *prom_stdout = NULL;
+ int speed = 0, offset = 0;
+- char *name;
+- u32 *spd;
++ const char *name;
++ const u32 *spd;
+
+ DBG(" -> check_legacy_serial_console()\n");
+
+@@ -513,7 +514,7 @@ static int __init check_legacy_serial_co
+ }
+ /* We are getting a weird phandle from OF ... */
+ /* ... So use the full path instead */
+- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
++ name = get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL) {
+ DBG(" no linux,stdout-path !\n");
+ return -ENODEV;
+@@ -525,12 +526,12 @@ static int __init check_legacy_serial_co
+ }
+ DBG("stdout is %s\n", prom_stdout->full_name);
+
+- name = (char *)get_property(prom_stdout, "name", NULL);
++ name = get_property(prom_stdout, "name", NULL);
+ if (!name) {
+ DBG(" stdout package has no name !\n");
+ goto not_found;
+ }
+- spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
++ spd = get_property(prom_stdout, "current-speed", NULL);
+ if (spd)
+ speed = *spd;
+
+diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
+index 23f34da..41c05dc 100644
+--- a/arch/powerpc/kernel/lparcfg.c
++++ b/arch/powerpc/kernel/lparcfg.c
+@@ -32,7 +32,6 @@
+ #include <asm/rtas.h>
+ #include <asm/system.h>
+ #include <asm/time.h>
+-#include <asm/iseries/it_exp_vpd_panel.h>
+ #include <asm/prom.h>
+ #include <asm/vdso_datapage.h>
+
+@@ -183,8 +182,14 @@ static unsigned int h_get_ppp(unsigned l
+ unsigned long *resource)
+ {
+ unsigned long rc;
+- rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated,
+- aggregation, resource);
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_GET_PPP, retbuf);
++
++ *entitled = retbuf[0];
++ *unallocated = retbuf[1];
++ *aggregation = retbuf[2];
++ *resource = retbuf[3];
+
+ log_plpar_hcall_return(rc, "H_GET_PPP");
+
+@@ -194,8 +199,12 @@ static unsigned int h_get_ppp(unsigned l
+ static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)
+ {
+ unsigned long rc;
+- unsigned long dummy;
+- rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy);
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_PIC, retbuf);
++
++ *pool_idle_time = retbuf[0];
++ *num_procs = retbuf[1];
+
+ if (rc != H_AUTHORITY)
+ log_plpar_hcall_return(rc, "H_PIC");
+@@ -310,12 +319,11 @@ static int pseries_lparcfg_data(struct s
+ int partition_potential_processors;
+ int partition_active_processors;
+ struct device_node *rtas_node;
+- int *lrdrp = NULL;
++ const int *lrdrp = NULL;
+
+ rtas_node = find_path_device("/rtas");
+ if (rtas_node)
+- lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity",
+- NULL);
++ lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL);
+
+ if (lrdrp == NULL) {
+ partition_potential_processors = vdso_data->processorCount;
+@@ -520,7 +528,8 @@ static int lparcfg_data(struct seq_file
+ const char *model = "";
+ const char *system_id = "";
+ const char *tmp;
+- unsigned int *lp_index_ptr, lp_index = 0;
++ const unsigned int *lp_index_ptr;
++ unsigned int lp_index = 0;
+
+ seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
+
+@@ -540,8 +549,7 @@ static int lparcfg_data(struct seq_file
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ system_id += 4;
+ }
+- lp_index_ptr = (unsigned int *)
+- get_property(rootdn, "ibm,partition-no", NULL);
++ lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+ if (lp_index_ptr)
+ lp_index = *lp_index_ptr;
+ }
+diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
+index be58985..a24b09c 100644
+--- a/arch/powerpc/kernel/machine_kexec_64.c
++++ b/arch/powerpc/kernel/machine_kexec_64.c
+@@ -31,8 +31,8 @@ int default_machine_kexec_prepare(struct
+ 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;
++ const unsigned long *basep;
++ const unsigned int *sizep;
+
+ if (!ppc_md.hpte_clear_all)
+ return -ENOENT;
+@@ -72,10 +72,8 @@ int default_machine_kexec_prepare(struct
+ /* 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);
++ basep = get_property(node, "linux,tce-base", NULL);
++ sizep = get_property(node, "linux,tce-size", NULL);
+ if (basep == NULL || sizep == NULL)
+ continue;
+
+diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
+index f770805..330c9dc 100644
+--- a/arch/powerpc/kernel/misc.S
++++ b/arch/powerpc/kernel/misc.S
+@@ -43,162 +43,3 @@ _GLOBAL(add_reloc_offset)
+ add r3,r3,r5
+ mtlr r0
+ blr
+-
+-/*
+- * I/O string operations
+- *
+- * insb(port, buf, len)
+- * outsb(port, buf, len)
+- * insw(port, buf, len)
+- * outsw(port, buf, len)
+- * insl(port, buf, len)
+- * outsl(port, buf, len)
+- * insw_ns(port, buf, len)
+- * outsw_ns(port, buf, len)
+- * insl_ns(port, buf, len)
+- * outsl_ns(port, buf, len)
+- *
+- * The *_ns versions don't do byte-swapping.
+- */
+-_GLOBAL(_insb)
+- sync
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,1
+- blelr-
+-00: lbz r5,0(r3)
+- eieio
+- stbu r5,1(r4)
+- bdnz 00b
+- twi 0,r5,0
+- isync
+- blr
+-
+-_GLOBAL(_outsb)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,1
+- blelr-
+- sync
+-00: lbzu r5,1(r4)
+- stb r5,0(r3)
+- bdnz 00b
+- sync
+- blr
+-
+-_GLOBAL(_insw)
+- sync
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,2
+- blelr-
+-00: lhbrx r5,0,r3
+- eieio
+- sthu r5,2(r4)
+- bdnz 00b
+- twi 0,r5,0
+- isync
+- blr
+-
+-_GLOBAL(_outsw)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,2
+- blelr-
+- sync
+-00: lhzu r5,2(r4)
+- sthbrx r5,0,r3
+- bdnz 00b
+- sync
+- blr
+-
+-_GLOBAL(_insl)
+- sync
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,4
+- blelr-
+-00: lwbrx r5,0,r3
+- eieio
+- stwu r5,4(r4)
+- bdnz 00b
+- twi 0,r5,0
+- isync
+- blr
+-
+-_GLOBAL(_outsl)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,4
+- blelr-
+- sync
+-00: lwzu r5,4(r4)
+- stwbrx r5,0,r3
+- bdnz 00b
+- sync
+- blr
+-
+-#ifdef CONFIG_PPC32
+-_GLOBAL(__ide_mm_insw)
+-#endif
+-_GLOBAL(_insw_ns)
+- sync
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,2
+- blelr-
+-00: lhz r5,0(r3)
+- eieio
+- sthu r5,2(r4)
+- bdnz 00b
+- twi 0,r5,0
+- isync
+- blr
+-
+-#ifdef CONFIG_PPC32
+-_GLOBAL(__ide_mm_outsw)
+-#endif
+-_GLOBAL(_outsw_ns)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,2
+- blelr-
+- sync
+-00: lhzu r5,2(r4)
+- sth r5,0(r3)
+- bdnz 00b
+- sync
+- blr
+-
+-#ifdef CONFIG_PPC32
+-_GLOBAL(__ide_mm_insl)
+-#endif
+-_GLOBAL(_insl_ns)
+- sync
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,4
+- blelr-
+-00: lwz r5,0(r3)
+- eieio
+- stwu r5,4(r4)
+- bdnz 00b
+- twi 0,r5,0
+- isync
+- blr
+-
+-#ifdef CONFIG_PPC32
+-_GLOBAL(__ide_mm_outsl)
+-#endif
+-_GLOBAL(_outsl_ns)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,4
+- blelr-
+- sync
+-00: lwzu r5,4(r4)
+- stw r5,0(r3)
+- bdnz 00b
+- sync
+- blr
+-
+diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
+index 58758d8..412bea3 100644
+--- a/arch/powerpc/kernel/misc_32.S
++++ b/arch/powerpc/kernel/misc_32.S
+@@ -102,80 +102,6 @@ _GLOBAL(reloc_got2)
+ blr
+
+ /*
+- * identify_cpu,
+- * called with r3 = data offset and r4 = CPU number
+- * doesn't change r3
+- */
+-_GLOBAL(identify_cpu)
+- addis r8,r3,cpu_specs at ha
+- addi r8,r8,cpu_specs at l
+- mfpvr r7
+-1:
+- lwz r5,CPU_SPEC_PVR_MASK(r8)
+- and r5,r5,r7
+- lwz r6,CPU_SPEC_PVR_VALUE(r8)
+- cmplw 0,r6,r5
+- beq 1f
+- addi r8,r8,CPU_SPEC_ENTRY_SIZE
+- b 1b
+-1:
+- addis r6,r3,cur_cpu_spec at ha
+- addi r6,r6,cur_cpu_spec at l
+- sub r8,r8,r3
+- stw r8,0(r6)
+- blr
+-
+-/*
+- * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
+- * and writes nop's over sections of code that don't apply for this cpu.
+- * r3 = data offset (not changed)
+- */
+-_GLOBAL(do_cpu_ftr_fixups)
+- /* Get CPU 0 features */
+- addis r6,r3,cur_cpu_spec at ha
+- addi r6,r6,cur_cpu_spec at l
+- lwz r4,0(r6)
+- add r4,r4,r3
+- lwz r4,CPU_SPEC_FEATURES(r4)
+-
+- /* Get the fixup table */
+- addis r6,r3,__start___ftr_fixup at ha
+- addi r6,r6,__start___ftr_fixup at l
+- addis r7,r3,__stop___ftr_fixup at ha
+- addi r7,r7,__stop___ftr_fixup at l
+-
+- /* Do the fixup */
+-1: cmplw 0,r6,r7
+- bgelr
+- addi r6,r6,16
+- lwz r8,-16(r6) /* mask */
+- and r8,r8,r4
+- lwz r9,-12(r6) /* value */
+- cmplw 0,r8,r9
+- beq 1b
+- lwz r8,-8(r6) /* section begin */
+- lwz r9,-4(r6) /* section end */
+- subf. r9,r8,r9
+- beq 1b
+- /* write nops over the section of code */
+- /* todo: if large section, add a branch at the start of it */
+- srwi r9,r9,2
+- mtctr r9
+- add r8,r8,r3
+- lis r0,0x60000000 at h /* nop */
+-3: stw r0,0(r8)
+- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE at l
+- beq 2f
+- dcbst 0,r8 /* suboptimal, but simpler */
+- sync
+- icbi 0,r8
+-2: addi r8,r8,4
+- bdnz 3b
+- sync /* additional sync needed on g4 */
+- isync
+- b 1b
+-
+-/*
+ * call_setup_cpu - call the setup_cpu function for this cpu
+ * r3 = data offset, r24 = cpu number
+ *
+@@ -843,7 +769,7 @@ _GLOBAL(kernel_thread)
+ addi r1,r1,16
+ blr
+
+-_GLOBAL(execve)
++_GLOBAL(kernel_execve)
+ li r0,__NR_execve
+ sc
+ bnslr
+diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
+index e3ed21c..21fd2c6 100644
+--- a/arch/powerpc/kernel/misc_64.S
++++ b/arch/powerpc/kernel/misc_64.S
+@@ -52,12 +52,12 @@ _GLOBAL(call_do_softirq)
+ blr
+
+ _GLOBAL(call_handle_irq)
+- ld r8,0(r7)
++ ld r8,0(r6)
+ mflr r0
+ std r0,16(r1)
+ mtctr r8
+- stdu r1,THREAD_SIZE-112(r6)
+- mr r1,r6
++ stdu r1,THREAD_SIZE-112(r5)
++ mr r1,r5
+ bctrl
+ ld r1,0(r1)
+ ld r0,16(r1)
+@@ -246,84 +246,6 @@ _GLOBAL(__flush_dcache_icache)
+ isync
+ blr
+
+-/*
+- * identify_cpu and calls setup_cpu
+- * In: r3 = base of the cpu_specs array
+- * r4 = address of cur_cpu_spec
+- * r5 = relocation offset
+- */
+-_GLOBAL(identify_cpu)
+- mfpvr r7
+-1:
+- lwz r8,CPU_SPEC_PVR_MASK(r3)
+- and r8,r8,r7
+- lwz r9,CPU_SPEC_PVR_VALUE(r3)
+- cmplw 0,r9,r8
+- beq 1f
+- addi r3,r3,CPU_SPEC_ENTRY_SIZE
+- b 1b
+-1:
+- sub r0,r3,r5
+- std r0,0(r4)
+- ld r4,CPU_SPEC_SETUP(r3)
+- cmpdi 0,r4,0
+- add r4,r4,r5
+- beqlr
+- ld r4,0(r4)
+- add r4,r4,r5
+- mtctr r4
+- /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */
+- mr r4,r3
+- mr r3,r5
+- bctr
+-
+-/*
+- * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
+- * and writes nop's over sections of code that don't apply for this cpu.
+- * r3 = data offset (not changed)
+- */
+-_GLOBAL(do_cpu_ftr_fixups)
+- /* Get CPU 0 features */
+- LOAD_REG_IMMEDIATE(r6,cur_cpu_spec)
+- sub r6,r6,r3
+- ld r4,0(r6)
+- sub r4,r4,r3
+- ld r4,CPU_SPEC_FEATURES(r4)
+- /* Get the fixup table */
+- LOAD_REG_IMMEDIATE(r6,__start___ftr_fixup)
+- sub r6,r6,r3
+- LOAD_REG_IMMEDIATE(r7,__stop___ftr_fixup)
+- sub r7,r7,r3
+- /* Do the fixup */
+-1: cmpld r6,r7
+- bgelr
+- addi r6,r6,32
+- ld r8,-32(r6) /* mask */
+- and r8,r8,r4
+- ld r9,-24(r6) /* value */
+- cmpld r8,r9
+- beq 1b
+- ld r8,-16(r6) /* section begin */
+- ld r9,-8(r6) /* section end */
+- subf. r9,r8,r9
+- beq 1b
+- /* write nops over the section of code */
+- /* todo: if large section, add a branch at the start of it */
+- srwi r9,r9,2
+- mtctr r9
+- sub r8,r8,r3
+- lis r0,0x60000000 at h /* nop */
+-3: stw r0,0(r8)
+- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE at l
+- beq 2f
+- dcbst 0,r8 /* suboptimal, but simpler */
+- sync
+- icbi 0,r8
+-2: addi r8,r8,4
+- bdnz 3b
+- sync /* additional sync needed on g4 */
+- isync
+- b 1b
+
+ #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
+ /*
+@@ -556,7 +478,7 @@ _GLOBAL(giveup_altivec)
+
+ #endif /* CONFIG_ALTIVEC */
+
+-_GLOBAL(execve)
++_GLOBAL(kernel_execve)
+ li r0,__NR_execve
+ sc
+ bnslr
+diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
+index 92f4e5f..e2c3c6a 100644
+--- a/arch/powerpc/kernel/module_32.c
++++ b/arch/powerpc/kernel/module_32.c
+@@ -24,6 +24,8 @@
+ #include <linux/kernel.h>
+ #include <linux/cache.h>
+
++#include "setup.h"
++
+ #if 0
+ #define DEBUGP printk
+ #else
+@@ -269,33 +271,50 @@ int apply_relocate_add(Elf32_Shdr *sechd
+ return 0;
+ }
+
++static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
++ const Elf_Shdr *sechdrs,
++ const char *name)
++{
++ char *secstrings;
++ unsigned int i;
++
++ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
++ for (i = 1; i < hdr->e_shnum; i++)
++ if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
++ return &sechdrs[i];
++ return NULL;
++}
++
+ int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+ {
+- char *secstrings;
+- unsigned int i;
++ const Elf_Shdr *sect;
+
+ me->arch.bug_table = NULL;
+ me->arch.num_bugs = 0;
+
+ /* Find the __bug_table section, if present */
+- secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+- for (i = 1; i < hdr->e_shnum; i++) {
+- if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
+- continue;
+- me->arch.bug_table = (void *) sechdrs[i].sh_addr;
+- me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
+- break;
++ sect = find_section(hdr, sechdrs, "__bug_table");
++ if (sect != NULL) {
++ me->arch.bug_table = (void *) sect->sh_addr;
++ me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
+ }
+
+- /*
++ /*
+ * Strictly speaking this should have a spinlock to protect against
+ * traversals, but since we only traverse on BUG()s, a spinlock
+ * could potentially lead to deadlock and thus be counter-productive.
+ */
+ list_add(&me->arch.bug_list, &module_bug_list);
+
++ /* Apply feature fixups */
++ sect = find_section(hdr, sechdrs, "__ftr_fixup");
++ if (sect != NULL)
++ do_feature_fixups(cur_cpu_spec->cpu_features,
++ (void *)sect->sh_addr,
++ (void *)sect->sh_addr + sect->sh_size);
++
+ return 0;
+ }
+
+diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
+index ba34001..8dd1f0a 100644
+--- a/arch/powerpc/kernel/module_64.c
++++ b/arch/powerpc/kernel/module_64.c
+@@ -22,6 +22,9 @@
+ #include <linux/vmalloc.h>
+ #include <asm/module.h>
+ #include <asm/uaccess.h>
++#include <asm/firmware.h>
++
++#include "setup.h"
+
+ /* FIXME: We don't do .init separately. To do this, we'd need to have
+ a separate r2 value in the init and core section, and stub between
+@@ -400,6 +403,11 @@ int apply_relocate_add(Elf64_Shdr *sechd
+ | (value & 0x03fffffc);
+ break;
+
++ case R_PPC64_REL64:
++ /* 64 bits relative (used by features fixups) */
++ *location = value - (unsigned long)location;
++ break;
++
+ default:
+ printk("%s: Unknown ADD relocation: %lu\n",
+ me->name,
+@@ -413,23 +421,33 @@ int apply_relocate_add(Elf64_Shdr *sechd
+
+ LIST_HEAD(module_bug_list);
+
+-int module_finalize(const Elf_Ehdr *hdr,
+- const Elf_Shdr *sechdrs, struct module *me)
++static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
++ const Elf_Shdr *sechdrs,
++ const char *name)
+ {
+ char *secstrings;
+ unsigned int i;
+
++ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
++ for (i = 1; i < hdr->e_shnum; i++)
++ if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
++ return &sechdrs[i];
++ return NULL;
++}
++
++int module_finalize(const Elf_Ehdr *hdr,
++ const Elf_Shdr *sechdrs, struct module *me)
++{
++ const Elf_Shdr *sect;
++
+ me->arch.bug_table = NULL;
+ me->arch.num_bugs = 0;
+
+ /* Find the __bug_table section, if present */
+- secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+- for (i = 1; i < hdr->e_shnum; i++) {
+- if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
+- continue;
+- me->arch.bug_table = (void *) sechdrs[i].sh_addr;
+- me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
+- break;
++ sect = find_section(hdr, sechdrs, "__bug_table");
++ if (sect != NULL) {
++ me->arch.bug_table = (void *) sect->sh_addr;
++ me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
+ }
+
+ /*
+@@ -439,6 +457,19 @@ int module_finalize(const Elf_Ehdr *hdr,
+ */
+ list_add(&me->arch.bug_list, &module_bug_list);
+
++ /* Apply feature fixups */
++ sect = find_section(hdr, sechdrs, "__ftr_fixup");
++ if (sect != NULL)
++ do_feature_fixups(cur_cpu_spec->cpu_features,
++ (void *)sect->sh_addr,
++ (void *)sect->sh_addr + sect->sh_size);
++
++ sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
++ if (sect != NULL)
++ do_feature_fixups(powerpc_firmware_features,
++ (void *)sect->sh_addr,
++ (void *)sect->sh_addr + sect->sh_size);
++
+ return 0;
+ }
+
+diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
+index 3262b73..397c83e 100644
+--- a/arch/powerpc/kernel/of_device.c
++++ b/arch/powerpc/kernel/of_device.c
+@@ -189,27 +189,9 @@ void of_release_dev(struct device *dev)
+ int of_device_register(struct of_device *ofdev)
+ {
+ int rc;
+- struct of_device **odprop;
+
+ BUG_ON(ofdev->node == NULL);
+
+- odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
+- if (!odprop) {
+- struct property *new_prop;
+-
+- new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *),
+- GFP_KERNEL);
+- if (new_prop == NULL)
+- return -ENOMEM;
+- new_prop->name = "linux,device";
+- new_prop->length = sizeof(sizeof(struct of_device *));
+- new_prop->value = (unsigned char *)&new_prop[1];
+- odprop = (struct of_device **)new_prop->value;
+- *odprop = NULL;
+- prom_add_property(ofdev->node, new_prop);
+- }
+- *odprop = ofdev;
+-
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+@@ -221,14 +203,8 @@ int of_device_register(struct of_device
+
+ void of_device_unregister(struct of_device *ofdev)
+ {
+- struct of_device **odprop;
+-
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+
+- odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
+- if (odprop)
+- *odprop = NULL;
+-
+ device_unregister(&ofdev->dev);
+ }
+
+diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
+index c68741f..55f1a25 100644
+--- a/arch/powerpc/kernel/paca.c
++++ b/arch/powerpc/kernel/paca.c
+@@ -17,6 +17,7 @@
+ #include <asm/lppaca.h>
+ #include <asm/iseries/it_lp_reg_save.h>
+ #include <asm/paca.h>
++#include <asm/mmu.h>
+
+
+ /* This symbol is provided by the linker - let it fill in the paca
+@@ -45,6 +46,17 @@ struct lppaca lppaca[] = {
+ },
+ };
+
++/*
++ * 3 persistent SLBs are registered here. The buffer will be zero
++ * initially, hence will all be invaild until we actually write them.
++ */
++struct slb_shadow slb_shadow[] __cacheline_aligned = {
++ [0 ... (NR_CPUS-1)] = {
++ .persistent = SLB_NUM_BOLTED,
++ .buffer_length = sizeof(struct slb_shadow),
++ },
++};
++
+ /* The Paca is an array with one entry per processor. Each contains an
+ * lppaca, which contains the information shared between the
+ * hypervisor and Linux.
+@@ -59,7 +71,8 @@ struct lppaca lppaca[] = {
+ .lock_token = 0x8000, \
+ .paca_index = (number), /* Paca Index */ \
+ .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \
+- .hw_cpu_id = 0xffff,
++ .hw_cpu_id = 0xffff, \
++ .slb_shadow_ptr = &slb_shadow[number],
+
+ #ifdef CONFIG_PPC_ISERIES
+ #define PACA_INIT_ISERIES(number) \
+diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
+index 09b1e1b..0d9ff72 100644
+--- a/arch/powerpc/kernel/pci_32.c
++++ b/arch/powerpc/kernel/pci_32.c
+@@ -441,14 +441,14 @@ update_bridge_base(struct pci_bus *bus,
+ end = res->end - off;
+ io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK;
+ io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK;
+- if (end > 0xffff) {
+- pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
+- start >> 16);
+- pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
+- end >> 16);
++ if (end > 0xffff)
+ io_base_lo |= PCI_IO_RANGE_TYPE_32;
+- } else
++ else
+ io_base_lo |= PCI_IO_RANGE_TYPE_16;
++ pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
++ start >> 16);
++ pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
++ end >> 16);
+ pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo);
+ pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo);
+
+@@ -633,12 +633,12 @@ pcibios_alloc_controller(void)
+ static void
+ make_one_node_map(struct device_node* node, u8 pci_bus)
+ {
+- int *bus_range;
++ const int *bus_range;
+ int len;
+
+ if (pci_bus >= pci_bus_count)
+ return;
+- bus_range = (int *) get_property(node, "bus-range", &len);
++ bus_range = get_property(node, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, "
+ "assuming it starts at 0\n", node->full_name);
+@@ -648,13 +648,13 @@ make_one_node_map(struct device_node* no
+
+ for (node=node->child; node != 0;node = node->sibling) {
+ struct pci_dev* dev;
+- unsigned int *class_code, *reg;
++ const unsigned int *class_code, *reg;
+
+- class_code = (unsigned int *) get_property(node, "class-code", NULL);
++ class_code = get_property(node, "class-code", NULL);
+ if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+ continue;
+- reg = (unsigned int *)get_property(node, "reg", NULL);
++ reg = get_property(node, "reg", NULL);
+ if (!reg)
+ continue;
+ dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+@@ -669,7 +669,7 @@ pcibios_make_OF_bus_map(void)
+ {
+ int i;
+ struct pci_controller* hose;
+- u8* of_prop_map;
++ struct property *map_prop;
+
+ pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL);
+ if (!pci_to_OF_bus_map) {
+@@ -691,9 +691,12 @@ pcibios_make_OF_bus_map(void)
+ continue;
+ make_one_node_map(node, hose->first_busno);
+ }
+- of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL);
+- if (of_prop_map)
+- memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count);
++ map_prop = of_find_property(find_path_device("/"),
++ "pci-OF-bus-map", NULL);
++ if (map_prop) {
++ BUG_ON(pci_bus_count > map_prop->length);
++ memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
++ }
+ #ifdef DEBUG
+ printk("PCI->OF bus map:\n");
+ for (i=0; i<pci_bus_count; i++) {
+@@ -712,7 +715,7 @@ scan_OF_pci_childs(struct device_node* n
+ struct device_node* sub_node;
+
+ for (; node != 0;node = node->sibling) {
+- unsigned int *class_code;
++ const unsigned int *class_code;
+
+ if (filter(node, data))
+ return node;
+@@ -722,7 +725,7 @@ scan_OF_pci_childs(struct device_node* n
+ * a fake root for all functions of a multi-function device,
+ * we go down them as well.
+ */
+- class_code = (unsigned int *) get_property(node, "class-code", NULL);
++ class_code = get_property(node, "class-code", NULL);
+ if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
+ strcmp(node->name, "multifunc-device"))
+@@ -737,10 +740,10 @@ scan_OF_pci_childs(struct device_node* n
+ static int
+ scan_OF_pci_childs_iterator(struct device_node* node, void* data)
+ {
+- unsigned int *reg;
++ const unsigned int *reg;
+ u8* fdata = (u8*)data;
+
+- reg = (unsigned int *) get_property(node, "reg", NULL);
++ reg = get_property(node, "reg", NULL);
+ if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
+ && ((reg[0] >> 16) & 0xff) == fdata[0])
+ return 1;
+@@ -841,7 +844,7 @@ find_OF_pci_device_filter(struct device_
+ int
+ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
+ {
+- unsigned int *reg;
++ const unsigned int *reg;
+ struct pci_controller* hose;
+ struct pci_dev* dev = NULL;
+
+@@ -854,7 +857,7 @@ pci_device_from_OF_node(struct device_no
+ if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
+ find_OF_pci_device_filter, (void *)node))
+ return -ENODEV;
+- reg = (unsigned int *) get_property(node, "reg", NULL);
++ reg = get_property(node, "reg", NULL);
+ if (!reg)
+ return -ENODEV;
+ *bus = (reg[0] >> 16) & 0xff;
+@@ -885,8 +888,8 @@ pci_process_bridge_OF_ranges(struct pci_
+ struct device_node *dev, int primary)
+ {
+ static unsigned int static_lc_ranges[256] __initdata;
+- unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
+- unsigned int size;
++ const unsigned int *dt_ranges;
++ unsigned int *lc_ranges, *ranges, *prev, size;
+ int rlen = 0, orig_rlen;
+ int memno = 0;
+ struct resource *res;
+@@ -897,7 +900,7 @@ pci_process_bridge_OF_ranges(struct pci_
+ * that can have more than 3 ranges, fortunately using contiguous
+ * addresses -- BenH
+ */
+- dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
++ dt_ranges = get_property(dev, "ranges", &rlen);
+ if (!dt_ranges)
+ return;
+ /* Sanity check, though hopefully that never happens */
+diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
+index 138134c..9bae8a5 100644
+--- a/arch/powerpc/kernel/pci_64.c
++++ b/arch/powerpc/kernel/pci_64.c
+@@ -30,6 +30,7 @@
+ #include <asm/byteorder.h>
+ #include <asm/machdep.h>
+ #include <asm/ppc-pci.h>
++#include <asm/firmware.h>
+
+ #ifdef DEBUG
+ #include <asm/udbg.h>
+@@ -185,34 +186,6 @@ static void __devinit pci_setup_pci_cont
+ spin_unlock(&hose_spinlock);
+ }
+
+-static void add_linux_pci_domain(struct device_node *dev,
+- struct pci_controller *phb)
+-{
+- struct property *of_prop;
+- unsigned int size;
+-
+- of_prop = (struct property *)
+- get_property(dev, "linux,pci-domain", &size);
+- if (of_prop != NULL)
+- return;
+- WARN_ON(of_prop && size < sizeof(int));
+- if (of_prop && size < sizeof(int))
+- of_prop = NULL;
+- size = sizeof(struct property) + sizeof(int);
+- if (of_prop == NULL) {
+- if (mem_init_done)
+- of_prop = kmalloc(size, GFP_KERNEL);
+- else
+- of_prop = alloc_bootmem(size);
+- }
+- memset(of_prop, 0, sizeof(struct property));
+- of_prop->name = "linux,pci-domain";
+- of_prop->length = sizeof(int);
+- of_prop->value = (unsigned char *)&of_prop[1];
+- *((int *)of_prop->value) = phb->global_number;
+- prom_add_property(dev, of_prop);
+-}
+-
+ struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
+ {
+ struct pci_controller *phb;
+@@ -227,26 +200,22 @@ struct pci_controller * pcibios_alloc_co
+ phb->arch_data = dev;
+ phb->is_dynamic = mem_init_done;
+ if (dev) {
+- PHB_SET_NODE(phb, of_node_to_nid(dev));
+- add_linux_pci_domain(dev, phb);
++ int nid = of_node_to_nid(dev);
++
++ if (nid < 0 || !node_online(nid))
++ nid = -1;
++
++ PHB_SET_NODE(phb, nid);
+ }
+ return phb;
+ }
+
+ void pcibios_free_controller(struct pci_controller *phb)
+ {
+- if (phb->arch_data) {
+- struct device_node *np = phb->arch_data;
+- int *domain = (int *)get_property(np,
+- "linux,pci-domain", NULL);
+- if (domain)
+- *domain = -1;
+- }
+ if (phb->is_dynamic)
+ kfree(phb);
+ }
+
+-#ifndef CONFIG_PPC_ISERIES
+ void __devinit pcibios_claim_one_bus(struct pci_bus *b)
+ {
+ struct pci_dev *dev;
+@@ -275,18 +244,20 @@ static void __init pcibios_claim_of_setu
+ {
+ struct pci_bus *b;
+
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return;
++
+ list_for_each_entry(b, &pci_root_buses, node)
+ pcibios_claim_one_bus(b);
+ }
+-#endif
+
+ #ifdef CONFIG_PPC_MULTIPLATFORM
+ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
+ {
+- u32 *prop;
++ const u32 *prop;
+ int len;
+
+- prop = (u32 *) get_property(np, name, &len);
++ prop = get_property(np, name, &len);
+ if (prop && len >= 4)
+ return *prop;
+ return def;
+@@ -315,10 +286,11 @@ static void pci_parse_of_addrs(struct de
+ u64 base, size;
+ unsigned int flags;
+ struct resource *res;
+- u32 *addrs, i;
++ const u32 *addrs;
++ u32 i;
+ int proplen;
+
+- addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
++ addrs = get_property(node, "assigned-addresses", &proplen);
+ if (!addrs)
+ return;
+ DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
+@@ -418,7 +390,7 @@ void __devinit of_scan_bus(struct device
+ struct pci_bus *bus)
+ {
+ struct device_node *child = NULL;
+- u32 *reg;
++ const u32 *reg;
+ int reglen, devfn;
+ struct pci_dev *dev;
+
+@@ -426,7 +398,7 @@ void __devinit of_scan_bus(struct device
+
+ while ((child = of_get_next_child(node, child)) != NULL) {
+ DBG(" * %s\n", child->full_name);
+- reg = (u32 *) get_property(child, "reg", ®len);
++ reg = get_property(child, "reg", ®len);
+ if (reg == NULL || reglen < 20)
+ continue;
+ devfn = (reg[0] >> 8) & 0xff;
+@@ -450,7 +422,7 @@ void __devinit of_scan_pci_bridge(struct
+ struct pci_dev *dev)
+ {
+ struct pci_bus *bus;
+- u32 *busrange, *ranges;
++ const u32 *busrange, *ranges;
+ int len, i, mode;
+ struct resource *res;
+ unsigned int flags;
+@@ -459,13 +431,13 @@ void __devinit of_scan_pci_bridge(struct
+ DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+
+ /* parse bus-range property */
+- busrange = (u32 *) get_property(node, "bus-range", &len);
++ busrange = get_property(node, "bus-range", &len);
+ if (busrange == NULL || len != 8) {
+ printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
+ node->full_name);
+ return;
+ }
+- ranges = (u32 *) get_property(node, "ranges", &len);
++ ranges = get_property(node, "ranges", &len);
+ if (ranges == NULL) {
+ printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
+ node->full_name);
+@@ -590,9 +562,8 @@ static int __init pcibios_init(void)
+ */
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
+-#ifdef CONFIG_PPC_ISERIES
+- iSeries_pcibios_init();
+-#endif
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ iSeries_pcibios_init();
+
+ printk(KERN_DEBUG "PCI: Probing PCI hardware\n");
+
+@@ -602,15 +573,15 @@ static int __init pcibios_init(void)
+ pci_bus_add_devices(hose->bus);
+ }
+
+-#ifndef CONFIG_PPC_ISERIES
+- if (pci_probe_only)
+- pcibios_claim_of_setup();
+- else
+- /* FIXME: `else' will be removed when
+- pci_assign_unassigned_resources() is able to work
+- correctly with [partially] allocated PCI tree. */
+- pci_assign_unassigned_resources();
+-#endif /* !CONFIG_PPC_ISERIES */
++ if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
++ if (pci_probe_only)
++ pcibios_claim_of_setup();
++ else
++ /* FIXME: `else' will be removed when
++ pci_assign_unassigned_resources() is able to work
++ correctly with [partially] allocated PCI tree. */
++ pci_assign_unassigned_resources();
++ }
+
+ /* Call machine dependent final fixup */
+ if (ppc_md.pcibios_fixup)
+@@ -622,8 +593,9 @@ static int __init pcibios_init(void)
+ printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
+
+ #ifdef CONFIG_PPC_MULTIPLATFORM
+- /* map in PCI I/O space */
+- phbs_remap_io();
++ if (!firmware_has_feature(FW_FEATURE_ISERIES))
++ /* map in PCI I/O space */
++ phbs_remap_io();
+ #endif
+
+ printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
+@@ -673,13 +645,13 @@ int pcibios_enable_device(struct pci_dev
+ */
+ int pci_domain_nr(struct pci_bus *bus)
+ {
+-#ifdef CONFIG_PPC_ISERIES
+- return 0;
+-#else
+- struct pci_controller *hose = pci_bus_to_host(bus);
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return 0;
++ else {
++ struct pci_controller *hose = pci_bus_to_host(bus);
+
+- return hose->global_number;
+-#endif
++ return hose->global_number;
++ }
+ }
+
+ EXPORT_SYMBOL(pci_domain_nr);
+@@ -687,12 +659,12 @@ EXPORT_SYMBOL(pci_domain_nr);
+ /* Decide whether to display the domain number in /proc */
+ int pci_proc_domain(struct pci_bus *bus)
+ {
+-#ifdef CONFIG_PPC_ISERIES
+- return 0;
+-#else
+- struct pci_controller *hose = pci_bus_to_host(bus);
+- return hose->buid;
+-#endif
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return 0;
++ else {
++ struct pci_controller *hose = pci_bus_to_host(bus);
++ return hose->buid;
++ }
+ }
+
+ /*
+@@ -929,13 +901,13 @@ static void __devinit pci_process_ISA_OF
+ unsigned int size;
+ };
+
+- struct isa_range *range;
++ const struct isa_range *range;
+ unsigned long pci_addr;
+ unsigned int isa_addr;
+ unsigned int size;
+ int rlen = 0;
+
+- range = (struct isa_range *) get_property(isa_node, "ranges", &rlen);
++ range = get_property(isa_node, "ranges", &rlen);
+ if (range == NULL || (rlen < sizeof(struct isa_range))) {
+ printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
+ "mapping 64k\n");
+@@ -976,7 +948,8 @@ static void __devinit pci_process_ISA_OF
+ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
+ struct device_node *dev, int prim)
+ {
+- unsigned int *ranges, pci_space;
++ const unsigned int *ranges;
++ unsigned int pci_space;
+ unsigned long size;
+ int rlen = 0;
+ int memno = 0;
+@@ -994,7 +967,7 @@ void __devinit pci_process_bridge_OF_ran
+ * (size depending on dev->n_addr_cells)
+ * cells 4+5 or 5+6: the size of the range
+ */
+- ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
++ ranges = get_property(dev, "ranges", &rlen);
+ if (ranges == NULL)
+ return;
+ hose->io_base_phys = 0;
+diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
+index 1c18953..68df018 100644
+--- a/arch/powerpc/kernel/pci_dn.c
++++ b/arch/powerpc/kernel/pci_dn.c
+@@ -40,8 +40,8 @@
+ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
+ {
+ struct pci_controller *phb = data;
+- int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
+- u32 *regs;
++ const int *type = get_property(dn, "ibm,pci-config-space-type", NULL);
++ const u32 *regs;
+ struct pci_dn *pdn;
+
+ if (mem_init_done)
+@@ -54,14 +54,14 @@ static void * __devinit update_dn_pci_in
+ dn->data = pdn;
+ pdn->node = dn;
+ pdn->phb = phb;
+- regs = (u32 *)get_property(dn, "reg", NULL);
++ regs = get_property(dn, "reg", NULL);
+ if (regs) {
+ /* First register entry is addr (00BBSS00) */
+ pdn->busno = (regs[0] >> 16) & 0xff;
+ pdn->devfn = (regs[0] >> 8) & 0xff;
+ }
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+- u32 *busp = (u32 *)get_property(dn, "linux,subbus", NULL);
++ const u32 *busp = get_property(dn, "linux,subbus", NULL);
+ if (busp)
+ pdn->bussubno = *busp;
+ }
+@@ -96,10 +96,11 @@ void *traverse_pci_devices(struct device
+
+ /* We started with a phb, iterate all childs */
+ for (dn = start->child; dn; dn = nextdn) {
+- u32 *classp, class;
++ const u32 *classp;
++ u32 class;
+
+ nextdn = NULL;
+- classp = (u32 *)get_property(dn, "class-code", NULL);
++ classp = get_property(dn, "class-code", NULL);
+ class = classp ? *classp : 0;
+
+ if (pre && ((ret = pre(dn, data)) != NULL))
+diff --git a/arch/powerpc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c
+deleted file mode 100644
+index bdc3977..0000000
+--- a/arch/powerpc/kernel/perfmon_fsl_booke.c
++++ /dev/null
+@@ -1,221 +0,0 @@
+-/* kernel/perfmon_fsl_booke.c
+- * Freescale Book-E Performance Monitor code
+- *
+- * Author: Andy Fleming
+- * Copyright (c) 2004 Freescale Semiconductor, Inc
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/stddef.h>
+-#include <linux/unistd.h>
+-#include <linux/ptrace.h>
+-#include <linux/slab.h>
+-#include <linux/user.h>
+-#include <linux/a.out.h>
+-#include <linux/interrupt.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/prctl.h>
+-
+-#include <asm/pgtable.h>
+-#include <asm/uaccess.h>
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/reg.h>
+-#include <asm/xmon.h>
+-#include <asm/pmc.h>
+-
+-static inline u32 get_pmlca(int ctr);
+-static inline void set_pmlca(int ctr, u32 pmlca);
+-
+-static inline u32 get_pmlca(int ctr)
+-{
+- u32 pmlca;
+-
+- switch (ctr) {
+- case 0:
+- pmlca = mfpmr(PMRN_PMLCA0);
+- break;
+- case 1:
+- pmlca = mfpmr(PMRN_PMLCA1);
+- break;
+- case 2:
+- pmlca = mfpmr(PMRN_PMLCA2);
+- break;
+- case 3:
+- pmlca = mfpmr(PMRN_PMLCA3);
+- break;
+- default:
+- panic("Bad ctr number\n");
+- }
+-
+- return pmlca;
+-}
+-
+-static inline void set_pmlca(int ctr, u32 pmlca)
+-{
+- switch (ctr) {
+- case 0:
+- mtpmr(PMRN_PMLCA0, pmlca);
+- break;
+- case 1:
+- mtpmr(PMRN_PMLCA1, pmlca);
+- break;
+- case 2:
+- mtpmr(PMRN_PMLCA2, pmlca);
+- break;
+- case 3:
+- mtpmr(PMRN_PMLCA3, pmlca);
+- break;
+- default:
+- panic("Bad ctr number\n");
+- }
+-}
+-
+-void init_pmc_stop(int ctr)
+-{
+- u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
+- PMLCA_FCM1 | PMLCA_FCM0);
+- u32 pmlcb = 0;
+-
+- switch (ctr) {
+- case 0:
+- mtpmr(PMRN_PMLCA0, pmlca);
+- mtpmr(PMRN_PMLCB0, pmlcb);
+- break;
+- case 1:
+- mtpmr(PMRN_PMLCA1, pmlca);
+- mtpmr(PMRN_PMLCB1, pmlcb);
+- break;
+- case 2:
+- mtpmr(PMRN_PMLCA2, pmlca);
+- mtpmr(PMRN_PMLCB2, pmlcb);
+- break;
+- case 3:
+- mtpmr(PMRN_PMLCA3, pmlca);
+- mtpmr(PMRN_PMLCB3, pmlcb);
+- break;
+- default:
+- panic("Bad ctr number!\n");
+- }
+-}
+-
+-void set_pmc_event(int ctr, int event)
+-{
+- u32 pmlca;
+-
+- pmlca = get_pmlca(ctr);
+-
+- pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
+- ((event << PMLCA_EVENT_SHIFT) &
+- PMLCA_EVENT_MASK);
+-
+- set_pmlca(ctr, pmlca);
+-}
+-
+-void set_pmc_user_kernel(int ctr, int user, int kernel)
+-{
+- u32 pmlca;
+-
+- pmlca = get_pmlca(ctr);
+-
+- if(user)
+- pmlca &= ~PMLCA_FCU;
+- else
+- pmlca |= PMLCA_FCU;
+-
+- if(kernel)
+- pmlca &= ~PMLCA_FCS;
+- else
+- pmlca |= PMLCA_FCS;
+-
+- set_pmlca(ctr, pmlca);
+-}
+-
+-void set_pmc_marked(int ctr, int mark0, int mark1)
+-{
+- u32 pmlca = get_pmlca(ctr);
+-
+- if(mark0)
+- pmlca &= ~PMLCA_FCM0;
+- else
+- pmlca |= PMLCA_FCM0;
+-
+- if(mark1)
+- pmlca &= ~PMLCA_FCM1;
+- else
+- pmlca |= PMLCA_FCM1;
+-
+- set_pmlca(ctr, pmlca);
+-}
+-
+-void pmc_start_ctr(int ctr, int enable)
+-{
+- u32 pmlca = get_pmlca(ctr);
+-
+- pmlca &= ~PMLCA_FC;
+-
+- if (enable)
+- pmlca |= PMLCA_CE;
+- else
+- pmlca &= ~PMLCA_CE;
+-
+- set_pmlca(ctr, pmlca);
+-}
+-
+-void pmc_start_ctrs(int enable)
+-{
+- u32 pmgc0 = mfpmr(PMRN_PMGC0);
+-
+- pmgc0 &= ~PMGC0_FAC;
+- pmgc0 |= PMGC0_FCECE;
+-
+- if (enable)
+- pmgc0 |= PMGC0_PMIE;
+- else
+- pmgc0 &= ~PMGC0_PMIE;
+-
+- mtpmr(PMRN_PMGC0, pmgc0);
+-}
+-
+-void pmc_stop_ctrs(void)
+-{
+- u32 pmgc0 = mfpmr(PMRN_PMGC0);
+-
+- pmgc0 |= PMGC0_FAC;
+-
+- pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
+-
+- mtpmr(PMRN_PMGC0, pmgc0);
+-}
+-
+-void dump_pmcs(void)
+-{
+- printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0));
+- printk("pmc\t\tpmlca\t\tpmlcb\n");
+- printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0),
+- mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0));
+- printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1),
+- mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1));
+- printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2),
+- mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2));
+- printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3),
+- mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
+-}
+-
+-EXPORT_SYMBOL(init_pmc_stop);
+-EXPORT_SYMBOL(set_pmc_event);
+-EXPORT_SYMBOL(set_pmc_user_kernel);
+-EXPORT_SYMBOL(set_pmc_marked);
+-EXPORT_SYMBOL(pmc_start_ctr);
+-EXPORT_SYMBOL(pmc_start_ctrs);
+-EXPORT_SYMBOL(pmc_stop_ctrs);
+-EXPORT_SYMBOL(dump_pmcs);
+diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
+index a0a2efa..3d8f6f4 100644
+--- a/arch/powerpc/kernel/pmc.c
++++ b/arch/powerpc/kernel/pmc.c
+@@ -71,7 +71,7 @@ int reserve_pmc_hardware(perf_irq_t new_
+ }
+
+ pmc_owner_caller = __builtin_return_address(0);
+- perf_irq = new_perf_irq ? : dummy_perf;
++ perf_irq = new_perf_irq ? new_perf_irq : dummy_perf;
+
+ out:
+ spin_unlock(&pmc_owner_lock);
+diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
+index 39d3bfc..807193a 100644
+--- a/arch/powerpc/kernel/ppc_ksyms.c
++++ b/arch/powerpc/kernel/ppc_ksyms.c
+@@ -91,25 +91,10 @@ EXPORT_SYMBOL(__copy_tofrom_user);
+ EXPORT_SYMBOL(__clear_user);
+ EXPORT_SYMBOL(__strncpy_from_user);
+ EXPORT_SYMBOL(__strnlen_user);
+-
+-#ifndef __powerpc64__
+-EXPORT_SYMBOL(__ide_mm_insl);
+-EXPORT_SYMBOL(__ide_mm_outsw);
+-EXPORT_SYMBOL(__ide_mm_insw);
+-EXPORT_SYMBOL(__ide_mm_outsl);
++#ifdef CONFIG_PPC64
++EXPORT_SYMBOL(copy_4K_page);
+ #endif
+
+-EXPORT_SYMBOL(_insb);
+-EXPORT_SYMBOL(_outsb);
+-EXPORT_SYMBOL(_insw);
+-EXPORT_SYMBOL(_outsw);
+-EXPORT_SYMBOL(_insl);
+-EXPORT_SYMBOL(_outsl);
+-EXPORT_SYMBOL(_insw_ns);
+-EXPORT_SYMBOL(_outsw_ns);
+-EXPORT_SYMBOL(_insl_ns);
+-EXPORT_SYMBOL(_outsl_ns);
+-
+ #if defined(CONFIG_PPC32) && (defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE))
+ EXPORT_SYMBOL(ppc_ide_md);
+ #endif
+diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
+index a127a1e..f3d4dd5 100644
+--- a/arch/powerpc/kernel/process.c
++++ b/arch/powerpc/kernel/process.c
+@@ -341,13 +341,6 @@ struct task_struct *__switch_to(struct t
+
+ static int instructions_to_print = 16;
+
+-#ifdef CONFIG_PPC64
+-#define BAD_PC(pc) ((REGION_ID(pc) != KERNEL_REGION_ID) && \
+- (REGION_ID(pc) != VMALLOC_REGION_ID))
+-#else
+-#define BAD_PC(pc) ((pc) < KERNELBASE)
+-#endif
+-
+ static void show_instructions(struct pt_regs *regs)
+ {
+ int i;
+@@ -366,7 +359,8 @@ static void show_instructions(struct pt_
+ * bad address because the pc *should* only be a
+ * kernel address.
+ */
+- if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) {
++ if (!__kernel_text_address(pc) ||
++ __get_user(instr, (unsigned int __user *)pc)) {
+ printk("XXXXXXXX ");
+ } else {
+ if (regs->nip == pc)
+@@ -424,7 +418,7 @@ void show_regs(struct pt_regs * regs)
+ printk("NIP: "REG" LR: "REG" CTR: "REG"\n",
+ regs->nip, regs->link, regs->ctr);
+ printk("REGS: %p TRAP: %04lx %s (%s)\n",
+- regs, regs->trap, print_tainted(), system_utsname.release);
++ regs, regs->trap, print_tainted(), init_utsname()->release);
+ printk("MSR: "REG" ", regs->msr);
+ printbits(regs->msr, msr_bits);
+ printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer);
+diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
+index a1787ff..bdb412d 100644
+--- a/arch/powerpc/kernel/prom.c
++++ b/arch/powerpc/kernel/prom.c
+@@ -724,7 +724,7 @@ static int __init early_init_dt_scan_cho
+ strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
+
+ #ifdef CONFIG_CMDLINE
+- if (l == 0 || (l == 1 && (*p) == 0))
++ if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
+ strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+ #endif /* CONFIG_CMDLINE */
+
+@@ -757,24 +757,9 @@ static int __init early_init_dt_scan_roo
+ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
+ {
+ cell_t *p = *cellp;
+- unsigned long r;
+
+- /* Ignore more than 2 cells */
+- while (s > sizeof(unsigned long) / 4) {
+- p++;
+- s--;
+- }
+- r = *p++;
+-#ifdef CONFIG_PPC64
+- if (s > 1) {
+- r <<= 32;
+- r |= *(p++);
+- s--;
+- }
+-#endif
+-
+- *cellp = p;
+- return r;
++ *cellp = p + s;
++ return of_read_ulong(p, s);
+ }
+
+
+@@ -942,11 +927,11 @@ void __init early_init_devtree(void *par
+ int
+ prom_n_addr_cells(struct device_node* np)
+ {
+- int* ip;
++ const int *ip;
+ do {
+ if (np->parent)
+ np = np->parent;
+- ip = (int *) get_property(np, "#address-cells", NULL);
++ ip = get_property(np, "#address-cells", NULL);
+ if (ip != NULL)
+ return *ip;
+ } while (np->parent);
+@@ -958,11 +943,11 @@ EXPORT_SYMBOL(prom_n_addr_cells);
+ int
+ prom_n_size_cells(struct device_node* np)
+ {
+- int* ip;
++ const int* ip;
+ do {
+ if (np->parent)
+ np = np->parent;
+- ip = (int *) get_property(np, "#size-cells", NULL);
++ ip = get_property(np, "#size-cells", NULL);
+ if (ip != NULL)
+ return *ip;
+ } while (np->parent);
+@@ -1029,12 +1014,12 @@ EXPORT_SYMBOL(find_all_nodes);
+ /** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+-int device_is_compatible(struct device_node *device, const char *compat)
++int device_is_compatible(const struct device_node *device, const char *compat)
+ {
+ const char* cp;
+ int cplen, l;
+
+- cp = (char *) get_property(device, "compatible", &cplen);
++ cp = get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+@@ -1449,7 +1434,7 @@ static int of_finish_dynamic_node(struct
+ {
+ struct device_node *parent = of_get_parent(node);
+ int err = 0;
+- phandle *ibm_phandle;
++ const phandle *ibm_phandle;
+
+ node->name = get_property(node, "name", NULL);
+ node->type = get_property(node, "device_type", NULL);
+@@ -1466,8 +1451,7 @@ static int of_finish_dynamic_node(struct
+ return -ENODEV;
+
+ /* fix up new node's linux_phandle field */
+- if ((ibm_phandle = (unsigned int *)get_property(node,
+- "ibm,phandle", NULL)))
++ if ((ibm_phandle = get_property(node, "ibm,phandle", NULL)))
+ node->linux_phandle = *ibm_phandle;
+
+ out:
+@@ -1507,7 +1491,8 @@ static int __init prom_reconfig_setup(vo
+ __initcall(prom_reconfig_setup);
+ #endif
+
+-struct property *of_find_property(struct device_node *np, const char *name,
++struct property *of_find_property(const struct device_node *np,
++ const char *name,
+ int *lenp)
+ {
+ struct property *pp;
+@@ -1528,7 +1513,8 @@ struct property *of_find_property(struct
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+-void *get_property(struct device_node *np, const char *name, int *lenp)
++const void *get_property(const struct device_node *np, const char *name,
++ int *lenp)
+ {
+ struct property *pp = of_find_property(np,name,lenp);
+ return pp ? pp->value : NULL;
+@@ -1658,16 +1644,16 @@ struct device_node *of_get_cpu_node(int
+ hardid = get_hard_smp_processor_id(cpu);
+
+ for_each_node_by_type(np, "cpu") {
+- u32 *intserv;
++ const u32 *intserv;
+ unsigned int plen, t;
+
+ /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
+ * fallback to "reg" property and assume no threads
+ */
+- intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s",
+- &plen);
++ intserv = get_property(np, "ibm,ppc-interrupt-server#s",
++ &plen);
+ if (intserv == NULL) {
+- u32 *reg = (u32 *)get_property(np, "reg", NULL);
++ const u32 *reg = get_property(np, "reg", NULL);
+ if (reg == NULL)
+ continue;
+ if (*reg == hardid) {
+diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
+index 4394e54..b917616 100644
+--- a/arch/powerpc/kernel/prom_init.c
++++ b/arch/powerpc/kernel/prom_init.c
+@@ -2033,16 +2033,22 @@ static void __init fixup_device_tree_map
+ #endif
+
+ #ifdef CONFIG_PPC_CHRP
+-/* Pegasos lacks the "ranges" property in the isa node */
++/* Pegasos and BriQ lacks the "ranges" property in the isa node */
+ static void __init fixup_device_tree_chrp(void)
+ {
+ phandle isa;
+ u32 isa_ranges[6];
++ u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
+ char *name;
+ int rc;
+
+ name = "/pci at 80000000/isa at c";
+ isa = call_prom("finddevice", 1, 1, ADDR(name));
++ if (!PHANDLE_VALID(isa)) {
++ name = "/pci at ff500000/isa at 6";
++ isa = call_prom("finddevice", 1, 1, ADDR(name));
++ rloc = 0x01003000; /* IO space; PCI device = 6 */
++ }
+ if (!PHANDLE_VALID(isa))
+ return;
+
+@@ -2054,7 +2060,7 @@ static void __init fixup_device_tree_chr
+
+ isa_ranges[0] = 0x1;
+ isa_ranges[1] = 0x0;
+- isa_ranges[2] = 0x01006000;
++ isa_ranges[2] = rloc;
+ isa_ranges[3] = 0x0;
+ isa_ranges[4] = 0x0;
+ isa_ranges[5] = 0x00010000;
+diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
+index a10825a..603dff3 100644
+--- a/arch/powerpc/kernel/prom_parse.c
++++ b/arch/powerpc/kernel/prom_parse.c
+@@ -27,7 +27,7 @@
+
+ /* Debug utility */
+ #ifdef DEBUG
+-static void of_dump_addr(const char *s, u32 *addr, int na)
++static void of_dump_addr(const char *s, const u32 *addr, int na)
+ {
+ printk("%s", s);
+ while(na--)
+@@ -35,7 +35,7 @@ static void of_dump_addr(const char *s,
+ printk("\n");
+ }
+ #else
+-static void of_dump_addr(const char *s, u32 *addr, int na) { }
++static void of_dump_addr(const char *s, const u32 *addr, int na) { }
+ #endif
+
+
+@@ -46,9 +46,10 @@ struct of_bus {
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(struct device_node *child,
+ int *addrc, int *sizec);
+- u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
++ u64 (*map)(u32 *addr, const u32 *range,
++ int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+- unsigned int (*get_flags)(u32 *addr);
++ unsigned int (*get_flags)(const u32 *addr);
+ };
+
+
+@@ -65,7 +66,8 @@ static void of_bus_default_count_cells(s
+ *sizec = prom_n_size_cells(dev);
+ }
+
+-static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
++static u64 of_bus_default_map(u32 *addr, const u32 *range,
++ int na, int ns, int pna)
+ {
+ u64 cp, s, da;
+
+@@ -93,7 +95,7 @@ static int of_bus_default_translate(u32
+ return 0;
+ }
+
+-static unsigned int of_bus_default_get_flags(u32 *addr)
++static unsigned int of_bus_default_get_flags(const u32 *addr)
+ {
+ return IORESOURCE_MEM;
+ }
+@@ -118,7 +120,7 @@ static void of_bus_pci_count_cells(struc
+ *sizec = 2;
+ }
+
+-static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
++static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+ {
+ u64 cp, s, da;
+
+@@ -143,7 +145,7 @@ static int of_bus_pci_translate(u32 *add
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+ }
+
+-static unsigned int of_bus_pci_get_flags(u32 *addr)
++static unsigned int of_bus_pci_get_flags(const u32 *addr)
+ {
+ unsigned int flags = 0;
+ u32 w = addr[0];
+@@ -178,7 +180,7 @@ static void of_bus_isa_count_cells(struc
+ *sizec = 1;
+ }
+
+-static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
++static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+ {
+ u64 cp, s, da;
+
+@@ -203,7 +205,7 @@ static int of_bus_isa_translate(u32 *add
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+ }
+
+-static unsigned int of_bus_isa_get_flags(u32 *addr)
++static unsigned int of_bus_isa_get_flags(const u32 *addr)
+ {
+ unsigned int flags = 0;
+ u32 w = addr[0];
+@@ -268,7 +270,7 @@ static int of_translate_one(struct devic
+ struct of_bus *pbus, u32 *addr,
+ int na, int ns, int pna)
+ {
+- u32 *ranges;
++ const u32 *ranges;
+ unsigned int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+@@ -285,7 +287,7 @@ static int of_translate_one(struct devic
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ */
+- ranges = (u32 *)get_property(parent, "ranges", &rlen);
++ ranges = get_property(parent, "ranges", &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+@@ -328,7 +330,7 @@ static int of_translate_one(struct devic
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+-u64 of_translate_address(struct device_node *dev, u32 *in_addr)
++u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
+ {
+ struct device_node *parent = NULL;
+ struct of_bus *bus, *pbus;
+@@ -405,10 +407,10 @@ u64 of_translate_address(struct device_n
+ }
+ EXPORT_SYMBOL(of_translate_address);
+
+-u32 *of_get_address(struct device_node *dev, int index, u64 *size,
++const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+ unsigned int *flags)
+ {
+- u32 *prop;
++ const u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+@@ -425,7 +427,7 @@ u32 *of_get_address(struct device_node *
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+- prop = (u32 *)get_property(dev, bus->addresses, &psize);
++ prop = get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+@@ -443,10 +445,10 @@ u32 *of_get_address(struct device_node *
+ }
+ EXPORT_SYMBOL(of_get_address);
+
+-u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
++const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+ unsigned int *flags)
+ {
+- u32 *prop;
++ const u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+@@ -467,7 +469,7 @@ u32 *of_get_pci_address(struct device_no
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+- prop = (u32 *)get_property(dev, bus->addresses, &psize);
++ prop = get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+@@ -485,7 +487,7 @@ u32 *of_get_pci_address(struct device_no
+ }
+ EXPORT_SYMBOL(of_get_pci_address);
+
+-static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
++static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
+ u64 size, unsigned int flags,
+ struct resource *r)
+ {
+@@ -516,7 +518,7 @@ static int __of_address_to_resource(stru
+ int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r)
+ {
+- u32 *addrp;
++ const u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+@@ -530,7 +532,7 @@ EXPORT_SYMBOL_GPL(of_address_to_resource
+ int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r)
+ {
+- u32 *addrp;
++ const u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+@@ -541,13 +543,14 @@ int of_pci_address_to_resource(struct de
+ }
+ EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+
+-void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
++void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
+ unsigned long *busno, unsigned long *phys, unsigned long *size)
+ {
+- u32 *dma_window, cells;
+- unsigned char *prop;
++ const u32 *dma_window;
++ u32 cells;
++ const unsigned char *prop;
+
+- dma_window = (u32 *)dma_window_prop;
++ dma_window = dma_window_prop;
+
+ /* busno is always one cell */
+ *busno = *(dma_window++);
+@@ -576,13 +579,13 @@ static struct device_node *of_irq_dflt_p
+ static struct device_node *of_irq_find_parent(struct device_node *child)
+ {
+ struct device_node *p;
+- phandle *parp;
++ const phandle *parp;
+
+ if (!of_node_get(child))
+ return NULL;
+
+ do {
+- parp = (phandle *)get_property(child, "interrupt-parent", NULL);
++ parp = get_property(child, "interrupt-parent", NULL);
+ if (parp == NULL)
+ p = of_get_parent(child);
+ else {
+@@ -639,11 +642,11 @@ void of_irq_map_init(unsigned int flags)
+
+ }
+
+-int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 ointsize,
+- u32 *addr, struct of_irq *out_irq)
++int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
++ const u32 *addr, struct of_irq *out_irq)
+ {
+ struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
+- u32 *tmp, *imap, *imask;
++ const u32 *tmp, *imap, *imask;
+ u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
+ int imaplen, match, i;
+
+@@ -657,7 +660,7 @@ int of_irq_map_raw(struct device_node *p
+ * is none, we are nice and just walk up the tree
+ */
+ do {
+- tmp = (u32 *)get_property(ipar, "#interrupt-cells", NULL);
++ tmp = get_property(ipar, "#interrupt-cells", NULL);
+ if (tmp != NULL) {
+ intsize = *tmp;
+ break;
+@@ -681,7 +684,7 @@ int of_irq_map_raw(struct device_node *p
+ */
+ old = of_node_get(ipar);
+ do {
+- tmp = (u32 *)get_property(old, "#address-cells", NULL);
++ tmp = get_property(old, "#address-cells", NULL);
+ tnode = of_get_parent(old);
+ of_node_put(old);
+ old = tnode;
+@@ -708,7 +711,7 @@ int of_irq_map_raw(struct device_node *p
+ }
+
+ /* Now look for an interrupt-map */
+- imap = (u32 *)get_property(ipar, "interrupt-map", &imaplen);
++ imap = get_property(ipar, "interrupt-map", &imaplen);
+ /* No interrupt map, check for an interrupt parent */
+ if (imap == NULL) {
+ DBG(" -> no map, getting parent\n");
+@@ -718,7 +721,7 @@ int of_irq_map_raw(struct device_node *p
+ imaplen /= sizeof(u32);
+
+ /* Look for a mask */
+- imask = (u32 *)get_property(ipar, "interrupt-map-mask", NULL);
++ imask = get_property(ipar, "interrupt-map-mask", NULL);
+
+ /* If we were passed no "reg" property and we attempt to parse
+ * an interrupt-map, then #address-cells must be 0.
+@@ -765,14 +768,14 @@ int of_irq_map_raw(struct device_node *p
+ /* Get #interrupt-cells and #address-cells of new
+ * parent
+ */
+- tmp = (u32 *)get_property(newpar, "#interrupt-cells",
++ tmp = get_property(newpar, "#interrupt-cells",
+ NULL);
+ if (tmp == NULL) {
+ DBG(" -> parent lacks #interrupt-cells !\n");
+ goto fail;
+ }
+ newintsize = *tmp;
+- tmp = (u32 *)get_property(newpar, "#address-cells",
++ tmp = get_property(newpar, "#address-cells",
+ NULL);
+ newaddrsize = (tmp == NULL) ? 0 : *tmp;
+
+@@ -818,14 +821,14 @@ EXPORT_SYMBOL_GPL(of_irq_map_raw);
+ static int of_irq_map_oldworld(struct device_node *device, int index,
+ struct of_irq *out_irq)
+ {
+- u32 *ints;
++ const u32 *ints;
+ int intlen;
+
+ /*
+ * Old machines just have a list of interrupt numbers
+ * and no interrupt-controller nodes.
+ */
+- ints = (u32 *) get_property(device, "AAPL,interrupts", &intlen);
++ ints = get_property(device, "AAPL,interrupts", &intlen);
+ if (ints == NULL)
+ return -EINVAL;
+ intlen /= sizeof(u32);
+@@ -850,7 +853,8 @@ static int of_irq_map_oldworld(struct de
+ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
+ {
+ struct device_node *p;
+- u32 *intspec, *tmp, intsize, intlen, *addr;
++ const u32 *intspec, *tmp, *addr;
++ u32 intsize, intlen;
+ int res;
+
+ DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
+@@ -860,13 +864,13 @@ int of_irq_map_one(struct device_node *d
+ return of_irq_map_oldworld(device, index, out_irq);
+
+ /* Get the interrupts property */
+- intspec = (u32 *)get_property(device, "interrupts", &intlen);
++ intspec = get_property(device, "interrupts", &intlen);
+ if (intspec == NULL)
+ return -EINVAL;
+ intlen /= sizeof(u32);
+
+ /* Get the reg property (if any) */
+- addr = (u32 *)get_property(device, "reg", NULL);
++ addr = get_property(device, "reg", NULL);
+
+ /* Look for the interrupt parent. */
+ p = of_irq_find_parent(device);
+@@ -874,7 +878,7 @@ int of_irq_map_one(struct device_node *d
+ return -EINVAL;
+
+ /* Get size of interrupt specifier */
+- tmp = (u32 *)get_property(p, "#interrupt-cells", NULL);
++ tmp = get_property(p, "#interrupt-cells", NULL);
+ if (tmp == NULL) {
+ of_node_put(p);
+ return -EINVAL;
+diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
+index dea75d7..975102a 100644
+--- a/arch/powerpc/kernel/ptrace.c
++++ b/arch/powerpc/kernel/ptrace.c
+@@ -526,9 +526,7 @@ static void do_syscall_trace(void)
+
+ void do_syscall_trace_enter(struct pt_regs *regs)
+ {
+-#ifdef CONFIG_PPC64
+ secure_computing(regs->gpr[0]);
+-#endif
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE)
+ && (current->ptrace & PT_PTRACED))
+@@ -548,12 +546,8 @@ void do_syscall_trace_enter(struct pt_re
+
+ void do_syscall_trace_leave(struct pt_regs *regs)
+ {
+-#ifdef CONFIG_PPC32
+- secure_computing(regs->gpr[0]);
+-#endif
+-
+ if (unlikely(current->audit_context))
+- audit_syscall_exit((regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
++ audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
+ regs->result);
+
+ if ((test_thread_flag(TIF_SYSCALL_TRACE)
+@@ -561,8 +555,3 @@ void do_syscall_trace_leave(struct pt_re
+ && (current->ptrace & PT_PTRACED))
+ do_syscall_trace();
+ }
+-
+-#ifdef CONFIG_PPC32
+-EXPORT_SYMBOL(do_syscall_trace_enter);
+-EXPORT_SYMBOL(do_syscall_trace_leave);
+-#endif
+diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
+index 9c9ad1f..2fe82ab 100644
+--- a/arch/powerpc/kernel/rtas-proc.c
++++ b/arch/powerpc/kernel/rtas-proc.c
+@@ -246,12 +246,12 @@ struct file_operations ppc_rtas_rmo_buf_
+
+ static int ppc_rtas_find_all_sensors(void);
+ static void ppc_rtas_process_sensor(struct seq_file *m,
+- struct individual_sensor *s, int state, int error, char *loc);
++ struct individual_sensor *s, int state, int error, const char *loc);
+ static char *ppc_rtas_process_error(int error);
+ static void get_location_code(struct seq_file *m,
+- struct individual_sensor *s, char *loc);
+-static void check_location_string(struct seq_file *m, char *c);
+-static void check_location(struct seq_file *m, char *c);
++ struct individual_sensor *s, const char *loc);
++static void check_location_string(struct seq_file *m, const char *c);
++static void check_location(struct seq_file *m, const char *c);
+
+ static int __init proc_rtas_init(void)
+ {
+@@ -446,11 +446,11 @@ static int ppc_rtas_sensors_show(struct
+ for (i=0; i<sensors.quant; i++) {
+ struct individual_sensor *p = &sensors.sensor[i];
+ char rstr[64];
+- char *loc;
++ const char *loc;
+ int llen, offs;
+
+ sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
+- loc = (char *) get_property(rtas_node, rstr, &llen);
++ loc = get_property(rtas_node, rstr, &llen);
+
+ /* A sensor may have multiple instances */
+ for (j = 0, offs = 0; j <= p->quant; j++) {
+@@ -474,10 +474,10 @@ static int ppc_rtas_sensors_show(struct
+
+ static int ppc_rtas_find_all_sensors(void)
+ {
+- unsigned int *utmp;
++ const unsigned int *utmp;
+ int len, i;
+
+- utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len);
++ utmp = get_property(rtas_node, "rtas-sensors", &len);
+ if (utmp == NULL) {
+ printk (KERN_ERR "error: could not get rtas-sensors\n");
+ return 1;
+@@ -530,7 +530,7 @@ static char *ppc_rtas_process_error(int
+ */
+
+ static void ppc_rtas_process_sensor(struct seq_file *m,
+- struct individual_sensor *s, int state, int error, char *loc)
++ struct individual_sensor *s, int state, int error, const char *loc)
+ {
+ /* Defined return vales */
+ const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t",
+@@ -682,7 +682,7 @@ static void ppc_rtas_process_sensor(stru
+
+ /* ****************************************************************** */
+
+-static void check_location(struct seq_file *m, char *c)
++static void check_location(struct seq_file *m, const char *c)
+ {
+ switch (c[0]) {
+ case LOC_PLANAR:
+@@ -719,7 +719,7 @@ static void check_location(struct seq_fi
+ * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
+ * the '.' may be an abbrevation
+ */
+-static void check_location_string(struct seq_file *m, char *c)
++static void check_location_string(struct seq_file *m, const char *c)
+ {
+ while (*c) {
+ if (isalpha(*c) || *c == '.')
+@@ -733,7 +733,8 @@ static void check_location_string(struct
+
+ /* ****************************************************************** */
+
+-static void get_location_code(struct seq_file *m, struct individual_sensor *s, char *loc)
++static void get_location_code(struct seq_file *m, struct individual_sensor *s,
++ const char *loc)
+ {
+ if (!loc || !*loc) {
+ seq_printf(m, "---");/* does not have a location */
+diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
+index 77f1e06..6ef80d4 100644
+--- a/arch/powerpc/kernel/rtas.c
++++ b/arch/powerpc/kernel/rtas.c
+@@ -177,10 +177,12 @@ void __init udbg_init_rtas_console(void)
+ void rtas_progress(char *s, unsigned short hex)
+ {
+ struct device_node *root;
+- int width, *p;
++ int width;
++ const int *p;
+ char *os;
+ static int display_character, set_indicator;
+- static int display_width, display_lines, *row_width, form_feed;
++ static int display_width, display_lines, form_feed;
++ const static int *row_width;
+ static DEFINE_SPINLOCK(progress_lock);
+ static int current_line;
+ static int pending_newline = 0; /* did last write end with unprinted newline? */
+@@ -191,16 +193,16 @@ void rtas_progress(char *s, unsigned sho
+ if (display_width == 0) {
+ display_width = 0x10;
+ if ((root = find_path_device("/rtas"))) {
+- if ((p = (unsigned int *)get_property(root,
++ if ((p = get_property(root,
+ "ibm,display-line-length", NULL)))
+ display_width = *p;
+- if ((p = (unsigned int *)get_property(root,
++ if ((p = get_property(root,
+ "ibm,form-feed", NULL)))
+ form_feed = *p;
+- if ((p = (unsigned int *)get_property(root,
++ if ((p = get_property(root,
+ "ibm,display-number-of-lines", NULL)))
+ display_lines = *p;
+- row_width = (unsigned int *)get_property(root,
++ row_width = get_property(root,
+ "ibm,display-truncation-length", NULL);
+ }
+ display_character = rtas_token("display-character");
+@@ -293,10 +295,10 @@ EXPORT_SYMBOL(rtas_progress); /* needed
+
+ int rtas_token(const char *service)
+ {
+- int *tokp;
++ const int *tokp;
+ if (rtas.dev == NULL)
+ return RTAS_UNKNOWN_SERVICE;
+- tokp = (int *) get_property(rtas.dev, service, NULL);
++ tokp = get_property(rtas.dev, service, NULL);
+ return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
+ }
+ EXPORT_SYMBOL(rtas_token);
+@@ -626,6 +628,9 @@ void rtas_os_term(char *str)
+ {
+ int status;
+
++ if (panic_timeout)
++ return;
++
+ if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term"))
+ return;
+
+@@ -687,15 +692,14 @@ static int rtas_ibm_suspend_me(struct rt
+ int i;
+ long state;
+ long rc;
+- unsigned long dummy;
+-
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+ struct rtas_suspend_me_data data;
+
+ /* Make sure the state is valid */
+- rc = plpar_hcall(H_VASI_STATE,
+- ((u64)args->args[0] << 32) | args->args[1],
+- 0, 0, 0,
+- &state, &dummy, &dummy);
++ rc = plpar_hcall(H_VASI_STATE, retbuf,
++ ((u64)args->args[0] << 32) | args->args[1]);
++
++ state = retbuf[0];
+
+ if (rc) {
+ printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);
+@@ -845,15 +849,15 @@ void __init rtas_initialize(void)
+ */
+ rtas.dev = of_find_node_by_name(NULL, "rtas");
+ if (rtas.dev) {
+- u32 *basep, *entryp;
+- u32 *sizep;
++ const u32 *basep, *entryp, *sizep;
+
+- basep = (u32 *)get_property(rtas.dev, "linux,rtas-base", NULL);
+- sizep = (u32 *)get_property(rtas.dev, "rtas-size", NULL);
++ basep = get_property(rtas.dev, "linux,rtas-base", NULL);
++ sizep = get_property(rtas.dev, "rtas-size", NULL);
+ if (basep != NULL && sizep != NULL) {
+ rtas.base = *basep;
+ rtas.size = *sizep;
+- entryp = (u32 *)get_property(rtas.dev, "linux,rtas-entry", NULL);
++ entryp = get_property(rtas.dev,
++ "linux,rtas-entry", NULL);
+ if (entryp == NULL) /* Ugh */
+ rtas.entry = rtas.base;
+ else
+@@ -909,6 +913,11 @@ int __init early_init_dt_scan_rtas(unsig
+ basep = of_get_flat_dt_prop(node, "get-term-char", NULL);
+ if (basep)
+ rtas_getchar_token = *basep;
++
++ if (rtas_putchar_token != RTAS_UNKNOWN_SERVICE &&
++ rtas_getchar_token != RTAS_UNKNOWN_SERVICE)
++ udbg_init_rtas_console();
++
+ #endif
+
+ /* break now */
+diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
+index cda0226..b4a0de7 100644
+--- a/arch/powerpc/kernel/rtas_pci.c
++++ b/arch/powerpc/kernel/rtas_pci.c
+@@ -57,7 +57,7 @@ static inline int config_access_valid(st
+
+ static int of_device_available(struct device_node * dn)
+ {
+- char * status;
++ const char *status;
+
+ status = get_property(dn, "status", NULL);
+
+@@ -81,8 +81,7 @@ int rtas_read_config(struct pci_dn *pdn,
+ if (!config_access_valid(pdn, where))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+- addr = ((where & 0xf00) << 20) | (pdn->busno << 16) |
+- (pdn->devfn << 8) | (where & 0xff);
++ addr = rtas_config_addr(pdn->busno, pdn->devfn, where);
+ buid = pdn->phb->buid;
+ if (buid) {
+ ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
+@@ -134,8 +133,7 @@ int rtas_write_config(struct pci_dn *pdn
+ if (!config_access_valid(pdn, where))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+- addr = ((where & 0xf00) << 20) | (pdn->busno << 16) |
+- (pdn->devfn << 8) | (where & 0xff);
++ addr = rtas_config_addr(pdn->busno, pdn->devfn, where);
+ buid = pdn->phb->buid;
+ if (buid) {
+ ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr,
+@@ -178,7 +176,7 @@ struct pci_ops rtas_pci_ops = {
+
+ int is_python(struct device_node *dev)
+ {
+- char *model = (char *)get_property(dev, "model", NULL);
++ const char *model = get_property(dev, "model", NULL);
+
+ if (model && strstr(model, "Python"))
+ return 1;
+@@ -234,7 +232,7 @@ void __init init_pci_config_tokens (void
+ unsigned long __devinit get_phb_buid (struct device_node *phb)
+ {
+ int addr_cells;
+- unsigned int *buid_vals;
++ const unsigned int *buid_vals;
+ unsigned int len;
+ unsigned long buid;
+
+@@ -247,7 +245,7 @@ unsigned long __devinit get_phb_buid (st
+ if (phb->parent->parent)
+ return 0;
+
+- buid_vals = (unsigned int *) get_property(phb, "reg", &len);
++ buid_vals = get_property(phb, "reg", &len);
+ if (buid_vals == NULL)
+ return 0;
+
+@@ -264,10 +262,10 @@ unsigned long __devinit get_phb_buid (st
+ static int phb_set_bus_ranges(struct device_node *dev,
+ struct pci_controller *phb)
+ {
+- int *bus_range;
++ const int *bus_range;
+ unsigned int len;
+
+- bus_range = (int *) get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ return 1;
+ }
+@@ -325,15 +323,15 @@ unsigned long __init find_and_init_phbs(
+ * in chosen.
+ */
+ if (of_chosen) {
+- int *prop;
++ const int *prop;
+
+- prop = (int *)get_property(of_chosen, "linux,pci-probe-only",
+- NULL);
++ prop = get_property(of_chosen,
++ "linux,pci-probe-only", NULL);
+ if (prop)
+ pci_probe_only = *prop;
+
+- prop = (int *)get_property(of_chosen,
+- "linux,pci-assign-all-buses", NULL);
++ prop = get_property(of_chosen,
++ "linux,pci-assign-all-buses", NULL);
+ if (prop)
+ pci_assign_all_buses = *prop;
+ }
+diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
+index 499c386..89cfaf4 100644
+--- a/arch/powerpc/kernel/setup-common.c
++++ b/arch/powerpc/kernel/setup-common.c
+@@ -304,19 +304,21 @@ struct seq_operations cpuinfo_op = {
+ void __init check_for_initrd(void)
+ {
+ #ifdef CONFIG_BLK_DEV_INITRD
+- unsigned long *prop;
++ const unsigned int *prop;
++ int len;
+
+ DBG(" -> check_for_initrd()\n");
+
+ if (of_chosen) {
+- prop = (unsigned long *)get_property(of_chosen,
+- "linux,initrd-start", NULL);
++ prop = get_property(of_chosen, "linux,initrd-start", &len);
+ if (prop != NULL) {
+- initrd_start = (unsigned long)__va(*prop);
+- prop = (unsigned long *)get_property(of_chosen,
+- "linux,initrd-end", NULL);
++ initrd_start = (unsigned long)
++ __va(of_read_ulong(prop, len / 4));
++ prop = get_property(of_chosen,
++ "linux,initrd-end", &len);
+ if (prop != NULL) {
+- initrd_end = (unsigned long)__va(*prop);
++ initrd_end = (unsigned long)
++ __va(of_read_ulong(prop, len / 4));
+ initrd_below_start_ok = 1;
+ } else
+ initrd_start = 0;
+@@ -366,15 +368,14 @@ void __init smp_setup_cpu_maps(void)
+ int cpu = 0;
+
+ while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
+- int *intserv;
++ const int *intserv;
+ int j, len = sizeof(u32), nthreads = 1;
+
+- intserv = (int *)get_property(dn, "ibm,ppc-interrupt-server#s",
+- &len);
++ intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+ if (intserv)
+ nthreads = len / sizeof(int);
+ else {
+- intserv = (int *) get_property(dn, "reg", NULL);
++ intserv = get_property(dn, "reg", NULL);
+ if (!intserv)
+ intserv = &cpu; /* assume logical == phys */
+ }
+@@ -395,13 +396,12 @@ void __init smp_setup_cpu_maps(void)
+ if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR) &&
+ (dn = of_find_node_by_path("/rtas"))) {
+ int num_addr_cell, num_size_cell, maxcpus;
+- unsigned int *ireg;
++ const unsigned int *ireg;
+
+ num_addr_cell = prom_n_addr_cells(dn);
+ num_size_cell = prom_n_size_cells(dn);
+
+- ireg = (unsigned int *)
+- get_property(dn, "ibm,lrdr-capacity", NULL);
++ ireg = get_property(dn, "ibm,lrdr-capacity", NULL);
+
+ if (!ireg)
+ goto out;
+@@ -442,27 +442,6 @@ void __init smp_setup_cpu_maps(void)
+ }
+ #endif /* CONFIG_SMP */
+
+-int __initdata do_early_xmon;
+-#ifdef CONFIG_XMON
+-static int __init early_xmon(char *p)
+-{
+- /* ensure xmon is enabled */
+- if (p) {
+- if (strncmp(p, "on", 2) == 0)
+- xmon_init(1);
+- if (strncmp(p, "off", 3) == 0)
+- xmon_init(0);
+- if (strncmp(p, "early", 5) != 0)
+- return 0;
+- }
+- xmon_init(1);
+- do_early_xmon = 1;
+-
+- return 0;
+-}
+-early_param("xmon", early_xmon);
+-#endif
+-
+ static __init int add_pcspkr(void)
+ {
+ struct device_node *np;
+diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
+index e0df2ba..a4c2964 100644
+--- a/arch/powerpc/kernel/setup_32.c
++++ b/arch/powerpc/kernel/setup_32.c
+@@ -67,10 +67,6 @@ int have_of = 1;
+ dev_t boot_dev;
+ #endif /* CONFIG_PPC_MULTIPLATFORM */
+
+-#ifdef CONFIG_MAGIC_SYSRQ
+-unsigned long SYSRQ_KEY = 0x54;
+-#endif /* CONFIG_MAGIC_SYSRQ */
+-
+ #ifdef CONFIG_VGA_CONSOLE
+ unsigned long vgacon_remap_base;
+ #endif
+@@ -95,6 +91,7 @@ int ucache_bsize;
+ unsigned long __init early_init(unsigned long dt_ptr)
+ {
+ unsigned long offset = reloc_offset();
++ struct cpu_spec *spec;
+
+ /* First zero the BSS -- use memset_io, some platforms don't have
+ * caches on yet */
+@@ -104,8 +101,11 @@ unsigned long __init early_init(unsigned
+ * Identify the CPU type and fix up code sections
+ * that depend on which cpu we have.
+ */
+- identify_cpu(offset, 0);
+- do_cpu_ftr_fixups(offset);
++ spec = identify_cpu(offset);
++
++ do_feature_fixups(spec->cpu_features,
++ PTRRELOC(&__start___ftr_fixup),
++ PTRRELOC(&__stop___ftr_fixup));
+
+ return KERNELBASE + offset;
+ }
+@@ -242,12 +242,11 @@ void __init setup_arch(char **cmdline_p)
+
+ smp_setup_cpu_maps();
+
+-#ifdef CONFIG_XMON_DEFAULT
+- xmon_init(1);
+-#endif
+ /* Register early console */
+ register_early_udbg_console();
+
++ xmon_setup();
++
+ #if defined(CONFIG_KGDB)
+ if (ppc_md.kgdb_map_scc)
+ ppc_md.kgdb_map_scc();
+@@ -284,9 +283,6 @@ void __init setup_arch(char **cmdline_p)
+ init_mm.end_data = (unsigned long) _edata;
+ init_mm.brk = klimit;
+
+- if (do_early_xmon)
+- debugger(NULL);
+-
+ /* set up the bootmem stuff with available memory */
+ do_init_bootmem();
+ if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
+diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
+index fd1785e..1627896 100644
+--- a/arch/powerpc/kernel/setup_64.c
++++ b/arch/powerpc/kernel/setup_64.c
+@@ -56,7 +56,6 @@
+ #include <asm/page.h>
+ #include <asm/mmu.h>
+ #include <asm/lmb.h>
+-#include <asm/iseries/it_lp_naca.h>
+ #include <asm/firmware.h>
+ #include <asm/xmon.h>
+ #include <asm/udbg.h>
+@@ -79,10 +78,10 @@ u64 ppc64_pft_size;
+ * before we've read this from the device tree.
+ */
+ struct ppc64_caches ppc64_caches = {
+- .dline_size = 0x80,
+- .log_dline_size = 7,
+- .iline_size = 0x80,
+- .log_iline_size = 7
++ .dline_size = 0x40,
++ .log_dline_size = 6,
++ .iline_size = 0x40,
++ .log_iline_size = 6
+ };
+ EXPORT_SYMBOL_GPL(ppc64_caches);
+
+@@ -94,11 +93,6 @@ int dcache_bsize;
+ int icache_bsize;
+ int ucache_bsize;
+
+-#ifdef CONFIG_MAGIC_SYSRQ
+-unsigned long SYSRQ_KEY;
+-#endif /* CONFIG_MAGIC_SYSRQ */
+-
+-
+ #ifdef CONFIG_SMP
+
+ static int smt_enabled_cmdline;
+@@ -107,7 +101,7 @@ static int smt_enabled_cmdline;
+ static void check_smt_enabled(void)
+ {
+ struct device_node *dn;
+- char *smt_option;
++ const char *smt_option;
+
+ /* Allow the command line to overrule the OF option */
+ if (smt_enabled_cmdline)
+@@ -116,7 +110,7 @@ static void check_smt_enabled(void)
+ dn = of_find_node_by_path("/options");
+
+ if (dn) {
+- smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL);
++ smt_option = get_property(dn, "ibm,smt-enabled", NULL);
+
+ if (smt_option) {
+ if (!strcmp(smt_option, "on"))
+@@ -176,6 +170,9 @@ void __init setup_paca(int cpu)
+
+ void __init early_setup(unsigned long dt_ptr)
+ {
++ /* Identify CPU type */
++ identify_cpu(0);
++
+ /* Assume we're on cpu 0 for now. Don't write to the paca yet! */
+ setup_paca(0);
+
+@@ -293,7 +290,7 @@ static void __init initialize_cache_info
+ */
+
+ if ( num_cpus == 1 ) {
+- u32 *sizep, *lsizep;
++ const u32 *sizep, *lsizep;
+ u32 size, lsize;
+ const char *dc, *ic;
+
+@@ -308,10 +305,10 @@ static void __init initialize_cache_info
+
+ size = 0;
+ lsize = cur_cpu_spec->dcache_bsize;
+- sizep = (u32 *)get_property(np, "d-cache-size", NULL);
++ sizep = get_property(np, "d-cache-size", NULL);
+ if (sizep != NULL)
+ size = *sizep;
+- lsizep = (u32 *) get_property(np, dc, NULL);
++ lsizep = get_property(np, dc, NULL);
+ if (lsizep != NULL)
+ lsize = *lsizep;
+ if (sizep == 0 || lsizep == 0)
+@@ -325,10 +322,10 @@ static void __init initialize_cache_info
+
+ size = 0;
+ lsize = cur_cpu_spec->icache_bsize;
+- sizep = (u32 *)get_property(np, "i-cache-size", NULL);
++ sizep = get_property(np, "i-cache-size", NULL);
+ if (sizep != NULL)
+ size = *sizep;
+- lsizep = (u32 *)get_property(np, ic, NULL);
++ lsizep = get_property(np, ic, NULL);
+ if (lsizep != NULL)
+ lsize = *lsizep;
+ if (sizep == 0 || lsizep == 0)
+@@ -354,6 +351,14 @@ void __init setup_system(void)
+ {
+ DBG(" -> setup_system()\n");
+
++ /* Apply the CPUs-specific and firmware specific fixups to kernel
++ * text (nop out sections not relevant to this CPU or this firmware)
++ */
++ do_feature_fixups(cur_cpu_spec->cpu_features,
++ &__start___ftr_fixup, &__stop___ftr_fixup);
++ do_feature_fixups(powerpc_firmware_features,
++ &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
++
+ /*
+ * Unflatten the device-tree passed by prom_init or kexec
+ */
+@@ -397,18 +402,14 @@ void __init setup_system(void)
+ find_legacy_serial_ports();
+
+ /*
+- * Initialize xmon
+- */
+-#ifdef CONFIG_XMON_DEFAULT
+- xmon_init(1);
+-#endif
+- /*
+ * Register early console
+ */
+ register_early_udbg_console();
+
+- if (do_early_xmon)
+- debugger(NULL);
++ /*
++ * Initialize xmon
++ */
++ xmon_setup();
+
+ check_smt_enabled();
+ smp_setup_cpu_maps();
+@@ -420,7 +421,7 @@ void __init setup_system(void)
+ smp_release_cpus();
+ #endif
+
+- printk("Starting Linux PPC64 %s\n", system_utsname.version);
++ printk("Starting Linux PPC64 %s\n", init_utsname()->version);
+
+ printk("-----------------------------------------------------\n");
+ printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
+diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
+index 6a9bc9c..35c6309 100644
+--- a/arch/powerpc/kernel/smp.c
++++ b/arch/powerpc/kernel/smp.c
+@@ -115,7 +115,7 @@ void __devinit smp_generic_kick_cpu(int
+ }
+ #endif
+
+-void smp_message_recv(int msg, struct pt_regs *regs)
++void smp_message_recv(int msg)
+ {
+ switch(msg) {
+ case PPC_MSG_CALL_FUNCTION:
+@@ -127,11 +127,11 @@ void smp_message_recv(int msg, struct pt
+ break;
+ case PPC_MSG_DEBUGGER_BREAK:
+ if (crash_ipi_function_ptr) {
+- crash_ipi_function_ptr(regs);
++ crash_ipi_function_ptr(get_irq_regs());
+ break;
+ }
+ #ifdef CONFIG_DEBUGGER
+- debugger_ipi(regs);
++ debugger_ipi(get_irq_regs());
+ break;
+ #endif /* CONFIG_DEBUGGER */
+ /* FALLTHROUGH */
+diff --git a/arch/powerpc/kernel/swsusp_32.S b/arch/powerpc/kernel/swsusp_32.S
+index 7369f9a..69e8f86 100644
+--- a/arch/powerpc/kernel/swsusp_32.S
++++ b/arch/powerpc/kernel/swsusp_32.S
+@@ -159,8 +159,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ isync
+
+ /* Load ptr the list of pages to copy in r3 */
+- lis r11,(pagedir_nosave - KERNELBASE)@h
+- ori r11,r11,pagedir_nosave at l
++ lis r11,(restore_pblist - KERNELBASE)@h
++ ori r11,r11,restore_pblist at l
+ lwz r10,0(r11)
+
+ /* Copy the pages. This is a very basic implementation, to
+diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
+index 2e29286..d15c33e 100644
+--- a/arch/powerpc/kernel/sys_ppc32.c
++++ b/arch/powerpc/kernel/sys_ppc32.c
+@@ -69,16 +69,20 @@ struct readdir_callback32 {
+ };
+
+ static int fillonedir(void * __buf, const char * name, int namlen,
+- off_t offset, ino_t ino, unsigned int d_type)
++ off_t offset, u64 ino, unsigned int d_type)
+ {
+ struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
+ struct old_linux_dirent32 __user * dirent;
++ ino_t d_ino;
+
+ if (buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ buf->count++;
+ dirent = buf->dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(offset, &dirent->d_offset);
+ put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+@@ -120,15 +124,20 @@ asmlinkage long ppc32_select(u32 n, comp
+
+ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
+ {
++ compat_ino_t ino;
+ long err;
+
+ if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
+ !new_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+
++ ino = stat->ino;
++ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
++ return -EOVERFLOW;
++
+ err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
+ err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
+- err |= __put_user(stat->ino, &statbuf->st_ino);
++ err |= __put_user(ino, &statbuf->st_ino);
+ err |= __put_user(stat->mode, &statbuf->st_mode);
+ err |= __put_user(stat->nlink, &statbuf->st_nlink);
+ err |= __put_user(stat->uid, &statbuf->st_uid);
+@@ -740,7 +749,7 @@ asmlinkage long compat_sys_umask(u32 mas
+ return sys_umask((int)mask);
+ }
+
+-#ifdef CONFIG_SYSCTL
++#ifdef CONFIG_SYSCTL_SYSCALL
+ struct __sysctl_args32 {
+ u32 name;
+ int nlen;
+diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
+index 9b69d99..d358866 100644
+--- a/arch/powerpc/kernel/syscalls.c
++++ b/arch/powerpc/kernel/syscalls.c
+@@ -260,7 +260,7 @@ long ppc_newuname(struct new_utsname __u
+ int err = 0;
+
+ down_read(&uts_sem);
+- if (copy_to_user(name, &system_utsname, sizeof(*name)))
++ if (copy_to_user(name, utsname(), sizeof(*name)))
+ err = -EFAULT;
+ up_read(&uts_sem);
+ if (!err)
+@@ -273,7 +273,7 @@ int sys_uname(struct old_utsname __user
+ int err = 0;
+
+ down_read(&uts_sem);
+- if (copy_to_user(name, &system_utsname, sizeof(*name)))
++ if (copy_to_user(name, utsname(), sizeof(*name)))
+ err = -EFAULT;
+ up_read(&uts_sem);
+ if (!err)
+@@ -289,19 +289,19 @@ int sys_olduname(struct oldold_utsname _
+ return -EFAULT;
+
+ down_read(&uts_sem);
+- error = __copy_to_user(&name->sysname, &system_utsname.sysname,
++ error = __copy_to_user(&name->sysname, &utsname()->sysname,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+- error |= __copy_to_user(&name->nodename, &system_utsname.nodename,
++ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+- error |= __copy_to_user(&name->release, &system_utsname.release,
++ error |= __copy_to_user(&name->release, &utsname()->release,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->release + __OLD_UTS_LEN);
+- error |= __copy_to_user(&name->version, &system_utsname.version,
++ error |= __copy_to_user(&name->version, &utsname()->version,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->version + __OLD_UTS_LEN);
+- error |= __copy_to_user(&name->machine, &system_utsname.machine,
++ error |= __copy_to_user(&name->machine, &utsname()->machine,
+ __OLD_UTS_LEN);
+ error |= override_machine(name->machine);
+ up_read(&uts_sem);
+diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
+index fec228c..d45a168 100644
+--- a/arch/powerpc/kernel/sysfs.c
++++ b/arch/powerpc/kernel/sysfs.c
+@@ -25,8 +25,8 @@ static DEFINE_PER_CPU(struct cpu, cpu_de
+ /* SMT stuff */
+
+ #ifdef CONFIG_PPC_MULTIPLATFORM
+-/* default to snooze disabled */
+-DEFINE_PER_CPU(unsigned long, smt_snooze_delay);
++/* Time in microseconds we delay before sleeping in the idle loop */
++DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 };
+
+ static ssize_t store_smt_snooze_delay(struct sys_device *dev, const char *buf,
+ size_t count)
+@@ -60,7 +60,7 @@ static int smt_snooze_cmdline;
+ static int __init smt_setup(void)
+ {
+ struct device_node *options;
+- unsigned int *val;
++ const unsigned int *val;
+ unsigned int cpu;
+
+ if (!cpu_has_feature(CPU_FTR_SMT))
+@@ -70,8 +70,7 @@ static int __init smt_setup(void)
+ if (!options)
+ return -ENODEV;
+
+- val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay",
+- NULL);
++ val = get_property(options, "ibm,smt-snooze-delay", NULL);
+ if (!smt_snooze_cmdline && val) {
+ for_each_possible_cpu(cpu)
+ per_cpu(smt_snooze_delay, cpu) = *val;
+@@ -231,7 +230,7 @@ static void register_cpu_online(unsigned
+ if (cur_cpu_spec->num_pmcs >= 8)
+ sysdev_create_file(s, &attr_pmc8);
+
+- if (cpu_has_feature(CPU_FTR_SMT))
++ if (cpu_has_feature(CPU_FTR_PURR))
+ sysdev_create_file(s, &attr_purr);
+ }
+
+@@ -273,7 +272,7 @@ static void unregister_cpu_online(unsign
+ if (cur_cpu_spec->num_pmcs >= 8)
+ sysdev_remove_file(s, &attr_pmc8);
+
+- if (cpu_has_feature(CPU_FTR_SMT))
++ if (cpu_has_feature(CPU_FTR_PURR))
+ sysdev_remove_file(s, &attr_purr);
+ }
+ #endif /* CONFIG_HOTPLUG_CPU */
+diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
+index a124499..a1b5e4b 100644
+--- a/arch/powerpc/kernel/time.c
++++ b/arch/powerpc/kernel/time.c
+@@ -51,6 +51,7 @@
+ #include <linux/rtc.h>
+ #include <linux/jiffies.h>
+ #include <linux/posix-timers.h>
++#include <linux/irq.h>
+
+ #include <asm/io.h>
+ #include <asm/processor.h>
+@@ -117,8 +118,6 @@ unsigned tb_to_ns_shift;
+
+ struct gettimeofday_struct do_gtod;
+
+-extern unsigned long wall_jiffies;
+-
+ extern struct timezone sys_tz;
+ static long timezone_offset;
+
+@@ -221,11 +220,8 @@ static void account_process_time(struct
+ */
+ struct cpu_purr_data {
+ int initialized; /* thread is running */
+- u64 tb0; /* timebase at origin time */
+- u64 purr0; /* PURR at origin time */
+ u64 tb; /* last TB value read */
+ u64 purr; /* last PURR value read */
+- u64 stolen; /* stolen time so far */
+ spinlock_t lock;
+ };
+
+@@ -235,10 +231,8 @@ static void snapshot_tb_and_purr(void *d
+ {
+ struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
+
+- p->tb0 = mftb();
+- p->purr0 = mfspr(SPRN_PURR);
+- p->tb = p->tb0;
+- p->purr = 0;
++ p->tb = mftb();
++ p->purr = mfspr(SPRN_PURR);
+ wmb();
+ p->initialized = 1;
+ }
+@@ -259,37 +253,24 @@ void snapshot_timebases(void)
+
+ void calculate_steal_time(void)
+ {
+- u64 tb, purr, t0;
++ u64 tb, purr;
+ s64 stolen;
+- struct cpu_purr_data *p0, *pme, *phim;
+- int cpu;
++ struct cpu_purr_data *pme;
+
+ if (!cpu_has_feature(CPU_FTR_PURR))
+ return;
+- cpu = smp_processor_id();
+- pme = &per_cpu(cpu_purr_data, cpu);
++ pme = &per_cpu(cpu_purr_data, smp_processor_id());
+ if (!pme->initialized)
+ return; /* this can happen in early boot */
+- p0 = &per_cpu(cpu_purr_data, cpu & ~1);
+- phim = &per_cpu(cpu_purr_data, cpu ^ 1);
+- spin_lock(&p0->lock);
++ spin_lock(&pme->lock);
+ tb = mftb();
+- purr = mfspr(SPRN_PURR) - pme->purr0;
+- if (!phim->initialized || !cpu_online(cpu ^ 1)) {
+- stolen = (tb - pme->tb) - (purr - pme->purr);
+- } else {
+- t0 = pme->tb0;
+- if (phim->tb0 < t0)
+- t0 = phim->tb0;
+- stolen = phim->tb - t0 - phim->purr - purr - p0->stolen;
+- }
+- if (stolen > 0) {
++ purr = mfspr(SPRN_PURR);
++ stolen = (tb - pme->tb) - (purr - pme->purr);
++ if (stolen > 0)
+ account_steal_time(current, stolen);
+- p0->stolen += stolen;
+- }
+ pme->tb = tb;
+ pme->purr = purr;
+- spin_unlock(&p0->lock);
++ spin_unlock(&pme->lock);
+ }
+
+ /*
+@@ -298,30 +279,17 @@ void calculate_steal_time(void)
+ */
+ static void snapshot_purr(void)
+ {
+- int cpu;
+- u64 purr;
+- struct cpu_purr_data *p0, *pme, *phim;
++ struct cpu_purr_data *pme;
+ unsigned long flags;
+
+ if (!cpu_has_feature(CPU_FTR_PURR))
+ return;
+- cpu = smp_processor_id();
+- pme = &per_cpu(cpu_purr_data, cpu);
+- p0 = &per_cpu(cpu_purr_data, cpu & ~1);
+- phim = &per_cpu(cpu_purr_data, cpu ^ 1);
+- spin_lock_irqsave(&p0->lock, flags);
+- pme->tb = pme->tb0 = mftb();
+- purr = mfspr(SPRN_PURR);
+- if (!phim->initialized) {
+- pme->purr = 0;
+- pme->purr0 = purr;
+- } else {
+- /* set p->purr and p->purr0 for no change in p0->stolen */
+- pme->purr = phim->tb - phim->tb0 - phim->purr - p0->stolen;
+- pme->purr0 = purr - pme->purr;
+- }
++ pme = &per_cpu(cpu_purr_data, smp_processor_id());
++ spin_lock_irqsave(&pme->lock, flags);
++ pme->tb = mftb();
++ pme->purr = mfspr(SPRN_PURR);
+ pme->initialized = 1;
+- spin_unlock_irqrestore(&p0->lock, flags);
++ spin_unlock_irqrestore(&pme->lock, flags);
+ }
+
+ #endif /* CONFIG_PPC_SPLPAR */
+@@ -645,6 +613,7 @@ static void iSeries_tb_recal(void)
+ */
+ void timer_interrupt(struct pt_regs * regs)
+ {
++ struct pt_regs *old_regs;
+ int next_dec;
+ int cpu = smp_processor_id();
+ unsigned long ticks;
+@@ -655,9 +624,10 @@ void timer_interrupt(struct pt_regs * re
+ do_IRQ(regs);
+ #endif
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ calculate_steal_time();
+
+ #ifdef CONFIG_PPC_ISERIES
+@@ -693,7 +663,7 @@ void timer_interrupt(struct pt_regs * re
+ tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
+ if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
+ tb_last_jiffy = tb_next_jiffy;
+- do_timer(regs);
++ do_timer(1);
+ timer_recalc_offset(tb_last_jiffy);
+ timer_check_rtc();
+ }
+@@ -705,7 +675,7 @@ void timer_interrupt(struct pt_regs * re
+
+ #ifdef CONFIG_PPC_ISERIES
+ if (hvlpevent_is_pending())
+- process_hvlpevents(regs);
++ process_hvlpevents();
+ #endif
+
+ #ifdef CONFIG_PPC64
+@@ -717,6 +687,7 @@ void timer_interrupt(struct pt_regs * re
+ #endif
+
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ void wakeup_decrementer(void)
+@@ -816,11 +787,6 @@ int do_settimeofday(struct timespec *tv)
+ /*
+ * Subtract off the number of nanoseconds since the
+ * beginning of the last tick.
+- * Note that since we don't increment jiffies_64 anywhere other
+- * than in do_timer (since we don't have a lost tick problem),
+- * wall_jiffies will always be the same as jiffies,
+- * and therefore the (jiffies - wall_jiffies) computation
+- * has been removed.
+ */
+ tb_delta = tb_ticks_since(tb_last_jiffy);
+ tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */
+@@ -860,19 +826,17 @@ EXPORT_SYMBOL(do_settimeofday);
+ static int __init get_freq(char *name, int cells, unsigned long *val)
+ {
+ struct device_node *cpu;
+- unsigned int *fp;
++ const unsigned int *fp;
+ int found = 0;
+
+ /* The cpu node should have timebase and clock frequency properties */
+ cpu = of_find_node_by_type(NULL, "cpu");
+
+ if (cpu) {
+- fp = (unsigned int *)get_property(cpu, name, NULL);
++ fp = get_property(cpu, name, NULL);
+ if (fp) {
+ found = 1;
+- *val = 0;
+- while (cells--)
+- *val = (*val << 32) | *fp++;
++ *val = of_read_ulong(fp, cells);
+ }
+
+ of_node_put(cpu);
+@@ -1050,6 +1014,48 @@ void __init time_init(void)
+ set_dec(tb_ticks_per_jiffy);
+ }
+
++#ifdef CONFIG_RTC_CLASS
++static int set_rtc_class_time(struct rtc_time *tm)
++{
++ int err;
++ struct class_device *class_dev =
++ rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
++
++ if (class_dev == NULL)
++ return -ENODEV;
++
++ err = rtc_set_time(class_dev, tm);
++
++ rtc_class_close(class_dev);
++
++ return 0;
++}
++
++static void get_rtc_class_time(struct rtc_time *tm)
++{
++ int err;
++ struct class_device *class_dev =
++ rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
++
++ if (class_dev == NULL)
++ return;
++
++ err = rtc_read_time(class_dev, tm);
++
++ rtc_class_close(class_dev);
++
++ return;
++}
++
++int __init rtc_class_hookup(void)
++{
++ ppc_md.get_rtc_time = get_rtc_class_time;
++ ppc_md.set_rtc_time = set_rtc_class_time;
++
++ return 0;
++}
++#endif /* CONFIG_RTC_CLASS */
++
+
+ #define FEBRUARY 2
+ #define STARTOFTIME 1970
+diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
+index 9b352bd..c66b477 100644
+--- a/arch/powerpc/kernel/traps.c
++++ b/arch/powerpc/kernel/traps.c
+@@ -598,6 +598,9 @@ static void parse_fpe(struct pt_regs *re
+ #define INST_STSWI 0x7c0005aa
+ #define INST_STSWX 0x7c00052a
+
++#define INST_POPCNTB 0x7c0000f4
++#define INST_POPCNTB_MASK 0xfc0007fe
++
+ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
+ {
+ u8 rT = (instword >> 21) & 0x1f;
+@@ -666,6 +669,23 @@ static int emulate_string_inst(struct pt
+ return 0;
+ }
+
++static int emulate_popcntb_inst(struct pt_regs *regs, u32 instword)
++{
++ u32 ra,rs;
++ unsigned long tmp;
++
++ ra = (instword >> 16) & 0x1f;
++ rs = (instword >> 21) & 0x1f;
++
++ tmp = regs->gpr[rs];
++ tmp = tmp - ((tmp >> 1) & 0x5555555555555555ULL);
++ tmp = (tmp & 0x3333333333333333ULL) + ((tmp >> 2) & 0x3333333333333333ULL);
++ tmp = (tmp + (tmp >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
++ regs->gpr[ra] = tmp;
++
++ return 0;
++}
++
+ static int emulate_instruction(struct pt_regs *regs)
+ {
+ u32 instword;
+@@ -703,6 +723,11 @@ static int emulate_instruction(struct pt
+ if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
+ return emulate_string_inst(regs, instword);
+
++ /* Emulate the popcntb (Population Count Bytes) instruction. */
++ if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) {
++ return emulate_popcntb_inst(regs, instword);
++ }
++
+ return -EINVAL;
+ }
+
+@@ -818,7 +843,7 @@ void __kprobes program_check_exception(s
+
+ void alignment_exception(struct pt_regs *regs)
+ {
+- int fixed = 0;
++ int sig, code, fixed = 0;
+
+ /* we don't implement logging of alignment exceptions */
+ if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS))
+@@ -832,14 +857,16 @@ void alignment_exception(struct pt_regs
+
+ /* Operand address was bad */
+ if (fixed == -EFAULT) {
+- if (user_mode(regs))
+- _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
+- else
+- /* Search exception table */
+- bad_page_fault(regs, regs->dar, SIGSEGV);
+- return;
++ sig = SIGSEGV;
++ code = SEGV_ACCERR;
++ } else {
++ sig = SIGBUS;
++ code = BUS_ADRALN;
+ }
+- _exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
++ if (user_mode(regs))
++ _exception(sig, regs, code, regs->dar);
++ else
++ bad_page_fault(regs, regs->dar, sig);
+ }
+
+ void StackOverflow(struct pt_regs *regs)
+@@ -875,14 +902,13 @@ void kernel_fp_unavailable_exception(str
+
+ void altivec_unavailable_exception(struct pt_regs *regs)
+ {
+-#if !defined(CONFIG_ALTIVEC)
+ if (user_mode(regs)) {
+ /* A user program has executed an altivec instruction,
+ but this kernel doesn't support altivec. */
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+ return;
+ }
+-#endif
++
+ printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
+ "%lx at %lx\n", regs->trap, regs->nip);
+ die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
+diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
+index 1a7e19c..c913ad5 100644
+--- a/arch/powerpc/kernel/vdso.c
++++ b/arch/powerpc/kernel/vdso.c
+@@ -36,6 +36,8 @@
+ #include <asm/vdso.h>
+ #include <asm/vdso_datapage.h>
+
++#include "setup.h"
++
+ #undef DEBUG
+
+ #ifdef DEBUG
+@@ -586,6 +588,43 @@ static __init int vdso_fixup_datapage(st
+ return 0;
+ }
+
++
++static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
++ struct lib64_elfinfo *v64)
++{
++ void *start32;
++ unsigned long size32;
++
++#ifdef CONFIG_PPC64
++ void *start64;
++ unsigned long size64;
++
++ start64 = find_section64(v64->hdr, "__ftr_fixup", &size64);
++ if (start64)
++ do_feature_fixups(cur_cpu_spec->cpu_features,
++ start64, start64 + size64);
++
++ start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64);
++ if (start64)
++ do_feature_fixups(powerpc_firmware_features,
++ start64, start64 + size64);
++#endif /* CONFIG_PPC64 */
++
++ start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
++ if (start32)
++ do_feature_fixups(cur_cpu_spec->cpu_features,
++ start32, start32 + size32);
++
++#ifdef CONFIG_PPC64
++ start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32);
++ if (start32)
++ do_feature_fixups(powerpc_firmware_features,
++ start32, start32 + size32);
++#endif /* CONFIG_PPC64 */
++
++ return 0;
++}
++
+ static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
+ struct lib64_elfinfo *v64)
+ {
+@@ -634,6 +673,9 @@ static __init int vdso_setup(void)
+ if (vdso_fixup_datapage(&v32, &v64))
+ return -1;
+
++ if (vdso_fixup_features(&v32, &v64))
++ return -1;
++
+ if (vdso_fixup_alt_funcs(&v32, &v64))
+ return -1;
+
+@@ -714,6 +756,7 @@ void __init vdso_init(void)
+ * Setup the syscall map in the vDOS
+ */
+ vdso_setup_syscall_map();
++
+ /*
+ * Initialize the vDSO images in memory, that is do necessary
+ * fixups of vDSO symbols, locate trampolines, etc...
+diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
+index 6187af2..26e138c 100644
+--- a/arch/powerpc/kernel/vdso32/vdso32.lds.S
++++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
+@@ -32,6 +32,18 @@ SECTIONS
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
++ . = ALIGN(8);
++ __ftr_fixup : {
++ *(__ftr_fixup)
++ }
++
++#ifdef CONFIG_PPC64
++ . = ALIGN(8);
++ __fw_ftr_fixup : {
++ *(__fw_ftr_fixup)
++ }
++#endif
++
+ /* Other stuff is appended to the text segment: */
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
+index 56e76ff..40ffd9b 100644
+--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
++++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
+@@ -229,8 +229,10 @@ V_FUNCTION_BEGIN(__do_get_xsec)
+ xor r0,r8,r8 /* create dependency */
+ add r3,r3,r0
+
+- /* Get TB & offset it */
+- mftb r7
++ /* Get TB & offset it. We use the MFTB macro which will generate
++ * workaround code for Cell.
++ */
++ MFTB(r7)
+ ld r9,CFG_TB_ORIG_STAMP(r3)
+ subf r7,r9,r7
+
+diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S
+index 4a2b6dc..2d70f35 100644
+--- a/arch/powerpc/kernel/vdso64/vdso64.lds.S
++++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S
+@@ -31,6 +31,16 @@ SECTIONS
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
++ . = ALIGN(8);
++ __ftr_fixup : {
++ *(__ftr_fixup)
++ }
++
++ . = ALIGN(8);
++ __fw_ftr_fixup : {
++ *(__fw_ftr_fixup)
++ }
++
+ /* Other stuff is appended to the text segment: */
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
+index fad8580..ed00787 100644
+--- a/arch/powerpc/kernel/vio.c
++++ b/arch/powerpc/kernel/vio.c
+@@ -77,7 +77,7 @@ static struct iommu_table *vio_build_iom
+ } else
+ #endif
+ {
+- unsigned char *dma_window;
++ const unsigned char *dma_window;
+ struct iommu_table *tbl;
+ unsigned long offset, size;
+
+@@ -92,9 +92,9 @@ static struct iommu_table *vio_build_iom
+ &tbl->it_index, &offset, &size);
+
+ /* TCE table size - measured in tce entries */
+- tbl->it_size = size >> PAGE_SHIFT;
++ tbl->it_size = size >> IOMMU_PAGE_SHIFT;
+ /* offset for VIO should always be 0 */
+- tbl->it_offset = offset >> PAGE_SHIFT;
++ tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
+ tbl->it_busno = 0;
+ tbl->it_type = TCE_VB;
+
+@@ -217,7 +217,7 @@ static void __devinit vio_dev_release(st
+ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
+ {
+ struct vio_dev *viodev;
+- unsigned int *unit_address;
++ const unsigned int *unit_address;
+
+ /* we need the 'device_type' property, in order to match with drivers */
+ if (of_node->type == NULL) {
+@@ -227,7 +227,7 @@ struct vio_dev * __devinit vio_register_
+ return NULL;
+ }
+
+- unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
++ unit_address = get_property(of_node, "reg", NULL);
+ if (unit_address == NULL) {
+ printk(KERN_WARNING "%s: node %s missing 'reg'\n",
+ __FUNCTION__,
+@@ -249,7 +249,7 @@ struct vio_dev * __devinit vio_register_
+ viodev->type = of_node->type;
+ viodev->unit_address = *unit_address;
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+- unit_address = (unsigned int *)get_property(of_node,
++ unit_address = get_property(of_node,
+ "linux,unit_address", NULL);
+ if (unit_address != NULL)
+ viodev->unit_address = *unit_address;
+@@ -423,7 +423,7 @@ static int vio_hotplug(struct device *de
+ {
+ const struct vio_dev *vio_dev = to_vio_dev(dev);
+ struct device_node *dn = dev->platform_data;
+- char *cp;
++ const char *cp;
+ int length;
+
+ if (!num_envp)
+@@ -431,7 +431,7 @@ static int vio_hotplug(struct device *de
+
+ if (!dn)
+ return -ENODEV;
+- cp = (char *)get_property(dn, "compatible", &length);
++ cp = get_property(dn, "compatible", &length);
+ if (!cp)
+ return -ENODEV;
+
+@@ -493,11 +493,11 @@ static struct vio_dev *vio_find_name(con
+ */
+ struct vio_dev *vio_find_node(struct device_node *vnode)
+ {
+- uint32_t *unit_address;
++ const uint32_t *unit_address;
+ char kobj_name[BUS_ID_SIZE];
+
+ /* construct the kobject name from the device node */
+- unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
++ unit_address = get_property(vnode, "reg", NULL);
+ if (!unit_address)
+ return NULL;
+ snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
+diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
+index 02665a0..e8342d8 100644
+--- a/arch/powerpc/kernel/vmlinux.lds.S
++++ b/arch/powerpc/kernel/vmlinux.lds.S
+@@ -108,13 +108,7 @@ SECTIONS
+
+ .initcall.init : {
+ __initcall_start = .;
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ __initcall_end = .;
+ }
+
+@@ -132,6 +126,14 @@ SECTIONS
+ *(__ftr_fixup)
+ __stop___ftr_fixup = .;
+ }
++#ifdef CONFIG_PPC64
++ . = ALIGN(8);
++ __fw_ftr_fixup : {
++ __start___fw_ftr_fixup = .;
++ *(__fw_ftr_fixup)
++ __stop___fw_ftr_fixup = .;
++ }
++#endif
+
+ . = ALIGN(PAGE_SIZE);
+ .init.ramfs : {
+diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
+index ff70964..a0360ae 100644
+--- a/arch/powerpc/lib/Makefile
++++ b/arch/powerpc/lib/Makefile
+@@ -14,10 +14,15 @@ endif
+ obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
+ memcpy_64.o usercopy_64.o mem_64.o string.o \
+ strcase.o
+-obj-$(CONFIG_PPC_ISERIES) += e2a.o
++obj-$(CONFIG_QUICC_ENGINE) += rheap.o
+ obj-$(CONFIG_XMON) += sstep.o
+
+ ifeq ($(CONFIG_PPC64),y)
+ obj-$(CONFIG_SMP) += locks.o
+ obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
+ endif
++
++# Temporary hack until we have migrated to asm-powerpc
++ifeq ($(CONFIG_PPC_MERGE),y)
++obj-$(CONFIG_CPM2) += rheap.o
++endif
+diff --git a/arch/powerpc/lib/e2a.c b/arch/powerpc/lib/e2a.c
+deleted file mode 100644
+index 4b72ed8..0000000
+--- a/arch/powerpc/lib/e2a.c
++++ /dev/null
+@@ -1,116 +0,0 @@
+-/*
+- * EBCDIC to ASCII conversion
+- *
+- * This function moved here from arch/powerpc/platforms/iseries/viopath.c
+- *
+- * (C) Copyright 2000-2004 IBM Corporation
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License as
+- * published by the Free Software Foundation; either version 2 of the
+- * License, or (at your option) anyu 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>
+-
+-unsigned char e2a(unsigned char x)
+-{
+- switch (x) {
+- case 0xF0:
+- return '0';
+- case 0xF1:
+- return '1';
+- case 0xF2:
+- return '2';
+- case 0xF3:
+- return '3';
+- case 0xF4:
+- return '4';
+- case 0xF5:
+- return '5';
+- case 0xF6:
+- return '6';
+- case 0xF7:
+- return '7';
+- case 0xF8:
+- return '8';
+- case 0xF9:
+- return '9';
+- case 0xC1:
+- return 'A';
+- case 0xC2:
+- return 'B';
+- case 0xC3:
+- return 'C';
+- case 0xC4:
+- return 'D';
+- case 0xC5:
+- return 'E';
+- case 0xC6:
+- return 'F';
+- case 0xC7:
+- return 'G';
+- case 0xC8:
+- return 'H';
+- case 0xC9:
+- return 'I';
+- case 0xD1:
+- return 'J';
+- case 0xD2:
+- return 'K';
+- case 0xD3:
+- return 'L';
+- case 0xD4:
+- return 'M';
+- case 0xD5:
+- return 'N';
+- case 0xD6:
+- return 'O';
+- case 0xD7:
+- return 'P';
+- case 0xD8:
+- return 'Q';
+- case 0xD9:
+- return 'R';
+- case 0xE2:
+- return 'S';
+- case 0xE3:
+- return 'T';
+- case 0xE4:
+- return 'U';
+- case 0xE5:
+- return 'V';
+- case 0xE6:
+- return 'W';
+- case 0xE7:
+- return 'X';
+- case 0xE8:
+- return 'Y';
+- case 0xE9:
+- return 'Z';
+- }
+- return ' ';
+-}
+-EXPORT_SYMBOL(e2a);
+-
+-unsigned char* strne2a(unsigned char *dest, const unsigned char *src, size_t n)
+-{
+- int i;
+-
+- n = strnlen(src, n);
+-
+- for (i = 0; i < n; i++)
+- dest[i] = e2a(src[i]);
+-
+- return dest;
+-}
+diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
+index 077bed7..80b482c 100644
+--- a/arch/powerpc/lib/locks.c
++++ b/arch/powerpc/lib/locks.c
+@@ -23,6 +23,7 @@
+ #include <asm/hvcall.h>
+ #include <asm/iseries/hv_call.h>
+ #include <asm/smp.h>
++#include <asm/firmware.h>
+
+ void __spin_yield(raw_spinlock_t *lock)
+ {
+@@ -39,13 +40,12 @@ void __spin_yield(raw_spinlock_t *lock)
+ rmb();
+ if (lock->slock != lock_value)
+ return; /* something has changed */
+-#ifdef CONFIG_PPC_ISERIES
+- HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
+- ((u64)holder_cpu << 32) | yield_count);
+-#else
+- plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu),
+- yield_count);
+-#endif
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
++ ((u64)holder_cpu << 32) | yield_count);
++ else
++ plpar_hcall_norets(H_CONFER,
++ get_hard_smp_processor_id(holder_cpu), yield_count);
+ }
+
+ /*
+@@ -69,13 +69,12 @@ void __rw_yield(raw_rwlock_t *rw)
+ rmb();
+ if (rw->lock != lock_value)
+ return; /* something has changed */
+-#ifdef CONFIG_PPC_ISERIES
+- HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
+- ((u64)holder_cpu << 32) | yield_count);
+-#else
+- plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu),
+- yield_count);
+-#endif
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
++ ((u64)holder_cpu << 32) | yield_count);
++ else
++ plpar_hcall_norets(H_CONFER,
++ get_hard_smp_processor_id(holder_cpu), yield_count);
+ }
+ #endif
+
+diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
+index 31e5118..57bf991 100644
+--- a/arch/powerpc/lib/rheap.c
++++ b/arch/powerpc/lib/rheap.c
+@@ -423,17 +423,21 @@ void *rh_detach_region(rh_info_t * info,
+ return (void *)s;
+ }
+
+-void *rh_alloc(rh_info_t * info, int size, const char *owner)
++void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
+ {
+ struct list_head *l;
+ rh_block_t *blk;
+ rh_block_t *newblk;
+ void *start;
+
+- /* Validate size */
+- if (size <= 0)
++ /* Validate size, (must be power of two) */
++ if (size <= 0 || (alignment & (alignment - 1)) != 0)
+ return ERR_PTR(-EINVAL);
+
++ /* given alignment larger that default rheap alignment */
++ if (alignment > info->alignment)
++ size += alignment - 1;
++
+ /* Align to configured alignment */
+ size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
+
+@@ -476,15 +480,27 @@ void *rh_alloc(rh_info_t * info, int siz
+
+ attach_taken_block(info, newblk);
+
++ /* for larger alignment return fixed up pointer */
++ /* this is no problem with the deallocator since */
++ /* we scan for pointers that lie in the blocks */
++ if (alignment > info->alignment)
++ start = (void *)(((unsigned long)start + alignment - 1) &
++ ~(alignment - 1));
++
+ return start;
+ }
+
++void *rh_alloc(rh_info_t * info, int size, const char *owner)
++{
++ return rh_alloc_align(info, size, info->alignment, owner);
++}
++
+ /* allocate at precisely the given address */
+ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
+ {
+ struct list_head *l;
+ rh_block_t *blk, *newblk1, *newblk2;
+- unsigned long s, e, m, bs, be;
++ unsigned long s, e, m, bs = 0, be = 0;
+
+ /* Validate size */
+ if (size <= 0)
+diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
+index 9590ba7..7e8ded0 100644
+--- a/arch/powerpc/lib/sstep.c
++++ b/arch/powerpc/lib/sstep.c
+@@ -9,6 +9,7 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+ #include <linux/kernel.h>
++#include <linux/kprobes.h>
+ #include <linux/ptrace.h>
+ #include <asm/sstep.h>
+ #include <asm/processor.h>
+@@ -25,7 +26,7 @@ extern char system_call_common[];
+ /*
+ * Determine whether a conditional branch instruction would branch.
+ */
+-static int branch_taken(unsigned int instr, struct pt_regs *regs)
++static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
+ {
+ unsigned int bo = (instr >> 21) & 0x1f;
+ unsigned int bi;
+@@ -51,7 +52,7 @@ static int branch_taken(unsigned int ins
+ * or -1 if the instruction is one that should not be stepped,
+ * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ */
+-int emulate_step(struct pt_regs *regs, unsigned int instr)
++int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+ {
+ unsigned int opcode, rd;
+ unsigned long int imm;
+diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
+index 754143e..29bc912 100644
+--- a/arch/powerpc/math-emu/Makefile
++++ b/arch/powerpc/math-emu/Makefile
+@@ -11,3 +11,6 @@ obj-$(CONFIG_MATH_EMULATION) += fabs.o f
+ mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
+ mtfsf.o mtfsfi.o stfiwx.o stfs.o \
+ udivmodti4.o
++
++CFLAGS_fabs.o = -fno-builtin-fabs
++CFLAGS_math.o = -fno-builtin-fabs
+diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
+index 78a0d59..e8fa506 100644
+--- a/arch/powerpc/mm/fault.c
++++ b/arch/powerpc/mm/fault.c
+@@ -333,7 +333,7 @@ good_area:
+ /* protection fault */
+ if (error_code & 0x08000000)
+ goto bad_area;
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ }
+
+@@ -386,7 +386,7 @@ bad_area_nosemaphore:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
+index 5615acc..fd68b74 100644
+--- a/arch/powerpc/mm/hugetlbpage.c
++++ b/arch/powerpc/mm/hugetlbpage.c
+@@ -480,9 +480,6 @@ static int open_high_hpage_areas(struct
+
+ mm->context.high_htlb_areas |= newareas;
+
+- /* update the paca copy of the context struct */
+- get_paca()->context = mm->context;
+-
+ /* the context change must make it to memory before the flush,
+ * so that further SLB misses do the right thing. */
+ mb();
+diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
+index eebd8b8..d1c0758 100644
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -256,20 +256,22 @@ void __init do_init_bootmem(void)
+
+ boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
+
++ /* Add active regions with valid PFNs */
++ for (i = 0; i < lmb.memory.cnt; i++) {
++ unsigned long start_pfn, end_pfn;
++ start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
++ end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
++ add_active_range(0, start_pfn, end_pfn);
++ }
++
+ /* Add all physical memory to the bootmem map, mark each area
+ * present.
+ */
+- for (i = 0; i < lmb.memory.cnt; i++) {
+- unsigned long base = lmb.memory.region[i].base;
+- unsigned long size = lmb_size_bytes(&lmb.memory, i);
+ #ifdef CONFIG_HIGHMEM
+- if (base >= total_lowmem)
+- continue;
+- if (base + size > total_lowmem)
+- size = total_lowmem - base;
++ free_bootmem_with_active_regions(0, total_lowmem >> PAGE_SHIFT);
++#else
++ free_bootmem_with_active_regions(0, max_pfn);
+ #endif
+- free_bootmem(base, size);
+- }
+
+ /* reserve the sections we're already using */
+ for (i = 0; i < lmb.reserved.cnt; i++)
+@@ -277,9 +279,8 @@ void __init do_init_bootmem(void)
+ lmb_size_bytes(&lmb.reserved, i));
+
+ /* XXX need to clip this if using highmem? */
+- for (i = 0; i < lmb.memory.cnt; i++)
+- memory_present(0, lmb_start_pfn(&lmb.memory, i),
+- lmb_end_pfn(&lmb.memory, i));
++ sparse_memory_present_with_active_regions(0);
++
+ init_bootmem_done = 1;
+ }
+
+@@ -288,10 +289,9 @@ void __init do_init_bootmem(void)
+ */
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES];
+- unsigned long zholes_size[MAX_NR_ZONES];
+ unsigned long total_ram = lmb_phys_mem_size();
+ unsigned long top_of_ram = lmb_end_of_DRAM();
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+ #ifdef CONFIG_HIGHMEM
+ map_page(PKMAP_BASE, 0, 0); /* XXX gross */
+@@ -307,26 +307,14 @@ void __init paging_init(void)
+ top_of_ram, total_ram);
+ printk(KERN_DEBUG "Memory hole size: %ldMB\n",
+ (top_of_ram - total_ram) >> 20);
+- /*
+- * All pages are DMA-able so we put them all in the DMA zone.
+- */
+- memset(zones_size, 0, sizeof(zones_size));
+- memset(zholes_size, 0, sizeof(zholes_size));
+-
+- zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
+- zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;
+-
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ #ifdef CONFIG_HIGHMEM
+- zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
+- zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT;
+- zholes_size[ZONE_HIGHMEM] = (top_of_ram - total_ram) >> PAGE_SHIFT;
++ max_zone_pfns[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
++ max_zone_pfns[ZONE_HIGHMEM] = top_of_ram >> PAGE_SHIFT;
+ #else
+- zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
+- zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;
+-#endif /* CONFIG_HIGHMEM */
+-
+- free_area_init_node(0, NODE_DATA(0), zones_size,
+- __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
++ max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
++#endif
++ free_area_init_nodes(max_zone_pfns);
+ }
+ #endif /* ! CONFIG_NEED_MULTIPLE_NODES */
+
+diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
+index fbe2393..9da01dc 100644
+--- a/arch/powerpc/mm/numa.c
++++ b/arch/powerpc/mm/numa.c
+@@ -39,96 +39,6 @@ static bootmem_data_t __initdata plat_no
+ static int min_common_depth;
+ static int n_mem_addr_cells, n_mem_size_cells;
+
+-/*
+- * We need somewhere to store start/end/node for each region until we have
+- * allocated the real node_data structures.
+- */
+-#define MAX_REGIONS (MAX_LMB_REGIONS*2)
+-static struct {
+- unsigned long start_pfn;
+- unsigned long end_pfn;
+- int nid;
+-} init_node_data[MAX_REGIONS] __initdata;
+-
+-int __init early_pfn_to_nid(unsigned long pfn)
+-{
+- unsigned int i;
+-
+- for (i = 0; init_node_data[i].end_pfn; i++) {
+- unsigned long start_pfn = init_node_data[i].start_pfn;
+- unsigned long end_pfn = init_node_data[i].end_pfn;
+-
+- if ((start_pfn <= pfn) && (pfn < end_pfn))
+- return init_node_data[i].nid;
+- }
+-
+- return -1;
+-}
+-
+-void __init add_region(unsigned int nid, unsigned long start_pfn,
+- unsigned long pages)
+-{
+- unsigned int i;
+-
+- dbg("add_region nid %d start_pfn 0x%lx pages 0x%lx\n",
+- nid, start_pfn, pages);
+-
+- for (i = 0; init_node_data[i].end_pfn; i++) {
+- if (init_node_data[i].nid != nid)
+- continue;
+- if (init_node_data[i].end_pfn == start_pfn) {
+- init_node_data[i].end_pfn += pages;
+- return;
+- }
+- if (init_node_data[i].start_pfn == (start_pfn + pages)) {
+- init_node_data[i].start_pfn -= pages;
+- return;
+- }
+- }
+-
+- /*
+- * Leave last entry NULL so we dont iterate off the end (we use
+- * entry.end_pfn to terminate the walk).
+- */
+- if (i >= (MAX_REGIONS - 1)) {
+- printk(KERN_ERR "WARNING: too many memory regions in "
+- "numa code, truncating\n");
+- return;
+- }
+-
+- init_node_data[i].start_pfn = start_pfn;
+- init_node_data[i].end_pfn = start_pfn + pages;
+- init_node_data[i].nid = nid;
+-}
+-
+-/* We assume init_node_data has no overlapping regions */
+-void __init get_region(unsigned int nid, unsigned long *start_pfn,
+- unsigned long *end_pfn, unsigned long *pages_present)
+-{
+- unsigned int i;
+-
+- *start_pfn = -1UL;
+- *end_pfn = *pages_present = 0;
+-
+- for (i = 0; init_node_data[i].end_pfn; i++) {
+- if (init_node_data[i].nid != nid)
+- continue;
+-
+- *pages_present += init_node_data[i].end_pfn -
+- init_node_data[i].start_pfn;
+-
+- if (init_node_data[i].start_pfn < *start_pfn)
+- *start_pfn = init_node_data[i].start_pfn;
+-
+- if (init_node_data[i].end_pfn > *end_pfn)
+- *end_pfn = init_node_data[i].end_pfn;
+- }
+-
+- /* We didnt find a matching region, return start/end as 0 */
+- if (*start_pfn == -1UL)
+- *start_pfn = 0;
+-}
+-
+ static void __cpuinit map_cpu_to_node(int cpu, int node)
+ {
+ numa_cpu_lookup_table[cpu] = node;
+@@ -159,12 +69,12 @@ static struct device_node * __cpuinit fi
+ {
+ unsigned int hw_cpuid = get_hard_smp_processor_id(cpu);
+ struct device_node *cpu_node = NULL;
+- unsigned int *interrupt_server, *reg;
++ const unsigned int *interrupt_server, *reg;
+ int len;
+
+ while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
+ /* Try interrupt server first */
+- interrupt_server = (unsigned int *)get_property(cpu_node,
++ interrupt_server = get_property(cpu_node,
+ "ibm,ppc-interrupt-server#s", &len);
+
+ len = len / sizeof(u32);
+@@ -175,8 +85,7 @@ static struct device_node * __cpuinit fi
+ return cpu_node;
+ }
+ } else {
+- reg = (unsigned int *)get_property(cpu_node,
+- "reg", &len);
++ reg = get_property(cpu_node, "reg", &len);
+ if (reg && (len > 0) && (reg[0] == hw_cpuid))
+ return cpu_node;
+ }
+@@ -186,9 +95,9 @@ static struct device_node * __cpuinit fi
+ }
+
+ /* must hold reference to node during call */
+-static int *of_get_associativity(struct device_node *dev)
++static const int *of_get_associativity(struct device_node *dev)
+ {
+- return (unsigned int *)get_property(dev, "ibm,associativity", NULL);
++ return get_property(dev, "ibm,associativity", NULL);
+ }
+
+ /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
+@@ -197,7 +106,7 @@ static int *of_get_associativity(struct
+ static int of_node_to_nid_single(struct device_node *device)
+ {
+ int nid = -1;
+- unsigned int *tmp;
++ const unsigned int *tmp;
+
+ if (min_common_depth == -1)
+ goto out;
+@@ -255,7 +164,7 @@ EXPORT_SYMBOL_GPL(of_node_to_nid);
+ static int __init find_min_common_depth(void)
+ {
+ int depth;
+- unsigned int *ref_points;
++ const unsigned int *ref_points;
+ struct device_node *rtas_root;
+ unsigned int len;
+
+@@ -270,7 +179,7 @@ static int __init find_min_common_depth(
+ * configuration (should be all 0's) and the second is for a normal
+ * NUMA configuration.
+ */
+- ref_points = (unsigned int *)get_property(rtas_root,
++ ref_points = get_property(rtas_root,
+ "ibm,associativity-reference-points", &len);
+
+ if ((len >= 1) && ref_points) {
+@@ -297,7 +206,7 @@ static void __init get_n_mem_cells(int *
+ of_node_put(memory);
+ }
+
+-static unsigned long __devinit read_n_cells(int n, unsigned int **buf)
++static unsigned long __devinit read_n_cells(int n, const unsigned int **buf)
+ {
+ unsigned long result = 0;
+
+@@ -435,15 +344,13 @@ static int __init parse_numa_properties(
+ unsigned long size;
+ int nid;
+ int ranges;
+- unsigned int *memcell_buf;
++ const unsigned int *memcell_buf;
+ unsigned int len;
+
+- memcell_buf = (unsigned int *)get_property(memory,
++ memcell_buf = get_property(memory,
+ "linux,usable-memory", &len);
+ if (!memcell_buf || len <= 0)
+- memcell_buf =
+- (unsigned int *)get_property(memory, "reg",
+- &len);
++ memcell_buf = get_property(memory, "reg", &len);
+ if (!memcell_buf || len <= 0)
+ continue;
+
+@@ -471,8 +378,8 @@ new_range:
+ continue;
+ }
+
+- add_region(nid, start >> PAGE_SHIFT,
+- size >> PAGE_SHIFT);
++ add_active_range(nid, start >> PAGE_SHIFT,
++ (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
+
+ if (--ranges)
+ goto new_range;
+@@ -485,6 +392,7 @@ static void __init setup_nonnuma(void)
+ {
+ unsigned long top_of_ram = lmb_end_of_DRAM();
+ unsigned long total_ram = lmb_phys_mem_size();
++ unsigned long start_pfn, end_pfn;
+ unsigned int i;
+
+ printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
+@@ -492,9 +400,11 @@ static void __init setup_nonnuma(void)
+ printk(KERN_DEBUG "Memory hole size: %ldMB\n",
+ (top_of_ram - total_ram) >> 20);
+
+- for (i = 0; i < lmb.memory.cnt; ++i)
+- add_region(0, lmb.memory.region[i].base >> PAGE_SHIFT,
+- lmb_size_pages(&lmb.memory, i));
++ for (i = 0; i < lmb.memory.cnt; ++i) {
++ start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
++ end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
++ add_active_range(0, start_pfn, end_pfn);
++ }
+ node_set_online(0);
+ }
+
+@@ -633,11 +543,11 @@ void __init do_init_bootmem(void)
+ (void *)(unsigned long)boot_cpuid);
+
+ for_each_online_node(nid) {
+- unsigned long start_pfn, end_pfn, pages_present;
++ unsigned long start_pfn, end_pfn;
+ unsigned long bootmem_paddr;
+ unsigned long bootmap_pages;
+
+- get_region(nid, &start_pfn, &end_pfn, &pages_present);
++ get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
+
+ /* Allocate the node structure node local if possible */
+ NODE_DATA(nid) = careful_allocation(nid,
+@@ -670,19 +580,7 @@ void __init do_init_bootmem(void)
+ init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
+ start_pfn, end_pfn);
+
+- /* Add free regions on this node */
+- for (i = 0; init_node_data[i].end_pfn; i++) {
+- unsigned long start, end;
+-
+- if (init_node_data[i].nid != nid)
+- continue;
+-
+- start = init_node_data[i].start_pfn << PAGE_SHIFT;
+- end = init_node_data[i].end_pfn << PAGE_SHIFT;
+-
+- dbg("free_bootmem %lx %lx\n", start, end - start);
+- free_bootmem_node(NODE_DATA(nid), start, end - start);
+- }
++ free_bootmem_with_active_regions(nid, end_pfn);
+
+ /* Mark reserved regions on this node */
+ for (i = 0; i < lmb.reserved.cnt; i++) {
+@@ -713,44 +611,16 @@ void __init do_init_bootmem(void)
+ }
+ }
+
+- /* Add regions into sparsemem */
+- for (i = 0; init_node_data[i].end_pfn; i++) {
+- unsigned long start, end;
+-
+- if (init_node_data[i].nid != nid)
+- continue;
+-
+- start = init_node_data[i].start_pfn;
+- end = init_node_data[i].end_pfn;
+-
+- memory_present(nid, start, end);
+- }
++ sparse_memory_present_with_active_regions(nid);
+ }
+ }
+
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES];
+- unsigned long zholes_size[MAX_NR_ZONES];
+- int nid;
+-
+- memset(zones_size, 0, sizeof(zones_size));
+- memset(zholes_size, 0, sizeof(zholes_size));
+-
+- for_each_online_node(nid) {
+- unsigned long start_pfn, end_pfn, pages_present;
+-
+- get_region(nid, &start_pfn, &end_pfn, &pages_present);
+-
+- zones_size[ZONE_DMA] = end_pfn - start_pfn;
+- zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] - pages_present;
+-
+- dbg("free_area_init node %d %lx %lx (hole: %lx)\n", nid,
+- zones_size[ZONE_DMA], start_pfn, zholes_size[ZONE_DMA]);
+-
+- free_area_init_node(nid, NODE_DATA(nid), zones_size, start_pfn,
+- zholes_size);
+- }
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] = lmb_end_of_DRAM() >> PAGE_SHIFT;
++ free_area_init_nodes(max_zone_pfns);
+ }
+
+ static int __init early_numa(char *p)
+@@ -787,10 +657,10 @@ int hot_add_scn_to_nid(unsigned long scn
+ while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+ unsigned long start, size;
+ int ranges;
+- unsigned int *memcell_buf;
++ const unsigned int *memcell_buf;
+ unsigned int len;
+
+- memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
++ memcell_buf = get_property(memory, "reg", &len);
+ if (!memcell_buf || len <= 0)
+ continue;
+
+diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
+index b1da031..ac64f4a 100644
+--- a/arch/powerpc/mm/pgtable_64.c
++++ b/arch/powerpc/mm/pgtable_64.c
+@@ -63,32 +63,13 @@
+ #include <asm/iommu.h>
+ #include <asm/abs_addr.h>
+ #include <asm/vdso.h>
++#include <asm/firmware.h>
+
+ #include "mmu_decl.h"
+
+ unsigned long ioremap_bot = IMALLOC_BASE;
+ static unsigned long phbs_io_bot = PHBS_IO_BASE;
+
+-#ifdef CONFIG_PPC_ISERIES
+-
+-void __iomem *ioremap(unsigned long addr, unsigned long size)
+-{
+- return (void __iomem *)addr;
+-}
+-
+-extern void __iomem *__ioremap(unsigned long addr, unsigned long size,
+- unsigned long flags)
+-{
+- return (void __iomem *)addr;
+-}
+-
+-void iounmap(volatile void __iomem *addr)
+-{
+- return;
+-}
+-
+-#else
+-
+ /*
+ * map_io_page currently only called by __ioremap
+ * map_io_page adds an entry to the ioremap page table
+@@ -161,6 +142,9 @@ void __iomem * __ioremap(unsigned long a
+ unsigned long pa, ea;
+ void __iomem *ret;
+
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return (void __iomem *)addr;
++
+ /*
+ * Choose an address to map it to.
+ * Once the imalloc system is running, we use it.
+@@ -255,6 +239,9 @@ void iounmap(volatile void __iomem *toke
+ {
+ void *addr;
+
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return;
++
+ if (!mem_init_done)
+ return;
+
+@@ -315,8 +302,6 @@ int iounmap_explicit(volatile void __iom
+ return 0;
+ }
+
+-#endif
+-
+ EXPORT_SYMBOL(ioremap);
+ EXPORT_SYMBOL(__ioremap);
+ EXPORT_SYMBOL(iounmap);
+diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
+index de0c884..d373391 100644
+--- a/arch/powerpc/mm/slb.c
++++ b/arch/powerpc/mm/slb.c
+@@ -22,6 +22,8 @@
+ #include <asm/paca.h>
+ #include <asm/cputable.h>
+ #include <asm/cacheflush.h>
++#include <asm/smp.h>
++#include <linux/compiler.h>
+
+ #ifdef DEBUG
+ #define DBG(fmt...) udbg_printf(fmt)
+@@ -50,9 +52,32 @@ static inline unsigned long mk_vsid_data
+ return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags;
+ }
+
+-static inline void create_slbe(unsigned long ea, unsigned long flags,
+- unsigned long entry)
++static inline void slb_shadow_update(unsigned long esid, unsigned long vsid,
++ unsigned long entry)
+ {
++ /*
++ * Clear the ESID first so the entry is not valid while we are
++ * updating it.
++ */
++ get_slb_shadow()->save_area[entry].esid = 0;
++ barrier();
++ get_slb_shadow()->save_area[entry].vsid = vsid;
++ barrier();
++ get_slb_shadow()->save_area[entry].esid = esid;
++
++}
++
++static inline void create_shadowed_slbe(unsigned long ea, unsigned long flags,
++ unsigned long entry)
++{
++ /*
++ * Updating the shadow buffer before writing the SLB ensures
++ * we don't get a stale entry here if we get preempted by PHYP
++ * between these two statements.
++ */
++ slb_shadow_update(mk_esid_data(ea, entry), mk_vsid_data(ea, flags),
++ entry);
++
+ asm volatile("slbmte %0,%1" :
+ : "r" (mk_vsid_data(ea, flags)),
+ "r" (mk_esid_data(ea, entry))
+@@ -77,6 +102,10 @@ void slb_flush_and_rebolt(void)
+ if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET)
+ ksp_esid_data &= ~SLB_ESID_V;
+
++ /* Only third entry (stack) may change here so only resave that */
++ slb_shadow_update(ksp_esid_data,
++ mk_vsid_data(ksp_esid_data, lflags), 2);
++
+ /* We need to do this all in asm, so we're sure we don't touch
+ * the stack between the slbia and rebolting it. */
+ asm volatile("isync\n"
+@@ -209,9 +238,9 @@ void slb_initialize(void)
+ asm volatile("isync":::"memory");
+ asm volatile("slbmte %0,%0"::"r" (0) : "memory");
+ asm volatile("isync; slbia; isync":::"memory");
+- create_slbe(PAGE_OFFSET, lflags, 0);
++ create_shadowed_slbe(PAGE_OFFSET, lflags, 0);
+
+- create_slbe(VMALLOC_START, vflags, 1);
++ create_shadowed_slbe(VMALLOC_START, vflags, 1);
+
+ /* We don't bolt the stack for the time being - we're in boot,
+ * so the stack is in the bolted segment. By the time it goes
+diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
+index dbc1abb..b10e470 100644
+--- a/arch/powerpc/mm/slb_low.S
++++ b/arch/powerpc/mm/slb_low.S
+@@ -21,6 +21,7 @@
+ #include <asm/page.h>
+ #include <asm/mmu.h>
+ #include <asm/pgtable.h>
++#include <asm/firmware.h>
+
+ /* void slb_allocate_realmode(unsigned long ea);
+ *
+@@ -183,6 +184,7 @@ slb_finish_load:
+ * dont have any LRU information to help us choose a slot.
+ */
+ #ifdef CONFIG_PPC_ISERIES
++BEGIN_FW_FTR_SECTION
+ /*
+ * On iSeries, the "bolted" stack segment can be cast out on
+ * shared processor switch so we need to check for a miss on
+@@ -194,6 +196,7 @@ slb_finish_load:
+ li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */
+ cmpld r9,r3
+ beq 3f
++END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+ #endif /* CONFIG_PPC_ISERIES */
+
+ ld r10,PACASTABRR(r13)
+diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
+index f6eef78..b58baa6 100644
+--- a/arch/powerpc/mm/tlb_64.c
++++ b/arch/powerpc/mm/tlb_64.c
+@@ -146,6 +146,7 @@ void hpte_update(struct mm_struct *mm, u
+ psize = mmu_huge_psize;
+ #else
+ BUG();
++ psize = pte_pagesize_index(pte); /* shutup gcc */
+ #endif
+ } else
+ psize = pte_pagesize_index(pte);
+diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
+index 3145d61..0b5df9c 100644
+--- a/arch/powerpc/oprofile/Makefile
++++ b/arch/powerpc/oprofile/Makefile
+@@ -13,4 +13,4 @@ DRIVER_OBJS := $(addprefix ../../../driv
+ oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
+ oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
+ oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
+-oprofile-$(CONFIG_PPC32) += op_model_7450.o
++oprofile-$(CONFIG_6xx) += op_model_7450.o
+diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c
+index 75f57bc..b4278cf 100644
+--- a/arch/powerpc/oprofile/backtrace.c
++++ b/arch/powerpc/oprofile/backtrace.c
+@@ -11,6 +11,7 @@
+ #include <linux/sched.h>
+ #include <asm/processor.h>
+ #include <asm/uaccess.h>
++#include <asm/compat.h>
+
+ #define STACK_SP(STACK) *(STACK)
+
+@@ -26,8 +27,9 @@
+ static unsigned int user_getsp32(unsigned int sp, int is_first)
+ {
+ unsigned int stack_frame[2];
++ void __user *p = compat_ptr(sp);
+
+- if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
++ if (!access_ok(VERIFY_READ, p, sizeof(stack_frame)))
+ return 0;
+
+ /*
+@@ -35,8 +37,7 @@ static unsigned int user_getsp32(unsigne
+ * which means that we've done all that we can do from
+ * interrupt context.
+ */
+- if (__copy_from_user_inatomic(stack_frame, (void *)(long)sp,
+- sizeof(stack_frame)))
++ if (__copy_from_user_inatomic(stack_frame, p, sizeof(stack_frame)))
+ return 0;
+
+ if (!is_first)
+@@ -54,10 +55,10 @@ static unsigned long user_getsp64(unsign
+ {
+ unsigned long stack_frame[3];
+
+- if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
++ if (!access_ok(VERIFY_READ, (void __user *)sp, sizeof(stack_frame)))
+ return 0;
+
+- if (__copy_from_user_inatomic(stack_frame, (void *)sp,
++ if (__copy_from_user_inatomic(stack_frame, (void __user *)sp,
+ sizeof(stack_frame)))
+ return 0;
+
+diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
+index fd0bbbe..63bbef3 100644
+--- a/arch/powerpc/oprofile/common.c
++++ b/arch/powerpc/oprofile/common.c
+@@ -34,6 +34,11 @@ static void op_handle_interrupt(struct p
+ model->handle_interrupt(regs, ctr);
+ }
+
++static void op_powerpc_cpu_setup(void *dummy)
++{
++ model->cpu_setup(ctr);
++}
++
+ static int op_powerpc_setup(void)
+ {
+ int err;
+@@ -47,7 +52,7 @@ static int op_powerpc_setup(void)
+ model->reg_setup(ctr, &sys, model->num_counters);
+
+ /* Configure the registers on all cpus. */
+- on_each_cpu(model->cpu_setup, NULL, 0, 1);
++ on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
+
+ return 0;
+ }
+@@ -142,7 +147,8 @@ int __init oprofile_arch_init(struct opr
+ case PPC_OPROFILE_POWER4:
+ model = &op_model_power4;
+ break;
+-#else
++#endif
++#ifdef CONFIG_6xx
+ case PPC_OPROFILE_G4:
+ model = &op_model_7450;
+ break;
+diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
+index e0491c3..f481c0e 100644
+--- a/arch/powerpc/oprofile/op_model_7450.c
++++ b/arch/powerpc/oprofile/op_model_7450.c
+@@ -1,5 +1,5 @@
+ /*
+- * oprofile/op_model_7450.c
++ * arch/powerpc/oprofile/op_model_7450.c
+ *
+ * Freescale 745x/744x oprofile support, based on fsl_booke support
+ * Copyright (C) 2004 Anton Blanchard <anton at au.ibm.com>, IBM
+@@ -81,7 +81,7 @@ static void pmc_stop_ctrs(void)
+
+ /* Configures the counters on this CPU based on the global
+ * settings */
+-static void fsl7450_cpu_setup(void *unused)
++static void fsl7450_cpu_setup(struct op_counter_config *ctr)
+ {
+ /* freeze all counters */
+ pmc_stop_ctrs();
+diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
+index 93d63e6..0b3c31f 100644
+--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
++++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
+@@ -1,5 +1,5 @@
+ /*
+- * oprofile/op_model_e500.c
++ * arch/powerpc/oprofile/op_model_fsl_booke.c
+ *
+ * Freescale Book-E oprofile support, based on ppc64 oprofile support
+ * Copyright (C) 2004 Anton Blanchard <anton at au.ibm.com>, IBM
+@@ -32,42 +32,152 @@ static unsigned long reset_value[OP_MAX_
+ static int num_counters;
+ static int oprofile_running;
+
+-static inline unsigned int ctr_read(unsigned int i)
++static void init_pmc_stop(int ctr)
+ {
+- switch(i) {
+- case 0:
+- return mfpmr(PMRN_PMC0);
+- case 1:
+- return mfpmr(PMRN_PMC1);
+- case 2:
+- return mfpmr(PMRN_PMC2);
+- case 3:
+- return mfpmr(PMRN_PMC3);
+- default:
+- return 0;
+- }
+-}
++ u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
++ PMLCA_FCM1 | PMLCA_FCM0);
++ u32 pmlcb = 0;
+
+-static inline void ctr_write(unsigned int i, unsigned int val)
+-{
+- switch(i) {
++ switch (ctr) {
+ case 0:
+- mtpmr(PMRN_PMC0, val);
++ mtpmr(PMRN_PMLCA0, pmlca);
++ mtpmr(PMRN_PMLCB0, pmlcb);
+ break;
+ case 1:
+- mtpmr(PMRN_PMC1, val);
++ mtpmr(PMRN_PMLCA1, pmlca);
++ mtpmr(PMRN_PMLCB1, pmlcb);
+ break;
+ case 2:
+- mtpmr(PMRN_PMC2, val);
++ mtpmr(PMRN_PMLCA2, pmlca);
++ mtpmr(PMRN_PMLCB2, pmlcb);
+ break;
+ case 3:
+- mtpmr(PMRN_PMC3, val);
++ mtpmr(PMRN_PMLCA3, pmlca);
++ mtpmr(PMRN_PMLCB3, pmlcb);
+ break;
+ default:
+- break;
++ panic("Bad ctr number!\n");
+ }
+ }
+
++static void set_pmc_event(int ctr, int event)
++{
++ u32 pmlca;
++
++ pmlca = get_pmlca(ctr);
++
++ pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
++ ((event << PMLCA_EVENT_SHIFT) &
++ PMLCA_EVENT_MASK);
++
++ set_pmlca(ctr, pmlca);
++}
++
++static void set_pmc_user_kernel(int ctr, int user, int kernel)
++{
++ u32 pmlca;
++
++ pmlca = get_pmlca(ctr);
++
++ if(user)
++ pmlca &= ~PMLCA_FCU;
++ else
++ pmlca |= PMLCA_FCU;
++
++ if(kernel)
++ pmlca &= ~PMLCA_FCS;
++ else
++ pmlca |= PMLCA_FCS;
++
++ set_pmlca(ctr, pmlca);
++}
++
++static void set_pmc_marked(int ctr, int mark0, int mark1)
++{
++ u32 pmlca = get_pmlca(ctr);
++
++ if(mark0)
++ pmlca &= ~PMLCA_FCM0;
++ else
++ pmlca |= PMLCA_FCM0;
++
++ if(mark1)
++ pmlca &= ~PMLCA_FCM1;
++ else
++ pmlca |= PMLCA_FCM1;
++
++ set_pmlca(ctr, pmlca);
++}
++
++static void pmc_start_ctr(int ctr, int enable)
++{
++ u32 pmlca = get_pmlca(ctr);
++
++ pmlca &= ~PMLCA_FC;
++
++ if (enable)
++ pmlca |= PMLCA_CE;
++ else
++ pmlca &= ~PMLCA_CE;
++
++ set_pmlca(ctr, pmlca);
++}
++
++static void pmc_start_ctrs(int enable)
++{
++ u32 pmgc0 = mfpmr(PMRN_PMGC0);
++
++ pmgc0 &= ~PMGC0_FAC;
++ pmgc0 |= PMGC0_FCECE;
++
++ if (enable)
++ pmgc0 |= PMGC0_PMIE;
++ else
++ pmgc0 &= ~PMGC0_PMIE;
++
++ mtpmr(PMRN_PMGC0, pmgc0);
++}
++
++static void pmc_stop_ctrs(void)
++{
++ u32 pmgc0 = mfpmr(PMRN_PMGC0);
++
++ pmgc0 |= PMGC0_FAC;
++
++ pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
++
++ mtpmr(PMRN_PMGC0, pmgc0);
++}
++
++static void dump_pmcs(void)
++{
++ printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0));
++ printk("pmc\t\tpmlca\t\tpmlcb\n");
++ printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0),
++ mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0));
++ printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1),
++ mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1));
++ printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2),
++ mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2));
++ printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3),
++ mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
++}
++
++static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
++{
++ int i;
++
++ /* freeze all counters */
++ pmc_stop_ctrs();
++
++ for (i = 0;i < num_counters;i++) {
++ init_pmc_stop(i);
++
++ set_pmc_event(i, ctr[i].event);
++
++ set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
++ }
++}
+
+ static void fsl_booke_reg_setup(struct op_counter_config *ctr,
+ struct op_system_config *sys,
+@@ -77,23 +187,14 @@ static void fsl_booke_reg_setup(struct o
+
+ num_counters = num_ctrs;
+
+- /* freeze all counters */
+- pmc_stop_ctrs();
+-
+ /* Our counters count up, and "count" refers to
+ * how much before the next interrupt, and we interrupt
+ * on overflow. So we calculate the starting value
+ * which will give us "count" until overflow.
+ * Then we set the events on the enabled counters */
+- for (i = 0; i < num_counters; ++i) {
++ for (i = 0; i < num_counters; ++i)
+ reset_value[i] = 0x80000000UL - ctr[i].count;
+
+- init_pmc_stop(i);
+-
+- set_pmc_event(i, ctr[i].event);
+-
+- set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
+- }
+ }
+
+ static void fsl_booke_start(struct op_counter_config *ctr)
+@@ -105,8 +206,8 @@ static void fsl_booke_start(struct op_co
+ for (i = 0; i < num_counters; ++i) {
+ if (ctr[i].enabled) {
+ ctr_write(i, reset_value[i]);
+- /* Set Each enabled counterd to only
+- * count when the Mark bit is not set */
++ /* Set each enabled counter to only
++ * count when the Mark bit is *not* set */
+ set_pmc_marked(i, 1, 0);
+ pmc_start_ctr(i, 1);
+ } else {
+@@ -177,6 +278,7 @@ static void fsl_booke_handle_interrupt(s
+
+ struct op_powerpc_model op_model_fsl_booke = {
+ .reg_setup = fsl_booke_reg_setup,
++ .cpu_setup = fsl_booke_cpu_setup,
+ .start = fsl_booke_start,
+ .stop = fsl_booke_stop,
+ .handle_interrupt = fsl_booke_handle_interrupt,
+diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
+index 506f6b7..356709d 100644
+--- a/arch/powerpc/oprofile/op_model_power4.c
++++ b/arch/powerpc/oprofile/op_model_power4.c
+@@ -76,13 +76,13 @@ static inline int mmcra_must_set_sample(
+ {
+ if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) ||
+ __is_processor(PV_970) || __is_processor(PV_970FX) ||
+- __is_processor(PV_970MP))
++ __is_processor(PV_970MP) || __is_processor(PV_970GX))
+ return 1;
+
+ return 0;
+ }
+
+-static void power4_cpu_setup(void *unused)
++static void power4_cpu_setup(struct op_counter_config *ctr)
+ {
+ unsigned int mmcr0 = mmcr0_val;
+ unsigned long mmcra = mmcra_val;
+diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
+index 042f8f4..19c5ee0 100644
+--- a/arch/powerpc/oprofile/op_model_rs64.c
++++ b/arch/powerpc/oprofile/op_model_rs64.c
+@@ -102,7 +102,7 @@ static void rs64_reg_setup(struct op_cou
+ /* XXX setup user and kernel profiling */
+ }
+
+-static void rs64_cpu_setup(void *unused)
++static void rs64_cpu_setup(struct op_counter_config *ctr)
+ {
+ unsigned int mmcr0;
+
+diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
+new file mode 100644
+index 0000000..47d841e
+--- /dev/null
++++ b/arch/powerpc/platforms/82xx/Kconfig
+@@ -0,0 +1,21 @@
++menu "Platform support"
++ depends on PPC_82xx
++
++choice
++ prompt "Machine Type"
++ default MPC82xx_ADS
++
++config MPC82xx_ADS
++ bool "Freescale MPC82xx ADS"
++ select DEFAULT_UIMAGE
++ select PQ2ADS
++ select 8272
++ select 8260
++ select CPM2
++ select FSL_SOC
++ help
++ This option enables support for the MPC8272 ADS board
++
++endchoice
++
++endmenu
+diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile
+new file mode 100644
+index 0000000..d9fd4c8
+--- /dev/null
++++ b/arch/powerpc/platforms/82xx/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the PowerPC 82xx linux kernel.
++#
++obj-$(CONFIG_PPC_82xx) += mpc82xx.o
++obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o
+diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h
+new file mode 100644
+index 0000000..9cd8893
+--- /dev/null
++++ b/arch/powerpc/platforms/82xx/m82xx_pci.h
+@@ -0,0 +1,19 @@
++#ifndef _PPC_KERNEL_M82XX_PCI_H
++#define _PPC_KERNEL_M82XX_PCI_H
++
++/*
++ * 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/m8260_pci.h>
++
++#define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET)
++
++#ifndef _IO_BASE
++#define _IO_BASE isa_io_base
++#endif
++
++#endif /* _PPC_KERNEL_M8260_PCI_H */
+diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
+new file mode 100644
+index 0000000..0f5b30d
+--- /dev/null
++++ b/arch/powerpc/platforms/82xx/mpc82xx.c
+@@ -0,0 +1,110 @@
++/*
++ * MPC82xx setup and early boot code plus other random bits.
++ *
++ * Author: Vitaly Bordug <vbordug at ru.mvista.com>
++ *
++ * Copyright (c) 2006 MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <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/interrupt.h>
++#include <linux/kdev_t.h>
++#include <linux/major.h>
++#include <linux/console.h>
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include <linux/root_dev.h>
++#include <linux/initrd.h>
++#include <linux/module.h>
++#include <linux/fsl_devices.h>
++#include <linux/fs_uart_pd.h>
++
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/atomic.h>
++#include <asm/time.h>
++#include <asm/io.h>
++#include <asm/machdep.h>
++#include <asm/bootinfo.h>
++#include <asm/pci-bridge.h>
++#include <asm/mpc8260.h>
++#include <asm/irq.h>
++#include <mm/mmu_decl.h>
++#include <asm/prom.h>
++#include <asm/cpm2.h>
++#include <asm/udbg.h>
++#include <asm/i8259.h>
++#include <linux/fs_enet_pd.h>
++
++#include <sysdev/fsl_soc.h>
++#include <sysdev/cpm2_pic.h>
++
++#include "pq2ads_pd.h"
++
++static int __init get_freq(char *name, unsigned long *val)
++{
++ struct device_node *cpu;
++ unsigned int *fp;
++ int found = 0;
++
++ /* The cpu node should have timebase and clock frequency properties */
++ cpu = of_find_node_by_type(NULL, "cpu");
++
++ if (cpu) {
++ fp = (unsigned int *)get_property(cpu, name, NULL);
++ if (fp) {
++ found = 1;
++ *val = *fp++;
++ }
++
++ of_node_put(cpu);
++ }
++
++ return found;
++}
++
++void __init m82xx_calibrate_decr(void)
++{
++ ppc_tb_freq = 125000000;
++ if (!get_freq("bus-frequency", &ppc_tb_freq)) {
++ printk(KERN_ERR "WARNING: Estimating decrementer frequency "
++ "(not found)\n");
++ }
++ ppc_tb_freq /= 4;
++ ppc_proc_freq = 1000000000;
++ if (!get_freq("clock-frequency", &ppc_proc_freq))
++ printk(KERN_ERR "WARNING: Estimating processor frequency"
++ "(not found)\n");
++}
++
++void mpc82xx_ads_show_cpuinfo(struct seq_file *m)
++{
++ uint pvid, svid, phid1;
++ uint memsize = total_memory;
++
++ pvid = mfspr(SPRN_PVR);
++ svid = mfspr(SPRN_SVR);
++
++ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
++ seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE);
++ seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
++ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
++
++ /* Display cpu Pll setting */
++ phid1 = mfspr(SPRN_HID1);
++ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
++
++ /* Display the amount of memory */
++ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
++}
+diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+new file mode 100644
+index 0000000..bb9acbb
+--- /dev/null
++++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+@@ -0,0 +1,658 @@
++/*
++ * MPC82xx_ads setup and early boot code plus other random bits.
++ *
++ * Author: Vitaly Bordug <vbordug at ru.mvista.com>
++ * m82xx_restart fix by Wade Farnsworth <wfarnsworth at mvista.com>
++ *
++ * Copyright (c) 2006 MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <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/interrupt.h>
++#include <linux/kdev_t.h>
++#include <linux/major.h>
++#include <linux/console.h>
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include <linux/root_dev.h>
++#include <linux/initrd.h>
++#include <linux/module.h>
++#include <linux/fsl_devices.h>
++#include <linux/fs_uart_pd.h>
++
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/atomic.h>
++#include <asm/time.h>
++#include <asm/io.h>
++#include <asm/machdep.h>
++#include <asm/bootinfo.h>
++#include <asm/pci-bridge.h>
++#include <asm/mpc8260.h>
++#include <asm/irq.h>
++#include <mm/mmu_decl.h>
++#include <asm/prom.h>
++#include <asm/cpm2.h>
++#include <asm/udbg.h>
++#include <asm/i8259.h>
++#include <linux/fs_enet_pd.h>
++
++#include <sysdev/fsl_soc.h>
++#include <../sysdev/cpm2_pic.h>
++
++#include "pq2ads_pd.h"
++
++#ifdef CONFIG_PCI
++static uint pci_clk_frq;
++static struct {
++ unsigned long *pci_int_stat_reg;
++ unsigned long *pci_int_mask_reg;
++} pci_regs;
++
++static unsigned long pci_int_base;
++static struct irq_host *pci_pic_host;
++static struct device_node *pci_pic_node;
++#endif
++
++static void __init mpc82xx_ads_pic_init(void)
++{
++ struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2");
++ struct resource r;
++ cpm2_map_t *cpm_reg;
++
++ if (np == NULL) {
++ printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
++ return;
++ }
++ if (of_address_to_resource(np, 0, &r)) {
++ printk(KERN_ERR "PIC init: invalid resource\n");
++ of_node_put(np);
++ return;
++ }
++ cpm2_pic_init(np);
++ of_node_put(np);
++
++ /* Initialize the default interrupt mapping priorities,
++ * in case the boot rom changed something on us.
++ */
++ cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t));
++ cpm_reg->im_intctl.ic_siprr = 0x05309770;
++ iounmap(cpm_reg);
++#ifdef CONFIG_PCI
++ /* Initialize stuff for the 82xx CPLD IC and install demux */
++ m82xx_pci_init_irq();
++#endif
++}
++
++static void init_fcc1_ioports(struct fs_platform_info *fpi)
++{
++ struct io_port *io;
++ u32 tempval;
++ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
++ struct device_node *np;
++ struct resource r;
++ u32 *bcsr;
++
++ np = of_find_node_by_type(NULL, "memory");
++ if (!np) {
++ printk(KERN_INFO "No memory node in device tree\n");
++ return;
++ }
++ if (of_address_to_resource(np, 1, &r)) {
++ printk(KERN_INFO "No memory reg property [1] in devicetree\n");
++ return;
++ }
++ of_node_put(np);
++ bcsr = ioremap(r.start + 4, sizeof(u32));
++ io = &immap->im_ioport;
++
++ /* Enable the PHY */
++ clrbits32(bcsr, BCSR1_FETHIEN);
++ setbits32(bcsr, BCSR1_FETH_RST);
++
++ /* FCC1 pins are on port A/C. */
++ /* Configure port A and C pins for FCC1 Ethernet. */
++
++ tempval = in_be32(&io->iop_pdira);
++ tempval &= ~PA1_DIRA0;
++ tempval |= PA1_DIRA1;
++ out_be32(&io->iop_pdira, tempval);
++
++ tempval = in_be32(&io->iop_psora);
++ tempval &= ~PA1_PSORA0;
++ tempval |= PA1_PSORA1;
++ out_be32(&io->iop_psora, tempval);
++
++ setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1);
++
++ /* Alter clocks */
++ tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8);
++
++ clrbits32(&io->iop_psorc, tempval);
++ clrbits32(&io->iop_pdirc, tempval);
++ setbits32(&io->iop_pparc, tempval);
++
++ cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX);
++ cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX);
++
++ iounmap(bcsr);
++ iounmap(immap);
++}
++
++static void init_fcc2_ioports(struct fs_platform_info *fpi)
++{
++ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
++ struct device_node *np;
++ struct resource r;
++ u32 *bcsr;
++
++ struct io_port *io;
++ u32 tempval;
++
++ np = of_find_node_by_type(NULL, "memory");
++ if (!np) {
++ printk(KERN_INFO "No memory node in device tree\n");
++ return;
++ }
++ if (of_address_to_resource(np, 1, &r)) {
++ printk(KERN_INFO "No memory reg property [1] in devicetree\n");
++ return;
++ }
++ of_node_put(np);
++ io = &immap->im_ioport;
++ bcsr = ioremap(r.start + 12, sizeof(u32));
++
++ /* Enable the PHY */
++ clrbits32(bcsr, BCSR3_FETHIEN2);
++ setbits32(bcsr, BCSR3_FETH2_RST);
++
++ /* FCC2 are port B/C. */
++ /* Configure port A and C pins for FCC2 Ethernet. */
++
++ tempval = in_be32(&io->iop_pdirb);
++ tempval &= ~PB2_DIRB0;
++ tempval |= PB2_DIRB1;
++ out_be32(&io->iop_pdirb, tempval);
++
++ tempval = in_be32(&io->iop_psorb);
++ tempval &= ~PB2_PSORB0;
++ tempval |= PB2_PSORB1;
++ out_be32(&io->iop_psorb, tempval);
++
++ setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1);
++
++ tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8);
++
++ /* Alter clocks */
++ clrbits32(&io->iop_psorc, tempval);
++ clrbits32(&io->iop_pdirc, tempval);
++ setbits32(&io->iop_pparc, tempval);
++
++ cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX);
++ cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX);
++
++ iounmap(bcsr);
++ iounmap(immap);
++}
++
++void init_fcc_ioports(struct fs_platform_info *fpi)
++{
++ int fcc_no = fs_get_fcc_index(fpi->fs_no);
++
++ switch (fcc_no) {
++ case 0:
++ init_fcc1_ioports(fpi);
++ break;
++ case 1:
++ init_fcc2_ioports(fpi);
++ break;
++ default:
++ printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n");
++ return;
++ }
++}
++
++static void init_scc1_uart_ioports(struct fs_uart_platform_info *data)
++{
++ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
++
++ /* SCC1 is only on port D */
++ setbits32(&immap->im_ioport.iop_ppard, 0x00000003);
++ clrbits32(&immap->im_ioport.iop_psord, 0x00000001);
++ setbits32(&immap->im_ioport.iop_psord, 0x00000002);
++ clrbits32(&immap->im_ioport.iop_pdird, 0x00000001);
++ setbits32(&immap->im_ioport.iop_pdird, 0x00000002);
++
++ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx)));
++ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx)));
++ setbits32(&immap->im_cpmux.cmx_scr,
++ ((data->clk_tx - 1) << (4 - data->clk_tx)));
++ setbits32(&immap->im_cpmux.cmx_scr,
++ ((data->clk_rx - 1) << (4 - data->clk_rx)));
++
++ iounmap(immap);
++}
++
++static void init_scc4_uart_ioports(struct fs_uart_platform_info *data)
++{
++ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
++
++ setbits32(&immap->im_ioport.iop_ppard, 0x00000600);
++ clrbits32(&immap->im_ioport.iop_psord, 0x00000600);
++ clrbits32(&immap->im_ioport.iop_pdird, 0x00000200);
++ setbits32(&immap->im_ioport.iop_pdird, 0x00000400);
++
++ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx)));
++ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx)));
++ setbits32(&immap->im_cpmux.cmx_scr,
++ ((data->clk_tx - 1) << (4 - data->clk_tx)));
++ setbits32(&immap->im_cpmux.cmx_scr,
++ ((data->clk_rx - 1) << (4 - data->clk_rx)));
++
++ iounmap(immap);
++}
++
++void init_scc_ioports(struct fs_uart_platform_info *data)
++{
++ int scc_no = fs_get_scc_index(data->fs_no);
++
++ switch (scc_no) {
++ case 0:
++ init_scc1_uart_ioports(data);
++ data->brg = data->clk_rx;
++ break;
++ case 3:
++ init_scc4_uart_ioports(data);
++ data->brg = data->clk_rx;
++ break;
++ default:
++ printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
++ return;
++ }
++}
++
++void __init m82xx_board_setup(void)
++{
++ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
++ struct device_node *np;
++ struct resource r;
++ u32 *bcsr;
++
++ np = of_find_node_by_type(NULL, "memory");
++ if (!np) {
++ printk(KERN_INFO "No memory node in device tree\n");
++ return;
++ }
++ if (of_address_to_resource(np, 1, &r)) {
++ printk(KERN_INFO "No memory reg property [1] in devicetree\n");
++ return;
++ }
++ of_node_put(np);
++ bcsr = ioremap(r.start + 4, sizeof(u32));
++ /* Enable the 2nd UART port */
++ clrbits32(bcsr, BCSR1_RS232_EN2);
++
++#ifdef CONFIG_SERIAL_CPM_SCC1
++ clrbits32((u32 *) & immap->im_scc[0].scc_sccm,
++ UART_SCCM_TX | UART_SCCM_RX);
++ clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl,
++ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
++#endif
++
++#ifdef CONFIG_SERIAL_CPM_SCC2
++ clrbits32((u32 *) & immap->im_scc[1].scc_sccm,
++ UART_SCCM_TX | UART_SCCM_RX);
++ clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl,
++ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
++#endif
++
++#ifdef CONFIG_SERIAL_CPM_SCC3
++ clrbits32((u32 *) & immap->im_scc[2].scc_sccm,
++ UART_SCCM_TX | UART_SCCM_RX);
++ clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl,
++ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
++#endif
++
++#ifdef CONFIG_SERIAL_CPM_SCC4
++ clrbits32((u32 *) & immap->im_scc[3].scc_sccm,
++ UART_SCCM_TX | UART_SCCM_RX);
++ clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl,
++ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
++#endif
++
++ iounmap(bcsr);
++ iounmap(immap);
++}
++
++#ifdef CONFIG_PCI
++static void m82xx_pci_mask_irq(unsigned int irq)
++{
++ int bit = irq - pci_int_base;
++
++ *pci_regs.pci_int_mask_reg |= (1 << (31 - bit));
++ return;
++}
++
++static void m82xx_pci_unmask_irq(unsigned int irq)
++{
++ int bit = irq - pci_int_base;
++
++ *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit));
++ return;
++}
++
++static void m82xx_pci_mask_and_ack(unsigned int irq)
++{
++ int bit = irq - pci_int_base;
++
++ *pci_regs.pci_int_mask_reg |= (1 << (31 - bit));
++ return;
++}
++
++static void m82xx_pci_end_irq(unsigned int irq)
++{
++ int bit = irq - pci_int_base;
++
++ *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit));
++ return;
++}
++
++struct hw_interrupt_type m82xx_pci_ic = {
++ .typename = "MPC82xx ADS PCI",
++ .name = "MPC82xx ADS PCI",
++ .enable = m82xx_pci_unmask_irq,
++ .disable = m82xx_pci_mask_irq,
++ .ack = m82xx_pci_mask_and_ack,
++ .end = m82xx_pci_end_irq,
++ .mask = m82xx_pci_mask_irq,
++ .mask_ack = m82xx_pci_mask_and_ack,
++ .unmask = m82xx_pci_unmask_irq,
++ .eoi = m82xx_pci_end_irq,
++};
++
++static void
++m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
++{
++ unsigned long stat, mask, pend;
++ int bit;
++
++ for (;;) {
++ stat = *pci_regs.pci_int_stat_reg;
++ mask = *pci_regs.pci_int_mask_reg;
++ pend = stat & ~mask & 0xf0000000;
++ if (!pend)
++ break;
++ for (bit = 0; pend != 0; ++bit, pend <<= 1) {
++ if (pend & 0x80000000)
++ __do_IRQ(pci_int_base + bit);
++ }
++ }
++}
++
++static int pci_pic_host_match(struct irq_host *h, struct device_node *node)
++{
++ return node == pci_pic_node;
++}
++
++static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ get_irq_desc(virq)->status |= IRQ_LEVEL;
++ set_irq_chip(virq, &m82xx_pci_ic);
++ return 0;
++}
++
++static void pci_host_unmap(struct irq_host *h, unsigned int virq)
++{
++ /* remove chip and handler */
++ set_irq_chip(virq, NULL);
++}
++
++static struct irq_host_ops pci_pic_host_ops = {
++ .match = pci_pic_host_match,
++ .map = pci_pic_host_map,
++ .unmap = pci_host_unmap,
++};
++
++void m82xx_pci_init_irq(void)
++{
++ int irq;
++ cpm2_map_t *immap;
++ struct device_node *np;
++ struct resource r;
++ const u32 *regs;
++ unsigned int size;
++ const u32 *irq_map;
++ int i;
++ unsigned int irq_max, irq_min;
++
++ if ((np = of_find_node_by_type(NULL, "soc")) == NULL) {
++ printk(KERN_INFO "No SOC node in device tree\n");
++ return;
++ }
++ memset(&r, 0, sizeof(r));
++ if (of_address_to_resource(np, 0, &r)) {
++ printk(KERN_INFO "No SOC reg property in device tree\n");
++ return;
++ }
++ immap = ioremap(r.start, sizeof(*immap));
++ of_node_put(np);
++
++ /* install the demultiplexer for the PCI cascade interrupt */
++ np = of_find_node_by_type(NULL, "pci");
++ if (!np) {
++ printk(KERN_INFO "No pci node on device tree\n");
++ iounmap(immap);
++ return;
++ }
++ irq_map = get_property(np, "interrupt-map", &size);
++ if ((!irq_map) || (size <= 7)) {
++ printk(KERN_INFO "No interrupt-map property of pci node\n");
++ iounmap(immap);
++ return;
++ }
++ size /= sizeof(irq_map[0]);
++ for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) {
++ if (irq_map[5] < irq_min)
++ irq_min = irq_map[5];
++ if (irq_map[5] > irq_max)
++ irq_max = irq_map[5];
++ }
++ pci_int_base = irq_min;
++ irq = irq_of_parse_and_map(np, 0);
++ set_irq_chained_handler(irq, m82xx_pci_irq_demux);
++ of_node_put(np);
++ np = of_find_node_by_type(NULL, "pci-pic");
++ if (!np) {
++ printk(KERN_INFO "No pci pic node on device tree\n");
++ iounmap(immap);
++ return;
++ }
++ pci_pic_node = of_node_get(np);
++ /* PCI interrupt controller registers: status and mask */
++ regs = get_property(np, "reg", &size);
++ if ((!regs) || (size <= 2)) {
++ printk(KERN_INFO "No reg property in pci pic node\n");
++ iounmap(immap);
++ return;
++ }
++ pci_regs.pci_int_stat_reg =
++ ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg));
++ pci_regs.pci_int_mask_reg =
++ ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg));
++ of_node_put(np);
++ /* configure chip select for PCI interrupt controller */
++ immap->im_memctl.memc_br3 = regs[0] | 0x00001801;
++ immap->im_memctl.memc_or3 = 0xffff8010;
++ /* make PCI IRQ level sensitive */
++ immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1)));
++
++ /* mask all PCI interrupts */
++ *pci_regs.pci_int_mask_reg |= 0xfff00000;
++ iounmap(immap);
++ pci_pic_host =
++ irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1,
++ &pci_pic_host_ops, irq_max + 1);
++ return;
++}
++
++static int m82xx_pci_exclude_device(u_char bus, u_char devfn)
++{
++ if (bus == 0 && PCI_SLOT(devfn) == 0)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ else
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static void
++__init mpc82xx_pcibios_fixup(void)
++{
++ struct pci_dev *dev = NULL;
++
++ for_each_pci_dev(dev) {
++ pci_read_irq_line(dev);
++ }
++}
++
++void __init add_bridge(struct device_node *np)
++{
++ int len;
++ struct pci_controller *hose;
++ struct resource r;
++ const int *bus_range;
++ const void *ptr;
++
++ memset(&r, 0, sizeof(r));
++ if (of_address_to_resource(np, 0, &r)) {
++ printk(KERN_INFO "No PCI reg property in device tree\n");
++ return;
++ }
++ if (!(ptr = get_property(np, "clock-frequency", NULL))) {
++ printk(KERN_INFO "No clock-frequency property in PCI node");
++ return;
++ }
++ pci_clk_frq = *(uint *) ptr;
++ of_node_put(np);
++ bus_range = get_property(np, "bus-range", &len);
++ if (bus_range == NULL || len < 2 * sizeof(int)) {
++ printk(KERN_WARNING "Can't get bus-range for %s, assume"
++ " bus 0\n", np->full_name);
++ }
++
++ pci_assign_all_buses = 1;
++
++ hose = pcibios_alloc_controller();
++
++ if (!hose)
++ return;
++
++ hose->arch_data = np;
++ hose->set_cfg_type = 1;
++
++ hose->first_busno = bus_range ? bus_range[0] : 0;
++ hose->last_busno = bus_range ? bus_range[1] : 0xff;
++ hose->bus_offset = 0;
++
++ hose->set_cfg_type = 1;
++
++ setup_indirect_pci(hose,
++ r.start + offsetof(pci_cpm2_t, pci_cfg_addr),
++ r.start + offsetof(pci_cpm2_t, pci_cfg_data));
++
++ pci_process_bridge_OF_ranges(hose, np, 1);
++}
++#endif
++
++/*
++ * Setup the architecture
++ */
++static void __init mpc82xx_ads_setup_arch(void)
++{
++#ifdef CONFIG_PCI
++ struct device_node *np;
++#endif
++
++ if (ppc_md.progress)
++ ppc_md.progress("mpc82xx_ads_setup_arch()", 0);
++ cpm2_reset();
++
++ /* Map I/O region to a 256MB BAT */
++
++ m82xx_board_setup();
++
++#ifdef CONFIG_PCI
++ ppc_md.pci_exclude_device = m82xx_pci_exclude_device;
++ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
++ add_bridge(np);
++
++ of_node_put(np);
++ ppc_md.pci_map_irq = NULL;
++ ppc_md.pcibios_fixup = mpc82xx_pcibios_fixup;
++ ppc_md.pcibios_fixup_bus = NULL;
++#endif
++
++#ifdef CONFIG_ROOT_NFS
++ ROOT_DEV = Root_NFS;
++#else
++ ROOT_DEV = Root_HDA1;
++#endif
++
++ if (ppc_md.progress)
++ ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0);
++}
++
++/*
++ * Called very early, device-tree isn't unflattened
++ */
++static int __init mpc82xx_ads_probe(void)
++{
++ /* We always match for now, eventually we should look at
++ * the flat dev tree to ensure this is the board we are
++ * supposed to run on
++ */
++ return 1;
++}
++
++#define RMR_CSRE 0x00000001
++static void m82xx_restart(char *cmd)
++{
++ __volatile__ unsigned char dummy;
++
++ local_irq_disable();
++ ((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE;
++
++ /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */
++ mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR));
++ dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0];
++ printk("Restart failed\n");
++ while (1) ;
++}
++
++static void m82xx_halt(void)
++{
++ local_irq_disable();
++ while (1) ;
++}
++
++define_machine(mpc82xx_ads)
++{
++ .name = "MPC82xx ADS",
++ .probe = mpc82xx_ads_probe,
++ .setup_arch = mpc82xx_ads_setup_arch,
++ .init_IRQ = mpc82xx_ads_pic_init,
++ .show_cpuinfo = mpc82xx_ads_show_cpuinfo,
++ .get_irq = cpm2_get_irq,
++ .calibrate_decr = m82xx_calibrate_decr,
++ .restart = m82xx_restart,.halt = m82xx_halt,
++};
+diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h
+new file mode 100644
+index 0000000..fb2f92b
+--- /dev/null
++++ b/arch/powerpc/platforms/82xx/pq2ads.h
+@@ -0,0 +1,65 @@
++/*
++ * PQ2/mpc8260 board-specific stuff
++ *
++ * A collection of structures, addresses, and values associated with
++ * the Freescale MPC8260ADS/MPC8266ADS-PCI boards.
++ * Copied from the RPX-Classic and SBS8260 stuff.
++ *
++ * Author: Vitaly Bordug <vbordug at ru.mvista.com>
++ *
++ * Originally written by Dan Malek for Motorola MPC8260 family
++ *
++ * Copyright (c) 2001 Dan Malek <dan at embeddedalley.com>
++ * Copyright (c) 2006 MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#ifdef __KERNEL__
++#ifndef __MACH_ADS8260_DEFS
++#define __MACH_ADS8260_DEFS
++
++#include <asm/ppcboot.h>
++
++/* For our show_cpuinfo hooks. */
++#define CPUINFO_VENDOR "Freescale Semiconductor"
++#define CPUINFO_MACHINE "PQ2 ADS PowerPC"
++
++/* Backword-compatibility stuff for the drivers */
++#define CPM_MAP_ADDR ((uint)0xf0000000)
++#define CPM_IRQ_OFFSET 0
++
++/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
++ * only on word boundaries.
++ * Not all are used (yet), or are interesting to us (yet).
++ */
++
++/* Things of interest in the CSR.
++ */
++#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */
++#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */
++#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable*/
++#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */
++#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */
++#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */
++#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/
++#define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */
++
++/* cpm serial driver works with constants below */
++
++#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET)
++#define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET)
++
++void m82xx_pci_init_irq(void);
++void mpc82xx_ads_show_cpuinfo(struct seq_file*);
++void m82xx_calibrate_decr(void);
++
++#endif /* __MACH_ADS8260_DEFS */
++#endif /* __KERNEL__ */
+diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
+index 5fe7b7f..7edb6b4 100644
+--- a/arch/powerpc/platforms/83xx/Kconfig
++++ b/arch/powerpc/platforms/83xx/Kconfig
+@@ -5,6 +5,13 @@ choice
+ prompt "Machine Type"
+ default MPC834x_SYS
+
++config MPC832x_MDS
++ bool "Freescale MPC832x MDS"
++ select DEFAULT_UIMAGE
++ select QUICC_ENGINE
++ help
++ This option enables support for the MPC832x MDS evaluation board.
++
+ config MPC834x_SYS
+ bool "Freescale MPC834x SYS"
+ select DEFAULT_UIMAGE
+@@ -25,12 +32,31 @@ config MPC834x_ITX
+ Be aware that PCI initialization is the bootloader's
+ responsiblilty.
+
++config MPC8360E_PB
++ bool "Freescale MPC8360E PB"
++ select DEFAULT_UIMAGE
++ select QUICC_ENGINE
++ help
++ This option enables support for the MPC836x EMDS Processor Board.
++
+ endchoice
+
++config PPC_MPC832x
++ bool
++ select PPC_UDBG_16550
++ select PPC_INDIRECT_PCI
++ default y if MPC832x_MDS
++
+ config MPC834x
+ bool
+ select PPC_UDBG_16550
+ select PPC_INDIRECT_PCI
+ default y if MPC834x_SYS || MPC834x_ITX
+
++config PPC_MPC836x
++ bool
++ select PPC_UDBG_16550
++ select PPC_INDIRECT_PCI
++ default y if MPC8360E_PB
++
+ endmenu
+diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
+index 9387a11..f1aa7e2 100644
+--- a/arch/powerpc/platforms/83xx/Makefile
++++ b/arch/powerpc/platforms/83xx/Makefile
+@@ -5,3 +5,5 @@ obj-y := misc.o
+ obj-$(CONFIG_PCI) += pci.o
+ obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o
+ obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o
++obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o
++obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o
+diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
+new file mode 100644
+index 0000000..54dea9d
+--- /dev/null
++++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
+@@ -0,0 +1,215 @@
++/*
++ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
++ *
++ * Description:
++ * MPC832xE MDS board specific routines.
++ *
++ * 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/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/major.h>
++#include <linux/console.h>
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include <linux/root_dev.h>
++#include <linux/initrd.h>
++
++#include <asm/system.h>
++#include <asm/atomic.h>
++#include <asm/time.h>
++#include <asm/io.h>
++#include <asm/machdep.h>
++#include <asm/ipic.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/prom.h>
++#include <asm/udbg.h>
++#include <sysdev/fsl_soc.h>
++#include <asm/qe.h>
++#include <asm/qe_ic.h>
++
++#include "mpc83xx.h"
++#include "mpc832x_mds.h"
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(fmt...) udbg_printf(fmt)
++#else
++#define DBG(fmt...)
++#endif
++
++#ifndef CONFIG_PCI
++unsigned long isa_io_base = 0;
++unsigned long isa_mem_base = 0;
++#endif
++
++static u8 *bcsr_regs = NULL;
++
++u8 *get_bcsr(void)
++{
++ return bcsr_regs;
++}
++
++/* ************************************************************************
++ *
++ * Setup the architecture
++ *
++ */
++static void __init mpc832x_sys_setup_arch(void)
++{
++ struct device_node *np;
++
++ if (ppc_md.progress)
++ ppc_md.progress("mpc832x_sys_setup_arch()", 0);
++
++ np = of_find_node_by_type(NULL, "cpu");
++ if (np != 0) {
++ unsigned int *fp =
++ (int *)get_property(np, "clock-frequency", NULL);
++ if (fp != 0)
++ loops_per_jiffy = *fp / HZ;
++ else
++ loops_per_jiffy = 50000000 / HZ;
++ of_node_put(np);
++ }
++
++ /* Map BCSR area */
++ np = of_find_node_by_name(NULL, "bcsr");
++ if (np != 0) {
++ struct resource res;
++
++ of_address_to_resource(np, 0, &res);
++ bcsr_regs = ioremap(res.start, res.end - res.start +1);
++ of_node_put(np);
++ }
++
++#ifdef CONFIG_PCI
++ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
++ add_bridge(np);
++
++ ppc_md.pci_swizzle = common_swizzle;
++ ppc_md.pci_exclude_device = mpc83xx_exclude_device;
++#endif
++
++#ifdef CONFIG_QUICC_ENGINE
++ qe_reset();
++
++ if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
++ par_io_init(np);
++ of_node_put(np);
++
++ for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
++ par_io_of_config(np);
++ }
++
++ if ((np = of_find_compatible_node(NULL, "network", "ucc_geth"))
++ != NULL){
++ /* Reset the Ethernet PHY */
++ bcsr_regs[9] &= ~0x20;
++ udelay(1000);
++ bcsr_regs[9] |= 0x20;
++ iounmap(bcsr_regs);
++ of_node_put(np);
++ }
++
++#endif /* CONFIG_QUICC_ENGINE */
++
++#ifdef CONFIG_BLK_DEV_INITRD
++ if (initrd_start)
++ ROOT_DEV = Root_RAM0;
++ else
++#endif
++#ifdef CONFIG_ROOT_NFS
++ ROOT_DEV = Root_NFS;
++#else
++ ROOT_DEV = Root_HDA1;
++#endif
++}
++
++void __init mpc832x_sys_init_IRQ(void)
++{
++
++ struct device_node *np;
++
++ np = of_find_node_by_type(NULL, "ipic");
++ if (!np)
++ return;
++
++ ipic_init(np, 0);
++
++ /* Initialize the default interrupt mapping priorities,
++ * in case the boot rom changed something on us.
++ */
++ ipic_set_default_priority();
++ of_node_put(np);
++
++#ifdef CONFIG_QUICC_ENGINE
++ np = of_find_node_by_type(NULL, "qeic");
++ if (!np)
++ return;
++
++ qe_ic_init(np, 0);
++ of_node_put(np);
++#endif /* CONFIG_QUICC_ENGINE */
++}
++
++#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
++extern ulong ds1374_get_rtc_time(void);
++extern int ds1374_set_rtc_time(ulong);
++
++static int __init mpc832x_rtc_hookup(void)
++{
++ struct timespec tv;
++
++ ppc_md.get_rtc_time = ds1374_get_rtc_time;
++ ppc_md.set_rtc_time = ds1374_set_rtc_time;
++
++ tv.tv_nsec = 0;
++ tv.tv_sec = (ppc_md.get_rtc_time) ();
++ do_settimeofday(&tv);
++
++ return 0;
++}
++
++late_initcall(mpc832x_rtc_hookup);
++#endif
++
++/*
++ * Called very early, MMU is off, device-tree isn't unflattened
++ */
++static int __init mpc832x_sys_probe(void)
++{
++ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
++ "model", NULL);
++
++ if (model == NULL)
++ return 0;
++ if (strcmp(model, "MPC8323EMDS"))
++ return 0;
++
++ DBG("%s found\n", model);
++
++ return 1;
++}
++
++define_machine(mpc832x_mds) {
++ .name = "MPC832x MDS",
++ .probe = mpc832x_sys_probe,
++ .setup_arch = mpc832x_sys_setup_arch,
++ .init_IRQ = mpc832x_sys_init_IRQ,
++ .get_irq = ipic_get_irq,
++ .restart = mpc83xx_restart,
++ .time_init = mpc83xx_time_init,
++ .calibrate_decr = generic_calibrate_decr,
++ .progress = udbg_progress,
++};
+diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
+new file mode 100644
+index 0000000..a495889
+--- /dev/null
++++ b/arch/powerpc/platforms/83xx/mpc832x_mds.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
++ *
++ * Description:
++ * MPC832x MDS board specific header.
++ *
++ * 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.
++ *
++ */
++
++#ifndef __MACH_MPC832x_MDS_H__
++#define __MACH_MPC832x_MDS_H__
++
++extern u8 *get_bcsr(void);
++
++#endif /* __MACH_MPC832x_MDS_H__ */
+diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
+index cf3967a..5446bab 100644
+--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
++++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
+@@ -11,7 +11,6 @@
+ * option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/stddef.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -60,8 +59,8 @@ static void __init mpc834x_itx_setup_arc
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != 0) {
+- unsigned int *fp =
+- (int *)get_property(np, "clock-frequency", NULL);
++ const unsigned int *fp =
++ get_property(np, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+@@ -109,6 +108,10 @@ static int __init mpc834x_itx_probe(void
+ return 1;
+ }
+
++#ifdef CONFIG_RTC_CLASS
++late_initcall(rtc_class_hookup);
++#endif
++
+ define_machine(mpc834x_itx) {
+ .name = "MPC834x ITX",
+ .probe = mpc834x_itx_probe,
+diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
+index 32df239..6771961 100644
+--- a/arch/powerpc/platforms/83xx/mpc834x_sys.c
++++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
+@@ -57,8 +57,8 @@ static void __init mpc834x_sys_setup_arc
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != 0) {
+- unsigned int *fp =
+- (int *)get_property(np, "clock-frequency", NULL);
++ const unsigned int *fp =
++ get_property(np, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h
+index fedecb7..7d5bbef 100644
+--- a/arch/powerpc/platforms/83xx/mpc834x_sys.h
++++ b/arch/powerpc/platforms/83xx/mpc834x_sys.h
+@@ -1,5 +1,5 @@
+ /*
+- * arch/powerppc/platforms/83xx/mpc834x_sys.h
++ * arch/powerpc/platforms/83xx/mpc834x_sys.h
+ *
+ * MPC834X SYS common board definitions
+ *
+diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
+new file mode 100644
+index 0000000..1a523c8
+--- /dev/null
++++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
++ *
++ * Author: Li Yang <LeoLi at freescale.com>
++ * Yin Olivia <Hong-hua.Yin at freescale.com>
++ *
++ * Description:
++ * MPC8360E MDS PB board specific routines.
++ *
++ * Changelog:
++ * Jun 21, 2006 Initial 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.
++ */
++
++#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/major.h>
++#include <linux/console.h>
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include <linux/root_dev.h>
++#include <linux/initrd.h>
++
++#include <asm/of_device.h>
++#include <asm/system.h>
++#include <asm/atomic.h>
++#include <asm/time.h>
++#include <asm/io.h>
++#include <asm/machdep.h>
++#include <asm/ipic.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/prom.h>
++#include <asm/udbg.h>
++#include <sysdev/fsl_soc.h>
++#include <asm/qe.h>
++#include <asm/qe_ic.h>
++
++#include "mpc83xx.h"
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(fmt...) udbg_printf(fmt)
++#else
++#define DBG(fmt...)
++#endif
++
++#ifndef CONFIG_PCI
++unsigned long isa_io_base = 0;
++unsigned long isa_mem_base = 0;
++#endif
++
++static u8 *bcsr_regs = NULL;
++
++u8 *get_bcsr(void)
++{
++ return bcsr_regs;
++}
++
++/* ************************************************************************
++ *
++ * Setup the architecture
++ *
++ */
++static void __init mpc8360_sys_setup_arch(void)
++{
++ struct device_node *np;
++
++ if (ppc_md.progress)
++ ppc_md.progress("mpc8360_sys_setup_arch()", 0);
++
++ np = of_find_node_by_type(NULL, "cpu");
++ if (np != 0) {
++ const unsigned int *fp =
++ get_property(np, "clock-frequency", NULL);
++ if (fp != 0)
++ loops_per_jiffy = *fp / HZ;
++ else
++ loops_per_jiffy = 50000000 / HZ;
++ of_node_put(np);
++ }
++
++ /* Map BCSR area */
++ np = of_find_node_by_name(NULL, "bcsr");
++ if (np != 0) {
++ struct resource res;
++
++ of_address_to_resource(np, 0, &res);
++ bcsr_regs = ioremap(res.start, res.end - res.start +1);
++ of_node_put(np);
++ }
++
++#ifdef CONFIG_PCI
++ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
++ add_bridge(np);
++
++ ppc_md.pci_swizzle = common_swizzle;
++ ppc_md.pci_exclude_device = mpc83xx_exclude_device;
++#endif
++
++#ifdef CONFIG_QUICC_ENGINE
++ qe_reset();
++
++ if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
++ par_io_init(np);
++ of_node_put(np);
++
++ for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
++ par_io_of_config(np);
++ }
++
++ if ((np = of_find_compatible_node(NULL, "network", "ucc_geth"))
++ != NULL){
++ /* Reset the Ethernet PHY */
++ bcsr_regs[9] &= ~0x20;
++ udelay(1000);
++ bcsr_regs[9] |= 0x20;
++ iounmap(bcsr_regs);
++ of_node_put(np);
++ }
++
++#endif /* CONFIG_QUICC_ENGINE */
++
++#ifdef CONFIG_BLK_DEV_INITRD
++ if (initrd_start)
++ ROOT_DEV = Root_RAM0;
++ else
++#endif
++#ifdef CONFIG_ROOT_NFS
++ ROOT_DEV = Root_NFS;
++#else
++ ROOT_DEV = Root_HDA1;
++#endif
++}
++
++static int __init mpc8360_declare_of_platform_devices(void)
++{
++ struct device_node *np;
++
++ for (np = NULL; (np = of_find_compatible_node(np, "network",
++ "ucc_geth")) != NULL;) {
++ int ucc_num;
++ char bus_id[BUS_ID_SIZE];
++
++ ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1;
++ snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num);
++ of_platform_device_create(np, bus_id, NULL);
++ }
++
++ return 0;
++}
++device_initcall(mpc8360_declare_of_platform_devices);
++
++void __init mpc8360_sys_init_IRQ(void)
++{
++
++ struct device_node *np;
++
++ np = of_find_node_by_type(NULL, "ipic");
++ if (!np)
++ return;
++
++ ipic_init(np, 0);
++
++ /* Initialize the default interrupt mapping priorities,
++ * in case the boot rom changed something on us.
++ */
++ ipic_set_default_priority();
++ of_node_put(np);
++
++#ifdef CONFIG_QUICC_ENGINE
++ np = of_find_node_by_type(NULL, "qeic");
++ if (!np)
++ return;
++
++ qe_ic_init(np, 0);
++ of_node_put(np);
++#endif /* CONFIG_QUICC_ENGINE */
++}
++
++#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
++extern ulong ds1374_get_rtc_time(void);
++extern int ds1374_set_rtc_time(ulong);
++
++static int __init mpc8360_rtc_hookup(void)
++{
++ struct timespec tv;
++
++ ppc_md.get_rtc_time = ds1374_get_rtc_time;
++ ppc_md.set_rtc_time = ds1374_set_rtc_time;
++
++ tv.tv_nsec = 0;
++ tv.tv_sec = (ppc_md.get_rtc_time) ();
++ do_settimeofday(&tv);
++
++ return 0;
++}
++
++late_initcall(mpc8360_rtc_hookup);
++#endif
++
++/*
++ * Called very early, MMU is off, device-tree isn't unflattened
++ */
++static int __init mpc8360_sys_probe(void)
++{
++ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
++ "model", NULL);
++ if (model == NULL)
++ return 0;
++ if (strcmp(model, "MPC8360EPB"))
++ return 0;
++
++ DBG("MPC8360EMDS-PB found\n");
++
++ return 1;
++}
++
++define_machine(mpc8360_sys) {
++ .name = "MPC8360E PB",
++ .probe = mpc8360_sys_probe,
++ .setup_arch = mpc8360_sys_setup_arch,
++ .init_IRQ = mpc8360_sys_init_IRQ,
++ .get_irq = ipic_get_irq,
++ .restart = mpc83xx_restart,
++ .time_init = mpc83xx_time_init,
++ .calibrate_decr = generic_calibrate_decr,
++ .progress = udbg_progress,
++};
+diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
+index 5d84a9c..4557ac5 100644
+--- a/arch/powerpc/platforms/83xx/pci.c
++++ b/arch/powerpc/platforms/83xx/pci.c
+@@ -59,7 +59,7 @@ int __init add_bridge(struct device_node
+ int len;
+ struct pci_controller *hose;
+ struct resource rsrc;
+- int *bus_range;
++ const int *bus_range;
+ int primary = 1, has_address = 0;
+ phys_addr_t immr = get_immrbase();
+
+@@ -69,7 +69,7 @@ int __init add_bridge(struct device_node
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
+- bus_range = (int *)get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", dev->full_name);
+diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
+index c3268d9..0584f3c 100644
+--- a/arch/powerpc/platforms/85xx/Kconfig
++++ b/arch/powerpc/platforms/85xx/Kconfig
+@@ -11,6 +11,12 @@ config MPC8540_ADS
+ help
+ This option enables support for the MPC 8540 ADS board
+
++config MPC8560_ADS
++ bool "Freescale MPC8560 ADS"
++ select DEFAULT_UIMAGE
++ help
++ This option enables support for the MPC 8560 ADS board
++
+ config MPC85xx_CDS
+ bool "Freescale MPC85xx CDS"
+ select DEFAULT_UIMAGE
+@@ -25,6 +31,11 @@ config MPC8540
+ select PPC_INDIRECT_PCI
+ default y if MPC8540_ADS || MPC85xx_CDS
+
++config MPC8560
++ bool
++ select PPC_INDIRECT_PCI
++ default y if MPC8560_ADS
++
+ config PPC_INDIRECT_PCI_BE
+ bool
+ depends on PPC_85xx
+@@ -34,4 +45,14 @@ config MPIC
+ bool
+ default y
+
++config CPM2
++ bool
++ depends on MPC8560
++ default y
++ help
++ The CPM2 (Communications Processor Module) is a coprocessor on
++ embedded CPUs made by Motorola. Selecting this option means that
++ you wish to build a kernel for a machine with a CPM2 coprocessor
++ on it.
++
+ endmenu
+diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
+index 7615aa5..282f5d0 100644
+--- a/arch/powerpc/platforms/85xx/Makefile
++++ b/arch/powerpc/platforms/85xx/Makefile
+@@ -3,4 +3,5 @@
+ #
+ obj-$(CONFIG_PPC_85xx) += misc.o pci.o
+ obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
++obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
+ obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
+diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/powerpc/platforms/85xx/mpc8540_ads.h
+index c0d56d2..da82f4c 100644
+--- a/arch/powerpc/platforms/85xx/mpc8540_ads.h
++++ b/arch/powerpc/platforms/85xx/mpc8540_ads.h
+@@ -1,5 +1,5 @@
+ /*
+- * arch/ppc/platforms/85xx/mpc8540_ads.h
++ * arch/powerpc/platforms/85xx/mpc8540_ads.h
+ *
+ * MPC8540ADS board definitions
+ *
+diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h
+index b44db62..83415db 100644
+--- a/arch/powerpc/platforms/85xx/mpc85xx.h
++++ b/arch/powerpc/platforms/85xx/mpc85xx.h
+@@ -1,5 +1,5 @@
+ /*
+- * arch/ppc/platforms/85xx/mpc85xx.h
++ * arch/powerpc/platforms/85xx/mpc85xx.h
+ *
+ * MPC85xx soc definitions/function decls
+ *
+diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+index 9d2acfb..d3e669d 100644
+--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
++++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+@@ -32,6 +32,13 @@
+ #include <sysdev/fsl_soc.h>
+ #include "mpc85xx.h"
+
++#ifdef CONFIG_CPM2
++#include <linux/fs_enet_pd.h>
++#include <asm/cpm2.h>
++#include <sysdev/cpm2_pic.h>
++#include <asm/fs_pd.h>
++#endif
++
+ #ifndef CONFIG_PCI
+ unsigned long isa_io_base = 0;
+ unsigned long isa_mem_base = 0;
+@@ -57,12 +64,28 @@ mpc85xx_pcibios_fixup(void)
+ }
+ #endif /* CONFIG_PCI */
+
++#ifdef CONFIG_CPM2
++
++static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
++{
++ int cascade_irq;
++
++ while ((cascade_irq = cpm2_get_irq()) >= 0) {
++ generic_handle_irq(cascade_irq);
++ }
++ desc->chip->eoi(irq);
++}
++
++#endif /* CONFIG_CPM2 */
+
+ void __init mpc85xx_ads_pic_init(void)
+ {
+ struct mpic *mpic;
+ struct resource r;
+ struct device_node *np = NULL;
++#ifdef CONFIG_CPM2
++ int irq;
++#endif
+
+ np = of_find_node_by_type(np, "open-pic");
+
+@@ -104,11 +127,103 @@ void __init mpc85xx_ads_pic_init(void)
+ mpic_assign_isu(mpic, 14, r.start + 0x10100);
+
+ mpic_init(mpic);
++
++#ifdef CONFIG_CPM2
++ /* Setup CPM2 PIC */
++ np = of_find_node_by_type(NULL, "cpm-pic");
++ if (np == NULL) {
++ printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
++ return;
++ }
++ irq = irq_of_parse_and_map(np, 0);
++
++ cpm2_pic_init(np);
++ set_irq_chained_handler(irq, cpm2_cascade);
++#endif
+ }
+
+ /*
+ * Setup the architecture
+ */
++#ifdef CONFIG_CPM2
++void init_fcc_ioports(struct fs_platform_info *fpi)
++{
++ struct io_port *io = cpm2_map(im_ioport);
++ int fcc_no = fs_get_fcc_index(fpi->fs_no);
++ int target;
++ u32 tempval;
++
++ switch(fcc_no) {
++ case 1:
++ tempval = in_be32(&io->iop_pdirb);
++ tempval &= ~PB2_DIRB0;
++ tempval |= PB2_DIRB1;
++ out_be32(&io->iop_pdirb, tempval);
++
++ tempval = in_be32(&io->iop_psorb);
++ tempval &= ~PB2_PSORB0;
++ tempval |= PB2_PSORB1;
++ out_be32(&io->iop_psorb, tempval);
++
++ tempval = in_be32(&io->iop_pparb);
++ tempval |= (PB2_DIRB0 | PB2_DIRB1);
++ out_be32(&io->iop_pparb, tempval);
++
++ target = CPM_CLK_FCC2;
++ break;
++ case 2:
++ tempval = in_be32(&io->iop_pdirb);
++ tempval &= ~PB3_DIRB0;
++ tempval |= PB3_DIRB1;
++ out_be32(&io->iop_pdirb, tempval);
++
++ tempval = in_be32(&io->iop_psorb);
++ tempval &= ~PB3_PSORB0;
++ tempval |= PB3_PSORB1;
++ out_be32(&io->iop_psorb, tempval);
++
++ tempval = in_be32(&io->iop_pparb);
++ tempval |= (PB3_DIRB0 | PB3_DIRB1);
++ out_be32(&io->iop_pparb, tempval);
++
++ tempval = in_be32(&io->iop_pdirc);
++ tempval |= PC3_DIRC1;
++ out_be32(&io->iop_pdirc, tempval);
++
++ tempval = in_be32(&io->iop_pparc);
++ tempval |= PC3_DIRC1;
++ out_be32(&io->iop_pparc, tempval);
++
++ target = CPM_CLK_FCC3;
++ break;
++ default:
++ printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n");
++ return;
++ }
++
++ /* Port C has clocks...... */
++ tempval = in_be32(&io->iop_psorc);
++ tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8));
++ out_be32(&io->iop_psorc, tempval);
++
++ tempval = in_be32(&io->iop_pdirc);
++ tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8));
++ out_be32(&io->iop_pdirc, tempval);
++ tempval = in_be32(&io->iop_pparc);
++ tempval |= (PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8));
++ out_be32(&io->iop_pparc, tempval);
++
++ cpm2_unmap(io);
++
++ /* Configure Serial Interface clock routing.
++ * First, clear FCC bits to zero,
++ * then set the ones we want.
++ */
++ cpm2_clk_setup(target, fpi->clk_rx, CPM_CLK_RX);
++ cpm2_clk_setup(target, fpi->clk_tx, CPM_CLK_TX);
++}
++#endif
++
+ static void __init mpc85xx_ads_setup_arch(void)
+ {
+ struct device_node *cpu;
+@@ -121,9 +236,9 @@ static void __init mpc85xx_ads_setup_arc
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+- unsigned int *fp;
++ const unsigned int *fp;
+
+- fp = (int *)get_property(cpu, "clock-frequency", NULL);
++ fp = get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+@@ -131,6 +246,10 @@ static void __init mpc85xx_ads_setup_arc
+ of_node_put(cpu);
+ }
+
++#ifdef CONFIG_CPM2
++ cpm2_reset();
++#endif
++
+ #ifdef CONFIG_PCI
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.h b/arch/powerpc/platforms/85xx/mpc85xx_ads.h
+new file mode 100644
+index 0000000..46c3532
+--- /dev/null
++++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.h
+@@ -0,0 +1,60 @@
++/*
++ * MPC85xx ADS board definitions
++ *
++ * Maintainer: Kumar Gala <galak at kernel.crashing.org>
++ *
++ * Copyright 2004 Freescale Semiconductor Inc.
++ *
++ * 2006 (c) MontaVista Software, Inc.
++ * Vitaly Bordug <vbordug at ru.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.
++ *
++ */
++
++#ifndef __MACH_MPC85XXADS_H
++#define __MACH_MPC85XXADS_H
++
++#include <linux/initrd.h>
++#include <sysdev/fsl_soc.h>
++
++#define BCSR_ADDR ((uint)0xf8000000)
++#define BCSR_SIZE ((uint)(32 * 1024))
++
++#ifdef CONFIG_CPM2
++
++#define MPC85xx_CPM_OFFSET (0x80000)
++
++#define CPM_MAP_ADDR (get_immrbase() + MPC85xx_CPM_OFFSET)
++#define CPM_IRQ_OFFSET 60
++
++#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET)
++#define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET)
++#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET)
++
++/* FCC1 Clock Source Configuration. These can be
++ * redefined in the board specific file.
++ * Can only choose from CLK9-12 */
++#define F1_RXCLK 12
++#define F1_TXCLK 11
++
++/* FCC2 Clock Source Configuration. These can be
++ * redefined in the board specific file.
++ * Can only choose from CLK13-16 */
++#define F2_RXCLK 13
++#define F2_TXCLK 14
++
++/* FCC3 Clock Source Configuration. These can be
++ * redefined in the board specific file.
++ * Can only choose from CLK13-16 */
++#define F3_RXCLK 15
++#define F3_TXCLK 16
++
++#endif /* CONFIG_CPM2 */
++#endif /* __MACH_MPC85XXADS_H */
+diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+index 1d357d3..953cd5d 100644
+--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
++++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+@@ -11,7 +11,6 @@
+ * option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/stddef.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -133,13 +132,12 @@ mpc85xx_cds_pcibios_fixup(void)
+
+ #ifdef CONFIG_PPC_I8259
+ #warning The i8259 PIC support is currently broken
+-static void mpc85xx_8259_cascade(unsigned int irq, struct
+- irq_desc *desc, struct pt_regs *regs)
++static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+- unsigned int cascade_irq = i8259_irq(regs);
++ unsigned int cascade_irq = i8259_irq();
+
+ if (cascade_irq != NO_IRQ)
+- generic_handle_irq(cascade_irq, regs);
++ generic_handle_irq(cascade_irq);
+
+ desc->chip->eoi(irq);
+ }
+@@ -151,8 +149,10 @@ void __init mpc85xx_cds_pic_init(void)
+ struct mpic *mpic;
+ struct resource r;
+ struct device_node *np = NULL;
++#ifdef CONFIG_PPC_I8259
+ struct device_node *cascade_node = NULL;
+ int cascade_irq;
++#endif
+
+ np = of_find_node_by_type(np, "open-pic");
+
+@@ -241,9 +241,9 @@ mpc85xx_cds_setup_arch(void)
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+- unsigned int *fp;
++ const unsigned int *fp;
+
+- fp = (int *)get_property(cpu, "clock-frequency", NULL);
++ fp = get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h
+index 671f54f..b251c9f 100644
+--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.h
++++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.h
+@@ -1,5 +1,5 @@
+ /*
+- * arch/ppc/platforms/85xx/mpc85xx_cds_common.h
++ * arch/powerpc/platforms/85xx/mpc85xx_cds.h
+ *
+ * MPC85xx CDS board definitions
+ *
+diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
+index 1d51f32..05930ee 100644
+--- a/arch/powerpc/platforms/85xx/pci.c
++++ b/arch/powerpc/platforms/85xx/pci.c
+@@ -41,7 +41,7 @@ int __init add_bridge(struct device_node
+ int len;
+ struct pci_controller *hose;
+ struct resource rsrc;
+- int *bus_range;
++ const int *bus_range;
+ int primary = 1, has_address = 0;
+ phys_addr_t immr = get_immrbase();
+
+@@ -51,7 +51,7 @@ int __init add_bridge(struct device_node
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
+- bus_range = (int *) get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", dev->full_name);
+diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+index 5e583cf..1a1c226 100644
+--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
++++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+@@ -53,12 +53,11 @@ unsigned long pci_dram_offset = 0;
+
+
+ #ifdef CONFIG_PCI
+-static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+- unsigned int cascade_irq = i8259_irq(regs);
++ unsigned int cascade_irq = i8259_irq();
+ if (cascade_irq != NO_IRQ)
+- generic_handle_irq(cascade_irq, regs);
++ generic_handle_irq(cascade_irq);
+ desc->chip->eoi(irq);
+ }
+ #endif /* CONFIG_PCI */
+@@ -347,9 +346,9 @@ mpc86xx_hpcn_setup_arch(void)
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != 0) {
+- unsigned int *fp;
++ const unsigned int *fp;
+
+- fp = (int *)get_property(np, "clock-frequency", NULL);
++ fp = get_property(np, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
+index a8c8f0a..481e18e 100644
+--- a/arch/powerpc/platforms/86xx/pci.c
++++ b/arch/powerpc/platforms/86xx/pci.c
+@@ -153,7 +153,7 @@ int __init add_bridge(struct device_node
+ int len;
+ struct pci_controller *hose;
+ struct resource rsrc;
+- int *bus_range;
++ const int *bus_range;
+ int has_address = 0;
+ int primary = 0;
+
+@@ -163,7 +163,7 @@ int __init add_bridge(struct device_node
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
+- bus_range = (int *) get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int))
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", dev->full_name);
+diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
+index 5cf46dc..e58fa95 100644
+--- a/arch/powerpc/platforms/Makefile
++++ b/arch/powerpc/platforms/Makefile
+@@ -13,5 +13,6 @@ obj-$(CONFIG_PPC_86xx) += 86xx/
+ obj-$(CONFIG_PPC_PSERIES) += pseries/
+ obj-$(CONFIG_PPC_ISERIES) += iseries/
+ obj-$(CONFIG_PPC_MAPLE) += maple/
++obj-$(CONFIG_PPC_PASEMI) += pasemi/
+ obj-$(CONFIG_PPC_CELL) += cell/
+ obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/
+diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
+index 0c8c7b6..3e430b4 100644
+--- a/arch/powerpc/platforms/cell/Kconfig
++++ b/arch/powerpc/platforms/cell/Kconfig
+@@ -16,11 +16,6 @@ config SPU_BASE
+ bool
+ default n
+
+-config SPUFS_MMAP
+- bool
+- depends on SPU_FS && SPARSEMEM
+- default y
+-
+ config CBE_RAS
+ bool "RAS features for bare metal Cell BE"
+ default y
+diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
+index ce696c1..2f194ba 100644
+--- a/arch/powerpc/platforms/cell/cbe_regs.c
++++ b/arch/powerpc/platforms/cell/cbe_regs.c
+@@ -6,8 +6,6 @@
+ * (c) 2006 Benjamin Herrenschmidt <benh at kernel.crashing.org>, IBM Corp.
+ */
+
+-
+-#include <linux/config.h>
+ #include <linux/percpu.h>
+ #include <linux/types.h>
+
+@@ -97,7 +95,7 @@ void __init cbe_regs_init(void)
+ struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
+
+ /* That hack must die die die ! */
+- struct address_prop {
++ const struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *prop;
+@@ -114,13 +112,11 @@ void __init cbe_regs_init(void)
+ if (cbe_thread_map[i].cpu_node == cpu)
+ cbe_thread_map[i].regs = map;
+
+- prop = (struct address_prop *)get_property(cpu, "pervasive",
+- NULL);
++ prop = get_property(cpu, "pervasive", NULL);
+ if (prop != NULL)
+ map->pmd_regs = ioremap(prop->address, prop->len);
+
+- prop = (struct address_prop *)get_property(cpu, "iic",
+- NULL);
++ prop = get_property(cpu, "iic", NULL);
+ if (prop != NULL)
+ map->iic_regs = ioremap(prop->address, prop->len);
+ }
+diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
+index d7bbb61..a914c12 100644
+--- a/arch/powerpc/platforms/cell/interrupt.c
++++ b/arch/powerpc/platforms/cell/interrupt.c
+@@ -21,6 +21,12 @@
+ * 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.
++ *
++ * TODO:
++ * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers
++ * vs node numbers in the setup code
++ * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from
++ * a non-active node to the active node)
+ */
+
+ #include <linux/interrupt.h>
+@@ -44,24 +50,25 @@ struct iic {
+ u8 target_id;
+ u8 eoi_stack[16];
+ int eoi_ptr;
+- struct irq_host *host;
++ struct device_node *node;
+ };
+
+ static DEFINE_PER_CPU(struct iic, iic);
+ #define IIC_NODE_COUNT 2
+-static struct irq_host *iic_hosts[IIC_NODE_COUNT];
++static struct irq_host *iic_host;
+
+ /* Convert between "pending" bits and hw irq number */
+ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
+ {
+ unsigned char unit = bits.source & 0xf;
++ unsigned char node = bits.source >> 4;
++ unsigned char class = bits.class & 3;
+
++ /* Decode IPIs */
+ if (bits.flags & CBE_IIC_IRQ_IPI)
+- return IIC_IRQ_IPI0 | (bits.prio >> 4);
+- else if (bits.class <= 3)
+- return (bits.class << 4) | unit;
++ return IIC_IRQ_TYPE_IPI | (bits.prio >> 4);
+ else
+- return IIC_IRQ_INVALID;
++ return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
+ }
+
+ static void iic_mask(unsigned int irq)
+@@ -86,21 +93,69 @@ static struct irq_chip iic_chip = {
+ .eoi = iic_eoi,
+ };
+
++
++static void iic_ioexc_eoi(unsigned int irq)
++{
++}
++
++static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
++{
++ struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data;
++ unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
++ unsigned long bits, ack;
++ int cascade;
++
++ for (;;) {
++ bits = in_be64(&node_iic->iic_is);
++ if (bits == 0)
++ break;
++ /* pre-ack edge interrupts */
++ ack = bits & IIC_ISR_EDGE_MASK;
++ if (ack)
++ out_be64(&node_iic->iic_is, ack);
++ /* handle them */
++ for (cascade = 63; cascade >= 0; cascade--)
++ if (bits & (0x8000000000000000UL >> cascade)) {
++ unsigned int cirq =
++ irq_linear_revmap(iic_host,
++ base | cascade);
++ if (cirq != NO_IRQ)
++ generic_handle_irq(cirq);
++ }
++ /* post-ack level interrupts */
++ ack = bits & ~IIC_ISR_EDGE_MASK;
++ if (ack)
++ out_be64(&node_iic->iic_is, ack);
++ }
++ desc->chip->eoi(irq);
++}
++
++
++static struct irq_chip iic_ioexc_chip = {
++ .typename = " CELL-IOEX",
++ .mask = iic_mask,
++ .unmask = iic_unmask,
++ .eoi = iic_ioexc_eoi,
++};
++
+ /* Get an IRQ number from the pending state register of the IIC */
+-static unsigned int iic_get_irq(struct pt_regs *regs)
++static unsigned int iic_get_irq(void)
+ {
+- struct cbe_iic_pending_bits pending;
+- struct iic *iic;
+-
+- iic = &__get_cpu_var(iic);
+- *(unsigned long *) &pending =
+- in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+- iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
+- BUG_ON(iic->eoi_ptr > 15);
+- if (pending.flags & CBE_IIC_IRQ_VALID)
+- return irq_linear_revmap(iic->host,
+- iic_pending_to_hwnum(pending));
+- return NO_IRQ;
++ struct cbe_iic_pending_bits pending;
++ struct iic *iic;
++ unsigned int virq;
++
++ iic = &__get_cpu_var(iic);
++ *(unsigned long *) &pending =
++ in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
++ if (!(pending.flags & CBE_IIC_IRQ_VALID))
++ return NO_IRQ;
++ virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending));
++ if (virq == NO_IRQ)
++ return NO_IRQ;
++ iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
++ BUG_ON(iic->eoi_ptr > 15);
++ return virq;
+ }
+
+ #ifdef CONFIG_SMP
+@@ -108,12 +163,7 @@ static unsigned int iic_get_irq(struct p
+ /* Use the highest interrupt priorities for IPI */
+ static inline int iic_ipi_to_irq(int ipi)
+ {
+- return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi;
+-}
+-
+-static inline int iic_irq_to_ipi(int irq)
+-{
+- return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0);
++ return IIC_IRQ_TYPE_IPI + 0xf - ipi;
+ }
+
+ void iic_setup_cpu(void)
+@@ -123,7 +173,7 @@ void iic_setup_cpu(void)
+
+ void iic_cause_IPI(int cpu, int mesg)
+ {
+- out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
++ out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
+ }
+
+ u8 iic_get_target_id(int cpu)
+@@ -134,49 +184,33 @@ EXPORT_SYMBOL_GPL(iic_get_target_id);
+
+ struct irq_host *iic_get_irq_host(int node)
+ {
+- if (node < 0 || node >= IIC_NODE_COUNT)
+- return NULL;
+- return iic_hosts[node];
++ return iic_host;
+ }
+ EXPORT_SYMBOL_GPL(iic_get_irq_host);
+
+
+-static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t iic_ipi_action(int irq, void *dev_id)
+ {
+ int ipi = (int)(long)dev_id;
+
+- smp_message_recv(ipi, regs);
++ smp_message_recv(ipi);
+
+ return IRQ_HANDLED;
+ }
+-
+ static void iic_request_ipi(int ipi, const char *name)
+ {
+- int node, virq;
++ int virq;
+
+- for (node = 0; node < IIC_NODE_COUNT; node++) {
+- char *rname;
+- if (iic_hosts[node] == NULL)
+- continue;
+- virq = irq_create_mapping(iic_hosts[node],
+- iic_ipi_to_irq(ipi));
+- if (virq == NO_IRQ) {
+- printk(KERN_ERR
+- "iic: failed to map IPI %s on node %d\n",
+- name, node);
+- continue;
+- }
+- rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
+- if (rname)
+- sprintf(rname, "%s node %d", name, node);
+- else
+- rname = (char *)name;
+- if (request_irq(virq, iic_ipi_action, IRQF_DISABLED,
+- rname, (void *)(long)ipi))
+- printk(KERN_ERR
+- "iic: failed to request IPI %s on node %d\n",
+- name, node);
++ virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
++ if (virq == NO_IRQ) {
++ printk(KERN_ERR
++ "iic: failed to map IPI %s\n", name);
++ return;
+ }
++ if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
++ (void *)(long)ipi))
++ printk(KERN_ERR
++ "iic: failed to request IPI %s\n", name);
+ }
+
+ void iic_request_IPIs(void)
+@@ -193,16 +227,24 @@ void iic_request_IPIs(void)
+
+ static int iic_host_match(struct irq_host *h, struct device_node *node)
+ {
+- return h->host_data != NULL && node == h->host_data;
++ return device_is_compatible(node,
++ "IBM,CBEA-Internal-Interrupt-Controller");
+ }
+
+ static int iic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+ {
+- if (hw < IIC_IRQ_IPI0)
+- set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+- else
++ switch (hw & IIC_IRQ_TYPE_MASK) {
++ case IIC_IRQ_TYPE_IPI:
+ set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq);
++ break;
++ case IIC_IRQ_TYPE_IOEXC:
++ set_irq_chip_and_handler(virq, &iic_ioexc_chip,
++ handle_fasteoi_irq);
++ break;
++ default:
++ set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
++ }
+ return 0;
+ }
+
+@@ -211,11 +253,39 @@ static int iic_host_xlate(struct irq_hos
+ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+
+ {
+- /* Currently, we don't translate anything. That needs to be fixed as
+- * we get better defined device-trees. iic interrupts have to be
+- * explicitely mapped by whoever needs them
+- */
+- return -ENODEV;
++ unsigned int node, ext, unit, class;
++ const u32 *val;
++
++ if (!device_is_compatible(ct,
++ "IBM,CBEA-Internal-Interrupt-Controller"))
++ return -ENODEV;
++ if (intsize != 1)
++ return -ENODEV;
++ val = get_property(ct, "#interrupt-cells", NULL);
++ if (val == NULL || *val != 1)
++ return -ENODEV;
++
++ node = intspec[0] >> 24;
++ ext = (intspec[0] >> 16) & 0xff;
++ class = (intspec[0] >> 8) & 0xff;
++ unit = intspec[0] & 0xff;
++
++ /* Check if node is in supported range */
++ if (node > 1)
++ return -EINVAL;
++
++ /* Build up interrupt number, special case for IO exceptions */
++ *out_hwirq = (node << IIC_IRQ_NODE_SHIFT);
++ if (unit == IIC_UNIT_IIC && class == 1)
++ *out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext;
++ else
++ *out_hwirq |= IIC_IRQ_TYPE_NORMAL |
++ (class << IIC_IRQ_CLASS_SHIFT) | unit;
++
++ /* Dummy flags, ignored by iic code */
++ *out_flags = IRQ_TYPE_EDGE_RISING;
++
++ return 0;
+ }
+
+ static struct irq_host_ops iic_host_ops = {
+@@ -225,7 +295,7 @@ static struct irq_host_ops iic_host_ops
+ };
+
+ static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
+- struct irq_host *host)
++ struct device_node *node)
+ {
+ /* XXX FIXME: should locate the linux CPU number from the HW cpu
+ * number properly. We are lucky for now
+@@ -237,29 +307,28 @@ static void __init init_one_iic(unsigned
+
+ iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe);
+ iic->eoi_stack[0] = 0xff;
+- iic->host = host;
++ iic->node = of_node_get(node);
+ out_be64(&iic->regs->prio, 0);
+
+- printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n",
+- hw_cpu, addr, iic->regs, iic->target_id);
++ printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n",
++ hw_cpu, iic->target_id, node->full_name);
+ }
+
+ static int __init setup_iic(void)
+ {
+ struct device_node *dn;
+ struct resource r0, r1;
+- struct irq_host *host;
+- int found = 0;
+- u32 *np;
++ unsigned int node, cascade, found = 0;
++ struct cbe_iic_regs __iomem *node_iic;
++ const u32 *np;
+
+ for (dn = NULL;
+ (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
+ if (!device_is_compatible(dn,
+ "IBM,CBEA-Internal-Interrupt-Controller"))
+ continue;
+- np = (u32 *)get_property(dn, "ibm,interrupt-server-ranges",
+- NULL);
+- if (np == NULL) {
++ np = get_property(dn, "ibm,interrupt-server-ranges", NULL);
++ if (np == NULL) {
+ printk(KERN_WARNING "IIC: CPU association not found\n");
+ of_node_put(dn);
+ return -ENODEV;
+@@ -270,19 +339,37 @@ static int __init setup_iic(void)
+ of_node_put(dn);
+ return -ENODEV;
+ }
+- host = NULL;
+- if (found < IIC_NODE_COUNT) {
+- host = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
+- IIC_SOURCE_COUNT,
+- &iic_host_ops,
+- IIC_IRQ_INVALID);
+- iic_hosts[found] = host;
+- BUG_ON(iic_hosts[found] == NULL);
+- iic_hosts[found]->host_data = of_node_get(dn);
+- found++;
+- }
+- init_one_iic(np[0], r0.start, host);
+- init_one_iic(np[1], r1.start, host);
++ found++;
++ init_one_iic(np[0], r0.start, dn);
++ init_one_iic(np[1], r1.start, dn);
++
++ /* Setup cascade for IO exceptions. XXX cleanup tricks to get
++ * node vs CPU etc...
++ * Note that we configure the IIC_IRR here with a hard coded
++ * priority of 1. We might want to improve that later.
++ */
++ node = np[0] >> 1;
++ node_iic = cbe_get_cpu_iic_regs(np[0]);
++ cascade = node << IIC_IRQ_NODE_SHIFT;
++ cascade |= 1 << IIC_IRQ_CLASS_SHIFT;
++ cascade |= IIC_UNIT_IIC;
++ cascade = irq_create_mapping(iic_host, cascade);
++ if (cascade == NO_IRQ)
++ continue;
++ /*
++ * irq_data is a generic pointer that gets passed back
++ * to us later, so the forced cast is fine.
++ */
++ set_irq_data(cascade, (void __force *)node_iic);
++ set_irq_chained_handler(cascade , iic_ioexc_cascade);
++ out_be64(&node_iic->iic_ir,
++ (1 << 12) /* priority */ |
++ (node << 4) /* dest node */ |
++ IIC_UNIT_THREAD_0 /* route them to thread 0 */);
++ /* Flush pending (make sure it triggers if there is
++ * anything pending
++ */
++ out_be64(&node_iic->iic_is, 0xfffffffffffffffful);
+ }
+
+ if (found)
+@@ -293,6 +380,12 @@ static int __init setup_iic(void)
+
+ void __init iic_init_IRQ(void)
+ {
++ /* Setup an irq host data structure */
++ iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
++ &iic_host_ops, IIC_IRQ_INVALID);
++ BUG_ON(iic_host == NULL);
++ irq_set_default_host(iic_host);
++
+ /* Discover and initialize iics */
+ if (setup_iic() < 0)
+ panic("IIC: Failed to initialize !\n");
+diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
+index 5560a92..9ba1d3c 100644
+--- a/arch/powerpc/platforms/cell/interrupt.h
++++ b/arch/powerpc/platforms/cell/interrupt.h
+@@ -2,48 +2,76 @@
+ #define ASM_CELL_PIC_H
+ #ifdef __KERNEL__
+ /*
+- * Mapping of IIC pending bits into per-node
+- * interrupt numbers.
++ * Mapping of IIC pending bits into per-node interrupt numbers.
+ *
+- * IRQ FF CC SS PP FF CC SS PP Description
++ * Interrupt numbers are in the range 0...0x1ff where the top bit
++ * (0x100) represent the source node. Only 2 nodes are supported with
++ * the current code though it's trivial to extend that if necessary using
++ * higher level bits
+ *
+- * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge
+- * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge
+- * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0
+- * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1
+- * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2
+- * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI
++ * The bottom 8 bits are split into 2 type bits and 6 data bits that
++ * depend on the type:
+ *
+- * F flags
+- * C class
+- * S source
+- * P Priority
+- * + node number
+- * * don't care
++ * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source
++ * 01 (0x40 | data) : IO exception. data is the exception number as
++ * defined by bit numbers in IIC_SR
++ * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority)
++ * and node is always 0 (IPIs are per-cpu, their source is
++ * not relevant)
++ * 11 (0xc0 | data) : reserved
+ *
+- * A node consists of a Cell Broadband Engine and an optional
+- * south bridge device providing a maximum of 64 IRQs.
+- * The south bridge may be connected to either IOIF0
+- * or IOIF1.
+- * Each SPE is represented as three IRQ lines, one per
+- * interrupt class.
+- * 16 IRQ numbers are reserved for inter processor
+- * interruptions, although these are only used in the
+- * range of the first node.
++ * In addition, interrupt number 0x80000000 is defined as always invalid
++ * (that is the node field is expected to never extend to move than 23 bits)
+ *
+- * This scheme needs 128 IRQ numbers per BIF node ID,
+- * which means that with the total of 512 lines
+- * available, we can have a maximum of four nodes.
+ */
+
+ enum {
+- IIC_IRQ_INVALID = 0xff,
+- IIC_IRQ_MAX = 0x3f,
+- IIC_IRQ_EXT_IOIF0 = 0x20,
+- IIC_IRQ_EXT_IOIF1 = 0x2b,
+- IIC_IRQ_IPI0 = 0x40,
+- IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */
+- IIC_SOURCE_COUNT = 0x50,
++ IIC_IRQ_INVALID = 0x80000000u,
++ IIC_IRQ_NODE_MASK = 0x100,
++ IIC_IRQ_NODE_SHIFT = 8,
++ IIC_IRQ_MAX = 0x1ff,
++ IIC_IRQ_TYPE_MASK = 0xc0,
++ IIC_IRQ_TYPE_NORMAL = 0x00,
++ IIC_IRQ_TYPE_IOEXC = 0x40,
++ IIC_IRQ_TYPE_IPI = 0x80,
++ IIC_IRQ_CLASS_SHIFT = 4,
++ IIC_IRQ_CLASS_0 = 0x00,
++ IIC_IRQ_CLASS_1 = 0x10,
++ IIC_IRQ_CLASS_2 = 0x20,
++ IIC_SOURCE_COUNT = 0x200,
++
++ /* Here are defined the various source/dest units. Avoid using those
++ * definitions if you can, they are mostly here for reference
++ */
++ IIC_UNIT_SPU_0 = 0x4,
++ IIC_UNIT_SPU_1 = 0x7,
++ IIC_UNIT_SPU_2 = 0x3,
++ IIC_UNIT_SPU_3 = 0x8,
++ IIC_UNIT_SPU_4 = 0x2,
++ IIC_UNIT_SPU_5 = 0x9,
++ IIC_UNIT_SPU_6 = 0x1,
++ IIC_UNIT_SPU_7 = 0xa,
++ IIC_UNIT_IOC_0 = 0x0,
++ IIC_UNIT_IOC_1 = 0xb,
++ IIC_UNIT_THREAD_0 = 0xe, /* target only */
++ IIC_UNIT_THREAD_1 = 0xf, /* target only */
++ IIC_UNIT_IIC = 0xe, /* source only (IO exceptions) */
++
++ /* Base numbers for the external interrupts */
++ IIC_IRQ_EXT_IOIF0 =
++ IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0,
++ IIC_IRQ_EXT_IOIF1 =
++ IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1,
++
++ /* Base numbers for the IIC_ISR interrupts */
++ IIC_IRQ_IOEX_TMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63,
++ IIC_IRQ_IOEX_PMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62,
++ IIC_IRQ_IOEX_ATI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61,
++ IIC_IRQ_IOEX_MATBFI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60,
++ IIC_IRQ_IOEX_ELDI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59,
++
++ /* Which bits in IIC_ISR are edge sensitive */
++ IIC_ISR_EDGE_MASK = 0x4ul,
+ };
+
+ extern void iic_init_IRQ(void);
+@@ -52,7 +80,6 @@ extern void iic_request_IPIs(void);
+ extern void iic_setup_cpu(void);
+
+ extern u8 iic_get_target_id(int cpu);
+-extern struct irq_host *iic_get_irq_host(int node);
+
+ extern void spider_init_IRQ(void);
+
+diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
+index a35004e..aca4c3d 100644
+--- a/arch/powerpc/platforms/cell/iommu.c
++++ b/arch/powerpc/platforms/cell/iommu.c
+@@ -308,15 +308,16 @@ static void cell_do_map_iommu(struct cel
+
+ static void iommu_devnode_setup(struct device_node *d)
+ {
+- unsigned int *ioid;
+- unsigned long *dma_window, map_start, map_size, token;
++ const unsigned int *ioid;
++ unsigned long map_start, map_size, token;
++ const unsigned long *dma_window;
+ struct cell_iommu *iommu;
+
+- ioid = (unsigned int *)get_property(d, "ioid", NULL);
++ ioid = get_property(d, "ioid", NULL);
+ if (!ioid)
+ pr_debug("No ioid entry found !\n");
+
+- dma_window = (unsigned long *)get_property(d, "ibm,dma-window", NULL);
++ dma_window = get_property(d, "ibm,dma-window", NULL);
+ if (!dma_window)
+ pr_debug("No ibm,dma-window entry found !\n");
+
+@@ -344,8 +345,8 @@ static int cell_map_iommu_hardcoded(int
+
+ /* node 0 */
+ iommu = &cell_iommus[0];
+- iommu->mapped_base = ioremap(0x20000511000, 0x1000);
+- iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000);
++ iommu->mapped_base = ioremap(0x20000511000ul, 0x1000);
++ iommu->mapped_mmio_base = ioremap(0x20000510000ul, 0x1000);
+
+ enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+@@ -357,8 +358,8 @@ static int cell_map_iommu_hardcoded(int
+
+ /* node 1 */
+ iommu = &cell_iommus[1];
+- iommu->mapped_base = ioremap(0x30000511000, 0x1000);
+- iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000);
++ iommu->mapped_base = ioremap(0x30000511000ul, 0x1000);
++ iommu->mapped_mmio_base = ioremap(0x30000510000ul, 0x1000);
+
+ enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+@@ -371,8 +372,9 @@ static int cell_map_iommu_hardcoded(int
+
+ static int cell_map_iommu(void)
+ {
+- unsigned int num_nodes = 0, *node_id;
+- unsigned long *base, *mmio_base;
++ unsigned int num_nodes = 0;
++ const unsigned int *node_id;
++ const unsigned long *base, *mmio_base;
+ struct device_node *dn;
+ struct cell_iommu *iommu = NULL;
+
+@@ -381,7 +383,7 @@ static int cell_map_iommu(void)
+ for(dn = of_find_node_by_type(NULL, "cpu");
+ dn;
+ dn = of_find_node_by_type(dn, "cpu")) {
+- node_id = (unsigned int *)get_property(dn, "node-id", NULL);
++ node_id = get_property(dn, "node-id", NULL);
+
+ if (num_nodes < *node_id)
+ num_nodes = *node_id;
+@@ -396,9 +398,9 @@ static int cell_map_iommu(void)
+ dn;
+ dn = of_find_node_by_type(dn, "cpu")) {
+
+- node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+- base = (unsigned long *)get_property(dn, "ioc-cache", NULL);
+- mmio_base = (unsigned long *)get_property(dn, "ioc-translation", NULL);
++ node_id = get_property(dn, "node-id", NULL);
++ base = get_property(dn, "ioc-cache", NULL);
++ mmio_base = get_property(dn, "ioc-translation", NULL);
+
+ if (!base || !mmio_base || !node_id)
+ return cell_map_iommu_hardcoded(num_nodes);
+diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
+index 033ad6e..0984c70 100644
+--- a/arch/powerpc/platforms/cell/ras.c
++++ b/arch/powerpc/platforms/cell/ras.c
+@@ -1,6 +1,5 @@
+ #define DEBUG
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/smp.h>
+diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
+index 282987d..22c228a 100644
+--- a/arch/powerpc/platforms/cell/setup.c
++++ b/arch/powerpc/platforms/cell/setup.c
+@@ -150,10 +150,6 @@ static int __init cell_probe(void)
+ !of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
+ return 0;
+
+-#ifdef CONFIG_UDBG_RTAS_CONSOLE
+- udbg_init_rtas_console();
+-#endif
+-
+ hpte_init_native();
+
+ return 1;
+diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
+index 46aef06..1c0acba 100644
+--- a/arch/powerpc/platforms/cell/smp.c
++++ b/arch/powerpc/platforms/cell/smp.c
+@@ -57,7 +57,7 @@
+ */
+ static cpumask_t of_spin_map;
+
+-extern void pSeries_secondary_smp_init(unsigned long);
++extern void generic_secondary_smp_init(unsigned long);
+
+ /**
+ * smp_startup_cpu() - start the given cpu
+@@ -74,7 +74,7 @@ static inline int __devinit smp_startup_
+ {
+ int status;
+ unsigned long start_here = __pa((u32)*((unsigned long *)
+- pSeries_secondary_smp_init));
++ generic_secondary_smp_init));
+ unsigned int pcpu;
+ int start_cpu;
+
+diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
+index 15217bb..21a9ebd 100644
+--- a/arch/powerpc/platforms/cell/spider-pic.c
++++ b/arch/powerpc/platforms/cell/spider-pic.c
+@@ -213,8 +213,7 @@ static struct irq_host_ops spider_host_o
+ .xlate = spider_host_xlate,
+ };
+
+-static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+ struct spider_pic *pic = desc->handler_data;
+ unsigned int cs, virq;
+@@ -225,7 +224,7 @@ static void spider_irq_cascade(unsigned
+ else
+ virq = irq_linear_revmap(pic->host, cs);
+ if (virq != NO_IRQ)
+- generic_handle_irq(virq, regs);
++ generic_handle_irq(virq);
+ desc->chip->eoi(irq);
+ }
+
+@@ -240,12 +239,10 @@ static void spider_irq_cascade(unsigned
+ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
+ {
+ unsigned int virq;
+- u32 *imap, *tmp;
++ const u32 *imap, *tmp;
+ int imaplen, intsize, unit;
+ struct device_node *iic;
+- struct irq_host *iic_host;
+
+-#if 0 /* Enable that when we have a way to retreive the node as well */
+ /* First, we check wether we have a real "interrupts" in the device
+ * tree in case the device-tree is ever fixed
+ */
+@@ -253,30 +250,29 @@ static unsigned int __init spider_find_c
+ if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) {
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+- goto bail;
++ return virq;
+ }
+-#endif
+
+ /* Now do the horrible hacks */
+- tmp = (u32 *)get_property(pic->of_node, "#interrupt-cells", NULL);
++ tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
+ if (tmp == NULL)
+ return NO_IRQ;
+ intsize = *tmp;
+- imap = (u32 *)get_property(pic->of_node, "interrupt-map", &imaplen);
++ imap = get_property(pic->of_node, "interrupt-map", &imaplen);
+ if (imap == NULL || imaplen < (intsize + 1))
+ return NO_IRQ;
+ iic = of_find_node_by_phandle(imap[intsize]);
+ if (iic == NULL)
+ return NO_IRQ;
+ imap += intsize + 1;
+- tmp = (u32 *)get_property(iic, "#interrupt-cells", NULL);
++ tmp = get_property(iic, "#interrupt-cells", NULL);
+ if (tmp == NULL)
+ return NO_IRQ;
+ intsize = *tmp;
+ /* Assume unit is last entry of interrupt specifier */
+ unit = imap[intsize - 1];
+ /* Ok, we have a unit, now let's try to get the node */
+- tmp = (u32 *)get_property(iic, "ibm,interrupt-server-ranges", NULL);
++ tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL);
+ if (tmp == NULL) {
+ of_node_put(iic);
+ return NO_IRQ;
+@@ -289,11 +285,11 @@ static unsigned int __init spider_find_c
+ * the iic host from the iic OF node, but that way I'm still compatible
+ * with really really old old firmwares for which we don't have a node
+ */
+- iic_host = iic_get_irq_host(pic->node_id);
+- if (iic_host == NULL)
+- return NO_IRQ;
+ /* Manufacture an IIC interrupt number of class 2 */
+- virq = irq_create_mapping(iic_host, 0x20 | unit);
++ virq = irq_create_mapping(NULL,
++ (pic->node_id << IIC_IRQ_NODE_SHIFT) |
++ (2 << IIC_IRQ_CLASS_SHIFT) |
++ unit);
+ if (virq == NO_IRQ)
+ printk(KERN_ERR "spider_pic: failed to map cascade !");
+ return virq;
+@@ -370,7 +366,7 @@ void __init spider_init_IRQ(void)
+ } else if (device_is_compatible(dn, "sti,platform-spider-pic")
+ && (chip < 2)) {
+ static long hard_coded_pics[] =
+- { 0x24000008000, 0x34000008000 };
++ { 0x24000008000ul, 0x34000008000ul};
+ r.start = hard_coded_pics[chip];
+ } else
+ continue;
+diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
+index d06042d..d0fb959 100644
+--- a/arch/powerpc/platforms/cell/spu_base.c
++++ b/arch/powerpc/platforms/cell/spu_base.c
+@@ -25,11 +25,13 @@
+ #include <linux/interrupt.h>
+ #include <linux/list.h>
+ #include <linux/module.h>
++#include <linux/pci.h>
+ #include <linux/poll.h>
+ #include <linux/ptrace.h>
+ #include <linux/slab.h>
+ #include <linux/wait.h>
+
++#include <asm/firmware.h>
+ #include <asm/io.h>
+ #include <asm/prom.h>
+ #include <linux/mutex.h>
+@@ -46,21 +48,21 @@ EXPORT_SYMBOL_GPL(spu_priv1_ops);
+ static int __spu_trap_invalid_dma(struct spu *spu)
+ {
+ pr_debug("%s\n", __FUNCTION__);
+- force_sig(SIGBUS, /* info, */ current);
++ spu->dma_callback(spu, SPE_EVENT_INVALID_DMA);
+ return 0;
+ }
+
+ static int __spu_trap_dma_align(struct spu *spu)
+ {
+ pr_debug("%s\n", __FUNCTION__);
+- force_sig(SIGBUS, /* info, */ current);
++ spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT);
+ return 0;
+ }
+
+ static int __spu_trap_error(struct spu *spu)
+ {
+ pr_debug("%s\n", __FUNCTION__);
+- force_sig(SIGILL, /* info, */ current);
++ spu->dma_callback(spu, SPE_EVENT_SPE_ERROR);
+ return 0;
+ }
+
+@@ -145,7 +147,7 @@ static int __spu_trap_data_map(struct sp
+ }
+
+ static irqreturn_t
+-spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
++spu_irq_class_0(int irq, void *data)
+ {
+ struct spu *spu;
+
+@@ -184,7 +186,7 @@ spu_irq_class_0_bottom(struct spu *spu)
+ EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
+
+ static irqreturn_t
+-spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
++spu_irq_class_1(int irq, void *data)
+ {
+ struct spu *spu;
+ unsigned long stat, mask, dar, dsisr;
+@@ -222,7 +224,7 @@ spu_irq_class_1(int irq, void *data, str
+ EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
+
+ static irqreturn_t
+-spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
++spu_irq_class_2(int irq, void *data)
+ {
+ struct spu *spu;
+ unsigned long stat;
+@@ -317,7 +319,7 @@ static void spu_free_irqs(struct spu *sp
+ free_irq(spu->irqs[2], spu);
+ }
+
+-static LIST_HEAD(spu_list);
++static struct list_head spu_list[MAX_NUMNODES];
+ static DEFINE_MUTEX(spu_mutex);
+
+ static void spu_init_channels(struct spu *spu)
+@@ -354,32 +356,42 @@ static void spu_init_channels(struct spu
+ }
+ }
+
+-struct spu *spu_alloc(void)
++struct spu *spu_alloc_node(int node)
+ {
+- struct spu *spu;
++ struct spu *spu = NULL;
+
+ mutex_lock(&spu_mutex);
+- if (!list_empty(&spu_list)) {
+- spu = list_entry(spu_list.next, struct spu, list);
++ if (!list_empty(&spu_list[node])) {
++ spu = list_entry(spu_list[node].next, struct spu, list);
+ list_del_init(&spu->list);
+- pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);
+- } else {
+- pr_debug("No SPU left\n");
+- spu = NULL;
++ pr_debug("Got SPU %x %d %d\n",
++ spu->isrc, spu->number, spu->node);
++ spu_init_channels(spu);
+ }
+ mutex_unlock(&spu_mutex);
+
+- if (spu)
+- spu_init_channels(spu);
++ return spu;
++}
++EXPORT_SYMBOL_GPL(spu_alloc_node);
++
++struct spu *spu_alloc(void)
++{
++ struct spu *spu = NULL;
++ int node;
++
++ for (node = 0; node < MAX_NUMNODES; node++) {
++ spu = spu_alloc_node(node);
++ if (spu)
++ break;
++ }
+
+ return spu;
+ }
+-EXPORT_SYMBOL_GPL(spu_alloc);
+
+ void spu_free(struct spu *spu)
+ {
+ mutex_lock(&spu_mutex);
+- list_add_tail(&spu->list, &spu_list);
++ list_add_tail(&spu->list, &spu_list[spu->node]);
+ mutex_unlock(&spu_mutex);
+ }
+ EXPORT_SYMBOL_GPL(spu_free);
+@@ -488,10 +500,10 @@ int spu_irq_class_1_bottom(struct spu *s
+
+ static int __init find_spu_node_id(struct device_node *spe)
+ {
+- unsigned int *id;
++ const unsigned int *id;
+ struct device_node *cpu;
+ cpu = spe->parent->parent;
+- id = (unsigned int *)get_property(cpu, "node-id", NULL);
++ id = get_property(cpu, "node-id", NULL);
+ return id ? *id : 0;
+ }
+
+@@ -500,7 +512,7 @@ static int __init cell_spuprop_present(s
+ {
+ static DEFINE_MUTEX(add_spumem_mutex);
+
+- struct address_prop {
++ const struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *p;
+@@ -511,7 +523,7 @@ static int __init cell_spuprop_present(s
+ struct zone *zone;
+ int ret;
+
+- p = (void*)get_property(spe, prop, &proplen);
++ p = get_property(spe, prop, &proplen);
+ WARN_ON(proplen != sizeof (*p));
+
+ start_pfn = p->address >> PAGE_SHIFT;
+@@ -531,14 +543,14 @@ static int __init cell_spuprop_present(s
+ static void __iomem * __init map_spe_prop(struct spu *spu,
+ struct device_node *n, const char *name)
+ {
+- struct address_prop {
++ const struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *prop;
+
+- void *p;
++ const void *p;
+ int proplen;
+- void* ret = NULL;
++ void __iomem *ret = NULL;
+ int err = 0;
+
+ p = get_property(n, name, &proplen);
+@@ -562,38 +574,37 @@ static void spu_unmap(struct spu *spu)
+ iounmap(spu->priv2);
+ iounmap(spu->priv1);
+ iounmap(spu->problem);
+- iounmap((u8 __iomem *)spu->local_store);
++ iounmap((__force u8 __iomem *)spu->local_store);
+ }
+
+ /* This function shall be abstracted for HV platforms */
+-static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
++static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np)
+ {
+- struct irq_host *host;
+ unsigned int isrc;
+- u32 *tmp;
+-
+- host = iic_get_irq_host(spu->node);
+- if (host == NULL)
+- return -ENODEV;
++ const u32 *tmp;
+
+- /* Get the interrupt source from the device-tree */
+- tmp = (u32 *)get_property(np, "isrc", NULL);
++ /* Get the interrupt source unit from the device-tree */
++ tmp = get_property(np, "isrc", NULL);
+ if (!tmp)
+ return -ENODEV;
+- spu->isrc = isrc = tmp[0];
++ isrc = tmp[0];
++
++ /* Add the node number */
++ isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
++ spu->isrc = isrc;
+
+ /* Now map interrupts of all 3 classes */
+- spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc);
+- spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc);
+- spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc);
++ spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
++ spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
++ spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
+
+ /* Right now, we only fail if class 2 failed */
+ return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
+ }
+
+-static int __init spu_map_device(struct spu *spu, struct device_node *node)
++static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
+ {
+- char *prop;
++ const char *prop;
+ int ret;
+
+ ret = -ENODEV;
+@@ -636,6 +647,88 @@ out:
+ return ret;
+ }
+
++static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
++{
++ struct of_irq oirq;
++ int ret;
++ int i;
++
++ for (i=0; i < 3; i++) {
++ ret = of_irq_map_one(np, i, &oirq);
++ if (ret)
++ goto err;
++
++ ret = -EINVAL;
++ spu->irqs[i] = irq_create_of_mapping(oirq.controller,
++ oirq.specifier, oirq.size);
++ if (spu->irqs[i] == NO_IRQ)
++ goto err;
++ }
++ return 0;
++
++err:
++ pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, spu->name);
++ for (; i >= 0; i--) {
++ if (spu->irqs[i] != NO_IRQ)
++ irq_dispose_mapping(spu->irqs[i]);
++ }
++ return ret;
++}
++
++static int spu_map_resource(struct device_node *node, int nr,
++ void __iomem** virt, unsigned long *phys)
++{
++ struct resource resource = { };
++ int ret;
++
++ ret = of_address_to_resource(node, 0, &resource);
++ if (ret)
++ goto out;
++
++ if (phys)
++ *phys = resource.start;
++ *virt = ioremap(resource.start, resource.end - resource.start);
++ if (!*virt)
++ ret = -EINVAL;
++
++out:
++ return ret;
++}
++
++static int __init spu_map_device(struct spu *spu, struct device_node *node)
++{
++ int ret = -ENODEV;
++ spu->name = get_property(node, "name", NULL);
++ if (!spu->name)
++ goto out;
++
++ ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
++ &spu->local_store_phys);
++ if (ret)
++ goto out;
++ ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
++ &spu->problem_phys);
++ if (ret)
++ goto out_unmap;
++ ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
++ NULL);
++ if (ret)
++ goto out_unmap;
++
++ if (!firmware_has_feature(FW_FEATURE_LPAR))
++ ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1,
++ NULL);
++ if (ret)
++ goto out_unmap;
++ return 0;
++
++out_unmap:
++ spu_unmap(spu);
++out:
++ pr_debug("failed to map spe %s: %d\n", spu->name, ret);
++ return ret;
++}
++
+ struct sysdev_class spu_sysdev_class = {
+ set_kset_name("spu")
+ };
+@@ -688,16 +781,28 @@ static int __init create_spu(struct devi
+ if (!spu)
+ goto out;
+
+- ret = spu_map_device(spu, spe);
+- if (ret)
+- goto out_free;
+-
+ spu->node = find_spu_node_id(spe);
++ if (spu->node >= MAX_NUMNODES) {
++ printk(KERN_WARNING "SPE %s on node %d ignored,"
++ " node number too big\n", spe->full_name, spu->node);
++ printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
++ return -ENODEV;
++ }
+ spu->nid = of_node_to_nid(spe);
+ if (spu->nid == -1)
+ spu->nid = 0;
++
++ ret = spu_map_device(spu, spe);
++ /* try old method */
++ if (ret)
++ ret = spu_map_device_old(spu, spe);
++ if (ret)
++ goto out_free;
++
+ ret = spu_map_interrupts(spu, spe);
+ if (ret)
++ ret = spu_map_interrupts_old(spu, spe);
++ if (ret)
+ goto out_unmap;
+ spin_lock_init(&spu->register_lock);
+ spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+@@ -707,13 +812,13 @@ static int __init create_spu(struct devi
+ spu->number = number++;
+ ret = spu_request_irqs(spu);
+ if (ret)
+- goto out_unmap;
++ goto out_unlock;
+
+ ret = spu_create_sysdev(spu);
+ if (ret)
+ goto out_free_irqs;
+
+- list_add(&spu->list, &spu_list);
++ list_add(&spu->list, &spu_list[spu->node]);
+ mutex_unlock(&spu_mutex);
+
+ pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
+@@ -723,9 +828,9 @@ static int __init create_spu(struct devi
+
+ out_free_irqs:
+ spu_free_irqs(spu);
+-
+-out_unmap:
++out_unlock:
+ mutex_unlock(&spu_mutex);
++out_unmap:
+ spu_unmap(spu);
+ out_free:
+ kfree(spu);
+@@ -746,9 +851,13 @@ static void destroy_spu(struct spu *spu)
+ static void cleanup_spu_base(void)
+ {
+ struct spu *spu, *tmp;
++ int node;
++
+ mutex_lock(&spu_mutex);
+- list_for_each_entry_safe(spu, tmp, &spu_list, list)
+- destroy_spu(spu);
++ for (node = 0; node < MAX_NUMNODES; node++) {
++ list_for_each_entry_safe(spu, tmp, &spu_list[node], list)
++ destroy_spu(spu);
++ }
+ mutex_unlock(&spu_mutex);
+ sysdev_class_unregister(&spu_sysdev_class);
+ }
+@@ -757,13 +866,16 @@ module_exit(cleanup_spu_base);
+ static int __init init_spu_base(void)
+ {
+ struct device_node *node;
+- int ret;
++ int i, ret;
+
+ /* create sysdev class for spus */
+ ret = sysdev_class_register(&spu_sysdev_class);
+ if (ret)
+ return ret;
+
++ for (i = 0; i < MAX_NUMNODES; i++)
++ INIT_LIST_HEAD(&spu_list[i]);
++
+ ret = -ENODEV;
+ for (node = of_find_node_by_type(NULL, "spe");
+ node; node = of_find_node_by_type(node, "spe")) {
+@@ -775,18 +887,6 @@ static int __init init_spu_base(void)
+ break;
+ }
+ }
+- /* in some old firmware versions, the spe is called 'spc', so we
+- look for that as well */
+- for (node = of_find_node_by_type(NULL, "spc");
+- node; node = of_find_node_by_type(node, "spc")) {
+- ret = create_spu(node);
+- if (ret) {
+- printk(KERN_WARNING "%s: Error initializing %s\n",
+- __FUNCTION__, node->name);
+- cleanup_spu_base();
+- break;
+- }
+- }
+ return ret;
+ }
+ module_init(init_spu_base);
+diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
+index bb5dc63..ecdfbb3 100644
+--- a/arch/powerpc/platforms/cell/spufs/Makefile
++++ b/arch/powerpc/platforms/cell/spufs/Makefile
+@@ -2,7 +2,7 @@ obj-y += switch.o
+
+ obj-$(CONFIG_SPU_FS) += spufs.o
+ spufs-y += inode.o file.o context.o syscalls.o
+-spufs-y += sched.o backing_ops.o hw_ops.o run.o
++spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
+
+ # Rules to build switch.o with the help of SPU tool chain
+ SPU_CROSS := spu-
+diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
+index 36439c5..034cf6a 100644
+--- a/arch/powerpc/platforms/cell/spufs/context.c
++++ b/arch/powerpc/platforms/cell/spufs/context.c
+@@ -27,7 +27,7 @@
+ #include <asm/spu_csa.h>
+ #include "spufs.h"
+
+-struct spu_context *alloc_spu_context(void)
++struct spu_context *alloc_spu_context(struct spu_gang *gang)
+ {
+ struct spu_context *ctx;
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+@@ -51,6 +51,8 @@ struct spu_context *alloc_spu_context(vo
+ ctx->state = SPU_STATE_SAVED;
+ ctx->ops = &spu_backing_ops;
+ ctx->owner = get_task_mm(current);
++ if (gang)
++ spu_gang_add_ctx(gang, ctx);
+ goto out;
+ out_free:
+ kfree(ctx);
+@@ -67,6 +69,8 @@ void destroy_spu_context(struct kref *kr
+ spu_deactivate(ctx);
+ up_write(&ctx->state_sema);
+ spu_fini_csa(&ctx->csa);
++ if (ctx->gang)
++ spu_gang_remove_ctx(ctx->gang, ctx);
+ kfree(ctx);
+ }
+
+diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
+index 58e794f..533e272 100644
+--- a/arch/powerpc/platforms/cell/spufs/file.c
++++ b/arch/powerpc/platforms/cell/spufs/file.c
+@@ -36,6 +36,8 @@
+
+ #include "spufs.h"
+
++#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
++
+
+ static int
+ spufs_mem_open(struct inode *inode, struct file *file)
+@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const
+ return ret;
+ }
+
+-#ifdef CONFIG_SPUFS_MMAP
+ static struct page *
+ spufs_mem_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+@@ -101,12 +102,16 @@ spufs_mem_mmap_nopage(struct vm_area_str
+
+ spu_acquire(ctx);
+
+- if (ctx->state == SPU_STATE_SAVED)
++ if (ctx->state == SPU_STATE_SAVED) {
++ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
++ & ~(_PAGE_NO_CACHE | _PAGE_GUARDED));
+ page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
+- else
++ } else {
++ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
++ | _PAGE_NO_CACHE | _PAGE_GUARDED);
+ page = pfn_to_page((ctx->spu->local_store_phys + offset)
+ >> PAGE_SHIFT);
+-
++ }
+ spu_release(ctx);
+
+ if (type)
+@@ -133,22 +138,19 @@ spufs_mem_mmap(struct file *file, struct
+ vma->vm_ops = &spufs_mem_mmap_vmops;
+ return 0;
+ }
+-#endif
+
+ static struct file_operations spufs_mem_fops = {
+ .open = spufs_mem_open,
+ .read = spufs_mem_read,
+ .write = spufs_mem_write,
+ .llseek = generic_file_llseek,
+-#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_mem_mmap,
+-#endif
+ };
+
+-#ifdef CONFIG_SPUFS_MMAP
+ static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+- int *type, unsigned long ps_offs)
++ int *type, unsigned long ps_offs,
++ unsigned long ps_size)
+ {
+ struct page *page = NOPAGE_SIGBUS;
+ int fault_type = VM_FAULT_SIGBUS;
+@@ -158,7 +160,7 @@ static struct page *spufs_ps_nopage(stru
+ int ret;
+
+ offset += vma->vm_pgoff << PAGE_SHIFT;
+- if (offset >= 0x4000)
++ if (offset >= ps_size)
+ goto out;
+
+ ret = spu_acquire_runnable(ctx);
+@@ -179,10 +181,11 @@ static struct page *spufs_ps_nopage(stru
+ return page;
+ }
+
++#if SPUFS_MMAP_4K
+ static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+ {
+- return spufs_ps_nopage(vma, address, type, 0x4000);
++ return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000);
+ }
+
+ static struct vm_operations_struct spufs_cntl_mmap_vmops = {
+@@ -191,17 +194,12 @@ static struct vm_operations_struct spufs
+
+ /*
+ * mmap support for problem state control area [0x4000 - 0x4fff].
+- * Mapping this area requires that the application have CAP_SYS_RAWIO,
+- * as these registers require special care when read/writing.
+ */
+ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+- if (!capable(CAP_SYS_RAWIO))
+- return -EPERM;
+-
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE | _PAGE_GUARDED);
+@@ -209,42 +207,49 @@ static int spufs_cntl_mmap(struct file *
+ vma->vm_ops = &spufs_cntl_mmap_vmops;
+ return 0;
+ }
+-#endif
++#else /* SPUFS_MMAP_4K */
++#define spufs_cntl_mmap NULL
++#endif /* !SPUFS_MMAP_4K */
+
+-static int spufs_cntl_open(struct inode *inode, struct file *file)
++static u64 spufs_cntl_get(void *data)
+ {
+- struct spufs_inode_info *i = SPUFS_I(inode);
+- struct spu_context *ctx = i->i_ctx;
++ struct spu_context *ctx = data;
++ u64 val;
+
+- file->private_data = ctx;
+- file->f_mapping = inode->i_mapping;
+- ctx->cntl = inode->i_mapping;
+- return 0;
++ spu_acquire(ctx);
++ val = ctx->ops->status_read(ctx);
++ spu_release(ctx);
++
++ return val;
+ }
+
+-static ssize_t
+-spufs_cntl_read(struct file *file, char __user *buffer,
+- size_t size, loff_t *pos)
++static void spufs_cntl_set(void *data, u64 val)
+ {
+- /* FIXME: read from spu status */
+- return -EINVAL;
++ struct spu_context *ctx = data;
++
++ spu_acquire(ctx);
++ ctx->ops->runcntl_write(ctx, val);
++ spu_release(ctx);
+ }
+
+-static ssize_t
+-spufs_cntl_write(struct file *file, const char __user *buffer,
+- size_t size, loff_t *pos)
++static int spufs_cntl_open(struct inode *inode, struct file *file)
+ {
+- /* FIXME: write to runctl bit */
+- return -EINVAL;
++ struct spufs_inode_info *i = SPUFS_I(inode);
++ struct spu_context *ctx = i->i_ctx;
++
++ file->private_data = ctx;
++ file->f_mapping = inode->i_mapping;
++ ctx->cntl = inode->i_mapping;
++ return simple_attr_open(inode, file, spufs_cntl_get,
++ spufs_cntl_set, "0x%08lx");
+ }
+
+ static struct file_operations spufs_cntl_fops = {
+ .open = spufs_cntl_open,
+- .read = spufs_cntl_read,
+- .write = spufs_cntl_write,
+-#ifdef CONFIG_SPUFS_MMAP
++ .release = simple_attr_close,
++ .read = simple_attr_read,
++ .write = simple_attr_write,
+ .mmap = spufs_cntl_mmap,
+-#endif
+ };
+
+ static int
+@@ -356,27 +361,54 @@ static int spufs_pipe_open(struct inode
+ return nonseekable_open(inode, file);
+ }
+
++/*
++ * Read as many bytes from the mailbox as possible, until
++ * one of the conditions becomes true:
++ *
++ * - no more data available in the mailbox
++ * - end of the user provided buffer
++ * - end of the mapped area
++ */
+ static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+ {
+ struct spu_context *ctx = file->private_data;
+- u32 mbox_data;
+- int ret;
++ u32 mbox_data, __user *udata;
++ ssize_t count;
+
+ if (len < 4)
+ return -EINVAL;
+
++ if (!access_ok(VERIFY_WRITE, buf, len))
++ return -EFAULT;
++
++ udata = (void __user *)buf;
++
+ spu_acquire(ctx);
+- ret = ctx->ops->mbox_read(ctx, &mbox_data);
++ for (count = 0; (count + 4) <= len; count += 4, udata++) {
++ int ret;
++ ret = ctx->ops->mbox_read(ctx, &mbox_data);
++ if (ret == 0)
++ break;
++
++ /*
++ * at the end of the mapped area, we can fault
++ * but still need to return the data we have
++ * read successfully so far.
++ */
++ ret = __put_user(mbox_data, udata);
++ if (ret) {
++ if (!count)
++ count = -EFAULT;
++ break;
++ }
++ }
+ spu_release(ctx);
+
+- if (!ret)
+- return -EAGAIN;
+-
+- if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
+- return -EFAULT;
++ if (!count)
++ count = -EAGAIN;
+
+- return 4;
++ return count;
+ }
+
+ static struct file_operations spufs_mbox_fops = {
+@@ -432,36 +464,70 @@ void spufs_ibox_callback(struct spu *spu
+ kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
+ }
+
++/*
++ * Read as many bytes from the interrupt mailbox as possible, until
++ * one of the conditions becomes true:
++ *
++ * - no more data available in the mailbox
++ * - end of the user provided buffer
++ * - end of the mapped area
++ *
++ * If the file is opened without O_NONBLOCK, we wait here until
++ * any data is available, but return when we have been able to
++ * read something.
++ */
+ static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+ {
+ struct spu_context *ctx = file->private_data;
+- u32 ibox_data;
+- ssize_t ret;
++ u32 ibox_data, __user *udata;
++ ssize_t count;
+
+ if (len < 4)
+ return -EINVAL;
+
++ if (!access_ok(VERIFY_WRITE, buf, len))
++ return -EFAULT;
++
++ udata = (void __user *)buf;
++
+ spu_acquire(ctx);
+
+- ret = 0;
++ /* wait only for the first element */
++ count = 0;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!spu_ibox_read(ctx, &ibox_data))
+- ret = -EAGAIN;
++ count = -EAGAIN;
+ } else {
+- ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
++ count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
+ }
++ if (count)
++ goto out;
+
+- spu_release(ctx);
++ /* if we can't write at all, return -EFAULT */
++ count = __put_user(ibox_data, udata);
++ if (count)
++ goto out;
+
+- if (ret)
+- return ret;
++ for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
++ int ret;
++ ret = ctx->ops->ibox_read(ctx, &ibox_data);
++ if (ret == 0)
++ break;
++ /*
++ * at the end of the mapped area, we can fault
++ * but still need to return the data we have
++ * read successfully so far.
++ */
++ ret = __put_user(ibox_data, udata);
++ if (ret)
++ break;
++ }
+
+- ret = 4;
+- if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
+- ret = -EFAULT;
++out:
++ spu_release(ctx);
+
+- return ret;
++ return count;
+ }
+
+ static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
+@@ -534,32 +600,67 @@ void spufs_wbox_callback(struct spu *spu
+ kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
+ }
+
++/*
++ * Write as many bytes to the interrupt mailbox as possible, until
++ * one of the conditions becomes true:
++ *
++ * - the mailbox is full
++ * - end of the user provided buffer
++ * - end of the mapped area
++ *
++ * If the file is opened without O_NONBLOCK, we wait here until
++ * space is availabyl, but return when we have been able to
++ * write something.
++ */
+ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *pos)
+ {
+ struct spu_context *ctx = file->private_data;
+- u32 wbox_data;
+- int ret;
++ u32 wbox_data, __user *udata;
++ ssize_t count;
+
+ if (len < 4)
+ return -EINVAL;
+
+- if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
++ udata = (void __user *)buf;
++ if (!access_ok(VERIFY_READ, buf, len))
++ return -EFAULT;
++
++ if (__get_user(wbox_data, udata))
+ return -EFAULT;
+
+ spu_acquire(ctx);
+
+- ret = 0;
++ /*
++ * make sure we can at least write one element, by waiting
++ * in case of !O_NONBLOCK
++ */
++ count = 0;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!spu_wbox_write(ctx, wbox_data))
+- ret = -EAGAIN;
++ count = -EAGAIN;
+ } else {
+- ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
++ count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
+ }
+
+- spu_release(ctx);
++ if (count)
++ goto out;
++
++ /* write aÑ much as possible */
++ for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
++ int ret;
++ ret = __get_user(wbox_data, udata);
++ if (ret)
++ break;
++
++ ret = spu_wbox_write(ctx, wbox_data);
++ if (ret == 0)
++ break;
++ }
+
+- return ret ? ret : sizeof wbox_data;
++out:
++ spu_release(ctx);
++ return count;
+ }
+
+ static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
+@@ -657,11 +758,19 @@ static ssize_t spufs_signal1_write(struc
+ return 4;
+ }
+
+-#ifdef CONFIG_SPUFS_MMAP
+ static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+ {
+- return spufs_ps_nopage(vma, address, type, 0x14000);
++#if PAGE_SIZE == 0x1000
++ return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000);
++#elif PAGE_SIZE == 0x10000
++ /* For 64k pages, both signal1 and signal2 can be used to mmap the whole
++ * signal 1 and 2 area
++ */
++ return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
++#else
++#error unsupported page size
++#endif
+ }
+
+ static struct vm_operations_struct spufs_signal1_mmap_vmops = {
+@@ -680,15 +789,12 @@ static int spufs_signal1_mmap(struct fil
+ vma->vm_ops = &spufs_signal1_mmap_vmops;
+ return 0;
+ }
+-#endif
+
+ static struct file_operations spufs_signal1_fops = {
+ .open = spufs_signal1_open,
+ .read = spufs_signal1_read,
+ .write = spufs_signal1_write,
+-#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_signal1_mmap,
+-#endif
+ };
+
+ static int spufs_signal2_open(struct inode *inode, struct file *file)
+@@ -743,11 +849,20 @@ static ssize_t spufs_signal2_write(struc
+ return 4;
+ }
+
+-#ifdef CONFIG_SPUFS_MMAP
++#if SPUFS_MMAP_4K
+ static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+ {
+- return spufs_ps_nopage(vma, address, type, 0x1c000);
++#if PAGE_SIZE == 0x1000
++ return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000);
++#elif PAGE_SIZE == 0x10000
++ /* For 64k pages, both signal1 and signal2 can be used to mmap the whole
++ * signal 1 and 2 area
++ */
++ return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
++#else
++#error unsupported page size
++#endif
+ }
+
+ static struct vm_operations_struct spufs_signal2_mmap_vmops = {
+@@ -767,15 +882,15 @@ static int spufs_signal2_mmap(struct fil
+ vma->vm_ops = &spufs_signal2_mmap_vmops;
+ return 0;
+ }
+-#endif
++#else /* SPUFS_MMAP_4K */
++#define spufs_signal2_mmap NULL
++#endif /* !SPUFS_MMAP_4K */
+
+ static struct file_operations spufs_signal2_fops = {
+ .open = spufs_signal2_open,
+ .read = spufs_signal2_read,
+ .write = spufs_signal2_write,
+-#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_signal2_mmap,
+-#endif
+ };
+
+ static void spufs_signal1_type_set(void *data, u64 val)
+@@ -824,11 +939,11 @@ static u64 spufs_signal2_type_get(void *
+ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
+ spufs_signal2_type_set, "%llu");
+
+-#ifdef CONFIG_SPUFS_MMAP
++#if SPUFS_MMAP_4K
+ static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+ {
+- return spufs_ps_nopage(vma, address, type, 0x0000);
++ return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000);
+ }
+
+ static struct vm_operations_struct spufs_mss_mmap_vmops = {
+@@ -837,17 +952,12 @@ static struct vm_operations_struct spufs
+
+ /*
+ * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
+- * Mapping this area requires that the application have CAP_SYS_RAWIO,
+- * as these registers require special care when read/writing.
+ */
+ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+- if (!capable(CAP_SYS_RAWIO))
+- return -EPERM;
+-
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE | _PAGE_GUARDED);
+@@ -855,7 +965,9 @@ static int spufs_mss_mmap(struct file *f
+ vma->vm_ops = &spufs_mss_mmap_vmops;
+ return 0;
+ }
+-#endif
++#else /* SPUFS_MMAP_4K */
++#define spufs_mss_mmap NULL
++#endif /* !SPUFS_MMAP_4K */
+
+ static int spufs_mss_open(struct inode *inode, struct file *file)
+ {
+@@ -867,17 +979,54 @@ static int spufs_mss_open(struct inode *
+
+ static struct file_operations spufs_mss_fops = {
+ .open = spufs_mss_open,
+-#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_mss_mmap,
+-#endif
++};
++
++static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma,
++ unsigned long address, int *type)
++{
++ return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000);
++}
++
++static struct vm_operations_struct spufs_psmap_mmap_vmops = {
++ .nopage = spufs_psmap_mmap_nopage,
++};
++
++/*
++ * mmap support for full problem state area [0x00000 - 0x1ffff].
++ */
++static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ if (!(vma->vm_flags & VM_SHARED))
++ return -EINVAL;
++
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
++ | _PAGE_NO_CACHE | _PAGE_GUARDED);
++
++ vma->vm_ops = &spufs_psmap_mmap_vmops;
++ return 0;
++}
++
++static int spufs_psmap_open(struct inode *inode, struct file *file)
++{
++ struct spufs_inode_info *i = SPUFS_I(inode);
++
++ file->private_data = i->i_ctx;
++ return nonseekable_open(inode, file);
++}
++
++static struct file_operations spufs_psmap_fops = {
++ .open = spufs_psmap_open,
++ .mmap = spufs_psmap_mmap,
+ };
+
+
+-#ifdef CONFIG_SPUFS_MMAP
++#if SPUFS_MMAP_4K
+ static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+ {
+- return spufs_ps_nopage(vma, address, type, 0x3000);
++ return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000);
+ }
+
+ static struct vm_operations_struct spufs_mfc_mmap_vmops = {
+@@ -886,17 +1035,12 @@ static struct vm_operations_struct spufs
+
+ /*
+ * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
+- * Mapping this area requires that the application have CAP_SYS_RAWIO,
+- * as these registers require special care when read/writing.
+ */
+ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+- if (!capable(CAP_SYS_RAWIO))
+- return -EPERM;
+-
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE | _PAGE_GUARDED);
+@@ -904,7 +1048,9 @@ static int spufs_mfc_mmap(struct file *f
+ vma->vm_ops = &spufs_mfc_mmap_vmops;
+ return 0;
+ }
+-#endif
++#else /* SPUFS_MMAP_4K */
++#define spufs_mfc_mmap NULL
++#endif /* !SPUFS_MMAP_4K */
+
+ static int spufs_mfc_open(struct inode *inode, struct file *file)
+ {
+@@ -1194,9 +1340,7 @@ static struct file_operations spufs_mfc_
+ .flush = spufs_mfc_flush,
+ .fsync = spufs_mfc_fsync,
+ .fasync = spufs_mfc_fasync,
+-#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_mfc_mmap,
+-#endif
+ };
+
+ static void spufs_npc_set(void *data, u64 val)
+@@ -1342,7 +1486,22 @@ static u64 spufs_id_get(void *data)
+
+ return num;
+ }
+-DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, 0, "0x%llx\n")
++DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n")
++
++static u64 spufs_object_id_get(void *data)
++{
++ struct spu_context *ctx = data;
++ return ctx->object_id;
++}
++
++static void spufs_object_id_set(void *data, u64 id)
++{
++ struct spu_context *ctx = data;
++ ctx->object_id = id;
++}
++
++DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
++ spufs_object_id_set, "0x%llx\n");
+
+ struct tree_descr spufs_dir_contents[] = {
+ { "mem", &spufs_mem_fops, 0666, },
+@@ -1367,6 +1526,8 @@ struct tree_descr spufs_dir_contents[] =
+ { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
+ { "event_mask", &spufs_event_mask_ops, 0666, },
+ { "srr0", &spufs_srr0_ops, 0666, },
++ { "psmap", &spufs_psmap_fops, 0666, },
+ { "phys-id", &spufs_id_ops, 0666, },
++ { "object-id", &spufs_object_id_ops, 0666, },
+ {},
+ };
+diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c
+new file mode 100644
+index 0000000..212ea78
+--- /dev/null
++++ b/arch/powerpc/platforms/cell/spufs/gang.c
+@@ -0,0 +1,81 @@
++/*
++ * SPU file system
++ *
++ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
++ *
++ * Author: Arnd Bergmann <arndb at de.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, 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/list.h>
++#include <linux/slab.h>
++
++#include "spufs.h"
++
++struct spu_gang *alloc_spu_gang(void)
++{
++ struct spu_gang *gang;
++
++ gang = kzalloc(sizeof *gang, GFP_KERNEL);
++ if (!gang)
++ goto out;
++
++ kref_init(&gang->kref);
++ mutex_init(&gang->mutex);
++ INIT_LIST_HEAD(&gang->list);
++
++out:
++ return gang;
++}
++
++static void destroy_spu_gang(struct kref *kref)
++{
++ struct spu_gang *gang;
++ gang = container_of(kref, struct spu_gang, kref);
++ WARN_ON(gang->contexts || !list_empty(&gang->list));
++ kfree(gang);
++}
++
++struct spu_gang *get_spu_gang(struct spu_gang *gang)
++{
++ kref_get(&gang->kref);
++ return gang;
++}
++
++int put_spu_gang(struct spu_gang *gang)
++{
++ return kref_put(&gang->kref, &destroy_spu_gang);
++}
++
++void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx)
++{
++ mutex_lock(&gang->mutex);
++ ctx->gang = get_spu_gang(gang);
++ list_add(&ctx->gang_list, &gang->list);
++ gang->contexts++;
++ mutex_unlock(&gang->mutex);
++}
++
++void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx)
++{
++ mutex_lock(&gang->mutex);
++ WARN_ON(ctx->gang != gang);
++ list_del_init(&ctx->gang_list);
++ gang->contexts--;
++ mutex_unlock(&gang->mutex);
++
++ put_spu_gang(gang);
++}
+diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
+index c8670f5..d805ffe 100644
+--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
++++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
+@@ -147,7 +147,7 @@ static void spu_hw_signal1_write(struct
+
+ static u32 spu_hw_signal2_read(struct spu_context *ctx)
+ {
+- return in_be32(&ctx->spu->problem->signal_notify1);
++ return in_be32(&ctx->spu->problem->signal_notify2);
+ }
+
+ static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
+@@ -234,7 +234,7 @@ static void spu_hw_runcntl_stop(struct s
+
+ static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
+ {
+- struct spu_problem *prob = ctx->spu->problem;
++ struct spu_problem __iomem *prob = ctx->spu->problem;
+ int ret;
+
+ spin_lock_irq(&ctx->spu->register_lock);
+@@ -263,7 +263,7 @@ static int spu_hw_send_mfc_command(struc
+ struct mfc_dma_command *cmd)
+ {
+ u32 status;
+- struct spu_problem *prob = ctx->spu->problem;
++ struct spu_problem __iomem *prob = ctx->spu->problem;
+
+ spin_lock_irq(&ctx->spu->register_lock);
+ out_be32(&prob->mfc_lsa_W, cmd->lsa);
+diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
+index 7b45728..427d00a 100644
+--- a/arch/powerpc/platforms/cell/spufs/inode.c
++++ b/arch/powerpc/platforms/cell/spufs/inode.c
+@@ -50,6 +50,10 @@ spufs_alloc_inode(struct super_block *sb
+ ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
++
++ ei->i_gang = NULL;
++ ei->i_ctx = NULL;
++
+ return &ei->vfs_inode;
+ }
+
+@@ -82,7 +86,6 @@ spufs_new_inode(struct super_block *sb,
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ out:
+@@ -120,7 +123,7 @@ spufs_new_file(struct super_block *sb, s
+ ret = 0;
+ inode->i_op = &spufs_file_iops;
+ inode->i_fop = fops;
+- inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
++ inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
+ d_add(dentry, inode);
+ out:
+ return ret;
+@@ -129,14 +132,19 @@ out:
+ static void
+ spufs_delete_inode(struct inode *inode)
+ {
+- if (SPUFS_I(inode)->i_ctx)
+- put_spu_context(SPUFS_I(inode)->i_ctx);
++ struct spufs_inode_info *ei = SPUFS_I(inode);
++
++ if (ei->i_ctx)
++ put_spu_context(ei->i_ctx);
++ if (ei->i_gang)
++ put_spu_gang(ei->i_gang);
+ clear_inode(inode);
+ }
+
+ static void spufs_prune_dir(struct dentry *dir)
+ {
+ struct dentry *dentry, *tmp;
++
+ mutex_lock(&dir->d_inode->i_mutex);
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ spin_lock(&dcache_lock);
+@@ -157,13 +165,13 @@ static void spufs_prune_dir(struct dentr
+ mutex_unlock(&dir->d_inode->i_mutex);
+ }
+
+-/* Caller must hold root->i_mutex */
+-static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
++/* Caller must hold parent->i_mutex */
++static int spufs_rmdir(struct inode *parent, struct dentry *dir)
+ {
+ /* remove all entries */
+- spufs_prune_dir(dir_dentry);
++ spufs_prune_dir(dir);
+
+- return simple_rmdir(root, dir_dentry);
++ return simple_rmdir(parent, dir);
+ }
+
+ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+@@ -192,17 +200,17 @@ out:
+ static int spufs_dir_close(struct inode *inode, struct file *file)
+ {
+ struct spu_context *ctx;
+- struct inode *dir;
+- struct dentry *dentry;
++ struct inode *parent;
++ struct dentry *dir;
+ int ret;
+
+- dentry = file->f_dentry;
+- dir = dentry->d_parent->d_inode;
+- ctx = SPUFS_I(dentry->d_inode)->i_ctx;
++ dir = file->f_dentry;
++ parent = dir->d_parent->d_inode;
++ ctx = SPUFS_I(dir->d_inode)->i_ctx;
+
+- mutex_lock(&dir->i_mutex);
+- ret = spufs_rmdir(dir, dentry);
+- mutex_unlock(&dir->i_mutex);
++ mutex_lock(&parent->i_mutex);
++ ret = spufs_rmdir(parent, dir);
++ mutex_unlock(&parent->i_mutex);
+ WARN_ON(ret);
+
+ /* We have to give up the mm_struct */
+@@ -225,7 +233,8 @@ struct file_operations spufs_context_fop
+ };
+
+ static int
+-spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
++ int mode)
+ {
+ int ret;
+ struct inode *inode;
+@@ -240,11 +249,13 @@ spufs_mkdir(struct inode *dir, struct de
+ inode->i_gid = dir->i_gid;
+ inode->i_mode &= S_ISGID;
+ }
+- ctx = alloc_spu_context();
++ ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
+ SPUFS_I(inode)->i_ctx = ctx;
+ if (!ctx)
+ goto out_iput;
+
++ ctx->flags = flags;
++
+ inode->i_op = &spufs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
+@@ -290,24 +301,177 @@ out:
+ return ret;
+ }
+
++static int spufs_create_context(struct inode *inode,
++ struct dentry *dentry,
++ struct vfsmount *mnt, int flags, int mode)
++{
++ int ret;
++
++ ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
++ if (ret)
++ goto out_unlock;
++
++ /*
++ * get references for dget and mntget, will be released
++ * in error path of *_open().
++ */
++ ret = spufs_context_open(dget(dentry), mntget(mnt));
++ if (ret < 0) {
++ WARN_ON(spufs_rmdir(inode, dentry));
++ mutex_unlock(&inode->i_mutex);
++ spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
++ goto out;
++ }
++
++out_unlock:
++ mutex_unlock(&inode->i_mutex);
++out:
++ dput(dentry);
++ return ret;
++}
++
++static int spufs_rmgang(struct inode *root, struct dentry *dir)
++{
++ /* FIXME: this fails if the dir is not empty,
++ which causes a leak of gangs. */
++ return simple_rmdir(root, dir);
++}
++
++static int spufs_gang_close(struct inode *inode, struct file *file)
++{
++ struct inode *parent;
++ struct dentry *dir;
++ int ret;
++
++ dir = file->f_dentry;
++ parent = dir->d_parent->d_inode;
++
++ ret = spufs_rmgang(parent, dir);
++ WARN_ON(ret);
++
++ return dcache_dir_close(inode, file);
++}
++
++struct file_operations spufs_gang_fops = {
++ .open = dcache_dir_open,
++ .release = spufs_gang_close,
++ .llseek = dcache_dir_lseek,
++ .read = generic_read_dir,
++ .readdir = dcache_readdir,
++ .fsync = simple_sync_file,
++};
++
++static int
++spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int ret;
++ struct inode *inode;
++ struct spu_gang *gang;
++
++ ret = -ENOSPC;
++ inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
++ if (!inode)
++ goto out;
++
++ ret = 0;
++ if (dir->i_mode & S_ISGID) {
++ inode->i_gid = dir->i_gid;
++ inode->i_mode &= S_ISGID;
++ }
++ gang = alloc_spu_gang();
++ SPUFS_I(inode)->i_ctx = NULL;
++ SPUFS_I(inode)->i_gang = gang;
++ if (!gang)
++ goto out_iput;
++
++ inode->i_op = &spufs_dir_inode_operations;
++ inode->i_fop = &simple_dir_operations;
++
++ d_instantiate(dentry, inode);
++ dget(dentry);
++ dir->i_nlink++;
++ dentry->d_inode->i_nlink++;
++ return ret;
++
++out_iput:
++ iput(inode);
++out:
++ return ret;
++}
++
++static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt)
++{
++ int ret;
++ struct file *filp;
++
++ ret = get_unused_fd();
++ if (ret < 0) {
++ dput(dentry);
++ mntput(mnt);
++ goto out;
++ }
++
++ filp = dentry_open(dentry, mnt, O_RDONLY);
++ if (IS_ERR(filp)) {
++ put_unused_fd(ret);
++ ret = PTR_ERR(filp);
++ goto out;
++ }
++
++ filp->f_op = &spufs_gang_fops;
++ fd_install(ret, filp);
++out:
++ return ret;
++}
++
++static int spufs_create_gang(struct inode *inode,
++ struct dentry *dentry,
++ struct vfsmount *mnt, int mode)
++{
++ int ret;
++
++ ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
++ if (ret)
++ goto out;
++
++ /*
++ * get references for dget and mntget, will be released
++ * in error path of *_open().
++ */
++ ret = spufs_gang_open(dget(dentry), mntget(mnt));
++ if (ret < 0)
++ WARN_ON(spufs_rmgang(inode, dentry));
++
++out:
++ mutex_unlock(&inode->i_mutex);
++ dput(dentry);
++ return ret;
++}
++
++
+ static struct file_system_type spufs_type;
+
+-long spufs_create_thread(struct nameidata *nd,
+- unsigned int flags, mode_t mode)
++long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
+ {
+ struct dentry *dentry;
+ int ret;
+
+- /* need to be at the root of spufs */
+ ret = -EINVAL;
+- if (nd->dentry->d_sb->s_type != &spufs_type ||
+- nd->dentry != nd->dentry->d_sb->s_root)
++ /* check if we are on spufs */
++ if (nd->dentry->d_sb->s_type != &spufs_type)
+ goto out;
+
+- /* all flags are reserved */
+- if (flags)
++ /* don't accept undefined flags */
++ if (flags & (~SPU_CREATE_FLAG_ALL))
+ goto out;
+
++ /* only threads can be underneath a gang */
++ if (nd->dentry != nd->dentry->d_sb->s_root) {
++ if ((flags & SPU_CREATE_GANG) ||
++ !SPUFS_I(nd->dentry->d_inode)->i_gang)
++ goto out;
++ }
++
+ dentry = lookup_create(nd, 1);
+ ret = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+@@ -318,22 +482,13 @@ long spufs_create_thread(struct nameidat
+ goto out_dput;
+
+ mode &= ~current->fs->umask;
+- ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO);
+- if (ret)
+- goto out_dput;
+
+- /*
+- * get references for dget and mntget, will be released
+- * in error path of *_open().
+- */
+- ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
+- if (ret < 0) {
+- WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry));
+- mutex_unlock(&nd->dentry->d_inode->i_mutex);
+- spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
+- dput(dentry);
+- goto out;
+- }
++ if (flags & SPU_CREATE_GANG)
++ return spufs_create_gang(nd->dentry->d_inode,
++ dentry, nd->mnt, mode);
++ else
++ return spufs_create_context(nd->dentry->d_inode,
++ dentry, nd->mnt, flags, mode);
+
+ out_dput:
+ dput(dentry);
+diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
+index 483c8b7..63df8cf 100644
+--- a/arch/powerpc/platforms/cell/spufs/run.c
++++ b/arch/powerpc/platforms/cell/spufs/run.c
+@@ -14,6 +14,26 @@ void spufs_stop_callback(struct spu *spu
+ wake_up_all(&ctx->stop_wq);
+ }
+
++void spufs_dma_callback(struct spu *spu, int type)
++{
++ struct spu_context *ctx = spu->ctx;
++
++ if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
++ ctx->event_return |= type;
++ wake_up_all(&ctx->stop_wq);
++ } else {
++ switch (type) {
++ case SPE_EVENT_DMA_ALIGNMENT:
++ case SPE_EVENT_INVALID_DMA:
++ force_sig(SIGBUS, /* info, */ current);
++ break;
++ case SPE_EVENT_SPE_ERROR:
++ force_sig(SIGILL, /* info */ current);
++ break;
++ }
++ }
++}
++
+ static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+ {
+ struct spu *spu;
+@@ -28,8 +48,7 @@ static inline int spu_stopped(struct spu
+ return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+ }
+
+-static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
+- u32 * status)
++static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
+ {
+ int ret;
+
+@@ -72,7 +91,7 @@ static inline int spu_reacquire_runnable
+ SPU_STATUS_STOPPED_BY_HALT)) {
+ return *status;
+ }
+- if ((ret = spu_run_init(ctx, npc, status)) != 0)
++ if ((ret = spu_run_init(ctx, npc)) != 0)
+ return ret;
+ return 0;
+ }
+@@ -177,46 +196,49 @@ static inline int spu_process_events(str
+ }
+
+ long spufs_run_spu(struct file *file, struct spu_context *ctx,
+- u32 * npc, u32 * status)
++ u32 *npc, u32 *event)
+ {
+ int ret;
++ u32 status;
+
+ if (down_interruptible(&ctx->run_sema))
+ return -ERESTARTSYS;
+
+- ret = spu_run_init(ctx, npc, status);
++ ctx->event_return = 0;
++ ret = spu_run_init(ctx, npc);
+ if (ret)
+ goto out;
+
+ do {
+- ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
++ ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
+ if (unlikely(ret))
+ break;
+- if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
+- (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
++ if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
++ (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
+ ret = spu_process_callback(ctx);
+ if (ret)
+ break;
+- *status &= ~SPU_STATUS_STOPPED_BY_STOP;
++ status &= ~SPU_STATUS_STOPPED_BY_STOP;
+ }
+ if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
+- ret = spu_reacquire_runnable(ctx, npc, status);
++ ret = spu_reacquire_runnable(ctx, npc, &status);
+ if (ret)
+ goto out;
+ continue;
+ }
+ ret = spu_process_events(ctx);
+
+- } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
++ } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
+ SPU_STATUS_STOPPED_BY_HALT)));
+
+ ctx->ops->runcntl_stop(ctx);
+- ret = spu_run_fini(ctx, npc, status);
++ ret = spu_run_fini(ctx, npc, &status);
+ if (!ret)
+- ret = *status;
++ ret = status;
+ spu_yield(ctx);
+
+ out:
++ *event = ctx->event_return;
+ up(&ctx->run_sema);
+ return ret;
+ }
+diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
+index 1350294..bd6fe4b 100644
+--- a/arch/powerpc/platforms/cell/spufs/sched.c
++++ b/arch/powerpc/platforms/cell/spufs/sched.c
+@@ -3,11 +3,7 @@
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter at us.ibm.com>
+ *
+- * SPU scheduler, based on Linux thread priority. For now use
+- * a simple "cooperative" yield model with no preemption. SPU
+- * scheduling will eventually be preemptive: When a thread with
+- * a higher static priority gets ready to run, then an active SPU
+- * context will be preempted and returned to the waitq.
++ * 2006-03-31 NUMA domains added.
+ *
+ * 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
+@@ -37,6 +33,9 @@
+ #include <linux/smp_lock.h>
+ #include <linux/stddef.h>
+ #include <linux/unistd.h>
++#include <linux/numa.h>
++#include <linux/mutex.h>
++#include <linux/notifier.h>
+
+ #include <asm/io.h>
+ #include <asm/mmu_context.h>
+@@ -49,128 +48,59 @@
+
+ #define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
+ struct spu_prio_array {
+- atomic_t nr_blocked;
+ unsigned long bitmap[SPU_BITMAP_SIZE];
+ wait_queue_head_t waitq[MAX_PRIO];
++ struct list_head active_list[MAX_NUMNODES];
++ struct mutex active_mutex[MAX_NUMNODES];
+ };
+
+-/* spu_runqueue - This is the main runqueue data structure for SPUs. */
+-struct spu_runqueue {
+- struct semaphore sem;
+- unsigned long nr_active;
+- unsigned long nr_idle;
+- unsigned long nr_switches;
+- struct list_head active_list;
+- struct list_head idle_list;
+- struct spu_prio_array prio;
+-};
+-
+-static struct spu_runqueue *spu_runqueues = NULL;
+-
+-static inline struct spu_runqueue *spu_rq(void)
+-{
+- /* Future: make this a per-NODE array,
+- * and use cpu_to_node(smp_processor_id())
+- */
+- return spu_runqueues;
+-}
++static struct spu_prio_array *spu_prio;
+
+-static inline struct spu *del_idle(struct spu_runqueue *rq)
++static inline int node_allowed(int node)
+ {
+- struct spu *spu;
++ cpumask_t mask;
+
+- BUG_ON(rq->nr_idle <= 0);
+- BUG_ON(list_empty(&rq->idle_list));
+- /* Future: Move SPU out of low-power SRI state. */
+- spu = list_entry(rq->idle_list.next, struct spu, sched_list);
+- list_del_init(&spu->sched_list);
+- rq->nr_idle--;
+- return spu;
++ if (!nr_cpus_node(node))
++ return 0;
++ mask = node_to_cpumask(node);
++ if (!cpus_intersects(mask, current->cpus_allowed))
++ return 0;
++ return 1;
+ }
+
+-static inline void del_active(struct spu_runqueue *rq, struct spu *spu)
++static inline void mm_needs_global_tlbie(struct mm_struct *mm)
+ {
+- BUG_ON(rq->nr_active <= 0);
+- BUG_ON(list_empty(&rq->active_list));
+- list_del_init(&spu->sched_list);
+- rq->nr_active--;
+-}
++ int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1;
+
+-static inline void add_idle(struct spu_runqueue *rq, struct spu *spu)
+-{
+- /* Future: Put SPU into low-power SRI state. */
+- list_add_tail(&spu->sched_list, &rq->idle_list);
+- rq->nr_idle++;
++ /* Global TLBIE broadcast required with SPEs. */
++ __cpus_setall(&mm->cpu_vm_mask, nr);
+ }
+
+-static inline void add_active(struct spu_runqueue *rq, struct spu *spu)
+-{
+- rq->nr_active++;
+- rq->nr_switches++;
+- list_add_tail(&spu->sched_list, &rq->active_list);
+-}
++static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
+
+-static void prio_wakeup(struct spu_runqueue *rq)
++static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
+ {
+- if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) {
+- int best = sched_find_first_bit(rq->prio.bitmap);
+- if (best < MAX_PRIO) {
+- wait_queue_head_t *wq = &rq->prio.waitq[best];
+- wake_up_interruptible_nr(wq, 1);
+- }
+- }
++ blocking_notifier_call_chain(&spu_switch_notifier,
++ ctx ? ctx->object_id : 0, spu);
+ }
+
+-static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx,
+- u64 flags)
++int spu_switch_event_register(struct notifier_block * n)
+ {
+- int prio = current->prio;
+- wait_queue_head_t *wq = &rq->prio.waitq[prio];
+- DEFINE_WAIT(wait);
+-
+- __set_bit(prio, rq->prio.bitmap);
+- atomic_inc(&rq->prio.nr_blocked);
+- prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE);
+- if (!signal_pending(current)) {
+- up(&rq->sem);
+- up_write(&ctx->state_sema);
+- pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
+- current->pid, current->prio);
+- schedule();
+- down_write(&ctx->state_sema);
+- down(&rq->sem);
+- }
+- finish_wait(wq, &wait);
+- atomic_dec(&rq->prio.nr_blocked);
+- if (!waitqueue_active(wq))
+- __clear_bit(prio, rq->prio.bitmap);
++ return blocking_notifier_chain_register(&spu_switch_notifier, n);
+ }
+
+-static inline int is_best_prio(struct spu_runqueue *rq)
++int spu_switch_event_unregister(struct notifier_block * n)
+ {
+- int best_prio;
+-
+- best_prio = sched_find_first_bit(rq->prio.bitmap);
+- return (current->prio < best_prio) ? 1 : 0;
++ return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
+ }
+
+-static inline void mm_needs_global_tlbie(struct mm_struct *mm)
+-{
+- /* Global TLBIE broadcast required with SPEs. */
+-#if (NR_CPUS > 1)
+- __cpus_setall(&mm->cpu_vm_mask, NR_CPUS);
+-#else
+- __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */
+-#endif
+-}
+
+ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
+ {
+- pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid,
+- spu->number);
++ pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
++ spu->number, spu->node);
+ spu->ctx = ctx;
+ spu->flags = 0;
+- ctx->flags = 0;
+ ctx->spu = spu;
+ ctx->ops = &spu_hw_ops;
+ spu->pid = current->pid;
+@@ -181,16 +111,20 @@ static inline void bind_context(struct s
+ spu->wbox_callback = spufs_wbox_callback;
+ spu->stop_callback = spufs_stop_callback;
+ spu->mfc_callback = spufs_mfc_callback;
++ spu->dma_callback = spufs_dma_callback;
+ mb();
+ spu_unmap_mappings(ctx);
+ spu_restore(&ctx->csa, spu);
+ spu->timestamp = jiffies;
++ spu_cpu_affinity_set(spu, raw_smp_processor_id());
++ spu_switch_notify(spu, ctx);
+ }
+
+ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
+ {
+- pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__,
+- spu->pid, spu->number);
++ pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
++ spu->pid, spu->number, spu->node);
++ spu_switch_notify(spu, NULL);
+ spu_unmap_mappings(ctx);
+ spu_save(&ctx->csa, spu);
+ spu->timestamp = jiffies;
+@@ -199,173 +133,158 @@ static inline void unbind_context(struct
+ spu->wbox_callback = NULL;
+ spu->stop_callback = NULL;
+ spu->mfc_callback = NULL;
++ spu->dma_callback = NULL;
+ spu->mm = NULL;
+ spu->pid = 0;
+ spu->prio = MAX_PRIO;
+ ctx->ops = &spu_backing_ops;
+ ctx->spu = NULL;
+- ctx->flags = 0;
+ spu->flags = 0;
+ spu->ctx = NULL;
+ }
+
+-static void spu_reaper(void *data)
++static inline void spu_add_wq(wait_queue_head_t * wq, wait_queue_t * wait,
++ int prio)
+ {
+- struct spu_context *ctx = data;
+- struct spu *spu;
+-
+- down_write(&ctx->state_sema);
+- spu = ctx->spu;
+- if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+- if (atomic_read(&spu->rq->prio.nr_blocked)) {
+- pr_debug("%s: spu=%d\n", __func__, spu->number);
+- ctx->ops->runcntl_stop(ctx);
+- spu_deactivate(ctx);
+- wake_up_all(&ctx->stop_wq);
+- } else {
+- clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+- }
+- }
+- up_write(&ctx->state_sema);
+- put_spu_context(ctx);
++ prepare_to_wait_exclusive(wq, wait, TASK_INTERRUPTIBLE);
++ set_bit(prio, spu_prio->bitmap);
+ }
+
+-static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu)
++static inline void spu_del_wq(wait_queue_head_t * wq, wait_queue_t * wait,
++ int prio)
+ {
+- struct spu_context *ctx = get_spu_context(spu->ctx);
+- unsigned long now = jiffies;
+- unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
+-
+- set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+- INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
+- if (time_after(now, expire))
+- schedule_work(&ctx->reap_work);
+- else
+- schedule_delayed_work(&ctx->reap_work, expire - now);
+-}
++ u64 flags;
+
+-static void check_preempt_active(struct spu_runqueue *rq)
+-{
+- struct list_head *p;
+- struct spu *worst = NULL;
+-
+- list_for_each(p, &rq->active_list) {
+- struct spu *spu = list_entry(p, struct spu, sched_list);
+- struct spu_context *ctx = spu->ctx;
+- if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+- if (!worst || (spu->prio > worst->prio)) {
+- worst = spu;
+- }
+- }
+- }
+- if (worst && (current->prio < worst->prio))
+- schedule_spu_reaper(rq, worst);
++ __set_current_state(TASK_RUNNING);
++
++ spin_lock_irqsave(&wq->lock, flags);
++
++ remove_wait_queue_locked(wq, wait);
++ if (list_empty(&wq->task_list))
++ clear_bit(prio, spu_prio->bitmap);
++
++ spin_unlock_irqrestore(&wq->lock, flags);
+ }
+
+-static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
++static void spu_prio_wait(struct spu_context *ctx, u64 flags)
+ {
+- struct spu_runqueue *rq;
+- struct spu *spu = NULL;
++ int prio = current->prio;
++ wait_queue_head_t *wq = &spu_prio->waitq[prio];
++ DEFINE_WAIT(wait);
+
+- rq = spu_rq();
+- down(&rq->sem);
+- for (;;) {
+- if (rq->nr_idle > 0) {
+- if (is_best_prio(rq)) {
+- /* Fall through. */
+- spu = del_idle(rq);
+- break;
+- } else {
+- prio_wakeup(rq);
+- up(&rq->sem);
+- yield();
+- if (signal_pending(current)) {
+- return NULL;
+- }
+- rq = spu_rq();
+- down(&rq->sem);
+- continue;
+- }
+- } else {
+- check_preempt_active(rq);
+- prio_wait(rq, ctx, flags);
+- if (signal_pending(current)) {
+- prio_wakeup(rq);
+- spu = NULL;
+- break;
+- }
+- continue;
+- }
++ if (ctx->spu)
++ return;
++
++ spu_add_wq(wq, &wait, prio);
++
++ if (!signal_pending(current)) {
++ up_write(&ctx->state_sema);
++ pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
++ current->pid, current->prio);
++ schedule();
++ down_write(&ctx->state_sema);
+ }
+- up(&rq->sem);
+- return spu;
++
++ spu_del_wq(wq, &wait, prio);
+ }
+
+-static void put_idle_spu(struct spu *spu)
++static void spu_prio_wakeup(void)
+ {
+- struct spu_runqueue *rq = spu->rq;
+-
+- down(&rq->sem);
+- add_idle(rq, spu);
+- prio_wakeup(rq);
+- up(&rq->sem);
++ int best = sched_find_first_bit(spu_prio->bitmap);
++ if (best < MAX_PRIO) {
++ wait_queue_head_t *wq = &spu_prio->waitq[best];
++ wake_up_interruptible_nr(wq, 1);
++ }
+ }
+
+ static int get_active_spu(struct spu *spu)
+ {
+- struct spu_runqueue *rq = spu->rq;
+- struct list_head *p;
++ int node = spu->node;
+ struct spu *tmp;
+ int rc = 0;
+
+- down(&rq->sem);
+- list_for_each(p, &rq->active_list) {
+- tmp = list_entry(p, struct spu, sched_list);
++ mutex_lock(&spu_prio->active_mutex[node]);
++ list_for_each_entry(tmp, &spu_prio->active_list[node], list) {
+ if (tmp == spu) {
+- del_active(rq, spu);
++ list_del_init(&spu->list);
+ rc = 1;
+ break;
+ }
+ }
+- up(&rq->sem);
++ mutex_unlock(&spu_prio->active_mutex[node]);
+ return rc;
+ }
+
+ static void put_active_spu(struct spu *spu)
+ {
+- struct spu_runqueue *rq = spu->rq;
++ int node = spu->node;
++
++ mutex_lock(&spu_prio->active_mutex[node]);
++ list_add_tail(&spu->list, &spu_prio->active_list[node]);
++ mutex_unlock(&spu_prio->active_mutex[node]);
++}
++
++static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags)
++{
++ struct spu *spu = NULL;
++ int node = cpu_to_node(raw_smp_processor_id());
++ int n;
+
+- down(&rq->sem);
+- add_active(rq, spu);
+- up(&rq->sem);
++ for (n = 0; n < MAX_NUMNODES; n++, node++) {
++ node = (node < MAX_NUMNODES) ? node : 0;
++ if (!node_allowed(node))
++ continue;
++ spu = spu_alloc_node(node);
++ if (spu)
++ break;
++ }
++ return spu;
+ }
+
+-/* Lock order:
+- * spu_activate() & spu_deactivate() require the
+- * caller to have down_write(&ctx->state_sema).
++static inline struct spu *spu_get(struct spu_context *ctx, u64 flags)
++{
++ /* Future: spu_get_idle() if possible,
++ * otherwise try to preempt an active
++ * context.
++ */
++ return spu_get_idle(ctx, flags);
++}
++
++/* The three externally callable interfaces
++ * for the scheduler begin here.
+ *
+- * The rq->sem is breifly held (inside or outside a
+- * given ctx lock) for list management, but is never
+- * held during save/restore.
++ * spu_activate - bind a context to SPU, waiting as needed.
++ * spu_deactivate - unbind a context from its SPU.
++ * spu_yield - yield an SPU if others are waiting.
+ */
+
+ int spu_activate(struct spu_context *ctx, u64 flags)
+ {
+ struct spu *spu;
++ int ret = 0;
+
+- if (ctx->spu)
+- return 0;
+- spu = get_idle_spu(ctx, flags);
+- if (!spu)
+- return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
+- bind_context(spu, ctx);
+- /*
+- * We're likely to wait for interrupts on the same
+- * CPU that we are now on, so send them here.
+- */
+- spu_cpu_affinity_set(spu, raw_smp_processor_id());
+- put_active_spu(spu);
+- return 0;
++ for (;;) {
++ if (ctx->spu)
++ return 0;
++ spu = spu_get(ctx, flags);
++ if (spu != NULL) {
++ if (ctx->spu != NULL) {
++ spu_free(spu);
++ spu_prio_wakeup();
++ break;
++ }
++ bind_context(spu, ctx);
++ put_active_spu(spu);
++ break;
++ }
++ spu_prio_wait(ctx, flags);
++ if (signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ spu_prio_wakeup();
++ break;
++ }
++ }
++ return ret;
+ }
+
+ void spu_deactivate(struct spu_context *ctx)
+@@ -378,8 +297,10 @@ void spu_deactivate(struct spu_context *
+ return;
+ needs_idle = get_active_spu(spu);
+ unbind_context(spu, ctx);
+- if (needs_idle)
+- put_idle_spu(spu);
++ if (needs_idle) {
++ spu_free(spu);
++ spu_prio_wakeup();
++ }
+ }
+
+ void spu_yield(struct spu_context *ctx)
+@@ -387,77 +308,60 @@ void spu_yield(struct spu_context *ctx)
+ struct spu *spu;
+ int need_yield = 0;
+
+- down_write(&ctx->state_sema);
+- spu = ctx->spu;
+- if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) {
+- pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number);
+- spu_deactivate(ctx);
+- ctx->state = SPU_STATE_SAVED;
+- need_yield = 1;
+- } else if (spu) {
+- spu->prio = MAX_PRIO;
++ if (down_write_trylock(&ctx->state_sema)) {
++ if ((spu = ctx->spu) != NULL) {
++ int best = sched_find_first_bit(spu_prio->bitmap);
++ if (best < MAX_PRIO) {
++ pr_debug("%s: yielding SPU %d NODE %d\n",
++ __FUNCTION__, spu->number, spu->node);
++ spu_deactivate(ctx);
++ ctx->state = SPU_STATE_SAVED;
++ need_yield = 1;
++ } else {
++ spu->prio = MAX_PRIO;
++ }
++ }
++ up_write(&ctx->state_sema);
+ }
+- up_write(&ctx->state_sema);
+ if (unlikely(need_yield))
+ yield();
+ }
+
+ int __init spu_sched_init(void)
+ {
+- struct spu_runqueue *rq;
+- struct spu *spu;
+ int i;
+
+- rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL);
+- if (!rq) {
+- printk(KERN_WARNING "%s: Unable to allocate runqueues.\n",
++ spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
++ if (!spu_prio) {
++ printk(KERN_WARNING "%s: Unable to allocate priority queue.\n",
+ __FUNCTION__);
+ return 1;
+ }
+- memset(rq, 0, sizeof(struct spu_runqueue));
+- init_MUTEX(&rq->sem);
+- INIT_LIST_HEAD(&rq->active_list);
+- INIT_LIST_HEAD(&rq->idle_list);
+- rq->nr_active = 0;
+- rq->nr_idle = 0;
+- rq->nr_switches = 0;
+- atomic_set(&rq->prio.nr_blocked, 0);
+ for (i = 0; i < MAX_PRIO; i++) {
+- init_waitqueue_head(&rq->prio.waitq[i]);
+- __clear_bit(i, rq->prio.bitmap);
++ init_waitqueue_head(&spu_prio->waitq[i]);
++ __clear_bit(i, spu_prio->bitmap);
+ }
+- __set_bit(MAX_PRIO, rq->prio.bitmap);
+- for (;;) {
+- spu = spu_alloc();
+- if (!spu)
+- break;
+- pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
+- add_idle(rq, spu);
+- spu->rq = rq;
+- spu->timestamp = jiffies;
+- }
+- if (!rq->nr_idle) {
+- printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
+- kfree(rq);
+- return 1;
++ __set_bit(MAX_PRIO, spu_prio->bitmap);
++ for (i = 0; i < MAX_NUMNODES; i++) {
++ mutex_init(&spu_prio->active_mutex[i]);
++ INIT_LIST_HEAD(&spu_prio->active_list[i]);
+ }
+ return 0;
+ }
+
+ void __exit spu_sched_exit(void)
+ {
+- struct spu_runqueue *rq = spu_rq();
+- struct spu *spu;
+-
+- if (!rq) {
+- printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__);
+- return;
+- }
+- while (rq->nr_idle > 0) {
+- spu = del_idle(rq);
+- if (!spu)
+- break;
+- spu_free(spu);
++ struct spu *spu, *tmp;
++ int node;
++
++ for (node = 0; node < MAX_NUMNODES; node++) {
++ mutex_lock(&spu_prio->active_mutex[node]);
++ list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node],
++ list) {
++ list_del_init(&spu->list);
++ spu_free(spu);
++ }
++ mutex_unlock(&spu_prio->active_mutex[node]);
+ }
+- kfree(rq);
++ kfree(spu_prio);
+ }
+diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
+index 4485738..a0f55ca 100644
+--- a/arch/powerpc/platforms/cell/spufs/spufs.h
++++ b/arch/powerpc/platforms/cell/spufs/spufs.h
+@@ -39,6 +39,8 @@ struct spu_context_ops;
+
+ #define SPU_CONTEXT_PREEMPT 0UL
+
++struct spu_gang;
++
+ struct spu_context {
+ struct spu *spu; /* pointer to a physical SPU */
+ struct spu_state csa; /* SPU context save area. */
+@@ -48,6 +50,7 @@ struct spu_context {
+ struct address_space *cntl; /* 'control' area mappings. */
+ struct address_space *signal1; /* 'signal1' area mappings. */
+ struct address_space *signal2; /* 'signal2' area mappings. */
++ u64 object_id; /* user space pointer for oprofile */
+
+ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
+ struct rw_semaphore state_sema;
+@@ -66,7 +69,18 @@ struct spu_context {
+ u32 tagwait;
+ struct spu_context_ops *ops;
+ struct work_struct reap_work;
+- u64 flags;
++ unsigned long flags;
++ unsigned long event_return;
++
++ struct list_head gang_list;
++ struct spu_gang *gang;
++};
++
++struct spu_gang {
++ struct list_head list;
++ struct mutex mutex;
++ struct kref kref;
++ int contexts;
+ };
+
+ struct mfc_dma_command {
+@@ -114,6 +128,7 @@ extern struct spu_context_ops spu_backin
+
+ struct spufs_inode_info {
+ struct spu_context *i_ctx;
++ struct spu_gang *i_gang;
+ struct inode vfs_inode;
+ };
+ #define SPUFS_I(inode) \
+@@ -124,12 +139,19 @@ extern struct tree_descr spufs_dir_conte
+ /* system call implementation */
+ long spufs_run_spu(struct file *file,
+ struct spu_context *ctx, u32 *npc, u32 *status);
+-long spufs_create_thread(struct nameidata *nd,
++long spufs_create(struct nameidata *nd,
+ unsigned int flags, mode_t mode);
+ extern struct file_operations spufs_context_fops;
+
++/* gang management */
++struct spu_gang *alloc_spu_gang(void);
++struct spu_gang *get_spu_gang(struct spu_gang *gang);
++int put_spu_gang(struct spu_gang *gang);
++void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx);
++void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
++
+ /* context management */
+-struct spu_context * alloc_spu_context(void);
++struct spu_context * alloc_spu_context(struct spu_gang *gang);
+ void destroy_spu_context(struct kref *kref);
+ struct spu_context * get_spu_context(struct spu_context *ctx);
+ int put_spu_context(struct spu_context *ctx);
+@@ -183,5 +205,6 @@ void spufs_ibox_callback(struct spu *spu
+ void spufs_wbox_callback(struct spu *spu);
+ void spufs_stop_callback(struct spu *spu);
+ void spufs_mfc_callback(struct spu *spu);
++void spufs_dma_callback(struct spu *spu, int type);
+
+ #endif
+diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
+index 9d9d82d..0f782ca 100644
+--- a/arch/powerpc/platforms/cell/spufs/switch.c
++++ b/arch/powerpc/platforms/cell/spufs/switch.c
+@@ -1779,6 +1779,15 @@ static inline void restore_mfc_cntl(stru
+ */
+ out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
+ eieio();
++ /*
++ * FIXME: this is to restart a DMA that we were processing
++ * before the save. better remember the fault information
++ * in the csa instead.
++ */
++ if ((csa->priv2.mfc_control_RW & MFC_CNTL_SUSPEND_DMA_QUEUE_MASK)) {
++ out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
++ eieio();
++ }
+ }
+
+ static inline void enable_user_access(struct spu_state *csa, struct spu *spu)
+diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
+index e6565a9..a6d1ae4 100644
+--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
++++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
+@@ -38,7 +38,7 @@ static long do_spu_run(struct file *filp
+ u32 npc, status;
+
+ ret = -EFAULT;
+- if (get_user(npc, unpc) || get_user(status, ustatus))
++ if (get_user(npc, unpc))
+ goto out;
+
+ /* check if this file was created by spu_create */
+@@ -49,7 +49,10 @@ static long do_spu_run(struct file *filp
+ i = SPUFS_I(filp->f_dentry->d_inode);
+ ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+
+- if (put_user(npc, unpc) || put_user(status, ustatus))
++ if (put_user(npc, unpc))
++ ret = -EFAULT;
++
++ if (ustatus && put_user(status, ustatus))
+ ret = -EFAULT;
+ out:
+ return ret;
+@@ -87,7 +90,7 @@ asmlinkage long sys_spu_create(const cha
+ ret = path_lookup(tmp, LOOKUP_PARENT|
+ LOOKUP_OPEN|LOOKUP_CREATE, &nd);
+ if (!ret) {
+- ret = spufs_create_thread(&nd, flags, mode);
++ ret = spufs_create(&nd, flags, mode);
+ path_release(&nd);
+ }
+ putname(tmp);
+diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c
+index 150f67d..0dd4a64 100644
+--- a/arch/powerpc/platforms/chrp/nvram.c
++++ b/arch/powerpc/platforms/chrp/nvram.c
+@@ -67,13 +67,14 @@ static void chrp_nvram_write(int addr, u
+ void __init chrp_nvram_init(void)
+ {
+ struct device_node *nvram;
+- unsigned int *nbytes_p, proplen;
++ const unsigned int *nbytes_p;
++ unsigned int proplen;
+
+ nvram = of_find_node_by_type(NULL, "nvram");
+ if (nvram == NULL)
+ return;
+
+- nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
++ nbytes_p = get_property(nvram, "#bytes", &proplen);
+ if (nbytes_p == NULL || proplen != sizeof(unsigned int))
+ return;
+
+diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
+index 6802cdc..0f43405 100644
+--- a/arch/powerpc/platforms/chrp/pci.c
++++ b/arch/powerpc/platforms/chrp/pci.c
+@@ -214,11 +214,11 @@ void __init
+ chrp_find_bridges(void)
+ {
+ struct device_node *dev;
+- int *bus_range;
++ const int *bus_range;
+ int len, index = -1;
+ struct pci_controller *hose;
+- unsigned int *dma;
+- char *model, *machine;
++ const unsigned int *dma;
++ const char *model, *machine;
+ int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
+ struct device_node *root = find_path_device("/");
+ struct resource r;
+@@ -246,7 +246,7 @@ chrp_find_bridges(void)
+ dev->full_name);
+ continue;
+ }
+- bus_range = (int *) get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+@@ -257,7 +257,7 @@ chrp_find_bridges(void)
+ else
+ printk(KERN_INFO "PCI buses %d..%d",
+ bus_range[0], bus_range[1]);
+- printk(" controlled by %s", dev->type);
++ printk(" controlled by %s", dev->full_name);
+ if (!is_longtrail)
+ printk(" at %llx", (unsigned long long)r.start);
+ printk("\n");
+@@ -289,6 +289,19 @@ chrp_find_bridges(void)
+ setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc);
+ } else if (is_pegasos == 2) {
+ setup_peg2(hose, dev);
++ } else if (!strncmp(model, "IBM,CPC710", 10)) {
++ setup_indirect_pci(hose,
++ r.start + 0x000f8000,
++ r.start + 0x000f8010);
++ if (index == 0) {
++ dma = get_property(dev, "system-dma-base",&len);
++ if (dma && len >= sizeof(*dma)) {
++ dma = (unsigned int *)
++ (((unsigned long)dma) +
++ len - sizeof(*dma));
++ pci_dram_offset = *dma;
++ }
++ }
+ } else {
+ printk("No methods for %s (model %s), using RTAS\n",
+ dev->full_name, model);
+@@ -299,15 +312,35 @@ chrp_find_bridges(void)
+
+ /* check the first bridge for a property that we can
+ use to set pci_dram_offset */
+- dma = (unsigned int *)
+- get_property(dev, "ibm,dma-ranges", &len);
++ dma = get_property(dev, "ibm,dma-ranges", &len);
+ if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
+ pci_dram_offset = dma[2] - dma[3];
+ printk("pci_dram_offset = %lx\n", pci_dram_offset);
+ }
+ }
++}
++
++/* SL82C105 IDE Control/Status Register */
++#define SL82C105_IDECSR 0x40
++
++/* Fixup for Winbond ATA quirk, required for briq */
++void chrp_pci_fixup_winbond_ata(struct pci_dev *sl82c105)
++{
++ u8 progif;
+
+- /* Do not fixup interrupts from OF tree on pegasos */
+- if (is_pegasos)
+- ppc_md.pcibios_fixup = NULL;
++ /* If non-briq machines need that fixup too, please speak up */
++ if (!machine_is(chrp) || _chrp_type != _CHRP_briq)
++ return;
++
++ if ((sl82c105->class & 5) != 5) {
++ printk("W83C553: Switching SL82C105 IDE to PCI native mode\n");
++ /* Enable SL82C105 PCI native IDE mode */
++ pci_read_config_byte(sl82c105, PCI_CLASS_PROG, &progif);
++ pci_write_config_byte(sl82c105, PCI_CLASS_PROG, progif | 0x05);
++ sl82c105->class |= 0x05;
++ /* Disable SL82C105 second port */
++ pci_write_config_word(sl82c105, SL82C105_IDECSR, 0x0003);
++ }
+ }
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105,
++ chrp_pci_fixup_winbond_ata);
+diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
+index 9c08ff3..49b8dab 100644
+--- a/arch/powerpc/platforms/chrp/setup.c
++++ b/arch/powerpc/platforms/chrp/setup.c
+@@ -70,10 +70,13 @@ unsigned long event_scan_interval;
+ * has to include <linux/interrupt.h> (to get irqreturn_t), which
+ * causes all sorts of problems. -- paulus
+ */
+-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
++extern irqreturn_t xmon_irq(int, void *);
+
+ extern unsigned long loops_per_jiffy;
+
++/* To be replaced by RTAS when available */
++static unsigned int *briq_SPOR;
++
+ #ifdef CONFIG_SMP
+ extern struct smp_ops_t chrp_smp_ops;
+ #endif
+@@ -92,6 +95,15 @@ static const char *gg2_cachemodes[4] = {
+ "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+ };
+
++static const char *chrp_names[] = {
++ "Unknown",
++ "","","",
++ "Motorola",
++ "IBM or Longtrail",
++ "Genesi Pegasos",
++ "Total Impact Briq"
++};
++
+ void chrp_show_cpuinfo(struct seq_file *m)
+ {
+ int i, sdramen;
+@@ -214,8 +226,7 @@ static void __init pegasos_set_l2cr(void
+ /* Enable L2 cache if needed */
+ np = find_type_devices("cpu");
+ if (np != NULL) {
+- unsigned int *l2cr = (unsigned int *)
+- get_property (np, "l2cr", NULL);
++ const unsigned int *l2cr = get_property(np, "l2cr", NULL);
+ if (l2cr == NULL) {
+ printk ("Pegasos l2cr : no cpu l2cr property found\n");
+ return;
+@@ -229,10 +240,18 @@ static void __init pegasos_set_l2cr(void
+ }
+ }
+
++static void briq_restart(char *cmd)
++{
++ local_irq_disable();
++ if (briq_SPOR)
++ out_be32(briq_SPOR, 0);
++ for(;;);
++}
++
+ void __init chrp_setup_arch(void)
+ {
+ struct device_node *root = find_path_device ("/");
+- char *machine = NULL;
++ const char *machine = NULL;
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+@@ -245,11 +264,16 @@ void __init chrp_setup_arch(void)
+ _chrp_type = _CHRP_IBM;
+ } else if (machine && strncmp(machine, "MOT", 3) == 0) {
+ _chrp_type = _CHRP_Motorola;
++ } else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) {
++ _chrp_type = _CHRP_briq;
++ /* Map the SPOR register on briq and change the restart hook */
++ briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4);
++ ppc_md.restart = briq_restart;
+ } else {
+ /* Let's assume it is an IBM chrp if all else fails */
+ _chrp_type = _CHRP_IBM;
+ }
+- printk("chrp type = %x\n", _chrp_type);
++ printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]);
+
+ rtas_initialize();
+ if (rtas_token("display-character") >= 0)
+@@ -311,12 +335,11 @@ chrp_event_scan(unsigned long unused)
+ jiffies + event_scan_interval);
+ }
+
+-static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+- unsigned int cascade_irq = i8259_irq(regs);
++ unsigned int cascade_irq = i8259_irq();
+ if (cascade_irq != NO_IRQ)
+- generic_handle_irq(cascade_irq, regs);
++ generic_handle_irq(cascade_irq);
+ desc->chip->eoi(irq);
+ }
+
+@@ -328,7 +351,7 @@ static void __init chrp_find_openpic(voi
+ struct device_node *np, *root;
+ int len, i, j;
+ int isu_size, idu_size;
+- unsigned int *iranges, *opprop = NULL;
++ const unsigned int *iranges, *opprop = NULL;
+ int oplen = 0;
+ unsigned long opaddr;
+ int na = 1;
+@@ -338,8 +361,7 @@ static void __init chrp_find_openpic(voi
+ return;
+ root = of_find_node_by_path("/");
+ if (root) {
+- opprop = (unsigned int *) get_property
+- (root, "platform-open-pic", &oplen);
++ opprop = get_property(root, "platform-open-pic", &oplen);
+ na = prom_n_addr_cells(root);
+ }
+ if (opprop && oplen >= na * sizeof(unsigned int)) {
+@@ -356,7 +378,7 @@ static void __init chrp_find_openpic(voi
+
+ printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
+
+- iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
++ iranges = get_property(np, "interrupt-ranges", &len);
+ if (iranges == NULL)
+ len = 0; /* non-distributed mpic */
+ else
+@@ -442,8 +464,8 @@ static void __init chrp_find_8259(void)
+ * from anyway
+ */
+ for (np = find_devices("pci"); np != NULL; np = np->next) {
+- unsigned int *addrp = (unsigned int *)
+- get_property(np, "8259-interrupt-acknowledge", NULL);
++ const unsigned int *addrp = get_property(np,
++ "8259-interrupt-acknowledge", NULL);
+
+ if (addrp == NULL)
+ continue;
+@@ -455,8 +477,10 @@ static void __init chrp_find_8259(void)
+ " address, polling\n");
+
+ i8259_init(pic, chrp_int_ack);
+- if (ppc_md.get_irq == NULL)
++ if (ppc_md.get_irq == NULL) {
+ ppc_md.get_irq = i8259_irq;
++ irq_set_default_host(i8259_get_host());
++ }
+ if (chrp_mpic != NULL) {
+ cascade_irq = irq_of_parse_and_map(pic, 0);
+ if (cascade_irq == NO_IRQ)
+@@ -502,7 +526,7 @@ void __init
+ chrp_init2(void)
+ {
+ struct device_node *device;
+- unsigned int *p = NULL;
++ const unsigned int *p = NULL;
+
+ #ifdef CONFIG_NVRAM
+ chrp_nvram_init();
+@@ -520,8 +544,7 @@ chrp_init2(void)
+ */
+ device = find_devices("rtas");
+ if (device)
+- p = (unsigned int *) get_property
+- (device, "rtas-event-scan-rate", NULL);
++ p = get_property(device, "rtas-event-scan-rate", NULL);
+ if (p && *p) {
+ /*
+ * Arrange to call chrp_event_scan at least *p times
+diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+index 5d393eb..bdb475c 100644
+--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
++++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+@@ -18,7 +18,6 @@
+ * 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/pci.h>
+@@ -62,8 +61,7 @@ pci_dram_offset = MPC7448_HPC2_PCI_MEM_O
+ extern int tsi108_setup_pci(struct device_node *dev);
+ extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+ extern void tsi108_pci_int_init(void);
+-extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs);
++extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc);
+
+ int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
+ {
+@@ -95,7 +93,7 @@ void mpc7448_hpc2_fixup_irq(struct pci_d
+ {
+ struct pci_controller *hose;
+ struct device_node *node;
+- unsigned int *interrupt;
++ const unsigned int *interrupt;
+ int busnr;
+ int len;
+ u8 slot;
+@@ -112,7 +110,7 @@ void mpc7448_hpc2_fixup_irq(struct pci_d
+ if (!node)
+ printk(KERN_ERR "No pci node found\n");
+
+- interrupt = (unsigned int *) get_property(node, "interrupt-map", &len);
++ interrupt = get_property(node, "interrupt-map", &len);
+ slot = find_slot_by_devfn(interrupt, dev->devfn);
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin == 0 || pin > 4)
+@@ -141,9 +139,9 @@ static void __init mpc7448_hpc2_setup_ar
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+- unsigned int *fp;
++ const unsigned int *fp;
+
+- fp = (int *)get_property(cpu, "clock-frequency", NULL);
++ fp = get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+@@ -201,7 +199,7 @@ static void __init mpc7448_hpc2_init_IRQ
+ tsi_pic = of_find_node_by_type(NULL, "open-pic");
+ if (tsi_pic) {
+ unsigned int size;
+- void *prop = get_property(tsi_pic, "reg", &size);
++ const void *prop = get_property(tsi_pic, "reg", &size);
+ mpic_paddr = of_translate_address(tsi_pic, prop);
+ }
+
+diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
+index 3d957a3..887b688 100644
+--- a/arch/powerpc/platforms/iseries/Kconfig
++++ b/arch/powerpc/platforms/iseries/Kconfig
+@@ -3,13 +3,17 @@ menu "iSeries device drivers"
+ depends on PPC_ISERIES
+
+ config VIOCONS
+- tristate "iSeries Virtual Console Support"
++ tristate "iSeries Virtual Console Support (Obsolete)"
++ help
++ This is the old virtual console driver for legacy iSeries.
++ You should use the iSeries Hypervisor Virtual Console
++ support instead.
+
+ config VIODASD
+ tristate "iSeries Virtual I/O disk support"
+ help
+ If you are running on an iSeries system and you want to use
+- virtual disks created and managed by OS/400, say Y.
++ virtual disks created and managed by OS/400, say Y.
+
+ config VIOCD
+ tristate "iSeries Virtual I/O CD support"
+diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
+index d194140..e305dee 100644
+--- a/arch/powerpc/platforms/iseries/dt.c
++++ b/arch/powerpc/platforms/iseries/dt.c
+@@ -1,5 +1,6 @@
+ /*
+- * Copyright (c) 2005-2006 Michael Ellerman, IBM Corporation
++ * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation
++ * Copyright (C) 2000-2004, IBM Corporation
+ *
+ * Description:
+ * This file contains all the routines to build a flattened device
+@@ -33,13 +34,13 @@
+ #include <asm/iseries/hv_types.h>
+ #include <asm/iseries/hv_lp_config.h>
+ #include <asm/iseries/hv_call_xm.h>
+-#include <asm/iseries/it_exp_vpd_panel.h>
+ #include <asm/udbg.h>
+
+ #include "processor_vpd.h"
+ #include "call_hpt.h"
+ #include "call_pci.h"
+ #include "pci.h"
++#include "it_exp_vpd_panel.h"
+
+ #ifdef DEBUG
+ #define DBG(fmt...) udbg_printf(fmt)
+@@ -76,6 +77,43 @@ static char __initdata device_type_pci[]
+ static char __initdata device_type_vdevice[] = "vdevice";
+ static char __initdata device_type_vscsi[] = "vscsi";
+
++
++/* EBCDIC to ASCII conversion routines */
++
++static unsigned char __init e2a(unsigned char x)
++{
++ switch (x) {
++ case 0x81 ... 0x89:
++ return x - 0x81 + 'a';
++ case 0x91 ... 0x99:
++ return x - 0x91 + 'j';
++ case 0xA2 ... 0xA9:
++ return x - 0xA2 + 's';
++ case 0xC1 ... 0xC9:
++ return x - 0xC1 + 'A';
++ case 0xD1 ... 0xD9:
++ return x - 0xD1 + 'J';
++ case 0xE2 ... 0xE9:
++ return x - 0xE2 + 'S';
++ case 0xF0 ... 0xF9:
++ return x - 0xF0 + '0';
++ }
++ return ' ';
++}
++
++static unsigned char * __init strne2a(unsigned char *dest,
++ const unsigned char *src, size_t n)
++{
++ int i;
++
++ n = strnlen(src, n);
++
++ for (i = 0; i < n; i++)
++ dest[i] = e2a(src[i]);
++
++ return dest;
++}
++
+ static struct iseries_flat_dt * __init dt_init(void)
+ {
+ struct iseries_flat_dt *dt;
+@@ -298,7 +336,8 @@ static void __init dt_vdevices(struct is
+ dt_prop_u32(dt, "#address-cells", 1);
+ dt_prop_u32(dt, "#size-cells", 0);
+
+- dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, NULL, 1);
++ dt_do_vdevice(dt, "vty", reg, -1, device_type_serial,
++ "IBM,iSeries-vty", 1);
+ reg++;
+
+ dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
+diff --git a/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c
+index 663a1af..f0475f0 100644
+--- a/arch/powerpc/platforms/iseries/hvlpconfig.c
++++ b/arch/powerpc/platforms/iseries/hvlpconfig.c
+@@ -18,9 +18,22 @@
+
+ #include <linux/module.h>
+ #include <asm/iseries/hv_lp_config.h>
++#include "it_lp_naca.h"
+
+ HvLpIndex HvLpConfig_getLpIndex_outline(void)
+ {
+ return HvLpConfig_getLpIndex();
+ }
+ EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
++
++HvLpIndex HvLpConfig_getLpIndex(void)
++{
++ return itLpNaca.xLpIndex;
++}
++EXPORT_SYMBOL(HvLpConfig_getLpIndex);
++
++HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
++{
++ return itLpNaca.xPrimaryLpIndex;
++}
++EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex);
+diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
+index e3bd201..218817d 100644
+--- a/arch/powerpc/platforms/iseries/iommu.c
++++ b/arch/powerpc/platforms/iseries/iommu.c
+@@ -43,9 +43,6 @@ static void tce_build_iSeries(struct iom
+ u64 rc;
+ u64 tce, rpn;
+
+- index <<= TCE_PAGE_FACTOR;
+- npages <<= TCE_PAGE_FACTOR;
+-
+ while (npages--) {
+ rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
+ tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
+@@ -75,9 +72,6 @@ static void tce_free_iSeries(struct iomm
+ {
+ u64 rc;
+
+- npages <<= TCE_PAGE_FACTOR;
+- index <<= TCE_PAGE_FACTOR;
+-
+ while (npages--) {
+ rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
+ if (rc)
+@@ -88,6 +82,23 @@ static void tce_free_iSeries(struct iomm
+ }
+
+ /*
++ * Structure passed to HvCallXm_getTceTableParms
++ */
++struct iommu_table_cb {
++ unsigned long itc_busno; /* Bus number for this tce table */
++ unsigned long itc_start; /* Will be NULL for secondary */
++ unsigned long itc_totalsize; /* Size (in pages) of whole table */
++ unsigned long itc_offset; /* Index into real tce table of the
++ start of our section */
++ unsigned long itc_size; /* Size (in pages) of our section */
++ unsigned long itc_index; /* Index of this tce table */
++ unsigned short itc_maxtables; /* Max num of tables for partition */
++ unsigned char itc_virtbus; /* Flag to indicate virtual bus */
++ unsigned char itc_slotno; /* IOA Tce Slot Index */
++ unsigned char itc_rsvd[4];
++};
++
++/*
+ * Call Hv with the architected data structure to get TCE table info.
+ * info. Put the returned data into the Linux representation of the
+ * TCE table data.
+@@ -119,10 +130,9 @@ void iommu_table_getparms_iSeries(unsign
+ panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
+
+ /* itc_size is in pages worth of table, it_size is in # of entries */
+- tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) /
+- TCE_ENTRY_SIZE) >> TCE_PAGE_FACTOR;
++ tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE;
+ tbl->it_busno = parms->itc_busno;
+- tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR;
++ tbl->it_offset = parms->itc_offset;
+ tbl->it_index = parms->itc_index;
+ tbl->it_blocksize = 1;
+ tbl->it_type = virtbus ? TCE_VB : TCE_PCI;
+@@ -162,7 +172,7 @@ void iommu_devnode_init_iSeries(struct d
+ {
+ struct iommu_table *tbl;
+ struct pci_dn *pdn = PCI_DN(dn);
+- u32 *lsn = (u32 *)get_property(dn, "linux,logical-slot-number", NULL);
++ const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL);
+
+ BUG_ON(lsn == NULL);
+
+diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
+index e324468..5225abf 100644
+--- a/arch/powerpc/platforms/iseries/irq.c
++++ b/arch/powerpc/platforms/iseries/irq.c
+@@ -43,10 +43,7 @@
+ #include "irq.h"
+ #include "pci.h"
+ #include "call_pci.h"
+-
+-#if defined(CONFIG_SMP)
+-extern void iSeries_smp_message_recv(struct pt_regs *);
+-#endif
++#include "smp.h"
+
+ #ifdef CONFIG_PCI
+
+@@ -88,7 +85,7 @@ static DEFINE_SPINLOCK(pending_irqs_lock
+ static int num_pending_irqs;
+ static int pending_irqs[NR_IRQS];
+
+-static void int_received(struct pci_event *event, struct pt_regs *regs)
++static void int_received(struct pci_event *event)
+ {
+ int irq;
+
+@@ -146,11 +143,11 @@ static void int_received(struct pci_even
+ }
+ }
+
+-static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
++static void pci_event_handler(struct HvLpEvent *event)
+ {
+ if (event && (event->xType == HvLpEvent_Type_PciIo)) {
+ if (hvlpevent_is_int(event))
+- int_received((struct pci_event *)event, regs);
++ int_received((struct pci_event *)event);
+ else
+ printk(KERN_ERR
+ "pci_event_handler: unexpected ack received\n");
+@@ -308,18 +305,18 @@ int __init iSeries_allocate_IRQ(HvBusNum
+ /*
+ * Get the next pending IRQ.
+ */
+-unsigned int iSeries_get_irq(struct pt_regs *regs)
++unsigned int iSeries_get_irq(void)
+ {
+ int irq = NO_IRQ_IGNORE;
+
+ #ifdef CONFIG_SMP
+ if (get_lppaca()->int_dword.fields.ipi_cnt) {
+ get_lppaca()->int_dword.fields.ipi_cnt = 0;
+- iSeries_smp_message_recv(regs);
++ iSeries_smp_message_recv();
+ }
+ #endif /* CONFIG_SMP */
+ if (hvlpevent_is_pending())
+- process_hvlpevents(regs);
++ process_hvlpevents();
+
+ #ifdef CONFIG_PCI
+ if (num_pending_irqs) {
+diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
+index 1ee8985..69f1b43 100644
+--- a/arch/powerpc/platforms/iseries/irq.h
++++ b/arch/powerpc/platforms/iseries/irq.h
+@@ -4,6 +4,6 @@
+ extern void iSeries_init_IRQ(void);
+ extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
+ extern void iSeries_activate_IRQs(void);
+-extern unsigned int iSeries_get_irq(struct pt_regs *);
++extern unsigned int iSeries_get_irq(void);
+
+ #endif /* _ISERIES_IRQ_H */
+diff --git a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
+new file mode 100644
+index 0000000..6de9097
+--- /dev/null
++++ b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2002 Dave Boutcher IBM Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
++#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
++
++/*
++ * This struct maps the panel information
++ *
++ * Warning:
++ * This data must match the architecture for the panel information
++ */
++
++#include <asm/types.h>
++
++struct ItExtVpdPanel {
++ /* Definition of the Extended Vpd On Panel Data Area */
++ char systemSerial[8];
++ char mfgID[4];
++ char reserved1[24];
++ char machineType[4];
++ char systemID[6];
++ char somUniqueCnt[4];
++ char serialNumberCount;
++ char reserved2[7];
++ u16 bbu3;
++ u16 bbu2;
++ u16 bbu1;
++ char xLocationLabel[8];
++ u8 xRsvd1[6];
++ u16 xFrameId;
++ u8 xRsvd2[48];
++};
++
++extern struct ItExtVpdPanel xItExtVpdPanel;
++
++#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */
+diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h
+new file mode 100644
+index 0000000..9bbf589
+--- /dev/null
++++ b/arch/powerpc/platforms/iseries/it_lp_naca.h
+@@ -0,0 +1,80 @@
++/*
++ * 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
++ * (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 _PLATFORMS_ISERIES_IT_LP_NACA_H
++#define _PLATFORMS_ISERIES_IT_LP_NACA_H
++
++#include <linux/types.h>
++
++/*
++ * This control block contains the data that is shared between the
++ * hypervisor (PLIC) and the OS.
++ */
++
++struct ItLpNaca {
++// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
++ u32 xDesc; // Eye catcher x00-x03
++ u16 xSize; // Size of this class x04-x05
++ u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07
++ u8 xMaxIntHdlrEntries; // Number of entries in array x08-x08
++ u8 xPrimaryLpIndex; // LP Index of Primary x09-x09
++ u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A
++ u8 xLpIndex; // LP Index x0B-x0B
++ u16 xMaxLpQueues; // Number of allocated queues x0C-x0D
++ u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F
++ u8 xPirEnvironMode; // Piranha or hardware x10-x10
++ u8 xPirConsoleMode; // Piranha console indicator x11-x11
++ u8 xPirDasdMode; // Piranha dasd indicator x12-x12
++ u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x17
++ u8 flags; // flags, see below x18-x1F
++ u8 xSpVpdFormat; // VPD areas are in CSP format ...
++ u8 xIntProcRatio; // Ratio of int procs to procs ...
++ u8 xRsvd1_2[5]; // Reserved ...
++ u16 xRsvd1_3; // Reserved x20-x21
++ u16 xPlicVrmIndex; // VRM index of PLIC x22-x23
++ u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x25
++ u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27
++ u64 xLoadAreaAddr; // ER address of load area x28-x2F
++ u32 xLoadAreaChunks; // Chunks for the load area x30-x33
++ u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37
++ // doing an ASR switch on PASE
++ // system call.
++ u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f
++ u8 xRsvd1_4[64]; // x40-x7F
++
++// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
++ u8 xRsvd2_0[128]; // Reserved x00-x7F
++
++// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
++// NB: Padding required to keep xInterrruptHdlr at x300 which is required
++// for v4r4 PLIC.
++ u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F
++ u8 xRsvd3_0[384]; // Reserved 180-2FF
++
++// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
++// handlers
++ u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF
++};
++
++extern struct ItLpNaca itLpNaca;
++
++#define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */
++#define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */
++#define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */
++#define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */
++
++#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */
+diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c
+index a776944..8162049 100644
+--- a/arch/powerpc/platforms/iseries/lpardata.c
++++ b/arch/powerpc/platforms/iseries/lpardata.c
+@@ -13,12 +13,10 @@
+ #include <asm/processor.h>
+ #include <asm/ptrace.h>
+ #include <asm/abs_addr.h>
+-#include <asm/iseries/it_lp_naca.h>
+ #include <asm/lppaca.h>
+ #include <asm/iseries/it_lp_reg_save.h>
+ #include <asm/paca.h>
+ #include <asm/iseries/lpar_map.h>
+-#include <asm/iseries/it_exp_vpd_panel.h>
+ #include <asm/iseries/it_lp_queue.h>
+
+ #include "naca.h"
+@@ -27,6 +25,8 @@
+ #include "ipl_parms.h"
+ #include "processor_vpd.h"
+ #include "release_data.h"
++#include "it_exp_vpd_panel.h"
++#include "it_lp_naca.h"
+
+ /* The HvReleaseData is the root of the information shared between
+ * the hypervisor and Linux.
+@@ -127,14 +127,12 @@ struct ItLpNaca itLpNaca = {
+ (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */
+ }
+ };
+-EXPORT_SYMBOL(itLpNaca);
+
+ /* May be filled in by the hypervisor so cannot end up in the BSS */
+ struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));
+
+ /* May be filled in by the hypervisor so cannot end up in the BSS */
+ struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));
+-EXPORT_SYMBOL(xItExtVpdPanel);
+
+ #define maxPhysicalProcessors 32
+
+diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
+index 2a9f81e..e3e929e 100644
+--- a/arch/powerpc/platforms/iseries/lpevents.c
++++ b/arch/powerpc/platforms/iseries/lpevents.c
+@@ -20,7 +20,7 @@
+ #include <asm/iseries/it_lp_queue.h>
+ #include <asm/iseries/hv_lp_event.h>
+ #include <asm/iseries/hv_call_event.h>
+-#include <asm/iseries/it_lp_naca.h>
++#include "it_lp_naca.h"
+
+ /*
+ * The LpQueue is used to pass event data from the hypervisor to
+@@ -116,7 +116,7 @@ static void hvlpevent_clear_valid(struct
+ hvlpevent_invalidate(event);
+ }
+
+-void process_hvlpevents(struct pt_regs *regs)
++void process_hvlpevents(void)
+ {
+ struct HvLpEvent * event;
+
+@@ -144,7 +144,7 @@ void process_hvlpevents(struct pt_regs *
+ __get_cpu_var(hvlpevent_counts)[event->xType]++;
+ if (event->xType < HvLpEvent_Type_NumTypes &&
+ lpEventHandler[event->xType])
+- lpEventHandler[event->xType](event, regs);
++ lpEventHandler[event->xType](event);
+ else
+ printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType );
+
+diff --git a/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h
+index 74f6889..1a7a3f5 100644
+--- a/arch/powerpc/platforms/iseries/main_store.h
++++ b/arch/powerpc/platforms/iseries/main_store.h
+@@ -61,9 +61,9 @@ struct IoHriMainStoreSegment4 {
+ };
+
+ /* Main Store VPD for Power4 */
+-struct IoHriMainStoreChipInfo1 {
+- u32 chipMfgID __attribute((packed));
+- char chipECLevel[4] __attribute((packed));
++struct __attribute((packed)) IoHriMainStoreChipInfo1 {
++ u32 chipMfgID;
++ char chipECLevel[4];
+ };
+
+ struct IoHriMainStoreVpdIdData {
+@@ -73,72 +73,72 @@ struct IoHriMainStoreVpdIdData {
+ char serialNumber[12];
+ };
+
+-struct IoHriMainStoreVpdFruData {
+- char fruLabel[8] __attribute((packed));
+- u8 numberOfSlots __attribute((packed));
+- u8 pluggingType __attribute((packed));
+- u16 slotMapIndex __attribute((packed));
++struct __attribute((packed)) IoHriMainStoreVpdFruData {
++ char fruLabel[8];
++ u8 numberOfSlots;
++ u8 pluggingType;
++ u16 slotMapIndex;
+ };
+
+-struct IoHriMainStoreAdrRangeBlock {
+- void *blockStart __attribute((packed));
+- void *blockEnd __attribute((packed));
+- u32 blockProcChipId __attribute((packed));
++struct __attribute((packed)) IoHriMainStoreAdrRangeBlock {
++ void *blockStart;
++ void *blockEnd;
++ u32 blockProcChipId;
+ };
+
+ #define MaxAreaAdrRangeBlocks 4
+
+-struct IoHriMainStoreArea4 {
+- u32 msVpdFormat __attribute((packed));
+- u8 containedVpdType __attribute((packed));
+- u8 reserved1 __attribute((packed));
+- u16 reserved2 __attribute((packed));
+-
+- u64 msExists __attribute((packed));
+- u64 msFunctional __attribute((packed));
+-
+- u32 memorySize __attribute((packed));
+- u32 procNodeId __attribute((packed));
+-
+- u32 numAdrRangeBlocks __attribute((packed));
+- struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks] __attribute((packed));
+-
+- struct IoHriMainStoreChipInfo1 chipInfo0 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo1 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo2 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo3 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo4 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo5 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo6 __attribute((packed));
+- struct IoHriMainStoreChipInfo1 chipInfo7 __attribute((packed));
+-
+- void *msRamAreaArray __attribute((packed));
+- u32 msRamAreaArrayNumEntries __attribute((packed));
+- u32 msRamAreaArrayEntrySize __attribute((packed));
+-
+- u32 numaDimmExists __attribute((packed));
+- u32 numaDimmFunctional __attribute((packed));
+- void *numaDimmArray __attribute((packed));
+- u32 numaDimmArrayNumEntries __attribute((packed));
+- u32 numaDimmArrayEntrySize __attribute((packed));
+-
+- struct IoHriMainStoreVpdIdData idData __attribute((packed));
+-
+- u64 powerData __attribute((packed));
+- u64 cardAssemblyPartNum __attribute((packed));
+- u64 chipSerialNum __attribute((packed));
+-
+- u64 reserved3 __attribute((packed));
+- char reserved4[16] __attribute((packed));
+-
+- struct IoHriMainStoreVpdFruData fruData __attribute((packed));
+-
+- u8 vpdPortNum __attribute((packed));
+- u8 reserved5 __attribute((packed));
+- u8 frameId __attribute((packed));
+- u8 rackUnit __attribute((packed));
+- char asciiKeywordVpd[256] __attribute((packed));
+- u32 reserved6 __attribute((packed));
++struct __attribute((packed)) IoHriMainStoreArea4 {
++ u32 msVpdFormat;
++ u8 containedVpdType;
++ u8 reserved1;
++ u16 reserved2;
++
++ u64 msExists;
++ u64 msFunctional;
++
++ u32 memorySize;
++ u32 procNodeId;
++
++ u32 numAdrRangeBlocks;
++ struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks];
++
++ struct IoHriMainStoreChipInfo1 chipInfo0;
++ struct IoHriMainStoreChipInfo1 chipInfo1;
++ struct IoHriMainStoreChipInfo1 chipInfo2;
++ struct IoHriMainStoreChipInfo1 chipInfo3;
++ struct IoHriMainStoreChipInfo1 chipInfo4;
++ struct IoHriMainStoreChipInfo1 chipInfo5;
++ struct IoHriMainStoreChipInfo1 chipInfo6;
++ struct IoHriMainStoreChipInfo1 chipInfo7;
++
++ void *msRamAreaArray;
++ u32 msRamAreaArrayNumEntries;
++ u32 msRamAreaArrayEntrySize;
++
++ u32 numaDimmExists;
++ u32 numaDimmFunctional;
++ void *numaDimmArray;
++ u32 numaDimmArrayNumEntries;
++ u32 numaDimmArrayEntrySize;
++
++ struct IoHriMainStoreVpdIdData idData;
++
++ u64 powerData;
++ u64 cardAssemblyPartNum;
++ u64 chipSerialNum;
++
++ u64 reserved3;
++ char reserved4[16];
++
++ struct IoHriMainStoreVpdFruData fruData;
++
++ u8 vpdPortNum;
++ u8 reserved5;
++ u8 frameId;
++ u8 rackUnit;
++ char asciiKeywordVpd[256];
++ u32 reserved6;
+ };
+
+
+diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
+index 1a2c2a5..b5737d6 100644
+--- a/arch/powerpc/platforms/iseries/mf.c
++++ b/arch/powerpc/platforms/iseries/mf.c
+@@ -357,7 +357,7 @@ static int dma_and_signal_ce_msg(char *c
+ */
+ static int shutdown(void)
+ {
+- int rc = kill_proc(1, SIGINT, 1);
++ int rc = kill_cad_pid(SIGINT, 1);
+
+ if (rc) {
+ printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
+@@ -513,7 +513,7 @@ static void handle_ack(struct io_mf_lp_e
+ * parse it enough to know if it is an interrupt or an
+ * acknowledge.
+ */
+-static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs)
++static void hv_handler(struct HvLpEvent *event)
+ {
+ if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
+ if (hvlpevent_is_ack(event))
+@@ -847,7 +847,7 @@ static int mf_get_boot_rtc(struct rtc_ti
+ /* We need to poll here as we are not yet taking interrupts */
+ while (rtc_data.busy) {
+ if (hvlpevent_is_pending())
+- process_hvlpevents(NULL);
++ process_hvlpevents();
+ }
+ return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
+ }
+diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
+index 35bcc98..4aa165e 100644
+--- a/arch/powerpc/platforms/iseries/pci.c
++++ b/arch/powerpc/platforms/iseries/pci.c
+@@ -34,6 +34,7 @@
+ #include <asm/pci-bridge.h>
+ #include <asm/iommu.h>
+ #include <asm/abs_addr.h>
++#include <asm/firmware.h>
+
+ #include <asm/iseries/hv_call_xm.h>
+ #include <asm/iseries/mf.h>
+@@ -176,12 +177,12 @@ void iSeries_pcibios_init(void)
+ }
+ while ((node = of_get_next_child(root, node)) != NULL) {
+ HvBusNumber bus;
+- u32 *busp;
++ const u32 *busp;
+
+ if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
+ continue;
+
+- busp = (u32 *)get_property(node, "bus-range", NULL);
++ busp = get_property(node, "bus-range", NULL);
+ if (busp == NULL)
+ continue;
+ bus = *busp;
+@@ -221,10 +222,9 @@ void __init iSeries_pci_final_fixup(void
+
+ if (node != NULL) {
+ struct pci_dn *pdn = PCI_DN(node);
+- u32 *agent;
++ const u32 *agent;
+
+- agent = (u32 *)get_property(node, "linux,agent-id",
+- NULL);
++ agent = get_property(node, "linux,agent-id", NULL);
+ if ((pdn != NULL) && (agent != NULL)) {
+ u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
+ pdn->bussubno);
+@@ -262,54 +262,6 @@ void __init iSeries_pci_final_fixup(void
+ mf_display_src(0xC9000200);
+ }
+
+-void pcibios_fixup_bus(struct pci_bus *PciBus)
+-{
+-}
+-
+-void pcibios_fixup_resources(struct pci_dev *pdev)
+-{
+-}
+-
+-/*
+- * I/0 Memory copy MUST use mmio commands on iSeries
+- * To do; For performance, include the hv call directly
+- */
+-void iSeries_memset_io(volatile void __iomem *dest, char c, size_t Count)
+-{
+- u8 ByteValue = c;
+- long NumberOfBytes = Count;
+-
+- while (NumberOfBytes > 0) {
+- iSeries_Write_Byte(ByteValue, dest++);
+- -- NumberOfBytes;
+- }
+-}
+-EXPORT_SYMBOL(iSeries_memset_io);
+-
+-void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t count)
+-{
+- char *src = source;
+- long NumberOfBytes = count;
+-
+- while (NumberOfBytes > 0) {
+- iSeries_Write_Byte(*src++, dest++);
+- -- NumberOfBytes;
+- }
+-}
+-EXPORT_SYMBOL(iSeries_memcpy_toio);
+-
+-void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *src, size_t count)
+-{
+- char *dst = dest;
+- long NumberOfBytes = count;
+-
+- while (NumberOfBytes > 0) {
+- *dst++ = iSeries_Read_Byte(src++);
+- -- NumberOfBytes;
+- }
+-}
+-EXPORT_SYMBOL(iSeries_memcpy_fromio);
+-
+ /*
+ * Look down the chain to find the matching Device Device
+ */
+@@ -492,7 +444,7 @@ static inline struct device_node *xlate_
+ * iSeries_Read_Word = Read Word (16 bit)
+ * iSeries_Read_Long = Read Long (32 bit)
+ */
+-u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
++static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
+ {
+ u64 BarOffset;
+ u64 dsa;
+@@ -519,9 +471,8 @@ u8 iSeries_Read_Byte(const volatile void
+
+ return (u8)ret.value;
+ }
+-EXPORT_SYMBOL(iSeries_Read_Byte);
+
+-u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
++static u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
+ {
+ u64 BarOffset;
+ u64 dsa;
+@@ -549,9 +500,8 @@ u16 iSeries_Read_Word(const volatile voi
+
+ return swab16((u16)ret.value);
+ }
+-EXPORT_SYMBOL(iSeries_Read_Word);
+
+-u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
++static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
+ {
+ u64 BarOffset;
+ u64 dsa;
+@@ -579,7 +529,6 @@ u32 iSeries_Read_Long(const volatile voi
+
+ return swab32((u32)ret.value);
+ }
+-EXPORT_SYMBOL(iSeries_Read_Long);
+
+ /*
+ * Write MM I/O Instructions for the iSeries
+@@ -588,7 +537,7 @@ EXPORT_SYMBOL(iSeries_Read_Long);
+ * iSeries_Write_Word = Write Word(16 bit)
+ * iSeries_Write_Long = Write Long(32 bit)
+ */
+-void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
++static void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
+ {
+ u64 BarOffset;
+ u64 dsa;
+@@ -613,9 +562,8 @@ void iSeries_Write_Byte(u8 data, volatil
+ rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
+ } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
+ }
+-EXPORT_SYMBOL(iSeries_Write_Byte);
+
+-void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress)
++static void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress)
+ {
+ u64 BarOffset;
+ u64 dsa;
+@@ -640,9 +588,8 @@ void iSeries_Write_Word(u16 data, volati
+ rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
+ } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
+ }
+-EXPORT_SYMBOL(iSeries_Write_Word);
+
+-void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress)
++static void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress)
+ {
+ u64 BarOffset;
+ u64 dsa;
+@@ -667,4 +614,224 @@ void iSeries_Write_Long(u32 data, volati
+ rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
+ } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
+ }
+-EXPORT_SYMBOL(iSeries_Write_Long);
++
++extern unsigned char __raw_readb(const volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return *(volatile unsigned char __force *)addr;
++}
++EXPORT_SYMBOL(__raw_readb);
++
++extern unsigned short __raw_readw(const volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return *(volatile unsigned short __force *)addr;
++}
++EXPORT_SYMBOL(__raw_readw);
++
++extern unsigned int __raw_readl(const volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return *(volatile unsigned int __force *)addr;
++}
++EXPORT_SYMBOL(__raw_readl);
++
++extern unsigned long __raw_readq(const volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return *(volatile unsigned long __force *)addr;
++}
++EXPORT_SYMBOL(__raw_readq);
++
++extern void __raw_writeb(unsigned char v, volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ *(volatile unsigned char __force *)addr = v;
++}
++EXPORT_SYMBOL(__raw_writeb);
++
++extern void __raw_writew(unsigned short v, volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ *(volatile unsigned short __force *)addr = v;
++}
++EXPORT_SYMBOL(__raw_writew);
++
++extern void __raw_writel(unsigned int v, volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ *(volatile unsigned int __force *)addr = v;
++}
++EXPORT_SYMBOL(__raw_writel);
++
++extern void __raw_writeq(unsigned long v, volatile void __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ *(volatile unsigned long __force *)addr = v;
++}
++EXPORT_SYMBOL(__raw_writeq);
++
++int in_8(const volatile unsigned char __iomem *addr)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return iSeries_Read_Byte(addr);
++ return __in_8(addr);
++}
++EXPORT_SYMBOL(in_8);
++
++void out_8(volatile unsigned char __iomem *addr, int val)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ iSeries_Write_Byte(val, addr);
++ else
++ __out_8(addr, val);
++}
++EXPORT_SYMBOL(out_8);
++
++int in_le16(const volatile unsigned short __iomem *addr)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return iSeries_Read_Word(addr);
++ return __in_le16(addr);
++}
++EXPORT_SYMBOL(in_le16);
++
++int in_be16(const volatile unsigned short __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return __in_be16(addr);
++}
++EXPORT_SYMBOL(in_be16);
++
++void out_le16(volatile unsigned short __iomem *addr, int val)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ iSeries_Write_Word(val, addr);
++ else
++ __out_le16(addr, val);
++}
++EXPORT_SYMBOL(out_le16);
++
++void out_be16(volatile unsigned short __iomem *addr, int val)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ __out_be16(addr, val);
++}
++EXPORT_SYMBOL(out_be16);
++
++unsigned in_le32(const volatile unsigned __iomem *addr)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return iSeries_Read_Long(addr);
++ return __in_le32(addr);
++}
++EXPORT_SYMBOL(in_le32);
++
++unsigned in_be32(const volatile unsigned __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return __in_be32(addr);
++}
++EXPORT_SYMBOL(in_be32);
++
++void out_le32(volatile unsigned __iomem *addr, int val)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ iSeries_Write_Long(val, addr);
++ else
++ __out_le32(addr, val);
++}
++EXPORT_SYMBOL(out_le32);
++
++void out_be32(volatile unsigned __iomem *addr, int val)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ __out_be32(addr, val);
++}
++EXPORT_SYMBOL(out_be32);
++
++unsigned long in_le64(const volatile unsigned long __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return __in_le64(addr);
++}
++EXPORT_SYMBOL(in_le64);
++
++unsigned long in_be64(const volatile unsigned long __iomem *addr)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ return __in_be64(addr);
++}
++EXPORT_SYMBOL(in_be64);
++
++void out_le64(volatile unsigned long __iomem *addr, unsigned long val)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ __out_le64(addr, val);
++}
++EXPORT_SYMBOL(out_le64);
++
++void out_be64(volatile unsigned long __iomem *addr, unsigned long val)
++{
++ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
++
++ __out_be64(addr, val);
++}
++EXPORT_SYMBOL(out_be64);
++
++void memset_io(volatile void __iomem *addr, int c, unsigned long n)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
++ volatile char __iomem *d = addr;
++
++ while (n-- > 0) {
++ iSeries_Write_Byte(c, d++);
++ }
++ } else
++ eeh_memset_io(addr, c, n);
++}
++EXPORT_SYMBOL(memset_io);
++
++void memcpy_fromio(void *dest, const volatile void __iomem *src,
++ unsigned long n)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
++ char *d = dest;
++ const volatile char __iomem *s = src;
++
++ while (n-- > 0) {
++ *d++ = iSeries_Read_Byte(s++);
++ }
++ } else
++ eeh_memcpy_fromio(dest, src, n);
++}
++EXPORT_SYMBOL(memcpy_fromio);
++
++void memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
++{
++ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
++ const char *s = src;
++ volatile char __iomem *d = dest;
++
++ while (n-- > 0) {
++ iSeries_Write_Byte(*s++, d++);
++ }
++ } else
++ eeh_memcpy_toio(dest, src, n);
++}
++EXPORT_SYMBOL(memcpy_toio);
+diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
+index c9605d7..6f73469 100644
+--- a/arch/powerpc/platforms/iseries/setup.c
++++ b/arch/powerpc/platforms/iseries/setup.c
+@@ -59,6 +59,7 @@
+ #include "irq.h"
+ #include "vpd_areas.h"
+ #include "processor_vpd.h"
++#include "it_lp_naca.h"
+ #include "main_store.h"
+ #include "call_sm.h"
+ #include "call_hpt.h"
+@@ -648,15 +649,21 @@ static void iseries_dedicated_idle(void)
+ void __init iSeries_init_IRQ(void) { }
+ #endif
+
++/*
++ * iSeries has no legacy IO, anything calling this function has to
++ * fail or bad things will happen
++ */
++static int iseries_check_legacy_ioport(unsigned int baseport)
++{
++ return -ENODEV;
++}
++
+ static int __init iseries_probe(void)
+ {
+ unsigned long root = of_get_flat_dt_root();
+ if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
+ return 0;
+
+- powerpc_firmware_features |= FW_FEATURE_ISERIES;
+- powerpc_firmware_features |= FW_FEATURE_LPAR;
+-
+ hpte_init_iSeries();
+
+ return 1;
+@@ -679,6 +686,7 @@ define_machine(iseries) {
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = iSeries_progress,
+ .probe = iseries_probe,
++ .check_legacy_ioport = iseries_check_legacy_ioport,
+ /* XXX Implement enable_pmcs for iSeries */
+ };
+
+@@ -686,6 +694,14 @@ void * __init iSeries_early_setup(void)
+ {
+ unsigned long phys_mem_size;
+
++ /* Identify CPU type. This is done again by the common code later
++ * on but calling this function multiple times is fine.
++ */
++ identify_cpu(0);
++
++ powerpc_firmware_features |= FW_FEATURE_ISERIES;
++ powerpc_firmware_features |= FW_FEATURE_LPAR;
++
+ iSeries_fixup_klimit();
+
+ /*
+diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
+index 2eb095e..aee5908 100644
+--- a/arch/powerpc/platforms/iseries/smp.c
++++ b/arch/powerpc/platforms/iseries/smp.c
+@@ -43,9 +43,11 @@
+ #include <asm/cputable.h>
+ #include <asm/system.h>
+
++#include "smp.h"
++
+ static unsigned long iSeries_smp_message[NR_CPUS];
+
+-void iSeries_smp_message_recv(struct pt_regs *regs)
++void iSeries_smp_message_recv(void)
+ {
+ int cpu = smp_processor_id();
+ int msg;
+@@ -55,7 +57,7 @@ void iSeries_smp_message_recv(struct pt_
+
+ for (msg = 0; msg < 4; msg++)
+ if (test_and_clear_bit(msg, &iSeries_smp_message[cpu]))
+- smp_message_recv(msg, regs);
++ smp_message_recv(msg);
+ }
+
+ static inline void smp_iSeries_do_message(int cpu, int msg)
+diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h
+new file mode 100644
+index 0000000..d501f7d
+--- /dev/null
++++ b/arch/powerpc/platforms/iseries/smp.h
+@@ -0,0 +1,6 @@
++#ifndef _PLATFORMS_ISERIES_SMP_H
++#define _PLATFORMS_ISERIES_SMP_H
++
++extern void iSeries_smp_message_recv(void);
++
++#endif /* _PLATFORMS_ISERIES_SMP_H */
+diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
+index 622a301..04e07e5 100644
+--- a/arch/powerpc/platforms/iseries/viopath.c
++++ b/arch/powerpc/platforms/iseries/viopath.c
+@@ -41,8 +41,8 @@
+
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
++#include <asm/prom.h>
+ #include <asm/iseries/hv_types.h>
+-#include <asm/iseries/it_exp_vpd_panel.h>
+ #include <asm/iseries/hv_lp_event.h>
+ #include <asm/iseries/hv_lp_config.h>
+ #include <asm/iseries/mf.h>
+@@ -116,6 +116,8 @@ static int proc_viopath_show(struct seq_
+ dma_addr_t handle;
+ HvLpEvent_Rc hvrc;
+ DECLARE_MUTEX_LOCKED(Semaphore);
++ struct device_node *node;
++ const char *sysid;
+
+ buf = kmalloc(HW_PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+@@ -143,20 +145,26 @@ static int proc_viopath_show(struct seq_
+
+ buf[HW_PAGE_SIZE-1] = '\0';
+ seq_printf(m, "%s", buf);
+- seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
+- seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n",
+- e2a(xItExtVpdPanel.mfgID[2]),
+- e2a(xItExtVpdPanel.mfgID[3]),
+- e2a(xItExtVpdPanel.systemSerial[1]),
+- e2a(xItExtVpdPanel.systemSerial[2]),
+- e2a(xItExtVpdPanel.systemSerial[3]),
+- e2a(xItExtVpdPanel.systemSerial[4]),
+- e2a(xItExtVpdPanel.systemSerial[5]));
+
+ dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ kfree(buf);
+
++ seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
++
++ node = of_find_node_by_path("/");
++ sysid = NULL;
++ if (node != NULL)
++ sysid = get_property(node, "system-id", NULL);
++
++ if (sysid == NULL)
++ seq_printf(m, "SRLNBR=<UNKNOWN>\n");
++ else
++ /* Skip "IBM," on front of serial number, see dt.c */
++ seq_printf(m, "SRLNBR=%s\n", sysid + 4);
++
++ of_node_put(node);
++
+ return 0;
+ }
+
+@@ -370,7 +378,7 @@ void vio_set_hostlp(void)
+ }
+ EXPORT_SYMBOL(vio_set_hostlp);
+
+-static void vio_handleEvent(struct HvLpEvent *event, struct pt_regs *regs)
++static void vio_handleEvent(struct HvLpEvent *event)
+ {
+ HvLpIndex remoteLp;
+ int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)
+diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c
+index 23a6d1e..9f83878 100644
+--- a/arch/powerpc/platforms/iseries/vpdinfo.c
++++ b/arch/powerpc/platforms/iseries/vpdinfo.c
+@@ -188,7 +188,7 @@ static void __init iSeries_Parse_Vpd(u8
+ {
+ u8 *TagPtr = VpdData;
+ int DataLen = VpdDataLen - 3;
+- u8 PhbId;
++ u8 PhbId = 0xff;
+
+ while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) {
+ int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
+@@ -205,15 +205,16 @@ static void __init iSeries_Parse_Vpd(u8
+ }
+ }
+
+-static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
++static int __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
+ u8 *frame, char card[4])
+ {
++ int status = 0;
+ int BusVpdLen = 0;
+ u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
+
+ if (BusVpdPtr == NULL) {
+ printk("PCI: Bus VPD Buffer allocation failure.\n");
+- return;
++ return 0;
+ }
+ BusVpdLen = HvCallPci_getBusVpd(bus, iseries_hv_addr(BusVpdPtr),
+ BUS_VPDSIZE);
+@@ -228,8 +229,10 @@ static void __init iSeries_Get_Location_
+ goto out_free;
+ }
+ iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card);
++ status = 1;
+ out_free:
+ kfree(BusVpdPtr);
++ return status;
+ }
+
+ /*
+@@ -246,7 +249,7 @@ void __init iSeries_Device_Information(s
+ struct device_node *DevNode = PciDev->sysdata;
+ struct pci_dn *pdn;
+ u16 bus;
+- u8 frame;
++ u8 frame = 0;
+ char card[4];
+ HvSubBusNumber subbus;
+ HvAgentId agent;
+@@ -262,10 +265,11 @@ void __init iSeries_Device_Information(s
+ subbus = pdn->bussubno;
+ agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
+ ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
+- iSeries_Get_Location_Code(bus, agent, &frame, card);
+
+- printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, Card %4s ",
+- count, bus, PCI_SLOT(PciDev->devfn), PciDev->vendor,
+- frame, card);
+- printk("0x%04X\n", (int)(PciDev->class >> 8));
++ if (iSeries_Get_Location_Code(bus, agent, &frame, card)) {
++ printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
++ "Card %4s 0x%04X\n", count, bus,
++ PCI_SLOT(PciDev->devfn), PciDev->vendor, frame,
++ card, (int)(PciDev->class >> 8));
++ }
+ }
+diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
+index 63a1670..63b4d1b 100644
+--- a/arch/powerpc/platforms/maple/pci.c
++++ b/arch/powerpc/platforms/maple/pci.c
+@@ -8,7 +8,7 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#define DEBUG
++#undef DEBUG
+
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
+@@ -16,6 +16,7 @@
+ #include <linux/string.h>
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
++#include <linux/irq.h>
+
+ #include <asm/sections.h>
+ #include <asm/io.h>
+@@ -33,21 +34,21 @@
+ #define DBG(x...)
+ #endif
+
+-static struct pci_controller *u3_agp, *u3_ht;
++static struct pci_controller *u3_agp, *u3_ht, *u4_pcie;
+
+ static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
+ {
+ for (; node != 0;node = node->sibling) {
+- int * bus_range;
+- unsigned int *class_code;
++ const int *bus_range;
++ const unsigned int *class_code;
+ int len;
+
+ /* For PCI<->PCI bridges or CardBus bridges, we go down */
+- class_code = (unsigned int *) get_property(node, "class-code", NULL);
++ class_code = get_property(node, "class-code", NULL);
+ if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+ continue;
+- bus_range = (int *) get_property(node, "bus-range", &len);
++ bus_range = get_property(node, "bus-range", &len);
+ if (bus_range != NULL && len > 2 * sizeof(int)) {
+ if (bus_range[1] > higher)
+ higher = bus_range[1];
+@@ -65,42 +66,48 @@ static int __init fixup_one_level_bus_ra
+ */
+ static void __init fixup_bus_range(struct device_node *bridge)
+ {
+- int * bus_range;
++ int *bus_range;
++ struct property *prop;
+ int len;
+
+ /* Lookup the "bus-range" property for the hose */
+- bus_range = (int *) get_property(bridge, "bus-range", &len);
+- if (bus_range == NULL || len < 2 * sizeof(int)) {
++ prop = of_find_property(bridge, "bus-range", &len);
++ if (prop == NULL || prop->value == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ bridge->full_name);
+ return;
+ }
++ bus_range = (int *)prop->value;
+ bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+ }
+
+
+-#define U3_AGP_CFA0(devfn, off) \
+- ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+- | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+- | (((unsigned long)(off)) & 0xFCUL))
++static unsigned long u3_agp_cfa0(u8 devfn, u8 off)
++{
++ return (1 << (unsigned long)PCI_SLOT(devfn)) |
++ ((unsigned long)PCI_FUNC(devfn) << 8) |
++ ((unsigned long)off & 0xFCUL);
++}
+
+-#define U3_AGP_CFA1(bus, devfn, off) \
+- ((((unsigned long)(bus)) << 16) \
+- |(((unsigned long)(devfn)) << 8) \
+- |(((unsigned long)(off)) & 0xFCUL) \
+- |1UL)
++static unsigned long u3_agp_cfa1(u8 bus, u8 devfn, u8 off)
++{
++ return ((unsigned long)bus << 16) |
++ ((unsigned long)devfn << 8) |
++ ((unsigned long)off & 0xFCUL) |
++ 1UL;
++}
+
+-static unsigned long u3_agp_cfg_access(struct pci_controller* hose,
++static volatile void __iomem *u3_agp_cfg_access(struct pci_controller* hose,
+ u8 bus, u8 dev_fn, u8 offset)
+ {
+ unsigned int caddr;
+
+ if (bus == hose->first_busno) {
+ if (dev_fn < (11 << 3))
+- return 0;
+- caddr = U3_AGP_CFA0(dev_fn, offset);
++ return NULL;
++ caddr = u3_agp_cfa0(dev_fn, offset);
+ } else
+- caddr = U3_AGP_CFA1(bus, dev_fn, offset);
++ caddr = u3_agp_cfa1(bus, dev_fn, offset);
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ do {
+@@ -108,14 +115,14 @@ static unsigned long u3_agp_cfg_access(s
+ } while (in_le32(hose->cfg_addr) != caddr);
+
+ offset &= 0x07;
+- return ((unsigned long)hose->cfg_data) + offset;
++ return hose->cfg_data + offset;
+ }
+
+ static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 *val)
+ {
+ struct pci_controller *hose;
+- unsigned long addr;
++ volatile void __iomem *addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+@@ -130,13 +137,13 @@ static int u3_agp_read_config(struct pci
+ */
+ switch (len) {
+ case 1:
+- *val = in_8((u8 *)addr);
++ *val = in_8(addr);
+ break;
+ case 2:
+- *val = in_le16((u16 *)addr);
++ *val = in_le16(addr);
+ break;
+ default:
+- *val = in_le32((u32 *)addr);
++ *val = in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+@@ -146,7 +153,7 @@ static int u3_agp_write_config(struct pc
+ int offset, int len, u32 val)
+ {
+ struct pci_controller *hose;
+- unsigned long addr;
++ volatile void __iomem *addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+@@ -161,16 +168,16 @@ static int u3_agp_write_config(struct pc
+ */
+ switch (len) {
+ case 1:
+- out_8((u8 *)addr, val);
+- (void) in_8((u8 *)addr);
++ out_8(addr, val);
++ (void) in_8(addr);
+ break;
+ case 2:
+- out_le16((u16 *)addr, val);
+- (void) in_le16((u16 *)addr);
++ out_le16(addr, val);
++ (void) in_le16(addr);
+ break;
+ default:
+- out_le32((u32 *)addr, val);
+- (void) in_le32((u32 *)addr);
++ out_le32(addr, val);
++ (void) in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+@@ -182,35 +189,40 @@ static struct pci_ops u3_agp_pci_ops =
+ u3_agp_write_config
+ };
+
++static unsigned long u3_ht_cfa0(u8 devfn, u8 off)
++{
++ return (devfn << 8) | off;
++}
+
+-#define U3_HT_CFA0(devfn, off) \
+- ((((unsigned long)devfn) << 8) | offset)
+-#define U3_HT_CFA1(bus, devfn, off) \
+- (U3_HT_CFA0(devfn, off) \
+- + (((unsigned long)bus) << 16) \
+- + 0x01000000UL)
++static unsigned long u3_ht_cfa1(u8 bus, u8 devfn, u8 off)
++{
++ return u3_ht_cfa0(devfn, off) + (bus << 16) + 0x01000000UL;
++}
+
+-static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
++static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose,
+ u8 bus, u8 devfn, u8 offset)
+ {
+ if (bus == hose->first_busno) {
+ if (PCI_SLOT(devfn) == 0)
+- return 0;
+- return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
++ return NULL;
++ return hose->cfg_data + u3_ht_cfa0(devfn, offset);
+ } else
+- return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
++ return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset);
+ }
+
+ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 *val)
+ {
+ struct pci_controller *hose;
+- unsigned long addr;
++ volatile void __iomem *addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
++ if (offset > 0xff)
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+@@ -221,13 +233,13 @@ static int u3_ht_read_config(struct pci_
+ */
+ switch (len) {
+ case 1:
+- *val = in_8((u8 *)addr);
++ *val = in_8(addr);
+ break;
+ case 2:
+- *val = in_le16((u16 *)addr);
++ *val = in_le16(addr);
+ break;
+ default:
+- *val = in_le32((u32 *)addr);
++ *val = in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+@@ -237,12 +249,15 @@ static int u3_ht_write_config(struct pci
+ int offset, int len, u32 val)
+ {
+ struct pci_controller *hose;
+- unsigned long addr;
++ volatile void __iomem *addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
++ if (offset > 0xff)
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+@@ -252,16 +267,16 @@ static int u3_ht_write_config(struct pci
+ */
+ switch (len) {
+ case 1:
+- out_8((u8 *)addr, val);
+- (void) in_8((u8 *)addr);
++ out_8(addr, val);
++ (void) in_8(addr);
+ break;
+ case 2:
+- out_le16((u16 *)addr, val);
+- (void) in_le16((u16 *)addr);
++ out_le16(addr, val);
++ (void) in_le16(addr);
+ break;
+ default:
+- out_le32((u32 *)addr, val);
+- (void) in_le32((u32 *)addr);
++ out_le32(addr, val);
++ (void) in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+@@ -273,6 +288,114 @@ static struct pci_ops u3_ht_pci_ops =
+ u3_ht_write_config
+ };
+
++static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off)
++{
++ return (1 << PCI_SLOT(devfn)) |
++ (PCI_FUNC(devfn) << 8) |
++ ((off >> 8) << 28) |
++ (off & 0xfcu);
++}
++
++static unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn,
++ unsigned int off)
++{
++ return (bus << 16) |
++ (devfn << 8) |
++ ((off >> 8) << 28) |
++ (off & 0xfcu) | 1u;
++}
++
++static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose,
++ u8 bus, u8 dev_fn, int offset)
++{
++ unsigned int caddr;
++
++ if (bus == hose->first_busno)
++ caddr = u4_pcie_cfa0(dev_fn, offset);
++ else
++ caddr = u4_pcie_cfa1(bus, dev_fn, offset);
++
++ /* Uninorth will return garbage if we don't read back the value ! */
++ do {
++ out_le32(hose->cfg_addr, caddr);
++ } while (in_le32(hose->cfg_addr) != caddr);
++
++ offset &= 0x03;
++ return hose->cfg_data + offset;
++}
++
++static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
++ int offset, int len, u32 *val)
++{
++ struct pci_controller *hose;
++ volatile void __iomem *addr;
++
++ hose = pci_bus_to_host(bus);
++ if (hose == NULL)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ if (offset >= 0x1000)
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
++ if (!addr)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ /*
++ * Note: the caller has already checked that offset is
++ * suitably aligned and that len is 1, 2 or 4.
++ */
++ switch (len) {
++ case 1:
++ *val = in_8(addr);
++ break;
++ case 2:
++ *val = in_le16(addr);
++ break;
++ default:
++ *val = in_le32(addr);
++ break;
++ }
++ return PCIBIOS_SUCCESSFUL;
++}
++static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
++ int offset, int len, u32 val)
++{
++ struct pci_controller *hose;
++ volatile void __iomem *addr;
++
++ hose = pci_bus_to_host(bus);
++ if (hose == NULL)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ if (offset >= 0x1000)
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
++ if (!addr)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ /*
++ * Note: the caller has already checked that offset is
++ * suitably aligned and that len is 1, 2 or 4.
++ */
++ switch (len) {
++ case 1:
++ out_8(addr, val);
++ (void) in_8(addr);
++ break;
++ case 2:
++ out_le16(addr, val);
++ (void) in_le16(addr);
++ break;
++ default:
++ out_le32(addr, val);
++ (void) in_le32(addr);
++ break;
++ }
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops u4_pcie_pci_ops =
++{
++ u4_pcie_read_config,
++ u4_pcie_write_config
++};
++
+ static void __init setup_u3_agp(struct pci_controller* hose)
+ {
+ /* On G5, we move AGP up to high bus number so we don't need
+@@ -293,6 +416,26 @@ static void __init setup_u3_agp(struct p
+ u3_agp = hose;
+ }
+
++static void __init setup_u4_pcie(struct pci_controller* hose)
++{
++ /* We currently only implement the "non-atomic" config space, to
++ * be optimised later.
++ */
++ hose->ops = &u4_pcie_pci_ops;
++ hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
++ hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
++
++ /* The bus contains a bridge from root -> device, we need to
++ * make it visible on bus 0 so that we pick the right type
++ * of config cycles. If we didn't, we would have to force all
++ * config cycles to be type 1. So we override the "bus-range"
++ * property here
++ */
++ hose->first_busno = 0x00;
++ hose->last_busno = 0xff;
++ u4_pcie = hose;
++}
++
+ static void __init setup_u3_ht(struct pci_controller* hose)
+ {
+ hose->ops = &u3_ht_pci_ops;
+@@ -301,7 +444,7 @@ static void __init setup_u3_ht(struct pc
+ * the reg address cell, we shall fix that by killing struct
+ * reg_property and using some accessor functions instead
+ */
+- hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);
++ hose->cfg_data = ioremap(0xf2000000, 0x02000000);
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xef;
+@@ -314,12 +457,12 @@ static int __init add_bridge(struct devi
+ int len;
+ struct pci_controller *hose;
+ char* disp_name;
+- int *bus_range;
++ const int *bus_range;
+ int primary = 1;
+
+ DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+- bus_range = (int *) get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+ dev->full_name);
+@@ -340,6 +483,10 @@ static int __init add_bridge(struct devi
+ setup_u3_ht(hose);
+ disp_name = "U3-HT";
+ primary = 1;
++ } else if (device_is_compatible(dev, "u4-pcie")) {
++ setup_u4_pcie(hose);
++ disp_name = "U4-PCIE";
++ primary = 0;
+ }
+ printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
+ disp_name, hose->first_busno, hose->last_busno);
+@@ -347,7 +494,6 @@ static int __init add_bridge(struct devi
+ /* Interpret the "ranges" property */
+ /* This also maps the I/O region and sets isa_io/mem_base */
+ pci_process_bridge_OF_ranges(hose, dev, primary);
+- pci_setup_phb_io(hose, primary);
+
+ /* Fixup "bus-range" OF property */
+ fixup_bus_range(dev);
+@@ -362,8 +508,30 @@ void __init maple_pcibios_fixup(void)
+
+ DBG(" -> maple_pcibios_fixup\n");
+
+- for_each_pci_dev(dev)
++ for_each_pci_dev(dev) {
++ /* Fixup IRQ for PCIe host */
++ if (u4_pcie != NULL && dev->bus->number == 0 &&
++ pci_bus_to_host(dev->bus) == u4_pcie) {
++ printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
++ dev->irq = irq_create_mapping(NULL, 1);
++ if (dev->irq != NO_IRQ)
++ set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
++ continue;
++ }
++
++ /* Hide AMD8111 IDE interrupt when in legacy mode so
++ * the driver calls pci_get_legacy_ide_irq()
++ */
++ if (dev->vendor == PCI_VENDOR_ID_AMD &&
++ dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
++ (dev->class & 5) != 5) {
++ dev->irq = NO_IRQ;
++ continue;
++ }
++
++ /* For all others, map the interrupt from the device-tree */
+ pci_read_irq_line(dev);
++ }
+
+ DBG(" <- maple_pcibios_fixup\n");
+ }
+@@ -374,8 +542,10 @@ static void __init maple_fixup_phb_resou
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+ unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
++
+ hose->io_resource.start += offset;
+ hose->io_resource.end += offset;
++
+ printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
+ hose->global_number,
+ (unsigned long long)hose->io_resource.start,
+@@ -417,6 +587,19 @@ void __init maple_pci_init(void)
+ if (ht && add_bridge(ht) != 0)
+ of_node_put(ht);
+
++ /*
++ * We need to call pci_setup_phb_io for the HT bridge first
++ * so it gets the I/O port numbers starting at 0, and we
++ * need to call it for the AGP bridge after that so it gets
++ * small positive I/O port numbers.
++ */
++ if (u3_ht)
++ pci_setup_phb_io(u3_ht, 1);
++ if (u3_agp)
++ pci_setup_phb_io(u3_agp, 0);
++ if (u4_pcie)
++ pci_setup_phb_io(u4_pcie, 0);
++
+ /* Fixup the IO resources on our host bridges as the common code
+ * does it only for childs of the host bridges
+ */
+@@ -451,8 +634,11 @@ int maple_pci_get_legacy_ide_irq(struct
+ return defirq;
+
+ np = pci_device_to_OF_node(pdev);
+- if (np == NULL)
++ if (np == NULL) {
++ printk("Failed to locate OF node for IDE %s\n",
++ pci_name(pdev));
+ return defirq;
++ }
+ irq = irq_of_parse_and_map(np, channel & 0x1);
+ if (irq == NO_IRQ) {
+ printk("Failed to map onboard IDE interrupt for channel %d\n",
+@@ -465,6 +651,9 @@ int maple_pci_get_legacy_ide_irq(struct
+ /* XXX: To remove once all firmwares are ok */
+ static void fixup_maple_ide(struct pci_dev* dev)
+ {
++ if (!machine_is(maple))
++ return;
++
+ #if 0 /* Enable this to enable IDE port 0 */
+ {
+ u8 v;
+@@ -481,7 +670,7 @@ static void fixup_maple_ide(struct pci_d
+ dev->resource[4].start = 0xcc00;
+ dev->resource[4].end = 0xcc10;
+ #endif
+-#if 1 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */
++#if 0 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */
+ {
+ struct pci_dev *apicdev;
+ u32 v;
+diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
+index 57567df..fe6b9bf 100644
+--- a/arch/powerpc/platforms/maple/setup.c
++++ b/arch/powerpc/platforms/maple/setup.c
+@@ -99,8 +99,7 @@ static unsigned long maple_find_nvram_ba
+ static void maple_restart(char *cmd)
+ {
+ unsigned int maple_nvram_base;
+- unsigned int maple_nvram_offset;
+- unsigned int maple_nvram_command;
++ const unsigned int *maple_nvram_offset, *maple_nvram_command;
+ struct device_node *sp;
+
+ maple_nvram_base = maple_find_nvram_base();
+@@ -113,14 +112,12 @@ static void maple_restart(char *cmd)
+ printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
+ goto fail;
+ }
+- maple_nvram_offset = *(unsigned int*) get_property(sp,
+- "restart-addr", NULL);
+- maple_nvram_command = *(unsigned int*) get_property(sp,
+- "restart-value", NULL);
++ maple_nvram_offset = get_property(sp, "restart-addr", NULL);
++ maple_nvram_command = get_property(sp, "restart-value", NULL);
+ of_node_put(sp);
+
+ /* send command */
+- outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset);
++ outb_p(*maple_nvram_command, maple_nvram_base + *maple_nvram_offset);
+ for (;;) ;
+ fail:
+ printk(KERN_EMERG "Maple: Manual Restart Required\n");
+@@ -129,8 +126,7 @@ static void maple_restart(char *cmd)
+ static void maple_power_off(void)
+ {
+ unsigned int maple_nvram_base;
+- unsigned int maple_nvram_offset;
+- unsigned int maple_nvram_command;
++ const unsigned int *maple_nvram_offset, *maple_nvram_command;
+ struct device_node *sp;
+
+ maple_nvram_base = maple_find_nvram_base();
+@@ -143,14 +139,12 @@ static void maple_power_off(void)
+ printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
+ goto fail;
+ }
+- maple_nvram_offset = *(unsigned int*) get_property(sp,
+- "power-off-addr", NULL);
+- maple_nvram_command = *(unsigned int*) get_property(sp,
+- "power-off-value", NULL);
++ maple_nvram_offset = get_property(sp, "power-off-addr", NULL);
++ maple_nvram_command = get_property(sp, "power-off-value", NULL);
+ of_node_put(sp);
+
+ /* send command */
+- outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset);
++ outb_p(*maple_nvram_command, maple_nvram_base + *maple_nvram_offset);
+ for (;;) ;
+ fail:
+ printk(KERN_EMERG "Maple: Manual Power-Down Required\n");
+@@ -211,7 +205,7 @@ static void __init maple_init_early(void
+ static void __init maple_init_IRQ(void)
+ {
+ struct device_node *root, *np, *mpic_node = NULL;
+- unsigned int *opprop;
++ const unsigned int *opprop;
+ unsigned long openpic_addr = 0;
+ int naddr, n, i, opplen, has_isus = 0;
+ struct mpic *mpic;
+@@ -241,8 +235,7 @@ static void __init maple_init_IRQ(void)
+ /* Find address list in /platform-open-pic */
+ root = of_find_node_by_path("/");
+ naddr = prom_n_addr_cells(root);
+- opprop = (unsigned int *) get_property(root, "platform-open-pic",
+- &opplen);
++ opprop = get_property(root, "platform-open-pic", &opplen);
+ if (opprop != 0) {
+ openpic_addr = of_read_number(opprop, naddr);
+ has_isus = (opplen > naddr);
+diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
+new file mode 100644
+index 0000000..1be1a99
+--- /dev/null
++++ b/arch/powerpc/platforms/pasemi/Makefile
+@@ -0,0 +1 @@
++obj-y += setup.o pci.o time.o
+diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
+new file mode 100644
+index 0000000..fd71d72
+--- /dev/null
++++ b/arch/powerpc/platforms/pasemi/pasemi.h
+@@ -0,0 +1,8 @@
++#ifndef _PASEMI_PASEMI_H
++#define _PASEMI_PASEMI_H
++
++extern unsigned long pas_get_boot_time(void);
++extern void pas_pci_init(void);
++extern void pas_pcibios_fixup(void);
++
++#endif /* _PASEMI_PASEMI_H */
+diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
+new file mode 100644
+index 0000000..39020c1
+--- /dev/null
++++ b/arch/powerpc/platforms/pasemi/pci.c
+@@ -0,0 +1,198 @@
++/*
++ * Copyright (C) 2006 PA Semi, Inc
++ *
++ * Authors: Kip Walker, PA Semi
++ * Olof Johansson, PA Semi
++ *
++ * Maintained by: Olof Johansson <olof at lixom.net>
++ *
++ * Based on arch/powerpc/platforms/maple/pci.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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/pci.h>
++
++#include <asm/pci-bridge.h>
++#include <asm/machdep.h>
++
++#include <asm/ppc-pci.h>
++
++#define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
++
++#define CONFIG_OFFSET_VALID(off) ((off) < 4096)
++
++static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
++ u8 bus, u8 devfn, int offset)
++{
++ return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset);
++}
++
++static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
++ int offset, int len, u32 *val)
++{
++ struct pci_controller *hose;
++ void volatile __iomem *addr;
++
++ hose = pci_bus_to_host(bus);
++ if (!hose)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ if (!CONFIG_OFFSET_VALID(offset))
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++
++ addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
++
++ /*
++ * Note: the caller has already checked that offset is
++ * suitably aligned and that len is 1, 2 or 4.
++ */
++ switch (len) {
++ case 1:
++ *val = in_8(addr);
++ break;
++ case 2:
++ *val = in_le16(addr);
++ break;
++ default:
++ *val = in_le32(addr);
++ break;
++ }
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
++ int offset, int len, u32 val)
++{
++ struct pci_controller *hose;
++ void volatile __iomem *addr;
++
++ hose = pci_bus_to_host(bus);
++ if (!hose)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ if (!CONFIG_OFFSET_VALID(offset))
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++
++ addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
++
++ /*
++ * Note: the caller has already checked that offset is
++ * suitably aligned and that len is 1, 2 or 4.
++ */
++ switch (len) {
++ case 1:
++ out_8(addr, val);
++ (void) in_8(addr);
++ break;
++ case 2:
++ out_le16(addr, val);
++ (void) in_le16(addr);
++ break;
++ default:
++ out_le32(addr, val);
++ (void) in_le32(addr);
++ break;
++ }
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops pa_pxp_ops = {
++ pa_pxp_read_config,
++ pa_pxp_write_config,
++};
++
++static void __init setup_pa_pxp(struct pci_controller *hose)
++{
++ hose->ops = &pa_pxp_ops;
++ hose->cfg_data = ioremap(0xe0000000, 0x10000000);
++}
++
++static int __init add_bridge(struct device_node *dev)
++{
++ struct pci_controller *hose;
++
++ pr_debug("Adding PCI host bridge %s\n", dev->full_name);
++
++ hose = pcibios_alloc_controller(dev);
++ if (!hose)
++ return -ENOMEM;
++
++ hose->first_busno = 0;
++ hose->last_busno = 0xff;
++
++ setup_pa_pxp(hose);
++
++ printk(KERN_INFO "Found PA-PXP PCI host bridge.\n");
++
++ /* Interpret the "ranges" property */
++ /* This also maps the I/O region and sets isa_io/mem_base */
++ pci_process_bridge_OF_ranges(hose, dev, 1);
++ pci_setup_phb_io(hose, 1);
++
++ return 0;
++}
++
++
++void __init pas_pcibios_fixup(void)
++{
++ struct pci_dev *dev = NULL;
++
++ for_each_pci_dev(dev)
++ pci_read_irq_line(dev);
++}
++
++static void __init pas_fixup_phb_resources(void)
++{
++ struct pci_controller *hose, *tmp;
++
++ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
++ unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
++ hose->io_resource.start += offset;
++ hose->io_resource.end += offset;
++ printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
++ hose->global_number,
++ hose->io_resource.start, hose->io_resource.end);
++ }
++}
++
++
++void __init pas_pci_init(void)
++{
++ struct device_node *np, *root;
++
++ root = of_find_node_by_path("/");
++ if (!root) {
++ printk(KERN_CRIT "pas_pci_init: can't find root "
++ "of device tree\n");
++ return;
++ }
++
++ for (np = NULL; (np = of_get_next_child(root, np)) != NULL;)
++ if (np->name && !strcmp(np->name, "pxp") && !add_bridge(np))
++ of_node_get(np);
++
++ of_node_put(root);
++
++ pas_fixup_phb_resources();
++
++ /* Setup the linkage between OF nodes and PHBs */
++ pci_devs_phb_init();
++
++ /* Use the common resource allocation mechanism */
++ pci_probe_only = 1;
++}
+diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
+new file mode 100644
+index 0000000..106896c
+--- /dev/null
++++ b/arch/powerpc/platforms/pasemi/setup.c
+@@ -0,0 +1,187 @@
++/*
++ * Copyright (C) 2006 PA Semi, Inc
++ *
++ * Authors: Kip Walker, PA Semi
++ * Olof Johansson, PA Semi
++ *
++ * Maintained by: Olof Johansson <olof at lixom.net>
++ *
++ * Based on arch/powerpc/platforms/maple/setup.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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/errno.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/console.h>
++
++#include <asm/prom.h>
++#include <asm/system.h>
++#include <asm/iommu.h>
++#include <asm/machdep.h>
++#include <asm/mpic.h>
++#include <asm/smp.h>
++#include <asm/time.h>
++
++#include "pasemi.h"
++
++static void pas_restart(char *cmd)
++{
++ printk("restart unimplemented, looping...\n");
++ for (;;) ;
++}
++
++static void pas_power_off(void)
++{
++ printk("power off unimplemented, looping...\n");
++ for (;;) ;
++}
++
++static void pas_halt(void)
++{
++ pas_power_off();
++}
++
++#ifdef CONFIG_SMP
++struct smp_ops_t pas_smp_ops = {
++ .probe = smp_mpic_probe,
++ .message_pass = smp_mpic_message_pass,
++ .kick_cpu = smp_generic_kick_cpu,
++ .setup_cpu = smp_mpic_setup_cpu,
++ .give_timebase = smp_generic_give_timebase,
++ .take_timebase = smp_generic_take_timebase,
++};
++#endif /* CONFIG_SMP */
++
++void __init pas_setup_arch(void)
++{
++#ifdef CONFIG_SMP
++ /* Setup SMP callback */
++ smp_ops = &pas_smp_ops;
++#endif
++ /* Lookup PCI hosts */
++ pas_pci_init();
++
++#ifdef CONFIG_DUMMY_CONSOLE
++ conswitchp = &dummy_con;
++#endif
++
++ printk(KERN_DEBUG "Using default idle loop\n");
++}
++
++static void iommu_dev_setup_null(struct pci_dev *dev) { }
++static void iommu_bus_setup_null(struct pci_bus *bus) { }
++
++static void __init pas_init_early(void)
++{
++ /* No iommu code yet */
++ ppc_md.iommu_dev_setup = iommu_dev_setup_null;
++ ppc_md.iommu_bus_setup = iommu_bus_setup_null;
++ pci_direct_iommu_init();
++}
++
++/* No legacy IO on our parts */
++static int pas_check_legacy_ioport(unsigned int baseport)
++{
++ return -ENODEV;
++}
++
++static __init void pas_init_IRQ(void)
++{
++ struct device_node *np;
++ struct device_node *root, *mpic_node;
++ unsigned long openpic_addr;
++ const unsigned int *opprop;
++ int naddr, opplen;
++ struct mpic *mpic;
++
++ mpic_node = NULL;
++
++ for_each_node_by_type(np, "interrupt-controller")
++ if (device_is_compatible(np, "open-pic")) {
++ mpic_node = np;
++ break;
++ }
++ if (!mpic_node)
++ for_each_node_by_type(np, "open-pic") {
++ mpic_node = np;
++ break;
++ }
++ if (!mpic_node) {
++ printk(KERN_ERR
++ "Failed to locate the MPIC interrupt controller\n");
++ return;
++ }
++
++ /* Find address list in /platform-open-pic */
++ root = of_find_node_by_path("/");
++ naddr = prom_n_addr_cells(root);
++ opprop = get_property(root, "platform-open-pic", &opplen);
++ if (!opprop) {
++ printk(KERN_ERR "No platform-open-pic property.\n");
++ of_node_put(root);
++ return;
++ }
++ openpic_addr = of_read_number(opprop, naddr);
++ printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
++ of_node_put(root);
++
++ mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0,
++ " PAS-OPIC ");
++ BUG_ON(!mpic);
++
++ mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
++ mpic_init(mpic);
++ of_node_put(mpic_node);
++ of_node_put(root);
++}
++
++static void __init pas_progress(char *s, unsigned short hex)
++{
++ printk("[%04x] : %s\n", hex, s ? s : "");
++}
++
++
++/*
++ * Called very early, MMU is off, device-tree isn't unflattened
++ */
++static int __init pas_probe(void)
++{
++ unsigned long root = of_get_flat_dt_root();
++
++ if (!of_flat_dt_is_compatible(root, "PA6T-1682M"))
++ return 0;
++
++ hpte_init_native();
++
++ return 1;
++}
++
++define_machine(pas) {
++ .name = "PA Semi PA6T-1682M",
++ .probe = pas_probe,
++ .setup_arch = pas_setup_arch,
++ .init_early = pas_init_early,
++ .init_IRQ = pas_init_IRQ,
++ .get_irq = mpic_get_irq,
++ .pcibios_fixup = pas_pcibios_fixup,
++ .restart = pas_restart,
++ .power_off = pas_power_off,
++ .halt = pas_halt,
++ .get_boot_time = pas_get_boot_time,
++ .calibrate_decr = generic_calibrate_decr,
++ .check_legacy_ioport = pas_check_legacy_ioport,
++ .progress = pas_progress,
++};
+diff --git a/arch/powerpc/platforms/pasemi/time.c b/arch/powerpc/platforms/pasemi/time.c
+new file mode 100644
+index 0000000..fa54351
+--- /dev/null
++++ b/arch/powerpc/platforms/pasemi/time.c
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2006 PA Semi, Inc
++ *
++ * Maintained by: Olof Johansson <olof at lixom.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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/time.h>
++
++#include <asm/time.h>
++
++unsigned long __init pas_get_boot_time(void)
++{
++ /* Let's just return a fake date right now */
++ return mktime(2006, 1, 1, 12, 0, 0);
++}
+diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
+index d664154..afa593a 100644
+--- a/arch/powerpc/platforms/powermac/backlight.c
++++ b/arch/powerpc/platforms/powermac/backlight.c
+@@ -60,7 +60,8 @@ int pmac_has_backlight_type(const char *
+ struct device_node* bk_node = find_devices("backlight");
+
+ if (bk_node) {
+- char *prop = get_property(bk_node, "backlight-control", NULL);
++ const char *prop = get_property(bk_node,
++ "backlight-control", NULL);
+ if (prop && strncmp(prop, type, strlen(type)) == 0)
+ return 1;
+ }
+diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
+index 6292624..c2b6b41 100644
+--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
++++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
+@@ -421,7 +421,7 @@ static int pmac_cpufreq_cpu_init(struct
+
+ static u32 read_gpio(struct device_node *np)
+ {
+- u32 *reg = (u32 *)get_property(np, "reg", NULL);
++ const u32 *reg = get_property(np, "reg", NULL);
+ u32 offset;
+
+ if (reg == NULL)
+@@ -497,7 +497,7 @@ static int pmac_cpufreq_init_MacRISC3(st
+ "frequency-gpio");
+ struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL,
+ "slewing-done");
+- u32 *value;
++ const u32 *value;
+
+ /*
+ * Check to see if it's GPIO driven or PMU only
+@@ -519,15 +519,15 @@ static int pmac_cpufreq_init_MacRISC3(st
+ */
+ if (frequency_gpio && slew_done_gpio) {
+ int lenp, rc;
+- u32 *freqs, *ratio;
++ const u32 *freqs, *ratio;
+
+- freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
++ freqs = get_property(cpunode, "bus-frequencies", &lenp);
+ lenp /= sizeof(u32);
+ if (freqs == NULL || lenp != 2) {
+ printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
+ return 1;
+ }
+- ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL);
++ ratio = get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+ if (ratio == NULL) {
+ printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
+ return 1;
+@@ -562,7 +562,7 @@ static int pmac_cpufreq_init_MacRISC3(st
+ /* If we use the PMU, look for the min & max frequencies in the
+ * device-tree
+ */
+- value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
++ value = get_property(cpunode, "min-clock-frequency", NULL);
+ if (!value)
+ return 1;
+ low_freq = (*value) / 1000;
+@@ -571,7 +571,7 @@ static int pmac_cpufreq_init_MacRISC3(st
+ if (low_freq < 100000)
+ low_freq *= 10;
+
+- value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL);
++ value = get_property(cpunode, "max-clock-frequency", NULL);
+ if (!value)
+ return 1;
+ hi_freq = (*value) / 1000;
+@@ -611,13 +611,14 @@ static int pmac_cpufreq_init_7447A(struc
+ static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
+ {
+ struct device_node *volt_gpio_np;
+- u32 pvr, *value;
++ u32 pvr;
++ const u32 *value;
+
+ if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+ return 1;
+
+ hi_freq = cur_freq;
+- value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
++ value = get_property(cpunode, "reduced-clock-frequency", NULL);
+ if (!value)
+ return 1;
+ low_freq = (*value) / 1000;
+@@ -650,7 +651,7 @@ static int pmac_cpufreq_init_750FX(struc
+ static int __init pmac_cpufreq_setup(void)
+ {
+ struct device_node *cpunode;
+- u32 *value;
++ const u32 *value;
+
+ if (strstr(cmd_line, "nocpufreq"))
+ return 0;
+@@ -661,7 +662,7 @@ static int __init pmac_cpufreq_setup(voi
+ goto out;
+
+ /* Get current cpu clock freq */
+- value = (u32 *)get_property(cpunode, "clock-frequency", NULL);
++ value = get_property(cpunode, "clock-frequency", NULL);
+ if (!value)
+ goto out;
+ cur_freq = (*value) / 1000;
+diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
+index 7b1156e..9d22361 100644
+--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
++++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
+@@ -89,7 +89,7 @@ static DEFINE_MUTEX(g5_switch_mutex);
+
+ #ifdef CONFIG_PMAC_SMU
+
+-static u32 *g5_pmode_data;
++static const u32 *g5_pmode_data;
+ static int g5_pmode_max;
+
+ static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
+@@ -104,7 +104,7 @@ static void g5_smu_switch_volt(int speed
+ {
+ struct smu_simple_cmd cmd;
+
+- DECLARE_COMPLETION(comp);
++ DECLARE_COMPLETION_ONSTACK(comp);
+ smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, smu_done_complete,
+ &comp, 'V', 'S', 'L', 'E', 'W',
+ 0xff, g5_fvt_cur+1, speed_mode);
+@@ -391,7 +391,8 @@ static int __init g5_neo2_cpufreq_init(s
+ unsigned int psize, ssize;
+ unsigned long max_freq;
+ char *freq_method, *volt_method;
+- u32 *valp, pvr_hi;
++ const u32 *valp;
++ u32 pvr_hi;
+ int use_volts_vdnap = 0;
+ int use_volts_smu = 0;
+ int rc = -ENODEV;
+@@ -409,8 +410,7 @@ static int __init g5_neo2_cpufreq_init(s
+ /* Get first CPU node */
+ for (cpunode = NULL;
+ (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+- u32 *reg =
+- (u32 *)get_property(cpunode, "reg", NULL);
++ const u32 *reg = get_property(cpunode, "reg", NULL);
+ if (reg == NULL || (*reg) != 0)
+ continue;
+ if (!strcmp(cpunode->type, "cpu"))
+@@ -422,7 +422,7 @@ static int __init g5_neo2_cpufreq_init(s
+ }
+
+ /* Check 970FX for now */
+- valp = (u32 *)get_property(cpunode, "cpu-version", NULL);
++ valp = get_property(cpunode, "cpu-version", NULL);
+ if (!valp) {
+ DBG("No cpu-version property !\n");
+ goto bail_noprops;
+@@ -434,7 +434,7 @@ static int __init g5_neo2_cpufreq_init(s
+ }
+
+ /* Look for the powertune data in the device-tree */
+- g5_pmode_data = (u32 *)get_property(cpunode, "power-mode-data",&psize);
++ g5_pmode_data = get_property(cpunode, "power-mode-data",&psize);
+ if (!g5_pmode_data) {
+ DBG("No power-mode-data !\n");
+ goto bail_noprops;
+@@ -442,7 +442,7 @@ static int __init g5_neo2_cpufreq_init(s
+ g5_pmode_max = psize / sizeof(u32) - 1;
+
+ if (use_volts_smu) {
+- struct smu_sdbp_header *shdr;
++ const struct smu_sdbp_header *shdr;
+
+ /* Look for the FVT table */
+ shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+@@ -493,7 +493,7 @@ static int __init g5_neo2_cpufreq_init(s
+ * half freq in this version. So far, I haven't yet seen a machine
+ * supporting anything else.
+ */
+- valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
++ valp = get_property(cpunode, "clock-frequency", NULL);
+ if (!valp)
+ return -ENODEV;
+ max_freq = (*valp)/1000;
+@@ -541,8 +541,8 @@ static int __init g5_neo2_cpufreq_init(s
+ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
+ {
+ struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
+- u8 *eeprom = NULL;
+- u32 *valp;
++ const u8 *eeprom = NULL;
++ const u32 *valp;
+ u64 max_freq, min_freq, ih, il;
+ int has_volt = 1, rc = 0;
+
+@@ -563,7 +563,7 @@ static int __init g5_pm72_cpufreq_init(s
+ /* Lookup the cpuid eeprom node */
+ cpuid = of_find_node_by_path("/u3 at 0,f8000000/i2c at f8001000/cpuid at a0");
+ if (cpuid != NULL)
+- eeprom = (u8 *)get_property(cpuid, "cpuid", NULL);
++ eeprom = get_property(cpuid, "cpuid", NULL);
+ if (eeprom == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
+ rc = -ENODEV;
+@@ -573,7 +573,8 @@ static int __init g5_pm72_cpufreq_init(s
+ /* Lookup the i2c hwclock */
+ for (hwclock = NULL;
+ (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
+- char *loc = get_property(hwclock, "hwctrl-location", NULL);
++ const char *loc = get_property(hwclock,
++ "hwctrl-location", NULL);
+ if (loc == NULL)
+ continue;
+ if (strcmp(loc, "CPU CLOCK"))
+@@ -637,7 +638,7 @@ static int __init g5_pm72_cpufreq_init(s
+ */
+
+ /* Get max frequency from device-tree */
+- valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
++ valp = get_property(cpunode, "clock-frequency", NULL);
+ if (!valp) {
+ printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
+ rc = -ENODEV;
+diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
+index f8313bf..e49621b 100644
+--- a/arch/powerpc/platforms/powermac/feature.c
++++ b/arch/powerpc/platforms/powermac/feature.c
+@@ -1058,8 +1058,8 @@ core99_reset_cpu(struct device_node *nod
+ if (np == NULL)
+ return -ENODEV;
+ for (np = np->child; np != NULL; np = np->sibling) {
+- u32 *num = (u32 *)get_property(np, "reg", NULL);
+- u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
++ const u32 *num = get_property(np, "reg", NULL);
++ const u32 *rst = get_property(np, "soft-reset", NULL);
+ if (num == NULL || rst == NULL)
+ continue;
+ if (param == *num) {
+@@ -1087,7 +1087,7 @@ core99_usb_enable(struct device_node *no
+ {
+ struct macio_chip *macio;
+ unsigned long flags;
+- char *prop;
++ const char *prop;
+ int number;
+ u32 reg;
+
+@@ -1096,7 +1096,7 @@ core99_usb_enable(struct device_node *no
+ macio->type != macio_intrepid)
+ return -ENODEV;
+
+- prop = (char *)get_property(node, "AAPL,clock-id", NULL);
++ prop = get_property(node, "AAPL,clock-id", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (strncmp(prop, "usb0u048", 8) == 0)
+@@ -1507,8 +1507,8 @@ static long g5_reset_cpu(struct device_n
+ if (np == NULL)
+ return -ENODEV;
+ for (np = np->child; np != NULL; np = np->sibling) {
+- u32 *num = (u32 *)get_property(np, "reg", NULL);
+- u32 *rst = (u32 *)get_property(np, "soft-reset", NULL);
++ const u32 *num = get_property(np, "reg", NULL);
++ const u32 *rst = get_property(np, "soft-reset", NULL);
+ if (num == NULL || rst == NULL)
+ continue;
+ if (param == *num) {
+@@ -2408,7 +2408,7 @@ static int __init probe_motherboard(void
+ */
+ dt = find_devices("device-tree");
+ if (dt != NULL)
+- model = (const char *) get_property(dt, "model", NULL);
++ model = get_property(dt, "model", NULL);
+ for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+ if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
+ pmac_mb = pmac_mb_defs[i];
+@@ -2536,7 +2536,7 @@ found:
+ */
+ static void __init probe_uninorth(void)
+ {
+- u32 *addrp;
++ const u32 *addrp;
+ phys_addr_t address;
+ unsigned long actrl;
+
+@@ -2555,7 +2555,7 @@ static void __init probe_uninorth(void)
+ if (uninorth_node == NULL)
+ return;
+
+- addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
++ addrp = get_property(uninorth_node, "reg", NULL);
+ if (addrp == NULL)
+ return;
+ address = of_translate_address(uninorth_node, addrp);
+@@ -2596,7 +2596,7 @@ static void __init probe_one_macio(const
+ struct device_node* node;
+ int i;
+ volatile u32 __iomem *base;
+- u32 *addrp, *revp;
++ const u32 *addrp, *revp;
+ phys_addr_t addr;
+ u64 size;
+
+@@ -2639,7 +2639,7 @@ static void __init probe_one_macio(const
+ return;
+ }
+ if (type == macio_keylargo || type == macio_keylargo2) {
+- u32 *did = (u32 *)get_property(node, "device-id", NULL);
++ const u32 *did = get_property(node, "device-id", NULL);
+ if (*did == 0x00000025)
+ type = macio_pangea;
+ if (*did == 0x0000003e)
+@@ -2652,7 +2652,7 @@ static void __init probe_one_macio(const
+ macio_chips[i].base = base;
+ macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+ macio_chips[i].name = macio_names[type];
+- revp = (u32 *)get_property(node, "revision-id", NULL);
++ revp = get_property(node, "revision-id", NULL);
+ if (revp)
+ macio_chips[i].rev = *revp;
+ printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
+@@ -2695,15 +2695,15 @@ static void __init
+ initial_serial_shutdown(struct device_node *np)
+ {
+ int len;
+- struct slot_names_prop {
++ const struct slot_names_prop {
+ int count;
+ char name[1];
+ } *slots;
+- char *conn;
++ const char *conn;
+ int port_type = PMAC_SCC_ASYNC;
+ int modem = 0;
+
+- slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
++ slots = get_property(np, "slot-names", &len);
+ conn = get_property(np, "AAPL,connector", &len);
+ if (conn && (strcmp(conn, "infrared") == 0))
+ port_type = PMAC_SCC_IRDA;
+diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
+index 8677f50..bfc4829 100644
+--- a/arch/powerpc/platforms/powermac/low_i2c.c
++++ b/arch/powerpc/platforms/powermac/low_i2c.c
+@@ -342,7 +342,7 @@ static void kw_i2c_handle_interrupt(stru
+ }
+
+ /* Interrupt handler */
+-static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t kw_i2c_irq(int irq, void *dev_id)
+ {
+ struct pmac_i2c_host_kw *host = dev_id;
+ unsigned long flags;
+@@ -477,7 +477,8 @@ static int kw_i2c_xfer(struct pmac_i2c_b
+ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
+ {
+ struct pmac_i2c_host_kw *host;
+- u32 *psteps, *prate, *addrp, steps;
++ const u32 *psteps, *prate, *addrp;
++ u32 steps;
+
+ host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL);
+ if (host == NULL) {
+@@ -490,7 +491,7 @@ static struct pmac_i2c_host_kw *__init k
+ * on all i2c keywest nodes so far ... we would have to fallback
+ * to macio parsing if that wasn't the case
+ */
+- addrp = (u32 *)get_property(np, "AAPL,address", NULL);
++ addrp = get_property(np, "AAPL,address", NULL);
+ if (addrp == NULL) {
+ printk(KERN_ERR "low_i2c: Can't find address for %s\n",
+ np->full_name);
+@@ -504,13 +505,13 @@ static struct pmac_i2c_host_kw *__init k
+ host->timeout_timer.function = kw_i2c_timeout;
+ host->timeout_timer.data = (unsigned long)host;
+
+- psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
++ psteps = get_property(np, "AAPL,address-step", NULL);
+ steps = psteps ? (*psteps) : 0x10;
+ for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
+ steps >>= 1;
+ /* Select interface rate */
+ host->speed = KW_I2C_MODE_25KHZ;
+- prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
++ prate = get_property(np, "AAPL,i2c-rate", NULL);
+ if (prate) switch(*prate) {
+ case 100:
+ host->speed = KW_I2C_MODE_100KHZ;
+@@ -618,8 +619,8 @@ static void __init kw_i2c_probe(void)
+ } else {
+ for (child = NULL;
+ (child = of_get_next_child(np, child)) != NULL;) {
+- u32 *reg =
+- (u32 *)get_property(child, "reg", NULL);
++ const u32 *reg = get_property(child,
++ "reg", NULL);
+ if (reg == NULL)
+ continue;
+ kw_i2c_add(host, np, child, *reg);
+@@ -881,7 +882,7 @@ static void __init smu_i2c_probe(void)
+ {
+ struct device_node *controller, *busnode;
+ struct pmac_i2c_bus *bus;
+- u32 *reg;
++ const u32 *reg;
+ int sz;
+
+ if (!smu_present())
+@@ -904,7 +905,7 @@ static void __init smu_i2c_probe(void)
+ if (strcmp(busnode->type, "i2c") &&
+ strcmp(busnode->type, "i2c-bus"))
+ continue;
+- reg = (u32 *)get_property(busnode, "reg", NULL);
++ reg = get_property(busnode, "reg", NULL);
+ if (reg == NULL)
+ continue;
+
+@@ -948,9 +949,8 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(s
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ if (p == bus->busnode) {
+ if (prev && bus->flags & pmac_i2c_multibus) {
+- u32 *reg;
+- reg = (u32 *)get_property(prev, "reg",
+- NULL);
++ const u32 *reg;
++ reg = get_property(prev, "reg", NULL);
+ if (!reg)
+ continue;
+ if (((*reg) >> 8) != bus->channel)
+@@ -971,7 +971,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
+
+ u8 pmac_i2c_get_dev_addr(struct device_node *device)
+ {
+- u32 *reg = (u32 *)get_property(device, "reg", NULL);
++ const u32 *reg = get_property(device, "reg", NULL);
+
+ if (reg == NULL)
+ return 0;
+diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
+index 6a36ea9..692945c 100644
+--- a/arch/powerpc/platforms/powermac/nvram.c
++++ b/arch/powerpc/platforms/powermac/nvram.c
+@@ -195,7 +195,7 @@ static void pmu_nvram_complete(struct ad
+ static unsigned char pmu_nvram_read_byte(int addr)
+ {
+ struct adb_request req;
+- DECLARE_COMPLETION(req_complete);
++ DECLARE_COMPLETION_ONSTACK(req_complete);
+
+ req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
+ if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
+@@ -211,7 +211,7 @@ static unsigned char pmu_nvram_read_byte
+ static void pmu_nvram_write_byte(int addr, unsigned char val)
+ {
+ struct adb_request req;
+- DECLARE_COMPLETION(req_complete);
++ DECLARE_COMPLETION_ONSTACK(req_complete);
+
+ req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
+ if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
+diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
+index 205d044..9923adc 100644
+--- a/arch/powerpc/platforms/powermac/pci.c
++++ b/arch/powerpc/platforms/powermac/pci.c
+@@ -66,16 +66,16 @@ struct device_node *k2_skiplist[2];
+ static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
+ {
+ for (; node != 0;node = node->sibling) {
+- int * bus_range;
+- unsigned int *class_code;
++ const int * bus_range;
++ const unsigned int *class_code;
+ int len;
+
+ /* For PCI<->PCI bridges or CardBus bridges, we go down */
+- class_code = (unsigned int *) get_property(node, "class-code", NULL);
++ class_code = get_property(node, "class-code", NULL);
+ if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+ continue;
+- bus_range = (int *) get_property(node, "bus-range", &len);
++ bus_range = get_property(node, "bus-range", &len);
+ if (bus_range != NULL && len > 2 * sizeof(int)) {
+ if (bus_range[1] > higher)
+ higher = bus_range[1];
+@@ -93,13 +93,15 @@ static int __init fixup_one_level_bus_ra
+ */
+ static void __init fixup_bus_range(struct device_node *bridge)
+ {
+- int * bus_range;
+- int len;
++ int *bus_range, len;
++ struct property *prop;
+
+ /* Lookup the "bus-range" property for the hose */
+- bus_range = (int *) get_property(bridge, "bus-range", &len);
+- if (bus_range == NULL || len < 2 * sizeof(int))
++ prop = of_find_property(bridge, "bus-range", &len);
++ if (prop == NULL || prop->length < 2 * sizeof(int))
+ return;
++
++ bus_range = (int *)prop->value;
+ bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+ }
+
+@@ -237,7 +239,7 @@ static struct pci_ops macrisc_pci_ops =
+ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+ {
+ struct device_node *np;
+- u32 *vendor, *device;
++ const u32 *vendor, *device;
+
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+@@ -245,8 +247,8 @@ static int chaos_validate_dev(struct pci
+ if (np == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+- vendor = (u32 *)get_property(np, "vendor-id", NULL);
+- device = (u32 *)get_property(np, "device-id", NULL);
++ vendor = get_property(np, "vendor-id", NULL);
++ device = get_property(np, "device-id", NULL);
+ if (vendor == NULL || device == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+@@ -686,20 +688,21 @@ static void __init fixup_nec_usb2(void)
+
+ for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
+ struct pci_controller *hose;
+- u32 data, *prop;
++ u32 data;
++ const u32 *prop;
+ u8 bus, devfn;
+
+- prop = (u32 *)get_property(nec, "vendor-id", NULL);
++ prop = get_property(nec, "vendor-id", NULL);
+ if (prop == NULL)
+ continue;
+ if (0x1033 != *prop)
+ continue;
+- prop = (u32 *)get_property(nec, "device-id", NULL);
++ prop = get_property(nec, "device-id", NULL);
+ if (prop == NULL)
+ continue;
+ if (0x0035 != *prop)
+ continue;
+- prop = (u32 *)get_property(nec, "reg", NULL);
++ prop = get_property(nec, "reg", NULL);
+ if (prop == NULL)
+ continue;
+ devfn = (prop[0] >> 8) & 0xff;
+@@ -898,7 +901,7 @@ static int __init add_bridge(struct devi
+ struct pci_controller *hose;
+ struct resource rsrc;
+ char *disp_name;
+- int *bus_range;
++ const int *bus_range;
+ int primary = 1, has_address = 0;
+
+ DBG("Adding PCI host bridge %s\n", dev->full_name);
+@@ -907,7 +910,7 @@ static int __init add_bridge(struct devi
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
+- bus_range = (int *) get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", dev->full_name);
+diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
+index aacfa59..5c6c15c 100644
+--- a/arch/powerpc/platforms/powermac/pfunc_base.c
++++ b/arch/powerpc/platforms/powermac/pfunc_base.c
+@@ -15,7 +15,7 @@
+ #define DBG(fmt...)
+ #endif
+
+-static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t macio_gpio_irq(int irq, void *data)
+ {
+ pmf_do_irq(data);
+
+@@ -114,7 +114,7 @@ static void macio_gpio_init_one(struct m
+ * we just create them all
+ */
+ for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
+- u32 *reg = (u32 *)get_property(gp, "reg", NULL);
++ const u32 *reg = get_property(gp, "reg", NULL);
+ unsigned long offset;
+ if (reg == NULL)
+ continue;
+diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
+index b117adb..7651f27 100644
+--- a/arch/powerpc/platforms/powermac/pfunc_core.c
++++ b/arch/powerpc/platforms/powermac/pfunc_core.c
+@@ -813,14 +813,15 @@ struct pmf_function *__pmf_find_function
+ struct pmf_device *dev;
+ struct pmf_function *func, *result = NULL;
+ char fname[64];
+- u32 *prop, ph;
++ const u32 *prop;
++ u32 ph;
+
+ /*
+ * Look for a "platform-*" function reference. If we can't find
+ * one, then we fallback to a direct call attempt
+ */
+ snprintf(fname, 63, "platform-%s", name);
+- prop = (u32 *)get_property(target, fname, NULL);
++ prop = get_property(target, fname, NULL);
+ if (prop == NULL)
+ goto find_it;
+ ph = *prop;
+diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
+index 39f7ddb..39db128 100644
+--- a/arch/powerpc/platforms/powermac/pic.c
++++ b/arch/powerpc/platforms/powermac/pic.c
+@@ -42,7 +42,7 @@
+ * has to include <linux/interrupt.h> (to get irqreturn_t), which
+ * causes all sorts of problems. -- paulus
+ */
+-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
++extern irqreturn_t xmon_irq(int, void *);
+
+ #ifdef CONFIG_PPC32
+ struct pmac_irq_hw {
+@@ -210,7 +210,7 @@ static struct irq_chip pmac_pic = {
+ .retrigger = pmac_retrigger,
+ };
+
+-static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
++static irqreturn_t gatwick_action(int cpl, void *dev_id)
+ {
+ unsigned long flags;
+ int irq, bits;
+@@ -227,7 +227,7 @@ static irqreturn_t gatwick_action(int cp
+ continue;
+ irq += __ilog2(bits);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ rc = IRQ_HANDLED;
+ }
+@@ -235,18 +235,18 @@ static irqreturn_t gatwick_action(int cp
+ return rc;
+ }
+
+-static unsigned int pmac_pic_get_irq(struct pt_regs *regs)
++static unsigned int pmac_pic_get_irq(void)
+ {
+ int irq;
+ unsigned long bits = 0;
+ unsigned long flags;
+
+ #ifdef CONFIG_SMP
+- void psurge_smp_message_recv(struct pt_regs *);
++ void psurge_smp_message_recv(void);
+
+ /* IPI's are a hack on the powersurge -- Cort */
+ if ( smp_processor_id() != 0 ) {
+- psurge_smp_message_recv(regs);
++ psurge_smp_message_recv();
+ return NO_IRQ_IGNORE; /* ignore, already handled */
+ }
+ #endif /* CONFIG_SMP */
+@@ -440,14 +440,13 @@ static void __init pmac_pic_probe_oldsty
+ }
+ #endif /* CONFIG_PPC32 */
+
+-static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+ struct mpic *mpic = desc->handler_data;
+
+- unsigned int cascade_irq = mpic_get_one_irq(mpic, regs);
++ unsigned int cascade_irq = mpic_get_one_irq(mpic);
+ if (cascade_irq != NO_IRQ)
+- generic_handle_irq(cascade_irq, regs);
++ generic_handle_irq(cascade_irq);
+ desc->chip->eoi(irq);
+ }
+
+diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h
+index 664103d..c44c89f 100644
+--- a/arch/powerpc/platforms/powermac/pic.h
++++ b/arch/powerpc/platforms/powermac/pic.h
+@@ -5,7 +5,7 @@
+
+ extern struct hw_interrupt_type pmac_pic;
+
+-void pmac_pic_init(void);
+-int pmac_get_irq(struct pt_regs *regs);
++extern void pmac_pic_init(void);
++extern int pmac_get_irq(void);
+
+ #endif /* __PPC_PLATFORMS_PMAC_PIC_H */
+diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
+index 31a9da7..824a618 100644
+--- a/arch/powerpc/platforms/powermac/setup.c
++++ b/arch/powerpc/platforms/powermac/setup.c
+@@ -116,7 +116,7 @@ extern struct smp_ops_t core99_smp_ops;
+ static void pmac_show_cpuinfo(struct seq_file *m)
+ {
+ struct device_node *np;
+- char *pp;
++ const char *pp;
+ int plen;
+ int mbmodel;
+ unsigned int mbflags;
+@@ -134,12 +134,12 @@ static void pmac_show_cpuinfo(struct seq
+ seq_printf(m, "machine\t\t: ");
+ np = of_find_node_by_path("/");
+ if (np != NULL) {
+- pp = (char *) get_property(np, "model", NULL);
++ pp = get_property(np, "model", NULL);
+ if (pp != NULL)
+ seq_printf(m, "%s\n", pp);
+ else
+ seq_printf(m, "PowerMac\n");
+- pp = (char *) get_property(np, "compatible", &plen);
++ pp = get_property(np, "compatible", &plen);
+ if (pp != NULL) {
+ seq_printf(m, "motherboard\t:");
+ while (plen > 0) {
+@@ -163,10 +163,8 @@ static void pmac_show_cpuinfo(struct seq
+ if (np == NULL)
+ np = of_find_node_by_type(NULL, "cache");
+ if (np != NULL) {
+- unsigned int *ic = (unsigned int *)
+- get_property(np, "i-cache-size", NULL);
+- unsigned int *dc = (unsigned int *)
+- get_property(np, "d-cache-size", NULL);
++ const unsigned int *ic = get_property(np, "i-cache-size", NULL);
++ const unsigned int *dc = get_property(np, "d-cache-size", NULL);
+ seq_printf(m, "L2 cache\t:");
+ has_l2cache = 1;
+ if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+@@ -254,7 +252,7 @@ static void __init l2cr_init(void)
+ if (np == 0)
+ np = find_type_devices("cpu");
+ if (np != 0) {
+- unsigned int *l2cr = (unsigned int *)
++ const unsigned int *l2cr =
+ get_property(np, "l2cr-value", NULL);
+ if (l2cr != 0) {
+ ppc_override_l2cr = 1;
+@@ -277,7 +275,7 @@ static void __init l2cr_init(void)
+ static void __init pmac_setup_arch(void)
+ {
+ struct device_node *cpu, *ic;
+- int *fp;
++ const int *fp;
+ unsigned long pvr;
+
+ pvr = PVR_VER(mfspr(SPRN_PVR));
+@@ -287,7 +285,7 @@ static void __init pmac_setup_arch(void)
+ loops_per_jiffy = 50000000 / HZ;
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != NULL) {
+- fp = (int *) get_property(cpu, "clock-frequency", NULL);
++ fp = get_property(cpu, "clock-frequency", NULL);
+ if (fp != NULL) {
+ if (pvr >= 0x30 && pvr < 0x80)
+ /* PPC970 etc. */
+diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S
+index 1174ca1..adee28d 100644
+--- a/arch/powerpc/platforms/powermac/sleep.S
++++ b/arch/powerpc/platforms/powermac/sleep.S
+@@ -45,7 +45,8 @@
+ .section .text
+ .align 5
+
+-#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
++#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC) || \
++ (defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32))
+
+ /* 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
+diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
+index 827b712..eeb2ae5 100644
+--- a/arch/powerpc/platforms/powermac/smp.c
++++ b/arch/powerpc/platforms/powermac/smp.c
+@@ -160,7 +160,7 @@ static inline void psurge_clr_ipi(int cp
+ */
+ static unsigned long psurge_smp_message[NR_CPUS];
+
+-void psurge_smp_message_recv(struct pt_regs *regs)
++void psurge_smp_message_recv(void)
+ {
+ int cpu = smp_processor_id();
+ int msg;
+@@ -174,12 +174,12 @@ void psurge_smp_message_recv(struct pt_r
+ /* make sure there is a message there */
+ for (msg = 0; msg < 4; msg++)
+ if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
+- smp_message_recv(msg, regs);
++ smp_message_recv(msg);
+ }
+
+-irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
++irqreturn_t psurge_primary_intr(int irq, void *d)
+ {
+- psurge_smp_message_recv(regs);
++ psurge_smp_message_recv();
+ return IRQ_HANDLED;
+ }
+
+@@ -328,6 +328,7 @@ static void __init smp_psurge_kick_cpu(i
+ {
+ unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
+ unsigned long a;
++ int i;
+
+ /* may need to flush here if secondary bats aren't setup */
+ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+@@ -340,7 +341,11 @@ static void __init smp_psurge_kick_cpu(i
+ mb();
+
+ psurge_set_ipi(nr);
+- udelay(10);
++ /*
++ * We can't use udelay here because the timebase is now frozen.
++ */
++ for (i = 0; i < 2000; ++i)
++ barrier();
+ psurge_clr_ipi(nr);
+
+ if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+@@ -548,7 +553,7 @@ static void __init smp_core99_setup_i2c_
+ struct device_node *cc = NULL;
+ struct device_node *p;
+ const char *name = NULL;
+- u32 *reg;
++ const u32 *reg;
+ int ok;
+
+ /* Look for the clock chip */
+@@ -562,7 +567,7 @@ static void __init smp_core99_setup_i2c_
+ pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
+ if (pmac_tb_clock_chip_host == NULL)
+ continue;
+- reg = (u32 *)get_property(cc, "reg", NULL);
++ reg = get_property(cc, "reg", NULL);
+ if (reg == NULL)
+ continue;
+ switch (*reg) {
+@@ -702,13 +707,12 @@ static void __init smp_core99_setup(int
+ /* GPIO based HW sync on ppc32 Core99 */
+ if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {
+ struct device_node *cpu;
+- u32 *tbprop = NULL;
++ const u32 *tbprop = NULL;
+
+ core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != NULL) {
+- tbprop = (u32 *)get_property(cpu, "timebase-enable",
+- NULL);
++ tbprop = get_property(cpu, "timebase-enable", NULL);
+ if (tbprop)
+ core99_tb_gpio = *tbprop;
+ of_node_put(cpu);
+diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
+index 37e5b1e..379db05 100644
+--- a/arch/powerpc/platforms/powermac/udbg_scc.c
++++ b/arch/powerpc/platforms/powermac/udbg_scc.c
+@@ -68,11 +68,11 @@ static unsigned char scc_inittab[] = {
+
+ void udbg_scc_init(int force_scc)
+ {
+- u32 *reg;
++ const u32 *reg;
+ unsigned long addr;
+ struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
+ struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
+- char *path;
++ const char *path;
+ int i, x;
+
+ escc = of_find_node_by_name(NULL, "escc");
+@@ -81,7 +81,7 @@ void udbg_scc_init(int force_scc)
+ macio = of_get_parent(escc);
+ if (macio == NULL)
+ goto bail;
+- path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
++ path = get_property(of_chosen, "linux,stdout-path", NULL);
+ if (path != NULL)
+ stdout = of_find_node_by_path(path);
+ for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
+@@ -96,13 +96,13 @@ void udbg_scc_init(int force_scc)
+ ch = ch_def ? ch_def : ch_a;
+
+ /* Get address within mac-io ASIC */
+- reg = (u32 *)get_property(escc, "reg", NULL);
++ reg = get_property(escc, "reg", NULL);
+ if (reg == NULL)
+ goto bail;
+ addr = reg[0];
+
+ /* Get address of mac-io PCI itself */
+- reg = (u32 *)get_property(macio, "assigned-addresses", NULL);
++ reg = get_property(macio, "assigned-addresses", NULL);
+ if (reg == NULL)
+ goto bail;
+ addr += reg[2];
+@@ -111,8 +111,6 @@ void udbg_scc_init(int force_scc)
+ pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
+ PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
+
+-
+- /* Setup for 57600 8N1 */
+ if (ch == ch_a)
+ addr += 0x20;
+ sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+@@ -125,9 +123,21 @@ void udbg_scc_init(int force_scc)
+ x = in_8(sccc);
+ out_8(sccc, 0x09); /* reset A or B side */
+ out_8(sccc, 0xc0);
++
++ /* If SCC was the OF output port, read the BRG value, else
++ * Setup for 57600 8N1
++ */
++ if (ch_def != NULL) {
++ out_8(sccc, 13);
++ scc_inittab[1] = in_8(sccc);
++ out_8(sccc, 12);
++ scc_inittab[3] = in_8(sccc);
++ }
++
+ for (i = 0; i < sizeof(scc_inittab); ++i)
+ out_8(sccc, scc_inittab[i]);
+
++
+ udbg_putc = udbg_scc_putc;
+ udbg_getc = udbg_scc_getc;
+ udbg_getc_poll = udbg_scc_getc_poll;
+diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
+index e5e0ff4..997243a 100644
+--- a/arch/powerpc/platforms/pseries/Makefile
++++ b/arch/powerpc/platforms/pseries/Makefile
+@@ -12,3 +12,4 @@ obj-$(CONFIG_EEH) += eeh.o eeh_cache.o e
+
+ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
+ obj-$(CONFIG_HVCS) += hvcserver.o
++obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
+diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
+index 32eaddf..3c2d63e 100644
+--- a/arch/powerpc/platforms/pseries/eeh.c
++++ b/arch/powerpc/platforms/pseries/eeh.c
+@@ -225,6 +225,7 @@ static void __eeh_mark_slot (struct devi
+
+ void eeh_mark_slot (struct device_node *dn, int mode_flag)
+ {
++ struct pci_dev *dev;
+ dn = find_device_pe (dn);
+
+ /* Back up one, since config addrs might be shared */
+@@ -232,6 +233,12 @@ void eeh_mark_slot (struct device_node *
+ dn = dn->parent;
+
+ PCI_DN(dn)->eeh_mode |= mode_flag;
++
++ /* Mark the pci device too */
++ dev = PCI_DN(dn)->pcidev;
++ if (dev)
++ dev->error_state = pci_channel_io_frozen;
++
+ __eeh_mark_slot (dn->child, mode_flag);
+ }
+
+@@ -449,7 +456,11 @@ EXPORT_SYMBOL(eeh_check_failure);
+ /* ------------------------------------------------------------- */
+ /* The code below deals with error recovery */
+
+-/** Return negative value if a permanent error, else return
++/**
++ * eeh_slot_availability - returns error status of slot
++ * @pdn pci device node
++ *
++ * Return negative value if a permanent error, else return
+ * a number of milliseconds to wait until the PCI slot is
+ * ready to be used.
+ */
+@@ -474,11 +485,42 @@ eeh_slot_availability(struct pci_dn *pdn
+
+ printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n",
+ rc, rets[0], rets[1], rets[2]);
+- return -1;
++ return -2;
+ }
+
+-/** rtas_pci_slot_reset raises/lowers the pci #RST line
+- * state: 1/0 to raise/lower the #RST
++/**
++ * rtas_pci_enable - enable MMIO or DMA transfers for this slot
++ * @pdn pci device node
++ */
++
++int
++rtas_pci_enable(struct pci_dn *pdn, int function)
++{
++ int config_addr;
++ int rc;
++
++ /* Use PE configuration address, if present */
++ config_addr = pdn->eeh_config_addr;
++ if (pdn->eeh_pe_config_addr)
++ config_addr = pdn->eeh_pe_config_addr;
++
++ rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
++ config_addr,
++ BUID_HI(pdn->phb->buid),
++ BUID_LO(pdn->phb->buid),
++ function);
++
++ if (rc)
++ printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n",
++ function, rc, pdn->node->full_name);
++
++ return rc;
++}
++
++/**
++ * rtas_pci_slot_reset - raises/lowers the pci #RST line
++ * @pdn pci device node
++ * @state: 1/0 to raise/lower the #RST
+ *
+ * Clear the EEH-frozen condition on a slot. This routine
+ * asserts the PCI #RST line if the 'state' argument is '1',
+@@ -511,24 +553,21 @@ rtas_pci_slot_reset(struct pci_dn *pdn,
+ BUID_HI(pdn->phb->buid),
+ BUID_LO(pdn->phb->buid),
+ state);
+- if (rc) {
+- printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d dn=%s\n",
++ if (rc)
++ printk (KERN_WARNING "EEH: Unable to reset the failed slot,"
++ " (%d) #RST=%d dn=%s\n",
+ rc, state, pdn->node->full_name);
+- return;
+- }
+ }
+
+-/** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
+- * dn -- device node to be reset.
++/**
++ * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
++ * @pdn: pci device node to be reset.
+ *
+ * Return 0 if success, else a non-zero value.
+ */
+
+-int
+-rtas_set_slot_reset(struct pci_dn *pdn)
++static void __rtas_set_slot_reset(struct pci_dn *pdn)
+ {
+- int i, rc;
+-
+ rtas_pci_slot_reset (pdn, 1);
+
+ /* The PCI bus requires that the reset be held high for at least
+@@ -549,17 +588,33 @@ rtas_set_slot_reset(struct pci_dn *pdn)
+ * up traffic. */
+ #define PCI_BUS_SETTLE_TIME_MSEC 1800
+ msleep (PCI_BUS_SETTLE_TIME_MSEC);
++}
++
++int rtas_set_slot_reset(struct pci_dn *pdn)
++{
++ int i, rc;
++
++ __rtas_set_slot_reset(pdn);
+
+ /* Now double check with the firmware to make sure the device is
+ * ready to be used; if not, wait for recovery. */
+ for (i=0; i<10; i++) {
+ rc = eeh_slot_availability (pdn);
+- if (rc < 0)
+- printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n", rc, pdn->node->full_name);
+ if (rc == 0)
+ return 0;
+- if (rc < 0)
++
++ if (rc == -2) {
++ printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n",
++ i, pdn->node->full_name);
++ __rtas_set_slot_reset(pdn);
++ continue;
++ }
++
++ if (rc < 0) {
++ printk (KERN_ERR "EEH: unrecoverable slot failure %s\n",
++ pdn->node->full_name);
+ return -1;
++ }
+
+ msleep (rc+100);
+ }
+@@ -582,6 +637,8 @@ rtas_set_slot_reset(struct pci_dn *pdn)
+
+ /**
+ * __restore_bars - Restore the Base Address Registers
++ * @pdn: pci device node
++ *
+ * Loads the PCI configuration space base address registers,
+ * the expansion ROM base address, the latency timer, and etc.
+ * from the saved values in the device node.
+@@ -691,11 +748,11 @@ static void *early_enable_eeh(struct dev
+ {
+ struct eeh_early_enable_info *info = data;
+ int ret;
+- char *status = get_property(dn, "status", NULL);
+- u32 *class_code = (u32 *)get_property(dn, "class-code", NULL);
+- u32 *vendor_id = (u32 *)get_property(dn, "vendor-id", NULL);
+- u32 *device_id = (u32 *)get_property(dn, "device-id", NULL);
+- u32 *regs;
++ const char *status = get_property(dn, "status", NULL);
++ const u32 *class_code = get_property(dn, "class-code", NULL);
++ const u32 *vendor_id = get_property(dn, "vendor-id", NULL);
++ const u32 *device_id = get_property(dn, "device-id", NULL);
++ const u32 *regs;
+ int enable;
+ struct pci_dn *pdn = PCI_DN(dn);
+
+@@ -737,7 +794,7 @@ static void *early_enable_eeh(struct dev
+
+ /* Ok... see if this device supports EEH. Some do, some don't,
+ * and the only way to find out is to check each and every one. */
+- regs = (u32 *)get_property(dn, "reg", NULL);
++ regs = get_property(dn, "reg", NULL);
+ if (regs) {
+ /* First register entry is addr (00BBSS00) */
+ /* Try to enable eeh */
+diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
+index c37a849..b6b462d 100644
+--- a/arch/powerpc/platforms/pseries/eeh_cache.c
++++ b/arch/powerpc/platforms/pseries/eeh_cache.c
+@@ -157,6 +157,7 @@ pci_addr_cache_insert(struct pci_dev *de
+ if (!piar)
+ return NULL;
+
++ pci_dev_get(dev);
+ piar->addr_lo = alo;
+ piar->addr_hi = ahi;
+ piar->pcidev = dev;
+@@ -178,7 +179,6 @@ static void __pci_addr_cache_insert_devi
+ struct device_node *dn;
+ struct pci_dn *pdn;
+ int i;
+- int inserted = 0;
+
+ dn = pci_device_to_OF_node(dev);
+ if (!dn) {
+@@ -197,9 +197,6 @@ static void __pci_addr_cache_insert_devi
+ return;
+ }
+
+- /* The cache holds a reference to the device... */
+- pci_dev_get(dev);
+-
+ /* Walk resources on this device, poke them into the tree */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ unsigned long start = pci_resource_start(dev,i);
+@@ -212,12 +209,7 @@ static void __pci_addr_cache_insert_devi
+ if (start == 0 || ~start == 0 || end == 0 || ~end == 0)
+ continue;
+ pci_addr_cache_insert(dev, start, end, flags);
+- inserted = 1;
+ }
+-
+- /* If there was nothing to add, the cache has no reference... */
+- if (!inserted)
+- pci_dev_put(dev);
+ }
+
+ /**
+@@ -240,7 +232,6 @@ void pci_addr_cache_insert_device(struct
+ static inline void __pci_addr_cache_remove_device(struct pci_dev *dev)
+ {
+ struct rb_node *n;
+- int removed = 0;
+
+ restart:
+ n = rb_first(&pci_io_addr_cache_root.rb_root);
+@@ -250,16 +241,12 @@ restart:
+
+ if (piar->pcidev == dev) {
+ rb_erase(n, &pci_io_addr_cache_root.rb_root);
+- removed = 1;
++ pci_dev_put(piar->pcidev);
+ kfree(piar);
+ goto restart;
+ }
+ n = rb_next(n);
+ }
+-
+- /* The cache no longer holds its reference to this device... */
+- if (removed)
+- pci_dev_put(dev);
+ }
+
+ /**
+diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
+index aaad2c0..c2bc990 100644
+--- a/arch/powerpc/platforms/pseries/eeh_driver.c
++++ b/arch/powerpc/platforms/pseries/eeh_driver.c
+@@ -77,8 +77,12 @@ static int irq_in_use(unsigned int irq)
+ }
+
+ /* ------------------------------------------------------- */
+-/** eeh_report_error - report an EEH error to each device,
+- * collect up and merge the device responses.
++/**
++ * eeh_report_error - report pci error to each device driver
++ *
++ * Report an EEH error to each device driver, collect up and
++ * merge the device driver responses. Cumulative response
++ * passed back in "userdata".
+ */
+
+ static void eeh_report_error(struct pci_dev *dev, void *userdata)
+@@ -96,24 +100,49 @@ static void eeh_report_error(struct pci_
+ PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
+ disable_irq_nosync(dev->irq);
+ }
+- if (!driver->err_handler)
+- return;
+- if (!driver->err_handler->error_detected)
++ if (!driver->err_handler ||
++ !driver->err_handler->error_detected)
+ return;
+
+ rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
+ if (*res == PCI_ERS_RESULT_NONE) *res = rc;
+- if (*res == PCI_ERS_RESULT_NEED_RESET) return;
+ if (*res == PCI_ERS_RESULT_DISCONNECT &&
+ rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
+ }
+
+-/** eeh_report_reset -- tell this device that the pci slot
+- * has been reset.
++/**
++ * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled
++ *
++ * Report an EEH error to each device driver, collect up and
++ * merge the device driver responses. Cumulative response
++ * passed back in "userdata".
++ */
++
++static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
++{
++ enum pci_ers_result rc, *res = userdata;
++ struct pci_driver *driver = dev->driver;
++
++ // dev->error_state = pci_channel_mmio_enabled;
++
++ if (!driver ||
++ !driver->err_handler ||
++ !driver->err_handler->mmio_enabled)
++ return;
++
++ rc = driver->err_handler->mmio_enabled (dev);
++ if (*res == PCI_ERS_RESULT_NONE) *res = rc;
++ if (*res == PCI_ERS_RESULT_DISCONNECT &&
++ rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
++}
++
++/**
++ * eeh_report_reset - tell device that slot has been reset
+ */
+
+ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
+ {
++ enum pci_ers_result rc, *res = userdata;
+ struct pci_driver *driver = dev->driver;
+ struct device_node *dn = pci_device_to_OF_node(dev);
+
+@@ -124,14 +153,20 @@ static void eeh_report_reset(struct pci_
+ PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+ enable_irq(dev->irq);
+ }
+- if (!driver->err_handler)
+- return;
+- if (!driver->err_handler->slot_reset)
++ if (!driver->err_handler ||
++ !driver->err_handler->slot_reset)
+ return;
+
+- driver->err_handler->slot_reset(dev);
++ rc = driver->err_handler->slot_reset(dev);
++ if (*res == PCI_ERS_RESULT_NONE) *res = rc;
++ if (*res == PCI_ERS_RESULT_DISCONNECT &&
++ rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
+ }
+
++/**
++ * eeh_report_resume - tell device to resume normal operations
++ */
++
+ static void eeh_report_resume(struct pci_dev *dev, void *userdata)
+ {
+ struct pci_driver *driver = dev->driver;
+@@ -148,6 +183,13 @@ static void eeh_report_resume(struct pci
+ driver->err_handler->resume(dev);
+ }
+
++/**
++ * eeh_report_failure - tell device driver that device is dead.
++ *
++ * This informs the device driver that the device is permanently
++ * dead, and that no further recovery attempts will be made on it.
++ */
++
+ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
+ {
+ struct pci_driver *driver = dev->driver;
+@@ -190,11 +232,11 @@ static void eeh_report_failure(struct pc
+
+ /**
+ * eeh_reset_device() -- perform actual reset of a pci slot
+- * Args: bus: pointer to the pci bus structure corresponding
++ * @bus: pointer to the pci bus structure corresponding
+ * to the isolated slot. A non-null value will
+ * cause all devices under the bus to be removed
+ * and then re-added.
+- * pe_dn: pointer to a "Partionable Endpoint" device node.
++ * @pe_dn: pointer to a "Partionable Endpoint" device node.
+ * This is the top-level structure on which pci
+ * bus resets can be performed.
+ */
+@@ -268,14 +310,14 @@ struct pci_dn * handle_eeh_events (struc
+
+ if (!frozen_dn) {
+
+- location = (char *) get_property(event->dn, "ibm,loc-code", NULL);
++ location = get_property(event->dn, "ibm,loc-code", NULL);
+ location = location ? location : "unknown";
+ printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
+ "for location=%s pci addr=%s\n",
+ location, pci_name(event->dev));
+ return NULL;
+ }
+- location = (char *) get_property(frozen_dn, "ibm,loc-code", NULL);
++ location = get_property(frozen_dn, "ibm,loc-code", NULL);
+ location = location ? location : "unknown";
+
+ /* There are two different styles for coming up with the PE.
+@@ -347,23 +389,43 @@ struct pci_dn * handle_eeh_events (struc
+ goto hard_fail;
+ }
+
+- /* If any device called out for a reset, then reset the slot */
+- if (result == PCI_ERS_RESULT_NEED_RESET) {
+- rc = eeh_reset_device(frozen_pdn, NULL);
+- if (rc)
+- goto hard_fail;
+- pci_walk_bus(frozen_bus, eeh_report_reset, NULL);
++ /* If all devices reported they can proceed, then re-enable MMIO */
++ if (result == PCI_ERS_RESULT_CAN_RECOVER) {
++ rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO);
++
++ if (rc) {
++ result = PCI_ERS_RESULT_NEED_RESET;
++ } else {
++ result = PCI_ERS_RESULT_NONE;
++ pci_walk_bus(frozen_bus, eeh_report_mmio_enabled, &result);
++ }
+ }
+
+- /* If all devices reported they can proceed, the re-enable PIO */
++ /* If all devices reported they can proceed, then re-enable DMA */
+ if (result == PCI_ERS_RESULT_CAN_RECOVER) {
+- /* XXX Not supported; we brute-force reset the device */
++ rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
++
++ if (rc)
++ result = PCI_ERS_RESULT_NEED_RESET;
++ }
++
++ /* If any device has a hard failure, then shut off everything. */
++ if (result == PCI_ERS_RESULT_DISCONNECT)
++ goto hard_fail;
++
++ /* If any device called out for a reset, then reset the slot */
++ if (result == PCI_ERS_RESULT_NEED_RESET) {
+ rc = eeh_reset_device(frozen_pdn, NULL);
+ if (rc)
+ goto hard_fail;
+- pci_walk_bus(frozen_bus, eeh_report_reset, NULL);
++ result = PCI_ERS_RESULT_NONE;
++ pci_walk_bus(frozen_bus, eeh_report_reset, &result);
+ }
+
++ /* All devices should claim they have recovered by now. */
++ if (result != PCI_ERS_RESULT_RECOVERED)
++ goto hard_fail;
++
+ /* Tell all device drivers that they can resume operations */
+ pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
+
+diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
+index 45ccc68..1370774 100644
+--- a/arch/powerpc/platforms/pseries/eeh_event.c
++++ b/arch/powerpc/platforms/pseries/eeh_event.c
+@@ -124,11 +124,11 @@ int eeh_send_failure_event (struct devic
+ {
+ unsigned long flags;
+ struct eeh_event *event;
+- char *location;
++ const char *location;
+
+ if (!mem_init_done) {
+ printk(KERN_ERR "EEH: event during early boot not handled\n");
+- location = (char *) get_property(dn, "ibm,loc-code", NULL);
++ location = get_property(dn, "ibm,loc-code", NULL);
+ printk(KERN_ERR "EEH: device node = %s\n", dn->full_name);
+ printk(KERN_ERR "EEH: PCI location = %s\n", location);
+ return 1;
+diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
+index c01d8f0..1c7b2ba 100644
+--- a/arch/powerpc/platforms/pseries/firmware.c
++++ b/arch/powerpc/platforms/pseries/firmware.c
+@@ -68,7 +68,7 @@ firmware_features_table[FIRMWARE_MAX_FEA
+ void __init fw_feature_init(void)
+ {
+ struct device_node *dn;
+- char *hypertas, *s;
++ const char *hypertas, *s;
+ int len, i;
+
+ DBG(" -> fw_feature_init()\n");
+diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
+index c9ff547..c00cfed 100644
+--- a/arch/powerpc/platforms/pseries/hvCall.S
++++ b/arch/powerpc/platforms/pseries/hvCall.S
+@@ -1,7 +1,6 @@
+ /*
+ * This file contains the generic code to perform a call to the
+ * pSeries LPAR hypervisor.
+- * NOTE: this file will go away when we move to inline this work.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -11,217 +10,153 @@
+ #include <asm/hvcall.h>
+ #include <asm/processor.h>
+ #include <asm/ppc_asm.h>
++#include <asm/asm-offsets.h>
+
+ #define STK_PARM(i) (48 + ((i)-3)*8)
+
+- .text
+-
+-/* long plpar_hcall(unsigned long opcode, R3
+- unsigned long arg1, R4
+- unsigned long arg2, R5
+- unsigned long arg3, R6
+- unsigned long arg4, R7
+- unsigned long *out1, R8
+- unsigned long *out2, R9
+- unsigned long *out3); R10
++#ifdef CONFIG_HCALL_STATS
++/*
++ * precall must preserve all registers. use unused STK_PARM()
++ * areas to save snapshots and opcode.
+ */
+-_GLOBAL(plpar_hcall)
+- HMT_MEDIUM
+-
+- mfcr r0
+-
+- std r8,STK_PARM(r8)(r1) /* Save out ptrs */
+- std r9,STK_PARM(r9)(r1)
+- std r10,STK_PARM(r10)(r1)
+-
+- stw r0,8(r1)
+-
+- HVSC /* invoke the hypervisor */
+-
+- lwz r0,8(r1)
+-
+- ld r8,STK_PARM(r8)(r1) /* Fetch r4-r6 ret args */
+- ld r9,STK_PARM(r9)(r1)
+- ld r10,STK_PARM(r10)(r1)
+- std r4,0(r8)
+- std r5,0(r9)
+- std r6,0(r10)
+-
+- mtcrf 0xff,r0
+- blr /* return r3 = status */
++#define HCALL_INST_PRECALL \
++ std r3,STK_PARM(r3)(r1); /* save opcode */ \
++ mftb r0; /* get timebase and */ \
++ std r0,STK_PARM(r5)(r1); /* save for later */ \
++BEGIN_FTR_SECTION; \
++ mfspr r0,SPRN_PURR; /* get PURR and */ \
++ std r0,STK_PARM(r6)(r1); /* save for later */ \
++END_FTR_SECTION_IFCLR(CPU_FTR_PURR);
++
++/*
++ * postcall is performed immediately before function return which
++ * allows liberal use of volatile registers.
++ */
++#define HCALL_INST_POSTCALL \
++ ld r4,STK_PARM(r3)(r1); /* validate opcode */ \
++ cmpldi cr7,r4,MAX_HCALL_OPCODE; \
++ bgt- cr7,1f; \
++ \
++ /* get time and PURR snapshots after hcall */ \
++ mftb r7; /* timebase after */ \
++BEGIN_FTR_SECTION; \
++ mfspr r8,SPRN_PURR; /* PURR after */ \
++ ld r6,STK_PARM(r6)(r1); /* PURR before */ \
++ subf r6,r6,r8; /* delta */ \
++END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
++ ld r5,STK_PARM(r5)(r1); /* timebase before */ \
++ subf r5,r5,r7; /* time delta */ \
++ \
++ /* calculate address of stat structure r4 = opcode */ \
++ srdi r4,r4,2; /* index into array */ \
++ mulli r4,r4,HCALL_STAT_SIZE; \
++ LOAD_REG_ADDR(r7, per_cpu__hcall_stats); \
++ add r4,r4,r7; \
++ ld r7,PACA_DATA_OFFSET(r13); /* per cpu offset */ \
++ add r4,r4,r7; \
++ \
++ /* update stats */ \
++ ld r7,HCALL_STAT_CALLS(r4); /* count */ \
++ addi r7,r7,1; \
++ std r7,HCALL_STAT_CALLS(r4); \
++ ld r7,HCALL_STAT_TB(r4); /* timebase */ \
++ add r7,r7,r5; \
++ std r7,HCALL_STAT_TB(r4); \
++BEGIN_FTR_SECTION; \
++ ld r7,HCALL_STAT_PURR(r4); /* PURR */ \
++ add r7,r7,r6; \
++ std r7,HCALL_STAT_PURR(r4); \
++END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
++1:
++#else
++#define HCALL_INST_PRECALL
++#define HCALL_INST_POSTCALL
++#endif
+
++ .text
+
+-/* Simple interface with no output values (other than status) */
+ _GLOBAL(plpar_hcall_norets)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+- HVSC /* invoke the hypervisor */
+-
+- lwz r0,8(r1)
+- mtcrf 0xff,r0
+- blr /* return r3 = status */
+-
+-
+-/* long plpar_hcall_8arg_2ret(unsigned long opcode, R3
+- unsigned long arg1, R4
+- unsigned long arg2, R5
+- unsigned long arg3, R6
+- unsigned long arg4, R7
+- unsigned long arg5, R8
+- unsigned long arg6, R9
+- unsigned long arg7, R10
+- unsigned long arg8, 112(R1)
+- unsigned long *out1); 120(R1)
+- */
+-_GLOBAL(plpar_hcall_8arg_2ret)
+- HMT_MEDIUM
+-
+- mfcr r0
+- ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */
+- stw r0,8(r1)
++ HCALL_INST_PRECALL
+
+ HVSC /* invoke the hypervisor */
+
++ HCALL_INST_POSTCALL
++
+ lwz r0,8(r1)
+- ld r10,STK_PARM(r12)(r1) /* Fetch r4 ret arg */
+- std r4,0(r10)
+ mtcrf 0xff,r0
+ blr /* return r3 = status */
+
+-
+-/* long plpar_hcall_4out(unsigned long opcode, R3
+- unsigned long arg1, R4
+- unsigned long arg2, R5
+- unsigned long arg3, R6
+- unsigned long arg4, R7
+- unsigned long *out1, R8
+- unsigned long *out2, R9
+- unsigned long *out3, R10
+- unsigned long *out4); 112(R1)
+- */
+-_GLOBAL(plpar_hcall_4out)
++_GLOBAL(plpar_hcall)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+- std r8,STK_PARM(r8)(r1) /* Save out ptrs */
+- std r9,STK_PARM(r9)(r1)
+- std r10,STK_PARM(r10)(r1)
+-
+- HVSC /* invoke the hypervisor */
+-
+- lwz r0,8(r1)
++ HCALL_INST_PRECALL
+
+- ld r8,STK_PARM(r8)(r1) /* Fetch r4-r7 ret args */
+- ld r9,STK_PARM(r9)(r1)
+- ld r10,STK_PARM(r10)(r1)
+- ld r11,STK_PARM(r11)(r1)
+- std r4,0(r8)
+- std r5,0(r9)
+- std r6,0(r10)
+- std r7,0(r11)
++ std r4,STK_PARM(r4)(r1) /* Save ret buffer */
+
+- mtcrf 0xff,r0
+- blr /* return r3 = status */
+-
+-/* plpar_hcall_7arg_7ret(unsigned long opcode, R3
+- unsigned long arg1, R4
+- unsigned long arg2, R5
+- unsigned long arg3, R6
+- unsigned long arg4, R7
+- unsigned long arg5, R8
+- unsigned long arg6, R9
+- unsigned long arg7, R10
+- unsigned long *out1, 112(R1)
+- unsigned long *out2, 110(R1)
+- unsigned long *out3, 108(R1)
+- unsigned long *out4, 106(R1)
+- unsigned long *out5, 104(R1)
+- unsigned long *out6, 102(R1)
+- unsigned long *out7); 100(R1)
+-*/
+-_GLOBAL(plpar_hcall_7arg_7ret)
+- HMT_MEDIUM
+-
+- mfcr r0
+- stw r0,8(r1)
++ mr r4,r5
++ mr r5,r6
++ mr r6,r7
++ mr r7,r8
++ mr r8,r9
++ mr r9,r10
+
+ HVSC /* invoke the hypervisor */
+
+- lwz r0,8(r1)
++ ld r12,STK_PARM(r4)(r1)
++ std r4, 0(r12)
++ std r5, 8(r12)
++ std r6, 16(r12)
++ std r7, 24(r12)
+
+- ld r11,STK_PARM(r11)(r1) /* Fetch r4 ret arg */
+- std r4,0(r11)
+- ld r11,STK_PARM(r12)(r1) /* Fetch r5 ret arg */
+- std r5,0(r11)
+- ld r11,STK_PARM(r13)(r1) /* Fetch r6 ret arg */
+- std r6,0(r11)
+- ld r11,STK_PARM(r14)(r1) /* Fetch r7 ret arg */
+- std r7,0(r11)
+- ld r11,STK_PARM(r15)(r1) /* Fetch r8 ret arg */
+- std r8,0(r11)
+- ld r11,STK_PARM(r16)(r1) /* Fetch r9 ret arg */
+- std r9,0(r11)
+- ld r11,STK_PARM(r17)(r1) /* Fetch r10 ret arg */
+- std r10,0(r11)
++ HCALL_INST_POSTCALL
+
++ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+-/* plpar_hcall_9arg_9ret(unsigned long opcode, R3
+- unsigned long arg1, R4
+- unsigned long arg2, R5
+- unsigned long arg3, R6
+- unsigned long arg4, R7
+- unsigned long arg5, R8
+- unsigned long arg6, R9
+- unsigned long arg7, R10
+- unsigned long arg8, 112(R1)
+- unsigned long arg9, 110(R1)
+- unsigned long *out1, 108(R1)
+- unsigned long *out2, 106(R1)
+- unsigned long *out3, 104(R1)
+- unsigned long *out4, 102(R1)
+- unsigned long *out5, 100(R1)
+- unsigned long *out6, 98(R1)
+- unsigned long *out7); 96(R1)
+- unsigned long *out8, 94(R1)
+- unsigned long *out9, 92(R1)
+-*/
+-_GLOBAL(plpar_hcall_9arg_9ret)
++_GLOBAL(plpar_hcall9)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+- ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */
+- ld r12,STK_PARM(r12)(r1) /* put arg9 in R12 */
++ HCALL_INST_PRECALL
++
++ std r4,STK_PARM(r4)(r1) /* Save ret buffer */
++
++ mr r4,r5
++ mr r5,r6
++ mr r6,r7
++ mr r7,r8
++ mr r8,r9
++ mr r9,r10
++ ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */
++ ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */
++ ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */
+
+ HVSC /* invoke the hypervisor */
+
+- ld r0,STK_PARM(r13)(r1) /* Fetch r4 ret arg */
+- stdx r4,r0,r0
+- ld r0,STK_PARM(r14)(r1) /* Fetch r5 ret arg */
+- stdx r5,r0,r0
+- ld r0,STK_PARM(r15)(r1) /* Fetch r6 ret arg */
+- stdx r6,r0,r0
+- ld r0,STK_PARM(r16)(r1) /* Fetch r7 ret arg */
+- stdx r7,r0,r0
+- ld r0,STK_PARM(r17)(r1) /* Fetch r8 ret arg */
+- stdx r8,r0,r0
+- ld r0,STK_PARM(r18)(r1) /* Fetch r9 ret arg */
+- stdx r9,r0,r0
+- ld r0,STK_PARM(r19)(r1) /* Fetch r10 ret arg */
+- stdx r10,r0,r0
+- ld r0,STK_PARM(r20)(r1) /* Fetch r11 ret arg */
+- stdx r11,r0,r0
+- ld r0,STK_PARM(r21)(r1) /* Fetch r12 ret arg */
+- stdx r12,r0,r0
++ ld r12,STK_PARM(r4)(r1)
++ std r4, 0(r12)
++ std r5, 8(r12)
++ std r6, 16(r12)
++ std r7, 24(r12)
++ std r8, 32(r12)
++ std r9, 40(r12)
++ std r10,48(r12)
++ std r11,56(r12)
++ std r12,64(r12)
++
++ HCALL_INST_POSTCALL
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c
+new file mode 100644
+index 0000000..446e17d
+--- /dev/null
++++ b/arch/powerpc/platforms/pseries/hvCall_inst.c
+@@ -0,0 +1,129 @@
++/*
++ * Copyright (C) 2006 Mike Kravetz IBM Corporation
++ *
++ * Hypervisor Call Instrumentation
++ *
++ * 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/percpu.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/cpumask.h>
++#include <asm/hvcall.h>
++#include <asm/firmware.h>
++#include <asm/cputable.h>
++
++DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats);
++
++/*
++ * Routines for displaying the statistics in debugfs
++ */
++static void *hc_start(struct seq_file *m, loff_t *pos)
++{
++ if ((int)*pos < HCALL_STAT_ARRAY_SIZE)
++ return (void *)(unsigned long)(*pos + 1);
++
++ return NULL;
++}
++
++static void *hc_next(struct seq_file *m, void *p, loff_t * pos)
++{
++ ++*pos;
++
++ return hc_start(m, pos);
++}
++
++static void hc_stop(struct seq_file *m, void *p)
++{
++}
++
++static int hc_show(struct seq_file *m, void *p)
++{
++ unsigned long h_num = (unsigned long)p;
++ struct hcall_stats *hs = (struct hcall_stats *)m->private;
++
++ if (hs[h_num].num_calls) {
++ if (!cpu_has_feature(CPU_FTR_PURR))
++ seq_printf(m, "%lu %lu %lu %lu\n", h_num<<2,
++ hs[h_num].num_calls,
++ hs[h_num].tb_total,
++ hs[h_num].purr_total);
++ else
++ seq_printf(m, "%lu %lu %lu\n", h_num<<2,
++ hs[h_num].num_calls,
++ hs[h_num].tb_total);
++ }
++
++ return 0;
++}
++
++static struct seq_operations hcall_inst_seq_ops = {
++ .start = hc_start,
++ .next = hc_next,
++ .stop = hc_stop,
++ .show = hc_show
++};
++
++static int hcall_inst_seq_open(struct inode *inode, struct file *file)
++{
++ int rc;
++ struct seq_file *seq;
++
++ rc = seq_open(file, &hcall_inst_seq_ops);
++ seq = file->private_data;
++ seq->private = file->f_dentry->d_inode->i_private;
++
++ return rc;
++}
++
++static struct file_operations hcall_inst_seq_fops = {
++ .open = hcall_inst_seq_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++#define HCALL_ROOT_DIR "hcall_inst"
++#define CPU_NAME_BUF_SIZE 32
++
++static int __init hcall_inst_init(void)
++{
++ struct dentry *hcall_root;
++ struct dentry *hcall_file;
++ char cpu_name_buf[CPU_NAME_BUF_SIZE];
++ int cpu;
++
++ if (!firmware_has_feature(FW_FEATURE_LPAR))
++ return 0;
++
++ hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
++ if (!hcall_root)
++ return -ENOMEM;
++
++ for_each_possible_cpu(cpu) {
++ snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
++ hcall_file = debugfs_create_file(cpu_name_buf, S_IRUGO,
++ hcall_root,
++ per_cpu(hcall_stats, cpu),
++ &hcall_inst_seq_fops);
++ if (!hcall_file)
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++__initcall(hcall_inst_init);
+diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
+index a72a987..3f6a89b 100644
+--- a/arch/powerpc/platforms/pseries/hvconsole.c
++++ b/arch/powerpc/platforms/pseries/hvconsole.c
+@@ -27,6 +27,7 @@
+ #include <linux/module.h>
+ #include <asm/hvcall.h>
+ #include <asm/hvconsole.h>
++#include "plpar_wrappers.h"
+
+ /**
+ * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
+@@ -40,9 +41,9 @@ int hvc_get_chars(uint32_t vtermno, char
+ {
+ unsigned long got;
+
+- if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got,
+- (unsigned long *)buf, (unsigned long *)buf+1) == H_SUCCESS)
++ if (plpar_get_term_char(vtermno, &got, buf) == H_SUCCESS)
+ return got;
++
+ return 0;
+ }
+
+diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
+index d67af2c..556c279 100644
+--- a/arch/powerpc/platforms/pseries/iommu.c
++++ b/arch/powerpc/platforms/pseries/iommu.c
+@@ -57,9 +57,6 @@ static void tce_build_pSeries(struct iom
+ u64 *tcep;
+ u64 rpn;
+
+- index <<= TCE_PAGE_FACTOR;
+- npages <<= TCE_PAGE_FACTOR;
+-
+ proto_tce = TCE_PCI_READ; // Read allowed
+
+ if (direction != DMA_TO_DEVICE)
+@@ -82,9 +79,6 @@ static void tce_free_pSeries(struct iomm
+ {
+ u64 *tcep;
+
+- npages <<= TCE_PAGE_FACTOR;
+- index <<= TCE_PAGE_FACTOR;
+-
+ tcep = ((u64 *)tbl->it_base) + index;
+
+ while (npages--)
+@@ -95,7 +89,6 @@ static unsigned long tce_get_pseries(str
+ {
+ u64 *tcep;
+
+- index <<= TCE_PAGE_FACTOR;
+ tcep = ((u64 *)tbl->it_base) + index;
+
+ return *tcep;
+@@ -109,9 +102,6 @@ static void tce_build_pSeriesLP(struct i
+ u64 proto_tce, tce;
+ u64 rpn;
+
+- tcenum <<= TCE_PAGE_FACTOR;
+- npages <<= TCE_PAGE_FACTOR;
+-
+ rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
+ proto_tce = TCE_PCI_READ;
+ if (direction != DMA_TO_DEVICE)
+@@ -146,7 +136,7 @@ static void tce_buildmulti_pSeriesLP(str
+ u64 rpn;
+ long l, limit;
+
+- if (TCE_PAGE_FACTOR == 0 && npages == 1)
++ if (npages == 1)
+ return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
+ direction);
+
+@@ -164,9 +154,6 @@ static void tce_buildmulti_pSeriesLP(str
+ __get_cpu_var(tce_page) = tcep;
+ }
+
+- tcenum <<= TCE_PAGE_FACTOR;
+- npages <<= TCE_PAGE_FACTOR;
+-
+ rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
+ proto_tce = TCE_PCI_READ;
+ if (direction != DMA_TO_DEVICE)
+@@ -207,9 +194,6 @@ static void tce_free_pSeriesLP(struct io
+ {
+ u64 rc;
+
+- tcenum <<= TCE_PAGE_FACTOR;
+- npages <<= TCE_PAGE_FACTOR;
+-
+ while (npages--) {
+ rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);
+
+@@ -229,9 +213,6 @@ static void tce_freemulti_pSeriesLP(stru
+ {
+ u64 rc;
+
+- tcenum <<= TCE_PAGE_FACTOR;
+- npages <<= TCE_PAGE_FACTOR;
+-
+ rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
+
+ if (rc && printk_ratelimit()) {
+@@ -248,7 +229,6 @@ static unsigned long tce_get_pSeriesLP(s
+ u64 rc;
+ unsigned long tce_ret;
+
+- tcenum <<= TCE_PAGE_FACTOR;
+ rc = plpar_tce_get((u64)tbl->it_index, (u64)tcenum << 12, &tce_ret);
+
+ if (rc && printk_ratelimit()) {
+@@ -267,13 +247,13 @@ static void iommu_table_setparms(struct
+ struct iommu_table *tbl)
+ {
+ struct device_node *node;
+- unsigned long *basep;
+- unsigned int *sizep;
++ const unsigned long *basep;
++ const u32 *sizep;
+
+ node = (struct device_node *)phb->arch_data;
+
+- basep = (unsigned long *)get_property(node, "linux,tce-base", NULL);
+- sizep = (unsigned int *)get_property(node, "linux,tce-size", NULL);
++ basep = get_property(node, "linux,tce-base", NULL);
++ sizep = get_property(node, "linux,tce-size", NULL);
+ if (basep == NULL || sizep == NULL) {
+ printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has "
+ "missing tce entries !\n", dn->full_name);
+@@ -289,7 +269,7 @@ static void iommu_table_setparms(struct
+ tbl->it_busno = phb->bus->number;
+
+ /* Units of tce entries */
+- tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT;
++ tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT;
+
+ /* Test if we are going over 2GB of DMA space */
+ if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
+@@ -300,7 +280,7 @@ static void iommu_table_setparms(struct
+ phb->dma_window_base_cur += phb->dma_window_size;
+
+ /* Set the tce table size - measured in entries */
+- tbl->it_size = phb->dma_window_size >> PAGE_SHIFT;
++ tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT;
+
+ tbl->it_index = 0;
+ tbl->it_blocksize = 16;
+@@ -315,7 +295,7 @@ static void iommu_table_setparms(struct
+ static void iommu_table_setparms_lpar(struct pci_controller *phb,
+ struct device_node *dn,
+ struct iommu_table *tbl,
+- unsigned char *dma_window)
++ const void *dma_window)
+ {
+ unsigned long offset, size;
+
+@@ -325,8 +305,8 @@ static void iommu_table_setparms_lpar(st
+ tbl->it_base = 0;
+ tbl->it_blocksize = 16;
+ tbl->it_type = TCE_PCI;
+- tbl->it_offset = offset >> PAGE_SHIFT;
+- tbl->it_size = size >> PAGE_SHIFT;
++ tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
++ tbl->it_size = size >> IOMMU_PAGE_SHIFT;
+ }
+
+ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
+@@ -415,7 +395,7 @@ static void iommu_bus_setup_pSeriesLP(st
+ struct iommu_table *tbl;
+ struct device_node *dn, *pdn;
+ struct pci_dn *ppci;
+- unsigned char *dma_window = NULL;
++ const void *dma_window = NULL;
+
+ DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
+
+@@ -519,11 +499,9 @@ static void iommu_dev_setup_pSeriesLP(st
+ {
+ struct device_node *pdn, *dn;
+ struct iommu_table *tbl;
+- unsigned char *dma_window = NULL;
++ const void *dma_window = NULL;
+ struct pci_dn *pci;
+
+- DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev));
+-
+ /* dev setup for LPAR is a little tricky, since the device tree might
+ * contain the dma-window properties per-device and not neccesarily
+ * for the bus. So we need to search upwards in the tree until we
+@@ -532,6 +510,9 @@ static void iommu_dev_setup_pSeriesLP(st
+ */
+ dn = pci_device_to_OF_node(dev);
+
++ DBG("iommu_dev_setup_pSeriesLP, dev %p (%s) %s\n",
++ dev, pci_name(dev), dn->full_name);
++
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ pdn = pdn->parent) {
+ dma_window = get_property(pdn, "ibm,dma-window", NULL);
+diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
+index 3aeb406..1820a0b 100644
+--- a/arch/powerpc/platforms/pseries/lpar.c
++++ b/arch/powerpc/platforms/pseries/lpar.c
+@@ -48,13 +48,11 @@
+ #define DBG_LOW(fmt...) do { } while(0)
+ #endif
+
+-/* in pSeries_hvCall.S */
++/* in hvCall.S */
+ EXPORT_SYMBOL(plpar_hcall);
+-EXPORT_SYMBOL(plpar_hcall_4out);
++EXPORT_SYMBOL(plpar_hcall9);
+ EXPORT_SYMBOL(plpar_hcall_norets);
+-EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
+-EXPORT_SYMBOL(plpar_hcall_7arg_7ret);
+-EXPORT_SYMBOL(plpar_hcall_9arg_9ret);
++
+ extern void pSeries_find_serial_port(void);
+
+
+@@ -204,20 +202,20 @@ void __init udbg_init_debug_lpar(void)
+ void __init find_udbg_vterm(void)
+ {
+ struct device_node *stdout_node;
+- u32 *termno;
+- char *name;
++ const u32 *termno;
++ const char *name;
+ int add_console;
+
+ /* find the boot console from /chosen/stdout */
+ if (!of_chosen)
+ return;
+- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
++ name = get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL)
+ return;
+ stdout_node = of_find_node_by_path(name);
+ if (!stdout_node)
+ return;
+- name = (char *)get_property(stdout_node, "name", NULL);
++ name = get_property(stdout_node, "name", NULL);
+ if (!name) {
+ printk(KERN_WARNING "stdout node missing 'name' property!\n");
+ goto out;
+@@ -228,7 +226,7 @@ void __init find_udbg_vterm(void)
+ /* Check if it's a virtual terminal */
+ if (strncmp(name, "vty", 3) != 0)
+ goto out;
+- termno = (u32 *)get_property(stdout_node, "reg", NULL);
++ termno = get_property(stdout_node, "reg", NULL);
+ if (termno == NULL)
+ goto out;
+ vtermno = termno[0];
+@@ -254,18 +252,34 @@ out:
+ void vpa_init(int cpu)
+ {
+ int hwcpu = get_hard_smp_processor_id(cpu);
+- unsigned long vpa = __pa(&lppaca[cpu]);
++ unsigned long addr;
+ long ret;
+
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ lppaca[cpu].vmxregs_in_use = 1;
+
+- ret = register_vpa(hwcpu, vpa);
++ addr = __pa(&lppaca[cpu]);
++ ret = register_vpa(hwcpu, addr);
+
+- if (ret)
++ if (ret) {
+ printk(KERN_ERR "WARNING: vpa_init: VPA registration for "
+ "cpu %d (hw %d) of area %lx returns %ld\n",
+- cpu, hwcpu, vpa, ret);
++ cpu, hwcpu, addr, ret);
++ return;
++ }
++ /*
++ * PAPR says this feature is SLB-Buffer but firmware never
++ * reports that. All SPLPAR support SLB shadow buffer.
++ */
++ addr = __pa(&slb_shadow[cpu]);
++ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
++ ret = register_slb_shadow(hwcpu, addr);
++ if (ret)
++ printk(KERN_ERR
++ "WARNING: vpa_init: SLB shadow buffer "
++ "registration for cpu %d (hw %d) of area %lx "
++ "returns %ld\n", cpu, hwcpu, addr, ret);
++ }
+ }
+
+ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
+@@ -277,7 +291,6 @@ long pSeries_lpar_hpte_insert(unsigned l
+ unsigned long flags;
+ unsigned long slot;
+ unsigned long hpte_v, hpte_r;
+- unsigned long dummy0, dummy1;
+
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
+@@ -302,8 +315,7 @@ long pSeries_lpar_hpte_insert(unsigned l
+ if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+ hpte_r &= ~_PAGE_COHERENT;
+
+- lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v,
+- hpte_r, &slot, &dummy0, &dummy1);
++ lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
+ if (unlikely(lpar_rc == H_PTEG_FULL)) {
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW(" full\n");
+diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
+index 18abfb1..64163ce 100644
+--- a/arch/powerpc/platforms/pseries/nvram.c
++++ b/arch/powerpc/platforms/pseries/nvram.c
+@@ -123,13 +123,14 @@ static ssize_t pSeries_nvram_get_size(vo
+ int __init pSeries_nvram_init(void)
+ {
+ struct device_node *nvram;
+- unsigned int *nbytes_p, proplen;
++ const unsigned int *nbytes_p;
++ unsigned int proplen;
+
+ nvram = of_find_node_by_type(NULL, "nvram");
+ if (nvram == NULL)
+ return -ENODEV;
+
+- nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
++ nbytes_p = get_property(nvram, "#bytes", &proplen);
+ if (nbytes_p == NULL || proplen != sizeof(unsigned int))
+ return -EIO;
+
+diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
+index e97e67f..410a6bc 100644
+--- a/arch/powerpc/platforms/pseries/pci.c
++++ b/arch/powerpc/platforms/pseries/pci.c
+@@ -60,7 +60,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI
+ static void __devinit check_s7a(void)
+ {
+ struct device_node *root;
+- char *model;
++ const char *model;
+
+ s7a_workaround = 0;
+ root = of_find_node_by_path("/");
+diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
+index 3bd1b3e..3eb7b29 100644
+--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
++++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
+@@ -5,20 +5,17 @@
+
+ static inline long poll_pending(void)
+ {
+- unsigned long dummy;
+- return plpar_hcall(H_POLL_PENDING, 0, 0, 0, 0, &dummy, &dummy, &dummy);
++ return plpar_hcall_norets(H_POLL_PENDING);
+ }
+
+ static inline long prod_processor(void)
+ {
+- plpar_hcall_norets(H_PROD);
+- return 0;
++ return plpar_hcall_norets(H_PROD);
+ }
+
+ static inline long cede_processor(void)
+ {
+- plpar_hcall_norets(H_CEDE);
+- return 0;
++ return plpar_hcall_norets(H_CEDE);
+ }
+
+ static inline long vpa_call(unsigned long flags, unsigned long cpu,
+@@ -40,23 +37,59 @@ static inline long register_vpa(unsigned
+ return vpa_call(0x1, cpu, vpa);
+ }
+
++static inline long unregister_slb_shadow(unsigned long cpu, unsigned long vpa)
++{
++ return vpa_call(0x7, cpu, vpa);
++}
++
++static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
++{
++ return vpa_call(0x3, cpu, vpa);
++}
++
+ extern void vpa_init(int cpu);
+
++static inline long plpar_pte_enter(unsigned long flags,
++ unsigned long hpte_group, unsigned long hpte_v,
++ unsigned long hpte_r, unsigned long *slot)
++{
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
++
++ *slot = retbuf[0];
++
++ return rc;
++}
++
+ static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
+ unsigned long avpn, unsigned long *old_pteh_ret,
+ unsigned long *old_ptel_ret)
+ {
+- unsigned long dummy;
+- return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0, old_pteh_ret,
+- old_ptel_ret, &dummy);
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
++
++ *old_pteh_ret = retbuf[0];
++ *old_ptel_ret = retbuf[1];
++
++ return rc;
+ }
+
+ static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
+ unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+ {
+- unsigned long dummy;
+- return plpar_hcall(H_READ, flags, ptex, 0, 0, old_pteh_ret,
+- old_ptel_ret, &dummy);
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_READ, retbuf, flags, ptex);
++
++ *old_pteh_ret = retbuf[0];
++ *old_ptel_ret = retbuf[1];
++
++ return rc;
+ }
+
+ static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
+@@ -68,9 +101,14 @@ static inline long plpar_pte_protect(uns
+ static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
+ unsigned long *tce_ret)
+ {
+- unsigned long dummy;
+- return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0, tce_ret, &dummy,
+- &dummy);
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
++
++ *tce_ret = retbuf[0];
++
++ return rc;
+ }
+
+ static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
+@@ -94,9 +132,17 @@ static inline long plpar_tce_stuff(unsig
+ static inline long plpar_get_term_char(unsigned long termno,
+ unsigned long *len_ret, char *buf_ret)
+ {
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+ unsigned long *lbuf = (unsigned long *)buf_ret; /* TODO: alignment? */
+- return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0, len_ret,
+- lbuf + 0, lbuf + 1);
++
++ rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno);
++
++ *len_ret = retbuf[0];
++ lbuf[0] = retbuf[1];
++ lbuf[1] = retbuf[2];
++
++ return rc;
+ }
+
+ static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
+@@ -107,4 +153,31 @@ static inline long plpar_put_term_char(u
+ lbuf[1]);
+ }
+
++static inline long plpar_eoi(unsigned long xirr)
++{
++ return plpar_hcall_norets(H_EOI, xirr);
++}
++
++static inline long plpar_cppr(unsigned long cppr)
++{
++ return plpar_hcall_norets(H_CPPR, cppr);
++}
++
++static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
++{
++ return plpar_hcall_norets(H_IPI, servernum, mfrr);
++}
++
++static inline long plpar_xirr(unsigned long *xirr_ret)
++{
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
++
++ rc = plpar_hcall(H_XIRR, retbuf);
++
++ *xirr_ret = retbuf[0];
++
++ return rc;
++}
++
+ #endif /* _PSERIES_PLPAR_WRAPPERS_H */
+diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
+index c7ffde1..b1d3d16 100644
+--- a/arch/powerpc/platforms/pseries/ras.c
++++ b/arch/powerpc/platforms/pseries/ras.c
+@@ -65,21 +65,19 @@ static int ras_check_exception_token;
+ #define EPOW_SENSOR_INDEX 0
+ #define RAS_VECTOR_OFFSET 0x500
+
+-static irqreturn_t ras_epow_interrupt(int irq, void *dev_id,
+- struct pt_regs * regs);
+-static irqreturn_t ras_error_interrupt(int irq, void *dev_id,
+- struct pt_regs * regs);
++static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
++static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
+
+ /* #define DEBUG */
+
+
+ static void request_ras_irqs(struct device_node *np,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ irq_handler_t handler,
+ const char *name)
+ {
+ int i, index, count = 0;
+ struct of_irq oirq;
+- u32 *opicprop;
++ const u32 *opicprop;
+ unsigned int opicplen;
+ unsigned int virqs[16];
+
+@@ -87,7 +85,7 @@ static void request_ras_irqs(struct devi
+ * map those interrupts using the default interrupt host and default
+ * trigger
+ */
+- opicprop = (u32 *)get_property(np, "open-pic-interrupt", &opicplen);
++ opicprop = get_property(np, "open-pic-interrupt", &opicplen);
+ if (opicprop) {
+ opicplen /= sizeof(u32);
+ for (i = 0; i < opicplen; i++) {
+@@ -166,8 +164,7 @@ __initcall(init_ras_IRQ);
+ * to examine the type of power failure and take appropriate action where
+ * the time horizon permits something useful to be done.
+ */
+-static irqreturn_t
+-ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
+ {
+ int status = 0xdeadbeef;
+ int state = 0;
+@@ -210,8 +207,7 @@ ras_epow_interrupt(int irq, void *dev_id
+ * For nonrecoverable errors, an error is logged and we stop all processing
+ * as quickly as possible in order to prevent propagation of the failure.
+ */
+-static irqreturn_t
+-ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
+ {
+ struct rtas_error_log *rtas_elog;
+ int status = 0xdeadbeef;
+@@ -337,7 +333,7 @@ static int recover_mce(struct pt_regs *r
+ err->disposition == RTAS_DISP_NOT_RECOVERED &&
+ err->target == RTAS_TARGET_MEMORY &&
+ err->type == RTAS_TYPE_ECC_UNCORR &&
+- !(current->pid == 0 || current->pid == 1)) {
++ !(current->pid == 0 || is_init(current))) {
+ /* Kill off a user process with an ECC error */
+ printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
+ current->pid);
+diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
+index 2e4e040..8ca2612 100644
+--- a/arch/powerpc/platforms/pseries/rtasd.c
++++ b/arch/powerpc/platforms/pseries/rtasd.c
+@@ -359,11 +359,11 @@ static int enable_surveillance(int timeo
+ static int get_eventscan_parms(void)
+ {
+ struct device_node *node;
+- int *ip;
++ const int *ip;
+
+ node = of_find_node_by_path("/rtas");
+
+- ip = (int *)get_property(node, "rtas-event-scan-rate", NULL);
++ ip = get_property(node, "rtas-event-scan-rate", NULL);
+ if (ip == NULL) {
+ printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
+ of_node_put(node);
+diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
+index 31867a7..89a8119 100644
+--- a/arch/powerpc/platforms/pseries/setup.c
++++ b/arch/powerpc/platforms/pseries/setup.c
+@@ -121,21 +121,20 @@ static void __init fwnmi_init(void)
+ fwnmi_active = 1;
+ }
+
+-void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+- unsigned int cascade_irq = i8259_irq(regs);
++ unsigned int cascade_irq = i8259_irq();
+ if (cascade_irq != NO_IRQ)
+- generic_handle_irq(cascade_irq, regs);
++ generic_handle_irq(cascade_irq);
+ desc->chip->eoi(irq);
+ }
+
+ static void __init pseries_mpic_init_IRQ(void)
+ {
+ struct device_node *np, *old, *cascade = NULL;
+- unsigned int *addrp;
++ const unsigned int *addrp;
+ unsigned long intack = 0;
+- unsigned int *opprop;
++ const unsigned int *opprop;
+ unsigned long openpic_addr = 0;
+ unsigned int cascade_irq;
+ int naddr, n, i, opplen;
+@@ -143,7 +142,7 @@ static void __init pseries_mpic_init_IRQ
+
+ np = of_find_node_by_path("/");
+ naddr = prom_n_addr_cells(np);
+- opprop = (unsigned int *) get_property(np, "platform-open-pic", &opplen);
++ opprop = get_property(np, "platform-open-pic", &opplen);
+ if (opprop != 0) {
+ openpic_addr = of_read_number(opprop, naddr);
+ printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
+@@ -180,7 +179,7 @@ static void __init pseries_mpic_init_IRQ
+
+ cascade_irq = irq_of_parse_and_map(cascade, 0);
+ if (cascade == NO_IRQ) {
+- printk(KERN_ERR "xics: failed to map cascade interrupt");
++ printk(KERN_ERR "mpic: failed to map cascade interrupt");
+ return;
+ }
+
+@@ -192,7 +191,7 @@ static void __init pseries_mpic_init_IRQ
+ break;
+ if (strcmp(np->name, "pci") != 0)
+ continue;
+- addrp = (u32 *)get_property(np, "8259-interrupt-acknowledge",
++ addrp = get_property(np, "8259-interrupt-acknowledge",
+ NULL);
+ if (addrp == NULL)
+ continue;
+@@ -223,23 +222,37 @@ static void pseries_lpar_enable_pmcs(voi
+ }
+
+ #ifdef CONFIG_KEXEC
+-static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary)
+-{
+- mpic_teardown_this_cpu(secondary);
+-}
+-
+-static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
++static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
+ {
+ /* Don't risk a hypervisor call if we're crashing */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
+- unsigned long vpa = __pa(get_lppaca());
++ unsigned long addr;
++
++ addr = __pa(get_slb_shadow());
++ if (unregister_slb_shadow(hard_smp_processor_id(), addr))
++ printk("SLB shadow buffer deregistration of "
++ "cpu %u (hw_cpu_id %d) failed\n",
++ smp_processor_id(),
++ hard_smp_processor_id());
+
+- if (unregister_vpa(hard_smp_processor_id(), vpa)) {
++ addr = __pa(get_lppaca());
++ if (unregister_vpa(hard_smp_processor_id(), addr)) {
+ printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
+ "failed\n", smp_processor_id(),
+ hard_smp_processor_id());
+ }
+ }
++}
++
++static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary)
++{
++ pseries_kexec_cpu_down(crash_shutdown, secondary);
++ mpic_teardown_this_cpu(secondary);
++}
++
++static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
++{
++ pseries_kexec_cpu_down(crash_shutdown, secondary);
+ xics_teardown_cpu(secondary);
+ }
+ #endif /* CONFIG_KEXEC */
+@@ -247,11 +260,11 @@ static void pseries_kexec_cpu_down_xics(
+ static void __init pseries_discover_pic(void)
+ {
+ struct device_node *np;
+- char *typep;
++ const char *typep;
+
+ for (np = NULL; (np = of_find_node_by_name(np,
+ "interrupt-controller"));) {
+- typep = (char *)get_property(np, "compatible", NULL);
++ typep = get_property(np, "compatible", NULL);
+ if (strstr(typep, "open-pic")) {
+ pSeries_mpic_node = of_node_get(np);
+ ppc_md.init_IRQ = pseries_mpic_init_IRQ;
+@@ -328,7 +341,7 @@ static int __init pSeries_init_panel(voi
+ {
+ /* Manually leave the kernel version on the panel. */
+ ppc_md.progress("Linux ppc64\n", 0);
+- ppc_md.progress(system_utsname.release, 0);
++ ppc_md.progress(init_utsname()->version, 0);
+
+ return 0;
+ }
+@@ -463,7 +476,6 @@ static void pseries_dedicated_idle_sleep
+ {
+ unsigned int cpu = smp_processor_id();
+ unsigned long start_snooze;
+- unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+
+ /*
+ * Indicate to the HV that we are idle. Now would be
+@@ -476,9 +488,9 @@ static void pseries_dedicated_idle_sleep
+ * has been checked recently. If we should poll for a little
+ * while, do so.
+ */
+- if (*smt_snooze_delay) {
++ if (__get_cpu_var(smt_snooze_delay)) {
+ start_snooze = get_tb() +
+- *smt_snooze_delay * tb_ticks_per_usec;
++ __get_cpu_var(smt_snooze_delay) * tb_ticks_per_usec;
+ local_irq_enable();
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+@@ -498,24 +510,7 @@ static void pseries_dedicated_idle_sleep
+ goto out;
+ }
+
+- /*
+- * If not SMT, cede processor. If CPU is running SMT
+- * cede if the other thread is not idle, so that it can
+- * go single-threaded. If the other thread is idle,
+- * we ask the hypervisor if it has pending work it
+- * wants to do and cede if it does. Otherwise we keep
+- * polling in order to reduce interrupt latency.
+- *
+- * Doing the cede when the other thread is active will
+- * result in this thread going dormant, meaning the other
+- * thread gets to run in single-threaded (ST) mode, which
+- * is slightly faster than SMT mode with this thread at
+- * very low priority. The cede enables interrupts, which
+- * doesn't matter here.
+- */
+- if (!cpu_has_feature(CPU_FTR_SMT) || !lppaca[cpu ^ 1].idle
+- || poll_pending() == H_PENDING)
+- cede_processor();
++ cede_processor();
+
+ out:
+ HMT_medium();
+diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
+index ac61098..c6624b8 100644
+--- a/arch/powerpc/platforms/pseries/smp.c
++++ b/arch/powerpc/platforms/pseries/smp.c
+@@ -62,7 +62,7 @@
+ */
+ static cpumask_t of_spin_map;
+
+-extern void pSeries_secondary_smp_init(unsigned long);
++extern void generic_secondary_smp_init(unsigned long);
+
+ #ifdef CONFIG_HOTPLUG_CPU
+
+@@ -145,9 +145,9 @@ static int pSeries_add_processor(struct
+ unsigned int cpu;
+ cpumask_t candidate_map, tmp = CPU_MASK_NONE;
+ int err = -ENOSPC, len, nthreads, i;
+- u32 *intserv;
++ const u32 *intserv;
+
+- intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", &len);
++ intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ if (!intserv)
+ return 0;
+
+@@ -205,9 +205,9 @@ static void pSeries_remove_processor(str
+ {
+ unsigned int cpu;
+ int len, nthreads, i;
+- u32 *intserv;
++ const u32 *intserv;
+
+- intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", &len);
++ intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ if (!intserv)
+ return;
+
+@@ -270,7 +270,7 @@ static inline int __devinit smp_startup_
+ {
+ int status;
+ unsigned long start_here = __pa((u32)*((unsigned long *)
+- pSeries_secondary_smp_init));
++ generic_secondary_smp_init));
+ unsigned int pcpu;
+ int start_cpu;
+
+diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
+index e988630..d071abe 100644
+--- a/arch/powerpc/platforms/pseries/xics.c
++++ b/arch/powerpc/platforms/pseries/xics.c
+@@ -34,6 +34,7 @@
+ #include <asm/i8259.h>
+
+ #include "xics.h"
++#include "plpar_wrappers.h"
+
+ #define XICS_IPI 2
+ #define XICS_IRQ_SPURIOUS 0
+@@ -110,27 +111,6 @@ static inline void direct_qirr_info(int
+ /* LPAR low level accessors */
+
+
+-static inline long plpar_eoi(unsigned long xirr)
+-{
+- return plpar_hcall_norets(H_EOI, xirr);
+-}
+-
+-static inline long plpar_cppr(unsigned long cppr)
+-{
+- return plpar_hcall_norets(H_CPPR, cppr);
+-}
+-
+-static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
+-{
+- return plpar_hcall_norets(H_IPI, servernum, mfrr);
+-}
+-
+-static inline long plpar_xirr(unsigned long *xirr_ret)
+-{
+- unsigned long dummy;
+- return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
+-}
+-
+ static inline unsigned int lpar_xirr_info_get(int n_cpu)
+ {
+ unsigned long lpar_rc;
+@@ -328,14 +308,14 @@ static inline unsigned int xics_remap_ir
+ return NO_IRQ;
+ }
+
+-static unsigned int xics_get_irq_direct(struct pt_regs *regs)
++static unsigned int xics_get_irq_direct(void)
+ {
+ unsigned int cpu = smp_processor_id();
+
+ return xics_remap_irq(direct_xirr_info_get(cpu));
+ }
+
+-static unsigned int xics_get_irq_lpar(struct pt_regs *regs)
++static unsigned int xics_get_irq_lpar(void)
+ {
+ unsigned int cpu = smp_processor_id();
+
+@@ -344,7 +324,7 @@ static unsigned int xics_get_irq_lpar(st
+
+ #ifdef CONFIG_SMP
+
+-static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs)
++static irqreturn_t xics_ipi_dispatch(int cpu)
+ {
+ WARN_ON(cpu_is_offline(cpu));
+
+@@ -352,47 +332,47 @@ static irqreturn_t xics_ipi_dispatch(int
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
+ &xics_ipi_message[cpu].value)) {
+ mb();
+- smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);
++ smp_message_recv(PPC_MSG_CALL_FUNCTION);
+ }
+ if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
+ &xics_ipi_message[cpu].value)) {
+ mb();
+- smp_message_recv(PPC_MSG_RESCHEDULE, regs);
++ smp_message_recv(PPC_MSG_RESCHEDULE);
+ }
+ #if 0
+ if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
+ &xics_ipi_message[cpu].value)) {
+ mb();
+- smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
++ smp_message_recv(PPC_MSG_MIGRATE_TASK);
+ }
+ #endif
+ #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+ if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
+ &xics_ipi_message[cpu].value)) {
+ mb();
+- smp_message_recv(PPC_MSG_DEBUGGER_BREAK, regs);
++ smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+ }
+ #endif
+ }
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
+ {
+ int cpu = smp_processor_id();
+
+ direct_qirr_info(cpu, 0xff);
+
+- return xics_ipi_dispatch(cpu, regs);
++ return xics_ipi_dispatch(cpu);
+ }
+
+-static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
+ {
+ int cpu = smp_processor_id();
+
+ lpar_qirr_info(cpu, 0xff);
+
+- return xics_ipi_dispatch(cpu, regs);
++ return xics_ipi_dispatch(cpu);
+ }
+
+ void xics_cause_IPI(int cpu)
+@@ -590,14 +570,14 @@ static void __init xics_init_one_node(st
+ unsigned int *indx)
+ {
+ unsigned int ilen;
+- u32 *ireg;
++ const u32 *ireg;
+
+ /* This code does the theorically broken assumption that the interrupt
+ * server numbers are the same as the hard CPU numbers.
+ * This happens to be the case so far but we are playing with fire...
+ * should be fixed one of these days. -BenH.
+ */
+- ireg = (u32 *)get_property(np, "ibm,interrupt-server-ranges", NULL);
++ ireg = get_property(np, "ibm,interrupt-server-ranges", NULL);
+
+ /* Do that ever happen ? we'll know soon enough... but even good'old
+ * f80 does have that property ..
+@@ -609,7 +589,7 @@ static void __init xics_init_one_node(st
+ */
+ *indx = *ireg;
+ }
+- ireg = (u32 *)get_property(np, "reg", &ilen);
++ ireg = get_property(np, "reg", &ilen);
+ if (!ireg)
+ panic("xics_init_IRQ: can't find interrupt reg property");
+
+@@ -635,7 +615,7 @@ static void __init xics_setup_8259_casca
+ {
+ struct device_node *np, *old, *found = NULL;
+ int cascade, naddr;
+- u32 *addrp;
++ const u32 *addrp;
+ unsigned long intack = 0;
+
+ for_each_node_by_type(np, "interrupt-controller")
+@@ -661,7 +641,7 @@ static void __init xics_setup_8259_casca
+ break;
+ if (strcmp(np->name, "pci") != 0)
+ continue;
+- addrp = (u32 *)get_property(np, "8259-interrupt-acknowledge", NULL);
++ addrp = get_property(np, "8259-interrupt-acknowledge", NULL);
+ if (addrp == NULL)
+ continue;
+ naddr = prom_n_addr_cells(np);
+@@ -680,7 +660,8 @@ void __init xics_init_IRQ(void)
+ {
+ int i;
+ struct device_node *np;
+- u32 *ireg, ilen, indx = 0;
++ u32 ilen, indx = 0;
++ const u32 *ireg;
+ int found = 0;
+
+ ppc64_boot_msg(0x20, "XICS Init");
+@@ -705,18 +686,17 @@ void __init xics_init_IRQ(void)
+ for (np = of_find_node_by_type(NULL, "cpu");
+ np;
+ np = of_find_node_by_type(np, "cpu")) {
+- ireg = (u32 *)get_property(np, "reg", &ilen);
++ ireg = get_property(np, "reg", &ilen);
+ if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) {
+- ireg = (u32 *)get_property(np,
+- "ibm,ppc-interrupt-gserver#s",
+- &ilen);
++ ireg = get_property(np,
++ "ibm,ppc-interrupt-gserver#s", &ilen);
+ i = ilen / sizeof(int);
+ if (ireg && i > 0) {
+ default_server = ireg[0];
+ /* take last element */
+ default_distrib_server = ireg[i-1];
+ }
+- ireg = (u32 *)get_property(np,
++ ireg = get_property(np,
+ "ibm,interrupt-server#-size", NULL);
+ if (ireg)
+ interrupt_server_size = *ireg;
+diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h
+index 6ee1055..db0ec3b 100644
+--- a/arch/powerpc/platforms/pseries/xics.h
++++ b/arch/powerpc/platforms/pseries/xics.h
+@@ -31,7 +31,6 @@ struct xics_ipi_struct {
+ extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
+
+ struct irq_desc;
+-extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs);
++extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc);
+
+ #endif /* _POWERPC_KERNEL_XICS_H */
+diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
+index e5e999e..91f052d 100644
+--- a/arch/powerpc/sysdev/Makefile
++++ b/arch/powerpc/sysdev/Makefile
+@@ -12,8 +12,14 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
+ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
+ obj-$(CONFIG_PPC_TODC) += todc.o
+ obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
++obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
+
+ ifeq ($(CONFIG_PPC_MERGE),y)
+ obj-$(CONFIG_PPC_I8259) += i8259.o
+ obj-$(CONFIG_PPC_83xx) += ipic.o
+ endif
++
++# Temporary hack until we have migrated to asm-powerpc
++ifeq ($(ARCH),powerpc)
++obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
++endif
+diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c
+new file mode 100644
+index 0000000..ec26599
+--- /dev/null
++++ b/arch/powerpc/sysdev/cpm2_common.c
+@@ -0,0 +1,309 @@
++/*
++ * General Purpose functions for the global management of the
++ * 8260 Communication Processor Module.
++ * Copyright (c) 1999-2001 Dan Malek <dan at embeddedalley.com>
++ * Copyright (c) 2000 MontaVista Software, Inc (source at mvista.com)
++ * 2.3.99 Updates
++ *
++ * 2006 (c) MontaVista Software, Inc.
++ * Vitaly Bordug <vbordug at ru.mvista.com>
++ * Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
++ *
++ * 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.
++ */
++
++/*
++ *
++ * In addition to the individual control of the communication
++ * channels, there are a few functions that globally affect the
++ * communication processor.
++ *
++ * Buffer descriptors must be allocated from the dual ported memory
++ * space. The allocator for that is here. When the communication
++ * process is reset, we reclaim the memory available. There is
++ * currently no deallocator for this memory.
++ */
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/param.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mpc8260.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/cpm2.h>
++#include <asm/rheap.h>
++#include <asm/fs_pd.h>
++
++#include <sysdev/fsl_soc.h>
++
++static void cpm2_dpinit(void);
++cpm_cpm2_t *cpmp; /* Pointer to comm processor space */
++
++/* We allocate this here because it is used almost exclusively for
++ * the communication processor devices.
++ */
++cpm2_map_t *cpm2_immr;
++intctl_cpm2_t *cpm2_intctl;
++
++#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
++ of space for CPM as it is larger
++ than on PQ2 */
++
++void
++cpm2_reset(void)
++{
++ cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
++ cpm2_intctl = cpm2_map(im_intctl);
++
++ /* Reclaim the DP memory for our use.
++ */
++ cpm2_dpinit();
++
++ /* Tell everyone where the comm processor resides.
++ */
++ cpmp = &cpm2_immr->im_cpm;
++}
++
++/* Set a baud rate generator. This needs lots of work. There are
++ * eight BRGs, which can be connected to the CPM channels or output
++ * as clocks. The BRGs are in two different block of internal
++ * memory mapped space.
++ * The baud rate clock is the system clock divided by something.
++ * It was set up long ago during the initial boot phase and is
++ * is given to us.
++ * Baud rate clocks are zero-based in the driver code (as that maps
++ * to port numbers). Documentation uses 1-based numbering.
++ */
++#define BRG_INT_CLK (get_brgfreq())
++#define BRG_UART_CLK (BRG_INT_CLK/16)
++
++/* This function is used by UARTS, or anything else that uses a 16x
++ * oversampled clock.
++ */
++void
++cpm_setbrg(uint brg, uint rate)
++{
++ volatile uint *bp;
++
++ /* This is good enough to get SMCs running.....
++ */
++ if (brg < 4) {
++ bp = cpm2_map_size(im_brgc1, 16);
++ } else {
++ bp = cpm2_map_size(im_brgc5, 16);
++ brg -= 4;
++ }
++ bp += brg;
++ *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
++
++ cpm2_unmap(bp);
++}
++
++/* This function is used to set high speed synchronous baud rate
++ * clocks.
++ */
++void
++cpm2_fastbrg(uint brg, uint rate, int div16)
++{
++ volatile uint *bp;
++
++ if (brg < 4) {
++ bp = cpm2_map_size(im_brgc1, 16);
++ }
++ else {
++ bp = cpm2_map_size(im_brgc5, 16);
++ brg -= 4;
++ }
++ bp += brg;
++ *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
++ if (div16)
++ *bp |= CPM_BRG_DIV16;
++
++ cpm2_unmap(bp);
++}
++
++int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
++{
++ int ret = 0;
++ int shift;
++ int i, bits = 0;
++ cpmux_t *im_cpmux;
++ u32 *reg;
++ u32 mask = 7;
++ u8 clk_map [24][3] = {
++ {CPM_CLK_FCC1, CPM_BRG5, 0},
++ {CPM_CLK_FCC1, CPM_BRG6, 1},
++ {CPM_CLK_FCC1, CPM_BRG7, 2},
++ {CPM_CLK_FCC1, CPM_BRG8, 3},
++ {CPM_CLK_FCC1, CPM_CLK9, 4},
++ {CPM_CLK_FCC1, CPM_CLK10, 5},
++ {CPM_CLK_FCC1, CPM_CLK11, 6},
++ {CPM_CLK_FCC1, CPM_CLK12, 7},
++ {CPM_CLK_FCC2, CPM_BRG5, 0},
++ {CPM_CLK_FCC2, CPM_BRG6, 1},
++ {CPM_CLK_FCC2, CPM_BRG7, 2},
++ {CPM_CLK_FCC2, CPM_BRG8, 3},
++ {CPM_CLK_FCC2, CPM_CLK13, 4},
++ {CPM_CLK_FCC2, CPM_CLK14, 5},
++ {CPM_CLK_FCC2, CPM_CLK15, 6},
++ {CPM_CLK_FCC2, CPM_CLK16, 7},
++ {CPM_CLK_FCC3, CPM_BRG5, 0},
++ {CPM_CLK_FCC3, CPM_BRG6, 1},
++ {CPM_CLK_FCC3, CPM_BRG7, 2},
++ {CPM_CLK_FCC3, CPM_BRG8, 3},
++ {CPM_CLK_FCC3, CPM_CLK13, 4},
++ {CPM_CLK_FCC3, CPM_CLK14, 5},
++ {CPM_CLK_FCC3, CPM_CLK15, 6},
++ {CPM_CLK_FCC3, CPM_CLK16, 7}
++ };
++
++ im_cpmux = cpm2_map(im_cpmux);
++
++ switch (target) {
++ case CPM_CLK_SCC1:
++ reg = &im_cpmux->cmx_scr;
++ shift = 24;
++ case CPM_CLK_SCC2:
++ reg = &im_cpmux->cmx_scr;
++ shift = 16;
++ break;
++ case CPM_CLK_SCC3:
++ reg = &im_cpmux->cmx_scr;
++ shift = 8;
++ break;
++ case CPM_CLK_SCC4:
++ reg = &im_cpmux->cmx_scr;
++ shift = 0;
++ break;
++ case CPM_CLK_FCC1:
++ reg = &im_cpmux->cmx_fcr;
++ shift = 24;
++ break;
++ case CPM_CLK_FCC2:
++ reg = &im_cpmux->cmx_fcr;
++ shift = 16;
++ break;
++ case CPM_CLK_FCC3:
++ reg = &im_cpmux->cmx_fcr;
++ shift = 8;
++ break;
++ default:
++ printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
++ return -EINVAL;
++ }
++
++ if (mode == CPM_CLK_RX)
++ shift +=3;
++
++ for (i=0; i<24; i++) {
++ if (clk_map[i][0] == target && clk_map[i][1] == clock) {
++ bits = clk_map[i][2];
++ break;
++ }
++ }
++ if (i == sizeof(clk_map)/3)
++ ret = -EINVAL;
++
++ bits <<= shift;
++ mask <<= shift;
++ out_be32(reg, (in_be32(reg) & ~mask) | bits);
++
++ cpm2_unmap(im_cpmux);
++ return ret;
++}
++
++/*
++ * dpalloc / dpfree bits.
++ */
++static spinlock_t cpm_dpmem_lock;
++/* 16 blocks should be enough to satisfy all requests
++ * until the memory subsystem goes up... */
++static rh_block_t cpm_boot_dpmem_rh_block[16];
++static rh_info_t cpm_dpmem_info;
++static u8* im_dprambase;
++
++static void cpm2_dpinit(void)
++{
++ spin_lock_init(&cpm_dpmem_lock);
++
++ im_dprambase = ioremap(CPM_MAP_ADDR, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
++
++ /* initialize the info header */
++ rh_init(&cpm_dpmem_info, 1,
++ sizeof(cpm_boot_dpmem_rh_block) /
++ sizeof(cpm_boot_dpmem_rh_block[0]),
++ cpm_boot_dpmem_rh_block);
++
++ /* Attach the usable dpmem area */
++ /* XXX: This is actually crap. CPM_DATAONLY_BASE and
++ * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
++ * varies with the processor and the microcode patches activated.
++ * But the following should be at least safe.
++ */
++ rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
++ CPM_DATAONLY_SIZE);
++}
++
++/* This function returns an index into the DPRAM area.
++ */
++uint cpm_dpalloc(uint size, uint align)
++{
++ void *start;
++ unsigned long flags;
++
++ spin_lock_irqsave(&cpm_dpmem_lock, flags);
++ cpm_dpmem_info.alignment = align;
++ start = rh_alloc(&cpm_dpmem_info, size, "commproc");
++ spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
++
++ return (uint)start;
++}
++EXPORT_SYMBOL(cpm_dpalloc);
++
++int cpm_dpfree(uint offset)
++{
++ int ret;
++ unsigned long flags;
++
++ spin_lock_irqsave(&cpm_dpmem_lock, flags);
++ ret = rh_free(&cpm_dpmem_info, (void *)offset);
++ spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(cpm_dpfree);
++
++/* not sure if this is ever needed */
++uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
++{
++ void *start;
++ unsigned long flags;
++
++ spin_lock_irqsave(&cpm_dpmem_lock, flags);
++ cpm_dpmem_info.alignment = align;
++ start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
++ spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
++
++ return (uint)start;
++}
++EXPORT_SYMBOL(cpm_dpalloc_fixed);
++
++void cpm_dpdump(void)
++{
++ rh_dump(&cpm_dpmem_info);
++}
++EXPORT_SYMBOL(cpm_dpdump);
++
++void *cpm_dpram_addr(uint offset)
++{
++ return (void *)(im_dprambase + offset);
++}
++EXPORT_SYMBOL(cpm_dpram_addr);
+diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
+new file mode 100644
+index 0000000..767ee66
+--- /dev/null
++++ b/arch/powerpc/sysdev/cpm2_pic.c
+@@ -0,0 +1,256 @@
++/*
++ * Platform information definitions.
++ *
++ * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates
++ * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek.
++ *
++ * Author: Vitaly Bordug <vbordug at ru.mvista.com>
++ *
++ * 1999-2001 (c) Dan Malek <dan at embeddedalley.com>
++ * 2006 (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.
++ */
++
++/* The CPM2 internal interrupt controller. It is usually
++ * the only interrupt controller.
++ * There are two 32-bit registers (high/low) for up to 64
++ * possible interrupts.
++ *
++ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
++ * in a simple arithmetic fashion to mask or pending registers.
++ * That is, interrupt 4 does not map to bit position 4.
++ * We create two tables, indexed by vector number, to indicate
++ * which register to use and which bit in the register to use.
++ */
++
++#include <linux/stddef.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/irq.h>
++
++#include <asm/immap_cpm2.h>
++#include <asm/mpc8260.h>
++#include <asm/io.h>
++#include <asm/prom.h>
++
++#include "cpm2_pic.h"
++
++static struct device_node *cpm2_pic_node;
++static struct irq_host *cpm2_pic_host;
++#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
++static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
++
++static const u_char irq_to_siureg[] = {
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++/* bit numbers do not match the docs, these are precomputed so the bit for
++ * a given irq is (1 << irq_to_siubit[irq]) */
++static const u_char irq_to_siubit[] = {
++ 0, 15, 14, 13, 12, 11, 10, 9,
++ 8, 7, 6, 5, 4, 3, 2, 1,
++ 2, 1, 0, 14, 13, 12, 11, 10,
++ 9, 8, 7, 6, 5, 4, 3, 0,
++ 31, 30, 29, 28, 27, 26, 25, 24,
++ 23, 22, 21, 20, 19, 18, 17, 16,
++ 16, 17, 18, 19, 20, 21, 22, 23,
++ 24, 25, 26, 27, 28, 29, 30, 31,
++};
++
++static void cpm2_mask_irq(unsigned int irq_nr)
++{
++ int bit, word;
++ volatile uint *simr;
++
++ irq_nr -= CPM_IRQ_OFFSET;
++
++ bit = irq_to_siubit[irq_nr];
++ word = irq_to_siureg[irq_nr];
++
++ simr = &(cpm2_intctl->ic_simrh);
++ ppc_cached_irq_mask[word] &= ~(1 << bit);
++ simr[word] = ppc_cached_irq_mask[word];
++}
++
++static void cpm2_unmask_irq(unsigned int irq_nr)
++{
++ int bit, word;
++ volatile uint *simr;
++
++ irq_nr -= CPM_IRQ_OFFSET;
++
++ bit = irq_to_siubit[irq_nr];
++ word = irq_to_siureg[irq_nr];
++
++ simr = &(cpm2_intctl->ic_simrh);
++ ppc_cached_irq_mask[word] |= 1 << bit;
++ simr[word] = ppc_cached_irq_mask[word];
++}
++
++static void cpm2_mask_and_ack(unsigned int irq_nr)
++{
++ int bit, word;
++ volatile uint *simr, *sipnr;
++
++ irq_nr -= CPM_IRQ_OFFSET;
++
++ bit = irq_to_siubit[irq_nr];
++ word = irq_to_siureg[irq_nr];
++
++ simr = &(cpm2_intctl->ic_simrh);
++ sipnr = &(cpm2_intctl->ic_sipnrh);
++ ppc_cached_irq_mask[word] &= ~(1 << bit);
++ simr[word] = ppc_cached_irq_mask[word];
++ sipnr[word] = 1 << bit;
++}
++
++static void cpm2_end_irq(unsigned int irq_nr)
++{
++ int bit, word;
++ volatile uint *simr;
++
++ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
++ && irq_desc[irq_nr].action) {
++
++ irq_nr -= CPM_IRQ_OFFSET;
++ bit = irq_to_siubit[irq_nr];
++ word = irq_to_siureg[irq_nr];
++
++ simr = &(cpm2_intctl->ic_simrh);
++ ppc_cached_irq_mask[word] |= 1 << bit;
++ simr[word] = ppc_cached_irq_mask[word];
++ /*
++ * Work around large numbers of spurious IRQs on PowerPC 82xx
++ * systems.
++ */
++ mb();
++ }
++}
++
++static struct irq_chip cpm2_pic = {
++ .typename = " CPM2 SIU ",
++ .enable = cpm2_unmask_irq,
++ .disable = cpm2_mask_irq,
++ .unmask = cpm2_unmask_irq,
++ .mask_ack = cpm2_mask_and_ack,
++ .end = cpm2_end_irq,
++};
++
++unsigned int cpm2_get_irq(void)
++{
++ int irq;
++ unsigned long bits;
++
++ /* For CPM2, read the SIVEC register and shift the bits down
++ * to get the irq number. */
++ bits = cpm2_intctl->ic_sivec;
++ irq = bits >> 26;
++
++ if (irq == 0)
++ return(-1);
++ return irq+CPM_IRQ_OFFSET;
++}
++
++static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
++{
++ return cpm2_pic_node == NULL || cpm2_pic_node == node;
++}
++
++static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
++
++ get_irq_desc(virq)->status |= IRQ_LEVEL;
++ set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq);
++ return 0;
++}
++
++static void cpm2_host_unmap(struct irq_host *h, unsigned int virq)
++{
++ /* Make sure irq is masked in hardware */
++ cpm2_mask_irq(virq);
++
++ /* remove chip and handler */
++ set_irq_chip_and_handler(virq, NULL, NULL);
++}
++
++static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
++ u32 *intspec, unsigned int intsize,
++ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
++{
++ static const unsigned char map_cpm2_senses[4] = {
++ IRQ_TYPE_LEVEL_LOW,
++ IRQ_TYPE_LEVEL_HIGH,
++ IRQ_TYPE_EDGE_FALLING,
++ IRQ_TYPE_EDGE_RISING,
++ };
++
++ *out_hwirq = intspec[0];
++ if (intsize > 1 && intspec[1] < 4)
++ *out_flags = map_cpm2_senses[intspec[1]];
++ else
++ *out_flags = IRQ_TYPE_NONE;
++
++ return 0;
++}
++
++static struct irq_host_ops cpm2_pic_host_ops = {
++ .match = cpm2_pic_host_match,
++ .map = cpm2_pic_host_map,
++ .unmap = cpm2_host_unmap,
++ .xlate = cpm2_pic_host_xlate,
++};
++
++void cpm2_pic_init(struct device_node *node)
++{
++ int i;
++
++ /* Clear the CPM IRQ controller, in case it has any bits set
++ * from the bootloader
++ */
++
++ /* Mask out everything */
++
++ cpm2_intctl->ic_simrh = 0x00000000;
++ cpm2_intctl->ic_simrl = 0x00000000;
++
++ wmb();
++
++ /* Ack everything */
++ cpm2_intctl->ic_sipnrh = 0xffffffff;
++ cpm2_intctl->ic_sipnrl = 0xffffffff;
++ wmb();
++
++ /* Dummy read of the vector */
++ i = cpm2_intctl->ic_sivec;
++ rmb();
++
++ /* Initialize the default interrupt mapping priorities,
++ * in case the boot rom changed something on us.
++ */
++ cpm2_intctl->ic_sicr = 0;
++ cpm2_intctl->ic_scprrh = 0x05309770;
++ cpm2_intctl->ic_scprrl = 0x05309770;
++
++ /* create a legacy host */
++ if (node)
++ cpm2_pic_node = of_node_get(node);
++
++ cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64);
++ if (cpm2_pic_host == NULL) {
++ printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
++ return;
++ }
++}
+diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
+new file mode 100644
+index 0000000..2840616
+--- /dev/null
++++ b/arch/powerpc/sysdev/cpm2_pic.h
+@@ -0,0 +1,10 @@
++#ifndef _PPC_KERNEL_CPM2_H
++#define _PPC_KERNEL_CPM2_H
++
++extern intctl_cpm2_t *cpm2_intctl;
++
++extern unsigned int cpm2_get_irq(void);
++
++extern void cpm2_pic_init(struct device_node*);
++
++#endif /* _PPC_KERNEL_CPM2_H */
+diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h
+index 1c8817c..ff202ed 100644
+--- a/arch/powerpc/sysdev/dart.h
++++ b/arch/powerpc/sysdev/dart.h
+@@ -72,7 +72,6 @@
+
+ #define DART_PAGE_SHIFT 12
+ #define DART_PAGE_SIZE (1 << DART_PAGE_SHIFT)
+-#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_PAGE_SHIFT)
+
+
+ #endif /* _POWERPC_SYSDEV_DART_H */
+diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
+index 03b4477..572b784 100644
+--- a/arch/powerpc/sysdev/dart_iommu.c
++++ b/arch/powerpc/sysdev/dart_iommu.c
+@@ -156,9 +156,6 @@ static void dart_build(struct iommu_tabl
+
+ DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
+
+- index <<= DART_PAGE_FACTOR;
+- npages <<= DART_PAGE_FACTOR;
+-
+ dp = ((unsigned int*)tbl->it_base) + index;
+
+ /* On U3, all memory is contigous, so we can move this
+@@ -199,9 +196,6 @@ static void dart_free(struct iommu_table
+
+ DBG("dart: free at: %lx, %lx\n", index, npages);
+
+- index <<= DART_PAGE_FACTOR;
+- npages <<= DART_PAGE_FACTOR;
+-
+ dp = ((unsigned int *)tbl->it_base) + index;
+
+ while (npages--)
+@@ -281,7 +275,7 @@ static void iommu_table_dart_setup(void)
+ iommu_table_dart.it_busno = 0;
+ iommu_table_dart.it_offset = 0;
+ /* it_size is in number of entries */
+- iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
++ iommu_table_dart.it_size = dart_tablesize / sizeof(u32);
+
+ /* Initialize the common IOMMU code */
+ iommu_table_dart.it_base = (unsigned long)dart_vbase;
+diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
+index ef10bcf..dbe92ae 100644
+--- a/arch/powerpc/sysdev/fsl_soc.c
++++ b/arch/powerpc/sysdev/fsl_soc.c
+@@ -3,6 +3,9 @@
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
++ * 2006 (c) MontaVista Software, Inc.
++ * Vitaly Bordug <vbordug at ru.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
+@@ -20,15 +23,21 @@
+ #include <linux/device.h>
+ #include <linux/platform_device.h>
+ #include <linux/fsl_devices.h>
++#include <linux/fs_enet_pd.h>
++#include <linux/fs_uart_pd.h>
+
+ #include <asm/system.h>
+ #include <asm/atomic.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/time.h>
+ #include <asm/prom.h>
+ #include <sysdev/fsl_soc.h>
+ #include <mm/mmu_decl.h>
++#include <asm/cpm2.h>
+
++extern void init_fcc_ioports(struct fs_platform_info*);
++extern void init_scc_ioports(struct fs_uart_platform_info*);
+ static phys_addr_t immrbase = -1;
+
+ phys_addr_t get_immrbase(void)
+@@ -41,8 +50,10 @@ phys_addr_t get_immrbase(void)
+ soc = of_find_node_by_type(NULL, "soc");
+ if (soc) {
+ unsigned int size;
+- void *prop = get_property(soc, "reg", &size);
+- immrbase = of_translate_address(soc, prop);
++ const void *prop = get_property(soc, "reg", &size);
++
++ if (prop)
++ immrbase = of_translate_address(soc, prop);
+ of_node_put(soc);
+ };
+
+@@ -51,6 +62,59 @@ phys_addr_t get_immrbase(void)
+
+ EXPORT_SYMBOL(get_immrbase);
+
++#ifdef CONFIG_CPM2
++
++static u32 brgfreq = -1;
++
++u32 get_brgfreq(void)
++{
++ struct device_node *node;
++
++ if (brgfreq != -1)
++ return brgfreq;
++
++ node = of_find_node_by_type(NULL, "cpm");
++ if (node) {
++ unsigned int size;
++ const unsigned int *prop = get_property(node, "brg-frequency",
++ &size);
++
++ if (prop)
++ brgfreq = *prop;
++ of_node_put(node);
++ };
++
++ return brgfreq;
++}
++
++EXPORT_SYMBOL(get_brgfreq);
++
++static u32 fs_baudrate = -1;
++
++u32 get_baudrate(void)
++{
++ struct device_node *node;
++
++ if (fs_baudrate != -1)
++ return fs_baudrate;
++
++ node = of_find_node_by_type(NULL, "serial");
++ if (node) {
++ unsigned int size;
++ const unsigned int *prop = get_property(node, "current-speed",
++ &size);
++
++ if (prop)
++ fs_baudrate = *prop;
++ of_node_put(node);
++ };
++
++ return fs_baudrate;
++}
++
++EXPORT_SYMBOL(get_baudrate);
++#endif /* CONFIG_CPM2 */
++
+ static int __init gfar_mdio_of_init(void)
+ {
+ struct device_node *np;
+@@ -85,8 +149,11 @@ static int __init gfar_mdio_of_init(void
+ mdio_data.irq[k] = -1;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+- u32 *id = get_property(child, "reg", NULL);
+- mdio_data.irq[*id] = irq_of_parse_and_map(child, 0);
++ int irq = irq_of_parse_and_map(child, 0);
++ if (irq != NO_IRQ) {
++ const u32 *id = get_property(child, "reg", NULL);
++ mdio_data.irq[*id] = irq;
++ }
+ }
+
+ ret =
+@@ -124,11 +191,11 @@ static int __init gfar_of_init(void)
+ struct resource r[4];
+ struct device_node *phy, *mdio;
+ struct gianfar_platform_data gfar_data;
+- unsigned int *id;
+- char *model;
+- void *mac_addr;
+- phandle *ph;
+- int n_res = 1;
++ const unsigned int *id;
++ const char *model;
++ const void *mac_addr;
++ const phandle *ph;
++ int n_res = 2;
+
+ memset(r, 0, sizeof(r));
+ memset(&gfar_data, 0, sizeof(gfar_data));
+@@ -159,7 +226,7 @@ static int __init gfar_of_init(void)
+
+ gfar_dev =
+ platform_device_register_simple("fsl-gianfar", i, &r[0],
+- n_res + 1);
++ n_res);
+
+ if (IS_ERR(gfar_dev)) {
+ ret = PTR_ERR(gfar_dev);
+@@ -193,7 +260,7 @@ static int __init gfar_of_init(void)
+ FSL_GIANFAR_DEV_HAS_VLAN |
+ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+
+- ph = (phandle *) get_property(np, "phy-handle", NULL);
++ ph = get_property(np, "phy-handle", NULL);
+ phy = of_find_node_by_phandle(*ph);
+
+ if (phy == NULL) {
+@@ -203,7 +270,7 @@ static int __init gfar_of_init(void)
+
+ mdio = of_get_parent(phy);
+
+- id = (u32 *) get_property(phy, "reg", NULL);
++ id = get_property(phy, "reg", NULL);
+ ret = of_address_to_resource(mdio, 0, &res);
+ if (ret) {
+ of_node_put(phy);
+@@ -247,7 +314,7 @@ static int __init fsl_i2c_of_init(void)
+ i++) {
+ struct resource r[2];
+ struct fsl_i2c_platform_data i2c_data;
+- unsigned char *flags = NULL;
++ const unsigned char *flags = NULL;
+
+ memset(&r, 0, sizeof(r));
+ memset(&i2c_data, 0, sizeof(i2c_data));
+@@ -298,7 +365,7 @@ static int __init mpc83xx_wdt_init(void)
+ struct resource r;
+ struct device_node *soc, *np;
+ struct platform_device *dev;
+- unsigned int *freq;
++ const unsigned int *freq;
+ int ret;
+
+ np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
+@@ -315,7 +382,7 @@ static int __init mpc83xx_wdt_init(void)
+ goto nosoc;
+ }
+
+- freq = (unsigned int *)get_property(soc, "bus-frequency", NULL);
++ freq = get_property(soc, "bus-frequency", NULL);
+ if (!freq) {
+ ret = -ENODEV;
+ goto err;
+@@ -355,7 +422,7 @@ nodev:
+ arch_initcall(mpc83xx_wdt_init);
+ #endif
+
+-static enum fsl_usb2_phy_modes determine_usb_phy(char * phy_type)
++static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
+ {
+ if (!phy_type)
+ return FSL_USB2_PHY_NONE;
+@@ -383,7 +450,7 @@ static int __init fsl_usb_of_init(void)
+ i++) {
+ struct resource r[2];
+ struct fsl_usb2_platform_data usb_data;
+- unsigned char *prop = NULL;
++ const unsigned char *prop = NULL;
+
+ memset(&r, 0, sizeof(r));
+ memset(&usb_data, 0, sizeof(usb_data));
+@@ -431,7 +498,7 @@ static int __init fsl_usb_of_init(void)
+ i++) {
+ struct resource r[2];
+ struct fsl_usb2_platform_data usb_data;
+- unsigned char *prop = NULL;
++ const unsigned char *prop = NULL;
+
+ memset(&r, 0, sizeof(r));
+ memset(&usb_data, 0, sizeof(usb_data));
+@@ -478,3 +545,256 @@ err:
+ }
+
+ arch_initcall(fsl_usb_of_init);
++
++#ifdef CONFIG_CPM2
++
++static const char fcc_regs[] = "fcc_regs";
++static const char fcc_regs_c[] = "fcc_regs_c";
++static const char fcc_pram[] = "fcc_pram";
++static char bus_id[9][BUS_ID_SIZE];
++
++static int __init fs_enet_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *fs_enet_dev;
++ struct resource res;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
++ i++) {
++ struct resource r[4];
++ struct device_node *phy, *mdio;
++ struct fs_platform_info fs_enet_data;
++ const unsigned int *id, *phy_addr, *phy_irq;
++ const void *mac_addr;
++ const phandle *ph;
++ const char *model;
++
++ memset(r, 0, sizeof(r));
++ memset(&fs_enet_data, 0, sizeof(fs_enet_data));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++ r[0].name = fcc_regs;
++
++ ret = of_address_to_resource(np, 1, &r[1]);
++ if (ret)
++ goto err;
++ r[1].name = fcc_pram;
++
++ ret = of_address_to_resource(np, 2, &r[2]);
++ if (ret)
++ goto err;
++ r[2].name = fcc_regs_c;
++ fs_enet_data.fcc_regs_c = r[2].start;
++
++ r[3].start = r[3].end = irq_of_parse_and_map(np, 0);
++ r[3].flags = IORESOURCE_IRQ;
++
++ fs_enet_dev =
++ platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
++
++ if (IS_ERR(fs_enet_dev)) {
++ ret = PTR_ERR(fs_enet_dev);
++ goto err;
++ }
++
++ model = get_property(np, "model", NULL);
++ if (model == NULL) {
++ ret = -ENODEV;
++ goto unreg;
++ }
++
++ mac_addr = get_property(np, "mac-address", NULL);
++ memcpy(fs_enet_data.macaddr, mac_addr, 6);
++
++ ph = get_property(np, "phy-handle", NULL);
++ phy = of_find_node_by_phandle(*ph);
++
++ if (phy == NULL) {
++ ret = -ENODEV;
++ goto unreg;
++ }
++
++ phy_addr = get_property(phy, "reg", NULL);
++ fs_enet_data.phy_addr = *phy_addr;
++
++ phy_irq = get_property(phy, "interrupts", NULL);
++
++ id = get_property(np, "device-id", NULL);
++ fs_enet_data.fs_no = *id;
++ strcpy(fs_enet_data.fs_type, model);
++
++ mdio = of_get_parent(phy);
++ ret = of_address_to_resource(mdio, 0, &res);
++ if (ret) {
++ of_node_put(phy);
++ of_node_put(mdio);
++ goto unreg;
++ }
++
++ fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
++ fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
++
++ if (strstr(model, "FCC")) {
++ int fcc_index = *id - 1;
++ const unsigned char *mdio_bb_prop;
++
++ fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
++ fs_enet_data.rx_ring = 32;
++ fs_enet_data.tx_ring = 32;
++ fs_enet_data.rx_copybreak = 240;
++ fs_enet_data.use_napi = 0;
++ fs_enet_data.napi_weight = 17;
++ fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index);
++ fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index);
++ fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index);
++
++ snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
++ (u32)res.start, fs_enet_data.phy_addr);
++ fs_enet_data.bus_id = (char*)&bus_id[(*id)];
++ fs_enet_data.init_ioports = init_fcc_ioports;
++
++ mdio_bb_prop = get_property(phy, "bitbang", NULL);
++ if (mdio_bb_prop) {
++ struct platform_device *fs_enet_mdio_bb_dev;
++ struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
++
++ fs_enet_mdio_bb_dev =
++ platform_device_register_simple("fsl-bb-mdio",
++ i, NULL, 0);
++ memset(&fs_enet_mdio_bb_data, 0,
++ sizeof(struct fs_mii_bb_platform_info));
++ fs_enet_mdio_bb_data.mdio_dat.bit =
++ mdio_bb_prop[0];
++ fs_enet_mdio_bb_data.mdio_dir.bit =
++ mdio_bb_prop[1];
++ fs_enet_mdio_bb_data.mdc_dat.bit =
++ mdio_bb_prop[2];
++ fs_enet_mdio_bb_data.mdio_port =
++ mdio_bb_prop[3];
++ fs_enet_mdio_bb_data.mdc_port =
++ mdio_bb_prop[4];
++ fs_enet_mdio_bb_data.delay =
++ mdio_bb_prop[5];
++
++ fs_enet_mdio_bb_data.irq[0] = phy_irq[0];
++ fs_enet_mdio_bb_data.irq[1] = -1;
++ fs_enet_mdio_bb_data.irq[2] = -1;
++ fs_enet_mdio_bb_data.irq[3] = phy_irq[0];
++ fs_enet_mdio_bb_data.irq[31] = -1;
++
++ fs_enet_mdio_bb_data.mdio_dat.offset =
++ (u32)&cpm2_immr->im_ioport.iop_pdatc;
++ fs_enet_mdio_bb_data.mdio_dir.offset =
++ (u32)&cpm2_immr->im_ioport.iop_pdirc;
++ fs_enet_mdio_bb_data.mdc_dat.offset =
++ (u32)&cpm2_immr->im_ioport.iop_pdatc;
++
++ ret = platform_device_add_data(
++ fs_enet_mdio_bb_dev,
++ &fs_enet_mdio_bb_data,
++ sizeof(struct fs_mii_bb_platform_info));
++ if (ret)
++ goto unreg;
++ }
++
++ of_node_put(phy);
++ of_node_put(mdio);
++
++ ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
++ sizeof(struct
++ fs_platform_info));
++ if (ret)
++ goto unreg;
++ }
++ }
++ return 0;
++
++unreg:
++ platform_device_unregister(fs_enet_dev);
++err:
++ return ret;
++}
++
++arch_initcall(fs_enet_of_init);
++
++static const char scc_regs[] = "regs";
++static const char scc_pram[] = "pram";
++
++static int __init cpm_uart_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *cpm_uart_dev;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
++ i++) {
++ struct resource r[3];
++ struct fs_uart_platform_info cpm_uart_data;
++ const int *id;
++ const char *model;
++
++ memset(r, 0, sizeof(r));
++ memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ r[0].name = scc_regs;
++
++ ret = of_address_to_resource(np, 1, &r[1]);
++ if (ret)
++ goto err;
++ r[1].name = scc_pram;
++
++ r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
++ r[2].flags = IORESOURCE_IRQ;
++
++ cpm_uart_dev =
++ platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
++
++ if (IS_ERR(cpm_uart_dev)) {
++ ret = PTR_ERR(cpm_uart_dev);
++ goto err;
++ }
++
++ id = get_property(np, "device-id", NULL);
++ cpm_uart_data.fs_no = *id;
++
++ model = (char*)get_property(np, "model", NULL);
++ strcpy(cpm_uart_data.fs_type, model);
++
++ cpm_uart_data.uart_clk = ppc_proc_freq;
++
++ cpm_uart_data.tx_num_fifo = 4;
++ cpm_uart_data.tx_buf_size = 32;
++ cpm_uart_data.rx_num_fifo = 4;
++ cpm_uart_data.rx_buf_size = 32;
++ cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
++ cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
++
++ ret =
++ platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
++ sizeof(struct
++ fs_uart_platform_info));
++ if (ret)
++ goto unreg;
++ }
++
++ return 0;
++
++unreg:
++ platform_device_unregister(cpm_uart_dev);
++err:
++ return ret;
++}
++
++arch_initcall(cpm_uart_of_init);
++#endif /* CONFIG_CPM2 */
+diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
+index c433d3f..04e145b 100644
+--- a/arch/powerpc/sysdev/fsl_soc.h
++++ b/arch/powerpc/sysdev/fsl_soc.h
+@@ -2,7 +2,11 @@
+ #define __PPC_FSL_SOC_H
+ #ifdef __KERNEL__
+
++#include <asm/mmu.h>
++
+ extern phys_addr_t get_immrbase(void);
++extern u32 get_brgfreq(void);
++extern u32 get_baudrate(void);
+
+ #endif
+ #endif
+diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
+index 9855820..ad87adc 100644
+--- a/arch/powerpc/sysdev/i8259.c
++++ b/arch/powerpc/sysdev/i8259.c
+@@ -34,7 +34,7 @@ static struct irq_host *i8259_host;
+ * which is called. It should be noted that polling is broken on some
+ * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
+ */
+-unsigned int i8259_irq(struct pt_regs *regs)
++unsigned int i8259_irq(void)
+ {
+ int irq;
+ int lock = 0;
+@@ -224,7 +224,12 @@ static struct irq_host_ops i8259_host_op
+ .xlate = i8259_host_xlate,
+ };
+
+-/****
++struct irq_host *i8259_get_host(void)
++{
++ return i8259_host;
++}
++
++/**
+ * i8259_init - Initialize the legacy controller
+ * @node: device node of the legacy PIC (can be NULL, but then, it will match
+ * all interrupts, so beware)
+diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
+index 70e7077..746f78c 100644
+--- a/arch/powerpc/sysdev/ipic.c
++++ b/arch/powerpc/sysdev/ipic.c
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/ipic.c
++ * arch/powerpc/sysdev/ipic.c
+ *
+ * IPIC routines implementations.
+ *
+@@ -210,7 +210,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 4,
+ },
+ [64] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_A,
+ .force = IPIC_SIFCR_L,
+@@ -218,7 +218,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 0,
+ },
+ [65] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_A,
+ .force = IPIC_SIFCR_L,
+@@ -226,7 +226,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 1,
+ },
+ [66] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_A,
+ .force = IPIC_SIFCR_L,
+@@ -234,7 +234,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 2,
+ },
+ [67] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_A,
+ .force = IPIC_SIFCR_L,
+@@ -242,7 +242,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 3,
+ },
+ [68] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_B,
+ .force = IPIC_SIFCR_L,
+@@ -250,7 +250,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 0,
+ },
+ [69] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_B,
+ .force = IPIC_SIFCR_L,
+@@ -258,7 +258,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 1,
+ },
+ [70] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_B,
+ .force = IPIC_SIFCR_L,
+@@ -266,7 +266,7 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 2,
+ },
+ [71] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = IPIC_SMPRR_B,
+ .force = IPIC_SIFCR_L,
+@@ -274,91 +274,91 @@ static struct ipic_info ipic_info[] = {
+ .prio_mask = 3,
+ },
+ [72] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 8,
+ },
+ [73] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 9,
+ },
+ [74] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 10,
+ },
+ [75] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 11,
+ },
+ [76] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 12,
+ },
+ [77] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 13,
+ },
+ [78] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 14,
+ },
+ [79] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 15,
+ },
+ [80] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 16,
+ },
+ [84] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 20,
+ },
+ [85] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 21,
+ },
+ [90] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+ .bit = 26,
+ },
+ [91] = {
+- .pend = IPIC_SIPNR_H,
++ .pend = IPIC_SIPNR_L,
+ .mask = IPIC_SIMSR_L,
+ .prio = 0,
+ .force = IPIC_SIFCR_L,
+@@ -473,9 +473,9 @@ static int ipic_set_irq_type(unsigned in
+ desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+ if (flow_type & IRQ_TYPE_LEVEL_LOW) {
+ desc->status |= IRQ_LEVEL;
+- set_irq_handler(virq, handle_level_irq);
++ desc->handle_irq = handle_level_irq;
+ } else {
+- set_irq_handler(virq, handle_edge_irq);
++ desc->handle_irq = handle_edge_irq;
+ }
+
+ /* only EXT IRQ senses are programmable on ipic
+@@ -709,7 +709,7 @@ void ipic_clear_mcp_status(u32 mask)
+ }
+
+ /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+-unsigned int ipic_get_irq(struct pt_regs *regs)
++unsigned int ipic_get_irq(void)
+ {
+ int irq;
+
+diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c
+index 615350d..ff23f5a 100644
+--- a/arch/powerpc/sysdev/mmio_nvram.c
++++ b/arch/powerpc/sysdev/mmio_nvram.c
+@@ -80,7 +80,7 @@ static ssize_t mmio_nvram_get_size(void)
+ int __init mmio_nvram_init(void)
+ {
+ struct device_node *nvram_node;
+- unsigned long *buffer;
++ const unsigned long *buffer;
+ int proplen;
+ unsigned long nvram_addr;
+ int ret;
+@@ -91,7 +91,7 @@ int __init mmio_nvram_init(void)
+ goto out;
+
+ ret = -EIO;
+- buffer = (unsigned long *)get_property(nvram_node, "reg", &proplen);
++ buffer = get_property(nvram_node, "reg", &proplen);
+ if (proplen != 2*sizeof(unsigned long))
+ goto out;
+
+diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
+index b604926..ba4833f 100644
+--- a/arch/powerpc/sysdev/mpic.c
++++ b/arch/powerpc/sysdev/mpic.c
+@@ -339,9 +339,9 @@ static void __init mpic_scan_ht_pic(stru
+ for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+ pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+ u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+- if (id == PCI_CAP_ID_HT_IRQCONF) {
++ if (id == PCI_CAP_ID_HT) {
+ id = readb(devbase + pos + 3);
+- if (id == 0x80)
++ if (id == HT_CAPTYPE_IRQ)
+ break;
+ }
+ }
+@@ -489,9 +489,9 @@ static inline void mpic_eoi(struct mpic
+ }
+
+ #ifdef CONFIG_SMP
+-static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
+ {
+- smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs);
++ smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0);
+ return IRQ_HANDLED;
+ }
+ #endif /* CONFIG_SMP */
+@@ -1217,7 +1217,7 @@ void mpic_send_ipi(unsigned int ipi_no,
+ mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
+ }
+
+-unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
++unsigned int mpic_get_one_irq(struct mpic *mpic)
+ {
+ u32 src;
+
+@@ -1230,13 +1230,13 @@ unsigned int mpic_get_one_irq(struct mpi
+ return irq_linear_revmap(mpic->irqhost, src);
+ }
+
+-unsigned int mpic_get_irq(struct pt_regs *regs)
++unsigned int mpic_get_irq(void)
+ {
+ struct mpic *mpic = mpic_primary;
+
+ BUG_ON(mpic == NULL);
+
+- return mpic_get_one_irq(mpic, regs);
++ return mpic_get_one_irq(mpic);
+ }
+
+
+diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
+new file mode 100644
+index 0000000..a725e80
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/Kconfig
+@@ -0,0 +1,30 @@
++#
++# QE Communication options
++#
++
++menu "QE Options"
++ depends on QUICC_ENGINE
++
++config UCC_SLOW
++ bool "UCC Slow Protocols Support"
++ default n
++ select UCC
++ help
++ This option provides qe_lib support to UCC slow
++ protocols: UART, BISYNC, QMC
++
++config UCC_FAST
++ bool "UCC Fast Protocols Support"
++ default n
++ select UCC
++ select UCC_SLOW
++ help
++ This option provides qe_lib support to UCC fast
++ protocols: HDLC, Ethernet, ATM, transparent
++
++config UCC
++ bool
++ default y if UCC_FAST || UCC_SLOW
++
++endmenu
++
+diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile
+new file mode 100644
+index 0000000..874fe1a
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/Makefile
+@@ -0,0 +1,8 @@
++#
++# Makefile for the linux ppc-specific parts of QE
++#
++obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o
++
++obj-$(CONFIG_UCC) += ucc.o
++obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
++obj-$(CONFIG_UCC_FAST) += ucc_fast.o
+diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
+new file mode 100644
+index 0000000..e422322
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/qe.c
+@@ -0,0 +1,352 @@
++/*
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
++ * Based on cpm2_common.c from Dan Malek (dmalek at jlc.net)
++ *
++ * Description:
++ * General Purpose functions for the global management of the
++ * QUICC Engine (QE).
++ *
++ * 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/errno.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/param.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/bootmem.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <asm/irq.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++#include <asm/prom.h>
++#include <asm/rheap.h>
++
++static void qe_snums_init(void);
++static void qe_muram_init(void);
++static int qe_sdma_init(void);
++
++static DEFINE_SPINLOCK(qe_lock);
++
++/* QE snum state */
++enum qe_snum_state {
++ QE_SNUM_STATE_USED,
++ QE_SNUM_STATE_FREE
++};
++
++/* QE snum */
++struct qe_snum {
++ u8 num;
++ enum qe_snum_state state;
++};
++
++/* We allocate this here because it is used almost exclusively for
++ * the communication processor devices.
++ */
++struct qe_immap *qe_immr = NULL;
++EXPORT_SYMBOL(qe_immr);
++
++static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
++
++static phys_addr_t qebase = -1;
++
++phys_addr_t get_qe_base(void)
++{
++ struct device_node *qe;
++
++ if (qebase != -1)
++ return qebase;
++
++ qe = of_find_node_by_type(NULL, "qe");
++ if (qe) {
++ unsigned int size;
++ const void *prop = get_property(qe, "reg", &size);
++ qebase = of_translate_address(qe, prop);
++ of_node_put(qe);
++ };
++
++ return qebase;
++}
++
++EXPORT_SYMBOL(get_qe_base);
++
++void qe_reset(void)
++{
++ if (qe_immr == NULL)
++ qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
++
++ qe_snums_init();
++
++ qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
++ QE_CR_PROTOCOL_UNSPECIFIED, 0);
++
++ /* Reclaim the MURAM memory for our use. */
++ qe_muram_init();
++
++ if (qe_sdma_init())
++ panic("sdma init failed!");
++}
++
++int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
++{
++ unsigned long flags;
++ u8 mcn_shift = 0, dev_shift = 0;
++
++ spin_lock_irqsave(&qe_lock, flags);
++ if (cmd == QE_RESET) {
++ out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
++ } else {
++ if (cmd == QE_ASSIGN_PAGE) {
++ /* Here device is the SNUM, not sub-block */
++ dev_shift = QE_CR_SNUM_SHIFT;
++ } else if (cmd == QE_ASSIGN_RISC) {
++ /* Here device is the SNUM, and mcnProtocol is
++ * e_QeCmdRiscAssignment value */
++ dev_shift = QE_CR_SNUM_SHIFT;
++ mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
++ } else {
++ if (device == QE_CR_SUBBLOCK_USB)
++ mcn_shift = QE_CR_MCN_USB_SHIFT;
++ else
++ mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
++ }
++
++ out_be32(&qe_immr->cp.cecdr, cmd_input);
++ out_be32(&qe_immr->cp.cecr,
++ (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
++ mcn_protocol << mcn_shift));
++ }
++
++ /* wait for the QE_CR_FLG to clear */
++ while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
++ cpu_relax();
++ spin_unlock_irqrestore(&qe_lock, flags);
++
++ return 0;
++}
++EXPORT_SYMBOL(qe_issue_cmd);
++
++/* Set a baud rate generator. This needs lots of work. There are
++ * 16 BRGs, which can be connected to the QE channels or output
++ * as clocks. The BRGs are in two different block of internal
++ * memory mapped space.
++ * The baud rate clock is the system clock divided by something.
++ * It was set up long ago during the initial boot phase and is
++ * is given to us.
++ * Baud rate clocks are zero-based in the driver code (as that maps
++ * to port numbers). Documentation uses 1-based numbering.
++ */
++static unsigned int brg_clk = 0;
++
++unsigned int get_brg_clk(void)
++{
++ struct device_node *qe;
++ if (brg_clk)
++ return brg_clk;
++
++ qe = of_find_node_by_type(NULL, "qe");
++ if (qe) {
++ unsigned int size;
++ const u32 *prop = get_property(qe, "brg-frequency", &size);
++ brg_clk = *prop;
++ of_node_put(qe);
++ };
++ return brg_clk;
++}
++
++/* This function is used by UARTS, or anything else that uses a 16x
++ * oversampled clock.
++ */
++void qe_setbrg(u32 brg, u32 rate)
++{
++ volatile u32 *bp;
++ u32 divisor, tempval;
++ int div16 = 0;
++
++ bp = &qe_immr->brg.brgc1;
++ bp += brg;
++
++ divisor = (get_brg_clk() / rate);
++ if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
++ div16 = 1;
++ divisor /= 16;
++ }
++
++ tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
++ if (div16)
++ tempval |= QE_BRGC_DIV16;
++
++ out_be32(bp, tempval);
++}
++
++/* Initialize SNUMs (thread serial numbers) according to
++ * QE Module Control chapter, SNUM table
++ */
++static void qe_snums_init(void)
++{
++ int i;
++ static const u8 snum_init[] = {
++ 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
++ 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
++ 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
++ 0xD8, 0xD9, 0xE8, 0xE9,
++ };
++
++ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
++ snums[i].num = snum_init[i];
++ snums[i].state = QE_SNUM_STATE_FREE;
++ }
++}
++
++int qe_get_snum(void)
++{
++ unsigned long flags;
++ int snum = -EBUSY;
++ int i;
++
++ spin_lock_irqsave(&qe_lock, flags);
++ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
++ if (snums[i].state == QE_SNUM_STATE_FREE) {
++ snums[i].state = QE_SNUM_STATE_USED;
++ snum = snums[i].num;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&qe_lock, flags);
++
++ return snum;
++}
++EXPORT_SYMBOL(qe_get_snum);
++
++void qe_put_snum(u8 snum)
++{
++ int i;
++
++ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
++ if (snums[i].num == snum) {
++ snums[i].state = QE_SNUM_STATE_FREE;
++ break;
++ }
++ }
++}
++EXPORT_SYMBOL(qe_put_snum);
++
++static int qe_sdma_init(void)
++{
++ struct sdma *sdma = &qe_immr->sdma;
++ u32 sdma_buf_offset;
++
++ if (!sdma)
++ return -ENODEV;
++
++ /* allocate 2 internal temporary buffers (512 bytes size each) for
++ * the SDMA */
++ sdma_buf_offset = qe_muram_alloc(512 * 2, 64);
++ if (IS_MURAM_ERR(sdma_buf_offset))
++ return -ENOMEM;
++
++ out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
++ out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
++ QE_SDMR_CEN_SHIFT)));
++
++ return 0;
++}
++
++/*
++ * muram_alloc / muram_free bits.
++ */
++static DEFINE_SPINLOCK(qe_muram_lock);
++
++/* 16 blocks should be enough to satisfy all requests
++ * until the memory subsystem goes up... */
++static rh_block_t qe_boot_muram_rh_block[16];
++static rh_info_t qe_muram_info;
++
++static void qe_muram_init(void)
++{
++ struct device_node *np;
++ u32 address;
++ u64 size;
++ unsigned int flags;
++
++ /* initialize the info header */
++ rh_init(&qe_muram_info, 1,
++ sizeof(qe_boot_muram_rh_block) /
++ sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
++
++ /* Attach the usable muram area */
++ /* XXX: This is a subset of the available muram. It
++ * varies with the processor and the microcode patches activated.
++ */
++ if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
++ address = *of_get_address(np, 0, &size, &flags);
++ of_node_put(np);
++ rh_attach_region(&qe_muram_info,
++ (void *)address, (int)size);
++ }
++}
++
++/* This function returns an index into the MURAM area.
++ */
++u32 qe_muram_alloc(u32 size, u32 align)
++{
++ void *start;
++ unsigned long flags;
++
++ spin_lock_irqsave(&qe_muram_lock, flags);
++ start = rh_alloc_align(&qe_muram_info, size, align, "QE");
++ spin_unlock_irqrestore(&qe_muram_lock, flags);
++
++ return (u32) start;
++}
++EXPORT_SYMBOL(qe_muram_alloc);
++
++int qe_muram_free(u32 offset)
++{
++ int ret;
++ unsigned long flags;
++
++ spin_lock_irqsave(&qe_muram_lock, flags);
++ ret = rh_free(&qe_muram_info, (void *)offset);
++ spin_unlock_irqrestore(&qe_muram_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(qe_muram_free);
++
++/* not sure if this is ever needed */
++u32 qe_muram_alloc_fixed(u32 offset, u32 size)
++{
++ void *start;
++ unsigned long flags;
++
++ spin_lock_irqsave(&qe_muram_lock, flags);
++ start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
++ spin_unlock_irqrestore(&qe_muram_lock, flags);
++
++ return (u32) start;
++}
++EXPORT_SYMBOL(qe_muram_alloc_fixed);
++
++void qe_muram_dump(void)
++{
++ rh_dump(&qe_muram_info);
++}
++EXPORT_SYMBOL(qe_muram_dump);
++
++void *qe_muram_addr(u32 offset)
++{
++ return (void *)&qe_immr->muram[offset];
++}
++EXPORT_SYMBOL(qe_muram_addr);
+diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
+new file mode 100644
+index 0000000..6995f51
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
+@@ -0,0 +1,553 @@
++/*
++ * arch/powerpc/sysdev/qe_lib/qe_ic.c
++ *
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Author: Li Yang <leoli at freescale.com>
++ * Based on code from Shlomi Gridish <gridish at freescale.com>
++ *
++ * QUICC ENGINE Interrupt Controller
++ *
++ * 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/errno.h>
++#include <linux/reboot.h>
++#include <linux/slab.h>
++#include <linux/stddef.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/sysdev.h>
++#include <linux/device.h>
++#include <linux/bootmem.h>
++#include <linux/spinlock.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/prom.h>
++#include <asm/qe_ic.h>
++
++#include "qe_ic.h"
++
++static DEFINE_SPINLOCK(qe_ic_lock);
++
++static struct qe_ic_info qe_ic_info[] = {
++ [1] = {
++ .mask = 0x00008000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 0,
++ .pri_reg = QEIC_CIPWCC,
++ },
++ [2] = {
++ .mask = 0x00004000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 1,
++ .pri_reg = QEIC_CIPWCC,
++ },
++ [3] = {
++ .mask = 0x00002000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 2,
++ .pri_reg = QEIC_CIPWCC,
++ },
++ [10] = {
++ .mask = 0x00000040,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 1,
++ .pri_reg = QEIC_CIPZCC,
++ },
++ [11] = {
++ .mask = 0x00000020,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 2,
++ .pri_reg = QEIC_CIPZCC,
++ },
++ [12] = {
++ .mask = 0x00000010,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 3,
++ .pri_reg = QEIC_CIPZCC,
++ },
++ [13] = {
++ .mask = 0x00000008,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 4,
++ .pri_reg = QEIC_CIPZCC,
++ },
++ [14] = {
++ .mask = 0x00000004,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 5,
++ .pri_reg = QEIC_CIPZCC,
++ },
++ [15] = {
++ .mask = 0x00000002,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 6,
++ .pri_reg = QEIC_CIPZCC,
++ },
++ [20] = {
++ .mask = 0x10000000,
++ .mask_reg = QEIC_CRIMR,
++ .pri_code = 3,
++ .pri_reg = QEIC_CIPRTA,
++ },
++ [25] = {
++ .mask = 0x00800000,
++ .mask_reg = QEIC_CRIMR,
++ .pri_code = 0,
++ .pri_reg = QEIC_CIPRTB,
++ },
++ [26] = {
++ .mask = 0x00400000,
++ .mask_reg = QEIC_CRIMR,
++ .pri_code = 1,
++ .pri_reg = QEIC_CIPRTB,
++ },
++ [27] = {
++ .mask = 0x00200000,
++ .mask_reg = QEIC_CRIMR,
++ .pri_code = 2,
++ .pri_reg = QEIC_CIPRTB,
++ },
++ [28] = {
++ .mask = 0x00100000,
++ .mask_reg = QEIC_CRIMR,
++ .pri_code = 3,
++ .pri_reg = QEIC_CIPRTB,
++ },
++ [32] = {
++ .mask = 0x80000000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 0,
++ .pri_reg = QEIC_CIPXCC,
++ },
++ [33] = {
++ .mask = 0x40000000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 1,
++ .pri_reg = QEIC_CIPXCC,
++ },
++ [34] = {
++ .mask = 0x20000000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 2,
++ .pri_reg = QEIC_CIPXCC,
++ },
++ [35] = {
++ .mask = 0x10000000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 3,
++ .pri_reg = QEIC_CIPXCC,
++ },
++ [36] = {
++ .mask = 0x08000000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 4,
++ .pri_reg = QEIC_CIPXCC,
++ },
++ [40] = {
++ .mask = 0x00800000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 0,
++ .pri_reg = QEIC_CIPYCC,
++ },
++ [41] = {
++ .mask = 0x00400000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 1,
++ .pri_reg = QEIC_CIPYCC,
++ },
++ [42] = {
++ .mask = 0x00200000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 2,
++ .pri_reg = QEIC_CIPYCC,
++ },
++ [43] = {
++ .mask = 0x00100000,
++ .mask_reg = QEIC_CIMR,
++ .pri_code = 3,
++ .pri_reg = QEIC_CIPYCC,
++ },
++};
++
++static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg)
++{
++ return in_be32(base + (reg >> 2));
++}
++
++static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg,
++ u32 value)
++{
++ out_be32(base + (reg >> 2), value);
++}
++
++static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
++{
++ return irq_desc[virq].chip_data;
++}
++
++#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
++
++static void qe_ic_unmask_irq(unsigned int virq)
++{
++ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++ unsigned int src = virq_to_hw(virq);
++ unsigned long flags;
++ u32 temp;
++
++ spin_lock_irqsave(&qe_ic_lock, flags);
++
++ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
++ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
++ temp | qe_ic_info[src].mask);
++
++ spin_unlock_irqrestore(&qe_ic_lock, flags);
++}
++
++static void qe_ic_mask_irq(unsigned int virq)
++{
++ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++ unsigned int src = virq_to_hw(virq);
++ unsigned long flags;
++ u32 temp;
++
++ spin_lock_irqsave(&qe_ic_lock, flags);
++
++ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
++ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
++ temp & ~qe_ic_info[src].mask);
++
++ spin_unlock_irqrestore(&qe_ic_lock, flags);
++}
++
++static void qe_ic_mask_irq_and_ack(unsigned int virq)
++{
++ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++ unsigned int src = virq_to_hw(virq);
++ unsigned long flags;
++ u32 temp;
++
++ spin_lock_irqsave(&qe_ic_lock, flags);
++
++ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
++ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
++ temp & ~qe_ic_info[src].mask);
++
++ /* There is nothing to do for ack here, ack is handled in ISR */
++
++ spin_unlock_irqrestore(&qe_ic_lock, flags);
++}
++
++static struct irq_chip qe_ic_irq_chip = {
++ .typename = " QEIC ",
++ .unmask = qe_ic_unmask_irq,
++ .mask = qe_ic_mask_irq,
++ .mask_ack = qe_ic_mask_irq_and_ack,
++};
++
++static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
++{
++ struct qe_ic *qe_ic = h->host_data;
++
++ /* Exact match, unless qe_ic node is NULL */
++ return qe_ic->of_node == NULL || qe_ic->of_node == node;
++}
++
++static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ struct qe_ic *qe_ic = h->host_data;
++ struct irq_chip *chip;
++
++ if (qe_ic_info[hw].mask == 0) {
++ printk(KERN_ERR "Can't map reserved IRQ \n");
++ return -EINVAL;
++ }
++ /* Default chip */
++ chip = &qe_ic->hc_irq;
++
++ set_irq_chip_data(virq, qe_ic);
++ get_irq_desc(virq)->status |= IRQ_LEVEL;
++
++ set_irq_chip_and_handler(virq, chip, handle_level_irq);
++
++ return 0;
++}
++
++static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct,
++ u32 * intspec, unsigned int intsize,
++ irq_hw_number_t * out_hwirq,
++ unsigned int *out_flags)
++{
++ *out_hwirq = intspec[0];
++ if (intsize > 1)
++ *out_flags = intspec[1];
++ else
++ *out_flags = IRQ_TYPE_NONE;
++ return 0;
++}
++
++static struct irq_host_ops qe_ic_host_ops = {
++ .match = qe_ic_host_match,
++ .map = qe_ic_host_map,
++ .xlate = qe_ic_host_xlate,
++};
++
++/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
++unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
++{
++ int irq;
++
++ BUG_ON(qe_ic == NULL);
++
++ /* get the interrupt source vector. */
++ irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
++
++ if (irq == 0)
++ return NO_IRQ;
++
++ return irq_linear_revmap(qe_ic->irqhost, irq);
++}
++
++/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
++unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
++{
++ int irq;
++
++ BUG_ON(qe_ic == NULL);
++
++ /* get the interrupt source vector. */
++ irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
++
++ if (irq == 0)
++ return NO_IRQ;
++
++ return irq_linear_revmap(qe_ic->irqhost, irq);
++}
++
++/* FIXME: We mask all the QE Low interrupts while handling. We should
++ * let other interrupt come in, but BAD interrupts are generated */
++void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
++{
++ struct qe_ic *qe_ic = desc->handler_data;
++ struct irq_chip *chip = irq_desc[irq].chip;
++
++ unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
++
++ chip->mask_ack(irq);
++ if (cascade_irq != NO_IRQ)
++ generic_handle_irq(cascade_irq);
++ chip->unmask(irq);
++}
++
++/* FIXME: We mask all the QE High interrupts while handling. We should
++ * let other interrupt come in, but BAD interrupts are generated */
++void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
++{
++ struct qe_ic *qe_ic = desc->handler_data;
++ struct irq_chip *chip = irq_desc[irq].chip;
++
++ unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
++
++ chip->mask_ack(irq);
++ if (cascade_irq != NO_IRQ)
++ generic_handle_irq(cascade_irq);
++ chip->unmask(irq);
++}
++
++void __init qe_ic_init(struct device_node *node, unsigned int flags)
++{
++ struct qe_ic *qe_ic;
++ struct resource res;
++ u32 temp = 0, ret, high_active = 0;
++
++ qe_ic = alloc_bootmem(sizeof(struct qe_ic));
++ if (qe_ic == NULL)
++ return;
++
++ memset(qe_ic, 0, sizeof(struct qe_ic));
++ qe_ic->of_node = node ? of_node_get(node) : NULL;
++
++ qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
++ NR_QE_IC_INTS, &qe_ic_host_ops, 0);
++ if (qe_ic->irqhost == NULL) {
++ of_node_put(node);
++ return;
++ }
++
++ ret = of_address_to_resource(node, 0, &res);
++ if (ret)
++ return;
++
++ qe_ic->regs = ioremap(res.start, res.end - res.start + 1);
++
++ qe_ic->irqhost->host_data = qe_ic;
++ qe_ic->hc_irq = qe_ic_irq_chip;
++
++ qe_ic->virq_high = irq_of_parse_and_map(node, 0);
++ qe_ic->virq_low = irq_of_parse_and_map(node, 1);
++
++ if (qe_ic->virq_low == NO_IRQ) {
++ printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
++ return;
++ }
++
++ /* default priority scheme is grouped. If spread mode is */
++ /* required, configure cicr accordingly. */
++ if (flags & QE_IC_SPREADMODE_GRP_W)
++ temp |= CICR_GWCC;
++ if (flags & QE_IC_SPREADMODE_GRP_X)
++ temp |= CICR_GXCC;
++ if (flags & QE_IC_SPREADMODE_GRP_Y)
++ temp |= CICR_GYCC;
++ if (flags & QE_IC_SPREADMODE_GRP_Z)
++ temp |= CICR_GZCC;
++ if (flags & QE_IC_SPREADMODE_GRP_RISCA)
++ temp |= CICR_GRTA;
++ if (flags & QE_IC_SPREADMODE_GRP_RISCB)
++ temp |= CICR_GRTB;
++
++ /* choose destination signal for highest priority interrupt */
++ if (flags & QE_IC_HIGH_SIGNAL) {
++ temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT);
++ high_active = 1;
++ }
++
++ qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
++
++ set_irq_data(qe_ic->virq_low, qe_ic);
++ set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low);
++
++ if (qe_ic->virq_high != NO_IRQ) {
++ set_irq_data(qe_ic->virq_high, qe_ic);
++ set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high);
++ }
++
++ printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs);
++}
++
++void qe_ic_set_highest_priority(unsigned int virq, int high)
++{
++ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++ unsigned int src = virq_to_hw(virq);
++ u32 temp = 0;
++
++ temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
++
++ temp &= ~CICR_HP_MASK;
++ temp |= src << CICR_HP_SHIFT;
++
++ temp &= ~CICR_HPIT_MASK;
++ temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
++
++ qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
++}
++
++/* Set Priority level within its group, from 1 to 8 */
++int qe_ic_set_priority(unsigned int virq, unsigned int priority)
++{
++ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++ unsigned int src = virq_to_hw(virq);
++ u32 temp;
++
++ if (priority > 8 || priority == 0)
++ return -EINVAL;
++ if (src > 127)
++ return -EINVAL;
++ if (qe_ic_info[src].pri_reg == 0)
++ return -EINVAL;
++
++ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
++
++ if (priority < 4) {
++ temp &= ~(0x7 << (32 - priority * 3));
++ temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
++ } else {
++ temp &= ~(0x7 << (24 - priority * 3));
++ temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
++ }
++
++ qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
++
++ return 0;
++}
++
++/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
++int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
++{
++ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++ unsigned int src = virq_to_hw(virq);
++ u32 temp, control_reg = QEIC_CICNR, shift = 0;
++
++ if (priority > 2 || priority == 0)
++ return -EINVAL;
++
++ switch (qe_ic_info[src].pri_reg) {
++ case QEIC_CIPZCC:
++ shift = CICNR_ZCC1T_SHIFT;
++ break;
++ case QEIC_CIPWCC:
++ shift = CICNR_WCC1T_SHIFT;
++ break;
++ case QEIC_CIPYCC:
++ shift = CICNR_YCC1T_SHIFT;
++ break;
++ case QEIC_CIPXCC:
++ shift = CICNR_XCC1T_SHIFT;
++ break;
++ case QEIC_CIPRTA:
++ shift = CRICR_RTA1T_SHIFT;
++ control_reg = QEIC_CRICR;
++ break;
++ case QEIC_CIPRTB:
++ shift = CRICR_RTB1T_SHIFT;
++ control_reg = QEIC_CRICR;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ shift += (2 - priority) * 2;
++ temp = qe_ic_read(qe_ic->regs, control_reg);
++ temp &= ~(SIGNAL_MASK << shift);
++ temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
++ qe_ic_write(qe_ic->regs, control_reg, temp);
++
++ return 0;
++}
++
++static struct sysdev_class qe_ic_sysclass = {
++ set_kset_name("qe_ic"),
++};
++
++static struct sys_device device_qe_ic = {
++ .id = 0,
++ .cls = &qe_ic_sysclass,
++};
++
++static int __init init_qe_ic_sysfs(void)
++{
++ int rc;
++
++ printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
++
++ rc = sysdev_class_register(&qe_ic_sysclass);
++ if (rc) {
++ printk(KERN_ERR "Failed registering qe_ic sys class\n");
++ return -ENODEV;
++ }
++ rc = sysdev_register(&device_qe_ic);
++ if (rc) {
++ printk(KERN_ERR "Failed registering qe_ic sys device\n");
++ return -ENODEV;
++ }
++ return 0;
++}
++
++subsys_initcall(init_qe_ic_sysfs);
+diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h
+new file mode 100644
+index 0000000..9a631ad
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h
+@@ -0,0 +1,106 @@
++/*
++ * arch/powerpc/sysdev/qe_lib/qe_ic.h
++ *
++ * QUICC ENGINE Interrupt Controller Header
++ *
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Author: Li Yang <leoli at freescale.com>
++ * Based on code from Shlomi Gridish <gridish at freescale.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.
++ */
++#ifndef _POWERPC_SYSDEV_QE_IC_H
++#define _POWERPC_SYSDEV_QE_IC_H
++
++#include <asm/qe_ic.h>
++
++#define NR_QE_IC_INTS 64
++
++/* QE IC registers offset */
++#define QEIC_CICR 0x00
++#define QEIC_CIVEC 0x04
++#define QEIC_CRIPNR 0x08
++#define QEIC_CIPNR 0x0c
++#define QEIC_CIPXCC 0x10
++#define QEIC_CIPYCC 0x14
++#define QEIC_CIPWCC 0x18
++#define QEIC_CIPZCC 0x1c
++#define QEIC_CIMR 0x20
++#define QEIC_CRIMR 0x24
++#define QEIC_CICNR 0x28
++#define QEIC_CIPRTA 0x30
++#define QEIC_CIPRTB 0x34
++#define QEIC_CRICR 0x3c
++#define QEIC_CHIVEC 0x60
++
++/* Interrupt priority registers */
++#define CIPCC_SHIFT_PRI0 29
++#define CIPCC_SHIFT_PRI1 26
++#define CIPCC_SHIFT_PRI2 23
++#define CIPCC_SHIFT_PRI3 20
++#define CIPCC_SHIFT_PRI4 13
++#define CIPCC_SHIFT_PRI5 10
++#define CIPCC_SHIFT_PRI6 7
++#define CIPCC_SHIFT_PRI7 4
++
++/* CICR priority modes */
++#define CICR_GWCC 0x00040000
++#define CICR_GXCC 0x00020000
++#define CICR_GYCC 0x00010000
++#define CICR_GZCC 0x00080000
++#define CICR_GRTA 0x00200000
++#define CICR_GRTB 0x00400000
++#define CICR_HPIT_SHIFT 8
++#define CICR_HPIT_MASK 0x00000300
++#define CICR_HP_SHIFT 24
++#define CICR_HP_MASK 0x3f000000
++
++/* CICNR */
++#define CICNR_WCC1T_SHIFT 20
++#define CICNR_ZCC1T_SHIFT 28
++#define CICNR_YCC1T_SHIFT 12
++#define CICNR_XCC1T_SHIFT 4
++
++/* CRICR */
++#define CRICR_RTA1T_SHIFT 20
++#define CRICR_RTB1T_SHIFT 28
++
++/* Signal indicator */
++#define SIGNAL_MASK 3
++#define SIGNAL_HIGH 2
++#define SIGNAL_LOW 0
++
++struct qe_ic {
++ /* Control registers offset */
++ volatile u32 __iomem *regs;
++
++ /* The remapper for this QEIC */
++ struct irq_host *irqhost;
++
++ /* The "linux" controller struct */
++ struct irq_chip hc_irq;
++
++ /* The device node of the interrupt controller */
++ struct device_node *of_node;
++
++ /* VIRQ numbers of QE high/low irqs */
++ unsigned int virq_high;
++ unsigned int virq_low;
++};
++
++/*
++ * QE interrupt controller internal structure
++ */
++struct qe_ic_info {
++ u32 mask; /* location of this source at the QIMR register. */
++ u32 mask_reg; /* Mask register offset */
++ u8 pri_code; /* for grouped interrupts sources - the interrupt
++ code as appears at the group priority register */
++ u32 pri_reg; /* Group priority register offset */
++};
++
++#endif /* _POWERPC_SYSDEV_QE_IC_H */
+diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
+new file mode 100644
+index 0000000..0afe6bf
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
+@@ -0,0 +1,225 @@
++/*
++ * arch/powerpc/sysdev/qe_lib/qe_io.c
++ *
++ * QE Parallel I/O ports configuration routines
++ *
++ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
++ *
++ * Author: Li Yang <LeoLi at freescale.com>
++ * Based on code from Shlomi Gridish <gridish at freescale.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/stddef.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/ioport.h>
++
++#include <asm/io.h>
++#include <asm/prom.h>
++#include <sysdev/fsl_soc.h>
++
++#undef DEBUG
++
++#define NUM_OF_PINS 32
++
++struct port_regs {
++ __be32 cpodr; /* Open drain register */
++ __be32 cpdata; /* Data register */
++ __be32 cpdir1; /* Direction register */
++ __be32 cpdir2; /* Direction register */
++ __be32 cppar1; /* Pin assignment register */
++ __be32 cppar2; /* Pin assignment register */
++};
++
++static struct port_regs *par_io = NULL;
++static int num_par_io_ports = 0;
++
++int par_io_init(struct device_node *np)
++{
++ struct resource res;
++ int ret;
++ const u32 *num_ports;
++
++ /* Map Parallel I/O ports registers */
++ ret = of_address_to_resource(np, 0, &res);
++ if (ret)
++ return ret;
++ par_io = ioremap(res.start, res.end - res.start + 1);
++
++ num_ports = get_property(np, "num-ports", NULL);
++ if (num_ports)
++ num_par_io_ports = *num_ports;
++
++ return 0;
++}
++
++int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
++ int assignment, int has_irq)
++{
++ u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
++
++ if (!par_io)
++ return -1;
++
++ /* calculate pin location for single and 2 bits information */
++ pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
++
++ /* Set open drain, if required */
++ tmp_val = in_be32(&par_io[port].cpodr);
++ if (open_drain)
++ out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
++ else
++ out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
++
++ /* define direction */
++ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
++ in_be32(&par_io[port].cpdir2) :
++ in_be32(&par_io[port].cpdir1);
++
++ /* get all bits mask for 2 bit per port */
++ pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
++ (pin % (NUM_OF_PINS / 2) + 1) * 2));
++
++ /* Get the final mask we need for the right definition */
++ new_mask2bits = (u32) (dir << (NUM_OF_PINS -
++ (pin % (NUM_OF_PINS / 2) + 1) * 2));
++
++ /* clear and set 2 bits mask */
++ if (pin > (NUM_OF_PINS / 2) - 1) {
++ out_be32(&par_io[port].cpdir2,
++ ~pin_mask2bits & tmp_val);
++ tmp_val &= ~pin_mask2bits;
++ out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
++ } else {
++ out_be32(&par_io[port].cpdir1,
++ ~pin_mask2bits & tmp_val);
++ tmp_val &= ~pin_mask2bits;
++ out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
++ }
++ /* define pin assignment */
++ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
++ in_be32(&par_io[port].cppar2) :
++ in_be32(&par_io[port].cppar1);
++
++ new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
++ (pin % (NUM_OF_PINS / 2) + 1) * 2));
++ /* clear and set 2 bits mask */
++ if (pin > (NUM_OF_PINS / 2) - 1) {
++ out_be32(&par_io[port].cppar2,
++ ~pin_mask2bits & tmp_val);
++ tmp_val &= ~pin_mask2bits;
++ out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
++ } else {
++ out_be32(&par_io[port].cppar1,
++ ~pin_mask2bits & tmp_val);
++ tmp_val &= ~pin_mask2bits;
++ out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(par_io_config_pin);
++
++int par_io_data_set(u8 port, u8 pin, u8 val)
++{
++ u32 pin_mask, tmp_val;
++
++ if (port >= num_par_io_ports)
++ return -EINVAL;
++ if (pin >= NUM_OF_PINS)
++ return -EINVAL;
++ /* calculate pin location */
++ pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin));
++
++ tmp_val = in_be32(&par_io[port].cpdata);
++
++ if (val == 0) /* clear */
++ out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val);
++ else /* set */
++ out_be32(&par_io[port].cpdata, pin_mask | tmp_val);
++
++ return 0;
++}
++EXPORT_SYMBOL(par_io_data_set);
++
++int par_io_of_config(struct device_node *np)
++{
++ struct device_node *pio;
++ const phandle *ph;
++ int pio_map_len;
++ const unsigned int *pio_map;
++
++ if (par_io == NULL) {
++ printk(KERN_ERR "par_io not initialized \n");
++ return -1;
++ }
++
++ ph = get_property(np, "pio-handle", NULL);
++ if (ph == 0) {
++ printk(KERN_ERR "pio-handle not available \n");
++ return -1;
++ }
++
++ pio = of_find_node_by_phandle(*ph);
++
++ pio_map = get_property(pio, "pio-map", &pio_map_len);
++ if (pio_map == NULL) {
++ printk(KERN_ERR "pio-map is not set! \n");
++ return -1;
++ }
++ pio_map_len /= sizeof(unsigned int);
++ if ((pio_map_len % 6) != 0) {
++ printk(KERN_ERR "pio-map format wrong! \n");
++ return -1;
++ }
++
++ while (pio_map_len > 0) {
++ par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
++ (int) pio_map[2], (int) pio_map[3],
++ (int) pio_map[4], (int) pio_map[5]);
++ pio_map += 6;
++ pio_map_len -= 6;
++ }
++ of_node_put(pio);
++ return 0;
++}
++EXPORT_SYMBOL(par_io_of_config);
++
++#ifdef DEBUG
++static void dump_par_io(void)
++{
++ int i;
++
++ printk(KERN_INFO "PAR IO registars:\n");
++ printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io);
++ for (i = 0; i < num_par_io_ports; i++) {
++ printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n",
++ i, (u32) & par_io[i].cpodr,
++ in_be32(&par_io[i].cpodr));
++ printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n",
++ i, (u32) & par_io[i].cpdata,
++ in_be32(&par_io[i].cpdata));
++ printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n",
++ i, (u32) & par_io[i].cpdir1,
++ in_be32(&par_io[i].cpdir1));
++ printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n",
++ i, (u32) & par_io[i].cpdir2,
++ in_be32(&par_io[i].cpdir2));
++ printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n",
++ i, (u32) & par_io[i].cppar1,
++ in_be32(&par_io[i].cppar1));
++ printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n",
++ i, (u32) & par_io[i].cppar2,
++ in_be32(&par_io[i].cppar2));
++ }
++
++}
++EXPORT_SYMBOL(dump_par_io);
++#endif /* DEBUG */
+diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
+new file mode 100644
+index 0000000..ac12a44
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/ucc.c
+@@ -0,0 +1,253 @@
++/*
++ * arch/powerpc/sysdev/qe_lib/ucc.c
++ *
++ * QE UCC API Set - UCC specific routines implementations.
++ *
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.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/errno.h>
++#include <linux/slab.h>
++#include <linux/stddef.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++#include <asm/ucc.h>
++
++static DEFINE_SPINLOCK(ucc_lock);
++
++int ucc_set_qe_mux_mii_mng(int ucc_num)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ucc_lock, flags);
++ out_be32(&qe_immr->qmx.cmxgcr,
++ ((in_be32(&qe_immr->qmx.cmxgcr) &
++ ~QE_CMXGCR_MII_ENET_MNG) |
++ (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT)));
++ spin_unlock_irqrestore(&ucc_lock, flags);
++
++ return 0;
++}
++
++int ucc_set_type(int ucc_num, struct ucc_common *regs,
++ enum ucc_speed_type speed)
++{
++ u8 guemr = 0;
++
++ /* check if the UCC number is in range. */
++ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
++ return -EINVAL;
++
++ guemr = regs->guemr;
++ guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX);
++ switch (speed) {
++ case UCC_SPEED_TYPE_SLOW:
++ guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
++ break;
++ case UCC_SPEED_TYPE_FAST:
++ guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX);
++ break;
++ default:
++ return -EINVAL;
++ }
++ regs->guemr = guemr;
++
++ return 0;
++}
++
++int ucc_init_guemr(struct ucc_common *regs)
++{
++ u8 guemr = 0;
++
++ if (!regs)
++ return -EINVAL;
++
++ /* Set bit 3 (which is reserved in the GUEMR register) to 1 */
++ guemr = UCC_GUEMR_SET_RESERVED3;
++
++ regs->guemr = guemr;
++
++ return 0;
++}
++
++static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num,
++ u8 * shift)
++{
++ switch (ucc_num) {
++ case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
++ *reg_num = 1;
++ *shift = 16;
++ break;
++ case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
++ *reg_num = 1;
++ *shift = 0;
++ break;
++ case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
++ *reg_num = 2;
++ *shift = 16;
++ break;
++ case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
++ *reg_num = 2;
++ *shift = 0;
++ break;
++ case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
++ *reg_num = 3;
++ *shift = 16;
++ break;
++ case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
++ *reg_num = 3;
++ *shift = 0;
++ break;
++ case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
++ *reg_num = 4;
++ *shift = 16;
++ break;
++ case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
++ *reg_num = 4;
++ *shift = 0;
++ break;
++ default:
++ break;
++ }
++}
++
++int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask)
++{
++ volatile u32 *p_cmxucr;
++ u8 reg_num;
++ u8 shift;
++
++ /* check if the UCC number is in range. */
++ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
++ return -EINVAL;
++
++ get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift);
++
++ if (set)
++ out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift));
++ else
++ out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift));
++
++ return 0;
++}
++
++int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode)
++{
++ volatile u32 *p_cmxucr;
++ u8 reg_num;
++ u8 shift;
++ u32 clock_bits;
++ u32 clock_mask;
++ int source = -1;
++
++ /* check if the UCC number is in range. */
++ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
++ return -EINVAL;
++
++ if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) {
++ printk(KERN_ERR
++ "ucc_set_qe_mux_rxtx: bad comm mode type passed.");
++ return -EINVAL;
++ }
++
++ get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift);
++
++ switch (reg_num) {
++ case 1:
++ switch (clock) {
++ case QE_BRG1: source = 1; break;
++ case QE_BRG2: source = 2; break;
++ case QE_BRG7: source = 3; break;
++ case QE_BRG8: source = 4; break;
++ case QE_CLK9: source = 5; break;
++ case QE_CLK10: source = 6; break;
++ case QE_CLK11: source = 7; break;
++ case QE_CLK12: source = 8; break;
++ case QE_CLK15: source = 9; break;
++ case QE_CLK16: source = 10; break;
++ default: source = -1; break;
++ }
++ break;
++ case 2:
++ switch (clock) {
++ case QE_BRG5: source = 1; break;
++ case QE_BRG6: source = 2; break;
++ case QE_BRG7: source = 3; break;
++ case QE_BRG8: source = 4; break;
++ case QE_CLK13: source = 5; break;
++ case QE_CLK14: source = 6; break;
++ case QE_CLK19: source = 7; break;
++ case QE_CLK20: source = 8; break;
++ case QE_CLK15: source = 9; break;
++ case QE_CLK16: source = 10; break;
++ default: source = -1; break;
++ }
++ break;
++ case 3:
++ switch (clock) {
++ case QE_BRG9: source = 1; break;
++ case QE_BRG10: source = 2; break;
++ case QE_BRG15: source = 3; break;
++ case QE_BRG16: source = 4; break;
++ case QE_CLK3: source = 5; break;
++ case QE_CLK4: source = 6; break;
++ case QE_CLK17: source = 7; break;
++ case QE_CLK18: source = 8; break;
++ case QE_CLK7: source = 9; break;
++ case QE_CLK8: source = 10; break;
++ case QE_CLK16: source = 11; break;
++ default: source = -1; break;
++ }
++ break;
++ case 4:
++ switch (clock) {
++ case QE_BRG13: source = 1; break;
++ case QE_BRG14: source = 2; break;
++ case QE_BRG15: source = 3; break;
++ case QE_BRG16: source = 4; break;
++ case QE_CLK5: source = 5; break;
++ case QE_CLK6: source = 6; break;
++ case QE_CLK21: source = 7; break;
++ case QE_CLK22: source = 8; break;
++ case QE_CLK7: source = 9; break;
++ case QE_CLK8: source = 10; break;
++ case QE_CLK16: source = 11; break;
++ default: source = -1; break;
++ }
++ break;
++ default:
++ source = -1;
++ break;
++ }
++
++ if (source == -1) {
++ printk(KERN_ERR
++ "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC.");
++ return -ENOENT;
++ }
++
++ clock_bits = (u32) source;
++ clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK;
++ if (mode == COMM_DIR_RX) {
++ clock_bits <<= 4; /* Rx field is 4 bits to left of Tx field */
++ clock_mask <<= 4; /* Rx field is 4 bits to left of Tx field */
++ }
++ clock_bits <<= shift;
++ clock_mask <<= shift;
++
++ out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits);
++
++ return 0;
++}
+diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+new file mode 100644
+index 0000000..75fa310
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+@@ -0,0 +1,396 @@
++/*
++ * arch/powerpc/sysdev/qe_lib/ucc_fast.c
++ *
++ * QE UCC Fast API Set - UCC Fast specific routines implementations.
++ *
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.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/errno.h>
++#include <linux/slab.h>
++#include <linux/stddef.h>
++#include <linux/interrupt.h>
++
++#include <asm/io.h>
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++
++#include <asm/ucc.h>
++#include <asm/ucc_fast.h>
++
++#define uccf_printk(level, format, arg...) \
++ printk(level format "\n", ## arg)
++
++#define uccf_dbg(format, arg...) \
++ uccf_printk(KERN_DEBUG , format , ## arg)
++#define uccf_err(format, arg...) \
++ uccf_printk(KERN_ERR , format , ## arg)
++#define uccf_info(format, arg...) \
++ uccf_printk(KERN_INFO , format , ## arg)
++#define uccf_warn(format, arg...) \
++ uccf_printk(KERN_WARNING , format , ## arg)
++
++#ifdef UCCF_VERBOSE_DEBUG
++#define uccf_vdbg uccf_dbg
++#else
++#define uccf_vdbg(fmt, args...) do { } while (0)
++#endif /* UCCF_VERBOSE_DEBUG */
++
++void ucc_fast_dump_regs(struct ucc_fast_private * uccf)
++{
++ uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num);
++ uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs);
++
++ uccf_info("gumr : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr));
++ uccf_info("upsmr : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr));
++ uccf_info("utodr : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr));
++ uccf_info("udsr : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr));
++ uccf_info("ucce : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce));
++ uccf_info("uccm : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm));
++ uccf_info("uccs : addr - 0x%08x, val - 0x%02x",
++ (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs);
++ uccf_info("urfb : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb));
++ uccf_info("urfs : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs));
++ uccf_info("urfet : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet));
++ uccf_info("urfset: addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->urfset,
++ in_be16(&uccf->uf_regs->urfset));
++ uccf_info("utfb : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb));
++ uccf_info("utfs : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs));
++ uccf_info("utfet : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet));
++ uccf_info("utftt : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt));
++ uccf_info("utpt : addr - 0x%08x, val - 0x%04x",
++ (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt));
++ uccf_info("urtry : addr - 0x%08x, val - 0x%08x",
++ (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry));
++ uccf_info("guemr : addr - 0x%08x, val - 0x%02x",
++ (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr);
++}
++
++u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
++{
++ switch (uccf_num) {
++ case 0: return QE_CR_SUBBLOCK_UCCFAST1;
++ case 1: return QE_CR_SUBBLOCK_UCCFAST2;
++ case 2: return QE_CR_SUBBLOCK_UCCFAST3;
++ case 3: return QE_CR_SUBBLOCK_UCCFAST4;
++ case 4: return QE_CR_SUBBLOCK_UCCFAST5;
++ case 5: return QE_CR_SUBBLOCK_UCCFAST6;
++ case 6: return QE_CR_SUBBLOCK_UCCFAST7;
++ case 7: return QE_CR_SUBBLOCK_UCCFAST8;
++ default: return QE_CR_SUBBLOCK_INVALID;
++ }
++}
++
++void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
++{
++ out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
++}
++
++void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
++{
++ struct ucc_fast *uf_regs;
++ u32 gumr;
++
++ uf_regs = uccf->uf_regs;
++
++ /* Enable reception and/or transmission on this UCC. */
++ gumr = in_be32(&uf_regs->gumr);
++ if (mode & COMM_DIR_TX) {
++ gumr |= UCC_FAST_GUMR_ENT;
++ uccf->enabled_tx = 1;
++ }
++ if (mode & COMM_DIR_RX) {
++ gumr |= UCC_FAST_GUMR_ENR;
++ uccf->enabled_rx = 1;
++ }
++ out_be32(&uf_regs->gumr, gumr);
++}
++
++void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
++{
++ struct ucc_fast *uf_regs;
++ u32 gumr;
++
++ uf_regs = uccf->uf_regs;
++
++ /* Disable reception and/or transmission on this UCC. */
++ gumr = in_be32(&uf_regs->gumr);
++ if (mode & COMM_DIR_TX) {
++ gumr &= ~UCC_FAST_GUMR_ENT;
++ uccf->enabled_tx = 0;
++ }
++ if (mode & COMM_DIR_RX) {
++ gumr &= ~UCC_FAST_GUMR_ENR;
++ uccf->enabled_rx = 0;
++ }
++ out_be32(&uf_regs->gumr, gumr);
++}
++
++int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret)
++{
++ struct ucc_fast_private *uccf;
++ struct ucc_fast *uf_regs;
++ u32 gumr = 0;
++ int ret;
++
++ uccf_vdbg("%s: IN", __FUNCTION__);
++
++ if (!uf_info)
++ return -EINVAL;
++
++ /* check if the UCC port number is in range. */
++ if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
++ uccf_err("ucc_fast_init: Illegal UCC number!");
++ return -EINVAL;
++ }
++
++ /* Check that 'max_rx_buf_length' is properly aligned (4). */
++ if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) {
++ uccf_err("ucc_fast_init: max_rx_buf_length not aligned.");
++ return -EINVAL;
++ }
++
++ /* Validate Virtual Fifo register values */
++ if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register urfs too small.");
++ return -EINVAL;
++ }
++
++ if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register urfs not aligned.");
++ return -EINVAL;
++ }
++
++ if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register urfet not aligned.");
++ return -EINVAL;
++ }
++
++ if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register urfset not aligned.");
++ return -EINVAL;
++ }
++
++ if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register utfs not aligned.");
++ return -EINVAL;
++ }
++
++ if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register utfet not aligned.");
++ return -EINVAL;
++ }
++
++ if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
++ uccf_err
++ ("ucc_fast_init: Virtual Fifo register utftt not aligned.");
++ return -EINVAL;
++ }
++
++ uccf = (struct ucc_fast_private *)
++ kmalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
++ if (!uccf) {
++ uccf_err
++ ("ucc_fast_init: No memory for UCC slow data structure!");
++ return -ENOMEM;
++ }
++ memset(uccf, 0, sizeof(struct ucc_fast_private));
++
++ /* Fill fast UCC structure */
++ uccf->uf_info = uf_info;
++ /* Set the PHY base address */
++ uccf->uf_regs =
++ (struct ucc_fast *) ioremap(uf_info->regs, sizeof(struct ucc_fast));
++ if (uccf->uf_regs == NULL) {
++ uccf_err
++ ("ucc_fast_init: No memory map for UCC slow controller!");
++ return -ENOMEM;
++ }
++
++ uccf->enabled_tx = 0;
++ uccf->enabled_rx = 0;
++ uccf->stopped_tx = 0;
++ uccf->stopped_rx = 0;
++ uf_regs = uccf->uf_regs;
++ uccf->p_ucce = (u32 *) & (uf_regs->ucce);
++ uccf->p_uccm = (u32 *) & (uf_regs->uccm);
++#ifdef STATISTICS
++ uccf->tx_frames = 0;
++ uccf->rx_frames = 0;
++ uccf->rx_discarded = 0;
++#endif /* STATISTICS */
++
++ /* Init Guemr register */
++ if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) {
++ uccf_err("ucc_fast_init: Could not init the guemr register.");
++ ucc_fast_free(uccf);
++ return ret;
++ }
++
++ /* Set UCC to fast type */
++ if ((ret = ucc_set_type(uf_info->ucc_num,
++ (struct ucc_common *) (uf_regs),
++ UCC_SPEED_TYPE_FAST))) {
++ uccf_err("ucc_fast_init: Could not set type to fast.");
++ ucc_fast_free(uccf);
++ return ret;
++ }
++
++ uccf->mrblr = uf_info->max_rx_buf_length;
++
++ /* Set GUMR */
++ /* For more details see the hardware spec. */
++ /* gumr starts as zero. */
++ if (uf_info->tci)
++ gumr |= UCC_FAST_GUMR_TCI;
++ gumr |= uf_info->ttx_trx;
++ if (uf_info->cdp)
++ gumr |= UCC_FAST_GUMR_CDP;
++ if (uf_info->ctsp)
++ gumr |= UCC_FAST_GUMR_CTSP;
++ if (uf_info->cds)
++ gumr |= UCC_FAST_GUMR_CDS;
++ if (uf_info->ctss)
++ gumr |= UCC_FAST_GUMR_CTSS;
++ if (uf_info->txsy)
++ gumr |= UCC_FAST_GUMR_TXSY;
++ if (uf_info->rsyn)
++ gumr |= UCC_FAST_GUMR_RSYN;
++ gumr |= uf_info->synl;
++ if (uf_info->rtsm)
++ gumr |= UCC_FAST_GUMR_RTSM;
++ gumr |= uf_info->renc;
++ if (uf_info->revd)
++ gumr |= UCC_FAST_GUMR_REVD;
++ gumr |= uf_info->tenc;
++ gumr |= uf_info->tcrc;
++ gumr |= uf_info->mode;
++ out_be32(&uf_regs->gumr, gumr);
++
++ /* Allocate memory for Tx Virtual Fifo */
++ uccf->ucc_fast_tx_virtual_fifo_base_offset =
++ qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
++ if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
++ uccf_err
++ ("ucc_fast_init: Can not allocate MURAM memory for "
++ "struct ucc_fastx_virtual_fifo_base_offset.");
++ uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
++ ucc_fast_free(uccf);
++ return -ENOMEM;
++ }
++
++ /* Allocate memory for Rx Virtual Fifo */
++ uccf->ucc_fast_rx_virtual_fifo_base_offset =
++ qe_muram_alloc(uf_info->urfs +
++ (u32)
++ UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
++ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
++ if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
++ uccf_err
++ ("ucc_fast_init: Can not allocate MURAM memory for "
++ "ucc_fast_rx_virtual_fifo_base_offset.");
++ uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
++ ucc_fast_free(uccf);
++ return -ENOMEM;
++ }
++
++ /* Set Virtual Fifo registers */
++ out_be16(&uf_regs->urfs, uf_info->urfs);
++ out_be16(&uf_regs->urfet, uf_info->urfet);
++ out_be16(&uf_regs->urfset, uf_info->urfset);
++ out_be16(&uf_regs->utfs, uf_info->utfs);
++ out_be16(&uf_regs->utfet, uf_info->utfet);
++ out_be16(&uf_regs->utftt, uf_info->utftt);
++ /* utfb, urfb are offsets from MURAM base */
++ out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset);
++ out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset);
++
++ /* Mux clocking */
++ /* Grant Support */
++ ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support);
++ /* Breakpoint Support */
++ ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support);
++ /* Set Tsa or NMSI mode. */
++ ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa);
++ /* If NMSI (not Tsa), set Tx and Rx clock. */
++ if (!uf_info->tsa) {
++ /* Rx clock routing */
++ if (uf_info->rx_clock != QE_CLK_NONE) {
++ if (ucc_set_qe_mux_rxtx
++ (uf_info->ucc_num, uf_info->rx_clock,
++ COMM_DIR_RX)) {
++ uccf_err
++ ("ucc_fast_init: Illegal value for parameter 'RxClock'.");
++ ucc_fast_free(uccf);
++ return -EINVAL;
++ }
++ }
++ /* Tx clock routing */
++ if (uf_info->tx_clock != QE_CLK_NONE) {
++ if (ucc_set_qe_mux_rxtx
++ (uf_info->ucc_num, uf_info->tx_clock,
++ COMM_DIR_TX)) {
++ uccf_err
++ ("ucc_fast_init: Illegal value for parameter 'TxClock'.");
++ ucc_fast_free(uccf);
++ return -EINVAL;
++ }
++ }
++ }
++
++ /* Set interrupt mask register at UCC level. */
++ out_be32(&uf_regs->uccm, uf_info->uccm_mask);
++
++ /* First, clear anything pending at UCC level,
++ * otherwise, old garbage may come through
++ * as soon as the dam is opened
++ * Writing '1' clears
++ */
++ out_be32(&uf_regs->ucce, 0xffffffff);
++
++ *uccf_ret = uccf;
++ return 0;
++}
++
++void ucc_fast_free(struct ucc_fast_private * uccf)
++{
++ if (!uccf)
++ return;
++
++ if (uccf->ucc_fast_tx_virtual_fifo_base_offset)
++ qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset);
++
++ if (uccf->ucc_fast_rx_virtual_fifo_base_offset)
++ qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset);
++
++ kfree(uccf);
++}
+diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+new file mode 100644
+index 0000000..a49da6b
+--- /dev/null
++++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+@@ -0,0 +1,404 @@
++/*
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
++ *
++ * Description:
++ * QE UCC Slow API Set - UCC Slow specific routines implementations.
++ *
++ * 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/errno.h>
++#include <linux/slab.h>
++#include <linux/stddef.h>
++#include <linux/interrupt.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++
++#include <asm/ucc.h>
++#include <asm/ucc_slow.h>
++
++#define uccs_printk(level, format, arg...) \
++ printk(level format "\n", ## arg)
++
++#define uccs_dbg(format, arg...) \
++ uccs_printk(KERN_DEBUG , format , ## arg)
++#define uccs_err(format, arg...) \
++ uccs_printk(KERN_ERR , format , ## arg)
++#define uccs_info(format, arg...) \
++ uccs_printk(KERN_INFO , format , ## arg)
++#define uccs_warn(format, arg...) \
++ uccs_printk(KERN_WARNING , format , ## arg)
++
++#ifdef UCCS_VERBOSE_DEBUG
++#define uccs_vdbg uccs_dbg
++#else
++#define uccs_vdbg(fmt, args...) do { } while (0)
++#endif /* UCCS_VERBOSE_DEBUG */
++
++u32 ucc_slow_get_qe_cr_subblock(int uccs_num)
++{
++ switch (uccs_num) {
++ case 0: return QE_CR_SUBBLOCK_UCCSLOW1;
++ case 1: return QE_CR_SUBBLOCK_UCCSLOW2;
++ case 2: return QE_CR_SUBBLOCK_UCCSLOW3;
++ case 3: return QE_CR_SUBBLOCK_UCCSLOW4;
++ case 4: return QE_CR_SUBBLOCK_UCCSLOW5;
++ case 5: return QE_CR_SUBBLOCK_UCCSLOW6;
++ case 6: return QE_CR_SUBBLOCK_UCCSLOW7;
++ case 7: return QE_CR_SUBBLOCK_UCCSLOW8;
++ default: return QE_CR_SUBBLOCK_INVALID;
++ }
++}
++
++void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs)
++{
++ out_be16(&uccs->us_regs->utodr, UCC_SLOW_TOD);
++}
++
++void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs)
++{
++ struct ucc_slow_info *us_info = uccs->us_info;
++ u32 id;
++
++ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
++ qe_issue_cmd(QE_GRACEFUL_STOP_TX, id,
++ QE_CR_PROTOCOL_UNSPECIFIED, 0);
++}
++
++void ucc_slow_stop_tx(struct ucc_slow_private * uccs)
++{
++ struct ucc_slow_info *us_info = uccs->us_info;
++ u32 id;
++
++ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
++ qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
++}
++
++void ucc_slow_restart_tx(struct ucc_slow_private * uccs)
++{
++ struct ucc_slow_info *us_info = uccs->us_info;
++ u32 id;
++
++ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
++ qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
++}
++
++void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode)
++{
++ struct ucc_slow *us_regs;
++ u32 gumr_l;
++
++ us_regs = uccs->us_regs;
++
++ /* Enable reception and/or transmission on this UCC. */
++ gumr_l = in_be32(&us_regs->gumr_l);
++ if (mode & COMM_DIR_TX) {
++ gumr_l |= UCC_SLOW_GUMR_L_ENT;
++ uccs->enabled_tx = 1;
++ }
++ if (mode & COMM_DIR_RX) {
++ gumr_l |= UCC_SLOW_GUMR_L_ENR;
++ uccs->enabled_rx = 1;
++ }
++ out_be32(&us_regs->gumr_l, gumr_l);
++}
++
++void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode)
++{
++ struct ucc_slow *us_regs;
++ u32 gumr_l;
++
++ us_regs = uccs->us_regs;
++
++ /* Disable reception and/or transmission on this UCC. */
++ gumr_l = in_be32(&us_regs->gumr_l);
++ if (mode & COMM_DIR_TX) {
++ gumr_l &= ~UCC_SLOW_GUMR_L_ENT;
++ uccs->enabled_tx = 0;
++ }
++ if (mode & COMM_DIR_RX) {
++ gumr_l &= ~UCC_SLOW_GUMR_L_ENR;
++ uccs->enabled_rx = 0;
++ }
++ out_be32(&us_regs->gumr_l, gumr_l);
++}
++
++int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret)
++{
++ u32 i;
++ struct ucc_slow *us_regs;
++ u32 gumr;
++ u8 function_code = 0;
++ u8 *bd;
++ struct ucc_slow_private *uccs;
++ u32 id;
++ u32 command;
++ int ret;
++
++ uccs_vdbg("%s: IN", __FUNCTION__);
++
++ if (!us_info)
++ return -EINVAL;
++
++ /* check if the UCC port number is in range. */
++ if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) {
++ uccs_err("ucc_slow_init: Illegal UCC number!");
++ return -EINVAL;
++ }
++
++ /*
++ * Set mrblr
++ * Check that 'max_rx_buf_length' is properly aligned (4), unless
++ * rfw is 1, meaning that QE accepts one byte at a time, unlike normal
++ * case when QE accepts 32 bits at a time.
++ */
++ if ((!us_info->rfw) &&
++ (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) {
++ uccs_err("max_rx_buf_length not aligned.");
++ return -EINVAL;
++ }
++
++ uccs = (struct ucc_slow_private *)
++ kmalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
++ if (!uccs) {
++ uccs_err
++ ("ucc_slow_init: No memory for UCC slow data structure!");
++ return -ENOMEM;
++ }
++ memset(uccs, 0, sizeof(struct ucc_slow_private));
++
++ /* Fill slow UCC structure */
++ uccs->us_info = us_info;
++ uccs->saved_uccm = 0;
++ uccs->p_rx_frame = 0;
++ uccs->us_regs = us_info->us_regs;
++ us_regs = uccs->us_regs;
++ uccs->p_ucce = (u16 *) & (us_regs->ucce);
++ uccs->p_uccm = (u16 *) & (us_regs->uccm);
++#ifdef STATISTICS
++ uccs->rx_frames = 0;
++ uccs->tx_frames = 0;
++ uccs->rx_discarded = 0;
++#endif /* STATISTICS */
++
++ /* Get PRAM base */
++ uccs->us_pram_offset = qe_muram_alloc(UCC_SLOW_PRAM_SIZE,
++ ALIGNMENT_OF_UCC_SLOW_PRAM);
++ if (IS_MURAM_ERR(uccs->us_pram_offset)) {
++ uccs_err
++ ("ucc_slow_init: Can not allocate MURAM memory "
++ "for Slow UCC.");
++ ucc_slow_free(uccs);
++ return -ENOMEM;
++ }
++ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
++ qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED,
++ (u32) uccs->us_pram_offset);
++
++ uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
++
++ /* Init Guemr register */
++ if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->us_regs)))) {
++ uccs_err("ucc_slow_init: Could not init the guemr register.");
++ ucc_slow_free(uccs);
++ return ret;
++ }
++
++ /* Set UCC to slow type */
++ if ((ret = ucc_set_type(us_info->ucc_num,
++ (struct ucc_common *) (us_info->us_regs),
++ UCC_SPEED_TYPE_SLOW))) {
++ uccs_err("ucc_slow_init: Could not init the guemr register.");
++ ucc_slow_free(uccs);
++ return ret;
++ }
++
++ out_be16(&uccs->us_pram->mrblr, us_info->max_rx_buf_length);
++
++ INIT_LIST_HEAD(&uccs->confQ);
++
++ /* Allocate BDs. */
++ uccs->rx_base_offset =
++ qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd),
++ QE_ALIGNMENT_OF_BD);
++ if (IS_MURAM_ERR(uccs->rx_base_offset)) {
++ uccs_err("ucc_slow_init: No memory for Rx BD's.");
++ uccs->rx_base_offset = 0;
++ ucc_slow_free(uccs);
++ return -ENOMEM;
++ }
++
++ uccs->tx_base_offset =
++ qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd),
++ QE_ALIGNMENT_OF_BD);
++ if (IS_MURAM_ERR(uccs->tx_base_offset)) {
++ uccs_err("ucc_slow_init: No memory for Tx BD's.");
++ uccs->tx_base_offset = 0;
++ ucc_slow_free(uccs);
++ return -ENOMEM;
++ }
++
++ /* Init Tx bds */
++ bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset);
++ for (i = 0; i < us_info->tx_bd_ring_len; i++) {
++ /* clear bd buffer */
++ out_be32(&(((struct qe_bd *)bd)->buf), 0);
++ /* set bd status and length */
++ out_be32((u32*)bd, 0);
++ bd += sizeof(struct qe_bd);
++ }
++ bd -= sizeof(struct qe_bd);
++ /* set bd status and length */
++ out_be32((u32*)bd, T_W); /* for last BD set Wrap bit */
++
++ /* Init Rx bds */
++ bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset);
++ for (i = 0; i < us_info->rx_bd_ring_len; i++) {
++ /* set bd status and length */
++ out_be32((u32*)bd, 0);
++ /* clear bd buffer */
++ out_be32(&(((struct qe_bd *)bd)->buf), 0);
++ bd += sizeof(struct qe_bd);
++ }
++ bd -= sizeof(struct qe_bd);
++ /* set bd status and length */
++ out_be32((u32*)bd, R_W); /* for last BD set Wrap bit */
++
++ /* Set GUMR (For more details see the hardware spec.). */
++ /* gumr_h */
++ gumr = 0;
++ gumr |= us_info->tcrc;
++ if (us_info->cdp)
++ gumr |= UCC_SLOW_GUMR_H_CDP;
++ if (us_info->ctsp)
++ gumr |= UCC_SLOW_GUMR_H_CTSP;
++ if (us_info->cds)
++ gumr |= UCC_SLOW_GUMR_H_CDS;
++ if (us_info->ctss)
++ gumr |= UCC_SLOW_GUMR_H_CTSS;
++ if (us_info->tfl)
++ gumr |= UCC_SLOW_GUMR_H_TFL;
++ if (us_info->rfw)
++ gumr |= UCC_SLOW_GUMR_H_RFW;
++ if (us_info->txsy)
++ gumr |= UCC_SLOW_GUMR_H_TXSY;
++ if (us_info->rtsm)
++ gumr |= UCC_SLOW_GUMR_H_RTSM;
++ out_be32(&us_regs->gumr_h, gumr);
++
++ /* gumr_l */
++ gumr = 0;
++ if (us_info->tci)
++ gumr |= UCC_SLOW_GUMR_L_TCI;
++ if (us_info->rinv)
++ gumr |= UCC_SLOW_GUMR_L_RINV;
++ if (us_info->tinv)
++ gumr |= UCC_SLOW_GUMR_L_TINV;
++ if (us_info->tend)
++ gumr |= UCC_SLOW_GUMR_L_TEND;
++ gumr |= us_info->tdcr;
++ gumr |= us_info->rdcr;
++ gumr |= us_info->tenc;
++ gumr |= us_info->renc;
++ gumr |= us_info->diag;
++ gumr |= us_info->mode;
++ out_be32(&us_regs->gumr_l, gumr);
++
++ /* Function code registers */
++ /* function_code has initial value 0 */
++
++ /* if the data is in cachable memory, the 'global' */
++ /* in the function code should be set. */
++ function_code |= us_info->data_mem_part;
++ function_code |= QE_BMR_BYTE_ORDER_BO_MOT; /* Required for QE */
++ uccs->us_pram->tfcr = function_code;
++ uccs->us_pram->rfcr = function_code;
++
++ /* rbase, tbase are offsets from MURAM base */
++ out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset);
++ out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset);
++
++ /* Mux clocking */
++ /* Grant Support */
++ ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support);
++ /* Breakpoint Support */
++ ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support);
++ /* Set Tsa or NMSI mode. */
++ ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa);
++ /* If NMSI (not Tsa), set Tx and Rx clock. */
++ if (!us_info->tsa) {
++ /* Rx clock routing */
++ if (ucc_set_qe_mux_rxtx
++ (us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) {
++ uccs_err
++ ("ucc_slow_init: Illegal value for parameter"
++ " 'RxClock'.");
++ ucc_slow_free(uccs);
++ return -EINVAL;
++ }
++ /* Tx clock routing */
++ if (ucc_set_qe_mux_rxtx(us_info->ucc_num,
++ us_info->tx_clock, COMM_DIR_TX)) {
++ uccs_err
++ ("ucc_slow_init: Illegal value for parameter "
++ "'TxClock'.");
++ ucc_slow_free(uccs);
++ return -EINVAL;
++ }
++ }
++
++ /*
++ * INTERRUPTS
++ */
++ /* Set interrupt mask register at UCC level. */
++ out_be16(&us_regs->uccm, us_info->uccm_mask);
++
++ /* First, clear anything pending at UCC level, */
++ /* otherwise, old garbage may come through */
++ /* as soon as the dam is opened. */
++
++ /* Writing '1' clears */
++ out_be16(&us_regs->ucce, 0xffff);
++
++ /* Issue QE Init command */
++ if (us_info->init_tx && us_info->init_rx)
++ command = QE_INIT_TX_RX;
++ else if (us_info->init_tx)
++ command = QE_INIT_TX;
++ else
++ command = QE_INIT_RX; /* We know at least one is TRUE */
++ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
++ qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
++
++ *uccs_ret = uccs;
++ return 0;
++}
++
++void ucc_slow_free(struct ucc_slow_private * uccs)
++{
++ if (!uccs)
++ return;
++
++ if (uccs->rx_base_offset)
++ qe_muram_free(uccs->rx_base_offset);
++
++ if (uccs->tx_base_offset)
++ qe_muram_free(uccs->tx_base_offset);
++
++ if (uccs->us_pram) {
++ qe_muram_free(uccs->us_pram_offset);
++ uccs->us_pram = NULL;
++ }
++
++ kfree(uccs);
++}
+diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
+index f303846..97f37ef 100644
+--- a/arch/powerpc/sysdev/tsi108_dev.c
++++ b/arch/powerpc/sysdev/tsi108_dev.c
+@@ -9,7 +9,6 @@
+ * option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/stddef.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -49,7 +48,7 @@ phys_addr_t get_csrbase(void)
+ tsi = of_find_node_by_type(NULL, "tsi-bridge");
+ if (tsi) {
+ unsigned int size;
+- void *prop = get_property(tsi, "reg", &size);
++ const void *prop = get_property(tsi, "reg", &size);
+ tsi108_csr_base = of_translate_address(tsi, prop);
+ of_node_put(tsi);
+ };
+@@ -80,7 +79,7 @@ static int __init tsi108_eth_of_init(voi
+ hw_info tsi_eth_data;
+ unsigned int *id;
+ unsigned int *phy_id;
+- void *mac_addr;
++ const void *mac_addr;
+ phandle *ph;
+
+ memset(r, 0, sizeof(r));
+diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
+index 2ab06ed..322f86e 100644
+--- a/arch/powerpc/sysdev/tsi108_pci.c
++++ b/arch/powerpc/sysdev/tsi108_pci.c
+@@ -194,7 +194,7 @@ int __init tsi108_setup_pci(struct devic
+ int len;
+ struct pci_controller *hose;
+ struct resource rsrc;
+- int *bus_range;
++ const int *bus_range;
+ int primary = 0, has_address = 0;
+
+ /* PCI Config mapping */
+@@ -207,7 +207,7 @@ int __init tsi108_setup_pci(struct devic
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
+- bus_range = (int *)get_property(dev, "bus-range", &len);
++ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", dev->full_name);
+@@ -405,11 +405,10 @@ void __init tsi108_pci_int_init(void)
+ init_pci_source();
+ }
+
+-void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc)
+ {
+ unsigned int cascade_irq = get_pci_source();
+ if (cascade_irq != NO_IRQ)
+- generic_handle_irq(cascade_irq, regs);
++ generic_handle_irq(cascade_irq);
+ desc->chip->eoi(irq);
+ }
+diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
+index 179b10c..f56ffef 100644
+--- a/arch/powerpc/xmon/xmon.c
++++ b/arch/powerpc/xmon/xmon.c
+@@ -2,6 +2,8 @@
+ * Routines providing a simple monitor for use on the PowerMac.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
++ * Copyright (C) 2001 PPC64 Team, IBM Corp
++ * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -19,6 +21,7 @@
+ #include <linux/module.h>
+ #include <linux/sysrq.h>
+ #include <linux/interrupt.h>
++#include <linux/irq.h>
+
+ #include <asm/ptrace.h>
+ #include <asm/string.h>
+@@ -33,6 +36,7 @@
+ #include <asm/rtas.h>
+ #include <asm/sstep.h>
+ #include <asm/bug.h>
++#include <asm/irq_regs.h>
+
+ #ifdef CONFIG_PPC64
+ #include <asm/hvcall.h>
+@@ -137,10 +141,14 @@ static void bootcmds(void);
+ static void proccall(void);
+ void dump_segments(void);
+ static void symbol_lookup(void);
++static void xmon_show_stack(unsigned long sp, unsigned long lr,
++ unsigned long pc);
+ static void xmon_print_symbol(unsigned long address, const char *mid,
+ const char *after);
+ static const char *getvecname(unsigned long vec);
+
++int xmon_no_auto_backtrace;
++
+ extern int print_insn_powerpc(unsigned long, unsigned long, int);
+
+ extern void xmon_enter(void);
+@@ -499,7 +507,7 @@ static int xmon_core(struct pt_regs *reg
+
+ mtmsr(msr); /* restore interrupt enable */
+
+- return cmd != 'X';
++ return cmd != 'X' && cmd != EOF;
+ }
+
+ int xmon(struct pt_regs *excp)
+@@ -514,13 +522,12 @@ int xmon(struct pt_regs *excp)
+ }
+ EXPORT_SYMBOL(xmon);
+
+-irqreturn_t
+-xmon_irq(int irq, void *d, struct pt_regs *regs)
++irqreturn_t xmon_irq(int irq, void *d)
+ {
+ unsigned long flags;
+ local_irq_save(flags);
+ printf("Keyboard interrupt\n");
+- xmon(regs);
++ xmon(get_irq_regs());
+ local_irq_restore(flags);
+ return IRQ_HANDLED;
+ }
+@@ -736,6 +743,12 @@ cmds(struct pt_regs *excp)
+
+ last_cmd = NULL;
+ xmon_regs = excp;
++
++ if (!xmon_no_auto_backtrace) {
++ xmon_no_auto_backtrace = 1;
++ xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
++ }
++
+ for(;;) {
+ #ifdef CONFIG_SMP
+ printf("%x:", smp_processor_id());
+@@ -2565,12 +2578,11 @@ void xmon_init(int enable)
+ }
+
+ #ifdef CONFIG_MAGIC_SYSRQ
+-static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_xmon(int key, struct tty_struct *tty)
+ {
+ /* ensure xmon is enabled */
+ xmon_init(1);
+- debugger(pt_regs);
++ debugger(get_irq_regs());
+ }
+
+ static struct sysrq_key_op sysrq_xmon_op =
+@@ -2587,3 +2599,34 @@ static int __init setup_xmon_sysrq(void)
+ }
+ __initcall(setup_xmon_sysrq);
+ #endif /* CONFIG_MAGIC_SYSRQ */
++
++int __initdata xmon_early, xmon_off;
++
++static int __init early_parse_xmon(char *p)
++{
++ if (!p || strncmp(p, "early", 5) == 0) {
++ /* just "xmon" is equivalent to "xmon=early" */
++ xmon_init(1);
++ xmon_early = 1;
++ } else if (strncmp(p, "on", 2) == 0)
++ xmon_init(1);
++ else if (strncmp(p, "off", 3) == 0)
++ xmon_off = 1;
++ else if (strncmp(p, "nobt", 4) == 0)
++ xmon_no_auto_backtrace = 1;
++ else
++ return 1;
++
++ return 0;
++}
++early_param("xmon", early_parse_xmon);
++
++void __init xmon_setup(void)
++{
++#ifdef CONFIG_XMON_DEFAULT
++ if (!xmon_off)
++ xmon_init(1);
++#endif
++ if (xmon_early)
++ debugger(NULL);
++}
+diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c
+index b81a367..e354839 100644
+--- a/arch/ppc/4xx_io/serial_sicc.c
++++ b/arch/ppc/4xx_io/serial_sicc.c
+@@ -414,7 +414,7 @@ static void siccuart_event(struct SICC_i
+ }
+
+ static void
+-siccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs)
++siccuart_rx_chars(struct SICC_info *info)
+ {
+ struct tty_struct *tty = info->tty;
+ unsigned int status, ch, rsr, flg, ignored = 0;
+@@ -441,7 +441,7 @@ siccuart_rx_chars(struct SICC_info *info
+ #ifdef SUPPORT_SYSRQ
+ if (info->sysrq) {
+ if (ch && time_before(jiffies, info->sysrq)) {
+- handle_sysrq(ch, regs, NULL);
++ handle_sysrq(ch, NULL);
+ info->sysrq = 0;
+ goto ignore_char;
+ }
+@@ -553,15 +553,15 @@ static void siccuart_tx_chars(struct SIC
+ }
+
+
+-static irqreturn_t siccuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t siccuart_int_rx(int irq, void *dev_id)
+ {
+ struct SICC_info *info = dev_id;
+- siccuart_rx_chars(info, regs);
++ siccuart_rx_chars(info)
+ return IRQ_HANDLED;
+ }
+
+
+-static irqreturn_t siccuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t siccuart_int_tx(int irq, void *dev_id)
+ {
+ struct SICC_info *info = dev_id;
+ siccuart_tx_chars(info);
+@@ -1720,7 +1720,7 @@ static int siccuart_open(struct tty_stru
+ return 0;
+ }
+
+-static struct tty_operations sicc_ops = {
++static const struct tty_operations sicc_ops = {
+ .open = siccuart_open,
+ .close = siccuart_close,
+ .write = siccuart_write,
+diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
+index ac6d55f..a6056c2 100644
+--- a/arch/ppc/8260_io/enet.c
++++ b/arch/ppc/8260_io/enet.c
+@@ -122,7 +122,7 @@ struct scc_enet_private {
+ static int scc_enet_open(struct net_device *dev);
+ static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int scc_enet_rx(struct net_device *dev);
+-static irqreturn_t scc_enet_interrupt(int irq, void *dev_id, struct pt_regs *);
++static irqreturn_t scc_enet_interrupt(int irq, void *dev_id);
+ static int scc_enet_close(struct net_device *dev);
+ static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+@@ -273,7 +273,7 @@ scc_enet_timeout(struct net_device *dev)
+ * This is called from the CPM handler, not the MPC core interrupt.
+ */
+ static irqreturn_t
+-scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++scc_enet_interrupt(int irq, void * dev_id)
+ {
+ struct net_device *dev = dev_id;
+ volatile struct scc_enet_private *cep;
+diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
+index e347fe8..2e1943e 100644
+--- a/arch/ppc/8260_io/fcc_enet.c
++++ b/arch/ppc/8260_io/fcc_enet.c
+@@ -140,7 +140,7 @@ typedef struct {
+ static int fcc_enet_open(struct net_device *dev);
+ static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int fcc_enet_rx(struct net_device *dev);
+-static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id, struct pt_regs *);
++static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id);
+ static int fcc_enet_close(struct net_device *dev);
+ static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev);
+ /* static void set_multicast_list(struct net_device *dev); */
+@@ -524,7 +524,7 @@ fcc_enet_timeout(struct net_device *dev)
+
+ /* The interrupt handler. */
+ static irqreturn_t
+-fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++fcc_enet_interrupt(int irq, void * dev_id)
+ {
+ struct net_device *dev = dev_id;
+ volatile struct fcc_enet_private *cep;
+@@ -1563,7 +1563,7 @@ mii_discover_phy(uint mii_reg, struct ne
+ #ifdef PHY_INTERRUPT
+ /* This interrupt occurs when the PHY detects a link change. */
+ static irqreturn_t
+-mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++mii_link_interrupt(int irq, void * dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct fcc_enet_private *fep = dev->priv;
+diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
+index 9b3ace2..3b23bcb 100644
+--- a/arch/ppc/8xx_io/commproc.c
++++ b/arch/ppc/8xx_io/commproc.c
+@@ -47,12 +47,12 @@ cpm8xx_t *cpmp; /* Pointer to comm proc
+ /* CPM interrupt vector functions.
+ */
+ struct cpm_action {
+- void (*handler)(void *, struct pt_regs * regs);
++ void (*handler)(void *);
+ void *dev_id;
+ };
+ static struct cpm_action cpm_vecs[CPMVEC_NR];
+-static irqreturn_t cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
+-static irqreturn_t cpm_error_interrupt(int irq, void *dev, struct pt_regs * regs);
++static irqreturn_t cpm_interrupt(int irq, void * dev);
++static irqreturn_t cpm_error_interrupt(int irq, void *dev);
+ static void alloc_host_memory(void);
+ /* Define a table of names to identify CPM interrupt handlers in
+ * /proc/interrupts.
+@@ -205,7 +205,7 @@ cpm_interrupt_init(void)
+ * Get the CPM interrupt vector.
+ */
+ int
+-cpm_get_irq(struct pt_regs *regs)
++cpm_get_irq(void)
+ {
+ int cpm_vec;
+
+@@ -222,7 +222,7 @@ cpm_get_irq(struct pt_regs *regs)
+ /* CPM interrupt controller cascade interrupt.
+ */
+ static irqreturn_t
+-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
++cpm_interrupt(int irq, void * dev)
+ {
+ /* This interrupt handler never actually gets called. It is
+ * installed only to unmask the CPM cascade interrupt in the SIU
+@@ -237,7 +237,7 @@ cpm_interrupt(int irq, void * dev, struc
+ * tests in the interrupt handler.
+ */
+ static irqreturn_t
+-cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
++cpm_error_interrupt(int irq, void *dev)
+ {
+ return IRQ_HANDLED;
+ }
+@@ -246,11 +246,11 @@ cpm_error_interrupt(int irq, void *dev,
+ * request_irq() to the handler prototype required by cpm_install_handler().
+ */
+ static irqreturn_t
+-cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
++cpm_handler_helper(int irq, void *dev_id)
+ {
+ int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+- (*cpm_vecs[cpm_vec].handler)(dev_id, regs);
++ (*cpm_vecs[cpm_vec].handler)(dev_id);
+
+ return IRQ_HANDLED;
+ }
+@@ -267,8 +267,7 @@ cpm_handler_helper(int irq, void *dev_id
+ * request_irq() or cpm_install_handler().
+ */
+ void
+-cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
+- void *dev_id)
++cpm_install_handler(int cpm_vec, void (*handler)(void *), void *dev_id)
+ {
+ int err;
+
+diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
+index f5f300f..959d31c 100644
+--- a/arch/ppc/8xx_io/cs4218_tdm.c
++++ b/arch/ppc/8xx_io/cs4218_tdm.c
+@@ -331,7 +331,7 @@ static int CS_SetFormat(int format);
+ static int CS_SetVolume(int volume);
+ static void cs4218_tdm_tx_intr(void *devid);
+ static void cs4218_tdm_rx_intr(void *devid);
+-static void cs4218_intr(void *devid, struct pt_regs *regs);
++static void cs4218_intr(void *devid);
+ static int cs_get_volume(uint reg);
+ static int cs_volume_setter(int volume, int mute);
+ static int cs_get_gain(uint reg);
+@@ -2646,7 +2646,7 @@ int __init tdm8xx_sound_init(void)
+ * full duplex operation.
+ */
+ static void
+-cs4218_intr(void *dev_id, struct pt_regs *regs)
++cs4218_intr(void *dev_id)
+ {
+ volatile smc_t *sp;
+ volatile cpm8xx_t *cp;
+diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
+index a695375..b23c45b 100644
+--- a/arch/ppc/8xx_io/enet.c
++++ b/arch/ppc/8xx_io/enet.c
+@@ -149,7 +149,7 @@ struct scc_enet_private {
+ static int scc_enet_open(struct net_device *dev);
+ static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int scc_enet_rx(struct net_device *dev);
+-static void scc_enet_interrupt(void *dev_id, struct pt_regs *regs);
++static void scc_enet_interrupt(void *dev_id);
+ static int scc_enet_close(struct net_device *dev);
+ static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+@@ -305,7 +305,7 @@ scc_enet_timeout(struct net_device *dev)
+ * This is called from the CPM handler, not the MPC core interrupt.
+ */
+ static void
+-scc_enet_interrupt(void *dev_id, struct pt_regs *regs)
++scc_enet_interrupt(void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ volatile struct scc_enet_private *cep;
+diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
+index 8b6295b..2f9fa9e 100644
+--- a/arch/ppc/8xx_io/fec.c
++++ b/arch/ppc/8xx_io/fec.c
+@@ -198,8 +198,7 @@ static int fec_enet_start_xmit(struct sk
+ #ifdef CONFIG_USE_MDIO
+ static void fec_enet_mii(struct net_device *dev);
+ #endif /* CONFIG_USE_MDIO */
+-static irqreturn_t fec_enet_interrupt(int irq, void * dev_id,
+- struct pt_regs * regs);
++static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
+ #ifdef CONFIG_FEC_PACKETHOOK
+ static void fec_enet_tx(struct net_device *dev, __u32 regval);
+ static void fec_enet_rx(struct net_device *dev, __u32 regval);
+@@ -472,7 +471,7 @@ fec_timeout(struct net_device *dev)
+ * This is called from the MPC core interrupt.
+ */
+ static irqreturn_t
+-fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++fec_enet_interrupt(int irq, void * dev_id)
+ {
+ struct net_device *dev = dev_id;
+ volatile fec_t *fecp;
+@@ -1408,7 +1407,7 @@ static
+ #ifdef CONFIG_RPXCLASSIC
+ void mii_link_interrupt(void *dev_id)
+ #else
+-irqreturn_t mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++irqreturn_t mii_link_interrupt(int irq, void * dev_id)
+ #endif
+ {
+ #ifdef CONFIG_USE_MDIO
+diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
+index a04cdf0..077711e 100644
+--- a/arch/ppc/Kconfig
++++ b/arch/ppc/Kconfig
+@@ -953,6 +953,9 @@ config NR_CPUS
+ config HIGHMEM
+ bool "High memory support"
+
++config ARCH_POPULATES_NODE_MAP
++ def_bool y
++
+ source kernel/Kconfig.hz
+ source kernel/Kconfig.preempt
+ source "mm/Kconfig"
+@@ -1204,7 +1207,7 @@ config PCI_DOMAINS
+ default PCI
+
+ config MPC83xx_PCI2
+- bool " Supprt for 2nd PCI host controller"
++ bool "Support for 2nd PCI host controller"
+ depends on PCI && MPC834x
+ default y if MPC834x_SYS
+
+@@ -1223,12 +1226,12 @@ config PCI_8260
+ default y
+
+ config 8260_PCI9
+- bool " Enable workaround for MPC826x erratum PCI 9"
++ bool "Enable workaround for MPC826x erratum PCI 9"
+ depends on PCI_8260 && !ADS8272
+ default y
+
+ choice
+- prompt " IDMA channel for PCI 9 workaround"
++ prompt "IDMA channel for PCI 9 workaround"
+ depends on 8260_PCI9
+
+ config 8260_PCI9_IDMA1
+@@ -1342,7 +1345,7 @@ config CONSISTENT_START_BOOL
+ depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+ help
+ This option allows you to set the base virtual address
+- of the the consistent memory pool. This pool of virtual
++ of the consistent memory pool. This pool of virtual
+ memory is used to make consistent memory allocations.
+
+ config CONSISTENT_START
+@@ -1353,7 +1356,7 @@ config CONSISTENT_SIZE_BOOL
+ bool "Set custom consistent memory pool size"
+ depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+ help
+- This option allows you to set the size of the the
++ This option allows you to set the size of the
+ consistent memory pool. This pool of virtual memory
+ is used to make consistent memory allocations.
+
+diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c
+index 0073527..8c880c0 100644
+--- a/arch/ppc/amiga/time.c
++++ b/arch/ppc/amiga/time.c
+@@ -1,4 +1,3 @@
+-#include <linux/config.h> /* CONFIG_HEARTBEAT */
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+diff --git a/arch/ppc/boot/include/mpsc_defs.h b/arch/ppc/boot/include/mpsc_defs.h
+index 2ce7bbb..9f37e13 100644
+--- a/arch/ppc/boot/include/mpsc_defs.h
++++ b/arch/ppc/boot/include/mpsc_defs.h
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/serial/mpsc/mpsc_defs.h
++ * arch/ppc/boot/include/mpsc_defs.h
+ *
+ * Register definitions for the Marvell Multi-Protocol Serial Controller (MPSC),
+ * Serial DMA Controller (SDMA), and Baud Rate Generator (BRG).
+diff --git a/arch/ppc/boot/simple/relocate.S b/arch/ppc/boot/simple/relocate.S
+index 0c02155..1bbbcd2 100644
+--- a/arch/ppc/boot/simple/relocate.S
++++ b/arch/ppc/boot/simple/relocate.S
+@@ -154,8 +154,8 @@ do_relocate_out:
+
+ start_ldr:
+ /* Clear all of BSS and set up stack for C calls */
+- lis r3,edata at h
+- ori r3,r3,edata at l
++ lis r3,__bss_start at h
++ ori r3,r3,__bss_start at l
+ lis r4,end at h
+ ori r4,r4,end at l
+ subi r3,r3,4
+@@ -163,7 +163,7 @@ start_ldr:
+ li r0,0
+ 50: stwu r0,4(r3)
+ cmpw cr0,r3,r4
+- bne 50b
++ blt 50b
+ 90: mr r9,r1 /* Save old stack pointer (in case it matters) */
+ lis r1,.stack at h
+ ori r1,r1,.stack at l
+diff --git a/arch/ppc/boot/utils/mkbugboot.c b/arch/ppc/boot/utils/mkbugboot.c
+index 29115e0..1640c41 100644
+--- a/arch/ppc/boot/utils/mkbugboot.c
++++ b/arch/ppc/boot/utils/mkbugboot.c
+@@ -19,36 +19,13 @@
+ #include <stdlib.h>
+ #include <errno.h>
+ #include <fcntl.h>
++#include <netinet/in.h>
+ #ifdef __sun__
+ #include <inttypes.h>
+ #else
+ #include <stdint.h>
+ #endif
+
+-#ifdef __i386__
+-#define cpu_to_be32(x) le32_to_cpu(x)
+-#define cpu_to_be16(x) le16_to_cpu(x)
+-#else
+-#define cpu_to_be32(x) (x)
+-#define cpu_to_be16(x) (x)
+-#endif
+-
+-#define cpu_to_le32(x) le32_to_cpu((x))
+-unsigned long le32_to_cpu(unsigned long x)
+-{
+- return (((x & 0x000000ffU) << 24) |
+- ((x & 0x0000ff00U) << 8) |
+- ((x & 0x00ff0000U) >> 8) |
+- ((x & 0xff000000U) >> 24));
+-}
+-
+-#define cpu_to_le16(x) le16_to_cpu((x))
+-unsigned short le16_to_cpu(unsigned short x)
+-{
+- return (((x & 0x00ff) << 8) |
+- ((x & 0xff00) >> 8));
+-}
+-
+ /* size of read buffer */
+ #define SIZE 0x1000
+
+@@ -62,124 +39,109 @@ typedef struct bug_boot_header {
+
+ #define HEADER_SIZE sizeof(bug_boot_header_t)
+
+-uint32_t copy_image(int32_t in_fd, int32_t out_fd)
++void update_checksum(void *buf, size_t size, uint16_t *sum)
+ {
+- uint8_t buf[SIZE];
+- int n;
+- uint32_t image_size = 0;
+- uint8_t zero = 0;
+-
+- lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
+-
+- /* Copy an image while recording its size */
+- while ( (n = read(in_fd, buf, SIZE)) > 0 )
+- {
+- image_size = image_size + n;
+- write(out_fd, buf, n);
+- }
+-
+- /* BUG romboot requires that our size is divisible by 2 */
+- /* align image to 2 byte boundary */
+- if (image_size % 2)
+- {
+- image_size++;
+- write(out_fd, &zero, 1);
+- }
+-
+- return image_size;
++ uint32_t csum = *sum;
++
++ while (size) {
++ csum += *(uint16_t *)buf;
++ if (csum > 0xffff)
++ csum -= 0xffff;
++ buf = (uint16_t *)buf + 1;
++ size -= 2;
++ }
++ *sum = csum;
+ }
+
+-void write_bugboot_header(int32_t out_fd, uint32_t boot_size)
++uint32_t copy_image(int in_fd, int out_fd, uint16_t *sum)
+ {
+- uint8_t header_block[HEADER_SIZE];
+- bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0];
+-
+- memset(header_block, 0, HEADER_SIZE);
+-
+- /* Fill in the PPCBUG ROM boot header */
+- strncpy(bbh->magic_word, "BOOT", 4); /* PPCBUG magic word */
+- bbh->entry_offset = cpu_to_be32(HEADER_SIZE); /* Entry address */
+- bbh->routine_length= cpu_to_be32(HEADER_SIZE+boot_size+2); /* Routine length */
+- strncpy(bbh->routine_name, "LINUXROM", 8); /* Routine name */
+-
+- /* Output the header and bootloader to the file */
+- write(out_fd, header_block, HEADER_SIZE);
++ uint8_t buf[SIZE];
++ int offset = 0;
++ int n;
++ uint32_t image_size = 0;
++
++ lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
++
++ /* Copy an image while recording its size */
++ while ( (n = read(in_fd, buf + offset, SIZE - offset)) > 0 ) {
++ n += offset;
++ offset = n & 1;
++ n -= offset;
++ image_size = image_size + n;
++ /* who's going to deal with short writes? */
++ write(out_fd, buf, n);
++ update_checksum(buf, n, sum);
++ if (offset)
++ buf[0] = buf[n];
++ }
++
++ /* BUG romboot requires that our size is divisible by 2 */
++ /* align image to 2 byte boundary */
++ if (offset) {
++ image_size += 2;
++ buf[1] = '\0';
++ write(out_fd, buf, 2);
++ update_checksum(buf, 2, sum);
++ }
++ return image_size;
+ }
+
+-uint16_t calc_checksum(int32_t bug_fd)
++void write_bugboot_header(int out_fd, uint32_t boot_size, uint16_t *sum)
+ {
+- uint32_t checksum_var = 0;
+- uint8_t buf[2];
+- int n;
+-
+- /* Checksum loop */
+- while ( (n = read(bug_fd, buf, 2) ) )
+- {
+- checksum_var = checksum_var + *(uint16_t *)buf;
+-
+- /* If we carry out, mask it and add one to the checksum */
+- if (checksum_var >> 16)
+- checksum_var = (checksum_var & 0x0000ffff) + 1;
+- }
+-
+- return checksum_var;
++ static bug_boot_header_t bbh = {
++ .magic_word = "BOOT",
++ .routine_name = "LINUXROM"
++ };
++
++ /* Fill in the PPCBUG ROM boot header */
++ bbh.entry_offset = htonl(HEADER_SIZE); /* Entry address */
++ bbh.routine_length= htonl(HEADER_SIZE+boot_size+2); /* Routine length */
++
++ /* Output the header and bootloader to the file */
++ write(out_fd, &bbh, sizeof(bug_boot_header_t));
++ update_checksum(&bbh, sizeof(bug_boot_header_t), sum);
+ }
+
+ int main(int argc, char *argv[])
+ {
+- int32_t image_fd, bugboot_fd;
+- int argptr = 1;
+- uint32_t kernel_size = 0;
+- uint16_t checksum = 0;
+- uint8_t bugbootname[256];
+-
+- if ( (argc != 3) )
+- {
+- fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
+- exit(-1);
+- }
+-
+- /* Get file args */
+-
+- /* kernel image file */
+- if ((image_fd = open( argv[argptr] , 0)) < 0)
+- exit(-1);
+- argptr++;
++ int image_fd, bugboot_fd;
++ uint32_t kernel_size = 0;
++ uint16_t checksum = 0;
+
+- /* bugboot file */
+- if ( !strcmp( argv[argptr], "-" ) )
+- bugboot_fd = 1; /* stdout */
+- else
+- if ((bugboot_fd = creat( argv[argptr] , 0755)) < 0)
+- exit(-1);
+- else
+- strcpy(bugbootname, argv[argptr]);
+- argptr++;
++ if (argc != 3) {
++ fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
++ exit(-1);
++ }
+
+- /* Set file position after ROM header block where zImage will be written */
+- lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
++ /* Get file args */
+
+- /* Copy kernel image into bugboot image */
+- kernel_size = copy_image(image_fd, bugboot_fd);
+- close(image_fd);
++ /* kernel image file */
++ if ((image_fd = open(argv[1] , 0)) < 0)
++ exit(-1);
+
+- /* Set file position to beginning where header/romboot will be written */
+- lseek(bugboot_fd, 0, SEEK_SET);
++ /* bugboot file */
++ if (!strcmp(argv[2], "-"))
++ bugboot_fd = 1; /* stdout */
++ else if ((bugboot_fd = creat(argv[2] , 0755)) < 0)
++ exit(-1);
+
+- /* Write out BUG header/romboot */
+- write_bugboot_header(bugboot_fd, kernel_size);
++ /* Set file position after ROM header block where zImage will be written */
++ lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
+
+- /* Close bugboot file */
+- close(bugboot_fd);
++ /* Copy kernel image into bugboot image */
++ kernel_size = copy_image(image_fd, bugboot_fd, &checksum);
+
+- /* Reopen it as read/write */
+- bugboot_fd = open(bugbootname, O_RDWR);
++ /* Set file position to beginning where header/romboot will be written */
++ lseek(bugboot_fd, 0, SEEK_SET);
+
+- /* Calculate checksum */
+- checksum = calc_checksum(bugboot_fd);
++ /* Write out BUG header/romboot */
++ write_bugboot_header(bugboot_fd, kernel_size, &checksum);
+
+- /* Write out the calculated checksum */
+- write(bugboot_fd, &checksum, 2);
++ /* Write out the calculated checksum */
++ lseek(bugboot_fd, 0, SEEK_END);
++ write(bugboot_fd, &checksum, 2);
+
+- return 0;
++ /* Close bugboot file */
++ close(bugboot_fd);
++ return 0;
+ }
+diff --git a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c
+index f6d5a2f..192bb39 100644
+--- a/arch/ppc/boot/utils/mkprep.c
++++ b/arch/ppc/boot/utils/mkprep.c
+@@ -15,279 +15,227 @@
+ * Modified for Sparc hosted builds by Peter Wahl <PeterWahl at web.de>
+ */
+
+-#include <fcntl.h>
+ #include <stdio.h>
+-#include <stdlib.h>
+ #include <string.h>
+-#include <strings.h>
+-#include <sys/stat.h>
+-#include <unistd.h>
+-
+-#define cpu_to_le32(x) le32_to_cpu((x))
+-unsigned long le32_to_cpu(unsigned long x)
+-{
+- return (((x & 0x000000ffU) << 24) |
+- ((x & 0x0000ff00U) << 8) |
+- ((x & 0x00ff0000U) >> 8) |
+- ((x & 0xff000000U) >> 24));
+-}
+-
+-
+-#define cpu_to_le16(x) le16_to_cpu((x))
+-unsigned short le16_to_cpu(unsigned short x)
+-{
+- return (((x & 0x00ff) << 8) |
+- ((x & 0xff00) >> 8));
+-}
+-
+-#define cpu_to_be32(x) (x)
+-#define be32_to_cpu(x) (x)
+-#define cpu_to_be16(x) (x)
+-#define be16_to_cpu(x) (x)
++#include <stdlib.h>
+
+ /* size of read buffer */
+ #define SIZE 0x1000
+
+-
+-typedef unsigned long dword_t;
+-typedef unsigned short word_t;
+-typedef unsigned char byte_t;
+-typedef byte_t block_t[512];
+-typedef byte_t page_t[4096];
+-
+-
+ /*
+ * Partition table entry
+ * - from the PReP spec
+ */
+ typedef struct partition_entry {
+- byte_t boot_indicator;
+- byte_t starting_head;
+- byte_t starting_sector;
+- byte_t starting_cylinder;
+-
+- byte_t system_indicator;
+- byte_t ending_head;
+- byte_t ending_sector;
+- byte_t ending_cylinder;
+-
+- dword_t beginning_sector;
+- dword_t number_of_sectors;
++ unsigned char boot_indicator;
++ unsigned char starting_head;
++ unsigned char starting_sector;
++ unsigned char starting_cylinder;
++
++ unsigned char system_indicator;
++ unsigned char ending_head;
++ unsigned char ending_sector;
++ unsigned char ending_cylinder;
++
++ unsigned char beginning_sector[4];
++ unsigned char number_of_sectors[4];
+ } partition_entry_t;
+
+ #define BootActive 0x80
+ #define SystemPrep 0x41
+
+-void copy_image(int , int);
+-void write_prep_partition(int , int );
+-void write_asm_data( int in, int out );
++void copy_image(FILE *, FILE *);
++void write_prep_partition(FILE *, FILE *);
++void write_asm_data(FILE *, FILE *);
+
+ unsigned int elfhdr_size = 65536;
+
+ int main(int argc, char *argv[])
+ {
+- int in_fd, out_fd;
+- int argptr = 1;
+- unsigned int prep = 0;
+- unsigned int asmoutput = 0;
+-
+- if ( (argc < 3) || (argc > 4) )
+- {
+- fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
+- exit(-1);
+- }
+-
+- /* needs to handle args more elegantly -- but this is a small/simple program */
+-
+- /* check for -pbp */
+- if ( !strcmp( argv[argptr], "-pbp" ) )
+- {
+- prep = 1;
+- argptr++;
+- }
+-
+- /* check for -asm */
+- if ( !strcmp( argv[argptr], "-asm" ) )
+- {
+- asmoutput = 1;
+- argptr++;
+- }
+-
+- /* input file */
+- if ( !strcmp( argv[argptr], "-" ) )
+- in_fd = 0; /* stdin */
+- else
+- if ((in_fd = open( argv[argptr] , 0)) < 0)
+- exit(-1);
+- argptr++;
+-
+- /* output file */
+- if ( !strcmp( argv[argptr], "-" ) )
+- out_fd = 1; /* stdout */
+- else
+- if ((out_fd = creat( argv[argptr] , 0755)) < 0)
+- exit(-1);
+- argptr++;
+-
+- /* skip elf header in input file */
+- /*if ( !prep )*/
+- lseek(in_fd, elfhdr_size, SEEK_SET);
+-
+- /* write prep partition if necessary */
+- if ( prep )
+- write_prep_partition( in_fd, out_fd );
+-
+- /* write input image to bootimage */
+- if ( asmoutput )
+- write_asm_data( in_fd, out_fd );
+- else
+- copy_image(in_fd, out_fd);
+-
+- return 0;
++ FILE *in, *out;
++ int argptr = 1;
++ int prep = 0;
++ int asmoutput = 0;
++
++ if (argc < 3 || argc > 4) {
++ fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",
++ argv[0]);
++ exit(-1);
++ }
++
++/* needs to handle args more elegantly -- but this is a small/simple program */
++
++ /* check for -pbp */
++ if (!strcmp(argv[argptr], "-pbp")) {
++ prep = 1;
++ argptr++;
++ }
++
++ /* check for -asm */
++ if (!strcmp(argv[argptr], "-asm")) {
++ asmoutput = 1;
++ argptr++;
++ }
++
++ /* input file */
++ if (!strcmp(argv[argptr], "-"))
++ in = stdin;
++ else if (!(in = fopen(argv[argptr], "r")))
++ exit(-1);
++ argptr++;
++
++ /* output file */
++ if (!strcmp(argv[argptr], "-"))
++ out = stdout;
++ else if (!(out = fopen(argv[argptr], "w")))
++ exit(-1);
++ argptr++;
++
++ /* skip elf header in input file */
++ /*if ( !prep )*/
++ fseek(in, elfhdr_size, SEEK_SET);
++
++ /* write prep partition if necessary */
++ if (prep)
++ write_prep_partition(in, out);
++
++ /* write input image to bootimage */
++ if (asmoutput)
++ write_asm_data(in, out);
++ else
++ copy_image(in, out);
++
++ return 0;
+ }
+
+-void write_prep_partition(int in, int out)
++void store_le32(unsigned int v, unsigned char *p)
+ {
+- unsigned char block[512];
+- partition_entry_t pe;
+- dword_t *entry = (dword_t *)&block[0];
+- dword_t *length = (dword_t *)&block[sizeof(long)];
+- struct stat info;
+-
+- if (fstat(in, &info) < 0)
+- {
+- fprintf(stderr,"info failed\n");
+- exit(-1);
+- }
+-
+- bzero( block, sizeof block );
+-
+- /* set entry point and boot image size skipping over elf header */
+-#ifdef __i386__
+- *entry = 0x400/*+65536*/;
+- *length = info.st_size-elfhdr_size+0x400;
+-#else
+- *entry = cpu_to_le32(0x400/*+65536*/);
+- *length = cpu_to_le32(info.st_size-elfhdr_size+0x400);
+-#endif /* __i386__ */
+-
+- /* sets magic number for msdos partition (used by linux) */
+- block[510] = 0x55;
+- block[511] = 0xAA;
+-
+- /*
+- * Build a "PReP" partition table entry in the boot record
+- * - "PReP" may only look at the system_indicator
+- */
+- pe.boot_indicator = BootActive;
+- pe.system_indicator = SystemPrep;
+- /*
+- * The first block of the diskette is used by this "boot record" which
+- * actually contains the partition table. (The first block of the
+- * partition contains the boot image, but I digress...) We'll set up
+- * one partition on the diskette and it shall contain the rest of the
+- * diskette.
+- */
+- pe.starting_head = 0; /* zero-based */
+- pe.starting_sector = 2; /* one-based */
+- pe.starting_cylinder = 0; /* zero-based */
+- pe.ending_head = 1; /* assumes two heads */
+- pe.ending_sector = 18; /* assumes 18 sectors/track */
+- pe.ending_cylinder = 79; /* assumes 80 cylinders/diskette */
+-
+- /*
+- * The "PReP" software ignores the above fields and just looks at
+- * the next two.
+- * - size of the diskette is (assumed to be)
+- * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+- * - unlike the above sector numbers, the beginning sector is zero-based!
+- */
++ p[0] = v;
++ p[1] = v >>= 8;
++ p[2] = v >>= 8;
++ p[3] = v >> 8;
++}
++
++void write_prep_partition(FILE *in, FILE *out)
++{
++ unsigned char block[512];
++ partition_entry_t pe;
++ unsigned char *entry = block;
++ unsigned char *length = block + 4;
++ long pos = ftell(in), size;
++
++ if (fseek(in, 0, SEEK_END) < 0) {
++ fprintf(stderr,"info failed\n");
++ exit(-1);
++ }
++ size = ftell(in);
++ if (fseek(in, pos, SEEK_SET) < 0) {
++ fprintf(stderr,"info failed\n");
++ exit(-1);
++ }
++
++ memset(block, '\0', sizeof(block));
++
++ /* set entry point and boot image size skipping over elf header */
++ store_le32(0x400/*+65536*/, entry);
++ store_le32(size-elfhdr_size+0x400, length);
++
++ /* sets magic number for msdos partition (used by linux) */
++ block[510] = 0x55;
++ block[511] = 0xAA;
++
++ /*
++ * Build a "PReP" partition table entry in the boot record
++ * - "PReP" may only look at the system_indicator
++ */
++ pe.boot_indicator = BootActive;
++ pe.system_indicator = SystemPrep;
++ /*
++ * The first block of the diskette is used by this "boot record" which
++ * actually contains the partition table. (The first block of the
++ * partition contains the boot image, but I digress...) We'll set up
++ * one partition on the diskette and it shall contain the rest of the
++ * diskette.
++ */
++ pe.starting_head = 0; /* zero-based */
++ pe.starting_sector = 2; /* one-based */
++ pe.starting_cylinder = 0; /* zero-based */
++ pe.ending_head = 1; /* assumes two heads */
++ pe.ending_sector = 18; /* assumes 18 sectors/track */
++ pe.ending_cylinder = 79; /* assumes 80 cylinders/diskette */
++
++ /*
++ * The "PReP" software ignores the above fields and just looks at
++ * the next two.
++ * - size of the diskette is (assumed to be)
++ * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
++ * - unlike the above sector numbers, the beginning sector is zero-based!
++ */
+ #if 0
+- pe.beginning_sector = cpu_to_le32(1);
+-#else
+- /* This has to be 0 on the PowerStack? */
+-#ifdef __i386__
+- pe.beginning_sector = 0;
++ store_le32(1, pe.beginning_sector);
+ #else
+- pe.beginning_sector = cpu_to_le32(0);
+-#endif /* __i386__ */
++ /* This has to be 0 on the PowerStack? */
++ store_le32(0, pe.beginning_sector);
+ #endif
+
+-#ifdef __i386__
+- pe.number_of_sectors = 2*18*80-1;
+-#else
+- pe.number_of_sectors = cpu_to_le32(2*18*80-1);
+-#endif /* __i386__ */
++ store_le32(2*18*80-1, pe.number_of_sectors);
+
+- memcpy(&block[0x1BE], &pe, sizeof(pe));
++ memcpy(&block[0x1BE], &pe, sizeof(pe));
+
+- write( out, block, sizeof(block) );
+- write( out, entry, sizeof(*entry) );
+- write( out, length, sizeof(*length) );
+- /* set file position to 2nd sector where image will be written */
+- lseek( out, 0x400, SEEK_SET );
++ fwrite(block, sizeof(block), 1, out);
++ fwrite(entry, 4, 1, out);
++ fwrite(length, 4, 1, out);
++ /* set file position to 2nd sector where image will be written */
++ fseek( out, 0x400, SEEK_SET );
+ }
+
+
+
+-void
+-copy_image(int in, int out)
++void copy_image(FILE *in, FILE *out)
+ {
+- char buf[SIZE];
+- int n;
++ char buf[SIZE];
++ int n;
+
+- while ( (n = read(in, buf, SIZE)) > 0 )
+- write(out, buf, n);
++ while ( (n = fread(buf, 1, SIZE, in)) > 0 )
++ fwrite(buf, 1, n, out);
+ }
+
+
+ void
+-write_asm_data( int in, int out )
++write_asm_data(FILE *in, FILE *out)
+ {
+- int i, cnt, pos, len;
+- unsigned int cksum, val;
+- unsigned char *lp;
+- unsigned char buf[SIZE];
+- unsigned char str[256];
+-
+- write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
+- strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
+- pos = 0;
+- cksum = 0;
+- while ((len = read(in, 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)
+- {
+- write( out, "\t.long\t", strlen( "\t.long\t" ) );
+- }
+- sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+- write( out, str, strlen(str) );
+- val = *(unsigned long *)lp;
+- cksum ^= val;
+- lp += 4;
+- if (++cnt == 4)
+- {
+- cnt = 0;
+- sprintf( str, " # %x \n", pos+i-12);
+- write( out, str, strlen(str) );
+- } else
+- {
+- write( out, ",", 1 );
+- }
+- }
+- if (cnt)
+- {
+- write( out, "0\n", 2 );
+- }
+- pos += len;
+- }
+- sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+- write( out, str, strlen(str) );
+-
+- fprintf(stderr, "cksum = %x\n", cksum);
++ int i, cnt, pos = 0;
++ unsigned int cksum = 0, val;
++ unsigned char *lp;
++ unsigned char buf[SIZE];
++ size_t len;
++
++ fputs("\t.data\n\t.globl input_data\ninput_data:\n", out);
++ while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
++ cnt = 0;
++ lp = buf;
++ /* Round up to longwords */
++ while (len & 3)
++ buf[len++] = '\0';
++ for (i = 0; i < len; i += 4) {
++ if (cnt == 0)
++ fputs("\t.long\t", out);
++ fprintf(out, "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(out, " # %x \n", pos+i-12);
++ } else {
++ fputs(",", out);
++ }
++ }
++ if (cnt)
++ fputs("0\n", out);
++ pos += len;
++ }
++ fprintf(out, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
++ fprintf(stderr, "cksum = %x\n", cksum);
+ }
+diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
+index 2fa0075..d319f9b 100644
+--- a/arch/ppc/kernel/misc.S
++++ b/arch/ppc/kernel/misc.S
+@@ -110,80 +110,6 @@ _GLOBAL(reloc_got2)
+ blr
+
+ /*
+- * identify_cpu,
+- * called with r3 = data offset and r4 = CPU number
+- * doesn't change r3
+- */
+-_GLOBAL(identify_cpu)
+- addis r8,r3,cpu_specs at ha
+- addi r8,r8,cpu_specs at l
+- mfpvr r7
+-1:
+- lwz r5,CPU_SPEC_PVR_MASK(r8)
+- and r5,r5,r7
+- lwz r6,CPU_SPEC_PVR_VALUE(r8)
+- cmplw 0,r6,r5
+- beq 1f
+- addi r8,r8,CPU_SPEC_ENTRY_SIZE
+- b 1b
+-1:
+- addis r6,r3,cur_cpu_spec at ha
+- addi r6,r6,cur_cpu_spec at l
+- sub r8,r8,r3
+- stw r8,0(r6)
+- blr
+-
+-/*
+- * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
+- * and writes nop's over sections of code that don't apply for this cpu.
+- * r3 = data offset (not changed)
+- */
+-_GLOBAL(do_cpu_ftr_fixups)
+- /* Get CPU 0 features */
+- addis r6,r3,cur_cpu_spec at ha
+- addi r6,r6,cur_cpu_spec at l
+- lwz r4,0(r6)
+- add r4,r4,r3
+- lwz r4,CPU_SPEC_FEATURES(r4)
+-
+- /* Get the fixup table */
+- addis r6,r3,__start___ftr_fixup at ha
+- addi r6,r6,__start___ftr_fixup at l
+- addis r7,r3,__stop___ftr_fixup at ha
+- addi r7,r7,__stop___ftr_fixup at l
+-
+- /* Do the fixup */
+-1: cmplw 0,r6,r7
+- bgelr
+- addi r6,r6,16
+- lwz r8,-16(r6) /* mask */
+- and r8,r8,r4
+- lwz r9,-12(r6) /* value */
+- cmplw 0,r8,r9
+- beq 1b
+- lwz r8,-8(r6) /* section begin */
+- lwz r9,-4(r6) /* section end */
+- subf. r9,r8,r9
+- beq 1b
+- /* write nops over the section of code */
+- /* todo: if large section, add a branch at the start of it */
+- srwi r9,r9,2
+- mtctr r9
+- add r8,r8,r3
+- lis r0,0x60000000 at h /* nop */
+-3: stw r0,0(r8)
+- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE at l
+- beq 2f
+- dcbst 0,r8 /* suboptimal, but simpler */
+- sync
+- icbi 0,r8
+-2: addi r8,r8,4
+- bdnz 3b
+- sync /* additional sync needed on g4 */
+- isync
+- b 1b
+-
+-/*
+ * call_setup_cpu - call the setup_cpu function for this cpu
+ * r3 = data offset, r24 = cpu number
+ *
+@@ -768,91 +694,6 @@ _GLOBAL(_outsb)
+ bdnz 00b
+ blr
+
+-_GLOBAL(_insw)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,2
+- blelr-
+-00: lhbrx r5,0,r3
+-01: eieio
+-02: sthu r5,2(r4)
+- ISYNC_8xx
+- .section .fixup,"ax"
+-03: blr
+- .text
+- .section __ex_table, "a"
+- .align 2
+- .long 00b, 03b
+- .long 01b, 03b
+- .long 02b, 03b
+- .text
+- bdnz 00b
+- blr
+-
+-_GLOBAL(_outsw)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,2
+- blelr-
+-00: lhzu r5,2(r4)
+-01: eieio
+-02: sthbrx r5,0,r3
+- ISYNC_8xx
+- .section .fixup,"ax"
+-03: blr
+- .text
+- .section __ex_table, "a"
+- .align 2
+- .long 00b, 03b
+- .long 01b, 03b
+- .long 02b, 03b
+- .text
+- bdnz 00b
+- blr
+-
+-_GLOBAL(_insl)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,4
+- blelr-
+-00: lwbrx r5,0,r3
+-01: eieio
+-02: stwu r5,4(r4)
+- ISYNC_8xx
+- .section .fixup,"ax"
+-03: blr
+- .text
+- .section __ex_table, "a"
+- .align 2
+- .long 00b, 03b
+- .long 01b, 03b
+- .long 02b, 03b
+- .text
+- bdnz 00b
+- blr
+-
+-_GLOBAL(_outsl)
+- cmpwi 0,r5,0
+- mtctr r5
+- subi r4,r4,4
+- blelr-
+-00: lwzu r5,4(r4)
+-01: stwbrx r5,0,r3
+-02: eieio
+- ISYNC_8xx
+- .section .fixup,"ax"
+-03: blr
+- .text
+- .section __ex_table, "a"
+- .align 2
+- .long 00b, 03b
+- .long 01b, 03b
+- .long 02b, 03b
+- .text
+- bdnz 00b
+- blr
+-
+-_GLOBAL(__ide_mm_insw)
+ _GLOBAL(_insw_ns)
+ cmpwi 0,r5,0
+ mtctr r5
+@@ -874,7 +715,6 @@ _GLOBAL(_insw_ns)
+ bdnz 00b
+ blr
+
+-_GLOBAL(__ide_mm_outsw)
+ _GLOBAL(_outsw_ns)
+ cmpwi 0,r5,0
+ mtctr r5
+@@ -896,7 +736,6 @@ _GLOBAL(_outsw_ns)
+ bdnz 00b
+ blr
+
+-_GLOBAL(__ide_mm_insl)
+ _GLOBAL(_insl_ns)
+ cmpwi 0,r5,0
+ mtctr r5
+@@ -918,7 +757,6 @@ _GLOBAL(_insl_ns)
+ bdnz 00b
+ blr
+
+-_GLOBAL(__ide_mm_outsl)
+ _GLOBAL(_outsl_ns)
+ cmpwi 0,r5,0
+ mtctr r5
+@@ -1030,20 +868,16 @@ _GLOBAL(kernel_thread)
+ addi r1,r1,16
+ blr
+
++_GLOBAL(kernel_execve)
++ li r0,__NR_execve
++ sc
++ bnslr
++ neg r3,r3
++ blr
++
+ /*
+ * This routine is just here to keep GCC happy - sigh...
+ */
+ _GLOBAL(__main)
+ blr
+
+-#define SYSCALL(name) \
+-_GLOBAL(name) \
+- li r0,__NR_##name; \
+- sc; \
+- bnslr; \
+- lis r4,errno at ha; \
+- stw r3,errno at l(r4); \
+- li r3,-1; \
+- blr
+-
+-SYSCALL(execve)
+diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
+index d173540..c8b65ca 100644
+--- a/arch/ppc/kernel/ppc_ksyms.c
++++ b/arch/ppc/kernel/ppc_ksyms.c
+@@ -115,17 +115,8 @@ EXPORT_SYMBOL(outw);
+ EXPORT_SYMBOL(outl);
+ EXPORT_SYMBOL(outsl);*/
+
+-EXPORT_SYMBOL(__ide_mm_insl);
+-EXPORT_SYMBOL(__ide_mm_outsw);
+-EXPORT_SYMBOL(__ide_mm_insw);
+-EXPORT_SYMBOL(__ide_mm_outsl);
+-
+ EXPORT_SYMBOL(_insb);
+ EXPORT_SYMBOL(_outsb);
+-EXPORT_SYMBOL(_insw);
+-EXPORT_SYMBOL(_outsw);
+-EXPORT_SYMBOL(_insl);
+-EXPORT_SYMBOL(_outsl);
+ EXPORT_SYMBOL(_insw_ns);
+ EXPORT_SYMBOL(_outsw_ns);
+ EXPORT_SYMBOL(_insl_ns);
+diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
+index a74f46d..27faeca 100644
+--- a/arch/ppc/kernel/setup.c
++++ b/arch/ppc/kernel/setup.c
+@@ -38,6 +38,7 @@
+ #include <asm/nvram.h>
+ #include <asm/xmon.h>
+ #include <asm/ocp.h>
++#include <asm/prom.h>
+
+ #define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \
+ defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \
+@@ -53,8 +54,6 @@
+
+ extern void platform_init(unsigned long r3, unsigned long r4,
+ unsigned long r5, unsigned long r6, unsigned long r7);
+-extern void identify_cpu(unsigned long offset, unsigned long cpu);
+-extern void do_cpu_ftr_fixups(unsigned long offset);
+ extern void reloc_got2(unsigned long offset);
+
+ extern void ppc6xx_idle(void);
+@@ -86,10 +85,6 @@ int ppc_do_canonicalize_irqs;
+ EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
+ #endif
+
+-#ifdef CONFIG_MAGIC_SYSRQ
+-unsigned long SYSRQ_KEY = 0x54;
+-#endif /* CONFIG_MAGIC_SYSRQ */
+-
+ #ifdef CONFIG_VGA_CONSOLE
+ unsigned long vgacon_remap_base;
+ #endif
+@@ -127,11 +122,8 @@ void machine_restart(char *cmd)
+ ppc_md.restart(cmd);
+ }
+
+-void machine_power_off(void)
++static void ppc_generic_power_off(void)
+ {
+-#ifdef CONFIG_NVRAM
+- nvram_sync();
+-#endif
+ ppc_md.power_off();
+ }
+
+@@ -143,7 +135,17 @@ void machine_halt(void)
+ ppc_md.halt();
+ }
+
+-void (*pm_power_off)(void) = machine_power_off;
++void (*pm_power_off)(void) = ppc_generic_power_off;
++
++void machine_power_off(void)
++{
++#ifdef CONFIG_NVRAM
++ nvram_sync();
++#endif
++ if (pm_power_off)
++ pm_power_off();
++ ppc_generic_power_off();
++}
+
+ #ifdef CONFIG_TAU
+ extern u32 cpu_temp(unsigned long cpu);
+@@ -298,6 +300,7 @@ early_init(int r3, int r4, int r5)
+ {
+ unsigned long phys;
+ unsigned long offset = reloc_offset();
++ struct cpu_spec *spec;
+
+ /* Default */
+ phys = offset + KERNELBASE;
+@@ -310,8 +313,10 @@ early_init(int r3, int r4, int r5)
+ * Identify the CPU type and fix up code sections
+ * that depend on which cpu we have.
+ */
+- identify_cpu(offset, 0);
+- do_cpu_ftr_fixups(offset);
++ spec = identify_cpu(offset);
++ do_feature_fixups(spec->cpu_features,
++ PTRRELOC(&__start___ftr_fixup),
++ PTRRELOC(&__stop___ftr_fixup));
+
+ return phys;
+ }
+diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
+index ca57e89..96a5597 100644
+--- a/arch/ppc/kernel/smp.c
++++ b/arch/ppc/kernel/smp.c
+@@ -84,7 +84,7 @@ smp_message_pass(int target, int msg)
+ /*
+ * Common functions
+ */
+-void smp_message_recv(int msg, struct pt_regs *regs)
++void smp_message_recv(int msg)
+ {
+ atomic_inc(&ipi_recv);
+
+@@ -100,7 +100,7 @@ void smp_message_recv(int msg, struct pt
+ break;
+ #ifdef CONFIG_XMON
+ case PPC_MSG_XMON_BREAK:
+- xmon(regs);
++ xmon(get_irq_regs());
+ break;
+ #endif /* CONFIG_XMON */
+ default:
+diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
+index 6ab8cc7..18ee851 100644
+--- a/arch/ppc/kernel/time.c
++++ b/arch/ppc/kernel/time.c
+@@ -62,6 +62,7 @@
+ #include <asm/cache.h>
+ #include <asm/8xx_immap.h>
+ #include <asm/machdep.h>
++#include <asm/irq_regs.h>
+
+ #include <asm/time.h>
+
+@@ -80,8 +81,6 @@ unsigned tb_to_us;
+ unsigned tb_last_stamp;
+ unsigned long tb_to_ns_scale;
+
+-extern unsigned long wall_jiffies;
+-
+ /* used for timezone offset */
+ static long timezone_offset;
+
+@@ -131,6 +130,7 @@ void wakeup_decrementer(void)
+ */
+ void timer_interrupt(struct pt_regs * regs)
+ {
++ struct pt_regs *old_regs;
+ int next_dec;
+ unsigned long cpu = smp_processor_id();
+ unsigned jiffy_stamp = last_jiffy_stamp(cpu);
+@@ -139,12 +139,13 @@ void timer_interrupt(struct pt_regs * re
+ if (atomic_read(&ppc_n_lost_interrupts) != 0)
+ do_IRQ(regs);
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+
+ while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) {
+ jiffy_stamp += tb_ticks_per_jiffy;
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ update_process_times(user_mode(regs));
+
+ if (smp_processor_id())
+@@ -153,7 +154,7 @@ void timer_interrupt(struct pt_regs * re
+ /* We are in an interrupt, no need to save/restore flags */
+ write_seqlock(&xtime_lock);
+ tb_last_stamp = jiffy_stamp;
+- do_timer(regs);
++ do_timer(1);
+
+ /*
+ * update the rtc when needed, this should be performed on the
+@@ -173,8 +174,7 @@ void timer_interrupt(struct pt_regs * re
+ */
+ if ( ppc_md.set_rtc_time && ntp_synced() &&
+ xtime.tv_sec - last_rtc_update >= 659 &&
+- abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
+- jiffies - wall_jiffies == 1) {
++ abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ) {
+ if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0)
+ last_rtc_update = xtime.tv_sec+1;
+ else
+@@ -191,6 +191,7 @@ void timer_interrupt(struct pt_regs * re
+ ppc_md.heartbeat();
+
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ /*
+@@ -200,7 +201,7 @@ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+ unsigned long seq;
+- unsigned delta, lost_ticks, usec, sec;
++ unsigned delta, usec, sec;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+@@ -214,10 +215,9 @@ void do_gettimeofday(struct timeval *tv)
+ if (!smp_tb_synchronized)
+ delta = 0;
+ #endif /* CONFIG_SMP */
+- lost_ticks = jiffies - wall_jiffies;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+- usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta);
++ usec += mulhwu(tb_to_us, delta);
+ while (usec >= 1000000) {
+ sec++;
+ usec -= 1000000;
+@@ -258,7 +258,6 @@ int do_settimeofday(struct timespec *tv)
+ * still reasonable when gettimeofday resolution is 1 jiffy.
+ */
+ tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id()));
+- tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
+
+ new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta);
+
+diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
+index d7a4330..9661a91 100644
+--- a/arch/ppc/kernel/traps.c
++++ b/arch/ppc/kernel/traps.c
+@@ -119,7 +119,7 @@ void _exception(int signr, struct pt_reg
+ * generate the same exception over and over again and we get
+ * nowhere. Better to kill it and let the kernel panic.
+ */
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ __sighandler_t handler;
+
+ spin_lock_irq(¤t->sighand->siglock);
+@@ -708,7 +708,7 @@ void single_step_exception(struct pt_reg
+
+ void alignment_exception(struct pt_regs *regs)
+ {
+- int fixed;
++ int sig, code, fixed = 0;
+
+ fixed = fix_alignment(regs);
+ if (fixed == 1) {
+@@ -717,14 +717,16 @@ void alignment_exception(struct pt_regs
+ return;
+ }
+ if (fixed == -EFAULT) {
+- /* fixed == -EFAULT means the operand address was bad */
+- if (user_mode(regs))
+- _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
+- else
+- bad_page_fault(regs, regs->dar, SIGSEGV);
+- return;
++ sig = SIGSEGV;
++ code = SEGV_ACCERR;
++ } else {
++ sig = SIGBUS;
++ code = BUS_ADRALN;
+ }
+- _exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
++ if (user_mode(regs))
++ _exception(sig, regs, code, regs->dar);
++ else
++ bad_page_fault(regs, regs->dar, sig);
+ }
+
+ void StackOverflow(struct pt_regs *regs)
+diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
+index 095fd33..16e8661 100644
+--- a/arch/ppc/kernel/vmlinux.lds.S
++++ b/arch/ppc/kernel/vmlinux.lds.S
+@@ -115,13 +115,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+
+diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
+index 5cdfb71..465f451 100644
+--- a/arch/ppc/mm/fault.c
++++ b/arch/ppc/mm/fault.c
+@@ -239,7 +239,7 @@ good_area:
+ /* protection fault */
+ if (error_code & 0x08000000)
+ goto bad_area;
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ }
+
+@@ -291,7 +291,7 @@ bad_area:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
+index 523392d..c374e53 100644
+--- a/arch/ppc/mm/init.c
++++ b/arch/ppc/mm/init.c
+@@ -358,8 +358,8 @@ void __init do_init_bootmem(void)
+ */
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES], i;
+-
++ unsigned long start_pfn, end_pfn;
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ #ifdef CONFIG_HIGHMEM
+ map_page(PKMAP_BASE, 0, 0); /* XXX gross */
+ pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k
+@@ -369,19 +369,19 @@ void __init paging_init(void)
+ (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN);
+ kmap_prot = PAGE_KERNEL;
+ #endif /* CONFIG_HIGHMEM */
++ /* All pages are DMA-able so we put them all in the DMA zone. */
++ start_pfn = __pa(PAGE_OFFSET) >> PAGE_SHIFT;
++ end_pfn = start_pfn + (total_memory >> PAGE_SHIFT);
++ add_active_range(0, start_pfn, end_pfn);
+
+- /*
+- * All pages are DMA-able so we put them all in the DMA zone.
+- */
+- zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
+- for (i = 1; i < MAX_NR_ZONES; i++)
+- zones_size[i] = 0;
+-
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ #ifdef CONFIG_HIGHMEM
+- zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT;
++ max_zone_pfns[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
++ max_zone_pfns[ZONE_HIGHMEM] = total_memory >> PAGE_SHIFT;
++#else
++ max_zone_pfns[ZONE_DMA] = total_memory >> PAGE_SHIFT;
+ #endif /* CONFIG_HIGHMEM */
+-
+- free_area_init(zones_size);
++ free_area_init_nodes(max_zone_pfns);
+ }
+
+ void __init mem_init(void)
+diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h
+index f5a5c0c..a6c0a13 100644
+--- a/arch/ppc/platforms/4xx/cpci405.h
++++ b/arch/ppc/platforms/4xx/cpci405.h
+@@ -13,7 +13,6 @@
+ #ifndef __CPCI405_H__
+ #define __CPCI405_H__
+
+-#include <linux/config.h>
+ #include <platforms/4xx/ibm405gp.h>
+ #include <asm/ppcboot.h>
+
+diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h b/arch/ppc/platforms/4xx/xparameters/xparameters.h
+index cd7d0e7..66ec5f3 100644
+--- a/arch/ppc/platforms/4xx/xparameters/xparameters.h
++++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/xparameters.h
++ * arch/ppc/platforms/4xx/xparameters/xparameters.h
+ *
+ * This file includes the correct xparameters.h for the CONFIG'ed board plus
+ * fixups to translate board specific XPAR values to a common set of names
+diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig
+index 7ddd331..6f2d0ad 100644
+--- a/arch/ppc/platforms/85xx/Kconfig
++++ b/arch/ppc/platforms/85xx/Kconfig
+@@ -24,12 +24,12 @@ config MPC8540_ADS
+ config MPC8548_CDS
+ bool "Freescale MPC8548 CDS"
+ help
+- This option enablese support for the MPC8548 CDS evaluation board.
++ This option enables support for the MPC8548 CDS evaluation board.
+
+ config MPC8555_CDS
+ bool "Freescale MPC8555 CDS"
+ help
+- This option enablese support for the MPC8555 CDS evaluation board.
++ This option enables support for the MPC8555 CDS evaluation board.
+
+ config MPC8560_ADS
+ bool "Freescale MPC8560 ADS"
+@@ -51,22 +51,22 @@ config STX_GP3
+ config TQM8540
+ bool "TQ Components TQM8540"
+ help
+- This option enablese support for the TQ Components TQM8540 board.
++ This option enables support for the TQ Components TQM8540 board.
+
+ config TQM8541
+ bool "TQ Components TQM8541"
+ help
+- This option enablese support for the TQ Components TQM8541 board.
++ This option enables support for the TQ Components TQM8541 board.
+
+ config TQM8555
+ bool "TQ Components TQM8555"
+ help
+- This option enablese support for the TQ Components TQM8555 board.
++ This option enables support for the TQ Components TQM8555 board.
+
+ config TQM8560
+ bool "TQ Components TQM8560"
+ help
+- This option enablese support for the TQ Components TQM8560 board.
++ This option enables support for the TQ Components TQM8560 board.
+
+ endchoice
+
+@@ -94,7 +94,7 @@ config MPC8560
+ default y
+
+ config 85xx_PCI2
+- bool "Supprt for 2nd PCI host controller"
++ bool "Support for 2nd PCI host controller"
+ depends on MPC8555_CDS
+ default y
+
+diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
+index 94badaf..14ecec7 100644
+--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
++++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
+@@ -211,10 +211,10 @@ mpc8560ads_setup_arch(void)
+ #endif
+ }
+
+-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cpm2_cascade(int irq, void *dev_id)
+ {
+- while ((irq = cpm2_get_irq(regs)) >= 0)
+- __do_IRQ(irq, regs);
++ while ((irq = cpm2_get_irq()) >= 0)
++ __do_IRQ(irq);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+index 7520458..5ce0f69 100644
+--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
++++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+@@ -127,10 +127,10 @@ mpc85xx_cds_show_cpuinfo(struct seq_file
+ }
+
+ #ifdef CONFIG_CPM2
+-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cpm2_cascade(int irq, void *dev_id)
+ {
+- while((irq = cpm2_get_irq(regs)) >= 0)
+- __do_IRQ(irq, regs);
++ while((irq = cpm2_get_irq()) >= 0)
++ __do_IRQ(irq);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/arch/ppc/platforms/85xx/sbc8560.h b/arch/ppc/platforms/85xx/sbc8560.h
+index c7d61cf..e5e156f 100644
+--- a/arch/ppc/platforms/85xx/sbc8560.h
++++ b/arch/ppc/platforms/85xx/sbc8560.h
+@@ -14,6 +14,7 @@
+ #define __MACH_SBC8560_H__
+
+ #include <platforms/85xx/sbc85xx.h>
++#include <asm/irq.h>
+
+ #define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+diff --git a/arch/ppc/platforms/85xx/sbc85xx.h b/arch/ppc/platforms/85xx/sbc85xx.h
+index 21ea7a5..51df4dc 100644
+--- a/arch/ppc/platforms/85xx/sbc85xx.h
++++ b/arch/ppc/platforms/85xx/sbc85xx.h
+@@ -49,4 +49,22 @@ extern void sbc8560_init_IRQ(void) __ini
+
+ #define MPC85XX_PCI1_IO_SIZE 0x01000000
+
++/* FCC1 Clock Source Configuration. These can be
++ * redefined in the board specific file.
++ * Can only choose from CLK9-12 */
++#define F1_RXCLK 12
++#define F1_TXCLK 11
++
++/* FCC2 Clock Source Configuration. These can be
++ * redefined in the board specific file.
++ * Can only choose from CLK13-16 */
++#define F2_RXCLK 13
++#define F2_TXCLK 14
++
++/* FCC3 Clock Source Configuration. These can be
++ * redefined in the board specific file.
++ * Can only choose from CLK13-16 */
++#define F3_RXCLK 15
++#define F3_TXCLK 16
++
+ #endif /* __PLATFORMS_85XX_SBC85XX_H__ */
+diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
+index 495aa79..4bb18ab 100644
+--- a/arch/ppc/platforms/85xx/stx_gp3.c
++++ b/arch/ppc/platforms/85xx/stx_gp3.c
+@@ -156,10 +156,10 @@ gp3_setup_arch(void)
+ printk ("bi_immr_base = %8.8lx\n", binfo->bi_immr_base);
+ }
+
+-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cpm2_cascade(int irq, void *dev_id)
+ {
+- while ((irq = cpm2_get_irq(regs)) >= 0)
+- __do_IRQ(irq, regs);
++ while ((irq = cpm2_get_irq()) >= 0)
++ __do_IRQ(irq);
+
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
+index 189ed41..dd45f2e 100644
+--- a/arch/ppc/platforms/85xx/tqm85xx.c
++++ b/arch/ppc/platforms/85xx/tqm85xx.c
+@@ -181,10 +181,10 @@ tqm85xx_setup_arch(void)
+ }
+
+ #ifdef CONFIG_MPC8560
+-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cpm2_cascade(int irq, void *dev_id)
+ {
+- while ((irq = cpm2_get_irq(regs)) >= 0)
+- __do_IRQ(irq, regs);
++ while ((irq = cpm2_get_irq()) >= 0)
++ __do_IRQ(irq);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c
+index 1d034ea..063274d 100644
+--- a/arch/ppc/platforms/apus_setup.c
++++ b/arch/ppc/platforms/apus_setup.c
+@@ -492,7 +492,7 @@ apus_halt(void)
+
+ static unsigned char last_ipl[8];
+
+-int apus_get_irq(struct pt_regs* regs)
++int apus_get_irq(void)
+ {
+ unsigned char ipl_emu, mask;
+ unsigned int level;
+diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c
+index e0f112a..d809e17 100644
+--- a/arch/ppc/platforms/hdpu.c
++++ b/arch/ppc/platforms/hdpu.c
+@@ -659,8 +659,7 @@ static void __init hdpu_map_io(void)
+ char hdpu_smp0[] = "SMP Cpu #0";
+ char hdpu_smp1[] = "SMP Cpu #1";
+
+-static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id)
+ {
+ volatile unsigned int doorbell;
+
+@@ -670,22 +669,21 @@ static irqreturn_t hdpu_smp_cpu0_int_han
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, doorbell);
+
+ if (doorbell & 1) {
+- smp_message_recv(0, regs);
++ smp_message_recv(0);
+ }
+ if (doorbell & 2) {
+- smp_message_recv(1, regs);
++ smp_message_recv(1);
+ }
+ if (doorbell & 4) {
+- smp_message_recv(2, regs);
++ smp_message_recv(2);
+ }
+ if (doorbell & 8) {
+- smp_message_recv(3, regs);
++ smp_message_recv(3);
+ }
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id)
+ {
+ volatile unsigned int doorbell;
+
+@@ -695,16 +693,16 @@ static irqreturn_t hdpu_smp_cpu1_int_han
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, doorbell);
+
+ if (doorbell & 1) {
+- smp_message_recv(0, regs);
++ smp_message_recv(0);
+ }
+ if (doorbell & 2) {
+- smp_message_recv(1, regs);
++ smp_message_recv(1);
+ }
+ if (doorbell & 4) {
+- smp_message_recv(2, regs);
++ smp_message_recv(2);
+ }
+ if (doorbell & 8) {
+- smp_message_recv(3, regs);
++ smp_message_recv(3);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h
+index 5490edb..d597b68 100644
+--- a/arch/ppc/platforms/lopec.h
++++ b/arch/ppc/platforms/lopec.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/lopec_serial.h
++ * arch/ppc/platforms/lopec.h
+ *
+ * Definitions for Motorola LoPEC board.
+ *
+diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c
+index 2a35fe2..1f9ea36 100644
+--- a/arch/ppc/platforms/mpc8272ads_setup.c
++++ b/arch/ppc/platforms/mpc8272ads_setup.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/ppc/platforms/82xx/pq2ads_pd.c
++ * arch/ppc/platforms/mpc8272ads_setup.c
+ *
+ * MPC82xx Board-specific PlatformDevice descriptions
+ *
+@@ -103,7 +103,7 @@ static struct fs_platform_info mpc82xx_e
+ },
+ };
+
+-static void init_fcc1_ioports(void)
++static void init_fcc1_ioports(struct fs_platform_info*)
+ {
+ struct io_port *io;
+ u32 tempval;
+@@ -144,7 +144,7 @@ static void init_fcc1_ioports(void)
+ iounmap(immap);
+ }
+
+-static void init_fcc2_ioports(void)
++static void init_fcc2_ioports(struct fs_platform_info*)
+ {
+ cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+ u32 *bcsr = ioremap(BCSR_ADDR+12, sizeof(u32));
+@@ -196,7 +196,7 @@ static void __init mpc8272ads_fixup_enet
+ bd_t* bi = (void*)__res;
+ int fs_no = fsid_fcc1+pdev->id-1;
+
+- if(fs_no > ARRAY_SIZE(mpc82xx_enet_pdata)) {
++ if(fs_no >= ARRAY_SIZE(mpc82xx_enet_pdata)) {
+ return;
+ }
+
+@@ -222,14 +222,14 @@ static void mpc8272ads_fixup_uart_pdata(
+ int id = fs_uart_id_scc2fsid(idx);
+
+ /* no need to alter anything if console */
+- if ((id <= num) && (!pdev->dev.platform_data)) {
++ if ((id < num) && (!pdev->dev.platform_data)) {
+ pinfo = &mpc8272_uart_pdata[id];
+ pinfo->uart_clk = bd->bi_intfreq;
+ pdev->dev.platform_data = pinfo;
+ }
+ }
+
+-static void init_scc1_uart_ioports(void)
++static void init_scc1_uart_ioports(struct fs_uart_platform_info*)
+ {
+ cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+
+@@ -246,7 +246,7 @@ static void init_scc1_uart_ioports(void)
+ iounmap(immap);
+ }
+
+-static void init_scc4_uart_ioports(void)
++static void init_scc4_uart_ioports(struct fs_uart_platform_info*)
+ {
+ cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+
+diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
+index e12cece..e95d2c1 100644
+--- a/arch/ppc/platforms/mpc866ads_setup.c
++++ b/arch/ppc/platforms/mpc866ads_setup.c
+@@ -137,7 +137,7 @@ void __init board_init(void)
+ iounmap(bcsr_io);
+ }
+
+-static void setup_fec1_ioports(void)
++static void setup_fec1_ioports(struct fs_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+
+@@ -145,7 +145,7 @@ static void setup_fec1_ioports(void)
+ setbits16(&immap->im_ioport.iop_pddir, 0x1fff);
+ }
+
+-static void setup_scc1_ioports(void)
++static void setup_scc1_ioports(struct fs_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+ unsigned *bcsr_io;
+@@ -194,7 +194,7 @@ static void setup_scc1_ioports(void)
+
+ }
+
+-static void setup_smc1_ioports(void)
++static void setup_smc1_ioports(struct fs_uart_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+ unsigned *bcsr_io;
+@@ -216,7 +216,7 @@ static void setup_smc1_ioports(void)
+
+ }
+
+-static void setup_smc2_ioports(void)
++static void setup_smc2_ioports(struct fs_uart_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+ unsigned *bcsr_io;
+@@ -259,7 +259,7 @@ static void mpc866ads_fixup_enet_pdata(s
+ /* Get pointer to Communication Processor */
+ cp = cpmp;
+
+- if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) {
++ if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) {
+ printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
+ return;
+ }
+@@ -305,7 +305,7 @@ static void __init mpc866ads_fixup_uart_
+ int id = fs_uart_id_smc2fsid(idx);
+
+ /* no need to alter anything if console */
+- if ((id <= num) && (!pdev->dev.platform_data)) {
++ if ((id < num) && (!pdev->dev.platform_data)) {
+ pinfo = &mpc866_uart_pdata[id];
+ pinfo->uart_clk = bd->bi_intfreq;
+ pdev->dev.platform_data = pinfo;
+diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c
+index 5dfa4e6..f8161f3 100644
+--- a/arch/ppc/platforms/mpc885ads_setup.c
++++ b/arch/ppc/platforms/mpc885ads_setup.c
+@@ -1,4 +1,4 @@
+-/*arch/ppc/platforms/mpc885ads-setup.c
++/*arch/ppc/platforms/mpc885ads_setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+@@ -161,7 +161,7 @@ void __init board_init(void)
+ #endif
+ }
+
+-static void setup_fec1_ioports(void)
++static void setup_fec1_ioports(struct fs_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+
+@@ -181,7 +181,7 @@ static void setup_fec1_ioports(void)
+ clrbits32(&immap->im_cpm.cp_cptr, 0x00000100);
+ }
+
+-static void setup_fec2_ioports(void)
++static void setup_fec2_ioports(struct fs_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+
+@@ -193,7 +193,7 @@ static void setup_fec2_ioports(void)
+ clrbits32(&immap->im_cpm.cp_cptr, 0x00000080);
+ }
+
+-static void setup_scc3_ioports(void)
++static void setup_scc3_ioports(struct fs_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+ unsigned *bcsr_io;
+@@ -263,7 +263,7 @@ static void mpc885ads_fixup_enet_pdata(s
+ char *e;
+ int i;
+
+- if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) {
++ if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) {
+ printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
+ return;
+ }
+@@ -315,7 +315,7 @@ static void __init mpc885ads_fixup_scc_e
+ mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+ }
+
+-static void setup_smc1_ioports(void)
++static void setup_smc1_ioports(struct fs_uart_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+ unsigned *bcsr_io;
+@@ -335,7 +335,7 @@ static void setup_smc1_ioports(void)
+ clrbits16(&immap->im_cpm.cp_pbodr, iobits);
+ }
+
+-static void setup_smc2_ioports(void)
++static void setup_smc2_ioports(struct fs_uart_platform_info*)
+ {
+ immap_t *immap = (immap_t *) IMAP_ADDR;
+ unsigned *bcsr_io;
+@@ -371,7 +371,7 @@ static void __init mpc885ads_fixup_uart_
+ int id = fs_uart_id_smc2fsid(idx);
+
+ /* no need to alter anything if console */
+- if ((id <= num) && (!pdev->dev.platform_data)) {
++ if ((id < num) && (!pdev->dev.platform_data)) {
+ pinfo = &mpc885_uart_pdata[id];
+ pinfo->uart_clk = bd->bi_intfreq;
+ pdev->dev.platform_data = pinfo;
+diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h
+index edd4794..9e2a09e 100644
+--- a/arch/ppc/platforms/mvme5100.h
++++ b/arch/ppc/platforms/mvme5100.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/platforms/mvme5100.h
++ * arch/ppc/platforms/mvme5100.h
+ *
+ * Definitions for Motorola MVME5100.
+ *
+diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h
+index 41a6dc8..d33ad8d 100644
+--- a/arch/ppc/platforms/powerpmc250.h
++++ b/arch/ppc/platforms/powerpmc250.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/platforms/powerpmc250.h
++ * arch/ppc/platforms/powerpmc250.h
+ *
+ * Definitions for Force PowerPMC-250 board support
+ *
+diff --git a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h
+index 015b4f5..4c7adcc 100644
+--- a/arch/ppc/platforms/prpmc750.h
++++ b/arch/ppc/platforms/prpmc750.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/platforms/prpmc750.h
++ * arch/ppc/platforms/prpmc750.h
+ *
+ * Definitions for Motorola PrPMC750 board support
+ *
+diff --git a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h
+index e53ec9b..26f604e 100644
+--- a/arch/ppc/platforms/prpmc800.h
++++ b/arch/ppc/platforms/prpmc800.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/platforms/prpmc800.h
++ * arch/ppc/platforms/prpmc800.h
+ *
+ * Definitions for Motorola PrPMC800 board support
+ *
+diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c
+index 3bb530a..13d70ab 100644
+--- a/arch/ppc/platforms/radstone_ppc7d.c
++++ b/arch/ppc/platforms/radstone_ppc7d.c
+@@ -451,11 +451,11 @@ static void __init ppc7d_calibrate_decr(
+ * Interrupt stuff
+ *****************************************************************************/
+
+-static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id)
+ {
+ u32 temp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE);
+ if (temp & (1 << 28)) {
+- i8259_irq(regs);
++ i8259_irq();
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, temp & (~(1 << 28)));
+ return IRQ_HANDLED;
+ }
+@@ -536,13 +536,13 @@ static u32 ppc7d_irq_canonicalize(u32 ir
+ return irq;
+ }
+
+-static int ppc7d_get_irq(struct pt_regs *regs)
++static int ppc7d_get_irq(void)
+ {
+ int irq;
+
+- irq = mv64360_get_irq(regs);
++ irq = mv64360_get_irq();
+ if (irq == (mv64360_irq_base + MV64x60_IRQ_GPP28))
+- irq = i8259_irq(regs);
++ irq = i8259_irq();
+ return irq;
+ }
+
+diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c
+index 60b769c..cc0935c 100644
+--- a/arch/ppc/platforms/sbc82xx.c
++++ b/arch/ppc/platforms/sbc82xx.c
+@@ -121,7 +121,7 @@ struct hw_interrupt_type sbc82xx_i8259_i
+ .end = sbc82xx_i8259_end_irq,
+ };
+
+-static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id)
+ {
+ spin_lock(&sbc82xx_i8259_lock);
+
+@@ -139,7 +139,7 @@ static irqreturn_t sbc82xx_i8259_demux(i
+ return IRQ_HANDLED;
+ }
+ }
+- __do_IRQ(NR_SIU_INTS + irq, regs);
++ __do_IRQ(NR_SIU_INTS + irq);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h
+index a31ff7e..f1f96f1 100644
+--- a/arch/ppc/platforms/spruce.h
++++ b/arch/ppc/platforms/spruce.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/platforms/spruce.h
++ * arch/ppc/platforms/spruce.h
+ *
+ * Definitions for IBM Spruce reference board support
+ *
+diff --git a/arch/ppc/syslib/cpc700.h b/arch/ppc/syslib/cpc700.h
+index 0a8a5d8..987e9aa 100644
+--- a/arch/ppc/syslib/cpc700.h
++++ b/arch/ppc/syslib/cpc700.h
+@@ -91,6 +91,6 @@ extern struct hw_interrupt_type cpc700_p
+ extern unsigned int cpc700_irq_assigns[32][2];
+
+ extern void __init cpc700_init_IRQ(void);
+-extern int cpc700_get_irq(struct pt_regs *);
++extern int cpc700_get_irq(void);
+
+ #endif /* __PPC_SYSLIB_CPC700_H__ */
+diff --git a/arch/ppc/syslib/cpc700_pic.c b/arch/ppc/syslib/cpc700_pic.c
+index 172aa21..d48e8f4 100644
+--- a/arch/ppc/syslib/cpc700_pic.c
++++ b/arch/ppc/syslib/cpc700_pic.c
+@@ -158,7 +158,7 @@ cpc700_init_IRQ(void)
+ * Find the highest IRQ that generating an interrupt, if any.
+ */
+ int
+-cpc700_get_irq(struct pt_regs *regs)
++cpc700_get_irq(void)
+ {
+ int irq = 0;
+ u_int irq_status, irq_test = 1;
+diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
+index c0fee0b..fb2d584 100644
+--- a/arch/ppc/syslib/cpm2_pic.c
++++ b/arch/ppc/syslib/cpm2_pic.c
+@@ -123,7 +123,7 @@ static struct hw_interrupt_type cpm2_pic
+ .end = cpm2_end_irq,
+ };
+
+-int cpm2_get_irq(struct pt_regs *regs)
++int cpm2_get_irq(void)
+ {
+ int irq;
+ unsigned long bits;
+diff --git a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h
+index 97cab8f..4673393 100644
+--- a/arch/ppc/syslib/cpm2_pic.h
++++ b/arch/ppc/syslib/cpm2_pic.h
+@@ -1,7 +1,7 @@
+ #ifndef _PPC_KERNEL_CPM2_H
+ #define _PPC_KERNEL_CPM2_H
+
+-extern int cpm2_get_irq(struct pt_regs *regs);
++extern int cpm2_get_irq(void);
+
+ extern void cpm2_init_IRQ(void);
+
+diff --git a/arch/ppc/syslib/gt64260_pic.c b/arch/ppc/syslib/gt64260_pic.c
+index 7fd550a..e84d432 100644
+--- a/arch/ppc/syslib/gt64260_pic.c
++++ b/arch/ppc/syslib/gt64260_pic.c
+@@ -110,9 +110,6 @@ gt64260_init_irq(void)
+ * This function returns the lowest interrupt number of all interrupts that
+ * are currently asserted.
+ *
+- * Input Variable(s):
+- * struct pt_regs* not used
+- *
+ * Output Variable(s):
+ * None.
+ *
+@@ -120,7 +117,7 @@ gt64260_init_irq(void)
+ * int <interrupt number> or -2 (bogus interrupt)
+ */
+ int
+-gt64260_get_irq(struct pt_regs *regs)
++gt64260_get_irq(void)
+ {
+ int irq;
+ int irq_gpp;
+@@ -229,7 +226,7 @@ gt64260_mask_irq(unsigned int irq)
+ }
+
+ static irqreturn_t
+-gt64260_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++gt64260_cpu_error_int_handler(int irq, void *dev_id)
+ {
+ printk(KERN_ERR "gt64260_cpu_error_int_handler: %s 0x%08x\n",
+ "Error on CPU interface - Cause regiser",
+@@ -250,7 +247,7 @@ gt64260_cpu_error_int_handler(int irq, v
+ }
+
+ static irqreturn_t
+-gt64260_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++gt64260_pci_error_int_handler(int irq, void *dev_id)
+ {
+ u32 val;
+ unsigned int pci_bus = (unsigned int)dev_id;
+diff --git a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c
+index eb35353..a43dda5 100644
+--- a/arch/ppc/syslib/i8259.c
++++ b/arch/ppc/syslib/i8259.c
+@@ -28,7 +28,7 @@ static int i8259_pic_irq_offset;
+ * which is called. It should be noted that polling is broken on some
+ * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
+ */
+-int i8259_irq(struct pt_regs *regs)
++int i8259_irq(void)
+ {
+ int irq;
+
+diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c
+index 4b77e6c..6ad52f4 100644
+--- a/arch/ppc/syslib/ibm440gx_common.c
++++ b/arch/ppc/syslib/ibm440gx_common.c
+@@ -119,7 +119,7 @@ static inline u32 l2c_diag(u32 addr)
+ return mfdcr(DCRN_L2C0_DATA);
+ }
+
+-static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs)
++static irqreturn_t l2c_error_handler(int irq, void* dev)
+ {
+ u32 sr = mfdcr(DCRN_L2C0_SR);
+ if (sr & L2C_SR_CPE){
+diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
+index 46801f5..10659c2 100644
+--- a/arch/ppc/syslib/ipic.c
++++ b/arch/ppc/syslib/ipic.c
+@@ -601,7 +601,7 @@ void ipic_clear_mcp_status(u32 mask)
+ }
+
+ /* Return an interrupt vector or -1 if no interrupt is pending. */
+-int ipic_get_irq(struct pt_regs *regs)
++int ipic_get_irq(void)
+ {
+ int irq;
+
+diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
+index 974581e..5475709 100644
+--- a/arch/ppc/syslib/m8260_pci_erratum9.c
++++ b/arch/ppc/syslib/m8260_pci_erratum9.c
+@@ -339,20 +339,6 @@ void insl(unsigned port, void *buf, int
+ idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
+ }
+
+-void insw_ns(unsigned port, void *buf, int ns)
+-{
+- u8 *addr = (u8 *)(port + _IO_BASE);
+-
+- idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
+-}
+-
+-void insl_ns(unsigned port, void *buf, int nl)
+-{
+- u8 *addr = (u8 *)(port + _IO_BASE);
+-
+- idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
+-}
+-
+ void *memcpy_fromio(void *dest, unsigned long src, size_t count)
+ {
+ unsigned long pa = iopa((unsigned long) src);
+@@ -373,8 +359,6 @@ EXPORT_SYMBOL(inl);
+ EXPORT_SYMBOL(insb);
+ EXPORT_SYMBOL(insw);
+ EXPORT_SYMBOL(insl);
+-EXPORT_SYMBOL(insw_ns);
+-EXPORT_SYMBOL(insl_ns);
+ EXPORT_SYMBOL(memcpy_fromio);
+
+ #endif /* ifdef CONFIG_8260_PCI9 */
+diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c
+index d3fa264..e3b586b 100644
+--- a/arch/ppc/syslib/m82xx_pci.c
++++ b/arch/ppc/syslib/m82xx_pci.c
+@@ -117,7 +117,7 @@ struct hw_interrupt_type pq2pci_ic = {
+ };
+
+ static irqreturn_t
+-pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
++pq2pci_irq_demux(int irq, void *dev_id)
+ {
+ unsigned long stat, mask, pend;
+ int bit;
+@@ -130,7 +130,7 @@ pq2pci_irq_demux(int irq, void *dev_id,
+ break;
+ for (bit = 0; pend != 0; ++bit, pend <<= 1) {
+ if (pend & 0x80000000)
+- __do_IRQ(NR_CPM_INTS + bit, regs);
++ __do_IRQ(NR_CPM_INTS + bit);
+ }
+ }
+
+diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
+index 54303a7..d8d299b 100644
+--- a/arch/ppc/syslib/m8xx_setup.c
++++ b/arch/ppc/syslib/m8xx_setup.c
+@@ -169,7 +169,7 @@ abort(void)
+ }
+
+ /* A place holder for time base interrupts, if they are ever enabled. */
+-irqreturn_t timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
++irqreturn_t timebase_interrupt(int irq, void * dev)
+ {
+ printk ("timebase_interrupt()\n");
+
+diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
+index ac11d7b..fffac8c 100644
+--- a/arch/ppc/syslib/m8xx_wdt.c
++++ b/arch/ppc/syslib/m8xx_wdt.c
+@@ -21,7 +21,7 @@
+ static int wdt_timeout;
+ int m8xx_has_internal_rtc = 0;
+
+-static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t m8xx_wdt_interrupt(int, void *);
+ static struct irqaction m8xx_wdt_irqaction = {
+ .handler = m8xx_wdt_interrupt,
+ .name = "watchdog",
+@@ -35,7 +35,7 @@ void m8xx_wdt_reset(void)
+ out_be16(&imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */
+ }
+
+-static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev)
+ {
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c
+index 6425b5c..af35a31 100644
+--- a/arch/ppc/syslib/mpc52xx_pic.c
++++ b/arch/ppc/syslib/mpc52xx_pic.c
+@@ -220,7 +220,7 @@ mpc52xx_init_irq(void)
+ }
+
+ int
+-mpc52xx_get_irq(struct pt_regs *regs)
++mpc52xx_get_irq(void)
+ {
+ u32 status;
+ int irq = -1;
+diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c
+index 3f6d162..4b7a333 100644
+--- a/arch/ppc/syslib/mv64360_pic.c
++++ b/arch/ppc/syslib/mv64360_pic.c
+@@ -55,10 +55,9 @@
+
+ static void mv64360_unmask_irq(unsigned int);
+ static void mv64360_mask_irq(unsigned int);
+-static irqreturn_t mv64360_cpu_error_int_handler(int, void *, struct pt_regs *);
+-static irqreturn_t mv64360_sram_error_int_handler(int, void *,
+- struct pt_regs *);
+-static irqreturn_t mv64360_pci_error_int_handler(int, void *, struct pt_regs *);
++static irqreturn_t mv64360_cpu_error_int_handler(int, void *);
++static irqreturn_t mv64360_sram_error_int_handler(int, void *);
++static irqreturn_t mv64360_pci_error_int_handler(int, void *);
+
+ /* ========================== local declarations =========================== */
+
+@@ -131,9 +130,6 @@ mv64360_init_irq(void)
+ * This function returns the lowest interrupt number of all interrupts that
+ * are currently asserted.
+ *
+- * Input Variable(s):
+- * struct pt_regs* not used
+- *
+ * Output Variable(s):
+ * None.
+ *
+@@ -142,7 +138,7 @@ mv64360_init_irq(void)
+ *
+ */
+ int
+-mv64360_get_irq(struct pt_regs *regs)
++mv64360_get_irq(void)
+ {
+ int irq;
+ int irq_gpp;
+@@ -283,7 +279,7 @@ mv64360_mask_irq(unsigned int irq)
+ }
+
+ static irqreturn_t
+-mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++mv64360_cpu_error_int_handler(int irq, void *dev_id)
+ {
+ printk(KERN_ERR "mv64360_cpu_error_int_handler: %s 0x%08x\n",
+ "Error on CPU interface - Cause regiser",
+@@ -304,7 +300,7 @@ mv64360_cpu_error_int_handler(int irq, v
+ }
+
+ static irqreturn_t
+-mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++mv64360_sram_error_int_handler(int irq, void *dev_id)
+ {
+ printk(KERN_ERR "mv64360_sram_error_int_handler: %s 0x%08x\n",
+ "Error in internal SRAM - Cause register",
+@@ -325,7 +321,7 @@ mv64360_sram_error_int_handler(int irq,
+ }
+
+ static irqreturn_t
+-mv64360_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++mv64360_pci_error_int_handler(int irq, void *dev_id)
+ {
+ u32 val;
+ unsigned int pci_bus = (unsigned int)dev_id;
+@@ -380,7 +376,7 @@ mv64360_register_hdlrs(void)
+ /* Clear old errors and register CPU interface error intr handler */
+ mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0);
+ if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base,
+- mv64360_cpu_error_int_handler, IRQF_DISABLED, CPU_INTR_STR, 0)))
++ mv64360_cpu_error_int_handler, IRQF_DISABLED, CPU_INTR_STR, NULL)))
+ printk(KERN_WARNING "Can't register cpu error handler: %d", rc);
+
+ mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0);
+@@ -389,7 +385,7 @@ mv64360_register_hdlrs(void)
+ /* Clear old errors and register internal SRAM error intr handler */
+ mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0);
+ if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base,
+- mv64360_sram_error_int_handler,IRQF_DISABLED,SRAM_INTR_STR, 0)))
++ mv64360_sram_error_int_handler,IRQF_DISABLED,SRAM_INTR_STR, NULL)))
+ printk(KERN_WARNING "Can't register SRAM error handler: %d",rc);
+
+ /* Clear old errors and register PCI 0 error intr handler */
+diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
+index aa0b957..18ec947 100644
+--- a/arch/ppc/syslib/open_pic.c
++++ b/arch/ppc/syslib/open_pic.c
+@@ -45,7 +45,7 @@ static u_int NumSources;
+ static int open_pic_irq_offset;
+ static volatile OpenPIC_Source __iomem *ISR[NR_IRQS];
+ static int openpic_cascade_irq = -1;
+-static int (*openpic_cascade_fn)(struct pt_regs *);
++static int (*openpic_cascade_fn)(void);
+
+ /* Global Operations */
+ static void openpic_disable_8259_pass_through(void);
+@@ -54,7 +54,7 @@ static void openpic_set_spurious(u_int v
+ #ifdef CONFIG_SMP
+ /* Interprocessor Interrupts */
+ static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+-static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *);
++static irqreturn_t openpic_ipi_action(int cpl, void *dev_id);
+ #endif
+
+ /* Timer Interrupts */
+@@ -700,7 +700,7 @@ static struct irqaction openpic_cascade_
+
+ void __init
+ openpic_hookup_cascade(u_int irq, char *name,
+- int (*cascade_fn)(struct pt_regs *))
++ int (*cascade_fn)(void))
+ {
+ openpic_cascade_irq = irq;
+ openpic_cascade_fn = cascade_fn;
+@@ -857,16 +857,16 @@ static void openpic_end_ipi(unsigned int
+ {
+ }
+
+-static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
++static irqreturn_t openpic_ipi_action(int cpl, void *dev_id)
+ {
+- smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
++ smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset);
+ return IRQ_HANDLED;
+ }
+
+ #endif /* CONFIG_SMP */
+
+ int
+-openpic_get_irq(struct pt_regs *regs)
++openpic_get_irq(void)
+ {
+ int irq = openpic_irq();
+
+@@ -876,7 +876,7 @@ openpic_get_irq(struct pt_regs *regs)
+ * This should move to irq.c eventually. -- paulus
+ */
+ if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) {
+- int cirq = openpic_cascade_fn(regs);
++ int cirq = openpic_cascade_fn();
+
+ /* Allow for the cascade being shared with other devices */
+ if (cirq != -1) {
+diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c
+index e1ff971..d585207 100644
+--- a/arch/ppc/syslib/open_pic2.c
++++ b/arch/ppc/syslib/open_pic2.c
+@@ -529,7 +529,7 @@ static void openpic2_end_irq(unsigned in
+ }
+
+ int
+-openpic2_get_irq(struct pt_regs *regs)
++openpic2_get_irq(void)
+ {
+ int irq = openpic2_irq();
+
+diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c
+index 1584c8b..607ebd1 100644
+--- a/arch/ppc/syslib/ppc403_pic.c
++++ b/arch/ppc/syslib/ppc403_pic.c
+@@ -42,7 +42,7 @@ static struct hw_interrupt_type ppc403_a
+ };
+
+ int
+-ppc403_pic_get_irq(struct pt_regs *regs)
++ppc403_pic_get_irq(void)
+ {
+ int irq;
+ unsigned long bits;
+diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
+index 745685d..ee0da4b 100644
+--- a/arch/ppc/syslib/ppc4xx_pic.c
++++ b/arch/ppc/syslib/ppc4xx_pic.c
+@@ -96,7 +96,7 @@ UIC_HANDLERS(1);
+ UIC_HANDLERS(2);
+ UIC_HANDLERS(3);
+
+-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
++static int ppc4xx_pic_get_irq(void)
+ {
+ u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
+ if (uic0 & UIC0_UIC1NC)
+@@ -125,7 +125,7 @@ UIC_HANDLERS(0);
+ UIC_HANDLERS(1);
+ UIC_HANDLERS(2);
+
+-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
++static int ppc4xx_pic_get_irq(void)
+ {
+ u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
+ if (uicb & UICB_UIC0NC)
+@@ -158,7 +158,7 @@ static void __init ppc4xx_pic_impl_init(
+ UIC_HANDLERS(0);
+ UIC_HANDLERS(1);
+
+-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
++static int ppc4xx_pic_get_irq(void)
+ {
+ u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
+ if (uic0 & UIC0_UIC1NC)
+@@ -179,7 +179,7 @@ static void __init ppc4xx_pic_impl_init(
+ #define ACK_UIC0_PARENT
+ UIC_HANDLERS(0);
+
+-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
++static int ppc4xx_pic_get_irq(void)
+ {
+ u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
+ return uic0 ? 32 - ffs(uic0) : -1;
+diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c
+index d9b471b..05b0e94 100644
+--- a/arch/ppc/syslib/ppc85xx_rio.c
++++ b/arch/ppc/syslib/ppc85xx_rio.c
+@@ -349,13 +349,12 @@ EXPORT_SYMBOL_GPL(rio_hw_add_outb_messag
+ * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+- * @regs: Register context
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+ static irqreturn_t
+-mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs *regs)
++mpc85xx_rio_tx_handler(int irq, void *dev_instance)
+ {
+ int osr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+@@ -517,13 +516,12 @@ void rio_close_outb_mbox(struct rio_mpor
+ * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+- * @regs: Register context
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+ static irqreturn_t
+-mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs)
++mpc85xx_rio_rx_handler(int irq, void *dev_instance)
+ {
+ int isr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+@@ -736,13 +734,12 @@ EXPORT_SYMBOL_GPL(rio_hw_get_inb_message
+ * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+- * @regs: Register context
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+ static irqreturn_t
+-mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *regs)
++mpc85xx_rio_dbell_handler(int irq, void *dev_instance)
+ {
+ int dsr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+diff --git a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c
+index d6c25fe..e8619c7 100644
+--- a/arch/ppc/syslib/ppc8xx_pic.c
++++ b/arch/ppc/syslib/ppc8xx_pic.c
+@@ -10,7 +10,7 @@
+ #include <asm/mpc8xx.h>
+ #include "ppc8xx_pic.h"
+
+-extern int cpm_get_irq(struct pt_regs *regs);
++extern int cpm_get_irq(void);
+
+ /* The 8xx internal interrupt controller. It is usually
+ * the only interrupt controller. Some boards, like the MBX and
+@@ -96,7 +96,7 @@ m8xx_get_irq(struct pt_regs *regs)
+ * get back SIU_LEVEL7. In this case, return -1
+ */
+ if (irq == CPM_INTERRUPT)
+- irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
++ irq = CPM_IRQ_OFFSET + cpm_get_irq();
+ #if defined(CONFIG_PCI)
+ else if (irq == ISA_BRIDGE_INT) {
+ int isa_irq;
+diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c
+index 39a93dc..6fd4cdb 100644
+--- a/arch/ppc/syslib/xilinx_pic.c
++++ b/arch/ppc/syslib/xilinx_pic.c
+@@ -86,7 +86,7 @@ static struct hw_interrupt_type xilinx_i
+ };
+
+ int
+-xilinx_pic_get_irq(struct pt_regs *regs)
++xilinx_pic_get_irq(void)
+ {
+ int irq;
+
+diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
+index f7e9298..d74a883 100644
+--- a/arch/ppc/xmon/start.c
++++ b/arch/ppc/xmon/start.c
+@@ -15,6 +15,7 @@
+ #include <asm/processor.h>
+ #include <asm/delay.h>
+ #include <asm/btext.h>
++#include <asm/ibm4xx.h>
+
+ static volatile unsigned char *sccc, *sccd;
+ unsigned int TXRDY, RXRDY, DLAB;
+@@ -57,23 +58,30 @@ static struct sysrq_key_op sysrq_xmon_op
+ void
+ xmon_map_scc(void)
+ {
+-#ifdef CONFIG_PPC_PREP
+- volatile unsigned char *base;
+-
+-#elif defined(CONFIG_GEMINI)
++#if defined(CONFIG_GEMINI)
+ /* should already be mapped by the kernel boot */
+- sccc = (volatile unsigned char *) 0xffeffb0d;
+ sccd = (volatile unsigned char *) 0xffeffb08;
+- TXRDY = 0x20;
+- RXRDY = 1;
+- DLAB = 0x80;
+ #elif defined(CONFIG_405GP)
+- sccc = (volatile unsigned char *)0xef600305;
+ sccd = (volatile unsigned char *)0xef600300;
++#elif defined(CONFIG_440EP)
++ sccd = (volatile unsigned char *) ioremap(PPC440EP_UART0_ADDR, 8);
++#elif defined(CONFIG_440SP)
++ sccd = (volatile unsigned char *) ioremap64(PPC440SP_UART0_ADDR, 8);
++#elif defined(CONFIG_440SPE)
++ sccd = (volatile unsigned char *) ioremap64(PPC440SPE_UART0_ADDR, 8);
++#elif defined(CONFIG_44x)
++ /* This is the default for 44x platforms. Any boards that have a
++ different UART address need to be put in cases before this or the
++ port will be mapped incorrectly */
++ sccd = (volatile unsigned char *) ioremap64(PPC440GP_UART0_ADDR, 8);
++#endif /* platform */
++
++#ifndef CONFIG_PPC_PREP
++ sccc = sccd + 5;
+ TXRDY = 0x20;
+ RXRDY = 1;
+ DLAB = 0x80;
+-#endif /* platform */
++#endif
+
+ register_sysrq_key('x', &sysrq_xmon_op);
+ }
+diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
+index 37d234f..b1a9174 100644
+--- a/arch/ppc/xmon/xmon.c
++++ b/arch/ppc/xmon/xmon.c
+@@ -153,6 +153,12 @@ static int xmon_trace[NR_CPUS];
+ #define SSTEP 1 /* stepping because of 's' command */
+ #define BRSTEP 2 /* stepping over breakpoint */
+
++#ifdef CONFIG_4xx
++#define MSR_SSTEP_ENABLE 0x200
++#else
++#define MSR_SSTEP_ENABLE 0x400
++#endif
++
+ static struct pt_regs *xmon_regs[NR_CPUS];
+
+ extern inline void sync(void)
+@@ -211,6 +217,14 @@ static void get_tb(unsigned *p)
+ p[1] = lo;
+ }
+
++static inline void xmon_enable_sstep(struct pt_regs *regs)
++{
++ regs->msr |= MSR_SSTEP_ENABLE;
++#ifdef CONFIG_4xx
++ mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
++#endif
++}
++
+ int xmon(struct pt_regs *excp)
+ {
+ struct pt_regs regs;
+@@ -254,10 +268,10 @@ int xmon(struct pt_regs *excp)
+ cmd = cmds(excp);
+ if (cmd == 's') {
+ xmon_trace[smp_processor_id()] = SSTEP;
+- excp->msr |= 0x400;
++ xmon_enable_sstep(excp);
+ } else if (at_breakpoint(excp->nip)) {
+ xmon_trace[smp_processor_id()] = BRSTEP;
+- excp->msr |= 0x400;
++ xmon_enable_sstep(excp);
+ } else {
+ xmon_trace[smp_processor_id()] = 0;
+ insert_bpts();
+@@ -298,7 +312,7 @@ xmon_bpt(struct pt_regs *regs)
+ remove_bpts();
+ excprint(regs);
+ xmon_trace[smp_processor_id()] = BRSTEP;
+- regs->msr |= 0x400;
++ xmon_enable_sstep(regs);
+ } else {
+ xmon(regs);
+ }
+@@ -385,7 +399,7 @@ insert_bpts(void)
+ }
+ store_inst((void *) bp->address);
+ }
+-#if !defined(CONFIG_8xx)
++#if ! (defined(CONFIG_8xx) || defined(CONFIG_4xx))
+ if (dabr.enabled)
+ set_dabr(dabr.address);
+ if (iabr.enabled)
+@@ -400,7 +414,7 @@ remove_bpts(void)
+ struct bpt *bp;
+ unsigned instr;
+
+-#if !defined(CONFIG_8xx)
++#if ! (defined(CONFIG_8xx) || defined(CONFIG_4xx))
+ set_dabr(0);
+ set_iabr(0);
+ #endif
+@@ -677,7 +691,7 @@ bpt_cmds(void)
+
+ cmd = inchar();
+ switch (cmd) {
+-#if !defined(CONFIG_8xx)
++#if ! (defined(CONFIG_8xx) || defined(CONFIG_4xx))
+ case 'd':
+ mode = 7;
+ cmd = inchar();
+@@ -792,7 +806,7 @@ backtrace(struct pt_regs *excp)
+ for (; sp != 0; sp = stack[0]) {
+ if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
+ break;
+- printf("[%.8lx] ", stack);
++ printf("[%.8lx] ", stack[0]);
+ xmon_print_symbol(stack[1], " ", "\n");
+ if (stack[1] == (unsigned) &ret_from_except
+ || stack[1] == (unsigned) &ret_from_except_full
+diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
+index 2f4f70c..245b81b 100644
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -30,6 +30,9 @@ config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
++config GENERIC_TIME
++ def_bool y
++
+ config GENERIC_BUST_SPINLOCK
+ bool
+
+@@ -51,6 +54,10 @@ config 64BIT
+ Select this option if you have a 64 bit IBM zSeries machine
+ and want to use the 64 bit addressing mode.
+
++config 32BIT
++ bool
++ default y if !64BIT
++
+ config SMP
+ bool "Symmetric multi-processing support"
+ ---help---
+@@ -149,6 +156,14 @@ config MARCH_Z990
+ This will be slightly faster but does not work on
+ older machines such as the z900.
+
++config MARCH_Z9_109
++ bool "IBM System z9"
++ help
++ Select this to enable optimizations for IBM System z9-109, IBM
++ System z9 Enterprise Class (z9 EC), and IBM System z9 Business
++ Class (z9 BC). The kernel will be slightly faster but will not
++ work on older machines such as the z990, z890, z900, and z800.
++
+ endchoice
+
+ config PACK_STACK
+@@ -460,8 +475,7 @@ config S390_HYPFS_FS
+ information in an s390 hypervisor environment.
+
+ config KEXEC
+- bool "kexec system call (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ bool "kexec system call"
+ 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
+@@ -487,8 +501,22 @@ source "drivers/net/Kconfig"
+
+ source "fs/Kconfig"
+
++menu "Instrumentation Support"
++
+ source "arch/s390/oprofile/Kconfig"
+
++config KPROBES
++ bool "Kprobes (EXPERIMENTAL)"
++ depends on EXPERIMENTAL && MODULES
++ help
++ Kprobes allows you to trap at almost any kernel address and
++ execute a callback function. register_kprobe() establishes
++ a probepoint and specifies the callback. Kprobes is useful
++ for kernel debugging, non-intrusive instrumentation and testing.
++ If in doubt, say "N".
++
++endmenu
++
+ source "arch/s390/Kconfig.debug"
+
+ source "security/Kconfig"
+diff --git a/arch/s390/Makefile b/arch/s390/Makefile
+index 74ef57d..5deb9f7 100644
+--- a/arch/s390/Makefile
++++ b/arch/s390/Makefile
+@@ -33,6 +33,7 @@ endif
+ cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5)
+ cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
+ cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
++cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
+
+ #
+ # Prevent tail-call optimizations, to get clearer backtraces:
+diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h
+index 71d65eb..0429481 100644
+--- a/arch/s390/appldata/appldata.h
++++ b/arch/s390/appldata/appldata.h
+@@ -29,22 +29,6 @@
+ #define CTL_APPLDATA_NET_SUM 2125
+ #define CTL_APPLDATA_PROC 2126
+
+-#ifndef CONFIG_64BIT
+-
+-#define APPLDATA_START_INTERVAL_REC 0x00 /* Function codes for */
+-#define APPLDATA_STOP_REC 0x01 /* DIAG 0xDC */
+-#define APPLDATA_GEN_EVENT_RECORD 0x02
+-#define APPLDATA_START_CONFIG_REC 0x03
+-
+-#else
+-
+-#define APPLDATA_START_INTERVAL_REC 0x80
+-#define APPLDATA_STOP_REC 0x81
+-#define APPLDATA_GEN_EVENT_RECORD 0x82
+-#define APPLDATA_START_CONFIG_REC 0x83
+-
+-#endif /* CONFIG_64BIT */
+-
+ #define P_INFO(x...) printk(KERN_INFO MY_PRINT_NAME " info: " x)
+ #define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x)
+ #define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x)
+diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
+index a0a94e0..af1e8fc 100644
+--- a/arch/s390/appldata/appldata_base.c
++++ b/arch/s390/appldata/appldata_base.c
+@@ -14,20 +14,20 @@
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/errno.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/smp.h>
+ #include <linux/interrupt.h>
+ #include <linux/proc_fs.h>
+-#include <linux/page-flags.h>
++#include <linux/mm.h>
+ #include <linux/swap.h>
+ #include <linux/pagemap.h>
+ #include <linux/sysctl.h>
+-#include <asm/timer.h>
+-//#include <linux/kernel_stat.h>
+ #include <linux/notifier.h>
+ #include <linux/cpu.h>
+ #include <linux/workqueue.h>
++#include <asm/appldata.h>
++#include <asm/timer.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/smp.h>
+
+ #include "appldata.h"
+
+@@ -39,34 +39,6 @@
+
+ #define TOD_MICRO 0x01000 /* nr. of TOD clock units
+ for 1 microsecond */
+-
+-/*
+- * Parameter list for DIAGNOSE X'DC'
+- */
+-#ifndef CONFIG_64BIT
+-struct appldata_parameter_list {
+- u16 diag; /* The DIAGNOSE code X'00DC' */
+- u8 function; /* The function code for the DIAGNOSE */
+- u8 parlist_length; /* Length of the parameter list */
+- u32 product_id_addr; /* Address of the 16-byte product ID */
+- u16 reserved;
+- u16 buffer_length; /* Length of the application data buffer */
+- u32 buffer_addr; /* Address of the application data buffer */
+-};
+-#else
+-struct appldata_parameter_list {
+- u16 diag;
+- u8 function;
+- u8 parlist_length;
+- u32 unused01;
+- u16 reserved;
+- u16 buffer_length;
+- u32 unused02;
+- u64 product_id_addr;
+- u64 buffer_addr;
+-};
+-#endif /* CONFIG_64BIT */
+-
+ /*
+ * /proc entries (sysctl)
+ */
+@@ -137,7 +109,7 @@ static LIST_HEAD(appldata_ops_list);
+ *
+ * schedule work and reschedule timer
+ */
+-static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
++static void appldata_timer_function(unsigned long data)
+ {
+ P_DEBUG(" -= Timer =-\n");
+ P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
+@@ -181,46 +153,17 @@ static void appldata_work_fn(void *data)
+ int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+ u16 length, char *mod_lvl)
+ {
+- unsigned long ry;
+- struct appldata_product_id {
+- char prod_nr[7]; /* product nr. */
+- char prod_fn[2]; /* product function */
+- char record_nr; /* record nr. */
+- char version_nr[2]; /* version */
+- char release_nr[2]; /* release */
+- char mod_lvl[2]; /* modification lvl. */
+- } appldata_product_id = {
+- /* all strings are EBCDIC, record_nr is byte */
++ struct appldata_product_id id = {
+ .prod_nr = {0xD3, 0xC9, 0xD5, 0xE4,
+- 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */
+- .prod_fn = {0xD5, 0xD3}, /* "NL" */
+- .record_nr = record_nr,
+- .version_nr = {0xF2, 0xF6}, /* "26" */
+- .release_nr = {0xF0, 0xF1}, /* "01" */
+- .mod_lvl = {mod_lvl[0], mod_lvl[1]},
+- };
+- struct appldata_parameter_list appldata_parameter_list = {
+- .diag = 0xDC,
+- .function = function,
+- .parlist_length =
+- sizeof(appldata_parameter_list),
+- .buffer_length = length,
+- .product_id_addr =
+- (unsigned long) &appldata_product_id,
+- .buffer_addr = virt_to_phys((void *) buffer)
++ 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */
++ .prod_fn = 0xD5D3, /* "NL" */
++ .version_nr = 0xF2F6, /* "26" */
++ .release_nr = 0xF0F1, /* "01" */
+ };
+
+- if (!MACHINE_IS_VM)
+- return -ENOSYS;
+- ry = -1;
+- asm volatile(
+- "diag %1,%0,0xDC\n\t"
+- : "=d" (ry)
+- : "d" (&appldata_parameter_list),
+- "m" (appldata_parameter_list),
+- "m" (appldata_product_id)
+- : "cc");
+- return (int) ry;
++ id.record_nr = record_nr;
++ id.mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1];
++ return appldata_asm(&id, function, (void *) buffer, length);
+ }
+ /************************ timer, work, DIAG <END> ****************************/
+
+@@ -367,6 +310,7 @@ appldata_interval_handler(ctl_table *ctl
+ if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) {
+ return -EFAULT;
+ }
++ interval = 0;
+ sscanf(buf, "%i", &interval);
+ if (interval <= 0) {
+ P_ERROR("Timer CPU interval has to be > 0!\n");
+diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
+index ab3b076..8aea369 100644
+--- a/arch/s390/appldata/appldata_mem.c
++++ b/arch/s390/appldata/appldata_mem.c
+@@ -117,8 +117,7 @@ static void appldata_get_mem_data(void *
+ mem_data->pgpgout = ev[PGPGOUT] >> 1;
+ mem_data->pswpin = ev[PSWPIN];
+ mem_data->pswpout = ev[PSWPOUT];
+- mem_data->pgalloc = ev[PGALLOC_HIGH] + ev[PGALLOC_NORMAL] +
+- ev[PGALLOC_DMA];
++ mem_data->pgalloc = ev[PGALLOC_NORMAL] + ev[PGALLOC_DMA];
+ mem_data->pgfault = ev[PGFAULT];
+ mem_data->pgmajfault = ev[PGMAJFAULT];
+
+diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
+index 161acc5..76a1552 100644
+--- a/arch/s390/appldata/appldata_os.c
++++ b/arch/s390/appldata/appldata_os.c
+@@ -16,6 +16,7 @@
+ #include <linux/kernel_stat.h>
+ #include <linux/netdevice.h>
+ #include <linux/sched.h>
++#include <asm/appldata.h>
+ #include <asm/smp.h>
+
+ #include "appldata.h"
+diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
+index 5713c7e..15c9eec 100644
+--- a/arch/s390/crypto/aes_s390.c
++++ b/arch/s390/crypto/aes_s390.c
+@@ -16,9 +16,9 @@
+ *
+ */
+
++#include <crypto/algapi.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+-#include <linux/crypto.h>
+ #include "crypt_s390.h"
+
+ #define AES_MIN_KEY_SIZE 16
+@@ -34,13 +34,16 @@ int has_aes_256 = 0;
+ struct s390_aes_ctx {
+ u8 iv[AES_BLOCK_SIZE];
+ u8 key[AES_MAX_KEY_SIZE];
++ long enc;
++ long dec;
+ int key_len;
+ };
+
+ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
+
+ switch (key_len) {
+ case 16:
+@@ -110,133 +113,206 @@ static void aes_decrypt(struct crypto_tf
+ }
+ }
+
+-static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
+-{
+- struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
+
+- /* only use complete blocks */
+- nbytes &= ~(AES_BLOCK_SIZE - 1);
++static struct crypto_alg aes_alg = {
++ .cra_name = "aes",
++ .cra_driver_name = "aes-s390",
++ .cra_priority = CRYPT_S390_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct s390_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 ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
++ unsigned int key_len)
++{
++ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+- switch (sctx->key_len) {
++ switch (key_len) {
+ case 16:
+- ret = crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ sctx->enc = KM_AES_128_ENCRYPT;
++ sctx->dec = KM_AES_128_DECRYPT;
+ break;
+ case 24:
+- ret = crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ sctx->enc = KM_AES_192_ENCRYPT;
++ sctx->dec = KM_AES_192_DECRYPT;
+ break;
+ case 32:
+- ret = crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ sctx->enc = KM_AES_256_ENCRYPT;
++ sctx->dec = KM_AES_256_DECRYPT;
+ break;
+ }
+- return nbytes;
++
++ return aes_set_key(tfm, in_key, key_len);
+ }
+
+-static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int ecb_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
++ struct blkcipher_walk *walk)
+ {
+- struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ int ret = blkcipher_walk_virt(desc, walk);
++ unsigned int nbytes;
+
+- /* only use complete blocks */
+- nbytes &= ~(AES_BLOCK_SIZE - 1);
++ while ((nbytes = walk->nbytes)) {
++ /* only use complete blocks */
++ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
++ u8 *out = walk->dst.virt.addr;
++ u8 *in = walk->src.virt.addr;
+
+- switch (sctx->key_len) {
+- case 16:
+- ret = crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+- break;
+- case 24:
+- ret = crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+- break;
+- case 32:
+- ret = crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+- break;
++ ret = crypt_s390_km(func, param, out, in, n);
++ BUG_ON((ret < 0) || (ret != n));
++
++ nbytes &= AES_BLOCK_SIZE - 1;
++ ret = blkcipher_walk_done(desc, walk, nbytes);
+ }
+- return nbytes;
++
++ return ret;
+ }
+
+-static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int ecb_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
+ {
+- struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- /* only use complete blocks */
+- nbytes &= ~(AES_BLOCK_SIZE - 1);
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
++}
+
+- memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE);
+- switch (sctx->key_len) {
++static int ecb_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
++}
++
++static struct crypto_alg ecb_aes_alg = {
++ .cra_name = "ecb(aes)",
++ .cra_driver_name = "ecb-aes-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct s390_aes_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .setkey = ecb_aes_set_key,
++ .encrypt = ecb_aes_encrypt,
++ .decrypt = ecb_aes_decrypt,
++ }
++ }
++};
++
++static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
++ unsigned int key_len)
++{
++ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++
++ switch (key_len) {
+ case 16:
+- ret = crypt_s390_kmc(KMC_AES_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ sctx->enc = KMC_AES_128_ENCRYPT;
++ sctx->dec = KMC_AES_128_DECRYPT;
+ break;
+ case 24:
+- ret = crypt_s390_kmc(KMC_AES_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ sctx->enc = KMC_AES_192_ENCRYPT;
++ sctx->dec = KMC_AES_192_DECRYPT;
+ break;
+ case 32:
+- ret = crypt_s390_kmc(KMC_AES_256_ENCRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ sctx->enc = KMC_AES_256_ENCRYPT;
++ sctx->dec = KMC_AES_256_DECRYPT;
+ break;
+ }
+- memcpy(desc->info, &sctx->iv, AES_BLOCK_SIZE);
+
+- return nbytes;
++ return aes_set_key(tfm, in_key, key_len);
+ }
+
+-static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
++ struct blkcipher_walk *walk)
+ {
+- struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ int ret = blkcipher_walk_virt(desc, walk);
++ unsigned int nbytes = walk->nbytes;
+
+- /* only use complete blocks */
+- nbytes &= ~(AES_BLOCK_SIZE - 1);
++ if (!nbytes)
++ goto out;
+
+- memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE);
+- switch (sctx->key_len) {
+- case 16:
+- ret = crypt_s390_kmc(KMC_AES_128_DECRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+- break;
+- case 24:
+- ret = crypt_s390_kmc(KMC_AES_192_DECRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+- break;
+- case 32:
+- ret = crypt_s390_kmc(KMC_AES_256_DECRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+- break;
+- }
+- return nbytes;
++ memcpy(param, walk->iv, AES_BLOCK_SIZE);
++ do {
++ /* only use complete blocks */
++ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
++ u8 *out = walk->dst.virt.addr;
++ u8 *in = walk->src.virt.addr;
++
++ ret = crypt_s390_kmc(func, param, out, in, n);
++ BUG_ON((ret < 0) || (ret != n));
++
++ nbytes &= AES_BLOCK_SIZE - 1;
++ ret = blkcipher_walk_done(desc, walk, nbytes);
++ } while ((nbytes = walk->nbytes));
++ memcpy(walk->iv, param, AES_BLOCK_SIZE);
++
++out:
++ return ret;
+ }
+
++static int cbc_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+-static struct crypto_alg aes_alg = {
+- .cra_name = "aes",
+- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
++}
++
++static int cbc_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
++}
++
++static struct crypto_alg cbc_aes_alg = {
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "cbc-aes-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_aes_ctx),
++ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+- .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
++ .cra_list = LIST_HEAD_INIT(cbc_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,
+- .cia_encrypt_ecb = aes_encrypt_ecb,
+- .cia_decrypt_ecb = aes_decrypt_ecb,
+- .cia_encrypt_cbc = aes_encrypt_cbc,
+- .cia_decrypt_cbc = aes_decrypt_cbc,
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = cbc_aes_set_key,
++ .encrypt = cbc_aes_encrypt,
++ .decrypt = cbc_aes_decrypt,
+ }
+ }
+ };
+@@ -256,13 +332,40 @@ static int __init aes_init(void)
+ return -ENOSYS;
+
+ ret = crypto_register_alg(&aes_alg);
+- if (ret != 0)
+- printk(KERN_INFO "crypt_s390: aes_s390 couldn't be loaded.\n");
++ if (ret != 0) {
++ printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
++ goto aes_err;
++ }
++
++ ret = crypto_register_alg(&ecb_aes_alg);
++ if (ret != 0) {
++ printk(KERN_INFO
++ "crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
++ goto ecb_aes_err;
++ }
++
++ ret = crypto_register_alg(&cbc_aes_alg);
++ if (ret != 0) {
++ printk(KERN_INFO
++ "crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
++ goto cbc_aes_err;
++ }
++
++out:
+ return ret;
++
++cbc_aes_err:
++ crypto_unregister_alg(&ecb_aes_alg);
++ecb_aes_err:
++ crypto_unregister_alg(&aes_alg);
++aes_err:
++ goto out;
+ }
+
+ static void __exit aes_fini(void)
+ {
++ crypto_unregister_alg(&cbc_aes_alg);
++ crypto_unregister_alg(&ecb_aes_alg);
+ crypto_unregister_alg(&aes_alg);
+ }
+
+diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
+index d1c259a..2b13708 100644
+--- a/arch/s390/crypto/crypt_s390.h
++++ b/arch/s390/crypto/crypt_s390.h
+@@ -20,6 +20,9 @@
+ #define CRYPT_S390_OP_MASK 0xFF00
+ #define CRYPT_S390_FUNC_MASK 0x00FF
+
++#define CRYPT_S390_PRIORITY 300
++#define CRYPT_S390_COMPOSITE_PRIORITY 400
++
+ /* s930 cryptographic operations */
+ enum crypt_s390_operations {
+ CRYPT_S390_KM = 0x0100,
+@@ -102,63 +105,6 @@ struct crypt_s390_query_status {
+ };
+
+ /*
+- * Standard fixup and ex_table sections for crypt_s390 inline functions.
+- * label 0: the s390 crypto operation
+- * label 1: just after 1 to catch illegal operation exception
+- * (unsupported model)
+- * label 6: the return point after fixup
+- * label 7: set error value if exception _in_ crypto operation
+- * label 8: set error value if illegal operation exception
+- * [ret] is the variable to receive the error code
+- * [ERR] is the error code value
+- */
+-#ifndef CONFIG_64BIT
+-#define __crypt_s390_fixup \
+- ".section .fixup,\"ax\" \n" \
+- "7: lhi %0,%h[e1] \n" \
+- " bras 1,9f \n" \
+- " .long 6b \n" \
+- "8: lhi %0,%h[e2] \n" \
+- " bras 1,9f \n" \
+- " .long 6b \n" \
+- "9: l 1,0(1) \n" \
+- " br 1 \n" \
+- ".previous \n" \
+- ".section __ex_table,\"a\" \n" \
+- " .align 4 \n" \
+- " .long 0b,7b \n" \
+- " .long 1b,8b \n" \
+- ".previous"
+-#else /* CONFIG_64BIT */
+-#define __crypt_s390_fixup \
+- ".section .fixup,\"ax\" \n" \
+- "7: lhi %0,%h[e1] \n" \
+- " jg 6b \n" \
+- "8: lhi %0,%h[e2] \n" \
+- " jg 6b \n" \
+- ".previous\n" \
+- ".section __ex_table,\"a\" \n" \
+- " .align 8 \n" \
+- " .quad 0b,7b \n" \
+- " .quad 1b,8b \n" \
+- ".previous"
+-#endif /* CONFIG_64BIT */
+-
+-/*
+- * Standard code for setting the result of s390 crypto instructions.
+- * %0: the register which will receive the result
+- * [result]: the register containing the result (e.g. second operand length
+- * to compute number of processed bytes].
+- */
+-#ifndef CONFIG_64BIT
+-#define __crypt_s390_set_result \
+- " lr %0,%[result] \n"
+-#else /* CONFIG_64BIT */
+-#define __crypt_s390_set_result \
+- " lgr %0,%[result] \n"
+-#endif
+-
+-/*
+ * Executes the KM (CIPHER MESSAGE) operation of the CPU.
+ * @param func: the function code passed to KM; see crypt_s390_km_func
+ * @param param: address of parameter block; see POP for details on each func
+@@ -173,28 +119,24 @@ crypt_s390_km(long func, void* param, u8
+ {
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void* __param asm("1") = param;
+- register u8* __dest asm("4") = dest;
+ register const u8* __src asm("2") = src;
+ register long __src_len asm("3") = src_len;
++ register u8* __dest asm("4") = dest;
+ int ret;
+
+- ret = 0;
+- __asm__ __volatile__ (
+- "0: .insn rre,0xB92E0000,%1,%2 \n" /* KM opcode */
++ asm volatile(
++ "0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+- __crypt_s390_set_result
+- "6: \n"
+- __crypt_s390_fixup
+- : "+d" (ret), "+a" (__dest), "+a" (__src),
+- [result] "+d" (__src_len)
+- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
+- "a" (__param)
+- : "cc", "memory"
+- );
+- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
+- ret = src_len - ret;
+- }
+- return ret;
++ " ahi %0,%h7\n"
++ "2: ahi %0,%h8\n"
++ "3:\n"
++ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
++ : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
++ : "d" (__func), "a" (__param), "0" (-EFAULT),
++ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
++ if (ret < 0)
++ return ret;
++ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+ }
+
+ /*
+@@ -212,28 +154,24 @@ crypt_s390_kmc(long func, void* param, u
+ {
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void* __param asm("1") = param;
+- register u8* __dest asm("4") = dest;
+ register const u8* __src asm("2") = src;
+ register long __src_len asm("3") = src_len;
++ register u8* __dest asm("4") = dest;
+ int ret;
+
+- ret = 0;
+- __asm__ __volatile__ (
+- "0: .insn rre,0xB92F0000,%1,%2 \n" /* KMC opcode */
++ asm volatile(
++ "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+- __crypt_s390_set_result
+- "6: \n"
+- __crypt_s390_fixup
+- : "+d" (ret), "+a" (__dest), "+a" (__src),
+- [result] "+d" (__src_len)
+- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
+- "a" (__param)
+- : "cc", "memory"
+- );
+- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
+- ret = src_len - ret;
+- }
+- return ret;
++ " ahi %0,%h7\n"
++ "2: ahi %0,%h8\n"
++ "3:\n"
++ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
++ : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
++ : "d" (__func), "a" (__param), "0" (-EFAULT),
++ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
++ if (ret < 0)
++ return ret;
++ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+ }
+
+ /*
+@@ -255,22 +193,19 @@ crypt_s390_kimd(long func, void* param,
+ register long __src_len asm("3") = src_len;
+ int ret;
+
+- ret = 0;
+- __asm__ __volatile__ (
+- "0: .insn rre,0xB93E0000,%1,%1 \n" /* KIMD opcode */
+- "1: brc 1,0b \n" /* handle partical completion */
+- __crypt_s390_set_result
+- "6: \n"
+- __crypt_s390_fixup
+- : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
+- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
+- "a" (__param)
+- : "cc", "memory"
+- );
+- if (ret >= 0 && (func & CRYPT_S390_FUNC_MASK)){
+- ret = src_len - ret;
+- }
+- return ret;
++ asm volatile(
++ "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
++ "1: brc 1,0b \n" /* handle partial completion */
++ " ahi %0,%h6\n"
++ "2: ahi %0,%h7\n"
++ "3:\n"
++ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
++ : "=d" (ret), "+a" (__src), "+d" (__src_len)
++ : "d" (__func), "a" (__param), "0" (-EFAULT),
++ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
++ if (ret < 0)
++ return ret;
++ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+ }
+
+ /*
+@@ -291,22 +226,19 @@ crypt_s390_klmd(long func, void* param,
+ register long __src_len asm("3") = src_len;
+ int ret;
+
+- ret = 0;
+- __asm__ __volatile__ (
+- "0: .insn rre,0xB93F0000,%1,%1 \n" /* KLMD opcode */
+- "1: brc 1,0b \n" /* handle partical completion */
+- __crypt_s390_set_result
+- "6: \n"
+- __crypt_s390_fixup
+- : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
+- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
+- "a" (__param)
+- : "cc", "memory"
+- );
+- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
+- ret = src_len - ret;
+- }
+- return ret;
++ asm volatile(
++ "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
++ "1: brc 1,0b \n" /* handle partial completion */
++ " ahi %0,%h6\n"
++ "2: ahi %0,%h7\n"
++ "3:\n"
++ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
++ : "=d" (ret), "+a" (__src), "+d" (__src_len)
++ : "d" (__func), "a" (__param), "0" (-EFAULT),
++ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
++ if (ret < 0)
++ return ret;
++ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+ }
+
+ /*
+@@ -328,22 +260,19 @@ crypt_s390_kmac(long func, void* param,
+ register long __src_len asm("3") = src_len;
+ int ret;
+
+- ret = 0;
+- __asm__ __volatile__ (
+- "0: .insn rre,0xB91E0000,%5,%5 \n" /* KMAC opcode */
+- "1: brc 1,0b \n" /* handle partical completion */
+- __crypt_s390_set_result
+- "6: \n"
+- __crypt_s390_fixup
+- : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
+- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
+- "a" (__param)
+- : "cc", "memory"
+- );
+- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
+- ret = src_len - ret;
+- }
+- return ret;
++ asm volatile(
++ "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
++ "1: brc 1,0b \n" /* handle partial completion */
++ " ahi %0,%h6\n"
++ "2: ahi %0,%h7\n"
++ "3:\n"
++ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
++ : "=d" (ret), "+a" (__src), "+d" (__src_len)
++ : "d" (__func), "a" (__param), "0" (-EFAULT),
++ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
++ if (ret < 0)
++ return ret;
++ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+ }
+
+ /**
+diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
+index b3f7496..2aba048 100644
+--- a/arch/s390/crypto/des_s390.c
++++ b/arch/s390/crypto/des_s390.c
+@@ -13,9 +13,10 @@
+ * (at your option) any later version.
+ *
+ */
++
++#include <crypto/algapi.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+-#include <linux/crypto.h>
+
+ #include "crypt_s390.h"
+ #include "crypto_des.h"
+@@ -45,9 +46,10 @@ struct crypt_s390_des3_192_ctx {
+ };
+
+ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
+ int ret;
+
+ /* test if key is valid (not a weak key) */
+@@ -71,85 +73,159 @@ static void des_decrypt(struct crypto_tf
+ crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+ }
+
+-static unsigned int des_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static struct crypto_alg des_alg = {
++ .cra_name = "des",
++ .cra_driver_name = "des-s390",
++ .cra_priority = CRYPT_S390_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(des_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = DES_KEY_SIZE,
++ .cia_max_keysize = DES_KEY_SIZE,
++ .cia_setkey = des_setkey,
++ .cia_encrypt = des_encrypt,
++ .cia_decrypt = des_decrypt,
++ }
++ }
++};
++
++static int ecb_desall_crypt(struct blkcipher_desc *desc, long func,
++ void *param, struct blkcipher_walk *walk)
+ {
+- struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ int ret = blkcipher_walk_virt(desc, walk);
++ unsigned int nbytes;
++
++ while ((nbytes = walk->nbytes)) {
++ /* only use complete blocks */
++ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
++ u8 *out = walk->dst.virt.addr;
++ u8 *in = walk->src.virt.addr;
+
+- /* only use complete blocks */
+- nbytes &= ~(DES_BLOCK_SIZE - 1);
+- ret = crypt_s390_km(KM_DEA_ENCRYPT, sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ ret = crypt_s390_km(func, param, out, in, n);
++ BUG_ON((ret < 0) || (ret != n));
+
+- return nbytes;
++ nbytes &= DES_BLOCK_SIZE - 1;
++ ret = blkcipher_walk_done(desc, walk, nbytes);
++ }
++
++ return ret;
+ }
+
+-static unsigned int des_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int cbc_desall_crypt(struct blkcipher_desc *desc, long func,
++ void *param, struct blkcipher_walk *walk)
+ {
+- struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ int ret = blkcipher_walk_virt(desc, walk);
++ unsigned int nbytes = walk->nbytes;
++
++ if (!nbytes)
++ goto out;
++
++ memcpy(param, walk->iv, DES_BLOCK_SIZE);
++ do {
++ /* only use complete blocks */
++ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
++ u8 *out = walk->dst.virt.addr;
++ u8 *in = walk->src.virt.addr;
+
+- /* only use complete blocks */
+- nbytes &= ~(DES_BLOCK_SIZE - 1);
+- ret = crypt_s390_km(KM_DEA_DECRYPT, sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ ret = crypt_s390_kmc(func, param, out, in, n);
++ BUG_ON((ret < 0) || (ret != n));
+
+- return nbytes;
++ nbytes &= DES_BLOCK_SIZE - 1;
++ ret = blkcipher_walk_done(desc, walk, nbytes);
++ } while ((nbytes = walk->nbytes));
++ memcpy(walk->iv, param, DES_BLOCK_SIZE);
++
++out:
++ return ret;
+ }
+
+-static unsigned int des_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int ecb_des_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
+ {
+- struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- /* only use complete blocks */
+- nbytes &= ~(DES_BLOCK_SIZE - 1);
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, sctx->key, &walk);
++}
+
+- memcpy(sctx->iv, desc->info, DES_BLOCK_SIZE);
+- ret = crypt_s390_kmc(KMC_DEA_ENCRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++static int ecb_des_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- memcpy(desc->info, sctx->iv, DES_BLOCK_SIZE);
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_desall_crypt(desc, KM_DEA_DECRYPT, sctx->key, &walk);
+ }
+
+-static unsigned int des_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static struct crypto_alg ecb_des_alg = {
++ .cra_name = "ecb(des)",
++ .cra_driver_name = "ecb-des-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .setkey = des_setkey,
++ .encrypt = ecb_des_encrypt,
++ .decrypt = ecb_des_decrypt,
++ }
++ }
++};
++
++static int cbc_des_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
+ {
+- struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- /* only use complete blocks */
+- nbytes &= ~(DES_BLOCK_SIZE - 1);
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, sctx->iv, &walk);
++}
+
+- memcpy(&sctx->iv, desc->info, DES_BLOCK_SIZE);
+- ret = crypt_s390_kmc(KMC_DEA_DECRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++static int cbc_des_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, sctx->iv, &walk);
+ }
+
+-static struct crypto_alg des_alg = {
+- .cra_name = "des",
+- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++static struct crypto_alg cbc_des_alg = {
++ .cra_name = "cbc(des)",
++ .cra_driver_name = "cbc-des-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
++ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+- .cra_list = LIST_HEAD_INIT(des_alg.cra_list),
++ .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list),
+ .cra_u = {
+- .cipher = {
+- .cia_min_keysize = DES_KEY_SIZE,
+- .cia_max_keysize = DES_KEY_SIZE,
+- .cia_setkey = des_setkey,
+- .cia_encrypt = des_encrypt,
+- .cia_decrypt = des_decrypt,
+- .cia_encrypt_ecb = des_encrypt_ecb,
+- .cia_decrypt_ecb = des_decrypt_ecb,
+- .cia_encrypt_cbc = des_encrypt_cbc,
+- .cia_decrypt_cbc = des_decrypt_cbc,
++ .blkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = des_setkey,
++ .encrypt = cbc_des_encrypt,
++ .decrypt = cbc_des_decrypt,
+ }
+ }
+ };
+@@ -167,11 +243,12 @@ static struct crypto_alg des_alg = {
+ *
+ */
+ static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ int i, ret;
+ struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
+- const u8* temp_key = key;
++ const u8 *temp_key = key;
++ u32 *flags = &tfm->crt_flags;
+
+ if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+@@ -202,89 +279,111 @@ static void des3_128_decrypt(struct cryp
+ DES3_128_BLOCK_SIZE);
+ }
+
+-static unsigned int des3_128_encrypt_ecb(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
+-{
+- struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++static struct crypto_alg des3_128_alg = {
++ .cra_name = "des3_ede128",
++ .cra_driver_name = "des3_ede128-s390",
++ .cra_priority = CRYPT_S390_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = DES3_128_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = DES3_128_KEY_SIZE,
++ .cia_max_keysize = DES3_128_KEY_SIZE,
++ .cia_setkey = des3_128_setkey,
++ .cia_encrypt = des3_128_encrypt,
++ .cia_decrypt = des3_128_decrypt,
++ }
++ }
++};
+
+- /* only use complete blocks */
+- nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+- ret = crypt_s390_km(KM_TDEA_128_ENCRYPT, sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++static int ecb_des3_128_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
++{
++ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_desall_crypt(desc, KM_TDEA_128_ENCRYPT, sctx->key, &walk);
+ }
+
+-static unsigned int des3_128_decrypt_ecb(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
++static int ecb_des3_128_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
+ {
+- struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- /* only use complete blocks */
+- nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+- ret = crypt_s390_km(KM_TDEA_128_DECRYPT, sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+-
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_desall_crypt(desc, KM_TDEA_128_DECRYPT, sctx->key, &walk);
+ }
+
+-static unsigned int des3_128_encrypt_cbc(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
+-{
+- struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
+-
+- /* only use complete blocks */
+- nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
++static struct crypto_alg ecb_des3_128_alg = {
++ .cra_name = "ecb(des3_ede128)",
++ .cra_driver_name = "ecb-des3_ede128-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES3_128_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(
++ ecb_des3_128_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES3_128_KEY_SIZE,
++ .max_keysize = DES3_128_KEY_SIZE,
++ .setkey = des3_128_setkey,
++ .encrypt = ecb_des3_128_encrypt,
++ .decrypt = ecb_des3_128_decrypt,
++ }
++ }
++};
+
+- memcpy(sctx->iv, desc->info, DES3_128_BLOCK_SIZE);
+- ret = crypt_s390_kmc(KMC_TDEA_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++static int cbc_des3_128_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
++{
++ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- memcpy(desc->info, sctx->iv, DES3_128_BLOCK_SIZE);
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_desall_crypt(desc, KMC_TDEA_128_ENCRYPT, sctx->iv, &walk);
+ }
+
+-static unsigned int des3_128_decrypt_cbc(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
++static int cbc_des3_128_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
+ {
+- struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
+-
+- /* only use complete blocks */
+- nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+-
+- memcpy(&sctx->iv, desc->info, DES3_128_BLOCK_SIZE);
+- ret = crypt_s390_kmc(KMC_TDEA_128_DECRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_desall_crypt(desc, KMC_TDEA_128_DECRYPT, sctx->iv, &walk);
+ }
+
+-static struct crypto_alg des3_128_alg = {
+- .cra_name = "des3_ede128",
+- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++static struct crypto_alg cbc_des3_128_alg = {
++ .cra_name = "cbc(des3_ede128)",
++ .cra_driver_name = "cbc-des3_ede128-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES3_128_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
++ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+- .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list),
++ .cra_list = LIST_HEAD_INIT(
++ cbc_des3_128_alg.cra_list),
+ .cra_u = {
+- .cipher = {
+- .cia_min_keysize = DES3_128_KEY_SIZE,
+- .cia_max_keysize = DES3_128_KEY_SIZE,
+- .cia_setkey = des3_128_setkey,
+- .cia_encrypt = des3_128_encrypt,
+- .cia_decrypt = des3_128_decrypt,
+- .cia_encrypt_ecb = des3_128_encrypt_ecb,
+- .cia_decrypt_ecb = des3_128_decrypt_ecb,
+- .cia_encrypt_cbc = des3_128_encrypt_cbc,
+- .cia_decrypt_cbc = des3_128_decrypt_cbc,
++ .blkcipher = {
++ .min_keysize = DES3_128_KEY_SIZE,
++ .max_keysize = DES3_128_KEY_SIZE,
++ .ivsize = DES3_128_BLOCK_SIZE,
++ .setkey = des3_128_setkey,
++ .encrypt = cbc_des3_128_encrypt,
++ .decrypt = cbc_des3_128_decrypt,
+ }
+ }
+ };
+@@ -303,11 +402,12 @@ static struct crypto_alg des3_128_alg =
+ *
+ */
+ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ int i, ret;
+ struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+- const u8* temp_key = key;
++ const u8 *temp_key = key;
++ u32 *flags = &tfm->crt_flags;
+
+ if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
+ memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
+@@ -341,89 +441,111 @@ static void des3_192_decrypt(struct cryp
+ DES3_192_BLOCK_SIZE);
+ }
+
+-static unsigned int des3_192_encrypt_ecb(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
+-{
+- struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++static struct crypto_alg des3_192_alg = {
++ .cra_name = "des3_ede",
++ .cra_driver_name = "des3_ede-s390",
++ .cra_priority = CRYPT_S390_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = DES3_192_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = DES3_192_KEY_SIZE,
++ .cia_max_keysize = DES3_192_KEY_SIZE,
++ .cia_setkey = des3_192_setkey,
++ .cia_encrypt = des3_192_encrypt,
++ .cia_decrypt = des3_192_decrypt,
++ }
++ }
++};
+
+- /* only use complete blocks */
+- nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+- ret = crypt_s390_km(KM_TDEA_192_ENCRYPT, sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++static int ecb_des3_192_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
++{
++ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, sctx->key, &walk);
+ }
+
+-static unsigned int des3_192_decrypt_ecb(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
++static int ecb_des3_192_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
+ {
+- struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
+-
+- /* only use complete blocks */
+- nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+- ret = crypt_s390_km(KM_TDEA_192_DECRYPT, sctx->key, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, sctx->key, &walk);
+ }
+
+-static unsigned int des3_192_encrypt_cbc(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
+-{
+- struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
+-
+- /* only use complete blocks */
+- nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
++static struct crypto_alg ecb_des3_192_alg = {
++ .cra_name = "ecb(des3_ede)",
++ .cra_driver_name = "ecb-des3_ede-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES3_192_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(
++ ecb_des3_192_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES3_192_KEY_SIZE,
++ .max_keysize = DES3_192_KEY_SIZE,
++ .setkey = des3_192_setkey,
++ .encrypt = ecb_des3_192_encrypt,
++ .decrypt = ecb_des3_192_decrypt,
++ }
++ }
++};
+
+- memcpy(sctx->iv, desc->info, DES3_192_BLOCK_SIZE);
+- ret = crypt_s390_kmc(KMC_TDEA_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
++static int cbc_des3_192_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
++{
++ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- memcpy(desc->info, sctx->iv, DES3_192_BLOCK_SIZE);
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, sctx->iv, &walk);
+ }
+
+-static unsigned int des3_192_decrypt_cbc(const struct cipher_desc *desc,
+- u8 *out, const u8 *in,
+- unsigned int nbytes)
++static int cbc_des3_192_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes)
+ {
+- struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+- int ret;
++ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
+
+- /* only use complete blocks */
+- nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+-
+- memcpy(&sctx->iv, desc->info, DES3_192_BLOCK_SIZE);
+- ret = crypt_s390_kmc(KMC_TDEA_192_DECRYPT, &sctx->iv, out, in, nbytes);
+- BUG_ON((ret < 0) || (ret != nbytes));
+-
+- return nbytes;
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, sctx->iv, &walk);
+ }
+
+-static struct crypto_alg des3_192_alg = {
+- .cra_name = "des3_ede",
+- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++static struct crypto_alg cbc_des3_192_alg = {
++ .cra_name = "cbc(des3_ede)",
++ .cra_driver_name = "cbc-des3_ede-s390",
++ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
++ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+- .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
++ .cra_list = LIST_HEAD_INIT(
++ cbc_des3_192_alg.cra_list),
+ .cra_u = {
+- .cipher = {
+- .cia_min_keysize = DES3_192_KEY_SIZE,
+- .cia_max_keysize = DES3_192_KEY_SIZE,
+- .cia_setkey = des3_192_setkey,
+- .cia_encrypt = des3_192_encrypt,
+- .cia_decrypt = des3_192_decrypt,
+- .cia_encrypt_ecb = des3_192_encrypt_ecb,
+- .cia_decrypt_ecb = des3_192_decrypt_ecb,
+- .cia_encrypt_cbc = des3_192_encrypt_cbc,
+- .cia_decrypt_cbc = des3_192_decrypt_cbc,
++ .blkcipher = {
++ .min_keysize = DES3_192_KEY_SIZE,
++ .max_keysize = DES3_192_KEY_SIZE,
++ .ivsize = DES3_192_BLOCK_SIZE,
++ .setkey = des3_192_setkey,
++ .encrypt = cbc_des3_192_encrypt,
++ .decrypt = cbc_des3_192_decrypt,
+ }
+ }
+ };
+@@ -437,22 +559,69 @@ static int init(void)
+ !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
+ return -ENOSYS;
+
+- ret |= (crypto_register_alg(&des_alg) == 0) ? 0:1;
+- ret |= (crypto_register_alg(&des3_128_alg) == 0) ? 0:2;
+- ret |= (crypto_register_alg(&des3_192_alg) == 0) ? 0:4;
+- if (ret) {
+- crypto_unregister_alg(&des3_192_alg);
+- crypto_unregister_alg(&des3_128_alg);
+- crypto_unregister_alg(&des_alg);
+- return -EEXIST;
+- }
+- return 0;
++ ret = crypto_register_alg(&des_alg);
++ if (ret)
++ goto des_err;
++ ret = crypto_register_alg(&ecb_des_alg);
++ if (ret)
++ goto ecb_des_err;
++ ret = crypto_register_alg(&cbc_des_alg);
++ if (ret)
++ goto cbc_des_err;
++
++ ret = crypto_register_alg(&des3_128_alg);
++ if (ret)
++ goto des3_128_err;
++ ret = crypto_register_alg(&ecb_des3_128_alg);
++ if (ret)
++ goto ecb_des3_128_err;
++ ret = crypto_register_alg(&cbc_des3_128_alg);
++ if (ret)
++ goto cbc_des3_128_err;
++
++ ret = crypto_register_alg(&des3_192_alg);
++ if (ret)
++ goto des3_192_err;
++ ret = crypto_register_alg(&ecb_des3_192_alg);
++ if (ret)
++ goto ecb_des3_192_err;
++ ret = crypto_register_alg(&cbc_des3_192_alg);
++ if (ret)
++ goto cbc_des3_192_err;
++
++out:
++ return ret;
++
++cbc_des3_192_err:
++ crypto_unregister_alg(&ecb_des3_192_alg);
++ecb_des3_192_err:
++ crypto_unregister_alg(&des3_192_alg);
++des3_192_err:
++ crypto_unregister_alg(&cbc_des3_128_alg);
++cbc_des3_128_err:
++ crypto_unregister_alg(&ecb_des3_128_alg);
++ecb_des3_128_err:
++ crypto_unregister_alg(&des3_128_alg);
++des3_128_err:
++ crypto_unregister_alg(&cbc_des_alg);
++cbc_des_err:
++ crypto_unregister_alg(&ecb_des_alg);
++ecb_des_err:
++ crypto_unregister_alg(&des_alg);
++des_err:
++ goto out;
+ }
+
+ static void __exit fini(void)
+ {
++ crypto_unregister_alg(&cbc_des3_192_alg);
++ crypto_unregister_alg(&ecb_des3_192_alg);
+ crypto_unregister_alg(&des3_192_alg);
++ crypto_unregister_alg(&cbc_des3_128_alg);
++ crypto_unregister_alg(&ecb_des3_128_alg);
+ crypto_unregister_alg(&des3_128_alg);
++ crypto_unregister_alg(&cbc_des_alg);
++ crypto_unregister_alg(&ecb_des_alg);
+ crypto_unregister_alg(&des_alg);
+ }
+
+diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
+index 9d34a35..49ca869 100644
+--- a/arch/s390/crypto/sha1_s390.c
++++ b/arch/s390/crypto/sha1_s390.c
+@@ -126,6 +126,8 @@ static void sha1_final(struct crypto_tfm
+
+ static struct crypto_alg alg = {
+ .cra_name = "sha1",
++ .cra_driver_name = "sha1-s390",
++ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx),
+diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
+index f573df3..8e4e675 100644
+--- a/arch/s390/crypto/sha256_s390.c
++++ b/arch/s390/crypto/sha256_s390.c
+@@ -127,6 +127,8 @@ static void sha256_final(struct crypto_t
+
+ static struct crypto_alg alg = {
+ .cra_name = "sha256",
++ .cra_driver_name = "sha256-s390",
++ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_sha256_ctx),
+diff --git a/arch/s390/defconfig b/arch/s390/defconfig
+index f1d4591..7cd51e7 100644
+--- a/arch/s390/defconfig
++++ b/arch/s390/defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc2
+-# Thu Jul 27 13:51:07 2006
++# Linux kernel version: 2.6.19-rc2
++# Wed Oct 18 17:11:10 2006
+ #
+ CONFIG_MMU=y
+ CONFIG_LOCKDEP_SUPPORT=y
+@@ -9,6 +9,7 @@ CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
+ CONFIG_S390=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+@@ -26,10 +27,11 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
++# CONFIG_UTS_NS is not set
+ CONFIG_AUDIT=y
+ # CONFIG_AUDITSYSCALL is not set
+ CONFIG_IKCONFIG=y
+@@ -38,7 +40,9 @@ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -47,12 +51,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -71,6 +75,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+@@ -100,6 +105,7 @@ CONFIG_HOTPLUG_CPU=y
+ CONFIG_DEFAULT_MIGRATION_COST=1000000
+ CONFIG_COMPAT=y
+ CONFIG_SYSVIPC_COMPAT=y
++CONFIG_AUDIT_ARCH=y
+
+ #
+ # Code generation options
+@@ -107,6 +113,7 @@ CONFIG_SYSVIPC_COMPAT=y
+ # CONFIG_MARCH_G5 is not set
+ CONFIG_MARCH_Z900=y
+ # CONFIG_MARCH_Z990 is not set
++# CONFIG_MARCH_Z9_109 is not set
+ CONFIG_PACK_STACK=y
+ # CONFIG_SMALL_STACK is not set
+ CONFIG_CHECK_STACK=y
+@@ -165,6 +172,7 @@ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ # CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ CONFIG_NET_KEY=y
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -183,21 +191,29 @@ CONFIG_IP_FIB_HASH=y
+ # CONFIG_INET_TUNNEL is not set
+ CONFIG_INET_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ CONFIG_IPV6=y
+ # CONFIG_IPV6_PRIVACY is not set
+ # CONFIG_IPV6_ROUTER_PREF is not set
+ # CONFIG_INET6_AH is not set
+ # CONFIG_INET6_ESP is not set
+ # CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+ CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET6_XFRM_MODE_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_BEET=y
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
+ # CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
+ # CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+@@ -224,7 +240,6 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=y
+ # 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
+
+@@ -301,6 +316,7 @@ CONFIG_SYS_HYPERVISOR=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -322,18 +338,18 @@ CONFIG_SCSI_CONSTANTS=y
+ CONFIG_SCSI_LOGGING=y
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ CONFIG_SCSI_FC_ATTRS=y
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+ # CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+ #
+ # CONFIG_ISCSI_TCP is not set
+-# CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_DEBUG is not set
+ CONFIG_ZFCP=y
+ CONFIG_CCW=y
+@@ -378,6 +394,7 @@ CONFIG_MD_RAID1=m
+ CONFIG_MD_MULTIPATH=m
+ # CONFIG_MD_FAULTY is not set
+ CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
+ CONFIG_DM_CRYPT=y
+ CONFIG_DM_SNAPSHOT=y
+ CONFIG_DM_MIRROR=y
+@@ -428,6 +445,7 @@ CONFIG_S390_TAPE_34XX=m
+ # CONFIG_VMLOGRDR is not set
+ # CONFIG_VMCP is not set
+ # CONFIG_MONREADER is not set
++CONFIG_MONWRITER=m
+
+ #
+ # Cryptographic devices
+@@ -486,14 +504,12 @@ CONFIG_IUCV=m
+ # CONFIG_NETIUCV is not set
+ # CONFIG_SMSGIUCV is not set
+ # CONFIG_CLAW is not set
+-# CONFIG_MPC is not set
+ CONFIG_QETH=y
+
+ #
+ # Gigabit Ethernet default settings
+ #
+ # CONFIG_QETH_IPV6 is not set
+-# CONFIG_QETH_PERF_STATS is not set
+ CONFIG_CCWGROUP=y
+ # CONFIG_PPP is not set
+ # CONFIG_SLIP is not set
+@@ -512,13 +528,15 @@ 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_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FS_POSIX_ACL=y
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -548,8 +566,10 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+@@ -597,6 +617,7 @@ CONFIG_SUNRPC=y
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+ # CONFIG_9P_FS is not set
++CONFIG_GENERIC_ACL=y
+
+ #
+ # Partition Types
+@@ -628,8 +649,11 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Instrumentation Support
+ #
++
++#
++# Profiling support
++#
+ # CONFIG_PROFILING is not set
+-CONFIG_STATISTICS=y
+ CONFIG_KPROBES=y
+
+ #
+@@ -637,11 +661,11 @@ CONFIG_KPROBES=y
+ #
+ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=17
+-# CONFIG_DETECT_SOFTLOCKUP is not set
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+ CONFIG_DEBUG_PREEMPT=y
+@@ -658,10 +682,13 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
+ # CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ # CONFIG_FRAME_POINTER is not set
+ # CONFIG_UNWIND_INFO is not set
+ CONFIG_FORCED_INLINING=y
++CONFIG_HEADERS_CHECK=y
+ # CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
+
+ #
+ # Security options
+@@ -673,6 +700,9 @@ CONFIG_FORCED_INLINING=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
+ # CONFIG_CRYPTO_HMAC is not set
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -684,6 +714,8 @@ CONFIG_CRYPTO=y
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
+ # CONFIG_CRYPTO_DES is not set
+ # CONFIG_CRYPTO_DES_S390 is not set
+ # CONFIG_CRYPTO_BLOWFISH is not set
+diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
+index ea5567b..f3dbd91 100644
+--- a/arch/s390/hypfs/hypfs.h
++++ b/arch/s390/hypfs/hypfs.h
+@@ -1,5 +1,5 @@
+ /*
+- * fs/hypfs/hypfs.h
++ * arch/s390/hypfs/hypfs.h
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
+index 1785bce..443fa37 100644
+--- a/arch/s390/hypfs/hypfs_diag.c
++++ b/arch/s390/hypfs/hypfs_diag.c
+@@ -1,5 +1,5 @@
+ /*
+- * fs/hypfs/hypfs_diag.c
++ * arch/s390/hypfs/hypfs_diag.c
+ * Hypervisor filesystem for Linux on s390. Diag 204 and 224
+ * implementation.
+ *
+@@ -333,22 +333,14 @@ static int diag204(unsigned long subcode
+ register unsigned long _subcode asm("0") = subcode;
+ register unsigned long _size asm("1") = size;
+
+- asm volatile (" diag %2,%0,0x204\n"
+- "0: \n" ".section __ex_table,\"a\"\n"
+-#ifndef __s390x__
+- " .align 4\n"
+- " .long 0b,0b\n"
+-#else
+- " .align 8\n"
+- " .quad 0b,0b\n"
+-#endif
+- ".previous":"+d" (_subcode), "+d"(_size)
+- :"d"(addr)
+- :"memory");
++ asm volatile(
++ " diag %2,%0,0x204\n"
++ "0:\n"
++ EX_TABLE(0b,0b)
++ : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
+ if (_subcode)
+ return -1;
+- else
+- return _size;
++ return _size;
+ }
+
+ /*
+@@ -403,7 +395,8 @@ static void *diag204_get_buffer(enum dia
+ *pages = 1;
+ return diag204_alloc_rbuf();
+ } else {/* INFO_EXT */
+- *pages = diag204(SUBC_RSI | INFO_EXT, 0, NULL);
++ *pages = diag204((unsigned long)SUBC_RSI |
++ (unsigned long)INFO_EXT, 0, NULL);
+ if (*pages <= 0)
+ return ERR_PTR(-ENOSYS);
+ else
+@@ -432,12 +425,14 @@ static int diag204_probe(void)
+
+ buf = diag204_get_buffer(INFO_EXT, &pages);
+ if (!IS_ERR(buf)) {
+- if (diag204(SUBC_STIB7 | INFO_EXT, pages, buf) >= 0) {
++ if (diag204((unsigned long)SUBC_STIB7 |
++ (unsigned long)INFO_EXT, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB7;
+ diag204_info_type = INFO_EXT;
+ goto out;
+ }
+- if (diag204(SUBC_STIB6 | INFO_EXT, pages, buf) >= 0) {
++ if (diag204((unsigned long)SUBC_STIB6 |
++ (unsigned long)INFO_EXT, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB7;
+ diag204_info_type = INFO_EXT;
+ goto out;
+@@ -452,7 +447,8 @@ static int diag204_probe(void)
+ rc = PTR_ERR(buf);
+ goto fail_alloc;
+ }
+- if (diag204(SUBC_STIB4 | INFO_SIMPLE, pages, buf) >= 0) {
++ if (diag204((unsigned long)SUBC_STIB4 |
++ (unsigned long)INFO_SIMPLE, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB4;
+ diag204_info_type = INFO_SIMPLE;
+ goto out;
+@@ -476,7 +472,8 @@ static void *diag204_store(void)
+ buf = diag204_get_buffer(diag204_info_type, &pages);
+ if (IS_ERR(buf))
+ goto out;
+- if (diag204(diag204_store_sc | diag204_info_type, pages, buf) < 0)
++ if (diag204((unsigned long)diag204_store_sc |
++ (unsigned long)diag204_info_type, pages, buf) < 0)
+ return ERR_PTR(-ENOSYS);
+ out:
+ return buf;
+@@ -486,8 +483,7 @@ out:
+
+ static void diag224(void *ptr)
+ {
+- asm volatile(" diag %0,%1,0x224\n"
+- : :"d" (0), "d"(ptr) : "memory");
++ asm volatile("diag %0,%1,0x224" : :"d" (0), "d"(ptr) : "memory");
+ }
+
+ static int diag224_get_name_table(void)
+@@ -531,7 +527,7 @@ __init int hypfs_diag_init(void)
+ return rc;
+ }
+
+-__exit void hypfs_diag_exit(void)
++void hypfs_diag_exit(void)
+ {
+ diag224_delete_name_table();
+ diag204_free_buffer();
+diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h
+index 793dea6..256b384 100644
+--- a/arch/s390/hypfs/hypfs_diag.h
++++ b/arch/s390/hypfs/hypfs_diag.h
+@@ -1,5 +1,5 @@
+ /*
+- * fs/hypfs/hypfs_diag.h
++ * arch/s390/hypfs_diag.h
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
+index 18c0919..cd702ae 100644
+--- a/arch/s390/hypfs/inode.c
++++ b/arch/s390/hypfs/inode.c
+@@ -1,5 +1,5 @@
+ /*
+- * fs/hypfs/inode.c
++ * arch/s390/hypfs/inode.c
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+@@ -91,7 +91,6 @@ static struct inode *hypfs_make_inode(st
+ ret->i_mode = mode;
+ ret->i_uid = hypfs_info->uid;
+ ret->i_gid = hypfs_info->gid;
+- ret->i_blksize = PAGE_CACHE_SIZE;
+ ret->i_blocks = 0;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ if (mode & S_IFDIR)
+@@ -104,13 +103,13 @@ static struct inode *hypfs_make_inode(st
+
+ static void hypfs_drop_inode(struct inode *inode)
+ {
+- kfree(inode->u.generic_ip);
++ kfree(inode->i_private);
+ generic_delete_inode(inode);
+ }
+
+ static int hypfs_open(struct inode *inode, struct file *filp)
+ {
+- char *data = filp->f_dentry->d_inode->u.generic_ip;
++ char *data = filp->f_dentry->d_inode->i_private;
+ struct hypfs_sb_info *fs_info;
+
+ if (filp->f_mode & FMODE_WRITE) {
+@@ -135,12 +134,20 @@ static int hypfs_open(struct inode *inod
+ return 0;
+ }
+
+-static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
+- size_t count, loff_t offset)
++static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t offset)
+ {
+ char *data;
+ size_t len;
+ struct file *filp = iocb->ki_filp;
++ /* XXX: temporary */
++ char __user *buf = iov[0].iov_base;
++ size_t count = iov[0].iov_len;
++
++ if (nr_segs != 1) {
++ count = -EINVAL;
++ goto out;
++ }
+
+ data = filp->private_data;
+ len = strlen(data);
+@@ -159,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kio
+ out:
+ return count;
+ }
+-static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos)
++static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t offset)
+ {
+ int rc;
+ struct super_block *sb;
+ struct hypfs_sb_info *fs_info;
++ size_t count = iov_length(iov, nr_segs);
+
+ sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
+ fs_info = sb->s_fs_info;
+@@ -312,10 +320,12 @@ static void hypfs_kill_super(struct supe
+ {
+ struct hypfs_sb_info *sb_info = sb->s_fs_info;
+
+- hypfs_delete_tree(sb->s_root);
+- hypfs_remove(sb_info->update_file);
+- kfree(sb->s_fs_info);
+- sb->s_fs_info = NULL;
++ if (sb->s_root) {
++ hypfs_delete_tree(sb->s_root);
++ hypfs_remove(sb_info->update_file);
++ kfree(sb->s_fs_info);
++ sb->s_fs_info = NULL;
++ }
+ kill_litter_super(sb);
+ }
+
+@@ -350,7 +360,7 @@ static struct dentry *hypfs_create_file(
+ parent->d_inode->i_nlink++;
+ } else
+ BUG();
+- inode->u.generic_ip = data;
++ inode->i_private = data;
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ return dentry;
+diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
+index 9a33ed6..aa97897 100644
+--- a/arch/s390/kernel/Makefile
++++ b/arch/s390/kernel/Makefile
+@@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional
+
+ obj-y := bitmap.o traps.o time.o process.o \
+ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
+- semaphore.o s390_ext.o debug.o profile.o irq.o reipl_diag.o
++ semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
+
+ obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
+ obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
+@@ -24,6 +24,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o
+
+ obj-$(CONFIG_VIRT_TIMER) += vtime.o
+ obj-$(CONFIG_STACKTRACE) += stacktrace.o
++obj-$(CONFIG_KPROBES) += kprobes.o
+
+ # Kexec part
+ S390_KEXEC_OBJS := machine_kexec.o crash.o
+diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
+index 785c9f7..5b33f82 100644
+--- a/arch/s390/kernel/compat_linux.c
++++ b/arch/s390/kernel/compat_linux.c
+@@ -295,6 +295,7 @@ static inline long put_tv32(struct compa
+ *
+ * This is really horribly ugly.
+ */
++#ifdef CONFIG_SYSVIPC
+ asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
+ {
+ if (call >> 16) /* hack for backward compatibility */
+@@ -338,6 +339,7 @@ asmlinkage long sys32_ipc(u32 call, int
+
+ return -ENOSYS;
+ }
++#endif
+
+ asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
+ {
+@@ -357,11 +359,16 @@ asmlinkage long sys32_ftruncate64(unsign
+
+ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
+ {
++ compat_ino_t ino;
+ int err;
+
+ if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+
++ ino = stat->ino;
++ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
++ return -EOVERFLOW;
++
+ err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
+ err |= put_user(stat->ino, &statbuf->st_ino);
+ err |= put_user(stat->mode, &statbuf->st_mode);
+@@ -544,10 +551,7 @@ sys32_execve(struct pt_regs regs)
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ current->thread.fp_regs.fpc=0;
+- __asm__ __volatile__
+- ("sr 0,0\n\t"
+- "sfpc 0,0\n\t"
+- : : :"0");
++ asm volatile("sfpc %0,0" : : "d" (0));
+ }
+ putname(filename);
+ out:
+@@ -708,7 +712,7 @@ asmlinkage long sys32_sendfile64(int out
+ return ret;
+ }
+
+-#ifdef CONFIG_SYSCTL
++#ifdef CONFIG_SYSCTL_SYSCALL
+ struct __sysctl_args32 {
+ u32 name;
+ int nlen;
+@@ -753,7 +757,9 @@ asmlinkage long sys32_sysctl(struct __sy
+ put_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)))
+ error = -EFAULT;
+ }
+- copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
++ if (copy_to_user(args->__unused, tmp.__unused,
++ sizeof(tmp.__unused)))
++ error = -EFAULT;
+ }
+ return error;
+ }
+diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
+index d49b876..861888a 100644
+--- a/arch/s390/kernel/compat_signal.c
++++ b/arch/s390/kernel/compat_signal.c
+@@ -169,12 +169,12 @@ sys32_sigaction(int sig, const struct ol
+ compat_old_sigset_t mask;
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(sa_handler, &act->sa_handler) ||
+- __get_user(sa_restorer, &act->sa_restorer))
++ __get_user(sa_restorer, &act->sa_restorer) ||
++ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
++ __get_user(mask, &act->sa_mask))
+ return -EFAULT;
+ new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
+ new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
+- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+- __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+@@ -185,10 +185,10 @@ sys32_sigaction(int sig, const struct ol
+ sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(sa_handler, &oact->sa_handler) ||
+- __put_user(sa_restorer, &oact->sa_restorer))
++ __put_user(sa_restorer, &oact->sa_restorer) ||
++ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
++ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+ 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;
+diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
+index 4d53b27..71e54ef 100644
+--- a/arch/s390/kernel/compat_wrapper.S
++++ b/arch/s390/kernel/compat_wrapper.S
+@@ -4,97 +4,97 @@
+ *
+ * Copyright (C) IBM Corp. 2000,2006
+ * Author(s): Gerhard Tonn (ton at de.ibm.com),
+-* Thomas Spatzier (tspat at de.ibm.com)
+-*/
++* Thomas Spatzier (tspat at de.ibm.com)
++*/
+
+- .globl sys32_exit_wrapper
++ .globl sys32_exit_wrapper
+ sys32_exit_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_exit # branch to sys_exit
+-
+- .globl sys32_read_wrapper
++
++ .globl sys32_read_wrapper
+ sys32_read_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ jg sys32_read # branch to sys_read
+
+- .globl sys32_write_wrapper
++ .globl sys32_write_wrapper
+ sys32_write_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # size_t
+ jg sys32_write # branch to system call
+
+- .globl sys32_open_wrapper
++ .globl sys32_open_wrapper
+ sys32_open_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_open # branch to system call
+
+- .globl sys32_close_wrapper
++ .globl sys32_close_wrapper
+ sys32_close_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_close # branch to system call
+
+- .globl sys32_creat_wrapper
++ .globl sys32_creat_wrapper
+ sys32_creat_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_creat # branch to system call
+
+- .globl sys32_link_wrapper
++ .globl sys32_link_wrapper
+ sys32_link_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_link # branch to system call
+
+- .globl sys32_unlink_wrapper
++ .globl sys32_unlink_wrapper
+ sys32_unlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_unlink # branch to system call
+
+- .globl sys32_chdir_wrapper
++ .globl sys32_chdir_wrapper
+ sys32_chdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_chdir # branch to system call
+
+- .globl sys32_time_wrapper
++ .globl sys32_time_wrapper
+ sys32_time_wrapper:
+ llgtr %r2,%r2 # int *
+ jg compat_sys_time # branch to system call
+
+- .globl sys32_mknod_wrapper
++ .globl sys32_mknod_wrapper
+ sys32_mknod_wrapper:
+ llgtr %r2,%r2 # const char *
+- lgfr %r3,%r3 # int
++ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # dev
+ jg sys_mknod # branch to system call
+
+- .globl sys32_chmod_wrapper
++ .globl sys32_chmod_wrapper
+ sys32_chmod_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # mode_t
+ jg sys_chmod # branch to system call
+
+- .globl sys32_lchown16_wrapper
++ .globl sys32_lchown16_wrapper
+ sys32_lchown16_wrapper:
+ llgtr %r2,%r2 # const char *
+- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
++ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
++ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ jg sys32_lchown16 # branch to system call
+
+- .globl sys32_lseek_wrapper
++ .globl sys32_lseek_wrapper
+ sys32_lseek_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ lgfr %r3,%r3 # off_t
+ llgfr %r4,%r4 # unsigned int
+ jg sys_lseek # branch to system call
+
+-#sys32_getpid_wrapper # void
++#sys32_getpid_wrapper # void
+
+- .globl sys32_mount_wrapper
++ .globl sys32_mount_wrapper
+ sys32_mount_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+@@ -103,19 +103,19 @@ sys32_mount_wrapper:
+ llgtr %r6,%r6 # void *
+ jg compat_sys_mount # branch to system call
+
+- .globl sys32_oldumount_wrapper
++ .globl sys32_oldumount_wrapper
+ sys32_oldumount_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_oldumount # branch to system call
+
+- .globl sys32_setuid16_wrapper
++ .globl sys32_setuid16_wrapper
+ sys32_setuid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ jg sys32_setuid16 # branch to system call
+
+-#sys32_getuid16_wrapper # void
++#sys32_getuid16_wrapper # void
+
+- .globl sys32_ptrace_wrapper
++ .globl sys32_ptrace_wrapper
+ sys32_ptrace_wrapper:
+ lgfr %r2,%r2 # long
+ lgfr %r3,%r3 # long
+@@ -123,168 +123,168 @@ sys32_ptrace_wrapper:
+ llgfr %r5,%r5 # long
+ jg sys_ptrace # branch to system call
+
+- .globl sys32_alarm_wrapper
++ .globl sys32_alarm_wrapper
+ sys32_alarm_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_alarm # branch to system call
+
+-#sys32_pause_wrapper # void
++#sys32_pause_wrapper # void
+
+- .globl compat_sys_utime_wrapper
++ .globl compat_sys_utime_wrapper
+ compat_sys_utime_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct compat_utimbuf *
+ jg compat_sys_utime # branch to system call
+
+- .globl sys32_access_wrapper
++ .globl sys32_access_wrapper
+ sys32_access_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_access # branch to system call
+
+- .globl sys32_nice_wrapper
++ .globl sys32_nice_wrapper
+ sys32_nice_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_nice # branch to system call
+
+-#sys32_sync_wrapper # void
++#sys32_sync_wrapper # void
+
+- .globl sys32_kill_wrapper
++ .globl sys32_kill_wrapper
+ sys32_kill_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_kill # branch to system call
+
+- .globl sys32_rename_wrapper
++ .globl sys32_rename_wrapper
+ sys32_rename_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_rename # branch to system call
+
+- .globl sys32_mkdir_wrapper
++ .globl sys32_mkdir_wrapper
+ sys32_mkdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_mkdir # branch to system call
+
+- .globl sys32_rmdir_wrapper
++ .globl sys32_rmdir_wrapper
+ sys32_rmdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_rmdir # branch to system call
+
+- .globl sys32_dup_wrapper
++ .globl sys32_dup_wrapper
+ sys32_dup_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_dup # branch to system call
+
+- .globl sys32_pipe_wrapper
++ .globl sys32_pipe_wrapper
+ sys32_pipe_wrapper:
+ llgtr %r2,%r2 # u32 *
+ jg sys_pipe # branch to system call
+
+- .globl compat_sys_times_wrapper
++ .globl compat_sys_times_wrapper
+ compat_sys_times_wrapper:
+ llgtr %r2,%r2 # struct compat_tms *
+ jg compat_sys_times # branch to system call
+
+- .globl sys32_brk_wrapper
++ .globl sys32_brk_wrapper
+ sys32_brk_wrapper:
+ llgtr %r2,%r2 # unsigned long
+ jg sys_brk # branch to system call
+
+- .globl sys32_setgid16_wrapper
++ .globl sys32_setgid16_wrapper
+ sys32_setgid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ jg sys32_setgid16 # branch to system call
+
+-#sys32_getgid16_wrapper # void
++#sys32_getgid16_wrapper # void
+
+ .globl sys32_signal_wrapper
+ sys32_signal_wrapper:
+- lgfr %r2,%r2 # int
++ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __sighandler_t
+ jg sys_signal
+
+-#sys32_geteuid16_wrapper # void
++#sys32_geteuid16_wrapper # void
+
+-#sys32_getegid16_wrapper # void
++#sys32_getegid16_wrapper # void
+
+- .globl sys32_acct_wrapper
++ .globl sys32_acct_wrapper
+ sys32_acct_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_acct # branch to system call
+
+- .globl sys32_umount_wrapper
++ .globl sys32_umount_wrapper
+ sys32_umount_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_umount # branch to system call
+
+- .globl compat_sys_ioctl_wrapper
++ .globl compat_sys_ioctl_wrapper
+ compat_sys_ioctl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned int
+ jg compat_sys_ioctl # branch to system call
+
+- .globl compat_sys_fcntl_wrapper
++ .globl compat_sys_fcntl_wrapper
+ compat_sys_fcntl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+- llgfr %r3,%r3 # unsigned int
++ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_fcntl # branch to system call
+
+- .globl sys32_setpgid_wrapper
++ .globl sys32_setpgid_wrapper
+ sys32_setpgid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ lgfr %r3,%r3 # pid_t
+ jg sys_setpgid # branch to system call
+
+- .globl sys32_umask_wrapper
++ .globl sys32_umask_wrapper
+ sys32_umask_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_umask # branch to system call
+
+- .globl sys32_chroot_wrapper
++ .globl sys32_chroot_wrapper
+ sys32_chroot_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_chroot # branch to system call
+
+ .globl sys32_ustat_wrapper
+ sys32_ustat_wrapper:
+- llgfr %r2,%r2 # dev_t
++ llgfr %r2,%r2 # dev_t
+ llgtr %r3,%r3 # struct ustat *
+ jg sys_ustat
+
+- .globl sys32_dup2_wrapper
++ .globl sys32_dup2_wrapper
+ sys32_dup2_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ jg sys_dup2 # branch to system call
+
+-#sys32_getppid_wrapper # void
++#sys32_getppid_wrapper # void
+
+-#sys32_getpgrp_wrapper # void
++#sys32_getpgrp_wrapper # void
+
+-#sys32_setsid_wrapper # void
++#sys32_setsid_wrapper # void
+
+- .globl sys32_sigaction_wrapper
++ .globl sys32_sigaction_wrapper
+ sys32_sigaction_wrapper:
+- lgfr %r2,%r2 # int
++ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct old_sigaction *
+ llgtr %r4,%r4 # struct old_sigaction32 *
+ jg sys32_sigaction # branch to system call
+
+- .globl sys32_setreuid16_wrapper
++ .globl sys32_setreuid16_wrapper
+ sys32_setreuid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
++ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ jg sys32_setreuid16 # branch to system call
+
+- .globl sys32_setregid16_wrapper
++ .globl sys32_setregid16_wrapper
+ sys32_setregid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
++ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ jg sys32_setregid16 # branch to system call
+
+ .globl sys_sigsuspend_wrapper
+@@ -294,95 +294,95 @@ sys_sigsuspend_wrapper:
+ llgfr %r4,%r4 # old_sigset_t
+ jg sys_sigsuspend
+
+- .globl compat_sys_sigpending_wrapper
++ .globl compat_sys_sigpending_wrapper
+ compat_sys_sigpending_wrapper:
+ llgtr %r2,%r2 # compat_old_sigset_t *
+ jg compat_sys_sigpending # branch to system call
+
+- .globl sys32_sethostname_wrapper
++ .globl sys32_sethostname_wrapper
+ sys32_sethostname_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_sethostname # branch to system call
+
+- .globl compat_sys_setrlimit_wrapper
++ .globl compat_sys_setrlimit_wrapper
+ compat_sys_setrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg compat_sys_setrlimit # branch to system call
+
+- .globl compat_sys_old_getrlimit_wrapper
++ .globl compat_sys_old_getrlimit_wrapper
+ compat_sys_old_getrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg compat_sys_old_getrlimit # branch to system call
+
+- .globl compat_sys_getrlimit_wrapper
++ .globl compat_sys_getrlimit_wrapper
+ compat_sys_getrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg compat_sys_getrlimit # branch to system call
+
+- .globl sys32_mmap2_wrapper
++ .globl sys32_mmap2_wrapper
+ sys32_mmap2_wrapper:
+ llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
+ jg sys32_mmap2 # branch to system call
+
+- .globl compat_sys_getrusage_wrapper
++ .globl compat_sys_getrusage_wrapper
+ compat_sys_getrusage_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct rusage_emu31 *
+ jg compat_sys_getrusage # branch to system call
+
+- .globl sys32_gettimeofday_wrapper
++ .globl sys32_gettimeofday_wrapper
+ sys32_gettimeofday_wrapper:
+ llgtr %r2,%r2 # struct timeval_emu31 *
+ llgtr %r3,%r3 # struct timezone *
+ jg sys32_gettimeofday # branch to system call
+
+- .globl sys32_settimeofday_wrapper
++ .globl sys32_settimeofday_wrapper
+ sys32_settimeofday_wrapper:
+ llgtr %r2,%r2 # struct timeval_emu31 *
+ llgtr %r3,%r3 # struct timezone *
+ jg sys32_settimeofday # branch to system call
+
+- .globl sys32_getgroups16_wrapper
++ .globl sys32_getgroups16_wrapper
+ sys32_getgroups16_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ jg sys32_getgroups16 # branch to system call
+
+- .globl sys32_setgroups16_wrapper
++ .globl sys32_setgroups16_wrapper
+ sys32_setgroups16_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ jg sys32_setgroups16 # branch to system call
+
+- .globl sys32_symlink_wrapper
++ .globl sys32_symlink_wrapper
+ sys32_symlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_symlink # branch to system call
+
+- .globl sys32_readlink_wrapper
++ .globl sys32_readlink_wrapper
+ sys32_readlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # char *
+ lgfr %r4,%r4 # int
+ jg sys_readlink # branch to system call
+
+- .globl sys32_uselib_wrapper
++ .globl sys32_uselib_wrapper
+ sys32_uselib_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_uselib # branch to system call
+
+- .globl sys32_swapon_wrapper
++ .globl sys32_swapon_wrapper
+ sys32_swapon_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_swapon # branch to system call
+
+- .globl sys32_reboot_wrapper
++ .globl sys32_reboot_wrapper
+ sys32_reboot_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+@@ -390,121 +390,121 @@ sys32_reboot_wrapper:
+ llgtr %r5,%r5 # void *
+ jg sys_reboot # branch to system call
+
+- .globl old32_readdir_wrapper
++ .globl old32_readdir_wrapper
+ old32_readdir_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg compat_sys_old_readdir # branch to system call
+
+- .globl old32_mmap_wrapper
++ .globl old32_mmap_wrapper
+ old32_mmap_wrapper:
+ llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
+ jg old32_mmap # branch to system call
+
+- .globl sys32_munmap_wrapper
++ .globl sys32_munmap_wrapper
+ sys32_munmap_wrapper:
+ llgfr %r2,%r2 # unsigned long
+- llgfr %r3,%r3 # size_t
++ llgfr %r3,%r3 # size_t
+ jg sys_munmap # branch to system call
+
+- .globl sys32_truncate_wrapper
++ .globl sys32_truncate_wrapper
+ sys32_truncate_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned long
+ jg sys_truncate # branch to system call
+
+- .globl sys32_ftruncate_wrapper
++ .globl sys32_ftruncate_wrapper
+ sys32_ftruncate_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+ jg sys_ftruncate # branch to system call
+
+- .globl sys32_fchmod_wrapper
++ .globl sys32_fchmod_wrapper
+ sys32_fchmod_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # mode_t
+ jg sys_fchmod # branch to system call
+
+- .globl sys32_fchown16_wrapper
++ .globl sys32_fchown16_wrapper
+ sys32_fchown16_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # compat_uid_t
+ llgfr %r4,%r4 # compat_uid_t
+ jg sys32_fchown16 # branch to system call
+
+- .globl sys32_getpriority_wrapper
++ .globl sys32_getpriority_wrapper
+ sys32_getpriority_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_getpriority # branch to system call
+
+- .globl sys32_setpriority_wrapper
++ .globl sys32_setpriority_wrapper
+ sys32_setpriority_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_setpriority # branch to system call
+
+- .globl compat_sys_statfs_wrapper
++ .globl compat_sys_statfs_wrapper
+ compat_sys_statfs_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct compat_statfs *
+ jg compat_sys_statfs # branch to system call
+
+- .globl compat_sys_fstatfs_wrapper
++ .globl compat_sys_fstatfs_wrapper
+ compat_sys_fstatfs_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct compat_statfs *
+ jg compat_sys_fstatfs # branch to system call
+
+- .globl compat_sys_socketcall_wrapper
++ .globl compat_sys_socketcall_wrapper
+ compat_sys_socketcall_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # u32 *
+ jg compat_sys_socketcall # branch to system call
+
+- .globl sys32_syslog_wrapper
++ .globl sys32_syslog_wrapper
+ sys32_syslog_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ lgfr %r4,%r4 # int
+ jg sys_syslog # branch to system call
+
+- .globl compat_sys_setitimer_wrapper
++ .globl compat_sys_setitimer_wrapper
+ compat_sys_setitimer_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct itimerval_emu31 *
+ llgtr %r4,%r4 # struct itimerval_emu31 *
+ jg compat_sys_setitimer # branch to system call
+
+- .globl compat_sys_getitimer_wrapper
++ .globl compat_sys_getitimer_wrapper
+ compat_sys_getitimer_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct itimerval_emu31 *
+ jg compat_sys_getitimer # branch to system call
+
+- .globl compat_sys_newstat_wrapper
++ .globl compat_sys_newstat_wrapper
+ compat_sys_newstat_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg compat_sys_newstat # branch to system call
+
+- .globl compat_sys_newlstat_wrapper
++ .globl compat_sys_newlstat_wrapper
+ compat_sys_newlstat_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg compat_sys_newlstat # branch to system call
+
+- .globl compat_sys_newfstat_wrapper
++ .globl compat_sys_newfstat_wrapper
+ compat_sys_newfstat_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg compat_sys_newfstat # branch to system call
+
+-#sys32_vhangup_wrapper # void
++#sys32_vhangup_wrapper # void
+
+- .globl compat_sys_wait4_wrapper
++ .globl compat_sys_wait4_wrapper
+ compat_sys_wait4_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # unsigned int *
+@@ -512,17 +512,17 @@ compat_sys_wait4_wrapper:
+ llgtr %r5,%r5 # struct rusage *
+ jg compat_sys_wait4 # branch to system call
+
+- .globl sys32_swapoff_wrapper
++ .globl sys32_swapoff_wrapper
+ sys32_swapoff_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_swapoff # branch to system call
+
+- .globl sys32_sysinfo_wrapper
++ .globl sys32_sysinfo_wrapper
+ sys32_sysinfo_wrapper:
+ llgtr %r2,%r2 # struct sysinfo_emu31 *
+ jg sys32_sysinfo # branch to system call
+
+- .globl sys32_ipc_wrapper
++ .globl sys32_ipc_wrapper
+ sys32_ipc_wrapper:
+ llgfr %r2,%r2 # uint
+ lgfr %r3,%r3 # int
+@@ -531,59 +531,59 @@ sys32_ipc_wrapper:
+ llgfr %r6,%r6 # u32
+ jg sys32_ipc # branch to system call
+
+- .globl sys32_fsync_wrapper
++ .globl sys32_fsync_wrapper
+ sys32_fsync_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fsync # branch to system call
+
+-#sys32_sigreturn_wrapper # done in sigreturn_glue
++#sys32_sigreturn_wrapper # done in sigreturn_glue
+
+-#sys32_clone_wrapper # done in clone_glue
++#sys32_clone_wrapper # done in clone_glue
+
+- .globl sys32_setdomainname_wrapper
++ .globl sys32_setdomainname_wrapper
+ sys32_setdomainname_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_setdomainname # branch to system call
+
+- .globl sys32_newuname_wrapper
++ .globl sys32_newuname_wrapper
+ sys32_newuname_wrapper:
+ llgtr %r2,%r2 # struct new_utsname *
+ jg s390x_newuname # branch to system call
+
+- .globl compat_sys_adjtimex_wrapper
++ .globl compat_sys_adjtimex_wrapper
+ compat_sys_adjtimex_wrapper:
+ llgtr %r2,%r2 # struct compat_timex *
+ jg compat_sys_adjtimex # branch to system call
+
+- .globl sys32_mprotect_wrapper
++ .globl sys32_mprotect_wrapper
+ sys32_mprotect_wrapper:
+ llgtr %r2,%r2 # unsigned long (actually pointer
+ llgfr %r3,%r3 # size_t
+ llgfr %r4,%r4 # unsigned long
+ jg sys_mprotect # branch to system call
+
+- .globl compat_sys_sigprocmask_wrapper
++ .globl compat_sys_sigprocmask_wrapper
+ compat_sys_sigprocmask_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_old_sigset_t *
+ llgtr %r4,%r4 # compat_old_sigset_t *
+ jg compat_sys_sigprocmask # branch to system call
+
+- .globl sys32_init_module_wrapper
++ .globl sys32_init_module_wrapper
+ sys32_init_module_wrapper:
+ llgtr %r2,%r2 # void *
+ llgfr %r3,%r3 # unsigned long
+ llgtr %r4,%r4 # char *
+ jg sys32_init_module # branch to system call
+
+- .globl sys32_delete_module_wrapper
++ .globl sys32_delete_module_wrapper
+ sys32_delete_module_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned int
+ jg sys32_delete_module # branch to system call
+
+- .globl sys32_quotactl_wrapper
++ .globl sys32_quotactl_wrapper
+ sys32_quotactl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+@@ -591,45 +591,45 @@ sys32_quotactl_wrapper:
+ llgtr %r5,%r5 # caddr_t
+ jg sys_quotactl # branch to system call
+
+- .globl sys32_getpgid_wrapper
++ .globl sys32_getpgid_wrapper
+ sys32_getpgid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_getpgid # branch to system call
+
+- .globl sys32_fchdir_wrapper
++ .globl sys32_fchdir_wrapper
+ sys32_fchdir_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fchdir # branch to system call
+
+- .globl sys32_bdflush_wrapper
++ .globl sys32_bdflush_wrapper
+ sys32_bdflush_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # long
+ jg sys_bdflush # branch to system call
+
+- .globl sys32_sysfs_wrapper
++ .globl sys32_sysfs_wrapper
+ sys32_sysfs_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys_sysfs # branch to system call
+
+- .globl sys32_personality_wrapper
++ .globl sys32_personality_wrapper
+ sys32_personality_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ jg s390x_personality # branch to system call
+
+- .globl sys32_setfsuid16_wrapper
++ .globl sys32_setfsuid16_wrapper
+ sys32_setfsuid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ jg sys32_setfsuid16 # branch to system call
+
+- .globl sys32_setfsgid16_wrapper
++ .globl sys32_setfsgid16_wrapper
+ sys32_setfsgid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ jg sys32_setfsgid16 # branch to system call
+
+- .globl sys32_llseek_wrapper
++ .globl sys32_llseek_wrapper
+ sys32_llseek_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+@@ -638,14 +638,14 @@ sys32_llseek_wrapper:
+ llgfr %r6,%r6 # unsigned int
+ jg sys_llseek # branch to system call
+
+- .globl sys32_getdents_wrapper
++ .globl sys32_getdents_wrapper
+ sys32_getdents_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg compat_sys_getdents # branch to system call
+
+- .globl compat_sys_select_wrapper
++ .globl compat_sys_select_wrapper
+ compat_sys_select_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_fd_set *
+@@ -654,113 +654,113 @@ compat_sys_select_wrapper:
+ llgtr %r6,%r6 # struct compat_timeval *
+ jg compat_sys_select # branch to system call
+
+- .globl sys32_flock_wrapper
++ .globl sys32_flock_wrapper
+ sys32_flock_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ jg sys_flock # branch to system call
+
+- .globl sys32_msync_wrapper
++ .globl sys32_msync_wrapper
+ sys32_msync_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ lgfr %r4,%r4 # int
+ jg sys_msync # branch to system call
+
+- .globl compat_sys_readv_wrapper
++ .globl compat_sys_readv_wrapper
+ compat_sys_readv_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct compat_iovec *
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_readv # branch to system call
+
+- .globl compat_sys_writev_wrapper
++ .globl compat_sys_writev_wrapper
+ compat_sys_writev_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct compat_iovec *
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_writev # branch to system call
+
+- .globl sys32_getsid_wrapper
++ .globl sys32_getsid_wrapper
+ sys32_getsid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_getsid # branch to system call
+
+- .globl sys32_fdatasync_wrapper
++ .globl sys32_fdatasync_wrapper
+ sys32_fdatasync_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fdatasync # branch to system call
+
+-#sys32_sysctl_wrapper # tbd
++#sys32_sysctl_wrapper # tbd
+
+- .globl sys32_mlock_wrapper
++ .globl sys32_mlock_wrapper
+ sys32_mlock_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_mlock # branch to system call
+
+- .globl sys32_munlock_wrapper
++ .globl sys32_munlock_wrapper
+ sys32_munlock_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_munlock # branch to system call
+
+- .globl sys32_mlockall_wrapper
++ .globl sys32_mlockall_wrapper
+ sys32_mlockall_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_mlockall # branch to system call
+
+-#sys32_munlockall_wrapper # void
++#sys32_munlockall_wrapper # void
+
+- .globl sys32_sched_setparam_wrapper
++ .globl sys32_sched_setparam_wrapper
+ sys32_sched_setparam_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct sched_param *
+ jg sys_sched_setparam # branch to system call
+
+- .globl sys32_sched_getparam_wrapper
++ .globl sys32_sched_getparam_wrapper
+ sys32_sched_getparam_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct sched_param *
+ jg sys_sched_getparam # branch to system call
+
+- .globl sys32_sched_setscheduler_wrapper
++ .globl sys32_sched_setscheduler_wrapper
+ sys32_sched_setscheduler_wrapper:
+ lgfr %r2,%r2 # pid_t
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # struct sched_param *
+ jg sys_sched_setscheduler # branch to system call
+
+- .globl sys32_sched_getscheduler_wrapper
++ .globl sys32_sched_getscheduler_wrapper
+ sys32_sched_getscheduler_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_sched_getscheduler # branch to system call
+
+-#sys32_sched_yield_wrapper # void
++#sys32_sched_yield_wrapper # void
+
+- .globl sys32_sched_get_priority_max_wrapper
++ .globl sys32_sched_get_priority_max_wrapper
+ sys32_sched_get_priority_max_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_sched_get_priority_max # branch to system call
+
+- .globl sys32_sched_get_priority_min_wrapper
++ .globl sys32_sched_get_priority_min_wrapper
+ sys32_sched_get_priority_min_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_sched_get_priority_min # branch to system call
+
+- .globl sys32_sched_rr_get_interval_wrapper
++ .globl sys32_sched_rr_get_interval_wrapper
+ sys32_sched_rr_get_interval_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg sys32_sched_rr_get_interval # branch to system call
+
+- .globl compat_sys_nanosleep_wrapper
++ .globl compat_sys_nanosleep_wrapper
+ compat_sys_nanosleep_wrapper:
+ llgtr %r2,%r2 # struct compat_timespec *
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg compat_sys_nanosleep # branch to system call
+
+- .globl sys32_mremap_wrapper
++ .globl sys32_mremap_wrapper
+ sys32_mremap_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # unsigned long
+@@ -769,49 +769,49 @@ sys32_mremap_wrapper:
+ llgfr %r6,%r6 # unsigned long
+ jg sys_mremap # branch to system call
+
+- .globl sys32_setresuid16_wrapper
++ .globl sys32_setresuid16_wrapper
+ sys32_setresuid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
++ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
++ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ jg sys32_setresuid16 # branch to system call
+
+- .globl sys32_getresuid16_wrapper
++ .globl sys32_getresuid16_wrapper
+ sys32_getresuid16_wrapper:
+ llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
+ llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
+ jg sys32_getresuid16 # branch to system call
+
+- .globl sys32_poll_wrapper
++ .globl sys32_poll_wrapper
+ sys32_poll_wrapper:
+- llgtr %r2,%r2 # struct pollfd *
+- llgfr %r3,%r3 # unsigned int
+- lgfr %r4,%r4 # long
++ llgtr %r2,%r2 # struct pollfd *
++ llgfr %r3,%r3 # unsigned int
++ lgfr %r4,%r4 # long
+ jg sys_poll # branch to system call
+
+- .globl compat_sys_nfsservctl_wrapper
++ .globl compat_sys_nfsservctl_wrapper
+ compat_sys_nfsservctl_wrapper:
+- lgfr %r2,%r2 # int
++ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct compat_nfsctl_arg*
+ llgtr %r4,%r4 # union compat_nfsctl_res*
+ jg compat_sys_nfsservctl # branch to system call
+
+- .globl sys32_setresgid16_wrapper
++ .globl sys32_setresgid16_wrapper
+ sys32_setresgid16_wrapper:
+- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
++ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
++ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
++ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ jg sys32_setresgid16 # branch to system call
+
+- .globl sys32_getresgid16_wrapper
++ .globl sys32_getresgid16_wrapper
+ sys32_getresgid16_wrapper:
+ llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
+ jg sys32_getresgid16 # branch to system call
+
+- .globl sys32_prctl_wrapper
++ .globl sys32_prctl_wrapper
+ sys32_prctl_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned long
+@@ -820,9 +820,9 @@ sys32_prctl_wrapper:
+ llgfr %r6,%r6 # unsigned long
+ jg sys_prctl # branch to system call
+
+-#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
++#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
+
+- .globl sys32_rt_sigaction_wrapper
++ .globl sys32_rt_sigaction_wrapper
+ sys32_rt_sigaction_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct sigaction_emu31 *
+@@ -830,7 +830,7 @@ sys32_rt_sigaction_wrapper:
+ llgfr %r5,%r5 # size_t
+ jg sys32_rt_sigaction # branch to system call
+
+- .globl sys32_rt_sigprocmask_wrapper
++ .globl sys32_rt_sigprocmask_wrapper
+ sys32_rt_sigprocmask_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # old_sigset_emu31 *
+@@ -838,13 +838,13 @@ sys32_rt_sigprocmask_wrapper:
+ llgfr %r5,%r5 # size_t
+ jg sys32_rt_sigprocmask # branch to system call
+
+- .globl sys32_rt_sigpending_wrapper
++ .globl sys32_rt_sigpending_wrapper
+ sys32_rt_sigpending_wrapper:
+ llgtr %r2,%r2 # sigset_emu31 *
+ llgfr %r3,%r3 # size_t
+ jg sys32_rt_sigpending # branch to system call
+
+- .globl compat_sys_rt_sigtimedwait_wrapper
++ .globl compat_sys_rt_sigtimedwait_wrapper
+ compat_sys_rt_sigtimedwait_wrapper:
+ llgtr %r2,%r2 # const sigset_emu31_t *
+ llgtr %r3,%r3 # siginfo_emu31_t *
+@@ -852,7 +852,7 @@ compat_sys_rt_sigtimedwait_wrapper:
+ llgfr %r5,%r5 # size_t
+ jg compat_sys_rt_sigtimedwait # branch to system call
+
+- .globl sys32_rt_sigqueueinfo_wrapper
++ .globl sys32_rt_sigqueueinfo_wrapper
+ sys32_rt_sigqueueinfo_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+@@ -865,7 +865,7 @@ compat_sys_rt_sigsuspend_wrapper:
+ llgfr %r3,%r3 # compat_size_t
+ jg compat_sys_rt_sigsuspend
+
+- .globl sys32_pread64_wrapper
++ .globl sys32_pread64_wrapper
+ sys32_pread64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+@@ -874,7 +874,7 @@ sys32_pread64_wrapper:
+ llgfr %r6,%r6 # u32
+ jg sys32_pread64 # branch to system call
+
+- .globl sys32_pwrite64_wrapper
++ .globl sys32_pwrite64_wrapper
+ sys32_pwrite64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+@@ -883,26 +883,26 @@ sys32_pwrite64_wrapper:
+ llgfr %r6,%r6 # u32
+ jg sys32_pwrite64 # branch to system call
+
+- .globl sys32_chown16_wrapper
++ .globl sys32_chown16_wrapper
+ sys32_chown16_wrapper:
+ llgtr %r2,%r2 # const char *
+- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
++ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
++ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ jg sys32_chown16 # branch to system call
+
+- .globl sys32_getcwd_wrapper
++ .globl sys32_getcwd_wrapper
+ sys32_getcwd_wrapper:
+ llgtr %r2,%r2 # char *
+ llgfr %r3,%r3 # unsigned long
+ jg sys_getcwd # branch to system call
+
+- .globl sys32_capget_wrapper
++ .globl sys32_capget_wrapper
+ sys32_capget_wrapper:
+ llgtr %r2,%r2 # cap_user_header_t
+ llgtr %r3,%r3 # cap_user_data_t
+ jg sys_capget # branch to system call
+
+- .globl sys32_capset_wrapper
++ .globl sys32_capset_wrapper
+ sys32_capset_wrapper:
+ llgtr %r2,%r2 # cap_user_header_t
+ llgtr %r3,%r3 # const cap_user_data_t
+@@ -910,11 +910,11 @@ sys32_capset_wrapper:
+
+ .globl sys32_sigaltstack_wrapper
+ sys32_sigaltstack_wrapper:
+- llgtr %r2,%r2 # const stack_emu31_t *
+- llgtr %r3,%r3 # stack_emu31_t *
++ llgtr %r2,%r2 # const stack_emu31_t *
++ llgtr %r3,%r3 # stack_emu31_t *
+ jg sys32_sigaltstack
+
+- .globl sys32_sendfile_wrapper
++ .globl sys32_sendfile_wrapper
+ sys32_sendfile_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+@@ -922,33 +922,33 @@ sys32_sendfile_wrapper:
+ llgfr %r5,%r5 # size_t
+ jg sys32_sendfile # branch to system call
+
+-#sys32_vfork_wrapper # done in vfork_glue
++#sys32_vfork_wrapper # done in vfork_glue
+
+- .globl sys32_truncate64_wrapper
++ .globl sys32_truncate64_wrapper
+ sys32_truncate64_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_truncate64 # branch to system call
+
+- .globl sys32_ftruncate64_wrapper
++ .globl sys32_ftruncate64_wrapper
+ sys32_ftruncate64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_ftruncate64 # branch to system call
+
+- .globl sys32_lchown_wrapper
++ .globl sys32_lchown_wrapper
+ sys32_lchown_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_lchown # branch to system call
+
+-#sys32_getuid_wrapper # void
+-#sys32_getgid_wrapper # void
+-#sys32_geteuid_wrapper # void
+-#sys32_getegid_wrapper # void
++#sys32_getuid_wrapper # void
++#sys32_getgid_wrapper # void
++#sys32_geteuid_wrapper # void
++#sys32_getegid_wrapper # void
+
+ .globl sys32_setreuid_wrapper
+ sys32_setreuid_wrapper:
+@@ -962,111 +962,111 @@ sys32_setregid_wrapper:
+ llgfr %r3,%r3 # gid_t
+ jg sys_setregid # branch to system call
+
+- .globl sys32_getgroups_wrapper
++ .globl sys32_getgroups_wrapper
+ sys32_getgroups_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # gid_t *
+ jg sys_getgroups # branch to system call
+
+- .globl sys32_setgroups_wrapper
++ .globl sys32_setgroups_wrapper
+ sys32_setgroups_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # gid_t *
+ jg sys_setgroups # branch to system call
+
+- .globl sys32_fchown_wrapper
++ .globl sys32_fchown_wrapper
+ sys32_fchown_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_fchown # branch to system call
+
+- .globl sys32_setresuid_wrapper
++ .globl sys32_setresuid_wrapper
+ sys32_setresuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # uid_t
+ jg sys_setresuid # branch to system call
+
+- .globl sys32_getresuid_wrapper
++ .globl sys32_getresuid_wrapper
+ sys32_getresuid_wrapper:
+ llgtr %r2,%r2 # uid_t *
+ llgtr %r3,%r3 # uid_t *
+ llgtr %r4,%r4 # uid_t *
+ jg sys_getresuid # branch to system call
+
+- .globl sys32_setresgid_wrapper
++ .globl sys32_setresgid_wrapper
+ sys32_setresgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ llgfr %r3,%r3 # gid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_setresgid # branch to system call
+
+- .globl sys32_getresgid_wrapper
++ .globl sys32_getresgid_wrapper
+ sys32_getresgid_wrapper:
+ llgtr %r2,%r2 # gid_t *
+ llgtr %r3,%r3 # gid_t *
+ llgtr %r4,%r4 # gid_t *
+ jg sys_getresgid # branch to system call
+
+- .globl sys32_chown_wrapper
++ .globl sys32_chown_wrapper
+ sys32_chown_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_chown # branch to system call
+
+- .globl sys32_setuid_wrapper
++ .globl sys32_setuid_wrapper
+ sys32_setuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ jg sys_setuid # branch to system call
+
+- .globl sys32_setgid_wrapper
++ .globl sys32_setgid_wrapper
+ sys32_setgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ jg sys_setgid # branch to system call
+
+- .globl sys32_setfsuid_wrapper
++ .globl sys32_setfsuid_wrapper
+ sys32_setfsuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ jg sys_setfsuid # branch to system call
+
+- .globl sys32_setfsgid_wrapper
++ .globl sys32_setfsgid_wrapper
+ sys32_setfsgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ jg sys_setfsgid # branch to system call
+
+- .globl sys32_pivot_root_wrapper
++ .globl sys32_pivot_root_wrapper
+ sys32_pivot_root_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_pivot_root # branch to system call
+
+- .globl sys32_mincore_wrapper
++ .globl sys32_mincore_wrapper
+ sys32_mincore_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ llgtr %r4,%r4 # unsigned char *
+ jg sys_mincore # branch to system call
+
+- .globl sys32_madvise_wrapper
++ .globl sys32_madvise_wrapper
+ sys32_madvise_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ lgfr %r4,%r4 # int
+ jg sys_madvise # branch to system call
+
+- .globl sys32_getdents64_wrapper
++ .globl sys32_getdents64_wrapper
+ sys32_getdents64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg sys_getdents64 # branch to system call
+
+- .globl compat_sys_fcntl64_wrapper
++ .globl compat_sys_fcntl64_wrapper
+ compat_sys_fcntl64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+- llgfr %r3,%r3 # unsigned int
++ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_fcntl64 # branch to system call
+
+@@ -1087,10 +1087,10 @@ sys32_stime_wrapper:
+ llgtr %r2,%r2 # long *
+ jg compat_sys_stime # branch to system call
+
+- .globl sys32_sysctl_wrapper
++ .globl sys32_sysctl_wrapper
+ sys32_sysctl_wrapper:
+- llgtr %r2,%r2 # struct __sysctl_args32 *
+- jg sys32_sysctl
++ llgtr %r2,%r2 # struct __sysctl_args32 *
++ jg sys32_sysctl
+
+ .globl sys32_fstat64_wrapper
+ sys32_fstat64_wrapper:
+@@ -1098,7 +1098,7 @@ sys32_fstat64_wrapper:
+ llgtr %r3,%r3 # struct stat64 *
+ jg sys32_fstat64 # branch to system call
+
+- .globl compat_sys_futex_wrapper
++ .globl compat_sys_futex_wrapper
+ compat_sys_futex_wrapper:
+ llgtr %r2,%r2 # u32 *
+ lgfr %r3,%r3 # int
+@@ -1213,22 +1213,22 @@ sys32_sched_getaffinity_wrapper:
+ llgtr %r4,%r4 # unsigned long *
+ jg compat_sys_sched_getaffinity
+
+- .globl sys32_exit_group_wrapper
++ .globl sys32_exit_group_wrapper
+ sys32_exit_group_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_exit_group # branch to system call
+
+- .globl sys32_set_tid_address_wrapper
++ .globl sys32_set_tid_address_wrapper
+ sys32_set_tid_address_wrapper:
+ llgtr %r2,%r2 # int *
+ jg sys_set_tid_address # branch to system call
+
+- .globl sys_epoll_create_wrapper
++ .globl sys_epoll_create_wrapper
+ sys_epoll_create_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_epoll_create # branch to system call
+
+- .globl sys_epoll_ctl_wrapper
++ .globl sys_epoll_ctl_wrapper
+ sys_epoll_ctl_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+@@ -1236,7 +1236,7 @@ sys_epoll_ctl_wrapper:
+ llgtr %r5,%r5 # struct epoll_event *
+ jg sys_epoll_ctl # branch to system call
+
+- .globl sys_epoll_wait_wrapper
++ .globl sys_epoll_wait_wrapper
+ sys_epoll_wait_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct epoll_event *
+@@ -1658,3 +1658,10 @@ compat_sys_vmsplice_wrapper:
+ llgfr %r4,%r4 # unsigned int
+ llgfr %r5,%r5 # unsigned int
+ jg compat_sys_vmsplice
++
++ .globl sys_getcpu_wrapper
++sys_getcpu_wrapper:
++ llgtr %r2,%r2 # unsigned *
++ llgtr %r3,%r3 # unsigned *
++ llgtr %r4,%r4 # struct getcpu_cache *
++ jg sys_getcpu
+diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
+index 4ef44e5..1eae74e 100644
+--- a/arch/s390/kernel/cpcmd.c
++++ b/arch/s390/kernel/cpcmd.c
+@@ -25,11 +25,8 @@ static char cpcmd_buf[241];
+ */
+ 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;
++ unsigned long flags, cmdlen;
++ int return_code, return_len;
+
+ spin_lock_irqsave(&cpcmd_lock, flags);
+ cmdlen = strlen(cmd);
+@@ -38,64 +35,44 @@ int __cpcmd(const char *cmd, char *resp
+ ASCEBC(cpcmd_buf, cmdlen);
+
+ if (response != NULL && rlen > 0) {
++ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
++ register unsigned long reg3 asm ("3") = (addr_t) response;
++ register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
++ register unsigned long reg5 asm ("5") = rlen;
++
+ memset(response, 0, rlen);
++ asm volatile(
+ #ifndef CONFIG_64BIT
+- 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, 1f\n"
+- "ar 5, %5\n"
+- "1: \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" );
++ " diag %2,%0,0x8\n"
++ " brc 8,1f\n"
++ " ar %1,%4\n"
+ #else /* CONFIG_64BIT */
+- 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, 1f\n"
+- "agr 5, %5\n"
+- "1: \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" );
++ " sam31\n"
++ " diag %2,%0,0x8\n"
++ " sam64\n"
++ " brc 8,1f\n"
++ " agr %1,%4\n"
+ #endif /* CONFIG_64BIT */
++ "1:\n"
++ : "+d" (reg4), "+d" (reg5)
++ : "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
++ return_code = (int) reg4;
++ return_len = (int) reg5;
+ EBCASC(response, rlen);
+ } else {
++ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
++ register unsigned long reg3 asm ("3") = cmdlen;
+ return_len = 0;
++ asm volatile(
+ #ifndef CONFIG_64BIT
+- 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" );
++ " diag %1,%0,0x8\n"
+ #else /* CONFIG_64BIT */
+- 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" );
++ " sam31\n"
++ " diag %1,%0,0x8\n"
++ " sam64\n"
+ #endif /* CONFIG_64BIT */
++ : "+d" (reg3) : "d" (reg2) : "cc");
++ return_code = (int) reg3;
+ }
+ spin_unlock_irqrestore(&cpcmd_lock, flags);
+ if (response_code != NULL)
+diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
+index 7ba2092..43f3d0c 100644
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -603,7 +603,7 @@ debug_open(struct inode *inode, struct f
+ debug_info_t *debug_info, *debug_info_snapshot;
+
+ down(&debug_lock);
+- debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip;
++ debug_info = file->f_dentry->d_inode->i_private;
+ /* find debug view */
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (!debug_info->views[i])
+diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
+index 5b5799a..dddc3de 100644
+--- a/arch/s390/kernel/entry.S
++++ b/arch/s390/kernel/entry.S
+@@ -4,8 +4,8 @@
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ * Author(s): Martin Schwidefsky (schwidefsky at de.ibm.com),
+- * Hartmut Penner (hp at de.ibm.com),
+- * Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com),
++ * Hartmut Penner (hp at de.ibm.com),
++ * Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com),
+ * Heiko Carstens <heiko.carstens at de.ibm.com>
+ */
+
+@@ -24,29 +24,29 @@
+ * Stack layout for the system_call stack entry.
+ * The first few entries are identical to the user_regs_struct.
+ */
+-SP_PTREGS = STACK_FRAME_OVERHEAD
+-SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
+-SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+-SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
+-SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
+-SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+-SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12
+-SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+-SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20
+-SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+-SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28
+-SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+-SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36
+-SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+-SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44
+-SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+-SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
+-SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+-SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
+-SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+-SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
+-SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
+-SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
++SP_PTREGS = STACK_FRAME_OVERHEAD
++SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
++SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
++SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
++SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
++SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
++SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12
++SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
++SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20
++SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
++SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28
++SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
++SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36
++SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
++SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44
++SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
++SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
++SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
++SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
++SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
++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_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+ _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
+@@ -81,14 +81,14 @@ STACK_SIZE = 1 << STACK_SHIFT
+ * R15 - kernel stack pointer
+ */
+
+- .macro STORE_TIMER lc_offset
++ .macro STORE_TIMER lc_offset
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ stpt \lc_offset
+ #endif
+ .endm
+
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+- .macro UPDATE_VTIME lc_from,lc_to,lc_sum
++ .macro UPDATE_VTIME lc_from,lc_to,lc_sum
+ lm %r10,%r11,\lc_from
+ sl %r10,\lc_to
+ sl %r11,\lc_to+4
+@@ -147,7 +147,7 @@ STACK_SIZE = 1 << STACK_SHIFT
+ 2:
+ .endm
+
+- .macro CREATE_STACK_FRAME psworg,savearea
++ .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
+@@ -160,7 +160,7 @@ STACK_SIZE = 1 << STACK_SHIFT
+ st %r12,__SF_BACKCHAIN(%r15) # clear back chain
+ .endm
+
+- .macro RESTORE_ALL psworg,sync
++ .macro RESTORE_ALL psworg,sync
+ mvc \psworg(8),SP_PSW(%r15) # move user PSW to lowcore
+ .if !\sync
+ ni \psworg+1,0xfd # clear wait state bit
+@@ -177,16 +177,16 @@ STACK_SIZE = 1 << STACK_SHIFT
+ * Returns:
+ * gpr2 = prev
+ */
+- .globl __switch_to
++ .globl __switch_to
+ __switch_to:
+- basr %r1,0
++ basr %r1,0
+ __switch_to_base:
+ tm __THREAD_per(%r3),0xe8 # new process is using per ?
+ bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine
+- stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff
+- clc __THREAD_per(12,%r3),__SF_EMPTY(%r15)
+- be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
+- lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
++ stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff
++ clc __THREAD_per(12,%r3),__SF_EMPTY(%r15)
++ be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
++ lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
+ __switch_to_noper:
+ l %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+@@ -195,13 +195,13 @@ __switch_to_noper:
+ 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
++ stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
+ st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
+ l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
+ lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
+ st %r3,__LC_CURRENT # __LC_CURRENT = current task struct
+ lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
+- l %r3,__THREAD_info(%r3) # load thread_info from task struct
++ l %r3,__THREAD_info(%r3) # load thread_info from task struct
+ st %r3,__LC_THREAD_INFO
+ ahi %r3,STACK_SIZE
+ st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
+@@ -213,7 +213,7 @@ __critical_start:
+ * are executed with interrupts enabled.
+ */
+
+- .globl system_call
++ .globl system_call
+ system_call:
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+ sysc_saveall:
+@@ -233,24 +233,24 @@ sysc_update:
+ #endif
+ sysc_do_svc:
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+- sla %r7,2 # *4 and test for svc 0
+- bnz BASED(sysc_nr_ok) # svc number > 0
++ sla %r7,2 # *4 and test for svc 0
++ bnz BASED(sysc_nr_ok) # svc number > 0
+ # svc 0: system call number in %r1
+ cl %r1,BASED(.Lnr_syscalls)
+ bnl BASED(sysc_nr_ok)
+- lr %r7,%r1 # copy svc number to %r7
+- sla %r7,2 # *4
++ lr %r7,%r1 # copy svc number to %r7
++ sla %r7,2 # *4
+ sysc_nr_ok:
+ mvc SP_ARGS(4,%r15),SP_R7(%r15)
+ sysc_do_restart:
+ l %r8,BASED(.Lsysc_table)
+ tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+ l %r8,0(%r7,%r8) # get system call addr.
+- bnz BASED(sysc_tracesys)
+- basr %r14,%r8 # call sys_xxxx
+- st %r2,SP_R2(%r15) # store return value (change R2 on stack)
+- # ATTENTION: check sys_execve_glue before
+- # changing anything here !!
++ bnz BASED(sysc_tracesys)
++ basr %r14,%r8 # call sys_xxxx
++ st %r2,SP_R2(%r15) # store return value (change R2 on stack)
++ # ATTENTION: check sys_execve_glue before
++ # changing anything here !!
+
+ sysc_return:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+@@ -258,14 +258,14 @@ sysc_return:
+ tm __TI_flags+3(%r9),_TIF_WORK_SVC
+ bnz BASED(sysc_work) # there is work to do (signals etc.)
+ sysc_leave:
+- RESTORE_ALL __LC_RETURN_PSW,1
++ RESTORE_ALL __LC_RETURN_PSW,1
+
+ #
+ # recheck if there is more work to do
+ #
+ sysc_work_loop:
+ tm __TI_flags+3(%r9),_TIF_WORK_SVC
+- bz BASED(sysc_leave) # there is no work to do
++ bz BASED(sysc_leave) # there is no work to do
+ #
+ # One of the work bits is on. Find out which one.
+ #
+@@ -284,11 +284,11 @@ sysc_work:
+
+ #
+ # _TIF_NEED_RESCHED is set, call schedule
+-#
+-sysc_reschedule:
+- l %r1,BASED(.Lschedule)
+- la %r14,BASED(sysc_work_loop)
+- br %r1 # call scheduler
++#
++sysc_reschedule:
++ l %r1,BASED(.Lschedule)
++ la %r14,BASED(sysc_work_loop)
++ br %r1 # call scheduler
+
+ #
+ # _TIF_MCCK_PENDING is set, call handler
+@@ -301,11 +301,11 @@ sysc_mcck_pending:
+ #
+ # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+ #
+-sysc_sigpending:
++sysc_sigpending:
+ ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- l %r1,BASED(.Ldo_signal)
+- basr %r14,%r1 # call do_signal
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Ldo_signal)
++ basr %r14,%r1 # call do_signal
+ tm __TI_flags+3(%r9),_TIF_RESTART_SVC
+ bo BASED(sysc_restart)
+ tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
+@@ -317,11 +317,11 @@ sysc_sigpending:
+ #
+ sysc_restart:
+ ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
+- l %r7,SP_R2(%r15) # load new svc number
++ l %r7,SP_R2(%r15) # load new svc number
+ sla %r7,2
+ mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
+- lm %r2,%r6,SP_R2(%r15) # load svc arguments
+- b BASED(sysc_do_restart) # restart svc
++ lm %r2,%r6,SP_R2(%r15) # load svc arguments
++ b BASED(sysc_do_restart) # restart svc
+
+ #
+ # _TIF_SINGLE_STEP is set, call do_single_step
+@@ -338,8 +338,8 @@ sysc_singlestep:
+ # call trace before and after sys_call
+ #
+ sysc_tracesys:
+- l %r1,BASED(.Ltrace)
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Ltrace)
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,0
+ srl %r7,2
+ st %r7,SP_R2(%r15)
+@@ -347,19 +347,19 @@ sysc_tracesys:
+ clc SP_R2(4,%r15),BASED(.Lnr_syscalls)
+ bnl BASED(sysc_tracenogo)
+ l %r8,BASED(.Lsysc_table)
+- l %r7,SP_R2(%r15) # strace might have changed the
+- sll %r7,2 # system call
++ l %r7,SP_R2(%r15) # strace might have changed the
++ sll %r7,2 # system call
+ l %r8,0(%r7,%r8)
+ sysc_tracego:
+ lm %r3,%r6,SP_R3(%r15)
+ l %r2,SP_ORIG_R2(%r15)
+- basr %r14,%r8 # call sys_xxx
+- st %r2,SP_R2(%r15) # store return value
++ basr %r14,%r8 # call sys_xxx
++ st %r2,SP_R2(%r15) # store return value
+ sysc_tracenogo:
+ tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+- bz BASED(sysc_return)
++ bz BASED(sysc_return)
+ l %r1,BASED(.Ltrace)
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,1
+ la %r14,BASED(sysc_return)
+ br %r1
+@@ -367,17 +367,17 @@ sysc_tracenogo:
+ #
+ # a new process exits the kernel with ret_from_fork
+ #
+- .globl ret_from_fork
++ .globl ret_from_fork
+ ret_from_fork:
+ l %r13,__LC_SVC_NEW_PSW+4
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
+ bo BASED(0f)
+ st %r15,SP_R15(%r15) # store stack pointer for new kthread
+-0: l %r1,BASED(.Lschedtail)
+- basr %r14,%r1
++0: l %r1,BASED(.Lschedtail)
++ basr %r14,%r1
+ TRACE_IRQS_ON
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ b BASED(sysc_return)
+
+ #
+@@ -386,52 +386,51 @@ ret_from_fork:
+ # but are called with different parameter.
+ # return-address is set up above
+ #
+-sys_clone_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- l %r1,BASED(.Lclone)
+- br %r1 # branch to sys_clone
+-
+-sys_fork_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- l %r1,BASED(.Lfork)
+- br %r1 # branch to sys_fork
+-
+-sys_vfork_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- l %r1,BASED(.Lvfork)
+- br %r1 # branch to sys_vfork
+-
+-sys_execve_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- l %r1,BASED(.Lexecve)
+- lr %r12,%r14 # save return address
+- basr %r14,%r1 # call sys_execve
+- ltr %r2,%r2 # check if execve failed
+- bnz 0(%r12) # it did fail -> store result in gpr2
+- b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8
+- # in system_call/sysc_tracesys
+-
+-sys_sigreturn_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+- l %r1,BASED(.Lsigreturn)
+- br %r1 # branch to sys_sigreturn
+-
+-sys_rt_sigreturn_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+- l %r1,BASED(.Lrt_sigreturn)
+- br %r1 # branch to sys_sigreturn
++sys_clone_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Lclone)
++ br %r1 # branch to sys_clone
+
+-sys_sigaltstack_glue:
+- la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+- l %r1,BASED(.Lsigaltstack)
+- br %r1 # branch to sys_sigreturn
++sys_fork_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Lfork)
++ br %r1 # branch to sys_fork
+
++sys_vfork_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Lvfork)
++ br %r1 # branch to sys_vfork
++
++sys_execve_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Lexecve)
++ lr %r12,%r14 # save return address
++ basr %r14,%r1 # call sys_execve
++ ltr %r2,%r2 # check if execve failed
++ bnz 0(%r12) # it did fail -> store result in gpr2
++ b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8
++ # in system_call/sysc_tracesys
++
++sys_sigreturn_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
++ l %r1,BASED(.Lsigreturn)
++ br %r1 # branch to sys_sigreturn
++
++sys_rt_sigreturn_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
++ l %r1,BASED(.Lrt_sigreturn)
++ br %r1 # branch to sys_sigreturn
++
++sys_sigaltstack_glue:
++ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
++ l %r1,BASED(.Lsigaltstack)
++ br %r1 # branch to sys_sigreturn
+
+ /*
+ * Program check handler routine
+ */
+
+- .globl pgm_check_handler
++ .globl pgm_check_handler
+ pgm_check_handler:
+ /*
+ * First we need to check for a special case:
+@@ -448,8 +447,8 @@ pgm_check_handler:
+ */
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+ SAVE_ALL_BASE __LC_SAVE_AREA
+- tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+- bnz BASED(pgm_per) # got per exception -> special case
++ 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_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+@@ -461,29 +460,29 @@ pgm_check_handler:
+ pgm_no_vtime:
+ #endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+- l %r3,__LC_PGM_ILC # load program interruption code
++ l %r3,__LC_PGM_ILC # load program interruption code
+ la %r8,0x7f
+ nr %r8,%r3
+ pgm_do_call:
+- l %r7,BASED(.Ljump_table)
+- sll %r8,2
+- l %r7,0(%r8,%r7) # load address of handler routine
+- la %r2,SP_PTREGS(%r15) # address of register-save area
+- la %r14,BASED(sysc_return)
+- br %r7 # branch to interrupt-handler
++ l %r7,BASED(.Ljump_table)
++ sll %r8,2
++ l %r7,0(%r8,%r7) # load address of handler routine
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ la %r14,BASED(sysc_return)
++ br %r7 # branch to interrupt-handler
+
+ #
+ # handle per exception
+ #
+ pgm_per:
+- tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+- bnz BASED(pgm_per_std) # ok, normal per event from user space
++ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
++ bnz BASED(pgm_per_std) # ok, normal per event from user space
+ # ok its one of the special cases, now we need to find out which one
+- clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
+- be BASED(pgm_svcper)
++ clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
++ be BASED(pgm_svcper)
+ # no interesting special case, ignore PER event
+- lm %r12,%r15,__LC_SAVE_AREA
+- lpsw 0x28
++ lm %r12,%r15,__LC_SAVE_AREA
++ lpsw 0x28
+
+ #
+ # Normal per exception
+@@ -505,10 +504,12 @@ pgm_no_vtime2:
+ mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
+ mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+ oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
+- l %r3,__LC_PGM_ILC # load program interruption code
++ tm SP_PSW+1(%r15),0x01 # kernel per event ?
++ bz BASED(kernel_per)
++ l %r3,__LC_PGM_ILC # load program interruption code
+ la %r8,0x7f
+- nr %r8,%r3 # clear per-event-bit and ilc
+- be BASED(sysc_return) # only per or per+check ?
++ nr %r8,%r3 # clear per-event-bit and ilc
++ be BASED(sysc_return) # only per or per+check ?
+ b BASED(pgm_do_call)
+
+ #
+@@ -536,11 +537,21 @@ pgm_no_vtime3:
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ b BASED(sysc_do_svc)
+
++#
++# per was called from kernel, must be kprobes
++#
++kernel_per:
++ mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ l %r1,BASED(.Lhandle_per) # load adr. of per handler
++ la %r14,BASED(sysc_leave) # load adr. of system return
++ br %r1 # branch to do_single_step
++
+ /*
+ * IO interrupt handler routine
+ */
+
+- .globl io_int_handler
++ .globl io_int_handler
+ io_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+@@ -557,42 +568,42 @@ io_no_vtime:
+ #endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+- l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
+- la %r2,SP_PTREGS(%r15) # address of register-save area
+- basr %r14,%r1 # branch to standard irq handler
++ l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ basr %r14,%r1 # branch to standard irq handler
+ TRACE_IRQS_ON
+
+ io_return:
+- tm SP_PSW+1(%r15),0x01 # returning to user ?
++ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ #ifdef CONFIG_PREEMPT
+- bno BASED(io_preempt) # no -> check for preemptive scheduling
++ bno BASED(io_preempt) # no -> check for preemptive scheduling
+ #else
+- bno BASED(io_leave) # no-> skip resched & signal
++ bno BASED(io_leave) # no-> skip resched & signal
+ #endif
+ tm __TI_flags+3(%r9),_TIF_WORK_INT
+- bnz BASED(io_work) # there is work to do (signals etc.)
++ bnz BASED(io_work) # there is work to do (signals etc.)
+ io_leave:
+- RESTORE_ALL __LC_RETURN_PSW,0
++ RESTORE_ALL __LC_RETURN_PSW,0
+ io_done:
+
+ #ifdef CONFIG_PREEMPT
+ io_preempt:
+ icm %r0,15,__TI_precount(%r9)
+- bnz BASED(io_leave)
++ bnz BASED(io_leave)
+ l %r1,SP_R15(%r15)
+ 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
++ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+ io_resume_loop:
+ tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
+ bno BASED(io_leave)
+- mvc __TI_precount(4,%r9),BASED(.Lc_pactive)
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+- l %r1,BASED(.Lschedule)
++ mvc __TI_precount(4,%r9),BASED(.Lc_pactive)
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ l %r1,BASED(.Lschedule)
+ basr %r14,%r1 # call schedule
+- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+- xc __TI_precount(4,%r9),__TI_precount(%r9)
++ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
++ xc __TI_precount(4,%r9),__TI_precount(%r9)
+ b BASED(io_resume_loop)
+ #endif
+
+@@ -603,16 +614,16 @@ io_work:
+ l %r1,__LC_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
++ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+ #
+ # One of the work bits is on. Find out which one.
+ # Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGMASK, _TIF_NEED_RESCHED
+-# and _TIF_MCCK_PENDING
++# and _TIF_MCCK_PENDING
+ #
+ io_work_loop:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+- bo BASED(io_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 | _TIF_RESTORE_SIGMASK)
+@@ -625,36 +636,36 @@ io_work_loop:
+ io_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ la %r14,BASED(io_work_loop)
+- br %r1 # TIF bit will be cleared by handler
++ br %r1 # TIF bit will be cleared by handler
+
+ #
+ # _TIF_NEED_RESCHED is set, call schedule
+-#
+-io_reschedule:
+- l %r1,BASED(.Lschedule)
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+- basr %r14,%r1 # call scheduler
+- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
++#
++io_reschedule:
++ l %r1,BASED(.Lschedule)
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ basr %r14,%r1 # call scheduler
++ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ tm __TI_flags+3(%r9),_TIF_WORK_INT
+- bz BASED(io_leave) # there is no work to do
++ bz BASED(io_leave) # there is no work to do
+ b BASED(io_work_loop)
+
+ #
+ # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+ #
+-io_sigpending:
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- l %r1,BASED(.Ldo_signal)
+- basr %r14,%r1 # call do_signal
+- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
++io_sigpending:
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ l %r1,BASED(.Ldo_signal)
++ basr %r14,%r1 # call do_signal
++ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ b BASED(io_work_loop)
+
+ /*
+ * External interrupt handler routine
+ */
+
+- .globl ext_int_handler
++ .globl ext_int_handler
+ ext_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+@@ -671,8 +682,8 @@ ext_no_vtime:
+ #endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+- la %r2,SP_PTREGS(%r15) # address of register-save area
+- lh %r3,__LC_EXT_INT_CODE # get interruption code
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ lh %r3,__LC_EXT_INT_CODE # get interruption code
+ l %r1,BASED(.Ldo_extint)
+ basr %r14,%r1
+ TRACE_IRQS_ON
+@@ -684,13 +695,13 @@ __critical_end:
+ * Machine check handler routines
+ */
+
+- .globl mcck_int_handler
++ .globl mcck_int_handler
+ mcck_int_handler:
+ 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
+ la %r12,__LC_MCK_OLD_PSW
+- tm __LC_MCCK_CODE,0x80 # system damage?
++ tm __LC_MCCK_CODE,0x80 # system damage?
+ bo BASED(mcck_int_main) # yes -> rest of mcck code invalid
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
+@@ -729,7 +740,7 @@ mcck_int_main:
+ l %r15,__LC_PANIC_STACK # load panic stack
+ 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+- tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
++ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ bno BASED(mcck_no_vtime) # no -> skip cleanup critical
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ bz BASED(mcck_no_vtime)
+@@ -740,14 +751,14 @@ mcck_no_vtime:
+ #endif
+ 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
+- tm SP_PSW+1(%r15),0x01 # returning to user ?
++ l %r1,BASED(.Ls390_mcck)
++ 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
++ 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
++ 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
+@@ -771,36 +782,36 @@ mcck_return:
+ lm %r0,%r15,SP_R0(%r15) # load gprs 0-15
+ lpsw __LC_RETURN_MCCK_PSW # back to caller
+
+- RESTORE_ALL __LC_RETURN_MCCK_PSW,0
++ RESTORE_ALL __LC_RETURN_MCCK_PSW,0
+
+ #ifdef CONFIG_SMP
+ /*
+ * Restart interruption handler, kick starter for additional CPUs
+ */
+- .globl restart_int_handler
++ .globl restart_int_handler
+ restart_int_handler:
+- l %r15,__LC_SAVE_AREA+60 # load ksp
+- lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
+- lam %a0,%a15,__LC_AREGS_SAVE_AREA
+- lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone
+- stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
+- basr %r14,0
+- l %r14,restart_addr-.(%r14)
+- br %r14 # branch to start_secondary
++ l %r15,__LC_SAVE_AREA+60 # load ksp
++ lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
++ lam %a0,%a15,__LC_AREGS_SAVE_AREA
++ lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone
++ stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
++ basr %r14,0
++ l %r14,restart_addr-.(%r14)
++ br %r14 # branch to start_secondary
+ restart_addr:
+- .long start_secondary
++ .long start_secondary
+ #else
+ /*
+ * If we do not run with SMP enabled, let the new CPU crash ...
+ */
+- .globl restart_int_handler
++ .globl restart_int_handler
+ restart_int_handler:
+- basr %r1,0
++ basr %r1,0
+ restart_base:
+- lpsw restart_crash-restart_base(%r1)
+- .align 8
++ lpsw restart_crash-restart_base(%r1)
++ .align 8
+ restart_crash:
+- .long 0x000a0000,0x00000000
++ .long 0x000a0000,0x00000000
+ restart_go:
+ #endif
+
+@@ -822,11 +833,11 @@ stack_overflow:
+ be BASED(0f)
+ la %r1,__LC_SAVE_AREA+16
+ 0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack
+- xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
++ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+ l %r1,BASED(1f) # branch to kernel_stack_overflow
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ br %r1
+-1: .long kernel_stack_overflow
++1: .long kernel_stack_overflow
+ #endif
+
+ cleanup_table_system_call:
+@@ -928,10 +939,10 @@ cleanup_novtime:
+ cleanup_system_call_insn:
+ .long sysc_saveall + 0x80000000
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+- .long system_call + 0x80000000
+- .long sysc_vtime + 0x80000000
+- .long sysc_stime + 0x80000000
+- .long sysc_update + 0x80000000
++ .long system_call + 0x80000000
++ .long sysc_vtime + 0x80000000
++ .long sysc_stime + 0x80000000
++ .long sysc_update + 0x80000000
+ #endif
+
+ cleanup_sysc_return:
+@@ -997,57 +1008,57 @@ cleanup_io_leave_insn:
+ /*
+ * Integer constants
+ */
+- .align 4
+-.Lc_spsize: .long SP_SIZE
+-.Lc_overhead: .long STACK_FRAME_OVERHEAD
+-.Lc_pactive: .long PREEMPT_ACTIVE
+-.Lnr_syscalls: .long NR_syscalls
+-.L0x018: .short 0x018
+-.L0x020: .short 0x020
+-.L0x028: .short 0x028
+-.L0x030: .short 0x030
+-.L0x038: .short 0x038
+-.Lc_1: .long 1
++ .align 4
++.Lc_spsize: .long SP_SIZE
++.Lc_overhead: .long STACK_FRAME_OVERHEAD
++.Lc_pactive: .long PREEMPT_ACTIVE
++.Lnr_syscalls: .long NR_syscalls
++.L0x018: .short 0x018
++.L0x020: .short 0x020
++.L0x028: .short 0x028
++.L0x030: .short 0x030
++.L0x038: .short 0x038
++.Lc_1: .long 1
+
+ /*
+ * Symbol constants
+ */
+-.Ls390_mcck: .long s390_do_machine_check
++.Ls390_mcck: .long s390_do_machine_check
+ .Ls390_handle_mcck:
+- .long s390_handle_mcck
+-.Lmck_old_psw: .long __LC_MCK_OLD_PSW
+-.Ldo_IRQ: .long do_IRQ
+-.Ldo_extint: .long do_extint
+-.Ldo_signal: .long do_signal
+-.Lhandle_per: .long do_single_step
+-.Ljump_table: .long pgm_check_table
+-.Lschedule: .long schedule
+-.Lclone: .long sys_clone
+-.Lexecve: .long sys_execve
+-.Lfork: .long sys_fork
+-.Lrt_sigreturn:.long sys_rt_sigreturn
++ .long s390_handle_mcck
++.Lmck_old_psw: .long __LC_MCK_OLD_PSW
++.Ldo_IRQ: .long do_IRQ
++.Ldo_extint: .long do_extint
++.Ldo_signal: .long do_signal
++.Lhandle_per: .long do_single_step
++.Ljump_table: .long pgm_check_table
++.Lschedule: .long schedule
++.Lclone: .long sys_clone
++.Lexecve: .long sys_execve
++.Lfork: .long sys_fork
++.Lrt_sigreturn: .long sys_rt_sigreturn
+ .Lrt_sigsuspend:
+- .long sys_rt_sigsuspend
+-.Lsigreturn: .long sys_sigreturn
+-.Lsigsuspend: .long sys_sigsuspend
+-.Lsigaltstack: .long sys_sigaltstack
+-.Ltrace: .long syscall_trace
+-.Lvfork: .long sys_vfork
+-.Lschedtail: .long schedule_tail
+-.Lsysc_table: .long sys_call_table
++ .long sys_rt_sigsuspend
++.Lsigreturn: .long sys_sigreturn
++.Lsigsuspend: .long sys_sigsuspend
++.Lsigaltstack: .long sys_sigaltstack
++.Ltrace: .long syscall_trace
++.Lvfork: .long sys_vfork
++.Lschedtail: .long schedule_tail
++.Lsysc_table: .long sys_call_table
+ #ifdef CONFIG_TRACE_IRQFLAGS
+-.Ltrace_irq_on:.long trace_hardirqs_on
++.Ltrace_irq_on: .long trace_hardirqs_on
+ .Ltrace_irq_off:
+- .long trace_hardirqs_off
++ .long trace_hardirqs_off
+ #endif
+ .Lcritical_start:
+- .long __critical_start + 0x80000000
++ .long __critical_start + 0x80000000
+ .Lcritical_end:
+- .long __critical_end + 0x80000000
++ .long __critical_end + 0x80000000
+ .Lcleanup_critical:
+- .long cleanup_critical
++ .long cleanup_critical
+
+- .section .rodata, "a"
++ .section .rodata, "a"
+ #define SYSCALL(esa,esame,emu) .long esa
+ sys_call_table:
+ #include "syscalls.S"
+diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
+index 56f5f61..0f758c3 100644
+--- a/arch/s390/kernel/entry64.S
++++ b/arch/s390/kernel/entry64.S
+@@ -4,8 +4,8 @@
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ * Author(s): Martin Schwidefsky (schwidefsky at de.ibm.com),
+- * Hartmut Penner (hp at de.ibm.com),
+- * Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com),
++ * Hartmut Penner (hp at de.ibm.com),
++ * Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com),
+ * Heiko Carstens <heiko.carstens at de.ibm.com>
+ */
+
+@@ -24,29 +24,29 @@
+ * Stack layout for the system_call stack entry.
+ * The first few entries are identical to the user_regs_struct.
+ */
+-SP_PTREGS = STACK_FRAME_OVERHEAD
+-SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
+-SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+-SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
+-SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+-SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+-SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+-SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+-SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+-SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+-SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+-SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64
+-SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72
+-SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80
+-SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88
+-SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96
+-SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104
+-SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
+-SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
+-SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+-SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
+-SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
+-SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
++SP_PTREGS = STACK_FRAME_OVERHEAD
++SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
++SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
++SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
++SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
++SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
++SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
++SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
++SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
++SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
++SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
++SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64
++SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72
++SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80
++SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88
++SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96
++SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104
++SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
++SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
++SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
++SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
++SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
++SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
+
+ STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
+ STACK_SIZE = 1 << STACK_SHIFT
+@@ -71,14 +71,14 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_
+ #define TRACE_IRQS_OFF
+ #endif
+
+- .macro STORE_TIMER lc_offset
++ .macro STORE_TIMER lc_offset
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ stpt \lc_offset
+ #endif
+ .endm
+
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+- .macro UPDATE_VTIME lc_from,lc_to,lc_sum
++ .macro UPDATE_VTIME lc_from,lc_to,lc_sum
+ lg %r10,\lc_from
+ slg %r10,\lc_to
+ alg %r10,\lc_sum
+@@ -94,7 +94,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_
+ * R15 - kernel stack pointer
+ */
+
+- .macro SAVE_ALL_BASE savearea
++ .macro SAVE_ALL_BASE savearea
+ stmg %r12,%r15,\savearea
+ larl %r13,system_call
+ .endm
+@@ -139,8 +139,8 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_
+ .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
++ 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
+ icm %r12,12,__LC_SVC_ILC
+@@ -149,7 +149,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_
+ mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack
+ la %r12,0
+ stg %r12,__SF_BACKCHAIN(%r15)
+- .endm
++ .endm
+
+ .macro RESTORE_ALL psworg,sync
+ mvc \psworg(16),SP_PSW(%r15) # move user PSW to lowcore
+@@ -168,29 +168,29 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_
+ * Returns:
+ * gpr2 = prev
+ */
+- .globl __switch_to
++ .globl __switch_to
+ __switch_to:
+ tm __THREAD_per+4(%r3),0xe8 # is the new process using per ?
+ jz __switch_to_noper # if not we're fine
+- stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
+- clc __THREAD_per(24,%r3),__SF_EMPTY(%r15)
+- je __switch_to_noper # we got away without bashing TLB's
+- lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
++ stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
++ clc __THREAD_per(24,%r3),__SF_EMPTY(%r15)
++ je __switch_to_noper # we got away without bashing TLB's
++ lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
+ __switch_to_noper:
+- lg %r4,__THREAD_info(%r2) # get thread_info of prev
++ 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
++ stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
+ stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
+ lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
+- lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
++ lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
+ stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct
+ lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
+- lg %r3,__THREAD_info(%r3) # load thread_info from task struct
++ lg %r3,__THREAD_info(%r3) # load thread_info from task struct
+ stg %r3,__LC_THREAD_INFO
+ aghi %r3,STACK_SIZE
+ stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
+@@ -202,14 +202,14 @@ __critical_start:
+ * are executed with interrupts enabled.
+ */
+
+- .globl system_call
++ .globl system_call
+ system_call:
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+ sysc_saveall:
+ SAVE_ALL_BASE __LC_SAVE_AREA
+ SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+- CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+- llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
++ 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:
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+@@ -222,45 +222,45 @@ sysc_update:
+ #endif
+ sysc_do_svc:
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+- slag %r7,%r7,2 # *4 and test for svc 0
++ slag %r7,%r7,2 # *4 and test for svc 0
+ jnz sysc_nr_ok
+ # svc 0: system call number in %r1
+ cl %r1,BASED(.Lnr_syscalls)
+ jnl sysc_nr_ok
+- lgfr %r7,%r1 # clear high word in r1
+- slag %r7,%r7,2 # svc 0: system call number in %r1
++ lgfr %r7,%r1 # clear high word in r1
++ slag %r7,%r7,2 # svc 0: system call number in %r1
+ sysc_nr_ok:
+ mvc SP_ARGS(8,%r15),SP_R7(%r15)
+ sysc_do_restart:
+- larl %r10,sys_call_table
++ larl %r10,sys_call_table
+ #ifdef CONFIG_COMPAT
+ tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ?
+ jno sysc_noemu
+- larl %r10,sys_call_table_emu # use 31 bit emulation system calls
++ larl %r10,sys_call_table_emu # use 31 bit emulation system calls
+ sysc_noemu:
+ #endif
+ tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+- lgf %r8,0(%r7,%r10) # load address of system call routine
+- jnz sysc_tracesys
+- basr %r14,%r8 # call sys_xxxx
+- stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
+- # ATTENTION: check sys_execve_glue before
+- # changing anything here !!
++ lgf %r8,0(%r7,%r10) # load address of system call routine
++ jnz sysc_tracesys
++ basr %r14,%r8 # call sys_xxxx
++ stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
++ # ATTENTION: check sys_execve_glue before
++ # changing anything here !!
+
+ sysc_return:
+- tm SP_PSW+1(%r15),0x01 # returning to user ?
+- jno sysc_leave
++ tm SP_PSW+1(%r15),0x01 # returning to user ?
++ jno sysc_leave
+ tm __TI_flags+7(%r9),_TIF_WORK_SVC
+- jnz sysc_work # there is work to do (signals etc.)
++ jnz sysc_work # there is work to do (signals etc.)
+ sysc_leave:
+- RESTORE_ALL __LC_RETURN_PSW,1
++ RESTORE_ALL __LC_RETURN_PSW,1
+
+ #
+ # recheck if there is more work to do
+ #
+ sysc_work_loop:
+ tm __TI_flags+7(%r9),_TIF_WORK_SVC
+- jz sysc_leave # there is no work to do
++ jz sysc_leave # there is no work to do
+ #
+ # One of the work bits is on. Find out which one.
+ #
+@@ -279,25 +279,25 @@ sysc_work:
+
+ #
+ # _TIF_NEED_RESCHED is set, call schedule
+-#
+-sysc_reschedule:
+- larl %r14,sysc_work_loop
+- jg schedule # return point is sysc_return
++#
++sysc_reschedule:
++ larl %r14,sysc_work_loop
++ 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
++ jg s390_handle_mcck # TIF bit will be cleared by handler
+
+ #
+ # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+ #
+-sysc_sigpending:
++sysc_sigpending:
+ ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- brasl %r14,do_signal # call do_signal
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ brasl %r14,do_signal # call do_signal
+ tm __TI_flags+7(%r9),_TIF_RESTART_SVC
+ jo sysc_restart
+ tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
+@@ -309,11 +309,11 @@ sysc_sigpending:
+ #
+ sysc_restart:
+ ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
+- lg %r7,SP_R2(%r15) # load new svc number
+- slag %r7,%r7,2 # *4
++ lg %r7,SP_R2(%r15) # load new svc number
++ slag %r7,%r7,2 # *4
+ mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
+- lmg %r2,%r6,SP_R2(%r15) # load svc arguments
+- j sysc_do_restart # restart svc
++ lmg %r2,%r6,SP_R2(%r15) # load svc arguments
++ j sysc_do_restart # restart svc
+
+ #
+ # _TIF_SINGLE_STEP is set, call do_single_step
+@@ -326,49 +326,48 @@ sysc_singlestep:
+ larl %r14,sysc_return # load adr. of system return
+ jg do_single_step # branch to do_sigtrap
+
+-
+ #
+ # call syscall_trace before and after system call
+ # special linkage: %r12 contains the return address for trace_svc
+ #
+ sysc_tracesys:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,0
+ srl %r7,2
+- stg %r7,SP_R2(%r15)
+- brasl %r14,syscall_trace
++ stg %r7,SP_R2(%r15)
++ brasl %r14,syscall_trace
+ lghi %r0,NR_syscalls
+ clg %r0,SP_R2(%r15)
+ jnh sysc_tracenogo
+- lg %r7,SP_R2(%r15) # strace might have changed the
+- sll %r7,2 # system call
++ lg %r7,SP_R2(%r15) # strace might have changed the
++ sll %r7,2 # system call
+ lgf %r8,0(%r7,%r10)
+ sysc_tracego:
+- lmg %r3,%r6,SP_R3(%r15)
+- lg %r2,SP_ORIG_R2(%r15)
+- basr %r14,%r8 # call sys_xxx
+- stg %r2,SP_R2(%r15) # store return value
++ lmg %r3,%r6,SP_R3(%r15)
++ lg %r2,SP_ORIG_R2(%r15)
++ basr %r14,%r8 # call sys_xxx
++ stg %r2,SP_R2(%r15) # store return value
+ sysc_tracenogo:
+ tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+- jz sysc_return
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++ jz sysc_return
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,1
+- larl %r14,sysc_return # return point is sysc_return
++ larl %r14,sysc_return # return point is sysc_return
+ jg syscall_trace
+
+ #
+ # a new process exits the kernel with ret_from_fork
+ #
+- .globl ret_from_fork
++ .globl ret_from_fork
+ ret_from_fork:
+ lg %r13,__LC_SVC_NEW_PSW+8
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
+ jo 0f
+ stg %r15,SP_R15(%r15) # store stack pointer for new kthread
+-0: brasl %r14,schedule_tail
++0: brasl %r14,schedule_tail
+ TRACE_IRQS_ON
+- stosm 24(%r15),0x03 # reenable interrupts
++ stosm 24(%r15),0x03 # reenable interrupts
+ j sysc_return
+
+ #
+@@ -377,78 +376,78 @@ ret_from_fork:
+ # but are called with different parameter.
+ # return-address is set up above
+ #
+-sys_clone_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- jg sys_clone # branch to sys_clone
++sys_clone_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ jg sys_clone # branch to sys_clone
+
+ #ifdef CONFIG_COMPAT
+-sys32_clone_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- jg sys32_clone # branch to sys32_clone
++sys32_clone_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ jg sys32_clone # branch to sys32_clone
+ #endif
+
+-sys_fork_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- jg sys_fork # branch to sys_fork
+-
+-sys_vfork_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- jg sys_vfork # branch to sys_vfork
+-
+-sys_execve_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- lgr %r12,%r14 # save return address
+- brasl %r14,sys_execve # call sys_execve
+- ltgr %r2,%r2 # check if execve failed
+- bnz 0(%r12) # it did fail -> store result in gpr2
+- b 6(%r12) # SKIP STG 2,SP_R2(15) in
+- # system_call/sysc_tracesys
++sys_fork_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ jg sys_fork # branch to sys_fork
++
++sys_vfork_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ jg sys_vfork # branch to sys_vfork
++
++sys_execve_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ lgr %r12,%r14 # save return address
++ brasl %r14,sys_execve # call sys_execve
++ ltgr %r2,%r2 # check if execve failed
++ bnz 0(%r12) # it did fail -> store result in gpr2
++ b 6(%r12) # SKIP STG 2,SP_R2(15) in
++ # system_call/sysc_tracesys
+ #ifdef CONFIG_COMPAT
+-sys32_execve_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs
+- lgr %r12,%r14 # save return address
+- brasl %r14,sys32_execve # call sys32_execve
+- ltgr %r2,%r2 # check if execve failed
+- bnz 0(%r12) # it did fail -> store result in gpr2
+- b 6(%r12) # SKIP STG 2,SP_R2(15) in
+- # system_call/sysc_tracesys
++sys32_execve_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs
++ lgr %r12,%r14 # save return address
++ brasl %r14,sys32_execve # call sys32_execve
++ ltgr %r2,%r2 # check if execve failed
++ bnz 0(%r12) # it did fail -> store result in gpr2
++ b 6(%r12) # SKIP STG 2,SP_R2(15) in
++ # system_call/sysc_tracesys
+ #endif
+
+-sys_sigreturn_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+- jg sys_sigreturn # branch to sys_sigreturn
++sys_sigreturn_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
++ jg sys_sigreturn # branch to sys_sigreturn
+
+ #ifdef CONFIG_COMPAT
+-sys32_sigreturn_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+- jg sys32_sigreturn # branch to sys32_sigreturn
++sys32_sigreturn_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
++ jg sys32_sigreturn # branch to sys32_sigreturn
+ #endif
+
+-sys_rt_sigreturn_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+- jg sys_rt_sigreturn # branch to sys_sigreturn
++sys_rt_sigreturn_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
++ jg sys_rt_sigreturn # branch to sys_sigreturn
+
+ #ifdef CONFIG_COMPAT
+-sys32_rt_sigreturn_glue:
+- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+- jg sys32_rt_sigreturn # branch to sys32_sigreturn
++sys32_rt_sigreturn_glue:
++ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
++ jg sys32_rt_sigreturn # branch to sys32_sigreturn
+ #endif
+
+ sys_sigaltstack_glue:
+- la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+- jg sys_sigaltstack # branch to sys_sigreturn
++ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
++ jg sys_sigaltstack # branch to sys_sigreturn
+
+ #ifdef CONFIG_COMPAT
+ sys32_sigaltstack_glue:
+- la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+- jg sys32_sigaltstack_wrapper # branch to sys_sigreturn
++ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
++ jg sys32_sigaltstack_wrapper # branch to sys_sigreturn
+ #endif
+
+ /*
+ * Program check handler routine
+ */
+
+- .globl pgm_check_handler
++ .globl pgm_check_handler
+ pgm_check_handler:
+ /*
+ * First we need to check for a special case:
+@@ -465,8 +464,8 @@ pgm_check_handler:
+ */
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+ SAVE_ALL_BASE __LC_SAVE_AREA
+- tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+- jnz pgm_per # got per exception -> special case
++ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
++ jnz pgm_per # got per exception -> special case
+ SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+@@ -478,29 +477,29 @@ pgm_check_handler:
+ pgm_no_vtime:
+ #endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+- lgf %r3,__LC_PGM_ILC # load program interruption code
++ lgf %r3,__LC_PGM_ILC # load program interruption code
+ lghi %r8,0x7f
+ ngr %r8,%r3
+ pgm_do_call:
+- sll %r8,3
+- larl %r1,pgm_check_table
+- lg %r1,0(%r8,%r1) # load address of handler routine
+- la %r2,SP_PTREGS(%r15) # address of register-save area
++ sll %r8,3
++ larl %r1,pgm_check_table
++ lg %r1,0(%r8,%r1) # load address of handler routine
++ la %r2,SP_PTREGS(%r15) # address of register-save area
+ larl %r14,sysc_return
+- br %r1 # branch to interrupt-handler
++ br %r1 # branch to interrupt-handler
+
+ #
+ # handle per exception
+ #
+ pgm_per:
+- tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+- jnz pgm_per_std # ok, normal per event from user space
++ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
++ jnz pgm_per_std # ok, normal per event from user space
+ # ok its one of the special cases, now we need to find out which one
+- clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
+- je pgm_svcper
++ clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
++ je pgm_svcper
+ # no interesting special case, ignore PER event
+ lmg %r12,%r15,__LC_SAVE_AREA
+- lpswe __LC_PGM_OLD_PSW
++ lpswe __LC_PGM_OLD_PSW
+
+ #
+ # Normal per exception
+@@ -518,13 +517,15 @@ pgm_no_vtime2:
+ #endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ lg %r1,__TI_task(%r9)
++ tm SP_PSW+1(%r15),0x01 # kernel per event ?
++ jz kernel_per
+ mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
+ mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
+ mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+ oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
+- lgf %r3,__LC_PGM_ILC # load program interruption code
++ lgf %r3,__LC_PGM_ILC # load program interruption code
+ lghi %r8,0x7f
+- ngr %r8,%r3 # clear per-event-bit and ilc
++ ngr %r8,%r3 # clear per-event-bit and ilc
+ je sysc_return
+ j pgm_do_call
+
+@@ -542,7 +543,7 @@ pgm_svcper:
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+ pgm_no_vtime3:
+ #endif
+- llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
++ llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ lg %r1,__TI_task(%r9)
+ mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
+@@ -553,10 +554,20 @@ pgm_no_vtime3:
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ j sysc_do_svc
+
++#
++# per was called from kernel, must be kprobes
++#
++kernel_per:
++ lhi %r0,__LC_PGM_OLD_PSW
++ sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ larl %r14,sysc_leave # load adr. of system ret, no work
++ jg do_single_step # branch to do_single_step
++
+ /*
+ * IO interrupt handler routine
+ */
+- .globl io_int_handler
++ .globl io_int_handler
+ io_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+@@ -573,42 +584,42 @@ io_no_vtime:
+ #endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+- la %r2,SP_PTREGS(%r15) # address of register-save area
+- brasl %r14,do_IRQ # call standard irq handler
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ brasl %r14,do_IRQ # call standard irq handler
+ TRACE_IRQS_ON
+
+ io_return:
+- tm SP_PSW+1(%r15),0x01 # returning to user ?
++ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ #ifdef CONFIG_PREEMPT
+- jno io_preempt # no -> check for preemptive scheduling
++ jno io_preempt # no -> check for preemptive scheduling
+ #else
+- jno io_leave # no-> skip resched & signal
++ jno io_leave # no-> skip resched & signal
+ #endif
+ tm __TI_flags+7(%r9),_TIF_WORK_INT
+- jnz io_work # there is work to do (signals etc.)
++ jnz io_work # there is work to do (signals etc.)
+ io_leave:
+- RESTORE_ALL __LC_RETURN_PSW,0
++ RESTORE_ALL __LC_RETURN_PSW,0
+ io_done:
+
+ #ifdef CONFIG_PREEMPT
+ io_preempt:
+- icm %r0,15,__TI_precount(%r9)
+- jnz io_leave
++ icm %r0,15,__TI_precount(%r9)
++ jnz io_leave
+ # switch to kernel stack
+ lg %r1,SP_R15(%r15)
+ aghi %r1,-SP_SIZE
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+- xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
++ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+ io_resume_loop:
+ tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
+ jno io_leave
+- larl %r1,.Lc_pactive
+- mvc __TI_precount(4,%r9),0(%r1)
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+- brasl %r14,schedule # call schedule
+- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+- xc __TI_precount(4,%r9),__TI_precount(%r9)
++ larl %r1,.Lc_pactive
++ mvc __TI_precount(4,%r9),0(%r1)
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ brasl %r14,schedule # call schedule
++ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
++ xc __TI_precount(4,%r9),__TI_precount(%r9)
+ j io_resume_loop
+ #endif
+
+@@ -619,7 +630,7 @@ io_work:
+ lg %r1,__LC_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
++ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+ #
+ # One of the work bits is on. Find out which one.
+@@ -644,11 +655,11 @@ io_mcck_pending:
+
+ #
+ # _TIF_NEED_RESCHED is set, call schedule
+-#
+-io_reschedule:
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+- brasl %r14,schedule # call scheduler
+- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
++#
++io_reschedule:
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ brasl %r14,schedule # call scheduler
++ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ tm __TI_flags+7(%r9),_TIF_WORK_INT
+ jz io_leave # there is no work to do
+ j io_work_loop
+@@ -656,17 +667,17 @@ io_reschedule:
+ #
+ # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+ #
+-io_sigpending:
+- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++io_sigpending:
++ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,do_signal # call do_signal
+- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
++ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ j io_work_loop
+
+ /*
+ * External interrupt handler routine
+ */
+- .globl ext_int_handler
++ .globl ext_int_handler
+ ext_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+@@ -683,9 +694,9 @@ ext_no_vtime:
+ #endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+- la %r2,SP_PTREGS(%r15) # address of register-save area
+- llgh %r3,__LC_EXT_INT_CODE # get interruption code
+- brasl %r14,do_extint
++ la %r2,SP_PTREGS(%r15) # address of register-save area
++ llgh %r3,__LC_EXT_INT_CODE # get interruption code
++ brasl %r14,do_extint
+ TRACE_IRQS_ON
+ j io_return
+
+@@ -694,14 +705,14 @@ __critical_end:
+ /*
+ * Machine check handler routines
+ */
+- .globl mcck_int_handler
++ .globl mcck_int_handler
+ mcck_int_handler:
+ 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
++ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
+ SAVE_ALL_BASE __LC_SAVE_AREA+64
+ la %r12,__LC_MCK_OLD_PSW
+- tm __LC_MCCK_CODE,0x80 # system damage?
++ tm __LC_MCCK_CODE,0x80 # system damage?
+ jo mcck_int_main # yes -> rest of mcck code invalid
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ la %r14,4095
+@@ -725,19 +736,19 @@ mcck_int_handler:
+ #endif
+ 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
++ 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)
++ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
+ jl mcck_int_main
+- brasl %r14,cleanup_critical
++ brasl %r14,cleanup_critical
+ mcck_int_main:
+- lg %r14,__LC_PANIC_STACK # are we already on the panic stack?
++ 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
++ lg %r15,__LC_PANIC_STACK # load panic stack
+ 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+@@ -752,7 +763,7 @@ mcck_no_vtime:
+ 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 ?
++ 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
+@@ -782,28 +793,28 @@ mcck_return:
+ /*
+ * Restart interruption handler, kick starter for additional CPUs
+ */
+- .globl restart_int_handler
++ .globl restart_int_handler
+ restart_int_handler:
+- lg %r15,__LC_SAVE_AREA+120 # load ksp
+- lghi %r10,__LC_CREGS_SAVE_AREA
+- lctlg %c0,%c15,0(%r10) # get new ctl regs
+- lghi %r10,__LC_AREGS_SAVE_AREA
+- lam %a0,%a15,0(%r10)
+- lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
+- stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
+- jg start_secondary
++ lg %r15,__LC_SAVE_AREA+120 # load ksp
++ lghi %r10,__LC_CREGS_SAVE_AREA
++ lctlg %c0,%c15,0(%r10) # get new ctl regs
++ lghi %r10,__LC_AREGS_SAVE_AREA
++ lam %a0,%a15,0(%r10)
++ lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
++ stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
++ jg start_secondary
+ #else
+ /*
+ * If we do not run with SMP enabled, let the new CPU crash ...
+ */
+- .globl restart_int_handler
++ .globl restart_int_handler
+ restart_int_handler:
+- basr %r1,0
++ basr %r1,0
+ restart_base:
+- lpswe restart_crash-restart_base(%r1)
+- .align 8
++ lpswe restart_crash-restart_base(%r1)
++ .align 8
+ restart_crash:
+- .long 0x000a0000,0x00000000,0x00000000,0x00000000
++ .long 0x000a0000,0x00000000,0x00000000,0x00000000
+ restart_go:
+ #endif
+
+@@ -815,7 +826,7 @@ restart_go:
+ */
+ stack_overflow:
+ lg %r15,__LC_PANIC_STACK # change to panic stack
+- aghi %r1,-SP_SIZE
++ aghi %r15,-SP_SIZE
+ mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
+ stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
+ la %r1,__LC_SAVE_AREA
+@@ -823,10 +834,10 @@ stack_overflow:
+ je 0f
+ chi %r12,__LC_PGM_OLD_PSW
+ je 0f
+- la %r1,__LC_SAVE_AREA+16
+-0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
+- xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+- la %r2,SP_PTREGS(%r15) # load pt_regs
++ la %r1,__LC_SAVE_AREA+32
++0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
++ xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
++ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg kernel_stack_overflow
+ #endif
+
+@@ -929,10 +940,10 @@ cleanup_novtime:
+ cleanup_system_call_insn:
+ .quad sysc_saveall
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+- .quad system_call
+- .quad sysc_vtime
+- .quad sysc_stime
+- .quad sysc_update
++ .quad system_call
++ .quad sysc_vtime
++ .quad sysc_stime
++ .quad sysc_update
+ #endif
+
+ cleanup_sysc_return:
+@@ -998,21 +1009,21 @@ cleanup_io_leave_insn:
+ /*
+ * Integer constants
+ */
+- .align 4
++ .align 4
+ .Lconst:
+-.Lc_pactive: .long PREEMPT_ACTIVE
+-.Lnr_syscalls: .long NR_syscalls
+-.L0x0130: .short 0x130
+-.L0x0140: .short 0x140
+-.L0x0150: .short 0x150
+-.L0x0160: .short 0x160
+-.L0x0170: .short 0x170
++.Lc_pactive: .long PREEMPT_ACTIVE
++.Lnr_syscalls: .long NR_syscalls
++.L0x0130: .short 0x130
++.L0x0140: .short 0x140
++.L0x0150: .short 0x150
++.L0x0160: .short 0x160
++.L0x0170: .short 0x170
+ .Lcritical_start:
+- .quad __critical_start
++ .quad __critical_start
+ .Lcritical_end:
+- .quad __critical_end
++ .quad __critical_end
+
+- .section .rodata, "a"
++ .section .rodata, "a"
+ #define SYSCALL(esa,esame,emu) .long esame
+ sys_call_table:
+ #include "syscalls.S"
+diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
+index adad886..0cf59bb 100644
+--- a/arch/s390/kernel/head.S
++++ b/arch/s390/kernel/head.S
+@@ -36,508 +36,451 @@
+ #endif
+
+ #ifndef CONFIG_IPL
+- .org 0
+- .long 0x00080000,0x80000000+startup # Just a restart PSW
++ .org 0
++ .long 0x00080000,0x80000000+startup # Just a restart PSW
+ #else
+ #ifdef CONFIG_IPL_TAPE
+ #define IPL_BS 1024
+- .org 0
+- .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+- .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
+- .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
+- .long 0x00000000,0x00000000 # external old psw
+- .long 0x00000000,0x00000000 # svc old psw
+- .long 0x00000000,0x00000000 # program check old psw
+- .long 0x00000000,0x00000000 # machine check old psw
+- .long 0x00000000,0x00000000 # io old psw
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x000a0000,0x00000058 # external new psw
+- .long 0x000a0000,0x00000060 # svc new psw
+- .long 0x000a0000,0x00000068 # program check new psw
+- .long 0x000a0000,0x00000070 # machine check new psw
+- .long 0x00080000,0x80000000+.Lioint # io new psw
+-
+- .org 0x100
++ .org 0
++ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
++ .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
++ .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
++ .long 0x00000000,0x00000000 # external old psw
++ .long 0x00000000,0x00000000 # svc old psw
++ .long 0x00000000,0x00000000 # program check old psw
++ .long 0x00000000,0x00000000 # machine check old psw
++ .long 0x00000000,0x00000000 # io old psw
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x000a0000,0x00000058 # external new psw
++ .long 0x000a0000,0x00000060 # svc new psw
++ .long 0x000a0000,0x00000068 # program check new psw
++ .long 0x000a0000,0x00000070 # machine check new psw
++ .long 0x00080000,0x80000000+.Lioint # io new psw
++
++ .org 0x100
+ #
+ # subroutine for loading from tape
+-# Paramters:
++# Paramters:
+ # R1 = device number
+ # R2 = load address
+-.Lloader:
+- st %r14,.Lldret
+- la %r3,.Lorbread # r3 = address of orb
+- la %r5,.Lirb # r5 = address of irb
+- st %r2,.Lccwread+4 # initialize CCW data addresses
+- lctl %c6,%c6,.Lcr6
+- slr %r2,%r2
++.Lloader:
++ st %r14,.Lldret
++ la %r3,.Lorbread # r3 = address of orb
++ la %r5,.Lirb # r5 = address of irb
++ st %r2,.Lccwread+4 # initialize CCW data addresses
++ lctl %c6,%c6,.Lcr6
++ slr %r2,%r2
+ .Lldlp:
+- la %r6,3 # 3 retries
++ la %r6,3 # 3 retries
+ .Lssch:
+- ssch 0(%r3) # load chunk of IPL_BS bytes
+- bnz .Llderr
++ ssch 0(%r3) # load chunk of IPL_BS bytes
++ bnz .Llderr
+ .Lw4end:
+- bas %r14,.Lwait4io
+- tm 8(%r5),0x82 # do we have a problem ?
+- bnz .Lrecov
+- slr %r7,%r7
+- icm %r7,3,10(%r5) # get residual count
+- lcr %r7,%r7
+- la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
+- ar %r2,%r7 # add to total size
+- tm 8(%r5),0x01 # found a tape mark ?
+- bnz .Ldone
+- l %r0,.Lccwread+4 # update CCW data addresses
+- ar %r0,%r7
+- st %r0,.Lccwread+4
+- b .Lldlp
++ bas %r14,.Lwait4io
++ tm 8(%r5),0x82 # do we have a problem ?
++ bnz .Lrecov
++ slr %r7,%r7
++ icm %r7,3,10(%r5) # get residual count
++ lcr %r7,%r7
++ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
++ ar %r2,%r7 # add to total size
++ tm 8(%r5),0x01 # found a tape mark ?
++ bnz .Ldone
++ l %r0,.Lccwread+4 # update CCW data addresses
++ ar %r0,%r7
++ st %r0,.Lccwread+4
++ b .Lldlp
+ .Ldone:
+- l %r14,.Lldret
+- br %r14 # r2 contains the total size
++ l %r14,.Lldret
++ br %r14 # r2 contains the total size
+ .Lrecov:
+- bas %r14,.Lsense # do the sensing
+- bct %r6,.Lssch # dec. retry count & branch
+- b .Llderr
++ bas %r14,.Lsense # do the sensing
++ bct %r6,.Lssch # dec. retry count & branch
++ b .Llderr
+ #
+ # Sense subroutine
+ #
+ .Lsense:
+- st %r14,.Lsnsret
+- la %r7,.Lorbsense
+- ssch 0(%r7) # start sense command
+- bnz .Llderr
+- bas %r14,.Lwait4io
+- l %r14,.Lsnsret
+- tm 8(%r5),0x82 # do we have a problem ?
+- bnz .Llderr
+- br %r14
++ st %r14,.Lsnsret
++ la %r7,.Lorbsense
++ ssch 0(%r7) # start sense command
++ bnz .Llderr
++ bas %r14,.Lwait4io
++ l %r14,.Lsnsret
++ tm 8(%r5),0x82 # do we have a problem ?
++ bnz .Llderr
++ br %r14
+ #
+ # Wait for interrupt subroutine
+ #
+ .Lwait4io:
+- lpsw .Lwaitpsw
++ lpsw .Lwaitpsw
+ .Lioint:
+- c %r1,0xb8 # compare subchannel number
+- bne .Lwait4io
+- tsch 0(%r5)
+- slr %r0,%r0
+- tm 8(%r5),0x82 # do we have a problem ?
+- bnz .Lwtexit
+- tm 8(%r5),0x04 # got device end ?
+- bz .Lwait4io
++ c %r1,0xb8 # compare subchannel number
++ bne .Lwait4io
++ tsch 0(%r5)
++ slr %r0,%r0
++ tm 8(%r5),0x82 # do we have a problem ?
++ bnz .Lwtexit
++ tm 8(%r5),0x04 # got device end ?
++ bz .Lwait4io
+ .Lwtexit:
+- br %r14
++ br %r14
+ .Llderr:
+- lpsw .Lcrash
++ lpsw .Lcrash
+
+- .align 8
++ .align 8
+ .Lorbread:
+- .long 0x00000000,0x0080ff00,.Lccwread
+- .align 8
++ .long 0x00000000,0x0080ff00,.Lccwread
++ .align 8
+ .Lorbsense:
+- .long 0x00000000,0x0080ff00,.Lccwsense
+- .align 8
++ .long 0x00000000,0x0080ff00,.Lccwsense
++ .align 8
+ .Lccwread:
+- .long 0x02200000+IPL_BS,0x00000000
++ .long 0x02200000+IPL_BS,0x00000000
+ .Lccwsense:
+- .long 0x04200001,0x00000000
++ .long 0x04200001,0x00000000
+ .Lwaitpsw:
+- .long 0x020a0000,0x80000000+.Lioint
++ .long 0x020a0000,0x80000000+.Lioint
+
+-.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+-.Lcr6: .long 0xff000000
+- .align 8
+-.Lcrash:.long 0x000a0000,0x00000000
+-.Lldret:.long 0
++.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++.Lcr6: .long 0xff000000
++ .align 8
++.Lcrash:.long 0x000a0000,0x00000000
++.Lldret:.long 0
+ .Lsnsret: .long 0
+-#endif /* CONFIG_IPL_TAPE */
++#endif /* CONFIG_IPL_TAPE */
+
+ #ifdef CONFIG_IPL_VM
+-#define IPL_BS 0x730
+- .org 0
+- .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+- .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
+- .long 0x02000068,0x60000050 # (a PSW and two CCWs).
+- .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
+- .long 0x020000f0,0x60000050 # The next 160 byte are loaded
+- .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
+- .long 0x02000190,0x60000050 # They form the continuation
+- .long 0x020001e0,0x60000050 # of the CCW program started
+- .long 0x02000230,0x60000050 # by ipl and load the range
+- .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
+- .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
+- .long 0x02000320,0x60000050 # in memory. At the end of
+- .long 0x02000370,0x60000050 # the channel program the PSW
+- .long 0x020003c0,0x60000050 # at location 0 is loaded.
+- .long 0x02000410,0x60000050 # Initial processing starts
+- .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
+- .long 0x020004b0,0x60000050
+- .long 0x02000500,0x60000050
+- .long 0x02000550,0x60000050
+- .long 0x020005a0,0x60000050
+- .long 0x020005f0,0x60000050
+- .long 0x02000640,0x60000050
+- .long 0x02000690,0x60000050
+- .long 0x020006e0,0x20000050
+-
+- .org 0xf0
++#define IPL_BS 0x730
++ .org 0
++ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
++ .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
++ .long 0x02000068,0x60000050 # (a PSW and two CCWs).
++ .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
++ .long 0x020000f0,0x60000050 # The next 160 byte are loaded
++ .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
++ .long 0x02000190,0x60000050 # They form the continuation
++ .long 0x020001e0,0x60000050 # of the CCW program started
++ .long 0x02000230,0x60000050 # by ipl and load the range
++ .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
++ .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
++ .long 0x02000320,0x60000050 # in memory. At the end of
++ .long 0x02000370,0x60000050 # the channel program the PSW
++ .long 0x020003c0,0x60000050 # at location 0 is loaded.
++ .long 0x02000410,0x60000050 # Initial processing starts
++ .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
++ .long 0x020004b0,0x60000050
++ .long 0x02000500,0x60000050
++ .long 0x02000550,0x60000050
++ .long 0x020005a0,0x60000050
++ .long 0x020005f0,0x60000050
++ .long 0x02000640,0x60000050
++ .long 0x02000690,0x60000050
++ .long 0x020006e0,0x20000050
++
++ .org 0xf0
+ #
+ # subroutine for loading cards from the reader
+ #
+-.Lloader:
+- la %r3,.Lorb # r2 = address of orb into r2
+- la %r5,.Lirb # r4 = address of irb
+- la %r6,.Lccws
+- la %r7,20
++.Lloader:
++ la %r3,.Lorb # r2 = address of orb into r2
++ la %r5,.Lirb # r4 = address of irb
++ la %r6,.Lccws
++ la %r7,20
+ .Linit:
+- st %r2,4(%r6) # initialize CCW data addresses
+- la %r2,0x50(%r2)
+- la %r6,8(%r6)
+- bct 7,.Linit
++ st %r2,4(%r6) # initialize CCW data addresses
++ la %r2,0x50(%r2)
++ la %r6,8(%r6)
++ bct 7,.Linit
+
+- lctl %c6,%c6,.Lcr6 # set IO subclass mask
+- slr %r2,%r2
++ lctl %c6,%c6,.Lcr6 # set IO subclass mask
++ slr %r2,%r2
+ .Lldlp:
+- ssch 0(%r3) # load chunk of 1600 bytes
+- bnz .Llderr
++ ssch 0(%r3) # load chunk of 1600 bytes
++ bnz .Llderr
+ .Lwait4irq:
+- mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
+- lpsw .Lwaitpsw
++ mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
++ lpsw .Lwaitpsw
+ .Lioint:
+- c %r1,0xb8 # compare subchannel number
+- bne .Lwait4irq
+- tsch 0(%r5)
+-
+- slr %r0,%r0
+- ic %r0,8(%r5) # get device status
+- chi %r0,8 # channel end ?
+- be .Lcont
+- chi %r0,12 # channel end + device end ?
+- be .Lcont
+-
+- l %r0,4(%r5)
+- s %r0,8(%r3) # r0/8 = number of ccws executed
+- mhi %r0,10 # *10 = number of bytes in ccws
+- lh %r3,10(%r5) # get residual count
+- sr %r0,%r3 # #ccws*80-residual=#bytes read
+- ar %r2,%r0
+-
+- br %r14 # r2 contains the total size
++ c %r1,0xb8 # compare subchannel number
++ bne .Lwait4irq
++ tsch 0(%r5)
++
++ slr %r0,%r0
++ ic %r0,8(%r5) # get device status
++ chi %r0,8 # channel end ?
++ be .Lcont
++ chi %r0,12 # channel end + device end ?
++ be .Lcont
++
++ l %r0,4(%r5)
++ s %r0,8(%r3) # r0/8 = number of ccws executed
++ mhi %r0,10 # *10 = number of bytes in ccws
++ lh %r3,10(%r5) # get residual count
++ sr %r0,%r3 # #ccws*80-residual=#bytes read
++ ar %r2,%r0
++
++ br %r14 # r2 contains the total size
+
+ .Lcont:
+- ahi %r2,0x640 # add 0x640 to total size
+- la %r6,.Lccws
+- la %r7,20
++ ahi %r2,0x640 # add 0x640 to total size
++ la %r6,.Lccws
++ la %r7,20
+ .Lincr:
+- l %r0,4(%r6) # update CCW data addresses
+- ahi %r0,0x640
+- st %r0,4(%r6)
+- ahi %r6,8
+- bct 7,.Lincr
++ l %r0,4(%r6) # update CCW data addresses
++ ahi %r0,0x640
++ st %r0,4(%r6)
++ ahi %r6,8
++ bct 7,.Lincr
+
+- b .Lldlp
++ b .Lldlp
+ .Llderr:
+- lpsw .Lcrash
+-
+- .align 8
+-.Lorb: .long 0x00000000,0x0080ff00,.Lccws
+-.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+-.Lcr6: .long 0xff000000
+-.Lloadp:.long 0,0
+- .align 8
+-.Lcrash:.long 0x000a0000,0x00000000
++ lpsw .Lcrash
++
++ .align 8
++.Lorb: .long 0x00000000,0x0080ff00,.Lccws
++.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++.Lcr6: .long 0xff000000
++.Lloadp:.long 0,0
++ .align 8
++.Lcrash:.long 0x000a0000,0x00000000
+ .Lnewpsw:
+- .long 0x00080000,0x80000000+.Lioint
++ .long 0x00080000,0x80000000+.Lioint
+ .Lwaitpsw:
+- .long 0x020a0000,0x80000000+.Lioint
++ .long 0x020a0000,0x80000000+.Lioint
+
+- .align 8
+-.Lccws: .rept 19
+- .long 0x02600050,0x00000000
+- .endr
+- .long 0x02200050,0x00000000
+-#endif /* CONFIG_IPL_VM */
++ .align 8
++.Lccws: .rept 19
++ .long 0x02600050,0x00000000
++ .endr
++ .long 0x02200050,0x00000000
++#endif /* CONFIG_IPL_VM */
+
+ iplstart:
+- lh %r1,0xb8 # test if subchannel number
+- bct %r1,.Lnoload # is valid
+- l %r1,0xb8 # load ipl subchannel number
+- la %r2,IPL_BS # load start address
+- bas %r14,.Lloader # load rest of ipl image
+- l %r12,.Lparm # pointer to parameter area
+- st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number
++ lh %r1,0xb8 # test if subchannel number
++ bct %r1,.Lnoload # is valid
++ l %r1,0xb8 # load ipl subchannel number
++ la %r2,IPL_BS # load start address
++ bas %r14,.Lloader # load rest of ipl image
++ l %r12,.Lparm # pointer to parameter area
++ st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number
+
+ #
+ # load parameter file from ipl device
+ #
+ .Lagain1:
+- l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # ramdisk loc. is temp
+- bas %r14,.Lloader # load parameter file
+- ltr %r2,%r2 # got anything ?
+- bz .Lnopf
+- chi %r2,895
+- bnh .Lnotrunc
+- la %r2,895
++ l %r2,.Linitrd # ramdisk loc. is temp
++ bas %r14,.Lloader # load parameter file
++ ltr %r2,%r2 # got anything ?
++ bz .Lnopf
++ chi %r2,895
++ bnh .Lnotrunc
++ la %r2,895
+ .Lnotrunc:
+- l %r4,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
+- clc 0(3,%r4),.L_hdr # if it is HDRx
+- bz .Lagain1 # skip dataset header
+- clc 0(3,%r4),.L_eof # if it is EOFx
+- bz .Lagain1 # skip dateset trailer
+- la %r5,0(%r4,%r2)
+- lr %r3,%r2
++ l %r4,.Linitrd
++ clc 0(3,%r4),.L_hdr # if it is HDRx
++ bz .Lagain1 # skip dataset header
++ clc 0(3,%r4),.L_eof # if it is EOFx
++ bz .Lagain1 # skip dateset trailer
++ la %r5,0(%r4,%r2)
++ lr %r3,%r2
+ .Lidebc:
+- tm 0(%r5),0x80 # high order bit set ?
+- bo .Ldocv # yes -> convert from EBCDIC
+- ahi %r5,-1
+- bct %r3,.Lidebc
+- b .Lnocv
++ tm 0(%r5),0x80 # high order bit set ?
++ bo .Ldocv # yes -> convert from EBCDIC
++ ahi %r5,-1
++ bct %r3,.Lidebc
++ b .Lnocv
+ .Ldocv:
+- l %r3,.Lcvtab
+- tr 0(256,%r4),0(%r3) # convert parameters to ascii
+- tr 256(256,%r4),0(%r3)
+- tr 512(256,%r4),0(%r3)
+- tr 768(122,%r4),0(%r3)
+-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+- mvc 0(256,%r3),0(%r4)
+- mvc 256(256,%r3),256(%r4)
+- mvc 512(256,%r3),512(%r4)
+- mvc 768(122,%r3),768(%r4)
+- slr %r0,%r0
+- b .Lcntlp
++ l %r3,.Lcvtab
++ tr 0(256,%r4),0(%r3) # convert parameters to ascii
++ tr 256(256,%r4),0(%r3)
++ tr 512(256,%r4),0(%r3)
++ tr 768(122,%r4),0(%r3)
++.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
++ mvc 0(256,%r3),0(%r4)
++ mvc 256(256,%r3),256(%r4)
++ mvc 512(256,%r3),512(%r4)
++ mvc 768(122,%r3),768(%r4)
++ slr %r0,%r0
++ b .Lcntlp
+ .Ldelspc:
+- ic %r0,0(%r2,%r3)
+- chi %r0,0x20 # is it a space ?
+- be .Lcntlp
+- ahi %r2,1
+- b .Leolp
++ ic %r0,0(%r2,%r3)
++ chi %r0,0x20 # is it a space ?
++ be .Lcntlp
++ ahi %r2,1
++ b .Leolp
+ .Lcntlp:
+- brct %r2,.Ldelspc
++ brct %r2,.Ldelspc
+ .Leolp:
+- slr %r0,%r0
+- stc %r0,0(%r2,%r3) # terminate buffer
++ slr %r0,%r0
++ stc %r0,0(%r2,%r3) # terminate buffer
+ .Lnopf:
+
+ #
+ # load ramdisk from ipl device
+-#
++#
+ .Lagain2:
+- l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # addr of ramdisk
+- bas %r14,.Lloader # load ramdisk
+- st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of ramdisk
+- ltr %r2,%r2
+- bnz .Lrdcont
+- st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found
++ l %r2,.Linitrd # addr of ramdisk
++ st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
++ bas %r14,.Lloader # load ramdisk
++ st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of rd
++ ltr %r2,%r2
++ bnz .Lrdcont
++ st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found
+ .Lrdcont:
+- l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
++ l %r2,.Linitrd
+
+- clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
+- bz .Lagain2
+- clc 0(3,%r2),.L_eof
+- bz .Lagain2
++ clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
++ bz .Lagain2
++ clc 0(3,%r2),.L_eof
++ bz .Lagain2
+
+ #ifdef CONFIG_IPL_VM
+ #
+ # reset files in VM reader
+ #
+- stidp __LC_CPUID # store cpuid
+- tm __LC_CPUID,0xff # running VM ?
+- bno .Lnoreset
+- la %r2,.Lreset
+- lhi %r3,26
+- diag %r2,%r3,8
+- la %r5,.Lirb
+- stsch 0(%r5) # check if irq is pending
+- tm 30(%r5),0x0f # by verifying if any of the
+- bnz .Lwaitforirq # activity or status control
+- tm 31(%r5),0xff # bits is set in the schib
+- bz .Lnoreset
++ stidp __LC_CPUID # store cpuid
++ tm __LC_CPUID,0xff # running VM ?
++ bno .Lnoreset
++ la %r2,.Lreset
++ lhi %r3,26
++ diag %r2,%r3,8
++ la %r5,.Lirb
++ stsch 0(%r5) # check if irq is pending
++ tm 30(%r5),0x0f # by verifying if any of the
++ bnz .Lwaitforirq # activity or status control
++ tm 31(%r5),0xff # bits is set in the schib
++ bz .Lnoreset
+ .Lwaitforirq:
+- mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
++ mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
+ .Lwaitrdrirq:
+- lpsw .Lrdrwaitpsw
++ lpsw .Lrdrwaitpsw
+ .Lrdrint:
+- c %r1,0xb8 # compare subchannel number
+- bne .Lwaitrdrirq
+- la %r5,.Lirb
+- tsch 0(%r5)
++ c %r1,0xb8 # compare subchannel number
++ bne .Lwaitrdrirq
++ la %r5,.Lirb
++ tsch 0(%r5)
+ .Lnoreset:
+- b .Lnoload
++ b .Lnoload
+
+- .align 8
++ .align 8
+ .Lrdrnewpsw:
+- .long 0x00080000,0x80000000+.Lrdrint
++ .long 0x00080000,0x80000000+.Lrdrint
+ .Lrdrwaitpsw:
+- .long 0x020a0000,0x80000000+.Lrdrint
++ .long 0x020a0000,0x80000000+.Lrdrint
+ #endif
+
+ #
+ # everything loaded, go for it
+ #
+ .Lnoload:
+- l %r1,.Lstartup
+- br %r1
++ l %r1,.Lstartup
++ br %r1
+
++.Linitrd:.long _end + 0x400000 # default address of initrd
+ .Lparm: .long PARMAREA
+ .Lstartup: .long startup
+-.Lcvtab:.long _ebcasc # ebcdic to ascii table
+-.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+- .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+- .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+-.L_eof: .long 0xc5d6c600 /* C'EOF' */
+-.L_hdr: .long 0xc8c4d900 /* C'HDR' */
++.Lcvtab:.long _ebcasc # ebcdic to ascii table
++.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
++ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
++ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
++.L_eof: .long 0xc5d6c600 /* C'EOF' */
++.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+
+-#endif /* CONFIG_IPL */
++#endif /* CONFIG_IPL */
+
+ #
+ # SALIPL loader support. Based on a patch by Rob van der Heij.
+ # This entry point is called directly from the SALIPL loader and
+ # doesn't need a builtin ipl record.
+ #
+- .org 0x800
+- .globl start
++ .org 0x800
++ .globl start
+ start:
+- stm %r0,%r15,0x07b0 # store registers
+- basr %r12,%r0
++ stm %r0,%r15,0x07b0 # store registers
++ basr %r12,%r0
+ .base:
+- l %r11,.parm
+- l %r8,.cmd # pointer to command buffer
++ l %r11,.parm
++ l %r8,.cmd # pointer to command buffer
+
+- ltr %r9,%r9 # do we have SALIPL parameters?
+- bp .sk8x8
++ ltr %r9,%r9 # do we have SALIPL parameters?
++ bp .sk8x8
+
+- mvc 0(64,%r8),0x00b0 # copy saved registers
+- xc 64(240-64,%r8),0(%r8) # remainder of buffer
+- tr 0(64,%r8),.lowcase
+- b .gotr
++ mvc 0(64,%r8),0x00b0 # copy saved registers
++ xc 64(240-64,%r8),0(%r8) # remainder of buffer
++ tr 0(64,%r8),.lowcase
++ b .gotr
+ .sk8x8:
+- mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
++ mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
+ .gotr:
+- l %r10,.tbl # EBCDIC to ASCII table
+- tr 0(240,%r8),0(%r10)
+- stidp __LC_CPUID # Are we running on VM maybe
+- cli __LC_CPUID,0xff
+- bnz .test
+- .long 0x83300060 # diag 3,0,x'0060' - storage size
+- b .done
++ l %r10,.tbl # EBCDIC to ASCII table
++ tr 0(240,%r8),0(%r10)
++ stidp __LC_CPUID # Are we running on VM maybe
++ cli __LC_CPUID,0xff
++ bnz .test
++ .long 0x83300060 # diag 3,0,x'0060' - storage size
++ b .done
+ .test:
+- mvc 0x68(8),.pgmnw # set up pgm check handler
+- l %r2,.fourmeg
+- lr %r3,%r2
+- bctr %r3,%r0 # 4M-1
+-.loop: iske %r0,%r3
+- ar %r3,%r2
++ mvc 0x68(8),.pgmnw # set up pgm check handler
++ l %r2,.fourmeg
++ lr %r3,%r2
++ bctr %r3,%r0 # 4M-1
++.loop: iske %r0,%r3
++ ar %r3,%r2
+ .pgmx:
+- sr %r3,%r2
+- la %r3,1(%r3)
++ sr %r3,%r2
++ la %r3,1(%r3)
+ .done:
+- l %r1,.memsize
+- st %r3,ARCH_OFFSET(%r1)
+- slr %r0,%r0
+- st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
+- st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
+- j startup # continue with startup
+-.tbl: .long _ebcasc # translate table
+-.cmd: .long COMMAND_LINE # address of command line buffer
+-.parm: .long PARMAREA
++ l %r1,.memsize
++ st %r3,ARCH_OFFSET(%r1)
++ slr %r0,%r0
++ st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
++ st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
++ j startup # continue with startup
++.tbl: .long _ebcasc # translate table
++.cmd: .long COMMAND_LINE # address of command line buffer
++.parm: .long PARMAREA
+ .memsize: .long memory_size
+ .fourmeg: .long 0x00400000 # 4M
+-.pgmnw: .long 0x00080000,.pgmx
++.pgmnw: .long 0x00080000,.pgmx
+ .lowcase:
+- .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
++ .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
+ .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+- .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
++ .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
+ .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+- .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
++ .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
+ .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+- .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
++ .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
+ .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+- .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
++ .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
+ .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+- .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
++ .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
+ .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+- .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
++ .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
+ .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+- .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
++ .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
+ .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+- .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
++ .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
+ .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+- .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
++ .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
+ .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+- .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
++ .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
+ .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+- .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
++ .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
+ .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+- .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
++ .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
+ .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
+- .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
++ .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
+ .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
+ .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
+ .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
+- .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
++ .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
+ .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
+-.macro GET_IPL_DEVICE
+-.Lget_ipl_device:
+- l %r1,0xb8 # get sid
+- sll %r1,15 # test if subchannel is enabled
+- srl %r1,31
+- ltr %r1,%r1
+- bz 2f-.LPG1(%r13) # subchannel disabled
+- l %r1,0xb8
+- la %r5,.Lipl_schib-.LPG1(%r13)
+- stsch 0(%r5) # get schib of subchannel
+- bnz 2f-.LPG1(%r13) # schib not available
+- tm 5(%r5),0x01 # devno valid?
+- bno 2f-.LPG1(%r13)
+- la %r6,ipl_parameter_flags-.LPG1(%r13)
+- oi 3(%r6),0x01 # set flag
+- la %r2,ipl_devno-.LPG1(%r13)
+- mvc 0(2,%r2),6(%r5) # store devno
+- tm 4(%r5),0x80 # qdio capable device?
+- bno 2f-.LPG1(%r13)
+- oi 3(%r6),0x02 # set flag
+-
+- # copy ipl parameters
+-
+- lhi %r0,4096
+- l %r2,20(%r0) # get address of parameter list
+- lhi %r3,IPL_PARMBLOCK_ORIGIN
+- st %r3,20(%r0)
+- lhi %r4,1
+- cr %r2,%r3 # start parameters < destination ?
+- jl 0f
+- lhi %r1,1 # copy direction is upwards
+- j 1f
+-0: lhi %r1,-1 # copy direction is downwards
+- ar %r2,%r0
+- ar %r3,%r0
+- ar %r2,%r1
+- ar %r3,%r1
+-1: mvc 0(1,%r3),0(%r2) # finally copy ipl parameters
+- ar %r3,%r1
+- ar %r2,%r1
+- sr %r0,%r4
+- jne 1b
+- b 2f-.LPG1(%r13)
+-
+- .align 4
+-.Lipl_schib:
+- .rept 13
+- .long 0
+- .endr
+-
+- .globl ipl_parameter_flags
+-ipl_parameter_flags:
+- .long 0
+- .globl ipl_devno
+-ipl_devno:
+- .word 0
+-2:
+-.endm
+-
+ #ifdef CONFIG_64BIT
+ #include "head64.S"
+ #else
+diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
+index a4dc61f..0a2c929 100644
+--- a/arch/s390/kernel/head31.S
++++ b/arch/s390/kernel/head31.S
+@@ -26,8 +26,8 @@ startup:basr %r13,0 # get base
+ #
+ .org PARMAREA
+ .long 0,0 # IPL_DEVICE
+- .long 0,RAMDISK_ORIGIN # INITRD_START
+- .long 0,RAMDISK_SIZE # INITRD_SIZE
++ .long 0,0 # INITRD_START
++ .long 0,0 # INITRD_SIZE
+
+ .org COMMAND_LINE
+ .byte "root=/dev/ram0 ro"
+@@ -37,12 +37,23 @@ startup:basr %r13,0 # get base
+
+ startup_continue:
+ basr %r13,0 # get base
+-.LPG1: GET_IPL_DEVICE
++.LPG1: mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+ lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
+ l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+ # move IPL device to lowcore
+ mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
++#
++# Setup stack
++#
++ l %r15,.Linittu-.LPG1(%r13)
++ mvc __LC_CURRENT(4),__TI_task(%r15)
++ ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE
++ st %r15,__LC_KERNEL_STACK # set end of kernel stack
++ ahi %r15,-96
++ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+
++ l %r14,.Lipl_save_parameters-.LPG1(%r13)
++ basr %r14,%r14
+ #
+ # clear bss memory
+ #
+@@ -114,6 +125,10 @@ startup_continue:
+ b .Lfchunk-.LPG1(%r13)
+
+ .align 4
++.Lipl_save_parameters:
++ .long ipl_save_parameters
++.Linittu:
++ .long init_thread_union
+ .Lpmask:
+ .byte 0
+ .align 8
+@@ -239,6 +254,16 @@ startup_continue:
+ oi 3(%r12),0x80 # set IDTE flag
+ .Lchkidte:
+
++#
++# find out if the diag 0x9c is available
++#
++ mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13)
++ stap __LC_CPUID+4 # store cpu address
++ lh %r1,__LC_CPUID+4
++ diag %r1,0,0x9c # test diag 0x9c
++ oi 2(%r12),1 # set diag9c flag
++.Lchkdiag9c:
++
+ lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
+ # virtual and never return ...
+ .align 8
+@@ -266,6 +291,7 @@ startup_continue:
+ .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
+ .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
+ .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte
++.Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c
+ .Lmemsize:.long memory_size
+ .Lmchunk:.long memory_chunk
+ .Lmflags:.long machine_flags
+@@ -273,7 +299,23 @@ startup_continue:
+ .Lbss_end: .long _end
+ .Lparmaddr: .long PARMAREA
+ .Lsccbaddr: .long .Lsccb
++
++ .globl ipl_schib
++ipl_schib:
++ .rept 13
++ .long 0
++ .endr
++
++ .globl ipl_flags
++ipl_flags:
++ .long 0
++ .globl ipl_devno
++ipl_devno:
++ .word 0
++
+ .org 0x12000
++.globl s390_readinfo_sccb
++s390_readinfo_sccb:
+ .Lsccb:
+ .hword 0x1000 # length, one page
+ .byte 0x00,0x00,0x00
+@@ -302,16 +344,6 @@ startup_continue:
+ .globl _stext
+ _stext: basr %r13,0 # get base
+ .LPG3:
+-#
+-# Setup stack
+-#
+- l %r15,.Linittu-.LPG3(%r13)
+- mvc __LC_CURRENT(4),__TI_task(%r15)
+- ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE
+- st %r15,__LC_KERNEL_STACK # set end of kernel stack
+- ahi %r15,-96
+- xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+-
+ # check control registers
+ stctl %c0,%c15,0(%r15)
+ oi 2(%r15),0x40 # enable sigp emergency signal
+@@ -330,6 +362,5 @@ _stext: basr %r13,0 # get base
+ #
+ .align 8
+ .Ldw: .long 0x000a0000,0x00000000
+-.Linittu:.long init_thread_union
+ .Lstart:.long start_kernel
+ .Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
+index 9d80c5b..42f54d4 100644
+--- a/arch/s390/kernel/head64.S
++++ b/arch/s390/kernel/head64.S
+@@ -15,221 +15,232 @@
+ # this is called either by the ipl loader or directly by PSW restart
+ # or linload or SALIPL
+ #
+- .org 0x10000
+-startup:basr %r13,0 # get base
+-.LPG0: l %r13,0f-.LPG0(%r13)
+- b 0(%r13)
+-0: .long startup_continue
++ .org 0x10000
++startup:basr %r13,0 # get base
++.LPG0: l %r13,0f-.LPG0(%r13)
++ b 0(%r13)
++0: .long startup_continue
+
+ #
+ # params at 10400 (setup.h)
+ #
+- .org PARMAREA
+- .quad 0 # IPL_DEVICE
+- .quad RAMDISK_ORIGIN # INITRD_START
+- .quad RAMDISK_SIZE # INITRD_SIZE
++ .org PARMAREA
++ .quad 0 # IPL_DEVICE
++ .quad 0 # INITRD_START
++ .quad 0 # INITRD_SIZE
+
+- .org COMMAND_LINE
+- .byte "root=/dev/ram0 ro"
+- .byte 0
++ .org COMMAND_LINE
++ .byte "root=/dev/ram0 ro"
++ .byte 0
+
+- .org 0x11000
++ .org 0x11000
+
+ startup_continue:
+- basr %r13,0 # get base
+-.LPG1: sll %r13,1 # remove high order bit
+- srl %r13,1
+- GET_IPL_DEVICE
+- lhi %r1,1 # mode 1 = esame
+- slr %r0,%r0 # set cpuid to zero
+- sigp %r1,%r0,0x12 # switch to esame mode
+- sam64 # switch to 64 bit mode
+- lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
+- lg %r12,.Lparmaddr-.LPG1(%r13)# pointer to parameter area
+- # move IPL device to lowcore
+- mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
++ basr %r13,0 # get base
++.LPG1: sll %r13,1 # remove high order bit
++ srl %r13,1
++ lhi %r1,1 # mode 1 = esame
++ mvi __LC_AR_MODE_ID,1 # set esame flag
++ slr %r0,%r0 # set cpuid to zero
++ sigp %r1,%r0,0x12 # switch to esame mode
++ sam64 # switch to 64 bit mode
++ lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
++ lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
++ # move IPL device to lowcore
++ mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
++#
++# Setup stack
++#
++ larl %r15,init_thread_union
++ lg %r14,__TI_task(%r15) # cache current in lowcore
++ stg %r14,__LC_CURRENT
++ aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
++ stg %r15,__LC_KERNEL_STACK # set end of kernel stack
++ aghi %r15,-160
++ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+
++ brasl %r14,ipl_save_parameters
+ #
+ # clear bss memory
+ #
+- larl %r2,__bss_start # start of bss segment
+- larl %r3,_end # end of bss segment
+- sgr %r3,%r2 # length of bss
+- sgr %r4,%r4 #
+- sgr %r5,%r5 # set src,length and pad to zero
+- mvcle %r2,%r4,0 # clear mem
+- jo .-4 # branch back, if not finish
++ larl %r2,__bss_start # start of bss segment
++ larl %r3,_end # end of bss segment
++ sgr %r3,%r2 # length of bss
++ sgr %r4,%r4 #
++ sgr %r5,%r5 # set src,length and pad to zero
++ mvcle %r2,%r4,0 # clear mem
++ jo .-4 # branch back, if not finish
+
+- l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
++ l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
+ .Lservicecall:
+- stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
++ stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
+
+- stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0
+- la %r1,0x200 # set bit 22
+- og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
+- stg %r1,.Lcr-.LPG1(%r13)
+- lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0
++ stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0
++ la %r1,0x200 # set bit 22
++ og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
++ stg %r1,.Lcr-.LPG1(%r13)
++ lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0
+
+- mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
+- larl %r1,.Lsclph
+- stg %r1,__LC_EXT_NEW_PSW+8 # set handler
++ mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
++ larl %r1,.Lsclph
++ stg %r1,__LC_EXT_NEW_PSW+8 # set handler
+
+- larl %r4,.Lsccb # %r4 is our index for sccb stuff
+- lgr %r1,%r4 # our sccb
+- .insn rre,0xb2200000,%r2,%r1 # service call
+- ipm %r1
+- srl %r1,28 # get cc code
+- xr %r3,%r3
+- chi %r1,3
+- be .Lfchunk-.LPG1(%r13) # leave
+- chi %r1,2
+- be .Lservicecall-.LPG1(%r13)
+- lpswe .Lwaitsclp-.LPG1(%r13)
++ larl %r4,.Lsccb # %r4 is our index for sccb stuff
++ lgr %r1,%r4 # our sccb
++ .insn rre,0xb2200000,%r2,%r1 # service call
++ ipm %r1
++ srl %r1,28 # get cc code
++ xr %r3,%r3
++ chi %r1,3
++ be .Lfchunk-.LPG1(%r13) # leave
++ chi %r1,2
++ be .Lservicecall-.LPG1(%r13)
++ lpswe .Lwaitsclp-.LPG1(%r13)
+ .Lsclph:
+- lh %r1,.Lsccbr-.Lsccb(%r4)
+- chi %r1,0x10 # 0x0010 is the sucess code
+- je .Lprocsccb # let's process the sccb
+- chi %r1,0x1f0
+- bne .Lfchunk-.LPG1(%r13) # unhandled error code
+- c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced
+- bne .Lfchunk-.LPG1(%r13) # if no, give up
+- l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP
+- b .Lservicecall-.LPG1(%r13)
++ lh %r1,.Lsccbr-.Lsccb(%r4)
++ chi %r1,0x10 # 0x0010 is the sucess code
++ je .Lprocsccb # let's process the sccb
++ chi %r1,0x1f0
++ bne .Lfchunk-.LPG1(%r13) # unhandled error code
++ c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced
++ bne .Lfchunk-.LPG1(%r13) # if no, give up
++ l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP
++ b .Lservicecall-.LPG1(%r13)
+ .Lprocsccb:
+- lghi %r1,0
+- icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
+- jnz .Lscnd
+- lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
++ lghi %r1,0
++ icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
++ jnz .Lscnd
++ lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
+ .Lscnd:
+- xr %r3,%r3 # same logic
+- ic %r3,.Lscpa1-.Lsccb(%r4)
+- chi %r3,0x00
+- jne .Lcompmem
+- l %r3,.Lscpa2-.Lsccb(%r4)
++ xr %r3,%r3 # same logic
++ ic %r3,.Lscpa1-.Lsccb(%r4)
++ chi %r3,0x00
++ jne .Lcompmem
++ l %r3,.Lscpa2-.Lsccb(%r4)
+ .Lcompmem:
+- mlgr %r2,%r1 # mem in MB on 128-bit
+- l %r1,.Lonemb-.LPG1(%r13)
+- mlgr %r2,%r1 # mem size in bytes in %r3
+- b .Lfchunk-.LPG1(%r13)
++ mlgr %r2,%r1 # mem in MB on 128-bit
++ l %r1,.Lonemb-.LPG1(%r13)
++ mlgr %r2,%r1 # mem size in bytes in %r3
++ b .Lfchunk-.LPG1(%r13)
+
+- .align 4
++ .align 4
+ .Lpmask:
+- .byte 0
+- .align 8
++ .byte 0
++ .align 8
+ .Lcr:
+- .quad 0x00 # place holder for cr0
++ .quad 0x00 # place holder for cr0
+ .Lwaitsclp:
+- .quad 0x0102000180000000,.Lsclph
++ .quad 0x0102000180000000,.Lsclph
+ .Lrcp:
+- .int 0x00120001 # Read SCP forced code
++ .int 0x00120001 # Read SCP forced code
+ .Lrcp2:
+- .int 0x00020001 # Read SCP code
++ .int 0x00020001 # Read SCP code
+ .Lonemb:
+- .int 0x100000
++ .int 0x100000
+
+ .Lfchunk:
+- # set program check new psw mask
+- mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
++ # set program check new psw mask
++ mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
+
+ #
+ # find memory chunks.
+ #
+- lgr %r9,%r3 # end of mem
+- larl %r1,.Lchkmem # set program check address
+- stg %r1,__LC_PGM_NEW_PSW+8
+- la %r1,1 # test in increments of 128KB
+- sllg %r1,%r1,17
+- larl %r3,memory_chunk
+- slgr %r4,%r4 # set start of chunk to zero
+- slgr %r5,%r5 # set end of chunk to zero
+- slr %r6,%r6 # set access code to zero
+- la %r10,MEMORY_CHUNKS # number of chunks
++ lgr %r9,%r3 # end of mem
++ larl %r1,.Lchkmem # set program check address
++ stg %r1,__LC_PGM_NEW_PSW+8
++ la %r1,1 # test in increments of 128KB
++ sllg %r1,%r1,17
++ larl %r3,memory_chunk
++ slgr %r4,%r4 # set start of chunk to zero
++ slgr %r5,%r5 # set end of chunk to zero
++ slr %r6,%r6 # set access code to zero
++ la %r10,MEMORY_CHUNKS # number of chunks
+ .Lloop:
+- tprot 0(%r5),0 # test protection of first byte
+- ipm %r7
+- srl %r7,28
+- clr %r6,%r7 # compare cc with last access code
+- je .Lsame
+- j .Lchkmem
++ tprot 0(%r5),0 # test protection of first byte
++ ipm %r7
++ srl %r7,28
++ clr %r6,%r7 # compare cc with last access code
++ je .Lsame
++ j .Lchkmem
+ .Lsame:
+- algr %r5,%r1 # add 128KB to end of chunk
+- # no need to check here,
+- brc 12,.Lloop # this is the same chunk
+-.Lchkmem: # > 16EB or tprot got a program check
+- clgr %r4,%r5 # chunk size > 0?
+- je .Lchkloop
+- stg %r4,0(%r3) # store start address of chunk
+- lgr %r0,%r5
+- slgr %r0,%r4
+- stg %r0,8(%r3) # store size of chunk
+- st %r6,20(%r3) # store type of chunk
+- la %r3,24(%r3)
+- larl %r8,memory_size
+- stg %r5,0(%r8) # store memory size
+- ahi %r10,-1 # update chunk number
++ algr %r5,%r1 # add 128KB to end of chunk
++ # no need to check here,
++ brc 12,.Lloop # this is the same chunk
++.Lchkmem: # > 16EB or tprot got a program check
++ clgr %r4,%r5 # chunk size > 0?
++ je .Lchkloop
++ stg %r4,0(%r3) # store start address of chunk
++ lgr %r0,%r5
++ slgr %r0,%r4
++ stg %r0,8(%r3) # store size of chunk
++ st %r6,20(%r3) # store type of chunk
++ la %r3,24(%r3)
++ larl %r8,memory_size
++ stg %r5,0(%r8) # store memory size
++ ahi %r10,-1 # update chunk number
+ .Lchkloop:
+- lr %r6,%r7 # set access code to last cc
++ lr %r6,%r7 # set access code to last cc
+ # we got an exception or we're starting a new
+ # chunk , we must check if we should
+ # still try to find valid memory (if we detected
+ # the amount of available storage), and if we
+ # have chunks left
+- lghi %r4,1
+- sllg %r4,%r4,31
+- clgr %r5,%r4
+- je .Lhsaskip
+- xr %r0, %r0
+- clgr %r0, %r9 # did we detect memory?
+- je .Ldonemem # if not, leave
+- chi %r10, 0 # do we have chunks left?
+- je .Ldonemem
++ lghi %r4,1
++ sllg %r4,%r4,31
++ clgr %r5,%r4
++ je .Lhsaskip
++ xr %r0, %r0
++ clgr %r0, %r9 # did we detect memory?
++ je .Ldonemem # if not, leave
++ chi %r10, 0 # do we have chunks left?
++ je .Ldonemem
+ .Lhsaskip:
+- algr %r5,%r1 # add 128KB to end of chunk
+- lgr %r4,%r5 # potential new chunk
+- clgr %r5,%r9 # should we go on?
+- jl .Lloop
+-.Ldonemem:
++ algr %r5,%r1 # add 128KB to end of chunk
++ lgr %r4,%r5 # potential new chunk
++ clgr %r5,%r9 # should we go on?
++ jl .Lloop
++.Ldonemem:
+
+- larl %r12,machine_flags
++ larl %r12,machine_flags
+ #
+ # find out if we are running under VM
+ #
+- stidp __LC_CPUID # store cpuid
+- tm __LC_CPUID,0xff # running under VM ?
+- bno 0f-.LPG1(%r13)
+- oi 7(%r12),1 # set VM flag
+-0: lh %r0,__LC_CPUID+4 # get cpu version
+- chi %r0,0x7490 # running on a P/390 ?
+- bne 1f-.LPG1(%r13)
+- oi 7(%r12),4 # set P/390 flag
++ stidp __LC_CPUID # store cpuid
++ tm __LC_CPUID,0xff # running under VM ?
++ bno 0f-.LPG1(%r13)
++ oi 7(%r12),1 # set VM flag
++0: lh %r0,__LC_CPUID+4 # get cpu version
++ chi %r0,0x7490 # running on a P/390 ?
++ bne 1f-.LPG1(%r13)
++ oi 7(%r12),4 # set P/390 flag
+ 1:
+
+ #
+ # find out if we have the MVPG instruction
+ #
+- la %r1,0f-.LPG1(%r13) # set program check address
+- stg %r1,__LC_PGM_NEW_PSW+8
+- sgr %r0,%r0
+- lghi %r1,0
+- lghi %r2,0
+- mvpg %r1,%r2 # test MVPG instruction
+- oi 7(%r12),16 # set MVPG flag
++ la %r1,0f-.LPG1(%r13) # set program check address
++ stg %r1,__LC_PGM_NEW_PSW+8
++ sgr %r0,%r0
++ lghi %r1,0
++ lghi %r2,0
++ mvpg %r1,%r2 # test MVPG instruction
++ oi 7(%r12),16 # set MVPG flag
+ 0:
+
+ #
+ # find out if the diag 0x44 works in 64 bit mode
+ #
+- la %r1,0f-.LPG1(%r13) # set program check address
+- stg %r1,__LC_PGM_NEW_PSW+8
+- diag 0,0,0x44 # test diag 0x44
+- oi 7(%r12),32 # set diag44 flag
+-0:
++ la %r1,0f-.LPG1(%r13) # set program check address
++ stg %r1,__LC_PGM_NEW_PSW+8
++ diag 0,0,0x44 # test diag 0x44
++ oi 7(%r12),32 # set diag44 flag
++0:
+
+ #
+ # find out if we have the IDTE instruction
+ #
+- la %r1,0f-.LPG1(%r13) # set program check address
+- stg %r1,__LC_PGM_NEW_PSW+8
++ la %r1,0f-.LPG1(%r13) # set program check address
++ stg %r1,__LC_PGM_NEW_PSW+8
+ .long 0xb2b10000 # store facility list
+ tm 0xc8,0x08 # check bit for clearing-by-ASCE
+ bno 0f-.LPG1(%r13)
+@@ -239,90 +250,117 @@ startup_continue:
+ oi 7(%r12),0x80 # set IDTE flag
+ 0:
+
+- lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
+- # virtual and never return ...
+- .align 16
+-.Lentry:.quad 0x0000000180000000,_stext
+-.Lctl: .quad 0x04b50002 # cr0: various things
+- .quad 0 # cr1: primary space segment table
+- .quad .Lduct # cr2: dispatchable unit control table
+- .quad 0 # cr3: instruction authorization
+- .quad 0 # cr4: instruction authorization
+- .quad 0xffffffffffffffff # cr5: primary-aste origin
+- .quad 0 # cr6: I/O interrupts
+- .quad 0 # cr7: secondary space segment table
+- .quad 0 # cr8: access registers translation
+- .quad 0 # cr9: tracing off
+- .quad 0 # cr10: tracing off
+- .quad 0 # cr11: tracing off
+- .quad 0 # cr12: tracing off
+- .quad 0 # cr13: home space segment table
+- .quad 0xc0000000 # cr14: machine check handling off
+- .quad 0 # cr15: linkage stack operations
+-.Lduct: .long 0,0,0,0,0,0,0,0
+- .long 0,0,0,0,0,0,0,0
+-.Lpcmsk:.quad 0x0000000180000000
++#
++# find out if the diag 0x9c is available
++#
++ la %r1,0f-.LPG1(%r13) # set program check address
++ stg %r1,__LC_PGM_NEW_PSW+8
++ stap __LC_CPUID+4 # store cpu address
++ lh %r1,__LC_CPUID+4
++ diag %r1,0,0x9c # test diag 0x9c
++ oi 6(%r12),1 # set diag9c flag
++0:
++
++#
++# find out if we have the MVCOS instruction
++#
++ la %r1,0f-.LPG1(%r13) # set program check address
++ stg %r1,__LC_PGM_NEW_PSW+8
++ .short 0xc800 # mvcos 0(%r0),0(%r0),%r0
++ .short 0x0000
++ .short 0x0000
++0: tm 0x8f,0x13 # special-operation exception?
++ bno 1f-.LPG1(%r13) # if yes, MVCOS is present
++ oi 6(%r12),2 # set MVCOS flag
++1:
++
++ lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
++ # virtual and never return ...
++ .align 16
++.Lentry:.quad 0x0000000180000000,_stext
++.Lctl: .quad 0x04b50002 # cr0: various things
++ .quad 0 # cr1: primary space segment table
++ .quad .Lduct # cr2: dispatchable unit control table
++ .quad 0 # cr3: instruction authorization
++ .quad 0 # cr4: instruction authorization
++ .quad 0xffffffffffffffff # cr5: primary-aste origin
++ .quad 0 # cr6: I/O interrupts
++ .quad 0 # cr7: secondary space segment table
++ .quad 0 # cr8: access registers translation
++ .quad 0 # cr9: tracing off
++ .quad 0 # cr10: tracing off
++ .quad 0 # cr11: tracing off
++ .quad 0 # cr12: tracing off
++ .quad 0 # cr13: home space segment table
++ .quad 0xc0000000 # cr14: machine check handling off
++ .quad 0 # cr15: linkage stack operations
++.Lduct: .long 0,0,0,0,0,0,0,0
++ .long 0,0,0,0,0,0,0,0
++.Lpcmsk:.quad 0x0000000180000000
+ .L4malign:.quad 0xffffffffffc00000
+-.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
+-.Lnop: .long 0x07000700
++.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
++.Lnop: .long 0x07000700
+ .Lparmaddr:
+ .quad PARMAREA
+
++ .globl ipl_schib
++ipl_schib:
++ .rept 13
++ .long 0
++ .endr
++
++ .globl ipl_flags
++ipl_flags:
++ .long 0
++ .globl ipl_devno
++ipl_devno:
++ .word 0
++
+ .org 0x12000
++.globl s390_readinfo_sccb
++s390_readinfo_sccb:
+ .Lsccb:
+- .hword 0x1000 # length, one page
+- .byte 0x00,0x00,0x00
+- .byte 0x80 # variable response bit set
++ .hword 0x1000 # length, one page
++ .byte 0x00,0x00,0x00
++ .byte 0x80 # variable response bit set
+ .Lsccbr:
+- .hword 0x00 # response code
++ .hword 0x00 # response code
+ .Lscpincr1:
+- .hword 0x00
++ .hword 0x00
+ .Lscpa1:
+- .byte 0x00
+- .fill 89,1,0
++ .byte 0x00
++ .fill 89,1,0
+ .Lscpa2:
+- .int 0x00
++ .int 0x00
+ .Lscpincr2:
+- .quad 0x00
+- .fill 3984,1,0
++ .quad 0x00
++ .fill 3984,1,0
+ .org 0x13000
+
+ #ifdef CONFIG_SHARED_KERNEL
+- .org 0x100000
++ .org 0x100000
+ #endif
+-
++
+ #
+ # startup-code, running in absolute addressing mode
+ #
+- .globl _stext
+-_stext: basr %r13,0 # get base
++ .globl _stext
++_stext: basr %r13,0 # get base
+ .LPG3:
+-#
+-# Setup stack
+-#
+- larl %r15,init_thread_union
+- lg %r14,__TI_task(%r15) # cache current in lowcore
+- stg %r14,__LC_CURRENT
+- aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
+- stg %r15,__LC_KERNEL_STACK # set end of kernel stack
+- aghi %r15,-160
+- xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+-
+ # check control registers
+- stctg %c0,%c15,0(%r15)
+- oi 6(%r15),0x40 # enable sigp emergency signal
+- oi 4(%r15),0x10 # switch on low address proctection
+- lctlg %c0,%c15,0(%r15)
++ stctg %c0,%c15,0(%r15)
++ oi 6(%r15),0x40 # enable sigp emergency signal
++ oi 4(%r15),0x10 # switch on low address proctection
++ lctlg %c0,%c15,0(%r15)
+
+-#
+- lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess
+- brasl %r14,start_kernel # go to C code
++ lam 0,15,.Laregs-.LPG3(%r13) # load acrs needed by uaccess
++ brasl %r14,start_kernel # go to C code
+ #
+ # We returned from start_kernel ?!? PANIK
+ #
+- basr %r13,0
+- lpswe .Ldw-.(%r13) # load disabled wait psw
+-#
+- .align 8
+-.Ldw: .quad 0x0002000180000000,0x0000000000000000
+-.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++ basr %r13,0
++ lpswe .Ldw-.(%r13) # load disabled wait psw
++
++ .align 8
++.Ldw: .quad 0x0002000180000000,0x0000000000000000
++.Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
+new file mode 100644
+index 0000000..1f5e782
+--- /dev/null
++++ b/arch/s390/kernel/ipl.c
+@@ -0,0 +1,933 @@
++/*
++ * arch/s390/kernel/ipl.c
++ * ipl/reipl/dump support for Linux on s390.
++ *
++ * Copyright (C) IBM Corp. 2005,2006
++ * Author(s): Michael Holzheu <holzheu at de.ibm.com>
++ * Heiko Carstens <heiko.carstens at de.ibm.com>
++ * Volker Sameske <sameske at de.ibm.com>
++ */
++
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++#include <asm/smp.h>
++#include <asm/setup.h>
++#include <asm/cpcmd.h>
++#include <asm/cio.h>
++
++#define IPL_PARM_BLOCK_VERSION 0
++
++enum ipl_type {
++ IPL_TYPE_NONE = 1,
++ IPL_TYPE_UNKNOWN = 2,
++ IPL_TYPE_CCW = 4,
++ IPL_TYPE_FCP = 8,
++};
++
++#define IPL_NONE_STR "none"
++#define IPL_UNKNOWN_STR "unknown"
++#define IPL_CCW_STR "ccw"
++#define IPL_FCP_STR "fcp"
++
++static char *ipl_type_str(enum ipl_type type)
++{
++ switch (type) {
++ case IPL_TYPE_NONE:
++ return IPL_NONE_STR;
++ case IPL_TYPE_CCW:
++ return IPL_CCW_STR;
++ case IPL_TYPE_FCP:
++ return IPL_FCP_STR;
++ case IPL_TYPE_UNKNOWN:
++ default:
++ return IPL_UNKNOWN_STR;
++ }
++}
++
++enum ipl_method {
++ IPL_METHOD_NONE,
++ IPL_METHOD_CCW_CIO,
++ IPL_METHOD_CCW_DIAG,
++ IPL_METHOD_CCW_VM,
++ IPL_METHOD_FCP_RO_DIAG,
++ IPL_METHOD_FCP_RW_DIAG,
++ IPL_METHOD_FCP_RO_VM,
++};
++
++enum shutdown_action {
++ SHUTDOWN_REIPL,
++ SHUTDOWN_DUMP,
++ SHUTDOWN_STOP,
++};
++
++#define SHUTDOWN_REIPL_STR "reipl"
++#define SHUTDOWN_DUMP_STR "dump"
++#define SHUTDOWN_STOP_STR "stop"
++
++static char *shutdown_action_str(enum shutdown_action action)
++{
++ switch (action) {
++ case SHUTDOWN_REIPL:
++ return SHUTDOWN_REIPL_STR;
++ case SHUTDOWN_DUMP:
++ return SHUTDOWN_DUMP_STR;
++ case SHUTDOWN_STOP:
++ return SHUTDOWN_STOP_STR;
++ default:
++ BUG();
++ }
++}
++
++enum diag308_subcode {
++ DIAG308_IPL = 3,
++ DIAG308_DUMP = 4,
++ DIAG308_SET = 5,
++ DIAG308_STORE = 6,
++};
++
++enum diag308_ipl_type {
++ DIAG308_IPL_TYPE_FCP = 0,
++ DIAG308_IPL_TYPE_CCW = 2,
++};
++
++enum diag308_opt {
++ DIAG308_IPL_OPT_IPL = 0x10,
++ DIAG308_IPL_OPT_DUMP = 0x20,
++};
++
++enum diag308_rc {
++ DIAG308_RC_OK = 1,
++};
++
++static int diag308_set_works = 0;
++
++static int reipl_capabilities = IPL_TYPE_UNKNOWN;
++static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
++static enum ipl_method reipl_method = IPL_METHOD_NONE;
++static struct ipl_parameter_block *reipl_block_fcp;
++static struct ipl_parameter_block *reipl_block_ccw;
++
++static int dump_capabilities = IPL_TYPE_NONE;
++static enum ipl_type dump_type = IPL_TYPE_NONE;
++static enum ipl_method dump_method = IPL_METHOD_NONE;
++static struct ipl_parameter_block *dump_block_fcp;
++static struct ipl_parameter_block *dump_block_ccw;
++
++static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
++
++static int diag308(unsigned long subcode, void *addr)
++{
++ register unsigned long _addr asm("0") = (unsigned long) addr;
++ register unsigned long _rc asm("1") = 0;
++
++ asm volatile(
++ " diag %0,%2,0x308\n"
++ "0:\n"
++ EX_TABLE(0b,0b)
++ : "+d" (_addr), "+d" (_rc)
++ : "d" (subcode) : "cc", "memory");
++ return _rc;
++}
++
++/* SYSFS */
++
++#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
++static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
++ char *page) \
++{ \
++ return sprintf(page, _format, _value); \
++} \
++static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
++ __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
++
++#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
++static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
++ char *page) \
++{ \
++ return sprintf(page, _fmt_out, \
++ (unsigned long long) _value); \
++} \
++static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
++ const char *buf, size_t len) \
++{ \
++ unsigned long long value; \
++ if (sscanf(buf, _fmt_in, &value) != 1) \
++ return -EINVAL; \
++ _value = value; \
++ return len; \
++} \
++static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
++ __ATTR(_name,(S_IRUGO | S_IWUSR), \
++ sys_##_prefix##_##_name##_show, \
++ sys_##_prefix##_##_name##_store);
++
++static void make_attrs_ro(struct attribute **attrs)
++{
++ while (*attrs) {
++ (*attrs)->mode = S_IRUGO;
++ attrs++;
++ }
++}
++
++/*
++ * ipl section
++ */
++
++static enum ipl_type ipl_get_type(void)
++{
++ struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
++
++ if (!(ipl_flags & IPL_DEVNO_VALID))
++ return IPL_TYPE_UNKNOWN;
++ if (!(ipl_flags & IPL_PARMBLOCK_VALID))
++ return IPL_TYPE_CCW;
++ if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION)
++ return IPL_TYPE_UNKNOWN;
++ if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)
++ return IPL_TYPE_UNKNOWN;
++ return IPL_TYPE_FCP;
++}
++
++static ssize_t ipl_type_show(struct subsystem *subsys, char *page)
++{
++ return sprintf(page, "%s\n", ipl_type_str(ipl_get_type()));
++}
++
++static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
++
++static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page)
++{
++ struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
++
++ switch (ipl_get_type()) {
++ case IPL_TYPE_CCW:
++ return sprintf(page, "0.0.%04x\n", ipl_devno);
++ case IPL_TYPE_FCP:
++ return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
++ default:
++ return 0;
++ }
++}
++
++static struct subsys_attribute sys_ipl_device_attr =
++ __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
++
++static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off,
++ size_t count)
++{
++ unsigned int size = IPL_PARMBLOCK_SIZE;
++
++ if (off > size)
++ return 0;
++ if (off + count > size)
++ count = size - off;
++ memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
++ return count;
++}
++
++static struct bin_attribute ipl_parameter_attr = {
++ .attr = {
++ .name = "binary_parameter",
++ .mode = S_IRUGO,
++ .owner = THIS_MODULE,
++ },
++ .size = PAGE_SIZE,
++ .read = &ipl_parameter_read,
++};
++
++static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off,
++ size_t count)
++{
++ unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
++ void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
++
++ if (off > size)
++ return 0;
++ if (off + count > size)
++ count = size - off;
++ memcpy(buf, scp_data + off, count);
++ return count;
++}
++
++static struct bin_attribute ipl_scp_data_attr = {
++ .attr = {
++ .name = "scp_data",
++ .mode = S_IRUGO,
++ .owner = THIS_MODULE,
++ },
++ .size = PAGE_SIZE,
++ .read = &ipl_scp_data_read,
++};
++
++/* FCP ipl device attributes */
++
++DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
++ IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
++DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
++ IPL_PARMBLOCK_START->ipl_info.fcp.lun);
++DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
++ IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
++DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
++ IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
++
++static struct attribute *ipl_fcp_attrs[] = {
++ &sys_ipl_type_attr.attr,
++ &sys_ipl_device_attr.attr,
++ &sys_ipl_fcp_wwpn_attr.attr,
++ &sys_ipl_fcp_lun_attr.attr,
++ &sys_ipl_fcp_bootprog_attr.attr,
++ &sys_ipl_fcp_br_lba_attr.attr,
++ NULL,
++};
++
++static struct attribute_group ipl_fcp_attr_group = {
++ .attrs = ipl_fcp_attrs,
++};
++
++/* CCW ipl device attributes */
++
++static struct attribute *ipl_ccw_attrs[] = {
++ &sys_ipl_type_attr.attr,
++ &sys_ipl_device_attr.attr,
++ NULL,
++};
++
++static struct attribute_group ipl_ccw_attr_group = {
++ .attrs = ipl_ccw_attrs,
++};
++
++/* UNKNOWN ipl device attributes */
++
++static struct attribute *ipl_unknown_attrs[] = {
++ &sys_ipl_type_attr.attr,
++ NULL,
++};
++
++static struct attribute_group ipl_unknown_attr_group = {
++ .attrs = ipl_unknown_attrs,
++};
++
++static decl_subsys(ipl, NULL, NULL);
++
++/*
++ * reipl section
++ */
++
++/* FCP reipl device attributes */
++
++DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
++ reipl_block_fcp->ipl_info.fcp.wwpn);
++DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
++ reipl_block_fcp->ipl_info.fcp.lun);
++DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
++ reipl_block_fcp->ipl_info.fcp.bootprog);
++DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
++ reipl_block_fcp->ipl_info.fcp.br_lba);
++DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
++ reipl_block_fcp->ipl_info.fcp.devno);
++
++static struct attribute *reipl_fcp_attrs[] = {
++ &sys_reipl_fcp_device_attr.attr,
++ &sys_reipl_fcp_wwpn_attr.attr,
++ &sys_reipl_fcp_lun_attr.attr,
++ &sys_reipl_fcp_bootprog_attr.attr,
++ &sys_reipl_fcp_br_lba_attr.attr,
++ NULL,
++};
++
++static struct attribute_group reipl_fcp_attr_group = {
++ .name = IPL_FCP_STR,
++ .attrs = reipl_fcp_attrs,
++};
++
++/* CCW reipl device attributes */
++
++DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
++ reipl_block_ccw->ipl_info.ccw.devno);
++
++static struct attribute *reipl_ccw_attrs[] = {
++ &sys_reipl_ccw_device_attr.attr,
++ NULL,
++};
++
++static struct attribute_group reipl_ccw_attr_group = {
++ .name = IPL_CCW_STR,
++ .attrs = reipl_ccw_attrs,
++};
++
++/* reipl type */
++
++static int reipl_set_type(enum ipl_type type)
++{
++ if (!(reipl_capabilities & type))
++ return -EINVAL;
++
++ switch(type) {
++ case IPL_TYPE_CCW:
++ if (MACHINE_IS_VM)
++ reipl_method = IPL_METHOD_CCW_VM;
++ else
++ reipl_method = IPL_METHOD_CCW_CIO;
++ break;
++ case IPL_TYPE_FCP:
++ if (diag308_set_works)
++ reipl_method = IPL_METHOD_FCP_RW_DIAG;
++ else if (MACHINE_IS_VM)
++ reipl_method = IPL_METHOD_FCP_RO_VM;
++ else
++ reipl_method = IPL_METHOD_FCP_RO_DIAG;
++ break;
++ default:
++ reipl_method = IPL_METHOD_NONE;
++ }
++ reipl_type = type;
++ return 0;
++}
++
++static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
++{
++ return sprintf(page, "%s\n", ipl_type_str(reipl_type));
++}
++
++static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
++ size_t len)
++{
++ int rc = -EINVAL;
++
++ if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
++ rc = reipl_set_type(IPL_TYPE_CCW);
++ else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
++ rc = reipl_set_type(IPL_TYPE_FCP);
++ return (rc != 0) ? rc : len;
++}
++
++static struct subsys_attribute reipl_type_attr =
++ __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
++
++static decl_subsys(reipl, NULL, NULL);
++
++/*
++ * dump section
++ */
++
++/* FCP dump device attributes */
++
++DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
++ dump_block_fcp->ipl_info.fcp.wwpn);
++DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
++ dump_block_fcp->ipl_info.fcp.lun);
++DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
++ dump_block_fcp->ipl_info.fcp.bootprog);
++DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
++ dump_block_fcp->ipl_info.fcp.br_lba);
++DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
++ dump_block_fcp->ipl_info.fcp.devno);
++
++static struct attribute *dump_fcp_attrs[] = {
++ &sys_dump_fcp_device_attr.attr,
++ &sys_dump_fcp_wwpn_attr.attr,
++ &sys_dump_fcp_lun_attr.attr,
++ &sys_dump_fcp_bootprog_attr.attr,
++ &sys_dump_fcp_br_lba_attr.attr,
++ NULL,
++};
++
++static struct attribute_group dump_fcp_attr_group = {
++ .name = IPL_FCP_STR,
++ .attrs = dump_fcp_attrs,
++};
++
++/* CCW dump device attributes */
++
++DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
++ dump_block_ccw->ipl_info.ccw.devno);
++
++static struct attribute *dump_ccw_attrs[] = {
++ &sys_dump_ccw_device_attr.attr,
++ NULL,
++};
++
++static struct attribute_group dump_ccw_attr_group = {
++ .name = IPL_CCW_STR,
++ .attrs = dump_ccw_attrs,
++};
++
++/* dump type */
++
++static int dump_set_type(enum ipl_type type)
++{
++ if (!(dump_capabilities & type))
++ return -EINVAL;
++ switch(type) {
++ case IPL_TYPE_CCW:
++ if (MACHINE_IS_VM)
++ dump_method = IPL_METHOD_CCW_VM;
++ else
++ dump_method = IPL_METHOD_CCW_CIO;
++ break;
++ case IPL_TYPE_FCP:
++ dump_method = IPL_METHOD_FCP_RW_DIAG;
++ break;
++ default:
++ dump_method = IPL_METHOD_NONE;
++ }
++ dump_type = type;
++ return 0;
++}
++
++static ssize_t dump_type_show(struct subsystem *subsys, char *page)
++{
++ return sprintf(page, "%s\n", ipl_type_str(dump_type));
++}
++
++static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
++ size_t len)
++{
++ int rc = -EINVAL;
++
++ if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0)
++ rc = dump_set_type(IPL_TYPE_NONE);
++ else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
++ rc = dump_set_type(IPL_TYPE_CCW);
++ else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
++ rc = dump_set_type(IPL_TYPE_FCP);
++ return (rc != 0) ? rc : len;
++}
++
++static struct subsys_attribute dump_type_attr =
++ __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
++
++static decl_subsys(dump, NULL, NULL);
++
++#ifdef CONFIG_SMP
++static void dump_smp_stop_all(void)
++{
++ int cpu;
++ preempt_disable();
++ for_each_online_cpu(cpu) {
++ if (cpu == smp_processor_id())
++ continue;
++ while (signal_processor(cpu, sigp_stop) == sigp_busy)
++ udelay(10);
++ }
++ preempt_enable();
++}
++#else
++#define dump_smp_stop_all() do { } while (0)
++#endif
++
++/*
++ * Shutdown actions section
++ */
++
++static decl_subsys(shutdown_actions, NULL, NULL);
++
++/* on panic */
++
++static ssize_t on_panic_show(struct subsystem *subsys, char *page)
++{
++ return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
++}
++
++static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
++ size_t len)
++{
++ if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
++ on_panic_action = SHUTDOWN_REIPL;
++ else if (strncmp(buf, SHUTDOWN_DUMP_STR,
++ strlen(SHUTDOWN_DUMP_STR)) == 0)
++ on_panic_action = SHUTDOWN_DUMP;
++ else if (strncmp(buf, SHUTDOWN_STOP_STR,
++ strlen(SHUTDOWN_STOP_STR)) == 0)
++ on_panic_action = SHUTDOWN_STOP;
++ else
++ return -EINVAL;
++
++ return len;
++}
++
++static struct subsys_attribute on_panic_attr =
++ __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
++
++static void print_fcp_block(struct ipl_parameter_block *fcp_block)
++{
++ printk(KERN_EMERG "wwpn: %016llx\n",
++ (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
++ printk(KERN_EMERG "lun: %016llx\n",
++ (unsigned long long)fcp_block->ipl_info.fcp.lun);
++ printk(KERN_EMERG "bootprog: %lld\n",
++ (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
++ printk(KERN_EMERG "br_lba: %lld\n",
++ (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
++ printk(KERN_EMERG "device: %llx\n",
++ (unsigned long long)fcp_block->ipl_info.fcp.devno);
++ printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt);
++}
++
++void do_reipl(void)
++{
++ struct ccw_dev_id devid;
++ static char buf[100];
++
++ switch (reipl_type) {
++ case IPL_TYPE_CCW:
++ printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
++ reipl_block_ccw->ipl_info.ccw.devno);
++ break;
++ case IPL_TYPE_FCP:
++ printk(KERN_EMERG "reboot on fcp device:\n");
++ print_fcp_block(reipl_block_fcp);
++ break;
++ default:
++ break;
++ }
++
++ switch (reipl_method) {
++ case IPL_METHOD_CCW_CIO:
++ devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
++ devid.ssid = 0;
++ reipl_ccw_dev(&devid);
++ break;
++ case IPL_METHOD_CCW_VM:
++ sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno);
++ cpcmd(buf, NULL, 0, NULL);
++ break;
++ case IPL_METHOD_CCW_DIAG:
++ diag308(DIAG308_SET, reipl_block_ccw);
++ diag308(DIAG308_IPL, NULL);
++ break;
++ case IPL_METHOD_FCP_RW_DIAG:
++ diag308(DIAG308_SET, reipl_block_fcp);
++ diag308(DIAG308_IPL, NULL);
++ break;
++ case IPL_METHOD_FCP_RO_DIAG:
++ diag308(DIAG308_IPL, NULL);
++ break;
++ case IPL_METHOD_FCP_RO_VM:
++ cpcmd("IPL", NULL, 0, NULL);
++ break;
++ case IPL_METHOD_NONE:
++ default:
++ if (MACHINE_IS_VM)
++ cpcmd("IPL", NULL, 0, NULL);
++ diag308(DIAG308_IPL, NULL);
++ break;
++ }
++ panic("reipl failed!\n");
++}
++
++static void do_dump(void)
++{
++ struct ccw_dev_id devid;
++ static char buf[100];
++
++ switch (dump_type) {
++ case IPL_TYPE_CCW:
++ printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
++ dump_block_ccw->ipl_info.ccw.devno);
++ break;
++ case IPL_TYPE_FCP:
++ printk(KERN_EMERG "Automatic dump on fcp device:\n");
++ print_fcp_block(dump_block_fcp);
++ break;
++ default:
++ return;
++ }
++
++ switch (dump_method) {
++ case IPL_METHOD_CCW_CIO:
++ dump_smp_stop_all();
++ devid.devno = dump_block_ccw->ipl_info.ccw.devno;
++ devid.ssid = 0;
++ reipl_ccw_dev(&devid);
++ break;
++ case IPL_METHOD_CCW_VM:
++ dump_smp_stop_all();
++ sprintf(buf, "STORE STATUS");
++ cpcmd(buf, NULL, 0, NULL);
++ sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
++ cpcmd(buf, NULL, 0, NULL);
++ break;
++ case IPL_METHOD_CCW_DIAG:
++ diag308(DIAG308_SET, dump_block_ccw);
++ diag308(DIAG308_DUMP, NULL);
++ break;
++ case IPL_METHOD_FCP_RW_DIAG:
++ diag308(DIAG308_SET, dump_block_fcp);
++ diag308(DIAG308_DUMP, NULL);
++ break;
++ case IPL_METHOD_NONE:
++ default:
++ return;
++ }
++ printk(KERN_EMERG "Dump failed!\n");
++}
++
++/* init functions */
++
++static int __init ipl_register_fcp_files(void)
++{
++ int rc;
++
++ rc = sysfs_create_group(&ipl_subsys.kset.kobj,
++ &ipl_fcp_attr_group);
++ if (rc)
++ goto out;
++ rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
++ &ipl_parameter_attr);
++ if (rc)
++ goto out_ipl_parm;
++ rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
++ &ipl_scp_data_attr);
++ if (!rc)
++ goto out;
++
++ sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
++
++out_ipl_parm:
++ sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
++out:
++ return rc;
++}
++
++static int __init ipl_init(void)
++{
++ int rc;
++
++ rc = firmware_register(&ipl_subsys);
++ if (rc)
++ return rc;
++ switch (ipl_get_type()) {
++ case IPL_TYPE_CCW:
++ rc = sysfs_create_group(&ipl_subsys.kset.kobj,
++ &ipl_ccw_attr_group);
++ break;
++ case IPL_TYPE_FCP:
++ rc = ipl_register_fcp_files();
++ break;
++ default:
++ rc = sysfs_create_group(&ipl_subsys.kset.kobj,
++ &ipl_unknown_attr_group);
++ break;
++ }
++ if (rc)
++ firmware_unregister(&ipl_subsys);
++ return rc;
++}
++
++static void __init reipl_probe(void)
++{
++ void *buffer;
++
++ buffer = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!buffer)
++ return;
++ if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
++ diag308_set_works = 1;
++ free_page((unsigned long)buffer);
++}
++
++static int __init reipl_ccw_init(void)
++{
++ int rc;
++
++ reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!reipl_block_ccw)
++ return -ENOMEM;
++ rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
++ if (rc) {
++ free_page((unsigned long)reipl_block_ccw);
++ return rc;
++ }
++ reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
++ reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
++ reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
++ reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
++ if (ipl_get_type() == IPL_TYPE_CCW)
++ reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
++ reipl_capabilities |= IPL_TYPE_CCW;
++ return 0;
++}
++
++static int __init reipl_fcp_init(void)
++{
++ int rc;
++
++ if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
++ return 0;
++ if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
++ make_attrs_ro(reipl_fcp_attrs);
++
++ reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!reipl_block_fcp)
++ return -ENOMEM;
++ rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
++ if (rc) {
++ free_page((unsigned long)reipl_block_fcp);
++ return rc;
++ }
++ if (ipl_get_type() == IPL_TYPE_FCP) {
++ memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
++ } else {
++ reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
++ reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
++ reipl_block_fcp->hdr.blk0_len =
++ sizeof(reipl_block_fcp->ipl_info.fcp);
++ reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
++ reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
++ }
++ reipl_capabilities |= IPL_TYPE_FCP;
++ return 0;
++}
++
++static int __init reipl_init(void)
++{
++ int rc;
++
++ rc = firmware_register(&reipl_subsys);
++ if (rc)
++ return rc;
++ rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
++ if (rc) {
++ firmware_unregister(&reipl_subsys);
++ return rc;
++ }
++ rc = reipl_ccw_init();
++ if (rc)
++ return rc;
++ rc = reipl_fcp_init();
++ if (rc)
++ return rc;
++ rc = reipl_set_type(ipl_get_type());
++ if (rc)
++ return rc;
++ return 0;
++}
++
++static int __init dump_ccw_init(void)
++{
++ int rc;
++
++ dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!dump_block_ccw)
++ return -ENOMEM;
++ rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
++ if (rc) {
++ free_page((unsigned long)dump_block_ccw);
++ return rc;
++ }
++ dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
++ dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
++ dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
++ dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
++ dump_capabilities |= IPL_TYPE_CCW;
++ return 0;
++}
++
++extern char s390_readinfo_sccb[];
++
++static int __init dump_fcp_init(void)
++{
++ int rc;
++
++ if(!(s390_readinfo_sccb[91] & 0x2))
++ return 0; /* LDIPL DUMP is not installed */
++ if (!diag308_set_works)
++ return 0;
++ dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!dump_block_fcp)
++ return -ENOMEM;
++ rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
++ if (rc) {
++ free_page((unsigned long)dump_block_fcp);
++ return rc;
++ }
++ dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
++ dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
++ dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp);
++ dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
++ dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
++ dump_capabilities |= IPL_TYPE_FCP;
++ return 0;
++}
++
++#define SHUTDOWN_ON_PANIC_PRIO 0
++
++static int shutdown_on_panic_notify(struct notifier_block *self,
++ unsigned long event, void *data)
++{
++ if (on_panic_action == SHUTDOWN_DUMP)
++ do_dump();
++ else if (on_panic_action == SHUTDOWN_REIPL)
++ do_reipl();
++ return NOTIFY_OK;
++}
++
++static struct notifier_block shutdown_on_panic_nb = {
++ .notifier_call = shutdown_on_panic_notify,
++ .priority = SHUTDOWN_ON_PANIC_PRIO
++};
++
++static int __init dump_init(void)
++{
++ int rc;
++
++ rc = firmware_register(&dump_subsys);
++ if (rc)
++ return rc;
++ rc = subsys_create_file(&dump_subsys, &dump_type_attr);
++ if (rc) {
++ firmware_unregister(&dump_subsys);
++ return rc;
++ }
++ rc = dump_ccw_init();
++ if (rc)
++ return rc;
++ rc = dump_fcp_init();
++ if (rc)
++ return rc;
++ dump_set_type(IPL_TYPE_NONE);
++ return 0;
++}
++
++static int __init shutdown_actions_init(void)
++{
++ int rc;
++
++ rc = firmware_register(&shutdown_actions_subsys);
++ if (rc)
++ return rc;
++ rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
++ if (rc) {
++ firmware_unregister(&shutdown_actions_subsys);
++ return rc;
++ }
++ atomic_notifier_chain_register(&panic_notifier_list,
++ &shutdown_on_panic_nb);
++ return 0;
++}
++
++static int __init s390_ipl_init(void)
++{
++ int rc;
++
++ reipl_probe();
++ rc = ipl_init();
++ if (rc)
++ return rc;
++ rc = reipl_init();
++ if (rc)
++ return rc;
++ rc = dump_init();
++ if (rc)
++ return rc;
++ rc = shutdown_actions_init();
++ if (rc)
++ return rc;
++ return 0;
++}
++
++__initcall(s390_ipl_init);
+diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
+new file mode 100644
+index 0000000..67914fe
+--- /dev/null
++++ b/arch/s390/kernel/kprobes.c
+@@ -0,0 +1,661 @@
++/*
++ * Kernel Probes (KProbes)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) IBM Corporation, 2002, 2006
++ *
++ * s390 port, used ppc64 as template. Mike Grundy <grundym at us.ibm.com>
++ */
++
++#include <linux/kprobes.h>
++#include <linux/ptrace.h>
++#include <linux/preempt.h>
++#include <linux/stop_machine.h>
++#include <asm/cacheflush.h>
++#include <asm/kdebug.h>
++#include <asm/sections.h>
++#include <asm/uaccess.h>
++#include <linux/module.h>
++
++DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
++DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
++
++int __kprobes arch_prepare_kprobe(struct kprobe *p)
++{
++ /* Make sure the probe isn't going on a difficult instruction */
++ if (is_prohibited_opcode((kprobe_opcode_t *) p->addr))
++ return -EINVAL;
++
++ if ((unsigned long)p->addr & 0x01) {
++ printk("Attempt to register kprobe at an unaligned address\n");
++ return -EINVAL;
++ }
++
++ /* Use the get_insn_slot() facility for correctness */
++ if (!(p->ainsn.insn = get_insn_slot()))
++ return -ENOMEM;
++
++ memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
++
++ get_instruction_type(&p->ainsn);
++ p->opcode = *p->addr;
++ return 0;
++}
++
++int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
++{
++ switch (*(__u8 *) instruction) {
++ case 0x0c: /* bassm */
++ case 0x0b: /* bsm */
++ case 0x83: /* diag */
++ case 0x44: /* ex */
++ return -EINVAL;
++ }
++ switch (*(__u16 *) instruction) {
++ case 0x0101: /* pr */
++ case 0xb25a: /* bsa */
++ case 0xb240: /* bakr */
++ case 0xb258: /* bsg */
++ case 0xb218: /* pc */
++ case 0xb228: /* pt */
++ return -EINVAL;
++ }
++ return 0;
++}
++
++void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
++{
++ /* default fixup method */
++ ainsn->fixup = FIXUP_PSW_NORMAL;
++
++ /* save r1 operand */
++ ainsn->reg = (*ainsn->insn & 0xf0) >> 4;
++
++ /* save the instruction length (pop 5-5) in bytes */
++ switch (*(__u8 *) (ainsn->insn) >> 4) {
++ case 0:
++ ainsn->ilen = 2;
++ break;
++ case 1:
++ case 2:
++ ainsn->ilen = 4;
++ break;
++ case 3:
++ ainsn->ilen = 6;
++ break;
++ }
++
++ switch (*(__u8 *) ainsn->insn) {
++ case 0x05: /* balr */
++ case 0x0d: /* basr */
++ ainsn->fixup = FIXUP_RETURN_REGISTER;
++ /* if r2 = 0, no branch will be taken */
++ if ((*ainsn->insn & 0x0f) == 0)
++ ainsn->fixup |= FIXUP_BRANCH_NOT_TAKEN;
++ break;
++ case 0x06: /* bctr */
++ case 0x07: /* bcr */
++ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
++ break;
++ case 0x45: /* bal */
++ case 0x4d: /* bas */
++ ainsn->fixup = FIXUP_RETURN_REGISTER;
++ break;
++ case 0x47: /* bc */
++ case 0x46: /* bct */
++ case 0x86: /* bxh */
++ case 0x87: /* bxle */
++ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
++ break;
++ case 0x82: /* lpsw */
++ ainsn->fixup = FIXUP_NOT_REQUIRED;
++ break;
++ case 0xb2: /* lpswe */
++ if (*(((__u8 *) ainsn->insn) + 1) == 0xb2) {
++ ainsn->fixup = FIXUP_NOT_REQUIRED;
++ }
++ break;
++ case 0xa7: /* bras */
++ if ((*ainsn->insn & 0x0f) == 0x05) {
++ ainsn->fixup |= FIXUP_RETURN_REGISTER;
++ }
++ break;
++ case 0xc0:
++ if ((*ainsn->insn & 0x0f) == 0x00 /* larl */
++ || (*ainsn->insn & 0x0f) == 0x05) /* brasl */
++ ainsn->fixup |= FIXUP_RETURN_REGISTER;
++ break;
++ case 0xeb:
++ if (*(((__u8 *) ainsn->insn) + 5 ) == 0x44 || /* bxhg */
++ *(((__u8 *) ainsn->insn) + 5) == 0x45) {/* bxleg */
++ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
++ }
++ break;
++ case 0xe3: /* bctg */
++ if (*(((__u8 *) ainsn->insn) + 5) == 0x46) {
++ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
++ }
++ break;
++ }
++}
++
++static int __kprobes swap_instruction(void *aref)
++{
++ struct ins_replace_args *args = aref;
++ int err = -EFAULT;
++
++ asm volatile(
++ "0: mvc 0(2,%2),0(%3)\n"
++ "1: la %0,0\n"
++ "2:\n"
++ EX_TABLE(0b,2b)
++ : "+d" (err), "=m" (*args->ptr)
++ : "a" (args->ptr), "a" (&args->new), "m" (args->new));
++ return err;
++}
++
++void __kprobes arch_arm_kprobe(struct kprobe *p)
++{
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++ unsigned long status = kcb->kprobe_status;
++ struct ins_replace_args args;
++
++ args.ptr = p->addr;
++ args.old = p->opcode;
++ args.new = BREAKPOINT_INSTRUCTION;
++
++ kcb->kprobe_status = KPROBE_SWAP_INST;
++ stop_machine_run(swap_instruction, &args, NR_CPUS);
++ kcb->kprobe_status = status;
++}
++
++void __kprobes arch_disarm_kprobe(struct kprobe *p)
++{
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++ unsigned long status = kcb->kprobe_status;
++ struct ins_replace_args args;
++
++ args.ptr = p->addr;
++ args.old = BREAKPOINT_INSTRUCTION;
++ args.new = p->opcode;
++
++ kcb->kprobe_status = KPROBE_SWAP_INST;
++ stop_machine_run(swap_instruction, &args, NR_CPUS);
++ kcb->kprobe_status = status;
++}
++
++void __kprobes arch_remove_kprobe(struct kprobe *p)
++{
++ mutex_lock(&kprobe_mutex);
++ free_insn_slot(p->ainsn.insn);
++ mutex_unlock(&kprobe_mutex);
++}
++
++static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
++{
++ per_cr_bits kprobe_per_regs[1];
++
++ memset(kprobe_per_regs, 0, sizeof(per_cr_bits));
++ regs->psw.addr = (unsigned long)p->ainsn.insn | PSW_ADDR_AMODE;
++
++ /* Set up the per control reg info, will pass to lctl */
++ kprobe_per_regs[0].em_instruction_fetch = 1;
++ kprobe_per_regs[0].starting_addr = (unsigned long)p->ainsn.insn;
++ kprobe_per_regs[0].ending_addr = (unsigned long)p->ainsn.insn + 1;
++
++ /* Set the PER control regs, turns on single step for this address */
++ __ctl_load(kprobe_per_regs, 9, 11);
++ regs->psw.mask |= PSW_MASK_PER;
++ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
++}
++
++static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
++{
++ kcb->prev_kprobe.kp = kprobe_running();
++ kcb->prev_kprobe.status = kcb->kprobe_status;
++ kcb->prev_kprobe.kprobe_saved_imask = kcb->kprobe_saved_imask;
++ memcpy(kcb->prev_kprobe.kprobe_saved_ctl, kcb->kprobe_saved_ctl,
++ sizeof(kcb->kprobe_saved_ctl));
++}
++
++static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
++{
++ __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
++ kcb->kprobe_status = kcb->prev_kprobe.status;
++ kcb->kprobe_saved_imask = kcb->prev_kprobe.kprobe_saved_imask;
++ memcpy(kcb->kprobe_saved_ctl, kcb->prev_kprobe.kprobe_saved_ctl,
++ sizeof(kcb->kprobe_saved_ctl));
++}
++
++static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
++ struct kprobe_ctlblk *kcb)
++{
++ __get_cpu_var(current_kprobe) = p;
++ /* Save the interrupt and per flags */
++ kcb->kprobe_saved_imask = regs->psw.mask &
++ (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
++ /* Save the control regs that govern PER */
++ __ctl_store(kcb->kprobe_saved_ctl, 9, 11);
++}
++
++/* Called with kretprobe_lock held */
++void __kprobes 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->gprs[14];
++
++ /* Replace the return addr with trampoline addr */
++ regs->gprs[14] = (unsigned long)&kretprobe_trampoline;
++
++ add_rp_inst(ri);
++ } else {
++ rp->nmissed++;
++ }
++}
++
++static int __kprobes kprobe_handler(struct pt_regs *regs)
++{
++ struct kprobe *p;
++ int ret = 0;
++ unsigned long *addr = (unsigned long *)
++ ((regs->psw.addr & PSW_ADDR_INSN) - 2);
++ struct kprobe_ctlblk *kcb;
++
++ /*
++ * We don't want to be preempted for the entire
++ * duration of kprobe processing
++ */
++ preempt_disable();
++ kcb = get_kprobe_ctlblk();
++
++ /* Check we're not actually recursing */
++ if (kprobe_running()) {
++ p = get_kprobe(addr);
++ if (p) {
++ if (kcb->kprobe_status == KPROBE_HIT_SS &&
++ *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
++ regs->psw.mask &= ~PSW_MASK_PER;
++ regs->psw.mask |= kcb->kprobe_saved_imask;
++ goto no_kprobe;
++ }
++ /* We have reentered the kprobe_handler(), since
++ * another probe was hit while within the handler.
++ * We here save the original kprobes variables and
++ * just single step on the instruction of the new probe
++ * without calling any user handlers.
++ */
++ save_previous_kprobe(kcb);
++ set_current_kprobe(p, regs, kcb);
++ kprobes_inc_nmissed_count(p);
++ prepare_singlestep(p, regs);
++ kcb->kprobe_status = KPROBE_REENTER;
++ return 1;
++ } else {
++ p = __get_cpu_var(current_kprobe);
++ if (p->break_handler && p->break_handler(p, regs)) {
++ goto ss_probe;
++ }
++ }
++ goto no_kprobe;
++ }
++
++ p = get_kprobe(addr);
++ if (!p) {
++ if (*addr != BREAKPOINT_INSTRUCTION) {
++ /*
++ * The breakpoint instruction was removed right
++ * after we hit it. Another cpu has removed
++ * either a probepoint or a debugger breakpoint
++ * at this address. In either case, no further
++ * handling of this interrupt is appropriate.
++ *
++ */
++ ret = 1;
++ }
++ /* Not one of ours: let kernel handle it */
++ goto no_kprobe;
++ }
++
++ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
++ set_current_kprobe(p, regs, kcb);
++ if (p->pre_handler && p->pre_handler(p, regs))
++ /* handler has already set things up, so skip ss setup */
++ return 1;
++
++ss_probe:
++ prepare_singlestep(p, regs);
++ kcb->kprobe_status = KPROBE_HIT_SS;
++ return 1;
++
++no_kprobe:
++ preempt_enable_no_resched();
++ return ret;
++}
++
++/*
++ * Function return probe trampoline:
++ * - init_kprobes() establishes a probepoint here
++ * - When the probed function returns, this probe
++ * causes the handlers to fire
++ */
++void __kprobes kretprobe_trampoline_holder(void)
++{
++ asm volatile(".global kretprobe_trampoline\n"
++ "kretprobe_trampoline: bcr 0,0\n");
++}
++
++/*
++ * Called when the probe at kretprobe trampoline is hit
++ */
++int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
++{
++ struct kretprobe_instance *ri = NULL;
++ struct hlist_head *head, empty_rp;
++ struct hlist_node *node, *tmp;
++ unsigned long flags, orig_ret_address = 0;
++ unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
++
++ INIT_HLIST_HEAD(&empty_rp);
++ spin_lock_irqsave(&kretprobe_lock, flags);
++ 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, &empty_rp);
++
++ 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->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
++
++ reset_current_kprobe();
++ spin_unlock_irqrestore(&kretprobe_lock, flags);
++ preempt_enable_no_resched();
++
++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++ hlist_del(&ri->hlist);
++ kfree(ri);
++ }
++ /*
++ * By returning a non-zero value, we are telling
++ * kprobe_handler() that we don't want the post_handler
++ * to run (and have re-enabled 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
++ * temporarily put back the original opcode to single-step, we
++ * single-stepped a copy of the instruction. The address of this
++ * copy is p->ainsn.insn.
++ */
++static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
++{
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++
++ regs->psw.addr &= PSW_ADDR_INSN;
++
++ if (p->ainsn.fixup & FIXUP_PSW_NORMAL)
++ regs->psw.addr = (unsigned long)p->addr +
++ ((unsigned long)regs->psw.addr -
++ (unsigned long)p->ainsn.insn);
++
++ if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN)
++ if ((unsigned long)regs->psw.addr -
++ (unsigned long)p->ainsn.insn == p->ainsn.ilen)
++ regs->psw.addr = (unsigned long)p->addr + p->ainsn.ilen;
++
++ if (p->ainsn.fixup & FIXUP_RETURN_REGISTER)
++ regs->gprs[p->ainsn.reg] = ((unsigned long)p->addr +
++ (regs->gprs[p->ainsn.reg] -
++ (unsigned long)p->ainsn.insn))
++ | PSW_ADDR_AMODE;
++
++ regs->psw.addr |= PSW_ADDR_AMODE;
++ /* turn off PER mode */
++ regs->psw.mask &= ~PSW_MASK_PER;
++ /* Restore the original per control regs */
++ __ctl_load(kcb->kprobe_saved_ctl, 9, 11);
++ regs->psw.mask |= kcb->kprobe_saved_imask;
++}
++
++static int __kprobes post_kprobe_handler(struct pt_regs *regs)
++{
++ struct kprobe *cur = kprobe_running();
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++
++ if (!cur)
++ return 0;
++
++ if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
++ kcb->kprobe_status = KPROBE_HIT_SSDONE;
++ cur->post_handler(cur, regs, 0);
++ }
++
++ resume_execution(cur, regs);
++
++ /*Restore back the original saved kprobes variables and continue. */
++ if (kcb->kprobe_status == KPROBE_REENTER) {
++ restore_previous_kprobe(kcb);
++ goto out;
++ }
++ reset_current_kprobe();
++out:
++ preempt_enable_no_resched();
++
++ /*
++ * if somebody else is singlestepping across a probe point, psw mask
++ * will have PER set, in which case, continue the remaining processing
++ * of do_single_step, as if this is not a probe hit.
++ */
++ if (regs->psw.mask & PSW_MASK_PER) {
++ return 0;
++ }
++
++ return 1;
++}
++
++static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
++{
++ struct kprobe *cur = kprobe_running();
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++ const struct exception_table_entry *entry;
++
++ switch(kcb->kprobe_status) {
++ case KPROBE_SWAP_INST:
++ /* We are here because the instruction replacement failed */
++ return 0;
++ case KPROBE_HIT_SS:
++ case KPROBE_REENTER:
++ /*
++ * We are here because the instruction being single
++ * stepped caused a page fault. We reset the current
++ * kprobe and the nip points back to the probe address
++ * and allow the page fault handler to continue as a
++ * normal page fault.
++ */
++ regs->psw.addr = (unsigned long)cur->addr | PSW_ADDR_AMODE;
++ regs->psw.mask &= ~PSW_MASK_PER;
++ regs->psw.mask |= kcb->kprobe_saved_imask;
++ if (kcb->kprobe_status == KPROBE_REENTER)
++ restore_previous_kprobe(kcb);
++ else
++ reset_current_kprobe();
++ preempt_enable_no_resched();
++ break;
++ case KPROBE_HIT_ACTIVE:
++ case KPROBE_HIT_SSDONE:
++ /*
++ * We increment the nmissed count for accounting,
++ * we can also use npre/npostfault count for accouting
++ * these specific fault cases.
++ */
++ kprobes_inc_nmissed_count(cur);
++
++ /*
++ * We come here because instructions in the pre/post
++ * handler caused the page_fault, this could happen
++ * if handler tries to access user space by
++ * copy_from_user(), get_user() etc. Let the
++ * user-specified handler try to fix it first.
++ */
++ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
++ return 1;
++
++ /*
++ * In case the user-specified fault handler returned
++ * zero, try to fix up.
++ */
++ entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
++ if (entry) {
++ regs->psw.addr = entry->fixup | PSW_ADDR_AMODE;
++ return 1;
++ }
++
++ /*
++ * fixup_exception() could not handle it,
++ * Let do_page_fault() fix it.
++ */
++ break;
++ default:
++ break;
++ }
++ return 0;
++}
++
++/*
++ * Wrapper routine to for handling exceptions.
++ */
++int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data)
++{
++ struct die_args *args = (struct die_args *)data;
++ int ret = NOTIFY_DONE;
++
++ switch (val) {
++ case DIE_BPT:
++ if (kprobe_handler(args->regs))
++ ret = NOTIFY_STOP;
++ break;
++ case DIE_SSTEP:
++ if (post_kprobe_handler(args->regs))
++ ret = NOTIFY_STOP;
++ break;
++ case DIE_TRAP:
++ case DIE_PAGE_FAULT:
++ /* kprobe_running() needs smp_processor_id() */
++ preempt_disable();
++ if (kprobe_running() &&
++ kprobe_fault_handler(args->regs, args->trapnr))
++ ret = NOTIFY_STOP;
++ preempt_enable();
++ break;
++ default:
++ break;
++ }
++ return ret;
++}
++
++int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
++{
++ struct jprobe *jp = container_of(p, struct jprobe, kp);
++ unsigned long addr;
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++
++ memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
++
++ /* setup return addr to the jprobe handler routine */
++ regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
++
++ /* r14 is the function return address */
++ kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
++ /* r15 is the stack pointer */
++ kcb->jprobe_saved_r15 = (unsigned long)regs->gprs[15];
++ addr = (unsigned long)kcb->jprobe_saved_r15;
++
++ memcpy(kcb->jprobes_stack, (kprobe_opcode_t *) addr,
++ MIN_STACK_SIZE(addr));
++ return 1;
++}
++
++void __kprobes jprobe_return(void)
++{
++ asm volatile(".word 0x0002");
++}
++
++void __kprobes jprobe_return_end(void)
++{
++ asm volatile("bcr 0,0");
++}
++
++int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
++{
++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++ unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_r15);
++
++ /* Put the regs back */
++ memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs));
++ /* put the stack back */
++ memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,
++ MIN_STACK_SIZE(stack_addr));
++ preempt_enable_no_resched();
++ 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/s390/kernel/process.c b/arch/s390/kernel/process.c
+index d3cbfa3..6603fbb 100644
+--- a/arch/s390/kernel/process.c
++++ b/arch/s390/kernel/process.c
+@@ -45,7 +45,7 @@
+ #include <asm/irq.h>
+ #include <asm/timer.h>
+
+-asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
++asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
+
+ /*
+ * Return saved PC of a blocked thread. used in kernel/sched.
+@@ -177,7 +177,8 @@ void show_regs(struct pt_regs *regs)
+
+ extern void kernel_thread_starter(void);
+
+-__asm__(".align 4\n"
++asm(
++ ".align 4\n"
+ "kernel_thread_starter:\n"
+ " la 2,0(10)\n"
+ " basr 14,9\n"
+diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
+index 658e5ac..0340477 100644
+--- a/arch/s390/kernel/reipl.S
++++ b/arch/s390/kernel/reipl.S
+@@ -8,63 +8,82 @@
+
+ #include <asm/lowcore.h>
+
+- .globl do_reipl
+-do_reipl: basr %r13,0
++ .globl do_reipl_asm
++do_reipl_asm: basr %r13,0
+ .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
+-.Lpg1: lctl %c6,%c6,.Lall-.Lpg0(%r13)
+- stctl %c0,%c0,.Lctlsave-.Lpg0(%r13)
+- ni .Lctlsave-.Lpg0(%r13),0xef
+- lctl %c0,%c0,.Lctlsave-.Lpg0(%r13)
+- lr %r1,%r2
+- mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
+- stsch .Lschib-.Lpg0(%r13)
+- oi .Lschib+5-.Lpg0(%r13),0x84
+-.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+- msch .Lschib-.Lpg0(%r13)
+- lhi %r0,5
+-.Lssch: ssch .Liplorb-.Lpg0(%r13)
++
++ # switch off lowcore protection
++
++.Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13)
++ stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13)
++ ni .Lctlsave1-.Lpg0(%r13),0xef
++ lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13)
++
++ # do store status of all registers
++
++ stm %r0,%r15,__LC_GPREGS_SAVE_AREA
++ stctl %c0,%c15,__LC_CREGS_SAVE_AREA
++ mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13)
++ stam %a0,%a15,__LC_AREGS_SAVE_AREA
++ stpx __LC_PREFIX_SAVE_AREA
++ stckc .Lclkcmp-.Lpg0(%r13)
++ mvc __LC_CLOCK_COMP_SAVE_AREA(8),.Lclkcmp-.Lpg0(%r13)
++ stpt __LC_CPU_TIMER_SAVE_AREA
++ st %r13, __LC_PSW_SAVE_AREA+4
++
++ lctl %c6,%c6,.Lall-.Lpg0(%r13)
++ lr %r1,%r2
++ mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
++ stsch .Lschib-.Lpg0(%r13)
++ oi .Lschib+5-.Lpg0(%r13),0x84
++.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
++ msch .Lschib-.Lpg0(%r13)
++ lhi %r0,5
++.Lssch: ssch .Liplorb-.Lpg0(%r13)
+ jz .L001
+- brct %r0,.Lssch
++ brct %r0,.Lssch
+ bas %r14,.Ldisab-.Lpg0(%r13)
+-.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
+-.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
++.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
++.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
+ .Lcont: c %r1,__LC_SUBCHANNEL_ID
+ jnz .Ltpi
+ clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
+ jnz .Ltpi
+- tsch .Liplirb-.Lpg0(%r13)
++ tsch .Liplirb-.Lpg0(%r13)
+ tm .Liplirb+9-.Lpg0(%r13),0xbf
+- jz .L002
+- bas %r14,.Ldisab-.Lpg0(%r13)
+-.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+- jz .L003
+- bas %r14,.Ldisab-.Lpg0(%r13)
++ jz .L002
++ bas %r14,.Ldisab-.Lpg0(%r13)
++.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
++ jz .L003
++ bas %r14,.Ldisab-.Lpg0(%r13)
+ .L003: spx .Lnull-.Lpg0(%r13)
+- st %r1,__LC_SUBCHANNEL_ID
+- lpsw 0
+- sigp 0,0,0(6)
+-.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
++ st %r1,__LC_SUBCHANNEL_ID
++ lpsw 0
++ sigp 0,0,0(6)
++.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
+ lpsw .Ldispsw-.Lpg0(%r13)
+- .align 8
++ .align 8
++.Lclkcmp: .quad 0x0000000000000000
+ .Lall: .long 0xff000000
+-.Lnull: .long 0x00000000
+-.Lctlsave: .long 0x00000000
+- .align 8
+-.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
+-.Lpcnew: .long 0x00080000,0x80000000+.Lecs
+-.Lionew: .long 0x00080000,0x80000000+.Lcont
++.Lnull: .long 0x00000000
++.Lctlsave1: .long 0x00000000
++.Lctlsave2: .long 0x00000000
++ .align 8
++.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
++.Lpcnew: .long 0x00080000,0x80000000+.Lecs
++.Lionew: .long 0x00080000,0x80000000+.Lcont
+ .Lwaitpsw: .long 0x020a0000,0x00000000+.Ltpi
+-.Ldispsw: .long 0x000a0000,0x00000000
+-.Liplccws: .long 0x02000000,0x60000018
+- .long 0x08000008,0x20000001
++.Ldispsw: .long 0x000a0000,0x00000000
++.Liplccws: .long 0x02000000,0x60000018
++ .long 0x08000008,0x20000001
+ .Liplorb: .long 0x0049504c,0x0040ff80
+ .long 0x00000000+.Liplccws
+-.Lschib: .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
++.Lschib: .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
+ .Liplirb: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+@@ -73,6 +92,3 @@ do_reipl: basr %r13,0
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+-
+-
+-
+diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
+index 4d090d6..de74350 100644
+--- a/arch/s390/kernel/reipl64.S
++++ b/arch/s390/kernel/reipl64.S
+@@ -4,56 +4,74 @@
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski at de.ibm.com)
+- Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com)
++ Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com)
+ */
+
+ #include <asm/lowcore.h>
+- .globl do_reipl
+-do_reipl: basr %r13,0
+-.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
++ .globl do_reipl_asm
++do_reipl_asm: basr %r13,0
++
++ # do store status of all registers
++
++.Lpg0: stg %r1,.Lregsave-.Lpg0(%r13)
++ lghi %r1,0x1000
++ stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1)
++ lg %r0,.Lregsave-.Lpg0(%r13)
++ stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1)
++ stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1)
++ stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1)
++ stpx __LC_PREFIX_SAVE_AREA-0x1000(%r1)
++ stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1)
++ stckc .Lclkcmp-.Lpg0(%r13)
++ mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13)
++ stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)
++ stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1)
++
++ lpswe .Lnewpsw-.Lpg0(%r13)
+ .Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
+- stctg %c0,%c0,.Lctlsave-.Lpg0(%r13)
+- ni .Lctlsave+4-.Lpg0(%r13),0xef
+- lctlg %c0,%c0,.Lctlsave-.Lpg0(%r13)
+- lgr %r1,%r2
+- mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
+- stsch .Lschib-.Lpg0(%r13)
+- oi .Lschib+5-.Lpg0(%r13),0x84
+-.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+- msch .Lschib-.Lpg0(%r13)
+- lghi %r0,5
+-.Lssch: ssch .Liplorb-.Lpg0(%r13)
++ stctg %c0,%c0,.Lregsave-.Lpg0(%r13)
++ ni .Lregsave+4-.Lpg0(%r13),0xef
++ lctlg %c0,%c0,.Lregsave-.Lpg0(%r13)
++ lgr %r1,%r2
++ mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
++ stsch .Lschib-.Lpg0(%r13)
++ oi .Lschib+5-.Lpg0(%r13),0x84
++.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
++ msch .Lschib-.Lpg0(%r13)
++ lghi %r0,5
++.Lssch: ssch .Liplorb-.Lpg0(%r13)
+ jz .L001
+- brct %r0,.Lssch
++ brct %r0,.Lssch
+ bas %r14,.Ldisab-.Lpg0(%r13)
+-.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
+-.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
++.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
++.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
+ .Lcont: c %r1,__LC_SUBCHANNEL_ID
+ jnz .Ltpi
+ clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
+ jnz .Ltpi
+- tsch .Liplirb-.Lpg0(%r13)
++ tsch .Liplirb-.Lpg0(%r13)
+ tm .Liplirb+9-.Lpg0(%r13),0xbf
+- jz .L002
+- bas %r14,.Ldisab-.Lpg0(%r13)
+-.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+- jz .L003
+- bas %r14,.Ldisab-.Lpg0(%r13)
++ jz .L002
++ bas %r14,.Ldisab-.Lpg0(%r13)
++.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
++ jz .L003
++ bas %r14,.Ldisab-.Lpg0(%r13)
+ .L003: spx .Lnull-.Lpg0(%r13)
+- st %r1,__LC_SUBCHANNEL_ID
+- lhi %r1,0 # mode 0 = esa
+- slr %r0,%r0 # set cpuid to zero
+- sigp %r1,%r0,0x12 # switch to esa mode
+- lpsw 0
+-.Ldisab: sll %r14,1
+- srl %r14,1 # need to kill hi bit to avoid specification exceptions.
+- st %r14,.Ldispsw+12-.Lpg0(%r13)
++ st %r1,__LC_SUBCHANNEL_ID
++ lhi %r1,0 # mode 0 = esa
++ slr %r0,%r0 # set cpuid to zero
++ sigp %r1,%r0,0x12 # switch to esa mode
++ lpsw 0
++.Ldisab: sll %r14,1
++ srl %r14,1 # need to kill hi bit to avoid specification exceptions.
++ st %r14,.Ldispsw+12-.Lpg0(%r13)
+ lpswe .Ldispsw-.Lpg0(%r13)
+- .align 8
++ .align 8
++.Lclkcmp: .quad 0x0000000000000000
+ .Lall: .quad 0x00000000ff000000
+-.Lctlsave: .quad 0x0000000000000000
+-.Lnull: .long 0x0000000000000000
+- .align 16
++.Lregsave: .quad 0x0000000000000000
++.Lnull: .long 0x0000000000000000
++ .align 16
+ /*
+ * These addresses have to be 31 bit otherwise
+ * the sigp will throw a specifcation exception
+@@ -63,26 +81,26 @@ do_reipl: basr %r13,0
+ * 31bit lpswe instruction a fact they appear to have
+ * ommited from the pop.
+ */
+-.Lnewpsw: .quad 0x0000000080000000
+- .quad .Lpg1
+-.Lpcnew: .quad 0x0000000080000000
+- .quad .Lecs
+-.Lionew: .quad 0x0000000080000000
+- .quad .Lcont
++.Lnewpsw: .quad 0x0000000080000000
++ .quad .Lpg1
++.Lpcnew: .quad 0x0000000080000000
++ .quad .Lecs
++.Lionew: .quad 0x0000000080000000
++ .quad .Lcont
+ .Lwaitpsw: .quad 0x0202000080000000
+- .quad .Ltpi
+-.Ldispsw: .quad 0x0002000080000000
+- .quad 0x0000000000000000
+-.Liplccws: .long 0x02000000,0x60000018
+- .long 0x08000008,0x20000001
++ .quad .Ltpi
++.Ldispsw: .quad 0x0002000080000000
++ .quad 0x0000000000000000
++.Liplccws: .long 0x02000000,0x60000018
++ .long 0x08000008,0x20000001
+ .Liplorb: .long 0x0049504c,0x0040ff80
+ .long 0x00000000+.Liplccws
+-.Lschib: .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
+- .long 0x00000000,0x00000000
++.Lschib: .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
++ .long 0x00000000,0x00000000
+ .Liplirb: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+@@ -91,6 +109,3 @@ do_reipl: basr %r13,0
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+-
+-
+-
+diff --git a/arch/s390/kernel/reipl_diag.c b/arch/s390/kernel/reipl_diag.c
+deleted file mode 100644
+index 1f33951..0000000
+--- a/arch/s390/kernel/reipl_diag.c
++++ /dev/null
+@@ -1,39 +0,0 @@
+-/*
+- * This file contains the implementation of the
+- * Linux re-IPL support
+- *
+- * (C) Copyright IBM Corp. 2005
+- *
+- * Author(s): Volker Sameske (sameske at de.ibm.com)
+- *
+- */
+-
+-#include <linux/kernel.h>
+-
+-static unsigned int reipl_diag_rc1;
+-static unsigned int reipl_diag_rc2;
+-
+-/*
+- * re-IPL the system using the last used IPL parameters
+- */
+-void reipl_diag(void)
+-{
+- asm volatile (
+- " la %%r4,0\n"
+- " la %%r5,0\n"
+- " diag %%r4,%2,0x308\n"
+- "0:\n"
+- " st %%r4,%0\n"
+- " st %%r5,%1\n"
+- ".section __ex_table,\"a\"\n"
+-#ifdef CONFIG_64BIT
+- " .align 8\n"
+- " .quad 0b, 0b\n"
+-#else
+- " .align 4\n"
+- " .long 0b, 0b\n"
+-#endif
+- ".previous\n"
+- : "=m" (reipl_diag_rc1), "=m" (reipl_diag_rc2)
+- : "d" (3) : "cc", "4", "5" );
+-}
+diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
+index 2a25ec7..f9899ff 100644
+--- a/arch/s390/kernel/relocate_kernel.S
++++ b/arch/s390/kernel/relocate_kernel.S
+@@ -3,7 +3,7 @@
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+- * Author(s): Rolf Adelsberger <adelsberger at de.ibm.com>
++ * Author(s): Rolf Adelsberger,
+ * Heiko Carstens <heiko.carstens at de.ibm.com>
+ *
+ */
+@@ -24,14 +24,14 @@
+ .text
+ .globl relocate_kernel
+ relocate_kernel:
+- basr %r13,0 #base address
++ basr %r13,0 # base address
+ .base:
+- stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external)
+- spx zero64-.base(%r13) #absolute addressing mode
++ stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external)
++ spx zero64-.base(%r13) # absolute addressing mode
+ stctl %c0,%c15,ctlregs-.base(%r13)
+ stm %r0,%r15,gprregs-.base(%r13)
+ la %r1,load_psw-.base(%r13)
+- mvc 0(8,%r0),0(%r1)
++ mvc 0(8,%r0),0(%r1)
+ la %r0,.back-.base(%r13)
+ st %r0,4(%r0)
+ oi 4(%r0),0x80
+@@ -51,50 +51,50 @@
+ .back_pgm:
+ lm %r0,%r15,gprregs-.base(%r13)
+ .start_reloc:
+- lhi %r10,-1 #preparing the mask
+- sll %r10,12 #shift it such that it becomes 0xf000
++ 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
++ 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...
++ 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...
++ 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
++ 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
++ 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
++ mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
+ tm have_diag308-.base(%r13),0x01
+ jno .no_diag308
+ diag %r0,%r0,0x308
+ .no_diag308:
+- sr %r1,%r1 #clear %r1
+- sr %r2,%r2 #clear %r2
+- sigp %r1,%r2,0x12 #set cpuid to zero
+- lpsw 0 #hopefully start new kernel...
++ 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:
+diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
+index 8cdb86e..4fb4430 100644
+--- a/arch/s390/kernel/relocate_kernel64.S
++++ b/arch/s390/kernel/relocate_kernel64.S
+@@ -3,7 +3,7 @@
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+- * Author(s): Rolf Adelsberger <adelsberger at de.ibm.com>
++ * Author(s): Rolf Adelsberger,
+ * Heiko Carstens <heiko.carstens at de.ibm.com>
+ *
+ */
+@@ -25,10 +25,10 @@
+ .text
+ .globl relocate_kernel
+ relocate_kernel:
+- basr %r13,0 #base address
++ basr %r13,0 # base address
+ .base:
+- stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQs
+- spx zero64-.base(%r13) #absolute addressing mode
++ stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs
++ spx zero64-.base(%r13) # absolute addressing mode
+ stctg %c0,%c15,ctlregs-.base(%r13)
+ stmg %r0,%r15,gprregs-.base(%r13)
+ lghi %r0,3
+@@ -37,16 +37,16 @@
+ la %r0,.back_pgm-.base(%r13)
+ stg %r0,0x1d8(%r0)
+ la %r1,load_psw-.base(%r13)
+- mvc 0(8,%r0),0(%r1)
++ mvc 0(8,%r0),0(%r1)
+ la %r0,.back-.base(%r13)
+ st %r0,4(%r0)
+ oi 4(%r0),0x80
+ lghi %r0,0
+ diag %r0,%r0,0x308
+ .back:
+- lhi %r1,1 #mode 1 = esame
+- sigp %r1,%r0,0x12 #switch to esame mode
+- sam64 #switch to 64 bit addressing mode
++ lhi %r1,1 # mode 1 = esame
++ sigp %r1,%r0,0x12 # switch to esame mode
++ sam64 # switch to 64 bit addressing mode
+ basr %r13,0
+ .back_base:
+ oi have_diag308-.back_base(%r13),0x01
+@@ -56,50 +56,50 @@
+ .back_pgm:
+ lmg %r0,%r15,gprregs-.base(%r13)
+ .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
++ 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...
++ 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...
++ 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
++ 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
++ 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
++ 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
++ mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
+ tm have_diag308-.base(%r13),0x01
+ jno .no_diag308
+ diag %r0,%r0,0x308
+ .no_diag308:
+- 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...
++ 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
++ .align 8
+ zero64:
+ .quad 0
+ load_psw:
+diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
+index c1b3835..4faf96f 100644
+--- a/arch/s390/kernel/s390_ext.c
++++ b/arch/s390/kernel/s390_ext.c
+@@ -16,6 +16,7 @@
+
+ #include <asm/lowcore.h>
+ #include <asm/s390_ext.h>
++#include <asm/irq_regs.h>
+ #include <asm/irq.h>
+
+ /*
+@@ -114,7 +115,9 @@ void do_extint(struct pt_regs *regs, uns
+ {
+ ext_int_info_t *p;
+ int index;
++ struct pt_regs *old_regs;
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+ asm volatile ("mc 0,0");
+ if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+@@ -122,18 +125,18 @@ void do_extint(struct pt_regs *regs, uns
+ * Make sure that the i/o interrupt did not "overtake"
+ * the last HZ timer interrupt.
+ */
+- account_ticks(regs);
++ account_ticks();
+ kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+ index = ext_hash(code);
+ for (p = ext_int_hash[index]; p; p = p->next) {
+ if (likely(p->code == code)) {
+ if (likely(p->handler))
+- p->handler(regs, code);
++ p->handler(code);
+ }
+ }
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ EXPORT_SYMBOL(register_external_interrupt);
+ EXPORT_SYMBOL(unregister_external_interrupt);
+-
+diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
+index c73a454..90b5ef5 100644
+--- a/arch/s390/kernel/s390_ksyms.c
++++ b/arch/s390/kernel/s390_ksyms.c
+@@ -25,12 +25,6 @@ EXPORT_SYMBOL(_oi_bitmap);
+ EXPORT_SYMBOL(_ni_bitmap);
+ EXPORT_SYMBOL(_zb_findmap);
+ EXPORT_SYMBOL(_sb_findmap);
+-EXPORT_SYMBOL(__copy_from_user_asm);
+-EXPORT_SYMBOL(__copy_to_user_asm);
+-EXPORT_SYMBOL(__copy_in_user_asm);
+-EXPORT_SYMBOL(__clear_user_asm);
+-EXPORT_SYMBOL(__strncpy_from_user_asm);
+-EXPORT_SYMBOL(__strnlen_user_asm);
+ EXPORT_SYMBOL(diag10);
+
+ /*
+@@ -57,4 +51,3 @@ EXPORT_SYMBOL(csum_fold);
+ EXPORT_SYMBOL(console_mode);
+ EXPORT_SYMBOL(console_devno);
+ EXPORT_SYMBOL(console_irq);
+-EXPORT_SYMBOL(sys_wait4);
+diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
+index 8dfb690..191303f 100644
+--- a/arch/s390/kernel/semaphore.c
++++ b/arch/s390/kernel/semaphore.c
+@@ -26,17 +26,17 @@ static inline int __sem_update_count(str
+ {
+ int old_val, new_val;
+
+- __asm__ __volatile__(" l %0,0(%3)\n"
+- "0: ltr %1,%0\n"
+- " jhe 1f\n"
+- " lhi %1,0\n"
+- "1: ar %1,%4\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b\n"
+- : "=&d" (old_val), "=&d" (new_val),
+- "=m" (sem->count)
+- : "a" (&sem->count), "d" (incr), "m" (sem->count)
+- : "cc" );
++ asm volatile(
++ " l %0,0(%3)\n"
++ "0: ltr %1,%0\n"
++ " jhe 1f\n"
++ " lhi %1,0\n"
++ "1: ar %1,%4\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b\n"
++ : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count)
++ : "a" (&sem->count), "d" (incr), "m" (sem->count)
++ : "cc");
+ return old_val;
+ }
+
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index c902f05..2aa13e8 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -37,6 +37,7 @@
+ #include <linux/kernel_stat.h>
+ #include <linux/device.h>
+ #include <linux/notifier.h>
++#include <linux/pfn.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -50,6 +51,12 @@
+ #include <asm/sections.h>
+
+ /*
++ * User copy operations.
++ */
++struct uaccess_ops uaccess;
++EXPORT_SYMBOL_GPL(uaccess);
++
++/*
+ * Machine setup..
+ */
+ unsigned int console_mode = 0;
+@@ -94,7 +101,7 @@ void __devinit cpu_init (void)
+ /*
+ * Store processor id in lowcore (used e.g. in timer_interrupt)
+ */
+- asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
++ asm volatile("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
+ S390_lowcore.cpu_data.cpu_addr = addr;
+
+ /*
+@@ -284,16 +291,9 @@ void (*_machine_power_off)(void) = machi
+ /*
+ * Reboot, halt and power_off routines for non SMP.
+ */
+-extern void reipl(unsigned long devno);
+-extern void reipl_diag(void);
+ static void do_machine_restart_nonsmp(char * __unused)
+ {
+- reipl_diag();
+-
+- if (MACHINE_IS_VM)
+- cpcmd ("IPL", NULL, 0, NULL);
+- else
+- reipl (0x10000 | S390_lowcore.ipl_device);
++ do_reipl();
+ }
+
+ static void do_machine_halt_nonsmp(void)
+@@ -450,7 +450,7 @@ setup_lowcore(void)
+ lc->extended_save_area_addr = (__u32)
+ __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+ /* enable extended save area */
+- ctl_set_bit(14, 29);
++ __ctl_set_bit(14, 29);
+ }
+ #endif
+ set_prefix((u32)(unsigned long) lc);
+@@ -501,15 +501,49 @@ setup_memory(void)
+ * partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+- start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+- end_pfn = max_pfn = memory_end >> PAGE_SHIFT;
++ start_pfn = PFN_UP(__pa(&_end));
++ end_pfn = max_pfn = PFN_DOWN(memory_end);
+
+ /* Initialize storage key for kernel pages */
+ for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
+ page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+
++#ifdef CONFIG_BLK_DEV_INITRD
+ /*
+- * Initialize the boot-time allocator (with low memory only):
++ * Move the initrd in case the bitmap of the bootmem allocater
++ * would overwrite it.
++ */
++
++ if (INITRD_START && INITRD_SIZE) {
++ unsigned long bmap_size;
++ unsigned long start;
++
++ bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1);
++ bmap_size = PFN_PHYS(bmap_size);
++
++ if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) {
++ start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE;
++
++ if (start + INITRD_SIZE > memory_end) {
++ printk("initrd extends beyond end of memory "
++ "(0x%08lx > 0x%08lx)\n"
++ "disabling initrd\n",
++ start + INITRD_SIZE, memory_end);
++ INITRD_START = INITRD_SIZE = 0;
++ } else {
++ printk("Moving initrd (0x%08lx -> 0x%08lx, "
++ "size: %ld)\n",
++ INITRD_START, start, INITRD_SIZE);
++ memmove((void *) start, (void *) INITRD_START,
++ INITRD_SIZE);
++ INITRD_START = start;
++ }
++ }
++ }
++#endif
++
++ /*
++ * Initialize the boot-time allocator
+ */
+ bootmap_size = init_bootmem(start_pfn, end_pfn);
+
+@@ -559,7 +593,7 @@ setup_memory(void)
+ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
+
+ #ifdef CONFIG_BLK_DEV_INITRD
+- if (INITRD_START) {
++ if (INITRD_START && INITRD_SIZE) {
+ if (INITRD_START + INITRD_SIZE <= memory_end) {
+ reserve_bootmem(INITRD_START, INITRD_SIZE);
+ initrd_start = INITRD_START;
+@@ -613,6 +647,11 @@ setup_arch(char **cmdline_p)
+
+ memory_end = memory_size;
+
++ if (MACHINE_HAS_MVCOS)
++ memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess));
++ else
++ memcpy(&uaccess, &uaccess_std, sizeof(uaccess));
++
+ parse_early_param();
+
+ #ifndef CONFIG_64BIT
+@@ -720,214 +759,3 @@ struct seq_operations cpuinfo_op = {
+ .show = show_cpuinfo,
+ };
+
+-#define DEFINE_IPL_ATTR(_name, _format, _value) \
+-static ssize_t ipl_##_name##_show(struct subsystem *subsys, \
+- char *page) \
+-{ \
+- return sprintf(page, _format, _value); \
+-} \
+-static struct subsys_attribute ipl_##_name##_attr = \
+- __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL);
+-
+-DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long)
+- IPL_PARMBLOCK_START->fcp.wwpn);
+-DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long)
+- IPL_PARMBLOCK_START->fcp.lun);
+-DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long)
+- IPL_PARMBLOCK_START->fcp.bootprog);
+-DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long)
+- IPL_PARMBLOCK_START->fcp.br_lba);
+-
+-enum ipl_type_type {
+- ipl_type_unknown,
+- ipl_type_ccw,
+- ipl_type_fcp,
+-};
+-
+-static enum ipl_type_type
+-get_ipl_type(void)
+-{
+- struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+-
+- if (!IPL_DEVNO_VALID)
+- return ipl_type_unknown;
+- if (!IPL_PARMBLOCK_VALID)
+- return ipl_type_ccw;
+- if (ipl->hdr.header.version > IPL_MAX_SUPPORTED_VERSION)
+- return ipl_type_unknown;
+- if (ipl->fcp.pbt != IPL_TYPE_FCP)
+- return ipl_type_unknown;
+- return ipl_type_fcp;
+-}
+-
+-static ssize_t
+-ipl_type_show(struct subsystem *subsys, char *page)
+-{
+- switch (get_ipl_type()) {
+- case ipl_type_ccw:
+- return sprintf(page, "ccw\n");
+- case ipl_type_fcp:
+- return sprintf(page, "fcp\n");
+- default:
+- return sprintf(page, "unknown\n");
+- }
+-}
+-
+-static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type);
+-
+-static ssize_t
+-ipl_device_show(struct subsystem *subsys, char *page)
+-{
+- struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+-
+- switch (get_ipl_type()) {
+- case ipl_type_ccw:
+- return sprintf(page, "0.0.%04x\n", ipl_devno);
+- case ipl_type_fcp:
+- return sprintf(page, "0.0.%04x\n", ipl->fcp.devno);
+- default:
+- return 0;
+- }
+-}
+-
+-static struct subsys_attribute ipl_device_attr =
+- __ATTR(device, S_IRUGO, ipl_device_show, NULL);
+-
+-static struct attribute *ipl_fcp_attrs[] = {
+- &ipl_type_attr.attr,
+- &ipl_device_attr.attr,
+- &ipl_wwpn_attr.attr,
+- &ipl_lun_attr.attr,
+- &ipl_bootprog_attr.attr,
+- &ipl_br_lba_attr.attr,
+- NULL,
+-};
+-
+-static struct attribute_group ipl_fcp_attr_group = {
+- .attrs = ipl_fcp_attrs,
+-};
+-
+-static struct attribute *ipl_ccw_attrs[] = {
+- &ipl_type_attr.attr,
+- &ipl_device_attr.attr,
+- NULL,
+-};
+-
+-static struct attribute_group ipl_ccw_attr_group = {
+- .attrs = ipl_ccw_attrs,
+-};
+-
+-static struct attribute *ipl_unknown_attrs[] = {
+- &ipl_type_attr.attr,
+- NULL,
+-};
+-
+-static struct attribute_group ipl_unknown_attr_group = {
+- .attrs = ipl_unknown_attrs,
+-};
+-
+-static ssize_t
+-ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+-{
+- unsigned int size = IPL_PARMBLOCK_SIZE;
+-
+- if (off > size)
+- return 0;
+- if (off + count > size)
+- count = size - off;
+-
+- memcpy(buf, (void *) IPL_PARMBLOCK_START + off, count);
+- return count;
+-}
+-
+-static struct bin_attribute ipl_parameter_attr = {
+- .attr = {
+- .name = "binary_parameter",
+- .mode = S_IRUGO,
+- .owner = THIS_MODULE,
+- },
+- .size = PAGE_SIZE,
+- .read = &ipl_parameter_read,
+-};
+-
+-static ssize_t
+-ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+-{
+- unsigned int size = IPL_PARMBLOCK_START->fcp.scp_data_len;
+- void *scp_data = &IPL_PARMBLOCK_START->fcp.scp_data;
+-
+- if (off > size)
+- return 0;
+- if (off + count > size)
+- count = size - off;
+-
+- memcpy(buf, scp_data + off, count);
+- return count;
+-}
+-
+-static struct bin_attribute ipl_scp_data_attr = {
+- .attr = {
+- .name = "scp_data",
+- .mode = S_IRUGO,
+- .owner = THIS_MODULE,
+- },
+- .size = PAGE_SIZE,
+- .read = &ipl_scp_data_read,
+-};
+-
+-static decl_subsys(ipl, NULL, NULL);
+-
+-static int ipl_register_fcp_files(void)
+-{
+- int rc;
+-
+- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+- &ipl_fcp_attr_group);
+- if (rc)
+- goto out;
+- rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+- &ipl_parameter_attr);
+- if (rc)
+- goto out_ipl_parm;
+- rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+- &ipl_scp_data_attr);
+- if (!rc)
+- goto out;
+-
+- sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
+-
+-out_ipl_parm:
+- sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
+-out:
+- return rc;
+-}
+-
+-static int __init
+-ipl_device_sysfs_register(void) {
+- int rc;
+-
+- rc = firmware_register(&ipl_subsys);
+- if (rc)
+- goto out;
+-
+- switch (get_ipl_type()) {
+- case ipl_type_ccw:
+- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+- &ipl_ccw_attr_group);
+- break;
+- case ipl_type_fcp:
+- rc = ipl_register_fcp_files();
+- break;
+- default:
+- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+- &ipl_unknown_attr_group);
+- break;
+- }
+-
+- if (rc)
+- firmware_unregister(&ipl_subsys);
+-out:
+- return rc;
+-}
+-
+-__initcall(ipl_device_sysfs_register);
+diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
+index a887b68..4c8a795 100644
+--- a/arch/s390/kernel/signal.c
++++ b/arch/s390/kernel/signal.c
+@@ -80,10 +80,10 @@ sys_sigaction(int sig, const struct old_
+ old_sigset_t mask;
+ if (!access_ok(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))
++ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
++ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
++ __get_user(mask, &act->sa_mask))
+ 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);
+ }
+
+@@ -92,10 +92,10 @@ sys_sigaction(int sig, const struct old_
+ if (!ret && oact) {
+ if (!access_ok(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))
++ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
++ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
++ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+ 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;
+@@ -113,58 +113,50 @@ sys_sigaltstack(const stack_t __user *us
+ /* Returns non-zero on fault. */
+ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
+ {
+- unsigned long old_mask = regs->psw.mask;
+- int err;
+-
++ _sigregs user_sregs;
++
+ save_access_regs(current->thread.acrs);
+
+ /* Copy a 'clean' PSW mask to the user to avoid leaking
+ information about whether PER is currently on. */
+- regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
+- err = __copy_to_user(&sregs->regs.psw, ®s->psw,
+- sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
+- regs->psw.mask = old_mask;
+- if (err != 0)
+- return err;
+- err = __copy_to_user(&sregs->regs.acrs, current->thread.acrs,
+- sizeof(sregs->regs.acrs));
+- if (err != 0)
+- return err;
++ user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
++ user_sregs.regs.psw.addr = regs->psw.addr;
++ memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs));
++ memcpy(&user_sregs.regs.acrs, current->thread.acrs,
++ sizeof(sregs->regs.acrs));
+ /*
+ * We have to store the fp registers to current->thread.fp_regs
+ * to merge them with the emulated registers.
+ */
+ save_fp_regs(¤t->thread.fp_regs);
+- return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs,
+- sizeof(s390_fp_regs));
++ memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs,
++ sizeof(s390_fp_regs));
++ return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs));
+ }
+
+ /* Returns positive number on error */
+ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
+ {
+- unsigned long old_mask = regs->psw.mask;
+ int err;
++ _sigregs user_sregs;
+
+ /* Alwys make any pending restarted system call return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+- err = __copy_from_user(®s->psw, &sregs->regs.psw,
+- sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
+- regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask);
+- regs->psw.addr |= PSW_ADDR_AMODE;
+- if (err)
+- return err;
+- err = __copy_from_user(¤t->thread.acrs, &sregs->regs.acrs,
+- sizeof(sregs->regs.acrs));
++ err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
+ if (err)
+ return err;
++ regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
++ user_sregs.regs.psw.mask);
++ regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr;
++ memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
++ memcpy(¤t->thread.acrs, &user_sregs.regs.acrs,
++ sizeof(sregs->regs.acrs));
+ restore_access_regs(current->thread.acrs);
+
+- err = __copy_from_user(¤t->thread.fp_regs, &sregs->fpregs,
+- sizeof(s390_fp_regs));
++ memcpy(¤t->thread.fp_regs, &user_sregs.fpregs,
++ sizeof(s390_fp_regs));
+ current->thread.fp_regs.fpc &= FPC_VALID_MASK;
+- if (err)
+- return err;
+
+ restore_fp_regs(¤t->thread.fp_regs);
+ regs->trap = -1; /* disable syscall checks */
+@@ -457,6 +449,7 @@ void do_signal(struct pt_regs *regs)
+ case -ERESTART_RESTARTBLOCK:
+ regs->gprs[2] = -EINTR;
+ }
++ regs->trap = -1; /* Don't deal with this again. */
+ }
+
+ /* Get signal to deliver. When running under ptrace, at this point
+diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
+index 8e03219..6282224 100644
+--- a/arch/s390/kernel/smp.c
++++ b/arch/s390/kernel/smp.c
+@@ -59,14 +59,11 @@ static struct task_struct *current_set[N
+ extern char vmhalt_cmd[];
+ extern char vmpoff_cmd[];
+
+-extern void reipl(unsigned long devno);
+-extern void reipl_diag(void);
+-
+ static void smp_ext_bitcall(int, ec_bit_sig);
+ static void smp_ext_bitcall_others(ec_bit_sig);
+
+ /*
+- * Structure and data for smp_call_function(). This is designed to minimise
++5B * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+ static DEFINE_SPINLOCK(call_lock);
+@@ -279,12 +276,7 @@ static void do_machine_restart(void * __
+ * interrupted by an external interrupt and s390irq
+ * locks are always held disabled).
+ */
+- reipl_diag();
+-
+- if (MACHINE_IS_VM)
+- cpcmd ("IPL", NULL, 0, NULL);
+- else
+- reipl (0x10000 | S390_lowcore.ipl_device);
++ do_reipl();
+ }
+
+ void machine_restart_smp(char * __unused)
+@@ -347,7 +339,7 @@ void machine_power_off_smp(void)
+ * cpus are handled.
+ */
+
+-void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
++void do_ext_call_interrupt(__u16 code)
+ {
+ unsigned long bits;
+
+@@ -426,59 +418,49 @@ void smp_send_reschedule(int cpu)
+ /*
+ * parameter area for the set/clear control bit callbacks
+ */
+-typedef struct
+-{
+- __u16 start_ctl;
+- __u16 end_ctl;
++struct ec_creg_mask_parms {
+ unsigned long orvals[16];
+ unsigned long andvals[16];
+-} ec_creg_mask_parms;
++};
+
+ /*
+ * callback for setting/clearing control bits
+ */
+ void smp_ctl_bit_callback(void *info) {
+- ec_creg_mask_parms *pp;
++ struct ec_creg_mask_parms *pp = info;
+ unsigned long cregs[16];
+ int i;
+
+- pp = (ec_creg_mask_parms *) info;
+- __ctl_store(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl);
+- for (i = pp->start_ctl; i <= pp->end_ctl; i++)
++ __ctl_store(cregs, 0, 15);
++ for (i = 0; i <= 15; i++)
+ cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
+- __ctl_load(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl);
++ __ctl_load(cregs, 0, 15);
+ }
+
+ /*
+ * Set a bit in a control register of all cpus
+ */
+-void smp_ctl_set_bit(int cr, int bit) {
+- ec_creg_mask_parms parms;
++void smp_ctl_set_bit(int cr, int bit)
++{
++ struct ec_creg_mask_parms parms;
+
+- parms.start_ctl = cr;
+- parms.end_ctl = cr;
++ memset(&parms.orvals, 0, sizeof(parms.orvals));
++ memset(&parms.andvals, 0xff, sizeof(parms.andvals));
+ parms.orvals[cr] = 1 << bit;
+- parms.andvals[cr] = -1L;
+- preempt_disable();
+- smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
+- __ctl_set_bit(cr, bit);
+- preempt_enable();
++ on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
+ }
+
+ /*
+ * Clear a bit in a control register of all cpus
+ */
+-void smp_ctl_clear_bit(int cr, int bit) {
+- ec_creg_mask_parms parms;
++void smp_ctl_clear_bit(int cr, int bit)
++{
++ struct ec_creg_mask_parms parms;
+
+- parms.start_ctl = cr;
+- parms.end_ctl = cr;
+- parms.orvals[cr] = 0;
++ memset(&parms.orvals, 0, sizeof(parms.orvals));
++ memset(&parms.andvals, 0xff, sizeof(parms.andvals));
+ parms.andvals[cr] = ~(1L << bit);
+- preempt_disable();
+- smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
+- __ctl_clear_bit(cr, bit);
+- preempt_enable();
++ on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
+ }
+
+ /*
+@@ -658,9 +640,9 @@ __cpu_up(unsigned int cpu)
+ sf->gprs[9] = (unsigned long) sf;
+ cpu_lowcore->save_area[15] = (unsigned long) sf;
+ __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15);
+- __asm__ __volatile__("stam 0,15,0(%0)"
+- : : "a" (&cpu_lowcore->access_regs_save_area)
+- : "memory");
++ asm volatile(
++ " stam 0,15,0(%0)"
++ : : "a" (&cpu_lowcore->access_regs_save_area) : "memory");
+ cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
+ cpu_lowcore->current_task = (unsigned long) idle;
+ cpu_lowcore->cpu_data.cpu_nr = cpu;
+@@ -716,7 +698,7 @@ int
+ __cpu_disable(void)
+ {
+ unsigned long flags;
+- ec_creg_mask_parms cr_parms;
++ struct ec_creg_mask_parms cr_parms;
+ int cpu = smp_processor_id();
+
+ spin_lock_irqsave(&smp_reserve_lock, flags);
+@@ -732,30 +714,21 @@ __cpu_disable(void)
+ pfault_fini();
+ #endif
+
+- /* disable all external interrupts */
++ memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals));
++ memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals));
+
+- cr_parms.start_ctl = 0;
+- cr_parms.end_ctl = 0;
++ /* disable all external interrupts */
+ cr_parms.orvals[0] = 0;
+ cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 |
+ 1<<11 | 1<<10 | 1<< 6 | 1<< 4);
+- smp_ctl_bit_callback(&cr_parms);
+-
+ /* disable all I/O interrupts */
+-
+- cr_parms.start_ctl = 6;
+- cr_parms.end_ctl = 6;
+ cr_parms.orvals[6] = 0;
+ cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 |
+ 1<<27 | 1<<26 | 1<<25 | 1<<24);
+- smp_ctl_bit_callback(&cr_parms);
+-
+ /* disable most machine checks */
+-
+- cr_parms.start_ctl = 14;
+- cr_parms.end_ctl = 14;
+ cr_parms.orvals[14] = 0;
+ cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24);
++
+ smp_ctl_bit_callback(&cr_parms);
+
+ spin_unlock_irqrestore(&smp_reserve_lock, flags);
+diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
+index de83f38..0d14a47 100644
+--- a/arch/s390/kernel/stacktrace.c
++++ b/arch/s390/kernel/stacktrace.c
+@@ -59,32 +59,30 @@ static inline unsigned long save_context
+ }
+ }
+
+-void save_stack_trace(struct stack_trace *trace,
+- struct task_struct *task, int all_contexts,
+- unsigned int skip)
++void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+ {
+ register unsigned long sp asm ("15");
+- unsigned long orig_sp;
++ unsigned long orig_sp, new_sp;
+
+- sp &= PSW_ADDR_INSN;
+- orig_sp = sp;
++ orig_sp = sp & PSW_ADDR_INSN;
+
+- sp = save_context_stack(trace, &skip, sp,
++ new_sp = save_context_stack(trace, &trace->skip, orig_sp,
+ S390_lowcore.panic_stack - PAGE_SIZE,
+ S390_lowcore.panic_stack);
+- if ((sp != orig_sp) && !all_contexts)
++ if ((new_sp != orig_sp) && !trace->all_contexts)
+ return;
+- sp = save_context_stack(trace, &skip, sp,
++ new_sp = save_context_stack(trace, &trace->skip, new_sp,
+ S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack);
+- if ((sp != orig_sp) && !all_contexts)
++ if ((new_sp != orig_sp) && !trace->all_contexts)
+ return;
+ if (task)
+- save_context_stack(trace, &skip, sp,
++ save_context_stack(trace, &trace->skip, new_sp,
+ (unsigned long) task_stack_page(task),
+ (unsigned long) task_stack_page(task) + THREAD_SIZE);
+ else
+- save_context_stack(trace, &skip, sp, S390_lowcore.thread_info,
++ save_context_stack(trace, &trace->skip, new_sp,
++ S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE);
+ return;
+ }
+diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
+index e351780..584ed95 100644
+--- a/arch/s390/kernel/sys_s390.c
++++ b/arch/s390/kernel/sys_s390.c
+@@ -27,6 +27,7 @@
+ #include <linux/file.h>
+ #include <linux/utsname.h>
+ #include <linux/personality.h>
++#include <linux/unistd.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
+@@ -266,3 +267,22 @@ s390_fadvise64_64(struct fadvise64_64_ar
+ return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
+ }
+
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register const char *__arg1 asm("2") = filename;
++ register char *const*__arg2 asm("3") = argv;
++ register char *const*__arg3 asm("4") = envp;
++ register long __svcres asm("2");
++ asm volatile(
++ "svc %b1"
++ : "=d" (__svcres)
++ : "i" (__NR_execve),
++ "0" (__arg1),
++ "d" (__arg2),
++ "d" (__arg3) : "memory");
++ return __svcres;
++}
+diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
+index 93be1d5..a4ceae3 100644
+--- a/arch/s390/kernel/syscalls.S
++++ b/arch/s390/kernel/syscalls.S
+@@ -318,3 +318,6 @@ SYSCALL(sys_splice,sys_splice,sys_splice
+ SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
+ SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
+ SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper)
++NI_SYSCALL /* 310 sys_move_pages */
++SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
++SYSCALL(sys_epoll_pwait,sys_epoll_pwait,sys_ni_syscall)
+diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
+index 74e6178..6cceed4 100644
+--- a/arch/s390/kernel/time.c
++++ b/arch/s390/kernel/time.c
+@@ -28,12 +28,14 @@
+ #include <linux/profile.h>
+ #include <linux/timex.h>
+ #include <linux/notifier.h>
++#include <linux/clocksource.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/delay.h>
+ #include <asm/s390_ext.h>
+ #include <asm/div64.h>
+ #include <asm/irq.h>
++#include <asm/irq_regs.h>
+ #include <asm/timer.h>
+
+ /* change this if you have some constant time drift */
+@@ -53,8 +55,6 @@ static u64 init_timer_cc;
+ static u64 jiffies_timer_cc;
+ static u64 xtime_cc;
+
+-extern unsigned long wall_jiffies;
+-
+ /*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+@@ -83,79 +83,10 @@ void tod_to_timeval(__u64 todval, struct
+ xtime->tv_nsec = ((todval * 1000) >> 12);
+ }
+
+-static inline unsigned long do_gettimeoffset(void)
+-{
+- __u64 now;
+-
+- now = (get_clock() - jiffies_timer_cc) >> 12;
+- /* We require the offset from the latest update of xtime */
+- now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
+- return (unsigned long) now;
+-}
+-
+-/*
+- * This version of gettimeofday has microsecond resolution.
+- */
+-void do_gettimeofday(struct timeval *tv)
+-{
+- unsigned long flags;
+- unsigned long seq;
+- unsigned long usec, sec;
+-
+- do {
+- seq = read_seqbegin_irqsave(&xtime_lock, flags);
+-
+- sec = xtime.tv_sec;
+- usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
+- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+-
+- while (usec >= 1000000) {
+- usec -= 1000000;
+- sec++;
+- }
+-
+- tv->tv_sec = sec;
+- tv->tv_usec = usec;
+-}
+-
+-EXPORT_SYMBOL(do_gettimeofday);
+-
+-int do_settimeofday(struct timespec *tv)
+-{
+- time_t wtm_sec, sec = tv->tv_sec;
+- long wtm_nsec, nsec = tv->tv_nsec;
+-
+- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+- return -EINVAL;
+-
+- write_seqlock_irq(&xtime_lock);
+- /* This is revolting. We need to set the xtime.tv_nsec
+- * correctly. However, the value in this location is
+- * is value at the last tick.
+- * Discover what correction gettimeofday
+- * would have done, and then undo it!
+- */
+- nsec -= do_gettimeoffset() * 1000;
+-
+- 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);
+-
+- ntp_clear();
+- write_sequnlock_irq(&xtime_lock);
+- clock_was_set();
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(do_settimeofday);
+-
+-
+ #ifdef CONFIG_PROFILING
+-#define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs)
++#define s390_do_profile() profile_tick(CPU_PROFILING)
+ #else
+-#define s390_do_profile(regs) do { ; } while(0)
++#define s390_do_profile() do { ; } while(0)
+ #endif /* CONFIG_PROFILING */
+
+
+@@ -163,10 +94,10 @@ EXPORT_SYMBOL(do_settimeofday);
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+-void account_ticks(struct pt_regs *regs)
++void account_ticks(void)
+ {
+ __u64 tmp;
+- __u32 ticks, xticks;
++ __u32 ticks;
+
+ /* Calculate how many ticks have passed. */
+ if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
+@@ -204,6 +135,7 @@ void account_ticks(struct pt_regs *regs)
+ */
+ write_seqlock(&xtime_lock);
+ if (S390_lowcore.jiffy_timer > xtime_cc) {
++ __u32 xticks;
+ tmp = S390_lowcore.jiffy_timer - xtime_cc;
+ if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
+ xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
+@@ -212,23 +144,21 @@ void account_ticks(struct pt_regs *regs)
+ xticks = 1;
+ xtime_cc += CLK_TICKS_PER_JIFFY;
+ }
+- while (xticks--)
+- do_timer(regs);
++ do_timer(xticks);
+ }
+ write_sequnlock(&xtime_lock);
+ #else
+- for (xticks = ticks; xticks > 0; xticks--)
+- do_timer(regs);
++ do_timer(ticks);
+ #endif
+
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ account_tick_vtime(current);
+ #else
+ while (ticks--)
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+
+- s390_do_profile(regs);
++ s390_do_profile();
+ }
+
+ #ifdef CONFIG_NO_IDLE_HZ
+@@ -289,9 +219,11 @@ static inline void stop_hz_timer(void)
+ */
+ static inline void start_hz_timer(void)
+ {
++ BUG_ON(!in_interrupt());
++
+ if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
+ return;
+- account_ticks(task_pt_regs(current));
++ account_ticks();
+ cpu_clear(smp_processor_id(), nohz_cpu_mask);
+ }
+
+@@ -341,6 +273,22 @@ void init_cpu_timer(void)
+
+ extern void vtime_init(void);
+
++static cycle_t read_tod_clock(void)
++{
++ return get_clock();
++}
++
++static struct clocksource clocksource_tod = {
++ .name = "tod",
++ .rating = 100,
++ .read = read_tod_clock,
++ .mask = -1ULL,
++ .mult = 1000,
++ .shift = 12,
++ .is_continuous = 1,
++};
++
++
+ /*
+ * Initialize the TOD clock and the CPU timer of
+ * the boot cpu.
+@@ -351,10 +299,12 @@ void __init time_init(void)
+ int cc;
+
+ /* kick the TOD clock */
+- asm volatile ("STCK 0(%1)\n\t"
+- "IPM %0\n\t"
+- "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc)
+- : "memory", "cc");
++ asm volatile(
++ " stck 0(%2)\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (cc), "=m" (init_timer_cc)
++ : "a" (&init_timer_cc) : "cc");
+ switch (cc) {
+ case 0: /* clock in set state: all is fine */
+ break;
+@@ -383,6 +333,9 @@ void __init time_init(void)
+ &ext_int_info_cc) != 0)
+ panic("Couldn't request external interrupt 0x1004");
+
++ if (clocksource_register(&clocksource_tod) != 0)
++ panic("Could not register TOD clock source");
++
+ init_cpu_timer();
+
+ #ifdef CONFIG_NO_IDLE_HZ
+diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
+index bde1d1d..92ecffb 100644
+--- a/arch/s390/kernel/traps.c
++++ b/arch/s390/kernel/traps.c
+@@ -29,6 +29,7 @@
+ #include <linux/module.h>
+ #include <linux/kallsyms.h>
+ #include <linux/reboot.h>
++#include <linux/kprobes.h>
+
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -39,6 +40,7 @@
+ #include <asm/s390_ext.h>
+ #include <asm/lowcore.h>
+ #include <asm/debug.h>
++#include <asm/kdebug.h>
+
+ /* Called from entry.S only */
+ extern void handle_per_exception(struct pt_regs *regs);
+@@ -59,7 +61,7 @@ extern pgm_check_handler_t do_dat_except
+ #ifdef CONFIG_PFAULT
+ extern int pfault_init(void);
+ extern void pfault_fini(void);
+-extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
++extern void pfault_interrupt(__u16 error_code);
+ static ext_int_info_t ext_int_pfault;
+ #endif
+ extern pgm_check_handler_t do_monitor_call;
+@@ -74,6 +76,20 @@ static int kstack_depth_to_print = 12;
+ static int kstack_depth_to_print = 20;
+ #endif /* CONFIG_64BIT */
+
++ATOMIC_NOTIFIER_HEAD(s390die_chain);
++
++int register_die_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_register(&s390die_chain, nb);
++}
++EXPORT_SYMBOL(register_die_notifier);
++
++int unregister_die_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(&s390die_chain, nb);
++}
++EXPORT_SYMBOL(unregister_die_notifier);
++
+ /*
+ * For show_trace we have tree different stack to consider:
+ * - the panic stack which is used if the kernel stack has overflown
+@@ -305,8 +321,9 @@ report_user_fault(long interruption_code
+ #endif
+ }
+
+-static void inline do_trap(long interruption_code, int signr, char *str,
+- struct pt_regs *regs, siginfo_t *info)
++static void __kprobes inline do_trap(long interruption_code, int signr,
++ char *str, struct pt_regs *regs,
++ siginfo_t *info)
+ {
+ /*
+ * We got all needed information from the lowcore and can
+@@ -315,6 +332,10 @@ static void inline do_trap(long interrup
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ local_irq_enable();
+
++ if (notify_die(DIE_TRAP, str, regs, interruption_code,
++ interruption_code, signr) == NOTIFY_STOP)
++ return;
++
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ struct task_struct *tsk = current;
+
+@@ -336,8 +357,12 @@ static inline void __user *get_check_add
+ return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+ }
+
+-void do_single_step(struct pt_regs *regs)
++void __kprobes do_single_step(struct pt_regs *regs)
+ {
++ if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0,
++ SIGTRAP) == NOTIFY_STOP){
++ return;
++ }
+ if ((current->ptrace & PT_PTRACED) != 0)
+ force_sig(SIGTRAP, current);
+ }
+@@ -437,7 +462,8 @@ asmlinkage void illegal_op(struct pt_reg
+ local_irq_enable();
+
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+- get_user(*((__u16 *) opcode), (__u16 __user *) location);
++ if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
++ return;
+ if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
+ if (current->ptrace & PT_PTRACED)
+ force_sig(SIGTRAP, current);
+@@ -445,20 +471,25 @@ asmlinkage void illegal_op(struct pt_reg
+ signal = SIGILL;
+ #ifdef CONFIG_MATHEMU
+ } else if (opcode[0] == 0xb3) {
+- get_user(*((__u16 *) (opcode+2)), location+1);
++ if (get_user(*((__u16 *) (opcode+2)), location+1))
++ return;
+ signal = math_emu_b3(opcode, regs);
+ } else if (opcode[0] == 0xed) {
+- get_user(*((__u32 *) (opcode+2)),
+- (__u32 *)(location+1));
++ if (get_user(*((__u32 *) (opcode+2)),
++ (__u32 __user *)(location+1)))
++ return;
+ signal = math_emu_ed(opcode, regs);
+ } else if (*((__u16 *) opcode) == 0xb299) {
+- get_user(*((__u16 *) (opcode+2)), location+1);
++ if (get_user(*((__u16 *) (opcode+2)), location+1))
++ return;
+ signal = math_emu_srnm(opcode, regs);
+ } else if (*((__u16 *) opcode) == 0xb29c) {
+- get_user(*((__u16 *) (opcode+2)), location+1);
++ if (get_user(*((__u16 *) (opcode+2)), location+1))
++ return;
+ signal = math_emu_stfpc(opcode, regs);
+ } else if (*((__u16 *) opcode) == 0xb29d) {
+- get_user(*((__u16 *) (opcode+2)), location+1);
++ if (get_user(*((__u16 *) (opcode+2)), location+1))
++ return;
+ signal = math_emu_lfpc(opcode, regs);
+ #endif
+ } else
+@@ -474,7 +505,7 @@ asmlinkage void illegal_op(struct pt_reg
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = SEGV_MAPERR;
+- info.si_addr = (void *) location;
++ info.si_addr = (void __user *) location;
+ do_trap(interruption_code, signal,
+ "user address fault", regs, &info);
+ } else
+@@ -495,10 +526,10 @@ asmlinkage void
+ specification_exception(struct pt_regs * regs, long interruption_code)
+ {
+ __u8 opcode[6];
+- __u16 *location = NULL;
++ __u16 __user *location = NULL;
+ int signal = 0;
+
+- location = (__u16 *) get_check_address(regs);
++ location = (__u16 __user *) get_check_address(regs);
+
+ /*
+ * We got all needed information from the lowcore and can
+@@ -572,8 +603,7 @@ asmlinkage void data_exception(struct pt
+ local_irq_enable();
+
+ if (MACHINE_HAS_IEEE)
+- __asm__ volatile ("stfpc %0\n\t"
+- : "=m" (current->thread.fp_regs.fpc));
++ asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+
+ #ifdef CONFIG_MATHEMU
+ else if (regs->psw.mask & PSW_MASK_PSTATE) {
+@@ -608,7 +638,7 @@ asmlinkage void data_exception(struct pt
+ break;
+ case 0xed:
+ get_user(*((__u32 *) (opcode+2)),
+- (__u32 *)(location+1));
++ (__u32 __user *)(location+1));
+ signal = math_emu_ed(opcode, regs);
+ break;
+ case 0xb2:
+diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
+index ff5f7bb..fe0f2e9 100644
+--- a/arch/s390/kernel/vmlinux.lds.S
++++ b/arch/s390/kernel/vmlinux.lds.S
+@@ -24,6 +24,7 @@ SECTIONS
+ *(.text)
+ SCHED_TEXT
+ LOCK_TEXT
++ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+ } = 0x0700
+@@ -82,13 +83,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+@@ -117,7 +112,7 @@ SECTIONS
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+- *(.exitcall.exit)
++ *(.exit.text) *(.exit.data) *(.exitcall.exit)
+ }
+
+ /* Stabs debugging sections. */
+diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
+index 2306cd8..21baaf5 100644
+--- a/arch/s390/kernel/vtime.c
++++ b/arch/s390/kernel/vtime.c
+@@ -22,6 +22,7 @@
+
+ #include <asm/s390_ext.h>
+ #include <asm/timer.h>
++#include <asm/irq_regs.h>
+
+ static ext_int_info_t ext_int_info_timer;
+ DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+@@ -208,11 +209,11 @@ static void list_add_sorted(struct vtime
+ * Do the callback functions of expired vtimer events.
+ * Called from within the interrupt handler.
+ */
+-static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
++static void do_callbacks(struct list_head *cb_list)
+ {
+ struct vtimer_queue *vt_list;
+ struct vtimer_list *event, *tmp;
+- void (*fn)(unsigned long, struct pt_regs*);
++ void (*fn)(unsigned long);
+ unsigned long data;
+
+ if (list_empty(cb_list))
+@@ -223,7 +224,7 @@ static void do_callbacks(struct list_hea
+ list_for_each_entry_safe(event, tmp, cb_list, entry) {
+ fn = event->function;
+ data = event->data;
+- fn(data, regs);
++ fn(data);
+
+ if (!event->interval)
+ /* delete one shot timer */
+@@ -241,7 +242,7 @@ static void do_callbacks(struct list_hea
+ /*
+ * Handler for the virtual CPU timer.
+ */
+-static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code)
++static void do_cpu_timer_interrupt(__u16 error_code)
+ {
+ int cpu;
+ __u64 next, delta;
+@@ -274,7 +275,7 @@ static void do_cpu_timer_interrupt(struc
+ list_move_tail(&event->entry, &cb_list);
+ }
+ spin_unlock(&vt_list->lock);
+- do_callbacks(&cb_list, regs);
++ do_callbacks(&cb_list);
+
+ /* next event is first in list */
+ spin_lock(&vt_list->lock);
+diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
+index e05d087..b0cfa6c 100644
+--- a/arch/s390/lib/Makefile
++++ b/arch/s390/lib/Makefile
+@@ -4,6 +4,7 @@
+
+ EXTRA_AFLAGS := -traditional
+
+-lib-y += delay.o string.o
+-lib-y += $(if $(CONFIG_64BIT),uaccess64.o,uaccess.o)
++lib-y += delay.o string.o uaccess_std.o
++lib-$(CONFIG_32BIT) += div64.o
++lib-$(CONFIG_64BIT) += uaccess_mvcos.o
+ lib-$(CONFIG_SMP) += spinlock.o
+diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
+index 468f4ea..027c474 100644
+--- a/arch/s390/lib/delay.c
++++ b/arch/s390/lib/delay.c
+@@ -27,9 +27,7 @@ void __delay(unsigned long loops)
+ * yield the megahertz number of the cpu. The important function
+ * is udelay and that is done using the tod clock. -- martin.
+ */
+- __asm__ __volatile__(
+- "0: brct %0,0b"
+- : /* no outputs */ : "r" ((loops/2) + 1));
++ asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1));
+ }
+
+ /*
+@@ -38,13 +36,12 @@ void __delay(unsigned long loops)
+ */
+ void __udelay(unsigned long usecs)
+ {
+- uint64_t start_cc, end_cc;
++ uint64_t start_cc;
+
+ if (usecs == 0)
+ return;
+- asm volatile ("STCK %0" : "=m" (start_cc));
++ start_cc = get_clock();
+ do {
+ cpu_relax();
+- asm volatile ("STCK %0" : "=m" (end_cc));
+- } while (((end_cc - start_cc)/4096) < usecs);
++ } while (((get_clock() - start_cc)/4096) < usecs);
+ }
+diff --git a/arch/s390/lib/div64.c b/arch/s390/lib/div64.c
+new file mode 100644
+index 0000000..0481f34
+--- /dev/null
++++ b/arch/s390/lib/div64.c
+@@ -0,0 +1,151 @@
++/*
++ * arch/s390/lib/div64.c
++ *
++ * __div64_32 implementation for 31 bit.
++ *
++ * Copyright (C) IBM Corp. 2006
++ * Author(s): Martin Schwidefsky (schwidefsky at de.ibm.com),
++ */
++
++#include <linux/types.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_MARCH_G5
++
++/*
++ * Function to divide an unsigned 64 bit integer by an unsigned
++ * 31 bit integer using signed 64/32 bit division.
++ */
++static uint32_t __div64_31(uint64_t *n, uint32_t base)
++{
++ register uint32_t reg2 asm("2");
++ register uint32_t reg3 asm("3");
++ uint32_t *words = (uint32_t *) n;
++ uint32_t tmp;
++
++ /* Special case base==1, remainder = 0, quotient = n */
++ if (base == 1)
++ return 0;
++ /*
++ * Special case base==0 will cause a fixed point divide exception
++ * on the dr instruction and may not happen anyway. For the
++ * following calculation we can assume base > 1. The first
++ * signed 64 / 32 bit division with an upper half of 0 will
++ * give the correct upper half of the 64 bit quotient.
++ */
++ reg2 = 0UL;
++ reg3 = words[0];
++ asm volatile(
++ " dr %0,%2\n"
++ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
++ words[0] = reg3;
++ reg3 = words[1];
++ /*
++ * To get the lower half of the 64 bit quotient and the 32 bit
++ * remainder we have to use a little trick. Since we only have
++ * a signed division the quotient can get too big. To avoid this
++ * the 64 bit dividend is halved, then the signed division will
++ * work. Afterwards the quotient and the remainder are doubled.
++ * If the last bit of the dividend has been one the remainder
++ * is increased by one then checked against the base. If the
++ * remainder has overflown subtract base and increase the
++ * quotient. Simple, no ?
++ */
++ asm volatile(
++ " nr %2,%1\n"
++ " srdl %0,1\n"
++ " dr %0,%3\n"
++ " alr %0,%0\n"
++ " alr %1,%1\n"
++ " alr %0,%2\n"
++ " clr %0,%3\n"
++ " jl 0f\n"
++ " slr %0,%3\n"
++ " alr %1,%2\n"
++ "0:\n"
++ : "+d" (reg2), "+d" (reg3), "=d" (tmp)
++ : "d" (base), "2" (1UL) : "cc" );
++ words[1] = reg3;
++ return reg2;
++}
++
++/*
++ * Function to divide an unsigned 64 bit integer by an unsigned
++ * 32 bit integer using the unsigned 64/31 bit division.
++ */
++uint32_t __div64_32(uint64_t *n, uint32_t base)
++{
++ uint32_t r;
++
++ /*
++ * If the most significant bit of base is set, divide n by
++ * (base/2). That allows to use 64/31 bit division and gives a
++ * good approximation of the result: n = (base/2)*q + r. The
++ * result needs to be corrected with two simple transformations.
++ * If base is already < 2^31-1 __div64_31 can be used directly.
++ */
++ r = __div64_31(n, ((signed) base < 0) ? (base/2) : base);
++ if ((signed) base < 0) {
++ uint64_t q = *n;
++ /*
++ * First transformation:
++ * n = (base/2)*q + r
++ * = ((base/2)*2)*(q/2) + ((q&1) ? (base/2) : 0) + r
++ * Since r < (base/2), r + (base/2) < base.
++ * With q1 = (q/2) and r1 = r + ((q&1) ? (base/2) : 0)
++ * n = ((base/2)*2)*q1 + r1 with r1 < base.
++ */
++ if (q & 1)
++ r += base/2;
++ q >>= 1;
++ /*
++ * Second transformation. ((base/2)*2) could have lost the
++ * last bit.
++ * n = ((base/2)*2)*q1 + r1
++ * = base*q1 - ((base&1) ? q1 : 0) + r1
++ */
++ if (base & 1) {
++ int64_t rx = r - q;
++ /*
++ * base is >= 2^31. The worst case for the while
++ * loop is n=2^64-1 base=2^31+1. That gives a
++ * maximum for q=(2^64-1)/2^31 = 0x1ffffffff. Since
++ * base >= 2^31 the loop is finished after a maximum
++ * of three iterations.
++ */
++ while (rx < 0) {
++ rx += base;
++ q--;
++ }
++ r = rx;
++ }
++ *n = q;
++ }
++ return r;
++}
++
++#else /* MARCH_G5 */
++
++uint32_t __div64_32(uint64_t *n, uint32_t base)
++{
++ register uint32_t reg2 asm("2");
++ register uint32_t reg3 asm("3");
++ uint32_t *words = (uint32_t *) n;
++
++ reg2 = 0UL;
++ reg3 = words[0];
++ asm volatile(
++ " dlr %0,%2\n"
++ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
++ words[0] = reg3;
++ reg3 = words[1];
++ asm volatile(
++ " dlr %0,%2\n"
++ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
++ words[1] = reg3;
++ return reg2;
++}
++
++#endif /* MARCH_G5 */
++
++EXPORT_SYMBOL(__div64_32);
+diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
+index b9b7958..8d76403 100644
+--- a/arch/s390/lib/spinlock.c
++++ b/arch/s390/lib/spinlock.c
+@@ -24,57 +24,76 @@ static int __init spin_retry_setup(char
+ }
+ __setup("spin_retry=", spin_retry_setup);
+
+-static inline void
+-_diag44(void)
++static inline void _raw_yield(void)
+ {
+-#ifdef CONFIG_64BIT
+ if (MACHINE_HAS_DIAG44)
+-#endif
+ asm volatile("diag 0,0,0x44");
+ }
+
+-void
+-_raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
++static inline void _raw_yield_cpu(int cpu)
++{
++ if (MACHINE_HAS_DIAG9C)
++ asm volatile("diag %0,0,0x9c"
++ : : "d" (__cpu_logical_map[cpu]));
++ else
++ _raw_yield();
++}
++
++void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
+ {
+ int count = spin_retry;
++ unsigned int cpu = ~smp_processor_id();
+
+ while (1) {
+ if (count-- <= 0) {
+- _diag44();
++ unsigned int owner = lp->owner_cpu;
++ if (owner != 0)
++ _raw_yield_cpu(~owner);
+ count = spin_retry;
+ }
+ if (__raw_spin_is_locked(lp))
+ continue;
+- if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
++ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
++ lp->owner_pc = pc;
+ return;
++ }
+ }
+ }
+ EXPORT_SYMBOL(_raw_spin_lock_wait);
+
+-int
+-_raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
++int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
+ {
+- int count = spin_retry;
++ unsigned int cpu = ~smp_processor_id();
++ int count;
+
+- while (count-- > 0) {
++ for (count = spin_retry; count > 0; count--) {
+ if (__raw_spin_is_locked(lp))
+ continue;
+- if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
++ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
++ lp->owner_pc = pc;
+ return 1;
++ }
+ }
+ return 0;
+ }
+ EXPORT_SYMBOL(_raw_spin_trylock_retry);
+
+-void
+-_raw_read_lock_wait(raw_rwlock_t *rw)
++void _raw_spin_relax(raw_spinlock_t *lock)
++{
++ unsigned int cpu = lock->owner_cpu;
++ if (cpu != 0)
++ _raw_yield_cpu(~cpu);
++}
++EXPORT_SYMBOL(_raw_spin_relax);
++
++void _raw_read_lock_wait(raw_rwlock_t *rw)
+ {
+ unsigned int old;
+ int count = spin_retry;
+
+ while (1) {
+ if (count-- <= 0) {
+- _diag44();
++ _raw_yield();
+ count = spin_retry;
+ }
+ if (!__raw_read_can_lock(rw))
+@@ -86,8 +105,7 @@ _raw_read_lock_wait(raw_rwlock_t *rw)
+ }
+ EXPORT_SYMBOL(_raw_read_lock_wait);
+
+-int
+-_raw_read_trylock_retry(raw_rwlock_t *rw)
++int _raw_read_trylock_retry(raw_rwlock_t *rw)
+ {
+ unsigned int old;
+ int count = spin_retry;
+@@ -103,14 +121,13 @@ _raw_read_trylock_retry(raw_rwlock_t *rw
+ }
+ EXPORT_SYMBOL(_raw_read_trylock_retry);
+
+-void
+-_raw_write_lock_wait(raw_rwlock_t *rw)
++void _raw_write_lock_wait(raw_rwlock_t *rw)
+ {
+ int count = spin_retry;
+
+ while (1) {
+ if (count-- <= 0) {
+- _diag44();
++ _raw_yield();
+ count = spin_retry;
+ }
+ if (!__raw_write_can_lock(rw))
+@@ -121,8 +138,7 @@ _raw_write_lock_wait(raw_rwlock_t *rw)
+ }
+ EXPORT_SYMBOL(_raw_write_lock_wait);
+
+-int
+-_raw_write_trylock_retry(raw_rwlock_t *rw)
++int _raw_write_trylock_retry(raw_rwlock_t *rw)
+ {
+ int count = spin_retry;
+
+diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
+deleted file mode 100644
+index 8372752..0000000
+--- a/arch/s390/lib/uaccess.S
++++ /dev/null
+@@ -1,211 +0,0 @@
+-/*
+- * arch/s390/lib/uaccess.S
+- * __copy_{from|to}_user functions.
+- *
+- * s390
+- * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+- * Authors(s): Martin Schwidefsky (schwidefsky at de.ibm.com)
+- *
+- * These functions have standard call interface
+- */
+-
+-#include <linux/errno.h>
+-#include <asm/lowcore.h>
+-#include <asm/asm-offsets.h>
+-
+- .text
+- .align 4
+- .globl __copy_from_user_asm
+- # %r2 = to, %r3 = n, %r4 = from
+-__copy_from_user_asm:
+- slr %r0,%r0
+-0: mvcp 0(%r3,%r2),0(%r4),%r0
+- jnz 1f
+- slr %r2,%r2
+- br %r14
+-1: la %r2,256(%r2)
+- la %r4,256(%r4)
+- ahi %r3,-256
+-2: mvcp 0(%r3,%r2),0(%r4),%r0
+- jnz 1b
+-3: slr %r2,%r2
+- br %r14
+-4: lhi %r0,-4096
+- lr %r5,%r4
+- slr %r5,%r0
+- nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
+- slr %r5,%r4 # %r5 = #bytes to next user page boundary
+- clr %r3,%r5 # copy crosses next page boundary ?
+- jnh 6f # no, the current page faulted
+- # move with the reduced length which is < 256
+-5: mvcp 0(%r5,%r2),0(%r4),%r0
+- slr %r3,%r5
+-6: lr %r2,%r3
+- br %r14
+- .section __ex_table,"a"
+- .long 0b,4b
+- .long 2b,4b
+- .long 5b,6b
+- .previous
+-
+- .align 4
+- .text
+- .globl __copy_to_user_asm
+- # %r2 = from, %r3 = n, %r4 = to
+-__copy_to_user_asm:
+- slr %r0,%r0
+-0: mvcs 0(%r3,%r4),0(%r2),%r0
+- jnz 1f
+- slr %r2,%r2
+- br %r14
+-1: la %r2,256(%r2)
+- la %r4,256(%r4)
+- ahi %r3,-256
+-2: mvcs 0(%r3,%r4),0(%r2),%r0
+- jnz 1b
+-3: slr %r2,%r2
+- br %r14
+-4: lhi %r0,-4096
+- lr %r5,%r4
+- slr %r5,%r0
+- nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
+- slr %r5,%r4 # %r5 = #bytes to next user page boundary
+- clr %r3,%r5 # copy crosses next page boundary ?
+- jnh 6f # no, the current page faulted
+- # move with the reduced length which is < 256
+-5: mvcs 0(%r5,%r4),0(%r2),%r0
+- slr %r3,%r5
+-6: lr %r2,%r3
+- br %r14
+- .section __ex_table,"a"
+- .long 0b,4b
+- .long 2b,4b
+- .long 5b,6b
+- .previous
+-
+- .align 4
+- .text
+- .globl __copy_in_user_asm
+- # %r2 = from, %r3 = n, %r4 = to
+-__copy_in_user_asm:
+- ahi %r3,-1
+- jo 6f
+- sacf 256
+- bras %r1,4f
+-0: ahi %r3,257
+-1: mvc 0(1,%r4),0(%r2)
+- la %r2,1(%r2)
+- la %r4,1(%r4)
+- ahi %r3,-1
+- jnz 1b
+-2: lr %r2,%r3
+- br %r14
+-3: mvc 0(256,%r4),0(%r2)
+- la %r2,256(%r2)
+- la %r4,256(%r4)
+-4: ahi %r3,-256
+- jnm 3b
+-5: ex %r3,4(%r1)
+- sacf 0
+-6: slr %r2,%r2
+- br %r14
+- .section __ex_table,"a"
+- .long 1b,2b
+- .long 3b,0b
+- .long 5b,0b
+- .previous
+-
+- .align 4
+- .text
+- .globl __clear_user_asm
+- # %r2 = to, %r3 = n
+-__clear_user_asm:
+- bras %r5,0f
+- .long empty_zero_page
+-0: l %r5,0(%r5)
+- slr %r0,%r0
+-1: mvcs 0(%r3,%r2),0(%r5),%r0
+- jnz 2f
+- slr %r2,%r2
+- br %r14
+-2: la %r2,256(%r2)
+- ahi %r3,-256
+-3: mvcs 0(%r3,%r2),0(%r5),%r0
+- jnz 2b
+-4: slr %r2,%r2
+- br %r14
+-5: lhi %r0,-4096
+- lr %r4,%r2
+- slr %r4,%r0
+- nr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
+- slr %r4,%r2 # %r4 = #bytes to next user page boundary
+- clr %r3,%r4 # clear crosses next page boundary ?
+- jnh 7f # no, the current page faulted
+- # clear with the reduced length which is < 256
+-6: mvcs 0(%r4,%r2),0(%r5),%r0
+- slr %r3,%r4
+-7: lr %r2,%r3
+- br %r14
+- .section __ex_table,"a"
+- .long 1b,5b
+- .long 3b,5b
+- .long 6b,7b
+- .previous
+-
+- .align 4
+- .text
+- .globl __strncpy_from_user_asm
+- # %r2 = count, %r3 = dst, %r4 = src
+-__strncpy_from_user_asm:
+- lhi %r0,0
+- lr %r1,%r4
+- la %r4,0(%r4) # clear high order bit from %r4
+- la %r2,0(%r2,%r4) # %r2 points to first byte after string
+- sacf 256
+-0: srst %r2,%r1
+- jo 0b
+- sacf 0
+- lr %r1,%r2
+- jh 1f # \0 found in string ?
+- ahi %r1,1 # include \0 in copy
+-1: slr %r1,%r4 # %r1 = copy length (without \0)
+- slr %r2,%r4 # %r2 = return length (including \0)
+-2: mvcp 0(%r1,%r3),0(%r4),%r0
+- jnz 3f
+- br %r14
+-3: la %r3,256(%r3)
+- la %r4,256(%r4)
+- ahi %r1,-256
+- mvcp 0(%r1,%r3),0(%r4),%r0
+- jnz 3b
+- br %r14
+-4: sacf 0
+- lhi %r2,-EFAULT
+- br %r14
+- .section __ex_table,"a"
+- .long 0b,4b
+- .previous
+-
+- .align 4
+- .text
+- .globl __strnlen_user_asm
+- # %r2 = count, %r3 = src
+-__strnlen_user_asm:
+- lhi %r0,0
+- lr %r1,%r3
+- la %r3,0(%r3) # clear high order bit from %r4
+- la %r2,0(%r2,%r3) # %r2 points to first byte after string
+- sacf 256
+-0: srst %r2,%r1
+- jo 0b
+- sacf 0
+- ahi %r2,1 # strnlen_user result includes the \0
+- # or return count+1 if \0 not found
+- slr %r2,%r3
+- br %r14
+-2: sacf 0
+- slr %r2,%r2 # return 0 on exception
+- br %r14
+- .section __ex_table,"a"
+- .long 0b,2b
+- .previous
+diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S
+deleted file mode 100644
+index 1f755be..0000000
+--- a/arch/s390/lib/uaccess64.S
++++ /dev/null
+@@ -1,207 +0,0 @@
+-/*
+- * arch/s390x/lib/uaccess.S
+- * __copy_{from|to}_user functions.
+- *
+- * s390
+- * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+- * Authors(s): Martin Schwidefsky (schwidefsky at de.ibm.com)
+- *
+- * These functions have standard call interface
+- */
+-
+-#include <linux/errno.h>
+-#include <asm/lowcore.h>
+-#include <asm/asm-offsets.h>
+-
+- .text
+- .align 4
+- .globl __copy_from_user_asm
+- # %r2 = to, %r3 = n, %r4 = from
+-__copy_from_user_asm:
+- slgr %r0,%r0
+-0: mvcp 0(%r3,%r2),0(%r4),%r0
+- jnz 1f
+- slgr %r2,%r2
+- br %r14
+-1: la %r2,256(%r2)
+- la %r4,256(%r4)
+- aghi %r3,-256
+-2: mvcp 0(%r3,%r2),0(%r4),%r0
+- jnz 1b
+-3: slgr %r2,%r2
+- br %r14
+-4: lghi %r0,-4096
+- lgr %r5,%r4
+- slgr %r5,%r0
+- ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
+- slgr %r5,%r4 # %r5 = #bytes to next user page boundary
+- clgr %r3,%r5 # copy crosses next page boundary ?
+- jnh 6f # no, the current page faulted
+- # move with the reduced length which is < 256
+-5: mvcp 0(%r5,%r2),0(%r4),%r0
+- slgr %r3,%r5
+-6: lgr %r2,%r3
+- br %r14
+- .section __ex_table,"a"
+- .quad 0b,4b
+- .quad 2b,4b
+- .quad 5b,6b
+- .previous
+-
+- .align 4
+- .text
+- .globl __copy_to_user_asm
+- # %r2 = from, %r3 = n, %r4 = to
+-__copy_to_user_asm:
+- slgr %r0,%r0
+-0: mvcs 0(%r3,%r4),0(%r2),%r0
+- jnz 1f
+- slgr %r2,%r2
+- br %r14
+-1: la %r2,256(%r2)
+- la %r4,256(%r4)
+- aghi %r3,-256
+-2: mvcs 0(%r3,%r4),0(%r2),%r0
+- jnz 1b
+-3: slgr %r2,%r2
+- br %r14
+-4: lghi %r0,-4096
+- lgr %r5,%r4
+- slgr %r5,%r0
+- ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
+- slgr %r5,%r4 # %r5 = #bytes to next user page boundary
+- clgr %r3,%r5 # copy crosses next page boundary ?
+- jnh 6f # no, the current page faulted
+- # move with the reduced length which is < 256
+-5: mvcs 0(%r5,%r4),0(%r2),%r0
+- slgr %r3,%r5
+-6: lgr %r2,%r3
+- br %r14
+- .section __ex_table,"a"
+- .quad 0b,4b
+- .quad 2b,4b
+- .quad 5b,6b
+- .previous
+-
+- .align 4
+- .text
+- .globl __copy_in_user_asm
+- # %r2 = from, %r3 = n, %r4 = to
+-__copy_in_user_asm:
+- aghi %r3,-1
+- jo 6f
+- sacf 256
+- bras %r1,4f
+-0: aghi %r3,257
+-1: mvc 0(1,%r4),0(%r2)
+- la %r2,1(%r2)
+- la %r4,1(%r4)
+- aghi %r3,-1
+- jnz 1b
+-2: lgr %r2,%r3
+- br %r14
+-3: mvc 0(256,%r4),0(%r2)
+- la %r2,256(%r2)
+- la %r4,256(%r4)
+-4: aghi %r3,-256
+- jnm 3b
+-5: ex %r3,4(%r1)
+- sacf 0
+-6: slgr %r2,%r2
+- br 14
+- .section __ex_table,"a"
+- .quad 1b,2b
+- .quad 3b,0b
+- .quad 5b,0b
+- .previous
+-
+- .align 4
+- .text
+- .globl __clear_user_asm
+- # %r2 = to, %r3 = n
+-__clear_user_asm:
+- slgr %r0,%r0
+- larl %r5,empty_zero_page
+-1: mvcs 0(%r3,%r2),0(%r5),%r0
+- jnz 2f
+- slgr %r2,%r2
+- br %r14
+-2: la %r2,256(%r2)
+- aghi %r3,-256
+-3: mvcs 0(%r3,%r2),0(%r5),%r0
+- jnz 2b
+-4: slgr %r2,%r2
+- br %r14
+-5: lghi %r0,-4096
+- lgr %r4,%r2
+- slgr %r4,%r0
+- ngr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
+- slgr %r4,%r2 # %r4 = #bytes to next user page boundary
+- clgr %r3,%r4 # clear crosses next page boundary ?
+- jnh 7f # no, the current page faulted
+- # clear with the reduced length which is < 256
+-6: mvcs 0(%r4,%r2),0(%r5),%r0
+- slgr %r3,%r4
+-7: lgr %r2,%r3
+- br %r14
+- .section __ex_table,"a"
+- .quad 1b,5b
+- .quad 3b,5b
+- .quad 6b,7b
+- .previous
+-
+- .align 4
+- .text
+- .globl __strncpy_from_user_asm
+- # %r2 = count, %r3 = dst, %r4 = src
+-__strncpy_from_user_asm:
+- lghi %r0,0
+- lgr %r1,%r4
+- la %r2,0(%r2,%r4) # %r2 points to first byte after string
+- sacf 256
+-0: srst %r2,%r1
+- jo 0b
+- sacf 0
+- lgr %r1,%r2
+- jh 1f # \0 found in string ?
+- aghi %r1,1 # include \0 in copy
+-1: slgr %r1,%r4 # %r1 = copy length (without \0)
+- slgr %r2,%r4 # %r2 = return length (including \0)
+-2: mvcp 0(%r1,%r3),0(%r4),%r0
+- jnz 3f
+- br %r14
+-3: la %r3,256(%r3)
+- la %r4,256(%r4)
+- aghi %r1,-256
+- mvcp 0(%r1,%r3),0(%r4),%r0
+- jnz 3b
+- br %r14
+-4: sacf 0
+- lghi %r2,-EFAULT
+- br %r14
+- .section __ex_table,"a"
+- .quad 0b,4b
+- .previous
+-
+- .align 4
+- .text
+- .globl __strnlen_user_asm
+- # %r2 = count, %r3 = src
+-__strnlen_user_asm:
+- lghi %r0,0
+- lgr %r1,%r3
+- la %r2,0(%r2,%r3) # %r2 points to first byte after string
+- sacf 256
+-0: srst %r2,%r1
+- jo 0b
+- sacf 0
+- aghi %r2,1 # strnlen_user result includes the \0
+- # or return count+1 if \0 not found
+- slgr %r2,%r3
+- br %r14
+-2: sacf 0
+- slgr %r2,%r2 # return 0 on exception
+- br %r14
+- .section __ex_table,"a"
+- .quad 0b,2b
+- .previous
+diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
+new file mode 100644
+index 0000000..121b293
+--- /dev/null
++++ b/arch/s390/lib/uaccess_mvcos.c
+@@ -0,0 +1,166 @@
++/*
++ * arch/s390/lib/uaccess_mvcos.c
++ *
++ * Optimized user space space access functions based on mvcos.
++ *
++ * Copyright (C) IBM Corp. 2006
++ * Author(s): Martin Schwidefsky (schwidefsky at de.ibm.com),
++ * Gerald Schaefer (gerald.schaefer at de.ibm.com)
++ */
++
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <asm/uaccess.h>
++#include <asm/futex.h>
++
++#ifndef __s390x__
++#define AHI "ahi"
++#define ALR "alr"
++#define CLR "clr"
++#define LHI "lhi"
++#define SLR "slr"
++#else
++#define AHI "aghi"
++#define ALR "algr"
++#define CLR "clgr"
++#define LHI "lghi"
++#define SLR "slgr"
++#endif
++
++size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
++{
++ register unsigned long reg0 asm("0") = 0x81UL;
++ unsigned long tmp1, tmp2;
++
++ tmp1 = -4096UL;
++ asm volatile(
++ "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
++ " jz 7f\n"
++ "1:"ALR" %0,%3\n"
++ " "SLR" %1,%3\n"
++ " "SLR" %2,%3\n"
++ " j 0b\n"
++ "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
++ " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
++ " "SLR" %4,%1\n"
++ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
++ " jnh 4f\n"
++ "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
++ " "SLR" %0,%4\n"
++ " "ALR" %2,%4\n"
++ "4:"LHI" %4,-1\n"
++ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
++ " bras %3,6f\n" /* memset loop */
++ " xc 0(1,%2),0(%2)\n"
++ "5: xc 0(256,%2),0(%2)\n"
++ " la %2,256(%2)\n"
++ "6:"AHI" %4,-256\n"
++ " jnm 5b\n"
++ " ex %4,0(%3)\n"
++ " j 8f\n"
++ "7:"SLR" %0,%0\n"
++ "8: \n"
++ EX_TABLE(0b,2b) EX_TABLE(3b,4b)
++ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
++ : "d" (reg0) : "cc", "memory");
++ return size;
++}
++
++size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
++{
++ register unsigned long reg0 asm("0") = 0x810000UL;
++ unsigned long tmp1, tmp2;
++
++ tmp1 = -4096UL;
++ asm volatile(
++ "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
++ " jz 4f\n"
++ "1:"ALR" %0,%3\n"
++ " "SLR" %1,%3\n"
++ " "SLR" %2,%3\n"
++ " j 0b\n"
++ "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
++ " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
++ " "SLR" %4,%1\n"
++ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
++ " jnh 5f\n"
++ "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
++ " "SLR" %0,%4\n"
++ " j 5f\n"
++ "4:"SLR" %0,%0\n"
++ "5: \n"
++ EX_TABLE(0b,2b) EX_TABLE(3b,5b)
++ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
++ : "d" (reg0) : "cc", "memory");
++ return size;
++}
++
++size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
++{
++ register unsigned long reg0 asm("0") = 0x810081UL;
++ unsigned long tmp1, tmp2;
++
++ tmp1 = -4096UL;
++ /* FIXME: copy with reduced length. */
++ asm volatile(
++ "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
++ " jz 2f\n"
++ "1:"ALR" %0,%3\n"
++ " "SLR" %1,%3\n"
++ " "SLR" %2,%3\n"
++ " j 0b\n"
++ "2:"SLR" %0,%0\n"
++ "3: \n"
++ EX_TABLE(0b,3b)
++ : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
++ : "d" (reg0) : "cc", "memory");
++ return size;
++}
++
++size_t clear_user_mvcos(size_t size, void __user *to)
++{
++ register unsigned long reg0 asm("0") = 0x810000UL;
++ unsigned long tmp1, tmp2;
++
++ tmp1 = -4096UL;
++ asm volatile(
++ "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
++ " jz 4f\n"
++ "1:"ALR" %0,%2\n"
++ " "SLR" %1,%2\n"
++ " j 0b\n"
++ "2: la %3,4095(%1)\n"/* %4 = to + 4095 */
++ " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */
++ " "SLR" %3,%1\n"
++ " "CLR" %0,%3\n" /* copy crosses next page boundary? */
++ " jnh 5f\n"
++ "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
++ " "SLR" %0,%3\n"
++ " j 5f\n"
++ "4:"SLR" %0,%0\n"
++ "5: \n"
++ EX_TABLE(0b,2b) EX_TABLE(3b,5b)
++ : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
++ : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
++ return size;
++}
++
++extern size_t copy_from_user_std_small(size_t, const void __user *, void *);
++extern size_t copy_to_user_std_small(size_t, void __user *, const void *);
++extern size_t strnlen_user_std(size_t, const char __user *);
++extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
++extern int futex_atomic_op(int, int __user *, int, int *);
++extern int futex_atomic_cmpxchg(int __user *, int, int);
++
++struct uaccess_ops uaccess_mvcos = {
++ .copy_from_user = copy_from_user_mvcos,
++ .copy_from_user_small = copy_from_user_std_small,
++ .copy_to_user = copy_to_user_mvcos,
++ .copy_to_user_small = copy_to_user_std_small,
++ .copy_in_user = copy_in_user_mvcos,
++ .clear_user = clear_user_mvcos,
++ .strnlen_user = strnlen_user_std,
++ .strncpy_from_user = strncpy_from_user_std,
++ .futex_atomic_op = futex_atomic_op,
++ .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
++};
+diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
+new file mode 100644
+index 0000000..f44f007
+--- /dev/null
++++ b/arch/s390/lib/uaccess_std.c
+@@ -0,0 +1,356 @@
++/*
++ * arch/s390/lib/uaccess_std.c
++ *
++ * Standard user space access functions based on mvcp/mvcs and doing
++ * interesting things in the secondary space mode.
++ *
++ * Copyright (C) IBM Corp. 2006
++ * Author(s): Martin Schwidefsky (schwidefsky at de.ibm.com),
++ * Gerald Schaefer (gerald.schaefer at de.ibm.com)
++ */
++
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <asm/uaccess.h>
++#include <asm/futex.h>
++
++#ifndef __s390x__
++#define AHI "ahi"
++#define ALR "alr"
++#define CLR "clr"
++#define LHI "lhi"
++#define SLR "slr"
++#else
++#define AHI "aghi"
++#define ALR "algr"
++#define CLR "clgr"
++#define LHI "lghi"
++#define SLR "slgr"
++#endif
++
++size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
++{
++ unsigned long tmp1, tmp2;
++
++ tmp1 = -256UL;
++ asm volatile(
++ "0: mvcp 0(%0,%2),0(%1),%3\n"
++ " jz 8f\n"
++ "1:"ALR" %0,%3\n"
++ " la %1,256(%1)\n"
++ " la %2,256(%2)\n"
++ "2: mvcp 0(%0,%2),0(%1),%3\n"
++ " jnz 1b\n"
++ " j 8f\n"
++ "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
++ " "LHI" %3,-4096\n"
++ " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
++ " "SLR" %4,%1\n"
++ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
++ " jnh 5f\n"
++ "4: mvcp 0(%4,%2),0(%1),%3\n"
++ " "SLR" %0,%4\n"
++ " "ALR" %2,%4\n"
++ "5:"LHI" %4,-1\n"
++ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
++ " bras %3,7f\n" /* memset loop */
++ " xc 0(1,%2),0(%2)\n"
++ "6: xc 0(256,%2),0(%2)\n"
++ " la %2,256(%2)\n"
++ "7:"AHI" %4,-256\n"
++ " jnm 6b\n"
++ " ex %4,0(%3)\n"
++ " j 9f\n"
++ "8:"SLR" %0,%0\n"
++ "9: \n"
++ EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,5b)
++ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
++ : : "cc", "memory");
++ return size;
++}
++
++size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x)
++{
++ unsigned long tmp1, tmp2;
++
++ tmp1 = 0UL;
++ asm volatile(
++ "0: mvcp 0(%0,%2),0(%1),%3\n"
++ " "SLR" %0,%0\n"
++ " j 5f\n"
++ "1: la %4,255(%1)\n" /* %4 = ptr + 255 */
++ " "LHI" %3,-4096\n"
++ " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
++ " "SLR" %4,%1\n"
++ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
++ " jnh 5f\n"
++ "2: mvcp 0(%4,%2),0(%1),%3\n"
++ " "SLR" %0,%4\n"
++ " "ALR" %2,%4\n"
++ "3:"LHI" %4,-1\n"
++ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
++ " bras %3,4f\n"
++ " xc 0(1,%2),0(%2)\n"
++ "4: ex %4,0(%3)\n"
++ "5:\n"
++ EX_TABLE(0b,1b) EX_TABLE(2b,3b)
++ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
++ : : "cc", "memory");
++ return size;
++}
++
++size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
++{
++ unsigned long tmp1, tmp2;
++
++ tmp1 = -256UL;
++ asm volatile(
++ "0: mvcs 0(%0,%1),0(%2),%3\n"
++ " jz 5f\n"
++ "1:"ALR" %0,%3\n"
++ " la %1,256(%1)\n"
++ " la %2,256(%2)\n"
++ "2: mvcs 0(%0,%1),0(%2),%3\n"
++ " jnz 1b\n"
++ " j 5f\n"
++ "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
++ " "LHI" %3,-4096\n"
++ " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
++ " "SLR" %4,%1\n"
++ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
++ " jnh 6f\n"
++ "4: mvcs 0(%4,%1),0(%2),%3\n"
++ " "SLR" %0,%4\n"
++ " j 6f\n"
++ "5:"SLR" %0,%0\n"
++ "6: \n"
++ EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
++ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
++ : : "cc", "memory");
++ return size;
++}
++
++size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x)
++{
++ unsigned long tmp1, tmp2;
++
++ tmp1 = 0UL;
++ asm volatile(
++ "0: mvcs 0(%0,%1),0(%2),%3\n"
++ " "SLR" %0,%0\n"
++ " j 3f\n"
++ "1: la %4,255(%1)\n" /* ptr + 255 */
++ " "LHI" %3,-4096\n"
++ " nr %4,%3\n" /* (ptr + 255) & -4096UL */
++ " "SLR" %4,%1\n"
++ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
++ " jnh 3f\n"
++ "2: mvcs 0(%4,%1),0(%2),%3\n"
++ " "SLR" %0,%4\n"
++ "3:\n"
++ EX_TABLE(0b,1b) EX_TABLE(2b,3b)
++ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
++ : : "cc", "memory");
++ return size;
++}
++
++size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
++{
++ unsigned long tmp1;
++
++ asm volatile(
++ " "AHI" %0,-1\n"
++ " jo 5f\n"
++ " sacf 256\n"
++ " bras %3,3f\n"
++ "0:"AHI" %0,257\n"
++ "1: mvc 0(1,%1),0(%2)\n"
++ " la %1,1(%1)\n"
++ " la %2,1(%2)\n"
++ " "AHI" %0,-1\n"
++ " jnz 1b\n"
++ " j 5f\n"
++ "2: mvc 0(256,%1),0(%2)\n"
++ " la %1,256(%1)\n"
++ " la %2,256(%2)\n"
++ "3:"AHI" %0,-256\n"
++ " jnm 2b\n"
++ "4: ex %0,1b-0b(%3)\n"
++ " sacf 0\n"
++ "5: "SLR" %0,%0\n"
++ "6:\n"
++ EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
++ : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
++ : : "cc", "memory");
++ return size;
++}
++
++size_t clear_user_std(size_t size, void __user *to)
++{
++ unsigned long tmp1, tmp2;
++
++ asm volatile(
++ " "AHI" %0,-1\n"
++ " jo 5f\n"
++ " sacf 256\n"
++ " bras %3,3f\n"
++ " xc 0(1,%1),0(%1)\n"
++ "0:"AHI" %0,257\n"
++ " la %2,255(%1)\n" /* %2 = ptr + 255 */
++ " srl %2,12\n"
++ " sll %2,12\n" /* %2 = (ptr + 255) & -4096 */
++ " "SLR" %2,%1\n"
++ " "CLR" %0,%2\n" /* clear crosses next page boundary? */
++ " jnh 5f\n"
++ " "AHI" %2,-1\n"
++ "1: ex %2,0(%3)\n"
++ " "AHI" %2,1\n"
++ " "SLR" %0,%2\n"
++ " j 5f\n"
++ "2: xc 0(256,%1),0(%1)\n"
++ " la %1,256(%1)\n"
++ "3:"AHI" %0,-256\n"
++ " jnm 2b\n"
++ "4: ex %0,0(%3)\n"
++ " sacf 0\n"
++ "5: "SLR" %0,%0\n"
++ "6:\n"
++ EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
++ : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
++ : : "cc", "memory");
++ return size;
++}
++
++size_t strnlen_user_std(size_t size, const char __user *src)
++{
++ register unsigned long reg0 asm("0") = 0UL;
++ unsigned long tmp1, tmp2;
++
++ asm volatile(
++ " la %2,0(%1)\n"
++ " la %3,0(%0,%1)\n"
++ " "SLR" %0,%0\n"
++ " sacf 256\n"
++ "0: srst %3,%2\n"
++ " jo 0b\n"
++ " la %0,1(%3)\n" /* strnlen_user results includes \0 */
++ " "SLR" %0,%1\n"
++ "1: sacf 0\n"
++ EX_TABLE(0b,1b)
++ : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2)
++ : "d" (reg0) : "cc", "memory");
++ return size;
++}
++
++size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
++{
++ register unsigned long reg0 asm("0") = 0UL;
++ unsigned long tmp1, tmp2;
++
++ asm volatile(
++ " la %3,0(%1)\n"
++ " la %4,0(%0,%1)\n"
++ " sacf 256\n"
++ "0: srst %4,%3\n"
++ " jo 0b\n"
++ " sacf 0\n"
++ " la %0,0(%4)\n"
++ " jh 1f\n" /* found \0 in string ? */
++ " "AHI" %4,1\n" /* include \0 in copy */
++ "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */
++ " "SLR" %4,%1\n" /* %4 = copy length (including \0) */
++ "2: mvcp 0(%4,%2),0(%1),%5\n"
++ " jz 9f\n"
++ "3:"AHI" %4,-256\n"
++ " la %1,256(%1)\n"
++ " la %2,256(%2)\n"
++ "4: mvcp 0(%4,%2),0(%1),%5\n"
++ " jnz 3b\n"
++ " j 9f\n"
++ "7: sacf 0\n"
++ "8:"LHI" %0,%6\n"
++ "9:\n"
++ EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b)
++ : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2)
++ : "d" (reg0), "K" (-EFAULT) : "cc", "memory");
++ return size;
++}
++
++#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
++ asm volatile( \
++ " sacf 256\n" \
++ "0: l %1,0(%6)\n" \
++ "1:"insn \
++ "2: cs %1,%2,0(%6)\n" \
++ "3: jl 1b\n" \
++ " lhi %0,0\n" \
++ "4: sacf 0\n" \
++ EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
++ : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
++ "=m" (*uaddr) \
++ : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
++ "m" (*uaddr) : "cc");
++
++int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
++{
++ int oldval = 0, newval, ret;
++
++ inc_preempt_count();
++
++ switch (op) {
++ case FUTEX_OP_SET:
++ __futex_atomic_op("lr %2,%5\n",
++ ret, oldval, newval, uaddr, oparg);
++ break;
++ case FUTEX_OP_ADD:
++ __futex_atomic_op("lr %2,%1\nar %2,%5\n",
++ ret, oldval, newval, uaddr, oparg);
++ break;
++ case FUTEX_OP_OR:
++ __futex_atomic_op("lr %2,%1\nor %2,%5\n",
++ ret, oldval, newval, uaddr, oparg);
++ break;
++ case FUTEX_OP_ANDN:
++ __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
++ ret, oldval, newval, uaddr, oparg);
++ break;
++ case FUTEX_OP_XOR:
++ __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
++ ret, oldval, newval, uaddr, oparg);
++ break;
++ default:
++ ret = -ENOSYS;
++ }
++ dec_preempt_count();
++ *old = oldval;
++ return ret;
++}
++
++int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
++{
++ int ret;
++
++ asm volatile(
++ " sacf 256\n"
++ " cs %1,%4,0(%5)\n"
++ "0: lr %0,%1\n"
++ "1: sacf 0\n"
++ EX_TABLE(0b,1b)
++ : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
++ : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
++ : "cc", "memory" );
++ return ret;
++}
++
++struct uaccess_ops uaccess_std = {
++ .copy_from_user = copy_from_user_std,
++ .copy_from_user_small = copy_from_user_std_small,
++ .copy_to_user = copy_to_user_std,
++ .copy_to_user_small = copy_to_user_std_small,
++ .copy_in_user = copy_in_user_std,
++ .clear_user = clear_user_std,
++ .strnlen_user = strnlen_user_std,
++ .strncpy_from_user = strncpy_from_user_std,
++ .futex_atomic_op = futex_atomic_op,
++ .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
++};
+diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
+index b4957c8..6b9aec5 100644
+--- a/arch/s390/math-emu/math.c
++++ b/arch/s390/math-emu/math.c
+@@ -1564,52 +1564,52 @@ static int emu_tceb (struct pt_regs *reg
+ }
+
+ static inline void emu_load_regd(int reg) {
+- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
++ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+- asm volatile ( /* load reg from fp_regs.fprs[reg] */
+- " bras 1,0f\n"
+- " ld 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" (reg<<4),"a" (¤t->thread.fp_regs.fprs[reg].d)
+- : "1" );
++ asm volatile( /* load reg from fp_regs.fprs[reg] */
++ " bras 1,0f\n"
++ " ld 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" (reg<<4),"a" (¤t->thread.fp_regs.fprs[reg].d)
++ : "1");
+ }
+
+ static inline void emu_load_rege(int reg) {
+- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
++ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+- asm volatile ( /* load reg from fp_regs.fprs[reg] */
+- " bras 1,0f\n"
+- " le 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f)
+- : "1" );
++ asm volatile( /* load reg from fp_regs.fprs[reg] */
++ " bras 1,0f\n"
++ " le 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f)
++ : "1");
+ }
+
+ static inline void emu_store_regd(int reg) {
+- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
++ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+- asm volatile ( /* store reg to fp_regs.fprs[reg] */
+- " bras 1,0f\n"
+- " std 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d)
+- : "1" );
++ asm volatile( /* store reg to fp_regs.fprs[reg] */
++ " bras 1,0f\n"
++ " std 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d)
++ : "1");
+ }
+
+
+ static inline void emu_store_rege(int reg) {
+- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
++ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+- asm volatile ( /* store reg to fp_regs.fprs[reg] */
+- " bras 1,0f\n"
+- " ste 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f)
+- : "1" );
++ asm volatile( /* store reg to fp_regs.fprs[reg] */
++ " bras 1,0f\n"
++ " ste 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f)
++ : "1");
+ }
+
+ int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+@@ -2089,23 +2089,22 @@ int math_emu_ldr(__u8 *opcode) {
+
+ if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
+ /* we got an exception therfore ry can't be in {0,2,4,6} */
+- __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
+- " bras 1,0f\n"
+- " ld 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" (opc & 0xf0),
+- "a" (&fp_regs->fprs[opc & 0xf].d)
+- : "1" );
++ asm volatile( /* load rx from fp_regs.fprs[ry] */
++ " bras 1,0f\n"
++ " ld 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].d)
++ : "1");
+ } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
+- __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
+- " bras 1,0f\n"
+- " std 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" ((opc & 0xf) << 4),
+- "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
+- : "1" );
++ asm volatile ( /* store ry to fp_regs.fprs[rx] */
++ " bras 1,0f\n"
++ " std 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" ((opc & 0xf) << 4),
++ "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
++ : "1");
+ } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+ fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
+ return 0;
+@@ -2120,23 +2119,22 @@ int math_emu_ler(__u8 *opcode) {
+
+ if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
+ /* we got an exception therfore ry can't be in {0,2,4,6} */
+- __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
+- " bras 1,0f\n"
+- " le 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" (opc & 0xf0),
+- "a" (&fp_regs->fprs[opc & 0xf].f)
+- : "1" );
++ asm volatile( /* load rx from fp_regs.fprs[ry] */
++ " bras 1,0f\n"
++ " le 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].f)
++ : "1");
+ } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
+- __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
+- " bras 1,0f\n"
+- " ste 0,0(%1)\n"
+- "0: ex %0,0(1)"
+- : /* no output */
+- : "a" ((opc & 0xf) << 4),
+- "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
+- : "1" );
++ asm volatile( /* store ry to fp_regs.fprs[rx] */
++ " bras 1,0f\n"
++ " ste 0,0(%1)\n"
++ "0: ex %0,0(1)"
++ : /* no output */
++ : "a" ((opc & 0xf) << 4),
++ "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
++ : "1");
+ } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+ fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
+ return 0;
+diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h
+index ab556b6..5b6ca45 100644
+--- a/arch/s390/math-emu/sfp-util.h
++++ b/arch/s390/math-emu/sfp-util.h
+@@ -4,48 +4,51 @@
+ #include <asm/byteorder.h>
+
+ #define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \
+- unsigned int __sh = (ah); \
+- unsigned int __sl = (al); \
+- __asm__ (" alr %1,%3\n" \
+- " brc 12,0f\n" \
+- " ahi %0,1\n" \
+- "0: alr %0,%2" \
+- : "+&d" (__sh), "+d" (__sl) \
+- : "d" (bh), "d" (bl) : "cc" ); \
+- (sh) = __sh; \
+- (sl) = __sl; \
++ unsigned int __sh = (ah); \
++ unsigned int __sl = (al); \
++ asm volatile( \
++ " alr %1,%3\n" \
++ " brc 12,0f\n" \
++ " ahi %0,1\n" \
++ "0: alr %0,%2" \
++ : "+&d" (__sh), "+d" (__sl) \
++ : "d" (bh), "d" (bl) : "cc"); \
++ (sh) = __sh; \
++ (sl) = __sl; \
+ })
+
+ #define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \
+- unsigned int __sh = (ah); \
+- unsigned int __sl = (al); \
+- __asm__ (" slr %1,%3\n" \
+- " brc 3,0f\n" \
+- " ahi %0,-1\n" \
+- "0: slr %0,%2" \
+- : "+&d" (__sh), "+d" (__sl) \
+- : "d" (bh), "d" (bl) : "cc" ); \
+- (sh) = __sh; \
+- (sl) = __sl; \
++ unsigned int __sh = (ah); \
++ unsigned int __sl = (al); \
++ asm volatile( \
++ " slr %1,%3\n" \
++ " brc 3,0f\n" \
++ " ahi %0,-1\n" \
++ "0: slr %0,%2" \
++ : "+&d" (__sh), "+d" (__sl) \
++ : "d" (bh), "d" (bl) : "cc"); \
++ (sh) = __sh; \
++ (sl) = __sl; \
+ })
+
+ /* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
+ #define umul_ppmm(wh, wl, u, v) ({ \
+- unsigned int __wh = u; \
+- unsigned int __wl = v; \
+- __asm__ (" ltr 1,%0\n" \
+- " mr 0,%1\n" \
+- " jnm 0f\n" \
+- " alr 0,%1\n" \
+- "0: ltr %1,%1\n" \
+- " jnm 1f\n" \
+- " alr 0,%0\n" \
+- "1: lr %0,0\n" \
+- " lr %1,1\n" \
+- : "+d" (__wh), "+d" (__wl) \
+- : : "0", "1", "cc" ); \
+- wh = __wh; \
+- wl = __wl; \
++ unsigned int __wh = u; \
++ unsigned int __wl = v; \
++ asm volatile( \
++ " ltr 1,%0\n" \
++ " mr 0,%1\n" \
++ " jnm 0f\n" \
++ " alr 0,%1\n" \
++ "0: ltr %1,%1\n" \
++ " jnm 1f\n" \
++ " alr 0,%0\n" \
++ "1: lr %0,0\n" \
++ " lr %1,1\n" \
++ : "+d" (__wh), "+d" (__wl) \
++ : : "0", "1", "cc"); \
++ wh = __wh; \
++ wl = __wl; \
+ })
+
+ #define udiv_qrnnd(q, r, n1, n0, d) \
+diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
+index ceea51c..607f50e 100644
+--- a/arch/s390/mm/cmm.c
++++ b/arch/s390/mm/cmm.c
+@@ -15,6 +15,8 @@
+ #include <linux/sched.h>
+ #include <linux/sysctl.h>
+ #include <linux/ctype.h>
++#include <linux/swap.h>
++#include <linux/kthread.h>
+
+ #include <asm/pgalloc.h>
+ #include <asm/uaccess.h>
+@@ -34,18 +36,18 @@ struct cmm_page_array {
+ unsigned long pages[CMM_NR_PAGES];
+ };
+
+-static long cmm_pages = 0;
+-static long cmm_timed_pages = 0;
+-static volatile long cmm_pages_target = 0;
+-static volatile long cmm_timed_pages_target = 0;
+-static long cmm_timeout_pages = 0;
+-static long cmm_timeout_seconds = 0;
++static long cmm_pages;
++static long cmm_timed_pages;
++static volatile long cmm_pages_target;
++static volatile long cmm_timed_pages_target;
++static long cmm_timeout_pages;
++static long cmm_timeout_seconds;
+
+-static struct cmm_page_array *cmm_page_list = NULL;
+-static struct cmm_page_array *cmm_timed_page_list = NULL;
++static struct cmm_page_array *cmm_page_list;
++static struct cmm_page_array *cmm_timed_page_list;
++static DEFINE_SPINLOCK(cmm_lock);
+
+-static unsigned long cmm_thread_active = 0;
+-static struct work_struct cmm_thread_starter;
++static struct task_struct *cmm_thread_ptr;
+ static wait_queue_head_t cmm_thread_wait;
+ static struct timer_list cmm_timer;
+
+@@ -53,87 +55,100 @@ static void cmm_timer_fn(unsigned long);
+ static void cmm_set_timer(void);
+
+ static long
+-cmm_strtoul(const char *cp, char **endp)
++cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
+ {
+- unsigned int base = 10;
+-
+- if (*cp == '0') {
+- base = 8;
+- cp++;
+- if ((*cp == 'x' || *cp == 'X') && isxdigit(cp[1])) {
+- base = 16;
+- cp++;
+- }
+- }
+- return simple_strtoul(cp, endp, base);
+-}
+-
+-static long
+-cmm_alloc_pages(long pages, long *counter, struct cmm_page_array **list)
+-{
+- struct cmm_page_array *pa;
+- unsigned long page;
++ struct cmm_page_array *pa, *npa;
++ unsigned long addr;
+
+- pa = *list;
+- while (pages) {
+- page = __get_free_page(GFP_NOIO);
+- if (!page)
++ while (nr) {
++ addr = __get_free_page(GFP_NOIO);
++ if (!addr)
+ break;
++ spin_lock(&cmm_lock);
++ pa = *list;
+ if (!pa || pa->index >= CMM_NR_PAGES) {
+ /* Need a new page for the page list. */
+- pa = (struct cmm_page_array *)
++ spin_unlock(&cmm_lock);
++ npa = (struct cmm_page_array *)
+ __get_free_page(GFP_NOIO);
+- if (!pa) {
+- free_page(page);
++ if (!npa) {
++ free_page(addr);
+ break;
+ }
+- pa->next = *list;
+- pa->index = 0;
+- *list = pa;
++ spin_lock(&cmm_lock);
++ pa = *list;
++ if (!pa || pa->index >= CMM_NR_PAGES) {
++ npa->next = pa;
++ npa->index = 0;
++ pa = npa;
++ *list = pa;
++ } else
++ free_page((unsigned long) npa);
+ }
+- diag10(page);
+- pa->pages[pa->index++] = page;
++ diag10(addr);
++ pa->pages[pa->index++] = addr;
+ (*counter)++;
+- pages--;
++ spin_unlock(&cmm_lock);
++ nr--;
+ }
+- return pages;
++ return nr;
+ }
+
+-static void
+-cmm_free_pages(long pages, long *counter, struct cmm_page_array **list)
++static long
++cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
+ {
+ struct cmm_page_array *pa;
+- unsigned long page;
++ unsigned long addr;
+
++ spin_lock(&cmm_lock);
+ pa = *list;
+- while (pages) {
++ while (nr) {
+ if (!pa || pa->index <= 0)
+ break;
+- page = pa->pages[--pa->index];
++ addr = pa->pages[--pa->index];
+ if (pa->index == 0) {
+ pa = pa->next;
+ free_page((unsigned long) *list);
+ *list = pa;
+ }
+- free_page(page);
++ free_page(addr);
+ (*counter)--;
+- pages--;
++ nr--;
+ }
++ spin_unlock(&cmm_lock);
++ return nr;
++}
++
++static int cmm_oom_notify(struct notifier_block *self,
++ unsigned long dummy, void *parm)
++{
++ unsigned long *freed = parm;
++ long nr = 256;
++
++ nr = cmm_free_pages(nr, &cmm_timed_pages, &cmm_timed_page_list);
++ if (nr > 0)
++ nr = cmm_free_pages(nr, &cmm_pages, &cmm_page_list);
++ cmm_pages_target = cmm_pages;
++ cmm_timed_pages_target = cmm_timed_pages;
++ *freed += 256 - nr;
++ return NOTIFY_OK;
+ }
+
++static struct notifier_block cmm_oom_nb = {
++ .notifier_call = cmm_oom_notify
++};
++
+ static int
+ cmm_thread(void *dummy)
+ {
+ int rc;
+
+- daemonize("cmmthread");
+ while (1) {
+ rc = wait_event_interruptible(cmm_thread_wait,
+ (cmm_pages != cmm_pages_target ||
+- cmm_timed_pages != cmm_timed_pages_target));
+- if (rc == -ERESTARTSYS) {
+- /* Got kill signal. End thread. */
+- clear_bit(0, &cmm_thread_active);
++ cmm_timed_pages != cmm_timed_pages_target ||
++ kthread_should_stop()));
++ if (kthread_should_stop() || rc == -ERESTARTSYS) {
+ cmm_pages_target = cmm_pages;
+ cmm_timed_pages_target = cmm_timed_pages;
+ break;
+@@ -159,16 +174,8 @@ cmm_thread(void *dummy)
+ }
+
+ static void
+-cmm_start_thread(void)
+-{
+- kernel_thread(cmm_thread, NULL, 0);
+-}
+-
+-static void
+ cmm_kick_thread(void)
+ {
+- if (!test_and_set_bit(0, &cmm_thread_active))
+- schedule_work(&cmm_thread_starter);
+ wake_up(&cmm_thread_wait);
+ }
+
+@@ -193,21 +200,21 @@ cmm_set_timer(void)
+ static void
+ cmm_timer_fn(unsigned long ignored)
+ {
+- long pages;
++ long nr;
+
+- pages = cmm_timed_pages_target - cmm_timeout_pages;
+- if (pages < 0)
++ nr = cmm_timed_pages_target - cmm_timeout_pages;
++ if (nr < 0)
+ cmm_timed_pages_target = 0;
+ else
+- cmm_timed_pages_target = pages;
++ cmm_timed_pages_target = nr;
+ cmm_kick_thread();
+ cmm_set_timer();
+ }
+
+ void
+-cmm_set_pages(long pages)
++cmm_set_pages(long nr)
+ {
+- cmm_pages_target = pages;
++ cmm_pages_target = nr;
+ cmm_kick_thread();
+ }
+
+@@ -218,9 +225,9 @@ cmm_get_pages(void)
+ }
+
+ void
+-cmm_add_timed_pages(long pages)
++cmm_add_timed_pages(long nr)
+ {
+- cmm_timed_pages_target += pages;
++ cmm_timed_pages_target += nr;
+ cmm_kick_thread();
+ }
+
+@@ -231,9 +238,9 @@ cmm_get_timed_pages(void)
+ }
+
+ void
+-cmm_set_timeout(long pages, long seconds)
++cmm_set_timeout(long nr, long seconds)
+ {
+- cmm_timeout_pages = pages;
++ cmm_timeout_pages = nr;
+ cmm_timeout_seconds = seconds;
+ cmm_set_timer();
+ }
+@@ -261,7 +268,7 @@ cmm_pages_handler(ctl_table *ctl, int wr
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+ char buf[16], *p;
+- long pages;
++ long nr;
+ int len;
+
+ if (!*lenp || (*ppos && !write)) {
+@@ -276,17 +283,17 @@ cmm_pages_handler(ctl_table *ctl, int wr
+ return -EFAULT;
+ buf[sizeof(buf) - 1] = '\0';
+ cmm_skip_blanks(buf, &p);
+- pages = cmm_strtoul(p, &p);
++ nr = simple_strtoul(p, &p, 0);
+ if (ctl == &cmm_table[0])
+- cmm_set_pages(pages);
++ cmm_set_pages(nr);
+ else
+- cmm_add_timed_pages(pages);
++ cmm_add_timed_pages(nr);
+ } else {
+ if (ctl == &cmm_table[0])
+- pages = cmm_get_pages();
++ nr = cmm_get_pages();
+ else
+- pages = cmm_get_timed_pages();
+- len = sprintf(buf, "%ld\n", pages);
++ nr = cmm_get_timed_pages();
++ len = sprintf(buf, "%ld\n", nr);
+ if (len > *lenp)
+ len = *lenp;
+ if (copy_to_user(buffer, buf, len))
+@@ -302,7 +309,7 @@ cmm_timeout_handler(ctl_table *ctl, int
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+ char buf[64], *p;
+- long pages, seconds;
++ long nr, seconds;
+ int len;
+
+ if (!*lenp || (*ppos && !write)) {
+@@ -317,10 +324,10 @@ cmm_timeout_handler(ctl_table *ctl, int
+ return -EFAULT;
+ buf[sizeof(buf) - 1] = '\0';
+ cmm_skip_blanks(buf, &p);
+- pages = cmm_strtoul(p, &p);
++ nr = simple_strtoul(p, &p, 0);
+ cmm_skip_blanks(p, &p);
+- seconds = cmm_strtoul(p, &p);
+- cmm_set_timeout(pages, seconds);
++ seconds = simple_strtoul(p, &p, 0);
++ cmm_set_timeout(nr, seconds);
+ } else {
+ len = sprintf(buf, "%ld %ld\n",
+ cmm_timeout_pages, cmm_timeout_seconds);
+@@ -373,7 +380,7 @@ static struct ctl_table cmm_dir_table[]
+ static void
+ cmm_smsg_target(char *from, char *msg)
+ {
+- long pages, seconds;
++ long nr, seconds;
+
+ if (strlen(sender) > 0 && strcmp(from, sender) != 0)
+ return;
+@@ -382,27 +389,27 @@ cmm_smsg_target(char *from, char *msg)
+ if (strncmp(msg, "SHRINK", 6) == 0) {
+ if (!cmm_skip_blanks(msg + 6, &msg))
+ return;
+- pages = cmm_strtoul(msg, &msg);
++ nr = simple_strtoul(msg, &msg, 0);
+ cmm_skip_blanks(msg, &msg);
+ if (*msg == '\0')
+- cmm_set_pages(pages);
++ cmm_set_pages(nr);
+ } else if (strncmp(msg, "RELEASE", 7) == 0) {
+ if (!cmm_skip_blanks(msg + 7, &msg))
+ return;
+- pages = cmm_strtoul(msg, &msg);
++ nr = simple_strtoul(msg, &msg, 0);
+ cmm_skip_blanks(msg, &msg);
+ if (*msg == '\0')
+- cmm_add_timed_pages(pages);
++ cmm_add_timed_pages(nr);
+ } else if (strncmp(msg, "REUSE", 5) == 0) {
+ if (!cmm_skip_blanks(msg + 5, &msg))
+ return;
+- pages = cmm_strtoul(msg, &msg);
++ nr = simple_strtoul(msg, &msg, 0);
+ if (!cmm_skip_blanks(msg, &msg))
+ return;
+- seconds = cmm_strtoul(msg, &msg);
++ seconds = simple_strtoul(msg, &msg, 0);
+ cmm_skip_blanks(msg, &msg);
+ if (*msg == '\0')
+- cmm_set_timeout(pages, seconds);
++ cmm_set_timeout(nr, seconds);
+ }
+ }
+ #endif
+@@ -412,21 +419,49 @@ struct ctl_table_header *cmm_sysctl_head
+ static int
+ cmm_init (void)
+ {
++ int rc = -ENOMEM;
++
+ #ifdef CONFIG_CMM_PROC
+ cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1);
++ if (!cmm_sysctl_header)
++ goto out;
+ #endif
+ #ifdef CONFIG_CMM_IUCV
+- smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
++ rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
++ if (rc < 0)
++ goto out_smsg;
+ #endif
+- INIT_WORK(&cmm_thread_starter, (void *) cmm_start_thread, NULL);
++ rc = register_oom_notifier(&cmm_oom_nb);
++ if (rc < 0)
++ goto out_oom_notify;
+ init_waitqueue_head(&cmm_thread_wait);
+ init_timer(&cmm_timer);
+- return 0;
++ cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
++ rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
++ if (!rc)
++ goto out;
++ /*
++ * kthread_create failed. undo all the stuff from above again.
++ */
++ unregister_oom_notifier(&cmm_oom_nb);
++
++out_oom_notify:
++#ifdef CONFIG_CMM_IUCV
++ smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
++out_smsg:
++#endif
++#ifdef CONFIG_CMM_PROC
++ unregister_sysctl_table(cmm_sysctl_header);
++#endif
++out:
++ return rc;
+ }
+
+ static void
+ cmm_exit(void)
+ {
++ kthread_stop(cmm_thread_ptr);
++ unregister_oom_notifier(&cmm_oom_nb);
+ cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
+ cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
+ #ifdef CONFIG_CMM_PROC
+diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
+index 9b11e3e..226275d 100644
+--- a/arch/s390/mm/extmem.c
++++ b/arch/s390/mm/extmem.c
+@@ -142,17 +142,17 @@ dcss_diag (__u8 func, void *parameter,
+
+ rx = (unsigned long) parameter;
+ ry = (unsigned long) func;
+- __asm__ __volatile__(
++ asm volatile(
+ #ifdef CONFIG_64BIT
+- " sam31\n" // switch to 31 bit
+- " diag %0,%1,0x64\n"
+- " sam64\n" // switch back to 64 bit
++ " sam31\n"
++ " diag %0,%1,0x64\n"
++ " sam64\n"
+ #else
+- " diag %0,%1,0x64\n"
++ " diag %0,%1,0x64\n"
+ #endif
+- " ipm %2\n"
+- " srl %2,28\n"
+- : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" );
++ " ipm %2\n"
++ " srl %2,28\n"
++ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+ *ret1 = rx;
+ *ret2 = ry;
+ return rc;
+diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
+index 7cd8257..1c323bb 100644
+--- a/arch/s390/mm/fault.c
++++ b/arch/s390/mm/fault.c
+@@ -25,10 +25,12 @@
+ #include <linux/console.h>
+ #include <linux/module.h>
+ #include <linux/hardirq.h>
++#include <linux/kprobes.h>
+
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
++#include <asm/kdebug.h>
+
+ #ifndef CONFIG_64BIT
+ #define __FAIL_ADDR_MASK 0x7ffff000
+@@ -48,6 +50,38 @@ extern int sysctl_userprocess_debug;
+
+ extern void die(const char *,struct pt_regs *,long);
+
++#ifdef CONFIG_KPROBES
++ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++int register_page_fault_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
++}
++
++int unregister_page_fault_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
++}
++
++static inline int notify_page_fault(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ struct die_args args = {
++ .regs = regs,
++ .str = str,
++ .err = err,
++ .trapnr = trap,
++ .signr = sig
++ };
++ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
++}
++#else
++static inline int notify_page_fault(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ return NOTIFY_DONE;
++}
++#endif
++
+ extern spinlock_t timerlist_lock;
+
+ /*
+@@ -159,7 +193,7 @@ static void do_sigsegv(struct pt_regs *r
+ * 11 Page translation -> Not present (nullification)
+ * 3b Region third trans. -> Not present (nullification)
+ */
+-static inline void
++static inline void __kprobes
+ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
+ {
+ struct task_struct *tsk;
+@@ -173,6 +207,10 @@ do_exception(struct pt_regs *regs, unsig
+ tsk = current;
+ mm = tsk->mm;
+
++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
++ SIGSEGV) == NOTIFY_STOP)
++ return;
++
+ /*
+ * Check for low-address protection. This needs to be treated
+ * as a special case because the translation exception code
+@@ -315,8 +353,9 @@ no_context:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (tsk->pid == 1) {
++ if (is_init(tsk)) {
+ yield();
++ down_read(&mm->mmap_sem);
+ goto survive;
+ }
+ printk("VM: killing process %s\n", tsk->comm);
+@@ -385,20 +424,13 @@ int pfault_init(void)
+
+ if (pfault_disable)
+ return -1;
+- __asm__ __volatile__(
+- " diag %1,%0,0x258\n"
+- "0: j 2f\n"
+- "1: la %0,8\n"
++ asm volatile(
++ " diag %1,%0,0x258\n"
++ "0: j 2f\n"
++ "1: la %0,8\n"
+ "2:\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+-#ifndef CONFIG_64BIT
+- " .long 0b,1b\n"
+-#else /* CONFIG_64BIT */
+- " .quad 0b,1b\n"
+-#endif /* CONFIG_64BIT */
+- ".previous"
+- : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc" );
++ EX_TABLE(0b,1b)
++ : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
+ __ctl_set_bit(0, 9);
+ return rc;
+ }
+@@ -411,22 +443,15 @@ void pfault_fini(void)
+ if (pfault_disable)
+ return;
+ __ctl_clear_bit(0,9);
+- __asm__ __volatile__(
+- " diag %0,0,0x258\n"
++ asm volatile(
++ " diag %0,0,0x258\n"
+ "0:\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+-#ifndef CONFIG_64BIT
+- " .long 0b,0b\n"
+-#else /* CONFIG_64BIT */
+- " .quad 0b,0b\n"
+-#endif /* CONFIG_64BIT */
+- ".previous"
+- : : "a" (&refbk), "m" (refbk) : "cc" );
++ EX_TABLE(0b,0b)
++ : : "a" (&refbk), "m" (refbk) : "cc");
+ }
+
+ asmlinkage void
+-pfault_interrupt(struct pt_regs *regs, __u16 error_code)
++pfault_interrupt(__u16 error_code)
+ {
+ struct task_struct *tsk;
+ __u16 subcode;
+diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
+index 6e6b6de..e1881c3 100644
+--- a/arch/s390/mm/init.c
++++ b/arch/s390/mm/init.c
+@@ -45,45 +45,38 @@ void diag10(unsigned long addr)
+ {
+ if (addr >= 0x7ff00000)
+ return;
++ asm volatile(
+ #ifdef CONFIG_64BIT
+- asm volatile (
+- " sam31\n"
+- " diag %0,%0,0x10\n"
+- "0: sam64\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b, 0b\n"
+- ".previous\n"
+- : : "a" (addr));
++ " sam31\n"
++ " diag %0,%0,0x10\n"
++ "0: sam64\n"
+ #else
+- asm volatile (
+- " diag %0,%0,0x10\n"
++ " diag %0,%0,0x10\n"
+ "0:\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b, 0b\n"
+- ".previous\n"
+- : : "a" (addr));
+ #endif
++ EX_TABLE(0b,0b)
++ : : "a" (addr));
+ }
+
+ void show_mem(void)
+ {
+ int i, total = 0, reserved = 0;
+ int shared = 0, cached = 0;
++ struct page *page;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ i = max_mapnr;
+ while (i-- > 0) {
++ page = pfn_to_page(i);
+ total++;
+- if (PageReserved(mem_map+i))
++ if (PageReserved(page))
+ reserved++;
+- else if (PageSwapCache(mem_map+i))
++ else if (PageSwapCache(page))
+ cached++;
+- else if (page_count(mem_map+i))
+- shared += page_count(mem_map+i) - 1;
++ else if (page_count(page))
++ shared += page_count(page) - 1;
+ }
+ printk("%d pages of RAM\n",total);
+ printk("%d reserved pages\n",reserved);
+@@ -108,16 +101,23 @@ void __init paging_init(void)
+ unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
+ static const int ssm_mask = 0x04000000L;
+ unsigned long ro_start_pfn, ro_end_pfn;
++ unsigned long zones_size[MAX_NR_ZONES];
+
+ ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata);
+ ro_end_pfn = PFN_UP((unsigned long)&__end_rodata);
+
++ memset(zones_size, 0, sizeof(zones_size));
++ zones_size[ZONE_DMA] = max_low_pfn;
++ free_area_init_node(0, &contig_page_data, zones_size,
++ __pa(PAGE_OFFSET) >> PAGE_SHIFT,
++ zholes_size);
++
+ /* unmap whole virtual address space */
+
+ pg_dir = swapper_pg_dir;
+
+- for (i=0;i<KERNEL_PGD_PTRS;i++)
+- pmd_clear((pmd_t*)pg_dir++);
++ for (i = 0; i < PTRS_PER_PGD; i++)
++ pmd_clear((pmd_t *) pg_dir++);
+
+ /*
+ * map whole physical memory to virtual memory (identity mapping)
+@@ -131,10 +131,7 @@ void __init paging_init(void)
+ */
+ pg_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+
+- pg_dir->pgd0 = (_PAGE_TABLE | __pa(pg_table));
+- pg_dir->pgd1 = (_PAGE_TABLE | (__pa(pg_table)+1024));
+- pg_dir->pgd2 = (_PAGE_TABLE | (__pa(pg_table)+2048));
+- pg_dir->pgd3 = (_PAGE_TABLE | (__pa(pg_table)+3072));
++ pmd_populate_kernel(&init_mm, (pmd_t *) pg_dir, pg_table);
+ pg_dir++;
+
+ for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
+@@ -143,8 +140,8 @@ void __init paging_init(void)
+ else
+ pte = pfn_pte(pfn, PAGE_KERNEL);
+ if (pfn >= max_low_pfn)
+- pte_clear(&init_mm, 0, &pte);
+- set_pte(pg_table, pte);
++ pte_val(pte) = _PAGE_TYPE_EMPTY;
++ set_pte(pg_table, pte);
+ pfn++;
+ }
+ }
+@@ -152,24 +149,12 @@ void __init paging_init(void)
+ S390_lowcore.kernel_asce = pgdir_k;
+
+ /* enable virtual mapping in kernel mode */
+- __asm__ __volatile__(" LCTL 1,1,%0\n"
+- " LCTL 7,7,%0\n"
+- " LCTL 13,13,%0\n"
+- " SSM %1"
+- : : "m" (pgdir_k), "m" (ssm_mask));
++ __ctl_load(pgdir_k, 1, 1);
++ __ctl_load(pgdir_k, 7, 7);
++ __ctl_load(pgdir_k, 13, 13);
++ __raw_local_irq_ssm(ssm_mask);
+
+ local_flush_tlb();
+-
+- {
+- unsigned long zones_size[MAX_NR_ZONES];
+-
+- memset(zones_size, 0, sizeof(zones_size));
+- zones_size[ZONE_DMA] = max_low_pfn;
+- free_area_init_node(0, &contig_page_data, zones_size,
+- __pa(PAGE_OFFSET) >> PAGE_SHIFT,
+- zholes_size);
+- }
+- return;
+ }
+
+ #else /* CONFIG_64BIT */
+@@ -236,10 +221,8 @@ void __init paging_init(void)
+ pte = pfn_pte(pfn, __pgprot(_PAGE_RO));
+ else
+ pte = pfn_pte(pfn, PAGE_KERNEL);
+- if (pfn >= max_low_pfn) {
+- pte_clear(&init_mm, 0, &pte);
+- continue;
+- }
++ if (pfn >= max_low_pfn)
++ pte_val(pte) = _PAGE_TYPE_EMPTY;
+ set_pte(pt_dir, pte);
+ pfn++;
+ }
+@@ -249,15 +232,12 @@ void __init paging_init(void)
+ S390_lowcore.kernel_asce = pgdir_k;
+
+ /* enable virtual mapping in kernel mode */
+- __asm__ __volatile__("lctlg 1,1,%0\n\t"
+- "lctlg 7,7,%0\n\t"
+- "lctlg 13,13,%0\n\t"
+- "ssm %1"
+- : :"m" (pgdir_k), "m" (ssm_mask));
++ __ctl_load(pgdir_k, 1, 1);
++ __ctl_load(pgdir_k, 7, 7);
++ __ctl_load(pgdir_k, 13, 13);
++ __raw_local_irq_ssm(ssm_mask);
+
+ local_flush_tlb();
+-
+- return;
+ }
+ #endif /* CONFIG_64BIT */
+
+diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
+index 1a0db1d..6a461d4 100644
+--- a/arch/sh/Kconfig
++++ b/arch/sh/Kconfig
+@@ -8,6 +8,7 @@ mainmenu "Linux/SuperH Kernel Configurat
+ config SUPERH
+ bool
+ default y
++ select EMBEDDED
+ help
+ The SuperH is a RISC processor targeted for use in embedded systems
+ and consumer electronics; it was also used in the Sega Dreamcast
+@@ -44,6 +45,9 @@ config GENERIC_CALIBRATE_DELAY
+ config GENERIC_IOMAP
+ bool
+
++config GENERIC_TIME
++ def_bool n
++
+ config ARCH_MAY_HAVE_PC_FDC
+ bool
+
+@@ -51,18 +55,23 @@ source "init/Kconfig"
+
+ menu "System type"
+
++config SOLUTION_ENGINE
++ bool
++
+ choice
+ prompt "SuperH system type"
+ default SH_UNKNOWN
+
+ config SH_SOLUTION_ENGINE
+ bool "SolutionEngine"
++ select SOLUTION_ENGINE
+ help
+ Select SolutionEngine if configuring for a Hitachi SH7709
+ or SH7750 evaluation board.
+
+ config SH_7751_SOLUTION_ENGINE
+ bool "SolutionEngine7751"
++ select SOLUTION_ENGINE
+ select CPU_SUBTYPE_SH7751
+ help
+ Select 7751 SolutionEngine if configuring for a Hitachi SH7751
+@@ -70,17 +79,27 @@ config SH_7751_SOLUTION_ENGINE
+
+ config SH_7300_SOLUTION_ENGINE
+ bool "SolutionEngine7300"
++ select SOLUTION_ENGINE
+ select CPU_SUBTYPE_SH7300
+ help
+- Select 7300 SolutionEngine if configuring for a Hitachi SH7300(SH-Mobile V)
+- evaluation board.
++ Select 7300 SolutionEngine if configuring for a Hitachi
++ SH7300(SH-Mobile V) evaluation board.
++
++config SH_7343_SOLUTION_ENGINE
++ bool "SolutionEngine7343"
++ select SOLUTION_ENGINE
++ select CPU_SUBTYPE_SH7343
++ help
++ Select 7343 SolutionEngine if configuring for a Hitachi
++ SH7343 (SH-Mobile 3AS) evaluation board.
+
+ config SH_73180_SOLUTION_ENGINE
+ bool "SolutionEngine73180"
+- select CPU_SUBTYPE_SH73180
+- help
+- Select 73180 SolutionEngine if configuring for a Hitachi SH73180(SH-Mobile 3)
+- evaluation board.
++ select SOLUTION_ENGINE
++ select CPU_SUBTYPE_SH73180
++ help
++ Select 73180 SolutionEngine if configuring for a Hitachi
++ SH73180(SH-Mobile 3) evaluation board.
+
+ config SH_7751_SYSTEMH
+ bool "SystemH7751R"
+@@ -89,12 +108,6 @@ config SH_7751_SYSTEMH
+ Select SystemH if you are configuring for a Renesas SystemH
+ 7751R evaluation board.
+
+-config SH_STB1_HARP
+- bool "STB1_Harp"
+-
+-config SH_STB1_OVERDRIVE
+- bool "STB1_Overdrive"
+-
+ config SH_HP6XX
+ bool "HP6XX"
+ help
+@@ -102,19 +115,6 @@ config SH_HP6XX
+ More information (hardware only) at
+ <http://www.hp.com/jornada/>.
+
+-config SH_CQREEK
+- bool "CqREEK"
+- help
+- Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
+- More information at
+- <http://sources.redhat.com/ecos/hardware.html#SuperH>.
+-
+-config SH_DMIDA
+- bool "DMIDA"
+- help
+- Select DMIDA if configuring for a DataMyte 4000 Industrial
+- Digital Assistant. More information at <http://www.dmida.com/>.
+-
+ config SH_EC3104
+ bool "EC3104"
+ help
+@@ -136,25 +136,9 @@ config SH_DREAMCAST
+ <http://www.m17n.org/linux-sh/dreamcast/>. There is a
+ Dreamcast project is at <http://linuxdc.sourceforge.net/>.
+
+-config SH_CAT68701
+- bool "CAT68701"
+-
+ config SH_BIGSUR
+ bool "BigSur"
+
+-config SH_SH2000
+- bool "SH2000"
+- select CPU_SUBTYPE_SH7709
+- help
+- SH-2000 is a single-board computer based around SH7709A chip
+- intended for embedded applications.
+- It has an Ethernet interface (CS8900A), direct connected
+- Compact Flash socket, three serial ports and PC-104 bus.
+- More information at <http://sh2000.sh-linux.org>.
+-
+-config SH_ADX
+- bool "ADX"
+-
+ config SH_MPC1211
+ bool "Interface MPC1211"
+ help
+@@ -184,6 +168,13 @@ config SH_HS7751RVOIP
+ Select HS7751RVOIP if configuring for a Renesas Technology
+ Sales VoIP board.
+
++config SH_7710VOIPGW
++ bool "SH7710-VOIP-GW"
++ select CPU_SUBTYPE_SH7710
++ help
++ Select this option to build a kernel for the SH7710 based
++ VOIP GW.
++
+ config SH_RTS7751R2D
+ bool "RTS7751R2D"
+ select CPU_SUBTYPE_SH7751R
+@@ -222,6 +213,12 @@ config SH_TITAN
+ Select Titan if you are configuring for a Nimble Microsystems
+ NetEngine NP51R.
+
++config SH_SHMIN
++ bool "SHMIN"
++ select CPU_SUBTYPE_SH7706
++ help
++ Select SHMIN if configureing for the SHMIN board
++
+ config SH_UNKNOWN
+ bool "BareCPU"
+ help
+@@ -238,35 +235,9 @@ endchoice
+
+ source "arch/sh/mm/Kconfig"
+
+-config MEMORY_START
+- hex "Physical memory start address"
+- default "0x08000000"
+- ---help---
+- Computers built with Hitachi SuperH processors always
+- map the ROM starting at address zero. But the processor
+- does not specify the range that RAM takes.
+-
+- The physical memory (RAM) start address will be automatically
+- set to 08000000. Other platforms, such as the Solution Engine
+- boards typically map RAM at 0C000000.
+-
+- Tweak this only when porting to a new machine which does not
+- already have a defconfig. Changing it from the known correct
+- value on any of the known systems will only lead to disaster.
+-
+-config MEMORY_SIZE
+- hex "Physical memory size"
+- default "0x00400000"
+- help
+- This sets the default memory size assumed by your SH kernel. It can
+- be overridden as normal by the 'mem=' argument on the kernel command
+- line. If unsure, consult your board specifications or just leave it
+- as 0x00400000 which was the default value before this became
+- configurable.
+-
+ config CF_ENABLER
+ bool "Compact Flash Enabler support"
+- depends on SH_ADX || SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_CAT68701 || SH_SH03
++ depends on SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_SH03
+ ---help---
+ Compact Flash is a small, removable mass storage device introduced
+ in 1994 originally as a PCMCIA device. If you say `Y' here, you
+@@ -294,7 +265,7 @@ config CF_AREA5
+ - "Area5" if CompactFlash is connected to Area 5 (0x14000000)
+ - "Area6" if it is connected to Area 6 (0x18000000)
+
+- "Area6" will work for most boards. For ADX, select "Area5".
++ "Area6" will work for most boards.
+
+ config CF_AREA6
+ bool "Area6"
+@@ -316,19 +287,6 @@ config CPU_LITTLE_ENDIAN
+ endian byte order. These modes require different kernels. Say Y if
+ your machine is little endian, N if it's a big endian machine.
+
+-# The SH7750 RTC module is disabled in the Dreamcast
+-config SH_RTC
+- bool
+- depends on !SH_DREAMCAST && !SH_SATURN && !SH_7300_SOLUTION_ENGINE && \
+- !SH_73180_SOLUTION_ENGINE && !SH_LANDISK && \
+- !SH_R7780RP
+- default y
+- help
+- Selecting this option will allow the Linux kernel to emulate
+- PC's RTC.
+-
+- If unsure, say N.
+-
+ config SH_FPU
+ bool "FPU support"
+ depends on !CPU_SH3
+@@ -339,14 +297,22 @@ config SH_FPU
+
+ This option must be set in order to enable the FPU.
+
++config SH_FPU_EMU
++ bool "FPU emulation support"
++ depends on !SH_FPU && EXPERIMENTAL
++ default n
++ help
++ Selecting this option will enable support for software FPU emulation.
++ Most SH-3 users will want to say Y here, whereas most SH-4 users will
++ want to say N.
++
+ config SH_DSP
+ bool "DSP support"
+- depends on !CPU_SH4
+- default y
++ default y if SH4AL_DSP || !CPU_SH4
++ default n
+ help
+ Selecting this option will enable support for SH processors that
+- have DSP units (ie, SH2-DSP and SH3-DSP). It is safe to say Y here
+- by default, as the existance of the DSP will be probed at runtime.
++ have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
+
+ This option must be set in order to enable the DSP.
+
+@@ -373,6 +339,9 @@ config CPU_HAS_INTEVT
+ config CPU_HAS_PINT_IRQ
+ bool
+
++config CPU_HAS_MASKREG_IRQ
++ bool
++
+ config CPU_HAS_INTC2_IRQ
+ bool
+
+@@ -391,6 +360,7 @@ config CPU_HAS_SR_RB
+ endmenu
+
+ menu "Timer support"
++depends on !GENERIC_TIME
+
+ config SH_TMU
+ bool "TMU timer support"
+@@ -400,16 +370,19 @@ config SH_TMU
+
+ endmenu
+
+-#source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
++source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
+
+-#source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
++source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
++
++source "arch/sh/boards/renesas/r7780rp/Kconfig"
+
+ config SH_PCLK_FREQ
+ int "Peripheral clock frequency (in Hz)"
+ default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
+ default "60000000" if CPU_SUBTYPE_SH7751
+- default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || CPU_SUBTYPE_SH7760
+- default "27000000" if CPU_SUBTYPE_SH73180
++ default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
++ CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705
++ default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
+ default "66000000" if CPU_SUBTYPE_SH4_202
+ help
+ This option is used to specify the peripheral clock frequency.
+@@ -440,10 +413,8 @@ source "arch/sh/cchips/Kconfig"
+
+ config HEARTBEAT
+ bool "Heartbeat LED"
+- depends on SH_MPC1211 || SH_SH03 || SH_CAT68701 || \
+- SH_STB1_HARP || SH_STB1_OVERDRIVE || SH_BIGSUR || \
+- SH_7751_SOLUTION_ENGINE || SH_7300_SOLUTION_ENGINE || \
+- SH_73180_SOLUTION_ENGINE || SH_SOLUTION_ENGINE || \
++ depends on SH_MPC1211 || SH_SH03 || \
++ SH_BIGSUR || SOLUTION_ENGINE || \
+ SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK
+ help
+ Use the power-on LED on your machine as a load meter. The exact
+@@ -459,6 +430,8 @@ config ISA_DMA_API
+
+ menu "Kernel features"
+
++source kernel/Kconfig.hz
++
+ config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+@@ -476,10 +449,6 @@ config KEXEC
+ support. As of this writing the exact hardware interface is
+ strongly in flux, so no good recommendation can be made.
+
+-config PREEMPT
+- bool "Preemptible Kernel (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
+-
+ config SMP
+ bool "Symmetric multi-processing support"
+ ---help---
+@@ -515,6 +484,8 @@ config NR_CPUS
+ This is purely to save memory - each supported CPU adds
+ approximately eight kilobytes to the kernel image.
+
++source "kernel/Kconfig.preempt"
++
+ config CPU_HAS_SR_RB
+ bool "CPU has SR.RB"
+ depends on CPU_SH3 || CPU_SH4
+@@ -636,6 +607,16 @@ source "fs/Kconfig.binfmt"
+
+ endmenu
+
++menu "Power management options (EXPERIMENTAL)"
++depends on EXPERIMENTAL
++
++source kernel/power/Kconfig
++
++config APM
++ bool "Advanced Power Management Emulation"
++ depends on PM
++endmenu
++
+ source "net/Kconfig"
+
+ source "drivers/Kconfig"
+diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
+index 8fb31ab..48479e0 100644
+--- a/arch/sh/Kconfig.debug
++++ b/arch/sh/Kconfig.debug
+@@ -30,8 +30,35 @@ config EARLY_PRINTK
+ when the kernel may crash or hang before the serial console is
+ initialised. If unsure, say N.
+
++config DEBUG_STACKOVERFLOW
++ bool "Check for stack overflows"
++ depends on DEBUG_KERNEL
++ help
++ This option will cause messages to be printed if free stack space
++ drops below a certain limit.
++
++config DEBUG_STACK_USAGE
++ bool "Stack utilization instrumentation"
++ depends on DEBUG_KERNEL
++ help
++ Enables the display of the minimum amount of free stack which each
++ task has ever had available in the sysrq-T and sysrq-P debug output.
++
++ This option will slow down process creation somewhat.
++
++config 4KSTACKS
++ bool "Use 4Kb for kernel stacks instead of 8Kb"
++ depends on DEBUG_KERNEL
++ help
++ If you say Y here the kernel will use a 4Kb stacksize for the
++ kernel stack attached to each process/thread. This facilitates
++ running more threads on a system and also reduces the pressure
++ on the VM subsystem for higher order allocations. This option
++ will also use IRQ stacks to compensate for the reduced stackspace.
++
+ config KGDB
+ bool "Include KGDB kernel debugger"
++ select FRAME_POINTER
+ help
+ Include in-kernel hooks for kgdb, the Linux kernel source level
+ debugger. See <http://kgdb.sourceforge.net/> for more information.
+@@ -112,13 +139,4 @@ endchoice
+
+ endmenu
+
+-config FRAME_POINTER
+- bool "Compile the kernel with frame pointers"
+- default y if KGDB
+- help
+- If you say Y here the resulting kernel image will be slightly larger
+- and slower, but it will give very useful debugging information.
+- If you don't debug the kernel, you can say N, but we may not be able
+- to solve problems without frame pointers.
+-
+ endmenu
+diff --git a/arch/sh/Makefile b/arch/sh/Makefile
+index e467a45..26d62ff 100644
+--- a/arch/sh/Makefile
++++ b/arch/sh/Makefile
+@@ -18,11 +18,13 @@ cflags-y := -mb
+ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml
+
+ isa-y := any
++isa-$(CONFIG_SH_DSP) := sh
+ isa-$(CONFIG_CPU_SH2) := sh2
++isa-$(CONFIG_CPU_SH2A) := sh2a
+ isa-$(CONFIG_CPU_SH3) := sh3
+ isa-$(CONFIG_CPU_SH4) := sh4
+ isa-$(CONFIG_CPU_SH4A) := sh4a
+-isa-$(CONFIG_CPU_SH2A) := sh2a
++isa-$(CONFIG_CPU_SH4AL_DSP) := sh4al
+
+ isa-$(CONFIG_SH_DSP) := $(isa-y)-dsp
+
+@@ -30,9 +32,11 @@ ifndef CONFIG_MMU
+ isa-y := $(isa-y)-nommu
+ endif
+
++ifndef CONFIG_SH_DSP
+ ifndef CONFIG_SH_FPU
+ isa-y := $(isa-y)-nofpu
+ endif
++endif
+
+ cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
+
+@@ -79,24 +83,19 @@ head-y := arch/sh/kernel/head.o arch/sh/
+ LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+ core-y += arch/sh/kernel/ arch/sh/mm/
++core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
+
+ # Boards
+ machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
+ machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751
+ machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se/7300
++machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343
+ machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180
+-machdir-$(CONFIG_SH_STB1_HARP) := harp
+-machdir-$(CONFIG_SH_STB1_OVERDRIVE) := overdrive
+ machdir-$(CONFIG_SH_HP6XX) := hp6xx
+-machdir-$(CONFIG_SH_CQREEK) := cqreek
+-machdir-$(CONFIG_SH_DMIDA) := dmida
+ machdir-$(CONFIG_SH_EC3104) := ec3104
+ machdir-$(CONFIG_SH_SATURN) := saturn
+ machdir-$(CONFIG_SH_DREAMCAST) := dreamcast
+-machdir-$(CONFIG_SH_CAT68701) := cat68701
+ machdir-$(CONFIG_SH_BIGSUR) := bigsur
+-machdir-$(CONFIG_SH_SH2000) := sh2000
+-machdir-$(CONFIG_SH_ADX) := adx
+ machdir-$(CONFIG_SH_MPC1211) := mpc1211
+ machdir-$(CONFIG_SH_SH03) := sh03
+ machdir-$(CONFIG_SH_SECUREEDGE5410) := snapgear
+@@ -104,16 +103,16 @@ machdir-$(CONFIG_SH_HS7751RVOIP) := ren
+ machdir-$(CONFIG_SH_RTS7751R2D) := renesas/rts7751r2d
+ machdir-$(CONFIG_SH_7751_SYSTEMH) := renesas/systemh
+ machdir-$(CONFIG_SH_EDOSK7705) := renesas/edosk7705
++machdir-$(CONFIG_SH_R7780RP) := renesas/r7780rp
++machdir-$(CONFIG_SH_7710VOIPGW) := renesas/sh7710voipgw
+ machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev
++machdir-$(CONFIG_SH_LANDISK) := landisk
++machdir-$(CONFIG_SH_TITAN) := titan
++machdir-$(CONFIG_SH_SHMIN) := shmin
+ machdir-$(CONFIG_SH_UNKNOWN) := unknown
+
+ incdir-y := $(notdir $(machdir-y))
+-
+-incdir-$(CONFIG_SH_SOLUTION_ENGINE) := se
+-incdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se7751
+-incdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se7300
+-incdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se73180
+-incdir-$(CONFIG_SH_HP600) := hp6xx
++incdir-$(CONFIG_SH_HP6XX) := hp6xx
+
+ ifneq ($(machdir-y),)
+ core-y += arch/sh/boards/$(machdir-y)/
+@@ -137,17 +136,14 @@ boot := arch/sh/boot
+
+ CPPFLAGS_vmlinux.lds := -traditional
+
+-ifneq ($(KBUILD_SRC),)
+ incdir-prefix := $(srctree)/include/asm-sh/
+-else
+-incdir-prefix :=
+-endif
+
+ # Update machine arch and proc symlinks if something which affects
+ # them changed. We use .arch and .mach to indicate when they were
+ # updated last, otherwise make uses the target directory mtime.
+
+-include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/auto.conf
++include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) \
++ include/config/auto.conf FORCE
+ @echo ' SYMLINK include/asm-sh/cpu -> include/asm-sh/$(cpuincdir-y)'
+ $(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
+ $(Q)ln -fsn $(incdir-prefix)$(cpuincdir-y) include/asm-sh/cpu
+@@ -157,7 +153,8 @@ include/asm-sh/.cpu: $(wildcard include/
+ # don't, just reference the parent directory so the semantics are
+ # kept roughly the same.
+
+-include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/auto.conf
++include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \
++ include/config/auto.conf FORCE
+ @echo -n ' SYMLINK include/asm-sh/mach -> '
+ $(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
+ $(Q)if [ -d $(incdir-prefix)$(incdir-y) ]; then \
+@@ -170,7 +167,7 @@ include/asm-sh/.mach: $(wildcard include
+ fi
+ @touch $@
+
+-archprepare: maketools include/asm-sh/.cpu include/asm-sh/.mach
++archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools
+
+ PHONY += maketools FORCE
+ maketools: include/linux/version.h FORCE
+@@ -191,4 +188,3 @@ CLEAN_FILES += include/asm-sh/machtypes.
+ define archhelp
+ @echo ' zImage - Compressed kernel image (arch/sh/boot/zImage)'
+ endef
+-
+diff --git a/arch/sh/boards/adx/Makefile b/arch/sh/boards/adx/Makefile
+deleted file mode 100644
+index 5b1c531..0000000
+--- a/arch/sh/boards/adx/Makefile
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#
+-# Makefile for ADX boards
+-#
+-
+-obj-y := setup.o irq.o irq_maskreq.o
+-
+diff --git a/arch/sh/boards/adx/irq.c b/arch/sh/boards/adx/irq.c
+deleted file mode 100644
+index c6ca409..0000000
+--- a/arch/sh/boards/adx/irq.c
++++ /dev/null
+@@ -1,31 +0,0 @@
+-/*
+- * linux/arch/sh/boards/adx/irq.c
+- *
+- * Copyright (C) 2001 A&D Co., Ltd.
+- *
+- * I/O routine and setup routines for A&D ADX 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.
+- *
+- */
+-
+-#include <asm/irq.h>
+-
+-void init_adx_IRQ(void)
+-{
+- int i;
+-
+-/* printk("init_adx_IRQ()\n");*/
+- /* setup irq_mask_register */
+- irq_mask_register = (unsigned short *)0xa6000008;
+-
+- /* cover all external interrupt area by maskreg_irq_type
+- * (Actually, irq15 doesn't exist)
+- */
+- for (i = 0; i < 16; i++) {
+- make_maskreg_irq(i);
+- disable_irq(i);
+- }
+-}
+diff --git a/arch/sh/boards/adx/irq_maskreg.c b/arch/sh/boards/adx/irq_maskreg.c
+deleted file mode 100644
+index 4b2abe5..0000000
+--- a/arch/sh/boards/adx/irq_maskreg.c
++++ /dev/null
+@@ -1,106 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/irq_maskreg.c
+- *
+- * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp>
+- *
+- * This file may be copied or modified under the terms of the GNU
+- * General Public License. See linux/COPYING for more information.
+- *
+- * Interrupt handling for Simple external interrupt mask register
+- *
+- * This is for the machine which have single 16 bit register
+- * for masking external IRQ individually.
+- * Each bit of the register is for masking each interrupt.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/machvec.h>
+-
+-/* address of external interrupt mask register
+- * address must be set prior to use these (maybe in init_XXX_irq())
+- * XXX : is it better to use .config than specifying it in code? */
+-unsigned short *irq_mask_register = 0;
+-
+-/* forward declaration */
+-static unsigned int startup_maskreg_irq(unsigned int irq);
+-static void shutdown_maskreg_irq(unsigned int irq);
+-static void enable_maskreg_irq(unsigned int irq);
+-static void disable_maskreg_irq(unsigned int irq);
+-static void mask_and_ack_maskreg(unsigned int);
+-static void end_maskreg_irq(unsigned int irq);
+-
+-/* hw_interrupt_type */
+-static struct hw_interrupt_type maskreg_irq_type = {
+- .typename = " Mask Register",
+- .startup = startup_maskreg_irq,
+- .shutdown = shutdown_maskreg_irq,
+- .enable = enable_maskreg_irq,
+- .disable = disable_maskreg_irq,
+- .ack = mask_and_ack_maskreg,
+- .end = end_maskreg_irq
+-};
+-
+-/* actual implementatin */
+-static unsigned int startup_maskreg_irq(unsigned int irq)
+-{
+- enable_maskreg_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static void shutdown_maskreg_irq(unsigned int irq)
+-{
+- disable_maskreg_irq(irq);
+-}
+-
+-static void disable_maskreg_irq(unsigned int irq)
+-{
+- if (irq_mask_register) {
+- unsigned long flags;
+- unsigned short val, mask = 0x01 << irq;
+-
+- /* Set "irq"th bit */
+- local_irq_save(flags);
+- val = ctrl_inw((unsigned long)irq_mask_register);
+- val |= mask;
+- ctrl_outw(val, (unsigned long)irq_mask_register);
+- local_irq_restore(flags);
+- }
+-}
+-
+-static void enable_maskreg_irq(unsigned int irq)
+-{
+- if (irq_mask_register) {
+- unsigned long flags;
+- unsigned short val, mask = ~(0x01 << irq);
+-
+- /* Clear "irq"th bit */
+- local_irq_save(flags);
+- val = ctrl_inw((unsigned long)irq_mask_register);
+- val &= mask;
+- ctrl_outw(val, (unsigned long)irq_mask_register);
+- local_irq_restore(flags);
+- }
+-}
+-
+-static void mask_and_ack_maskreg(unsigned int irq)
+-{
+- disable_maskreg_irq(irq);
+-}
+-
+-static void end_maskreg_irq(unsigned int irq)
+-{
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+- enable_maskreg_irq(irq);
+-}
+-
+-void make_maskreg_irq(unsigned int irq)
+-{
+- disable_irq_nosync(irq);
+- irq_desc[irq].chip = &maskreg_irq_type;
+- disable_maskreg_irq(irq);
+-}
+diff --git a/arch/sh/boards/adx/setup.c b/arch/sh/boards/adx/setup.c
+deleted file mode 100644
+index 4938d95..0000000
+--- a/arch/sh/boards/adx/setup.c
++++ /dev/null
+@@ -1,56 +0,0 @@
+-/*
+- * linux/arch/sh/board/adx/setup.c
+- *
+- * Copyright (C) 2001 A&D Co., Ltd.
+- *
+- * I/O routine and setup routines for A&D ADX 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.
+- *
+- */
+-
+-#include <asm/machvec.h>
+-#include <linux/module.h>
+-
+-extern void init_adx_IRQ(void);
+-extern void *cf_io_base;
+-
+-const char *get_system_type(void)
+-{
+- return "A&D ADX";
+-}
+-
+-unsigned long adx_isa_port2addr(unsigned long offset)
+-{
+- /* CompactFlash (IDE) */
+- if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset == 0x3f6)) {
+- return (unsigned long)cf_io_base + offset;
+- }
+-
+- /* eth0 */
+- if ((offset >= 0x300) && (offset <= 0x30f)) {
+- return 0xa5000000 + offset; /* COMM BOARD (AREA1) */
+- }
+-
+- return offset + 0xb0000000; /* IOBUS (AREA 4)*/
+-}
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_adx __initmv = {
+- .mv_nr_irqs = 48,
+- .mv_isa_port2addr = adx_isa_port2addr,
+- .mv_init_irq = init_adx_IRQ,
+-};
+-ALIAS_MV(adx)
+-
+-int __init platform_setup(void)
+-{
+- /* Nothing to see here .. */
+- return 0;
+-}
+-
+diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c
+index 6835381..23071f9 100644
+--- a/arch/sh/boards/bigsur/io.c
++++ b/arch/sh/boards/bigsur/io.c
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-sh/io_bigsur.c
++ * arch/sh/boards/bigsur/io.c
+ *
+ * By Dustin McIntire (dustin at sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+diff --git a/arch/sh/boards/bigsur/irq.c b/arch/sh/boards/bigsur/irq.c
+index ac946a2..1ab04da 100644
+--- a/arch/sh/boards/bigsur/irq.c
++++ b/arch/sh/boards/bigsur/irq.c
+@@ -19,6 +19,7 @@
+ * IRQ functions for a Hitachi Big Sur Evaluation Board.
+ *
+ */
++#undef DEBUG
+
+ #include <linux/sched.h>
+ #include <linux/module.h>
+@@ -41,10 +42,8 @@
+ #undef BIGSUR_DEBUG
+
+ #ifdef BIGSUR_DEBUG
+-#define DPRINTK(args...) printk(args)
+ #define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
+ #else
+-#define DPRINTK(args...)
+ #define DIPRINTK(n, args...)
+ #endif /* BIGSUR_DEBUG */
+
+@@ -60,45 +59,39 @@ extern int hd64465_irq_demux(int irq);
+ /* Level 1 IRQ routines */
+ static void disable_bigsur_l1irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned char mask;
+ unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+ unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+- DPRINTK("Disable L1 IRQ %d\n", irq);
++ pr_debug("Disable L1 IRQ %d\n", irq);
+ DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+- local_irq_save(flags);
+
+ /* Disable IRQ - set mask bit */
+ mask = inb(mask_port) | bit;
+ outb(mask, mask_port);
+- local_irq_restore(flags);
+ return;
+ }
+- DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
++ pr_debug("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+ }
+
+ static void enable_bigsur_l1irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned char mask;
+ unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+ unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+- DPRINTK("Enable L1 IRQ %d\n", irq);
++ pr_debug("Enable L1 IRQ %d\n", irq);
+ DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+- local_irq_save(flags);
+ /* Enable L1 IRQ - clear mask bit */
+ mask = inb(mask_port) & ~bit;
+ outb(mask, mask_port);
+- local_irq_restore(flags);
+ return;
+ }
+- DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
++ pr_debug("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+ }
+
+
+@@ -126,51 +119,45 @@ static const u32 imr_offset = BIGSUR_IMR
+ /* Level 2 IRQ routines */
+ static void disable_bigsur_l2irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned char mask;
+ unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+ unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+- if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+- DPRINTK("Disable L2 IRQ %d\n", irq);
++ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
++ pr_debug("Disable L2 IRQ %d\n", irq);
+ DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+- local_irq_save(flags);
+
+ /* Disable L2 IRQ - set mask bit */
+ mask = inb(mask_port) | bit;
+ outb(mask, mask_port);
+- local_irq_restore(flags);
+ return;
+ }
+- DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
++ pr_debug("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+ }
+
+ static void enable_bigsur_l2irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned char mask;
+ unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+ unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+- if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+- DPRINTK("Enable L2 IRQ %d\n", irq);
++ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
++ pr_debug("Enable L2 IRQ %d\n", irq);
+ DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+- local_irq_save(flags);
+
+ /* Enable L2 IRQ - clear mask bit */
+ mask = inb(mask_port) & ~bit;
+ outb(mask, mask_port);
+- local_irq_restore(flags);
+ return;
+ }
+- DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
++ pr_debug("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+ }
+
+ static void mask_and_ack_bigsur(unsigned int irq)
+ {
+- DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
++ pr_debug("mask_and_ack_bigsur IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ disable_bigsur_l1irq(irq);
+ else
+@@ -179,7 +166,7 @@ static void mask_and_ack_bigsur(unsigned
+
+ static void end_bigsur_irq(unsigned int irq)
+ {
+- DPRINTK("end_bigsur_irq IRQ %d\n", irq);
++ pr_debug("end_bigsur_irq IRQ %d\n", irq);
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ enable_bigsur_l1irq(irq);
+@@ -193,7 +180,7 @@ static unsigned int startup_bigsur_irq(u
+ u8 mask;
+ u32 reg;
+
+- DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
++ pr_debug("startup_bigsur_irq IRQ %d\n", irq);
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* Enable the L1 IRQ */
+@@ -218,7 +205,7 @@ static unsigned int startup_bigsur_irq(u
+
+ static void shutdown_bigsur_irq(unsigned int irq)
+ {
+- DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
++ pr_debug("shutdown_bigsur_irq IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ disable_bigsur_l1irq(irq);
+ else
+@@ -260,7 +247,7 @@ static void make_bigsur_l1isr(unsigned i
+ disable_bigsur_l1irq(irq);
+ return;
+ }
+- DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
++ pr_debug("make_bigsur_l1isr: bad irq, %d\n", irq);
+ return;
+ }
+
+@@ -277,7 +264,7 @@ static void make_bigsur_l2isr(unsigned i
+ disable_bigsur_l2irq(irq);
+ return;
+ }
+- DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
++ pr_debug("make_bigsur_l2isr: bad irq, %d\n", irq);
+ return;
+ }
+
+diff --git a/arch/sh/boards/bigsur/led.c b/arch/sh/boards/bigsur/led.c
+index 6b08c0e..d221439 100644
+--- a/arch/sh/boards/bigsur/led.c
++++ b/arch/sh/boards/bigsur/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/led_bigsur.c
++ * linux/arch/sh/boards/bigsur/led.c
+ *
+ * By Dustin McIntire (dustin at sensoria.com) (c)2001
+ * Derived from led_se.c and led.c, which bore the message:
+diff --git a/arch/sh/boards/bigsur/setup.c b/arch/sh/boards/bigsur/setup.c
+index dfeede9..9711c20 100644
+--- a/arch/sh/boards/bigsur/setup.c
++++ b/arch/sh/boards/bigsur/setup.c
+@@ -41,31 +41,7 @@
+ // Big Sur Init Routines
+ /*===========================================================*/
+
+-const char *get_system_type(void)
+-{
+- return "Big Sur";
+-}
+-
+-/*
+- * The Machine Vector
+- */
+-extern void heartbeat_bigsur(void);
+-extern void init_bigsur_IRQ(void);
+-
+-struct sh_machine_vector mv_bigsur __initmv = {
+- .mv_nr_irqs = NR_IRQS, // Defined in <asm/irq.h>
+-
+- .mv_isa_port2addr = bigsur_isa_port2addr,
+- .mv_irq_demux = bigsur_irq_demux,
+-
+- .mv_init_irq = init_bigsur_IRQ,
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_bigsur,
+-#endif
+-};
+-ALIAS_MV(bigsur)
+-
+-int __init platform_setup(void)
++static void __init bigsur_setup(char **cmdline_p)
+ {
+ /* Mask all 2nd level IRQ's */
+ outb(-1,BIGSUR_IMR0);
+@@ -89,7 +65,24 @@ int __init platform_setup(void)
+ outw(1, BIGSUR_ETHR+0xe);
+ /* set the IO port to BIGSUR_ETHER_IOPORT */
+ outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
+-
+- return 0;
+ }
+
++/*
++ * The Machine Vector
++ */
++extern void heartbeat_bigsur(void);
++extern void init_bigsur_IRQ(void);
++
++struct sh_machine_vector mv_bigsur __initmv = {
++ .mv_name = "Big Sur",
++ .mv_setup = bigsur_setup,
++
++ .mv_isa_port2addr = bigsur_isa_port2addr,
++ .mv_irq_demux = bigsur_irq_demux,
++
++ .mv_init_irq = init_bigsur_IRQ,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_bigsur,
++#endif
++};
++ALIAS_MV(bigsur)
+diff --git a/arch/sh/boards/cat68701/Makefile b/arch/sh/boards/cat68701/Makefile
+deleted file mode 100644
+index 52c1de0..0000000
+--- a/arch/sh/boards/cat68701/Makefile
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#
+-# Makefile for the CAT-68701 specific parts of the kernel
+-#
+-
+-obj-y := setup.o irq.o
+-
+diff --git a/arch/sh/boards/cat68701/irq.c b/arch/sh/boards/cat68701/irq.c
+deleted file mode 100644
+index f9a6d18..0000000
+--- a/arch/sh/boards/cat68701/irq.c
++++ /dev/null
+@@ -1,28 +0,0 @@
+-/*
+- * linux/arch/sh/boards/cat68701/irq.c
+- *
+- * Copyright (C) 2000 Niibe Yutaka
+- * 2001 Yutaro Ebihara
+- *
+- * Setup routines for A-ONE Corp CAT-68701 SH7708 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.
+- *
+- */
+-
+-#include <asm/irq.h>
+-
+-int cat68701_irq_demux(int irq)
+-{
+- if(irq==13) return 14;
+- if(irq==7) return 10;
+- return irq;
+-}
+-
+-void init_cat68701_IRQ()
+-{
+- make_imask_irq(10);
+- make_imask_irq(14);
+-}
+diff --git a/arch/sh/boards/cat68701/setup.c b/arch/sh/boards/cat68701/setup.c
+deleted file mode 100644
+index 90e5175..0000000
+--- a/arch/sh/boards/cat68701/setup.c
++++ /dev/null
+@@ -1,85 +0,0 @@
+-/*
+- * linux/arch/sh/boards/cat68701/setup.c
+- *
+- * Copyright (C) 2000 Niibe Yutaka
+- * 2001 Yutaro Ebihara
+- *
+- * Setup routines for A-ONE Corp CAT-68701 SH7708 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.
+- *
+- */
+-
+-#include <asm/io.h>
+-#include <asm/machvec.h>
+-#include <asm/mach/io.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/sched.h>
+-
+-const char *get_system_type(void)
+-{
+- return "CAT-68701";
+-}
+-
+-#ifdef CONFIG_HEARTBEAT
+-void heartbeat_cat68701()
+-{
+- static unsigned int cnt = 0, period = 0 , bit = 0;
+- cnt += 1;
+- if (cnt < period) {
+- return;
+- }
+- cnt = 0;
+-
+- /* Go through the points (roughly!):
+- * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+- */
+- period = 110 - ( (300<<FSHIFT)/
+- ((avenrun[0]/5) + (3<<FSHIFT)) );
+-
+- if(bit){ bit=0; }else{ bit=1; }
+- outw(bit<<15,0x3fe);
+-}
+-#endif /* CONFIG_HEARTBEAT */
+-
+-unsigned long cat68701_isa_port2addr(unsigned long offset)
+-{
+- /* CompactFlash (IDE) */
+- if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6))
+- return 0xba000000 + offset;
+-
+- /* INPUT PORT */
+- if ((offset >= 0x3fc) && (offset <= 0x3fd))
+- return 0xb4007000 + offset;
+-
+- /* OUTPUT PORT */
+- if ((offset >= 0x3fe) && (offset <= 0x3ff))
+- return 0xb4007400 + offset;
+-
+- return offset + 0xb4000000; /* other I/O (EREA 5)*/
+-}
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_cat68701 __initmv = {
+- .mv_nr_irqs = 32,
+- .mv_isa_port2addr = cat68701_isa_port2addr,
+- .mv_irq_demux = cat68701_irq_demux,
+-
+- .mv_init_irq = init_cat68701_IRQ,
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_cat68701,
+-#endif
+-};
+-ALIAS_MV(cat68701)
+-
+-int __init platform_setup(void)
+-{
+- /* dummy read erea5 (CS8900A) */
+-}
+-
+diff --git a/arch/sh/boards/cqreek/Makefile b/arch/sh/boards/cqreek/Makefile
+deleted file mode 100644
+index 1a788a8..0000000
+--- a/arch/sh/boards/cqreek/Makefile
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#
+-# Makefile for the CqREEK specific parts of the kernel
+-#
+-
+-obj-y := setup.o irq.o
+-
+diff --git a/arch/sh/boards/cqreek/irq.c b/arch/sh/boards/cqreek/irq.c
+deleted file mode 100644
+index 2955adc..0000000
+--- a/arch/sh/boards/cqreek/irq.c
++++ /dev/null
+@@ -1,128 +0,0 @@
+-/* $Id: irq.c,v 1.1.2.4 2002/11/04 20:33:56 lethal Exp $
+- *
+- * arch/sh/boards/cqreek/irq.c
+- *
+- * Copyright (C) 2000 Niibe Yutaka
+- *
+- * CqREEK IDE/ISA Bridge Support.
+- *
+- */
+-
+-#include <linux/irq.h>
+-#include <linux/init.h>
+-
+-#include <asm/cqreek/cqreek.h>
+-#include <asm/io.h>
+-#include <asm/io_generic.h>
+-#include <asm/irq.h>
+-#include <asm/machvec.h>
+-#include <asm/machvec_init.h>
+-#include <asm/rtc.h>
+-
+-struct cqreek_irq_data {
+- unsigned short mask_port; /* Port of Interrupt Mask Register */
+- unsigned short stat_port; /* Port of Interrupt Status Register */
+- unsigned short bit; /* Value of the bit */
+-};
+-static struct cqreek_irq_data cqreek_irq_data[NR_IRQS];
+-
+-static void disable_cqreek_irq(unsigned int irq)
+-{
+- unsigned long flags;
+- unsigned short mask;
+- unsigned short mask_port = cqreek_irq_data[irq].mask_port;
+- unsigned short bit = cqreek_irq_data[irq].bit;
+-
+- local_irq_save(flags);
+- /* Disable IRQ */
+- mask = inw(mask_port) & ~bit;
+- outw_p(mask, mask_port);
+- local_irq_restore(flags);
+-}
+-
+-static void enable_cqreek_irq(unsigned int irq)
+-{
+- unsigned long flags;
+- unsigned short mask;
+- unsigned short mask_port = cqreek_irq_data[irq].mask_port;
+- unsigned short bit = cqreek_irq_data[irq].bit;
+-
+- local_irq_save(flags);
+- /* Enable IRQ */
+- mask = inw(mask_port) | bit;
+- outw_p(mask, mask_port);
+- local_irq_restore(flags);
+-}
+-
+-static void mask_and_ack_cqreek(unsigned int irq)
+-{
+- unsigned short stat_port = cqreek_irq_data[irq].stat_port;
+- unsigned short bit = cqreek_irq_data[irq].bit;
+-
+- disable_cqreek_irq(irq);
+- /* Clear IRQ (it might be edge IRQ) */
+- inw(stat_port);
+- outw_p(bit, stat_port);
+-}
+-
+-static void end_cqreek_irq(unsigned int irq)
+-{
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+- enable_cqreek_irq(irq);
+-}
+-
+-static unsigned int startup_cqreek_irq(unsigned int irq)
+-{
+- enable_cqreek_irq(irq);
+- return 0;
+-}
+-
+-static void shutdown_cqreek_irq(unsigned int irq)
+-{
+- disable_cqreek_irq(irq);
+-}
+-
+-static struct hw_interrupt_type cqreek_irq_type = {
+- .typename = "CqREEK-IRQ",
+- .startup = startup_cqreek_irq,
+- .shutdown = shutdown_cqreek_irq,
+- .enable = enable_cqreek_irq,
+- .disable = disable_cqreek_irq,
+- .ack = mask_and_ack_cqreek,
+- .end = end_cqreek_irq
+-};
+-
+-int cqreek_has_ide, cqreek_has_isa;
+-
+-/* XXX: This is just for test for my NE2000 ISA board
+- What we really need is virtualized IRQ and demultiplexer like HP600 port */
+-void __init init_cqreek_IRQ(void)
+-{
+- if (cqreek_has_ide) {
+- cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK;
+- cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
+- cqreek_irq_data[14].bit = 1;
+-
+- irq_desc[14].chip = &cqreek_irq_type;
+- irq_desc[14].status = IRQ_DISABLED;
+- irq_desc[14].action = 0;
+- irq_desc[14].depth = 1;
+-
+- disable_cqreek_irq(14);
+- }
+-
+- if (cqreek_has_isa) {
+- cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK;
+- cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT;
+- cqreek_irq_data[10].bit = (1 << 10);
+-
+- /* XXX: Err... we may need demultiplexer for ISA irq... */
+- irq_desc[10].chip = &cqreek_irq_type;
+- irq_desc[10].status = IRQ_DISABLED;
+- irq_desc[10].action = 0;
+- irq_desc[10].depth = 1;
+-
+- disable_cqreek_irq(10);
+- }
+-}
+-
+diff --git a/arch/sh/boards/cqreek/setup.c b/arch/sh/boards/cqreek/setup.c
+deleted file mode 100644
+index eff4ed9..0000000
+--- a/arch/sh/boards/cqreek/setup.c
++++ /dev/null
+@@ -1,100 +0,0 @@
+-/* $Id: setup.c,v 1.5 2003/08/04 01:51:58 lethal Exp $
+- *
+- * arch/sh/kernel/setup_cqreek.c
+- *
+- * Copyright (C) 2000 Niibe Yutaka
+- *
+- * CqREEK IDE/ISA Bridge Support.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <asm/mach/cqreek.h>
+-#include <asm/machvec.h>
+-#include <asm/io.h>
+-#include <asm/io_generic.h>
+-#include <asm/irq.h>
+-#include <asm/rtc.h>
+-
+-#define IDE_OFFSET 0xA4000000UL
+-#define ISA_OFFSET 0xA4A00000UL
+-
+-const char *get_system_type(void)
+-{
+- return "CqREEK";
+-}
+-
+-static unsigned long cqreek_port2addr(unsigned long port)
+-{
+- if (0x0000<=port && port<=0x0040)
+- return IDE_OFFSET + port;
+- if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
+- return IDE_OFFSET + port;
+-
+- return ISA_OFFSET + port;
+-}
+-
+-/*
+- * The Machine Vector
+- */
+-struct sh_machine_vector mv_cqreek __initmv = {
+-#if defined(CONFIG_CPU_SH4)
+- .mv_nr_irqs = 48,
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+- .mv_nr_irqs = 32,
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+- .mv_nr_irqs = 61,
+-#endif
+-
+- .mv_init_irq = init_cqreek_IRQ,
+-
+- .mv_isa_port2addr = cqreek_port2addr,
+-};
+-ALIAS_MV(cqreek)
+-
+-/*
+- * Initialize the board
+- */
+-void __init platform_setup(void)
+-{
+- int i;
+-/* udelay is not available at setup time yet... */
+-#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
+-
+- if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
+- outw_p(0, BRIDGE_IDE_INTR_LVL);
+- outw_p(0, BRIDGE_IDE_INTR_MASK);
+-
+- outw_p(0, BRIDGE_IDE_CTRL);
+- DELAY();
+-
+- outw_p(0x8000, BRIDGE_IDE_CTRL);
+- DELAY();
+-
+- outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
+- outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
+- outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
+- cqreek_has_ide=1;
+- }
+-
+- if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
+- outw_p(0, BRIDGE_ISA_INTR_LVL);
+- outw_p(0, BRIDGE_ISA_INTR_MASK);
+-
+- outw_p(0, BRIDGE_ISA_CTRL);
+- DELAY();
+- outw_p(0x8000, BRIDGE_ISA_CTRL);
+- DELAY();
+-
+- outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
+- outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
+- outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
+- cqreek_has_isa=1;
+- }
+-
+- printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", cqreek_has_ide, cqreek_has_isa);
+-}
+-
+diff --git a/arch/sh/boards/dmida/Makefile b/arch/sh/boards/dmida/Makefile
+deleted file mode 100644
+index 75999aa..0000000
+--- a/arch/sh/boards/dmida/Makefile
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#
+-# Makefile for the DataMyte Industrial Digital Assistant(tm) specific parts
+-# of the kernel
+-#
+-
+-obj-y := mach.o
+-
+diff --git a/arch/sh/boards/dmida/mach.c b/arch/sh/boards/dmida/mach.c
+deleted file mode 100644
+index d03a25f..0000000
+--- a/arch/sh/boards/dmida/mach.c
++++ /dev/null
+@@ -1,59 +0,0 @@
+-/*
+- * linux/arch/sh/boards/dmida/mach.c
+- *
+- * by Greg Banks <gbanks at pocketpenguins.com>
+- * (c) 2000 PocketPenguins Inc
+- *
+- * Derived from mach_hp600.c, which bore the message:
+- * Copyright (C) 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the DataMyte Industrial Digital Assistant(tm).
+- * See http://www.dmida.com
+- *
+- */
+-
+-#include <linux/init.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/machvec_init.h>
+-
+-#include <asm/io.h>
+-#include <asm/hd64465/hd64465.h>
+-#include <asm/irq.h>
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_dmida __initmv = {
+- .mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM,
+-
+- .mv_inb = hd64465_inb,
+- .mv_inw = hd64465_inw,
+- .mv_inl = hd64465_inl,
+- .mv_outb = hd64465_outb,
+- .mv_outw = hd64465_outw,
+- .mv_outl = hd64465_outl,
+-
+- .mv_inb_p = hd64465_inb_p,
+- .mv_inw_p = hd64465_inw,
+- .mv_inl_p = hd64465_inl,
+- .mv_outb_p = hd64465_outb_p,
+- .mv_outw_p = hd64465_outw,
+- .mv_outl_p = hd64465_outl,
+-
+- .mv_insb = hd64465_insb,
+- .mv_insw = hd64465_insw,
+- .mv_insl = hd64465_insl,
+- .mv_outsb = hd64465_outsb,
+- .mv_outsw = hd64465_outsw,
+- .mv_outsl = hd64465_outsl,
+-
+- .mv_irq_demux = hd64465_irq_demux,
+-};
+-ALIAS_MV(dmida)
+-
+diff --git a/arch/sh/boards/dreamcast/irq.c b/arch/sh/boards/dreamcast/irq.c
+index b10a6b1..5bf01f8 100644
+--- a/arch/sh/boards/dreamcast/irq.c
++++ b/arch/sh/boards/dreamcast/irq.c
+@@ -10,7 +10,6 @@
+ */
+
+ #include <linux/irq.h>
+-
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/dreamcast/sysasic.h>
+@@ -26,10 +25,10 @@
+ event.
+
+ There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event
+- types can be found in include/asm-sh/dc_sysasic.h. There are three groups
+- of EMRs that parallel the ESRs. Each EMR group corresponds to an IRQ, so
+- 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
+- IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
++ types can be found in include/asm-sh/dreamcast/sysasic.h. There are three
++ groups of EMRs that parallel the ESRs. Each EMR group corresponds to an
++ IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928
++ triggers IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
+
+ In the kernel, these events are mapped to virtual IRQs so that drivers can
+ respond to them as they would a normal interrupt. In order to keep this
+@@ -57,29 +56,23 @@
+ /* Disable the hardware event by masking its bit in its EMR */
+ static inline void disable_systemasic_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+ __u32 mask;
+
+- local_irq_save(flags);
+ mask = inl(emr);
+ mask &= ~(1 << EVENT_BIT(irq));
+ outl(mask, emr);
+- local_irq_restore(flags);
+ }
+
+ /* Enable the hardware event by setting its bit in its EMR */
+ static inline void enable_systemasic_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+ __u32 mask;
+
+- local_irq_save(flags);
+ mask = inl(emr);
+ mask |= (1 << EVENT_BIT(irq));
+ outl(mask, emr);
+- local_irq_restore(flags);
+ }
+
+ /* Acknowledge a hardware event by writing its bit back to its ESR */
+diff --git a/arch/sh/boards/dreamcast/rtc.c b/arch/sh/boards/dreamcast/rtc.c
+index 379de16..b3a876a 100644
+--- a/arch/sh/boards/dreamcast/rtc.c
++++ b/arch/sh/boards/dreamcast/rtc.c
+@@ -1,4 +1,5 @@
+-/* arch/sh/kernel/rtc-aica.c
++/*
++ * arch/sh/boards/dreamcast/rtc.c
+ *
+ * Dreamcast AICA RTC routines.
+ *
+@@ -10,15 +11,12 @@
+ */
+
+ #include <linux/time.h>
+-
++#include <asm/rtc.h>
+ #include <asm/io.h>
+
+-extern void (*rtc_get_time)(struct timespec *);
+-extern int (*rtc_set_time)(const time_t);
+-
+ /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in
+- seconds to get the standard Unix Epoch when getting the time, and add 20
+- years when setting the time. */
++ seconds) to get the standard Unix Epoch when getting the time, and add
++ 20 years when setting the time. */
+ #define TWENTY_YEARS ((20 * 365LU + 5) * 86400)
+
+ /* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit
+@@ -32,7 +30,8 @@ extern int (*rtc_set_time)(const time_t)
+ *
+ * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch.
+ */
+-void aica_rtc_gettimeofday(struct timespec *ts) {
++void aica_rtc_gettimeofday(struct timespec *ts)
++{
+ unsigned long val1, val2;
+
+ do {
+@@ -55,7 +54,8 @@ void aica_rtc_gettimeofday(struct timesp
+ *
+ * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter.
+ */
+-int aica_rtc_settimeofday(const time_t secs) {
++int aica_rtc_settimeofday(const time_t secs)
++{
+ unsigned long val1, val2;
+ unsigned long adj = secs + TWENTY_YEARS;
+
+@@ -75,7 +75,7 @@ int aica_rtc_settimeofday(const time_t s
+
+ void aica_time_init(void)
+ {
+- rtc_get_time = aica_rtc_gettimeofday;
+- rtc_set_time = aica_rtc_settimeofday;
++ rtc_sh_get_time = aica_rtc_gettimeofday;
++ rtc_sh_set_time = aica_rtc_settimeofday;
+ }
+
+diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c
+index 0027b80..f13017e 100644
+--- a/arch/sh/boards/dreamcast/setup.c
++++ b/arch/sh/boards/dreamcast/setup.c
+@@ -22,41 +22,21 @@
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <linux/device.h>
+-
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/rtc.h>
+ #include <asm/machvec.h>
+-#include <asm/machvec_init.h>
+ #include <asm/mach/sysasic.h>
+
+ extern struct hw_interrupt_type systemasic_int;
+-/* XXX: Move this into it's proper header. */
+-extern void (*board_time_init)(void);
+ extern void aica_time_init(void);
+ extern int gapspci_init(void);
+ extern int systemasic_irq_demux(int);
+
+-void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
++void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
+ int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
+
+-const char *get_system_type(void)
+-{
+- return "Sega Dreamcast";
+-}
+-
+-struct sh_machine_vector mv_dreamcast __initmv = {
+- .mv_nr_irqs = NR_IRQS,
+-
+- .mv_irq_demux = systemasic_irq_demux,
+-
+-#ifdef CONFIG_PCI
+- .mv_consistent_alloc = dreamcast_consistent_alloc,
+- .mv_consistent_free = dreamcast_consistent_free,
+-#endif
+-};
+-ALIAS_MV(dreamcast)
+-
+-int __init platform_setup(void)
++static void __init dreamcast_setup(char **cmdline_p)
+ {
+ int i;
+
+@@ -78,6 +58,16 @@ int __init platform_setup(void)
+ if (gapspci_init() < 0)
+ printk(KERN_WARNING "GAPSPCI was not detected.\n");
+ #endif
+-
+- return 0;
+ }
++
++struct sh_machine_vector mv_dreamcast __initmv = {
++ .mv_name = "Sega Dreamcast",
++ .mv_setup = dreamcast_setup,
++ .mv_irq_demux = systemasic_irq_demux,
++
++#ifdef CONFIG_PCI
++ .mv_consistent_alloc = dreamcast_consistent_alloc,
++ .mv_consistent_free = dreamcast_consistent_free,
++#endif
++};
++ALIAS_MV(dreamcast)
+diff --git a/arch/sh/boards/ec3104/io.c b/arch/sh/boards/ec3104/io.c
+index a70928c..2f86394 100644
+--- a/arch/sh/boards/ec3104/io.c
++++ b/arch/sh/boards/ec3104/io.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/io_ec3104.c
++ * linux/arch/sh/boards/ec3104/io.c
+ * EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf at tux.org>
+diff --git a/arch/sh/boards/ec3104/setup.c b/arch/sh/boards/ec3104/setup.c
+index 4b3ef16..902bc97 100644
+--- a/arch/sh/boards/ec3104/setup.c
++++ b/arch/sh/boards/ec3104/setup.c
+@@ -21,22 +21,36 @@
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <linux/types.h>
+-
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/machvec.h>
+ #include <asm/mach/ec3104.h>
+
+-const char *get_system_type(void)
++static void __init ec3104_setup(char **cmdline_p)
+ {
+- return "EC3104";
++ char str[8];
++ int i;
++
++ for (i=0; i<8; i++)
++ str[i] = ctrl_readb(EC3104_BASE + i);
++
++ for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
++ irq_desc[i].handler = &ec3104_int;
++
++ printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
++ str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
++
++ /* mask all interrupts. this should have been done by the boot
++ * loader for us but we want to be sure ... */
++ ctrl_writel(0xffffffff, EC3104_IMR);
+ }
+
+ /*
+ * The Machine Vector
+ */
+-
+ struct sh_machine_vector mv_ec3104 __initmv = {
++ .mv_name = "EC3104",
++ .mv_setup = ec3104_setup,
+ .mv_nr_irqs = 96,
+
+ .mv_inb = ec3104_inb,
+@@ -48,31 +62,4 @@ struct sh_machine_vector mv_ec3104 __ini
+
+ .mv_irq_demux = ec3104_irq_demux,
+ };
+-
+ ALIAS_MV(ec3104)
+-
+-int __init platform_setup(void)
+-{
+- char str[8];
+- int i;
+-
+- if (0)
+- return 0;
+-
+- for (i=0; i<8; i++)
+- str[i] = ctrl_readb(EC3104_BASE + i);
+-
+- for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
+- irq_desc[i].chip = &ec3104_int;
+-
+- printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
+- str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
+-
+-
+- /* mask all interrupts. this should have been done by the boot
+- * loader for us but we want to be sure ... */
+- ctrl_writel(0xffffffff, EC3104_IMR);
+-
+- return 0;
+-}
+-
+diff --git a/arch/sh/boards/harp/Makefile b/arch/sh/boards/harp/Makefile
+deleted file mode 100644
+index eb753d3..0000000
+--- a/arch/sh/boards/harp/Makefile
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#
+-# Makefile for STMicroelectronics board specific parts of the kernel
+-#
+-
+-obj-y := irq.o setup.o mach.o led.o
+-
+-obj-$(CONFIG_PCI) += pcidma.o
+-
+diff --git a/arch/sh/boards/harp/irq.c b/arch/sh/boards/harp/irq.c
+deleted file mode 100644
+index 96bb41c..0000000
+--- a/arch/sh/boards/harp/irq.c
++++ /dev/null
+@@ -1,147 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Looks after interrupts on the HARP board.
+- *
+- * Bases on the IPR irq system
+- */
+-
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/harp/harp.h>
+-
+-
+-#define NUM_EXTERNAL_IRQS 16
+-
+-// Early versions of the STB1 Overdrive required this nasty frig
+-//#define INVERT_INTMASK_WRITES
+-
+-static void enable_harp_irq(unsigned int irq);
+-static void disable_harp_irq(unsigned int irq);
+-
+-/* shutdown is same as "disable" */
+-#define shutdown_harp_irq disable_harp_irq
+-
+-static void mask_and_ack_harp(unsigned int);
+-static void end_harp_irq(unsigned int irq);
+-
+-static unsigned int startup_harp_irq(unsigned int irq)
+-{
+- enable_harp_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static struct hw_interrupt_type harp_irq_type = {
+- .typename = "Harp-IRQ",
+- .startup = startup_harp_irq,
+- .shutdown = shutdown_harp_irq,
+- .enable = enable_harp_irq,
+- .disable = disable_harp_irq,
+- .ack = mask_and_ack_harp,
+- .end = end_harp_irq
+-};
+-
+-static void disable_harp_irq(unsigned int irq)
+-{
+- unsigned val, flags;
+- unsigned maskReg;
+- unsigned mask;
+- int pri;
+-
+- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+- return;
+-
+- pri = 15 - irq;
+-
+- if (pri < 8) {
+- maskReg = EPLD_INTMASK0;
+- } else {
+- maskReg = EPLD_INTMASK1;
+- pri -= 8;
+- }
+-
+- local_irq_save(flags);
+- mask = ctrl_inl(maskReg);
+- mask &= (~(1 << pri));
+-#if defined(INVERT_INTMASK_WRITES)
+- mask ^= 0xff;
+-#endif
+- ctrl_outl(mask, maskReg);
+- local_irq_restore(flags);
+-}
+-
+-static void enable_harp_irq(unsigned int irq)
+-{
+- unsigned flags;
+- unsigned maskReg;
+- unsigned mask;
+- int pri;
+-
+- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+- return;
+-
+- pri = 15 - irq;
+-
+- if (pri < 8) {
+- maskReg = EPLD_INTMASK0;
+- } else {
+- maskReg = EPLD_INTMASK1;
+- pri -= 8;
+- }
+-
+- local_irq_save(flags);
+- mask = ctrl_inl(maskReg);
+-
+-
+- mask |= (1 << pri);
+-
+-#if defined(INVERT_INTMASK_WRITES)
+- mask ^= 0xff;
+-#endif
+- ctrl_outl(mask, maskReg);
+-
+- local_irq_restore(flags);
+-}
+-
+-/* This functions sets the desired irq handler to be an overdrive type */
+-static void __init make_harp_irq(unsigned int irq)
+-{
+- disable_irq_nosync(irq);
+- irq_desc[irq].chip = &harp_irq_type;
+- disable_harp_irq(irq);
+-}
+-
+-static void mask_and_ack_harp(unsigned int irq)
+-{
+- disable_harp_irq(irq);
+-}
+-
+-static void end_harp_irq(unsigned int irq)
+-{
+- enable_harp_irq(irq);
+-}
+-
+-void __init init_harp_irq(void)
+-{
+- int i;
+-
+-#if !defined(INVERT_INTMASK_WRITES)
+- // On the harp these are set to enable an interrupt
+- ctrl_outl(0x00, EPLD_INTMASK0);
+- ctrl_outl(0x00, EPLD_INTMASK1);
+-#else
+- // On the Overdrive the data is inverted before being stored in the reg
+- ctrl_outl(0xff, EPLD_INTMASK0);
+- ctrl_outl(0xff, EPLD_INTMASK1);
+-#endif
+-
+- for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+- make_harp_irq(i);
+- }
+-}
+diff --git a/arch/sh/boards/harp/led.c b/arch/sh/boards/harp/led.c
+deleted file mode 100644
+index aeb7b39..0000000
+--- a/arch/sh/boards/harp/led.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/*
+- * linux/arch/sh/stboards/led.c
+- *
+- * Copyright (C) 2000 Stuart Menefy <stuart.menefy at st.com>
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * This file contains ST40STB1 HARP and compatible code.
+- */
+-
+-#include <asm/io.h>
+-#include <asm/harp/harp.h>
+-
+-/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
+-/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
+-/* Works for HARP and overdrive */
+-static void mach_led(int position, int value)
+-{
+- if (value) {
+- ctrl_outl(EPLD_LED_ON, EPLD_LED);
+- } else {
+- ctrl_outl(EPLD_LED_OFF, EPLD_LED);
+- }
+-}
+-
+-#ifdef CONFIG_HEARTBEAT
+-
+-#include <linux/sched.h>
+-
+-/* acts like an actual heart beat -- ie thump-thump-pause... */
+-void heartbeat_harp(void)
+-{
+- static unsigned cnt = 0, period = 0, dist = 0;
+-
+- if (cnt == 0 || cnt == dist)
+- mach_led( -1, 1);
+- else if (cnt == 7 || cnt == dist+7)
+- mach_led( -1, 0);
+-
+- if (++cnt > period) {
+- cnt = 0;
+- /* The hyperbolic function below modifies the heartbeat period
+- * length in dependency of the current (5min) load. It goes
+- * through the points f(0)=126, f(1)=86, f(5)=51,
+- * f(inf)->30. */
+- period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+- dist = period / 4;
+- }
+-}
+-#endif
+diff --git a/arch/sh/boards/harp/mach.c b/arch/sh/boards/harp/mach.c
+deleted file mode 100644
+index a946dd1..0000000
+--- a/arch/sh/boards/harp/mach.c
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*
+- * linux/arch/sh/boards/harp/mach.c
+- *
+- * Copyright (C) 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the STMicroelectronics STB1 HARP and compatible boards
+- */
+-
+-#include <linux/init.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/machvec_init.h>
+-#include <asm/hd64465/io.h>
+-#include <asm/hd64465/hd64465.h>
+-
+-void setup_harp(void);
+-void init_harp_irq(void);
+-void heartbeat_harp(void);
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_harp __initmv = {
+- .mv_nr_irqs = 89 + HD64465_IRQ_NUM,
+-
+- .mv_inb = hd64465_inb,
+- .mv_inw = hd64465_inw,
+- .mv_inl = hd64465_inl,
+- .mv_outb = hd64465_outb,
+- .mv_outw = hd64465_outw,
+- .mv_outl = hd64465_outl,
+-
+- .mv_inb_p = hd64465_inb_p,
+- .mv_inw_p = hd64465_inw,
+- .mv_inl_p = hd64465_inl,
+- .mv_outb_p = hd64465_outb_p,
+- .mv_outw_p = hd64465_outw,
+- .mv_outl_p = hd64465_outl,
+-
+- .mv_insb = hd64465_insb,
+- .mv_insw = hd64465_insw,
+- .mv_insl = hd64465_insl,
+- .mv_outsb = hd64465_outsb,
+- .mv_outsw = hd64465_outsw,
+- .mv_outsl = hd64465_outsl,
+-
+- .mv_isa_port2addr = hd64465_isa_port2addr,
+-
+-#ifdef CONFIG_PCI
+- .mv_init_irq = init_harp_irq,
+-#endif
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_harp,
+-#endif
+-};
+-
+-ALIAS_MV(harp)
+diff --git a/arch/sh/boards/harp/pcidma.c b/arch/sh/boards/harp/pcidma.c
+deleted file mode 100644
+index 4753113..0000000
+--- a/arch/sh/boards/harp/pcidma.c
++++ /dev/null
+@@ -1,42 +0,0 @@
+-/*
+- * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Dynamic DMA mapping support.
+- */
+-
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/string.h>
+-#include <linux/pci.h>
+-#include <asm/io.h>
+-#include <asm/addrspace.h>
+-
+-
+-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+- dma_addr_t * dma_handle)
+-{
+- void *ret;
+- int gfp = GFP_ATOMIC;
+-
+- ret = (void *) __get_free_pages(gfp, get_order(size));
+-
+- if (ret != NULL) {
+- /* Is it neccessary to do the memset? */
+- memset(ret, 0, size);
+- *dma_handle = virt_to_bus(ret);
+- }
+- /* We must flush the cache before we pass it on to the device */
+- flush_cache_all();
+- return P2SEGADDR(ret);
+-}
+-
+-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+- void *vaddr, dma_addr_t dma_handle)
+-{
+- unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+-
+- free_pages(p1addr, get_order(size));
+-}
+diff --git a/arch/sh/boards/harp/setup.c b/arch/sh/boards/harp/setup.c
+deleted file mode 100644
+index 886e450..0000000
+--- a/arch/sh/boards/harp/setup.c
++++ /dev/null
+@@ -1,90 +0,0 @@
+-/*
+- * arch/sh/stboard/setup.c
+- *
+- * Copyright (C) 2001 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * STMicroelectronics ST40STB1 HARP and compatible support.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <asm/io.h>
+-#include <asm/harp/harp.h>
+-
+-const char *get_system_type(void)
+-{
+- return "STB1 Harp";
+-}
+-
+-/*
+- * Initialize the board
+- */
+-int __init platform_setup(void)
+-{
+-#ifdef CONFIG_SH_STB1_HARP
+- unsigned long ic8_version, ic36_version;
+-
+- ic8_version = ctrl_inl(EPLD_REVID2);
+- ic36_version = ctrl_inl(EPLD_REVID1);
+-
+- printk("STMicroelectronics STB1 HARP initialisaton\n");
+- printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
+- (ic8_version >> 4) & 0xf, ic8_version & 0xf,
+- (ic36_version >> 4) & 0xf, ic36_version & 0xf);
+-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+- unsigned long version;
+-
+- version = ctrl_inl(EPLD_REVID);
+-
+- printk("STMicroelectronics STB1 Overdrive initialisaton\n");
+- printk("EPLD version: %d.%02d\n",
+- (version >> 4) & 0xf, version & 0xf);
+-#else
+-#error Undefined machine
+-#endif
+-
+- /* Currently all STB1 chips have problems with the sleep instruction,
+- * so disable it here.
+- */
+- disable_hlt();
+-
+- return 0;
+-}
+-
+-/*
+- * pcibios_map_platform_irq
+- *
+- * This is board specific and returns the IRQ for a given PCI device.
+- * It is used by the PCI code (arch/sh/kernel/st40_pci*)
+- *
+- */
+-
+-#define HARP_PCI_IRQ 1
+-#define HARP_BRIDGE_IRQ 2
+-#define OVERDRIVE_SLOT0_IRQ 0
+-
+-
+-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- switch (slot) {
+-#ifdef CONFIG_SH_STB1_HARP
+- case 2: /*This is the PCI slot on the */
+- return HARP_PCI_IRQ;
+- case 1: /* this is the bridge */
+- return HARP_BRIDGE_IRQ;
+-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+- case 1:
+- case 2:
+- case 3:
+- return slot - 1;
+-#else
+-#error Unknown board
+-#endif
+- default:
+- return -1;
+- }
+-}
+-
+diff --git a/arch/sh/boards/hp6xx/Makefile b/arch/sh/boards/hp6xx/Makefile
+index 927fe0a..ff1b7f5 100644
+--- a/arch/sh/boards/hp6xx/Makefile
++++ b/arch/sh/boards/hp6xx/Makefile
+@@ -2,5 +2,6 @@
+ # Makefile for the HP6xx specific parts of the kernel
+ #
+
+-obj-y := mach.o setup.o
+-
++obj-y := setup.o
++obj-$(CONFIG_PM) += pm.o pm_wakeup.o
++obj-$(CONFIG_APM) += hp6xx_apm.o
+diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c
+new file mode 100644
+index 0000000..d146cda
+--- /dev/null
++++ b/arch/sh/boards/hp6xx/hp6xx_apm.c
+@@ -0,0 +1,122 @@
++/*
++ * bios-less APM driver for hp680
++ *
++ * Copyright 2005 (c) Andriy Skulysh <askulysh at gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++#include <linux/module.h>
++#include <linux/apm_bios.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <asm/io.h>
++#include <asm/apm.h>
++#include <asm/adc.h>
++#include <asm/hp6xx.h>
++
++#define SH7709_PGDR 0xa400012c
++
++#define APM_CRITICAL 10
++#define APM_LOW 30
++
++#define HP680_BATTERY_MAX 875
++#define HP680_BATTERY_MIN 600
++#define HP680_BATTERY_AC_ON 900
++
++#define MODNAME "hp6x0_apm"
++
++static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
++{
++ u8 pgdr;
++ char *p;
++ int battery_status;
++ int battery_flag;
++ int ac_line_status;
++ int time_units = APM_BATTERY_LIFE_UNKNOWN;
++
++ int battery = adc_single(ADC_CHANNEL_BATTERY);
++ int backup = adc_single(ADC_CHANNEL_BACKUP);
++ int charging = adc_single(ADC_CHANNEL_CHARGE);
++ int percentage;
++
++ percentage = 100 * (battery - HP680_BATTERY_MIN) /
++ (HP680_BATTERY_MAX - HP680_BATTERY_MIN);
++
++ ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
++ APM_AC_ONLINE : APM_AC_OFFLINE;
++
++ p = buf;
++
++ pgdr = ctrl_inb(SH7709_PGDR);
++ if (pgdr & PGDR_MAIN_BATTERY_OUT) {
++ battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
++ battery_flag = 0x80;
++ percentage = -1;
++ } else if (charging < 8 ) {
++ battery_status = APM_BATTERY_STATUS_CHARGING;
++ battery_flag = 0x08;
++ ac_line_status = 0xff;
++ } else if (percentage <= APM_CRITICAL) {
++ battery_status = APM_BATTERY_STATUS_CRITICAL;
++ battery_flag = 0x04;
++ } else if (percentage <= APM_LOW) {
++ battery_status = APM_BATTERY_STATUS_LOW;
++ battery_flag = 0x02;
++ } else {
++ battery_status = APM_BATTERY_STATUS_HIGH;
++ battery_flag = 0x01;
++ }
++
++ p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
++ APM_32_BIT_SUPPORT,
++ ac_line_status,
++ battery_status,
++ battery_flag,
++ percentage,
++ time_units,
++ "min");
++ p += sprintf(p, "bat=%d backup=%d charge=%d\n",
++ battery, backup, charging);
++
++ return p - buf;
++}
++
++static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
++{
++ if (!apm_suspended)
++ apm_queue_event(APM_USER_SUSPEND);
++
++ return IRQ_HANDLED;
++}
++
++static int __init hp6x0_apm_init(void)
++{
++ int ret;
++
++ ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
++ IRQF_DISABLED, MODNAME, 0);
++ if (unlikely(ret < 0)) {
++ printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
++ HP680_BTN_IRQ);
++ return ret;
++ }
++
++ apm_get_info = hp6x0_apm_get_info;
++
++ return ret;
++}
++
++static void __exit hp6x0_apm_exit(void)
++{
++ free_irq(HP680_BTN_IRQ, 0);
++ apm_get_info = 0;
++}
++
++module_init(hp6x0_apm_init);
++module_exit(hp6x0_apm_exit);
++
++MODULE_AUTHOR("Adriy Skulysh");
++MODULE_DESCRIPTION("hp6xx Advanced Power Management");
++MODULE_LICENSE("GPL");
+diff --git a/arch/sh/boards/hp6xx/pm.c b/arch/sh/boards/hp6xx/pm.c
+new file mode 100644
+index 0000000..d194773
+--- /dev/null
++++ b/arch/sh/boards/hp6xx/pm.c
+@@ -0,0 +1,87 @@
++/*
++ * hp6x0 Power Management Routines
++ *
++ * Copyright (c) 2006 Andriy Skulysh <askulsyh at gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++#include <linux/init.h>
++#include <linux/suspend.h>
++#include <linux/errno.h>
++#include <linux/time.h>
++#include <asm/io.h>
++#include <asm/hd64461.h>
++#include <asm/hp6xx.h>
++#include <asm/cpu/dac.h>
++#include <asm/pm.h>
++
++#define STBCR 0xffffff82
++#define STBCR2 0xffffff88
++
++static int hp6x0_pm_enter(suspend_state_t state)
++{
++ u8 stbcr, stbcr2;
++#ifdef CONFIG_HD64461_ENABLER
++ u8 scr;
++ u16 hd64461_stbcr;
++#endif
++
++ if (state != PM_SUSPEND_MEM)
++ return -EINVAL;
++
++#ifdef CONFIG_HD64461_ENABLER
++ outb(0, HD64461_PCC1CSCIER);
++
++ scr = inb(HD64461_PCC1SCR);
++ scr |= HD64461_PCCSCR_VCC1;
++ outb(scr, HD64461_PCC1SCR);
++
++ hd64461_stbcr = inw(HD64461_STBCR);
++ hd64461_stbcr |= HD64461_STBCR_SPC1ST;
++ outw(hd64461_stbcr, HD64461_STBCR);
++#endif
++
++ ctrl_outb(0x1f, DACR);
++
++ stbcr = ctrl_inb(STBCR);
++ ctrl_outb(0x01, STBCR);
++
++ stbcr2 = ctrl_inb(STBCR2);
++ ctrl_outb(0x7f , STBCR2);
++
++ outw(0xf07f, HD64461_SCPUCR);
++
++ pm_enter();
++
++ outw(0, HD64461_SCPUCR);
++ ctrl_outb(stbcr, STBCR);
++ ctrl_outb(stbcr2, STBCR2);
++
++#ifdef CONFIG_HD64461_ENABLER
++ hd64461_stbcr = inw(HD64461_STBCR);
++ hd64461_stbcr &= ~HD64461_STBCR_SPC1ST;
++ outw(hd64461_stbcr, HD64461_STBCR);
++
++ outb(0x4c, HD64461_PCC1CSCIER);
++ outb(0x00, HD64461_PCC1CSCR);
++#endif
++
++ return 0;
++}
++
++/*
++ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
++ */
++static struct pm_ops hp6x0_pm_ops = {
++ .pm_disk_mode = PM_DISK_FIRMWARE,
++ .enter = hp6x0_pm_enter,
++};
++
++static int __init hp6x0_pm_init(void)
++{
++ pm_set_ops(&hp6x0_pm_ops);
++ return 0;
++}
++
++late_initcall(hp6x0_pm_init);
+diff --git a/arch/sh/boards/hp6xx/pm_wakeup.S b/arch/sh/boards/hp6xx/pm_wakeup.S
+new file mode 100644
+index 0000000..45e9bf0
+--- /dev/null
++++ b/arch/sh/boards/hp6xx/pm_wakeup.S
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (c) 2006 Andriy Skulysh <askulsyh at gmail.com>
++ *
++ * 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/linkage.h>
++#include <asm/cpu/mmu_context.h>
++
++#define k0 r0
++#define k1 r1
++#define k2 r2
++#define k3 r3
++#define k4 r4
++
++/*
++ * Kernel mode register usage:
++ * k0 scratch
++ * k1 scratch
++ * k2 scratch (Exception code)
++ * k3 scratch (Return address)
++ * k4 scratch
++ * k5 reserved
++ * k6 Global Interrupt Mask (0--15 << 4)
++ * k7 CURRENT_THREAD_INFO (pointer to current thread info)
++ */
++
++ENTRY(wakeup_start)
++! clear STBY bit
++ mov #-126, k2
++ and #127, k0
++ mov.b k0, @k2
++! enable refresh
++ mov.l 5f, k1
++ mov.w 6f, k0
++ mov.w k0, @k1
++! jump to handler
++ mov.l 2f, k2
++ mov.l 3f, k3
++ mov.l @k2, k2
++
++ mov.l 4f, k1
++ jmp @k1
++ nop
++
++ .align 2
++1: .long EXPEVT
++2: .long INTEVT
++3: .long ret_from_irq
++4: .long handle_exception
++5: .long 0xffffff68
++6: .word 0x0524
++
++ENTRY(wakeup_end)
++ nop
+diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c
+index 71f3156..b5a9664 100644
+--- a/arch/sh/boards/hp6xx/setup.c
++++ b/arch/sh/boards/hp6xx/setup.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/boards/hp6xx/hp680/setup.c
++ * linux/arch/sh/boards/hp6xx/setup.c
+ *
+ * Copyright (C) 2002 Andriy Skulysh
+ *
+@@ -8,22 +8,22 @@
+ *
+ * Setup code for an HP680 (internal peripherials only)
+ */
+-
++#include <linux/types.h>
+ #include <linux/init.h>
+-#include <asm/io.h>
+ #include <asm/hd64461.h>
+-#include <asm/hp6xx/hp6xx.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hp6xx.h>
+ #include <asm/cpu/dac.h>
+
+-const char *get_system_type(void)
+-{
+- return "HP6xx";
+-}
++#define SCPCR 0xa4000116
++#define SCPDR 0xa4000136
+
+-int __init platform_setup(void)
++static void __init hp6xx_setup(char **cmdline_p)
+ {
+ u8 v8;
+ u16 v;
++
+ v = inw(HD64461_STBCR);
+ v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
+ HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
+@@ -50,5 +50,51 @@ int __init platform_setup(void)
+ v8 &= ~DACR_DAE;
+ ctrl_outb(v8,DACR);
+
+- return 0;
++ v8 = ctrl_inb(SCPDR);
++ v8 |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
++ v8 &= ~SCPDR_TS_SCAN_ENABLE;
++ ctrl_outb(v8, SCPDR);
++
++ v = ctrl_inw(SCPCR);
++ v &= ~SCPCR_TS_MASK;
++ v |= SCPCR_TS_ENABLE;
++ ctrl_outw(v, SCPCR);
+ }
++
++/*
++ * XXX: This is stupid, we should have a generic machine vector for the cchips
++ * and just wrap the platform setup code in to this, as it's the only thing
++ * that ends up being different.
++ */
++struct sh_machine_vector mv_hp6xx __initmv = {
++ .mv_name = "hp6xx",
++ .mv_setup = hp6xx_setup,
++ .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
++
++ .mv_inb = hd64461_inb,
++ .mv_inw = hd64461_inw,
++ .mv_inl = hd64461_inl,
++ .mv_outb = hd64461_outb,
++ .mv_outw = hd64461_outw,
++ .mv_outl = hd64461_outl,
++
++ .mv_inb_p = hd64461_inb_p,
++ .mv_inw_p = hd64461_inw,
++ .mv_inl_p = hd64461_inl,
++ .mv_outb_p = hd64461_outb_p,
++ .mv_outw_p = hd64461_outw,
++ .mv_outl_p = hd64461_outl,
++
++ .mv_insb = hd64461_insb,
++ .mv_insw = hd64461_insw,
++ .mv_insl = hd64461_insl,
++ .mv_outsb = hd64461_outsb,
++ .mv_outsw = hd64461_outsw,
++ .mv_outsl = hd64461_outsl,
++
++ .mv_readw = hd64461_readw,
++ .mv_writew = hd64461_writew,
++
++ .mv_irq_demux = hd64461_irq_demux,
++};
++ALIAS_MV(hp6xx)
+diff --git a/arch/sh/boards/landisk/Makefile b/arch/sh/boards/landisk/Makefile
+new file mode 100644
+index 0000000..89e4beb
+--- /dev/null
++++ b/arch/sh/boards/landisk/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for I-O DATA DEVICE, INC. "LANDISK Series"
++#
++
++obj-y := setup.o io.o irq.o rtc.o landisk_pwb.o
+diff --git a/arch/sh/boards/landisk/io.c b/arch/sh/boards/landisk/io.c
+new file mode 100644
+index 0000000..92498b4
+--- /dev/null
++++ b/arch/sh/boards/landisk/io.c
+@@ -0,0 +1,250 @@
++/*
++ * arch/sh/boards/landisk/io.c
++ *
++ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
++ * Based largely on io_se.c.
++ *
++ * I/O routine for I-O Data Device, Inc. LANDISK.
++ *
++ * Initial version only to support LAN access; some
++ * placeholder code from io_landisk.c left in with the
++ * expectation of later SuperIO and PCMCIA access.
++ */
++/*
++ * modifed by kogiidena
++ * 2005.03.03
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <asm/landisk/iodata_landisk.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++
++extern void *area5_io_base; /* Area 5 I/O Base address */
++extern void *area6_io_base; /* Area 6 I/O Base address */
++
++static inline unsigned long port2adr(unsigned int port)
++{
++ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
++ if (port == 0x3f6)
++ return ((unsigned long)area5_io_base + 0x2c);
++ else
++ return ((unsigned long)area5_io_base + PA_PIDE_OFFSET +
++ ((port - 0x1f0) << 1));
++ else if ((0x170 <= port && port < 0x178) || port == 0x376)
++ if (port == 0x376)
++ return ((unsigned long)area6_io_base + 0x2c);
++ else
++ return ((unsigned long)area6_io_base + PA_SIDE_OFFSET +
++ ((port - 0x170) << 1));
++ else
++ maybebadio((unsigned long)port);
++
++ return port;
++}
++
++/*
++ * General outline: remap really low stuff [eventually] to SuperIO,
++ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
++ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
++ * should be way beyond the window, and is used w/o translation for
++ * compatibility.
++ */
++u8 landisk_inb(unsigned long port)
++{
++ if (PXSEG(port))
++ return ctrl_inb(port);
++ else if (is_pci_ioaddr(port))
++ return ctrl_inb(pci_ioaddr(port));
++
++ return ctrl_inw(port2adr(port)) & 0xff;
++}
++
++u8 landisk_inb_p(unsigned long port)
++{
++ u8 v;
++
++ if (PXSEG(port))
++ v = ctrl_inb(port);
++ else if (is_pci_ioaddr(port))
++ v = ctrl_inb(pci_ioaddr(port));
++ else
++ v = ctrl_inw(port2adr(port)) & 0xff;
++
++ ctrl_delay();
++
++ return v;
++}
++
++u16 landisk_inw(unsigned long port)
++{
++ if (PXSEG(port))
++ return ctrl_inw(port);
++ else if (is_pci_ioaddr(port))
++ return ctrl_inw(pci_ioaddr(port));
++ else
++ maybebadio(port);
++
++ return 0;
++}
++
++u32 landisk_inl(unsigned long port)
++{
++ if (PXSEG(port))
++ return ctrl_inl(port);
++ else if (is_pci_ioaddr(port))
++ return ctrl_inl(pci_ioaddr(port));
++ else
++ maybebadio(port);
++
++ return 0;
++}
++
++void landisk_outb(u8 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outb(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outb(value, pci_ioaddr(port));
++ else
++ ctrl_outw(value, port2adr(port));
++}
++
++void landisk_outb_p(u8 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outb(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outb(value, pci_ioaddr(port));
++ else
++ ctrl_outw(value, port2adr(port));
++ ctrl_delay();
++}
++
++void landisk_outw(u16 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outw(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outw(value, pci_ioaddr(port));
++ else
++ maybebadio(port);
++}
++
++void landisk_outl(u32 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outl(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outl(value, pci_ioaddr(port));
++ else
++ maybebadio(port);
++}
++
++void landisk_insb(unsigned long port, void *dst, unsigned long count)
++{
++ volatile u16 *p;
++ u8 *buf = dst;
++
++ if (PXSEG(port)) {
++ while (count--)
++ *buf++ = *(volatile u8 *)port;
++ } else if (is_pci_ioaddr(port)) {
++ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
++
++ while (count--)
++ *buf++ = *bp;
++ } else {
++ p = (volatile u16 *)port2adr(port);
++ while (count--)
++ *buf++ = *p & 0xff;
++ }
++}
++
++void landisk_insw(unsigned long port, void *dst, unsigned long count)
++{
++ volatile u16 *p;
++ u16 *buf = dst;
++
++ if (PXSEG(port))
++ p = (volatile u16 *)port;
++ else if (is_pci_ioaddr(port))
++ p = (volatile u16 *)pci_ioaddr(port);
++ else
++ p = (volatile u16 *)port2adr(port);
++ while (count--)
++ *buf++ = *p;
++}
++
++void landisk_insl(unsigned long port, void *dst, unsigned long count)
++{
++ u32 *buf = dst;
++
++ if (is_pci_ioaddr(port)) {
++ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
++
++ while (count--)
++ *buf++ = *p;
++ } else
++ maybebadio(port);
++}
++
++void landisk_outsb(unsigned long port, const void *src, unsigned long count)
++{
++ volatile u16 *p;
++ const u8 *buf = src;
++
++ if (PXSEG(port))
++ while (count--)
++ ctrl_outb(*buf++, port);
++ else if (is_pci_ioaddr(port)) {
++ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
++
++ while (count--)
++ *bp = *buf++;
++ } else {
++ p = (volatile u16 *)port2adr(port);
++ while (count--)
++ *p = *buf++;
++ }
++}
++
++void landisk_outsw(unsigned long port, const void *src, unsigned long count)
++{
++ volatile u16 *p;
++ const u16 *buf = src;
++
++ if (PXSEG(port))
++ p = (volatile u16 *)port;
++ else if (is_pci_ioaddr(port))
++ p = (volatile u16 *)pci_ioaddr(port);
++ else
++ p = (volatile u16 *)port2adr(port);
++
++ while (count--)
++ *p = *buf++;
++}
++
++void landisk_outsl(unsigned long port, const void *src, unsigned long count)
++{
++ const u32 *buf = src;
++
++ if (is_pci_ioaddr(port)) {
++ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
++
++ while (count--)
++ *p = *buf++;
++ } else
++ maybebadio(port);
++}
++
++void __iomem *landisk_ioport_map(unsigned long port, unsigned int size)
++{
++ if (PXSEG(port))
++ return (void __iomem *)port;
++ else if (is_pci_ioaddr(port))
++ return (void __iomem *)pci_ioaddr(port);
++
++ return (void __iomem *)port2adr(port);
++}
+diff --git a/arch/sh/boards/landisk/irq.c b/arch/sh/boards/landisk/irq.c
+new file mode 100644
+index 0000000..8f2e1c6
+--- /dev/null
++++ b/arch/sh/boards/landisk/irq.c
+@@ -0,0 +1,97 @@
++/*
++ * arch/sh/boards/landisk/irq.c
++ *
++ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
++ * Based largely on io_se.c.
++ *
++ * I/O routine for I-O Data Device, Inc. LANDISK.
++ *
++ * Initial version only to support LAN access; some
++ * placeholder code from io_landisk.c left in with the
++ * expectation of later SuperIO and PCMCIA access.
++ */
++/*
++ * modified by kogiidena
++ * 2005.03.03
++ */
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/landisk/iodata_landisk.h>
++
++static void enable_landisk_irq(unsigned int irq);
++static void disable_landisk_irq(unsigned int irq);
++
++/* shutdown is same as "disable" */
++#define shutdown_landisk_irq disable_landisk_irq
++
++static void ack_landisk_irq(unsigned int irq);
++static void end_landisk_irq(unsigned int irq);
++
++static unsigned int startup_landisk_irq(unsigned int irq)
++{
++ enable_landisk_irq(irq);
++ return 0; /* never anything pending */
++}
++
++static void disable_landisk_irq(unsigned int irq)
++{
++ unsigned char val;
++ unsigned char mask = 0xff ^ (0x01 << (irq - 5));
++
++ /* Set the priority in IPR to 0 */
++ val = ctrl_inb(PA_IMASK);
++ val &= mask;
++ ctrl_outb(val, PA_IMASK);
++}
++
++static void enable_landisk_irq(unsigned int irq)
++{
++ unsigned char val;
++ unsigned char value = (0x01 << (irq - 5));
++
++ /* Set priority in IPR back to original value */
++ val = ctrl_inb(PA_IMASK);
++ val |= value;
++ ctrl_outb(val, PA_IMASK);
++}
++
++static void ack_landisk_irq(unsigned int irq)
++{
++ disable_landisk_irq(irq);
++}
++
++static void end_landisk_irq(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
++ enable_landisk_irq(irq);
++}
++
++static struct hw_interrupt_type landisk_irq_type = {
++ .typename = "LANDISK IRQ",
++ .startup = startup_landisk_irq,
++ .shutdown = shutdown_landisk_irq,
++ .enable = enable_landisk_irq,
++ .disable = disable_landisk_irq,
++ .ack = ack_landisk_irq,
++ .end = end_landisk_irq
++};
++
++static void make_landisk_irq(unsigned int irq)
++{
++ disable_irq_nosync(irq);
++ irq_desc[irq].chip = &landisk_irq_type;
++ disable_landisk_irq(irq);
++}
++
++/*
++ * Initialize IRQ setting
++ */
++void __init init_landisk_IRQ(void)
++{
++ int i;
++
++ for (i = 5; i < 14; i++)
++ make_landisk_irq(i);
++}
+diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c
+new file mode 100644
+index 0000000..e625249
+--- /dev/null
++++ b/arch/sh/boards/landisk/landisk_pwb.c
+@@ -0,0 +1,346 @@
++/*
++ * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch.
++ *
++ * This driver will also support the I-O DATA Device, Inc. LANDISK 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.
++ *
++ * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
++ *
++ * LED control drive function added by kogiidena
++ */
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/major.h>
++#include <linux/poll.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/landisk/iodata_landisk.h>
++
++#define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */
++#define LED_MINOR 21 /* LED minor no. */
++#define BTN_MINOR 22 /* BUTTON minor no. */
++#define GIO_MINOR 40 /* GIO minor no. */
++
++static int openCnt;
++static int openCntLED;
++static int openCntGio;
++static int openCntBtn;
++static int landisk_btn;
++static int landisk_btnctrlpid;
++/*
++ * Functions prototypes
++ */
++
++static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++ unsigned long arg);
++
++static int swdrv_open(struct inode *inode, struct file *filp)
++{
++ int minor;
++
++ minor = MINOR(inode->i_rdev);
++ filp->private_data = (void *)minor;
++
++ if (minor == SHUTDOWN_BTN_MINOR) {
++ if (openCnt > 0) {
++ return -EALREADY;
++ } else {
++ openCnt++;
++ return 0;
++ }
++ } else if (minor == LED_MINOR) {
++ if (openCntLED > 0) {
++ return -EALREADY;
++ } else {
++ openCntLED++;
++ return 0;
++ }
++ } else if (minor == BTN_MINOR) {
++ if (openCntBtn > 0) {
++ return -EALREADY;
++ } else {
++ openCntBtn++;
++ return 0;
++ }
++ } else if (minor == GIO_MINOR) {
++ if (openCntGio > 0) {
++ return -EALREADY;
++ } else {
++ openCntGio++;
++ return 0;
++ }
++ }
++ return -ENOENT;
++
++}
++
++static int swdrv_close(struct inode *inode, struct file *filp)
++{
++ int minor;
++
++ minor = MINOR(inode->i_rdev);
++ if (minor == SHUTDOWN_BTN_MINOR) {
++ openCnt--;
++ } else if (minor == LED_MINOR) {
++ openCntLED--;
++ } else if (minor == BTN_MINOR) {
++ openCntBtn--;
++ } else if (minor == GIO_MINOR) {
++ openCntGio--;
++ }
++ return 0;
++}
++
++static int swdrv_read(struct file *filp, char *buff, size_t count,
++ loff_t * ppos)
++{
++ int minor;
++ minor = (int)(filp->private_data);
++
++ if (!access_ok(VERIFY_WRITE, (void *)buff, count))
++ return -EFAULT;
++
++ if (minor == SHUTDOWN_BTN_MINOR) {
++ if (landisk_btn & 0x10) {
++ put_user(1, buff);
++ return 1;
++ } else {
++ return 0;
++ }
++ }
++ return 0;
++}
++
++static int swdrv_write(struct file *filp, const char *buff, size_t count,
++ loff_t * ppos)
++{
++ int minor;
++ minor = (int)(filp->private_data);
++
++ if (minor == SHUTDOWN_BTN_MINOR) {
++ return count;
++ }
++ return count;
++}
++
++static irqreturn_t sw_interrupt(int irq, void *dev_id)
++{
++ landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));
++ disable_irq(IRQ_BUTTON);
++ disable_irq(IRQ_POWER);
++ ctrl_outb(0x00, PA_PWRINT_CLR);
++
++ if (landisk_btnctrlpid != 0) {
++ kill_proc(landisk_btnctrlpid, SIGUSR1, 1);
++ landisk_btnctrlpid = 0;
++ }
++
++ return IRQ_HANDLED;
++}
++
++static struct file_operations swdrv_fops = {
++ .read = swdrv_read, /* read */
++ .write = swdrv_write, /* write */
++ .open = swdrv_open, /* open */
++ .release = swdrv_close, /* release */
++ .ioctl = gio_ioctl, /* ioctl */
++
++};
++
++static char banner[] __initdata =
++ KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n";
++
++int __init swdrv_init(void)
++{
++ int error;
++
++ printk("%s", banner);
++
++ openCnt = 0;
++ openCntLED = 0;
++ openCntBtn = 0;
++ openCntGio = 0;
++ landisk_btn = 0;
++ landisk_btnctrlpid = 0;
++
++ if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) {
++ printk(KERN_ERR
++ "Button, LED and GIO driver:Couldn't register driver, error=%d\n",
++ error);
++ return 1;
++ }
++
++ if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
++ printk(KERN_ERR "Unable to get IRQ 11.\n");
++ return 1;
++ }
++ if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
++ printk(KERN_ERR "Unable to get IRQ 12.\n");
++ return 1;
++ }
++ ctrl_outb(0x00, PA_PWRINT_CLR);
++
++ return 0;
++}
++
++module_init(swdrv_init);
++
++/*
++ * gio driver
++ *
++ */
++
++#include <asm/landisk/gio.h>
++
++static int gio_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ int minor;
++ unsigned int data, mask;
++ static unsigned int addr = 0;
++
++ minor = (int)(filp->private_data);
++
++ /* access control */
++ if (minor == GIO_MINOR) {
++ ;
++ } else if (minor == LED_MINOR) {
++ if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) {
++ ;
++ } else {
++ return -EINVAL;
++ }
++ } else if (minor == BTN_MINOR) {
++ if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) {
++ ;
++ } else {
++ return -EINVAL;
++ }
++ } else {
++ return -EINVAL;
++ }
++
++ if (cmd & 0x01) { /* write */
++ if (copy_from_user(&data, (int *)arg, sizeof(int))) {
++ return -EFAULT;
++ }
++ }
++
++ switch (cmd) {
++ case GIODRV_IOCSGIOSETADDR: /* addres set */
++ addr = data;
++ break;
++
++ case GIODRV_IOCSGIODATA1: /* write byte */
++ ctrl_outb((unsigned char)(0x0ff & data), addr);
++ break;
++
++ case GIODRV_IOCSGIODATA2: /* write word */
++ if (addr & 0x01) {
++ return -EFAULT;
++ }
++ ctrl_outw((unsigned short int)(0x0ffff & data), addr);
++ break;
++
++ case GIODRV_IOCSGIODATA4: /* write long */
++ if (addr & 0x03) {
++ return -EFAULT;
++ }
++ ctrl_outl(data, addr);
++ break;
++
++ case GIODRV_IOCGGIODATA1: /* read byte */
++ data = ctrl_inb(addr);
++ break;
++
++ case GIODRV_IOCGGIODATA2: /* read word */
++ if (addr & 0x01) {
++ return -EFAULT;
++ }
++ data = ctrl_inw(addr);
++ break;
++
++ case GIODRV_IOCGGIODATA4: /* read long */
++ if (addr & 0x03) {
++ return -EFAULT;
++ }
++ data = ctrl_inl(addr);
++ break;
++ case GIODRV_IOCSGIO_LED: /* write */
++ mask = ((data & 0x00ffffff) << 8)
++ | ((data & 0x0000ffff) << 16)
++ | ((data & 0x000000ff) << 24);
++ landisk_ledparam = data & (~mask);
++ if (landisk_arch == 0) { /* arch == landisk */
++ landisk_ledparam &= 0x03030303;
++ mask = (~(landisk_ledparam >> 22)) & 0x000c;
++ landisk_ledparam |= mask;
++ } else { /* arch == usl-5p */
++ mask = (landisk_ledparam >> 24) & 0x0001;
++ landisk_ledparam |= mask;
++ landisk_ledparam &= 0x007f7f7f;
++ }
++ landisk_ledparam |= 0x80;
++ break;
++ case GIODRV_IOCGGIO_LED: /* read */
++ data = landisk_ledparam;
++ if (landisk_arch == 0) { /* arch == landisk */
++ data &= 0x03030303;
++ } else { /* arch == usl-5p */
++ ;
++ }
++ data &= (~0x080);
++ break;
++ case GIODRV_IOCSGIO_BUZZER: /* write */
++ landisk_buzzerparam = data;
++ landisk_ledparam |= 0x80;
++ break;
++ case GIODRV_IOCGGIO_LANDISK: /* read */
++ data = landisk_arch & 0x01;
++ break;
++ case GIODRV_IOCGGIO_BTN: /* read */
++ data = (0x0ff & ctrl_inb(PA_PWRINT_CLR));
++ data <<= 8;
++ data |= (0x0ff & ctrl_inb(PA_IMASK));
++ data <<= 8;
++ data |= (0x0ff & landisk_btn);
++ data <<= 8;
++ data |= (0x0ff & (~ctrl_inb(PA_STATUS)));
++ break;
++ case GIODRV_IOCSGIO_BTNPID: /* write */
++ landisk_btnctrlpid = data;
++ landisk_btn = 0;
++ if (irq_desc[IRQ_BUTTON].depth) {
++ enable_irq(IRQ_BUTTON);
++ }
++ if (irq_desc[IRQ_POWER].depth) {
++ enable_irq(IRQ_POWER);
++ }
++ break;
++ case GIODRV_IOCGGIO_BTNPID: /* read */
++ data = landisk_btnctrlpid;
++ break;
++ default:
++ return -EFAULT;
++ break;
++ }
++
++ if ((cmd & 0x01) == 0) { /* read */
++ if (copy_to_user((int *)arg, &data, sizeof(int))) {
++ return -EFAULT;
++ }
++ }
++ return 0;
++}
+diff --git a/arch/sh/boards/landisk/rtc.c b/arch/sh/boards/landisk/rtc.c
+new file mode 100644
+index 0000000..0a9a2a2
+--- /dev/null
++++ b/arch/sh/boards/landisk/rtc.c
+@@ -0,0 +1,91 @@
++/*
++ * arch/sh/boards/landisk/rtc.c -- RTC support
++ *
++ * Copyright (C) 2000 Philipp Rumpf <prumpf at tux.org>
++ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
++ */
++/*
++ * modifed by kogiidena
++ * 2005.09.16
++ */
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/bcd.h>
++#include <asm/rtc.h>
++
++extern spinlock_t rtc_lock;
++
++extern void
++rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon,
++ unsigned int BCD_day, unsigned int BCD_hr,
++ unsigned int BCD_min, unsigned int BCD_sec);
++
++extern unsigned long
++rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon,
++ unsigned int *BCD_day, unsigned int *BCD_hr,
++ unsigned int *BCD_min, unsigned int *BCD_sec);
++
++void landisk_rtc_gettimeofday(struct timespec *tv)
++{
++ unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
++ unsigned long flags;
++
++ spin_lock_irqsave(&rtc_lock, flags);
++ tv->tv_sec = rs5c313_get_cmos_time
++ (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
++ tv->tv_nsec = 0;
++ spin_unlock_irqrestore(&rtc_lock, flags);
++}
++
++int landisk_rtc_settimeofday(const time_t secs)
++{
++ int retval = 0;
++ int real_seconds, real_minutes, cmos_minutes;
++ unsigned long flags;
++ unsigned long nowtime = secs;
++ unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
++
++ spin_lock_irqsave(&rtc_lock, flags);
++
++ rs5c313_get_cmos_time
++ (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
++ cmos_minutes = BCD_min;
++ BCD_TO_BIN(cmos_minutes);
++
++ /*
++ * since we're only adjusting minutes and seconds,
++ * don't interfere with hour overflow. This avoids
++ * messing with unknown time zones but requires your
++ * RTC not to be off by more than 15 minutes
++ */
++ real_seconds = nowtime % 60;
++ real_minutes = nowtime / 60;
++ if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
++ real_minutes += 30; /* correct for half hour time zone */
++ real_minutes %= 60;
++
++ if (abs(real_minutes - cmos_minutes) < 30) {
++ BIN_TO_BCD(real_seconds);
++ BIN_TO_BCD(real_minutes);
++ rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr,
++ real_minutes, real_seconds);
++ } else {
++ printk(KERN_WARNING
++ "set_rtc_time: can't update from %d to %d\n",
++ cmos_minutes, real_minutes);
++ retval = -1;
++ }
++
++ spin_unlock_irqrestore(&rtc_lock, flags);
++ return retval;
++}
++
++void landisk_time_init(void)
++{
++ rtc_sh_get_time = landisk_rtc_gettimeofday;
++ rtc_sh_set_time = landisk_rtc_settimeofday;
++}
+diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c
+new file mode 100644
+index 0000000..122d699
+--- /dev/null
++++ b/arch/sh/boards/landisk/setup.c
+@@ -0,0 +1,176 @@
++/*
++ * arch/sh/boards/landisk/setup.c
++ *
++ * Copyright (C) 2000 Kazumoto Kojima
++ * Copyright (C) 2002 Paul Mundt
++ *
++ * I-O DATA Device, Inc. LANDISK Support.
++ *
++ * Modified for LANDISK by
++ * Atom Create Engineering Co., Ltd. 2002.
++ *
++ * modifed by kogiidena
++ * 2005.09.16
++ *
++ * 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/init.h>
++#include <linux/pm.h>
++#include <linux/mm.h>
++#include <asm/machvec.h>
++#include <asm/rtc.h>
++#include <asm/landisk/iodata_landisk.h>
++#include <asm/io.h>
++
++void landisk_time_init(void);
++void init_landisk_IRQ(void);
++
++int landisk_ledparam;
++int landisk_buzzerparam;
++int landisk_arch;
++
++/* cycle the led's in the clasic knightrider/sun pattern */
++static void heartbeat_landisk(void)
++{
++ static unsigned int cnt = 0, blink = 0x00, period = 25;
++ volatile u8 *p = (volatile u8 *)PA_LED;
++ char data;
++
++ if ((landisk_ledparam & 0x080) == 0)
++ return;
++
++ cnt += 1;
++
++ if (cnt < period)
++ return;
++
++ cnt = 0;
++ blink++;
++
++ data = (blink & 0x01) ? (landisk_ledparam >> 16) : 0;
++ data |= (blink & 0x02) ? (landisk_ledparam >> 8) : 0;
++ data |= landisk_ledparam;
++
++ /* buzzer */
++ if (landisk_buzzerparam & 0x1) {
++ data |= 0x80;
++ } else {
++ data &= 0x7f;
++ }
++ *p = data;
++
++ if (((landisk_ledparam & 0x007f7f00) == 0) &&
++ (landisk_buzzerparam == 0))
++ landisk_ledparam &= (~0x0080);
++
++ landisk_buzzerparam >>= 1;
++}
++
++static void landisk_power_off(void)
++{
++ ctrl_outb(0x01, PA_SHUTDOWN);
++}
++
++static void check_usl5p(void)
++{
++ volatile u8 *p = (volatile u8 *)PA_LED;
++ u8 tmp1, tmp2;
++
++ tmp1 = *p;
++ *p = 0x40;
++ tmp2 = *p;
++ *p = tmp1;
++
++ landisk_arch = (tmp2 == 0x40);
++ if (landisk_arch == 1) {
++ /* arch == usl-5p */
++ landisk_ledparam = 0x00000380;
++ landisk_ledparam |= (tmp1 & 0x07c);
++ } else {
++ /* arch == landisk */
++ landisk_ledparam = 0x02000180;
++ landisk_ledparam |= 0x04;
++ }
++}
++
++void *area5_io_base;
++void *area6_io_base;
++
++static int __init landisk_cf_init(void)
++{
++ pgprot_t prot;
++ unsigned long paddrbase, psize;
++
++ /* open I/O area window */
++ paddrbase = virt_to_phys((void *)PA_AREA5_IO);
++ psize = PAGE_SIZE;
++ prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16);
++ area5_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
++ if (!area5_io_base) {
++ printk("allocate_cf_area : can't open CF I/O window!\n");
++ return -ENOMEM;
++ }
++
++ paddrbase = virt_to_phys((void *)PA_AREA6_IO);
++ psize = PAGE_SIZE;
++ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
++ area6_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
++ if (!area6_io_base) {
++ printk("allocate_cf_area : can't open HDD I/O window!\n");
++ return -ENOMEM;
++ }
++
++ printk(KERN_INFO "Allocate Area5/6 success.\n");
++
++ /* XXX : do we need attribute and common-memory area also? */
++
++ return 0;
++}
++
++static void __init landisk_setup(char **cmdline_p)
++{
++ device_initcall(landisk_cf_init);
++
++ landisk_buzzerparam = 0;
++ check_usl5p();
++
++ printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n");
++
++ board_time_init = landisk_time_init;
++ pm_power_off = landisk_power_off;
++}
++
++/*
++ * The Machine Vector
++ */
++struct sh_machine_vector mv_landisk __initmv = {
++ .mv_name = "LANDISK",
++ .mv_setup = landisk_setup,
++ .mv_nr_irqs = 72,
++ .mv_inb = landisk_inb,
++ .mv_inw = landisk_inw,
++ .mv_inl = landisk_inl,
++ .mv_outb = landisk_outb,
++ .mv_outw = landisk_outw,
++ .mv_outl = landisk_outl,
++ .mv_inb_p = landisk_inb_p,
++ .mv_inw_p = landisk_inw,
++ .mv_inl_p = landisk_inl,
++ .mv_outb_p = landisk_outb_p,
++ .mv_outw_p = landisk_outw,
++ .mv_outl_p = landisk_outl,
++ .mv_insb = landisk_insb,
++ .mv_insw = landisk_insw,
++ .mv_insl = landisk_insl,
++ .mv_outsb = landisk_outsb,
++ .mv_outsw = landisk_outsw,
++ .mv_outsl = landisk_outsl,
++ .mv_ioport_map = landisk_ioport_map,
++ .mv_init_irq = init_landisk_IRQ,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_landisk,
++#endif
++};
++ALIAS_MV(landisk)
+diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c
+index 1fe3692..8df1591 100644
+--- a/arch/sh/boards/mpc1211/led.c
++++ b/arch/sh/boards/mpc1211/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/led_mpc1211.c
++ * linux/arch/sh/boards/mpc1211/led.c
+ *
+ * Copyright (C) 2001 Saito.K & Jeanne
+ *
+diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c
+index a76c655..03b123a 100644
+--- a/arch/sh/boards/mpc1211/rtc.c
++++ b/arch/sh/boards/mpc1211/rtc.c
+@@ -130,7 +130,7 @@ int mpc1211_rtc_settimeofday(const struc
+
+ void mpc1211_time_init(void)
+ {
+- rtc_get_time = mpc1211_rtc_gettimeofday;
+- rtc_set_time = mpc1211_rtc_settimeofday;
++ rtc_sh_get_time = mpc1211_rtc_gettimeofday;
++ rtc_sh_set_time = mpc1211_rtc_settimeofday;
+ }
+
+diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c
+index 2bfb221..7c3d1d3 100644
+--- a/arch/sh/boards/mpc1211/setup.c
++++ b/arch/sh/boards/mpc1211/setup.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/board/mpc1211/setup.c
++ * linux/arch/sh/boards/mpc1211/setup.c
+ *
+ * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y
+ *
+@@ -10,14 +10,12 @@
+ #include <linux/hdreg.h>
+ #include <linux/ide.h>
+ #include <linux/interrupt.h>
+-
+ #include <asm/io.h>
+ #include <asm/machvec.h>
+ #include <asm/mpc1211/mpc1211.h>
+ #include <asm/mpc1211/pci.h>
+ #include <asm/mpc1211/m1543c.h>
+
+-
+ /* ALI15X3 SMBus address offsets */
+ #define SMBHSTSTS (0 + 0x3100)
+ #define SMBHSTCNT (1 + 0x3100)
+@@ -50,11 +48,6 @@
+ #define ALI15X3_STS_TERM 0x80 /* terminated by abort */
+ #define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
+
+-const char *get_system_type(void)
+-{
+- return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
+-}
+-
+ static void __init pci_write_config(unsigned long busNo,
+ unsigned long devNo,
+ unsigned long fncNo,
+@@ -76,13 +69,9 @@ static void __init pci_write_config(unsi
+
+ static unsigned char m_irq_mask = 0xfb;
+ static unsigned char s_irq_mask = 0xff;
+-volatile unsigned long irq_err_count;
+
+ static void disable_mpc1211_irq(unsigned int irq)
+ {
+- unsigned long flags;
+-
+- save_and_cli(flags);
+ if( irq < 8) {
+ m_irq_mask |= (1 << irq);
+ outb(m_irq_mask,I8259_M_MR);
+@@ -90,16 +79,11 @@ static void disable_mpc1211_irq(unsigned
+ s_irq_mask |= (1 << (irq - 8));
+ outb(s_irq_mask,I8259_S_MR);
+ }
+- restore_flags(flags);
+
+ }
+
+ static void enable_mpc1211_irq(unsigned int irq)
+ {
+- unsigned long flags;
+-
+- save_and_cli(flags);
+-
+ if( irq < 8) {
+ m_irq_mask &= ~(1 << irq);
+ outb(m_irq_mask,I8259_M_MR);
+@@ -107,7 +91,6 @@ static void enable_mpc1211_irq(unsigned
+ s_irq_mask &= ~(1 << (irq - 8));
+ outb(s_irq_mask,I8259_S_MR);
+ }
+- restore_flags(flags);
+ }
+
+ static inline int mpc1211_irq_real(unsigned int irq)
+@@ -131,14 +114,10 @@ static inline int mpc1211_irq_real(unsig
+
+ static void mask_and_ack_mpc1211(unsigned int irq)
+ {
+- unsigned long flags;
+-
+- save_and_cli(flags);
+-
+ if(irq < 8) {
+ if(m_irq_mask & (1<<irq)){
+ if(!mpc1211_irq_real(irq)){
+- irq_err_count++;
++ atomic_inc(&irq_err_count)
+ printk("spurious 8259A interrupt: IRQ %x\n",irq);
+ }
+ } else {
+@@ -151,7 +130,7 @@ static void mask_and_ack_mpc1211(unsigne
+ } else {
+ if(s_irq_mask & (1<<(irq - 8))){
+ if(!mpc1211_irq_real(irq)){
+- irq_err_count++;
++ atomic_inc(&irq_err_count);
+ printk("spurious 8259A interrupt: IRQ %x\n",irq);
+ }
+ } else {
+@@ -162,7 +141,6 @@ static void mask_and_ack_mpc1211(unsigne
+ outb(0x60+(irq-8),I8259_S_CR); /* EOI */
+ outb(0x60+2,I8259_M_CR);
+ }
+- restore_flags(flags);
+ }
+
+ static void end_mpc1211_irq(unsigned int irq)
+@@ -219,7 +197,7 @@ int mpc1211_irq_demux(int irq)
+ return irq;
+ }
+
+-void __init init_mpc1211_IRQ(void)
++static void __init init_mpc1211_IRQ(void)
+ {
+ int i;
+ /*
+@@ -255,23 +233,12 @@ void __init init_mpc1211_IRQ(void)
+ }
+ }
+
+-/*
+- Initialize the board
+-*/
+-
+-
+-static void delay (void)
+-{
+- volatile unsigned short tmp;
+- tmp = *(volatile unsigned short *) 0xa0000000;
+-}
+-
+-static void delay1000 (void)
++static void delay1000(void)
+ {
+ int i;
+
+ for (i=0; i<1000; i++)
+- delay ();
++ ctrl_delay();
+ }
+
+ static int put_smb_blk(unsigned char *p, int address, int command, int no)
+@@ -314,26 +281,10 @@ static int put_smb_blk(unsigned char *p,
+ return 0;
+ }
+
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_mpc1211 __initmv = {
+- .mv_nr_irqs = 48,
+- .mv_irq_demux = mpc1211_irq_demux,
+- .mv_init_irq = init_mpc1211_IRQ,
+-
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_mpc1211,
+-#endif
+-};
+-
+-ALIAS_MV(mpc1211)
+-
+ /* arch/sh/boards/mpc1211/rtc.c */
+ void mpc1211_time_init(void);
+
+-int __init platform_setup(void)
++static void __init mpc1211_setup(char **cmdline_p)
+ {
+ unsigned char spd_buf[128];
+
+@@ -357,3 +308,18 @@ int __init platform_setup(void)
+ return 0;
+ }
+
++/*
++ * The Machine Vector
++ */
++struct sh_machine_vector mv_mpc1211 __initmv = {
++ .mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)",
++ .mv_setup = mpc1211_setup,
++ .mv_nr_irqs = 48,
++ .mv_irq_demux = mpc1211_irq_demux,
++ .mv_init_irq = init_mpc1211_IRQ,
++
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_mpc1211,
++#endif
++};
++ALIAS_MV(mpc1211)
+diff --git a/arch/sh/boards/overdrive/Makefile b/arch/sh/boards/overdrive/Makefile
+deleted file mode 100644
+index 245f03b..0000000
+--- a/arch/sh/boards/overdrive/Makefile
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#
+-# Makefile for the STMicroelectronics Overdrive specific parts of the kernel
+-#
+-
+-obj-y := mach.o setup.o io.o irq.o led.o
+-
+-obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o
+-
+diff --git a/arch/sh/boards/overdrive/fpga.c b/arch/sh/boards/overdrive/fpga.c
+deleted file mode 100644
+index 956c239..0000000
+--- a/arch/sh/boards/overdrive/fpga.c
++++ /dev/null
+@@ -1,133 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * This file handles programming up the Altera Flex10K that interfaces to
+- * the Galileo, and does the PS/2 keyboard and mouse
+- *
+- */
+-
+-
+-#include <linux/kernel.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-
+-
+-#include <asm/overdriver/gt64111.h>
+-#include <asm/overdrive/overdrive.h>
+-#include <asm/overdrive/fpga.h>
+-
+-#define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT
+-#define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK
+-
+-/* I need to find out what (if any) the real delay factor here is */
+-/* The delay is definately not critical */
+-#define long_delay() {int i;for(i=0;i<10000;i++);}
+-#define short_delay() {int i;for(i=0;i<100;i++);}
+-
+-static void __init program_overdrive_fpga(const unsigned char *fpgacode,
+- int size)
+-{
+- int timeout = 0;
+- int i, j;
+- unsigned char b;
+- static volatile unsigned char *FPGA_ControlReg =
+- (volatile unsigned char *) (OVERDRIVE_CTRL);
+- static volatile unsigned char *FPGA_ProgramReg =
+- (volatile unsigned char *) (FPGA_DCLK_ADDRESS);
+-
+- printk("FPGA: Commencing FPGA Programming\n");
+-
+- /* The PCI reset but MUST be low when programming the FPGA !!! */
+- b = (*FPGA_ControlReg) & RESET_PCI_MASK;
+-
+- (*FPGA_ControlReg) = b;
+-
+- /* Prepare FPGA to program */
+-
+- FPGA_NotConfigHigh();
+- long_delay();
+-
+- FPGA_NotConfigLow();
+- short_delay();
+-
+- while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) {
+- printk("FPGA: Waiting for NotStatus to go Low ... \n");
+- }
+-
+- FPGA_NotConfigHigh();
+-
+- /* Wait for FPGA "ready to be programmed" signal */
+- printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n");
+-
+- for (timeout = 0;
+- (((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0)
+- && (timeout < FPGA_TIMEOUT)); timeout++);
+-
+- /* Check if timeout condition occured - i.e. an error */
+-
+- if (timeout == FPGA_TIMEOUT) {
+- printk
+- ("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n");
+- return;
+- }
+-
+- printk("FPGA: Copying data to FPGA ... %d bytes\n", size);
+-
+- /* Copy array to FPGA - bit at a time */
+-
+- for (i = 0; i < size; i++) {
+- volatile unsigned w = 0;
+-
+- for (j = 0; j < 8; j++) {
+- *FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01;
+- short_delay();
+- }
+- if ((i & 0x3ff) == 0) {
+- printk(".");
+- }
+- }
+-
+- /* Waiting for CONFDONE to go high - means the program is complete */
+-
+- for (timeout = 0;
+- (((*FPGA_ProgramReg & FPGA_CONFDONE) == 0)
+- && (timeout < FPGA_TIMEOUT)); timeout++) {
+-
+- *FPGA_ProgramReg = 0x0;
+- long_delay();
+- }
+-
+- if (timeout == FPGA_TIMEOUT) {
+- printk
+- ("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n");
+- return;
+- } else { /* Clock another 10 times - gets the device into a working state */
+- for (i = 0; i < 10; i++) {
+- *FPGA_ProgramReg = 0x0;
+- short_delay();
+- }
+- }
+-
+- printk("FPGA: Programming complete\n");
+-}
+-
+-
+-static const unsigned char __init fpgacode[] = {
+-#include "./overdrive.ttf" /* Code from maxplus2 compiler */
+- , 0, 0
+-};
+-
+-
+-int __init init_overdrive_fpga(void)
+-{
+- program_overdrive_fpga(fpgacode, sizeof(fpgacode));
+-
+- return 0;
+-}
+diff --git a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c
+deleted file mode 100644
+index 29e4897..0000000
+--- a/arch/sh/boards/overdrive/galileo.c
++++ /dev/null
+@@ -1,587 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * This file contains the PCI routines required for the Galileo GT6411
+- * PCI bridge as used on the Orion and Overdrive boards.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-#include <linux/types.h>
+-#include <linux/ioport.h>
+-
+-#include <asm/overdrive/overdrive.h>
+-#include <asm/overdrive/gt64111.h>
+-
+-
+-/* After boot, we shift the Galileo registers so that they appear
+- * in BANK6, along with IO space. This means we can have one contingous
+- * lump of PCI address space without these registers appearing in the
+- * middle of them
+- */
+-
+-#define GT64111_BASE_ADDRESS 0xbb000000
+-#define GT64111_IO_BASE_ADDRESS 0x1000
+-/* The GT64111 registers appear at this address to the SH4 after reset */
+-#define RESET_GT64111_BASE_ADDRESS 0xb4000000
+-
+-/* Macros used to access the Galileo registers */
+-#define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x)
+-#define GT64111_REG(x) (GT64111_BASE_ADDRESS+x)
+-
+-#define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x))
+-
+-#define RESET_GT_READ(x) readl(RESET_GT64111_REG(x))
+-
+-#define GT_WRITE(x,v) writel((v),GT64111_REG(x))
+-#define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x))
+-#define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x))
+-
+-#define GT_READ(x) readl(GT64111_REG(x))
+-#define GT_READ_BYTE(x) readb(GT64111_REG(x))
+-#define GT_READ_SHORT(x) readw(GT64111_REG(x))
+-
+-
+-/* Where the various SH banks start at */
+-#define SH_BANK4_ADR 0xb0000000
+-#define SH_BANK5_ADR 0xb4000000
+-#define SH_BANK6_ADR 0xb8000000
+-
+-/* Masks out everything but lines 28,27,26 */
+-#define BANK_SELECT_MASK 0x1c000000
+-
+-#define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK)
+-
+-/*
+- * Masks used for address conversaion. Bank 6 is used for IO and
+- * has all the address bits zeroed by the FPGA. Special case this
+- */
+-#define MEMORY_BANK_MASK 0x1fffffff
+-#define IO_BANK_MASK 0x03ffffff
+-
+-/* Mark bank 6 as the bank used for IO. You can change this in the FPGA code
+- * if you want
+- */
+-#define IO_BANK_ADR PCI_GTIO_BASE
+-
+-/* Will select the correct mask to apply depending on the SH$ address */
+-#define SELECT_BANK_MASK(x) \
+- ( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK)
+-
+-/* Converts between PCI space and P2 region */
+-#define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x))
+-
+-/* Various macros for figuring out what to stick in the Galileo registers.
+- * You *really* don't want to figure this stuff out by hand, you always get
+- * it wrong
+- */
+-#define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff)
+-#define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f)
+-#define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff)
+-
+-#define PROGRAM_HI_LO(block,a,s) \
+- GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\
+- GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1))
+-
+-#define PROGRAM_SUB_HI_LO(block,a,s) \
+- GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\
+- GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1))
+-
+-/* We need to set the size, and the offset register */
+-
+-#define GT_BAR_MASK(x) ((x)&~0xfff)
+-
+-/* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */
+-#define PROGRAM_GT_BAR(block,a,s) \
+- GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\
+- write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\
+- GT_BAR_MASK(a))
+-
+-#define DISABLE_GT_BAR(block) \
+- GT_WRITE(PCI_##block##_BANK_SIZE,0),\
+- GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\
+- 0x80000000)
+-
+-/* Macros to disable things we are not going to use */
+-#define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\
+- GT_WRITE(x##_HI_DEC_ADR,0x00)
+-
+-#define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\
+- GT_WRITE(x##_HI_DEC_ADR,0x00)
+-
+-static void __init reset_pci(void)
+-{
+- /* Set RESET_PCI bit high */
+- writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
+- udelay(250);
+-
+- /* Set RESET_PCI bit low */
+- writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL);
+- udelay(250);
+-
+- writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
+- udelay(250);
+-}
+-
+-static int write_config_to_galileo(int where, u32 val);
+-#define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val)
+-
+-#define ENABLE_PCI_DRAM
+-
+-
+-#ifdef TEST_DRAM
+-/* Test function to check out if the PCI DRAM is working OK */
+-static int /* __init */ test_dram(unsigned *base, unsigned size)
+-{
+- unsigned *p = base;
+- unsigned *end = (unsigned *) (((unsigned) base) + size);
+- unsigned w;
+-
+- for (p = base; p < end; p++) {
+- *p = 0xffffffff;
+- if (*p != 0xffffffff) {
+- printk("AAARGH -write failed!!! at %p is %x\n", p,
+- *p);
+- return 0;
+- }
+- *p = 0x0;
+- if (*p != 0x0) {
+- printk("AAARGH -write failed!!!\n");
+- return 0;
+- }
+- }
+-
+- for (p = base; p < end; p++) {
+- *p = (unsigned) p;
+- if (*p != (unsigned) p) {
+- printk("Failed at 0x%p, actually is 0x%x\n", p,
+- *p);
+- return 0;
+- }
+- }
+-
+- for (p = base; p < end; p++) {
+- w = ((unsigned) p & 0xffff0000);
+- *p = w | (w >> 16);
+- }
+-
+- for (p = base; p < end; p++) {
+- w = ((unsigned) p & 0xffff0000);
+- w |= (w >> 16);
+- if (*p != w) {
+- printk
+- ("Failed at 0x%p, should be 0x%x actually is 0x%x\n",
+- p, w, *p);
+- return 0;
+- }
+- }
+-
+- return 1;
+-}
+-#endif
+-
+-
+-/* Function to set up and initialise the galileo. This sets up the BARS,
+- * maps the DRAM into the address space etc,etc
+- */
+-int __init galileo_init(void)
+-{
+- reset_pci();
+-
+- /* Now shift the galileo regs into this block */
+- RESET_GT_WRITE(INTERNAL_SPACE_DEC,
+- GT_MEM_LO_ADR(GT64111_BASE_ADDRESS));
+-
+- /* Should have a sanity check here, that you can read back at the new
+- * address what you just wrote
+- */
+-
+- /* Disable decode for all regions */
+- DISABLE_DECODE(RAS10);
+- DISABLE_DECODE(RAS32);
+- DISABLE_DECODE(CS20);
+- DISABLE_DECODE(CS3);
+- DISABLE_DECODE(PCI_IO);
+- DISABLE_DECODE(PCI_MEM0);
+- DISABLE_DECODE(PCI_MEM1);
+-
+- /* Disable all BARS */
+- GT_WRITE(BAR_ENABLE_ADR, 0x1ff);
+- DISABLE_GT_BAR(RAS10);
+- DISABLE_GT_BAR(RAS32);
+- DISABLE_GT_BAR(CS20);
+- DISABLE_GT_BAR(CS3);
+-
+- /* Tell the BAR where the IO registers now are */
+- GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK(
+- (GT64111_IO_BASE_ADDRESS &
+- IO_BANK_MASK)));
+- /* set up a 112 Mb decode */
+- PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024);
+-
+- /* Set up a 32 MB io space decode */
+- PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024);
+-
+-#ifdef ENABLE_PCI_DRAM
+- /* Program up the DRAM configuration - there is DRAM only in bank 0 */
+- /* Now set up the DRAM decode */
+- PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE);
+- /* And the sub decode */
+- PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE);
+-
+- DISABLE_SUB_DECODE(RAS1);
+-
+- /* Set refresh rate */
+- GT_WRITE(DRAM_BANK0_PARMS, 0x3f);
+- GT_WRITE(DRAM_CFG, 0x100);
+-
+- /* we have to lob off the top bits rememeber!! */
+- PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE);
+-
+-#endif
+-
+- /* We are only interested in decoding RAS10 and the Galileo's internal
+- * registers (as IO) on the PCI bus
+- */
+-#ifdef ENABLE_PCI_DRAM
+- GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff);
+-#else
+- GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff);
+-#endif
+-
+- /* Change the class code to host bridge, it actually powers up
+- * as a memory controller
+- */
+- GT_CONFIG_WRITE(8, 0x06000011);
+-
+- /* Allow the galileo to master the PCI bus */
+- GT_CONFIG_WRITE(PCI_COMMAND,
+- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+- PCI_COMMAND_IO);
+-
+-
+-#if 0
+- printk("Testing PCI DRAM - ");
+- if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
+- printk("Passed\n");
+- }else {
+- printk("FAILED\n");
+- }
+-#endif
+- return 0;
+-
+-}
+-
+-
+-#define SET_CONFIG_BITS(bus,devfn,where)\
+- ((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3))
+-
+-#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where)
+-
+-/* This write to the galileo config registers, unlike the functions below, can
+- * be used before the PCI subsystem has started up
+- */
+-static int __init write_config_to_galileo(int where, u32 val)
+-{
+- GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where));
+-
+- GT_WRITE(PCI_CFG_DATA, val);
+- return 0;
+-}
+-
+-/* We exclude the galileo and slot 31, the galileo because I don't know how to stop
+- * the setup code shagging up the setup I have done on it, and 31 because the whole
+- * thing locks up if you try to access that slot (which doesn't exist of course anyway
+- */
+-
+-#define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31)))
+-
+-static int galileo_read_config_byte(struct pci_dev *dev, int where,
+- u8 * val)
+-{
+-
+-
+- /* I suspect this doesn't work because this drives a special cycle ? */
+- if (EXCLUDED_DEV(dev)) {
+- *val = 0xff;
+- return PCIBIOS_SUCCESSFUL;
+- }
+- /* Start the config cycle */
+- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+- /* Read back the result */
+- *val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3));
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-
+-static int galileo_read_config_word(struct pci_dev *dev, int where,
+- u16 * val)
+-{
+-
+- if (EXCLUDED_DEV(dev)) {
+- *val = 0xffff;
+- return PCIBIOS_SUCCESSFUL;
+- }
+-
+- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+- *val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2));
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-
+-static int galileo_read_config_dword(struct pci_dev *dev, int where,
+- u32 * val)
+-{
+- if (EXCLUDED_DEV(dev)) {
+- *val = 0xffffffff;
+- return PCIBIOS_SUCCESSFUL;
+- }
+-
+- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+- *val = GT_READ(PCI_CFG_DATA);
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int galileo_write_config_byte(struct pci_dev *dev, int where,
+- u8 val)
+-{
+- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+-
+- GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val);
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-
+-static int galileo_write_config_word(struct pci_dev *dev, int where,
+- u16 val)
+-{
+- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+-
+- GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val);
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int galileo_write_config_dword(struct pci_dev *dev, int where,
+- u32 val)
+-{
+- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+-
+- GT_WRITE(PCI_CFG_DATA, val);
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static struct pci_ops pci_config_ops = {
+- galileo_read_config_byte,
+- galileo_read_config_word,
+- galileo_read_config_dword,
+- galileo_write_config_byte,
+- galileo_write_config_word,
+- galileo_write_config_dword
+-};
+-
+-
+-/* Everything hangs off this */
+-static struct pci_bus *pci_root_bus;
+-
+-
+-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+-{
+- return PCI_SLOT(dev->devfn);
+-}
+-
+-static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- /* Slot 1: Galileo
+- * Slot 2: PCI Slot 1
+- * Slot 3: PCI Slot 2
+- * Slot 4: ESS
+- */
+- switch (slot) {
+- case 2:
+- return OVERDRIVE_PCI_IRQ1;
+- case 3:
+- /* Note this assumes you have a hacked card in slot 2 */
+- return OVERDRIVE_PCI_IRQ2;
+- case 4:
+- return OVERDRIVE_ESS_IRQ;
+- default:
+- /* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */
+- return -1;
+- }
+-}
+-
+-
+-
+-void __init
+-pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+-{
+- ranges->io_start -= bus->resource[0]->start;
+- ranges->io_end -= bus->resource[0]->start;
+- ranges->mem_start -= bus->resource[1]->start;
+- ranges->mem_end -= bus->resource[1]->start;
+-}
+-
+-static void __init pci_fixup_ide_bases(struct pci_dev *d)
+-{
+- int i;
+-
+- /*
+- * PCI IDE controllers use non-standard I/O port decoding, respect it.
+- */
+- if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+- return;
+- printk("PCI: IDE base address fixup for %s\n", pci_name(d));
+- for(i=0; i<4; i++) {
+- struct resource *r = &d->resource[i];
+- if ((r->start & ~0x80) == 0x374) {
+- r->start |= 2;
+- r->end = r->start;
+- }
+- }
+-}
+-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+-
+-void __init pcibios_init(void)
+-{
+- static struct resource galio,galmem;
+-
+- /* Allocate the registers used by the Galileo */
+- galio.flags = IORESOURCE_IO;
+- galio.name = "Galileo GT64011";
+- galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH;
+- galmem.name = "Galileo GT64011 DRAM";
+-
+- allocate_resource(&ioport_resource, &galio, 256,
+- GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL);
+- allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE,
+- PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE,
+- PCI_DRAM_SIZE, NULL, NULL);
+-
+- /* ok, do the scan man */
+- pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+-
+- pci_assign_unassigned_resources();
+- pci_fixup_irqs(no_swizzle, map_od_irq);
+-
+-#ifdef TEST_DRAM
+- printk("Testing PCI DRAM - ");
+- if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
+- printk("Passed\n");
+- }else {
+- printk("FAILED\n");
+- }
+-#endif
+-
+-}
+-
+-char * __init pcibios_setup(char *str)
+-{
+- return str;
+-}
+-
+-
+-
+-int pcibios_enable_device(struct pci_dev *dev)
+-{
+-
+- 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;
+-
+-}
+-
+-/* We should do some optimisation work here I think. Ok for now though */
+-void __init pcibios_fixup_bus(struct pci_bus *bus)
+-{
+-
+-}
+-
+-void pcibios_align_resource(void *data, struct resource *res,
+- resource_size_t size)
+-{
+-}
+-
+-void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+- struct resource *res, int resource)
+-{
+-
+- unsigned long where, size;
+- u32 reg;
+-
+-
+- printk("PCI: Assigning %3s %08lx to %s\n",
+- res->flags & IORESOURCE_IO ? "IO" : "MEM",
+- res->start, dev->name);
+-
+- where = PCI_BASE_ADDRESS_0 + resource * 4;
+- size = res->end - res->start;
+-
+- pci_read_config_dword(dev, where, ®);
+- reg = (reg & size) | (((u32) (res->start - root->start)) & ~size);
+- pci_write_config_dword(dev, where, reg);
+-}
+-
+-
+-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+-{
+- printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
+- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+-}
+-
+-/*
+- * If we set up a device for bus mastering, we need to check the latency
+- * timer as certain crappy BIOSes forget to set it properly.
+- */
+-unsigned int pcibios_max_latency = 255;
+-
+-void pcibios_set_master(struct pci_dev *dev)
+-{
+- u8 lat;
+- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+- if (lat < 16)
+- lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+- else if (lat > pcibios_max_latency)
+- lat = pcibios_max_latency;
+- else
+- return;
+- printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+- pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+-}
+diff --git a/arch/sh/boards/overdrive/io.c b/arch/sh/boards/overdrive/io.c
+deleted file mode 100644
+index 4671b6b..0000000
+--- a/arch/sh/boards/overdrive/io.c
++++ /dev/null
+@@ -1,172 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * This file contains the I/O routines for use on the overdrive board
+- *
+- */
+-
+-#include <linux/types.h>
+-#include <linux/delay.h>
+-#include <asm/processor.h>
+-#include <asm/io.h>
+-#include <asm/addrspace.h>
+-
+-#include <asm/overdrive/overdrive.h>
+-
+-/*
+- * readX/writeX() are used to access memory mapped devices. On some
+- * architectures the memory mapped IO stuff needs to be accessed
+- * differently. On the SuperH architecture, we just read/write the
+- * memory location directly.
+- */
+-
+-#define dprintk(x...)
+-
+-/* Translates an IO address to where it is mapped in memory */
+-
+-#define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE)
+-
+-unsigned char od_inb(unsigned long port)
+-{
+-dprintk("od_inb(%x)\n", port);
+- return readb(io_addr(port)) & 0xff;
+-}
+-
+-
+-unsigned short od_inw(unsigned long port)
+-{
+-dprintk("od_inw(%x)\n", port);
+- return readw(io_addr(port)) & 0xffff;
+-}
+-
+-unsigned int od_inl(unsigned long port)
+-{
+-dprintk("od_inl(%x)\n", port);
+- return readl(io_addr(port));
+-}
+-
+-void od_outb(unsigned char value, unsigned long port)
+-{
+-dprintk("od_outb(%x, %x)\n", value, port);
+- writeb(value, io_addr(port));
+-}
+-
+-void od_outw(unsigned short value, unsigned long port)
+-{
+-dprintk("od_outw(%x, %x)\n", value, port);
+- writew(value, io_addr(port));
+-}
+-
+-void od_outl(unsigned int value, unsigned long port)
+-{
+-dprintk("od_outl(%x, %x)\n", value, port);
+- writel(value, io_addr(port));
+-}
+-
+-/* This is horrible at the moment - needs more work to do something sensible */
+-#define IO_DELAY() udelay(10)
+-
+-#define OUT_DELAY(x,type) \
+-void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
+-
+-#define IN_DELAY(x,type) \
+-unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
+-
+-
+-OUT_DELAY(b,char)
+-OUT_DELAY(w,short)
+-OUT_DELAY(l,int)
+-
+-IN_DELAY(b,char)
+-IN_DELAY(w,short)
+-IN_DELAY(l,int)
+-
+-
+-/* Now for the string version of these functions */
+-void od_outsb(unsigned long port, const void *addr, unsigned long count)
+-{
+- int i;
+- unsigned char *p = (unsigned char *) addr;
+-
+- for (i = 0; i < count; i++, p++) {
+- outb(*p, port);
+- }
+-}
+-
+-
+-void od_insb(unsigned long port, void *addr, unsigned long count)
+-{
+- int i;
+- unsigned char *p = (unsigned char *) addr;
+-
+- for (i = 0; i < count; i++, p++) {
+- *p = inb(port);
+- }
+-}
+-
+-/* For the 16 and 32 bit string functions, we have to worry about alignment.
+- * The SH does not do unaligned accesses, so we have to read as bytes and
+- * then write as a word or dword.
+- * This can be optimised a lot more, especially in the case where the data
+- * is aligned
+- */
+-
+-void od_outsw(unsigned long port, const void *addr, unsigned long count)
+-{
+- int i;
+- unsigned short tmp;
+- unsigned char *p = (unsigned char *) addr;
+-
+- for (i = 0; i < count; i++, p += 2) {
+- tmp = (*p) | ((*(p + 1)) << 8);
+- outw(tmp, port);
+- }
+-}
+-
+-
+-void od_insw(unsigned long port, void *addr, unsigned long count)
+-{
+- int i;
+- unsigned short tmp;
+- unsigned char *p = (unsigned char *) addr;
+-
+- for (i = 0; i < count; i++, p += 2) {
+- tmp = inw(port);
+- p[0] = tmp & 0xff;
+- p[1] = (tmp >> 8) & 0xff;
+- }
+-}
+-
+-
+-void od_outsl(unsigned long port, const void *addr, unsigned long count)
+-{
+- int i;
+- unsigned tmp;
+- unsigned char *p = (unsigned char *) addr;
+-
+- for (i = 0; i < count; i++, p += 4) {
+- tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) |
+- ((*(p + 3)) << 24);
+- outl(tmp, port);
+- }
+-}
+-
+-
+-void od_insl(unsigned long port, void *addr, unsigned long count)
+-{
+- int i;
+- unsigned tmp;
+- unsigned char *p = (unsigned char *) addr;
+-
+- for (i = 0; i < count; i++, p += 4) {
+- tmp = inl(port);
+- p[0] = tmp & 0xff;
+- p[1] = (tmp >> 8) & 0xff;
+- p[2] = (tmp >> 16) & 0xff;
+- p[3] = (tmp >> 24) & 0xff;
+-
+- }
+-}
+diff --git a/arch/sh/boards/overdrive/irq.c b/arch/sh/boards/overdrive/irq.c
+deleted file mode 100644
+index 5d730c7..0000000
+--- a/arch/sh/boards/overdrive/irq.c
++++ /dev/null
+@@ -1,191 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Looks after interrupts on the overdrive board.
+- *
+- * Bases on the IPR irq system
+- */
+-
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <asm/system.h>
+-#include <asm/io.h>
+-
+-#include <asm/overdrive/overdrive.h>
+-
+-struct od_data {
+- int overdrive_irq;
+- int irq_mask;
+-};
+-
+-#define NUM_EXTERNAL_IRQS 16
+-#define EXTERNAL_IRQ_NOT_IN_USE (-1)
+-#define EXTERNAL_IRQ_NOT_ASSIGNED (-1)
+-
+-/*
+- * This table is used to determine what to program into the FPGA's CT register
+- * for the specified Linux IRQ.
+- *
+- * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0))
+- * but is one greater than that because the because the FPGA treats 0
+- * as disabled, a value of 1 asserts PCI_Int0, and so on.
+- *
+- * The overdrive_irq specifies which of the eight interrupt sources generates
+- * that interrupt, and but is multiplied by four to give the bit offset into
+- * the CT register.
+- *
+- * The seven interrupts levels (SH4 IRL's) we have available here is hardwired
+- * by the EPLD. The assignments here of which PCI interrupt generates each
+- * level is arbitary.
+- */
+-static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {
+- /* overdrive_irq , irq_mask */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */
+- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */
+-};
+-
+-static void set_od_data(int overdrive_irq, int irq)
+-{
+- if (irq >= NUM_EXTERNAL_IRQS || irq < 0)
+- return;
+- od_data_table[irq].overdrive_irq = overdrive_irq << 2;
+-}
+-
+-static void enable_od_irq(unsigned int irq);
+-void disable_od_irq(unsigned int irq);
+-
+-/* shutdown is same as "disable" */
+-#define shutdown_od_irq disable_od_irq
+-
+-static void mask_and_ack_od(unsigned int);
+-static void end_od_irq(unsigned int irq);
+-
+-static unsigned int startup_od_irq(unsigned int irq)
+-{
+- enable_od_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static struct hw_interrupt_type od_irq_type = {
+- .typename = "Overdrive-IRQ",
+- .startup = startup_od_irq,
+- .shutdown = shutdown_od_irq,
+- .enable = enable_od_irq,
+- .disable = disable_od_irq,
+- .ack = mask_and_ack_od,
+- .end = end_od_irq
+-};
+-
+-static void disable_od_irq(unsigned int irq)
+-{
+- unsigned val, flags;
+- int overdrive_irq;
+- unsigned mask;
+-
+- /* Not a valid interrupt */
+- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+- return;
+-
+- /* Is is necessary to use a cli here? Would a spinlock not be
+- * mroe efficient?
+- */
+- local_irq_save(flags);
+- overdrive_irq = od_data_table[irq].overdrive_irq;
+- if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
+- mask = ~(0x7 << overdrive_irq);
+- val = ctrl_inl(OVERDRIVE_INT_CT);
+- val &= mask;
+- ctrl_outl(val, OVERDRIVE_INT_CT);
+- }
+- local_irq_restore(flags);
+-}
+-
+-static void enable_od_irq(unsigned int irq)
+-{
+- unsigned val, flags;
+- int overdrive_irq;
+- unsigned mask;
+-
+- /* Not a valid interrupt */
+- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+- return;
+-
+- /* Set priority in OD back to original value */
+- local_irq_save(flags);
+- /* This one is not in use currently */
+- overdrive_irq = od_data_table[irq].overdrive_irq;
+- if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
+- val = ctrl_inl(OVERDRIVE_INT_CT);
+- mask = ~(0x7 << overdrive_irq);
+- val &= mask;
+- mask = od_data_table[irq].irq_mask << overdrive_irq;
+- val |= mask;
+- ctrl_outl(val, OVERDRIVE_INT_CT);
+- }
+- local_irq_restore(flags);
+-}
+-
+-
+-
+-/* this functions sets the desired irq handler to be an overdrive type */
+-static void __init make_od_irq(unsigned int irq)
+-{
+- disable_irq_nosync(irq);
+- irq_desc[irq].chip = &od_irq_type;
+- disable_od_irq(irq);
+-}
+-
+-
+-static void mask_and_ack_od(unsigned int irq)
+-{
+- disable_od_irq(irq);
+-}
+-
+-static void end_od_irq(unsigned int irq)
+-{
+- enable_od_irq(irq);
+-}
+-
+-void __init init_overdrive_irq(void)
+-{
+- int i;
+-
+- /* Disable all interrupts */
+- ctrl_outl(0, OVERDRIVE_INT_CT);
+-
+- /* Update interrupt pin mode to use encoded interrupts */
+- i = ctrl_inw(INTC_ICR);
+- i &= ~INTC_ICR_IRLM;
+- ctrl_outw(i, INTC_ICR);
+-
+- for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+- if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {
+- make_od_irq(i);
+- } else if (i != 15) { // Cannot use imask on level 15
+- make_imask_irq(i);
+- }
+- }
+-
+- /* Set up the interrupts */
+- set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);
+- set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);
+- set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);
+-}
+diff --git a/arch/sh/boards/overdrive/led.c b/arch/sh/boards/overdrive/led.c
+deleted file mode 100644
+index 860d7f2..0000000
+--- a/arch/sh/boards/overdrive/led.c
++++ /dev/null
+@@ -1,58 +0,0 @@
+-/*
+- * linux/arch/sh/overdrive/led.c
+- *
+- * Copyright (C) 1999 Stuart Menefy <stuart.menefy at st.com>
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * This file contains an Overdrive specific LED feature.
+- */
+-
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/overdrive/overdrive.h>
+-
+-static void mach_led(int position, int value)
+-{
+- unsigned long flags;
+- unsigned long reg;
+-
+- local_irq_save(flags);
+-
+- reg = readl(OVERDRIVE_CTRL);
+- if (value) {
+- reg |= (1<<3);
+- } else {
+- reg &= ~(1<<3);
+- }
+- writel(reg, OVERDRIVE_CTRL);
+-
+- local_irq_restore(flags);
+-}
+-
+-#ifdef CONFIG_HEARTBEAT
+-
+-#include <linux/sched.h>
+-
+-/* acts like an actual heart beat -- ie thump-thump-pause... */
+-void heartbeat_od(void)
+-{
+- static unsigned cnt = 0, period = 0, dist = 0;
+-
+- if (cnt == 0 || cnt == dist)
+- mach_led( -1, 1);
+- else if (cnt == 7 || cnt == dist+7)
+- mach_led( -1, 0);
+-
+- if (++cnt > period) {
+- cnt = 0;
+- /* The hyperbolic function below modifies the heartbeat period
+- * length in dependency of the current (5min) load. It goes
+- * through the points f(0)=126, f(1)=86, f(5)=51,
+- * f(inf)->30. */
+- period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+- dist = period / 4;
+- }
+-}
+-#endif /* CONFIG_HEARTBEAT */
+diff --git a/arch/sh/boards/overdrive/mach.c b/arch/sh/boards/overdrive/mach.c
+deleted file mode 100644
+index 2834a03..0000000
+--- a/arch/sh/boards/overdrive/mach.c
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*
+- * linux/arch/sh/overdrive/mach.c
+- *
+- * Copyright (C) 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the STMicroelectronics Overdrive
+- */
+-
+-#include <linux/init.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/machvec_init.h>
+-
+-#include <asm/io_unknown.h>
+-#include <asm/io_generic.h>
+-#include <asm/overdrive/io.h>
+-
+-void heartbeat_od(void);
+-void init_overdrive_irq(void);
+-void galileo_pcibios_init(void);
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_od __initmv = {
+- .mv_nr_irqs = 48,
+-
+- .mv_inb = od_inb,
+- .mv_inw = od_inw,
+- .mv_inl = od_inl,
+- .mv_outb = od_outb,
+- .mv_outw = od_outw,
+- .mv_outl = od_outl,
+-
+- .mv_inb_p = od_inb_p,
+- .mv_inw_p = od_inw_p,
+- .mv_inl_p = od_inl_p,
+- .mv_outb_p = od_outb_p,
+- .mv_outw_p = od_outw_p,
+- .mv_outl_p = od_outl_p,
+-
+- .mv_insb = od_insb,
+- .mv_insw = od_insw,
+- .mv_insl = od_insl,
+- .mv_outsb = od_outsb,
+- .mv_outsw = od_outsw,
+- .mv_outsl = od_outsl,
+-
+-#ifdef CONFIG_PCI
+- .mv_init_irq = init_overdrive_irq,
+-#endif
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_od,
+-#endif
+-};
+-
+-ALIAS_MV(od)
+diff --git a/arch/sh/boards/overdrive/pcidma.c b/arch/sh/boards/overdrive/pcidma.c
+deleted file mode 100644
+index 1c9bfed..0000000
+--- a/arch/sh/boards/overdrive/pcidma.c
++++ /dev/null
+@@ -1,46 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Dynamic DMA mapping support.
+- *
+- * On the overdrive, we can only DMA from memory behind the PCI bus!
+- * this means that all DMA'able memory must come from there.
+- * this restriction will not apply to later boards.
+- */
+-
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/string.h>
+-#include <linux/pci.h>
+-#include <asm/io.h>
+-
+-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+- dma_addr_t * dma_handle)
+-{
+- void *ret;
+- int gfp = GFP_ATOMIC;
+-
+- printk("BUG: pci_alloc_consistent() called - not yet supported\n");
+- /* We ALWAYS need DMA memory on the overdrive hardware,
+- * due to it's extreme weirdness
+- * Need to flush the cache here as well, since the memory
+- * can still be seen through the cache!
+- */
+- gfp |= GFP_DMA;
+- ret = (void *) __get_free_pages(gfp, get_order(size));
+-
+- if (ret != NULL) {
+- memset(ret, 0, size);
+- *dma_handle = virt_to_bus(ret);
+- }
+- return ret;
+-}
+-
+-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+- void *vaddr, dma_addr_t dma_handle)
+-{
+- free_pages((unsigned long) vaddr, get_order(size));
+-}
+diff --git a/arch/sh/boards/overdrive/setup.c b/arch/sh/boards/overdrive/setup.c
+deleted file mode 100644
+index a3a7744..0000000
+--- a/arch/sh/boards/overdrive/setup.c
++++ /dev/null
+@@ -1,36 +0,0 @@
+-/*
+- * arch/sh/overdrive/setup.c
+- *
+- * Copyright (C) 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * STMicroelectronics Overdrive Support.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <asm/io.h>
+-
+-#include <asm/overdrive/overdrive.h>
+-#include <asm/overdrive/fpga.h>
+-
+-const char *get_system_type(void)
+-{
+- return "SH7750 Overdrive";
+-}
+-
+-/*
+- * Initialize the board
+- */
+-int __init platform_setup(void)
+-{
+-#ifdef CONFIG_PCI
+- init_overdrive_fpga();
+- galileo_init();
+-#endif
+-
+- /* Enable RS232 receive buffers */
+- writel(0x1e, OVERDRIVE_CTRL);
+-}
+diff --git a/arch/sh/boards/renesas/edosk7705/Makefile b/arch/sh/boards/renesas/edosk7705/Makefile
+index 7fccbf2..14bdd53 100644
+--- a/arch/sh/boards/renesas/edosk7705/Makefile
++++ b/arch/sh/boards/renesas/edosk7705/Makefile
+@@ -1,10 +1,6 @@
+ #
+ # Makefile for the EDOSK7705 specific parts of the kernel
+ #
+-# 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).
+-#
+
+ obj-y := setup.o io.o
+
+diff --git a/arch/sh/boards/renesas/edosk7705/setup.c b/arch/sh/boards/renesas/edosk7705/setup.c
+index ba143fa..ec5be01 100644
+--- a/arch/sh/boards/renesas/edosk7705/setup.c
++++ b/arch/sh/boards/renesas/edosk7705/setup.c
+@@ -8,19 +8,21 @@
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+-
+ #include <linux/init.h>
+ #include <asm/machvec.h>
+-#include <asm/machvec_init.h>
+ #include <asm/edosk7705/io.h>
+
+-static void init_edosk7705(void);
++static void __init sh_edosk7705_init_irq(void)
++{
++ /* This is the Ethernet interrupt */
++ make_imask_irq(0x09);
++}
+
+ /*
+ * The Machine Vector
+ */
+-
+ struct sh_machine_vector mv_edosk7705 __initmv = {
++ .mv_name = "EDOSK7705",
+ .mv_nr_irqs = 80,
+
+ .mv_inb = sh_edosk7705_inb,
+@@ -37,23 +39,6 @@ struct sh_machine_vector mv_edosk7705 __
+ .mv_outsl = sh_edosk7705_outsl,
+
+ .mv_isa_port2addr = sh_edosk7705_isa_port2addr,
+- .mv_init_irq = init_edosk7705,
++ .mv_init_irq = sh_edosk7705_init_irq,
+ };
+ ALIAS_MV(edosk7705)
+-
+-static void __init init_edosk7705(void)
+-{
+- /* This is the Ethernet interrupt */
+- make_imask_irq(0x09);
+-}
+-
+-const char *get_system_type(void)
+-{
+- return "EDOSK7705";
+-}
+-
+-void __init platform_setup(void)
+-{
+- /* Nothing .. */
+-}
+-
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/Kconfig b/arch/sh/boards/renesas/hs7751rvoip/Kconfig
+new file mode 100644
+index 0000000..1743be4
+--- /dev/null
++++ b/arch/sh/boards/renesas/hs7751rvoip/Kconfig
+@@ -0,0 +1,12 @@
++if SH_HS7751RVOIP
++
++menu "HS7751RVoIP options"
++
++config HS7751RVOIP_CODEC
++ bool "Support VoIP Codec section"
++ help
++ Selecting this option will support CODEC section.
++
++endmenu
++
++endif
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/Makefile b/arch/sh/boards/renesas/hs7751rvoip/Makefile
+index e8b4109..e626377 100644
+--- a/arch/sh/boards/renesas/hs7751rvoip/Makefile
++++ b/arch/sh/boards/renesas/hs7751rvoip/Makefile
+@@ -1,12 +1,8 @@
+ #
+ # Makefile for the HS7751RVoIP specific parts of the kernel
+ #
+-# 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).
+-#
+
+-obj-y := mach.o setup.o io.o irq.o led.o
++obj-y := setup.o io.o irq.o
+
+ obj-$(CONFIG_PCI) += pci.o
+
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c
+index 3a1abfa..bb9aa0d 100644
+--- a/arch/sh/boards/renesas/hs7751rvoip/io.c
++++ b/arch/sh/boards/renesas/hs7751rvoip/io.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/io_hs7751rvoip.c
++ * linux/arch/sh/boards/renesas/hs7751rvoip/io.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+@@ -10,21 +10,16 @@
+ * placeholder code from io_hs7751rvoip.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+-#include <asm/io.h>
+-#include <asm/hs7751rvoip/hs7751rvoip.h>
+-#include <asm/addrspace.h>
+-
+ #include <linux/module.h>
+ #include <linux/pci.h>
+-#include "../../../drivers/pci/pci-sh7751.h"
++#include <asm/io.h>
++#include <asm/hs7751rvoip.h>
++#include <asm/addrspace.h>
+
+-extern void *area5_io8_base; /* Area 5 8bit I/O Base address */
+ extern void *area6_io8_base; /* Area 6 8bit I/O Base address */
+ extern void *area5_io16_base; /* Area 5 16bit I/O Base address */
+-extern void *area6_io16_base; /* Area 6 16bit I/O Base address */
+
+ /*
+ * The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC)
+@@ -33,25 +28,8 @@ extern void *area6_io16_base; /* Area 6
+ * like the other Solution Engine boards.
+ */
+
+-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+-#define PCI_IO_AREA SH7751_PCI_IO_BASE
+-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+-
+-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+-
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ #define CODEC_IO_BASE 0x1000
+-#endif
+-
+-#define maybebadio(name,port) \
+- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+- #name, (port), (__u32) __builtin_return_address(0))
+-
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
++#define CODEC_IOMAP(a) ((unsigned long)area6_io8_base + ((a) - CODEC_IO_BASE))
+
+ static inline unsigned long port2adr(unsigned int port)
+ {
+@@ -59,9 +37,10 @@ static inline unsigned long port2adr(uns
+ if (port == 0x3f6)
+ return ((unsigned long)area5_io16_base + 0x0c);
+ else
+- return ((unsigned long)area5_io16_base + 0x800 + ((port-0x1f0) << 1));
++ return ((unsigned long)area5_io16_base + 0x800 +
++ ((port-0x1f0) << 1));
+ else
+- maybebadio(port2adr, (unsigned long)port);
++ maybebadio((unsigned long)port);
+ return port;
+ }
+
+@@ -78,25 +57,10 @@ static inline int shifted_port(unsigned
+ }
+
+ #if defined(CONFIG_HS7751RVOIP_CODEC)
+-static inline int
+-codec_port(unsigned long port)
+-{
+- if (CODEC_IO_BASE <= port && port < (CODEC_IO_BASE+0x20))
+- return 1;
+- else
+- return 0;
+-}
+-#endif
+-
+-/* In case someone configures the kernel w/o PCI support: in that */
+-/* scenario, don't ever bother to check for PCI-window addresses */
+-
+-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+-#if defined(CONFIG_PCI)
+-#define CHECK_SH7751_PCIIO(port) \
+- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
++#define codec_port(port) \
++ ((CODEC_IO_BASE <= (port)) && ((port) < (CODEC_IO_BASE + 0x20)))
+ #else
+-#define CHECK_SH7751_PCIIO(port) (0)
++#define codec_port(port) (0)
+ #endif
+
+ /*
+@@ -109,15 +73,13 @@ codec_port(unsigned long port)
+ unsigned char hs7751rvoip_inb(unsigned long port)
+ {
+ if (PXSEG(port))
+- return *(volatile unsigned char *)port;
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
++ return ctrl_inb(port);
+ else if (codec_port(port))
+- return *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
+-#endif
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- return *(volatile unsigned char *)PCI_IOMAP(port);
++ return ctrl_inb(CODEC_IOMAP(port));
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return ctrl_inb(pci_ioaddr(port));
+ else
+- return (*(volatile unsigned short *)port2adr(port) & 0xff);
++ return ctrl_inw(port2adr(port)) & 0xff;
+ }
+
+ unsigned char hs7751rvoip_inb_p(unsigned long port)
+@@ -125,38 +87,36 @@ unsigned char hs7751rvoip_inb_p(unsigned
+ unsigned char v;
+
+ if (PXSEG(port))
+- v = *(volatile unsigned char *)port;
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
++ v = ctrl_inb(port);
+ else if (codec_port(port))
+- v = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
+-#endif
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- v = *(volatile unsigned char *)PCI_IOMAP(port);
++ v = ctrl_inb(CODEC_IOMAP(port));
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ v = ctrl_inb(pci_ioaddr(port));
+ else
+- v = (*(volatile unsigned short *)port2adr(port) & 0xff);
+- delay();
++ v = ctrl_inw(port2adr(port)) & 0xff;
++ ctrl_delay();
+ return v;
+ }
+
+ unsigned short hs7751rvoip_inw(unsigned long port)
+ {
+ if (PXSEG(port))
+- return *(volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- return *(volatile unsigned short *)PCI_IOMAP(port);
++ return ctrl_inw(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return ctrl_inw(pci_ioaddr(port));
+ else
+- maybebadio(inw, port);
++ maybebadio(port);
+ return 0;
+ }
+
+ unsigned int hs7751rvoip_inl(unsigned long port)
+ {
+ if (PXSEG(port))
+- return *(volatile unsigned long *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- return *(volatile unsigned long *)PCI_IOMAP(port);
++ return ctrl_inl(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return ctrl_inl(pci_ioaddr(port));
+ else
+- maybebadio(inl, port);
++ maybebadio(port);
+ return 0;
+ }
+
+@@ -164,146 +124,160 @@ void hs7751rvoip_outb(unsigned char valu
+ {
+
+ if (PXSEG(port))
+- *(volatile unsigned char *)port = value;
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
++ ctrl_outb(value, port);
+ else if (codec_port(port))
+- *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
+-#endif
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(unsigned char *)PCI_IOMAP(port) = value;
++ ctrl_outb(value, CODEC_IOMAP(port));
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outb(value, pci_ioaddr(port));
+ else
+- *(volatile unsigned short *)port2adr(port) = value;
++ ctrl_outb(value, port2adr(port));
+ }
+
+ void hs7751rvoip_outb_p(unsigned char value, unsigned long port)
+ {
+ if (PXSEG(port))
+- *(volatile unsigned char *)port = value;
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
++ ctrl_outb(value, port);
+ else if (codec_port(port))
+- *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
+-#endif
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(unsigned char *)PCI_IOMAP(port) = value;
++ ctrl_outb(value, CODEC_IOMAP(port));
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outb(value, pci_ioaddr(port));
+ else
+- *(volatile unsigned short *)port2adr(port) = value;
+- delay();
++ ctrl_outw(value, port2adr(port));
++
++ ctrl_delay();
+ }
+
+ void hs7751rvoip_outw(unsigned short value, unsigned long port)
+ {
+ if (PXSEG(port))
+- *(volatile unsigned short *)port = value;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(unsigned short *)PCI_IOMAP(port) = value;
++ ctrl_outw(value, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outw(value, pci_ioaddr(port));
+ else
+- maybebadio(outw, port);
++ maybebadio(port);
+ }
+
+ void hs7751rvoip_outl(unsigned int value, unsigned long port)
+ {
+ if (PXSEG(port))
+- *(volatile unsigned long *)port = value;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *((unsigned long *)PCI_IOMAP(port)) = value;
++ ctrl_outl(value, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outl(value, pci_ioaddr(port));
+ else
+- maybebadio(outl, port);
++ maybebadio(port);
+ }
+
+ void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count)
+ {
++ u8 *buf = addr;
++
+ if (PXSEG(port))
+- while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port;
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
++ while (count--)
++ *buf++ = ctrl_inb(port);
+ else if (codec_port(port))
+- while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
+-#endif
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
++ while (count--)
++ *buf++ = ctrl_inb(CODEC_IOMAP(port));
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+
+- while (count--) *((volatile unsigned char *) addr)++ = *bp;
++ while (count--)
++ *buf++ = *bp;
+ } else {
+- volatile __u16 *p = (volatile unsigned short *)port2adr(port);
++ volatile u16 *p = (volatile u16 *)port2adr(port);
+
+- while (count--) *((unsigned char *) addr)++ = *p & 0xff;
++ while (count--)
++ *buf++ = *p & 0xff;
+ }
+ }
+
+ void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count)
+ {
+- volatile __u16 *p;
++ volatile u16 *p;
++ u16 *buf = addr;
+
+ if (PXSEG(port))
+- p = (volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- p = (volatile unsigned short *)PCI_IOMAP(port);
++ p = (volatile u16 *)port;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ p = (volatile u16 *)pci_ioaddr(port);
+ else
+- p = (volatile unsigned short *)port2adr(port);
+- while (count--) *((__u16 *) addr)++ = *p;
++ p = (volatile u16 *)port2adr(port);
++ while (count--)
++ *buf++ = *p;
+ }
+
+ void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count)
+ {
+- if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+
+- while (count--) *((__u32 *) addr)++ = *p;
++ if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
++ u32 *buf = addr;
++
++ while (count--)
++ *buf++ = *p;
+ } else
+- maybebadio(insl, port);
++ maybebadio(port);
+ }
+
+ void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count)
+ {
++ const u8 *buf = addr;
++
+ if (PXSEG(port))
+- while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++;
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
++ while (count--)
++ ctrl_outb(*buf++, port);
+ else if (codec_port(port))
+- while (count--) *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = *((unsigned char *) addr)++;
+-#endif
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
++ while (count--)
++ ctrl_outb(*buf++, CODEC_IOMAP(port));
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+
+- while (count--) *bp = *((volatile unsigned char *) addr)++;
++ while (count--)
++ *bp = *buf++;
+ } else {
+- volatile __u16 *p = (volatile unsigned short *)port2adr(port);
++ volatile u16 *p = (volatile u16 *)port2adr(port);
+
+- while (count--) *p = *((unsigned char *) addr)++;
++ while (count--)
++ *p = *buf++;
+ }
+ }
+
+ void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count)
+ {
+- volatile __u16 *p;
++ volatile u16 *p;
++ const u16 *buf = addr;
+
+ if (PXSEG(port))
+- p = (volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- p = (volatile unsigned short *)PCI_IOMAP(port);
++ p = (volatile u16 *)port;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ p = (volatile u16 *)pci_ioaddr(port);
+ else
+- p = (volatile unsigned short *)port2adr(port);
+- while (count--) *p = *((__u16 *) addr)++;
++ p = (volatile u16 *)port2adr(port);
++
++ while (count--)
++ *p = *buf++;
+ }
+
+ void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count)
+ {
+- if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
++ const u32 *buf = addr;
+
+- while (count--) *p = *((__u32 *) addr)++;
++ if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
++
++ while (count--)
++ *p = *buf++;
+ } else
+- maybebadio(outsl, port);
++ maybebadio(port);
+ }
+
+-void *hs7751rvoip_ioremap(unsigned long offset, unsigned long size)
++void __iomem *hs7751rvoip_ioport_map(unsigned long port, unsigned int size)
+ {
+- if (offset >= 0xfd000000)
+- return (void *)offset;
+- else
+- return (void *)P2SEGADDR(offset);
+-}
+-EXPORT_SYMBOL(hs7751rvoip_ioremap);
++ if (PXSEG(port))
++ return (void __iomem *)port;
++ else if (unlikely(codec_port(port) && (size == 1)))
++ return (void __iomem *)CODEC_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return (void __iomem *)pci_ioaddr(port);
+
+-unsigned long hs7751rvoip_isa_port2addr(unsigned long offset)
+-{
+- return port2adr(offset);
++ return (void __iomem *)port2adr(port);
+ }
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c
+index 705b7dd..943f93a 100644
+--- a/arch/sh/boards/renesas/hs7751rvoip/irq.c
++++ b/arch/sh/boards/renesas/hs7751rvoip/irq.c
+@@ -14,7 +14,7 @@
+ #include <linux/irq.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+-#include <asm/hs7751rvoip/hs7751rvoip.h>
++#include <asm/hs7751rvoip.h>
+
+ static int mask_pos[] = {8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7};
+
+@@ -35,30 +35,24 @@ static unsigned int startup_hs7751rvoip_
+
+ static void disable_hs7751rvoip_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short val;
+ unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
+
+ /* Set the priority in IPR to 0 */
+- local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR3);
+ val &= mask;
+ ctrl_outw(val, IRLCNTR3);
+- local_irq_restore(flags);
+ }
+
+ static void enable_hs7751rvoip_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short val;
+ unsigned short value = (0x0001 << mask_pos[irq]);
+
+ /* Set priority in IPR back to original value */
+- local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR3);
+ val |= value;
+ ctrl_outw(val, IRLCNTR3);
+- local_irq_restore(flags);
+ }
+
+ static void ack_hs7751rvoip_irq(unsigned int irq)
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/led.c b/arch/sh/boards/renesas/hs7751rvoip/led.c
+deleted file mode 100644
+index b6608ff..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/led.c
++++ /dev/null
+@@ -1,26 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/setup_hs7751rvoip.c
+- *
+- * Copyright (C) 2000 Kazumoto Kojima
+- *
+- * Renesas Technology Sales HS7751RVoIP Support.
+- *
+- * Modified for HS7751RVoIP by
+- * Atom Create Engineering Co., Ltd. 2002.
+- * Lineo uSolutions, Inc. 2003.
+- */
+-
+-#include <asm/io.h>
+-#include <asm/hs7751rvoip/hs7751rvoip.h>
+-
+-extern unsigned int debug_counter;
+-
+-void debug_led_disp(void)
+-{
+- unsigned short value;
+-
+- value = (unsigned char)debug_counter++;
+- ctrl_outb((0xf0|value), PA_OUTPORTR);
+- if (value == 0x0f)
+- debug_counter = 0;
+-}
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/mach.c b/arch/sh/boards/renesas/hs7751rvoip/mach.c
+deleted file mode 100644
+index caf967f..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/mach.c
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/mach_hs7751rvoip.c
+- *
+- * Minor tweak of mach_se.c file to reference hs7751rvoip-specific items.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the Renesas Technology sales HS7751RVoIP
+- */
+-
+-#include <linux/init.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/irq.h>
+-#include <asm/hs7751rvoip/io.h>
+-
+-extern void init_hs7751rvoip_IRQ(void);
+-extern void *hs7751rvoip_ioremap(unsigned long, unsigned long);
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_hs7751rvoip __initmv = {
+- .mv_nr_irqs = 72,
+-
+- .mv_inb = hs7751rvoip_inb,
+- .mv_inw = hs7751rvoip_inw,
+- .mv_inl = hs7751rvoip_inl,
+- .mv_outb = hs7751rvoip_outb,
+- .mv_outw = hs7751rvoip_outw,
+- .mv_outl = hs7751rvoip_outl,
+-
+- .mv_inb_p = hs7751rvoip_inb_p,
+- .mv_inw_p = hs7751rvoip_inw,
+- .mv_inl_p = hs7751rvoip_inl,
+- .mv_outb_p = hs7751rvoip_outb_p,
+- .mv_outw_p = hs7751rvoip_outw,
+- .mv_outl_p = hs7751rvoip_outl,
+-
+- .mv_insb = hs7751rvoip_insb,
+- .mv_insw = hs7751rvoip_insw,
+- .mv_insl = hs7751rvoip_insl,
+- .mv_outsb = hs7751rvoip_outsb,
+- .mv_outsw = hs7751rvoip_outsw,
+- .mv_outsl = hs7751rvoip_outsl,
+-
+- .mv_ioremap = hs7751rvoip_ioremap,
+- .mv_isa_port2addr = hs7751rvoip_isa_port2addr,
+- .mv_init_irq = init_hs7751rvoip_IRQ,
+-};
+-ALIAS_MV(hs7751rvoip)
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c
+index 7e5786b..1c0ddee 100644
+--- a/arch/sh/boards/renesas/hs7751rvoip/pci.c
++++ b/arch/sh/boards/renesas/hs7751rvoip/pci.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/pci-hs7751rvoip.c
++ * linux/arch/sh/boards/renesas/hs7751rvoip/pci.c
+ *
+ * Author: Ian DaSilva (idasilva at mvista.com)
+ *
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c
+index 29fb5ff..f7d0e30 100644
+--- a/arch/sh/boards/renesas/hs7751rvoip/setup.c
++++ b/arch/sh/boards/renesas/hs7751rvoip/setup.c
+@@ -1,44 +1,37 @@
+ /*
+- * linux/arch/sh/kernel/setup_hs7751rvoip.c
++ * Renesas Technology Sales HS7751RVoIP Support.
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+- * Renesas Technology Sales HS7751RVoIP Support.
+- *
+ * Modified for HS7751RVoIP by
+ * Atom Create Engineering Co., Ltd. 2002.
+ * Lineo uSolutions, Inc. 2003.
+ */
+-
+ #include <linux/init.h>
+ #include <linux/irq.h>
+-
+-#include <linux/hdreg.h>
+-#include <linux/ide.h>
+-#include <asm/io.h>
+-#include <asm/hs7751rvoip/hs7751rvoip.h>
+-
+ #include <linux/mm.h>
+-#include <linux/vmalloc.h>
+-
+-/* defined in mm/ioremap.c */
+-extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
++#include <linux/pm.h>
++#include <asm/hs7751rvoip.h>
++#include <asm/io.h>
++#include <asm/machvec.h>
+
+-unsigned int debug_counter;
++static struct ipr_data hs77501rvoip_ipr_map[] = {
++#if defined(CONFIG_HS7751RVOIP_CODEC)
++ { DMTE0_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE1_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++#endif
++};
+
+-const char *get_system_type(void)
++static void __init hs7751rvoip_init_irq(void)
+ {
+- return "HS7751RVoIP";
++ make_ipr_irq(hs77501rvoip_ipr_map, ARRAY_SIZE(hs77501rvoip_ipr_map));
++
++ init_hs7751rvoip_IRQ();
+ }
+
+-/*
+- * Initialize the board
+- */
+-void __init platform_setup(void)
++static void hs7751rvoip_power_off(void)
+ {
+- printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
+- ctrl_outb(0xf0, PA_OUTPORTR);
+- debug_counter = 0;
++ ctrl_outw(ctrl_inw(PA_OUTPORTR) & 0xffdf, PA_OUTPORTR);
+ }
+
+ void *area5_io8_base;
+@@ -46,16 +39,15 @@ void *area6_io8_base;
+ void *area5_io16_base;
+ void *area6_io16_base;
+
+-int __init cf_init(void)
++static int __init hs7751rvoip_cf_init(void)
+ {
+ pgprot_t prot;
+- unsigned long paddrbase, psize;
++ unsigned long paddrbase;
+
+ /* open I/O area window */
+ paddrbase = virt_to_phys((void *)(PA_AREA5_IO+0x00000800));
+- psize = PAGE_SIZE;
+ prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_COM16);
+- area5_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot);
++ area5_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+ if (!area5_io16_base) {
+ printk("allocate_cf_area : can't open CF I/O window!\n");
+ return -ENOMEM;
+@@ -64,19 +56,18 @@ int __init cf_init(void)
+ /* XXX : do we need attribute and common-memory area also? */
+
+ paddrbase = virt_to_phys((void *)PA_AREA6_IO);
+- psize = PAGE_SIZE;
+ #if defined(CONFIG_HS7751RVOIP_CODEC)
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_COM8);
+ #else
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO8);
+ #endif
+- area6_io8_base = p3_ioremap(paddrbase, psize, prot.pgprot);
++ area6_io8_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+ if (!area6_io8_base) {
+ printk("allocate_cf_area : can't open CODEC I/O 8bit window!\n");
+ return -ENOMEM;
+ }
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
+- area6_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot);
++ area6_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+ if (!area6_io16_base) {
+ printk("allocate_cf_area : can't open CODEC I/O 16bit window!\n");
+ return -ENOMEM;
+@@ -85,4 +76,46 @@ int __init cf_init(void)
+ return 0;
+ }
+
+-__initcall (cf_init);
++/*
++ * Initialize the board
++ */
++static void __init hs7751rvoip_setup(char **cmdline_p)
++{
++ device_initcall(hs7751rvoip_cf_init);
++
++ ctrl_outb(0xf0, PA_OUTPORTR);
++ pm_power_off = hs7751rvoip_power_off;
++
++ printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
++}
++
++struct sh_machine_vector mv_hs7751rvoip __initmv = {
++ .mv_name = "HS7751RVoIP",
++ .mv_setup = hs7751rvoip_setup,
++ .mv_nr_irqs = 72,
++
++ .mv_inb = hs7751rvoip_inb,
++ .mv_inw = hs7751rvoip_inw,
++ .mv_inl = hs7751rvoip_inl,
++ .mv_outb = hs7751rvoip_outb,
++ .mv_outw = hs7751rvoip_outw,
++ .mv_outl = hs7751rvoip_outl,
++
++ .mv_inb_p = hs7751rvoip_inb_p,
++ .mv_inw_p = hs7751rvoip_inw,
++ .mv_inl_p = hs7751rvoip_inl,
++ .mv_outb_p = hs7751rvoip_outb_p,
++ .mv_outw_p = hs7751rvoip_outw,
++ .mv_outl_p = hs7751rvoip_outl,
++
++ .mv_insb = hs7751rvoip_insb,
++ .mv_insw = hs7751rvoip_insw,
++ .mv_insl = hs7751rvoip_insl,
++ .mv_outsb = hs7751rvoip_outsb,
++ .mv_outsw = hs7751rvoip_outsw,
++ .mv_outsl = hs7751rvoip_outsl,
++
++ .mv_init_irq = hs7751rvoip_init_irq,
++ .mv_ioport_map = hs7751rvoip_ioport_map,
++};
++ALIAS_MV(hs7751rvoip)
+diff --git a/arch/sh/boards/renesas/r7780rp/Kconfig b/arch/sh/boards/renesas/r7780rp/Kconfig
+new file mode 100644
+index 0000000..c26d981
+--- /dev/null
++++ b/arch/sh/boards/renesas/r7780rp/Kconfig
+@@ -0,0 +1,14 @@
++if SH_R7780RP
++
++menu "R7780RP options"
++
++config SH_R7780MP
++ bool "R7780MP board support"
++ default y
++ help
++ Selecting this option will enable support for the mass-production
++ version of the R7780RP. If in doubt, say Y.
++
++endmenu
++
++endif
+diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
+new file mode 100644
+index 0000000..f1776d0
+--- /dev/null
++++ b/arch/sh/boards/renesas/r7780rp/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for the R7780RP-1 specific parts of the kernel
++#
++
++obj-y := setup.o io.o irq.o
++obj-$(CONFIG_HEARTBEAT) += led.o
+diff --git a/arch/sh/boards/renesas/r7780rp/io.c b/arch/sh/boards/renesas/r7780rp/io.c
+new file mode 100644
+index 0000000..311cccc
+--- /dev/null
++++ b/arch/sh/boards/renesas/r7780rp/io.c
+@@ -0,0 +1,301 @@
++/*
++ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
++ * Based largely on io_se.c.
++ *
++ * I/O routine for Renesas Solutions Highlander R7780RP-1
++ *
++ * Initial version only to support LAN access; some
++ * placeholder code from io_r7780rp.c left in with the
++ * expectation of later SuperIO and PCMCIA access.
++ */
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <asm/r7780rp.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++
++static inline unsigned long port2adr(unsigned int port)
++{
++ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
++ if (port == 0x3f6)
++ return (PA_AREA5_IO + 0x80c);
++ else
++ return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1));
++ else
++ maybebadio((unsigned long)port);
++
++ return port;
++}
++
++static inline unsigned long port88796l(unsigned int port, int flag)
++{
++ unsigned long addr;
++
++ if (flag)
++ addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1);
++ else
++ addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1) + 0x1000;
++
++ return addr;
++}
++
++/* The 7780 R7780RP-1 seems to have everything hooked */
++/* up pretty normally (nothing on high-bytes only...) so this */
++/* shouldn't be needed */
++static inline int shifted_port(unsigned long port)
++{
++ /* For IDE registers, value is not shifted */
++ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
++ return 0;
++ else
++ return 1;
++}
++
++#if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE)
++#define CHECK_AX88796L_PORT(port) \
++ ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20)))
++#else
++#define CHECK_AX88796L_PORT(port) (0)
++#endif
++
++/*
++ * General outline: remap really low stuff [eventually] to SuperIO,
++ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
++ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
++ * should be way beyond the window, and is used w/o translation for
++ * compatibility.
++ */
++u8 r7780rp_inb(unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ return ctrl_inw(port88796l(port, 0)) & 0xff;
++ else if (PXSEG(port))
++ return ctrl_inb(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return ctrl_inb(pci_ioaddr(port));
++
++ return ctrl_inw(port2adr(port)) & 0xff;
++}
++
++u8 r7780rp_inb_p(unsigned long port)
++{
++ u8 v;
++
++ if (CHECK_AX88796L_PORT(port))
++ v = ctrl_inw(port88796l(port, 0)) & 0xff;
++ else if (PXSEG(port))
++ v = ctrl_inb(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ v = ctrl_inb(pci_ioaddr(port));
++ else
++ v = ctrl_inw(port2adr(port)) & 0xff;
++
++ ctrl_delay();
++
++ return v;
++}
++
++u16 r7780rp_inw(unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ maybebadio(port);
++ else if (PXSEG(port))
++ return ctrl_inw(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return ctrl_inw(pci_ioaddr(port));
++ else
++ maybebadio(port);
++
++ return 0;
++}
++
++u32 r7780rp_inl(unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ maybebadio(port);
++ else if (PXSEG(port))
++ return ctrl_inl(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return ctrl_inl(pci_ioaddr(port));
++ else
++ maybebadio(port);
++
++ return 0;
++}
++
++void r7780rp_outb(u8 value, unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ ctrl_outw(value, port88796l(port, 0));
++ else if (PXSEG(port))
++ ctrl_outb(value, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outb(value, pci_ioaddr(port));
++ else
++ ctrl_outw(value, port2adr(port));
++}
++
++void r7780rp_outb_p(u8 value, unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ ctrl_outw(value, port88796l(port, 0));
++ else if (PXSEG(port))
++ ctrl_outb(value, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outb(value, pci_ioaddr(port));
++ else
++ ctrl_outw(value, port2adr(port));
++
++ ctrl_delay();
++}
++
++void r7780rp_outw(u16 value, unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ maybebadio(port);
++ else if (PXSEG(port))
++ ctrl_outw(value, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outw(value, pci_ioaddr(port));
++ else
++ maybebadio(port);
++}
++
++void r7780rp_outl(u32 value, unsigned long port)
++{
++ if (CHECK_AX88796L_PORT(port))
++ maybebadio(port);
++ else if (PXSEG(port))
++ ctrl_outl(value, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ ctrl_outl(value, pci_ioaddr(port));
++ else
++ maybebadio(port);
++}
++
++void r7780rp_insb(unsigned long port, void *dst, unsigned long count)
++{
++ volatile u16 *p;
++ u8 *buf = dst;
++
++ if (CHECK_AX88796L_PORT(port)) {
++ p = (volatile u16 *)port88796l(port, 0);
++ while (count--)
++ *buf++ = *p & 0xff;
++ } else if (PXSEG(port)) {
++ while (count--)
++ *buf++ = *(volatile u8 *)port;
++ } else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
++
++ while (count--)
++ *buf++ = *bp;
++ } else {
++ p = (volatile u16 *)port2adr(port);
++ while (count--)
++ *buf++ = *p & 0xff;
++ }
++}
++
++void r7780rp_insw(unsigned long port, void *dst, unsigned long count)
++{
++ volatile u16 *p;
++ u16 *buf = dst;
++
++ if (CHECK_AX88796L_PORT(port))
++ p = (volatile u16 *)port88796l(port, 1);
++ else if (PXSEG(port))
++ p = (volatile u16 *)port;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ p = (volatile u16 *)pci_ioaddr(port);
++ else
++ p = (volatile u16 *)port2adr(port);
++
++ while (count--)
++ *buf++ = *p;
++}
++
++void r7780rp_insl(unsigned long port, void *dst, unsigned long count)
++{
++ u32 *buf = dst;
++
++ if (CHECK_AX88796L_PORT(port))
++ maybebadio(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
++
++ while (count--)
++ *buf++ = *p;
++ } else
++ maybebadio(port);
++}
++
++void r7780rp_outsb(unsigned long port, const void *src, unsigned long count)
++{
++ volatile u16 *p;
++ const u8 *buf = src;
++
++ if (CHECK_AX88796L_PORT(port)) {
++ p = (volatile u16 *)port88796l(port, 0);
++ while (count--)
++ *p = *buf++;
++ } else if (PXSEG(port))
++ while (count--)
++ ctrl_outb(*buf++, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
++
++ while (count--)
++ *bp = *buf++;
++ } else {
++ p = (volatile u16 *)port2adr(port);
++ while (count--)
++ *p = *buf++;
++ }
++}
++
++void r7780rp_outsw(unsigned long port, const void *src, unsigned long count)
++{
++ volatile u16 *p;
++ const u16 *buf = src;
++
++ if (CHECK_AX88796L_PORT(port))
++ p = (volatile u16 *)port88796l(port, 1);
++ else if (PXSEG(port))
++ p = (volatile u16 *)port;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ p = (volatile u16 *)pci_ioaddr(port);
++ else
++ p = (volatile u16 *)port2adr(port);
++
++ while (count--)
++ *p = *buf++;
++}
++
++void r7780rp_outsl(unsigned long port, const void *src, unsigned long count)
++{
++ const u32 *buf = src;
++
++ if (CHECK_AX88796L_PORT(port))
++ maybebadio(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
++
++ while (count--)
++ *p = *buf++;
++ } else
++ maybebadio(port);
++}
++
++void __iomem *r7780rp_ioport_map(unsigned long port, unsigned int size)
++{
++ if (CHECK_AX88796L_PORT(port))
++ return (void __iomem *)port88796l(port, size > 1);
++ else if (PXSEG(port))
++ return (void __iomem *)port;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return (void __iomem *)pci_ioaddr(port);
++
++ return (void __iomem *)port2adr(port);
++}
+diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c
+new file mode 100644
+index 0000000..aa15ec5
+--- /dev/null
++++ b/arch/sh/boards/renesas/r7780rp/irq.c
+@@ -0,0 +1,55 @@
++/*
++ * Renesas Solutions Highlander R7780RP-1 Support.
++ *
++ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/init.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <asm/r7780rp.h>
++
++#ifdef CONFIG_SH_R7780MP
++static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
++#else
++static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0};
++#endif
++
++static void enable_r7780rp_irq(unsigned int irq)
++{
++ /* Set priority in IPR back to original value */
++ ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1);
++}
++
++static void disable_r7780rp_irq(unsigned int irq)
++{
++ /* Set the priority in IPR to 0 */
++ ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])),
++ IRLCNTR1);
++}
++
++static struct irq_chip r7780rp_irq_chip __read_mostly = {
++ .name = "R7780RP",
++ .mask = disable_r7780rp_irq,
++ .unmask = enable_r7780rp_irq,
++ .mask_ack = disable_r7780rp_irq,
++};
++
++/*
++ * Initialize IRQ setting
++ */
++void __init init_r7780rp_IRQ(void)
++{
++ int i;
++
++ for (i = 0; i < 15; i++) {
++ disable_irq_nosync(i);
++ set_irq_chip_and_handler_name(i, &r7780rp_irq_chip,
++ handle_level_irq, "level");
++ enable_r7780rp_irq(i);
++ }
++}
+diff --git a/arch/sh/boards/renesas/r7780rp/led.c b/arch/sh/boards/renesas/r7780rp/led.c
+new file mode 100644
+index 0000000..6a00a25
+--- /dev/null
++++ b/arch/sh/boards/renesas/r7780rp/led.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (C) Atom Create Engineering Co., Ltd.
++ *
++ * May be copied or modified under the terms of GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ * This file contains Renesas Solutions HIGHLANDER R7780RP-1 specific LED code.
++ */
++#include <linux/sched.h>
++#include <asm/io.h>
++#include <asm/r7780rp/r7780rp.h>
++
++/* Cycle the LED's in the clasic Knightriger/Sun pattern */
++void heartbeat_r7780rp(void)
++{
++ static unsigned int cnt = 0, period = 0;
++ volatile unsigned short *p = (volatile unsigned short *)PA_OBLED;
++ static unsigned bit = 0, up = 1;
++ unsigned bit_pos[] = {2, 1, 0, 3, 6, 5, 4, 7};
++
++ cnt += 1;
++ if (cnt < period)
++ return;
++
++ cnt = 0;
++
++ /* Go through the points (roughly!):
++ * f(0)=10, f(1)=16, f(2)=20, f(5)=35, f(int)->110
++ */
++ period = 110 - ((300 << FSHIFT)/((avenrun[0]/5) + (3<<FSHIFT)));
++
++ *p = 1 << bit_pos[bit];
++ if (up)
++ if (bit == 7) {
++ bit--;
++ up = 0;
++ } else
++ bit++;
++ else if (bit == 0)
++ up = 1;
++ else
++ bit--;
++}
+diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
+new file mode 100644
+index 0000000..c331cae
+--- /dev/null
++++ b/arch/sh/boards/renesas/r7780rp/setup.c
+@@ -0,0 +1,163 @@
++/*
++ * arch/sh/boards/renesas/r7780rp/setup.c
++ *
++ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
++ * Copyright (C) 2005, 2006 Paul Mundt
++ *
++ * Renesas Solutions Highlander R7780RP-1 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.
++ */
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <asm/machvec.h>
++#include <asm/r7780rp.h>
++#include <asm/clock.h>
++#include <asm/io.h>
++
++extern void heartbeat_r7780rp(void);
++extern void init_r7780rp_IRQ(void);
++
++static struct resource m66596_usb_host_resources[] = {
++ [0] = {
++ .start = 0xa4800000,
++ .end = 0xa4ffffff,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = 6, /* irq number */
++ .end = 6,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device m66596_usb_host_device = {
++ .name = "m66596-hcd",
++ .id = 0,
++ .dev = {
++ .dma_mask = NULL, /* don't use dma */
++ .coherent_dma_mask = 0xffffffff,
++ },
++ .num_resources = ARRAY_SIZE(m66596_usb_host_resources),
++ .resource = m66596_usb_host_resources,
++};
++
++static struct platform_device *r7780rp_devices[] __initdata = {
++ &m66596_usb_host_device,
++};
++
++static int __init r7780rp_devices_setup(void)
++{
++ return platform_add_devices(r7780rp_devices,
++ ARRAY_SIZE(r7780rp_devices));
++}
++
++/*
++ * Platform specific clocks
++ */
++static void ivdr_clk_enable(struct clk *clk)
++{
++ ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << 8), PA_IVDRCTL);
++}
++
++static void ivdr_clk_disable(struct clk *clk)
++{
++ ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << 8), PA_IVDRCTL);
++}
++
++static struct clk_ops ivdr_clk_ops = {
++ .enable = ivdr_clk_enable,
++ .disable = ivdr_clk_disable,
++};
++
++static struct clk ivdr_clk = {
++ .name = "ivdr_clk",
++ .ops = &ivdr_clk_ops,
++};
++
++static struct clk *r7780rp_clocks[] = {
++ &ivdr_clk,
++};
++
++static void r7780rp_power_off(void)
++{
++#ifdef CONFIG_SH_R7780MP
++ ctrl_outw(0x0001, PA_POFF);
++#endif
++}
++
++/*
++ * Initialize the board
++ */
++static void __init r7780rp_setup(char **cmdline_p)
++{
++ u16 ver = ctrl_inw(PA_VERREG);
++ int i;
++
++ device_initcall(r7780rp_devices_setup);
++
++ printk(KERN_INFO "Renesas Solutions Highlander R7780RP-1 support.\n");
++
++ printk(KERN_INFO "Board version: %d (revision %d), "
++ "FPGA version: %d (revision %d)\n",
++ (ver >> 12) & 0xf, (ver >> 8) & 0xf,
++ (ver >> 4) & 0xf, ver & 0xf);
++
++ /*
++ * Enable the important clocks right away..
++ */
++ for (i = 0; i < ARRAY_SIZE(r7780rp_clocks); i++) {
++ struct clk *clk = r7780rp_clocks[i];
++
++ clk_register(clk);
++ clk_enable(clk);
++ }
++
++ ctrl_outw(0x0000, PA_OBLED); /* Clear LED. */
++#ifndef CONFIG_SH_R7780MP
++ ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */
++#endif
++ ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x0100, PA_IVDRCTL); /* Si13112 */
++
++ pm_power_off = r7780rp_power_off;
++}
++
++/*
++ * The Machine Vector
++ */
++struct sh_machine_vector mv_r7780rp __initmv = {
++ .mv_name = "Highlander R7780RP-1",
++ .mv_setup = r7780rp_setup,
++
++ .mv_nr_irqs = 109,
++
++ .mv_inb = r7780rp_inb,
++ .mv_inw = r7780rp_inw,
++ .mv_inl = r7780rp_inl,
++ .mv_outb = r7780rp_outb,
++ .mv_outw = r7780rp_outw,
++ .mv_outl = r7780rp_outl,
++
++ .mv_inb_p = r7780rp_inb_p,
++ .mv_inw_p = r7780rp_inw,
++ .mv_inl_p = r7780rp_inl,
++ .mv_outb_p = r7780rp_outb_p,
++ .mv_outw_p = r7780rp_outw,
++ .mv_outl_p = r7780rp_outl,
++
++ .mv_insb = r7780rp_insb,
++ .mv_insw = r7780rp_insw,
++ .mv_insl = r7780rp_insl,
++ .mv_outsb = r7780rp_outsb,
++ .mv_outsw = r7780rp_outsw,
++ .mv_outsl = r7780rp_outsl,
++
++ .mv_ioport_map = r7780rp_ioport_map,
++ .mv_init_irq = init_r7780rp_IRQ,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_r7780rp,
++#endif
++};
++ALIAS_MV(r7780rp)
+diff --git a/arch/sh/boards/renesas/rts7751r2d/Kconfig b/arch/sh/boards/renesas/rts7751r2d/Kconfig
+new file mode 100644
+index 0000000..7780d1f
+--- /dev/null
++++ b/arch/sh/boards/renesas/rts7751r2d/Kconfig
+@@ -0,0 +1,12 @@
++if SH_RTS7751R2D
++
++menu "RTS7751R2D options"
++
++config RTS7751R2D_REV11
++ bool "RTS7751R2D Rev. 1.1 board support"
++ help
++ Selecting this option will support version rev. 1.1.
++endmenu
++
++endif
++
+diff --git a/arch/sh/boards/renesas/rts7751r2d/Makefile b/arch/sh/boards/renesas/rts7751r2d/Makefile
+index daa5333..686fc9e 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/Makefile
++++ b/arch/sh/boards/renesas/rts7751r2d/Makefile
+@@ -1,10 +1,6 @@
+ #
+ # Makefile for the RTS7751R2D specific parts of the kernel
+ #
+-# 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).
+-#
+-
+-obj-y := mach.o setup.o io.o irq.o led.o
+
++obj-y := setup.o io.o irq.o
++obj-$(CONFIG_HEARTBEAT) += led.o
+diff --git a/arch/sh/boards/renesas/rts7751r2d/io.c b/arch/sh/boards/renesas/rts7751r2d/io.c
+index 123abbb..f2507a8 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/io.c
++++ b/arch/sh/boards/renesas/rts7751r2d/io.c
+@@ -1,6 +1,4 @@
+ /*
+- * linux/arch/sh/kernel/io_rts7751r2d.c
+- *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+@@ -10,16 +8,12 @@
+ * placeholder code from io_rts7751r2d.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+-#include <asm/io.h>
+-#include <asm/rts7751r2d/rts7751r2d.h>
+-#include <asm/addrspace.h>
+-
+-#include <linux/module.h>
+ #include <linux/pci.h>
+-#include "../../../drivers/pci/pci-sh7751.h"
++#include <linux/io.h>
++#include <asm/rts7751r2d.h>
++#include <asm/addrspace.h>
+
+ /*
+ * The 7751R RTS7751R2D uses the built-in PCI controller (PCIC)
+@@ -28,22 +22,6 @@
+ * like the other Solution Engine boards.
+ */
+
+-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+-#define PCI_IO_AREA SH7751_PCI_IO_BASE
+-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+-
+-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+-
+-#define maybebadio(name,port) \
+- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+- #name, (port), (__u32) __builtin_return_address(0))
+-
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
+-
+ static inline unsigned long port2adr(unsigned int port)
+ {
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+@@ -52,7 +30,7 @@ static inline unsigned long port2adr(uns
+ else
+ return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1));
+ else
+- maybebadio(port2adr, (unsigned long)port);
++ maybebadio((unsigned long)port);
+
+ return port;
+ }
+@@ -81,17 +59,6 @@ static inline int shifted_port(unsigned
+ return 1;
+ }
+
+-/* In case someone configures the kernel w/o PCI support: in that */
+-/* scenario, don't ever bother to check for PCI-window addresses */
+-
+-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+-#if defined(CONFIG_PCI)
+-#define CHECK_SH7751_PCIIO(port) \
+- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+-#else
+-#define CHECK_SH7751_PCIIO(port) (0)
+-#endif
+-
+ #if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE)
+ #define CHECK_AX88796L_PORT(port) \
+ ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20)))
+@@ -112,8 +79,8 @@ unsigned char rts7751r2d_inb(unsigned lo
+ return (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
+ else if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- return *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return *(volatile unsigned char *)pci_ioaddr(port);
+ else
+ return (*(volatile unsigned short *)port2adr(port) & 0xff);
+ }
+@@ -126,11 +93,12 @@ unsigned char rts7751r2d_inb_p(unsigned
+ v = (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
+ else if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- v = *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ v = *(volatile unsigned char *)pci_ioaddr(port);
+ else
+ v = (*(volatile unsigned short *)port2adr(port) & 0xff);
+- delay();
++
++ ctrl_delay();
+
+ return v;
+ }
+@@ -138,13 +106,13 @@ unsigned char rts7751r2d_inb_p(unsigned
+ unsigned short rts7751r2d_inw(unsigned long port)
+ {
+ if (CHECK_AX88796L_PORT(port))
+- maybebadio(inw, port);
++ maybebadio(port);
+ else if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- return *(volatile unsigned short *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return *(volatile unsigned short *)pci_ioaddr(port);
+ else
+- maybebadio(inw, port);
++ maybebadio(port);
+
+ return 0;
+ }
+@@ -152,13 +120,13 @@ unsigned short rts7751r2d_inw(unsigned l
+ unsigned int rts7751r2d_inl(unsigned long port)
+ {
+ if (CHECK_AX88796L_PORT(port))
+- maybebadio(inl, port);
++ maybebadio(port);
+ else if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- return *(volatile unsigned long *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ return *(volatile unsigned long *)pci_ioaddr(port);
+ else
+- maybebadio(inl, port);
++ maybebadio(port);
+
+ return 0;
+ }
+@@ -169,8 +137,8 @@ void rts7751r2d_outb(unsigned char value
+ *((volatile unsigned short *)port88796l(port, 0)) = value;
+ else if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(volatile unsigned char *)PCI_IOMAP(port) = value;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ *(volatile unsigned char *)pci_ioaddr(port) = value;
+ else
+ *(volatile unsigned short *)port2adr(port) = value;
+ }
+@@ -181,143 +149,152 @@ void rts7751r2d_outb_p(unsigned char val
+ *((volatile unsigned short *)port88796l(port, 0)) = value;
+ else if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(volatile unsigned char *)PCI_IOMAP(port) = value;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ *(volatile unsigned char *)pci_ioaddr(port) = value;
+ else
+ *(volatile unsigned short *)port2adr(port) = value;
+- delay();
++
++ ctrl_delay();
+ }
+
+ void rts7751r2d_outw(unsigned short value, unsigned long port)
+ {
+ if (CHECK_AX88796L_PORT(port))
+- maybebadio(outw, port);
++ maybebadio(port);
+ else if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(volatile unsigned short *)PCI_IOMAP(port) = value;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ *(volatile unsigned short *)pci_ioaddr(port) = value;
+ else
+- maybebadio(outw, port);
++ maybebadio(port);
+ }
+
+ void rts7751r2d_outl(unsigned int value, unsigned long port)
+ {
+ if (CHECK_AX88796L_PORT(port))
+- maybebadio(outl, port);
++ maybebadio(port);
+ else if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- *(volatile unsigned long *)PCI_IOMAP(port) = value;
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ *(volatile unsigned long *)pci_ioaddr(port) = value;
+ else
+- maybebadio(outl, port);
++ maybebadio(port);
+ }
+
+ void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count)
+ {
++ unsigned long a = (unsigned long)addr;
+ volatile __u8 *bp;
+ volatile __u16 *p;
+- unsigned char *s = addr;
+
+ if (CHECK_AX88796L_PORT(port)) {
+ p = (volatile unsigned short *)port88796l(port, 0);
+- while (count--) *s++ = *p & 0xff;
++ while (count--)
++ ctrl_outb(*p & 0xff, a++);
+ } else if (PXSEG(port))
+- while (count--) *s++ = *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- bp = (__u8 *)PCI_IOMAP(port);
+- while (count--) *s++ = *bp;
++ while (count--)
++ ctrl_outb(ctrl_inb(port), a++);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ bp = (__u8 *)pci_ioaddr(port);
++ while (count--)
++ ctrl_outb(*bp, a++);
+ } else {
+ p = (volatile unsigned short *)port2adr(port);
+- while (count--) *s++ = *p & 0xff;
++ while (count--)
++ ctrl_outb(*p & 0xff, a++);
+ }
+ }
+
+ void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count)
+ {
++ unsigned long a = (unsigned long)addr;
+ volatile __u16 *p;
+- __u16 *s = addr;
+
+ if (CHECK_AX88796L_PORT(port))
+ p = (volatile unsigned short *)port88796l(port, 1);
+ else if (PXSEG(port))
+ p = (volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- p = (volatile unsigned short *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ p = (volatile unsigned short *)pci_ioaddr(port);
+ else
+ p = (volatile unsigned short *)port2adr(port);
+- while (count--) *s++ = *p;
++ while (count--)
++ ctrl_outw(*p, a++);
+ }
+
+ void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count)
+ {
+ if (CHECK_AX88796L_PORT(port))
+- maybebadio(insl, port);
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+- __u32 *s = addr;
+-
+- while (count--) *s++ = *p;
++ maybebadio(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ unsigned long a = (unsigned long)addr;
++
++ while (count--) {
++ ctrl_outl(ctrl_inl(pci_ioaddr(port)), a);
++ a += 4;
++ }
+ } else
+- maybebadio(insl, port);
++ maybebadio(port);
+ }
+
+ void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count)
+ {
++ unsigned long a = (unsigned long)addr;
+ volatile __u8 *bp;
+ volatile __u16 *p;
+- const __u8 *s = addr;
+
+ if (CHECK_AX88796L_PORT(port)) {
+ p = (volatile unsigned short *)port88796l(port, 0);
+- while (count--) *p = *s++;
++ while (count--)
++ *p = ctrl_inb(a++);
+ } else if (PXSEG(port))
+- while (count--) *(volatile unsigned char *)port = *s++;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- bp = (__u8 *)PCI_IOMAP(port);
+- while (count--) *bp = *s++;
++ while (count--)
++ ctrl_outb(a++, port);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ bp = (__u8 *)pci_ioaddr(port);
++ while (count--)
++ *bp = ctrl_inb(a++);
+ } else {
+ p = (volatile unsigned short *)port2adr(port);
+- while (count--) *p = *s++;
++ while (count--)
++ *p = ctrl_inb(a++);
+ }
+ }
+
+ void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count)
+ {
++ unsigned long a = (unsigned long)addr;
+ volatile __u16 *p;
+- const __u16 *s = addr;
+
+ if (CHECK_AX88796L_PORT(port))
+ p = (volatile unsigned short *)port88796l(port, 1);
+ else if (PXSEG(port))
+ p = (volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+- p = (volatile unsigned short *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port))
++ p = (volatile unsigned short *)pci_ioaddr(port);
+ else
+ p = (volatile unsigned short *)port2adr(port);
+- while (count--) *p = *s++;
++
++ while (count--) {
++ ctrl_outw(*p, a);
++ a += 2;
++ }
+ }
+
+ void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count)
+ {
+ if (CHECK_AX88796L_PORT(port))
+- maybebadio(outsl, port);
+- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+- const __u32 *s = addr;
+-
+- while (count--) *p = *s++;
++ maybebadio(port);
++ else if (is_pci_ioaddr(port) || shifted_port(port)) {
++ unsigned long a = (unsigned long)addr;
++
++ while (count--) {
++ ctrl_outl(ctrl_inl(a), pci_ioaddr(port));
++ a += 4;
++ }
+ } else
+- maybebadio(outsl, port);
+-}
+-
+-void *rts7751r2d_ioremap(unsigned long offset, unsigned long size)
+-{
+- if (offset >= 0xfd000000)
+- return (void *)offset;
+- else
+- return (void *)P2SEGADDR(offset);
++ maybebadio(port);
+ }
+-EXPORT_SYMBOL(rts7751r2d_ioremap);
+
+ unsigned long rts7751r2d_isa_port2addr(unsigned long offset)
+ {
+diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c
+index 1545354..cb0eb20 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/irq.c
++++ b/arch/sh/boards/renesas/rts7751r2d/irq.c
+@@ -8,12 +8,10 @@
+ * Modified for RTS7751R2D by
+ * Atom Create Engineering Co., Ltd. 2002.
+ */
+-
+ #include <linux/init.h>
+ #include <linux/irq.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/rts7751r2d/rts7751r2d.h>
++#include <linux/io.h>
++#include <asm/rts7751r2d.h>
+
+ #if defined(CONFIG_RTS7751R2D_REV11)
+ static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0};
+@@ -41,30 +39,24 @@ static unsigned int startup_rts7751r2d_i
+
+ static void disable_rts7751r2d_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short val;
+ unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
+
+ /* Set the priority in IPR to 0 */
+- local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR1);
+ val &= mask;
+ ctrl_outw(val, IRLCNTR1);
+- local_irq_restore(flags);
+ }
+
+ static void enable_rts7751r2d_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short val;
+ unsigned short value = (0x0001 << mask_pos[irq]);
+
+ /* Set priority in IPR back to original value */
+- local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR1);
+ val |= value;
+ ctrl_outw(val, IRLCNTR1);
+- local_irq_restore(flags);
+ }
+
+ int rts7751r2d_irq_demux(int irq)
+diff --git a/arch/sh/boards/renesas/rts7751r2d/led.c b/arch/sh/boards/renesas/rts7751r2d/led.c
+index 4d16de7..509f548 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/led.c
++++ b/arch/sh/boards/renesas/rts7751r2d/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/led_rts7751r2d.c
++ * linux/arch/sh/boards/renesas/rts7751r2d/led.c
+ *
+ * Copyright (C) Atom Create Engineering Co., Ltd.
+ *
+@@ -8,15 +8,9 @@
+ *
+ * This file contains Renesas Technology Sales RTS7751R2D specific LED code.
+ */
+-
+-#include <asm/io.h>
+-#include <asm/rts7751r2d/rts7751r2d.h>
+-
+-extern unsigned int debug_counter;
+-
+-#ifdef CONFIG_HEARTBEAT
+-
++#include <linux/io.h>
+ #include <linux/sched.h>
++#include <asm/rts7751r2d.h>
+
+ /* Cycle the LED's in the clasic Knightriger/Sun pattern */
+ void heartbeat_rts7751r2d(void)
+@@ -48,19 +42,3 @@ void heartbeat_rts7751r2d(void)
+ else
+ bit--;
+ }
+-#endif /* CONFIG_HEARTBEAT */
+-
+-void rts7751r2d_led(unsigned short value)
+-{
+- ctrl_outw(value, PA_OUTPORT);
+-}
+-
+-void debug_led_disp(void)
+-{
+- unsigned short value;
+-
+- value = (unsigned short)debug_counter++;
+- rts7751r2d_led(value);
+- if (value == 0xff)
+- debug_counter = 0;
+-}
+diff --git a/arch/sh/boards/renesas/rts7751r2d/mach.c b/arch/sh/boards/renesas/rts7751r2d/mach.c
+deleted file mode 100644
+index 5ed9e97..0000000
+--- a/arch/sh/boards/renesas/rts7751r2d/mach.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/mach_rts7751r2d.c
+- *
+- * Minor tweak of mach_se.c file to reference rts7751r2d-specific items.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the Renesas Technology sales RTS7751R2D
+- */
+-
+-#include <linux/init.h>
+-#include <linux/types.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/irq.h>
+-#include <asm/rts7751r2d/io.h>
+-
+-extern void heartbeat_rts7751r2d(void);
+-extern void init_rts7751r2d_IRQ(void);
+-extern void *rts7751r2d_ioremap(unsigned long, unsigned long);
+-extern int rts7751r2d_irq_demux(int irq);
+-
+-extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
+-extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_rts7751r2d __initmv = {
+- .mv_nr_irqs = 72,
+-
+- .mv_inb = rts7751r2d_inb,
+- .mv_inw = rts7751r2d_inw,
+- .mv_inl = rts7751r2d_inl,
+- .mv_outb = rts7751r2d_outb,
+- .mv_outw = rts7751r2d_outw,
+- .mv_outl = rts7751r2d_outl,
+-
+- .mv_inb_p = rts7751r2d_inb_p,
+- .mv_inw_p = rts7751r2d_inw,
+- .mv_inl_p = rts7751r2d_inl,
+- .mv_outb_p = rts7751r2d_outb_p,
+- .mv_outw_p = rts7751r2d_outw,
+- .mv_outl_p = rts7751r2d_outl,
+-
+- .mv_insb = rts7751r2d_insb,
+- .mv_insw = rts7751r2d_insw,
+- .mv_insl = rts7751r2d_insl,
+- .mv_outsb = rts7751r2d_outsb,
+- .mv_outsw = rts7751r2d_outsw,
+- .mv_outsl = rts7751r2d_outsl,
+-
+- .mv_ioremap = rts7751r2d_ioremap,
+- .mv_isa_port2addr = rts7751r2d_isa_port2addr,
+- .mv_init_irq = init_rts7751r2d_IRQ,
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_rts7751r2d,
+-#endif
+- .mv_irq_demux = rts7751r2d_irq_demux,
+-
+-#ifdef CONFIG_USB_OHCI_HCD
+- .mv_consistent_alloc = voyagergx_consistent_alloc,
+- .mv_consistent_free = voyagergx_consistent_free,
+-#endif
+-};
+-ALIAS_MV(rts7751r2d)
+diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
+index 2587fd1..5c042d3 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
++++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
+@@ -1,31 +1,142 @@
+ /*
+- * linux/arch/sh/kernel/setup_rts7751r2d.c
+- *
+- * Copyright (C) 2000 Kazumoto Kojima
+- *
+ * Renesas Technology Sales RTS7751R2D Support.
+ *
+- * Modified for RTS7751R2D by
+- * Atom Create Engineering Co., Ltd. 2002.
++ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
++ * Copyright (C) 2004 - 2006 Paul Mundt
++ *
++ * 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/init.h>
++#include <linux/platform_device.h>
++#include <linux/serial_8250.h>
++#include <linux/pm.h>
++#include <asm/machvec.h>
++#include <asm/mach/rts7751r2d.h>
+ #include <asm/io.h>
+-#include <asm/rts7751r2d/rts7751r2d.h>
++#include <asm/voyagergx.h>
++
++extern void heartbeat_rts7751r2d(void);
++extern void init_rts7751r2d_IRQ(void);
++extern int rts7751r2d_irq_demux(int irq);
++
++extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
++extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
++
++static struct plat_serial8250_port uart_platform_data[] = {
++ {
++ .membase = (void *)VOYAGER_UART_BASE,
++ .mapbase = VOYAGER_UART_BASE,
++ .iotype = UPIO_MEM,
++ .irq = VOYAGER_UART0_IRQ,
++ .flags = UPF_BOOT_AUTOCONF,
++ .regshift = 2,
++ .uartclk = (9600 * 16),
++ }, {
++ .flags = 0,
++ },
++};
++
++static void __init voyagergx_serial_init(void)
++{
++ unsigned long val;
++
++ /*
++ * GPIO Control
++ */
++ val = inl(GPIO_MUX_HIGH);
++ val |= 0x00001fe0;
++ outl(val, GPIO_MUX_HIGH);
++
++ /*
++ * Power Mode Gate
++ */
++ val = inl(POWER_MODE0_GATE);
++ val |= (POWER_MODE0_GATE_U0 | POWER_MODE0_GATE_U1);
++ outl(val, POWER_MODE0_GATE);
++
++ val = inl(POWER_MODE1_GATE);
++ val |= (POWER_MODE1_GATE_U0 | POWER_MODE1_GATE_U1);
++ outl(val, POWER_MODE1_GATE);
++}
++
++static struct platform_device uart_device = {
++ .name = "serial8250",
++ .id = -1,
++ .dev = {
++ .platform_data = uart_platform_data,
++ },
++};
++
++static struct platform_device *rts7751r2d_devices[] __initdata = {
++ &uart_device,
++};
+
+-unsigned int debug_counter;
++static int __init rts7751r2d_devices_setup(void)
++{
++ return platform_add_devices(rts7751r2d_devices,
++ ARRAY_SIZE(rts7751r2d_devices));
++}
+
+-const char *get_system_type(void)
++static void rts7751r2d_power_off(void)
+ {
+- return "RTS7751R2D";
++ ctrl_outw(0x0001, PA_POWOFF);
+ }
+
+ /*
+ * Initialize the board
+ */
+-void __init platform_setup(void)
++static void __init rts7751r2d_setup(char **cmdline_p)
+ {
+- printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
++ device_initcall(rts7751r2d_devices_setup);
++
+ ctrl_outw(0x0000, PA_OUTPORT);
+- debug_counter = 0;
++ pm_power_off = rts7751r2d_power_off;
++
++ voyagergx_serial_init();
++
++ printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
+ }
++
++/*
++ * The Machine Vector
++ */
++struct sh_machine_vector mv_rts7751r2d __initmv = {
++ .mv_name = "RTS7751R2D",
++ .mv_setup = rts7751r2d_setup,
++ .mv_nr_irqs = 72,
++
++ .mv_inb = rts7751r2d_inb,
++ .mv_inw = rts7751r2d_inw,
++ .mv_inl = rts7751r2d_inl,
++ .mv_outb = rts7751r2d_outb,
++ .mv_outw = rts7751r2d_outw,
++ .mv_outl = rts7751r2d_outl,
++
++ .mv_inb_p = rts7751r2d_inb_p,
++ .mv_inw_p = rts7751r2d_inw,
++ .mv_inl_p = rts7751r2d_inl,
++ .mv_outb_p = rts7751r2d_outb_p,
++ .mv_outw_p = rts7751r2d_outw,
++ .mv_outl_p = rts7751r2d_outl,
++
++ .mv_insb = rts7751r2d_insb,
++ .mv_insw = rts7751r2d_insw,
++ .mv_insl = rts7751r2d_insl,
++ .mv_outsb = rts7751r2d_outsb,
++ .mv_outsw = rts7751r2d_outsw,
++ .mv_outsl = rts7751r2d_outsl,
++
++ .mv_init_irq = init_rts7751r2d_IRQ,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_rts7751r2d,
++#endif
++ .mv_irq_demux = rts7751r2d_irq_demux,
++
++#ifdef CONFIG_USB_SM501
++ .mv_consistent_alloc = voyagergx_consistent_alloc,
++ .mv_consistent_free = voyagergx_consistent_free,
++#endif
++};
++ALIAS_MV(rts7751r2d)
+diff --git a/arch/sh/boards/renesas/sh7710voipgw/Makefile b/arch/sh/boards/renesas/sh7710voipgw/Makefile
+new file mode 100644
+index 0000000..7703756
+--- /dev/null
++++ b/arch/sh/boards/renesas/sh7710voipgw/Makefile
+@@ -0,0 +1 @@
++obj-y := setup.o
+diff --git a/arch/sh/boards/renesas/sh7710voipgw/setup.c b/arch/sh/boards/renesas/sh7710voipgw/setup.c
+new file mode 100644
+index 0000000..180810b
+--- /dev/null
++++ b/arch/sh/boards/renesas/sh7710voipgw/setup.c
+@@ -0,0 +1,96 @@
++/*
++ * Renesas Technology SH7710 VoIP Gateway
++ *
++ * Copyright (C) 2006 Ranjit Deshpande
++ * Kenati Technologies Inc.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ */
++#include <linux/init.h>
++#include <asm/machvec.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++static struct ipr_data sh7710voipgw_ipr_map[] = {
++ { TIMER2_IRQ, TIMER2_IPR_ADDR, TIMER2_IPR_POS, TIMER2_PRIORITY },
++ { WDT_IRQ, WDT_IPR_ADDR, WDT_IPR_POS, WDT_PRIORITY },
++
++ /* SCIF0 */
++ { SCIF0_ERI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
++ { SCIF0_RXI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
++ { SCIF0_BRI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
++ { SCIF0_TXI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
++
++ /* DMAC-1 */
++ { DMTE0_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE1_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE2_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE3_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++
++ /* DMAC-2 */
++ { DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY },
++ { DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY },
++
++ /* IPSEC */
++ { IPSEC_IRQ, IPSEC_IPR_ADDR, IPSEC_IPR_POS, IPSEC_PRIORITY },
++
++ /* EDMAC */
++ { EDMAC0_IRQ, EDMAC0_IPR_ADDR, EDMAC0_IPR_POS, EDMAC0_PRIORITY },
++ { EDMAC1_IRQ, EDMAC1_IPR_ADDR, EDMAC1_IPR_POS, EDMAC1_PRIORITY },
++ { EDMAC2_IRQ, EDMAC2_IPR_ADDR, EDMAC2_IPR_POS, EDMAC2_PRIORITY },
++
++ /* SIOF0 */
++ { SIOF0_ERI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++ { SIOF0_TXI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++ { SIOF0_RXI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++ { SIOF0_CCI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++
++ /* SIOF1 */
++ { SIOF1_ERI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS, SIOF1_PRIORITY },
++ { SIOF1_TXI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS, SIOF1_PRIORITY },
++ { SIOF1_RXI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS, SIOF1_PRIORITY },
++ { SIOF1_CCI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS, SIOF1_PRIORITY },
++
++ /* SLIC IRQ's */
++ { IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY },
++ { IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY },
++};
++
++/*
++ * Initialize IRQ setting
++ */
++static void __init sh7710voipgw_init_irq(void)
++{
++ /* Disable all interrupts in IPR registers */
++ ctrl_outw(0x0, INTC_IPRA);
++ ctrl_outw(0x0, INTC_IPRB);
++ ctrl_outw(0x0, INTC_IPRC);
++ ctrl_outw(0x0, INTC_IPRD);
++ ctrl_outw(0x0, INTC_IPRE);
++ ctrl_outw(0x0, INTC_IPRF);
++ ctrl_outw(0x0, INTC_IPRG);
++ ctrl_outw(0x0, INTC_IPRH);
++ ctrl_outw(0x0, INTC_IPRI);
++
++ /* Ack all interrupt sources in the IRR0 register */
++ ctrl_outb(0x3f, INTC_IRR0);
++
++ /* Use IRQ0 - IRQ3 as active low interrupt lines i.e. disable
++ * IRL mode.
++ */
++ ctrl_outw(0x2aa, INTC_ICR1);
++
++ make_ipr_irq(sh7710voipgw_ipr_map, ARRAY_SIZE(sh7710voipgw_ipr_map));
++}
++
++/*
++ * The Machine Vector
++ */
++struct sh_machine_vector mv_sh7710voipgw __initmv = {
++ .mv_name = "SH7710 VoIP Gateway",
++ .mv_nr_irqs = 104,
++ .mv_init_irq = sh7710voipgw_init_irq,
++};
++ALIAS_MV(sh7710voipgw)
+diff --git a/arch/sh/boards/renesas/systemh/io.c b/arch/sh/boards/renesas/systemh/io.c
+index cf97901..1b767e1 100644
+--- a/arch/sh/boards/renesas/systemh/io.c
++++ b/arch/sh/boards/renesas/systemh/io.c
+@@ -1,70 +1,29 @@
+ /*
+- * linux/arch/sh/boards/systemh/io.c
++ * linux/arch/sh/boards/renesas/systemh/io.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Hitachi 7751 Systemh.
+- *
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+-#include <asm/systemh/7751systemh.h>
++#include <linux/pci.h>
++#include <asm/systemh7751.h>
+ #include <asm/addrspace.h>
+ #include <asm/io.h>
+
+-#include <linux/pci.h>
+-#include "../../drivers/pci/pci-sh7751.h"
+-
+-/*
+- * The 7751 SystemH Engine uses the built-in PCI controller (PCIC)
+- * of the 7751 processor, and has a SuperIO accessible on its memory
+- * bus.
+- */
+-
+-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+-#define PCI_IO_AREA SH7751_PCI_IO_BASE
+-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+-
+-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+ #define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
+ of smc lan chip*/
+-
+-#define maybebadio(name,port) \
+- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+- #name, (port), (__u32) __builtin_return_address(0))
+-
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
+-
+ static inline volatile __u16 *
+ port2adr(unsigned int port)
+ {
+ if (port >= 0x2000)
+ return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+-#if 0
+- else
+- return (volatile __u16 *) (PA_SUPERIO + (port << 1));
+-#endif
+- maybebadio(name,(unsigned long)port);
++ maybebadio((unsigned long)port);
+ return (volatile __u16*)port;
+ }
+
+-/* In case someone configures the kernel w/o PCI support: in that */
+-/* scenario, don't ever bother to check for PCI-window addresses */
+-
+-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+-#if defined(CONFIG_PCI)
+-#define CHECK_SH7751_PCIIO(port) \
+- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+-#else
+-#define CHECK_SH7751_PCIIO(port) (0)
+-#endif
+-
+ /*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+@@ -76,8 +35,8 @@ unsigned char sh7751systemh_inb(unsigned
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned char *)pci_ioaddr(port);
+ else if (port <= 0x3F1)
+ return *(volatile unsigned char *)ETHER_IOMAP(port);
+ else
+@@ -90,13 +49,13 @@ unsigned char sh7751systemh_inb_p(unsign
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- v = *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ v = *(volatile unsigned char *)pci_ioaddr(port);
+ else if (port <= 0x3F1)
+ v = *(volatile unsigned char *)ETHER_IOMAP(port);
+ else
+ v = (*port2adr(port))&0xff;
+- delay();
++ ctrl_delay();
+ return v;
+ }
+
+@@ -104,14 +63,14 @@ unsigned short sh7751systemh_inw(unsigne
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned short *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned short *)pci_ioaddr(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else if (port <= 0x3F1)
+ return *(volatile unsigned int *)ETHER_IOMAP(port);
+ else
+- maybebadio(inw, port);
++ maybebadio(port);
+ return 0;
+ }
+
+@@ -119,14 +78,14 @@ unsigned int sh7751systemh_inl(unsigned
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned int *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned int *)pci_ioaddr(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else if (port <= 0x3F1)
+ return *(volatile unsigned int *)ETHER_IOMAP(port);
+ else
+- maybebadio(inl, port);
++ maybebadio(port);
+ return 0;
+ }
+
+@@ -135,8 +94,8 @@ void sh7751systemh_outb(unsigned char va
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned char*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned char*)pci_ioaddr(port)) = value;
+ else if (port <= 0x3F1)
+ *(volatile unsigned char *)ETHER_IOMAP(port) = value;
+ else
+@@ -147,37 +106,37 @@ void sh7751systemh_outb_p(unsigned char
+ {
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned char*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned char*)pci_ioaddr(port)) = value;
+ else if (port <= 0x3F1)
+ *(volatile unsigned char *)ETHER_IOMAP(port) = value;
+ else
+ *(port2adr(port)) = value;
+- delay();
++ ctrl_delay();
+ }
+
+ void sh7751systemh_outw(unsigned short value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned short *)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned short *)pci_ioaddr(port)) = value;
+ else if (port >= 0x2000)
+ *port2adr(port) = value;
+ else if (port <= 0x3F1)
+ *(volatile unsigned short *)ETHER_IOMAP(port) = value;
+ else
+- maybebadio(outw, port);
++ maybebadio(port);
+ }
+
+ void sh7751systemh_outl(unsigned int value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned long*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned long*)pci_ioaddr(port)) = value;
+ else
+- maybebadio(outl, port);
++ maybebadio(port);
+ }
+
+ void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
+@@ -194,7 +153,7 @@ void sh7751systemh_insw(unsigned long po
+
+ void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
+ {
+- maybebadio(insl, port);
++ maybebadio(port);
+ }
+
+ void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
+@@ -211,73 +170,5 @@ void sh7751systemh_outsw(unsigned long p
+
+ void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
+ {
+- maybebadio(outsw, port);
+-}
+-
+-/* For read/write calls, just copy generic (pass-thru); PCIMBR is */
+-/* already set up. For a larger memory space, these would need to */
+-/* reset PCIMBR as needed on a per-call basis... */
+-
+-unsigned char sh7751systemh_readb(unsigned long addr)
+-{
+- return *(volatile unsigned char*)addr;
+-}
+-
+-unsigned short sh7751systemh_readw(unsigned long addr)
+-{
+- return *(volatile unsigned short*)addr;
+-}
+-
+-unsigned int sh7751systemh_readl(unsigned long addr)
+-{
+- return *(volatile unsigned long*)addr;
+-}
+-
+-void sh7751systemh_writeb(unsigned char b, unsigned long addr)
+-{
+- *(volatile unsigned char*)addr = b;
+-}
+-
+-void sh7751systemh_writew(unsigned short b, unsigned long addr)
+-{
+- *(volatile unsigned short*)addr = b;
+-}
+-
+-void sh7751systemh_writel(unsigned int b, unsigned long addr)
+-{
+- *(volatile unsigned long*)addr = b;
+-}
+-
+-
+-
+-/* Map ISA bus address to the real address. Only for PCMCIA. */
+-
+-/* ISA page descriptor. */
+-static __u32 sh_isa_memmap[256];
+-
+-#if 0
+-static int
+-sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+-{
+- int idx;
+-
+- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+- return -1;
+-
+- idx = start >> 12;
+- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+- start, length, offset, idx, sh_isa_memmap[idx]);
+- return 0;
+-}
+-#endif
+-
+-unsigned long
+-sh7751systemh_isa_port2addr(unsigned long offset)
+-{
+- int idx;
+-
+- idx = (offset >> 12) & 0xff;
+- offset &= 0xfff;
+- return sh_isa_memmap[idx] + offset;
++ maybebadio(port);
+ }
+diff --git a/arch/sh/boards/renesas/systemh/irq.c b/arch/sh/boards/renesas/systemh/irq.c
+index 8372d96..0ba2fe6 100644
+--- a/arch/sh/boards/renesas/systemh/irq.c
++++ b/arch/sh/boards/renesas/systemh/irq.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/boards/systemh/irq.c
++ * linux/arch/sh/boards/renesas/systemh/irq.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+@@ -15,7 +15,7 @@
+ #include <linux/hdreg.h>
+ #include <linux/ide.h>
+ #include <asm/io.h>
+-#include <asm/mach/7751systemh.h>
++#include <asm/systemh7751.h>
+ #include <asm/smc37c93x.h>
+
+ /* address of external interrupt mask register
+@@ -57,12 +57,9 @@ static void shutdown_systemh_irq(unsigne
+ static void disable_systemh_irq(unsigned int irq)
+ {
+ if (systemh_irq_mask_register) {
+- unsigned long flags;
+ unsigned long val, mask = 0x01 << 1;
+
+ /* Clear the "irq"th bit in the mask and set it in the request */
+- local_irq_save(flags);
+-
+ val = ctrl_inl((unsigned long)systemh_irq_mask_register);
+ val &= ~mask;
+ ctrl_outl(val, (unsigned long)systemh_irq_mask_register);
+@@ -70,23 +67,18 @@ static void disable_systemh_irq(unsigned
+ val = ctrl_inl((unsigned long)systemh_irq_request_register);
+ val |= mask;
+ ctrl_outl(val, (unsigned long)systemh_irq_request_register);
+-
+- local_irq_restore(flags);
+ }
+ }
+
+ static void enable_systemh_irq(unsigned int irq)
+ {
+ if (systemh_irq_mask_register) {
+- unsigned long flags;
+ unsigned long val, mask = 0x01 << 1;
+
+ /* Set "irq"th bit in the mask register */
+- local_irq_save(flags);
+ val = ctrl_inl((unsigned long)systemh_irq_mask_register);
+ val |= mask;
+ ctrl_outl(val, (unsigned long)systemh_irq_mask_register);
+- local_irq_restore(flags);
+ }
+ }
+
+diff --git a/arch/sh/boards/renesas/systemh/setup.c b/arch/sh/boards/renesas/systemh/setup.c
+index 826fa3d..9361176 100644
+--- a/arch/sh/boards/renesas/systemh/setup.c
++++ b/arch/sh/boards/renesas/systemh/setup.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/boards/systemh/setup.c
++ * linux/arch/sh/boards/renesas/systemh/setup.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2003 Paul Mundt
+@@ -15,28 +15,21 @@
+ * for more details.
+ */
+ #include <linux/init.h>
+-#include <asm/mach/7751systemh.h>
+-#include <asm/mach/io.h>
+ #include <asm/machvec.h>
++#include <asm/systemh7751.h>
+
+ extern void make_systemh_irq(unsigned int irq);
+
+-const char *get_system_type(void)
+-{
+- return "7751 SystemH";
+-}
+-
+ /*
+ * Initialize IRQ setting
+ */
+-void __init init_7751systemh_IRQ(void)
++static void __init sh7751systemh_init_irq(void)
+ {
+-/* make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); LAN */
+-/* make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-4); */
+ make_systemh_irq(0xb); /* Ethernet interrupt */
+ }
+
+ struct sh_machine_vector mv_7751systemh __initmv = {
++ .mv_name = "7751 SystemH",
+ .mv_nr_irqs = 72,
+
+ .mv_inb = sh7751systemh_inb,
+@@ -60,21 +53,6 @@ struct sh_machine_vector mv_7751systemh
+ .mv_outsw = sh7751systemh_outsw,
+ .mv_outsl = sh7751systemh_outsl,
+
+- .mv_readb = sh7751systemh_readb,
+- .mv_readw = sh7751systemh_readw,
+- .mv_readl = sh7751systemh_readl,
+- .mv_writeb = sh7751systemh_writeb,
+- .mv_writew = sh7751systemh_writew,
+- .mv_writel = sh7751systemh_writel,
+-
+- .mv_isa_port2addr = sh7751systemh_isa_port2addr,
+-
+- .mv_init_irq = init_7751systemh_IRQ,
++ .mv_init_irq = sh7751systemh_init_irq,
+ };
+ ALIAS_MV(7751systemh)
+-
+-int __init platform_setup(void)
+-{
+- return 0;
+-}
+-
+diff --git a/arch/sh/boards/saturn/setup.c b/arch/sh/boards/saturn/setup.c
+index bea6c57..a3a37c9 100644
+--- a/arch/sh/boards/saturn/setup.c
++++ b/arch/sh/boards/saturn/setup.c
+@@ -9,22 +9,17 @@
+ */
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+-
+ #include <asm/io.h>
+ #include <asm/machvec.h>
+ #include <asm/mach/io.h>
+
+ extern int saturn_irq_demux(int irq_nr);
+
+-const char *get_system_type(void)
+-{
+- return "Sega Saturn";
+-}
+-
+ /*
+ * The Machine Vector
+ */
+ struct sh_machine_vector mv_saturn __initmv = {
++ .mv_name = "Sega Saturn",
+ .mv_nr_irqs = 80, /* Fix this later */
+
+ .mv_isa_port2addr = saturn_isa_port2addr,
+@@ -33,11 +28,4 @@ struct sh_machine_vector mv_saturn __ini
+ .mv_ioremap = saturn_ioremap,
+ .mv_iounmap = saturn_iounmap,
+ };
+-
+ ALIAS_MV(saturn)
+-
+-int __init platform_setup(void)
+-{
+- return 0;
+-}
+-
+diff --git a/arch/sh/boards/se/7300/io.c b/arch/sh/boards/se/7300/io.c
+index f449a94..8a03d7a 100644
+--- a/arch/sh/boards/se/7300/io.c
++++ b/arch/sh/boards/se/7300/io.c
+@@ -9,8 +9,8 @@
+ */
+
+ #include <linux/kernel.h>
+-#include <asm/mach/se7300.h>
+ #include <asm/io.h>
++#include <asm/se7300.h>
+
+ #define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
+
+@@ -99,6 +99,7 @@ bad_outb(struct iop *p, unsigned char va
+ badio(inw, port);
+ }
+
++#ifdef CONFIG_SMC91X
+ /* MSTLANEX01 LAN at 0xb400:0000 */
+ static struct iop laniop = {
+ .start = 0x300,
+@@ -110,6 +111,7 @@ static struct iop laniop = {
+ .outb = simple_outb,
+ .outw = simple_outw,
+ };
++#endif
+
+ /* NE2000 pc card NIC */
+ static struct iop neiop = {
+@@ -123,6 +125,7 @@ static struct iop neiop = {
+ .outw = simple_outw,
+ };
+
++#ifdef CONFIG_IDE
+ /* CF in CF slot */
+ static struct iop cfiop = {
+ .base = 0xb0600000,
+@@ -132,12 +135,13 @@ static struct iop cfiop = {
+ .outb = pcc_outb,
+ .outw = simple_outw,
+ };
++#endif
+
+ static __inline__ struct iop *
+ port2iop(unsigned long port)
+ {
+ if (0) ;
+-#if defined(CONFIG_SMC91111)
++#if defined(CONFIG_SMC91X)
+ else if (laniop.check(&laniop, port))
+ return &laniop;
+ #endif
+diff --git a/arch/sh/boards/se/7300/irq.c b/arch/sh/boards/se/7300/irq.c
+index 216a78d..1279d77 100644
+--- a/arch/sh/boards/se/7300/irq.c
++++ b/arch/sh/boards/se/7300/irq.c
+@@ -11,7 +11,18 @@
+ #include <linux/irq.h>
+ #include <asm/irq.h>
+ #include <asm/io.h>
+-#include <asm/mach/se7300.h>
++#include <asm/se7300.h>
++
++static struct ipr_data se7300_ipr_map[] = {
++ /* PC_IRQ[0-3] -> IRQ0 (32) */
++ { IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, 0x0f - IRQ0_IRQ },
++ /* A_IRQ[0-3] -> IRQ1 (33) */
++ { IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, 0x0f - IRQ1_IRQ },
++ { SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++ { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++};
+
+ /*
+ * Initialize IRQ setting
+@@ -23,14 +34,7 @@ init_7300se_IRQ(void)
+ ctrl_outw(0xa000, INTC_ICR1); /* IRQ mode; IRQ0,1 enable. */
+ ctrl_outw(0x0000, PORT_PFCR); /* use F for IRQ[3:0] and SIU. */
+
+- /* PC_IRQ[0-3] -> IRQ0 (32) */
+- make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, 0x0f - IRQ0_IRQ);
+- /* A_IRQ[0-3] -> IRQ1 (33) */
+- make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, 0x0f - IRQ1_IRQ);
+- make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+- make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+- make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+- make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
++ make_ipr_irq(se7300_ipr_map, ARRAY_SIZE(se7300_ipr_map));
+
+ ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */
+ }
+diff --git a/arch/sh/boards/se/7300/led.c b/arch/sh/boards/se/7300/led.c
+index ad51f0a..4d03bb7 100644
+--- a/arch/sh/boards/se/7300/led.c
++++ b/arch/sh/boards/se/7300/led.c
+@@ -12,24 +12,10 @@
+ */
+
+ #include <linux/sched.h>
+-#include <asm/mach/se7300.h>
+-
+-static void
+-mach_led(int position, int value)
+-{
+- volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+-
+- if (value) {
+- *p |= (1 << 8);
+- } else {
+- *p &= ~(1 << 8);
+- }
+-}
+-
++#include <asm/se7300.h>
+
+ /* Cycle the LED's in the clasic Knightrider/Sun pattern */
+-void
+-heartbeat_7300se(void)
++void heartbeat_7300se(void)
+ {
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+diff --git a/arch/sh/boards/se/7300/setup.c b/arch/sh/boards/se/7300/setup.c
+index ebcd98d..6f082a7 100644
+--- a/arch/sh/boards/se/7300/setup.c
++++ b/arch/sh/boards/se/7300/setup.c
+@@ -9,23 +9,16 @@
+
+ #include <linux/init.h>
+ #include <asm/machvec.h>
+-#include <asm/machvec_init.h>
+-#include <asm/mach/io.h>
++#include <asm/se7300.h>
+
+ void heartbeat_7300se(void);
+ void init_7300se_IRQ(void);
+
+-const char *
+-get_system_type(void)
+-{
+- return "SolutionEngine 7300";
+-}
+-
+ /*
+ * The Machine Vector
+ */
+-
+ struct sh_machine_vector mv_7300se __initmv = {
++ .mv_name = "SolutionEngine 7300",
+ .mv_nr_irqs = 109,
+ .mv_inb = sh7300se_inb,
+ .mv_inw = sh7300se_inw,
+@@ -53,13 +46,4 @@ struct sh_machine_vector mv_7300se __ini
+ .mv_heartbeat = heartbeat_7300se,
+ #endif
+ };
+-
+ ALIAS_MV(7300se)
+-/*
+- * Initialize the board
+- */
+-void __init
+-platform_setup(void)
+-{
+-
+-}
+diff --git a/arch/sh/boards/se/73180/io.c b/arch/sh/boards/se/73180/io.c
+index 755df5a..7271557 100644
+--- a/arch/sh/boards/se/73180/io.c
++++ b/arch/sh/boards/se/73180/io.c
+@@ -99,6 +99,7 @@ bad_outb(struct iop *p, unsigned char va
+ badio(inw, port);
+ }
+
++#ifdef CONFIG_SMC91X
+ /* MSTLANEX01 LAN at 0xb400:0000 */
+ static struct iop laniop = {
+ .start = 0x300,
+@@ -110,6 +111,7 @@ static struct iop laniop = {
+ .outb = simple_outb,
+ .outw = simple_outw,
+ };
++#endif
+
+ /* NE2000 pc card NIC */
+ static struct iop neiop = {
+@@ -123,6 +125,7 @@ static struct iop neiop = {
+ .outw = simple_outw,
+ };
+
++#ifdef CONFIG_IDE
+ /* CF in CF slot */
+ static struct iop cfiop = {
+ .base = 0xb0600000,
+@@ -132,12 +135,13 @@ static struct iop cfiop = {
+ .outb = pcc_outb,
+ .outw = simple_outw,
+ };
++#endif
+
+ static __inline__ struct iop *
+ port2iop(unsigned long port)
+ {
+ if (0) ;
+-#if defined(CONFIG_SMC91111)
++#if defined(CONFIG_SMC91X)
+ else if (laniop.check(&laniop, port))
+ return &laniop;
+ #endif
+diff --git a/arch/sh/boards/se/73180/irq.c b/arch/sh/boards/se/73180/irq.c
+index 4344d0e..e7200c5 100644
+--- a/arch/sh/boards/se/73180/irq.c
++++ b/arch/sh/boards/se/73180/irq.c
+@@ -7,7 +7,6 @@
+ * Modified for SH-Mobile SolutionEngine 73180 Support
+ * by YOSHII Takashi <yoshii-takashi at hitachi-ul.co.jp>
+ *
+- *
+ */
+
+ #include <linux/init.h>
+@@ -17,14 +16,6 @@
+ #include <asm/mach/se73180.h>
+
+ static int
+-intreq2irq(int i)
+-{
+- if (i == 5)
+- return 10;
+- return 32 + 7 - i;
+-}
+-
+-static int
+ irq2intreq(int irq)
+ {
+ if (irq == 10)
+@@ -96,13 +87,38 @@ shmse_irq_demux(int irq)
+ return irq;
+ }
+
++static struct ipr_data se73180_siof0_ipr_map[] = {
++ { SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++};
++static struct ipr_data se73180_vpu_ipr_map[] = {
++ { VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8 },
++};
++static struct ipr_data se73180_other_ipr_map[] = {
++ { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY },
++ { IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++ { SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY },
++
++ /* VIO interrupt */
++ { CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++ { BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++ { VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++
++ { LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY },
++};
++
+ /*
+ * Initialize IRQ setting
+ */
+ void __init
+ init_73180se_IRQ(void)
+ {
+- make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
++ make_ipr_irq(se73180_siof0_ipr_map, ARRAY_SIZE(se73180_siof0_ipr_map));
+
+ ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */
+ ctrl_outw(0x2000, 0xb07fffec); /* mrshpc irq enable */
+@@ -110,27 +126,11 @@ init_73180se_IRQ(void)
+ ctrl_outw(2 << ((7 - 5) * 2), INTC_ICR1); /* low-level irq */
+ make_intreq_irq(10);
+
+- make_ipr_irq(VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8);
++ make_ipr_irq(se73180_vpu_ipr_map, ARRAY_SIZE(se73180_vpu_ipr_map));
+
+ ctrl_outb(0x0f, INTC_IMCR5); /* enable SCIF IRQ */
+
+- make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+- make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+- make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+- make_ipr_irq(IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+- make_ipr_irq(IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+- IIC0_PRIORITY);
+- make_ipr_irq(IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+- IIC0_PRIORITY);
+- make_ipr_irq(IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+- make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+- make_ipr_irq(SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY);
+-
+- /* VIO interrupt */
+- make_ipr_irq(CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+- make_ipr_irq(BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+- make_ipr_irq(VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
++ make_ipr_irq(se73180_other_ipr_map, ARRAY_SIZE(se73180_other_ipr_map));
+
+- make_ipr_irq(LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY);
+ ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */
+ }
+diff --git a/arch/sh/boards/se/73180/led.c b/arch/sh/boards/se/73180/led.c
+index 610439f..4b72e9a 100644
+--- a/arch/sh/boards/se/73180/led.c
++++ b/arch/sh/boards/se/73180/led.c
+@@ -14,21 +14,8 @@
+ #include <linux/sched.h>
+ #include <asm/mach/se73180.h>
+
+-static void
+-mach_led(int position, int value)
+-{
+- volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+-
+- if (value) {
+- *p |= (1 << LED_SHIFT);
+- } else {
+- *p &= ~(1 << LED_SHIFT);
+- }
+-}
+-
+ /* Cycle the LED's in the clasic Knightrider/Sun pattern */
+-void
+-heartbeat_73180se(void)
++void heartbeat_73180se(void)
+ {
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c
+index cdb7b5f..b38ef50 100644
+--- a/arch/sh/boards/se/73180/setup.c
++++ b/arch/sh/boards/se/73180/setup.c
+@@ -11,23 +11,17 @@
+
+ #include <linux/init.h>
+ #include <asm/machvec.h>
+-#include <asm/machvec_init.h>
+-#include <asm/mach/io.h>
++#include <asm/se73180.h>
++#include <asm/irq.h>
+
+ void heartbeat_73180se(void);
+ void init_73180se_IRQ(void);
+
+-const char *
+-get_system_type(void)
+-{
+- return "SolutionEngine 73180";
+-}
+-
+ /*
+ * The Machine Vector
+ */
+-
+ struct sh_machine_vector mv_73180se __initmv = {
++ .mv_name = "SolutionEngine 73180",
+ .mv_nr_irqs = 108,
+ .mv_inb = sh73180se_inb,
+ .mv_inw = sh73180se_inw,
+@@ -51,17 +45,9 @@ struct sh_machine_vector mv_73180se __in
+ .mv_outsl = sh73180se_outsl,
+
+ .mv_init_irq = init_73180se_IRQ,
++ .mv_irq_demux = shmse_irq_demux,
+ #ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_73180se,
+ #endif
+ };
+-
+ ALIAS_MV(73180se)
+-/*
+- * Initialize the board
+- */
+-void __init
+-platform_setup(void)
+-{
+-
+-}
+diff --git a/arch/sh/boards/se/7343/Makefile b/arch/sh/boards/se/7343/Makefile
+new file mode 100644
+index 0000000..4291069
+--- /dev/null
++++ b/arch/sh/boards/se/7343/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the 7343 SolutionEngine specific parts of the kernel
++#
++
++obj-y := setup.o io.o irq.o
++
++obj-$(CONFIG_HEARTBEAT) += led.o
+diff --git a/arch/sh/boards/se/7343/io.c b/arch/sh/boards/se/7343/io.c
+new file mode 100644
+index 0000000..3a6d114
+--- /dev/null
++++ b/arch/sh/boards/se/7343/io.c
+@@ -0,0 +1,273 @@
++/*
++ * arch/sh/boards/se/7343/io.c
++ *
++ * I/O routine for SH-Mobile3AS 7343 SolutionEngine.
++ *
++ */
++#include <linux/kernel.h>
++#include <asm/io.h>
++#include <asm/mach/se7343.h>
++
++#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
++
++struct iop {
++ unsigned long start, end;
++ unsigned long base;
++ struct iop *(*check) (struct iop * p, unsigned long port);
++ unsigned char (*inb) (struct iop * p, unsigned long port);
++ unsigned short (*inw) (struct iop * p, unsigned long port);
++ void (*outb) (struct iop * p, unsigned char value, unsigned long port);
++ void (*outw) (struct iop * p, unsigned short value, unsigned long port);
++};
++
++struct iop *
++simple_check(struct iop *p, unsigned long port)
++{
++ static int count;
++
++ if (count < 100)
++ count++;
++
++ port &= 0xFFFF;
++
++ if ((p->start <= port) && (port <= p->end))
++ return p;
++ else
++ badio(check, port);
++}
++
++struct iop *
++ide_check(struct iop *p, unsigned long port)
++{
++ if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
++ return p;
++ return NULL;
++}
++
++unsigned char
++simple_inb(struct iop *p, unsigned long port)
++{
++ return *(unsigned char *) (p->base + port);
++}
++
++unsigned short
++simple_inw(struct iop *p, unsigned long port)
++{
++ return *(unsigned short *) (p->base + port);
++}
++
++void
++simple_outb(struct iop *p, unsigned char value, unsigned long port)
++{
++ *(unsigned char *) (p->base + port) = value;
++}
++
++void
++simple_outw(struct iop *p, unsigned short value, unsigned long port)
++{
++ *(unsigned short *) (p->base + port) = value;
++}
++
++unsigned char
++pcc_inb(struct iop *p, unsigned long port)
++{
++ unsigned long addr = p->base + port + 0x40000;
++ unsigned long v;
++
++ if (port & 1)
++ addr += 0x00400000;
++ v = *(volatile unsigned char *) addr;
++ return v;
++}
++
++void
++pcc_outb(struct iop *p, unsigned char value, unsigned long port)
++{
++ unsigned long addr = p->base + port + 0x40000;
++
++ if (port & 1)
++ addr += 0x00400000;
++ *(volatile unsigned char *) addr = value;
++}
++
++unsigned char
++bad_inb(struct iop *p, unsigned long port)
++{
++ badio(inb, port);
++}
++
++void
++bad_outb(struct iop *p, unsigned char value, unsigned long port)
++{
++ badio(inw, port);
++}
++
++#ifdef CONFIG_SMC91X
++/* MSTLANEX01 LAN at 0xb400:0000 */
++static struct iop laniop = {
++ .start = 0x00,
++ .end = 0x0F,
++ .base = 0x04000000,
++ .check = simple_check,
++ .inb = simple_inb,
++ .inw = simple_inw,
++ .outb = simple_outb,
++ .outw = simple_outw,
++};
++#endif
++
++#ifdef CONFIG_NE2000
++/* NE2000 pc card NIC */
++static struct iop neiop = {
++ .start = 0x280,
++ .end = 0x29f,
++ .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */
++ .check = simple_check,
++ .inb = pcc_inb,
++ .inw = simple_inw,
++ .outb = pcc_outb,
++ .outw = simple_outw,
++};
++#endif
++
++#ifdef CONFIG_IDE
++/* CF in CF slot */
++static struct iop cfiop = {
++ .base = 0xb0600000,
++ .check = ide_check,
++ .inb = pcc_inb,
++ .inw = simple_inw,
++ .outb = pcc_outb,
++ .outw = simple_outw,
++};
++#endif
++
++static __inline__ struct iop *
++port2iop(unsigned long port)
++{
++ if (0) ;
++#if defined(CONFIG_SMC91X)
++ else if (laniop.check(&laniop, port))
++ return &laniop;
++#endif
++#if defined(CONFIG_NE2000)
++ else if (neiop.check(&neiop, port))
++ return &neiop;
++#endif
++#if defined(CONFIG_IDE)
++ else if (cfiop.check(&cfiop, port))
++ return &cfiop;
++#endif
++ else
++ return NULL;
++}
++
++static inline void
++delay(void)
++{
++ ctrl_inw(0xac000000);
++ ctrl_inw(0xac000000);
++}
++
++unsigned char
++sh7343se_inb(unsigned long port)
++{
++ struct iop *p = port2iop(port);
++ return (p->inb) (p, port);
++}
++
++unsigned char
++sh7343se_inb_p(unsigned long port)
++{
++ unsigned char v = sh7343se_inb(port);
++ delay();
++ return v;
++}
++
++unsigned short
++sh7343se_inw(unsigned long port)
++{
++ struct iop *p = port2iop(port);
++ return (p->inw) (p, port);
++}
++
++unsigned int
++sh7343se_inl(unsigned long port)
++{
++ badio(inl, port);
++}
++
++void
++sh7343se_outb(unsigned char value, unsigned long port)
++{
++ struct iop *p = port2iop(port);
++ (p->outb) (p, value, port);
++}
++
++void
++sh7343se_outb_p(unsigned char value, unsigned long port)
++{
++ sh7343se_outb(value, port);
++ delay();
++}
++
++void
++sh7343se_outw(unsigned short value, unsigned long port)
++{
++ struct iop *p = port2iop(port);
++ (p->outw) (p, value, port);
++}
++
++void
++sh7343se_outl(unsigned int value, unsigned long port)
++{
++ badio(outl, port);
++}
++
++void
++sh7343se_insb(unsigned long port, void *addr, unsigned long count)
++{
++ unsigned char *a = addr;
++ struct iop *p = port2iop(port);
++ while (count--)
++ *a++ = (p->inb) (p, port);
++}
++
++void
++sh7343se_insw(unsigned long port, void *addr, unsigned long count)
++{
++ unsigned short *a = addr;
++ struct iop *p = port2iop(port);
++ while (count--)
++ *a++ = (p->inw) (p, port);
++}
++
++void
++sh7343se_insl(unsigned long port, void *addr, unsigned long count)
++{
++ badio(insl, port);
++}
++
++void
++sh7343se_outsb(unsigned long port, const void *addr, unsigned long count)
++{
++ unsigned char *a = (unsigned char *) addr;
++ struct iop *p = port2iop(port);
++ while (count--)
++ (p->outb) (p, *a++, port);
++}
++
++void
++sh7343se_outsw(unsigned long port, const void *addr, unsigned long count)
++{
++ unsigned short *a = (unsigned short *) addr;
++ struct iop *p = port2iop(port);
++ while (count--)
++ (p->outw) (p, *a++, port);
++}
++
++void
++sh7343se_outsl(unsigned long port, const void *addr, unsigned long count)
++{
++ badio(outsw, port);
++}
+diff --git a/arch/sh/boards/se/7343/irq.c b/arch/sh/boards/se/7343/irq.c
+new file mode 100644
+index 0000000..360153e
+--- /dev/null
++++ b/arch/sh/boards/se/7343/irq.c
+@@ -0,0 +1,199 @@
++/*
++ * arch/sh/boards/se/7343/irq.c
++ *
++ */
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/mach/se7343.h>
++
++static void
++disable_intreq_irq(unsigned int irq)
++{
++ int bit = irq - OFFCHIP_IRQ_BASE;
++ u16 val;
++
++ val = ctrl_inw(PA_CPLD_IMSK);
++ val |= 1 << bit;
++ ctrl_outw(val, PA_CPLD_IMSK);
++}
++
++static void
++enable_intreq_irq(unsigned int irq)
++{
++ int bit = irq - OFFCHIP_IRQ_BASE;
++ u16 val;
++
++ val = ctrl_inw(PA_CPLD_IMSK);
++ val &= ~(1 << bit);
++ ctrl_outw(val, PA_CPLD_IMSK);
++}
++
++static void
++mask_and_ack_intreq_irq(unsigned int irq)
++{
++ disable_intreq_irq(irq);
++}
++
++static unsigned int
++startup_intreq_irq(unsigned int irq)
++{
++ enable_intreq_irq(irq);
++ return 0;
++}
++
++static void
++shutdown_intreq_irq(unsigned int irq)
++{
++ disable_intreq_irq(irq);
++}
++
++static void
++end_intreq_irq(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
++ enable_intreq_irq(irq);
++}
++
++static struct hw_interrupt_type intreq_irq_type = {
++ .typename = "FPGA-IRQ",
++ .startup = startup_intreq_irq,
++ .shutdown = shutdown_intreq_irq,
++ .enable = enable_intreq_irq,
++ .disable = disable_intreq_irq,
++ .ack = mask_and_ack_intreq_irq,
++ .end = end_intreq_irq
++};
++
++static void
++make_intreq_irq(unsigned int irq)
++{
++ disable_irq_nosync(irq);
++ irq_desc[irq].chip = &intreq_irq_type;
++ disable_intreq_irq(irq);
++}
++
++int
++shmse_irq_demux(int irq)
++{
++ int bit;
++ volatile u16 val;
++
++ if (irq == IRQ5_IRQ) {
++ /* Read status Register */
++ val = ctrl_inw(PA_CPLD_ST);
++ bit = ffs(val);
++ if (bit != 0)
++ return OFFCHIP_IRQ_BASE + bit - 1;
++ }
++ return irq;
++}
++
++/* IRQ5 is multiplexed between the following sources:
++ * 1. PC Card socket
++ * 2. Extension slot
++ * 3. USB Controller
++ * 4. Serial Controller
++ *
++ * We configure IRQ5 as a cascade IRQ.
++ */
++static struct irqaction irq5 = { no_action, 0, CPU_MASK_NONE, "IRQ5-cascade",
++ NULL, NULL};
++
++static struct ipr_data se7343_irq5_ipr_map[] = {
++ { IRQ5_IRQ, IRQ5_IPR_ADDR+2, IRQ5_IPR_POS, IRQ5_PRIORITY },
++};
++static struct ipr_data se7343_siof0_vpu_ipr_map[] = {
++ { SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++ { VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8 },
++};
++static struct ipr_data se7343_other_ipr_map[] = {
++ { DMTE0_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE1_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY },
++ { DMTE5_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY },
++
++ /* I2C block */
++ { IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++ { IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY },
++
++ { IIC1_ALI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS, IIC1_PRIORITY },
++ { IIC1_TACKI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS, IIC1_PRIORITY },
++ { IIC1_WAITI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS, IIC1_PRIORITY },
++ { IIC1_DTEI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS, IIC1_PRIORITY },
++
++ /* SIOF */
++ { SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY },
++
++ /* SIU */
++ { SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY },
++
++ /* VIO interrupt */
++ { CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++ { BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++ { VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
++
++ /*MFI interrupt*/
++
++ { MFI_IRQ, MFI_IPR_ADDR, MFI_IPR_POS, MFI_PRIORITY },
++
++ /* LCD controller */
++ { LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY },
++};
++
++/*
++ * Initialize IRQ setting
++ */
++void __init
++init_7343se_IRQ(void)
++{
++ /* Setup Multiplexed interrupts */
++ ctrl_outw(8, PA_CPLD_MODESET); /* Set all CPLD interrupts to active
++ * low.
++ */
++ /* Mask all CPLD controller interrupts */
++ ctrl_outw(0x0fff, PA_CPLD_IMSK);
++
++ /* PC Card interrupts */
++ make_intreq_irq(PC_IRQ0);
++ make_intreq_irq(PC_IRQ1);
++ make_intreq_irq(PC_IRQ2);
++ make_intreq_irq(PC_IRQ3);
++
++ /* Extension Slot Interrupts */
++ make_intreq_irq(EXT_IRQ0);
++ make_intreq_irq(EXT_IRQ1);
++ make_intreq_irq(EXT_IRQ2);
++ make_intreq_irq(EXT_IRQ3);
++
++ /* USB Controller interrupts */
++ make_intreq_irq(USB_IRQ0);
++ make_intreq_irq(USB_IRQ1);
++
++ /* Serial Controller interrupts */
++ make_intreq_irq(UART_IRQ0);
++ make_intreq_irq(UART_IRQ1);
++
++ /* Setup all external interrupts to be active low */
++ ctrl_outw(0xaaaa, INTC_ICR1);
++
++ make_ipr_irq(se7343_irq5_ipr_map, ARRAY_SIZE(se7343_irq5_ipr_map));
++
++ setup_irq(IRQ5_IRQ, &irq5);
++ /* Set port control to use IRQ5 */
++ *(u16 *)0xA4050108 &= ~0xc;
++
++ make_ipr_irq(se7343_siof0_vpu_ipr_map, ARRAY_SIZE(se7343_siof0_vpu_ipr_map));
++
++ ctrl_outb(0x0f, INTC_IMCR5); /* enable SCIF IRQ */
++
++ make_ipr_irq(se7343_other_ipr_map, ARRAY_SIZE(se7343_other_ipr_map));
++
++ ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */
++}
+diff --git a/arch/sh/boards/se/7343/led.c b/arch/sh/boards/se/7343/led.c
+new file mode 100644
+index 0000000..6b39e19
+--- /dev/null
++++ b/arch/sh/boards/se/7343/led.c
+@@ -0,0 +1,44 @@
++/*
++ * arch/sh/boards/se/7343/led.c
++ *
++ */
++#include <linux/sched.h>
++#include <asm/mach/se7343.h>
++
++/* Cycle the LED's in the clasic Knightrider/Sun pattern */
++void heartbeat_7343se(void)
++{
++ static unsigned int cnt = 0, period = 0;
++ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
++ static unsigned bit = 0, up = 1;
++
++ cnt += 1;
++ if (cnt < period) {
++ return;
++ }
++
++ cnt = 0;
++
++ /* Go through the points (roughly!):
++ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
++ */
++ period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT)));
++
++ if (up) {
++ if (bit == 7) {
++ bit--;
++ up = 0;
++ } else {
++ bit++;
++ }
++ } else {
++ if (bit == 0) {
++ bit++;
++ up = 1;
++ } else {
++ bit--;
++ }
++ }
++ *p = 1 << (bit + LED_SHIFT);
++
++}
+diff --git a/arch/sh/boards/se/7343/setup.c b/arch/sh/boards/se/7343/setup.c
+new file mode 100644
+index 0000000..c7d17fe
+--- /dev/null
++++ b/arch/sh/boards/se/7343/setup.c
+@@ -0,0 +1,83 @@
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <asm/machvec.h>
++#include <asm/mach/se7343.h>
++#include <asm/irq.h>
++
++void heartbeat_7343se(void);
++void init_7343se_IRQ(void);
++
++static struct resource smc91x_resources[] = {
++ [0] = {
++ .start = 0x10000000,
++ .end = 0x1000000F,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ /*
++ * shared with other devices via externel
++ * interrupt controller in FPGA...
++ */
++ .start = EXT_IRQ2,
++ .end = EXT_IRQ2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device smc91x_device = {
++ .name = "smc91x",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(smc91x_resources),
++ .resource = smc91x_resources,
++};
++
++static struct platform_device *smc91x_platform_devices[] __initdata = {
++ &smc91x_device,
++};
++
++static int __init sh7343se_devices_setup(void)
++{
++ return platform_add_devices(smc91x_platform_devices,
++ ARRAY_SIZE(smc91x_platform_devices));
++}
++
++static void __init sh7343se_setup(char **cmdline_p)
++{
++ device_initcall(sh7343se_devices_setup);
++}
++
++/*
++ * The Machine Vector
++ */
++struct sh_machine_vector mv_7343se __initmv = {
++ .mv_name = "SolutionEngine 7343",
++ .mv_setup = sh7343se_setup,
++ .mv_nr_irqs = 108,
++ .mv_inb = sh7343se_inb,
++ .mv_inw = sh7343se_inw,
++ .mv_inl = sh7343se_inl,
++ .mv_outb = sh7343se_outb,
++ .mv_outw = sh7343se_outw,
++ .mv_outl = sh7343se_outl,
++
++ .mv_inb_p = sh7343se_inb_p,
++ .mv_inw_p = sh7343se_inw,
++ .mv_inl_p = sh7343se_inl,
++ .mv_outb_p = sh7343se_outb_p,
++ .mv_outw_p = sh7343se_outw,
++ .mv_outl_p = sh7343se_outl,
++
++ .mv_insb = sh7343se_insb,
++ .mv_insw = sh7343se_insw,
++ .mv_insl = sh7343se_insl,
++ .mv_outsb = sh7343se_outsb,
++ .mv_outsw = sh7343se_outsw,
++ .mv_outsl = sh7343se_outsl,
++
++ .mv_init_irq = init_7343se_IRQ,
++ .mv_irq_demux = shmse_irq_demux,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_7343se,
++#endif
++};
++ALIAS_MV(7343se)
+diff --git a/arch/sh/boards/se/770x/Makefile b/arch/sh/boards/se/770x/Makefile
+index be89a73..9a5035f 100644
+--- a/arch/sh/boards/se/770x/Makefile
++++ b/arch/sh/boards/se/770x/Makefile
+@@ -2,5 +2,5 @@
+ # Makefile for the 770x SolutionEngine specific parts of the kernel
+ #
+
+-obj-y := mach.o setup.o io.o irq.o led.o
+-
++obj-y := setup.o io.o irq.o
++obj-$(CONFIG_HEARTBEAT) += led.o
+diff --git a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c
+index 9a39ee9..9941949 100644
+--- a/arch/sh/boards/se/770x/io.c
++++ b/arch/sh/boards/se/770x/io.c
+@@ -1,4 +1,4 @@
+-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
++/* $Id: io.c,v 1.7 2006/02/05 21:55:29 lethal Exp $
+ *
+ * linux/arch/sh/kernel/io_se.c
+ *
+@@ -11,7 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <asm/io.h>
+-#include <asm/se/se.h>
++#include <asm/se.h>
+
+ /* SH pcmcia io window base, start and end. */
+ int sh_pcic_io_wbase = 0xb8400000;
+@@ -20,11 +20,6 @@ int sh_pcic_io_stop;
+ int sh_pcic_io_type;
+ int sh_pcic_io_dummy;
+
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
+-
+ /* MS7750 requires special versions of in*, out* routines, since
+ PC-like io ports are located at upper half byte of 16-bit word which
+ can be accessed only with 16-bit wide. */
+@@ -52,10 +47,6 @@ shifted_port(unsigned long port)
+ return 1;
+ }
+
+-#define maybebadio(name,port) \
+- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+- #name, (port), (__u32) __builtin_return_address(0))
+-
+ unsigned char se_inb(unsigned long port)
+ {
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
+@@ -76,7 +67,7 @@ unsigned char se_inb_p(unsigned long por
+ v = (*port2adr(port) >> 8);
+ else
+ v = (*port2adr(port))&0xff;
+- delay();
++ ctrl_delay();
+ return v;
+ }
+
+@@ -86,13 +77,13 @@ unsigned short se_inw(unsigned long port
+ (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
+ return *port2adr(port);
+ else
+- maybebadio(inw, port);
++ maybebadio(port);
+ return 0;
+ }
+
+ unsigned int se_inl(unsigned long port)
+ {
+- maybebadio(inl, port);
++ maybebadio(port);
+ return 0;
+ }
+
+@@ -114,7 +105,7 @@ void se_outb_p(unsigned char value, unsi
+ *(port2adr(port)) = value << 8;
+ else
+ *(port2adr(port)) = value;
+- delay();
++ ctrl_delay();
+ }
+
+ void se_outw(unsigned short value, unsigned long port)
+@@ -123,12 +114,12 @@ void se_outw(unsigned short value, unsig
+ (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
+ *port2adr(port) = value;
+ else
+- maybebadio(outw, port);
++ maybebadio(port);
+ }
+
+ void se_outl(unsigned int value, unsigned long port)
+ {
+- maybebadio(outl, port);
++ maybebadio(port);
+ }
+
+ void se_insb(unsigned long port, void *addr, unsigned long count)
+@@ -159,7 +150,7 @@ void se_insw(unsigned long port, void *a
+
+ void se_insl(unsigned long port, void *addr, unsigned long count)
+ {
+- maybebadio(insl, port);
++ maybebadio(port);
+ }
+
+ void se_outsb(unsigned long port, const void *addr, unsigned long count)
+@@ -190,37 +181,5 @@ void se_outsw(unsigned long port, const
+
+ void se_outsl(unsigned long port, const void *addr, unsigned long count)
+ {
+- maybebadio(outsw, port);
+-}
+-
+-/* Map ISA bus address to the real address. Only for PCMCIA. */
+-
+-/* ISA page descriptor. */
+-static __u32 sh_isa_memmap[256];
+-
+-static int
+-sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+-{
+- int idx;
+-
+- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+- return -1;
+-
+- idx = start >> 12;
+- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+-#if 0
+- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+- start, length, offset, idx, sh_isa_memmap[idx]);
+-#endif
+- return 0;
+-}
+-
+-unsigned long
+-se_isa_port2addr(unsigned long offset)
+-{
+- int idx;
+-
+- idx = (offset >> 12) & 0xff;
+- offset &= 0xfff;
+- return sh_isa_memmap[idx] + offset;
++ maybebadio(port);
+ }
+diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
+index 3e55871..fcd7cd7 100644
+--- a/arch/sh/boards/se/770x/irq.c
++++ b/arch/sh/boards/se/770x/irq.c
+@@ -11,7 +11,49 @@
+ #include <linux/irq.h>
+ #include <asm/irq.h>
+ #include <asm/io.h>
+-#include <asm/se/se.h>
++#include <asm/se.h>
++
++static struct ipr_data se770x_ipr_map[] = {
++#if defined(CONFIG_CPU_SUBTYPE_SH7705)
++ /* This is default value */
++ { 0xf-0x2, BCR_ILCRA, 2, 0x2 },
++ { 0xf-0xa, BCR_ILCRA, 1, 0xa },
++ { 0xf-0x5, BCR_ILCRB, 0, 0x5 },
++ { 0xf-0x8, BCR_ILCRC, 1, 0x8 },
++ { 0xf-0xc, BCR_ILCRC, 0, 0xc },
++ { 0xf-0xe, BCR_ILCRD, 3, 0xe },
++ { 0xf-0x3, BCR_ILCRD, 1, 0x3 }, /* LAN */
++ { 0xf-0xd, BCR_ILCRE, 2, 0xd },
++ { 0xf-0x9, BCR_ILCRE, 1, 0x9 },
++ { 0xf-0x1, BCR_ILCRE, 0, 0x1 },
++ { 0xf-0xf, BCR_ILCRF, 3, 0xf },
++ { 0xf-0xb, BCR_ILCRF, 1, 0xb },
++ { 0xf-0x7, BCR_ILCRG, 3, 0x7 },
++ { 0xf-0x6, BCR_ILCRG, 2, 0x6 },
++ { 0xf-0x4, BCR_ILCRG, 1, 0x4 },
++#else
++ { 14, BCR_ILCRA, 2, 0x0f-14 },
++ { 12, BCR_ILCRA, 1, 0x0f-12 },
++ { 8, BCR_ILCRB, 1, 0x0f- 8 },
++ { 6, BCR_ILCRC, 3, 0x0f- 6 },
++ { 5, BCR_ILCRC, 2, 0x0f- 5 },
++ { 4, BCR_ILCRC, 1, 0x0f- 4 },
++ { 3, BCR_ILCRC, 0, 0x0f- 3 },
++ { 1, BCR_ILCRD, 3, 0x0f- 1 },
++
++ { 10, BCR_ILCRD, 1, 0x0f-10 }, /* LAN */
++
++ { 0, BCR_ILCRE, 3, 0x0f- 0 }, /* PCIRQ3 */
++ { 11, BCR_ILCRE, 2, 0x0f-11 }, /* PCIRQ2 */
++ { 9, BCR_ILCRE, 1, 0x0f- 9 }, /* PCIRQ1 */
++ { 7, BCR_ILCRE, 0, 0x0f- 7 }, /* PCIRQ0 */
++
++ /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
++ /* NOTE: #2 and #13 are not used on PC */
++ { 13, BCR_ILCRG, 1, 0x0f-13 }, /* SLOTIRQ2 */
++ { 2, BCR_ILCRG, 0, 0x0f- 2 }, /* SLOTIRQ1 */
++#endif
++};
+
+ /*
+ * Initialize IRQ setting
+@@ -38,42 +80,6 @@ void __init init_se_IRQ(void)
+ ctrl_outw(0, BCR_ILCRE);
+ ctrl_outw(0, BCR_ILCRF);
+ ctrl_outw(0, BCR_ILCRG);
+- /* This is default value */
+- make_ipr_irq(0xf-0x2, BCR_ILCRA, 2, 0x2);
+- make_ipr_irq(0xf-0xa, BCR_ILCRA, 1, 0xa);
+- make_ipr_irq(0xf-0x5, BCR_ILCRB, 0, 0x5);
+- make_ipr_irq(0xf-0x8, BCR_ILCRC, 1, 0x8);
+- make_ipr_irq(0xf-0xc, BCR_ILCRC, 0, 0xc);
+- make_ipr_irq(0xf-0xe, BCR_ILCRD, 3, 0xe);
+- make_ipr_irq(0xf-0x3, BCR_ILCRD, 1, 0x3); /* LAN */
+- make_ipr_irq(0xf-0xd, BCR_ILCRE, 2, 0xd);
+- make_ipr_irq(0xf-0x9, BCR_ILCRE, 1, 0x9);
+- make_ipr_irq(0xf-0x1, BCR_ILCRE, 0, 0x1);
+- make_ipr_irq(0xf-0xf, BCR_ILCRF, 3, 0xf);
+- make_ipr_irq(0xf-0xb, BCR_ILCRF, 1, 0xb);
+- make_ipr_irq(0xf-0x7, BCR_ILCRG, 3, 0x7);
+- make_ipr_irq(0xf-0x6, BCR_ILCRG, 2, 0x6);
+- make_ipr_irq(0xf-0x4, BCR_ILCRG, 1, 0x4);
+-#else
+- make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
+- make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
+- make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
+- make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
+- make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
+- make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
+- make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
+- make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
+-
+- make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
+-
+- make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
+- make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
+- make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
+- make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
+-
+- /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
+- /* NOTE: #2 and #13 are not used on PC */
+- make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
+- make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
+ #endif
++ make_ipr_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map));
+ }
+diff --git a/arch/sh/boards/se/770x/led.c b/arch/sh/boards/se/770x/led.c
+index 3cddbda..d93dd83 100644
+--- a/arch/sh/boards/se/770x/led.c
++++ b/arch/sh/boards/se/770x/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/led_se.c
++ * linux/arch/sh/boards/se/770x/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy at st.com>
+ *
+@@ -9,22 +9,8 @@
+ * This file contains Solution Engine specific LED code.
+ */
+
+-#include <asm/se/se.h>
+-
+-static void mach_led(int position, int value)
+-{
+- volatile unsigned short* p = (volatile unsigned short*)PA_LED;
+-
+- if (value) {
+- *p |= (1<<8);
+- } else {
+- *p &= ~(1<<8);
+- }
+-}
+-
+-#ifdef CONFIG_HEARTBEAT
+-
+ #include <linux/sched.h>
++#include <asm/se.h>
+
+ /* Cycle the LED's in the clasic Knightrider/Sun pattern */
+ void heartbeat_se(void)
+@@ -64,4 +50,3 @@ void heartbeat_se(void)
+ *p = 1<<(bit+8);
+
+ }
+-#endif /* CONFIG_HEARTBEAT */
+diff --git a/arch/sh/boards/se/770x/mach.c b/arch/sh/boards/se/770x/mach.c
+deleted file mode 100644
+index 6ec07bd..0000000
+--- a/arch/sh/boards/se/770x/mach.c
++++ /dev/null
+@@ -1,67 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/mach_se.c
+- *
+- * Copyright (C) 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the Hitachi SolutionEngine
+- */
+-
+-#include <linux/init.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/machvec_init.h>
+-
+-#include <asm/se/io.h>
+-
+-void heartbeat_se(void);
+-void setup_se(void);
+-void init_se_IRQ(void);
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_se __initmv = {
+-#if defined(CONFIG_CPU_SH4)
+- .mv_nr_irqs = 48,
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+- .mv_nr_irqs = 32,
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+- .mv_nr_irqs = 61,
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+- .mv_nr_irqs = 86,
+-#endif
+-
+- .mv_inb = se_inb,
+- .mv_inw = se_inw,
+- .mv_inl = se_inl,
+- .mv_outb = se_outb,
+- .mv_outw = se_outw,
+- .mv_outl = se_outl,
+-
+- .mv_inb_p = se_inb_p,
+- .mv_inw_p = se_inw,
+- .mv_inl_p = se_inl,
+- .mv_outb_p = se_outb_p,
+- .mv_outw_p = se_outw,
+- .mv_outl_p = se_outl,
+-
+- .mv_insb = se_insb,
+- .mv_insw = se_insw,
+- .mv_insl = se_insl,
+- .mv_outsb = se_outsb,
+- .mv_outsw = se_outsw,
+- .mv_outsl = se_outsl,
+-
+- .mv_isa_port2addr = se_isa_port2addr,
+-
+- .mv_init_irq = init_se_IRQ,
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_se,
+-#endif
+-};
+-ALIAS_MV(se)
+diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
+index 7d1a071..a1d51d5 100644
+--- a/arch/sh/boards/se/770x/setup.c
++++ b/arch/sh/boards/se/770x/setup.c
+@@ -7,15 +7,14 @@
+ * Hitachi SolutionEngine Support.
+ *
+ */
+-
+ #include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <linux/hdreg.h>
+-#include <linux/ide.h>
++#include <asm/machvec.h>
++#include <asm/se.h>
+ #include <asm/io.h>
+-#include <asm/se/se.h>
+-#include <asm/se/smc37c93x.h>
++#include <asm/smc37c93x.h>
++
++void heartbeat_se(void);
++void init_se_IRQ(void);
+
+ /*
+ * Configure the Super I/O chip
+@@ -26,7 +25,8 @@ static void __init smsc_config(int index
+ outb_p(data, DATA_PORT);
+ }
+
+-static void __init init_smsc(void)
++/* XXX: Another candidate for a more generic cchip machine vector */
++static void __init smsc_setup(char **cmdline_p)
+ {
+ outb_p(CONFIG_ENTER, CONFIG_PORT);
+ outb_p(CONFIG_ENTER, CONFIG_PORT);
+@@ -69,16 +69,46 @@ static void __init init_smsc(void)
+ outb_p(CONFIG_EXIT, CONFIG_PORT);
+ }
+
+-const char *get_system_type(void)
+-{
+- return "SolutionEngine";
+-}
+-
+ /*
+- * Initialize the board
++ * The Machine Vector
+ */
+-void __init platform_setup(void)
+-{
+- init_smsc();
+- /* XXX: RTC setting comes here */
+-}
++struct sh_machine_vector mv_se __initmv = {
++ .mv_name = "SolutionEngine",
++ .mv_setup = smsc_setup,
++#if defined(CONFIG_CPU_SH4)
++ .mv_nr_irqs = 48,
++#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
++ .mv_nr_irqs = 32,
++#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
++ .mv_nr_irqs = 61,
++#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
++ .mv_nr_irqs = 86,
++#endif
++
++ .mv_inb = se_inb,
++ .mv_inw = se_inw,
++ .mv_inl = se_inl,
++ .mv_outb = se_outb,
++ .mv_outw = se_outw,
++ .mv_outl = se_outl,
++
++ .mv_inb_p = se_inb_p,
++ .mv_inw_p = se_inw,
++ .mv_inl_p = se_inl,
++ .mv_outb_p = se_outb_p,
++ .mv_outw_p = se_outw,
++ .mv_outl_p = se_outl,
++
++ .mv_insb = se_insb,
++ .mv_insw = se_insw,
++ .mv_insl = se_insl,
++ .mv_outsb = se_outsb,
++ .mv_outsw = se_outsw,
++ .mv_outsl = se_outsl,
++
++ .mv_init_irq = init_se_IRQ,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_se,
++#endif
++};
++ALIAS_MV(se)
+diff --git a/arch/sh/boards/se/7751/Makefile b/arch/sh/boards/se/7751/Makefile
+index ce7ca24..188900c 100644
+--- a/arch/sh/boards/se/7751/Makefile
++++ b/arch/sh/boards/se/7751/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the 7751 SolutionEngine specific parts of the kernel
+ #
+
+-obj-y := mach.o setup.o io.o irq.o led.o
++obj-y := setup.o io.o irq.o
+
+ obj-$(CONFIG_PCI) += pci.o
+-
++obj-$(CONFIG_HEARTBEAT) += led.o
+diff --git a/arch/sh/boards/se/7751/io.c b/arch/sh/boards/se/7751/io.c
+index 99041b2..e8d846c 100644
+--- a/arch/sh/boards/se/7751/io.c
++++ b/arch/sh/boards/se/7751/io.c
+@@ -1,6 +1,4 @@
+-/*
+- * linux/arch/sh/kernel/io_7751se.c
+- *
++/*
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+@@ -10,96 +8,21 @@
+ * placeholder code from io_se.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
++#include <linux/pci.h>
+ #include <asm/io.h>
+-#include <asm/se7751/se7751.h>
++#include <asm/se7751.h>
+ #include <asm/addrspace.h>
+
+-#include <linux/pci.h>
+-#include "../../../drivers/pci/pci-sh7751.h"
+-
+-#if 0
+-/******************************************************************
+- * Variables from io_se.c, related to PCMCIA (not PCI); we're not
+- * compiling them in, and have removed references from functions
+- * which follow. [Many checked for IO ports in the range bounded
+- * by sh_pcic_io_start/stop, and used sh_pcic_io_wbase as offset.
+- * As start/stop are uninitialized, only port 0x0 would match?]
+- * When used, remember to adjust names to avoid clash with io_se?
+- *****************************************************************/
+-/* SH pcmcia io window base, start and end. */
+-int sh_pcic_io_wbase = 0xb8400000;
+-int sh_pcic_io_start;
+-int sh_pcic_io_stop;
+-int sh_pcic_io_type;
+-int sh_pcic_io_dummy;
+-/*************************************************************/
+-#endif
+-
+-/*
+- * The 7751 Solution Engine uses the built-in PCI controller (PCIC)
+- * of the 7751 processor, and has a SuperIO accessible via the PCI.
+- * The board also includes a PCMCIA controller on its memory bus,
+- * like the other Solution Engine boards.
+- */
+-
+-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+-#define PCI_IO_AREA SH7751_PCI_IO_BASE
+-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+-
+-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+-
+-#define maybebadio(name,port) \
+- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+- #name, (port), (__u32) __builtin_return_address(0))
+-
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
+-
+-static inline volatile __u16 *
+-port2adr(unsigned int port)
++static inline volatile u16 *port2adr(unsigned int port)
+ {
+ if (port >= 0x2000)
+ return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+-#if 0
+- else
+- return (volatile __u16 *) (PA_SUPERIO + (port << 1));
+-#endif
+- maybebadio(name,(unsigned long)port);
++ maybebadio((unsigned long)port);
+ return (volatile __u16*)port;
+ }
+
+-#if 0
+-/* The 7751 Solution Engine seems to have everything hooked */
+-/* up pretty normally (nothing on high-bytes only...) so this */
+-/* shouldn't be needed */
+-static inline int
+-shifted_port(unsigned long port)
+-{
+- /* For IDE registers, value is not shifted */
+- if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+- return 0;
+- else
+- return 1;
+-}
+-#endif
+-
+-/* In case someone configures the kernel w/o PCI support: in that */
+-/* scenario, don't ever bother to check for PCI-window addresses */
+-
+-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+-#if defined(CONFIG_PCI)
+-#define CHECK_SH7751_PCIIO(port) \
+- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+-#else
+-#define CHECK_SH7751_PCIIO(port) (0)
+-#endif
+-
+ /*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+@@ -111,10 +34,10 @@ unsigned char sh7751se_inb(unsigned long
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned char *)pci_ioaddr(port);
+ else
+- return (*port2adr(port))&0xff;
++ return (*port2adr(port)) & 0xff;
+ }
+
+ unsigned char sh7751se_inb_p(unsigned long port)
+@@ -123,11 +46,11 @@ unsigned char sh7751se_inb_p(unsigned lo
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- v = *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ v = *(volatile unsigned char *)pci_ioaddr(port);
+ else
+- v = (*port2adr(port))&0xff;
+- delay();
++ v = (*port2adr(port)) & 0xff;
++ ctrl_delay();
+ return v;
+ }
+
+@@ -135,12 +58,12 @@ unsigned short sh7751se_inw(unsigned lon
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned short *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned short *)pci_ioaddr(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+- maybebadio(inw, port);
++ maybebadio(port);
+ return 0;
+ }
+
+@@ -148,12 +71,12 @@ unsigned int sh7751se_inl(unsigned long
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned int *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned int *)pci_ioaddr(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+- maybebadio(inl, port);
++ maybebadio(port);
+ return 0;
+ }
+
+@@ -162,8 +85,8 @@ void sh7751se_outb(unsigned char value,
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned char*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned char*)pci_ioaddr(port)) = value;
+ else
+ *(port2adr(port)) = value;
+ }
+@@ -172,73 +95,41 @@ void sh7751se_outb_p(unsigned char value
+ {
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned char*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned char*)pci_ioaddr(port)) = value;
+ else
+ *(port2adr(port)) = value;
+- delay();
++ ctrl_delay();
+ }
+
+ void sh7751se_outw(unsigned short value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned short *)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned short *)pci_ioaddr(port)) = value;
+ else if (port >= 0x2000)
+ *port2adr(port) = value;
+ else
+- maybebadio(outw, port);
++ maybebadio(port);
+ }
+
+ void sh7751se_outl(unsigned int value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned long*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned long*)pci_ioaddr(port)) = value;
+ else
+- maybebadio(outl, port);
++ maybebadio(port);
+ }
+
+ void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
+ {
+- maybebadio(insl, port);
++ maybebadio(port);
+ }
+
+ void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
+ {
+- maybebadio(outsw, port);
+-}
+-
+-/* Map ISA bus address to the real address. Only for PCMCIA. */
+-
+-/* ISA page descriptor. */
+-static __u32 sh_isa_memmap[256];
+-
+-#if 0
+-static int
+-sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+-{
+- int idx;
+-
+- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+- return -1;
+-
+- idx = start >> 12;
+- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+- start, length, offset, idx, sh_isa_memmap[idx]);
+- return 0;
+-}
+-#endif
+-
+-unsigned long
+-sh7751se_isa_port2addr(unsigned long offset)
+-{
+- int idx;
+-
+- idx = (offset >> 12) & 0xff;
+- offset &= 0xfff;
+- return sh_isa_memmap[idx] + offset;
++ maybebadio(port);
+ }
+diff --git a/arch/sh/boards/se/7751/irq.c b/arch/sh/boards/se/7751/irq.c
+index bf6c023..e4c63a4 100644
+--- a/arch/sh/boards/se/7751/irq.c
++++ b/arch/sh/boards/se/7751/irq.c
+@@ -12,55 +12,52 @@
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <asm/irq.h>
+-#include <asm/se7751/se7751.h>
+-
+-/*
+- * Initialize IRQ setting
+- */
+-void __init init_7751se_IRQ(void)
+-{
++#include <asm/se7751.h>
+
++static struct ipr_data se7751_ipr_map[] = {
+ /* Leave old Solution Engine code in for reference. */
+ #if defined(CONFIG_SH_SOLUTION_ENGINE)
+- /*
+- * Super I/O (Just mimic PC):
+- * 1: keyboard
+- * 3: serial 0
+- * 4: serial 1
+- * 5: printer
+- * 6: floppy
+- * 8: rtc
+- * 12: mouse
+- * 14: ide0
+- */
+- make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
+- make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
+- make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
+- make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
+- make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
+- make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
+- make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
+- make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
+-
+- make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
+-
+- make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
+- make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
+- make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
+- make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
+-
+- /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
+- /* NOTE: #2 and #13 are not used on PC */
+- make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
+- make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
+-
++ /*
++ * Super I/O (Just mimic PC):
++ * 1: keyboard
++ * 3: serial 0
++ * 4: serial 1
++ * 5: printer
++ * 6: floppy
++ * 8: rtc
++ * 12: mouse
++ * 14: ide0
++ */
++ { 14, BCR_ILCRA, 2, 0x0f-14 },
++ { 12, BCR_ILCRA, 1, 0x0f-12 },
++ { 8, BCR_ILCRB, 1, 0x0f- 8 },
++ { 6, BCR_ILCRC, 3, 0x0f- 6 },
++ { 5, BCR_ILCRC, 2, 0x0f- 5 },
++ { 4, BCR_ILCRC, 1, 0x0f- 4 },
++ { 3, BCR_ILCRC, 0, 0x0f- 3 },
++ { 1, BCR_ILCRD, 3, 0x0f- 1 },
++
++ { 10, BCR_ILCRD, 1, 0x0f-10 }, /* LAN */
++
++ { 0, BCR_ILCRE, 3, 0x0f- 0 }, /* PCIRQ3 */
++ { 11, BCR_ILCRE, 2, 0x0f-11 }, /* PCIRQ2 */
++ { 9, BCR_ILCRE, 1, 0x0f- 9 }, /* PCIRQ1 */
++ { 7, BCR_ILCRE, 0, 0x0f- 7 }, /* PCIRQ0 */
++
++ /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
++ /* NOTE: #2 and #13 are not used on PC */
++ { 13, BCR_ILCRG, 1, 0x0f-13 }, /* SLOTIRQ2 */
++ { 2, BCR_ILCRG, 0, 0x0f- 2 }, /* SLOTIRQ1 */
+ #elif defined(CONFIG_SH_7751_SOLUTION_ENGINE)
+-
+- make_ipr_irq(13, BCR_ILCRD, 3, 2);
+-
+- /* Add additional calls to make_ipr_irq() as drivers are added
+- * and tested.
+- */
++ { 13, BCR_ILCRD, 3, 2 },
++ /* Add additional entries here as drivers are added and tested. */
+ #endif
++};
+
++/*
++ * Initialize IRQ setting
++ */
++void __init init_7751se_IRQ(void)
++{
++ make_ipr_irq(se7751_ipr_map, ARRAY_SIZE(se7751_ipr_map));
+ }
+diff --git a/arch/sh/boards/se/7751/led.c b/arch/sh/boards/se/7751/led.c
+index a878726..de4194d 100644
+--- a/arch/sh/boards/se/7751/led.c
++++ b/arch/sh/boards/se/7751/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/led_se.c
++ * linux/arch/sh/boards/se/7751/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy at st.com>
+ *
+@@ -8,23 +8,8 @@
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+-
+-#include <asm/se7751/se7751.h>
+-
+-static void mach_led(int position, int value)
+-{
+- volatile unsigned short* p = (volatile unsigned short*)PA_LED;
+-
+- if (value) {
+- *p |= (1<<8);
+- } else {
+- *p &= ~(1<<8);
+- }
+-}
+-
+-#ifdef CONFIG_HEARTBEAT
+-
+ #include <linux/sched.h>
++#include <asm/se7751.h>
+
+ /* Cycle the LED's in the clasic Knightrider/Sun pattern */
+ void heartbeat_7751se(void)
+@@ -64,4 +49,3 @@ void heartbeat_7751se(void)
+ *p = 1<<(bit+8);
+
+ }
+-#endif /* CONFIG_HEARTBEAT */
+diff --git a/arch/sh/boards/se/7751/mach.c b/arch/sh/boards/se/7751/mach.c
+deleted file mode 100644
+index 62d8d3e..0000000
+--- a/arch/sh/boards/se/7751/mach.c
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/mach_7751se.c
+- *
+- * Minor tweak of mach_se.c file to reference 7751se-specific items.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Machine vector for the Hitachi 7751 SolutionEngine
+- */
+-
+-#include <linux/init.h>
+-
+-#include <asm/machvec.h>
+-#include <asm/rtc.h>
+-#include <asm/machvec_init.h>
+-
+-#include <asm/se7751/io.h>
+-
+-void heartbeat_7751se(void);
+-void init_7751se_IRQ(void);
+-
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_7751se __initmv = {
+- .mv_nr_irqs = 72,
+-
+- .mv_inb = sh7751se_inb,
+- .mv_inw = sh7751se_inw,
+- .mv_inl = sh7751se_inl,
+- .mv_outb = sh7751se_outb,
+- .mv_outw = sh7751se_outw,
+- .mv_outl = sh7751se_outl,
+-
+- .mv_inb_p = sh7751se_inb_p,
+- .mv_inw_p = sh7751se_inw,
+- .mv_inl_p = sh7751se_inl,
+- .mv_outb_p = sh7751se_outb_p,
+- .mv_outw_p = sh7751se_outw,
+- .mv_outl_p = sh7751se_outl,
+-
+- .mv_insl = sh7751se_insl,
+- .mv_outsl = sh7751se_outsl,
+-
+- .mv_isa_port2addr = sh7751se_isa_port2addr,
+-
+- .mv_init_irq = init_7751se_IRQ,
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = heartbeat_7751se,
+-#endif
+-};
+-ALIAS_MV(7751se)
+diff --git a/arch/sh/boards/se/7751/pci.c b/arch/sh/boards/se/7751/pci.c
+index 3ee0301..203b292 100644
+--- a/arch/sh/boards/se/7751/pci.c
++++ b/arch/sh/boards/se/7751/pci.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/pci-7751se.c
++ * linux/arch/sh/boards/se/7751/pci.c
+ *
+ * Author: Ian DaSilva (idasilva at mvista.com)
+ *
+diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
+index 48dc5ae..f7e1dd3 100644
+--- a/arch/sh/boards/se/7751/setup.c
++++ b/arch/sh/boards/se/7751/setup.c
+@@ -1,4 +1,4 @@
+-/*
++/*
+ * linux/arch/sh/kernel/setup_7751se.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+@@ -8,81 +8,16 @@
+ * Modified for 7751 Solution Engine by
+ * Ian da Silva and Jeremy Siegel, 2001.
+ */
+-
+ #include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <linux/hdreg.h>
+-#include <linux/ide.h>
++#include <asm/machvec.h>
++#include <asm/se7751.h>
+ #include <asm/io.h>
+-#include <asm/se7751/se7751.h>
+-
+-#ifdef CONFIG_SH_KGDB
+-#include <asm/kgdb.h>
+-#endif
+-
+-/*
+- * Configure the Super I/O chip
+- */
+-#if 0
+-/* Leftover code from regular Solution Engine, for reference. */
+-/* The SH7751 Solution Engine has a different SuperIO. */
+-static void __init smsc_config(int index, int data)
+-{
+- outb_p(index, INDEX_PORT);
+- outb_p(data, DATA_PORT);
+-}
+-
+-static void __init init_smsc(void)
+-{
+- outb_p(CONFIG_ENTER, CONFIG_PORT);
+- outb_p(CONFIG_ENTER, CONFIG_PORT);
+-
+- /* FDC */
+- smsc_config(CURRENT_LDN_INDEX, LDN_FDC);
+- smsc_config(ACTIVATE_INDEX, 0x01);
+- smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */
+-
+- /* IDE1 */
+- smsc_config(CURRENT_LDN_INDEX, LDN_IDE1);
+- smsc_config(ACTIVATE_INDEX, 0x01);
+- smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */
+-
+- /* AUXIO (GPIO): to use IDE1 */
+- smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO);
+- smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */
+- smsc_config(GPIO47_INDEX, 0x00); /* nIOWOP */
+-
+- /* COM1 */
+- smsc_config(CURRENT_LDN_INDEX, LDN_COM1);
+- smsc_config(ACTIVATE_INDEX, 0x01);
+- smsc_config(IO_BASE_HI_INDEX, 0x03);
+- smsc_config(IO_BASE_LO_INDEX, 0xf8);
+- smsc_config(IRQ_SELECT_INDEX, 4); /* IRQ4 */
+-
+- /* COM2 */
+- smsc_config(CURRENT_LDN_INDEX, LDN_COM2);
+- smsc_config(ACTIVATE_INDEX, 0x01);
+- smsc_config(IO_BASE_HI_INDEX, 0x02);
+- smsc_config(IO_BASE_LO_INDEX, 0xf8);
+- smsc_config(IRQ_SELECT_INDEX, 3); /* IRQ3 */
+-
+- /* RTC */
+- smsc_config(CURRENT_LDN_INDEX, LDN_RTC);
+- smsc_config(ACTIVATE_INDEX, 0x01);
+- smsc_config(IRQ_SELECT_INDEX, 8); /* IRQ8 */
+-
+- /* XXX: PARPORT, KBD, and MOUSE will come here... */
+- outb_p(CONFIG_EXIT, CONFIG_PORT);
+-}
+-#endif
+
+-const char *get_system_type(void)
+-{
+- return "7751 SolutionEngine";
+-}
++void heartbeat_7751se(void);
++void init_7751se_IRQ(void);
+
+ #ifdef CONFIG_SH_KGDB
++#include <asm/kgdb.h>
+ static int kgdb_uart_setup(void);
+ static struct kgdb_sermap kgdb_uart_sermap =
+ { "ttyS", 0, kgdb_uart_setup, NULL };
+@@ -91,7 +26,7 @@ static struct kgdb_sermap kgdb_uart_serm
+ /*
+ * Initialize the board
+ */
+-void __init platform_setup(void)
++static void __init sh7751se_setup(char **cmdline_p)
+ {
+ /* Call init_smsc() replacement to set up SuperIO. */
+ /* XXX: RTC setting comes here */
+@@ -225,3 +160,37 @@ static int kgdb_uart_setup(void)
+ return 0;
+ }
+ #endif /* CONFIG_SH_KGDB */
++
++
++/*
++ * The Machine Vector
++ */
++
++struct sh_machine_vector mv_7751se __initmv = {
++ .mv_name = "7751 SolutionEngine",
++ .mv_setup = sh7751se_setup,
++ .mv_nr_irqs = 72,
++
++ .mv_inb = sh7751se_inb,
++ .mv_inw = sh7751se_inw,
++ .mv_inl = sh7751se_inl,
++ .mv_outb = sh7751se_outb,
++ .mv_outw = sh7751se_outw,
++ .mv_outl = sh7751se_outl,
++
++ .mv_inb_p = sh7751se_inb_p,
++ .mv_inw_p = sh7751se_inw,
++ .mv_inl_p = sh7751se_inl,
++ .mv_outb_p = sh7751se_outb_p,
++ .mv_outw_p = sh7751se_outw,
++ .mv_outl_p = sh7751se_outl,
++
++ .mv_insl = sh7751se_insl,
++ .mv_outsl = sh7751se_outsl,
++
++ .mv_init_irq = init_7751se_IRQ,
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = heartbeat_7751se,
++#endif
++};
++ALIAS_MV(7751se)
+diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c
+index d609863..0a9266b 100644
+--- a/arch/sh/boards/sh03/rtc.c
++++ b/arch/sh/boards/sh03/rtc.c
+@@ -10,9 +10,10 @@
+ #include <linux/sched.h>
+ #include <linux/time.h>
+ #include <linux/bcd.h>
+-#include <asm/io.h>
+ #include <linux/rtc.h>
+ #include <linux/spinlock.h>
++#include <asm/io.h>
++#include <asm/rtc.h>
+
+ #define RTC_BASE 0xb0000000
+ #define RTC_SEC1 (RTC_BASE + 0)
+@@ -34,8 +35,6 @@
+ #define RTC_BUSY 1
+ #define RTC_STOP 2
+
+-extern void (*rtc_get_time)(struct timespec *);
+-extern int (*rtc_set_time)(const time_t);
+ extern spinlock_t rtc_lock;
+
+ unsigned long get_cmos_time(void)
+@@ -128,6 +127,6 @@ int sh03_rtc_settimeofday(const time_t s
+
+ void sh03_time_init(void)
+ {
+- rtc_get_time = sh03_rtc_gettimeofday;
+- rtc_set_time = sh03_rtc_settimeofday;
++ rtc_sh_get_time = sh03_rtc_gettimeofday;
++ rtc_sh_set_time = sh03_rtc_settimeofday;
+ }
+diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c
+index 60290f8..5ad1e19 100644
+--- a/arch/sh/boards/sh03/setup.c
++++ b/arch/sh/boards/sh03/setup.c
+@@ -7,65 +7,56 @@
+
+ #include <linux/init.h>
+ #include <linux/irq.h>
+-#include <linux/hdreg.h>
+-#include <linux/ide.h>
++#include <linux/pci.h>
+ #include <asm/io.h>
++#include <asm/rtc.h>
+ #include <asm/sh03/io.h>
+ #include <asm/sh03/sh03.h>
+ #include <asm/addrspace.h>
+-#include "../../drivers/pci/pci-sh7751.h"
+
+-extern void (*board_time_init)(void);
+-
+-const char *get_system_type(void)
+-{
+- return "Interface CTP/PCI-SH03)";
+-}
++static struct ipr_data sh03_ipr_map[] = {
++ { IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY },
++ { IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY },
++ { IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY },
++ { IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY },
++};
+
+-void init_sh03_IRQ(void)
++static void __init init_sh03_IRQ(void)
+ {
+ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+-
+- make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
+- make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
+- make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
+- make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
++ make_ipr_irq(sh03_ipr_map, ARRAY_SIZE(sh03_ipr_map));
+ }
+
+ extern void *cf_io_base;
+
+-unsigned long sh03_isa_port2addr(unsigned long port)
++static void __iomem *sh03_ioport_map(unsigned long port, unsigned int size)
+ {
+ if (PXSEG(port))
+- return port;
++ return (void __iomem *)port;
+ /* CompactFlash (IDE) */
+- if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6)) {
+- return (unsigned long)cf_io_base + port;
+- }
+- return port + SH7751_PCI_IO_BASE;
++ if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6))
++ return (void __iomem *)((unsigned long)cf_io_base + port);
++
++ return (void __iomem *)(port + PCI_IO_BASE);
+ }
+
+-/*
+- * The Machine Vector
+- */
++/* arch/sh/boards/sh03/rtc.c */
++void sh03_time_init(void);
++
++static void __init sh03_setup(char **cmdline_p)
++{
++ board_time_init = sh03_time_init;
++}
+
+ struct sh_machine_vector mv_sh03 __initmv = {
++ .mv_name = "Interface (CTP/PCI-SH03)",
++ .mv_setup = sh03_setup,
+ .mv_nr_irqs = 48,
+- .mv_isa_port2addr = sh03_isa_port2addr,
++ .mv_ioport_map = sh03_ioport_map,
+ .mv_init_irq = init_sh03_IRQ,
+
+ #ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_sh03,
+ #endif
+ };
+-
+ ALIAS_MV(sh03)
+-
+-/* arch/sh/boards/sh03/rtc.c */
+-void sh03_time_init(void);
+-
+-int __init platform_setup(void)
+-{
+- board_time_init = sh03_time_init;
+- return 0;
+-}
+diff --git a/arch/sh/boards/sh2000/Makefile b/arch/sh/boards/sh2000/Makefile
+deleted file mode 100644
+index 05d390c..0000000
+--- a/arch/sh/boards/sh2000/Makefile
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#
+-# Makefile for the SH2000 specific parts of the kernel
+-#
+-
+-obj-y := setup.o
+-
+diff --git a/arch/sh/boards/sh2000/setup.c b/arch/sh/boards/sh2000/setup.c
+deleted file mode 100644
+index 2fe6a11..0000000
+--- a/arch/sh/boards/sh2000/setup.c
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/setup_sh2000.c
+- *
+- * Copyright (C) 2001 SUGIOKA Tochinobu
+- *
+- * SH-2000 Support.
+- *
+- */
+-
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <asm/io.h>
+-#include <asm/machvec.h>
+-#include <asm/mach/sh2000.h>
+-
+-#define CF_CIS_BASE 0xb4200000
+-
+-#define PORT_PECR 0xa4000108
+-#define PORT_PHCR 0xa400010E
+-#define PORT_ICR1 0xa4000010
+-#define PORT_IRR0 0xa4000004
+-
+-#define IDE_OFFSET 0xb6200000
+-#define NIC_OFFSET 0xb6000000
+-#define EXTBUS_OFFSET 0xba000000
+-
+-
+-const char *get_system_type(void)
+-{
+- return "sh2000";
+-}
+-
+-static unsigned long sh2000_isa_port2addr(unsigned long offset)
+-{
+- if((offset & ~7) == 0x1f0 || offset == 0x3f6)
+- return IDE_OFFSET + offset;
+- else if((offset & ~0x1f) == 0x300)
+- return NIC_OFFSET + offset;
+- return EXTBUS_OFFSET + offset;
+-}
+-
+-/*
+- * The Machine Vector
+- */
+-struct sh_machine_vector mv_sh2000 __initmv = {
+- .mv_nr_irqs = 80,
+- .mv_isa_port2addr = sh2000_isa_port2addr,
+-};
+-ALIAS_MV(sh2000)
+-
+-/*
+- * Initialize the board
+- */
+-int __init platform_setup(void)
+-{
+- /* XXX: RTC setting comes here */
+-
+- /* These should be done by BIOS/IPL ... */
+- /* Enable nCE2A, nCE2B output */
+- ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR);
+- /* Enable the Compact Flash card, and set the level interrupt */
+- ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
+- /* Enable interrupt */
+- ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR);
+- ctrl_outw(1, PORT_ICR1);
+- ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0);
+- printk(KERN_INFO "SH-2000 Setup...done\n");
+- return 0;
+-}
+diff --git a/arch/sh/boards/shmin/Makefile b/arch/sh/boards/shmin/Makefile
+new file mode 100644
+index 0000000..3190cc7
+--- /dev/null
++++ b/arch/sh/boards/shmin/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the SHMIN board.
++#
++
++obj-y := setup.o
+diff --git a/arch/sh/boards/shmin/setup.c b/arch/sh/boards/shmin/setup.c
+new file mode 100644
+index 0000000..a31a1d1
+--- /dev/null
++++ b/arch/sh/boards/shmin/setup.c
+@@ -0,0 +1,41 @@
++/*
++ * arch/sh/boards/shmin/setup.c
++ *
++ * Copyright (C) 2006 Takashi YOSHII
++ *
++ * SHMIN Support.
++ */
++#include <linux/init.h>
++#include <asm/machvec.h>
++#include <asm/shmin.h>
++#include <asm/clock.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++
++#define PFC_PHCR 0xa400010e
++
++static void __init init_shmin_irq(void)
++{
++ ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ
++ ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active.
++}
++
++static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
++{
++ static int dummy;
++
++ if ((port & ~0x1f) == SHMIN_NE_BASE)
++ return (void __iomem *)(SHMIN_IO_BASE + port);
++
++ dummy = 0;
++
++ return &dummy;
++
++}
++
++struct sh_machine_vector mv_shmin __initmv = {
++ .mv_name = "SHMIN",
++ .mv_init_irq = init_shmin_irq,
++ .mv_ioport_map = shmin_ioport_map,
++};
++ALIAS_MV(shmin)
+diff --git a/arch/sh/boards/snapgear/io.c b/arch/sh/boards/snapgear/io.c
+index e2eb78f..0f48242 100644
+--- a/arch/sh/boards/snapgear/io.c
++++ b/arch/sh/boards/snapgear/io.c
+@@ -1,6 +1,4 @@
+-/*
+- * linux/arch/sh/kernel/io_7751se.c
+- *
++/*
+ * Copyright (C) 2002 David McCullough <davidm at snapgear.com>
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+@@ -11,67 +9,22 @@
+ * placeholder code from io_se.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/pci.h>
+ #include <asm/io.h>
+ #include <asm/addrspace.h>
+
+-#include <asm/pci.h>
+-#include "../../drivers/pci/pci-sh7751.h"
+-
+ #ifdef CONFIG_SH_SECUREEDGE5410
+ unsigned short secureedge5410_ioport;
+ #endif
+
+-/*
+- * The SnapGear uses the built-in PCI controller (PCIC)
+- * of the 7751 processor
+- */
+-
+-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+-#define PCI_IO_AREA SH7751_PCI_IO_BASE
+-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+-
+-
+-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+-
+-
+-#define maybebadio(name,port) \
+- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+- #name, (port), (__u32) __builtin_return_address(0))
+-
+-
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
+-
+-
+ static inline volatile __u16 *port2adr(unsigned int port)
+ {
+-#if 0
+- if (port >= 0x2000)
+- return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+-#endif
+- maybebadio(name,(unsigned long)port);
++ maybebadio((unsigned long)port);
+ return (volatile __u16*)port;
+ }
+
+-
+-/* In case someone configures the kernel w/o PCI support: in that */
+-/* scenario, don't ever bother to check for PCI-window addresses */
+-
+-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+-#if defined(CONFIG_PCI)
+-#define CHECK_SH7751_PCIIO(port) \
+- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+-#else
+-#define CHECK_SH7751_PCIIO(port) (0)
+-#endif
+-
+ /*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+@@ -79,148 +32,106 @@ static inline volatile __u16 *port2adr(u
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+-
+ unsigned char snapgear_inb(unsigned long port)
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned char *)pci_ioaddr(port);
+ else
+- return (*port2adr(port))&0xff;
++ return (*port2adr(port)) & 0xff;
+ }
+
+-
+ unsigned char snapgear_inb_p(unsigned long port)
+ {
+ unsigned char v;
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- v = *(volatile unsigned char *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ v = *(volatile unsigned char *)pci_ioaddr(port);
+ else
+- v = (*port2adr(port))&0xff;
+- delay();
++ v = (*port2adr(port))&0xff;
++ ctrl_delay();
+ return v;
+ }
+
+-
+ unsigned short snapgear_inw(unsigned long port)
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned short *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned short *)pci_ioaddr(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+- maybebadio(inw, port);
++ maybebadio(port);
+ return 0;
+ }
+
+-
+ unsigned int snapgear_inl(unsigned long port)
+ {
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+- else if (CHECK_SH7751_PCIIO(port))
+- return *(volatile unsigned int *)PCI_IOMAP(port);
++ else if (is_pci_ioaddr(port))
++ return *(volatile unsigned int *)pci_ioaddr(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+- maybebadio(inl, port);
++ maybebadio(port);
+ return 0;
+ }
+
+-
+ void snapgear_outb(unsigned char value, unsigned long port)
+ {
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned char*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned char*)pci_ioaddr(port)) = value;
+ else
+ *(port2adr(port)) = value;
+ }
+
+-
+ void snapgear_outb_p(unsigned char value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned char*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned char*)pci_ioaddr(port)) = value;
+ else
+ *(port2adr(port)) = value;
+- delay();
++ ctrl_delay();
+ }
+
+-
+ void snapgear_outw(unsigned short value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned short *)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned short *)pci_ioaddr(port)) = value;
+ else if (port >= 0x2000)
+ *port2adr(port) = value;
+ else
+- maybebadio(outw, port);
++ maybebadio(port);
+ }
+
+-
+ void snapgear_outl(unsigned int value, unsigned long port)
+ {
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+- else if (CHECK_SH7751_PCIIO(port))
+- *((unsigned long*)PCI_IOMAP(port)) = value;
++ else if (is_pci_ioaddr(port))
++ *((unsigned long*)pci_ioaddr(port)) = value;
+ else
+- maybebadio(outl, port);
++ maybebadio(port);
+ }
+
+ void snapgear_insl(unsigned long port, void *addr, unsigned long count)
+ {
+- maybebadio(insl, port);
++ maybebadio(port);
+ }
+
+ void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
+ {
+- maybebadio(outsw, port);
+-}
+-
+-/* Map ISA bus address to the real address. Only for PCMCIA. */
+-
+-
+-/* ISA page descriptor. */
+-static __u32 sh_isa_memmap[256];
+-
+-
+-#if 0
+-static int sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+-{
+- int idx;
+-
+- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+- return -1;
+-
+- idx = start >> 12;
+- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+-#if 0
+- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+- start, length, offset, idx, sh_isa_memmap[idx]);
+-#endif
+- return 0;
+-}
+-#endif
+-
+-unsigned long snapgear_isa_port2addr(unsigned long offset)
+-{
+- int idx;
+-
+- idx = (offset >> 12) & 0xff;
+- offset &= 0xfff;
+- return sh_isa_memmap[idx] + offset;
++ maybebadio(port);
+ }
+diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c
+index b71e009..1659fdd 100644
+--- a/arch/sh/boards/snapgear/rtc.c
++++ b/arch/sh/boards/snapgear/rtc.c
+@@ -17,14 +17,9 @@
+ #include <linux/time.h>
+ #include <linux/rtc.h>
+ #include <linux/mc146818rtc.h>
+-
+ #include <asm/io.h>
+-#include <asm/rtc.h>
+-#include <asm/mc146818rtc.h>
+-
+-/****************************************************************************/
+
+-static int use_ds1302 = 0;
++static int use_ds1302;
+
+ /****************************************************************************/
+ /*
+@@ -82,10 +77,6 @@ static unsigned int ds1302_readbyte(unsi
+ unsigned int val;
+ unsigned long flags;
+
+-#if 0
+- printk("SnapGear RTC: ds1302_readbyte(addr=%x)\n", addr);
+-#endif
+-
+ local_irq_save(flags);
+ set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+@@ -104,10 +95,6 @@ static void ds1302_writebyte(unsigned in
+ {
+ unsigned long flags;
+
+-#if 0
+- printk("SnapGear RTC: ds1302_writebyte(addr=%x)\n", addr);
+-#endif
+-
+ local_irq_save(flags);
+ set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+@@ -168,11 +155,8 @@ void __init secureedge5410_rtc_init(void
+ }
+
+ if (use_ds1302) {
+- rtc_get_time = snapgear_rtc_gettimeofday;
+- rtc_set_time = snapgear_rtc_settimeofday;
+- } else {
+- rtc_get_time = sh_rtc_gettimeofday;
+- rtc_set_time = sh_rtc_settimeofday;
++ rtc_sh_get_time = snapgear_rtc_gettimeofday;
++ rtc_sh_set_time = snapgear_rtc_settimeofday;
+ }
+
+ printk("SnapGear RTC: using %s rtc.\n", use_ds1302 ? "ds1302" : "internal");
+@@ -187,10 +171,8 @@ void snapgear_rtc_gettimeofday(struct ti
+ {
+ unsigned int sec, min, hr, day, mon, yr;
+
+- if (!use_ds1302) {
+- sh_rtc_gettimeofday(ts);
++ if (!use_ds1302)
+ return;
+- }
+
+ sec = bcd2int(ds1302_readbyte(RTC_ADDR_SEC));
+ min = bcd2int(ds1302_readbyte(RTC_ADDR_MIN));
+@@ -231,7 +213,7 @@ int snapgear_rtc_settimeofday(const time
+ unsigned long nowtime;
+
+ if (!use_ds1302)
+- return sh_rtc_settimeofday(secs);
++ return 0;
+
+ /*
+ * This is called direct from the kernel timer handling code.
+@@ -240,10 +222,6 @@ int snapgear_rtc_settimeofday(const time
+
+ nowtime = secs;
+
+-#if 1
+- printk("SnapGear RTC: snapgear_rtc_settimeofday(nowtime=%ld)\n", nowtime);
+-#endif
+-
+ /* STOP RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
+
+@@ -329,5 +307,3 @@ void secureedge5410_cmos_write(unsigned
+ default: break;
+ }
+ }
+-
+-/****************************************************************************/
+diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c
+index f1f7c70..650fb36 100644
+--- a/arch/sh/boards/snapgear/setup.c
++++ b/arch/sh/boards/snapgear/setup.c
+@@ -1,5 +1,4 @@
+-/****************************************************************************/
+-/*
++/*
+ * linux/arch/sh/boards/snapgear/setup.c
+ *
+ * Copyright (C) 2002 David McCullough <davidm at snapgear.com>
+@@ -12,8 +11,6 @@
+ * Modified for 7751 Solution Engine by
+ * Ian da Silva and Jeremy Siegel, 2001.
+ */
+-/****************************************************************************/
+-
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+@@ -21,14 +18,13 @@
+ #include <linux/delay.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+-
+ #include <asm/machvec.h>
+-#include <asm/mach/io.h>
++#include <asm/snapgear.h>
+ #include <asm/irq.h>
+ #include <asm/io.h>
++#include <asm/rtc.h>
+ #include <asm/cpu/timer.h>
+
+-extern void (*board_time_init)(void);
+ extern void secureedge5410_rtc_init(void);
+ extern void pcibios_init(void);
+
+@@ -37,7 +33,7 @@ extern void pcibios_init(void);
+ * EraseConfig handling functions
+ */
+
+-static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
+ {
+ volatile char dummy __attribute__((unused)) = * (volatile char *) 0xb8000000;
+
+@@ -72,114 +68,37 @@ module_init(eraseconfig_init);
+ * IRL3 = crypto
+ */
+
+-static void __init init_snapgear_IRQ(void)
+-{
+- /* enable individual interrupt mode for externals */
+- ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+-
+- printk("Setup SnapGear IRQ/IPR ...\n");
+-
++static struct ipr_data snapgear_ipr_map[] = {
+ make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
+ make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
+ make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
+ make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
+-}
+-
+-/****************************************************************************/
+-/*
+- * Fast poll interrupt simulator.
+- */
++};
+
+-/*
+- * Leave all of the fast timer/fast poll stuff commented out for now, since
+- * it's not clear whether it actually works or not. Since it wasn't being used
+- * at all in 2.4, we'll assume it's not sane for 2.6 either.. -- PFM
+- */
+-#if 0
+-#define FAST_POLL 1000
+-//#define FAST_POLL_INTR
+-
+-#define FASTTIMER_IRQ 17
+-#define FASTTIMER_IPR_ADDR INTC_IPRA
+-#define FASTTIMER_IPR_POS 2
+-#define FASTTIMER_PRIORITY 3
+-
+-#ifdef FAST_POLL_INTR
+-#define TMU1_TCR_INIT 0x0020
+-#else
+-#define TMU1_TCR_INIT 0
+-#endif
+-#define TMU_TSTR_INIT 1
+-#define TMU1_TCR_CALIB 0x0000
+-
+-
+-#ifdef FAST_POLL_INTR
+-static void fast_timer_irq(int irq, void *dev_instance, struct pt_regs *regs)
++static void __init init_snapgear_IRQ(void)
+ {
+- unsigned long timer_status;
+- timer_status = ctrl_inw(TMU1_TCR);
+- timer_status &= ~0x100;
+- ctrl_outw(timer_status, TMU1_TCR);
+-}
+-#endif
++ /* enable individual interrupt mode for externals */
++ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+
+-/*
+- * return the current ticks on the fast timer
+- */
++ printk("Setup SnapGear IRQ/IPR ...\n");
+
+-unsigned long fast_timer_count(void)
+-{
+- return(ctrl_inl(TMU1_TCNT));
++ make_ipr_irq(snapgear_ipr_map, ARRAY_SIZE(snapgear_ipr_map));
+ }
+
+ /*
+- * setup a fast timer for profiling etc etc
++ * Initialize the board
+ */
+-
+-static void setup_fast_timer()
+-{
+- unsigned long interval;
+-
+-#ifdef FAST_POLL_INTR
+- interval = (current_cpu_data.module_clock/4 + FAST_POLL/2) / FAST_POLL;
+-
+- make_ipr_irq(FASTTIMER_IRQ, FASTTIMER_IPR_ADDR, FASTTIMER_IPR_POS,
+- FASTTIMER_PRIORITY);
+-
+- printk("SnapGear: %dHz fast timer on IRQ %d\n",FAST_POLL,FASTTIMER_IRQ);
+-
+- if (request_irq(FASTTIMER_IRQ, fast_timer_irq, 0, "SnapGear fast timer",
+- NULL) != 0)
+- printk("%s(%d): request_irq() failed?\n", __FILE__, __LINE__);
+-#else
+- printk("SnapGear: fast timer running\n",FAST_POLL,FASTTIMER_IRQ);
+- interval = 0xffffffff;
+-#endif
+-
+- ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */
+- ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
+- ctrl_outl(interval, TMU1_TCOR);
+- ctrl_outl(interval, TMU1_TCNT);
+- ctrl_outb(ctrl_inb(TMU_TSTR) | 0x2, TMU_TSTR); /* enable timer 1 */
+-
+- printk("Timer count 1 = 0x%x\n", fast_timer_count());
+- udelay(1000);
+- printk("Timer count 2 = 0x%x\n", fast_timer_count());
+-}
+-#endif
+-
+-/****************************************************************************/
+-
+-const char *get_system_type(void)
++static void __init snapgear_setup(char **cmdline_p)
+ {
+- return "SnapGear SecureEdge5410";
++ board_time_init = secureedge5410_rtc_init;
+ }
+
+ /*
+ * The Machine Vector
+ */
+-
+ struct sh_machine_vector mv_snapgear __initmv = {
++ .mv_name = "SnapGear SecureEdge5410",
++ .mv_setup = snapgear_setup,
+ .mv_nr_irqs = 72,
+
+ .mv_inb = snapgear_inb,
+@@ -196,20 +115,6 @@ struct sh_machine_vector mv_snapgear __i
+ .mv_outw_p = snapgear_outw,
+ .mv_outl_p = snapgear_outl,
+
+- .mv_isa_port2addr = snapgear_isa_port2addr,
+-
+ .mv_init_irq = init_snapgear_IRQ,
+ };
+ ALIAS_MV(snapgear)
+-
+-/*
+- * Initialize the board
+- */
+-
+-int __init platform_setup(void)
+-{
+- board_time_init = secureedge5410_rtc_init;
+-
+- return 0;
+-}
+-
+diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c
+index 4836b94..83419bf 100644
+--- a/arch/sh/boards/superh/microdev/io.c
++++ b/arch/sh/boards/superh/microdev/io.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/io_microdev.c
++ * linux/arch/sh/boards/superh/microdev/io.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan at superh.com)
+ * Copyright (C) 2003, 2004 SuperH, Inc.
+diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c
+index 236398f..8c64baa 100644
+--- a/arch/sh/boards/superh/microdev/irq.c
++++ b/arch/sh/boards/superh/microdev/irq.c
+@@ -11,14 +11,12 @@
+
+ #include <linux/init.h>
+ #include <linux/irq.h>
+-
+ #include <asm/system.h>
+ #include <asm/io.h>
+ #include <asm/microdev.h>
+
+ #define NUM_EXTERNAL_IRQS 16 /* IRL0 .. IRL15 */
+
+-
+ static const struct {
+ unsigned char fpgaIrq;
+ unsigned char mapped;
+@@ -93,53 +91,42 @@ static struct hw_interrupt_type microdev
+
+ static void disable_microdev_irq(unsigned int irq)
+ {
+- unsigned int flags;
+ unsigned int fpgaIrq;
+
+- if (irq >= NUM_EXTERNAL_IRQS) return;
+- if (!fpgaIrqTable[irq].mapped) return;
++ if (irq >= NUM_EXTERNAL_IRQS)
++ return;
++ if (!fpgaIrqTable[irq].mapped)
++ return;
+
+ fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
+
+- /* disable interrupts */
+- local_irq_save(flags);
+-
+- /* disable interupts on the FPGA INTC register */
++ /* disable interupts on the FPGA INTC register */
+ ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
+-
+- /* restore interrupts */
+- local_irq_restore(flags);
+ }
+
+ static void enable_microdev_irq(unsigned int irq)
+ {
+ unsigned long priorityReg, priorities, pri;
+- unsigned int flags;
+ unsigned int fpgaIrq;
+
+-
+- if (irq >= NUM_EXTERNAL_IRQS) return;
+- if (!fpgaIrqTable[irq].mapped) return;
++ if (unlikely(irq >= NUM_EXTERNAL_IRQS))
++ return;
++ if (unlikely(!fpgaIrqTable[irq].mapped))
++ return;
+
+ pri = 15 - irq;
+
+ fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
+ priorityReg = MICRODEV_FPGA_INTPRI_REG(fpgaIrq);
+
+- /* disable interrupts */
+- local_irq_save(flags);
+-
+- /* set priority for the interrupt */
++ /* set priority for the interrupt */
+ priorities = ctrl_inl(priorityReg);
+ priorities &= ~MICRODEV_FPGA_INTPRI_MASK(fpgaIrq);
+ priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri);
+ ctrl_outl(priorities, priorityReg);
+
+- /* enable interupts on the FPGA INTC register */
++ /* enable interupts on the FPGA INTC register */
+ ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
+-
+- /* restore interrupts */
+- local_irq_restore(flags);
+ }
+
+ /* This functions sets the desired irq handler to be a MicroDev type */
+@@ -158,9 +145,7 @@ static void mask_and_ack_microdev(unsign
+ static void end_microdev_irq(unsigned int irq)
+ {
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+- {
+ enable_microdev_irq(irq);
+- }
+ }
+
+ extern void __init init_microdev_irq(void)
+@@ -171,9 +156,7 @@ extern void __init init_microdev_irq(voi
+ ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG);
+
+ for (i = 0; i < NUM_EXTERNAL_IRQS; i++)
+- {
+ make_microdev_irq(i);
+- }
+ }
+
+ extern void microdev_print_fpga_intc_status(void)
+diff --git a/arch/sh/boards/superh/microdev/led.c b/arch/sh/boards/superh/microdev/led.c
+index a38f535..36e54b4 100644
+--- a/arch/sh/boards/superh/microdev/led.c
++++ b/arch/sh/boards/superh/microdev/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/led_microdev.c
++ * linux/arch/sh/boards/superh/microdev/led.c
+ *
+ * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
+ * Copyright (C) 2003 Richard Curnow (Richard.Curnow at superh.com)
+diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c
+index 61b402a..031c814 100644
+--- a/arch/sh/boards/superh/microdev/setup.c
++++ b/arch/sh/boards/superh/microdev/setup.c
+@@ -10,7 +10,6 @@
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+-
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
+ #include <linux/ioport.h>
+@@ -21,41 +20,6 @@
+
+ extern void microdev_heartbeat(void);
+
+-/*
+- * The Machine Vector
+- */
+-
+-struct sh_machine_vector mv_sh4202_microdev __initmv = {
+- .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */
+-
+- .mv_inb = microdev_inb,
+- .mv_inw = microdev_inw,
+- .mv_inl = microdev_inl,
+- .mv_outb = microdev_outb,
+- .mv_outw = microdev_outw,
+- .mv_outl = microdev_outl,
+-
+- .mv_inb_p = microdev_inb_p,
+- .mv_inw_p = microdev_inw_p,
+- .mv_inl_p = microdev_inl_p,
+- .mv_outb_p = microdev_outb_p,
+- .mv_outw_p = microdev_outw_p,
+- .mv_outl_p = microdev_outl_p,
+-
+- .mv_insb = microdev_insb,
+- .mv_insw = microdev_insw,
+- .mv_insl = microdev_insl,
+- .mv_outsb = microdev_outsb,
+- .mv_outsw = microdev_outsw,
+- .mv_outsl = microdev_outsl,
+-
+- .mv_init_irq = init_microdev_irq,
+-
+-#ifdef CONFIG_HEARTBEAT
+- .mv_heartbeat = microdev_heartbeat,
+-#endif
+-};
+-ALIAS_MV(sh4202_microdev)
+
+ /****************************************************************************/
+
+@@ -113,11 +77,6 @@ ALIAS_MV(sh4202_microdev)
+ /* assume a Keyboard Controller is present */
+ int microdev_kbd_controller_present = 1;
+
+-const char *get_system_type(void)
+-{
+- return "SH4-202 MicroDev";
+-}
+-
+ static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = 0x300,
+@@ -291,25 +250,9 @@ static int __init microdev_devices_setup
+ return platform_add_devices(microdev_devices, ARRAY_SIZE(microdev_devices));
+ }
+
+-__initcall(microdev_devices_setup);
+-
+-void __init platform_setup(void)
+-{
+- int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
+- const int fpgaRevision = *fpgaRevisionRegister;
+- int * const CacheControlRegister = (int*)CCR;
+-
+- printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
+- get_system_type(), fpgaRevision, *CacheControlRegister);
+-}
+-
+-
+-/****************************************************************************/
+-
+-
+- /*
+- * Setup for the SMSC FDC37C93xAPM
+- */
++/*
++ * Setup for the SMSC FDC37C93xAPM
++ */
+ static int __init smsc_superio_setup(void)
+ {
+
+@@ -412,8 +355,52 @@ static int __init smsc_superio_setup(voi
+ return 0;
+ }
+
++static void __init microdev_setup(char **cmdline_p)
++{
++ int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
++ const int fpgaRevision = *fpgaRevisionRegister;
++ int * const CacheControlRegister = (int*)CCR;
++
++ device_initcall(microdev_devices_setup);
++ device_initcall(smsc_superio_setup);
+
+-/* This is grotty, but, because kernel is always referenced on the link line
+- * before any devices, this is safe.
++ printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
++ get_system_type(), fpgaRevision, *CacheControlRegister);
++}
++
++/*
++ * The Machine Vector
+ */
+-__initcall(smsc_superio_setup);
++struct sh_machine_vector mv_sh4202_microdev __initmv = {
++ .mv_name = "SH4-202 MicroDev",
++ .mv_setup = microdev_setup,
++ .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */
++
++ .mv_inb = microdev_inb,
++ .mv_inw = microdev_inw,
++ .mv_inl = microdev_inl,
++ .mv_outb = microdev_outb,
++ .mv_outw = microdev_outw,
++ .mv_outl = microdev_outl,
++
++ .mv_inb_p = microdev_inb_p,
++ .mv_inw_p = microdev_inw_p,
++ .mv_inl_p = microdev_inl_p,
++ .mv_outb_p = microdev_outb_p,
++ .mv_outw_p = microdev_outw_p,
++ .mv_outl_p = microdev_outl_p,
++
++ .mv_insb = microdev_insb,
++ .mv_insw = microdev_insw,
++ .mv_insl = microdev_insl,
++ .mv_outsb = microdev_outsb,
++ .mv_outsw = microdev_outsw,
++ .mv_outsl = microdev_outsl,
++
++ .mv_init_irq = init_microdev_irq,
++
++#ifdef CONFIG_HEARTBEAT
++ .mv_heartbeat = microdev_heartbeat,
++#endif
++};
++ALIAS_MV(sh4202_microdev)
+diff --git a/arch/sh/boards/titan/Makefile b/arch/sh/boards/titan/Makefile
+new file mode 100644
+index 0000000..08d7537
+--- /dev/null
++++ b/arch/sh/boards/titan/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the Nimble Microsystems TITAN specific parts of the kernel
++#
++
++obj-y := setup.o io.o
+diff --git a/arch/sh/boards/titan/io.c b/arch/sh/boards/titan/io.c
+new file mode 100644
+index 0000000..4730c1d
+--- /dev/null
++++ b/arch/sh/boards/titan/io.c
+@@ -0,0 +1,126 @@
++/*
++ * I/O routines for Titan
++ */
++#include <linux/pci.h>
++#include <asm/machvec.h>
++#include <asm/addrspace.h>
++#include <asm/titan.h>
++#include <asm/io.h>
++
++static inline unsigned int port2adr(unsigned int port)
++{
++ maybebadio((unsigned long)port);
++ return port;
++}
++
++u8 titan_inb(unsigned long port)
++{
++ if (PXSEG(port))
++ return ctrl_inb(port);
++ else if (is_pci_ioaddr(port))
++ return ctrl_inb(pci_ioaddr(port));
++ return ctrl_inw(port2adr(port)) & 0xff;
++}
++
++u8 titan_inb_p(unsigned long port)
++{
++ u8 v;
++
++ if (PXSEG(port))
++ v = ctrl_inb(port);
++ else if (is_pci_ioaddr(port))
++ v = ctrl_inb(pci_ioaddr(port));
++ else
++ v = ctrl_inw(port2adr(port)) & 0xff;
++ ctrl_delay();
++ return v;
++}
++
++u16 titan_inw(unsigned long port)
++{
++ if (PXSEG(port))
++ return ctrl_inw(port);
++ else if (is_pci_ioaddr(port))
++ return ctrl_inw(pci_ioaddr(port));
++ else if (port >= 0x2000)
++ return ctrl_inw(port2adr(port));
++ else
++ maybebadio(port);
++ return 0;
++}
++
++u32 titan_inl(unsigned long port)
++{
++ if (PXSEG(port))
++ return ctrl_inl(port);
++ else if (is_pci_ioaddr(port))
++ return ctrl_inl(pci_ioaddr(port));
++ else if (port >= 0x2000)
++ return ctrl_inw(port2adr(port));
++ else
++ maybebadio(port);
++ return 0;
++}
++
++void titan_outb(u8 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outb(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outb(value, pci_ioaddr(port));
++ else
++ ctrl_outw(value, port2adr(port));
++}
++
++void titan_outb_p(u8 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outb(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outb(value, pci_ioaddr(port));
++ else
++ ctrl_outw(value, port2adr(port));
++ ctrl_delay();
++}
++
++void titan_outw(u16 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outw(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outw(value, pci_ioaddr(port));
++ else if (port >= 0x2000)
++ ctrl_outw(value, port2adr(port));
++ else
++ maybebadio(port);
++}
++
++void titan_outl(u32 value, unsigned long port)
++{
++ if (PXSEG(port))
++ ctrl_outl(value, port);
++ else if (is_pci_ioaddr(port))
++ ctrl_outl(value, pci_ioaddr(port));
++ else
++ maybebadio(port);
++}
++
++void titan_insl(unsigned long port, void *dst, unsigned long count)
++{
++ maybebadio(port);
++}
++
++void titan_outsl(unsigned long port, const void *src, unsigned long count)
++{
++ maybebadio(port);
++}
++
++void __iomem *titan_ioport_map(unsigned long port, unsigned int size)
++{
++ if (PXSEG(port) || is_pci_memaddr(port))
++ return (void __iomem *)port;
++ else if (is_pci_ioaddr(port))
++ return (void __iomem *)pci_ioaddr(port);
++
++ return (void __iomem *)port2adr(port);
++}
+diff --git a/arch/sh/boards/titan/setup.c b/arch/sh/boards/titan/setup.c
+new file mode 100644
+index 0000000..a6046d9
+--- /dev/null
++++ b/arch/sh/boards/titan/setup.c
+@@ -0,0 +1,52 @@
++/*
++ * Setup for Titan
++ */
++
++#include <linux/init.h>
++#include <asm/irq.h>
++#include <asm/titan.h>
++#include <asm/io.h>
++
++extern void __init pcibios_init_platform(void);
++
++static struct ipr_data titan_ipr_map[] = {
++ { TITAN_IRQ_WAN, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY },
++ { TITAN_IRQ_LAN, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY },
++ { TITAN_IRQ_MPCIA, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY },
++ { TITAN_IRQ_USB, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY },
++};
++
++static void __init init_titan_irq(void)
++{
++ /* enable individual interrupt mode for externals */
++ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
++
++ make_ipr_irq(titan_ipr_map, ARRAY_SIZE(titan_ipr_map));
++}
++
++struct sh_machine_vector mv_titan __initmv = {
++ .mv_name = "Titan",
++
++ .mv_inb = titan_inb,
++ .mv_inw = titan_inw,
++ .mv_inl = titan_inl,
++ .mv_outb = titan_outb,
++ .mv_outw = titan_outw,
++ .mv_outl = titan_outl,
++
++ .mv_inb_p = titan_inb_p,
++ .mv_inw_p = titan_inw,
++ .mv_inl_p = titan_inl,
++ .mv_outb_p = titan_outb_p,
++ .mv_outw_p = titan_outw,
++ .mv_outl_p = titan_outl,
++
++ .mv_insl = titan_insl,
++ .mv_outsl = titan_outsl,
++
++ .mv_ioport_map = titan_ioport_map,
++
++ .mv_init_irq = init_titan_irq,
++ .mv_init_pci = pcibios_init_platform,
++};
++ALIAS_MV(titan)
+diff --git a/arch/sh/boards/unknown/setup.c b/arch/sh/boards/unknown/setup.c
+index c5e4ed1..1c94137 100644
+--- a/arch/sh/boards/unknown/setup.c
++++ b/arch/sh/boards/unknown/setup.c
+@@ -14,19 +14,8 @@
+ */
+ #include <linux/init.h>
+ #include <asm/machvec.h>
+-#include <asm/irq.h>
+
+ struct sh_machine_vector mv_unknown __initmv = {
+- .mv_nr_irqs = NR_IRQS,
++ .mv_name = "Unknown",
+ };
+ ALIAS_MV(unknown)
+-
+-const char *get_system_type(void)
+-{
+- return "Unknown";
+-}
+-
+-void __init platform_setup(void)
+-{
+-}
+-
+diff --git a/arch/sh/boot/.gitignore b/arch/sh/boot/.gitignore
+new file mode 100644
+index 0000000..b6718de
+--- /dev/null
++++ b/arch/sh/boot/.gitignore
+@@ -0,0 +1 @@
++zImage
+diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
+index 75a6876..e5f4437 100644
+--- a/arch/sh/boot/compressed/Makefile
++++ b/arch/sh/boot/compressed/Makefile
+@@ -18,13 +18,20 @@ endif
+ # Assign dummy values if these 2 variables are not defined,
+ # in order to suppress error message.
+ #
++CONFIG_PAGE_OFFSET ?= 0x80000000
+ CONFIG_MEMORY_START ?= 0x0c000000
+ CONFIG_BOOT_LINK_OFFSET ?= 0x00800000
+-IMAGE_OFFSET := $(shell printf "0x%8x" $$[0x80000000+$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
++
++IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_PAGE_OFFSET) + \
++ $(CONFIG_MEMORY_START) + \
++ $(CONFIG_BOOT_LINK_OFFSET)])
++
++LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+ LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
+
+-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
++
++$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
+ $(call if_changed,ld)
+ @:
+
+diff --git a/arch/sh/cchips/Kconfig b/arch/sh/cchips/Kconfig
+index 155d139..0582ca8 100644
+--- a/arch/sh/cchips/Kconfig
++++ b/arch/sh/cchips/Kconfig
+@@ -65,6 +65,11 @@ config HD64461_IRQ
+
+ Do not change this unless you know what you are doing.
+
++config HD64461_IOBASE
++ hex "HD64461 start address"
++ depends on HD64461
++ default "0xb0000000"
++
+ config HD64461_ENABLER
+ bool "HD64461 PCMCIA enabler"
+ depends on HD64461
+@@ -73,7 +78,6 @@ config HD64461_ENABLER
+ via the HD64461 companion chip.
+ Otherwise, say N.
+
+-
+ config HD64465_IOBASE
+ hex "HD64465 start address"
+ depends on HD64465
+diff --git a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
+index ac30626..7909a1b 100644
+--- a/arch/sh/cchips/hd6446x/hd64461/io.c
++++ b/arch/sh/cchips/hd6446x/hd64461/io.c
+@@ -1,11 +1,10 @@
+ /*
+- * $Id: io.c,v 1.6 2004/03/16 00:07:50 lethal Exp $
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * Typical I/O routines for HD64461 system.
+ */
+
+ #include <asm/io.h>
+-#include <asm/hd64461/hd64461.h>
++#include <asm/hd64461.h>
+
+ #define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
+
+@@ -54,11 +53,6 @@ static __inline__ unsigned long PORT2ADD
+ return 0xa0000000 + (port & 0x1fffffff);
+ }
+
+-static inline void delay(void)
+-{
+- ctrl_inw(0xa0000000);
+-}
+-
+ unsigned char hd64461_inb(unsigned long port)
+ {
+ return *(volatile unsigned char*)PORT2ADDR(port);
+@@ -67,7 +61,7 @@ unsigned char hd64461_inb(unsigned long
+ unsigned char hd64461_inb_p(unsigned long port)
+ {
+ unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
+- delay();
++ ctrl_delay();
+ return v;
+ }
+
+@@ -89,7 +83,7 @@ void hd64461_outb(unsigned char b, unsig
+ void hd64461_outb_p(unsigned char b, unsigned long port)
+ {
+ *(volatile unsigned char*)PORT2ADDR(port) = b;
+- delay();
++ ctrl_delay();
+ }
+
+ void hd64461_outw(unsigned short b, unsigned long port)
+@@ -144,13 +138,13 @@ void hd64461_outsl(unsigned long port, c
+ while(count--) *addr=*buf++;
+ }
+
+-unsigned short hd64461_readw(unsigned long addr)
++unsigned short hd64461_readw(void __iomem *addr)
+ {
+- return *(volatile unsigned short*)(MEM_BASE+addr);
++ return ctrl_inw(MEM_BASE+(unsigned long __force)addr);
+ }
+
+-void hd64461_writew(unsigned short b, unsigned long addr)
++void hd64461_writew(unsigned short b, void __iomem *addr)
+ {
+- *(volatile unsigned short*)(MEM_BASE+addr) = b;
++ ctrl_outw(b, MEM_BASE+(unsigned long __force)addr);
+ }
+
+diff --git a/arch/sh/cchips/hd6446x/hd64461/setup.c b/arch/sh/cchips/hd6446x/hd64461/setup.c
+index ad12601..4d49b5c 100644
+--- a/arch/sh/cchips/hd6446x/hd64461/setup.c
++++ b/arch/sh/cchips/hd6446x/hd64461/setup.c
+@@ -11,36 +11,28 @@
+ #include <linux/interrupt.h>
+ #include <linux/init.h>
+ #include <linux/irq.h>
+-
+ #include <asm/io.h>
+ #include <asm/irq.h>
+-
+-#include <asm/hd64461/hd64461.h>
++#include <asm/hd64461.h>
+
+ static void disable_hd64461_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short nimr;
+ unsigned short mask = 1 << (irq - HD64461_IRQBASE);
+
+- local_irq_save(flags);
+ nimr = inw(HD64461_NIMR);
+ nimr |= mask;
+ outw(nimr, HD64461_NIMR);
+- local_irq_restore(flags);
+ }
+
+ static void enable_hd64461_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short nimr;
+ unsigned short mask = 1 << (irq - HD64461_IRQBASE);
+
+- local_irq_save(flags);
+ nimr = inw(HD64461_NIMR);
+ nimr &= ~mask;
+ outw(nimr, HD64461_NIMR);
+- local_irq_restore(flags);
+ }
+
+ static void mask_and_ack_hd64461(unsigned int irq)
+@@ -79,7 +71,7 @@ static struct hw_interrupt_type hd64461_
+ .end = end_hd64461_irq,
+ };
+
+-static irqreturn_t hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hd64461_interrupt(int irq, void *dev_id)
+ {
+ printk(KERN_INFO
+ "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
+diff --git a/arch/sh/cchips/hd6446x/hd64465/gpio.c b/arch/sh/cchips/hd6446x/hd64465/gpio.c
+index 72320d0..4343185 100644
+--- a/arch/sh/cchips/hd6446x/hd64465/gpio.c
++++ b/arch/sh/cchips/hd6446x/hd64465/gpio.c
+@@ -85,7 +85,7 @@ static struct {
+ void *dev;
+ } handlers[GPIO_NPORTS * 8];
+
+-static irqreturn_t hd64465_gpio_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t hd64465_gpio_interrupt(int irq, void *dev)
+ {
+ unsigned short port, pin, isr, mask, portpin;
+
+diff --git a/arch/sh/cchips/hd6446x/hd64465/setup.c b/arch/sh/cchips/hd6446x/hd64465/setup.c
+index d2b2851..d126e1f 100644
+--- a/arch/sh/cchips/hd6446x/hd64465/setup.c
++++ b/arch/sh/cchips/hd6446x/hd64465/setup.c
+@@ -25,31 +25,25 @@
+
+ static void disable_hd64465_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short nimr;
+ unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
+
+ pr_debug("disable_hd64465_irq(%d): mask=%x\n", irq, mask);
+- local_irq_save(flags);
+ nimr = inw(HD64465_REG_NIMR);
+ nimr |= mask;
+ outw(nimr, HD64465_REG_NIMR);
+- local_irq_restore(flags);
+ }
+
+
+ static void enable_hd64465_irq(unsigned int irq)
+ {
+- unsigned long flags;
+ unsigned short nimr;
+ unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
+
+ pr_debug("enable_hd64465_irq(%d): mask=%x\n", irq, mask);
+- local_irq_save(flags);
+ nimr = inw(HD64465_REG_NIMR);
+ nimr &= ~mask;
+ outw(nimr, HD64465_REG_NIMR);
+- local_irq_restore(flags);
+ }
+
+
+@@ -90,7 +84,7 @@ static struct hw_interrupt_type hd64465_
+ };
+
+
+-static irqreturn_t hd64465_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hd64465_interrupt(int irq, void *dev_id)
+ {
+ printk(KERN_INFO
+ "HD64465: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
+diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c
+index 0dc1fb8..f7ea700 100644
+--- a/arch/sh/cchips/voyagergx/irq.c
++++ b/arch/sh/cchips/voyagergx/irq.c
+@@ -17,52 +17,34 @@
+
+ Copyright 2003 (c) Lineo uSolutions,Inc.
+ */
+-/* -------------------------------------------------------------------- */
+-
+-#undef DEBUG
+-
+-#include <linux/sched.h>
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/param.h>
+-#include <linux/ioport.h>
+ #include <linux/interrupt.h>
+ #include <linux/init.h>
+-#include <linux/irq.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/rts7751r2d/rts7751r2d.h>
+-#include <asm/rts7751r2d/voyagergx_reg.h>
++#include <linux/io.h>
++#include <asm/voyagergx.h>
++#include <asm/rts7751r2d.h>
+
+ static void disable_voyagergx_irq(unsigned int irq)
+ {
+- unsigned long flags, val;
+- unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
++ unsigned long val;
++ unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
+
+- pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
+- local_irq_save(flags);
++ pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
+ val = inl(VOYAGER_INT_MASK);
+ val &= ~mask;
+ outl(val, VOYAGER_INT_MASK);
+- local_irq_restore(flags);
+ }
+
+-
+ static void enable_voyagergx_irq(unsigned int irq)
+ {
+- unsigned long flags, val;
+- unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
++ unsigned long val;
++ unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
+
+- pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
+- local_irq_save(flags);
++ pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
+ val = inl(VOYAGER_INT_MASK);
+ val |= mask;
+ outl(val, VOYAGER_INT_MASK);
+- local_irq_restore(flags);
+ }
+
+-
+ static void mask_and_ack_voyagergx(unsigned int irq)
+ {
+ disable_voyagergx_irq(irq);
+@@ -95,7 +77,7 @@ static struct hw_interrupt_type voyagerg
+ .end = end_voyagergx_irq,
+ };
+
+-static irqreturn_t voyagergx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
+ {
+ printk(KERN_INFO
+ "VoyagerGX: spurious interrupt, status: 0x%x\n",
+@@ -103,9 +85,6 @@ static irqreturn_t voyagergx_interrupt(i
+ return IRQ_HANDLED;
+ }
+
+-
+-/*====================================================*/
+-
+ static struct {
+ int (*func)(int, void *);
+ void *dev;
+@@ -147,7 +126,7 @@ int voyagergx_irq_demux(int irq)
+ } else {
+ printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
+ }
+- pr_debug("voyagergx_irq_demux %d \n", i);
++ pr_debug("voyagergx_irq_demux %ld\n", i);
+ #else
+ for (bit = 1, i = 0 ; i < VOYAGER_IRQ_NUM ; bit <<= 1, i++)
+ if (val & bit)
+@@ -195,4 +174,3 @@ void __init setup_voyagergx_irq(void)
+
+ setup_irq(IRQ_VOYAGER, &irq0);
+ }
+-
+diff --git a/arch/sh/cchips/voyagergx/setup.c b/arch/sh/cchips/voyagergx/setup.c
+index 139ca88..66b2fed 100644
+--- a/arch/sh/cchips/voyagergx/setup.c
++++ b/arch/sh/cchips/voyagergx/setup.c
+@@ -13,7 +13,7 @@
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <asm/io.h>
+-#include <asm/rts7751r2d/voyagergx_reg.h>
++#include <asm/voyagergx.h>
+
+ static int __init setup_voyagergx(void)
+ {
+diff --git a/arch/sh/configs/adx_defconfig b/arch/sh/configs/adx_defconfig
+deleted file mode 100644
+index 353bfdc..0000000
+--- a/arch/sh/configs/adx_defconfig
++++ /dev/null
+@@ -1,539 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:26 2005
+-#
+-CONFIG_SUPERH=y
+-CONFIG_UID16=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=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 is not set
+-# CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
+-# CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_HOTPLUG is not set
+-# CONFIG_IKCONFIG is not set
+-# CONFIG_EMBEDDED is not set
+-CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-# CONFIG_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
+-
+-#
+-# System type
+-#
+-# CONFIG_SH_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
+-# CONFIG_SH_EC3104 is not set
+-# CONFIG_SH_SATURN is not set
+-# CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+-# CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-CONFIG_SH_ADX=y
+-# CONFIG_SH_MPC1211 is not set
+-# CONFIG_SH_SH03 is not set
+-# CONFIG_SH_SECUREEDGE5410 is not set
+-# CONFIG_SH_HS7751RVOIP is not set
+-# CONFIG_SH_RTS7751R2D is not set
+-# CONFIG_SH_EDOSK7705 is not set
+-# CONFIG_SH_SH4202_MICRODEV is not set
+-# CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
+-CONFIG_CPU_SH4=y
+-# CONFIG_CPU_SUBTYPE_SH7604 is not set
+-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+-# CONFIG_CPU_SUBTYPE_SH7705 is not set
+-# CONFIG_CPU_SUBTYPE_SH7707 is not set
+-# CONFIG_CPU_SUBTYPE_SH7708 is not set
+-# CONFIG_CPU_SUBTYPE_SH7709 is not set
+-CONFIG_CPU_SUBTYPE_SH7750=y
+-# CONFIG_CPU_SUBTYPE_SH7751 is not set
+-# CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+-CONFIG_MMU=y
+-# CONFIG_CMDLINE_BOOL is not set
+-CONFIG_MEMORY_START=0x08000000
+-CONFIG_MEMORY_SIZE=0x00400000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_CF_ENABLER=y
+-# CONFIG_CF_AREA5 is not set
+-CONFIG_CF_AREA6=y
+-CONFIG_CF_BASE_ADDR=0xb8000000
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
+-# CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=50000000
+-
+-#
+-# CPU Frequency scaling
+-#
+-# CONFIG_CPU_FREQ is not set
+-
+-#
+-# DMA support
+-#
+-# CONFIG_SH_DMA is not set
+-
+-#
+-# Companion Chips
+-#
+-# CONFIG_HD6446X_SERIES is not set
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+-#
+-# CONFIG_PCI is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PC-card bridges
+-#
+-
+-#
+-# PCI Hotplug Support
+-#
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_FLAT is not set
+-# CONFIG_BINFMT_MISC is not set
+-
+-#
+-# SH initrd options
+-#
+-# CONFIG_EMBEDDED_RAMDISK is not set
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-# CONFIG_MTD is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-# CONFIG_BLK_DEV_LOOP is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_INITRD=y
+-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
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-CONFIG_IDE=y
+-CONFIG_IDE_MAX_HWIFS=4
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/ide.txt for help/info on IDE drives
+-#
+-# CONFIG_BLK_DEV_IDE_SATA is not set
+-CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
+-# CONFIG_BLK_DEV_IDECD 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_SH=y
+-# CONFIG_IDE_ARM is not set
+-# CONFIG_BLK_DEV_IDEDMA is not set
+-# CONFIG_IDEDMA_AUTO is not set
+-# CONFIG_BLK_DEV_HD is not set
+-
+-#
+-# SCSI device support
+-#
+-# CONFIG_SCSI 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 is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-
+-#
+-# Userland interfaces
+-#
+-CONFIG_INPUT_MOUSEDEV=y
+-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input I/O drivers
+-#
+-# CONFIG_GAMEPORT is not set
+-CONFIG_SOUND_GAMEPORT=y
+-CONFIG_SERIO=y
+-CONFIG_SERIO_I8042=y
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_CT82C710 is not set
+-CONFIG_SERIO_LIBPS2=y
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+-# Input Device Drivers
+-#
+-CONFIG_INPUT_KEYBOARD=y
+-CONFIG_KEYBOARD_ATKBD=y
+-# CONFIG_KEYBOARD_SUNKBD is not set
+-# CONFIG_KEYBOARD_LKKBD is not set
+-# CONFIG_KEYBOARD_XTKBD is not set
+-# CONFIG_KEYBOARD_NEWTON is not set
+-CONFIG_INPUT_MOUSE=y
+-CONFIG_MOUSE_PS2=y
+-# CONFIG_MOUSE_SERIAL is not set
+-# CONFIG_MOUSE_VSXXXAA is not set
+-# CONFIG_INPUT_JOYSTICK is not set
+-# CONFIG_INPUT_TOUCHSCREEN is not set
+-# CONFIG_INPUT_MISC is not set
+-
+-#
+-# Character devices
+-#
+-CONFIG_VT=y
+-CONFIG_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-# CONFIG_SERIAL_SH_SCI is not set
+-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
+-
+-#
+-# 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
+-#
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_FB is not set
+-
+-#
+-# Console display driver support
+-#
+-CONFIG_VGA_CONSOLE=y
+-CONFIG_DUMMY_CONSOLE=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
+-# CONFIG_USB_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=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_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
+-
+-#
+-# Partition Types
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
+-CONFIG_SH_STANDARD_BIOS=y
+-# CONFIG_EARLY_SCIF_CONSOLE is not set
+-# CONFIG_EARLY_PRINTK 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/sh/configs/cqreek_defconfig b/arch/sh/configs/cqreek_defconfig
+deleted file mode 100644
+index 614662a..0000000
+--- a/arch/sh/configs/cqreek_defconfig
++++ /dev/null
+@@ -1,533 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:38 2005
+-#
+-CONFIG_SUPERH=y
+-CONFIG_UID16=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=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 is not set
+-# CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
+-# CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_HOTPLUG is not set
+-# CONFIG_IKCONFIG is not set
+-# CONFIG_EMBEDDED is not set
+-CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-# CONFIG_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
+-
+-#
+-# System type
+-#
+-# CONFIG_SH_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-CONFIG_SH_CQREEK=y
+-# CONFIG_SH_DMIDA is not set
+-# CONFIG_SH_EC3104 is not set
+-# CONFIG_SH_SATURN is not set
+-# CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+-# CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+-# CONFIG_SH_MPC1211 is not set
+-# CONFIG_SH_SH03 is not set
+-# CONFIG_SH_SECUREEDGE5410 is not set
+-# CONFIG_SH_HS7751RVOIP is not set
+-# CONFIG_SH_RTS7751R2D is not set
+-# CONFIG_SH_EDOSK7705 is not set
+-# CONFIG_SH_SH4202_MICRODEV is not set
+-# CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-CONFIG_CPU_SH3=y
+-# CONFIG_CPU_SH4 is not set
+-# CONFIG_CPU_SUBTYPE_SH7604 is not set
+-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+-# CONFIG_CPU_SUBTYPE_SH7705 is not set
+-# CONFIG_CPU_SUBTYPE_SH7707 is not set
+-CONFIG_CPU_SUBTYPE_SH7708=y
+-# CONFIG_CPU_SUBTYPE_SH7709 is not set
+-# CONFIG_CPU_SUBTYPE_SH7750 is not set
+-# CONFIG_CPU_SUBTYPE_SH7751 is not set
+-# CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+-CONFIG_MMU=y
+-# CONFIG_CMDLINE_BOOL is not set
+-CONFIG_MEMORY_START=0x0c000000
+-CONFIG_MEMORY_SIZE=0x00400000
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_RTC=y
+-CONFIG_SH_DSP=y
+-CONFIG_SH_ADC=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=1193182
+-
+-#
+-# CPU Frequency scaling
+-#
+-# CONFIG_CPU_FREQ is not set
+-
+-#
+-# DMA support
+-#
+-# CONFIG_SH_DMA is not set
+-
+-#
+-# Companion Chips
+-#
+-# CONFIG_HD6446X_SERIES is not set
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+-#
+-# CONFIG_PCI is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PC-card bridges
+-#
+-
+-#
+-# PCI Hotplug Support
+-#
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_FLAT is not set
+-# CONFIG_BINFMT_MISC is not set
+-
+-#
+-# SH initrd options
+-#
+-# CONFIG_EMBEDDED_RAMDISK is not set
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-# CONFIG_MTD is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_FD is not set
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-# CONFIG_BLK_DEV_LOOP is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_INITRD=y
+-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
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-CONFIG_IDE=y
+-CONFIG_IDE_MAX_HWIFS=4
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/ide.txt for help/info on IDE drives
+-#
+-# CONFIG_BLK_DEV_IDE_SATA is not set
+-CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
+-# CONFIG_BLK_DEV_IDECD 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_SH=y
+-# CONFIG_IDE_ARM is not set
+-# CONFIG_BLK_DEV_IDEDMA is not set
+-# CONFIG_IDEDMA_AUTO is not set
+-# CONFIG_BLK_DEV_HD is not set
+-
+-#
+-# SCSI device support
+-#
+-# CONFIG_SCSI 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 is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-
+-#
+-# Userland interfaces
+-#
+-CONFIG_INPUT_MOUSEDEV=y
+-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input I/O drivers
+-#
+-# CONFIG_GAMEPORT is not set
+-CONFIG_SOUND_GAMEPORT=y
+-CONFIG_SERIO=y
+-CONFIG_SERIO_I8042=y
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_CT82C710 is not set
+-CONFIG_SERIO_LIBPS2=y
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+-# Input Device Drivers
+-#
+-CONFIG_INPUT_KEYBOARD=y
+-CONFIG_KEYBOARD_ATKBD=y
+-# CONFIG_KEYBOARD_SUNKBD is not set
+-# CONFIG_KEYBOARD_LKKBD is not set
+-# CONFIG_KEYBOARD_XTKBD is not set
+-# CONFIG_KEYBOARD_NEWTON is not set
+-CONFIG_INPUT_MOUSE=y
+-CONFIG_MOUSE_PS2=y
+-# CONFIG_MOUSE_SERIAL is not set
+-# CONFIG_MOUSE_VSXXXAA is not set
+-# CONFIG_INPUT_JOYSTICK is not set
+-# CONFIG_INPUT_TOUCHSCREEN is not set
+-# CONFIG_INPUT_MISC is not set
+-
+-#
+-# Character devices
+-#
+-CONFIG_VT=y
+-CONFIG_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-# CONFIG_SERIAL_SH_SCI is not set
+-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
+-
+-#
+-# 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
+-#
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_FB is not set
+-
+-#
+-# Console display driver support
+-#
+-CONFIG_VGA_CONSOLE=y
+-CONFIG_DUMMY_CONSOLE=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
+-# CONFIG_USB_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=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_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
+-
+-#
+-# Partition Types
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
+-CONFIG_SH_STANDARD_BIOS=y
+-# CONFIG_EARLY_PRINTK 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/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
+index 776c190..8b6b5a7 100644
+--- a/arch/sh/configs/dreamcast_defconfig
++++ b/arch/sh/configs/dreamcast_defconfig
+@@ -1,50 +1,63 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:40 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 10:51:55 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-CONFIG_CLEAN_COMPILE=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+ # General setup
+ #
+ CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-CONFIG_HOTPLUG=y
+-CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -52,82 +65,158 @@ CONFIG_CC_ALIGN_JUMPS=0
+ 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
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ CONFIG_SH_DREAMCAST=y
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ CONFIG_CPU_SUBTYPE_SH7750=y
++CONFIG_CPU_SUBTYPE_SH7091=y
++CONFIG_CPU_SUBTYPE_SH7750R=y
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ # CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_HUGETLB_PAGE_SIZE_64K=y
+-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+-# CONFIG_CMDLINE_BOOL is not set
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x01000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_PREEMPT=y
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_VSYSCALL=y
++CONFIG_HUGETLB_PAGE_SIZE_64K=y
++# CONFIG_HUGETLB_PAGE_SIZE_1MB 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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+-CONFIG_SH_OCRAM=y
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ CONFIG_SH_STORE_QUEUES=y
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
+ CONFIG_SH_PCLK_FREQ=49876504
+
+ #
+ # 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
+@@ -137,8 +226,8 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+ CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+ CONFIG_CPU_FREQ_GOV_USERSPACE=y
+ # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+-CONFIG_CPU_FREQ_TABLE=y
+-CONFIG_SH_CPU_FREQ=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_SH_CPU_FREQ is not set
+
+ #
+ # DMA support
+@@ -154,14 +243,35 @@ CONFIG_NR_DMA_CHANNELS=9
+ # CONFIG_HD6446X_SERIES is not set
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC1,115200 panic=3"
++
++#
++# Bus options
+ #
+-CONFIG_MAPLE=y
+ CONFIG_PCI=y
+ # CONFIG_SH_PCIDMA_NONCOHERENT is not set
+ CONFIG_PCI_AUTO=y
+-CONFIG_PCI_LEGACY_PROC=y
+-CONFIG_PCI_NAMES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+@@ -169,10 +279,6 @@ CONFIG_PCI_NAMES=y
+ # CONFIG_PCCARD is not set
+
+ #
+-# PC-card bridges
+-#
+-
+-#
+ # PCI Hotplug Support
+ #
+ # CONFIG_HOTPLUG_PCI is not set
+@@ -185,9 +291,92 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
+ #
+-# CONFIG_EMBEDDED_RAMDISK is not set
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
+
+ #
+ # Device Drivers
+@@ -199,6 +388,12 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_STANDALONE is not set
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -217,7 +412,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=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
+@@ -226,21 +420,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_BLK_DEV_LOOP is not set
+ # CONFIG_BLK_DEV_NBD is not set
+ # CONFIG_BLK_DEV_SX8 is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=1024
+-CONFIG_BLK_DEV_INITRD=y
+-CONFIG_INITRAMFS_SOURCE=""
+-# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD 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
+
+ #
+@@ -251,7 +433,14 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -261,6 +450,7 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -273,70 +463,8 @@ CONFIG_IOSCHED_CFQ=y
+ # CONFIG_I2O is not set
+
+ #
+-# Networking support
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
++# Network device support
+ #
+-CONFIG_PACKET=y
+-# CONFIG_PACKET_MMAP is not set
+-# CONFIG_NETLINK_DEV is not set
+-CONFIG_UNIX=y
+-# CONFIG_NET_KEY is not set
+-CONFIG_INET=y
+-# CONFIG_IP_MULTICAST is not set
+-# CONFIG_IP_ADVANCED_ROUTER is not set
+-CONFIG_IP_PNP=y
+-CONFIG_IP_PNP_DHCP=y
+-# CONFIG_IP_PNP_BOOTP is not set
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_SYN_COOKIES is not set
+-# CONFIG_INET_AH is not set
+-# CONFIG_INET_ESP is not set
+-# CONFIG_INET_IPCOMP is not set
+-# CONFIG_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
+@@ -349,6 +477,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_ARCNET is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -356,6 +489,7 @@ CONFIG_MII=y
+ # CONFIG_STNIC is not set
+ # CONFIG_HAPPYMEAL is not set
+ # CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
+ # CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_SMC91X is not set
+
+@@ -398,15 +532,22 @@ CONFIG_8139TOO=y
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+ # CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -428,6 +569,8 @@ CONFIG_8139TOO=y
+ # CONFIG_SLIP is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -443,6 +586,7 @@ CONFIG_8139TOO=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -457,19 +601,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # 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_LIBPS2=y
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+ # Input Device Drivers
+ #
+ CONFIG_INPUT_KEYBOARD=y
+@@ -478,22 +609,33 @@ CONFIG_KEYBOARD_ATKBD=y
+ # CONFIG_KEYBOARD_LKKBD is not set
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
+-# CONFIG_KEYBOARD_MAPLE is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ # CONFIG_MOUSE_SERIAL is not set
+-# CONFIG_MOUSE_MAPLE 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_I8042 is not set
++# CONFIG_SERIO_SERPORT is not set
++# CONFIG_SERIO_PCIPS2 is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_GAMEPORT is not set
++
++#
+ # Character devices
+ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -505,9 +647,11 @@ CONFIG_HW_CONSOLE=y
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=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
+@@ -528,13 +672,14 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+ CONFIG_SH_WDT=y
++# CONFIG_SH_WDT_MMAP is not set
+
+ #
+ # PCI-based Watchdog Cards
+ #
+ # CONFIG_PCIPCWATCHDOG is not set
+ # CONFIG_WDTPCI is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -547,14 +692,35 @@ CONFIG_SH_WDT=y
+ # CONFIG_RAW_DRIVER is not set
+
+ #
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -564,6 +730,7 @@ CONFIG_SH_WDT=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -573,7 +740,13 @@ CONFIG_SH_WDT=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ CONFIG_FB=y
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ # CONFIG_FB_MODE_HELPERS is not set
+ # CONFIG_FB_TILEBLITTING is not set
+ # CONFIG_FB_CIRRUS is not set
+@@ -583,9 +756,10 @@ CONFIG_FB=y
+ # CONFIG_FB_IMSTT is not set
+ CONFIG_FB_PVR2=y
+ # CONFIG_FB_EPSON1355 is not set
++# CONFIG_FB_S1D13XXX 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
+ # CONFIG_FB_RADEON is not set
+ # CONFIG_FB_ATY128 is not set
+ # CONFIG_FB_ATY is not set
+@@ -601,18 +775,20 @@ CONFIG_FB_PVR2=y
+ #
+ # Console display driver support
+ #
+-# CONFIG_VGA_CONSOLE is not set
+ CONFIG_DUMMY_CONSOLE=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+ 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
+@@ -634,12 +810,13 @@ CONFIG_LOGO_SUPERH_CLUT224=y
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -653,29 +830,64 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # 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
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+-CONFIG_ROMFS_FS=y
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
++# CONFIG_DNOTIFY is not set
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -695,16 +907,14 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=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_TMPFS_POSIX_ACL is not set
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -716,7 +926,7 @@ CONFIG_RAMFS=y
+ # CONFIG_BEFS_FS is not set
+ # CONFIG_BFS_FS is not set
+ # CONFIG_EFS_FS is not set
+-CONFIG_CRAMFS=y
++# CONFIG_CRAMFS is not set
+ # CONFIG_VXFS_FS is not set
+ # CONFIG_HPFS_FS is not set
+ # CONFIG_QNX4FS_FS is not set
+@@ -726,22 +936,14 @@ CONFIG_CRAMFS=y
+ #
+ # Network File Systems
+ #
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V4 is not set
+-# CONFIG_NFS_DIRECTIO is not set
++# CONFIG_NFS_FS is not set
+ # CONFIG_NFSD is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=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
++# CONFIG_9P_FS is not set
+
+ #
+ # Partition Types
+@@ -758,14 +960,19 @@ CONFIG_MSDOS_PARTITION=y
+ # Profiling support
+ #
+ CONFIG_PROFILING=y
+-CONFIG_OPROFILE=y
++# CONFIG_OPROFILE is not set
+
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-CONFIG_DEBUG_PREEMPT=y
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -782,13 +989,10 @@ CONFIG_DEBUG_PREEMPT=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+-CONFIG_ZLIB_INFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/hp6xx_defconfig b/arch/sh/configs/hp6xx_defconfig
+index b36f102..b931d9b 100644
+--- a/arch/sh/configs/hp6xx_defconfig
++++ b/arch/sh/configs/hp6xx_defconfig
+@@ -1,21 +1,21 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-sh
+-# Wed Jan 4 15:32:56 2006
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:10:06 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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
+
+@@ -27,26 +27,31 @@ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ # CONFIG_SYSVIPC is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
+-CONFIG_HOTPLUG=y
++# CONFIG_UTS_NS is not set
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+-# CONFIG_EMBEDDED is not set
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
++CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -56,7 +61,10 @@ CONFIG_BASE_SMALL=0
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
+
+ #
+ # IO Schedulers
+@@ -77,29 +85,26 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+ CONFIG_SH_HP6XX=y
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
+ # CONFIG_SH_LANDISK is not set
+ # CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+
+ #
+@@ -117,9 +122,11 @@ CONFIG_CPU_SH3=y
+ #
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ CONFIG_CPU_SUBTYPE_SH7709=y
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+ #
+ # SH-4 Processor Support
+@@ -142,14 +149,23 @@ CONFIG_CPU_SUBTYPE_SH7709=y
+ #
+ # SH-4A Processor Support
+ #
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+ # CONFIG_CPU_SUBTYPE_SH7770 is not set
+ # CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+ #
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
+ # Memory management options
+ #
+ CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x0c000000
++CONFIG_MEMORY_SIZE=0x00400000
++CONFIG_VSYSCALL=y
+ CONFIG_SELECT_MEMORY_MODEL=y
+ CONFIG_FLATMEM_MANUAL=y
+ # CONFIG_DISCONTIGMEM_MANUAL is not set
+@@ -158,6 +174,7 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
+
+ #
+ # Cache configuration
+@@ -165,22 +182,22 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
+ # CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
+-CONFIG_MEMORY_START=0x0c000000
+-CONFIG_MEMORY_SIZE=0x00400000
+
+ #
+ # Processor features
+ #
+ CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_SH_RTC=y
++# CONFIG_SH_FPU_EMU is not set
+ # CONFIG_SH_DSP is not set
+ CONFIG_SH_ADC=y
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_PINT_IRQ=y
++CONFIG_CPU_HAS_SR_RB=y
+
+ #
+ # Timer support
+ #
+ CONFIG_SH_TMU=y
+-CONFIG_SH_PCLK_FREQ_BOOL=y
+ CONFIG_SH_PCLK_FREQ=22110000
+
+ #
+@@ -194,7 +211,6 @@ CONFIG_SH_PCLK_FREQ=22110000
+ CONFIG_SH_DMA=y
+ CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+ # CONFIG_NR_DMA_CHANNELS_BOOL is not set
+-# CONFIG_DMA_PAGE_OPS is not set
+
+ #
+ # Companion Chips
+@@ -209,9 +225,15 @@ CONFIG_HD64461_ENABLER=y
+ #
+ # Kernel features
+ #
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
+ # CONFIG_KEXEC is not set
+-# CONFIG_PREEMPT is not set
+ # CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
+
+ #
+ # Boot options
+@@ -241,8 +263,6 @@ CONFIG_PCMCIA_IOCTL=y
+ #
+ # CONFIG_I82365 is not set
+ # CONFIG_TCIC is not set
+-CONFIG_HD64461_PCMCIA=y
+-CONFIG_HD64461_PCMCIA_SOCKETS=1
+ CONFIG_PCMCIA_PROBE=y
+
+ #
+@@ -257,6 +277,15 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
++# Power management options (EXPERIMENTAL)
++#
++CONFIG_PM=y
++CONFIG_PM_LEGACY=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_PM_SYSFS_DEPRECATED is not set
++CONFIG_APM=y
++
++#
+ # Networking
+ #
+ # CONFIG_NET is not set
+@@ -271,6 +300,7 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_STANDALONE is not set
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ CONFIG_FW_LOADER=y
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -299,6 +329,7 @@ CONFIG_FW_LOADER=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+
+@@ -315,7 +346,7 @@ CONFIG_BLK_DEV_IDE=y
+ # 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_IDECS=y
+ # CONFIG_BLK_DEV_IDECD is not set
+ # CONFIG_BLK_DEV_IDETAPE is not set
+ # CONFIG_BLK_DEV_IDEFLOPPY is not set
+@@ -325,7 +356,6 @@ CONFIG_BLK_DEV_IDEDISK=y
+ # IDE chipset support/bugfixes
+ #
+ CONFIG_IDE_GENERIC=y
+-CONFIG_IDE_SH=y
+ # CONFIG_IDE_ARM is not set
+ # CONFIG_IDE_CHIPSETS is not set
+ # CONFIG_BLK_DEV_IDEDMA is not set
+@@ -337,6 +367,12 @@ CONFIG_IDE_SH=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Old CD-ROM drivers (not SCSI, not IDE)
+@@ -356,19 +392,12 @@ CONFIG_IDE_SH=y
+ #
+ # IEEE 1394 (FireWire) support
+ #
+-# CONFIG_IEEE1394 is not set
+
+ #
+ # I2O device support
+ #
+
+ #
+-# Network device support
+-#
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+ # ISDN subsystem
+ #
+
+@@ -381,6 +410,7 @@ CONFIG_IDE_SH=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -390,17 +420,33 @@ 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_TSDEV=y
++CONFIG_INPUT_TSDEV_SCREEN_X=240
++CONFIG_INPUT_TSDEV_SCREEN_Y=320
+ # CONFIG_INPUT_EVDEV is not set
+ # CONFIG_INPUT_EVBUG is not set
+
+ #
+ # Input Device Drivers
+ #
+-# CONFIG_INPUT_KEYBOARD is not set
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ATKBD is not set
++# 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_KEYBOARD_STOWAWAY is not set
+ # CONFIG_INPUT_MOUSE is not set
+ # CONFIG_INPUT_JOYSTICK is not set
+-# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++CONFIG_TOUCHSCREEN_HP600=y
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+ # CONFIG_INPUT_MISC is not set
+
+ #
+@@ -409,6 +455,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ CONFIG_SERIO=y
+ # CONFIG_SERIO_I8042 is not set
+ # CONFIG_SERIO_SERPORT is not set
++# CONFIG_SERIO_LIBPS2 is not set
+ # CONFIG_SERIO_RAW is not set
+ # CONFIG_GAMEPORT is not set
+
+@@ -418,6 +465,7 @@ CONFIG_SERIO=y
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -442,7 +490,7 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -471,15 +519,23 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+ #
+ CONFIG_HWMON=y
+ # CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+@@ -487,13 +543,10 @@ CONFIG_HWMON=y
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -502,11 +555,13 @@ CONFIG_HWMON=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ CONFIG_FB=y
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ # CONFIG_FB_MODE_HELPERS is not set
+ # CONFIG_FB_TILEBLITTING is not set
+ # CONFIG_FB_EPSON1355 is not set
+@@ -553,7 +608,7 @@ CONFIG_SOUND=y
+ # Open Sound System
+ #
+ CONFIG_SOUND_PRIME=y
+-# CONFIG_OBSOLETE_OSS_DRIVER is not set
++# CONFIG_OSS_OBSOLETE_DRIVER is not set
+ # CONFIG_SOUND_MSNDCLAS is not set
+ # CONFIG_SOUND_MSNDPIN is not set
+ CONFIG_SOUND_SH_DAC_AUDIO=y
+@@ -564,6 +619,7 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+@@ -580,12 +636,42 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
+
+ #
+-# SN Devices
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
+ #
+
+ #
+@@ -595,7 +681,6 @@ 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
+ # CONFIG_JFS_FS is not set
+ # CONFIG_FS_POSIX_ACL is not set
+@@ -603,6 +688,7 @@ CONFIG_EXT2_FS=y
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+@@ -630,12 +716,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ # CONFIG_TMPFS is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -713,9 +800,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+ CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_FRAME_POINTER is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_UNWIND_INFO is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_KGDB is not set
+
+@@ -731,13 +823,10 @@ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+ # CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/hs7751rvoip_defconfig b/arch/sh/configs/hs7751rvoip_defconfig
+new file mode 100644
+index 0000000..e1a886d
+--- /dev/null
++++ b/arch/sh/configs/hs7751rvoip_defconfig
+@@ -0,0 +1,908 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18
++# Tue Oct 3 13:04:52 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++# CONFIG_KALLSYMS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# System type
++#
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++CONFIG_SH_HS7751RVOIP=y
++# CONFIG_SH_7710VOIPGW is not set
++# CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++CONFIG_CPU_SUBTYPE_SH7751=y
++CONFIG_CPU_SUBTYPE_SH7751R=y
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x0c000000
++CONFIG_MEMORY_SIZE=0x04000000
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
++# CONFIG_SH_STORE_QUEUES is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++
++#
++# HS7751RVoIP options
++#
++CONFIG_HS7751RVOIP_CODEC=y
++CONFIG_SH_PCLK_FREQ=60000000
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++# CONFIG_SH_DMA is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="mem=64M console=ttySC1,115200 root=/dev/hda1"
++
++#
++# Bus options
++#
++# CONFIG_PCI is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_ASK_IP_FIB_HASH=y
++# CONFIG_IP_FIB_TRIE is not set
++CONFIG_IP_FIB_HASH=y
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=m
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_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_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_INITRD is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=1
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_BLK_DEV_IDECD 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_BLK_DEV_IDEDMA is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA 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
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_STNIC is not set
++# CONFIG_SMC91X 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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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 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
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_I8042=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW 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_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=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_HW_RANDOM=y
++# CONFIG_GEN_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB is not set
++# 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
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++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_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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=y
++# CONFIG_NFS_V3_ACL is not set
++CONFIG_NFS_V4=y
++CONFIG_NFS_DIRECTIO=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=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
++# CONFIG_9P_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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_SH_STANDARD_BIOS is not set
++# CONFIG_EARLY_SCIF_CONSOLE is not set
++# CONFIG_KGDB is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
++# 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_ECB=m
++CONFIG_CRYPTO_CBC=m
++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
++#
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
+new file mode 100644
+index 0000000..238c0f1
+--- /dev/null
++++ b/arch/sh/configs/landisk_defconfig
+@@ -0,0 +1,1450 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:14:13 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_EXTRA_PASS=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# System type
++#
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++# CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
++# CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++CONFIG_SH_LANDISK=y
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++CONFIG_CPU_SUBTYPE_SH7751=y
++CONFIG_CPU_SUBTYPE_SH7751R=y
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x0c000000
++CONFIG_MEMORY_SIZE=0x04000000
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
++# CONFIG_SH_STORE_QUEUES is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=33333333
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++CONFIG_SH_DMA=y
++CONFIG_NR_ONCHIP_DMA_CHANNELS=4
++# CONFIG_NR_DMA_CHANNELS_BOOL is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++CONFIG_HEARTBEAT=y
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++CONFIG_KEXEC=y
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
++#
++CONFIG_ISA=y
++CONFIG_PCI=y
++CONFIG_SH_PCIDMA_NONCOHERENT=y
++CONFIG_PCI_AUTO=y
++CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++CONFIG_PCCARD=y
++# CONFIG_PCMCIA_DEBUG is not set
++CONFIG_PCMCIA=y
++CONFIG_PCMCIA_LOAD_CIS=y
++CONFIG_PCMCIA_IOCTL=y
++CONFIG_CARDBUS=y
++
++#
++# PC-card bridges
++#
++CONFIG_YENTA=y
++CONFIG_YENTA_O2=y
++CONFIG_YENTA_RICOH=y
++CONFIG_YENTA_TI=y
++CONFIG_YENTA_ENE_TUNE=y
++CONFIG_YENTA_TOSHIBA=y
++# CONFIG_PD6729 is not set
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++CONFIG_PCMCIA_PROBE=y
++CONFIG_PCCARD_NONSTATIC=y
++
++#
++# PCI Hotplug Support
++#
++# CONFIG_HOTPLUG_PCI is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_ASK_IP_FIB_HASH=y
++# CONFIG_IP_FIB_TRIE is not set
++CONFIG_IP_FIB_HASH=y
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_IP_NF_CONNTRACK=m
++CONFIG_IP_NF_CT_ACCT=y
++CONFIG_IP_NF_CONNTRACK_MARK=y
++# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
++# CONFIG_IP_NF_CT_PROTO_SCTP is not set
++CONFIG_IP_NF_FTP=m
++CONFIG_IP_NF_IRC=m
++# CONFIG_IP_NF_NETBIOS_NS is not set
++CONFIG_IP_NF_TFTP=m
++CONFIG_IP_NF_AMANDA=m
++# CONFIG_IP_NF_PPTP is not set
++# CONFIG_IP_NF_H323 is not set
++# CONFIG_IP_NF_SIP is not set
++CONFIG_IP_NF_QUEUE=m
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++CONFIG_LLC=m
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++CONFIG_ATALK=m
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB 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
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_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
++#
++# CONFIG_PNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_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_SX8 is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
++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=y
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++CONFIG_BLK_DEV_IDESCSI=y
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++CONFIG_IDE_GENERIC=y
++CONFIG_BLK_DEV_IDEPCI=y
++CONFIG_IDEPCI_SHARE_IRQ=y
++CONFIG_BLK_DEV_OFFBOARD=y
++CONFIG_BLK_DEV_GENERIC=y
++# CONFIG_BLK_DEV_OPTI621 is not set
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
++CONFIG_IDEDMA_PCI_AUTO=y
++CONFIG_IDEDMA_ONLYDISK=y
++CONFIG_BLK_DEV_AEC62XX=y
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++# CONFIG_BLK_DEV_CMD64X is not set
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5520 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_SC1200 is not set
++# CONFIG_BLK_DEV_PIIX 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
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
++# CONFIG_IDE_ARM is not set
++# CONFIG_IDE_CHIPSETS is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_IVB is not set
++CONFIG_IDEDMA_AUTO=y
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AHA152X is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_IN2000 is not set
++# CONFIG_SCSI_ARCMSR is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_DTC3280 is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_GENERIC_NCR5380 is not set
++# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_NCR53C406A is not set
++# CONFIG_SCSI_STEX is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_IPR is not set
++# CONFIG_SCSI_PAS16 is not set
++# CONFIG_SCSI_PSI240I is not set
++# CONFIG_SCSI_QLOGIC_FAS is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_SYM53C416 is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_T128 is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# PCMCIA SCSI adapter support
++#
++# CONFIG_PCMCIA_AHA152X is not set
++# CONFIG_PCMCIA_FDOMAIN is not set
++# CONFIG_PCMCIA_NINJA_SCSI is not set
++# CONFIG_PCMCIA_QLOGIC is not set
++# CONFIG_PCMCIA_SYM53C500 is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
++# Old CD-ROM drivers (not SCSI, not IDE)
++#
++# CONFIG_CD_NO_IDESCSI is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++CONFIG_MD=y
++CONFIG_BLK_DEV_MD=m
++CONFIG_MD_LINEAR=m
++CONFIG_MD_RAID0=m
++CONFIG_MD_RAID1=m
++# CONFIG_MD_RAID10 is not set
++# CONFIG_MD_RAID456 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_MD_FAULTY is not set
++# CONFIG_BLK_DEV_DM is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=m
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_STNIC is not set
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_SMC91X is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++
++#
++# Tulip family network device support
++#
++# CONFIG_NET_TULIP 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=y
++# CONFIG_PCNET32 is not set
++# CONFIG_AMD8111_ETH is not set
++# CONFIG_ADAPTEC_STARFIRE is not set
++# CONFIG_AC3200 is not set
++# CONFIG_APRICOT is not set
++# CONFIG_B44 is not set
++# CONFIG_FORCEDETH is not set
++# CONFIG_CS89x0 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 is not set
++CONFIG_8139CP=y
++# 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_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
++
++#
++# Ethernet (10000 Mbit)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# PCMCIA network device support
++#
++# CONFIG_NET_PCMCIA is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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 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
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_CONSOLE=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
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# 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
++
++#
++# PCMCIA character devices
++#
++# CONFIG_SYNCLINK_CS is not set
++# CONFIG_CARDMAN_4000 is not set
++# CONFIG_CARDMAN_4040 is not set
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L1=y
++CONFIG_VIDEO_V4L1_COMPAT=y
++CONFIG_VIDEO_V4L2=y
++
++#
++# Video Capture Adapters
++#
++
++#
++# Video Capture Adapters
++#
++# CONFIG_VIDEO_ADV_DEBUG is not set
++CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
++# CONFIG_VIDEO_VIVI is not set
++# CONFIG_VIDEO_PMS is not set
++# CONFIG_VIDEO_CPIA is not set
++# CONFIG_VIDEO_CPIA2 is not set
++# CONFIG_VIDEO_STRADIS is not set
++
++#
++# V4L USB devices
++#
++CONFIG_VIDEO_USBVIDEO=m
++CONFIG_USB_VICAM=m
++CONFIG_USB_IBMCAM=m
++CONFIG_USB_KONICAWC=m
++# CONFIG_USB_QUICKCAM_MESSENGER is not set
++# CONFIG_USB_ET61X251 is not set
++CONFIG_USB_OV511=m
++CONFIG_USB_SE401=m
++CONFIG_USB_SN9C102=m
++CONFIG_USB_STV680=m
++# CONFIG_USB_ZC0301 is not set
++CONFIG_USB_PWC=m
++# CONFIG_USB_PWC_DEBUG is not set
++
++#
++# Radio Adapters
++#
++# CONFIG_RADIO_CADET is not set
++# CONFIG_RADIO_RTRACK is not set
++# CONFIG_RADIO_RTRACK2 is not set
++# CONFIG_RADIO_AZTECH is not set
++# CONFIG_RADIO_GEMTEK is not set
++# CONFIG_RADIO_GEMTEK_PCI is not set
++# CONFIG_RADIO_MAXIRADIO is not set
++# CONFIG_RADIO_MAESTRO is not set
++# CONFIG_RADIO_SF16FMI is not set
++# CONFIG_RADIO_SF16FMR2 is not set
++# CONFIG_RADIO_TERRATEC is not set
++# CONFIG_RADIO_TRUST is not set
++# CONFIG_RADIO_TYPHOON is not set
++# CONFIG_RADIO_ZOLTRIX is not set
++CONFIG_USB_DSBR=m
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++CONFIG_USB_DABUSB=m
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB is not set
++
++#
++# Console display driver support
++#
++# CONFIG_MDA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FONT_8x16=y
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=m
++
++#
++# Advanced Linux Sound Architecture
++#
++# CONFIG_SND is not set
++
++#
++# Open Sound System
++#
++CONFIG_SOUND_PRIME=m
++# CONFIG_OSS_OBSOLETE_DRIVER is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++
++#
++# USB support
++#
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_SPLIT_ISO is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++# CONFIG_USB_EHCI_TT_NEWSCHED 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 is not set
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++CONFIG_USB_PRINTER=m
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# may also be needed; see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=m
++# CONFIG_USB_STORAGE_DEBUG is not set
++CONFIG_USB_STORAGE_DATAFAB=y
++CONFIG_USB_STORAGE_FREECOM=y
++CONFIG_USB_STORAGE_ISD200=y
++CONFIG_USB_STORAGE_DPCM=y
++# CONFIG_USB_STORAGE_USBAT is not set
++CONFIG_USB_STORAGE_SDDR09=y
++CONFIG_USB_STORAGE_SDDR55=y
++CONFIG_USB_STORAGE_JUMPSHOT=y
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=m
++CONFIG_USB_HIDINPUT=y
++# CONFIG_USB_HIDINPUT_POWERBOOK is not set
++# CONFIG_HID_FF is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++# CONFIG_USB_USBNET is not set
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_AIRPRIME is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++CONFIG_USB_SERIAL_FTDI_SIO=m
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=m
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++
++#
++# USB Miscellaneous drivers
++#
++CONFIG_USB_EMI62=m
++CONFIG_USB_EMI26=m
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++CONFIG_USB_SISUSBVGA=m
++CONFIG_USB_SISUSBVGA_CON=y
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TEST is not set
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++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=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=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_REISERFS_FS_XATTR is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=m
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++CONFIG_NTFS_FS=m
++# CONFIG_NTFS_DEBUG is not set
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++# CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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=m
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_UFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++CONFIG_NFS_FS=m
++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=m
++CONFIG_NFSD_V3=y
++# CONFIG_NFSD_V3_ACL is not set
++# CONFIG_NFSD_V4 is not set
++CONFIG_NFSD_TCP=y
++CONFIG_LOCKD=m
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=m
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=m
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++CONFIG_SMB_FS=m
++# CONFIG_SMB_NLS_DEFAULT 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
++# CONFIG_9P_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=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++CONFIG_NLS_CODEPAGE_932=y
++# 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_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++CONFIG_SH_STANDARD_BIOS=y
++# CONFIG_EARLY_SCIF_CONSOLE is not set
++# CONFIG_EARLY_PRINTK 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
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/microdev_defconfig b/arch/sh/configs/microdev_defconfig
+index ab3db76..e89d951 100644
+--- a/arch/sh/configs/microdev_defconfig
++++ b/arch/sh/configs/microdev_defconfig
+@@ -1,19 +1,21 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.16-rc1
+-# Fri Jan 27 19:43:20 2006
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:27:01 2006
+ #
+ CONFIG_SUPERH=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-CONFIG_CLEAN_COMPILE=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_LOCK_KERNEL=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+@@ -28,13 +30,17 @@ CONFIG_SWAP=y
+ # CONFIG_POSIX_MQUEUE is not set
+ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_UID16=y
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+ CONFIG_HOTPLUG=y
+@@ -45,11 +51,9 @@ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -62,7 +66,10 @@ CONFIG_BASE_SMALL=0
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ # CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
+
+ #
+ # IO Schedulers
+@@ -83,30 +90,26 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+ # CONFIG_SH_HP6XX is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
+ # CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ CONFIG_SH_SH4202_MICRODEV=y
+ # CONFIG_SH_LANDISK is not set
+ # CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+
+ #
+@@ -124,9 +127,11 @@ CONFIG_CPU_SH4=y
+ #
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+ #
+ # SH-4 Processor Support
+@@ -149,14 +154,25 @@ CONFIG_CPU_SUBTYPE_SH4_202=y
+ #
+ # SH-4A Processor Support
+ #
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+ # CONFIG_CPU_SUBTYPE_SH7770 is not set
+ # CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+ #
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
+ # Memory management options
+ #
+ CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x08000000
++CONFIG_MEMORY_SIZE=0x04000000
++CONFIG_VSYSCALL=y
++CONFIG_HUGETLB_PAGE_SIZE_64K=y
++# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+ CONFIG_SELECT_MEMORY_MODEL=y
+ CONFIG_FLATMEM_MANUAL=y
+ # CONFIG_DISCONTIGMEM_MANUAL is not set
+@@ -165,22 +181,21 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
+
+ #
+ # Cache configuration
+ #
+ # CONFIG_SH_DIRECT_MAPPED is not set
+-# CONFIG_SH_WRITETHROUGH is not set
++CONFIG_SH_WRITETHROUGH=y
+ # CONFIG_SH_OCRAM is not set
+-CONFIG_MEMORY_START=0x08000000
+-CONFIG_MEMORY_SIZE=0x04000000
+
+ #
+ # Processor features
+ #
+ CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_SH_RTC=y
+ CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+ CONFIG_CPU_HAS_INTEVT=y
+ CONFIG_CPU_HAS_SR_RB=y
+@@ -212,9 +227,16 @@ CONFIG_HEARTBEAT=y
+ #
+ # Kernel features
+ #
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
+ # CONFIG_KEXEC is not set
+-CONFIG_PREEMPT=y
+ # CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
+
+ #
+ # Boot options
+@@ -223,12 +245,12 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000
+ CONFIG_BOOT_LINK_OFFSET=0x00800000
+ # CONFIG_UBC_WAKEUP is not set
+ CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="console=ttySC0,115200"
++CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/hda1"
+
+ #
+ # Bus options
+ #
+-# CONFIG_SUPERHYWAY is not set
++CONFIG_SUPERHYWAY=y
+ # CONFIG_PCI is not set
+
+ #
+@@ -248,6 +270,11 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
+ # Networking
+ #
+ CONFIG_NET=y
+@@ -255,15 +282,19 @@ CONFIG_NET=y
+ #
+ # Networking options
+ #
++# CONFIG_NETDEBUG is not set
+ # CONFIG_PACKET is not set
+ # CONFIG_UNIX is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
+ # 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_DHCP is not set
+ # CONFIG_IP_PNP_BOOTP is not set
+ # CONFIG_IP_PNP_RARP is not set
+ # CONFIG_NET_IPIP is not set
+@@ -273,12 +304,19 @@ CONFIG_IP_PNP_DHCP=y
+ # CONFIG_INET_AH is not set
+ # CONFIG_INET_ESP is not set
+ # CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+ #
+@@ -304,7 +342,6 @@ CONFIG_TCP_CONG_BIC=y
+ # 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
+
+@@ -332,6 +369,7 @@ CONFIG_TCP_CONG_BIC=y
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -361,6 +399,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+@@ -397,6 +436,12 @@ CONFIG_IDE_GENERIC=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -502,6 +547,7 @@ CONFIG_SMC91X=y
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -518,7 +564,8 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-CONFIG_RTC=y
++CONFIG_HW_RANDOM=y
++# CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+
+@@ -547,13 +594,15 @@ CONFIG_RTC=y
+ #
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+ #
+ CONFIG_HWMON=y
+ # CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+@@ -561,13 +610,10 @@ CONFIG_HWMON=y
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -577,7 +623,9 @@ CONFIG_HWMON=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -589,6 +637,7 @@ CONFIG_HWMON=y
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+@@ -605,15 +654,42 @@ CONFIG_HWMON=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+
+ #
+-# SN Devices
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
+ #
+
+ #
+-# EDAC - error detection and reporting (RAS)
++# DMA Devices
+ #
+
+ #
+@@ -637,6 +713,7 @@ CONFIG_FS_MBCACHE=y
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+@@ -664,12 +741,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+-# CONFIG_HUGETLBFS is not set
+-# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_TMPFS_POSIX_ACL is not set
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+ # CONFIG_CONFIGFS_FS is not set
+
+ #
+@@ -772,10 +850,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ # CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+ CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_FRAME_POINTER is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_UNWIND_INFO is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -790,6 +872,9 @@ CONFIG_LOG_BUF_SHIFT=14
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_MANAGER=y
+ # CONFIG_CRYPTO_HMAC is not set
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -799,6 +884,8 @@ CONFIG_CRYPTO_MD5=y
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_ECB=y
++CONFIG_CRYPTO_CBC=y
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+@@ -813,7 +900,6 @@ CONFIG_CRYPTO_DES=y
+ # 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
+@@ -826,3 +912,4 @@ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
+new file mode 100644
+index 0000000..34e2046
+--- /dev/null
++++ b/arch/sh/configs/r7780rp_defconfig
+@@ -0,0 +1,1243 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.19-rc3
++# Tue Oct 31 12:32:06 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++# CONFIG_GENERIC_TIME is not set
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++# CONFIG_FUTEX is not set
++# CONFIG_EPOLL is not set
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++CONFIG_DEFAULT_NOOP=y
++CONFIG_DEFAULT_IOSCHED="noop"
++
++#
++# System type
++#
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++# CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
++# CONFIG_SH_RTS7751R2D is not set
++CONFIG_SH_R7780RP=y
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH4=y
++CONFIG_CPU_SH4A=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++# CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++CONFIG_CPU_SUBTYPE_SH7780=y
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x08000000
++CONFIG_MEMORY_SIZE=0x08000000
++# CONFIG_32BIT is not set
++CONFIG_VSYSCALL=y
++CONFIG_HUGETLB_PAGE_SIZE_64K=y
++# CONFIG_HUGETLB_PAGE_SIZE_1MB 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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
++CONFIG_SH_STORE_QUEUES=y
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_INTC2_IRQ=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++
++#
++# R7780RP options
++#
++CONFIG_SH_R7780MP=y
++CONFIG_SH_PCLK_FREQ=32000000
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++# CONFIG_SH_DMA is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="mem=128M console=ttySC0,115200 root=/dev/sda1"
++
++#
++# Bus options
++#
++CONFIG_PCI=y
++CONFIG_SH_PCIDMA_NONCOHERENT=y
++CONFIG_PCI_AUTO=y
++CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
++# CONFIG_PCI_DEBUG is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++CONFIG_HOTPLUG_PCI=y
++# CONFIG_HOTPLUG_PCI_FAKE is not set
++# CONFIG_HOTPLUG_PCI_CPCI is not set
++# CONFIG_HOTPLUG_PCI_SHPC is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_ASK_IP_FIB_HASH=y
++# CONFIG_IP_FIB_TRIE is not set
++CONFIG_IP_FIB_HASH=y
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++CONFIG_BRIDGE=m
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++CONFIG_LLC=m
++# 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++CONFIG_WIRELESS_EXT=y
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=m
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_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_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=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# Misc devices
++#
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=m
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_IPR is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++CONFIG_ATA=y
++# CONFIG_SATA_AHCI is not set
++# CONFIG_SATA_SVW is not set
++# CONFIG_ATA_PIIX is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
++# CONFIG_PDC_ADMA is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++CONFIG_SATA_SIL=y
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
++# CONFIG_PATA_ALI is not set
++# CONFIG_PATA_AMD is not set
++# CONFIG_PATA_ARTOP is not set
++# CONFIG_PATA_ATIIXP is not set
++# CONFIG_PATA_CMD64X is not set
++# CONFIG_PATA_CS5520 is not set
++# CONFIG_PATA_CS5530 is not set
++# CONFIG_PATA_CYPRESS is not set
++# CONFIG_PATA_EFAR is not set
++# CONFIG_ATA_GENERIC is not set
++# CONFIG_PATA_HPT366 is not set
++# CONFIG_PATA_HPT37X is not set
++# CONFIG_PATA_HPT3X2N is not set
++# CONFIG_PATA_HPT3X3 is not set
++# CONFIG_PATA_IT821X is not set
++# CONFIG_PATA_JMICRON is not set
++# CONFIG_PATA_TRIFLEX is not set
++# CONFIG_PATA_MPIIX is not set
++# CONFIG_PATA_OLDPIIX is not set
++# CONFIG_PATA_NETCELL is not set
++# CONFIG_PATA_NS87410 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_OPTIDMA is not set
++# CONFIG_PATA_PDC_OLD is not set
++# CONFIG_PATA_RADISYS is not set
++# CONFIG_PATA_RZ1000 is not set
++# CONFIG_PATA_SC1200 is not set
++# CONFIG_PATA_SERVERWORKS is not set
++# CONFIG_PATA_PDC2027X is not set
++# CONFIG_PATA_SIL680 is not set
++# CONFIG_PATA_SIS is not set
++# CONFIG_PATA_VIA is not set
++# CONFIG_PATA_WINBOND is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++
++#
++# Network device support
++#
++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
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_STNIC is not set
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_SMC91X 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=m
++# CONFIG_PCNET32_NAPI 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 is not set
++CONFIG_8139CP=m
++CONFIG_8139TOO=m
++# CONFIG_8139TOO_PIO is not set
++# CONFIG_8139TOO_TUNE_TWISTER is not set
++CONFIG_8139TOO_8129=y
++# CONFIG_8139_OLD_RX_RESET 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=m
++CONFIG_VIA_RHINE_MMIO=y
++# CONFIG_VIA_RHINE_NAPI is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++CONFIG_E1000=m
++# CONFIG_E1000_NAPI is not set
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++CONFIG_R8169=y
++# CONFIG_R8169_NAPI is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
++
++#
++# Ethernet (10000 Mbit)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
++
++#
++# Obsolete Wireless cards support (pre-802.11)
++#
++# CONFIG_STRIP is not set
++
++#
++# Wireless 802.11b ISA/PCI cards support
++#
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
++CONFIG_HERMES=m
++# CONFIG_PLX_HERMES is not set
++# CONFIG_TMD_HERMES is not set
++# CONFIG_NORTEL_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=m
++# CONFIG_HOSTAP 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_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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 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_KEYBOARD_STOWAWAY 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
++
++#
++# 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_LIBPS2=y
++# CONFIG_SERIO_RAW 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_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_CONSOLE=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
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# 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
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=m
++
++#
++# Advanced Linux Sound Architecture
++#
++# CONFIG_SND is not set
++
++#
++# Open Sound System
++#
++CONFIG_SOUND_PRIME=m
++# CONFIG_OSS_OBSOLETE_DRIVER is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++
++#
++# USB support
++#
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++
++#
++# RTC drivers
++#
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++CONFIG_RTC_DRV_SH=y
++# CONFIG_RTC_DRV_TEST is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++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=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4DEV_FS is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS 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_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++CONFIG_NTFS_FS=y
++# CONFIG_NTFS_DEBUG is not set
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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=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=y
++CONFIG_NFSD_TCP=y
++CONFIG_ROOT_NFS=y
++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
++# 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
++# CONFIG_9P_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=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++CONFIG_NLS_CODEPAGE_932=y
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS 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_SPINLOCK=y
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_INFO is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
++CONFIG_FRAME_POINTER=y
++CONFIG_FORCED_INLINING=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_SH_STANDARD_BIOS is not set
++# CONFIG_EARLY_SCIF_CONSOLE is not set
++# CONFIG_DEBUG_STACKOVERFLOW is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_4KSTACKS is not set
++# CONFIG_KGDB is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_HMAC=y
++# 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_ECB=m
++CONFIG_CRYPTO_CBC=y
++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
++#
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
+diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
+index e43cf57..099e98f 100644
+--- a/arch/sh/configs/rts7751r2d_defconfig
++++ b/arch/sh/configs/rts7751r2d_defconfig
+@@ -1,125 +1,215 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:42 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:38:36 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-CONFIG_HOTPLUG=y
+-CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # 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
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ CONFIG_SH_RTS7751R2D=y
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ CONFIG_CPU_SUBTYPE_SH7751=y
++CONFIG_CPU_SUBTYPE_SH7751R=y
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x04000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00010000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++
++#
++# RTS7751R2D options
++#
+ CONFIG_RTS7751R2D_REV11=y
+-CONFIG_SH_PCLK_CALC=y
+ CONFIG_SH_PCLK_FREQ=60000000
+
+ #
+@@ -140,17 +230,37 @@ CONFIG_NR_ONCHIP_DMA_CHANNELS=8
+ CONFIG_VOYAGERGX=y
+ # CONFIG_HD6446X_SERIES is not set
+ CONFIG_HEARTBEAT=y
+-CONFIG_RTC_9701JE=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00010000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
++
++#
++# Bus options
+ #
+ CONFIG_PCI=y
+ CONFIG_SH_PCIDMA_NONCOHERENT=y
+ CONFIG_PCI_AUTO=y
+ CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+@@ -158,10 +268,6 @@ CONFIG_PCI_NAMES=y
+ # CONFIG_PCCARD is not set
+
+ #
+-# PC-card bridges
+-#
+-
+-#
+ # PCI Hotplug Support
+ #
+ CONFIG_HOTPLUG_PCI=y
+@@ -177,6 +283,95 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++CONFIG_WIRELESS_EXT=y
++
++#
+ # Device Drivers
+ #
+
+@@ -186,6 +381,12 @@ CONFIG_BINFMT_ELF=y
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -204,7 +405,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=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
+@@ -216,18 +416,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_BLK_DEV_INITRD is not set
+-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
+
+ #
+@@ -253,7 +444,6 @@ CONFIG_BLK_DEV_IDEDISK=y
+ #
+ CONFIG_IDE_GENERIC=y
+ # CONFIG_BLK_DEV_IDEPCI is not set
+-CONFIG_IDE_SH=y
+ # CONFIG_IDE_ARM is not set
+ # CONFIG_BLK_DEV_IDEDMA is not set
+ # CONFIG_IDEDMA_AUTO is not set
+@@ -262,7 +452,14 @@ CONFIG_IDE_SH=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -272,6 +469,7 @@ CONFIG_IDE_SH=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -284,67 +482,8 @@ CONFIG_IDE_SH=y
+ # CONFIG_I2O is not set
+
+ #
+-# Networking support
++# Network device 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 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
+@@ -357,6 +496,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_ARCNET is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -364,6 +508,7 @@ CONFIG_MII=y
+ # CONFIG_STNIC is not set
+ # CONFIG_HAPPYMEAL is not set
+ # CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
+ # CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_SMC91X is not set
+
+@@ -406,15 +551,22 @@ CONFIG_8139TOO=y
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+ # CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -425,6 +577,7 @@ CONFIG_8139TOO=y
+ # Wireless LAN (non-hamradio)
+ #
+ CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+ #
+ # Obsolete Wireless cards support (pre-802.11)
+@@ -434,9 +587,12 @@ CONFIG_NET_RADIO=y
+ #
+ # Wireless 802.11b ISA/PCI cards support
+ #
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
+ CONFIG_HERMES=m
+ # CONFIG_PLX_HERMES is not set
+ # CONFIG_TMD_HERMES is not set
++# CONFIG_NORTEL_HERMES is not set
+ # CONFIG_PCI_HERMES is not set
+ # CONFIG_ATMEL is not set
+
+@@ -444,6 +600,7 @@ CONFIG_HERMES=m
+ # Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+ #
+ # CONFIG_PRISM54 is not set
++# CONFIG_HOSTAP is not set
+ CONFIG_NET_WIRELESS=y
+
+ #
+@@ -456,6 +613,8 @@ CONFIG_NET_WIRELESS=y
+ # CONFIG_SLIP is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -473,20 +632,10 @@ CONFIG_NET_WIRELESS=y
+ # CONFIG_INPUT is not set
+
+ #
+-# Userland interfaces
+-#
+-
++# Hardware I/O ports
+ #
+-# 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_GAMEPORT is not set
+
+ #
+ # Character devices
+@@ -503,6 +652,7 @@ CONFIG_SOUND_GAMEPORT=y
+ # Non-8250 serial port support
+ #
+ # CONFIG_SERIAL_SH_SCI is not set
++# CONFIG_SERIAL_JSM is not set
+ # CONFIG_UNIX98_PTYS is not set
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+@@ -516,7 +666,7 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -529,14 +679,35 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # CONFIG_RAW_DRIVER is not set
+
+ #
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -546,6 +717,7 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -555,7 +727,9 @@ CONFIG_LEGACY_PTY_COUNT=256
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -573,6 +747,9 @@ CONFIG_SND_RAWMIDI=m
+ # CONFIG_SND_SEQUENCER is not set
+ # CONFIG_SND_MIXER_OSS is not set
+ # CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
+ # CONFIG_SND_VERBOSE_PRINTK is not set
+ # CONFIG_SND_DEBUG is not set
+
+@@ -581,6 +758,8 @@ CONFIG_SND_RAWMIDI=m
+ #
+ CONFIG_SND_MPU401_UART=m
+ CONFIG_SND_OPL3_LIB=m
++CONFIG_SND_AC97_CODEC=m
++CONFIG_SND_AC97_BUS=m
+ # CONFIG_SND_DUMMY is not set
+ # CONFIG_SND_MTPAV is not set
+ # CONFIG_SND_SERIAL_U16550 is not set
+@@ -589,7 +768,8 @@ CONFIG_SND_OPL3_LIB=m
+ #
+ # PCI devices
+ #
+-CONFIG_SND_AC97_CODEC=m
++# CONFIG_SND_AD1889 is not set
++# CONFIG_SND_ALS300 is not set
+ # CONFIG_SND_ALI5451 is not set
+ # CONFIG_SND_ATIIXP is not set
+ # CONFIG_SND_ATIIXP_MODEM is not set
+@@ -598,73 +778,63 @@ CONFIG_SND_AC97_CODEC=m
+ # CONFIG_SND_AU8830 is not set
+ # CONFIG_SND_AZT3328 is not set
+ # CONFIG_SND_BT87X is not set
+-# CONFIG_SND_CS46XX is not set
++# CONFIG_SND_CA0106 is not set
++# CONFIG_SND_CMIPCI is not set
+ # CONFIG_SND_CS4281 is not set
++# CONFIG_SND_CS46XX 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
+-# CONFIG_SND_RME32 is not set
+-# CONFIG_SND_RME96 is not set
+-# CONFIG_SND_RME9652 is not set
+-# CONFIG_SND_HDSP is not set
+-# CONFIG_SND_TRIDENT is not set
+-CONFIG_SND_YMFPCI=m
+-# CONFIG_SND_ALS4000 is not set
+-# CONFIG_SND_CMIPCI is not set
+ # CONFIG_SND_ENS1370 is not set
+ # CONFIG_SND_ENS1371 is not set
+ # CONFIG_SND_ES1938 is not set
+ # CONFIG_SND_ES1968 is not set
+-# CONFIG_SND_MAESTRO3 is not set
+ # CONFIG_SND_FM801 is not set
++# CONFIG_SND_HDA_INTEL is not set
++# CONFIG_SND_HDSP is not set
++# CONFIG_SND_HDSPM is not set
+ # CONFIG_SND_ICE1712 is not set
+ # CONFIG_SND_ICE1724 is not set
+ # CONFIG_SND_INTEL8X0 is not set
+ # CONFIG_SND_INTEL8X0M is not set
++# CONFIG_SND_KORG1212 is not set
++# CONFIG_SND_MAESTRO3 is not set
++# CONFIG_SND_MIXART is not set
++# CONFIG_SND_NM256 is not set
++# CONFIG_SND_PCXHR is not set
++# CONFIG_SND_RME32 is not set
++# CONFIG_SND_RME96 is not set
++# CONFIG_SND_RME9652 is not set
+ # CONFIG_SND_SONICVIBES is not set
++# CONFIG_SND_TRIDENT is not set
+ # CONFIG_SND_VIA82XX is not set
+ # CONFIG_SND_VIA82XX_MODEM is not set
+ # CONFIG_SND_VX222 is not set
++CONFIG_SND_YMFPCI=m
++# CONFIG_SND_AC97_POWER_SAVE is not set
+
+ #
+ # Open Sound System
+ #
+ CONFIG_SOUND_PRIME=m
++# CONFIG_OSS_OBSOLETE_DRIVER is not set
+ # CONFIG_SOUND_BT878 is not set
+-CONFIG_SOUND_CMPCI=m
+-# CONFIG_SOUND_EMU10K1 is not set
+-# CONFIG_SOUND_FUSION is not set
+-# CONFIG_SOUND_CS4281 is not set
+-# CONFIG_SOUND_ES1370 is not set
+ # CONFIG_SOUND_ES1371 is not set
+-# CONFIG_SOUND_ESSSOLO1 is not set
+-# CONFIG_SOUND_MAESTRO is not set
+-# CONFIG_SOUND_MAESTRO3 is not set
+ # CONFIG_SOUND_ICH is not set
+-# CONFIG_SOUND_SONICVIBES is not set
+ # CONFIG_SOUND_TRIDENT is not set
+ # CONFIG_SOUND_MSNDCLAS is not set
+ # CONFIG_SOUND_MSNDPIN is not set
+ # CONFIG_SOUND_VIA82CXXX is not set
+-# CONFIG_SOUND_OSS is not set
+-# CONFIG_SOUND_ALI5455 is not set
+-# CONFIG_SOUND_FORTE is not set
+-# CONFIG_SOUND_RME96XX is not set
+-# CONFIG_SOUND_AD1980 is not set
+-CONFIG_SOUND_VOYAGERGX=m
+
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -678,30 +848,66 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ 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
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ CONFIG_MINIX_FS=y
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -724,12 +930,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+-# CONFIG_DEVFS_FS is not set
+ # CONFIG_TMPFS is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -758,6 +965,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
+@@ -818,8 +1026,14 @@ CONFIG_OPROFILE=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -836,12 +1050,10 @@ CONFIG_OPROFILE=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/se7300_defconfig b/arch/sh/configs/se7300_defconfig
+index 4b71cd6..8a21790 100644
+--- a/arch/sh/configs/se7300_defconfig
++++ b/arch/sh/configs/se7300_defconfig
+@@ -1,45 +1,55 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:43 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:43:22 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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_LOCALVERSION_AUTO=y
+ # CONFIG_SWAP is not set
+ # CONFIG_SYSVIPC 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_UTS_NS is not set
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ # CONFIG_KALLSYMS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
+ # CONFIG_FUTEX is not set
+ # 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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -47,68 +57,145 @@ CONFIG_CC_ALIGN_JUMPS=0
+ # CONFIG_MODULES is not set
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++CONFIG_DEFAULT_NOOP=y
++CONFIG_DEFAULT_IOSCHED="noop"
++
++#
+ # System type
+ #
++CONFIG_SOLUTION_ENGINE=y
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ CONFIG_SH_7300_SOLUTION_ENGINE=y
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH3=y
+-# CONFIG_CPU_SH4 is not set
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ CONFIG_CPU_SUBTYPE_SH7300=y
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ # CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram0"
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x04000000
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_DSP=y
+-# CONFIG_SH_ADC is not set
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00210000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
+-# CONFIG_SMP is not set
+-# CONFIG_SH_PCLK_CALC is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_SH_FPU_EMU is not set
++CONFIG_SH_DSP=y
++# CONFIG_SH_ADC is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
+ CONFIG_SH_PCLK_FREQ=33333333
+
+ #
+@@ -128,17 +215,34 @@ CONFIG_SH_PCLK_FREQ=33333333
+ CONFIG_HEARTBEAT=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
+ #
+-# CONFIG_PCI is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
+
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00210000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram0"
++
++#
++# Bus options
+ #
+-# CONFIG_PCCARD is not set
++# CONFIG_PCI is not set
+
+ #
+-# PC-card bridges
++# PCCARD (PCMCIA/CardBus) support
+ #
+
+ #
+@@ -153,10 +257,14 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
+ #
+-CONFIG_EMBEDDED_RAMDISK=y
+-CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
++# CONFIG_NET is not set
+
+ #
+ # Device Drivers
+@@ -167,7 +275,11 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.g
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -186,26 +298,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ #
+ # 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_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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
+-
+-#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ # CONFIG_IDE is not set
+@@ -213,7 +315,14 @@ CONFIG_IOSCHED_NOOP=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -223,6 +332,7 @@ CONFIG_IOSCHED_NOOP=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -233,13 +343,6 @@ CONFIG_IOSCHED_NOOP=y
+ #
+
+ #
+-# Networking support
+-#
+-# CONFIG_NET is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+ # ISDN subsystem
+ #
+
+@@ -252,6 +355,7 @@ CONFIG_IOSCHED_NOOP=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -266,18 +370,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # 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_LIBPS2 is not set
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+ # Input Device Drivers
+ #
+ # CONFIG_INPUT_KEYBOARD is not set
+@@ -287,6 +379,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_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_GAMEPORT is not set
++
++#
+ # Character devices
+ #
+ # CONFIG_VT is not set
+@@ -301,6 +403,7 @@ CONFIG_SERIO=y
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -328,7 +431,7 @@ CONFIG_WATCHDOG=y
+ #
+ CONFIG_SOFT_WATCHDOG=y
+ # CONFIG_SH_WDT is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -336,18 +439,38 @@ CONFIG_SOFT_WATCHDOG=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
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -357,6 +480,7 @@ CONFIG_SOFT_WATCHDOG=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -365,7 +489,9 @@ CONFIG_SOFT_WATCHDOG=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -377,9 +503,10 @@ CONFIG_SOFT_WATCHDOG=y
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -393,30 +520,64 @@ CONFIG_SOFT_WATCHDOG=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
+
+ #
+ # File systems
+ #
+ 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
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -436,14 +597,13 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+-CONFIG_DEVFS_FS=y
+-CONFIG_DEVFS_MOUNT=y
+-# CONFIG_DEVFS_DEBUG is not set
+ # CONFIG_TMPFS is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -481,8 +641,16 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
+ CONFIG_SH_STANDARD_BIOS=y
+ CONFIG_EARLY_PRINTK=y
+ CONFIG_KGDB=y
+@@ -520,12 +688,9 @@ CONFIG_KGDB_DEFBITS_8=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+diff --git a/arch/sh/configs/se73180_defconfig b/arch/sh/configs/se73180_defconfig
+index d217e44..1a76615 100644
+--- a/arch/sh/configs/se73180_defconfig
++++ b/arch/sh/configs/se73180_defconfig
+@@ -1,119 +1,208 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:44 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:44:45 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ # CONFIG_SYSVIPC is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
+-# CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_HOTPLUG is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ # CONFIG_KALLSYMS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
+ # CONFIG_FUTEX is not set
+ # 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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # 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
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_LSF 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_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++CONFIG_DEFAULT_NOOP=y
++CONFIG_DEFAULT_IOSCHED="noop"
++
++#
+ # System type
+ #
++CONFIG_SOLUTION_ENGINE=y
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ CONFIG_SH_73180_SOLUTION_ENGINE=y
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++CONFIG_CPU_SH4A=y
++CONFIG_CPU_SH4AL_DSP=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ # CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-CONFIG_CPU_SUBTYPE_SH73180=y
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++CONFIG_CPU_SUBTYPE_SH73180=y
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram"
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x02000000
+-# CONFIG_MEMORY_OVERRIDE is not set
+-# CONFIG_SH_FPU is not set
+-CONFIG_ZERO_PAGE_OFFSET=0x00010000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_32BIT=y
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_SH_FPU is not set
++# CONFIG_SH_FPU_EMU is not set
++CONFIG_SH_DSP=y
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-# CONFIG_SH_PCLK_CALC is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
+ CONFIG_SH_PCLK_FREQ=27000000
+
+ #
+@@ -133,17 +222,34 @@ CONFIG_SH_PCLK_FREQ=27000000
+ CONFIG_HEARTBEAT=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
+ #
+-# CONFIG_PCI is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
+
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# Boot options
+ #
+-# CONFIG_PCCARD is not set
++CONFIG_ZERO_PAGE_OFFSET=0x00010000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram"
+
+ #
+-# PC-card bridges
++# Bus options
++#
++# CONFIG_PCI is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
+ #
+
+ #
+@@ -158,10 +264,14 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
+ #
+-CONFIG_EMBEDDED_RAMDISK=y
+-CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
++# CONFIG_NET is not set
+
+ #
+ # Device Drivers
+@@ -172,7 +282,11 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.g
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -191,27 +305,17 @@ CONFIG_PREVENT_FIRMWARE_BUILD=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
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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
+-
+-#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ # CONFIG_IDE is not set
+@@ -219,7 +323,14 @@ CONFIG_IOSCHED_NOOP=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -229,6 +340,7 @@ CONFIG_IOSCHED_NOOP=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -239,13 +351,6 @@ CONFIG_IOSCHED_NOOP=y
+ #
+
+ #
+-# Networking support
+-#
+-# CONFIG_NET is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+ # ISDN subsystem
+ #
+
+@@ -260,20 +365,10 @@ CONFIG_IOSCHED_NOOP=y
+ # CONFIG_INPUT is not set
+
+ #
+-# Userland interfaces
+-#
+-
++# Hardware I/O ports
+ #
+-# 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_GAMEPORT is not set
+
+ #
+ # Character devices
+@@ -290,6 +385,7 @@ CONFIG_SOUND_GAMEPORT=y
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -312,7 +408,7 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+ # CONFIG_SH_WDT is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -320,18 +416,38 @@ CONFIG_WATCHDOG=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
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -341,6 +457,7 @@ CONFIG_WATCHDOG=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -349,6 +466,7 @@ CONFIG_WATCHDOG=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
+
+ #
+@@ -361,9 +479,10 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -377,30 +496,64 @@ CONFIG_WATCHDOG=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
+
+ #
+ # File systems
+ #
+ 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
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -420,12 +573,10 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ # CONFIG_SYSFS is not set
+-CONFIG_DEVFS_FS=y
+-CONFIG_DEVFS_MOUNT=y
+-# CONFIG_DEVFS_DEBUG is not set
+ CONFIG_TMPFS=y
+-# CONFIG_TMPFS_XATTR is not set
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+@@ -466,8 +617,13 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
+ CONFIG_SH_STANDARD_BIOS=y
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_EARLY_PRINTK is not set
+@@ -477,7 +633,6 @@ CONFIG_SH_STANDARD_BIOS=y
+ # Security options
+ #
+ # CONFIG_KEYS is not set
+-# CONFIG_SECURITY is not set
+
+ #
+ # Cryptographic options
+@@ -485,12 +640,9 @@ CONFIG_SH_STANDARD_BIOS=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+diff --git a/arch/sh/configs/se7343_defconfig b/arch/sh/configs/se7343_defconfig
+new file mode 100644
+index 0000000..84c0075
+--- /dev/null
++++ b/arch/sh/configs/se7343_defconfig
+@@ -0,0 +1,1018 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:46:17 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++# CONFIG_FUTEX is not set
++# CONFIG_EPOLL is not set
++# CONFIG_SHMEM is not set
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_TINY_SHMEM=y
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_AS is not set
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++# CONFIG_DEFAULT_AS is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++
++#
++# System type
++#
++CONFIG_SOLUTION_ENGINE=y
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++CONFIG_SH_7343_SOLUTION_ENGINE=y
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++# CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
++# CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH4=y
++CONFIG_CPU_SH4A=y
++CONFIG_CPU_SH4AL_DSP=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++# CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++CONFIG_CPU_SUBTYPE_SH7343=y
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x0c000000
++CONFIG_MEMORY_SIZE=0x01000000
++CONFIG_32BIT=y
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_SH_FPU is not set
++# CONFIG_SH_FPU_EMU is not set
++CONFIG_SH_DSP=y
++# CONFIG_SH_STORE_QUEUES is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=27000000
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++# CONFIG_SH_DMA is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++CONFIG_HEARTBEAT=y
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
++#
++# CONFIG_PCI is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 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=y
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_CONCAT=y
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++CONFIG_MTD_RAM=y
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# 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_INITRD is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA 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
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_STNIC is not set
++CONFIG_SMC91X=y
++
++#
++# 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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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 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
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_UNIX98_PTYS is not set
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_GEN_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=y
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_PCA_ISA is not set
++
++#
++# Miscellaneous 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_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
++# CONFIG_I2C_DEBUG_CHIP is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L1=y
++CONFIG_VIDEO_V4L1_COMPAT=y
++CONFIG_VIDEO_V4L2=y
++
++#
++# Video Capture Adapters
++#
++
++#
++# Video Capture Adapters
++#
++# CONFIG_VIDEO_ADV_DEBUG is not set
++CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
++# CONFIG_VIDEO_VIVI is not set
++# CONFIG_VIDEO_CPIA is not set
++# CONFIG_VIDEO_SAA5246A is not set
++# CONFIG_VIDEO_SAA5249 is not set
++# CONFIG_TUNER_3036 is not set
++
++#
++# Radio Adapters
++#
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++CONFIG_FB=y
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++# CONFIG_FB_EPSON1355 is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++
++#
++# Logo configuration
++#
++# CONFIG_LOGO is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++
++#
++# Advanced Linux Sound Architecture
++#
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_SEQUENCER=y
++# CONFIG_SND_SEQ_DUMMY is not set
++CONFIG_SND_OSSEMUL=y
++# CONFIG_SND_MIXER_OSS is not set
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_SEQUENCER_OSS is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++
++#
++# Generic devices
++#
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_VIRMIDI is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++
++#
++# Open Sound System
++#
++# CONFIG_SOUND_PRIME is not set
++
++#
++# USB support
++#
++# CONFIG_USB_ARCH_HAS_HCD is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_INOTIFY 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
++# 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_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_DIRECTIO is not set
++CONFIG_NFSD=y
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=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
++# CONFIG_9P_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_SH_STANDARD_BIOS is not set
++# CONFIG_EARLY_SCIF_CONSOLE 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
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig
+index e4a1460..06ebd6e 100644
+--- a/arch/sh/configs/se7705_defconfig
++++ b/arch/sh/configs/se7705_defconfig
+@@ -1,125 +1,212 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:45 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:03:04 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-CONFIG_CLEAN_COMPILE=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+ # General setup
+ #
+ CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
+ # CONFIG_SWAP is not set
+ # CONFIG_SYSVIPC is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # 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_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ # CONFIG_KALLSYMS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # 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
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++# CONFIG_IOSCHED_DEADLINE is not set
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
++CONFIG_SOLUTION_ENGINE=y
+ CONFIG_SH_SOLUTION_ENGINE=y
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH3=y
+-# CONFIG_CPU_SH4 is not set
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ CONFIG_CPU_SUBTYPE_SH7705=y
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ # CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+-CONFIG_SH7705_CACHE_32KB=y
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-# CONFIG_CMDLINE_BOOL is not set
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x02000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++CONFIG_SH7705_CACHE_32KB=y
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
+ # CONFIG_CF_ENABLER is not set
+-CONFIG_SH_RTC=y
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_SH_FPU_EMU is not set
+ # CONFIG_SH_DSP is not set
+ # CONFIG_SH_ADC is not set
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_PREEMPT=y
+-# CONFIG_UBC_WAKEUP is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_PINT_IRQ=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
+ CONFIG_SH_PCLK_FREQ=33333333
+
+ #
+@@ -139,17 +226,34 @@ CONFIG_SH_PCLK_FREQ=33333333
+ CONFIG_HEARTBEAT=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
+ #
+-# CONFIG_PCI is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
+
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
+ #
+-# CONFIG_PCCARD is not set
++# CONFIG_PCI is not set
+
+ #
+-# PC-card bridges
++# PCCARD (PCMCIA/CardBus) support
+ #
+
+ #
+@@ -164,9 +268,95 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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
++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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
+ #
+-# CONFIG_EMBEDDED_RAMDISK is not set
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
+
+ #
+ # Device Drivers
+@@ -177,15 +367,20 @@ CONFIG_BINFMT_ELF=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+ #
+ CONFIG_MTD=y
+ # CONFIG_MTD_DEBUG is not set
+-CONFIG_MTD_PARTITIONS=y
+ # CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
+ # CONFIG_MTD_REDBOOT_PARTS is not set
+ # CONFIG_MTD_CMDLINE_PARTS is not set
+
+@@ -197,6 +392,8 @@ CONFIG_MTD_BLOCK=y
+ # CONFIG_FTL is not set
+ # CONFIG_NFTL is not set
+ # CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
+
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -217,22 +414,19 @@ CONFIG_MTD_CFI_I2=y
+ # CONFIG_MTD_CFI_I8 is not set
+ # CONFIG_MTD_CFI_INTELEXT is not set
+ CONFIG_MTD_CFI_AMDSTD=y
+-CONFIG_MTD_CFI_AMDSTD_RETRY=0
+ # CONFIG_MTD_CFI_STAA is not set
+ CONFIG_MTD_CFI_UTIL=y
+ # CONFIG_MTD_RAM is not set
+ # CONFIG_MTD_ROM is not set
+ # CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+ #
+ # Mapping drivers for chip access
+ #
+ # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+ # CONFIG_MTD_PHYSMAP is not set
+-CONFIG_MTD_SOLUTIONENGINE=y
+-CONFIG_MTD_SUPERH_RESERVE=0x300000
+-# CONFIG_MTD_MPC1211 is not set
+-# CONFIG_MTD_RTS7751R2D is not set
++# CONFIG_MTD_PLATRAM is not set
+
+ #
+ # Self-contained MTD device drivers
+@@ -240,7 +434,6 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_PHRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+ # CONFIG_MTD_BLOCK2MTD is not set
+
+ #
+@@ -256,6 +449,11 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
+ # CONFIG_MTD_NAND is not set
+
+ #
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
+ # Parallel port support
+ #
+ # CONFIG_PARPORT is not set
+@@ -267,25 +465,15 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
+ #
+ # 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=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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 is not set
+-# CONFIG_IOSCHED_CFQ is not set
+ # CONFIG_ATA_OVER_ETH is not set
+
+ #
+@@ -296,7 +484,14 @@ CONFIG_IOSCHED_AS=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -306,6 +501,7 @@ CONFIG_IOSCHED_AS=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -316,70 +512,8 @@ CONFIG_IOSCHED_AS=y
+ #
+
+ #
+-# 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=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
++# Network device support
+ #
+-# 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
+@@ -387,6 +521,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_TUN is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -422,10 +561,14 @@ CONFIG_PPP_ASYNC=y
+ # CONFIG_PPP_SYNC_TTY is not set
+ CONFIG_PPP_DEFLATE=y
+ # CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_MPPE is not set
+ # CONFIG_PPPOE is not set
+ # CONFIG_SLIP is not set
++CONFIG_SLHC=y
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -441,6 +584,7 @@ CONFIG_PPP_DEFLATE=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -452,18 +596,6 @@ CONFIG_INPUT=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_LIBPS2 is not set
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+ # Input Device Drivers
+ #
+ # CONFIG_INPUT_KEYBOARD is not set
+@@ -473,6 +605,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_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_GAMEPORT is not set
++
++#
+ # Character devices
+ #
+ # CONFIG_VT is not set
+@@ -487,6 +629,7 @@ CONFIG_SERIO=y
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -502,7 +645,7 @@ CONFIG_UNIX98_PTYS=y
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -510,18 +653,38 @@ CONFIG_UNIX98_PTYS=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
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -531,6 +694,7 @@ CONFIG_UNIX98_PTYS=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -540,6 +704,7 @@ CONFIG_UNIX98_PTYS=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
+
+ #
+@@ -552,9 +717,10 @@ CONFIG_UNIX98_PTYS=y
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -568,30 +734,64 @@ CONFIG_UNIX98_PTYS=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
+
+ #
+ # File systems
+ #
+ 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
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -611,9 +811,8 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ # CONFIG_SYSFS is not set
+-# 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
+@@ -632,8 +831,9 @@ CONFIG_RAMFS=y
+ # CONFIG_JFFS_FS is not set
+ CONFIG_JFFS2_FS=y
+ CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
+ # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+ CONFIG_JFFS2_ZLIB=y
+ CONFIG_JFFS2_RTIME=y
+@@ -655,6 +855,7 @@ CONFIG_NFS_FS=y
+ # 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
+@@ -663,6 +864,7 @@ CONFIG_SUNRPC=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
+@@ -683,9 +885,13 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-CONFIG_DEBUG_PREEMPT=y
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_KGDB is not set
+
+@@ -693,7 +899,6 @@ CONFIG_DEBUG_PREEMPT=y
+ # Security options
+ #
+ # CONFIG_KEYS is not set
+-# CONFIG_SECURITY is not set
+
+ #
+ # Cryptographic options
+@@ -701,14 +906,12 @@ CONFIG_DEBUG_PREEMPT=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ CONFIG_CRC_CCITT=y
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
+index 6dc3158..5d357d6 100644
+--- a/arch/sh/configs/se7750_defconfig
++++ b/arch/sh/configs/se7750_defconfig
+@@ -1,131 +1,218 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:46 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 11:49:01 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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_LOCALVERSION_AUTO=y
+ # CONFIG_SWAP is not set
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_HOTPLUG is not set
+-CONFIG_KOBJECT_UEVENT=y
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # 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
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
++CONFIG_SOLUTION_ENGINE=y
+ CONFIG_SH_SOLUTION_ENGINE=y
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ CONFIG_CPU_SUBTYPE_SH7750=y
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ # CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="console=ttySC1,38400 root=/dev/nfs ip=bootp"
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x02000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
+ CONFIG_CF_ENABLER=y
+ # CONFIG_CF_AREA5 is not set
+ CONFIG_CF_AREA6=y
+ CONFIG_CF_BASE_ADDR=0xb8000000
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
++
++#
++# Processor features
++#
+ CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=49876504
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=50000000
+
+ #
+ # CPU Frequency scaling
+@@ -144,17 +231,34 @@ CONFIG_SH_PCLK_FREQ=49876504
+ CONFIG_HEARTBEAT=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
+ #
+-# CONFIG_PCI is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
+
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC1,38400 root=/dev/nfs ip=bootp"
++
++#
++# Bus options
+ #
+-# CONFIG_PCCARD is not set
++# CONFIG_PCI is not set
+
+ #
+-# PC-card bridges
++# PCCARD (PCMCIA/CardBus) support
+ #
+
+ #
+@@ -169,6 +273,98 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
+ # Device Drivers
+ #
+
+@@ -177,15 +373,20 @@ CONFIG_BINFMT_ELF=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+ #
+ CONFIG_MTD=y
+ # CONFIG_MTD_DEBUG is not set
+-CONFIG_MTD_PARTITIONS=y
+ # CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
+ # CONFIG_MTD_REDBOOT_PARTS is not set
+ # CONFIG_MTD_CMDLINE_PARTS is not set
+
+@@ -197,6 +398,8 @@ CONFIG_MTD_BLOCK=y
+ # CONFIG_FTL is not set
+ # CONFIG_NFTL is not set
+ # CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
+
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -217,22 +420,19 @@ CONFIG_MTD_CFI_I2=y
+ # CONFIG_MTD_CFI_I8 is not set
+ # CONFIG_MTD_CFI_INTELEXT is not set
+ CONFIG_MTD_CFI_AMDSTD=y
+-CONFIG_MTD_CFI_AMDSTD_RETRY=0
+ # CONFIG_MTD_CFI_STAA is not set
+ CONFIG_MTD_CFI_UTIL=y
+ # CONFIG_MTD_RAM is not set
+ CONFIG_MTD_ROM=y
+ # CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+ #
+ # Mapping drivers for chip access
+ #
+ # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+ # CONFIG_MTD_PHYSMAP is not set
+-CONFIG_MTD_SOLUTIONENGINE=y
+-CONFIG_MTD_SUPERH_RESERVE=0x00010000
+-# CONFIG_MTD_MPC1211 is not set
+-# CONFIG_MTD_RTS7751R2D is not set
++# CONFIG_MTD_PLATRAM is not set
+
+ #
+ # Self-contained MTD device drivers
+@@ -240,7 +440,6 @@ CONFIG_MTD_SUPERH_RESERVE=0x00010000
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_PHRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+ # CONFIG_MTD_BLOCK2MTD is not set
+
+ #
+@@ -256,6 +455,11 @@ CONFIG_MTD_SUPERH_RESERVE=0x00010000
+ # CONFIG_MTD_NAND is not set
+
+ #
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
+ # Parallel port support
+ #
+ # CONFIG_PARPORT is not set
+@@ -267,23 +471,12 @@ CONFIG_MTD_SUPERH_RESERVE=0x00010000
+ #
+ # 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_BLK_DEV_INITRD 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
+
+ #
+@@ -294,7 +487,14 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -304,6 +504,7 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -314,71 +515,8 @@ CONFIG_IOSCHED_CFQ=y
+ #
+
+ #
+-# 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=y
+-# CONFIG_IP_ADVANCED_ROUTER is not set
+-CONFIG_IP_PNP=y
+-# CONFIG_IP_PNP_DHCP is not set
+-CONFIG_IP_PNP_BOOTP=y
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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)
++# Network device support
+ #
+-# 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
+@@ -386,6 +524,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_TUN is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -418,6 +561,8 @@ CONFIG_STNIC=y
+ # CONFIG_SLIP is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -435,20 +580,10 @@ CONFIG_STNIC=y
+ # CONFIG_INPUT is not set
+
+ #
+-# Userland interfaces
++# Hardware I/O ports
+ #
+-
+-#
+-# 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_GAMEPORT is not set
+
+ #
+ # Character devices
+@@ -462,12 +597,14 @@ CONFIG_SOUND_GAMEPORT=y
+ CONFIG_SERIAL_8250=y
+ # CONFIG_SERIAL_8250_CONSOLE is not set
+ CONFIG_SERIAL_8250_NR_UARTS=2
++CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+ # CONFIG_SERIAL_8250_EXTENDED is not set
+
+ #
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -491,7 +628,8 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+ CONFIG_SH_WDT=y
+-# CONFIG_RTC is not set
++# CONFIG_SH_WDT_MMAP is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -499,18 +637,38 @@ CONFIG_SH_WDT=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
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -520,6 +678,7 @@ CONFIG_SH_WDT=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -529,7 +688,9 @@ CONFIG_SH_WDT=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -541,9 +702,10 @@ CONFIG_SH_WDT=y
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -557,29 +719,63 @@ CONFIG_SH_WDT=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
+
+ #
+ # 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
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -599,14 +795,14 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=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
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -621,8 +817,9 @@ CONFIG_RAMFS=y
+ # CONFIG_JFFS_FS is not set
+ CONFIG_JFFS2_FS=y
+ CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
+ # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+ CONFIG_JFFS2_ZLIB=y
+ CONFIG_JFFS2_RTIME=y
+@@ -644,6 +841,7 @@ CONFIG_NFS_FS=y
+ # 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
+@@ -652,6 +850,7 @@ CONFIG_SUNRPC=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
+@@ -667,6 +866,7 @@ CONFIG_PARTITION_ADVANCED=y
+ # CONFIG_SGI_PARTITION is not set
+ # CONFIG_ULTRIX_PARTITION is not set
+ # CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
+ # CONFIG_EFI_PARTITION is not set
+
+ #
+@@ -682,8 +882,14 @@ CONFIG_PARTITION_ADVANCED=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -700,14 +906,12 @@ CONFIG_PARTITION_ADVANCED=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/se7751_defconfig b/arch/sh/configs/se7751_defconfig
+index 1ce0289..a909559 100644
+--- a/arch/sh/configs/se7751_defconfig
++++ b/arch/sh/configs/se7751_defconfig
+@@ -1,126 +1,213 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:48 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:10:12 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # 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_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # 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
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
++CONFIG_SOLUTION_ENGINE=y
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ CONFIG_SH_7751_SOLUTION_ENGINE=y
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ CONFIG_CPU_SUBTYPE_SH7751=y
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="console=ttySC1,38400"
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x04000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00010000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=60013568
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=60000000
+
+ #
+ # CPU Frequency scaling
+@@ -139,28 +226,39 @@ CONFIG_SH_PCLK_FREQ=60013568
+ CONFIG_HEARTBEAT=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
+ #
+-CONFIG_PCI=y
+-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+-CONFIG_PCI_AUTO=y
+-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-# CONFIG_PCI_NAMES is not set
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
+
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00010000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC1,38400"
++
+ #
+-# CONFIG_PCCARD is not set
++# Bus options
++#
++# CONFIG_PCI is not set
+
+ #
+-# PC-card bridges
++# PCCARD (PCMCIA/CardBus) support
+ #
+
+ #
+ # PCI Hotplug Support
+ #
+-# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -170,9 +268,115 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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=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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++CONFIG_NETFILTER_DEBUG=y
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_IP_NF_CONNTRACK is not set
++CONFIG_IP_NF_QUEUE=y
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
+ #
+-# CONFIG_EMBEDDED_RAMDISK is not set
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
+
+ #
+ # Device Drivers
+@@ -183,15 +387,20 @@ CONFIG_BINFMT_ELF=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+ #
+ CONFIG_MTD=y
+ # CONFIG_MTD_DEBUG is not set
+-CONFIG_MTD_PARTITIONS=y
+ # CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
+ # CONFIG_MTD_REDBOOT_PARTS is not set
+ # CONFIG_MTD_CMDLINE_PARTS is not set
+
+@@ -203,6 +412,8 @@ CONFIG_MTD_BLOCK=y
+ # CONFIG_FTL is not set
+ # CONFIG_NFTL is not set
+ # CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
+
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -223,30 +434,26 @@ CONFIG_MTD_CFI_I2=y
+ # CONFIG_MTD_CFI_I8 is not set
+ # CONFIG_MTD_CFI_INTELEXT is not set
+ CONFIG_MTD_CFI_AMDSTD=y
+-CONFIG_MTD_CFI_AMDSTD_RETRY=0
+ # CONFIG_MTD_CFI_STAA is not set
+ CONFIG_MTD_CFI_UTIL=y
+ CONFIG_MTD_RAM=y
+ # CONFIG_MTD_ROM is not set
+ # CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+ #
+ # Mapping drivers for chip access
+ #
+ # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+ # CONFIG_MTD_PHYSMAP is not set
+-# CONFIG_MTD_SOLUTIONENGINE is not set
+-# CONFIG_MTD_MPC1211 is not set
+-# CONFIG_MTD_RTS7751R2D is not set
++# CONFIG_MTD_PLATRAM is not set
+
+ #
+ # Self-contained MTD device drivers
+ #
+-# CONFIG_MTD_PMC551 is not set
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_PHRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+-# CONFIG_MTD_BLKMTD is not set
+ # CONFIG_MTD_BLOCK2MTD is not set
+
+ #
+@@ -262,6 +469,11 @@ CONFIG_MTD_RAM=y
+ # CONFIG_MTD_NAND is not set
+
+ #
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
+ # Parallel port support
+ #
+ # CONFIG_PARPORT is not set
+@@ -273,30 +485,15 @@ CONFIG_MTD_RAM=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
+-# 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=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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
+
+ #
+@@ -307,7 +504,14 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -317,109 +521,29 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # 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_NETLINK_DEV=y
+-CONFIG_UNIX=y
+-# CONFIG_NET_KEY is not set
+-CONFIG_INET=y
+-CONFIG_IP_MULTICAST=y
+-# CONFIG_IP_ADVANCED_ROUTER is not set
+-CONFIG_IP_PNP=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=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=y
+-
+-#
+-# IP: Netfilter Configuration
+-#
+-# CONFIG_IP_NF_CONNTRACK is not set
+-# CONFIG_IP_NF_CONNTRACK_MARK is not set
+-CONFIG_IP_NF_QUEUE=y
+-# 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
++# Network device support
+ #
+-# 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
+-# CONFIG_ETHERTAP is not set
+
+ #
+-# ARCnet devices
++# PHY device support
+ #
+-# CONFIG_ARCNET is not set
++# CONFIG_PHYLIB is not set
+
+ #
+ # Ethernet (10 or 100Mbit)
+@@ -427,60 +551,19 @@ CONFIG_NETDEVICES=y
+ CONFIG_NET_ETHERNET=y
+ CONFIG_MII=y
+ # CONFIG_STNIC is not set
+-# CONFIG_HAPPYMEAL is not set
+-# CONFIG_SUNGEM is not set
+-# CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_SMC91X 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=y
+-# CONFIG_AMD8111_ETH is not set
+-# CONFIG_ADAPTEC_STARFIRE is not set
+-# CONFIG_B44 is not set
+-# CONFIG_FORCEDETH is not set
+-# CONFIG_DGRS is not set
+-# CONFIG_EEPRO100 is not set
+-# CONFIG_E100 is not set
+-# CONFIG_FEALNX is not set
+-# CONFIG_NATSEMI is not set
+-# CONFIG_NE2K_PCI is not set
+-# CONFIG_8139CP is not set
+-# CONFIG_8139TOO is not set
+-# CONFIG_SIS900 is not set
+-# CONFIG_EPIC100 is not set
+-# CONFIG_SUNDANCE is not set
+-# CONFIG_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_SK98LIN is not set
+-# CONFIG_VIA_VELOCITY 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)
+@@ -491,12 +574,12 @@ CONFIG_PCNET32=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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -514,20 +597,10 @@ CONFIG_PCNET32=y
+ # CONFIG_INPUT is not set
+
+ #
+-# Userland interfaces
+-#
+-
++# Hardware I/O ports
+ #
+-# 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_GAMEPORT is not set
+
+ #
+ # Character devices
+@@ -564,33 +637,46 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+ # CONFIG_SH_WDT is not set
+-
+-#
+-# PCI-based Watchdog Cards
+-#
+-# CONFIG_PCIPCWATCHDOG is not set
+-# CONFIG_WDTPCI is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # 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
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -600,6 +686,7 @@ CONFIG_WATCHDOG=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -609,7 +696,9 @@ CONFIG_WATCHDOG=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -619,12 +708,12 @@ CONFIG_WATCHDOG=y
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+-CONFIG_USB_ARCH_HAS_HCD=y
+-CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_HCD is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -638,30 +727,65 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
+
+ #
+ # File systems
+ #
+ 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
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -681,14 +805,14 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=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
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -703,8 +827,9 @@ CONFIG_RAMFS=y
+ # CONFIG_JFFS_FS is not set
+ CONFIG_JFFS2_FS=y
+ CONFIG_JFFS2_FS_DEBUG=0
+-# CONFIG_JFFS2_FS_NAND is not set
+-# CONFIG_JFFS2_FS_NOR_ECC is not set
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
+ # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+ CONFIG_JFFS2_ZLIB=y
+ CONFIG_JFFS2_RTIME=y
+@@ -726,6 +851,7 @@ CONFIG_JFFS2_RTIME=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
+@@ -746,8 +872,14 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -764,14 +896,12 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig
+index 078f78c..9fd5ea7 100644
+--- a/arch/sh/configs/sh03_defconfig
++++ b/arch/sh/configs/sh03_defconfig
+@@ -1,51 +1,63 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:49 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:13:26 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-# CONFIG_CLEAN_COMPILE is not set
+-CONFIG_BROKEN=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+ # General setup
+ #
+ CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-CONFIG_HOTPLUG=y
+-CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+-# CONFIG_EMBEDDED is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -53,81 +65,154 @@ CONFIG_CC_ALIGN_JUMPS=0
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+-CONFIG_OBSOLETE_MODPARM=y
+ CONFIG_MODVERSIONS=y
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ CONFIG_SH_SH03=y
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ CONFIG_CPU_SUBTYPE_SH7751=y
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x08000000
+ CONFIG_MEMORY_SIZE=0x08000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
+ CONFIG_CF_ENABLER=y
+ CONFIG_CF_AREA5=y
+ # CONFIG_CF_AREA6 is not set
+ CONFIG_CF_BASE_ADDR=0xb4000000
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00004000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
++
++#
++# Processor features
++#
+ CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_PREEMPT=y
+-# CONFIG_UBC_WAKEUP is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=49876504
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=60000000
+
+ #
+ # CPU Frequency scaling
+@@ -146,14 +231,36 @@ CONFIG_SH_PCLK_FREQ=49876504
+ CONFIG_HEARTBEAT=y
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00004000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
++
++#
++# Bus options
+ #
+ CONFIG_PCI=y
+ CONFIG_SH_PCIDMA_NONCOHERENT=y
+ CONFIG_PCI_AUTO=y
+ CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+-CONFIG_PCI_LEGACY_PROC=y
+-CONFIG_PCI_NAMES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+@@ -161,10 +268,6 @@ CONFIG_PCI_NAMES=y
+ # CONFIG_PCCARD is not set
+
+ #
+-# PC-card bridges
+-#
+-
+-#
+ # PCI Hotplug Support
+ #
+ CONFIG_HOTPLUG_PCI=m
+@@ -180,9 +283,96 @@ CONFIG_BINFMT_ELF=y
+ CONFIG_BINFMT_MISC=y
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
+ #
+-# CONFIG_EMBEDDED_RAMDISK is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++CONFIG_NET_KEY=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# 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
++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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
+
+ #
+ # Device Drivers
+@@ -194,6 +384,12 @@ CONFIG_BINFMT_MISC=y
+ # CONFIG_STANDALONE is not set
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ # CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -212,7 +408,6 @@ CONFIG_BINFMT_MISC=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
+@@ -225,18 +420,9 @@ CONFIG_BLK_DEV_NBD=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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
+
+ #
+@@ -263,7 +449,6 @@ CONFIG_BLK_DEV_IDEFLOPPY=m
+ #
+ CONFIG_IDE_GENERIC=y
+ # CONFIG_BLK_DEV_IDEPCI is not set
+-CONFIG_IDE_SH=y
+ # CONFIG_IDE_ARM is not set
+ # CONFIG_BLK_DEV_IDEDMA is not set
+ # CONFIG_IDEDMA_AUTO is not set
+@@ -272,7 +457,9 @@ CONFIG_IDE_SH=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=m
++# CONFIG_SCSI_NETLINK is not set
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -284,6 +471,7 @@ CONFIG_BLK_DEV_SD=m
+ CONFIG_BLK_DEV_SR=m
+ CONFIG_BLK_DEV_SR_VENDOR=y
+ CONFIG_CHR_DEV_SG=m
++# CONFIG_CHR_DEV_SCH is not set
+
+ #
+ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+@@ -293,15 +481,18 @@ CONFIG_CHR_DEV_SG=m
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ # CONFIG_SCSI_FC_ATTRS is not set
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+ #
++# CONFIG_ISCSI_TCP is not set
+ # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+ # CONFIG_SCSI_3W_9XXX is not set
+ # CONFIG_SCSI_ACARD is not set
+@@ -309,40 +500,35 @@ CONFIG_CHR_DEV_SG=m
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
+ # CONFIG_SCSI_DPT_I2O is not set
+-# CONFIG_SCSI_ADVANSYS is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_BUSLOGIC is not set
+-# CONFIG_SCSI_CPQFCTS is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP 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
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 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 is not set
+-CONFIG_SCSI_QLA2XXX=m
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+ # CONFIG_SCSI_NSP32 is not set
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ # CONFIG_MD is not set
+@@ -351,6 +537,9 @@ CONFIG_SCSI_QLA2XXX=m
+ # Fusion MPT device support
+ #
+ # CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -363,73 +552,8 @@ CONFIG_SCSI_QLA2XXX=m
+ # CONFIG_I2O is not set
+
+ #
+-# Networking support
++# Network device 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=y
+-CONFIG_INET=y
+-CONFIG_IP_MULTICAST=y
+-# CONFIG_IP_ADVANCED_ROUTER is not set
+-CONFIG_IP_PNP=y
+-CONFIG_IP_PNP_DHCP=y
+-CONFIG_IP_PNP_BOOTP=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=y
+-# CONFIG_IP_TCPDIAG_IPV6 is not set
+-# CONFIG_IPV6 is not set
+-# CONFIG_NETFILTER is not set
+-CONFIG_XFRM=y
+-# CONFIG_XFRM_USER 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
+@@ -442,6 +566,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_ARCNET is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -449,6 +578,7 @@ CONFIG_MII=y
+ # CONFIG_STNIC is not set
+ # CONFIG_HAPPYMEAL is not set
+ # CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
+ # CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_SMC91X is not set
+
+@@ -487,15 +617,22 @@ CONFIG_8139CP=y
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+ # CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -518,6 +655,8 @@ CONFIG_8139CP=y
+ # CONFIG_NET_FC is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -533,6 +672,7 @@ CONFIG_8139CP=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -547,14 +687,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # 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
+@@ -564,27 +696,38 @@ CONFIG_SOUND_GAMEPORT=y
+ # CONFIG_INPUT_MISC is not set
+
+ #
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
+ # Character devices
+ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=m
++CONFIG_SERIAL_8250_PCI=m
+ CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ # CONFIG_SERIAL_8250_EXTENDED is not set
+
+ #
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=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
+@@ -605,14 +748,14 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_SOFT_WATCHDOG is not set
+ CONFIG_SH_WDT=m
++# CONFIG_SH_WDT_MMAP is not set
+
+ #
+ # PCI-based Watchdog Cards
+ #
+ # CONFIG_PCIPCWATCHDOG is not set
+ # CONFIG_WDTPCI is not set
+-# CONFIG_RTC is not set
+-CONFIG_SH03_RTC=y
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -625,14 +768,35 @@ CONFIG_SH03_RTC=y
+ # CONFIG_RAW_DRIVER is not set
+
+ #
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -642,6 +806,7 @@ CONFIG_SH03_RTC=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -651,13 +816,14 @@ CONFIG_SH03_RTC=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # 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
+@@ -667,12 +833,13 @@ CONFIG_DUMMY_CONSOLE=y
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -686,17 +853,53 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA 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=y
+@@ -707,17 +910,17 @@ CONFIG_FS_MBCACHE=y
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+ CONFIG_FS_POSIX_ACL=y
+-
+-#
+-# XFS support
+-#
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ CONFIG_AUTOFS_FS=y
+ CONFIG_AUTOFS4_FS=y
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -744,14 +947,14 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=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
++# CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -775,16 +978,19 @@ 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=y
+ CONFIG_ROOT_NFS=y
+ 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
+@@ -794,6 +1000,7 @@ CONFIG_RPCSEC_GSS_KRB5=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
+@@ -813,6 +1020,7 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_SGI_PARTITION is not set
+ # CONFIG_ULTRIX_PARTITION is not set
+ # CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
+ # CONFIG_EFI_PARTITION is not set
+
+ #
+@@ -868,9 +1076,14 @@ CONFIG_OPROFILE=m
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-CONFIG_DEBUG_PREEMPT=y
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
+ CONFIG_SH_STANDARD_BIOS=y
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_EARLY_PRINTK is not set
+@@ -886,6 +1099,10 @@ CONFIG_SH_STANDARD_BIOS=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ # CONFIG_CRYPTO_NULL is not set
+ # CONFIG_CRYPTO_MD4 is not set
+@@ -894,6 +1111,9 @@ CONFIG_CRYPTO_SHA1=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_ECB=m
++CONFIG_CRYPTO_CBC=m
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_BLOWFISH is not set
+ # CONFIG_CRYPTO_TWOFISH is not set
+@@ -918,7 +1138,9 @@ CONFIG_CRYPTO_DEFLATE=y
+ # Library routines
+ #
+ CONFIG_CRC_CCITT=y
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/sh7710voipgw_defconfig b/arch/sh/configs/sh7710voipgw_defconfig
+new file mode 100644
+index 0000000..9380c32
+--- /dev/null
++++ b/arch/sh/configs/sh7710voipgw_defconfig
+@@ -0,0 +1,955 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:48:56 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++# CONFIG_FUTEX is not set
++# CONFIG_EPOLL is not set
++# CONFIG_SHMEM is not set
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_TINY_SHMEM=y
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_AS is not set
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++# CONFIG_DEFAULT_AS is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++
++#
++# System type
++#
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++# CONFIG_SH_HS7751RVOIP is not set
++CONFIG_SH_7710VOIPGW=y
++# CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH3=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++CONFIG_CPU_SUBTYPE_SH7710=y
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++# CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x0c000000
++CONFIG_MEMORY_SIZE=0x00800000
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_SH_FPU_EMU is not set
++CONFIG_SH_DSP=y
++# CONFIG_SH_ADC is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=32768000
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++# CONFIG_SH_DMA is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
++#
++# CONFIG_PCI is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_IP_NF_CONNTRACK=y
++# CONFIG_IP_NF_CT_ACCT is not set
++# CONFIG_IP_NF_CONNTRACK_MARK is not set
++# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
++# CONFIG_IP_NF_CT_PROTO_SCTP is not set
++CONFIG_IP_NF_FTP=m
++# CONFIG_IP_NF_IRC is not set
++# CONFIG_IP_NF_NETBIOS_NS is not set
++# CONFIG_IP_NF_TFTP is not set
++# CONFIG_IP_NF_AMANDA is not set
++CONFIG_IP_NF_PPTP=m
++# CONFIG_IP_NF_H323 is not set
++# CONFIG_IP_NF_SIP is not set
++# CONFIG_IP_NF_QUEUE is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_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
++
++#
++# Queueing/Scheduling
++#
++CONFIG_NET_SCH_CBQ=y
++# CONFIG_NET_SCH_HTB is not set
++# CONFIG_NET_SCH_HFSC is not set
++# CONFIG_NET_SCH_PRIO is not set
++# CONFIG_NET_SCH_RED is not set
++# CONFIG_NET_SCH_SFQ is not set
++# CONFIG_NET_SCH_TEQL is not set
++# CONFIG_NET_SCH_TBF is not set
++# CONFIG_NET_SCH_GRED is not set
++# CONFIG_NET_SCH_DSMARK is not set
++# CONFIG_NET_SCH_NETEM is not set
++CONFIG_NET_SCH_INGRESS=y
++
++#
++# Classification
++#
++CONFIG_NET_CLS=y
++CONFIG_NET_CLS_BASIC=y
++CONFIG_NET_CLS_TCINDEX=y
++CONFIG_NET_CLS_ROUTE4=y
++CONFIG_NET_CLS_ROUTE=y
++# CONFIG_NET_CLS_FW is not set
++CONFIG_NET_CLS_U32=y
++# CONFIG_CLS_U32_PERF is not set
++# CONFIG_CLS_U32_MARK is not set
++# CONFIG_NET_CLS_RSVP is not set
++# CONFIG_NET_CLS_RSVP6 is not set
++# CONFIG_NET_EMATCH is not set
++# CONFIG_NET_CLS_ACT is not set
++CONFIG_NET_CLS_POLICE=y
++# CONFIG_NET_CLS_IND is not set
++CONFIG_NET_ESTIMATOR=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++CONFIG_MTD_RAM=y
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# 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_INITRD is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA 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
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_MII is not set
++# CONFIG_STNIC is not set
++# CONFIG_SMC91X 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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++CONFIG_PHONE=y
++# CONFIG_PHONE_IXJ is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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 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
++
++#
++# 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_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_UNIX98_PTYS is not set
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_GEN_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB is not set
++# 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
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_INOTIFY 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
++# 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_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_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_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++# CONFIG_NFS_FS is not set
++# CONFIG_NFSD 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
++# CONFIG_9P_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_SH_STANDARD_BIOS 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
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/sh/configs/shmin_defconfig b/arch/sh/configs/shmin_defconfig
+new file mode 100644
+index 0000000..8800fef
+--- /dev/null
++++ b/arch/sh/configs/shmin_defconfig
+@@ -0,0 +1,862 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:52:49 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++# CONFIG_SWAP is not set
++# CONFIG_SYSVIPC is not set
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_UID16 is not set
++# CONFIG_SYSCTL_SYSCALL is not set
++# CONFIG_KALLSYMS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++# CONFIG_BUG is not set
++# CONFIG_ELF_CORE is not set
++# CONFIG_BASE_FULL is not set
++# CONFIG_FUTEX is not set
++# CONFIG_EPOLL is not set
++# CONFIG_SHMEM is not set
++# CONFIG_SLAB is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_TINY_SHMEM=y
++CONFIG_BASE_SMALL=1
++CONFIG_SLOB=y
++
++#
++# Loadable module support
++#
++# CONFIG_MODULES is not set
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_LSF 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_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++CONFIG_DEFAULT_NOOP=y
++CONFIG_DEFAULT_IOSCHED="noop"
++
++#
++# System type
++#
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++# CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
++# CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++CONFIG_SH_SHMIN=y
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH3=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++CONFIG_CPU_SUBTYPE_SH7706=y
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++# CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x0c000000
++CONFIG_MEMORY_SIZE=0x00800000
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_SH_FPU_EMU is not set
++# CONFIG_SH_DSP is not set
++# CONFIG_SH_ADC is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=32000000
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++# CONFIG_SH_DMA is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00210000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC1,115200 root=1f01 mtdparts=phys_mapped_flash:64k(firm)ro,-(sys) netdev=34,0x300,eth0 "
++
++#
++# Bus options
++#
++# CONFIG_PCI is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++
++#
++# PCI Hotplug Support
++#
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++# CONFIG_PACKET is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++
++#
++# User Modules And Translation Layers
++#
++# CONFIG_MTD_CHAR is not set
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++CONFIG_MTD_JEDECPROBE=y
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0xa0000000
++CONFIG_MTD_PHYSMAP_LEN=0x80000
++CONFIG_MTD_PHYSMAP_BANKWIDTH=1
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# 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_INITRD is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA 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
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_MII is not set
++# CONFIG_STNIC is not set
++# CONFIG_SMC91X 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
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER 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_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_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_HW_RANDOM=y
++# CONFIG_GEN_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# 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
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_INOTIFY 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
++# 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_PROC_SYSCTL=y
++# CONFIG_SYSFS is not set
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL 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_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++CONFIG_CRAMFS=y
++# 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_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
++# 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
++# CONFIG_9P_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# Native Language Support
++#
++# CONFIG_NLS is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_UNWIND_INFO is not set
++CONFIG_SH_STANDARD_BIOS=y
++CONFIG_EARLY_PRINTK=y
++# CONFIG_KGDB is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++
++#
++# Cryptographic options
++#
++# CONFIG_CRYPTO is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
+diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
+index 69cf02a..98503f1 100644
+--- a/arch/sh/configs/snapgear_defconfig
++++ b/arch/sh/configs/snapgear_defconfig
+@@ -1,48 +1,60 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:51 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:55:47 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # 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_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ # CONFIG_SYSVIPC is not set
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # 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_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -50,70 +62,145 @@ CONFIG_CC_ALIGN_JUMPS=0
+ # CONFIG_MODULES is not set
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ CONFIG_SH_SECUREEDGE5410=y
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ CONFIG_CPU_SUBTYPE_SH7751=y
++CONFIG_CPU_SUBTYPE_SH7751R=y
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-# CONFIG_CMDLINE_BOOL is not set
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x08000000
+ CONFIG_MEMORY_SIZE=0x01000000
+-CONFIG_MEMORY_SET=y
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_PREEMPT is not set
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=60013568
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=60000000
+
+ #
+ # CPU Frequency scaling
+@@ -133,28 +220,42 @@ CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+ # CONFIG_HD6446X_SERIES is not set
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
+ #
+ CONFIG_PCI=y
+ # CONFIG_SH_PCIDMA_NONCOHERENT is not set
+ CONFIG_PCI_AUTO=y
+ CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_PCI_NAMES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+ #
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PC-card bridges
+-#
+
+ #
+ # PCI Hotplug Support
+ #
+-# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -164,9 +265,94 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++# CONFIG_PACKET is not set
++# CONFIG_UNIX is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
+ #
+-# CONFIG_EMBEDDED_RAMDISK is not set
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
+
+ #
+ # Device Drivers
+@@ -177,7 +363,12 @@ CONFIG_BINFMT_ELF=y
+ #
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -196,7 +387,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=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
+@@ -208,18 +398,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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
+
+ #
+@@ -230,7 +411,14 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -240,6 +428,7 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # Fusion MPT device support
+ #
++# CONFIG_FUSION is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -252,69 +441,8 @@ CONFIG_IOSCHED_CFQ=y
+ # 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 is not set
+-# 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 is not set
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
++# Network device support
+ #
+-# 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
+@@ -327,6 +455,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_ARCNET is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -334,6 +467,7 @@ CONFIG_MII=y
+ # CONFIG_STNIC is not set
+ # CONFIG_HAPPYMEAL is not set
+ # CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
+ # CONFIG_NET_VENDOR_3COM is not set
+ # CONFIG_SMC91X is not set
+
+@@ -376,15 +510,22 @@ CONFIG_8139TOO=y
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+ # CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -406,6 +547,8 @@ CONFIG_8139TOO=y
+ # CONFIG_SLIP is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -421,6 +564,7 @@ CONFIG_8139TOO=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -435,18 +579,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # CONFIG_INPUT_EVBUG is not set
+
+ #
+-# Input I/O drivers
+-#
+-# CONFIG_GAMEPORT is not set
+-CONFIG_SOUND_GAMEPORT=y
+-CONFIG_SERIO=y
+-CONFIG_SERIO_I8042=y
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_CT82C710 is not set
+-# CONFIG_SERIO_PCIPS2 is not set
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+ # Input Device Drivers
+ #
+ # CONFIG_INPUT_KEYBOARD is not set
+@@ -456,11 +588,23 @@ CONFIG_SERIO_SERPORT=y
+ # CONFIG_INPUT_MISC is not set
+
+ #
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_I8042=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_PCIPS2 is not set
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_GAMEPORT is not set
++
++#
+ # Character devices
+ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -472,6 +616,7 @@ CONFIG_HW_CONSOLE=y
+ # Non-8250 serial port support
+ #
+ # CONFIG_SERIAL_SH_SCI is not set
++# CONFIG_SERIAL_JSM is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+@@ -485,7 +630,7 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -498,14 +643,35 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # CONFIG_RAW_DRIVER is not set
+
+ #
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -515,6 +681,7 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -524,13 +691,14 @@ CONFIG_LEGACY_PTY_COUNT=256
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
+
+ #
+ # Console display driver support
+ #
+-CONFIG_VGA_CONSOLE=y
+ CONFIG_DUMMY_CONSOLE=y
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -540,12 +708,13 @@ CONFIG_DUMMY_CONSOLE=y
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -559,30 +728,66 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ 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
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -602,16 +807,14 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ # CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=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_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -635,12 +838,14 @@ CONFIG_CRAMFS=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
+@@ -649,6 +854,7 @@ CONFIG_SUNRPC=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
+@@ -669,8 +875,15 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_UNWIND_INFO is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -687,13 +900,11 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
+index 431c9c9..c16350d 100644
+--- a/arch/sh/configs/systemh_defconfig
++++ b/arch/sh/configs/systemh_defconfig
+@@ -1,48 +1,58 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11-sh
+-# Wed Mar 2 15:09:53 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 12:57:29 2006
+ #
+ CONFIG_SUPERH=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-# CONFIG_CLEAN_COMPILE is not set
+-CONFIG_BROKEN=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+ # General setup
+ #
+ CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ # CONFIG_SYSVIPC is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_SYSCTL is not set
+-# CONFIG_AUDIT is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_HOTPLUG is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++# CONFIG_HOTPLUG is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -50,75 +60,150 @@ CONFIG_CC_ALIGN_JUMPS=0
+ 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 is not set
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
+ # System type
+ #
+ # CONFIG_SH_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+ # CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+ # CONFIG_SH_73180_SOLUTION_ENGINE is not set
+ CONFIG_SH_7751_SYSTEMH=y
+-# CONFIG_SH_STB1_HARP is not set
+-# CONFIG_SH_STB1_OVERDRIVE is not set
+-# CONFIG_SH_HP620 is not set
+-# CONFIG_SH_HP680 is not set
+-# CONFIG_SH_HP690 is not set
+-# CONFIG_SH_CQREEK is not set
+-# CONFIG_SH_DMIDA is not set
++# CONFIG_SH_HP6XX is not set
+ # CONFIG_SH_EC3104 is not set
+ # CONFIG_SH_SATURN is not set
+ # CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_CAT68701 is not set
+ # CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_SH2000 is not set
+-# CONFIG_SH_ADX is not set
+ # CONFIG_SH_MPC1211 is not set
+ # CONFIG_SH_SH03 is not set
+ # CONFIG_SH_SECUREEDGE5410 is not set
+ # CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
+ # CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
+ # CONFIG_SH_EDOSK7705 is not set
+ # CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++# CONFIG_SH_TITAN is not set
++# CONFIG_SH_SHMIN is not set
+ # CONFIG_SH_UNKNOWN is not set
+-# CONFIG_CPU_SH2 is not set
+-# CONFIG_CPU_SH3 is not set
++
++#
++# Processor selection
++#
+ CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7300 is not set
+ # CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
+ # CONFIG_CPU_SUBTYPE_SH7707 is not set
+ # CONFIG_CPU_SUBTYPE_SH7708 is not set
+ # CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
+ CONFIG_CPU_SUBTYPE_SH7751=y
++CONFIG_CPU_SUBTYPE_SH7751R=y
+ # CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
+ # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+ # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
+ CONFIG_MMU=y
+-# CONFIG_CMDLINE_BOOL is not set
++CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x0c000000
+ CONFIG_MEMORY_SIZE=0x00400000
+-# CONFIG_MEMORY_OVERRIDE is not set
+-CONFIG_SH_RTC=y
+-CONFIG_SH_FPU=y
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_PREEMPT=y
+-# CONFIG_UBC_WAKEUP is not set
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
+ # CONFIG_SH_WRITETHROUGH is not set
+ # CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
+ # CONFIG_SH_STORE_QUEUES is not set
+-# CONFIG_SMP is not set
+-CONFIG_SH_PCLK_CALC=y
+-CONFIG_SH_PCLK_FREQ=49876504
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=60000000
+
+ #
+ # CPU Frequency scaling
+@@ -136,28 +221,39 @@ CONFIG_SH_PCLK_FREQ=49876504
+ # CONFIG_HD6446X_SERIES is not set
+
+ #
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Kernel features
+ #
+-CONFIG_PCI=y
+-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+-CONFIG_PCI_AUTO=y
+-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+-CONFIG_PCI_LEGACY_PROC=y
+-CONFIG_PCI_NAMES=y
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
+
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_UBC_WAKEUP is not set
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
+ #
+-# CONFIG_PCCARD is not set
++# CONFIG_PCI is not set
+
+ #
+-# PC-card bridges
++# PCCARD (PCMCIA/CardBus) support
+ #
+
+ #
+ # PCI Hotplug Support
+ #
+-# CONFIG_HOTPLUG_PCI is not set
+
+ #
+ # Executable file formats
+@@ -167,9 +263,14 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+-# SH initrd options
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
+ #
+-# CONFIG_EMBEDDED_RAMDISK is not set
++# CONFIG_NET is not set
+
+ #
+ # Device Drivers
+@@ -180,7 +281,11 @@ CONFIG_BINFMT_ELF=y
+ #
+ # CONFIG_STANDALONE is not set
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -199,31 +304,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=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
+-# 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_SX8 is not set
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=1024
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ CONFIG_BLK_DEV_INITRD=y
+-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
+-
+-#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ # CONFIG_IDE is not set
+@@ -231,7 +321,14 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ # CONFIG_SCSI is not set
++# CONFIG_SCSI_NETLINK is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
+
+ #
+ # Multi-device support (RAID and LVM)
+@@ -241,23 +338,15 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # 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 is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -274,25 +363,14 @@ CONFIG_IOSCHED_CFQ=y
+ # CONFIG_INPUT is not set
+
+ #
+-# Userland interfaces
+-#
+-
++# Hardware I/O ports
+ #
+-# 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_LIBPS2 is not set
+ # CONFIG_SERIO_RAW is not set
+-
+-#
+-# Input Device Drivers
+-#
++# CONFIG_GAMEPORT is not set
+
+ #
+ # Character devices
+@@ -322,27 +400,46 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # 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
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -352,6 +449,7 @@ CONFIG_LEGACY_PTY_COUNT=256
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -360,7 +458,9 @@ CONFIG_LEGACY_PTY_COUNT=256
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+ #
+ # Sound
+@@ -370,12 +470,12 @@ CONFIG_LEGACY_PTY_COUNT=256
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+-CONFIG_USB_ARCH_HAS_HCD=y
+-CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_HCD is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -389,29 +489,62 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+-# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
+
+ #
+ # 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
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
+ # CONFIG_MINIX_FS is not set
+ CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -431,16 +564,14 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=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_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -478,9 +609,14 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
+ # CONFIG_DEBUG_KERNEL is not set
+-CONFIG_DEBUG_PREEMPT=y
+-# CONFIG_FRAME_POINTER is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_FS is not set
+ # CONFIG_SH_STANDARD_BIOS is not set
+ # CONFIG_EARLY_SCIF_CONSOLE is not set
+ # CONFIG_KGDB is not set
+@@ -497,13 +633,11 @@ CONFIG_DEBUG_PREEMPT=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig
+new file mode 100644
+index 0000000..41049cf
+--- /dev/null
++++ b/arch/sh/configs/titan_defconfig
+@@ -0,0 +1,1697 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.19-rc3
++# Mon Oct 30 18:04:49 2006
++#
++CONFIG_SUPERH=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++# CONFIG_GENERIC_TIME is not set
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_POSIX_MQUEUE=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
++# CONFIG_AUDIT is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# System type
++#
++# CONFIG_SH_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SOLUTION_ENGINE is not set
++# CONFIG_SH_7300_SOLUTION_ENGINE is not set
++# CONFIG_SH_7343_SOLUTION_ENGINE is not set
++# CONFIG_SH_73180_SOLUTION_ENGINE is not set
++# CONFIG_SH_7751_SYSTEMH is not set
++# CONFIG_SH_HP6XX is not set
++# CONFIG_SH_EC3104 is not set
++# CONFIG_SH_SATURN is not set
++# CONFIG_SH_DREAMCAST is not set
++# CONFIG_SH_BIGSUR is not set
++# CONFIG_SH_MPC1211 is not set
++# CONFIG_SH_SH03 is not set
++# CONFIG_SH_SECUREEDGE5410 is not set
++# CONFIG_SH_HS7751RVOIP is not set
++# CONFIG_SH_7710VOIPGW is not set
++# CONFIG_SH_RTS7751R2D is not set
++# CONFIG_SH_R7780RP is not set
++# CONFIG_SH_EDOSK7705 is not set
++# CONFIG_SH_SH4202_MICRODEV is not set
++# CONFIG_SH_LANDISK is not set
++CONFIG_SH_TITAN=y
++# CONFIG_SH_SHMIN is not set
++# CONFIG_SH_UNKNOWN is not set
++
++#
++# Processor selection
++#
++CONFIG_CPU_SH4=y
++
++#
++# SH-2 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7604 is not set
++
++#
++# SH-3 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7300 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++
++#
++# SH-4 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++CONFIG_CPU_SUBTYPE_SH7751=y
++CONFIG_CPU_SUBTYPE_SH7751R=y
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++
++#
++# ST40 Processor Support
++#
++# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
++# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
++
++#
++# SH-4A Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++
++#
++# SH4AL-DSP Processor Support
++#
++# CONFIG_CPU_SUBTYPE_SH73180 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++
++#
++# Memory management options
++#
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x08030000
++CONFIG_MEMORY_SIZE=0x7fd0000
++CONFIG_VSYSCALL=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_SH_WRITETHROUGH is not set
++# CONFIG_SH_OCRAM is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_SH_FPU=y
++# CONFIG_SH_DSP is not set
++# CONFIG_SH_STORE_QUEUES is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++
++#
++# Timer support
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_PCLK_FREQ=30000000
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++CONFIG_SH_DMA=y
++CONFIG_NR_ONCHIP_DMA_CHANNELS=8
++# CONFIG_NR_DMA_CHANNELS_BOOL is not set
++
++#
++# Companion Chips
++#
++# CONFIG_HD6446X_SERIES is not set
++
++#
++# Kernel features
++#
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_KEXEC is not set
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT_NONE is not set
++CONFIG_PREEMPT_VOLUNTARY=y
++# CONFIG_PREEMPT is not set
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x009e0000
++# CONFIG_UBC_WAKEUP is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttySC1,38400N81 root=/dev/nfs ip=:::::eth1:autoconf rw"
++
++#
++# Bus options
++#
++CONFIG_PCI=y
++CONFIG_SH_PCIDMA_NONCOHERENT=y
++CONFIG_PCI_AUTO=y
++CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
++# CONFIG_PCI_DEBUG is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# PCI Hotplug Support
++#
++CONFIG_HOTPLUG_PCI=y
++# CONFIG_HOTPLUG_PCI_FAKE is not set
++# CONFIG_HOTPLUG_PCI_CPCI is not set
++# CONFIG_HOTPLUG_PCI_SHPC is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_FLAT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options (EXPERIMENTAL)
++#
++# CONFIG_PM is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++CONFIG_NET_KEY=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_ASK_IP_FIB_HASH=y
++# CONFIG_IP_FIB_TRIE is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_MULTIPLE_TABLES=y
++# CONFIG_IP_ROUTE_FWMARK is not set
++CONFIG_IP_ROUTE_MULTIPATH=y
++CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
++CONFIG_IP_ROUTE_MULTIPATH_RR=m
++CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
++CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
++CONFIG_IP_ROUTE_MULTIPATH_DRR=m
++# CONFIG_IP_ROUTE_VERBOSE 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=y
++CONFIG_NET_IPGRE=y
++CONFIG_NET_IPGRE_BROADCAST=y
++CONFIG_IP_MROUTE=y
++CONFIG_IP_PIMSM_V1=y
++CONFIG_IP_PIMSM_V2=y
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++CONFIG_INET_AH=y
++CONFIG_INET_ESP=y
++CONFIG_INET_IPCOMP=y
++CONFIG_INET_XFRM_TUNNEL=y
++CONFIG_INET_TUNNEL=y
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_DIAG=m
++CONFIG_INET_TCP_DIAG=m
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++CONFIG_IPV6=y
++CONFIG_IPV6_PRIVACY=y
++# CONFIG_IPV6_ROUTER_PREF is not set
++CONFIG_INET6_AH=y
++CONFIG_INET6_ESP=y
++CONFIG_INET6_IPCOMP=y
++# CONFIG_IPV6_MIP6 is not set
++CONFIG_INET6_XFRM_TUNNEL=y
++CONFIG_INET6_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_BEET=y
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=m
++CONFIG_IPV6_TUNNEL=y
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_BRIDGE_NETFILTER=y
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=m
++CONFIG_NETFILTER_NETLINK_QUEUE=m
++CONFIG_NETFILTER_NETLINK_LOG=m
++CONFIG_NETFILTER_XTABLES=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_SCTP=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_IP_NF_CONNTRACK=m
++CONFIG_IP_NF_CT_ACCT=y
++CONFIG_IP_NF_CONNTRACK_MARK=y
++CONFIG_IP_NF_CONNTRACK_EVENTS=y
++CONFIG_IP_NF_CONNTRACK_NETLINK=m
++# CONFIG_IP_NF_CT_PROTO_SCTP is not set
++CONFIG_IP_NF_FTP=m
++CONFIG_IP_NF_IRC=m
++CONFIG_IP_NF_NETBIOS_NS=m
++CONFIG_IP_NF_TFTP=m
++# CONFIG_IP_NF_AMANDA is not set
++CONFIG_IP_NF_PPTP=m
++CONFIG_IP_NF_H323=m
++# CONFIG_IP_NF_SIP is not set
++CONFIG_IP_NF_QUEUE=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_IPRANGE=m
++CONFIG_IP_NF_MATCH_TOS=m
++CONFIG_IP_NF_MATCH_RECENT=m
++CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_AH=m
++CONFIG_IP_NF_MATCH_TTL=m
++CONFIG_IP_NF_MATCH_OWNER=m
++CONFIG_IP_NF_MATCH_ADDRTYPE=m
++CONFIG_IP_NF_MATCH_HASHLIMIT=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_TARGET_LOG=m
++CONFIG_IP_NF_TARGET_ULOG=m
++CONFIG_IP_NF_TARGET_TCPMSS=m
++CONFIG_IP_NF_NAT=m
++CONFIG_IP_NF_NAT_NEEDED=y
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_IP_NF_TARGET_NETMAP=m
++CONFIG_IP_NF_TARGET_SAME=m
++CONFIG_IP_NF_NAT_SNMP_BASIC=m
++CONFIG_IP_NF_NAT_IRC=m
++CONFIG_IP_NF_NAT_FTP=m
++CONFIG_IP_NF_NAT_TFTP=m
++CONFIG_IP_NF_NAT_PPTP=m
++CONFIG_IP_NF_NAT_H323=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_TARGET_TOS=m
++CONFIG_IP_NF_TARGET_ECN=m
++CONFIG_IP_NF_TARGET_TTL=m
++CONFIG_IP_NF_TARGET_CLUSTERIP=m
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_IP_NF_ARPFILTER=m
++CONFIG_IP_NF_ARP_MANGLE=m
++
++#
++# IPv6: Netfilter Configuration (EXPERIMENTAL)
++#
++CONFIG_IP6_NF_QUEUE=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_HL=m
++CONFIG_IP6_NF_MATCH_OWNER=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_LOG=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_TARGET_HL=m
++CONFIG_IP6_NF_RAW=m
++
++#
++# Bridge: Netfilter Configuration
++#
++# CONFIG_BRIDGE_NF_EBTABLES is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++CONFIG_BRIDGE=y
++CONFIG_VLAN_8021Q=y
++# CONFIG_DECNET is not set
++CONFIG_LLC=y
++# 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_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
++
++#
++# Queueing/Scheduling
++#
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++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=m
++CONFIG_NET_SCH_INGRESS=m
++
++#
++# Classification
++#
++CONFIG_NET_CLS=y
++CONFIG_NET_CLS_BASIC=m
++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=y
++CONFIG_CLS_U32_MARK=y
++CONFIG_NET_CLS_RSVP=m
++CONFIG_NET_CLS_RSVP6=m
++CONFIG_NET_EMATCH=y
++CONFIG_NET_EMATCH_STACK=32
++CONFIG_NET_EMATCH_CMP=m
++CONFIG_NET_EMATCH_NBYTE=m
++CONFIG_NET_EMATCH_U32=m
++CONFIG_NET_EMATCH_META=m
++CONFIG_NET_EMATCH_TEXT=m
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_ACT_POLICE=m
++CONFIG_NET_ACT_GACT=m
++CONFIG_GACT_PROB=y
++CONFIG_NET_ACT_MIRRED=m
++CONFIG_NET_ACT_IPT=m
++CONFIG_NET_ACT_PEDIT=m
++# CONFIG_NET_ACT_SIMP is not set
++CONFIG_NET_CLS_IND=y
++CONFIG_NET_ESTIMATOR=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++CONFIG_IEEE80211=y
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=y
++CONFIG_IEEE80211_CRYPT_CCMP=y
++CONFIG_IEEE80211_CRYPT_TKIP=y
++CONFIG_IEEE80211_SOFTMAC=m
++# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
++CONFIG_WIRELESS_EXT=y
++CONFIG_FIB_RULES=y
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=m
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++CONFIG_CONNECTOR=m
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=m
++CONFIG_MTD_DEBUG=y
++CONFIG_MTD_DEBUG_VERBOSE=0
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_PARTITIONS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=m
++CONFIG_MTD_BLOCK=m
++# CONFIG_MTD_BLOCK_RO is not set
++CONFIG_FTL=m
++CONFIG_NFTL=m
++# CONFIG_NFTL_RW is not set
++CONFIG_INFTL=m
++CONFIG_RFD_FTL=m
++# CONFIG_SSFDC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=m
++CONFIG_MTD_JEDECPROBE=m
++CONFIG_MTD_GEN_PROBE=m
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++
++#
++# NAND Flash Device Drivers
++#
++CONFIG_MTD_NAND=m
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND_IDS=m
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=m
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_SX8 is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++CONFIG_ATA_OVER_ETH=m
++
++#
++# Misc devices
++#
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=m
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=m
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=m
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_IFB is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=m
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++
++#
++# PHY device support
++#
++CONFIG_PHYLIB=m
++
++#
++# MII PHY device drivers
++#
++CONFIG_MARVELL_PHY=m
++CONFIG_DAVICOM_PHY=m
++CONFIG_QSEMI_PHY=m
++CONFIG_LXT_PHY=m
++CONFIG_CICADA_PHY=m
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_FIXED_PHY is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_STNIC is not set
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_SMC91X 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 is not set
++# CONFIG_8139CP is not set
++CONFIG_8139TOO=y
++# CONFIG_8139TOO_PIO is not set
++CONFIG_8139TOO_TUNE_TWISTER=y
++# CONFIG_8139TOO_8129 is not set
++CONFIG_8139_OLD_RX_RESET=y
++# 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_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
++
++#
++# Ethernet (10000 Mbit)
++#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++CONFIG_NET_WIRELESS_RTNETLINK=y
++
++#
++# Obsolete Wireless cards support (pre-802.11)
++#
++# CONFIG_STRIP is not set
++
++#
++# Wireless 802.11b ISA/PCI cards support
++#
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
++# CONFIG_HERMES is not set
++# CONFIG_ATMEL is not set
++
++#
++# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
++#
++CONFIG_PRISM54=m
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++CONFIG_BCM43XX=m
++CONFIG_BCM43XX_DEBUG=y
++CONFIG_BCM43XX_DMA=y
++CONFIG_BCM43XX_PIO=y
++CONFIG_BCM43XX_DMA_AND_PIO_MODE=y
++# CONFIG_BCM43XX_DMA_MODE is not set
++# CONFIG_BCM43XX_PIO_MODE is not set
++# CONFIG_ZD1211RW 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=m
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_ASYNC=m
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++CONFIG_PPP_MPPE=m
++CONFIG_PPPOE=m
++CONFIG_SLIP=m
++CONFIG_SLIP_COMPRESSED=y
++CONFIG_SLHC=m
++CONFIG_SLIP_SMART=y
++# CONFIG_SLIP_MODE_SLIP6 is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++
++#
++# 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 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
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_CONSOLE=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
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_SH_WDT=m
++# CONFIG_SH_WDT_MMAP is not set
++
++#
++# PCI-based Watchdog Cards
++#
++# CONFIG_PCIPCWATCHDOG is not set
++# CONFIG_WDTPCI is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_HW_RANDOM=y
++# 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
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
++# Dallas's 1-wire bus
++#
++# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
++
++#
++# Graphics support
++#
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# 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=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_SPLIT_ISO=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# 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 is not set
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=m
++CONFIG_USB_PRINTER=m
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# may also be needed; see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_DPCM 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
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Input Devices
++#
++# CONFIG_USB_HID is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB Network Adapters
++#
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_USBNET=m
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_CDCETHER=m
++# CONFIG_USB_NET_GL620A is not set
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++# CONFIG_USB_NET_MCS7830 is not set
++# CONFIG_USB_NET_RNDIS_HOST is not set
++# CONFIG_USB_NET_CDC_SUBSET is not set
++CONFIG_USB_NET_ZAURUS=m
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++CONFIG_USB_SERIAL=m
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_AIRPRIME is not set
++CONFIG_USB_SERIAL_ARK3116=m
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=m
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_TEST is not set
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# MMC/SD Card support
++#
++# CONFIG_MMC is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
++# InfiniBand support
++#
++# CONFIG_INFINIBAND is not set
++
++#
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++CONFIG_RTC_LIB=m
++CONFIG_RTC_CLASS=m
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=m
++CONFIG_RTC_INTF_PROC=m
++CONFIG_RTC_INTF_DEV=m
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++
++#
++# RTC drivers
++#
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++CONFIG_RTC_DRV_SH=m
++# CONFIG_RTC_DRV_TEST is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
++# File systems
++#
++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_EXT4DEV_FS=m
++# CONFIG_EXT4DEV_FS_XATTR is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=m
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_REISERFS_FS=m
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_REISERFS_FS_XATTR is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_XFS_FS=m
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_SECURITY is not set
++# CONFIG_XFS_POSIX_ACL is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++CONFIG_FUSE_FS=m
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=m
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++CONFIG_ZISOFS_FS=m
++CONFIG_UDF_FS=m
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_VFAT_FS=m
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++CONFIG_CONFIGFS_FS=m
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_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_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# 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=y
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=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=m
++# CONFIG_SMB_NLS_DEFAULT is not set
++CONFIG_CIFS=m
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_CIFS_EXPERIMENTAL is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_9P_FS=m
++
++#
++# 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_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++CONFIG_NLS=m
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# 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=m
++CONFIG_NLS_ISO8859_1=m
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++CONFIG_NLS_UTF8=m
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_LOG_BUF_SHIFT=16
++# CONFIG_DETECT_SOFTLOCKUP is not set
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_FRAME_POINTER is not set
++# CONFIG_FORCED_INLINING is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_SH_STANDARD_BIOS is not set
++# CONFIG_EARLY_SCIF_CONSOLE is not set
++# CONFIG_EARLY_PRINTK is not set
++# CONFIG_DEBUG_STACKOVERFLOW is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_4KSTACKS is not set
++# CONFIG_KGDB is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_HMAC=y
++CONFIG_CRYPTO_NULL=m
++CONFIG_CRYPTO_MD4=m
++CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_SHA1=y
++CONFIG_CRYPTO_SHA256=m
++CONFIG_CRYPTO_SHA512=m
++CONFIG_CRYPTO_WP512=m
++CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=y
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_DES=y
++CONFIG_CRYPTO_BLOWFISH=m
++CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
++CONFIG_CRYPTO_SERPENT=m
++CONFIG_CRYPTO_AES=y
++CONFIG_CRYPTO_CAST5=m
++CONFIG_CRYPTO_CAST6=m
++CONFIG_CRYPTO_TEA=m
++CONFIG_CRYPTO_ARC4=y
++CONFIG_CRYPTO_KHAZAD=m
++CONFIG_CRYPTO_ANUBIS=m
++CONFIG_CRYPTO_DEFLATE=y
++CONFIG_CRYPTO_MICHAEL_MIC=y
++CONFIG_CRYPTO_CRC32C=m
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Hardware crypto devices
++#
++
++#
++# Library routines
++#
++CONFIG_CRC_CCITT=m
++CONFIG_CRC16=m
++CONFIG_CRC32=y
++CONFIG_LIBCRC32C=m
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_TEXTSEARCH_BM=m
++CONFIG_TEXTSEARCH_FSM=m
++CONFIG_PLIST=y
+diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
+index 0f15216..defc13c 100644
+--- a/arch/sh/drivers/dma/Kconfig
++++ b/arch/sh/drivers/dma/Kconfig
+@@ -11,6 +11,8 @@ config SH_DMA
+ config NR_ONCHIP_DMA_CHANNELS
+ depends on SH_DMA
+ int "Number of on-chip DMAC channels"
++ default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
++ default "12" if CPU_SUBTYPE_SH7780
+ default "4"
+ help
+ This allows you to specify the number of channels that the on-chip
+@@ -52,4 +54,3 @@ config DMA_PAGE_OPS_CHANNEL
+ are dual-address capable.
+
+ endmenu
+-
+diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c
+index 0f866f8..0caf11b 100644
+--- a/arch/sh/drivers/dma/dma-g2.c
++++ b/arch/sh/drivers/dma/dma-g2.c
+@@ -3,7 +3,7 @@
+ *
+ * G2 bus DMA support
+ *
+- * Copyright (C) 2003, 2004 Paul Mundt
++ * Copyright (C) 2003 - 2006 Paul Mundt
+ *
+ * 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
+@@ -13,7 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+-
++#include <asm/cacheflush.h>
+ #include <asm/mach/sysasic.h>
+ #include <asm/mach/dma.h>
+ #include <asm/dma.h>
+@@ -47,17 +47,31 @@ struct g2_dma_info {
+
+ static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800;
+
+-static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++#define g2_bytes_remaining(i) \
++ ((g2_dma->channel[i].size - \
++ g2_dma->status[i].size) & 0x0fffffff)
++
++static irqreturn_t g2_dma_interrupt(int irq, void *dev_id)
+ {
+- /* FIXME: Do some meaningful completion work here.. */
+- return IRQ_HANDLED;
+-}
++ int i;
+
+-static struct irqaction g2_dma_irq = {
+- .name = "g2 DMA handler",
+- .handler = g2_dma_interrupt,
+- .flags = IRQF_DISABLED,
+-};
++ for (i = 0; i < G2_NR_DMA_CHANNELS; i++) {
++ if (g2_dma->status[i].status & 0x20000000) {
++ unsigned int bytes = g2_bytes_remaining(i);
++
++ if (likely(bytes == 0)) {
++ struct dma_info *info = dev_id;
++ struct dma_channel *chan = info->channels + i;
++
++ wake_up(&chan->wait_queue);
++
++ return IRQ_HANDLED;
++ }
++ }
++ }
++
++ return IRQ_NONE;
++}
+
+ static int g2_enable_dma(struct dma_channel *chan)
+ {
+@@ -135,8 +149,14 @@ static int g2_xfer_dma(struct dma_channe
+ return 0;
+ }
+
++static int g2_get_residue(struct dma_channel *chan)
++{
++ return g2_bytes_remaining(chan->chan);
++}
++
+ static struct dma_ops g2_dma_ops = {
+ .xfer = g2_xfer_dma,
++ .get_residue = g2_get_residue,
+ };
+
+ static struct dma_info g2_dma_info = {
+@@ -148,13 +168,22 @@ static struct dma_info g2_dma_info = {
+
+ static int __init g2_dma_init(void)
+ {
+- setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq);
++ int ret;
++
++ ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, IRQF_DISABLED,
++ "g2 DMA handler", &g2_dma_info);
++ if (unlikely(ret))
++ return -EINVAL;
+
+ /* Magic */
+ g2_dma->wait_state = 27;
+ g2_dma->magic = 0x4659404f;
+
+- return register_dmac(&g2_dma_info);
++ ret = register_dmac(&g2_dma_info);
++ if (unlikely(ret != 0))
++ free_irq(HW_EVENT_G2_DMA, 0);
++
++ return ret;
+ }
+
+ static void __exit g2_dma_exit(void)
+@@ -169,4 +198,3 @@ module_exit(g2_dma_exit);
+ MODULE_AUTHOR("Paul Mundt <lethal at linux-sh.org>");
+ MODULE_DESCRIPTION("G2 bus DMA driver");
+ MODULE_LICENSE("GPL");
+-
+diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c
+index 30a580a..838fad5 100644
+--- a/arch/sh/drivers/dma/dma-pvr2.c
++++ b/arch/sh/drivers/dma/dma-pvr2.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh/boards/dreamcast/dma-pvr2.c
++ * arch/sh/drivers/dma/dma-pvr2.c
+ *
+ * NEC PowerVR 2 (Dreamcast) DMA support
+ *
+@@ -18,10 +18,10 @@
+ #include <asm/dma.h>
+ #include <asm/io.h>
+
+-static unsigned int xfer_complete = 0;
+-static int count = 0;
++static unsigned int xfer_complete;
++static int count;
+
+-static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id)
+ {
+ if (get_dma_residue(PVR2_CASCADE_CHAN)) {
+ printk(KERN_WARNING "DMA: SH DMAC did not complete transfer "
+@@ -107,4 +107,3 @@ module_exit(pvr2_dma_exit);
+ MODULE_AUTHOR("Paul Mundt <lethal at linux-sh.org>");
+ MODULE_DESCRIPTION("NEC PowerVR 2 DMA driver");
+ MODULE_LICENSE("GPL");
+-
+diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
+index e028a2d..6607860 100644
+--- a/arch/sh/drivers/dma/dma-sh.c
++++ b/arch/sh/drivers/dma/dma-sh.c
+@@ -11,35 +11,42 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+-
+ #include <linux/init.h>
+-#include <linux/irq.h>
+ #include <linux/interrupt.h>
+ #include <linux/module.h>
+ #include <asm/dreamcast/dma.h>
+-#include <asm/signal.h>
+-#include <asm/irq.h>
+ #include <asm/dma.h>
+ #include <asm/io.h>
+ #include "dma-sh.h"
+
+-static inline unsigned int get_dmte_irq(unsigned int chan)
+-{
+- unsigned int irq = 0;
+
++
++#ifdef CONFIG_CPU_SH4
++static struct ipr_data dmae_ipr_map[] = {
++ { DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++};
++#endif
++static struct ipr_data dmte_ipr_map[] = {
+ /*
+ * Normally we could just do DMTE0_IRQ + chan outright, though in the
+ * case of the 7751R, the DMTE IRQs for channels > 4 start right above
+ * the SCIF
+ */
+- if (chan < 4) {
+- irq = DMTE0_IRQ + chan;
+- } else {
+-#ifdef DMTE4_IRQ
+- irq = DMTE4_IRQ + chan - 4;
+-#endif
+- }
++ { DMTE0_IRQ + 0, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE0_IRQ + 1, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE0_IRQ + 2, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE0_IRQ + 3, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE4_IRQ + 0, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE4_IRQ + 1, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE4_IRQ + 2, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++ { DMTE4_IRQ + 3, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY },
++};
+
++static inline unsigned int get_dmte_irq(unsigned int chan)
++{
++ unsigned int irq = 0;
++ if (chan < ARRAY_SIZE(dmte_ipr_map))
++ irq = dmte_ipr_map[chan].irq;
+ return irq;
+ }
+
+@@ -64,9 +71,9 @@ static inline unsigned int calc_xmit_shi
+ * Besides that it needs to waken any waiting process, which should handle
+ * setting up the next transfer.
+ */
+-static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_tei(int irq, void *dev_id)
+ {
+- struct dma_channel *chan = (struct dma_channel *)dev_id;
++ struct dma_channel *chan = dev_id;
+ u32 chcr;
+
+ chcr = ctrl_inl(CHCR[chan->chan]);
+@@ -84,18 +91,23 @@ static irqreturn_t dma_tei(int irq, void
+
+ static int sh_dmac_request_dma(struct dma_channel *chan)
+ {
+- char name[32];
++ if (unlikely(!chan->flags & DMA_TEI_CAPABLE))
++ return 0;
+
+- snprintf(name, sizeof(name), "DMAC Transfer End (Channel %d)",
++ chan->name = kzalloc(32, GFP_KERNEL);
++ if (unlikely(chan->name == NULL))
++ return -ENOMEM;
++ snprintf(chan->name, 32, "DMAC Transfer End (Channel %d)",
+ chan->chan);
+
+ return request_irq(get_dmte_irq(chan->chan), dma_tei,
+- IRQF_DISABLED, name, chan);
++ IRQF_DISABLED, chan->name, chan);
+ }
+
+ static void sh_dmac_free_dma(struct dma_channel *chan)
+ {
+ free_irq(get_dmte_irq(chan->chan), chan);
++ kfree(chan->name);
+ }
+
+ static void
+@@ -227,7 +239,7 @@ static inline int dmaor_reset(void)
+ }
+
+ #if defined(CONFIG_CPU_SH4)
+-static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dma_err(int irq, void *dummy)
+ {
+ dmaor_reset();
+ disable_irq(irq);
+@@ -257,24 +269,23 @@ static int __init sh_dmac_init(void)
+ int i;
+
+ #ifdef CONFIG_CPU_SH4
+- make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
++ make_ipr_irq(dmae_ipr_map, ARRAY_SIZE(dmae_ipr_map));
+ i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0);
+- if (i < 0)
++ if (unlikely(i < 0))
+ return i;
+ #endif
+
+- for (i = 0; i < info->nr_channels; i++) {
+- int irq = get_dmte_irq(i);
+-
+- make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+- }
++ i = info->nr_channels;
++ if (i > ARRAY_SIZE(dmte_ipr_map))
++ i = ARRAY_SIZE(dmte_ipr_map);
++ make_ipr_irq(dmte_ipr_map, i);
+
+ /*
+ * Initialize DMAOR, and clean up any error flags that may have
+ * been set.
+ */
+ i = dmaor_reset();
+- if (i < 0)
++ if (unlikely(i != 0))
+ return i;
+
+ return register_dmac(info);
+diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
+index 70a5d82..29b8ef9 100644
+--- a/arch/sh/drivers/dma/dma-sysfs.c
++++ b/arch/sh/drivers/dma/dma-sysfs.c
+@@ -48,12 +48,11 @@ static int __init dma_sysclass_init(void
+ int ret;
+
+ ret = sysdev_class_register(&dma_sysclass);
+- if (ret == 0)
+- sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr);
++ if (unlikely(ret))
++ return ret;
+
+- return ret;
++ return sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr);
+ }
+-
+ postcore_initcall(dma_sysclass_init);
+
+ static ssize_t dma_show_dev_id(struct sys_device *dev, char *buf)
+@@ -152,4 +151,3 @@ void dma_remove_sysfs_files(struct dma_c
+
+ sysdev_unregister(dev);
+ }
+-
+diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
+index 365bc16..9e00cb8 100644
+--- a/arch/sh/drivers/pci/Makefile
++++ b/arch/sh/drivers/pci/Makefile
+@@ -6,7 +6,8 @@ obj-y += pci.o
+ obj-$(CONFIG_PCI_AUTO) += pci-auto.o
+
+ obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o
+-obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o
+
+ obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \
+ dma-dreamcast.o
+@@ -14,3 +15,6 @@ obj-$(CONFIG_SH_SECUREEDGE5410) += ops-
+ obj-$(CONFIG_SH_BIGSUR) += ops-bigsur.o
+ obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o
+ obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o
++obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o
++obj-$(CONFIG_SH_TITAN) += ops-titan.o
++obj-$(CONFIG_SH_LANDISK) += ops-landisk.o
+diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
+index 6acf02b..230d6ec 100644
+--- a/arch/sh/drivers/pci/dma-dreamcast.c
++++ b/arch/sh/drivers/pci/dma-dreamcast.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh/pci/dma-dreamcast.c
++ * arch/sh/drivers/pci/dma-dreamcast.c
+ *
+ * PCI DMA support for the Sega Dreamcast
+ *
+diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
+index 63b1c6f..6f53f82 100644
+--- a/arch/sh/drivers/pci/fixups-dreamcast.c
++++ b/arch/sh/drivers/pci/fixups-dreamcast.c
+@@ -1,10 +1,10 @@
+ /*
+- * arch/sh/pci/fixups-dreamcast.c
++ * arch/sh/drivers/pci/fixups-dreamcast.c
+ *
+ * PCI fixups for the Sega Dreamcast
+ *
+ * Copyright (C) 2001, 2002 M. R. Brown
+- * Copyright (C) 2002, 2003 Paul Mundt
++ * Copyright (C) 2002, 2003, 2006 Paul Mundt
+ *
+ * This file originally bore the message (with enclosed-$):
+ * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
+@@ -45,36 +45,16 @@ static void __init gapspci_fixup_resourc
+ printk("PCI: Failed resource fixup\n");
+ }
+ }
+-
+ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
+
+-void __init pcibios_fixup_bus(struct pci_bus *bus)
++int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+ {
+- /*
+- * We don't have any sub bus to fix up, and this is a rather
+- * stupid place to put general device fixups. Don't do it.
+- * Use the pcibios_fixups table or suffer the consequences.
++ /*
++ * The interrupt routing semantics here are quite trivial.
++ *
++ * We basically only support one interrupt, so we only bother
++ * updating a device's interrupt line with this single shared
++ * interrupt. Keeps routing quite simple, doesn't it?
+ */
++ return GAPSPCI_IRQ;
+ }
+-
+-void __init pcibios_fixup_irqs(void)
+-{
+- struct pci_dev *dev = 0;
+-
+- for_each_pci_dev(dev) {
+- /*
+- * The interrupt routing semantics here are quite trivial.
+- *
+- * We basically only support one interrupt, so we only bother
+- * updating a device's interrupt line with this single shared
+- * interrupt. Keeps routing quite simple, doesn't it?
+- */
+- printk(KERN_NOTICE "PCI: Fixing up IRQ routing for device %s\n",
+- pci_name(dev));
+-
+- dev->irq = GAPSPCI_IRQ;
+-
+- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+- }
+-}
+-
+diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
+new file mode 100644
+index 0000000..3e321df
+--- /dev/null
++++ b/arch/sh/drivers/pci/fixups-r7780rp.c
+@@ -0,0 +1,45 @@
++/*
++ * arch/sh/drivers/pci/fixups-r7780rp.c
++ *
++ * Highlander R7780RP-1 PCI fixups
++ *
++ * Copyright (C) 2003 Lineo uSolutions, Inc.
++ * Copyright (C) 2004 - 2006 Paul Mundt
++ *
++ * 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/pci.h>
++#include "pci-sh4.h"
++#include <asm/io.h>
++
++int pci_fixup_pcic(void)
++{
++ pci_write_reg(0x000043ff, SH4_PCIINTM);
++ pci_write_reg(0x0000380f, SH4_PCIAINTM);
++
++ pci_write_reg(0xfbb00047, SH7780_PCICMD);
++ pci_write_reg(0x00000000, SH7780_PCIIBAR);
++
++ pci_write_reg(0x00011912, SH7780_PCISVID);
++ pci_write_reg(0x08000000, SH7780_PCICSCR0);
++ pci_write_reg(0x0000001b, SH7780_PCICSAR0);
++ pci_write_reg(0xfd000000, SH7780_PCICSCR1);
++ pci_write_reg(0x0000000f, SH7780_PCICSAR1);
++
++ pci_write_reg(0xfd000000, SH7780_PCIMBR0);
++ pci_write_reg(0x00fc0000, SH7780_PCIMBMR0);
++
++#ifdef CONFIG_32BIT
++ pci_write_reg(0xc0000000, SH7780_PCIMBR2);
++ pci_write_reg(0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
++#endif
++
++ /* Set IOBR for windows containing area specified in pci.h */
++ pci_write_reg((PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE - 1)),
++ SH7780_PCIIOBR);
++ pci_write_reg(((SH7780_PCI_IO_SIZE-1) & (7<<18)), SH7780_PCIIOBMR);
++
++ return 0;
++}
+diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
+index 0c590fc..e72ceb5 100644
+--- a/arch/sh/drivers/pci/fixups-rts7751r2d.c
++++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
+@@ -10,8 +10,7 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+-#include "pci-sh7751.h"
+-#include <asm/io.h>
++#include "pci-sh4.h"
+
+ #define PCIMCR_MRSET_OFF 0xBFFFFFFF
+ #define PCIMCR_RFSH_OFF 0xFFFFFFFB
+@@ -22,22 +21,23 @@ int pci_fixup_pcic(void)
+
+ bcr1 = inl(SH7751_BCR1);
+ bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
+- outl(bcr1, PCI_REG(SH7751_PCIBCR1));
++ pci_write_reg(bcr1, SH4_PCIBCR1);
+
+ /* Enable all interrupts, so we known what to fix */
+- outl(0x0000c3ff, PCI_REG(SH7751_PCIINTM));
+- outl(0x0000380f, PCI_REG(SH7751_PCIAINTM));
++ pci_write_reg(0x0000c3ff, SH4_PCIINTM);
++ pci_write_reg(0x0000380f, SH4_PCIAINTM);
+
+- outl(0xfb900047, PCI_REG(SH7751_PCICONF1));
+- outl(0xab000001, PCI_REG(SH7751_PCICONF4));
++ pci_write_reg(0xfb900047, SH7751_PCICONF1);
++ pci_write_reg(0xab000001, SH7751_PCICONF4);
+
+ mcr = inl(SH7751_MCR);
+ mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+- outl(mcr, PCI_REG(SH7751_PCIMCR));
++ pci_write_reg(mcr, SH4_PCIMCR);
++
++ pci_write_reg(0x0c000000, SH7751_PCICONF5);
++ pci_write_reg(0xd0000000, SH7751_PCICONF6);
++ pci_write_reg(0x0c000000, SH4_PCILAR0);
++ pci_write_reg(0x00000000, SH4_PCILAR1);
+
+- outl(0x0c000000, PCI_REG(SH7751_PCICONF5));
+- outl(0xd0000000, PCI_REG(SH7751_PCICONF6));
+- outl(0x0c000000, PCI_REG(SH7751_PCILAR0));
+- outl(0x00000000, PCI_REG(SH7751_PCILAR1));
+ return 0;
+ }
+diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
+index 57ac26c..2e8a18b 100644
+--- a/arch/sh/drivers/pci/fixups-sh03.c
++++ b/arch/sh/drivers/pci/fixups-sh03.c
+@@ -3,11 +3,7 @@
+ #include <linux/types.h>
+ #include <linux/pci.h>
+
+-/*
+- * IRQ functions
+- */
+-
+-int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev)
++int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+ {
+ int irq;
+
+@@ -17,8 +13,9 @@ int __init pcibios_map_platform_irq(u8 s
+ case 8: return 5; /* eth1 */
+ case 6: return 2; /* PCI bridge */
+ default:
+- printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+- return 2;
++ printk(KERN_ERR "PCI: Bad IRQ mapping request "
++ "for slot %d\n", slot);
++ return 2;
+ }
+ } else {
+ switch (pin) {
+@@ -32,30 +29,3 @@ int __init pcibios_map_platform_irq(u8 s
+ }
+ return irq;
+ }
+-
+-static u8 __init sh03_no_swizzle(struct pci_dev *dev, u8 *pin)
+-{
+- /* no swizzling */
+- return PCI_SLOT(dev->devfn);
+-}
+-
+-static int sh03_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- int irq = -1;
+-
+- /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+- irq = pcibios_map_platform_irq(slot, pin, dev);
+- if( irq < 0 ) {
+- pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
+- return irq;
+- }
+-
+- pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
+-
+- return irq;
+-}
+-
+-void __init pcibios_fixup_irqs(void)
+-{
+- pci_fixup_irqs(sh03_no_swizzle, sh03_pci_lookup_irq);
+-}
+diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c
+index ae82c6c..eb31be7 100644
+--- a/arch/sh/drivers/pci/ops-bigsur.c
++++ b/arch/sh/drivers/pci/ops-bigsur.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/pci-bigsur.c
++ * linux/arch/sh/drivers/pci/ops-bigsur.c
+ *
+ * By Dustin McIntire (dustin at sensoria.com) (c)2001
+ *
+@@ -10,15 +10,12 @@
+ *
+ * PCI initialization for the Hitachi Big Sur Evaluation Board
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+-#include <linux/delay.h>
+ #include <linux/pci.h>
+-
+ #include <asm/io.h>
+-#include "pci-sh7751.h"
++#include "pci-sh4.h"
+ #include <asm/bigsur/bigsur.h>
+
+ #define BIGSUR_PCI_IO 0x4000
+@@ -41,11 +38,11 @@ static struct resource sh7751_mem_resour
+ extern struct pci_ops sh7751_pci_ops;
+
+ struct pci_channel board_pci_channels[] = {
+- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
++ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { 0, }
+ };
+
+-static struct sh7751_pci_address_map sh7751_pci_map = {
++static struct sh4_pci_address_map sh7751_pci_map = {
+ .window0 = {
+ .base = SH7751_CS3_BASE_ADDR,
+ .size = BIGSUR_LSR0_SIZE,
+@@ -58,7 +55,7 @@ static struct sh7751_pci_address_map sh7
+ };
+
+ /*
+- * Initialize the Big Sur PCI interface
++ * Initialize the Big Sur PCI interface
+ * Setup hardware to be Central Funtion
+ * Copy the BSR regs to the PCI interface
+ * Setup PCI windows into local RAM
+@@ -68,15 +65,15 @@ int __init pcibios_init_platform(void)
+ return sh7751_pcic_init(&sh7751_pci_map);
+ }
+
+-int pcibios_map_platform_irq(u8 slot, u8 pin)
++int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+ {
+- /*
++ /*
+ * The Big Sur can be used in a CPCI chassis, but the SH7751 PCI
+ * interface is on the wrong end of the board so that it can also
+ * support a V320 CPI interface chip... Therefor the IRQ mapping is
+ * somewhat use dependent... I'l assume a linear map for now, i.e.
+ * INTA=slot0,pin0... INTD=slot3,pin0...
+- */
++ */
+ int irq = (slot + pin-1) % 4 + BIGSUR_SH7751_PCI_IRQ_BASE;
+
+ PCIDBG(2, "PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n",
+@@ -84,4 +81,3 @@ int pcibios_map_platform_irq(u8 slot, u8
+
+ return irq;
+ }
+-
+diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c
+index 23d5279..381306c 100644
+--- a/arch/sh/drivers/pci/ops-dreamcast.c
++++ b/arch/sh/drivers/pci/ops-dreamcast.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh/pci/ops-dreamcast.c
++ * arch/sh/drivers/pci/ops-dreamcast.c
+ *
+ * PCI operations for the Sega Dreamcast
+ *
+diff --git a/arch/sh/drivers/pci/ops-landisk.c b/arch/sh/drivers/pci/ops-landisk.c
+new file mode 100644
+index 0000000..d060308
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-landisk.c
+@@ -0,0 +1,67 @@
++/*
++ * arch/sh/drivers/pci/ops-landisk.c
++ *
++ * PCI initialization for the I-O DATA Device, Inc. LANDISK board
++ *
++ * Copyright (C) 2006 kogiidena
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include "pci-sh4.h"
++
++static struct resource sh7751_io_resource = {
++ .name = "SH7751 IO",
++ .start = 0x4000,
++ .end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
++ .flags = IORESOURCE_IO
++};
++
++static struct resource sh7751_mem_resource = {
++ .name = "SH7751 mem",
++ .start = SH7751_PCI_MEMORY_BASE,
++ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
++ .flags = IORESOURCE_MEM
++};
++
++struct pci_channel board_pci_channels[] = {
++ {&sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0x3ff},
++ {NULL, NULL, NULL, 0, 0},
++};
++
++static struct sh4_pci_address_map sh7751_pci_map = {
++ .window0 = {
++ .base = SH7751_CS3_BASE_ADDR,
++ .size = (64 << 20), /* 64MB */
++ },
++
++ .flags = SH4_PCIC_NO_RESET,
++};
++
++int __init pcibios_init_platform(void)
++{
++ return sh7751_pcic_init(&sh7751_pci_map);
++}
++
++int pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
++{
++ /*
++ * slot0: pin1-4 = irq5,6,7,8
++ * slot1: pin1-4 = irq6,7,8,5
++ * slot2: pin1-4 = irq7,8,5,6
++ * slot3: pin1-4 = irq8,5,6,7
++ */
++ int irq = ((slot + pin - 1) & 0x3) + 5;
++
++ if ((slot | (pin - 1)) > 0x3) {
++ printk("PCI: Bad IRQ mapping request for slot %d pin %c\n",
++ slot, pin - 1 + 'A');
++ return -1;
++ }
++ return irq;
++}
+diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
+new file mode 100644
+index 0000000..eeea157
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-r7780rp.c
+@@ -0,0 +1,73 @@
++/*
++ * Author: Ian DaSilva (idasilva at mvista.com)
++ *
++ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ * PCI initialization for the Renesas SH7780 Highlander R7780RP-1 board
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <asm/r7780rp.h>
++#include <asm/io.h>
++#include "pci-sh4.h"
++
++int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
++{
++ switch (slot) {
++ case 0: return IRQ_PCISLOT1; /* PCI Interrupt #1 */
++ case 1: return IRQ_PCISLOT2; /* PCI Interrupt #2 */
++ case 2: return IRQ_PCISLOT3; /* PCI Interrupt #3 */
++ case 3: return IRQ_PCISLOT4; /* PCI Interrupt E4 */
++ default:
++ printk(KERN_ERR "PCI: Bad IRQ mapping "
++ "request for slot %d, func %d\n", slot, pin-1);
++ return -1;
++ }
++}
++
++static struct resource sh7780_io_resource = {
++ .name = "SH7780_IO",
++ .start = 0x2000,
++ .end = 0x2000 + SH7780_PCI_IO_SIZE - 1,
++ .flags = IORESOURCE_IO
++};
++
++static struct resource sh7780_mem_resource = {
++ .name = "SH7780_mem",
++ .start = SH7780_PCI_MEMORY_BASE,
++ .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
++ .flags = IORESOURCE_MEM
++};
++
++extern struct pci_ops sh7780_pci_ops;
++
++struct pci_channel board_pci_channels[] = {
++ { &sh4_pci_ops, &sh7780_io_resource, &sh7780_mem_resource, 0, 0xff },
++ { NULL, NULL, NULL, 0, 0 },
++};
++EXPORT_SYMBOL(board_pci_channels);
++
++static struct sh4_pci_address_map sh7780_pci_map = {
++ .window0 = {
++ .base = SH7780_CS2_BASE_ADDR,
++ .size = 0x04000000,
++ },
++
++ .window1 = {
++ .base = SH7780_CS3_BASE_ADDR,
++ .size = 0x04000000,
++ },
++
++ .flags = SH4_PCIC_NO_RESET,
++};
++
++int __init pcibios_init_platform(void)
++{
++ return sh7780_pcic_init(&sh7780_pci_map);
++}
+diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c
+index 83171d1..4a518d9 100644
+--- a/arch/sh/drivers/pci/ops-rts7751r2d.c
++++ b/arch/sh/drivers/pci/ops-rts7751r2d.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sh/kernel/pci-rts7751r2d.c
++ * linux/arch/sh/drivers/pci/ops-rts7751r2d.c
+ *
+ * Author: Ian DaSilva (idasilva at mvista.com)
+ *
+@@ -10,29 +10,24 @@
+ *
+ * PCI initialization for the Renesas SH7751R RTS7751R2D board
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+-#include <linux/delay.h>
+ #include <linux/pci.h>
+-#include <linux/module.h>
++#include <linux/io.h>
++#include <asm/rts7751r2d.h>
++#include "pci-sh4.h"
+
+-#include <asm/io.h>
+-#include "pci-sh7751.h"
+-#include <asm/rts7751r2d/rts7751r2d.h>
++static u8 rts7751r2d_irq_tab[] __initdata = {
++ IRQ_PCISLOT1,
++ IRQ_PCISLOT2,
++ IRQ_PCMCIA,
++ IRQ_PCIETH,
++};
+
+-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
++int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+ {
+- switch (slot) {
+- case 0: return IRQ_PCISLOT1; /* PCI Extend slot #1 */
+- case 1: return IRQ_PCISLOT2; /* PCI Extend slot #2 */
+- case 2: return IRQ_PCMCIA; /* PCI Cardbus Bridge */
+- case 3: return IRQ_PCIETH; /* Realtek Ethernet controller */
+- default:
+- printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+- return -1;
+- }
++ return rts7751r2d_irq_tab[slot];
+ }
+
+ static struct resource sh7751_io_resource = {
+@@ -52,12 +47,12 @@ static struct resource sh7751_mem_resour
+ extern struct pci_ops sh7751_pci_ops;
+
+ struct pci_channel board_pci_channels[] = {
+- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
++ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+ };
+ EXPORT_SYMBOL(board_pci_channels);
+
+-static struct sh7751_pci_address_map sh7751_pci_map = {
++static struct sh4_pci_address_map sh7751_pci_map = {
+ .window0 = {
+ .base = SH7751_CS3_BASE_ADDR,
+ .size = 0x04000000,
+@@ -68,7 +63,7 @@ static struct sh7751_pci_address_map sh7
+ .size = 0x00000000, /* Unused */
+ },
+
+- .flags = SH7751_PCIC_NO_RESET,
++ .flags = SH4_PCIC_NO_RESET,
+ };
+
+ int __init pcibios_init_platform(void)
+diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c
+index e58d556..ebb58e6 100644
+--- a/arch/sh/drivers/pci/ops-sh03.c
++++ b/arch/sh/drivers/pci/ops-sh03.c
+@@ -35,10 +35,10 @@ static struct resource sh7751_mem_resour
+ .flags = IORESOURCE_MEM
+ };
+
+-extern struct pci_ops sh7751_pci_ops;
++extern struct pci_ops sh4_pci_ops;
+
+ struct pci_channel board_pci_channels[] = {
+- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
++ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+ };
+
+diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
+new file mode 100644
+index 0000000..2d43710
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-sh4.c
+@@ -0,0 +1,164 @@
++/*
++ * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780).
++ *
++ * Copyright (C) 2002 - 2006 Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License v2. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/pci.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include "pci-sh4.h"
++
++/*
++ * Direct access to PCI hardware...
++ */
++#define CONFIG_CMD(bus, devfn, where) \
++ P1SEGADDR((bus->number << 16) | (devfn << 8) | (where & ~3))
++
++static DEFINE_SPINLOCK(sh4_pci_lock);
++
++/*
++ * Functions for accessing PCI configuration space with type 1 accesses
++ */
++static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 *val)
++{
++ unsigned long flags;
++ u32 data;
++
++ /*
++ * PCIPDR may only be accessed as 32 bit words,
++ * so we must do byte alignment by hand
++ */
++ spin_lock_irqsave(&sh4_pci_lock, flags);
++ pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
++ data = pci_read_reg(SH4_PCIPDR);
++ spin_unlock_irqrestore(&sh4_pci_lock, flags);
++
++ switch (size) {
++ case 1:
++ *val = (data >> ((where & 3) << 3)) & 0xff;
++ break;
++ case 2:
++ *val = (data >> ((where & 2) << 3)) & 0xffff;
++ break;
++ case 4:
++ *val = data;
++ break;
++ default:
++ return PCIBIOS_FUNC_NOT_SUPPORTED;
++ }
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++/*
++ * Since SH4 only does 32bit access we'll have to do a read,
++ * mask,write operation.
++ * We'll allow an odd byte offset, though it should be illegal.
++ */
++static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 val)
++{
++ unsigned long flags;
++ int shift;
++ u32 data;
++
++ spin_lock_irqsave(&sh4_pci_lock, flags);
++ pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
++ data = pci_read_reg(SH4_PCIPDR);
++ spin_unlock_irqrestore(&sh4_pci_lock, flags);
++
++ switch (size) {
++ case 1:
++ shift = (where & 3) << 3;
++ data &= ~(0xff << shift);
++ data |= ((val & 0xff) << shift);
++ break;
++ case 2:
++ shift = (where & 2) << 3;
++ data &= ~(0xffff << shift);
++ data |= ((val & 0xffff) << shift);
++ break;
++ case 4:
++ data = val;
++ break;
++ default:
++ return PCIBIOS_FUNC_NOT_SUPPORTED;
++ }
++
++ pci_write_reg(data, SH4_PCIPDR);
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++struct pci_ops sh4_pci_ops = {
++ .read = sh4_pci_read,
++ .write = sh4_pci_write,
++};
++
++/*
++ * Not really related to pci_ops, but it's common and not worth shoving
++ * somewhere else for now..
++ */
++static unsigned int pci_probe = PCI_PROBE_CONF1;
++
++int __init sh4_pci_check_direct(void)
++{
++ /*
++ * Check if configuration works.
++ */
++ if (pci_probe & PCI_PROBE_CONF1) {
++ unsigned int tmp = pci_read_reg(SH4_PCIPAR);
++
++ pci_write_reg(P1SEG, SH4_PCIPAR);
++
++ if (pci_read_reg(SH4_PCIPAR) == P1SEG) {
++ pci_write_reg(tmp, SH4_PCIPAR);
++ printk(KERN_INFO "PCI: Using configuration type 1\n");
++ request_region(PCI_REG(SH4_PCIPAR), 8, "PCI conf1");
++
++ return 0;
++ }
++
++ pci_write_reg(tmp, SH4_PCIPAR);
++ }
++
++ pr_debug("PCI: pci_check_direct failed\n");
++ return -EINVAL;
++}
++
++/* Handle generic fixups */
++static void __init pci_fixup_ide_bases(struct pci_dev *d)
++{
++ int i;
++
++ /*
++ * PCI IDE controllers use non-standard I/O port decoding, respect it.
++ */
++ if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
++ return;
++ pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
++ for(i = 0; i < 4; i++) {
++ struct resource *r = &d->resource[i];
++
++ if ((r->start & ~0x80) == 0x374) {
++ r->start |= 2;
++ r->end = r->start;
++ }
++ }
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
++
++char * __init pcibios_setup(char *str)
++{
++ if (!strcmp(str, "off")) {
++ pci_probe = 0;
++ return NULL;
++ }
++
++ return str;
++}
+diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c
+index 3cbd14d..53dd893 100644
+--- a/arch/sh/drivers/pci/ops-snapgear.c
++++ b/arch/sh/drivers/pci/ops-snapgear.c
+@@ -2,7 +2,7 @@
+ * arch/sh/drivers/pci/ops-snapgear.c
+ *
+ * Author: David McCullough <davidm at snapgear.com>
+- *
++ *
+ * Ported to new API by Paul Mundt <lethal at linux-sh.org>
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+@@ -12,15 +12,11 @@
+ *
+ * PCI initialization for the SnapGear boards
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/init.h>
+-#include <linux/delay.h>
+ #include <linux/pci.h>
+-
+-#include <asm/io.h>
+-#include "pci-sh7751.h"
++#include "pci-sh4.h"
+
+ #define SNAPGEAR_PCI_IO 0x4000
+ #define SNAPGEAR_PCI_MEM 0xfd000000
+@@ -43,14 +39,12 @@ static struct resource sh7751_mem_resour
+ .flags = IORESOURCE_MEM,
+ };
+
+-extern struct pci_ops sh7751_pci_ops;
+-
+ struct pci_channel board_pci_channels[] = {
+- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
++ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { 0, }
+ };
+
+-static struct sh7751_pci_address_map sh7751_pci_map = {
++static struct sh4_pci_address_map sh7751_pci_map = {
+ .window0 = {
+ .base = SH7751_CS2_BASE_ADDR,
+ .size = SNAPGEAR_LSR0_SIZE,
+@@ -61,11 +55,11 @@ static struct sh7751_pci_address_map sh7
+ .size = SNAPGEAR_LSR1_SIZE,
+ },
+
+- .flags = SH7751_PCIC_NO_RESET,
++ .flags = SH4_PCIC_NO_RESET,
+ };
+
+ /*
+- * Initialize the SnapGear PCI interface
++ * Initialize the SnapGear PCI interface
+ * Setup hardware to be Central Funtion
+ * Copy the BSR regs to the PCI interface
+ * Setup PCI windows into local RAM
+@@ -75,7 +69,7 @@ int __init pcibios_init_platform(void)
+ return sh7751_pcic_init(&sh7751_pci_map);
+ }
+
+-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
++int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+ {
+ int irq = -1;
+
+@@ -98,4 +92,3 @@ void __init pcibios_fixup(void)
+ {
+ /* Nothing to fixup .. */
+ }
+-
+diff --git a/arch/sh/drivers/pci/ops-titan.c b/arch/sh/drivers/pci/ops-titan.c
+new file mode 100644
+index 0000000..cd56d53
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-titan.c
+@@ -0,0 +1,81 @@
++/*
++ * arch/sh/drivers/pci/ops-titan.c
++ *
++ * Ported to new API by Paul Mundt <lethal at linux-sh.org>
++ *
++ * Modified from ops-snapgear.c written by David McCullough
++ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ * PCI initialization for the Titan boards
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <asm/io.h>
++#include <asm/titan.h>
++#include "pci-sh4.h"
++
++int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
++{
++ int irq = -1;
++
++ switch (slot) {
++ case 0: irq = TITAN_IRQ_WAN; break; /* eth0 (WAN) */
++ case 1: irq = TITAN_IRQ_LAN; break; /* eth1 (LAN) */
++ case 2: irq = TITAN_IRQ_MPCIA; break; /* mPCI A */
++ case 3: irq = TITAN_IRQ_MPCIB; break; /* mPCI B */
++ case 4: irq = TITAN_IRQ_USB; break; /* USB */
++ default:
++ printk(KERN_INFO "PCI: Bad IRQ mapping "
++ "request for slot %d\n", slot);
++ return -1;
++ }
++
++ printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n",
++ slot, pin - 1 + 'A', irq);
++
++ return irq;
++}
++
++static struct resource sh7751_io_resource = {
++ .name = "SH7751_IO",
++ .start = SH7751_PCI_IO_BASE,
++ .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
++ .flags = IORESOURCE_IO
++};
++
++static struct resource sh7751_mem_resource = {
++ .name = "SH7751_mem",
++ .start = SH7751_PCI_MEMORY_BASE,
++ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
++ .flags = IORESOURCE_MEM
++};
++
++struct pci_channel board_pci_channels[] = {
++ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
++ { NULL, NULL, NULL, 0, 0 },
++};
++EXPORT_SYMBOL(board_pci_channels);
++
++static struct sh4_pci_address_map sh7751_pci_map = {
++ .window0 = {
++ .base = SH7751_CS2_BASE_ADDR,
++ .size = SH7751_MEM_REGION_SIZE*2, /* cs2 and cs3 */
++ },
++
++ .window1 = {
++ .base = SH7751_CS2_BASE_ADDR,
++ .size = SH7751_MEM_REGION_SIZE*2,
++ },
++
++ .flags = SH4_PCIC_NO_RESET,
++};
++
++int __init pcibios_init_platform(void)
++{
++ return sh7751_pcic_init(&sh7751_pci_map);
++}
+diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c
+index 4cef4d1..ecf1634 100644
+--- a/arch/sh/drivers/pci/pci-auto.c
++++ b/arch/sh/drivers/pci/pci-auto.c
+@@ -45,11 +45,11 @@
+ #include <linux/types.h>
+ #include <linux/pci.h>
+
+-#undef DEBUG
+-#ifdef DEBUG
++#define DEBUG
++#ifdef DEBUG
+ #define DBG(x...) printk(x)
+ #else
+-#define DBG(x...)
++#define DBG(x...)
+ #endif
+
+ /*
+@@ -102,7 +102,7 @@ static u32 pciauto_upper_iospc;
+ static u32 pciauto_lower_memspc;
+ static u32 pciauto_upper_memspc;
+
+-static void __init
++static void __init
+ pciauto_setup_bars(struct pci_channel *hose,
+ int top_bus,
+ int current_bus,
+@@ -116,7 +116,6 @@ pciauto_setup_bars(struct pci_channel *h
+ int found_mem64 = 0;
+
+ for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
+-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+ u32 bar_addr;
+
+ /* Read the old BAR value */
+@@ -125,7 +124,6 @@ pciauto_setup_bars(struct pci_channel *h
+ pci_devfn,
+ bar,
+ &bar_addr);
+-#endif
+
+ /* Tickle the BAR and get the response */
+ early_write_config_dword(hose, top_bus,
+@@ -140,8 +138,7 @@ pciauto_setup_bars(struct pci_channel *h
+ bar,
+ &bar_response);
+
+-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+- /*
++ /*
+ * Write the old BAR value back out, only update the BAR
+ * if we implicitly want resources to be updated, which
+ * is done by the generic code further down. -- PFM.
+@@ -151,7 +148,6 @@ pciauto_setup_bars(struct pci_channel *h
+ pci_devfn,
+ bar,
+ bar_addr);
+-#endif
+
+ /* If BAR is not implemented go to the next BAR */
+ if (!bar_response)
+@@ -177,7 +173,7 @@ retry:
+ PCI_BASE_ADDRESS_MEM_TYPE_64)
+ found_mem64 = 1;
+
+- addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
++ addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
+ upper_limit = &pciauto_upper_memspc;
+ lower_limit = &pciauto_lower_memspc;
+ DBG(" Mem");
+@@ -193,22 +189,22 @@ retry:
+ if ((bar_value + bar_size) > *upper_limit) {
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ if (io_resource_inuse->child) {
+- io_resource_inuse =
++ io_resource_inuse =
+ io_resource_inuse->child;
+- pciauto_lower_iospc =
++ pciauto_lower_iospc =
+ io_resource_inuse->start;
+- pciauto_upper_iospc =
++ pciauto_upper_iospc =
+ io_resource_inuse->end + 1;
+ goto retry;
+ }
+
+ } else {
+ if (mem_resource_inuse->child) {
+- mem_resource_inuse =
++ mem_resource_inuse =
+ mem_resource_inuse->child;
+- pciauto_lower_memspc =
++ pciauto_lower_memspc =
+ mem_resource_inuse->start;
+- pciauto_upper_memspc =
++ pciauto_upper_memspc =
+ mem_resource_inuse->end + 1;
+ goto retry;
+ }
+@@ -230,7 +226,7 @@ retry:
+ * 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) {
+ bar += 4;
+ early_write_config_dword(hose, top_bus,
+@@ -362,7 +358,6 @@ pciauto_postscan_setup_cardbus_bridge(st
+ {
+ u32 temp;
+
+-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+ /*
+ * [jsun] we always bump up baselines a little, so that if there
+ * nothing behind P2P bridge, we don't wind up overlapping IO/MEM
+@@ -370,7 +365,6 @@ pciauto_postscan_setup_cardbus_bridge(st
+ */
+ pciauto_lower_memspc += 1;
+ pciauto_lower_iospc += 1;
+-#endif
+
+ /*
+ * Configure subordinate bus number. The PCI subsystem
+@@ -396,11 +390,6 @@ pciauto_postscan_setup_cardbus_bridge(st
+ * configured by this routine to happily live behind a
+ * P2P bridge in a system.
+ */
+-#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
+- pciauto_lower_memspc += 0x00400000;
+- pciauto_lower_iospc += 0x00004000;
+-#endif
+-
+ /* Align memory and I/O to 4KB and 4 byte boundaries. */
+ pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
+ & ~(0x1000 - 1);
+@@ -433,12 +422,12 @@ pciauto_bus_scan(struct pci_channel *hos
+ int devfn_stop = 0xff;
+
+ sub_bus = current_bus;
+-
++
+ if (hose->first_devfn)
+ devfn_start = hose->first_devfn;
+ if (hose->last_devfn)
+ devfn_stop = hose->last_devfn;
+-
++
+ for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) {
+
+ if (PCI_FUNC(pci_devfn) && !found_multi)
+@@ -471,9 +460,6 @@ pciauto_bus_scan(struct pci_channel *hos
+ if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+ DBG(" Bridge: primary=%.2x, secondary=%.2x\n",
+ current_bus, sub_bus + 1);
+-#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
+- pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1);
+-#endif
+ pciauto_prescan_setup_bridge(hose, top_bus, current_bus,
+ pci_devfn, sub_bus);
+ DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
+@@ -490,10 +476,10 @@ pciauto_bus_scan(struct pci_channel *hos
+ DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
+ /* Place CardBus Socket/ExCA registers */
+ pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0);
+-
++
+ pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
+ current_bus, pci_devfn, sub_bus);
+-
++
+ DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
+ sub_bus + 1,
+ pciauto_lower_iospc, pciauto_lower_memspc);
+diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h
+new file mode 100644
+index 0000000..5a61d60
+--- /dev/null
++++ b/arch/sh/drivers/pci/pci-sh4.h
+@@ -0,0 +1,180 @@
++#ifndef __PCI_SH4_H
++#define __PCI_SH4_H
++
++#ifdef CONFIG_CPU_SUBTYPE_SH7780
++#include "pci-sh7780.h"
++#else
++#include "pci-sh7751.h"
++#endif
++
++#include <asm/io.h>
++
++/* startup values */
++#define PCI_PROBE_BIOS 1
++#define PCI_PROBE_CONF1 2
++#define PCI_PROBE_CONF2 4
++#define PCI_NO_SORT 0x100
++#define PCI_BIOS_SORT 0x200
++#define PCI_NO_CHECKS 0x400
++#define PCI_ASSIGN_ROMS 0x1000
++#define PCI_BIOS_IRQ_SCAN 0x2000
++
++#define SH4_PCICR 0x100 /* PCI Control Register */
++ #define SH4_PCICR_PREFIX 0xA5000000 /* CR prefix for write */
++ #define SH4_PCICR_FTO 0x00000400 /* TRDY/IRDY Enable */
++ #define SH4_PCICR_TRSB 0x00000200 /* Target Read Single */
++ #define SH4_PCICR_BSWP 0x00000100 /* Target Byte Swap */
++ #define SH4_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */
++ #define SH4_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */
++ #define SH4_PCICR_MD 0x00000030 /* MD9 and MD10 status */
++ #define SH4_PCICR_SERR 0x00000008 /* SERR output assert */
++ #define SH4_PCICR_INTA 0x00000004 /* INTA output assert */
++ #define SH4_PCICR_PRST 0x00000002 /* PCI Reset Assert */
++ #define SH4_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */
++#define SH4_PCILSR0 0x104 /* PCI Local Space Register0 */
++#define SH4_PCILSR1 0x108 /* PCI Local Space Register1 */
++#define SH4_PCILAR0 0x10C /* PCI Local Addr Register1 */
++#define SH4_PCILAR1 0x110 /* PCI Local Addr Register1 */
++#define SH4_PCIINT 0x114 /* PCI Interrupt Register */
++ #define SH4_PCIINT_MLCK 0x00008000 /* Master Lock Error */
++ #define SH4_PCIINT_TABT 0x00004000 /* Target Abort Error */
++ #define SH4_PCIINT_TRET 0x00000200 /* Target Retry Error */
++ #define SH4_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */
++ #define SH4_PCIINT_PRTY 0x00000080 /* Address Parity Error */
++ #define SH4_PCIINT_SERR 0x00000040 /* SERR Detection Error */
++ #define SH4_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */
++ #define SH4_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Err Det. */
++ #define SH4_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */
++ #define SH4_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */
++ #define SH4_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */
++ #define SH4_PCIINT_MRPD 0x00000001 /* Master Read PERR Detect */
++#define SH4_PCIINTM 0x118 /* PCI Interrupt Mask */
++#define SH4_PCIALR 0x11C /* Error Address Register */
++#define SH4_PCICLR 0x120 /* Error Command/Data */
++ #define SH4_PCICLR_MPIO 0x80000000
++ #define SH4_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */
++ #define SH4_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */
++ #define SH4_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */
++ #define SH4_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */
++ #define SH4_PCICLR_TGT 0x04000000 /* Target Transfer Error */
++ #define SH4_PCICLR_CMDL 0x0000000F /* PCI Command at Error */
++#define SH4_PCIAINT 0x130 /* Arbiter Interrupt Register */
++ #define SH4_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */
++ #define SH4_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */
++ #define SH4_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */
++ #define SH4_PCIAINT_TABT 0x00000008 /* Target Abort */
++ #define SH4_PCIAINT_MABT 0x00000004 /* Master Abort */
++ #define SH4_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */
++ #define SH4_PCIAINT_WDPE 0x00000001 /* Write Data Parity Error */
++#define SH4_PCIAINTM 0x134 /* Arbiter Int. Mask Register */
++#define SH4_PCIBMLR 0x138 /* Error Bus Master Register */
++ #define SH4_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */
++ #define SH4_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */
++ #define SH4_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */
++ #define SH4_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */
++ #define SH4_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */
++#define SH4_PCIDMABT 0x140 /* DMA Transfer Arb. Register */
++ #define SH4_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */
++#define SH4_PCIDPA0 0x180 /* DMA0 Transfer Addr. */
++#define SH4_PCIDLA0 0x184 /* DMA0 Local Addr. */
++#define SH4_PCIDTC0 0x188 /* DMA0 Transfer Cnt. */
++#define SH4_PCIDCR0 0x18C /* DMA0 Control Register */
++ #define SH4_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */
++ #define SH4_PCIDCR_MAST 0x00000100 /* DMA Termination Type */
++ #define SH4_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/
++ #define SH4_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */
++ #define SH4_PCIDCR_LHLD 0x00000020 /* Local Address Control */
++ #define SH4_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/
++ #define SH4_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */
++ #define SH4_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */
++ #define SH4_PCIDCR_STOP 0x00000002 /* Force DMA Stop */
++ #define SH4_PCIDCR_STRT 0x00000001 /* DMA Start */
++#define SH4_PCIDPA1 0x190 /* DMA1 Transfer Addr. */
++#define SH4_PCIDLA1 0x194 /* DMA1 Local Addr. */
++#define SH4_PCIDTC1 0x198 /* DMA1 Transfer Cnt. */
++#define SH4_PCIDCR1 0x19C /* DMA1 Control Register */
++#define SH4_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. */
++#define SH4_PCIDLA2 0x1A4 /* DMA2 Local Addr. */
++#define SH4_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. */
++#define SH4_PCIDCR2 0x1AC /* DMA2 Control Register */
++#define SH4_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. */
++#define SH4_PCIDLA3 0x1B4 /* DMA3 Local Addr. */
++#define SH4_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. */
++#define SH4_PCIDCR3 0x1BC /* DMA3 Control Register */
++#define SH4_PCIPAR 0x1C0 /* PIO Address Register */
++ #define SH4_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */
++ #define SH4_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */
++ #define SH4_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */
++ #define SH4_PCIPAR_REGAD 0x000000FC /* Register Address Number */
++#define SH4_PCIMBR 0x1C4 /* Memory Base Address */
++ #define SH4_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */
++ #define SH4_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */
++#define SH4_PCIIOBR 0x1C8 /* I/O Base Address Register */
++ #define SH4_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */
++ #define SH4_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */
++#define SH4_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
++ #define SH4_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */
++ #define SH4_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */
++#define SH4_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
++#define SH4_PCICLKR 0x1D4 /* Clock Ctrl. Register */
++ #define SH4_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */
++ #define SH4_PCICLKR_BCSTP 0x00000001 /* BCLK Clock Stop */
++/* For definitions of BCR, MCR see ... */
++#define SH4_PCIBCR1 0x1E0 /* Memory BCR1 Register */
++ #define SH4_PCIMBR0 SH4_PCIBCR1
++#define SH4_PCIBCR2 0x1E4 /* Memory BCR2 Register */
++ #define SH4_PCIMBMR0 SH4_PCIBCR2
++#define SH4_PCIWCR1 0x1E8 /* Wait Control 1 Register */
++#define SH4_PCIWCR2 0x1EC /* Wait Control 2 Register */
++#define SH4_PCIWCR3 0x1F0 /* Wait Control 3 Register */
++ #define SH4_PCIMBR2 SH4_PCIWCR3
++#define SH4_PCIMCR 0x1F4 /* Memory Control Register */
++#define SH4_PCIBCR3 0x1f8 /* Memory BCR3 Register */
++#define SH4_PCIPCTR 0x200 /* Port Control Register */
++ #define SH4_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */
++ #define SH4_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */
++ #define SH4_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */
++ #define SH4_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */
++ #define SH4_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */
++ #define SH4_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */
++ #define SH4_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */
++ #define SH4_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */
++ #define SH4_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */
++#define SH4_PCIPDTR 0x204 /* Port Data Register */
++ #define SH4_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */
++ #define SH4_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */
++ #define SH4_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */
++ #define SH4_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */
++ #define SH4_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */
++ #define SH4_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */
++#define SH4_PCIPDR 0x220 /* Port IO Data Register */
++
++/* Flags */
++#define SH4_PCIC_NO_RESET 0x0001
++
++/* arch/sh/kernel/drivers/pci/ops-sh4.c */
++extern struct pci_ops sh4_pci_ops;
++int sh4_pci_check_direct(void);
++int pci_fixup_pcic(void);
++
++struct sh4_pci_address_space {
++ unsigned long base;
++ unsigned long size;
++};
++
++struct sh4_pci_address_map {
++ struct sh4_pci_address_space window0;
++ struct sh4_pci_address_space window1;
++ unsigned long flags;
++};
++
++static inline void pci_write_reg(unsigned long val, unsigned long reg)
++{
++ outl(val, PCI_REG(reg));
++}
++
++static inline unsigned long pci_read_reg(unsigned long reg)
++{
++ return inl(PCI_REG(reg));
++}
++#endif /* __PCI_SH4_H */
+diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
+index 682f3da..85e1ee2 100644
+--- a/arch/sh/drivers/pci/pci-sh7751.c
++++ b/arch/sh/drivers/pci/pci-sh7751.c
+@@ -15,180 +15,14 @@
+
+ #undef DEBUG
+
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/pci.h>
+-#include <linux/sched.h>
+-#include <linux/ioport.h>
++#include <linux/types.h>
+ #include <linux/errno.h>
+-#include <linux/irq.h>
+ #include <linux/delay.h>
+-
+-#include <asm/machvec.h>
++#include "pci-sh4.h"
++#include <asm/addrspace.h>
+ #include <asm/io.h>
+-#include "pci-sh7751.h"
+-
+-static unsigned int pci_probe = PCI_PROBE_CONF1;
+-extern int pci_fixup_pcic(void);
+-
+-void pcibios_fixup_irqs(void) __attribute__ ((weak));
+-
+-/*
+- * Direct access to PCI hardware...
+- */
+-
+-#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
+-
+-/*
+- * Functions for accessing PCI configuration space with type 1 accesses
+- */
+-static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn,
+- int where, int size, u32 *val)
+-{
+- unsigned long flags;
+- u32 data;
+-
+- /*
+- * PCIPDR may only be accessed as 32 bit words,
+- * so we must do byte alignment by hand
+- */
+- local_irq_save(flags);
+- outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
+- data = inl(PCI_REG(SH7751_PCIPDR));
+- local_irq_restore(flags);
+-
+- switch (size) {
+- case 1:
+- *val = (data >> ((where & 3) << 3)) & 0xff;
+- break;
+- case 2:
+- *val = (data >> ((where & 2) << 3)) & 0xffff;
+- break;
+- case 4:
+- *val = data;
+- break;
+- default:
+- return PCIBIOS_FUNC_NOT_SUPPORTED;
+- }
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-/*
+- * Since SH7751 only does 32bit access we'll have to do a read,
+- * mask,write operation.
+- * We'll allow an odd byte offset, though it should be illegal.
+- */
+-static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn,
+- int where, int size, u32 val)
+-{
+- unsigned long flags;
+- int shift;
+- u32 data;
+-
+- local_irq_save(flags);
+- outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
+- data = inl(PCI_REG(SH7751_PCIPDR));
+- local_irq_restore(flags);
+-
+- switch (size) {
+- case 1:
+- shift = (where & 3) << 3;
+- data &= ~(0xff << shift);
+- data |= ((val & 0xff) << shift);
+- break;
+- case 2:
+- shift = (where & 2) << 3;
+- data &= ~(0xffff << shift);
+- data |= ((val & 0xffff) << shift);
+- break;
+- case 4:
+- data = val;
+- break;
+- default:
+- return PCIBIOS_FUNC_NOT_SUPPORTED;
+- }
+-
+- outl(data, PCI_REG(SH7751_PCIPDR));
+-
+- return PCIBIOS_SUCCESSFUL;
+-}
+-
+-#undef CONFIG_CMD
+-
+-struct pci_ops sh7751_pci_ops = {
+- .read = sh7751_pci_read,
+- .write = sh7751_pci_write,
+-};
+-
+-static int __init pci_check_direct(void)
+-{
+- unsigned int tmp, id;
+-
+- /* check for SH7751/SH7751R hardware */
+- id = inl(SH7751_PCIREG_BASE+SH7751_PCICONF0);
+- if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
+- id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
+- pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
+- return -ENODEV;
+- }
+-
+- /*
+- * Check if configuration works.
+- */
+- if (pci_probe & PCI_PROBE_CONF1) {
+- tmp = inl (PCI_REG(SH7751_PCIPAR));
+- outl (0x80000000, PCI_REG(SH7751_PCIPAR));
+- if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
+- outl (tmp, PCI_REG(SH7751_PCIPAR));
+- printk(KERN_INFO "PCI: Using configuration type 1\n");
+- request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
+- return 0;
+- }
+- outl (tmp, PCI_REG(SH7751_PCIPAR));
+- }
+-
+- pr_debug("PCI: pci_check_direct failed\n");
+- return -EINVAL;
+-}
+-
+-/***************************************************************************************/
+-
+-/*
+- * Handle bus scanning and fixups ....
+- */
+-
+-static void __init pci_fixup_ide_bases(struct pci_dev *d)
+-{
+- int i;
+-
+- /*
+- * PCI IDE controllers use non-standard I/O port decoding, respect it.
+- */
+- if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+- return;
+- pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
+- for(i=0; i<4; i++) {
+- struct resource *r = &d->resource[i];
+- if ((r->start & ~0x80) == 0x374) {
+- r->start |= 2;
+- r->end = r->start;
+- }
+- }
+-}
+-
+-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+-
+-/*
+- * Called after each bus is probed, but before its children
+- * are examined.
+- */
+-
+-void __init pcibios_fixup_bus(struct pci_bus *b)
+-{
+- pci_read_bridge_bases(b);
+-}
+
+ /*
+ * Initialization. Try all known PCI access methods. Note that we support
+@@ -196,25 +30,29 @@ void __init pcibios_fixup_bus(struct pci
+ * to access config space.
+ *
+ * Note that the platform specific initialization (BSC registers, and memory
+- * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
+- * exitst and via the platform defined function pcibios_init_platform().
+- * See pci_bigsur.c for implementation;
+- *
+- * The BIOS version of the pci functions is not yet implemented but it is left
+- * in for completeness. Currently an error will be genereated at compile time.
++ * space mapping) will be called via the platform defined function
++ * pcibios_init_platform().
+ */
+-
+ static int __init sh7751_pci_init(void)
+ {
++ unsigned int id;
+ int ret;
+
+ pr_debug("PCI: Starting intialization.\n");
+- if ((ret = pci_check_direct()) != 0)
++
++ /* check for SH7751/SH7751R hardware */
++ id = pci_read_reg(SH7751_PCICONF0);
++ if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
++ id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
++ pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
++ return -ENODEV;
++ }
++
++ if ((ret = sh4_pci_check_direct()) != 0)
+ return ret;
+
+ return pcibios_init_platform();
+ }
+-
+ subsys_initcall(sh7751_pci_init);
+
+ static int __init __area_sdram_check(unsigned int area)
+@@ -223,26 +61,26 @@ static int __init __area_sdram_check(uns
+
+ word = inl(SH7751_BCR1);
+ /* check BCR for SDRAM in area */
+- if(((word >> area) & 1) == 0) {
++ if (((word >> area) & 1) == 0) {
+ printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n",
+ area, word);
+ return 0;
+ }
+- outl(word, PCI_REG(SH7751_PCIBCR1));
++ pci_write_reg(word, SH4_PCIBCR1);
+
+ word = (u16)inw(SH7751_BCR2);
+ /* check BCR2 for 32bit SDRAM interface*/
+- if(((word >> (area << 1)) & 0x3) != 0x3) {
++ if (((word >> (area << 1)) & 0x3) != 0x3) {
+ printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n",
+ area, word);
+ return 0;
+ }
+- outl(word, PCI_REG(SH7751_PCIBCR2));
++ pci_write_reg(word, SH4_PCIBCR2);
+
+ return 1;
+ }
+
+-int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
++int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
+ {
+ u32 reg;
+ u32 word;
+@@ -251,39 +89,39 @@ int __init sh7751_pcic_init(struct sh775
+ reg = inl(SH7751_BCR1);
+ reg |= 0x80000;
+ outl(reg, SH7751_BCR1);
+-
++
+ /* Turn the clocks back on (not done in reset)*/
+- outl(0, PCI_REG(SH7751_PCICLKR));
++ pci_write_reg(0, SH4_PCICLKR);
+ /* Clear Powerdown IRQ's (not done in reset) */
+- word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0;
+- outl(word, PCI_REG(SH7751_PCIPINT));
++ word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0;
++ pci_write_reg(word, SH4_PCIPINT);
+
+ /*
+ * This code is unused for some boards as it is done in the
+ * bootloader and doing it here means the MAC addresses loaded
+ * by the bootloader get lost.
+ */
+- if (!(map->flags & SH7751_PCIC_NO_RESET)) {
++ if (!(map->flags & SH4_PCIC_NO_RESET)) {
+ /* toggle PCI reset pin */
+- word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
+- outl(word,PCI_REG(SH7751_PCICR));
++ word = SH4_PCICR_PREFIX | SH4_PCICR_PRST;
++ pci_write_reg(word, SH4_PCICR);
+ /* Wait for a long time... not 1 sec. but long enough */
+ mdelay(100);
+- word = SH7751_PCICR_PREFIX;
+- outl(word,PCI_REG(SH7751_PCICR));
++ word = SH4_PCICR_PREFIX;
++ pci_write_reg(word, SH4_PCICR);
+ }
+-
++
+ /* set the command/status bits to:
+ * Wait Cycle Control + Parity Enable + Bus Master +
+ * Mem space enable
+ */
+ word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
+ SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
+- outl(word, PCI_REG(SH7751_PCICONF1));
++ pci_write_reg(word, SH7751_PCICONF1);
+
+ /* define this host as the host bridge */
+- word = SH7751_PCI_HOST_BRIDGE << 24;
+- outl(word, PCI_REG(SH7751_PCICONF2));
++ word = PCI_BASE_CLASS_BRIDGE << 24;
++ pci_write_reg(word, SH7751_PCICONF2);
+
+ /* Set IO and Mem windows to local address
+ * Make PCI and local address the same for easy 1 to 1 mapping
+@@ -291,46 +129,49 @@ int __init sh7751_pcic_init(struct sh775
+ * Window1 = map->window1.size @ cached area base = SDRAM
+ */
+ word = map->window0.size - 1;
+- outl(word, PCI_REG(SH7751_PCILSR0));
++ pci_write_reg(word, SH4_PCILSR0);
+ word = map->window1.size - 1;
+- outl(word, PCI_REG(SH7751_PCILSR1));
++ pci_write_reg(word, SH4_PCILSR1);
+ /* Set the values on window 0 PCI config registers */
+ word = P2SEGADDR(map->window0.base);
+- outl(word, PCI_REG(SH7751_PCILAR0));
+- outl(word, PCI_REG(SH7751_PCICONF5));
++ pci_write_reg(word, SH4_PCILAR0);
++ pci_write_reg(word, SH7751_PCICONF5);
+ /* Set the values on window 1 PCI config registers */
+ word = PHYSADDR(map->window1.base);
+- outl(word, PCI_REG(SH7751_PCILAR1));
+- outl(word, PCI_REG(SH7751_PCICONF6));
++ pci_write_reg(word, SH4_PCILAR1);
++ pci_write_reg(word, SH7751_PCICONF6);
+
+- /* Set the local 16MB PCI memory space window to
++ /* Set the local 16MB PCI memory space window to
+ * the lowest PCI mapped address
+ */
+- word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK;
+- PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word);
+- outl(word , PCI_REG(SH7751_PCIMBR));
++ word = PCIBIOS_MIN_MEM & SH4_PCIMBR_MASK;
++ pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word);
++ pci_write_reg(word , SH4_PCIMBR);
+
+ /* Map IO space into PCI IO window
+ * The IO window is 64K-PCIBIOS_MIN_IO in size
+- * IO addresses will be translated to the
++ * IO addresses will be translated to the
+ * PCI IO window base address
+ */
+- PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO,
+- (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO);
++ pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n",
++ PCIBIOS_MIN_IO, (64 << 10),
++ SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO);
+
+- /*
++ /*
+ * XXX: For now, leave this board-specific. In the event we have other
+ * boards that need to do similar work, this can be wrapped.
+ */
+ #ifdef CONFIG_SH_BIGSUR
+- bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
++ bigsur_port_map(PCIBIOS_MIN_IO, (64 << 10),
++ SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO, 0);
+ #endif
+
+- /* Make sure the MSB's of IO window are set to access PCI space correctly */
+- word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK;
+- PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word);
+- outl(word, PCI_REG(SH7751_PCIIOBR));
+-
++ /* Make sure the MSB's of IO window are set to access PCI space
++ * correctly */
++ word = PCIBIOS_MIN_IO & SH4_PCIIOBR_MASK;
++ pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word);
++ pci_write_reg(word, SH4_PCIIOBR);
++
+ /* Set PCI WCRx, BCRx's, copy from BSC locations */
+
+ /* check BCR for SDRAM in specified area */
+@@ -349,13 +190,13 @@ int __init sh7751_pcic_init(struct sh775
+
+ /* configure the wait control registers */
+ word = inl(SH7751_WCR1);
+- outl(word, PCI_REG(SH7751_PCIWCR1));
++ pci_write_reg(word, SH4_PCIWCR1);
+ word = inl(SH7751_WCR2);
+- outl(word, PCI_REG(SH7751_PCIWCR2));
++ pci_write_reg(word, SH4_PCIWCR2);
+ word = inl(SH7751_WCR3);
+- outl(word, PCI_REG(SH7751_PCIWCR3));
++ pci_write_reg(word, SH4_PCIWCR3);
+ word = inl(SH7751_MCR);
+- outl(word, PCI_REG(SH7751_PCIMCR));
++ pci_write_reg(word, SH4_PCIMCR);
+
+ /* NOTE: I'm ignoring the PCI error IRQs for now..
+ * TODO: add support for the internal error interrupts and
+@@ -368,49 +209,8 @@ int __init sh7751_pcic_init(struct sh775
+
+ /* SH7751 init done, set central function init complete */
+ /* use round robin mode to stop a device starving/overruning */
+- word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM;
+- outl(word,PCI_REG(SH7751_PCICR));
++ word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM;
++ pci_write_reg(word, SH4_PCICR);
+
+ return 1;
+ }
+-
+-char * __init pcibios_setup(char *str)
+-{
+- if (!strcmp(str, "off")) {
+- pci_probe = 0;
+- return NULL;
+- }
+-
+- return str;
+-}
+-
+-/*
+- * IRQ functions
+- */
+-static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin)
+-{
+- /* no swizzling */
+- return PCI_SLOT(dev->devfn);
+-}
+-
+-static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+- int irq = -1;
+-
+- /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+- irq = pcibios_map_platform_irq(slot,pin);
+- if( irq < 0 ) {
+- pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
+- return irq;
+- }
+-
+- pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
+-
+- return irq;
+-}
+-
+-void __init pcibios_fixup_irqs(void)
+-{
+- pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq);
+-}
+-
+diff --git a/arch/sh/drivers/pci/pci-sh7751.h b/arch/sh/drivers/pci/pci-sh7751.h
+index 1fee5ca..68e3cb5 100644
+--- a/arch/sh/drivers/pci/pci-sh7751.h
++++ b/arch/sh/drivers/pci/pci-sh7751.h
+@@ -3,7 +3,7 @@
+ *
+ * Dustin McIntire (dustin at sensoria.com) (c) 2001
+ * Paul Mundt (lethal at linux-sh.org) (c) 2003
+- *
++ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+@@ -12,28 +12,6 @@
+ #ifndef _PCI_SH7751_H_
+ #define _PCI_SH7751_H_
+
+-#include <linux/pci.h>
+-
+-/* set debug level 4=verbose...1=terse */
+-//#define DEBUG_PCI 3
+-#undef DEBUG_PCI
+-
+-#ifdef DEBUG_PCI
+-#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); }
+-#else
+-#define PCIDBG(n, x...)
+-#endif
+-
+-/* startup values */
+-#define PCI_PROBE_BIOS 1
+-#define PCI_PROBE_CONF1 2
+-#define PCI_PROBE_CONF2 4
+-#define PCI_NO_SORT 0x100
+-#define PCI_BIOS_SORT 0x200
+-#define PCI_NO_CHECKS 0x400
+-#define PCI_ASSIGN_ROMS 0x1000
+-#define PCI_BIOS_IRQ_SCAN 0x2000
+-
+ /* Platform Specific Values */
+ #define SH7751_VENDOR_ID 0x1054
+ #define SH7751_DEVICE_ID 0x3505
+@@ -128,131 +106,6 @@
+ #define SH7751_PCICONF17_PMEN 0x00010000 /* PME Enable */
+ #define SH7751_PCICONF17_PWST 0x00000003 /* Power State */
+ /* SH7715 Internal PCI Registers */
+-#define SH7751_PCICR 0x100 /* PCI Control Register */
+- #define SH7751_PCICR_PREFIX 0xA5000000 /* CR prefix for write */
+- #define SH7751_PCICR_TRSB 0x00000200 /* Target Read Single */
+- #define SH7751_PCICR_BSWP 0x00000100 /* Target Byte Swap */
+- #define SH7751_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */
+- #define SH7751_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */
+- #define SH7751_PCICR_MD 0x00000030 /* MD9 and MD10 status */
+- #define SH7751_PCICR_SERR 0x00000008 /* SERR output assert */
+- #define SH7751_PCICR_INTA 0x00000004 /* INTA output assert */
+- #define SH7751_PCICR_PRST 0x00000002 /* PCI Reset Assert */
+- #define SH7751_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */
+-#define SH7751_PCILSR0 0x104 /* PCI Local Space Register0 */
+-#define SH7751_PCILSR1 0x108 /* PCI Local Space Register1 */
+-#define SH7751_PCILAR0 0x10C /* PCI Local Address Register1 */
+-#define SH7751_PCILAR1 0x110 /* PCI Local Address Register1 */
+-#define SH7751_PCIINT 0x114 /* PCI Interrupt Register */
+- #define SH7751_PCIINT_MLCK 0x00008000 /* Master Lock Error */
+- #define SH7751_PCIINT_TABT 0x00004000 /* Target Abort Error */
+- #define SH7751_PCIINT_TRET 0x00000200 /* Target Retry Error */
+- #define SH7751_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */
+- #define SH7751_PCIINT_PRTY 0x00000080 /* Address Parity Error */
+- #define SH7751_PCIINT_SERR 0x00000040 /* SERR Detection Error */
+- #define SH7751_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */
+- #define SH7751_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Error Det. */
+- #define SH7751_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */
+- #define SH7751_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */
+- #define SH7751_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */
+- #define SH7751_PCIINT_MRPD 0x00000002 /* Master Read PERR Detect */
+-#define SH7751_PCIINTM 0x118 /* PCI Interrupt Mask Register */
+-#define SH7751_PCIALR 0x11C /* Error Address Register */
+-#define SH7751_PCICLR 0x120 /* Error Command/Data Register */
+- #define SH7751_PCICLR_MPIO 0x80000000 /* Error Command/Data Register */
+- #define SH7751_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */
+- #define SH7751_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */
+- #define SH7751_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */
+- #define SH7751_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */
+- #define SH7751_PCICLR_TGT 0x04000000 /* Target Transfer Error */
+- #define SH7751_PCICLR_CMDL 0x0000000F /* PCI Command at Error */
+-#define SH7751_PCIAINT 0x130 /* Arbiter Interrupt Register */
+- #define SH7751_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */
+- #define SH7751_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */
+- #define SH7751_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */
+- #define SH7751_PCIAINT_TABT 0x00000008 /* Target Abort */
+- #define SH7751_PCIAINT_MABT 0x00000004 /* Master Abort */
+- #define SH7751_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */
+- #define SH7751_PCIAINT_WDPE 0x00000002 /* Write Data Parity Error */
+-#define SH7751_PCIAINTM 0x134 /* Arbiter Int. Mask Register */
+-#define SH7751_PCIBMLR 0x138 /* Error Bus Master Register */
+- #define SH7751_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */
+- #define SH7751_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */
+- #define SH7751_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */
+- #define SH7751_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */
+- #define SH7751_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */
+-#define SH7751_PCIDMABT 0x140 /* DMA Transfer Arb. Register */
+- #define SH7751_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */
+-#define SH7751_PCIDPA0 0x180 /* DMA0 Transfer Addr. Register */
+-#define SH7751_PCIDLA0 0x184 /* DMA0 Local Addr. Register */
+-#define SH7751_PCIDTC0 0x188 /* DMA0 Transfer Cnt. Register */
+-#define SH7751_PCIDCR0 0x18C /* DMA0 Control Register */
+- #define SH7751_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */
+- #define SH7751_PCIDCR_MAST 0x00000100 /* DMA Termination Type */
+- #define SH7751_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/
+- #define SH7751_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */
+- #define SH7751_PCIDCR_LHLD 0x00000020 /* Local Address Control */
+- #define SH7751_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/
+- #define SH7751_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */
+- #define SH7751_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */
+- #define SH7751_PCIDCR_STOP 0x00000002 /* Force DMA Stop */
+- #define SH7751_PCIDCR_STRT 0x00000001 /* DMA Start */
+-#define SH7751_PCIDPA1 0x190 /* DMA1 Transfer Addr. Register */
+-#define SH7751_PCIDLA1 0x194 /* DMA1 Local Addr. Register */
+-#define SH7751_PCIDTC1 0x198 /* DMA1 Transfer Cnt. Register */
+-#define SH7751_PCIDCR1 0x19C /* DMA1 Control Register */
+-#define SH7751_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. Register */
+-#define SH7751_PCIDLA2 0x1A4 /* DMA2 Local Addr. Register */
+-#define SH7751_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. Register */
+-#define SH7751_PCIDCR2 0x1AC /* DMA2 Control Register */
+-#define SH7751_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. Register */
+-#define SH7751_PCIDLA3 0x1B4 /* DMA3 Local Addr. Register */
+-#define SH7751_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. Register */
+-#define SH7751_PCIDCR3 0x1BC /* DMA3 Control Register */
+-#define SH7751_PCIPAR 0x1C0 /* PIO Address Register */
+- #define SH7751_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */
+- #define SH7751_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */
+- #define SH7751_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */
+- #define SH7751_PCIPAR_REGAD 0x000000FC /* Register Address Number */
+-#define SH7751_PCIMBR 0x1C4 /* Memory Base Address Register */
+- #define SH7751_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */
+- #define SH7751_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */
+-#define SH7751_PCIIOBR 0x1C8 /* I/O Base Address Register */
+- #define SH7751_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */
+- #define SH7751_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */
+-#define SH7751_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
+- #define SH7751_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */
+- #define SH7751_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */
+-#define SH7751_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
+-#define SH7751_PCICLKR 0x1D4 /* Clock Ctrl. Register */
+- #define SH7751_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */
+- #define SH7751_PCICLKR_BCSTP 0x00000002 /* BCLK Clock Stop */
+-/* For definitions of BCR, MCR see ... */
+-#define SH7751_PCIBCR1 0x1E0 /* Memory BCR1 Register */
+-#define SH7751_PCIBCR2 0x1E4 /* Memory BCR2 Register */
+-#define SH7751_PCIWCR1 0x1E8 /* Wait Control 1 Register */
+-#define SH7751_PCIWCR2 0x1EC /* Wait Control 2 Register */
+-#define SH7751_PCIWCR3 0x1F0 /* Wait Control 3 Register */
+-#define SH7751_PCIMCR 0x1F4 /* Memory Control Register */
+-#define SH7751_PCIBCR3 0x1f8 /* Memory BCR3 Register */
+-#define SH7751_PCIPCTR 0x200 /* Port Control Register */
+- #define SH7751_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */
+- #define SH7751_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */
+- #define SH7751_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */
+- #define SH7751_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */
+- #define SH7751_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */
+- #define SH7751_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */
+- #define SH7751_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */
+- #define SH7751_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */
+- #define SH7751_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */
+-#define SH7751_PCIPDTR 0x204 /* Port Data Register */
+- #define SH7751_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */
+- #define SH7751_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */
+- #define SH7751_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */
+- #define SH7751_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */
+- #define SH7751_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */
+- #define SH7751_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */
+-#define SH7751_PCIPDR 0x220 /* Port IO Data Register */
+
+ /* Memory Control Registers */
+ #define SH7751_BCR1 0xFF800000 /* Memory BCR1 Register */
+@@ -274,30 +127,9 @@
+ #define SH7751_CS5_BASE_ADDR (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+ #define SH7751_CS6_BASE_ADDR (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+
+-/* General PCI values */
+-#define SH7751_PCI_HOST_BRIDGE 0x6
+-
+-/* Flags */
+-#define SH7751_PCIC_NO_RESET 0x0001
+-
+-/* External functions defined per platform i.e. Big Sur, SE... (these could be routed
+- * through the machine vectors... */
+-extern int pcibios_init_platform(void);
+-extern int pcibios_map_platform_irq(u8 slot, u8 pin);
+-
+-struct sh7751_pci_address_space {
+- unsigned long base;
+- unsigned long size;
+-};
+-
+-struct sh7751_pci_address_map {
+- struct sh7751_pci_address_space window0;
+- struct sh7751_pci_address_space window1;
+- unsigned long flags;
+-};
++struct sh4_pci_address_map;
+
+ /* arch/sh/drivers/pci/pci-sh7751.c */
+-extern int sh7751_pcic_init(struct sh7751_pci_address_map *map);
++int sh7751_pcic_init(struct sh4_pci_address_map *map);
+
+ #endif /* _PCI_SH7751_H_ */
+-
+diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
+new file mode 100644
+index 0000000..d6e6352
+--- /dev/null
++++ b/arch/sh/drivers/pci/pci-sh7780.c
+@@ -0,0 +1,137 @@
++/*
++ * Low-Level PCI Support for the SH7780
++ *
++ * Dustin McIntire (dustin at sensoria.com)
++ * Derived from arch/i386/kernel/pci-*.c which bore the message:
++ * (c) 1999--2000 Martin Mares <mj at ucw.cz>
++ *
++ * Ported to the new API by Paul Mundt <lethal at linux-sh.org>
++ * With cleanup by Paul van Gool <pvangool at mimotech.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ */
++#undef DEBUG
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include "pci-sh4.h"
++
++/*
++ * Initialization. Try all known PCI access methods. Note that we support
++ * using both PCI BIOS and direct access: in such cases, we use I/O ports
++ * to access config space.
++ *
++ * Note that the platform specific initialization (BSC registers, and memory
++ * space mapping) will be called via the platform defined function
++ * pcibios_init_platform().
++ */
++static int __init sh7780_pci_init(void)
++{
++ unsigned int id;
++ int ret;
++
++ pr_debug("PCI: Starting intialization.\n");
++
++ outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */
++
++ /* check for SH7780/SH7780R hardware */
++ id = pci_read_reg(SH7780_PCIVID);
++ if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) &&
++ (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) {
++ printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id);
++ return -ENODEV;
++ }
++
++ /* Setup the INTC */
++ ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */
++ ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */
++ ctrl_outl(0x40000000, INTC_INTMSK1); /* disable IRL4-7 Interrupt */
++ ctrl_outl(0x0000fffe, INTC_INTMSK2); /* disable IRL4-7 Interrupt */
++ ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */
++ ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */
++
++ if ((ret = sh4_pci_check_direct()) != 0)
++ return ret;
++
++ return pcibios_init_platform();
++}
++core_initcall(sh7780_pci_init);
++
++int __init sh7780_pcic_init(struct sh4_pci_address_map *map)
++{
++ u32 word;
++
++ /*
++ * This code is unused for some boards as it is done in the
++ * bootloader and doing it here means the MAC addresses loaded
++ * by the bootloader get lost.
++ */
++ if (!(map->flags & SH4_PCIC_NO_RESET)) {
++ /* toggle PCI reset pin */
++ word = SH4_PCICR_PREFIX | SH4_PCICR_PRST;
++ pci_write_reg(word, SH4_PCICR);
++ /* Wait for a long time... not 1 sec. but long enough */
++ mdelay(100);
++ word = SH4_PCICR_PREFIX;
++ pci_write_reg(word, SH4_PCICR);
++ }
++
++ /* set the command/status bits to:
++ * Wait Cycle Control + Parity Enable + Bus Master +
++ * Mem space enable
++ */
++ pci_write_reg(0x00000046, SH7780_PCICMD);
++
++ /* define this host as the host bridge */
++ word = PCI_BASE_CLASS_BRIDGE << 24;
++ pci_write_reg(word, SH7780_PCIRID);
++
++ /* Set IO and Mem windows to local address
++ * Make PCI and local address the same for easy 1 to 1 mapping
++ * Window0 = map->window0.size @ non-cached area base = SDRAM
++ * Window1 = map->window1.size @ cached area base = SDRAM
++ */
++ word = ((map->window0.size - 1) & 0x1ff00001) | 0x01;
++ pci_write_reg(0x07f00001, SH4_PCILSR0);
++ word = ((map->window1.size - 1) & 0x1ff00001) | 0x01;
++ pci_write_reg(0x00000001, SH4_PCILSR1);
++ /* Set the values on window 0 PCI config registers */
++ word = P2SEGADDR(map->window0.base);
++ pci_write_reg(0xa8000000, SH4_PCILAR0);
++ pci_write_reg(0x08000000, SH7780_PCIMBAR0);
++ /* Set the values on window 1 PCI config registers */
++ word = P2SEGADDR(map->window1.base);
++ pci_write_reg(0x00000000, SH4_PCILAR1);
++ pci_write_reg(0x00000000, SH7780_PCIMBAR1);
++
++ /* Map IO space into PCI IO window
++ * The IO window is 64K-PCIBIOS_MIN_IO in size
++ * IO addresses will be translated to the
++ * PCI IO window base address
++ */
++ pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n",
++ PCIBIOS_MIN_IO, (64 << 10),
++ SH7780_PCI_IO_BASE + PCIBIOS_MIN_IO);
++
++ /* NOTE: I'm ignoring the PCI error IRQs for now..
++ * TODO: add support for the internal error interrupts and
++ * DMA interrupts...
++ */
++
++#ifdef CONFIG_SH_R7780RP
++ pci_fixup_pcic();
++#endif
++
++ /* SH7780 init done, set central function init complete */
++ /* use round robin mode to stop a device starving/overruning */
++ word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO;
++ pci_write_reg(word, SH4_PCICR);
++
++ return 1;
++}
+diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
+new file mode 100644
+index 0000000..f02d218
+--- /dev/null
++++ b/arch/sh/drivers/pci/pci-sh7780.h
+@@ -0,0 +1,94 @@
++/*
++ * Low-Level PCI Support for SH7780 targets
++ *
++ * Dustin McIntire (dustin at sensoria.com) (c) 2001
++ * Paul Mundt (lethal at linux-sh.org) (c) 2003
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ */
++
++#ifndef _PCI_SH7780_H_
++#define _PCI_SH7780_H_
++
++/* Platform Specific Values */
++#define SH7780_VENDOR_ID 0x1912
++#define SH7780_DEVICE_ID 0x0002
++#define SH7781_DEVICE_ID 0x0001
++
++/* SH7780 Control Registers */
++#define SH7780_PCI_VCR0 0xFE000000
++#define SH7780_PCI_VCR1 0xFE000004
++#define SH7780_PCI_VCR2 0xFE000008
++
++/* SH7780 Specific Values */
++#define SH7780_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */
++#define SH7780_PCI_CONFIG_SIZE 0x01000000 /* Config space size */
++
++#define SH7780_PCI_MEMORY_BASE 0xFD000000 /* Memory space base addr */
++#define SH7780_PCI_MEM_SIZE 0x01000000 /* Size of Memory window */
++
++#define SH7780_PCI_IO_BASE 0xFE400000 /* IO space base address */
++#define SH7780_PCI_IO_SIZE 0x00400000 /* Size of IO window */
++
++#define SH7780_PCIREG_BASE 0xFE040000 /* PCI regs base address */
++#define PCI_REG(n) (SH7780_PCIREG_BASE+n)
++
++/* SH7780 PCI Config Registers */
++#define SH7780_PCIVID 0x000 /* Vendor ID */
++#define SH7780_PCIDID 0x002 /* Device ID */
++#define SH7780_PCICMD 0x004 /* Command */
++#define SH7780_PCISTATUS 0x006 /* Status */
++#define SH7780_PCIRID 0x008 /* Revision ID */
++#define SH7780_PCIPIF 0x009 /* Program Interface */
++#define SH7780_PCISUB 0x00a /* Sub class code */
++#define SH7780_PCIBCC 0x00b /* Base class code */
++#define SH7780_PCICLS 0x00c /* Cache line size */
++#define SH7780_PCILTM 0x00d /* latency timer */
++#define SH7780_PCIHDR 0x00e /* Header type */
++#define SH7780_PCIBIST 0x00f /* BIST */
++#define SH7780_PCIIBAR 0x010 /* IO Base address */
++#define SH7780_PCIMBAR0 0x014 /* Memory base address0 */
++#define SH7780_PCIMBAR1 0x018 /* Memory base address1 */
++#define SH7780_PCISVID 0x02c /* Sub system vendor ID */
++#define SH7780_PCISID 0x02e /* Sub system ID */
++#define SH7780_PCICP 0x034
++#define SH7780_PCIINTLINE 0x03c /* Interrupt line */
++#define SH7780_PCIINTPIN 0x03d /* Interrupt pin */
++#define SH7780_PCIMINGNT 0x03e /* Minumum grand */
++#define SH7780_PCIMAXLAT 0x03f /* Maxmum latency */
++#define SH7780_PCICID 0x040
++#define SH7780_PCINIP 0x041
++#define SH7780_PCIPMC 0x042
++#define SH7780_PCIPMCSR 0x044
++#define SH7780_PCIPMCSR_BSE 0x046
++#define SH7780_PCICDD 0x047
++
++#define SH7780_PCIMBR0 0x1E0
++#define SH7780_PCIMBMR0 0x1E4
++#define SH7780_PCIMBR2 0x1F0
++#define SH7780_PCIMBMR2 0x1F4
++#define SH7780_PCIIOBR 0x1F8
++#define SH7780_PCIIOBMR 0x1FC
++#define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */
++#define SH7780_PCICSCR1 0x214 /* Cache Snoop2 Cnt. Register */
++#define SH7780_PCICSAR0 0x218 /* Cache Snoop1 Addr. Register */
++#define SH7780_PCICSAR1 0x21C /* Cache Snoop2 Addr. Register */
++
++/* General Memory Config Addresses */
++#define SH7780_CS0_BASE_ADDR 0x0
++#define SH7780_MEM_REGION_SIZE 0x04000000
++#define SH7780_CS1_BASE_ADDR (SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE)
++#define SH7780_CS2_BASE_ADDR (SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE)
++#define SH7780_CS3_BASE_ADDR (SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE)
++#define SH7780_CS4_BASE_ADDR (SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE)
++#define SH7780_CS5_BASE_ADDR (SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE)
++#define SH7780_CS6_BASE_ADDR (SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE)
++
++struct sh4_pci_address_map;
++
++/* arch/sh/drivers/pci/pci-sh7780.c */
++int sh7780_pcic_init(struct sh4_pci_address_map *map);
++
++#endif /* _PCI_SH7780_H_ */
+diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
+index 7c81b8b..efecb3d 100644
+--- a/arch/sh/drivers/pci/pci-st40.c
++++ b/arch/sh/drivers/pci/pci-st40.c
+@@ -70,12 +70,6 @@
+ static void pci_set_rbar_region(unsigned int region, unsigned long localAddr,
+ unsigned long pciOffset, unsigned long regionSize);
+
+-/*
+- * The pcibios_map_platform_irq function is defined in the appropriate
+- * board specific code and referenced here
+- */
+-extern int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
+-
+ static __init void SetPCIPLL(void)
+ {
+ {
+@@ -167,7 +161,7 @@ static char * pci_commands[16]={
+ "Memory Write-and-Invalidate"
+ };
+
+-static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t st40_pci_irq(int irq, void *dev_instance)
+ {
+ unsigned pci_int, pci_air, pci_cir, pci_aint;
+ static int count=0;
+@@ -422,13 +416,6 @@ struct pci_ops st40pci_config_ops = {
+ /* Everything hangs off this */
+ static struct pci_bus *pci_root_bus;
+
+-
+-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+-{
+- return PCI_SLOT(dev->devfn);
+-}
+-
+-
+ static int __init pcibios_init(void)
+ {
+ extern unsigned long memory_start, memory_end;
+@@ -465,17 +452,11 @@ static int __init pcibios_init(void)
+ /* ok, do the scan man */
+ pci_root_bus = pci_scan_bus(0, &st40pci_config_ops, NULL);
+ pci_assign_unassigned_resources();
+- pci_fixup_irqs(no_swizzle, pcibios_map_platform_irq);
+
+ return 0;
+ }
+-
+ subsys_initcall(pcibios_init);
+
+-void __init pcibios_fixup_bus(struct pci_bus *bus)
+-{
+-}
+-
+ /*
+ * Publish a region of local address space over the PCI bus
+ * to other devices.
+diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
+index 3d546ba..d439336 100644
+--- a/arch/sh/drivers/pci/pci.c
++++ b/arch/sh/drivers/pci/pci.c
+@@ -1,21 +1,45 @@
+-/* arch/sh/kernel/pci.c
+- * $Id: pci.c,v 1.1 2003/08/24 19:15:45 lethal Exp $
++/*
++ * arch/sh/drivers/pci/pci.c
+ *
+ * Copyright (c) 2002 M. R. Brown <mrbrown at linux-sh.org>
+- *
+- *
++ * Copyright (c) 2004 - 2006 Paul Mundt <lethal at linux-sh.org>
++ *
+ * These functions are collected here to reduce duplication of common
+ * code amongst the many platform-specific PCI support code files.
+- *
++ *
+ * These routines require the following board-specific routines:
+ * void pcibios_fixup_irqs();
+ *
+ * See include/asm-sh/pci.h for more 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.
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
+ #include <linux/init.h>
++#include <asm/io.h>
++
++static inline u8 bridge_swizzle(u8 pin, u8 slot)
++{
++ return (((pin - 1) + slot) % 4) + 1;
++}
++
++static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp)
++{
++ u8 pin = *pinp;
++
++ while (dev->bus->parent) {
++ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
++ /* Move up the chain of bridges. */
++ dev = dev->bus->self;
++ }
++ *pinp = pin;
++
++ /* The slot is the slot of the last bridge. */
++ return PCI_SLOT(dev->devfn);
++}
+
+ static int __init pcibios_init(void)
+ {
+@@ -26,26 +50,32 @@ static int __init pcibios_init(void)
+ #ifdef CONFIG_PCI_AUTO
+ /* assign resources */
+ busno = 0;
+- for (p = board_pci_channels; p->pci_ops != NULL; p++) {
++ for (p = board_pci_channels; p->pci_ops != NULL; p++)
+ busno = pciauto_assign_resources(busno, p) + 1;
+- }
+ #endif
+
+ /* scan the buses */
+ busno = 0;
+- for (p= board_pci_channels; p->pci_ops != NULL; p++) {
++ for (p = board_pci_channels; p->pci_ops != NULL; p++) {
+ bus = pci_scan_bus(busno, p->pci_ops, p);
+- busno = bus->subordinate+1;
++ busno = bus->subordinate + 1;
+ }
+
+- /* board-specific fixups */
+- pcibios_fixup_irqs();
++ pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq);
+
+ return 0;
+ }
+-
+ subsys_initcall(pcibios_init);
+
++/*
++ * Called after each bus is probed, but before its children
++ * are examined.
++ */
++void __init pcibios_fixup_bus(struct pci_bus *bus)
++{
++ pci_read_bridge_bases(bus);
++}
++
+ void
+ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+@@ -61,13 +91,17 @@ pcibios_update_resource(struct pci_dev *
+ new |= PCI_ROM_ADDRESS_ENABLE;
+ reg = dev->rom_base_reg;
+ } else {
+- /* Somebody might have asked allocation of a non-standard resource */
++ /*
++ * Somebody might have asked allocation of a non-standard
++ * resource
++ */
+ return;
+ }
+-
++
+ pci_write_config_dword(dev, reg, new);
+ pci_read_config_dword(dev, reg, &check);
+- if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
++ if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ?
++ PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+ printk(KERN_ERR "PCI: Error while updating region "
+ "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
+ new, check);
+@@ -145,7 +179,8 @@ void pcibios_set_master(struct pci_dev *
+ lat = pcibios_max_latency;
+ else
+ return;
+- printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
++ printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n",
++ pci_name(dev), lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+ }
+
+@@ -153,3 +188,39 @@ void __init pcibios_update_irq(struct pc
+ {
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+ }
++
++void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
++{
++ unsigned long start = pci_resource_start(dev, bar);
++ unsigned long len = pci_resource_len(dev, bar);
++ unsigned long flags = pci_resource_flags(dev, bar);
++
++ if (unlikely(!len || !start))
++ return NULL;
++ if (maxlen && len > maxlen)
++ len = maxlen;
++
++ /*
++ * Presently the IORESOURCE_MEM case is a bit special, most
++ * SH7751 style PCI controllers have PCI memory at a fixed
++ * location in the address space where no remapping is desired
++ * (typically at 0xfd000000, but is_pci_memaddr() will know
++ * best). With the IORESOURCE_MEM case more care has to be taken
++ * to inhibit page table mapping for legacy cores, but this is
++ * punted off to __ioremap().
++ * -- PFM.
++ */
++ if (flags & IORESOURCE_IO)
++ return ioport_map(start, len);
++ if (flags & IORESOURCE_MEM)
++ return ioremap(start, len);
++
++ return NULL;
++}
++EXPORT_SYMBOL(pci_iomap);
++
++void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
++{
++ iounmap(addr);
++}
++EXPORT_SYMBOL(pci_iounmap);
+diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
+index f05cd96..5da88a4 100644
+--- a/arch/sh/kernel/Makefile
++++ b/arch/sh/kernel/Makefile
+@@ -6,9 +6,10 @@ extra-y := head.o init_task.o vmlinux.ld
+
+ obj-y := process.o signal.o entry.o traps.o irq.o \
+ ptrace.o setup.o time.o sys_sh.o semaphore.o \
+- io.o io_generic.o sh_ksyms.o
++ io.o io_generic.o sh_ksyms.o syscalls.o
+
+ obj-y += cpu/ timers/
++obj-$(CONFIG_VSYSCALL) += vsyscall/
+
+ obj-$(CONFIG_SMP) += smp.o
+ obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
+@@ -18,3 +19,5 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
+ obj-$(CONFIG_MODULES) += module.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
++obj-$(CONFIG_APM) += apm.o
++obj-$(CONFIG_PM) += pm.o
+diff --git a/arch/sh/kernel/apm.c b/arch/sh/kernel/apm.c
+new file mode 100644
+index 0000000..4f66f91
+--- /dev/null
++++ b/arch/sh/kernel/apm.c
+@@ -0,0 +1,538 @@
++/*
++ * bios-less APM driver for hp680
++ *
++ * Copyright 2005 (c) Andriy Skulysh <askulysh at gmail.com>
++ *
++ * based on ARM APM driver by
++ * Jamey Hicks <jamey at crl.dec.com>
++ *
++ * adapted from the APM BIOS driver for Linux by
++ * Stephen Rothwell (sfr at linuxcare.com)
++ *
++ * APM 1.2 Reference:
++ * Intel Corporation, Microsoft Corporation. Advanced Power Management
++ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
++ *
++ * [This document is available from Microsoft at:
++ * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
++ */
++#include <linux/module.h>
++#include <linux/poll.h>
++#include <linux/timer.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/miscdevice.h>
++#include <linux/apm_bios.h>
++#include <linux/pm.h>
++#include <linux/pm_legacy.h>
++#include <asm/apm.h>
++
++#define MODNAME "apm"
++
++/*
++ * The apm_bios device is one of the misc char devices.
++ * This is its minor number.
++ */
++#define APM_MINOR_DEV 134
++
++/*
++ * Maximum number of events stored
++ */
++#define APM_MAX_EVENTS 16
++
++struct apm_queue {
++ unsigned int event_head;
++ unsigned int event_tail;
++ apm_event_t events[APM_MAX_EVENTS];
++};
++
++/*
++ * The per-file APM data
++ */
++struct apm_user {
++ struct list_head list;
++
++ unsigned int suser: 1;
++ unsigned int writer: 1;
++ unsigned int reader: 1;
++
++ int suspend_result;
++ unsigned int suspend_state;
++#define SUSPEND_NONE 0 /* no suspend pending */
++#define SUSPEND_PENDING 1 /* suspend pending read */
++#define SUSPEND_READ 2 /* suspend read, pending ack */
++#define SUSPEND_ACKED 3 /* suspend acked */
++#define SUSPEND_DONE 4 /* suspend completed */
++
++ struct apm_queue queue;
++};
++
++/*
++ * Local variables
++ */
++static int suspends_pending;
++
++static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
++static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
++
++/*
++ * This is a list of everyone who has opened /dev/apm_bios
++ */
++static DECLARE_RWSEM(user_list_lock);
++static LIST_HEAD(apm_user_list);
++
++/*
++ * kapmd info. kapmd provides us a process context to handle
++ * "APM" events within - specifically necessary if we're going
++ * to be suspending the system.
++ */
++static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
++static DECLARE_COMPLETION(kapmd_exit);
++static DEFINE_SPINLOCK(kapmd_queue_lock);
++static struct apm_queue kapmd_queue;
++
++int apm_suspended;
++EXPORT_SYMBOL(apm_suspended);
++
++/* Platform-specific apm_read_proc(). */
++int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
++EXPORT_SYMBOL(apm_get_info);
++
++/*
++ * APM event queue management.
++ */
++static inline int queue_empty(struct apm_queue *q)
++{
++ return q->event_head == q->event_tail;
++}
++
++static inline apm_event_t queue_get_event(struct apm_queue *q)
++{
++ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
++ return q->events[q->event_tail];
++}
++
++static void queue_add_event(struct apm_queue *q, apm_event_t event)
++{
++ q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
++ if (q->event_head == q->event_tail) {
++ static int notified;
++
++ if (notified++ == 0)
++ printk(KERN_ERR "apm: an event queue overflowed\n");
++
++ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
++ }
++ q->events[q->event_head] = event;
++}
++
++static void queue_event_one_user(struct apm_user *as, apm_event_t event)
++{
++ if (as->suser && as->writer) {
++ switch (event) {
++ case APM_SYS_SUSPEND:
++ case APM_USER_SUSPEND:
++ /*
++ * If this user already has a suspend pending,
++ * don't queue another one.
++ */
++ if (as->suspend_state != SUSPEND_NONE)
++ return;
++
++ as->suspend_state = SUSPEND_PENDING;
++ suspends_pending++;
++ break;
++ }
++ }
++ queue_add_event(&as->queue, event);
++}
++
++static void queue_event(apm_event_t event, struct apm_user *sender)
++{
++ struct apm_user *as;
++
++ down_read(&user_list_lock);
++
++ list_for_each_entry(as, &apm_user_list, list)
++ if (as != sender && as->reader)
++ queue_event_one_user(as, event);
++
++ up_read(&user_list_lock);
++ wake_up_interruptible(&apm_waitqueue);
++}
++
++/**
++ * apm_queue_event - queue an APM event for kapmd
++ * @event: APM event
++ *
++ * Queue an APM event for kapmd to process and ultimately take the
++ * appropriate action. Only a subset of events are handled:
++ * %APM_LOW_BATTERY
++ * %APM_POWER_STATUS_CHANGE
++ * %APM_USER_SUSPEND
++ * %APM_SYS_SUSPEND
++ * %APM_CRITICAL_SUSPEND
++ */
++void apm_queue_event(apm_event_t event)
++{
++ spin_lock_irq(&kapmd_queue_lock);
++ queue_add_event(&kapmd_queue, event);
++ spin_unlock_irq(&kapmd_queue_lock);
++
++ wake_up_interruptible(&kapmd_wait);
++}
++EXPORT_SYMBOL(apm_queue_event);
++
++static void apm_suspend(void)
++{
++ struct apm_user *as;
++ int err;
++
++ apm_suspended = 1;
++ err = pm_suspend(PM_SUSPEND_MEM);
++
++ /*
++ * Anyone on the APM queues will think we're still suspended.
++ * Send a message so everyone knows we're now awake again.
++ */
++ queue_event(APM_NORMAL_RESUME, NULL);
++
++ /*
++ * Finally, wake up anyone who is sleeping on the suspend.
++ */
++ down_read(&user_list_lock);
++ list_for_each_entry(as, &apm_user_list, list) {
++ as->suspend_result = err;
++ as->suspend_state = SUSPEND_DONE;
++ }
++ up_read(&user_list_lock);
++
++ wake_up(&apm_suspend_waitqueue);
++ apm_suspended = 0;
++}
++
++static ssize_t apm_read(struct file *fp, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct apm_user *as = fp->private_data;
++ apm_event_t event;
++ int i = count, ret = 0;
++
++ if (count < sizeof(apm_event_t))
++ return -EINVAL;
++
++ if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++
++ wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
++
++ while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
++ event = queue_get_event(&as->queue);
++
++ ret = -EFAULT;
++ if (copy_to_user(buf, &event, sizeof(event)))
++ break;
++
++ if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)
++ as->suspend_state = SUSPEND_READ;
++
++ buf += sizeof(event);
++ i -= sizeof(event);
++ }
++
++ if (i < count)
++ ret = count - i;
++
++ return ret;
++}
++
++static unsigned int apm_poll(struct file *fp, poll_table * wait)
++{
++ struct apm_user *as = fp->private_data;
++
++ poll_wait(fp, &apm_waitqueue, wait);
++ return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
++}
++
++/*
++ * apm_ioctl - handle APM ioctl
++ *
++ * APM_IOC_SUSPEND
++ * This IOCTL is overloaded, and performs two functions. It is used to:
++ * - initiate a suspend
++ * - acknowledge a suspend read from /dev/apm_bios.
++ * Only when everyone who has opened /dev/apm_bios with write permission
++ * has acknowledge does the actual suspend happen.
++ */
++static int
++apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
++{
++ struct apm_user *as = filp->private_data;
++ unsigned long flags;
++ int err = -EINVAL;
++
++ if (!as->suser || !as->writer)
++ return -EPERM;
++
++ switch (cmd) {
++ case APM_IOC_SUSPEND:
++ as->suspend_result = -EINTR;
++
++ if (as->suspend_state == SUSPEND_READ) {
++ /*
++ * If we read a suspend command from /dev/apm_bios,
++ * then the corresponding APM_IOC_SUSPEND ioctl is
++ * interpreted as an acknowledge.
++ */
++ as->suspend_state = SUSPEND_ACKED;
++ suspends_pending--;
++ } else {
++ /*
++ * Otherwise it is a request to suspend the system.
++ * Queue an event for all readers, and expect an
++ * acknowledge from all writers who haven't already
++ * acknowledged.
++ */
++ queue_event(APM_USER_SUSPEND, as);
++ }
++
++ /*
++ * If there are no further acknowledges required, suspend
++ * the system.
++ */
++ if (suspends_pending == 0)
++ apm_suspend();
++
++ /*
++ * Wait for the suspend/resume to complete. If there are
++ * pending acknowledges, we wait here for them.
++ *
++ * Note that we need to ensure that the PM subsystem does
++ * not kick us out of the wait when it suspends the threads.
++ */
++ flags = current->flags;
++ current->flags |= PF_NOFREEZE;
++
++ /*
++ * Note: do not allow a thread which is acking the suspend
++ * to escape until the resume is complete.
++ */
++ if (as->suspend_state == SUSPEND_ACKED)
++ wait_event(apm_suspend_waitqueue,
++ as->suspend_state == SUSPEND_DONE);
++ else
++ wait_event_interruptible(apm_suspend_waitqueue,
++ as->suspend_state == SUSPEND_DONE);
++
++ current->flags = flags;
++ err = as->suspend_result;
++ as->suspend_state = SUSPEND_NONE;
++ break;
++ }
++
++ return err;
++}
++
++static int apm_release(struct inode * inode, struct file * filp)
++{
++ struct apm_user *as = filp->private_data;
++ filp->private_data = NULL;
++
++ down_write(&user_list_lock);
++ list_del(&as->list);
++ up_write(&user_list_lock);
++
++ /*
++ * We are now unhooked from the chain. As far as new
++ * events are concerned, we no longer exist. However, we
++ * need to balance suspends_pending, which means the
++ * possibility of sleeping.
++ */
++ if (as->suspend_state != SUSPEND_NONE) {
++ suspends_pending -= 1;
++ if (suspends_pending == 0)
++ apm_suspend();
++ }
++
++ kfree(as);
++ return 0;
++}
++
++static int apm_open(struct inode * inode, struct file * filp)
++{
++ struct apm_user *as;
++
++ as = kzalloc(sizeof(*as), GFP_KERNEL);
++ if (as) {
++ /*
++ * XXX - this is a tiny bit broken, when we consider BSD
++ * process accounting. If the device is opened by root, we
++ * instantly flag that we used superuser privs. Who knows,
++ * we might close the device immediately without doing a
++ * privileged operation -- cevans
++ */
++ as->suser = capable(CAP_SYS_ADMIN);
++ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
++ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
++
++ down_write(&user_list_lock);
++ list_add(&as->list, &apm_user_list);
++ up_write(&user_list_lock);
++
++ filp->private_data = as;
++ }
++
++ return as ? 0 : -ENOMEM;
++}
++
++static struct file_operations apm_bios_fops = {
++ .owner = THIS_MODULE,
++ .read = apm_read,
++ .poll = apm_poll,
++ .ioctl = apm_ioctl,
++ .open = apm_open,
++ .release = apm_release,
++};
++
++static struct miscdevice apm_device = {
++ .minor = APM_MINOR_DEV,
++ .name = "apm_bios",
++ .fops = &apm_bios_fops
++};
++
++
++#ifdef CONFIG_PROC_FS
++/*
++ * Arguments, with symbols from linux/apm_bios.h.
++ *
++ * 0) Linux driver version (this will change if format changes)
++ * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
++ * 2) APM flags from APM Installation Check (0x00):
++ * bit 0: APM_16_BIT_SUPPORT
++ * bit 1: APM_32_BIT_SUPPORT
++ * bit 2: APM_IDLE_SLOWS_CLOCK
++ * bit 3: APM_BIOS_DISABLED
++ * bit 4: APM_BIOS_DISENGAGED
++ * 3) AC line status
++ * 0x00: Off-line
++ * 0x01: On-line
++ * 0x02: On backup power (BIOS >= 1.1 only)
++ * 0xff: Unknown
++ * 4) Battery status
++ * 0x00: High
++ * 0x01: Low
++ * 0x02: Critical
++ * 0x03: Charging
++ * 0x04: Selected battery not present (BIOS >= 1.2 only)
++ * 0xff: Unknown
++ * 5) Battery flag
++ * bit 0: High
++ * bit 1: Low
++ * bit 2: Critical
++ * bit 3: Charging
++ * bit 7: No system battery
++ * 0xff: Unknown
++ * 6) Remaining battery life (percentage of charge):
++ * 0-100: valid
++ * -1: Unknown
++ * 7) Remaining battery life (time units):
++ * Number of remaining minutes or seconds
++ * -1: Unknown
++ * 8) min = minutes; sec = seconds
++ */
++static int apm_read_proc(char *buf, char **start, off_t fpos, int length)
++{
++ if (likely(apm_get_info))
++ return apm_get_info(buf, start, fpos, length);
++
++ return -EINVAL;
++}
++#endif
++
++static int kapmd(void *arg)
++{
++ daemonize("kapmd");
++ current->flags |= PF_NOFREEZE;
++
++ do {
++ apm_event_t event;
++
++ wait_event_interruptible(kapmd_wait,
++ !queue_empty(&kapmd_queue) || !pm_active);
++
++ if (!pm_active)
++ break;
++
++ spin_lock_irq(&kapmd_queue_lock);
++ event = 0;
++ if (!queue_empty(&kapmd_queue))
++ event = queue_get_event(&kapmd_queue);
++ spin_unlock_irq(&kapmd_queue_lock);
++
++ switch (event) {
++ case 0:
++ break;
++
++ case APM_LOW_BATTERY:
++ case APM_POWER_STATUS_CHANGE:
++ queue_event(event, NULL);
++ break;
++
++ case APM_USER_SUSPEND:
++ case APM_SYS_SUSPEND:
++ queue_event(event, NULL);
++ if (suspends_pending == 0)
++ apm_suspend();
++ break;
++
++ case APM_CRITICAL_SUSPEND:
++ apm_suspend();
++ break;
++ }
++ } while (1);
++
++ complete_and_exit(&kapmd_exit, 0);
++}
++
++static int __init apm_init(void)
++{
++ int ret;
++
++ pm_active = 1;
++
++ ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
++ if (unlikely(ret < 0)) {
++ pm_active = 0;
++ return ret;
++ }
++
++ create_proc_info_entry("apm", 0, NULL, apm_read_proc);
++
++ ret = misc_register(&apm_device);
++ if (unlikely(ret != 0)) {
++ remove_proc_entry("apm", NULL);
++
++ pm_active = 0;
++ wake_up(&kapmd_wait);
++ wait_for_completion(&kapmd_exit);
++ }
++
++ return ret;
++}
++
++static void __exit apm_exit(void)
++{
++ misc_deregister(&apm_device);
++ remove_proc_entry("apm", NULL);
++
++ pm_active = 0;
++ wake_up(&kapmd_wait);
++ wait_for_completion(&kapmd_exit);
++}
++
++module_init(apm_init);
++module_exit(apm_exit);
++
++MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh");
++MODULE_DESCRIPTION("Advanced Power Management");
++MODULE_LICENSE("GPL");
+diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
+index f1f9ab8..3e5fa1e 100644
+--- a/arch/sh/kernel/cf-enabler.c
++++ b/arch/sh/kernel/cf-enabler.c
+@@ -10,7 +10,8 @@
+ */
+
+ #include <linux/init.h>
+-
++#include <linux/mm.h>
++#include <linux/vmalloc.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+
+@@ -32,8 +33,6 @@
+ /* SH4 can't access PCMCIA interface through P2 area.
+ * we must remap it with appropreate attribute bit of the page set.
+ * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
+-#include <linux/mm.h>
+-#include <linux/vmalloc.h>
+
+ #if defined(CONFIG_CF_AREA6)
+ #define slot_no 0
+@@ -41,9 +40,6 @@
+ #define slot_no 1
+ #endif
+
+-/* defined in mm/ioremap.c */
+-extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
+-
+ /* use this pointer to access to directly connected compact flash io area*/
+ void *cf_io_base;
+
+@@ -62,7 +58,7 @@ static int __init allocate_cf_area(void)
+ return -ENOMEM;
+ }
+ /* printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n",
+- paddrbase, psize, prot.pgprot, cf_io_base);*/
++ paddrbase, psize, prot.pgprot, cf_io_base);*/
+
+ /* XXX : do we need attribute and common-memory area also? */
+
+@@ -87,7 +83,7 @@ static int __init cf_init_default(void)
+ }
+
+ #if defined(CONFIG_SH_SOLUTION_ENGINE)
+-#include <asm/se/se.h>
++#include <asm/se.h>
+
+ /*
+ * SolutionEngine
+diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
+index 59d5b74..fb5dac0 100644
+--- a/arch/sh/kernel/cpu/Makefile
++++ b/arch/sh/kernel/cpu/Makefile
+@@ -8,6 +8,5 @@ obj-$(CONFIG_CPU_SH2) += sh2/
+ obj-$(CONFIG_CPU_SH3) += sh3/
+ obj-$(CONFIG_CPU_SH4) += sh4/
+
+-obj-$(CONFIG_SH_RTC) += rtc.o
+ obj-$(CONFIG_UBC_WAKEUP) += ubc.o
+ obj-$(CONFIG_SH_ADC) += adc.o
+diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
+index 97fa37f..51ec64c 100644
+--- a/arch/sh/kernel/cpu/clock.c
++++ b/arch/sh/kernel/cpu/clock.c
+@@ -1,7 +1,7 @@
+ /*
+ * arch/sh/kernel/cpu/clock.c - SuperH clock framework
+ *
+- * Copyright (C) 2005 Paul Mundt
++ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * This clock framework is derived from the OMAP version by:
+ *
+@@ -15,6 +15,7 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
++#include <linux/mutex.h>
+ #include <linux/list.h>
+ #include <linux/kref.h>
+ #include <linux/seq_file.h>
+@@ -24,7 +25,7 @@
+
+ static LIST_HEAD(clock_list);
+ static DEFINE_SPINLOCK(clock_lock);
+-static DECLARE_MUTEX(clock_list_sem);
++static DEFINE_MUTEX(clock_list_sem);
+
+ /*
+ * Each subtype is expected to define the init routines for these clocks,
+@@ -140,21 +141,21 @@ void clk_disable(struct clk *clk)
+
+ int clk_register(struct clk *clk)
+ {
+- down(&clock_list_sem);
++ mutex_lock(&clock_list_sem);
+
+ list_add(&clk->node, &clock_list);
+ kref_init(&clk->kref);
+
+- up(&clock_list_sem);
++ mutex_unlock(&clock_list_sem);
+
+ return 0;
+ }
+
+ void clk_unregister(struct clk *clk)
+ {
+- down(&clock_list_sem);
++ mutex_lock(&clock_list_sem);
+ list_del(&clk->node);
+- up(&clock_list_sem);
++ mutex_unlock(&clock_list_sem);
+ }
+
+ inline unsigned long clk_get_rate(struct clk *clk)
+@@ -198,14 +199,14 @@ struct clk *clk_get(const char *id)
+ {
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+- down(&clock_list_sem);
++ mutex_lock(&clock_list_sem);
+ list_for_each_entry(p, &clock_list, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+- up(&clock_list_sem);
++ mutex_unlock(&clock_list_sem);
+
+ return clk;
+ }
+@@ -225,7 +226,7 @@ int __init clk_init(void)
+ {
+ int i, ret = 0;
+
+- BUG_ON(unlikely(!master_clk.rate));
++ BUG_ON(!master_clk.rate);
+
+ for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
+ struct clk *clk = onchip_clocks[i];
+diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
+index 868e68b..bfb90eb 100644
+--- a/arch/sh/kernel/cpu/init.c
++++ b/arch/sh/kernel/cpu/init.c
+@@ -4,6 +4,7 @@
+ * CPU init code
+ *
+ * Copyright (C) 2002, 2003 Paul Mundt
++ * Copyright (C) 2003 Richard Curnow
+ *
+ * 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
+@@ -13,6 +14,7 @@
+ #include <linux/kernel.h>
+ #include <asm/processor.h>
+ #include <asm/uaccess.h>
++#include <asm/page.h>
+ #include <asm/system.h>
+ #include <asm/cacheflush.h>
+ #include <asm/cache.h>
+@@ -51,7 +53,15 @@ static void __init cache_init(void)
+ ccr = ctrl_inl(CCR);
+
+ /*
+- * If the cache is already enabled .. flush it.
++ * At this point we don't know whether the cache is enabled or not - a
++ * bootloader may have enabled it. There are at least 2 things that
++ * could be dirty in the cache at this point:
++ * 1. kernel command line set up by boot loader
++ * 2. spilled registers from the prolog of this function
++ * => before re-initialising the cache, we must do a purge of the whole
++ * cache out to memory for safety. As long as nothing is spilled
++ * during the loop to lines that have already been done, this is safe.
++ * - RPC
+ */
+ if (ccr & CCR_CACHE_ENABLE) {
+ unsigned long ways, waysize, addrstart;
+@@ -98,6 +108,8 @@ static void __init cache_init(void)
+ /* Force EMODE if possible */
+ if (cpu_data->dcache.ways > 1)
+ flags |= CCR_CACHE_EMODE;
++ else
++ flags &= ~CCR_CACHE_EMODE;
+ #endif
+
+ #ifdef CONFIG_SH_WRITETHROUGH
+@@ -112,6 +124,9 @@ static void __init cache_init(void)
+ /* Turn on OCRAM -- halve the OC */
+ flags |= CCR_CACHE_ORA;
+ cpu_data->dcache.sets >>= 1;
++
++ cpu_data->dcache.way_size = cpu_data->dcache.sets *
++ cpu_data->dcache.linesz;
+ #endif
+
+ ctrl_outl(flags, CCR);
+@@ -184,6 +199,10 @@ asmlinkage void __init sh_cpu_init(void)
+ /* Init the cache */
+ cache_init();
+
++ shm_align_mask = max_t(unsigned long,
++ cpu_data->dcache.way_size - 1,
++ PAGE_SIZE - 1);
++
+ /* Disable the FPU */
+ if (fpu_disabled) {
+ printk("FPU Disabled\n");
+diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
+index e3cccea..1c034c2 100644
+--- a/arch/sh/kernel/cpu/irq/Makefile
++++ b/arch/sh/kernel/cpu/irq/Makefile
+@@ -3,5 +3,6 @@
+ #
+ obj-y += ipr.o imask.o
+
+-obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
+-obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
++obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
++obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
++obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
+diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
+index 30064bf..74ca576 100644
+--- a/arch/sh/kernel/cpu/irq/intc2.c
++++ b/arch/sh/kernel/cpu/irq/intc2.c
+@@ -10,93 +10,31 @@
+ * These are the "new Hitachi style" interrupts, as present on the
+ * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
+ */
+-
+ #include <linux/kernel.h>
+-#include <linux/init.h>
+ #include <linux/irq.h>
++#include <linux/io.h>
+ #include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/machvec.h>
+-
+-struct intc2_data {
+- unsigned char msk_offset;
+- unsigned char msk_shift;
+-
+- int (*clear_irq) (int);
+-};
+-
+-static struct intc2_data intc2_data[NR_INTC2_IRQS];
+-
+-static void enable_intc2_irq(unsigned int irq);
+-static void disable_intc2_irq(unsigned int irq);
+-
+-/* shutdown is same as "disable" */
+-#define shutdown_intc2_irq disable_intc2_irq
+-
+-static void mask_and_ack_intc2(unsigned int);
+-static void end_intc2_irq(unsigned int irq);
+-
+-static unsigned int startup_intc2_irq(unsigned int irq)
+-{
+- enable_intc2_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static struct hw_interrupt_type intc2_irq_type = {
+- .typename = "INTC2-IRQ",
+- .startup = startup_intc2_irq,
+- .shutdown = shutdown_intc2_irq,
+- .enable = enable_intc2_irq,
+- .disable = disable_intc2_irq,
+- .ack = mask_and_ack_intc2,
+- .end = end_intc2_irq
+-};
+
+ static void disable_intc2_irq(unsigned int irq)
+ {
+- int irq_offset = irq - INTC2_FIRST_IRQ;
+- int msk_shift, msk_offset;
+-
+- /* Sanity check */
+- if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
+- return;
+-
+- msk_shift = intc2_data[irq_offset].msk_shift;
+- msk_offset = intc2_data[irq_offset].msk_offset;
+-
+- ctrl_outl(1 << msk_shift,
+- INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset);
++ struct intc2_data *p = get_irq_chip_data(irq);
++ ctrl_outl(1 << p->msk_shift,
++ INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset);
+ }
+
+ static void enable_intc2_irq(unsigned int irq)
+ {
+- int irq_offset = irq - INTC2_FIRST_IRQ;
+- int msk_shift, msk_offset;
+-
+- /* Sanity check */
+- if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
+- return;
+-
+- msk_shift = intc2_data[irq_offset].msk_shift;
+- msk_offset = intc2_data[irq_offset].msk_offset;
+-
+- ctrl_outl(1 << msk_shift,
+- INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset);
++ struct intc2_data *p = get_irq_chip_data(irq);
++ ctrl_outl(1 << p->msk_shift,
++ INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset);
+ }
+
+-static void mask_and_ack_intc2(unsigned int irq)
+-{
+- disable_intc2_irq(irq);
+-}
+-
+-static void end_intc2_irq(unsigned int irq)
+-{
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+- enable_intc2_irq(irq);
+-
+- if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq))
+- intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq);
+-}
++static struct irq_chip intc2_irq_chip = {
++ .name = "INTC2",
++ .mask = disable_intc2_irq,
++ .unmask = enable_intc2_irq,
++ .mask_ack = disable_intc2_irq,
++};
+
+ /*
+ * Setup an INTC2 style interrupt.
+@@ -106,179 +44,36 @@ static void end_intc2_irq(unsigned int i
+ * PIO1 which is INTPRI00[19,16] and INTMSK00[13]
+ * would be: ^ ^ ^ ^
+ * | | | |
+- * make_intc2_irq(84, 0, 16, 0, 13);
++ * { 84, 0, 16, 0, 13 },
++ *
++ * in the intc2_data table.
+ */
+-void make_intc2_irq(unsigned int irq,
+- unsigned int ipr_offset, unsigned int ipr_shift,
+- unsigned int msk_offset, unsigned int msk_shift,
+- unsigned int priority)
++void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs)
+ {
+- int irq_offset = irq - INTC2_FIRST_IRQ;
+- unsigned int flags;
+- unsigned long ipr;
+-
+- if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
+- return;
+-
+- disable_irq_nosync(irq);
+-
+- /* Fill the data we need */
+- intc2_data[irq_offset].msk_offset = msk_offset;
+- intc2_data[irq_offset].msk_shift = msk_shift;
+- intc2_data[irq_offset].clear_irq = NULL;
+-
+- /* Set the priority level */
+- local_irq_save(flags);
+-
+- ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset);
+- ipr &= ~(0xf << ipr_shift);
+- ipr |= priority << ipr_shift;
+- ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset);
+-
+- local_irq_restore(flags);
++ int i;
+
+- irq_desc[irq].chip = &intc2_irq_type;
++ for (i = 0; i < nr_irqs; i++) {
++ unsigned long ipr, flags;
++ struct intc2_data *p = table + i;
+
+- disable_intc2_irq(irq);
+-}
++ disable_irq_nosync(p->irq);
+
+-static struct intc2_init {
+- unsigned short irq;
+- unsigned char ipr_offset, ipr_shift;
+- unsigned char msk_offset, msk_shift;
+- unsigned char priority;
+-} intc2_init_data[] __initdata = {
+-#if defined(CONFIG_CPU_SUBTYPE_ST40)
+- {64, 0, 0, 0, 0, 13}, /* PCI serr */
+- {65, 0, 4, 0, 1, 13}, /* PCI err */
+- {66, 0, 4, 0, 2, 13}, /* PCI ad */
+- {67, 0, 4, 0, 3, 13}, /* PCI pwd down */
+- {72, 0, 8, 0, 5, 13}, /* DMAC INT0 */
+- {73, 0, 8, 0, 6, 13}, /* DMAC INT1 */
+- {74, 0, 8, 0, 7, 13}, /* DMAC INT2 */
+- {75, 0, 8, 0, 8, 13}, /* DMAC INT3 */
+- {76, 0, 8, 0, 9, 13}, /* DMAC INT4 */
+- {78, 0, 8, 0, 11, 13}, /* DMAC ERR */
+- {80, 0, 12, 0, 12, 13}, /* PIO0 */
+- {84, 0, 16, 0, 13, 13}, /* PIO1 */
+- {88, 0, 20, 0, 14, 13}, /* PIO2 */
+- {112, 4, 0, 4, 0, 13}, /* Mailbox */
+- #ifdef CONFIG_CPU_SUBTYPE_ST40GX1
+- {116, 4, 4, 4, 4, 13}, /* SSC0 */
+- {120, 4, 8, 4, 8, 13}, /* IR Blaster */
+- {124, 4, 12, 4, 12, 13}, /* USB host */
+- {128, 4, 16, 4, 16, 13}, /* Video processor BLITTER */
+- {132, 4, 20, 4, 20, 13}, /* UART0 */
+- {134, 4, 20, 4, 22, 13}, /* UART2 */
+- {136, 4, 24, 4, 24, 13}, /* IO_PIO0 */
+- {140, 4, 28, 4, 28, 13}, /* EMPI */
+- {144, 8, 0, 8, 0, 13}, /* MAFE */
+- {148, 8, 4, 8, 4, 13}, /* PWM */
+- {152, 8, 8, 8, 8, 13}, /* SSC1 */
+- {156, 8, 12, 8, 12, 13}, /* IO_PIO1 */
+- {160, 8, 16, 8, 16, 13}, /* USB target */
+- {164, 8, 20, 8, 20, 13}, /* UART1 */
+- {168, 8, 24, 8, 24, 13}, /* Teletext */
+- {172, 8, 28, 8, 28, 13}, /* VideoSync VTG */
+- {173, 8, 28, 8, 29, 13}, /* VideoSync DVP0 */
+- {174, 8, 28, 8, 30, 13}, /* VideoSync DVP1 */
+-#endif
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+-/*
+- * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0
+- */
+- /* INTPRIO0 | INTMSK0 */
+- {48, 0, 28, 0, 31, 3}, /* IRQ 4 */
+- {49, 0, 24, 0, 30, 3}, /* IRQ 3 */
+- {50, 0, 20, 0, 29, 3}, /* IRQ 2 */
+- {51, 0, 16, 0, 28, 3}, /* IRQ 1 */
+- /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */
+- /* INTPRIO4 | INTMSK0 */
+- {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */
+- {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */
+- {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */
+- {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */
+- {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */
+- {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */
+- {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */
+- {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */
+- /* INTPRIO8 | INTMSK0 */
+- {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */
+- {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */
+- {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */
+- {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */
+- {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */
+- {65, 8, 24, 0, 16, 3}, /* LCDC */
+- /* 66, 67 unused */
+- {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */
+- {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */
+- {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */
+- /* 71 unused */
+- {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */
+- {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */
+- {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */
+- {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */
+- {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */
+- {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */
+- {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */
+- {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */
+- /* | INTMSK4 */
+- {80, 8, 4, 4, 23, 3}, /* SIM_ERI */
+- {81, 8, 4, 4, 22, 3}, /* SIM_RXI */
+- {82, 8, 4, 4, 21, 3}, /* SIM_TXI */
+- {83, 8, 4, 4, 20, 3}, /* SIM_TEI */
+- {84, 8, 0, 4, 19, 3}, /* HSPII */
+- /* INTPRIOC | INTMSK4 */
+- /* 85-87 unused/reserved */
+- {88, 12, 20, 4, 18, 3}, /* MMCI0 */
+- {89, 12, 20, 4, 17, 3}, /* MMCI1 */
+- {90, 12, 20, 4, 16, 3}, /* MMCI2 */
+- {91, 12, 20, 4, 15, 3}, /* MMCI3 */
+- {92, 12, 12, 4, 6, 3}, /* MFI (unsure, bug? in my 7760 manual*/
+- /* 93-107 reserved/undocumented */
+- {108,12, 4, 4, 1, 3}, /* ADC */
+- {109,12, 0, 4, 0, 3}, /* CMTI */
+- /* 110-111 reserved/unused */
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+- { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2},
+-#ifdef CONFIG_SH_RTC
+- { RTC_IRQ, 4, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
+-#endif
+- { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
+- { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
+- { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
+- { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
++ /* Set the priority level */
++ local_irq_save(flags);
+
+- { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
+- { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
+- { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
+- { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
++ ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET +
++ p->ipr_offset);
++ ipr &= ~(0xf << p->ipr_shift);
++ ipr |= p->priority << p->ipr_shift;
++ ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET +
++ p->ipr_offset);
+
+- { PCIC0_IRQ, 0x10, 8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY },
+- { PCIC1_IRQ, 0x10, 0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY },
+- { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY },
+- { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY },
+- { PCIC4_IRQ, 0x14, 8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY },
+-#endif
+-};
++ local_irq_restore(flags);
+
+-void __init init_IRQ_intc2(void)
+-{
+- int i;
++ set_irq_chip_and_handler_name(p->irq, &intc2_irq_chip,
++ handle_level_irq, "level");
++ set_irq_chip_data(p->irq, p);
+
+- for (i = 0; i < ARRAY_SIZE(intc2_init_data); i++) {
+- struct intc2_init *p = intc2_init_data + i;
+- make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
+- p-> msk_offset, p->msk_shift, p->priority);
++ enable_intc2_irq(p->irq);
+ }
+ }
+-
+-/* Adds a termination callback to the interrupt */
+-void intc2_add_clear_irq(int irq, int (*fn)(int))
+-{
+- if (unlikely(irq < INTC2_FIRST_IRQ))
+- return;
+-
+- intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
+-}
+-
+diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
+index 0f54594..a008956 100644
+--- a/arch/sh/kernel/cpu/irq/ipr.c
++++ b/arch/sh/kernel/cpu/irq/ipr.c
+@@ -1,11 +1,10 @@
+ /*
+- * arch/sh/kernel/cpu/irq/ipr.c
++ * Interrupt handling for IPR-based IRQ.
+ *
+ * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000 Kazumoto Kojima
+- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
+- *
+- * Interrupt handling for IPR-based IRQ.
++ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
++ * Copyright (C) 2006 Paul Mundt
+ *
+ * Supported system:
+ * On-chip supporting modules (TMU, RTC, etc.).
+@@ -13,155 +12,94 @@
+ * Hitachi SolutionEngine external I/O:
+ * MS7709SE01, MS7709ASE01, and MS7750SE01
+ *
++ * 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/init.h>
+ #include <linux/irq.h>
+ #include <linux/module.h>
+-
+ #include <asm/system.h>
+ #include <asm/io.h>
+ #include <asm/machvec.h>
+
+-struct ipr_data {
+- unsigned int addr; /* Address of Interrupt Priority Register */
+- int shift; /* Shifts of the 16-bit data */
+- int priority; /* The priority */
+-};
+-static struct ipr_data ipr_data[NR_IRQS];
+-
+-static void enable_ipr_irq(unsigned int irq);
+-static void disable_ipr_irq(unsigned int irq);
+-
+-/* shutdown is same as "disable" */
+-#define shutdown_ipr_irq disable_ipr_irq
+-
+-static void mask_and_ack_ipr(unsigned int);
+-static void end_ipr_irq(unsigned int irq);
+-
+-static unsigned int startup_ipr_irq(unsigned int irq)
+-{
+- enable_ipr_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static struct hw_interrupt_type ipr_irq_type = {
+- .typename = "IPR-IRQ",
+- .startup = startup_ipr_irq,
+- .shutdown = shutdown_ipr_irq,
+- .enable = enable_ipr_irq,
+- .disable = disable_ipr_irq,
+- .ack = mask_and_ack_ipr,
+- .end = end_ipr_irq
+-};
+
+ static void disable_ipr_irq(unsigned int irq)
+ {
+- unsigned long val, flags;
+- unsigned int addr = ipr_data[irq].addr;
+- unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
+-
++ struct ipr_data *p = get_irq_chip_data(irq);
++ int shift = p->shift*4;
+ /* Set the priority in IPR to 0 */
+- local_irq_save(flags);
+- val = ctrl_inw(addr);
+- val &= mask;
+- ctrl_outw(val, addr);
+- local_irq_restore(flags);
++ ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << shift)), p->addr);
+ }
+
+ static void enable_ipr_irq(unsigned int irq)
+ {
+- unsigned long val, flags;
+- unsigned int addr = ipr_data[irq].addr;
+- int priority = ipr_data[irq].priority;
+- unsigned short value = (priority << ipr_data[irq].shift);
+-
++ struct ipr_data *p = get_irq_chip_data(irq);
++ int shift = p->shift*4;
+ /* Set priority in IPR back to original value */
+- local_irq_save(flags);
+- val = ctrl_inw(addr);
+- val |= value;
+- ctrl_outw(val, addr);
+- local_irq_restore(flags);
++ ctrl_outw(ctrl_inw(p->addr) | (p->priority << shift), p->addr);
+ }
+
+-static void mask_and_ack_ipr(unsigned int irq)
+-{
+- disable_ipr_irq(irq);
+-
+-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+- defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+- /* This is needed when we use edge triggered setting */
+- /* XXX: Is it really needed? */
+- if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) {
+- /* Clear external interrupt request */
+- int a = ctrl_inb(INTC_IRR0);
+- a &= ~(1 << (irq - IRQ0_IRQ));
+- ctrl_outb(a, INTC_IRR0);
+- }
+-#endif
+-}
++static struct irq_chip ipr_irq_chip = {
++ .name = "IPR",
++ .mask = disable_ipr_irq,
++ .unmask = enable_ipr_irq,
++ .mask_ack = disable_ipr_irq,
++};
+
+-static void end_ipr_irq(unsigned int irq)
++void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
+ {
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
++ int i;
++
++ for (i = 0; i < nr_irqs; i++) {
++ unsigned int irq = table[i].irq;
++ disable_irq_nosync(irq);
++ set_irq_chip_and_handler_name(irq, &ipr_irq_chip,
++ handle_level_irq, "level");
++ set_irq_chip_data(irq, &table[i]);
+ enable_ipr_irq(irq);
++ }
+ }
++EXPORT_SYMBOL(make_ipr_irq);
+
+-void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
+-{
+- disable_irq_nosync(irq);
+- ipr_data[irq].addr = addr;
+- ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
+- ipr_data[irq].priority = priority;
+-
+- irq_desc[irq].chip = &ipr_irq_type;
+- disable_ipr_irq(irq);
+-}
+-
+-void __init init_IRQ(void)
+-{
++static struct ipr_data sys_ipr_map[] = {
+ #ifndef CONFIG_CPU_SUBTYPE_SH7780
+- make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
+- make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY);
+-#if defined(CONFIG_SH_RTC)
+- make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
++ { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY },
++ { TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY },
++#ifdef RTC_IRQ
++ { RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY },
+ #endif
+-
+ #ifdef SCI_ERI_IRQ
+- make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
+- make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
+- make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
++ { SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY },
++ { SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY },
++ { SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY },
+ #endif
+-
+ #ifdef SCIF1_ERI_IRQ
+- make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+- make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+- make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+- make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
++ { SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
++ { SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
++ { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
++ { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
+ #endif
+-
+ #if defined(CONFIG_CPU_SUBTYPE_SH7300)
+- make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY);
+- make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+- make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+- make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
++ { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
++ { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
++ { VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
+ #endif
+-
+ #ifdef SCIF_ERI_IRQ
+- make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+- make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+- make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+- make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
++ { SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
++ { SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
++ { SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
++ { SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
+ #endif
+-
+ #ifdef IRDA_ERI_IRQ
+- make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+- make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+- make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+- make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
++ { IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
++ { IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
++ { IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
++ { IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
+ #endif
+-
+ #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+ /*
+ * Initialize the Interrupt Controller (INTC)
+@@ -173,14 +111,19 @@ void __init init_IRQ(void)
+ * You should set corresponding bits of PFC to "00"
+ * to enable these interrupts.
+ */
+- make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY);
+- make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY);
+- make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY);
+- make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY);
+- make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY);
+- make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY);
++ { IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY },
++ { IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY },
++ { IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY },
++ { IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY },
++ { IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY },
++ { IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY },
+ #endif
+ #endif
++};
++
++void __init init_IRQ(void)
++{
++ make_ipr_irq(sys_ipr_map, ARRAY_SIZE(sys_ipr_map));
+
+ #ifdef CONFIG_CPU_HAS_PINT_IRQ
+ init_IRQ_pint();
+@@ -192,6 +135,8 @@ void __init init_IRQ(void)
+ /* Perform the machine specific initialisation */
+ if (sh_mv.mv_init_irq != NULL)
+ sh_mv.mv_init_irq();
++
++ irq_ctx_init(smp_processor_id());
+ }
+
+ #if !defined(CONFIG_CPU_HAS_PINT_IRQ)
+@@ -200,5 +145,3 @@ int ipr_irq_demux(int irq)
+ return irq;
+ }
+ #endif
+-
+-EXPORT_SYMBOL(make_ipr_irq);
+diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c
+new file mode 100644
+index 0000000..492db31
+--- /dev/null
++++ b/arch/sh/kernel/cpu/irq/maskreg.c
+@@ -0,0 +1,93 @@
++/*
++ * Interrupt handling for Simple external interrupt mask register
++ *
++ * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp>
++ *
++ * This is for the machine which have single 16 bit register
++ * for masking external IRQ individually.
++ * Each bit of the register is for masking each interrupt.
++ *
++ * This file may be copied or modified under the terms of the GNU
++ * General Public License. See linux/COPYING for more information.
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++
++/* address of external interrupt mask register */
++unsigned long irq_mask_register;
++
++/* forward declaration */
++static unsigned int startup_maskreg_irq(unsigned int irq);
++static void shutdown_maskreg_irq(unsigned int irq);
++static void enable_maskreg_irq(unsigned int irq);
++static void disable_maskreg_irq(unsigned int irq);
++static void mask_and_ack_maskreg(unsigned int);
++static void end_maskreg_irq(unsigned int irq);
++
++/* hw_interrupt_type */
++static struct hw_interrupt_type maskreg_irq_type = {
++ .typename = "Mask Register",
++ .startup = startup_maskreg_irq,
++ .shutdown = shutdown_maskreg_irq,
++ .enable = enable_maskreg_irq,
++ .disable = disable_maskreg_irq,
++ .ack = mask_and_ack_maskreg,
++ .end = end_maskreg_irq
++};
++
++/* actual implementatin */
++static unsigned int startup_maskreg_irq(unsigned int irq)
++{
++ enable_maskreg_irq(irq);
++ return 0; /* never anything pending */
++}
++
++static void shutdown_maskreg_irq(unsigned int irq)
++{
++ disable_maskreg_irq(irq);
++}
++
++static void disable_maskreg_irq(unsigned int irq)
++{
++ unsigned short val, mask = 0x01 << irq;
++
++ BUG_ON(!irq_mask_register);
++
++ /* Set "irq"th bit */
++ val = ctrl_inw(irq_mask_register);
++ val |= mask;
++ ctrl_outw(val, irq_mask_register);
++}
++
++static void enable_maskreg_irq(unsigned int irq)
++{
++ unsigned short val, mask = ~(0x01 << irq);
++
++ BUG_ON(!irq_mask_register);
++
++ /* Clear "irq"th bit */
++ val = ctrl_inw(irq_mask_register);
++ val &= mask;
++ ctrl_outw(val, irq_mask_register);
++}
++
++static void mask_and_ack_maskreg(unsigned int irq)
++{
++ disable_maskreg_irq(irq);
++}
++
++static void end_maskreg_irq(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
++ enable_maskreg_irq(irq);
++}
++
++void make_maskreg_irq(unsigned int irq)
++{
++ disable_irq_nosync(irq);
++ irq_desc[irq].handler = &maskreg_irq_type;
++ disable_maskreg_irq(irq);
++}
+diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
+index 80cd810..f600077 100644
+--- a/arch/sh/kernel/cpu/irq/pint.c
++++ b/arch/sh/kernel/cpu/irq/pint.c
+@@ -48,26 +48,22 @@ static struct hw_interrupt_type pint_irq
+
+ static void disable_pint_irq(unsigned int irq)
+ {
+- unsigned long val, flags;
++ unsigned long val;
+
+- local_irq_save(flags);
+ val = ctrl_inw(INTC_INTER);
+ val &= ~(1 << (irq - PINT_IRQ_BASE));
+ ctrl_outw(val, INTC_INTER); /* disable PINTn */
+ portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
+- local_irq_restore(flags);
+ }
+
+ static void enable_pint_irq(unsigned int irq)
+ {
+- unsigned long val, flags;
++ unsigned long val;
+
+- local_irq_save(flags);
+ val = ctrl_inw(INTC_INTER);
+ val |= 1 << (irq - PINT_IRQ_BASE);
+ ctrl_outw(val, INTC_INTER); /* enable PINTn */
+ portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
+- local_irq_restore(flags);
+ }
+
+ static void mask_and_ack_pint(unsigned int irq)
+@@ -88,12 +84,16 @@ void make_pint_irq(unsigned int irq)
+ disable_pint_irq(irq);
+ }
+
++static struct ipr_data pint_ipr_map[] = {
++ { PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY },
++ { PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY },
++};
++
+ void __init init_IRQ_pint(void)
+ {
+ int i;
+
+- make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY);
+- make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY);
++ make_ipr_irq(pint_ipr_map, ARRAY_SIZE(pint_ipr_map));
+
+ enable_irq(PINT0_IRQ);
+ enable_irq(PINT8_IRQ);
+diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c
+deleted file mode 100644
+index 4304cf7..0000000
+--- a/arch/sh/kernel/cpu/rtc.c
++++ /dev/null
+@@ -1,128 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
+- *
+- * Copyright (C) 2000 Philipp Rumpf <prumpf at tux.org>
+- * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+- */
+-
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/time.h>
+-#include <linux/bcd.h>
+-#include <asm/io.h>
+-#include <asm/rtc.h>
+-
+-void sh_rtc_gettimeofday(struct timespec *ts)
+-{
+- unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
+- unsigned long flags;
+-
+- again:
+- do {
+- local_irq_save(flags);
+- ctrl_outb(0, RCR1); /* Clear CF-bit */
+- sec128 = ctrl_inb(R64CNT);
+- sec = ctrl_inb(RSECCNT);
+- min = ctrl_inb(RMINCNT);
+- hr = ctrl_inb(RHRCNT);
+- wk = ctrl_inb(RWKCNT);
+- day = ctrl_inb(RDAYCNT);
+- mon = ctrl_inb(RMONCNT);
+-#if defined(CONFIG_CPU_SH4)
+- yr = ctrl_inw(RYRCNT);
+- yr100 = (yr >> 8);
+- yr &= 0xff;
+-#else
+- yr = ctrl_inb(RYRCNT);
+- yr100 = (yr == 0x99) ? 0x19 : 0x20;
+-#endif
+- sec2 = ctrl_inb(R64CNT);
+- cf_bit = ctrl_inb(RCR1) & RCR1_CF;
+- local_irq_restore(flags);
+- } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
+-
+- BCD_TO_BIN(yr100);
+- BCD_TO_BIN(yr);
+- BCD_TO_BIN(mon);
+- BCD_TO_BIN(day);
+- BCD_TO_BIN(hr);
+- BCD_TO_BIN(min);
+- BCD_TO_BIN(sec);
+-
+- if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+- hr > 23 || min > 59 || sec > 59) {
+- printk(KERN_ERR
+- "SH RTC: invalid value, resetting to 1 Jan 2000\n");
+- local_irq_save(flags);
+- ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */
+- ctrl_outb(0, RSECCNT);
+- ctrl_outb(0, RMINCNT);
+- ctrl_outb(0, RHRCNT);
+- ctrl_outb(6, RWKCNT);
+- ctrl_outb(1, RDAYCNT);
+- ctrl_outb(1, RMONCNT);
+-#if defined(CONFIG_CPU_SH4)
+- ctrl_outw(0x2000, RYRCNT);
+-#else
+- ctrl_outb(0, RYRCNT);
+-#endif
+- ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */
+- goto again;
+- }
+-
+-#if RTC_BIT_INVERTED != 0
+- if ((sec128 & RTC_BIT_INVERTED))
+- sec--;
+-#endif
+-
+- ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+- ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000;
+-}
+-
+-/*
+- * Changed to only care about tv_sec, and not the full timespec struct
+- * (i.e. tv_nsec). It can easily be switched to timespec for future cpus
+- * that support setting usec or nsec RTC values.
+- */
+-int sh_rtc_settimeofday(const time_t secs)
+-{
+- int retval = 0;
+- int real_seconds, real_minutes, cmos_minutes;
+- unsigned long flags;
+-
+- local_irq_save(flags);
+- ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */
+-
+- cmos_minutes = ctrl_inb(RMINCNT);
+- BCD_TO_BIN(cmos_minutes);
+-
+- /*
+- * since we're only adjusting minutes and seconds,
+- * don't interfere with hour overflow. This avoids
+- * messing with unknown time zones but requires your
+- * RTC not to be off by more than 15 minutes
+- */
+- real_seconds = secs % 60;
+- real_minutes = secs / 60;
+- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+- real_minutes += 30; /* correct for half hour time zone */
+- real_minutes %= 60;
+-
+- if (abs(real_minutes - cmos_minutes) < 30) {
+- BIN_TO_BCD(real_seconds);
+- BIN_TO_BCD(real_minutes);
+- ctrl_outb(real_seconds, RSECCNT);
+- ctrl_outb(real_minutes, RMINCNT);
+- } else {
+- printk(KERN_WARNING
+- "set_rtc_time: can't update from %d to %d\n",
+- cmos_minutes, real_minutes);
+- retval = -1;
+- }
+-
+- ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */
+- local_irq_restore(flags);
+-
+- return retval;
+-}
+diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
+index b54dbb9..58d3815 100644
+--- a/arch/sh/kernel/cpu/sh3/Makefile
++++ b/arch/sh/kernel/cpu/sh3/Makefile
+@@ -4,10 +4,21 @@
+
+ obj-y := ex.o probe.o
+
++# CPU subtype setup
++obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
++
++# Primary on-chip clocks (common)
+ clock-$(CONFIG_CPU_SH3) := clock-sh3.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o
++clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
++clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7300.o
+
+ obj-y += $(clock-y)
+-
+diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7706.c b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
+new file mode 100644
+index 0000000..0cf96f9
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
+@@ -0,0 +1,84 @@
++/*
++ * arch/sh/kernel/cpu/sh3/clock-sh7706.c
++ *
++ * SH7706 support for the clock framework
++ *
++ * Copyright (C) 2006 Takashi YOSHII
++ *
++ * Based on arch/sh/kernel/cpu/sh3/clock-sh7709.c
++ * Copyright (C) 2005 Andriy Skulysh
++ *
++ * 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/init.h>
++#include <linux/kernel.h>
++#include <asm/clock.h>
++#include <asm/freq.h>
++#include <asm/io.h>
++
++static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
++static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
++static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
++
++static void master_clk_init(struct clk *clk)
++{
++ int frqcr = ctrl_inw(FRQCR);
++ int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
++
++ clk->rate *= pfc_divisors[idx];
++}
++
++static struct clk_ops sh7706_master_clk_ops = {
++ .init = master_clk_init,
++};
++
++static void module_clk_recalc(struct clk *clk)
++{
++ int frqcr = ctrl_inw(FRQCR);
++ int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
++
++ clk->rate = clk->parent->rate / pfc_divisors[idx];
++}
++
++static struct clk_ops sh7706_module_clk_ops = {
++ .recalc = module_clk_recalc,
++};
++
++static void bus_clk_recalc(struct clk *clk)
++{
++ int frqcr = ctrl_inw(FRQCR);
++ int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
++
++ clk->rate = clk->parent->rate / stc_multipliers[idx];
++}
++
++static struct clk_ops sh7706_bus_clk_ops = {
++ .recalc = bus_clk_recalc,
++};
++
++static void cpu_clk_recalc(struct clk *clk)
++{
++ int frqcr = ctrl_inw(FRQCR);
++ int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
++
++ clk->rate = clk->parent->rate / ifc_divisors[idx];
++}
++
++static struct clk_ops sh7706_cpu_clk_ops = {
++ .recalc = cpu_clk_recalc,
++};
++
++static struct clk_ops *sh7706_clk_ops[] = {
++ &sh7706_master_clk_ops,
++ &sh7706_module_clk_ops,
++ &sh7706_bus_clk_ops,
++ &sh7706_cpu_clk_ops,
++};
++
++void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
++{
++ if (idx < ARRAY_SIZE(sh7706_clk_ops))
++ *ops = sh7706_clk_ops[idx];
++}
+diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
+index cc04e9e..ba3082d 100644
+--- a/arch/sh/kernel/cpu/sh3/ex.S
++++ b/arch/sh/kernel/cpu/sh3/ex.S
+@@ -4,7 +4,7 @@
+ * The SH-3 exception vector table.
+
+ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
+- * Copyright (C) 2003 Paul Mundt
++ * Copyright (C) 2003 - 2006 Paul Mundt
+ *
+ * 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
+@@ -49,150 +49,10 @@ ENTRY(nmi_slot)
+ #endif
+ ENTRY(user_break_point_trap)
+ .long break_point_trap /* 1E0 */
+-ENTRY(interrupt_table)
+- ! external hardware
+- .long do_IRQ ! 0000 /* 200 */
+- .long do_IRQ ! 0001
+- .long do_IRQ ! 0010
+- .long do_IRQ ! 0011
+- .long do_IRQ ! 0100
+- .long do_IRQ ! 0101
+- .long do_IRQ ! 0110
+- .long do_IRQ ! 0111
+- .long do_IRQ ! 1000 /* 300 */
+- .long do_IRQ ! 1001
+- .long do_IRQ ! 1010
+- .long do_IRQ ! 1011
+- .long do_IRQ ! 1100
+- .long do_IRQ ! 1101
+- .long do_IRQ ! 1110
+- .long exception_error
+- ! Internal hardware
+- .long do_IRQ ! TMU0 tuni0 /* 400 */
+- .long do_IRQ ! TMU1 tuni1
+- .long do_IRQ ! TMU2 tuni2
+- .long do_IRQ ! ticpi2
+- .long do_IRQ ! RTC ati
+- .long do_IRQ ! pri
+- .long do_IRQ ! cui
+- .long do_IRQ ! SCI eri
+- .long do_IRQ ! rxi /* 500 */
+- .long do_IRQ ! txi
+- .long do_IRQ ! tei
+- .long do_IRQ ! WDT iti /* 560 */
+- .long do_IRQ ! REF rcmi
+- .long do_IRQ ! rovi
+- .long do_IRQ
+- .long do_IRQ /* 5E0 */
+-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+- defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+- .long do_IRQ ! 32 IRQ irq0 /* 600 */
+- .long do_IRQ ! 33 irq1
+- .long do_IRQ ! 34 irq2
+- .long do_IRQ ! 35 irq3
+- .long do_IRQ ! 36 irq4
+- .long do_IRQ ! 37 irq5
+- .long do_IRQ ! 38
+- .long do_IRQ ! 39
+- .long do_IRQ ! 40 PINT pint0-7 /* 700 */
+- .long do_IRQ ! 41 pint8-15
+- .long do_IRQ ! 42
+- .long do_IRQ ! 43
+- .long do_IRQ ! 44
+- .long do_IRQ ! 45
+- .long do_IRQ ! 46
+- .long do_IRQ ! 47
+- .long do_IRQ ! 48 DMAC dei0 /* 800 */
+- .long do_IRQ ! 49 dei1
+- .long do_IRQ ! 50 dei2
+- .long do_IRQ ! 51 dei3
+- .long do_IRQ ! 52 IrDA eri1
+- .long do_IRQ ! 53 rxi1
+- .long do_IRQ ! 54 bri1
+- .long do_IRQ ! 55 txi1
+- .long do_IRQ ! 56 SCIF eri2
+- .long do_IRQ ! 57 rxi2
+- .long do_IRQ ! 58 bri2
+- .long do_IRQ ! 59 txi2
+- .long do_IRQ ! 60 ADC adi /* 980 */
+-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+- .long exception_none ! 61 /* 9A0 */
+- .long exception_none ! 62
+- .long exception_none ! 63
+- .long exception_none ! 64 /* A00 */
+- .long do_IRQ ! 65 USB usi0
+- .long do_IRQ ! 66 usi1
+- .long exception_none ! 67
+- .long exception_none ! 68
+- .long exception_none ! 69
+- .long exception_none ! 70
+- .long exception_none ! 71
+- .long exception_none ! 72 /* B00 */
+- .long exception_none ! 73
+- .long exception_none ! 74
+- .long exception_none ! 75
+- .long exception_none ! 76
+- .long exception_none ! 77
+- .long exception_none ! 78
+- .long exception_none ! 79
+- .long do_IRQ ! 80 TPU0 tpi0 /* C00 */
+- .long do_IRQ ! 81 TPU1 tpi1
+- .long exception_none ! 82
+- .long exception_none ! 83
+- .long do_IRQ ! 84 TPU2 tpi2
+- .long do_IRQ ! 85 TPU3 tpi3 /* CA0 */
+-#endif
+-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7300)
+- .long do_IRQ ! 61 LCDC lcdi /* 9A0 */
+- .long do_IRQ ! 62 PCC pcc0i
+- .long do_IRQ ! 63 pcc1i /* 9E0 */
+-#endif
+-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+- .long do_IRQ ! 64
+- .long do_IRQ ! 65
+- .long do_IRQ ! 66
+- .long do_IRQ ! 67
+- .long do_IRQ ! 68
+- .long do_IRQ ! 69
+- .long do_IRQ ! 70
+- .long do_IRQ ! 71
+- .long do_IRQ ! 72
+- .long do_IRQ ! 73
+- .long do_IRQ ! 74
+- .long do_IRQ ! 75
+- .long do_IRQ ! 76
+- .long do_IRQ ! 77
+- .long do_IRQ ! 78
+- .long do_IRQ ! 79
+- .long do_IRQ ! 80 SCIF0(SH7300)
+- .long do_IRQ ! 81
+- .long do_IRQ ! 82
+- .long do_IRQ ! 83
+- .long do_IRQ ! 84
+- .long do_IRQ ! 85
+- .long do_IRQ ! 86
+- .long do_IRQ ! 87
+- .long do_IRQ ! 88
+- .long do_IRQ ! 89
+- .long do_IRQ ! 90
+- .long do_IRQ ! 91
+- .long do_IRQ ! 92
+- .long do_IRQ ! 93
+- .long do_IRQ ! 94
+- .long do_IRQ ! 95
+- .long do_IRQ ! 96
+- .long do_IRQ ! 97
+- .long do_IRQ ! 98
+- .long do_IRQ ! 99
+- .long do_IRQ ! 100
+- .long do_IRQ ! 101
+- .long do_IRQ ! 102
+- .long do_IRQ ! 103
+- .long do_IRQ ! 104
+- .long do_IRQ ! 105
+- .long do_IRQ ! 106
+- .long do_IRQ ! 107
+- .long do_IRQ ! 108
+-#endif
+-#endif
+
++ /*
++ * Pad the remainder of the table out, exceptions residing in far
++ * away offsets can be manually inserted in to their appropriate
++ * location via set_exception_table_{evt,vec}().
++ */
++ .balign 4096,0,4096
+diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
+index 5cdc886..e670988 100644
+--- a/arch/sh/kernel/cpu/sh3/probe.c
++++ b/arch/sh/kernel/cpu/sh3/probe.c
+@@ -72,6 +72,12 @@ int __init detect_cpu_and_cache_system(v
+ cpu_data->dcache.sets = 256;
+ cpu_data->type = CPU_SH7729;
+
++#if defined(CONFIG_CPU_SUBTYPE_SH7706)
++ cpu_data->type = CPU_SH7706;
++#endif
++#if defined(CONFIG_CPU_SUBTYPE_SH7710)
++ cpu_data->type = CPU_SH7710;
++#endif
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705)
+ cpu_data->type = CPU_SH7705;
+
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7300.c b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
+new file mode 100644
+index 0000000..ab4d204
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
+@@ -0,0 +1,43 @@
++/*
++ * SH7300 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xa4430000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCI,
++ .irqs = { 80, 80, 80, 80 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7300_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7300_devices_setup(void)
++{
++ return platform_add_devices(sh7300_devices,
++ ARRAY_SIZE(sh7300_devices));
++}
++__initcall(sh7300_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+new file mode 100644
+index 0000000..a8e41c5
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+@@ -0,0 +1,48 @@
++/*
++ * SH7705 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xa4400000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 52, 53, 55, 54 },
++ }, {
++ .mapbase = 0xa4410000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 56, 57, 59, 58 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7705_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7705_devices_setup(void)
++{
++ return platform_add_devices(sh7705_devices,
++ ARRAY_SIZE(sh7705_devices));
++}
++__initcall(sh7705_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
+new file mode 100644
+index 0000000..f933723
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
+@@ -0,0 +1,43 @@
++/*
++ * SH7708 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xfffffe80,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCI,
++ .irqs = { 23, 24, 25, 0 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7708_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7708_devices_setup(void)
++{
++ return platform_add_devices(sh7708_devices,
++ ARRAY_SIZE(sh7708_devices));
++}
++__initcall(sh7708_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+new file mode 100644
+index 0000000..ff43ef2
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+@@ -0,0 +1,53 @@
++/*
++ * SH7707/SH7709 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xfffffe80,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCI,
++ .irqs = { 23, 24, 25, 0 },
++ }, {
++ .mapbase = 0xa4000150,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 56, 57, 59, 58 },
++ }, {
++ .mapbase = 0xa4000140,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_IRDA,
++ .irqs = { 52, 53, 55, 54 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7709_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7709_devices_setup(void)
++{
++ return platform_add_devices(sh7709_devices,
++ ARRAY_SIZE(sh7709_devices));
++}
++__initcall(sh7709_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+new file mode 100644
+index 0000000..895f99e
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+@@ -0,0 +1,43 @@
++/*
++ * SH7710 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xa4400000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 52, 53, 55, 54 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7710_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7710_devices_setup(void)
++{
++ return platform_add_devices(sh7710_devices,
++ ARRAY_SIZE(sh7710_devices));
++}
++__initcall(sh7710_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
+index 3d5cafc..8dbf389 100644
+--- a/arch/sh/kernel/cpu/sh4/Makefile
++++ b/arch/sh/kernel/cpu/sh4/Makefile
+@@ -7,6 +7,16 @@ obj-y := ex.o probe.o
+ obj-$(CONFIG_SH_FPU) += fpu.o
+ obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
+
++# CPU subtype setup
++obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
++obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
++obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
++
+ # Primary on-chip clocks (common)
+ clock-$(CONFIG_CPU_SH4) := clock-sh4.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
+diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
+index 26a27df..ac8ab57 100644
+--- a/arch/sh/kernel/cpu/sh4/ex.S
++++ b/arch/sh/kernel/cpu/sh4/ex.S
+@@ -4,7 +4,7 @@
+ * The SH-4 exception vector table.
+
+ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
+- * Copyright (C) 2003 Paul Mundt
++ * Copyright (C) 2003 - 2006 Paul Mundt
+ *
+ * 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
+@@ -53,331 +53,10 @@ ENTRY(nmi_slot)
+ #endif
+ ENTRY(user_break_point_trap)
+ .long break_point_trap /* 1E0 */
+-ENTRY(interrupt_table)
+- ! external hardware
+- .long do_IRQ ! 0000 /* 200 */
+- .long do_IRQ ! 0001
+- .long do_IRQ ! 0010
+- .long do_IRQ ! 0011
+- .long do_IRQ ! 0100
+- .long do_IRQ ! 0101
+- .long do_IRQ ! 0110
+- .long do_IRQ ! 0111
+- .long do_IRQ ! 1000 /* 300 */
+- .long do_IRQ ! 1001
+- .long do_IRQ ! 1010
+- .long do_IRQ ! 1011
+- .long do_IRQ ! 1100
+- .long do_IRQ ! 1101
+- .long do_IRQ ! 1110
+- .long exception_error
+- ! Internal hardware
+- .long do_IRQ ! TMU0 tuni0 /* 400 */
+- .long do_IRQ ! TMU1 tuni1
+- .long do_IRQ ! TMU2 tuni2
+- .long do_IRQ ! ticpi2
+-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error /* 500 */
+- .long exception_error
+- .long exception_error
+-#else
+- .long do_IRQ ! RTC ati
+- .long do_IRQ ! pri
+- .long do_IRQ ! cui
+- .long do_IRQ ! SCI eri
+- .long do_IRQ ! rxi /* 500 */
+- .long do_IRQ ! txi
+- .long do_IRQ ! tei
+-#endif
+- .long do_IRQ ! WDT iti /* 560 */
+- .long do_IRQ ! REF rcmi
+- .long do_IRQ ! rovi
+- .long do_IRQ
+- .long do_IRQ /* 5E0 */
+- .long do_IRQ ! 32 Hitachi UDI /* 600 */
+- .long do_IRQ ! 33 GPIO
+- .long do_IRQ ! 34 DMAC dmte0
+- .long do_IRQ ! 35 dmte1
+- .long do_IRQ ! 36 dmte2
+- .long do_IRQ ! 37 dmte3
+- .long do_IRQ ! 38 dmae
+- .long exception_error ! 39 /* 6E0 */
+-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+- .long exception_error /* 700 */
+- .long exception_error
+- .long exception_error
+- .long exception_error /* 760 */
+-#else
+- .long do_IRQ ! 40 SCIF eri /* 700 */
+- .long do_IRQ ! 41 rxi
+- .long do_IRQ ! 42 bri
+- .long do_IRQ ! 43 txi
+-#endif
+-#if CONFIG_NR_ONCHIP_DMA_CHANNELS == 8
+- .long do_IRQ ! 44 DMAC dmte4 /* 780 */
+- .long do_IRQ ! 45 dmte5
+- .long do_IRQ ! 46 dmte6
+- .long do_IRQ ! 47 dmte7 /* 7E0 */
+-#else
+- .long exception_error ! 44 /* 780 */
+- .long exception_error ! 45
+- .long exception_error ! 46
+- .long exception_error ! 47
+-#endif
+-#if defined(CONFIG_SH_FPU)
+- .long do_fpu_state_restore ! 48 /* 800 */
+- .long do_fpu_state_restore ! 49 /* 820 */
+-#else
+- .long exception_error
+- .long exception_error
+-#endif
+-#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+- .long exception_error /* 840 */
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error /* 900 */
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long do_IRQ ! PCI serr /* A00 */
+- .long do_IRQ ! dma3
+- .long do_IRQ ! dma2
+- .long do_IRQ ! dma1
+- .long do_IRQ ! dma0
+- .long do_IRQ ! pwon
+- .long do_IRQ ! pwdwn
+- .long do_IRQ ! err
+- .long do_IRQ ! TMU3 tuni3 /* B00 */
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long do_IRQ ! TMU4 tuni4 /* B80 */
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+- .long do_IRQ ! IRQ irq6 /* 840 */
+- .long do_IRQ ! irq7
+- .long do_IRQ ! SCIF eri0
+- .long do_IRQ ! rxi0
+- .long do_IRQ ! bri0
+- .long do_IRQ ! txi0
+- .long do_IRQ ! HCAN2 cani0 /* 900 */
+- .long do_IRQ ! cani1
+- .long do_IRQ ! SSI ssii0
+- .long do_IRQ ! ssii1
+- .long do_IRQ ! HAC haci0
+- .long do_IRQ ! haci1
+- .long do_IRQ ! IIC iici0
+- .long do_IRQ ! iici1
+- .long do_IRQ ! USB usbi /* A00 */
+- .long do_IRQ ! LCDC vint
+- .long exception_error
+- .long exception_error
+- .long do_IRQ ! DMABRG dmabrgi0
+- .long do_IRQ ! dmabrgi1
+- .long do_IRQ ! dmabrgi2
+- .long exception_error
+- .long do_IRQ ! SCIF eri1 /* B00 */
+- .long do_IRQ ! rxi1
+- .long do_IRQ ! bri1
+- .long do_IRQ ! txi1
+- .long do_IRQ ! eri2
+- .long do_IRQ ! rxi2
+- .long do_IRQ ! bri2
+- .long do_IRQ ! txi2
+- .long do_IRQ ! SIM simeri /* C00 */
+- .long do_IRQ ! simrxi
+- .long do_IRQ ! simtxi
+- .long do_IRQ ! simtei
+- .long do_IRQ ! HSPI spii
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long do_IRQ ! MMCIF mmci0 /* D00 */
+- .long do_IRQ ! mmci1
+- .long do_IRQ ! mmci2
+- .long do_IRQ ! mmci3
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error /* E00 */
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long do_IRQ ! MFI mfii
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long exception_error /* F00 */
+- .long exception_error
+- .long exception_error
+- .long exception_error
+- .long do_IRQ ! ADC adi
+- .long do_IRQ ! CMT cmti /* FA0 */
+-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
+- .long do_IRQ ! 50 0x840
+- .long do_IRQ ! 51 0x860
+- .long do_IRQ ! 52 0x880
+- .long do_IRQ ! 53 0x8a0
+- .long do_IRQ ! 54 0x8c0
+- .long do_IRQ ! 55 0x8e0
+- .long do_IRQ ! 56 0x900
+- .long do_IRQ ! 57 0x920
+- .long do_IRQ ! 58 0x940
+- .long do_IRQ ! 59 0x960
+- .long do_IRQ ! 60 0x980
+- .long do_IRQ ! 61 0x9a0
+- .long do_IRQ ! 62 0x9c0
+- .long do_IRQ ! 63 0x9e0
+- .long do_IRQ ! 64 0xa00
+- .long do_IRQ ! 65 0xa20
+- .long do_IRQ ! 66 0xa40
+- .long do_IRQ ! 67 0xa60
+- .long do_IRQ ! 68 0xa80
+- .long do_IRQ ! 69 0xaa0
+- .long do_IRQ ! 70 0xac0
+- .long do_IRQ ! 71 0xae0
+- .long do_IRQ ! 72 0xb00
+- .long do_IRQ ! 73 0xb20
+- .long do_IRQ ! 74 0xb40
+- .long do_IRQ ! 75 0xb60
+- .long do_IRQ ! 76 0xb80
+- .long do_IRQ ! 77 0xba0
+- .long do_IRQ ! 78 0xbc0
+- .long do_IRQ ! 79 0xbe0
+- .long do_IRQ ! 80 0xc00
+- .long do_IRQ ! 81 0xc20
+- .long do_IRQ ! 82 0xc40
+- .long do_IRQ ! 83 0xc60
+- .long do_IRQ ! 84 0xc80
+- .long do_IRQ ! 85 0xca0
+- .long do_IRQ ! 86 0xcc0
+- .long do_IRQ ! 87 0xce0
+- .long do_IRQ ! 88 0xd00
+- .long do_IRQ ! 89 0xd20
+- .long do_IRQ ! 90 0xd40
+- .long do_IRQ ! 91 0xd60
+- .long do_IRQ ! 92 0xd80
+- .long do_IRQ ! 93 0xda0
+- .long do_IRQ ! 94 0xdc0
+- .long do_IRQ ! 95 0xde0
+- .long do_IRQ ! 96 0xe00
+- .long do_IRQ ! 97 0xe20
+- .long do_IRQ ! 98 0xe40
+- .long do_IRQ ! 99 0xe60
+- .long do_IRQ ! 100 0xe80
+- .long do_IRQ ! 101 0xea0
+- .long do_IRQ ! 102 0xec0
+- .long do_IRQ ! 103 0xee0
+- .long do_IRQ ! 104 0xf00
+- .long do_IRQ ! 105 0xf20
+- .long do_IRQ ! 106 0xf40
+- .long do_IRQ ! 107 0xf60
+- .long do_IRQ ! 108 0xf80
+-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+- .long exception_error ! 50 0x840
+- .long exception_error ! 51 0x860
+- .long exception_error ! 52 0x880
+- .long exception_error ! 53 0x8a0
+- .long exception_error ! 54 0x8c0
+- .long exception_error ! 55 0x8e0
+- .long exception_error ! 56 0x900
+- .long exception_error ! 57 0x920
+- .long exception_error ! 58 0x940
+- .long exception_error ! 59 0x960
+- .long exception_error ! 60 0x980
+- .long exception_error ! 61 0x9a0
+- .long exception_error ! 62 0x9c0
+- .long exception_error ! 63 0x9e0
+- .long do_IRQ ! 64 0xa00 PCI serr
+- .long do_IRQ ! 65 0xa20 err
+- .long do_IRQ ! 66 0xa40 ad
+- .long do_IRQ ! 67 0xa60 pwr_dwn
+- .long exception_error ! 68 0xa80
+- .long exception_error ! 69 0xaa0
+- .long exception_error ! 70 0xac0
+- .long exception_error ! 71 0xae0
+- .long do_IRQ ! 72 0xb00 DMA INT0
+- .long do_IRQ ! 73 0xb20 INT1
+- .long do_IRQ ! 74 0xb40 INT2
+- .long do_IRQ ! 75 0xb60 INT3
+- .long do_IRQ ! 76 0xb80 INT4
+- .long exception_error ! 77 0xba0
+- .long do_IRQ ! 78 0xbc0 DMA ERR
+- .long exception_error ! 79 0xbe0
+- .long do_IRQ ! 80 0xc00 PIO0
+- .long do_IRQ ! 81 0xc20 PIO1
+- .long do_IRQ ! 82 0xc40 PIO2
+- .long exception_error ! 83 0xc60
+- .long exception_error ! 84 0xc80
+- .long exception_error ! 85 0xca0
+- .long exception_error ! 86 0xcc0
+- .long exception_error ! 87 0xce0
+- .long exception_error ! 88 0xd00
+- .long exception_error ! 89 0xd20
+- .long exception_error ! 90 0xd40
+- .long exception_error ! 91 0xd60
+- .long exception_error ! 92 0xd80
+- .long exception_error ! 93 0xda0
+- .long exception_error ! 94 0xdc0
+- .long exception_error ! 95 0xde0
+- .long exception_error ! 96 0xe00
+- .long exception_error ! 97 0xe20
+- .long exception_error ! 98 0xe40
+- .long exception_error ! 99 0xe60
+- .long exception_error ! 100 0xe80
+- .long exception_error ! 101 0xea0
+- .long exception_error ! 102 0xec0
+- .long exception_error ! 103 0xee0
+- .long exception_error ! 104 0xf00
+- .long exception_error ! 105 0xf20
+- .long exception_error ! 106 0xf40
+- .long exception_error ! 107 0xf60
+- .long exception_error ! 108 0xf80
+- .long exception_error ! 109 0xfa0
+- .long exception_error ! 110 0xfc0
+- .long exception_error ! 111 0xfe0
+- .long do_IRQ ! 112 0x1000 Mailbox
+- .long exception_error ! 113 0x1020
+- .long exception_error ! 114 0x1040
+- .long exception_error ! 115 0x1060
+- .long exception_error ! 116 0x1080
+- .long exception_error ! 117 0x10a0
+- .long exception_error ! 118 0x10c0
+- .long exception_error ! 119 0x10e0
+- .long exception_error ! 120 0x1100
+- .long exception_error ! 121 0x1120
+- .long exception_error ! 122 0x1140
+- .long exception_error ! 123 0x1160
+- .long exception_error ! 124 0x1180
+- .long exception_error ! 125 0x11a0
+- .long exception_error ! 126 0x11c0
+- .long exception_error ! 127 0x11e0
+- .long exception_error ! 128 0x1200
+- .long exception_error ! 129 0x1220
+- .long exception_error ! 130 0x1240
+- .long exception_error ! 131 0x1260
+- .long exception_error ! 132 0x1280
+- .long exception_error ! 133 0x12a0
+- .long exception_error ! 134 0x12c0
+- .long exception_error ! 135 0x12e0
+- .long exception_error ! 136 0x1300
+- .long exception_error ! 137 0x1320
+- .long exception_error ! 138 0x1340
+- .long exception_error ! 139 0x1360
+- .long do_IRQ ! 140 0x1380 EMPI INV_ADDR
+- .long exception_error ! 141 0x13a0
+- .long exception_error ! 142 0x13c0
+- .long exception_error ! 143 0x13e0
+-#endif
+
++ /*
++ * Pad the remainder of the table out, exceptions residing in far
++ * away offsets can be manually inserted in to their appropriate
++ * location via set_exception_table_{evt,vec}().
++ */
++ .balign 4096,0,4096
+diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
+index 42427b7..c294de1 100644
+--- a/arch/sh/kernel/cpu/sh4/probe.c
++++ b/arch/sh/kernel/cpu/sh4/probe.c
+@@ -3,7 +3,7 @@
+ *
+ * CPU Subtype Probing for SH-4.
+ *
+- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
++ * Copyright (C) 2001 - 2006 Paul Mundt
+ * Copyright (C) 2003 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+@@ -29,7 +29,7 @@ int __init detect_cpu_and_cache_system(v
+ [9] = (1 << 16)
+ };
+
+- pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
++ pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff;
+ prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
+ cvr = (ctrl_inl(CCN_CVR));
+
+@@ -38,7 +38,6 @@ int __init detect_cpu_and_cache_system(v
+ */
+ cpu_data->icache.way_incr = (1 << 13);
+ cpu_data->icache.entry_shift = 5;
+- cpu_data->icache.entry_mask = 0x1fe0;
+ cpu_data->icache.sets = 256;
+ cpu_data->icache.ways = 1;
+ cpu_data->icache.linesz = L1_CACHE_BYTES;
+@@ -48,13 +47,29 @@ int __init detect_cpu_and_cache_system(v
+ */
+ cpu_data->dcache.way_incr = (1 << 14);
+ cpu_data->dcache.entry_shift = 5;
+- cpu_data->dcache.entry_mask = 0x3fe0;
+ cpu_data->dcache.sets = 512;
+ cpu_data->dcache.ways = 1;
+ cpu_data->dcache.linesz = L1_CACHE_BYTES;
+
+- /* Set the FPU flag, virtually all SH-4's have one */
+- cpu_data->flags |= CPU_HAS_FPU;
++ /*
++ * Setup some generic flags we can probe
++ * (L2 and DSP detection only work on SH-4A)
++ */
++ if (((pvr >> 16) & 0xff) == 0x10) {
++ if ((cvr & 0x02000000) == 0)
++ cpu_data->flags |= CPU_HAS_L2_CACHE;
++ if ((cvr & 0x10000000) == 0)
++ cpu_data->flags |= CPU_HAS_DSP;
++
++ cpu_data->flags |= CPU_HAS_LLSC;
++ }
++
++ /* FPU detection works for everyone */
++ if ((cvr & 0x20000000) == 1)
++ cpu_data->flags |= CPU_HAS_FPU;
++
++ /* Mask off the upper chip ID */
++ pvr &= 0xffff;
+
+ /*
+ * Probe the underlying processor version/revision and
+@@ -63,56 +78,101 @@ int __init detect_cpu_and_cache_system(v
+ switch (pvr) {
+ case 0x205:
+ cpu_data->type = CPU_SH7750;
+- cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
++ cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
++ CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
+ break;
+ case 0x206:
+ cpu_data->type = CPU_SH7750S;
+- cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
++ cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
++ CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
+ break;
+ case 0x1100:
+ cpu_data->type = CPU_SH7751;
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
+ break;
+ case 0x2000:
+ cpu_data->type = CPU_SH73180;
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+- cpu_data->flags &= ~CPU_HAS_FPU;
++ cpu_data->flags |= CPU_HAS_LLSC;
++ break;
++ case 0x2001:
++ case 0x2004:
++ cpu_data->type = CPU_SH7770;
++ cpu_data->icache.ways = 4;
++ cpu_data->dcache.ways = 4;
++
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
++ break;
++ case 0x2006:
++ case 0x200A:
++ if (prr == 0x61)
++ cpu_data->type = CPU_SH7781;
++ else
++ cpu_data->type = CPU_SH7780;
++
++ cpu_data->icache.ways = 4;
++ cpu_data->dcache.ways = 4;
++
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
++ CPU_HAS_LLSC;
++ break;
++ case 0x3000:
++ case 0x3003:
++ cpu_data->type = CPU_SH7343;
++ cpu_data->icache.ways = 4;
++ cpu_data->dcache.ways = 4;
++ cpu_data->flags |= CPU_HAS_LLSC;
+ break;
+ case 0x8000:
+ cpu_data->type = CPU_ST40RA;
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
+ break;
+ case 0x8100:
+ cpu_data->type = CPU_ST40GX1;
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
+ break;
+ case 0x700:
+ cpu_data->type = CPU_SH4_501;
+ cpu_data->icache.ways = 2;
+ cpu_data->dcache.ways = 2;
+-
+- /* No FPU on the SH4-500 series.. */
+- cpu_data->flags &= ~CPU_HAS_FPU;
++ cpu_data->flags |= CPU_HAS_PTEA;
+ break;
+ case 0x600:
+ cpu_data->type = CPU_SH4_202;
+ cpu_data->icache.ways = 2;
+ cpu_data->dcache.ways = 2;
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
+ break;
+ case 0x500 ... 0x501:
+ switch (prr) {
+- case 0x10: cpu_data->type = CPU_SH7750R; break;
+- case 0x11: cpu_data->type = CPU_SH7751R; break;
+- case 0x50: cpu_data->type = CPU_SH7760; break;
++ case 0x10:
++ cpu_data->type = CPU_SH7750R;
++ break;
++ case 0x11:
++ cpu_data->type = CPU_SH7751R;
++ break;
++ case 0x50 ... 0x5f:
++ cpu_data->type = CPU_SH7760;
++ break;
+ }
+
+ cpu_data->icache.ways = 2;
+ cpu_data->dcache.ways = 2;
+
++ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
++
+ break;
+ default:
+ cpu_data->type = CPU_SH_NONE;
+ break;
+ }
+
++#ifdef CONFIG_SH_DIRECT_MAPPED
++ cpu_data->icache.ways = 1;
++ cpu_data->dcache.ways = 1;
++#endif
++
+ /*
+ * On anything that's not a direct-mapped cache, look to the CVR
+ * for I/D-cache specifics.
+@@ -121,18 +181,56 @@ int __init detect_cpu_and_cache_system(v
+ size = sizes[(cvr >> 20) & 0xf];
+ cpu_data->icache.way_incr = (size >> 1);
+ cpu_data->icache.sets = (size >> 6);
+- cpu_data->icache.entry_mask =
+- (cpu_data->icache.way_incr - (1 << 5));
++
+ }
+
++ /* Setup the rest of the I-cache info */
++ cpu_data->icache.entry_mask = cpu_data->icache.way_incr -
++ cpu_data->icache.linesz;
++
++ cpu_data->icache.way_size = cpu_data->icache.sets *
++ cpu_data->icache.linesz;
++
++ /* And the rest of the D-cache */
+ if (cpu_data->dcache.ways > 1) {
+ size = sizes[(cvr >> 16) & 0xf];
+ cpu_data->dcache.way_incr = (size >> 1);
+ cpu_data->dcache.sets = (size >> 6);
+- cpu_data->dcache.entry_mask =
+- (cpu_data->dcache.way_incr - (1 << 5));
++ }
++
++ cpu_data->dcache.entry_mask = cpu_data->dcache.way_incr -
++ cpu_data->dcache.linesz;
++
++ cpu_data->dcache.way_size = cpu_data->dcache.sets *
++ cpu_data->dcache.linesz;
++
++ /*
++ * Setup the L2 cache desc
++ *
++ * SH-4A's have an optional PIPT L2.
++ */
++ if (cpu_data->flags & CPU_HAS_L2_CACHE) {
++ /*
++ * Size calculation is much more sensible
++ * than it is for the L1.
++ *
++ * Sizes are 128KB, 258KB, 512KB, and 1MB.
++ */
++ size = (cvr & 0xf) << 17;
++
++ BUG_ON(!size);
++
++ cpu_data->scache.way_incr = (1 << 16);
++ cpu_data->scache.entry_shift = 5;
++ cpu_data->scache.ways = 4;
++ cpu_data->scache.linesz = L1_CACHE_BYTES;
++ cpu_data->scache.entry_mask =
++ (cpu_data->scache.way_incr - cpu_data->scache.linesz);
++ cpu_data->scache.sets = size /
++ (cpu_data->scache.linesz * cpu_data->scache.ways);
++ cpu_data->scache.way_size =
++ (cpu_data->scache.sets * cpu_data->scache.linesz);
+ }
+
+ return 0;
+ }
+-
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+new file mode 100644
+index 0000000..6e4e965
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+@@ -0,0 +1,43 @@
++/*
++ * SH4-202 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xffe80000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 40, 41, 43, 42 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh4202_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh4202_devices_setup(void)
++{
++ return platform_add_devices(sh4202_devices,
++ ARRAY_SIZE(sh4202_devices));
++}
++__initcall(sh4202_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh73180.c b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
+new file mode 100644
+index 0000000..cc9ea1e
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
+@@ -0,0 +1,43 @@
++/*
++ * SH73180 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xffe80000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 80, 81, 83, 82 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh73180_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh73180_devices_setup(void)
++{
++ return platform_add_devices(sh73180_devices,
++ ARRAY_SIZE(sh73180_devices));
++}
++__initcall(sh73180_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7343.c b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
+new file mode 100644
+index 0000000..91d61cf
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
+@@ -0,0 +1,43 @@
++/*
++ * SH7343 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xffe00000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 80, 81, 83, 82 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7343_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7343_devices_setup(void)
++{
++ return platform_add_devices(sh7343_devices,
++ ARRAY_SIZE(sh7343_devices));
++}
++__initcall(sh7343_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+new file mode 100644
+index 0000000..50812d5
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+@@ -0,0 +1,48 @@
++/*
++ * SH7750/SH7751 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xffe00000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCI,
++ .irqs = { 23, 24, 25, 0 },
++ }, {
++ .mapbase = 0xffe80000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 40, 41, 43, 42 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7750_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7750_devices_setup(void)
++{
++ return platform_add_devices(sh7750_devices,
++ ARRAY_SIZE(sh7750_devices));
++}
++__initcall(sh7750_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+new file mode 100644
+index 0000000..07e5377
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+@@ -0,0 +1,116 @@
++/*
++ * SH7760 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xfe600000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 52, 53, 55, 54 },
++ }, {
++ .mapbase = 0xfe610000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 72, 73, 75, 74 },
++ }, {
++ .mapbase = 0xfe620000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 76, 77, 79, 78 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7760_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7760_devices_setup(void)
++{
++ return platform_add_devices(sh7760_devices,
++ ARRAY_SIZE(sh7760_devices));
++}
++__initcall(sh7760_devices_setup);
++
++/*
++ * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0
++ */
++static struct intc2_data intc2_irq_table[] = {
++ /* INTPRIO0 | INTMSK0 */
++ {48, 0, 28, 0, 31, 3}, /* IRQ 4 */
++ {49, 0, 24, 0, 30, 3}, /* IRQ 3 */
++ {50, 0, 20, 0, 29, 3}, /* IRQ 2 */
++ {51, 0, 16, 0, 28, 3}, /* IRQ 1 */
++ /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */
++ /* INTPRIO4 | INTMSK0 */
++ {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */
++ {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */
++ {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */
++ {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */
++ {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */
++ {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */
++ {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */
++ {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */
++ /* INTPRIO8 | INTMSK0 */
++ {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */
++ {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */
++ {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */
++ {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */
++ {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */
++ {65, 8, 24, 0, 16, 3}, /* LCDC */
++ /* 66, 67 unused */
++ {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */
++ {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */
++ {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */
++ /* 71 unused */
++ {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */
++ {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */
++ {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */
++ {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */
++ {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */
++ {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */
++ {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */
++ {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */
++ /* | INTMSK4 */
++ {80, 8, 4, 4, 23, 3}, /* SIM_ERI */
++ {81, 8, 4, 4, 22, 3}, /* SIM_RXI */
++ {82, 8, 4, 4, 21, 3}, /* SIM_TXI */
++ {83, 8, 4, 4, 20, 3}, /* SIM_TEI */
++ {84, 8, 0, 4, 19, 3}, /* HSPII */
++ /* INTPRIOC | INTMSK4 */
++ /* 85-87 unused/reserved */
++ {88, 12, 20, 4, 18, 3}, /* MMCI0 */
++ {89, 12, 20, 4, 17, 3}, /* MMCI1 */
++ {90, 12, 20, 4, 16, 3}, /* MMCI2 */
++ {91, 12, 20, 4, 15, 3}, /* MMCI3 */
++ {92, 12, 12, 4, 6, 3}, /* MFI (unsure, bug? in my 7760 manual*/
++ /* 93-107 reserved/undocumented */
++ {108,12, 4, 4, 1, 3}, /* ADC */
++ {109,12, 0, 4, 0, 3}, /* CMTI */
++ /* 110-111 reserved/unused */
++};
++
++void __init init_IRQ_intc2(void)
++{
++ make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
++}
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7770.c b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
+new file mode 100644
+index 0000000..6a04cc5
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
+@@ -0,0 +1,53 @@
++/*
++ * SH7770 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xff923000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 61, 61, 61, 61 },
++ }, {
++ .mapbase = 0xff924000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 62, 62, 62, 62 },
++ }, {
++ .mapbase = 0xff925000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 63, 63, 63, 63 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7770_devices[] __initdata = {
++ &sci_device,
++};
++
++static int __init sh7770_devices_setup(void)
++{
++ return platform_add_devices(sh7770_devices,
++ ARRAY_SIZE(sh7770_devices));
++}
++__initcall(sh7770_devices_setup);
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
+new file mode 100644
+index 0000000..814ddb2
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
+@@ -0,0 +1,106 @@
++/*
++ * SH7780 Setup
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++static struct resource rtc_resources[] = {
++ [0] = {
++ .start = 0xffe80000,
++ .end = 0xffe80000 + 0x58 - 1,
++ .flags = IORESOURCE_IO,
++ },
++ [1] = {
++ /* Period IRQ */
++ .start = 21,
++ .flags = IORESOURCE_IRQ,
++ },
++ [2] = {
++ /* Carry IRQ */
++ .start = 22,
++ .flags = IORESOURCE_IRQ,
++ },
++ [3] = {
++ /* Alarm IRQ */
++ .start = 23,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device rtc_device = {
++ .name = "sh-rtc",
++ .id = -1,
++ .num_resources = ARRAY_SIZE(rtc_resources),
++ .resource = rtc_resources,
++};
++
++static struct plat_sci_port sci_platform_data[] = {
++ {
++ .mapbase = 0xffe00000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 40, 41, 43, 42 },
++ }, {
++ .mapbase = 0xffe10000,
++ .flags = UPF_BOOT_AUTOCONF,
++ .type = PORT_SCIF,
++ .irqs = { 76, 77, 79, 78 },
++ }, {
++ .flags = 0,
++ }
++};
++
++static struct platform_device sci_device = {
++ .name = "sh-sci",
++ .id = -1,
++ .dev = {
++ .platform_data = sci_platform_data,
++ },
++};
++
++static struct platform_device *sh7780_devices[] __initdata = {
++ &rtc_device,
++ &sci_device,
++};
++
++static int __init sh7780_devices_setup(void)
++{
++ return platform_add_devices(sh7780_devices,
++ ARRAY_SIZE(sh7780_devices));
++}
++__initcall(sh7780_devices_setup);
++
++static struct intc2_data intc2_irq_table[] = {
++ { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2 },
++ { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
++ { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY },
++ { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY },
++ { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
++ { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
++ { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
++ { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
++
++ { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
++ { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
++ { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
++ { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
++
++ { PCIC0_IRQ, 0x10, 8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY },
++ { PCIC1_IRQ, 0x10, 0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY },
++ { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY },
++ { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY },
++ { PCIC4_IRQ, 0x14, 8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY },
++};
++
++void __init init_IRQ_intc2(void)
++{
++ make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
++}
+diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
+index b09805f..7bcc73f 100644
+--- a/arch/sh/kernel/cpu/sh4/sq.c
++++ b/arch/sh/kernel/cpu/sh4/sq.c
+@@ -1,49 +1,52 @@
+ /*
+- * arch/sh/kernel/cpu/sq.c
++ * arch/sh/kernel/cpu/sh4/sq.c
+ *
+ * General management API for SH-4 integrated Store Queues
+ *
+- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
++ * Copyright (C) 2001 - 2006 Paul Mundt
+ * Copyright (C) 2001, 2002 M. R. Brown
+ *
+- * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
+- * hack that was part of the LinuxDC project. For all intents and purposes,
+- * this is a completely new interface that really doesn't have much in common
+- * with the old zone-based approach at all. In fact, it's only listed here for
+- * general completeness.
+- *
+ * 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/init.h>
++#include <linux/cpu.h>
++#include <linux/bitmap.h>
++#include <linux/sysdev.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+-#include <linux/list.h>
+-#include <linux/proc_fs.h>
+-#include <linux/miscdevice.h>
+ #include <linux/vmalloc.h>
+-
++#include <linux/mm.h>
+ #include <asm/io.h>
+ #include <asm/page.h>
+-#include <asm/mmu_context.h>
++#include <asm/cacheflush.h>
+ #include <asm/cpu/sq.h>
+
+-static LIST_HEAD(sq_mapping_list);
++struct sq_mapping;
++
++struct sq_mapping {
++ const char *name;
++
++ unsigned long sq_addr;
++ unsigned long addr;
++ unsigned int size;
++
++ struct sq_mapping *next;
++};
++
++static struct sq_mapping *sq_mapping_list;
+ static DEFINE_SPINLOCK(sq_mapping_lock);
++static kmem_cache_t *sq_cache;
++static unsigned long *sq_bitmap;
+
+-/**
+- * sq_flush - Flush (prefetch) the store queue cache
+- * @addr: the store queue address to flush
+- *
+- * Executes a prefetch instruction on the specified store queue cache,
+- * so that the cached data is written to physical memory.
+- */
+-inline void sq_flush(void *addr)
+-{
+- __asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
+-}
++#define store_queue_barrier() \
++do { \
++ (void)ctrl_inl(P4SEG_STORE_QUE); \
++ ctrl_outl(0, P4SEG_STORE_QUE + 0); \
++ ctrl_outl(0, P4SEG_STORE_QUE + 8); \
++} while (0);
+
+ /**
+ * sq_flush_range - Flush (prefetch) a specific SQ range
+@@ -56,152 +59,73 @@ inline void sq_flush(void *addr)
+ void sq_flush_range(unsigned long start, unsigned int len)
+ {
+ volatile unsigned long *sq = (unsigned long *)start;
+- unsigned long dummy;
+
+ /* Flush the queues */
+ for (len >>= 5; len--; sq += 8)
+- sq_flush((void *)sq);
++ prefetchw((void *)sq);
+
+ /* Wait for completion */
+- dummy = ctrl_inl(P4SEG_STORE_QUE);
+-
+- ctrl_outl(0, P4SEG_STORE_QUE + 0);
+- ctrl_outl(0, P4SEG_STORE_QUE + 8);
++ store_queue_barrier();
+ }
+
+-static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name)
++static inline void sq_mapping_list_add(struct sq_mapping *map)
+ {
+- struct sq_mapping *map;
+-
+- if (virt + size > SQ_ADDRMAX)
+- return ERR_PTR(-ENOSPC);
+-
+- map = kmalloc(sizeof(struct sq_mapping), GFP_KERNEL);
+- if (!map)
+- return ERR_PTR(-ENOMEM);
++ struct sq_mapping **p, *tmp;
+
+- INIT_LIST_HEAD(&map->list);
++ spin_lock_irq(&sq_mapping_lock);
+
+- map->sq_addr = virt;
+- map->addr = phys;
+- map->size = size + 1;
+- map->name = name;
++ p = &sq_mapping_list;
++ while ((tmp = *p) != NULL)
++ p = &tmp->next;
+
+- list_add(&map->list, &sq_mapping_list);
++ map->next = tmp;
++ *p = map;
+
+- return map;
++ spin_unlock_irq(&sq_mapping_lock);
+ }
+
+-static unsigned long __sq_get_next_addr(void)
++static inline void sq_mapping_list_del(struct sq_mapping *map)
+ {
+- if (!list_empty(&sq_mapping_list)) {
+- struct list_head *pos, *tmp;
+-
+- /*
+- * Read one off the list head, as it will have the highest
+- * mapped allocation. Set the next one up right above it.
+- *
+- * This is somewhat sub-optimal, as we don't look at
+- * gaps between allocations or anything lower then the
+- * highest-level allocation.
+- *
+- * However, in the interest of performance and the general
+- * lack of desire to do constant list rebalancing, we don't
+- * worry about it.
+- */
+- list_for_each_safe(pos, tmp, &sq_mapping_list) {
+- struct sq_mapping *entry;
+-
+- entry = list_entry(pos, typeof(*entry), list);
+-
+- return entry->sq_addr + entry->size;
++ struct sq_mapping **p, *tmp;
++
++ spin_lock_irq(&sq_mapping_lock);
++
++ for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next)
++ if (tmp == map) {
++ *p = tmp->next;
++ break;
+ }
+- }
+
+- return P4SEG_STORE_QUE;
++ spin_unlock_irq(&sq_mapping_lock);
+ }
+
+-/**
+- * __sq_remap - Perform a translation from the SQ to a phys addr
+- * @map: sq mapping containing phys and store queue addresses.
+- *
+- * Maps the store queue address specified in the mapping to the physical
+- * address specified in the mapping.
+- */
+-static struct sq_mapping *__sq_remap(struct sq_mapping *map)
++static int __sq_remap(struct sq_mapping *map, unsigned long flags)
+ {
+- unsigned long flags, pteh, ptel;
++#if defined(CONFIG_MMU)
+ struct vm_struct *vma;
+- pgprot_t pgprot;
+-
+- /*
+- * Without an MMU (or with it turned off), this is much more
+- * straightforward, as we can just load up each queue's QACR with
+- * the physical address appropriately masked.
+- */
+-
+- ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
+- ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
+
+-#ifdef CONFIG_MMU
+- /*
+- * With an MMU on the other hand, things are slightly more involved.
+- * Namely, we have to have a direct mapping between the SQ addr and
+- * the associated physical address in the UTLB by way of setting up
+- * a virt<->phys translation by hand. We do this by simply specifying
+- * the SQ addr in UTLB.VPN and the associated physical address in
+- * UTLB.PPN.
+- *
+- * Notably, even though this is a special case translation, and some
+- * of the configuration bits are meaningless, we're still required
+- * to have a valid ASID context in PTEH.
+- *
+- * We could also probably get by without explicitly setting PTEA, but
+- * we do it here just for good measure.
+- */
+- spin_lock_irqsave(&sq_mapping_lock, flags);
+-
+- pteh = map->sq_addr;
+- ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
+-
+- ptel = map->addr & PAGE_MASK;
+- ctrl_outl(((ptel >> 28) & 0xe) | (ptel & 0x1), MMU_PTEA);
+-
+- pgprot = pgprot_noncached(PAGE_KERNEL);
+-
+- ptel &= _PAGE_FLAGS_HARDWARE_MASK;
+- ptel |= pgprot_val(pgprot);
+- ctrl_outl(ptel, MMU_PTEL);
+-
+- __asm__ __volatile__ ("ldtlb" : : : "memory");
+-
+- spin_unlock_irqrestore(&sq_mapping_lock, flags);
+-
+- /*
+- * Next, we need to map ourselves in the kernel page table, so that
+- * future accesses after a TLB flush will be handled when we take a
+- * page fault.
+- *
+- * Theoretically we could just do this directly and not worry about
+- * setting up the translation by hand ahead of time, but for the
+- * cases where we want a one-shot SQ mapping followed by a quick
+- * writeout before we hit the TLB flush, we do it anyways. This way
+- * we at least save ourselves the initial page fault overhead.
+- */
+ vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
+ if (!vma)
+- return ERR_PTR(-ENOMEM);
++ return -ENOMEM;
+
+ vma->phys_addr = map->addr;
+
+ if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
+- map->size, pgprot_val(pgprot))) {
++ map->size, flags)) {
+ vunmap(vma->addr);
+- return NULL;
++ return -EAGAIN;
+ }
+-#endif /* CONFIG_MMU */
++#else
++ /*
++ * Without an MMU (or with it turned off), this is much more
++ * straightforward, as we can just load up each queue's QACR with
++ * the physical address appropriately masked.
++ */
++ ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
++ ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
++#endif
+
+- return map;
++ return 0;
+ }
+
+ /**
+@@ -209,42 +133,65 @@ static struct sq_mapping *__sq_remap(str
+ * @phys: Physical address of mapping.
+ * @size: Length of mapping.
+ * @name: User invoking mapping.
++ * @flags: Protection flags.
+ *
+ * Remaps the physical address @phys through the next available store queue
+ * address of @size length. @name is logged at boot time as well as through
+- * the procfs interface.
+- *
+- * A pre-allocated and filled sq_mapping pointer is returned, and must be
+- * cleaned up with a call to sq_unmap() when the user is done with the
+- * mapping.
++ * the sysfs interface.
+ */
+-struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name)
++unsigned long sq_remap(unsigned long phys, unsigned int size,
++ const char *name, unsigned long flags)
+ {
+ struct sq_mapping *map;
+- unsigned long virt, end;
++ unsigned long end;
+ unsigned int psz;
++ int ret, page;
+
+ /* Don't allow wraparound or zero size */
+ end = phys + size - 1;
+- if (!size || end < phys)
+- return NULL;
++ if (unlikely(!size || end < phys))
++ return -EINVAL;
+ /* Don't allow anyone to remap normal memory.. */
+- if (phys < virt_to_phys(high_memory))
+- return NULL;
++ if (unlikely(phys < virt_to_phys(high_memory)))
++ return -EINVAL;
+
+ phys &= PAGE_MASK;
++ size = PAGE_ALIGN(end + 1) - phys;
++
++ map = kmem_cache_alloc(sq_cache, GFP_KERNEL);
++ if (unlikely(!map))
++ return -ENOMEM;
++
++ map->addr = phys;
++ map->size = size;
++ map->name = name;
++
++ page = bitmap_find_free_region(sq_bitmap, 0x04000000,
++ get_order(map->size));
++ if (unlikely(page < 0)) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
++
++ ret = __sq_remap(map, flags);
++ if (unlikely(ret != 0))
++ goto out;
++
++ psz = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++ pr_info("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
++ likely(map->name) ? map->name : "???",
++ psz, psz == 1 ? " " : "s",
++ map->sq_addr, map->addr);
+
+- size = PAGE_ALIGN(end + 1) - phys;
+- virt = __sq_get_next_addr();
+- psz = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
+- map = __sq_alloc_mapping(virt, phys, size, name);
++ sq_mapping_list_add(map);
+
+- printk("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
+- map->name ? map->name : "???",
+- psz, psz == 1 ? " " : "s",
+- map->sq_addr, map->addr);
++ return map->sq_addr;
+
+- return __sq_remap(map);
++out:
++ kmem_cache_free(sq_cache, map);
++ return ret;
+ }
+
+ /**
+@@ -255,188 +202,198 @@ struct sq_mapping *sq_remap(unsigned lon
+ * sq_remap(). Also frees up the pte that was previously inserted into
+ * the kernel page table and discards the UTLB translation.
+ */
+-void sq_unmap(struct sq_mapping *map)
++void sq_unmap(unsigned long vaddr)
+ {
+- if (map->sq_addr > (unsigned long)high_memory)
+- vfree((void *)(map->sq_addr & PAGE_MASK));
++ struct sq_mapping **p, *map;
++ struct vm_struct *vma;
++ int page;
+
+- list_del(&map->list);
+- kfree(map);
+-}
++ for (p = &sq_mapping_list; (map = *p); p = &map->next)
++ if (map->sq_addr == vaddr)
++ break;
+
+-/**
+- * sq_clear - Clear a store queue range
+- * @addr: Address to start clearing from.
+- * @len: Length to clear.
+- *
+- * A quick zero-fill implementation for clearing out memory that has been
+- * remapped through the store queues.
+- */
+-void sq_clear(unsigned long addr, unsigned int len)
+-{
+- int i;
++ if (unlikely(!map)) {
++ printk("%s: bad store queue address 0x%08lx\n",
++ __FUNCTION__, vaddr);
++ return;
++ }
+
+- /* Clear out both queues linearly */
+- for (i = 0; i < 8; i++) {
+- ctrl_outl(0, addr + i + 0);
+- ctrl_outl(0, addr + i + 8);
++ page = (map->sq_addr - P4SEG_STORE_QUE) >> PAGE_SHIFT;
++ bitmap_release_region(sq_bitmap, page, get_order(map->size));
++
++#ifdef CONFIG_MMU
++ vma = remove_vm_area((void *)(map->sq_addr & PAGE_MASK));
++ if (!vma) {
++ printk(KERN_ERR "%s: bad address 0x%08lx\n",
++ __FUNCTION__, map->sq_addr);
++ return;
+ }
++#endif
++
++ sq_mapping_list_del(map);
+
+- sq_flush_range(addr, len);
++ kmem_cache_free(sq_cache, map);
+ }
+
+-/**
+- * sq_vma_unmap - Unmap a VMA range
+- * @area: VMA containing range.
+- * @addr: Start of range.
+- * @len: Length of range.
++/*
++ * Needlessly complex sysfs interface. Unfortunately it doesn't seem like
++ * there is any other easy way to add things on a per-cpu basis without
++ * putting the directory entries somewhere stupid and having to create
++ * links in sysfs by hand back in to the per-cpu directories.
+ *
+- * Searches the sq_mapping_list for a mapping matching the sq addr @addr,
+- * and subsequently frees up the entry. Further cleanup is done by generic
+- * code.
++ * Some day we may want to have an additional abstraction per store
++ * queue, but considering the kobject hell we already have to deal with,
++ * it's simply not worth the trouble.
+ */
+-static void sq_vma_unmap(struct vm_area_struct *area,
+- unsigned long addr, size_t len)
+-{
+- struct list_head *pos, *tmp;
++static struct kobject *sq_kobject[NR_CPUS];
+
+- list_for_each_safe(pos, tmp, &sq_mapping_list) {
+- struct sq_mapping *entry;
++struct sq_sysfs_attr {
++ struct attribute attr;
++ ssize_t (*show)(char *buf);
++ ssize_t (*store)(const char *buf, size_t count);
++};
+
+- entry = list_entry(pos, typeof(*entry), list);
++#define to_sq_sysfs_attr(attr) container_of(attr, struct sq_sysfs_attr, attr)
+
+- if (entry->sq_addr == addr) {
+- /*
+- * We could probably get away without doing the tlb flush
+- * here, as generic code should take care of most of this
+- * when unmapping the rest of the VMA range for us. Leave
+- * it in for added sanity for the time being..
+- */
+- __flush_tlb_page(get_asid(), entry->sq_addr & PAGE_MASK);
++static ssize_t sq_sysfs_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
+
+- list_del(&entry->list);
+- kfree(entry);
++ if (likely(sattr->show))
++ return sattr->show(buf);
+
+- return;
+- }
+- }
++ return -EIO;
+ }
+
+-/**
+- * sq_vma_sync - Sync a VMA range
+- * @area: VMA containing range.
+- * @start: Start of range.
+- * @len: Length of range.
+- * @flags: Additional flags.
+- *
+- * Synchronizes an sq mapped range by flushing the store queue cache for
+- * the duration of the mapping.
+- *
+- * Used internally for user mappings, which must use msync() to prefetch
+- * the store queue cache.
+- */
+-static int sq_vma_sync(struct vm_area_struct *area,
+- unsigned long start, size_t len, unsigned int flags)
++static ssize_t sq_sysfs_store(struct kobject *kobj, struct attribute *attr,
++ const char *buf, size_t count)
+ {
+- sq_flush_range(start, len);
++ struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
+
+- return 0;
++ if (likely(sattr->store))
++ return sattr->store(buf, count);
++
++ return -EIO;
+ }
+
+-static struct vm_operations_struct sq_vma_ops = {
+- .unmap = sq_vma_unmap,
+- .sync = sq_vma_sync,
+-};
++static ssize_t mapping_show(char *buf)
++{
++ struct sq_mapping **list, *entry;
++ char *p = buf;
+
+-/**
+- * sq_mmap - mmap() for /dev/cpu/sq
+- * @file: unused.
+- * @vma: VMA to remap.
+- *
+- * Remap the specified vma @vma through the store queues, and setup associated
+- * information for the new mapping. Also build up the page tables for the new
+- * area.
+- */
+-static int sq_mmap(struct file *file, struct vm_area_struct *vma)
++ for (list = &sq_mapping_list; (entry = *list); list = &entry->next)
++ p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n",
++ entry->sq_addr, entry->sq_addr + entry->size,
++ entry->addr, entry->name);
++
++ return p - buf;
++}
++
++static ssize_t mapping_store(const char *buf, size_t count)
+ {
+- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+- unsigned long size = vma->vm_end - vma->vm_start;
+- struct sq_mapping *map;
++ unsigned long base = 0, len = 0;
+
+- /*
+- * We're not interested in any arbitrary virtual address that has
+- * been stuck in the VMA, as we already know what addresses we
+- * want. Save off the size, and reposition the VMA to begin at
+- * the next available sq address.
+- */
+- vma->vm_start = __sq_get_next_addr();
+- vma->vm_end = vma->vm_start + size;
++ sscanf(buf, "%lx %lx", &base, &len);
++ if (!base)
++ return -EIO;
+
+- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++ if (likely(len)) {
++ int ret = sq_remap(base, len, "Userspace",
++ pgprot_val(PAGE_SHARED));
++ if (ret < 0)
++ return ret;
++ } else
++ sq_unmap(base);
+
+- vma->vm_flags |= VM_IO | VM_RESERVED;
++ return count;
++}
+
+- map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace");
++static struct sq_sysfs_attr mapping_attr =
++ __ATTR(mapping, 0644, mapping_show, mapping_store);
+
+- if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- return -EAGAIN;
++static struct attribute *sq_sysfs_attrs[] = {
++ &mapping_attr.attr,
++ NULL,
++};
+
+- vma->vm_ops = &sq_vma_ops;
++static struct sysfs_ops sq_sysfs_ops = {
++ .show = sq_sysfs_show,
++ .store = sq_sysfs_store,
++};
+
+- return 0;
+-}
++static struct kobj_type ktype_percpu_entry = {
++ .sysfs_ops = &sq_sysfs_ops,
++ .default_attrs = sq_sysfs_attrs,
++};
+
+-#ifdef CONFIG_PROC_FS
+-static int sq_mapping_read_proc(char *buf, char **start, off_t off,
+- int len, int *eof, void *data)
++static int __devinit sq_sysdev_add(struct sys_device *sysdev)
+ {
+- struct list_head *pos;
+- char *p = buf;
++ unsigned int cpu = sysdev->id;
++ struct kobject *kobj;
+
+- list_for_each_prev(pos, &sq_mapping_list) {
+- struct sq_mapping *entry;
++ sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
++ if (unlikely(!sq_kobject[cpu]))
++ return -ENOMEM;
+
+- entry = list_entry(pos, typeof(*entry), list);
++ kobj = sq_kobject[cpu];
++ kobj->parent = &sysdev->kobj;
++ kobject_set_name(kobj, "%s", "sq");
++ kobj->ktype = &ktype_percpu_entry;
+
+- p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n", entry->sq_addr,
+- entry->sq_addr + entry->size - 1, entry->addr,
+- entry->name);
+- }
+-
+- return p - buf;
++ return kobject_register(kobj);
+ }
+-#endif
+
+-static struct file_operations sq_fops = {
+- .owner = THIS_MODULE,
+- .mmap = sq_mmap,
+-};
++static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
++{
++ unsigned int cpu = sysdev->id;
++ struct kobject *kobj = sq_kobject[cpu];
+
+-static struct miscdevice sq_dev = {
+- .minor = STORE_QUEUE_MINOR,
+- .name = "sq",
+- .fops = &sq_fops,
++ kobject_unregister(kobj);
++ return 0;
++}
++
++static struct sysdev_driver sq_sysdev_driver = {
++ .add = sq_sysdev_add,
++ .remove = __devexit_p(sq_sysdev_remove),
+ };
+
+ static int __init sq_api_init(void)
+ {
+- int ret;
++ unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT;
++ unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
++ int ret = -ENOMEM;
++
+ printk(KERN_NOTICE "sq: Registering store queue API.\n");
+
+- create_proc_read_entry("sq_mapping", 0, 0, sq_mapping_read_proc, 0);
++ sq_cache = kmem_cache_create("store_queue_cache",
++ sizeof(struct sq_mapping), 0, 0,
++ NULL, NULL);
++ if (unlikely(!sq_cache))
++ return ret;
+
+- ret = misc_register(&sq_dev);
+- if (ret)
+- remove_proc_entry("sq_mapping", NULL);
++ sq_bitmap = kzalloc(size, GFP_KERNEL);
++ if (unlikely(!sq_bitmap))
++ goto out;
++
++ ret = sysdev_driver_register(&cpu_sysdev_class, &sq_sysdev_driver);
++ if (unlikely(ret != 0))
++ goto out;
++
++ return 0;
++
++out:
++ kfree(sq_bitmap);
++ kmem_cache_destroy(sq_cache);
+
+ return ret;
+ }
+
+ static void __exit sq_api_exit(void)
+ {
+- misc_deregister(&sq_dev);
+- remove_proc_entry("sq_mapping", NULL);
++ sysdev_driver_unregister(&cpu_sysdev_class, &sq_sysdev_driver);
++ kfree(sq_bitmap);
++ kmem_cache_destroy(sq_cache);
+ }
+
+ module_init(sq_api_init);
+@@ -445,11 +402,7 @@ module_exit(sq_api_exit);
+ MODULE_AUTHOR("Paul Mundt <lethal at linux-sh.org>, M. R. Brown <mrbrown at 0xd6.org>");
+ MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
+ MODULE_LICENSE("GPL");
+-MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR);
+
+ EXPORT_SYMBOL(sq_remap);
+ EXPORT_SYMBOL(sq_unmap);
+-EXPORT_SYMBOL(sq_clear);
+-EXPORT_SYMBOL(sq_flush);
+ EXPORT_SYMBOL(sq_flush_range);
+-
+diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
+index 0c569b2..8192307 100644
+--- a/arch/sh/kernel/cpu/ubc.S
++++ b/arch/sh/kernel/cpu/ubc.S
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh/kernel/ubc.S
++ * arch/sh/kernel/cpu/ubc.S
+ *
+ * Set of management routines for the User Break Controller (UBC)
+ *
+diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
+index 1378db3..a000227 100644
+--- a/arch/sh/kernel/early_printk.c
++++ b/arch/sh/kernel/early_printk.c
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1999, 2000 Niibe Yutaka
+ * Copyright (C) 2002 M. R. Brown
+- * Copyright (C) 2004 Paul Mundt
++ * Copyright (C) 2004 - 2006 Paul Mundt
+ *
+ * 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
+@@ -49,7 +49,7 @@ static int __init sh_console_setup(struc
+ return 0;
+ }
+
+-static struct console early_console = {
++static struct console bios_console = {
+ .name = "bios",
+ .write = sh_console_write,
+ .setup = sh_console_setup,
+@@ -59,34 +59,43 @@ static struct console early_console = {
+ #endif
+
+ #ifdef CONFIG_EARLY_SCIF_CONSOLE
++#include <linux/serial_core.h>
++#include "../../../drivers/serial/sh-sci.h"
++
++#ifdef CONFIG_CPU_SH4
+ #define SCIF_REG 0xffe80000
++#elif defined(CONFIG_CPU_SUBTYPE_SH72060)
++#define SCIF_REG 0xfffe9800
++#else
++#error "Undefined SCIF for this subtype"
++#endif
++
++static struct uart_port scif_port = {
++ .mapbase = SCIF_REG,
++ .membase = (char __iomem *)SCIF_REG,
++};
+
+ static void scif_sercon_putc(int c)
+ {
+- while (!(ctrl_inw(SCIF_REG + 0x10) & 0x20)) ;
++ while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16))
++ ;
+
+- ctrl_outb(c, SCIF_REG + 12);
+- ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0x9f), SCIF_REG + 0x10);
++ sci_out(&scif_port, SCxTDR, c);
++ sci_in(&scif_port, SCxSR);
++ sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40));
++
++ while ((sci_in(&scif_port, SCxSR) & 0x40) == 0);
++ ;
+
+ if (c == '\n')
+ scif_sercon_putc('\r');
+ }
+
+-static void scif_sercon_flush(void)
+-{
+- ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
+-
+- while (!(ctrl_inw(SCIF_REG + 0x10) & 0x40)) ;
+-
+- ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
+-}
+-
+-static void scif_sercon_write(struct console *con, const char *s, unsigned count)
++static void scif_sercon_write(struct console *con, const char *s,
++ unsigned count)
+ {
+ while (count-- > 0)
+ scif_sercon_putc(*s++);
+-
+- scif_sercon_flush();
+ }
+
+ static int __init scif_sercon_setup(struct console *con, char *options)
+@@ -96,7 +105,7 @@ static int __init scif_sercon_setup(stru
+ return 0;
+ }
+
+-static struct console early_console = {
++static struct console scif_console = {
+ .name = "sercon",
+ .write = scif_sercon_write,
+ .setup = scif_sercon_setup,
+@@ -104,7 +113,7 @@ static struct console early_console = {
+ .index = -1,
+ };
+
+-void scif_sercon_init(int baud)
++static void scif_sercon_init(int baud)
+ {
+ ctrl_outw(0, SCIF_REG + 8);
+ ctrl_outw(0, SCIF_REG);
+@@ -122,16 +131,61 @@ void scif_sercon_init(int baud)
+ }
+ #endif
+
+-void __init enable_early_printk(void)
++/*
++ * Setup a default console, if more than one is compiled in, rely on the
++ * earlyprintk= parsing to give priority.
++ */
++static struct console *early_console =
++#ifdef CONFIG_SH_STANDARD_BIOS
++ &bios_console
++#elif defined(CONFIG_EARLY_SCIF_CONSOLE)
++ &scif_console
++#else
++ NULL
++#endif
++ ;
++
++static int __initdata keep_early;
++
++int __init setup_early_printk(char *opt)
+ {
+-#ifdef CONFIG_EARLY_SCIF_CONSOLE
+- scif_sercon_init(115200);
++ char *space;
++ char buf[256];
++
++ strlcpy(buf, opt, sizeof(buf));
++ space = strchr(buf, ' ');
++ if (space)
++ *space = 0;
++
++ if (strstr(buf, "keep"))
++ keep_early = 1;
++
++#ifdef CONFIG_SH_STANDARD_BIOS
++ if (!strncmp(buf, "bios", 4))
++ early_console = &bios_console;
++#endif
++#if defined(CONFIG_EARLY_SCIF_CONSOLE)
++ if (!strncmp(buf, "serial", 6)) {
++ early_console = &scif_console;
++
++#ifdef CONFIG_CPU_SH4
++ scif_sercon_init(115200);
++#endif
++ }
+ #endif
+- register_console(&early_console);
++
++ if (likely(early_console))
++ register_console(early_console);
++
++ return 1;
+ }
++__setup("earlyprintk=", setup_early_printk);
+
+-void disable_early_printk(void)
++void __init disable_early_printk(void)
+ {
+- unregister_console(&early_console);
++ if (!keep_early) {
++ printk("disabling early console\n");
++ unregister_console(early_console);
++ } else
++ printk("keeping early console\n");
+ }
+-
+diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
+index 7dfd2ba..39aaefb 100644
+--- a/arch/sh/kernel/entry.S
++++ b/arch/sh/kernel/entry.S
+@@ -1,41 +1,22 @@
+-/* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $
+- *
++/*
+ * linux/arch/sh/entry.S
+ *
+ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
+- * Copyright (C) 2003 Paul Mundt
++ * Copyright (C) 2003 - 2006 Paul Mundt
+ *
+ * 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/sys.h>
++#include <linux/errno.h>
+ #include <linux/linkage.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/thread_info.h>
+ #include <asm/cpu/mmu_context.h>
+ #include <asm/unistd.h>
+
+-#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
+-#define sys_nfsservctl sys_ni_syscall
+-#endif
+-
+-#if !defined(CONFIG_MMU)
+-#define sys_madvise sys_ni_syscall
+-#define sys_readahead sys_ni_syscall
+-#define sys_mprotect sys_ni_syscall
+-#define sys_msync sys_ni_syscall
+-#define sys_mlock sys_ni_syscall
+-#define sys_munlock sys_ni_syscall
+-#define sys_mlockall sys_ni_syscall
+-#define sys_munlockall sys_ni_syscall
+-#define sys_mremap sys_ni_syscall
+-#define sys_mincore sys_ni_syscall
+-#define sys_remap_file_pages sys_ni_syscall
+-#endif
+-
+ ! NOTE:
+ ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
+ ! to be jumped is too far, but it causes illegal slot exception.
+@@ -71,10 +52,6 @@
+ * syscall #
+ *
+ */
+-
+-ENOSYS = 38
+-EINVAL = 22
+-
+ #if defined(CONFIG_KGDB_NMI)
+ NMI_VEC = 0x1c0 ! Must catch early for debounce
+ #endif
+@@ -100,7 +77,6 @@ OFF_TRA = (16*4+6*4)
+ #define k3 r3
+ #define k4 r4
+
+-#define k_ex_code r2_bank /* r2_bank1 */
+ #define g_imask r6 /* r6_bank1 */
+ #define k_g_imask r6_bank /* r6_bank1 */
+ #define current r7 /* r7_bank1 */
+@@ -326,7 +302,7 @@ ENTRY(exception_error)
+ .align 2
+ ret_from_exception:
+ preempt_stop()
+-ret_from_irq:
++ENTRY(ret_from_irq)
+ !
+ mov #OFF_SR, r0
+ mov.l @(r0,r15), r0 ! get status register
+@@ -389,11 +365,12 @@ work_pending:
+ ! r8: current_thread_info
+ ! t: result of "tst #_TIF_NEED_RESCHED, r0"
+ bf/s work_resched
+- tst #_TIF_SIGPENDING, r0
++ tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
+ work_notifysig:
+ bt/s restore_all
+ mov r15, r4
+- mov #0, r5
++ mov r12, r5 ! set arg1(save_r0)
++ mov r0, r6
+ mov.l 2f, r1
+ mova restore_all, r0
+ jmp @r1
+@@ -431,7 +408,7 @@ work_resched:
+
+ .align 2
+ 1: .long schedule
+-2: .long do_signal
++2: .long do_notify_resume
+
+ .align 2
+ syscall_exit_work:
+@@ -552,6 +529,7 @@ syscall_call:
+ mov.l @r9, r8
+ jsr @r8 ! jump to specific syscall handler
+ nop
++ mov.l @(OFF_R0,r15), r12 ! save r0
+ mov.l r0, @(OFF_R0,r15) ! save the return value
+ !
+ syscall_exit:
+@@ -644,7 +622,7 @@ skip_restore:
+ !
+ #if defined(CONFIG_KGDB_NMI)
+ ! Clear in_nmi
+- mov.l 4f, k0
++ mov.l 6f, k0
+ mov #0, k1
+ mov.b k1, @k0
+ #endif
+@@ -711,7 +689,7 @@ interrupt:
+ 0:
+ #endif /* defined(CONFIG_KGDB_NMI) */
+ bra handle_exception
+- mov.l @k2, k2
++ mov #-1, k2 ! interrupt exception marker
+
+ .align 2
+ 1: .long EXPEVT
+@@ -722,7 +700,7 @@ interrupt:
+ !
+ !
+ .align 2
+-handle_exception:
++ENTRY(handle_exception)
+ ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
+ ! save all registers onto stack.
+ !
+@@ -732,13 +710,12 @@ handle_exception:
+ bt/s 1f ! It's a kernel to kernel transition.
+ mov r15, k0 ! save original stack to k0
+ /* User space to kernel */
+- mov #0x20, k1
+- shll8 k1 ! k1 := 8192 (== THREAD_SIZE)
++ mov #(THREAD_SIZE >> 8), k1
++ shll8 k1 ! k1 := THREAD_SIZE
+ add current, k1
+ mov k1, r15 ! change to kernel stack
+ !
+-1: mov #-1, k4
+- mov.l 2f, k1
++1: mov.l 2f, k1
+ !
+ #ifdef CONFIG_SH_DSP
+ mov.l r2, @-r15 ! Save r2, we need another reg
+@@ -783,6 +760,8 @@ skip_save:
+ #endif
+ ! Save the user registers on the stack.
+ mov.l k2, @-r15 ! EXPEVT
++
++ mov #-1, k4
+ mov.l k4, @-r15 ! set TRA (default: -1)
+ !
+ sts.l macl, @-r15
+@@ -817,8 +796,21 @@ skip_save:
+ mov.l r2, @-r15
+ mov.l r1, @-r15
+ mov.l r0, @-r15
+- ! Then, dispatch to the handler, according to the exception code.
+- stc k_ex_code, r8
++
++ /*
++ * This gets a bit tricky.. in the INTEVT case we don't want to use
++ * the VBR offset as a destination in the jump call table, since all
++ * of the destinations are the same. In this case, (interrupt) sets
++ * a marker in r2 (now r2_bank since SR.RB changed), which we check
++ * to determine the exception type. For all other exceptions, we
++ * forcibly read EXPEVT from memory and fix up the jump address, in
++ * the interrupt exception case we jump to do_IRQ() and defer the
++ * INTEVT read until there. As a bonus, we can also clean up the SR.RB
++ * checks that do_IRQ() was doing..
++ */
++ stc r2_bank, r8
++ cmp/pz r8
++ bf interrupt_exception
+ shlr2 r8
+ shlr r8
+ mov.l 4f, r9
+@@ -826,6 +818,8 @@ skip_save:
+ mov.l @r9, r9
+ jmp @r9
+ nop
++ rts
++ nop
+
+ .align 2
+ 1: .long 0x00001000 ! DSP=1
+@@ -833,305 +827,17 @@ skip_save:
+ 3: .long 0xcfffffff ! RB=0, BL=0
+ 4: .long exception_handling_table
+
++interrupt_exception:
++ mov.l 1f, r9
++ jmp @r9
++ nop
++ rts
++ nop
++
++ .align 2
++1: .long do_IRQ
++
+ .align 2
+ ENTRY(exception_none)
+ rts
+ nop
+-
+- .data
+-ENTRY(sys_call_table)
+- .long sys_ni_syscall /* 0 - old "setup()" system call*/
+- .long sys_exit
+- .long sys_fork
+- .long sys_read
+- .long sys_write
+- .long sys_open /* 5 */
+- .long sys_close
+- .long sys_waitpid
+- .long sys_creat
+- .long sys_link
+- .long sys_unlink /* 10 */
+- .long sys_execve
+- .long sys_chdir
+- .long sys_time
+- .long sys_mknod
+- .long sys_chmod /* 15 */
+- .long sys_lchown16
+- .long sys_ni_syscall /* old break syscall holder */
+- .long sys_stat
+- .long sys_lseek
+- .long sys_getpid /* 20 */
+- .long sys_mount
+- .long sys_oldumount
+- .long sys_setuid16
+- .long sys_getuid16
+- .long sys_stime /* 25 */
+- .long sys_ptrace
+- .long sys_alarm
+- .long sys_fstat
+- .long sys_pause
+- .long sys_utime /* 30 */
+- .long sys_ni_syscall /* old stty syscall holder */
+- .long sys_ni_syscall /* old gtty syscall holder */
+- .long sys_access
+- .long sys_nice
+- .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
+- .long sys_sync
+- .long sys_kill
+- .long sys_rename
+- .long sys_mkdir
+- .long sys_rmdir /* 40 */
+- .long sys_dup
+- .long sys_pipe
+- .long sys_times
+- .long sys_ni_syscall /* old prof syscall holder */
+- .long sys_brk /* 45 */
+- .long sys_setgid16
+- .long sys_getgid16
+- .long sys_signal
+- .long sys_geteuid16
+- .long sys_getegid16 /* 50 */
+- .long sys_acct
+- .long sys_umount /* recycled never used phys() */
+- .long sys_ni_syscall /* old lock syscall holder */
+- .long sys_ioctl
+- .long sys_fcntl /* 55 */
+- .long sys_ni_syscall /* old mpx syscall holder */
+- .long sys_setpgid
+- .long sys_ni_syscall /* old ulimit syscall holder */
+- .long sys_ni_syscall /* sys_olduname */
+- .long sys_umask /* 60 */
+- .long sys_chroot
+- .long sys_ustat
+- .long sys_dup2
+- .long sys_getppid
+- .long sys_getpgrp /* 65 */
+- .long sys_setsid
+- .long sys_sigaction
+- .long sys_sgetmask
+- .long sys_ssetmask
+- .long sys_setreuid16 /* 70 */
+- .long sys_setregid16
+- .long sys_sigsuspend
+- .long sys_sigpending
+- .long sys_sethostname
+- .long sys_setrlimit /* 75 */
+- .long sys_old_getrlimit
+- .long sys_getrusage
+- .long sys_gettimeofday
+- .long sys_settimeofday
+- .long sys_getgroups16 /* 80 */
+- .long sys_setgroups16
+- .long sys_ni_syscall /* sys_oldselect */
+- .long sys_symlink
+- .long sys_lstat
+- .long sys_readlink /* 85 */
+- .long sys_uselib
+- .long sys_swapon
+- .long sys_reboot
+- .long old_readdir
+- .long old_mmap /* 90 */
+- .long sys_munmap
+- .long sys_truncate
+- .long sys_ftruncate
+- .long sys_fchmod
+- .long sys_fchown16 /* 95 */
+- .long sys_getpriority
+- .long sys_setpriority
+- .long sys_ni_syscall /* old profil syscall holder */
+- .long sys_statfs
+- .long sys_fstatfs /* 100 */
+- .long sys_ni_syscall /* ioperm */
+- .long sys_socketcall
+- .long sys_syslog
+- .long sys_setitimer
+- .long sys_getitimer /* 105 */
+- .long sys_newstat
+- .long sys_newlstat
+- .long sys_newfstat
+- .long sys_uname
+- .long sys_ni_syscall /* 110 */ /* iopl */
+- .long sys_vhangup
+- .long sys_ni_syscall /* idle */
+- .long sys_ni_syscall /* vm86old */
+- .long sys_wait4
+- .long sys_swapoff /* 115 */
+- .long sys_sysinfo
+- .long sys_ipc
+- .long sys_fsync
+- .long sys_sigreturn
+- .long sys_clone /* 120 */
+- .long sys_setdomainname
+- .long sys_newuname
+- .long sys_ni_syscall /* sys_modify_ldt */
+- .long sys_adjtimex
+- .long sys_mprotect /* 125 */
+- .long sys_sigprocmask
+- .long sys_ni_syscall /* old "create_module" */
+- .long sys_init_module
+- .long sys_delete_module
+- .long sys_ni_syscall /* 130: old "get_kernel_syms" */
+- .long sys_quotactl
+- .long sys_getpgid
+- .long sys_fchdir
+- .long sys_bdflush
+- .long sys_sysfs /* 135 */
+- .long sys_personality
+- .long sys_ni_syscall /* for afs_syscall */
+- .long sys_setfsuid16
+- .long sys_setfsgid16
+- .long sys_llseek /* 140 */
+- .long sys_getdents
+- .long sys_select
+- .long sys_flock
+- .long sys_msync
+- .long sys_readv /* 145 */
+- .long sys_writev
+- .long sys_getsid
+- .long sys_fdatasync
+- .long sys_sysctl
+- .long sys_mlock /* 150 */
+- .long sys_munlock
+- .long sys_mlockall
+- .long sys_munlockall
+- .long sys_sched_setparam
+- .long sys_sched_getparam /* 155 */
+- .long sys_sched_setscheduler
+- .long sys_sched_getscheduler
+- .long sys_sched_yield
+- .long sys_sched_get_priority_max
+- .long sys_sched_get_priority_min /* 160 */
+- .long sys_sched_rr_get_interval
+- .long sys_nanosleep
+- .long sys_mremap
+- .long sys_setresuid16
+- .long sys_getresuid16 /* 165 */
+- .long sys_ni_syscall /* vm86 */
+- .long sys_ni_syscall /* old "query_module" */
+- .long sys_poll
+- .long sys_nfsservctl
+- .long sys_setresgid16 /* 170 */
+- .long sys_getresgid16
+- .long sys_prctl
+- .long sys_rt_sigreturn
+- .long sys_rt_sigaction
+- .long sys_rt_sigprocmask /* 175 */
+- .long sys_rt_sigpending
+- .long sys_rt_sigtimedwait
+- .long sys_rt_sigqueueinfo
+- .long sys_rt_sigsuspend
+- .long sys_pread_wrapper /* 180 */
+- .long sys_pwrite_wrapper
+- .long sys_chown16
+- .long sys_getcwd
+- .long sys_capget
+- .long sys_capset /* 185 */
+- .long sys_sigaltstack
+- .long sys_sendfile
+- .long sys_ni_syscall /* streams1 */
+- .long sys_ni_syscall /* streams2 */
+- .long sys_vfork /* 190 */
+- .long sys_getrlimit
+- .long sys_mmap2
+- .long sys_truncate64
+- .long sys_ftruncate64
+- .long sys_stat64 /* 195 */
+- .long sys_lstat64
+- .long sys_fstat64
+- .long sys_lchown
+- .long sys_getuid
+- .long sys_getgid /* 200 */
+- .long sys_geteuid
+- .long sys_getegid
+- .long sys_setreuid
+- .long sys_setregid
+- .long sys_getgroups /* 205 */
+- .long sys_setgroups
+- .long sys_fchown
+- .long sys_setresuid
+- .long sys_getresuid
+- .long sys_setresgid /* 210 */
+- .long sys_getresgid
+- .long sys_chown
+- .long sys_setuid
+- .long sys_setgid
+- .long sys_setfsuid /* 215 */
+- .long sys_setfsgid
+- .long sys_pivot_root
+- .long sys_mincore
+- .long sys_madvise
+- .long sys_getdents64 /* 220 */
+- .long sys_fcntl64
+- .long sys_ni_syscall /* reserved for TUX */
+- .long sys_ni_syscall /* Reserved for Security */
+- .long sys_gettid
+- .long sys_readahead /* 225 */
+- .long sys_setxattr
+- .long sys_lsetxattr
+- .long sys_fsetxattr
+- .long sys_getxattr
+- .long sys_lgetxattr /* 230 */
+- .long sys_fgetxattr
+- .long sys_listxattr
+- .long sys_llistxattr
+- .long sys_flistxattr
+- .long sys_removexattr /* 235 */
+- .long sys_lremovexattr
+- .long sys_fremovexattr
+- .long sys_tkill
+- .long sys_sendfile64
+- .long sys_futex /* 240 */
+- .long sys_sched_setaffinity
+- .long sys_sched_getaffinity
+- .long sys_ni_syscall
+- .long sys_ni_syscall
+- .long sys_io_setup /* 245 */
+- .long sys_io_destroy
+- .long sys_io_getevents
+- .long sys_io_submit
+- .long sys_io_cancel
+- .long sys_fadvise64 /* 250 */
+- .long sys_ni_syscall
+- .long sys_exit_group
+- .long sys_lookup_dcookie
+- .long sys_epoll_create
+- .long sys_epoll_ctl /* 255 */
+- .long sys_epoll_wait
+- .long sys_remap_file_pages
+- .long sys_set_tid_address
+- .long sys_timer_create
+- .long sys_timer_settime /* 260 */
+- .long sys_timer_gettime
+- .long sys_timer_getoverrun
+- .long sys_timer_delete
+- .long sys_clock_settime
+- .long sys_clock_gettime /* 265 */
+- .long sys_clock_getres
+- .long sys_clock_nanosleep
+- .long sys_statfs64
+- .long sys_fstatfs64
+- .long sys_tgkill /* 270 */
+- .long sys_utimes
+- .long sys_fadvise64_64_wrapper
+- .long sys_ni_syscall /* Reserved for vserver */
+- .long sys_ni_syscall /* Reserved for mbind */
+- .long sys_ni_syscall /* 275 - get_mempolicy */
+- .long sys_ni_syscall /* set_mempolicy */
+- .long sys_mq_open
+- .long sys_mq_unlink
+- .long sys_mq_timedsend
+- .long sys_mq_timedreceive /* 280 */
+- .long sys_mq_notify
+- .long sys_mq_getsetattr
+- .long sys_ni_syscall /* Reserved for kexec */
+- .long sys_waitid
+- .long sys_add_key /* 285 */
+- .long sys_request_key
+- .long sys_keyctl
+- .long sys_ioprio_set
+- .long sys_ioprio_get
+- .long sys_inotify_init /* 290 */
+- .long sys_inotify_add_watch
+- .long sys_inotify_rm_watch
+-
+-/* End of entry.S */
+diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
+index 9b9e6ef..f5f53d1 100644
+--- a/arch/sh/kernel/head.S
++++ b/arch/sh/kernel/head.S
+@@ -11,6 +11,18 @@
+ * Head.S contains the SH exception handlers and startup code.
+ */
+ #include <linux/linkage.h>
++#include <asm/thread_info.h>
++
++#ifdef CONFIG_CPU_SH4A
++#define SYNCO() synco
++
++#define PREFI(label, reg) \
++ mov.l label, reg; \
++ prefi @reg
++#else
++#define SYNCO()
++#define PREFI(label, reg)
++#endif
+
+ .section .empty_zero_page, "aw"
+ ENTRY(empty_zero_page)
+@@ -42,18 +54,25 @@ ENTRY(_stext)
+ ! Initialize global interrupt mask
+ mov #0, r0
+ ldc r0, r6_bank
++
++ /*
++ * Prefetch if possible to reduce cache miss penalty.
++ *
++ * We do this early on for SH-4A as a micro-optimization,
++ * as later on we will have speculative execution enabled
++ * and this will become less of an issue.
++ */
++ PREFI(5f, r0)
++ PREFI(6f, r0)
++
+ !
+ mov.l 2f, r0
+ mov r0, r15 ! Set initial r15 (stack pointer)
+- mov #0x20, r1 !
+- shll8 r1 ! r1 = 8192
++ mov #(THREAD_SIZE >> 8), r1
++ shll8 r1 ! r1 = THREAD_SIZE
+ sub r1, r0 !
+ ldc r0, r7_bank ! ... and initial thread_info
+- !
+- ! Additional CPU initialization
+- mov.l 6f, r0
+- jsr @r0
+- nop
++
+ ! Clear BSS area
+ mov.l 3f, r1
+ add #4, r1
+@@ -62,6 +81,14 @@ ENTRY(_stext)
+ 9: cmp/hs r2, r1
+ bf/s 9b ! while (r1 < r2)
+ mov.l r0, at -r2
++
++ ! Additional CPU initialization
++ mov.l 6f, r0
++ jsr @r0
++ nop
++
++ SYNCO() ! Wait for pending instructions..
++
+ ! Start kernel
+ mov.l 5f, r0
+ jmp @r0
+@@ -69,7 +96,7 @@ ENTRY(_stext)
+
+ .balign 4
+ 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+-2: .long stack
++2: .long init_thread_union+THREAD_SIZE
+ 3: .long __bss_start
+ 4: .long _end
+ 5: .long start_kernel
+diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
+index 71c9fde..501fe03 100644
+--- a/arch/sh/kernel/io.c
++++ b/arch/sh/kernel/io.c
+@@ -61,6 +61,73 @@ void memset_io(volatile void __iomem *ds
+ }
+ EXPORT_SYMBOL(memset_io);
+
++void __raw_readsl(unsigned long addr, void *datap, int len)
++{
++ u32 *data;
++
++ for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
++ *data++ = ctrl_inl(addr);
++
++ if (likely(len >= (0x20 >> 2))) {
++ int tmp2, tmp3, tmp4, tmp5, tmp6;
++
++ __asm__ __volatile__(
++ "1: \n\t"
++ "mov.l @%7, r0 \n\t"
++ "mov.l @%7, %2 \n\t"
++#ifdef CONFIG_CPU_SH4
++ "movca.l r0, @%0 \n\t"
++#else
++ "mov.l r0, @%0 \n\t"
++#endif
++ "mov.l @%7, %3 \n\t"
++ "mov.l @%7, %4 \n\t"
++ "mov.l @%7, %5 \n\t"
++ "mov.l @%7, %6 \n\t"
++ "mov.l @%7, r7 \n\t"
++ "mov.l @%7, r0 \n\t"
++ "mov.l %2, @(0x04,%0) \n\t"
++ "mov #0x20>>2, %2 \n\t"
++ "mov.l %3, @(0x08,%0) \n\t"
++ "sub %2, %1 \n\t"
++ "mov.l %4, @(0x0c,%0) \n\t"
++ "cmp/hi %1, %2 ! T if 32 > len \n\t"
++ "mov.l %5, @(0x10,%0) \n\t"
++ "mov.l %6, @(0x14,%0) \n\t"
++ "mov.l r7, @(0x18,%0) \n\t"
++ "mov.l r0, @(0x1c,%0) \n\t"
++ "bf.s 1b \n\t"
++ " add #0x20, %0 \n\t"
++ : "=&r" (data), "=&r" (len),
++ "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
++ "=&r" (tmp5), "=&r" (tmp6)
++ : "r"(addr), "0" (data), "1" (len)
++ : "r0", "r7", "t", "memory");
++ }
++
++ for (; len != 0; len--)
++ *data++ = ctrl_inl(addr);
++}
++EXPORT_SYMBOL(__raw_readsl);
++
++void __raw_writesl(unsigned long addr, const void *data, int len)
++{
++ if (likely(len != 0)) {
++ int tmp1;
++
++ __asm__ __volatile__ (
++ "1: \n\t"
++ "mov.l @%0+, %1 \n\t"
++ "dt %3 \n\t"
++ "bf.s 1b \n\t"
++ " mov.l %1, @%4 \n\t"
++ : "=&r" (data), "=&r" (tmp1)
++ : "0" (data), "r" (len), "r"(addr)
++ : "t", "memory");
++ }
++}
++EXPORT_SYMBOL(__raw_writesl);
++
+ void __iomem *ioport_map(unsigned long port, unsigned int nr)
+ {
+ return sh_mv.mv_ioport_map(port, nr);
+diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
+index c2e07f7..944128c 100644
+--- a/arch/sh/kernel/irq.c
++++ b/arch/sh/kernel/irq.c
+@@ -1,5 +1,4 @@
+-/* $Id: irq.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $
+- *
++/*
+ * linux/arch/sh/kernel/irq.c
+ *
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+@@ -7,15 +6,20 @@
+ *
+ * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ */
+-
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
++#include <linux/module.h>
+ #include <linux/kernel_stat.h>
+ #include <linux/seq_file.h>
++#include <linux/io.h>
+ #include <asm/irq.h>
+ #include <asm/processor.h>
++#include <asm/uaccess.h>
++#include <asm/thread_info.h>
+ #include <asm/cpu/mmu_context.h>
+
++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, it doesn't deserve
+@@ -23,6 +27,7 @@
+ */
+ void ack_bad_irq(unsigned int irq)
+ {
++ atomic_inc(&irq_err_count);
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+ }
+
+@@ -46,8 +51,10 @@ int show_interrupts(struct seq_file *p,
+ if (!action)
+ goto unlock;
+ seq_printf(p, "%3d: ",i);
+- seq_printf(p, "%10u ", kstat_irqs(i));
+- seq_printf(p, " %14s", irq_desc[i].chip->typename);
++ for_each_online_cpu(j)
++ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
++ seq_printf(p, " %14s", irq_desc[i].chip->name);
++ seq_printf(p, "-%-8s", irq_desc[i].name);
+ seq_printf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+@@ -55,39 +62,190 @@ int show_interrupts(struct seq_file *p,
+ seq_putc(p, '\n');
+ unlock:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+- }
++ } else if (i == NR_IRQS)
++ seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
++
+ return 0;
+ }
+ #endif
+
++#ifdef CONFIG_4KSTACKS
++/*
++ * per-CPU IRQ handling contexts (thread information and stack)
++ */
++union irq_ctx {
++ struct thread_info tinfo;
++ u32 stack[THREAD_SIZE/sizeof(u32)];
++};
++
++static union irq_ctx *hardirq_ctx[NR_CPUS];
++static union irq_ctx *softirq_ctx[NR_CPUS];
++#endif
+
+ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs regs)
+ {
+- int irq = r4;
++ struct pt_regs *old_regs = set_irq_regs(®s);
++ int irq;
++#ifdef CONFIG_4KSTACKS
++ union irq_ctx *curctx, *irqctx;
++#endif
+
+ irq_enter();
+
++#ifdef CONFIG_DEBUG_STACKOVERFLOW
++ /* Debugging check for stack overflow: is there less than 1KB free? */
++ {
++ long sp;
++
++ __asm__ __volatile__ ("and r15, %0" :
++ "=r" (sp) : "0" (THREAD_SIZE - 1));
++
++ if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
++ printk("do_IRQ: stack overflow: %ld\n",
++ sp - sizeof(struct thread_info));
++ dump_stack();
++ }
++ }
++#endif
++
+ #ifdef CONFIG_CPU_HAS_INTEVT
+- __asm__ __volatile__ (
+-#ifdef CONFIG_CPU_HAS_SR_RB
+- "stc r2_bank, %0\n\t"
++ irq = (ctrl_inl(INTEVT) >> 5) - 16;
+ #else
+- "mov.l @%1, %0\n\t"
+-#endif
+- "shlr2 %0\n\t"
+- "shlr2 %0\n\t"
+- "shlr %0\n\t"
+- "add #-16, %0\n\t"
+- : "=z" (irq), "=r" (r4)
+- : "1" (INTEVT)
+- : "memory"
+- );
++ irq = r4;
+ #endif
+
+ irq = irq_demux(irq);
+- __do_IRQ(irq, ®s);
++
++#ifdef CONFIG_4KSTACKS
++ curctx = (union irq_ctx *)current_thread_info();
++ irqctx = hardirq_ctx[smp_processor_id()];
++
++ /*
++ * this is where we switch to the IRQ stack. However, if we are
++ * already using the IRQ stack (because we interrupted a hardirq
++ * handler) we can't do that and just have to keep using the
++ * current stack (which is the irq stack already after all)
++ */
++ if (curctx != irqctx) {
++ u32 *isp;
++
++ isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
++ irqctx->tinfo.task = curctx->tinfo.task;
++ irqctx->tinfo.previous_sp = current_stack_pointer;
++
++ __asm__ __volatile__ (
++ "mov %0, r4 \n"
++ "mov r15, r9 \n"
++ "jsr @%1 \n"
++ /* swith to the irq stack */
++ " mov %2, r15 \n"
++ /* restore the stack (ring zero) */
++ "mov r9, r15 \n"
++ : /* no outputs */
++ : "r" (irq), "r" (generic_handle_irq), "r" (isp)
++ /* XXX: A somewhat excessive clobber list? -PFM */
++ : "memory", "r0", "r1", "r2", "r3", "r4",
++ "r5", "r6", "r7", "r8", "t", "pr"
++ );
++ } else
++#endif
++ generic_handle_irq(irq);
++
+ irq_exit();
++
++ set_irq_regs(old_regs);
+ return 1;
+ }
++
++#ifdef CONFIG_4KSTACKS
++/*
++ * These should really be __section__(".bss.page_aligned") as well, but
++ * gcc's 3.0 and earlier don't handle that correctly.
++ */
++static char softirq_stack[NR_CPUS * THREAD_SIZE]
++ __attribute__((__aligned__(THREAD_SIZE)));
++
++static char hardirq_stack[NR_CPUS * THREAD_SIZE]
++ __attribute__((__aligned__(THREAD_SIZE)));
++
++/*
++ * allocate per-cpu stacks for hardirq and for softirq processing
++ */
++void irq_ctx_init(int cpu)
++{
++ union irq_ctx *irqctx;
++
++ if (hardirq_ctx[cpu])
++ return;
++
++ irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE];
++ irqctx->tinfo.task = NULL;
++ irqctx->tinfo.exec_domain = NULL;
++ irqctx->tinfo.cpu = cpu;
++ irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
++ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
++
++ hardirq_ctx[cpu] = irqctx;
++
++ irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE];
++ irqctx->tinfo.task = NULL;
++ irqctx->tinfo.exec_domain = NULL;
++ irqctx->tinfo.cpu = cpu;
++ irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
++ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
++
++ softirq_ctx[cpu] = irqctx;
++
++ printk("CPU %u irqstacks, hard=%p soft=%p\n",
++ 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)
++{
++ unsigned long flags;
++ struct thread_info *curctx;
++ union irq_ctx *irqctx;
++ u32 *isp;
++
++ if (in_interrupt())
++ return;
++
++ local_irq_save(flags);
++
++ if (local_softirq_pending()) {
++ curctx = current_thread_info();
++ irqctx = softirq_ctx[smp_processor_id()];
++ irqctx->tinfo.task = curctx->task;
++ irqctx->tinfo.previous_sp = current_stack_pointer;
++
++ /* build the stack frame on the softirq stack */
++ isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
++
++ __asm__ __volatile__ (
++ "mov r15, r9 \n"
++ "jsr @%0 \n"
++ /* switch to the softirq stack */
++ " mov %1, r15 \n"
++ /* restore the thread stack */
++ "mov r9, r15 \n"
++ : /* no outputs */
++ : "r" (__do_softirq), "r" (isp)
++ /* XXX: A somewhat excessive clobber list? -PFM */
++ : "memory", "r0", "r1", "r2", "r3", "r4",
++ "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
++ );
++ }
++
++ local_irq_restore(flags);
++}
++EXPORT_SYMBOL(do_softirq);
++#endif
+diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
+index 42638b9..9c6315f 100644
+--- a/arch/sh/kernel/kgdb_stub.c
++++ b/arch/sh/kernel/kgdb_stub.c
+@@ -101,16 +101,17 @@
+ #include <linux/linkage.h>
+ #include <linux/init.h>
+
++#ifdef CONFIG_SH_KGDB_CONSOLE
++#include <linux/console.h>
++#endif
++
+ #include <asm/system.h>
+ #include <asm/current.h>
+ #include <asm/signal.h>
+ #include <asm/pgtable.h>
+ #include <asm/ptrace.h>
+ #include <asm/kgdb.h>
+-
+-#ifdef CONFIG_SH_KGDB_CONSOLE
+-#include <linux/console.h>
+-#endif
++#include <asm/io.h>
+
+ /* Function pointers for linkage */
+ kgdb_debug_hook_t *kgdb_debug_hook;
+@@ -240,7 +241,6 @@ static jmp_buf rem_com_env;
+ /* Misc static */
+ static int stepped_address;
+ static short stepped_opcode;
+-static const char hexchars[] = "0123456789abcdef";
+ static char in_buffer[BUFMAX];
+ static char out_buffer[OUTBUFMAX];
+
+@@ -253,29 +253,6 @@ typedef unsigned char threadref[8];
+ #define BUF_THREAD_ID_SIZE 16
+ #endif
+
+-/* Return addr as a real volatile address */
+-static inline unsigned int ctrl_inl(const unsigned long addr)
+-{
+- return *(volatile unsigned long *) addr;
+-}
+-
+-/* Correctly set *addr using volatile */
+-static inline void ctrl_outl(const unsigned int b, unsigned long addr)
+-{
+- *(volatile unsigned long *) addr = b;
+-}
+-
+-/* Get high hex bits */
+-static char highhex(const int x)
+-{
+- return hexchars[(x >> 4) & 0xf];
+-}
+-
+-/* Get low hex bits */
+-static char lowhex(const int x)
+-{
+- return hexchars[x & 0xf];
+-}
+
+ /* Convert ch to hex */
+ static int hex(const char ch)
+diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
+index 6bcd8d9..08587cd 100644
+--- a/arch/sh/kernel/machine_kexec.c
++++ b/arch/sh/kernel/machine_kexec.c
+@@ -29,12 +29,6 @@ extern const unsigned char relocate_new_
+ extern const unsigned int relocate_new_kernel_size;
+ extern void *gdb_vbr_vector;
+
+-/*
+- * 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)
+ {
+ }
+diff --git a/arch/sh/kernel/pm.c b/arch/sh/kernel/pm.c
+new file mode 100644
+index 0000000..10ab62c
+--- /dev/null
++++ b/arch/sh/kernel/pm.c
+@@ -0,0 +1,88 @@
++/*
++ * Generic Power Management Routine
++ *
++ * Copyright (c) 2006 Andriy Skulysh <askulsyh at gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++#include <linux/suspend.h>
++#include <linux/delay.h>
++#include <linux/gfp.h>
++#include <asm/freq.h>
++#include <asm/io.h>
++#include <asm/watchdog.h>
++#include <asm/pm.h>
++
++#define INTR_OFFSET 0x600
++
++#define STBCR 0xffffff82
++#define STBCR2 0xffffff88
++
++#define STBCR_STBY 0x80
++#define STBCR_MSTP2 0x04
++
++#define MCR 0xffffff68
++#define RTCNT 0xffffff70
++
++#define MCR_RMODE 2
++#define MCR_RFSH 4
++
++void pm_enter(void)
++{
++ u8 stbcr, csr;
++ u16 frqcr, mcr;
++ u32 vbr_new, vbr_old;
++
++ set_bl_bit();
++
++ /* set wdt */
++ csr = sh_wdt_read_csr();
++ csr &= ~WTCSR_TME;
++ csr |= WTCSR_CKS_4096;
++ sh_wdt_write_csr(csr);
++ csr = sh_wdt_read_csr();
++ sh_wdt_write_cnt(0);
++
++ /* disable PLL1 */
++ frqcr = ctrl_inw(FRQCR);
++ frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
++ ctrl_outw(frqcr, FRQCR);
++
++ /* enable standby */
++ stbcr = ctrl_inb(STBCR);
++ ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
++
++ /* set self-refresh */
++ mcr = ctrl_inw(MCR);
++ ctrl_outw(mcr & ~MCR_RFSH, MCR);
++
++ /* set interrupt handler */
++ asm volatile("stc vbr, %0" : "=r" (vbr_old));
++ vbr_new = get_zeroed_page(GFP_ATOMIC);
++ udelay(50);
++ memcpy((void*)(vbr_new + INTR_OFFSET),
++ &wakeup_start, &wakeup_end - &wakeup_start);
++ asm volatile("ldc %0, vbr" : : "r" (vbr_new));
++
++ ctrl_outw(0, RTCNT);
++ ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR);
++
++ cpu_sleep();
++
++ asm volatile("ldc %0, vbr" : : "r" (vbr_old));
++
++ free_page(vbr_new);
++
++ /* enable PLL1 */
++ frqcr = ctrl_inw(FRQCR);
++ frqcr |= FRQCR_PSTBY;
++ ctrl_outw(frqcr, FRQCR);
++ udelay(50);
++ frqcr |= FRQCR_PLLEN;
++ ctrl_outw(frqcr, FRQCR);
++
++ ctrl_outb(stbcr, STBCR);
++
++ clear_bl_bit();
++}
+diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
+index 22dc9c2..a52b13a 100644
+--- a/arch/sh/kernel/process.c
++++ b/arch/sh/kernel/process.c
+@@ -5,6 +5,7 @@
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
++ * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
+ */
+
+ /*
+@@ -26,6 +27,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/mmu_context.h>
+ #include <asm/elf.h>
++#include <asm/ubc.h>
+
+ static int hlt_counter=0;
+
+@@ -80,16 +82,6 @@ void cpu_idle(void)
+
+ void machine_restart(char * __unused)
+ {
+-
+-#ifdef CONFIG_KEXEC
+- struct kimage *image;
+- image = xchg(&kexec_image, 0);
+- if (image) {
+- machine_shutdown();
+- machine_kexec(image);
+- }
+-#endif
+-
+ /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
+ asm volatile("ldc %0, sr\n\t"
+ "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
+@@ -113,7 +105,7 @@ void show_regs(struct pt_regs * regs)
+ {
+ printk("\n");
+ printk("Pid : %d, Comm: %20s\n", current->pid, current->comm);
+- print_symbol("PC is at %s\n", regs->pc);
++ print_symbol("PC is at %s\n", instruction_pointer(regs));
+ printk("PC : %08lx SP : %08lx SR : %08lx ",
+ regs->pc, regs->regs[15], regs->sr);
+ #ifdef CONFIG_MMU
+@@ -138,15 +130,7 @@ void show_regs(struct pt_regs * regs)
+ printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
+ regs->mach, regs->macl, regs->gbr, regs->pr);
+
+- /*
+- * If we're in kernel mode, dump the stack too..
+- */
+- if (!user_mode(regs)) {
+- extern void show_task(unsigned long *sp);
+- unsigned long sp = regs->regs[15];
+-
+- show_task((unsigned long *)sp);
+- }
++ show_trace(NULL, (unsigned long *)regs->regs[15], regs);
+ }
+
+ /*
+@@ -262,6 +246,7 @@ int copy_thread(int nr, unsigned long cl
+ unsigned long unused,
+ struct task_struct *p, struct pt_regs *regs)
+ {
++ struct thread_info *ti = task_thread_info(p);
+ struct pt_regs *childregs;
+ #if defined(CONFIG_SH_FPU)
+ struct task_struct *tsk = current;
+@@ -276,8 +261,10 @@ int copy_thread(int nr, unsigned long cl
+
+ if (user_mode(regs)) {
+ childregs->regs[15] = usp;
++ ti->addr_limit = USER_DS;
+ } else {
+ childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
++ ti->addr_limit = KERNEL_DS;
+ }
+ if (clone_flags & CLONE_SETTLS) {
+ childregs->gbr = childregs->regs[0];
+@@ -296,21 +283,42 @@ int copy_thread(int nr, unsigned long cl
+ static void
+ ubc_set_tracing(int asid, unsigned long pc)
+ {
++#if defined(CONFIG_CPU_SH4A)
++ unsigned long val;
++
++ val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
++ val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));
++
++ ctrl_outl(val, UBC_CBR0);
++ ctrl_outl(pc, UBC_CAR0);
++ ctrl_outl(0x0, UBC_CAMR0);
++ ctrl_outl(0x0, UBC_CBCR);
++
++ val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
++ ctrl_outl(val, UBC_CRR0);
++
++ /* Read UBC register that we writed last. For chekking UBC Register changed */
++ val = ctrl_inl(UBC_CRR0);
++
++#else /* CONFIG_CPU_SH4A */
+ ctrl_outl(pc, UBC_BARA);
+
++#ifdef CONFIG_MMU
+ /* We don't have any ASID settings for the SH-2! */
+ if (cpu_data->type != CPU_SH7604)
+ ctrl_outb(asid, UBC_BASRA);
++#endif
+
+ ctrl_outl(0, UBC_BAMRA);
+
+- if (cpu_data->type == CPU_SH7729) {
++ if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) {
+ ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
+ ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
+ } else {
+ ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
+ ctrl_outw(BRCR_PCBA, UBC_BRCR);
+ }
++#endif /* CONFIG_CPU_SH4A */
+ }
+
+ /*
+@@ -343,6 +351,7 @@ struct task_struct *__switch_to(struct t
+ }
+ #endif
+
++#ifdef CONFIG_MMU
+ /*
+ * Restore the kernel mode register
+ * k7 (r7_bank1)
+@@ -350,19 +359,26 @@ struct task_struct *__switch_to(struct t
+ asm volatile("ldc %0, r7_bank"
+ : /* no output */
+ : "r" (task_thread_info(next)));
++#endif
+
+-#ifdef CONFIG_MMU
+ /* If no tasks are using the UBC, we're done */
+ if (ubc_usercnt == 0)
+ /* If no tasks are using the UBC, we're done */;
+ else if (next->thread.ubc_pc && next->mm) {
+- ubc_set_tracing(next->mm->context & MMU_CONTEXT_ASID_MASK,
+- next->thread.ubc_pc);
++ int asid = 0;
++#ifdef CONFIG_MMU
++ asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK;
++#endif
++ ubc_set_tracing(asid, next->thread.ubc_pc);
+ } else {
++#if defined(CONFIG_CPU_SH4A)
++ ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
++ ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
++#else
+ ctrl_outw(0, UBC_BBRA);
+ ctrl_outw(0, UBC_BBRB);
+- }
+ #endif
++ }
+
+ return prev;
+ }
+@@ -461,8 +477,13 @@ asmlinkage void break_point_trap(unsigne
+ struct pt_regs regs)
+ {
+ /* Clear tracing. */
++#if defined(CONFIG_CPU_SH4A)
++ ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
++ ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
++#else
+ ctrl_outw(0, UBC_BBRA);
+ ctrl_outw(0, UBC_BBRB);
++#endif
+ current->thread.ubc_pc = 0;
+ ubc_usercnt -= 1;
+
+diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
+index f7eebbd..04ca13a 100644
+--- a/arch/sh/kernel/ptrace.c
++++ b/arch/sh/kernel/ptrace.c
+@@ -224,7 +224,6 @@ long arch_ptrace(struct task_struct *chi
+
+ case PTRACE_SETDSPREGS: {
+ unsigned long dp;
+- int i;
+
+ ret = -EIO;
+ dp = ((unsigned long) child) + THREAD_SIZE -
+diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c
+index a3c24dc..184119e 100644
+--- a/arch/sh/kernel/semaphore.c
++++ b/arch/sh/kernel/semaphore.c
+@@ -14,7 +14,7 @@
+ #include <asm/semaphore.h>
+ #include <asm/semaphore-helper.h>
+
+-spinlock_t semaphore_wake_lock;
++DEFINE_SPINLOCK(semaphore_wake_lock);
+
+ /*
+ * Semaphores are implemented using a two-way counter:
+diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
+index e75189c..36d86f9 100644
+--- a/arch/sh/kernel/setup.c
++++ b/arch/sh/kernel/setup.c
+@@ -1,5 +1,4 @@
+-/* $Id: setup.c,v 1.30 2003/10/13 07:21:19 lethal Exp $
+- *
++/*
+ * linux/arch/sh/kernel/setup.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+@@ -21,6 +20,7 @@
+ #include <linux/utsname.h>
+ #include <linux/cpu.h>
+ #include <linux/pfn.h>
++#include <linux/fs.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/sections.h>
+@@ -43,27 +43,14 @@ extern void * __rd_start, * __rd_end;
+ * The bigger value means no problem.
+ */
+ struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
++#ifdef CONFIG_VT
+ struct screen_info screen_info;
++#endif
+
+ #if defined(CONFIG_SH_UNKNOWN)
+ struct sh_machine_vector sh_mv;
+ #endif
+
+-/* We need this to satisfy some external references. */
+-struct screen_info screen_info = {
+- 0, 25, /* orig-x, orig-y */
+- 0, /* unused */
+- 0, /* orig-video-page */
+- 0, /* orig-video-mode */
+- 80, /* orig-video-cols */
+- 0,0,0, /* ega_ax, ega_bx, ega_cx */
+- 25, /* orig-video-lines */
+- 0, /* orig-video-isVGA */
+- 16 /* orig-video-points */
+-};
+-
+-extern void platform_setup(void);
+-extern char *get_system_type(void);
+ extern int root_mountflags;
+
+ #define MV_NAME_SIZE 32
+@@ -90,29 +77,8 @@ static struct sh_machine_vector* __init
+
+ static char command_line[COMMAND_LINE_SIZE] = { 0, };
+
+-struct resource standard_io_resources[] = {
+- { "dma1", 0x00, 0x1f },
+- { "pic1", 0x20, 0x3f },
+- { "timer", 0x40, 0x5f },
+- { "keyboard", 0x60, 0x6f },
+- { "dma page reg", 0x80, 0x8f },
+- { "pic2", 0xa0, 0xbf },
+- { "dma2", 0xc0, 0xdf },
+- { "fpu", 0xf0, 0xff }
+-};
+-
+-#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+-
+-/* System RAM - interrupted by the 640kB-1M hole */
+-#define code_resource (ram_resources[3])
+-#define data_resource (ram_resources[4])
+-static struct resource ram_resources[] = {
+- { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
+- { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
+- { "Video RAM area", 0x0a0000, 0x0bffff },
+- { "Kernel code", 0x100000, 0 },
+- { "Kernel data", 0, 0 }
+-};
++static struct resource code_resource = { .name = "Kernel code", };
++static struct resource data_resource = { .name = "Kernel data", };
+
+ unsigned long memory_start, memory_end;
+
+@@ -145,6 +111,24 @@ static inline void parse_cmdline (char *
+ memory_end = memory_start + mem_size;
+ }
+ }
++
++#ifdef CONFIG_EARLY_PRINTK
++ if (c == ' ' && !memcmp(from, "earlyprintk=", 12)) {
++ char *ep_end;
++
++ if (to != command_line)
++ to--;
++
++ from += 12;
++ ep_end = strchr(from, ' ');
++
++ setup_early_printk(from);
++ printk("early console enabled\n");
++
++ from = ep_end;
++ }
++#endif
++
+ if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
+ char* mv_end;
+ char* mv_comma;
+@@ -237,6 +221,9 @@ static int __init sh_mv_setup(char **cmd
+ __set_io_port_base(mv_io_base);
+ #endif
+
++ if (!sh_mv.mv_nr_irqs)
++ sh_mv.mv_nr_irqs = NR_IRQS;
++
+ return 0;
+ }
+
+@@ -245,11 +232,6 @@ void __init setup_arch(char **cmdline_p)
+ unsigned long bootmap_size;
+ unsigned long start_pfn, max_pfn, max_low_pfn;
+
+-#ifdef CONFIG_EARLY_PRINTK
+- extern void enable_early_printk(void);
+-
+- enable_early_printk();
+-#endif
+ #ifdef CONFIG_CMDLINE_BOOL
+ strcpy(COMMAND_LINE, CONFIG_CMDLINE);
+ #endif
+@@ -368,14 +350,14 @@ void __init setup_arch(char **cmdline_p)
+ #endif
+
+ /* Perform the machine specific initialisation */
+- platform_setup();
++ if (likely(sh_mv.mv_setup))
++ sh_mv.mv_setup(cmdline_p);
+
+ paging_init();
+ }
+
+ struct sh_machine_vector* __init get_mv_byname(const char* name)
+ {
+- extern int strcasecmp(const char *, const char *);
+ extern long __machvec_start, __machvec_end;
+ struct sh_machine_vector *all_vecs =
+ (struct sh_machine_vector *)&__machvec_start;
+@@ -410,25 +392,18 @@ static int __init topology_init(void)
+ subsys_initcall(topology_init);
+
+ static const char *cpu_name[] = {
+- [CPU_SH7604] = "SH7604",
+- [CPU_SH7705] = "SH7705",
+- [CPU_SH7708] = "SH7708",
+- [CPU_SH7729] = "SH7729",
+- [CPU_SH7300] = "SH7300",
+- [CPU_SH7750] = "SH7750",
+- [CPU_SH7750S] = "SH7750S",
+- [CPU_SH7750R] = "SH7750R",
+- [CPU_SH7751] = "SH7751",
+- [CPU_SH7751R] = "SH7751R",
+- [CPU_SH7760] = "SH7760",
+- [CPU_SH73180] = "SH73180",
+- [CPU_ST40RA] = "ST40RA",
+- [CPU_ST40GX1] = "ST40GX1",
+- [CPU_SH4_202] = "SH4-202",
+- [CPU_SH4_501] = "SH4-501",
+- [CPU_SH7770] = "SH7770",
+- [CPU_SH7780] = "SH7780",
+- [CPU_SH7781] = "SH7781",
++ [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300",
++ [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
++ [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
++ [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
++ [CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
++ [CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
++ [CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
++ [CPU_SH7760] = "SH7760", [CPU_SH73180] = "SH73180",
++ [CPU_ST40RA] = "ST40RA", [CPU_ST40GX1] = "ST40GX1",
++ [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
++ [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
++ [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
+ [CPU_SH_NONE] = "Unknown"
+ };
+
+@@ -438,8 +413,10 @@ const char *get_cpu_subtype(void)
+ }
+
+ #ifdef CONFIG_PROC_FS
++/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
+ static const char *cpu_flags[] = {
+- "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", "ptea", NULL
++ "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
++ "ptea", "llsc", "l2", NULL
+ };
+
+ static void show_cpuflags(struct seq_file *m)
+@@ -460,7 +437,8 @@ static void show_cpuflags(struct seq_fil
+ seq_printf(m, "\n");
+ }
+
+-static void show_cacheinfo(struct seq_file *m, const char *type, struct cache_info info)
++static void show_cacheinfo(struct seq_file *m, const char *type,
++ struct cache_info info)
+ {
+ unsigned int cache_size;
+
+@@ -481,7 +459,7 @@ static int show_cpuinfo(struct seq_file
+ seq_printf(m, "machine\t\t: %s\n", get_system_type());
+
+ seq_printf(m, "processor\t: %d\n", cpu);
+- seq_printf(m, "cpu family\t: %s\n", system_utsname.machine);
++ seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine);
+ seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype());
+
+ show_cpuflags(m);
+@@ -493,7 +471,7 @@ static int show_cpuinfo(struct seq_file
+ * unified cache on the SH-2 and SH-3, as well as the harvard
+ * style cache on the SH-4.
+ */
+- if (test_bit(SH_CACHE_COMBINED, &(boot_cpu_data.icache.flags))) {
++ if (boot_cpu_data.icache.flags & SH_CACHE_COMBINED) {
+ seq_printf(m, "unified\n");
+ show_cacheinfo(m, "cache", boot_cpu_data.icache);
+ } else {
+@@ -502,6 +480,10 @@ static int show_cpuinfo(struct seq_file
+ show_cacheinfo(m, "dcache", boot_cpu_data.dcache);
+ }
+
++ /* Optional secondary cache */
++ if (boot_cpu_data.flags & CPU_HAS_L2_CACHE)
++ show_cacheinfo(m, "scache", boot_cpu_data.scache);
++
+ seq_printf(m, "bogomips\t: %lu.%02lu\n",
+ boot_cpu_data.loops_per_jiffy/(500000/HZ),
+ (boot_cpu_data.loops_per_jiffy/(5000/HZ)) % 100);
+@@ -617,4 +599,3 @@ static int __init kgdb_parse_options(cha
+ }
+ __setup("kgdb=", kgdb_parse_options);
+ #endif /* CONFIG_SH_KGDB */
+-
+diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
+index 245ed8f..9daad70 100644
+--- a/arch/sh/kernel/sh_ksyms.c
++++ b/arch/sh/kernel/sh_ksyms.c
+@@ -27,21 +27,11 @@ EXPORT_SYMBOL(sh_mv);
+
+ /* platform dependent support */
+ EXPORT_SYMBOL(dump_fpu);
+-EXPORT_SYMBOL(iounmap);
+-EXPORT_SYMBOL(enable_irq);
+-EXPORT_SYMBOL(disable_irq);
+-EXPORT_SYMBOL(probe_irq_mask);
+ EXPORT_SYMBOL(kernel_thread);
+-EXPORT_SYMBOL(disable_irq_nosync);
+ EXPORT_SYMBOL(irq_desc);
+ EXPORT_SYMBOL(no_irq_type);
+
+-EXPORT_SYMBOL(strstr);
+ EXPORT_SYMBOL(strlen);
+-EXPORT_SYMBOL(strnlen);
+-EXPORT_SYMBOL(strchr);
+-EXPORT_SYMBOL(strcat);
+-EXPORT_SYMBOL(strncat);
+
+ /* PCI exports */
+ #ifdef CONFIG_PCI
+@@ -52,13 +42,8 @@ EXPORT_SYMBOL(pci_free_consistent);
+ /* mem exports */
+ EXPORT_SYMBOL(memchr);
+ EXPORT_SYMBOL(memcpy);
+-EXPORT_SYMBOL(memcpy_fromio);
+-EXPORT_SYMBOL(memcpy_toio);
+ EXPORT_SYMBOL(memset);
+-EXPORT_SYMBOL(memset_io);
+ EXPORT_SYMBOL(memmove);
+-EXPORT_SYMBOL(memcmp);
+-EXPORT_SYMBOL(memscan);
+ EXPORT_SYMBOL(__copy_user);
+ EXPORT_SYMBOL(boot_cpu_data);
+
+@@ -87,6 +72,7 @@ DECLARE_EXPORT(__ashrdi3);
+ DECLARE_EXPORT(__ashldi3);
+ DECLARE_EXPORT(__lshrdi3);
+ DECLARE_EXPORT(__movstr);
++DECLARE_EXPORT(__movstrSI16);
+
+ EXPORT_SYMBOL(strcpy);
+
+@@ -94,7 +80,9 @@ EXPORT_SYMBOL(strcpy);
+ DECLARE_EXPORT(__movstr_i4_even);
+ DECLARE_EXPORT(__movstr_i4_odd);
+ DECLARE_EXPORT(__movstrSI12_i4);
++#endif
+
++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+ /* needed by some modules */
+ EXPORT_SYMBOL(flush_cache_all);
+ EXPORT_SYMBOL(flush_cache_range);
+@@ -102,11 +90,9 @@ EXPORT_SYMBOL(flush_dcache_page);
+ EXPORT_SYMBOL(__flush_purge_region);
+ #endif
+
+-#if defined(CONFIG_SH7705_CACHE_32KB)
+-EXPORT_SYMBOL(flush_cache_all);
+-EXPORT_SYMBOL(flush_cache_range);
+-EXPORT_SYMBOL(flush_dcache_page);
+-EXPORT_SYMBOL(__flush_purge_region);
++#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
++ defined(CONFIG_SH7705_CACHE_32KB))
++EXPORT_SYMBOL(clear_user_page);
+ #endif
+
+ EXPORT_SYMBOL(flush_tlb_page);
+@@ -116,7 +102,12 @@ EXPORT_SYMBOL(__down_trylock);
+ EXPORT_SYMBOL(synchronize_irq);
+ #endif
+
++#ifdef CONFIG_PM
++EXPORT_SYMBOL(pm_suspend);
++#endif
++
+ EXPORT_SYMBOL(csum_partial);
++#ifdef CONFIG_IPV6
+ EXPORT_SYMBOL(csum_ipv6_magic);
+-EXPORT_SYMBOL(consistent_sync);
++#endif
+ EXPORT_SYMBOL(clear_page);
+diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
+index b475c4d..5213f5b 100644
+--- a/arch/sh/kernel/signal.c
++++ b/arch/sh/kernel/signal.c
+@@ -8,7 +8,6 @@
+ * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
+ *
+ */
+-
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+ #include <linux/smp.h>
+@@ -21,6 +20,7 @@
+ #include <linux/unistd.h>
+ #include <linux/stddef.h>
+ #include <linux/tty.h>
++#include <linux/elf.h>
+ #include <linux/personality.h>
+ #include <linux/binfmts.h>
+
+@@ -29,12 +29,8 @@
+ #include <asm/pgtable.h>
+ #include <asm/cacheflush.h>
+
+-#define DEBUG_SIG 0
+-
+ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+-
+ /*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+@@ -43,51 +39,17 @@ sys_sigsuspend(old_sigset_t mask,
+ unsigned long r5, unsigned long r6, unsigned long r7,
+ struct pt_regs regs)
+ {
+- sigset_t saveset;
+-
+ mask &= _BLOCKABLE;
+ spin_lock_irq(¤t->sighand->siglock);
+- saveset = current->blocked;
++ current->saved_sigmask = current->blocked;
+ siginitset(¤t->blocked, mask);
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+
+- regs.regs[0] = -EINTR;
+- while (1) {
+- current->state = TASK_INTERRUPTIBLE;
+- schedule();
+- if (do_signal(®s, &saveset))
+- return -EINTR;
+- }
+-}
+-
+-asmlinkage int
+-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+- unsigned long r6, unsigned long r7,
+- struct pt_regs regs)
+-{
+- sigset_t saveset, newset;
+-
+- /* XXX: Don't preclude handling different sized sigset_t's. */
+- if (sigsetsize != sizeof(sigset_t))
+- return -EINVAL;
+-
+- if (copy_from_user(&newset, unewset, sizeof(newset)))
+- return -EFAULT;
+- sigdelsetmask(&newset, ~_BLOCKABLE);
+- spin_lock_irq(¤t->sighand->siglock);
+- saveset = current->blocked;
+- current->blocked = newset;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->sighand->siglock);
+-
+- regs.regs[0] = -EINTR;
+- while (1) {
+- current->state = TASK_INTERRUPTIBLE;
+- schedule();
+- if (do_signal(®s, &saveset))
+- return -EINTR;
+- }
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ set_thread_flag(TIF_RESTORE_SIGMASK);
++ return -ERESTARTNOHAND;
+ }
+
+ asmlinkage int
+@@ -348,7 +310,12 @@ get_sigframe(struct k_sigaction *ka, uns
+ return (void __user *)((sp - frame_size) & -8ul);
+ }
+
+-static void setup_frame(int sig, struct k_sigaction *ka,
++/* These symbols are defined with the addresses in the vsyscall page.
++ See vsyscall-trapa.S. */
++extern void __user __kernel_sigreturn;
++extern void __user __kernel_rt_sigreturn;
++
++static int setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs *regs)
+ {
+ struct sigframe __user *frame;
+@@ -368,15 +335,18 @@ static void setup_frame(int sig, struct
+
+ err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+- if (_NSIG_WORDS > 1) {
++ if (_NSIG_WORDS > 1)
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+- }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa.sa_restorer;
++#ifdef CONFIG_VSYSCALL
++ } else if (likely(current->mm->context.vdso)) {
++ regs->pr = VDSO_SYM(&__kernel_sigreturn);
++#endif
+ } else {
+ /* Generate return code (system call to sigreturn) */
+ err |= __put_user(MOVW(7), &frame->retcode[0]);
+@@ -402,21 +372,22 @@ static void setup_frame(int sig, struct
+
+ set_fs(USER_DS);
+
+-#if DEBUG_SIG
+- printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+- current->comm, current->pid, frame, regs->pc, regs->pr);
+-#endif
++ pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
++ current->comm, current->pid, frame, regs->pc, regs->pr);
+
+ flush_cache_sigtramp(regs->pr);
++
+ if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
+ flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
+- return;
++
++ return 0;
+
+ give_sigsegv:
+ force_sigsegv(sig, current);
++ return -EFAULT;
+ }
+
+-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
++static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+ {
+ struct rt_sigframe __user *frame;
+@@ -452,6 +423,10 @@ static void setup_rt_frame(int sig, stru
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa.sa_restorer;
++#ifdef CONFIG_VSYSCALL
++ } else if (likely(current->mm->context.vdso)) {
++ regs->pr = VDSO_SYM(&__kernel_rt_sigreturn);
++#endif
+ } else {
+ /* Generate return code (system call to rt_sigreturn) */
+ err |= __put_user(MOVW(7), &frame->retcode[0]);
+@@ -477,28 +452,31 @@ static void setup_rt_frame(int sig, stru
+
+ set_fs(USER_DS);
+
+-#if DEBUG_SIG
+- printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+- current->comm, current->pid, frame, regs->pc, regs->pr);
+-#endif
++ pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
++ current->comm, current->pid, frame, regs->pc, regs->pr);
+
+ flush_cache_sigtramp(regs->pr);
++
+ if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
+ flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
+- return;
++
++ return 0;
+
+ give_sigsegv:
+ force_sigsegv(sig, current);
++ return -EFAULT;
+ }
+
+ /*
+ * OK, we're invoking a handler
+ */
+
+-static void
++static int
+ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *oldset, struct pt_regs *regs)
+ {
++ int ret;
++
+ /* Are we from a system call? */
+ if (regs->tra >= 0) {
+ /* If so, check system call restarting.. */
+@@ -539,19 +517,23 @@ handle_signal(unsigned long sig, struct
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+- setup_rt_frame(sig, ka, info, oldset, regs);
++ ret = setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+- setup_frame(sig, ka, oldset, regs);
++ ret = setup_frame(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+- spin_lock_irq(¤t->sighand->siglock);
+- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+- if (!(ka->sa.sa_flags & SA_NODEFER))
+- sigaddset(¤t->blocked,sig);
+- recalc_sigpending();
+- spin_unlock_irq(¤t->sighand->siglock);
++ if (ret == 0) {
++ spin_lock_irq(¤t->sighand->siglock);
++ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
++ if (!(ka->sa.sa_flags & SA_NODEFER))
++ sigaddset(¤t->blocked,sig);
++ recalc_sigpending();
++ spin_unlock_irq(¤t->sighand->siglock);
++ }
++
++ return ret;
+ }
+
+ /*
+@@ -563,11 +545,12 @@ handle_signal(unsigned long sig, struct
+ * 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)
++static void do_signal(struct pt_regs *regs, unsigned int save_r0)
+ {
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
++ sigset_t *oldset;
+
+ /*
+ * We want the common case to go fast, which
+@@ -576,19 +559,27 @@ int do_signal(struct pt_regs *regs, sigs
+ * if so.
+ */
+ if (!user_mode(regs))
+- return 1;
++ return;
+
+ if (try_to_freeze())
+ goto no_signal;
+
+- if (!oldset)
++ if (test_thread_flag(TIF_RESTORE_SIGMASK))
++ oldset = ¤t->saved_sigmask;
++ else
+ oldset = ¤t->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+- handle_signal(signr, &ka, &info, oldset, regs);
+- return 1;
++ if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
++ /* a signal was successfully delivered; the saved
++ * sigmask will have been stored in the signal frame,
++ * and will be restored by sigreturn, so we can simply
++ * clear the TIF_RESTORE_SIGMASK flag */
++ if (test_thread_flag(TIF_RESTORE_SIGMASK))
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ }
+ }
+
+ no_signal:
+@@ -597,10 +588,27 @@ int do_signal(struct pt_regs *regs, sigs
+ /* Restart the system call - no handlers present */
+ if (regs->regs[0] == -ERESTARTNOHAND ||
+ regs->regs[0] == -ERESTARTSYS ||
+- regs->regs[0] == -ERESTARTNOINTR ||
+- regs->regs[0] == -ERESTART_RESTARTBLOCK) {
++ regs->regs[0] == -ERESTARTNOINTR) {
++ regs->regs[0] = save_r0;
++ regs->pc -= 2;
++ } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
+ regs->pc -= 2;
++ regs->regs[3] = __NR_restart_syscall;
+ }
+ }
+- return 0;
++
++ /* if there's no signal to deliver, we just put the saved sigmask
++ * back */
++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
++ }
++}
++
++asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
++ __u32 thread_info_flags)
++{
++ /* deal with pending signal delivery */
++ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
++ do_signal(regs, save_r0);
+ }
+diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
+index 6c0fb7c..dbebadd 100644
+--- a/arch/sh/kernel/smp.c
++++ b/arch/sh/kernel/smp.c
+@@ -42,6 +42,7 @@ cpumask_t cpu_possible_map;
+ EXPORT_SYMBOL(cpu_possible_map);
+
+ cpumask_t cpu_online_map;
++EXPORT_SYMBOL(cpu_online_map);
+ static atomic_t cpus_booted = ATOMIC_INIT(0);
+
+ /* These are defined by the board-specific code. */
+diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
+index 917b2f3..8fde950 100644
+--- a/arch/sh/kernel/sys_sh.c
++++ b/arch/sh/kernel/sys_sh.c
+@@ -21,9 +21,11 @@
+ #include <linux/mman.h>
+ #include <linux/file.h>
+ #include <linux/utsname.h>
+-
++#include <linux/module.h>
++#include <asm/cacheflush.h>
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
++#include <asm/unistd.h>
+
+ /*
+ * sys_pipe() is the normal C calling standard for creating
+@@ -44,11 +46,16 @@ asmlinkage int sys_pipe(unsigned long r4
+ return error;
+ }
+
+-#if defined(HAVE_ARCH_UNMAPPED_AREA)
++unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
++
++EXPORT_SYMBOL(shm_align_mask);
++
+ /*
+- * To avoid cache alias, we map the shard page with same color.
++ * To avoid cache aliases, we map the shared page with same color.
+ */
+-#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1))
++#define COLOUR_ALIGN(addr, pgoff) \
++ ((((addr) + shm_align_mask) & ~shm_align_mask) + \
++ (((pgoff) << PAGE_SHIFT) & shm_align_mask))
+
+ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+@@ -56,43 +63,52 @@ unsigned long arch_get_unmapped_area(str
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long start_addr;
++ int do_colour_align;
+
+ if (flags & MAP_FIXED) {
+ /* We do not accept a shared mapping if it would violate
+ * cache aliasing constraints.
+ */
+- if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
++ if ((flags & MAP_SHARED) && (addr & shm_align_mask))
+ return -EINVAL;
+ return addr;
+ }
+
+- if (len > TASK_SIZE)
++ if (unlikely(len > TASK_SIZE))
+ return -ENOMEM;
+
++ do_colour_align = 0;
++ if (filp || (flags & MAP_SHARED))
++ do_colour_align = 1;
++
+ if (addr) {
+- if (flags & MAP_PRIVATE)
+- addr = PAGE_ALIGN(addr);
++ if (do_colour_align)
++ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+- addr = COLOUR_ALIGN(addr);
++ addr = PAGE_ALIGN(addr);
++
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+- if (len <= mm->cached_hole_size) {
++
++ if (len > mm->cached_hole_size) {
++ start_addr = addr = mm->free_area_cache;
++ } else {
+ mm->cached_hole_size = 0;
+- mm->free_area_cache = TASK_UNMAPPED_BASE;
++ start_addr = addr = TASK_UNMAPPED_BASE;
+ }
+- if (flags & MAP_PRIVATE)
+- addr = PAGE_ALIGN(mm->free_area_cache);
+- else
+- addr = COLOUR_ALIGN(mm->free_area_cache);
+- start_addr = addr;
+
+ full_search:
++ if (do_colour_align)
++ addr = COLOUR_ALIGN(addr, pgoff);
++ else
++ addr = PAGE_ALIGN(mm->free_area_cache);
++
+ for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
+ /* At this point: (!vma || addr < vma->vm_end). */
+- if (TASK_SIZE - len < addr) {
++ if (unlikely(TASK_SIZE - len < addr)) {
+ /*
+ * Start a new search - just in case we missed
+ * some holes.
+@@ -104,7 +120,7 @@ full_search:
+ }
+ return -ENOMEM;
+ }
+- if (!vma || addr + len <= vma->vm_start) {
++ if (likely(!vma || addr + len <= vma->vm_start)) {
+ /*
+ * Remember the place where we stopped the search:
+ */
+@@ -115,11 +131,10 @@ full_search:
+ mm->cached_hole_size = vma->vm_start - addr;
+
+ addr = vma->vm_end;
+- if (!(flags & MAP_PRIVATE))
+- addr = COLOUR_ALIGN(addr);
++ if (do_colour_align)
++ addr = COLOUR_ALIGN(addr, pgoff);
+ }
+ }
+-#endif
+
+ static inline long
+ do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+@@ -267,7 +282,7 @@ asmlinkage int sys_uname(struct old_utsn
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+- err=copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ return err?-EFAULT:0;
+ }
+@@ -295,3 +310,19 @@ asmlinkage int sys_fadvise64_64_wrapper(
+ (u64)len0 << 32 | len1, advice);
+ #endif
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register long __sc0 __asm__ ("r3") = __NR_execve;
++ register long __sc4 __asm__ ("r4") = (long) filename;
++ register long __sc5 __asm__ ("r5") = (long) argv;
++ register long __sc6 __asm__ ("r6") = (long) envp;
++ __asm__ __volatile__ ("trapa #0x13" : "=z" (__sc0)
++ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
++ : "memory");
++ return __sc0;
++}
+diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
+new file mode 100644
+index 0000000..ca81976
+--- /dev/null
++++ b/arch/sh/kernel/syscalls.S
+@@ -0,0 +1,356 @@
++/*
++ * arch/sh/kernel/syscalls.S
++ *
++ * System call table for SuperH
++ *
++ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
++ * Copyright (C) 2003 Paul Mundt
++ *
++ * 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/sys.h>
++#include <linux/linkage.h>
++
++#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
++#define sys_nfsservctl sys_ni_syscall
++#endif
++
++#if !defined(CONFIG_MMU)
++#define sys_madvise sys_ni_syscall
++#define sys_readahead sys_ni_syscall
++#define sys_mprotect sys_ni_syscall
++#define sys_msync sys_ni_syscall
++#define sys_mlock sys_ni_syscall
++#define sys_munlock sys_ni_syscall
++#define sys_mlockall sys_ni_syscall
++#define sys_munlockall sys_ni_syscall
++#define sys_mremap sys_ni_syscall
++#define sys_mincore sys_ni_syscall
++#define sys_remap_file_pages sys_ni_syscall
++#endif
++
++ .data
++ENTRY(sys_call_table)
++ .long sys_restart_syscall /* 0 - old "setup()" system call*/
++ .long sys_exit
++ .long sys_fork
++ .long sys_read
++ .long sys_write
++ .long sys_open /* 5 */
++ .long sys_close
++ .long sys_waitpid
++ .long sys_creat
++ .long sys_link
++ .long sys_unlink /* 10 */
++ .long sys_execve
++ .long sys_chdir
++ .long sys_time
++ .long sys_mknod
++ .long sys_chmod /* 15 */
++ .long sys_lchown16
++ .long sys_ni_syscall /* old break syscall holder */
++ .long sys_stat
++ .long sys_lseek
++ .long sys_getpid /* 20 */
++ .long sys_mount
++ .long sys_oldumount
++ .long sys_setuid16
++ .long sys_getuid16
++ .long sys_stime /* 25 */
++ .long sys_ptrace
++ .long sys_alarm
++ .long sys_fstat
++ .long sys_pause
++ .long sys_utime /* 30 */
++ .long sys_ni_syscall /* old stty syscall holder */
++ .long sys_ni_syscall /* old gtty syscall holder */
++ .long sys_access
++ .long sys_nice
++ .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
++ .long sys_sync
++ .long sys_kill
++ .long sys_rename
++ .long sys_mkdir
++ .long sys_rmdir /* 40 */
++ .long sys_dup
++ .long sys_pipe
++ .long sys_times
++ .long sys_ni_syscall /* old prof syscall holder */
++ .long sys_brk /* 45 */
++ .long sys_setgid16
++ .long sys_getgid16
++ .long sys_signal
++ .long sys_geteuid16
++ .long sys_getegid16 /* 50 */
++ .long sys_acct
++ .long sys_umount /* recycled never used phys() */
++ .long sys_ni_syscall /* old lock syscall holder */
++ .long sys_ioctl
++ .long sys_fcntl /* 55 */
++ .long sys_ni_syscall /* old mpx syscall holder */
++ .long sys_setpgid
++ .long sys_ni_syscall /* old ulimit syscall holder */
++ .long sys_ni_syscall /* sys_olduname */
++ .long sys_umask /* 60 */
++ .long sys_chroot
++ .long sys_ustat
++ .long sys_dup2
++ .long sys_getppid
++ .long sys_getpgrp /* 65 */
++ .long sys_setsid
++ .long sys_sigaction
++ .long sys_sgetmask
++ .long sys_ssetmask
++ .long sys_setreuid16 /* 70 */
++ .long sys_setregid16
++ .long sys_sigsuspend
++ .long sys_sigpending
++ .long sys_sethostname
++ .long sys_setrlimit /* 75 */
++ .long sys_old_getrlimit
++ .long sys_getrusage
++ .long sys_gettimeofday
++ .long sys_settimeofday
++ .long sys_getgroups16 /* 80 */
++ .long sys_setgroups16
++ .long sys_ni_syscall /* sys_oldselect */
++ .long sys_symlink
++ .long sys_lstat
++ .long sys_readlink /* 85 */
++ .long sys_uselib
++ .long sys_swapon
++ .long sys_reboot
++ .long old_readdir
++ .long old_mmap /* 90 */
++ .long sys_munmap
++ .long sys_truncate
++ .long sys_ftruncate
++ .long sys_fchmod
++ .long sys_fchown16 /* 95 */
++ .long sys_getpriority
++ .long sys_setpriority
++ .long sys_ni_syscall /* old profil syscall holder */
++ .long sys_statfs
++ .long sys_fstatfs /* 100 */
++ .long sys_ni_syscall /* ioperm */
++ .long sys_socketcall
++ .long sys_syslog
++ .long sys_setitimer
++ .long sys_getitimer /* 105 */
++ .long sys_newstat
++ .long sys_newlstat
++ .long sys_newfstat
++ .long sys_uname
++ .long sys_ni_syscall /* 110 */ /* iopl */
++ .long sys_vhangup
++ .long sys_ni_syscall /* idle */
++ .long sys_ni_syscall /* vm86old */
++ .long sys_wait4
++ .long sys_swapoff /* 115 */
++ .long sys_sysinfo
++ .long sys_ipc
++ .long sys_fsync
++ .long sys_sigreturn
++ .long sys_clone /* 120 */
++ .long sys_setdomainname
++ .long sys_newuname
++ .long sys_ni_syscall /* sys_modify_ldt */
++ .long sys_adjtimex
++ .long sys_mprotect /* 125 */
++ .long sys_sigprocmask
++ .long sys_ni_syscall /* old "create_module" */
++ .long sys_init_module
++ .long sys_delete_module
++ .long sys_ni_syscall /* 130: old "get_kernel_syms" */
++ .long sys_quotactl
++ .long sys_getpgid
++ .long sys_fchdir
++ .long sys_bdflush
++ .long sys_sysfs /* 135 */
++ .long sys_personality
++ .long sys_ni_syscall /* for afs_syscall */
++ .long sys_setfsuid16
++ .long sys_setfsgid16
++ .long sys_llseek /* 140 */
++ .long sys_getdents
++ .long sys_select
++ .long sys_flock
++ .long sys_msync
++ .long sys_readv /* 145 */
++ .long sys_writev
++ .long sys_getsid
++ .long sys_fdatasync
++ .long sys_sysctl
++ .long sys_mlock /* 150 */
++ .long sys_munlock
++ .long sys_mlockall
++ .long sys_munlockall
++ .long sys_sched_setparam
++ .long sys_sched_getparam /* 155 */
++ .long sys_sched_setscheduler
++ .long sys_sched_getscheduler
++ .long sys_sched_yield
++ .long sys_sched_get_priority_max
++ .long sys_sched_get_priority_min /* 160 */
++ .long sys_sched_rr_get_interval
++ .long sys_nanosleep
++ .long sys_mremap
++ .long sys_setresuid16
++ .long sys_getresuid16 /* 165 */
++ .long sys_ni_syscall /* vm86 */
++ .long sys_ni_syscall /* old "query_module" */
++ .long sys_poll
++ .long sys_nfsservctl
++ .long sys_setresgid16 /* 170 */
++ .long sys_getresgid16
++ .long sys_prctl
++ .long sys_rt_sigreturn
++ .long sys_rt_sigaction
++ .long sys_rt_sigprocmask /* 175 */
++ .long sys_rt_sigpending
++ .long sys_rt_sigtimedwait
++ .long sys_rt_sigqueueinfo
++ .long sys_rt_sigsuspend
++ .long sys_pread_wrapper /* 180 */
++ .long sys_pwrite_wrapper
++ .long sys_chown16
++ .long sys_getcwd
++ .long sys_capget
++ .long sys_capset /* 185 */
++ .long sys_sigaltstack
++ .long sys_sendfile
++ .long sys_ni_syscall /* streams1 */
++ .long sys_ni_syscall /* streams2 */
++ .long sys_vfork /* 190 */
++ .long sys_getrlimit
++ .long sys_mmap2
++ .long sys_truncate64
++ .long sys_ftruncate64
++ .long sys_stat64 /* 195 */
++ .long sys_lstat64
++ .long sys_fstat64
++ .long sys_lchown
++ .long sys_getuid
++ .long sys_getgid /* 200 */
++ .long sys_geteuid
++ .long sys_getegid
++ .long sys_setreuid
++ .long sys_setregid
++ .long sys_getgroups /* 205 */
++ .long sys_setgroups
++ .long sys_fchown
++ .long sys_setresuid
++ .long sys_getresuid
++ .long sys_setresgid /* 210 */
++ .long sys_getresgid
++ .long sys_chown
++ .long sys_setuid
++ .long sys_setgid
++ .long sys_setfsuid /* 215 */
++ .long sys_setfsgid
++ .long sys_pivot_root
++ .long sys_mincore
++ .long sys_madvise
++ .long sys_getdents64 /* 220 */
++ .long sys_fcntl64
++ .long sys_ni_syscall /* reserved for TUX */
++ .long sys_ni_syscall /* Reserved for Security */
++ .long sys_gettid
++ .long sys_readahead /* 225 */
++ .long sys_setxattr
++ .long sys_lsetxattr
++ .long sys_fsetxattr
++ .long sys_getxattr
++ .long sys_lgetxattr /* 230 */
++ .long sys_fgetxattr
++ .long sys_listxattr
++ .long sys_llistxattr
++ .long sys_flistxattr
++ .long sys_removexattr /* 235 */
++ .long sys_lremovexattr
++ .long sys_fremovexattr
++ .long sys_tkill
++ .long sys_sendfile64
++ .long sys_futex /* 240 */
++ .long sys_sched_setaffinity
++ .long sys_sched_getaffinity
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_io_setup /* 245 */
++ .long sys_io_destroy
++ .long sys_io_getevents
++ .long sys_io_submit
++ .long sys_io_cancel
++ .long sys_fadvise64 /* 250 */
++ .long sys_ni_syscall
++ .long sys_exit_group
++ .long sys_lookup_dcookie
++ .long sys_epoll_create
++ .long sys_epoll_ctl /* 255 */
++ .long sys_epoll_wait
++ .long sys_remap_file_pages
++ .long sys_set_tid_address
++ .long sys_timer_create
++ .long sys_timer_settime /* 260 */
++ .long sys_timer_gettime
++ .long sys_timer_getoverrun
++ .long sys_timer_delete
++ .long sys_clock_settime
++ .long sys_clock_gettime /* 265 */
++ .long sys_clock_getres
++ .long sys_clock_nanosleep
++ .long sys_statfs64
++ .long sys_fstatfs64
++ .long sys_tgkill /* 270 */
++ .long sys_utimes
++ .long sys_fadvise64_64_wrapper
++ .long sys_ni_syscall /* Reserved for vserver */
++ .long sys_ni_syscall /* Reserved for mbind */
++ .long sys_ni_syscall /* 275 - get_mempolicy */
++ .long sys_ni_syscall /* set_mempolicy */
++ .long sys_mq_open
++ .long sys_mq_unlink
++ .long sys_mq_timedsend
++ .long sys_mq_timedreceive /* 280 */
++ .long sys_mq_notify
++ .long sys_mq_getsetattr
++ .long sys_kexec_load
++ .long sys_waitid
++ .long sys_ni_syscall /* 285 */
++ .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
++ .long sys_migrate_pages
++ .long sys_openat /* 295 */
++ .long sys_mkdirat
++ .long sys_mknodat
++ .long sys_fchownat
++ .long sys_futimesat
++ .long sys_fstatat64 /* 300 */
++ .long sys_unlinkat
++ .long sys_renameat
++ .long sys_linkat
++ .long sys_symlinkat
++ .long sys_readlinkat /* 305 */
++ .long sys_fchmodat
++ .long sys_faccessat
++ .long sys_pselect6
++ .long sys_ppoll
++ .long sys_unshare /* 310 */
++ .long sys_set_robust_list
++ .long sys_get_robust_list
++ .long sys_splice
++ .long sys_sync_file_range
++ .long sys_tee /* 315 */
++ .long sys_vmsplice
++ .long sys_move_pages
++ .long sys_getcpu
++ .long sys_epoll_pwait
+diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
+index a1589f8..57e708d 100644
+--- a/arch/sh/kernel/time.c
++++ b/arch/sh/kernel/time.c
+@@ -3,13 +3,12 @@
+ *
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ * Copyright (C) 2000 Philipp Rumpf <prumpf at tux.org>
+- * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
++ * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 M. R. Brown <mrbrown at linux-sh.org>
+ *
+ * Some code taken from i386 version.
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ */
+-
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+@@ -19,22 +18,26 @@
+ #include <asm/timer.h>
+ #include <asm/kgdb.h>
+
+-extern unsigned long wall_jiffies;
+ struct sys_timer *sys_timer;
+
+ /* Move this somewhere more sensible.. */
+ DEFINE_SPINLOCK(rtc_lock);
+ EXPORT_SYMBOL(rtc_lock);
+
+-/* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want
+- * these routines anywhere... */
+-#ifdef CONFIG_SH_RTC
+-void (*rtc_get_time)(struct timespec *) = sh_rtc_gettimeofday;
+-int (*rtc_set_time)(const time_t) = sh_rtc_settimeofday;
+-#else
+-void (*rtc_get_time)(struct timespec *);
+-int (*rtc_set_time)(const time_t);
+-#endif
++/* Dummy RTC ops */
++static void null_rtc_get_time(struct timespec *tv)
++{
++ tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
++ tv->tv_nsec = 0;
++}
++
++static int null_rtc_set_time(const time_t secs)
++{
++ return 0;
++}
++
++void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
++int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
+
+ /*
+ * Scheduler clock - returns current time in nanosec units.
+@@ -44,20 +47,15 @@ unsigned long long __attribute__ ((weak)
+ return (unsigned long long)jiffies * (1000000000 / HZ);
+ }
+
++#ifndef CONFIG_GENERIC_TIME
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long seq;
+ unsigned long usec, sec;
+- unsigned long lost;
+
+ do {
+ seq = read_seqbegin(&xtime_lock);
+ usec = get_timer_offset();
+-
+- lost = jiffies - wall_jiffies;
+- if (lost)
+- usec += lost * (1000000 / HZ);
+-
+ sec = xtime.tv_sec;
+ usec += xtime.tv_nsec / 1000;
+ } while (read_seqretry(&xtime_lock, seq));
+@@ -70,7 +68,6 @@ void do_gettimeofday(struct timeval *tv)
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+ }
+-
+ EXPORT_SYMBOL(do_gettimeofday);
+
+ int do_settimeofday(struct timespec *tv)
+@@ -88,8 +85,7 @@ int do_settimeofday(struct timespec *tv)
+ * wall time. Discover what correction gettimeofday() would have
+ * made, and then undo it!
+ */
+- nsec -= 1000 * (get_timer_offset() +
+- (jiffies - wall_jiffies) * (1000000 / HZ));
++ nsec -= 1000 * get_timer_offset();
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+@@ -103,8 +99,8 @@ int do_settimeofday(struct timespec *tv)
+
+ return 0;
+ }
+-
+ EXPORT_SYMBOL(do_settimeofday);
++#endif /* !CONFIG_GENERIC_TIME */
+
+ /* last time the RTC clock got updated */
+ static long last_rtc_update;
+@@ -113,13 +109,14 @@ static long last_rtc_update;
+ * handle_timer_tick() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+-void handle_timer_tick(struct pt_regs *regs)
++void handle_timer_tick(void)
+ {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+- profile_tick(CPU_PROFILING, regs);
++ if (current->pid)
++ profile_tick(CPU_PROFILING);
+
+ #ifdef CONFIG_HEARTBEAT
+ if (sh_mv.mv_heartbeat != NULL)
+@@ -135,7 +132,7 @@ void handle_timer_tick(struct pt_regs *r
+ xtime.tv_sec > last_rtc_update + 660 &&
+ (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+ (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+- if (rtc_set_time(xtime.tv_sec) == 0)
++ if (rtc_sh_set_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ /* do it again in 60s */
+@@ -143,8 +140,33 @@ void handle_timer_tick(struct pt_regs *r
+ }
+ }
+
++#ifdef CONFIG_PM
++int timer_suspend(struct sys_device *dev, pm_message_t state)
++{
++ struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
++
++ sys_timer->ops->stop();
++
++ return 0;
++}
++
++int timer_resume(struct sys_device *dev)
++{
++ struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
++
++ sys_timer->ops->start();
++
++ return 0;
++}
++#else
++#define timer_suspend NULL
++#define timer_resume NULL
++#endif
++
+ static struct sysdev_class timer_sysclass = {
+ set_kset_name("timer"),
++ .suspend = timer_suspend,
++ .resume = timer_resume,
+ };
+
+ static int __init timer_init_sysfs(void)
+@@ -156,7 +178,6 @@ static int __init timer_init_sysfs(void)
+ sys_timer->dev.cls = &timer_sysclass;
+ return sysdev_register(&sys_timer->dev);
+ }
+-
+ device_initcall(timer_init_sysfs);
+
+ void (*board_time_init)(void);
+@@ -168,15 +189,9 @@ void __init time_init(void)
+
+ clk_init();
+
+- if (rtc_get_time) {
+- rtc_get_time(&xtime);
+- } else {
+- xtime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+- xtime.tv_nsec = 0;
+- }
+-
+- set_normalized_timespec(&wall_to_monotonic,
+- -xtime.tv_sec, -xtime.tv_nsec);
++ rtc_sh_get_time(&xtime);
++ set_normalized_timespec(&wall_to_monotonic,
++ -xtime.tv_sec, -xtime.tv_nsec);
+
+ /*
+ * Find the timer to use as the system timer, it will be
+diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
+index d4212ad..2492701 100644
+--- a/arch/sh/kernel/timers/timer-tmu.c
++++ b/arch/sh/kernel/timers/timer-tmu.c
+@@ -80,8 +80,7 @@ static unsigned long tmu_timer_get_offse
+ return count;
+ }
+
+-static irqreturn_t tmu_timer_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
+ {
+ unsigned long timer_status;
+
+@@ -98,7 +97,7 @@ static irqreturn_t tmu_timer_interrupt(i
+ * locally disabled. -arca
+ */
+ write_seqlock(&xtime_lock);
+- handle_timer_tick(regs);
++ handle_timer_tick();
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+@@ -111,60 +110,6 @@ static struct irqaction tmu_irq = {
+ .mask = CPU_MASK_NONE,
+ };
+
+-/*
+- * Hah! We'll see if this works (switching from usecs to nsecs).
+- */
+-static unsigned long tmu_timer_get_frequency(void)
+-{
+- u32 freq;
+- struct timespec ts1, ts2;
+- unsigned long diff_nsec;
+- unsigned long factor;
+-
+- /* Setup the timer: We don't want to generate interrupts, just
+- * have it count down at its natural rate.
+- */
+- ctrl_outb(0, TMU_TSTR);
+-#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
+- ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+-#endif
+- ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR);
+- ctrl_outl(0xffffffff, TMU0_TCOR);
+- ctrl_outl(0xffffffff, TMU0_TCNT);
+-
+- rtc_get_time(&ts2);
+-
+- do {
+- rtc_get_time(&ts1);
+- } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+-
+- /* actually start the timer */
+- ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+-
+- do {
+- rtc_get_time(&ts2);
+- } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+-
+- freq = 0xffffffff - ctrl_inl(TMU0_TCNT);
+- if (ts2.tv_nsec < ts1.tv_nsec) {
+- ts2.tv_nsec += 1000000000;
+- ts2.tv_sec--;
+- }
+-
+- diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
+-
+- /* this should work well if the RTC has a precision of n Hz, where
+- * n is an integer. I don't think we have to worry about the other
+- * cases. */
+- factor = (1000000000 + diff_nsec/2) / diff_nsec;
+-
+- if (factor * diff_nsec > 1100000000 ||
+- factor * diff_nsec < 900000000)
+- panic("weird RTC (diff_nsec %ld)", diff_nsec);
+-
+- return freq * factor;
+-}
+-
+ static void tmu_clk_init(struct clk *clk)
+ {
+ u8 divisor = TMU0_TCR_INIT & 0x7;
+@@ -188,6 +133,18 @@ static struct clk tmu0_clk = {
+ .ops = &tmu_clk_ops,
+ };
+
++static int tmu_timer_start(void)
++{
++ ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
++ return 0;
++}
++
++static int tmu_timer_stop(void)
++{
++ ctrl_outb(0, TMU_TSTR);
++ return 0;
++}
++
+ static int tmu_timer_init(void)
+ {
+ unsigned long interval;
+@@ -197,7 +154,7 @@ static int tmu_timer_init(void)
+ tmu0_clk.parent = clk_get("module_clk");
+
+ /* Start TMU0 */
+- ctrl_outb(0, TMU_TSTR);
++ tmu_timer_stop();
+ #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
+ ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+ #endif
+@@ -211,19 +168,21 @@ static int tmu_timer_init(void)
+ ctrl_outl(interval, TMU0_TCOR);
+ ctrl_outl(interval, TMU0_TCNT);
+
+- ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
++ tmu_timer_start();
+
+ return 0;
+ }
+
+ struct sys_timer_ops tmu_timer_ops = {
+ .init = tmu_timer_init,
+- .get_frequency = tmu_timer_get_frequency,
++ .start = tmu_timer_start,
++ .stop = tmu_timer_stop,
++#ifndef CONFIG_GENERIC_TIME
+ .get_offset = tmu_timer_get_offset,
++#endif
+ };
+
+ struct sys_timer tmu_timer = {
+ .name = "tmu",
+ .ops = &tmu_timer_ops,
+ };
+-
+diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
+index d9db118..53dfa55 100644
+--- a/arch/sh/kernel/traps.c
++++ b/arch/sh/kernel/traps.c
+@@ -1,75 +1,37 @@
+-/* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $
+- *
+- * linux/arch/sh/traps.c
++/*
++ * 'traps.c' handles hardware traps and faults after we have saved some
++ * state in 'entry.S'.
+ *
+ * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2000 Philipp Rumpf
+ * Copyright (C) 2000 David Howells
+- * Copyright (C) 2002, 2003 Paul Mundt
+- */
+-
+-/*
+- * 'Traps.c' handles hardware traps and faults after we have saved some
+- * state in 'entry.S'.
++ * Copyright (C) 2002 - 2006 Paul Mundt
++ *
++ * 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/sched.h>
+ #include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/errno.h>
+ #include <linux/ptrace.h>
+-#include <linux/timer.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+ #include <linux/init.h>
+-#include <linux/delay.h>
+ #include <linux/spinlock.h>
+ #include <linux/module.h>
+ #include <linux/kallsyms.h>
+-
++#include <linux/io.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/atomic.h>
+-#include <asm/processor.h>
+-#include <asm/sections.h>
+
+ #ifdef CONFIG_SH_KGDB
+ #include <asm/kgdb.h>
+-#define CHK_REMOTE_DEBUG(regs) \
+-{ \
+- if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \
+- { \
+- (*kgdb_debug_hook)(regs); \
+- } \
++#define CHK_REMOTE_DEBUG(regs) \
++{ \
++ if (kgdb_debug_hook && !user_mode(regs))\
++ (*kgdb_debug_hook)(regs); \
+ }
+ #else
+ #define CHK_REMOTE_DEBUG(regs)
+ #endif
+
+-#define DO_ERROR(trapnr, signr, str, name, tsk) \
+-asmlinkage void do_##name(unsigned long r4, unsigned long r5, \
+- unsigned long r6, unsigned long r7, \
+- struct pt_regs regs) \
+-{ \
+- unsigned long error_code; \
+- \
+- /* Check if it's a DSP instruction */ \
+- if (is_dsp_inst(®s)) { \
+- /* Enable DSP mode, and restart instruction. */ \
+- regs.sr |= SR_DSP; \
+- return; \
+- } \
+- \
+- asm volatile("stc r2_bank, %0": "=r" (error_code)); \
+- local_irq_enable(); \
+- tsk->thread.error_code = error_code; \
+- tsk->thread.trap_no = trapnr; \
+- CHK_REMOTE_DEBUG(®s); \
+- force_sig(signr, tsk); \
+- die_if_no_fixup(str,®s,error_code); \
+-}
+-
+ #ifdef CONFIG_CPU_SH2
+ #define TRAP_RESERVED_INST 4
+ #define TRAP_ILLEGAL_SLOT_INST 6
+@@ -78,15 +40,34 @@ asmlinkage void do_##name(unsigned long
+ #define TRAP_ILLEGAL_SLOT_INST 13
+ #endif
+
+-/*
+- * These constants are for searching for possible module text
+- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
+- * a guess of how much space is likely to be vmalloced.
+- */
+-#define VMALLOC_OFFSET (8*1024*1024)
+-#define MODULE_RANGE (8*1024*1024)
++static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
++{
++ unsigned long p;
++ int i;
++
++ printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
++
++ for (p = bottom & ~31; p < top; ) {
++ printk("%04lx: ", p & 0xffff);
++
++ for (i = 0; i < 8; i++, p += 4) {
++ unsigned int val;
++
++ if (p < bottom || p >= top)
++ printk(" ");
++ else {
++ if (__get_user(val, (unsigned int __user *)p)) {
++ printk("\n");
++ return;
++ }
++ printk("%08x ", val);
++ }
++ }
++ printk("\n");
++ }
++}
+
+-spinlock_t die_lock;
++DEFINE_SPINLOCK(die_lock);
+
+ void die(const char * str, struct pt_regs * regs, long err)
+ {
+@@ -94,14 +75,28 @@ void die(const char * str, struct pt_reg
+
+ console_verbose();
+ spin_lock_irq(&die_lock);
++ bust_spinlocks(1);
++
+ printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
++
+ CHK_REMOTE_DEBUG(regs);
++ print_modules();
+ show_regs(regs);
++
++ printk("Process: %s (pid: %d, stack limit = %p)\n",
++ current->comm, current->pid, task_stack_page(current) + 1);
++
++ if (!user_mode(regs) || in_interrupt())
++ dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
++ (unsigned long)task_stack_page(current));
++
++ bust_spinlocks(0);
+ spin_unlock_irq(&die_lock);
+ do_exit(SIGSEGV);
+ }
+
+-static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
++static inline void die_if_kernel(const char *str, struct pt_regs *regs,
++ long err)
+ {
+ if (!user_mode(regs))
+ die(str, regs, err);
+@@ -118,8 +113,7 @@ static int handle_unaligned_notify_count
+ */
+ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
+ {
+- if (!user_mode(regs))
+- {
++ if (!user_mode(regs)) {
+ const struct exception_table_entry *fixup;
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+@@ -575,8 +569,120 @@ int is_dsp_inst(struct pt_regs *regs)
+ #define is_dsp_inst(regs) (0)
+ #endif /* CONFIG_SH_DSP */
+
+-DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current)
+-DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current)
++/* arch/sh/kernel/cpu/sh4/fpu.c */
++extern int do_fpu_inst(unsigned short, struct pt_regs *);
++extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
++ unsigned long r6, unsigned long r7, struct pt_regs regs);
++
++asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
++ unsigned long r6, unsigned long r7,
++ struct pt_regs regs)
++{
++ unsigned long error_code;
++ struct task_struct *tsk = current;
++
++#ifdef CONFIG_SH_FPU_EMU
++ unsigned short inst;
++ int err;
++
++ get_user(inst, (unsigned short*)regs.pc);
++
++ err = do_fpu_inst(inst, ®s);
++ if (!err) {
++ regs.pc += 2;
++ return;
++ }
++ /* not a FPU inst. */
++#endif
++
++#ifdef CONFIG_SH_DSP
++ /* Check if it's a DSP instruction */
++ if (is_dsp_inst(®s)) {
++ /* Enable DSP mode, and restart instruction. */
++ regs.sr |= SR_DSP;
++ return;
++ }
++#endif
++
++ asm volatile("stc r2_bank, %0": "=r" (error_code));
++ local_irq_enable();
++ tsk->thread.error_code = error_code;
++ tsk->thread.trap_no = TRAP_RESERVED_INST;
++ CHK_REMOTE_DEBUG(®s);
++ force_sig(SIGILL, tsk);
++ die_if_no_fixup("reserved instruction", ®s, error_code);
++}
++
++#ifdef CONFIG_SH_FPU_EMU
++static int emulate_branch(unsigned short inst, struct pt_regs* regs)
++{
++ /*
++ * bfs: 8fxx: PC+=d*2+4;
++ * bts: 8dxx: PC+=d*2+4;
++ * bra: axxx: PC+=D*2+4;
++ * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
++ * braf:0x23: PC+=Rn*2+4;
++ * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
++ * jmp: 4x2b: PC=Rn;
++ * jsr: 4x0b: PC=Rn after PR=PC+4;
++ * rts: 000b: PC=PR;
++ */
++ if ((inst & 0xfd00) == 0x8d00) {
++ regs->pc += SH_PC_8BIT_OFFSET(inst);
++ return 0;
++ }
++
++ if ((inst & 0xe000) == 0xa000) {
++ regs->pc += SH_PC_12BIT_OFFSET(inst);
++ return 0;
++ }
++
++ if ((inst & 0xf0df) == 0x0003) {
++ regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
++ return 0;
++ }
++
++ if ((inst & 0xf0df) == 0x400b) {
++ regs->pc = regs->regs[(inst & 0x0f00) >> 8];
++ return 0;
++ }
++
++ if ((inst & 0xffff) == 0x000b) {
++ regs->pc = regs->pr;
++ return 0;
++ }
++
++ return 1;
++}
++#endif
++
++asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
++ unsigned long r6, unsigned long r7,
++ struct pt_regs regs)
++{
++ unsigned long error_code;
++ struct task_struct *tsk = current;
++#ifdef CONFIG_SH_FPU_EMU
++ unsigned short inst;
++
++ get_user(inst, (unsigned short *)regs.pc + 1);
++ if (!do_fpu_inst(inst, ®s)) {
++ get_user(inst, (unsigned short *)regs.pc);
++ if (!emulate_branch(inst, ®s))
++ return;
++ /* fault in branch.*/
++ }
++ /* not a FPU inst. */
++#endif
++
++ asm volatile("stc r2_bank, %0": "=r" (error_code));
++ local_irq_enable();
++ tsk->thread.error_code = error_code;
++ tsk->thread.trap_no = TRAP_RESERVED_INST;
++ CHK_REMOTE_DEBUG(®s);
++ force_sig(SIGILL, tsk);
++ die_if_no_fixup("illegal slot instruction", ®s, error_code);
++}
+
+ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+@@ -625,83 +731,76 @@ void __init per_cpu_trap_init(void)
+ : "memory");
+ }
+
+-void __init trap_init(void)
++void *set_exception_table_vec(unsigned int vec, void *handler)
+ {
+ extern void *exception_handling_table[];
++ void *old_handler;
++
++ old_handler = exception_handling_table[vec];
++ exception_handling_table[vec] = handler;
++ return old_handler;
++}
+
+- exception_handling_table[TRAP_RESERVED_INST]
+- = (void *)do_reserved_inst;
+- exception_handling_table[TRAP_ILLEGAL_SLOT_INST]
+- = (void *)do_illegal_slot_inst;
+-
+-#ifdef CONFIG_CPU_SH4
+- if (!(cpu_data->flags & CPU_HAS_FPU)) {
+- /* For SH-4 lacking an FPU, treat floating point instructions
+- as reserved. */
+- /* entry 64 corresponds to EXPEVT=0x800 */
+- exception_handling_table[64] = (void *)do_reserved_inst;
+- exception_handling_table[65] = (void *)do_illegal_slot_inst;
+- }
++void __init trap_init(void)
++{
++ set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
++ set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
++
++#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
++ defined(CONFIG_SH_FPU_EMU)
++ /*
++ * For SH-4 lacking an FPU, treat floating point instructions as
++ * reserved. They'll be handled in the math-emu case, or faulted on
++ * otherwise.
++ */
++ set_exception_table_evt(0x800, do_reserved_inst);
++ set_exception_table_evt(0x820, do_illegal_slot_inst);
++#elif defined(CONFIG_SH_FPU)
++ set_exception_table_evt(0x800, do_fpu_state_restore);
++ set_exception_table_evt(0x820, do_fpu_state_restore);
+ #endif
+
+ /* Setup VBR for boot cpu */
+ per_cpu_trap_init();
+ }
+
+-void show_stack(struct task_struct *tsk, unsigned long *sp)
++void show_trace(struct task_struct *tsk, unsigned long *sp,
++ struct pt_regs *regs)
+ {
+- unsigned long *stack, addr;
+- unsigned long module_start = VMALLOC_START;
+- unsigned long module_end = VMALLOC_END;
+- int i = 1;
++ unsigned long addr;
+
+- if (tsk && !sp) {
+- sp = (unsigned long *)tsk->thread.sp;
+- }
+-
+- if (!sp) {
+- __asm__ __volatile__ (
+- "mov r15, %0\n\t"
+- "stc r7_bank, %1\n\t"
+- : "=r" (module_start),
+- "=r" (module_end)
+- );
+-
+- sp = (unsigned long *)module_start;
+- }
+-
+- stack = sp;
++ if (regs && user_mode(regs))
++ return;
+
+ printk("\nCall trace: ");
+ #ifdef CONFIG_KALLSYMS
+ printk("\n");
+ #endif
+
+- while (!kstack_end(stack)) {
+- addr = *stack++;
+- if (((addr >= (unsigned long)_text) &&
+- (addr <= (unsigned long)_etext)) ||
+- ((addr >= module_start) && (addr <= module_end))) {
+- /*
+- * For 80-columns display, 6 entry is maximum.
+- * NOTE: '[<8c00abcd>] ' consumes 13 columns .
+- */
+-#ifndef CONFIG_KALLSYMS
+- if (i && ((i % 6) == 0))
+- printk("\n ");
+-#endif
+- printk("[<%08lx>] ", addr);
+- print_symbol("%s\n", addr);
+- i++;
+- }
++ while (!kstack_end(sp)) {
++ addr = *sp++;
++ if (kernel_text_address(addr))
++ print_ip_sym(addr);
+ }
+
+ printk("\n");
+ }
+
+-void show_task(unsigned long *sp)
++void show_stack(struct task_struct *tsk, unsigned long *sp)
+ {
+- show_stack(NULL, sp);
++ unsigned long stack;
++
++ if (!tsk)
++ tsk = current;
++ if (tsk == current)
++ sp = (unsigned long *)current_stack_pointer;
++ else
++ sp = (unsigned long *)tsk->thread.sp;
++
++ stack = (unsigned long)sp;
++ dump_mem("Stack: ", stack, THREAD_SIZE +
++ (unsigned long)task_stack_page(tsk));
++ show_trace(tsk, sp, NULL);
+ }
+
+ void dump_stack(void)
+diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
+index 95fdd91..77b4026 100644
+--- a/arch/sh/kernel/vmlinux.lds.S
++++ b/arch/sh/kernel/vmlinux.lds.S
+@@ -2,6 +2,7 @@
+ * ld script to make SuperH Linux kernel
+ * Written by Niibe Yutaka
+ */
++#include <asm/thread_info.h>
+ #include <asm-generic/vmlinux.lds.h>
+
+ #ifdef CONFIG_CPU_LITTLE_ENDIAN
+@@ -13,7 +14,7 @@ OUTPUT_ARCH(sh)
+ ENTRY(_start)
+ SECTIONS
+ {
+- . = 0x80000000 + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
++ . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
+ _text = .; /* Text and read-only data */
+ text = .; /* Text and read-only data */
+ .empty_zero_page : {
+@@ -40,16 +41,16 @@ SECTIONS
+ *(.data)
+
+ /* Align the initial ramdisk image (INITRD) on page boundaries. */
+- . = ALIGN(4096);
++ . = ALIGN(PAGE_SIZE);
+ __rd_start = .;
+ *(.initrd)
+- . = ALIGN(4096);
++ . = ALIGN(PAGE_SIZE);
+ __rd_end = .;
+
+ CONSTRUCTORS
+ }
+
+- . = ALIGN(4096);
++ . = ALIGN(PAGE_SIZE);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(32);
+@@ -60,12 +61,10 @@ SECTIONS
+
+ _edata = .; /* End of data section */
+
+- . = ALIGN(8192); /* init_task */
++ . = ALIGN(THREAD_SIZE); /* init_task */
+ .data.init_task : { *(.data.init_task) }
+- /* stack */
+- .stack : { stack = .; _stack = .; }
+
+- . = ALIGN(4096); /* Init code and data */
++ . = ALIGN(PAGE_SIZE); /* Init code and data */
+ __init_begin = .;
+ _sinittext = .;
+ .init.text : { *(.init.text) }
+@@ -77,13 +76,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+@@ -96,7 +89,7 @@ SECTIONS
+ __machvec_start = .;
+ .init.machvec : { *(.init.machvec) }
+ __machvec_end = .;
+- . = ALIGN(4096);
++ . = ALIGN(PAGE_SIZE);
+ __init_end = .;
+
+ . = ALIGN(4);
+diff --git a/arch/sh/kernel/vsyscall/.gitignore b/arch/sh/kernel/vsyscall/.gitignore
+new file mode 100644
+index 0000000..40836ad
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/.gitignore
+@@ -0,0 +1 @@
++vsyscall.lds
+diff --git a/arch/sh/kernel/vsyscall/Makefile b/arch/sh/kernel/vsyscall/Makefile
+new file mode 100644
+index 0000000..4bbce1c
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/Makefile
+@@ -0,0 +1,36 @@
++obj-y += vsyscall.o vsyscall-syscall.o
++
++$(obj)/vsyscall-syscall.o: \
++ $(foreach F,trapa,$(obj)/vsyscall-$F.so)
++
++# Teach kbuild about targets
++targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so)
++targets += vsyscall-note.o vsyscall.lds
++
++# The DSO images are built using a special linker script
++quiet_cmd_syscall = SYSCALL $@
++ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
++ -Wl,-T,$(filter-out FORCE,$^) -o $@
++
++export CPPFLAGS_vsyscall.lds += -P -C -Ush
++
++vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \
++ $(call ld-option, -Wl$(comma)--hash-style=sysv)
++
++SYSCFLAGS_vsyscall-trapa.so = $(vsyscall-flags)
++
++$(obj)/vsyscall-trapa.so: \
++$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
++ $(call if_changed,syscall)
++
++# We also create a special relocatable object that should mirror the symbol
++# table and layout of the linked DSO. With ld -R we can then refer to
++# these symbols in the kernel code rather than hand-coded addresses.
++extra-y += vsyscall-syms.o
++$(obj)/built-in.o: $(obj)/vsyscall-syms.o
++$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
++
++SYSCFLAGS_vsyscall-syms.o = -r
++$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
++ $(obj)/vsyscall-trapa.o $(obj)/vsyscall-note.o FORCE
++ $(call if_changed,syscall)
+diff --git a/arch/sh/kernel/vsyscall/vsyscall-note.S b/arch/sh/kernel/vsyscall/vsyscall-note.S
+new file mode 100644
+index 0000000..d4b5be4
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/vsyscall-note.S
+@@ -0,0 +1,25 @@
++/*
++ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
++ * Here we can supply some information useful to userland.
++ */
++
++#include <linux/uts.h>
++#include <linux/version.h>
++
++#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
++ .section name, flags; \
++ .balign 4; \
++ .long 1f - 0f; /* name length */ \
++ .long 3f - 2f; /* data length */ \
++ .long type; /* note type */ \
++0: .asciz vendor; /* vendor name */ \
++1: .balign 4; \
++2:
++
++#define ASM_ELF_NOTE_END \
++3: .balign 4; /* pad out section */ \
++ .previous
++
++ ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
++ .long LINUX_VERSION_CODE
++ ASM_ELF_NOTE_END
+diff --git a/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S
+new file mode 100644
+index 0000000..555a64f
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S
+@@ -0,0 +1,39 @@
++#include <asm/unistd.h>
++
++ .text
++ .balign 32
++ .globl __kernel_sigreturn
++ .type __kernel_sigreturn, at function
++__kernel_sigreturn:
++.LSTART_sigreturn:
++ mov.w 1f, r3
++ trapa #0x10
++ or r0, r0
++ or r0, r0
++ or r0, r0
++ or r0, r0
++ or r0, r0
++
++1: .short __NR_sigreturn
++.LEND_sigreturn:
++ .size __kernel_sigreturn,.-.LSTART_sigreturn
++
++ .balign 32
++ .globl __kernel_rt_sigreturn
++ .type __kernel_rt_sigreturn, at function
++__kernel_rt_sigreturn:
++.LSTART_rt_sigreturn:
++ mov.w 1f, r3
++ trapa #0x10
++ or r0, r0
++ or r0, r0
++ or r0, r0
++ or r0, r0
++ or r0, r0
++
++1: .short __NR_rt_sigreturn
++.LEND_rt_sigreturn:
++ .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
++
++ .section .eh_frame,"a", at progbits
++ .previous
+diff --git a/arch/sh/kernel/vsyscall/vsyscall-syscall.S b/arch/sh/kernel/vsyscall/vsyscall-syscall.S
+new file mode 100644
+index 0000000..c2ac7f0
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/vsyscall-syscall.S
+@@ -0,0 +1,10 @@
++#include <linux/init.h>
++
++__INITDATA
++
++ .globl vsyscall_trapa_start, vsyscall_trapa_end
++vsyscall_trapa_start:
++ .incbin "arch/sh/kernel/vsyscall/vsyscall-trapa.so"
++vsyscall_trapa_end:
++
++__FINIT
+diff --git a/arch/sh/kernel/vsyscall/vsyscall-trapa.S b/arch/sh/kernel/vsyscall/vsyscall-trapa.S
+new file mode 100644
+index 0000000..3b6eb34
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/vsyscall-trapa.S
+@@ -0,0 +1,42 @@
++ .text
++ .globl __kernel_vsyscall
++ .type __kernel_vsyscall, at function
++__kernel_vsyscall:
++.LSTART_vsyscall:
++ /* XXX: We'll have to do something here once we opt to use the vDSO
++ * page for something other than the signal trampoline.. as well as
++ * fill out .eh_frame -- PFM. */
++.LEND_vsyscall:
++ .size __kernel_vsyscall,.-.LSTART_vsyscall
++ .previous
++
++ .section .eh_frame,"a", at progbits
++.LCIE:
++ .ualong .LCIE_end - .LCIE_start
++.LCIE_start:
++ .ualong 0 /* CIE ID */
++ .byte 0x1 /* Version number */
++ .string "zRS" /* NUL-terminated augmentation string */
++ .uleb128 0x1 /* Code alignment factor */
++ .sleb128 -4 /* Data alignment factor */
++ .byte 0x11 /* Return address register column */
++ /* Augmentation length and data (none) */
++ .byte 0xc /* DW_CFA_def_cfa */
++ .uleb128 0xf /* r15 */
++ .uleb128 0x0 /* offset 0 */
++
++ .align 2
++.LCIE_end:
++
++ .ualong .LFDE_end-.LFDE_start /* Length FDE */
++.LFDE_start:
++ .ualong .LCIE /* CIE pointer */
++ .ualong .LSTART_vsyscall-. /* start address */
++ .ualong .LEND_vsyscall-.LSTART_vsyscall
++ .uleb128 0
++ .align 2
++.LFDE_end:
++ .previous
++
++/* Get the common code for the sigreturn entry points */
++#include "vsyscall-sigreturn.S"
+diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
+new file mode 100644
+index 0000000..075d6cc
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/vsyscall.c
+@@ -0,0 +1,150 @@
++/*
++ * arch/sh/kernel/vsyscall.c
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * vDSO randomization
++ * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
++ *
++ * 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/mm.h>
++#include <linux/slab.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/gfp.h>
++#include <linux/module.h>
++#include <linux/elf.h>
++
++/*
++ * Should the kernel map a VDSO page into processes and pass its
++ * address down to glibc upon exec()?
++ */
++unsigned int __read_mostly vdso_enabled = 1;
++EXPORT_SYMBOL_GPL(vdso_enabled);
++
++static int __init vdso_setup(char *s)
++{
++ vdso_enabled = simple_strtoul(s, NULL, 0);
++ return 1;
++}
++__setup("vdso=", vdso_setup);
++
++/*
++ * These symbols are defined by vsyscall.o to mark the bounds
++ * of the ELF DSO images included therein.
++ */
++extern const char vsyscall_trapa_start, vsyscall_trapa_end;
++static void *syscall_page;
++
++int __init vsyscall_init(void)
++{
++ syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
++
++ /*
++ * XXX: Map this page to a fixmap entry if we get around
++ * to adding the page to ELF core dumps
++ */
++
++ memcpy(syscall_page,
++ &vsyscall_trapa_start,
++ &vsyscall_trapa_end - &vsyscall_trapa_start);
++
++ return 0;
++}
++
++static struct page *syscall_vma_nopage(struct vm_area_struct *vma,
++ unsigned long address, int *type)
++{
++ unsigned long offset = address - vma->vm_start;
++ struct page *page;
++
++ if (address < vma->vm_start || address > vma->vm_end)
++ return NOPAGE_SIGBUS;
++
++ page = virt_to_page(syscall_page + offset);
++
++ get_page(page);
++
++ return page;
++}
++
++/* Prevent VMA merging */
++static void syscall_vma_close(struct vm_area_struct *vma)
++{
++}
++
++static struct vm_operations_struct syscall_vm_ops = {
++ .nopage = syscall_vma_nopage,
++ .close = syscall_vma_close,
++};
++
++/* Setup a VMA at program startup for the vsyscall page */
++int arch_setup_additional_pages(struct linux_binprm *bprm,
++ int executable_stack)
++{
++ struct vm_area_struct *vma;
++ struct mm_struct *mm = current->mm;
++ unsigned long addr;
++ int ret;
++
++ down_write(&mm->mmap_sem);
++ addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
++ if (IS_ERR_VALUE(addr)) {
++ ret = addr;
++ goto up_fail;
++ }
++
++ vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
++ if (!vma) {
++ ret = -ENOMEM;
++ goto up_fail;
++ }
++
++ vma->vm_start = addr;
++ vma->vm_end = addr + PAGE_SIZE;
++ /* MAYWRITE to allow gdb to COW and set breakpoints */
++ vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
++ vma->vm_flags |= mm->def_flags;
++ vma->vm_page_prot = protection_map[vma->vm_flags & 7];
++ vma->vm_ops = &syscall_vm_ops;
++ vma->vm_mm = mm;
++
++ ret = insert_vm_struct(mm, vma);
++ if (unlikely(ret)) {
++ kmem_cache_free(vm_area_cachep, vma);
++ goto up_fail;
++ }
++
++ current->mm->context.vdso = (void *)addr;
++
++ mm->total_vm++;
++up_fail:
++ up_write(&mm->mmap_sem);
++ return ret;
++}
++
++const char *arch_vma_name(struct vm_area_struct *vma)
++{
++ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
++ return "[vdso]";
++
++ return NULL;
++}
++
++struct vm_area_struct *get_gate_vma(struct task_struct *task)
++{
++ return NULL;
++}
++
++int in_gate_area(struct task_struct *task, unsigned long address)
++{
++ return 0;
++}
++
++int in_gate_area_no_task(unsigned long address)
++{
++ return 0;
++}
+diff --git a/arch/sh/kernel/vsyscall/vsyscall.lds.S b/arch/sh/kernel/vsyscall/vsyscall.lds.S
+new file mode 100644
+index 0000000..b13c3d4
+--- /dev/null
++++ b/arch/sh/kernel/vsyscall/vsyscall.lds.S
+@@ -0,0 +1,74 @@
++/*
++ * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
++ * object prelinked to its virtual address, and with only one read-only
++ * segment (that fits in one page). This script controls its layout.
++ */
++#include <asm/asm-offsets.h>
++
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
++#else
++OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
++#endif
++OUTPUT_ARCH(sh)
++
++/* The ELF entry point can be used to set the AT_SYSINFO value. */
++ENTRY(__kernel_vsyscall);
++
++SECTIONS
++{
++ . = SIZEOF_HEADERS;
++
++ .hash : { *(.hash) } :text
++ .gnu.hash : { *(.gnu.hash) }
++ .dynsym : { *(.dynsym) }
++ .dynstr : { *(.dynstr) }
++ .gnu.version : { *(.gnu.version) }
++ .gnu.version_d : { *(.gnu.version_d) }
++ .gnu.version_r : { *(.gnu.version_r) }
++
++ /* This linker script is used both with -r and with -shared.
++ For the layouts to match, we need to skip more than enough
++ space for the dynamic symbol table et al. If this amount
++ is insufficient, ld -shared will barf. Just increase it here. */
++ . = 0x400;
++
++ .text : { *(.text) } :text =0x90909090
++ .note : { *(.note.*) } :text :note
++ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
++ .eh_frame : { KEEP (*(.eh_frame)) } :text
++ .dynamic : { *(.dynamic) } :text :dynamic
++ .useless : {
++ *(.got.plt) *(.got)
++ *(.data .data.* .gnu.linkonce.d.*)
++ *(.dynbss)
++ *(.bss .bss.* .gnu.linkonce.b.*)
++ } :text
++}
++
++/*
++ * We must supply the ELF program headers explicitly to get just one
++ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
++ */
++PHDRS
++{
++ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
++ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
++ note PT_NOTE FLAGS(4); /* PF_R */
++ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
++}
++
++/*
++ * This controls what symbols we export from the DSO.
++ */
++VERSION
++{
++ LINUX_2.6 {
++ global:
++ __kernel_vsyscall;
++ __kernel_sigreturn;
++ __kernel_rt_sigreturn;
++
++ local: *;
++ };
++}
+diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S
+index 7c50dfe..cbdd0d4 100644
+--- a/arch/sh/lib/checksum.S
++++ b/arch/sh/lib/checksum.S
+@@ -202,8 +202,9 @@ ENTRY(csum_partial_copy_generic)
+ cmp/pz r6 ! Jump if we had at least two bytes.
+ bt/s 1f
+ clrt
++ add #2,r6 ! r6 was < 2. Deal with it.
+ bra 4f
+- add #2,r6 ! r6 was < 2. Deal with it.
++ mov r6,r2
+
+ 3: ! Handle different src and dest alignments.
+ ! This is not common, so simple byte by byte copy will do.
+diff --git a/arch/sh/lib/memcpy-sh4.S b/arch/sh/lib/memcpy-sh4.S
+index db6b736..560bc17 100644
+--- a/arch/sh/lib/memcpy-sh4.S
++++ b/arch/sh/lib/memcpy-sh4.S
+@@ -727,8 +727,8 @@ ENTRY(memcpy)
+ mov.l @(0x04,r5), r11 ! 18 LS (latency=2)
+ xtrct r9, r8 ! 48 EX
+
+- mov.w @(0x02,r5), r12 ! 18 LS (latency=2)
+- xtrct r10, r9 ! 48 EX
++ mov.l @(0x00,r5), r12 ! 18 LS (latency=2)
++ xtrct r10, r9 ! 48 EX
+
+ movca.l r0, at r1 ! 40 LS (latency=3-7)
+ add #-0x1c, r1 ! 50 EX
+diff --git a/arch/sh/lib/memset.S b/arch/sh/lib/memset.S
+index 9567009..af91fe2 100644
+--- a/arch/sh/lib/memset.S
++++ b/arch/sh/lib/memset.S
+@@ -29,6 +29,7 @@ ENTRY(memset)
+ bf/s 1b
+ mov.b r5, at -r4
+ 2: ! make VVVV
++ extu.b r5,r5
+ swap.b r5,r0 ! V0
+ or r0,r5 ! VV
+ swap.w r5,r0 ! VV00
+diff --git a/arch/sh/math-emu/Makefile b/arch/sh/math-emu/Makefile
+new file mode 100644
+index 0000000..638b342
+--- /dev/null
++++ b/arch/sh/math-emu/Makefile
+@@ -0,0 +1 @@
++obj-y := math.o
+diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
+new file mode 100644
+index 0000000..1efbac1
+--- /dev/null
++++ b/arch/sh/math-emu/math.c
+@@ -0,0 +1,623 @@
++/*
++ * arch/sh/math-emu/math.c
++ *
++ * Copyright (C) 2006 Takashi YOSHII <takasi-y at ops.dti.ne.jp>
++ *
++ * 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/errno.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++#include <asm/io.h>
++
++#include "sfp-util.h"
++#include <math-emu/soft-fp.h>
++#include <math-emu/single.h>
++#include <math-emu/double.h>
++
++#define FPUL (fregs->fpul)
++#define FPSCR (fregs->fpscr)
++#define FPSCR_RM (FPSCR&3)
++#define FPSCR_DN ((FPSCR>>18)&1)
++#define FPSCR_PR ((FPSCR>>19)&1)
++#define FPSCR_SZ ((FPSCR>>20)&1)
++#define FPSCR_FR ((FPSCR>>21)&1)
++#define FPSCR_MASK 0x003fffffUL
++
++#define BANK(n) (n^(FPSCR_FR?16:0))
++#define FR ((unsigned long*)(fregs->fp_regs))
++#define FR0 (FR[BANK(0)])
++#define FRn (FR[BANK(n)])
++#define FRm (FR[BANK(m)])
++#define DR ((unsigned long long*)(fregs->fp_regs))
++#define DRn (DR[BANK(n)/2])
++#define DRm (DR[BANK(m)/2])
++
++#define XREG(n) (n^16)
++#define XFn (FR[BANK(XREG(n))])
++#define XFm (FR[BANK(XREG(m))])
++#define XDn (DR[BANK(XREG(n))/2])
++#define XDm (DR[BANK(XREG(m))/2])
++
++#define R0 (regs->regs[0])
++#define Rn (regs->regs[n])
++#define Rm (regs->regs[m])
++
++#define WRITE(d,a) ({if(put_user(d, (typeof (d)*)a)) return -EFAULT;})
++#define READ(d,a) ({if(get_user(d, (typeof (d)*)a)) return -EFAULT;})
++
++#define PACK_S(r,f) FP_PACK_SP(&r,f)
++#define UNPACK_S(f,r) FP_UNPACK_SP(f,&r)
++#define PACK_D(r,f) \
++ {u32 t[2]; FP_PACK_DP(t,f); ((u32*)&r)[0]=t[1]; ((u32*)&r)[1]=t[0];}
++#define UNPACK_D(f,r) \
++ {u32 t[2]; t[0]=((u32*)&r)[1]; t[1]=((u32*)&r)[0]; FP_UNPACK_DP(f,t);}
++
++// 2 args instructions.
++#define BOTH_PRmn(op,x) \
++ FP_DECL_EX; if(FPSCR_PR) op(D,x,DRm,DRn); else op(S,x,FRm,FRn);
++
++#define CMP_X(SZ,R,M,N) do{ \
++ FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \
++ UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
++ FP_CMP_##SZ(R, Fn, Fm, 2); }while(0)
++#define EQ_X(SZ,R,M,N) do{ \
++ FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \
++ UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
++ FP_CMP_EQ_##SZ(R, Fn, Fm); }while(0)
++#define CMP(OP) ({ int r; BOTH_PRmn(OP##_X,r); r; })
++
++static int
++fcmp_gt(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ if (CMP(CMP) > 0)
++ regs->sr |= 1;
++ else
++ regs->sr &= ~1;
++
++ return 0;
++}
++
++static int
++fcmp_eq(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ if (CMP(CMP /*EQ*/) == 0)
++ regs->sr |= 1;
++ else
++ regs->sr &= ~1;
++ return 0;
++}
++
++#define ARITH_X(SZ,OP,M,N) do{ \
++ FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); FP_DECL_##SZ(Fr); \
++ UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
++ FP_##OP##_##SZ(Fr, Fn, Fm); \
++ PACK_##SZ(N, Fr); }while(0)
++
++static int
++fadd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ BOTH_PRmn(ARITH_X, ADD);
++ return 0;
++}
++
++static int
++fsub(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ BOTH_PRmn(ARITH_X, SUB);
++ return 0;
++}
++
++static int
++fmul(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ BOTH_PRmn(ARITH_X, MUL);
++ return 0;
++}
++
++static int
++fdiv(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ BOTH_PRmn(ARITH_X, DIV);
++ return 0;
++}
++
++static int
++fmac(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ FP_DECL_EX;
++ FP_DECL_S(Fr);
++ FP_DECL_S(Ft);
++ FP_DECL_S(F0);
++ FP_DECL_S(Fm);
++ FP_DECL_S(Fn);
++ UNPACK_S(F0, FR0);
++ UNPACK_S(Fm, FRm);
++ UNPACK_S(Fn, FRn);
++ FP_MUL_S(Ft, Fm, F0);
++ FP_ADD_S(Fr, Fn, Ft);
++ PACK_S(FRn, Fr);
++ return 0;
++}
++
++// to process fmov's extention (odd n for DR access XD).
++#define FMOV_EXT(x) if(x&1) x+=16-1
++
++static int
++fmov_idx_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(n);
++ READ(FRn, Rm + R0 + 4);
++ n++;
++ READ(FRn, Rm + R0);
++ } else {
++ READ(FRn, Rm + R0);
++ }
++
++ return 0;
++}
++
++static int
++fmov_mem_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(n);
++ READ(FRn, Rm + 4);
++ n++;
++ READ(FRn, Rm);
++ } else {
++ READ(FRn, Rm);
++ }
++
++ return 0;
++}
++
++static int
++fmov_inc_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(n);
++ READ(FRn, Rm + 4);
++ n++;
++ READ(FRn, Rm);
++ Rm += 8;
++ } else {
++ READ(FRn, Rm);
++ Rm += 4;
++ }
++
++ return 0;
++}
++
++static int
++fmov_reg_idx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(m);
++ WRITE(FRm, Rn + R0 + 4);
++ m++;
++ WRITE(FRm, Rn + R0);
++ } else {
++ WRITE(FRm, Rn + R0);
++ }
++
++ return 0;
++}
++
++static int
++fmov_reg_mem(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(m);
++ WRITE(FRm, Rn + 4);
++ m++;
++ WRITE(FRm, Rn);
++ } else {
++ WRITE(FRm, Rn);
++ }
++
++ return 0;
++}
++
++static int
++fmov_reg_dec(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(m);
++ Rn -= 8;
++ WRITE(FRm, Rn + 4);
++ m++;
++ WRITE(FRm, Rn);
++ } else {
++ Rn -= 4;
++ WRITE(FRm, Rn);
++ }
++
++ return 0;
++}
++
++static int
++fmov_reg_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
++ int n)
++{
++ if (FPSCR_SZ) {
++ FMOV_EXT(m);
++ FMOV_EXT(n);
++ DRn = DRm;
++ } else {
++ FRn = FRm;
++ }
++
++ return 0;
++}
++
++static int
++fnop_mn(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
++{
++ return -EINVAL;
++}
++
++// 1 arg instructions.
++#define NOTYETn(i) static int i(struct sh_fpu_soft_struct *fregs, int n) \
++ { printk( #i " not yet done.\n"); return 0; }
++
++NOTYETn(ftrv)
++NOTYETn(fsqrt)
++NOTYETn(fipr)
++NOTYETn(fsca)
++NOTYETn(fsrra)
++
++#define EMU_FLOAT_X(SZ,N) do { \
++ FP_DECL_##SZ(Fn); \
++ FP_FROM_INT_##SZ(Fn, FPUL, 32, int); \
++ PACK_##SZ(N, Fn); }while(0)
++static int ffloat(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FP_DECL_EX;
++
++ if (FPSCR_PR)
++ EMU_FLOAT_X(D, DRn);
++ else
++ EMU_FLOAT_X(S, FRn);
++
++ return 0;
++}
++
++#define EMU_FTRC_X(SZ,N) do { \
++ FP_DECL_##SZ(Fn); \
++ UNPACK_##SZ(Fn, N); \
++ FP_TO_INT_##SZ(FPUL, Fn, 32, 1); }while(0)
++static int ftrc(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FP_DECL_EX;
++
++ if (FPSCR_PR)
++ EMU_FTRC_X(D, DRn);
++ else
++ EMU_FTRC_X(S, FRn);
++
++ return 0;
++}
++
++static int fcnvsd(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FP_DECL_EX;
++ FP_DECL_S(Fn);
++ FP_DECL_D(Fr);
++ UNPACK_S(Fn, FPUL);
++ FP_CONV(D, S, 2, 1, Fr, Fn);
++ PACK_D(DRn, Fr);
++ return 0;
++}
++
++static int fcnvds(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FP_DECL_EX;
++ FP_DECL_D(Fn);
++ FP_DECL_S(Fr);
++ UNPACK_D(Fn, DRn);
++ FP_CONV(S, D, 1, 2, Fr, Fn);
++ PACK_S(FPUL, Fr);
++ return 0;
++}
++
++static int fxchg(struct sh_fpu_soft_struct *fregs, int flag)
++{
++ FPSCR ^= flag;
++ return 0;
++}
++
++static int fsts(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FRn = FPUL;
++ return 0;
++}
++
++static int flds(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FPUL = FRn;
++ return 0;
++}
++
++static int fneg(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FRn ^= (1 << (_FP_W_TYPE_SIZE - 1));
++ return 0;
++}
++
++static int fabs(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FRn &= ~(1 << (_FP_W_TYPE_SIZE - 1));
++ return 0;
++}
++
++static int fld0(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FRn = 0;
++ return 0;
++}
++
++static int fld1(struct sh_fpu_soft_struct *fregs, int n)
++{
++ FRn = (_FP_EXPBIAS_S << (_FP_FRACBITS_S - 1));
++ return 0;
++}
++
++static int fnop_n(struct sh_fpu_soft_struct *fregs, int n)
++{
++ return -EINVAL;
++}
++
++/// Instruction decoders.
++
++static int id_fxfd(struct sh_fpu_soft_struct *, int);
++static int id_fnxd(struct sh_fpu_soft_struct *, struct pt_regs *, int, int);
++
++static int (*fnxd[])(struct sh_fpu_soft_struct *, int) = {
++ fsts, flds, ffloat, ftrc, fneg, fabs, fsqrt, fsrra,
++ fld0, fld1, fcnvsd, fcnvds, fnop_n, fnop_n, fipr, id_fxfd
++};
++
++static int (*fnmx[])(struct sh_fpu_soft_struct *, struct pt_regs *, int, int) = {
++ fadd, fsub, fmul, fdiv, fcmp_eq, fcmp_gt, fmov_idx_reg, fmov_reg_idx,
++ fmov_mem_reg, fmov_inc_reg, fmov_reg_mem, fmov_reg_dec,
++ fmov_reg_reg, id_fnxd, fmac, fnop_mn};
++
++static int id_fxfd(struct sh_fpu_soft_struct *fregs, int x)
++{
++ const int flag[] = { FPSCR_SZ, FPSCR_PR, FPSCR_FR, 0 };
++ switch (x & 3) {
++ case 3:
++ fxchg(fregs, flag[x >> 2]);
++ break;
++ case 1:
++ ftrv(fregs, x - 1);
++ break;
++ default:
++ fsca(fregs, x);
++ }
++ return 0;
++}
++
++static int
++id_fnxd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int x, int n)
++{
++ return (fnxd[x])(fregs, n);
++}
++
++static int
++id_fnmx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code)
++{
++ int n = (code >> 8) & 0xf, m = (code >> 4) & 0xf, x = code & 0xf;
++ return (fnmx[x])(fregs, regs, m, n);
++}
++
++static int
++id_sys(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code)
++{
++ int n = ((code >> 8) & 0xf);
++ unsigned long *reg = (code & 0x0010) ? &FPUL : &FPSCR;
++
++ switch (code & 0xf0ff) {
++ case 0x005a:
++ case 0x006a:
++ Rn = *reg;
++ break;
++ case 0x405a:
++ case 0x406a:
++ *reg = Rn;
++ break;
++ case 0x4052:
++ case 0x4062:
++ Rn -= 4;
++ WRITE(*reg, Rn);
++ break;
++ case 0x4056:
++ case 0x4066:
++ READ(*reg, Rn);
++ Rn += 4;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_regs *regs)
++{
++ if ((code & 0xf000) == 0xf000)
++ return id_fnmx(fregs, regs, code);
++ else
++ return id_sys(fregs, regs, code);
++}
++
++/**
++ * denormal_to_double - Given denormalized float number,
++ * store double float
++ *
++ * @fpu: Pointer to sh_fpu_hard structure
++ * @n: Index to FP register
++ */
++static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
++{
++ unsigned long du, dl;
++ unsigned long x = fpu->fpul;
++ int exp = 1023 - 126;
++
++ if (x != 0 && (x & 0x7f800000) == 0) {
++ du = (x & 0x80000000);
++ while ((x & 0x00800000) == 0) {
++ x <<= 1;
++ exp--;
++ }
++ x &= 0x007fffff;
++ du |= (exp << 20) | (x >> 3);
++ dl = x << 29;
++
++ fpu->fp_regs[n] = du;
++ fpu->fp_regs[n+1] = dl;
++ }
++}
++
++/**
++ * ieee_fpe_handler - Handle denormalized number exception
++ *
++ * @regs: Pointer to register structure
++ *
++ * Returns 1 when it's handled (should not cause exception).
++ */
++static int ieee_fpe_handler(struct pt_regs *regs)
++{
++ unsigned short insn = *(unsigned short *)regs->pc;
++ unsigned short finsn;
++ unsigned long nextpc;
++ int nib[4] = {
++ (insn >> 12) & 0xf,
++ (insn >> 8) & 0xf,
++ (insn >> 4) & 0xf,
++ insn & 0xf};
++
++ if (nib[0] == 0xb ||
++ (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
++ regs->pr = regs->pc + 4;
++
++ if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
++ nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
++ finsn = *(unsigned short *) (regs->pc + 2);
++ } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
++ if (regs->sr & 1)
++ nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
++ else
++ nextpc = regs->pc + 4;
++ finsn = *(unsigned short *) (regs->pc + 2);
++ } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
++ if (regs->sr & 1)
++ nextpc = regs->pc + 4;
++ else
++ nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
++ finsn = *(unsigned short *) (regs->pc + 2);
++ } else if (nib[0] == 0x4 && nib[3] == 0xb &&
++ (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
++ nextpc = regs->regs[nib[1]];
++ finsn = *(unsigned short *) (regs->pc + 2);
++ } else if (nib[0] == 0x0 && nib[3] == 0x3 &&
++ (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
++ nextpc = regs->pc + 4 + regs->regs[nib[1]];
++ finsn = *(unsigned short *) (regs->pc + 2);
++ } else if (insn == 0x000b) { /* rts */
++ nextpc = regs->pr;
++ finsn = *(unsigned short *) (regs->pc + 2);
++ } else {
++ nextpc = regs->pc + 2;
++ finsn = insn;
++ }
++
++ if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
++ struct task_struct *tsk = current;
++
++ if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
++ /* FPU error */
++ denormal_to_double (&tsk->thread.fpu.hard,
++ (finsn >> 8) & 0xf);
++ tsk->thread.fpu.hard.fpscr &=
++ ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
++ set_tsk_thread_flag(tsk, TIF_USEDFPU);
++ } else {
++ tsk->thread.trap_no = 11;
++ tsk->thread.error_code = 0;
++ force_sig(SIGFPE, tsk);
++ }
++
++ regs->pc = nextpc;
++ return 1;
++ }
++
++ return 0;
++}
++
++asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5,
++ unsigned long r6, unsigned long r7,
++ struct pt_regs regs)
++{
++ struct task_struct *tsk = current;
++
++ if (ieee_fpe_handler (®s))
++ return;
++
++ regs.pc += 2;
++ tsk->thread.trap_no = 11;
++ tsk->thread.error_code = 0;
++ force_sig(SIGFPE, tsk);
++}
++
++/**
++ * fpu_init - Initialize FPU registers
++ * @fpu: Pointer to software emulated FPU registers.
++ */
++static void fpu_init(struct sh_fpu_soft_struct *fpu)
++{
++ int i;
++
++ fpu->fpscr = FPSCR_INIT;
++ fpu->fpul = 0;
++
++ for (i = 0; i < 16; i++) {
++ fpu->fp_regs[i] = 0;
++ fpu->xfp_regs[i]= 0;
++ }
++}
++
++/**
++ * do_fpu_inst - Handle reserved instructions for FPU emulation
++ * @inst: instruction code.
++ * @regs: registers on stack.
++ */
++int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
++{
++ struct task_struct *tsk = current;
++ struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft);
++
++ if (!test_tsk_thread_flag(tsk, TIF_USEDFPU)) {
++ /* initialize once. */
++ fpu_init(fpu);
++ set_tsk_thread_flag(tsk, TIF_USEDFPU);
++ }
++
++ return fpu_emulate(inst, fpu, regs);
++}
+diff --git a/arch/sh/math-emu/sfp-util.h b/arch/sh/math-emu/sfp-util.h
+new file mode 100644
+index 0000000..8ae1bd3
+--- /dev/null
++++ b/arch/sh/math-emu/sfp-util.h
+@@ -0,0 +1,72 @@
++/*
++ * These are copied from glibc/stdlib/longlong.h
++ */
++
++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
++ do { \
++ UWtype __x; \
++ __x = (al) + (bl); \
++ (sh) = (ah) + (bh) + (__x < (al)); \
++ (sl) = __x; \
++ } while (0)
++
++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
++ do { \
++ UWtype __x; \
++ __x = (al) - (bl); \
++ (sh) = (ah) - (bh) - (__x > (al)); \
++ (sl) = __x; \
++ } while (0)
++
++#define umul_ppmm(w1, w0, u, v) \
++ __asm__ ("dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \
++ : "=r" ((u32)(w1)), "=r" ((u32)(w0)) \
++ : "r" ((u32)(u)), "r" ((u32)(v)) \
++ : "macl", "mach")
++
++#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
++#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
++#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
++
++#define udiv_qrnnd(q, r, n1, n0, d) \
++ do { \
++ UWtype __d1, __d0, __q1, __q0; \
++ UWtype __r1, __r0, __m; \
++ __d1 = __ll_highpart (d); \
++ __d0 = __ll_lowpart (d); \
++ \
++ __r1 = (n1) % __d1; \
++ __q1 = (n1) / __d1; \
++ __m = (UWtype) __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 = (UWtype) __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) = (UWtype) __q1 * __ll_B | __q0; \
++ (r) = __r0; \
++ } while (0)
++
++#define abort() return 0
++
++#define __BYTE_ORDER __LITTLE_ENDIAN
++
++
+diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
+index fb586b1..9dd6064 100644
+--- a/arch/sh/mm/Kconfig
++++ b/arch/sh/mm/Kconfig
+@@ -20,7 +20,10 @@ config CPU_SH4
+ config CPU_SH4A
+ bool
+ select CPU_SH4
+- select CPU_HAS_INTC2_IRQ
++
++config CPU_SH4AL_DSP
++ bool
++ select CPU_SH4A
+
+ config CPU_SUBTYPE_ST40
+ bool
+@@ -48,6 +51,12 @@ config CPU_SUBTYPE_SH7705
+ select CPU_SH3
+ select CPU_HAS_PINT_IRQ
+
++config CPU_SUBTYPE_SH7706
++ bool "Support SH7706 processor"
++ select CPU_SH3
++ help
++ Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
++
+ config CPU_SUBTYPE_SH7707
+ bool "Support SH7707 processor"
+ select CPU_SH3
+@@ -69,6 +78,12 @@ config CPU_SUBTYPE_SH7709
+ help
+ Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU.
+
++config CPU_SUBTYPE_SH7710
++ bool "Support SH7710 processor"
++ select CPU_SH3
++ help
++ Select SH7710 if you have a SH3-DSP SH7710 CPU.
++
+ comment "SH-4 Processor Support"
+
+ config CPU_SUBTYPE_SH7750
+@@ -133,10 +148,6 @@ config CPU_SUBTYPE_ST40GX1
+
+ comment "SH-4A Processor Support"
+
+-config CPU_SUBTYPE_SH73180
+- bool "Support SH73180 processor"
+- select CPU_SH4A
+-
+ config CPU_SUBTYPE_SH7770
+ bool "Support SH7770 processor"
+ select CPU_SH4A
+@@ -144,6 +155,17 @@ config CPU_SUBTYPE_SH7770
+ config CPU_SUBTYPE_SH7780
+ bool "Support SH7780 processor"
+ select CPU_SH4A
++ select CPU_HAS_INTC2_IRQ
++
++comment "SH4AL-DSP Processor Support"
++
++config CPU_SUBTYPE_SH73180
++ bool "Support SH73180 processor"
++ select CPU_SH4AL_DSP
++
++config CPU_SUBTYPE_SH7343
++ bool "Support SH7343 processor"
++ select CPU_SH4AL_DSP
+
+ endmenu
+
+@@ -161,15 +183,59 @@ config MMU
+ turning this off will boot the kernel on these machines with the
+ MMU implicitly switched off.
+
++config PAGE_OFFSET
++ hex
++ default "0x80000000" if MMU
++ default "0x00000000"
++
++config MEMORY_START
++ hex "Physical memory start address"
++ default "0x08000000"
++ ---help---
++ Computers built with Hitachi SuperH processors always
++ map the ROM starting at address zero. But the processor
++ does not specify the range that RAM takes.
++
++ The physical memory (RAM) start address will be automatically
++ set to 08000000. Other platforms, such as the Solution Engine
++ boards typically map RAM at 0C000000.
++
++ Tweak this only when porting to a new machine which does not
++ already have a defconfig. Changing it from the known correct
++ value on any of the known systems will only lead to disaster.
++
++config MEMORY_SIZE
++ hex "Physical memory size"
++ default "0x00400000"
++ help
++ This sets the default memory size assumed by your SH kernel. It can
++ be overridden as normal by the 'mem=' argument on the kernel command
++ line. If unsure, consult your board specifications or just leave it
++ as 0x00400000 which was the default value before this became
++ configurable.
++
+ config 32BIT
+ bool "Support 32-bit physical addressing through PMB"
+- depends on CPU_SH4A
++ depends on CPU_SH4A && MMU
+ default y
+ help
+ If you say Y here, physical addressing will be extended to
+ 32-bits through the SH-4A PMB. If this is not set, legacy
+ 29-bit physical addressing will be used.
+
++config VSYSCALL
++ bool "Support vsyscall page"
++ depends on MMU
++ default y
++ help
++ This will enable support for the kernel mapping a vDSO page
++ in process space, and subsequently handing down the entry point
++ to the libc through the ELF auxiliary vector.
++
++ From the kernel side this is used for the signal trampoline.
++ For systems with an MMU that can afford to give up a page,
++ (the default value) say Y.
++
+ choice
+ prompt "HugeTLB page size"
+ depends on HUGETLB_PAGE && CPU_SH4 && MMU
+diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
+index 9489a14..3ffd7f6 100644
+--- a/arch/sh/mm/Makefile
++++ b/arch/sh/mm/Makefile
+@@ -6,20 +6,26 @@ obj-y := init.o extable.o consistent.o
+
+ obj-$(CONFIG_CPU_SH2) += cache-sh2.o
+ obj-$(CONFIG_CPU_SH3) += cache-sh3.o
+-obj-$(CONFIG_CPU_SH4) += cache-sh4.o pg-sh4.o
++obj-$(CONFIG_CPU_SH4) += cache-sh4.o
+
+ obj-$(CONFIG_DMA_PAGE_OPS) += pg-dma.o
+ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+
+ mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o
+-mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o
++mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \
++ ioremap.o
+
+ obj-y += $(mmu-y)
+
++ifdef CONFIG_DEBUG_FS
++obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
++endif
++
+ ifdef CONFIG_MMU
+-obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
+-obj-$(CONFIG_CPU_SH4) += tlb-sh4.o ioremap.o
++obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
++obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o
+ obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
+ endif
+
+-obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
++obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
++obj-$(CONFIG_32BIT) += pmb.o
+diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
+new file mode 100644
+index 0000000..e0122bd
+--- /dev/null
++++ b/arch/sh/mm/cache-debugfs.c
+@@ -0,0 +1,147 @@
++/*
++ * debugfs ops for the L1 cache
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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/init.h>
++#include <linux/module.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <asm/processor.h>
++#include <asm/uaccess.h>
++#include <asm/cache.h>
++#include <asm/io.h>
++
++enum cache_type {
++ CACHE_TYPE_ICACHE,
++ CACHE_TYPE_DCACHE,
++ CACHE_TYPE_UNIFIED,
++};
++
++static int cache_seq_show(struct seq_file *file, void *iter)
++{
++ unsigned int cache_type = (unsigned int)file->private;
++ struct cache_info *cache;
++ unsigned int waysize, way, cache_size;
++ unsigned long ccr, base;
++ static unsigned long addrstart = 0;
++
++ /*
++ * Go uncached immediately so we don't skew the results any
++ * more than we already are..
++ */
++ jump_to_P2();
++
++ ccr = ctrl_inl(CCR);
++ if ((ccr & CCR_CACHE_ENABLE) == 0) {
++ back_to_P1();
++
++ seq_printf(file, "disabled\n");
++ return 0;
++ }
++
++ if (cache_type == CACHE_TYPE_DCACHE) {
++ base = CACHE_OC_ADDRESS_ARRAY;
++ cache = &cpu_data->dcache;
++ } else {
++ base = CACHE_IC_ADDRESS_ARRAY;
++ cache = &cpu_data->icache;
++ }
++
++ /*
++ * Due to the amount of data written out (depending on the cache size),
++ * we may be iterated over multiple times. In this case, keep track of
++ * the entry position in addrstart, and rewind it when we've hit the
++ * end of the cache.
++ *
++ * Likewise, the same code is used for multiple caches, so care must
++ * be taken for bouncing addrstart back and forth so the appropriate
++ * cache is hit.
++ */
++ cache_size = cache->ways * cache->sets * cache->linesz;
++ if (((addrstart & 0xff000000) != base) ||
++ (addrstart & 0x00ffffff) > cache_size)
++ addrstart = base;
++
++ waysize = cache->sets;
++
++ /*
++ * If the OC is already in RAM mode, we only have
++ * half of the entries to consider..
++ */
++ if ((ccr & CCR_CACHE_ORA) && cache_type == CACHE_TYPE_DCACHE)
++ waysize >>= 1;
++
++ waysize <<= cache->entry_shift;
++
++ for (way = 0; way < cache->ways; way++) {
++ unsigned long addr;
++ unsigned int line;
++
++ seq_printf(file, "-----------------------------------------\n");
++ seq_printf(file, "Way %d\n", way);
++ seq_printf(file, "-----------------------------------------\n");
++
++ for (addr = addrstart, line = 0;
++ addr < addrstart + waysize;
++ addr += cache->linesz, line++) {
++ unsigned long data = ctrl_inl(addr);
++
++ /* Check the V bit, ignore invalid cachelines */
++ if ((data & 1) == 0)
++ continue;
++
++ /* U: Dirty, cache tag is 10 bits up */
++ seq_printf(file, "%3d: %c 0x%lx\n",
++ line, data & 2 ? 'U' : ' ',
++ data & 0x1ffffc00);
++ }
++
++ addrstart += cache->way_incr;
++ }
++
++ back_to_P1();
++
++ return 0;
++}
++
++static int cache_debugfs_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, cache_seq_show, inode->i_private);
++}
++
++static struct file_operations cache_debugfs_fops = {
++ .owner = THIS_MODULE,
++ .open = cache_debugfs_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++static int __init cache_debugfs_init(void)
++{
++ struct dentry *dcache_dentry, *icache_dentry;
++
++ dcache_dentry = debugfs_create_file("dcache", S_IRUSR, NULL,
++ (unsigned int *)CACHE_TYPE_DCACHE,
++ &cache_debugfs_fops);
++ if (IS_ERR(dcache_dentry))
++ return PTR_ERR(dcache_dentry);
++
++ icache_dentry = debugfs_create_file("icache", S_IRUSR, NULL,
++ (unsigned int *)CACHE_TYPE_ICACHE,
++ &cache_debugfs_fops);
++ if (IS_ERR(icache_dentry)) {
++ debugfs_remove(dcache_dentry);
++ return PTR_ERR(icache_dentry);
++ }
++
++ return 0;
++}
++module_init(cache_debugfs_init);
++
++MODULE_LICENSE("GPL v2");
+diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
+index 524cea5..e48cc22 100644
+--- a/arch/sh/mm/cache-sh4.c
++++ b/arch/sh/mm/cache-sh4.c
+@@ -2,49 +2,120 @@
+ * arch/sh/mm/cache-sh4.c
+ *
+ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
+- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
++ * Copyright (C) 2001 - 2006 Paul Mundt
+ * Copyright (C) 2003 Richard Curnow
+ *
+ * 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/init.h>
+-#include <linux/mman.h>
+ #include <linux/mm.h>
+-#include <linux/threads.h>
+ #include <asm/addrspace.h>
+-#include <asm/page.h>
+ #include <asm/pgtable.h>
+ #include <asm/processor.h>
+ #include <asm/cache.h>
+ #include <asm/io.h>
+-#include <asm/uaccess.h>
+ #include <asm/pgalloc.h>
+ #include <asm/mmu_context.h>
+ #include <asm/cacheflush.h>
+
+-extern void __flush_cache_4096_all(unsigned long start);
+-static void __flush_cache_4096_all_ex(unsigned long start);
+-extern void __flush_dcache_all(void);
+-static void __flush_dcache_all_ex(void);
++/*
++ * The maximum number of pages we support up to when doing ranged dcache
++ * flushing. Anything exceeding this will simply flush the dcache in its
++ * entirety.
++ */
++#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
++
++static void __flush_dcache_segment_1way(unsigned long start,
++ unsigned long extent);
++static void __flush_dcache_segment_2way(unsigned long start,
++ unsigned long extent);
++static void __flush_dcache_segment_4way(unsigned long start,
++ unsigned long extent);
++
++static void __flush_cache_4096(unsigned long addr, unsigned long phys,
++ unsigned long exec_offset);
++
++/*
++ * This is initialised here to ensure that it is not placed in the BSS. If
++ * that were to happen, note that cache_init gets called before the BSS is
++ * cleared, so this would get nulled out which would be hopeless.
++ */
++static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
++ (void (*)(unsigned long, unsigned long))0xdeadbeef;
++
++static void compute_alias(struct cache_info *c)
++{
++ c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
++ c->n_aliases = (c->alias_mask >> PAGE_SHIFT) + 1;
++}
++
++static void __init emit_cache_params(void)
++{
++ printk("PVR=%08x CVR=%08x PRR=%08x\n",
++ ctrl_inl(CCN_PVR),
++ ctrl_inl(CCN_CVR),
++ ctrl_inl(CCN_PRR));
++ printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n",
++ cpu_data->icache.ways,
++ cpu_data->icache.sets,
++ cpu_data->icache.way_incr);
++ printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
++ cpu_data->icache.entry_mask,
++ cpu_data->icache.alias_mask,
++ cpu_data->icache.n_aliases);
++ printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n",
++ cpu_data->dcache.ways,
++ cpu_data->dcache.sets,
++ cpu_data->dcache.way_incr);
++ printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
++ cpu_data->dcache.entry_mask,
++ cpu_data->dcache.alias_mask,
++ cpu_data->dcache.n_aliases);
++
++ if (!__flush_dcache_segment_fn)
++ panic("unknown number of cache ways\n");
++}
+
+ /*
+ * SH-4 has virtually indexed and physically tagged cache.
+ */
+
+-struct semaphore p3map_sem[4];
++/* Worst case assumed to be 64k cache, direct-mapped i.e. 4 synonym bits. */
++#define MAX_P3_SEMAPHORES 16
++
++struct semaphore p3map_sem[MAX_P3_SEMAPHORES];
+
+ void __init p3_cache_init(void)
+ {
+- if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE))
++ int i;
++
++ compute_alias(&cpu_data->icache);
++ compute_alias(&cpu_data->dcache);
++
++ switch (cpu_data->dcache.ways) {
++ case 1:
++ __flush_dcache_segment_fn = __flush_dcache_segment_1way;
++ break;
++ case 2:
++ __flush_dcache_segment_fn = __flush_dcache_segment_2way;
++ break;
++ case 4:
++ __flush_dcache_segment_fn = __flush_dcache_segment_4way;
++ break;
++ default:
++ __flush_dcache_segment_fn = NULL;
++ break;
++ }
++
++ emit_cache_params();
++
++ if (remap_area_pages(P3SEG, 0, PAGE_SIZE * 4, _PAGE_CACHABLE))
+ panic("%s failed.", __FUNCTION__);
+
+- sema_init (&p3map_sem[0], 1);
+- sema_init (&p3map_sem[1], 1);
+- sema_init (&p3map_sem[2], 1);
+- sema_init (&p3map_sem[3], 1);
++ for (i = 0; i < cpu_data->dcache.n_aliases; i++)
++ sema_init(&p3map_sem[i], 1);
+ }
+
+ /*
+@@ -89,7 +160,6 @@ void __flush_purge_region(void *start, i
+ }
+ }
+
+-
+ /*
+ * No write back please
+ */
+@@ -108,40 +178,6 @@ void __flush_invalidate_region(void *sta
+ }
+ }
+
+-static void __flush_dcache_all_ex(void)
+-{
+- unsigned long addr, end_addr, entry_offset;
+-
+- end_addr = CACHE_OC_ADDRESS_ARRAY + (cpu_data->dcache.sets << cpu_data->dcache.entry_shift) * cpu_data->dcache.ways;
+- entry_offset = 1 << cpu_data->dcache.entry_shift;
+- for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; addr += entry_offset) {
+- ctrl_outl(0, addr);
+- }
+-}
+-
+-static void __flush_cache_4096_all_ex(unsigned long start)
+-{
+- unsigned long addr, entry_offset;
+- int i;
+-
+- entry_offset = 1 << cpu_data->dcache.entry_shift;
+- for (i = 0; i < cpu_data->dcache.ways; i++, start += cpu_data->dcache.way_incr) {
+- for (addr = CACHE_OC_ADDRESS_ARRAY + start;
+- addr < CACHE_OC_ADDRESS_ARRAY + 4096 + start;
+- addr += entry_offset) {
+- ctrl_outl(0, addr);
+- }
+- }
+-}
+-
+-void flush_cache_4096_all(unsigned long start)
+-{
+- if (cpu_data->dcache.ways == 1)
+- __flush_cache_4096_all(start);
+- else
+- __flush_cache_4096_all_ex(start);
+-}
+-
+ /*
+ * Write back the range of D-cache, and purge the I-cache.
+ *
+@@ -153,14 +189,14 @@ void flush_icache_range(unsigned long st
+ }
+
+ /*
+- * Write back the D-cache and purge the I-cache for signal trampoline.
++ * Write back the D-cache and purge the I-cache for signal trampoline.
+ * .. which happens to be the same behavior as flush_icache_range().
+ * So, we simply flush out a line.
+ */
+ void flush_cache_sigtramp(unsigned long addr)
+ {
+ unsigned long v, index;
+- unsigned long flags;
++ unsigned long flags;
+ int i;
+
+ v = addr & ~(L1_CACHE_BYTES-1);
+@@ -172,30 +208,33 @@ void flush_cache_sigtramp(unsigned long
+
+ local_irq_save(flags);
+ jump_to_P2();
+- for(i = 0; i < cpu_data->icache.ways; i++, index += cpu_data->icache.way_incr)
++
++ for (i = 0; i < cpu_data->icache.ways;
++ i++, index += cpu_data->icache.way_incr)
+ ctrl_outl(0, index); /* Clear out Valid-bit */
++
+ back_to_P1();
++ wmb();
+ local_irq_restore(flags);
+ }
+
+ static inline void flush_cache_4096(unsigned long start,
+ unsigned long phys)
+ {
+- unsigned long flags;
+- extern void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset);
++ unsigned long flags, exec_offset = 0;
+
+ /*
+- * SH7751, SH7751R, and ST40 have no restriction to handle cache.
+- * (While SH7750 must do that at P2 area.)
++ * All types of SH-4 require PC to be in P2 to operate on the I-cache.
++ * Some types of SH-4 require PC to be in P2 to operate on the D-cache.
+ */
+- if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG)
+- || start < CACHE_OC_ADDRESS_ARRAY) {
+- local_irq_save(flags);
+- __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0x20000000);
+- local_irq_restore(flags);
+- } else {
+- __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0);
+- }
++ if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) ||
++ (start < CACHE_OC_ADDRESS_ARRAY))
++ exec_offset = 0x20000000;
++
++ local_irq_save(flags);
++ __flush_cache_4096(start | SH_CACHE_ASSOC,
++ P1SEGADDR(phys), exec_offset);
++ local_irq_restore(flags);
+ }
+
+ /*
+@@ -206,15 +245,19 @@ void flush_dcache_page(struct page *page
+ {
+ if (test_bit(PG_mapped, &page->flags)) {
+ unsigned long phys = PHYSADDR(page_address(page));
++ unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
++ int i, n;
+
+ /* Loop all the D-cache */
+- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys);
+- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys);
+- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys);
+- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys);
++ n = cpu_data->dcache.n_aliases;
++ for (i = 0; i < n; i++, addr += PAGE_SIZE)
++ flush_cache_4096(addr, phys);
+ }
++
++ wmb();
+ }
+
++/* TODO: Selective icache invalidation through IC address array.. */
+ static inline void flush_icache_all(void)
+ {
+ unsigned long flags, ccr;
+@@ -227,34 +270,142 @@ static inline void flush_icache_all(void
+ ccr |= CCR_CACHE_ICI;
+ ctrl_outl(ccr, CCR);
+
++ /*
++ * back_to_P1() will take care of the barrier for us, don't add
++ * another one!
++ */
++
+ back_to_P1();
+ local_irq_restore(flags);
+ }
+
++void flush_dcache_all(void)
++{
++ (*__flush_dcache_segment_fn)(0UL, cpu_data->dcache.way_size);
++ wmb();
++}
++
+ void flush_cache_all(void)
+ {
+- if (cpu_data->dcache.ways == 1)
+- __flush_dcache_all();
+- else
+- __flush_dcache_all_ex();
++ flush_dcache_all();
+ flush_icache_all();
+ }
+
++static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
++ unsigned long end)
++{
++ unsigned long d = 0, p = start & PAGE_MASK;
++ unsigned long alias_mask = cpu_data->dcache.alias_mask;
++ unsigned long n_aliases = cpu_data->dcache.n_aliases;
++ unsigned long select_bit;
++ unsigned long all_aliases_mask;
++ unsigned long addr_offset;
++ pgd_t *dir;
++ pmd_t *pmd;
++ pud_t *pud;
++ pte_t *pte;
++ int i;
++
++ dir = pgd_offset(mm, p);
++ pud = pud_offset(dir, p);
++ pmd = pmd_offset(pud, p);
++ end = PAGE_ALIGN(end);
++
++ all_aliases_mask = (1 << n_aliases) - 1;
++
++ do {
++ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
++ p &= PMD_MASK;
++ p += PMD_SIZE;
++ pmd++;
++
++ continue;
++ }
++
++ pte = pte_offset_kernel(pmd, p);
++
++ do {
++ unsigned long phys;
++ pte_t entry = *pte;
++
++ if (!(pte_val(entry) & _PAGE_PRESENT)) {
++ pte++;
++ p += PAGE_SIZE;
++ continue;
++ }
++
++ phys = pte_val(entry) & PTE_PHYS_MASK;
++
++ if ((p ^ phys) & alias_mask) {
++ d |= 1 << ((p & alias_mask) >> PAGE_SHIFT);
++ d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT);
++
++ if (d == all_aliases_mask)
++ goto loop_exit;
++ }
++
++ pte++;
++ p += PAGE_SIZE;
++ } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
++ pmd++;
++ } while (p < end);
++
++loop_exit:
++ addr_offset = 0;
++ select_bit = 1;
++
++ for (i = 0; i < n_aliases; i++) {
++ if (d & select_bit) {
++ (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE);
++ wmb();
++ }
++
++ select_bit <<= 1;
++ addr_offset += PAGE_SIZE;
++ }
++}
++
++/*
++ * Note : (RPC) since the caches are physically tagged, the only point
++ * of flush_cache_mm for SH-4 is to get rid of aliases from the
++ * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that
++ * lines can stay resident so long as the virtual address they were
++ * accessed with (hence cache set) is in accord with the physical
++ * address (i.e. tag). It's no different here. So I reckon we don't
++ * need to flush the I-cache, since aliases don't matter for that. We
++ * should try that.
++ *
++ * Caller takes mm->mmap_sem.
++ */
+ void flush_cache_mm(struct mm_struct *mm)
+ {
+- /* Is there any good way? */
+- /* XXX: possibly call flush_cache_range for each vm area */
+- /*
+- * FIXME: Really, the optimal solution here would be able to flush out
+- * individual lines created by the specified context, but this isn't
+- * feasible for a number of architectures (such as MIPS, and some
+- * SPARC) .. is this possible for SuperH?
+- *
+- * In the meantime, we'll just flush all of the caches.. this
+- * seems to be the simplest way to avoid at least a few wasted
+- * cache flushes. -Lethal
++ /*
++ * If cache is only 4k-per-way, there are never any 'aliases'. Since
++ * the cache is physically tagged, the data can just be left in there.
+ */
+- flush_cache_all();
++ if (cpu_data->dcache.n_aliases == 0)
++ return;
++
++ /*
++ * Don't bother groveling around the dcache for the VMA ranges
++ * if there are too many PTEs to make it worthwhile.
++ */
++ if (mm->nr_ptes >= MAX_DCACHE_PAGES)
++ flush_dcache_all();
++ else {
++ struct vm_area_struct *vma;
++
++ /*
++ * In this case there are reasonably sized ranges to flush,
++ * iterate through the VMA list and take care of any aliases.
++ */
++ for (vma = mm->mmap; vma; vma = vma->vm_next)
++ __flush_cache_mm(mm, vma->vm_start, vma->vm_end);
++ }
++
++ /* Only touch the icache if one of the VMAs has VM_EXEC set. */
++ if (mm->exec_vm)
++ flush_icache_all();
+ }
+
+ /*
+@@ -263,27 +414,40 @@ void flush_cache_mm(struct mm_struct *mm
+ * ADDR: Virtual Address (U0 address)
+ * PFN: Physical page number
+ */
+-void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
++void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
++ unsigned long pfn)
+ {
+ unsigned long phys = pfn << PAGE_SHIFT;
++ unsigned int alias_mask;
++
++ alias_mask = cpu_data->dcache.alias_mask;
+
+ /* We only need to flush D-cache when we have alias */
+- if ((address^phys) & CACHE_ALIAS) {
++ if ((address^phys) & alias_mask) {
+ /* Loop 4K of the D-cache */
+ flush_cache_4096(
+- CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS),
++ CACHE_OC_ADDRESS_ARRAY | (address & alias_mask),
+ phys);
+ /* Loop another 4K of the D-cache */
+ flush_cache_4096(
+- CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS),
++ CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask),
+ phys);
+ }
+
+- if (vma->vm_flags & VM_EXEC)
+- /* Loop 4K (half) of the I-cache */
++ alias_mask = cpu_data->icache.alias_mask;
++ if (vma->vm_flags & VM_EXEC) {
++ /*
++ * Evict entries from the portion of the cache from which code
++ * may have been executed at this address (virtual). There's
++ * no need to evict from the portion corresponding to the
++ * physical address as for the D-cache, because we know the
++ * kernel has never executed the code through its identity
++ * translation.
++ */
+ flush_cache_4096(
+- CACHE_IC_ADDRESS_ARRAY | (address & 0x1000),
++ CACHE_IC_ADDRESS_ARRAY | (address & alias_mask),
+ phys);
++ }
+ }
+
+ /*
+@@ -298,52 +462,31 @@ void flush_cache_page(struct vm_area_str
+ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+ {
+- unsigned long p = start & PAGE_MASK;
+- pgd_t *dir;
+- pmd_t *pmd;
+- pte_t *pte;
+- pte_t entry;
+- unsigned long phys;
+- unsigned long d = 0;
+-
+- dir = pgd_offset(vma->vm_mm, p);
+- pmd = pmd_offset(dir, p);
++ /*
++ * If cache is only 4k-per-way, there are never any 'aliases'. Since
++ * the cache is physically tagged, the data can just be left in there.
++ */
++ if (cpu_data->dcache.n_aliases == 0)
++ return;
+
+- do {
+- if (pmd_none(*pmd) || pmd_bad(*pmd)) {
+- p &= ~((1 << PMD_SHIFT) -1);
+- p += (1 << PMD_SHIFT);
+- pmd++;
+- continue;
+- }
+- pte = pte_offset_kernel(pmd, p);
+- do {
+- entry = *pte;
+- if ((pte_val(entry) & _PAGE_PRESENT)) {
+- phys = pte_val(entry)&PTE_PHYS_MASK;
+- if ((p^phys) & CACHE_ALIAS) {
+- d |= 1 << ((p & CACHE_ALIAS)>>12);
+- d |= 1 << ((phys & CACHE_ALIAS)>>12);
+- if (d == 0x0f)
+- goto loop_exit;
+- }
+- }
+- pte++;
+- p += PAGE_SIZE;
+- } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
+- pmd++;
+- } while (p < end);
+- loop_exit:
+- if (d & 1)
+- flush_cache_4096_all(0);
+- if (d & 2)
+- flush_cache_4096_all(0x1000);
+- if (d & 4)
+- flush_cache_4096_all(0x2000);
+- if (d & 8)
+- flush_cache_4096_all(0x3000);
+- if (vma->vm_flags & VM_EXEC)
++ /*
++ * Don't bother with the lookup and alias check if we have a
++ * wide range to cover, just blow away the dcache in its
++ * entirety instead. -- PFM.
++ */
++ if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES)
++ flush_dcache_all();
++ else
++ __flush_cache_mm(vma->vm_mm, start, end);
++
++ if (vma->vm_flags & VM_EXEC) {
++ /*
++ * TODO: Is this required??? Need to look at how I-cache
++ * coherency is assured when new programs are loaded to see if
++ * this matters.
++ */
+ flush_icache_all();
++ }
+ }
+
+ /*
+@@ -357,5 +500,273 @@ void flush_icache_user_range(struct vm_a
+ struct page *page, unsigned long addr, int len)
+ {
+ flush_cache_page(vma, addr, page_to_pfn(page));
++ mb();
++}
++
++/**
++ * __flush_cache_4096
++ *
++ * @addr: address in memory mapped cache array
++ * @phys: P1 address to flush (has to match tags if addr has 'A' bit
++ * set i.e. associative write)
++ * @exec_offset: set to 0x20000000 if flush has to be executed from P2
++ * region else 0x0
++ *
++ * The offset into the cache array implied by 'addr' selects the
++ * 'colour' of the virtual address range that will be flushed. The
++ * operation (purge/write-back) is selected by the lower 2 bits of
++ * 'phys'.
++ */
++static void __flush_cache_4096(unsigned long addr, unsigned long phys,
++ unsigned long exec_offset)
++{
++ int way_count;
++ unsigned long base_addr = addr;
++ struct cache_info *dcache;
++ unsigned long way_incr;
++ unsigned long a, ea, p;
++ unsigned long temp_pc;
++
++ dcache = &cpu_data->dcache;
++ /* Write this way for better assembly. */
++ way_count = dcache->ways;
++ way_incr = dcache->way_incr;
++
++ /*
++ * Apply exec_offset (i.e. branch to P2 if required.).
++ *
++ * FIXME:
++ *
++ * If I write "=r" for the (temp_pc), it puts this in r6 hence
++ * trashing exec_offset before it's been added on - why? Hence
++ * "=&r" as a 'workaround'
++ */
++ asm volatile("mov.l 1f, %0\n\t"
++ "add %1, %0\n\t"
++ "jmp @%0\n\t"
++ "nop\n\t"
++ ".balign 4\n\t"
++ "1: .long 2f\n\t"
++ "2:\n" : "=&r" (temp_pc) : "r" (exec_offset));
++
++ /*
++ * We know there will be >=1 iteration, so write as do-while to avoid
++ * pointless nead-of-loop check for 0 iterations.
++ */
++ do {
++ ea = base_addr + PAGE_SIZE;
++ a = base_addr;
++ p = phys;
++
++ do {
++ *(volatile unsigned long *)a = p;
++ /*
++ * Next line: intentionally not p+32, saves an add, p
++ * will do since only the cache tag bits need to
++ * match.
++ */
++ *(volatile unsigned long *)(a+32) = p;
++ a += 64;
++ p += 64;
++ } while (a < ea);
++
++ base_addr += way_incr;
++ } while (--way_count != 0);
+ }
+
++/*
++ * Break the 1, 2 and 4 way variants of this out into separate functions to
++ * avoid nearly all the overhead of having the conditional stuff in the function
++ * bodies (+ the 1 and 2 way cases avoid saving any registers too).
++ */
++static void __flush_dcache_segment_1way(unsigned long start,
++ unsigned long extent_per_way)
++{
++ unsigned long orig_sr, sr_with_bl;
++ unsigned long base_addr;
++ unsigned long way_incr, linesz, way_size;
++ struct cache_info *dcache;
++ register unsigned long a0, a0e;
++
++ asm volatile("stc sr, %0" : "=r" (orig_sr));
++ sr_with_bl = orig_sr | (1<<28);
++ base_addr = ((unsigned long)&empty_zero_page[0]);
++
++ /*
++ * The previous code aligned base_addr to 16k, i.e. the way_size of all
++ * existing SH-4 D-caches. Whilst I don't see a need to have this
++ * aligned to any better than the cache line size (which it will be
++ * anyway by construction), let's align it to at least the way_size of
++ * any existing or conceivable SH-4 D-cache. -- RPC
++ */
++ base_addr = ((base_addr >> 16) << 16);
++ base_addr |= start;
++
++ dcache = &cpu_data->dcache;
++ linesz = dcache->linesz;
++ way_incr = dcache->way_incr;
++ way_size = dcache->way_size;
++
++ a0 = base_addr;
++ a0e = base_addr + extent_per_way;
++ do {
++ asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
++ asm volatile("movca.l r0, @%0\n\t"
++ "ocbi @%0" : : "r" (a0));
++ a0 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "ocbi @%0" : : "r" (a0));
++ a0 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "ocbi @%0" : : "r" (a0));
++ a0 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "ocbi @%0" : : "r" (a0));
++ asm volatile("ldc %0, sr" : : "r" (orig_sr));
++ a0 += linesz;
++ } while (a0 < a0e);
++}
++
++static void __flush_dcache_segment_2way(unsigned long start,
++ unsigned long extent_per_way)
++{
++ unsigned long orig_sr, sr_with_bl;
++ unsigned long base_addr;
++ unsigned long way_incr, linesz, way_size;
++ struct cache_info *dcache;
++ register unsigned long a0, a1, a0e;
++
++ asm volatile("stc sr, %0" : "=r" (orig_sr));
++ sr_with_bl = orig_sr | (1<<28);
++ base_addr = ((unsigned long)&empty_zero_page[0]);
++
++ /* See comment under 1-way above */
++ base_addr = ((base_addr >> 16) << 16);
++ base_addr |= start;
++
++ dcache = &cpu_data->dcache;
++ linesz = dcache->linesz;
++ way_incr = dcache->way_incr;
++ way_size = dcache->way_size;
++
++ a0 = base_addr;
++ a1 = a0 + way_incr;
++ a0e = base_addr + extent_per_way;
++ do {
++ asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1" : :
++ "r" (a0), "r" (a1));
++ a0 += linesz;
++ a1 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1" : :
++ "r" (a0), "r" (a1));
++ a0 += linesz;
++ a1 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1" : :
++ "r" (a0), "r" (a1));
++ a0 += linesz;
++ a1 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1" : :
++ "r" (a0), "r" (a1));
++ asm volatile("ldc %0, sr" : : "r" (orig_sr));
++ a0 += linesz;
++ a1 += linesz;
++ } while (a0 < a0e);
++}
++
++static void __flush_dcache_segment_4way(unsigned long start,
++ unsigned long extent_per_way)
++{
++ unsigned long orig_sr, sr_with_bl;
++ unsigned long base_addr;
++ unsigned long way_incr, linesz, way_size;
++ struct cache_info *dcache;
++ register unsigned long a0, a1, a2, a3, a0e;
++
++ asm volatile("stc sr, %0" : "=r" (orig_sr));
++ sr_with_bl = orig_sr | (1<<28);
++ base_addr = ((unsigned long)&empty_zero_page[0]);
++
++ /* See comment under 1-way above */
++ base_addr = ((base_addr >> 16) << 16);
++ base_addr |= start;
++
++ dcache = &cpu_data->dcache;
++ linesz = dcache->linesz;
++ way_incr = dcache->way_incr;
++ way_size = dcache->way_size;
++
++ a0 = base_addr;
++ a1 = a0 + way_incr;
++ a2 = a1 + way_incr;
++ a3 = a2 + way_incr;
++ a0e = base_addr + extent_per_way;
++ do {
++ asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "movca.l r0, @%2\n\t"
++ "movca.l r0, @%3\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1\n\t"
++ "ocbi @%2\n\t"
++ "ocbi @%3\n\t" : :
++ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
++ a0 += linesz;
++ a1 += linesz;
++ a2 += linesz;
++ a3 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "movca.l r0, @%2\n\t"
++ "movca.l r0, @%3\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1\n\t"
++ "ocbi @%2\n\t"
++ "ocbi @%3\n\t" : :
++ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
++ a0 += linesz;
++ a1 += linesz;
++ a2 += linesz;
++ a3 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "movca.l r0, @%2\n\t"
++ "movca.l r0, @%3\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1\n\t"
++ "ocbi @%2\n\t"
++ "ocbi @%3\n\t" : :
++ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
++ a0 += linesz;
++ a1 += linesz;
++ a2 += linesz;
++ a3 += linesz;
++ asm volatile("movca.l r0, @%0\n\t"
++ "movca.l r0, @%1\n\t"
++ "movca.l r0, @%2\n\t"
++ "movca.l r0, @%3\n\t"
++ "ocbi @%0\n\t"
++ "ocbi @%1\n\t"
++ "ocbi @%2\n\t"
++ "ocbi @%3\n\t" : :
++ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
++ asm volatile("ldc %0, sr" : : "r" (orig_sr));
++ a0 += linesz;
++ a1 += linesz;
++ a2 += linesz;
++ a3 += linesz;
++ } while (a0 < a0e);
++}
+diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
+index ad8ed7d..045abdf 100644
+--- a/arch/sh/mm/cache-sh7705.c
++++ b/arch/sh/mm/cache-sh7705.c
+@@ -9,7 +9,6 @@
+ * for more details.
+ *
+ */
+-
+ #include <linux/init.h>
+ #include <linux/mman.h>
+ #include <linux/mm.h>
+@@ -25,14 +24,10 @@
+ #include <asm/mmu_context.h>
+ #include <asm/cacheflush.h>
+
+-/* The 32KB cache on the SH7705 suffers from the same synonym problem
+- * as SH4 CPUs */
+-
+-#define __pte_offset(address) \
+- ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+-#define pte_offset(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \
+- __pte_offset(address))
+-
++/*
++ * The 32KB cache on the SH7705 suffers from the same synonym problem
++ * as SH4 CPUs
++ */
+ static inline void cache_wback_all(void)
+ {
+ unsigned long ways, waysize, addrstart;
+@@ -73,7 +68,6 @@ void flush_icache_range(unsigned long st
+ __flush_wback_region((void *)start, end - start);
+ }
+
+-
+ /*
+ * Writeback&Invalidate the D-cache of the page
+ */
+@@ -128,7 +122,6 @@ static void __flush_dcache_page(unsigned
+ local_irq_restore(flags);
+ }
+
+-
+ /*
+ * Write back & invalidate the D-cache of the page.
+ * (To avoid "alias" issues)
+@@ -186,7 +179,8 @@ void flush_cache_range(struct vm_area_st
+ *
+ * ADDRESS: Virtual Address (U0 address)
+ */
+-void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
++void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
++ unsigned long pfn)
+ {
+ __flush_dcache_page(pfn << PAGE_SHIFT);
+ }
+@@ -203,4 +197,3 @@ void flush_icache_page(struct vm_area_st
+ {
+ __flush_purge_region(page_address(page), PAGE_SIZE);
+ }
+-
+diff --git a/arch/sh/mm/clear_page.S b/arch/sh/mm/clear_page.S
+index 08acead..7b96425 100644
+--- a/arch/sh/mm/clear_page.S
++++ b/arch/sh/mm/clear_page.S
+@@ -193,102 +193,5 @@ ENTRY(__clear_user_page)
+ nop
+ .L4096: .word 4096
+
+-ENTRY(__flush_cache_4096)
+- mov.l 1f,r3
+- add r6,r3
+- mov r4,r0
+- mov #64,r2
+- shll r2
+- mov #64,r6
+- jmp @r3
+- mov #96,r7
+- .align 2
+-1: .long 2f
+-2:
+- .rept 32
+- mov.l r5, at r0
+- mov.l r5,@(32,r0)
+- mov.l r5,@(r0,r6)
+- mov.l r5,@(r0,r7)
+- add r2,r5
+- add r2,r0
+- .endr
+- nop
+- nop
+- nop
+- nop
+- nop
+- nop
+- nop
+- rts
+- nop
+-
+-ENTRY(__flush_dcache_all)
+- mov.l 2f,r0
+- mov.l 3f,r4
+- and r0,r4 ! r4 = (unsigned long)&empty_zero_page[0] & ~0xffffc000
+- stc sr,r1 ! save SR
+- mov.l 4f,r2
+- or r1,r2
+- mov #32,r3
+- shll2 r3
+-1:
+- ldc r2,sr ! set BL bit
+- movca.l r0, at r4
+- ocbi @r4
+- add #32,r4
+- movca.l r0, at r4
+- ocbi @r4
+- add #32,r4
+- movca.l r0, at r4
+- ocbi @r4
+- add #32,r4
+- movca.l r0, at r4
+- ocbi @r4
+- ldc r1,sr ! restore SR
+- dt r3
+- bf/s 1b
+- add #32,r4
+-
+- rts
+- nop
+- .align 2
+-2: .long 0xffffc000
+-3: .long empty_zero_page
+-4: .long 0x10000000 ! BL bit
+-
+-/* __flush_cache_4096_all(unsigned long addr) */
+-ENTRY(__flush_cache_4096_all)
+- mov.l 2f,r0
+- mov.l 3f,r2
+- and r0,r2
+- or r2,r4 ! r4 = addr | (unsigned long)&empty_zero_page[0] & ~0x3fff
+- stc sr,r1 ! save SR
+- mov.l 4f,r2
+- or r1,r2
+- mov #32,r3
+-1:
+- ldc r2,sr ! set BL bit
+- movca.l r0, at r4
+- ocbi @r4
+- add #32,r4
+- movca.l r0, at r4
+- ocbi @r4
+- add #32,r4
+- movca.l r0, at r4
+- ocbi @r4
+- add #32,r4
+- movca.l r0, at r4
+- ocbi @r4
+- ldc r1,sr ! restore SR
+- dt r3
+- bf/s 1b
+- add #32,r4
+-
+- rts
+- nop
+- .align 2
+-2: .long 0xffffc000
+-3: .long empty_zero_page
+-4: .long 0x10000000 ! BL bit
+ #endif
++
+diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
+index ee73e30..38c82d8 100644
+--- a/arch/sh/mm/consistent.c
++++ b/arch/sh/mm/consistent.c
+@@ -9,6 +9,8 @@
+ */
+ #include <linux/mm.h>
+ #include <linux/dma-mapping.h>
++#include <asm/cacheflush.h>
++#include <asm/addrspace.h>
+ #include <asm/io.h>
+
+ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
+@@ -26,6 +28,7 @@ void *consistent_alloc(gfp_t gfp, size_t
+ split_page(page, order);
+
+ ret = page_address(page);
++ memset(ret, 0, size);
+ *handle = virt_to_phys(ret);
+
+ /*
+diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
+index 775f86c..68663b8 100644
+--- a/arch/sh/mm/fault.c
++++ b/arch/sh/mm/fault.c
+@@ -1,33 +1,22 @@
+-/* $Id: fault.c,v 1.14 2004/01/13 05:52:11 kkojima Exp $
++/*
++ * Page fault handler for SH with an MMU.
+ *
+- * linux/arch/sh/mm/fault.c
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2003 Paul Mundt
+ *
+ * Based on linux/arch/i386/mm/fault.c:
+ * Copyright (C) 1995 Linus Torvalds
++ *
++ * 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/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/mman.h>
+ #include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-
++#include <linux/hardirq.h>
++#include <linux/kprobes.h>
+ #include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgalloc.h>
+ #include <asm/mmu_context.h>
+-#include <asm/cacheflush.h>
+ #include <asm/kgdb.h>
+
+ extern void die(const char *,struct pt_regs *,long);
+@@ -80,7 +69,7 @@ good_area:
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ }
+
+@@ -160,7 +149,7 @@ no_context:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+@@ -187,18 +176,30 @@ do_sigbus:
+ goto no_context;
+ }
+
++#ifdef CONFIG_SH_STORE_QUEUES
+ /*
+- * Called with interrupt disabled.
++ * This is a special case for the SH-4 store queues, as pages for this
++ * space still need to be faulted in before it's possible to flush the
++ * store queue cache for writeout to the remapped region.
+ */
+-asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
+- unsigned long address)
++#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000)
++#else
++#define P3_ADDR_MAX P4SEG
++#endif
++
++/*
++ * Called with interrupts disabled.
++ */
++asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
++ unsigned long writeaccess,
++ unsigned long address)
+ {
+- unsigned long addrmax = P4SEG;
+ pgd_t *pgd;
++ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t entry;
+- struct mm_struct *mm;
++ struct mm_struct *mm = current->mm;
+ spinlock_t *ptl;
+ int ret = 1;
+
+@@ -207,31 +208,37 @@ asmlinkage int __do_page_fault(struct pt
+ kgdb_bus_err_hook();
+ #endif
+
+-#ifdef CONFIG_SH_STORE_QUEUES
+- addrmax = P4SEG_STORE_QUE + 0x04000000;
+-#endif
+-
+- if (address >= P3SEG && address < addrmax) {
++ /*
++ * We don't take page faults for P1, P2, and parts of P4, these
++ * are always mapped, whether it be due to legacy behaviour in
++ * 29-bit mode, or due to PMB configuration in 32-bit mode.
++ */
++ if (address >= P3SEG && address < P3_ADDR_MAX) {
+ pgd = pgd_offset_k(address);
+ mm = NULL;
+- } else if (address >= TASK_SIZE)
+- return 1;
+- else if (!(mm = current->mm))
+- return 1;
+- else
++ } else {
++ if (unlikely(address >= TASK_SIZE || !mm))
++ return 1;
++
+ pgd = pgd_offset(mm, address);
++ }
+
+- pmd = pmd_offset(pgd, address);
++ pud = pud_offset(pgd, address);
++ if (pud_none_or_clear_bad(pud))
++ return 1;
++ pmd = pmd_offset(pud, address);
+ if (pmd_none_or_clear_bad(pmd))
+ return 1;
++
+ if (mm)
+ pte = pte_offset_map_lock(mm, pmd, address, &ptl);
+ else
+ pte = pte_offset_kernel(pmd, address);
+
+ entry = *pte;
+- if (pte_none(entry) || pte_not_present(entry)
+- || (writeaccess && !pte_write(entry)))
++ if (unlikely(pte_none(entry) || pte_not_present(entry)))
++ goto unlock;
++ if (unlikely(writeaccess && !pte_write(entry)))
+ goto unlock;
+
+ if (writeaccess)
+@@ -243,13 +250,7 @@ asmlinkage int __do_page_fault(struct pt
+ * ITLB is not affected by "ldtlb" instruction.
+ * So, we need to flush the entry by ourselves.
+ */
+-
+- {
+- unsigned long flags;
+- local_irq_save(flags);
+- __flush_tlb_page(get_asid(), address&PAGE_MASK);
+- local_irq_restore(flags);
+- }
++ __flush_tlb_page(get_asid(), address & PAGE_MASK);
+ #endif
+
+ set_pte(pte, entry);
+@@ -260,121 +261,3 @@ unlock:
+ pte_unmap_unlock(pte, ptl);
+ return ret;
+ }
+-
+-void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+-{
+- if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) {
+- unsigned long flags;
+- unsigned long asid;
+- unsigned long saved_asid = MMU_NO_ASID;
+-
+- asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
+- page &= PAGE_MASK;
+-
+- local_irq_save(flags);
+- if (vma->vm_mm != current->mm) {
+- saved_asid = get_asid();
+- set_asid(asid);
+- }
+- __flush_tlb_page(asid, page);
+- if (saved_asid != MMU_NO_ASID)
+- set_asid(saved_asid);
+- local_irq_restore(flags);
+- }
+-}
+-
+-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+- unsigned long end)
+-{
+- struct mm_struct *mm = vma->vm_mm;
+-
+- if (mm->context != NO_CONTEXT) {
+- unsigned long flags;
+- int size;
+-
+- local_irq_save(flags);
+- size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+- if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
+- mm->context = NO_CONTEXT;
+- if (mm == current->mm)
+- activate_context(mm);
+- } else {
+- unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK;
+- unsigned long saved_asid = MMU_NO_ASID;
+-
+- start &= PAGE_MASK;
+- end += (PAGE_SIZE - 1);
+- end &= PAGE_MASK;
+- if (mm != current->mm) {
+- saved_asid = get_asid();
+- set_asid(asid);
+- }
+- while (start < end) {
+- __flush_tlb_page(asid, start);
+- start += PAGE_SIZE;
+- }
+- if (saved_asid != MMU_NO_ASID)
+- set_asid(saved_asid);
+- }
+- local_irq_restore(flags);
+- }
+-}
+-
+-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+-{
+- unsigned long flags;
+- int size;
+-
+- local_irq_save(flags);
+- size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+- if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
+- flush_tlb_all();
+- } else {
+- unsigned long asid = init_mm.context&MMU_CONTEXT_ASID_MASK;
+- unsigned long saved_asid = get_asid();
+-
+- start &= PAGE_MASK;
+- end += (PAGE_SIZE - 1);
+- end &= PAGE_MASK;
+- set_asid(asid);
+- while (start < end) {
+- __flush_tlb_page(asid, start);
+- start += PAGE_SIZE;
+- }
+- set_asid(saved_asid);
+- }
+- local_irq_restore(flags);
+-}
+-
+-void flush_tlb_mm(struct mm_struct *mm)
+-{
+- /* Invalidate all TLB of this process. */
+- /* Instead of invalidating each TLB, we get new MMU context. */
+- if (mm->context != NO_CONTEXT) {
+- unsigned long flags;
+-
+- local_irq_save(flags);
+- mm->context = NO_CONTEXT;
+- if (mm == current->mm)
+- activate_context(mm);
+- local_irq_restore(flags);
+- }
+-}
+-
+-void flush_tlb_all(void)
+-{
+- unsigned long flags, status;
+-
+- /*
+- * Flush all the TLB.
+- *
+- * Write to the MMU control register's bit:
+- * TF-bit for SH-3, TI-bit for SH-4.
+- * It's same position, bit #2.
+- */
+- local_irq_save(flags);
+- status = ctrl_inl(MMUCR);
+- status |= 0x04;
+- ctrl_outl(status, MMUCR);
+- local_irq_restore(flags);
+-}
+diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
+index 2a85bc1..329059d 100644
+--- a/arch/sh/mm/hugetlbpage.c
++++ b/arch/sh/mm/hugetlbpage.c
+@@ -26,61 +26,41 @@
+ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+ {
+ pgd_t *pgd;
++ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd) {
+- pmd = pmd_alloc(mm, pgd, addr);
+- if (pmd)
+- pte = pte_alloc_map(mm, pmd, addr);
++ pud = pud_alloc(mm, pgd, addr);
++ if (pud) {
++ pmd = pmd_alloc(mm, pud, addr);
++ if (pmd)
++ pte = pte_alloc_map(mm, pmd, addr);
++ }
+ }
++
+ return pte;
+ }
+
+ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+ {
+ pgd_t *pgd;
++ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd) {
+- pmd = pmd_offset(pgd, addr);
+- if (pmd)
+- pte = pte_offset_map(pmd, addr);
+- }
+- return pte;
+-}
+-
+-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+- pte_t *ptep, pte_t entry)
+-{
+- int i;
+-
+- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+- set_pte_at(mm, addr, ptep, entry);
+- ptep++;
+- addr += PAGE_SIZE;
+- pte_val(entry) += PAGE_SIZE;
++ pud = pud_offset(pgd, addr);
++ if (pud) {
++ pmd = pmd_offset(pud, addr);
++ if (pmd)
++ pte = pte_offset_map(pmd, addr);
++ }
+ }
+-}
+-
+-pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+- pte_t *ptep)
+-{
+- pte_t entry;
+- int i;
+-
+- entry = *ptep;
+
+- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+- pte_clear(mm, addr, ptep);
+- addr += PAGE_SIZE;
+- ptep++;
+- }
+-
+- return entry;
++ return pte;
+ }
+
+ struct page *follow_huge_addr(struct mm_struct *mm,
+diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
+index 8ea27ca..7154d1c 100644
+--- a/arch/sh/mm/init.c
++++ b/arch/sh/mm/init.c
+@@ -24,7 +24,7 @@
+ #include <linux/highmem.h>
+ #include <linux/bootmem.h>
+ #include <linux/pagemap.h>
+-
++#include <linux/proc_fs.h>
+ #include <asm/processor.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -80,6 +80,7 @@ void show_mem(void)
+ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
+ {
+ pgd_t *pgd;
++ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+@@ -89,7 +90,17 @@ static void set_pte_phys(unsigned long a
+ return;
+ }
+
+- pmd = pmd_offset(pgd, addr);
++ pud = pud_offset(pgd, addr);
++ if (pud_none(*pud)) {
++ pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
++ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
++ if (pmd != pmd_offset(pud, 0)) {
++ pud_ERROR(*pud);
++ return;
++ }
++ }
++
++ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd)) {
+ pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
+ set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
+@@ -212,6 +223,8 @@ void __init paging_init(void)
+ free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+ }
+
++static struct kcore_list kcore_mem, kcore_vmalloc;
++
+ void __init mem_init(void)
+ {
+ extern unsigned long empty_zero_page[1024];
+@@ -237,8 +250,13 @@ void __init mem_init(void)
+ * Setup wrappers for copy/clear_page(), these will get overridden
+ * later in the boot process if a better method is available.
+ */
++#ifdef CONFIG_MMU
+ copy_page = copy_page_slow;
+ clear_page = clear_page_slow;
++#else
++ copy_page = copy_page_nommu;
++ clear_page = clear_page_nommu;
++#endif
+
+ /* this will put all low memory onto the freelists */
+ totalram_pages += free_all_bootmem_node(NODE_DATA(0));
+@@ -254,7 +272,12 @@ void __init mem_init(void)
+ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+- printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
++ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
++ kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
++ VMALLOC_END - VMALLOC_START);
++
++ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
++ "%dk reserved, %dk data, %dk init)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
+ codesize >> 10,
+@@ -263,6 +286,9 @@ void __init mem_init(void)
+ initsize >> 10);
+
+ p3_cache_init();
++
++ /* Initialize the vDSO */
++ vsyscall_init();
+ }
+
+ void free_initmem(void)
+diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c
+index 96fa4a9..a9fe80c 100644
+--- a/arch/sh/mm/ioremap.c
++++ b/arch/sh/mm/ioremap.c
+@@ -15,6 +15,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/module.h>
+ #include <linux/mm.h>
++#include <linux/pci.h>
+ #include <asm/io.h>
+ #include <asm/page.h>
+ #include <asm/pgalloc.h>
+@@ -135,6 +136,20 @@ void __iomem *__ioremap(unsigned long ph
+ return (void __iomem *)phys_to_virt(phys_addr);
+
+ /*
++ * If we're on an SH7751 or SH7780 PCI controller, PCI memory is
++ * mapped at the end of the address space (typically 0xfd000000)
++ * in a non-translatable area, so mapping through page tables for
++ * this area is not only pointless, but also fundamentally
++ * broken. Just return the physical address instead.
++ *
++ * For boards that map a small PCI memory aperture somewhere in
++ * P1/P2 space, ioremap() will already do the right thing,
++ * and we'll never get this far.
++ */
++ if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
++ return (void __iomem *)phys_addr;
++
++ /*
+ * Don't allow anybody to remap normal RAM that we're using..
+ */
+ if (phys_addr < virt_to_phys(high_memory))
+@@ -192,7 +207,7 @@ void __iounmap(void __iomem *addr)
+ unsigned long vaddr = (unsigned long __force)addr;
+ struct vm_struct *p;
+
+- if (PXSEG(vaddr) < P3SEG)
++ if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr))
+ return;
+
+ #ifdef CONFIG_32BIT
+diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c
+index 8f9165a..d15221b 100644
+--- a/arch/sh/mm/pg-nommu.c
++++ b/arch/sh/mm/pg-nommu.c
+@@ -14,23 +14,24 @@
+ #include <linux/string.h>
+ #include <asm/page.h>
+
+-static void copy_page_nommu(void *to, void *from)
++void copy_page_nommu(void *to, void *from)
+ {
+ memcpy(to, from, PAGE_SIZE);
+ }
+
+-static void clear_page_nommu(void *to)
++void clear_page_nommu(void *to)
+ {
+ memset(to, 0, PAGE_SIZE);
+ }
+
+-static int __init pg_nommu_init(void)
++__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n)
+ {
+- copy_page = copy_page_nommu;
+- clear_page = clear_page_nommu;
+-
++ memcpy(to, from, n);
+ return 0;
+ }
+
+-subsys_initcall(pg_nommu_init);
+-
++__kernel_size_t __clear_user(void *to, __kernel_size_t n)
++{
++ memset(to, 0, n);
++ return 0;
++}
+diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c
+index c776b60..07371ed 100644
+--- a/arch/sh/mm/pg-sh4.c
++++ b/arch/sh/mm/pg-sh4.c
+@@ -2,7 +2,7 @@
+ * arch/sh/mm/pg-sh4.c
+ *
+ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
+- * Copyright (C) 2002 Paul Mundt
++ * Copyright (C) 2002 - 2005 Paul Mundt
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+@@ -23,6 +23,8 @@
+
+ extern struct semaphore p3map_sem[];
+
++#define CACHE_ALIAS (cpu_data->dcache.alias_mask)
++
+ /*
+ * clear_user_page
+ * @to: P1 address
+@@ -35,14 +37,15 @@ void clear_user_page(void *to, unsigned
+ if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
+ clear_page(to);
+ else {
+- pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
++ pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
+ _PAGE_RW | _PAGE_CACHABLE |
+- _PAGE_DIRTY | _PAGE_ACCESSED |
++ _PAGE_DIRTY | _PAGE_ACCESSED |
+ _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
+ unsigned long phys_addr = PHYSADDR(to);
+ unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
+- pgd_t *dir = pgd_offset_k(p3_addr);
+- pmd_t *pmd = pmd_offset(dir, p3_addr);
++ pgd_t *pgd = pgd_offset_k(p3_addr);
++ pud_t *pud = pud_offset(pgd, p3_addr);
++ pmd_t *pmd = pmd_offset(pud, p3_addr);
+ pte_t *pte = pte_offset_kernel(pmd, p3_addr);
+ pte_t entry;
+ unsigned long flags;
+@@ -67,21 +70,22 @@ void clear_user_page(void *to, unsigned
+ * @address: U0 address to be mapped
+ * @page: page (virt_to_page(to))
+ */
+-void copy_user_page(void *to, void *from, unsigned long address,
++void copy_user_page(void *to, void *from, unsigned long address,
+ struct page *page)
+ {
+ __set_bit(PG_mapped, &page->flags);
+ if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
+ copy_page(to, from);
+ else {
+- pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
++ pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
+ _PAGE_RW | _PAGE_CACHABLE |
+- _PAGE_DIRTY | _PAGE_ACCESSED |
++ _PAGE_DIRTY | _PAGE_ACCESSED |
+ _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
+ unsigned long phys_addr = PHYSADDR(to);
+ unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
+- pgd_t *dir = pgd_offset_k(p3_addr);
+- pmd_t *pmd = pmd_offset(dir, p3_addr);
++ pgd_t *pgd = pgd_offset_k(p3_addr);
++ pud_t *pud = pud_offset(pgd, p3_addr);
++ pmd_t *pmd = pmd_offset(pud, p3_addr);
+ pte_t *pte = pte_offset_kernel(pmd, p3_addr);
+ pte_t entry;
+ unsigned long flags;
+diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
+new file mode 100644
+index 0000000..92e7453
+--- /dev/null
++++ b/arch/sh/mm/pmb.c
+@@ -0,0 +1,400 @@
++/*
++ * arch/sh/mm/pmb.c
++ *
++ * Privileged Space Mapping Buffer (PMB) Support.
++ *
++ * Copyright (C) 2005, 2006 Paul Mundt
++ *
++ * P1/P2 Section mapping definitions from map32.h, which was:
++ *
++ * Copyright 2003 (c) Lineo Solutions,Inc.
++ *
++ * 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/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/bitops.h>
++#include <linux/debugfs.h>
++#include <linux/fs.h>
++#include <linux/seq_file.h>
++#include <linux/err.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/mmu.h>
++#include <asm/io.h>
++
++#define NR_PMB_ENTRIES 16
++
++static kmem_cache_t *pmb_cache;
++static unsigned long pmb_map;
++
++static struct pmb_entry pmb_init_map[] = {
++ /* vpn ppn flags (ub/sz/c/wt) */
++
++ /* P1 Section Mappings */
++ { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, },
++ { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, },
++ { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, },
++ { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, },
++ { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, },
++ { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, },
++
++ /* P2 Section Mappings */
++ { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
++ { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
++ { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, },
++ { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
++ { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
++ { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
++};
++
++static inline unsigned long mk_pmb_entry(unsigned int entry)
++{
++ return (entry & PMB_E_MASK) << PMB_E_SHIFT;
++}
++
++static inline unsigned long mk_pmb_addr(unsigned int entry)
++{
++ return mk_pmb_entry(entry) | PMB_ADDR;
++}
++
++static inline unsigned long mk_pmb_data(unsigned int entry)
++{
++ return mk_pmb_entry(entry) | PMB_DATA;
++}
++
++struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
++ unsigned long flags)
++{
++ struct pmb_entry *pmbe;
++
++ pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL);
++ if (!pmbe)
++ return ERR_PTR(-ENOMEM);
++
++ pmbe->vpn = vpn;
++ pmbe->ppn = ppn;
++ pmbe->flags = flags;
++
++ return pmbe;
++}
++
++void pmb_free(struct pmb_entry *pmbe)
++{
++ kmem_cache_free(pmb_cache, pmbe);
++}
++
++/*
++ * Must be in P2 for __set_pmb_entry()
++ */
++int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
++ unsigned long flags, int *entry)
++{
++ unsigned int pos = *entry;
++
++ if (unlikely(pos == PMB_NO_ENTRY))
++ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
++
++repeat:
++ if (unlikely(pos > NR_PMB_ENTRIES))
++ return -ENOSPC;
++
++ if (test_and_set_bit(pos, &pmb_map)) {
++ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
++ goto repeat;
++ }
++
++ ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
++
++#ifdef CONFIG_SH_WRITETHROUGH
++ /*
++ * When we are in 32-bit address extended mode, CCR.CB becomes
++ * invalid, so care must be taken to manually adjust cacheable
++ * translations.
++ */
++ if (likely(flags & PMB_C))
++ flags |= PMB_WT;
++#endif
++
++ ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
++
++ *entry = pos;
++
++ return 0;
++}
++
++int set_pmb_entry(struct pmb_entry *pmbe)
++{
++ int ret;
++
++ jump_to_P2();
++ ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
++ back_to_P1();
++
++ return ret;
++}
++
++void clear_pmb_entry(struct pmb_entry *pmbe)
++{
++ unsigned int entry = pmbe->entry;
++ unsigned long addr;
++
++ /*
++ * Don't allow clearing of wired init entries, P1 or P2 access
++ * without a corresponding mapping in the PMB will lead to reset
++ * by the TLB.
++ */
++ if (unlikely(entry < ARRAY_SIZE(pmb_init_map) ||
++ entry >= NR_PMB_ENTRIES))
++ return;
++
++ jump_to_P2();
++
++ /* Clear V-bit */
++ addr = mk_pmb_addr(entry);
++ ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
++
++ addr = mk_pmb_data(entry);
++ ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
++
++ back_to_P1();
++
++ clear_bit(entry, &pmb_map);
++}
++
++static DEFINE_SPINLOCK(pmb_list_lock);
++static struct pmb_entry *pmb_list;
++
++static inline void pmb_list_add(struct pmb_entry *pmbe)
++{
++ struct pmb_entry **p, *tmp;
++
++ p = &pmb_list;
++ while ((tmp = *p) != NULL)
++ p = &tmp->next;
++
++ pmbe->next = tmp;
++ *p = pmbe;
++}
++
++static inline void pmb_list_del(struct pmb_entry *pmbe)
++{
++ struct pmb_entry **p, *tmp;
++
++ for (p = &pmb_list; (tmp = *p); p = &tmp->next)
++ if (tmp == pmbe) {
++ *p = tmp->next;
++ return;
++ }
++}
++
++static struct {
++ unsigned long size;
++ int flag;
++} pmb_sizes[] = {
++ { .size = 0x20000000, .flag = PMB_SZ_512M, },
++ { .size = 0x08000000, .flag = PMB_SZ_128M, },
++ { .size = 0x04000000, .flag = PMB_SZ_64M, },
++ { .size = 0x01000000, .flag = PMB_SZ_16M, },
++};
++
++long pmb_remap(unsigned long vaddr, unsigned long phys,
++ unsigned long size, unsigned long flags)
++{
++ struct pmb_entry *pmbp;
++ unsigned long wanted;
++ int pmb_flags, i;
++
++ /* Convert typical pgprot value to the PMB equivalent */
++ if (flags & _PAGE_CACHABLE) {
++ if (flags & _PAGE_WT)
++ pmb_flags = PMB_WT;
++ else
++ pmb_flags = PMB_C;
++ } else
++ pmb_flags = PMB_WT | PMB_UB;
++
++ pmbp = NULL;
++ wanted = size;
++
++again:
++ for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
++ struct pmb_entry *pmbe;
++ int ret;
++
++ if (size < pmb_sizes[i].size)
++ continue;
++
++ pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
++ if (IS_ERR(pmbe))
++ return PTR_ERR(pmbe);
++
++ ret = set_pmb_entry(pmbe);
++ if (ret != 0) {
++ pmb_free(pmbe);
++ return -EBUSY;
++ }
++
++ phys += pmb_sizes[i].size;
++ vaddr += pmb_sizes[i].size;
++ size -= pmb_sizes[i].size;
++
++ /*
++ * Link adjacent entries that span multiple PMB entries
++ * for easier tear-down.
++ */
++ if (likely(pmbp))
++ pmbp->link = pmbe;
++
++ pmbp = pmbe;
++ }
++
++ if (size >= 0x1000000)
++ goto again;
++
++ return wanted - size;
++}
++
++void pmb_unmap(unsigned long addr)
++{
++ struct pmb_entry **p, *pmbe;
++
++ for (p = &pmb_list; (pmbe = *p); p = &pmbe->next)
++ if (pmbe->vpn == addr)
++ break;
++
++ if (unlikely(!pmbe))
++ return;
++
++ WARN_ON(!test_bit(pmbe->entry, &pmb_map));
++
++ do {
++ struct pmb_entry *pmblink = pmbe;
++
++ clear_pmb_entry(pmbe);
++ pmbe = pmblink->link;
++
++ pmb_free(pmblink);
++ } while (pmbe);
++}
++
++static void pmb_cache_ctor(void *pmb, kmem_cache_t *cachep, unsigned long flags)
++{
++ struct pmb_entry *pmbe = pmb;
++
++ memset(pmb, 0, sizeof(struct pmb_entry));
++
++ spin_lock_irq(&pmb_list_lock);
++
++ pmbe->entry = PMB_NO_ENTRY;
++ pmb_list_add(pmbe);
++
++ spin_unlock_irq(&pmb_list_lock);
++}
++
++static void pmb_cache_dtor(void *pmb, kmem_cache_t *cachep, unsigned long flags)
++{
++ spin_lock_irq(&pmb_list_lock);
++ pmb_list_del(pmb);
++ spin_unlock_irq(&pmb_list_lock);
++}
++
++static int __init pmb_init(void)
++{
++ unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
++ unsigned int entry;
++
++ BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
++
++ pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry),
++ 0, 0, pmb_cache_ctor, pmb_cache_dtor);
++ BUG_ON(!pmb_cache);
++
++ jump_to_P2();
++
++ /*
++ * Ordering is important, P2 must be mapped in the PMB before we
++ * can set PMB.SE, and P1 must be mapped before we jump back to
++ * P1 space.
++ */
++ for (entry = 0; entry < nr_entries; entry++) {
++ struct pmb_entry *pmbe = pmb_init_map + entry;
++
++ __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry);
++ }
++
++ ctrl_outl(0, PMB_IRMCR);
++
++ /* PMB.SE and UB[7] */
++ ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
++
++ back_to_P1();
++
++ return 0;
++}
++arch_initcall(pmb_init);
++
++static int pmb_seq_show(struct seq_file *file, void *iter)
++{
++ int i;
++
++ seq_printf(file, "V: Valid, C: Cacheable, WT: Write-Through\n"
++ "CB: Copy-Back, B: Buffered, UB: Unbuffered\n");
++ seq_printf(file, "ety vpn ppn size flags\n");
++
++ for (i = 0; i < NR_PMB_ENTRIES; i++) {
++ unsigned long addr, data;
++ unsigned int size;
++ char *sz_str = NULL;
++
++ addr = ctrl_inl(mk_pmb_addr(i));
++ data = ctrl_inl(mk_pmb_data(i));
++
++ size = data & PMB_SZ_MASK;
++ sz_str = (size == PMB_SZ_16M) ? " 16MB":
++ (size == PMB_SZ_64M) ? " 64MB":
++ (size == PMB_SZ_128M) ? "128MB":
++ "512MB";
++
++ /* 02: V 0x88 0x08 128MB C CB B */
++ seq_printf(file, "%02d: %c 0x%02lx 0x%02lx %s %c %s %s\n",
++ i, ((addr & PMB_V) && (data & PMB_V)) ? 'V' : ' ',
++ (addr >> 24) & 0xff, (data >> 24) & 0xff,
++ sz_str, (data & PMB_C) ? 'C' : ' ',
++ (data & PMB_WT) ? "WT" : "CB",
++ (data & PMB_UB) ? "UB" : " B");
++ }
++
++ return 0;
++}
++
++static int pmb_debugfs_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmb_seq_show, NULL);
++}
++
++static struct file_operations pmb_debugfs_fops = {
++ .owner = THIS_MODULE,
++ .open = pmb_debugfs_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++static int __init pmb_debugfs_init(void)
++{
++ struct dentry *dentry;
++
++ dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmb_debugfs_fops);
++ if (IS_ERR(dentry))
++ return PTR_ERR(dentry);
++
++ return 0;
++}
++postcore_initcall(pmb_debugfs_init);
+diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c
+new file mode 100644
+index 0000000..73ec7f6
+--- /dev/null
++++ b/arch/sh/mm/tlb-flush.c
+@@ -0,0 +1,134 @@
++/*
++ * TLB flushing operations for SH with an MMU.
++ *
++ * Copyright (C) 1999 Niibe Yutaka
++ * Copyright (C) 2003 Paul Mundt
++ *
++ * 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/mm.h>
++#include <asm/mmu_context.h>
++#include <asm/tlbflush.h>
++
++void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
++{
++ if (vma->vm_mm && vma->vm_mm->context.id != NO_CONTEXT) {
++ unsigned long flags;
++ unsigned long asid;
++ unsigned long saved_asid = MMU_NO_ASID;
++
++ asid = vma->vm_mm->context.id & MMU_CONTEXT_ASID_MASK;
++ page &= PAGE_MASK;
++
++ local_irq_save(flags);
++ if (vma->vm_mm != current->mm) {
++ saved_asid = get_asid();
++ set_asid(asid);
++ }
++ __flush_tlb_page(asid, page);
++ if (saved_asid != MMU_NO_ASID)
++ set_asid(saved_asid);
++ local_irq_restore(flags);
++ }
++}
++
++void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end)
++{
++ struct mm_struct *mm = vma->vm_mm;
++
++ if (mm->context.id != NO_CONTEXT) {
++ unsigned long flags;
++ int size;
++
++ local_irq_save(flags);
++ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++ if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
++ mm->context.id = NO_CONTEXT;
++ if (mm == current->mm)
++ activate_context(mm);
++ } else {
++ unsigned long asid;
++ unsigned long saved_asid = MMU_NO_ASID;
++
++ asid = mm->context.id & MMU_CONTEXT_ASID_MASK;
++ start &= PAGE_MASK;
++ end += (PAGE_SIZE - 1);
++ end &= PAGE_MASK;
++ if (mm != current->mm) {
++ saved_asid = get_asid();
++ set_asid(asid);
++ }
++ while (start < end) {
++ __flush_tlb_page(asid, start);
++ start += PAGE_SIZE;
++ }
++ if (saved_asid != MMU_NO_ASID)
++ set_asid(saved_asid);
++ }
++ local_irq_restore(flags);
++ }
++}
++
++void flush_tlb_kernel_range(unsigned long start, unsigned long end)
++{
++ unsigned long flags;
++ int size;
++
++ local_irq_save(flags);
++ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++ if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
++ flush_tlb_all();
++ } else {
++ unsigned long asid;
++ unsigned long saved_asid = get_asid();
++
++ asid = init_mm.context.id & MMU_CONTEXT_ASID_MASK;
++ start &= PAGE_MASK;
++ end += (PAGE_SIZE - 1);
++ end &= PAGE_MASK;
++ set_asid(asid);
++ while (start < end) {
++ __flush_tlb_page(asid, start);
++ start += PAGE_SIZE;
++ }
++ set_asid(saved_asid);
++ }
++ local_irq_restore(flags);
++}
++
++void flush_tlb_mm(struct mm_struct *mm)
++{
++ /* Invalidate all TLB of this process. */
++ /* Instead of invalidating each TLB, we get new MMU context. */
++ if (mm->context.id != NO_CONTEXT) {
++ unsigned long flags;
++
++ local_irq_save(flags);
++ mm->context.id = NO_CONTEXT;
++ if (mm == current->mm)
++ activate_context(mm);
++ local_irq_restore(flags);
++ }
++}
++
++void flush_tlb_all(void)
++{
++ unsigned long flags, status;
++
++ /*
++ * Flush all the TLB.
++ *
++ * Write to the MMU control register's bit:
++ * TF-bit for SH-3, TI-bit for SH-4.
++ * It's same position, bit #2.
++ */
++ local_irq_save(flags);
++ status = ctrl_inl(MMUCR);
++ status |= 0x04;
++ ctrl_outl(status, MMUCR);
++ ctrl_barrier();
++ local_irq_restore(flags);
++}
+diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
+index 115b1b6..812b2d5 100644
+--- a/arch/sh/mm/tlb-sh4.c
++++ b/arch/sh/mm/tlb-sh4.c
+@@ -36,7 +36,6 @@ void update_mmu_cache(struct vm_area_str
+ unsigned long vpn;
+ struct page *page;
+ unsigned long pfn;
+- unsigned long ptea;
+
+ /* Ptrace may call this routine. */
+ if (vma && current->active_mm != vma->vm_mm)
+@@ -59,10 +58,11 @@ void update_mmu_cache(struct vm_area_str
+ ctrl_outl(vpn, MMU_PTEH);
+
+ pteval = pte_val(pte);
++
+ /* Set PTEA register */
+- /* TODO: make this look less hacky */
+- ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
+- ctrl_outl(ptea, MMU_PTEA);
++ if (cpu_data->flags & CPU_HAS_PTEA)
++ /* TODO: make this look less hacky */
++ ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
+
+ /* Set PTEL register */
+ pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile
+index 686738d..1f25d9b 100644
+--- a/arch/sh/oprofile/Makefile
++++ b/arch/sh/oprofile/Makefile
+@@ -7,7 +7,11 @@ DRIVER_OBJS = $(addprefix ../../../drive
+ timer_int.o )
+
+ profdrvr-y := op_model_null.o
++
++# SH7750-style performance counters exist across 7750/7750S and 7091.
++profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750S) := op_model_sh7750.o
+ profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750) := op_model_sh7750.o
++profdrvr-$(CONFIG_CPU_SUBTYPE_SH7091) := op_model_sh7750.o
+
+ oprofile-y := $(DRIVER_OBJS) $(profdrvr-y)
+
+diff --git a/arch/sh/tools/gen-mach-types b/arch/sh/tools/gen-mach-types
+index bb2b822..65161e3 100644
+--- a/arch/sh/tools/gen-mach-types
++++ b/arch/sh/tools/gen-mach-types
+@@ -20,8 +20,6 @@ END {
+ printf("#ifndef __ASM_SH_MACHTYPES_H\n");
+ printf("#define __ASM_SH_MACHTYPES_H\n");
+ printf("\n");
+- printf("#include <linux/config.h>\n");
+- printf("\n");
+ printf("/*\n");
+ printf(" * We'll use the following MACH_xxx defs for placeholders for the time\n");
+ printf(" * being .. these will all go away once sh_machtype is assigned per-board.\n");
+diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
+index 182fe90..ac57638 100644
+--- a/arch/sh/tools/mach-types
++++ b/arch/sh/tools/mach-types
+@@ -8,16 +8,15 @@
+ SE SH_SOLUTION_ENGINE
+ 7751SE SH_7751_SOLUTION_ENGINE
+ 7300SE SH_7300_SOLUTION_ENGINE
++7343SE SH_7343_SOLUTION_ENGINE
+ 73180SE SH_73180_SOLUTION_ENGINE
+ 7751SYSTEMH SH_7751_SYSTEMH
+ HP6XX SH_HP6XX
+ HD64461 HD64461
+ HD64465 HD64465
+-SH2000 SH_SH2000
+ SATURN SH_SATURN
+ DREAMCAST SH_DREAMCAST
+ BIGSUR SH_BIGSUR
+-ADX SH_ADX
+ MPC1211 SH_MPC1211
+ SNAPGEAR SH_SECUREEDGE5410
+ HS7751RVOIP SH_HS7751RVOIP
+@@ -25,4 +24,9 @@ RTS7751R2D SH_RTS7751R2D
+ EDOSK7705 SH_EDOSK7705
+ SH4202_MICRODEV SH_SH4202_MICRODEV
+ SH03 SH_SH03
+-
++LANDISK SH_LANDISK
++R7780RP SH_R7780RP
++R7780MP SH_R7780MP
++TITAN SH_TITAN
++SHMIN SH_SHMIN
++7710VOIPGW SH_7710VOIPGW
+diff --git a/arch/sh64/boot/compressed/misc.c b/arch/sh64/boot/compressed/misc.c
+index ee7a1b6..aea00c5 100644
+--- a/arch/sh64/boot/compressed/misc.c
++++ b/arch/sh64/boot/compressed/misc.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/shmedia/boot/compressed/misc.c
++ * arch/sh64/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
+index 48f2740..d81df57 100644
+--- a/arch/sh64/configs/cayman_defconfig
++++ b/arch/sh64/configs/cayman_defconfig
+@@ -1,49 +1,62 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.11
+-# Fri Feb 25 18:14:31 2005
++# Linux kernel version: 2.6.18
++# Tue Oct 3 13:30:51 2006
+ #
+ CONFIG_SUPERH=y
+ CONFIG_SUPERH64=y
+ CONFIG_MMU=y
+-CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_LOG_BUF_SHIFT=14
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-CONFIG_CLEAN_COMPILE=y
+ CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
+
+ #
+ # General setup
+ #
+ CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ # CONFIG_SYSVIPC is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+-# CONFIG_HOTPLUG is not set
+-CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
++# CONFIG_RELAY is not set
++CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -51,6 +64,27 @@ CONFIG_CC_ALIGN_JUMPS=0
+ # CONFIG_MODULES is not set
+
+ #
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++
++#
+ # System type
+ #
+ # CONFIG_SH_GENERIC is not set
+@@ -103,15 +137,23 @@ CONFIG_HEARTBEAT=y
+ CONFIG_HDSP253_LED=y
+ CONFIG_SH_DMA=y
+ CONFIG_PREEMPT=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_SPARSEMEM_STATIC is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
+
+ #
+ # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+ #
+-CONFIG_SUPERHYWAY=y
+ CONFIG_PCI=y
+ CONFIG_SH_PCIDMA_NONCOHERENT=y
+-CONFIG_PCI_LEGACY_PROC=y
+-CONFIG_PCI_NAMES=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
++# CONFIG_PCI_DEBUG is not set
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+@@ -119,10 +161,6 @@ CONFIG_PCI_NAMES=y
+ # CONFIG_PCCARD is not set
+
+ #
+-# PC-card bridges
+-#
+-
+-#
+ # PCI Hotplug Support
+ #
+ # CONFIG_HOTPLUG_PCI is not set
+@@ -135,6 +173,92 @@ CONFIG_BINFMT_ELF=y
+ # CONFIG_BINFMT_MISC is not set
+
+ #
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# 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 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_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC 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_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_IEEE80211 is not set
++
++#
+ # Device Drivers
+ #
+
+@@ -145,6 +269,12 @@ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
+
+ #
+ # Memory Technology Devices (MTD)
+@@ -163,7 +293,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=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
+@@ -176,18 +305,9 @@ CONFIG_BLK_DEV_LOOP=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_BLK_DEV_INITRD is not set
+-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
+
+ #
+@@ -198,7 +318,9 @@ CONFIG_IOSCHED_CFQ=y
+ #
+ # SCSI device support
+ #
++# CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++# CONFIG_SCSI_NETLINK is not set
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -209,6 +331,7 @@ CONFIG_BLK_DEV_SD=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
+@@ -218,15 +341,18 @@ CONFIG_SCSI_MULTI_LUN=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=y
+ # CONFIG_SCSI_FC_ATTRS is not set
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+ #
++# CONFIG_ISCSI_TCP is not set
+ # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+ # CONFIG_SCSI_3W_9XXX is not set
+ # CONFIG_SCSI_ACARD is not set
+@@ -234,40 +360,39 @@ CONFIG_SCSI_SPI_ATTRS=y
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
+ # CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_BUSLOGIC is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_HPTIOP 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
++# CONFIG_SCSI_STEX is not set
+ CONFIG_SCSI_SYM53C8XX_2=y
+ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
++CONFIG_SCSI_SYM53C8XX_MMIO=y
+ # CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_ISP is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+ # CONFIG_SCSI_NSP32 is not set
+ # CONFIG_SCSI_DEBUG is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ # CONFIG_MD is not set
+@@ -276,6 +401,9 @@ CONFIG_SCSI_QLA2XXX=y
+ # Fusion MPT device support
+ #
+ # CONFIG_FUSION is not set
++# CONFIG_FUSION_SPI is not set
++# CONFIG_FUSION_FC is not set
++# CONFIG_FUSION_SAS is not set
+
+ #
+ # IEEE 1394 (FireWire) support
+@@ -288,70 +416,8 @@ CONFIG_SCSI_QLA2XXX=y
+ # CONFIG_I2O is not set
+
+ #
+-# Networking support
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
++# Network device support
+ #
+-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 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=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
+@@ -364,6 +430,11 @@ CONFIG_NETDEVICES=y
+ # CONFIG_ARCNET is not set
+
+ #
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
+ # Ethernet (10 or 100Mbit)
+ #
+ CONFIG_NET_ETHERNET=y
+@@ -371,7 +442,9 @@ CONFIG_NET_ETHERNET=y
+ # CONFIG_STNIC is not set
+ # CONFIG_HAPPYMEAL is not set
+ # CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
+ # CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_SMC91X is not set
+
+ #
+ # Tulip family network device support
+@@ -385,6 +458,7 @@ CONFIG_TULIP=y
+ # CONFIG_DE4X5 is not set
+ # CONFIG_WINBOND_840 is not set
+ # CONFIG_DM9102 is not set
++# CONFIG_ULI526X is not set
+ # CONFIG_HP100 is not set
+ CONFIG_NET_PCI=y
+ # CONFIG_PCNET32 is not set
+@@ -416,15 +490,22 @@ CONFIG_NET_PCI=y
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+ # CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+ #
++# CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -447,6 +528,8 @@ CONFIG_NET_PCI=y
+ # CONFIG_NET_FC is not set
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
+
+ #
+ # ISDN subsystem
+@@ -462,6 +545,7 @@ CONFIG_NET_PCI=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -476,19 +560,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # CONFIG_INPUT_EVBUG is not set
+
+ #
+-# Input I/O drivers
+-#
+-# CONFIG_GAMEPORT is not set
+-CONFIG_SOUND_GAMEPORT=y
+-CONFIG_SERIO=y
+-CONFIG_SERIO_I8042=y
+-CONFIG_SERIO_SERPORT=y
+-# CONFIG_SERIO_CT82C710 is not set
+-# CONFIG_SERIO_PCIPS2 is not set
+-CONFIG_SERIO_LIBPS2=y
+-# CONFIG_SERIO_RAW is not set
+-
+-#
+ # Input Device Drivers
+ #
+ CONFIG_INPUT_KEYBOARD=y
+@@ -497,6 +568,7 @@ CONFIG_KEYBOARD_ATKBD=y
+ # CONFIG_KEYBOARD_LKKBD is not set
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ # CONFIG_MOUSE_SERIAL is not set
+@@ -506,11 +578,23 @@ CONFIG_MOUSE_PS2=y
+ # CONFIG_INPUT_MISC is not set
+
+ #
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_I8042=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_PCIPS2 is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_GAMEPORT is not set
++
++#
+ # Character devices
+ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -522,9 +606,11 @@ CONFIG_HW_CONSOLE=y
+ # Non-8250 serial port support
+ #
+ CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+ CONFIG_SERIAL_SH_SCI_CONSOLE=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
+@@ -551,7 +637,7 @@ CONFIG_WATCHDOG=y
+ #
+ # CONFIG_PCIPCWATCHDOG is not set
+ # CONFIG_WDTPCI is not set
+-# CONFIG_RTC is not set
++CONFIG_HW_RANDOM=y
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_DTLK is not set
+ # CONFIG_R3964 is not set
+@@ -564,14 +650,35 @@ CONFIG_WATCHDOG=y
+ # CONFIG_RAW_DRIVER is not set
+
+ #
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++
++#
+ # I2C support
+ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+ # Misc devices
+@@ -581,6 +688,7 @@ CONFIG_WATCHDOG=y
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -590,7 +698,13 @@ CONFIG_WATCHDOG=y
+ #
+ # Graphics support
+ #
++CONFIG_FIRMWARE_EDID=y
+ CONFIG_FB=y
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ CONFIG_FB_MODE_HELPERS=y
+ # CONFIG_FB_TILEBLITTING is not set
+ # CONFIG_FB_CIRRUS is not set
+@@ -599,9 +713,10 @@ CONFIG_FB_MODE_HELPERS=y
+ # CONFIG_FB_ASILIANT is not set
+ # CONFIG_FB_IMSTT is not set
+ # CONFIG_FB_EPSON1355 is not set
++# CONFIG_FB_S1D13XXX 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
+ # CONFIG_FB_RADEON is not set
+ # CONFIG_FB_ATY128 is not set
+ # CONFIG_FB_ATY is not set
+@@ -617,18 +732,20 @@ CONFIG_FB_KYRO=y
+ #
+ # Console display driver support
+ #
+-# CONFIG_VGA_CONSOLE is not set
+ CONFIG_DUMMY_CONSOLE=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+ CONFIG_FONTS=y
+ # CONFIG_FONT_8x8 is not set
+ 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
+@@ -650,12 +767,13 @@ CONFIG_LOGO_SUPERH_CLUT224=y
+ #
+ # USB support
+ #
+-# CONFIG_USB is not set
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB is not set
+
+ #
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+
+ #
+@@ -669,15 +787,51 @@ CONFIG_USB_ARCH_HAS_OHCI=y
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ 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=y
+ # CONFIG_EXT3_FS_POSIX_ACL is not set
+@@ -687,17 +841,18 @@ CONFIG_JBD=y
+ CONFIG_FS_MBCACHE=y
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+-
+-#
+-# XFS support
+-#
++# CONFIG_FS_POSIX_ACL is not set
+ # CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
+ CONFIG_MINIX_FS=y
+ CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -717,14 +872,14 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=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
++# CONFIG_TMPFS_POSIX_ACL is not set
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -748,12 +903,14 @@ CONFIG_RAMFS=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
+@@ -762,6 +919,7 @@ CONFIG_SUNRPC=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
+@@ -781,6 +939,7 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_SGI_PARTITION is not set
+ # CONFIG_ULTRIX_PARTITION is not set
+ # CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
+ # CONFIG_EFI_PARTITION is not set
+
+ #
+@@ -796,13 +955,32 @@ CONFIG_MSDOS_PARTITION=y
+ #
+ # Kernel hacking
+ #
+-CONFIG_DEBUG_KERNEL=y
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_LOG_BUF_SHIFT=14
++CONFIG_DETECT_SOFTLOCKUP=y
+ CONFIG_SCHEDSTATS=y
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
++CONFIG_FORCED_INLINING=y
++# CONFIG_RCU_TORTURE_TEST is not set
+ # CONFIG_EARLY_PRINTK is not set
+ # CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+ CONFIG_SH64_PROC_TLB=y
+@@ -824,14 +1002,12 @@ CONFIG_SH64_SR_WATCH=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+diff --git a/arch/sh64/kernel/alphanum.c b/arch/sh64/kernel/alphanum.c
+index 9079d1e..91707c1 100644
+--- a/arch/sh64/kernel/alphanum.c
++++ b/arch/sh64/kernel/alphanum.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh64/kernel/alpanum.c
++ * arch/sh64/kernel/alphanum.c
+ *
+ * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
+ *
+diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c
+index db475b7..525d0ec 100644
+--- a/arch/sh64/kernel/process.c
++++ b/arch/sh64/kernel/process.c
+@@ -20,261 +20,16 @@
+ /*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+-
+-/* Temporary flags/tests. All to be removed/undefined. BEGIN */
+-#define IDLE_TRACE
+-#define VM_SHOW_TABLES
+-#define VM_TEST_FAULT
+-#define VM_TEST_RTLBMISS
+-#define VM_TEST_WTLBMISS
+-
+-#undef VM_SHOW_TABLES
+-#undef IDLE_TRACE
+-/* Temporary flags/tests. All to be removed/undefined. END */
+-
+-#define __KERNEL_SYSCALLS__
+-#include <stdarg.h>
+-
+-#include <linux/kernel.h>
+-#include <linux/rwsem.h>
+ #include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+ #include <linux/ptrace.h>
+-#include <linux/slab.h>
+-#include <linux/vmalloc.h>
+-#include <linux/user.h>
+-#include <linux/a.out.h>
+-#include <linux/interrupt.h>
+-#include <linux/unistd.h>
+-#include <linux/delay.h>
+ #include <linux/reboot.h>
+ #include <linux/init.h>
+-
++#include <linux/module.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/processor.h> /* includes also <asm/registers.h> */
+-#include <asm/mmu_context.h>
+-#include <asm/elf.h>
+-#include <asm/page.h>
+-
+-#include <linux/irq.h>
+
+ struct task_struct *last_task_used_math = NULL;
+
+-#ifdef IDLE_TRACE
+-#ifdef VM_SHOW_TABLES
+-/* For testing */
+-static void print_PTE(long base)
+-{
+- int i, skip=0;
+- long long x, y, *p = (long long *) base;
+-
+- for (i=0; i< 512; i++, p++){
+- if (*p == 0) {
+- if (!skip) {
+- skip++;
+- printk("(0s) ");
+- }
+- } else {
+- skip=0;
+- x = (*p) >> 32;
+- y = (*p) & 0xffffffff;
+- printk("%08Lx%08Lx ", x, y);
+- if (!((i+1)&0x3)) printk("\n");
+- }
+- }
+-}
+-
+-/* For testing */
+-static void print_DIR(long base)
+-{
+- int i, skip=0;
+- long *p = (long *) base;
+-
+- for (i=0; i< 512; i++, p++){
+- if (*p == 0) {
+- if (!skip) {
+- skip++;
+- printk("(0s) ");
+- }
+- } else {
+- skip=0;
+- printk("%08lx ", *p);
+- if (!((i+1)&0x7)) printk("\n");
+- }
+- }
+-}
+-
+-/* For testing */
+-static void print_vmalloc_first_tables(void)
+-{
+-
+-#define PRESENT 0x800 /* Bit 11 */
+-
+- /*
+- * Do it really dirty by looking at raw addresses,
+- * raw offsets, no types. If we used pgtable/pgalloc
+- * macros/definitions we could hide potential bugs.
+- *
+- * Note that pointers are 32-bit for CDC.
+- */
+- long pgdt, pmdt, ptet;
+-
+- pgdt = (long) &swapper_pg_dir;
+- printk("-->PGD (0x%08lx):\n", pgdt);
+- print_DIR(pgdt);
+- printk("\n");
+-
+- /* VMALLOC pool is mapped at 0xc0000000, second (pointer) entry in PGD */
+- pgdt += 4;
+- pmdt = (long) (* (long *) pgdt);
+- if (!(pmdt & PRESENT)) {
+- printk("No PMD\n");
+- return;
+- } else pmdt &= 0xfffff000;
+-
+- printk("-->PMD (0x%08lx):\n", pmdt);
+- print_DIR(pmdt);
+- printk("\n");
+-
+- /* Get the pmdt displacement for 0xc0000000 */
+- pmdt += 2048;
+-
+- /* just look at first two address ranges ... */
+- /* ... 0xc0000000 ... */
+- ptet = (long) (* (long *) pmdt);
+- if (!(ptet & PRESENT)) {
+- printk("No PTE0\n");
+- return;
+- } else ptet &= 0xfffff000;
+-
+- printk("-->PTE0 (0x%08lx):\n", ptet);
+- print_PTE(ptet);
+- printk("\n");
+-
+- /* ... 0xc0001000 ... */
+- ptet += 4;
+- if (!(ptet & PRESENT)) {
+- printk("No PTE1\n");
+- return;
+- } else ptet &= 0xfffff000;
+- printk("-->PTE1 (0x%08lx):\n", ptet);
+- print_PTE(ptet);
+- printk("\n");
+-}
+-#else
+-#define print_vmalloc_first_tables()
+-#endif /* VM_SHOW_TABLES */
+-
+-static void test_VM(void)
+-{
+- void *a, *b, *c;
+-
+-#ifdef VM_SHOW_TABLES
+- printk("Initial PGD/PMD/PTE\n");
+-#endif
+- print_vmalloc_first_tables();
+-
+- printk("Allocating 2 bytes\n");
+- a = vmalloc(2);
+- print_vmalloc_first_tables();
+-
+- printk("Allocating 4100 bytes\n");
+- b = vmalloc(4100);
+- print_vmalloc_first_tables();
+-
+- printk("Allocating 20234 bytes\n");
+- c = vmalloc(20234);
+- print_vmalloc_first_tables();
+-
+-#ifdef VM_TEST_FAULT
+- /* Here you may want to fault ! */
+-
+-#ifdef VM_TEST_RTLBMISS
+- printk("Ready to fault upon read.\n");
+- if (* (char *) a) {
+- printk("RTLBMISSed on area a !\n");
+- }
+- printk("RTLBMISSed on area a !\n");
+-#endif
+-
+-#ifdef VM_TEST_WTLBMISS
+- printk("Ready to fault upon write.\n");
+- *((char *) b) = 'L';
+- printk("WTLBMISSed on area b !\n");
+-#endif
+-
+-#endif /* VM_TEST_FAULT */
+-
+- printk("Deallocating the 4100 byte chunk\n");
+- vfree(b);
+- print_vmalloc_first_tables();
+-
+- printk("Deallocating the 2 byte chunk\n");
+- vfree(a);
+- print_vmalloc_first_tables();
+-
+- printk("Deallocating the last chunk\n");
+- vfree(c);
+- print_vmalloc_first_tables();
+-}
+-
+-extern unsigned long volatile jiffies;
+-int once = 0;
+-unsigned long old_jiffies;
+-int pid = -1, pgid = -1;
+-
+-void idle_trace(void)
+-{
+-
+- _syscall0(int, getpid)
+- _syscall1(int, getpgid, int, pid)
+-
+- if (!once) {
+- /* VM allocation/deallocation simple test */
+- test_VM();
+- pid = getpid();
+-
+- printk("Got all through to Idle !!\n");
+- printk("I'm now going to loop forever ...\n");
+- printk("Any ! below is a timer tick.\n");
+- printk("Any . below is a getpgid system call from pid = %d.\n", pid);
+-
+-
+- old_jiffies = jiffies;
+- once++;
+- }
+-
+- if (old_jiffies != jiffies) {
+- old_jiffies = jiffies - old_jiffies;
+- switch (old_jiffies) {
+- case 1:
+- printk("!");
+- break;
+- case 2:
+- printk("!!");
+- break;
+- case 3:
+- printk("!!!");
+- break;
+- case 4:
+- printk("!!!!");
+- break;
+- default:
+- printk("(%d!)", (int) old_jiffies);
+- }
+- old_jiffies = jiffies;
+- }
+- pgid = getpgid(pid);
+- printk(".");
+-}
+-#else
+-#define idle_trace() do { } while (0)
+-#endif /* IDLE_TRACE */
+-
+ static int hlt_counter = 1;
+
+ #define HARD_IDLE_TIMEOUT (HZ / 3)
+@@ -323,7 +78,6 @@ void cpu_idle(void)
+ local_irq_disable();
+ while (!need_resched()) {
+ local_irq_enable();
+- idle_trace();
+ hlt();
+ local_irq_disable();
+ }
+@@ -622,6 +376,10 @@ void free_task_struct(struct task_struct
+ /*
+ * Create a kernel thread
+ */
++ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
++{
++ do_exit(fn(arg));
++}
+
+ /*
+ * This is the mechanism for creating a new kernel thread.
+@@ -633,19 +391,17 @@ void free_task_struct(struct task_struct
+ */
+ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+ {
+- /* A bit less processor dependent than older sh ... */
+- unsigned int reply;
++ struct pt_regs regs;
+
+-static __inline__ _syscall2(int,clone,unsigned long,flags,unsigned long,newsp)
+-static __inline__ _syscall1(int,exit,int,ret)
++ memset(®s, 0, sizeof(regs));
++ regs.regs[2] = (unsigned long)arg;
++ regs.regs[3] = (unsigned long)fn;
+
+- reply = clone(flags | CLONE_VM, 0);
+- if (!reply) {
+- /* Child */
+- reply = exit(fn(arg));
+- }
++ regs.pc = (unsigned long)kernel_thread_helper;
++ regs.sr = (1 << 30);
+
+- return reply;
++ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
++ ®s, 0, NULL, NULL);
+ }
+
+ /*
+diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c
+index 58ff7d5..ad0fa4e 100644
+--- a/arch/sh64/kernel/sys_sh64.c
++++ b/arch/sh64/kernel/sys_sh64.c
+@@ -32,6 +32,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
+ #include <asm/ptrace.h>
++#include <asm/unistd.h>
+
+ #define REG_3 3
+
+@@ -279,7 +280,25 @@ asmlinkage int sys_uname(struct old_utsn
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+- err=copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ return err?-EFAULT:0;
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
++ register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
++ register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
++ register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
++ __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)"
++ : "=r" (__sc0)
++ : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
++ __asm__ __volatile__ ("!dummy %0 %1 %2 %3"
++ : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
++ return __sc0;
++}
+diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
+index b8162e5..9c4a38a 100644
+--- a/arch/sh64/kernel/time.c
++++ b/arch/sh64/kernel/time.c
+@@ -107,8 +107,6 @@
+
+ #define TICK_SIZE (tick_nsec / 1000)
+
+-extern unsigned long wall_jiffies;
+-
+ static unsigned long tmu_base, rtc_base;
+ unsigned long cprc_base;
+
+@@ -194,13 +192,6 @@ void do_gettimeofday(struct timeval *tv)
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = usecs_since_tick();
+- {
+- unsigned long lost = jiffies - wall_jiffies;
+-
+- if (lost)
+- usec += lost * (1000000 / HZ);
+- }
+-
+ sec = xtime.tv_sec;
+ usec += xtime.tv_nsec / 1000;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+@@ -229,8 +220,7 @@ int do_settimeofday(struct timespec *tv)
+ * wall time. Discover what correction gettimeofday() would have
+ * made, and then undo it!
+ */
+- nsec -= 1000 * (usecs_since_tick() +
+- (jiffies - wall_jiffies) * (1000000 / HZ));
++ nsec -= 1000 * usecs_since_tick();
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+@@ -298,7 +288,7 @@ static inline void do_timer_interrupt(in
+ asm ("getcon cr62, %0" : "=r" (current_ctc));
+ ctc_last_interrupt = (unsigned long) current_ctc;
+
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
+index a8fcc3a..95c4d75 100644
+--- a/arch/sh64/kernel/vmlinux.lds.S
++++ b/arch/sh64/kernel/vmlinux.lds.S
+@@ -108,13 +108,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : C_PHYS(.initcall.init) {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c
+index 53c1cab..0e8a742 100644
+--- a/arch/sh64/lib/c-checksum.c
++++ b/arch/sh64/lib/c-checksum.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh/lib/csum_parial.c
++ * arch/sh64/lib/c-checksum.c
+ *
+ * This file contains network checksum routines that are better done
+ * in an architecture-specific manner due to speed..
+diff --git a/arch/sh64/mach-cayman/led.c b/arch/sh64/mach-cayman/led.c
+index 8b3cc4c..b4e122f 100644
+--- a/arch/sh64/mach-cayman/led.c
++++ b/arch/sh64/mach-cayman/led.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh64/kernel/led_cayman.c
++ * arch/sh64/mach-cayman/led.c
+ *
+ * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
+ *
+diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
+index f08d0ea..8e2f6c2 100644
+--- a/arch/sh64/mm/fault.c
++++ b/arch/sh64/mm/fault.c
+@@ -277,7 +277,7 @@ bad_area:
+ show_regs(regs);
+ #endif
+ }
+- if (tsk->pid == 1) {
++ if (is_init(tsk)) {
+ panic("INIT had user mode bad_area\n");
+ }
+ tsk->thread.address = address;
+@@ -319,14 +319,14 @@ no_context:
+ * us unable to handle the page fault gracefully.
+ */
+ out_of_memory:
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ panic("INIT out of memory\n");
+ yield();
+ goto survive;
+ }
+ printk("fault:Out of memory\n");
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c
+index 1169757..83295bd 100644
+--- a/arch/sh64/mm/init.c
++++ b/arch/sh64/mm/init.c
+@@ -110,7 +110,7 @@ void show_mem(void)
+ */
+ void __init paging_init(void)
+ {
+- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+ pgd_init((unsigned long)swapper_pg_dir);
+ pgd_init((unsigned long)swapper_pg_dir +
+diff --git a/arch/sh64/oprofile/op_model_null.c b/arch/sh64/oprofile/op_model_null.c
+index a845b08..a750ea1 100644
+--- a/arch/sh64/oprofile/op_model_null.c
++++ b/arch/sh64/oprofile/op_model_null.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/sh/oprofile/op_model_null.c
++ * arch/sh64/oprofile/op_model_null.c
+ *
+ * Copyright (C) 2003 Paul Mundt
+ *
+diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
+index 9431e96..2f96610 100644
+--- a/arch/sparc/Kconfig
++++ b/arch/sparc/Kconfig
+@@ -289,6 +289,13 @@ endmenu
+
+ source "fs/Kconfig"
+
++menu "Instrumentation Support"
++ depends on EXPERIMENTAL
++
++source "arch/sparc/oprofile/Kconfig"
++
++endmenu
++
+ source "arch/sparc/Kconfig.debug"
+
+ source "security/Kconfig"
+diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
+index 4cdbb2d..f33c381 100644
+--- a/arch/sparc/Makefile
++++ b/arch/sparc/Makefile
+@@ -30,6 +30,8 @@ HEAD_Y := $(head-y)
+ core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/
+ libs-y += arch/sparc/prom/ arch/sparc/lib/
+
++drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/
++
+ # Export what is needed by arch/sparc/boot/Makefile
+ # Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-)
+ INIT_Y := $(patsubst %/, %/built-in.o, $(init-y))
+diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
+index 81c0cbd..ba58c3a 100644
+--- a/arch/sparc/kernel/ebus.c
++++ b/arch/sparc/kernel/ebus.c
+@@ -237,12 +237,12 @@ void __init fill_ebus_device(struct devi
+ dev->ofdev.node = dp;
+ dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
+ dev->ofdev.dev.bus = &ebus_bus_type;
+- strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
+
+ /* Register with core */
+ if (of_device_register(&dev->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+- dev->ofdev.dev.bus_id);
++ dp->path_component_name);
+
+ if ((dp = dp->child) != NULL) {
+ dev->children = (struct linux_ebus_child *)
+@@ -277,7 +277,7 @@ void __init ebus_init(void)
+ struct pci_dev *pdev;
+ struct pcidev_cookie *cookie;
+ struct device_node *dp;
+- unsigned long addr, *base;
++ struct resource *p;
+ unsigned short pci_command;
+ int len, reg, nreg;
+ int num_ebus = 0;
+@@ -321,24 +321,23 @@ void __init ebus_init(void)
+ }
+ nreg = len / sizeof(struct linux_prom_pci_registers);
+
+- base = &ebus->self->resource[0].start;
++ p = &ebus->self->resource[0];
+ for (reg = 0; reg < nreg; reg++) {
+ if (!(regs[reg].which_io & 0x03000000))
+ continue;
+
+- addr = regs[reg].phys_lo;
+- *base++ = addr;
++ (p++)->start = regs[reg].phys_lo;
+ }
+
+ ebus->ofdev.node = dp;
+ ebus->ofdev.dev.parent = &pdev->dev;
+ ebus->ofdev.dev.bus = &ebus_bus_type;
+- strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
+
+ /* Register with core */
+ if (of_device_register(&ebus->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+- ebus->ofdev.dev.bus_id);
++ dp->path_component_name);
+
+
+ nd = dp->child;
+diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
+index a4edff4..831f540 100644
+--- a/arch/sparc/kernel/entry.S
++++ b/arch/sparc/kernel/entry.S
+@@ -32,13 +32,12 @@
+ #include <asm/mxcc.h>
+ #include <asm/thread_info.h>
+ #include <asm/param.h>
++#include <asm/unistd.h>
+
+ #include <asm/asmmacro.h>
+
+ #define curptr g6
+
+-#define NR_SYSCALLS 300 /* Each OS is different... */
+-
+ /* These are just handy. */
+ #define _SV save %sp, -STACKFRAME_SZ, %sp
+ #define _RS restore
+diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
+index 8654b44..54d51b4 100644
+--- a/arch/sparc/kernel/ioport.c
++++ b/arch/sparc/kernel/ioport.c
+@@ -25,7 +25,6 @@
+ * <zaitcev> Sounds reasonable
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+@@ -508,6 +507,7 @@ void __init sbus_arch_bus_ranges_init(st
+
+ void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
+ {
++#ifndef CONFIG_SUN4
+ struct device_node *parent = dp->parent;
+
+ if (sparc_cpu_model != sun4d &&
+@@ -524,6 +524,7 @@ void __init sbus_setup_iommu(struct sbus
+
+ iounit_init(dp->node, parent->node, sbus);
+ }
++#endif
+ }
+
+ void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
+diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
+index 72f0201..c8cb211 100644
+--- a/arch/sparc/kernel/irq.c
++++ b/arch/sparc/kernel/irq.c
+@@ -46,6 +46,7 @@
+ #include <asm/pgtable.h>
+ #include <asm/pcic.h>
+ #include <asm/cacheflush.h>
++#include <asm/irq_regs.h>
+
+ #ifdef CONFIG_SMP
+ #define SMP_NOP2 "nop; nop;\n\t"
+@@ -133,8 +134,8 @@ static void irq_panic(void)
+ prom_halt();
+ }
+
+-void (*sparc_init_timers)(irqreturn_t (*)(int, void *,struct pt_regs *)) =
+- (void (*)(irqreturn_t (*)(int, void *,struct pt_regs *))) irq_panic;
++void (*sparc_init_timers)(irq_handler_t ) =
++ (void (*)(irq_handler_t )) irq_panic;
+
+ /*
+ * Dave Redman (djhr at tadpole.co.uk)
+@@ -319,12 +320,14 @@ void unexpected_irq(int irq, void *dev_i
+
+ void handler_irq(int irq, struct pt_regs * regs)
+ {
++ struct pt_regs *old_regs;
+ struct irqaction * action;
+ int cpu = smp_processor_id();
+ #ifdef CONFIG_SMP
+ extern void smp4m_irq_rotate(int cpu);
+ #endif
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+ disable_pil_irq(irq);
+ #ifdef CONFIG_SMP
+@@ -338,27 +341,31 @@ void handler_irq(int irq, struct pt_regs
+ do {
+ if (!action || !action->handler)
+ unexpected_irq(irq, NULL, regs);
+- action->handler(irq, action->dev_id, regs);
++ action->handler(irq, action->dev_id);
+ action = action->next;
+ } while (action);
+ sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS;
+ enable_pil_irq(irq);
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ #ifdef CONFIG_BLK_DEV_FD
+-extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern void floppy_interrupt(int irq, void *dev_id);
+
+ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ int cpu = smp_processor_id();
+
++ old_regs = set_irq_regs(regs);
+ disable_pil_irq(irq);
+ irq_enter();
+ kstat_cpu(cpu).irqs[irq]++;
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ irq_exit();
+ enable_pil_irq(irq);
++ set_irq_regs(old_regs);
+ // XXX Eek, it's totally changed with preempt_count() and such
+ // if (softirq_pending(cpu))
+ // do_softirq();
+@@ -369,7 +376,7 @@ void sparc_floppy_irq(int irq, void *dev
+ * thus no sharing possible.
+ */
+ int request_fast_irq(unsigned int irq,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irqflags, const char *devname)
+ {
+ struct irqaction *action;
+@@ -468,7 +475,7 @@ out:
+ }
+
+ int request_irq(unsigned int irq,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irqflags, const char * devname, void *dev_id)
+ {
+ struct irqaction * action, **actionp;
+@@ -478,7 +485,7 @@ int request_irq(unsigned int irq,
+
+ if (sparc_cpu_model == sun4d) {
+ extern int sun4d_request_irq(unsigned int,
+- irqreturn_t (*)(int, void *, struct pt_regs *),
++ irq_handler_t ,
+ unsigned long, const char *, void *);
+ return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
+ }
+diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
+index 97bf87e..46200c4 100644
+--- a/arch/sparc/kernel/of_device.c
++++ b/arch/sparc/kernel/of_device.c
+@@ -1,4 +1,3 @@
+-#include <linux/config.h>
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -652,7 +651,7 @@ build_resources:
+ if (!parent)
+ strcpy(op->dev.bus_id, "root");
+ else
+- strcpy(op->dev.bus_id, dp->path_component_name);
++ sprintf(op->dev.bus_id, "%08x", dp->node);
+
+ if (of_device_register(op)) {
+ printk("%s: Could not register of device.\n",
+diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
+index bfd31aa..207f1b6 100644
+--- a/arch/sparc/kernel/pcic.c
++++ b/arch/sparc/kernel/pcic.c
+@@ -34,6 +34,7 @@
+ #include <asm/pcic.h>
+ #include <asm/timer.h>
+ #include <asm/uaccess.h>
++#include <asm/irq_regs.h>
+
+
+ unsigned int pcic_pin_to_irq(unsigned int pin, char *name);
+@@ -708,13 +709,13 @@ static void pcic_clear_clock_irq(void)
+ pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT);
+ }
+
+-static irqreturn_t pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
++static irqreturn_t pcic_timer_handler (int irq, void *h)
+ {
+ write_seqlock(&xtime_lock); /* Dummy, to show that we remember */
+ pcic_clear_clock_irq();
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+@@ -765,8 +766,6 @@ static __inline__ unsigned long do_getti
+ return count;
+ }
+
+-extern unsigned long wall_jiffies;
+-
+ static void pci_do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+@@ -775,26 +774,17 @@ static void pci_do_gettimeofday(struct t
+ unsigned long max_ntp_tick = tick_usec - tickadj;
+
+ do {
+- unsigned long lost;
+-
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = do_gettimeoffset();
+- lost = jiffies - wall_jiffies;
+
+ /*
+ * If time_adjust is negative then NTP is slowing the clock
+ * so make sure not to go into next possible interval.
+ * Better to lose some accuracy than have time go backwards..
+ */
+- if (unlikely(time_adjust < 0)) {
++ if (unlikely(time_adjust < 0))
+ usec = min(usec, max_ntp_tick);
+
+- if (lost)
+- usec += lost * max_ntp_tick;
+- }
+- else if (unlikely(lost))
+- usec += lost * tick_usec;
+-
+ sec = xtime.tv_sec;
+ usec += (xtime.tv_nsec / 1000);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+@@ -819,8 +809,7 @@ static int pci_do_settimeofday(struct ti
+ * wall time. Discover what correction gettimeofday() would have
+ * made, and then undo it!
+ */
+- tv->tv_nsec -= 1000 * (do_gettimeoffset() +
+- (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));
++ tv->tv_nsec -= 1000 * do_gettimeoffset();
+ while (tv->tv_nsec < 0) {
+ tv->tv_nsec += NSEC_PER_SEC;
+ tv->tv_sec--;
+diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
+index 4ca9e5f..2cc302b 100644
+--- a/arch/sparc/kernel/prom.c
++++ b/arch/sparc/kernel/prom.c
+@@ -243,7 +243,7 @@ int of_set_property(struct device_node *
+ void *old_val = prop->value;
+ int ret;
+
+- ret = prom_setprop(dp->node, name, val, len);
++ ret = prom_setprop(dp->node, (char *) name, val, len);
+ err = -EINVAL;
+ if (ret >= 0) {
+ prop->value = new_val;
+@@ -477,7 +477,10 @@ static struct property * __init build_on
+ p->length = 0;
+ } else {
+ p->value = prom_early_alloc(p->length + 1);
+- prom_getproperty(node, p->name, p->value, p->length);
++ len = prom_getproperty(node, p->name, p->value,
++ p->length);
++ if (len <= 0)
++ p->length = 0;
+ ((unsigned char *)p->value)[p->length] = '\0';
+ }
+ }
+diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
+index 0251cab..383526a 100644
+--- a/arch/sparc/kernel/setup.c
++++ b/arch/sparc/kernel/setup.c
+@@ -103,7 +103,6 @@ void prom_sync_me(void)
+
+ unsigned int boot_flags __initdata = 0;
+ #define BOOTME_DEBUG 0x1
+-#define BOOTME_SINGLE 0x2
+
+ /* Exported for mm/init.c:paging_init. */
+ unsigned long cmdline_memory_size __initdata = 0;
+@@ -121,16 +120,6 @@ static struct console prom_debug_console
+ .index = -1,
+ };
+
+-int obp_system_intr(void)
+-{
+- if (boot_flags & BOOTME_DEBUG) {
+- printk("OBP: system interrupted\n");
+- prom_halt();
+- return 1;
+- }
+- return 0;
+-}
+-
+ /*
+ * Process kernel command line switches that are specific to the
+ * SPARC or that require special low-level processing.
+@@ -142,7 +131,6 @@ static void __init process_switch(char c
+ boot_flags |= BOOTME_DEBUG;
+ break;
+ case 's':
+- boot_flags |= BOOTME_SINGLE;
+ break;
+ case 'h':
+ prom_printf("boot_flags_init: Halt!\n");
+diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
+index 4d441a5..33dadd9 100644
+--- a/arch/sparc/kernel/sparc_ksyms.c
++++ b/arch/sparc/kernel/sparc_ksyms.c
+@@ -87,6 +87,7 @@ extern void ___set_bit(void);
+ extern void ___clear_bit(void);
+ extern void ___change_bit(void);
+ extern void ___rw_read_enter(void);
++extern void ___rw_read_try(void);
+ extern void ___rw_read_exit(void);
+ extern void ___rw_write_enter(void);
+
+@@ -104,8 +105,9 @@ extern unsigned _Urem(unsigned, unsigned
+ EXPORT_SYMBOL(sparc_cpu_model);
+ EXPORT_SYMBOL(kernel_thread);
+ #ifdef CONFIG_SMP
+-// XXX find what uses (or used) these.
++// XXX find what uses (or used) these. AV: see asm/spinlock.h
+ EXPORT_SYMBOL(___rw_read_enter);
++EXPORT_SYMBOL(___rw_read_try);
+ EXPORT_SYMBOL(___rw_read_exit);
+ EXPORT_SYMBOL(___rw_write_enter);
+ #endif
+diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
+index 4be2c86..009e891 100644
+--- a/arch/sparc/kernel/sun4c_irq.c
++++ b/arch/sparc/kernel/sun4c_irq.c
+@@ -154,7 +154,7 @@ static void sun4c_load_profile_irq(int c
+ /* Errm.. not sure how to do this.. */
+ }
+
+-static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
++static void __init sun4c_init_timers(irq_handler_t counter_fn)
+ {
+ int irq;
+
+diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
+index 74eed97..d4f9da8 100644
+--- a/arch/sparc/kernel/sun4d_irq.c
++++ b/arch/sparc/kernel/sun4d_irq.c
+@@ -38,6 +38,7 @@
+ #include <asm/sbus.h>
+ #include <asm/sbi.h>
+ #include <asm/cacheflush.h>
++#include <asm/irq_regs.h>
+
+ /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
+ /* #define DISTRIBUTE_IRQS */
+@@ -198,6 +199,7 @@ extern void unexpected_irq(int, void *,
+
+ void sun4d_handler_irq(int irq, struct pt_regs * regs)
+ {
++ struct pt_regs *old_regs;
+ struct irqaction * action;
+ int cpu = smp_processor_id();
+ /* SBUS IRQ level (1 - 7) */
+@@ -208,6 +210,7 @@ void sun4d_handler_irq(int irq, struct p
+
+ cc_set_iclr(1 << irq);
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+ kstat_cpu(cpu).irqs[irq]++;
+ if (!sbusl) {
+@@ -215,7 +218,7 @@ void sun4d_handler_irq(int irq, struct p
+ if (!action)
+ unexpected_irq(irq, NULL, regs);
+ do {
+- action->handler(irq, action->dev_id, regs);
++ action->handler(irq, action->dev_id);
+ action = action->next;
+ } while (action);
+ } else {
+@@ -242,7 +245,7 @@ void sun4d_handler_irq(int irq, struct p
+ if (!action)
+ unexpected_irq(irq, NULL, regs);
+ do {
+- action->handler(irq, action->dev_id, regs);
++ action->handler(irq, action->dev_id);
+ action = action->next;
+ } while (action);
+ release_sbi(SBI2DEVID(sbino), slot);
+@@ -250,6 +253,7 @@ void sun4d_handler_irq(int irq, struct p
+ }
+ }
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
+@@ -272,7 +276,7 @@ unsigned int sun4d_sbint_to_irq(struct s
+ }
+
+ int sun4d_request_irq(unsigned int irq,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irqflags, const char * devname, void *dev_id)
+ {
+ struct irqaction *action, *tmp = NULL, **actionp;
+@@ -466,7 +470,7 @@ static void sun4d_load_profile_irq(int c
+ bw_set_prof_limit(cpu, limit);
+ }
+
+-static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
++static void __init sun4d_init_timers(irq_handler_t counter_fn)
+ {
+ int irq;
+ int cpu;
+diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
+index 3ff4edd..c80ea61 100644
+--- a/arch/sparc/kernel/sun4d_smp.c
++++ b/arch/sparc/kernel/sun4d_smp.c
+@@ -23,6 +23,7 @@
+
+ #include <asm/ptrace.h>
+ #include <asm/atomic.h>
++#include <asm/irq_regs.h>
+
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+@@ -369,10 +370,12 @@ void smp4d_message_pass(int target, int
+
+ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ int cpu = hard_smp4d_processor_id();
+ static int cpu_tick[NR_CPUS];
+ static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
+
++ old_regs = set_irq_regs(regs);
+ bw_get_prof_limit(cpu);
+ bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */
+
+@@ -384,7 +387,7 @@ void smp4d_percpu_timer_interrupt(struct
+ show_leds(cpu);
+ }
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+
+ if(!--prof_counter(cpu)) {
+ int user = user_mode(regs);
+@@ -395,6 +398,7 @@ void smp4d_percpu_timer_interrupt(struct
+
+ prof_counter(cpu) = prof_multiplier(cpu);
+ }
++ set_irq_regs(old_regs);
+ }
+
+ extern unsigned int lvl14_resolution;
+diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
+index 7cefa30..a654c16 100644
+--- a/arch/sparc/kernel/sun4m_irq.c
++++ b/arch/sparc/kernel/sun4m_irq.c
+@@ -228,7 +228,7 @@ static void sun4m_load_profile_irq(int c
+ sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+ }
+
+-static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
++static void __init sun4m_init_timers(irq_handler_t counter_fn)
+ {
+ int reg_count, irq, cpu;
+ struct linux_prom_registers cnt_regs[PROMREG_MAX];
+diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
+index 7d4a649..e2d9c01 100644
+--- a/arch/sparc/kernel/sun4m_smp.c
++++ b/arch/sparc/kernel/sun4m_smp.c
+@@ -19,6 +19,7 @@
+ #include <linux/profile.h>
+ #include <asm/cacheflush.h>
+ #include <asm/tlbflush.h>
++#include <asm/irq_regs.h>
+
+ #include <asm/ptrace.h>
+ #include <asm/atomic.h>
+@@ -353,11 +354,14 @@ void smp4m_cross_call_irq(void)
+
+ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs;
+ int cpu = smp_processor_id();
+
++ old_regs = set_irq_regs(regs);
++
+ clear_profile_irq(cpu);
+
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+
+ if(!--prof_counter(cpu)) {
+ int user = user_mode(regs);
+@@ -368,6 +372,7 @@ void smp4m_percpu_timer_interrupt(struct
+
+ prof_counter(cpu) = prof_multiplier(cpu);
+ }
++ set_irq_regs(old_regs);
+ }
+
+ extern unsigned int lvl14_resolution;
+diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c
+index c09afd9..01b07bb 100644
+--- a/arch/sparc/kernel/sys_solaris.c
++++ b/arch/sparc/kernel/sys_solaris.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/sparc/sys_solaris.c
++ * linux/arch/sparc/kernel/sys_solaris.c
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel at nuclecu.unam.mx)
+ */
+diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
+index 896863f..a954a0c 100644
+--- a/arch/sparc/kernel/sys_sparc.c
++++ b/arch/sparc/kernel/sys_sparc.c
+@@ -24,6 +24,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
++#include <asm/unistd.h>
+
+ /* #define DEBUG_UNIMP_SYSCALL */
+
+@@ -475,16 +476,38 @@ asmlinkage int sys_getdomainname(char __
+
+ down_read(&uts_sem);
+
+- nlen = strlen(system_utsname.domainname) + 1;
++ nlen = strlen(utsname()->domainname) + 1;
+ err = -EINVAL;
+ if (nlen > len)
+ goto out;
+
+ err = -EFAULT;
+- if (!copy_to_user(name, system_utsname.domainname, nlen))
++ if (!copy_to_user(name, utsname()->domainname, nlen))
+ err = 0;
+
+ out:
+ up_read(&uts_sem);
+ return err;
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ long __res;
++ register long __g1 __asm__ ("g1") = __NR_execve;
++ register long __o0 __asm__ ("o0") = (long)(filename);
++ register long __o1 __asm__ ("o1") = (long)(argv);
++ register long __o2 __asm__ ("o2") = (long)(envp);
++ asm volatile ("t 0x10\n\t"
++ "bcc 1f\n\t"
++ "mov %%o0, %0\n\t"
++ "sub %%g0, %%o0, %0\n\t"
++ "1:\n\t"
++ : "=r" (__res), "=&r" (__o0)
++ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
++ : "cc");
++ return __res;
++}
+diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
+index aa0fb2e..6f3ac54 100644
+--- a/arch/sparc/kernel/sys_sunos.c
++++ b/arch/sparc/kernel/sys_sunos.c
+@@ -325,21 +325,25 @@ struct sunos_dirent_callback {
+ #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+ static int sunos_filldir(void * __buf, const char * name, int namlen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct sunos_dirent __user *dirent;
+ struct sunos_dirent_callback * buf = __buf;
++ unsigned long d_ino;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->curr;
+ buf->previous = dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ copy_to_user(dirent->d_name, name, namlen);
+@@ -406,19 +410,23 @@ struct sunos_direntry_callback {
+ };
+
+ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct sunos_direntry __user *dirent;
+ struct sunos_direntry_callback *buf = __buf;
++ unsigned long d_ino;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ dirent = buf->curr;
+ buf->previous = dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ copy_to_user(dirent->d_name, name, namlen);
+@@ -483,13 +491,18 @@ asmlinkage int sunos_uname(struct sunos_
+ {
+ int ret;
+ down_read(&uts_sem);
+- ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
++ ret = copy_to_user(&name->sname[0], &utsname()->sysname[0],
++ sizeof(name->sname) - 1);
+ if (!ret) {
+- ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
++ ret |= __copy_to_user(&name->nname[0], &utsname()->nodename[0],
++ sizeof(name->nname) - 1);
+ ret |= __put_user('\0', &name->nname[8]);
+- ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+- ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+- ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
++ ret |= __copy_to_user(&name->rel[0], &utsname()->release[0],
++ sizeof(name->rel) - 1);
++ ret |= __copy_to_user(&name->ver[0], &utsname()->version[0],
++ sizeof(name->ver) - 1);
++ ret |= __copy_to_user(&name->mach[0], &utsname()->machine[0],
++ sizeof(name->mach) - 1);
+ }
+ up_read(&uts_sem);
+ return ret ? -EFAULT : 0;
+diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
+index 10df38e..ea75ca5 100644
+--- a/arch/sparc/kernel/systbls.S
++++ b/arch/sparc/kernel/systbls.S
+@@ -78,7 +78,7 @@ sys_call_table:
+ /*285*/ .long sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64
+ /*290*/ .long sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
+ /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
+-/*300*/ .long sys_set_robust_list, sys_get_robust_list
++/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages
+
+ #ifdef CONFIG_SUNOS_EMUL
+ /* Now the SunOS syscall table. */
+@@ -190,6 +190,7 @@ sunos_sys_table:
+ /*290*/ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+- .long sunos_nosys, sunos_nosys, sunos_nosys
++ .long sunos_nosys
++/*300*/ .long sunos_nosys, sunos_nosys, sunos_nosys
+
+ #endif
+diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
+index d3b4daa..f1a7bd1 100644
+--- a/arch/sparc/kernel/tick14.c
++++ b/arch/sparc/kernel/tick14.c
+@@ -55,7 +55,7 @@ void install_obp_ticker(void)
+ linux_lvl14[3] = obp_lvl14[3];
+ }
+
+-void claim_ticker14(irqreturn_t (*handler)(int, void *, struct pt_regs *),
++void claim_ticker14(irq_handler_t handler,
+ int irq_nr, unsigned int timeout )
+ {
+ int cpu = smp_processor_id();
+diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
+index 845081b..6c7aa51 100644
+--- a/arch/sparc/kernel/time.c
++++ b/arch/sparc/kernel/time.c
+@@ -42,8 +42,7 @@
+ #include <asm/page.h>
+ #include <asm/pcic.h>
+ #include <asm/of_device.h>
+-
+-extern unsigned long wall_jiffies;
++#include <asm/irq_regs.h>
+
+ DEFINE_SPINLOCK(rtc_lock);
+ enum sparc_clock_type sp_clock_typ;
+@@ -96,6 +95,8 @@ unsigned long profile_pc(struct pt_regs
+ return pc;
+ }
+
++EXPORT_SYMBOL(profile_pc);
++
+ __volatile__ unsigned int *master_l10_counter;
+ __volatile__ unsigned int *master_l10_limit;
+
+@@ -106,13 +107,13 @@ __volatile__ unsigned int *master_l10_li
+
+ #define TICK_SIZE (tick_nsec / 1000)
+
+-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++irqreturn_t timer_interrupt(int irq, void *dev_id)
+ {
+ /* last time the cmos clock got updated */
+ static long last_rtc_update;
+
+ #ifndef CONFIG_SMP
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ #endif
+
+ /* Protect counter clear so that do_gettimeoffset works */
+@@ -128,9 +129,9 @@ irqreturn_t timer_interrupt(int irq, voi
+ #endif
+ clear_clock_irq();
+
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+
+
+@@ -449,7 +450,7 @@ unsigned long long sched_clock(void)
+
+ /* Ok, my cute asm atomicity trick doesn't work anymore.
+ * There are just too many variables that need to be protected
+- * now (both members of xtime, wall_jiffies, et al.)
++ * now (both members of xtime, et al.)
+ */
+ void do_gettimeofday(struct timeval *tv)
+ {
+@@ -459,26 +460,17 @@ void do_gettimeofday(struct timeval *tv)
+ unsigned long max_ntp_tick = tick_usec - tickadj;
+
+ do {
+- unsigned long lost;
+-
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = do_gettimeoffset();
+- lost = jiffies - wall_jiffies;
+
+ /*
+ * If time_adjust is negative then NTP is slowing the clock
+ * so make sure not to go into next possible interval.
+ * Better to lose some accuracy than have time go backwards..
+ */
+- if (unlikely(time_adjust < 0)) {
++ if (unlikely(time_adjust < 0))
+ usec = min(usec, max_ntp_tick);
+
+- if (lost)
+- usec += lost * max_ntp_tick;
+- }
+- else if (unlikely(lost))
+- usec += lost * tick_usec;
+-
+ sec = xtime.tv_sec;
+ usec += (xtime.tv_nsec / 1000);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+@@ -521,8 +513,7 @@ static int sbus_do_settimeofday(struct t
+ * wall time. Discover what correction gettimeofday() would have
+ * made, and then undo it!
+ */
+- nsec -= 1000 * (do_gettimeoffset() +
+- (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));
++ nsec -= 1000 * do_gettimeoffset();
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
+index 346c19a..5cc5ff7 100644
+--- a/arch/sparc/kernel/vmlinux.lds.S
++++ b/arch/sparc/kernel/vmlinux.lds.S
+@@ -36,11 +36,11 @@ SECTIONS
+
+ . = ALIGN(4096);
+ __init_begin = .;
++ _sinittext = .;
+ .init.text : {
+- _sinittext = .;
+ *(.init.text)
+- _einittext = .;
+ }
++ _einittext = .;
+ __init_text_end = .;
+ .init.data : { *(.init.data) }
+ . = ALIGN(16);
+@@ -49,13 +49,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S
+index 577505b..ef095b6 100644
+--- a/arch/sparc/lib/copy_user.S
++++ b/arch/sparc/lib/copy_user.S
+@@ -14,6 +14,7 @@
+ #include <asm/ptrace.h>
+ #include <asm/asmmacro.h>
+ #include <asm/page.h>
++#include <asm/thread_info.h>
+
+ /* Work around cpp -rob */
+ #define ALLOC #alloc
+@@ -366,6 +367,9 @@ fixupretl:
+ blu 1f
+ cmp %o1, %g1
+ bgeu 1f
++ ld [%g6 + TI_PREEMPT], %g1
++ cmp %g1, 0
++ bne 1f
+ nop
+ save %sp, -64, %sp
+ mov %i0, %o0
+diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S
+index 95fa484..b1df55c 100644
+--- a/arch/sparc/lib/locks.S
++++ b/arch/sparc/lib/locks.S
+@@ -25,6 +25,15 @@ ___rw_read_enter_spin_on_wlock:
+ ldstub [%g1 + 3], %g2
+ b ___rw_read_enter_spin_on_wlock
+ ldub [%g1 + 3], %g2
++___rw_read_try_spin_on_wlock:
++ andcc %g2, 0xff, %g0
++ be,a ___rw_read_try
++ ldstub [%g1 + 3], %g2
++ xnorcc %g2, 0x0, %o0 /* if g2 is ~0, set o0 to 0 and bugger off */
++ bne,a ___rw_read_enter_spin_on_wlock
++ ld [%g1], %g2
++ retl
++ mov %g4, %o7
+ ___rw_read_exit_spin_on_wlock:
+ orcc %g2, 0x0, %g0
+ be,a ___rw_read_exit
+@@ -60,6 +69,17 @@ ___rw_read_exit:
+ retl
+ mov %g4, %o7
+
++ .globl ___rw_read_try
++___rw_read_try:
++ orcc %g2, 0x0, %g0
++ bne ___rw_read_try_spin_on_wlock
++ ld [%g1], %g2
++ add %g2, 1, %g2
++ st %g2, [%g1]
++ set 1, %o1
++ retl
++ mov %g4, %o7
++
+ .globl ___rw_write_enter
+ ___rw_write_enter:
+ orcc %g2, 0x0, %g0
+diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
+index 16e13f6..0df7121 100644
+--- a/arch/sparc/mm/srmmu.c
++++ b/arch/sparc/mm/srmmu.c
+@@ -402,7 +402,7 @@ void srmmu_nocache_calcsize(void)
+ srmmu_nocache_end = SRMMU_NOCACHE_VADDR + srmmu_nocache_size;
+ }
+
+-void srmmu_nocache_init(void)
++void __init srmmu_nocache_init(void)
+ {
+ unsigned int bitmap_bits;
+ pgd_t *pgd;
+@@ -2175,7 +2175,7 @@ void __init ld_mmu_srmmu(void)
+
+ BTFIXUPSET_CALL(pte_pfn, srmmu_pte_pfn, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM);
+- BTFIXUPSET_CALL(pgd_page, srmmu_pgd_page, BTFIXUPCALL_NORM);
++ BTFIXUPSET_CALL(pgd_page_vaddr, srmmu_pgd_page, BTFIXUPCALL_NORM);
+
+ BTFIXUPSET_SETHI(none_mask, 0xF0000000);
+
+diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
+index 7fdddf3..436021c 100644
+--- a/arch/sparc/mm/sun4c.c
++++ b/arch/sparc/mm/sun4c.c
+@@ -2280,5 +2280,5 @@ void __init ld_mmu_sun4c(void)
+
+ /* These should _never_ get called with two level tables. */
+ BTFIXUPSET_CALL(pgd_set, sun4c_pgd_set, BTFIXUPCALL_NOP);
+- BTFIXUPSET_CALL(pgd_page, sun4c_pgd_page, BTFIXUPCALL_RETO0);
++ BTFIXUPSET_CALL(pgd_page_vaddr, sun4c_pgd_page, BTFIXUPCALL_RETO0);
+ }
+diff --git a/arch/sparc/oprofile/Kconfig b/arch/sparc/oprofile/Kconfig
+new file mode 100644
+index 0000000..d8a8408
+--- /dev/null
++++ b/arch/sparc/oprofile/Kconfig
+@@ -0,0 +1,17 @@
++config PROFILING
++ bool "Profiling support (EXPERIMENTAL)"
++ help
++ Say Y here to enable the extended profiling support mechanisms used
++ by profilers such as OProfile.
++
++
++config OPROFILE
++ tristate "OProfile system profiling (EXPERIMENTAL)"
++ depends on PROFILING
++ help
++ OProfile is a profiling system capable of profiling the
++ whole system, include the kernel, kernel modules, libraries,
++ and applications.
++
++ If unsure, say N.
++
+diff --git a/arch/sparc/oprofile/Makefile b/arch/sparc/oprofile/Makefile
+new file mode 100644
+index 0000000..e9feca1
+--- /dev/null
++++ b/arch/sparc/oprofile/Makefile
+@@ -0,0 +1,9 @@
++obj-$(CONFIG_OPROFILE) += oprofile.o
++
++DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
++ oprof.o cpu_buffer.o buffer_sync.o \
++ event_buffer.o oprofile_files.o \
++ oprofilefs.o oprofile_stats.o \
++ timer_int.o )
++
++oprofile-y := $(DRIVER_OBJS) init.o
+diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
+new file mode 100644
+index 0000000..9ab815b
+--- /dev/null
++++ b/arch/sparc/oprofile/init.c
+@@ -0,0 +1,23 @@
++/**
++ * @file init.c
++ *
++ * @remark Copyright 2002 OProfile authors
++ * @remark Read the file COPYING
++ *
++ * @author John Levon <levon at movementarian.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/oprofile.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++
++int __init oprofile_arch_init(struct oprofile_operations * ops)
++{
++ return -ENODEV;
++}
++
++
++void oprofile_arch_exit(void)
++{
++}
+diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
+index 8d8ca71..b627f8d 100644
+--- a/arch/sparc64/Kconfig
++++ b/arch/sparc64/Kconfig
+@@ -420,7 +420,7 @@ source "arch/sparc64/oprofile/Kconfig"
+
+ config KPROBES
+ bool "Kprobes (EXPERIMENTAL)"
+- depends on EXPERIMENTAL && MODULES
++ depends on KALLSYMS && EXPERIMENTAL && MODULES
+ help
+ Kprobes allows you to trap at almost any kernel address and
+ execute a callback function. register_kprobe() establishes
+diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
+index 43d9229..2f4612f 100644
+--- a/arch/sparc64/defconfig
++++ b/arch/sparc64/defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc2
+-# Fri Jul 21 14:19:24 2006
++# Linux kernel version: 2.6.19-rc2
++# Tue Oct 17 19:29:20 2006
+ #
+ CONFIG_SPARC=y
+ CONFIG_SPARC64=y
+@@ -9,6 +9,7 @@ CONFIG_64BIT=y
+ CONFIG_MMU=y
+ CONFIG_TIME_INTERPOLATION=y
+ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_AUDIT_ARCH=y
+ CONFIG_SPARC64_PAGE_SIZE_8KB=y
+ # CONFIG_SPARC64_PAGE_SIZE_64KB is not set
+ # CONFIG_SPARC64_PAGE_SIZE_512KB is not set
+@@ -34,17 +35,20 @@ CONFIG_LOCALVERSION=""
+ # CONFIG_LOCALVERSION_AUTO is not set
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_UID16=y
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -53,12 +57,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -76,6 +80,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ CONFIG_BLK_DEV_IO_TRACE=y
+
+ #
+@@ -140,6 +145,7 @@ CONFIG_SUN_AUXIO=y
+ CONFIG_SUN_IO=y
+ CONFIG_PCI=y
+ CONFIG_PCI_DOMAINS=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ # CONFIG_PCI_DEBUG is not set
+ CONFIG_SUN_OPENPROMFS=m
+ CONFIG_SPARC32_COMPAT=y
+@@ -152,7 +158,7 @@ CONFIG_BINFMT_ELF32=y
+ #
+ CONFIG_BINFMT_ELF=y
+ CONFIG_BINFMT_MISC=m
+-# CONFIG_SOLARIS_EMUL is not set
++CONFIG_SOLARIS_EMUL=y
+ # CONFIG_CMDLINE_BOOL is not set
+
+ #
+@@ -169,6 +175,7 @@ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+ CONFIG_XFRM=y
+ CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
+ CONFIG_NET_KEY=m
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+@@ -190,23 +197,12 @@ CONFIG_INET_XFRM_TUNNEL=y
+ CONFIG_INET_TUNNEL=y
+ CONFIG_INET_XFRM_MODE_TRANSPORT=y
+ CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+-CONFIG_TCP_CONG_ADVANCED=y
+-
+-#
+-# TCP congestion control
+-#
+-CONFIG_TCP_CONG_BIC=y
+-CONFIG_TCP_CONG_CUBIC=m
+-CONFIG_TCP_CONG_WESTWOOD=m
+-CONFIG_TCP_CONG_HTCP=m
+-CONFIG_TCP_CONG_HSTCP=m
+-CONFIG_TCP_CONG_HYBLA=m
+-CONFIG_TCP_CONG_VEGAS=m
+-CONFIG_TCP_CONG_SCALABLE=m
+-CONFIG_TCP_CONG_LP=m
+-CONFIG_TCP_CONG_VENO=m
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ CONFIG_IPV6=m
+ CONFIG_IPV6_PRIVACY=y
+ CONFIG_IPV6_ROUTER_PREF=y
+@@ -214,11 +210,17 @@ CONFIG_IPV6_ROUTE_INFO=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
++# CONFIG_IPV6_MIP6 is not set
+ CONFIG_INET6_XFRM_TUNNEL=m
+ CONFIG_INET6_TUNNEL=m
+ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+ CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=m
+ CONFIG_IPV6_TUNNEL=m
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
+ # CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+@@ -233,6 +235,7 @@ CONFIG_IP_DCCP_ACKVEC=y
+ # DCCP CCIDs Configuration (EXPERIMENTAL)
+ #
+ CONFIG_IP_DCCP_CCID2=m
++# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+ CONFIG_IP_DCCP_CCID3=m
+ CONFIG_IP_DCCP_TFRC_LIB=m
+
+@@ -240,6 +243,7 @@ CONFIG_IP_DCCP_TFRC_LIB=m
+ # DCCP Kernel Hacking
+ #
+ # CONFIG_IP_DCCP_DEBUG is not set
++# CONFIG_NET_DCCPPROBE is not set
+
+ #
+ # SCTP Configuration (EXPERIMENTAL)
+@@ -259,7 +263,6 @@ CONFIG_VLAN_8021Q=m
+ # 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
+
+@@ -332,6 +335,12 @@ CONFIG_CDROM_PKTCDVD_WCACHE=y
+ CONFIG_ATA_OVER_ETH=m
+
+ #
++# Misc devices
++#
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
+@@ -373,6 +382,7 @@ CONFIG_BLK_DEV_ALI15X3=y
+ # CONFIG_BLK_DEV_CS5530 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+ # CONFIG_BLK_DEV_PIIX is not set
+ # CONFIG_BLK_DEV_IT821X is not set
+@@ -395,6 +405,7 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ CONFIG_RAID_ATTRS=m
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ CONFIG_SCSI_PROC_FS=y
+
+ #
+@@ -416,12 +427,13 @@ CONFIG_SCSI_CONSTANTS=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=y
+ CONFIG_SCSI_FC_ATTRS=y
+ CONFIG_SCSI_ISCSI_ATTRS=m
+ # CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+@@ -434,21 +446,23 @@ CONFIG_ISCSI_TCP=m
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_ARCMSR is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLOGICPTI is not set
+ # CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI is not set
+ # CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+@@ -456,6 +470,11 @@ CONFIG_ISCSI_TCP=m
+ # CONFIG_SCSI_SUNESP is not set
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ CONFIG_MD=y
+@@ -469,6 +488,7 @@ CONFIG_MD_RAID456=m
+ CONFIG_MD_MULTIPATH=m
+ # CONFIG_MD_FAULTY is not set
+ CONFIG_BLK_DEV_DM=m
++# CONFIG_DM_DEBUG is not set
+ CONFIG_DM_CRYPT=m
+ CONFIG_DM_SNAPSHOT=m
+ CONFIG_DM_MIRROR=m
+@@ -569,6 +589,7 @@ CONFIG_E1000_NAPI=y
+ # CONFIG_VIA_VELOCITY is not set
+ CONFIG_TIGON3=m
+ CONFIG_BNX2=m
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -616,6 +637,7 @@ CONFIG_BNX2=m
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -638,6 +660,7 @@ CONFIG_KEYBOARD_SUNKBD=y
+ CONFIG_KEYBOARD_LKKBD=m
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ CONFIG_MOUSE_SERIAL=y
+@@ -712,7 +735,6 @@ CONFIG_RTC=y
+ # TPM devices
+ #
+ # CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+
+ #
+ # I2C support
+@@ -815,6 +837,7 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_SMSC47M192 is not set
+ # CONFIG_SENSORS_SMSC47B397 is not set
+ # CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_SENSORS_VT8231 is not set
+ # CONFIG_SENSORS_W83781D is not set
+ # CONFIG_SENSORS_W83791D is not set
+@@ -825,14 +848,9 @@ CONFIG_HWMON=y
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+-# Misc devices
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -845,6 +863,7 @@ CONFIG_VIDEO_V4L2=y
+ #
+ # CONFIG_FIRMWARE_EDID is not set
+ CONFIG_FB=y
++CONFIG_FB_DDC=y
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+@@ -1000,6 +1019,7 @@ CONFIG_SND_ALI5451=m
+ # CONFIG_SND_VIA82XX_MODEM is not set
+ # CONFIG_SND_VX222 is not set
+ # CONFIG_SND_YMFPCI is not set
++# CONFIG_SND_AC97_POWER_SAVE is not set
+
+ #
+ # USB devices
+@@ -1116,6 +1136,7 @@ CONFIG_USB_HIDDEV=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+@@ -1123,12 +1144,13 @@ CONFIG_USB_HIDDEV=y
+ # CONFIG_USB_LED is not set
+ # CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
+ # CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_SISUSBVGA is not set
+ # CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+ # CONFIG_USB_TEST is not set
+
+ #
+@@ -1213,6 +1235,7 @@ CONFIG_EXT3_FS=y
+ CONFIG_EXT3_FS_XATTR=y
+ CONFIG_EXT3_FS_POSIX_ACL=y
+ CONFIG_EXT3_FS_SECURITY=y
++# CONFIG_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+@@ -1220,6 +1243,7 @@ CONFIG_FS_MBCACHE=y
+ # CONFIG_JFS_FS is not set
+ CONFIG_FS_POSIX_ACL=y
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -1249,8 +1273,10 @@ CONFIG_DNOTIFY=y
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+@@ -1261,6 +1287,7 @@ CONFIG_RAMFS=y
+ #
+ # CONFIG_ADFS_FS is not set
+ # CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_FS is not set
+ # CONFIG_HFS_FS is not set
+ # CONFIG_HFSPLUS_FS is not set
+ # CONFIG_BEFS_FS is not set
+@@ -1347,6 +1374,7 @@ CONFIG_KPROBES=y
+ # Kernel hacking
+ #
+ CONFIG_PRINTK_TIME=y
++CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+@@ -1366,9 +1394,12 @@ CONFIG_DEBUG_BUGVERBOSE=y
+ # CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ # CONFIG_UNWIND_INFO is not set
+ CONFIG_FORCED_INLINING=y
++# CONFIG_HEADERS_CHECK is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
+ # CONFIG_DEBUG_STACK_USAGE is not set
+ # CONFIG_DEBUG_DCFLUSH is not set
+ # CONFIG_STACK_DEBUG is not set
+@@ -1386,6 +1417,10 @@ CONFIG_KEYS=y
+ # Cryptographic options
+ #
+ CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=y
+ CONFIG_CRYPTO_NULL=m
+ CONFIG_CRYPTO_MD4=y
+@@ -1395,9 +1430,12 @@ CONFIG_CRYPTO_SHA256=m
+ CONFIG_CRYPTO_SHA512=m
+ CONFIG_CRYPTO_WP512=m
+ CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=y
+ CONFIG_CRYPTO_DES=y
+ CONFIG_CRYPTO_BLOWFISH=m
+ CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
+ CONFIG_CRYPTO_SERPENT=m
+ CONFIG_CRYPTO_AES=m
+ CONFIG_CRYPTO_CAST5=m
+diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
+index 718350a..826118e 100644
+--- a/arch/sparc64/kernel/auxio.c
++++ b/arch/sparc64/kernel/auxio.c
+@@ -5,7 +5,6 @@
+ * Refactoring for unified NCR/PCIO support 2002 Eric Brower (ebrower at usa.net)
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
+index b66336d..e724c54 100644
+--- a/arch/sparc64/kernel/central.c
++++ b/arch/sparc64/kernel/central.c
+@@ -126,6 +126,10 @@ static void probe_other_fhcs(void)
+ int board;
+ u32 tmp;
+
++ if (dp->parent &&
++ dp->parent->parent != NULL)
++ continue;
++
+ fhc = (struct linux_fhc *)
+ central_alloc_bootmem(sizeof(struct linux_fhc));
+ if (fhc == NULL)
+diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
+index 8a9b470..35bf895 100644
+--- a/arch/sparc64/kernel/ebus.c
++++ b/arch/sparc64/kernel/ebus.c
+@@ -79,7 +79,7 @@ static void __ebus_dma_reset(struct ebus
+ }
+ }
+
+-static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
+ {
+ struct ebus_dma_info *p = dev_id;
+ unsigned long flags;
+@@ -389,12 +389,12 @@ static void __init fill_ebus_device(stru
+ dev->ofdev.node = dp;
+ dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
+ dev->ofdev.dev.bus = &ebus_bus_type;
+- strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
+
+ /* Register with core */
+ if (of_device_register(&dev->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+- dev->ofdev.dev.bus_id);
++ dp->path_component_name);
+
+ dp = dp->child;
+ if (dp) {
+@@ -494,12 +494,12 @@ void __init ebus_init(void)
+ ebus->ofdev.node = dp;
+ ebus->ofdev.dev.parent = &pdev->dev;
+ ebus->ofdev.dev.bus = &ebus_bus_type;
+- strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
+
+ /* Register with core */
+ if (of_device_register(&ebus->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+- ebus->ofdev.dev.bus_id);
++ dp->path_component_name);
+
+
+ child = dp->child;
+diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
+index 0aaa35f..6f28bec 100644
+--- a/arch/sparc64/kernel/entry.S
++++ b/arch/sparc64/kernel/entry.S
+@@ -22,11 +22,10 @@
+ #include <asm/auxio.h>
+ #include <asm/sfafsr.h>
+ #include <asm/pil.h>
++#include <asm/unistd.h>
+
+ #define curptr g6
+
+-#define NR_SYSCALLS 300 /* Each OS is different... */
+-
+ .text
+ .align 32
+
+diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
+index 4e64724..d64b1ea 100644
+--- a/arch/sparc64/kernel/irq.c
++++ b/arch/sparc64/kernel/irq.c
+@@ -522,12 +522,13 @@ void ack_bad_irq(unsigned int virt_irq)
+ }
+
+ #ifndef CONFIG_SMP
+-extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
++extern irqreturn_t timer_interrupt(int, void *);
+
+ void timer_irq(int irq, struct pt_regs *regs)
+ {
+ unsigned long clr_mask = 1 << irq;
+ unsigned long tick_mask = tick_ops->softint_mask;
++ struct pt_regs *old_regs;
+
+ if (get_softint() & tick_mask) {
+ irq = 0;
+@@ -535,21 +536,25 @@ void timer_irq(int irq, struct pt_regs *
+ }
+ clear_softint(clr_mask);
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+
+ kstat_this_cpu.irqs[0]++;
+- timer_interrupt(irq, NULL, regs);
++ timer_interrupt(irq, NULL);
+
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+ #endif
+
+ void handler_irq(int irq, struct pt_regs *regs)
+ {
+ struct ino_bucket *bucket;
++ struct pt_regs *old_regs;
+
+ clear_softint(1 << irq);
+
++ old_regs = set_irq_regs(regs);
+ irq_enter();
+
+ /* Sliiiick... */
+@@ -558,12 +563,13 @@ void handler_irq(int irq, struct pt_regs
+ struct ino_bucket *next = __bucket(bucket->irq_chain);
+
+ bucket->irq_chain = 0;
+- __do_IRQ(bucket->virt_irq, regs);
++ __do_IRQ(bucket->virt_irq);
+
+ bucket = next;
+ }
+
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ struct sun5_timer {
+diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
+index 0f3aec7..f028e68 100644
+--- a/arch/sparc64/kernel/isa.c
++++ b/arch/sparc64/kernel/isa.c
+@@ -115,12 +115,12 @@ static void __init isa_fill_devices(stru
+ isa_dev->ofdev.node = dp;
+ isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
+ isa_dev->ofdev.dev.bus = &isa_bus_type;
+- strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(isa_dev->ofdev.dev.bus_id, "isa[%08x]", dp->node);
+
+ /* Register with core */
+ if (of_device_register(&isa_dev->ofdev) != 0) {
+ printk(KERN_DEBUG "isa: device registration error for %s!\n",
+- isa_dev->ofdev.dev.bus_id);
++ dp->path_component_name);
+ kfree(isa_dev);
+ goto next_sibling;
+ }
+@@ -191,12 +191,12 @@ void __init isa_init(void)
+ isa_br->ofdev.node = dp;
+ isa_br->ofdev.dev.parent = &pdev->dev;
+ isa_br->ofdev.dev.bus = &isa_bus_type;
+- strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(isa_br->ofdev.dev.bus_id, "isa%d", index);
+
+ /* Register with core */
+ if (of_device_register(&isa_br->ofdev) != 0) {
+ printk(KERN_DEBUG "isa: device registration error for %s!\n",
+- isa_br->ofdev.dev.bus_id);
++ dp->path_component_name);
+ kfree(isa_br);
+ return;
+ }
+diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
+index 238bbf6..8cc14fc 100644
+--- a/arch/sparc64/kernel/of_device.c
++++ b/arch/sparc64/kernel/of_device.c
+@@ -1,4 +1,3 @@
+-#include <linux/config.h>
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -132,8 +131,13 @@ static int of_device_resume(struct devic
+ void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
+ {
+ unsigned long ret = res->start + offset;
++ struct resource *r;
+
+- if (!request_region(ret, size, name))
++ if (res->flags & IORESOURCE_MEM)
++ r = request_mem_region(ret, size, name);
++ else
++ r = request_region(ret, size, name);
++ if (!r)
+ ret = 0;
+
+ return (void __iomem *) ret;
+@@ -398,16 +402,22 @@ static void of_bus_sbus_count_cells(stru
+ *sizec = 1;
+ }
+
+-static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+-{
+- return of_bus_default_map(addr, range, na, ns, pna);
+-}
+-
+-static unsigned int of_bus_sbus_get_flags(u32 *addr)
++/*
++ * FHC/Central bus specific translator.
++ *
++ * This is just needed to hard-code the address and size cell
++ * counts. 'fhc' and 'central' nodes lack the #address-cells and
++ * #size-cells properties, and if you walk to the root on such
++ * Enterprise boxes all you'll get is a #size-cells of 2 which is
++ * not what we want to use.
++ */
++static int of_bus_fhc_match(struct device_node *np)
+ {
+- return IORESOURCE_MEM;
++ return !strcmp(np->name, "fhc") ||
++ !strcmp(np->name, "central");
+ }
+
++#define of_bus_fhc_count_cells of_bus_sbus_count_cells
+
+ /*
+ * Array of bus specific translators
+@@ -429,8 +439,17 @@ static struct of_bus of_busses[] = {
+ .addr_prop_name = "reg",
+ .match = of_bus_sbus_match,
+ .count_cells = of_bus_sbus_count_cells,
+- .map = of_bus_sbus_map,
+- .get_flags = of_bus_sbus_get_flags,
++ .map = of_bus_default_map,
++ .get_flags = of_bus_default_get_flags,
++ },
++ /* FHC */
++ {
++ .name = "fhc",
++ .addr_prop_name = "reg",
++ .match = of_bus_fhc_match,
++ .count_cells = of_bus_fhc_count_cells,
++ .map = of_bus_default_map,
++ .get_flags = of_bus_default_get_flags,
+ },
+ /* Default */
+ {
+@@ -842,7 +861,7 @@ static struct of_device * __init scan_on
+ if (!parent)
+ strcpy(op->dev.bus_id, "root");
+ else
+- strcpy(op->dev.bus_id, dp->path_component_name);
++ sprintf(op->dev.bus_id, "%08x", dp->node);
+
+ if (of_device_register(op)) {
+ printk("%s: Could not register of device.\n",
+diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
+index 7a59cc7..827ae30 100644
+--- a/arch/sparc64/kernel/pci_common.c
++++ b/arch/sparc64/kernel/pci_common.c
+@@ -330,19 +330,6 @@ __init get_device_resource(struct linux_
+ return res;
+ }
+
+-static int __init pdev_resource_collisions_expected(struct pci_dev *pdev)
+-{
+- if (pdev->vendor != PCI_VENDOR_ID_SUN)
+- return 0;
+-
+- if (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS ||
+- pdev->device == PCI_DEVICE_ID_SUN_RIO_1394 ||
+- pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+- return 1;
+-
+- return 0;
+-}
+-
+ static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev)
+ {
+@@ -400,19 +387,23 @@ static void __init pdev_record_assignmen
+ pbm->parent->resource_adjust(pdev, res, root);
+
+ if (request_resource(root, res) < 0) {
++ int rnum;
++
+ /* OK, there is some conflict. But this is fine
+ * since we'll reassign it in the fixup pass.
+ *
+- * We notify the user that OBP made an error if it
+- * is a case we don't expect.
++ * Do not print the warning for ROM resources
++ * as such a conflict is quite common and
++ * harmless as the ROM bar is disabled.
+ */
+- if (!pdev_resource_collisions_expected(pdev)) {
+- printk(KERN_ERR "PCI: Address space collision on region %ld "
++ rnum = (res - &pdev->resource[0]);
++ if (rnum != PCI_ROM_RESOURCE)
++ printk(KERN_ERR "PCI: Resource collision, "
++ "region %d "
+ "[%016lx:%016lx] of device %s\n",
+- (res - &pdev->resource[0]),
++ rnum,
+ res->start, res->end,
+ pci_name(pdev));
+- }
+ }
+ }
+ }
+diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
+index 82e5455..2e7f142 100644
+--- a/arch/sparc64/kernel/pci_iommu.c
++++ b/arch/sparc64/kernel/pci_iommu.c
+@@ -281,7 +281,7 @@ static void pci_4u_free_consistent(struc
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+- free_npages(iommu, dvma, npages);
++ free_npages(iommu, dvma - iommu->page_table_map_base, npages);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
+index 1ec0aab..fda5db2 100644
+--- a/arch/sparc64/kernel/pci_psycho.c
++++ b/arch/sparc64/kernel/pci_psycho.c
+@@ -533,7 +533,7 @@ static void psycho_check_iommu_error(str
+ #define PSYCHO_UEAFSR_RESV2 0x00000000007fffffUL /* Reserved */
+ #define PSYCHO_UE_AFAR 0x0038UL
+
+-static irqreturn_t psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
+@@ -610,7 +610,7 @@ static irqreturn_t psycho_ue_intr(int ir
+ #define PSYCHO_CEAFSR_RESV2 0x00000000007fffffUL /* Reserved */
+ #define PSYCHO_CE_AFAR 0x0040UL
+
+-static irqreturn_t psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
+@@ -735,7 +735,7 @@ static irqreturn_t psycho_pcierr_intr_ot
+ return ret;
+ }
+
+-static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
+ {
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
+diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
+index 4589185..94bb681 100644
+--- a/arch/sparc64/kernel/pci_sabre.c
++++ b/arch/sparc64/kernel/pci_sabre.c
+@@ -574,7 +574,7 @@ static void sabre_check_iommu_error(stru
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ }
+
+-static irqreturn_t sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;
+@@ -634,7 +634,7 @@ static irqreturn_t sabre_ue_intr(int irq
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;
+@@ -726,7 +726,7 @@ static irqreturn_t sabre_pcierr_intr_oth
+ return ret;
+ }
+
+-static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg, afar_reg;
+@@ -1196,7 +1196,7 @@ static void pbm_register_toplevel_resour
+ &pbm->mem_space);
+ }
+
+-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
++static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end)
+ {
+ struct pci_pbm_info *pbm;
+ struct device_node *node;
+@@ -1261,6 +1261,8 @@ static void sabre_pbm_init(struct pci_co
+ node = node->sibling;
+ }
+ if (simbas_found == 0) {
++ struct resource *rp;
++
+ /* No APBs underneath, probably this is a hummingbird
+ * system.
+ */
+@@ -1302,8 +1304,10 @@ static void sabre_pbm_init(struct pci_co
+ pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL;
+ pbm->io_space.flags = IORESOURCE_IO;
+
+- pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE;
+- pbm->mem_space.end = pbm->mem_space.start + (unsigned long)dma_begin - 1UL;
++ pbm->mem_space.start =
++ (p->pbm_A.controller_regs + SABRE_MEMSPACE);
++ pbm->mem_space.end =
++ (pbm->mem_space.start + ((1UL << 32UL) - 1UL));
+ pbm->mem_space.flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
+@@ -1315,6 +1319,17 @@ static void sabre_pbm_init(struct pci_co
+ prom_halt();
+ }
+
++ rp = kmalloc(sizeof(*rp), GFP_KERNEL);
++ if (!rp) {
++ prom_printf("Cannot allocate IOMMU resource.\n");
++ prom_halt();
++ }
++ rp->name = "IOMMU";
++ rp->start = pbm->mem_space.start + (unsigned long) dma_start;
++ rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL;
++ rp->flags = IORESOURCE_BUSY;
++ request_resource(&pbm->mem_space, rp);
++
+ pci_register_legacy_regions(&pbm->io_space,
+ &pbm->mem_space);
+ }
+@@ -1450,5 +1465,5 @@ void sabre_init(struct device_node *dp,
+ /*
+ * Look for APB underneath.
+ */
+- sabre_pbm_init(p, dp, vdma[0]);
++ sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]);
+ }
+diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
+index 75ade83..66911b1 100644
+--- a/arch/sparc64/kernel/pci_schizo.c
++++ b/arch/sparc64/kernel/pci_schizo.c
+@@ -515,7 +515,7 @@ static void schizo_check_iommu_error(str
+ #define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL /* Safari */
+ #define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL /* Safari */
+
+-static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
+@@ -603,7 +603,7 @@ static irqreturn_t schizo_ue_intr(int ir
+ #define SCHIZO_CEAFSR_MTAG 0x000000000000e000UL
+ #define SCHIZO_CEAFSR_ECCSYND 0x00000000000001ffUL
+
+-static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
+@@ -778,7 +778,7 @@ static irqreturn_t schizo_pcierr_intr_ot
+ return ret;
+ }
+
+-static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
+ {
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
+@@ -933,7 +933,7 @@ static irqreturn_t schizo_pcierr_intr(in
+ /* We only expect UNMAP errors here. The rest of the Safari errors
+ * are marked fatal and thus cause a system reset.
+ */
+-static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
+ {
+ struct pci_controller_info *p = dev_id;
+ u64 errlog;
+diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
+index e55466c..699b24b 100644
+--- a/arch/sparc64/kernel/power.c
++++ b/arch/sparc64/kernel/power.c
+@@ -4,8 +4,6 @@
+ * Copyright (C) 1999 David S. Miller (davem at redhat.com)
+ */
+
+-#define __KERNEL_SYSCALLS__
+-
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+@@ -14,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+ #include <linux/pm.h>
++#include <linux/syscalls.h>
+
+ #include <asm/system.h>
+ #include <asm/auxio.h>
+@@ -36,7 +35,7 @@ static void __iomem *power_reg;
+ static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
+ static int button_pressed;
+
+-static irqreturn_t power_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t power_handler(int irq, void *dev_id)
+ {
+ if (button_pressed == 0) {
+ button_pressed = 1;
+@@ -98,7 +97,7 @@ again:
+
+ /* Ok, down we go... */
+ button_pressed = 0;
+- if (execve("/sbin/shutdown", argv, envp) < 0) {
++ if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
+ printk("powerd: shutdown execution failed\n");
+ add_wait_queue(&powerd_wait, &wait);
+ goto again;
+diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
+index 5cc5ab6..0917c24 100644
+--- a/arch/sparc64/kernel/prom.c
++++ b/arch/sparc64/kernel/prom.c
+@@ -15,7 +15,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/string.h>
+@@ -794,7 +793,7 @@ static unsigned int schizo_irq_build(str
+ return virt_irq;
+ }
+
+-static void schizo_irq_trans_init(struct device_node *dp)
++static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
+ {
+ struct linux_prom64_registers *regs;
+ struct schizo_irq_data *irq_data;
+@@ -808,11 +807,24 @@ static void schizo_irq_trans_init(struct
+ dp->irq_trans->data = irq_data;
+
+ irq_data->pbm_regs = regs[0].phys_addr;
+- irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
++ if (is_tomatillo)
++ irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
++ else
++ irq_data->sync_reg = 0UL;
+ irq_data->portid = of_getintprop_default(dp, "portid", 0);
+ irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
+ }
+
++static void schizo_irq_trans_init(struct device_node *dp)
++{
++ __schizo_irq_trans_init(dp, 0);
++}
++
++static void tomatillo_irq_trans_init(struct device_node *dp)
++{
++ __schizo_irq_trans_init(dp, 1);
++}
++
+ static unsigned int pci_sun4v_irq_build(struct device_node *dp,
+ unsigned int devino,
+ void *_data)
+@@ -1051,8 +1063,8 @@ static struct irq_trans pci_irq_trans_ta
+ { "pci108e,8001", schizo_irq_trans_init },
+ { "SUNW,schizo+", schizo_irq_trans_init },
+ { "pci108e,8002", schizo_irq_trans_init },
+- { "SUNW,tomatillo", schizo_irq_trans_init },
+- { "pci108e,a801", schizo_irq_trans_init },
++ { "SUNW,tomatillo", tomatillo_irq_trans_init },
++ { "pci108e,a801", tomatillo_irq_trans_init },
+ { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+ };
+ #endif
+@@ -1080,23 +1092,22 @@ static void sun4v_vdev_irq_trans_init(st
+
+ static void irq_trans_init(struct device_node *dp)
+ {
+- const char *model;
+ #ifdef CONFIG_PCI
++ const char *model;
+ int i;
+ #endif
+
++#ifdef CONFIG_PCI
+ model = of_get_property(dp, "model", NULL);
+ if (!model)
+ model = of_get_property(dp, "compatible", NULL);
+- if (!model)
+- return;
+-
+-#ifdef CONFIG_PCI
+- for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
+- struct irq_trans *t = &pci_irq_trans_table[i];
++ if (model) {
++ for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
++ struct irq_trans *t = &pci_irq_trans_table[i];
+
+- if (!strcmp(model, t->name))
+- return t->init(dp);
++ if (!strcmp(model, t->name))
++ return t->init(dp);
++ }
+ }
+ #endif
+ #ifdef CONFIG_SBUS
+@@ -1104,8 +1115,9 @@ static void irq_trans_init(struct device
+ !strcmp(dp->name, "sbi"))
+ return sbus_irq_trans_init(dp);
+ #endif
+- if (!strcmp(dp->name, "central"))
+- return central_irq_trans_init(dp->child);
++ if (!strcmp(dp->name, "fhc") &&
++ !strcmp(dp->parent->name, "central"))
++ return central_irq_trans_init(dp);
+ if (!strcmp(dp->name, "virtual-devices"))
+ return sun4v_vdev_irq_trans_init(dp);
+ }
+@@ -1517,7 +1529,7 @@ static char * __init get_one_property(ph
+ return buf;
+ }
+
+-static struct device_node * __init create_node(phandle node)
++static struct device_node * __init create_node(phandle node, struct device_node *parent)
+ {
+ struct device_node *dp;
+
+@@ -1526,6 +1538,7 @@ static struct device_node * __init creat
+
+ dp = prom_early_alloc(sizeof(*dp));
+ dp->unique_id = unique_id++;
++ dp->parent = parent;
+
+ kref_init(&dp->kref);
+
+@@ -1544,12 +1557,11 @@ static struct device_node * __init build
+ {
+ struct device_node *dp;
+
+- dp = create_node(node);
++ dp = create_node(node, parent);
+ if (dp) {
+ *(*nextp) = dp;
+ *nextp = &dp->allnext;
+
+- dp->parent = parent;
+ dp->path_component_name = build_path_component(dp);
+ dp->full_name = build_full_name(dp);
+
+@@ -1565,7 +1577,7 @@ void __init prom_build_devicetree(void)
+ {
+ struct device_node **nextp;
+
+- allnodes = create_node(prom_root_node);
++ allnodes = create_node(prom_root_node, NULL);
+ allnodes->path_component_name = "";
+ allnodes->full_name = "/";
+
+diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
+index c49a577..01d6d86 100644
+--- a/arch/sparc64/kernel/sbus.c
++++ b/arch/sparc64/kernel/sbus.c
+@@ -839,7 +839,7 @@ unsigned int sbus_build_irq(void *buscoo
+ #define SYSIO_UEAFSR_SIZE 0x00001c0000000000UL /* Bad transfer size 2^SIZE */
+ #define SYSIO_UEAFSR_MID 0x000003e000000000UL /* UPA MID causing the fault */
+ #define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
+-static irqreturn_t sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
+ {
+ struct sbus_bus *sbus = dev_id;
+ struct sbus_iommu *iommu = sbus->iommu;
+@@ -911,7 +911,7 @@ static irqreturn_t sysio_ue_handler(int
+ #define SYSIO_CEAFSR_SIZE 0x00001c0000000000UL /* Bad transfer size 2^SIZE */
+ #define SYSIO_CEAFSR_MID 0x000003e000000000UL /* UPA MID causing the fault */
+ #define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
+-static irqreturn_t sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
+ {
+ struct sbus_bus *sbus = dev_id;
+ struct sbus_iommu *iommu = sbus->iommu;
+@@ -988,7 +988,7 @@ static irqreturn_t sysio_ce_handler(int
+ #define SYSIO_SBAFSR_SIZE 0x00001c0000000000UL /* Size of transfer */
+ #define SYSIO_SBAFSR_MID 0x000003e000000000UL /* MID causing the error */
+ #define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */
+-static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
+ {
+ struct sbus_bus *sbus = dev_id;
+ struct sbus_iommu *iommu = sbus->iommu;
+diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
+index 9582874..bf033b3 100644
+--- a/arch/sparc64/kernel/setup.c
++++ b/arch/sparc64/kernel/setup.c
+@@ -74,7 +74,6 @@ prom_console_write(struct console *con,
+
+ unsigned int boot_flags = 0;
+ #define BOOTME_DEBUG 0x1
+-#define BOOTME_SINGLE 0x2
+
+ /* Exported for mm/init.c:paging_init. */
+ unsigned long cmdline_memory_size = 0;
+@@ -91,16 +90,6 @@ void kernel_enter_debugger(void)
+ {
+ }
+
+-int obp_system_intr(void)
+-{
+- if (boot_flags & BOOTME_DEBUG) {
+- printk("OBP: system interrupted\n");
+- prom_halt();
+- return 1;
+- }
+- return 0;
+-}
+-
+ /*
+ * Process kernel command line switches that are specific to the
+ * SPARC or that require special low-level processing.
+@@ -112,7 +101,6 @@ static void __init process_switch(char c
+ boot_flags |= BOOTME_DEBUG;
+ break;
+ case 's':
+- boot_flags |= BOOTME_SINGLE;
+ break;
+ case 'h':
+ prom_printf("boot_flags_init: Halt!\n");
+diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
+index 708ba9b..c45f21b 100644
+--- a/arch/sparc64/kernel/signal32.c
++++ b/arch/sparc64/kernel/signal32.c
+@@ -29,6 +29,7 @@
+ #include <asm/psrcompat.h>
+ #include <asm/fpumacro.h>
+ #include <asm/visasm.h>
++#include <asm/compat_signal.h>
+
+ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
+index f62bf3a..cc09d82 100644
+--- a/arch/sparc64/kernel/smp.c
++++ b/arch/sparc64/kernel/smp.c
+@@ -31,6 +31,7 @@
+ #include <asm/cpudata.h>
+
+ #include <asm/irq.h>
++#include <asm/irq_regs.h>
+ #include <asm/page.h>
+ #include <asm/pgtable.h>
+ #include <asm/oplib.h>
+@@ -1187,6 +1188,7 @@ void smp_percpu_timer_interrupt(struct p
+ unsigned long compare, tick, pstate;
+ int cpu = smp_processor_id();
+ int user = user_mode(regs);
++ struct pt_regs *old_regs;
+
+ /*
+ * Check for level 14 softint.
+@@ -1203,8 +1205,9 @@ void smp_percpu_timer_interrupt(struct p
+ clear_softint(tick_mask);
+ }
+
++ old_regs = set_irq_regs(regs);
+ do {
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ if (!--prof_counter(cpu)) {
+ irq_enter();
+
+@@ -1236,6 +1239,7 @@ void smp_percpu_timer_interrupt(struct p
+ : /* no outputs */
+ : "r" (pstate));
+ } while (time_after_eq(tick, compare));
++ set_irq_regs(old_regs);
+ }
+
+ static void __init smp_setup_percpu_timer(void)
+diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
+index c608c94..a53d4ab 100644
+--- a/arch/sparc64/kernel/sys_sparc.c
++++ b/arch/sparc64/kernel/sys_sparc.c
+@@ -31,6 +31,7 @@
+ #include <asm/utrap.h>
+ #include <asm/perfctr.h>
+ #include <asm/a.out.h>
++#include <asm/unistd.h>
+
+ /* #define DEBUG_UNIMP_SYSCALL */
+
+@@ -712,13 +713,13 @@ asmlinkage long sys_getdomainname(char _
+
+ down_read(&uts_sem);
+
+- nlen = strlen(system_utsname.domainname) + 1;
++ nlen = strlen(utsname()->domainname) + 1;
+ err = -EINVAL;
+ if (nlen > len)
+ goto out;
+
+ err = -EFAULT;
+- if (!copy_to_user(name, system_utsname.domainname, nlen))
++ if (!copy_to_user(name, utsname()->domainname, nlen))
+ err = 0;
+
+ out:
+@@ -963,3 +964,23 @@ asmlinkage long sys_perfctr(int opcode,
+ };
+ return err;
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ long __res;
++ register long __g1 __asm__ ("g1") = __NR_execve;
++ register long __o0 __asm__ ("o0") = (long)(filename);
++ register long __o1 __asm__ ("o1") = (long)(argv);
++ register long __o2 __asm__ ("o2") = (long)(envp);
++ asm volatile ("t 0x6d\n\t"
++ "sub %%g0, %%o0, %0\n\t"
++ "movcc %%xcc, %%o0, %0\n\t"
++ : "=r" (__res), "=&r" (__o0)
++ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
++ : "cc");
++ return __res;
++}
+diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
+index c88ae23..e27cb71 100644
+--- a/arch/sparc64/kernel/sys_sparc32.c
++++ b/arch/sparc64/kernel/sys_sparc32.c
+@@ -61,6 +61,7 @@
+ #include <asm/semaphore.h>
+ #include <asm/mmu_context.h>
+ #include <asm/a.out.h>
++#include <asm/compat_signal.h>
+
+ asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
+ {
+@@ -337,12 +338,17 @@ asmlinkage long sys32_ftruncate64(unsign
+
+ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
+ {
++ compat_ino_t ino;
+ int err;
+
+ if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
+ !old_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+
++ ino = stat->ino;
++ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
++ return -EOVERFLOW;
++
+ err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
+ err |= put_user(stat->ino, &statbuf->st_ino);
+ err |= put_user(stat->mode, &statbuf->st_mode);
+@@ -1016,7 +1022,7 @@ struct __sysctl_args32 {
+
+ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
+ {
+-#ifndef CONFIG_SYSCTL
++#ifndef CONFIG_SYSCTL_SYSCALL
+ return -ENOSYS;
+ #else
+ struct __sysctl_args32 tmp;
+diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
+index 87ebdf8..7da72d3 100644
+--- a/arch/sparc64/kernel/sys_sunos32.c
++++ b/arch/sparc64/kernel/sys_sunos32.c
+@@ -43,6 +43,7 @@
+ #include <asm/idprom.h> /* for gethostid() */
+ #include <asm/unistd.h>
+ #include <asm/system.h>
++#include <asm/compat_signal.h>
+
+ /* For the nfs mount emulation */
+ #include <linux/socket.h>
+@@ -280,16 +281,20 @@ static int sunos_filldir(void * __buf, c
+ struct sunos_dirent __user *dirent;
+ struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
++ u32 d_ino;
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->curr;
+ buf->previous = dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ if (copy_to_user(dirent->d_name, name, namlen))
+@@ -363,14 +368,18 @@ static int sunos_filldirentry(void * __b
+ struct sunos_direntry_callback * buf =
+ (struct sunos_direntry_callback *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
++ u32 d_ino;
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ dirent = buf->curr;
+ buf->previous = dirent;
+- put_user(ino, &dirent->d_ino);
++ put_user(d_ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ if (copy_to_user(dirent->d_name, name, namlen))
+@@ -439,16 +448,16 @@ asmlinkage int sunos_uname(struct sunos_
+ int ret;
+
+ down_read(&uts_sem);
+- ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0],
++ ret = copy_to_user(&name->sname[0], &utsname()->sysname[0],
+ sizeof(name->sname) - 1);
+- ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0],
++ ret |= copy_to_user(&name->nname[0], &utsname()->nodename[0],
+ sizeof(name->nname) - 1);
+ ret |= put_user('\0', &name->nname[8]);
+- ret |= copy_to_user(&name->rel[0], &system_utsname.release[0],
++ ret |= copy_to_user(&name->rel[0], &utsname()->release[0],
+ sizeof(name->rel) - 1);
+- ret |= copy_to_user(&name->ver[0], &system_utsname.version[0],
++ ret |= copy_to_user(&name->ver[0], &utsname()->version[0],
+ sizeof(name->ver) - 1);
+- ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0],
++ ret |= copy_to_user(&name->mach[0], &utsname()->machine[0],
+ sizeof(name->mach) - 1);
+ up_read(&uts_sem);
+ return (ret ? -EFAULT : 0);
+diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
+index 419a63f..9a80267 100644
+--- a/arch/sparc64/kernel/systbls.S
++++ b/arch/sparc64/kernel/systbls.S
+@@ -79,7 +79,7 @@ sys_call_table32:
+ .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64
+ /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
+ .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
+-/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list
++/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages
+
+ #endif /* CONFIG_COMPAT */
+
+@@ -149,7 +149,7 @@ sys_call_table:
+ .word sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64
+ /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
+ .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
+-/*300*/ .word sys_set_robust_list, sys_get_robust_list
++/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages
+
+ #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
+ defined(CONFIG_SOLARIS_EMUL_MODULE)
+@@ -262,5 +262,7 @@ sunos_sys_table:
+ /*290*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+- .word sunos_nosys, sunos_nosys, sunos_nosys
++ .word sunos_nosys
++/*300*/ .word sunos_nosys, sunos_nosys, sunos_nosys
++
+ #endif
+diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
+index 094d3e3..061e1b1 100644
+--- a/arch/sparc64/kernel/time.c
++++ b/arch/sparc64/kernel/time.c
+@@ -45,6 +45,7 @@
+ #include <asm/cpudata.h>
+ #include <asm/uaccess.h>
+ #include <asm/prom.h>
++#include <asm/irq_regs.h>
+
+ DEFINE_SPINLOCK(mostek_lock);
+ DEFINE_SPINLOCK(rtc_lock);
+@@ -53,8 +54,6 @@ void __iomem *mstk48t02_regs = NULL;
+ unsigned long ds1287_regs = 0UL;
+ #endif
+
+-extern unsigned long wall_jiffies;
+-
+ static void __iomem *mstk48t08_regs;
+ static void __iomem *mstk48t59_regs;
+
+@@ -454,7 +453,7 @@ static inline void timer_check_rtc(void)
+ }
+ }
+
+-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++irqreturn_t timer_interrupt(int irq, void *dev_id)
+ {
+ unsigned long ticks, compare, pstate;
+
+@@ -462,10 +461,10 @@ irqreturn_t timer_interrupt(int irq, voi
+
+ do {
+ #ifndef CONFIG_SMP
+- profile_tick(CPU_PROFILING, regs);
+- update_process_times(user_mode(regs));
++ profile_tick(CPU_PROFILING);
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+- do_timer(regs);
++ do_timer(1);
+
+ /* Guarantee that the following sequences execute
+ * uninterrupted.
+@@ -496,7 +495,7 @@ void timer_tick_interrupt(struct pt_regs
+ {
+ write_seqlock(&xtime_lock);
+
+- do_timer(regs);
++ do_timer(1);
+
+ timer_check_rtc();
+
+@@ -983,7 +982,7 @@ static struct time_interpolator sparc64_
+ };
+
+ /* The quotient formula is taken from the IA64 port. */
+-#define SPARC64_NSEC_PER_CYC_SHIFT 30UL
++#define SPARC64_NSEC_PER_CYC_SHIFT 10UL
+ void __init time_init(void)
+ {
+ unsigned long clock = sparc64_init_timers();
+diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
+index 68420e2..fe1796c 100644
+--- a/arch/sparc64/kernel/traps.c
++++ b/arch/sparc64/kernel/traps.c
+@@ -87,6 +87,7 @@ static void dump_tl1_traplog(struct tl1_
+ i + 1,
+ p->trapstack[i].tstate, p->trapstack[i].tpc,
+ p->trapstack[i].tnpc, p->trapstack[i].tt);
++ print_symbol("TRAPLOG: TPC<%s>\n", p->trapstack[i].tpc);
+ }
+ }
+
+@@ -1134,6 +1135,9 @@ static void cheetah_log_errors(struct pt
+ printk("%s" "ERROR(%d): TPC[%lx] TNPC[%lx] O7[%lx] TSTATE[%lx]\n",
+ (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+ regs->tpc, regs->tnpc, regs->u_regs[UREG_I7], regs->tstate);
++ printk("%s" "ERROR(%d): ",
++ (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id());
++ print_symbol("TPC<%s>\n", regs->tpc);
+ printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n",
+ (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+ (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT,
+@@ -1741,6 +1745,7 @@ void cheetah_plus_parity_error(int type,
+ smp_processor_id(),
+ (type & 0x1) ? 'I' : 'D',
+ regs->tpc);
++ print_symbol(KERN_EMERG "TPC<%s>\n", regs->tpc);
+ panic("Irrecoverable Cheetah+ parity error.");
+ }
+
+@@ -1748,6 +1753,7 @@ void cheetah_plus_parity_error(int type,
+ smp_processor_id(),
+ (type & 0x1) ? 'I' : 'D',
+ regs->tpc);
++ print_symbol(KERN_WARNING "TPC<%s>\n", regs->tpc);
+ }
+
+ struct sun4v_error_entry {
+@@ -1946,6 +1952,7 @@ void sun4v_itlb_error_report(struct pt_r
+
+ printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
+ regs->tpc, tl);
++ print_symbol(KERN_EMERG "SUN4V-ITLB: TPC<%s>\n", regs->tpc);
+ printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] "
+ "pte[%lx] error[%lx]\n",
+ sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
+@@ -1966,6 +1973,7 @@ void sun4v_dtlb_error_report(struct pt_r
+
+ printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
+ regs->tpc, tl);
++ print_symbol(KERN_EMERG "SUN4V-DTLB: TPC<%s>\n", regs->tpc);
+ printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] "
+ "pte[%lx] error[%lx]\n",
+ sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
+diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
+index b097379..bd9de8c 100644
+--- a/arch/sparc64/kernel/vmlinux.lds.S
++++ b/arch/sparc64/kernel/vmlinux.lds.S
+@@ -57,13 +57,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
+index dcba4e6..09cb7fc 100644
+--- a/arch/sparc64/mm/init.c
++++ b/arch/sparc64/mm/init.c
+@@ -920,8 +920,7 @@ static unsigned long __init bootmem_init
+ if (sparc_ramdisk_image || sparc_ramdisk_image64) {
+ unsigned long ramdisk_image = sparc_ramdisk_image ?
+ sparc_ramdisk_image : sparc_ramdisk_image64;
+- if (ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE)
+- ramdisk_image -= KERNBASE;
++ ramdisk_image -= KERNBASE;
+ initrd_start = ramdisk_image + phys_base;
+ initrd_end = initrd_start + sparc_ramdisk_size;
+ if (initrd_end > end_of_phys_memory) {
+diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
+index 0f0eb6a..12a940c 100644
+--- a/arch/sparc64/solaris/fs.c
++++ b/arch/sparc64/solaris/fs.c
+@@ -82,12 +82,17 @@ struct sol_stat64 {
+
+ static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf)
+ {
++ u32 ino;
++
+ if (kbuf->size > MAX_NON_LFS ||
+ !sysv_valid_dev(kbuf->dev) ||
+ !sysv_valid_dev(kbuf->rdev))
+ return -EOVERFLOW;
++ ino = kbuf->ino;
++ if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
++ return -EOVERFLOW;
+ if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) ||
+- __put_user (kbuf->ino, &ubuf->st_ino) ||
++ __put_user (ino, &ubuf->st_ino) ||
+ __put_user (kbuf->mode, &ubuf->st_mode) ||
+ __put_user (kbuf->nlink, &ubuf->st_nlink) ||
+ __put_user (kbuf->uid, &ubuf->st_uid) ||
+diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
+index 8135ec3..9ed9979 100644
+--- a/arch/sparc64/solaris/misc.c
++++ b/arch/sparc64/solaris/misc.c
+@@ -11,6 +11,7 @@
+ #include <linux/limits.h>
+ #include <linux/mm.h>
+ #include <linux/smp.h>
++#include <linux/tty.h>
+ #include <linux/mman.h>
+ #include <linux/file.h>
+ #include <linux/timex.h>
+@@ -248,7 +249,7 @@ asmlinkage int solaris_utssys(u32 buf, u
+ /* Let's cheat */
+ err = set_utsfield(v->sysname, "SunOS", 1, 0);
+ down_read(&uts_sem);
+- err |= set_utsfield(v->nodename, system_utsname.nodename,
++ err |= set_utsfield(v->nodename, utsname()->nodename,
+ 1, 1);
+ up_read(&uts_sem);
+ err |= set_utsfield(v->release, "2.6", 0, 0);
+@@ -272,7 +273,7 @@ asmlinkage int solaris_utsname(u32 buf)
+ /* Why should we not lie a bit? */
+ down_read(&uts_sem);
+ err = set_utsfield(v->sysname, "SunOS", 0, 0);
+- err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1);
++ err |= set_utsfield(v->nodename, utsname()->nodename, 1, 1);
+ err |= set_utsfield(v->release, "5.6", 0, 0);
+ err |= set_utsfield(v->version, "Generic", 0, 0);
+ err |= set_utsfield(v->machine, machine(), 0, 0);
+@@ -304,7 +305,7 @@ asmlinkage int solaris_sysinfo(int cmd,
+ case SI_HOSTNAME:
+ r = buffer + 256;
+ down_read(&uts_sem);
+- for (p = system_utsname.nodename, q = buffer;
++ for (p = utsname()->nodename, q = buffer;
+ q < r && *p && *p != '.'; *q++ = *p++);
+ up_read(&uts_sem);
+ *q = 0;
+@@ -422,7 +423,9 @@ asmlinkage int solaris_procids(int cmd,
+ Solaris setpgrp and setsid? */
+ ret = sys_setpgid(0, 0);
+ if (ret) return ret;
++ mutex_lock(&tty_mutex);
+ current->signal->tty = NULL;
++ mutex_unlock(&tty_mutex);
+ return process_group(current);
+ }
+ case 2: /* getsid */
+@@ -736,20 +739,15 @@ struct exec_domain solaris_exec_domain =
+
+ extern int init_socksys(void);
+
+-#ifdef MODULE
+-
+ MODULE_AUTHOR("Jakub Jelinek (jj at ultra.linux.cz), Patrik Rak (prak3264 at ss1000.ms.mff.cuni.cz)");
+ MODULE_DESCRIPTION("Solaris binary emulation module");
+ MODULE_LICENSE("GPL");
+
+-#ifdef __sparc_v9__
+ extern u32 tl0_solaris[8];
+ #define update_ttable(x) \
+ tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000; \
+ wmb(); \
+ __asm__ __volatile__ ("flush %0" : : "r" (&tl0_solaris[3]))
+-#else
+-#endif
+
+ extern u32 solaris_sparc_syscall[];
+ extern u32 solaris_syscall[];
+@@ -757,7 +755,7 @@ extern void cleanup_socksys(void);
+
+ extern u32 entry64_personality_patch;
+
+-int init_module(void)
++static int __init solaris_init(void)
+ {
+ int ret;
+
+@@ -777,19 +775,12 @@ int init_module(void)
+ return 0;
+ }
+
+-void cleanup_module(void)
++static void __exit solaris_exit(void)
+ {
+ update_ttable(solaris_syscall);
+ cleanup_socksys();
+ unregister_exec_domain(&solaris_exec_domain);
+ }
+
+-#else
+-int init_solaris_emul(void)
+-{
+- register_exec_domain(&solaris_exec_domain);
+- init_socksys();
+- return 0;
+-}
+-#endif
+-
++module_init(solaris_init);
++module_exit(solaris_exit);
+diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
+index bc3df95..7c90e41 100644
+--- a/arch/sparc64/solaris/socksys.c
++++ b/arch/sparc64/solaris/socksys.c
+@@ -168,8 +168,7 @@ static struct file_operations socksys_fo
+ .release = socksys_release,
+ };
+
+-int __init
+-init_socksys(void)
++int __init init_socksys(void)
+ {
+ int ret;
+ struct file * file;
+@@ -199,8 +198,7 @@ init_socksys(void)
+ return 0;
+ }
+
+-void
+-cleanup_socksys(void)
++void __exit cleanup_socksys(void)
+ {
+ if (unregister_chrdev(30, "socksys"))
+ printk ("Couldn't unregister socksys character device\n");
+diff --git a/arch/um/Kconfig b/arch/um/Kconfig
+index 76e85bb..5ac1f29 100644
+--- a/arch/um/Kconfig
++++ b/arch/um/Kconfig
+@@ -1,3 +1,8 @@
++config DEFCONFIG_LIST
++ string
++ option defconfig_list
++ default "arch/$ARCH/defconfig"
++
+ # UML uses the generic IRQ sugsystem
+ config GENERIC_HARDIRQS
+ bool
+@@ -25,6 +30,19 @@ config PCI
+ config PCMCIA
+ bool
+
++# Yet to do!
++config TRACE_IRQFLAGS_SUPPORT
++ bool
++ default n
++
++config LOCKDEP_SUPPORT
++ bool
++ default y
++
++config STACKTRACE_SUPPORT
++ bool
++ default y
++
+ config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+@@ -37,13 +55,16 @@ config IRQ_RELEASE_METHOD
+ menu "UML-specific options"
+
+ config MODE_TT
+- bool "Tracing thread support"
++ bool "Tracing thread support (DEPRECATED)"
+ default n
++ depends on BROKEN
+ help
+ This option controls whether tracing thread support is compiled
+- into UML. This option is largely obsolete, given that skas0 provides
++ into UML. This option is largely obsolete, given that skas0 provides
+ skas security and performance without needing to patch the host.
+- It is safe to say 'N' here.
++ It is safe to say 'N' here; saying 'Y' may cause additional problems
++ with the resulting binary even if you run UML in SKAS mode, and running
++ in TT mode is strongly *NOT RECOMMENDED*.
+
+ config STATIC_LINK
+ bool "Force a static link"
+@@ -56,6 +77,9 @@ config STATIC_LINK
+ for use in a chroot jail. So, if you intend to run UML inside a
+ chroot, and you disable CONFIG_MODE_TT, you probably want to say Y
+ here.
++ Additionally, this option enables using higher memory spaces (up to
++ 2.75G) for UML - disabling CONFIG_MODE_TT and enabling this option leads
++ to best results for this.
+
+ config KERNEL_HALF_GIGS
+ int "Kernel address space size (in .5G units)"
+@@ -72,10 +96,13 @@ config MODE_SKAS
+ default y
+ help
+ This option controls whether skas (separate kernel address space)
+- support is compiled in. If you have applied the skas patch to the
+- host, then you certainly want to say Y here (and consider saying N
+- to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this
+- option will shrink the UML binary slightly.
++ support is compiled in.
++ Unless you have specific needs to use TT mode (which applies almost only
++ to developers), you should say Y here.
++ SKAS mode will make use of the SKAS3 patch if it is applied on the host
++ (and your UML will run in SKAS3 mode), but if no SKAS patch is applied
++ on the host it will run in SKAS0 mode, which is anyway faster than TT
++ mode.
+
+ source "arch/um/Kconfig.arch"
+ source "mm/Kconfig"
+@@ -257,7 +284,7 @@ config UML_REAL_TIME_CLOCK
+ UML and spend long times with UML stopped at a breakpoint. In this
+ case, when UML is restarted, it will call the timer enough times to make
+ up for the time spent at the breakpoint. This could result in a
+- noticable lag. If this is a problem, then disable this option.
++ noticeable lag. If this is a problem, then disable this option.
+
+ endmenu
+
+diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
+index 62d87b7..e03e40c 100644
+--- a/arch/um/Kconfig.char
++++ b/arch/um/Kconfig.char
+@@ -190,6 +190,11 @@ config HOSTAUDIO
+ tristate
+ default UML_SOUND
+
++#It is selected elsewhere, so kconfig would warn without this.
++config HW_RANDOM
++ tristate
++ default n
++
+ config UML_RANDOM
+ tristate "Hardware random number generator"
+ help
+diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
+index f6eb72d..f191a55 100644
+--- a/arch/um/Kconfig.i386
++++ b/arch/um/Kconfig.i386
+@@ -16,23 +16,42 @@ config SEMAPHORE_SLEEPERS
+ bool
+ default y
+
+-config HOST_2G_2G
+- bool "2G/2G host address space split"
+- default n
+- help
+- This is needed when the host on which you run has a 2G/2G memory
+- split, instead of the customary 3G/1G.
+-
+- Note that to enable such a host
+- configuration, which makes sense only in some cases, you need special
+- host patches.
+-
+- So, if you do not know what to do here, say 'N'.
++choice
++ prompt "Host memory split"
++ default HOST_VMSPLIT_3G
++ ---help---
++ This is needed when the host kernel on which you run has a non-default
++ (like 2G/2G) memory split, instead of the customary 3G/1G. If you did
++ not recompile your own kernel but use the default distro's one, you can
++ safely accept the "Default split" option.
++
++ It can be enabled on recent (>=2.6.16-rc2) vanilla kernels via
++ CONFIG_VM_SPLIT_*, or on previous kernels with special patches (-ck
++ patchset by Con Kolivas, or other ones) - option names match closely the
++ host CONFIG_VM_SPLIT_* ones.
++
++ A lower setting (where 1G/3G is lowest and 3G/1G is higher) will
++ tolerate even more "normal" host kernels, but an higher setting will be
++ stricter.
++
++ So, if you do not know what to do here, say 'Default split'.
++
++ config HOST_VMSPLIT_3G
++ bool "Default split (3G/1G user/kernel host split)"
++ config HOST_VMSPLIT_3G_OPT
++ bool "3G/1G user/kernel host split (for full 1G low memory)"
++ config HOST_VMSPLIT_2G
++ bool "2G/2G user/kernel host split"
++ config HOST_VMSPLIT_1G
++ bool "1G/3G user/kernel host split"
++endchoice
+
+ config TOP_ADDR
+- hex
+- default 0xc0000000 if !HOST_2G_2G
+- default 0x80000000 if HOST_2G_2G
++ hex
++ default 0xB0000000 if HOST_VMSPLIT_3G_OPT
++ default 0x78000000 if HOST_VMSPLIT_2G
++ default 0x40000000 if HOST_VMSPLIT_1G
++ default 0xC0000000
+
+ config 3_LEVEL_PGTABLES
+ bool "Three-level pagetables (EXPERIMENTAL)"
+diff --git a/arch/um/Makefile b/arch/um/Makefile
+index f6ad832..5d5ed72 100644
+--- a/arch/um/Makefile
++++ b/arch/um/Makefile
+@@ -64,9 +64,14 @@ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSU
+
+ AFLAGS += $(ARCH_INCLUDE)
+
+-USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
+-USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
+- $(MODE_INCLUDE) -D_FILE_OFFSET_BITS=64
++USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\
++ $(patsubst -I%,,$(CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \
++ -D_FILE_OFFSET_BITS=64
++
++include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
++
++#This will adjust *FLAGS accordingly to the platform.
++include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
+
+ # -Derrno=kernel_errno - This turns all kernel references to errno into
+ # kernel_errno to separate them from the libc errno. This allows -fno-common
+@@ -74,15 +79,11 @@ USER_CFLAGS := $(patsubst -D__KERNEL__,,
+ # errnos.
+ # These apply to kernelspace only.
+
+-CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
+- -Dmktime=kernel_mktime
++KERNEL_DEFINES = -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
++ -Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES)
++CFLAGS += $(KERNEL_DEFINES)
+ CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
+
+-include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
+-
+-#This will adjust *FLAGS accordingly to the platform.
+-include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
+-
+ # These are needed for clean and mrproper, since in that case .config is not
+ # included; the values here are meaningless
+
+@@ -102,7 +103,7 @@ linux: vmlinux
+ define archhelp
+ echo '* linux - Binary kernel image (./linux) - for backward'
+ echo ' compatibility only, this creates a hard link to the'
+- echo ' real kernel binary, the the "vmlinux" binary you'
++ echo ' real kernel binary, the "vmlinux" binary you'
+ echo ' find in the kernel root.'
+ endef
+
+diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
+index b65ca11..c9f1c5b 100644
+--- a/arch/um/Makefile-i386
++++ b/arch/um/Makefile-i386
+@@ -16,7 +16,6 @@ OBJCOPYFLAGS := -O binary -R .note -R
+ ifeq ("$(origin SUBARCH)", "command line")
+ ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)")
+ CFLAGS += $(call cc-option,-m32)
+-USER_CFLAGS += $(call cc-option,-m32)
+ AFLAGS += $(call cc-option,-m32)
+ LINK-y += $(call cc-option,-m32)
+ UML_OBJCOPYFLAGS += -F $(ELF_FORMAT)
+@@ -25,7 +24,7 @@ export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UM
+ endif
+ endif
+
+-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
++ARCH_KERNEL_DEFINES += -U__$(SUBARCH)__ -U$(SUBARCH)
+
+ # First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y.
+ include $(srctree)/arch/i386/Makefile.cpu
+@@ -38,4 +37,3 @@ cflags-y += $(call cc-option,-mpreferred
+ cflags-y += -ffreestanding
+
+ CFLAGS += $(cflags-y)
+-USER_CFLAGS += $(cflags-y)
+diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
+index 9558a7c..69ecea6 100644
+--- a/arch/um/Makefile-x86_64
++++ b/arch/um/Makefile-x86_64
+@@ -1,13 +1,16 @@
+ # Copyright 2003 - 2004 Pathscale, Inc
+ # Released under the GPL
+
+-core-y += arch/um/sys-x86_64/
++core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/
+ START := 0x60000000
+
++_extra_flags_ = -fno-builtin -m64
++
+ #We #undef __x86_64__ for kernelspace, not for userspace where
+ #it's needed for headers to work!
+-CFLAGS += -U__$(SUBARCH)__ -fno-builtin -m64
+-USER_CFLAGS += -fno-builtin -m64
++ARCH_KERNEL_DEFINES = -U__$(SUBARCH)__
++CFLAGS += $(_extra_flags_)
++
+ CHECKFLAGS += -m64
+ AFLAGS += -m64
+ LDFLAGS += -m elf_x86_64
+diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
+index 7218c75..3576b3c 100644
+--- a/arch/um/drivers/chan_kern.c
++++ b/arch/um/drivers/chan_kern.c
+@@ -110,7 +110,7 @@ static void not_configged_free(void *dat
+ "UML\n");
+ }
+
+-static struct chan_ops not_configged_ops = {
++static const struct chan_ops not_configged_ops = {
+ .init = not_configged_init,
+ .open = not_configged_open,
+ .close = not_configged_close,
+@@ -373,7 +373,7 @@ int console_write_chan(struct list_head
+ }
+
+ int console_open_chan(struct line *line, struct console *co,
+- struct chan_opts *opts)
++ const struct chan_opts *opts)
+ {
+ int err;
+
+@@ -494,10 +494,10 @@ int chan_config_string(struct list_head
+
+ struct chan_type {
+ char *key;
+- struct chan_ops *ops;
++ const struct chan_ops *ops;
+ };
+
+-static struct chan_type chan_table[] = {
++static const struct chan_type chan_table[] = {
+ { "fd", &fd_ops },
+
+ #ifdef CONFIG_NULL_CHAN
+@@ -534,17 +534,17 @@ static struct chan_type chan_table[] = {
+ };
+
+ static struct chan *parse_chan(struct line *line, char *str, int device,
+- struct chan_opts *opts)
++ const struct chan_opts *opts)
+ {
+- struct chan_type *entry;
+- struct chan_ops *ops;
++ const struct chan_type *entry;
++ const struct chan_ops *ops;
+ struct chan *chan;
+ void *data;
+ int i;
+
+ ops = NULL;
+ data = NULL;
+- for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
++ for(i = 0; i < ARRAY_SIZE(chan_table); i++){
+ entry = &chan_table[i];
+ if(!strncmp(str, entry->key, strlen(entry->key))){
+ ops = entry->ops;
+@@ -582,7 +582,7 @@ static struct chan *parse_chan(struct li
+ }
+
+ int parse_chan_pair(char *str, struct line *line, int device,
+- struct chan_opts *opts)
++ const struct chan_opts *opts)
+ {
+ struct list_head *chans = &line->chan_list;
+ struct chan *new, *chan;
+diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
+index 7a5b4af..c6a3084 100644
+--- a/arch/um/drivers/cow_sys.h
++++ b/arch/um/drivers/cow_sys.h
+@@ -5,6 +5,7 @@
+ #include "user_util.h"
+ #include "os.h"
+ #include "user.h"
++#include "um_malloc.h"
+
+ static inline void *cow_malloc(int size)
+ {
+diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h
+index 7326c42..3bc3cf6 100644
+--- a/arch/um/drivers/daemon.h
++++ b/arch/um/drivers/daemon.h
+@@ -18,7 +18,7 @@ struct daemon_data {
+ void *dev;
+ };
+
+-extern struct net_user_info daemon_user_info;
++extern const struct net_user_info daemon_user_info;
+
+ extern int daemon_user_write(int fd, void *buf, int len,
+ struct daemon_data *pri);
+diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
+index 53d09ed..8243869 100644
+--- a/arch/um/drivers/daemon_kern.c
++++ b/arch/um/drivers/daemon_kern.c
+@@ -57,7 +57,7 @@ static int daemon_write(int fd, struct s
+ (struct daemon_data *) &lp->user));
+ }
+
+-static struct net_kern_info daemon_kern_info = {
++static const struct net_kern_info daemon_kern_info = {
+ .init = daemon_init,
+ .protocol = eth_protocol,
+ .read = daemon_read,
+diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
+index c944265..310af0f 100644
+--- a/arch/um/drivers/daemon_user.c
++++ b/arch/um/drivers/daemon_user.c
+@@ -17,6 +17,7 @@
+ #include "user_util.h"
+ #include "user.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+@@ -182,7 +183,7 @@ static int daemon_set_mtu(int mtu, void
+ return(mtu);
+ }
+
+-struct net_user_info daemon_user_info = {
++const struct net_user_info daemon_user_info = {
+ .init = daemon_user_init,
+ .open = daemon_open,
+ .close = NULL,
+diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
+index c41f75e..218aa0e 100644
+--- a/arch/um/drivers/fd.c
++++ b/arch/um/drivers/fd.c
+@@ -12,6 +12,7 @@
+ #include "user_util.h"
+ #include "chan_user.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ struct fd_chan {
+ int fd;
+@@ -20,7 +21,7 @@ struct fd_chan {
+ char str[sizeof("1234567890\0")];
+ };
+
+-static void *fd_init(char *str, int device, struct chan_opts *opts)
++static void *fd_init(char *str, int device, const struct chan_opts *opts)
+ {
+ struct fd_chan *data;
+ char *end;
+@@ -77,7 +78,7 @@ static void fd_close(int fd, void *d)
+ }
+ }
+
+-struct chan_ops fd_ops = {
++const struct chan_ops fd_ops = {
+ .type = "fd",
+ .init = fd_init,
+ .open = fd_open,
+diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
+index 37232f9..a0d148e 100644
+--- a/arch/um/drivers/hostaudio_kern.c
++++ b/arch/um/drivers/hostaudio_kern.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/module.h"
+ #include "linux/init.h"
+ #include "linux/slab.h"
+@@ -280,7 +279,7 @@ static int hostmixer_release(struct inod
+
+ /* kernel module operations */
+
+-static struct file_operations hostaudio_fops = {
++static const struct file_operations hostaudio_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = hostaudio_read,
+@@ -292,7 +291,7 @@ static struct file_operations hostaudio_
+ .release = hostaudio_release,
+ };
+
+-static struct file_operations hostmixer_fops = {
++static const struct file_operations hostmixer_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = hostmixer_ioctl_mixdev,
+diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
+index ebebaab..426633e 100644
+--- a/arch/um/drivers/line.c
++++ b/arch/um/drivers/line.c
+@@ -20,7 +20,7 @@
+
+ #define LINE_BUFSIZE 4096
+
+-static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
++static irqreturn_t line_interrupt(int irq, void *data)
+ {
+ struct chan *chan = data;
+ struct line *line = chan->line;
+@@ -251,7 +251,7 @@ void line_set_termios(struct tty_struct
+ /* nothing */
+ }
+
+-static struct {
++static const struct {
+ int cmd;
+ char *level;
+ char *name;
+@@ -364,8 +364,7 @@ void line_unthrottle(struct tty_struct *
+ reactivate_chan(&line->chan_list, line->driver->read_irq);
+ }
+
+-static irqreturn_t line_write_interrupt(int irq, void *data,
+- struct pt_regs *unused)
++static irqreturn_t line_write_interrupt(int irq, void *data)
+ {
+ struct chan *chan = data;
+ struct line *line = chan->line;
+@@ -405,7 +404,7 @@ static irqreturn_t line_write_interrupt(
+
+ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
+ {
+- struct line_driver *driver = line->driver;
++ const struct line_driver *driver = line->driver;
+ int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
+
+ if (input)
+@@ -497,7 +496,7 @@ void close_lines(struct line *lines, int
+ }
+
+ /* Common setup code for both startup command line and mconsole initialization.
+- * @lines contains the the array (of size @num) to modify;
++ * @lines contains the array (of size @num) to modify;
+ * @init is the setup string;
+ */
+
+@@ -558,7 +557,7 @@ int line_setup(struct line *lines, unsig
+ }
+
+ int line_config(struct line *lines, unsigned int num, char *str,
+- struct chan_opts *opts)
++ const struct chan_opts *opts)
+ {
+ struct line *line;
+ char *new;
+@@ -642,9 +641,9 @@ int line_remove(struct line *lines, unsi
+ }
+
+ struct tty_driver *line_register_devfs(struct lines *set,
+- struct line_driver *line_driver,
+- struct tty_operations *ops, struct line *lines,
+- int nlines)
++ struct line_driver *line_driver,
++ const struct tty_operations *ops,
++ struct line *lines, int nlines)
+ {
+ int i;
+ struct tty_driver *driver = alloc_tty_driver(nlines);
+@@ -712,7 +711,7 @@ struct winch {
+ struct tty_struct *tty;
+ };
+
+-static irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
++static irqreturn_t winch_interrupt(int irq, void *data)
+ {
+ struct winch *winch = data;
+ struct tty_struct *tty;
+diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
+index a2c6db2..bc56af9 100644
+--- a/arch/um/drivers/mcast.h
++++ b/arch/um/drivers/mcast.h
+@@ -13,7 +13,7 @@ struct mcast_data {
+ void *dev;
+ };
+
+-extern struct net_user_info mcast_user_info;
++extern const struct net_user_info mcast_user_info;
+
+ extern int mcast_user_write(int fd, void *buf, int len,
+ struct mcast_data *pri);
+diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
+index 3a7af18..c090fbd 100644
+--- a/arch/um/drivers/mcast_kern.c
++++ b/arch/um/drivers/mcast_kern.c
+@@ -61,7 +61,7 @@ static int mcast_write(int fd, struct sk
+ (struct mcast_data *) &lp->user);
+ }
+
+-static struct net_kern_info mcast_kern_info = {
++static const struct net_kern_info mcast_kern_info = {
+ .init = mcast_init,
+ .protocol = eth_protocol,
+ .read = mcast_read,
+diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
+index afe85bf..8138f5e 100644
+--- a/arch/um/drivers/mcast_user.c
++++ b/arch/um/drivers/mcast_user.c
+@@ -23,6 +23,7 @@
+ #include "user_util.h"
+ #include "user.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+@@ -152,7 +153,7 @@ static int mcast_set_mtu(int mtu, void *
+ return(mtu);
+ }
+
+-struct net_user_info mcast_user_info = {
++const struct net_user_info mcast_user_info = {
+ .init = mcast_user_init,
+ .open = mcast_open,
+ .close = mcast_close,
+diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
+index b414522..7b17216 100644
+--- a/arch/um/drivers/mconsole_kern.c
++++ b/arch/um/drivers/mconsole_kern.c
+@@ -74,13 +74,12 @@ static void mc_work_proc(void *unused)
+
+ static DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
+
+-static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t mconsole_interrupt(int irq, void *dev_id)
+ {
+ /* long to avoid size mismatch warnings from gcc */
+ long fd;
+ struct mconsole_entry *new;
+- struct mc_request req;
++ static struct mc_request req; /* that's OK */
+
+ fd = (long) dev_id;
+ while (mconsole_get_request(fd, &req)){
+@@ -92,6 +91,7 @@ static irqreturn_t mconsole_interrupt(in
+ mconsole_reply(&req, "Out of memory", 1, 0);
+ else {
+ new->request = req;
++ new->request.regs = get_irq_regs()->regs;
+ list_add(&new->list, &mc_requests);
+ }
+ }
+@@ -106,9 +106,9 @@ void mconsole_version(struct mc_request
+ {
+ char version[256];
+
+- sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
+- system_utsname.nodename, system_utsname.release,
+- system_utsname.version, system_utsname.machine);
++ sprintf(version, "%s %s %s %s %s", utsname()->sysname,
++ utsname()->nodename, utsname()->release,
++ utsname()->version, utsname()->machine);
+ mconsole_reply(req, version, 0, 0);
+ }
+
+@@ -315,9 +315,21 @@ void mconsole_stop(struct mc_request *re
+ {
+ deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
+ os_set_fd_block(req->originating_fd, 1);
+- mconsole_reply(req, "", 0, 0);
+- while(mconsole_get_request(req->originating_fd, req)){
+- if(req->cmd->handler == mconsole_go) break;
++ mconsole_reply(req, "stopped", 0, 0);
++ while (mconsole_get_request(req->originating_fd, req)) {
++ if (req->cmd->handler == mconsole_go)
++ break;
++ if (req->cmd->handler == mconsole_stop) {
++ mconsole_reply(req, "Already stopped", 1, 0);
++ continue;
++ }
++ if (req->cmd->handler == mconsole_sysrq) {
++ struct pt_regs *old_regs;
++ old_regs = set_irq_regs((struct pt_regs *)&req->regs);
++ mconsole_sysrq(req);
++ set_irq_regs(old_regs);
++ continue;
++ }
+ (*req->cmd->handler)(req);
+ }
+ os_set_fd_block(req->originating_fd, 0);
+@@ -497,7 +509,7 @@ static void mconsole_get_config(int (*ge
+ }
+
+ error = NULL;
+- size = sizeof(default_buf)/sizeof(default_buf[0]);
++ size = ARRAY_SIZE(default_buf);
+ buf = default_buf;
+
+ while(1){
+@@ -598,6 +610,11 @@ out:
+ mconsole_reply(req, err_msg, err, 0);
+ }
+
++struct mconsole_output {
++ struct list_head list;
++ struct mc_request *req;
++};
++
+ static DEFINE_SPINLOCK(console_lock);
+ static LIST_HEAD(clients);
+ static char console_buf[MCONSOLE_MAX_DATA];
+@@ -622,10 +639,10 @@ static void console_write(struct console
+ return;
+
+ list_for_each(ele, &clients){
+- struct mconsole_entry *entry;
++ struct mconsole_output *entry;
+
+- entry = list_entry(ele, struct mconsole_entry, list);
+- mconsole_reply_len(&entry->request, console_buf,
++ entry = list_entry(ele, struct mconsole_output, list);
++ mconsole_reply_len(entry->req, console_buf,
+ console_index, 0, 1);
+ }
+
+@@ -649,10 +666,10 @@ late_initcall(mc_add_console);
+ static void with_console(struct mc_request *req, void (*proc)(void *),
+ void *arg)
+ {
+- struct mconsole_entry entry;
++ struct mconsole_output entry;
+ unsigned long flags;
+
+- entry.request = *req;
++ entry.req = req;
+ list_add(&entry.list, &clients);
+ spin_lock_irqsave(&console_lock, flags);
+
+@@ -669,8 +686,7 @@ static void with_console(struct mc_reque
+ static void sysrq_proc(void *arg)
+ {
+ char *op = arg;
+-
+- handle_sysrq(*op, ¤t->thread.regs, NULL);
++ handle_sysrq(*op, NULL);
+ }
+
+ void mconsole_sysrq(struct mc_request *req)
+diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
+index 9bfd405..75aef6f 100644
+--- a/arch/um/drivers/mconsole_user.c
++++ b/arch/um/drivers/mconsole_user.c
+@@ -14,8 +14,10 @@
+ #include <sys/un.h>
+ #include <unistd.h>
+ #include "user.h"
++#include "sysdep/ptrace.h"
+ #include "mconsole.h"
+ #include "umid.h"
++#include "user_util.h"
+
+ static struct mconsole_command commands[] = {
+ /* With uts namespaces, uts information becomes process-specific, so
+@@ -65,14 +67,14 @@ static struct mconsole_command *mconsole
+ struct mconsole_command *cmd;
+ int i;
+
+- for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
++ for(i = 0; i < ARRAY_SIZE(commands); i++){
+ cmd = &commands[i];
+ if(!strncmp(req->request.data, cmd->command,
+ strlen(cmd->command))){
+- return(cmd);
++ return cmd;
+ }
+ }
+- return(NULL);
++ return NULL;
+ }
+
+ #define MIN(a,b) ((a)<(b) ? (a):(b))
+@@ -130,6 +132,10 @@ int mconsole_get_request(int fd, struct
+ int mconsole_reply_len(struct mc_request *req, const char *str, int total,
+ int err, int more)
+ {
++ /* XXX This is a stack consumption problem. It'd be nice to
++ * make it global and serialize access to it, but there are a
++ * ton of callers to this function.
++ */
+ struct mconsole_reply reply;
+ int len, n;
+
+diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
+index 022f67b..df3516e 100644
+--- a/arch/um/drivers/mmapper_kern.c
++++ b/arch/um/drivers/mmapper_kern.c
+@@ -85,7 +85,7 @@ mmapper_release(struct inode *inode, str
+ return 0;
+ }
+
+-static struct file_operations mmapper_fops = {
++static const struct file_operations mmapper_fops = {
+ .owner = THIS_MODULE,
+ .read = mmapper_read,
+ .write = mmapper_write,
+@@ -95,6 +95,7 @@ static struct file_operations mmapper_fo
+ .release = mmapper_release,
+ };
+
++/* No locking needed - only used (and modified) by below initcall and exitcall. */
+ static struct miscdevice mmapper_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mmapper",
+diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
+index 501f956..ec9eb8b 100644
+--- a/arch/um/drivers/net_kern.c
++++ b/arch/um/drivers/net_kern.c
+@@ -5,7 +5,6 @@
+ * Licensed under the GPL.
+ */
+
+-#include "linux/config.h"
+ #include "linux/kernel.h"
+ #include "linux/netdevice.h"
+ #include "linux/rtnetlink.h"
+@@ -31,6 +30,11 @@
+ #include "irq_user.h"
+ #include "irq_kern.h"
+
++static inline void set_ether_mac(struct net_device *dev, unsigned char *addr)
++{
++ memcpy(dev->dev_addr, addr, ETH_ALEN);
++}
++
+ #define DRIVER_NAME "uml-netdev"
+
+ static DEFINE_SPINLOCK(opened_lock);
+@@ -73,7 +77,7 @@ static void uml_dev_close(void* dev)
+ dev_close( (struct net_device *) dev);
+ }
+
+-irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t uml_net_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct uml_net_private *lp = dev->priv;
+@@ -109,18 +113,11 @@ static int uml_net_open(struct net_devic
+ struct uml_net_private *lp = dev->priv;
+ int err;
+
+- spin_lock(&lp->lock);
+-
+ if(lp->fd >= 0){
+ err = -ENXIO;
+ goto out;
+ }
+
+- if(!lp->have_mac){
+- dev_ip_addr(dev, &lp->mac[2]);
+- set_ether_mac(dev, lp->mac);
+- }
+-
+ lp->fd = (*lp->open)(&lp->user);
+ if(lp->fd < 0){
+ err = lp->fd;
+@@ -144,8 +141,6 @@ static int uml_net_open(struct net_devic
+ */
+ while((err = uml_net_rx(dev)) > 0) ;
+
+- spin_unlock(&lp->lock);
+-
+ spin_lock(&opened_lock);
+ list_add(&lp->list, &opened);
+ spin_unlock(&opened_lock);
+@@ -155,7 +150,6 @@ out_close:
+ if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
+ lp->fd = -1;
+ out:
+- spin_unlock(&lp->lock);
+ return err;
+ }
+
+@@ -164,15 +158,12 @@ static int uml_net_close(struct net_devi
+ struct uml_net_private *lp = dev->priv;
+
+ netif_stop_queue(dev);
+- spin_lock(&lp->lock);
+
+ free_irq(dev->irq, dev);
+ if(lp->close != NULL)
+ (*lp->close)(lp->fd, &lp->user);
+ lp->fd = -1;
+
+- spin_unlock(&lp->lock);
+-
+ spin_lock(&opened_lock);
+ list_del(&lp->list);
+ spin_unlock(&opened_lock);
+@@ -241,9 +232,9 @@ static int uml_net_set_mac(struct net_de
+ struct uml_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);
++ spin_lock_irq(&lp->lock);
++ set_ether_mac(dev, hwaddr->sa_data);
++ spin_unlock_irq(&lp->lock);
+
+ return(0);
+ }
+@@ -253,7 +244,7 @@ static int uml_net_change_mtu(struct net
+ struct uml_net_private *lp = dev->priv;
+ int err = 0;
+
+- spin_lock(&lp->lock);
++ spin_lock_irq(&lp->lock);
+
+ new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
+ if(new_mtu < 0){
+@@ -264,7 +255,7 @@ static int uml_net_change_mtu(struct net
+ dev->mtu = new_mtu;
+
+ out:
+- spin_unlock(&lp->lock);
++ spin_unlock_irq(&lp->lock);
+ return err;
+ }
+
+@@ -290,6 +281,37 @@ void uml_net_user_timer_expire(unsigned
+ #endif
+ }
+
++static void setup_etheraddr(char *str, unsigned char *addr)
++{
++ char *end;
++ int i;
++
++ if(str == NULL)
++ goto random;
++
++ for(i=0;i<6;i++){
++ addr[i] = simple_strtoul(str, &end, 16);
++ if((end == str) ||
++ ((*end != ':') && (*end != ',') && (*end != '\0'))){
++ printk(KERN_ERR
++ "setup_etheraddr: failed to parse '%s' "
++ "as an ethernet address\n", str);
++ goto random;
++ }
++ str = end + 1;
++ }
++ if(addr[0] & 1){
++ printk(KERN_ERR
++ "Attempt to assign a broadcast ethernet address to a "
++ "device disallowed\n");
++ goto random;
++ }
++ return;
++
++random:
++ random_ether_addr(addr);
++}
++
+ static DEFINE_SPINLOCK(devices_lock);
+ static LIST_HEAD(devices);
+
+@@ -325,15 +347,13 @@ static int eth_configure(int n, void *in
+ list_add(&device->list, &devices);
+ spin_unlock(&devices_lock);
+
+- if (setup_etheraddr(mac, device->mac))
+- device->have_mac = 1;
++ setup_etheraddr(mac, device->mac);
+
+ printk(KERN_INFO "Netdevice %d ", n);
+- if (device->have_mac)
+- printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
+- device->mac[0], device->mac[1],
+- device->mac[2], device->mac[3],
+- device->mac[4], device->mac[5]);
++ printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
++ device->mac[0], device->mac[1],
++ device->mac[2], device->mac[3],
++ device->mac[4], device->mac[5]);
+ printk(": ");
+ dev = alloc_etherdev(size);
+ if (dev == NULL) {
+@@ -399,7 +419,6 @@ static int eth_configure(int n, void *in
+ .dev = dev,
+ .fd = -1,
+ .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
+- .have_mac = device->have_mac,
+ .protocol = transport->kern->protocol,
+ .open = transport->user->open,
+ .close = transport->user->close,
+@@ -414,14 +433,12 @@ static int eth_configure(int n, void *in
+ init_timer(&lp->tl);
+ spin_lock_init(&lp->lock);
+ lp->tl.function = uml_net_user_timer_expire;
+- if (lp->have_mac)
+- memcpy(lp->mac, device->mac, sizeof(lp->mac));
++ memcpy(lp->mac, device->mac, sizeof(lp->mac));
+
+ if (transport->user->init)
+ (*transport->user->init)(&lp->user, dev);
+
+- if (device->have_mac)
+- set_ether_mac(dev, device->mac);
++ set_ether_mac(dev, device->mac);
+
+ return 0;
+ }
+@@ -564,12 +581,13 @@ static int eth_setup(char *str)
+ int n, err;
+
+ err = eth_parse(str, &n, &str);
+- if(err) return(1);
++ if(err)
++ return 1;
+
+- new = alloc_bootmem(sizeof(new));
++ new = alloc_bootmem(sizeof(*new));
+ if (new == NULL){
+ printk("eth_init : alloc_bootmem failed\n");
+- return(1);
++ return 1;
+ }
+
+ INIT_LIST_HEAD(&new->list);
+@@ -577,7 +595,7 @@ static int eth_setup(char *str)
+ new->init = str;
+
+ list_add_tail(&new->list, ð_cmd_line);
+- return(1);
++ return 1;
+ }
+
+ __setup("eth", eth_setup);
+@@ -749,54 +767,6 @@ static void close_devices(void)
+
+ __uml_exitcall(close_devices);
+
+-int setup_etheraddr(char *str, unsigned char *addr)
+-{
+- char *end;
+- int i;
+-
+- if(str == NULL)
+- return(0);
+- for(i=0;i<6;i++){
+- addr[i] = simple_strtoul(str, &end, 16);
+- if((end == str) ||
+- ((*end != ':') && (*end != ',') && (*end != '\0'))){
+- printk(KERN_ERR
+- "setup_etheraddr: failed to parse '%s' "
+- "as an ethernet address\n", str);
+- return(0);
+- }
+- str = end + 1;
+- }
+- if(addr[0] & 1){
+- printk(KERN_ERR
+- "Attempt to assign a broadcast ethernet address to a "
+- "device disallowed\n");
+- return(0);
+- }
+- return(1);
+-}
+-
+-void dev_ip_addr(void *d, unsigned char *bin_buf)
+-{
+- struct net_device *dev = d;
+- struct in_device *ip = dev->ip_ptr;
+- struct in_ifaddr *in;
+-
+- if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
+- printk(KERN_WARNING "dev_ip_addr - device not assigned an "
+- "IP address\n");
+- return;
+- }
+- memcpy(bin_buf, &in->ifa_address, sizeof(in->ifa_address));
+-}
+-
+-void set_ether_mac(void *d, unsigned char *addr)
+-{
+- struct net_device *dev = d;
+-
+- memcpy(dev->dev_addr, addr, ETH_ALEN);
+-}
+-
+ struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
+ {
+ if((skb != NULL) && (skb_tailroom(skb) < extra)){
+@@ -834,7 +804,7 @@ int dev_netmask(void *d, void *m)
+ struct net_device *dev = d;
+ struct in_device *ip = dev->ip_ptr;
+ struct in_ifaddr *in;
+- __u32 *mask_out = m;
++ __be32 *mask_out = m;
+
+ if(ip == NULL)
+ return(1);
+diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
+index 107c5e4..0ffd7ac 100644
+--- a/arch/um/drivers/net_user.c
++++ b/arch/um/drivers/net_user.c
+@@ -12,11 +12,13 @@
+ #include <string.h>
+ #include <sys/socket.h>
+ #include <sys/wait.h>
++#include <sys/time.h>
+ #include "user.h"
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "net_user.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ int tap_open_common(void *dev, char *gate_addr)
+ {
+diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
+index 14cc5f7..9016c68 100644
+--- a/arch/um/drivers/null.c
++++ b/arch/um/drivers/null.c
+@@ -8,9 +8,10 @@
+ #include "chan_user.h"
+ #include "os.h"
+
++/* This address is used only as a unique identifer */
+ static int null_chan;
+
+-static void *null_init(char *str, int device, struct chan_opts *opts)
++static void *null_init(char *str, int device, const struct chan_opts *opts)
+ {
+ return(&null_chan);
+ }
+@@ -31,7 +32,7 @@ static void null_free(void *data)
+ {
+ }
+
+-struct chan_ops null_ops = {
++const struct chan_ops null_ops = {
+ .type = "null",
+ .init = null_init,
+ .open = null_open,
+diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
+index 466ff2c..6e1ef85 100644
+--- a/arch/um/drivers/pcap_kern.c
++++ b/arch/um/drivers/pcap_kern.c
+@@ -46,7 +46,7 @@ static int pcap_write(int fd, struct sk_
+ return(-EPERM);
+ }
+
+-static struct net_kern_info pcap_kern_info = {
++static const struct net_kern_info pcap_kern_info = {
+ .init = pcap_init,
+ .protocol = eth_protocol,
+ .read = pcap_read,
+@@ -76,7 +76,7 @@ int pcap_setup(char *str, char **mac_out
+ if(host_if != NULL)
+ init->host_if = host_if;
+
+- for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
++ for(i = 0; i < ARRAY_SIZE(options); i++){
+ if(options[i] == NULL)
+ continue;
+ if(!strcmp(options[i], "promisc"))
+diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
+index edfcb29..11921a7 100644
+--- a/arch/um/drivers/pcap_user.c
++++ b/arch/um/drivers/pcap_user.c
+@@ -12,6 +12,7 @@
+ #include "net_user.h"
+ #include "pcap_user.h"
+ #include "user.h"
++#include "um_malloc.h"
+
+ #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+@@ -120,7 +121,7 @@ int pcap_user_read(int fd, void *buffer,
+ return(hdata.len);
+ }
+
+-struct net_user_info pcap_user_info = {
++const struct net_user_info pcap_user_info = {
+ .init = pcap_user_init,
+ .open = pcap_open,
+ .close = NULL,
+diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h
+index 58f9f6a..96b80b5 100644
+--- a/arch/um/drivers/pcap_user.h
++++ b/arch/um/drivers/pcap_user.h
+@@ -15,7 +15,7 @@ struct pcap_data {
+ void *dev;
+ };
+
+-extern struct net_user_info pcap_user_info;
++extern const struct net_user_info pcap_user_info;
+
+ extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
+
+diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
+index 73755f3..ce9f373 100644
+--- a/arch/um/drivers/port_kern.c
++++ b/arch/um/drivers/port_kern.c
+@@ -47,7 +47,7 @@ struct connection {
+ struct port_list *port;
+ };
+
+-static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t pipe_interrupt(int irq, void *data)
+ {
+ struct connection *conn = data;
+ int fd;
+@@ -152,7 +152,7 @@ void port_work_proc(void *unused)
+
+ DECLARE_WORK(port_work, port_work_proc, NULL);
+
+-static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t port_interrupt(int irq, void *data)
+ {
+ struct port_list *port = data;
+
+diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
+index c43e8bb..bc6afaf 100644
+--- a/arch/um/drivers/port_user.c
++++ b/arch/um/drivers/port_user.c
+@@ -19,6 +19,7 @@
+ #include "chan_user.h"
+ #include "port.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ struct port_chan {
+ int raw;
+@@ -27,7 +28,7 @@ struct port_chan {
+ char dev[sizeof("32768\0")];
+ };
+
+-static void *port_init(char *str, int device, struct chan_opts *opts)
++static void *port_init(char *str, int device, const struct chan_opts *opts)
+ {
+ struct port_chan *data;
+ void *kern_data;
+@@ -100,7 +101,7 @@ static void port_close(int fd, void *d)
+ os_close_file(fd);
+ }
+
+-struct chan_ops port_ops = {
++const struct chan_ops port_ops = {
+ .type = "port",
+ .init = port_init,
+ .open = port_open,
+diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
+index 1c555c3..829a5ec 100644
+--- a/arch/um/drivers/pty.c
++++ b/arch/um/drivers/pty.c
+@@ -13,6 +13,7 @@
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ struct pty_chan {
+ void (*announce)(char *dev_name, int dev);
+@@ -22,7 +23,7 @@ struct pty_chan {
+ char dev_name[sizeof("/dev/pts/0123456\0")];
+ };
+
+-static void *pty_chan_init(char *str, int device, struct chan_opts *opts)
++static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
+ {
+ struct pty_chan *data;
+
+@@ -118,7 +119,7 @@ static int pty_open(int input, int outpu
+ return(fd);
+ }
+
+-struct chan_ops pty_ops = {
++const struct chan_ops pty_ops = {
+ .type = "pty",
+ .init = pty_chan_init,
+ .open = pty_open,
+@@ -131,7 +132,7 @@ struct chan_ops pty_ops = {
+ .winch = 0,
+ };
+
+-struct chan_ops pts_ops = {
++const struct chan_ops pts_ops = {
+ .type = "pts",
+ .init = pty_chan_init,
+ .open = pts_open,
+diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
+index ba471f5..73b2bdd 100644
+--- a/arch/um/drivers/random.c
++++ b/arch/um/drivers/random.c
+@@ -20,6 +20,10 @@
+
+ #define RNG_MISCDEV_MINOR 183 /* official */
+
++/* Changed at init time, in the non-modular case, and at module load
++ * time, in the module case. Presumably, the module subsystem
++ * protects against a module being loaded twice at the same time.
++ */
+ static int random_fd = -1;
+
+ static int rng_dev_open (struct inode *inode, struct file *filp)
+@@ -68,7 +72,7 @@ static ssize_t rng_dev_read (struct file
+ return ret;
+ }
+
+-static struct file_operations rng_chrdev_ops = {
++static const struct file_operations rng_chrdev_ops = {
+ .owner = THIS_MODULE,
+ .open = rng_dev_open,
+ .read = rng_dev_read,
+diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
+index bb0dab4..c64f8c6 100644
+--- a/arch/um/drivers/slip.h
++++ b/arch/um/drivers/slip.h
+@@ -12,7 +12,7 @@ struct slip_data {
+ struct slip_proto slip;
+ };
+
+-extern struct net_user_info slip_user_info;
++extern const struct net_user_info slip_user_info;
+
+ extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
+ extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
+diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
+index 163ee0d..788da54 100644
+--- a/arch/um/drivers/slip_kern.c
++++ b/arch/um/drivers/slip_kern.c
+@@ -1,4 +1,3 @@
+-#include "linux/config.h"
+ #include "linux/kernel.h"
+ #include "linux/stddef.h"
+ #include "linux/init.h"
+@@ -61,7 +60,7 @@ static int slip_write(int fd, struct sk_
+ (struct slip_data *) &lp->user));
+ }
+
+-struct net_kern_info slip_kern_info = {
++const struct net_kern_info slip_kern_info = {
+ .init = slip_init,
+ .protocol = slip_protocol,
+ .read = slip_read,
+diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
+index 89fbec1..7eddacc 100644
+--- a/arch/um/drivers/slip_user.c
++++ b/arch/um/drivers/slip_user.c
+@@ -15,6 +15,7 @@
+ #include "slip.h"
+ #include "slip_common.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ void slip_user_init(void *data, void *dev)
+ {
+@@ -241,7 +242,7 @@ static void slip_del_addr(unsigned char
+ close_addr(addr, netmask, pri->name);
+ }
+
+-struct net_user_info slip_user_info = {
++const struct net_user_info slip_user_info = {
+ .init = slip_user_init,
+ .open = slip_open,
+ .close = slip_close,
+diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
+index 6cf88ab..89ccf83 100644
+--- a/arch/um/drivers/slirp.h
++++ b/arch/um/drivers/slirp.h
+@@ -24,7 +24,7 @@ struct slirp_data {
+ struct slip_proto slip;
+ };
+
+-extern struct net_user_info slirp_user_info;
++extern const struct net_user_info slirp_user_info;
+
+ extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
+ extern int slirp_user_write(int fd, void *buf, int len,
+diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
+index 95e50c9..ae322e1 100644
+--- a/arch/um/drivers/slirp_kern.c
++++ b/arch/um/drivers/slirp_kern.c
+@@ -64,7 +64,7 @@ static int slirp_write(int fd, struct sk
+ (struct slirp_data *) &lp->user));
+ }
+
+-struct net_kern_info slirp_kern_info = {
++const struct net_kern_info slirp_kern_info = {
+ .init = slirp_init,
+ .protocol = slirp_protocol,
+ .read = slirp_read,
+diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
+index 33c5f6e..ce5e85d 100644
+--- a/arch/um/drivers/slirp_user.c
++++ b/arch/um/drivers/slirp_user.c
+@@ -126,7 +126,7 @@ static int slirp_set_mtu(int mtu, void *
+ return(mtu);
+ }
+
+-struct net_user_info slirp_user_info = {
++const struct net_user_info slirp_user_info = {
+ .init = slirp_user_init,
+ .open = slirp_open,
+ .close = slirp_close,
+diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
+index 6dafd6f..ed9c590 100644
+--- a/arch/um/drivers/ssl.c
++++ b/arch/um/drivers/ssl.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/fs.h"
+ #include "linux/tty.h"
+ #include "linux/tty_driver.h"
+@@ -23,7 +22,7 @@
+ #include "irq_user.h"
+ #include "mconsole_kern.h"
+
+-static int ssl_version = 1;
++static const int ssl_version = 1;
+
+ /* Referenced only by tty_driver below - presumably it's locked correctly
+ * by the tty driver.
+@@ -123,7 +122,7 @@ void ssl_hangup(struct tty_struct *tty)
+ }
+ #endif
+
+-static struct tty_operations ssl_ops = {
++static const struct tty_operations ssl_ops = {
+ .open = ssl_open,
+ .close = line_close,
+ .write = line_write,
+diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c
+index 6d2cf32..9115392 100644
+--- a/arch/um/drivers/stderr_console.c
++++ b/arch/um/drivers/stderr_console.c
+@@ -9,6 +9,8 @@
+ /*
+ * Don't register by default -- as this registeres very early in the
+ * boot process it becomes the default console.
++ *
++ * Initialized at init time.
+ */
+ static int use_stderr_console = 0;
+
+diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
+index 856f568..7a4897e 100644
+--- a/arch/um/drivers/stdio_console.c
++++ b/arch/um/drivers/stdio_console.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/posix_types.h"
+ #include "linux/tty.h"
+ #include "linux/tty_flip.h"
+@@ -108,9 +107,10 @@ static int con_open(struct tty_struct *t
+ return line_open(vts, tty);
+ }
+
++/* Set in an initcall, checked in an exitcall */
+ static int con_init_done = 0;
+
+-static struct tty_operations console_ops = {
++static const struct tty_operations console_ops = {
+ .open = con_open,
+ .close = line_close,
+ .write = line_write,
+diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
+index 9f70edf..d95d643 100644
+--- a/arch/um/drivers/tty.c
++++ b/arch/um/drivers/tty.c
+@@ -11,6 +11,7 @@
+ #include "user_util.h"
+ #include "user.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ struct tty_chan {
+ char *dev;
+@@ -18,7 +19,7 @@ struct tty_chan {
+ struct termios tt;
+ };
+
+-static void *tty_chan_init(char *str, int device, struct chan_opts *opts)
++static void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
+ {
+ struct tty_chan *data;
+
+@@ -62,7 +63,7 @@ static int tty_open(int input, int outpu
+ return fd;
+ }
+
+-struct chan_ops tty_ops = {
++const struct chan_ops tty_ops = {
+ .type = "tty",
+ .init = tty_chan_init,
+ .open = tty_open,
+diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
+index 3408531..49c047b 100644
+--- a/arch/um/drivers/ubd_kern.c
++++ b/arch/um/drivers/ubd_kern.c
+@@ -20,7 +20,6 @@
+ #define MAJOR_NR UBD_MAJOR
+ #define UBD_SHIFT 4
+
+-#include "linux/config.h"
+ #include "linux/module.h"
+ #include "linux/blkdev.h"
+ #include "linux/hdreg.h"
+@@ -107,10 +106,15 @@ static inline void ubd_set_bit(__u64 bit
+
+ #define DRIVER_NAME "uml-blkdev"
+
++/* Can be taken in interrupt context, and is passed to the block layer to lock
++ * the request queue. Kernel side code knows that. */
+ static DEFINE_SPINLOCK(ubd_io_lock);
+-static DEFINE_SPINLOCK(ubd_lock);
+
+-static void (*do_ubd)(void);
++static DEFINE_MUTEX(ubd_lock);
++
++/* XXX - this made sense in 2.4 days, now it's only used as a boolean, and
++ * probably it doesn't make sense even for that. */
++static int do_ubd;
+
+ static int ubd_open(struct inode * inode, struct file * filp);
+ static int ubd_release(struct inode * inode, struct file * file);
+@@ -118,7 +122,7 @@ static int ubd_ioctl(struct inode * inod
+ unsigned int cmd, unsigned long arg);
+ static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
+
+-#define MAX_DEV (8)
++#define MAX_DEV (16)
+
+ static struct block_device_operations ubd_blops = {
+ .owner = THIS_MODULE,
+@@ -151,8 +155,9 @@ static struct gendisk *fake_gendisk[MAX_
+ static struct openflags global_openflags = OPEN_FLAGS;
+
+ struct cow {
+- /* This is the backing file, actually */
++ /* backing file name */
+ char *file;
++ /* backing file fd */
+ int fd;
+ unsigned long *bitmap;
+ unsigned long bitmap_len;
+@@ -161,14 +166,16 @@ struct cow {
+ };
+
+ struct ubd {
++ /* name (and fd, below) of the file opened for writing, either the
++ * backing or the cow file. */
+ char *file;
+ int count;
+ int fd;
+ __u64 size;
+ struct openflags boot_openflags;
+ struct openflags openflags;
+- int shared;
+- int no_cow;
++ unsigned shared:1;
++ unsigned no_cow:1;
+ struct cow cow;
+ struct platform_device pdev;
+ };
+@@ -193,18 +200,7 @@ struct ubd {
+ .cow = DEFAULT_COW, \
+ }
+
+-struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
+-
+-static int ubd0_init(void)
+-{
+- struct ubd *dev = &ubd_dev[0];
+-
+- if(dev->file == NULL)
+- dev->file = "root_fs";
+- return(0);
+-}
+-
+-__initcall(ubd0_init);
++struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
+
+ /* Only changed by fake_ide_setup which is a setup */
+ static int fake_ide = 0;
+@@ -278,7 +274,7 @@ static int parse_unit(char **ptr)
+ return(-1);
+ *ptr = end;
+ }
+- else if (('a' <= *str) && (*str <= 'h')) {
++ else if (('a' <= *str) && (*str <= 'z')) {
+ n = *str - 'a';
+ str++;
+ *ptr = str;
+@@ -286,9 +282,13 @@ static int parse_unit(char **ptr)
+ return(n);
+ }
+
++/* If *index_out == -1 at exit, the passed option was a general one;
++ * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
++ * should not be freed on exit.
++ */
+ static int ubd_setup_common(char *str, int *index_out)
+ {
+- struct ubd *dev;
++ struct ubd *ubd_dev;
+ struct openflags flags = global_openflags;
+ char *backing_file;
+ int n, err, i;
+@@ -312,7 +312,7 @@ static int ubd_setup_common(char *str, i
+ }
+
+ err = 1;
+- spin_lock(&ubd_lock);
++ mutex_lock(&ubd_lock);
+ if(fake_major != MAJOR_NR){
+ printk(KERN_ERR "Can't assign a fake major twice\n");
+ goto out1;
+@@ -324,7 +324,7 @@ static int ubd_setup_common(char *str, i
+ major);
+ err = 0;
+ out1:
+- spin_unlock(&ubd_lock);
++ mutex_unlock(&ubd_lock);
+ return(err);
+ }
+
+@@ -341,10 +341,10 @@ static int ubd_setup_common(char *str, i
+ }
+
+ err = 1;
+- spin_lock(&ubd_lock);
++ mutex_lock(&ubd_lock);
+
+- dev = &ubd_dev[n];
+- if(dev->file != NULL){
++ ubd_dev = &ubd_devs[n];
++ if(ubd_dev->file != NULL){
+ printk(KERN_ERR "ubd_setup : device already configured\n");
+ goto out;
+ }
+@@ -361,10 +361,10 @@ static int ubd_setup_common(char *str, i
+ flags.s = 1;
+ break;
+ case 'd':
+- dev->no_cow = 1;
++ ubd_dev->no_cow = 1;
+ break;
+ case 'c':
+- dev->shared = 1;
++ ubd_dev->shared = 1;
+ break;
+ case '=':
+ str++;
+@@ -391,7 +391,7 @@ break_loop:
+ }
+
+ if(backing_file){
+- if(dev->no_cow)
++ if(ubd_dev->no_cow)
+ printk(KERN_ERR "Can't specify both 'd' and a "
+ "cow file\n");
+ else {
+@@ -399,11 +399,11 @@ break_loop:
+ backing_file++;
+ }
+ }
+- dev->file = str;
+- dev->cow.file = backing_file;
+- dev->boot_openflags = flags;
++ ubd_dev->file = str;
++ ubd_dev->cow.file = backing_file;
++ ubd_dev->boot_openflags = flags;
+ out:
+- spin_unlock(&ubd_lock);
++ mutex_unlock(&ubd_lock);
+ return(err);
+ }
+
+@@ -473,8 +473,9 @@ int thread_fd = -1;
+
+ /* Changed by ubd_handler, which is serialized because interrupts only
+ * happen on CPU 0.
++ * XXX: currently unused.
+ */
+-int intr_count = 0;
++static int intr_count = 0;
+
+ /* call ubd_finish if you need to serialize */
+ static void __ubd_finish(struct request *req, int error)
+@@ -494,6 +495,8 @@ static void __ubd_finish(struct request
+ end_request(req, 1);
+ }
+
++/* Callable only from interrupt context - otherwise you need to do
++ * spin_lock_irq()/spin_lock_irqsave() */
+ static inline void ubd_finish(struct request *req, int error)
+ {
+ spin_lock(&ubd_io_lock);
+@@ -501,14 +504,15 @@ static inline void ubd_finish(struct req
+ spin_unlock(&ubd_io_lock);
+ }
+
+-/* Called without ubd_io_lock held */
++/* XXX - move this inside ubd_intr. */
++/* Called without ubd_io_lock held, and only in interrupt context. */
+ static void ubd_handler(void)
+ {
+ struct io_thread_req req;
+ struct request *rq = elv_next_request(ubd_queue);
+ int n;
+
+- do_ubd = NULL;
++ do_ubd = 0;
+ intr_count++;
+ n = os_read_file(thread_fd, &req, sizeof(req));
+ if(n != sizeof(req)){
+@@ -522,10 +526,12 @@ static void ubd_handler(void)
+
+ ubd_finish(rq, req.error);
+ reactivate_fd(thread_fd, UBD_IRQ);
++ spin_lock(&ubd_io_lock);
+ do_ubd_request(ubd_queue);
++ spin_unlock(&ubd_io_lock);
+ }
+
+-static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
++static irqreturn_t ubd_intr(int irq, void *dev)
+ {
+ ubd_handler();
+ return(IRQ_HANDLED);
+@@ -542,87 +548,90 @@ void kill_io_thread(void)
+
+ __uml_exitcall(kill_io_thread);
+
+-static int ubd_file_size(struct ubd *dev, __u64 *size_out)
++static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
+ {
+ char *file;
+
+- file = dev->cow.file ? dev->cow.file : dev->file;
++ file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
+ return(os_file_size(file, size_out));
+ }
+
+-static void ubd_close(struct ubd *dev)
++static void ubd_close_dev(struct ubd *ubd_dev)
+ {
+- os_close_file(dev->fd);
+- if(dev->cow.file == NULL)
++ os_close_file(ubd_dev->fd);
++ if(ubd_dev->cow.file == NULL)
+ return;
+
+- os_close_file(dev->cow.fd);
+- vfree(dev->cow.bitmap);
+- dev->cow.bitmap = NULL;
++ os_close_file(ubd_dev->cow.fd);
++ vfree(ubd_dev->cow.bitmap);
++ ubd_dev->cow.bitmap = NULL;
+ }
+
+-static int ubd_open_dev(struct ubd *dev)
++static int ubd_open_dev(struct ubd *ubd_dev)
+ {
+ struct openflags flags;
+ char **back_ptr;
+ int err, create_cow, *create_ptr;
++ int fd;
+
+- dev->openflags = dev->boot_openflags;
++ ubd_dev->openflags = ubd_dev->boot_openflags;
+ create_cow = 0;
+- create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
+- back_ptr = dev->no_cow ? NULL : &dev->cow.file;
+- dev->fd = open_ubd_file(dev->file, &dev->openflags, dev->shared,
+- back_ptr, &dev->cow.bitmap_offset,
+- &dev->cow.bitmap_len, &dev->cow.data_offset,
++ create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
++ back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
++
++ fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
++ back_ptr, &ubd_dev->cow.bitmap_offset,
++ &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
+ create_ptr);
+
+- if((dev->fd == -ENOENT) && create_cow){
+- dev->fd = create_cow_file(dev->file, dev->cow.file,
+- dev->openflags, 1 << 9, PAGE_SIZE,
+- &dev->cow.bitmap_offset,
+- &dev->cow.bitmap_len,
+- &dev->cow.data_offset);
+- if(dev->fd >= 0){
++ if((fd == -ENOENT) && create_cow){
++ fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
++ ubd_dev->openflags, 1 << 9, PAGE_SIZE,
++ &ubd_dev->cow.bitmap_offset,
++ &ubd_dev->cow.bitmap_len,
++ &ubd_dev->cow.data_offset);
++ if(fd >= 0){
+ printk(KERN_INFO "Creating \"%s\" as COW file for "
+- "\"%s\"\n", dev->file, dev->cow.file);
++ "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
+ }
+ }
+
+- if(dev->fd < 0){
+- printk("Failed to open '%s', errno = %d\n", dev->file,
+- -dev->fd);
+- return(dev->fd);
++ if(fd < 0){
++ printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
++ -fd);
++ return fd;
+ }
++ ubd_dev->fd = fd;
+
+- if(dev->cow.file != NULL){
++ if(ubd_dev->cow.file != NULL){
+ err = -ENOMEM;
+- dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
+- if(dev->cow.bitmap == NULL){
++ ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
++ if(ubd_dev->cow.bitmap == NULL){
+ printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
+ goto error;
+ }
+ flush_tlb_kernel_vm();
+
+- err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
+- dev->cow.bitmap_offset,
+- dev->cow.bitmap_len);
++ err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
++ ubd_dev->cow.bitmap_offset,
++ ubd_dev->cow.bitmap_len);
+ if(err < 0)
+ goto error;
+
+- flags = dev->openflags;
++ flags = ubd_dev->openflags;
+ flags.w = 0;
+- err = open_ubd_file(dev->cow.file, &flags, dev->shared, NULL,
++ err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
+ NULL, NULL, NULL, NULL);
+ if(err < 0) goto error;
+- dev->cow.fd = err;
++ ubd_dev->cow.fd = err;
+ }
+ return(0);
+ error:
+- os_close_file(dev->fd);
++ os_close_file(ubd_dev->fd);
+ return(err);
+ }
+
+-static int ubd_new_disk(int major, u64 size, int unit,
++static int ubd_disk_register(int major, u64 size, int unit,
+ struct gendisk **disk_out)
+
+ {
+@@ -643,13 +652,13 @@ static int ubd_new_disk(int major, u64 s
+
+ /* sysfs register (not for ide fake devices) */
+ if (major == MAJOR_NR) {
+- ubd_dev[unit].pdev.id = unit;
+- ubd_dev[unit].pdev.name = DRIVER_NAME;
+- platform_device_register(&ubd_dev[unit].pdev);
+- disk->driverfs_dev = &ubd_dev[unit].pdev.dev;
++ ubd_devs[unit].pdev.id = unit;
++ ubd_devs[unit].pdev.name = DRIVER_NAME;
++ platform_device_register(&ubd_devs[unit].pdev);
++ disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
+ }
+
+- disk->private_data = &ubd_dev[unit];
++ disk->private_data = &ubd_devs[unit];
+ disk->queue = ubd_queue;
+ add_disk(disk);
+
+@@ -661,28 +670,25 @@ static int ubd_new_disk(int major, u64 s
+
+ static int ubd_add(int n)
+ {
+- struct ubd *dev = &ubd_dev[n];
++ struct ubd *ubd_dev = &ubd_devs[n];
+ int err;
+
+ err = -ENODEV;
+- if(dev->file == NULL)
++ if(ubd_dev->file == NULL)
+ goto out;
+
+- if (ubd_open_dev(dev))
+- goto out;
+-
+- err = ubd_file_size(dev, &dev->size);
++ err = ubd_file_size(ubd_dev, &ubd_dev->size);
+ if(err < 0)
+- goto out_close;
++ goto out;
+
+- dev->size = ROUND_BLOCK(dev->size);
++ ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
+
+- err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
++ err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
+ if(err)
+- goto out_close;
++ goto out;
+
+ if(fake_major != MAJOR_NR)
+- ubd_new_disk(fake_major, dev->size, n,
++ ubd_disk_register(fake_major, ubd_dev->size, n,
+ &fake_gendisk[n]);
+
+ /* perhaps this should also be under the "if (fake_major)" above */
+@@ -691,40 +697,47 @@ static int ubd_add(int n)
+ make_ide_entries(ubd_gendisk[n]->disk_name);
+
+ err = 0;
+-out_close:
+- ubd_close(dev);
+ out:
+ return err;
+ }
+
+ static int ubd_config(char *str)
+ {
+- int n, err;
++ int n, ret;
+
+ str = kstrdup(str, GFP_KERNEL);
+- if(str == NULL){
++ if (str == NULL) {
+ printk(KERN_ERR "ubd_config failed to strdup string\n");
+- return(1);
++ ret = 1;
++ goto out;
+ }
+- err = ubd_setup_common(str, &n);
+- if(err){
+- kfree(str);
+- return(-1);
++ ret = ubd_setup_common(str, &n);
++ if (ret) {
++ ret = -1;
++ goto err_free;
++ }
++ if (n == -1) {
++ ret = 0;
++ goto err_free;
+ }
+- if(n == -1) return(0);
+
+- spin_lock(&ubd_lock);
+- err = ubd_add(n);
+- if(err)
+- ubd_dev[n].file = NULL;
+- spin_unlock(&ubd_lock);
++ mutex_lock(&ubd_lock);
++ ret = ubd_add(n);
++ if (ret)
++ ubd_devs[n].file = NULL;
++ mutex_unlock(&ubd_lock);
+
+- return(err);
++out:
++ return ret;
++
++err_free:
++ kfree(str);
++ goto out;
+ }
+
+ static int ubd_get_config(char *name, char *str, int size, char **error_out)
+ {
+- struct ubd *dev;
++ struct ubd *ubd_dev;
+ int n, len = 0;
+
+ n = parse_unit(&name);
+@@ -733,24 +746,24 @@ static int ubd_get_config(char *name, ch
+ return(-1);
+ }
+
+- dev = &ubd_dev[n];
+- spin_lock(&ubd_lock);
++ ubd_dev = &ubd_devs[n];
++ mutex_lock(&ubd_lock);
+
+- if(dev->file == NULL){
++ if(ubd_dev->file == NULL){
+ CONFIG_CHUNK(str, size, len, "", 1);
+ goto out;
+ }
+
+- CONFIG_CHUNK(str, size, len, dev->file, 0);
++ CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
+
+- if(dev->cow.file != NULL){
++ if(ubd_dev->cow.file != NULL){
+ CONFIG_CHUNK(str, size, len, ",", 0);
+- CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
++ CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
+ }
+ else CONFIG_CHUNK(str, size, len, "", 1);
+
+ out:
+- spin_unlock(&ubd_lock);
++ mutex_unlock(&ubd_lock);
+ return(len);
+ }
+
+@@ -766,22 +779,22 @@ static int ubd_id(char **str, int *start
+
+ static int ubd_remove(int n)
+ {
+- struct ubd *dev;
++ struct ubd *ubd_dev;
+ int err = -ENODEV;
+
+- spin_lock(&ubd_lock);
++ mutex_lock(&ubd_lock);
+
+ if(ubd_gendisk[n] == NULL)
+ goto out;
+
+- dev = &ubd_dev[n];
++ ubd_dev = &ubd_devs[n];
+
+- if(dev->file == NULL)
++ if(ubd_dev->file == NULL)
+ goto out;
+
+ /* you cannot remove a open disk */
+ err = -EBUSY;
+- if(dev->count > 0)
++ if(ubd_dev->count > 0)
+ goto out;
+
+ del_gendisk(ubd_gendisk[n]);
+@@ -794,14 +807,15 @@ static int ubd_remove(int n)
+ fake_gendisk[n] = NULL;
+ }
+
+- platform_device_unregister(&dev->pdev);
+- *dev = ((struct ubd) DEFAULT_UBD);
++ platform_device_unregister(&ubd_dev->pdev);
++ *ubd_dev = ((struct ubd) DEFAULT_UBD);
+ err = 0;
+ out:
+- spin_unlock(&ubd_lock);
++ mutex_unlock(&ubd_lock);
+ return err;
+ }
+
++/* All these are called by mconsole in process context and without ubd-specific locks. */
+ static struct mc_device ubd_mc = {
+ .name = "ubd",
+ .config = ubd_config,
+@@ -810,7 +824,7 @@ static struct mc_device ubd_mc = {
+ .remove = ubd_remove,
+ };
+
+-static int ubd_mc_init(void)
++static int __init ubd_mc_init(void)
+ {
+ mconsole_register_dev(&ubd_mc);
+ return 0;
+@@ -818,13 +832,24 @@ static int ubd_mc_init(void)
+
+ __initcall(ubd_mc_init);
+
++static int __init ubd0_init(void)
++{
++ struct ubd *ubd_dev = &ubd_devs[0];
++
++ if(ubd_dev->file == NULL)
++ ubd_dev->file = "root_fs";
++ return(0);
++}
++
++__initcall(ubd0_init);
++
+ static struct platform_driver ubd_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ };
+
+-int ubd_init(void)
++static int __init ubd_init(void)
+ {
+ int i;
+
+@@ -852,7 +877,7 @@ int ubd_init(void)
+
+ late_initcall(ubd_init);
+
+-int ubd_driver_init(void){
++static int __init ubd_driver_init(void){
+ unsigned long stack;
+ int err;
+
+@@ -873,7 +898,7 @@ int ubd_driver_init(void){
+ return(0);
+ }
+ err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
+- IRQF_DISABLED, "ubd", ubd_dev);
++ IRQF_DISABLED, "ubd", ubd_devs);
+ if(err != 0)
+ printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
+ return 0;
+@@ -884,24 +909,24 @@ device_initcall(ubd_driver_init);
+ static int ubd_open(struct inode *inode, struct file *filp)
+ {
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+- struct ubd *dev = disk->private_data;
++ struct ubd *ubd_dev = disk->private_data;
+ int err = 0;
+
+- if(dev->count == 0){
+- err = ubd_open_dev(dev);
++ if(ubd_dev->count == 0){
++ err = ubd_open_dev(ubd_dev);
+ if(err){
+ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
+- disk->disk_name, dev->file, -err);
++ disk->disk_name, ubd_dev->file, -err);
+ goto out;
+ }
+ }
+- dev->count++;
+- set_disk_ro(disk, !dev->openflags.w);
++ ubd_dev->count++;
++ set_disk_ro(disk, !ubd_dev->openflags.w);
+
+ /* This should no more be needed. And it didn't work anyway to exclude
+ * read-write remounting of filesystems.*/
+- /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
+- if(--dev->count == 0) ubd_close(dev);
++ /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
++ if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
+ err = -EROFS;
+ }*/
+ out:
+@@ -911,10 +936,10 @@ static int ubd_open(struct inode *inode,
+ static int ubd_release(struct inode * inode, struct file * file)
+ {
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+- struct ubd *dev = disk->private_data;
++ struct ubd *ubd_dev = disk->private_data;
+
+- if(--dev->count == 0)
+- ubd_close(dev);
++ if(--ubd_dev->count == 0)
++ ubd_close_dev(ubd_dev);
+ return(0);
+ }
+
+@@ -982,14 +1007,12 @@ static void cowify_req(struct io_thread_
+ static int prepare_request(struct request *req, struct io_thread_req *io_req)
+ {
+ struct gendisk *disk = req->rq_disk;
+- struct ubd *dev = disk->private_data;
++ struct ubd *ubd_dev = disk->private_data;
+ __u64 offset;
+ int len;
+
+- if(req->rq_status == RQ_INACTIVE) return(1);
+-
+ /* This should be impossible now */
+- if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
++ if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
+ printk("Write attempted on readonly ubd device %s\n",
+ disk->disk_name);
+ end_request(req, 0);
+@@ -999,8 +1022,8 @@ static int prepare_request(struct reques
+ offset = ((__u64) req->sector) << 9;
+ len = req->current_nr_sectors << 9;
+
+- io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
+- io_req->fds[1] = dev->fd;
++ io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
++ io_req->fds[1] = ubd_dev->fd;
+ io_req->cow_offset = -1;
+ io_req->offset = offset;
+ io_req->length = len;
+@@ -1009,13 +1032,13 @@ static int prepare_request(struct reques
+
+ io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
+ io_req->offsets[0] = 0;
+- io_req->offsets[1] = dev->cow.data_offset;
++ io_req->offsets[1] = ubd_dev->cow.data_offset;
+ io_req->buffer = req->buffer;
+ io_req->sectorsize = 1 << 9;
+
+- if(dev->cow.file != NULL)
+- cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
+- dev->cow.bitmap_len);
++ if(ubd_dev->cow.file != NULL)
++ cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
++ ubd_dev->cow.bitmap_len);
+
+ return(0);
+ }
+@@ -1041,7 +1064,7 @@ static void do_ubd_request(request_queue
+ return;
+ err = prepare_request(req, &io_req);
+ if(!err){
+- do_ubd = ubd_handler;
++ do_ubd = 1;
+ n = os_write_file(thread_fd, (char *) &io_req,
+ sizeof(io_req));
+ if(n != sizeof(io_req))
+@@ -1053,18 +1076,18 @@ static void do_ubd_request(request_queue
+
+ static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+ {
+- struct ubd *dev = bdev->bd_disk->private_data;
++ struct ubd *ubd_dev = bdev->bd_disk->private_data;
+
+ geo->heads = 128;
+ geo->sectors = 32;
+- geo->cylinders = dev->size / (128 * 32 * 512);
++ geo->cylinders = ubd_dev->size / (128 * 32 * 512);
+ return 0;
+ }
+
+ static int ubd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+ {
+- struct ubd *dev = inode->i_bdev->bd_disk->private_data;
++ struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
+ struct hd_driveid ubd_id = {
+ .cyls = 0,
+ .heads = 128,
+@@ -1074,7 +1097,7 @@ static int ubd_ioctl(struct inode * inod
+ switch (cmd) {
+ struct cdrom_volctrl volume;
+ case HDIO_GET_IDENTITY:
+- ubd_id.cyls = dev->size / (128 * 32 * 512);
++ ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
+ if(copy_to_user((char __user *) arg, (char *) &ubd_id,
+ sizeof(ubd_id)))
+ return(-EFAULT);
+@@ -1361,8 +1384,8 @@ void do_io(struct io_thread_req *req)
+ */
+ int kernel_fd = -1;
+
+-/* Only changed by the io thread */
+-int io_count = 0;
++/* Only changed by the io thread. XXX: currently unused. */
++static int io_count = 0;
+
+ int io_thread(void *arg)
+ {
+diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
+index aaa6366..850221d 100644
+--- a/arch/um/drivers/xterm.c
++++ b/arch/um/drivers/xterm.c
+@@ -31,7 +31,7 @@ struct xterm_chan {
+ };
+
+ /* Not static because it's called directly by the tt mode gdb code */
+-void *xterm_init(char *str, int device, struct chan_opts *opts)
++void *xterm_init(char *str, int device, const struct chan_opts *opts)
+ {
+ struct xterm_chan *data;
+
+@@ -136,8 +136,6 @@ int xterm_open(int input, int output, in
+ return(pid);
+ }
+
+- if(data->stack == 0) free_stack(stack, 0);
+-
+ if (data->direct_rcv) {
+ new = os_rcv_fd(fd, &data->helper_pid);
+ } else {
+@@ -194,7 +192,7 @@ static void xterm_free(void *d)
+ free(d);
+ }
+
+-struct chan_ops xterm_ops = {
++const struct chan_ops xterm_ops = {
+ .type = "xterm",
+ .init = xterm_init,
+ .open = xterm_open,
+diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
+index 6036ec8..a4ce705 100644
+--- a/arch/um/drivers/xterm_kern.c
++++ b/arch/um/drivers/xterm_kern.c
+@@ -21,7 +21,7 @@ struct xterm_wait {
+ int new_fd;
+ };
+
+-static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t xterm_interrupt(int irq, void *data)
+ {
+ struct xterm_wait *xterm = data;
+ int fd;
+diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
+index 1bb5e9d..572d286 100644
+--- a/arch/um/include/chan_kern.h
++++ b/arch/um/include/chan_kern.h
+@@ -23,21 +23,21 @@ struct chan {
+ unsigned int opened:1;
+ unsigned int enabled:1;
+ int fd;
+- struct chan_ops *ops;
++ const struct chan_ops *ops;
+ void *data;
+ };
+
+ extern void chan_interrupt(struct list_head *chans, struct work_struct *task,
+ struct tty_struct *tty, int irq);
+ extern int parse_chan_pair(char *str, struct line *line, int device,
+- struct chan_opts *opts);
++ const struct chan_opts *opts);
+ extern int open_chan(struct list_head *chans);
+ extern int write_chan(struct list_head *chans, const char *buf, int len,
+ int write_irq);
+ extern int console_write_chan(struct list_head *chans, const char *buf,
+ int len);
+ extern int console_open_chan(struct line *line, struct console *co,
+- struct chan_opts *opts);
++ const struct chan_opts *opts);
+ extern void deactivate_chan(struct list_head *chans, int irq);
+ extern void reactivate_chan(struct list_head *chans, int irq);
+ extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
+diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
+index 659bb3c..a795547 100644
+--- a/arch/um/include/chan_user.h
++++ b/arch/um/include/chan_user.h
+@@ -20,7 +20,7 @@ enum chan_init_pri { INIT_STATIC, INIT_A
+
+ struct chan_ops {
+ char *type;
+- void *(*init)(char *, int, struct chan_opts *);
++ void *(*init)(char *, int, const struct chan_opts *);
+ int (*open)(int, int, int, void *, char **);
+ void (*close)(int, void *);
+ int (*read)(int, char *, void *);
+@@ -31,8 +31,8 @@ struct chan_ops {
+ int winch;
+ };
+
+-extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
+- xterm_ops;
++extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops,
++ tty_ops, xterm_ops;
+
+ extern void generic_close(int fd, void *unused);
+ extern int generic_read(int fd, char *c_out, void *unused);
+diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
+index 356390d..461175f 100644
+--- a/arch/um/include/common-offsets.h
++++ b/arch/um/include/common-offsets.h
+@@ -1,9 +1,16 @@
+ /* for use by sys-$SUBARCH/kernel-offsets.c */
+
++DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
++#ifdef CONFIG_MODE_TT
++OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
++#endif
++
+ OFFSET(HOST_TASK_REGS, task_struct, thread.regs);
+ OFFSET(HOST_TASK_PID, task_struct, pid);
++
+ DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE);
+ DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC);
++
+ DEFINE_STR(UM_KERN_EMERG, KERN_EMERG);
+ DEFINE_STR(UM_KERN_ALERT, KERN_ALERT);
+ DEFINE_STR(UM_KERN_CRIT, KERN_CRIT);
+@@ -12,6 +19,10 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING
+ DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
+ DEFINE_STR(UM_KERN_INFO, KERN_INFO);
+ DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
++
+ DEFINE(UM_ELF_CLASS, ELF_CLASS);
+ DEFINE(UM_ELFCLASS32, ELFCLASS32);
+ DEFINE(UM_ELFCLASS64, ELFCLASS64);
++
++/* For crypto assembler code. */
++DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h
+index c222d56..4f77559 100644
+--- a/arch/um/include/irq_kern.h
++++ b/arch/um/include/irq_kern.h
+@@ -10,12 +10,11 @@
+ #include "asm/ptrace.h"
+
+ extern int um_request_irq(unsigned int irq, int fd, int type,
+- irqreturn_t (*handler)(int, void *,
+- struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irqflags, const char * devname,
+ void *dev_id);
+ extern int init_aio_irq(int irq, char *name,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *));
++ irq_handler_t handler);
+
+ #endif
+
+diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
+index b98bdd8..cec9fcc 100644
+--- a/arch/um/include/kern_util.h
++++ b/arch/um/include/kern_util.h
+@@ -6,7 +6,6 @@
+ #ifndef __KERN_UTIL_H__
+ #define __KERN_UTIL_H__
+
+-#include "linux/threads.h"
+ #include "sysdep/ptrace.h"
+ #include "sysdep/faultinfo.h"
+
+@@ -21,13 +20,12 @@ struct kern_handlers {
+ kern_hndl timer_handler;
+ };
+
+-extern struct kern_handlers handlinfo_kern;
++extern const struct kern_handlers handlinfo_kern;
+
+ extern int ncpus;
+ extern char *linux_prog;
+ extern char *gdb_init;
+ extern int kmalloc_ok;
+-extern int timer_irq_inited;
+ extern int jail;
+ extern int nsyscalls;
+
+diff --git a/arch/um/include/line.h b/arch/um/include/line.h
+index 27bf2f6..7be2481 100644
+--- a/arch/um/include/line.h
++++ b/arch/um/include/line.h
+@@ -52,7 +52,7 @@ struct line {
+
+ int sigio;
+ struct work_struct task;
+- struct line_driver *driver;
++ const struct line_driver *driver;
+ int have_irq;
+ };
+
+@@ -91,15 +91,14 @@ extern int line_setup_irq(int fd, int in
+ void *data);
+ extern void line_close_chan(struct line *line);
+ extern struct tty_driver * line_register_devfs(struct lines *set,
+- struct line_driver *line_driver,
+- struct tty_operations *driver,
+- struct line *lines,
+- int nlines);
++ struct line_driver *line_driver,
++ const struct tty_operations *driver,
++ struct line *lines, int nlines);
+ extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
+ extern void close_lines(struct line *lines, int nlines);
+
+ extern int line_config(struct line *lines, unsigned int sizeof_lines,
+- char *str, struct chan_opts *opts);
++ char *str, const struct chan_opts *opts);
+ 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,
+diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h
+index 1b5c013..e860bc5 100644
+--- a/arch/um/include/longjmp.h
++++ b/arch/um/include/longjmp.h
+@@ -1,15 +1,19 @@
+ #ifndef __UML_LONGJMP_H
+ #define __UML_LONGJMP_H
+
+-#include <setjmp.h>
++#include "sysdep/archsetjmp.h"
+ #include "os.h"
+
++extern int setjmp(jmp_buf);
++extern void longjmp(jmp_buf, int);
++
+ #define UML_LONGJMP(buf, val) do { \
+ longjmp(*buf, val); \
+ } while(0)
+
+ #define UML_SETJMP(buf) ({ \
+- int n, enable; \
++ int n; \
++ volatile int enable; \
+ enable = get_signals(); \
+ n = setjmp(*buf); \
+ if(n != 0) \
+diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
+index 58f67d3..2666815 100644
+--- a/arch/um/include/mconsole.h
++++ b/arch/um/include/mconsole.h
+@@ -61,6 +61,7 @@ struct mc_request
+
+ struct mconsole_request request;
+ struct mconsole_command *cmd;
++ union uml_pt_regs regs;
+ };
+
+ extern char mconsole_socket_name[];
+diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
+index d86ee14..1ea6d92 100644
+--- a/arch/um/include/mconsole_kern.h
++++ b/arch/um/include/mconsole_kern.h
+@@ -6,7 +6,6 @@
+ #ifndef __MCONSOLE_KERN_H__
+ #define __MCONSOLE_KERN_H__
+
+-#include "linux/config.h"
+ #include "linux/list.h"
+ #include "mconsole.h"
+
+@@ -15,6 +14,7 @@ struct mconsole_entry {
+ struct mc_request request;
+ };
+
++/* All these methods are called in process context. */
+ struct mc_device {
+ struct list_head list;
+ char *name;
+diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h
+index e7539a8..88e5e77 100644
+--- a/arch/um/include/mode_kern.h
++++ b/arch/um/include/mode_kern.h
+@@ -6,8 +6,6 @@
+ #ifndef __MODE_KERN_H__
+ #define __MODE_KERN_H__
+
+-#include "linux/config.h"
+-
+ #ifdef CONFIG_MODE_TT
+ #include "mode_kern_tt.h"
+ #endif
+diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
+index f7de6df..280459f 100644
+--- a/arch/um/include/net_kern.h
++++ b/arch/um/include/net_kern.h
+@@ -18,7 +18,6 @@ struct uml_net {
+ struct platform_device pdev;
+ int index;
+ unsigned char mac[ETH_ALEN];
+- int have_mac;
+ };
+
+ struct uml_net_private {
+@@ -29,7 +28,6 @@ struct uml_net_private {
+ struct net_device_stats stats;
+ int fd;
+ unsigned char mac[ETH_ALEN];
+- int have_mac;
+ unsigned short (*protocol)(struct sk_buff *);
+ int (*open)(void *);
+ void (*close)(int, void *);
+@@ -54,15 +52,14 @@ struct transport {
+ struct list_head list;
+ char *name;
+ int (*setup)(char *, char **, void *);
+- struct net_user_info *user;
+- struct net_kern_info *kern;
++ const struct net_user_info *user;
++ const struct net_kern_info *kern;
+ int private_size;
+ int setup_size;
+ };
+
+ extern struct net_device *ether_init(int);
+ extern unsigned short ether_protocol(struct sk_buff *);
+-extern int setup_etheraddr(char *str, unsigned char *addr);
+ extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
+ extern int tap_setup_common(char *str, char *type, char **dev_name,
+ char **mac_out, char **gate_addr);
+@@ -70,14 +67,3 @@ extern void register_transport(struct tr
+ extern unsigned short eth_protocol(struct sk_buff *skb);
+
+ #endif
+-
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * Emacs will notice this stuff at the end of the file and automatically
+- * adjust the settings for this buffer only. This must remain at the end
+- * of the file.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-file-style: "linux"
+- * End:
+- */
+diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
+index 800c403..19f207c 100644
+--- a/arch/um/include/net_user.h
++++ b/arch/um/include/net_user.h
+@@ -1,4 +1,4 @@
+-/*
++/*
+ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
+ * Licensed under the GPL
+ */
+@@ -25,10 +25,8 @@ struct net_user_info {
+ };
+
+ extern void ether_user_init(void *data, void *dev);
+-extern void dev_ip_addr(void *d, unsigned char *bin_buf);
+-extern void set_ether_mac(void *d, unsigned char *addr);
+-extern void iter_addresses(void *d, void (*cb)(unsigned char *,
+- unsigned char *, void *),
++extern void iter_addresses(void *d, void (*cb)(unsigned char *,
++ unsigned char *, void *),
+ void *arg);
+
+ extern void *get_output_buffer(int *len_out);
+@@ -53,14 +51,3 @@ extern char *split_if_spec(char *str, ..
+ extern int dev_netmask(void *d, void *m);
+
+ #endif
+-
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * Emacs will notice this stuff at the end of the file and automatically
+- * adjust the settings for this buffer only. This must remain at the end
+- * of the file.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-file-style: "linux"
+- * End:
+- */
+diff --git a/arch/um/include/os.h b/arch/um/include/os.h
+index 5316e8a..6516f6d 100644
+--- a/arch/um/include/os.h
++++ b/arch/um/include/os.h
+@@ -14,6 +14,7 @@
+ #include "skas/mm_id.h"
+ #include "irq_user.h"
+ #include "sysdep/tls.h"
++#include "sysdep/archsetjmp.h"
+
+ #define OS_TYPE_FILE 1
+ #define OS_TYPE_DIR 2
+@@ -198,7 +199,10 @@ extern long os_ptrace_ldt(long pid, long
+ extern int os_getpid(void);
+ extern int os_getpgrp(void);
+
++#ifdef UML_CONFIG_MODE_TT
+ extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
++extern void stop(void);
++#endif
+ extern void init_new_thread_signals(void);
+ extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
+
+@@ -216,7 +220,6 @@ extern void os_flush_stdout(void);
+ */
+ extern void forward_ipi(int fd, int pid);
+ extern void kill_child_dead(int pid);
+-extern void stop(void);
+ extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
+ extern int protect_memory(unsigned long addr, unsigned long len,
+ int r, int w, int x, int must_succeed);
+@@ -276,9 +279,11 @@ extern int setjmp_wrapper(void (*proc)(v
+
+ extern void switch_timers(int to_real);
+ extern void idle_sleep(int secs);
++extern int set_interval(int is_virtual);
++#ifdef CONFIG_MODE_TT
+ extern void enable_timer(void);
++#endif
+ extern void disable_timer(void);
+-extern void user_time_init(void);
+ extern void uml_idle_timer(void);
+ extern unsigned long long os_nsecs(void);
+
+@@ -305,12 +310,9 @@ extern int copy_context_skas0(unsigned l
+ extern void userspace(union uml_pt_regs *regs);
+ extern void map_stub_pages(int fd, unsigned long code,
+ unsigned long data, unsigned long stack);
+-extern void new_thread(void *stack, void **switch_buf_ptr,
+- void **fork_buf_ptr, void (*handler)(int));
+-extern void thread_wait(void *sw, void *fb);
+-extern void switch_threads(void *me, void *next);
+-extern int start_idle_thread(void *stack, void *switch_buf_ptr,
+- void **fork_buf_ptr);
++extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
++extern void switch_threads(jmp_buf *me, jmp_buf *you);
++extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
+ extern void initial_thread_cb_skas(void (*proc)(void *),
+ void *arg);
+ extern void halt_skas(void);
+@@ -329,6 +331,7 @@ extern void os_set_ioignore(void);
+ extern void init_irq_signals(int on_sigstack);
+
+ /* sigio.c */
++extern int add_sigio_fd(int fd);
+ extern int ignore_sigio_fd(int fd);
+ extern void maybe_sigio_broken(int fd, int read);
+
+diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
+index 83b688c..f845b36 100644
+--- a/arch/um/include/registers.h
++++ b/arch/um/include/registers.h
+@@ -7,6 +7,7 @@
+ #define __REGISTERS_H
+
+ #include "sysdep/ptrace.h"
++#include "sysdep/archsetjmp.h"
+
+ extern void init_thread_registers(union uml_pt_regs *to);
+ extern int save_fp_registers(int pid, unsigned long *fp_regs);
+@@ -15,6 +16,6 @@ extern void save_registers(int pid, unio
+ 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, unsigned long * fp_regs);
+-extern void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer);
++extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
+
+ #endif
+diff --git a/arch/um/include/skas/mmu-skas.h b/arch/um/include/skas/mmu-skas.h
+index d8869a6..b26986c 100644
+--- a/arch/um/include/skas/mmu-skas.h
++++ b/arch/um/include/skas/mmu-skas.h
+@@ -6,7 +6,6 @@
+ #ifndef __SKAS_MMU_H
+ #define __SKAS_MMU_H
+
+-#include "linux/config.h"
+ #include "mm_id.h"
+ #include "asm/ldt.h"
+
+diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h
+index 853b26f..e88926b 100644
+--- a/arch/um/include/skas/skas.h
++++ b/arch/um/include/skas/skas.h
+@@ -14,8 +14,7 @@ extern int proc_mm, ptrace_faultinfo, pt
+ extern int skas_needs_stub;
+
+ extern int user_thread(unsigned long stack, int flags);
+-extern void new_thread_proc(void *stack, void (*handler)(int sig));
+-extern void new_thread_handler(int sig);
++extern void new_thread_handler(void);
+ extern void handle_syscall(union uml_pt_regs *regs);
+ extern int new_mm(unsigned long stack);
+ extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
+diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h
+new file mode 100644
+index 0000000..11bafab
+--- /dev/null
++++ b/arch/um/include/sysdep-i386/archsetjmp.h
+@@ -0,0 +1,22 @@
++/*
++ * arch/i386/include/klibc/archsetjmp.h
++ */
++
++#ifndef _KLIBC_ARCHSETJMP_H
++#define _KLIBC_ARCHSETJMP_H
++
++struct __jmp_buf {
++ unsigned int __ebx;
++ unsigned int __esp;
++ unsigned int __ebp;
++ unsigned int __esi;
++ unsigned int __edi;
++ unsigned int __eip;
++};
++
++typedef struct __jmp_buf jmp_buf[1];
++
++#define JB_IP __eip
++#define JB_SP __esp
++
++#endif /* _SETJMP_H */
+diff --git a/arch/um/include/sysdep-i386/barrier.h b/arch/um/include/sysdep-i386/barrier.h
+new file mode 100644
+index 0000000..b58d52c
+--- /dev/null
++++ b/arch/um/include/sysdep-i386/barrier.h
+@@ -0,0 +1,9 @@
++#ifndef __SYSDEP_I386_BARRIER_H
++#define __SYSDEP_I386_BARRIER_H
++
++/* Copied from include/asm-i386 for use by userspace. i386 has the option
++ * of using mfence, but I'm just using this, which works everywhere, for now.
++ */
++#define mb() asm volatile("lock; addl $0,0(%esp)")
++
++#endif
+diff --git a/arch/um/include/sysdep-i386/kernel-offsets.h b/arch/um/include/sysdep-i386/kernel-offsets.h
+index 2c13de3..97ec9d8 100644
+--- a/arch/um/include/sysdep-i386/kernel-offsets.h
++++ b/arch/um/include/sysdep-i386/kernel-offsets.h
+@@ -1,6 +1,7 @@
+ #include <linux/stddef.h>
+ #include <linux/sched.h>
+ #include <linux/elf.h>
++#include <linux/crypto.h>
+ #include <asm/mman.h>
+
+ #define DEFINE(sym, val) \
+@@ -17,9 +18,5 @@
+ void foo(void)
+ {
+ OFFSET(HOST_TASK_DEBUGREGS, task_struct, thread.arch.debugregs);
+- DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
+-#ifdef CONFIG_MODE_TT
+- OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
+-#endif
+ #include <common-offsets.h>
+ }
+diff --git a/arch/um/include/sysdep-i386/signal.h b/arch/um/include/sysdep-i386/signal.h
+deleted file mode 100644
+index 07518b1..0000000
+--- a/arch/um/include/sysdep-i386/signal.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*
+- * Copyright (C) 2004 PathScale, Inc
+- * Licensed under the GPL
+- */
+-
+-#ifndef __I386_SIGNAL_H_
+-#define __I386_SIGNAL_H_
+-
+-#include <signal.h>
+-
+-#define ARCH_SIGHDLR_PARAM int sig
+-
+-#define ARCH_GET_SIGCONTEXT(sc, sig) \
+- do sc = (struct sigcontext *) (&sig + 1); while(0)
+-
+-#endif
+-
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * Emacs will notice this stuff at the end of the file and automatically
+- * adjust the settings for this buffer only. This must remain at the end
+- * of the file.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-file-style: "linux"
+- * End:
+- */
+diff --git a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/include/sysdep-ppc/ptrace.h
+index 8a27353..df2397d 100644
+--- a/arch/um/include/sysdep-ppc/ptrace.h
++++ b/arch/um/include/sysdep-ppc/ptrace.h
+@@ -5,7 +5,6 @@
+ #ifndef __SYS_PTRACE_PPC_H
+ #define __SYS_PTRACE_PPC_H
+
+-#include "linux/config.h"
+ #include "linux/types.h"
+
+ /* the following taken from <asm-ppc/ptrace.h> */
+diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h
+new file mode 100644
+index 0000000..9a5e1a6
+--- /dev/null
++++ b/arch/um/include/sysdep-x86_64/archsetjmp.h
+@@ -0,0 +1,24 @@
++/*
++ * arch/x86_64/include/klibc/archsetjmp.h
++ */
++
++#ifndef _KLIBC_ARCHSETJMP_H
++#define _KLIBC_ARCHSETJMP_H
++
++struct __jmp_buf {
++ unsigned long __rbx;
++ unsigned long __rsp;
++ unsigned long __rbp;
++ unsigned long __r12;
++ unsigned long __r13;
++ unsigned long __r14;
++ unsigned long __r15;
++ unsigned long __rip;
++};
++
++typedef struct __jmp_buf jmp_buf[1];
++
++#define JB_IP __rip
++#define JB_SP __rsp
++
++#endif /* _SETJMP_H */
+diff --git a/arch/um/include/sysdep-x86_64/barrier.h b/arch/um/include/sysdep-x86_64/barrier.h
+new file mode 100644
+index 0000000..7b610be
+--- /dev/null
++++ b/arch/um/include/sysdep-x86_64/barrier.h
+@@ -0,0 +1,7 @@
++#ifndef __SYSDEP_X86_64_BARRIER_H
++#define __SYSDEP_X86_64_BARRIER_H
++
++/* Copied from include/asm-x86_64 for use by userspace. */
++#define mb() asm volatile("mfence":::"memory")
++
++#endif
+diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h
+index 91d129f..a307237 100644
+--- a/arch/um/include/sysdep-x86_64/kernel-offsets.h
++++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h
+@@ -2,6 +2,7 @@
+ #include <linux/sched.h>
+ #include <linux/time.h>
+ #include <linux/elf.h>
++#include <linux/crypto.h>
+ #include <asm/page.h>
+ #include <asm/mman.h>
+
+@@ -18,9 +19,5 @@
+
+ void foo(void)
+ {
+- DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
+-#ifdef CONFIG_MODE_TT
+- OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
+-#endif
+ #include <common-offsets.h>
+ }
+diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
+index 8d353f0..617bb9e 100644
+--- a/arch/um/include/sysdep-x86_64/ptrace.h
++++ b/arch/um/include/sysdep-x86_64/ptrace.h
+@@ -50,6 +50,21 @@
+ #define HOST_FS 25
+ #define HOST_GS 26
+
++/* Also defined in asm/ptrace-x86_64.h, but not in libc headers. So, these
++ * are already defined for kernel code, but not for userspace code.
++ */
++#ifndef FS_BASE
++/* These aren't defined in ptrace.h, but exist in struct user_regs_struct,
++ * which is what x86_64 ptrace actually uses.
++ */
++#define FS_BASE (HOST_FS_BASE * sizeof(long))
++#define GS_BASE (HOST_GS_BASE * sizeof(long))
++#define DS (HOST_DS * sizeof(long))
++#define ES (HOST_ES * sizeof(long))
++#define FS (HOST_FS * sizeof(long))
++#define GS (HOST_GS * sizeof(long))
++#endif
++
+ #define REGS_FS_BASE(r) ((r)[HOST_FS_BASE])
+ #define REGS_GS_BASE(r) ((r)[HOST_GS_BASE])
+ #define REGS_DS(r) ((r)[HOST_DS])
+@@ -89,9 +104,12 @@ union uml_pt_regs {
+ #endif
+ #ifdef UML_CONFIG_MODE_SKAS
+ struct skas_regs {
+- /* XXX */
+- unsigned long regs[27];
+- unsigned long fp[65];
++ /* x86_64 ptrace uses sizeof(user_regs_struct) as its register
++ * file size, while i386 uses FRAME_SIZE. Therefore, we need
++ * to use UM_FRAME_SIZE here instead of HOST_FRAME_SIZE.
++ */
++ unsigned long regs[UM_FRAME_SIZE];
++ unsigned long fp[HOST_FP_SIZE];
+ struct faultinfo faultinfo;
+ long syscall;
+ int is_user;
+@@ -120,11 +138,16 @@ extern int mode_tt;
+ #define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
+ #define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
+ #define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
++#define UPT_FS_BASE(r) \
++ __CHOOSE_MODE(SC_FS_BASE(UPT_SC(r)), REGS_FS_BASE((r)->skas.regs))
+ #define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
++#define UPT_GS_BASE(r) \
++ __CHOOSE_MODE(SC_GS_BASE(UPT_SC(r)), REGS_GS_BASE((r)->skas.regs))
+ #define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
+ #define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
+ #define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
+ #define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
++#define UPT_SS(r) __CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
+ #define UPT_ORIG_RAX(r) \
+ __CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
+
+@@ -183,6 +206,13 @@ struct syscall_args {
+ case RBP: val = UPT_RBP(regs); break; \
+ case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \
+ case CS: val = UPT_CS(regs); break; \
++ case SS: val = UPT_SS(regs); break; \
++ case FS_BASE: val = UPT_FS_BASE(regs); break; \
++ case GS_BASE: val = UPT_GS_BASE(regs); break; \
++ case DS: val = UPT_DS(regs); break; \
++ case ES: val = UPT_ES(regs); break; \
++ case FS : val = UPT_FS (regs); break; \
++ case GS: val = UPT_GS(regs); break; \
+ case EFLAGS: val = UPT_EFLAGS(regs); break; \
+ default : \
+ panic("Bad register in UPT_REG : %d\n", reg); \
+@@ -214,6 +244,13 @@ struct syscall_args {
+ case RBP: UPT_RBP(regs) = __upt_val; break; \
+ case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \
+ case CS: UPT_CS(regs) = __upt_val; break; \
++ case SS: UPT_SS(regs) = __upt_val; break; \
++ case FS_BASE: UPT_FS_BASE(regs) = __upt_val; break; \
++ case GS_BASE: UPT_GS_BASE(regs) = __upt_val; break; \
++ case DS: UPT_DS(regs) = __upt_val; break; \
++ case ES: UPT_ES(regs) = __upt_val; break; \
++ case FS: UPT_FS(regs) = __upt_val; break; \
++ case GS: UPT_GS(regs) = __upt_val; break; \
+ case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \
+ default : \
+ panic("Bad register in UPT_SET : %d\n", reg); \
+diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
+index 128faf0..4cd61a8 100644
+--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
++++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
+@@ -55,7 +55,7 @@
+ #define PTRACE_OLDSETOPTIONS 21
+ #endif
+
+-/* These are before the system call, so the the system call number is RAX
++/* These are before the system call, so the system call number is RAX
+ * rather than ORIG_RAX, and arg4 is R10 rather than RCX
+ */
+ #define REGS_SYSCALL_NR PT_INDEX(RAX)
+diff --git a/arch/um/include/sysdep-x86_64/sc.h b/arch/um/include/sysdep-x86_64/sc.h
+index a160d9f..8aee45b 100644
+--- a/arch/um/include/sysdep-x86_64/sc.h
++++ b/arch/um/include/sysdep-x86_64/sc.h
+@@ -35,11 +35,11 @@
+ #define SC_GS(sc) SC_OFFSET(sc, SC_GS)
+ #define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS)
+ #define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK)
++#define SC_SS(sc) SC_OFFSET(sc, SC_SS)
+ #if 0
+ #define SC_ORIG_RAX(sc) SC_OFFSET(sc, SC_ORIG_RAX)
+ #define SC_DS(sc) SC_OFFSET(sc, SC_DS)
+ #define SC_ES(sc) SC_OFFSET(sc, SC_ES)
+-#define SC_SS(sc) SC_OFFSET(sc, SC_SS)
+ #endif
+
+ #endif
+diff --git a/arch/um/include/sysdep-x86_64/signal.h b/arch/um/include/sysdep-x86_64/signal.h
+deleted file mode 100644
+index 6142897..0000000
+--- a/arch/um/include/sysdep-x86_64/signal.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * Copyright (C) 2004 PathScale, Inc
+- * Licensed under the GPL
+- */
+-
+-#ifndef __X86_64_SIGNAL_H_
+-#define __X86_64_SIGNAL_H_
+-
+-#define ARCH_SIGHDLR_PARAM int sig
+-
+-#define ARCH_GET_SIGCONTEXT(sc, sig_addr) \
+- do { \
+- struct ucontext *__uc; \
+- asm("movq %%rdx, %0" : "=r" (__uc)); \
+- sc = (struct sigcontext *) &__uc->uc_mcontext; \
+- } while(0)
+-
+-#endif
+-
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * Emacs will notice this stuff at the end of the file and automatically
+- * adjust the settings for this buffer only. This must remain at the end
+- * of the file.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-file-style: "linux"
+- * End:
+- */
+diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h
+new file mode 100644
+index 0000000..0363a9b
+--- /dev/null
++++ b/arch/um/include/um_malloc.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade at yahoo.it>
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_MALLOC_H__
++#define __UM_MALLOC_H__
++
++extern void *um_kmalloc(int size);
++extern void *um_kmalloc_atomic(int size);
++extern void kfree(const void *ptr);
++
++extern void *um_vmalloc(int size);
++extern void *um_vmalloc_atomic(int size);
++extern void vfree(void *ptr);
++
++#endif /* __UM_MALLOC_H__ */
+diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
+index 4567f1e..5126a99 100644
+--- a/arch/um/include/um_uaccess.h
++++ b/arch/um/include/um_uaccess.h
+@@ -6,7 +6,6 @@
+ #ifndef __ARCH_UM_UACCESS_H
+ #define __ARCH_UM_UACCESS_H
+
+-#include "linux/config.h"
+ #include "choose-mode.h"
+
+ #ifdef CONFIG_MODE_TT
+diff --git a/arch/um/include/user.h b/arch/um/include/user.h
+index 39f8c88..acadce3 100644
+--- a/arch/um/include/user.h
++++ b/arch/um/include/user.h
+@@ -11,17 +11,11 @@ extern void panic(const char *fmt, ...)
+ extern int printk(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+ extern void schedule(void);
+-extern void *um_kmalloc(int size);
+-extern void *um_kmalloc_atomic(int size);
+-extern void kfree(void *ptr);
+ extern int in_aton(char *str);
+ extern int open_gdb_chan(void);
+ /* These use size_t, however unsigned long is correct on both i386 and x86_64. */
+ extern unsigned long strlcpy(char *, const char *, unsigned long);
+ extern unsigned long strlcat(char *, const char *, unsigned long);
+-extern void *um_vmalloc(int size);
+-extern void *um_vmalloc_atomic(int size);
+-extern void vfree(void *ptr);
+
+ #endif
+
+diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
+index 802d784..06625fe 100644
+--- a/arch/um/include/user_util.h
++++ b/arch/um/include/user_util.h
+@@ -52,7 +52,6 @@ extern int linux_main(int argc, char **a
+ extern void set_cmdline(char *cmd);
+ extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
+ extern int get_pty(void);
+-extern void *um_kmalloc(int size);
+ extern int switcheroo(int fd, int prot, void *from, void *to, int size);
+ extern void do_exec(int old_pid, int new_pid);
+ extern void tracer_panic(char *msg, ...)
+diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
+index a2d9306..6fa63a2 100644
+--- a/arch/um/kernel/Makefile
++++ b/arch/um/kernel/Makefile
+@@ -7,7 +7,7 @@ extra-y := vmlinux.lds
+ clean-files :=
+
+ obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
+- physmem.o process_kern.o ptrace.o reboot.o resource.o sigio.o \
++ physmem.o process.o ptrace.o reboot.o resource.o sigio.o \
+ signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
+ um_arch.o umid.o
+
+diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
+index 68ed24d..e36f92b 100644
+--- a/arch/um/kernel/dyn.lds.S
++++ b/arch/um/kernel/dyn.lds.S
+@@ -14,6 +14,7 @@ SECTIONS
+ * is remapped.*/
+ __binary_start = .;
+ . = ALIGN(4096); /* Init code and data */
++ _text = .;
+ _stext = .;
+ __init_begin = .;
+ .init.text : {
+diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
+index fc38a6d..0561c43 100644
+--- a/arch/um/kernel/exec.c
++++ b/arch/um/kernel/exec.c
+@@ -41,9 +41,11 @@ static long execve1(char *file, char __u
+ long error;
+
+ #ifdef CONFIG_TTY_LOG
+- task_lock(current);
++ mutex_lock(&tty_mutex);
++ task_lock(current); /* FIXME: is this needed ? */
+ log_exec(argv, current->signal->tty);
+ task_unlock(current);
++ mutex_unlock(&tty_mutex);
+ #endif
+ error = do_execve(file, argv, env, ¤t->thread.regs);
+ if (error == 0){
+diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
+index d21ebad..8b7f2cd 100644
+--- a/arch/um/kernel/exitcode.c
++++ b/arch/um/kernel/exitcode.c
+@@ -16,9 +16,13 @@ int uml_exitcode = 0;
+ static int read_proc_exitcode(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+ {
+- int len;
++ int len, val;
+
+- len = sprintf(page, "%d\n", uml_exitcode);
++ /* Save uml_exitcode in a local so that we don't need to guarantee
++ * that sprintf accesses it atomically.
++ */
++ val = uml_exitcode;
++ len = sprintf(page, "%d\n", val);
+ len -= off;
+ if(len <= off+count) *eof = 1;
+ *start = page + off;
+diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
+index 2c86e7f..13aa115 100644
+--- a/arch/um/kernel/gmon_syms.c
++++ b/arch/um/kernel/gmon_syms.c
+@@ -5,7 +5,7 @@
+
+ #include "linux/module.h"
+
+-extern void __bb_init_func(void *);
++extern void __bb_init_func(void *) __attribute__((weak));
+ EXPORT_SYMBOL(__bb_init_func);
+
+ /* This is defined (and referred to in profiling stub code) only by some GCC
+@@ -21,14 +21,3 @@ EXPORT_SYMBOL(__gcov_init);
+
+ extern void __gcov_merge_add(void *) __attribute__((weak));
+ EXPORT_SYMBOL(__gcov_merge_add);
+-
+-/*
+- * 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/init_task.c b/arch/um/kernel/init_task.c
+index 49ed5dd..8cde431 100644
+--- a/arch/um/kernel/init_task.c
++++ b/arch/um/kernel/init_task.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/mm.h"
+ #include "linux/module.h"
+ #include "linux/sched.h"
+diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
+index 589c69a..5c1e611 100644
+--- a/arch/um/kernel/irq.c
++++ b/arch/um/kernel/irq.c
+@@ -5,7 +5,6 @@
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ */
+
+-#include "linux/config.h"
+ #include "linux/kernel.h"
+ #include "linux/module.h"
+ #include "linux/smp.h"
+@@ -32,6 +31,7 @@
+ #include "irq_kern.h"
+ #include "os.h"
+ #include "sigio.h"
++#include "um_malloc.h"
+ #include "misc_constants.h"
+
+ /*
+@@ -142,19 +142,6 @@ int activate_fd(int irq, int fd, int typ
+ .events = events,
+ .current_events = 0 } );
+
+- /* Critical section - locked by a spinlock because this stuff can
+- * be changed from interrupt handlers. The stuff above is done
+- * outside the lock because it allocates memory.
+- */
+-
+- /* Actually, it only looks like it can be called from interrupt
+- * context. The culprit is reactivate_fd, which calls
+- * maybe_sigio_broken, which calls write_sigio_workaround,
+- * which calls activate_fd. However, write_sigio_workaround should
+- * only be called once, at boot time. That would make it clear that
+- * this is called only from process context, and can be locked with
+- * a semaphore.
+- */
+ spin_lock_irqsave(&irq_lock, flags);
+ for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
+ if ((irq_fd->fd == fd) && (irq_fd->type == type)) {
+@@ -165,7 +152,6 @@ int activate_fd(int irq, int fd, int typ
+ }
+ }
+
+- /*-------------*/
+ if (type == IRQ_WRITE)
+ fd = -1;
+
+@@ -198,7 +184,6 @@ int activate_fd(int irq, int fd, int typ
+
+ spin_lock_irqsave(&irq_lock, flags);
+ }
+- /*-------------*/
+
+ *last_irq_ptr = new_fd;
+ last_irq_ptr = &new_fd->next;
+@@ -210,14 +195,14 @@ int activate_fd(int irq, int fd, int typ
+ */
+ maybe_sigio_broken(fd, (type == IRQ_READ));
+
+- return(0);
++ return 0;
+
+ out_unlock:
+ spin_unlock_irqrestore(&irq_lock, flags);
+ out_kfree:
+ kfree(new_fd);
+ out:
+- return(err);
++ return err;
+ }
+
+ static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+@@ -302,10 +287,7 @@ void reactivate_fd(int fd, int irqnum)
+ os_set_pollfd(i, irq->fd);
+ spin_unlock_irqrestore(&irq_lock, flags);
+
+- /* This calls activate_fd, so it has to be outside the critical
+- * section.
+- */
+- maybe_sigio_broken(fd, (irq->type == IRQ_READ));
++ add_sigio_fd(fd);
+ }
+
+ void deactivate_fd(int fd, int irqnum)
+@@ -316,11 +298,15 @@ void deactivate_fd(int fd, int irqnum)
+
+ spin_lock_irqsave(&irq_lock, flags);
+ irq = find_irq_by_fd(fd, irqnum, &i);
+- if (irq == NULL)
+- goto out;
++ if(irq == NULL){
++ spin_unlock_irqrestore(&irq_lock, flags);
++ return;
++ }
++
+ os_set_pollfd(i, -1);
+- out:
+ spin_unlock_irqrestore(&irq_lock, flags);
++
++ ignore_sigio_fd(fd);
+ }
+
+ int deactivate_all_fds(void)
+@@ -370,14 +356,16 @@ void forward_interrupts(int pid)
+ */
+ unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
+ {
+- irq_enter();
+- __do_IRQ(irq, (struct pt_regs *)regs);
+- irq_exit();
+- return 1;
++ struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
++ irq_enter();
++ __do_IRQ(irq);
++ irq_exit();
++ set_irq_regs(old_regs);
++ return 1;
+ }
+
+ int um_request_irq(unsigned int irq, int fd, int type,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irqflags, const char * devname,
+ void *dev_id)
+ {
+@@ -438,8 +426,7 @@ void __init init_IRQ(void)
+ }
+ }
+
+-int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *,
+- struct pt_regs *))
++int init_aio_irq(int irq, char *name, irq_handler_t handler)
+ {
+ int fds[2], err;
+
+diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
+index c97045d..0e00cf9 100644
+--- a/arch/um/kernel/ksyms.c
++++ b/arch/um/kernel/ksyms.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/module.h"
+ #include "linux/string.h"
+ #include "linux/smp_lock.h"
+@@ -21,7 +20,6 @@
+ #include "mem_user.h"
+ #include "os.h"
+
+-EXPORT_SYMBOL(stop);
+ EXPORT_SYMBOL(uml_physmem);
+ EXPORT_SYMBOL(set_signals);
+ EXPORT_SYMBOL(get_signals);
+@@ -41,12 +39,14 @@ EXPORT_SYMBOL(handle_page_fault);
+ EXPORT_SYMBOL(find_iomem);
+
+ #ifdef CONFIG_MODE_TT
++EXPORT_SYMBOL(stop);
+ EXPORT_SYMBOL(strncpy_from_user_tt);
+ EXPORT_SYMBOL(copy_from_user_tt);
+ EXPORT_SYMBOL(copy_to_user_tt);
+ #endif
+
+ #ifdef CONFIG_MODE_SKAS
++EXPORT_SYMBOL(strnlen_user_skas);
+ EXPORT_SYMBOL(strncpy_from_user_skas);
+ EXPORT_SYMBOL(copy_to_user_skas);
+ EXPORT_SYMBOL(copy_from_user_skas);
+diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
+index 6128016..c95855b 100644
+--- a/arch/um/kernel/mem.c
++++ b/arch/um/kernel/mem.c
+@@ -79,8 +79,10 @@ void mem_init(void)
+
+ /* this will put all low memory onto the freelists */
+ totalram_pages = free_all_bootmem();
++#ifdef CONFIG_HIGHMEM
+ totalhigh_pages = highmem >> PAGE_SHIFT;
+ totalram_pages += totalhigh_pages;
++#endif
+ num_physpages = totalram_pages;
+ max_pfn = totalram_pages;
+ printk(KERN_INFO "Memory: %luk available\n",
+@@ -221,10 +223,14 @@ void paging_init(void)
+
+ empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+ empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+- for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++)
++ for(i = 0; i < ARRAY_SIZE(zones_size); i++)
+ zones_size[i] = 0;
+- zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
++
++ zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
++ (uml_physmem >> PAGE_SHIFT);
++#ifdef CONFIG_HIGHMEM
+ zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
++#endif
+ free_area_init(zones_size);
+
+ /*
+diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
+new file mode 100644
+index 0000000..348b272
+--- /dev/null
++++ b/arch/um/kernel/process.c
+@@ -0,0 +1,484 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike at karaya.com)
++ * Copyright 2003 PathScale, Inc.
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/interrupt.h"
++#include "linux/string.h"
++#include "linux/mm.h"
++#include "linux/slab.h"
++#include "linux/utsname.h"
++#include "linux/fs.h"
++#include "linux/utime.h"
++#include "linux/smp_lock.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/capability.h"
++#include "linux/vmalloc.h"
++#include "linux/spinlock.h"
++#include "linux/proc_fs.h"
++#include "linux/ptrace.h"
++#include "linux/random.h"
++#include "linux/personality.h"
++#include "asm/unistd.h"
++#include "asm/mman.h"
++#include "asm/segment.h"
++#include "asm/stat.h"
++#include "asm/pgtable.h"
++#include "asm/processor.h"
++#include "asm/tlbflush.h"
++#include "asm/uaccess.h"
++#include "asm/user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "signal_kern.h"
++#include "init.h"
++#include "irq_user.h"
++#include "mem_user.h"
++#include "tlb.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "os.h"
++#include "mode.h"
++#include "mode_kern.h"
++#include "choose-mode.h"
++#include "um_malloc.h"
++
++/* This is a per-cpu array. A processor only modifies its entry and it only
++ * cares about its entry, so it's OK if another processor is modifying its
++ * entry.
++ */
++struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
++
++int external_pid(void *t)
++{
++ struct task_struct *task = t ? t : current;
++
++ return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
++}
++
++int pid_to_processor_id(int pid)
++{
++ int i;
++
++ for(i = 0; i < ncpus; i++){
++ if(cpu_tasks[i].pid == pid) return(i);
++ }
++ return(-1);
++}
++
++void free_stack(unsigned long stack, int order)
++{
++ free_pages(stack, order);
++}
++
++unsigned long alloc_stack(int order, int atomic)
++{
++ unsigned long page;
++ gfp_t flags = GFP_KERNEL;
++
++ if (atomic)
++ flags = GFP_ATOMIC;
++ page = __get_free_pages(flags, order);
++ if(page == 0)
++ return(0);
++ stack_protections(page);
++ return(page);
++}
++
++int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++{
++ int pid;
++
++ current->thread.request.u.thread.proc = fn;
++ current->thread.request.u.thread.arg = arg;
++ pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
++ ¤t->thread.regs, 0, NULL, NULL);
++ if(pid < 0)
++ panic("do_fork failed in kernel_thread, errno = %d", pid);
++ return(pid);
++}
++
++void set_current(void *t)
++{
++ struct task_struct *task = t;
++
++ cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
++ { external_pid(task), task });
++}
++
++void *_switch_to(void *prev, void *next, void *last)
++{
++ struct task_struct *from = prev;
++ struct task_struct *to= next;
++
++ to->thread.prev_sched = from;
++ set_current(to);
++
++ do {
++ current->thread.saved_task = NULL ;
++ CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next);
++ if(current->thread.saved_task)
++ show_regs(&(current->thread.regs));
++ next= current->thread.saved_task;
++ prev= current;
++ } while(current->thread.saved_task);
++
++ return(current->thread.prev_sched);
++
++}
++
++void interrupt_end(void)
++{
++ if(need_resched()) schedule();
++ if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
++}
++
++void release_thread(struct task_struct *task)
++{
++ CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
++}
++
++void exit_thread(void)
++{
++ unprotect_stack((unsigned long) current_thread);
++}
++
++void *get_current(void)
++{
++ return(current);
++}
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
++ unsigned long stack_top, struct task_struct * p,
++ struct pt_regs *regs)
++{
++ int ret;
++
++ p->thread = (struct thread_struct) INIT_THREAD;
++ ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
++ clone_flags, sp, stack_top, p, regs);
++
++ if (ret || !current->thread.forking)
++ goto out;
++
++ clear_flushed_tls(p);
++
++ /*
++ * Set a new TLS for the child thread?
++ */
++ if (clone_flags & CLONE_SETTLS)
++ ret = arch_copy_tls(p);
++
++out:
++ return ret;
++}
++
++void initial_thread_cb(void (*proc)(void *), void *arg)
++{
++ int save_kmalloc_ok = kmalloc_ok;
++
++ kmalloc_ok = 0;
++ CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
++ arg);
++ kmalloc_ok = save_kmalloc_ok;
++}
++
++unsigned long stack_sp(unsigned long page)
++{
++ return(page + PAGE_SIZE - sizeof(void *));
++}
++
++int current_pid(void)
++{
++ return(current->pid);
++}
++
++void default_idle(void)
++{
++ CHOOSE_MODE(uml_idle_timer(), (void) 0);
++
++ while(1){
++ /* endless idle loop with no priority at all */
++
++ /*
++ * although we are an idle CPU, we do not want to
++ * get into the scheduler unnecessarily.
++ */
++ if(need_resched())
++ schedule();
++
++ idle_sleep(10);
++ }
++}
++
++void cpu_idle(void)
++{
++ CHOOSE_MODE(init_idle_tt(), init_idle_skas());
++}
++
++int page_size(void)
++{
++ return(PAGE_SIZE);
++}
++
++void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
++ pte_t *pte_out)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ pte_t ptent;
++
++ if(task->mm == NULL)
++ return(ERR_PTR(-EINVAL));
++ pgd = pgd_offset(task->mm, addr);
++ if(!pgd_present(*pgd))
++ return(ERR_PTR(-EINVAL));
++
++ pud = pud_offset(pgd, addr);
++ if(!pud_present(*pud))
++ return(ERR_PTR(-EINVAL));
++
++ pmd = pmd_offset(pud, addr);
++ if(!pmd_present(*pmd))
++ return(ERR_PTR(-EINVAL));
++
++ pte = pte_offset_kernel(pmd, addr);
++ ptent = *pte;
++ if(!pte_present(ptent))
++ return(ERR_PTR(-EINVAL));
++
++ if(pte_out != NULL)
++ *pte_out = ptent;
++ return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK));
++}
++
++char *current_cmd(void)
++{
++#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
++ return("(Unknown)");
++#else
++ void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
++ return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
++#endif
++}
++
++void force_sigbus(void)
++{
++ printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
++ current->pid);
++ lock_kernel();
++ sigaddset(¤t->pending.signal, SIGBUS);
++ recalc_sigpending();
++ current->flags |= PF_SIGNALED;
++ do_exit(SIGBUS | 0x80);
++}
++
++void dump_thread(struct pt_regs *regs, struct user *u)
++{
++}
++
++void enable_hlt(void)
++{
++ panic("enable_hlt");
++}
++
++EXPORT_SYMBOL(enable_hlt);
++
++void disable_hlt(void)
++{
++ panic("disable_hlt");
++}
++
++EXPORT_SYMBOL(disable_hlt);
++
++void *um_kmalloc(int size)
++{
++ return kmalloc(size, GFP_KERNEL);
++}
++
++void *um_kmalloc_atomic(int size)
++{
++ return kmalloc(size, GFP_ATOMIC);
++}
++
++void *um_vmalloc(int size)
++{
++ return vmalloc(size);
++}
++
++void *um_vmalloc_atomic(int size)
++{
++ return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL);
++}
++
++int __cant_sleep(void) {
++ return in_atomic() || irqs_disabled() || in_interrupt();
++ /* Is in_interrupt() really needed? */
++}
++
++unsigned long get_fault_addr(void)
++{
++ return((unsigned long) current->thread.fault_addr);
++}
++
++EXPORT_SYMBOL(get_fault_addr);
++
++void not_implemented(void)
++{
++ printk(KERN_DEBUG "Something isn't implemented in here\n");
++}
++
++EXPORT_SYMBOL(not_implemented);
++
++int user_context(unsigned long sp)
++{
++ unsigned long stack;
++
++ stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
++ return(stack != (unsigned long) current_thread);
++}
++
++extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
++
++void do_uml_exitcalls(void)
++{
++ exitcall_t *call;
++
++ call = &__uml_exitcall_end;
++ while (--call >= &__uml_exitcall_begin)
++ (*call)();
++}
++
++char *uml_strdup(char *string)
++{
++ return kstrdup(string, GFP_KERNEL);
++}
++
++int copy_to_user_proc(void __user *to, void *from, int size)
++{
++ return(copy_to_user(to, from, size));
++}
++
++int copy_from_user_proc(void *to, void __user *from, int size)
++{
++ return(copy_from_user(to, from, size));
++}
++
++int clear_user_proc(void __user *buf, int size)
++{
++ return(clear_user(buf, size));
++}
++
++int strlen_user_proc(char __user *str)
++{
++ return(strlen_user(str));
++}
++
++int smp_sigio_handler(void)
++{
++#ifdef CONFIG_SMP
++ int cpu = current_thread->cpu;
++ IPI_handler(cpu);
++ if(cpu != 0)
++ return(1);
++#endif
++ return(0);
++}
++
++int cpu(void)
++{
++ return(current_thread->cpu);
++}
++
++static atomic_t using_sysemu = ATOMIC_INIT(0);
++int sysemu_supported;
++
++void set_using_sysemu(int value)
++{
++ if (value > sysemu_supported)
++ return;
++ atomic_set(&using_sysemu, value);
++}
++
++int get_using_sysemu(void)
++{
++ return atomic_read(&using_sysemu);
++}
++
++static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
++{
++ if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
++ *eof = 1;
++
++ return strlen(buf);
++}
++
++static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data)
++{
++ char tmp[2];
++
++ if (copy_from_user(tmp, buf, 1))
++ return -EFAULT;
++
++ if (tmp[0] >= '0' && tmp[0] <= '2')
++ set_using_sysemu(tmp[0] - '0');
++ return count; /*We use the first char, but pretend to write everything*/
++}
++
++int __init make_proc_sysemu(void)
++{
++ struct proc_dir_entry *ent;
++ if (!sysemu_supported)
++ return 0;
++
++ ent = create_proc_entry("sysemu", 0600, &proc_root);
++
++ if (ent == NULL)
++ {
++ printk(KERN_WARNING "Failed to register /proc/sysemu\n");
++ return(0);
++ }
++
++ ent->read_proc = proc_read_sysemu;
++ ent->write_proc = proc_write_sysemu;
++
++ return 0;
++}
++
++late_initcall(make_proc_sysemu);
++
++int singlestepping(void * t)
++{
++ struct task_struct *task = t ? t : current;
++
++ if ( ! (task->ptrace & PT_DTRACE) )
++ return(0);
++
++ if (task->thread.singlestep_syscall)
++ return(1);
++
++ return 2;
++}
++
++/*
++ * Only x86 and x86_64 have an arch_align_stack().
++ * All other arches have "#define arch_align_stack(x) (x)"
++ * in their asm/system.h
++ * As this is included in UML from asm-um/system-generic.h,
++ * we can use it to behave as the subarch does.
++ */
++#ifndef arch_align_stack
++unsigned long arch_align_stack(unsigned long sp)
++{
++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
++ sp -= get_random_int() % 8192;
++ return sp & ~0xf;
++}
++#endif
+diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
+deleted file mode 100644
+index f6a5a50..0000000
+--- a/arch/um/kernel/process_kern.c
++++ /dev/null
+@@ -1,483 +0,0 @@
+-/*
+- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike at karaya.com)
+- * Copyright 2003 PathScale, Inc.
+- * Licensed under the GPL
+- */
+-
+-#include "linux/config.h"
+-#include "linux/kernel.h"
+-#include "linux/sched.h"
+-#include "linux/interrupt.h"
+-#include "linux/string.h"
+-#include "linux/mm.h"
+-#include "linux/slab.h"
+-#include "linux/utsname.h"
+-#include "linux/fs.h"
+-#include "linux/utime.h"
+-#include "linux/smp_lock.h"
+-#include "linux/module.h"
+-#include "linux/init.h"
+-#include "linux/capability.h"
+-#include "linux/vmalloc.h"
+-#include "linux/spinlock.h"
+-#include "linux/proc_fs.h"
+-#include "linux/ptrace.h"
+-#include "linux/random.h"
+-#include "asm/unistd.h"
+-#include "asm/mman.h"
+-#include "asm/segment.h"
+-#include "asm/stat.h"
+-#include "asm/pgtable.h"
+-#include "asm/processor.h"
+-#include "asm/tlbflush.h"
+-#include "asm/uaccess.h"
+-#include "asm/user.h"
+-#include "user_util.h"
+-#include "kern_util.h"
+-#include "kern.h"
+-#include "signal_kern.h"
+-#include "init.h"
+-#include "irq_user.h"
+-#include "mem_user.h"
+-#include "tlb.h"
+-#include "frame_kern.h"
+-#include "sigcontext.h"
+-#include "os.h"
+-#include "mode.h"
+-#include "mode_kern.h"
+-#include "choose-mode.h"
+-
+-/* This is a per-cpu array. A processor only modifies its entry and it only
+- * cares about its entry, so it's OK if another processor is modifying its
+- * entry.
+- */
+-struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
+-
+-int external_pid(void *t)
+-{
+- struct task_struct *task = t ? t : current;
+-
+- return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
+-}
+-
+-int pid_to_processor_id(int pid)
+-{
+- int i;
+-
+- for(i = 0; i < ncpus; i++){
+- if(cpu_tasks[i].pid == pid) return(i);
+- }
+- return(-1);
+-}
+-
+-void free_stack(unsigned long stack, int order)
+-{
+- free_pages(stack, order);
+-}
+-
+-unsigned long alloc_stack(int order, int atomic)
+-{
+- unsigned long page;
+- gfp_t flags = GFP_KERNEL;
+-
+- if (atomic)
+- flags = GFP_ATOMIC;
+- page = __get_free_pages(flags, order);
+- if(page == 0)
+- return(0);
+- stack_protections(page);
+- return(page);
+-}
+-
+-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+-{
+- int pid;
+-
+- current->thread.request.u.thread.proc = fn;
+- current->thread.request.u.thread.arg = arg;
+- pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
+- ¤t->thread.regs, 0, NULL, NULL);
+- if(pid < 0)
+- panic("do_fork failed in kernel_thread, errno = %d", pid);
+- return(pid);
+-}
+-
+-void set_current(void *t)
+-{
+- struct task_struct *task = t;
+-
+- cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
+- { external_pid(task), task });
+-}
+-
+-void *_switch_to(void *prev, void *next, void *last)
+-{
+- struct task_struct *from = prev;
+- struct task_struct *to= next;
+-
+- to->thread.prev_sched = from;
+- set_current(to);
+-
+- do {
+- current->thread.saved_task = NULL ;
+- CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next);
+- if(current->thread.saved_task)
+- show_regs(&(current->thread.regs));
+- next= current->thread.saved_task;
+- prev= current;
+- } while(current->thread.saved_task);
+-
+- return(current->thread.prev_sched);
+-
+-}
+-
+-void interrupt_end(void)
+-{
+- if(need_resched()) schedule();
+- if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
+-}
+-
+-void release_thread(struct task_struct *task)
+-{
+- CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
+-}
+-
+-void exit_thread(void)
+-{
+- unprotect_stack((unsigned long) current_thread);
+-}
+-
+-void *get_current(void)
+-{
+- return(current);
+-}
+-
+-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+- unsigned long stack_top, struct task_struct * p,
+- struct pt_regs *regs)
+-{
+- int ret;
+-
+- p->thread = (struct thread_struct) INIT_THREAD;
+- ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
+- clone_flags, sp, stack_top, p, regs);
+-
+- if (ret || !current->thread.forking)
+- goto out;
+-
+- clear_flushed_tls(p);
+-
+- /*
+- * Set a new TLS for the child thread?
+- */
+- if (clone_flags & CLONE_SETTLS)
+- ret = arch_copy_tls(p);
+-
+-out:
+- return ret;
+-}
+-
+-void initial_thread_cb(void (*proc)(void *), void *arg)
+-{
+- int save_kmalloc_ok = kmalloc_ok;
+-
+- kmalloc_ok = 0;
+- CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
+- arg);
+- kmalloc_ok = save_kmalloc_ok;
+-}
+-
+-unsigned long stack_sp(unsigned long page)
+-{
+- return(page + PAGE_SIZE - sizeof(void *));
+-}
+-
+-int current_pid(void)
+-{
+- return(current->pid);
+-}
+-
+-void default_idle(void)
+-{
+- CHOOSE_MODE(uml_idle_timer(), (void) 0);
+-
+- while(1){
+- /* endless idle loop with no priority at all */
+-
+- /*
+- * although we are an idle CPU, we do not want to
+- * get into the scheduler unnecessarily.
+- */
+- if(need_resched())
+- schedule();
+-
+- idle_sleep(10);
+- }
+-}
+-
+-void cpu_idle(void)
+-{
+- CHOOSE_MODE(init_idle_tt(), init_idle_skas());
+-}
+-
+-int page_size(void)
+-{
+- return(PAGE_SIZE);
+-}
+-
+-void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
+- pte_t *pte_out)
+-{
+- pgd_t *pgd;
+- pud_t *pud;
+- pmd_t *pmd;
+- pte_t *pte;
+- pte_t ptent;
+-
+- if(task->mm == NULL)
+- return(ERR_PTR(-EINVAL));
+- pgd = pgd_offset(task->mm, addr);
+- if(!pgd_present(*pgd))
+- return(ERR_PTR(-EINVAL));
+-
+- pud = pud_offset(pgd, addr);
+- if(!pud_present(*pud))
+- return(ERR_PTR(-EINVAL));
+-
+- pmd = pmd_offset(pud, addr);
+- if(!pmd_present(*pmd))
+- return(ERR_PTR(-EINVAL));
+-
+- pte = pte_offset_kernel(pmd, addr);
+- ptent = *pte;
+- if(!pte_present(ptent))
+- return(ERR_PTR(-EINVAL));
+-
+- if(pte_out != NULL)
+- *pte_out = ptent;
+- return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK));
+-}
+-
+-char *current_cmd(void)
+-{
+-#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
+- return("(Unknown)");
+-#else
+- void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
+- return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
+-#endif
+-}
+-
+-void force_sigbus(void)
+-{
+- printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
+- current->pid);
+- lock_kernel();
+- sigaddset(¤t->pending.signal, SIGBUS);
+- recalc_sigpending();
+- current->flags |= PF_SIGNALED;
+- do_exit(SIGBUS | 0x80);
+-}
+-
+-void dump_thread(struct pt_regs *regs, struct user *u)
+-{
+-}
+-
+-void enable_hlt(void)
+-{
+- panic("enable_hlt");
+-}
+-
+-EXPORT_SYMBOL(enable_hlt);
+-
+-void disable_hlt(void)
+-{
+- panic("disable_hlt");
+-}
+-
+-EXPORT_SYMBOL(disable_hlt);
+-
+-void *um_kmalloc(int size)
+-{
+- return kmalloc(size, GFP_KERNEL);
+-}
+-
+-void *um_kmalloc_atomic(int size)
+-{
+- return kmalloc(size, GFP_ATOMIC);
+-}
+-
+-void *um_vmalloc(int size)
+-{
+- return vmalloc(size);
+-}
+-
+-void *um_vmalloc_atomic(int size)
+-{
+- return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL);
+-}
+-
+-int __cant_sleep(void) {
+- return in_atomic() || irqs_disabled() || in_interrupt();
+- /* Is in_interrupt() really needed? */
+-}
+-
+-unsigned long get_fault_addr(void)
+-{
+- return((unsigned long) current->thread.fault_addr);
+-}
+-
+-EXPORT_SYMBOL(get_fault_addr);
+-
+-void not_implemented(void)
+-{
+- printk(KERN_DEBUG "Something isn't implemented in here\n");
+-}
+-
+-EXPORT_SYMBOL(not_implemented);
+-
+-int user_context(unsigned long sp)
+-{
+- unsigned long stack;
+-
+- stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
+- return(stack != (unsigned long) current_thread);
+-}
+-
+-extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
+-
+-void do_uml_exitcalls(void)
+-{
+- exitcall_t *call;
+-
+- call = &__uml_exitcall_end;
+- while (--call >= &__uml_exitcall_begin)
+- (*call)();
+-}
+-
+-char *uml_strdup(char *string)
+-{
+- return kstrdup(string, GFP_KERNEL);
+-}
+-
+-int copy_to_user_proc(void __user *to, void *from, int size)
+-{
+- return(copy_to_user(to, from, size));
+-}
+-
+-int copy_from_user_proc(void *to, void __user *from, int size)
+-{
+- return(copy_from_user(to, from, size));
+-}
+-
+-int clear_user_proc(void __user *buf, int size)
+-{
+- return(clear_user(buf, size));
+-}
+-
+-int strlen_user_proc(char __user *str)
+-{
+- return(strlen_user(str));
+-}
+-
+-int smp_sigio_handler(void)
+-{
+-#ifdef CONFIG_SMP
+- int cpu = current_thread->cpu;
+- IPI_handler(cpu);
+- if(cpu != 0)
+- return(1);
+-#endif
+- return(0);
+-}
+-
+-int cpu(void)
+-{
+- return(current_thread->cpu);
+-}
+-
+-static atomic_t using_sysemu = ATOMIC_INIT(0);
+-int sysemu_supported;
+-
+-void set_using_sysemu(int value)
+-{
+- if (value > sysemu_supported)
+- return;
+- atomic_set(&using_sysemu, value);
+-}
+-
+-int get_using_sysemu(void)
+-{
+- return atomic_read(&using_sysemu);
+-}
+-
+-static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
+-{
+- if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
+- *eof = 1;
+-
+- return strlen(buf);
+-}
+-
+-static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data)
+-{
+- char tmp[2];
+-
+- if (copy_from_user(tmp, buf, 1))
+- return -EFAULT;
+-
+- if (tmp[0] >= '0' && tmp[0] <= '2')
+- set_using_sysemu(tmp[0] - '0');
+- return count; /*We use the first char, but pretend to write everything*/
+-}
+-
+-int __init make_proc_sysemu(void)
+-{
+- struct proc_dir_entry *ent;
+- if (!sysemu_supported)
+- return 0;
+-
+- ent = create_proc_entry("sysemu", 0600, &proc_root);
+-
+- if (ent == NULL)
+- {
+- printk(KERN_WARNING "Failed to register /proc/sysemu\n");
+- return(0);
+- }
+-
+- ent->read_proc = proc_read_sysemu;
+- ent->write_proc = proc_write_sysemu;
+-
+- return 0;
+-}
+-
+-late_initcall(make_proc_sysemu);
+-
+-int singlestepping(void * t)
+-{
+- struct task_struct *task = t ? t : current;
+-
+- if ( ! (task->ptrace & PT_DTRACE) )
+- return(0);
+-
+- if (task->thread.singlestep_syscall)
+- return(1);
+-
+- return 2;
+-}
+-
+-/*
+- * Only x86 and x86_64 have an arch_align_stack().
+- * All other arches have "#define arch_align_stack(x) (x)"
+- * in their asm/system.h
+- * As this is included in UML from asm-um/system-generic.h,
+- * we can use it to behave as the subarch does.
+- */
+-#ifndef arch_align_stack
+-unsigned long arch_align_stack(unsigned long sp)
+-{
+- if (randomize_va_space)
+- sp -= get_random_int() % 8192;
+- return sp & ~0xf;
+-}
+-#endif
+diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
+index 3ef73bf..f602623 100644
+--- a/arch/um/kernel/reboot.c
++++ b/arch/um/kernel/reboot.c
+@@ -22,7 +22,7 @@ static void kill_idlers(int me)
+ struct task_struct *p;
+ int i;
+
+- for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){
++ for(i = 0; i < ARRAY_SIZE(idle_threads); i++){
+ p = idle_threads[i];
+ if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
+ os_kill_process(p->thread.mode.tt.extern_pid, 0);
+@@ -62,14 +62,3 @@ void machine_halt(void)
+ {
+ machine_power_off();
+ }
+-
+-/*
+- * 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/sigio.c b/arch/um/kernel/sigio.c
+index 0ad755c..2b0ab43 100644
+--- a/arch/um/kernel/sigio.c
++++ b/arch/um/kernel/sigio.c
+@@ -17,7 +17,7 @@
+ /* Protected by sigio_lock() called from write_sigio_workaround */
+ static int sigio_irq_fd = -1;
+
+-static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
++static irqreturn_t sigio_interrupt(int irq, void *data)
+ {
+ char c;
+
+diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
+index 4aa9808..2a32e5e 100644
+--- a/arch/um/kernel/signal.c
++++ b/arch/um/kernel/signal.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/stddef.h"
+ #include "linux/sys.h"
+ #include "linux/sched.h"
+diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
+index ea3a8e4..3e3fa7e 100644
+--- a/arch/um/kernel/skas/Makefile
++++ b/arch/um/kernel/skas/Makefile
+@@ -3,8 +3,7 @@
+ # Licensed under the GPL
+ #
+
+-obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \
+- syscall.o tlb.o uaccess.o
++obj-y := clone.o exec.o mem.o mmu.o process.o syscall.o tlb.o uaccess.o
+
+ # clone.o is in the stub, so it can't be built with profiling
+ # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
+diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c
+new file mode 100644
+index 0000000..54b7959
+--- /dev/null
++++ b/arch/um/kernel/skas/exec.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "asm/current.h"
++#include "asm/page.h"
++#include "asm/signal.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++#include "tlb.h"
++#include "skas.h"
++#include "um_mmu.h"
++#include "os.h"
++
++void flush_thread_skas(void)
++{
++ force_flush_all();
++ switch_mm_skas(¤t->mm->context.skas.id);
++}
++
++void start_thread_skas(struct pt_regs *regs, unsigned long eip,
++ unsigned long esp)
++{
++ set_fs(USER_DS);
++ PT_REGS_IP(regs) = eip;
++ PT_REGS_SP(regs) = esp;
++}
+diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
+deleted file mode 100644
+index 77ed7bb..0000000
+--- a/arch/um/kernel/skas/exec_kern.c
++++ /dev/null
+@@ -1,41 +0,0 @@
+-/*
+- * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
+- * Licensed under the GPL
+- */
+-
+-#include "linux/kernel.h"
+-#include "asm/current.h"
+-#include "asm/page.h"
+-#include "asm/signal.h"
+-#include "asm/ptrace.h"
+-#include "asm/uaccess.h"
+-#include "asm/mmu_context.h"
+-#include "tlb.h"
+-#include "skas.h"
+-#include "um_mmu.h"
+-#include "os.h"
+-
+-void flush_thread_skas(void)
+-{
+- force_flush_all();
+- switch_mm_skas(¤t->mm->context.skas.id);
+-}
+-
+-void start_thread_skas(struct pt_regs *regs, unsigned long eip,
+- unsigned long esp)
+-{
+- set_fs(USER_DS);
+- PT_REGS_IP(regs) = eip;
+- PT_REGS_SP(regs) = esp;
+-}
+-
+-/*
+- * 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/mem.c b/arch/um/kernel/skas/mem.c
+index 27bbf54..0d2cce6 100644
+--- a/arch/um/kernel/skas/mem.c
++++ b/arch/um/kernel/skas/mem.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/mm.h"
+ #include "asm/pgtable.h"
+ #include "mem_user.h"
+diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
+index 624ca23..2c6d090 100644
+--- a/arch/um/kernel/skas/mmu.c
++++ b/arch/um/kernel/skas/mmu.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/sched.h"
+ #include "linux/list.h"
+ #include "linux/spinlock.h"
+@@ -55,14 +54,13 @@ static int init_stub_pte(struct mm_struc
+ * destroy_context_skas.
+ */
+
+- mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
++ mm->context.skas.last_page_table = pmd_page_vaddr(*pmd);
+ #ifdef CONFIG_3_LEVEL_PGTABLES
+ mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud));
+ #endif
+
+ *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
+- *pte = pte_mkexec(*pte);
+- *pte = pte_wrprotect(*pte);
++ *pte = pte_mkread(*pte);
+ return(0);
+
+ out_pmd:
+diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
+new file mode 100644
+index 0000000..ae4fa71
+--- /dev/null
++++ b/arch/um/kernel/skas/process.c
+@@ -0,0 +1,217 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "linux/ptrace.h"
++#include "linux/proc_fs.h"
++#include "linux/file.h"
++#include "linux/errno.h"
++#include "linux/init.h"
++#include "asm/uaccess.h"
++#include "asm/atomic.h"
++#include "kern_util.h"
++#include "skas.h"
++#include "os.h"
++#include "user_util.h"
++#include "tlb.h"
++#include "kern.h"
++#include "mode.h"
++#include "registers.h"
++
++void switch_to_skas(void *prev, void *next)
++{
++ struct task_struct *from, *to;
++
++ from = prev;
++ to = next;
++
++ /* XXX need to check runqueues[cpu].idle */
++ if(current->pid == 0)
++ switch_timers(0);
++
++ switch_threads(&from->thread.mode.skas.switch_buf,
++ &to->thread.mode.skas.switch_buf);
++
++ arch_switch_to_skas(current->thread.prev_sched, current);
++
++ if(current->pid == 0)
++ switch_timers(1);
++}
++
++extern void schedule_tail(struct task_struct *prev);
++
++/* This is called magically, by its address being stuffed in a jmp_buf
++ * and being longjmp-d to.
++ */
++void new_thread_handler(void)
++{
++ int (*fn)(void *), n;
++ void *arg;
++
++ if(current->thread.prev_sched != NULL)
++ schedule_tail(current->thread.prev_sched);
++ current->thread.prev_sched = NULL;
++
++ fn = current->thread.request.u.thread.proc;
++ arg = current->thread.request.u.thread.arg;
++
++ /* The return value is 1 if the kernel thread execs a process,
++ * 0 if it just exits
++ */
++ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf);
++ if(n == 1){
++ /* Handle any immediate reschedules or signals */
++ interrupt_end();
++ userspace(¤t->thread.regs.regs);
++ }
++ else do_exit(0);
++}
++
++void release_thread_skas(struct task_struct *task)
++{
++}
++
++/* Called magically, see new_thread_handler above */
++void fork_handler(void)
++{
++ force_flush_all();
++ if(current->thread.prev_sched == NULL)
++ panic("blech");
++
++ schedule_tail(current->thread.prev_sched);
++
++ /* XXX: if interrupt_end() calls schedule, this call to
++ * arch_switch_to_skas isn't needed. We could want to apply this to
++ * improve performance. -bb */
++ arch_switch_to_skas(current->thread.prev_sched, current);
++
++ current->thread.prev_sched = NULL;
++
++/* Handle any immediate reschedules or signals */
++ interrupt_end();
++
++ userspace(¤t->thread.regs.regs);
++}
++
++int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
++ unsigned long stack_top, struct task_struct * p,
++ struct pt_regs *regs)
++{
++ void (*handler)(void);
++
++ if(current->thread.forking){
++ memcpy(&p->thread.regs.regs.skas, ®s->regs.skas,
++ sizeof(p->thread.regs.regs.skas));
++ REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
++ if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
++
++ handler = fork_handler;
++
++ arch_copy_thread(¤t->thread.arch, &p->thread.arch);
++ }
++ else {
++ init_thread_registers(&p->thread.regs.regs);
++ p->thread.request.u.thread = current->thread.request.u.thread;
++ handler = new_thread_handler;
++ }
++
++ new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf,
++ handler);
++ return(0);
++}
++
++int new_mm(unsigned long stack)
++{
++ int fd;
++
++ fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
++ if(fd < 0)
++ return(fd);
++
++ if(skas_needs_stub)
++ map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
++
++ return(fd);
++}
++
++void init_idle_skas(void)
++{
++ cpu_tasks[current_thread->cpu].pid = os_getpid();
++ default_idle();
++}
++
++extern void start_kernel(void);
++
++static int start_kernel_proc(void *unused)
++{
++ int pid;
++
++ block_signals();
++ pid = os_getpid();
++
++ cpu_tasks[0].pid = pid;
++ cpu_tasks[0].task = current;
++#ifdef CONFIG_SMP
++ cpu_online_map = cpumask_of_cpu(0);
++#endif
++ start_kernel();
++ return(0);
++}
++
++extern int userspace_pid[];
++
++int start_uml_skas(void)
++{
++ if(proc_mm)
++ userspace_pid[0] = start_userspace(0);
++
++ init_new_thread_signals();
++
++ init_task.thread.request.u.thread.proc = start_kernel_proc;
++ init_task.thread.request.u.thread.arg = NULL;
++ return(start_idle_thread(task_stack_page(&init_task),
++ &init_task.thread.mode.skas.switch_buf));
++}
++
++int external_pid_skas(struct task_struct *task)
++{
++#warning Need to look up userspace_pid by cpu
++ return(userspace_pid[0]);
++}
++
++int thread_pid_skas(struct task_struct *task)
++{
++#warning Need to look up userspace_pid by cpu
++ return(userspace_pid[0]);
++}
++
++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/process_kern.c b/arch/um/kernel/skas/process_kern.c
+deleted file mode 100644
+index 55caeec..0000000
+--- a/arch/um/kernel/skas/process_kern.c
++++ /dev/null
+@@ -1,227 +0,0 @@
+-/*
+- * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
+- * Licensed under the GPL
+- */
+-
+-#include "linux/sched.h"
+-#include "linux/slab.h"
+-#include "linux/ptrace.h"
+-#include "linux/proc_fs.h"
+-#include "linux/file.h"
+-#include "linux/errno.h"
+-#include "linux/init.h"
+-#include "asm/uaccess.h"
+-#include "asm/atomic.h"
+-#include "kern_util.h"
+-#include "skas.h"
+-#include "os.h"
+-#include "user_util.h"
+-#include "tlb.h"
+-#include "kern.h"
+-#include "mode.h"
+-#include "registers.h"
+-
+-void switch_to_skas(void *prev, void *next)
+-{
+- struct task_struct *from, *to;
+-
+- from = prev;
+- to = next;
+-
+- /* XXX need to check runqueues[cpu].idle */
+- if(current->pid == 0)
+- switch_timers(0);
+-
+- switch_threads(&from->thread.mode.skas.switch_buf,
+- to->thread.mode.skas.switch_buf);
+-
+- arch_switch_to_skas(current->thread.prev_sched, current);
+-
+- if(current->pid == 0)
+- switch_timers(1);
+-}
+-
+-extern void schedule_tail(struct task_struct *prev);
+-
+-void new_thread_handler(int sig)
+-{
+- int (*fn)(void *), n;
+- void *arg;
+-
+- fn = current->thread.request.u.thread.proc;
+- arg = current->thread.request.u.thread.arg;
+- os_usr1_signal(1);
+- thread_wait(¤t->thread.mode.skas.switch_buf,
+- current->thread.mode.skas.fork_buf);
+-
+- if(current->thread.prev_sched != NULL)
+- schedule_tail(current->thread.prev_sched);
+- current->thread.prev_sched = NULL;
+-
+- /* The return value is 1 if the kernel thread execs a process,
+- * 0 if it just exits
+- */
+- n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf);
+- if(n == 1){
+- /* Handle any immediate reschedules or signals */
+- interrupt_end();
+- userspace(¤t->thread.regs.regs);
+- }
+- else do_exit(0);
+-}
+-
+-void new_thread_proc(void *stack, void (*handler)(int sig))
+-{
+- init_new_thread_stack(stack, handler);
+- os_usr1_process(os_getpid());
+-}
+-
+-void release_thread_skas(struct task_struct *task)
+-{
+-}
+-
+-void fork_handler(int sig)
+-{
+- os_usr1_signal(1);
+- thread_wait(¤t->thread.mode.skas.switch_buf,
+- current->thread.mode.skas.fork_buf);
+-
+- force_flush_all();
+- if(current->thread.prev_sched == NULL)
+- panic("blech");
+-
+- schedule_tail(current->thread.prev_sched);
+-
+- /* XXX: if interrupt_end() calls schedule, this call to
+- * arch_switch_to_skas isn't needed. We could want to apply this to
+- * improve performance. -bb */
+- arch_switch_to_skas(current->thread.prev_sched, current);
+-
+- current->thread.prev_sched = NULL;
+-
+-/* Handle any immediate reschedules or signals */
+- interrupt_end();
+-
+- userspace(¤t->thread.regs.regs);
+-}
+-
+-int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
+- unsigned long stack_top, struct task_struct * p,
+- struct pt_regs *regs)
+-{
+- void (*handler)(int);
+-
+- if(current->thread.forking){
+- memcpy(&p->thread.regs.regs.skas, ®s->regs.skas,
+- sizeof(p->thread.regs.regs.skas));
+- REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
+- if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
+-
+- handler = fork_handler;
+-
+- arch_copy_thread(¤t->thread.arch, &p->thread.arch);
+- }
+- else {
+- init_thread_registers(&p->thread.regs.regs);
+- p->thread.request.u.thread = current->thread.request.u.thread;
+- handler = new_thread_handler;
+- }
+-
+- new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf,
+- &p->thread.mode.skas.fork_buf, handler);
+- return(0);
+-}
+-
+-int new_mm(unsigned long stack)
+-{
+- int fd;
+-
+- fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
+- if(fd < 0)
+- return(fd);
+-
+- if(skas_needs_stub)
+- map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
+-
+- return(fd);
+-}
+-
+-void init_idle_skas(void)
+-{
+- cpu_tasks[current_thread->cpu].pid = os_getpid();
+- default_idle();
+-}
+-
+-extern void start_kernel(void);
+-
+-static int start_kernel_proc(void *unused)
+-{
+- int pid;
+-
+- block_signals();
+- pid = os_getpid();
+-
+- cpu_tasks[0].pid = pid;
+- cpu_tasks[0].task = current;
+-#ifdef CONFIG_SMP
+- cpu_online_map = cpumask_of_cpu(0);
+-#endif
+- start_kernel();
+- return(0);
+-}
+-
+-extern int userspace_pid[];
+-
+-int start_uml_skas(void)
+-{
+- if(proc_mm)
+- userspace_pid[0] = start_userspace(0);
+-
+- init_new_thread_signals();
+-
+- init_task.thread.request.u.thread.proc = start_kernel_proc;
+- init_task.thread.request.u.thread.arg = NULL;
+- return(start_idle_thread(task_stack_page(&init_task),
+- &init_task.thread.mode.skas.switch_buf,
+- &init_task.thread.mode.skas.fork_buf));
+-}
+-
+-int external_pid_skas(struct task_struct *task)
+-{
+-#warning Need to look up userspace_pid by cpu
+- return(userspace_pid[0]);
+-}
+-
+-int thread_pid_skas(struct task_struct *task)
+-{
+-#warning Need to look up userspace_pid by cpu
+- return(userspace_pid[0]);
+-}
+-
+-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/tlb.c b/arch/um/kernel/skas/tlb.c
+index 6e84963..27eb29c 100644
+--- a/arch/um/kernel/skas/tlb.c
++++ b/arch/um/kernel/skas/tlb.c
+@@ -6,7 +6,6 @@
+
+ #include "linux/stddef.h"
+ #include "linux/sched.h"
+-#include "linux/config.h"
+ #include "linux/mm.h"
+ #include "asm/page.h"
+ #include "asm/pgtable.h"
+diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
+index 511116a..759b070 100644
+--- a/arch/um/kernel/smp.c
++++ b/arch/um/kernel/smp.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/percpu.h"
+ #include "asm/pgalloc.h"
+ #include "asm/tlb.h"
+diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
+index 48cf88d..f5ed862 100644
+--- a/arch/um/kernel/syscall.c
++++ b/arch/um/kernel/syscall.c
+@@ -110,7 +110,7 @@ long sys_uname(struct old_utsname __user
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+- err = copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ return err?-EFAULT:0;
+ }
+@@ -126,21 +126,21 @@ long sys_olduname(struct oldold_utsname
+
+ down_read(&uts_sem);
+
+- error = __copy_to_user(&name->sysname,&system_utsname.sysname,
++ error = __copy_to_user(&name->sysname, &utsname()->sysname,
+ __OLD_UTS_LEN);
+- error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
++ error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+ __OLD_UTS_LEN);
+- error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->release,&system_utsname.release,
++ error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->release, &utsname()->release,
+ __OLD_UTS_LEN);
+- error |= __put_user(0,name->release+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->version,&system_utsname.version,
++ error |= __put_user(0, name->release + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->version, &utsname()->version,
+ __OLD_UTS_LEN);
+- error |= __put_user(0,name->version+__OLD_UTS_LEN);
+- error |= __copy_to_user(&name->machine,&system_utsname.machine,
++ error |= __put_user(0, name->version + __OLD_UTS_LEN);
++ error |= __copy_to_user(&name->machine, &utsname()->machine,
+ __OLD_UTS_LEN);
+- error |= __put_user(0,name->machine+__OLD_UTS_LEN);
++ error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+
+ up_read(&uts_sem);
+
+@@ -164,3 +164,16 @@ int next_syscall_index(int limit)
+ spin_unlock(&syscall_lock);
+ return(ret);
+ }
++
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ mm_segment_t fs;
++ int ret;
++
++ fs = get_fs();
++ set_fs(KERNEL_DS);
++ ret = um_execve(filename, argv, envp);
++ set_fs(fs);
++
++ return ret;
++}
+diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
+index b331e97..239c980 100644
+--- a/arch/um/kernel/sysrq.c
++++ b/arch/um/kernel/sysrq.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/sched.h"
+ #include "linux/kernel.h"
+ #include "linux/module.h"
+diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
+index 552ca1c..2e354b3 100644
+--- a/arch/um/kernel/time.c
++++ b/arch/um/kernel/time.c
+@@ -35,9 +35,6 @@ unsigned long long sched_clock(void)
+ return (unsigned long long)jiffies_64 * (1000000000 / HZ);
+ }
+
+-/* Changed at early boot */
+-int timer_irq_inited = 0;
+-
+ static unsigned long long prev_nsecs;
+ #ifdef CONFIG_UML_REAL_TIME_CLOCK
+ static long long delta; /* Deviation per interval */
+@@ -89,16 +86,16 @@ static inline unsigned long long get_tim
+ return nsecs;
+ }
+
+-irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
++irqreturn_t um_timer(int irq, void *dev)
+ {
+ unsigned long long nsecs;
+ unsigned long flags;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+
+- do_timer(regs);
++ do_timer(1);
+
+- nsecs = get_time() + local_offset;
++ nsecs = get_time();
+ xtime.tv_sec = nsecs / NSEC_PER_SEC;
+ xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
+
+@@ -113,12 +110,13 @@ static void register_timer(void)
+
+ err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL);
+ if(err != 0)
+- printk(KERN_ERR "timer_init : request_irq failed - "
++ printk(KERN_ERR "register_timer : request_irq failed - "
+ "errno = %d\n", -err);
+
+- timer_irq_inited = 1;
+-
+- user_time_init();
++ err = set_interval(1);
++ if(err != 0)
++ printk(KERN_ERR "register_timer : set_interval failed - "
++ "errno = %d\n", -err);
+ }
+
+ extern void (*late_time_init)(void);
+diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
+index f5b0636..54a5ff2 100644
+--- a/arch/um/kernel/tlb.c
++++ b/arch/um/kernel/tlb.c
+@@ -1,4 +1,4 @@
+-/*
++/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike at karaya.com)
+ * Licensed under the GPL
+ */
+@@ -16,12 +16,12 @@
+ #include "os.h"
+
+ static 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 r, int w, int x, struct host_vm_op *ops, int *index,
+ int last_filled, union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
+ {
+- __u64 offset;
++ __u64 offset;
+ struct host_vm_op *last;
+ int fd, ret = 0;
+
+@@ -89,7 +89,7 @@ static int add_munmap(unsigned long addr
+ static 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, union mm_context *mmu, void **flush,
+- int (*do_ops)(union mm_context *, struct host_vm_op *,
++ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
+ {
+ struct host_vm_op *last;
+@@ -124,105 +124,105 @@ static int add_mprotect(unsigned long ad
+ #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,
++ unsigned long end_addr, int force,
+ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
+ {
+- 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[1];
+- void *flush = NULL;
+- int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
+- int ret = 0;
+-
+- if(mm == NULL) return;
+-
+- ops[0].type = NONE;
+- for(addr = start_addr; addr < end_addr && !ret;){
+- npgd = pgd_offset(mm, addr);
+- if(!pgd_present(*npgd)){
+- end = ADD_ROUND(addr, PGDIR_SIZE);
+- if(end > end_addr)
+- end = end_addr;
+- if(force || pgd_newpage(*npgd)){
+- ret = add_munmap(addr, end - addr, ops,
+- &op_index, last_op, mmu,
+- &flush, do_ops);
+- pgd_mkuptodate(*npgd);
+- }
+- addr = end;
+- continue;
+- }
+-
+- npud = pud_offset(npgd, addr);
+- if(!pud_present(*npud)){
+- end = ADD_ROUND(addr, PUD_SIZE);
+- if(end > end_addr)
+- end = end_addr;
+- if(force || pud_newpage(*npud)){
+- ret = add_munmap(addr, end - addr, ops,
+- &op_index, last_op, mmu,
+- &flush, do_ops);
+- pud_mkuptodate(*npud);
+- }
+- addr = end;
+- continue;
+- }
+-
+- npmd = pmd_offset(npud, addr);
+- if(!pmd_present(*npmd)){
+- end = ADD_ROUND(addr, PMD_SIZE);
+- if(end > end_addr)
+- end = end_addr;
+- if(force || pmd_newpage(*npmd)){
+- ret = add_munmap(addr, end - addr, ops,
+- &op_index, last_op, mmu,
+- &flush, do_ops);
+- pmd_mkuptodate(*npmd);
+- }
+- addr = end;
+- continue;
+- }
+-
+- npte = pte_offset_kernel(npmd, addr);
+- r = pte_read(*npte);
+- w = pte_write(*npte);
+- x = pte_exec(*npte);
++ 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[1];
++ void *flush = NULL;
++ int op_index = -1, last_op = ARRAY_SIZE(ops) - 1;
++ int ret = 0;
++
++ if(mm == NULL)
++ return;
++
++ ops[0].type = NONE;
++ for(addr = start_addr; addr < end_addr && !ret;){
++ npgd = pgd_offset(mm, addr);
++ if(!pgd_present(*npgd)){
++ end = ADD_ROUND(addr, PGDIR_SIZE);
++ if(end > end_addr)
++ end = end_addr;
++ if(force || pgd_newpage(*npgd)){
++ ret = add_munmap(addr, end - addr, ops,
++ &op_index, last_op, mmu,
++ &flush, do_ops);
++ pgd_mkuptodate(*npgd);
++ }
++ addr = end;
++ continue;
++ }
++
++ npud = pud_offset(npgd, addr);
++ if(!pud_present(*npud)){
++ end = ADD_ROUND(addr, PUD_SIZE);
++ if(end > end_addr)
++ end = end_addr;
++ if(force || pud_newpage(*npud)){
++ ret = add_munmap(addr, end - addr, ops,
++ &op_index, last_op, mmu,
++ &flush, do_ops);
++ pud_mkuptodate(*npud);
++ }
++ addr = end;
++ continue;
++ }
++
++ npmd = pmd_offset(npud, addr);
++ if(!pmd_present(*npmd)){
++ end = ADD_ROUND(addr, PMD_SIZE);
++ if(end > end_addr)
++ end = end_addr;
++ if(force || pmd_newpage(*npmd)){
++ ret = add_munmap(addr, end - addr, ops,
++ &op_index, last_op, mmu,
++ &flush, do_ops);
++ pmd_mkuptodate(*npmd);
++ }
++ addr = end;
++ continue;
++ }
++
++ npte = pte_offset_kernel(npmd, addr);
++ r = pte_read(*npte);
++ w = pte_write(*npte);
++ x = pte_exec(*npte);
+ if (!pte_young(*npte)) {
+ r = 0;
+ w = 0;
+ } else if (!pte_dirty(*npte)) {
+ w = 0;
+ }
+- if(force || pte_newpage(*npte)){
+- if(pte_present(*npte))
+- ret = add_mmap(addr,
+- pte_val(*npte) & PAGE_MASK,
+- PAGE_SIZE, r, w, x, ops,
+- &op_index, last_op, mmu,
+- &flush, do_ops);
++ if(force || pte_newpage(*npte)){
++ if(pte_present(*npte))
++ ret = add_mmap(addr,
++ pte_val(*npte) & PAGE_MASK,
++ PAGE_SIZE, r, w, x, ops,
++ &op_index, last_op, mmu,
++ &flush, do_ops);
+ else ret = add_munmap(addr, PAGE_SIZE, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
+- }
+- else if(pte_newprot(*npte))
++ }
++ else if(pte_newprot(*npte))
+ ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
+
+- *npte = pte_mkuptodate(*npte);
+- addr += PAGE_SIZE;
+- }
+-
++ *npte = pte_mkuptodate(*npte);
++ addr += PAGE_SIZE;
++ }
+ if(!ret)
+ ret = (*do_ops)(mmu, ops, op_index, 1, &flush);
+
+- /* This is not an else because ret is modified above */
++/* This is not an else because ret is modified above */
+ if(ret) {
+ printk("fix_range_common: failed, killing current process\n");
+ force_sig(SIGKILL, current);
+@@ -231,160 +231,160 @@ void fix_range_common(struct mm_struct *
+
+ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
+ {
+- struct mm_struct *mm;
+- pgd_t *pgd;
+- pud_t *pud;
+- pmd_t *pmd;
+- pte_t *pte;
+- unsigned long addr, last;
+- int updated = 0, err;
+-
+- mm = &init_mm;
+- for(addr = start; addr < end;){
+- pgd = pgd_offset(mm, addr);
+- if(!pgd_present(*pgd)){
+- last = ADD_ROUND(addr, PGDIR_SIZE);
+- if(last > end)
+- last = end;
+- if(pgd_newpage(*pgd)){
+- updated = 1;
+- err = os_unmap_memory((void *) addr,
+- last - addr);
+- if(err < 0)
+- panic("munmap failed, errno = %d\n",
+- -err);
+- }
+- addr = last;
+- continue;
+- }
+-
+- pud = pud_offset(pgd, addr);
+- if(!pud_present(*pud)){
+- last = ADD_ROUND(addr, PUD_SIZE);
+- if(last > end)
+- last = end;
+- if(pud_newpage(*pud)){
+- updated = 1;
+- err = os_unmap_memory((void *) addr,
+- last - addr);
+- if(err < 0)
+- panic("munmap failed, errno = %d\n",
+- -err);
+- }
+- addr = last;
+- continue;
+- }
+-
+- pmd = pmd_offset(pud, addr);
+- if(!pmd_present(*pmd)){
+- last = ADD_ROUND(addr, PMD_SIZE);
+- if(last > end)
+- last = end;
+- if(pmd_newpage(*pmd)){
+- updated = 1;
+- err = os_unmap_memory((void *) addr,
+- last - addr);
+- if(err < 0)
+- panic("munmap failed, errno = %d\n",
+- -err);
+- }
+- addr = last;
+- continue;
+- }
+-
+- pte = pte_offset_kernel(pmd, addr);
+- if(!pte_present(*pte) || pte_newpage(*pte)){
+- updated = 1;
+- err = os_unmap_memory((void *) addr,
+- PAGE_SIZE);
+- if(err < 0)
+- panic("munmap failed, errno = %d\n",
+- -err);
+- if(pte_present(*pte))
+- map_memory(addr,
+- pte_val(*pte) & PAGE_MASK,
+- PAGE_SIZE, 1, 1, 1);
+- }
+- else if(pte_newprot(*pte)){
+- updated = 1;
+- os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1);
+- }
+- addr += PAGE_SIZE;
+- }
+- return(updated);
++ struct mm_struct *mm;
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ unsigned long addr, last;
++ int updated = 0, err;
++
++ mm = &init_mm;
++ for(addr = start; addr < end;){
++ pgd = pgd_offset(mm, addr);
++ if(!pgd_present(*pgd)){
++ last = ADD_ROUND(addr, PGDIR_SIZE);
++ if(last > end)
++ last = end;
++ if(pgd_newpage(*pgd)){
++ updated = 1;
++ err = os_unmap_memory((void *) addr,
++ last - addr);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ }
++ addr = last;
++ continue;
++ }
++
++ pud = pud_offset(pgd, addr);
++ if(!pud_present(*pud)){
++ last = ADD_ROUND(addr, PUD_SIZE);
++ if(last > end)
++ last = end;
++ if(pud_newpage(*pud)){
++ updated = 1;
++ err = os_unmap_memory((void *) addr,
++ last - addr);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ }
++ addr = last;
++ continue;
++ }
++
++ pmd = pmd_offset(pud, addr);
++ if(!pmd_present(*pmd)){
++ last = ADD_ROUND(addr, PMD_SIZE);
++ if(last > end)
++ last = end;
++ if(pmd_newpage(*pmd)){
++ updated = 1;
++ err = os_unmap_memory((void *) addr,
++ last - addr);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ }
++ addr = last;
++ continue;
++ }
++
++ pte = pte_offset_kernel(pmd, addr);
++ if(!pte_present(*pte) || pte_newpage(*pte)){
++ updated = 1;
++ err = os_unmap_memory((void *) addr,
++ PAGE_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ if(pte_present(*pte))
++ map_memory(addr,
++ pte_val(*pte) & PAGE_MASK,
++ PAGE_SIZE, 1, 1, 1);
++ }
++ else if(pte_newprot(*pte)){
++ updated = 1;
++ os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1);
++ }
++ addr += PAGE_SIZE;
++ }
++ return(updated);
+ }
+
+ pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
+ {
+- return(pgd_offset(mm, address));
++ return(pgd_offset(mm, address));
+ }
+
+ pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
+ {
+- return(pud_offset(pgd, address));
++ return(pud_offset(pgd, address));
+ }
+
+ pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
+ {
+- return(pmd_offset(pud, address));
++ return(pmd_offset(pud, address));
+ }
+
+ pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
+ {
+- return(pte_offset_kernel(pmd, address));
++ return(pte_offset_kernel(pmd, address));
+ }
+
+ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
+ {
+- pgd_t *pgd = pgd_offset(task->mm, addr);
+- pud_t *pud = pud_offset(pgd, addr);
+- pmd_t *pmd = pmd_offset(pud, addr);
++ pgd_t *pgd = pgd_offset(task->mm, addr);
++ pud_t *pud = pud_offset(pgd, addr);
++ pmd_t *pmd = pmd_offset(pud, addr);
+
+- return(pte_offset_map(pmd, addr));
++ return(pte_offset_map(pmd, addr));
+ }
+
+ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+ {
+- address &= PAGE_MASK;
+- flush_tlb_range(vma, address, address + PAGE_SIZE);
++ address &= PAGE_MASK;
++ flush_tlb_range(vma, address, address + PAGE_SIZE);
+ }
+
+ void flush_tlb_all(void)
+ {
+- flush_tlb_mm(current->mm);
++ 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);
++ 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));
++ 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);
++ 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);
++ 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);
++ 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());
++ CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
+ }
+
+diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
+index ac70fa5..b5f124a 100644
+--- a/arch/um/kernel/trap.c
++++ b/arch/um/kernel/trap.c
+@@ -8,7 +8,6 @@
+ #include "linux/sched.h"
+ #include "linux/mm.h"
+ #include "linux/spinlock.h"
+-#include "linux/config.h"
+ #include "linux/init.h"
+ #include "linux/ptrace.h"
+ #include "asm/semaphore.h"
+@@ -120,7 +119,7 @@ out_nosemaphore:
+ * us unable to handle the page fault gracefully.
+ */
+ out_of_memory:
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ up_read(&mm->mmap_sem);
+ yield();
+ down_read(&mm->mmap_sem);
+@@ -140,14 +139,6 @@ void segv_handler(int sig, union uml_pt_
+ segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
+ }
+
+-struct kern_handlers handlinfo_kern = {
+- .relay_signal = relay_signal,
+- .winch = winch,
+- .bus_handler = relay_signal,
+- .page_fault = segv_handler,
+- .sigio_handler = sigio_handler,
+- .timer_handler = timer_handler
+-};
+ /*
+ * We give a *copy* of the faultinfo in the regs to segv.
+ * This must be done, since nesting SEGVs could overwrite
+@@ -227,9 +218,16 @@ void bad_segv(struct faultinfo fi, unsig
+
+ void relay_signal(int sig, union uml_pt_regs *regs)
+ {
+- if(arch_handle_signal(sig, regs)) return;
+- if(!UPT_IS_USER(regs))
++ if(arch_handle_signal(sig, regs))
++ return;
++
++ if(!UPT_IS_USER(regs)){
++ if(sig == SIGBUS)
++ printk("Bus error - the /dev/shm or /tmp mount likely "
++ "just ran out of space\n");
+ panic("Kernel mode signal %d", sig);
++ }
++
+ current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
+ force_sig(sig, current);
+ }
+@@ -246,6 +244,15 @@ void winch(int sig, union uml_pt_regs *r
+ do_IRQ(WINCH_IRQ, regs);
+ }
+
++const struct kern_handlers handlinfo_kern = {
++ .relay_signal = relay_signal,
++ .winch = winch,
++ .bus_handler = bus_handler,
++ .page_fault = segv_handler,
++ .sigio_handler = sigio_handler,
++ .timer_handler = timer_handler
++};
++
+ void trap_init(void)
+ {
+ }
+diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
+index 2650638..68e1bf6 100644
+--- a/arch/um/kernel/tt/gdb_kern.c
++++ b/arch/um/kernel/tt/gdb_kern.c
+@@ -4,7 +4,6 @@
+ */
+
+ #include "linux/init.h"
+-#include "linux/config.h"
+ #include "mconsole_kern.h"
+
+ #ifdef CONFIG_MCONSOLE
+diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
+index 84a23b1..4d1929d 100644
+--- a/arch/um/kernel/tt/mem.c
++++ b/arch/um/kernel/tt/mem.c
+@@ -4,7 +4,6 @@
+ */
+
+ #include "linux/stddef.h"
+-#include "linux/config.h"
+ #include "linux/mm.h"
+ #include "asm/uaccess.h"
+ #include "mem_user.h"
+diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
+index 9882342..b919535 100644
+--- a/arch/um/kernel/tt/tracer.c
++++ b/arch/um/kernel/tt/tracer.c
+@@ -176,7 +176,6 @@ struct {
+ int signal_index[32];
+ int nsignals = 0;
+ int debug_trace = 0;
+-extern int io_nsignals, io_count, intr_count;
+
+ extern void signal_usr1(int sig);
+
+diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
+index 6c92bbc..ed1abcf 100644
+--- a/arch/um/kernel/tt/uaccess_user.c
++++ b/arch/um/kernel/tt/uaccess_user.c
+@@ -4,13 +4,13 @@
+ * Licensed under the GPL
+ */
+
+-#include <setjmp.h>
+ #include <string.h>
+ #include "user_util.h"
+ #include "uml_uaccess.h"
+ #include "task.h"
+ #include "kern_util.h"
+ #include "os.h"
++#include "longjmp.h"
+
+ int __do_copy_from_user(void *to, const void *from, int n,
+ void **fault_addr, void **fault_catcher)
+@@ -80,10 +80,10 @@ int __do_strnlen_user(const char *str, u
+ struct tt_regs save = TASK_REGS(get_current())->tt;
+ int ret;
+ unsigned long *faddrp = (unsigned long *)fault_addr;
+- sigjmp_buf jbuf;
++ jmp_buf jbuf;
+
+ *fault_catcher = &jbuf;
+- if(sigsetjmp(jbuf, 1) == 0)
++ if(UML_SETJMP(&jbuf) == 0)
+ ret = strlen(str) + 1;
+ else ret = *faddrp - (unsigned long) str;
+
+diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
+index 7896cf9..66f43c9 100644
+--- a/arch/um/kernel/um_arch.c
++++ b/arch/um/kernel/um_arch.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/kernel.h"
+ #include "linux/sched.h"
+ #include "linux/notifier.h"
+@@ -106,7 +105,7 @@ static void c_stop(struct seq_file *m, v
+ {
+ }
+
+-struct seq_operations cpuinfo_op = {
++const struct seq_operations cpuinfo_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+@@ -167,7 +166,7 @@ static char *usage_string =
+
+ static int __init uml_version_setup(char *line, int *add)
+ {
+- printf("%s\n", system_utsname.release);
++ printf("%s\n", init_utsname()->release);
+ exit(0);
+
+ return 0;
+@@ -278,7 +277,7 @@ static int __init Usage(char *line, int
+ {
+ const char **p;
+
+- printf(usage_string, system_utsname.release);
++ printf(usage_string, init_utsname()->release);
+ p = &__uml_help_start;
+ while (p < &__uml_help_end) {
+ printf("%s", *p);
+@@ -403,7 +402,7 @@ int linux_main(int argc, char **argv)
+ /* Reserve up to 4M after the current brk */
+ uml_reserved = ROUND_4M(brk_start) + (1 << 22);
+
+- setup_machinename(system_utsname.machine);
++ setup_machinename(init_utsname()->machine);
+
+ #ifdef CONFIG_CMDLINE_ON_HOST
+ argv1_begin = argv[1];
+diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
+index 8eca47a..f630127 100644
+--- a/arch/um/kernel/uml.lds.S
++++ b/arch/um/kernel/uml.lds.S
+@@ -25,6 +25,7 @@ SECTIONS
+ . = ALIGN(4096); /* Init code and data */
+ #endif
+
++ _text = .;
+ _stext = .;
+ __init_begin = .;
+ .init.text : {
+diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
+index f4bfc4c..b418392 100644
+--- a/arch/um/os-Linux/Makefile
++++ b/arch/um/os-Linux/Makefile
+@@ -4,15 +4,19 @@
+ #
+
+ obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \
+- signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \
++ signal.o start_up.o time.o trap.o tty.o uaccess.o umid.o tls.o \
+ user_syms.o util.o drivers/ sys-$(SUBARCH)/
+
+ obj-$(CONFIG_MODE_SKAS) += skas/
++
++obj-$(CONFIG_MODE_TT) += tt.o
++user-objs-$(CONFIG_MODE_TT) += tt.o
++
+ obj-$(CONFIG_TTY_LOG) += tty_log.o
+ user-objs-$(CONFIG_TTY_LOG) += tty_log.o
+
+ USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \
+- process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \
++ process.o sigio.o signal.o start_up.o time.o trap.o tty.o tls.o \
+ uaccess.o umid.o util.o
+
+ CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
+diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h
+index b84f6c4..57ecdaf 100644
+--- a/arch/um/os-Linux/drivers/etap.h
++++ b/arch/um/os-Linux/drivers/etap.h
+@@ -13,7 +13,7 @@ struct ethertap_data {
+ void *dev;
+ };
+
+-extern struct net_user_info ethertap_user_info;
++extern const struct net_user_info ethertap_user_info;
+
+ /*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
+index 768606b..16385e2 100644
+--- a/arch/um/os-Linux/drivers/ethertap_kern.c
++++ b/arch/um/os-Linux/drivers/ethertap_kern.c
+@@ -65,7 +65,7 @@ static int etap_write(int fd, struct sk_
+ return(net_send(fd, (*skb)->data, (*skb)->len));
+ }
+
+-struct net_kern_info ethertap_kern_info = {
++const struct net_kern_info ethertap_kern_info = {
+ .init = etap_init,
+ .protocol = eth_protocol,
+ .read = etap_read,
+diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
+index 8f49507..863981b 100644
+--- a/arch/um/os-Linux/drivers/ethertap_user.c
++++ b/arch/um/os-Linux/drivers/ethertap_user.c
+@@ -20,6 +20,7 @@
+ #include "net_user.h"
+ #include "etap.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ #define MAX_PACKET ETH_MAX_PACKET
+
+@@ -216,7 +217,7 @@ static void etap_del_addr(unsigned char
+ etap_close_addr(addr, netmask, &pri->control_fd);
+ }
+
+-struct net_user_info ethertap_user_info = {
++const struct net_user_info ethertap_user_info = {
+ .init = etap_user_init,
+ .open = etap_open,
+ .close = etap_close,
+diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
+index 25d4a28..d3e8d3a 100644
+--- a/arch/um/os-Linux/drivers/tuntap.h
++++ b/arch/um/os-Linux/drivers/tuntap.h
+@@ -16,7 +16,7 @@ struct tuntap_data {
+ void *dev;
+ };
+
+-extern struct net_user_info tuntap_user_info;
++extern const struct net_user_info tuntap_user_info;
+
+ #endif
+
+diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
+index 190009a..0edbac6 100644
+--- a/arch/um/os-Linux/drivers/tuntap_kern.c
++++ b/arch/um/os-Linux/drivers/tuntap_kern.c
+@@ -53,7 +53,7 @@ static int tuntap_write(int fd, struct s
+ return(net_write(fd, (*skb)->data, (*skb)->len));
+ }
+
+-struct net_kern_info tuntap_kern_info = {
++const struct net_kern_info tuntap_kern_info = {
+ .init = tuntap_init,
+ .protocol = eth_protocol,
+ .read = tuntap_read,
+diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
+index 87c3aa0..e846b23 100644
+--- a/arch/um/os-Linux/drivers/tuntap_user.c
++++ b/arch/um/os-Linux/drivers/tuntap_user.c
+@@ -205,7 +205,7 @@ static int tuntap_set_mtu(int mtu, void
+ return(mtu);
+ }
+
+-struct net_user_info tuntap_user_info = {
++const struct net_user_info tuntap_user_info = {
+ .init = tuntap_user_init,
+ .open = tuntap_open,
+ .close = tuntap_close,
+diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
+index 6987d1d..d13299c 100644
+--- a/arch/um/os-Linux/helper.c
++++ b/arch/um/os-Linux/helper.c
+@@ -35,22 +35,23 @@ static int helper_child(void *arg)
+ char **argv = data->argv;
+ int errval;
+
+- if(helper_pause){
++ if (helper_pause){
+ signal(SIGHUP, helper_hup);
+ pause();
+ }
+- if(data->pre_exec != NULL)
++ if (data->pre_exec != NULL)
+ (*data->pre_exec)(data->pre_data);
+ execvp(argv[0], argv);
+- errval = errno;
++ errval = -errno;
+ printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno);
+ os_write_file(data->fd, &errval, sizeof(errval));
+ kill(os_getpid(), SIGKILL);
+- return(0);
++ return 0;
+ }
+
+ /* Returns either the pid of the child process we run or -E* on failure.
+- * XXX The alloc_stack here breaks if this is called in the tracing thread */
++ * XXX The alloc_stack here breaks if this is called in the tracing thread, so
++ * we need to receive a preallocated stack (a local buffer is ok). */
+ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
+ unsigned long *stack_out)
+ {
+@@ -58,20 +59,21 @@ int run_helper(void (*pre_exec)(void *),
+ unsigned long stack, sp;
+ int pid, fds[2], ret, n;
+
+- if((stack_out != NULL) && (*stack_out != 0))
++ if ((stack_out != NULL) && (*stack_out != 0))
+ stack = *stack_out;
+- else stack = alloc_stack(0, __cant_sleep());
+- if(stack == 0)
+- return(-ENOMEM);
++ else
++ stack = alloc_stack(0, __cant_sleep());
++ if (stack == 0)
++ return -ENOMEM;
+
+ ret = os_pipe(fds, 1, 0);
+- if(ret < 0){
++ if (ret < 0) {
+ printk("run_helper : pipe failed, ret = %d\n", -ret);
+ goto out_free;
+ }
+
+ ret = os_set_exec_close(fds[1], 1);
+- if(ret < 0){
++ if (ret < 0) {
+ printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
+ -ret);
+ goto out_close;
+@@ -83,7 +85,7 @@ int run_helper(void (*pre_exec)(void *),
+ data.argv = argv;
+ data.fd = fds[1];
+ pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
+- if(pid < 0){
++ if (pid < 0) {
+ ret = -errno;
+ printk("run_helper : clone failed, errno = %d\n", errno);
+ goto out_close;
+@@ -95,16 +97,16 @@ int run_helper(void (*pre_exec)(void *),
+ /* Read the errno value from the child, if the exec failed, or get 0 if
+ * the exec succeeded because the pipe fd was set as close-on-exec. */
+ n = os_read_file(fds[0], &ret, sizeof(ret));
+- if (n < 0) {
+- printk("run_helper : read on pipe failed, ret = %d\n", -n);
+- ret = n;
+- kill(pid, SIGKILL);
+- CATCH_EINTR(waitpid(pid, NULL, 0));
+- } else if(n != 0){
+- CATCH_EINTR(n = waitpid(pid, NULL, 0));
+- ret = -errno;
+- } else {
++ if (n == 0) {
+ ret = pid;
++ } else {
++ if (n < 0) {
++ printk("run_helper : read on pipe failed, ret = %d\n",
++ -n);
++ ret = n;
++ kill(pid, SIGKILL);
++ }
++ CATCH_EINTR(waitpid(pid, NULL, 0));
+ }
+
+ out_close:
+@@ -112,10 +114,9 @@ out_close:
+ close(fds[1]);
+ close(fds[0]);
+ out_free:
+- if(stack_out == NULL)
++ if ((stack_out == NULL) || (*stack_out == 0))
+ free_stack(stack, 0);
+- else *stack_out = stack;
+- return(ret);
++ return ret;
+ }
+
+ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
+@@ -125,31 +126,32 @@ int run_helper_thread(int (*proc)(void *
+ int pid, status, err;
+
+ stack = alloc_stack(stack_order, __cant_sleep());
+- if(stack == 0) return(-ENOMEM);
++ if (stack == 0)
++ return -ENOMEM;
+
+ sp = stack + (page_size() << stack_order) - sizeof(void *);
+ pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
+- if(pid < 0){
++ if (pid < 0) {
+ err = -errno;
+ printk("run_helper_thread : clone failed, errno = %d\n",
+ errno);
+ return err;
+ }
+- if(stack_out == NULL){
++ if (stack_out == NULL) {
+ CATCH_EINTR(pid = waitpid(pid, &status, 0));
+- if(pid < 0){
++ if (pid < 0) {
+ err = -errno;
+ printk("run_helper_thread - wait failed, errno = %d\n",
+ errno);
+ pid = err;
+ }
+- if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
++ if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+ printk("run_helper_thread - thread returned status "
+ "0x%x\n", status);
+ free_stack(stack, stack_order);
+- }
+- else *stack_out = stack;
+- return(pid);
++ } else
++ *stack_out = stack;
++ return pid;
+ }
+
+ int helper_wait(int pid)
+@@ -157,9 +159,9 @@ int helper_wait(int pid)
+ int ret;
+
+ CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG));
+- if(ret < 0){
++ if (ret < 0) {
+ ret = -errno;
+ printk("helper_wait : waitpid failed, errno = %d\n", errno);
+ }
+- return(ret);
++ return ret;
+ }
+diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
+index 7555bf9..d46b818 100644
+--- a/arch/um/os-Linux/irq.c
++++ b/arch/um/os-Linux/irq.c
+@@ -18,6 +18,7 @@
+ #include "sigio.h"
+ #include "irq_user.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ static struct pollfd *pollfds = NULL;
+ static int pollfds_num = 0;
+@@ -132,7 +133,7 @@ void os_set_pollfd(int i, int fd)
+
+ void os_set_ioignore(void)
+ {
+- set_handler(SIGIO, SIG_IGN, 0, -1);
++ signal(SIGIO, SIG_IGN);
+ }
+
+ void init_irq_signals(int on_sigstack)
+diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
+index 90912aa..685feaa 100644
+--- a/arch/um/os-Linux/main.c
++++ b/arch/um/os-Linux/main.c
+@@ -23,6 +23,7 @@
+ #include "choose-mode.h"
+ #include "uml-config.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ /* Set in set_stklim, which is called from main and __wrap_malloc.
+ * __wrap_malloc only calls it if main hasn't started.
+@@ -67,13 +68,32 @@ static __init void do_uml_initcalls(void
+
+ static void last_ditch_exit(int sig)
+ {
+- signal(SIGINT, SIG_DFL);
+- signal(SIGTERM, SIG_DFL);
+- signal(SIGHUP, SIG_DFL);
+ uml_cleanup();
+ exit(1);
+ }
+
++static void install_fatal_handler(int sig)
++{
++ struct sigaction action;
++
++ /* All signals are enabled in this handler ... */
++ sigemptyset(&action.sa_mask);
++
++ /* ... including the signal being handled, plus we want the
++ * handler reset to the default behavior, so that if an exit
++ * handler is hanging for some reason, the UML will just die
++ * after this signal is sent a second time.
++ */
++ action.sa_flags = SA_RESETHAND | SA_NODEFER;
++ action.sa_restorer = NULL;
++ action.sa_handler = last_ditch_exit;
++ if(sigaction(sig, &action, NULL) < 0){
++ printf("failed to install handler for signal %d - errno = %d\n",
++ errno);
++ exit(1);
++ }
++}
++
+ #define UML_LIB_PATH ":/usr/lib/uml"
+
+ static void setup_env_path(void)
+@@ -158,9 +178,12 @@ int main(int argc, char **argv, char **e
+ }
+ new_argv[argc] = NULL;
+
+- set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+- set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+- set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++ /* Allow these signals to bring down a UML if all other
++ * methods of control fail.
++ */
++ install_fatal_handler(SIGINT);
++ install_fatal_handler(SIGTERM);
++ install_fatal_handler(SIGHUP);
+
+ scan_elf_aux( envp);
+
+diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
+index 560c806..4203681 100644
+--- a/arch/um/os-Linux/mem.c
++++ b/arch/um/os-Linux/mem.c
+@@ -114,14 +114,14 @@ static void which_tmpdir(void)
+ }
+
+ while(1){
+- found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' ');
++ found = next(fd, buf, ARRAY_SIZE(buf), ' ');
+ if(found != 1)
+ break;
+
+ if(!strncmp(buf, "/dev/shm", strlen("/dev/shm")))
+ goto found;
+
+- found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), '\n');
++ found = next(fd, buf, ARRAY_SIZE(buf), '\n');
+ if(found != 1)
+ break;
+ }
+@@ -132,20 +132,24 @@ err:
+ else if(found < 0)
+ printf("read returned errno %d\n", -found);
+
++out:
++ close(fd);
++
+ return;
+
+ found:
+- found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' ');
++ found = next(fd, buf, ARRAY_SIZE(buf), ' ');
+ if(found != 1)
+ goto err;
+
+ if(strncmp(buf, "tmpfs", strlen("tmpfs"))){
+ printf("not tmpfs\n");
+- return;
++ goto out;
+ }
+
+ printf("OK\n");
+ default_tmpdir = "/dev/shm";
++ goto out;
+ }
+
+ /*
+diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
+index b98d3ca..c692a19 100644
+--- a/arch/um/os-Linux/process.c
++++ b/arch/um/os-Linux/process.c
+@@ -7,11 +7,10 @@
+ #include <stdio.h>
+ #include <errno.h>
+ #include <signal.h>
+-#include <setjmp.h>
+-#include <linux/unistd.h>
+ #include <sys/mman.h>
+ #include <sys/wait.h>
+ #include <sys/mman.h>
++#include <sys/syscall.h>
+ #include "ptrace_user.h"
+ #include "os.h"
+ #include "user.h"
+@@ -141,11 +140,9 @@ void os_usr1_process(int pid)
+ * syscalls, and also breaks with clone(), which does not unshare the TLS.
+ */
+
+-inline _syscall0(pid_t, getpid)
+-
+ int os_getpid(void)
+ {
+- return(getpid());
++ return(syscall(__NR_getpid));
+ }
+
+ int os_getpgrp(void)
+@@ -247,7 +244,17 @@ void init_new_thread_stack(void *sig_sta
+ set_sigstack(sig_stack, pages * page_size());
+ flags = SA_ONSTACK;
+ }
+- if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
++ if(usr1_handler){
++ struct sigaction sa;
++
++ sa.sa_handler = usr1_handler;
++ sigemptyset(&sa.sa_mask);
++ sa.sa_flags = flags;
++ sa.sa_restorer = NULL;
++ if(sigaction(SIGUSR1, &sa, NULL) < 0)
++ panic("init_new_thread_stack - sigaction failed - "
++ "errno = %d\n", errno);
++ }
+ }
+
+ void init_new_thread_signals(void)
+diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
+index 0ecac56..925a652 100644
+--- a/arch/um/os-Linux/sigio.c
++++ b/arch/um/os-Linux/sigio.c
+@@ -19,6 +19,7 @@
+ #include "user_util.h"
+ #include "sigio.h"
+ #include "os.h"
++#include "um_malloc.h"
+
+ /* Protected by sigio_lock(), also used by sigio_cleanup, which is an
+ * exitcall.
+@@ -43,17 +44,9 @@ struct pollfds {
+ /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread
+ * synchronizes with it.
+ */
+-static struct pollfds current_poll = {
+- .poll = NULL,
+- .size = 0,
+- .used = 0
+-};
+-
+-static struct pollfds next_poll = {
+- .poll = NULL,
+- .size = 0,
+- .used = 0
+-};
++static struct pollfds current_poll;
++static struct pollfds next_poll;
++static struct pollfds all_sigio_fds;
+
+ static int write_sigio_thread(void *unused)
+ {
+@@ -78,7 +71,8 @@ static int write_sigio_thread(void *unus
+ n = os_read_file(sigio_private[1], &c, sizeof(c));
+ if(n != sizeof(c))
+ printk("write_sigio_thread : "
+- "read failed, err = %d\n", -n);
++ "read on socket failed, "
++ "err = %d\n", -n);
+ tmp = current_poll;
+ current_poll = next_poll;
+ next_poll = tmp;
+@@ -93,35 +87,36 @@ static int write_sigio_thread(void *unus
+
+ n = os_write_file(respond_fd, &c, sizeof(c));
+ if(n != sizeof(c))
+- printk("write_sigio_thread : write failed, "
+- "err = %d\n", -n);
++ printk("write_sigio_thread : write on socket "
++ "failed, err = %d\n", -n);
+ }
+ }
+
+ return 0;
+ }
+
+-static int need_poll(int n)
++static int need_poll(struct pollfds *polls, int n)
+ {
+- if(n <= next_poll.size){
+- next_poll.used = n;
+- return(0);
++ if(n <= polls->size){
++ polls->used = n;
++ return 0;
+ }
+- kfree(next_poll.poll);
+- next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
+- if(next_poll.poll == NULL){
++ kfree(polls->poll);
++ polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
++ if(polls->poll == NULL){
+ printk("need_poll : failed to allocate new pollfds\n");
+- next_poll.size = 0;
+- next_poll.used = 0;
+- return(-1);
++ polls->size = 0;
++ polls->used = 0;
++ return -ENOMEM;
+ }
+- next_poll.size = n;
+- next_poll.used = n;
+- return(0);
++ polls->size = n;
++ polls->used = n;
++ return 0;
+ }
+
+ /* Must be called with sigio_lock held, because it's needed by the marked
+- * critical section. */
++ * critical section.
++ */
+ static void update_thread(void)
+ {
+ unsigned long flags;
+@@ -156,34 +151,39 @@ static void update_thread(void)
+ set_signals(flags);
+ }
+
+-static int add_sigio_fd(int fd, int read)
++int add_sigio_fd(int fd)
+ {
+- int err = 0, i, n, events;
++ struct pollfd *p;
++ int err = 0, i, n;
+
+ sigio_lock();
++ for(i = 0; i < all_sigio_fds.used; i++){
++ if(all_sigio_fds.poll[i].fd == fd)
++ break;
++ }
++ if(i == all_sigio_fds.used)
++ goto out;
++
++ p = &all_sigio_fds.poll[i];
++
+ for(i = 0; i < current_poll.used; i++){
+ if(current_poll.poll[i].fd == fd)
+ goto out;
+ }
+
+ n = current_poll.used + 1;
+- err = need_poll(n);
++ err = need_poll(&next_poll, n);
+ if(err)
+ goto out;
+
+ for(i = 0; i < current_poll.used; i++)
+ next_poll.poll[i] = current_poll.poll[i];
+
+- if(read) events = POLLIN;
+- else events = POLLOUT;
+-
+- next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd,
+- .events = events,
+- .revents = 0 });
++ next_poll.poll[n - 1] = *p;
+ update_thread();
+ out:
+ sigio_unlock();
+- return(err);
++ return err;
+ }
+
+ int ignore_sigio_fd(int fd)
+@@ -205,18 +205,14 @@ int ignore_sigio_fd(int fd)
+ if(i == current_poll.used)
+ goto out;
+
+- err = need_poll(current_poll.used - 1);
++ err = need_poll(&next_poll, current_poll.used - 1);
+ if(err)
+ goto out;
+
+ for(i = 0; i < current_poll.used; i++){
+ p = ¤t_poll.poll[i];
+- if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
+- }
+- if(n == i){
+- printk("ignore_sigio_fd : fd %d not found\n", fd);
+- err = -1;
+- goto out;
++ if(p->fd != fd)
++ next_poll.poll[n++] = *p;
+ }
+
+ update_thread();
+@@ -234,7 +230,7 @@ static struct pollfd *setup_initial_poll
+ printk("setup_initial_poll : failed to allocate poll\n");
+ return NULL;
+ }
+- *p = ((struct pollfd) { .fd = fd,
++ *p = ((struct pollfd) { .fd = fd,
+ .events = POLLIN,
+ .revents = 0 });
+ return p;
+@@ -323,6 +319,8 @@ out_close1:
+
+ void maybe_sigio_broken(int fd, int read)
+ {
++ int err;
++
+ if(!isatty(fd))
+ return;
+
+@@ -330,7 +328,19 @@ void maybe_sigio_broken(int fd, int read
+ return;
+
+ write_sigio_workaround();
+- add_sigio_fd(fd, read);
++
++ sigio_lock();
++ err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
++ if(err){
++ printk("maybe_sigio_broken - failed to add pollfd\n");
++ goto out;
++ }
++ all_sigio_fds.poll[all_sigio_fds.used++] =
++ ((struct pollfd) { .fd = fd,
++ .events = read ? POLLIN : POLLOUT,
++ .revents = 0 });
++out:
++ sigio_unlock();
+ }
+
+ static void sigio_cleanup(void)
+diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
+index 60e4fae..b897e85 100644
+--- a/arch/um/os-Linux/signal.c
++++ b/arch/um/os-Linux/signal.c
+@@ -15,7 +15,7 @@
+ #include "user.h"
+ #include "signal_kern.h"
+ #include "sysdep/sigcontext.h"
+-#include "sysdep/signal.h"
++#include "sysdep/barrier.h"
+ #include "sigcontext.h"
+ #include "mode.h"
+ #include "os.h"
+@@ -35,21 +35,17 @@
+ #define SIGALRM_BIT 2
+ #define SIGALRM_MASK (1 << SIGALRM_BIT)
+
+-static int signals_enabled = 1;
+-static int pending = 0;
++/* These are used by both the signal handlers and
++ * block/unblock_signals. I don't want modifications cached in a
++ * register - they must go straight to memory.
++ */
++static volatile int signals_enabled = 1;
++static volatile int pending = 0;
+
+-void sig_handler(ARCH_SIGHDLR_PARAM)
++void sig_handler(int sig, struct sigcontext *sc)
+ {
+- struct sigcontext *sc;
+ int enabled;
+
+- /* Must be the first thing that this handler does - x86_64 stores
+- * the sigcontext in %rdx, and we need to save it before it has a
+- * chance to get trashed.
+- */
+-
+- ARCH_GET_SIGCONTEXT(sc, sig);
+-
+ enabled = signals_enabled;
+ if(!enabled && (sig == SIGIO)){
+ pending |= SIGIO_MASK;
+@@ -64,15 +60,8 @@ void sig_handler(ARCH_SIGHDLR_PARAM)
+ set_signals(enabled);
+ }
+
+-extern int timer_irq_inited;
+-
+ static void real_alarm_handler(int sig, struct sigcontext *sc)
+ {
+- if(!timer_irq_inited){
+- signals_enabled = 1;
+- return;
+- }
+-
+ if(sig == SIGALRM)
+ switch_timers(0);
+
+@@ -84,13 +73,10 @@ static void real_alarm_handler(int sig,
+
+ }
+
+-void alarm_handler(ARCH_SIGHDLR_PARAM)
++void alarm_handler(int sig, struct sigcontext *sc)
+ {
+- struct sigcontext *sc;
+ int enabled;
+
+- ARCH_GET_SIGCONTEXT(sc, sig);
+-
+ enabled = signals_enabled;
+ if(!signals_enabled){
+ if(sig == SIGVTALRM)
+@@ -126,6 +112,10 @@ void remove_sigstack(void)
+ panic("disabling signal stack failed, errno = %d\n", errno);
+ }
+
++void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
++
++extern void hard_handler(int sig);
++
+ void set_handler(int sig, void (*handler)(int), int flags, ...)
+ {
+ struct sigaction action;
+@@ -133,13 +123,16 @@ void set_handler(int sig, void (*handler
+ sigset_t sig_mask;
+ int mask;
+
+- va_start(ap, flags);
+- action.sa_handler = handler;
++ handlers[sig] = (void (*)(int, struct sigcontext *)) handler;
++ action.sa_handler = hard_handler;
++
+ sigemptyset(&action.sa_mask);
+- while((mask = va_arg(ap, int)) != -1){
++
++ va_start(ap, flags);
++ while((mask = va_arg(ap, int)) != -1)
+ sigaddset(&action.sa_mask, mask);
+- }
+ va_end(ap);
++
+ action.sa_flags = flags;
+ action.sa_restorer = NULL;
+ if(sigaction(sig, &action, NULL) < 0)
+@@ -164,6 +157,12 @@ int change_sig(int signal, int on)
+ void block_signals(void)
+ {
+ signals_enabled = 0;
++ /* This must return with signals disabled, so this barrier
++ * ensures that writes are flushed out before the return.
++ * This might matter if gcc figures out how to inline this and
++ * decides to shuffle this code into the caller.
++ */
++ mb();
+ }
+
+ void unblock_signals(void)
+@@ -183,9 +182,23 @@ void unblock_signals(void)
+ */
+ signals_enabled = 1;
+
++ /* Setting signals_enabled and reading pending must
++ * happen in this order.
++ */
++ mb();
++
+ save_pending = pending;
+- if(save_pending == 0)
++ if(save_pending == 0){
++ /* This must return with signals enabled, so
++ * this barrier ensures that writes are
++ * flushed out before the return. This might
++ * matter if gcc figures out how to inline
++ * this (unlikely, given its size) and decides
++ * to shuffle this code into the caller.
++ */
++ mb();
+ return;
++ }
+
+ pending = 0;
+
+diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
+index 7baf90f..9b34fe6 100644
+--- a/arch/um/os-Linux/skas/process.c
++++ b/arch/um/os-Linux/skas/process.c
+@@ -8,14 +8,13 @@
+ #include <unistd.h>
+ #include <errno.h>
+ #include <signal.h>
+-#include <setjmp.h>
+ #include <sched.h>
+ #include "ptrace_user.h"
+ #include <sys/wait.h>
+ #include <sys/mman.h>
+ #include <sys/user.h>
+ #include <sys/time.h>
+-#include <asm/unistd.h>
++#include <sys/syscall.h>
+ #include <asm/types.h>
+ #include "user.h"
+ #include "sysdep/ptrace.h"
+@@ -156,11 +155,15 @@ extern int __syscall_stub_start;
+ static int userspace_tramp(void *stack)
+ {
+ void *addr;
++ int err;
+
+ ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+ init_new_thread_signals();
+- enable_timer();
++ err = set_interval(1);
++ if(err)
++ panic("userspace_tramp - setting timer failed, errno = %d\n",
++ err);
+
+ if(!proc_mm){
+ /* This has a pte, but it can't be mapped in with the usual
+@@ -190,14 +193,25 @@ static int userspace_tramp(void *stack)
+ }
+ }
+ if(!ptrace_faultinfo && (stack != NULL)){
++ struct sigaction sa;
++
+ 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);
++ sigemptyset(&sa.sa_mask);
++ sigaddset(&sa.sa_mask, SIGIO);
++ sigaddset(&sa.sa_mask, SIGWINCH);
++ sigaddset(&sa.sa_mask, SIGALRM);
++ sigaddset(&sa.sa_mask, SIGVTALRM);
++ sigaddset(&sa.sa_mask, SIGUSR1);
++ sa.sa_flags = SA_ONSTACK;
++ sa.sa_handler = (void *) v;
++ sa.sa_restorer = NULL;
++ if(sigaction(SIGSEGV, &sa, NULL) < 0)
++ panic("userspace_tramp - setting SIGSEGV handler "
++ "failed - errno = %d\n", errno);
+ }
+
+ os_stop_process(os_getpid());
+@@ -430,56 +444,22 @@ void map_stub_pages(int fd, unsigned lon
+ }
+ }
+
+-void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
+- void (*handler)(int))
++void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
+ {
+- unsigned long flags;
+- jmp_buf switch_buf, fork_buf;
+-
+- *switch_buf_ptr = &switch_buf;
+- *fork_buf_ptr = &fork_buf;
+-
+- /* Somewhat subtle - siglongjmp restores the signal mask before doing
+- * the longjmp. This means that when jumping from one stack to another
+- * when the target stack has interrupts enabled, an interrupt may occur
+- * on the source stack. This is bad when starting up a process because
+- * it's not supposed to get timer ticks until it has been scheduled.
+- * So, we disable interrupts around the sigsetjmp to ensure that
+- * they can't happen until we get back here where they are safe.
+- */
+- flags = get_signals();
+- block_signals();
+- if(UML_SETJMP(&fork_buf) == 0)
+- new_thread_proc(stack, handler);
+-
+- remove_sigstack();
+-
+- set_signals(flags);
++ (*buf)[0].JB_IP = (unsigned long) handler;
++ (*buf)[0].JB_SP = (unsigned long) stack +
++ (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
+ }
+
+ #define INIT_JMP_NEW_THREAD 0
+-#define INIT_JMP_REMOVE_SIGSTACK 1
+-#define INIT_JMP_CALLBACK 2
+-#define INIT_JMP_HALT 3
+-#define INIT_JMP_REBOOT 4
++#define INIT_JMP_CALLBACK 1
++#define INIT_JMP_HALT 2
++#define INIT_JMP_REBOOT 3
+
+-void thread_wait(void *sw, void *fb)
++void switch_threads(jmp_buf *me, jmp_buf *you)
+ {
+- jmp_buf buf, **switch_buf = sw, *fork_buf;
+-
+- *switch_buf = &buf;
+- fork_buf = fb;
+- if(UML_SETJMP(&buf) == 0)
+- siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
+-}
+-
+-void switch_threads(void *me, void *next)
+-{
+- jmp_buf my_buf, **me_ptr = me, *next_buf = next;
+-
+- *me_ptr = &my_buf;
+- if(UML_SETJMP(&my_buf) == 0)
+- UML_LONGJMP(next_buf, 1);
++ if(UML_SETJMP(me) == 0)
++ UML_LONGJMP(you, 1);
+ }
+
+ static jmp_buf initial_jmpbuf;
+@@ -489,23 +469,21 @@ static void (*cb_proc)(void *arg);
+ static void *cb_arg;
+ static jmp_buf *cb_back;
+
+-int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
++int start_idle_thread(void *stack, jmp_buf *switch_buf)
+ {
+- jmp_buf **switch_buf = switch_buf_ptr;
+ int n;
+
+ set_handler(SIGWINCH, (__sighandler_t) sig_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
+ SIGVTALRM, -1);
+
+- *fork_buf_ptr = &initial_jmpbuf;
+ n = UML_SETJMP(&initial_jmpbuf);
+ switch(n){
+ case INIT_JMP_NEW_THREAD:
+- new_thread_proc((void *) stack, new_thread_handler);
+- break;
+- case INIT_JMP_REMOVE_SIGSTACK:
+- remove_sigstack();
++ (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
++ (*switch_buf)[0].JB_SP = (unsigned long) stack +
++ (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) -
++ sizeof(void *);
+ break;
+ case INIT_JMP_CALLBACK:
+ (*cb_proc)(cb_arg);
+@@ -520,7 +498,7 @@ int start_idle_thread(void *stack, void
+ default:
+ panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
+ }
+- UML_LONGJMP(*switch_buf, 1);
++ UML_LONGJMP(switch_buf, 1);
+ }
+
+ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
+diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
+index 5031485..7fe9268 100644
+--- a/arch/um/os-Linux/start_up.c
++++ b/arch/um/os-Linux/start_up.c
+@@ -14,7 +14,6 @@
+ #include <sched.h>
+ #include <fcntl.h>
+ #include <errno.h>
+-#include <setjmp.h>
+ #include <sys/time.h>
+ #include <sys/wait.h>
+ #include <sys/mman.h>
+diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile
+index b321361..3780662 100644
+--- a/arch/um/os-Linux/sys-i386/Makefile
++++ b/arch/um/os-Linux/sys-i386/Makefile
+@@ -3,7 +3,7 @@
+ # Licensed under the GPL
+ #
+
+-obj-$(CONFIG_MODE_SKAS) = registers.o tls.o
++obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o
+
+ USER_OBJS := $(obj-y)
+
+diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
+index 516f66d..7cd0369 100644
+--- a/arch/um/os-Linux/sys-i386/registers.c
++++ b/arch/um/os-Linux/sys-i386/registers.c
+@@ -5,12 +5,12 @@
+
+ #include <errno.h>
+ #include <string.h>
+-#include <setjmp.h>
+ #include "sysdep/ptrace_user.h"
+ #include "sysdep/ptrace.h"
+ #include "uml-config.h"
+ #include "skas_ptregs.h"
+ #include "registers.h"
++#include "longjmp.h"
+ #include "user.h"
+
+ /* These are set once at boot time and not changed thereafter */
+@@ -130,11 +130,14 @@ void get_safe_registers(unsigned long *r
+ HOST_FP_SIZE * sizeof(unsigned long));
+ }
+
+-void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer)
++unsigned long get_thread_reg(int reg, jmp_buf *buf)
+ {
+- struct __jmp_buf_tag *jmpbuf = buffer;
+-
+- UPT_SET(uml_regs, EIP, jmpbuf->__jmpbuf[JB_PC]);
+- UPT_SET(uml_regs, UESP, jmpbuf->__jmpbuf[JB_SP]);
+- UPT_SET(uml_regs, EBP, jmpbuf->__jmpbuf[JB_BP]);
++ switch(reg){
++ case EIP: return buf[0]->__eip;
++ case UESP: return buf[0]->__esp;
++ case EBP: return buf[0]->__ebp;
++ default:
++ printk("get_thread_regs - unknown register %d\n", reg);
++ return 0;
++ }
+ }
+diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c
+new file mode 100644
+index 0000000..0d3eae5
+--- /dev/null
++++ b/arch/um/os-Linux/sys-i386/signal.c
+@@ -0,0 +1,15 @@
++/*
++ * Copyright (C) 2006 Jeff Dike (jdike at addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++
++extern void (*handlers[])(int sig, struct sigcontext *sc);
++
++void hard_handler(int sig)
++{
++ struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
++
++ (*handlers[sig])(sig, sc);
++}
+diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c
+index 120abbe..2565320 100644
+--- a/arch/um/os-Linux/sys-i386/tls.c
++++ b/arch/um/os-Linux/sys-i386/tls.c
+@@ -1,10 +1,12 @@
+ #include <errno.h>
+ #include <linux/unistd.h>
++
++#include <sys/syscall.h>
++#include <unistd.h>
++
+ #include "sysdep/tls.h"
+ #include "user_util.h"
+
+-static _syscall1(int, get_thread_area, user_desc_t *, u_info);
+-
+ /* Checks whether host supports TLS, and sets *tls_min according to the value
+ * valid on the host.
+ * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */
+@@ -17,7 +19,7 @@ void check_host_supports_tls(int *suppor
+ user_desc_t info;
+ info.entry_number = val[i];
+
+- if (get_thread_area(&info) == 0) {
++ if (syscall(__NR_get_thread_area, &info) == 0) {
+ *tls_min = val[i];
+ *supports_tls = 1;
+ return;
+diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile
+index 340ef26..f67842a 100644
+--- a/arch/um/os-Linux/sys-x86_64/Makefile
++++ b/arch/um/os-Linux/sys-x86_64/Makefile
+@@ -3,7 +3,7 @@
+ # Licensed under the GPL
+ #
+
+-obj-$(CONFIG_MODE_SKAS) = registers.o
++obj-$(CONFIG_MODE_SKAS) = registers.o signal.o
+
+ USER_OBJS := $(obj-y)
+
+diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
+index becd898..cb8e8a2 100644
+--- a/arch/um/os-Linux/sys-x86_64/registers.c
++++ b/arch/um/os-Linux/sys-x86_64/registers.c
+@@ -5,11 +5,11 @@
+
+ #include <errno.h>
+ #include <string.h>
+-#include <setjmp.h>
+ #include "ptrace_user.h"
+ #include "uml-config.h"
+ #include "skas_ptregs.h"
+ #include "registers.h"
++#include "longjmp.h"
+ #include "user.h"
+
+ /* These are set once at boot time and not changed thereafter */
+@@ -78,11 +78,14 @@ void get_safe_registers(unsigned long *r
+ HOST_FP_SIZE * sizeof(unsigned long));
+ }
+
+-void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer)
++unsigned long get_thread_reg(int reg, jmp_buf *buf)
+ {
+- struct __jmp_buf_tag *jmpbuf = buffer;
+-
+- UPT_SET(uml_regs, RIP, jmpbuf->__jmpbuf[JB_PC]);
+- UPT_SET(uml_regs, RSP, jmpbuf->__jmpbuf[JB_RSP]);
+- UPT_SET(uml_regs, RBP, jmpbuf->__jmpbuf[JB_RBP]);
++ switch(reg){
++ case RIP: return buf[0]->__rip;
++ case RSP: return buf[0]->__rsp;
++ case RBP: return buf[0]->__rbp;
++ default:
++ printk("get_thread_regs - unknown register %d\n", reg);
++ return 0;
++ }
+ }
+diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c
+new file mode 100644
+index 0000000..3f369e5
+--- /dev/null
++++ b/arch/um/os-Linux/sys-x86_64/signal.c
+@@ -0,0 +1,16 @@
++/*
++ * Copyright (C) 2006 Jeff Dike (jdike at addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++
++extern void (*handlers[])(int sig, struct sigcontext *sc);
++
++void hard_handler(int sig)
++{
++ struct ucontext *uc;
++ asm("movq %%rdx, %0" : "=r" (uc));
++
++ (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext);
++}
+diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
+index 4ae73c0..2115b8b 100644
+--- a/arch/um/os-Linux/time.c
++++ b/arch/um/os-Linux/time.c
+@@ -16,21 +16,27 @@
+ #include "process.h"
+ #include "kern_constants.h"
+ #include "os.h"
++#include "uml-config.h"
+
+-static void set_interval(int timer_type)
++int set_interval(int is_virtual)
+ {
+ int usec = 1000000/hz();
++ int timer_type = is_virtual ? ITIMER_VIRTUAL : ITIMER_REAL;
+ struct itimerval interval = ((struct itimerval) { { 0, usec },
+ { 0, usec } });
+
+ if(setitimer(timer_type, &interval, NULL) == -1)
+- panic("setitimer failed - errno = %d\n", errno);
++ return -errno;
++
++ return 0;
+ }
+
++#ifdef UML_CONFIG_MODE_TT
+ void enable_timer(void)
+ {
+- set_interval(ITIMER_VIRTUAL);
++ set_interval(1);
+ }
++#endif
+
+ void disable_timer(void)
+ {
+@@ -40,8 +46,8 @@ void disable_timer(void)
+ printk("disnable_timer - setitimer failed, errno = %d\n",
+ errno);
+ /* If there are signals already queued, after unblocking ignore them */
+- set_handler(SIGALRM, SIG_IGN, 0, -1);
+- set_handler(SIGVTALRM, SIG_IGN, 0, -1);
++ signal(SIGALRM, SIG_IGN);
++ signal(SIGVTALRM, SIG_IGN);
+ }
+
+ void switch_timers(int to_real)
+@@ -74,7 +80,7 @@ void uml_idle_timer(void)
+
+ set_handler(SIGALRM, (__sighandler_t) alarm_handler,
+ SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
+- set_interval(ITIMER_REAL);
++ set_interval(0);
+ }
+ #endif
+
+@@ -94,8 +100,3 @@ void idle_sleep(int secs)
+ ts.tv_nsec = 0;
+ nanosleep(&ts, NULL);
+ }
+-
+-void user_time_init(void)
+-{
+- set_interval(ITIMER_VIRTUAL);
+-}
+diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c
+index 9cb09a4..16215b9 100644
+--- a/arch/um/os-Linux/tls.c
++++ b/arch/um/os-Linux/tls.c
+@@ -1,5 +1,7 @@
+ #include <errno.h>
++#include <unistd.h>
+ #include <sys/ptrace.h>
++#include <sys/syscall.h>
+ #include <asm/ldt.h>
+ #include "sysdep/tls.h"
+ #include "uml-config.h"
+@@ -48,14 +50,11 @@ int os_get_thread_area(user_desc_t *info
+ #ifdef UML_CONFIG_MODE_TT
+ #include "linux/unistd.h"
+
+-static _syscall1(int, get_thread_area, user_desc_t *, u_info);
+-static _syscall1(int, set_thread_area, user_desc_t *, u_info);
+-
+ int do_set_thread_area_tt(user_desc_t *info)
+ {
+ int ret;
+
+- ret = set_thread_area(info);
++ ret = syscall(__NR_set_thread_area,info);
+ if (ret < 0) {
+ ret = -errno;
+ }
+@@ -66,7 +65,7 @@ int do_get_thread_area_tt(user_desc_t *i
+ {
+ int ret;
+
+- ret = get_thread_area(info);
++ ret = syscall(__NR_get_thread_area,info);
+ if (ret < 0) {
+ ret = -errno;
+ }
+diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
+index 90b29ae..1df231a 100644
+--- a/arch/um/os-Linux/trap.c
++++ b/arch/um/os-Linux/trap.c
+@@ -5,7 +5,6 @@
+
+ #include <stdlib.h>
+ #include <signal.h>
+-#include <setjmp.h>
+ #include "kern_util.h"
+ #include "user_util.h"
+ #include "os.h"
+diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
+index 5461a06..3dc3a02 100644
+--- a/arch/um/os-Linux/tt.c
++++ b/arch/um/os-Linux/tt.c
+@@ -10,7 +10,6 @@
+ #include <errno.h>
+ #include <stdarg.h>
+ #include <stdlib.h>
+-#include <setjmp.h>
+ #include <sys/time.h>
+ #include <sys/ptrace.h>
+ #include <linux/ptrace.h>
+diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c
+index 865f6a6..bbb73a6 100644
+--- a/arch/um/os-Linux/uaccess.c
++++ b/arch/um/os-Linux/uaccess.c
+@@ -4,8 +4,7 @@
+ * Licensed under the GPL
+ */
+
+-#include <setjmp.h>
+-#include <string.h>
++#include <stddef.h>
+ #include "longjmp.h"
+
+ unsigned long __do_user_copy(void *to, const void *from, int n,
+diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
+index c47a2a7..56b8a50 100644
+--- a/arch/um/os-Linux/util.c
++++ b/arch/um/os-Linux/util.c
+@@ -7,7 +7,6 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <limits.h>
+-#include <setjmp.h>
+ #include <sys/mman.h>
+ #include <sys/stat.h>
+ #include <sys/utsname.h>
+@@ -81,11 +80,18 @@ void setup_machinename(char *machine_out
+ struct utsname host;
+
+ uname(&host);
+-#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT)
++#ifdef UML_CONFIG_UML_X86
++# ifndef UML_CONFIG_64BIT
+ if (!strcmp(host.machine, "x86_64")) {
+ strcpy(machine_out, "i686");
+ return;
+ }
++# else
++ if (!strcmp(host.machine, "i686")) {
++ strcpy(machine_out, "x86_64");
++ return;
++ }
++# endif
+ #endif
+ strcpy(machine_out, host.machine);
+ }
+@@ -107,11 +113,11 @@ int setjmp_wrapper(void (*proc)(void *,
+ jmp_buf buf;
+ int n;
+
+- n = sigsetjmp(buf, 1);
++ n = UML_SETJMP(&buf);
+ if(n == 0){
+ va_start(args, proc);
+ (*proc)(&buf, &args);
+ }
+ va_end(args);
+- return(n);
++ return n;
+ }
+diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
+index 374d61a..0e32adf 100644
+--- a/arch/um/sys-i386/Makefile
++++ b/arch/um/sys-i386/Makefile
+@@ -1,10 +1,10 @@
+ obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+- ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \
++ ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \
+ sys_call_table.o tls.o
+
+ obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
+
+-subarch-obj-y = lib/bitops.o kernel/semaphore.o
++subarch-obj-y = lib/bitops.o lib/semaphore.o
+ subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o
+ subarch-obj-$(CONFIG_MODULES) += kernel/module.o
+
+diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
+index 41b0ab2..f1bcd39 100644
+--- a/arch/um/sys-i386/bugs.c
++++ b/arch/um/sys-i386/bugs.c
+@@ -13,6 +13,7 @@
+ #include "sysdep/ptrace.h"
+ #include "task.h"
+ #include "os.h"
++#include "user_util.h"
+
+ #define MAXTOKEN 64
+
+@@ -104,17 +105,17 @@ int cpu_feature(char *what, char *buf, i
+ static int check_cpu_flag(char *feature, int *have_it)
+ {
+ char buf[MAXTOKEN], c;
+- int fd, len = sizeof(buf)/sizeof(buf[0]);
++ int fd, len = ARRAY_SIZE(buf);
+
+ printk("Checking for host processor %s support...", feature);
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+- return(0);
++ return 0;
+ }
+
+ *have_it = 0;
+- if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
++ if(!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf)))
+ goto out;
+
+ c = token(fd, buf, len - 1, ' ');
+@@ -138,7 +139,7 @@ static int check_cpu_flag(char *feature,
+ if(*have_it == 0) printk("No\n");
+ else if(*have_it == 1) printk("Yes\n");
+ os_close_file(fd);
+- return(1);
++ return 1;
+ }
+
+ #if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
+diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
+index fe0877b..e299ee5 100644
+--- a/arch/um/sys-i386/ldt.c
++++ b/arch/um/sys-i386/ldt.c
+@@ -4,7 +4,6 @@
+ */
+
+ #include "linux/stddef.h"
+-#include "linux/config.h"
+ #include "linux/sched.h"
+ #include "linux/slab.h"
+ #include "linux/types.h"
+@@ -424,9 +423,8 @@ void ldt_get_host_info(void)
+ size++;
+ }
+
+- if(size < sizeof(dummy_list)/sizeof(dummy_list[0])) {
++ if(size < ARRAY_SIZE(dummy_list))
+ host_ldt_entries = dummy_list;
+- }
+ else {
+ size = (size + 1) * sizeof(dummy_list[0]);
+ host_ldt_entries = (short *)kmalloc(size, GFP_KERNEL);
+diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
+index 40aa885..5f3cc66 100644
+--- a/arch/um/sys-i386/ptrace_user.c
++++ b/arch/um/sys-i386/ptrace_user.c
+@@ -15,6 +15,7 @@
+ #include "user.h"
+ #include "os.h"
+ #include "uml-config.h"
++#include "user_util.h"
+
+ int ptrace_getregs(long pid, unsigned long *regs_out)
+ {
+@@ -51,7 +52,7 @@ static void write_debugregs(int pid, uns
+ int nregs, i;
+
+ dummy = NULL;
+- nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
++ nregs = ARRAY_SIZE(dummy->u_debugreg);
+ for(i = 0; i < nregs; i++){
+ if((i == 4) || (i == 5)) continue;
+ if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
+@@ -68,7 +69,7 @@ static void read_debugregs(int pid, unsi
+ int nregs, i;
+
+ dummy = NULL;
+- nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
++ nregs = ARRAY_SIZE(dummy->u_debugreg);
+ for(i = 0; i < nregs; i++){
+ regs[i] = ptrace(PTRACE_PEEKUSR, pid,
+ &dummy->u_debugreg[i], 0);
+diff --git a/arch/um/sys-i386/setjmp.S b/arch/um/sys-i386/setjmp.S
+new file mode 100644
+index 0000000..b766792
+--- /dev/null
++++ b/arch/um/sys-i386/setjmp.S
+@@ -0,0 +1,58 @@
++#
++# arch/i386/setjmp.S
++#
++# setjmp/longjmp for the i386 architecture
++#
++
++#
++# The jmp_buf is assumed to contain the following, in order:
++# %ebx
++# %esp
++# %ebp
++# %esi
++# %edi
++# <return address>
++#
++
++ .text
++ .align 4
++ .globl setjmp
++ .type setjmp, @function
++setjmp:
++#ifdef _REGPARM
++ movl %eax,%edx
++#else
++ movl 4(%esp),%edx
++#endif
++ popl %ecx # Return address, and adjust the stack
++ xorl %eax,%eax # Return value
++ movl %ebx,(%edx)
++ movl %esp,4(%edx) # Post-return %esp!
++ pushl %ecx # Make the call/return stack happy
++ movl %ebp,8(%edx)
++ movl %esi,12(%edx)
++ movl %edi,16(%edx)
++ movl %ecx,20(%edx) # Return address
++ ret
++
++ .size setjmp,.-setjmp
++
++ .text
++ .align 4
++ .globl longjmp
++ .type longjmp, @function
++longjmp:
++#ifdef _REGPARM
++ xchgl %eax,%edx
++#else
++ movl 4(%esp),%edx # jmp_ptr address
++ movl 8(%esp),%eax # Return value
++#endif
++ movl (%edx),%ebx
++ movl 4(%edx),%esp
++ movl 8(%edx),%ebp
++ movl 12(%edx),%esi
++ movl 16(%edx),%edi
++ jmp *20(%edx)
++
++ .size longjmp,.-longjmp
+diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
+index d5244f0..171b3e9 100644
+--- a/arch/um/sys-i386/sysrq.c
++++ b/arch/um/sys-i386/sysrq.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/kernel.h"
+ #include "linux/smp.h"
+ #include "linux/sched.h"
+diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
+index 71b9796..643dab5 100644
+--- a/arch/um/sys-i386/tls.c
++++ b/arch/um/sys-i386/tls.c
+@@ -3,7 +3,6 @@
+ * Licensed under the GPL
+ */
+
+-#include "linux/config.h"
+ #include "linux/kernel.h"
+ #include "linux/sched.h"
+ #include "linux/slab.h"
+diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
+index c19794d..f41768b 100644
+--- a/arch/um/sys-x86_64/Makefile
++++ b/arch/um/sys-x86_64/Makefile
+@@ -5,8 +5,8 @@
+ #
+
+ obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
+- sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \
+- tls.o
++ setjmp.o sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o \
++ ksyms.o tls.o
+
+ obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
+ obj-$(CONFIG_MODULES) += um_module.o
+diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c
+index 8592738..12c5936 100644
+--- a/arch/um/sys-x86_64/ksyms.c
++++ b/arch/um/sys-x86_64/ksyms.c
+@@ -14,6 +14,3 @@ EXPORT_SYMBOL(__up_wakeup);
+
+ /*XXX: we need them because they would be exported by x86_64 */
+ EXPORT_SYMBOL(__memcpy);
+-
+-/* Networking helper routines. */
+-EXPORT_SYMBOL(ip_compute_csum);
+diff --git a/arch/um/sys-x86_64/setjmp.S b/arch/um/sys-x86_64/setjmp.S
+new file mode 100644
+index 0000000..45f547b
+--- /dev/null
++++ b/arch/um/sys-x86_64/setjmp.S
+@@ -0,0 +1,54 @@
++#
++# arch/x86_64/setjmp.S
++#
++# setjmp/longjmp for the x86-64 architecture
++#
++
++#
++# The jmp_buf is assumed to contain the following, in order:
++# %rbx
++# %rsp (post-return)
++# %rbp
++# %r12
++# %r13
++# %r14
++# %r15
++# <return address>
++#
++
++ .text
++ .align 4
++ .globl setjmp
++ .type setjmp, @function
++setjmp:
++ pop %rsi # Return address, and adjust the stack
++ xorl %eax,%eax # Return value
++ movq %rbx,(%rdi)
++ movq %rsp,8(%rdi) # Post-return %rsp!
++ push %rsi # Make the call/return stack happy
++ movq %rbp,16(%rdi)
++ movq %r12,24(%rdi)
++ movq %r13,32(%rdi)
++ movq %r14,40(%rdi)
++ movq %r15,48(%rdi)
++ movq %rsi,56(%rdi) # Return address
++ ret
++
++ .size setjmp,.-setjmp
++
++ .text
++ .align 4
++ .globl longjmp
++ .type longjmp, @function
++longjmp:
++ movl %esi,%eax # Return value (int)
++ movq (%rdi),%rbx
++ movq 8(%rdi),%rsp
++ movq 16(%rdi),%rbp
++ movq 24(%rdi),%r12
++ movq 32(%rdi),%r13
++ movq 40(%rdi),%r14
++ movq 48(%rdi),%r15
++ jmp *56(%rdi)
++
++ .size longjmp,.-longjmp
+diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
+index 1c96702..652fa34 100644
+--- a/arch/um/sys-x86_64/stub_segv.c
++++ b/arch/um/sys-x86_64/stub_segv.c
+@@ -5,7 +5,6 @@
+
+ #include <stddef.h>
+ #include <signal.h>
+-#include <linux/compiler.h>
+ #include <asm/unistd.h>
+ #include "uml-config.h"
+ #include "sysdep/sigcontext.h"
+diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
+index 6fce9f4..73ce446 100644
+--- a/arch/um/sys-x86_64/syscalls.c
++++ b/arch/um/sys-x86_64/syscalls.c
+@@ -21,7 +21,7 @@ asmlinkage long sys_uname64(struct new_u
+ {
+ int err;
+ down_read(&uts_sem);
+- err = copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ if (personality(current->personality) == PER_LINUX32)
+ err |= copy_to_user(&name->machine, "i686", 5);
+diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c
+index d0a25af..ce3e07f 100644
+--- a/arch/um/sys-x86_64/sysrq.c
++++ b/arch/um/sys-x86_64/sysrq.c
+@@ -16,7 +16,7 @@ void __show_regs(struct pt_regs * regs)
+ printk("\n");
+ print_modules();
+ printk("Pid: %d, comm: %.20s %s %s\n",
+- current->pid, current->comm, print_tainted(), system_utsname.release);
++ current->pid, current->comm, print_tainted(), init_utsname()->release);
+ printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff,
+ PT_REGS_RIP(regs));
+ printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs),
+diff --git a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S
+index d991e45..8bc521c 100644
+--- a/arch/v850/kernel/entry.S
++++ b/arch/v850/kernel/entry.S
+@@ -195,7 +195,7 @@
+ sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \
+ type ## _STATE_SAVER
+ /* Pop a register state pushed by PUSH_STATE, except for the stack pointer,
+- from the the stack. */
++ from the stack. */
+ #define POP_STATE(type) \
+ mov sp, ep; \
+ type ## _STATE_RESTORER; \
+diff --git a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c
+index 491614c..92f514f 100644
+--- a/arch/v850/kernel/memcons.c
++++ b/arch/v850/kernel/memcons.c
+@@ -30,7 +30,7 @@ static DEFINE_SPINLOCK(memcons_lock);
+
+ static size_t write (const char *buf, size_t len)
+ {
+- int flags;
++ unsigned long flags;
+ char *point;
+
+ spin_lock_irqsave (memcons_lock, flags);
+@@ -104,7 +104,7 @@ int memcons_tty_chars_in_buffer (struct
+ return 0;
+ }
+
+-static struct tty_operations ops = {
++static const struct tty_operations ops = {
+ .open = memcons_tty_open,
+ .write = memcons_tty_write,
+ .write_room = memcons_tty_write_room,
+diff --git a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c
+index f654088..996bd4f 100644
+--- a/arch/v850/kernel/rte_cb_leds.c
++++ b/arch/v850/kernel/rte_cb_leds.c
+@@ -42,7 +42,7 @@ do { \
+ len = LED_NUM_DIGITS - pos; \
+ \
+ if (len > 0) { \
+- int _flags; \
++ unsigned long _flags; \
+ const char *_end = buf + len; \
+ img_decl = &leds_image[pos]; \
+ \
+diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c
+index f36b778..35213fa 100644
+--- a/arch/v850/kernel/rte_mb_a_pci.c
++++ b/arch/v850/kernel/rte_mb_a_pci.c
+@@ -365,7 +365,7 @@ static DEFINE_SPINLOCK(mb_sram_lock);
+ static void *alloc_mb_sram (size_t size)
+ {
+ struct mb_sram_free_area *prev, *fa;
+- int flags;
++ unsigned long flags;
+ void *mem = 0;
+
+ spin_lock_irqsave (mb_sram_lock, flags);
+@@ -406,7 +406,7 @@ static void *alloc_mb_sram (size_t size)
+ static void free_mb_sram (void *mem, size_t size)
+ {
+ struct mb_sram_free_area *prev, *fa, *new_fa;
+- int flags;
++ unsigned long flags;
+ void *end = mem + size;
+
+ spin_lock_irqsave (mb_sram_lock, flags);
+@@ -517,7 +517,7 @@ static DEFINE_SPINLOCK(dma_mappings_lock
+
+ static struct dma_mapping *new_dma_mapping (size_t size)
+ {
+- int flags;
++ unsigned long flags;
+ struct dma_mapping *mapping;
+ void *mb_sram_block = alloc_mb_sram (size);
+
+@@ -575,7 +575,7 @@ static struct dma_mapping *new_dma_mappi
+
+ static struct dma_mapping *find_dma_mapping (void *mb_sram_addr)
+ {
+- int flags;
++ unsigned long flags;
+ struct dma_mapping *mapping;
+
+ spin_lock_irqsave (dma_mappings_lock, flags);
+@@ -592,7 +592,7 @@ static struct dma_mapping *find_dma_mapp
+
+ static struct dma_mapping *deactivate_dma_mapping (void *mb_sram_addr)
+ {
+- int flags;
++ unsigned long flags;
+ struct dma_mapping *mapping, *prev;
+
+ spin_lock_irqsave (dma_mappings_lock, flags);
+@@ -622,7 +622,7 @@ static struct dma_mapping *deactivate_dm
+ static inline void
+ free_dma_mapping (struct dma_mapping *mapping)
+ {
+- int flags;
++ unsigned long flags;
+
+ free_mb_sram (mapping->mb_sram_addr, mapping->size);
+
+diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c
+index 3975aa0..9973596 100644
+--- a/arch/v850/kernel/simcons.c
++++ b/arch/v850/kernel/simcons.c
+@@ -77,7 +77,7 @@ int simcons_tty_chars_in_buffer (struct
+ return 0;
+ }
+
+-static struct tty_operations ops = {
++static const struct tty_operations ops = {
+ .open = simcons_tty_open,
+ .write = simcons_tty_write,
+ .write_room = simcons_tty_write_room,
+diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c
+index 2ec0700..d2b1fb1 100644
+--- a/arch/v850/kernel/syscalls.c
++++ b/arch/v850/kernel/syscalls.c
+@@ -33,6 +33,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
+ #include <asm/semaphore.h>
++#include <asm/unistd.h>
+
+ /*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+@@ -194,3 +195,22 @@ unsigned long sys_mmap (unsigned long ad
+ out:
+ return err;
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ register char *__a __asm__ ("r6") = filename;
++ register void *__b __asm__ ("r7") = argv;
++ register void *__c __asm__ ("r8") = envp;
++ register unsigned long __syscall __asm__ ("r12") = __NR_execve;
++ register unsigned long __ret __asm__ ("r10");
++ __asm__ __volatile__ ("trap 0"
++ : "=r" (__ret), "=r" (__syscall)
++ : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c)
++ : "r1", "r5", "r11", "r13", "r14",
++ "r15", "r16", "r17", "r18", "r19");
++ return __ret;
++}
+diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
+index a0b4669..cd06f47 100644
+--- a/arch/v850/kernel/time.c
++++ b/arch/v850/kernel/time.c
+@@ -10,7 +10,6 @@
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+-#include <linux/config.h> /* CONFIG_HEARTBEAT */
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -51,7 +50,7 @@ static irqreturn_t timer_interrupt (int
+ if (mach_tick)
+ mach_tick ();
+
+- do_timer (regs);
++ do_timer (1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S
+index 6339921..88d087f 100644
+--- a/arch/v850/kernel/vmlinux.lds.S
++++ b/arch/v850/kernel/vmlinux.lds.S
+@@ -140,13 +140,7 @@
+ ___setup_end = . ; \
+ ___initcall_start = . ; \
+ *(.initcall.init) \
+- *(.initcall1.init) \
+- *(.initcall2.init) \
+- *(.initcall3.init) \
+- *(.initcall4.init) \
+- *(.initcall5.init) \
+- *(.initcall6.init) \
+- *(.initcall7.init) \
++ INITCALLS \
+ . = ALIGN (4) ; \
+ ___initcall_end = . ; \
+ ___con_initcall_start = .; \
+diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
+index 6cd4878..010d226 100644
+--- a/arch/x86_64/Kconfig
++++ b/arch/x86_64/Kconfig
+@@ -24,6 +24,10 @@ config X86
+ bool
+ default y
+
++config ZONE_DMA32
++ bool
++ default y
++
+ config LOCKDEP_SUPPORT
+ bool
+ default y
+@@ -81,6 +85,9 @@ config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
++config ARCH_POPULATES_NODE_MAP
++ def_bool y
++
+ config DMI
+ bool
+ default y
+@@ -105,6 +112,7 @@ config X86_PC
+
+ config X86_VSMP
+ bool "Support for ScaleMP vSMP"
++ depends on PCI
+ help
+ Support for ScaleMP vSMP systems. Say 'Y' here if this kernel is
+ supposed to run on these EM64T-based machines. Only choose this option
+@@ -163,6 +171,7 @@ config X86_GOOD_APIC
+
+ config MICROCODE
+ tristate "/dev/cpu/microcode - Intel CPU microcode support"
++ select FW_LOADER
+ ---help---
+ If you say Y here the 'File systems' section, you will be
+ able to update the microcode on Intel processors. You will
+@@ -178,6 +187,11 @@ config MICROCODE
+ If you use modprobe or kmod you may also want to add the line
+ 'alias char-major-10-184 microcode' to your /etc/modules.conf file.
+
++config MICROCODE_OLD_INTERFACE
++ bool
++ depends on MICROCODE
++ default y
++
+ config X86_MSR
+ tristate "/dev/cpu/*/msr - Model-specific register support"
+ help
+@@ -291,12 +305,12 @@ config NUMA
+
+ config K8_NUMA
+ bool "Old style AMD Opteron NUMA detection"
+- depends on NUMA
++ depends on NUMA && PCI
+ default y
+ help
+ Enable K8 NUMA node topology detection. You should say Y here if
+ you have a multi processor AMD K8 system. This uses an old
+- method to read the NUMA configurtion directly from the builtin
++ method to read the NUMA configuration directly from the builtin
+ Northbridge of Opteron. It is recommended to use X86_64_ACPI_NUMA
+ instead, which also takes priority if both are compiled in.
+
+@@ -353,6 +367,10 @@ config ARCH_FLATMEM_ENABLE
+
+ source "mm/Kconfig"
+
++config MEMORY_HOTPLUG_RESERVE
++ def_bool y
++ depends on (MEMORY_HOTPLUG && DISCONTIGMEM)
++
+ config HAVE_ARCH_EARLY_PFN_TO_NID
+ def_bool y
+ depends on NUMA
+@@ -421,7 +439,6 @@ config IOMMU
+
+ config CALGARY_IOMMU
+ bool "IBM Calgary IOMMU support"
+- default y
+ select SWIOTLB
+ depends on PCI && EXPERIMENTAL
+ help
+@@ -468,8 +485,7 @@ config X86_MCE_AMD
+ the DRAM Error Threshold.
+
+ config KEXEC
+- bool "kexec system call (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ bool "kexec system call"
+ 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
+@@ -488,7 +504,14 @@ config CRASH_DUMP
+ bool "kernel crash dumps (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+- Generate crash dump after being started by kexec.
++ Generate crash dump after being started by kexec.
++ This should be normally only set in special crash dump kernels
++ which are loaded in the main kernel with kexec-tools into
++ a specially reserved region and then later executed after
++ a crash by kdump/kexec. The crash dump kernel must be compiled
++ to a memory address not used by the main kernel or BIOS using
++ PHYSICAL_START.
++ For more details see Documentation/kdump/kdump.txt
+
+ config PHYSICAL_START
+ hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+@@ -526,6 +549,30 @@ config SECCOMP
+
+ If unsure, say Y. Only embedded should say N here.
+
++config CC_STACKPROTECTOR
++ bool "Enable -fstack-protector buffer overflow detection (EXPRIMENTAL)"
++ depends on EXPERIMENTAL
++ help
++ This option turns on the -fstack-protector GCC feature. This
++ feature puts, at the beginning of critical functions, a canary
++ value on the stack just before the return address, and validates
++ the value just before actually returning. Stack based buffer
++ overflows (that need to overwrite this return address) now also
++ overwrite the canary, which gets detected and the attack is then
++ neutralized via a kernel panic.
++
++ This feature requires gcc version 4.2 or above, or a distribution
++ gcc with the feature backported. Older versions are automatically
++ detected and for those versions, this configuration option is ignored.
++
++config CC_STACKPROTECTOR_ALL
++ bool "Use stack-protector for all functions"
++ depends on CC_STACKPROTECTOR
++ help
++ Normally, GCC only inserts the canary value protection for
++ functions that use large-ish on-stack buffers. By enabling
++ this option, GCC will be asked to do this for ALL functions.
++
+ source kernel/Kconfig.hz
+
+ config REORDER
+@@ -643,7 +690,7 @@ source "arch/x86_64/oprofile/Kconfig"
+
+ config KPROBES
+ bool "Kprobes (EXPERIMENTAL)"
+- depends on EXPERIMENTAL && MODULES
++ depends on KALLSYMS && EXPERIMENTAL && MODULES
+ help
+ Kprobes allows you to trap at almost any kernel address and
+ execute a callback function. register_kprobe() establishes
+diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
+index 431bb4b..1397214 100644
+--- a/arch/x86_64/Makefile
++++ b/arch/x86_64/Makefile
+@@ -54,6 +54,20 @@ endif
+ cflags-y += $(call cc-option,-funit-at-a-time)
+ # prevent gcc from generating any FP code by mistake
+ cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
++# this works around some issues with generating unwind tables in older gccs
++# newer gccs do it by default
++cflags-y += -maccumulate-outgoing-args
++
++# do binutils support CFI?
++cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
++AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
++
++# is .cfi_signal_frame supported too?
++cflags-y += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,)
++AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,)
++
++cflags-$(CONFIG_CC_STACKPROTECTOR) += $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) -fstack-protector )
++cflags-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) -fstack-protector-all )
+
+ CFLAGS += $(cflags-y)
+ CFLAGS_KERNEL += $(cflags-kernel-y)
+diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
+index f89d96f..e70fa6e 100644
+--- a/arch/x86_64/boot/compressed/Makefile
++++ b/arch/x86_64/boot/compressed/Makefile
+@@ -7,7 +7,8 @@
+ #
+
+ targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+-EXTRA_AFLAGS := -traditional -m32
++EXTRA_AFLAGS := -traditional
++AFLAGS := $(subst -m64,-m32,$(AFLAGS))
+
+ # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
+ # -m32
+diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
+index a50b631..c3bfd22 100644
+--- a/arch/x86_64/boot/setup.S
++++ b/arch/x86_64/boot/setup.S
+@@ -526,12 +526,12 @@ is_disk1:
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %ds
+- movw $0, (0x1ff) # default is no pointing device
++ movb $0, (0x1ff) # default is no pointing device
+ int $0x11 # int 0x11: equipment list
+ testb $0x04, %al # check if mouse installed
+ jz no_psmouse
+
+- movw $0xAA, (0x1ff) # device present
++ movb $0xAA, (0x1ff) # device present
+ no_psmouse:
+
+ #include "../../i386/boot/edd.S"
+diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
+index 2aa565c..d6ff88f 100644
+--- a/arch/x86_64/boot/video.S
++++ b/arch/x86_64/boot/video.S
+@@ -11,8 +11,6 @@
+ *
+ */
+
+-#include <linux/config.h> /* for CONFIG_VIDEO_* */
+-
+ /* Enable autodetection of SVGA adapters and modes. */
+ #undef CONFIG_VIDEO_SVGA
+
+diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile
+index 426d20f..15b538a 100644
+--- a/arch/x86_64/crypto/Makefile
++++ b/arch/x86_64/crypto/Makefile
+@@ -5,5 +5,8 @@
+ #
+
+ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
++obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
+
+ aes-x86_64-y := aes-x86_64-asm.o aes.o
++twofish-x86_64-y := twofish-x86_64-asm.o twofish.o
++
+diff --git a/arch/x86_64/crypto/aes.c b/arch/x86_64/crypto/aes.c
+index 68866fa..5cdb13e 100644
+--- a/arch/x86_64/crypto/aes.c
++++ b/arch/x86_64/crypto/aes.c
+@@ -228,13 +228,14 @@ static void __init gen_tabs(void)
+ }
+
+ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __le32 *key = (const __le32 *)in_key;
++ u32 *flags = &tfm->crt_flags;
+ u32 i, j, t, u, v, w;
+
+- if (key_len != 16 && key_len != 24 && key_len != 32) {
++ if (key_len % 8) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+diff --git a/arch/x86_64/crypto/twofish-x86_64-asm.S b/arch/x86_64/crypto/twofish-x86_64-asm.S
+new file mode 100644
+index 0000000..35974a5
+--- /dev/null
++++ b/arch/x86_64/crypto/twofish-x86_64-asm.S
+@@ -0,0 +1,324 @@
++/***************************************************************************
++* Copyright (C) 2006 by Joachim Fritschi, <jfritschi at freenet.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., *
++* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
++***************************************************************************/
++
++.file "twofish-x86_64-asm.S"
++.text
++
++#include <asm/asm-offsets.h>
++
++#define a_offset 0
++#define b_offset 4
++#define c_offset 8
++#define d_offset 12
++
++/* Structure of the crypto context struct*/
++
++#define s0 0 /* S0 Array 256 Words each */
++#define s1 1024 /* S1 Array */
++#define s2 2048 /* S2 Array */
++#define s3 3072 /* S3 Array */
++#define w 4096 /* 8 whitening keys (word) */
++#define k 4128 /* key 1-32 ( word ) */
++
++/* define a few register aliases to allow macro substitution */
++
++#define R0 %rax
++#define R0D %eax
++#define R0B %al
++#define R0H %ah
++
++#define R1 %rbx
++#define R1D %ebx
++#define R1B %bl
++#define R1H %bh
++
++#define R2 %rcx
++#define R2D %ecx
++#define R2B %cl
++#define R2H %ch
++
++#define R3 %rdx
++#define R3D %edx
++#define R3B %dl
++#define R3H %dh
++
++
++/* performs input whitening */
++#define input_whitening(src,context,offset)\
++ xor w+offset(context), src;
++
++/* performs input whitening */
++#define output_whitening(src,context,offset)\
++ xor w+16+offset(context), src;
++
++
++/*
++ * a input register containing a (rotated 16)
++ * b input register containing b
++ * c input register containing c
++ * d input register containing d (already rol $1)
++ * operations on a and b are interleaved to increase performance
++ */
++#define encrypt_round(a,b,c,d,round)\
++ movzx b ## B, %edi;\
++ mov s1(%r11,%rdi,4),%r8d;\
++ movzx a ## B, %edi;\
++ mov s2(%r11,%rdi,4),%r9d;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor s2(%r11,%rdi,4),%r8d;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s3(%r11,%rdi,4),%r9d;\
++ movzx b ## B, %edi;\
++ xor s3(%r11,%rdi,4),%r8d;\
++ movzx a ## B, %edi;\
++ xor (%r11,%rdi,4), %r9d;\
++ movzx b ## H, %edi;\
++ ror $15, b ## D;\
++ xor (%r11,%rdi,4), %r8d;\
++ movzx a ## H, %edi;\
++ xor s1(%r11,%rdi,4),%r9d;\
++ add %r8d, %r9d;\
++ add %r9d, %r8d;\
++ add k+round(%r11), %r9d;\
++ xor %r9d, c ## D;\
++ rol $15, c ## D;\
++ add k+4+round(%r11),%r8d;\
++ xor %r8d, d ## D;
++
++/*
++ * a input register containing a(rotated 16)
++ * b input register containing b
++ * c input register containing c
++ * d input register containing d (already rol $1)
++ * operations on a and b are interleaved to increase performance
++ * during the round a and b are prepared for the output whitening
++ */
++#define encrypt_last_round(a,b,c,d,round)\
++ mov b ## D, %r10d;\
++ shl $32, %r10;\
++ movzx b ## B, %edi;\
++ mov s1(%r11,%rdi,4),%r8d;\
++ movzx a ## B, %edi;\
++ mov s2(%r11,%rdi,4),%r9d;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor s2(%r11,%rdi,4),%r8d;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s3(%r11,%rdi,4),%r9d;\
++ movzx b ## B, %edi;\
++ xor s3(%r11,%rdi,4),%r8d;\
++ movzx a ## B, %edi;\
++ xor (%r11,%rdi,4), %r9d;\
++ xor a, %r10;\
++ movzx b ## H, %edi;\
++ xor (%r11,%rdi,4), %r8d;\
++ movzx a ## H, %edi;\
++ xor s1(%r11,%rdi,4),%r9d;\
++ add %r8d, %r9d;\
++ add %r9d, %r8d;\
++ add k+round(%r11), %r9d;\
++ xor %r9d, c ## D;\
++ ror $1, c ## D;\
++ add k+4+round(%r11),%r8d;\
++ xor %r8d, d ## D
++
++/*
++ * a input register containing a
++ * b input register containing b (rotated 16)
++ * c input register containing c (already rol $1)
++ * d input register containing d
++ * operations on a and b are interleaved to increase performance
++ */
++#define decrypt_round(a,b,c,d,round)\
++ movzx a ## B, %edi;\
++ mov (%r11,%rdi,4), %r9d;\
++ movzx b ## B, %edi;\
++ mov s3(%r11,%rdi,4),%r8d;\
++ movzx a ## H, %edi;\
++ ror $16, a ## D;\
++ xor s1(%r11,%rdi,4),%r9d;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor (%r11,%rdi,4), %r8d;\
++ movzx a ## B, %edi;\
++ xor s2(%r11,%rdi,4),%r9d;\
++ movzx b ## B, %edi;\
++ xor s1(%r11,%rdi,4),%r8d;\
++ movzx a ## H, %edi;\
++ ror $15, a ## D;\
++ xor s3(%r11,%rdi,4),%r9d;\
++ movzx b ## H, %edi;\
++ xor s2(%r11,%rdi,4),%r8d;\
++ add %r8d, %r9d;\
++ add %r9d, %r8d;\
++ add k+round(%r11), %r9d;\
++ xor %r9d, c ## D;\
++ add k+4+round(%r11),%r8d;\
++ xor %r8d, d ## D;\
++ rol $15, d ## D;
++
++/*
++ * a input register containing a
++ * b input register containing b
++ * c input register containing c (already rol $1)
++ * d input register containing d
++ * operations on a and b are interleaved to increase performance
++ * during the round a and b are prepared for the output whitening
++ */
++#define decrypt_last_round(a,b,c,d,round)\
++ movzx a ## B, %edi;\
++ mov (%r11,%rdi,4), %r9d;\
++ movzx b ## B, %edi;\
++ mov s3(%r11,%rdi,4),%r8d;\
++ movzx b ## H, %edi;\
++ ror $16, b ## D;\
++ xor (%r11,%rdi,4), %r8d;\
++ movzx a ## H, %edi;\
++ mov b ## D, %r10d;\
++ shl $32, %r10;\
++ xor a, %r10;\
++ ror $16, a ## D;\
++ xor s1(%r11,%rdi,4),%r9d;\
++ movzx b ## B, %edi;\
++ xor s1(%r11,%rdi,4),%r8d;\
++ movzx a ## B, %edi;\
++ xor s2(%r11,%rdi,4),%r9d;\
++ movzx b ## H, %edi;\
++ xor s2(%r11,%rdi,4),%r8d;\
++ movzx a ## H, %edi;\
++ xor s3(%r11,%rdi,4),%r9d;\
++ add %r8d, %r9d;\
++ add %r9d, %r8d;\
++ add k+round(%r11), %r9d;\
++ xor %r9d, c ## D;\
++ add k+4+round(%r11),%r8d;\
++ xor %r8d, d ## D;\
++ ror $1, d ## D;
++
++.align 8
++.global twofish_enc_blk
++.global twofish_dec_blk
++
++twofish_enc_blk:
++ pushq R1
++
++ /* %rdi contains the crypto tfm adress */
++ /* %rsi contains the output adress */
++ /* %rdx contains the input adress */
++ add $crypto_tfm_ctx_offset, %rdi /* set ctx adress */
++ /* ctx adress is moved to free one non-rex register
++ as target for the 8bit high operations */
++ mov %rdi, %r11
++
++ movq (R3), R1
++ movq 8(R3), R3
++ input_whitening(R1,%r11,a_offset)
++ input_whitening(R3,%r11,c_offset)
++ mov R1D, R0D
++ rol $16, R0D
++ shr $32, R1
++ mov R3D, R2D
++ shr $32, R3
++ rol $1, R3D
++
++ encrypt_round(R0,R1,R2,R3,0);
++ encrypt_round(R2,R3,R0,R1,8);
++ encrypt_round(R0,R1,R2,R3,2*8);
++ encrypt_round(R2,R3,R0,R1,3*8);
++ encrypt_round(R0,R1,R2,R3,4*8);
++ encrypt_round(R2,R3,R0,R1,5*8);
++ encrypt_round(R0,R1,R2,R3,6*8);
++ encrypt_round(R2,R3,R0,R1,7*8);
++ encrypt_round(R0,R1,R2,R3,8*8);
++ encrypt_round(R2,R3,R0,R1,9*8);
++ encrypt_round(R0,R1,R2,R3,10*8);
++ encrypt_round(R2,R3,R0,R1,11*8);
++ encrypt_round(R0,R1,R2,R3,12*8);
++ encrypt_round(R2,R3,R0,R1,13*8);
++ encrypt_round(R0,R1,R2,R3,14*8);
++ encrypt_last_round(R2,R3,R0,R1,15*8);
++
++
++ output_whitening(%r10,%r11,a_offset)
++ movq %r10, (%rsi)
++
++ shl $32, R1
++ xor R0, R1
++
++ output_whitening(R1,%r11,c_offset)
++ movq R1, 8(%rsi)
++
++ popq R1
++ movq $1,%rax
++ ret
++
++twofish_dec_blk:
++ pushq R1
++
++ /* %rdi contains the crypto tfm adress */
++ /* %rsi contains the output adress */
++ /* %rdx contains the input adress */
++ add $crypto_tfm_ctx_offset, %rdi /* set ctx adress */
++ /* ctx adress is moved to free one non-rex register
++ as target for the 8bit high operations */
++ mov %rdi, %r11
++
++ movq (R3), R1
++ movq 8(R3), R3
++ output_whitening(R1,%r11,a_offset)
++ output_whitening(R3,%r11,c_offset)
++ mov R1D, R0D
++ shr $32, R1
++ rol $16, R1D
++ mov R3D, R2D
++ shr $32, R3
++ rol $1, R2D
++
++ decrypt_round(R0,R1,R2,R3,15*8);
++ decrypt_round(R2,R3,R0,R1,14*8);
++ decrypt_round(R0,R1,R2,R3,13*8);
++ decrypt_round(R2,R3,R0,R1,12*8);
++ decrypt_round(R0,R1,R2,R3,11*8);
++ decrypt_round(R2,R3,R0,R1,10*8);
++ decrypt_round(R0,R1,R2,R3,9*8);
++ decrypt_round(R2,R3,R0,R1,8*8);
++ decrypt_round(R0,R1,R2,R3,7*8);
++ decrypt_round(R2,R3,R0,R1,6*8);
++ decrypt_round(R0,R1,R2,R3,5*8);
++ decrypt_round(R2,R3,R0,R1,4*8);
++ decrypt_round(R0,R1,R2,R3,3*8);
++ decrypt_round(R2,R3,R0,R1,2*8);
++ decrypt_round(R0,R1,R2,R3,1*8);
++ decrypt_last_round(R2,R3,R0,R1,0);
++
++ input_whitening(%r10,%r11,a_offset)
++ movq %r10, (%rsi)
++
++ shl $32, R1
++ xor R0, R1
++
++ input_whitening(R1,%r11,c_offset)
++ movq R1, 8(%rsi)
++
++ popq R1
++ movq $1,%rax
++ ret
+diff --git a/arch/x86_64/crypto/twofish.c b/arch/x86_64/crypto/twofish.c
+new file mode 100644
+index 0000000..182d91d
+--- /dev/null
++++ b/arch/x86_64/crypto/twofish.c
+@@ -0,0 +1,97 @@
++/*
++ * Glue Code for optimized x86_64 assembler version of TWOFISH
++ *
++ * Originally Twofish for GPG
++ * By Matthew Skala <mskala at ansuz.sooke.bc.ca>, July 26, 1998
++ * 256-bit key length added March 20, 1999
++ * Some modifications to reduce the text size by Werner Koch, April, 1998
++ * Ported to the kerneli patch by Marc Mutz <Marc at Mutz.com>
++ * Ported to CryptoAPI by Colin Slater <hoho at tacomeat.net>
++ *
++ * The original author has disclaimed all copyright interest in this
++ * code and thus put it in the public domain. The subsequent authors
++ * have put this under the GNU General Public License.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
++ * USA
++ *
++ * This code is a "clean room" implementation, written from the paper
++ * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
++ * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
++ * through http://www.counterpane.com/twofish.html
++ *
++ * For background information on multiplication in finite fields, used for
++ * the matrix operations in the key schedule, see the book _Contemporary
++ * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
++ * Third Edition.
++ */
++
++#include <crypto/twofish.h>
++#include <linux/crypto.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++
++asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
++asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
++
++static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
++{
++ twofish_enc_blk(tfm, dst, src);
++}
++
++static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
++{
++ twofish_dec_blk(tfm, dst, src);
++}
++
++static struct crypto_alg alg = {
++ .cra_name = "twofish",
++ .cra_driver_name = "twofish-x86_64",
++ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = TF_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct twofish_ctx),
++ .cra_alignmask = 3,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = TF_MIN_KEY_SIZE,
++ .cia_max_keysize = TF_MAX_KEY_SIZE,
++ .cia_setkey = twofish_setkey,
++ .cia_encrypt = twofish_encrypt,
++ .cia_decrypt = twofish_decrypt
++ }
++ }
++};
++
++static int __init init(void)
++{
++ return crypto_register_alg(&alg);
++}
++
++static void __exit fini(void)
++{
++ crypto_unregister_alg(&alg);
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION ("Twofish Cipher Algorithm, x86_64 asm optimized");
++MODULE_ALIAS("twofish");
+diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
+index 5fb9707..0f5d44e 100644
+--- a/arch/x86_64/defconfig
++++ b/arch/x86_64/defconfig
+@@ -1,11 +1,12 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18-rc4
+-# Thu Aug 24 21:05:55 2006
++# Linux kernel version: 2.6.19-rc2-git4
++# Sat Oct 21 03:38:52 2006
+ #
+ CONFIG_X86_64=y
+ CONFIG_64BIT=y
+ CONFIG_X86=y
++CONFIG_ZONE_DMA32=y
+ CONFIG_LOCKDEP_SUPPORT=y
+ CONFIG_STACKTRACE_SUPPORT=y
+ CONFIG_SEMAPHORE_SLEEPERS=y
+@@ -18,7 +19,9 @@ CONFIG_EARLY_PRINTK=y
+ CONFIG_GENERIC_ISA_DMA=y
+ CONFIG_GENERIC_IOMAP=y
+ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_ARCH_POPULATES_NODE_MAP=y
+ CONFIG_DMI=y
++CONFIG_AUDIT_ARCH=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+@@ -35,19 +38,22 @@ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
+ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-CONFIG_SYSCTL=y
++# CONFIG_UTS_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_CPUSETS is not set
+ # CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_UID16=y
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
+ # CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++# CONFIG_SYSCTL_SYSCALL is not set
+ CONFIG_KALLSYMS=y
+ CONFIG_KALLSYMS_ALL=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -56,12 +62,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
+-CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+ CONFIG_SHMEM=y
+ CONFIG_SLAB=y
+ CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -80,6 +86,7 @@ CONFIG_STOP_MACHINE=y
+ #
+ # Block layer
+ #
++CONFIG_BLOCK=y
+ CONFIG_LBD=y
+ # CONFIG_BLK_DEV_IO_TRACE is not set
+ # CONFIG_LSF is not set
+@@ -160,6 +167,7 @@ CONFIG_X86_MCE_AMD=y
+ # CONFIG_CRASH_DUMP is not set
+ CONFIG_PHYSICAL_START=0x200000
+ CONFIG_SECCOMP=y
++# CONFIG_CC_STACKPROTECTOR is not set
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+ # CONFIG_HZ_1000 is not set
+@@ -177,6 +185,7 @@ CONFIG_GENERIC_PENDING_IRQ=y
+ CONFIG_PM=y
+ # CONFIG_PM_LEGACY is not set
+ # CONFIG_PM_DEBUG is not set
++# CONFIG_PM_SYSFS_DEPRECATED is not set
+ CONFIG_SOFTWARE_SUSPEND=y
+ CONFIG_PM_STD_PARTITION=""
+ CONFIG_SUSPEND_SMP=y
+@@ -248,8 +257,11 @@ CONFIG_PCI=y
+ CONFIG_PCI_DIRECT=y
+ CONFIG_PCI_MMCONFIG=y
+ CONFIG_PCIEPORTBUS=y
++CONFIG_PCIEAER=y
+ CONFIG_PCI_MSI=y
++# CONFIG_PCI_MULTITHREAD_PROBE is not set
+ # CONFIG_PCI_DEBUG is not set
++# CONFIG_HT_IRQ is not set
+
+ #
+ # PCCARD (PCMCIA/CardBus) support
+@@ -304,21 +316,28 @@ CONFIG_IP_PNP_DHCP=y
+ # CONFIG_INET_TUNNEL is not set
+ # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+ # CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+-CONFIG_TCP_CONG_BIC=y
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
+ CONFIG_IPV6=y
+ # CONFIG_IPV6_PRIVACY is not set
+ # CONFIG_IPV6_ROUTER_PREF is not set
+ # CONFIG_INET6_AH is not set
+ # CONFIG_INET6_ESP is not set
+ # CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
+ # CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
+ # CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+ # CONFIG_INET6_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
+ # CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
+ # CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+@@ -345,7 +364,6 @@ CONFIG_IPV6=y
+ # 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
+
+@@ -420,6 +438,13 @@ CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_ATA_OVER_ETH is not set
+
+ #
++# Misc devices
++#
++# CONFIG_IBM_ASM is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++
++#
+ # ATA/ATAPI/MFM/RLL support
+ #
+ CONFIG_IDE=y
+@@ -464,6 +489,7 @@ CONFIG_BLK_DEV_ATIIXP=y
+ # CONFIG_BLK_DEV_CS5530 is not set
+ # CONFIG_BLK_DEV_HPT34X is not set
+ # CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
+ # CONFIG_BLK_DEV_SC1200 is not set
+ CONFIG_BLK_DEV_PIIX=y
+ # CONFIG_BLK_DEV_IT821X is not set
+@@ -487,6 +513,7 @@ CONFIG_IDEDMA_AUTO=y
+ #
+ # CONFIG_RAID_ATTRS is not set
+ CONFIG_SCSI=y
++CONFIG_SCSI_NETLINK=y
+ # CONFIG_SCSI_PROC_FS is not set
+
+ #
+@@ -508,12 +535,13 @@ CONFIG_SCSI_CONSTANTS=y
+ # CONFIG_SCSI_LOGGING is not set
+
+ #
+-# SCSI Transport Attributes
++# SCSI Transports
+ #
+ CONFIG_SCSI_SPI_ATTRS=y
+ CONFIG_SCSI_FC_ATTRS=y
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+ CONFIG_SCSI_SAS_ATTRS=y
++# CONFIG_SCSI_SAS_LIBSAS is not set
+
+ #
+ # SCSI low-level drivers
+@@ -532,29 +560,14 @@ CONFIG_AIC79XX_RESET_DELAY_MS=4000
+ # CONFIG_AIC79XX_DEBUG_ENABLE is not set
+ CONFIG_AIC79XX_DEBUG_MASK=0
+ # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
++# CONFIG_SCSI_AIC94XX is not set
++# CONFIG_SCSI_ARCMSR is not set
+ CONFIG_MEGARAID_NEWGEN=y
+ CONFIG_MEGARAID_MM=y
+ CONFIG_MEGARAID_MAILBOX=y
+ # CONFIG_MEGARAID_LEGACY is not set
+ CONFIG_MEGARAID_SAS=y
+-CONFIG_SCSI_SATA=y
+-CONFIG_SCSI_SATA_AHCI=y
+-CONFIG_SCSI_SATA_SVW=y
+-CONFIG_SCSI_ATA_PIIX=y
+-# CONFIG_SCSI_SATA_MV is not set
+-CONFIG_SCSI_SATA_NV=y
+-# CONFIG_SCSI_PDC_ADMA is not set
+ # CONFIG_SCSI_HPTIOP is not set
+-# CONFIG_SCSI_SATA_QSTOR is not set
+-# CONFIG_SCSI_SATA_PROMISE is not set
+-# CONFIG_SCSI_SATA_SX4 is not set
+-CONFIG_SCSI_SATA_SIL=y
+-# CONFIG_SCSI_SATA_SIL24 is not set
+-# CONFIG_SCSI_SATA_SIS is not set
+-# CONFIG_SCSI_SATA_ULI is not set
+-CONFIG_SCSI_SATA_VIA=y
+-# CONFIG_SCSI_SATA_VITESSE is not set
+-CONFIG_SCSI_SATA_INTEL_COMBINED=y
+ # CONFIG_SCSI_BUSLOGIC is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_EATA is not set
+@@ -563,21 +576,78 @@ CONFIG_SCSI_SATA_INTEL_COMBINED=y
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+ # CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_STEX is not set
+ # CONFIG_SCSI_SYM53C8XX_2 is not set
+ # CONFIG_SCSI_IPR is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_QLA_ISCSI 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
+
+ #
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++CONFIG_ATA=y
++CONFIG_SATA_AHCI=y
++CONFIG_SATA_SVW=y
++CONFIG_ATA_PIIX=y
++# CONFIG_SATA_MV is not set
++CONFIG_SATA_NV=y
++# CONFIG_PDC_ADMA is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SX4 is not set
++CONFIG_SATA_SIL=y
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_ULI is not set
++CONFIG_SATA_VIA=y
++# CONFIG_SATA_VITESSE is not set
++CONFIG_SATA_INTEL_COMBINED=y
++# CONFIG_PATA_ALI is not set
++# CONFIG_PATA_AMD is not set
++# CONFIG_PATA_ARTOP is not set
++# CONFIG_PATA_ATIIXP is not set
++# CONFIG_PATA_CMD64X is not set
++# CONFIG_PATA_CS5520 is not set
++# CONFIG_PATA_CS5530 is not set
++# CONFIG_PATA_CYPRESS is not set
++# CONFIG_PATA_EFAR is not set
++# CONFIG_ATA_GENERIC is not set
++# CONFIG_PATA_HPT366 is not set
++# CONFIG_PATA_HPT37X is not set
++# CONFIG_PATA_HPT3X2N is not set
++# CONFIG_PATA_HPT3X3 is not set
++# CONFIG_PATA_IT821X is not set
++# CONFIG_PATA_JMICRON is not set
++# CONFIG_PATA_TRIFLEX is not set
++# CONFIG_PATA_MPIIX is not set
++# CONFIG_PATA_OLDPIIX is not set
++# CONFIG_PATA_NETCELL is not set
++# CONFIG_PATA_NS87410 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_OPTIDMA is not set
++# CONFIG_PATA_PDC_OLD is not set
++# CONFIG_PATA_RADISYS is not set
++# CONFIG_PATA_RZ1000 is not set
++# CONFIG_PATA_SC1200 is not set
++# CONFIG_PATA_SERVERWORKS is not set
++# CONFIG_PATA_PDC2027X is not set
++# CONFIG_PATA_SIL680 is not set
++# CONFIG_PATA_SIS is not set
++# CONFIG_PATA_VIA is not set
++# CONFIG_PATA_WINBOND is not set
++
++#
+ # Multi-device support (RAID and LVM)
+ #
+ CONFIG_MD=y
+ # CONFIG_BLK_DEV_MD is not set
+ CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
+ # CONFIG_DM_CRYPT is not set
+ # CONFIG_DM_SNAPSHOT is not set
+ # CONFIG_DM_MIRROR is not set
+@@ -678,6 +748,7 @@ CONFIG_NET_PCI=y
+ # CONFIG_ADAPTEC_STARFIRE is not set
+ CONFIG_B44=y
+ CONFIG_FORCEDETH=y
++# CONFIG_FORCEDETH_NAPI is not set
+ # CONFIG_DGRS is not set
+ # CONFIG_EEPRO100 is not set
+ CONFIG_E100=y
+@@ -714,6 +785,7 @@ CONFIG_E1000=y
+ # CONFIG_VIA_VELOCITY is not set
+ CONFIG_TIGON3=y
+ CONFIG_BNX2=y
++# CONFIG_QLA3XXX is not set
+
+ #
+ # Ethernet (10000 Mbit)
+@@ -764,6 +836,7 @@ CONFIG_NET_POLL_CONTROLLER=y
+ # Input device support
+ #
+ CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
+
+ #
+ # Userland interfaces
+@@ -786,6 +859,7 @@ CONFIG_KEYBOARD_ATKBD=y
+ # CONFIG_KEYBOARD_LKKBD is not set
+ # CONFIG_KEYBOARD_XTKBD is not set
+ # CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
+ CONFIG_INPUT_MOUSE=y
+ CONFIG_MOUSE_PS2=y
+ # CONFIG_MOUSE_SERIAL is not set
+@@ -941,6 +1015,7 @@ CONFIG_I2C_ISA=m
+ #
+ # Dallas's 1-wire bus
+ #
++# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -953,6 +1028,7 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_ADM1026 is not set
+ # CONFIG_SENSORS_ADM1031 is not set
+ # CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_K8TEMP is not set
+ # CONFIG_SENSORS_ASB100 is not set
+ # CONFIG_SENSORS_ATXP1 is not set
+ # CONFIG_SENSORS_DS1621 is not set
+@@ -979,6 +1055,7 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_SMSC47M192 is not set
+ CONFIG_SENSORS_SMSC47B397=m
+ # CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_SENSORS_VT8231 is not set
+ # CONFIG_SENSORS_W83781D is not set
+ # CONFIG_SENSORS_W83791D is not set
+@@ -990,15 +1067,9 @@ CONFIG_SENSORS_SMSC47B397=m
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+
+ #
+-# Misc devices
+-#
+-# CONFIG_IBM_ASM is not set
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -1036,6 +1107,7 @@ CONFIG_SOUND=y
+ # Open Sound System
+ #
+ CONFIG_SOUND_PRIME=y
++CONFIG_OSS_OBSOLETE_DRIVER=y
+ # CONFIG_SOUND_BT878 is not set
+ # CONFIG_SOUND_EMU10K1 is not set
+ # CONFIG_SOUND_FUSION is not set
+@@ -1046,7 +1118,6 @@ CONFIG_SOUND_ICH=y
+ # CONFIG_SOUND_MSNDPIN is not set
+ # CONFIG_SOUND_VIA82CXXX is not set
+ # CONFIG_SOUND_OSS is not set
+-# CONFIG_SOUND_TVMIXER is not set
+
+ #
+ # USB support
+@@ -1104,6 +1175,7 @@ CONFIG_USB_STORAGE=y
+ # CONFIG_USB_STORAGE_SDDR55 is not set
+ # CONFIG_USB_STORAGE_JUMPSHOT is not set
+ # CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
+ # CONFIG_USB_LIBUSUAL is not set
+
+ #
+@@ -1157,6 +1229,7 @@ CONFIG_USB_MON=y
+ #
+ # CONFIG_USB_EMI62 is not set
+ # CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
+ # CONFIG_USB_AUERSWALD is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+@@ -1164,12 +1237,13 @@ CONFIG_USB_MON=y
+ # CONFIG_USB_LED is not set
+ # CONFIG_USB_CYPRESS_CY7C63 is not set
+ # CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_PHIDGET is not set
+ # CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
+ # CONFIG_USB_APPLEDISPLAY is not set
+ # CONFIG_USB_SISUSBVGA is not set
+ # CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
+ # CONFIG_USB_TEST is not set
+
+ #
+@@ -1203,7 +1277,6 @@ CONFIG_USB_MON=y
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+-# CONFIG_IPATH_CORE is not set
+
+ #
+ # EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+@@ -1247,6 +1320,7 @@ CONFIG_EXT3_FS=y
+ CONFIG_EXT3_FS_XATTR=y
+ CONFIG_EXT3_FS_POSIX_ACL=y
+ # CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+@@ -1259,6 +1333,7 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
+ # CONFIG_JFS_FS is not set
+ CONFIG_FS_POSIX_ACL=y
+ # CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+@@ -1269,6 +1344,7 @@ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+ CONFIG_AUTOFS4_FS=y
+ # CONFIG_FUSE_FS is not set
++CONFIG_GENERIC_ACL=y
+
+ #
+ # CD-ROM/DVD Filesystems
+@@ -1293,8 +1369,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+ #
+ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
+ CONFIG_HUGETLBFS=y
+ CONFIG_HUGETLB_PAGE=y
+ CONFIG_RAMFS=y
+@@ -1407,6 +1485,7 @@ CONFIG_KPROBES=y
+ #
+ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
+ CONFIG_MAGIC_SYSRQ=y
+ CONFIG_UNUSED_SYMBOLS=y
+ CONFIG_DEBUG_KERNEL=y
+@@ -1427,11 +1506,14 @@ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_DEBUG_INFO is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
+ # CONFIG_FRAME_POINTER is not set
+ CONFIG_UNWIND_INFO=y
+ CONFIG_STACK_UNWIND=y
+ # CONFIG_FORCED_INLINING is not set
++# CONFIG_HEADERS_CHECK is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
+ # CONFIG_DEBUG_RODATA is not set
+ # CONFIG_IOMMU_DEBUG is not set
+ CONFIG_DEBUG_STACKOVERFLOW=y
+@@ -1449,10 +1531,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y
+ # CONFIG_CRYPTO is not set
+
+ #
+-# Hardware crypto devices
+-#
+-
+-#
+ # Library routines
+ #
+ # CONFIG_CRC_CCITT is not set
+diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
+index 3bf58af..396d3c1 100644
+--- a/arch/x86_64/ia32/ia32_aout.c
++++ b/arch/x86_64/ia32/ia32_aout.c
+@@ -333,7 +333,8 @@ static int load_aout_binary(struct linux
+ return error;
+ }
+
+- error = bprm->file->f_op->read(bprm->file, (char *)text_addr,
++ error = bprm->file->f_op->read(bprm->file,
++ (char __user *)text_addr,
+ ex.a_text+ex.a_data, &pos);
+ if ((signed long)error < 0) {
+ send_sig(SIGKILL, current, 0);
+@@ -366,7 +367,8 @@ static int load_aout_binary(struct linux
+ down_write(¤t->mm->mmap_sem);
+ do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
+ up_write(¤t->mm->mmap_sem);
+- bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
++ bprm->file->f_op->read(bprm->file,
++ (char __user *)N_TXTADDR(ex),
+ ex.a_text+ex.a_data, &pos);
+ flush_icache_range((unsigned long) N_TXTADDR(ex),
+ (unsigned long) N_TXTADDR(ex) +
+@@ -477,7 +479,7 @@ static int load_aout_library(struct file
+ do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
+ up_write(¤t->mm->mmap_sem);
+
+- file->f_op->read(file, (char *)start_addr,
++ file->f_op->read(file, (char __user *)start_addr,
+ ex.a_text + ex.a_data, &pos);
+ flush_icache_range((unsigned long) start_addr,
+ (unsigned long) start_addr + ex.a_text + ex.a_data);
+diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
+index 2fd5a67..82ef182 100644
+--- a/arch/x86_64/ia32/ia32_binfmt.c
++++ b/arch/x86_64/ia32/ia32_binfmt.c
+@@ -6,7 +6,6 @@
+ * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
+ */
+ #include <linux/types.h>
+-#include <linux/config.h>
+ #include <linux/stddef.h>
+ #include <linux/rwsem.h>
+ #include <linux/sched.h>
+diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
+index 25e5ca2..0e0a266 100644
+--- a/arch/x86_64/ia32/ia32_signal.c
++++ b/arch/x86_64/ia32/ia32_signal.c
+@@ -113,25 +113,19 @@ int copy_siginfo_from_user32(siginfo_t *
+ }
+
+ asmlinkage long
+-sys32_sigsuspend(int history0, int history1, old_sigset_t mask,
+- struct pt_regs *regs)
++sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
+ {
+- sigset_t saveset;
+-
+ mask &= _BLOCKABLE;
+ spin_lock_irq(¤t->sighand->siglock);
+- saveset = current->blocked;
++ current->saved_sigmask = current->blocked;
+ siginitset(¤t->blocked, mask);
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+
+- regs->rax = -EINTR;
+- while (1) {
+- current->state = TASK_INTERRUPTIBLE;
+- schedule();
+- if (do_signal(regs, &saveset))
+- return -EINTR;
+- }
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ set_thread_flag(TIF_RESTORE_SIGMASK);
++ return -ERESTARTNOHAND;
+ }
+
+ asmlinkage long
+@@ -437,15 +431,7 @@ int ia32_setup_frame(int sig, struct k_s
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+- {
+- struct exec_domain *ed = current_thread_info()->exec_domain;
+- err |= __put_user((ed
+- && ed->signal_invmap
+- && sig < 32
+- ? ed->signal_invmap[sig]
+- : sig),
+- &frame->sig);
+- }
++ err |= __put_user(sig, &frame->sig);
+ if (err)
+ goto give_sigsegv;
+
+@@ -492,6 +478,11 @@ int ia32_setup_frame(int sig, struct k_s
+ regs->rsp = (unsigned long) frame;
+ regs->rip = (unsigned long) ka->sa.sa_handler;
+
++ /* Make -mregparm=3 work */
++ regs->rax = sig;
++ regs->rdx = 0;
++ regs->rcx = 0;
++
+ asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
+ asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
+
+@@ -499,20 +490,20 @@ int ia32_setup_frame(int sig, struct k_s
+ regs->ss = __USER32_DS;
+
+ set_fs(USER_DS);
+- regs->eflags &= ~TF_MASK;
+- if (test_thread_flag(TIF_SINGLESTEP))
+- ptrace_notify(SIGTRAP);
++ regs->eflags &= ~TF_MASK;
++ if (test_thread_flag(TIF_SINGLESTEP))
++ ptrace_notify(SIGTRAP);
+
+ #if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->rip, frame->pretcode);
+ #endif
+
+- return 1;
++ return 0;
+
+ give_sigsegv:
+ force_sigsegv(sig, current);
+- return 0;
++ return -EFAULT;
+ }
+
+ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+@@ -588,6 +579,11 @@ int ia32_setup_rt_frame(int sig, struct
+ regs->rsp = (unsigned long) frame;
+ regs->rip = (unsigned long) ka->sa.sa_handler;
+
++ /* Make -mregparm=3 work */
++ regs->rax = sig;
++ regs->rdx = (unsigned long) &frame->info;
++ regs->rcx = (unsigned long) &frame->uc;
++
+ asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
+ asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
+
+@@ -595,18 +591,18 @@ int ia32_setup_rt_frame(int sig, struct
+ regs->ss = __USER32_DS;
+
+ set_fs(USER_DS);
+- regs->eflags &= ~TF_MASK;
+- if (test_thread_flag(TIF_SINGLESTEP))
+- ptrace_notify(SIGTRAP);
++ regs->eflags &= ~TF_MASK;
++ if (test_thread_flag(TIF_SINGLESTEP))
++ ptrace_notify(SIGTRAP);
+
+ #if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->rip, frame->pretcode);
+ #endif
+
+- return 1;
++ return 0;
+
+ give_sigsegv:
+ force_sigsegv(sig, current);
+- return 0;
++ return -EFAULT;
+ }
+diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
+index 5d4a7d1..b4aa875 100644
+--- a/arch/x86_64/ia32/ia32entry.S
++++ b/arch/x86_64/ia32/ia32entry.S
+@@ -71,6 +71,7 @@
+ */
+ ENTRY(ia32_sysenter_target)
+ CFI_STARTPROC32 simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,0
+ CFI_REGISTER rsp,rbp
+ swapgs
+@@ -186,6 +187,7 @@ ENDPROC(ia32_sysenter_target)
+ */
+ ENTRY(ia32_cstar_target)
+ CFI_STARTPROC32 simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,PDA_STACKOFFSET
+ CFI_REGISTER rip,rcx
+ /*CFI_REGISTER rflags,r11*/
+@@ -293,6 +295,7 @@ ia32_badarg:
+
+ ENTRY(ia32_syscall)
+ CFI_STARTPROC simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,SS+8-RIP
+ /*CFI_REL_OFFSET ss,SS-RIP*/
+ CFI_REL_OFFSET rsp,RSP-RIP
+@@ -370,6 +373,7 @@ ENTRY(ia32_ptregs_common)
+ popq %r11
+ CFI_ENDPROC
+ CFI_STARTPROC32 simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,SS+8-ARGOFFSET
+ CFI_REL_OFFSET rax,RAX-ARGOFFSET
+ CFI_REL_OFFSET rcx,RCX-ARGOFFSET
+@@ -703,8 +707,8 @@ ia32_sys_call_table:
+ .quad sys_readlinkat /* 305 */
+ .quad sys_fchmodat
+ .quad sys_faccessat
+- .quad quiet_ni_syscall /* pselect6 for now */
+- .quad quiet_ni_syscall /* ppoll for now */
++ .quad compat_sys_pselect6
++ .quad compat_sys_ppoll
+ .quad sys_unshare /* 310 */
+ .quad compat_sys_set_robust_list
+ .quad compat_sys_get_robust_list
+@@ -713,4 +717,5 @@ ia32_sys_call_table:
+ .quad sys_tee
+ .quad compat_sys_vmsplice
+ .quad compat_sys_move_pages
++ .quad sys_getcpu
+ ia32_syscall_end:
+diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
+index 659c072..3a7561d 100644
+--- a/arch/x86_64/ia32/ptrace32.c
++++ b/arch/x86_64/ia32/ptrace32.c
+@@ -117,6 +117,10 @@ static int putreg32(struct task_struct *
+ if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
+ return -EIO;
+ child->thread.debugreg7 = val;
++ if (val)
++ set_tsk_thread_flag(child, TIF_DEBUG);
++ else
++ clear_tsk_thread_flag(child, TIF_DEBUG);
+ break;
+
+ default:
+@@ -201,9 +205,9 @@ static int getreg32(struct task_struct *
+ static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
+ {
+ int ret;
+- compat_siginfo_t *si32 = (compat_siginfo_t *)compat_ptr(data);
++ compat_siginfo_t __user *si32 = compat_ptr(data);
+ siginfo_t ssi;
+- siginfo_t *si = compat_alloc_user_space(sizeof(siginfo_t));
++ siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
+ if (request == PTRACE_SETSIGINFO) {
+ memset(&ssi, 0, sizeof(siginfo_t));
+ ret = copy_siginfo_from_user32(&ssi, si32);
+@@ -371,8 +375,10 @@ asmlinkage long sys32_ptrace(long reques
+ ret = -EIO;
+ if (!access_ok(VERIFY_READ, u, sizeof(*u)))
+ break;
+- /* no checking to be bug-to-bug compatible with i386 */
+- __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
++ /* no checking to be bug-to-bug compatible with i386. */
++ /* but silence warning */
++ if (__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)))
++ ;
+ set_stopped_child_used_math(child);
+ child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
+ ret = 0;
+diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
+index 9c13099..c9bac3a 100644
+--- a/arch/x86_64/ia32/sys_ia32.c
++++ b/arch/x86_64/ia32/sys_ia32.c
+@@ -60,6 +60,7 @@
+ #include <linux/highuid.h>
+ #include <linux/vmalloc.h>
+ #include <linux/fsnotify.h>
++#include <linux/sysctl.h>
+ #include <asm/mman.h>
+ #include <asm/types.h>
+ #include <asm/uaccess.h>
+@@ -75,6 +76,8 @@
+
+ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
+ {
++ compat_ino_t ino;
++
+ typeof(ubuf->st_uid) uid = 0;
+ typeof(ubuf->st_gid) gid = 0;
+ SET_UID(uid, kbuf->uid);
+@@ -83,9 +86,12 @@ int cp_compat_stat(struct kstat *kbuf, s
+ return -EOVERFLOW;
+ if (kbuf->size >= 0x7fffffff)
+ return -EOVERFLOW;
++ ino = kbuf->ino;
++ if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
++ return -EOVERFLOW;
+ if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
+ __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
+- __put_user (kbuf->ino, &ubuf->st_ino) ||
++ __put_user (ino, &ubuf->st_ino) ||
+ __put_user (kbuf->mode, &ubuf->st_mode) ||
+ __put_user (kbuf->nlink, &ubuf->st_nlink) ||
+ __put_user (uid, &ubuf->st_uid) ||
+@@ -389,7 +395,9 @@ sys32_rt_sigprocmask(int how, compat_sig
+ }
+ }
+ set_fs (KERNEL_DS);
+- ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL,
++ ret = sys_rt_sigprocmask(how,
++ set ? (sigset_t __user *)&s : NULL,
++ oset ? (sigset_t __user *)&s : NULL,
+ sigsetsize);
+ set_fs (old_fs);
+ if (ret) return ret;
+@@ -541,7 +549,7 @@ sys32_sysinfo(struct sysinfo32 __user *i
+ int bitcount = 0;
+
+ set_fs (KERNEL_DS);
+- ret = sys_sysinfo(&s);
++ ret = sys_sysinfo((struct sysinfo __user *)&s);
+ set_fs (old_fs);
+
+ /* Check to see if any memory value is too large for 32-bit and scale
+@@ -589,7 +597,7 @@ sys32_sched_rr_get_interval(compat_pid_t
+ mm_segment_t old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+- ret = sys_sched_rr_get_interval(pid, &t);
++ ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
+ set_fs (old_fs);
+ if (put_compat_timespec(&t, interval))
+ return -EFAULT;
+@@ -605,7 +613,7 @@ sys32_rt_sigpending(compat_sigset_t __us
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+- ret = sys_rt_sigpending(&s, sigsetsize);
++ ret = sys_rt_sigpending((sigset_t __user *)&s, sigsetsize);
+ set_fs (old_fs);
+ if (!ret) {
+ switch (_NSIG_WORDS) {
+@@ -630,7 +638,7 @@ sys32_rt_sigqueueinfo(int pid, int sig,
+ if (copy_siginfo_from_user32(&info, uinfo))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+- ret = sys_rt_sigqueueinfo(pid, sig, &info);
++ ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
+ set_fs (old_fs);
+ return ret;
+ }
+@@ -645,7 +653,7 @@ sys32_pause(void)
+ }
+
+
+-#ifdef CONFIG_SYSCTL
++#ifdef CONFIG_SYSCTL_SYSCALL
+ struct sysctl_ia32 {
+ unsigned int name;
+ int nlen;
+@@ -666,9 +674,6 @@ sys32_sysctl(struct sysctl_ia32 __user *
+ size_t oldlen;
+ int __user *namep;
+ long ret;
+- extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
+- void *newval, size_t newlen);
+-
+
+ if (copy_from_user(&a32, args32, sizeof (a32)))
+ return -EFAULT;
+@@ -692,7 +697,8 @@ sys32_sysctl(struct sysctl_ia32 __user *
+
+ set_fs(KERNEL_DS);
+ lock_kernel();
+- ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen);
++ ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *)&oldlen,
++ newvalp, (size_t) a32.newlen);
+ unlock_kernel();
+ set_fs(old_fs);
+
+@@ -743,7 +749,8 @@ sys32_sendfile(int out_fd, int in_fd, co
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+- ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
++ ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
++ count);
+ set_fs(old_fs);
+
+ if (offset && put_user(of, offset))
+@@ -778,36 +785,40 @@ asmlinkage long sys32_mmap2(unsigned lon
+
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+- int error;
++ int err;
+
+ if (!name)
+ return -EFAULT;
+- if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
++ if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
+ return -EFAULT;
+
+ down_read(&uts_sem);
+-
+- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+- __put_user(0,name->sysname+__OLD_UTS_LEN);
+- __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+- __put_user(0,name->nodename+__OLD_UTS_LEN);
+- __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+- __put_user(0,name->release+__OLD_UTS_LEN);
+- __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+- __put_user(0,name->version+__OLD_UTS_LEN);
+- {
+- char *arch = "x86_64";
+- if (personality(current->personality) == PER_LINUX32)
+- arch = "i686";
++
++ err = __copy_to_user(&name->sysname,&utsname()->sysname,
++ __OLD_UTS_LEN);
++ err |= __put_user(0,name->sysname+__OLD_UTS_LEN);
++ err |= __copy_to_user(&name->nodename,&utsname()->nodename,
++ __OLD_UTS_LEN);
++ err |= __put_user(0,name->nodename+__OLD_UTS_LEN);
++ err |= __copy_to_user(&name->release,&utsname()->release,
++ __OLD_UTS_LEN);
++ err |= __put_user(0,name->release+__OLD_UTS_LEN);
++ err |= __copy_to_user(&name->version,&utsname()->version,
++ __OLD_UTS_LEN);
++ err |= __put_user(0,name->version+__OLD_UTS_LEN);
++ {
++ char *arch = "x86_64";
++ if (personality(current->personality) == PER_LINUX32)
++ arch = "i686";
+
+- __copy_to_user(&name->machine,arch,strlen(arch)+1);
+- }
+-
+- up_read(&uts_sem);
+-
+- error = error ? -EFAULT : 0;
+-
+- return error;
++ err |= __copy_to_user(&name->machine, arch, strlen(arch)+1);
++ }
++
++ up_read(&uts_sem);
++
++ err = err ? -EFAULT : 0;
++
++ return err;
+ }
+
+ long sys32_uname(struct old_utsname __user * name)
+@@ -816,7 +827,7 @@ long sys32_uname(struct old_utsname __us
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+- err=copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ if (personality(current->personality) == PER_LINUX32)
+ err |= copy_to_user(&name->machine, "i686", 5);
+@@ -831,7 +842,7 @@ long sys32_ustat(unsigned dev, struct us
+
+ seg = get_fs();
+ set_fs(KERNEL_DS);
+- ret = sys_ustat(dev,&u);
++ ret = sys_ustat(dev, (struct ustat __user *)&u);
+ set_fs(seg);
+ if (ret >= 0) {
+ if (!access_ok(VERIFY_WRITE,u32p,sizeof(struct ustat32)) ||
+diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
+index b5aaeaf..3c7cbff 100644
+--- a/arch/x86_64/kernel/Makefile
++++ b/arch/x86_64/kernel/Makefile
+@@ -11,7 +11,7 @@ obj-y := process.o signal.o entry.o trap
+ pci-dma.o pci-nommu.o alternative.o
+
+ obj-$(CONFIG_STACKTRACE) += stacktrace.o
+-obj-$(CONFIG_X86_MCE) += mce.o
++obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o
+ obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o
+ obj-$(CONFIG_X86_MCE_AMD) += mce_amd.o
+ obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/
+@@ -20,8 +20,8 @@ obj-$(CONFIG_X86_MSR) += msr.o
+ obj-$(CONFIG_MICROCODE) += microcode.o
+ obj-$(CONFIG_X86_CPUID) += cpuid.o
+ obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o
+-obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
+-obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o \
++obj-y += apic.o nmi.o
++obj-y += 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_CRASH_DUMP) += crash_dump.o
+@@ -39,12 +39,14 @@ obj-$(CONFIG_K8_NB) += k8.o
+ obj-$(CONFIG_AUDIT) += audit.o
+
+ obj-$(CONFIG_MODULES) += module.o
++obj-$(CONFIG_PCI) += early-quirks.o
+
+ obj-y += topology.o
+ obj-y += intel_cacheinfo.o
+
+ CFLAGS_vsyscall.o := $(PROFILING) -g0
+
++therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o
+ bootflag-y += ../../i386/kernel/bootflag.o
+ cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o
+ topology-y += ../../i386/kernel/topology.o
+@@ -54,4 +56,3 @@ quirks-y += ../../i386/kernel/quirks.o
+ i8237-y += ../../i386/kernel/i8237.o
+ msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o
+ alternative-y += ../../i386/kernel/alternative.o
+-
+diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
+index 58af8e7..b487396 100644
+--- a/arch/x86_64/kernel/aperture.c
++++ b/arch/x86_64/kernel/aperture.c
+@@ -17,6 +17,7 @@
+ #include <linux/pci_ids.h>
+ #include <linux/pci.h>
+ #include <linux/bitops.h>
++#include <linux/ioport.h>
+ #include <asm/e820.h>
+ #include <asm/io.h>
+ #include <asm/proto.h>
+@@ -33,6 +34,18 @@ int fallback_aper_force __initdata = 0;
+
+ int fix_aperture __initdata = 1;
+
++static struct resource gart_resource = {
++ .name = "GART",
++ .flags = IORESOURCE_MEM,
++};
++
++static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
++{
++ gart_resource.start = aper_base;
++ gart_resource.end = aper_base + aper_size - 1;
++ insert_resource(&iomem_resource, &gart_resource);
++}
++
+ /* This code runs before the PCI subsystem is initialized, so just
+ access the northbridge directly. */
+
+@@ -48,7 +61,7 @@ static u32 __init allocate_aperture(void
+
+ /*
+ * Aperture has to be naturally aligned. This means an 2GB aperture won't
+- * have much chances to find a place in the lower 4GB of memory.
++ * have much chance of finding a place in the lower 4GB of memory.
+ * Unfortunately we cannot move it up because that would make the
+ * IOMMU useless.
+ */
+@@ -62,6 +75,7 @@ static u32 __init allocate_aperture(void
+ }
+ printk("Mapping aperture over %d KB of RAM @ %lx\n",
+ aper_size >> 10, __pa(p));
++ insert_aperture_resource((u32)__pa(p), aper_size);
+ return (u32)__pa(p);
+ }
+
+@@ -198,7 +212,7 @@ void __init iommu_hole_init(void)
+ u64 aper_base, last_aper_base = 0;
+ int valid_agp = 0;
+
+- if (iommu_aperture_disabled || !fix_aperture)
++ if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
+ return;
+
+ printk("Checking aperture...\n");
+@@ -233,8 +247,13 @@ void __init iommu_hole_init(void)
+ last_aper_base = aper_base;
+ }
+
+- if (!fix && !fallback_aper_force)
++ if (!fix && !fallback_aper_force) {
++ if (last_aper_base) {
++ unsigned long n = (32 * 1024 * 1024) << last_aper_order;
++ insert_aperture_resource((u32)last_aper_base, n);
++ }
+ return;
++ }
+
+ if (!fallback_aper_force)
+ aper_alloc = search_agp_bridge(&aper_order, &valid_agp);
+diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
+index 2b8cef0..4d9d5ed 100644
+--- a/arch/x86_64/kernel/apic.c
++++ b/arch/x86_64/kernel/apic.c
+@@ -36,7 +36,9 @@
+ #include <asm/idle.h>
+ #include <asm/proto.h>
+ #include <asm/timex.h>
++#include <asm/apic.h>
+
++int apic_mapped;
+ int apic_verbosity;
+ int apic_runs_main_timer;
+ int apic_calibrate_pmtmr __initdata;
+@@ -136,72 +138,40 @@ void clear_local_APIC(void)
+ apic_read(APIC_ESR);
+ }
+
+-void __init connect_bsp_APIC(void)
+-{
+- if (pic_mode) {
+- /*
+- * Do not trust the local APIC being empty at bootup.
+- */
+- clear_local_APIC();
+- /*
+- * PIC mode, enable APIC mode in the IMCR, i.e.
+- * connect BSP's local APIC to INT and NMI lines.
+- */
+- apic_printk(APIC_VERBOSE, "leaving PIC mode, enabling APIC mode.\n");
+- outb(0x70, 0x22);
+- outb(0x01, 0x23);
+- }
+-}
+-
+ void disconnect_bsp_APIC(int virt_wire_setup)
+ {
+- if (pic_mode) {
+- /*
+- * Put the board back into PIC mode (has an effect
+- * only on certain older boards). Note that APIC
+- * interrupts, including IPIs, won't work beyond
+- * this point! The only exception are INIT IPIs.
+- */
+- apic_printk(APIC_QUIET, "disabling APIC mode, entering PIC mode.\n");
+- 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(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(APIC_LVT0, value);
+- }
+- else {
+- /* Disable LVT0 */
+- apic_write(APIC_LVT0, APIC_LVT_MASKED);
+- }
++ /* Go back to Virtual Wire compatibility mode */
++ unsigned long value;
+
+- /* For LVT1 make it edge triggered, active high, nmi and enabled */
+- value = apic_read(APIC_LVT1);
+- value &= ~(
+- APIC_MODE_MASK | APIC_SEND_PENDING |
++ /* 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(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);
++ 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(APIC_LVT1, value);
++ value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
++ apic_write(APIC_LVT0, value);
++ } else {
++ /* Disable LVT0 */
++ apic_write(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(APIC_LVT1, value);
+ }
+
+ void disable_local_APIC(void)
+@@ -297,8 +267,6 @@ void __init sync_Arb_IDs(void)
+ | APIC_DM_INIT);
+ }
+
+-extern void __error_in_apic_c (void);
+-
+ /*
+ * An initial setup of the virtual wire mode.
+ */
+@@ -345,8 +313,7 @@ void __cpuinit setup_local_APIC (void)
+
+ value = apic_read(APIC_LVR);
+
+- if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
+- __error_in_apic_c();
++ BUILD_BUG_ON((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f);
+
+ /*
+ * Double-check whether this APIC is really registered.
+@@ -399,32 +366,8 @@ void __cpuinit setup_local_APIC (void)
+ */
+ value |= APIC_SPIV_APIC_ENABLED;
+
+- /*
+- * Some unknown Intel IO/APIC (or APIC) errata is biting us with
+- * certain networking cards. If high frequency interrupts are
+- * happening on a particular IOAPIC pin, plus the IOAPIC routing
+- * entry is masked/unmasked at a high rate as well then sooner or
+- * later IOAPIC line gets 'stuck', no more interrupts are received
+- * from the device. If focus CPU is disabled then the hang goes
+- * away, oh well :-(
+- *
+- * [ This bug can be reproduced easily with a level-triggered
+- * PCI Ne2000 networking cards and PII/PIII processors, dual
+- * BX chipset. ]
+- */
+- /*
+- * Actually disabling the focus CPU check just makes the hang less
+- * frequent as it makes the interrupt distributon model be more
+- * like LRU than MRU (the short-term load is more even across CPUs).
+- * See also the comment in end_level_ioapic_irq(). --macro
+- */
+-#if 1
+- /* Enable focus processor (bit==0) */
+- value &= ~APIC_SPIV_FOCUS_DISABLED;
+-#else
+- /* Disable focus processor (bit==1) */
+- value |= APIC_SPIV_FOCUS_DISABLED;
+-#endif
++ /* We always use processor focus */
++
+ /*
+ * Set spurious IRQ vector
+ */
+@@ -442,7 +385,7 @@ void __cpuinit setup_local_APIC (void)
+ * TODO: set up through-local-APIC from through-I/O-APIC? --macro
+ */
+ value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
+- if (!smp_processor_id() && (pic_mode || !value)) {
++ if (!smp_processor_id() && !value) {
+ value = APIC_DM_EXTINT;
+ apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
+ } else {
+@@ -479,8 +422,7 @@ void __cpuinit setup_local_APIC (void)
+ }
+
+ nmi_watchdog_default();
+- if (nmi_watchdog == NMI_LOCAL_APIC)
+- setup_apic_nmi_watchdog();
++ setup_apic_nmi_watchdog(NULL);
+ apic_pm_activate();
+ }
+
+@@ -527,8 +469,7 @@ static int lapic_suspend(struct sys_devi
+ apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
+ apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
+ apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
+- local_save_flags(flags);
+- local_irq_disable();
++ local_irq_save(flags);
+ disable_local_APIC();
+ local_irq_restore(flags);
+ return 0;
+@@ -606,18 +547,24 @@ static void apic_pm_activate(void) { }
+
+ static int __init apic_set_verbosity(char *str)
+ {
++ if (str == NULL) {
++ skip_ioapic_setup = 0;
++ ioapic_force = 1;
++ return 0;
++ }
+ if (strcmp("debug", str) == 0)
+ apic_verbosity = APIC_DEBUG;
+ else if (strcmp("verbose", str) == 0)
+ apic_verbosity = APIC_VERBOSE;
+- else
++ else {
+ printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+- " use apic=verbose or apic=debug", str);
++ " use apic=verbose or apic=debug\n", str);
++ return -EINVAL;
++ }
+
+- return 1;
++ return 0;
+ }
+-
+-__setup("apic=", apic_set_verbosity);
++early_param("apic", apic_set_verbosity);
+
+ /*
+ * Detect and enable local APICs on non-SMP boards.
+@@ -654,6 +601,7 @@ void __init init_apic_mappings(void)
+ apic_phys = mp_lapic_addr;
+
+ set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
++ apic_mapped = 1;
+ apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
+
+ /*
+@@ -662,7 +610,6 @@ void __init init_apic_mappings(void)
+ */
+ boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+
+-#ifdef CONFIG_X86_IO_APIC
+ {
+ unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+ int i;
+@@ -680,7 +627,6 @@ void __init init_apic_mappings(void)
+ idx++;
+ }
+ }
+-#endif
+ }
+
+ /*
+@@ -939,19 +885,19 @@ void setup_APIC_extened_lvt(unsigned cha
+ * value into /proc/profile.
+ */
+
+-void smp_local_timer_interrupt(struct pt_regs *regs)
++void smp_local_timer_interrupt(void)
+ {
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ #ifdef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+ if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
+- main_timer_handler(regs);
++ main_timer_handler();
+ /*
+ * We take the 'long' return path, and there every subsystem
+ * grabs the appropriate locks (kernel lock/ irq lock).
+ *
+- * we might want to decouple profiling from the 'long path',
++ * We might want to decouple profiling from the 'long path',
+ * and do the profiling totally in assembly.
+ *
+ * Currently this isn't too much of an issue (performance wise),
+@@ -969,6 +915,8 @@ void smp_local_timer_interrupt(struct pt
+ */
+ void smp_apic_timer_interrupt(struct pt_regs *regs)
+ {
++ struct pt_regs *old_regs = set_irq_regs(regs);
++
+ /*
+ * the NMI deadlock-detector uses this.
+ */
+@@ -986,8 +934,9 @@ void smp_apic_timer_interrupt(struct pt_
+ */
+ exit_idle();
+ irq_enter();
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ /*
+@@ -1123,19 +1072,15 @@ int __init APIC_init_uniprocessor (void)
+
+ verify_local_APIC();
+
+- connect_bsp_APIC();
+-
+ phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
+ apic_write(APIC_ID, SET_APIC_ID(boot_cpu_id));
+
+ setup_local_APIC();
+
+-#ifdef CONFIG_X86_IO_APIC
+ if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
+- setup_IO_APIC();
++ setup_IO_APIC();
+ else
+ nr_ioapics = 0;
+-#endif
+ setup_boot_APIC_clock();
+ check_nmi_watchdog();
+ return 0;
+@@ -1144,14 +1089,17 @@ int __init APIC_init_uniprocessor (void)
+ static __init int setup_disableapic(char *str)
+ {
+ disable_apic = 1;
+- return 1;
+-}
++ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
++ return 0;
++}
++early_param("disableapic", setup_disableapic);
+
++/* same as disableapic, for compatibility */
+ static __init int setup_nolapic(char *str)
+ {
+- disable_apic = 1;
+- return 1;
++ return setup_disableapic(str);
+ }
++early_param("nolapic", setup_nolapic);
+
+ static __init int setup_noapictimer(char *str)
+ {
+@@ -1184,11 +1132,5 @@ static __init int setup_apicpmtimer(char
+ }
+ __setup("apicpmtimer", setup_apicpmtimer);
+
+-/* dummy parsing: see setup.c */
+-
+-__setup("disableapic", setup_disableapic);
+-__setup("nolapic", setup_nolapic); /* same as disableapic, for compatibility */
+-
+ __setup("noapictimer", setup_noapictimer);
+
+-/* no "lapic" flag - we only use the lapic when the BIOS tells us so. */
+diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
+index d8d5750..3525f88 100644
+--- a/arch/x86_64/kernel/crash.c
++++ b/arch/x86_64/kernel/crash.c
+@@ -23,6 +23,7 @@
+ #include <asm/nmi.h>
+ #include <asm/hw_irq.h>
+ #include <asm/mach_apic.h>
++#include <asm/kdebug.h>
+
+ /* This keeps a track of which one is crashing cpu. */
+ static int crashing_cpu;
+@@ -68,7 +69,7 @@ static void crash_save_this_cpu(struct p
+ * 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.
++ * all of that, no need to invent something new.
+ */
+
+ buf = (u32*)per_cpu_ptr(crash_notes, cpu);
+@@ -95,15 +96,25 @@ static void crash_save_self(struct pt_re
+ #ifdef CONFIG_SMP
+ static atomic_t waiting_for_crash_ipi;
+
+-static int crash_nmi_callback(struct pt_regs *regs, int cpu)
++static int crash_nmi_callback(struct notifier_block *self,
++ unsigned long val, void *data)
+ {
++ struct pt_regs *regs;
++ int cpu;
++
++ if (val != DIE_NMI_IPI)
++ return NOTIFY_OK;
++
++ regs = ((struct die_args *)data)->regs;
++ cpu = raw_smp_processor_id();
++
+ /*
+ * 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;
++ return NOTIFY_STOP;
+ local_irq_disable();
+
+ crash_save_this_cpu(regs, cpu);
+@@ -127,12 +138,17 @@ static void smp_send_nmi_allbutself(void
+ * cpu hotplug shouldn't matter.
+ */
+
++static struct notifier_block crash_nmi_nb = {
++ .notifier_call = crash_nmi_callback,
++};
++
+ static void nmi_shootdown_cpus(void)
+ {
+ unsigned long msecs;
+
+ atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+- set_nmi_callback(crash_nmi_callback);
++ if (register_die_notifier(&crash_nmi_nb))
++ return; /* return what? */
+
+ /*
+ * Ensure the new callback function is set before sending
+@@ -178,9 +194,7 @@ void machine_crash_shutdown(struct pt_re
+ if(cpu_has_apic)
+ disable_local_APIC();
+
+-#if defined(CONFIG_X86_IO_APIC)
+ disable_IO_APIC();
+-#endif
+
+ crash_save_self(regs);
+ }
+diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
+index d6d7f73..a75c829 100644
+--- a/arch/x86_64/kernel/e820.c
++++ b/arch/x86_64/kernel/e820.c
+@@ -16,6 +16,7 @@
+ #include <linux/string.h>
+ #include <linux/kexec.h>
+ #include <linux/module.h>
++#include <linux/mm.h>
+
+ #include <asm/pgtable.h>
+ #include <asm/page.h>
+@@ -24,6 +25,8 @@
+ #include <asm/bootsetup.h>
+ #include <asm/sections.h>
+
++struct e820map e820 __initdata;
++
+ /*
+ * PFN of last memory page.
+ */
+@@ -40,7 +43,7 @@ unsigned long end_pfn_map;
+ /*
+ * Last pfn which the user wants to use.
+ */
+-unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;
++static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
+
+ extern struct resource code_resource, data_resource;
+
+@@ -51,13 +54,13 @@ static inline int bad_addr(unsigned long
+
+ /* various gunk below that needed for SMP startup */
+ if (addr < 0x8000) {
+- *addrp = 0x8000;
++ *addrp = PAGE_ALIGN(0x8000);
+ return 1;
+ }
+
+ /* direct mapping tables of the kernel */
+ if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) {
+- *addrp = table_end << PAGE_SHIFT;
++ *addrp = PAGE_ALIGN(table_end << PAGE_SHIFT);
+ return 1;
+ }
+
+@@ -65,23 +68,18 @@ static inline int bad_addr(unsigned long
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (LOADER_TYPE && INITRD_START && last >= INITRD_START &&
+ addr < INITRD_START+INITRD_SIZE) {
+- *addrp = INITRD_START + INITRD_SIZE;
++ *addrp = PAGE_ALIGN(INITRD_START + INITRD_SIZE);
+ return 1;
+ }
+ #endif
+- /* kernel code + 640k memory hole (later should not be needed, but
+- be paranoid for now) */
+- if (last >= 640*1024 && addr < 1024*1024) {
+- *addrp = 1024*1024;
+- return 1;
+- }
+- if (last >= __pa_symbol(&_text) && last < __pa_symbol(&_end)) {
+- *addrp = __pa_symbol(&_end);
++ /* kernel code */
++ if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) {
++ *addrp = PAGE_ALIGN(__pa_symbol(&_end));
+ return 1;
+ }
+
+ if (last >= ebda_addr && addr < ebda_addr + ebda_size) {
+- *addrp = ebda_addr + ebda_size;
++ *addrp = PAGE_ALIGN(ebda_addr + ebda_size);
+ return 1;
+ }
+
+@@ -154,7 +152,7 @@ unsigned long __init find_e820_area(unsi
+ continue;
+ while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
+ ;
+- last = addr + size;
++ last = PAGE_ALIGN(addr) + size;
+ if (last > ei->addr + ei->size)
+ continue;
+ if (last > end)
+@@ -164,59 +162,14 @@ unsigned long __init find_e820_area(unsi
+ return -1UL;
+ }
+
+-/*
+- * Free bootmem based on the e820 table for a node.
+- */
+-void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
+-{
+- int i;
+- for (i = 0; i < e820.nr_map; i++) {
+- struct e820entry *ei = &e820.map[i];
+- unsigned long last, addr;
+-
+- if (ei->type != E820_RAM ||
+- ei->addr+ei->size <= start ||
+- ei->addr >= end)
+- continue;
+-
+- addr = round_up(ei->addr, PAGE_SIZE);
+- if (addr < start)
+- addr = start;
+-
+- last = round_down(ei->addr + ei->size, PAGE_SIZE);
+- if (last >= end)
+- last = end;
+-
+- if (last > addr && last-addr >= PAGE_SIZE)
+- free_bootmem_node(pgdat, addr, last-addr);
+- }
+-}
+-
+ /*
+ * Find the highest page frame number we have available
+ */
+ unsigned long __init e820_end_of_ram(void)
+ {
+- int i;
+ unsigned long end_pfn = 0;
++ end_pfn = find_max_pfn_with_active_regions();
+
+- for (i = 0; i < e820.nr_map; i++) {
+- struct e820entry *ei = &e820.map[i];
+- unsigned long start, end;
+-
+- start = round_up(ei->addr, PAGE_SIZE);
+- end = round_down(ei->addr + ei->size, PAGE_SIZE);
+- if (start >= end)
+- continue;
+- if (ei->type == E820_RAM) {
+- if (end > end_pfn<<PAGE_SHIFT)
+- end_pfn = end>>PAGE_SHIFT;
+- } else {
+- if (end > end_pfn_map<<PAGE_SHIFT)
+- end_pfn_map = end>>PAGE_SHIFT;
+- }
+- }
+-
+ if (end_pfn > end_pfn_map)
+ end_pfn_map = end_pfn;
+ if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
+@@ -226,43 +179,10 @@ unsigned long __init e820_end_of_ram(voi
+ if (end_pfn > end_pfn_map)
+ end_pfn = end_pfn_map;
+
++ printk("end_pfn_map = %lu\n", end_pfn_map);
+ return end_pfn;
+ }
+
+-/*
+- * Compute how much memory is missing in a range.
+- * Unlike the other functions in this file the arguments are in page numbers.
+- */
+-unsigned long __init
+-e820_hole_size(unsigned long start_pfn, unsigned long end_pfn)
+-{
+- unsigned long ram = 0;
+- unsigned long start = start_pfn << PAGE_SHIFT;
+- unsigned long end = end_pfn << PAGE_SHIFT;
+- int i;
+- for (i = 0; i < e820.nr_map; i++) {
+- struct e820entry *ei = &e820.map[i];
+- unsigned long last, addr;
+-
+- if (ei->type != E820_RAM ||
+- ei->addr+ei->size <= start ||
+- ei->addr >= end)
+- continue;
+-
+- addr = round_up(ei->addr, PAGE_SIZE);
+- if (addr < start)
+- addr = start;
+-
+- last = round_down(ei->addr + ei->size, PAGE_SIZE);
+- if (last >= end)
+- last = end;
+-
+- if (last > addr)
+- ram += last - addr;
+- }
+- return ((end - start) - ram) >> PAGE_SHIFT;
+-}
+-
+ /*
+ * Mark e820 reserved areas as busy for the resource manager.
+ */
+@@ -297,6 +217,96 @@ void __init e820_reserve_resources(void)
+ }
+ }
+
++/* Mark pages corresponding to given address range as nosave */
++static void __init
++e820_mark_nosave_range(unsigned long start, unsigned long end)
++{
++ unsigned long pfn, max_pfn;
++
++ if (start >= end)
++ return;
++
++ printk("Nosave address range: %016lx - %016lx\n", start, end);
++ max_pfn = end >> PAGE_SHIFT;
++ for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++)
++ if (pfn_valid(pfn))
++ SetPageNosave(pfn_to_page(pfn));
++}
++
++/*
++ * Find the ranges of physical addresses that do not correspond to
++ * e820 RAM areas and mark the corresponding pages as nosave for software
++ * suspend and suspend to RAM.
++ *
++ * This function requires the e820 map to be sorted and without any
++ * overlapping entries and assumes the first e820 area to be RAM.
++ */
++void __init e820_mark_nosave_regions(void)
++{
++ int i;
++ unsigned long paddr;
++
++ paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
++ for (i = 1; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++
++ if (paddr < ei->addr)
++ e820_mark_nosave_range(paddr,
++ round_up(ei->addr, PAGE_SIZE));
++
++ paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
++ if (ei->type != E820_RAM)
++ e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE),
++ paddr);
++
++ if (paddr >= (end_pfn << PAGE_SHIFT))
++ break;
++ }
++}
++
++/* Walk the e820 map and register active regions within a node */
++void __init
++e820_register_active_regions(int nid, unsigned long start_pfn,
++ unsigned long end_pfn)
++{
++ int i;
++ unsigned long ei_startpfn, ei_endpfn;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
++ ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE)
++ >> PAGE_SHIFT;
++
++ /* Skip map entries smaller than a page */
++ if (ei_startpfn > ei_endpfn)
++ continue;
++
++ /* Check if end_pfn_map should be updated */
++ if (ei->type != E820_RAM && ei_endpfn > end_pfn_map)
++ end_pfn_map = ei_endpfn;
++
++ /* Skip if map is outside the node */
++ if (ei->type != E820_RAM ||
++ ei_endpfn <= start_pfn ||
++ ei_startpfn >= end_pfn)
++ continue;
++
++ /* Check for overlaps */
++ if (ei_startpfn < start_pfn)
++ ei_startpfn = start_pfn;
++ if (ei_endpfn > end_pfn)
++ ei_endpfn = end_pfn;
++
++ /* Obey end_user_pfn to save on memmap */
++ if (ei_startpfn >= end_user_pfn)
++ continue;
++ if (ei_endpfn > end_user_pfn)
++ ei_endpfn = end_user_pfn;
++
++ add_active_range(nid, ei_startpfn, ei_endpfn);
++ }
++}
++
+ /*
+ * Add a memory region to the kernel e820 map.
+ */
+@@ -517,13 +527,6 @@ static int __init sanitize_e820_map(stru
+ * If we're lucky and live on a modern system, the setup code
+ * will have given us a memory map that we can use to properly
+ * set up memory. If we aren't, we'll fake a memory map.
+- *
+- * We check to see that the memory map contains at least 2 elements
+- * before we'll use it, because the detection code in setup.S may
+- * not be perfect and most every PC known to man has two memory
+- * regions: one from 0 to 640k, and one from 1mb up. (The IBM
+- * thinkpad 560x, for example, does not cooperate with the memory
+- * detection code.)
+ */
+ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+ {
+@@ -541,34 +544,19 @@ static int __init copy_e820_map(struct e
+ if (start > end)
+ return -1;
+
+- /*
+- * Some BIOSes claim RAM in the 640k - 1M region.
+- * Not right. Fix it up.
+- *
+- * This should be removed on Hammer which is supposed to not
+- * have non e820 covered ISA mappings there, but I had some strange
+- * problems so it stays for now. -AK
+- */
+- if (type == E820_RAM) {
+- if (start < 0x100000ULL && end > 0xA0000ULL) {
+- if (start < 0xA0000ULL)
+- add_memory_region(start, 0xA0000ULL-start, type);
+- if (end <= 0x100000ULL)
+- continue;
+- start = 0x100000ULL;
+- size = end - start;
+- }
+- }
+-
+ add_memory_region(start, size, type);
+ } while (biosmap++,--nr_map);
+ return 0;
+ }
+
+-void __init setup_memory_region(void)
++void early_panic(char *msg)
+ {
+- char *who = "BIOS-e820";
++ early_printk(msg);
++ panic(msg);
++}
+
++void __init setup_memory_region(void)
++{
+ /*
+ * Try to copy the BIOS-supplied E820-map.
+ *
+@@ -576,51 +564,70 @@ void __init setup_memory_region(void)
+ * the next section from 1mb->appropriate_mem_k
+ */
+ sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+- if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+- unsigned long mem_size;
+-
+- /* compare results from other methods and take the greater */
+- if (ALT_MEM_K < EXT_MEM_K) {
+- mem_size = EXT_MEM_K;
+- who = "BIOS-88";
+- } else {
+- mem_size = ALT_MEM_K;
+- who = "BIOS-e801";
+- }
+-
+- e820.nr_map = 0;
+- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+- add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+- }
++ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0)
++ early_panic("Cannot find a valid memory map");
+ printk(KERN_INFO "BIOS-provided physical RAM map:\n");
+- e820_print_map(who);
++ e820_print_map("BIOS-e820");
+ }
+
+-void __init parse_memopt(char *p, char **from)
+-{
+- end_user_pfn = memparse(p, from);
++static int __init parse_memopt(char *p)
++{
++ if (!p)
++ return -EINVAL;
++ end_user_pfn = memparse(p, &p);
+ end_user_pfn >>= PAGE_SHIFT;
++ return 0;
+ }
++early_param("mem", parse_memopt);
++
++static int userdef __initdata;
+
+-void __init parse_memmapopt(char *p, char **from)
++static int __init parse_memmap_opt(char *p)
+ {
++ char *oldp;
+ unsigned long long start_at, mem_size;
+
+- mem_size = memparse(p, from);
+- p = *from;
++ if (!strcmp(p, "exactmap")) {
++#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.
++ */
++ saved_max_pfn = e820_end_of_ram();
++#endif
++ end_pfn_map = 0;
++ e820.nr_map = 0;
++ userdef = 1;
++ return 0;
++ }
++
++ oldp = p;
++ mem_size = memparse(p, &p);
++ if (p == oldp)
++ return -EINVAL;
+ if (*p == '@') {
+- start_at = memparse(p+1, from);
++ start_at = memparse(p+1, &p);
+ add_memory_region(start_at, mem_size, E820_RAM);
+ } else if (*p == '#') {
+- start_at = memparse(p+1, from);
++ start_at = memparse(p+1, &p);
+ add_memory_region(start_at, mem_size, E820_ACPI);
+ } else if (*p == '$') {
+- start_at = memparse(p+1, from);
++ start_at = memparse(p+1, &p);
+ add_memory_region(start_at, mem_size, E820_RESERVED);
+ } else {
+ end_user_pfn = (mem_size >> PAGE_SHIFT);
+ }
+- p = *from;
++ return *p == '\0' ? 0 : -EINVAL;
++}
++early_param("memmap", parse_memmap_opt);
++
++void finish_e820_parsing(void)
++{
++ if (userdef) {
++ printk(KERN_INFO "user-defined physical RAM map:\n");
++ e820_print_map("user");
++ }
+ }
+
+ unsigned long pci_mem_start = 0xaeedbabe;
+diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
+new file mode 100644
+index 0000000..2b1245d
+--- /dev/null
++++ b/arch/x86_64/kernel/early-quirks.c
+@@ -0,0 +1,123 @@
++/* Various workarounds for chipset bugs.
++ This code runs very early and can't use the regular PCI subsystem
++ The entries are keyed to PCI bridges which usually identify chipsets
++ uniquely.
++ This is only for whole classes of chipsets with specific problems which
++ need early invasive action (e.g. before the timers are initialized).
++ Most PCI device specific workarounds can be done later and should be
++ in standard PCI quirks
++ Mainboard specific bugs should be handled by DMI entries.
++ CPU specific bugs in setup.c */
++
++#include <linux/pci.h>
++#include <linux/acpi.h>
++#include <linux/pci_ids.h>
++#include <asm/pci-direct.h>
++#include <asm/proto.h>
++#include <asm/dma.h>
++
++static void via_bugs(void)
++{
++#ifdef CONFIG_IOMMU
++ if ((end_pfn > MAX_DMA32_PFN || force_iommu) &&
++ !iommu_aperture_allowed) {
++ printk(KERN_INFO
++ "Looks like a VIA chipset. Disabling IOMMU. Override with iommu=allowed\n");
++ iommu_aperture_disabled = 1;
++ }
++#endif
++}
++
++#ifdef CONFIG_ACPI
++
++static int nvidia_hpet_detected __initdata;
++
++static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
++{
++ nvidia_hpet_detected = 1;
++ return 0;
++}
++#endif
++
++static void nvidia_bugs(void)
++{
++#ifdef CONFIG_ACPI
++ /*
++ * All timer overrides on Nvidia are
++ * wrong unless HPET is enabled.
++ */
++ nvidia_hpet_detected = 0;
++ acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
++ if (nvidia_hpet_detected == 0) {
++ acpi_skip_timer_override = 1;
++ printk(KERN_INFO "Nvidia board "
++ "detected. Ignoring ACPI "
++ "timer override.\n");
++ }
++#endif
++ /* RED-PEN skip them on mptables too? */
++
++}
++
++static void ati_bugs(void)
++{
++ if (timer_over_8254 == 1) {
++ timer_over_8254 = 0;
++ printk(KERN_INFO
++ "ATI board detected. Disabling timer routing over 8254.\n");
++ }
++}
++
++struct chipset {
++ u16 vendor;
++ void (*f)(void);
++};
++
++static struct chipset early_qrk[] = {
++ { PCI_VENDOR_ID_NVIDIA, nvidia_bugs },
++ { PCI_VENDOR_ID_VIA, via_bugs },
++ { PCI_VENDOR_ID_ATI, ati_bugs },
++ {}
++};
++
++void __init early_quirks(void)
++{
++ int num, slot, func;
++
++ if (!early_pci_allowed())
++ return;
++
++ /* Poor man's PCI discovery */
++ for (num = 0; num < 32; num++) {
++ for (slot = 0; slot < 32; slot++) {
++ for (func = 0; func < 8; func++) {
++ u32 class;
++ u32 vendor;
++ u8 type;
++ int i;
++ class = read_pci_config(num,slot,func,
++ PCI_CLASS_REVISION);
++ if (class == 0xffffffff)
++ break;
++
++ if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
++ continue;
++
++ vendor = read_pci_config(num, slot, func,
++ PCI_VENDOR_ID);
++ vendor &= 0xffff;
++
++ for (i = 0; early_qrk[i].f; i++)
++ if (early_qrk[i].vendor == vendor) {
++ early_qrk[i].f();
++ return;
++ }
++
++ type = read_pci_config_byte(num, slot, func,
++ PCI_HEADER_TYPE);
++ if (!(type & 0x80))
++ break;
++ }
++ }
++ }
++}
+diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
+index 140051e..e22ecd5 100644
+--- a/arch/x86_64/kernel/early_printk.c
++++ b/arch/x86_64/kernel/early_printk.c
+@@ -215,20 +215,16 @@ void early_printk(const char *fmt, ...)
+
+ static int __initdata keep_early;
+
+-int __init setup_early_printk(char *opt)
++static int __init setup_early_printk(char *buf)
+ {
+- char *space;
+- char buf[256];
++ if (!buf)
++ return 0;
+
+ if (early_console_initialized)
+- return 1;
+-
+- strlcpy(buf,opt,sizeof(buf));
+- space = strchr(buf, ' ');
+- if (space)
+- *space = 0;
++ return 0;
++ early_console_initialized = 1;
+
+- if (strstr(buf,"keep"))
++ if (!strcmp(buf,"keep"))
+ keep_early = 1;
+
+ if (!strncmp(buf, "serial", 6)) {
+@@ -248,11 +244,12 @@ int __init setup_early_printk(char *opt)
+ early_console = &simnow_console;
+ keep_early = 1;
+ }
+- early_console_initialized = 1;
+ register_console(early_console);
+ return 0;
+ }
+
++early_param("earlyprintk", setup_early_printk);
++
+ void __init disable_early_printk(void)
+ {
+ if (!early_console_initialized || !early_console)
+@@ -266,4 +263,3 @@ void __init disable_early_printk(void)
+ }
+ }
+
+-__setup("earlyprintk=", setup_early_printk);
+diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
+index aa8d893..7d401b0 100644
+--- a/arch/x86_64/kernel/entry.S
++++ b/arch/x86_64/kernel/entry.S
+@@ -4,8 +4,6 @@
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
+ * Copyright (C) 2000 Pavel Machek <pavel at suse.cz>
+- *
+- * $Id$
+ */
+
+ /*
+@@ -22,15 +20,25 @@
+ * at the top of the kernel process stack.
+ * - partial stack frame: partially saved registers upto R11.
+ * - full stack frame: Like partial stack frame, but all register saved.
+- *
+- * TODO:
+- * - schedule it carefully for the final hardware.
++ *
++ * Some macro usage:
++ * - CFI macros are used to generate dwarf2 unwind information for better
++ * backtraces. They don't change any code.
++ * - SAVE_ALL/RESTORE_ALL - Save/restore all registers
++ * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify.
++ * There are unfortunately lots of special cases where some registers
++ * not touched. The macro is a big mess that should be cleaned up.
++ * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS.
++ * Gives a full stack frame.
++ * - ENTRY/END Define functions in the symbol table.
++ * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack
++ * frame that is otherwise undefined after a SYSCALL
++ * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
++ * - errorentry/paranoidentry/zeroentry - Define exception entry points.
+ */
+
+-#define ASSEMBLY 1
+ #include <linux/linkage.h>
+ #include <asm/segment.h>
+-#include <asm/smp.h>
+ #include <asm/cache.h>
+ #include <asm/errno.h>
+ #include <asm/dwarf2.h>
+@@ -115,6 +123,7 @@
+ .macro CFI_DEFAULT_STACK start=1
+ .if \start
+ CFI_STARTPROC simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,SS+8
+ .else
+ CFI_DEF_CFA_OFFSET SS+8
+@@ -146,6 +155,10 @@
+ /* rdi: prev */
+ ENTRY(ret_from_fork)
+ CFI_DEFAULT_STACK
++ push kernel_eflags(%rip)
++ CFI_ADJUST_CFA_OFFSET 4
++ popf # reset kernel eflags
++ CFI_ADJUST_CFA_OFFSET -4
+ call schedule_tail
+ GET_THREAD_INFO(%rcx)
+ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
+@@ -199,6 +212,7 @@ END(ret_from_fork)
+
+ ENTRY(system_call)
+ CFI_STARTPROC simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,PDA_STACKOFFSET
+ CFI_REGISTER rip,rcx
+ /*CFI_REGISTER rflags,r11*/
+@@ -301,6 +315,8 @@ tracesys:
+ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
+ RESTORE_REST
+ cmpq $__NR_syscall_max,%rax
++ movq $-ENOSYS,%rcx
++ cmova %rcx,%rax
+ ja 1f
+ movq %r10,%rcx /* fixup for C */
+ call *sys_call_table(,%rax,8)
+@@ -316,6 +332,7 @@ END(system_call)
+ */
+ ENTRY(int_ret_from_sys_call)
+ CFI_STARTPROC simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,SS+8-ARGOFFSET
+ /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
+ CFI_REL_OFFSET rsp,RSP-ARGOFFSET
+@@ -476,6 +493,7 @@ END(stub_rt_sigreturn)
+ */
+ .macro _frame ref
+ CFI_STARTPROC simple
++ CFI_SIGNAL_FRAME
+ CFI_DEF_CFA rsp,SS+8-\ref
+ /*CFI_REL_OFFSET ss,SS-\ref*/
+ CFI_REL_OFFSET rsp,RSP-\ref
+@@ -511,7 +529,12 @@ END(stub_rt_sigreturn)
+ testl $3,CS(%rdi)
+ je 1f
+ swapgs
+-1: incl %gs:pda_irqcount # RED-PEN should check preempt count
++ /* irqcount is used to check if a CPU is already on an interrupt
++ stack or not. While this is essentially redundant with preempt_count
++ it is a little cheaper to use a separate counter in the PDA
++ (short of moving irq_enter into assembly, which would be too
++ much work) */
++1: incl %gs:pda_irqcount
+ cmoveq %gs:pda_irqstackptr,%rsp
+ push %rbp # backlink for old unwinder
+ /*
+@@ -619,8 +642,7 @@ retint_signal:
+ #ifdef CONFIG_PREEMPT
+ /* Returning to kernel space. Check if we need preemption */
+ /* rcx: threadinfo. interrupts off. */
+- .p2align
+-retint_kernel:
++ENTRY(retint_kernel)
+ cmpl $0,threadinfo_preempt_count(%rcx)
+ jnz retint_restore_args
+ bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
+@@ -679,7 +701,6 @@ ENTRY(call_function_interrupt)
+ END(call_function_interrupt)
+ #endif
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+ ENTRY(apic_timer_interrupt)
+ apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
+ END(apic_timer_interrupt)
+@@ -691,7 +712,6 @@ END(error_interrupt)
+ ENTRY(spurious_interrupt)
+ apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
+ END(spurious_interrupt)
+-#endif
+
+ /*
+ * Exception entry points.
+@@ -768,7 +788,9 @@ paranoid_exit\trace:
+ testl $3,CS(%rsp)
+ jnz paranoid_userspace\trace
+ paranoid_swapgs\trace:
++ .if \trace
+ TRACE_IRQS_IRETQ 0
++ .endif
+ swapgs
+ paranoid_restore\trace:
+ RESTORE_ALL 8
+@@ -814,7 +836,7 @@ paranoid_schedule\trace:
+ * Exception entry point. This expects an error code/orig_rax on the stack
+ * and the exception handler in %rax.
+ */
+-ENTRY(error_entry)
++KPROBE_ENTRY(error_entry)
+ _frame RDI
+ /* rdi slot contains rax, oldrax contains error code */
+ cld
+@@ -898,7 +920,7 @@ error_kernelspace:
+ cmpq $gs_change,RIP(%rsp)
+ je error_swapgs
+ jmp error_sti
+-END(error_entry)
++KPROBE_END(error_entry)
+
+ /* Reload gs selector with exception handling */
+ /* edi: new selector */
+@@ -1003,7 +1025,7 @@ ENDPROC(child_rip)
+ * do_sys_execve asm fallback arguments:
+ * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
+ */
+-ENTRY(execve)
++ENTRY(kernel_execve)
+ CFI_STARTPROC
+ FAKE_STACK_FRAME $0
+ SAVE_ALL
+@@ -1016,12 +1038,11 @@ ENTRY(execve)
+ UNFAKE_STACK_FRAME
+ ret
+ CFI_ENDPROC
+-ENDPROC(execve)
++ENDPROC(kernel_execve)
+
+ KPROBE_ENTRY(page_fault)
+ errorentry do_page_fault
+-END(page_fault)
+- .previous .text
++KPROBE_END(page_fault)
+
+ ENTRY(coprocessor_error)
+ zeroentry do_coprocessor_error
+@@ -1042,8 +1063,7 @@ KPROBE_ENTRY(debug)
+ CFI_ADJUST_CFA_OFFSET 8
+ paranoidentry do_debug, DEBUG_STACK
+ paranoidexit
+-END(debug)
+- .previous .text
++KPROBE_END(debug)
+
+ /* runs on exception stack */
+ KPROBE_ENTRY(nmi)
+@@ -1057,8 +1077,7 @@ KPROBE_ENTRY(nmi)
+ jmp paranoid_exit1
+ CFI_ENDPROC
+ #endif
+-END(nmi)
+- .previous .text
++KPROBE_END(nmi)
+
+ KPROBE_ENTRY(int3)
+ INTR_FRAME
+@@ -1067,8 +1086,7 @@ KPROBE_ENTRY(int3)
+ paranoidentry do_int3, DEBUG_STACK
+ jmp paranoid_exit1
+ CFI_ENDPROC
+-END(int3)
+- .previous .text
++KPROBE_END(int3)
+
+ ENTRY(overflow)
+ zeroentry do_overflow
+@@ -1116,8 +1134,7 @@ END(stack_segment)
+
+ KPROBE_ENTRY(general_protection)
+ errorentry do_general_protection
+-END(general_protection)
+- .previous .text
++KPROBE_END(general_protection)
+
+ ENTRY(alignment_check)
+ errorentry do_alignment_check
+diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c
+index 3020917..73d7630 100644
+--- a/arch/x86_64/kernel/genapic_cluster.c
++++ b/arch/x86_64/kernel/genapic_cluster.c
+@@ -63,6 +63,13 @@ static cpumask_t cluster_target_cpus(voi
+ return cpumask_of_cpu(0);
+ }
+
++static cpumask_t cluster_vector_allocation_domain(int cpu)
++{
++ cpumask_t domain = CPU_MASK_NONE;
++ cpu_set(cpu, domain);
++ return domain;
++}
++
+ static void cluster_send_IPI_mask(cpumask_t mask, int vector)
+ {
+ send_IPI_mask_sequence(mask, vector);
+@@ -118,8 +125,8 @@ struct genapic apic_cluster = {
+ .name = "clustered",
+ .int_delivery_mode = dest_Fixed,
+ .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
+- .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_FIXED,
+ .target_cpus = cluster_target_cpus,
++ .vector_allocation_domain = cluster_vector_allocation_domain,
+ .apic_id_registered = cluster_apic_id_registered,
+ .init_apic_ldr = cluster_init_apic_ldr,
+ .send_IPI_all = cluster_send_IPI_all,
+diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
+index eb86d37..7c01db8 100644
+--- a/arch/x86_64/kernel/genapic_flat.c
++++ b/arch/x86_64/kernel/genapic_flat.c
+@@ -22,6 +22,20 @@ static cpumask_t flat_target_cpus(void)
+ return cpu_online_map;
+ }
+
++static cpumask_t flat_vector_allocation_domain(int cpu)
++{
++ /* Careful. Some cpus do not strictly honor the set of cpus
++ * specified in the interrupt destination when using lowest
++ * priority interrupt delivery mode.
++ *
++ * In particular there was a hyperthreading cpu observed to
++ * deliver interrupts to the wrong hyperthread when only one
++ * hyperthread was specified in the interrupt desitination.
++ */
++ cpumask_t domain = { { [0] = APIC_ALL_CPUS, } };
++ return domain;
++}
++
+ /*
+ * Set up the logical destination ID.
+ *
+@@ -49,8 +63,7 @@ static void flat_send_IPI_mask(cpumask_t
+ unsigned long cfg;
+ unsigned long flags;
+
+- local_save_flags(flags);
+- local_irq_disable();
++ local_irq_save(flags);
+
+ /*
+ * Wait for idle.
+@@ -121,8 +134,8 @@ struct genapic apic_flat = {
+ .name = "flat",
+ .int_delivery_mode = dest_LowestPrio,
+ .int_dest_mode = (APIC_DEST_LOGICAL != 0),
+- .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
+ .target_cpus = flat_target_cpus,
++ .vector_allocation_domain = flat_vector_allocation_domain,
+ .apic_id_registered = flat_apic_id_registered,
+ .init_apic_ldr = flat_init_apic_ldr,
+ .send_IPI_all = flat_send_IPI_all,
+@@ -140,9 +153,17 @@ struct genapic apic_flat = {
+
+ static cpumask_t physflat_target_cpus(void)
+ {
+- return cpumask_of_cpu(0);
++ return cpu_online_map;
+ }
+
++static cpumask_t physflat_vector_allocation_domain(int cpu)
++{
++ cpumask_t domain = CPU_MASK_NONE;
++ cpu_set(cpu, domain);
++ return domain;
++}
++
++
+ static void physflat_send_IPI_mask(cpumask_t cpumask, int vector)
+ {
+ send_IPI_mask_sequence(cpumask, vector);
+@@ -180,8 +201,8 @@ struct genapic apic_physflat = {
+ .name = "physical flat",
+ .int_delivery_mode = dest_Fixed,
+ .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
+- .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_FIXED,
+ .target_cpus = physflat_target_cpus,
++ .vector_allocation_domain = physflat_vector_allocation_domain,
+ .apic_id_registered = flat_apic_id_registered,
+ .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/
+ .send_IPI_all = physflat_send_IPI_all,
+diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
+index c9739ca..1e6f808 100644
+--- a/arch/x86_64/kernel/head.S
++++ b/arch/x86_64/kernel/head.S
+@@ -5,8 +5,6 @@
+ * Copyright (C) 2000 Pavel Machek <pavel at suse.cz>
+ * Copyright (C) 2000 Karsten Keil <kkeil at suse.de>
+ * Copyright (C) 2001,2002 Andi Kleen <ak at suse.de>
+- *
+- * $Id: head.S,v 1.49 2002/03/19 17:39:25 ak Exp $
+ */
+
+
+@@ -187,12 +185,15 @@ startup_64:
+
+ /* Finally jump to run C code and to be on real kernel address
+ * Since we are running on identity-mapped space we have to jump
+- * to the full 64bit address , this is only possible as indirect
+- * jump
++ * to the full 64bit address, this is only possible as indirect
++ * jump. In addition we need to ensure %cs is set so we make this
++ * a far return.
+ */
+ movq initial_code(%rip),%rax
+- pushq $0 # fake return address
+- jmp *%rax
++ pushq $0 # fake return address to stop unwinder
++ pushq $__KERNEL_CS # set correct cs
++ pushq %rax # target address in negative space
++ lretq
+
+ /* SMP bootup changes these two */
+ .align 8
+@@ -371,7 +372,7 @@ ENTRY(cpu_gdt_table)
+ .quad 0,0 /* TSS */
+ .quad 0,0 /* LDT */
+ .quad 0,0,0 /* three TLS descriptors */
+- .quad 0 /* unused */
++ .quad 0x0000f40000000000 /* node/CPU stored in limit */
+ gdt_end:
+ /* asm/segment.h:GDT_ENTRIES must match this */
+ /* This should be a multiple of the cache line size */
+diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
+index 36647ce..9561eb3 100644
+--- a/arch/x86_64/kernel/head64.c
++++ b/arch/x86_64/kernel/head64.c
+@@ -45,38 +45,16 @@ static void __init copy_bootdata(char *r
+ new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
+ if (!new_data) {
+ if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
+- printk("so old bootloader that it does not support commandline?!\n");
+ return;
+ }
+ new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
+- printk("old bootloader convention, maybe loadlin?\n");
+ }
+ command_line = (char *) ((u64)(new_data));
+ memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+- printk("Bootdata ok (command line is %s)\n", saved_command_line);
+-}
+-
+-static void __init setup_boot_cpu_data(void)
+-{
+- unsigned int dummy, eax;
+-
+- /* get vendor info */
+- cpuid(0, (unsigned int *)&boot_cpu_data.cpuid_level,
+- (unsigned int *)&boot_cpu_data.x86_vendor_id[0],
+- (unsigned int *)&boot_cpu_data.x86_vendor_id[8],
+- (unsigned int *)&boot_cpu_data.x86_vendor_id[4]);
+-
+- /* get cpu type */
+- cpuid(1, &eax, &dummy, &dummy,
+- (unsigned int *) &boot_cpu_data.x86_capability);
+- boot_cpu_data.x86 = (eax >> 8) & 0xf;
+- boot_cpu_data.x86_model = (eax >> 4) & 0xf;
+- boot_cpu_data.x86_mask = eax & 0xf;
+ }
+
+ void __init x86_64_start_kernel(char * real_mode_data)
+ {
+- char *s;
+ int i;
+
+ for (i = 0; i < 256; i++)
+@@ -84,10 +62,7 @@ void __init x86_64_start_kernel(char * r
+ asm volatile("lidt %0" :: "m" (idt_descr));
+ clear_bss();
+
+- /*
+- * This must be called really, really early:
+- */
+- lockdep_init();
++ early_printk("Kernel alive\n");
+
+ /*
+ * switch to init_level4_pgt from boot_level4_pgt
+@@ -103,22 +78,5 @@ void __init x86_64_start_kernel(char * r
+ #ifdef CONFIG_SMP
+ cpu_set(0, cpu_online_map);
+ #endif
+- s = strstr(saved_command_line, "earlyprintk=");
+- if (s != NULL)
+- setup_early_printk(strchr(s, '=') + 1);
+-#ifdef CONFIG_NUMA
+- s = strstr(saved_command_line, "numa=");
+- if (s != NULL)
+- numa_setup(s+5);
+-#endif
+-#ifdef CONFIG_X86_IO_APIC
+- if (strstr(saved_command_line, "disableapic"))
+- disable_apic = 1;
+-#endif
+- /* You need early console to see that */
+- if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE)
+- panic("Kernel too big for kernel mapping\n");
+-
+- setup_boot_cpu_data();
+ start_kernel();
+ }
+diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
+index 0434b1f..c4ef801 100644
+--- a/arch/x86_64/kernel/i8259.c
++++ b/arch/x86_64/kernel/i8259.c
+@@ -43,19 +43,11 @@
+ BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+ BI(x,c) BI(x,d) BI(x,e) BI(x,f)
+
+-#define BUILD_15_IRQS(x) \
+- BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+- BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+- BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+- BI(x,c) BI(x,d) BI(x,e)
+-
+ /*
+ * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
+ * (these are usually mapped to vectors 0x20-0x2f)
+ */
+-BUILD_16_IRQS(0x0)
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * The IO-APIC gives us many more interrupt sources. Most of these
+ * are unused but an SMP system is supposed to have enough memory ...
+@@ -66,19 +58,12 @@ BUILD_16_IRQS(0x0)
+ *
+ * (these are usually mapped into the 0x30-0xff vector range)
+ */
+- BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
++ BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+ BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
+ BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
+-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
+-
+-#ifdef CONFIG_PCI_MSI
+- BUILD_15_IRQS(0xe)
+-#endif
+-
+-#endif
++BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
+
+ #undef BUILD_16_IRQS
+-#undef BUILD_15_IRQS
+ #undef BI
+
+
+@@ -91,31 +76,15 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
+ IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
+
+-#define IRQLIST_15(x) \
+- IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+- IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+- IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+- IRQ(x,c), IRQ(x,d), IRQ(x,e)
+-
+ void (*interrupt[NR_IRQS])(void) = {
+- IRQLIST_16(0x0),
+-
+-#ifdef CONFIG_X86_IO_APIC
+- IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
++ IRQLIST_16(0x2), IRQLIST_16(0x3),
+ IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
+ IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
+- IRQLIST_16(0xc), IRQLIST_16(0xd)
+-
+-#ifdef CONFIG_PCI_MSI
+- , IRQLIST_15(0xe)
+-#endif
+-
+-#endif
++ IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
+ };
+
+ #undef IRQ
+ #undef IRQLIST_16
+-#undef IRQLIST_14
+
+ /*
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+@@ -126,40 +95,15 @@ void (*interrupt[NR_IRQS])(void) = {
+ * moves to arch independent land
+ */
+
++static int i8259A_auto_eoi;
+ DEFINE_SPINLOCK(i8259A_lock);
+-
+-static void end_8259A_irq (unsigned int irq)
+-{
+- if (irq > 256) {
+- char var;
+- printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current));
+-
+- BUG();
+- }
+-
+- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+- irq_desc[irq].action)
+- enable_8259A_irq(irq);
+-}
+-
+-#define shutdown_8259A_irq disable_8259A_irq
+-
+ static void mask_and_ack_8259A(unsigned int);
+
+-static unsigned int startup_8259A_irq(unsigned int irq)
+-{
+- enable_8259A_irq(irq);
+- return 0; /* never anything pending */
+-}
+-
+-static struct hw_interrupt_type i8259A_irq_type = {
+- .typename = "XT-PIC",
+- .startup = startup_8259A_irq,
+- .shutdown = shutdown_8259A_irq,
+- .enable = enable_8259A_irq,
+- .disable = disable_8259A_irq,
+- .ack = mask_and_ack_8259A,
+- .end = end_8259A_irq,
++static struct irq_chip i8259A_chip = {
++ .name = "XT-PIC",
++ .mask = disable_8259A_irq,
++ .unmask = enable_8259A_irq,
++ .mask_ack = mask_and_ack_8259A,
+ };
+
+ /*
+@@ -234,7 +178,8 @@ void make_8259A_irq(unsigned int irq)
+ {
+ disable_irq_nosync(irq);
+ io_apic_irqs &= ~(1<<irq);
+- irq_desc[irq].chip = &i8259A_irq_type;
++ set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
++ "XT");
+ enable_irq(irq);
+ }
+
+@@ -341,6 +286,8 @@ void init_8259A(int auto_eoi)
+ {
+ unsigned long flags;
+
++ i8259A_auto_eoi = auto_eoi;
++
+ spin_lock_irqsave(&i8259A_lock, flags);
+
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+@@ -368,9 +315,9 @@ void init_8259A(int auto_eoi)
+ * in AEOI mode we just have to mask the interrupt
+ * when acking.
+ */
+- i8259A_irq_type.ack = disable_8259A_irq;
++ i8259A_chip.mask_ack = disable_8259A_irq;
+ else
+- i8259A_irq_type.ack = mask_and_ack_8259A;
++ i8259A_chip.mask_ack = mask_and_ack_8259A;
+
+ udelay(100); /* wait for 8259A to initialize */
+
+@@ -399,7 +346,7 @@ static void save_ELCR(char *trigger)
+
+ static int i8259A_resume(struct sys_device *dev)
+ {
+- init_8259A(0);
++ init_8259A(i8259A_auto_eoi);
+ restore_ELCR(irq_trigger);
+ return 0;
+ }
+@@ -448,14 +395,32 @@ device_initcall(i8259A_init_sysfs);
+ */
+
+ static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL};
++DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
++ [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1,
++ [FIRST_EXTERNAL_VECTOR + 0] = 0,
++ [FIRST_EXTERNAL_VECTOR + 1] = 1,
++ [FIRST_EXTERNAL_VECTOR + 2] = 2,
++ [FIRST_EXTERNAL_VECTOR + 3] = 3,
++ [FIRST_EXTERNAL_VECTOR + 4] = 4,
++ [FIRST_EXTERNAL_VECTOR + 5] = 5,
++ [FIRST_EXTERNAL_VECTOR + 6] = 6,
++ [FIRST_EXTERNAL_VECTOR + 7] = 7,
++ [FIRST_EXTERNAL_VECTOR + 8] = 8,
++ [FIRST_EXTERNAL_VECTOR + 9] = 9,
++ [FIRST_EXTERNAL_VECTOR + 10] = 10,
++ [FIRST_EXTERNAL_VECTOR + 11] = 11,
++ [FIRST_EXTERNAL_VECTOR + 12] = 12,
++ [FIRST_EXTERNAL_VECTOR + 13] = 13,
++ [FIRST_EXTERNAL_VECTOR + 14] = 14,
++ [FIRST_EXTERNAL_VECTOR + 15] = 15,
++ [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1
++};
+
+ void __init init_ISA_irqs (void)
+ {
+ int i;
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+ init_bsp_APIC();
+-#endif
+ init_8259A(0);
+
+ for (i = 0; i < NR_IRQS; i++) {
+@@ -467,12 +432,13 @@ void __init init_ISA_irqs (void)
+ /*
+ * 16 old-style INTA-cycle interrupts:
+ */
+- irq_desc[i].chip = &i8259A_irq_type;
++ set_irq_chip_and_handler_name(i, &i8259A_chip,
++ handle_level_irq, "XT");
+ } else {
+ /*
+ * 'high' PCI IRQs filled in on demand
+ */
+- irq_desc[i].chip = &no_irq_type;
++ irq_desc[i].chip = &no_irq_chip;
+ }
+ }
+ }
+@@ -546,8 +512,6 @@ void __init init_IRQ(void)
+ */
+ for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
+ int vector = FIRST_EXTERNAL_VECTOR + i;
+- if (i >= NR_IRQS)
+- break;
+ if (vector != IA32_SYSCALL_VECTOR)
+ set_intr_gate(vector, interrupt[i]);
+ }
+@@ -557,7 +521,7 @@ void __init init_IRQ(void)
+ * IRQ0 must be given a fixed assignment and initialized,
+ * because it's used before the IO-APIC is set up.
+ */
+- set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
++ __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0;
+
+ /*
+ * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+@@ -581,14 +545,12 @@ void __init init_IRQ(void)
+ set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+ set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+ /* self generated IPI for local APIC timer */
+ set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
+
+ /* IPI vectors for APIC spurious and error interrupts */
+ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+ set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+-#endif
+
+ /*
+ * Set the clock to HZ Hz, we already have a valid
+diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
+index 924a4a3..fe429e5 100644
+--- a/arch/x86_64/kernel/io_apic.c
++++ b/arch/x86_64/kernel/io_apic.c
+@@ -26,9 +26,12 @@
+ #include <linux/delay.h>
+ #include <linux/sched.h>
+ #include <linux/smp_lock.h>
++#include <linux/pci.h>
+ #include <linux/mc146818rtc.h>
+ #include <linux/acpi.h>
+ #include <linux/sysdev.h>
++#include <linux/msi.h>
++#include <linux/htirq.h>
+ #ifdef CONFIG_ACPI
+ #include <acpi/acpi_bus.h>
+ #endif
+@@ -41,6 +44,10 @@
+ #include <asm/acpi.h>
+ #include <asm/dma.h>
+ #include <asm/nmi.h>
++#include <asm/msidef.h>
++#include <asm/hypertransport.h>
++
++static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result);
+
+ #define __apicdebuginit __init
+
+@@ -48,15 +55,15 @@ int sis_apic_bug; /* not actually suppor
+
+ static int no_timer_check;
+
+-int disable_timer_pin_1 __initdata;
++static int disable_timer_pin_1 __initdata;
+
+-int timer_over_8254 __initdata = 0;
++int timer_over_8254 __initdata = 1;
+
+ /* Where if anywhere is the i8259 connect in external int mode */
+ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
+
+ static DEFINE_SPINLOCK(ioapic_lock);
+-static DEFINE_SPINLOCK(vector_lock);
++DEFINE_SPINLOCK(vector_lock);
+
+ /*
+ * # of IRQ routing registers
+@@ -81,14 +88,6 @@ static struct irq_pin_list {
+ short apic, pin, next;
+ } irq_2_pin[PIN_MAP_SIZE];
+
+-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
+-#ifdef CONFIG_PCI_MSI
+-#define vector_to_irq(vector) \
+- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
+-#else
+-#define vector_to_irq(vector) (vector)
+-#endif
+-
+ #define __DO_ACTION(R, ACTION, FINAL) \
+ \
+ { \
+@@ -111,12 +110,63 @@ int vector_irq[NR_VECTORS] __read_mostly
+ FINAL; \
+ }
+
++union entry_union {
++ struct { u32 w1, w2; };
++ struct IO_APIC_route_entry entry;
++};
++
++static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
++{
++ union entry_union eu;
++ unsigned long flags;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
++ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ return eu.entry;
++}
++
++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
++{
++ unsigned long flags;
++ union entry_union eu;
++ eu.entry = e;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x10 + 2*pin, eu.w1);
++ io_apic_write(apic, 0x11 + 2*pin, eu.w2);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
+ #ifdef CONFIG_SMP
++static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
++{
++ int apic, pin;
++ struct irq_pin_list *entry = irq_2_pin + irq;
++
++ BUG_ON(irq >= NR_IRQS);
++ for (;;) {
++ unsigned int reg;
++ apic = entry->apic;
++ pin = entry->pin;
++ if (pin == -1)
++ break;
++ io_apic_write(apic, 0x11 + pin*2, dest);
++ reg = io_apic_read(apic, 0x10 + pin*2);
++ reg &= ~0x000000ff;
++ reg |= vector;
++ io_apic_modify(apic, reg);
++ if (!entry->next)
++ break;
++ entry = irq_2_pin + entry->next;
++ }
++}
++
+ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+ {
+ unsigned long flags;
+ unsigned int dest;
+ cpumask_t tmp;
++ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+@@ -124,7 +174,11 @@ static void set_ioapic_affinity_irq(unsi
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+- dest = cpu_mask_to_apicid(mask);
++ vector = assign_irq_vector(irq, mask, &tmp);
++ if (vector < 0)
++ return;
++
++ dest = cpu_mask_to_apicid(tmp);
+
+ /*
+ * Only the high 8 bits are valid.
+@@ -132,14 +186,12 @@ static void set_ioapic_affinity_irq(unsi
+ dest = SET_APIC_LOGICAL_ID(dest);
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+- __DO_ACTION(1, = dest, )
+- set_irq_info(irq, mask);
++ __target_IO_APIC_irq(irq, dest, vector);
++ set_native_irq_info(irq, mask);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+ #endif
+
+-static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
+-
+ /*
+ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
+ * shared ISA-space IRQs, so we have to support them. We are super
+@@ -196,13 +248,9 @@ static void unmask_IO_APIC_irq (unsigned
+ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+ {
+ struct IO_APIC_route_entry entry;
+- unsigned long flags;
+
+ /* Check delivery_mode to be sure we're not clearing an SMI pin */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+- *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ entry = ioapic_read_entry(apic, pin);
+ if (entry.delivery_mode == dest_SMI)
+ return;
+ /*
+@@ -210,10 +258,7 @@ static void clear_IO_APIC_pin(unsigned i
+ */
+ memset(&entry, 0, sizeof(entry));
+ entry.mask = 1;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_write_entry(apic, pin, entry);
+ }
+
+ static void clear_IO_APIC (void)
+@@ -225,14 +270,6 @@ static void clear_IO_APIC (void)
+ clear_IO_APIC_pin(apic, pin);
+ }
+
+-/*
+- * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
+- * specific CPU-side IRQs.
+- */
+-
+-#define MAX_PIRQS 8
+-static int pirq_entries [MAX_PIRQS];
+-static int pirqs_enabled;
+ int skip_ioapic_setup;
+ int ioapic_force;
+
+@@ -241,18 +278,17 @@ int ioapic_force;
+ static int __init disable_ioapic_setup(char *str)
+ {
+ skip_ioapic_setup = 1;
+- return 1;
++ return 0;
+ }
++early_param("noapic", disable_ioapic_setup);
+
+-static int __init enable_ioapic_setup(char *str)
++/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
++static int __init disable_timer_pin_setup(char *arg)
+ {
+- ioapic_force = 1;
+- skip_ioapic_setup = 0;
++ disable_timer_pin_1 = 1;
+ return 1;
+ }
+-
+-__setup("noapic", disable_ioapic_setup);
+-__setup("apic", enable_ioapic_setup);
++__setup("disable_timer_pin_1", disable_timer_pin_setup);
+
+ static int __init setup_disable_8254_timer(char *s)
+ {
+@@ -268,135 +304,6 @@ static int __init setup_enable_8254_time
+ __setup("disable_8254_timer", setup_disable_8254_timer);
+ __setup("enable_8254_timer", setup_enable_8254_timer);
+
+-#include <asm/pci-direct.h>
+-#include <linux/pci_ids.h>
+-#include <linux/pci.h>
+-
+-
+-#ifdef CONFIG_ACPI
+-
+-static int nvidia_hpet_detected __initdata;
+-
+-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+-{
+- nvidia_hpet_detected = 1;
+- return 0;
+-}
+-#endif
+-
+-/* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC
+- off. Check for an Nvidia or VIA PCI bridge and turn it off.
+- Use pci direct infrastructure because this runs before the PCI subsystem.
+-
+- Can be overwritten with "apic"
+-
+- And another hack to disable the IOMMU on VIA chipsets.
+-
+- ... and others. Really should move this somewhere else.
+-
+- Kludge-O-Rama. */
+-void __init check_ioapic(void)
+-{
+- int num,slot,func;
+- /* Poor man's PCI discovery */
+- for (num = 0; num < 32; num++) {
+- for (slot = 0; slot < 32; slot++) {
+- for (func = 0; func < 8; func++) {
+- u32 class;
+- u32 vendor;
+- u8 type;
+- class = read_pci_config(num,slot,func,
+- PCI_CLASS_REVISION);
+- if (class == 0xffffffff)
+- break;
+-
+- if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
+- continue;
+-
+- vendor = read_pci_config(num, slot, func,
+- PCI_VENDOR_ID);
+- vendor &= 0xffff;
+- switch (vendor) {
+- case PCI_VENDOR_ID_VIA:
+-#ifdef CONFIG_IOMMU
+- if ((end_pfn > MAX_DMA32_PFN ||
+- force_iommu) &&
+- !iommu_aperture_allowed) {
+- printk(KERN_INFO
+- "Looks like a VIA chipset. Disabling IOMMU. Override with \"iommu=allowed\"\n");
+- iommu_aperture_disabled = 1;
+- }
+-#endif
+- return;
+- case PCI_VENDOR_ID_NVIDIA:
+-#ifdef CONFIG_ACPI
+- /*
+- * All timer overrides on Nvidia are
+- * wrong unless HPET is enabled.
+- */
+- nvidia_hpet_detected = 0;
+- acpi_table_parse(ACPI_HPET,
+- nvidia_hpet_check);
+- if (nvidia_hpet_detected == 0) {
+- acpi_skip_timer_override = 1;
+- printk(KERN_INFO "Nvidia board "
+- "detected. Ignoring ACPI "
+- "timer override.\n");
+- }
+-#endif
+- /* RED-PEN skip them on mptables too? */
+- return;
+-
+- /* This should be actually default, but
+- for 2.6.16 let's do it for ATI only where
+- it's really needed. */
+- case PCI_VENDOR_ID_ATI:
+- if (timer_over_8254 == 1) {
+- timer_over_8254 = 0;
+- printk(KERN_INFO
+- "ATI board detected. Disabling timer routing over 8254.\n");
+- }
+- return;
+- }
+-
+-
+- /* No multi-function device? */
+- type = read_pci_config_byte(num,slot,func,
+- PCI_HEADER_TYPE);
+- if (!(type & 0x80))
+- break;
+- }
+- }
+- }
+-}
+-
+-static int __init ioapic_pirq_setup(char *str)
+-{
+- int i, max;
+- int ints[MAX_PIRQS+1];
+-
+- get_options(str, ARRAY_SIZE(ints), ints);
+-
+- for (i = 0; i < MAX_PIRQS; i++)
+- pirq_entries[i] = -1;
+-
+- pirqs_enabled = 1;
+- apic_printk(APIC_VERBOSE, "PIRQ redirection, working around broken MP-BIOS.\n");
+- max = MAX_PIRQS;
+- if (ints[0] < MAX_PIRQS)
+- max = ints[0];
+-
+- for (i = 0; i < max; i++) {
+- apic_printk(APIC_VERBOSE, "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
+- /*
+- * PIRQs are mapped upside down, usually.
+- */
+- pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
+- }
+- return 1;
+-}
+-
+-__setup("pirq=", ioapic_pirq_setup);
+
+ /*
+ * Find the IRQ entry number of a certain pin.
+@@ -425,9 +332,7 @@ static int __init find_isa_irq_pin(int i
+ for (i = 0; i < mp_irq_entries; i++) {
+ int lbus = mp_irqs[i].mpc_srcbus;
+
+- if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
+- mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
+- mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
++ if (test_bit(lbus, mp_bus_not_pci) &&
+ (mp_irqs[i].mpc_irqtype == type) &&
+ (mp_irqs[i].mpc_srcbusirq == irq))
+
+@@ -443,9 +348,7 @@ static int __init find_isa_irq_apic(int
+ for (i = 0; i < mp_irq_entries; i++) {
+ int lbus = mp_irqs[i].mpc_srcbus;
+
+- if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
+- mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
+- mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
++ if (test_bit(lbus, mp_bus_not_pci) &&
+ (mp_irqs[i].mpc_irqtype == type) &&
+ (mp_irqs[i].mpc_srcbusirq == irq))
+ break;
+@@ -485,7 +388,7 @@ int IO_APIC_get_PCI_irq_vector(int bus,
+ mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
+ break;
+
+- if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
++ if (!test_bit(lbus, mp_bus_not_pci) &&
+ !mp_irqs[i].mpc_irqtype &&
+ (bus == lbus) &&
+ (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
+@@ -508,27 +411,6 @@ int IO_APIC_get_PCI_irq_vector(int bus,
+ return best_guess;
+ }
+
+-/*
+- * EISA Edge/Level control register, ELCR
+- */
+-static int EISA_ELCR(unsigned int irq)
+-{
+- if (irq < 16) {
+- unsigned int port = 0x4d0 + (irq >> 3);
+- return (inb(port) >> (irq & 7)) & 1;
+- }
+- apic_printk(APIC_VERBOSE, "Broken MPtable reports ISA irq %d\n", irq);
+- return 0;
+-}
+-
+-/* EISA interrupts are always polarity zero and can be edge or level
+- * trigger depending on the ELCR value. If an interrupt is listed as
+- * EISA conforming in the MP table, that means its trigger type must
+- * be read in from the ELCR */
+-
+-#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
+-#define default_EISA_polarity(idx) (0)
+-
+ /* ISA interrupts are always polarity zero edge triggered,
+ * when listed as conforming in the MP table. */
+
+@@ -541,12 +423,6 @@ static int EISA_ELCR(unsigned int irq)
+ #define default_PCI_trigger(idx) (1)
+ #define default_PCI_polarity(idx) (1)
+
+-/* MCA interrupts are always polarity zero level triggered,
+- * when listed as conforming in the MP table. */
+-
+-#define default_MCA_trigger(idx) (1)
+-#define default_MCA_polarity(idx) (0)
+-
+ static int __init MPBIOS_polarity(int idx)
+ {
+ int bus = mp_irqs[idx].mpc_srcbus;
+@@ -558,38 +434,11 @@ static int __init MPBIOS_polarity(int id
+ switch (mp_irqs[idx].mpc_irqflag & 3)
+ {
+ case 0: /* conforms, ie. bus-type dependent polarity */
+- {
+- switch (mp_bus_id_to_type[bus])
+- {
+- case MP_BUS_ISA: /* ISA pin */
+- {
+- polarity = default_ISA_polarity(idx);
+- break;
+- }
+- case MP_BUS_EISA: /* EISA pin */
+- {
+- polarity = default_EISA_polarity(idx);
+- break;
+- }
+- case MP_BUS_PCI: /* PCI pin */
+- {
+- polarity = default_PCI_polarity(idx);
+- break;
+- }
+- case MP_BUS_MCA: /* MCA pin */
+- {
+- polarity = default_MCA_polarity(idx);
+- break;
+- }
+- default:
+- {
+- printk(KERN_WARNING "broken BIOS!!\n");
+- polarity = 1;
+- break;
+- }
+- }
++ if (test_bit(bus, mp_bus_not_pci))
++ polarity = default_ISA_polarity(idx);
++ else
++ polarity = default_PCI_polarity(idx);
+ break;
+- }
+ case 1: /* high active */
+ {
+ polarity = 0;
+@@ -627,38 +476,11 @@ static int MPBIOS_trigger(int idx)
+ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
+ {
+ case 0: /* conforms, ie. bus-type dependent */
+- {
+- switch (mp_bus_id_to_type[bus])
+- {
+- case MP_BUS_ISA: /* ISA pin */
+- {
+- trigger = default_ISA_trigger(idx);
+- break;
+- }
+- case MP_BUS_EISA: /* EISA pin */
+- {
+- trigger = default_EISA_trigger(idx);
+- break;
+- }
+- case MP_BUS_PCI: /* PCI pin */
+- {
+- trigger = default_PCI_trigger(idx);
+- break;
+- }
+- case MP_BUS_MCA: /* MCA pin */
+- {
+- trigger = default_MCA_trigger(idx);
+- break;
+- }
+- default:
+- {
+- printk(KERN_WARNING "broken BIOS!!\n");
+- trigger = 1;
+- break;
+- }
+- }
++ if (test_bit(bus, mp_bus_not_pci))
++ trigger = default_ISA_trigger(idx);
++ else
++ trigger = default_PCI_trigger(idx);
+ break;
+- }
+ case 1: /* edge */
+ {
+ trigger = 0;
+@@ -695,64 +517,6 @@ static inline int irq_trigger(int idx)
+ return MPBIOS_trigger(idx);
+ }
+
+-static int next_irq = 16;
+-
+-/*
+- * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ
+- * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
+- * from ACPI, which can reach 800 in large boxen.
+- *
+- * Compact the sparse GSI space into a sequential IRQ series and reuse
+- * vectors if possible.
+- */
+-int gsi_irq_sharing(int gsi)
+-{
+- int i, tries, vector;
+-
+- BUG_ON(gsi >= NR_IRQ_VECTORS);
+-
+- if (platform_legacy_irq(gsi))
+- return gsi;
+-
+- if (gsi_2_irq[gsi] != 0xFF)
+- return (int)gsi_2_irq[gsi];
+-
+- tries = NR_IRQS;
+- try_again:
+- vector = assign_irq_vector(gsi);
+-
+- /*
+- * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
+- * use of vector and if found, return that IRQ. However, we never want
+- * to share legacy IRQs, which usually have a different trigger mode
+- * than PCI.
+- */
+- for (i = 0; i < NR_IRQS; i++)
+- if (IO_APIC_VECTOR(i) == vector)
+- break;
+- if (platform_legacy_irq(i)) {
+- if (--tries >= 0) {
+- IO_APIC_VECTOR(i) = 0;
+- goto try_again;
+- }
+- panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
+- }
+- if (i < NR_IRQS) {
+- gsi_2_irq[gsi] = i;
+- printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
+- gsi, vector, i);
+- return i;
+- }
+-
+- i = next_irq++;
+- BUG_ON(i >= NR_IRQS);
+- gsi_2_irq[gsi] = i;
+- IO_APIC_VECTOR(i) = vector;
+- printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
+- gsi, vector, i);
+- return i;
+-}
+-
+ static int pin_2_irq(int idx, int apic, int pin)
+ {
+ int irq, i;
+@@ -764,49 +528,16 @@ static int pin_2_irq(int idx, int apic,
+ if (mp_irqs[idx].mpc_dstirq != pin)
+ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
+
+- switch (mp_bus_id_to_type[bus])
+- {
+- case MP_BUS_ISA: /* ISA pin */
+- case MP_BUS_EISA:
+- case MP_BUS_MCA:
+- {
+- irq = mp_irqs[idx].mpc_srcbusirq;
+- break;
+- }
+- case MP_BUS_PCI: /* PCI pin */
+- {
+- /*
+- * PCI IRQs are mapped in order
+- */
+- i = irq = 0;
+- while (i < apic)
+- irq += nr_ioapic_registers[i++];
+- irq += pin;
+- irq = gsi_irq_sharing(irq);
+- break;
+- }
+- default:
+- {
+- printk(KERN_ERR "unknown bus type %d.\n",bus);
+- irq = 0;
+- break;
+- }
+- }
+- BUG_ON(irq >= NR_IRQS);
+-
+- /*
+- * PCI IRQ command line redirection. Yes, limits are hardcoded.
+- */
+- if ((pin >= 16) && (pin <= 23)) {
+- if (pirq_entries[pin-16] != -1) {
+- if (!pirq_entries[pin-16]) {
+- apic_printk(APIC_VERBOSE, "disabling PIRQ%d\n", pin-16);
+- } else {
+- irq = pirq_entries[pin-16];
+- apic_printk(APIC_VERBOSE, "using PIRQ%d -> IRQ %d\n",
+- pin-16, irq);
+- }
+- }
++ if (test_bit(bus, mp_bus_not_pci)) {
++ irq = mp_irqs[idx].mpc_srcbusirq;
++ } else {
++ /*
++ * PCI IRQs are mapped in order
++ */
++ i = irq = 0;
++ while (i < apic)
++ irq += nr_ioapic_registers[i++];
++ irq += pin;
+ }
+ BUG_ON(irq >= NR_IRQS);
+ return irq;
+@@ -830,46 +561,158 @@ static inline int IO_APIC_irq_trigger(in
+ }
+
+ /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
+-u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
++static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = {
++ [0] = FIRST_EXTERNAL_VECTOR + 0,
++ [1] = FIRST_EXTERNAL_VECTOR + 1,
++ [2] = FIRST_EXTERNAL_VECTOR + 2,
++ [3] = FIRST_EXTERNAL_VECTOR + 3,
++ [4] = FIRST_EXTERNAL_VECTOR + 4,
++ [5] = FIRST_EXTERNAL_VECTOR + 5,
++ [6] = FIRST_EXTERNAL_VECTOR + 6,
++ [7] = FIRST_EXTERNAL_VECTOR + 7,
++ [8] = FIRST_EXTERNAL_VECTOR + 8,
++ [9] = FIRST_EXTERNAL_VECTOR + 9,
++ [10] = FIRST_EXTERNAL_VECTOR + 10,
++ [11] = FIRST_EXTERNAL_VECTOR + 11,
++ [12] = FIRST_EXTERNAL_VECTOR + 12,
++ [13] = FIRST_EXTERNAL_VECTOR + 13,
++ [14] = FIRST_EXTERNAL_VECTOR + 14,
++ [15] = FIRST_EXTERNAL_VECTOR + 15,
++};
++
++static cpumask_t irq_domain[NR_IRQ_VECTORS] __read_mostly = {
++ [0] = CPU_MASK_ALL,
++ [1] = CPU_MASK_ALL,
++ [2] = CPU_MASK_ALL,
++ [3] = CPU_MASK_ALL,
++ [4] = CPU_MASK_ALL,
++ [5] = CPU_MASK_ALL,
++ [6] = CPU_MASK_ALL,
++ [7] = CPU_MASK_ALL,
++ [8] = CPU_MASK_ALL,
++ [9] = CPU_MASK_ALL,
++ [10] = CPU_MASK_ALL,
++ [11] = CPU_MASK_ALL,
++ [12] = CPU_MASK_ALL,
++ [13] = CPU_MASK_ALL,
++ [14] = CPU_MASK_ALL,
++ [15] = CPU_MASK_ALL,
++};
+
+-int assign_irq_vector(int irq)
++static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
+ {
+- static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+- unsigned long flags;
+- int vector;
++ /*
++ * NOTE! The local APIC isn't very good at handling
++ * multiple interrupts at the same interrupt level.
++ * As the interrupt level is determined by taking the
++ * vector number and shifting that right by 4, we
++ * want to spread these out a bit so that they don't
++ * all fall in the same interrupt level.
++ *
++ * Also, we've got to be careful not to trash gate
++ * 0x80, because int 0x80 is hm, kind of importantish. ;)
++ */
++ static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
++ int old_vector = -1;
++ int cpu;
+
+- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
++ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+
+- spin_lock_irqsave(&vector_lock, flags);
++ /* Only try and allocate irqs on cpus that are present */
++ cpus_and(mask, mask, cpu_online_map);
+
+- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+- spin_unlock_irqrestore(&vector_lock, flags);
+- return IO_APIC_VECTOR(irq);
++ if (irq_vector[irq] > 0)
++ old_vector = irq_vector[irq];
++ if (old_vector > 0) {
++ cpus_and(*result, irq_domain[irq], mask);
++ if (!cpus_empty(*result))
++ return old_vector;
+ }
++
++ for_each_cpu_mask(cpu, mask) {
++ cpumask_t domain, new_mask;
++ int new_cpu;
++ int vector, offset;
++
++ domain = vector_allocation_domain(cpu);
++ cpus_and(new_mask, domain, cpu_online_map);
++
++ vector = current_vector;
++ offset = current_offset;
+ next:
+- current_vector += 8;
+- if (current_vector == IA32_SYSCALL_VECTOR)
+- goto next;
+-
+- if (current_vector >= FIRST_SYSTEM_VECTOR) {
+- /* If we run out of vectors on large boxen, must share them. */
+- offset = (offset + 1) % 8;
+- current_vector = FIRST_DEVICE_VECTOR + offset;
++ vector += 8;
++ if (vector >= FIRST_SYSTEM_VECTOR) {
++ /* If we run out of vectors on large boxen, must share them. */
++ offset = (offset + 1) % 8;
++ vector = FIRST_DEVICE_VECTOR + offset;
++ }
++ if (unlikely(current_vector == vector))
++ continue;
++ if (vector == IA32_SYSCALL_VECTOR)
++ goto next;
++ for_each_cpu_mask(new_cpu, new_mask)
++ if (per_cpu(vector_irq, new_cpu)[vector] != -1)
++ goto next;
++ /* Found one! */
++ current_vector = vector;
++ current_offset = offset;
++ if (old_vector >= 0) {
++ cpumask_t old_mask;
++ int old_cpu;
++ cpus_and(old_mask, irq_domain[irq], cpu_online_map);
++ for_each_cpu_mask(old_cpu, old_mask)
++ per_cpu(vector_irq, old_cpu)[old_vector] = -1;
++ }
++ for_each_cpu_mask(new_cpu, new_mask)
++ per_cpu(vector_irq, new_cpu)[vector] = irq;
++ irq_vector[irq] = vector;
++ irq_domain[irq] = domain;
++ cpus_and(*result, domain, mask);
++ return vector;
+ }
++ return -ENOSPC;
++}
+
+- vector = current_vector;
+- vector_irq[vector] = irq;
+- if (irq != AUTO_ASSIGN)
+- IO_APIC_VECTOR(irq) = vector;
++static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
++{
++ int vector;
++ unsigned long flags;
+
++ spin_lock_irqsave(&vector_lock, flags);
++ vector = __assign_irq_vector(irq, mask, result);
+ spin_unlock_irqrestore(&vector_lock, flags);
+-
+ return vector;
+ }
+
++void __setup_vector_irq(int cpu)
++{
++ /* Initialize vector_irq on a new cpu */
++ /* This function must be called with vector_lock held */
++ unsigned long flags;
++ int irq, vector;
++
++
++ /* Mark the inuse vectors */
++ for (irq = 0; irq < NR_IRQ_VECTORS; ++irq) {
++ if (!cpu_isset(cpu, irq_domain[irq]))
++ continue;
++ vector = irq_vector[irq];
++ per_cpu(vector_irq, cpu)[vector] = irq;
++ }
++ /* Mark the free vectors */
++ for (vector = 0; vector < NR_VECTORS; ++vector) {
++ irq = per_cpu(vector_irq, cpu)[vector];
++ if (irq < 0)
++ continue;
++ if (!cpu_isset(cpu, irq_domain[irq]))
++ per_cpu(vector_irq, cpu)[vector] = -1;
++ }
++}
++
++
+ extern void (*interrupt[NR_IRQS])(void);
+-static struct hw_interrupt_type ioapic_level_type;
+-static struct hw_interrupt_type ioapic_edge_type;
++
++static struct irq_chip ioapic_chip;
+
+ #define IOAPIC_AUTO -1
+ #define IOAPIC_EDGE 0
+@@ -877,16 +720,13 @@ static struct hw_interrupt_type ioapic_e
+
+ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+ {
+- unsigned idx;
+-
+- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+-
+ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
+ trigger == IOAPIC_LEVEL)
+- irq_desc[idx].chip = &ioapic_level_type;
++ set_irq_chip_and_handler_name(irq, &ioapic_chip,
++ handle_fasteoi_irq, "fasteoi");
+ else
+- irq_desc[idx].chip = &ioapic_edge_type;
+- set_intr_gate(vector, interrupt[idx]);
++ set_irq_chip_and_handler_name(irq, &ioapic_chip,
++ handle_edge_irq, "edge");
+ }
+
+ static void __init setup_IO_APIC_irqs(void)
+@@ -936,16 +776,21 @@ static void __init setup_IO_APIC_irqs(vo
+ continue;
+
+ if (IO_APIC_IRQ(irq)) {
+- vector = assign_irq_vector(irq);
++ cpumask_t mask;
++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
++ if (vector < 0)
++ continue;
++
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
+ entry.vector = vector;
+
+ ioapic_register_intr(irq, vector, IOAPIC_AUTO);
+ if (!apic && (irq < 16))
+ disable_8259A_irq(irq);
+ }
++ ioapic_write_entry(apic, pin, entry);
++
+ spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+ set_native_irq_info(irq, TARGET_CPUS);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+@@ -987,7 +832,7 @@ static void __init setup_ExtINT_IRQ0_pin
+ * The timer IRQ doesn't have to know that behind the
+ * scene we have a 8259A-master in AEOI mode ...
+ */
+- irq_desc[0].chip = &ioapic_edge_type;
++ set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
+
+ /*
+ * Add it to the IO-APIC irq-routing table:
+@@ -1083,10 +928,7 @@ void __apicdebuginit print_IO_APIC(void)
+ for (i = 0; i <= reg_01.bits.entries; i++) {
+ struct IO_APIC_route_entry entry;
+
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+- *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ entry = ioapic_read_entry(apic, i);
+
+ printk(KERN_DEBUG " %02x %03X %02X ",
+ i,
+@@ -1106,17 +948,12 @@ void __apicdebuginit print_IO_APIC(void)
+ );
+ }
+ }
+- if (use_pci_vector())
+- printk(KERN_INFO "Using vector-based indexing\n");
+ printk(KERN_DEBUG "IRQ to pin mappings:\n");
+ for (i = 0; i < NR_IRQS; i++) {
+ struct irq_pin_list *entry = irq_2_pin + i;
+ if (entry->pin < 0)
+ continue;
+- if (use_pci_vector() && !platform_legacy_irq(i))
+- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+- else
+- printk(KERN_DEBUG "IRQ%d ", i);
++ printk(KERN_DEBUG "IRQ%d ", i);
+ for (;;) {
+ printk("-> %d:%d", entry->apic, entry->pin);
+ if (!entry->next)
+@@ -1281,9 +1118,6 @@ static void __init enable_IO_APIC(void)
+ irq_2_pin[i].pin = -1;
+ irq_2_pin[i].next = 0;
+ }
+- if (!pirqs_enabled)
+- for (i = 0; i < MAX_PIRQS; i++)
+- pirq_entries[i] = -1;
+
+ /*
+ * The number of IO-APIC IRQ registers (== #pins):
+@@ -1299,11 +1133,7 @@ static void __init enable_IO_APIC(void)
+ /* See if any of the pins is in ExtINT mode */
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ struct IO_APIC_route_entry entry;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+- *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
+-
++ entry = ioapic_read_entry(apic, pin);
+
+ /* If the interrupt line is enabled and in ExtInt mode
+ * I have found the pin where the i8259 is connected.
+@@ -1355,7 +1185,6 @@ void disable_IO_APIC(void)
+ */
+ if (ioapic_i8259.pin != -1) {
+ struct IO_APIC_route_entry entry;
+- unsigned long flags;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.mask = 0; /* Enabled */
+@@ -1372,84 +1201,13 @@ void disable_IO_APIC(void)
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin,
+- *(((int *)&entry)+1));
+- io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin,
+- *(((int *)&entry)+0));
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
+ }
+
+ disconnect_bsp_APIC(ioapic_i8259.pin != -1);
+ }
+
+ /*
+- * function to set the IO-APIC physical IDs based on the
+- * values stored in the MPC table.
+- *
+- * by Matt Domsch <Matt_Domsch at dell.com> Tue Dec 21 12:25:05 CST 1999
+- */
+-
+-static void __init setup_ioapic_ids_from_mpc (void)
+-{
+- union IO_APIC_reg_00 reg_00;
+- int apic;
+- int i;
+- unsigned char old_id;
+- unsigned long flags;
+-
+- /*
+- * Set the IOAPIC ID to the value stored in the MPC table.
+- */
+- for (apic = 0; apic < nr_ioapics; apic++) {
+-
+- /* Read the register 0 value */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- reg_00.raw = io_apic_read(apic, 0);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
+-
+- old_id = mp_ioapics[apic].mpc_apicid;
+-
+-
+- printk(KERN_INFO "Using IO-APIC %d\n", mp_ioapics[apic].mpc_apicid);
+-
+-
+- /*
+- * We need to adjust the IRQ routing table
+- * if the ID changed.
+- */
+- if (old_id != mp_ioapics[apic].mpc_apicid)
+- for (i = 0; i < mp_irq_entries; i++)
+- if (mp_irqs[i].mpc_dstapic == old_id)
+- mp_irqs[i].mpc_dstapic
+- = mp_ioapics[apic].mpc_apicid;
+-
+- /*
+- * Read the right value from the MPC table and
+- * write it into the ID register.
+- */
+- apic_printk(APIC_VERBOSE,KERN_INFO "...changing IO-APIC physical APIC ID to %d ...",
+- mp_ioapics[apic].mpc_apicid);
+-
+- reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(apic, 0, reg_00.raw);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
+-
+- /*
+- * Sanity check
+- */
+- spin_lock_irqsave(&ioapic_lock, flags);
+- reg_00.raw = io_apic_read(apic, 0);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
+- if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
+- printk("could not set ID!\n");
+- else
+- apic_printk(APIC_VERBOSE," ok.\n");
+- }
+-}
+-
+-/*
+ * There is a nasty bug in some older SMP boards, their mptable lies
+ * about the timer IRQ. We do the following to work around the situation:
+ *
+@@ -1502,7 +1260,7 @@ static int __init timer_irq_works(void)
+ * an edge even if it isn't on the 8259A...
+ */
+
+-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
++static unsigned int startup_ioapic_irq(unsigned int irq)
+ {
+ int was_pending = 0;
+ unsigned long flags;
+@@ -1519,107 +1277,19 @@ static unsigned int startup_edge_ioapic_
+ return was_pending;
+ }
+
+-/*
+- * Once we have recorded IRQ_PENDING already, we can mask the
+- * interrupt for real. This prevents IRQ storms from unhandled
+- * devices.
+- */
+-static void ack_edge_ioapic_irq(unsigned int irq)
+-{
+- move_irq(irq);
+- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
+- == (IRQ_PENDING | IRQ_DISABLED))
+- mask_IO_APIC_irq(irq);
+- ack_APIC_irq();
+-}
+-
+-/*
+- * Level triggered interrupts can just be masked,
+- * and shutting down and starting up the interrupt
+- * is the same as enabling and disabling them -- except
+- * with a startup need to return a "was pending" value.
+- *
+- * Level triggered interrupts are special because we
+- * do not touch any IO-APIC register while handling
+- * them. We ack the APIC in the end-IRQ handler, not
+- * in the start-IRQ-handler. Protection against reentrance
+- * from the same interrupt is still provided, both by the
+- * generic IRQ layer and by the fact that an unacked local
+- * APIC does not accept IRQs.
+- */
+-static unsigned int startup_level_ioapic_irq (unsigned int irq)
+-{
+- unmask_IO_APIC_irq(irq);
+-
+- return 0; /* don't check for pending */
+-}
+-
+-static void end_level_ioapic_irq (unsigned int irq)
+-{
+- move_irq(irq);
+- ack_APIC_irq();
+-}
+-
+-#ifdef CONFIG_PCI_MSI
+-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- return startup_edge_ioapic_irq(irq);
+-}
+-
+-static void ack_edge_ioapic_vector(unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- move_native_irq(vector);
+- ack_edge_ioapic_irq(irq);
+-}
+-
+-static unsigned int startup_level_ioapic_vector (unsigned int vector)
++static int ioapic_retrigger_irq(unsigned int irq)
+ {
+- int irq = vector_to_irq(vector);
+-
+- return startup_level_ioapic_irq (irq);
+-}
+-
+-static void end_level_ioapic_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- move_native_irq(vector);
+- end_level_ioapic_irq(irq);
+-}
+-
+-static void mask_IO_APIC_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- mask_IO_APIC_irq(irq);
+-}
+-
+-static void unmask_IO_APIC_vector (unsigned int vector)
+-{
+- int irq = vector_to_irq(vector);
+-
+- unmask_IO_APIC_irq(irq);
+-}
+-
+-#ifdef CONFIG_SMP
+-static void set_ioapic_affinity_vector (unsigned int vector,
+- cpumask_t cpu_mask)
+-{
+- int irq = vector_to_irq(vector);
++ cpumask_t mask;
++ unsigned vector;
++ unsigned long flags;
+
+- set_native_irq_info(vector, cpu_mask);
+- set_ioapic_affinity_irq(irq, cpu_mask);
+-}
+-#endif // CONFIG_SMP
+-#endif // CONFIG_PCI_MSI
++ spin_lock_irqsave(&vector_lock, flags);
++ vector = irq_vector[irq];
++ cpus_clear(mask);
++ cpu_set(first_cpu(irq_domain[irq]), mask);
+
+-static int ioapic_retrigger(unsigned int irq)
+-{
+- send_IPI_self(IO_APIC_VECTOR(irq));
++ send_IPI_mask(mask, vector);
++ spin_unlock_irqrestore(&vector_lock, flags);
+
+ return 1;
+ }
+@@ -1633,32 +1303,47 @@ static int ioapic_retrigger(unsigned int
+ * races.
+ */
+
+-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
+- .typename = "IO-APIC-edge",
+- .startup = startup_edge_ioapic,
+- .shutdown = shutdown_edge_ioapic,
+- .enable = enable_edge_ioapic,
+- .disable = disable_edge_ioapic,
+- .ack = ack_edge_ioapic,
+- .end = end_edge_ioapic,
+-#ifdef CONFIG_SMP
+- .set_affinity = set_ioapic_affinity,
++static void ack_apic_edge(unsigned int irq)
++{
++ move_native_irq(irq);
++ ack_APIC_irq();
++}
++
++static void ack_apic_level(unsigned int irq)
++{
++ int do_unmask_irq = 0;
++
++#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
++ /* If we are moving the irq we need to mask it */
++ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
++ do_unmask_irq = 1;
++ mask_IO_APIC_irq(irq);
++ }
+ #endif
+- .retrigger = ioapic_retrigger,
+-};
+
+-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
+- .typename = "IO-APIC-level",
+- .startup = startup_level_ioapic,
+- .shutdown = shutdown_level_ioapic,
+- .enable = enable_level_ioapic,
+- .disable = disable_level_ioapic,
+- .ack = mask_and_ack_level_ioapic,
+- .end = end_level_ioapic,
++ /*
++ * We must acknowledge the irq before we move it or the acknowledge will
++ * not propogate properly.
++ */
++ ack_APIC_irq();
++
++ /* Now we can move and renable the irq */
++ move_masked_irq(irq);
++ if (unlikely(do_unmask_irq))
++ unmask_IO_APIC_irq(irq);
++}
++
++static struct irq_chip ioapic_chip __read_mostly = {
++ .name = "IO-APIC",
++ .startup = startup_ioapic_irq,
++ .mask = mask_IO_APIC_irq,
++ .unmask = unmask_IO_APIC_irq,
++ .ack = ack_apic_edge,
++ .eoi = ack_apic_level,
+ #ifdef CONFIG_SMP
+- .set_affinity = set_ioapic_affinity,
++ .set_affinity = set_ioapic_affinity_irq,
+ #endif
+- .retrigger = ioapic_retrigger,
++ .retrigger = ioapic_retrigger_irq,
+ };
+
+ static inline void init_IO_APIC_traps(void)
+@@ -1678,12 +1363,7 @@ static inline void init_IO_APIC_traps(vo
+ */
+ for (irq = 0; irq < NR_IRQS ; irq++) {
+ int tmp = irq;
+- if (use_pci_vector()) {
+- if (!platform_legacy_irq(tmp))
+- if ((tmp = vector_to_irq(tmp)) == -1)
+- continue;
+- }
+- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
++ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
+ /*
+ * Hmm.. We don't have an entry for this,
+ * so default to an old-fashioned 8259
+@@ -1693,7 +1373,7 @@ static inline void init_IO_APIC_traps(vo
+ make_8259A_irq(irq);
+ else
+ /* Strange. Oh, well.. */
+- irq_desc[irq].chip = &no_irq_type;
++ irq_desc[irq].chip = &no_irq_chip;
+ }
+ }
+ }
+@@ -1812,8 +1492,6 @@ static inline void unlock_ExtINT_logic(v
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+
+-int timer_uses_ioapic_pin_0;
+-
+ /*
+ * This code may look a bit paranoid, but it's supposed to cooperate with
+ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
+@@ -1826,13 +1504,13 @@ static inline void check_timer(void)
+ {
+ int apic1, pin1, apic2, pin2;
+ int vector;
++ cpumask_t mask;
+
+ /*
+ * get/set the timer IRQ vector:
+ */
+ disable_8259A_irq(0);
+- vector = assign_irq_vector(0);
+- set_intr_gate(vector, interrupt[0]);
++ vector = assign_irq_vector(0, TARGET_CPUS, &mask);
+
+ /*
+ * Subtle, code in do_timer_interrupt() expects an AEOI
+@@ -1851,9 +1529,6 @@ static inline void check_timer(void)
+ pin2 = ioapic_i8259.pin;
+ apic2 = ioapic_i8259.apic;
+
+- if (pin1 == 0)
+- timer_uses_ioapic_pin_0 = 1;
+-
+ apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
+ vector, apic1, pin1, apic2, pin2);
+
+@@ -1964,11 +1639,6 @@ void __init setup_IO_APIC(void)
+
+ apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
+
+- /*
+- * Set up the IO-APIC IRQ routing table.
+- */
+- if (!acpi_ioapic)
+- setup_ioapic_ids_from_mpc();
+ sync_Arb_IDs();
+ setup_IO_APIC_irqs();
+ init_IO_APIC_traps();
+@@ -1987,17 +1657,12 @@ static int ioapic_suspend(struct sys_dev
+ {
+ struct IO_APIC_route_entry *entry;
+ struct sysfs_ioapic_data *data;
+- unsigned long flags;
+ int i;
+
+ data = container_of(dev, struct sysfs_ioapic_data, dev);
+ entry = data->entry;
+- spin_lock_irqsave(&ioapic_lock, flags);
+- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
+- *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
+- *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
+- }
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ )
++ *entry = ioapic_read_entry(dev->id, i);
+
+ return 0;
+ }
+@@ -2019,11 +1684,9 @@ static int ioapic_resume(struct sys_devi
+ reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
+ io_apic_write(dev->id, 0, reg_00.raw);
+ }
+- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
+- io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
+- io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
+- }
+ spin_unlock_irqrestore(&ioapic_lock, flags);
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i++)
++ ioapic_write_entry(dev->id, i, entry[i]);
+
+ return 0;
+ }
+@@ -2069,26 +1732,253 @@ static int __init ioapic_init_sysfs(void
+
+ device_initcall(ioapic_init_sysfs);
+
+-/* --------------------------------------------------------------------------
+- ACPI-based IOAPIC Configuration
+- -------------------------------------------------------------------------- */
++/*
++ * Dynamic irq allocate and deallocation
++ */
++int create_irq(void)
++{
++ /* Allocate an unused irq */
++ int irq;
++ int new;
++ int vector = 0;
++ unsigned long flags;
++ cpumask_t mask;
+
+-#ifdef CONFIG_ACPI
++ irq = -ENOSPC;
++ spin_lock_irqsave(&vector_lock, flags);
++ for (new = (NR_IRQS - 1); new >= 0; new--) {
++ if (platform_legacy_irq(new))
++ continue;
++ if (irq_vector[new] != 0)
++ continue;
++ vector = __assign_irq_vector(new, TARGET_CPUS, &mask);
++ if (likely(vector > 0))
++ irq = new;
++ break;
++ }
++ spin_unlock_irqrestore(&vector_lock, flags);
+
+-#define IO_APIC_MAX_ID 0xFE
++ if (irq >= 0) {
++ dynamic_irq_init(irq);
++ }
++ return irq;
++}
+
+-int __init io_apic_get_version (int ioapic)
++void destroy_irq(unsigned int irq)
+ {
+- union IO_APIC_reg_01 reg_01;
+ unsigned long flags;
+
+- spin_lock_irqsave(&ioapic_lock, flags);
+- reg_01.raw = io_apic_read(ioapic, 1);
+- spin_unlock_irqrestore(&ioapic_lock, flags);
++ dynamic_irq_cleanup(irq);
+
+- return reg_01.bits.version;
++ spin_lock_irqsave(&vector_lock, flags);
++ irq_vector[irq] = 0;
++ spin_unlock_irqrestore(&vector_lock, flags);
+ }
+
++/*
++ * MSI mesage composition
++ */
++#ifdef CONFIG_PCI_MSI
++static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
++{
++ int vector;
++ unsigned dest;
++ cpumask_t tmp;
++
++ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
++ if (vector >= 0) {
++ dest = cpu_mask_to_apicid(tmp);
++
++ msg->address_hi = MSI_ADDR_BASE_HI;
++ msg->address_lo =
++ MSI_ADDR_BASE_LO |
++ ((INT_DEST_MODE == 0) ?
++ MSI_ADDR_DEST_MODE_PHYSICAL:
++ MSI_ADDR_DEST_MODE_LOGICAL) |
++ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
++ MSI_ADDR_REDIRECTION_CPU:
++ MSI_ADDR_REDIRECTION_LOWPRI) |
++ MSI_ADDR_DEST_ID(dest);
++
++ msg->data =
++ MSI_DATA_TRIGGER_EDGE |
++ MSI_DATA_LEVEL_ASSERT |
++ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
++ MSI_DATA_DELIVERY_FIXED:
++ MSI_DATA_DELIVERY_LOWPRI) |
++ MSI_DATA_VECTOR(vector);
++ }
++ return vector;
++}
++
++#ifdef CONFIG_SMP
++static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
++{
++ struct msi_msg msg;
++ unsigned int dest;
++ cpumask_t tmp;
++ int vector;
++
++ cpus_and(tmp, mask, cpu_online_map);
++ if (cpus_empty(tmp))
++ tmp = TARGET_CPUS;
++
++ cpus_and(mask, tmp, CPU_MASK_ALL);
++
++ vector = assign_irq_vector(irq, mask, &tmp);
++ if (vector < 0)
++ return;
++
++ dest = cpu_mask_to_apicid(tmp);
++
++ read_msi_msg(irq, &msg);
++
++ msg.data &= ~MSI_DATA_VECTOR_MASK;
++ msg.data |= MSI_DATA_VECTOR(vector);
++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
++ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
++
++ write_msi_msg(irq, &msg);
++ set_native_irq_info(irq, mask);
++}
++#endif /* CONFIG_SMP */
++
++/*
++ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
++ * which implement the MSI or MSI-X Capability Structure.
++ */
++static struct irq_chip msi_chip = {
++ .name = "PCI-MSI",
++ .unmask = unmask_msi_irq,
++ .mask = mask_msi_irq,
++ .ack = ack_apic_edge,
++#ifdef CONFIG_SMP
++ .set_affinity = set_msi_irq_affinity,
++#endif
++ .retrigger = ioapic_retrigger_irq,
++};
++
++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
++{
++ struct msi_msg msg;
++ int ret;
++ ret = msi_compose_msg(dev, irq, &msg);
++ if (ret < 0)
++ return ret;
++
++ write_msi_msg(irq, &msg);
++
++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
++
++ return 0;
++}
++
++void arch_teardown_msi_irq(unsigned int irq)
++{
++ return;
++}
++
++#endif /* CONFIG_PCI_MSI */
++
++/*
++ * Hypertransport interrupt support
++ */
++#ifdef CONFIG_HT_IRQ
++
++#ifdef CONFIG_SMP
++
++static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
++{
++ u32 low, high;
++ low = read_ht_irq_low(irq);
++ high = read_ht_irq_high(irq);
++
++ low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
++ high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
++
++ low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
++ high |= HT_IRQ_HIGH_DEST_ID(dest);
++
++ write_ht_irq_low(irq, low);
++ write_ht_irq_high(irq, high);
++}
++
++static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
++{
++ unsigned int dest;
++ cpumask_t tmp;
++ int vector;
++
++ cpus_and(tmp, mask, cpu_online_map);
++ if (cpus_empty(tmp))
++ tmp = TARGET_CPUS;
++
++ cpus_and(mask, tmp, CPU_MASK_ALL);
++
++ vector = assign_irq_vector(irq, mask, &tmp);
++ if (vector < 0)
++ return;
++
++ dest = cpu_mask_to_apicid(tmp);
++
++ target_ht_irq(irq, dest, vector & 0xff);
++ set_native_irq_info(irq, mask);
++}
++#endif
++
++static struct irq_chip ht_irq_chip = {
++ .name = "PCI-HT",
++ .mask = mask_ht_irq,
++ .unmask = unmask_ht_irq,
++ .ack = ack_apic_edge,
++#ifdef CONFIG_SMP
++ .set_affinity = set_ht_irq_affinity,
++#endif
++ .retrigger = ioapic_retrigger_irq,
++};
++
++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
++{
++ int vector;
++ cpumask_t tmp;
++
++ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
++ if (vector >= 0) {
++ u32 low, high;
++ unsigned dest;
++
++ dest = cpu_mask_to_apicid(tmp);
++
++ high = HT_IRQ_HIGH_DEST_ID(dest);
++
++ low = HT_IRQ_LOW_BASE |
++ HT_IRQ_LOW_DEST_ID(dest) |
++ HT_IRQ_LOW_VECTOR(vector) |
++ ((INT_DEST_MODE == 0) ?
++ HT_IRQ_LOW_DM_PHYSICAL :
++ HT_IRQ_LOW_DM_LOGICAL) |
++ HT_IRQ_LOW_RQEOI_EDGE |
++ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
++ HT_IRQ_LOW_MT_FIXED :
++ HT_IRQ_LOW_MT_ARBITRATED);
++
++ write_ht_irq_low(irq, low);
++ write_ht_irq_high(irq, high);
++
++ set_irq_chip_and_handler_name(irq, &ht_irq_chip,
++ handle_edge_irq, "edge");
++ }
++ return vector;
++}
++#endif /* CONFIG_HT_IRQ */
++
++/* --------------------------------------------------------------------------
++ ACPI-based IOAPIC Configuration
++ -------------------------------------------------------------------------- */
++
++#ifdef CONFIG_ACPI
++
++#define IO_APIC_MAX_ID 0xFE
+
+ int __init io_apic_get_redir_entries (int ioapic)
+ {
+@@ -2107,6 +1997,8 @@ int io_apic_set_pci_routing (int ioapic,
+ {
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
++ int vector;
++ cpumask_t mask;
+
+ if (!IO_APIC_IRQ(irq)) {
+ apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
+@@ -2115,6 +2007,17 @@ int io_apic_set_pci_routing (int ioapic,
+ }
+
+ /*
++ * IRQs < 16 are already in the irq_2_pin[] map
++ */
++ if (irq >= 16)
++ add_pin_to_irq(irq, ioapic, pin);
++
++
++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
++ if (vector < 0)
++ return vector;
++
++ /*
+ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
+ * Note that we mask (disable) IRQs now -- these get enabled when the
+ * corresponding device driver registers for this IRQ.
+@@ -2124,19 +2027,11 @@ int io_apic_set_pci_routing (int ioapic,
+
+ entry.delivery_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = INT_DEST_MODE;
+- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
+ entry.trigger = triggering;
+ entry.polarity = polarity;
+ entry.mask = 1; /* Disabled (masked) */
+-
+- irq = gsi_irq_sharing(irq);
+- /*
+- * IRQs < 16 are already in the irq_2_pin[] map
+- */
+- if (irq >= 16)
+- add_pin_to_irq(irq, ioapic, pin);
+-
+- entry.vector = assign_irq_vector(irq);
++ entry.vector = vector & 0xff;
+
+ apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
+ "IRQ %d Mode:%i Active:%i)\n", ioapic,
+@@ -2148,10 +2043,10 @@ int io_apic_set_pci_routing (int ioapic,
+ if (!ioapic && (irq < 16))
+ disable_8259A_irq(irq);
+
++ ioapic_write_entry(ioapic, pin, entry);
++
+ spin_lock_irqsave(&ioapic_lock, flags);
+- io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
+- io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
++ set_native_irq_info(irq, TARGET_CPUS);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ return 0;
+diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c
+index b816149..fe063d3 100644
+--- a/arch/x86_64/kernel/ioport.c
++++ b/arch/x86_64/kernel/ioport.c
+@@ -56,6 +56,7 @@ asmlinkage long sys_ioperm(unsigned long
+
+ memset(bitmap, 0xff, IO_BITMAP_BYTES);
+ t->io_bitmap_ptr = bitmap;
++ set_thread_flag(TIF_IO_BITMAP);
+ }
+
+ /*
+diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
+index 5221a53..e46c558 100644
+--- a/arch/x86_64/kernel/irq.c
++++ b/arch/x86_64/kernel/irq.c
+@@ -20,11 +20,6 @@
+ #include <asm/idle.h>
+
+ atomic_t irq_err_count;
+-#ifdef CONFIG_X86_IO_APIC
+-#ifdef APIC_MISMATCH_DEBUG
+-atomic_t irq_mis_count;
+-#endif
+-#endif
+
+ #ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /*
+@@ -79,7 +74,8 @@ int show_interrupts(struct seq_file *p,
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ #endif
+- seq_printf(p, " %14s", irq_desc[i].chip->typename);
++ seq_printf(p, " %8s", irq_desc[i].chip->name);
++ seq_printf(p, "-%-8s", irq_desc[i].name);
+
+ seq_printf(p, " %s", action->name);
+ for (action=action->next; action; action = action->next)
+@@ -92,18 +88,11 @@ skip:
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", cpu_pda(j)->__nmi_count);
+ seq_putc(p, '\n');
+-#ifdef CONFIG_X86_LOCAL_APIC
+ seq_printf(p, "LOC: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs);
+ seq_putc(p, '\n');
+-#endif
+ seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+-#ifdef CONFIG_X86_IO_APIC
+-#ifdef APIC_MISMATCH_DEBUG
+- seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+-#endif
+-#endif
+ }
+ return 0;
+ }
+@@ -114,24 +103,30 @@ skip:
+ * handlers).
+ */
+ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
+-{
+- /* high bit used in ret_from_ code */
+- unsigned irq = ~regs->orig_rax;
++{
++ struct pt_regs *old_regs = set_irq_regs(regs);
+
+- if (unlikely(irq >= NR_IRQS)) {
+- printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+- __FUNCTION__, irq);
+- BUG();
+- }
++ /* high bit used in ret_from_ code */
++ unsigned vector = ~regs->orig_rax;
++ unsigned irq;
+
+ exit_idle();
+ irq_enter();
++ irq = __get_cpu_var(vector_irq)[vector];
++
+ #ifdef CONFIG_DEBUG_STACKOVERFLOW
+ stack_overflow_check(regs);
+ #endif
+- __do_IRQ(irq, regs);
++
++ if (likely(irq < NR_IRQS))
++ generic_handle_irq(irq);
++ else
++ printk(KERN_EMERG "%s: %d.%d No irq handler for vector\n",
++ __func__, smp_processor_id(), vector);
++
+ irq_exit();
+
++ set_irq_regs(old_regs);
+ return 1;
+ }
+
+diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
+index ffc73ac..ac24156 100644
+--- a/arch/x86_64/kernel/kprobes.c
++++ b/arch/x86_64/kernel/kprobes.c
+@@ -270,20 +270,19 @@ void __kprobes arch_prepare_kretprobe(st
+ struct pt_regs *regs)
+ {
+ unsigned long *sara = (unsigned long *)regs->rsp;
+- struct kretprobe_instance *ri;
++ struct kretprobe_instance *ri;
+
+- if ((ri = get_free_rp_inst(rp)) != NULL) {
+- ri->rp = rp;
+- ri->task = current;
++ if ((ri = get_free_rp_inst(rp)) != NULL) {
++ ri->rp = rp;
++ ri->task = current;
+ ri->ret_addr = (kprobe_opcode_t *) *sara;
+
+ /* Replace the return addr with trampoline addr */
+ *sara = (unsigned long) &kretprobe_trampoline;
+-
+- add_rp_inst(ri);
+- } else {
+- rp->nmissed++;
+- }
++ add_rp_inst(ri);
++ } else {
++ rp->nmissed++;
++ }
+ }
+
+ int __kprobes kprobe_handler(struct pt_regs *regs)
+@@ -405,14 +404,15 @@ no_kprobe:
+ */
+ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+ {
+- struct kretprobe_instance *ri = NULL;
+- struct hlist_head *head;
+- struct hlist_node *node, *tmp;
++ struct kretprobe_instance *ri = NULL;
++ struct hlist_head *head, empty_rp;
++ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+
++ INIT_HLIST_HEAD(&empty_rp);
+ spin_lock_irqsave(&kretprobe_lock, flags);
+- head = kretprobe_inst_table_head(current);
++ head = kretprobe_inst_table_head(current);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+@@ -423,20 +423,20 @@ int __kprobes trampoline_probe_handler(s
+ * 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
++ * 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)
++ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+- continue;
++ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+- recycle_rp_inst(ri);
++ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+@@ -454,12 +454,16 @@ int __kprobes trampoline_probe_handler(s
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ preempt_enable_no_resched();
+
+- /*
+- * By returning a non-zero value, we are telling
+- * kprobe_handler() that we don't want the post_handler
++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++ hlist_del(&ri->hlist);
++ kfree(ri);
++ }
++ /*
++ * By returning a non-zero value, we are telling
++ * kprobe_handler() that we don't want the post_handler
+ * to run (and have re-enabled preemption)
+- */
+- return 1;
++ */
++ return 1;
+ }
+
+ /*
+diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
+index 106076b..0497e3b 100644
+--- a/arch/x86_64/kernel/machine_kexec.c
++++ b/arch/x86_64/kernel/machine_kexec.c
+@@ -15,6 +15,15 @@
+ #include <asm/mmu_context.h>
+ #include <asm/io.h>
+
++#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
++static u64 kexec_pgd[512] PAGE_ALIGNED;
++static u64 kexec_pud0[512] PAGE_ALIGNED;
++static u64 kexec_pmd0[512] PAGE_ALIGNED;
++static u64 kexec_pte0[512] PAGE_ALIGNED;
++static u64 kexec_pud1[512] PAGE_ALIGNED;
++static u64 kexec_pmd1[512] PAGE_ALIGNED;
++static u64 kexec_pte1[512] PAGE_ALIGNED;
++
+ static void init_level2_page(pmd_t *level2p, unsigned long addr)
+ {
+ unsigned long end_addr;
+@@ -144,32 +153,19 @@ static void load_segments(void)
+ );
+ }
+
+-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;
+-
+-extern const unsigned char relocate_new_kernel[];
+-extern const unsigned long relocate_new_kernel_size;
+-
+ int machine_kexec_prepare(struct kimage *image)
+ {
+- unsigned long start_pgtable, control_code_buffer;
++ unsigned long start_pgtable;
+ int result;
+
+ /* Calculate the offsets */
+ start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
+- control_code_buffer = start_pgtable + PAGE_SIZE;
+
+ /* 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;
+ }
+
+@@ -184,28 +180,34 @@ void machine_kexec_cleanup(struct kimage
+ */
+ 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;
++ unsigned long page_list[PAGES_NR];
++ void *control_page;
+
+ /* 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 + PAGE_SIZE;
+-
+- /* 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();
+-
++ control_page = page_address(image->control_code_page) + PAGE_SIZE;
++ memcpy(control_page, relocate_kernel, PAGE_SIZE);
++
++ page_list[PA_CONTROL_PAGE] = __pa(control_page);
++ page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
++ page_list[PA_PGD] = __pa(kexec_pgd);
++ page_list[VA_PGD] = (unsigned long)kexec_pgd;
++ page_list[PA_PUD_0] = __pa(kexec_pud0);
++ page_list[VA_PUD_0] = (unsigned long)kexec_pud0;
++ page_list[PA_PMD_0] = __pa(kexec_pmd0);
++ page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
++ page_list[PA_PTE_0] = __pa(kexec_pte0);
++ page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
++ page_list[PA_PUD_1] = __pa(kexec_pud1);
++ page_list[VA_PUD_1] = (unsigned long)kexec_pud1;
++ page_list[PA_PMD_1] = __pa(kexec_pmd1);
++ page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
++ page_list[PA_PTE_1] = __pa(kexec_pte1);
++ page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
++
++ page_list[PA_TABLE_PAGE] =
++ (unsigned long)__pa(page_address(image->control_code_page));
+
+ /* The segment registers are funny things, they have both a
+ * visible and an invisible part. Whenever the visible part is
+@@ -222,7 +224,36 @@ NORET_TYPE void machine_kexec(struct kim
+ */
+ 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);
++ relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
++ image->start);
+ }
++
++/* crashkernel=size at 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.
++ */
++static int __init setup_crashkernel(char *arg)
++{
++ unsigned long size, base;
++ char *p;
++ if (!arg)
++ return -EINVAL;
++ size = memparse(arg, &p);
++ if (arg == p)
++ return -EINVAL;
++ if (*p == '@') {
++ base = memparse(p+1, &p);
++ /* FIXME: Do I want a sanity check to validate the
++ * memory range? Yes you do, but it's too early for
++ * e820 -AK */
++ crashk_res.start = base;
++ crashk_res.end = base + size - 1;
++ }
++ return 0;
++}
++early_param("crashkernel", setup_crashkernel);
++
+diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
+index 4e017fb..bbea888 100644
+--- a/arch/x86_64/kernel/mce.c
++++ b/arch/x86_64/kernel/mce.c
+@@ -182,7 +182,7 @@ void do_machine_check(struct pt_regs * r
+ goto out2;
+
+ memset(&m, 0, sizeof(struct mce));
+- m.cpu = safe_smp_processor_id();
++ m.cpu = smp_processor_id();
+ rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
+ if (!(m.mcgstatus & MCG_STATUS_RIPV))
+ kill_it = 1;
+@@ -274,6 +274,33 @@ void do_machine_check(struct pt_regs * r
+ atomic_dec(&mce_entry);
+ }
+
++#ifdef CONFIG_X86_MCE_INTEL
++/***
++ * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog
++ * @cpu: The CPU on which the event occured.
++ * @status: Event status information
++ *
++ * This function should be called by the thermal interrupt after the
++ * event has been processed and the decision was made to log the event
++ * further.
++ *
++ * The status parameter will be saved to the 'status' field of 'struct mce'
++ * and historically has been the register value of the
++ * MSR_IA32_THERMAL_STATUS (Intel) msr.
++ */
++void mce_log_therm_throt_event(unsigned int cpu, __u64 status)
++{
++ struct mce m;
++
++ memset(&m, 0, sizeof(m));
++ m.cpu = cpu;
++ m.bank = MCE_THERMAL_BANK;
++ m.status = status;
++ rdtscll(m.tsc);
++ mce_log(&m);
++}
++#endif /* CONFIG_X86_MCE_INTEL */
++
+ /*
+ * Periodic polling timer for "silent" machine check errors.
+ */
+diff --git a/arch/x86_64/kernel/mce_intel.c b/arch/x86_64/kernel/mce_intel.c
+index 8f533d2..6551505 100644
+--- a/arch/x86_64/kernel/mce_intel.c
++++ b/arch/x86_64/kernel/mce_intel.c
+@@ -11,36 +11,21 @@
+ #include <asm/mce.h>
+ #include <asm/hw_irq.h>
+ #include <asm/idle.h>
+-
+-static DEFINE_PER_CPU(unsigned long, next_check);
++#include <asm/therm_throt.h>
+
+ asmlinkage void smp_thermal_interrupt(void)
+ {
+- struct mce m;
++ __u64 msr_val;
+
+ ack_APIC_irq();
+
+ exit_idle();
+ irq_enter();
+- if (time_before(jiffies, __get_cpu_var(next_check)))
+- goto done;
+-
+- __get_cpu_var(next_check) = jiffies + HZ*300;
+- memset(&m, 0, sizeof(m));
+- m.cpu = smp_processor_id();
+- m.bank = MCE_THERMAL_BANK;
+- rdtscll(m.tsc);
+- rdmsrl(MSR_IA32_THERM_STATUS, m.status);
+- if (m.status & 0x1) {
+- printk(KERN_EMERG
+- "CPU%d: Temperature above threshold, cpu clock throttled\n", m.cpu);
+- add_taint(TAINT_MACHINE_CHECK);
+- } else {
+- printk(KERN_EMERG "CPU%d: Temperature/speed normal\n", m.cpu);
+- }
+
+- mce_log(&m);
+-done:
++ rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
++ if (therm_throt_process(msr_val & 1))
++ mce_log_therm_throt_event(smp_processor_id(), msr_val);
++
+ irq_exit();
+ }
+
+@@ -92,6 +77,9 @@ static void __cpuinit intel_init_thermal
+ apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+ printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
+ cpu, tm2 ? "TM2" : "TM1");
++
++ /* enable thermal throttle processing */
++ atomic_set(&therm_throt_en, 1);
+ return;
+ }
+
+diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
+index a1ab419..b147ab1 100644
+--- a/arch/x86_64/kernel/mpparse.c
++++ b/arch/x86_64/kernel/mpparse.c
+@@ -41,8 +41,7 @@ int acpi_found_madt;
+ * Various Linux-internal data structures created from the
+ * MP-table.
+ */
+-unsigned char apic_version [MAX_APICS];
+-unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
++DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
+ int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
+
+ static int mp_current_pci_id = 0;
+@@ -56,7 +55,6 @@ struct mpc_config_intsrc mp_irqs[MAX_IRQ
+ int mp_irq_entries;
+
+ int nr_ioapics;
+-int pic_mode;
+ unsigned long mp_lapic_addr = 0;
+
+
+@@ -71,19 +69,6 @@ unsigned disabled_cpus __initdata;
+ /* Bitmask of physically existing CPUs */
+ physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE;
+
+-/* ACPI MADT entry parsing functions */
+-#ifdef CONFIG_ACPI
+-extern struct acpi_boot_flags acpi_boot;
+-#ifdef CONFIG_X86_LOCAL_APIC
+-extern int acpi_parse_lapic (acpi_table_entry_header *header);
+-extern int acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header);
+-extern int acpi_parse_lapic_nmi (acpi_table_entry_header *header);
+-#endif /*CONFIG_X86_LOCAL_APIC*/
+-#ifdef CONFIG_X86_IO_APIC
+-extern int acpi_parse_ioapic (acpi_table_entry_header *header);
+-#endif /*CONFIG_X86_IO_APIC*/
+-#endif /*CONFIG_ACPI*/
+-
+ u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+
+
+@@ -108,24 +93,20 @@ static int __init mpf_checksum(unsigned
+ static void __cpuinit MP_processor_info (struct mpc_config_processor *m)
+ {
+ int cpu;
+- unsigned char ver;
+ cpumask_t tmp_map;
++ char *bootup_cpu = "";
+
+ if (!(m->mpc_cpuflag & CPU_ENABLED)) {
+ disabled_cpus++;
+ return;
+ }
+-
+- printk(KERN_INFO "Processor #%d %d:%d APIC version %d\n",
+- m->mpc_apicid,
+- (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8,
+- (m->mpc_cpufeature & CPU_MODEL_MASK)>>4,
+- m->mpc_apicver);
+-
+ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+- Dprintk(" Bootup CPU\n");
++ bootup_cpu = " (Bootup-CPU)";
+ boot_cpu_id = m->mpc_apicid;
+ }
++
++ printk(KERN_INFO "Processor #%d%s\n", m->mpc_apicid, bootup_cpu);
++
+ if (num_processors >= NR_CPUS) {
+ printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
+ " Processor ignored.\n", NR_CPUS);
+@@ -136,24 +117,7 @@ static void __cpuinit MP_processor_info
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+
+-#if MAX_APICS < 255
+- if ((int)m->mpc_apicid > MAX_APICS) {
+- printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
+- m->mpc_apicid, MAX_APICS);
+- return;
+- }
+-#endif
+- ver = m->mpc_apicver;
+-
+ physid_set(m->mpc_apicid, phys_cpu_present_map);
+- /*
+- * Validate version
+- */
+- if (ver == 0x0) {
+- printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
+- ver = 0x10;
+- }
+- apic_version[m->mpc_apicid] = ver;
+ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+ /*
+ * bios_cpu_apicid is required to have processors listed
+@@ -178,37 +142,42 @@ static void __init MP_bus_info (struct m
+ Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
+
+ if (strncmp(str, "ISA", 3) == 0) {
+- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
+- } else if (strncmp(str, "EISA", 4) == 0) {
+- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
++ set_bit(m->mpc_busid, mp_bus_not_pci);
+ } else if (strncmp(str, "PCI", 3) == 0) {
+- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
++ clear_bit(m->mpc_busid, mp_bus_not_pci);
+ mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
+ mp_current_pci_id++;
+- } else if (strncmp(str, "MCA", 3) == 0) {
+- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
+ } else {
+ printk(KERN_ERR "Unknown bustype %s\n", str);
+ }
+ }
+
++static int bad_ioapic(unsigned long address)
++{
++ if (nr_ioapics >= MAX_IO_APICS) {
++ printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
++ "(found %d)\n", MAX_IO_APICS, nr_ioapics);
++ panic("Recompile kernel with bigger MAX_IO_APICS!\n");
++ }
++ if (!address) {
++ printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
++ " found in table, skipping!\n");
++ return 1;
++ }
++ return 0;
++}
++
+ static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
+ {
+ if (!(m->mpc_flags & MPC_APIC_USABLE))
+ return;
+
+- printk("I/O APIC #%d Version %d at 0x%X.\n",
+- m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
+- if (nr_ioapics >= MAX_IO_APICS) {
+- printk(KERN_ERR "Max # of I/O APICs (%d) exceeded (found %d).\n",
+- MAX_IO_APICS, nr_ioapics);
+- panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
+- }
+- if (!m->mpc_apicaddr) {
+- printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
+- " found in MP table, skipping!\n");
++ printk("I/O APIC #%d at 0x%X.\n",
++ m->mpc_apicid, m->mpc_apicaddr);
++
++ if (bad_ioapic(m->mpc_apicaddr))
+ return;
+- }
++
+ mp_ioapics[nr_ioapics] = *m;
+ nr_ioapics++;
+ }
+@@ -232,19 +201,6 @@ static void __init MP_lintsrc_info (stru
+ m->mpc_irqtype, m->mpc_irqflag & 3,
+ (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
+ m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
+- /*
+- * Well it seems all SMP boards in existence
+- * use ExtINT/LVT1 == LINT0 and
+- * NMI/LVT2 == LINT1 - the following check
+- * will show us if this assumptions is false.
+- * Until then we do not have to add baggage.
+- */
+- if ((m->mpc_irqtype == mp_ExtINT) &&
+- (m->mpc_destapiclint != 0))
+- BUG();
+- if ((m->mpc_irqtype == mp_NMI) &&
+- (m->mpc_destapiclint != 1))
+- BUG();
+ }
+
+ /*
+@@ -258,7 +214,7 @@ static int __init smp_read_mpc(struct mp
+ unsigned char *mpt=((unsigned char *)mpc)+count;
+
+ if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
+- printk("SMP mptable: bad signature [%c%c%c%c]!\n",
++ printk("MPTABLE: bad signature [%c%c%c%c]!\n",
+ mpc->mpc_signature[0],
+ mpc->mpc_signature[1],
+ mpc->mpc_signature[2],
+@@ -266,31 +222,31 @@ static int __init smp_read_mpc(struct mp
+ return 0;
+ }
+ if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {
+- printk("SMP mptable: checksum error!\n");
++ printk("MPTABLE: checksum error!\n");
+ return 0;
+ }
+ if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
+- printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",
++ printk(KERN_ERR "MPTABLE: bad table version (%d)!!\n",
+ mpc->mpc_spec);
+ return 0;
+ }
+ if (!mpc->mpc_lapic) {
+- printk(KERN_ERR "SMP mptable: null local APIC address!\n");
++ printk(KERN_ERR "MPTABLE: null local APIC address!\n");
+ return 0;
+ }
+ memcpy(str,mpc->mpc_oem,8);
+- str[8]=0;
+- printk(KERN_INFO "OEM ID: %s ",str);
++ str[8] = 0;
++ printk(KERN_INFO "MPTABLE: OEM ID: %s ",str);
+
+ memcpy(str,mpc->mpc_productid,12);
+- str[12]=0;
+- printk("Product ID: %s ",str);
++ str[12] = 0;
++ printk("MPTABLE: Product ID: %s ",str);
+
+- printk("APIC at: 0x%X\n",mpc->mpc_lapic);
++ printk("MPTABLE: APIC at: 0x%X\n",mpc->mpc_lapic);
+
+ /* save the local APIC address, it might be non-default */
+ if (!acpi_lapic)
+- mp_lapic_addr = mpc->mpc_lapic;
++ mp_lapic_addr = mpc->mpc_lapic;
+
+ /*
+ * Now process the configuration blocks.
+@@ -302,7 +258,7 @@ static int __init smp_read_mpc(struct mp
+ struct mpc_config_processor *m=
+ (struct mpc_config_processor *)mpt;
+ if (!acpi_lapic)
+- MP_processor_info(m);
++ MP_processor_info(m);
+ mpt += sizeof(*m);
+ count += sizeof(*m);
+ break;
+@@ -321,8 +277,8 @@ static int __init smp_read_mpc(struct mp
+ struct mpc_config_ioapic *m=
+ (struct mpc_config_ioapic *)mpt;
+ MP_ioapic_info(m);
+- mpt+=sizeof(*m);
+- count+=sizeof(*m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
+ break;
+ }
+ case MP_INTSRC:
+@@ -331,8 +287,8 @@ static int __init smp_read_mpc(struct mp
+ (struct mpc_config_intsrc *)mpt;
+
+ MP_intsrc_info(m);
+- mpt+=sizeof(*m);
+- count+=sizeof(*m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
+ break;
+ }
+ case MP_LINTSRC:
+@@ -340,15 +296,15 @@ static int __init smp_read_mpc(struct mp
+ struct mpc_config_lintsrc *m=
+ (struct mpc_config_lintsrc *)mpt;
+ MP_lintsrc_info(m);
+- mpt+=sizeof(*m);
+- count+=sizeof(*m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
+ break;
+ }
+ }
+ }
+ clustered_apic_check();
+ if (!num_processors)
+- printk(KERN_ERR "SMP mptable: no processors registered!\n");
++ printk(KERN_ERR "MPTABLE: no processors registered!\n");
+ return num_processors;
+ }
+
+@@ -444,13 +400,10 @@ static inline void __init construct_defa
+ * 2 CPUs, numbered 0 & 1.
+ */
+ processor.mpc_type = MP_PROCESSOR;
+- /* Either an integrated APIC or a discrete 82489DX. */
+- processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
++ processor.mpc_apicver = 0;
+ processor.mpc_cpuflag = CPU_ENABLED;
+- processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
+- (boot_cpu_data.x86_model << 4) |
+- boot_cpu_data.x86_mask;
+- processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
++ processor.mpc_cpufeature = 0;
++ processor.mpc_featureflag = 0;
+ processor.mpc_reserved[0] = 0;
+ processor.mpc_reserved[1] = 0;
+ for (i = 0; i < 2; i++) {
+@@ -469,14 +422,6 @@ static inline void __init construct_defa
+ case 5:
+ memcpy(bus.mpc_bustype, "ISA ", 6);
+ break;
+- case 2:
+- case 6:
+- case 3:
+- memcpy(bus.mpc_bustype, "EISA ", 6);
+- break;
+- case 4:
+- case 7:
+- memcpy(bus.mpc_bustype, "MCA ", 6);
+ }
+ MP_bus_info(&bus);
+ if (mpc_default_type > 4) {
+@@ -487,7 +432,7 @@ static inline void __init construct_defa
+
+ ioapic.mpc_type = MP_IOAPIC;
+ ioapic.mpc_apicid = 2;
+- ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
++ ioapic.mpc_apicver = 0;
+ ioapic.mpc_flags = MPC_APIC_USABLE;
+ ioapic.mpc_apicaddr = 0xFEC00000;
+ MP_ioapic_info(&ioapic);
+@@ -530,13 +475,6 @@ void __init get_smp_config (void)
+ printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n");
+
+ printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
+- if (mpf->mpf_feature2 & (1<<7)) {
+- printk(KERN_INFO " IMCR and PIC compatibility mode.\n");
+- pic_mode = 1;
+- } else {
+- printk(KERN_INFO " Virtual Wire compatibility mode.\n");
+- pic_mode = 0;
+- }
+
+ /*
+ * Now see if we need to read further.
+@@ -616,7 +554,7 @@ static int __init smp_scan_config (unsig
+ return 0;
+ }
+
+-void __init find_intel_smp (void)
++void __init find_smp_config(void)
+ {
+ unsigned int address;
+
+@@ -633,9 +571,7 @@ void __init find_intel_smp (void)
+ smp_scan_config(0xF0000,0x10000))
+ return;
+ /*
+- * If it is an SMP machine we should know now, unless the
+- * configuration is in an EISA/MCA bus machine with an
+- * extended bios data area.
++ * If it is an SMP machine we should know now.
+ *
+ * there is a real-mode segmented pointer pointing to the
+ * 4K EBDA area at 0x40E, calculate and scan it here.
+@@ -656,69 +592,41 @@ void __init find_intel_smp (void)
+ printk(KERN_INFO "No mptable found.\n");
+ }
+
+-/*
+- * - Intel MP Configuration Table
+- */
+-void __init find_smp_config (void)
+-{
+-#ifdef CONFIG_X86_LOCAL_APIC
+- find_intel_smp();
+-#endif
+-}
+-
+-
+ /* --------------------------------------------------------------------------
+ ACPI-based MP Configuration
+ -------------------------------------------------------------------------- */
+
+ #ifdef CONFIG_ACPI
+
+-void __init mp_register_lapic_address (
+- u64 address)
++void __init mp_register_lapic_address(u64 address)
+ {
+ mp_lapic_addr = (unsigned long) address;
+-
+ set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
+-
+ if (boot_cpu_id == -1U)
+ boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+-
+- Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid);
+ }
+
+-
+-void __cpuinit mp_register_lapic (
+- u8 id,
+- u8 enabled)
++void __cpuinit mp_register_lapic (u8 id, u8 enabled)
+ {
+ struct mpc_config_processor processor;
+ int boot_cpu = 0;
+
+- if (id >= MAX_APICS) {
+- printk(KERN_WARNING "Processor #%d invalid (max %d)\n",
+- id, MAX_APICS);
+- return;
+- }
+-
+- if (id == boot_cpu_physical_apicid)
++ if (id == boot_cpu_id)
+ boot_cpu = 1;
+
+ processor.mpc_type = MP_PROCESSOR;
+ processor.mpc_apicid = id;
+- processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR));
++ processor.mpc_apicver = 0;
+ processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0);
+ processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0);
+- processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
+- (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
+- processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
++ processor.mpc_cpufeature = 0;
++ processor.mpc_featureflag = 0;
+ processor.mpc_reserved[0] = 0;
+ processor.mpc_reserved[1] = 0;
+
+ MP_processor_info(&processor);
+ }
+
+-#ifdef CONFIG_X86_IO_APIC
+-
+ #define MP_ISA_BUS 0
+ #define MP_MAX_IOAPIC_PIN 127
+
+@@ -729,11 +637,9 @@ static struct mp_ioapic_routing {
+ u32 pin_programmed[4];
+ } mp_ioapic_routing[MAX_IO_APICS];
+
+-
+-static int mp_find_ioapic (
+- int gsi)
++static int mp_find_ioapic(int gsi)
+ {
+- int i = 0;
++ int i = 0;
+
+ /* Find the IOAPIC that manages this GSI. */
+ for (i = 0; i < nr_ioapics; i++) {
+@@ -743,28 +649,15 @@ static int mp_find_ioapic (
+ }
+
+ printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
+-
+ return -1;
+ }
+-
+
+-void __init mp_register_ioapic (
+- u8 id,
+- u32 address,
+- u32 gsi_base)
++void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
+ {
+- int idx = 0;
++ int idx = 0;
+
+- if (nr_ioapics >= MAX_IO_APICS) {
+- printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
+- "(found %d)\n", MAX_IO_APICS, nr_ioapics);
+- panic("Recompile kernel with bigger MAX_IO_APICS!\n");
+- }
+- if (!address) {
+- printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
+- " found in MADT table, skipping!\n");
++ if (bad_ioapic(address))
+ return;
+- }
+
+ idx = nr_ioapics++;
+
+@@ -774,7 +667,7 @@ void __init mp_register_ioapic (
+
+ set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
+ mp_ioapics[idx].mpc_apicid = id;
+- mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
++ mp_ioapics[idx].mpc_apicver = 0;
+
+ /*
+ * Build basic IRQ lookup table to facilitate gsi->io_apic lookups
+@@ -785,21 +678,15 @@ void __init mp_register_ioapic (
+ mp_ioapic_routing[idx].gsi_end = gsi_base +
+ io_apic_get_redir_entries(idx);
+
+- printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
++ printk(KERN_INFO "IOAPIC[%d]: apic_id %d, address 0x%x, "
+ "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
+- mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
++ mp_ioapics[idx].mpc_apicaddr,
+ mp_ioapic_routing[idx].gsi_start,
+ mp_ioapic_routing[idx].gsi_end);
+-
+- return;
+ }
+
+-
+-void __init mp_override_legacy_irq (
+- u8 bus_irq,
+- u8 polarity,
+- u8 trigger,
+- u32 gsi)
++void __init
++mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
+ {
+ struct mpc_config_intsrc intsrc;
+ int ioapic = -1;
+@@ -837,22 +724,18 @@ void __init mp_override_legacy_irq (
+ mp_irqs[mp_irq_entries] = intsrc;
+ if (++mp_irq_entries == MAX_IRQ_SOURCES)
+ panic("Max # of irq sources exceeded!\n");
+-
+- return;
+ }
+
+-
+-void __init mp_config_acpi_legacy_irqs (void)
++void __init mp_config_acpi_legacy_irqs(void)
+ {
+ struct mpc_config_intsrc intsrc;
+- int i = 0;
+- int ioapic = -1;
++ int i = 0;
++ int ioapic = -1;
+
+ /*
+ * Fabricate the legacy ISA bus (bus #31).
+ */
+- mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
+- Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
++ set_bit(MP_ISA_BUS, mp_bus_not_pci);
+
+ /*
+ * Locate the IOAPIC that manages the ISA IRQs (0-15).
+@@ -905,24 +788,13 @@ void __init mp_config_acpi_legacy_irqs (
+ if (++mp_irq_entries == MAX_IRQ_SOURCES)
+ panic("Max # of irq sources exceeded!\n");
+ }
+-
+- return;
+ }
+
+-#define MAX_GSI_NUM 4096
+-
+ int mp_register_gsi(u32 gsi, int triggering, int polarity)
+ {
+- int ioapic = -1;
+- int ioapic_pin = 0;
+- int idx, bit = 0;
+- static int pci_irq = 16;
+- /*
+- * Mapping between Global System Interrupts, which
+- * represent all possible interrupts, to the IRQs
+- * assigned to actual devices.
+- */
+- static int gsi_to_irq[MAX_GSI_NUM];
++ int ioapic = -1;
++ int ioapic_pin = 0;
++ int idx, bit = 0;
+
+ if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
+ return gsi;
+@@ -955,47 +827,14 @@ int mp_register_gsi(u32 gsi, int trigger
+ if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+ Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
+ mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+- return gsi_to_irq[gsi];
++ return gsi;
+ }
+
+ mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
+
+- if (triggering == ACPI_LEVEL_SENSITIVE) {
+- /*
+- * For PCI devices assign IRQs in order, avoiding gaps
+- * due to unused I/O APIC pins.
+- */
+- int irq = gsi;
+- if (gsi < MAX_GSI_NUM) {
+- /*
+- * Retain the VIA chipset work-around (gsi > 15), but
+- * avoid a problem where the 8254 timer (IRQ0) is setup
+- * via an override (so it's not on pin 0 of the ioapic),
+- * and at the same time, the pin 0 interrupt is a PCI
+- * type. The gsi > 15 test could cause these two pins
+- * to be shared as IRQ0, and they are not shareable.
+- * So test for this condition, and if necessary, avoid
+- * the pin collision.
+- */
+- if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
+- gsi = pci_irq++;
+- /*
+- * Don't assign IRQ used by ACPI SCI
+- */
+- if (gsi == acpi_fadt.sci_int)
+- gsi = pci_irq++;
+- gsi_to_irq[irq] = gsi;
+- } else {
+- printk(KERN_ERR "GSI %u is too high\n", gsi);
+- return gsi;
+- }
+- }
+-
+ io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
+ triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
+ polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
+ return gsi;
+ }
+-
+-#endif /*CONFIG_X86_IO_APIC*/
+ #endif /*CONFIG_ACPI*/
+diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
+index 5baa0c7..7af9cb3 100644
+--- a/arch/x86_64/kernel/nmi.c
++++ b/arch/x86_64/kernel/nmi.c
+@@ -28,71 +28,142 @@
+ #include <asm/mce.h>
+ #include <asm/intel_arch_perfmon.h>
+
+-/*
+- * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
+- * - it may be reserved by some other driver, or not
+- * - when not reserved by some other driver, it may be used for
+- * the NMI watchdog, or not
+- *
+- * This is maintained separately from nmi_active because the NMI
+- * watchdog may also be driven from the I/O APIC timer.
++int unknown_nmi_panic;
++int nmi_watchdog_enabled;
++int panic_on_unrecovered_nmi;
++
++/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
++ * evtsel_nmi_owner tracks the ownership of the event selection
++ * - different performance counters/ event selection may be reserved for
++ * different subsystems this reservation system just tries to coordinate
++ * things a little
+ */
+-static DEFINE_SPINLOCK(lapic_nmi_owner_lock);
+-static unsigned int lapic_nmi_owner;
+-#define LAPIC_NMI_WATCHDOG (1<<0)
+-#define LAPIC_NMI_RESERVED (1<<1)
++static DEFINE_PER_CPU(unsigned, perfctr_nmi_owner);
++static DEFINE_PER_CPU(unsigned, evntsel_nmi_owner[2]);
++
++/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
++ * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
++ */
++#define NMI_MAX_COUNTER_BITS 66
+
+ /* nmi_active:
+- * +1: the lapic NMI watchdog is active, but can be disabled
+- * 0: the lapic NMI watchdog has not been set up, and cannot
++ * >0: the lapic NMI watchdog is active, but can be disabled
++ * <0: the lapic NMI watchdog has not been set up, and cannot
+ * be enabled
+- * -1: the lapic NMI watchdog is disabled, but can be enabled
++ * 0: the lapic NMI watchdog is disabled, but can be enabled
+ */
+-int nmi_active; /* oprofile uses this */
++atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+ int panic_on_timeout;
+
+ unsigned int nmi_watchdog = NMI_DEFAULT;
+ static unsigned int nmi_hz = HZ;
+-static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
+-static unsigned int nmi_p4_cccr_val;
+
+-/* Note that these events don't tick when the CPU idles. This means
+- the frequency varies with CPU load. */
++struct nmi_watchdog_ctlblk {
++ int enabled;
++ u64 check_bit;
++ unsigned int cccr_msr;
++ unsigned int perfctr_msr; /* the MSR to reset in NMI handler */
++ unsigned int evntsel_msr; /* the MSR to select the events to handle */
++};
++static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+
+-#define K7_EVNTSEL_ENABLE (1 << 22)
+-#define K7_EVNTSEL_INT (1 << 20)
+-#define K7_EVNTSEL_OS (1 << 17)
+-#define K7_EVNTSEL_USR (1 << 16)
+-#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
+-#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
++/* local prototypes */
++static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
+
+-#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
+-#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
++/* converts an msr to an appropriate reservation bit */
++static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
++{
++ /* returns the bit offset of the performance counter register */
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ return (msr - MSR_K7_PERFCTR0);
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
++ return (msr - MSR_ARCH_PERFMON_PERFCTR0);
++ else
++ return (msr - MSR_P4_BPU_PERFCTR0);
++ }
++ return 0;
++}
+
+-#define MSR_P4_MISC_ENABLE 0x1A0
+-#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
+-#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
+-#define MSR_P4_PERFCTR0 0x300
+-#define MSR_P4_CCCR0 0x360
+-#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
+-#define P4_ESCR_OS (1<<3)
+-#define P4_ESCR_USR (1<<2)
+-#define P4_CCCR_OVF_PMI0 (1<<26)
+-#define P4_CCCR_OVF_PMI1 (1<<27)
+-#define P4_CCCR_THRESHOLD(N) ((N)<<20)
+-#define P4_CCCR_COMPLEMENT (1<<19)
+-#define P4_CCCR_COMPARE (1<<18)
+-#define P4_CCCR_REQUIRED (3<<16)
+-#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
+-#define P4_CCCR_ENABLE (1<<12)
+-/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+- CRU_ESCR0 (with any non-null event selector) through a complemented
+- max threshold. [IA32-Vol3, Section 14.9.9] */
+-#define MSR_P4_IQ_COUNTER0 0x30C
+-#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+-#define P4_NMI_IQ_CCCR0 \
+- (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)
++/* converts an msr to an appropriate reservation bit */
++static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
++{
++ /* returns the bit offset of the event selection register */
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ return (msr - MSR_K7_EVNTSEL0);
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
++ return (msr - MSR_ARCH_PERFMON_EVENTSEL0);
++ else
++ return (msr - MSR_P4_BSU_ESCR0);
++ }
++ return 0;
++}
++
++/* checks for a bit availability (hack for oprofile) */
++int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
++{
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner)));
++}
++
++/* checks the an msr for availability */
++int avail_to_resrv_perfctr_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_perfctr_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner)));
++}
++
++int reserve_perfctr_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_perfctr_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ if (!test_and_set_bit(counter, &__get_cpu_var(perfctr_nmi_owner)))
++ return 1;
++ return 0;
++}
++
++void release_perfctr_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_perfctr_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ clear_bit(counter, &__get_cpu_var(perfctr_nmi_owner));
++}
++
++int reserve_evntsel_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_evntsel_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ if (!test_and_set_bit(counter, &__get_cpu_var(evntsel_nmi_owner)))
++ return 1;
++ return 0;
++}
++
++void release_evntsel_nmi(unsigned int msr)
++{
++ unsigned int counter;
++
++ counter = nmi_evntsel_msr_to_bit(msr);
++ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
++
++ clear_bit(counter, &__get_cpu_var(evntsel_nmi_owner));
++}
+
+ static __cpuinit inline int nmi_known_cpu(void)
+ {
+@@ -109,7 +180,7 @@ static __cpuinit inline int nmi_known_cp
+ }
+
+ /* Run after command line and cpu_init init, but before all other checks */
+-void __cpuinit nmi_watchdog_default(void)
++void nmi_watchdog_default(void)
+ {
+ if (nmi_watchdog != NMI_DEFAULT)
+ return;
+@@ -145,6 +216,12 @@ int __init check_nmi_watchdog (void)
+ int *counts;
+ int cpu;
+
++ if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT))
++ return 0;
++
++ if (!atomic_read(&nmi_active))
++ return 0;
++
+ counts = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
+ if (!counts)
+ return -1;
+@@ -162,26 +239,43 @@ int __init check_nmi_watchdog (void)
+ mdelay((10*1000)/nmi_hz); // wait 10 ticks
+
+ for_each_online_cpu(cpu) {
++ if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled)
++ continue;
+ if (cpu_pda(cpu)->__nmi_count - counts[cpu] <= 5) {
+- endflag = 1;
+ printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
+ cpu,
+ counts[cpu],
+ cpu_pda(cpu)->__nmi_count);
+- nmi_active = 0;
+- lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG;
+- nmi_perfctr_msr = 0;
+- kfree(counts);
+- return -1;
++ per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0;
++ atomic_dec(&nmi_active);
+ }
+ }
++ if (!atomic_read(&nmi_active)) {
++ kfree(counts);
++ atomic_set(&nmi_active, -1);
++ return -1;
++ }
+ endflag = 1;
+ printk("OK.\n");
+
+ /* now that we know it works we can reduce NMI frequency to
+ something more reasonable; makes a difference in some configs */
+- if (nmi_watchdog == NMI_LOCAL_APIC)
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
+ nmi_hz = 1;
++ /*
++ * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter
++ * are writable, with higher bits sign extending from bit 31.
++ * So, we can only program the counter with 31 bit values and
++ * 32nd bit should be 1, for 33.. to be 1.
++ * Find the appropriate nmi_hz
++ */
++ if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0 &&
++ ((u64)cpu_khz * 1000) > 0x7fffffffULL) {
++ nmi_hz = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1;
++ }
++ }
+
+ kfree(counts);
+ return 0;
+@@ -201,91 +295,65 @@ int __init setup_nmi_watchdog(char *str)
+
+ get_option(&str, &nmi);
+
+- if (nmi >= NMI_INVALID)
++ if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
+ return 0;
++
++ if ((nmi == NMI_LOCAL_APIC) && (nmi_known_cpu() == 0))
++ return 0; /* no lapic support */
+ nmi_watchdog = nmi;
+ return 1;
+ }
+
+ __setup("nmi_watchdog=", setup_nmi_watchdog);
+
+-static void disable_intel_arch_watchdog(void);
+-
+ static void disable_lapic_nmi_watchdog(void)
+ {
+- if (nmi_active <= 0)
++ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
++
++ if (atomic_read(&nmi_active) <= 0)
+ return;
+- switch (boot_cpu_data.x86_vendor) {
+- case X86_VENDOR_AMD:
+- wrmsr(MSR_K7_EVNTSEL0, 0, 0);
+- break;
+- case X86_VENDOR_INTEL:
+- if (boot_cpu_data.x86 == 15) {
+- wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+- wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+- } else if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+- disable_intel_arch_watchdog();
+- }
+- break;
+- }
+- nmi_active = -1;
+- /* tell do_nmi() and others that we're not active any more */
+- nmi_watchdog = 0;
+-}
+
+-static void enable_lapic_nmi_watchdog(void)
+-{
+- if (nmi_active < 0) {
+- nmi_watchdog = NMI_LOCAL_APIC;
+- touch_nmi_watchdog();
+- setup_apic_nmi_watchdog();
+- }
++ on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
++
++ BUG_ON(atomic_read(&nmi_active) != 0);
+ }
+
+-int reserve_lapic_nmi(void)
++static void enable_lapic_nmi_watchdog(void)
+ {
+- unsigned int old_owner;
++ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+- spin_lock(&lapic_nmi_owner_lock);
+- old_owner = lapic_nmi_owner;
+- lapic_nmi_owner |= LAPIC_NMI_RESERVED;
+- spin_unlock(&lapic_nmi_owner_lock);
+- if (old_owner & LAPIC_NMI_RESERVED)
+- return -EBUSY;
+- if (old_owner & LAPIC_NMI_WATCHDOG)
+- disable_lapic_nmi_watchdog();
+- return 0;
+-}
++ /* are we already enabled */
++ if (atomic_read(&nmi_active) != 0)
++ return;
+
+-void release_lapic_nmi(void)
+-{
+- unsigned int new_owner;
++ /* are we lapic aware */
++ if (nmi_known_cpu() <= 0)
++ return;
+
+- spin_lock(&lapic_nmi_owner_lock);
+- new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
+- lapic_nmi_owner = new_owner;
+- spin_unlock(&lapic_nmi_owner_lock);
+- if (new_owner & LAPIC_NMI_WATCHDOG)
+- enable_lapic_nmi_watchdog();
++ on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
++ touch_nmi_watchdog();
+ }
+
+ void disable_timer_nmi_watchdog(void)
+ {
+- if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
++ BUG_ON(nmi_watchdog != NMI_IO_APIC);
++
++ if (atomic_read(&nmi_active) <= 0)
+ return;
+
+ disable_irq(0);
+- unset_nmi_callback();
+- nmi_active = -1;
+- nmi_watchdog = NMI_NONE;
++ on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
++
++ BUG_ON(atomic_read(&nmi_active) != 0);
+ }
+
+ void enable_timer_nmi_watchdog(void)
+ {
+- if (nmi_active < 0) {
+- nmi_watchdog = NMI_IO_APIC;
++ BUG_ON(nmi_watchdog != NMI_IO_APIC);
++
++ if (atomic_read(&nmi_active) == 0) {
+ touch_nmi_watchdog();
+- nmi_active = 1;
++ on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
+ enable_irq(0);
+ }
+ }
+@@ -296,15 +364,20 @@ static int nmi_pm_active; /* nmi_active
+
+ static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
+ {
+- nmi_pm_active = nmi_active;
+- disable_lapic_nmi_watchdog();
++ /* only CPU0 goes here, other CPUs should be offline */
++ nmi_pm_active = atomic_read(&nmi_active);
++ stop_apic_nmi_watchdog(NULL);
++ BUG_ON(atomic_read(&nmi_active) != 0);
+ return 0;
+ }
+
+ static int lapic_nmi_resume(struct sys_device *dev)
+ {
+- if (nmi_pm_active > 0)
+- enable_lapic_nmi_watchdog();
++ /* only CPU0 goes here, other CPUs should be offline */
++ if (nmi_pm_active > 0) {
++ setup_apic_nmi_watchdog(NULL);
++ touch_nmi_watchdog();
++ }
+ return 0;
+ }
+
+@@ -323,7 +396,13 @@ static int __init init_lapic_nmi_sysfs(v
+ {
+ int error;
+
+- if (nmi_active == 0 || nmi_watchdog != NMI_LOCAL_APIC)
++ /* should really be a BUG_ON but b/c this is an
++ * init call, it just doesn't work. -dcz
++ */
++ if (nmi_watchdog != NMI_LOCAL_APIC)
++ return 0;
++
++ if ( atomic_read(&nmi_active) < 0 )
+ return 0;
+
+ error = sysdev_class_register(&nmi_sysclass);
+@@ -341,74 +420,209 @@ late_initcall(init_lapic_nmi_sysfs);
+ * Original code written by Keith Owens.
+ */
+
+-static void clear_msr_range(unsigned int base, unsigned int n)
+-{
+- unsigned int i;
++/* Note that these events don't tick when the CPU idles. This means
++ the frequency varies with CPU load. */
+
+- for(i = 0; i < n; ++i)
+- wrmsr(base+i, 0, 0);
+-}
++#define K7_EVNTSEL_ENABLE (1 << 22)
++#define K7_EVNTSEL_INT (1 << 20)
++#define K7_EVNTSEL_OS (1 << 17)
++#define K7_EVNTSEL_USR (1 << 16)
++#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
++#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
+
+-static void setup_k7_watchdog(void)
++static int setup_k7_watchdog(void)
+ {
+- int i;
++ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+- nmi_perfctr_msr = MSR_K7_PERFCTR0;
++ perfctr_msr = MSR_K7_PERFCTR0;
++ evntsel_msr = MSR_K7_EVNTSEL0;
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
+
+- for(i = 0; i < 4; ++i) {
+- /* Simulator may not support it */
+- if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL)) {
+- nmi_perfctr_msr = 0;
+- return;
+- }
+- wrmsrl(MSR_K7_PERFCTR0+i, 0UL);
+- }
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
++
++ /* Simulator may not support it */
++ if (checking_wrmsrl(evntsel_msr, 0UL))
++ goto fail2;
++ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = K7_EVNTSEL_INT
+ | K7_EVNTSEL_OS
+ | K7_EVNTSEL_USR
+ | K7_NMI_EVENT;
+
+- wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
+- wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz * 1000 / nmi_hz));
++ /* setup the timer */
++ wrmsr(evntsel_msr, evntsel, 0);
++ wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= K7_EVNTSEL_ENABLE;
+- wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
++ wrmsr(evntsel_msr, evntsel, 0);
++
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = 0; //unused
++ wd->check_bit = 1ULL<<63;
++ return 1;
++fail2:
++ release_evntsel_nmi(evntsel_msr);
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
+ }
+
+-static void disable_intel_arch_watchdog(void)
++static void stop_k7_watchdog(void)
+ {
+- unsigned ebx;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+- /*
+- * Check whether the Architectural PerfMon supports
+- * Unhalted Core Cycles Event or not.
+- * NOTE: Corresponding bit = 0 in ebp indicates event present.
++ wrmsr(wd->evntsel_msr, 0, 0);
++
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
++}
++
++/* Note that these events don't tick when the CPU idles. This means
++ the frequency varies with CPU load. */
++
++#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
++#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
++#define P4_ESCR_OS (1<<3)
++#define P4_ESCR_USR (1<<2)
++#define P4_CCCR_OVF_PMI0 (1<<26)
++#define P4_CCCR_OVF_PMI1 (1<<27)
++#define P4_CCCR_THRESHOLD(N) ((N)<<20)
++#define P4_CCCR_COMPLEMENT (1<<19)
++#define P4_CCCR_COMPARE (1<<18)
++#define P4_CCCR_REQUIRED (3<<16)
++#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
++#define P4_CCCR_ENABLE (1<<12)
++#define P4_CCCR_OVF (1<<31)
++/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
++ CRU_ESCR0 (with any non-null event selector) through a complemented
++ max threshold. [IA32-Vol3, Section 14.9.9] */
++
++static int setup_p4_watchdog(void)
++{
++ unsigned int perfctr_msr, evntsel_msr, cccr_msr;
++ unsigned int evntsel, cccr_val;
++ unsigned int misc_enable, dummy;
++ unsigned int ht_num;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
++ if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
++ return 0;
++
++#ifdef CONFIG_SMP
++ /* detect which hyperthread we are on */
++ if (smp_num_siblings == 2) {
++ unsigned int ebx, apicid;
++
++ ebx = cpuid_ebx(1);
++ apicid = (ebx >> 24) & 0xff;
++ ht_num = apicid & 1;
++ } else
++#endif
++ ht_num = 0;
++
++ /* performance counters are shared resources
++ * assign each hyperthread its own set
++ * (re-use the ESCR0 register, seems safe
++ * and keeps the cccr_val the same)
+ */
+- ebx = cpuid_ebx(10);
+- if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+- wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
++ if (!ht_num) {
++ /* logical cpu 0 */
++ perfctr_msr = MSR_P4_IQ_PERFCTR0;
++ evntsel_msr = MSR_P4_CRU_ESCR0;
++ cccr_msr = MSR_P4_IQ_CCCR0;
++ cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
++ } else {
++ /* logical cpu 1 */
++ perfctr_msr = MSR_P4_IQ_PERFCTR1;
++ evntsel_msr = MSR_P4_CRU_ESCR0;
++ cccr_msr = MSR_P4_IQ_CCCR1;
++ cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4);
++ }
++
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
++
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
++
++ evntsel = P4_ESCR_EVENT_SELECT(0x3F)
++ | P4_ESCR_OS
++ | P4_ESCR_USR;
++
++ cccr_val |= P4_CCCR_THRESHOLD(15)
++ | P4_CCCR_COMPLEMENT
++ | P4_CCCR_COMPARE
++ | P4_CCCR_REQUIRED;
++
++ wrmsr(evntsel_msr, evntsel, 0);
++ wrmsr(cccr_msr, cccr_val, 0);
++ wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
++ apic_write(APIC_LVTPC, APIC_DM_NMI);
++ cccr_val |= P4_CCCR_ENABLE;
++ wrmsr(cccr_msr, cccr_val, 0);
++
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = cccr_msr;
++ wd->check_bit = 1ULL<<39;
++ return 1;
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
++}
++
++static void stop_p4_watchdog(void)
++{
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ wrmsr(wd->cccr_msr, 0, 0);
++ wrmsr(wd->evntsel_msr, 0, 0);
++
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
+ }
+
++#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
++#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
++
+ static int setup_intel_arch_watchdog(void)
+ {
++ unsigned int ebx;
++ union cpuid10_eax eax;
++ unsigned int unused;
++ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+- unsigned ebx;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ /*
+ * Check whether the Architectural PerfMon supports
+ * Unhalted Core Cycles Event or not.
+- * NOTE: Corresponding bit = 0 in ebp indicates event present.
++ * NOTE: Corresponding bit = 0 in ebx indicates event present.
+ */
+- ebx = cpuid_ebx(10);
+- if ((ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+- return 0;
++ cpuid(10, &(eax.full), &ebx, &unused, &unused);
++ if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
++ (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
++ goto fail;
++
++ perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
++ evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0;
+
+- nmi_perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
++ if (!reserve_perfctr_nmi(perfctr_msr))
++ goto fail;
+
+- clear_msr_range(MSR_ARCH_PERFMON_EVENTSEL0, 2);
+- clear_msr_range(MSR_ARCH_PERFMON_PERFCTR0, 2);
++ if (!reserve_evntsel_nmi(evntsel_msr))
++ goto fail1;
++
++ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = ARCH_PERFMON_EVENTSEL_INT
+ | ARCH_PERFMON_EVENTSEL_OS
+@@ -416,84 +630,122 @@ static int setup_intel_arch_watchdog(voi
+ | ARCH_PERFMON_NMI_EVENT_SEL
+ | ARCH_PERFMON_NMI_EVENT_UMASK;
+
+- wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
+- wrmsrl(MSR_ARCH_PERFMON_PERFCTR0, -((u64)cpu_khz * 1000 / nmi_hz));
++ /* setup the timer */
++ wrmsr(evntsel_msr, evntsel, 0);
++ wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
++
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+- wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
++ wrmsr(evntsel_msr, evntsel, 0);
++
++ wd->perfctr_msr = perfctr_msr;
++ wd->evntsel_msr = evntsel_msr;
++ wd->cccr_msr = 0; //unused
++ wd->check_bit = 1ULL << (eax.split.bit_width - 1);
+ return 1;
++fail1:
++ release_perfctr_nmi(perfctr_msr);
++fail:
++ return 0;
+ }
+
+-
+-static int setup_p4_watchdog(void)
++static void stop_intel_arch_watchdog(void)
+ {
+- unsigned int misc_enable, dummy;
++ unsigned int ebx;
++ union cpuid10_eax eax;
++ unsigned int unused;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+- rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
+- if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+- return 0;
++ /*
++ * Check whether the Architectural PerfMon supports
++ * Unhalted Core Cycles Event or not.
++ * NOTE: Corresponding bit = 0 in ebx indicates event present.
++ */
++ cpuid(10, &(eax.full), &ebx, &unused, &unused);
++ if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
++ (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
++ return;
+
+- nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+- nmi_p4_cccr_val = P4_NMI_IQ_CCCR0;
+-#ifdef CONFIG_SMP
+- if (smp_num_siblings == 2)
+- nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1;
+-#endif
++ wrmsr(wd->evntsel_msr, 0, 0);
+
+- if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+- clear_msr_range(0x3F1, 2);
+- /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+- docs doesn't fully define it, so leave it alone for now. */
+- if (boot_cpu_data.x86_model >= 0x3) {
+- /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
+- clear_msr_range(0x3A0, 26);
+- clear_msr_range(0x3BC, 3);
+- } else {
+- clear_msr_range(0x3A0, 31);
+- }
+- clear_msr_range(0x3C0, 6);
+- clear_msr_range(0x3C8, 6);
+- clear_msr_range(0x3E0, 2);
+- clear_msr_range(MSR_P4_CCCR0, 18);
+- clear_msr_range(MSR_P4_PERFCTR0, 18);
+-
+- wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+- wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+- Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz * 1000UL / nmi_hz));
+- wrmsrl(MSR_P4_IQ_COUNTER0, -((u64)cpu_khz * 1000 / nmi_hz));
+- apic_write(APIC_LVTPC, APIC_DM_NMI);
+- wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
+- return 1;
++ release_evntsel_nmi(wd->evntsel_msr);
++ release_perfctr_nmi(wd->perfctr_msr);
+ }
+
+-void setup_apic_nmi_watchdog(void)
++void setup_apic_nmi_watchdog(void *unused)
+ {
+- switch (boot_cpu_data.x86_vendor) {
+- case X86_VENDOR_AMD:
+- if (boot_cpu_data.x86 != 15)
+- return;
+- if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
+- return;
+- setup_k7_watchdog();
+- break;
+- case X86_VENDOR_INTEL:
+- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+- if (!setup_intel_arch_watchdog())
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++
++ /* only support LOCAL and IO APICs for now */
++ if ((nmi_watchdog != NMI_LOCAL_APIC) &&
++ (nmi_watchdog != NMI_IO_APIC))
++ return;
++
++ if (wd->enabled == 1)
++ return;
++
++ /* cheap hack to support suspend/resume */
++ /* if cpu0 is not active neither should the other cpus */
++ if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
++ return;
++
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
+ return;
+- } else if (boot_cpu_data.x86 == 15) {
++ if (!setup_k7_watchdog())
++ return;
++ break;
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
++ if (!setup_intel_arch_watchdog())
++ return;
++ break;
++ }
+ if (!setup_p4_watchdog())
+ return;
+- } else {
++ break;
++ default:
+ return;
+ }
++ }
++ wd->enabled = 1;
++ atomic_inc(&nmi_active);
++}
++
++void stop_apic_nmi_watchdog(void *unused)
++{
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+- break;
++ /* only support LOCAL and IO APICs for now */
++ if ((nmi_watchdog != NMI_LOCAL_APIC) &&
++ (nmi_watchdog != NMI_IO_APIC))
++ return;
+
+- default:
++ if (wd->enabled == 0)
+ return;
++
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_AMD:
++ if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
++ return;
++ stop_k7_watchdog();
++ break;
++ case X86_VENDOR_INTEL:
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
++ stop_intel_arch_watchdog();
++ break;
++ }
++ stop_p4_watchdog();
++ break;
++ default:
++ return;
++ }
+ }
+- lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
+- nmi_active = 1;
++ wd->enabled = 0;
++ atomic_dec(&nmi_active);
+ }
+
+ /*
+@@ -526,93 +778,109 @@ void touch_nmi_watchdog (void)
+ touch_softlockup_watchdog();
+ }
+
+-void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
++int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
+ {
+ int sum;
+ int touched = 0;
++ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
++ u64 dummy;
++ int rc=0;
++
++ /* check for other users first */
++ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
++ == NOTIFY_STOP) {
++ rc = 1;
++ touched = 1;
++ }
+
+ sum = read_pda(apic_timer_irqs);
+ if (__get_cpu_var(nmi_touch)) {
+ __get_cpu_var(nmi_touch) = 0;
+ touched = 1;
+ }
++
+ #ifdef CONFIG_X86_MCE
+ /* Could check oops_in_progress here too, but it's safer
+ not too */
+ if (atomic_read(&mce_entry) > 0)
+ touched = 1;
+ #endif
++ /* if the apic timer isn't firing, this cpu isn't doing much */
+ if (!touched && __get_cpu_var(last_irq_sum) == sum) {
+ /*
+ * Ayiee, looks like this CPU is stuck ...
+ * wait a few IRQs (5 seconds) before doing the oops ...
+ */
+ local_inc(&__get_cpu_var(alert_counter));
+- if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) {
+- if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
+- == NOTIFY_STOP) {
+- local_set(&__get_cpu_var(alert_counter), 0);
+- return;
+- }
+- die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs);
+- }
++ if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz)
++ die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs,
++ panic_on_timeout);
+ } else {
+ __get_cpu_var(last_irq_sum) = sum;
+ local_set(&__get_cpu_var(alert_counter), 0);
+ }
+- if (nmi_perfctr_msr) {
+- if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+- /*
+- * P4 quirks:
+- * - An overflown perfctr will assert its interrupt
+- * until the OVF flag in its CCCR is cleared.
+- * - LVTPC is masked on interrupt and must be
+- * unmasked by the LVTPC handler.
+- */
+- wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
+- apic_write(APIC_LVTPC, APIC_DM_NMI);
+- } else if (nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
+- /*
+- * For Intel based architectural perfmon
+- * - LVTPC is masked on interrupt and must be
+- * unmasked by the LVTPC handler.
++
++ /* see if the nmi watchdog went off */
++ if (wd->enabled) {
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ rdmsrl(wd->perfctr_msr, dummy);
++ if (dummy & wd->check_bit){
++ /* this wasn't a watchdog timer interrupt */
++ goto done;
++ }
++
++ /* only Intel uses the cccr msr */
++ if (wd->cccr_msr != 0) {
++ /*
++ * P4 quirks:
++ * - An overflown perfctr will assert its interrupt
++ * until the OVF flag in its CCCR is cleared.
++ * - LVTPC is masked on interrupt and must be
++ * unmasked by the LVTPC handler.
++ */
++ rdmsrl(wd->cccr_msr, dummy);
++ dummy &= ~P4_CCCR_OVF;
++ wrmsrl(wd->cccr_msr, dummy);
++ apic_write(APIC_LVTPC, APIC_DM_NMI);
++ } else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
++ /*
++ * ArchPerfom/Core Duo needs to re-unmask
++ * the apic vector
++ */
++ apic_write(APIC_LVTPC, APIC_DM_NMI);
++ }
++ /* start the cycle over again */
++ wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
++ rc = 1;
++ } else if (nmi_watchdog == NMI_IO_APIC) {
++ /* don't know how to accurately check for this.
++ * just assume it was a watchdog timer interrupt
++ * This matches the old behaviour.
+ */
+- apic_write(APIC_LVTPC, APIC_DM_NMI);
+- }
+- wrmsrl(nmi_perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
++ rc = 1;
++ } else
++ printk(KERN_WARNING "Unknown enabled NMI hardware?!\n");
+ }
++done:
++ return rc;
+ }
+
+-static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu)
+-{
+- return 0;
+-}
+-
+-static nmi_callback_t nmi_callback = dummy_nmi_callback;
+-
+ asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
+ {
+- int cpu = safe_smp_processor_id();
+-
+ nmi_enter();
+ add_pda(__nmi_count,1);
+- if (!rcu_dereference(nmi_callback)(regs, cpu))
+- default_do_nmi(regs);
++ default_do_nmi(regs);
+ nmi_exit();
+ }
+
+-void set_nmi_callback(nmi_callback_t callback)
++int do_nmi_callback(struct pt_regs * regs, int cpu)
+ {
+- vmalloc_sync_all();
+- rcu_assign_pointer(nmi_callback, callback);
+-}
+-EXPORT_SYMBOL_GPL(set_nmi_callback);
+-
+-void unset_nmi_callback(void)
+-{
+- nmi_callback = dummy_nmi_callback;
++#ifdef CONFIG_SYSCTL
++ if (unknown_nmi_panic)
++ return unknown_nmi_panic_callback(regs, cpu);
++#endif
++ return 0;
+ }
+-EXPORT_SYMBOL_GPL(unset_nmi_callback);
+
+ #ifdef CONFIG_SYSCTL
+
+@@ -621,36 +889,42 @@ static int unknown_nmi_panic_callback(st
+ unsigned char reason = get_nmi_reason();
+ char buf[64];
+
+- if (!(reason & 0xc0)) {
+- sprintf(buf, "NMI received for unknown reason %02x\n", reason);
+- die_nmi(buf,regs);
+- }
++ sprintf(buf, "NMI received for unknown reason %02x\n", reason);
++ die_nmi(buf, regs, 1); /* Always panic here */
+ return 0;
+ }
+
+ /*
+- * proc handler for /proc/sys/kernel/unknown_nmi_panic
++ * proc handler for /proc/sys/kernel/nmi
+ */
+-int proc_unknown_nmi_panic(struct ctl_table *table, int write, struct file *file,
++int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
+ void __user *buffer, size_t *length, loff_t *ppos)
+ {
+ int old_state;
+
+- old_state = unknown_nmi_panic;
++ nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
++ old_state = nmi_watchdog_enabled;
+ proc_dointvec(table, write, file, buffer, length, ppos);
+- if (!!old_state == !!unknown_nmi_panic)
++ if (!!old_state == !!nmi_watchdog_enabled)
+ return 0;
+
+- if (unknown_nmi_panic) {
+- if (reserve_lapic_nmi() < 0) {
+- unknown_nmi_panic = 0;
+- return -EBUSY;
+- } else {
+- set_nmi_callback(unknown_nmi_panic_callback);
+- }
++ if (atomic_read(&nmi_active) < 0) {
++ printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
++ return -EIO;
++ }
++
++ /* if nmi_watchdog is not set yet, then set it */
++ nmi_watchdog_default();
++
++ if (nmi_watchdog == NMI_LOCAL_APIC) {
++ if (nmi_watchdog_enabled)
++ enable_lapic_nmi_watchdog();
++ else
++ disable_lapic_nmi_watchdog();
+ } else {
+- release_lapic_nmi();
+- unset_nmi_callback();
++ printk( KERN_WARNING
++ "NMI watchdog doesn't know what hardware to touch\n");
++ return -EIO;
+ }
+ return 0;
+ }
+@@ -659,8 +933,12 @@ int proc_unknown_nmi_panic(struct ctl_ta
+
+ EXPORT_SYMBOL(nmi_active);
+ EXPORT_SYMBOL(nmi_watchdog);
+-EXPORT_SYMBOL(reserve_lapic_nmi);
+-EXPORT_SYMBOL(release_lapic_nmi);
++EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
++EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
++EXPORT_SYMBOL(reserve_perfctr_nmi);
++EXPORT_SYMBOL(release_perfctr_nmi);
++EXPORT_SYMBOL(reserve_evntsel_nmi);
++EXPORT_SYMBOL(release_evntsel_nmi);
+ EXPORT_SYMBOL(disable_timer_nmi_watchdog);
+ EXPORT_SYMBOL(enable_timer_nmi_watchdog);
+ EXPORT_SYMBOL(touch_nmi_watchdog);
+diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
+index 146924b..37a7708 100644
+--- a/arch/x86_64/kernel/pci-calgary.c
++++ b/arch/x86_64/kernel/pci-calgary.c
+@@ -2,8 +2,9 @@
+ * Derived from arch/powerpc/kernel/iommu.c
+ *
+ * Copyright (C) IBM Corporation, 2006
++ * Copyright (C) 2006 Jon Mason <jdmason at kudzu.us>
+ *
+- * Author: Jon Mason <jdmason at us.ibm.com>
++ * Author: Jon Mason <jdmason at kudzu.us>
+ * Author: Muli Ben-Yehuda <muli at il.ibm.com>
+
+ * This program is free software; you can redistribute it and/or modify
+@@ -21,7 +22,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+@@ -52,7 +52,8 @@
+ #define ONE_BASED_CHASSIS_NUM 1
+
+ /* register offsets inside the host bridge space */
+-#define PHB_CSR_OFFSET 0x0110
++#define CALGARY_CONFIG_REG 0x0108
++#define PHB_CSR_OFFSET 0x0110 /* Channel Status */
+ #define PHB_PLSSR_OFFSET 0x0120
+ #define PHB_CONFIG_RW_OFFSET 0x0160
+ #define PHB_IOBASE_BAR_LOW 0x0170
+@@ -83,10 +84,13 @@
+ #define TAR_VALID 0x0000000000000008UL
+ /* CSR (Channel/DMA Status Register) */
+ #define CSR_AGENT_MASK 0xffe0ffff
++/* CCR (Calgary Configuration Register) */
++#define CCR_2SEC_TIMEOUT 0x000000000000000EUL
+
+ #define MAX_NUM_OF_PHBS 8 /* how many PHBs in total? */
+ #define MAX_NUM_CHASSIS 8 /* max number of chassis */
+-#define MAX_PHB_BUS_NUM (MAX_NUM_OF_PHBS * MAX_NUM_CHASSIS * 2) /* max dev->bus->number */
++/* MAX_PHB_BUS_NUM is the maximal possible dev->bus->number */
++#define MAX_PHB_BUS_NUM (MAX_NUM_OF_PHBS * MAX_NUM_CHASSIS * 2)
+ #define PHBS_PER_CALGARY 4
+
+ /* register offsets in Calgary's internal register space */
+@@ -111,31 +115,49 @@ static const unsigned long phb_offsets[]
+ 0xB000 /* PHB3 */
+ };
+
+-static char bus_to_phb[MAX_PHB_BUS_NUM];
+-void* tce_table_kva[MAX_PHB_BUS_NUM];
+ unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED;
+ static int translate_empty_slots __read_mostly = 0;
+ static int calgary_detected __read_mostly = 0;
+
+-/*
+- * the bitmap of PHBs the user requested that we disable
+- * translation on.
+- */
+-static DECLARE_BITMAP(translation_disabled, MAX_PHB_BUS_NUM);
++struct calgary_bus_info {
++ void *tce_space;
++ unsigned char translation_disabled;
++ signed char phbid;
++};
++
++static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
+
+ static void tce_cache_blast(struct iommu_table *tbl);
+
+ /* enable this to stress test the chip's TCE cache */
+ #ifdef CONFIG_IOMMU_DEBUG
+-static inline void tce_cache_blast_stress(struct iommu_table *tbl)
++int debugging __read_mostly = 1;
++
++static inline unsigned long verify_bit_range(unsigned long* bitmap,
++ int expected, unsigned long start, unsigned long end)
+ {
+- tce_cache_blast(tbl);
++ unsigned long idx = start;
++
++ BUG_ON(start >= end);
++
++ while (idx < end) {
++ if (!!test_bit(idx, bitmap) != expected)
++ return idx;
++ ++idx;
++ }
++
++ /* all bits have the expected value */
++ return ~0UL;
+ }
+-#else
+-static inline void tce_cache_blast_stress(struct iommu_table *tbl)
++#else /* debugging is disabled */
++int debugging __read_mostly = 0;
++
++static inline unsigned long verify_bit_range(unsigned long* bitmap,
++ int expected, unsigned long start, unsigned long end)
+ {
++ return ~0UL;
+ }
+-#endif /* BLAST_TCE_CACHE_ON_UNMAP */
++#endif /* CONFIG_IOMMU_DEBUG */
+
+ static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
+ {
+@@ -149,7 +171,7 @@ static inline unsigned int num_dma_pages
+
+ static inline int translate_phb(struct pci_dev* dev)
+ {
+- int disabled = test_bit(dev->bus->number, translation_disabled);
++ int disabled = bus_info[dev->bus->number].translation_disabled;
+ return !disabled;
+ }
+
+@@ -158,6 +180,7 @@ static void iommu_range_reserve(struct i
+ {
+ unsigned long index;
+ unsigned long end;
++ unsigned long badbit;
+
+ index = start_addr >> PAGE_SHIFT;
+
+@@ -169,14 +192,15 @@ static void iommu_range_reserve(struct i
+ if (end > tbl->it_size) /* don't go off the table */
+ end = tbl->it_size;
+
+- while (index < end) {
+- if (test_bit(index, tbl->it_map))
++ badbit = verify_bit_range(tbl->it_map, 0, index, end);
++ if (badbit != ~0UL) {
++ if (printk_ratelimit())
+ printk(KERN_ERR "Calgary: entry already allocated at "
+ "0x%lx tbl %p dma 0x%lx npages %u\n",
+- index, tbl, start_addr, npages);
+- ++index;
++ badbit, tbl, start_addr, npages);
+ }
+- set_bit_string(tbl->it_map, start_addr >> PAGE_SHIFT, npages);
++
++ set_bit_string(tbl->it_map, index, npages);
+ }
+
+ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
+@@ -243,7 +267,7 @@ static void __iommu_free(struct iommu_ta
+ unsigned int npages)
+ {
+ unsigned long entry;
+- unsigned long i;
++ unsigned long badbit;
+
+ entry = dma_addr >> PAGE_SHIFT;
+
+@@ -251,16 +275,15 @@ static void __iommu_free(struct iommu_ta
+
+ tce_free(tbl, entry, npages);
+
+- for (i = 0; i < npages; ++i) {
+- if (!test_bit(entry + i, tbl->it_map))
++ badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages);
++ if (badbit != ~0UL) {
++ if (printk_ratelimit())
+ printk(KERN_ERR "Calgary: bit is off at 0x%lx "
+ "tbl %p dma 0x%Lx entry 0x%lx npages %u\n",
+- entry + i, tbl, dma_addr, entry, npages);
++ badbit, tbl, dma_addr, entry, npages);
+ }
+
+ __clear_bit_string(tbl->it_map, entry, npages);
+-
+- tce_cache_blast_stress(tbl);
+ }
+
+ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
+@@ -454,7 +477,7 @@ static struct dma_mapping_ops calgary_dm
+
+ static inline int busno_to_phbid(unsigned char num)
+ {
+- return bus_to_phb[num];
++ return bus_info[num].phbid;
+ }
+
+ static inline unsigned long split_queue_offset(unsigned char num)
+@@ -631,6 +654,10 @@ static int __init calgary_setup_tar(stru
+ if (ret)
+ return ret;
+
++ tbl = dev->sysdata;
++ tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
++ tce_free(tbl, 0, tbl->it_size);
++
+ calgary_reserve_regions(dev);
+
+ /* set TARs for each PHB */
+@@ -654,11 +681,12 @@ static int __init calgary_setup_tar(stru
+ return 0;
+ }
+
+-static void __init calgary_free_tar(struct pci_dev *dev)
++static void __init calgary_free_bus(struct pci_dev *dev)
+ {
+ u64 val64;
+ struct iommu_table *tbl = dev->sysdata;
+ void __iomem *target;
++ unsigned int bitmapsz;
+
+ target = calgary_reg(tbl->bbar, tar_offset(dev->bus->number));
+ val64 = be64_to_cpu(readq(target));
+@@ -666,8 +694,15 @@ static void __init calgary_free_tar(stru
+ writeq(cpu_to_be64(val64), target);
+ readq(target); /* flush */
+
++ bitmapsz = tbl->it_size / BITS_PER_BYTE;
++ free_pages((unsigned long)tbl->it_map, get_order(bitmapsz));
++ tbl->it_map = NULL;
++
+ kfree(tbl);
+ dev->sysdata = NULL;
++
++ /* Can't free bootmem allocated memory after system is up :-( */
++ bus_info[dev->bus->number].tce_space = NULL;
+ }
+
+ static void calgary_watchdog(unsigned long data)
+@@ -683,7 +718,7 @@ static void calgary_watchdog(unsigned lo
+
+ /* If no error, the agent ID in the CSR is not valid */
+ if (val32 & CSR_AGENT_MASK) {
+- printk(KERN_EMERG "calgary_watchdog: DMA error on bus %d, "
++ printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, "
+ "CSR = %#x\n", dev->bus->number, val32);
+ writel(0, target);
+
+@@ -700,6 +735,38 @@ static void calgary_watchdog(unsigned lo
+ }
+ }
+
++static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
++ unsigned char busnum)
++{
++ u64 val64;
++ void __iomem *target;
++ unsigned long phb_shift = -1;
++ u64 mask;
++
++ switch (busno_to_phbid(busnum)) {
++ case 0: phb_shift = (63 - 19);
++ break;
++ case 1: phb_shift = (63 - 23);
++ break;
++ case 2: phb_shift = (63 - 27);
++ break;
++ case 3: phb_shift = (63 - 35);
++ break;
++ default:
++ BUG_ON(busno_to_phbid(busnum));
++ }
++
++ target = calgary_reg(bbar, CALGARY_CONFIG_REG);
++ val64 = be64_to_cpu(readq(target));
++
++ /* zero out this PHB's timer bits */
++ mask = ~(0xFUL << phb_shift);
++ val64 &= mask;
++ val64 |= (CCR_2SEC_TIMEOUT << phb_shift);
++ writeq(cpu_to_be64(val64), target);
++ readq(target); /* flush */
++}
++
+ static void __init calgary_enable_translation(struct pci_dev *dev)
+ {
+ u32 val32;
+@@ -717,13 +784,20 @@ static void __init calgary_enable_transl
+ val32 = be32_to_cpu(readl(target));
+ val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;
+
+- printk(KERN_INFO "Calgary: enabling translation on PHB %d\n", busnum);
++ printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum);
+ printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
+ "bus.\n");
+
+ writel(cpu_to_be32(val32), target);
+ readl(target); /* flush */
+
++ /*
++ * Give split completion a longer timeout on bus 1 for aic94xx
++ * http://bugzilla.kernel.org/show_bug.cgi?id=7180
++ */
++ if (busnum == 1)
++ calgary_increase_split_completion_timeout(bbar, busnum);
++
+ init_timer(&tbl->watchdog_timer);
+ tbl->watchdog_timer.function = &calgary_watchdog;
+ tbl->watchdog_timer.data = (unsigned long)dev;
+@@ -747,7 +821,7 @@ static void __init calgary_disable_trans
+ val32 = be32_to_cpu(readl(target));
+ val32 &= ~(PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE);
+
+- printk(KERN_INFO "Calgary: disabling translation on PHB %d!\n", busnum);
++ printk(KERN_INFO "Calgary: disabling translation on PHB %#x!\n", busnum);
+ writel(cpu_to_be32(val32), target);
+ readl(target); /* flush */
+
+@@ -759,7 +833,16 @@ static inline unsigned int __init locate
+ int rionodeid;
+ u32 address;
+
+- rionodeid = (dev->bus->number % 15 > 4) ? 3 : 2;
++ /*
++ * Each Calgary has four busses. The first four busses (first Calgary)
++ * have RIO node ID 2, then the next four (second Calgary) have RIO
++ * node ID 3, the next four (third Calgary) have node ID 2 again, etc.
++ * We use a gross hack - relying on the dev->bus->number ordering,
++ * modulo 14 - to decide which Calgary a given bus is on. Busses 0, 1,
++ * 2 and 4 are on the first Calgary (id 2), 6, 8, a and c are on the
++ * second (id 3), and then it repeats modulo 14.
++ */
++ rionodeid = (dev->bus->number % 14 > 4) ? 3 : 2;
+ /*
+ * register space address calculation as follows:
+ * FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase)
+@@ -767,17 +850,16 @@ static inline unsigned int __init locate
+ * RioNodeId is 2 for first Calgary, 3 for second Calgary
+ */
+ address = START_ADDRESS -
+- (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 15)) +
++ (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 14)) +
+ (0x100000) * (rionodeid - CHASSIS_BASE);
+ return address;
+ }
+
+-static int __init calgary_init_one_nontraslated(struct pci_dev *dev)
++static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
+ {
++ pci_dev_get(dev);
+ dev->sysdata = NULL;
+ dev->bus->self = dev;
+-
+- return 0;
+ }
+
+ static int __init calgary_init_one(struct pci_dev *dev)
+@@ -786,6 +868,8 @@ static int __init calgary_init_one(struc
+ void __iomem *bbar;
+ int ret;
+
++ BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
++
+ address = locate_register_space(dev);
+ /* map entire 1MB of Calgary config space */
+ bbar = ioremap_nocache(address, 1024 * 1024);
+@@ -798,6 +882,7 @@ static int __init calgary_init_one(struc
+ if (ret)
+ goto iounmap;
+
++ pci_dev_get(dev);
+ dev->bus->self = dev;
+ calgary_enable_translation(dev);
+
+@@ -811,10 +896,10 @@ done:
+
+ static int __init calgary_init(void)
+ {
+- int i, ret = -ENODEV;
++ int ret = -ENODEV;
+ struct pci_dev *dev = NULL;
+
+- for (i = 0; i < MAX_PHB_BUS_NUM; i++) {
++ do {
+ dev = pci_get_device(PCI_VENDOR_ID_IBM,
+ PCI_DEVICE_ID_IBM_CALGARY,
+ dev);
+@@ -824,32 +909,34 @@ static int __init calgary_init(void)
+ calgary_init_one_nontraslated(dev);
+ continue;
+ }
+- if (!tce_table_kva[dev->bus->number] && !translate_empty_slots) {
+- pci_dev_put(dev);
++ if (!bus_info[dev->bus->number].tce_space && !translate_empty_slots)
+ continue;
+- }
++
+ ret = calgary_init_one(dev);
+ if (ret)
+ goto error;
+- }
++ } while (1);
+
+ return ret;
+
+ error:
+- for (i--; i >= 0; i--) {
++ do {
+ dev = pci_find_device_reverse(PCI_VENDOR_ID_IBM,
+ PCI_DEVICE_ID_IBM_CALGARY,
+ dev);
++ if (!dev)
++ break;
+ if (!translate_phb(dev)) {
+ pci_dev_put(dev);
+ continue;
+ }
+- if (!tce_table_kva[dev->bus->number] && !translate_empty_slots)
++ if (!bus_info[dev->bus->number].tce_space && !translate_empty_slots)
+ continue;
++
+ calgary_disable_translation(dev);
+- calgary_free_tar(dev);
+- pci_dev_put(dev);
+- }
++ calgary_free_bus(dev);
++ pci_dev_put(dev); /* Undo calgary_init_one()'s pci_dev_get() */
++ } while (1);
+
+ return ret;
+ }
+@@ -890,13 +977,15 @@ void __init detect_calgary(void)
+ if (swiotlb || no_iommu || iommu_detected)
+ return;
+
++ if (!early_pci_allowed())
++ return;
++
+ specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
+
+ for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
+ int dev;
+-
+- tce_table_kva[bus] = NULL;
+- bus_to_phb[bus] = -1;
++ struct calgary_bus_info *info = &bus_info[bus];
++ info->phbid = -1;
+
+ if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
+ continue;
+@@ -907,12 +996,9 @@ void __init detect_calgary(void)
+ */
+ phb = (phb + 1) % PHBS_PER_CALGARY;
+
+- if (test_bit(bus, translation_disabled)) {
+- printk(KERN_INFO "Calgary: translation is disabled for "
+- "PHB 0x%x\n", bus);
+- /* skip this phb, don't allocate a tbl for it */
++ if (info->translation_disabled)
+ continue;
+- }
++
+ /*
+ * Scan the slots of the PCI bus to see if there is a device present.
+ * The parent bus will be the zero-ith device, so start at 1.
+@@ -923,8 +1009,8 @@ void __init detect_calgary(void)
+ tbl = alloc_tce_table();
+ if (!tbl)
+ goto cleanup;
+- tce_table_kva[bus] = tbl;
+- bus_to_phb[bus] = phb;
++ info->tce_space = tbl;
++ info->phbid = phb;
+ calgary_found = 1;
+ break;
+ }
+@@ -934,15 +1020,20 @@ void __init detect_calgary(void)
+ if (calgary_found) {
+ iommu_detected = 1;
+ calgary_detected = 1;
+- printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected. "
+- "TCE table spec is %d.\n", specified_table_size);
++ printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected.\n");
++ printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d, "
++ "CONFIG_IOMMU_DEBUG is %s.\n", specified_table_size,
++ debugging ? "enabled" : "disabled");
+ }
+ return;
+
+ cleanup:
+- for (--bus; bus >= 0; --bus)
+- if (tce_table_kva[bus])
+- free_tce_table(tce_table_kva[bus]);
++ for (--bus; bus >= 0; --bus) {
++ struct calgary_bus_info *info = &bus_info[bus];
++
++ if (info->tce_space)
++ free_tce_table(info->tce_space);
++ }
+ }
+
+ int __init calgary_iommu_init(void)
+@@ -1015,8 +1106,8 @@ static int __init calgary_parse_options(
+
+ if (bridge < MAX_PHB_BUS_NUM) {
+ printk(KERN_INFO "Calgary: disabling "
+- "translation for PHB 0x%x\n", bridge);
+- set_bit(bridge, translation_disabled);
++ "translation for PHB %#x\n", bridge);
++ bus_info[bridge].translation_disabled = 1;
+ }
+ }
+
+diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
+index 9c44f4f..f8d8574 100644
+--- a/arch/x86_64/kernel/pci-dma.c
++++ b/arch/x86_64/kernel/pci-dma.c
+@@ -170,8 +170,20 @@ void dma_free_coherent(struct device *de
+ }
+ EXPORT_SYMBOL(dma_free_coherent);
+
++static int forbid_dac __read_mostly;
++
+ int dma_supported(struct device *dev, u64 mask)
+ {
++#ifdef CONFIG_PCI
++ if (mask > 0xffffffff && forbid_dac > 0) {
++
++
++
++ printk(KERN_INFO "PCI: Disallowing DAC for device %s\n", dev->bus_id);
++ return 0;
++ }
++#endif
++
+ if (dma_ops->dma_supported)
+ return dma_ops->dma_supported(dev, mask);
+
+@@ -231,56 +243,66 @@ EXPORT_SYMBOL(dma_set_mask);
+ allowed overwrite iommu off workarounds for specific chipsets.
+ soft Use software bounce buffering (default for Intel machines)
+ noaperture Don't touch the aperture for AGP.
++ allowdac Allow DMA >4GB
++ nodac Forbid DMA >4GB
++ panic Force panic when IOMMU overflows
+ */
+ __init int iommu_setup(char *p)
+ {
+- iommu_merge = 1;
+-
+- while (*p) {
+- if (!strncmp(p,"off",3))
+- no_iommu = 1;
+- /* gart_parse_options has more force support */
+- if (!strncmp(p,"force",5))
+- force_iommu = 1;
+- if (!strncmp(p,"noforce",7)) {
+- iommu_merge = 0;
+- force_iommu = 0;
+- }
+-
+- if (!strncmp(p, "biomerge",8)) {
+- iommu_bio_merge = 4096;
+- iommu_merge = 1;
+- force_iommu = 1;
+- }
+- if (!strncmp(p, "panic",5))
+- panic_on_overflow = 1;
+- if (!strncmp(p, "nopanic",7))
+- panic_on_overflow = 0;
+- if (!strncmp(p, "merge",5)) {
+- iommu_merge = 1;
+- force_iommu = 1;
+- }
+- if (!strncmp(p, "nomerge",7))
+- iommu_merge = 0;
+- if (!strncmp(p, "forcesac",8))
+- iommu_sac_force = 1;
++ iommu_merge = 1;
++
++ if (!p)
++ return -EINVAL;
++
++ while (*p) {
++ if (!strncmp(p,"off",3))
++ no_iommu = 1;
++ /* gart_parse_options has more force support */
++ if (!strncmp(p,"force",5))
++ force_iommu = 1;
++ if (!strncmp(p,"noforce",7)) {
++ iommu_merge = 0;
++ force_iommu = 0;
++ }
++
++ if (!strncmp(p, "biomerge",8)) {
++ iommu_bio_merge = 4096;
++ iommu_merge = 1;
++ force_iommu = 1;
++ }
++ if (!strncmp(p, "panic",5))
++ panic_on_overflow = 1;
++ if (!strncmp(p, "nopanic",7))
++ panic_on_overflow = 0;
++ if (!strncmp(p, "merge",5)) {
++ iommu_merge = 1;
++ force_iommu = 1;
++ }
++ if (!strncmp(p, "nomerge",7))
++ iommu_merge = 0;
++ if (!strncmp(p, "forcesac",8))
++ iommu_sac_force = 1;
++ if (!strncmp(p, "allowdac", 8))
++ forbid_dac = 0;
++ if (!strncmp(p, "nodac", 5))
++ forbid_dac = -1;
+
+ #ifdef CONFIG_SWIOTLB
+- if (!strncmp(p, "soft",4))
+- swiotlb = 1;
++ if (!strncmp(p, "soft",4))
++ swiotlb = 1;
+ #endif
+
+ #ifdef CONFIG_IOMMU
+- gart_parse_options(p);
++ gart_parse_options(p);
+ #endif
+
+- p += strcspn(p, ",");
+- if (*p == ',')
+- ++p;
+- }
+- return 1;
++ p += strcspn(p, ",");
++ if (*p == ',')
++ ++p;
++ }
++ return 0;
+ }
+-__setup("iommu=", iommu_setup);
++early_param("iommu", iommu_setup);
+
+ void __init pci_iommu_alloc(void)
+ {
+diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
+index 6d3e61b..16261a8 100644
+--- a/arch/x86_64/kernel/pci-gart.c
++++ b/arch/x86_64/kernel/pci-gart.c
+@@ -239,8 +239,6 @@ dma_addr_t gart_map_single(struct device
+ {
+ unsigned long phys_mem, bus;
+
+- BUG_ON(dir == DMA_NONE);
+-
+ if (!dev)
+ dev = &fallback_dev;
+
+@@ -383,7 +381,6 @@ int gart_map_sg(struct device *dev, stru
+ unsigned long pages = 0;
+ int need = 0, nextneed;
+
+- BUG_ON(dir == DMA_NONE);
+ if (nents == 0)
+ return 0;
+
+diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
+index aad7609..df09ab0 100644
+--- a/arch/x86_64/kernel/pci-nommu.c
++++ b/arch/x86_64/kernel/pci-nommu.c
+@@ -59,7 +59,6 @@ int nommu_map_sg(struct device *hwdev, s
+ {
+ int i;
+
+- BUG_ON(direction == DMA_NONE);
+ for (i = 0; i < nents; i++ ) {
+ struct scatterlist *s = &sg[i];
+ BUG_ON(!s->page);
+diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
+index 6a55f87..697f0aa 100644
+--- a/arch/x86_64/kernel/pci-swiotlb.c
++++ b/arch/x86_64/kernel/pci-swiotlb.c
+@@ -3,7 +3,8 @@
+ #include <linux/pci.h>
+ #include <linux/cache.h>
+ #include <linux/module.h>
+-#include <asm/dma-mapping.h>
++#include <linux/dma-mapping.h>
++
+ #include <asm/proto.h>
+ #include <asm/swiotlb.h>
+ #include <asm/dma.h>
+diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
+index bb6745d..49f7fac 100644
+--- a/arch/x86_64/kernel/process.c
++++ b/arch/x86_64/kernel/process.c
+@@ -80,25 +80,25 @@ void idle_notifier_unregister(struct not
+ }
+ EXPORT_SYMBOL(idle_notifier_unregister);
+
+-enum idle_state { CPU_IDLE, CPU_NOT_IDLE };
+-static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE;
+-
+ void enter_idle(void)
+ {
+- __get_cpu_var(idle_state) = CPU_IDLE;
++ write_pda(isidle, 1);
+ atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
+ }
+
+ static void __exit_idle(void)
+ {
+- __get_cpu_var(idle_state) = CPU_NOT_IDLE;
++ if (read_pda(isidle) == 0)
++ return;
++ write_pda(isidle, 0);
+ atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
+ }
+
+ /* Called from interrupts to signify idle end */
+ void exit_idle(void)
+ {
+- if (current->pid | read_pda(irqcount))
++ /* idle loop has pid 0 */
++ if (current->pid)
+ return;
+ __exit_idle();
+ }
+@@ -220,6 +220,9 @@ void cpu_idle (void)
+ play_dead();
+ enter_idle();
+ idle();
++ /* In many cases the interrupt that ended idle
++ has already called exit_idle. But some idle
++ loops can be woken up without interrupt. */
+ __exit_idle();
+ }
+
+@@ -235,20 +238,28 @@ void cpu_idle (void)
+ * We execute MONITOR against need_resched and enter optimized wait state
+ * through MWAIT. Whenever someone changes need_resched, we would be woken
+ * up from MWAIT (without an IPI).
++ *
++ * New with Core Duo processors, MWAIT can take some hints based on CPU
++ * capability.
+ */
+-static void mwait_idle(void)
++void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
+ {
+- local_irq_enable();
+-
+- while (!need_resched()) {
++ if (!need_resched()) {
+ __monitor((void *)¤t_thread_info()->flags, 0, 0);
+ smp_mb();
+- if (need_resched())
+- break;
+- __mwait(0, 0);
++ if (!need_resched())
++ __mwait(eax, ecx);
+ }
+ }
+
++/* Default MONITOR/MWAIT with no hints, used for default C1 state */
++static void mwait_idle(void)
++{
++ local_irq_enable();
++ while (!need_resched())
++ mwait_idle_with_hints(0,0);
++}
++
+ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
+ {
+ static int printed;
+@@ -291,9 +302,9 @@ void __show_regs(struct pt_regs * regs)
+ print_modules();
+ printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+ current->pid, current->comm, print_tainted(),
+- system_utsname.release,
+- (int)strcspn(system_utsname.version, " "),
+- system_utsname.version);
++ init_utsname()->release,
++ (int)strcspn(init_utsname()->version, " "),
++ init_utsname()->version);
+ printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
+ printk_address(regs->rip);
+ printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp,
+@@ -350,6 +361,7 @@ void exit_thread(void)
+
+ kfree(t->io_bitmap_ptr);
+ t->io_bitmap_ptr = NULL;
++ clear_thread_flag(TIF_IO_BITMAP);
+ /*
+ * Careful, clear this in the TSS too:
+ */
+@@ -369,6 +381,7 @@ void flush_thread(void)
+ if (t->flags & _TIF_IA32)
+ current_thread_info()->status |= TS_COMPAT;
+ }
++ t->flags &= ~_TIF_DEBUG;
+
+ tsk->thread.debugreg0 = 0;
+ tsk->thread.debugreg1 = 0;
+@@ -461,7 +474,7 @@ int copy_thread(int nr, unsigned long cl
+ asm("mov %%es,%0" : "=m" (p->thread.es));
+ asm("mov %%ds,%0" : "=m" (p->thread.ds));
+
+- if (unlikely(me->thread.io_bitmap_ptr != NULL)) {
++ if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
+ p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
+ if (!p->thread.io_bitmap_ptr) {
+ p->thread.io_bitmap_max = 0;
+@@ -469,6 +482,7 @@ int copy_thread(int nr, unsigned long cl
+ }
+ memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr,
+ IO_BITMAP_BYTES);
++ set_tsk_thread_flag(p, TIF_IO_BITMAP);
+ }
+
+ /*
+@@ -498,6 +512,40 @@ out:
+ */
+ #define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r)
+
++static inline void __switch_to_xtra(struct task_struct *prev_p,
++ struct task_struct *next_p,
++ struct tss_struct *tss)
++{
++ struct thread_struct *prev, *next;
++
++ prev = &prev_p->thread,
++ next = &next_p->thread;
++
++ if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
++ loaddebug(next, 0);
++ loaddebug(next, 1);
++ loaddebug(next, 2);
++ loaddebug(next, 3);
++ /* no 4 and 5 */
++ loaddebug(next, 6);
++ loaddebug(next, 7);
++ }
++
++ if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
++ /*
++ * Copy the relevant range of the IO bitmap.
++ * Normally this is 128 bytes or less:
++ */
++ memcpy(tss->io_bitmap, next->io_bitmap_ptr,
++ max(prev->io_bitmap_max, next->io_bitmap_max));
++ } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) {
++ /*
++ * Clear any possible leftover bits:
++ */
++ memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
++ }
++}
++
+ /*
+ * switch_to(x,y) should switch tasks from x to y.
+ *
+@@ -515,6 +563,10 @@ __switch_to(struct task_struct *prev_p,
+ int cpu = smp_processor_id();
+ struct tss_struct *tss = &per_cpu(init_tss, cpu);
+
++ /* we're going to use this soon, after a few expensive things */
++ if (next_p->fpu_counter>5)
++ prefetch(&next->i387.fxsave);
++
+ /*
+ * Reload esp0, LDT and the page table pointer:
+ */
+@@ -571,6 +623,9 @@ __switch_to(struct task_struct *prev_p,
+ prev->gsindex = gsindex;
+ }
+
++ /* Must be after DS reload */
++ unlazy_fpu(prev_p);
++
+ /*
+ * Switch the PDA and FPU contexts.
+ */
+@@ -578,46 +633,30 @@ __switch_to(struct task_struct *prev_p,
+ write_pda(oldrsp, next->userrsp);
+ write_pda(pcurrent, next_p);
+
+- /* This must be here to ensure both math_state_restore() and
+- kernel_fpu_begin() work consistently.
+- And the AMD workaround requires it to be after DS reload. */
+- unlazy_fpu(prev_p);
+ write_pda(kernelstack,
+- task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
+-
++ (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
++#ifdef CONFIG_CC_STACKPROTECTOR
++ write_pda(stack_canary, next_p->stack_canary);
+ /*
+- * Now maybe reload the debug registers
++ * Build time only check to make sure the stack_canary is at
++ * offset 40 in the pda; this is a gcc ABI requirement
+ */
+- if (unlikely(next->debugreg7)) {
+- loaddebug(next, 0);
+- loaddebug(next, 1);
+- loaddebug(next, 2);
+- loaddebug(next, 3);
+- /* no 4 and 5 */
+- loaddebug(next, 6);
+- loaddebug(next, 7);
+- }
+-
++ BUILD_BUG_ON(offsetof(struct x8664_pda, stack_canary) != 40);
++#endif
+
+- /*
+- * Handle the IO bitmap
+- */
+- if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
+- if (next->io_bitmap_ptr)
+- /*
+- * Copy the relevant range of the IO bitmap.
+- * Normally this is 128 bytes or less:
+- */
+- memcpy(tss->io_bitmap, next->io_bitmap_ptr,
+- max(prev->io_bitmap_max, next->io_bitmap_max));
+- else {
+- /*
+- * Clear any possible leftover bits:
+- */
+- memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
+- }
+- }
++ /*
++ * Now maybe reload the debug registers and handle I/O bitmaps
++ */
++ if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW))
++ || test_tsk_thread_flag(prev_p, TIF_IO_BITMAP))
++ __switch_to_xtra(prev_p, next_p, tss);
+
++ /* If the task has used fpu the last 5 timeslices, just do a full
++ * restore of the math state immediately to avoid the trap; the
++ * chances of needing FPU soon are obviously high now
++ */
++ if (next_p->fpu_counter>5)
++ math_state_restore();
+ return prev_p;
+ }
+
+@@ -834,7 +873,7 @@ int dump_task_regs(struct task_struct *t
+
+ unsigned long arch_align_stack(unsigned long sp)
+ {
+- if (randomize_va_space)
++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ sp -= get_random_int() % 8192;
+ return sp & ~0xf;
+ }
+diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
+index 2d50024..addc14a 100644
+--- a/arch/x86_64/kernel/ptrace.c
++++ b/arch/x86_64/kernel/ptrace.c
+@@ -116,17 +116,17 @@ unsigned long convert_rip_to_linear(stru
+ return addr;
+ }
+
+-static int is_at_popf(struct task_struct *child, struct pt_regs *regs)
++static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
+ {
+ int i, copied;
+- unsigned char opcode[16];
++ unsigned char opcode[15];
+ unsigned long addr = convert_rip_to_linear(child, regs);
+
+ copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
+ for (i = 0; i < copied; i++) {
+ switch (opcode[i]) {
+- /* popf */
+- case 0x9d:
++ /* popf and iret */
++ case 0x9d: case 0xcf:
+ return 1;
+
+ /* CHECKME: 64 65 */
+@@ -138,14 +138,17 @@ static int is_at_popf(struct task_struct
+ case 0x26: case 0x2e:
+ case 0x36: case 0x3e:
+ case 0x64: case 0x65:
+- case 0xf0: case 0xf2: case 0xf3:
++ case 0xf2: case 0xf3:
+ continue;
+
+- /* REX prefixes */
+ case 0x40 ... 0x4f:
++ if (regs->cs != __USER_CS)
++ /* 32-bit mode: register increment */
++ return 0;
++ /* 64-bit mode: REX prefix */
+ continue;
+
+- /* CHECKME: f0, f2, f3 */
++ /* CHECKME: f2, f3 */
+
+ /*
+ * pushf: NOTE! We should probably not let
+@@ -186,10 +189,8 @@ static void set_singlestep(struct task_s
+ * ..but if TF is changed by the instruction we will trace,
+ * don't mark it as being "us" that set it, so that we
+ * won't clear it by hand later.
+- *
+- * AK: this is not enough, LAHF and IRET can change TF in user space too.
+ */
+- if (is_at_popf(child, regs))
++ if (is_setting_trap_flag(child, regs))
+ return;
+
+ child->ptrace |= PT_DTRACE;
+@@ -420,9 +421,13 @@ long arch_ptrace(struct task_struct *chi
+ if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+ break;
+ if (i == 4) {
+- child->thread.debugreg7 = data;
++ child->thread.debugreg7 = data;
++ if (data)
++ set_tsk_thread_flag(child, TIF_DEBUG);
++ else
++ clear_tsk_thread_flag(child, TIF_DEBUG);
+ ret = 0;
+- }
++ }
+ break;
+ }
+ break;
+diff --git a/arch/x86_64/kernel/relocate_kernel.S b/arch/x86_64/kernel/relocate_kernel.S
+index d24fa9b..14e9587 100644
+--- a/arch/x86_64/kernel/relocate_kernel.S
++++ b/arch/x86_64/kernel/relocate_kernel.S
+@@ -7,31 +7,169 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/page.h>
++#include <asm/kexec.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
++/*
++ * Must be relocatable PIC code callable as a C function
++ */
++
++#define PTR(x) (x << 3)
++#define PAGE_ALIGNED (1 << PAGE_SHIFT)
++#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */
++
++ .text
++ .align PAGE_ALIGNED
+ .code64
++ .globl relocate_kernel
++relocate_kernel:
++ /* %rdi indirection_page
++ * %rsi page_list
++ * %rdx start address
++ */
++
++ /* map the control page at its virtual address */
++
++ movq $0x0000ff8000000000, %r10 /* mask */
++ mov $(39 - 3), %cl /* bits to shift */
++ movq PTR(VA_CONTROL_PAGE)(%rsi), %r11 /* address to map */
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PGD)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_PUD_0)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ shrq $9, %r10
++ sub $9, %cl
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PUD_0)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_PMD_0)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ shrq $9, %r10
++ sub $9, %cl
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PMD_0)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_PTE_0)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ shrq $9, %r10
++ sub $9, %cl
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PTE_0)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ /* identity map the control page at its physical address */
++
++ movq $0x0000ff8000000000, %r10 /* mask */
++ mov $(39 - 3), %cl /* bits to shift */
++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r11 /* address to map */
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PGD)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_PUD_1)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ shrq $9, %r10
++ sub $9, %cl
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PUD_1)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_PMD_1)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ shrq $9, %r10
++ sub $9, %cl
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PMD_1)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_PTE_1)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
++ shrq $9, %r10
++ sub $9, %cl
++
++ movq %r11, %r9
++ andq %r10, %r9
++ shrq %cl, %r9
++
++ movq PTR(VA_PTE_1)(%rsi), %r8
++ addq %r8, %r9
++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r8
++ orq $PAGE_ATTR, %r8
++ movq %r8, (%r9)
++
+ relocate_new_kernel:
+- /* %rdi page_list
+- * %rsi reboot_code_buffer
++ /* %rdi indirection_page
++ * %rsi page_list
+ * %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
++ /* get physical address of control page now */
++ /* this is impossible after page table switch */
++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r8
++
++ /* get physical address of page table now too */
++ movq PTR(PA_TABLE_PAGE)(%rsi), %rcx
+
+- /* store the parameters back on the stack */
+- pushq %rdx /* store the start address */
++ /* switch to new set of page tables */
++ movq PTR(PA_PGD)(%rsi), %r9
++ movq %r9, %cr3
++
++ /* setup a new stack at the end of the physical control page */
++ lea 4096(%r8), %rsp
++
++ /* jump to identity mapped page */
++ addq $(identity_mapped - relocate_kernel), %r8
++ pushq %r8
++ ret
++
++identity_mapped:
++ /* store the start address on the stack */
++ pushq %rdx
+
+ /* Set cr0 to a known state:
+ * 31 1 == Paging enabled
+@@ -136,8 +274,3 @@ relocate_new_kernel:
+ 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 34afad7..fc944b5 100644
+--- a/arch/x86_64/kernel/setup.c
++++ b/arch/x86_64/kernel/setup.c
+@@ -74,16 +74,6 @@ EXPORT_SYMBOL(boot_cpu_data);
+
+ unsigned long mmu_cr4_features;
+
+-int acpi_disabled;
+-EXPORT_SYMBOL(acpi_disabled);
+-#ifdef CONFIG_ACPI
+-extern int __initdata acpi_ht;
+-extern acpi_interrupt_flags acpi_sci_flags;
+-int __initdata acpi_force = 0;
+-#endif
+-
+-int acpi_numa __initdata;
+-
+ /* Boot loader ID as an integer, for the benefit of proc_dointvec */
+ int bootloader_type;
+
+@@ -107,7 +97,6 @@ struct sys_desc_table_struct {
+
+ struct edid_info edid_info;
+ EXPORT_SYMBOL_GPL(edid_info);
+-struct e820map e820;
+
+ extern int root_mountflags;
+
+@@ -134,9 +123,6 @@ struct resource standard_io_resources[]
+ .flags = IORESOURCE_BUSY | IORESOURCE_IO }
+ };
+
+-#define STANDARD_IO_RESOURCES \
+- (sizeof standard_io_resources / sizeof standard_io_resources[0])
+-
+ #define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
+
+ struct resource data_resource = {
+@@ -183,9 +169,6 @@ static struct resource adapter_rom_resou
+ .flags = IORESOURCE_ROM }
+ };
+
+-#define ADAPTER_ROM_RESOURCES \
+- (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
+-
+ static struct resource video_rom_resource = {
+ .name = "Video ROM",
+ .start = 0xc0000,
+@@ -256,7 +239,8 @@ static void __init probe_roms(void)
+ }
+
+ /* check for adapter roms on 2k boundaries */
+- for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
++ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper;
++ start += 2048) {
+ rom = isa_bus_to_virt(start);
+ if (!romsignature(rom))
+ continue;
+@@ -276,185 +260,22 @@ static void __init probe_roms(void)
+ }
+ }
+
+-/* Check for full argument with no trailing characters */
+-static int fullarg(char *p, char *arg)
++#ifdef CONFIG_PROC_VMCORE
++/* elfcorehdr= specifies the location of elf core header
++ * stored by the crashed kernel. This option will be passed
++ * by kexec loader to the capture kernel.
++ */
++static int __init setup_elfcorehdr(char *arg)
+ {
+- int l = strlen(arg);
+- return !memcmp(p, arg, l) && (p[l] == 0 || isspace(p[l]));
++ char *end;
++ if (!arg)
++ return -EINVAL;
++ elfcorehdr_addr = memparse(arg, &end);
++ return end > arg ? 0 : -EINVAL;
+ }
+-
+-static __init void parse_cmdline_early (char ** cmdline_p)
+-{
+- char c = ' ', *to = command_line, *from = COMMAND_LINE;
+- int len = 0;
+- int userdef = 0;
+-
+- for (;;) {
+- if (c != ' ')
+- goto next_char;
+-
+-#ifdef CONFIG_SMP
+- /*
+- * If the BIOS enumerates physical processors before logical,
+- * maxcpus=N at enumeration-time can be used to disable HT.
+- */
+- else if (!memcmp(from, "maxcpus=", 8)) {
+- extern unsigned int maxcpus;
+-
+- maxcpus = simple_strtoul(from + 8, NULL, 0);
+- }
+-#endif
+-#ifdef CONFIG_ACPI
+- /* "acpi=off" disables both ACPI table parsing and interpreter init */
+- if (fullarg(from,"acpi=off"))
+- disable_acpi();
+-
+- if (fullarg(from, "acpi=force")) {
+- /* add later when we do DMI horrors: */
+- acpi_force = 1;
+- acpi_disabled = 0;
+- }
+-
+- /* acpi=ht just means: do ACPI MADT parsing
+- at bootup, but don't enable the full ACPI interpreter */
+- if (fullarg(from, "acpi=ht")) {
+- if (!acpi_force)
+- disable_acpi();
+- acpi_ht = 1;
+- }
+- else if (fullarg(from, "pci=noacpi"))
+- acpi_disable_pci();
+- else if (fullarg(from, "acpi=noirq"))
+- acpi_noirq_set();
+-
+- else if (fullarg(from, "acpi_sci=edge"))
+- acpi_sci_flags.trigger = 1;
+- else if (fullarg(from, "acpi_sci=level"))
+- acpi_sci_flags.trigger = 3;
+- else if (fullarg(from, "acpi_sci=high"))
+- acpi_sci_flags.polarity = 1;
+- else if (fullarg(from, "acpi_sci=low"))
+- acpi_sci_flags.polarity = 3;
+-
+- /* acpi=strict disables out-of-spec workarounds */
+- else if (fullarg(from, "acpi=strict")) {
+- acpi_strict = 1;
+- }
+-#ifdef CONFIG_X86_IO_APIC
+- else if (fullarg(from, "acpi_skip_timer_override"))
+- acpi_skip_timer_override = 1;
+-#endif
++early_param("elfcorehdr", setup_elfcorehdr);
+ #endif
+
+- if (fullarg(from, "disable_timer_pin_1"))
+- disable_timer_pin_1 = 1;
+- if (fullarg(from, "enable_timer_pin_1"))
+- disable_timer_pin_1 = -1;
+-
+- if (fullarg(from, "nolapic") || fullarg(from, "disableapic")) {
+- clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+- disable_apic = 1;
+- }
+-
+- if (fullarg(from, "noapic"))
+- skip_ioapic_setup = 1;
+-
+- if (fullarg(from,"apic")) {
+- skip_ioapic_setup = 0;
+- ioapic_force = 1;
+- }
+-
+- if (!memcmp(from, "mem=", 4))
+- parse_memopt(from+4, &from);
+-
+- if (!memcmp(from, "memmap=", 7)) {
+- /* exactmap option is for used defined memory */
+- 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.
+- */
+- saved_max_pfn = e820_end_of_ram();
+-#endif
+- from += 8+7;
+- end_pfn_map = 0;
+- e820.nr_map = 0;
+- userdef = 1;
+- }
+- else {
+- parse_memmapopt(from+7, &from);
+- userdef = 1;
+- }
+- }
+-
+-#ifdef CONFIG_NUMA
+- if (!memcmp(from, "numa=", 5))
+- numa_setup(from+5);
+-#endif
+-
+- if (!memcmp(from,"iommu=",6)) {
+- iommu_setup(from+6);
+- }
+-
+- if (fullarg(from,"oops=panic"))
+- panic_on_oops = 1;
+-
+- if (!memcmp(from, "noexec=", 7))
+- nonx_setup(from + 7);
+-
+-#ifdef CONFIG_KEXEC
+- /* crashkernel=size at 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_PROC_VMCORE
+- /* elfcorehdr= specifies the location of elf core header
+- * stored by the crashed kernel. This option will be passed
+- * by kexec loader to the capture kernel.
+- */
+- else if(!memcmp(from, "elfcorehdr=", 11))
+- elfcorehdr_addr = memparse(from+11, &from);
+-#endif
+-
+-#ifdef CONFIG_HOTPLUG_CPU
+- else if (!memcmp(from, "additional_cpus=", 16))
+- setup_additional_cpus(from+16);
+-#endif
+-
+- next_char:
+- c = *(from++);
+- if (!c)
+- break;
+- if (COMMAND_LINE_SIZE <= ++len)
+- break;
+- *(to++) = c;
+- }
+- if (userdef) {
+- printk(KERN_INFO "user-defined physical RAM map:\n");
+- e820_print_map("user");
+- }
+- *to = '\0';
+- *cmdline_p = command_line;
+-}
+-
+ #ifndef CONFIG_NUMA
+ static void __init
+ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+@@ -466,7 +287,8 @@ contig_initmem_init(unsigned long start_
+ if (bootmap == -1L)
+ panic("Cannot find bootmem map of size %ld\n",bootmap_size);
+ bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
+- e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT);
++ e820_register_active_regions(0, start_pfn, end_pfn);
++ free_bootmem_with_active_regions(0, end_pfn);
+ reserve_bootmem(bootmap, bootmap_size);
+ }
+ #endif
+@@ -521,6 +343,8 @@ static void discover_ebda(void)
+
+ void __init setup_arch(char **cmdline_p)
+ {
++ printk(KERN_INFO "Command line: %s\n", saved_command_line);
++
+ ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+ screen_info = SCREEN_INFO;
+ edid_info = EDID_INFO;
+@@ -547,16 +371,22 @@ void __init setup_arch(char **cmdline_p)
+ data_resource.start = virt_to_phys(&_etext);
+ data_resource.end = virt_to_phys(&_edata)-1;
+
+- parse_cmdline_early(cmdline_p);
+-
+ early_identify_cpu(&boot_cpu_data);
+
++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE);
++ *cmdline_p = command_line;
++
++ parse_early_param();
++
++ finish_e820_parsing();
++
++ e820_register_active_regions(0, 0, -1UL);
+ /*
+ * partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+ end_pfn = e820_end_of_ram();
+- num_physpages = end_pfn; /* for pfn_valid */
++ num_physpages = end_pfn;
+
+ check_efer();
+
+@@ -576,6 +406,14 @@ void __init setup_arch(char **cmdline_p)
+ acpi_boot_table_init();
+ #endif
+
++ /* How many end-of-memory variables you have, grandma! */
++ max_low_pfn = end_pfn;
++ max_pfn = end_pfn;
++ high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
++
++ /* Remove active ranges so rediscovery with NUMA-awareness happens */
++ remove_all_active_ranges();
++
+ #ifdef CONFIG_ACPI_NUMA
+ /*
+ * Parse SRAT to discover nodes.
+@@ -625,12 +463,10 @@ void __init setup_arch(char **cmdline_p)
+ */
+ acpi_reserve_bootmem();
+ #endif
+-#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * Find and reserve possible boot-time SMP configuration:
+ */
+ find_smp_config();
+-#endif
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (LOADER_TYPE && INITRD_START) {
+ if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
+@@ -657,7 +493,9 @@ void __init setup_arch(char **cmdline_p)
+
+ paging_init();
+
+- check_ioapic();
++#ifdef CONFIG_PCI
++ early_quirks();
++#endif
+
+ /*
+ * set this early, so we dont allocate cpu0
+@@ -674,14 +512,12 @@ void __init setup_arch(char **cmdline_p)
+
+ init_cpu_to_node();
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * get boot-time SMP configuration:
+ */
+ if (smp_found_config)
+ get_smp_config();
+ init_apic_mappings();
+-#endif
+
+ /*
+ * Request address space for all standard RAM and ROM resources
+@@ -689,13 +525,14 @@ void __init setup_arch(char **cmdline_p)
+ */
+ probe_roms();
+ e820_reserve_resources();
++ e820_mark_nosave_regions();
+
+ request_resource(&iomem_resource, &video_ram_resource);
+
+ {
+ unsigned i;
+ /* request I/O space for devices used on all i[345]86 PCs */
+- for (i = 0; i < STANDARD_IO_RESOURCES; i++)
++ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
+ request_resource(&ioport_resource, &standard_io_resources[i]);
+ }
+
+@@ -838,7 +675,7 @@ static void __init amd_detect_cmp(struct
+ #endif
+ }
+
+-static void __init init_amd(struct cpuinfo_x86 *c)
++static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+ {
+ unsigned level;
+
+@@ -894,6 +731,12 @@ static void __init init_amd(struct cpuin
+
+ /* Fix cpuid4 emulation for more */
+ num_cache_leaves = 3;
++
++ /* When there is only one core no need to synchronize RDTSC */
++ if (num_possible_cpus() == 1)
++ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
++ else
++ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+ }
+
+ static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
+@@ -975,8 +818,7 @@ static void srat_detect_node(void)
+ node = first_node(node_online_map);
+ numa_set_node(cpu, node);
+
+- if (acpi_numa > 0)
+- printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
++ printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+ #endif
+ }
+
+@@ -1010,6 +852,8 @@ static void __cpuinit init_intel(struct
+ if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
+ (c->x86 == 0x6 && c->x86_model >= 0x0e))
+ set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
++ if (c->x86 == 6)
++ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
+ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+ c->x86_max_cores = intel_num_cpu_cores(c);
+
+@@ -1228,8 +1072,8 @@ static int show_cpuinfo(struct seq_file
+
+ /* Intel-defined (#2) */
+ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+- "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL,
+- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
++ NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* VIA/Cyrix/Centaur-defined */
+diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
+index 417de56..8c4b80f 100644
+--- a/arch/x86_64/kernel/setup64.c
++++ b/arch/x86_64/kernel/setup64.c
+@@ -24,7 +24,7 @@
+ #include <asm/proto.h>
+ #include <asm/sections.h>
+
+-char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
++char x86_boot_params[BOOT_PARAM_SIZE] __initdata;
+
+ cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
+
+@@ -46,8 +46,10 @@ Control non executable mappings for 64bi
+ on Enable(default)
+ off Disable
+ */
+-int __init nonx_setup(char *str)
++static int __init nonx_setup(char *str)
+ {
++ if (!str)
++ return -EINVAL;
+ if (!strncmp(str, "on", 2)) {
+ __supported_pte_mask |= _PAGE_NX;
+ do_not_nx = 0;
+@@ -55,9 +57,9 @@ int __init nonx_setup(char *str)
+ do_not_nx = 1;
+ __supported_pte_mask &= ~_PAGE_NX;
+ }
+- return 1;
++ return 0;
+ }
+-__setup("noexec=", nonx_setup); /* parsed early actually */
++early_param("noexec", nonx_setup);
+
+ int force_personality32 = 0;
+
+@@ -93,12 +95,9 @@ void __init setup_per_cpu_areas(void)
+ #endif
+
+ /* Copy section for each CPU (we discard the original) */
+- size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
+-#ifdef CONFIG_MODULES
+- if (size < PERCPU_ENOUGH_ROOM)
+- size = PERCPU_ENOUGH_ROOM;
+-#endif
++ size = PERCPU_ENOUGH_ROOM;
+
++ printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", size);
+ for_each_cpu_mask (i, cpu_possible_map) {
+ char *ptr;
+
+@@ -122,7 +121,10 @@ void pda_init(int cpu)
+
+ /* Setup up data that may be needed in __get_free_pages early */
+ asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
++ /* Memory clobbers used to order PDA accessed */
++ mb();
+ wrmsrl(MSR_GS_BASE, pda);
++ mb();
+
+ pda->cpunumber = cpu;
+ pda->irqcount = -1;
+@@ -178,6 +180,8 @@ void __cpuinit check_efer(void)
+ }
+ }
+
++unsigned long kernel_eflags;
++
+ /*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+@@ -235,28 +239,17 @@ void __cpuinit cpu_init (void)
+ * set up and load the per-CPU TSS
+ */
+ for (v = 0; v < N_EXCEPTION_STACKS; v++) {
++ static const unsigned int order[N_EXCEPTION_STACKS] = {
++ [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
++ [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
++ };
+ if (cpu) {
+- static const unsigned int order[N_EXCEPTION_STACKS] = {
+- [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
+- [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
+- };
+-
+ estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
+ if (!estacks)
+ panic("Cannot allocate exception stack %ld %d\n",
+ v, cpu);
+ }
+- switch (v + 1) {
+-#if DEBUG_STKSZ > EXCEPTION_STKSZ
+- case DEBUG_STACK:
+- cpu_pda(cpu)->debugstack = (unsigned long)estacks;
+- estacks += DEBUG_STKSZ;
+- break;
+-#endif
+- default:
+- estacks += EXCEPTION_STKSZ;
+- break;
+- }
++ estacks += PAGE_SIZE << order[v];
+ orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks;
+ }
+
+@@ -290,4 +283,6 @@ void __cpuinit cpu_init (void)
+ set_debugreg(0UL, 7);
+
+ fpu_init();
++
++ raw_local_save_flags(kernel_eflags);
+ }
+diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
+index 2816117..49ec324 100644
+--- a/arch/x86_64/kernel/signal.c
++++ b/arch/x86_64/kernel/signal.c
+@@ -38,37 +38,6 @@ int ia32_setup_frame(int sig, struct k_s
+ sigset_t *set, struct pt_regs * regs);
+
+ asmlinkage long
+-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
+-{
+- sigset_t saveset, newset;
+-
+- /* XXX: Don't preclude handling different sized sigset_t's. */
+- if (sigsetsize != sizeof(sigset_t))
+- return -EINVAL;
+-
+- if (copy_from_user(&newset, unewset, sizeof(newset)))
+- return -EFAULT;
+- sigdelsetmask(&newset, ~_BLOCKABLE);
+-
+- spin_lock_irq(¤t->sighand->siglock);
+- saveset = current->blocked;
+- current->blocked = newset;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->sighand->siglock);
+-#ifdef DEBUG_SIG
+- printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
+- saveset, newset, regs, regs->rip);
+-#endif
+- regs->rax = -EINTR;
+- while (1) {
+- current->state = TASK_INTERRUPTIBLE;
+- schedule();
+- if (do_signal(regs, &saveset))
+- return -EINTR;
+- }
+-}
+-
+-asmlinkage long
+ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+ struct pt_regs *regs)
+ {
+@@ -308,11 +277,6 @@ static int setup_rt_frame(int sig, struc
+ #endif
+
+ /* Set up registers for signal handler */
+- {
+- struct exec_domain *ed = current_thread_info()->exec_domain;
+- if (unlikely(ed && ed->signal_invmap && sig < 32))
+- sig = ed->signal_invmap[sig];
+- }
+ regs->rdi = sig;
+ /* In case the signal handler was declared without prototypes */
+ regs->rax = 0;
+@@ -341,11 +305,11 @@ static int setup_rt_frame(int sig, struc
+ current->comm, current->pid, frame, regs->rip, frame->pretcode);
+ #endif
+
+- return 1;
++ return 0;
+
+ give_sigsegv:
+ force_sigsegv(sig, current);
+- return 0;
++ return -EFAULT;
+ }
+
+ /*
+@@ -408,7 +372,7 @@ handle_signal(unsigned long sig, siginfo
+ #endif
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
+
+- if (ret) {
++ if (ret == 0) {
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+@@ -425,11 +389,12 @@ handle_signal(unsigned long sig, siginfo
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+-int do_signal(struct pt_regs *regs, sigset_t *oldset)
++static void do_signal(struct pt_regs *regs)
+ {
+ struct k_sigaction ka;
+ siginfo_t info;
+ int signr;
++ sigset_t *oldset;
+
+ /*
+ * We want the common case to go fast, which
+@@ -438,9 +403,11 @@ int do_signal(struct pt_regs *regs, sigs
+ * if so.
+ */
+ if (!user_mode(regs))
+- return 1;
++ return;
+
+- if (!oldset)
++ if (test_thread_flag(TIF_RESTORE_SIGMASK))
++ oldset = ¤t->saved_sigmask;
++ else
+ oldset = ¤t->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+@@ -454,30 +421,46 @@ int do_signal(struct pt_regs *regs, sigs
+ set_debugreg(current->thread.debugreg7, 7);
+
+ /* Whee! Actually deliver the signal. */
+- return handle_signal(signr, &info, &ka, oldset, regs);
++ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
++ /* a signal was successfully delivered; the saved
++ * sigmask will have been stored in the signal frame,
++ * and will be restored by sigreturn, so we can simply
++ * clear the TIF_RESTORE_SIGMASK flag */
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ }
++ return;
+ }
+
+ /* Did we come from a system call? */
+ if ((long)regs->orig_rax >= 0) {
+ /* Restart the system call - no handlers present */
+ long res = regs->rax;
+- if (res == -ERESTARTNOHAND ||
+- res == -ERESTARTSYS ||
+- res == -ERESTARTNOINTR) {
++ switch (res) {
++ case -ERESTARTNOHAND:
++ case -ERESTARTSYS:
++ case -ERESTARTNOINTR:
+ regs->rax = regs->orig_rax;
+ regs->rip -= 2;
+- }
+- if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) {
++ break;
++ case -ERESTART_RESTARTBLOCK:
+ regs->rax = test_thread_flag(TIF_IA32) ?
+ __NR_ia32_restart_syscall :
+ __NR_restart_syscall;
+ regs->rip -= 2;
++ break;
+ }
+ }
+- return 0;
++
++ /* if there's no signal to deliver, we just put the saved sigmask
++ back. */
++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++ clear_thread_flag(TIF_RESTORE_SIGMASK);
++ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
++ }
+ }
+
+-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags)
++void
++do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
+ {
+ #ifdef DEBUG_SIG
+ printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n",
+@@ -491,8 +474,8 @@ void do_notify_resume(struct pt_regs *re
+ }
+
+ /* deal with pending signal delivery */
+- if (thread_info_flags & _TIF_SIGPENDING)
+- do_signal(regs,oldset);
++ if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
++ do_signal(regs);
+ }
+
+ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
+index 06af6ca..4f67697 100644
+--- a/arch/x86_64/kernel/smp.c
++++ b/arch/x86_64/kernel/smp.c
+@@ -522,26 +522,3 @@ asmlinkage void smp_call_function_interr
+ }
+ }
+
+-int safe_smp_processor_id(void)
+-{
+- unsigned apicid, i;
+-
+- if (disable_apic)
+- return 0;
+-
+- apicid = hard_smp_processor_id();
+- if (apicid < NR_CPUS && x86_cpu_to_apicid[apicid] == apicid)
+- return apicid;
+-
+- for (i = 0; i < NR_CPUS; ++i) {
+- if (x86_cpu_to_apicid[i] == apicid)
+- return i;
+- }
+-
+- /* No entries in x86_cpu_to_apicid? Either no MPS|ACPI,
+- * or called too early. Either way, we must be CPU 0. */
+- if (x86_cpu_to_apicid[0] == BAD_APICID)
+- return 0;
+-
+- return 0; /* Should not happen */
+-}
+diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
+index 9753802..62c2e74 100644
+--- a/arch/x86_64/kernel/smpboot.c
++++ b/arch/x86_64/kernel/smpboot.c
+@@ -46,9 +46,10 @@
+ #include <linux/bootmem.h>
+ #include <linux/thread_info.h>
+ #include <linux/module.h>
+-
+ #include <linux/delay.h>
+ #include <linux/mc146818rtc.h>
++#include <linux/smp.h>
++
+ #include <asm/mtrr.h>
+ #include <asm/pgalloc.h>
+ #include <asm/desc.h>
+@@ -580,12 +581,16 @@ void __cpuinit start_secondary(void)
+ * smp_call_function().
+ */
+ lock_ipi_call_lock();
++ spin_lock(&vector_lock);
+
++ /* Setup the per cpu irq handling data structures */
++ __setup_vector_irq(smp_processor_id());
+ /*
+ * Allow the master to continue.
+ */
+ cpu_set(smp_processor_id(), cpu_online_map);
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
++ spin_unlock(&vector_lock);
+ unlock_ipi_call_lock();
+
+ cpu_idle();
+@@ -798,7 +803,6 @@ static int __cpuinit do_boot_cpu(int cpu
+ cpu, node);
+ }
+
+-
+ alternatives_smp_switch(1);
+
+ c_idle.idle = get_idle_for_cpu(cpu);
+@@ -1090,7 +1094,6 @@ void __init smp_prepare_cpus(unsigned in
+ /*
+ * Switch from PIC to APIC mode.
+ */
+- connect_bsp_APIC();
+ setup_local_APIC();
+
+ if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id) {
+@@ -1175,12 +1178,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
+ void __init smp_cpus_done(unsigned int max_cpus)
+ {
+ smp_cleanup_boot();
+-
+-#ifdef CONFIG_X86_IO_APIC
+ setup_ioapic_dest();
+-#endif
+-
+ check_nmi_watchdog();
++ time_init_gtod();
+ }
+
+ #ifdef CONFIG_HOTPLUG_CPU
+@@ -1233,6 +1233,8 @@ int __cpu_disable(void)
+ if (cpu == 0)
+ return -EBUSY;
+
++ if (nmi_watchdog == NMI_LOCAL_APIC)
++ stop_apic_nmi_watchdog(NULL);
+ clear_local_APIC();
+
+ /*
+@@ -1247,8 +1249,10 @@ int __cpu_disable(void)
+ local_irq_disable();
+ remove_siblinginfo(cpu);
+
++ spin_lock(&vector_lock);
+ /* It's now safe to remove this processor from the online map */
+ cpu_clear(cpu, cpu_online_map);
++ spin_unlock(&vector_lock);
+ remove_cpu_from_maps();
+ fixup_irqs(cpu_online_map);
+ return 0;
+@@ -1272,11 +1276,11 @@ void __cpu_die(unsigned int cpu)
+ printk(KERN_ERR "CPU %u didn't die...\n", cpu);
+ }
+
+-__init int setup_additional_cpus(char *s)
++static __init int setup_additional_cpus(char *s)
+ {
+- return get_option(&s, &additional_cpus);
++ return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL;
+ }
+-__setup("additional_cpus=", setup_additional_cpus);
++early_param("additional_cpus", setup_additional_cpus);
+
+ #else /* ... !CONFIG_HOTPLUG_CPU */
+
+diff --git a/arch/x86_64/kernel/stacktrace.c b/arch/x86_64/kernel/stacktrace.c
+index 32cf55e..6026b31 100644
+--- a/arch/x86_64/kernel/stacktrace.c
++++ b/arch/x86_64/kernel/stacktrace.c
+@@ -7,215 +7,49 @@
+ */
+ #include <linux/sched.h>
+ #include <linux/stacktrace.h>
++#include <linux/module.h>
++#include <asm/stacktrace.h>
+
+-#include <asm/smp.h>
+-
+-static inline int
+-in_range(unsigned long start, unsigned long addr, unsigned long end)
++static void save_stack_warning(void *data, char *msg)
+ {
+- return addr >= start && addr <= end;
+ }
+
+-static unsigned long
+-get_stack_end(struct task_struct *task, unsigned long stack)
++static void
++save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
+ {
+- unsigned long stack_start, stack_end, flags;
+- int i, cpu;
+-
+- /*
+- * The most common case is that we are in the task stack:
+- */
+- stack_start = (unsigned long)task->thread_info;
+- stack_end = stack_start + THREAD_SIZE;
+-
+- if (in_range(stack_start, stack, stack_end))
+- return stack_end;
+-
+- /*
+- * We are in an interrupt if irqstackptr is set:
+- */
+- raw_local_irq_save(flags);
+- cpu = safe_smp_processor_id();
+- stack_end = (unsigned long)cpu_pda(cpu)->irqstackptr;
+-
+- if (stack_end) {
+- stack_start = stack_end & ~(IRQSTACKSIZE-1);
+- if (in_range(stack_start, stack, stack_end))
+- goto out_restore;
+- /*
+- * We get here if we are in an IRQ context but we
+- * are also in an exception stack.
+- */
+- }
+-
+- /*
+- * Iterate over all exception stacks, and figure out whether
+- * 'stack' is in one of them:
+- */
+- for (i = 0; i < N_EXCEPTION_STACKS; i++) {
+- /*
+- * set 'end' to the end of the exception stack.
+- */
+- stack_end = per_cpu(init_tss, cpu).ist[i];
+- stack_start = stack_end - EXCEPTION_STKSZ;
+-
+- /*
+- * Is 'stack' above this exception frame's end?
+- * If yes then skip to the next frame.
+- */
+- if (stack >= stack_end)
+- continue;
+- /*
+- * Is 'stack' above this exception frame's start address?
+- * If yes then we found the right frame.
+- */
+- if (stack >= stack_start)
+- goto out_restore;
+-
+- /*
+- * If this is a debug stack, and if it has a larger size than
+- * the usual exception stacks, then 'stack' might still
+- * be within the lower portion of the debug stack:
+- */
+-#if DEBUG_STKSZ > EXCEPTION_STKSZ
+- if (i == DEBUG_STACK - 1 && stack >= stack_end - DEBUG_STKSZ) {
+- /*
+- * Black magic. A large debug stack is composed of
+- * multiple exception stack entries, which we
+- * iterate through now. Dont look:
+- */
+- do {
+- stack_end -= EXCEPTION_STKSZ;
+- stack_start -= EXCEPTION_STKSZ;
+- } while (stack < stack_start);
+-
+- goto out_restore;
+- }
+-#endif
+- }
+- /*
+- * Ok, 'stack' is not pointing to any of the system stacks.
+- */
+- stack_end = 0;
+-
+-out_restore:
+- raw_local_irq_restore(flags);
+-
+- return stack_end;
+ }
+
+-
+-/*
+- * Save stack-backtrace addresses into a stack_trace buffer:
+- */
+-static inline unsigned long
+-save_context_stack(struct stack_trace *trace, unsigned int skip,
+- unsigned long stack, unsigned long stack_end)
++static int save_stack_stack(void *data, char *name)
+ {
+- unsigned long addr;
+-
+-#ifdef CONFIG_FRAME_POINTER
+- unsigned long prev_stack = 0;
++ struct stack_trace *trace = (struct stack_trace *)data;
++ return trace->all_contexts ? 0 : -1;
++}
+
+- while (in_range(prev_stack, stack, stack_end)) {
+- pr_debug("stack: %p\n", (void *)stack);
+- addr = (unsigned long)(((unsigned long *)stack)[1]);
+- pr_debug("addr: %p\n", (void *)addr);
+- if (!skip)
+- trace->entries[trace->nr_entries++] = addr-1;
+- else
+- skip--;
+- if (trace->nr_entries >= trace->max_entries)
+- break;
+- if (!addr)
+- return 0;
+- /*
+- * Stack frames must go forwards (otherwise a loop could
+- * happen if the stackframe is corrupted), so we move
+- * prev_stack forwards:
+- */
+- prev_stack = stack;
+- stack = (unsigned long)(((unsigned long *)stack)[0]);
+- }
+- pr_debug("invalid: %p\n", (void *)stack);
+-#else
+- while (stack < stack_end) {
+- addr = ((unsigned long *)stack)[0];
+- stack += sizeof(long);
+- if (__kernel_text_address(addr)) {
+- if (!skip)
+- trace->entries[trace->nr_entries++] = addr-1;
+- else
+- skip--;
+- if (trace->nr_entries >= trace->max_entries)
+- break;
+- }
++static void save_stack_address(void *data, unsigned long addr)
++{
++ struct stack_trace *trace = (struct stack_trace *)data;
++ if (trace->skip > 0) {
++ trace->skip--;
++ return;
+ }
+-#endif
+- return stack;
++ if (trace->nr_entries < trace->max_entries - 1)
++ trace->entries[trace->nr_entries++] = addr;
+ }
+
+-#define MAX_STACKS 10
++static struct stacktrace_ops save_stack_ops = {
++ .warning = save_stack_warning,
++ .warning_symbol = save_stack_warning_symbol,
++ .stack = save_stack_stack,
++ .address = save_stack_address,
++};
+
+ /*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+- * If all_contexts is set, all contexts (hardirq, softirq and process)
+- * are saved. If not set then only the current context is saved.
+ */
+-void save_stack_trace(struct stack_trace *trace,
+- struct task_struct *task, int all_contexts,
+- unsigned int skip)
++void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+ {
+- unsigned long stack = (unsigned long)&stack;
+- int i, nr_stacks = 0, stacks_done[MAX_STACKS];
+-
+- WARN_ON(trace->nr_entries || !trace->max_entries);
+-
+- if (!task)
+- task = current;
+-
+- pr_debug("task: %p, ti: %p\n", task, task->thread_info);
+-
+- if (!task || task == current) {
+- /* Grab rbp right from our regs: */
+- asm ("mov %%rbp, %0" : "=r" (stack));
+- pr_debug("rbp: %p\n", (void *)stack);
+- } else {
+- /* rbp is the last reg pushed by switch_to(): */
+- stack = task->thread.rsp;
+- pr_debug("other task rsp: %p\n", (void *)stack);
+- stack = (unsigned long)(((unsigned long *)stack)[0]);
+- pr_debug("other task rbp: %p\n", (void *)stack);
+- }
+-
+- while (1) {
+- unsigned long stack_end = get_stack_end(task, stack);
+-
+- pr_debug("stack: %p\n", (void *)stack);
+- pr_debug("stack end: %p\n", (void *)stack_end);
+-
+- /*
+- * Invalid stack addres?
+- */
+- if (!stack_end)
+- return;
+- /*
+- * Were we in this stack already? (recursion)
+- */
+- for (i = 0; i < nr_stacks; i++)
+- if (stacks_done[i] == stack_end)
+- return;
+- stacks_done[nr_stacks] = stack_end;
+-
+- stack = save_context_stack(trace, skip, stack, stack_end);
+- if (!all_contexts || !stack ||
+- trace->nr_entries >= trace->max_entries)
+- return;
+- trace->entries[trace->nr_entries++] = ULONG_MAX;
+- if (trace->nr_entries >= trace->max_entries)
+- return;
+- if (++nr_stacks >= MAX_STACKS)
+- return;
+- }
++ dump_trace(task, NULL, NULL, &save_stack_ops, trace);
++ trace->entries[trace->nr_entries++] = ULONG_MAX;
+ }
++EXPORT_SYMBOL(save_stack_trace);
+
+diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S
+index 320b6fb..bfbe007 100644
+--- a/arch/x86_64/kernel/suspend_asm.S
++++ b/arch/x86_64/kernel/suspend_asm.S
+@@ -54,7 +54,7 @@ ENTRY(restore_image)
+ movq %rcx, %cr3;
+ movq %rax, %cr4; # turn PGE back on
+
+- movq pagedir_nosave(%rip), %rdx
++ movq restore_pblist(%rip), %rdx
+ loop:
+ testq %rdx, %rdx
+ jz done
+diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
+index 6449ea8..76bf7c2 100644
+--- a/arch/x86_64/kernel/sys_x86_64.c
++++ b/arch/x86_64/kernel/sys_x86_64.c
+@@ -148,7 +148,7 @@ asmlinkage long sys_uname(struct new_uts
+ {
+ int err;
+ down_read(&uts_sem);
+- err = copy_to_user(name, &system_utsname, sizeof (*name));
++ err = copy_to_user(name, utsname(), sizeof (*name));
+ up_read(&uts_sem);
+ if (personality(current->personality) == PER_LINUX32)
+ err |= copy_to_user(&name->machine, "i686", 5);
+diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
+index 5530dda..f61fb8e 100644
+--- a/arch/x86_64/kernel/tce.c
++++ b/arch/x86_64/kernel/tce.c
+@@ -1,4 +1,6 @@
+ /*
++ * This file manages the translation entries for the IBM Calgary IOMMU.
++ *
+ * Derived from arch/powerpc/platforms/pseries/iommu.c
+ *
+ * Copyright (C) IBM Corporation, 2006
+@@ -21,7 +23,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/slab.h>
+ #include <linux/mm.h>
+@@ -104,14 +105,6 @@ static int tce_table_setparms(struct pci
+ /* set the tce table size - measured in entries */
+ tbl->it_size = table_size_to_number_of_entries(specified_table_size);
+
+- tbl->it_base = (unsigned long)tce_table_kva[dev->bus->number];
+- if (!tbl->it_base) {
+- printk(KERN_ERR "Calgary: iommu_table_setparms: "
+- "no table allocated?!\n");
+- ret = -ENOMEM;
+- goto done;
+- }
+-
+ /*
+ * number of bytes needed for the bitmap size in number of
+ * entries; we need one bit per entry
+@@ -160,8 +153,6 @@ int build_tce_table(struct pci_dev *dev,
+ if (ret)
+ goto free_tbl;
+
+- tce_free(tbl, 0, tbl->it_size);
+-
+ tbl->bbar = bbar;
+
+ /*
+diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
+index 7a9b182..88722f1 100644
+--- a/arch/x86_64/kernel/time.c
++++ b/arch/x86_64/kernel/time.c
+@@ -24,6 +24,8 @@
+ #include <linux/device.h>
+ #include <linux/sysdev.h>
+ #include <linux/bcd.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
+ #include <linux/kallsyms.h>
+ #include <linux/acpi.h>
+ #ifdef CONFIG_ACPI
+@@ -39,9 +41,7 @@
+ #include <asm/sections.h>
+ #include <linux/cpufreq.h>
+ #include <linux/hpet.h>
+-#ifdef CONFIG_X86_LOCAL_APIC
+ #include <asm/apic.h>
+-#endif
+
+ #ifdef CONFIG_CPU_FREQ
+ static void cpufreq_delayed_get(void);
+@@ -49,7 +49,7 @@ static void cpufreq_delayed_get(void);
+ extern void i8254_timer_resume(void);
+ extern int using_apic_timer;
+
+-static char *time_init_gtod(void);
++static char *timename = NULL;
+
+ DEFINE_SPINLOCK(rtc_lock);
+ EXPORT_SYMBOL(rtc_lock);
+@@ -77,7 +77,6 @@ unsigned long long monotonic_base;
+ struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */
+
+ volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
+-unsigned long __wall_jiffies __section_wall_jiffies = INITIAL_JIFFIES;
+ struct timespec __xtime __section_xtime;
+ struct timezone __sys_tz __section_sys_tz;
+
+@@ -119,7 +118,7 @@ unsigned int (*do_gettimeoffset)(void) =
+
+ void do_gettimeofday(struct timeval *tv)
+ {
+- unsigned long seq, t;
++ unsigned long seq;
+ unsigned int sec, usec;
+
+ do {
+@@ -136,10 +135,7 @@ void do_gettimeofday(struct timeval *tv)
+ be found. Note when you fix it here you need to do the same
+ in arch/x86_64/kernel/vsyscall.c and export all needed
+ variables in vmlinux.lds. -AK */
+-
+- t = (jiffies - wall_jiffies) * USEC_PER_TICK +
+- do_gettimeoffset();
+- usec += t;
++ usec += do_gettimeoffset();
+
+ } while (read_seqretry(&xtime_lock, seq));
+
+@@ -165,8 +161,7 @@ int do_settimeofday(struct timespec *tv)
+
+ write_seqlock_irq(&xtime_lock);
+
+- nsec -= do_gettimeoffset() * NSEC_PER_USEC +
+- (jiffies - wall_jiffies) * NSEC_PER_TICK;
++ nsec -= do_gettimeoffset() * NSEC_PER_USEC;
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+@@ -187,20 +182,15 @@ unsigned long profile_pc(struct pt_regs
+ {
+ unsigned long pc = instruction_pointer(regs);
+
+- /* Assume the lock function has either no stack frame or only a single
+- word. This checks if the address on the stack looks like a kernel
+- text address.
+- There is a small window for false hits, but in that case the tick
+- is just accounted to the spinlock function.
+- Better would be to write these functions in assembler again
+- and check exactly. */
++ /* Assume the lock function has either no stack frame or a copy
++ of eflags from PUSHF
++ Eflags always has bits 22 and up cleared unlike kernel addresses. */
+ if (!user_mode(regs) && in_lock_functions(pc)) {
+- char *v = *(char **)regs->rsp;
+- if ((v >= _stext && v <= _etext) ||
+- (v >= _sinittext && v <= _einittext) ||
+- (v >= (char *)MODULES_VADDR && v <= (char *)MODULES_END))
+- return (unsigned long)v;
+- return ((unsigned long *)regs->rsp)[1];
++ unsigned long *sp = (unsigned long *)regs->rsp;
++ if (sp[0] >> 22)
++ return sp[0];
++ if (sp[1] >> 22)
++ return sp[1];
+ }
+ return pc;
+ }
+@@ -281,6 +271,7 @@ static void set_rtc_mmss(unsigned long n
+ * Note: This function is required to return accurate
+ * time even in the absence of multiple timer ticks.
+ */
++static inline unsigned long long cycles_2_ns(unsigned long long cyc);
+ unsigned long long monotonic_clock(void)
+ {
+ unsigned long seq;
+@@ -305,27 +296,26 @@ unsigned long long monotonic_clock(void)
+ base = monotonic_base;
+ } while (read_seqretry(&xtime_lock, seq));
+ this_offset = get_cycles_sync();
+- /* FIXME: 1000 or 1000000? */
+- offset = (this_offset - last_offset)*1000 / cpu_khz;
++ offset = cycles_2_ns(this_offset - last_offset);
+ }
+ return base + offset;
+ }
+ EXPORT_SYMBOL(monotonic_clock);
+
+-static noinline void handle_lost_ticks(int lost, struct pt_regs *regs)
++static noinline void handle_lost_ticks(int lost)
+ {
+ static long lost_count;
+ static int warned;
+ if (report_lost_ticks) {
+ printk(KERN_WARNING "time.c: Lost %d timer tick(s)! ", lost);
+- print_symbol("rip %s)\n", regs->rip);
++ print_symbol("rip %s)\n", get_irq_regs()->rip);
+ }
+
+ if (lost_count == 1000 && !warned) {
+ printk(KERN_WARNING "warning: many lost ticks.\n"
+ KERN_WARNING "Your time source seems to be instable or "
+ "some driver is hogging interupts\n");
+- print_symbol("rip %s\n", regs->rip);
++ print_symbol("rip %s\n", get_irq_regs()->rip);
+ if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) {
+ printk(KERN_WARNING "Falling back to HPET\n");
+ if (hpet_use_timer)
+@@ -349,7 +339,7 @@ static noinline void handle_lost_ticks(i
+ #endif
+ }
+
+-void main_timer_handler(struct pt_regs *regs)
++void main_timer_handler(void)
+ {
+ static unsigned long rtc_update = 0;
+ unsigned long tsc;
+@@ -410,8 +400,7 @@ void main_timer_handler(struct pt_regs *
+ offset %= USEC_PER_TICK;
+ }
+
+- /* FIXME: 1000 or 1000000? */
+- monotonic_base += (tsc - vxtime.last_tsc) * 1000000 / cpu_khz;
++ monotonic_base += cycles_2_ns(tsc - vxtime.last_tsc);
+
+ vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot;
+
+@@ -421,18 +410,18 @@ void main_timer_handler(struct pt_regs *
+ (((long) offset << US_SCALE) / vxtime.tsc_quot) - 1;
+ }
+
+- if (lost > 0) {
+- handle_lost_ticks(lost, regs);
+- jiffies += lost;
+- }
++ if (lost > 0)
++ handle_lost_ticks(lost);
++ else
++ lost = 0;
+
+ /*
+ * Do the timer stuff.
+ */
+
+- do_timer(regs);
++ do_timer(lost + 1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(get_irq_regs()));
+ #endif
+
+ /*
+@@ -441,12 +430,8 @@ void main_timer_handler(struct pt_regs *
+ * have to call the local interrupt handler.
+ */
+
+-#ifndef CONFIG_X86_LOCAL_APIC
+- profile_tick(CPU_PROFILING, regs);
+-#else
+ if (!using_apic_timer)
+- smp_local_timer_interrupt(regs);
+-#endif
++ smp_local_timer_interrupt();
+
+ /*
+ * If we have an externally synchronized Linux clock, then update CMOS clock
+@@ -465,15 +450,13 @@ void main_timer_handler(struct pt_regs *
+ write_sequnlock(&xtime_lock);
+ }
+
+-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t timer_interrupt(int irq, void *dev_id)
+ {
+ if (apic_runs_main_timer > 1)
+ return IRQ_HANDLED;
+- main_timer_handler(regs);
+-#ifdef CONFIG_X86_LOCAL_APIC
++ main_timer_handler();
+ if (using_apic_timer)
+ smp_send_timer_broadcast_ipi();
+-#endif
+ return IRQ_HANDLED;
+ }
+
+@@ -893,11 +876,17 @@ static struct irqaction irq0 = {
+ timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL
+ };
+
+-void __init time_init(void)
++static int __cpuinit
++time_cpu_notifier(struct notifier_block *nb, unsigned long action, void *hcpu)
+ {
+- char *timename;
+- char *gtod;
++ unsigned cpu = (unsigned long) hcpu;
++ if (action == CPU_ONLINE)
++ vsyscall_set_cpu(cpu);
++ return NOTIFY_DONE;
++}
+
++void __init time_init(void)
++{
+ if (nohpet)
+ vxtime.hpet_address = 0;
+
+@@ -931,18 +920,17 @@ void __init time_init(void)
+ }
+
+ vxtime.mode = VXTIME_TSC;
+- gtod = time_init_gtod();
+-
+- printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n",
+- vxtime_hz / 1000000, vxtime_hz % 1000000, timename, gtod);
+- printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+- cpu_khz / 1000, cpu_khz % 1000);
+ vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz;
+ vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
+ vxtime.last_tsc = get_cycles_sync();
++ set_cyc2ns_scale(cpu_khz);
+ setup_irq(0, &irq0);
++ hotcpu_notifier(time_cpu_notifier, 0);
++ time_cpu_notifier(NULL, CPU_ONLINE, (void *)(long)smp_processor_id());
+
+- set_cyc2ns_scale(cpu_khz);
++#ifndef CONFIG_SMP
++ time_init_gtod();
++#endif
+ }
+
+ /*
+@@ -960,7 +948,7 @@ __cpuinit int unsynchronized_tsc(void)
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+ #ifdef CONFIG_ACPI
+ /* But TSC doesn't tick in C3 so don't use it there */
+- if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 100)
++ if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 1000)
+ return 1;
+ #endif
+ return 0;
+@@ -973,12 +961,18 @@ __cpuinit int unsynchronized_tsc(void)
+ /*
+ * Decide what mode gettimeofday should use.
+ */
+-__init static char *time_init_gtod(void)
++void time_init_gtod(void)
+ {
+ char *timetype;
+
+ if (unsynchronized_tsc())
+ notsc = 1;
++
++ if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
++ vgetcpu_mode = VGETCPU_RDTSCP;
++ else
++ vgetcpu_mode = VGETCPU_LSL;
++
+ if (vxtime.hpet_address && notsc) {
+ timetype = hpet_use_timer ? "HPET" : "PIT/HPET";
+ if (hpet_use_timer)
+@@ -1001,7 +995,16 @@ __init static char *time_init_gtod(void)
+ timetype = hpet_use_timer ? "HPET/TSC" : "PIT/TSC";
+ vxtime.mode = VXTIME_TSC;
+ }
+- return timetype;
++
++ printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n",
++ vxtime_hz / 1000000, vxtime_hz % 1000000, timename, timetype);
++ printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
++ cpu_khz / 1000, cpu_khz % 1000);
++ vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz;
++ vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
++ vxtime.last_tsc = get_cycles_sync();
++
++ set_cyc2ns_scale(cpu_khz);
+ }
+
+ __setup("report_lost_ticks", time_setup);
+@@ -1031,8 +1034,16 @@ static int timer_resume(struct sys_devic
+ unsigned long flags;
+ unsigned long sec;
+ unsigned long ctime = get_cmos_time();
+- unsigned long sleep_length = (ctime - sleep_start) * HZ;
++ long sleep_length = (ctime - sleep_start) * HZ;
+
++ if (sleep_length < 0) {
++ printk(KERN_WARNING "Time skew detected in timer resume!\n");
++ /* The time after the resume must not be earlier than the time
++ * before the suspend or some nasty things will happen
++ */
++ sleep_length = 0;
++ ctime = sleep_start;
++ }
+ if (vxtime.hpet_address)
+ hpet_reenable();
+ else
+@@ -1055,7 +1066,6 @@ static int timer_resume(struct sys_devic
+ vxtime.last_tsc = get_cycles_sync();
+ write_sequnlock_irqrestore(&xtime_lock,flags);
+ jiffies += sleep_length;
+- wall_jiffies += sleep_length;
+ monotonic_base += sleep_length * (NSEC_PER_SEC/HZ);
+ touch_softlockup_watchdog();
+ return 0;
+@@ -1148,23 +1158,25 @@ int hpet_rtc_timer_init(void)
+ hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+ local_irq_save(flags);
++
+ cnt = hpet_readl(HPET_COUNTER);
+ cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
+ hpet_writel(cnt, HPET_T1_CMP);
+ hpet_t1_cmp = cnt;
+- local_irq_restore(flags);
+
+ cfg = hpet_readl(HPET_T1_CFG);
+ cfg &= ~HPET_TN_PERIODIC;
+ cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+ hpet_writel(cfg, HPET_T1_CFG);
+
++ local_irq_restore(flags);
++
+ return 1;
+ }
+
+ static void hpet_rtc_timer_reinit(void)
+ {
+- unsigned int cfg, cnt;
++ unsigned int cfg, cnt, ticks_per_int, lost_ints;
+
+ if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
+ cfg = hpet_readl(HPET_T1_CFG);
+@@ -1179,10 +1191,33 @@ static void hpet_rtc_timer_reinit(void)
+ hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+ /* It is more accurate to use the comparator value than current count.*/
+- cnt = hpet_t1_cmp;
+- cnt += hpet_tick*HZ/hpet_rtc_int_freq;
+- hpet_writel(cnt, HPET_T1_CMP);
+- hpet_t1_cmp = cnt;
++ ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
++ hpet_t1_cmp += ticks_per_int;
++ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
++
++ /*
++ * If the interrupt handler was delayed too long, the write above tries
++ * to schedule the next interrupt in the past and the hardware would
++ * not interrupt until the counter had wrapped around.
++ * So we have to check that the comparator wasn't set to a past time.
++ */
++ cnt = hpet_readl(HPET_COUNTER);
++ if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
++ lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
++ /* Make sure that, even with the time needed to execute
++ * this code, the next scheduled interrupt has been moved
++ * back to the future: */
++ lost_ints++;
++
++ hpet_t1_cmp += lost_ints * ticks_per_int;
++ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
++
++ if (PIE_on)
++ PIE_count += lost_ints;
++
++ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
++ hpet_rtc_int_freq);
++ }
+ }
+
+ /*
+@@ -1302,7 +1337,7 @@ irqreturn_t hpet_rtc_interrupt(int irq,
+ }
+ if (call_rtc_interrupt) {
+ rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
+- rtc_interrupt(rtc_int_flag, dev_id, regs);
++ rtc_interrupt(rtc_int_flag, dev_id);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
+index 23a03eb..c79b99a 100644
+--- a/arch/x86_64/kernel/trampoline.S
++++ b/arch/x86_64/kernel/trampoline.S
+@@ -64,7 +64,7 @@ idt_48:
+ .word 0, 0 # idt base = 0L
+
+ gdt_48:
+- .short __KERNEL32_CS + 7 # gdt limit
++ .short GDT_ENTRIES*8 - 1 # gdt limit
+ .long cpu_gdt_table-__START_KERNEL_map
+
+ .globl trampoline_end
+diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
+index b124977..7819022 100644
+--- a/arch/x86_64/kernel/traps.c
++++ b/arch/x86_64/kernel/traps.c
+@@ -23,6 +23,7 @@
+ #include <linux/delay.h>
+ #include <linux/spinlock.h>
+ #include <linux/interrupt.h>
++#include <linux/kallsyms.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/nmi.h>
+@@ -45,6 +46,7 @@
+ #include <asm/pda.h>
+ #include <asm/proto.h>
+ #include <asm/nmi.h>
++#include <asm/stacktrace.h>
+
+ asmlinkage void divide_error(void);
+ asmlinkage void debug(void);
+@@ -114,7 +116,6 @@ static int call_trace = 1;
+ #endif
+
+ #ifdef CONFIG_KALLSYMS
+-# include <linux/kallsyms.h>
+ void printk_address(unsigned long address)
+ {
+ unsigned long offset = 0, symsize;
+@@ -142,7 +143,7 @@ void printk_address(unsigned long addres
+ #endif
+
+ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+- unsigned *usedp, const char **idp)
++ unsigned *usedp, char **idp)
+ {
+ static char ids[][8] = {
+ [DEBUG_STACK - 1] = "#DB",
+@@ -161,26 +162,7 @@ static unsigned long *in_exception_stack
+ * 'stack' is in one of them:
+ */
+ for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+- unsigned long end;
+-
+- /*
+- * set 'end' to the end of the exception stack.
+- */
+- switch (k + 1) {
+- /*
+- * TODO: this block is not needed i think, because
+- * setup64.c:cpu_init() sets up t->ist[DEBUG_STACK]
+- * properly too.
+- */
+-#if DEBUG_STKSZ > EXCEPTION_STKSZ
+- case DEBUG_STACK:
+- end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ;
+- break;
+-#endif
+- default:
+- end = per_cpu(orig_ist, cpu).ist[k];
+- break;
+- }
++ unsigned long end = per_cpu(orig_ist, cpu).ist[k];
+ /*
+ * Is 'stack' above this exception frame's end?
+ * If yes then skip to the next frame.
+@@ -234,13 +216,19 @@ static unsigned long *in_exception_stack
+ return NULL;
+ }
+
+-static int show_trace_unwind(struct unwind_frame_info *info, void *context)
++struct ops_and_data {
++ struct stacktrace_ops *ops;
++ void *data;
++};
++
++static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
+ {
++ struct ops_and_data *oad = (struct ops_and_data *)context;
+ int n = 0;
+
+ while (unwind(info) == 0 && UNW_PC(info)) {
+ n++;
+- printk_address(UNW_PC(info));
++ oad->ops->address(oad->data, UNW_PC(info));
+ if (arch_unw_user_mode(info))
+ break;
+ }
+@@ -254,45 +242,53 @@ static int show_trace_unwind(struct unwi
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+-void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack)
++void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack,
++ struct stacktrace_ops *ops, void *data)
+ {
+- const unsigned cpu = safe_smp_processor_id();
++ const unsigned cpu = smp_processor_id();
+ unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
+ unsigned used = 0;
+
+- printk("\nCall Trace:\n");
+-
+ if (!tsk)
+ tsk = current;
+
+ if (call_trace >= 0) {
+ int unw_ret = 0;
+ struct unwind_frame_info info;
++ struct ops_and_data oad = { .ops = ops, .data = data };
+
+ if (regs) {
+ if (unwind_init_frame_info(&info, tsk, regs) == 0)
+- unw_ret = show_trace_unwind(&info, NULL);
++ unw_ret = dump_trace_unwind(&info, &oad);
+ } else if (tsk == current)
+- unw_ret = unwind_init_running(&info, show_trace_unwind, NULL);
++ unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad);
+ else {
+ if (unwind_init_blocked(&info, tsk) == 0)
+- unw_ret = show_trace_unwind(&info, NULL);
++ unw_ret = dump_trace_unwind(&info, &oad);
+ }
+ if (unw_ret > 0) {
+ if (call_trace == 1 && !arch_unw_user_mode(&info)) {
+- print_symbol("DWARF2 unwinder stuck at %s\n",
++ ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n",
+ UNW_PC(&info));
+ if ((long)UNW_SP(&info) < 0) {
+- printk("Leftover inexact backtrace:\n");
++ ops->warning(data, "Leftover inexact backtrace:\n");
+ stack = (unsigned long *)UNW_SP(&info);
++ if (!stack)
++ return;
+ } else
+- printk("Full inexact backtrace again:\n");
++ ops->warning(data, "Full inexact backtrace again:\n");
+ } else if (call_trace >= 1)
+ return;
+ else
+- printk("Full inexact backtrace again:\n");
++ ops->warning(data, "Full inexact backtrace again:\n");
+ } else
+- printk("Inexact backtrace:\n");
++ ops->warning(data, "Inexact backtrace:\n");
++ }
++ if (!stack) {
++ unsigned long dummy;
++ stack = &dummy;
++ if (tsk && tsk != current)
++ stack = (unsigned long *)tsk->thread.rsp;
+ }
+
+ /*
+@@ -303,7 +299,9 @@ void show_trace(struct task_struct *tsk,
+ #define HANDLE_STACK(cond) \
+ do while (cond) { \
+ unsigned long addr = *stack++; \
+- if (kernel_text_address(addr)) { \
++ if (oops_in_progress ? \
++ __kernel_text_address(addr) : \
++ kernel_text_address(addr)) { \
+ /* \
+ * If the address is either in the text segment of the \
+ * kernel, or in the region which contains vmalloc'ed \
+@@ -312,7 +310,7 @@ void show_trace(struct task_struct *tsk,
+ * down the cause of the crash will be able to figure \
+ * out the call path that was taken. \
+ */ \
+- printk_address(addr); \
++ ops->address(data, addr); \
+ } \
+ } while (0)
+
+@@ -321,16 +319,17 @@ void show_trace(struct task_struct *tsk,
+ * current stack address. If the stacks consist of nested
+ * exceptions
+ */
+- for ( ; ; ) {
+- const char *id;
++ for (;;) {
++ char *id;
+ unsigned long *estack_end;
+ estack_end = in_exception_stack(cpu, (unsigned long)stack,
+ &used, &id);
+
+ if (estack_end) {
+- printk(" <%s>", id);
++ if (ops->stack(data, id) < 0)
++ break;
+ HANDLE_STACK (stack < estack_end);
+- printk(" <EOE>");
++ ops->stack(data, "<EOE>");
+ /*
+ * We link to the next stack via the
+ * second-to-last pointer (index -2 to end) in the
+@@ -345,7 +344,8 @@ void show_trace(struct task_struct *tsk,
+ (IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+ if (stack >= irqstack && stack < irqstack_end) {
+- printk(" <IRQ>");
++ if (ops->stack(data, "IRQ") < 0)
++ break;
+ HANDLE_STACK (stack < irqstack_end);
+ /*
+ * We link to the next stack (which would be
+@@ -354,7 +354,7 @@ void show_trace(struct task_struct *tsk,
+ */
+ stack = (unsigned long *) (irqstack_end[-1]);
+ irqstack_end = NULL;
+- printk(" <EOI>");
++ ops->stack(data, "EOI");
+ continue;
+ }
+ }
+@@ -362,19 +362,57 @@ void show_trace(struct task_struct *tsk,
+ }
+
+ /*
+- * This prints the process stack:
++ * This handles the process stack:
+ */
+ HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0);
+ #undef HANDLE_STACK
++}
++EXPORT_SYMBOL(dump_trace);
++
++static void
++print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
++{
++ print_symbol(msg, symbol);
++ printk("\n");
++}
++
++static void print_trace_warning(void *data, char *msg)
++{
++ printk("%s\n", msg);
++}
++
++static int print_trace_stack(void *data, char *name)
++{
++ printk(" <%s> ", name);
++ return 0;
++}
++
++static void print_trace_address(void *data, unsigned long addr)
++{
++ printk_address(addr);
++}
++
++static struct stacktrace_ops print_trace_ops = {
++ .warning = print_trace_warning,
++ .warning_symbol = print_trace_warning_symbol,
++ .stack = print_trace_stack,
++ .address = print_trace_address,
++};
+
++void
++show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack)
++{
++ printk("\nCall Trace:\n");
++ dump_trace(tsk, regs, stack, &print_trace_ops, NULL);
+ printk("\n");
+ }
+
+-static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp)
++static void
++_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *rsp)
+ {
+ unsigned long *stack;
+ int i;
+- const int cpu = safe_smp_processor_id();
++ const int cpu = smp_processor_id();
+ unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr);
+ unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
+
+@@ -428,7 +466,7 @@ void show_registers(struct pt_regs *regs
+ int i;
+ int in_kernel = !user_mode(regs);
+ unsigned long rsp;
+- const int cpu = safe_smp_processor_id();
++ const int cpu = smp_processor_id();
+ struct task_struct *cur = cpu_pda(cpu)->pcurrent;
+
+ rsp = regs->rsp;
+@@ -503,9 +541,11 @@ static unsigned int die_nest_count;
+
+ unsigned __kprobes long oops_begin(void)
+ {
+- int cpu = safe_smp_processor_id();
++ int cpu = smp_processor_id();
+ unsigned long flags;
+
++ oops_enter();
++
+ /* racy, but better than risking deadlock. */
+ local_irq_save(flags);
+ if (!spin_trylock(&die_lock)) {
+@@ -534,6 +574,7 @@ void __kprobes oops_end(unsigned long fl
+ spin_unlock_irqrestore(&die_lock, flags);
+ if (panic_on_oops)
+ panic("Fatal exception");
++ oops_exit();
+ }
+
+ void __kprobes __die(const char * str, struct pt_regs * regs, long err)
+@@ -570,7 +611,7 @@ void die(const char * str, struct pt_reg
+ do_exit(SIGSEGV);
+ }
+
+-void __kprobes die_nmi(char *str, struct pt_regs *regs)
++void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
+ {
+ unsigned long flags = oops_begin();
+
+@@ -578,13 +619,12 @@ void __kprobes die_nmi(char *str, struct
+ * We are in trouble anyway, lets at least try
+ * to get a message out.
+ */
+- printk(str, safe_smp_processor_id());
++ printk(str, smp_processor_id());
+ show_registers(regs);
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+- if (panic_on_timeout || panic_on_oops)
+- panic("nmi watchdog");
+- printk("console shuts up ...\n");
++ if (do_panic || panic_on_oops)
++ panic("Non maskable interrupt");
+ oops_end(flags);
+ nmi_exit();
+ local_irq_enable();
+@@ -730,8 +770,15 @@ asmlinkage void __kprobes do_general_pro
+ static __kprobes void
+ mem_parity_error(unsigned char reason, struct pt_regs * regs)
+ {
+- printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
+- printk("You probably have a hardware problem with your RAM chips\n");
++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
++ reason);
++ printk(KERN_EMERG "You probably have a hardware problem with your "
++ "RAM chips\n");
++
++ if (panic_on_unrecovered_nmi)
++ panic("NMI: Not continuing");
++
++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+
+ /* Clear and disable the memory parity error line. */
+ reason = (reason & 0xf) | 4;
+@@ -754,9 +801,15 @@ io_check_error(unsigned char reason, str
+
+ static __kprobes void
+ unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+-{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+- printk("Dazed and confused, but trying to continue\n");
+- printk("Do you have a strange power saving mode enabled?\n");
++{
++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
++ reason);
++ printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
++
++ if (panic_on_unrecovered_nmi)
++ panic("NMI: Not continuing");
++
++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+ }
+
+ /* Runs on IST stack. This code must keep interrupts off all the time.
+@@ -776,17 +829,15 @@ asmlinkage __kprobes void default_do_nmi
+ if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
+ == NOTIFY_STOP)
+ return;
+-#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * Ok, so this is none of the documented NMI sources,
+ * so it must be the NMI watchdog.
+ */
+- if (nmi_watchdog > 0) {
+- nmi_watchdog_tick(regs,reason);
++ if (nmi_watchdog_tick(regs,reason))
+ return;
+- }
+-#endif
+- unknown_nmi_error(reason, regs);
++ if (!do_nmi_callback(regs,cpu))
++ unknown_nmi_error(reason, regs);
++
+ return;
+ }
+ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+@@ -1071,6 +1122,7 @@ asmlinkage void math_state_restore(void)
+ init_fpu(me);
+ restore_fpu_checking(&me->thread.i387.fxsave);
+ task_thread_info(me)->status |= TS_USEDFPU;
++ me->fpu_counter++;
+ }
+
+ void __init trap_init(void)
+@@ -1109,24 +1161,30 @@ void __init trap_init(void)
+ }
+
+
+-/* Actual parsing is done early in setup.c. */
+-static int __init oops_dummy(char *s)
++static int __init oops_setup(char *s)
+ {
+- panic_on_oops = 1;
+- return 1;
++ if (!s)
++ return -EINVAL;
++ if (!strcmp(s, "panic"))
++ panic_on_oops = 1;
++ return 0;
+ }
+-__setup("oops=", oops_dummy);
++early_param("oops", oops_setup);
+
+ static int __init kstack_setup(char *s)
+ {
++ if (!s)
++ return -EINVAL;
+ kstack_depth_to_print = simple_strtoul(s,NULL,0);
+- return 1;
++ return 0;
+ }
+-__setup("kstack=", kstack_setup);
++early_param("kstack", kstack_setup);
+
+ #ifdef CONFIG_STACK_UNWIND
+ static int __init call_trace_setup(char *s)
+ {
++ if (!s)
++ return -EINVAL;
+ if (strcmp(s, "old") == 0)
+ call_trace = -1;
+ else if (strcmp(s, "both") == 0)
+@@ -1135,7 +1193,7 @@ static int __init call_trace_setup(char
+ call_trace = 1;
+ else if (strcmp(s, "new") == 0)
+ call_trace = 2;
+- return 1;
++ return 0;
+ }
+-__setup("call_trace=", call_trace_setup);
++early_param("call_trace", call_trace_setup);
+ #endif
+diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
+index 7c4de31..edb24aa 100644
+--- a/arch/x86_64/kernel/vmlinux.lds.S
++++ b/arch/x86_64/kernel/vmlinux.lds.S
+@@ -13,6 +13,13 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86
+ OUTPUT_ARCH(i386:x86-64)
+ ENTRY(phys_startup_64)
+ jiffies_64 = jiffies;
++PHDRS {
++ text PT_LOAD FLAGS(5); /* R_E */
++ data PT_LOAD FLAGS(7); /* RWE */
++ user PT_LOAD FLAGS(7); /* RWE */
++ data.init PT_LOAD FLAGS(7); /* RWE */
++ note PT_NOTE FLAGS(4); /* R__ */
++}
+ SECTIONS
+ {
+ . = __START_KERNEL;
+@@ -31,7 +38,7 @@ SECTIONS
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+- } = 0x9090
++ } :text = 0x9090
+ /* out-of-line lock text */
+ .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
+
+@@ -57,17 +64,10 @@ SECTIONS
+ .data : AT(ADDR(.data) - LOAD_OFFSET) {
+ *(.data)
+ CONSTRUCTORS
+- }
++ } :data
+
+ _edata = .; /* End of data section */
+
+- __bss_start = .; /* BSS */
+- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+- *(.bss.page_aligned)
+- *(.bss)
+- }
+- __bss_stop = .;
+-
+ . = ALIGN(PAGE_SIZE);
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+@@ -89,7 +89,7 @@ SECTIONS
+ #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+
+ . = VSYSCALL_ADDR;
+- .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) }
++ .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user
+ __vsyscall_0 = VSYSCALL_VIRT_ADDR;
+
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+@@ -99,8 +99,8 @@ SECTIONS
+ .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) }
+ vxtime = VVIRT(.vxtime);
+
+- .wall_jiffies : AT(VLOAD(.wall_jiffies)) { *(.wall_jiffies) }
+- wall_jiffies = VVIRT(.wall_jiffies);
++ .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
++ vgetcpu_mode = VVIRT(.vgetcpu_mode);
+
+ .sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) }
+ sys_tz = VVIRT(.sys_tz);
+@@ -132,7 +132,7 @@ SECTIONS
+ . = ALIGN(8192); /* init_task */
+ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+ *(.data.init_task)
+- }
++ }:data.init
+
+ . = ALIGN(4096);
+ .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+@@ -175,13 +175,7 @@ SECTIONS
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+@@ -207,14 +201,12 @@ SECTIONS
+ __initramfs_start = .;
+ .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
+ __initramfs_end = .;
+- /* temporary here to work around NR_CPUS. If you see this comment in 2.6.17+
+- complain */
+- . = ALIGN(4096);
+- __init_end = .;
+- . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
++ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ __per_cpu_start = .;
+ .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
+ __per_cpu_end = .;
++ . = ALIGN(4096);
++ __init_end = .;
+
+ . = ALIGN(4096);
+ __nosave_begin = .;
+@@ -222,6 +214,13 @@ SECTIONS
+ . = ALIGN(4096);
+ __nosave_end = .;
+
++ __bss_start = .; /* BSS */
++ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
++ *(.bss.page_aligned)
++ *(.bss)
++ }
++ __bss_stop = .;
++
+ _end = . ;
+
+ /* Sections to be discarded */
+diff --git a/arch/x86_64/kernel/vsmp.c b/arch/x86_64/kernel/vsmp.c
+index 92f70c7..414caf0 100644
+--- a/arch/x86_64/kernel/vsmp.c
++++ b/arch/x86_64/kernel/vsmp.c
+@@ -14,12 +14,16 @@
+ #include <linux/pci_ids.h>
+ #include <linux/pci_regs.h>
+ #include <asm/pci-direct.h>
++#include <asm/io.h>
+
+ static int __init vsmp_init(void)
+ {
+ void *address;
+ unsigned int cap, ctl;
+
++ if (!early_pci_allowed())
++ return 0;
++
+ /* Check if we are running on a ScaleMP vSMP box */
+ if ((read_pci_config_16(0, 0x1f, 0, PCI_VENDOR_ID) != PCI_VENDOR_ID_SCALEMP) ||
+ (read_pci_config_16(0, 0x1f, 0, PCI_DEVICE_ID) != PCI_DEVICE_ID_SCALEMP_VSMP_CTL))
+diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
+index f603037..a98b460 100644
+--- a/arch/x86_64/kernel/vsyscall.c
++++ b/arch/x86_64/kernel/vsyscall.c
+@@ -26,6 +26,7 @@
+ #include <linux/seqlock.h>
+ #include <linux/jiffies.h>
+ #include <linux/sysctl.h>
++#include <linux/getcpu.h>
+
+ #include <asm/vsyscall.h>
+ #include <asm/pgtable.h>
+@@ -33,11 +34,15 @@
+ #include <asm/fixmap.h>
+ #include <asm/errno.h>
+ #include <asm/io.h>
++#include <asm/segment.h>
++#include <asm/desc.h>
++#include <asm/topology.h>
+
+ #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
+
+ int __sysctl_vsyscall __section_sysctl_vsyscall = 1;
+ seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED;
++int __vgetcpu_mode __section_vgetcpu_mode;
+
+ #include <asm/unistd.h>
+
+@@ -61,8 +66,7 @@ static __always_inline void do_vgettimeo
+ sequence = read_seqbegin(&__xtime_lock);
+
+ sec = __xtime.tv_sec;
+- usec = (__xtime.tv_nsec / 1000) +
+- (__jiffies - __wall_jiffies) * (1000000 / HZ);
++ usec = __xtime.tv_nsec / 1000;
+
+ if (__vxtime.mode != VXTIME_HPET) {
+ t = get_cycles_sync();
+@@ -72,7 +76,8 @@ static __always_inline void do_vgettimeo
+ __vxtime.tsc_quot) >> 32;
+ /* See comment in x86_64 do_gettimeofday. */
+ } else {
+- usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) -
++ usec += ((readl((void __iomem *)
++ fix_to_virt(VSYSCALL_HPET) + 0xf0) -
+ __vxtime.last) * __vxtime.quot) >> 32;
+ }
+ } while (read_seqretry(&__xtime_lock, sequence));
+@@ -127,9 +132,46 @@ time_t __vsyscall(1) vtime(time_t *t)
+ return __xtime.tv_sec;
+ }
+
+-long __vsyscall(2) venosys_0(void)
++/* Fast way to get current CPU and node.
++ This helps to do per node and per CPU caches in user space.
++ The result is not guaranteed without CPU affinity, but usually
++ works out because the scheduler tries to keep a thread on the same
++ CPU.
++
++ tcache must point to a two element sized long array.
++ All arguments can be NULL. */
++long __vsyscall(2)
++vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+ {
+- return -ENOSYS;
++ unsigned int dummy, p;
++ unsigned long j = 0;
++
++ /* Fast cache - only recompute value once per jiffies and avoid
++ relatively costly rdtscp/cpuid otherwise.
++ This works because the scheduler usually keeps the process
++ on the same CPU and this syscall doesn't guarantee its
++ results anyways.
++ We do this here because otherwise user space would do it on
++ its own in a likely inferior way (no access to jiffies).
++ If you don't like it pass NULL. */
++ if (tcache && tcache->blob[0] == (j = __jiffies)) {
++ p = tcache->blob[1];
++ } else if (__vgetcpu_mode == VGETCPU_RDTSCP) {
++ /* Load per CPU data from RDTSCP */
++ rdtscp(dummy, dummy, p);
++ } else {
++ /* Load per CPU data from GDT */
++ asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
++ }
++ if (tcache) {
++ tcache->blob[0] = j;
++ tcache->blob[1] = p;
++ }
++ if (cpu)
++ *cpu = p & 0xfff;
++ if (node)
++ *node = p >> 12;
++ return 0;
+ }
+
+ long __vsyscall(3) venosys_1(void)
+@@ -149,7 +191,8 @@ static int vsyscall_sysctl_change(ctl_ta
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+ extern u16 vsysc1, vsysc2;
+- u16 *map1, *map2;
++ u16 __iomem *map1;
++ u16 __iomem *map2;
+ int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+ if (!write)
+ return ret;
+@@ -164,11 +207,11 @@ static int vsyscall_sysctl_change(ctl_ta
+ goto out;
+ }
+ if (!sysctl_vsyscall) {
+- *map1 = SYSCALL;
+- *map2 = SYSCALL;
++ writew(SYSCALL, map1);
++ writew(SYSCALL, map2);
+ } else {
+- *map1 = NOP2;
+- *map2 = NOP2;
++ writew(NOP2, map1);
++ writew(NOP2, map2);
+ }
+ iounmap(map2);
+ out:
+@@ -200,6 +243,43 @@ static ctl_table kernel_root_table2[] =
+
+ #endif
+
++static void __cpuinit write_rdtscp_cb(void *info)
++{
++ write_rdtscp_aux((unsigned long)info);
++}
++
++void __cpuinit vsyscall_set_cpu(int cpu)
++{
++ unsigned long *d;
++ unsigned long node = 0;
++#ifdef CONFIG_NUMA
++ node = cpu_to_node[cpu];
++#endif
++ if (cpu_has(&cpu_data[cpu], X86_FEATURE_RDTSCP)) {
++ void *info = (void *)((node << 12) | cpu);
++ /* Can happen on preemptive kernel */
++ if (get_cpu() == cpu)
++ write_rdtscp_cb(info);
++#ifdef CONFIG_SMP
++ else {
++ /* the notifier is unfortunately not executed on the
++ target CPU */
++ smp_call_function_single(cpu,write_rdtscp_cb,info,0,1);
++ }
++#endif
++ put_cpu();
++ }
++
++ /* Store cpu number in limit so that it can be loaded quickly
++ in user space in vgetcpu.
++ 12 bits for the CPU and 8 bits for the node. */
++ d = (unsigned long *)(cpu_gdt(cpu) + GDT_ENTRY_PER_CPU);
++ *d = 0x0f40000000000ULL;
++ *d |= cpu;
++ *d |= (node & 0xf) << 12;
++ *d |= (node >> 4) << 48;
++}
++
+ static void __init map_vsyscall(void)
+ {
+ extern char __vsyscall_0;
+@@ -214,6 +294,7 @@ static int __init vsyscall_init(void)
+ VSYSCALL_ADDR(__NR_vgettimeofday)));
+ BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
+ BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
++ BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu));
+ map_vsyscall();
+ #ifdef CONFIG_SYSCTL
+ register_sysctl_table(kernel_root_table2, 0);
+diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
+index 370952c..6d77e47 100644
+--- a/arch/x86_64/kernel/x8664_ksyms.c
++++ b/arch/x86_64/kernel/x8664_ksyms.c
+@@ -1,7 +1,6 @@
+ /* Exports for assembly files.
+ All C exports should go in the respective C files. */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/smp.h>
+
+@@ -29,6 +28,7 @@ EXPORT_SYMBOL(__put_user_8);
+ EXPORT_SYMBOL(copy_user_generic);
+ EXPORT_SYMBOL(copy_from_user);
+ EXPORT_SYMBOL(copy_to_user);
++EXPORT_SYMBOL(__copy_from_user_inatomic);
+
+ EXPORT_SYMBOL(copy_page);
+ EXPORT_SYMBOL(clear_page);
+diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile
+index ccef6ae..b78d417 100644
+--- a/arch/x86_64/lib/Makefile
++++ b/arch/x86_64/lib/Makefile
+@@ -9,4 +9,4 @@ obj-y := io.o iomap_copy.o
+ lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \
+ usercopy.o getuser.o putuser.o \
+ thunk.o clear_page.o copy_page.o bitstr.o bitops.o
+-lib-y += memcpy.o memmove.o memset.o copy_user.o
++lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o
+diff --git a/arch/x86_64/lib/clear_page.S b/arch/x86_64/lib/clear_page.S
+index 1f81b79..9a10a78 100644
+--- a/arch/x86_64/lib/clear_page.S
++++ b/arch/x86_64/lib/clear_page.S
+@@ -1,10 +1,22 @@
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++
+ /*
+ * Zero a page.
+ * rdi page
+ */
+- .globl clear_page
+- .p2align 4
+-clear_page:
++ ALIGN
++clear_page_c:
++ CFI_STARTPROC
++ movl $4096/8,%ecx
++ xorl %eax,%eax
++ rep stosq
++ ret
++ CFI_ENDPROC
++ENDPROC(clear_page)
++
++ENTRY(clear_page)
++ CFI_STARTPROC
+ xorl %eax,%eax
+ movl $4096/64,%ecx
+ .p2align 4
+@@ -23,28 +35,25 @@ clear_page:
+ jnz .Lloop
+ nop
+ ret
+-clear_page_end:
++ CFI_ENDPROC
++.Lclear_page_end:
++ENDPROC(clear_page)
+
+ /* Some CPUs run faster using the string instructions.
+ It is also a lot simpler. Use this when possible */
+
+ #include <asm/cpufeature.h>
+
++ .section .altinstr_replacement,"ax"
++1: .byte 0xeb /* jmp <disp8> */
++ .byte (clear_page_c - clear_page) - (2f - 1b) /* offset */
++2:
++ .previous
+ .section .altinstructions,"a"
+ .align 8
+- .quad clear_page
+- .quad clear_page_c
+- .byte X86_FEATURE_REP_GOOD
+- .byte clear_page_end-clear_page
+- .byte clear_page_c_end-clear_page_c
+- .previous
+-
+- .section .altinstr_replacement,"ax"
+-clear_page_c:
+- movl $4096/8,%ecx
+- xorl %eax,%eax
+- rep
+- stosq
+- ret
+-clear_page_c_end:
++ .quad clear_page
++ .quad 1b
++ .byte X86_FEATURE_REP_GOOD
++ .byte .Lclear_page_end - clear_page
++ .byte 2b - 1b
+ .previous
+diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S
+index 8fa19d9..727a5d4 100644
+--- a/arch/x86_64/lib/copy_page.S
++++ b/arch/x86_64/lib/copy_page.S
+@@ -1,17 +1,32 @@
+ /* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
+-
++
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++
++ ALIGN
++copy_page_c:
++ CFI_STARTPROC
++ movl $4096/8,%ecx
++ rep movsq
++ ret
++ CFI_ENDPROC
++ENDPROC(copy_page_c)
++
+ /* Don't use streaming store because it's better when the target
+ ends up in cache. */
+
+ /* Could vary the prefetch distance based on SMP/UP */
+
+- .globl copy_page
+- .p2align 4
+-copy_page:
++ENTRY(copy_page)
++ CFI_STARTPROC
+ subq $3*8,%rsp
++ CFI_ADJUST_CFA_OFFSET 3*8
+ movq %rbx,(%rsp)
++ CFI_REL_OFFSET rbx, 0
+ movq %r12,1*8(%rsp)
++ CFI_REL_OFFSET r12, 1*8
+ movq %r13,2*8(%rsp)
++ CFI_REL_OFFSET r13, 2*8
+
+ movl $(4096/64)-5,%ecx
+ .p2align 4
+@@ -72,30 +87,33 @@ copy_page:
+ jnz .Loop2
+
+ movq (%rsp),%rbx
++ CFI_RESTORE rbx
+ movq 1*8(%rsp),%r12
++ CFI_RESTORE r12
+ movq 2*8(%rsp),%r13
++ CFI_RESTORE r13
+ addq $3*8,%rsp
++ CFI_ADJUST_CFA_OFFSET -3*8
+ ret
++.Lcopy_page_end:
++ CFI_ENDPROC
++ENDPROC(copy_page)
+
+ /* Some CPUs run faster using the string copy instructions.
+ It is also a lot simpler. Use this when possible */
+
+ #include <asm/cpufeature.h>
+
++ .section .altinstr_replacement,"ax"
++1: .byte 0xeb /* jmp <disp8> */
++ .byte (copy_page_c - copy_page) - (2f - 1b) /* offset */
++2:
++ .previous
+ .section .altinstructions,"a"
+ .align 8
+- .quad copy_page
+- .quad copy_page_c
+- .byte X86_FEATURE_REP_GOOD
+- .byte copy_page_c_end-copy_page_c
+- .byte copy_page_c_end-copy_page_c
+- .previous
+-
+- .section .altinstr_replacement,"ax"
+-copy_page_c:
+- movl $4096/8,%ecx
+- rep
+- movsq
+- ret
+-copy_page_c_end:
++ .quad copy_page
++ .quad 1b
++ .byte X86_FEATURE_REP_GOOD
++ .byte .Lcopy_page_end - copy_page
++ .byte 2b - 1b
+ .previous
+diff --git a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user.S
+index f64569b..70bebd3 100644
+--- a/arch/x86_64/lib/copy_user.S
++++ b/arch/x86_64/lib/copy_user.S
+@@ -4,56 +4,78 @@
+ * Functions to copy from and to user space.
+ */
+
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++
+ #define FIX_ALIGNMENT 1
+
+- #include <asm/current.h>
+- #include <asm/asm-offsets.h>
+- #include <asm/thread_info.h>
+- #include <asm/cpufeature.h>
++#include <asm/current.h>
++#include <asm/asm-offsets.h>
++#include <asm/thread_info.h>
++#include <asm/cpufeature.h>
+
+-/* Standard copy_to_user with segment limit checking */
+- .globl copy_to_user
+- .p2align 4
+-copy_to_user:
+- GET_THREAD_INFO(%rax)
+- movq %rdi,%rcx
+- addq %rdx,%rcx
+- jc bad_to_user
+- cmpq threadinfo_addr_limit(%rax),%rcx
+- jae bad_to_user
+-2:
++ .macro ALTERNATIVE_JUMP feature,orig,alt
++0:
+ .byte 0xe9 /* 32bit jump */
+- .long .Lcug-1f
++ .long \orig-1f /* by default jump to orig */
+ 1:
+-
+ .section .altinstr_replacement,"ax"
+-3: .byte 0xe9 /* replacement jmp with 8 bit immediate */
+- .long copy_user_generic_c-1b /* offset */
++2: .byte 0xe9 /* near jump with 32bit immediate */
++ .long \alt-1b /* offset */ /* or alternatively to alt */
+ .previous
+ .section .altinstructions,"a"
+ .align 8
++ .quad 0b
+ .quad 2b
+- .quad 3b
+- .byte X86_FEATURE_REP_GOOD
++ .byte \feature /* when feature is set */
+ .byte 5
+ .byte 5
+ .previous
++ .endm
++
++/* Standard copy_to_user with segment limit checking */
++ENTRY(copy_to_user)
++ CFI_STARTPROC
++ GET_THREAD_INFO(%rax)
++ movq %rdi,%rcx
++ addq %rdx,%rcx
++ jc bad_to_user
++ cmpq threadinfo_addr_limit(%rax),%rcx
++ jae bad_to_user
++ xorl %eax,%eax /* clear zero flag */
++ ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
++ CFI_ENDPROC
++
++ENTRY(copy_user_generic)
++ CFI_STARTPROC
++ movl $1,%ecx /* set zero flag */
++ ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
++ CFI_ENDPROC
++
++ENTRY(__copy_from_user_inatomic)
++ CFI_STARTPROC
++ xorl %ecx,%ecx /* clear zero flag */
++ ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
++ CFI_ENDPROC
+
+ /* Standard copy_from_user with segment limit checking */
+- .globl copy_from_user
+- .p2align 4
+-copy_from_user:
++ENTRY(copy_from_user)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%rax)
+ movq %rsi,%rcx
+ addq %rdx,%rcx
+ jc bad_from_user
+ cmpq threadinfo_addr_limit(%rax),%rcx
+ jae bad_from_user
+- /* FALL THROUGH to copy_user_generic */
++ movl $1,%ecx /* set zero flag */
++ ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
++ CFI_ENDPROC
++ENDPROC(copy_from_user)
+
+ .section .fixup,"ax"
+ /* must zero dest */
+ bad_from_user:
++ CFI_STARTPROC
+ movl %edx,%ecx
+ xorl %eax,%eax
+ rep
+@@ -61,40 +83,32 @@ bad_from_user:
+ bad_to_user:
+ movl %edx,%eax
+ ret
++ CFI_ENDPROC
++END(bad_from_user)
+ .previous
+
+
+ /*
+- * copy_user_generic - memory copy with exception handling.
++ * copy_user_generic_unrolled - memory copy with exception handling.
++ * This version is for CPUs like P4 that don't have efficient micro code for rep movsq
+ *
+ * Input:
+ * rdi destination
+ * rsi source
+ * rdx count
++ * ecx zero flag -- if true zero destination on error
+ *
+ * Output:
+ * eax uncopied bytes or 0 if successful.
+ */
+- .globl copy_user_generic
+- .p2align 4
+-copy_user_generic:
+- .byte 0x66,0x66,0x90 /* 5 byte nop for replacement jump */
+- .byte 0x66,0x90
+-1:
+- .section .altinstr_replacement,"ax"
+-2: .byte 0xe9 /* near jump with 32bit immediate */
+- .long copy_user_generic_c-1b /* offset */
+- .previous
+- .section .altinstructions,"a"
+- .align 8
+- .quad copy_user_generic
+- .quad 2b
+- .byte X86_FEATURE_REP_GOOD
+- .byte 5
+- .byte 5
+- .previous
+-.Lcug:
++ENTRY(copy_user_generic_unrolled)
++ CFI_STARTPROC
+ pushq %rbx
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rbx, 0
++ pushq %rcx
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rcx, 0
+ xorl %eax,%eax /*zero for the exception handler */
+
+ #ifdef FIX_ALIGNMENT
+@@ -168,9 +182,16 @@ copy_user_generic:
+ decl %ecx
+ jnz .Lloop_1
+
++ CFI_REMEMBER_STATE
+ .Lende:
++ popq %rcx
++ CFI_ADJUST_CFA_OFFSET -8
++ CFI_RESTORE rcx
+ popq %rbx
++ CFI_ADJUST_CFA_OFFSET -8
++ CFI_RESTORE rbx
+ ret
++ CFI_RESTORE_STATE
+
+ #ifdef FIX_ALIGNMENT
+ /* align destination */
+@@ -252,6 +273,8 @@ copy_user_generic:
+ addl %ecx,%edx
+ /* edx: bytes to zero, rdi: dest, eax:zero */
+ .Lzero_rest:
++ cmpl $0,(%rsp)
++ jz .Le_zero
+ movq %rdx,%rcx
+ .Le_byte:
+ xorl %eax,%eax
+@@ -261,6 +284,9 @@ copy_user_generic:
+ .Le_zero:
+ movq %rdx,%rax
+ jmp .Lende
++ CFI_ENDPROC
++ENDPROC(copy_user_generic)
++
+
+ /* Some CPUs run faster using the string copy instructions.
+ This is also a lot simpler. Use them when possible.
+@@ -270,6 +296,7 @@ copy_user_generic:
+ /* rdi destination
+ * rsi source
+ * rdx count
++ * ecx zero flag
+ *
+ * Output:
+ * eax uncopied bytes or 0 if successfull.
+@@ -280,22 +307,48 @@ copy_user_generic:
+ * And more would be dangerous because both Intel and AMD have
+ * errata with rep movsq > 4GB. If someone feels the need to fix
+ * this please consider this.
+- */
+-copy_user_generic_c:
++ */
++ENTRY(copy_user_generic_string)
++ CFI_STARTPROC
++ movl %ecx,%r8d /* save zero flag */
+ movl %edx,%ecx
+ shrl $3,%ecx
+ andl $7,%edx
++ jz 10f
+ 1: rep
+ movsq
+ movl %edx,%ecx
+ 2: rep
+ movsb
+-4: movl %ecx,%eax
++9: movl %ecx,%eax
+ ret
+-3: lea (%rdx,%rcx,8),%rax
++
++ /* multiple of 8 byte */
++10: rep
++ movsq
++ xor %eax,%eax
+ ret
+
++ /* exception handling */
++3: lea (%rdx,%rcx,8),%rax /* exception on quad loop */
++ jmp 6f
++5: movl %ecx,%eax /* exception on byte loop */
++ /* eax: left over bytes */
++6: testl %r8d,%r8d /* zero flag set? */
++ jz 7f
++ movl %eax,%ecx /* initialize x86 loop counter */
++ push %rax
++ xorl %eax,%eax
++8: rep
++ stosb /* zero the rest */
++11: pop %rax
++7: ret
++ CFI_ENDPROC
++END(copy_user_generic_c)
++
+ .section __ex_table,"a"
+ .quad 1b,3b
+- .quad 2b,4b
++ .quad 2b,5b
++ .quad 8b,11b
++ .quad 10b,3b
+ .previous
+diff --git a/arch/x86_64/lib/csum-copy.S b/arch/x86_64/lib/csum-copy.S
+index 72fd55e..f0dba36 100644
+--- a/arch/x86_64/lib/csum-copy.S
++++ b/arch/x86_64/lib/csum-copy.S
+@@ -5,8 +5,9 @@
+ * License. See the file COPYING in the main directory of this archive
+ * for more details. No warranty for anything given at all.
+ */
+- #include <linux/linkage.h>
+- #include <asm/errno.h>
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++#include <asm/errno.h>
+
+ /*
+ * Checksum copy with exception handling.
+@@ -53,19 +54,24 @@
+ .endm
+
+
+- .globl csum_partial_copy_generic
+- .p2align 4
+-csum_partial_copy_generic:
++ENTRY(csum_partial_copy_generic)
++ CFI_STARTPROC
+ cmpl $3*64,%edx
+ jle .Lignore
+
+ .Lignore:
+ subq $7*8,%rsp
++ CFI_ADJUST_CFA_OFFSET 7*8
+ movq %rbx,2*8(%rsp)
++ CFI_REL_OFFSET rbx, 2*8
+ movq %r12,3*8(%rsp)
++ CFI_REL_OFFSET r12, 3*8
+ movq %r14,4*8(%rsp)
++ CFI_REL_OFFSET r14, 4*8
+ movq %r13,5*8(%rsp)
++ CFI_REL_OFFSET r13, 5*8
+ movq %rbp,6*8(%rsp)
++ CFI_REL_OFFSET rbp, 6*8
+
+ movq %r8,(%rsp)
+ movq %r9,1*8(%rsp)
+@@ -208,14 +214,22 @@ csum_partial_copy_generic:
+ addl %ebx,%eax
+ adcl %r9d,%eax /* carry */
+
++ CFI_REMEMBER_STATE
+ .Lende:
+ movq 2*8(%rsp),%rbx
++ CFI_RESTORE rbx
+ movq 3*8(%rsp),%r12
++ CFI_RESTORE r12
+ movq 4*8(%rsp),%r14
++ CFI_RESTORE r14
+ movq 5*8(%rsp),%r13
++ CFI_RESTORE r13
+ movq 6*8(%rsp),%rbp
++ CFI_RESTORE rbp
+ addq $7*8,%rsp
++ CFI_ADJUST_CFA_OFFSET -7*8
+ ret
++ CFI_RESTORE_STATE
+
+ /* Exception handlers. Very simple, zeroing is done in the wrappers */
+ .Lbad_source:
+@@ -231,3 +245,5 @@ csum_partial_copy_generic:
+ jz .Lende
+ movl $-EFAULT,(%rax)
+ jmp .Lende
++ CFI_ENDPROC
++ENDPROC(csum_partial_copy_generic)
+diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
+index b6cd3cc..50be909 100644
+--- a/arch/x86_64/lib/delay.c
++++ b/arch/x86_64/lib/delay.c
+@@ -8,7 +8,6 @@
+ * depends wildly on alignment on many x86 processors.
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/delay.h>
+diff --git a/arch/x86_64/lib/getuser.S b/arch/x86_64/lib/getuser.S
+index 3844d5e..5448876 100644
+--- a/arch/x86_64/lib/getuser.S
++++ b/arch/x86_64/lib/getuser.S
+@@ -27,25 +27,26 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/dwarf2.h>
+ #include <asm/page.h>
+ #include <asm/errno.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/thread_info.h>
+
+ .text
+- .p2align 4
+-.globl __get_user_1
+-__get_user_1:
++ENTRY(__get_user_1)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae bad_get_user
+ 1: movzb (%rcx),%edx
+ xorl %eax,%eax
+ ret
++ CFI_ENDPROC
++ENDPROC(__get_user_1)
+
+- .p2align 4
+-.globl __get_user_2
+-__get_user_2:
++ENTRY(__get_user_2)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ addq $1,%rcx
+ jc 20f
+@@ -57,10 +58,11 @@ __get_user_2:
+ ret
+ 20: decq %rcx
+ jmp bad_get_user
++ CFI_ENDPROC
++ENDPROC(__get_user_2)
+
+- .p2align 4
+-.globl __get_user_4
+-__get_user_4:
++ENTRY(__get_user_4)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ addq $3,%rcx
+ jc 30f
+@@ -72,10 +74,11 @@ __get_user_4:
+ ret
+ 30: subq $3,%rcx
+ jmp bad_get_user
++ CFI_ENDPROC
++ENDPROC(__get_user_4)
+
+- .p2align 4
+-.globl __get_user_8
+-__get_user_8:
++ENTRY(__get_user_8)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ addq $7,%rcx
+ jc 40f
+@@ -87,11 +90,16 @@ __get_user_8:
+ ret
+ 40: subq $7,%rcx
+ jmp bad_get_user
++ CFI_ENDPROC
++ENDPROC(__get_user_8)
+
+ bad_get_user:
++ CFI_STARTPROC
+ xorl %edx,%edx
+ movq $(-EFAULT),%rax
+ ret
++ CFI_ENDPROC
++END(bad_get_user)
+
+ .section __ex_table,"a"
+ .quad 1b,bad_get_user
+diff --git a/arch/x86_64/lib/iomap_copy.S b/arch/x86_64/lib/iomap_copy.S
+index 8bbade5..05a95e7 100644
+--- a/arch/x86_64/lib/iomap_copy.S
++++ b/arch/x86_64/lib/iomap_copy.S
+@@ -15,12 +15,16 @@
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++
+ /*
+ * override generic version in lib/iomap_copy.c
+ */
+- .globl __iowrite32_copy
+- .p2align 4
+-__iowrite32_copy:
++ENTRY(__iowrite32_copy)
++ CFI_STARTPROC
+ movl %edx,%ecx
+ rep movsd
+ ret
++ CFI_ENDPROC
++ENDPROC(__iowrite32_copy)
+diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S
+index 5554948..0ea0ddc 100644
+--- a/arch/x86_64/lib/memcpy.S
++++ b/arch/x86_64/lib/memcpy.S
+@@ -1,6 +1,9 @@
+ /* Copyright 2002 Andi Kleen */
+-
+- #include <asm/cpufeature.h>
++
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++#include <asm/cpufeature.h>
++
+ /*
+ * memcpy - Copy a memory block.
+ *
+@@ -13,12 +16,26 @@
+ * rax original destination
+ */
+
+- .globl __memcpy
+- .globl memcpy
+- .p2align 4
+-__memcpy:
+-memcpy:
++ ALIGN
++memcpy_c:
++ CFI_STARTPROC
++ movq %rdi,%rax
++ movl %edx,%ecx
++ shrl $3,%ecx
++ andl $7,%edx
++ rep movsq
++ movl %edx,%ecx
++ rep movsb
++ ret
++ CFI_ENDPROC
++ENDPROC(memcpy_c)
++
++ENTRY(__memcpy)
++ENTRY(memcpy)
++ CFI_STARTPROC
+ pushq %rbx
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rbx, 0
+ movq %rdi,%rax
+
+ movl %edx,%ecx
+@@ -86,36 +103,27 @@ memcpy:
+
+ .Lende:
+ popq %rbx
++ CFI_ADJUST_CFA_OFFSET -8
++ CFI_RESTORE rbx
+ ret
+ .Lfinal:
++ CFI_ENDPROC
++ENDPROC(memcpy)
++ENDPROC(__memcpy)
+
+ /* Some CPUs run faster using the string copy instructions.
+ It is also a lot simpler. Use this when possible */
+
++ .section .altinstr_replacement,"ax"
++1: .byte 0xeb /* jmp <disp8> */
++ .byte (memcpy_c - memcpy) - (2f - 1b) /* offset */
++2:
++ .previous
+ .section .altinstructions,"a"
+ .align 8
+- .quad memcpy
+- .quad memcpy_c
+- .byte X86_FEATURE_REP_GOOD
+- .byte .Lfinal-memcpy
+- .byte memcpy_c_end-memcpy_c
+- .previous
+-
+- .section .altinstr_replacement,"ax"
+- /* rdi destination
+- * rsi source
+- * rdx count
+- */
+-memcpy_c:
+- movq %rdi,%rax
+- movl %edx,%ecx
+- shrl $3,%ecx
+- andl $7,%edx
+- rep
+- movsq
+- movl %edx,%ecx
+- rep
+- movsb
+- ret
+-memcpy_c_end:
++ .quad memcpy
++ .quad 1b
++ .byte X86_FEATURE_REP_GOOD
++ .byte .Lfinal - memcpy
++ .byte 2b - 1b
+ .previous
+diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S
+index ad397f2..2c59481 100644
+--- a/arch/x86_64/lib/memset.S
++++ b/arch/x86_64/lib/memset.S
+@@ -1,4 +1,8 @@
+ /* Copyright 2002 Andi Kleen, SuSE Labs */
++
++#include <linux/linkage.h>
++#include <asm/dwarf2.h>
++
+ /*
+ * ISO C memset - set a memory block to a byte value.
+ *
+@@ -8,11 +12,29 @@
+ *
+ * rax original destination
+ */
+- .globl __memset
+- .globl memset
+- .p2align 4
+-memset:
+-__memset:
++ ALIGN
++memset_c:
++ CFI_STARTPROC
++ movq %rdi,%r9
++ movl %edx,%r8d
++ andl $7,%r8d
++ movl %edx,%ecx
++ shrl $3,%ecx
++ /* expand byte value */
++ movzbl %sil,%esi
++ movabs $0x0101010101010101,%rax
++ mulq %rsi /* with rax, clobbers rdx */
++ rep stosq
++ movl %r8d,%ecx
++ rep stosb
++ movq %r9,%rax
++ ret
++ CFI_ENDPROC
++ENDPROC(memset_c)
++
++ENTRY(memset)
++ENTRY(__memset)
++ CFI_STARTPROC
+ movq %rdi,%r10
+ movq %rdx,%r11
+
+@@ -25,6 +47,7 @@ __memset:
+ movl %edi,%r9d
+ andl $7,%r9d
+ jnz .Lbad_alignment
++ CFI_REMEMBER_STATE
+ .Lafter_bad_alignment:
+
+ movl %r11d,%ecx
+@@ -75,6 +98,7 @@ __memset:
+ movq %r10,%rax
+ ret
+
++ CFI_RESTORE_STATE
+ .Lbad_alignment:
+ cmpq $7,%r11
+ jbe .Lhandle_7
+@@ -84,42 +108,26 @@ __memset:
+ addq %r8,%rdi
+ subq %r8,%r11
+ jmp .Lafter_bad_alignment
++.Lfinal:
++ CFI_ENDPROC
++ENDPROC(memset)
++ENDPROC(__memset)
+
+ /* Some CPUs run faster using the string instructions.
+ It is also a lot simpler. Use this when possible */
+
+ #include <asm/cpufeature.h>
+
++ .section .altinstr_replacement,"ax"
++1: .byte 0xeb /* jmp <disp8> */
++ .byte (memset_c - memset) - (2f - 1b) /* offset */
++2:
++ .previous
+ .section .altinstructions,"a"
+ .align 8
+- .quad memset
+- .quad memset_c
+- .byte X86_FEATURE_REP_GOOD
+- .byte memset_c_end-memset_c
+- .byte memset_c_end-memset_c
+- .previous
+-
+- .section .altinstr_replacement,"ax"
+- /* rdi destination
+- * rsi value
+- * rdx count
+- */
+-memset_c:
+- movq %rdi,%r9
+- movl %edx,%r8d
+- andl $7,%r8d
+- movl %edx,%ecx
+- shrl $3,%ecx
+- /* expand byte value */
+- movzbl %sil,%esi
+- movabs $0x0101010101010101,%rax
+- mulq %rsi /* with rax, clobbers rdx */
+- rep
+- stosq
+- movl %r8d,%ecx
+- rep
+- stosb
+- movq %r9,%rax
+- ret
+-memset_c_end:
++ .quad memset
++ .quad 1b
++ .byte X86_FEATURE_REP_GOOD
++ .byte .Lfinal - memset
++ .byte 2b - 1b
+ .previous
+diff --git a/arch/x86_64/lib/putuser.S b/arch/x86_64/lib/putuser.S
+index 7f55939..4989f5a 100644
+--- a/arch/x86_64/lib/putuser.S
++++ b/arch/x86_64/lib/putuser.S
+@@ -25,25 +25,26 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/dwarf2.h>
+ #include <asm/page.h>
+ #include <asm/errno.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/thread_info.h>
+
+ .text
+- .p2align 4
+-.globl __put_user_1
+-__put_user_1:
++ENTRY(__put_user_1)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae bad_put_user
+ 1: movb %dl,(%rcx)
+ xorl %eax,%eax
+ ret
++ CFI_ENDPROC
++ENDPROC(__put_user_1)
+
+- .p2align 4
+-.globl __put_user_2
+-__put_user_2:
++ENTRY(__put_user_2)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ addq $1,%rcx
+ jc 20f
+@@ -55,10 +56,11 @@ __put_user_2:
+ ret
+ 20: decq %rcx
+ jmp bad_put_user
++ CFI_ENDPROC
++ENDPROC(__put_user_2)
+
+- .p2align 4
+-.globl __put_user_4
+-__put_user_4:
++ENTRY(__put_user_4)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ addq $3,%rcx
+ jc 30f
+@@ -70,10 +72,11 @@ __put_user_4:
+ ret
+ 30: subq $3,%rcx
+ jmp bad_put_user
++ CFI_ENDPROC
++ENDPROC(__put_user_4)
+
+- .p2align 4
+-.globl __put_user_8
+-__put_user_8:
++ENTRY(__put_user_8)
++ CFI_STARTPROC
+ GET_THREAD_INFO(%r8)
+ addq $7,%rcx
+ jc 40f
+@@ -85,10 +88,15 @@ __put_user_8:
+ ret
+ 40: subq $7,%rcx
+ jmp bad_put_user
++ CFI_ENDPROC
++ENDPROC(__put_user_8)
+
+ bad_put_user:
++ CFI_STARTPROC
+ movq $(-EFAULT),%rax
+ ret
++ CFI_ENDPROC
++END(bad_put_user)
+
+ .section __ex_table,"a"
+ .quad 1b,bad_put_user
+diff --git a/arch/x86_64/lib/rwlock.S b/arch/x86_64/lib/rwlock.S
+new file mode 100644
+index 0000000..0cde1f8
+--- /dev/null
++++ b/arch/x86_64/lib/rwlock.S
+@@ -0,0 +1,38 @@
++/* Slow paths of read/write spinlocks. */
++
++#include <linux/linkage.h>
++#include <asm/rwlock.h>
++#include <asm/alternative-asm.i>
++#include <asm/dwarf2.h>
++
++/* rdi: pointer to rwlock_t */
++ENTRY(__write_lock_failed)
++ CFI_STARTPROC
++ LOCK_PREFIX
++ addl $RW_LOCK_BIAS,(%rdi)
++1: rep
++ nop
++ cmpl $RW_LOCK_BIAS,(%rdi)
++ jne 1b
++ LOCK_PREFIX
++ subl $RW_LOCK_BIAS,(%rdi)
++ jnz __write_lock_failed
++ ret
++ CFI_ENDPROC
++END(__write_lock_failed)
++
++/* rdi: pointer to rwlock_t */
++ENTRY(__read_lock_failed)
++ CFI_STARTPROC
++ LOCK_PREFIX
++ incl (%rdi)
++1: rep
++ nop
++ cmpl $1,(%rdi)
++ js 1b
++ LOCK_PREFIX
++ decl (%rdi)
++ js __read_lock_failed
++ ret
++ CFI_ENDPROC
++END(__read_lock_failed)
+diff --git a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk.S
+index 332ea5d..55e586d 100644
+--- a/arch/x86_64/lib/thunk.S
++++ b/arch/x86_64/lib/thunk.S
+@@ -1,12 +1,10 @@
+- /*
+- * Save registers before calling assembly functions. This avoids
+- * disturbance of register allocation in some inline assembly constructs.
+- * Copyright 2001,2002 by Andi Kleen, SuSE Labs.
+- * Subject to the GNU public license, v.2. No warranty of any kind.
+- * $Id: thunk.S,v 1.2 2002/03/13 20:06:58 ak Exp $
+- */
++/*
++ * Save registers before calling assembly functions. This avoids
++ * disturbance of register allocation in some inline assembly constructs.
++ * Copyright 2001,2002 by Andi Kleen, SuSE Labs.
++ * Subject to the GNU public license, v.2. No warranty of any kind.
++ */
+
+- #include <linux/config.h>
+ #include <linux/linkage.h>
+ #include <asm/dwarf2.h>
+ #include <asm/calling.h>
+@@ -67,33 +65,3 @@ restore_norax:
+ RESTORE_ARGS 1
+ ret
+ CFI_ENDPROC
+-
+-#ifdef CONFIG_SMP
+-/* Support for read/write spinlocks. */
+- .text
+-/* rax: pointer to rwlock_t */
+-ENTRY(__write_lock_failed)
+- lock
+- addl $RW_LOCK_BIAS,(%rax)
+-1: rep
+- nop
+- cmpl $RW_LOCK_BIAS,(%rax)
+- jne 1b
+- lock
+- subl $RW_LOCK_BIAS,(%rax)
+- jnz __write_lock_failed
+- ret
+-
+-/* rax: pointer to rwlock_t */
+-ENTRY(__read_lock_failed)
+- lock
+- incl (%rax)
+-1: rep
+- nop
+- cmpl $1,(%rax)
+- js 1b
+- lock
+- decl (%rax)
+- js __read_lock_failed
+- ret
+-#endif
+diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
+index ac8ea66..3751b47 100644
+--- a/arch/x86_64/mm/fault.c
++++ b/arch/x86_64/mm/fault.c
+@@ -40,8 +40,7 @@
+ #define PF_RSVD (1<<3)
+ #define PF_INSTR (1<<4)
+
+-#ifdef CONFIG_KPROBES
+-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+ /* Hook to register for page fault notifications */
+ int register_page_fault_notifier(struct notifier_block *nb)
+@@ -49,11 +48,13 @@ int register_page_fault_notifier(struct
+ vmalloc_sync_all();
+ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
+ }
++EXPORT_SYMBOL_GPL(register_page_fault_notifier);
+
+ int unregister_page_fault_notifier(struct notifier_block *nb)
+ {
+ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
+ }
++EXPORT_SYMBOL_GPL(unregister_page_fault_notifier);
+
+ static inline int notify_page_fault(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig)
+@@ -67,13 +68,6 @@ static inline int notify_page_fault(enum
+ };
+ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
+ }
+-#else
+-static inline int notify_page_fault(enum die_val val, const char *str,
+- struct pt_regs *regs, long err, int trap, int sig)
+-{
+- return NOTIFY_DONE;
+-}
+-#endif
+
+ void bust_spinlocks(int yes)
+ {
+@@ -102,7 +96,7 @@ void bust_spinlocks(int yes)
+ static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr,
+ unsigned long error_code)
+ {
+- unsigned char *instr;
++ unsigned char __user *instr;
+ int scan_more = 1;
+ int prefetch = 0;
+ unsigned char *max_instr;
+@@ -111,7 +105,7 @@ static noinline int is_prefetch(struct p
+ if (error_code & PF_INSTR)
+ return 0;
+
+- instr = (unsigned char *)convert_rip_to_linear(current, regs);
++ instr = (unsigned char __user *)convert_rip_to_linear(current, regs);
+ max_instr = instr + 15;
+
+ if (user_mode(regs) && instr >= (unsigned char *)TASK_SIZE)
+@@ -122,7 +116,7 @@ static noinline int is_prefetch(struct p
+ unsigned char instr_hi;
+ unsigned char instr_lo;
+
+- if (__get_user(opcode, instr))
++ if (__get_user(opcode, (char __user *)instr))
+ break;
+
+ instr_hi = opcode & 0xf0;
+@@ -160,7 +154,7 @@ static noinline int is_prefetch(struct p
+ case 0x00:
+ /* Prefetch instruction is 0x0F0D or 0x0F18 */
+ scan_more = 0;
+- if (__get_user(opcode, instr))
++ if (__get_user(opcode, (char __user *)instr))
+ break;
+ prefetch = (instr_lo == 0xF) &&
+ (opcode == 0x0D || opcode == 0x18);
+@@ -176,7 +170,7 @@ static noinline int is_prefetch(struct p
+ static int bad_address(void *p)
+ {
+ unsigned long dummy;
+- return __get_user(dummy, (unsigned long *)p);
++ return __get_user(dummy, (unsigned long __user *)p);
+ }
+
+ void dump_pagetable(unsigned long address)
+@@ -250,7 +244,7 @@ static int is_errata93(struct pt_regs *r
+
+ int unhandled_signal(struct task_struct *tsk, int sig)
+ {
+- if (tsk->pid == 1)
++ if (is_init(tsk))
+ return 1;
+ if (tsk->ptrace & PT_PTRACED)
+ return 0;
+@@ -299,7 +293,7 @@ static int vmalloc_fault(unsigned long a
+ if (pgd_none(*pgd))
+ set_pgd(pgd, *pgd_ref);
+ else
+- BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref));
++ BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
+
+ /* Below here mismatches are bugs because these lower tables
+ are shared */
+@@ -308,7 +302,7 @@ static int vmalloc_fault(unsigned long a
+ pud_ref = pud_offset(pgd_ref, address);
+ if (pud_none(*pud_ref))
+ return -1;
+- if (pud_none(*pud) || pud_page(*pud) != pud_page(*pud_ref))
++ if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref))
+ BUG();
+ pmd = pmd_offset(pud, address);
+ pmd_ref = pmd_offset(pud_ref, address);
+@@ -470,7 +464,7 @@ good_area:
+ case PF_PROT: /* read, present */
+ goto bad_area;
+ case 0: /* read, not present */
+- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ }
+
+@@ -586,7 +580,7 @@ no_context:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ goto again;
+ }
+@@ -641,7 +635,7 @@ void vmalloc_sync_all(void)
+ if (pgd_none(*pgd))
+ set_pgd(pgd, *pgd_ref);
+ else
+- BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref));
++ BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
+ }
+ spin_unlock(&pgd_lock);
+ set_bit(pgd_index(address), insync);
+diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
+index d14fb2d..971dc11 100644
+--- a/arch/x86_64/mm/init.c
++++ b/arch/x86_64/mm/init.c
+@@ -229,7 +229,6 @@ __init void *early_ioremap(unsigned long
+
+ /* actually usually some more */
+ if (size >= LARGE_PAGE_SIZE) {
+- printk("SMBIOS area too long %lu\n", size);
+ return NULL;
+ }
+ set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE));
+@@ -250,12 +249,13 @@ __init void early_iounmap(void *addr, un
+ }
+
+ static void __meminit
+-phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end)
++phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
+ {
+- int i;
++ int i = pmd_index(address);
+
+- for (i = 0; i < PTRS_PER_PMD; pmd++, i++, address += PMD_SIZE) {
++ for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
+ unsigned long entry;
++ pmd_t *pmd = pmd_page + pmd_index(address);
+
+ if (address >= end) {
+ if (!after_bootmem)
+@@ -263,6 +263,10 @@ phys_pmd_init(pmd_t *pmd, unsigned long
+ set_pmd(pmd, __pmd(0));
+ break;
+ }
++
++ if (pmd_val(*pmd))
++ continue;
++
+ entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
+ entry &= __supported_pte_mask;
+ set_pmd(pmd, __pmd(entry));
+@@ -272,45 +276,41 @@ phys_pmd_init(pmd_t *pmd, unsigned long
+ static void __meminit
+ phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end)
+ {
+- pmd_t *pmd = pmd_offset(pud, (unsigned long)__va(address));
+-
+- if (pmd_none(*pmd)) {
+- spin_lock(&init_mm.page_table_lock);
+- phys_pmd_init(pmd, address, end);
+- spin_unlock(&init_mm.page_table_lock);
+- __flush_tlb_all();
+- }
++ pmd_t *pmd = pmd_offset(pud,0);
++ spin_lock(&init_mm.page_table_lock);
++ phys_pmd_init(pmd, address, end);
++ spin_unlock(&init_mm.page_table_lock);
++ __flush_tlb_all();
+ }
+
+-static void __meminit phys_pud_init(pud_t *pud, unsigned long address, unsigned long end)
++static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
+ {
+- long i = pud_index(address);
++ int i = pud_index(addr);
+
+- pud = pud + i;
+
+- if (after_bootmem && pud_val(*pud)) {
+- phys_pmd_update(pud, address, end);
+- return;
+- }
+-
+- for (; i < PTRS_PER_PUD; pud++, i++) {
++ for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE ) {
+ int map;
+- unsigned long paddr, pmd_phys;
++ unsigned long pmd_phys;
++ pud_t *pud = pud_page + pud_index(addr);
+ pmd_t *pmd;
+
+- paddr = (address & PGDIR_MASK) + i*PUD_SIZE;
+- if (paddr >= end)
++ if (addr >= end)
+ break;
+
+- if (!after_bootmem && !e820_any_mapped(paddr, paddr+PUD_SIZE, 0)) {
++ if (!after_bootmem && !e820_any_mapped(addr,addr+PUD_SIZE,0)) {
+ set_pud(pud, __pud(0));
+ continue;
+ }
+
++ if (pud_val(*pud)) {
++ phys_pmd_update(pud, addr, end);
++ continue;
++ }
++
+ pmd = alloc_low_page(&map, &pmd_phys);
+ spin_lock(&init_mm.page_table_lock);
+ set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
+- phys_pmd_init(pmd, paddr, end);
++ phys_pmd_init(pmd, addr, end);
+ spin_unlock(&init_mm.page_table_lock);
+ unmap_low_page(map);
+ }
+@@ -403,69 +403,18 @@ void __cpuinit zap_low_mappings(int cpu)
+ __flush_tlb_all();
+ }
+
+-/* Compute zone sizes for the DMA and DMA32 zones in a node. */
+-__init void
+-size_zones(unsigned long *z, unsigned long *h,
+- unsigned long start_pfn, unsigned long end_pfn)
+-{
+- int i;
+- unsigned long w;
+-
+- for (i = 0; i < MAX_NR_ZONES; i++)
+- z[i] = 0;
+-
+- if (start_pfn < MAX_DMA_PFN)
+- z[ZONE_DMA] = MAX_DMA_PFN - start_pfn;
+- if (start_pfn < MAX_DMA32_PFN) {
+- unsigned long dma32_pfn = MAX_DMA32_PFN;
+- if (dma32_pfn > end_pfn)
+- dma32_pfn = end_pfn;
+- z[ZONE_DMA32] = dma32_pfn - start_pfn;
+- }
+- z[ZONE_NORMAL] = end_pfn - start_pfn;
+-
+- /* Remove lower zones from higher ones. */
+- w = 0;
+- for (i = 0; i < MAX_NR_ZONES; i++) {
+- if (z[i])
+- z[i] -= w;
+- w += z[i];
+- }
+-
+- /* Compute holes */
+- w = start_pfn;
+- for (i = 0; i < MAX_NR_ZONES; i++) {
+- unsigned long s = w;
+- w += z[i];
+- h[i] = e820_hole_size(s, w);
+- }
+-
+- /* Add the space pace needed for mem_map to the holes too. */
+- for (i = 0; i < MAX_NR_ZONES; i++)
+- h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE;
+-
+- /* The 16MB DMA zone has the kernel and other misc mappings.
+- Account them too */
+- if (h[ZONE_DMA]) {
+- h[ZONE_DMA] += dma_reserve;
+- if (h[ZONE_DMA] >= z[ZONE_DMA]) {
+- printk(KERN_WARNING
+- "Kernel too large and filling up ZONE_DMA?\n");
+- h[ZONE_DMA] = z[ZONE_DMA];
+- }
+- }
+-}
+-
+ #ifndef CONFIG_NUMA
+ void __init paging_init(void)
+ {
+- unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES];
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
++ max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
++ max_zone_pfns[ZONE_NORMAL] = end_pfn;
+
+ memory_present(0, 0, end_pfn);
+ sparse_init();
+- size_zones(zones, holes, 0, end_pfn);
+- free_area_init_node(0, NODE_DATA(0), zones,
+- __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
++ free_area_init_nodes(max_zone_pfns);
+ }
+ #endif
+
+@@ -517,36 +466,23 @@ void online_page(struct page *page)
+
+ #ifdef CONFIG_MEMORY_HOTPLUG
+ /*
+- * XXX: memory_add_physaddr_to_nid() is to find node id from physical address
+- * via probe interface of sysfs. If acpi notifies hot-add event, then it
+- * can tell node id by searching dsdt. But, probe interface doesn't have
+- * node id. So, return 0 as node id at this time.
+- */
+-#ifdef CONFIG_NUMA
+-int memory_add_physaddr_to_nid(u64 start)
+-{
+- return 0;
+-}
+-#endif
+-
+-/*
+ * Memory is added always to NORMAL zone. This means you will never get
+ * additional DMA/DMA32 memory.
+ */
+ int arch_add_memory(int nid, u64 start, u64 size)
+ {
+ struct pglist_data *pgdat = NODE_DATA(nid);
+- struct zone *zone = pgdat->node_zones + MAX_NR_ZONES-2;
++ struct zone *zone = pgdat->node_zones + ZONE_NORMAL;
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ int ret;
+
++ init_memory_mapping(start, (start + size -1));
++
+ ret = __add_pages(zone, start_pfn, nr_pages);
+ if (ret)
+ goto error;
+
+- init_memory_mapping(start, (start + size -1));
+-
+ return ret;
+ error:
+ printk("%s: Problem encountered in __add_pages!\n", __func__);
+@@ -560,7 +496,24 @@ int remove_memory(u64 start, u64 size)
+ }
+ EXPORT_SYMBOL_GPL(remove_memory);
+
+-#else /* CONFIG_MEMORY_HOTPLUG */
++#ifndef CONFIG_ACPI_NUMA
++int memory_add_physaddr_to_nid(u64 start)
++{
++ return 0;
++}
++EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
++#endif
++
++#ifndef CONFIG_ACPI_NUMA
++int memory_add_physaddr_to_nid(u64 start)
++{
++ return 0;
++}
++#endif
++
++#endif /* CONFIG_MEMORY_HOTPLUG */
++
++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
+ /*
+ * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
+ * just online the pages.
+@@ -586,7 +539,7 @@ int __add_pages(struct zone *z, unsigned
+ }
+ return err;
+ }
+-#endif /* CONFIG_MEMORY_HOTPLUG */
++#endif
+
+ static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
+ kcore_vsyscall;
+@@ -597,12 +550,6 @@ void __init mem_init(void)
+
+ pci_iommu_alloc();
+
+- /* How many end-of-memory variables you have, grandma! */
+- max_low_pfn = end_pfn;
+- max_pfn = end_pfn;
+- num_physpages = end_pfn;
+- high_memory = (void *) __va(end_pfn * PAGE_SIZE);
+-
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
+
+@@ -614,7 +561,8 @@ void __init mem_init(void)
+ #else
+ totalram_pages = free_all_bootmem();
+ #endif
+- reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
++ reservedpages = end_pfn - totalram_pages -
++ absent_pages_in_range(0, end_pfn);
+
+ after_bootmem = 1;
+
+@@ -714,8 +662,10 @@ void __init reserve_bootmem_generic(unsi
+ #else
+ reserve_bootmem(phys, len);
+ #endif
+- if (phys+len <= MAX_DMA_PFN*PAGE_SIZE)
++ if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
+ dma_reserve += len / PAGE_SIZE;
++ set_dma_reserve(dma_reserve);
++ }
+ }
+
+ int kern_addr_valid(unsigned long addr)
+diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
+index 45d7d82..c6e5e8d 100644
+--- a/arch/x86_64/mm/ioremap.c
++++ b/arch/x86_64/mm/ioremap.c
+@@ -12,117 +12,16 @@
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/module.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <asm/pgalloc.h>
+ #include <asm/fixmap.h>
+-#include <asm/cacheflush.h>
+ #include <asm/tlbflush.h>
++#include <asm/cacheflush.h>
+ #include <asm/proto.h>
+
+ #define ISA_START_ADDRESS 0xa0000
+ #define ISA_END_ADDRESS 0x100000
+
+-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+- unsigned long pfn;
+-
+- address &= ~PMD_MASK;
+- end = address + size;
+- if (end > PMD_SIZE)
+- end = PMD_SIZE;
+- if (address >= end)
+- BUG();
+- pfn = phys_addr >> PAGE_SHIFT;
+- do {
+- if (!pte_none(*pte)) {
+- printk("remap_area_pte: page already exists\n");
+- BUG();
+- }
+- set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW |
+- _PAGE_GLOBAL | _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+- address += PAGE_SIZE;
+- pfn++;
+- pte++;
+- } while (address && (address < end));
+-}
+-
+-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+-
+- address &= ~PUD_MASK;
+- end = address + size;
+- if (end > PUD_SIZE)
+- end = PUD_SIZE;
+- phys_addr -= address;
+- if (address >= end)
+- BUG();
+- do {
+- pte_t * pte = pte_alloc_kernel(pmd, address);
+- if (!pte)
+- return -ENOMEM;
+- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+- address = (address + PMD_SIZE) & PMD_MASK;
+- pmd++;
+- } while (address && (address < end));
+- return 0;
+-}
+-
+-static inline int remap_area_pud(pud_t * pud, unsigned long address, unsigned long size,
+- unsigned long phys_addr, unsigned long flags)
+-{
+- unsigned long end;
+-
+- address &= ~PGDIR_MASK;
+- end = address + size;
+- if (end > PGDIR_SIZE)
+- end = PGDIR_SIZE;
+- phys_addr -= address;
+- if (address >= end)
+- BUG();
+- do {
+- pmd_t * pmd = pmd_alloc(&init_mm, pud, address);
+- if (!pmd)
+- return -ENOMEM;
+- remap_area_pmd(pmd, address, end - address, address + phys_addr, flags);
+- address = (address + PUD_SIZE) & PUD_MASK;
+- pud++;
+- } while (address && (address < end));
+- return 0;
+-}
+-
+-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+- unsigned long size, unsigned long flags)
+-{
+- int error;
+- pgd_t *pgd;
+- unsigned long end = address + size;
+-
+- phys_addr -= address;
+- pgd = pgd_offset_k(address);
+- flush_cache_all();
+- if (address >= end)
+- BUG();
+- do {
+- pud_t *pud;
+- pud = pud_alloc(&init_mm, pgd, address);
+- error = -ENOMEM;
+- if (!pud)
+- break;
+- if (remap_area_pud(pud, address, end - address,
+- phys_addr + address, flags))
+- break;
+- error = 0;
+- address = (address + PGDIR_SIZE) & PGDIR_MASK;
+- pgd++;
+- } while (address && (address < end));
+- flush_tlb_all();
+- return error;
+-}
+-
+ /*
+ * Fix up the linear direct mapping of the kernel to avoid cache attribute
+ * conflicts.
+@@ -165,6 +64,7 @@ void __iomem * __ioremap(unsigned long p
+ void * addr;
+ struct vm_struct * area;
+ unsigned long offset, last_addr;
++ pgprot_t pgprot;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+@@ -194,6 +94,8 @@ void __iomem * __ioremap(unsigned long p
+ }
+ #endif
+
++ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_GLOBAL
++ | _PAGE_DIRTY | _PAGE_ACCESSED | flags);
+ /*
+ * Mappings have to be page-aligned
+ */
+@@ -209,7 +111,8 @@ void __iomem * __ioremap(unsigned long p
+ return NULL;
+ area->phys_addr = phys_addr;
+ addr = area->addr;
+- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
++ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
++ phys_addr, pgprot)) {
+ remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
+ return NULL;
+ }
+diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
+index 7c45c2d..b5b8dba 100644
+--- a/arch/x86_64/mm/k8topology.c
++++ b/arch/x86_64/mm/k8topology.c
+@@ -54,6 +54,9 @@ int __init k8_scan_nodes(unsigned long s
+
+ nodes_clear(nodes_parsed);
+
++ if (!early_pci_allowed())
++ return -1;
++
+ nb = find_northbridge();
+ if (nb < 0)
+ return nb;
+@@ -146,6 +149,9 @@ int __init k8_scan_nodes(unsigned long s
+
+ nodes[nodeid].start = base;
+ nodes[nodeid].end = limit;
++ e820_register_active_regions(nodeid,
++ nodes[nodeid].start >> PAGE_SHIFT,
++ nodes[nodeid].end >> PAGE_SHIFT);
+
+ prevbase = base;
+
+diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
+index b2fac14..2ee2e00 100644
+--- a/arch/x86_64/mm/numa.c
++++ b/arch/x86_64/mm/numa.c
+@@ -161,7 +161,7 @@ void __init setup_node_bootmem(int nodei
+ bootmap_start >> PAGE_SHIFT,
+ start_pfn, end_pfn);
+
+- e820_bootmem_free(NODE_DATA(nodeid), start, end);
++ free_bootmem_with_active_regions(nodeid, end);
+
+ reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
+ reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages<<PAGE_SHIFT);
+@@ -175,13 +175,11 @@ void __init setup_node_bootmem(int nodei
+ void __init setup_node_zones(int nodeid)
+ {
+ unsigned long start_pfn, end_pfn, memmapsize, limit;
+- unsigned long zones[MAX_NR_ZONES];
+- unsigned long holes[MAX_NR_ZONES];
+
+ start_pfn = node_start_pfn(nodeid);
+ end_pfn = node_end_pfn(nodeid);
+
+- Dprintk(KERN_INFO "Setting up node %d %lx-%lx\n",
++ Dprintk(KERN_INFO "Setting up memmap for node %d %lx-%lx\n",
+ nodeid, start_pfn, end_pfn);
+
+ /* Try to allocate mem_map at end to not fill up precious <4GB
+@@ -195,10 +193,6 @@ void __init setup_node_zones(int nodeid)
+ round_down(limit - memmapsize, PAGE_SIZE),
+ limit);
+ #endif
+-
+- size_zones(zones, holes, start_pfn, end_pfn);
+- free_area_init_node(nodeid, NODE_DATA(nodeid), zones,
+- start_pfn, holes);
+ }
+
+ void __init numa_init_array(void)
+@@ -225,7 +219,7 @@ void __init numa_init_array(void)
+ int numa_fake __initdata = 0;
+
+ /* Numa emulation */
+-static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
++static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+ {
+ int i;
+ struct bootnode nodes[MAX_NUMNODES];
+@@ -259,8 +253,11 @@ static int numa_emulation(unsigned long
+ printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n");
+ return -1;
+ }
+- for_each_online_node(i)
++ for_each_online_node(i) {
++ e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
++ nodes[i].end >> PAGE_SHIFT);
+ setup_node_bootmem(i, nodes[i].start, nodes[i].end);
++ }
+ numa_init_array();
+ return 0;
+ }
+@@ -299,6 +296,7 @@ void __init numa_initmem_init(unsigned l
+ for (i = 0; i < NR_CPUS; i++)
+ numa_set_node(i, 0);
+ node_to_cpumask[0] = cpumask_of_cpu(0);
++ e820_register_active_regions(0, start_pfn, end_pfn);
+ setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
+ }
+
+@@ -340,17 +338,25 @@ static void __init arch_sparse_init(void
+ void __init paging_init(void)
+ {
+ int i;
++ unsigned long max_zone_pfns[MAX_NR_ZONES];
++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
++ max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
++ max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
++ max_zone_pfns[ZONE_NORMAL] = end_pfn;
+
+ arch_sparse_init();
+
+ for_each_online_node(i) {
+ setup_node_zones(i);
+ }
++
++ free_area_init_nodes(max_zone_pfns);
+ }
+
+-/* [numa=off] */
+-__init int numa_setup(char *opt)
++static __init int numa_setup(char *opt)
+ {
++ if (!opt)
++ return -EINVAL;
+ if (!strncmp(opt,"off",3))
+ numa_off = 1;
+ #ifdef CONFIG_NUMA_EMU
+@@ -366,9 +372,11 @@ __init int numa_setup(char *opt)
+ if (!strncmp(opt,"hotadd=", 7))
+ hotadd_percent = simple_strtoul(opt+7, NULL, 10);
+ #endif
+- return 1;
++ return 0;
+ }
+
++early_param("numa", numa_setup);
++
+ /*
+ * Setup early cpu_to_node.
+ *
+diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c
+index 2685b1f..3e231d7 100644
+--- a/arch/x86_64/mm/pageattr.c
++++ b/arch/x86_64/mm/pageattr.c
+@@ -108,8 +108,8 @@ static void revert_page(unsigned long ad
+ BUG_ON(pud_none(*pud));
+ pmd = pmd_offset(pud, address);
+ BUG_ON(pmd_val(*pmd) & _PAGE_PSE);
+- pgprot_val(ref_prot) |= _PAGE_PSE;
+ large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot);
++ large_pte = pte_mkhuge(large_pte);
+ set_pte((pte_t *)pmd, large_pte);
+ }
+
+@@ -119,32 +119,28 @@ __change_page_attr(unsigned long address
+ {
+ pte_t *kpte;
+ struct page *kpte_page;
+- unsigned kpte_flags;
+ pgprot_t ref_prot2;
+ kpte = lookup_address(address);
+ if (!kpte) return 0;
+ kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+- kpte_flags = pte_val(*kpte);
+ if (pgprot_val(prot) != pgprot_val(ref_prot)) {
+- if ((kpte_flags & _PAGE_PSE) == 0) {
++ if (!pte_huge(*kpte)) {
+ set_pte(kpte, pfn_pte(pfn, prot));
+ } else {
+ /*
+ * split_large_page will take the reference for this
+ * change_page_attr on the split page.
+ */
+-
+ struct page *split;
+- ref_prot2 = __pgprot(pgprot_val(pte_pgprot(*lookup_address(address))) & ~(1<<_PAGE_BIT_PSE));
+-
++ ref_prot2 = pte_pgprot(pte_clrhuge(*kpte));
+ split = split_large_page(address, prot, ref_prot2);
+ if (!split)
+ return -ENOMEM;
+- set_pte(kpte,mk_pte(split, ref_prot2));
++ set_pte(kpte, mk_pte(split, ref_prot2));
+ kpte_page = split;
+- }
++ }
+ page_private(kpte_page)++;
+- } else if ((kpte_flags & _PAGE_PSE) == 0) {
++ } else if (!pte_huge(*kpte)) {
+ set_pte(kpte, pfn_pte(pfn, ref_prot));
+ BUG_ON(page_private(kpte_page) == 0);
+ page_private(kpte_page)--;
+@@ -190,10 +186,12 @@ int change_page_attr_addr(unsigned long
+ * lowmem */
+ if (__pa(address) < KERNEL_TEXT_SIZE) {
+ unsigned long addr2;
+- pgprot_t prot2 = prot;
++ pgprot_t prot2;
+ addr2 = __START_KERNEL_map + __pa(address);
+- pgprot_val(prot2) &= ~_PAGE_NX;
+- err = __change_page_attr(addr2, pfn, prot2, PAGE_KERNEL_EXEC);
++ /* Make sure the kernel mappings stay executable */
++ prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot)));
++ err = __change_page_attr(addr2, pfn, prot2,
++ PAGE_KERNEL_EXEC);
+ }
+ }
+ up_write(&init_mm.mmap_sem);
+diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
+index 502fce6..1087e15 100644
+--- a/arch/x86_64/mm/srat.c
++++ b/arch/x86_64/mm/srat.c
+@@ -21,22 +21,15 @@
+ #include <asm/numa.h>
+ #include <asm/e820.h>
+
+-#if (defined(CONFIG_ACPI_HOTPLUG_MEMORY) || \
+- defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE)) \
+- && !defined(CONFIG_MEMORY_HOTPLUG)
+-#define RESERVE_HOTADD 1
+-#endif
++int acpi_numa __initdata;
+
+ static struct acpi_table_slit *acpi_slit;
+
+ static nodemask_t nodes_parsed __initdata;
+ static struct bootnode nodes[MAX_NUMNODES] __initdata;
+-static struct bootnode nodes_add[MAX_NUMNODES] __initdata;
++static struct bootnode nodes_add[MAX_NUMNODES];
+ static int found_add_area __initdata;
+ int hotadd_percent __initdata = 0;
+-#ifndef RESERVE_HOTADD
+-#define hotadd_percent 0 /* Ignore all settings */
+-#endif
+
+ /* Too small nodes confuse the VM badly. Usually they result
+ from BIOS bugs. */
+@@ -91,6 +84,7 @@ static __init void bad_srat(void)
+ apicid_to_node[i] = NUMA_NO_NODE;
+ for (i = 0; i < MAX_NUMNODES; i++)
+ nodes_add[i].start = nodes[i].end = 0;
++ remove_all_active_ranges();
+ }
+
+ static __init inline int srat_disabled(void)
+@@ -157,7 +151,7 @@ acpi_numa_processor_affinity_init(struct
+ pxm, pa->apic_id, node);
+ }
+
+-#ifdef RESERVE_HOTADD
++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
+ /*
+ * Protect against too large hotadd areas that would fill up memory.
+ */
+@@ -173,7 +167,7 @@ static int hotadd_enough_memory(struct b
+
+ if (mem < 0)
+ return 0;
+- allowed = (end_pfn - e820_hole_size(0, end_pfn)) * PAGE_SIZE;
++ allowed = (end_pfn - absent_pages_in_range(0, end_pfn)) * PAGE_SIZE;
+ allowed = (allowed / 100) * hotadd_percent;
+ if (allocated + mem > allowed) {
+ unsigned long range;
+@@ -200,15 +194,37 @@ static int hotadd_enough_memory(struct b
+ return 1;
+ }
+
++static int update_end_of_memory(unsigned long end)
++{
++ found_add_area = 1;
++ if ((end >> PAGE_SHIFT) > end_pfn)
++ end_pfn = end >> PAGE_SHIFT;
++ return 1;
++}
++
++static inline int save_add_info(void)
++{
++ return hotadd_percent > 0;
++}
++#else
++int update_end_of_memory(unsigned long end) {return -1;}
++static int hotadd_enough_memory(struct bootnode *nd) {return 1;}
++#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
++static inline int save_add_info(void) {return 1;}
++#else
++static inline int save_add_info(void) {return 0;}
++#endif
++#endif
+ /*
+- * It is fine to add this area to the nodes data it will be used later
++ * Update nodes_add and decide if to include add are in the zone.
++ * Both SPARSE and RESERVE need nodes_add infomation.
+ * This code supports one contigious hot add area per node.
+ */
+ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
+ {
+ unsigned long s_pfn = start >> PAGE_SHIFT;
+ unsigned long e_pfn = end >> PAGE_SHIFT;
+- int changed = 0;
++ int ret = 0, changed = 0;
+ struct bootnode *nd = &nodes_add[node];
+
+ /* I had some trouble with strange memory hotadd regions breaking
+@@ -223,8 +239,10 @@ static int reserve_hotadd(int node, unsi
+ }
+
+ /* This check might be a bit too strict, but I'm keeping it for now. */
+- if (e820_hole_size(s_pfn, e_pfn) != e_pfn - s_pfn) {
+- printk(KERN_ERR "SRAT: Hotplug area has existing memory\n");
++ if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
++ printk(KERN_ERR
++ "SRAT: Hotplug area %lu -> %lu has existing memory\n",
++ s_pfn, e_pfn);
+ return -1;
+ }
+
+@@ -235,7 +253,6 @@ static int reserve_hotadd(int node, unsi
+
+ /* Looks good */
+
+- found_add_area = 1;
+ if (nd->start == nd->end) {
+ nd->start = start;
+ nd->end = end;
+@@ -253,14 +270,12 @@ static int reserve_hotadd(int node, unsi
+ printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
+ }
+
+- if ((nd->end >> PAGE_SHIFT) > end_pfn)
+- end_pfn = nd->end >> PAGE_SHIFT;
++ ret = update_end_of_memory(nd->end);
+
+ if (changed)
+ printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", nd->start, nd->end);
+- return 0;
++ return ret;
+ }
+-#endif
+
+ /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
+ void __init
+@@ -279,7 +294,7 @@ acpi_numa_memory_affinity_init(struct ac
+ }
+ if (ma->flags.enabled == 0)
+ return;
+- if (ma->flags.hot_pluggable && hotadd_percent == 0)
++ if (ma->flags.hot_pluggable && !save_add_info())
+ return;
+ start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
+ end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
+@@ -317,16 +332,18 @@ acpi_numa_memory_affinity_init(struct ac
+
+ printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
+ nd->start, nd->end);
++ e820_register_active_regions(node, nd->start >> PAGE_SHIFT,
++ nd->end >> PAGE_SHIFT);
++ push_node_boundaries(node, nd->start >> PAGE_SHIFT,
++ nd->end >> PAGE_SHIFT);
+
+-#ifdef RESERVE_HOTADD
+- if (ma->flags.hot_pluggable && reserve_hotadd(node, start, end) < 0) {
++ if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) {
+ /* Ignore hotadd region. Undo damage */
+ printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
+ *nd = oldnode;
+ if ((nd->start | nd->end) == 0)
+ node_clear(node, nodes_parsed);
+ }
+-#endif
+ }
+
+ /* Sanity check to catch more bad SRATs (they are amazingly common).
+@@ -341,13 +358,12 @@ static int nodes_cover_memory(void)
+ unsigned long s = nodes[i].start >> PAGE_SHIFT;
+ unsigned long e = nodes[i].end >> PAGE_SHIFT;
+ pxmram += e - s;
+- pxmram -= e820_hole_size(s, e);
+- pxmram -= nodes_add[i].end - nodes_add[i].start;
++ pxmram -= absent_pages_in_range(s, e);
+ if ((long)pxmram < 0)
+ pxmram = 0;
+ }
+
+- e820ram = end_pfn - e820_hole_size(0, end_pfn);
++ e820ram = end_pfn - absent_pages_in_range(0, end_pfn);
+ /* We seem to lose 3 pages somewhere. Allow a bit of slack. */
+ if ((long)(e820ram - pxmram) >= 1*1024*1024) {
+ printk(KERN_ERR
+@@ -450,3 +466,16 @@ int __node_distance(int a, int b)
+ }
+
+ EXPORT_SYMBOL(__node_distance);
++
++int memory_add_physaddr_to_nid(u64 start)
++{
++ int i, ret = 0;
++
++ for_each_node(i)
++ if (nodes_add[i].start <= start && nodes_add[i].end > start)
++ ret = i;
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
++
+diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
+index a3f6ad5..149aba0 100644
+--- a/arch/x86_64/pci/Makefile
++++ b/arch/x86_64/pci/Makefile
+@@ -3,13 +3,13 @@
+ #
+ # Reuse the i386 PCI subsystem
+ #
+-CFLAGS += -Iarch/i386/pci
++EXTRA_CFLAGS += -Iarch/i386/pci
+
+ obj-y := i386.o
+ obj-$(CONFIG_PCI_DIRECT)+= direct.o
+ obj-y += fixup.o init.o
+ obj-$(CONFIG_ACPI) += acpi.o
+-obj-y += legacy.o irq.o common.o
++obj-y += legacy.o irq.o common.o early.o
+ # mmconfig has a 64bit special
+ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o
+
+@@ -23,3 +23,4 @@ common-y += ../../i386/pci/common.o
+ fixup-y += ../../i386/pci/fixup.o
+ i386-y += ../../i386/pci/i386.o
+ init-y += ../../i386/pci/init.o
++early-y += ../../i386/pci/early.o
+diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
+index 3c55c76..e61093b 100644
+--- a/arch/x86_64/pci/mmconfig.c
++++ b/arch/x86_64/pci/mmconfig.c
+@@ -156,15 +156,45 @@ static __init void unreachable_devices(v
+ addr = pci_dev_base(0, k, PCI_DEVFN(i, 0));
+ if (addr == NULL|| readl(addr) != val1) {
+ set_bit(i + 32*k, fallback_slots);
+- printk(KERN_NOTICE
+- "PCI: No mmconfig possible on device %x:%x\n",
+- k, i);
++ printk(KERN_NOTICE "PCI: No mmconfig possible"
++ " on device %02x:%02x\n", k, i);
+ }
+ }
+ }
+ }
+
+-void __init pci_mmcfg_init(void)
++static __init void pci_mmcfg_insert_resources(void)
++{
++#define PCI_MMCFG_RESOURCE_NAME_LEN 19
++ int i;
++ struct resource *res;
++ char *names;
++ unsigned num_buses;
++
++ res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
++ pci_mmcfg_config_num, GFP_KERNEL);
++
++ if (!res) {
++ printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
++ return;
++ }
++
++ names = (void *)&res[pci_mmcfg_config_num];
++ for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
++ num_buses = pci_mmcfg_config[i].end_bus_number -
++ pci_mmcfg_config[i].start_bus_number + 1;
++ res->name = names;
++ snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
++ pci_mmcfg_config[i].pci_segment_group_number);
++ res->start = pci_mmcfg_config[i].base_address;
++ res->end = res->start + (num_buses << 20) - 1;
++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++ insert_resource(&iomem_resource, res);
++ names += PCI_MMCFG_RESOURCE_NAME_LEN;
++ }
++}
++
++void __init pci_mmcfg_init(int type)
+ {
+ int i;
+
+@@ -177,7 +207,9 @@ void __init pci_mmcfg_init(void)
+ (pci_mmcfg_config[0].base_address == 0))
+ return;
+
+- if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
++ /* Only do this check when type 1 works. If it doesn't work
++ assume we run on a Mac and always use MCFG */
++ if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
+ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+ E820_RESERVED)) {
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
+@@ -186,10 +218,9 @@ void __init pci_mmcfg_init(void)
+ return;
+ }
+
+- /* RED-PEN i386 doesn't do _nocache right now */
+ 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");
++ printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
+ return;
+ }
+ for (i = 0; i < pci_mmcfg_config_num; ++i) {
+@@ -197,7 +228,8 @@ void __init pci_mmcfg_init(void)
+ pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
+ MMCONFIG_APER_MAX);
+ if (!pci_mmcfg_virt[i].virt) {
+- printk("PCI: Cannot map mmconfig aperture for segment %d\n",
++ printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
++ "segment %d\n",
+ pci_mmcfg_config[i].pci_segment_group_number);
+ return;
+ }
+@@ -205,6 +237,7 @@ void __init pci_mmcfg_init(void)
+ }
+
+ unreachable_devices();
++ pci_mmcfg_insert_resources();
+
+ 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
+index 848f173..c1e69a1 100644
+--- a/arch/xtensa/Kconfig
++++ b/arch/xtensa/Kconfig
+@@ -206,7 +206,7 @@ source "drivers/pci/hotplug/Kconfig"
+
+ endmenu
+
+-menu "Exectuable file formats"
++menu "Executable file formats"
+
+ # only elf supported
+ config KCORE_ELF
+@@ -241,7 +241,7 @@ menu "Xtensa initrd options"
+ bool "Embed root filesystem ramdisk into the kernel"
+
+ config EMBEDDED_RAMDISK_IMAGE
+- string "Filename of gziped ramdisk image"
++ string "Filename of gzipped ramdisk image"
+ depends on EMBEDDED_RAMDISK
+ default "ramdisk.gz"
+ help
+diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
+index d1683cf..2ea1755 100644
+--- a/arch/xtensa/kernel/module.c
++++ b/arch/xtensa/kernel/module.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/kernel/platform.c
++ * arch/xtensa/kernel/module.c
+ *
+ * Module support.
+ *
+diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
+index 1ff8226..6648fa9 100644
+--- a/arch/xtensa/kernel/pci-dma.c
++++ b/arch/xtensa/kernel/pci-dma.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/pci-dma.c
++ * arch/xtensa/kernel/pci-dma.c
+ *
+ * DMA coherent memory allocation.
+ *
+diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
+index 8709f82..45571cc 100644
+--- a/arch/xtensa/kernel/pci.c
++++ b/arch/xtensa/kernel/pci.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/pcibios.c
++ * arch/xtensa/kernel/pci.c
+ *
+ * PCI bios-type initialisation for PCI machines
+ *
+diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
+index 82684d0..c99ab72 100644
+--- a/arch/xtensa/kernel/setup.c
++++ b/arch/xtensa/kernel/setup.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/setup.c
++ * arch/xtensa/kernel/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
+diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
+index 4688ba2..f49cb23 100644
+--- a/arch/xtensa/kernel/syscalls.c
++++ b/arch/xtensa/kernel/syscalls.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/kernel/syscall.c
++ * arch/xtensa/kernel/syscalls.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
+@@ -128,7 +128,7 @@ out:
+
+ int sys_uname(struct old_utsname * name)
+ {
+- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
++ if (name && !copy_to_user(name, utsname(), sizeof (*name)))
+ return 0;
+ return -EFAULT;
+ }
+@@ -266,3 +266,23 @@ void system_call (struct pt_regs *regs)
+ regs->areg[2] = res;
+ do_syscall_trace();
+ }
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++ 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_execve), "a" (filename), "a" (argv), "a" (envp)
++ : "a2", "a3", "a4", "a5");
++ return __res;
++}
+diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
+index 412ab32..37347e3 100644
+--- a/arch/xtensa/kernel/time.c
++++ b/arch/xtensa/kernel/time.c
+@@ -26,8 +26,6 @@
+ #include <asm/platform.h>
+
+
+-extern volatile unsigned long wall_jiffies;
+-
+ DEFINE_SPINLOCK(rtc_lock);
+ EXPORT_SYMBOL(rtc_lock);
+
+@@ -110,7 +108,6 @@ int do_settimeofday(struct timespec *tv)
+ */
+ 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);
+@@ -129,7 +126,7 @@ EXPORT_SYMBOL(do_settimeofday);
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+- unsigned long sec, usec, delta, lost, seq;
++ unsigned long sec, usec, delta, seq;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+@@ -137,12 +134,9 @@ void do_gettimeofday(struct timeval *tv)
+ 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;
++ usec += (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+ for (; usec >= 1000000; sec++, usec -= 1000000)
+ ;
+
+@@ -175,12 +169,11 @@ again:
+
+ last_ccount_stamp = next;
+ next += CCOUNT_PER_JIFFY;
+- do_timer (regs); /* Linux handler in kernel/timer.c */
++ do_timer (1); /* Linux handler in kernel/timer.c */
+
+ if (ntp_synced() &&
+ xtime.tv_sec - last_rtc_update >= 659 &&
+- abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
+- jiffies - wall_jiffies == 1) {
++ abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ) {
+
+ if (platform_set_rtc_time(xtime.tv_sec+1) == 0)
+ last_rtc_update = xtime.tv_sec+1;
+diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
+index ab6cdbd..cfe75f5 100644
+--- a/arch/xtensa/kernel/vmlinux.lds.S
++++ b/arch/xtensa/kernel/vmlinux.lds.S
+@@ -184,13 +184,7 @@ SECTIONS
+
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+
+diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c
+index 90c790f..a71733a 100644
+--- a/arch/xtensa/lib/pci-auto.c
++++ b/arch/xtensa/lib/pci-auto.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/kernel/pci-auto.c
++ * arch/xtensa/lib/pci-auto.c
+ *
+ * PCI autoconfiguration library
+ *
+diff --git a/arch/xtensa/lib/usercopy.S b/arch/xtensa/lib/usercopy.S
+index 265db26..4641ef5 100644
+--- a/arch/xtensa/lib/usercopy.S
++++ b/arch/xtensa/lib/usercopy.S
+@@ -5,10 +5,10 @@
+ *
+ * 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
++ * of 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
++ * could lose 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.
+ *
+diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
+index a945a33..dd0dbec 100644
+--- a/arch/xtensa/mm/fault.c
++++ b/arch/xtensa/mm/fault.c
+@@ -144,7 +144,7 @@ bad_area:
+ */
+ out_of_memory:
+ up_read(&mm->mmap_sem);
+- if (current->pid == 1) {
++ if (is_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
+index 7d28914..6979927 100644
+--- a/arch/xtensa/mm/pgtable.c
++++ b/arch/xtensa/mm/pgtable.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/mm/fault.c
++ * arch/xtensa/mm/pgtable.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
+diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
+index d3bd3bf..0fefb86 100644
+--- a/arch/xtensa/mm/tlb.c
++++ b/arch/xtensa/mm/tlb.c
+@@ -1,5 +1,5 @@
+ /*
+- * arch/xtensa/mm/mmu.c
++ * arch/xtensa/mm/tlb.c
+ *
+ * Logic that manipulates the Xtensa MMU. Derived from MIPS.
+ *
+diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
+index 22d3c57..5c947ca 100644
+--- a/arch/xtensa/platform-iss/console.c
++++ b/arch/xtensa/platform-iss/console.c
+@@ -191,7 +191,7 @@ static int rs_read_proc(char *page, char
+ }
+
+
+-static struct tty_operations serial_ops = {
++static const struct tty_operations serial_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
+index d96164e..15d6441 100644
+--- a/arch/xtensa/platform-iss/network.c
++++ b/arch/xtensa/platform-iss/network.c
+@@ -201,7 +201,7 @@ static void dev_ip_addr(void *d, char *b
+ struct net_device *dev = d;
+ struct in_device *ip = dev->ip_ptr;
+ struct in_ifaddr *in;
+- u32 addr;
++ __be32 addr;
+
+ if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
+ printk(KERN_WARNING "Device not assigned an IP address!\n");
+diff --git a/block/Kconfig b/block/Kconfig
+index b6f5f0a..83766a6 100644
+--- a/block/Kconfig
++++ b/block/Kconfig
+@@ -1,6 +1,24 @@
+ #
+ # Block layer core configuration
+ #
++config BLOCK
++ bool "Enable the block layer" if EMBEDDED
++ default y
++ help
++ This permits the block layer to be removed from the kernel if it's not
++ needed (on some embedded devices for example). If this option is
++ disabled, then blockdev files will become unusable and some
++ filesystems (such as ext3) will become unavailable.
++
++ This option will also disable SCSI character devices and USB storage
++ since they make use of various block layer definitions and
++ facilities.
++
++ Say Y here unless you know you really don't want to mount disks and
++ suchlike.
++
++if BLOCK
++
+ #XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64
+ #for instance.
+ config LBD
+@@ -33,4 +51,6 @@ config LSF
+
+ If unsure, say Y.
+
++endif
++
+ source block/Kconfig.iosched
+diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
+index 48d090e..903f0d3 100644
+--- a/block/Kconfig.iosched
++++ b/block/Kconfig.iosched
+@@ -1,3 +1,4 @@
++if BLOCK
+
+ menu "IO Schedulers"
+
+@@ -67,3 +68,5 @@ config DEFAULT_IOSCHED
+ default "noop" if DEFAULT_NOOP
+
+ endmenu
++
++endif
+diff --git a/block/Makefile b/block/Makefile
+index c05de0e..4b84d0d 100644
+--- a/block/Makefile
++++ b/block/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the kernel block layer
+ #
+
+-obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
++obj-$(CONFIG_BLOCK) := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
+
+ obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
+ obj-$(CONFIG_IOSCHED_AS) += as-iosched.o
+diff --git a/block/as-iosched.c b/block/as-iosched.c
+index 5da56d4..50b95e4 100644
+--- a/block/as-iosched.c
++++ b/block/as-iosched.c
+@@ -1,7 +1,7 @@
+ /*
+ * Anticipatory & deadline i/o scheduler.
+ *
+- * Copyright (C) 2002 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2002 Jens Axboe <axboe at kernel.dk>
+ * Nick Piggin <nickpiggin at yahoo.com.au>
+ *
+ */
+@@ -14,7 +14,6 @@
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/compiler.h>
+-#include <linux/hash.h>
+ #include <linux/rbtree.h>
+ #include <linux/interrupt.h>
+
+@@ -93,9 +92,8 @@ struct as_data {
+ struct rb_root sort_list[2];
+ struct list_head fifo_list[2];
+
+- struct as_rq *next_arq[2]; /* next in sort order */
++ struct request *next_rq[2]; /* next in sort order */
+ sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */
+- struct hlist_head *hash; /* request hash */
+
+ unsigned long exit_prob; /* probability a task will exit while
+ being waited on */
+@@ -115,7 +113,6 @@ struct as_data {
+ int write_batch_count; /* max # of reqs in a write batch */
+ int current_write_count; /* how many requests left this batch */
+ int write_batch_idled; /* has the write batch gone idle? */
+- mempool_t *arq_pool;
+
+ enum anticipation_status antic_status;
+ unsigned long antic_start; /* jiffies: when it started */
+@@ -133,8 +130,6 @@ struct as_data {
+ unsigned long antic_expire;
+ };
+
+-#define list_entry_fifo(ptr) list_entry((ptr), struct as_rq, fifo)
+-
+ /*
+ * per-request data.
+ */
+@@ -150,40 +145,14 @@ enum arq_state {
+ AS_RQ_POSTSCHED, /* when they shouldn't be */
+ };
+
+-struct as_rq {
+- /*
+- * rbtree index, key is the starting offset
+- */
+- struct rb_node rb_node;
+- sector_t rb_key;
+-
+- struct request *request;
+-
+- struct io_context *io_context; /* The submitting task */
+-
+- /*
+- * request hash, key is the ending offset (for back merge lookup)
+- */
+- struct hlist_node hash;
+-
+- /*
+- * expire fifo
+- */
+- struct list_head fifo;
+- unsigned long expires;
++#define RQ_IOC(rq) ((struct io_context *) (rq)->elevator_private)
++#define RQ_STATE(rq) ((enum arq_state)(rq)->elevator_private2)
++#define RQ_SET_STATE(rq, state) ((rq)->elevator_private2 = (void *) state)
+
+- unsigned int is_sync;
+- enum arq_state state;
+-};
+-
+-#define RQ_DATA(rq) ((struct as_rq *) (rq)->elevator_private)
+-
+-static kmem_cache_t *arq_pool;
+-
+-static atomic_t ioc_count = ATOMIC_INIT(0);
++static DEFINE_PER_CPU(unsigned long, ioc_count);
+ static struct completion *ioc_gone;
+
+-static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq);
++static void as_move_to_dispatch(struct as_data *ad, struct request *rq);
+ static void as_antic_stop(struct as_data *ad);
+
+ /*
+@@ -194,7 +163,8 @@ static void as_antic_stop(struct as_data
+ static void free_as_io_context(struct as_io_context *aic)
+ {
+ kfree(aic);
+- if (atomic_dec_and_test(&ioc_count) && ioc_gone)
++ elv_ioc_count_dec(ioc_count);
++ if (ioc_gone && !elv_ioc_count_read(ioc_count))
+ complete(ioc_gone);
+ }
+
+@@ -230,7 +200,7 @@ static struct as_io_context *alloc_as_io
+ ret->seek_total = 0;
+ ret->seek_samples = 0;
+ ret->seek_mean = 0;
+- atomic_inc(&ioc_count);
++ elv_ioc_count_inc(ioc_count);
+ }
+
+ return ret;
+@@ -240,9 +210,9 @@ static struct as_io_context *alloc_as_io
+ * If the current task has no AS IO context then create one and initialise it.
+ * Then take a ref on the task's io context and return it.
+ */
+-static struct io_context *as_get_io_context(void)
++static struct io_context *as_get_io_context(int node)
+ {
+- struct io_context *ioc = get_io_context(GFP_ATOMIC);
++ struct io_context *ioc = get_io_context(GFP_ATOMIC, node);
+ if (ioc && !ioc->aic) {
+ ioc->aic = alloc_as_io_context();
+ if (!ioc->aic) {
+@@ -253,194 +223,43 @@ static struct io_context *as_get_io_cont
+ return ioc;
+ }
+
+-static void as_put_io_context(struct as_rq *arq)
++static void as_put_io_context(struct request *rq)
+ {
+ struct as_io_context *aic;
+
+- if (unlikely(!arq->io_context))
++ if (unlikely(!RQ_IOC(rq)))
+ return;
+
+- aic = arq->io_context->aic;
++ aic = RQ_IOC(rq)->aic;
+
+- if (arq->is_sync == REQ_SYNC && aic) {
++ if (rq_is_sync(rq) && aic) {
+ spin_lock(&aic->lock);
+ set_bit(AS_TASK_IORUNNING, &aic->state);
+ aic->last_end_request = jiffies;
+ spin_unlock(&aic->lock);
+ }
+
+- put_io_context(arq->io_context);
+-}
+-
+-/*
+- * the back merge hash support functions
+- */
+-static const int as_hash_shift = 6;
+-#define AS_HASH_BLOCK(sec) ((sec) >> 3)
+-#define AS_HASH_FN(sec) (hash_long(AS_HASH_BLOCK((sec)), as_hash_shift))
+-#define AS_HASH_ENTRIES (1 << as_hash_shift)
+-#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
+-
+-static inline void __as_del_arq_hash(struct as_rq *arq)
+-{
+- hlist_del_init(&arq->hash);
+-}
+-
+-static inline void as_del_arq_hash(struct as_rq *arq)
+-{
+- if (!hlist_unhashed(&arq->hash))
+- __as_del_arq_hash(arq);
+-}
+-
+-static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq)
+-{
+- struct request *rq = arq->request;
+-
+- BUG_ON(!hlist_unhashed(&arq->hash));
+-
+- hlist_add_head(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]);
+-}
+-
+-/*
+- * move hot entry to front of chain
+- */
+-static inline void as_hot_arq_hash(struct as_data *ad, struct as_rq *arq)
+-{
+- struct request *rq = arq->request;
+- struct hlist_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))];
+-
+- if (hlist_unhashed(&arq->hash)) {
+- WARN_ON(1);
+- return;
+- }
+-
+- if (&arq->hash != head->first) {
+- hlist_del(&arq->hash);
+- hlist_add_head(&arq->hash, head);
+- }
+-}
+-
+-static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset)
+-{
+- struct hlist_head *hash_list = &ad->hash[AS_HASH_FN(offset)];
+- struct hlist_node *entry, *next;
+- struct as_rq *arq;
+-
+- hlist_for_each_entry_safe(arq, entry, next, hash_list, hash) {
+- struct request *__rq = arq->request;
+-
+- BUG_ON(hlist_unhashed(&arq->hash));
+-
+- if (!rq_mergeable(__rq)) {
+- as_del_arq_hash(arq);
+- continue;
+- }
+-
+- if (rq_hash_key(__rq) == offset)
+- return __rq;
+- }
+-
+- return NULL;
++ put_io_context(RQ_IOC(rq));
+ }
+
+ /*
+ * rb tree support functions
+ */
+-#define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node)
+-#define ARQ_RB_ROOT(ad, arq) (&(ad)->sort_list[(arq)->is_sync])
+-#define rq_rb_key(rq) (rq)->sector
+-
+-/*
+- * as_find_first_arq finds the first (lowest sector numbered) request
+- * for the specified data_dir. Used to sweep back to the start of the disk
+- * (1-way elevator) after we process the last (highest sector) request.
+- */
+-static struct as_rq *as_find_first_arq(struct as_data *ad, int data_dir)
+-{
+- struct rb_node *n = ad->sort_list[data_dir].rb_node;
+-
+- if (n == NULL)
+- return NULL;
+-
+- for (;;) {
+- if (n->rb_left == NULL)
+- return rb_entry_arq(n);
+-
+- n = n->rb_left;
+- }
+-}
+-
+-/*
+- * Add the request to the rb tree if it is unique. If there is an alias (an
+- * existing request against the same sector), which can happen when using
+- * direct IO, then return the alias.
+- */
+-static struct as_rq *__as_add_arq_rb(struct as_data *ad, struct as_rq *arq)
+-{
+- struct rb_node **p = &ARQ_RB_ROOT(ad, arq)->rb_node;
+- struct rb_node *parent = NULL;
+- struct as_rq *__arq;
+- struct request *rq = arq->request;
+-
+- arq->rb_key = rq_rb_key(rq);
+-
+- while (*p) {
+- parent = *p;
+- __arq = rb_entry_arq(parent);
+-
+- if (arq->rb_key < __arq->rb_key)
+- p = &(*p)->rb_left;
+- else if (arq->rb_key > __arq->rb_key)
+- p = &(*p)->rb_right;
+- else
+- return __arq;
+- }
+-
+- rb_link_node(&arq->rb_node, parent, p);
+- rb_insert_color(&arq->rb_node, ARQ_RB_ROOT(ad, arq));
+-
+- return NULL;
+-}
++#define RQ_RB_ROOT(ad, rq) (&(ad)->sort_list[rq_is_sync((rq))])
+
+-static void as_add_arq_rb(struct as_data *ad, struct as_rq *arq)
++static void as_add_rq_rb(struct as_data *ad, struct request *rq)
+ {
+- struct as_rq *alias;
++ struct request *alias;
+
+- while ((unlikely(alias = __as_add_arq_rb(ad, arq)))) {
++ while ((unlikely(alias = elv_rb_add(RQ_RB_ROOT(ad, rq), rq)))) {
+ as_move_to_dispatch(ad, alias);
+ as_antic_stop(ad);
+ }
+ }
+
+-static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq)
+-{
+- if (!RB_EMPTY_NODE(&arq->rb_node)) {
+- WARN_ON(1);
+- return;
+- }
+-
+- rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq));
+- RB_CLEAR_NODE(&arq->rb_node);
+-}
+-
+-static struct request *
+-as_find_arq_rb(struct as_data *ad, sector_t sector, int data_dir)
++static inline void as_del_rq_rb(struct as_data *ad, struct request *rq)
+ {
+- struct rb_node *n = ad->sort_list[data_dir].rb_node;
+- struct as_rq *arq;
+-
+- while (n) {
+- arq = rb_entry_arq(n);
+-
+- if (sector < arq->rb_key)
+- n = n->rb_left;
+- else if (sector > arq->rb_key)
+- n = n->rb_right;
+- else
+- return arq->request;
+- }
+-
+- return NULL;
++ elv_rb_del(RQ_RB_ROOT(ad, rq), rq);
+ }
+
+ /*
+@@ -458,26 +277,26 @@ as_find_arq_rb(struct as_data *ad, secto
+ * as_choose_req selects the preferred one of two requests of the same data_dir
+ * ignoring time - eg. timeouts, which is the job of as_dispatch_request
+ */
+-static struct as_rq *
+-as_choose_req(struct as_data *ad, struct as_rq *arq1, struct as_rq *arq2)
++static struct request *
++as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2)
+ {
+ int data_dir;
+ sector_t last, s1, s2, d1, d2;
+ int r1_wrap=0, r2_wrap=0; /* requests are behind the disk head */
+ const sector_t maxback = MAXBACK;
+
+- if (arq1 == NULL || arq1 == arq2)
+- return arq2;
+- if (arq2 == NULL)
+- return arq1;
++ if (rq1 == NULL || rq1 == rq2)
++ return rq2;
++ if (rq2 == NULL)
++ return rq1;
+
+- data_dir = arq1->is_sync;
++ data_dir = rq_is_sync(rq1);
+
+ last = ad->last_sector[data_dir];
+- s1 = arq1->request->sector;
+- s2 = arq2->request->sector;
++ s1 = rq1->sector;
++ s2 = rq2->sector;
+
+- BUG_ON(data_dir != arq2->is_sync);
++ BUG_ON(data_dir != rq_is_sync(rq2));
+
+ /*
+ * Strict one way elevator _except_ in the case where we allow
+@@ -504,61 +323,58 @@ as_choose_req(struct as_data *ad, struct
+
+ /* Found required data */
+ if (!r1_wrap && r2_wrap)
+- return arq1;
++ return rq1;
+ else if (!r2_wrap && r1_wrap)
+- return arq2;
++ return rq2;
+ else if (r1_wrap && r2_wrap) {
+ /* both behind the head */
+ if (s1 <= s2)
+- return arq1;
++ return rq1;
+ else
+- return arq2;
++ return rq2;
+ }
+
+ /* Both requests in front of the head */
+ if (d1 < d2)
+- return arq1;
++ return rq1;
+ else if (d2 < d1)
+- return arq2;
++ return rq2;
+ else {
+ if (s1 >= s2)
+- return arq1;
++ return rq1;
+ else
+- return arq2;
++ return rq2;
+ }
+ }
+
+ /*
+- * as_find_next_arq finds the next request after @prev in elevator order.
++ * as_find_next_rq finds the next request after @prev in elevator order.
+ * this with as_choose_req form the basis for how the scheduler chooses
+ * what request to process next. Anticipation works on top of this.
+ */
+-static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *last)
++static struct request *
++as_find_next_rq(struct as_data *ad, struct request *last)
+ {
+- const int data_dir = last->is_sync;
+- struct as_rq *ret;
+ struct rb_node *rbnext = rb_next(&last->rb_node);
+ struct rb_node *rbprev = rb_prev(&last->rb_node);
+- struct as_rq *arq_next, *arq_prev;
++ struct request *next = NULL, *prev = NULL;
+
+- BUG_ON(!RB_EMPTY_NODE(&last->rb_node));
++ BUG_ON(RB_EMPTY_NODE(&last->rb_node));
+
+ if (rbprev)
+- arq_prev = rb_entry_arq(rbprev);
+- else
+- arq_prev = NULL;
++ prev = rb_entry_rq(rbprev);
+
+ if (rbnext)
+- arq_next = rb_entry_arq(rbnext);
++ next = rb_entry_rq(rbnext);
+ else {
+- arq_next = as_find_first_arq(ad, data_dir);
+- if (arq_next == last)
+- arq_next = NULL;
+- }
++ const int data_dir = rq_is_sync(last);
+
+- ret = as_choose_req(ad, arq_next, arq_prev);
++ rbnext = rb_first(&ad->sort_list[data_dir]);
++ if (rbnext && rbnext != &last->rb_node)
++ next = rb_entry_rq(rbnext);
++ }
+
+- return ret;
++ return as_choose_req(ad, next, prev);
+ }
+
+ /*
+@@ -712,8 +528,7 @@ static void as_update_seekdist(struct as
+ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
+ struct request *rq)
+ {
+- struct as_rq *arq = RQ_DATA(rq);
+- int data_dir = arq->is_sync;
++ int data_dir = rq_is_sync(rq);
+ unsigned long thinktime = 0;
+ sector_t seek_dist;
+
+@@ -752,11 +567,11 @@ static void as_update_iohist(struct as_d
+ * previous one issued.
+ */
+ static int as_close_req(struct as_data *ad, struct as_io_context *aic,
+- struct as_rq *arq)
++ struct request *rq)
+ {
+ unsigned long delay; /* milliseconds */
+ sector_t last = ad->last_sector[ad->batch_data_dir];
+- sector_t next = arq->request->sector;
++ sector_t next = rq->sector;
+ sector_t delta; /* acceptable close offset (in sectors) */
+ sector_t s;
+
+@@ -813,7 +628,7 @@ static int as_close_req(struct as_data *
+ *
+ * If this task has queued some other IO, do not enter enticipation.
+ */
+-static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq)
++static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+ {
+ struct io_context *ioc;
+ struct as_io_context *aic;
+@@ -821,7 +636,7 @@ static int as_can_break_anticipation(str
+ ioc = ad->io_context;
+ BUG_ON(!ioc);
+
+- if (arq && ioc == arq->io_context) {
++ if (rq && ioc == RQ_IOC(rq)) {
+ /* request from same process */
+ return 1;
+ }
+@@ -848,7 +663,7 @@ static int as_can_break_anticipation(str
+ return 1;
+ }
+
+- if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, aic, arq)) {
++ if (rq && rq_is_sync(rq) && as_close_req(ad, aic, rq)) {
+ /*
+ * Found a close request that is not one of ours.
+ *
+@@ -864,7 +679,7 @@ static int as_can_break_anticipation(str
+ ad->exit_no_coop = (7*ad->exit_no_coop)/8;
+ }
+
+- as_update_iohist(ad, aic, arq->request);
++ as_update_iohist(ad, aic, rq);
+ return 1;
+ }
+
+@@ -891,10 +706,10 @@ static int as_can_break_anticipation(str
+ }
+
+ /*
+- * as_can_anticipate indicates whether we should either run arq
++ * as_can_anticipate indicates whether we should either run rq
+ * or keep anticipating a better request.
+ */
+-static int as_can_anticipate(struct as_data *ad, struct as_rq *arq)
++static int as_can_anticipate(struct as_data *ad, struct request *rq)
+ {
+ if (!ad->io_context)
+ /*
+@@ -908,7 +723,7 @@ static int as_can_anticipate(struct as_d
+ */
+ return 0;
+
+- if (as_can_break_anticipation(ad, arq))
++ if (as_can_break_anticipation(ad, rq))
+ /*
+ * This request is a good candidate. Don't keep anticipating,
+ * run it.
+@@ -926,16 +741,16 @@ static int as_can_anticipate(struct as_d
+ }
+
+ /*
+- * as_update_arq must be called whenever a request (arq) is added to
++ * as_update_rq must be called whenever a request (rq) is added to
+ * the sort_list. This function keeps caches up to date, and checks if the
+ * request might be one we are "anticipating"
+ */
+-static void as_update_arq(struct as_data *ad, struct as_rq *arq)
++static void as_update_rq(struct as_data *ad, struct request *rq)
+ {
+- const int data_dir = arq->is_sync;
++ const int data_dir = rq_is_sync(rq);
+
+- /* keep the next_arq cache up to date */
+- ad->next_arq[data_dir] = as_choose_req(ad, arq, ad->next_arq[data_dir]);
++ /* keep the next_rq cache up to date */
++ ad->next_rq[data_dir] = as_choose_req(ad, rq, ad->next_rq[data_dir]);
+
+ /*
+ * have we been anticipating this request?
+@@ -944,7 +759,7 @@ static void as_update_arq(struct as_data
+ */
+ if (ad->antic_status == ANTIC_WAIT_REQ
+ || ad->antic_status == ANTIC_WAIT_NEXT) {
+- if (as_can_break_anticipation(ad, arq))
++ if (as_can_break_anticipation(ad, rq))
+ as_antic_stop(ad);
+ }
+ }
+@@ -984,12 +799,11 @@ static void update_write_batch(struct as
+ static void as_completed_request(request_queue_t *q, struct request *rq)
+ {
+ struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq = RQ_DATA(rq);
+
+ WARN_ON(!list_empty(&rq->queuelist));
+
+- if (arq->state != AS_RQ_REMOVED) {
+- printk("arq->state %d\n", arq->state);
++ if (RQ_STATE(rq) != AS_RQ_REMOVED) {
++ printk("rq->state %d\n", RQ_STATE(rq));
+ WARN_ON(1);
+ goto out;
+ }
+@@ -1009,14 +823,14 @@ static void as_completed_request(request
+ * actually serviced. This should help devices with big TCQ windows
+ * and writeback caches
+ */
+- if (ad->new_batch && ad->batch_data_dir == arq->is_sync) {
++ if (ad->new_batch && ad->batch_data_dir == rq_is_sync(rq)) {
+ update_write_batch(ad);
+ ad->current_batch_expires = jiffies +
+ ad->batch_expire[REQ_SYNC];
+ ad->new_batch = 0;
+ }
+
+- if (ad->io_context == arq->io_context && ad->io_context) {
++ if (ad->io_context == RQ_IOC(rq) && ad->io_context) {
+ ad->antic_start = jiffies;
+ ad->ioc_finished = 1;
+ if (ad->antic_status == ANTIC_WAIT_REQ) {
+@@ -1028,9 +842,9 @@ static void as_completed_request(request
+ }
+ }
+
+- as_put_io_context(arq);
++ as_put_io_context(rq);
+ out:
+- arq->state = AS_RQ_POSTSCHED;
++ RQ_SET_STATE(rq, AS_RQ_POSTSCHED);
+ }
+
+ /*
+@@ -1041,27 +855,27 @@ out:
+ */
+ static void as_remove_queued_request(request_queue_t *q, struct request *rq)
+ {
+- struct as_rq *arq = RQ_DATA(rq);
+- const int data_dir = arq->is_sync;
++ const int data_dir = rq_is_sync(rq);
+ struct as_data *ad = q->elevator->elevator_data;
++ struct io_context *ioc;
+
+- WARN_ON(arq->state != AS_RQ_QUEUED);
++ WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
+
+- if (arq->io_context && arq->io_context->aic) {
+- BUG_ON(!atomic_read(&arq->io_context->aic->nr_queued));
+- atomic_dec(&arq->io_context->aic->nr_queued);
++ ioc = RQ_IOC(rq);
++ if (ioc && ioc->aic) {
++ BUG_ON(!atomic_read(&ioc->aic->nr_queued));
++ atomic_dec(&ioc->aic->nr_queued);
+ }
+
+ /*
+- * Update the "next_arq" cache if we are about to remove its
++ * Update the "next_rq" cache if we are about to remove its
+ * entry
+ */
+- if (ad->next_arq[data_dir] == arq)
+- ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
++ if (ad->next_rq[data_dir] == rq)
++ ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
+
+- list_del_init(&arq->fifo);
+- as_del_arq_hash(arq);
+- as_del_arq_rb(ad, arq);
++ rq_fifo_clear(rq);
++ as_del_rq_rb(ad, rq);
+ }
+
+ /*
+@@ -1074,7 +888,7 @@ static void as_remove_queued_request(req
+ */
+ static int as_fifo_expired(struct as_data *ad, int adir)
+ {
+- struct as_rq *arq;
++ struct request *rq;
+ long delta_jif;
+
+ delta_jif = jiffies - ad->last_check_fifo[adir];
+@@ -1088,9 +902,9 @@ static int as_fifo_expired(struct as_dat
+ if (list_empty(&ad->fifo_list[adir]))
+ return 0;
+
+- arq = list_entry_fifo(ad->fifo_list[adir].next);
++ rq = rq_entry_fifo(ad->fifo_list[adir].next);
+
+- return time_after(jiffies, arq->expires);
++ return time_after(jiffies, rq_fifo_time(rq));
+ }
+
+ /*
+@@ -1113,25 +927,25 @@ static inline int as_batch_expired(struc
+ /*
+ * move an entry to dispatch queue
+ */
+-static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
++static void as_move_to_dispatch(struct as_data *ad, struct request *rq)
+ {
+- struct request *rq = arq->request;
+- const int data_dir = arq->is_sync;
++ const int data_dir = rq_is_sync(rq);
+
+- BUG_ON(!RB_EMPTY_NODE(&arq->rb_node));
++ BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
+
+ as_antic_stop(ad);
+ ad->antic_status = ANTIC_OFF;
+
+ /*
+ * This has to be set in order to be correctly updated by
+- * as_find_next_arq
++ * as_find_next_rq
+ */
+ ad->last_sector[data_dir] = rq->sector + rq->nr_sectors;
+
+ if (data_dir == REQ_SYNC) {
++ struct io_context *ioc = RQ_IOC(rq);
+ /* In case we have to anticipate after this */
+- copy_io_context(&ad->io_context, &arq->io_context);
++ copy_io_context(&ad->io_context, &ioc);
+ } else {
+ if (ad->io_context) {
+ put_io_context(ad->io_context);
+@@ -1143,19 +957,19 @@ static void as_move_to_dispatch(struct a
+ }
+ ad->ioc_finished = 0;
+
+- ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
++ ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
+
+ /*
+ * take it off the sort and fifo list, add to dispatch queue
+ */
+ as_remove_queued_request(ad->q, rq);
+- WARN_ON(arq->state != AS_RQ_QUEUED);
++ WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
+
+ elv_dispatch_sort(ad->q, rq);
+
+- arq->state = AS_RQ_DISPATCHED;
+- if (arq->io_context && arq->io_context->aic)
+- atomic_inc(&arq->io_context->aic->nr_dispatched);
++ RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
++ if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
++ atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
+ ad->nr_dispatched++;
+ }
+
+@@ -1167,9 +981,9 @@ static void as_move_to_dispatch(struct a
+ static int as_dispatch_request(request_queue_t *q, int force)
+ {
+ struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq;
+ const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]);
+ const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]);
++ struct request *rq;
+
+ if (unlikely(force)) {
+ /*
+@@ -1185,14 +999,14 @@ static int as_dispatch_request(request_q
+ ad->changed_batch = 0;
+ ad->new_batch = 0;
+
+- while (ad->next_arq[REQ_SYNC]) {
+- as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]);
++ while (ad->next_rq[REQ_SYNC]) {
++ as_move_to_dispatch(ad, ad->next_rq[REQ_SYNC]);
+ dispatched++;
+ }
+ ad->last_check_fifo[REQ_SYNC] = jiffies;
+
+- while (ad->next_arq[REQ_ASYNC]) {
+- as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]);
++ while (ad->next_rq[REQ_ASYNC]) {
++ as_move_to_dispatch(ad, ad->next_rq[REQ_ASYNC]);
+ dispatched++;
+ }
+ ad->last_check_fifo[REQ_ASYNC] = jiffies;
+@@ -1216,19 +1030,19 @@ static int as_dispatch_request(request_q
+ /*
+ * batch is still running or no reads or no writes
+ */
+- arq = ad->next_arq[ad->batch_data_dir];
++ rq = ad->next_rq[ad->batch_data_dir];
+
+ if (ad->batch_data_dir == REQ_SYNC && ad->antic_expire) {
+ if (as_fifo_expired(ad, REQ_SYNC))
+ goto fifo_expired;
+
+- if (as_can_anticipate(ad, arq)) {
++ if (as_can_anticipate(ad, rq)) {
+ as_antic_waitreq(ad);
+ return 0;
+ }
+ }
+
+- if (arq) {
++ if (rq) {
+ /* we have a "next request" */
+ if (reads && !writes)
+ ad->current_batch_expires =
+@@ -1256,7 +1070,7 @@ static int as_dispatch_request(request_q
+ ad->changed_batch = 1;
+ }
+ ad->batch_data_dir = REQ_SYNC;
+- arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
++ rq = rq_entry_fifo(ad->fifo_list[REQ_SYNC].next);
+ ad->last_check_fifo[ad->batch_data_dir] = jiffies;
+ goto dispatch_request;
+ }
+@@ -1282,7 +1096,7 @@ dispatch_writes:
+ ad->batch_data_dir = REQ_ASYNC;
+ ad->current_write_count = ad->write_batch_count;
+ ad->write_batch_idled = 0;
+- arq = ad->next_arq[ad->batch_data_dir];
++ rq = ad->next_rq[ad->batch_data_dir];
+ goto dispatch_request;
+ }
+
+@@ -1296,8 +1110,7 @@ dispatch_request:
+
+ if (as_fifo_expired(ad, ad->batch_data_dir)) {
+ fifo_expired:
+- arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
+- BUG_ON(arq == NULL);
++ rq = rq_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
+ }
+
+ if (ad->changed_batch) {
+@@ -1316,70 +1129,58 @@ fifo_expired:
+ }
+
+ /*
+- * arq is the selected appropriate request.
++ * rq is the selected appropriate request.
+ */
+- as_move_to_dispatch(ad, arq);
++ as_move_to_dispatch(ad, rq);
+
+ return 1;
+ }
+
+ /*
+- * add arq to rbtree and fifo
++ * add rq to rbtree and fifo
+ */
+ static void as_add_request(request_queue_t *q, struct request *rq)
+ {
+ struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq = RQ_DATA(rq);
+ int data_dir;
+
+- arq->state = AS_RQ_NEW;
++ RQ_SET_STATE(rq, AS_RQ_NEW);
+
+- if (rq_data_dir(arq->request) == READ
+- || (arq->request->flags & REQ_RW_SYNC))
+- arq->is_sync = 1;
+- else
+- arq->is_sync = 0;
+- data_dir = arq->is_sync;
++ data_dir = rq_is_sync(rq);
+
+- arq->io_context = as_get_io_context();
++ rq->elevator_private = as_get_io_context(q->node);
+
+- if (arq->io_context) {
+- as_update_iohist(ad, arq->io_context->aic, arq->request);
+- atomic_inc(&arq->io_context->aic->nr_queued);
++ if (RQ_IOC(rq)) {
++ as_update_iohist(ad, RQ_IOC(rq)->aic, rq);
++ atomic_inc(&RQ_IOC(rq)->aic->nr_queued);
+ }
+
+- as_add_arq_rb(ad, arq);
+- if (rq_mergeable(arq->request))
+- as_add_arq_hash(ad, arq);
++ as_add_rq_rb(ad, rq);
+
+ /*
+ * set expire time (only used for reads) and add to fifo list
+ */
+- arq->expires = jiffies + ad->fifo_expire[data_dir];
+- list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]);
++ rq_set_fifo_time(rq, jiffies + ad->fifo_expire[data_dir]);
++ list_add_tail(&rq->queuelist, &ad->fifo_list[data_dir]);
+
+- as_update_arq(ad, arq); /* keep state machine up to date */
+- arq->state = AS_RQ_QUEUED;
++ as_update_rq(ad, rq); /* keep state machine up to date */
++ RQ_SET_STATE(rq, AS_RQ_QUEUED);
+ }
+
+ static void as_activate_request(request_queue_t *q, struct request *rq)
+ {
+- struct as_rq *arq = RQ_DATA(rq);
+-
+- WARN_ON(arq->state != AS_RQ_DISPATCHED);
+- arq->state = AS_RQ_REMOVED;
+- if (arq->io_context && arq->io_context->aic)
+- atomic_dec(&arq->io_context->aic->nr_dispatched);
++ WARN_ON(RQ_STATE(rq) != AS_RQ_DISPATCHED);
++ RQ_SET_STATE(rq, AS_RQ_REMOVED);
++ if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
++ atomic_dec(&RQ_IOC(rq)->aic->nr_dispatched);
+ }
+
+ static void as_deactivate_request(request_queue_t *q, struct request *rq)
+ {
+- struct as_rq *arq = RQ_DATA(rq);
+-
+- WARN_ON(arq->state != AS_RQ_REMOVED);
+- arq->state = AS_RQ_DISPATCHED;
+- if (arq->io_context && arq->io_context->aic)
+- atomic_inc(&arq->io_context->aic->nr_dispatched);
++ WARN_ON(RQ_STATE(rq) != AS_RQ_REMOVED);
++ RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
++ if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
++ atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
+ }
+
+ /*
+@@ -1396,93 +1197,35 @@ static int as_queue_empty(request_queue_
+ && list_empty(&ad->fifo_list[REQ_SYNC]);
+ }
+
+-static struct request *as_former_request(request_queue_t *q,
+- struct request *rq)
+-{
+- struct as_rq *arq = RQ_DATA(rq);
+- struct rb_node *rbprev = rb_prev(&arq->rb_node);
+- struct request *ret = NULL;
+-
+- if (rbprev)
+- ret = rb_entry_arq(rbprev)->request;
+-
+- return ret;
+-}
+-
+-static struct request *as_latter_request(request_queue_t *q,
+- struct request *rq)
+-{
+- struct as_rq *arq = RQ_DATA(rq);
+- struct rb_node *rbnext = rb_next(&arq->rb_node);
+- struct request *ret = NULL;
+-
+- if (rbnext)
+- ret = rb_entry_arq(rbnext)->request;
+-
+- return ret;
+-}
+-
+ static int
+ as_merge(request_queue_t *q, struct request **req, struct bio *bio)
+ {
+ struct as_data *ad = q->elevator->elevator_data;
+ sector_t rb_key = bio->bi_sector + bio_sectors(bio);
+ struct request *__rq;
+- int ret;
+-
+- /*
+- * see if the merge hash can satisfy a back merge
+- */
+- __rq = as_find_arq_hash(ad, 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;
+- }
+- }
+
+ /*
+ * check for front merge
+ */
+- __rq = as_find_arq_rb(ad, rb_key, bio_data_dir(bio));
+- if (__rq) {
+- BUG_ON(rb_key != rq_rb_key(__rq));
+-
+- if (elv_rq_merge_ok(__rq, bio)) {
+- ret = ELEVATOR_FRONT_MERGE;
+- goto out;
+- }
++ __rq = elv_rb_find(&ad->sort_list[bio_data_dir(bio)], rb_key);
++ if (__rq && elv_rq_merge_ok(__rq, bio)) {
++ *req = __rq;
++ return ELEVATOR_FRONT_MERGE;
+ }
+
+ return ELEVATOR_NO_MERGE;
+-out:
+- if (ret) {
+- if (rq_mergeable(__rq))
+- as_hot_arq_hash(ad, RQ_DATA(__rq));
+- }
+- *req = __rq;
+- return ret;
+ }
+
+-static void as_merged_request(request_queue_t *q, struct request *req)
++static void as_merged_request(request_queue_t *q, struct request *req, int type)
+ {
+ struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq = RQ_DATA(req);
+-
+- /*
+- * hash always needs to be repositioned, key is end sector
+- */
+- as_del_arq_hash(arq);
+- as_add_arq_hash(ad, arq);
+
+ /*
+ * if the merge was a front merge, we need to reposition request
+ */
+- if (rq_rb_key(req) != arq->rb_key) {
+- as_del_arq_rb(ad, arq);
+- as_add_arq_rb(ad, arq);
++ if (type == ELEVATOR_FRONT_MERGE) {
++ as_del_rq_rb(ad, req);
++ as_add_rq_rb(ad, req);
+ /*
+ * Note! At this stage of this and the next function, our next
+ * request may not be optimal - eg the request may have "grown"
+@@ -1494,38 +1237,22 @@ static void as_merged_request(request_qu
+ static void as_merged_requests(request_queue_t *q, struct request *req,
+ struct request *next)
+ {
+- struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq = RQ_DATA(req);
+- struct as_rq *anext = RQ_DATA(next);
+-
+- BUG_ON(!arq);
+- BUG_ON(!anext);
+-
+ /*
+- * reposition arq (this is the merged request) in hash, and in rbtree
+- * in case of a front merge
++ * if next expires before rq, assign its expire time to arq
++ * and move into next position (next will be deleted) in fifo
+ */
+- as_del_arq_hash(arq);
+- as_add_arq_hash(ad, arq);
+-
+- if (rq_rb_key(req) != arq->rb_key) {
+- as_del_arq_rb(ad, arq);
+- as_add_arq_rb(ad, arq);
+- }
++ if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
++ if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
++ struct io_context *rioc = RQ_IOC(req);
++ struct io_context *nioc = RQ_IOC(next);
+
+- /*
+- * if anext expires before arq, assign its expire time to arq
+- * and move into anext position (anext will be deleted) in fifo
+- */
+- if (!list_empty(&arq->fifo) && !list_empty(&anext->fifo)) {
+- if (time_before(anext->expires, arq->expires)) {
+- list_move(&arq->fifo, &anext->fifo);
+- arq->expires = anext->expires;
++ list_move(&req->queuelist, &next->queuelist);
++ rq_set_fifo_time(req, rq_fifo_time(next));
+ /*
+ * Don't copy here but swap, because when anext is
+ * removed below, it must contain the unused context
+ */
+- swap_io_context(&arq->io_context, &anext->io_context);
++ swap_io_context(&rioc, &nioc);
+ }
+ }
+
+@@ -1533,9 +1260,9 @@ static void as_merged_requests(request_q
+ * kill knowledge of next, this one is a goner
+ */
+ as_remove_queued_request(q, next);
+- as_put_io_context(anext);
++ as_put_io_context(next);
+
+- anext->state = AS_RQ_MERGED;
++ RQ_SET_STATE(next, AS_RQ_MERGED);
+ }
+
+ /*
+@@ -1553,61 +1280,18 @@ static void as_work_handler(void *data)
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+- if (!as_queue_empty(q))
+- q->request_fn(q);
++ blk_start_queueing(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+
+-static void as_put_request(request_queue_t *q, struct request *rq)
+-{
+- struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq = RQ_DATA(rq);
+-
+- if (!arq) {
+- WARN_ON(1);
+- return;
+- }
+-
+- if (unlikely(arq->state != AS_RQ_POSTSCHED &&
+- arq->state != AS_RQ_PRESCHED &&
+- arq->state != AS_RQ_MERGED)) {
+- printk("arq->state %d\n", arq->state);
+- WARN_ON(1);
+- }
+-
+- mempool_free(arq, ad->arq_pool);
+- rq->elevator_private = NULL;
+-}
+-
+-static int as_set_request(request_queue_t *q, struct request *rq,
+- struct bio *bio, gfp_t gfp_mask)
+-{
+- struct as_data *ad = q->elevator->elevator_data;
+- struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
+-
+- if (arq) {
+- memset(arq, 0, sizeof(*arq));
+- RB_CLEAR_NODE(&arq->rb_node);
+- arq->request = rq;
+- arq->state = AS_RQ_PRESCHED;
+- arq->io_context = NULL;
+- INIT_HLIST_NODE(&arq->hash);
+- INIT_LIST_HEAD(&arq->fifo);
+- rq->elevator_private = arq;
+- return 0;
+- }
+-
+- return 1;
+-}
+-
+-static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
++static int as_may_queue(request_queue_t *q, int rw)
+ {
+ int ret = ELV_MQUEUE_MAY;
+ struct as_data *ad = q->elevator->elevator_data;
+ struct io_context *ioc;
+ if (ad->antic_status == ANTIC_WAIT_REQ ||
+ ad->antic_status == ANTIC_WAIT_NEXT) {
+- ioc = as_get_io_context();
++ ioc = as_get_io_context(q->node);
+ if (ad->io_context == ioc)
+ ret = ELV_MQUEUE_MUST;
+ put_io_context(ioc);
+@@ -1626,23 +1310,16 @@ static void as_exit_queue(elevator_t *e)
+ BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC]));
+ BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC]));
+
+- mempool_destroy(ad->arq_pool);
+ put_io_context(ad->io_context);
+- kfree(ad->hash);
+ kfree(ad);
+ }
+
+ /*
+- * initialize elevator private data (as_data), and alloc a arq for
+- * each request on the free lists
++ * initialize elevator private data (as_data).
+ */
+ static void *as_init_queue(request_queue_t *q, elevator_t *e)
+ {
+ struct as_data *ad;
+- int i;
+-
+- if (!arq_pool)
+- return NULL;
+
+ ad = kmalloc_node(sizeof(*ad), GFP_KERNEL, q->node);
+ if (!ad)
+@@ -1651,30 +1328,12 @@ static void *as_init_queue(request_queue
+
+ ad->q = q; /* Identify what queue the data belongs to */
+
+- ad->hash = kmalloc_node(sizeof(struct hlist_head)*AS_HASH_ENTRIES,
+- GFP_KERNEL, q->node);
+- if (!ad->hash) {
+- kfree(ad);
+- return NULL;
+- }
+-
+- ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
+- mempool_free_slab, arq_pool, q->node);
+- if (!ad->arq_pool) {
+- kfree(ad->hash);
+- kfree(ad);
+- return NULL;
+- }
+-
+ /* anticipatory scheduling helpers */
+ ad->antic_timer.function = as_antic_timeout;
+ ad->antic_timer.data = (unsigned long)q;
+ init_timer(&ad->antic_timer);
+ INIT_WORK(&ad->antic_work, as_work_handler, q);
+
+- for (i = 0; i < AS_HASH_ENTRIES; i++)
+- INIT_HLIST_HEAD(&ad->hash[i]);
+-
+ INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]);
+ INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]);
+ ad->sort_list[REQ_SYNC] = RB_ROOT;
+@@ -1787,10 +1446,8 @@ static struct elevator_type iosched_as =
+ .elevator_deactivate_req_fn = as_deactivate_request,
+ .elevator_queue_empty_fn = as_queue_empty,
+ .elevator_completed_req_fn = as_completed_request,
+- .elevator_former_req_fn = as_former_request,
+- .elevator_latter_req_fn = as_latter_request,
+- .elevator_set_req_fn = as_set_request,
+- .elevator_put_req_fn = as_put_request,
++ .elevator_former_req_fn = elv_rb_former_request,
++ .elevator_latter_req_fn = elv_rb_latter_request,
+ .elevator_may_queue_fn = as_may_queue,
+ .elevator_init_fn = as_init_queue,
+ .elevator_exit_fn = as_exit_queue,
+@@ -1806,11 +1463,6 @@ static int __init as_init(void)
+ {
+ int ret;
+
+- arq_pool = kmem_cache_create("as_arq", sizeof(struct as_rq),
+- 0, 0, NULL, NULL);
+- if (!arq_pool)
+- return -ENOMEM;
+-
+ ret = elv_register(&iosched_as);
+ if (!ret) {
+ /*
+@@ -1822,21 +1474,19 @@ static int __init as_init(void)
+ return 0;
+ }
+
+- kmem_cache_destroy(arq_pool);
+ return ret;
+ }
+
+ static void __exit as_exit(void)
+ {
+- DECLARE_COMPLETION(all_gone);
++ DECLARE_COMPLETION_ONSTACK(all_gone);
+ elv_unregister(&iosched_as);
+ ioc_gone = &all_gone;
+ /* ioc_gone's update must be visible before reading ioc_count */
+ smp_wmb();
+- if (atomic_read(&ioc_count))
++ if (elv_ioc_count_read(ioc_count))
+ wait_for_completion(ioc_gone);
+ synchronize_rcu();
+- kmem_cache_destroy(arq_pool);
+ }
+
+ module_init(as_init);
+diff --git a/block/blktrace.c b/block/blktrace.c
+index 265f7a8..135593c 100644
+--- a/block/blktrace.c
++++ b/block/blktrace.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2006 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2006 Jens Axboe <axboe at kernel.dk>
+ *
+ * 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
+@@ -69,7 +69,7 @@ static u32 ddir_act[2] __read_mostly = {
+ /*
+ * Bio action bits of interest
+ */
+-static u32 bio_act[5] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD) };
++static u32 bio_act[9] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD), 0, 0, 0, BLK_TC_ACT(BLK_TC_META) };
+
+ /*
+ * More could be added as needed, taking care to increment the decrementer
+@@ -81,6 +81,8 @@ static u32 bio_act[5] __read_mostly = {
+ (((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1))
+ #define trace_ahead_bit(rw) \
+ (((rw) & (1 << BIO_RW_AHEAD)) << (2 - BIO_RW_AHEAD))
++#define trace_meta_bit(rw) \
++ (((rw) & (1 << BIO_RW_META)) >> (BIO_RW_META - 3))
+
+ /*
+ * The worker for the various blk_add_trace*() types. Fills out a
+@@ -103,6 +105,7 @@ void __blk_add_trace(struct blk_trace *b
+ what |= bio_act[trace_barrier_bit(rw)];
+ what |= bio_act[trace_sync_bit(rw)];
+ what |= bio_act[trace_ahead_bit(rw)];
++ what |= bio_act[trace_meta_bit(rw)];
+
+ pid = tsk->pid;
+ if (unlikely(act_log_check(bt, what, sector, pid)))
+@@ -217,7 +220,7 @@ static int blk_trace_remove(request_queu
+
+ static int blk_dropped_open(struct inode *inode, struct file *filp)
+ {
+- filp->private_data = inode->u.generic_ip;
++ filp->private_data = inode->i_private;
+
+ return 0;
+ }
+@@ -450,8 +453,10 @@ int blk_trace_ioctl(struct block_device
+ **/
+ void blk_trace_shutdown(request_queue_t *q)
+ {
+- blk_trace_startstop(q, 0);
+- blk_trace_remove(q);
++ if (q->blk_trace) {
++ blk_trace_startstop(q, 0);
++ blk_trace_remove(q);
++ }
+ }
+
+ /*
+@@ -471,6 +476,9 @@ static void blk_check_time(unsigned long
+ *t -= (a + b) / 2;
+ }
+
++/*
++ * calibrate our inter-CPU timings
++ */
+ static void blk_trace_check_cpu_time(void *data)
+ {
+ unsigned long long *t;
+@@ -488,20 +496,6 @@ static void blk_trace_check_cpu_time(voi
+ put_cpu();
+ }
+
+-/*
+- * Call blk_trace_check_cpu_time() on each CPU to calibrate our inter-CPU
+- * timings
+- */
+-static void blk_trace_calibrate_offsets(void)
+-{
+- unsigned long flags;
+-
+- smp_call_function(blk_trace_check_cpu_time, NULL, 1, 1);
+- local_irq_save(flags);
+- blk_trace_check_cpu_time(NULL);
+- local_irq_restore(flags);
+-}
+-
+ static void blk_trace_set_ht_offsets(void)
+ {
+ #if defined(CONFIG_SCHED_SMT)
+@@ -530,7 +524,7 @@ static void blk_trace_set_ht_offsets(voi
+ static __init int blk_trace_init(void)
+ {
+ mutex_init(&blk_tree_mutex);
+- blk_trace_calibrate_offsets();
++ on_each_cpu(blk_trace_check_cpu_time, NULL, 1, 1);
+ blk_trace_set_ht_offsets();
+
+ return 0;
+diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
+index 3a3aee0..1d9c3c7 100644
+--- a/block/cfq-iosched.c
++++ b/block/cfq-iosched.c
+@@ -4,7 +4,7 @@
+ * Based on ideas from a previously unfinished io
+ * scheduler (round robin per-process disk scheduling) and Andrea Arcangeli.
+ *
+- * Copyright (C) 2003 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2003 Jens Axboe <axboe at kernel.dk>
+ */
+ #include <linux/module.h>
+ #include <linux/blkdev.h>
+@@ -17,7 +17,6 @@
+ * tunables
+ */
+ static const int cfq_quantum = 4; /* max queue in one round of service */
+-static const int cfq_queued = 8; /* minimum rq allocate limit per-queue*/
+ static const int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
+ static const int cfq_back_max = 16 * 1024; /* maximum backwards seek, in KiB */
+ static const int cfq_back_penalty = 2; /* penalty of a backwards seek */
+@@ -32,8 +31,6 @@ static int cfq_slice_idle = HZ / 125;
+
+ #define CFQ_KEY_ASYNC (0)
+
+-static DEFINE_SPINLOCK(cfq_exit_lock);
+-
+ /*
+ * for the hash of cfqq inside the cfqd
+ */
+@@ -41,37 +38,19 @@ static DEFINE_SPINLOCK(cfq_exit_lock);
+ #define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT)
+ #define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash)
+
+-/*
+- * for the hash of crq inside the cfqq
+- */
+-#define CFQ_MHASH_SHIFT 6
+-#define CFQ_MHASH_BLOCK(sec) ((sec) >> 3)
+-#define CFQ_MHASH_ENTRIES (1 << CFQ_MHASH_SHIFT)
+-#define CFQ_MHASH_FN(sec) hash_long(CFQ_MHASH_BLOCK(sec), CFQ_MHASH_SHIFT)
+-#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
+-#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
++#define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private)
++#define RQ_CFQQ(rq) ((rq)->elevator_private2)
+
+-/*
+- * rb-tree defines
+- */
+-#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)
+-#define rq_rb_key(rq) (rq)->sector
+-
+-static kmem_cache_t *crq_pool;
+ static kmem_cache_t *cfq_pool;
+ static kmem_cache_t *cfq_ioc_pool;
+
+-static atomic_t ioc_count = ATOMIC_INIT(0);
++static DEFINE_PER_CPU(unsigned long, ioc_count);
+ static struct completion *ioc_gone;
+
+ #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)
+@@ -103,29 +82,14 @@ struct cfq_data {
+ unsigned int busy_queues;
+
+ /*
+- * non-ordered list of empty cfqq's
+- */
+- struct list_head empty_list;
+-
+- /*
+ * cfqq lookup hash
+ */
+ struct hlist_head *cfq_hash;
+
+- /*
+- * global crq hash for all queues
+- */
+- struct hlist_head *crq_hash;
+-
+- mempool_t *crq_pool;
+-
+ int rq_in_driver;
+ int hw_tag;
+
+ /*
+- * schedule slice state info
+- */
+- /*
+ * idle window management
+ */
+ struct timer_list idle_slice_timer;
+@@ -141,13 +105,10 @@ struct cfq_data {
+ sector_t last_sector;
+ unsigned long last_end_request;
+
+- unsigned int rq_starved;
+-
+ /*
+ * tunables, see top of file
+ */
+ unsigned int cfq_quantum;
+- unsigned int cfq_queued;
+ unsigned int cfq_fifo_expire[2];
+ unsigned int cfq_back_penalty;
+ unsigned int cfq_back_max;
+@@ -170,23 +131,24 @@ struct cfq_queue {
+ struct hlist_node cfq_hash;
+ /* hash key */
+ unsigned int key;
+- /* on either rr or empty list of cfqd */
++ /* member of the rr/busy/cur/idle cfqd list */
+ struct list_head cfq_list;
+ /* sorted list of pending requests */
+ struct rb_root sort_list;
+ /* if fifo isn't expired, next request to serve */
+- struct cfq_rq *next_crq;
++ struct request *next_rq;
+ /* requests queued in sort_list */
+ int queued[2];
+ /* currently allocated requests */
+ int allocated[2];
++ /* pending metadata requests */
++ int meta_pending;
+ /* fifo list of requests in sort_list */
+ struct list_head fifo;
+
+ unsigned long slice_start;
+ unsigned long slice_end;
+ unsigned long slice_left;
+- unsigned long service_last;
+
+ /* number of requests that are on the dispatch list */
+ int on_dispatch[2];
+@@ -199,18 +161,6 @@ struct cfq_queue {
+ unsigned int flags;
+ };
+
+-struct cfq_rq {
+- struct rb_node rb_node;
+- sector_t rb_key;
+- struct request *request;
+- struct hlist_node hash;
+-
+- struct cfq_queue *cfq_queue;
+- struct cfq_io_context *io_context;
+-
+- unsigned int crq_flags;
+-};
+-
+ enum cfqq_state_flags {
+ CFQ_CFQQ_FLAG_on_rr = 0,
+ CFQ_CFQQ_FLAG_wait_request,
+@@ -220,6 +170,7 @@ enum cfqq_state_flags {
+ CFQ_CFQQ_FLAG_fifo_expire,
+ CFQ_CFQQ_FLAG_idle_window,
+ CFQ_CFQQ_FLAG_prio_changed,
++ CFQ_CFQQ_FLAG_queue_new,
+ };
+
+ #define CFQ_CFQQ_FNS(name) \
+@@ -244,70 +195,14 @@ CFQ_CFQQ_FNS(must_dispatch);
+ CFQ_CFQQ_FNS(fifo_expire);
+ CFQ_CFQQ_FNS(idle_window);
+ CFQ_CFQQ_FNS(prio_changed);
++CFQ_CFQQ_FNS(queue_new);
+ #undef CFQ_CFQQ_FNS
+
+-enum cfq_rq_state_flags {
+- CFQ_CRQ_FLAG_is_sync = 0,
+-};
+-
+-#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(is_sync);
+-#undef CFQ_CRQ_FNS
+-
+ static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
+-static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *);
++static void cfq_dispatch_insert(request_queue_t *, struct request *);
+ static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
+
+ /*
+- * lots of deadline iosched dupes, can be abstracted later...
+- */
+-static inline void cfq_del_crq_hash(struct cfq_rq *crq)
+-{
+- hlist_del_init(&crq->hash);
+-}
+-
+-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));
+-
+- hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]);
+-}
+-
+-static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
+-{
+- struct hlist_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)];
+- struct hlist_node *entry, *next;
+-
+- hlist_for_each_safe(entry, next, hash_list) {
+- struct cfq_rq *crq = list_entry_hash(entry);
+- struct request *__rq = crq->request;
+-
+- if (!rq_mergeable(__rq)) {
+- cfq_del_crq_hash(crq);
+- continue;
+- }
+-
+- if (rq_hash_key(__rq) == offset)
+- return __rq;
+- }
+-
+- return NULL;
+-}
+-
+-/*
+ * scheduler run of queue, if there are requests pending and no one in the
+ * driver that will restart queueing
+ */
+@@ -333,12 +228,12 @@ static inline pid_t cfq_queue_pid(struct
+ }
+
+ /*
+- * Lifted from AS - choose which of crq1 and crq2 that is best served now.
++ * Lifted from AS - choose which of rq1 and rq2 that is best served now.
+ * We choose the request that is closest to the head right now. Distance
+ * behind the head is penalized and only allowed to a certain extent.
+ */
+-static struct cfq_rq *
+-cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
++static struct request *
++cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
+ {
+ sector_t last, s1, s2, d1 = 0, d2 = 0;
+ unsigned long back_max;
+@@ -346,18 +241,22 @@ cfq_choose_req(struct cfq_data *cfqd, st
+ #define CFQ_RQ2_WRAP 0x02 /* request 2 wraps */
+ unsigned wrap = 0; /* bit mask: requests behind the disk head? */
+
+- if (crq1 == NULL || crq1 == crq2)
+- return crq2;
+- if (crq2 == NULL)
+- return crq1;
++ if (rq1 == NULL || rq1 == rq2)
++ return rq2;
++ if (rq2 == NULL)
++ return rq1;
+
+- if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2))
+- return crq1;
+- else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1))
+- return crq2;
++ if (rq_is_sync(rq1) && !rq_is_sync(rq2))
++ return rq1;
++ else if (rq_is_sync(rq2) && !rq_is_sync(rq1))
++ return rq2;
++ if (rq_is_meta(rq1) && !rq_is_meta(rq2))
++ return rq1;
++ else if (rq_is_meta(rq2) && !rq_is_meta(rq1))
++ return rq2;
+
+- s1 = crq1->request->sector;
+- s2 = crq2->request->sector;
++ s1 = rq1->sector;
++ s2 = rq2->sector;
+
+ last = cfqd->last_sector;
+
+@@ -392,23 +291,23 @@ cfq_choose_req(struct cfq_data *cfqd, st
+ * check two variables for all permutations: --> faster!
+ */
+ switch (wrap) {
+- case 0: /* common case for CFQ: crq1 and crq2 not wrapped */
++ case 0: /* common case for CFQ: rq1 and rq2 not wrapped */
+ if (d1 < d2)
+- return crq1;
++ return rq1;
+ else if (d2 < d1)
+- return crq2;
++ return rq2;
+ else {
+ if (s1 >= s2)
+- return crq1;
++ return rq1;
+ else
+- return crq2;
++ return rq2;
+ }
+
+ case CFQ_RQ2_WRAP:
+- return crq1;
++ return rq1;
+ case CFQ_RQ1_WRAP:
+- return crq2;
+- case (CFQ_RQ1_WRAP|CFQ_RQ2_WRAP): /* both crqs wrapped */
++ return rq2;
++ case (CFQ_RQ1_WRAP|CFQ_RQ2_WRAP): /* both rqs wrapped */
+ default:
+ /*
+ * Since both rqs are wrapped,
+@@ -417,50 +316,43 @@ cfq_choose_req(struct cfq_data *cfqd, st
+ * since back seek takes more time than forward.
+ */
+ if (s1 <= s2)
+- return crq1;
++ return rq1;
+ else
+- return crq2;
++ return rq2;
+ }
+ }
+
+ /*
+ * would be nice to take fifo expire time into account as well
+ */
+-static struct cfq_rq *
+-cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+- struct cfq_rq *last)
++static struct request *
++cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
++ struct request *last)
+ {
+- struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
+- struct rb_node *rbnext, *rbprev;
+-
+- if (!(rbnext = rb_next(&last->rb_node))) {
+- rbnext = rb_first(&cfqq->sort_list);
+- if (rbnext == &last->rb_node)
+- rbnext = NULL;
+- }
++ struct rb_node *rbnext = rb_next(&last->rb_node);
++ struct rb_node *rbprev = rb_prev(&last->rb_node);
++ struct request *next = NULL, *prev = NULL;
+
+- rbprev = rb_prev(&last->rb_node);
++ BUG_ON(RB_EMPTY_NODE(&last->rb_node));
+
+ if (rbprev)
+- crq_prev = rb_entry_crq(rbprev);
+- if (rbnext)
+- crq_next = rb_entry_crq(rbnext);
+-
+- return cfq_choose_req(cfqd, crq_next, crq_prev);
+-}
++ prev = rb_entry_rq(rbprev);
+
+-static void cfq_update_next_crq(struct cfq_rq *crq)
+-{
+- struct cfq_queue *cfqq = crq->cfq_queue;
++ if (rbnext)
++ next = rb_entry_rq(rbnext);
++ else {
++ rbnext = rb_first(&cfqq->sort_list);
++ if (rbnext && rbnext != &last->rb_node)
++ next = rb_entry_rq(rbnext);
++ }
+
+- if (cfqq->next_crq == crq)
+- cfqq->next_crq = cfq_find_next_crq(cfqq->cfqd, cfqq, crq);
++ return cfq_choose_req(cfqd, next, prev);
+ }
+
+ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
+ {
+ struct cfq_data *cfqd = cfqq->cfqd;
+- struct list_head *list, *entry;
++ struct list_head *list;
+
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
+
+@@ -485,31 +377,26 @@ static void cfq_resort_rr_list(struct cf
+ }
+
+ /*
+- * if queue was preempted, just add to front to be fair. busy_rr
+- * isn't sorted, but insert at the back for fairness.
++ * If this queue was preempted or is new (never been serviced), let
++ * it be added first for fairness but beind other new queues.
++ * Otherwise, just add to the back of the list.
+ */
+- if (preempted || list == &cfqd->busy_rr) {
+- if (preempted)
+- list = list->prev;
++ if (preempted || cfq_cfqq_queue_new(cfqq)) {
++ struct list_head *n = list;
++ struct cfq_queue *__cfqq;
+
+- list_add_tail(&cfqq->cfq_list, list);
+- return;
+- }
++ while (n->next != list) {
++ __cfqq = list_entry_cfqq(n->next);
++ if (!cfq_cfqq_queue_new(__cfqq))
++ break;
+
+- /*
+- * sort by when queue was last serviced
+- */
+- entry = list;
+- while ((entry = entry->prev) != list) {
+- struct cfq_queue *__cfqq = list_entry_cfqq(entry);
++ n = n->next;
++ }
+
+- if (!__cfqq->service_last)
+- break;
+- if (time_before(__cfqq->service_last, cfqq->service_last))
+- break;
++ list = n;
+ }
+
+- list_add(&cfqq->cfq_list, entry);
++ list_add_tail(&cfqq->cfq_list, list);
+ }
+
+ /*
+@@ -531,7 +418,7 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, s
+ {
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
+ cfq_clear_cfqq_on_rr(cfqq);
+- list_move(&cfqq->cfq_list, &cfqd->empty_list);
++ list_del_init(&cfqq->cfq_list);
+
+ BUG_ON(!cfqd->busy_queues);
+ cfqd->busy_queues--;
+@@ -540,81 +427,46 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, s
+ /*
+ * rb tree support functions
+ */
+-static inline void cfq_del_crq_rb(struct cfq_rq *crq)
++static inline void cfq_del_rq_rb(struct request *rq)
+ {
+- struct cfq_queue *cfqq = crq->cfq_queue;
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+ struct cfq_data *cfqd = cfqq->cfqd;
+- const int sync = cfq_crq_is_sync(crq);
++ const int sync = rq_is_sync(rq);
+
+ BUG_ON(!cfqq->queued[sync]);
+ cfqq->queued[sync]--;
+
+- cfq_update_next_crq(crq);
+-
+- rb_erase(&crq->rb_node, &cfqq->sort_list);
++ elv_rb_del(&cfqq->sort_list, rq);
+
+ if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
+ cfq_del_cfqq_rr(cfqd, cfqq);
+ }
+
+-static struct cfq_rq *
+-__cfq_add_crq_rb(struct cfq_rq *crq)
++static void cfq_add_rq_rb(struct request *rq)
+ {
+- struct rb_node **p = &crq->cfq_queue->sort_list.rb_node;
+- struct rb_node *parent = NULL;
+- struct cfq_rq *__crq;
+-
+- while (*p) {
+- parent = *p;
+- __crq = rb_entry_crq(parent);
+-
+- if (crq->rb_key < __crq->rb_key)
+- p = &(*p)->rb_left;
+- else if (crq->rb_key > __crq->rb_key)
+- p = &(*p)->rb_right;
+- else
+- return __crq;
+- }
+-
+- rb_link_node(&crq->rb_node, parent, p);
+- return NULL;
+-}
+-
+-static void cfq_add_crq_rb(struct cfq_rq *crq)
+-{
+- struct cfq_queue *cfqq = crq->cfq_queue;
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+ struct cfq_data *cfqd = cfqq->cfqd;
+- struct request *rq = crq->request;
+- struct cfq_rq *__alias;
++ struct request *__alias;
+
+- crq->rb_key = rq_rb_key(rq);
+- cfqq->queued[cfq_crq_is_sync(crq)]++;
++ cfqq->queued[rq_is_sync(rq)]++;
+
+ /*
+ * looks a little odd, but the first insert might return an alias.
+ * if that happens, put the alias on the dispatch list
+ */
+- while ((__alias = __cfq_add_crq_rb(crq)) != NULL)
++ while ((__alias = elv_rb_add(&cfqq->sort_list, rq)) != NULL)
+ cfq_dispatch_insert(cfqd->queue, __alias);
+
+- rb_insert_color(&crq->rb_node, &cfqq->sort_list);
+-
+ if (!cfq_cfqq_on_rr(cfqq))
+ cfq_add_cfqq_rr(cfqd, cfqq);
+-
+- /*
+- * check if this request is a better next-serve candidate
+- */
+- cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
+ }
+
+ static inline void
+-cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
++cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
+ {
+- rb_erase(&crq->rb_node, &cfqq->sort_list);
+- cfqq->queued[cfq_crq_is_sync(crq)]--;
+-
+- cfq_add_crq_rb(crq);
++ elv_rb_del(&cfqq->sort_list, rq);
++ cfqq->queued[rq_is_sync(rq)]--;
++ cfq_add_rq_rb(rq);
+ }
+
+ static struct request *
+@@ -623,27 +475,14 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd
+ struct task_struct *tsk = current;
+ pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio));
+ struct cfq_queue *cfqq;
+- struct rb_node *n;
+- sector_t sector;
+
+ cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+- if (!cfqq)
+- goto out;
+-
+- sector = bio->bi_sector + bio_sectors(bio);
+- n = cfqq->sort_list.rb_node;
+- while (n) {
+- struct cfq_rq *crq = rb_entry_crq(n);
++ if (cfqq) {
++ sector_t sector = bio->bi_sector + bio_sectors(bio);
+
+- if (sector < crq->rb_key)
+- n = n->rb_left;
+- else if (sector > crq->rb_key)
+- n = n->rb_right;
+- else
+- return crq->request;
++ return elv_rb_find(&cfqq->sort_list, sector);
+ }
+
+-out:
+ return NULL;
+ }
+
+@@ -673,11 +512,18 @@ static void cfq_deactivate_request(reque
+
+ static void cfq_remove_request(struct request *rq)
+ {
+- struct cfq_rq *crq = RQ_DATA(rq);
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
++
++ if (cfqq->next_rq == rq)
++ cfqq->next_rq = cfq_find_next_rq(cfqq->cfqd, cfqq, rq);
+
+ list_del_init(&rq->queuelist);
+- cfq_del_crq_rb(crq);
+- cfq_del_crq_hash(crq);
++ cfq_del_rq_rb(rq);
++
++ if (rq_is_meta(rq)) {
++ WARN_ON(!cfqq->meta_pending);
++ cfqq->meta_pending--;
++ }
+ }
+
+ static int
+@@ -685,39 +531,23 @@ cfq_merge(request_queue_t *q, struct req
+ {
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct request *__rq;
+- int ret;
+-
+- __rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
+- if (__rq && elv_rq_merge_ok(__rq, bio)) {
+- ret = ELEVATOR_BACK_MERGE;
+- goto out;
+- }
+
+ __rq = cfq_find_rq_fmerge(cfqd, bio);
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+- ret = ELEVATOR_FRONT_MERGE;
+- goto out;
++ *req = __rq;
++ return ELEVATOR_FRONT_MERGE;
+ }
+
+ return ELEVATOR_NO_MERGE;
+-out:
+- *req = __rq;
+- return ret;
+ }
+
+-static void cfq_merged_request(request_queue_t *q, struct request *req)
++static void cfq_merged_request(request_queue_t *q, struct request *req,
++ int type)
+ {
+- struct cfq_data *cfqd = q->elevator->elevator_data;
+- struct cfq_rq *crq = RQ_DATA(req);
+-
+- cfq_del_crq_hash(crq);
+- cfq_add_crq_hash(cfqd, crq);
++ if (type == ELEVATOR_FRONT_MERGE) {
++ struct cfq_queue *cfqq = RQ_CFQQ(req);
+
+- if (rq_rb_key(req) != crq->rb_key) {
+- struct cfq_queue *cfqq = crq->cfq_queue;
+-
+- cfq_update_next_crq(crq);
+- cfq_reposition_crq_rb(cfqq, crq);
++ cfq_reposition_rq_rb(cfqq, req);
+ }
+ }
+
+@@ -725,8 +555,6 @@ static void
+ cfq_merged_requests(request_queue_t *q, struct request *rq,
+ struct request *next)
+ {
+- cfq_merged_request(q, rq);
+-
+ /*
+ * reposition in fifo if next is older than rq
+ */
+@@ -768,13 +596,12 @@ __cfq_slice_expired(struct cfq_data *cfq
+ if (cfq_cfqq_wait_request(cfqq))
+ del_timer(&cfqd->idle_slice_timer);
+
+- if (!preempted && !cfq_cfqq_dispatched(cfqq)) {
+- cfqq->service_last = now;
++ if (!preempted && !cfq_cfqq_dispatched(cfqq))
+ cfq_schedule_dispatch(cfqd);
+- }
+
+ cfq_clear_cfqq_must_dispatch(cfqq);
+ cfq_clear_cfqq_wait_request(cfqq);
++ cfq_clear_cfqq_queue_new(cfqq);
+
+ /*
+ * store what was left of this slice, if the queue idled out
+@@ -868,26 +695,25 @@ static struct cfq_queue *cfq_set_active_
+ {
+ struct cfq_queue *cfqq = 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)
++ if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1) {
++ /*
++ * 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
++ */
+ cfqq = list_entry_cfqq(cfqd->cur_rr.next);
+-
+- /*
+- * If no new queues are available, check if the busy list has some
+- * before falling back to idle io.
+- */
+- if (!cfqq && !list_empty(&cfqd->busy_rr))
++ } else if (!list_empty(&cfqd->busy_rr)) {
++ /*
++ * If no new queues are available, check if the busy list has
++ * some before falling back to idle io.
++ */
+ cfqq = list_entry_cfqq(cfqd->busy_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)) {
++ } else if (!list_empty(&cfqd->idle_rr)) {
++ /*
++ * 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
++ */
+ unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+
+ if (time_after_eq(jiffies, end))
+@@ -942,16 +768,14 @@ static int cfq_arm_slice_timer(struct cf
+ return 1;
+ }
+
+-static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq)
++static void cfq_dispatch_insert(request_queue_t *q, struct request *rq)
+ {
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+- struct cfq_queue *cfqq = crq->cfq_queue;
+- struct request *rq;
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+
+- cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
+- cfq_remove_request(crq->request);
+- cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
+- elv_dispatch_sort(q, crq->request);
++ cfq_remove_request(rq);
++ cfqq->on_dispatch[rq_is_sync(rq)]++;
++ elv_dispatch_sort(q, rq);
+
+ rq = list_entry(q->queue_head.prev, struct request, queuelist);
+ cfqd->last_sector = rq->sector + rq->nr_sectors;
+@@ -960,24 +784,23 @@ static void cfq_dispatch_insert(request_
+ /*
+ * return expired entry, or NULL to just start from scratch in rbtree
+ */
+-static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
++static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq)
+ {
+ struct cfq_data *cfqd = cfqq->cfqd;
+ struct request *rq;
+- struct cfq_rq *crq;
++ int fifo;
+
+ if (cfq_cfqq_fifo_expire(cfqq))
+ return NULL;
++ if (list_empty(&cfqq->fifo))
++ return NULL;
+
+- if (!list_empty(&cfqq->fifo)) {
+- int fifo = cfq_cfqq_class_sync(cfqq);
++ fifo = cfq_cfqq_class_sync(cfqq);
++ rq = rq_entry_fifo(cfqq->fifo.next);
+
+- 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;
+- }
++ if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
++ cfq_mark_cfqq_fifo_expire(cfqq);
++ return rq;
+ }
+
+ return NULL;
+@@ -1063,25 +886,25 @@ __cfq_dispatch_requests(struct cfq_data
+ BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
+
+ do {
+- struct cfq_rq *crq;
++ struct request *rq;
+
+ /*
+ * follow expired path, else get first next available
+ */
+- if ((crq = cfq_check_fifo(cfqq)) == NULL)
+- crq = cfqq->next_crq;
++ if ((rq = cfq_check_fifo(cfqq)) == NULL)
++ rq = cfqq->next_rq;
+
+ /*
+ * finally, insert request into driver dispatch list
+ */
+- cfq_dispatch_insert(cfqd->queue, crq);
++ cfq_dispatch_insert(cfqd->queue, rq);
+
+ cfqd->dispatch_slice++;
+ dispatched++;
+
+ if (!cfqd->active_cic) {
+- atomic_inc(&crq->io_context->ioc->refcount);
+- cfqd->active_cic = crq->io_context;
++ atomic_inc(&RQ_CIC(rq)->ioc->refcount);
++ cfqd->active_cic = RQ_CIC(rq);
+ }
+
+ if (RB_EMPTY_ROOT(&cfqq->sort_list))
+@@ -1112,13 +935,12 @@ static int
+ cfq_forced_dispatch_cfqqs(struct list_head *list)
+ {
+ struct cfq_queue *cfqq, *next;
+- struct cfq_rq *crq;
+ int dispatched;
+
+ dispatched = 0;
+ list_for_each_entry_safe(cfqq, next, list, cfq_list) {
+- while ((crq = cfqq->next_crq)) {
+- cfq_dispatch_insert(cfqq->cfqd->queue, crq);
++ while (cfqq->next_rq) {
++ cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
+ dispatched++;
+ }
+ BUG_ON(!list_empty(&cfqq->fifo));
+@@ -1194,8 +1016,8 @@ cfq_dispatch_requests(request_queue_t *q
+ }
+
+ /*
+- * task holds one reference to the queue, dropped when task exits. each crq
+- * in-flight on this queue also holds a reference, dropped when crq is freed.
++ * task holds one reference to the queue, dropped when task exits. each rq
++ * in-flight on this queue also holds a reference, dropped when rq is freed.
+ *
+ * queue lock must be held here.
+ */
+@@ -1223,7 +1045,7 @@ static void cfq_put_queue(struct cfq_que
+ kmem_cache_free(cfq_pool, cfqq);
+ }
+
+-static inline struct cfq_queue *
++static struct cfq_queue *
+ __cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
+ const int hashval)
+ {
+@@ -1260,62 +1082,63 @@ static void cfq_free_io_context(struct i
+ freed++;
+ }
+
+- if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone)
++ elv_ioc_count_mod(ioc_count, -freed);
++
++ if (ioc_gone && !elv_ioc_count_read(ioc_count))
+ complete(ioc_gone);
+ }
+
+-static void cfq_trim(struct io_context *ioc)
++static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+ {
+- ioc->set_ioprio = NULL;
+- cfq_free_io_context(ioc);
++ if (unlikely(cfqq == cfqd->active_queue))
++ __cfq_slice_expired(cfqd, cfqq, 0);
++
++ cfq_put_queue(cfqq);
+ }
+
+-/*
+- * Called with interrupts disabled
+- */
+-static void cfq_exit_single_io_context(struct cfq_io_context *cic)
++static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
++ struct cfq_io_context *cic)
+ {
+- struct cfq_data *cfqd = cic->key;
+- request_queue_t *q;
+-
+- if (!cfqd)
+- return;
+-
+- q = cfqd->queue;
+-
+- WARN_ON(!irqs_disabled());
+-
+- spin_lock(q->queue_lock);
++ list_del_init(&cic->queue_list);
++ smp_wmb();
++ cic->key = NULL;
+
+ if (cic->cfqq[ASYNC]) {
+- if (unlikely(cic->cfqq[ASYNC] == cfqd->active_queue))
+- __cfq_slice_expired(cfqd, cic->cfqq[ASYNC], 0);
+- cfq_put_queue(cic->cfqq[ASYNC]);
++ cfq_exit_cfqq(cfqd, cic->cfqq[ASYNC]);
+ cic->cfqq[ASYNC] = NULL;
+ }
+
+ if (cic->cfqq[SYNC]) {
+- if (unlikely(cic->cfqq[SYNC] == cfqd->active_queue))
+- __cfq_slice_expired(cfqd, cic->cfqq[SYNC], 0);
+- cfq_put_queue(cic->cfqq[SYNC]);
++ cfq_exit_cfqq(cfqd, cic->cfqq[SYNC]);
+ cic->cfqq[SYNC] = NULL;
+ }
++}
+
+- cic->key = NULL;
+- list_del_init(&cic->queue_list);
+- spin_unlock(q->queue_lock);
++
++/*
++ * Called with interrupts disabled
++ */
++static void cfq_exit_single_io_context(struct cfq_io_context *cic)
++{
++ struct cfq_data *cfqd = cic->key;
++
++ if (cfqd) {
++ request_queue_t *q = cfqd->queue;
++
++ spin_lock_irq(q->queue_lock);
++ __cfq_exit_single_io_context(cfqd, cic);
++ spin_unlock_irq(q->queue_lock);
++ }
+ }
+
+ static void cfq_exit_io_context(struct io_context *ioc)
+ {
+ struct cfq_io_context *__cic;
+- unsigned long flags;
+ struct rb_node *n;
+
+ /*
+ * put the reference this task is holding to the various queues
+ */
+- spin_lock_irqsave(&cfq_exit_lock, flags);
+
+ n = rb_first(&ioc->cic_root);
+ while (n != NULL) {
+@@ -1324,22 +1147,21 @@ static void cfq_exit_io_context(struct i
+ cfq_exit_single_io_context(__cic);
+ n = rb_next(n);
+ }
+-
+- spin_unlock_irqrestore(&cfq_exit_lock, flags);
+ }
+
+ static struct cfq_io_context *
+ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+ {
+- struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
++ struct cfq_io_context *cic;
+
++ cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask, cfqd->queue->node);
+ if (cic) {
+ memset(cic, 0, sizeof(*cic));
+ cic->last_end_request = jiffies;
+ INIT_LIST_HEAD(&cic->queue_list);
+ cic->dtor = cfq_free_io_context;
+ cic->exit = cfq_exit_io_context;
+- atomic_inc(&ioc_count);
++ elv_ioc_count_inc(ioc_count);
+ }
+
+ return cic;
+@@ -1396,11 +1218,12 @@ static inline void changed_ioprio(struct
+ {
+ struct cfq_data *cfqd = cic->key;
+ struct cfq_queue *cfqq;
++ unsigned long flags;
+
+ if (unlikely(!cfqd))
+ return;
+
+- spin_lock(cfqd->queue->queue_lock);
++ spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+ cfqq = cic->cfqq[ASYNC];
+ if (cfqq) {
+@@ -1417,18 +1240,15 @@ static inline void changed_ioprio(struct
+ if (cfqq)
+ cfq_mark_cfqq_prio_changed(cfqq);
+
+- spin_unlock(cfqd->queue->queue_lock);
++ spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+ }
+
+-/*
+- * callback from sys_ioprio_set, irqs are disabled
+- */
+-static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
++static void cfq_ioc_set_ioprio(struct io_context *ioc)
+ {
+ struct cfq_io_context *cic;
+ struct rb_node *n;
+
+- spin_lock(&cfq_exit_lock);
++ ioc->ioprio_changed = 0;
+
+ n = rb_first(&ioc->cic_root);
+ while (n != NULL) {
+@@ -1437,10 +1257,6 @@ static int cfq_ioc_set_ioprio(struct io_
+ changed_ioprio(cic);
+ n = rb_next(n);
+ }
+-
+- spin_unlock(&cfq_exit_lock);
+-
+- return 0;
+ }
+
+ static struct cfq_queue *
+@@ -1460,12 +1276,18 @@ retry:
+ cfqq = new_cfqq;
+ new_cfqq = NULL;
+ } else if (gfp_mask & __GFP_WAIT) {
++ /*
++ * Inform the allocator of the fact that we will
++ * just repeat this allocation if it fails, to allow
++ * the allocator to do whatever it needs to attempt to
++ * free memory.
++ */
+ spin_unlock_irq(cfqd->queue->queue_lock);
+- new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
++ new_cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask|__GFP_NOFAIL, cfqd->queue->node);
+ spin_lock_irq(cfqd->queue->queue_lock);
+ goto retry;
+ } else {
+- cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
++ cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask, cfqd->queue->node);
+ if (!cfqq)
+ goto out;
+ }
+@@ -1480,13 +1302,13 @@ retry:
+ hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
+ atomic_set(&cfqq->ref, 0);
+ cfqq->cfqd = cfqd;
+- 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_mark_cfqq_queue_new(cfqq);
+ cfq_init_prio_data(cfqq);
+ }
+
+@@ -1502,12 +1324,10 @@ out:
+ static void
+ cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
+ {
+- spin_lock(&cfq_exit_lock);
++ WARN_ON(!list_empty(&cic->queue_list));
+ rb_erase(&cic->rb_node, &ioc->cic_root);
+- list_del_init(&cic->queue_list);
+- spin_unlock(&cfq_exit_lock);
+ kmem_cache_free(cfq_ioc_pool, cic);
+- atomic_dec(&ioc_count);
++ elv_ioc_count_dec(ioc_count);
+ }
+
+ static struct cfq_io_context *
+@@ -1546,12 +1366,12 @@ cfq_cic_link(struct cfq_data *cfqd, stru
+ struct rb_node **p;
+ struct rb_node *parent;
+ struct cfq_io_context *__cic;
++ unsigned long flags;
+ void *k;
+
+ cic->ioc = ioc;
+ cic->key = cfqd;
+
+- ioc->set_ioprio = cfq_ioc_set_ioprio;
+ restart:
+ parent = NULL;
+ p = &ioc->cic_root.rb_node;
+@@ -1573,11 +1393,12 @@ restart:
+ BUG();
+ }
+
+- spin_lock(&cfq_exit_lock);
+ rb_link_node(&cic->rb_node, parent, p);
+ rb_insert_color(&cic->rb_node, &ioc->cic_root);
++
++ spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+ list_add(&cic->queue_list, &cfqd->cic_list);
+- spin_unlock(&cfq_exit_lock);
++ spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+ }
+
+ /*
+@@ -1593,7 +1414,7 @@ cfq_get_io_context(struct cfq_data *cfqd
+
+ might_sleep_if(gfp_mask & __GFP_WAIT);
+
+- ioc = get_io_context(gfp_mask);
++ ioc = get_io_context(gfp_mask, cfqd->queue->node);
+ if (!ioc)
+ return NULL;
+
+@@ -1607,6 +1428,10 @@ cfq_get_io_context(struct cfq_data *cfqd
+
+ cfq_cic_link(cfqd, ioc, cic);
+ out:
++ smp_read_barrier_depends();
++ if (unlikely(ioc->ioprio_changed))
++ cfq_ioc_set_ioprio(ioc);
++
+ return cic;
+ err:
+ put_io_context(ioc);
+@@ -1640,15 +1465,15 @@ cfq_update_io_thinktime(struct cfq_data
+
+ static void
+ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+- struct cfq_rq *crq)
++ struct request *rq)
+ {
+ sector_t sdist;
+ u64 total;
+
+- if (cic->last_request_pos < crq->request->sector)
+- sdist = crq->request->sector - cic->last_request_pos;
++ if (cic->last_request_pos < rq->sector)
++ sdist = rq->sector - cic->last_request_pos;
+ else
+- sdist = cic->last_request_pos - crq->request->sector;
++ sdist = cic->last_request_pos - rq->sector;
+
+ /*
+ * Don't allow the seek distance to get too large from the
+@@ -1699,7 +1524,7 @@ cfq_update_idle_window(struct cfq_data *
+ */
+ static int
+ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
+- struct cfq_rq *crq)
++ struct request *rq)
+ {
+ struct cfq_queue *cfqq = cfqd->active_queue;
+
+@@ -1718,7 +1543,17 @@ cfq_should_preempt(struct cfq_data *cfqd
+ */
+ if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
+ return 0;
+- if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
++ /*
++ * if the new request is sync, but the currently running queue is
++ * not, let the sync request have priority.
++ */
++ if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
++ return 1;
++ /*
++ * So both queues are sync. Let the new request get disk time if
++ * it's a metadata request and the current queue is doing regular IO.
++ */
++ if (rq_is_meta(rq) && !cfqq->meta_pending)
+ return 1;
+
+ return 0;
+@@ -1730,47 +1565,45 @@ cfq_should_preempt(struct cfq_data *cfqd
+ */
+ 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);
++ cfq_slice_expired(cfqd, 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, 1);
+- __cfq_set_active_queue(cfqd, cfqq);
+-}
+-
+-/*
+- * 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;
++ /*
++ * Put the new queue at the front of the of the current list,
++ * so we know that it will be selected next.
++ */
++ BUG_ON(!cfq_cfqq_on_rr(cfqq));
++ list_move(&cfqq->cfq_list, &cfqd->cur_rr);
+
+- if (!blk_queue_plugged(q))
+- q->request_fn(q);
+- else
+- __generic_unplug_device(q);
++ cfqq->slice_end = cfqq->slice_left + jiffies;
+ }
+
+ /*
+- * Called when a new fs request (crq) is added (to cfqq). Check if there's
++ * Called when a new fs request (rq) 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)
++cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
++ struct request *rq)
+ {
+- struct cfq_io_context *cic = crq->io_context;
++ struct cfq_io_context *cic = RQ_CIC(rq);
++
++ if (rq_is_meta(rq))
++ cfqq->meta_pending++;
++
++ /*
++ * check if this request is a better next-serve candidate)) {
++ */
++ cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq);
++ BUG_ON(!cfqq->next_rq);
+
+ /*
+ * we never wait for an async request and we don't allow preemption
+ * of an async request. so just return early
+ */
+- if (!cfq_crq_is_sync(crq)) {
++ if (!rq_is_sync(rq)) {
+ /*
+ * sync process issued an async request, if it's waiting
+ * then expire it and kick rq handling.
+@@ -1778,17 +1611,17 @@ cfq_crq_enqueued(struct cfq_data *cfqd,
+ if (cic == cfqd->active_cic &&
+ del_timer(&cfqd->idle_slice_timer)) {
+ cfq_slice_expired(cfqd, 0);
+- cfq_start_queueing(cfqd, cfqq);
++ blk_start_queueing(cfqd->queue);
+ }
+ return;
+ }
+
+ cfq_update_io_thinktime(cfqd, cic);
+- cfq_update_io_seektime(cfqd, cic, crq);
++ cfq_update_io_seektime(cfqd, cic, rq);
+ cfq_update_idle_window(cfqd, cfqq, cic);
+
+ cic->last_queue = jiffies;
+- cic->last_request_pos = crq->request->sector + crq->request->nr_sectors;
++ cic->last_request_pos = rq->sector + rq->nr_sectors;
+
+ if (cfqq == cfqd->active_queue) {
+ /*
+@@ -1799,9 +1632,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd,
+ if (cfq_cfqq_wait_request(cfqq)) {
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ del_timer(&cfqd->idle_slice_timer);
+- cfq_start_queueing(cfqd, cfqq);
++ blk_start_queueing(cfqd->queue);
+ }
+- } else if (cfq_should_preempt(cfqd, cfqq, crq)) {
++ } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
+ /*
+ * not the active queue - expire current slice if it is
+ * idle and has expired it's mean thinktime or this new queue
+@@ -1809,34 +1642,29 @@ cfq_crq_enqueued(struct cfq_data *cfqd,
+ */
+ cfq_preempt_queue(cfqd, cfqq);
+ cfq_mark_cfqq_must_dispatch(cfqq);
+- cfq_start_queueing(cfqd, cfqq);
++ blk_start_queueing(cfqd->queue);
+ }
+ }
+
+ static void cfq_insert_request(request_queue_t *q, struct request *rq)
+ {
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+- struct cfq_rq *crq = RQ_DATA(rq);
+- struct cfq_queue *cfqq = crq->cfq_queue;
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+
+ cfq_init_prio_data(cfqq);
+
+- cfq_add_crq_rb(crq);
++ cfq_add_rq_rb(rq);
+
+ list_add_tail(&rq->queuelist, &cfqq->fifo);
+
+- if (rq_mergeable(rq))
+- cfq_add_crq_hash(cfqd, crq);
+-
+- cfq_crq_enqueued(cfqd, cfqq, crq);
++ cfq_rq_enqueued(cfqd, cfqq, rq);
+ }
+
+ static void cfq_completed_request(request_queue_t *q, struct request *rq)
+ {
+- struct cfq_rq *crq = RQ_DATA(rq);
+- struct cfq_queue *cfqq = crq->cfq_queue;
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+ struct cfq_data *cfqd = cfqq->cfqd;
+- const int sync = cfq_crq_is_sync(crq);
++ const int sync = rq_is_sync(rq);
+ unsigned long now;
+
+ now = jiffies;
+@@ -1849,15 +1677,11 @@ static void cfq_completed_request(reques
+ if (!cfq_class_idle(cfqq))
+ cfqd->last_end_request = now;
+
+- if (!cfq_cfqq_dispatched(cfqq)) {
+- if (cfq_cfqq_on_rr(cfqq)) {
+- cfqq->service_last = now;
+- cfq_resort_rr_list(cfqq, 0);
+- }
+- }
++ if (!cfq_cfqq_dispatched(cfqq) && cfq_cfqq_on_rr(cfqq))
++ cfq_resort_rr_list(cfqq, 0);
+
+ if (sync)
+- crq->io_context->last_end_request = now;
++ RQ_CIC(rq)->last_end_request = now;
+
+ /*
+ * If this is the active queue, check if it needs to be expired,
+@@ -1873,30 +1697,6 @@ static void cfq_completed_request(reques
+ }
+ }
+
+-static struct request *
+-cfq_former_request(request_queue_t *q, struct request *rq)
+-{
+- struct cfq_rq *crq = RQ_DATA(rq);
+- struct rb_node *rbprev = rb_prev(&crq->rb_node);
+-
+- if (rbprev)
+- return rb_entry_crq(rbprev)->request;
+-
+- return NULL;
+-}
+-
+-static struct request *
+-cfq_latter_request(request_queue_t *q, struct request *rq)
+-{
+- struct cfq_rq *crq = RQ_DATA(rq);
+- struct rb_node *rbnext = rb_next(&crq->rb_node);
+-
+- if (rbnext)
+- return rb_entry_crq(rbnext)->request;
+-
+- return NULL;
+-}
+-
+ /*
+ * we temporarily boost lower priority queues if they are holding fs exclusive
+ * resources. they are boosted to normal prio (CLASS_BE/4)
+@@ -1933,9 +1733,7 @@ static void cfq_prio_boost(struct cfq_qu
+ cfq_resort_rr_list(cfqq, 0);
+ }
+
+-static inline int
+-__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+- struct task_struct *task, int rw)
++static inline int __cfq_may_queue(struct cfq_queue *cfqq)
+ {
+ if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
+ !cfq_cfqq_must_alloc_slice(cfqq)) {
+@@ -1946,7 +1744,7 @@ __cfq_may_queue(struct cfq_data *cfqd, s
+ return ELV_MQUEUE_MAY;
+ }
+
+-static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
++static int cfq_may_queue(request_queue_t *q, int rw)
+ {
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct task_struct *tsk = current;
+@@ -1963,48 +1761,30 @@ static int cfq_may_queue(request_queue_t
+ cfq_init_prio_data(cfqq);
+ cfq_prio_boost(cfqq);
+
+- return __cfq_may_queue(cfqd, cfqq, tsk, rw);
++ return __cfq_may_queue(cfqq);
+ }
+
+ 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;
+-
+- if (unlikely(cfqd->rq_starved)) {
+- struct request_list *rl = &q->rq;
+-
+- smp_mb();
+- if (waitqueue_active(&rl->wait[READ]))
+- wake_up(&rl->wait[READ]);
+- if (waitqueue_active(&rl->wait[WRITE]))
+- wake_up(&rl->wait[WRITE]);
+- }
+-}
+-
+ /*
+ * queue lock held here
+ */
+ static void cfq_put_request(request_queue_t *q, struct request *rq)
+ {
+- struct cfq_data *cfqd = q->elevator->elevator_data;
+- struct cfq_rq *crq = RQ_DATA(rq);
++ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+
+- if (crq) {
+- struct cfq_queue *cfqq = crq->cfq_queue;
++ if (cfqq) {
+ const int rw = rq_data_dir(rq);
+
+ BUG_ON(!cfqq->allocated[rw]);
+ cfqq->allocated[rw]--;
+
+- put_io_context(crq->io_context->ioc);
++ put_io_context(RQ_CIC(rq)->ioc);
+
+- mempool_free(crq, cfqd->crq_pool);
+ rq->elevator_private = NULL;
++ rq->elevator_private2 = NULL;
+
+- cfq_check_waiters(q, cfqq);
+ cfq_put_queue(cfqq);
+ }
+ }
+@@ -2013,8 +1793,7 @@ static void cfq_put_request(request_queu
+ * Allocate cfq data structures associated with this request.
+ */
+ static int
+-cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+- gfp_t gfp_mask)
++cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
+ {
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct task_struct *tsk = current;
+@@ -2022,7 +1801,6 @@ cfq_set_request(request_queue_t *q, stru
+ const int rw = rq_data_dir(rq);
+ pid_t key = cfq_queue_pid(tsk, rw);
+ struct cfq_queue *cfqq;
+- struct cfq_rq *crq;
+ unsigned long flags;
+ int is_sync = key != CFQ_KEY_ASYNC;
+
+@@ -2046,42 +1824,18 @@ cfq_set_request(request_queue_t *q, stru
+
+ cfqq->allocated[rw]++;
+ cfq_clear_cfqq_must_alloc(cfqq);
+- cfqd->rq_starved = 0;
+ atomic_inc(&cfqq->ref);
+- spin_unlock_irqrestore(q->queue_lock, flags);
+
+- crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
+- if (crq) {
+- RB_CLEAR_NODE(&crq->rb_node);
+- crq->rb_key = 0;
+- crq->request = rq;
+- INIT_HLIST_NODE(&crq->hash);
+- crq->cfq_queue = cfqq;
+- crq->io_context = cic;
+-
+- if (is_sync)
+- cfq_mark_crq_is_sync(crq);
+- else
+- cfq_clear_crq_is_sync(crq);
++ spin_unlock_irqrestore(q->queue_lock, flags);
+
+- rq->elevator_private = crq;
+- return 0;
+- }
++ rq->elevator_private = cic;
++ rq->elevator_private2 = cfqq;
++ return 0;
+
+- 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);
+ 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;
+@@ -2090,27 +1844,10 @@ queue_fail:
+ 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);
++ blk_start_queueing(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+
+@@ -2193,7 +1930,6 @@ static void cfq_exit_queue(elevator_t *e
+
+ cfq_shutdown_timer_wq(cfqd);
+
+- spin_lock(&cfq_exit_lock);
+ spin_lock_irq(q->queue_lock);
+
+ if (cfqd->active_queue)
+@@ -2203,25 +1939,14 @@ static void cfq_exit_queue(elevator_t *e
+ struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
+ struct cfq_io_context,
+ queue_list);
+- if (cic->cfqq[ASYNC]) {
+- cfq_put_queue(cic->cfqq[ASYNC]);
+- cic->cfqq[ASYNC] = NULL;
+- }
+- if (cic->cfqq[SYNC]) {
+- cfq_put_queue(cic->cfqq[SYNC]);
+- cic->cfqq[SYNC] = NULL;
+- }
+- cic->key = NULL;
+- list_del_init(&cic->queue_list);
++
++ __cfq_exit_single_io_context(cfqd, cic);
+ }
+
+ spin_unlock_irq(q->queue_lock);
+- spin_unlock(&cfq_exit_lock);
+
+ cfq_shutdown_timer_wq(cfqd);
+
+- mempool_destroy(cfqd->crq_pool);
+- kfree(cfqd->crq_hash);
+ kfree(cfqd->cfq_hash);
+ kfree(cfqd);
+ }
+@@ -2231,7 +1956,7 @@ static void *cfq_init_queue(request_queu
+ struct cfq_data *cfqd;
+ int i;
+
+- cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL);
++ cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
+ if (!cfqd)
+ return NULL;
+
+@@ -2243,23 +1968,12 @@ static void *cfq_init_queue(request_queu
+ INIT_LIST_HEAD(&cfqd->busy_rr);
+ INIT_LIST_HEAD(&cfqd->cur_rr);
+ INIT_LIST_HEAD(&cfqd->idle_rr);
+- INIT_LIST_HEAD(&cfqd->empty_list);
+ INIT_LIST_HEAD(&cfqd->cic_list);
+
+- cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
+- if (!cfqd->crq_hash)
+- goto out_crqhash;
+-
+- cfqd->cfq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL);
++ cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
+ if (!cfqd->cfq_hash)
+- goto out_cfqhash;
+-
+- cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool);
+- if (!cfqd->crq_pool)
+- goto out_crqpool;
++ goto out_free;
+
+- for (i = 0; i < CFQ_MHASH_ENTRIES; i++)
+- INIT_HLIST_HEAD(&cfqd->crq_hash[i]);
+ for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
+ INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
+
+@@ -2275,7 +1989,6 @@ static void *cfq_init_queue(request_queu
+
+ INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
+
+- cfqd->cfq_queued = cfq_queued;
+ cfqd->cfq_quantum = cfq_quantum;
+ cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
+ cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
+@@ -2287,19 +2000,13 @@ static void *cfq_init_queue(request_queu
+ cfqd->cfq_slice_idle = cfq_slice_idle;
+
+ return cfqd;
+-out_crqpool:
+- kfree(cfqd->cfq_hash);
+-out_cfqhash:
+- kfree(cfqd->crq_hash);
+-out_crqhash:
++out_free:
+ kfree(cfqd);
+ return NULL;
+ }
+
+ static void cfq_slab_kill(void)
+ {
+- if (crq_pool)
+- kmem_cache_destroy(crq_pool);
+ if (cfq_pool)
+ kmem_cache_destroy(cfq_pool);
+ if (cfq_ioc_pool)
+@@ -2308,11 +2015,6 @@ static void cfq_slab_kill(void)
+
+ static int __init cfq_slab_setup(void)
+ {
+- crq_pool = kmem_cache_create("crq_pool", sizeof(struct cfq_rq), 0, 0,
+- NULL, NULL);
+- if (!crq_pool)
+- goto fail;
+-
+ cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
+ NULL, NULL);
+ if (!cfq_pool)
+@@ -2358,7 +2060,6 @@ static ssize_t __FUNC(elevator_t *e, cha
+ return cfq_var_show(__data, (page)); \
+ }
+ SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0);
+-SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 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_seek_max_show, cfqd->cfq_back_max, 0);
+@@ -2386,7 +2087,6 @@ static ssize_t __FUNC(elevator_t *e, con
+ return ret; \
+ }
+ 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_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_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
+@@ -2402,7 +2102,6 @@ STORE_FUNCTION(cfq_slice_async_rq_store,
+
+ static struct elv_fs_entry cfq_attrs[] = {
+ CFQ_ATTR(quantum),
+- CFQ_ATTR(queued),
+ CFQ_ATTR(fifo_expire_sync),
+ CFQ_ATTR(fifo_expire_async),
+ CFQ_ATTR(back_seek_max),
+@@ -2425,14 +2124,14 @@ static struct elevator_type iosched_cfq
+ .elevator_deactivate_req_fn = cfq_deactivate_request,
+ .elevator_queue_empty_fn = cfq_queue_empty,
+ .elevator_completed_req_fn = cfq_completed_request,
+- .elevator_former_req_fn = cfq_former_request,
+- .elevator_latter_req_fn = cfq_latter_request,
++ .elevator_former_req_fn = elv_rb_former_request,
++ .elevator_latter_req_fn = elv_rb_latter_request,
+ .elevator_set_req_fn = cfq_set_request,
+ .elevator_put_req_fn = cfq_put_request,
+ .elevator_may_queue_fn = cfq_may_queue,
+ .elevator_init_fn = cfq_init_queue,
+ .elevator_exit_fn = cfq_exit_queue,
+- .trim = cfq_trim,
++ .trim = cfq_free_io_context,
+ },
+ .elevator_attrs = cfq_attrs,
+ .elevator_name = "cfq",
+@@ -2463,12 +2162,12 @@ static int __init cfq_init(void)
+
+ static void __exit cfq_exit(void)
+ {
+- DECLARE_COMPLETION(all_gone);
++ DECLARE_COMPLETION_ONSTACK(all_gone);
+ elv_unregister(&iosched_cfq);
+ ioc_gone = &all_gone;
+ /* ioc_gone's update must be visible before reading ioc_count */
+ smp_wmb();
+- if (atomic_read(&ioc_count))
++ if (elv_ioc_count_read(ioc_count))
+ wait_for_completion(ioc_gone);
+ synchronize_rcu();
+ cfq_slab_kill();
+diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
+index c7ca9f0..b7c5b34 100644
+--- a/block/deadline-iosched.c
++++ b/block/deadline-iosched.c
+@@ -1,7 +1,7 @@
+ /*
+ * Deadline i/o scheduler.
+ *
+- * Copyright (C) 2002 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2002 Jens Axboe <axboe at kernel.dk>
+ */
+ #include <linux/kernel.h>
+ #include <linux/fs.h>
+@@ -12,7 +12,6 @@
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/compiler.h>
+-#include <linux/hash.h>
+ #include <linux/rbtree.h>
+
+ /*
+@@ -24,13 +23,6 @@ static const int writes_starved = 2;
+ static const int fifo_batch = 16; /* # of sequential requests treated as one
+ by the above parameters. For throughput. */
+
+-static const int deadline_hash_shift = 5;
+-#define DL_HASH_BLOCK(sec) ((sec) >> 3)
+-#define DL_HASH_FN(sec) (hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift))
+-#define DL_HASH_ENTRIES (1 << deadline_hash_shift)
+-#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
+-#define ON_HASH(drq) (!hlist_unhashed(&(drq)->hash))
+-
+ struct deadline_data {
+ /*
+ * run time data
+@@ -45,8 +37,7 @@ struct deadline_data {
+ /*
+ * next in sort order. read, write or both are NULL
+ */
+- struct deadline_rq *next_drq[2];
+- struct hlist_head *hash; /* request hash */
++ struct request *next_rq[2];
+ unsigned int batching; /* number of sequential requests made */
+ sector_t last_sector; /* head position */
+ unsigned int starved; /* times reads have starved writes */
+@@ -58,240 +49,69 @@ struct deadline_data {
+ int fifo_batch;
+ int writes_starved;
+ int front_merges;
+-
+- mempool_t *drq_pool;
+ };
+
+-/*
+- * pre-request data.
+- */
+-struct deadline_rq {
+- /*
+- * rbtree index, key is the starting offset
+- */
+- struct rb_node rb_node;
+- sector_t rb_key;
+-
+- struct request *request;
+-
+- /*
+- * request hash, key is the ending offset (for back merge lookup)
+- */
+- struct hlist_node hash;
+-
+- /*
+- * expire fifo
+- */
+- struct list_head fifo;
+- unsigned long expires;
+-};
+-
+-static void deadline_move_request(struct deadline_data *dd, struct deadline_rq *drq);
+-
+-static kmem_cache_t *drq_pool;
+-
+-#define RQ_DATA(rq) ((struct deadline_rq *) (rq)->elevator_private)
++static void deadline_move_request(struct deadline_data *, struct request *);
+
+-/*
+- * the back merge hash support functions
+- */
+-static inline void __deadline_del_drq_hash(struct deadline_rq *drq)
+-{
+- hlist_del_init(&drq->hash);
+-}
+-
+-static inline void deadline_del_drq_hash(struct deadline_rq *drq)
+-{
+- if (ON_HASH(drq))
+- __deadline_del_drq_hash(drq);
+-}
+-
+-static inline void
+-deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
+-{
+- struct request *rq = drq->request;
+-
+- BUG_ON(ON_HASH(drq));
+-
+- hlist_add_head(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]);
+-}
+-
+-/*
+- * move hot entry to front of chain
+- */
+-static inline void
+-deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
+-{
+- struct request *rq = drq->request;
+- struct hlist_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))];
+-
+- if (ON_HASH(drq) && &drq->hash != head->first) {
+- hlist_del(&drq->hash);
+- hlist_add_head(&drq->hash, head);
+- }
+-}
+-
+-static struct request *
+-deadline_find_drq_hash(struct deadline_data *dd, sector_t offset)
+-{
+- struct hlist_head *hash_list = &dd->hash[DL_HASH_FN(offset)];
+- struct hlist_node *entry, *next;
+- struct deadline_rq *drq;
+-
+- hlist_for_each_entry_safe(drq, entry, next, hash_list, hash) {
+- struct request *__rq = drq->request;
+-
+- BUG_ON(!ON_HASH(drq));
+-
+- if (!rq_mergeable(__rq)) {
+- __deadline_del_drq_hash(drq);
+- continue;
+- }
+-
+- if (rq_hash_key(__rq) == offset)
+- return __rq;
+- }
+-
+- return NULL;
+-}
+-
+-/*
+- * rb tree support functions
+- */
+-#define rb_entry_drq(node) rb_entry((node), struct deadline_rq, rb_node)
+-#define DRQ_RB_ROOT(dd, drq) (&(dd)->sort_list[rq_data_dir((drq)->request)])
+-#define rq_rb_key(rq) (rq)->sector
+-
+-static struct deadline_rq *
+-__deadline_add_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
+-{
+- struct rb_node **p = &DRQ_RB_ROOT(dd, drq)->rb_node;
+- struct rb_node *parent = NULL;
+- struct deadline_rq *__drq;
+-
+- while (*p) {
+- parent = *p;
+- __drq = rb_entry_drq(parent);
+-
+- if (drq->rb_key < __drq->rb_key)
+- p = &(*p)->rb_left;
+- else if (drq->rb_key > __drq->rb_key)
+- p = &(*p)->rb_right;
+- else
+- return __drq;
+- }
+-
+- rb_link_node(&drq->rb_node, parent, p);
+- return NULL;
+-}
++#define RQ_RB_ROOT(dd, rq) (&(dd)->sort_list[rq_data_dir((rq))])
+
+ static void
+-deadline_add_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
++deadline_add_rq_rb(struct deadline_data *dd, struct request *rq)
+ {
+- struct deadline_rq *__alias;
+-
+- drq->rb_key = rq_rb_key(drq->request);
++ struct rb_root *root = RQ_RB_ROOT(dd, rq);
++ struct request *__alias;
+
+ retry:
+- __alias = __deadline_add_drq_rb(dd, drq);
+- if (!__alias) {
+- rb_insert_color(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
+- return;
++ __alias = elv_rb_add(root, rq);
++ if (unlikely(__alias)) {
++ deadline_move_request(dd, __alias);
++ goto retry;
+ }
+-
+- deadline_move_request(dd, __alias);
+- goto retry;
+ }
+
+ static inline void
+-deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
++deadline_del_rq_rb(struct deadline_data *dd, struct request *rq)
+ {
+- const int data_dir = rq_data_dir(drq->request);
++ const int data_dir = rq_data_dir(rq);
+
+- if (dd->next_drq[data_dir] == drq) {
+- struct rb_node *rbnext = rb_next(&drq->rb_node);
++ if (dd->next_rq[data_dir] == rq) {
++ struct rb_node *rbnext = rb_next(&rq->rb_node);
+
+- dd->next_drq[data_dir] = NULL;
++ dd->next_rq[data_dir] = NULL;
+ if (rbnext)
+- dd->next_drq[data_dir] = rb_entry_drq(rbnext);
+- }
+-
+- BUG_ON(!RB_EMPTY_NODE(&drq->rb_node));
+- rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
+- RB_CLEAR_NODE(&drq->rb_node);
+-}
+-
+-static struct request *
+-deadline_find_drq_rb(struct deadline_data *dd, sector_t sector, int data_dir)
+-{
+- struct rb_node *n = dd->sort_list[data_dir].rb_node;
+- struct deadline_rq *drq;
+-
+- while (n) {
+- drq = rb_entry_drq(n);
+-
+- if (sector < drq->rb_key)
+- n = n->rb_left;
+- else if (sector > drq->rb_key)
+- n = n->rb_right;
+- else
+- return drq->request;
++ dd->next_rq[data_dir] = rb_entry_rq(rbnext);
+ }
+
+- return NULL;
++ elv_rb_del(RQ_RB_ROOT(dd, rq), rq);
+ }
+
+ /*
+- * deadline_find_first_drq finds the first (lowest sector numbered) request
+- * for the specified data_dir. Used to sweep back to the start of the disk
+- * (1-way elevator) after we process the last (highest sector) request.
+- */
+-static struct deadline_rq *
+-deadline_find_first_drq(struct deadline_data *dd, int data_dir)
+-{
+- struct rb_node *n = dd->sort_list[data_dir].rb_node;
+-
+- for (;;) {
+- if (n->rb_left == NULL)
+- return rb_entry_drq(n);
+-
+- n = n->rb_left;
+- }
+-}
+-
+-/*
+- * add drq to rbtree and fifo
++ * add rq to rbtree and fifo
+ */
+ static void
+ deadline_add_request(struct request_queue *q, struct request *rq)
+ {
+ struct deadline_data *dd = q->elevator->elevator_data;
+- struct deadline_rq *drq = RQ_DATA(rq);
++ const int data_dir = rq_data_dir(rq);
+
+- const int data_dir = rq_data_dir(drq->request);
++ deadline_add_rq_rb(dd, rq);
+
+- deadline_add_drq_rb(dd, drq);
+ /*
+ * set expire time (only used for reads) and add to fifo list
+ */
+- drq->expires = jiffies + dd->fifo_expire[data_dir];
+- list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]);
+-
+- if (rq_mergeable(rq))
+- deadline_add_drq_hash(dd, drq);
++ rq_set_fifo_time(rq, jiffies + dd->fifo_expire[data_dir]);
++ list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]);
+ }
+
+ /*
+- * remove rq from rbtree, fifo, and hash
++ * remove rq from rbtree and fifo.
+ */
+ static void deadline_remove_request(request_queue_t *q, struct request *rq)
+ {
+- struct deadline_rq *drq = RQ_DATA(rq);
+ struct deadline_data *dd = q->elevator->elevator_data;
+
+- list_del_init(&drq->fifo);
+- deadline_del_drq_rb(dd, drq);
+- deadline_del_drq_hash(drq);
++ rq_fifo_clear(rq);
++ deadline_del_rq_rb(dd, rq);
+ }
+
+ static int
+@@ -302,27 +122,14 @@ deadline_merge(request_queue_t *q, struc
+ int ret;
+
+ /*
+- * see if the merge hash can satisfy a back merge
+- */
+- __rq = deadline_find_drq_hash(dd, 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;
+- }
+- }
+-
+- /*
+ * check for front merge
+ */
+ if (dd->front_merges) {
+- sector_t rb_key = bio->bi_sector + bio_sectors(bio);
++ sector_t sector = bio->bi_sector + bio_sectors(bio);
+
+- __rq = deadline_find_drq_rb(dd, rb_key, bio_data_dir(bio));
++ __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector);
+ if (__rq) {
+- BUG_ON(rb_key != rq_rb_key(__rq));
++ BUG_ON(sector != __rq->sector);
+
+ if (elv_rq_merge_ok(__rq, bio)) {
+ ret = ELEVATOR_FRONT_MERGE;
+@@ -333,29 +140,21 @@ deadline_merge(request_queue_t *q, struc
+
+ return ELEVATOR_NO_MERGE;
+ out:
+- if (ret)
+- deadline_hot_drq_hash(dd, RQ_DATA(__rq));
+ *req = __rq;
+ return ret;
+ }
+
+-static void deadline_merged_request(request_queue_t *q, struct request *req)
++static void deadline_merged_request(request_queue_t *q, struct request *req,
++ int type)
+ {
+ struct deadline_data *dd = q->elevator->elevator_data;
+- struct deadline_rq *drq = RQ_DATA(req);
+-
+- /*
+- * hash always needs to be repositioned, key is end sector
+- */
+- deadline_del_drq_hash(drq);
+- deadline_add_drq_hash(dd, drq);
+
+ /*
+ * if the merge was a front merge, we need to reposition request
+ */
+- if (rq_rb_key(req) != drq->rb_key) {
+- deadline_del_drq_rb(dd, drq);
+- deadline_add_drq_rb(dd, drq);
++ if (type == ELEVATOR_FRONT_MERGE) {
++ elv_rb_del(RQ_RB_ROOT(dd, req), req);
++ deadline_add_rq_rb(dd, req);
+ }
+ }
+
+@@ -363,33 +162,14 @@ static void
+ deadline_merged_requests(request_queue_t *q, struct request *req,
+ struct request *next)
+ {
+- struct deadline_data *dd = q->elevator->elevator_data;
+- struct deadline_rq *drq = RQ_DATA(req);
+- struct deadline_rq *dnext = RQ_DATA(next);
+-
+- BUG_ON(!drq);
+- BUG_ON(!dnext);
+-
+ /*
+- * reposition drq (this is the merged request) in hash, and in rbtree
+- * in case of a front merge
++ * if next expires before rq, assign its expire time to rq
++ * and move into next position (next will be deleted) in fifo
+ */
+- deadline_del_drq_hash(drq);
+- deadline_add_drq_hash(dd, drq);
+-
+- if (rq_rb_key(req) != drq->rb_key) {
+- deadline_del_drq_rb(dd, drq);
+- deadline_add_drq_rb(dd, drq);
+- }
+-
+- /*
+- * if dnext expires before drq, assign its expire time to drq
+- * and move into dnext position (dnext will be deleted) in fifo
+- */
+- if (!list_empty(&drq->fifo) && !list_empty(&dnext->fifo)) {
+- if (time_before(dnext->expires, drq->expires)) {
+- list_move(&drq->fifo, &dnext->fifo);
+- drq->expires = dnext->expires;
++ if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
++ if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
++ list_move(&req->queuelist, &next->queuelist);
++ rq_set_fifo_time(req, rq_fifo_time(next));
+ }
+ }
+
+@@ -403,52 +183,50 @@ deadline_merged_requests(request_queue_t
+ * move request from sort list to dispatch queue.
+ */
+ static inline void
+-deadline_move_to_dispatch(struct deadline_data *dd, struct deadline_rq *drq)
++deadline_move_to_dispatch(struct deadline_data *dd, struct request *rq)
+ {
+- request_queue_t *q = drq->request->q;
++ request_queue_t *q = rq->q;
+
+- deadline_remove_request(q, drq->request);
+- elv_dispatch_add_tail(q, drq->request);
++ deadline_remove_request(q, rq);
++ elv_dispatch_add_tail(q, rq);
+ }
+
+ /*
+ * move an entry to dispatch queue
+ */
+ static void
+-deadline_move_request(struct deadline_data *dd, struct deadline_rq *drq)
++deadline_move_request(struct deadline_data *dd, struct request *rq)
+ {
+- const int data_dir = rq_data_dir(drq->request);
+- struct rb_node *rbnext = rb_next(&drq->rb_node);
++ const int data_dir = rq_data_dir(rq);
++ struct rb_node *rbnext = rb_next(&rq->rb_node);
+
+- dd->next_drq[READ] = NULL;
+- dd->next_drq[WRITE] = NULL;
++ dd->next_rq[READ] = NULL;
++ dd->next_rq[WRITE] = NULL;
+
+ if (rbnext)
+- dd->next_drq[data_dir] = rb_entry_drq(rbnext);
++ dd->next_rq[data_dir] = rb_entry_rq(rbnext);
+
+- dd->last_sector = drq->request->sector + drq->request->nr_sectors;
++ dd->last_sector = rq->sector + rq->nr_sectors;
+
+ /*
+ * take it off the sort and fifo list, move
+ * to dispatch queue
+ */
+- deadline_move_to_dispatch(dd, drq);
++ deadline_move_to_dispatch(dd, rq);
+ }
+
+-#define list_entry_fifo(ptr) list_entry((ptr), struct deadline_rq, fifo)
+-
+ /*
+ * deadline_check_fifo returns 0 if there are no expired reads on the fifo,
+ * 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir])
+ */
+ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
+ {
+- struct deadline_rq *drq = list_entry_fifo(dd->fifo_list[ddir].next);
++ struct request *rq = rq_entry_fifo(dd->fifo_list[ddir].next);
+
+ /*
+- * drq is expired!
++ * rq is expired!
+ */
+- if (time_after(jiffies, drq->expires))
++ if (time_after(jiffies, rq_fifo_time(rq)))
+ return 1;
+
+ return 0;
+@@ -463,21 +241,21 @@ static int deadline_dispatch_requests(re
+ struct deadline_data *dd = q->elevator->elevator_data;
+ const int reads = !list_empty(&dd->fifo_list[READ]);
+ const int writes = !list_empty(&dd->fifo_list[WRITE]);
+- struct deadline_rq *drq;
++ struct request *rq;
+ int data_dir;
+
+ /*
+ * batches are currently reads XOR writes
+ */
+- if (dd->next_drq[WRITE])
+- drq = dd->next_drq[WRITE];
++ if (dd->next_rq[WRITE])
++ rq = dd->next_rq[WRITE];
+ else
+- drq = dd->next_drq[READ];
++ rq = dd->next_rq[READ];
+
+- if (drq) {
++ if (rq) {
+ /* we have a "next request" */
+
+- if (dd->last_sector != drq->request->sector)
++ if (dd->last_sector != rq->sector)
+ /* end the batch on a non sequential request */
+ dd->batching += dd->fifo_batch;
+
+@@ -526,30 +304,33 @@ dispatch_find_request:
+ if (deadline_check_fifo(dd, data_dir)) {
+ /* An expired request exists - satisfy it */
+ dd->batching = 0;
+- drq = list_entry_fifo(dd->fifo_list[data_dir].next);
++ rq = rq_entry_fifo(dd->fifo_list[data_dir].next);
+
+- } else if (dd->next_drq[data_dir]) {
++ } else if (dd->next_rq[data_dir]) {
+ /*
+ * The last req was the same dir and we have a next request in
+ * sort order. No expired requests so continue on from here.
+ */
+- drq = dd->next_drq[data_dir];
++ rq = dd->next_rq[data_dir];
+ } else {
++ struct rb_node *node;
+ /*
+ * The last req was the other direction or we have run out of
+ * higher-sectored requests. Go back to the lowest sectored
+ * request (1 way elevator) and start a new batch.
+ */
+ dd->batching = 0;
+- drq = deadline_find_first_drq(dd, data_dir);
++ node = rb_first(&dd->sort_list[data_dir]);
++ if (node)
++ rq = rb_entry_rq(node);
+ }
+
+ dispatch_request:
+ /*
+- * drq is the selected appropriate request.
++ * rq is the selected appropriate request.
+ */
+ dd->batching++;
+- deadline_move_request(dd, drq);
++ deadline_move_request(dd, rq);
+
+ return 1;
+ }
+@@ -562,30 +343,6 @@ static int deadline_queue_empty(request_
+ && list_empty(&dd->fifo_list[READ]);
+ }
+
+-static struct request *
+-deadline_former_request(request_queue_t *q, struct request *rq)
+-{
+- struct deadline_rq *drq = RQ_DATA(rq);
+- struct rb_node *rbprev = rb_prev(&drq->rb_node);
+-
+- if (rbprev)
+- return rb_entry_drq(rbprev)->request;
+-
+- return NULL;
+-}
+-
+-static struct request *
+-deadline_latter_request(request_queue_t *q, struct request *rq)
+-{
+- struct deadline_rq *drq = RQ_DATA(rq);
+- struct rb_node *rbnext = rb_next(&drq->rb_node);
+-
+- if (rbnext)
+- return rb_entry_drq(rbnext)->request;
+-
+- return NULL;
+-}
+-
+ static void deadline_exit_queue(elevator_t *e)
+ {
+ struct deadline_data *dd = e->elevator_data;
+@@ -593,46 +350,21 @@ static void deadline_exit_queue(elevator
+ BUG_ON(!list_empty(&dd->fifo_list[READ]));
+ BUG_ON(!list_empty(&dd->fifo_list[WRITE]));
+
+- mempool_destroy(dd->drq_pool);
+- kfree(dd->hash);
+ kfree(dd);
+ }
+
+ /*
+- * initialize elevator private data (deadline_data), and alloc a drq for
+- * each request on the free lists
++ * initialize elevator private data (deadline_data).
+ */
+ static void *deadline_init_queue(request_queue_t *q, elevator_t *e)
+ {
+ struct deadline_data *dd;
+- int i;
+-
+- if (!drq_pool)
+- return NULL;
+
+ dd = kmalloc_node(sizeof(*dd), GFP_KERNEL, q->node);
+ if (!dd)
+ return NULL;
+ memset(dd, 0, sizeof(*dd));
+
+- dd->hash = kmalloc_node(sizeof(struct hlist_head)*DL_HASH_ENTRIES,
+- GFP_KERNEL, q->node);
+- if (!dd->hash) {
+- kfree(dd);
+- return NULL;
+- }
+-
+- dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
+- mempool_free_slab, drq_pool, q->node);
+- if (!dd->drq_pool) {
+- kfree(dd->hash);
+- kfree(dd);
+- return NULL;
+- }
+-
+- for (i = 0; i < DL_HASH_ENTRIES; i++)
+- INIT_HLIST_HEAD(&dd->hash[i]);
+-
+ INIT_LIST_HEAD(&dd->fifo_list[READ]);
+ INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
+ dd->sort_list[READ] = RB_ROOT;
+@@ -645,39 +377,6 @@ static void *deadline_init_queue(request
+ return dd;
+ }
+
+-static void deadline_put_request(request_queue_t *q, struct request *rq)
+-{
+- struct deadline_data *dd = q->elevator->elevator_data;
+- struct deadline_rq *drq = RQ_DATA(rq);
+-
+- mempool_free(drq, dd->drq_pool);
+- rq->elevator_private = NULL;
+-}
+-
+-static int
+-deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+- gfp_t gfp_mask)
+-{
+- struct deadline_data *dd = q->elevator->elevator_data;
+- struct deadline_rq *drq;
+-
+- drq = mempool_alloc(dd->drq_pool, gfp_mask);
+- if (drq) {
+- memset(drq, 0, sizeof(*drq));
+- RB_CLEAR_NODE(&drq->rb_node);
+- drq->request = rq;
+-
+- INIT_HLIST_NODE(&drq->hash);
+-
+- INIT_LIST_HEAD(&drq->fifo);
+-
+- rq->elevator_private = drq;
+- return 0;
+- }
+-
+- return 1;
+-}
+-
+ /*
+ * sysfs parts below
+ */
+@@ -757,10 +456,8 @@ static struct elevator_type iosched_dead
+ .elevator_dispatch_fn = deadline_dispatch_requests,
+ .elevator_add_req_fn = deadline_add_request,
+ .elevator_queue_empty_fn = deadline_queue_empty,
+- .elevator_former_req_fn = deadline_former_request,
+- .elevator_latter_req_fn = deadline_latter_request,
+- .elevator_set_req_fn = deadline_set_request,
+- .elevator_put_req_fn = deadline_put_request,
++ .elevator_former_req_fn = elv_rb_former_request,
++ .elevator_latter_req_fn = elv_rb_latter_request,
+ .elevator_init_fn = deadline_init_queue,
+ .elevator_exit_fn = deadline_exit_queue,
+ },
+@@ -772,24 +469,11 @@ static struct elevator_type iosched_dead
+
+ static int __init deadline_init(void)
+ {
+- int ret;
+-
+- drq_pool = kmem_cache_create("deadline_drq", sizeof(struct deadline_rq),
+- 0, 0, NULL, NULL);
+-
+- if (!drq_pool)
+- return -ENOMEM;
+-
+- ret = elv_register(&iosched_deadline);
+- if (ret)
+- kmem_cache_destroy(drq_pool);
+-
+- return ret;
++ return elv_register(&iosched_deadline);
+ }
+
+ static void __exit deadline_exit(void)
+ {
+- kmem_cache_destroy(drq_pool);
+ elv_unregister(&iosched_deadline);
+ }
+
+diff --git a/block/elevator.c b/block/elevator.c
+index 9b72dc7..8ccd163 100644
+--- a/block/elevator.c
++++ b/block/elevator.c
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 2000 Andrea Arcangeli <andrea at suse.de> SuSE
+ *
+- * 30042000 Jens Axboe <axboe at suse.de> :
++ * 30042000 Jens Axboe <axboe at kernel.dk> :
+ *
+ * Split the elevator a bit so that it is possible to choose a different
+ * one or even write a new "plug in". There are three pieces:
+@@ -33,6 +33,7 @@
+ #include <linux/compiler.h>
+ #include <linux/delay.h>
+ #include <linux/blktrace_api.h>
++#include <linux/hash.h>
+
+ #include <asm/uaccess.h>
+
+@@ -40,6 +41,16 @@ static DEFINE_SPINLOCK(elv_list_lock);
+ static LIST_HEAD(elv_list);
+
+ /*
++ * Merge hash stuff.
++ */
++static const int elv_hash_shift = 6;
++#define ELV_HASH_BLOCK(sec) ((sec) >> 3)
++#define ELV_HASH_FN(sec) (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
++#define ELV_HASH_ENTRIES (1 << elv_hash_shift)
++#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
++#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash))
++
++/*
+ * can we safely merge with this request?
+ */
+ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
+@@ -56,8 +67,7 @@ inline int elv_rq_merge_ok(struct reques
+ /*
+ * same device and no special stuff set, merge is ok
+ */
+- if (rq->rq_disk == bio->bi_bdev->bd_disk &&
+- !rq->waiting && !rq->special)
++ if (rq->rq_disk == bio->bi_bdev->bd_disk && !rq->special)
+ return 1;
+
+ return 0;
+@@ -83,21 +93,18 @@ static inline int elv_try_merge(struct r
+
+ static struct elevator_type *elevator_find(const char *name)
+ {
+- struct elevator_type *e = NULL;
++ struct elevator_type *e;
+ struct list_head *entry;
+
+ list_for_each(entry, &elv_list) {
+- struct elevator_type *__e;
+
+- __e = list_entry(entry, struct elevator_type, list);
++ e = list_entry(entry, struct elevator_type, list);
+
+- if (!strcmp(__e->elevator_name, name)) {
+- e = __e;
+- break;
+- }
++ if (!strcmp(e->elevator_name, name))
++ return e;
+ }
+
+- return e;
++ return NULL;
+ }
+
+ static void elevator_put(struct elevator_type *e)
+@@ -151,27 +158,44 @@ __setup("elevator=", elevator_setup);
+
+ static struct kobj_type elv_ktype;
+
+-static elevator_t *elevator_alloc(struct elevator_type *e)
+-{
+- elevator_t *eq = kmalloc(sizeof(elevator_t), GFP_KERNEL);
+- if (eq) {
+- memset(eq, 0, sizeof(*eq));
+- eq->ops = &e->ops;
+- eq->elevator_type = e;
+- kobject_init(&eq->kobj);
+- snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
+- eq->kobj.ktype = &elv_ktype;
+- mutex_init(&eq->sysfs_lock);
+- } else {
+- elevator_put(e);
+- }
++static elevator_t *elevator_alloc(request_queue_t *q, struct elevator_type *e)
++{
++ elevator_t *eq;
++ int i;
++
++ eq = kmalloc_node(sizeof(elevator_t), GFP_KERNEL, q->node);
++ if (unlikely(!eq))
++ goto err;
++
++ memset(eq, 0, sizeof(*eq));
++ eq->ops = &e->ops;
++ eq->elevator_type = e;
++ kobject_init(&eq->kobj);
++ snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
++ eq->kobj.ktype = &elv_ktype;
++ mutex_init(&eq->sysfs_lock);
++
++ eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES,
++ GFP_KERNEL, q->node);
++ if (!eq->hash)
++ goto err;
++
++ for (i = 0; i < ELV_HASH_ENTRIES; i++)
++ INIT_HLIST_HEAD(&eq->hash[i]);
++
+ return eq;
++err:
++ kfree(eq);
++ elevator_put(e);
++ return NULL;
+ }
+
+ static void elevator_release(struct kobject *kobj)
+ {
+ elevator_t *e = container_of(kobj, elevator_t, kobj);
++
+ elevator_put(e->elevator_type);
++ kfree(e->hash);
+ kfree(e);
+ }
+
+@@ -198,7 +222,7 @@ int elevator_init(request_queue_t *q, ch
+ e = elevator_get("noop");
+ }
+
+- eq = elevator_alloc(e);
++ eq = elevator_alloc(q, e);
+ if (!eq)
+ return -ENOMEM;
+
+@@ -212,6 +236,8 @@ int elevator_init(request_queue_t *q, ch
+ return ret;
+ }
+
++EXPORT_SYMBOL(elevator_init);
++
+ void elevator_exit(elevator_t *e)
+ {
+ mutex_lock(&e->sysfs_lock);
+@@ -223,10 +249,118 @@ void elevator_exit(elevator_t *e)
+ kobject_put(&e->kobj);
+ }
+
++EXPORT_SYMBOL(elevator_exit);
++
++static inline void __elv_rqhash_del(struct request *rq)
++{
++ hlist_del_init(&rq->hash);
++}
++
++static void elv_rqhash_del(request_queue_t *q, struct request *rq)
++{
++ if (ELV_ON_HASH(rq))
++ __elv_rqhash_del(rq);
++}
++
++static void elv_rqhash_add(request_queue_t *q, struct request *rq)
++{
++ elevator_t *e = q->elevator;
++
++ BUG_ON(ELV_ON_HASH(rq));
++ hlist_add_head(&rq->hash, &e->hash[ELV_HASH_FN(rq_hash_key(rq))]);
++}
++
++static void elv_rqhash_reposition(request_queue_t *q, struct request *rq)
++{
++ __elv_rqhash_del(rq);
++ elv_rqhash_add(q, rq);
++}
++
++static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset)
++{
++ elevator_t *e = q->elevator;
++ struct hlist_head *hash_list = &e->hash[ELV_HASH_FN(offset)];
++ struct hlist_node *entry, *next;
++ struct request *rq;
++
++ hlist_for_each_entry_safe(rq, entry, next, hash_list, hash) {
++ BUG_ON(!ELV_ON_HASH(rq));
++
++ if (unlikely(!rq_mergeable(rq))) {
++ __elv_rqhash_del(rq);
++ continue;
++ }
++
++ if (rq_hash_key(rq) == offset)
++ return rq;
++ }
++
++ return NULL;
++}
++
++/*
++ * RB-tree support functions for inserting/lookup/removal of requests
++ * in a sorted RB tree.
++ */
++struct request *elv_rb_add(struct rb_root *root, struct request *rq)
++{
++ struct rb_node **p = &root->rb_node;
++ struct rb_node *parent = NULL;
++ struct request *__rq;
++
++ while (*p) {
++ parent = *p;
++ __rq = rb_entry(parent, struct request, rb_node);
++
++ if (rq->sector < __rq->sector)
++ p = &(*p)->rb_left;
++ else if (rq->sector > __rq->sector)
++ p = &(*p)->rb_right;
++ else
++ return __rq;
++ }
++
++ rb_link_node(&rq->rb_node, parent, p);
++ rb_insert_color(&rq->rb_node, root);
++ return NULL;
++}
++
++EXPORT_SYMBOL(elv_rb_add);
++
++void elv_rb_del(struct rb_root *root, struct request *rq)
++{
++ BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
++ rb_erase(&rq->rb_node, root);
++ RB_CLEAR_NODE(&rq->rb_node);
++}
++
++EXPORT_SYMBOL(elv_rb_del);
++
++struct request *elv_rb_find(struct rb_root *root, sector_t sector)
++{
++ struct rb_node *n = root->rb_node;
++ struct request *rq;
++
++ while (n) {
++ rq = rb_entry(n, struct request, rb_node);
++
++ if (sector < rq->sector)
++ n = n->rb_left;
++ else if (sector > rq->sector)
++ n = n->rb_right;
++ else
++ return rq;
++ }
++
++ return NULL;
++}
++
++EXPORT_SYMBOL(elv_rb_find);
++
+ /*
+ * Insert rq into dispatch queue of q. Queue lock must be held on
+- * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be
+- * appended to the dispatch queue. To be used by specific elevators.
++ * entry. rq is sort insted into the dispatch queue. To be used by
++ * specific elevators.
+ */
+ void elv_dispatch_sort(request_queue_t *q, struct request *rq)
+ {
+@@ -235,6 +369,9 @@ void elv_dispatch_sort(request_queue_t *
+
+ if (q->last_merge == rq)
+ q->last_merge = NULL;
++
++ elv_rqhash_del(q, rq);
++
+ q->nr_sorted--;
+
+ boundary = q->end_sector;
+@@ -242,7 +379,7 @@ void elv_dispatch_sort(request_queue_t *
+ list_for_each_prev(entry, &q->queue_head) {
+ struct request *pos = list_entry_rq(entry);
+
+- if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
++ if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
+ break;
+ if (rq->sector >= boundary) {
+ if (pos->sector < boundary)
+@@ -258,11 +395,38 @@ void elv_dispatch_sort(request_queue_t *
+ list_add(&rq->queuelist, entry);
+ }
+
++EXPORT_SYMBOL(elv_dispatch_sort);
++
++/*
++ * Insert rq into dispatch queue of q. Queue lock must be held on
++ * entry. rq is added to the back of the dispatch queue. To be used by
++ * specific elevators.
++ */
++void elv_dispatch_add_tail(struct request_queue *q, struct request *rq)
++{
++ if (q->last_merge == rq)
++ q->last_merge = NULL;
++
++ elv_rqhash_del(q, rq);
++
++ q->nr_sorted--;
++
++ q->end_sector = rq_end_sector(rq);
++ q->boundary_rq = rq;
++ list_add_tail(&rq->queuelist, &q->queue_head);
++}
++
++EXPORT_SYMBOL(elv_dispatch_add_tail);
++
+ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
+ {
+ elevator_t *e = q->elevator;
++ struct request *__rq;
+ int ret;
+
++ /*
++ * First try one-hit cache.
++ */
+ if (q->last_merge) {
+ ret = elv_try_merge(q->last_merge, bio);
+ if (ret != ELEVATOR_NO_MERGE) {
+@@ -271,18 +435,30 @@ int elv_merge(request_queue_t *q, struct
+ }
+ }
+
++ /*
++ * See if our hash lookup can find a potential backmerge.
++ */
++ __rq = elv_rqhash_find(q, bio->bi_sector);
++ if (__rq && elv_rq_merge_ok(__rq, bio)) {
++ *req = __rq;
++ return ELEVATOR_BACK_MERGE;
++ }
++
+ if (e->ops->elevator_merge_fn)
+ return e->ops->elevator_merge_fn(q, req, bio);
+
+ return ELEVATOR_NO_MERGE;
+ }
+
+-void elv_merged_request(request_queue_t *q, struct request *rq)
++void elv_merged_request(request_queue_t *q, struct request *rq, int type)
+ {
+ elevator_t *e = q->elevator;
+
+ if (e->ops->elevator_merged_fn)
+- e->ops->elevator_merged_fn(q, rq);
++ e->ops->elevator_merged_fn(q, rq, type);
++
++ if (type == ELEVATOR_BACK_MERGE)
++ elv_rqhash_reposition(q, rq);
+
+ q->last_merge = rq;
+ }
+@@ -294,8 +470,11 @@ void elv_merge_requests(request_queue_t
+
+ if (e->ops->elevator_merge_req_fn)
+ e->ops->elevator_merge_req_fn(q, rq, next);
+- q->nr_sorted--;
+
++ elv_rqhash_reposition(q, rq);
++ elv_rqhash_del(q, next);
++
++ q->nr_sorted--;
+ q->last_merge = rq;
+ }
+
+@@ -313,7 +492,7 @@ void elv_requeue_request(request_queue_t
+ e->ops->elevator_deactivate_req_fn(q, rq);
+ }
+
+- rq->flags &= ~REQ_STARTED;
++ rq->cmd_flags &= ~REQ_STARTED;
+
+ elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
+ }
+@@ -344,13 +523,13 @@ void elv_insert(request_queue_t *q, stru
+
+ switch (where) {
+ case ELEVATOR_INSERT_FRONT:
+- rq->flags |= REQ_SOFTBARRIER;
++ rq->cmd_flags |= REQ_SOFTBARRIER;
+
+ list_add(&rq->queuelist, &q->queue_head);
+ break;
+
+ case ELEVATOR_INSERT_BACK:
+- rq->flags |= REQ_SOFTBARRIER;
++ rq->cmd_flags |= REQ_SOFTBARRIER;
+ elv_drain_elevator(q);
+ list_add_tail(&rq->queuelist, &q->queue_head);
+ /*
+@@ -369,10 +548,14 @@ void elv_insert(request_queue_t *q, stru
+
+ case ELEVATOR_INSERT_SORT:
+ BUG_ON(!blk_fs_request(rq));
+- rq->flags |= REQ_SORTED;
++ rq->cmd_flags |= REQ_SORTED;
+ q->nr_sorted++;
+- if (q->last_merge == NULL && rq_mergeable(rq))
+- q->last_merge = rq;
++ if (rq_mergeable(rq)) {
++ elv_rqhash_add(q, rq);
++ if (!q->last_merge)
++ q->last_merge = rq;
++ }
++
+ /*
+ * Some ioscheds (cfq) run q->request_fn directly, so
+ * rq cannot be accessed after calling
+@@ -387,7 +570,7 @@ void elv_insert(request_queue_t *q, stru
+ * insertion; otherwise, requests should be requeued
+ * in ordseq order.
+ */
+- rq->flags |= REQ_SOFTBARRIER;
++ rq->cmd_flags |= REQ_SOFTBARRIER;
+
+ if (q->ordseq == 0) {
+ list_add(&rq->queuelist, &q->queue_head);
+@@ -429,9 +612,9 @@ void __elv_add_request(request_queue_t *
+ int plug)
+ {
+ if (q->ordcolor)
+- rq->flags |= REQ_ORDERED_COLOR;
++ rq->cmd_flags |= REQ_ORDERED_COLOR;
+
+- if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
++ if (rq->cmd_flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
+ /*
+ * toggle ordered color
+ */
+@@ -452,7 +635,7 @@ void __elv_add_request(request_queue_t *
+ q->end_sector = rq_end_sector(rq);
+ q->boundary_rq = rq;
+ }
+- } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
++ } else if (!(rq->cmd_flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
+ where = ELEVATOR_INSERT_BACK;
+
+ if (plug)
+@@ -461,6 +644,8 @@ void __elv_add_request(request_queue_t *
+ elv_insert(q, rq, where);
+ }
+
++EXPORT_SYMBOL(__elv_add_request);
++
+ void elv_add_request(request_queue_t *q, struct request *rq, int where,
+ int plug)
+ {
+@@ -471,6 +656,8 @@ void elv_add_request(request_queue_t *q,
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+
++EXPORT_SYMBOL(elv_add_request);
++
+ static inline struct request *__elv_next_request(request_queue_t *q)
+ {
+ struct request *rq;
+@@ -493,7 +680,7 @@ struct request *elv_next_request(request
+ int ret;
+
+ while ((rq = __elv_next_request(q)) != NULL) {
+- if (!(rq->flags & REQ_STARTED)) {
++ if (!(rq->cmd_flags & REQ_STARTED)) {
+ elevator_t *e = q->elevator;
+
+ /*
+@@ -510,7 +697,7 @@ struct request *elv_next_request(request
+ * it, a request that has been delayed should
+ * not be passed by new incoming requests
+ */
+- rq->flags |= REQ_STARTED;
++ rq->cmd_flags |= REQ_STARTED;
+ blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
+ }
+
+@@ -519,7 +706,7 @@ struct request *elv_next_request(request
+ q->boundary_rq = NULL;
+ }
+
+- if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn)
++ if ((rq->cmd_flags & REQ_DONTPREP) || !q->prep_rq_fn)
+ break;
+
+ ret = q->prep_rq_fn(q, rq);
+@@ -541,7 +728,7 @@ struct request *elv_next_request(request
+ nr_bytes = rq->data_len;
+
+ blkdev_dequeue_request(rq);
+- rq->flags |= REQ_QUIET;
++ rq->cmd_flags |= REQ_QUIET;
+ end_that_request_chunk(rq, 0, nr_bytes);
+ end_that_request_last(rq, 0);
+ } else {
+@@ -554,9 +741,12 @@ struct request *elv_next_request(request
+ return rq;
+ }
+
++EXPORT_SYMBOL(elv_next_request);
++
+ void elv_dequeue_request(request_queue_t *q, struct request *rq)
+ {
+ BUG_ON(list_empty(&rq->queuelist));
++ BUG_ON(ELV_ON_HASH(rq));
+
+ list_del_init(&rq->queuelist);
+
+@@ -569,6 +759,8 @@ void elv_dequeue_request(request_queue_t
+ q->in_flight++;
+ }
+
++EXPORT_SYMBOL(elv_dequeue_request);
++
+ int elv_queue_empty(request_queue_t *q)
+ {
+ elevator_t *e = q->elevator;
+@@ -582,6 +774,8 @@ int elv_queue_empty(request_queue_t *q)
+ return 1;
+ }
+
++EXPORT_SYMBOL(elv_queue_empty);
++
+ struct request *elv_latter_request(request_queue_t *q, struct request *rq)
+ {
+ elevator_t *e = q->elevator;
+@@ -600,13 +794,12 @@ struct request *elv_former_request(reque
+ return NULL;
+ }
+
+-int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+- gfp_t gfp_mask)
++int elv_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
+ {
+ elevator_t *e = q->elevator;
+
+ if (e->ops->elevator_set_req_fn)
+- return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
++ return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
+
+ rq->elevator_private = NULL;
+ return 0;
+@@ -620,12 +813,12 @@ void elv_put_request(request_queue_t *q,
+ e->ops->elevator_put_req_fn(q, rq);
+ }
+
+-int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
++int elv_may_queue(request_queue_t *q, int rw)
+ {
+ elevator_t *e = q->elevator;
+
+ if (e->ops->elevator_may_queue_fn)
+- return e->ops->elevator_may_queue_fn(q, rw, bio);
++ return e->ops->elevator_may_queue_fn(q, rw);
+
+ return ELV_MQUEUE_MAY;
+ }
+@@ -792,7 +985,7 @@ static int elevator_switch(request_queue
+ /*
+ * Allocate new elevator
+ */
+- e = elevator_alloc(new_e);
++ e = elevator_alloc(q, new_e);
+ if (!e)
+ return 0;
+
+@@ -892,7 +1085,7 @@ ssize_t elv_iosched_show(request_queue_t
+ struct list_head *entry;
+ int len = 0;
+
+- spin_lock_irq(q->queue_lock);
++ spin_lock_irq(&elv_list_lock);
+ list_for_each(entry, &elv_list) {
+ struct elevator_type *__e;
+
+@@ -902,17 +1095,32 @@ ssize_t elv_iosched_show(request_queue_t
+ else
+ len += sprintf(name+len, "%s ", __e->elevator_name);
+ }
+- spin_unlock_irq(q->queue_lock);
++ spin_unlock_irq(&elv_list_lock);
+
+ len += sprintf(len+name, "\n");
+ return len;
+ }
+
+-EXPORT_SYMBOL(elv_dispatch_sort);
+-EXPORT_SYMBOL(elv_add_request);
+-EXPORT_SYMBOL(__elv_add_request);
+-EXPORT_SYMBOL(elv_next_request);
+-EXPORT_SYMBOL(elv_dequeue_request);
+-EXPORT_SYMBOL(elv_queue_empty);
+-EXPORT_SYMBOL(elevator_exit);
+-EXPORT_SYMBOL(elevator_init);
++struct request *elv_rb_former_request(request_queue_t *q, struct request *rq)
++{
++ struct rb_node *rbprev = rb_prev(&rq->rb_node);
++
++ if (rbprev)
++ return rb_entry_rq(rbprev);
++
++ return NULL;
++}
++
++EXPORT_SYMBOL(elv_rb_former_request);
++
++struct request *elv_rb_latter_request(request_queue_t *q, struct request *rq)
++{
++ struct rb_node *rbnext = rb_next(&rq->rb_node);
++
++ if (rbnext)
++ return rb_entry_rq(rbnext);
++
++ return NULL;
++}
++
++EXPORT_SYMBOL(elv_rb_latter_request);
+diff --git a/block/genhd.c b/block/genhd.c
+index 25d1f42..653919d 100644
+--- a/block/genhd.c
++++ b/block/genhd.c
+@@ -295,10 +295,15 @@ static struct kobject *base_probe(dev_t
+
+ static int __init genhd_device_init(void)
+ {
++ int err;
++
+ bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
+ blk_dev_init();
+- subsystem_register(&block_subsys);
+- return 0;
++ err = subsystem_register(&block_subsys);
++ if (err < 0)
++ printk(KERN_WARNING "%s: subsystem_register error: %d\n",
++ __FUNCTION__, err);
++ return err;
+ }
+
+ subsys_initcall(genhd_device_init);
+diff --git a/block/ioctl.c b/block/ioctl.c
+index 309760b..58aab63 100644
+--- a/block/ioctl.c
++++ b/block/ioctl.c
+@@ -199,8 +199,8 @@ static int blkdev_locked_ioctl(struct fi
+ return -ENOIOCTLCMD;
+ }
+
+-static int blkdev_driver_ioctl(struct inode *inode, struct file *file,
+- struct gendisk *disk, unsigned cmd, unsigned long arg)
++int blkdev_driver_ioctl(struct inode *inode, struct file *file,
++ struct gendisk *disk, unsigned cmd, unsigned long arg)
+ {
+ int ret;
+ if (disk->fops->unlocked_ioctl)
+@@ -215,6 +215,7 @@ static int blkdev_driver_ioctl(struct in
+
+ return -ENOTTY;
+ }
++EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
+
+ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+ unsigned long arg)
+diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
+index ddd9253..9eaee66 100644
+--- a/block/ll_rw_blk.c
++++ b/block/ll_rw_blk.c
+@@ -39,6 +39,7 @@ static void blk_unplug_timeout(unsigned
+ static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
+ static void init_request_from_bio(struct request *req, struct bio *bio);
+ static int __make_request(request_queue_t *q, struct bio *bio);
++static struct io_context *current_io_context(gfp_t gfp_flags, int node);
+
+ /*
+ * For the allocated request tables
+@@ -55,11 +56,6 @@ static kmem_cache_t *requestq_cachep;
+ */
+ static kmem_cache_t *iocontext_cachep;
+
+-static wait_queue_head_t congestion_wqh[2] = {
+- __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
+- __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
+- };
+-
+ /*
+ * Controlling structure to kblockd
+ */
+@@ -111,35 +107,6 @@ static void blk_queue_congestion_thresho
+ q->nr_congestion_off = nr;
+ }
+
+-/*
+- * A queue has just exitted congestion. Note this in the global counter of
+- * congested queues, and wake up anyone who was waiting for requests to be
+- * put back.
+- */
+-static void clear_queue_congested(request_queue_t *q, int rw)
+-{
+- enum bdi_state bit;
+- wait_queue_head_t *wqh = &congestion_wqh[rw];
+-
+- bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
+- clear_bit(bit, &q->backing_dev_info.state);
+- smp_mb__after_clear_bit();
+- if (waitqueue_active(wqh))
+- wake_up(wqh);
+-}
+-
+-/*
+- * A queue has just entered congestion. Flag that in the queue's VM-visible
+- * state flags and increment the global gounter of congested queues.
+- */
+-static void set_queue_congested(request_queue_t *q, int rw)
+-{
+- enum bdi_state bit;
+-
+- bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
+- set_bit(bit, &q->backing_dev_info.state);
+-}
+-
+ /**
+ * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
+ * @bdev: device
+@@ -158,7 +125,6 @@ struct backing_dev_info *blk_get_backing
+ ret = &q->backing_dev_info;
+ return ret;
+ }
+-
+ EXPORT_SYMBOL(blk_get_backing_dev_info);
+
+ void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data)
+@@ -166,7 +132,6 @@ void blk_queue_activity_fn(request_queue
+ q->activity_fn = fn;
+ q->activity_data = data;
+ }
+-
+ EXPORT_SYMBOL(blk_queue_activity_fn);
+
+ /**
+@@ -277,19 +242,19 @@ void blk_queue_make_request(request_queu
+
+ EXPORT_SYMBOL(blk_queue_make_request);
+
+-static inline void rq_init(request_queue_t *q, struct request *rq)
++static void rq_init(request_queue_t *q, struct request *rq)
+ {
+ INIT_LIST_HEAD(&rq->queuelist);
+ INIT_LIST_HEAD(&rq->donelist);
+
+ rq->errors = 0;
+- rq->rq_status = RQ_ACTIVE;
+ rq->bio = rq->biotail = NULL;
++ INIT_HLIST_NODE(&rq->hash);
++ RB_CLEAR_NODE(&rq->rb_node);
+ rq->ioprio = 0;
+ rq->buffer = NULL;
+ rq->ref_count = 1;
+ rq->q = q;
+- rq->waiting = NULL;
+ rq->special = NULL;
+ rq->data_len = 0;
+ rq->data = NULL;
+@@ -382,8 +347,8 @@ unsigned blk_ordered_req_seq(struct requ
+ if (rq == &q->post_flush_rq)
+ return QUEUE_ORDSEQ_POSTFLUSH;
+
+- if ((rq->flags & REQ_ORDERED_COLOR) ==
+- (q->orig_bar_rq->flags & REQ_ORDERED_COLOR))
++ if ((rq->cmd_flags & REQ_ORDERED_COLOR) ==
++ (q->orig_bar_rq->cmd_flags & REQ_ORDERED_COLOR))
+ return QUEUE_ORDSEQ_DRAIN;
+ else
+ return QUEUE_ORDSEQ_DONE;
+@@ -446,11 +411,11 @@ static void queue_flush(request_queue_t
+ end_io = post_flush_end_io;
+ }
+
++ rq->cmd_flags = REQ_HARDBARRIER;
+ rq_init(q, rq);
+- rq->flags = REQ_HARDBARRIER;
+ rq->elevator_private = NULL;
++ rq->elevator_private2 = NULL;
+ rq->rq_disk = q->bar_rq.rq_disk;
+- rq->rl = NULL;
+ rq->end_io = end_io;
+ q->prepare_flush_fn(q, rq);
+
+@@ -471,11 +436,13 @@ static inline struct request *start_orde
+ blkdev_dequeue_request(rq);
+ q->orig_bar_rq = rq;
+ rq = &q->bar_rq;
++ rq->cmd_flags = 0;
+ rq_init(q, rq);
+- rq->flags = bio_data_dir(q->orig_bar_rq->bio);
+- rq->flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0;
++ if (bio_data_dir(q->orig_bar_rq->bio) == WRITE)
++ rq->cmd_flags |= REQ_RW;
++ rq->cmd_flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0;
+ rq->elevator_private = NULL;
+- rq->rl = NULL;
++ rq->elevator_private2 = NULL;
+ init_request_from_bio(rq, q->orig_bar_rq->bio);
+ rq->end_io = bar_end_io;
+
+@@ -587,8 +554,8 @@ static int flush_dry_bio_endio(struct bi
+ return 0;
+ }
+
+-static inline int ordered_bio_endio(struct request *rq, struct bio *bio,
+- unsigned int nbytes, int error)
++static int ordered_bio_endio(struct request *rq, struct bio *bio,
++ unsigned int nbytes, int error)
+ {
+ request_queue_t *q = rq->q;
+ bio_end_io_t *endio;
+@@ -837,32 +804,24 @@ EXPORT_SYMBOL(blk_queue_dma_alignment);
+ **/
+ struct request *blk_queue_find_tag(request_queue_t *q, int tag)
+ {
+- struct blk_queue_tag *bqt = q->queue_tags;
+-
+- if (unlikely(bqt == NULL || tag >= bqt->real_max_depth))
+- return NULL;
+-
+- return bqt->tag_index[tag];
++ return blk_map_queue_find_tag(q->queue_tags, tag);
+ }
+
+ EXPORT_SYMBOL(blk_queue_find_tag);
+
+ /**
+- * __blk_queue_free_tags - release tag maintenance info
+- * @q: the request queue for the device
++ * __blk_free_tags - release a given set of tag maintenance info
++ * @bqt: the tag map to free
+ *
+- * Notes:
+- * blk_cleanup_queue() will take care of calling this function, if tagging
+- * has been used. So there's no need to call this directly.
+- **/
+-static void __blk_queue_free_tags(request_queue_t *q)
++ * Tries to free the specified @bqt at . Returns true if it was
++ * actually freed and false if there are still references using it
++ */
++static int __blk_free_tags(struct blk_queue_tag *bqt)
+ {
+- struct blk_queue_tag *bqt = q->queue_tags;
+-
+- if (!bqt)
+- return;
++ int retval;
+
+- if (atomic_dec_and_test(&bqt->refcnt)) {
++ retval = atomic_dec_and_test(&bqt->refcnt);
++ if (retval) {
+ BUG_ON(bqt->busy);
+ BUG_ON(!list_empty(&bqt->busy_list));
+
+@@ -873,12 +832,49 @@ static void __blk_queue_free_tags(reques
+ bqt->tag_map = NULL;
+
+ kfree(bqt);
++
+ }
+
++ return retval;
++}
++
++/**
++ * __blk_queue_free_tags - release tag maintenance info
++ * @q: the request queue for the device
++ *
++ * Notes:
++ * blk_cleanup_queue() will take care of calling this function, if tagging
++ * has been used. So there's no need to call this directly.
++ **/
++static void __blk_queue_free_tags(request_queue_t *q)
++{
++ struct blk_queue_tag *bqt = q->queue_tags;
++
++ if (!bqt)
++ return;
++
++ __blk_free_tags(bqt);
++
+ q->queue_tags = NULL;
+ q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED);
+ }
+
++
++/**
++ * blk_free_tags - release a given set of tag maintenance info
++ * @bqt: the tag map to free
++ *
++ * For externally managed @bqt@ frees the map. Callers of this
++ * function must guarantee to have released all the queues that
++ * might have been using this tag map.
++ */
++void blk_free_tags(struct blk_queue_tag *bqt)
++{
++ if (unlikely(!__blk_free_tags(bqt)))
++ BUG();
++}
++EXPORT_SYMBOL(blk_free_tags);
++
+ /**
+ * blk_queue_free_tags - release tag maintenance info
+ * @q: the request queue for the device
+@@ -901,7 +897,7 @@ init_tag_map(request_queue_t *q, struct
+ unsigned long *tag_map;
+ int nr_ulongs;
+
+- if (depth > q->nr_requests * 2) {
++ if (q && depth > q->nr_requests * 2) {
+ depth = q->nr_requests * 2;
+ printk(KERN_ERR "%s: adjusted depth to %d\n",
+ __FUNCTION__, depth);
+@@ -927,6 +923,38 @@ fail:
+ return -ENOMEM;
+ }
+
++static struct blk_queue_tag *__blk_queue_init_tags(struct request_queue *q,
++ int depth)
++{
++ struct blk_queue_tag *tags;
++
++ tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC);
++ if (!tags)
++ goto fail;
++
++ if (init_tag_map(q, tags, depth))
++ goto fail;
++
++ INIT_LIST_HEAD(&tags->busy_list);
++ tags->busy = 0;
++ atomic_set(&tags->refcnt, 1);
++ return tags;
++fail:
++ kfree(tags);
++ return NULL;
++}
++
++/**
++ * blk_init_tags - initialize the tag info for an external tag map
++ * @depth: the maximum queue depth supported
++ * @tags: the tag to use
++ **/
++struct blk_queue_tag *blk_init_tags(int depth)
++{
++ return __blk_queue_init_tags(NULL, depth);
++}
++EXPORT_SYMBOL(blk_init_tags);
++
+ /**
+ * blk_queue_init_tags - initialize the queue tag info
+ * @q: the request queue for the device
+@@ -941,16 +969,10 @@ int blk_queue_init_tags(request_queue_t
+ BUG_ON(tags && q->queue_tags && tags != q->queue_tags);
+
+ if (!tags && !q->queue_tags) {
+- tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC);
+- if (!tags)
+- goto fail;
++ tags = __blk_queue_init_tags(q, depth);
+
+- if (init_tag_map(q, tags, depth))
++ if (!tags)
+ goto fail;
+-
+- INIT_LIST_HEAD(&tags->busy_list);
+- tags->busy = 0;
+- atomic_set(&tags->refcnt, 1);
+ } else if (q->queue_tags) {
+ if ((rc = blk_queue_resize_tags(q, depth)))
+ return rc;
+@@ -1002,6 +1024,13 @@ int blk_queue_resize_tags(request_queue_
+ }
+
+ /*
++ * Currently cannot replace a shared tag map with a new
++ * one, so error out if this is the case
++ */
++ if (atomic_read(&bqt->refcnt) != 1)
++ return -EBUSY;
++
++ /*
+ * save the old state info, so we can copy it back
+ */
+ tag_index = bqt->tag_index;
+@@ -1057,7 +1086,7 @@ void blk_queue_end_tag(request_queue_t *
+ }
+
+ list_del_init(&rq->queuelist);
+- rq->flags &= ~REQ_QUEUED;
++ rq->cmd_flags &= ~REQ_QUEUED;
+ rq->tag = -1;
+
+ if (unlikely(bqt->tag_index[tag] == NULL))
+@@ -1093,7 +1122,7 @@ int blk_queue_start_tag(request_queue_t
+ struct blk_queue_tag *bqt = q->queue_tags;
+ int tag;
+
+- if (unlikely((rq->flags & REQ_QUEUED))) {
++ if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
+ printk(KERN_ERR
+ "%s: request %p for device [%s] already tagged %d",
+ __FUNCTION__, rq,
+@@ -1101,13 +1130,18 @@ int blk_queue_start_tag(request_queue_t
+ BUG();
+ }
+
+- tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
+- if (tag >= bqt->max_depth)
+- return 1;
++ /*
++ * Protect against shared tag maps, as we may not have exclusive
++ * access to the tag map.
++ */
++ do {
++ tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
++ if (tag >= bqt->max_depth)
++ return 1;
+
+- __set_bit(tag, bqt->tag_map);
++ } while (test_and_set_bit(tag, bqt->tag_map));
+
+- rq->flags |= REQ_QUEUED;
++ rq->cmd_flags |= REQ_QUEUED;
+ rq->tag = tag;
+ bqt->tag_index[tag] = rq;
+ blkdev_dequeue_request(rq);
+@@ -1143,65 +1177,31 @@ void blk_queue_invalidate_tags(request_q
+ printk(KERN_ERR
+ "%s: bad tag found on list\n", __FUNCTION__);
+ list_del_init(&rq->queuelist);
+- rq->flags &= ~REQ_QUEUED;
++ rq->cmd_flags &= ~REQ_QUEUED;
+ } else
+ blk_queue_end_tag(q, rq);
+
+- rq->flags &= ~REQ_STARTED;
++ rq->cmd_flags &= ~REQ_STARTED;
+ __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 0);
+ }
+ }
+
+ EXPORT_SYMBOL(blk_queue_invalidate_tags);
+
+-static const char * const rq_flags[] = {
+- "REQ_RW",
+- "REQ_FAILFAST",
+- "REQ_SORTED",
+- "REQ_SOFTBARRIER",
+- "REQ_HARDBARRIER",
+- "REQ_FUA",
+- "REQ_CMD",
+- "REQ_NOMERGE",
+- "REQ_STARTED",
+- "REQ_DONTPREP",
+- "REQ_QUEUED",
+- "REQ_ELVPRIV",
+- "REQ_PC",
+- "REQ_BLOCK_PC",
+- "REQ_SENSE",
+- "REQ_FAILED",
+- "REQ_QUIET",
+- "REQ_SPECIAL",
+- "REQ_DRIVE_CMD",
+- "REQ_DRIVE_TASK",
+- "REQ_DRIVE_TASKFILE",
+- "REQ_PREEMPT",
+- "REQ_PM_SUSPEND",
+- "REQ_PM_RESUME",
+- "REQ_PM_SHUTDOWN",
+- "REQ_ORDERED_COLOR",
+-};
+-
+ void blk_dump_rq_flags(struct request *rq, char *msg)
+ {
+ int bit;
+
+- printk("%s: dev %s: flags = ", msg,
+- rq->rq_disk ? rq->rq_disk->disk_name : "?");
+- bit = 0;
+- do {
+- if (rq->flags & (1 << bit))
+- printk("%s ", rq_flags[bit]);
+- bit++;
+- } while (bit < __REQ_NR_BITS);
++ printk("%s: dev %s: type=%x, flags=%x\n", msg,
++ rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
++ rq->cmd_flags);
+
+ printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector,
+ rq->nr_sectors,
+ rq->current_nr_sectors);
+ printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len);
+
+- if (rq->flags & (REQ_BLOCK_PC | REQ_PC)) {
++ if (blk_pc_request(rq)) {
+ printk("cdb: ");
+ for (bit = 0; bit < sizeof(rq->cmd); bit++)
+ printk("%02x ", rq->cmd[bit]);
+@@ -1374,7 +1374,7 @@ static inline int ll_new_mergeable(reque
+ int nr_phys_segs = bio_phys_segments(q, bio);
+
+ if (req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
+- req->flags |= REQ_NOMERGE;
++ req->cmd_flags |= REQ_NOMERGE;
+ if (req == q->last_merge)
+ q->last_merge = NULL;
+ return 0;
+@@ -1397,7 +1397,7 @@ static inline int ll_new_hw_segment(requ
+
+ if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments
+ || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
+- req->flags |= REQ_NOMERGE;
++ req->cmd_flags |= REQ_NOMERGE;
+ if (req == q->last_merge)
+ q->last_merge = NULL;
+ return 0;
+@@ -1424,7 +1424,7 @@ static int ll_back_merge_fn(request_queu
+ max_sectors = q->max_sectors;
+
+ if (req->nr_sectors + bio_sectors(bio) > max_sectors) {
+- req->flags |= REQ_NOMERGE;
++ req->cmd_flags |= REQ_NOMERGE;
+ if (req == q->last_merge)
+ q->last_merge = NULL;
+ return 0;
+@@ -1463,7 +1463,7 @@ static int ll_front_merge_fn(request_que
+
+
+ if (req->nr_sectors + bio_sectors(bio) > max_sectors) {
+- req->flags |= REQ_NOMERGE;
++ req->cmd_flags |= REQ_NOMERGE;
+ if (req == q->last_merge)
+ q->last_merge = NULL;
+ return 0;
+@@ -1780,8 +1780,7 @@ static void blk_release_queue(struct kob
+ if (q->queue_tags)
+ __blk_queue_free_tags(q);
+
+- if (q->blk_trace)
+- blk_trace_shutdown(q);
++ blk_trace_shutdown(q);
+
+ kmem_cache_free(requestq_cachep, q);
+ }
+@@ -1963,14 +1962,13 @@ EXPORT_SYMBOL(blk_get_queue);
+
+ static inline void blk_free_request(request_queue_t *q, struct request *rq)
+ {
+- if (rq->flags & REQ_ELVPRIV)
++ if (rq->cmd_flags & REQ_ELVPRIV)
+ elv_put_request(q, rq);
+ mempool_free(rq, q->rq.rq_pool);
+ }
+
+-static inline struct request *
+-blk_alloc_request(request_queue_t *q, int rw, struct bio *bio,
+- int priv, gfp_t gfp_mask)
++static struct request *
++blk_alloc_request(request_queue_t *q, int rw, int priv, gfp_t gfp_mask)
+ {
+ struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
+
+@@ -1978,17 +1976,17 @@ blk_alloc_request(request_queue_t *q, in
+ return NULL;
+
+ /*
+- * first three bits are identical in rq->flags and bio->bi_rw,
++ * first three bits are identical in rq->cmd_flags and bio->bi_rw,
+ * see bio.h and blkdev.h
+ */
+- rq->flags = rw;
++ rq->cmd_flags = rw | REQ_ALLOCED;
+
+ if (priv) {
+- if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) {
++ if (unlikely(elv_set_request(q, rq, gfp_mask))) {
+ mempool_free(rq, q->rq.rq_pool);
+ return NULL;
+ }
+- rq->flags |= REQ_ELVPRIV;
++ rq->cmd_flags |= REQ_ELVPRIV;
+ }
+
+ return rq;
+@@ -2033,7 +2031,7 @@ static void __freed_request(request_queu
+ struct request_list *rl = &q->rq;
+
+ if (rl->count[rw] < queue_congestion_off_threshold(q))
+- clear_queue_congested(q, rw);
++ blk_clear_queue_congested(q, rw);
+
+ if (rl->count[rw] + 1 <= q->nr_requests) {
+ if (waitqueue_active(&rl->wait[rw]))
+@@ -2075,13 +2073,13 @@ static struct request *get_request(reque
+ struct io_context *ioc = NULL;
+ int may_queue, priv;
+
+- may_queue = elv_may_queue(q, rw, bio);
++ may_queue = elv_may_queue(q, rw);
+ if (may_queue == ELV_MQUEUE_NO)
+ goto rq_starved;
+
+ if (rl->count[rw]+1 >= queue_congestion_on_threshold(q)) {
+ if (rl->count[rw]+1 >= q->nr_requests) {
+- ioc = current_io_context(GFP_ATOMIC);
++ ioc = current_io_context(GFP_ATOMIC, q->node);
+ /*
+ * The queue will fill after this allocation, so set
+ * it as full, and mark this process as "batching".
+@@ -2103,7 +2101,7 @@ static struct request *get_request(reque
+ }
+ }
+ }
+- set_queue_congested(q, rw);
++ blk_set_queue_congested(q, rw);
+ }
+
+ /*
+@@ -2123,7 +2121,7 @@ static struct request *get_request(reque
+
+ spin_unlock_irq(q->queue_lock);
+
+- rq = blk_alloc_request(q, rw, bio, priv, gfp_mask);
++ rq = blk_alloc_request(q, rw, priv, gfp_mask);
+ if (unlikely(!rq)) {
+ /*
+ * Allocation failed presumably due to memory. Undo anything
+@@ -2159,7 +2157,6 @@ rq_starved:
+ ioc->nr_batch_requests--;
+
+ rq_init(q, rq);
+- rq->rl = rl;
+
+ blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
+ out:
+@@ -2202,7 +2199,7 @@ static struct request *get_request_wait(
+ * up to a big batch of them for a small period time.
+ * See ioc_batching, ioc_set_batching
+ */
+- ioc = current_io_context(GFP_NOIO);
++ ioc = current_io_context(GFP_NOIO, q->node);
+ ioc_set_batching(q, ioc);
+
+ spin_lock_irq(q->queue_lock);
+@@ -2234,6 +2231,25 @@ struct request *blk_get_request(request_
+ EXPORT_SYMBOL(blk_get_request);
+
+ /**
++ * blk_start_queueing - initiate dispatch of requests to device
++ * @q: request queue to kick into gear
++ *
++ * This is basically a helper to remove the need to know whether a queue
++ * is plugged or not if someone just wants to initiate dispatch of requests
++ * for this queue.
++ *
++ * The queue lock must be held with interrupts disabled.
++ */
++void blk_start_queueing(request_queue_t *q)
++{
++ if (!blk_queue_plugged(q))
++ q->request_fn(q);
++ else
++ __generic_unplug_device(q);
++}
++EXPORT_SYMBOL(blk_start_queueing);
++
++/**
+ * blk_requeue_request - put a request back on queue
+ * @q: request queue where request should be inserted
+ * @rq: request to be inserted
+@@ -2285,7 +2301,8 @@ void blk_insert_request(request_queue_t
+ * must not attempt merges on this) and that it acts as a soft
+ * barrier
+ */
+- rq->flags |= REQ_SPECIAL | REQ_SOFTBARRIER;
++ rq->cmd_type = REQ_TYPE_SPECIAL;
++ rq->cmd_flags |= REQ_SOFTBARRIER;
+
+ rq->special = data;
+
+@@ -2299,11 +2316,7 @@ void blk_insert_request(request_queue_t
+
+ drive_stat_acct(rq, rq->nr_sectors, 1);
+ __elv_add_request(q, rq, where, 0);
+-
+- if (blk_queue_plugged(q))
+- __generic_unplug_device(q);
+- else
+- q->request_fn(q);
++ blk_start_queueing(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+
+@@ -2492,7 +2505,7 @@ void blk_execute_rq_nowait(request_queue
+ int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
+
+ rq->rq_disk = bd_disk;
+- rq->flags |= REQ_NOMERGE;
++ rq->cmd_flags |= REQ_NOMERGE;
+ rq->end_io = done;
+ WARN_ON(irqs_disabled());
+ spin_lock_irq(q->queue_lock);
+@@ -2532,10 +2545,9 @@ int blk_execute_rq(request_queue_t *q, s
+ rq->sense_len = 0;
+ }
+
+- rq->waiting = &wait;
++ rq->end_io_data = &wait;
+ blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
+ wait_for_completion(&wait);
+- rq->waiting = NULL;
+
+ if (rq->errors)
+ err = -EIO;
+@@ -2644,8 +2656,6 @@ EXPORT_SYMBOL_GPL(disk_round_stats);
+ */
+ void __blk_put_request(request_queue_t *q, struct request *req)
+ {
+- struct request_list *rl = req->rl;
+-
+ if (unlikely(!q))
+ return;
+ if (unlikely(--req->ref_count))
+@@ -2653,18 +2663,16 @@ void __blk_put_request(request_queue_t *
+
+ elv_completed_request(q, req);
+
+- req->rq_status = RQ_INACTIVE;
+- req->rl = NULL;
+-
+ /*
+ * Request may not have originated from ll_rw_blk. if not,
+ * it didn't come out of our reserved rq pools
+ */
+- if (rl) {
++ if (req->cmd_flags & REQ_ALLOCED) {
+ int rw = rq_data_dir(req);
+- int priv = req->flags & REQ_ELVPRIV;
++ int priv = req->cmd_flags & REQ_ELVPRIV;
+
+ BUG_ON(!list_empty(&req->queuelist));
++ BUG_ON(!hlist_unhashed(&req->hash));
+
+ blk_free_request(q, req);
+ freed_request(q, rw, priv);
+@@ -2698,9 +2706,9 @@ EXPORT_SYMBOL(blk_put_request);
+ */
+ void blk_end_sync_rq(struct request *rq, int error)
+ {
+- struct completion *waiting = rq->waiting;
++ struct completion *waiting = rq->end_io_data;
+
+- rq->waiting = NULL;
++ rq->end_io_data = NULL;
+ __blk_put_request(rq->q, rq);
+
+ /*
+@@ -2711,29 +2719,6 @@ void blk_end_sync_rq(struct request *rq,
+ }
+ EXPORT_SYMBOL(blk_end_sync_rq);
+
+-/**
+- * blk_congestion_wait - wait for a queue to become uncongested
+- * @rw: READ or WRITE
+- * @timeout: timeout in jiffies
+- *
+- * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion.
+- * If no queues are congested then just wait for the next request to be
+- * returned.
+- */
+-long blk_congestion_wait(int rw, long timeout)
+-{
+- long ret;
+- DEFINE_WAIT(wait);
+- wait_queue_head_t *wqh = &congestion_wqh[rw];
+-
+- prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
+- ret = io_schedule_timeout(timeout);
+- finish_wait(wqh, &wait);
+- return ret;
+-}
+-
+-EXPORT_SYMBOL(blk_congestion_wait);
+-
+ /*
+ * Has to be called with the request spinlock acquired
+ */
+@@ -2751,7 +2736,7 @@ static int attempt_merge(request_queue_t
+
+ if (rq_data_dir(req) != rq_data_dir(next)
+ || req->rq_disk != next->rq_disk
+- || next->waiting || next->special)
++ || next->special)
+ return 0;
+
+ /*
+@@ -2812,22 +2797,24 @@ static inline int attempt_front_merge(re
+
+ static void init_request_from_bio(struct request *req, struct bio *bio)
+ {
+- req->flags |= REQ_CMD;
++ req->cmd_type = REQ_TYPE_FS;
+
+ /*
+ * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
+ */
+ if (bio_rw_ahead(bio) || bio_failfast(bio))
+- req->flags |= REQ_FAILFAST;
++ req->cmd_flags |= REQ_FAILFAST;
+
+ /*
+ * REQ_BARRIER implies no merging, but lets make it explicit
+ */
+ if (unlikely(bio_barrier(bio)))
+- req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
++ req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
+
+ if (bio_sync(bio))
+- req->flags |= REQ_RW_SYNC;
++ req->cmd_flags |= REQ_RW_SYNC;
++ if (bio_rw_meta(bio))
++ req->cmd_flags |= REQ_RW_META;
+
+ req->errors = 0;
+ req->hard_sector = req->sector = bio->bi_sector;
+@@ -2836,7 +2823,6 @@ static void init_request_from_bio(struct
+ req->nr_phys_segments = bio_phys_segments(req->q, bio);
+ req->nr_hw_segments = bio_hw_segments(req->q, bio);
+ req->buffer = bio_data(bio); /* see ->buffer comment above */
+- req->waiting = NULL;
+ req->bio = req->biotail = bio;
+ req->ioprio = bio_prio(bio);
+ req->rq_disk = bio->bi_bdev->bd_disk;
+@@ -2846,17 +2832,11 @@ static void init_request_from_bio(struct
+ static int __make_request(request_queue_t *q, struct bio *bio)
+ {
+ struct request *req;
+- int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
+- unsigned short prio;
+- sector_t sector;
++ int el_ret, nr_sectors, barrier, err;
++ const unsigned short prio = bio_prio(bio);
++ const int sync = bio_sync(bio);
+
+- 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);
+
+ /*
+ * low level driver can indicate that it wants pages above a
+@@ -2865,8 +2845,6 @@ static int __make_request(request_queue_
+ */
+ blk_queue_bounce(q, &bio);
+
+- spin_lock_prefetch(q->queue_lock);
+-
+ barrier = bio_barrier(bio);
+ if (unlikely(barrier) && (q->next_ordered == QUEUE_ORDERED_NONE)) {
+ err = -EOPNOTSUPP;
+@@ -2894,7 +2872,7 @@ static int __make_request(request_queue_
+ 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);
++ elv_merged_request(q, req, el_ret);
+ goto out;
+
+ case ELEVATOR_FRONT_MERGE:
+@@ -2914,14 +2892,14 @@ static int __make_request(request_queue_
+ * not touch req->buffer either...
+ */
+ req->buffer = bio_data(bio);
+- req->current_nr_sectors = cur_nr_sectors;
+- req->hard_cur_sectors = cur_nr_sectors;
+- req->sector = req->hard_sector = sector;
++ req->current_nr_sectors = bio_cur_sectors(bio);
++ req->hard_cur_sectors = req->current_nr_sectors;
++ req->sector = req->hard_sector = bio->bi_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);
++ elv_merged_request(q, req, el_ret);
+ goto out;
+
+ /* ELV_NO_MERGE: elevator says don't/can't merge. */
+@@ -2934,7 +2912,7 @@ get_rq:
+ * Grab a free request. This is might sleep but can not fail.
+ * Returns with the queue unlocked.
+ */
+- req = get_request_wait(q, rw, bio);
++ req = get_request_wait(q, bio_data_dir(bio), bio);
+
+ /*
+ * After dropping the lock and possibly sleeping here, our request
+@@ -3021,6 +2999,7 @@ void generic_make_request(struct bio *bi
+ {
+ request_queue_t *q;
+ sector_t maxsector;
++ sector_t old_sector;
+ int ret, nr_sectors = bio_sectors(bio);
+ dev_t old_dev;
+
+@@ -3049,7 +3028,7 @@ void generic_make_request(struct bio *bi
+ * NOTE: we don't repeat the blk_size check for each new device.
+ * Stacking drivers are expected to know what they are doing.
+ */
+- maxsector = -1;
++ old_sector = -1;
+ old_dev = 0;
+ do {
+ char b[BDEVNAME_SIZE];
+@@ -3083,15 +3062,31 @@ end_io:
+ */
+ blk_partition_remap(bio);
+
+- if (maxsector != -1)
++ if (old_sector != -1)
+ blk_add_trace_remap(q, bio, old_dev, bio->bi_sector,
+- maxsector);
++ old_sector);
+
+ blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
+
+- maxsector = bio->bi_sector;
++ old_sector = bio->bi_sector;
+ old_dev = bio->bi_bdev->bd_dev;
+
++ maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
++ if (maxsector) {
++ sector_t sector = bio->bi_sector;
++
++ if (maxsector < nr_sectors ||
++ maxsector - nr_sectors < sector) {
++ /*
++ * This may well happen - partitions are not
++ * checked to make sure they are within the size
++ * of the whole device.
++ */
++ handle_bad_sector(bio);
++ goto end_io;
++ }
++ }
++
+ ret = q->make_request_fn(q, bio);
+ } while (ret);
+ }
+@@ -3228,7 +3223,7 @@ static int __end_that_request_first(stru
+ req->errors = 0;
+
+ if (!uptodate) {
+- if (blk_fs_request(req) && !(req->flags & REQ_QUIET))
++ if (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))
+ printk("end_request: I/O error, dev %s, sector %llu\n",
+ req->rq_disk ? req->rq_disk->disk_name : "?",
+ (unsigned long long)req->sector);
+@@ -3491,8 +3486,8 @@ EXPORT_SYMBOL(end_request);
+
+ void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio)
+ {
+- /* first two bits are identical in rq->flags and bio->bi_rw */
+- rq->flags |= (bio->bi_rw & 3);
++ /* first two bits are identical in rq->cmd_flags and bio->bi_rw */
++ rq->cmd_flags |= (bio->bi_rw & 3);
+
+ rq->nr_phys_segments = bio_phys_segments(q, bio);
+ rq->nr_hw_segments = bio_hw_segments(q, bio);
+@@ -3580,25 +3575,22 @@ EXPORT_SYMBOL(put_io_context);
+ /* Called by the exitting task */
+ void exit_io_context(void)
+ {
+- unsigned long flags;
+ struct io_context *ioc;
+ struct cfq_io_context *cic;
+
+- 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);
+
++ ioc->task = NULL;
+ if (ioc->aic && ioc->aic->exit)
+ ioc->aic->exit(ioc->aic);
+ if (ioc->cic_root.rb_node != NULL) {
+ cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
+ cic->exit(ioc);
+ }
+-
++
+ put_io_context(ioc);
+ }
+
+@@ -3610,7 +3602,7 @@ void exit_io_context(void)
+ * 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 *current_io_context(gfp_t gfp_flags)
++static struct io_context *current_io_context(gfp_t gfp_flags, int node)
+ {
+ struct task_struct *tsk = current;
+ struct io_context *ret;
+@@ -3619,11 +3611,11 @@ struct io_context *current_io_context(gf
+ if (likely(ret))
+ return ret;
+
+- ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
++ ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
+ if (ret) {
+ atomic_set(&ret->refcount, 1);
+ ret->task = current;
+- ret->set_ioprio = NULL;
++ ret->ioprio_changed = 0;
+ ret->last_waited = jiffies; /* doesn't matter... */
+ ret->nr_batch_requests = 0; /* because this is 0 */
+ ret->aic = NULL;
+@@ -3643,10 +3635,10 @@ EXPORT_SYMBOL(current_io_context);
+ *
+ * This is always called in the context of the task which submitted the I/O.
+ */
+-struct io_context *get_io_context(gfp_t gfp_flags)
++struct io_context *get_io_context(gfp_t gfp_flags, int node)
+ {
+ struct io_context *ret;
+- ret = current_io_context(gfp_flags);
++ ret = current_io_context(gfp_flags, node);
+ if (likely(ret))
+ atomic_inc(&ret->refcount);
+ return ret;
+@@ -3719,14 +3711,14 @@ queue_requests_store(struct request_queu
+ blk_queue_congestion_threshold(q);
+
+ if (rl->count[READ] >= queue_congestion_on_threshold(q))
+- set_queue_congested(q, READ);
++ blk_set_queue_congested(q, READ);
+ else if (rl->count[READ] < queue_congestion_off_threshold(q))
+- clear_queue_congested(q, READ);
++ blk_clear_queue_congested(q, READ);
+
+ if (rl->count[WRITE] >= queue_congestion_on_threshold(q))
+- set_queue_congested(q, WRITE);
++ blk_set_queue_congested(q, WRITE);
+ else if (rl->count[WRITE] < queue_congestion_off_threshold(q))
+- clear_queue_congested(q, WRITE);
++ blk_clear_queue_congested(q, WRITE);
+
+ if (rl->count[READ] >= q->nr_requests) {
+ blk_set_queue_full(q, READ);
+@@ -3759,9 +3751,6 @@ queue_ra_store(struct request_queue *q,
+ ssize_t ret = queue_var_store(&ra_kb, page, count);
+
+ spin_lock_irq(q->queue_lock);
+- if (ra_kb > (q->max_sectors >> 1))
+- ra_kb = (q->max_sectors >> 1);
+-
+ q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
+ spin_unlock_irq(q->queue_lock);
+
+diff --git a/block/noop-iosched.c b/block/noop-iosched.c
+index 56a7c62..79af431 100644
+--- a/block/noop-iosched.c
++++ b/block/noop-iosched.c
+@@ -69,7 +69,7 @@ static void *noop_init_queue(request_que
+ {
+ struct noop_data *nd;
+
+- nd = kmalloc(sizeof(*nd), GFP_KERNEL);
++ nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node);
+ if (!nd)
+ return NULL;
+ INIT_LIST_HEAD(&nd->queue);
+diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
+index b33eda2..2dc3264 100644
+--- a/block/scsi_ioctl.c
++++ b/block/scsi_ioctl.c
+@@ -294,7 +294,7 @@ static int sg_io(struct file *file, requ
+ rq->sense = sense;
+ rq->sense_len = 0;
+
+- rq->flags |= REQ_BLOCK_PC;
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ bio = rq->bio;
+
+ /*
+@@ -470,7 +470,7 @@ int sg_scsi_ioctl(struct file *file, str
+ memset(sense, 0, sizeof(sense));
+ rq->sense = sense;
+ rq->sense_len = 0;
+- rq->flags |= REQ_BLOCK_PC;
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+
+ blk_execute_rq(q, disk, rq, 0);
+
+@@ -502,7 +502,7 @@ static int __blk_send_generic(request_qu
+ int err;
+
+ rq = blk_get_request(q, WRITE, __GFP_WAIT);
+- rq->flags |= REQ_BLOCK_PC;
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->data = NULL;
+ rq->data_len = 0;
+ rq->timeout = BLK_DEFAULT_TIMEOUT;
+diff --git a/crypto/Kconfig b/crypto/Kconfig
+index ba133d5..cbae839 100644
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -9,47 +9,71 @@ config CRYPTO
+ help
+ This option provides the core Cryptographic API.
+
++if CRYPTO
++
++config CRYPTO_ALGAPI
++ tristate
++ help
++ This option provides the API for cryptographic algorithms.
++
++config CRYPTO_BLKCIPHER
++ tristate
++ select CRYPTO_ALGAPI
++
++config CRYPTO_HASH
++ tristate
++ select CRYPTO_ALGAPI
++
++config CRYPTO_MANAGER
++ tristate "Cryptographic algorithm manager"
++ select CRYPTO_ALGAPI
++ help
++ Create default cryptographic template instantiations such as
++ cbc(aes).
++
+ config CRYPTO_HMAC
+- bool "HMAC support"
+- depends on CRYPTO
++ tristate "HMAC support"
++ select CRYPTO_HASH
++ select CRYPTO_MANAGER
+ help
+ HMAC: Keyed-Hashing for Message Authentication (RFC2104).
+ This is required for IPSec.
+
+ config CRYPTO_NULL
+ tristate "Null algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ These are 'Null' algorithms, used by IPsec, which do nothing.
+
+ config CRYPTO_MD4
+ tristate "MD4 digest algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ MD4 message digest algorithm (RFC1320).
+
+ config CRYPTO_MD5
+ tristate "MD5 digest algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ MD5 message digest algorithm (RFC1321).
+
+ config CRYPTO_SHA1
+ tristate "SHA1 digest algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+ config CRYPTO_SHA1_S390
+ tristate "SHA1 digest algorithm (s390)"
+- depends on CRYPTO && S390
++ depends on S390
++ select CRYPTO_ALGAPI
+ help
+ This is the s390 hardware accelerated implementation of the
+ SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+ config CRYPTO_SHA256
+ tristate "SHA256 digest algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ SHA256 secure hash standard (DFIPS 180-2).
+
+@@ -58,7 +82,8 @@ config CRYPTO_SHA256
+
+ config CRYPTO_SHA256_S390
+ tristate "SHA256 digest algorithm (s390)"
+- depends on CRYPTO && S390
++ depends on S390
++ select CRYPTO_ALGAPI
+ help
+ This is the s390 hardware accelerated implementation of the
+ SHA256 secure hash standard (DFIPS 180-2).
+@@ -68,7 +93,7 @@ config CRYPTO_SHA256_S390
+
+ config CRYPTO_SHA512
+ tristate "SHA384 and SHA512 digest algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ SHA512 secure hash standard (DFIPS 180-2).
+
+@@ -80,7 +105,7 @@ config CRYPTO_SHA512
+
+ config CRYPTO_WP512
+ tristate "Whirlpool digest algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Whirlpool hash algorithm 512, 384 and 256-bit hashes
+
+@@ -92,7 +117,7 @@ config CRYPTO_WP512
+
+ config CRYPTO_TGR192
+ tristate "Tiger digest algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Tiger hash algorithm 192, 160 and 128-bit hashes
+
+@@ -103,21 +128,42 @@ config CRYPTO_TGR192
+ See also:
+ <http://www.cs.technion.ac.il/~biham/Reports/Tiger/>.
+
++config CRYPTO_ECB
++ tristate "ECB support"
++ select CRYPTO_BLKCIPHER
++ select CRYPTO_MANAGER
++ default m
++ help
++ ECB: Electronic CodeBook mode
++ This is the simplest block cipher algorithm. It simply encrypts
++ the input block by block.
++
++config CRYPTO_CBC
++ tristate "CBC support"
++ select CRYPTO_BLKCIPHER
++ select CRYPTO_MANAGER
++ default m
++ help
++ CBC: Cipher Block Chaining mode
++ This block cipher algorithm is required for IPSec.
++
+ config CRYPTO_DES
+ tristate "DES and Triple DES EDE cipher algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+ config CRYPTO_DES_S390
+ tristate "DES and Triple DES cipher algorithms (s390)"
+- depends on CRYPTO && S390
++ depends on S390
++ select CRYPTO_ALGAPI
++ select CRYPTO_BLKCIPHER
+ help
+ DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+ config CRYPTO_BLOWFISH
+ tristate "Blowfish cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Blowfish cipher algorithm, by Bruce Schneier.
+
+@@ -130,7 +176,8 @@ config CRYPTO_BLOWFISH
+
+ config CRYPTO_TWOFISH
+ tristate "Twofish cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
++ select CRYPTO_TWOFISH_COMMON
+ help
+ Twofish cipher algorithm.
+
+@@ -142,9 +189,47 @@ config CRYPTO_TWOFISH
+ See also:
+ <http://www.schneier.com/twofish.html>
+
++config CRYPTO_TWOFISH_COMMON
++ tristate
++ help
++ Common parts of the Twofish cipher algorithm shared by the
++ generic c and the assembler implementations.
++
++config CRYPTO_TWOFISH_586
++ tristate "Twofish cipher algorithms (i586)"
++ depends on (X86 || UML_X86) && !64BIT
++ select CRYPTO_ALGAPI
++ select CRYPTO_TWOFISH_COMMON
++ help
++ Twofish cipher algorithm.
++
++ Twofish was submitted as an AES (Advanced Encryption Standard)
++ candidate cipher by researchers at CounterPane Systems. It is a
++ 16 round block cipher supporting key sizes of 128, 192, and 256
++ bits.
++
++ See also:
++ <http://www.schneier.com/twofish.html>
++
++config CRYPTO_TWOFISH_X86_64
++ tristate "Twofish cipher algorithm (x86_64)"
++ depends on (X86 || UML_X86) && 64BIT
++ select CRYPTO_ALGAPI
++ select CRYPTO_TWOFISH_COMMON
++ help
++ Twofish cipher algorithm (x86_64).
++
++ Twofish was submitted as an AES (Advanced Encryption Standard)
++ candidate cipher by researchers at CounterPane Systems. It is a
++ 16 round block cipher supporting key sizes of 128, 192, and 256
++ bits.
++
++ See also:
++ <http://www.schneier.com/twofish.html>
++
+ config CRYPTO_SERPENT
+ tristate "Serpent cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Serpent cipher algorithm, by Anderson, Biham & Knudsen.
+
+@@ -157,7 +242,7 @@ config CRYPTO_SERPENT
+
+ config CRYPTO_AES
+ tristate "AES cipher algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ AES cipher algorithms (FIPS-197). AES uses the Rijndael
+ algorithm.
+@@ -177,7 +262,8 @@ config CRYPTO_AES
+
+ config CRYPTO_AES_586
+ tristate "AES cipher algorithms (i586)"
+- depends on CRYPTO && ((X86 || UML_X86) && !64BIT)
++ depends on (X86 || UML_X86) && !64BIT
++ select CRYPTO_ALGAPI
+ help
+ AES cipher algorithms (FIPS-197). AES uses the Rijndael
+ algorithm.
+@@ -197,7 +283,8 @@ config CRYPTO_AES_586
+
+ config CRYPTO_AES_X86_64
+ tristate "AES cipher algorithms (x86_64)"
+- depends on CRYPTO && ((X86 || UML_X86) && 64BIT)
++ depends on (X86 || UML_X86) && 64BIT
++ select CRYPTO_ALGAPI
+ help
+ AES cipher algorithms (FIPS-197). AES uses the Rijndael
+ algorithm.
+@@ -217,7 +304,9 @@ config CRYPTO_AES_X86_64
+
+ config CRYPTO_AES_S390
+ tristate "AES cipher algorithms (s390)"
+- depends on CRYPTO && S390
++ depends on S390
++ select CRYPTO_ALGAPI
++ select CRYPTO_BLKCIPHER
+ help
+ This is the s390 hardware accelerated implementation of the
+ AES cipher algorithms (FIPS-197). AES uses the Rijndael
+@@ -237,21 +326,21 @@ config CRYPTO_AES_S390
+
+ config CRYPTO_CAST5
+ tristate "CAST5 (CAST-128) cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ The CAST5 encryption algorithm (synonymous with CAST-128) is
+ described in RFC2144.
+
+ config CRYPTO_CAST6
+ tristate "CAST6 (CAST-256) cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ The CAST6 encryption algorithm (synonymous with CAST-256) is
+ described in RFC2612.
+
+ config CRYPTO_TEA
+ tristate "TEA, XTEA and XETA cipher algorithms"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ TEA cipher algorithm.
+
+@@ -268,7 +357,7 @@ config CRYPTO_TEA
+
+ config CRYPTO_ARC4
+ tristate "ARC4 cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ ARC4 cipher algorithm.
+
+@@ -279,7 +368,7 @@ config CRYPTO_ARC4
+
+ config CRYPTO_KHAZAD
+ tristate "Khazad cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Khazad cipher algorithm.
+
+@@ -292,7 +381,7 @@ config CRYPTO_KHAZAD
+
+ config CRYPTO_ANUBIS
+ tristate "Anubis cipher algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Anubis cipher algorithm.
+
+@@ -307,7 +396,7 @@ config CRYPTO_ANUBIS
+
+ config CRYPTO_DEFLATE
+ tristate "Deflate compression algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ select ZLIB_INFLATE
+ select ZLIB_DEFLATE
+ help
+@@ -318,7 +407,7 @@ config CRYPTO_DEFLATE
+
+ config CRYPTO_MICHAEL_MIC
+ tristate "Michael MIC keyed digest algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ help
+ Michael MIC is used for message integrity protection in TKIP
+ (IEEE 802.11i). This algorithm is required for TKIP, but it
+@@ -327,7 +416,7 @@ config CRYPTO_MICHAEL_MIC
+
+ config CRYPTO_CRC32C
+ tristate "CRC32c CRC algorithm"
+- depends on CRYPTO
++ select CRYPTO_ALGAPI
+ select LIBCRC32C
+ help
+ Castagnoli, et al Cyclic Redundancy-Check Algorithm. Used
+@@ -337,10 +426,13 @@ config CRYPTO_CRC32C
+
+ config CRYPTO_TEST
+ tristate "Testing module"
+- depends on CRYPTO && m
++ depends on m
++ select CRYPTO_ALGAPI
+ help
+ Quick & dirty crypto test module.
+
+ source "drivers/crypto/Kconfig"
+-endmenu
+
++endif # if CRYPTO
++
++endmenu
+diff --git a/crypto/Makefile b/crypto/Makefile
+index d287b9e..7236620 100644
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -2,11 +2,18 @@
+ # Cryptographic API
+ #
+
+-proc-crypto-$(CONFIG_PROC_FS) = proc.o
++obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o
+
+-obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o \
+- $(proc-crypto-y)
++crypto_algapi-$(CONFIG_PROC_FS) += proc.o
++crypto_algapi-objs := algapi.o $(crypto_algapi-y)
++obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
+
++obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
++
++crypto_hash-objs := hash.o
++obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
++
++obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
+ obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
+ obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
+ obj-$(CONFIG_CRYPTO_MD4) += md4.o
+@@ -16,9 +23,12 @@ obj-$(CONFIG_CRYPTO_SHA256) += sha256.o
+ obj-$(CONFIG_CRYPTO_SHA512) += sha512.o
+ obj-$(CONFIG_CRYPTO_WP512) += wp512.o
+ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
++obj-$(CONFIG_CRYPTO_ECB) += ecb.o
++obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+ obj-$(CONFIG_CRYPTO_DES) += des.o
+ obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
+ obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
++obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
+ obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
+ obj-$(CONFIG_CRYPTO_AES) += aes.o
+ obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
+diff --git a/crypto/aes.c b/crypto/aes.c
+index a038711..e244077 100644
+--- a/crypto/aes.c
++++ b/crypto/aes.c
+@@ -249,13 +249,14 @@ gen_tabs (void)
+ }
+
+ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __le32 *key = (const __le32 *)in_key;
++ u32 *flags = &tfm->crt_flags;
+ u32 i, t, u, v, w;
+
+- if (key_len != 16 && key_len != 24 && key_len != 32) {
++ if (key_len % 8) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+diff --git a/crypto/algapi.c b/crypto/algapi.c
+new file mode 100644
+index 0000000..c915300
+--- /dev/null
++++ b/crypto/algapi.c
+@@ -0,0 +1,486 @@
++/*
++ * Cryptographic API for algorithms (i.e., low-level API).
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/rtnetlink.h>
++#include <linux/string.h>
++
++#include "internal.h"
++
++static LIST_HEAD(crypto_template_list);
++
++void crypto_larval_error(const char *name, u32 type, u32 mask)
++{
++ struct crypto_alg *alg;
++
++ down_read(&crypto_alg_sem);
++ alg = __crypto_alg_lookup(name, type, mask);
++ up_read(&crypto_alg_sem);
++
++ if (alg) {
++ if (crypto_is_larval(alg)) {
++ struct crypto_larval *larval = (void *)alg;
++ complete(&larval->completion);
++ }
++ crypto_mod_put(alg);
++ }
++}
++EXPORT_SYMBOL_GPL(crypto_larval_error);
++
++static inline int crypto_set_driver_name(struct crypto_alg *alg)
++{
++ static const char suffix[] = "-generic";
++ char *driver_name = alg->cra_driver_name;
++ int len;
++
++ if (*driver_name)
++ return 0;
++
++ len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
++ if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
++ return -ENAMETOOLONG;
++
++ memcpy(driver_name + len, suffix, sizeof(suffix));
++ return 0;
++}
++
++static int crypto_check_alg(struct crypto_alg *alg)
++{
++ if (alg->cra_alignmask & (alg->cra_alignmask + 1))
++ return -EINVAL;
++
++ if (alg->cra_alignmask & alg->cra_blocksize)
++ return -EINVAL;
++
++ if (alg->cra_blocksize > PAGE_SIZE / 8)
++ return -EINVAL;
++
++ if (alg->cra_priority < 0)
++ return -EINVAL;
++
++ return crypto_set_driver_name(alg);
++}
++
++static void crypto_destroy_instance(struct crypto_alg *alg)
++{
++ struct crypto_instance *inst = (void *)alg;
++ struct crypto_template *tmpl = inst->tmpl;
++
++ tmpl->free(inst);
++ crypto_tmpl_put(tmpl);
++}
++
++static void crypto_remove_spawns(struct list_head *spawns,
++ struct list_head *list)
++{
++ struct crypto_spawn *spawn, *n;
++
++ list_for_each_entry_safe(spawn, n, spawns, list) {
++ struct crypto_instance *inst = spawn->inst;
++ struct crypto_template *tmpl = inst->tmpl;
++
++ list_del_init(&spawn->list);
++ spawn->alg = NULL;
++
++ if (crypto_is_dead(&inst->alg))
++ continue;
++
++ inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
++ if (!tmpl || !crypto_tmpl_get(tmpl))
++ continue;
++
++ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
++ list_move(&inst->alg.cra_list, list);
++ hlist_del(&inst->list);
++ inst->alg.cra_destroy = crypto_destroy_instance;
++
++ if (!list_empty(&inst->alg.cra_users)) {
++ if (&n->list == spawns)
++ n = list_entry(inst->alg.cra_users.next,
++ typeof(*n), list);
++ __list_splice(&inst->alg.cra_users, spawns->prev);
++ }
++ }
++}
++
++static int __crypto_register_alg(struct crypto_alg *alg,
++ struct list_head *list)
++{
++ struct crypto_alg *q;
++ int ret = -EAGAIN;
++
++ if (crypto_is_dead(alg))
++ goto out;
++
++ INIT_LIST_HEAD(&alg->cra_users);
++
++ ret = -EEXIST;
++
++ atomic_set(&alg->cra_refcnt, 1);
++ list_for_each_entry(q, &crypto_alg_list, cra_list) {
++ if (q == alg)
++ goto out;
++
++ if (crypto_is_moribund(q))
++ continue;
++
++ if (crypto_is_larval(q)) {
++ struct crypto_larval *larval = (void *)q;
++
++ if (strcmp(alg->cra_name, q->cra_name) &&
++ strcmp(alg->cra_driver_name, q->cra_name))
++ continue;
++
++ if (larval->adult)
++ continue;
++ if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
++ continue;
++ if (!crypto_mod_get(alg))
++ continue;
++
++ larval->adult = alg;
++ complete(&larval->completion);
++ continue;
++ }
++
++ if (strcmp(alg->cra_name, q->cra_name))
++ continue;
++
++ if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
++ q->cra_priority > alg->cra_priority)
++ continue;
++
++ crypto_remove_spawns(&q->cra_users, list);
++ }
++
++ list_add(&alg->cra_list, &crypto_alg_list);
++
++ crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
++ ret = 0;
++
++out:
++ return ret;
++}
++
++static void crypto_remove_final(struct list_head *list)
++{
++ struct crypto_alg *alg;
++ struct crypto_alg *n;
++
++ list_for_each_entry_safe(alg, n, list, cra_list) {
++ list_del_init(&alg->cra_list);
++ crypto_alg_put(alg);
++ }
++}
++
++int crypto_register_alg(struct crypto_alg *alg)
++{
++ LIST_HEAD(list);
++ int err;
++
++ err = crypto_check_alg(alg);
++ if (err)
++ return err;
++
++ down_write(&crypto_alg_sem);
++ err = __crypto_register_alg(alg, &list);
++ up_write(&crypto_alg_sem);
++
++ crypto_remove_final(&list);
++ return err;
++}
++EXPORT_SYMBOL_GPL(crypto_register_alg);
++
++static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
++{
++ if (unlikely(list_empty(&alg->cra_list)))
++ return -ENOENT;
++
++ alg->cra_flags |= CRYPTO_ALG_DEAD;
++
++ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
++ list_del_init(&alg->cra_list);
++ crypto_remove_spawns(&alg->cra_users, list);
++
++ return 0;
++}
++
++int crypto_unregister_alg(struct crypto_alg *alg)
++{
++ int ret;
++ LIST_HEAD(list);
++
++ down_write(&crypto_alg_sem);
++ ret = crypto_remove_alg(alg, &list);
++ up_write(&crypto_alg_sem);
++
++ if (ret)
++ return ret;
++
++ BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
++ if (alg->cra_destroy)
++ alg->cra_destroy(alg);
++
++ crypto_remove_final(&list);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(crypto_unregister_alg);
++
++int crypto_register_template(struct crypto_template *tmpl)
++{
++ struct crypto_template *q;
++ int err = -EEXIST;
++
++ down_write(&crypto_alg_sem);
++
++ list_for_each_entry(q, &crypto_template_list, list) {
++ if (q == tmpl)
++ goto out;
++ }
++
++ list_add(&tmpl->list, &crypto_template_list);
++ crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
++ err = 0;
++out:
++ up_write(&crypto_alg_sem);
++ return err;
++}
++EXPORT_SYMBOL_GPL(crypto_register_template);
++
++void crypto_unregister_template(struct crypto_template *tmpl)
++{
++ struct crypto_instance *inst;
++ struct hlist_node *p, *n;
++ struct hlist_head *list;
++ LIST_HEAD(users);
++
++ down_write(&crypto_alg_sem);
++
++ BUG_ON(list_empty(&tmpl->list));
++ list_del_init(&tmpl->list);
++
++ list = &tmpl->instances;
++ hlist_for_each_entry(inst, p, list, list) {
++ int err = crypto_remove_alg(&inst->alg, &users);
++ BUG_ON(err);
++ }
++
++ crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
++
++ up_write(&crypto_alg_sem);
++
++ hlist_for_each_entry_safe(inst, p, n, list, list) {
++ BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
++ tmpl->free(inst);
++ }
++ crypto_remove_final(&users);
++}
++EXPORT_SYMBOL_GPL(crypto_unregister_template);
++
++static struct crypto_template *__crypto_lookup_template(const char *name)
++{
++ struct crypto_template *q, *tmpl = NULL;
++
++ down_read(&crypto_alg_sem);
++ list_for_each_entry(q, &crypto_template_list, list) {
++ if (strcmp(q->name, name))
++ continue;
++ if (unlikely(!crypto_tmpl_get(q)))
++ continue;
++
++ tmpl = q;
++ break;
++ }
++ up_read(&crypto_alg_sem);
++
++ return tmpl;
++}
++
++struct crypto_template *crypto_lookup_template(const char *name)
++{
++ return try_then_request_module(__crypto_lookup_template(name), name);
++}
++EXPORT_SYMBOL_GPL(crypto_lookup_template);
++
++int crypto_register_instance(struct crypto_template *tmpl,
++ struct crypto_instance *inst)
++{
++ LIST_HEAD(list);
++ int err = -EINVAL;
++
++ if (inst->alg.cra_destroy)
++ goto err;
++
++ err = crypto_check_alg(&inst->alg);
++ if (err)
++ goto err;
++
++ inst->alg.cra_module = tmpl->module;
++
++ down_write(&crypto_alg_sem);
++
++ err = __crypto_register_alg(&inst->alg, &list);
++ if (err)
++ goto unlock;
++
++ hlist_add_head(&inst->list, &tmpl->instances);
++ inst->tmpl = tmpl;
++
++unlock:
++ up_write(&crypto_alg_sem);
++
++ crypto_remove_final(&list);
++
++err:
++ return err;
++}
++EXPORT_SYMBOL_GPL(crypto_register_instance);
++
++int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
++ struct crypto_instance *inst)
++{
++ int err = -EAGAIN;
++
++ spawn->inst = inst;
++
++ down_write(&crypto_alg_sem);
++ if (!crypto_is_moribund(alg)) {
++ list_add(&spawn->list, &alg->cra_users);
++ spawn->alg = alg;
++ err = 0;
++ }
++ up_write(&crypto_alg_sem);
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(crypto_init_spawn);
++
++void crypto_drop_spawn(struct crypto_spawn *spawn)
++{
++ down_write(&crypto_alg_sem);
++ list_del(&spawn->list);
++ up_write(&crypto_alg_sem);
++}
++EXPORT_SYMBOL_GPL(crypto_drop_spawn);
++
++struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
++{
++ struct crypto_alg *alg;
++ struct crypto_alg *alg2;
++ struct crypto_tfm *tfm;
++
++ down_read(&crypto_alg_sem);
++ alg = spawn->alg;
++ alg2 = alg;
++ if (alg2)
++ alg2 = crypto_mod_get(alg2);
++ up_read(&crypto_alg_sem);
++
++ if (!alg2) {
++ if (alg)
++ crypto_shoot_alg(alg);
++ return ERR_PTR(-EAGAIN);
++ }
++
++ tfm = __crypto_alloc_tfm(alg, 0);
++ if (IS_ERR(tfm))
++ crypto_mod_put(alg);
++
++ return tfm;
++}
++EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
++
++int crypto_register_notifier(struct notifier_block *nb)
++{
++ return blocking_notifier_chain_register(&crypto_chain, nb);
++}
++EXPORT_SYMBOL_GPL(crypto_register_notifier);
++
++int crypto_unregister_notifier(struct notifier_block *nb)
++{
++ return blocking_notifier_chain_unregister(&crypto_chain, nb);
++}
++EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
++
++struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
++ u32 type, u32 mask)
++{
++ struct rtattr *rta = param;
++ struct crypto_attr_alg *alga;
++
++ if (!RTA_OK(rta, len))
++ return ERR_PTR(-EBADR);
++ if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga))
++ return ERR_PTR(-EINVAL);
++
++ alga = RTA_DATA(rta);
++ alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
++
++ return crypto_alg_mod_lookup(alga->name, type, mask);
++}
++EXPORT_SYMBOL_GPL(crypto_get_attr_alg);
++
++struct crypto_instance *crypto_alloc_instance(const char *name,
++ struct crypto_alg *alg)
++{
++ struct crypto_instance *inst;
++ struct crypto_spawn *spawn;
++ int err;
++
++ inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
++ if (!inst)
++ return ERR_PTR(-ENOMEM);
++
++ err = -ENAMETOOLONG;
++ if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
++ alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
++ goto err_free_inst;
++
++ if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
++ name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
++ goto err_free_inst;
++
++ spawn = crypto_instance_ctx(inst);
++ err = crypto_init_spawn(spawn, alg, inst);
++
++ if (err)
++ goto err_free_inst;
++
++ return inst;
++
++err_free_inst:
++ kfree(inst);
++ return ERR_PTR(err);
++}
++EXPORT_SYMBOL_GPL(crypto_alloc_instance);
++
++static int __init crypto_algapi_init(void)
++{
++ crypto_init_proc();
++ return 0;
++}
++
++static void __exit crypto_algapi_exit(void)
++{
++ crypto_exit_proc();
++}
++
++module_init(crypto_algapi_init);
++module_exit(crypto_algapi_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Cryptographic algorithms API");
+diff --git a/crypto/anubis.c b/crypto/anubis.c
+index 7e2e1a2..1c771f7 100644
+--- a/crypto/anubis.c
++++ b/crypto/anubis.c
+@@ -461,10 +461,11 @@ static const u32 rc[] = {
+ };
+
+ static int anubis_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct anubis_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __be32 *key = (const __be32 *)in_key;
++ u32 *flags = &tfm->crt_flags;
+ int N, R, i, r;
+ u32 kappa[ANUBIS_MAX_N];
+ u32 inter[ANUBIS_MAX_N];
+diff --git a/crypto/api.c b/crypto/api.c
+index c11ec1f..4fb7fa4 100644
+--- a/crypto/api.c
++++ b/crypto/api.c
+@@ -15,70 +15,202 @@
+ *
+ */
+
+-#include <linux/compiler.h>
+-#include <linux/init.h>
+-#include <linux/crypto.h>
++#include <linux/err.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/kmod.h>
+-#include <linux/rwsem.h>
++#include <linux/module.h>
++#include <linux/param.h>
++#include <linux/sched.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include "internal.h"
+
+ LIST_HEAD(crypto_alg_list);
++EXPORT_SYMBOL_GPL(crypto_alg_list);
+ DECLARE_RWSEM(crypto_alg_sem);
++EXPORT_SYMBOL_GPL(crypto_alg_sem);
+
+-static inline int crypto_alg_get(struct crypto_alg *alg)
++BLOCKING_NOTIFIER_HEAD(crypto_chain);
++EXPORT_SYMBOL_GPL(crypto_chain);
++
++static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
++{
++ atomic_inc(&alg->cra_refcnt);
++ return alg;
++}
++
++struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
+ {
+- return try_module_get(alg->cra_module);
++ return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
+ }
++EXPORT_SYMBOL_GPL(crypto_mod_get);
+
+-static inline void crypto_alg_put(struct crypto_alg *alg)
++void crypto_mod_put(struct crypto_alg *alg)
+ {
++ crypto_alg_put(alg);
+ module_put(alg->cra_module);
+ }
++EXPORT_SYMBOL_GPL(crypto_mod_put);
+
+-static struct crypto_alg *crypto_alg_lookup(const char *name)
++struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask)
+ {
+ struct crypto_alg *q, *alg = NULL;
+- int best = -1;
++ int best = -2;
+
+- if (!name)
+- return NULL;
+-
+- down_read(&crypto_alg_sem);
+-
+ list_for_each_entry(q, &crypto_alg_list, cra_list) {
+ int exact, fuzzy;
+
++ if (crypto_is_moribund(q))
++ continue;
++
++ if ((q->cra_flags ^ type) & mask)
++ continue;
++
++ if (crypto_is_larval(q) &&
++ ((struct crypto_larval *)q)->mask != mask)
++ continue;
++
+ exact = !strcmp(q->cra_driver_name, name);
+ fuzzy = !strcmp(q->cra_name, name);
+ if (!exact && !(fuzzy && q->cra_priority > best))
+ continue;
+
+- if (unlikely(!crypto_alg_get(q)))
++ if (unlikely(!crypto_mod_get(q)))
+ continue;
+
+ best = q->cra_priority;
+ if (alg)
+- crypto_alg_put(alg);
++ crypto_mod_put(alg);
+ alg = q;
+
+ if (exact)
+ break;
+ }
+-
++
++ return alg;
++}
++EXPORT_SYMBOL_GPL(__crypto_alg_lookup);
++
++static void crypto_larval_destroy(struct crypto_alg *alg)
++{
++ struct crypto_larval *larval = (void *)alg;
++
++ BUG_ON(!crypto_is_larval(alg));
++ if (larval->adult)
++ crypto_mod_put(larval->adult);
++ kfree(larval);
++}
++
++static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type,
++ u32 mask)
++{
++ struct crypto_alg *alg;
++ struct crypto_larval *larval;
++
++ larval = kzalloc(sizeof(*larval), GFP_KERNEL);
++ if (!larval)
++ return ERR_PTR(-ENOMEM);
++
++ larval->mask = mask;
++ larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
++ larval->alg.cra_priority = -1;
++ larval->alg.cra_destroy = crypto_larval_destroy;
++
++ atomic_set(&larval->alg.cra_refcnt, 2);
++ strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
++ init_completion(&larval->completion);
++
++ down_write(&crypto_alg_sem);
++ alg = __crypto_alg_lookup(name, type, mask);
++ if (!alg) {
++ alg = &larval->alg;
++ list_add(&alg->cra_list, &crypto_alg_list);
++ }
++ up_write(&crypto_alg_sem);
++
++ if (alg != &larval->alg)
++ kfree(larval);
++
++ return alg;
++}
++
++static void crypto_larval_kill(struct crypto_alg *alg)
++{
++ struct crypto_larval *larval = (void *)alg;
++
++ down_write(&crypto_alg_sem);
++ list_del(&alg->cra_list);
++ up_write(&crypto_alg_sem);
++ complete(&larval->completion);
++ crypto_alg_put(alg);
++}
++
++static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
++{
++ struct crypto_larval *larval = (void *)alg;
++
++ wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
++ alg = larval->adult;
++ if (alg) {
++ if (!crypto_mod_get(alg))
++ alg = ERR_PTR(-EAGAIN);
++ } else
++ alg = ERR_PTR(-ENOENT);
++ crypto_mod_put(&larval->alg);
++
++ return alg;
++}
++
++static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
++ u32 mask)
++{
++ struct crypto_alg *alg;
++
++ down_read(&crypto_alg_sem);
++ alg = __crypto_alg_lookup(name, type, mask);
+ up_read(&crypto_alg_sem);
++
+ 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)
++struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+ {
+- return try_then_request_module(crypto_alg_lookup(name), name);
++ struct crypto_alg *alg;
++ struct crypto_alg *larval;
++ int ok;
++
++ if (!name)
++ return ERR_PTR(-ENOENT);
++
++ mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
++ type &= mask;
++
++ alg = try_then_request_module(crypto_alg_lookup(name, type, mask),
++ name);
++ if (alg)
++ return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
++
++ larval = crypto_larval_alloc(name, type, mask);
++ if (IS_ERR(larval) || !crypto_is_larval(larval))
++ return larval;
++
++ ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval);
++ if (ok == NOTIFY_DONE) {
++ request_module("cryptomgr");
++ ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval);
++ }
++
++ if (ok == NOTIFY_STOP)
++ alg = crypto_larval_wait(larval);
++ else {
++ crypto_mod_put(larval);
++ alg = ERR_PTR(-ENOENT);
++ }
++ crypto_larval_kill(larval);
++ return alg;
+ }
++EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
+
+ static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
+ {
+@@ -94,17 +226,18 @@ static int crypto_init_flags(struct cryp
+
+ case CRYPTO_ALG_TYPE_COMPRESS:
+ return crypto_init_compress_flags(tfm, flags);
+-
+- default:
+- break;
+ }
+
+- BUG();
+- return -EINVAL;
++ return 0;
+ }
+
+ static int crypto_init_ops(struct crypto_tfm *tfm)
+ {
++ const struct crypto_type *type = tfm->__crt_alg->cra_type;
++
++ if (type)
++ return type->init(tfm);
++
+ switch (crypto_tfm_alg_type(tfm)) {
+ case CRYPTO_ALG_TYPE_CIPHER:
+ return crypto_init_cipher_ops(tfm);
+@@ -125,6 +258,14 @@ static int crypto_init_ops(struct crypto
+
+ static void crypto_exit_ops(struct crypto_tfm *tfm)
+ {
++ const struct crypto_type *type = tfm->__crt_alg->cra_type;
++
++ if (type) {
++ if (type->exit)
++ type->exit(tfm);
++ return;
++ }
++
+ switch (crypto_tfm_alg_type(tfm)) {
+ case CRYPTO_ALG_TYPE_CIPHER:
+ crypto_exit_cipher_ops(tfm);
+@@ -146,53 +287,67 @@ static void crypto_exit_ops(struct crypt
+
+ static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
+ {
++ const struct crypto_type *type = alg->cra_type;
+ unsigned int len;
+
++ len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
++ if (type)
++ return len + type->ctxsize(alg);
++
+ switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ default:
+ BUG();
+
+ case CRYPTO_ALG_TYPE_CIPHER:
+- len = crypto_cipher_ctxsize(alg, flags);
++ len += crypto_cipher_ctxsize(alg, flags);
+ break;
+
+ case CRYPTO_ALG_TYPE_DIGEST:
+- len = crypto_digest_ctxsize(alg, flags);
++ len += crypto_digest_ctxsize(alg, flags);
+ break;
+
+ case CRYPTO_ALG_TYPE_COMPRESS:
+- len = crypto_compress_ctxsize(alg, flags);
++ len += crypto_compress_ctxsize(alg, flags);
+ break;
+ }
+
+- return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
++ return len;
+ }
+
+-struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
++void crypto_shoot_alg(struct crypto_alg *alg)
++{
++ down_write(&crypto_alg_sem);
++ alg->cra_flags |= CRYPTO_ALG_DYING;
++ up_write(&crypto_alg_sem);
++}
++EXPORT_SYMBOL_GPL(crypto_shoot_alg);
++
++struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, 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;
++ int err = -ENOMEM;
+
+ tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
+ tfm = kzalloc(tfm_size, GFP_KERNEL);
+ if (tfm == NULL)
+- goto out_put;
++ goto out_err;
+
+ tfm->__crt_alg = alg;
+-
+- if (crypto_init_flags(tfm, flags))
++
++ err = crypto_init_flags(tfm, flags);
++ if (err)
+ goto out_free_tfm;
+
+- if (crypto_init_ops(tfm))
++ err = crypto_init_ops(tfm);
++ if (err)
+ goto out_free_tfm;
+
+- if (alg->cra_init && alg->cra_init(tfm))
++ if (alg->cra_init && (err = alg->cra_init(tfm))) {
++ if (err == -EAGAIN)
++ crypto_shoot_alg(alg);
+ goto cra_init_failed;
++ }
+
+ goto out;
+
+@@ -200,13 +355,98 @@ cra_init_failed:
+ crypto_exit_ops(tfm);
+ out_free_tfm:
+ kfree(tfm);
+- tfm = NULL;
+-out_put:
+- crypto_alg_put(alg);
++out_err:
++ tfm = ERR_PTR(err);
+ out:
+ return tfm;
+ }
++EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
++
++struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
++{
++ struct crypto_tfm *tfm = NULL;
++ int err;
++
++ do {
++ struct crypto_alg *alg;
++
++ alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC);
++ err = PTR_ERR(alg);
++ if (IS_ERR(alg))
++ continue;
++
++ tfm = __crypto_alloc_tfm(alg, flags);
++ err = 0;
++ if (IS_ERR(tfm)) {
++ crypto_mod_put(alg);
++ err = PTR_ERR(tfm);
++ tfm = NULL;
++ }
++ } while (err == -EAGAIN && !signal_pending(current));
++
++ return tfm;
++}
+
++/*
++ * crypto_alloc_base - Locate algorithm and allocate transform
++ * @alg_name: Name of algorithm
++ * @type: Type of algorithm
++ * @mask: Mask for type comparison
++ *
++ * crypto_alloc_base() will first attempt to locate an already loaded
++ * algorithm. If that fails and the kernel supports dynamically loadable
++ * modules, it will then attempt to load a module of the same name or
++ * alias. If that fails it will send a query to any loaded crypto manager
++ * to construct an algorithm on the fly. A refcount is grabbed on the
++ * algorithm which is then associated with the new transform.
++ *
++ * The returned transform is of a non-determinate type. Most people
++ * should use one of the more specific allocation functions such as
++ * crypto_alloc_blkcipher.
++ *
++ * In case of error the return value is an error pointer.
++ */
++struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask)
++{
++ struct crypto_tfm *tfm;
++ int err;
++
++ for (;;) {
++ struct crypto_alg *alg;
++
++ alg = crypto_alg_mod_lookup(alg_name, type, mask);
++ if (IS_ERR(alg)) {
++ err = PTR_ERR(alg);
++ goto err;
++ }
++
++ tfm = __crypto_alloc_tfm(alg, 0);
++ if (!IS_ERR(tfm))
++ return tfm;
++
++ crypto_mod_put(alg);
++ err = PTR_ERR(tfm);
++
++err:
++ if (err != -EAGAIN)
++ break;
++ if (signal_pending(current)) {
++ err = -EINTR;
++ break;
++ }
++ }
++
++ return ERR_PTR(err);
++}
++EXPORT_SYMBOL_GPL(crypto_alloc_base);
++
++/*
++ * crypto_free_tfm - Free crypto transform
++ * @tfm: Transform to free
++ *
++ * crypto_free_tfm() frees up the transform and any associated resources,
++ * then drops the refcount on the associated algorithm.
++ */
+ void crypto_free_tfm(struct crypto_tfm *tfm)
+ {
+ struct crypto_alg *alg;
+@@ -221,108 +461,39 @@ void crypto_free_tfm(struct crypto_tfm *
+ if (alg->cra_exit)
+ alg->cra_exit(tfm);
+ crypto_exit_ops(tfm);
+- crypto_alg_put(alg);
++ crypto_mod_put(alg);
+ memset(tfm, 0, size);
+ kfree(tfm);
+ }
+
+-static inline int crypto_set_driver_name(struct crypto_alg *alg)
+-{
+- static const char suffix[] = "-generic";
+- char *driver_name = alg->cra_driver_name;
+- int len;
+-
+- if (*driver_name)
+- return 0;
+-
+- len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+- if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
+- return -ENAMETOOLONG;
+-
+- memcpy(driver_name + len, suffix, sizeof(suffix));
+- return 0;
+-}
+-
+-int crypto_register_alg(struct crypto_alg *alg)
++int crypto_alg_available(const char *name, u32 flags)
+ {
+- int ret;
+- struct crypto_alg *q;
+-
+- if (alg->cra_alignmask & (alg->cra_alignmask + 1))
+- return -EINVAL;
+-
+- if (alg->cra_alignmask & alg->cra_blocksize)
+- return -EINVAL;
+-
+- if (alg->cra_blocksize > PAGE_SIZE / 8)
+- return -EINVAL;
+-
+- if (alg->cra_priority < 0)
+- return -EINVAL;
+-
+- ret = crypto_set_driver_name(alg);
+- if (unlikely(ret))
+- return ret;
+-
+- down_write(&crypto_alg_sem);
++ int ret = 0;
++ struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0,
++ CRYPTO_ALG_ASYNC);
+
+- list_for_each_entry(q, &crypto_alg_list, cra_list) {
+- if (q == alg) {
+- ret = -EEXIST;
+- goto out;
+- }
++ if (!IS_ERR(alg)) {
++ crypto_mod_put(alg);
++ ret = 1;
+ }
+
+- list_add(&alg->cra_list, &crypto_alg_list);
+-out:
+- up_write(&crypto_alg_sem);
+ return ret;
+ }
+
+-int crypto_unregister_alg(struct crypto_alg *alg)
+-{
+- int ret = -ENOENT;
+- struct crypto_alg *q;
+-
+- BUG_ON(!alg->cra_module);
+-
+- down_write(&crypto_alg_sem);
+- list_for_each_entry(q, &crypto_alg_list, cra_list) {
+- if (alg == q) {
+- list_del(&alg->cra_list);
+- ret = 0;
+- goto out;
+- }
+- }
+-out:
+- up_write(&crypto_alg_sem);
+- return ret;
+-}
++EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
++EXPORT_SYMBOL_GPL(crypto_free_tfm);
++EXPORT_SYMBOL_GPL(crypto_alg_available);
+
+-int crypto_alg_available(const char *name, u32 flags)
++int crypto_has_alg(const char *name, u32 type, u32 mask)
+ {
+ int ret = 0;
+- struct crypto_alg *alg = crypto_alg_mod_lookup(name);
++ struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask);
+
+- if (alg) {
+- crypto_alg_put(alg);
++ if (!IS_ERR(alg)) {
++ crypto_mod_put(alg);
+ ret = 1;
+ }
+
+ return ret;
+ }
+-
+-static int __init init_crypto(void)
+-{
+- printk(KERN_INFO "Initializing Cryptographic API\n");
+- crypto_init_proc();
+- return 0;
+-}
+-
+-__initcall(init_crypto);
+-
+-EXPORT_SYMBOL_GPL(crypto_register_alg);
+-EXPORT_SYMBOL_GPL(crypto_unregister_alg);
+-EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
+-EXPORT_SYMBOL_GPL(crypto_free_tfm);
+-EXPORT_SYMBOL_GPL(crypto_alg_available);
++EXPORT_SYMBOL_GPL(crypto_has_alg);
+diff --git a/crypto/arc4.c b/crypto/arc4.c
+index 5edc6a6..8be47e1 100644
+--- a/crypto/arc4.c
++++ b/crypto/arc4.c
+@@ -25,7 +25,7 @@ struct arc4_ctx {
+ };
+
+ static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
+ int i, j = 0, k = 0;
+diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
+new file mode 100644
+index 0000000..034c939
+--- /dev/null
++++ b/crypto/blkcipher.c
+@@ -0,0 +1,405 @@
++/*
++ * Block chaining cipher operations.
++ *
++ * 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 page.
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <linux/crypto.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/scatterlist.h>
++#include <linux/seq_file.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#include "internal.h"
++#include "scatterwalk.h"
++
++enum {
++ BLKCIPHER_WALK_PHYS = 1 << 0,
++ BLKCIPHER_WALK_SLOW = 1 << 1,
++ BLKCIPHER_WALK_COPY = 1 << 2,
++ BLKCIPHER_WALK_DIFF = 1 << 3,
++};
++
++static int blkcipher_walk_next(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk);
++static int blkcipher_walk_first(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk);
++
++static inline void blkcipher_map_src(struct blkcipher_walk *walk)
++{
++ walk->src.virt.addr = scatterwalk_map(&walk->in, 0);
++}
++
++static inline void blkcipher_map_dst(struct blkcipher_walk *walk)
++{
++ walk->dst.virt.addr = scatterwalk_map(&walk->out, 1);
++}
++
++static inline void blkcipher_unmap_src(struct blkcipher_walk *walk)
++{
++ scatterwalk_unmap(walk->src.virt.addr, 0);
++}
++
++static inline void blkcipher_unmap_dst(struct blkcipher_walk *walk)
++{
++ scatterwalk_unmap(walk->dst.virt.addr, 1);
++}
++
++static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len)
++{
++ if (offset_in_page(start + len) < len)
++ return (u8 *)((unsigned long)(start + len) & PAGE_MASK);
++ return start;
++}
++
++static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm,
++ struct blkcipher_walk *walk,
++ unsigned int bsize)
++{
++ u8 *addr;
++ unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
++
++ addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1);
++ addr = blkcipher_get_spot(addr, bsize);
++ scatterwalk_copychunks(addr, &walk->out, bsize, 1);
++ return bsize;
++}
++
++static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk,
++ unsigned int n)
++{
++ n = walk->nbytes - n;
++
++ if (walk->flags & BLKCIPHER_WALK_COPY) {
++ blkcipher_map_dst(walk);
++ memcpy(walk->dst.virt.addr, walk->page, n);
++ blkcipher_unmap_dst(walk);
++ } else if (!(walk->flags & BLKCIPHER_WALK_PHYS)) {
++ blkcipher_unmap_src(walk);
++ if (walk->flags & BLKCIPHER_WALK_DIFF)
++ blkcipher_unmap_dst(walk);
++ }
++
++ scatterwalk_advance(&walk->in, n);
++ scatterwalk_advance(&walk->out, n);
++
++ return n;
++}
++
++int blkcipher_walk_done(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk, int err)
++{
++ struct crypto_blkcipher *tfm = desc->tfm;
++ unsigned int nbytes = 0;
++
++ if (likely(err >= 0)) {
++ unsigned int bsize = crypto_blkcipher_blocksize(tfm);
++ unsigned int n;
++
++ if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW)))
++ n = blkcipher_done_fast(walk, err);
++ else
++ n = blkcipher_done_slow(tfm, walk, bsize);
++
++ nbytes = walk->total - n;
++ err = 0;
++ }
++
++ scatterwalk_done(&walk->in, 0, nbytes);
++ scatterwalk_done(&walk->out, 1, nbytes);
++
++ walk->total = nbytes;
++ walk->nbytes = nbytes;
++
++ if (nbytes) {
++ crypto_yield(desc->flags);
++ return blkcipher_walk_next(desc, walk);
++ }
++
++ if (walk->iv != desc->info)
++ memcpy(desc->info, walk->iv, crypto_blkcipher_ivsize(tfm));
++ if (walk->buffer != walk->page)
++ kfree(walk->buffer);
++ if (walk->page)
++ free_page((unsigned long)walk->page);
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(blkcipher_walk_done);
++
++static inline int blkcipher_next_slow(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk,
++ unsigned int bsize,
++ unsigned int alignmask)
++{
++ unsigned int n;
++
++ if (walk->buffer)
++ goto ok;
++
++ walk->buffer = walk->page;
++ if (walk->buffer)
++ goto ok;
++
++ n = bsize * 2 + (alignmask & ~(crypto_tfm_ctx_alignment() - 1));
++ walk->buffer = kmalloc(n, GFP_ATOMIC);
++ if (!walk->buffer)
++ return blkcipher_walk_done(desc, walk, -ENOMEM);
++
++ok:
++ walk->dst.virt.addr = (u8 *)ALIGN((unsigned long)walk->buffer,
++ alignmask + 1);
++ walk->dst.virt.addr = blkcipher_get_spot(walk->dst.virt.addr, bsize);
++ walk->src.virt.addr = blkcipher_get_spot(walk->dst.virt.addr + bsize,
++ bsize);
++
++ scatterwalk_copychunks(walk->src.virt.addr, &walk->in, bsize, 0);
++
++ walk->nbytes = bsize;
++ walk->flags |= BLKCIPHER_WALK_SLOW;
++
++ return 0;
++}
++
++static inline int blkcipher_next_copy(struct blkcipher_walk *walk)
++{
++ u8 *tmp = walk->page;
++
++ blkcipher_map_src(walk);
++ memcpy(tmp, walk->src.virt.addr, walk->nbytes);
++ blkcipher_unmap_src(walk);
++
++ walk->src.virt.addr = tmp;
++ walk->dst.virt.addr = tmp;
++
++ return 0;
++}
++
++static inline int blkcipher_next_fast(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk)
++{
++ unsigned long diff;
++
++ walk->src.phys.page = scatterwalk_page(&walk->in);
++ walk->src.phys.offset = offset_in_page(walk->in.offset);
++ walk->dst.phys.page = scatterwalk_page(&walk->out);
++ walk->dst.phys.offset = offset_in_page(walk->out.offset);
++
++ if (walk->flags & BLKCIPHER_WALK_PHYS)
++ return 0;
++
++ diff = walk->src.phys.offset - walk->dst.phys.offset;
++ diff |= walk->src.virt.page - walk->dst.virt.page;
++
++ blkcipher_map_src(walk);
++ walk->dst.virt.addr = walk->src.virt.addr;
++
++ if (diff) {
++ walk->flags |= BLKCIPHER_WALK_DIFF;
++ blkcipher_map_dst(walk);
++ }
++
++ return 0;
++}
++
++static int blkcipher_walk_next(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk)
++{
++ struct crypto_blkcipher *tfm = desc->tfm;
++ unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
++ unsigned int bsize = crypto_blkcipher_blocksize(tfm);
++ unsigned int n;
++ int err;
++
++ n = walk->total;
++ if (unlikely(n < bsize)) {
++ desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
++ return blkcipher_walk_done(desc, walk, -EINVAL);
++ }
++
++ walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY |
++ BLKCIPHER_WALK_DIFF);
++ if (!scatterwalk_aligned(&walk->in, alignmask) ||
++ !scatterwalk_aligned(&walk->out, alignmask)) {
++ walk->flags |= BLKCIPHER_WALK_COPY;
++ if (!walk->page) {
++ walk->page = (void *)__get_free_page(GFP_ATOMIC);
++ if (!walk->page)
++ n = 0;
++ }
++ }
++
++ n = scatterwalk_clamp(&walk->in, n);
++ n = scatterwalk_clamp(&walk->out, n);
++
++ if (unlikely(n < bsize)) {
++ err = blkcipher_next_slow(desc, walk, bsize, alignmask);
++ goto set_phys_lowmem;
++ }
++
++ walk->nbytes = n;
++ if (walk->flags & BLKCIPHER_WALK_COPY) {
++ err = blkcipher_next_copy(walk);
++ goto set_phys_lowmem;
++ }
++
++ return blkcipher_next_fast(desc, walk);
++
++set_phys_lowmem:
++ if (walk->flags & BLKCIPHER_WALK_PHYS) {
++ walk->src.phys.page = virt_to_page(walk->src.virt.addr);
++ walk->dst.phys.page = virt_to_page(walk->dst.virt.addr);
++ walk->src.phys.offset &= PAGE_SIZE - 1;
++ walk->dst.phys.offset &= PAGE_SIZE - 1;
++ }
++ return err;
++}
++
++static inline int blkcipher_copy_iv(struct blkcipher_walk *walk,
++ struct crypto_blkcipher *tfm,
++ unsigned int alignmask)
++{
++ unsigned bs = crypto_blkcipher_blocksize(tfm);
++ unsigned int ivsize = crypto_blkcipher_ivsize(tfm);
++ unsigned int size = bs * 2 + ivsize + max(bs, ivsize) - (alignmask + 1);
++ u8 *iv;
++
++ size += alignmask & ~(crypto_tfm_ctx_alignment() - 1);
++ walk->buffer = kmalloc(size, GFP_ATOMIC);
++ if (!walk->buffer)
++ return -ENOMEM;
++
++ iv = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1);
++ iv = blkcipher_get_spot(iv, bs) + bs;
++ iv = blkcipher_get_spot(iv, bs) + bs;
++ iv = blkcipher_get_spot(iv, ivsize);
++
++ walk->iv = memcpy(iv, walk->iv, ivsize);
++ return 0;
++}
++
++int blkcipher_walk_virt(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk)
++{
++ walk->flags &= ~BLKCIPHER_WALK_PHYS;
++ return blkcipher_walk_first(desc, walk);
++}
++EXPORT_SYMBOL_GPL(blkcipher_walk_virt);
++
++int blkcipher_walk_phys(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk)
++{
++ walk->flags |= BLKCIPHER_WALK_PHYS;
++ return blkcipher_walk_first(desc, walk);
++}
++EXPORT_SYMBOL_GPL(blkcipher_walk_phys);
++
++static int blkcipher_walk_first(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk)
++{
++ struct crypto_blkcipher *tfm = desc->tfm;
++ unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
++
++ walk->nbytes = walk->total;
++ if (unlikely(!walk->total))
++ return 0;
++
++ walk->buffer = NULL;
++ walk->iv = desc->info;
++ if (unlikely(((unsigned long)walk->iv & alignmask))) {
++ int err = blkcipher_copy_iv(walk, tfm, alignmask);
++ if (err)
++ return err;
++ }
++
++ scatterwalk_start(&walk->in, walk->in.sg);
++ scatterwalk_start(&walk->out, walk->out.sg);
++ walk->page = NULL;
++
++ return blkcipher_walk_next(desc, walk);
++}
++
++static int setkey(struct crypto_tfm *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher;
++
++ if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++ return -EINVAL;
++ }
++
++ return cipher->setkey(tfm, key, keylen);
++}
++
++static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg)
++{
++ struct blkcipher_alg *cipher = &alg->cra_blkcipher;
++ unsigned int len = alg->cra_ctxsize;
++
++ if (cipher->ivsize) {
++ len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
++ len += cipher->ivsize;
++ }
++
++ return len;
++}
++
++static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm)
++{
++ struct blkcipher_tfm *crt = &tfm->crt_blkcipher;
++ struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
++ unsigned long align = crypto_tfm_alg_alignmask(tfm) + 1;
++ unsigned long addr;
++
++ if (alg->ivsize > PAGE_SIZE / 8)
++ return -EINVAL;
++
++ crt->setkey = setkey;
++ crt->encrypt = alg->encrypt;
++ crt->decrypt = alg->decrypt;
++
++ addr = (unsigned long)crypto_tfm_ctx(tfm);
++ addr = ALIGN(addr, align);
++ addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align);
++ crt->iv = (void *)addr;
++
++ return 0;
++}
++
++static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
++ __attribute_used__;
++static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
++{
++ seq_printf(m, "type : blkcipher\n");
++ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
++ seq_printf(m, "min keysize : %u\n", alg->cra_blkcipher.min_keysize);
++ seq_printf(m, "max keysize : %u\n", alg->cra_blkcipher.max_keysize);
++ seq_printf(m, "ivsize : %u\n", alg->cra_blkcipher.ivsize);
++}
++
++const struct crypto_type crypto_blkcipher_type = {
++ .ctxsize = crypto_blkcipher_ctxsize,
++ .init = crypto_init_blkcipher_ops,
++#ifdef CONFIG_PROC_FS
++ .show = crypto_blkcipher_show,
++#endif
++};
++EXPORT_SYMBOL_GPL(crypto_blkcipher_type);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Generic block chaining cipher type");
+diff --git a/crypto/blowfish.c b/crypto/blowfish.c
+index 490265f..55238c4 100644
+--- a/crypto/blowfish.c
++++ b/crypto/blowfish.c
+@@ -399,8 +399,7 @@ static void bf_decrypt(struct crypto_tfm
+ /*
+ * Calculates the blowfish S and P boxes for encryption and decryption.
+ */
+-static int bf_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++static int bf_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+ {
+ struct bf_ctx *ctx = crypto_tfm_ctx(tfm);
+ u32 *P = ctx->p;
+diff --git a/crypto/cast5.c b/crypto/cast5.c
+index 08eef58..13ea60a 100644
+--- a/crypto/cast5.c
++++ b/crypto/cast5.c
+@@ -769,8 +769,7 @@ static void key_schedule(u32 * x, u32 *
+ }
+
+
+-static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned key_len, u32 *flags)
++static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len)
+ {
+ struct cast5_ctx *c = crypto_tfm_ctx(tfm);
+ int i;
+@@ -778,11 +777,6 @@ static int cast5_setkey(struct crypto_tf
+ u32 z[4];
+ u32 k[16];
+ __be32 p_key[4];
+-
+- if (key_len < 5 || key_len > 16) {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL;
+- }
+
+ c->rr = key_len <= 10 ? 1 : 0;
+
+diff --git a/crypto/cast6.c b/crypto/cast6.c
+index 08e33bf..136ab6d 100644
+--- a/crypto/cast6.c
++++ b/crypto/cast6.c
+@@ -382,14 +382,15 @@ static inline void W(u32 *key, unsigned
+ }
+
+ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned key_len, u32 *flags)
++ unsigned key_len)
+ {
+ int i;
+ u32 key[8];
+ __be32 p_key[8]; /* padded key */
+ struct cast6_ctx *c = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
+
+- if (key_len < 16 || key_len > 32 || key_len % 4 != 0) {
++ if (key_len % 4 != 0) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+diff --git a/crypto/cbc.c b/crypto/cbc.c
+new file mode 100644
+index 0000000..f5542b4
+--- /dev/null
++++ b/crypto/cbc.c
+@@ -0,0 +1,344 @@
++/*
++ * CBC: Cipher Block Chaining mode
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <crypto/algapi.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/scatterlist.h>
++#include <linux/slab.h>
++
++struct crypto_cbc_ctx {
++ struct crypto_cipher *child;
++ void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
++};
++
++static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key,
++ unsigned int keylen)
++{
++ struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(parent);
++ struct crypto_cipher *child = ctx->child;
++ int err;
++
++ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
++ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
++ CRYPTO_TFM_REQ_MASK);
++ err = crypto_cipher_setkey(child, key, keylen);
++ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
++ CRYPTO_TFM_RES_MASK);
++ return err;
++}
++
++static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk,
++ struct crypto_cipher *tfm,
++ void (*xor)(u8 *, const u8 *,
++ unsigned int))
++{
++ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
++ crypto_cipher_alg(tfm)->cia_encrypt;
++ int bsize = crypto_cipher_blocksize(tfm);
++ unsigned int nbytes = walk->nbytes;
++ u8 *src = walk->src.virt.addr;
++ u8 *dst = walk->dst.virt.addr;
++ u8 *iv = walk->iv;
++
++ do {
++ xor(iv, src, bsize);
++ fn(crypto_cipher_tfm(tfm), dst, iv);
++ memcpy(iv, dst, bsize);
++
++ src += bsize;
++ dst += bsize;
++ } while ((nbytes -= bsize) >= bsize);
++
++ return nbytes;
++}
++
++static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk,
++ struct crypto_cipher *tfm,
++ void (*xor)(u8 *, const u8 *,
++ unsigned int))
++{
++ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
++ crypto_cipher_alg(tfm)->cia_encrypt;
++ int bsize = crypto_cipher_blocksize(tfm);
++ unsigned int nbytes = walk->nbytes;
++ u8 *src = walk->src.virt.addr;
++ u8 *iv = walk->iv;
++
++ do {
++ xor(src, iv, bsize);
++ fn(crypto_cipher_tfm(tfm), src, src);
++ iv = src;
++
++ src += bsize;
++ } while ((nbytes -= bsize) >= bsize);
++
++ memcpy(walk->iv, iv, bsize);
++
++ return nbytes;
++}
++
++static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct blkcipher_walk walk;
++ struct crypto_blkcipher *tfm = desc->tfm;
++ struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
++ struct crypto_cipher *child = ctx->child;
++ void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ if (walk.src.virt.addr == walk.dst.virt.addr)
++ nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child,
++ xor);
++ else
++ nbytes = crypto_cbc_encrypt_segment(desc, &walk, child,
++ xor);
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk,
++ struct crypto_cipher *tfm,
++ void (*xor)(u8 *, const u8 *,
++ unsigned int))
++{
++ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
++ crypto_cipher_alg(tfm)->cia_decrypt;
++ int bsize = crypto_cipher_blocksize(tfm);
++ unsigned int nbytes = walk->nbytes;
++ u8 *src = walk->src.virt.addr;
++ u8 *dst = walk->dst.virt.addr;
++ u8 *iv = walk->iv;
++
++ do {
++ fn(crypto_cipher_tfm(tfm), dst, src);
++ xor(dst, iv, bsize);
++ iv = src;
++
++ src += bsize;
++ dst += bsize;
++ } while ((nbytes -= bsize) >= bsize);
++
++ memcpy(walk->iv, iv, bsize);
++
++ return nbytes;
++}
++
++static int crypto_cbc_decrypt_inplace(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk,
++ struct crypto_cipher *tfm,
++ void (*xor)(u8 *, const u8 *,
++ unsigned int))
++{
++ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
++ crypto_cipher_alg(tfm)->cia_decrypt;
++ int bsize = crypto_cipher_blocksize(tfm);
++ unsigned long alignmask = crypto_cipher_alignmask(tfm);
++ unsigned int nbytes = walk->nbytes;
++ u8 *src = walk->src.virt.addr;
++ u8 stack[bsize + alignmask];
++ u8 *first_iv = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
++
++ memcpy(first_iv, walk->iv, bsize);
++
++ /* Start of the last block. */
++ src += nbytes - nbytes % bsize - bsize;
++ memcpy(walk->iv, src, bsize);
++
++ for (;;) {
++ fn(crypto_cipher_tfm(tfm), src, src);
++ if ((nbytes -= bsize) < bsize)
++ break;
++ xor(src, src - bsize, bsize);
++ src -= bsize;
++ }
++
++ xor(src, first_iv, bsize);
++
++ return nbytes;
++}
++
++static int crypto_cbc_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct blkcipher_walk walk;
++ struct crypto_blkcipher *tfm = desc->tfm;
++ struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
++ struct crypto_cipher *child = ctx->child;
++ void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ if (walk.src.virt.addr == walk.dst.virt.addr)
++ nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child,
++ xor);
++ else
++ nbytes = crypto_cbc_decrypt_segment(desc, &walk, child,
++ xor);
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
++{
++ do {
++ *a++ ^= *b++;
++ } while (--bs);
++}
++
++static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
++{
++ u32 *a = (u32 *)dst;
++ u32 *b = (u32 *)src;
++
++ do {
++ *a++ ^= *b++;
++ } while ((bs -= 4));
++}
++
++static void xor_64(u8 *a, const u8 *b, unsigned int bs)
++{
++ ((u32 *)a)[0] ^= ((u32 *)b)[0];
++ ((u32 *)a)[1] ^= ((u32 *)b)[1];
++}
++
++static void xor_128(u8 *a, const u8 *b, unsigned int bs)
++{
++ ((u32 *)a)[0] ^= ((u32 *)b)[0];
++ ((u32 *)a)[1] ^= ((u32 *)b)[1];
++ ((u32 *)a)[2] ^= ((u32 *)b)[2];
++ ((u32 *)a)[3] ^= ((u32 *)b)[3];
++}
++
++static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
++{
++ struct crypto_instance *inst = (void *)tfm->__crt_alg;
++ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
++ struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ switch (crypto_tfm_alg_blocksize(tfm)) {
++ case 8:
++ ctx->xor = xor_64;
++ break;
++
++ case 16:
++ ctx->xor = xor_128;
++ break;
++
++ default:
++ if (crypto_tfm_alg_blocksize(tfm) % 4)
++ ctx->xor = xor_byte;
++ else
++ ctx->xor = xor_quad;
++ }
++
++ tfm = crypto_spawn_tfm(spawn);
++ if (IS_ERR(tfm))
++ return PTR_ERR(tfm);
++
++ ctx->child = crypto_cipher_cast(tfm);
++ return 0;
++}
++
++static void crypto_cbc_exit_tfm(struct crypto_tfm *tfm)
++{
++ struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
++ crypto_free_cipher(ctx->child);
++}
++
++static struct crypto_instance *crypto_cbc_alloc(void *param, unsigned int len)
++{
++ struct crypto_instance *inst;
++ struct crypto_alg *alg;
++
++ alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
++ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
++ if (IS_ERR(alg))
++ return ERR_PTR(PTR_ERR(alg));
++
++ inst = crypto_alloc_instance("cbc", alg);
++ if (IS_ERR(inst))
++ goto out_put_alg;
++
++ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
++ inst->alg.cra_priority = alg->cra_priority;
++ inst->alg.cra_blocksize = alg->cra_blocksize;
++ inst->alg.cra_alignmask = alg->cra_alignmask;
++ inst->alg.cra_type = &crypto_blkcipher_type;
++
++ if (!(alg->cra_blocksize % 4))
++ inst->alg.cra_alignmask |= 3;
++ inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
++ inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
++ inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
++
++ inst->alg.cra_ctxsize = sizeof(struct crypto_cbc_ctx);
++
++ inst->alg.cra_init = crypto_cbc_init_tfm;
++ inst->alg.cra_exit = crypto_cbc_exit_tfm;
++
++ inst->alg.cra_blkcipher.setkey = crypto_cbc_setkey;
++ inst->alg.cra_blkcipher.encrypt = crypto_cbc_encrypt;
++ inst->alg.cra_blkcipher.decrypt = crypto_cbc_decrypt;
++
++out_put_alg:
++ crypto_mod_put(alg);
++ return inst;
++}
++
++static void crypto_cbc_free(struct crypto_instance *inst)
++{
++ crypto_drop_spawn(crypto_instance_ctx(inst));
++ kfree(inst);
++}
++
++static struct crypto_template crypto_cbc_tmpl = {
++ .name = "cbc",
++ .alloc = crypto_cbc_alloc,
++ .free = crypto_cbc_free,
++ .module = THIS_MODULE,
++};
++
++static int __init crypto_cbc_module_init(void)
++{
++ return crypto_register_template(&crypto_cbc_tmpl);
++}
++
++static void __exit crypto_cbc_module_exit(void)
++{
++ crypto_unregister_template(&crypto_cbc_tmpl);
++}
++
++module_init(crypto_cbc_module_init);
++module_exit(crypto_cbc_module_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("CBC block cipher algorithm");
+diff --git a/crypto/cipher.c b/crypto/cipher.c
+index b899eb9..9e03701 100644
+--- a/crypto/cipher.c
++++ b/crypto/cipher.c
+@@ -23,6 +23,28 @@
+ #include "internal.h"
+ #include "scatterwalk.h"
+
++struct cipher_alg_compat {
++ unsigned int cia_min_keysize;
++ unsigned int cia_max_keysize;
++ int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
++ unsigned int keylen);
++ void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
++ void (*cia_decrypt)(struct crypto_tfm *tfm, 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);
++};
++
+ static inline void xor_64(u8 *a, const u8 *b)
+ {
+ ((u32 *)a)[0] ^= ((u32 *)b)[0];
+@@ -45,15 +67,10 @@ static unsigned int crypt_slow(const str
+ u8 buffer[bsize * 2 + alignmask];
+ u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ u8 *dst = src + bsize;
+- unsigned int n;
+-
+- n = scatterwalk_copychunks(src, in, bsize, 0);
+- scatterwalk_advance(in, n);
+
++ scatterwalk_copychunks(src, in, bsize, 0);
+ desc->prfn(desc, dst, src, bsize);
+-
+- n = scatterwalk_copychunks(dst, out, bsize, 1);
+- scatterwalk_advance(out, n);
++ scatterwalk_copychunks(dst, out, bsize, 1);
+
+ return bsize;
+ }
+@@ -64,12 +81,16 @@ static inline unsigned int crypt_fast(co
+ unsigned int nbytes, u8 *tmp)
+ {
+ u8 *src, *dst;
++ u8 *real_src, *real_dst;
++
++ real_src = scatterwalk_map(in, 0);
++ real_dst = scatterwalk_map(out, 1);
+
+- src = in->data;
+- dst = scatterwalk_samebuf(in, out) ? src : out->data;
++ src = real_src;
++ dst = scatterwalk_samebuf(in, out) ? src : real_dst;
+
+ if (tmp) {
+- memcpy(tmp, in->data, nbytes);
++ memcpy(tmp, src, nbytes);
+ src = tmp;
+ dst = tmp;
+ }
+@@ -77,7 +98,10 @@ static inline unsigned int crypt_fast(co
+ nbytes = desc->prfn(desc, dst, src, nbytes);
+
+ if (tmp)
+- memcpy(out->data, tmp, nbytes);
++ memcpy(real_dst, tmp, nbytes);
++
++ scatterwalk_unmap(real_src, 0);
++ scatterwalk_unmap(real_dst, 1);
+
+ scatterwalk_advance(in, nbytes);
+ scatterwalk_advance(out, nbytes);
+@@ -126,9 +150,6 @@ static int crypt(const struct cipher_des
+ tmp = (u8 *)buffer;
+ }
+
+- scatterwalk_map(&walk_in, 0);
+- scatterwalk_map(&walk_out, 1);
+-
+ n = scatterwalk_clamp(&walk_in, n);
+ n = scatterwalk_clamp(&walk_out, n);
+
+@@ -145,7 +166,7 @@ static int crypt(const struct cipher_des
+ if (!nbytes)
+ break;
+
+- crypto_yield(tfm);
++ crypto_yield(tfm->crt_flags);
+ }
+
+ if (buffer)
+@@ -264,12 +285,12 @@ static int setkey(struct crypto_tfm *tfm
+ {
+ struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+
++ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
+ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ } else
+- return cia->cia_setkey(tfm, key, keylen,
+- &tfm->crt_flags);
++ return cia->cia_setkey(tfm, key, keylen);
+ }
+
+ static int ecb_encrypt(struct crypto_tfm *tfm,
+@@ -277,7 +298,7 @@ static int ecb_encrypt(struct crypto_tfm
+ struct scatterlist *src, unsigned int nbytes)
+ {
+ struct cipher_desc desc;
+- struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++ struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_encrypt;
+@@ -292,7 +313,7 @@ static int ecb_decrypt(struct crypto_tfm
+ unsigned int nbytes)
+ {
+ struct cipher_desc desc;
+- struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++ struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_decrypt;
+@@ -307,7 +328,7 @@ static int cbc_encrypt(struct crypto_tfm
+ unsigned int nbytes)
+ {
+ struct cipher_desc desc;
+- struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++ struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_encrypt;
+@@ -323,7 +344,7 @@ static int cbc_encrypt_iv(struct crypto_
+ unsigned int nbytes, u8 *iv)
+ {
+ struct cipher_desc desc;
+- struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++ struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_encrypt;
+@@ -339,7 +360,7 @@ static int cbc_decrypt(struct crypto_tfm
+ unsigned int nbytes)
+ {
+ struct cipher_desc desc;
+- struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++ struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_decrypt;
+@@ -355,7 +376,7 @@ static int cbc_decrypt_iv(struct crypto_
+ unsigned int nbytes, u8 *iv)
+ {
+ struct cipher_desc desc;
+- struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++ struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_decrypt;
+@@ -388,17 +409,67 @@ int crypto_init_cipher_flags(struct cryp
+ return 0;
+ }
+
++static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
++ const u8 *),
++ struct crypto_tfm *tfm,
++ u8 *dst, const u8 *src)
++{
++ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
++ unsigned int size = crypto_tfm_alg_blocksize(tfm);
++ u8 buffer[size + alignmask];
++ u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
++
++ memcpy(tmp, src, size);
++ fn(tfm, tmp, tmp);
++ memcpy(dst, tmp, size);
++}
++
++static void cipher_encrypt_unaligned(struct crypto_tfm *tfm,
++ u8 *dst, const u8 *src)
++{
++ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
++ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++
++ if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
++ cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src);
++ return;
++ }
++
++ cipher->cia_encrypt(tfm, dst, src);
++}
++
++static void cipher_decrypt_unaligned(struct crypto_tfm *tfm,
++ u8 *dst, const u8 *src)
++{
++ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
++ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
++
++ if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
++ cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src);
++ return;
++ }
++
++ cipher->cia_decrypt(tfm, dst, src);
++}
++
+ int crypto_init_cipher_ops(struct crypto_tfm *tfm)
+ {
+ int ret = 0;
+ struct cipher_tfm *ops = &tfm->crt_cipher;
++ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ ops->cit_setkey = setkey;
++ ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ?
++ cipher_encrypt_unaligned : cipher->cia_encrypt;
++ ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
++ cipher_decrypt_unaligned : cipher->cia_decrypt;
+
+ switch (tfm->crt_cipher.cit_mode) {
+ case CRYPTO_TFM_MODE_ECB:
+ ops->cit_encrypt = ecb_encrypt;
+ ops->cit_decrypt = ecb_decrypt;
++ ops->cit_encrypt_iv = nocrypt_iv;
++ ops->cit_decrypt_iv = nocrypt_iv;
+ break;
+
+ case CRYPTO_TFM_MODE_CBC:
+diff --git a/crypto/crc32c.c b/crypto/crc32c.c
+index f266012..0fa7443 100644
+--- a/crypto/crc32c.c
++++ b/crypto/crc32c.c
+@@ -16,14 +16,14 @@
+ #include <linux/string.h>
+ #include <linux/crypto.h>
+ #include <linux/crc32c.h>
+-#include <linux/types.h>
+-#include <asm/byteorder.h>
++#include <linux/kernel.h>
+
+ #define CHKSUM_BLOCK_SIZE 32
+ #define CHKSUM_DIGEST_SIZE 4
+
+ struct chksum_ctx {
+ u32 crc;
++ u32 key;
+ };
+
+ /*
+@@ -35,7 +35,7 @@ static void chksum_init(struct crypto_tf
+ {
+ struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+
+- mctx->crc = ~(u32)0; /* common usage */
++ mctx->crc = mctx->key;
+ }
+
+ /*
+@@ -44,16 +44,15 @@ static void chksum_init(struct crypto_tf
+ * the seed.
+ */
+ static int chksum_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+
+ if (keylen != sizeof(mctx->crc)) {
+- if (flags)
+- *flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+- mctx->crc = __cpu_to_le32(*(u32 *)key);
++ mctx->key = le32_to_cpu(*(__le32 *)key);
+ return 0;
+ }
+
+@@ -61,19 +60,23 @@ static void chksum_update(struct crypto_
+ unsigned int length)
+ {
+ struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+- u32 mcrc;
+
+- mcrc = crc32c(mctx->crc, data, (size_t)length);
+-
+- mctx->crc = mcrc;
++ mctx->crc = crc32c(mctx->crc, data, length);
+ }
+
+ static void chksum_final(struct crypto_tfm *tfm, u8 *out)
+ {
+ struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+- u32 mcrc = (mctx->crc ^ ~(u32)0);
+
+- *(u32 *)out = __le32_to_cpu(mcrc);
++ *(__le32 *)out = ~cpu_to_le32(mctx->crc);
++}
++
++static int crc32c_cra_init(struct crypto_tfm *tfm)
++{
++ struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
++
++ mctx->key = ~0;
++ return 0;
+ }
+
+ static struct crypto_alg alg = {
+@@ -83,6 +86,7 @@ static struct crypto_alg alg = {
+ .cra_ctxsize = sizeof(struct chksum_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(alg.cra_list),
++ .cra_init = crc32c_cra_init,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize= CHKSUM_DIGEST_SIZE,
+diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
+index a0d956b..24dbb5d 100644
+--- a/crypto/crypto_null.c
++++ b/crypto/crypto_null.c
+@@ -48,7 +48,7 @@ static void null_final(struct crypto_tfm
+ { }
+
+ static int null_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ { return 0; }
+
+ static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c
+new file mode 100644
+index 0000000..9b5b156
+--- /dev/null
++++ b/crypto/cryptomgr.c
+@@ -0,0 +1,156 @@
++/*
++ * Create default crypto algorithm instances.
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <linux/crypto.h>
++#include <linux/ctype.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/rtnetlink.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/workqueue.h>
++
++#include "internal.h"
++
++struct cryptomgr_param {
++ struct work_struct work;
++
++ struct {
++ struct rtattr attr;
++ struct crypto_attr_alg data;
++ } alg;
++
++ struct {
++ u32 type;
++ u32 mask;
++ char name[CRYPTO_MAX_ALG_NAME];
++ } larval;
++
++ char template[CRYPTO_MAX_ALG_NAME];
++};
++
++static void cryptomgr_probe(void *data)
++{
++ struct cryptomgr_param *param = data;
++ struct crypto_template *tmpl;
++ struct crypto_instance *inst;
++ int err;
++
++ tmpl = crypto_lookup_template(param->template);
++ if (!tmpl)
++ goto err;
++
++ do {
++ inst = tmpl->alloc(¶m->alg, sizeof(param->alg));
++ if (IS_ERR(inst))
++ err = PTR_ERR(inst);
++ else if ((err = crypto_register_instance(tmpl, inst)))
++ tmpl->free(inst);
++ } while (err == -EAGAIN && !signal_pending(current));
++
++ crypto_tmpl_put(tmpl);
++
++ if (err)
++ goto err;
++
++out:
++ kfree(param);
++ return;
++
++err:
++ crypto_larval_error(param->larval.name, param->larval.type,
++ param->larval.mask);
++ goto out;
++}
++
++static int cryptomgr_schedule_probe(struct crypto_larval *larval)
++{
++ struct cryptomgr_param *param;
++ const char *name = larval->alg.cra_name;
++ const char *p;
++ unsigned int len;
++
++ param = kmalloc(sizeof(*param), GFP_KERNEL);
++ if (!param)
++ goto err;
++
++ for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
++ ;
++
++ len = p - name;
++ if (!len || *p != '(')
++ goto err_free_param;
++
++ memcpy(param->template, name, len);
++ param->template[len] = 0;
++
++ name = p + 1;
++ for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
++ ;
++
++ len = p - name;
++ if (!len || *p != ')' || p[1])
++ goto err_free_param;
++
++ param->alg.attr.rta_len = sizeof(param->alg);
++ param->alg.attr.rta_type = CRYPTOA_ALG;
++ memcpy(param->alg.data.name, name, len);
++ param->alg.data.name[len] = 0;
++
++ memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
++ param->larval.type = larval->alg.cra_flags;
++ param->larval.mask = larval->mask;
++
++ INIT_WORK(¶m->work, cryptomgr_probe, param);
++ schedule_work(¶m->work);
++
++ return NOTIFY_STOP;
++
++err_free_param:
++ kfree(param);
++err:
++ return NOTIFY_OK;
++}
++
++static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
++ void *data)
++{
++ switch (msg) {
++ case CRYPTO_MSG_ALG_REQUEST:
++ return cryptomgr_schedule_probe(data);
++ }
++
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block cryptomgr_notifier = {
++ .notifier_call = cryptomgr_notify,
++};
++
++static int __init cryptomgr_init(void)
++{
++ return crypto_register_notifier(&cryptomgr_notifier);
++}
++
++static void __exit cryptomgr_exit(void)
++{
++ int err = crypto_unregister_notifier(&cryptomgr_notifier);
++ BUG_ON(err);
++}
++
++module_init(cryptomgr_init);
++module_exit(cryptomgr_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Crypto Algorithm Manager");
+diff --git a/crypto/des.c b/crypto/des.c
+index a9d3c23..1df3a71 100644
+--- a/crypto/des.c
++++ b/crypto/des.c
+@@ -784,9 +784,10 @@ static void dkey(u32 *pe, const u8 *k)
+ }
+
+ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ struct des_ctx *dctx = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
+ u32 tmp[DES_EXPKEY_WORDS];
+ int ret;
+
+@@ -864,11 +865,12 @@ static void des_decrypt(struct crypto_tf
+ *
+ */
+ static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ const u32 *K = (const u32 *)key;
+ struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
+ u32 *expkey = dctx->expkey;
++ u32 *flags = &tfm->crt_flags;
+
+ if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+ !((K[2] ^ K[4]) | (K[3] ^ K[5]))))
+diff --git a/crypto/digest.c b/crypto/digest.c
+index 603006a..0155a94 100644
+--- a/crypto/digest.c
++++ b/crypto/digest.c
+@@ -11,29 +11,89 @@
+ * any later version.
+ *
+ */
+-#include <linux/crypto.h>
++
+ #include <linux/mm.h>
+ #include <linux/errno.h>
+ #include <linux/highmem.h>
+-#include <asm/scatterlist.h>
++#include <linux/module.h>
++#include <linux/scatterlist.h>
++
+ #include "internal.h"
++#include "scatterwalk.h"
+
+-static void init(struct crypto_tfm *tfm)
++void crypto_digest_init(struct crypto_tfm *tfm)
+ {
+- tfm->__crt_alg->cra_digest.dia_init(tfm);
++ struct crypto_hash *hash = crypto_hash_cast(tfm);
++ struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
++
++ crypto_hash_init(&desc);
++}
++EXPORT_SYMBOL_GPL(crypto_digest_init);
++
++void crypto_digest_update(struct crypto_tfm *tfm,
++ struct scatterlist *sg, unsigned int nsg)
++{
++ struct crypto_hash *hash = crypto_hash_cast(tfm);
++ struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
++ unsigned int nbytes = 0;
++ unsigned int i;
++
++ for (i = 0; i < nsg; i++)
++ nbytes += sg[i].length;
++
++ crypto_hash_update(&desc, sg, nbytes);
++}
++EXPORT_SYMBOL_GPL(crypto_digest_update);
++
++void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
++{
++ struct crypto_hash *hash = crypto_hash_cast(tfm);
++ struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
++
++ crypto_hash_final(&desc, out);
+ }
++EXPORT_SYMBOL_GPL(crypto_digest_final);
+
+-static void update(struct crypto_tfm *tfm,
+- struct scatterlist *sg, unsigned int nsg)
++void crypto_digest_digest(struct crypto_tfm *tfm,
++ struct scatterlist *sg, unsigned int nsg, u8 *out)
+ {
++ struct crypto_hash *hash = crypto_hash_cast(tfm);
++ struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
++ unsigned int nbytes = 0;
+ unsigned int i;
++
++ for (i = 0; i < nsg; i++)
++ nbytes += sg[i].length;
++
++ crypto_hash_digest(&desc, sg, nbytes, out);
++}
++EXPORT_SYMBOL_GPL(crypto_digest_digest);
++
++static int init(struct hash_desc *desc)
++{
++ struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
++
++ tfm->__crt_alg->cra_digest.dia_init(tfm);
++ return 0;
++}
++
++static int update(struct hash_desc *desc,
++ struct scatterlist *sg, unsigned int nbytes)
++{
++ struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
+ unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
+
+- for (i = 0; i < nsg; i++) {
++ if (!nbytes)
++ return 0;
++
++ for (;;) {
++ struct page *pg = sg->page;
++ unsigned int offset = sg->offset;
++ unsigned int l = sg->length;
+
+- struct page *pg = sg[i].page;
+- unsigned int offset = sg[i].offset;
+- unsigned int l = sg[i].length;
++ if (unlikely(l > nbytes))
++ l = nbytes;
++ nbytes -= l;
+
+ do {
+ unsigned int bytes_from_page = min(l, ((unsigned int)
+@@ -55,41 +115,60 @@ static void update(struct crypto_tfm *tf
+ tfm->__crt_alg->cra_digest.dia_update(tfm, p,
+ bytes_from_page);
+ crypto_kunmap(src, 0);
+- crypto_yield(tfm);
++ crypto_yield(desc->flags);
+ offset = 0;
+ pg++;
+ l -= bytes_from_page;
+ } while (l > 0);
++
++ if (!nbytes)
++ break;
++ sg = sg_next(sg);
+ }
++
++ return 0;
+ }
+
+-static void final(struct crypto_tfm *tfm, u8 *out)
++static int final(struct hash_desc *desc, u8 *out)
+ {
++ struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
++ struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
++
+ if (unlikely((unsigned long)out & alignmask)) {
+- unsigned int size = crypto_tfm_alg_digestsize(tfm);
+- u8 buffer[size + alignmask];
+- u8 *dst = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+- tfm->__crt_alg->cra_digest.dia_final(tfm, dst);
+- memcpy(out, dst, size);
++ unsigned long align = alignmask + 1;
++ unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
++ u8 *dst = (u8 *)ALIGN(addr, align) +
++ ALIGN(tfm->__crt_alg->cra_ctxsize, align);
++
++ digest->dia_final(tfm, dst);
++ memcpy(out, dst, digest->dia_digestsize);
+ } else
+- tfm->__crt_alg->cra_digest.dia_final(tfm, out);
++ digest->dia_final(tfm, out);
++
++ return 0;
++}
++
++static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
++{
++ crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
++ return -ENOSYS;
+ }
+
+-static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
++static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
+ {
+- u32 flags;
+- if (tfm->__crt_alg->cra_digest.dia_setkey == NULL)
+- return -ENOSYS;
+- return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen, &flags);
++ struct crypto_tfm *tfm = crypto_hash_tfm(hash);
++
++ crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
++ return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
+ }
+
+-static void digest(struct crypto_tfm *tfm,
+- struct scatterlist *sg, unsigned int nsg, u8 *out)
++static int digest(struct hash_desc *desc,
++ struct scatterlist *sg, unsigned int nbytes, u8 *out)
+ {
+- init(tfm);
+- update(tfm, sg, nsg);
+- final(tfm, out);
++ init(desc);
++ update(desc, sg, nbytes);
++ return final(desc, out);
+ }
+
+ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
+@@ -99,18 +178,22 @@ int crypto_init_digest_flags(struct cryp
+
+ int crypto_init_digest_ops(struct crypto_tfm *tfm)
+ {
+- struct digest_tfm *ops = &tfm->crt_digest;
++ struct hash_tfm *ops = &tfm->crt_hash;
++ struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
++
++ if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm))
++ return -EINVAL;
+
+- ops->dit_init = init;
+- ops->dit_update = update;
+- ops->dit_final = final;
+- ops->dit_digest = digest;
+- ops->dit_setkey = setkey;
++ ops->init = init;
++ ops->update = update;
++ ops->final = final;
++ ops->digest = digest;
++ ops->setkey = dalg->dia_setkey ? setkey : nosetkey;
++ ops->digestsize = dalg->dia_digestsize;
+
+- return crypto_alloc_hmac_block(tfm);
++ return 0;
+ }
+
+ void crypto_exit_digest_ops(struct crypto_tfm *tfm)
+ {
+- crypto_free_hmac_block(tfm);
+ }
+diff --git a/crypto/ecb.c b/crypto/ecb.c
+new file mode 100644
+index 0000000..f239aa9
+--- /dev/null
++++ b/crypto/ecb.c
+@@ -0,0 +1,181 @@
++/*
++ * ECB: Electronic CodeBook mode
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <crypto/algapi.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/scatterlist.h>
++#include <linux/slab.h>
++
++struct crypto_ecb_ctx {
++ struct crypto_cipher *child;
++};
++
++static int crypto_ecb_setkey(struct crypto_tfm *parent, const u8 *key,
++ unsigned int keylen)
++{
++ struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(parent);
++ struct crypto_cipher *child = ctx->child;
++ int err;
++
++ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
++ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
++ CRYPTO_TFM_REQ_MASK);
++ err = crypto_cipher_setkey(child, key, keylen);
++ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
++ CRYPTO_TFM_RES_MASK);
++ return err;
++}
++
++static int crypto_ecb_crypt(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk,
++ struct crypto_cipher *tfm,
++ void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
++{
++ int bsize = crypto_cipher_blocksize(tfm);
++ unsigned int nbytes;
++ int err;
++
++ err = blkcipher_walk_virt(desc, walk);
++
++ while ((nbytes = walk->nbytes)) {
++ u8 *wsrc = walk->src.virt.addr;
++ u8 *wdst = walk->dst.virt.addr;
++
++ do {
++ fn(crypto_cipher_tfm(tfm), wdst, wsrc);
++
++ wsrc += bsize;
++ wdst += bsize;
++ } while ((nbytes -= bsize) >= bsize);
++
++ err = blkcipher_walk_done(desc, walk, nbytes);
++ }
++
++ return err;
++}
++
++static int crypto_ecb_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct blkcipher_walk walk;
++ struct crypto_blkcipher *tfm = desc->tfm;
++ struct crypto_ecb_ctx *ctx = crypto_blkcipher_ctx(tfm);
++ struct crypto_cipher *child = ctx->child;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return crypto_ecb_crypt(desc, &walk, child,
++ crypto_cipher_alg(child)->cia_encrypt);
++}
++
++static int crypto_ecb_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct blkcipher_walk walk;
++ struct crypto_blkcipher *tfm = desc->tfm;
++ struct crypto_ecb_ctx *ctx = crypto_blkcipher_ctx(tfm);
++ struct crypto_cipher *child = ctx->child;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ return crypto_ecb_crypt(desc, &walk, child,
++ crypto_cipher_alg(child)->cia_decrypt);
++}
++
++static int crypto_ecb_init_tfm(struct crypto_tfm *tfm)
++{
++ struct crypto_instance *inst = (void *)tfm->__crt_alg;
++ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
++ struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ tfm = crypto_spawn_tfm(spawn);
++ if (IS_ERR(tfm))
++ return PTR_ERR(tfm);
++
++ ctx->child = crypto_cipher_cast(tfm);
++ return 0;
++}
++
++static void crypto_ecb_exit_tfm(struct crypto_tfm *tfm)
++{
++ struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(tfm);
++ crypto_free_cipher(ctx->child);
++}
++
++static struct crypto_instance *crypto_ecb_alloc(void *param, unsigned int len)
++{
++ struct crypto_instance *inst;
++ struct crypto_alg *alg;
++
++ alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
++ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
++ if (IS_ERR(alg))
++ return ERR_PTR(PTR_ERR(alg));
++
++ inst = crypto_alloc_instance("ecb", alg);
++ if (IS_ERR(inst))
++ goto out_put_alg;
++
++ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
++ inst->alg.cra_priority = alg->cra_priority;
++ inst->alg.cra_blocksize = alg->cra_blocksize;
++ inst->alg.cra_alignmask = alg->cra_alignmask;
++ inst->alg.cra_type = &crypto_blkcipher_type;
++
++ inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
++ inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
++
++ inst->alg.cra_ctxsize = sizeof(struct crypto_ecb_ctx);
++
++ inst->alg.cra_init = crypto_ecb_init_tfm;
++ inst->alg.cra_exit = crypto_ecb_exit_tfm;
++
++ inst->alg.cra_blkcipher.setkey = crypto_ecb_setkey;
++ inst->alg.cra_blkcipher.encrypt = crypto_ecb_encrypt;
++ inst->alg.cra_blkcipher.decrypt = crypto_ecb_decrypt;
++
++out_put_alg:
++ crypto_mod_put(alg);
++ return inst;
++}
++
++static void crypto_ecb_free(struct crypto_instance *inst)
++{
++ crypto_drop_spawn(crypto_instance_ctx(inst));
++ kfree(inst);
++}
++
++static struct crypto_template crypto_ecb_tmpl = {
++ .name = "ecb",
++ .alloc = crypto_ecb_alloc,
++ .free = crypto_ecb_free,
++ .module = THIS_MODULE,
++};
++
++static int __init crypto_ecb_module_init(void)
++{
++ return crypto_register_template(&crypto_ecb_tmpl);
++}
++
++static void __exit crypto_ecb_module_exit(void)
++{
++ crypto_unregister_template(&crypto_ecb_tmpl);
++}
++
++module_init(crypto_ecb_module_init);
++module_exit(crypto_ecb_module_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("ECB block cipher algorithm");
+diff --git a/crypto/hash.c b/crypto/hash.c
+new file mode 100644
+index 0000000..cdec23d
+--- /dev/null
++++ b/crypto/hash.c
+@@ -0,0 +1,61 @@
++/*
++ * Cryptographic Hash operations.
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++
++#include "internal.h"
++
++static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg)
++{
++ return alg->cra_ctxsize;
++}
++
++static int crypto_init_hash_ops(struct crypto_tfm *tfm)
++{
++ struct hash_tfm *crt = &tfm->crt_hash;
++ struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
++
++ if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
++ return -EINVAL;
++
++ crt->init = alg->init;
++ crt->update = alg->update;
++ crt->final = alg->final;
++ crt->digest = alg->digest;
++ crt->setkey = alg->setkey;
++ crt->digestsize = alg->digestsize;
++
++ return 0;
++}
++
++static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
++ __attribute_used__;
++static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
++{
++ seq_printf(m, "type : hash\n");
++ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
++ seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize);
++}
++
++const struct crypto_type crypto_hash_type = {
++ .ctxsize = crypto_hash_ctxsize,
++ .init = crypto_init_hash_ops,
++#ifdef CONFIG_PROC_FS
++ .show = crypto_hash_show,
++#endif
++};
++EXPORT_SYMBOL_GPL(crypto_hash_type);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Generic cryptographic hash type");
+diff --git a/crypto/hmac.c b/crypto/hmac.c
+index 46120de..b521bcd 100644
+--- a/crypto/hmac.c
++++ b/crypto/hmac.c
+@@ -4,121 +4,261 @@
+ * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
+ *
+ * Copyright (c) 2002 James Morris <jmorris at intercode.com.au>
++ * Copyright (c) 2006 Herbert Xu <herbert at gondor.apana.org.au>
+ *
+ * The HMAC implementation is derived from USAGI.
+ * Copyright (c) 2002 Kazunori Miyazawa <miyazawa at linux-ipv6.org> / USAGI
+ *
+ * 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)
++ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+-#include <linux/crypto.h>
+-#include <linux/mm.h>
+-#include <linux/highmem.h>
+-#include <linux/slab.h>
++
++#include <crypto/algapi.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/scatterlist.h>
+-#include "internal.h"
++#include <linux/slab.h>
++#include <linux/string.h>
++
++struct hmac_ctx {
++ struct crypto_hash *child;
++};
+
+-static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen)
++static inline void *align_ptr(void *p, unsigned int align)
+ {
+- struct scatterlist tmp;
+-
+- sg_set_buf(&tmp, key, keylen);
+- crypto_digest_digest(tfm, &tmp, 1, key);
++ return (void *)ALIGN((unsigned long)p, align);
+ }
+
+-int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
++static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm)
+ {
+- int ret = 0;
++ return align_ptr(crypto_hash_ctx_aligned(tfm) +
++ crypto_hash_blocksize(tfm) * 2 +
++ crypto_hash_digestsize(tfm), sizeof(void *));
++}
+
+- BUG_ON(!crypto_tfm_alg_blocksize(tfm));
+-
+- tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
+- GFP_KERNEL);
+- if (tfm->crt_digest.dit_hmac_block == NULL)
+- ret = -ENOMEM;
++static int hmac_setkey(struct crypto_hash *parent,
++ const u8 *inkey, unsigned int keylen)
++{
++ int bs = crypto_hash_blocksize(parent);
++ int ds = crypto_hash_digestsize(parent);
++ char *ipad = crypto_hash_ctx_aligned(parent);
++ char *opad = ipad + bs;
++ char *digest = opad + bs;
++ struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
++ struct crypto_hash *tfm = ctx->child;
++ unsigned int i;
+
+- return ret;
+-
++ if (keylen > bs) {
++ struct hash_desc desc;
++ struct scatterlist tmp;
++ int err;
++
++ desc.tfm = tfm;
++ desc.flags = crypto_hash_get_flags(parent);
++ desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
++ sg_set_buf(&tmp, inkey, keylen);
++
++ err = crypto_hash_digest(&desc, &tmp, keylen, digest);
++ if (err)
++ return err;
++
++ inkey = digest;
++ keylen = ds;
++ }
++
++ memcpy(ipad, inkey, keylen);
++ memset(ipad + keylen, 0, bs - keylen);
++ memcpy(opad, ipad, bs);
++
++ for (i = 0; i < bs; i++) {
++ ipad[i] ^= 0x36;
++ opad[i] ^= 0x5c;
++ }
++
++ return 0;
++}
++
++static int hmac_init(struct hash_desc *pdesc)
++{
++ struct crypto_hash *parent = pdesc->tfm;
++ int bs = crypto_hash_blocksize(parent);
++ int ds = crypto_hash_digestsize(parent);
++ char *ipad = crypto_hash_ctx_aligned(parent);
++ struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *));
++ struct hash_desc desc;
++ struct scatterlist tmp;
++ int err;
++
++ desc.tfm = ctx->child;
++ desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
++ sg_set_buf(&tmp, ipad, bs);
++
++ err = crypto_hash_init(&desc);
++ if (unlikely(err))
++ return err;
++
++ return crypto_hash_update(&desc, &tmp, bs);
+ }
+
+-void crypto_free_hmac_block(struct crypto_tfm *tfm)
++static int hmac_update(struct hash_desc *pdesc,
++ struct scatterlist *sg, unsigned int nbytes)
+ {
+- kfree(tfm->crt_digest.dit_hmac_block);
++ struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
++ struct hash_desc desc;
++
++ desc.tfm = ctx->child;
++ desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
++
++ return crypto_hash_update(&desc, sg, nbytes);
+ }
+
+-void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
++static int hmac_final(struct hash_desc *pdesc, u8 *out)
+ {
+- unsigned int i;
++ struct crypto_hash *parent = pdesc->tfm;
++ int bs = crypto_hash_blocksize(parent);
++ int ds = crypto_hash_digestsize(parent);
++ char *opad = crypto_hash_ctx_aligned(parent) + bs;
++ char *digest = opad + bs;
++ struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
++ struct hash_desc desc;
+ struct scatterlist tmp;
+- char *ipad = tfm->crt_digest.dit_hmac_block;
+-
+- if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
+- hash_key(tfm, key, *keylen);
+- *keylen = crypto_tfm_alg_digestsize(tfm);
+- }
++ int err;
+
+- memset(ipad, 0, crypto_tfm_alg_blocksize(tfm));
+- memcpy(ipad, key, *keylen);
++ desc.tfm = ctx->child;
++ desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
++ sg_set_buf(&tmp, opad, bs + ds);
+
+- for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
+- ipad[i] ^= 0x36;
++ err = crypto_hash_final(&desc, digest);
++ if (unlikely(err))
++ return err;
+
+- sg_set_buf(&tmp, ipad, crypto_tfm_alg_blocksize(tfm));
+-
+- crypto_digest_init(tfm);
+- crypto_digest_update(tfm, &tmp, 1);
++ return crypto_hash_digest(&desc, &tmp, bs + ds, out);
+ }
+
+-void crypto_hmac_update(struct crypto_tfm *tfm,
+- struct scatterlist *sg, unsigned int nsg)
++static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
++ unsigned int nbytes, u8 *out)
+ {
+- crypto_digest_update(tfm, sg, nsg);
++ struct crypto_hash *parent = pdesc->tfm;
++ int bs = crypto_hash_blocksize(parent);
++ int ds = crypto_hash_digestsize(parent);
++ char *ipad = crypto_hash_ctx_aligned(parent);
++ char *opad = ipad + bs;
++ char *digest = opad + bs;
++ struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
++ struct hash_desc desc;
++ struct scatterlist sg1[2];
++ struct scatterlist sg2[1];
++ int err;
++
++ desc.tfm = ctx->child;
++ desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
++
++ sg_set_buf(sg1, ipad, bs);
++ sg1[1].page = (void *)sg;
++ sg1[1].length = 0;
++ sg_set_buf(sg2, opad, bs + ds);
++
++ err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest);
++ if (unlikely(err))
++ return err;
++
++ return crypto_hash_digest(&desc, sg2, bs + ds, out);
+ }
+
+-void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
+- unsigned int *keylen, u8 *out)
++static int hmac_init_tfm(struct crypto_tfm *tfm)
+ {
+- unsigned int i;
+- struct scatterlist tmp;
+- char *opad = tfm->crt_digest.dit_hmac_block;
+-
+- if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
+- hash_key(tfm, key, *keylen);
+- *keylen = crypto_tfm_alg_digestsize(tfm);
+- }
++ struct crypto_instance *inst = (void *)tfm->__crt_alg;
++ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
++ struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
+
+- crypto_digest_final(tfm, out);
++ tfm = crypto_spawn_tfm(spawn);
++ if (IS_ERR(tfm))
++ return PTR_ERR(tfm);
+
+- memset(opad, 0, crypto_tfm_alg_blocksize(tfm));
+- memcpy(opad, key, *keylen);
+-
+- for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
+- opad[i] ^= 0x5c;
++ ctx->child = crypto_hash_cast(tfm);
++ return 0;
++}
++
++static void hmac_exit_tfm(struct crypto_tfm *tfm)
++{
++ struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
++ crypto_free_hash(ctx->child);
++}
++
++static void hmac_free(struct crypto_instance *inst)
++{
++ crypto_drop_spawn(crypto_instance_ctx(inst));
++ kfree(inst);
++}
++
++static struct crypto_instance *hmac_alloc(void *param, unsigned int len)
++{
++ struct crypto_instance *inst;
++ struct crypto_alg *alg;
++
++ alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH,
++ CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
++ if (IS_ERR(alg))
++ return ERR_PTR(PTR_ERR(alg));
++
++ inst = crypto_alloc_instance("hmac", alg);
++ if (IS_ERR(inst))
++ goto out_put_alg;
++
++ inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
++ inst->alg.cra_priority = alg->cra_priority;
++ inst->alg.cra_blocksize = alg->cra_blocksize;
++ inst->alg.cra_alignmask = alg->cra_alignmask;
++ inst->alg.cra_type = &crypto_hash_type;
+
+- sg_set_buf(&tmp, opad, crypto_tfm_alg_blocksize(tfm));
++ inst->alg.cra_hash.digestsize =
++ (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
++ CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
++ alg->cra_digest.dia_digestsize;
+
+- crypto_digest_init(tfm);
+- crypto_digest_update(tfm, &tmp, 1);
+-
+- sg_set_buf(&tmp, out, crypto_tfm_alg_digestsize(tfm));
+-
+- crypto_digest_update(tfm, &tmp, 1);
+- crypto_digest_final(tfm, out);
++ inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
++ ALIGN(inst->alg.cra_blocksize * 2 +
++ inst->alg.cra_hash.digestsize,
++ sizeof(void *));
++
++ inst->alg.cra_init = hmac_init_tfm;
++ inst->alg.cra_exit = hmac_exit_tfm;
++
++ inst->alg.cra_hash.init = hmac_init;
++ inst->alg.cra_hash.update = hmac_update;
++ inst->alg.cra_hash.final = hmac_final;
++ inst->alg.cra_hash.digest = hmac_digest;
++ inst->alg.cra_hash.setkey = hmac_setkey;
++
++out_put_alg:
++ crypto_mod_put(alg);
++ return inst;
++}
++
++static struct crypto_template hmac_tmpl = {
++ .name = "hmac",
++ .alloc = hmac_alloc,
++ .free = hmac_free,
++ .module = THIS_MODULE,
++};
++
++static int __init hmac_module_init(void)
++{
++ return crypto_register_template(&hmac_tmpl);
+ }
+
+-void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
+- struct scatterlist *sg, unsigned int nsg, u8 *out)
++static void __exit hmac_module_exit(void)
+ {
+- crypto_hmac_init(tfm, key, keylen);
+- crypto_hmac_update(tfm, sg, nsg);
+- crypto_hmac_final(tfm, key, keylen, out);
++ crypto_unregister_template(&hmac_tmpl);
+ }
+
+-EXPORT_SYMBOL_GPL(crypto_hmac_init);
+-EXPORT_SYMBOL_GPL(crypto_hmac_update);
+-EXPORT_SYMBOL_GPL(crypto_hmac_final);
+-EXPORT_SYMBOL_GPL(crypto_hmac);
++module_init(hmac_module_init);
++module_exit(hmac_module_exit);
+
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("HMAC hash algorithm");
+diff --git a/crypto/internal.h b/crypto/internal.h
+index 959e602..2da6ad4 100644
+--- a/crypto/internal.h
++++ b/crypto/internal.h
+@@ -12,19 +12,43 @@
+ */
+ #ifndef _CRYPTO_INTERNAL_H
+ #define _CRYPTO_INTERNAL_H
+-#include <linux/crypto.h>
++
++#include <crypto/algapi.h>
++#include <linux/completion.h>
+ #include <linux/mm.h>
+ #include <linux/highmem.h>
+ #include <linux/interrupt.h>
+ #include <linux/init.h>
+ #include <linux/list.h>
++#include <linux/module.h>
+ #include <linux/kernel.h>
++#include <linux/notifier.h>
+ #include <linux/rwsem.h>
+ #include <linux/slab.h>
+ #include <asm/kmap_types.h>
+
++/* Crypto notification events. */
++enum {
++ CRYPTO_MSG_ALG_REQUEST,
++ CRYPTO_MSG_ALG_REGISTER,
++ CRYPTO_MSG_ALG_UNREGISTER,
++ CRYPTO_MSG_TMPL_REGISTER,
++ CRYPTO_MSG_TMPL_UNREGISTER,
++};
++
++struct crypto_instance;
++struct crypto_template;
++
++struct crypto_larval {
++ struct crypto_alg alg;
++ struct crypto_alg *adult;
++ struct completion completion;
++ u32 mask;
++};
++
+ extern struct list_head crypto_alg_list;
+ extern struct rw_semaphore crypto_alg_sem;
++extern struct blocking_notifier_head crypto_chain;
+
+ extern enum km_type crypto_km_types[];
+
+@@ -43,36 +67,33 @@ static inline void crypto_kunmap(void *v
+ kunmap_atomic(vaddr, crypto_kmap_type(out));
+ }
+
+-static inline void crypto_yield(struct crypto_tfm *tfm)
++static inline void crypto_yield(u32 flags)
+ {
+- if (tfm->crt_flags & CRYPTO_TFM_REQ_MAY_SLEEP)
++ if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
+ cond_resched();
+ }
+
+-#ifdef CONFIG_CRYPTO_HMAC
+-int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
+-void crypto_free_hmac_block(struct crypto_tfm *tfm);
+-#else
+-static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
+-{
+- return 0;
+-}
+-
+-static inline void crypto_free_hmac_block(struct crypto_tfm *tfm)
+-{ }
+-#endif
+-
+ #ifdef CONFIG_PROC_FS
+ void __init crypto_init_proc(void);
++void __exit crypto_exit_proc(void);
+ #else
+ static inline void crypto_init_proc(void)
+ { }
++static inline void crypto_exit_proc(void)
++{ }
+ #endif
+
+ static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
+ int flags)
+ {
+- return alg->cra_ctxsize;
++ unsigned int len = alg->cra_ctxsize;
++
++ if (alg->cra_alignmask) {
++ len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
++ len += alg->cra_digest.dia_digestsize;
++ }
++
++ return len;
+ }
+
+ static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg,
+@@ -96,6 +117,10 @@ static inline unsigned int crypto_compre
+ return alg->cra_ctxsize;
+ }
+
++struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
++struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask);
++struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
++
+ 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);
+@@ -108,5 +133,52 @@ void crypto_exit_digest_ops(struct crypt
+ void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
+ void crypto_exit_compress_ops(struct crypto_tfm *tfm);
+
++void crypto_larval_error(const char *name, u32 type, u32 mask);
++
++void crypto_shoot_alg(struct crypto_alg *alg);
++struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags);
++
++int crypto_register_instance(struct crypto_template *tmpl,
++ struct crypto_instance *inst);
++
++int crypto_register_notifier(struct notifier_block *nb);
++int crypto_unregister_notifier(struct notifier_block *nb);
++
++static inline void crypto_alg_put(struct crypto_alg *alg)
++{
++ if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
++ alg->cra_destroy(alg);
++}
++
++static inline int crypto_tmpl_get(struct crypto_template *tmpl)
++{
++ return try_module_get(tmpl->module);
++}
++
++static inline void crypto_tmpl_put(struct crypto_template *tmpl)
++{
++ module_put(tmpl->module);
++}
++
++static inline int crypto_is_larval(struct crypto_alg *alg)
++{
++ return alg->cra_flags & CRYPTO_ALG_LARVAL;
++}
++
++static inline int crypto_is_dead(struct crypto_alg *alg)
++{
++ return alg->cra_flags & CRYPTO_ALG_DEAD;
++}
++
++static inline int crypto_is_moribund(struct crypto_alg *alg)
++{
++ return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING);
++}
++
++static inline int crypto_notify(unsigned long val, void *v)
++{
++ return blocking_notifier_call_chain(&crypto_chain, val, v);
++}
++
+ #endif /* _CRYPTO_INTERNAL_H */
+
+diff --git a/crypto/khazad.c b/crypto/khazad.c
+index d4c9d36..9fa24a2 100644
+--- a/crypto/khazad.c
++++ b/crypto/khazad.c
+@@ -755,19 +755,13 @@ static const u64 c[KHAZAD_ROUNDS + 1] =
+ };
+
+ static int khazad_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct khazad_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __be32 *key = (const __be32 *)in_key;
+ int r;
+ const u64 *S = T7;
+ u64 K2, K1;
+-
+- if (key_len != 16)
+- {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL;
+- }
+
+ /* key is supposed to be 32-bit aligned */
+ K2 = ((u64)be32_to_cpu(key[0]) << 32) | be32_to_cpu(key[1]);
+diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
+index d061da2..094397b 100644
+--- a/crypto/michael_mic.c
++++ b/crypto/michael_mic.c
+@@ -123,14 +123,13 @@ static void michael_final(struct crypto_
+
+
+ static int michael_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
+ const __le32 *data = (const __le32 *)key;
+
+ if (keylen != 8) {
+- if (flags)
+- *flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+diff --git a/crypto/proc.c b/crypto/proc.c
+index c0a5dd7..dabce06 100644
+--- a/crypto/proc.c
++++ b/crypto/proc.c
+@@ -12,6 +12,8 @@
+ * any later version.
+ *
+ */
++
++#include <asm/atomic.h>
+ #include <linux/init.h>
+ #include <linux/crypto.h>
+ #include <linux/rwsem.h>
+@@ -54,6 +56,7 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "driver : %s\n", alg->cra_driver_name);
+ seq_printf(m, "module : %s\n", module_name(alg->cra_module));
+ seq_printf(m, "priority : %d\n", alg->cra_priority);
++ seq_printf(m, "refcnt : %d\n", atomic_read(&alg->cra_refcnt));
+
+ switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ case CRYPTO_ALG_TYPE_CIPHER:
+@@ -75,7 +78,10 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "type : compression\n");
+ break;
+ default:
+- seq_printf(m, "type : unknown\n");
++ if (alg->cra_type && alg->cra_type->show)
++ alg->cra_type->show(m, alg);
++ else
++ seq_printf(m, "type : unknown\n");
+ break;
+ }
+
+@@ -110,3 +116,8 @@ void __init crypto_init_proc(void)
+ if (proc)
+ proc->proc_fops = &proc_crypto_ops;
+ }
++
++void __exit crypto_exit_proc(void)
++{
++ remove_proc_entry("crypto", NULL);
++}
+diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
+index 2953e2c..35172d3 100644
+--- a/crypto/scatterwalk.c
++++ b/crypto/scatterwalk.c
+@@ -15,9 +15,11 @@
+ */
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
++#include <linux/module.h>
+ #include <linux/pagemap.h>
+ #include <linux/highmem.h>
+-#include <asm/scatterlist.h>
++#include <linux/scatterlist.h>
++
+ #include "internal.h"
+ #include "scatterwalk.h"
+
+@@ -27,88 +29,77 @@ enum km_type crypto_km_types[] = {
+ KM_SOFTIRQ0,
+ KM_SOFTIRQ1,
+ };
++EXPORT_SYMBOL_GPL(crypto_km_types);
+
+-static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
++static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
+ {
+- if (out)
+- memcpy(sgdata, buf, nbytes);
+- else
+- memcpy(buf, sgdata, nbytes);
++ void *src = out ? buf : sgdata;
++ void *dst = out ? sgdata : buf;
++
++ memcpy(dst, src, nbytes);
+ }
+
+ void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
+ {
+- unsigned int rest_of_page;
+-
+ walk->sg = sg;
+
+- walk->page = sg->page;
+- walk->len_this_segment = sg->length;
+-
+ BUG_ON(!sg->length);
+
+- rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1));
+- walk->len_this_page = min(sg->length, rest_of_page);
+ walk->offset = sg->offset;
+ }
++EXPORT_SYMBOL_GPL(scatterwalk_start);
+
+-void scatterwalk_map(struct scatter_walk *walk, int out)
+-{
+- walk->data = crypto_kmap(walk->page, out) + walk->offset;
+-}
+-
+-static inline void scatterwalk_unmap(struct scatter_walk *walk, int out)
++void *scatterwalk_map(struct scatter_walk *walk, int out)
+ {
+- /* walk->data may be pointing the first byte of the next page;
+- however, we know we transfered at least one byte. So,
+- walk->data - 1 will be a virtual address in the mapped page. */
+- crypto_kunmap(walk->data - 1, out);
++ return crypto_kmap(scatterwalk_page(walk), out) +
++ offset_in_page(walk->offset);
+ }
++EXPORT_SYMBOL_GPL(scatterwalk_map);
+
+ static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
+ unsigned int more)
+ {
+ if (out)
+- flush_dcache_page(walk->page);
++ flush_dcache_page(scatterwalk_page(walk));
+
+ if (more) {
+- walk->len_this_segment -= walk->len_this_page;
+-
+- if (walk->len_this_segment) {
+- walk->page++;
+- walk->len_this_page = min(walk->len_this_segment,
+- (unsigned)PAGE_CACHE_SIZE);
+- walk->offset = 0;
+- }
+- else
++ walk->offset += PAGE_SIZE - 1;
++ walk->offset &= PAGE_MASK;
++ if (walk->offset >= walk->sg->offset + walk->sg->length)
+ scatterwalk_start(walk, sg_next(walk->sg));
+ }
+ }
+
+ void scatterwalk_done(struct scatter_walk *walk, int out, int more)
+ {
+- scatterwalk_unmap(walk, out);
+- if (walk->len_this_page == 0 || !more)
++ if (!offset_in_page(walk->offset) || !more)
+ scatterwalk_pagedone(walk, out, more);
+ }
++EXPORT_SYMBOL_GPL(scatterwalk_done);
+
+-/*
+- * Do not call this unless the total length of all of the fragments
+- * has been verified as multiple of the block size.
+- */
+-int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
+- size_t nbytes, int out)
++void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
++ size_t nbytes, int out)
+ {
+- 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;
++ for (;;) {
++ unsigned int len_this_page = scatterwalk_pagelen(walk);
++ u8 *vaddr;
++
++ if (len_this_page > nbytes)
++ len_this_page = nbytes;
++
++ vaddr = scatterwalk_map(walk, out);
++ memcpy_dir(buf, vaddr, len_this_page, out);
++ scatterwalk_unmap(vaddr, out);
++
++ if (nbytes == len_this_page)
++ break;
++
++ buf += len_this_page;
++ nbytes -= len_this_page;
+
+- scatterwalk_unmap(walk, out);
+ scatterwalk_pagedone(walk, out, 1);
+- scatterwalk_map(walk, out);
+ }
+
+- memcpy_dir(buf, walk->data, nbytes, out);
+- return nbytes;
++ scatterwalk_advance(walk, nbytes);
+ }
++EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
+diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h
+index e79925c..f1592cc 100644
+--- a/crypto/scatterwalk.h
++++ b/crypto/scatterwalk.h
+@@ -14,45 +14,42 @@
+
+ #ifndef _CRYPTO_SCATTERWALK_H
+ #define _CRYPTO_SCATTERWALK_H
++
+ #include <linux/mm.h>
+-#include <asm/scatterlist.h>
++#include <linux/scatterlist.h>
+
+-struct scatter_walk {
+- struct scatterlist *sg;
+- struct page *page;
+- void *data;
+- unsigned int len_this_page;
+- unsigned int len_this_segment;
+- unsigned int offset;
+-};
++#include "internal.h"
+
+-/* Define sg_next is an inline routine now in case we want to change
+- scatterlist to a linked list later. */
+ static inline struct scatterlist *sg_next(struct scatterlist *sg)
+ {
+- return sg + 1;
++ return (++sg)->length ? sg : (void *)sg->page;
+ }
+
+-static inline int scatterwalk_samebuf(struct scatter_walk *walk_in,
+- struct scatter_walk *walk_out)
++static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
++ struct scatter_walk *walk_out)
+ {
+- return walk_in->page == walk_out->page &&
+- walk_in->offset == walk_out->offset;
++ return !(((walk_in->sg->page - walk_out->sg->page) << PAGE_SHIFT) +
++ (int)(walk_in->offset - walk_out->offset));
++}
++
++static inline unsigned int scatterwalk_pagelen(struct scatter_walk *walk)
++{
++ unsigned int len = walk->sg->offset + walk->sg->length - walk->offset;
++ unsigned int len_this_page = offset_in_page(~walk->offset) + 1;
++ return len_this_page > len ? len : len_this_page;
+ }
+
+ static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk,
+ unsigned int nbytes)
+ {
+- return nbytes > walk->len_this_page ? walk->len_this_page : nbytes;
++ unsigned int len_this_page = scatterwalk_pagelen(walk);
++ return nbytes > len_this_page ? len_this_page : nbytes;
+ }
+
+ static inline void scatterwalk_advance(struct scatter_walk *walk,
+ unsigned int nbytes)
+ {
+- walk->data += nbytes;
+ walk->offset += nbytes;
+- walk->len_this_page -= nbytes;
+- walk->len_this_segment -= nbytes;
+ }
+
+ static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk,
+@@ -61,9 +58,20 @@ static inline unsigned int scatterwalk_a
+ return !(walk->offset & alignmask);
+ }
+
++static inline struct page *scatterwalk_page(struct scatter_walk *walk)
++{
++ return walk->sg->page + (walk->offset >> PAGE_SHIFT);
++}
++
++static inline void scatterwalk_unmap(void *vaddr, int out)
++{
++ crypto_kunmap(vaddr, out);
++}
++
+ 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);
++void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
++ size_t nbytes, int out);
++void *scatterwalk_map(struct scatter_walk *walk, int out);
+ void scatterwalk_done(struct scatter_walk *walk, int out, int more);
+
+ #endif /* _CRYPTO_SCATTERWALK_H */
+diff --git a/crypto/serpent.c b/crypto/serpent.c
+index de60cdd..2b0a19a 100644
+--- a/crypto/serpent.c
++++ b/crypto/serpent.c
+@@ -216,7 +216,7 @@ struct serpent_ctx {
+
+
+ static int serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+ u32 *k = ctx->expkey;
+@@ -224,13 +224,6 @@ static int serpent_setkey(struct crypto_
+ u32 r0,r1,r2,r3,r4;
+ int i;
+
+- if ((keylen < SERPENT_MIN_KEY_SIZE)
+- || (keylen > SERPENT_MAX_KEY_SIZE))
+- {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL;
+- }
+-
+ /* Copy key, add padding */
+
+ for (i = 0; i < keylen; ++i)
+@@ -371,10 +364,10 @@ static void serpent_encrypt(struct crypt
+ {
+ struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+ const u32
+- *k = ctx->expkey,
+- *s = (const u32 *)src;
+- u32 *d = (u32 *)dst,
+- r0, r1, r2, r3, r4;
++ *k = ctx->expkey;
++ const __le32 *s = (const __le32 *)src;
++ __le32 *d = (__le32 *)dst;
++ u32 r0, r1, r2, r3, r4;
+
+ /*
+ * Note: The conversions between u8* and u32* might cause trouble
+@@ -430,10 +423,10 @@ static void serpent_decrypt(struct crypt
+ {
+ struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+ const u32
+- *k = ((struct serpent_ctx *)ctx)->expkey,
+- *s = (const u32 *)src;
+- u32 *d = (u32 *)dst,
+- r0, r1, r2, r3, r4;
++ *k = ((struct serpent_ctx *)ctx)->expkey;
++ const __le32 *s = (const __le32 *)src;
++ __le32 *d = (__le32 *)dst;
++ u32 r0, r1, r2, r3, r4;
+
+ r0 = le32_to_cpu(s[0]);
+ r1 = le32_to_cpu(s[1]);
+@@ -497,21 +490,15 @@ static struct crypto_alg serpent_alg = {
+ };
+
+ static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags)
++ unsigned int keylen)
+ {
+ u8 rev_key[SERPENT_MAX_KEY_SIZE];
+ int i;
+
+- if ((keylen < SERPENT_MIN_KEY_SIZE)
+- || (keylen > SERPENT_MAX_KEY_SIZE)) {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL;
+- }
+-
+ for (i = 0; i < keylen; ++i)
+ rev_key[keylen - i - 1] = key[i];
+
+- return serpent_setkey(tfm, rev_key, keylen, flags);
++ return serpent_setkey(tfm, rev_key, keylen);
+ }
+
+ static void tnepres_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+diff --git a/crypto/sha1.c b/crypto/sha1.c
+index 6c77b68..1bba551 100644
+--- a/crypto/sha1.c
++++ b/crypto/sha1.c
+@@ -109,6 +109,7 @@ static void sha1_final(struct crypto_tfm
+
+ static struct crypto_alg alg = {
+ .cra_name = "sha1",
++ .cra_driver_name= "sha1-generic",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct sha1_ctx),
+@@ -137,3 +138,5 @@ module_exit(fini);
+
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
++
++MODULE_ALIAS("sha1-generic");
+diff --git a/crypto/sha256.c b/crypto/sha256.c
+index bc71d85..716195b 100644
+--- a/crypto/sha256.c
++++ b/crypto/sha256.c
+@@ -309,6 +309,7 @@ static void sha256_final(struct crypto_t
+
+ static struct crypto_alg alg = {
+ .cra_name = "sha256",
++ .cra_driver_name= "sha256-generic",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = SHA256_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct sha256_ctx),
+@@ -337,3 +338,5 @@ module_exit(fini);
+
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm");
++
++MODULE_ALIAS("sha256-generic");
+diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
+index e52f56c..8330742 100644
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -17,6 +17,7 @@
+ *
+ */
+
++#include <linux/err.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/mm.h>
+@@ -54,8 +55,6 @@
+ */
+ #define ENCRYPT 1
+ #define DECRYPT 0
+-#define MODE_ECB 1
+-#define MODE_CBC 0
+
+ static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
+
+@@ -89,9 +88,11 @@ static void test_hash(char *algo, struct
+ unsigned int i, j, k, temp;
+ struct scatterlist sg[8];
+ char result[64];
+- struct crypto_tfm *tfm;
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
+ struct hash_testvec *hash_tv;
+ unsigned int tsize;
++ int ret;
+
+ printk("\ntesting %s\n", algo);
+
+@@ -105,30 +106,42 @@ static void test_hash(char *algo, struct
+
+ memcpy(tvmem, template, tsize);
+ hash_tv = (void *)tvmem;
+- tfm = crypto_alloc_tfm(algo, 0);
+- if (tfm == NULL) {
+- printk("failed to load transform for %s\n", algo);
++
++ tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ printk("failed to load transform for %s: %ld\n", algo,
++ PTR_ERR(tfm));
+ return;
+ }
+
++ desc.tfm = tfm;
++ desc.flags = 0;
++
+ for (i = 0; i < tcount; i++) {
+ printk("test %u:\n", i + 1);
+ memset(result, 0, 64);
+
+ sg_set_buf(&sg[0], hash_tv[i].plaintext, hash_tv[i].psize);
+
+- crypto_digest_init(tfm);
+- if (tfm->crt_u.digest.dit_setkey) {
+- crypto_digest_setkey(tfm, hash_tv[i].key,
+- hash_tv[i].ksize);
++ if (hash_tv[i].ksize) {
++ ret = crypto_hash_setkey(tfm, hash_tv[i].key,
++ hash_tv[i].ksize);
++ if (ret) {
++ printk("setkey() failed ret=%d\n", ret);
++ goto out;
++ }
++ }
++
++ ret = crypto_hash_digest(&desc, sg, hash_tv[i].psize, result);
++ if (ret) {
++ printk("digest () failed ret=%d\n", ret);
++ goto out;
+ }
+- crypto_digest_update(tfm, sg, 1);
+- crypto_digest_final(tfm, result);
+
+- hexdump(result, crypto_tfm_alg_digestsize(tfm));
++ hexdump(result, crypto_hash_digestsize(tfm));
+ printk("%s\n",
+ memcmp(result, hash_tv[i].digest,
+- crypto_tfm_alg_digestsize(tfm)) ?
++ crypto_hash_digestsize(tfm)) ?
+ "fail" : "pass");
+ }
+
+@@ -154,127 +167,56 @@ static void test_hash(char *algo, struct
+ hash_tv[i].tap[k]);
+ }
+
+- crypto_digest_digest(tfm, sg, hash_tv[i].np, result);
+-
+- hexdump(result, crypto_tfm_alg_digestsize(tfm));
+- printk("%s\n",
+- memcmp(result, hash_tv[i].digest,
+- crypto_tfm_alg_digestsize(tfm)) ?
+- "fail" : "pass");
+- }
+- }
+-
+- crypto_free_tfm(tfm);
+-}
+-
+-
+-#ifdef CONFIG_CRYPTO_HMAC
+-
+-static void test_hmac(char *algo, struct hmac_testvec *template,
+- unsigned int tcount)
+-{
+- unsigned int i, j, k, temp;
+- struct scatterlist sg[8];
+- char result[64];
+- struct crypto_tfm *tfm;
+- struct hmac_testvec *hmac_tv;
+- unsigned int tsize, klen;
+-
+- tfm = crypto_alloc_tfm(algo, 0);
+- if (tfm == NULL) {
+- printk("failed to load transform for %s\n", algo);
+- return;
+- }
+-
+- printk("\ntesting hmac_%s\n", algo);
+-
+- tsize = sizeof(struct hmac_testvec);
+- tsize *= tcount;
+- if (tsize > TVMEMSIZE) {
+- printk("template (%u) too big for tvmem (%u)\n", tsize,
+- TVMEMSIZE);
+- goto out;
+- }
+-
+- memcpy(tvmem, template, tsize);
+- hmac_tv = (void *)tvmem;
+-
+- for (i = 0; i < tcount; i++) {
+- printk("test %u:\n", i + 1);
+- memset(result, 0, sizeof (result));
+-
+- klen = hmac_tv[i].ksize;
+- sg_set_buf(&sg[0], hmac_tv[i].plaintext, hmac_tv[i].psize);
+-
+- crypto_hmac(tfm, hmac_tv[i].key, &klen, sg, 1, result);
++ if (hash_tv[i].ksize) {
++ ret = crypto_hash_setkey(tfm, hash_tv[i].key,
++ hash_tv[i].ksize);
+
+- hexdump(result, crypto_tfm_alg_digestsize(tfm));
+- printk("%s\n",
+- memcmp(result, hmac_tv[i].digest,
+- crypto_tfm_alg_digestsize(tfm)) ? "fail" :
+- "pass");
+- }
+-
+- printk("\ntesting hmac_%s across pages\n", algo);
+-
+- memset(xbuf, 0, XBUFSIZE);
+-
+- j = 0;
+- for (i = 0; i < tcount; i++) {
+- if (hmac_tv[i].np) {
+- j++;
+- printk("test %u:\n",j);
+- memset(result, 0, 64);
+-
+- temp = 0;
+- klen = hmac_tv[i].ksize;
+- for (k = 0; k < hmac_tv[i].np; k++) {
+- memcpy(&xbuf[IDX[k]],
+- hmac_tv[i].plaintext + temp,
+- hmac_tv[i].tap[k]);
+- temp += hmac_tv[i].tap[k];
+- sg_set_buf(&sg[k], &xbuf[IDX[k]],
+- hmac_tv[i].tap[k]);
++ if (ret) {
++ printk("setkey() failed ret=%d\n", ret);
++ goto out;
++ }
+ }
+
+- crypto_hmac(tfm, hmac_tv[i].key, &klen, sg,
+- hmac_tv[i].np, result);
+- hexdump(result, crypto_tfm_alg_digestsize(tfm));
++ ret = crypto_hash_digest(&desc, sg, hash_tv[i].psize,
++ result);
++ if (ret) {
++ printk("digest () failed ret=%d\n", ret);
++ goto out;
++ }
+
++ hexdump(result, crypto_hash_digestsize(tfm));
+ printk("%s\n",
+- memcmp(result, hmac_tv[i].digest,
+- crypto_tfm_alg_digestsize(tfm)) ?
++ memcmp(result, hash_tv[i].digest,
++ crypto_hash_digestsize(tfm)) ?
+ "fail" : "pass");
+ }
+ }
++
+ out:
+- crypto_free_tfm(tfm);
++ crypto_free_hash(tfm);
+ }
+
+-#endif /* CONFIG_CRYPTO_HMAC */
+-
+-static void test_cipher(char *algo, int mode, int enc,
++static void test_cipher(char *algo, int enc,
+ struct cipher_testvec *template, unsigned int tcount)
+ {
+ unsigned int ret, i, j, k, temp;
+ unsigned int tsize;
++ unsigned int iv_len;
++ unsigned int len;
+ char *q;
+- struct crypto_tfm *tfm;
++ struct crypto_blkcipher *tfm;
+ char *key;
+ struct cipher_testvec *cipher_tv;
++ struct blkcipher_desc desc;
+ struct scatterlist sg[8];
+- const char *e, *m;
++ const char *e;
+
+ if (enc == ENCRYPT)
+ e = "encryption";
+ else
+ e = "decryption";
+- if (mode == MODE_ECB)
+- m = "ECB";
+- else
+- m = "CBC";
+
+- printk("\ntesting %s %s %s\n", algo, m, e);
++ printk("\ntesting %s %s\n", algo, e);
+
+ tsize = sizeof (struct cipher_testvec);
+ tsize *= tcount;
+@@ -288,15 +230,15 @@ static void test_cipher(char *algo, int
+ memcpy(tvmem, template, tsize);
+ cipher_tv = (void *)tvmem;
+
+- if (mode)
+- tfm = crypto_alloc_tfm(algo, 0);
+- else
+- tfm = crypto_alloc_tfm(algo, CRYPTO_TFM_MODE_CBC);
++ tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC);
+
+- if (tfm == NULL) {
+- printk("failed to load transform for %s %s\n", algo, m);
++ if (IS_ERR(tfm)) {
++ printk("failed to load transform for %s: %ld\n", algo,
++ PTR_ERR(tfm));
+ return;
+ }
++ desc.tfm = tfm;
++ desc.flags = 0;
+
+ j = 0;
+ for (i = 0; i < tcount; i++) {
+@@ -305,14 +247,17 @@ static void test_cipher(char *algo, int
+ printk("test %u (%d bit key):\n",
+ j, cipher_tv[i].klen * 8);
+
+- tfm->crt_flags = 0;
++ crypto_blkcipher_clear_flags(tfm, ~0);
+ if (cipher_tv[i].wk)
+- tfm->crt_flags |= CRYPTO_TFM_REQ_WEAK_KEY;
++ crypto_blkcipher_set_flags(
++ tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+ key = cipher_tv[i].key;
+
+- ret = crypto_cipher_setkey(tfm, key, cipher_tv[i].klen);
++ ret = crypto_blkcipher_setkey(tfm, key,
++ cipher_tv[i].klen);
+ if (ret) {
+- printk("setkey() failed flags=%x\n", tfm->crt_flags);
++ printk("setkey() failed flags=%x\n",
++ crypto_blkcipher_get_flags(tfm));
+
+ if (!cipher_tv[i].fail)
+ goto out;
+@@ -321,19 +266,19 @@ static void test_cipher(char *algo, int
+ sg_set_buf(&sg[0], cipher_tv[i].input,
+ cipher_tv[i].ilen);
+
+- if (!mode) {
+- crypto_cipher_set_iv(tfm, cipher_tv[i].iv,
+- crypto_tfm_alg_ivsize(tfm));
+- }
+-
+- if (enc)
+- ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);
+- else
+- ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);
++ iv_len = crypto_blkcipher_ivsize(tfm);
++ if (iv_len)
++ crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv,
++ iv_len);
+
++ len = cipher_tv[i].ilen;
++ ret = enc ?
++ crypto_blkcipher_encrypt(&desc, sg, sg, len) :
++ crypto_blkcipher_decrypt(&desc, sg, sg, len);
+
+ if (ret) {
+- printk("%s () failed flags=%x\n", e, tfm->crt_flags);
++ printk("%s () failed flags=%x\n", e,
++ desc.flags);
+ goto out;
+ }
+
+@@ -346,7 +291,7 @@ static void test_cipher(char *algo, int
+ }
+ }
+
+- printk("\ntesting %s %s %s across pages (chunking)\n", algo, m, e);
++ printk("\ntesting %s %s across pages (chunking)\n", algo, e);
+ memset(xbuf, 0, XBUFSIZE);
+
+ j = 0;
+@@ -356,14 +301,17 @@ static void test_cipher(char *algo, int
+ printk("test %u (%d bit key):\n",
+ j, cipher_tv[i].klen * 8);
+
+- tfm->crt_flags = 0;
++ crypto_blkcipher_clear_flags(tfm, ~0);
+ if (cipher_tv[i].wk)
+- tfm->crt_flags |= CRYPTO_TFM_REQ_WEAK_KEY;
++ crypto_blkcipher_set_flags(
++ tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+ key = cipher_tv[i].key;
+
+- ret = crypto_cipher_setkey(tfm, key, cipher_tv[i].klen);
++ ret = crypto_blkcipher_setkey(tfm, key,
++ cipher_tv[i].klen);
+ if (ret) {
+- printk("setkey() failed flags=%x\n", tfm->crt_flags);
++ printk("setkey() failed flags=%x\n",
++ crypto_blkcipher_get_flags(tfm));
+
+ if (!cipher_tv[i].fail)
+ goto out;
+@@ -379,18 +327,19 @@ static void test_cipher(char *algo, int
+ cipher_tv[i].tap[k]);
+ }
+
+- if (!mode) {
+- crypto_cipher_set_iv(tfm, cipher_tv[i].iv,
+- crypto_tfm_alg_ivsize(tfm));
+- }
++ iv_len = crypto_blkcipher_ivsize(tfm);
++ if (iv_len)
++ crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv,
++ iv_len);
+
+- if (enc)
+- ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);
+- else
+- ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);
++ len = cipher_tv[i].ilen;
++ ret = enc ?
++ crypto_blkcipher_encrypt(&desc, sg, sg, len) :
++ crypto_blkcipher_decrypt(&desc, sg, sg, len);
+
+ if (ret) {
+- printk("%s () failed flags=%x\n", e, tfm->crt_flags);
++ printk("%s () failed flags=%x\n", e,
++ desc.flags);
+ goto out;
+ }
+
+@@ -409,10 +358,10 @@ static void test_cipher(char *algo, int
+ }
+
+ out:
+- crypto_free_tfm(tfm);
++ crypto_free_blkcipher(tfm);
+ }
+
+-static int test_cipher_jiffies(struct crypto_tfm *tfm, int enc, char *p,
++static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, char *p,
+ int blen, int sec)
+ {
+ struct scatterlist sg[1];
+@@ -425,9 +374,9 @@ static int test_cipher_jiffies(struct cr
+ for (start = jiffies, end = start + sec * HZ, bcount = 0;
+ time_before(jiffies, end); bcount++) {
+ if (enc)
+- ret = crypto_cipher_encrypt(tfm, sg, sg, blen);
++ ret = crypto_blkcipher_encrypt(desc, sg, sg, blen);
+ else
+- ret = crypto_cipher_decrypt(tfm, sg, sg, blen);
++ ret = crypto_blkcipher_decrypt(desc, sg, sg, blen);
+
+ if (ret)
+ return ret;
+@@ -438,7 +387,7 @@ static int test_cipher_jiffies(struct cr
+ return 0;
+ }
+
+-static int test_cipher_cycles(struct crypto_tfm *tfm, int enc, char *p,
++static int test_cipher_cycles(struct blkcipher_desc *desc, int enc, char *p,
+ int blen)
+ {
+ struct scatterlist sg[1];
+@@ -454,9 +403,9 @@ static int test_cipher_cycles(struct cry
+ /* Warm-up run. */
+ for (i = 0; i < 4; i++) {
+ if (enc)
+- ret = crypto_cipher_encrypt(tfm, sg, sg, blen);
++ ret = crypto_blkcipher_encrypt(desc, sg, sg, blen);
+ else
+- ret = crypto_cipher_decrypt(tfm, sg, sg, blen);
++ ret = crypto_blkcipher_decrypt(desc, sg, sg, blen);
+
+ if (ret)
+ goto out;
+@@ -468,9 +417,9 @@ static int test_cipher_cycles(struct cry
+
+ start = get_cycles();
+ if (enc)
+- ret = crypto_cipher_encrypt(tfm, sg, sg, blen);
++ ret = crypto_blkcipher_encrypt(desc, sg, sg, blen);
+ else
+- ret = crypto_cipher_decrypt(tfm, sg, sg, blen);
++ ret = crypto_blkcipher_decrypt(desc, sg, sg, blen);
+ end = get_cycles();
+
+ if (ret)
+@@ -490,35 +439,32 @@ out:
+ return ret;
+ }
+
+-static void test_cipher_speed(char *algo, int mode, int enc, unsigned int sec,
++static void test_cipher_speed(char *algo, int enc, unsigned int sec,
+ struct cipher_testvec *template,
+ unsigned int tcount, struct cipher_speed *speed)
+ {
+ unsigned int ret, i, j, iv_len;
+ unsigned char *key, *p, iv[128];
+- struct crypto_tfm *tfm;
+- const char *e, *m;
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ const char *e;
+
+ if (enc == ENCRYPT)
+ e = "encryption";
+ else
+ e = "decryption";
+- if (mode == MODE_ECB)
+- m = "ECB";
+- else
+- m = "CBC";
+
+- printk("\ntesting speed of %s %s %s\n", algo, m, e);
++ printk("\ntesting speed of %s %s\n", algo, e);
+
+- if (mode)
+- tfm = crypto_alloc_tfm(algo, 0);
+- else
+- tfm = crypto_alloc_tfm(algo, CRYPTO_TFM_MODE_CBC);
++ tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC);
+
+- if (tfm == NULL) {
+- printk("failed to load transform for %s %s\n", algo, m);
++ if (IS_ERR(tfm)) {
++ printk("failed to load transform for %s: %ld\n", algo,
++ PTR_ERR(tfm));
+ return;
+ }
++ desc.tfm = tfm;
++ desc.flags = 0;
+
+ for (i = 0; speed[i].klen != 0; i++) {
+ if ((speed[i].blen + speed[i].klen) > TVMEMSIZE) {
+@@ -542,125 +488,231 @@ static void test_cipher_speed(char *algo
+ }
+ p = (unsigned char *)tvmem + speed[i].klen;
+
+- ret = crypto_cipher_setkey(tfm, key, speed[i].klen);
++ ret = crypto_blkcipher_setkey(tfm, key, speed[i].klen);
+ if (ret) {
+- printk("setkey() failed flags=%x\n", tfm->crt_flags);
++ printk("setkey() failed flags=%x\n",
++ crypto_blkcipher_get_flags(tfm));
+ goto out;
+ }
+
+- if (!mode) {
+- iv_len = crypto_tfm_alg_ivsize(tfm);
++ iv_len = crypto_blkcipher_ivsize(tfm);
++ if (iv_len) {
+ memset(&iv, 0xff, iv_len);
+- crypto_cipher_set_iv(tfm, iv, iv_len);
++ crypto_blkcipher_set_iv(tfm, iv, iv_len);
+ }
+
+ if (sec)
+- ret = test_cipher_jiffies(tfm, enc, p, speed[i].blen,
++ ret = test_cipher_jiffies(&desc, enc, p, speed[i].blen,
+ sec);
+ else
+- ret = test_cipher_cycles(tfm, enc, p, speed[i].blen);
++ ret = test_cipher_cycles(&desc, enc, p, speed[i].blen);
+
+ if (ret) {
+- printk("%s() failed flags=%x\n", e, tfm->crt_flags);
++ printk("%s() failed flags=%x\n", e, desc.flags);
+ break;
+ }
+ }
+
+ out:
+- crypto_free_tfm(tfm);
++ crypto_free_blkcipher(tfm);
+ }
+
+-static void test_digest_jiffies(struct crypto_tfm *tfm, char *p, int blen,
+- int plen, char *out, int sec)
++static int test_hash_jiffies_digest(struct hash_desc *desc, char *p, int blen,
++ char *out, int sec)
++{
++ struct scatterlist sg[1];
++ unsigned long start, end;
++ int bcount;
++ int ret;
++
++ for (start = jiffies, end = start + sec * HZ, bcount = 0;
++ time_before(jiffies, end); bcount++) {
++ sg_set_buf(sg, p, blen);
++ ret = crypto_hash_digest(desc, sg, blen, out);
++ if (ret)
++ return ret;
++ }
++
++ printk("%6u opers/sec, %9lu bytes/sec\n",
++ bcount / sec, ((long)bcount * blen) / sec);
++
++ return 0;
++}
++
++static int test_hash_jiffies(struct hash_desc *desc, char *p, int blen,
++ int plen, char *out, int sec)
+ {
+ struct scatterlist sg[1];
+ unsigned long start, end;
+ int bcount, pcount;
++ int ret;
++
++ if (plen == blen)
++ return test_hash_jiffies_digest(desc, p, blen, out, sec);
+
+ for (start = jiffies, end = start + sec * HZ, bcount = 0;
+ time_before(jiffies, end); bcount++) {
+- crypto_digest_init(tfm);
++ ret = crypto_hash_init(desc);
++ if (ret)
++ return ret;
+ for (pcount = 0; pcount < blen; pcount += plen) {
+ sg_set_buf(sg, p + pcount, plen);
+- crypto_digest_update(tfm, sg, 1);
++ ret = crypto_hash_update(desc, sg, plen);
++ if (ret)
++ return ret;
+ }
+ /* we assume there is enough space in 'out' for the result */
+- crypto_digest_final(tfm, out);
++ ret = crypto_hash_final(desc, out);
++ if (ret)
++ return ret;
+ }
+
+ printk("%6u opers/sec, %9lu bytes/sec\n",
+ bcount / sec, ((long)bcount * blen) / sec);
+
+- return;
++ return 0;
++}
++
++static int test_hash_cycles_digest(struct hash_desc *desc, char *p, int blen,
++ char *out)
++{
++ struct scatterlist sg[1];
++ unsigned long cycles = 0;
++ int i;
++ int ret;
++
++ local_bh_disable();
++ local_irq_disable();
++
++ /* Warm-up run. */
++ for (i = 0; i < 4; i++) {
++ sg_set_buf(sg, p, blen);
++ ret = crypto_hash_digest(desc, sg, blen, out);
++ if (ret)
++ goto out;
++ }
++
++ /* The real thing. */
++ for (i = 0; i < 8; i++) {
++ cycles_t start, end;
++
++ start = get_cycles();
++
++ sg_set_buf(sg, p, blen);
++ ret = crypto_hash_digest(desc, sg, blen, out);
++ if (ret)
++ goto out;
++
++ end = get_cycles();
++
++ cycles += end - start;
++ }
++
++out:
++ local_irq_enable();
++ local_bh_enable();
++
++ if (ret)
++ return ret;
++
++ printk("%6lu cycles/operation, %4lu cycles/byte\n",
++ cycles / 8, cycles / (8 * blen));
++
++ return 0;
+ }
+
+-static void test_digest_cycles(struct crypto_tfm *tfm, char *p, int blen,
+- int plen, char *out)
++static int test_hash_cycles(struct hash_desc *desc, char *p, int blen,
++ int plen, char *out)
+ {
+ struct scatterlist sg[1];
+ unsigned long cycles = 0;
+ int i, pcount;
++ int ret;
++
++ if (plen == blen)
++ return test_hash_cycles_digest(desc, p, blen, out);
+
+ local_bh_disable();
+ local_irq_disable();
+
+ /* Warm-up run. */
+ for (i = 0; i < 4; i++) {
+- crypto_digest_init(tfm);
++ ret = crypto_hash_init(desc);
++ if (ret)
++ goto out;
+ for (pcount = 0; pcount < blen; pcount += plen) {
+ sg_set_buf(sg, p + pcount, plen);
+- crypto_digest_update(tfm, sg, 1);
++ ret = crypto_hash_update(desc, sg, plen);
++ if (ret)
++ goto out;
+ }
+- crypto_digest_final(tfm, out);
++ crypto_hash_final(desc, out);
++ if (ret)
++ goto out;
+ }
+
+ /* The real thing. */
+ for (i = 0; i < 8; i++) {
+ cycles_t start, end;
+
+- crypto_digest_init(tfm);
+-
+ start = get_cycles();
+
++ ret = crypto_hash_init(desc);
++ if (ret)
++ goto out;
+ for (pcount = 0; pcount < blen; pcount += plen) {
+ sg_set_buf(sg, p + pcount, plen);
+- crypto_digest_update(tfm, sg, 1);
++ ret = crypto_hash_update(desc, sg, plen);
++ if (ret)
++ goto out;
+ }
+- crypto_digest_final(tfm, out);
++ ret = crypto_hash_final(desc, out);
++ if (ret)
++ goto out;
+
+ end = get_cycles();
+
+ cycles += end - start;
+ }
+
++out:
+ local_irq_enable();
+ local_bh_enable();
+
++ if (ret)
++ return ret;
++
+ printk("%6lu cycles/operation, %4lu cycles/byte\n",
+ cycles / 8, cycles / (8 * blen));
+
+- return;
++ return 0;
+ }
+
+-static void test_digest_speed(char *algo, unsigned int sec,
+- struct digest_speed *speed)
++static void test_hash_speed(char *algo, unsigned int sec,
++ struct hash_speed *speed)
+ {
+- struct crypto_tfm *tfm;
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
+ char output[1024];
+ int i;
++ int ret;
+
+ printk("\ntesting speed of %s\n", algo);
+
+- tfm = crypto_alloc_tfm(algo, 0);
++ tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
+
+- if (tfm == NULL) {
+- printk("failed to load transform for %s\n", algo);
++ if (IS_ERR(tfm)) {
++ printk("failed to load transform for %s: %ld\n", algo,
++ PTR_ERR(tfm));
+ return;
+ }
+
+- if (crypto_tfm_alg_digestsize(tfm) > sizeof(output)) {
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_hash_digestsize(tfm) > sizeof(output)) {
+ printk("digestsize(%u) > outputbuffer(%zu)\n",
+- crypto_tfm_alg_digestsize(tfm), sizeof(output));
++ crypto_hash_digestsize(tfm), sizeof(output));
+ goto out;
+ }
+
+@@ -677,20 +729,27 @@ static void test_digest_speed(char *algo
+ memset(tvmem, 0xff, speed[i].blen);
+
+ if (sec)
+- test_digest_jiffies(tfm, tvmem, speed[i].blen, speed[i].plen, output, sec);
++ ret = test_hash_jiffies(&desc, tvmem, speed[i].blen,
++ speed[i].plen, output, sec);
+ else
+- test_digest_cycles(tfm, tvmem, speed[i].blen, speed[i].plen, output);
++ ret = test_hash_cycles(&desc, tvmem, speed[i].blen,
++ speed[i].plen, output);
++
++ if (ret) {
++ printk("hashing failed ret=%d\n", ret);
++ break;
++ }
+ }
+
+ out:
+- crypto_free_tfm(tfm);
++ crypto_free_hash(tfm);
+ }
+
+ static void test_deflate(void)
+ {
+ unsigned int i;
+ char result[COMP_BUF_SIZE];
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+ struct comp_testvec *tv;
+ unsigned int tsize;
+
+@@ -762,105 +821,7 @@ static void test_deflate(void)
+ ilen, dlen);
+ }
+ out:
+- crypto_free_tfm(tfm);
+-}
+-
+-static void test_crc32c(void)
+-{
+-#define NUMVEC 6
+-#define VECSIZE 40
+-
+- int i, j, pass;
+- u32 crc;
+- u8 b, test_vec[NUMVEC][VECSIZE];
+- static u32 vec_results[NUMVEC] = {
+- 0x0e2c157f, 0xe980ebf6, 0xde74bded,
+- 0xd579c862, 0xba979ad0, 0x2b29d913
+- };
+- static u32 tot_vec_results = 0x24c5d375;
+-
+- struct scatterlist sg[NUMVEC];
+- struct crypto_tfm *tfm;
+- char *fmtdata = "testing crc32c initialized to %08x: %s\n";
+-#define SEEDTESTVAL 0xedcba987
+- u32 seed;
+-
+- printk("\ntesting crc32c\n");
+-
+- tfm = crypto_alloc_tfm("crc32c", 0);
+- if (tfm == NULL) {
+- printk("failed to load transform for crc32c\n");
+- return;
+- }
+-
+- crypto_digest_init(tfm);
+- crypto_digest_final(tfm, (u8*)&crc);
+- printk(fmtdata, crc, (crc == 0) ? "pass" : "ERROR");
+-
+- /*
+- * stuff test_vec with known values, simple incrementing
+- * byte values.
+- */
+- b = 0;
+- for (i = 0; i < NUMVEC; i++) {
+- for (j = 0; j < VECSIZE; j++)
+- test_vec[i][j] = ++b;
+- sg_set_buf(&sg[i], test_vec[i], VECSIZE);
+- }
+-
+- seed = SEEDTESTVAL;
+- (void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
+- crypto_digest_final(tfm, (u8*)&crc);
+- printk("testing crc32c setkey returns %08x : %s\n", crc, (crc == (SEEDTESTVAL ^ ~(u32)0)) ?
+- "pass" : "ERROR");
+-
+- printk("testing crc32c using update/final:\n");
+-
+- pass = 1; /* assume all is well */
+-
+- for (i = 0; i < NUMVEC; i++) {
+- seed = ~(u32)0;
+- (void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
+- crypto_digest_update(tfm, &sg[i], 1);
+- crypto_digest_final(tfm, (u8*)&crc);
+- if (crc == vec_results[i]) {
+- printk(" %08x:OK", crc);
+- } else {
+- printk(" %08x:BAD, wanted %08x\n", crc, vec_results[i]);
+- pass = 0;
+- }
+- }
+-
+- printk("\ntesting crc32c using incremental accumulator:\n");
+- crc = 0;
+- for (i = 0; i < NUMVEC; i++) {
+- seed = (crc ^ ~(u32)0);
+- (void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
+- crypto_digest_update(tfm, &sg[i], 1);
+- crypto_digest_final(tfm, (u8*)&crc);
+- }
+- if (crc == tot_vec_results) {
+- printk(" %08x:OK", crc);
+- } else {
+- printk(" %08x:BAD, wanted %08x\n", crc, tot_vec_results);
+- pass = 0;
+- }
+-
+- printk("\ntesting crc32c using digest:\n");
+- seed = ~(u32)0;
+- (void)crypto_digest_setkey(tfm, (const u8*)&seed, sizeof(u32));
+- crypto_digest_digest(tfm, sg, NUMVEC, (u8*)&crc);
+- if (crc == tot_vec_results) {
+- printk(" %08x:OK", crc);
+- } else {
+- printk(" %08x:BAD, wanted %08x\n", crc, tot_vec_results);
+- pass = 0;
+- }
+-
+- printk("\n%s\n", pass ? "pass" : "ERROR");
+-
+- crypto_free_tfm(tfm);
+- printk("crc32c test complete\n");
++ crypto_free_comp(tfm);
+ }
+
+ static void test_available(void)
+@@ -869,8 +830,8 @@ static void test_available(void)
+
+ while (*name) {
+ printk("alg %s ", *name);
+- printk((crypto_alg_available(*name, 0)) ?
+- "found\n" : "not found\n");
++ printk(crypto_has_alg(*name, 0, CRYPTO_ALG_ASYNC) ?
++ "found\n" : "not found\n");
+ name++;
+ }
+ }
+@@ -885,79 +846,119 @@ static void do_test(void)
+ test_hash("sha1", sha1_tv_template, SHA1_TEST_VECTORS);
+
+ //DES
+- test_cipher ("des", MODE_ECB, ENCRYPT, des_enc_tv_template, DES_ENC_TEST_VECTORS);
+- test_cipher ("des", MODE_ECB, DECRYPT, des_dec_tv_template, DES_DEC_TEST_VECTORS);
+- test_cipher ("des", MODE_CBC, ENCRYPT, des_cbc_enc_tv_template, DES_CBC_ENC_TEST_VECTORS);
+- test_cipher ("des", MODE_CBC, DECRYPT, des_cbc_dec_tv_template, DES_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(des)", ENCRYPT, des_enc_tv_template,
++ DES_ENC_TEST_VECTORS);
++ test_cipher("ecb(des)", DECRYPT, des_dec_tv_template,
++ DES_DEC_TEST_VECTORS);
++ test_cipher("cbc(des)", ENCRYPT, des_cbc_enc_tv_template,
++ DES_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(des)", DECRYPT, des_cbc_dec_tv_template,
++ DES_CBC_DEC_TEST_VECTORS);
+
+ //DES3_EDE
+- test_cipher ("des3_ede", MODE_ECB, ENCRYPT, des3_ede_enc_tv_template, DES3_EDE_ENC_TEST_VECTORS);
+- test_cipher ("des3_ede", MODE_ECB, DECRYPT, des3_ede_dec_tv_template, DES3_EDE_DEC_TEST_VECTORS);
++ test_cipher("ecb(des3_ede)", ENCRYPT, des3_ede_enc_tv_template,
++ DES3_EDE_ENC_TEST_VECTORS);
++ test_cipher("ecb(des3_ede)", DECRYPT, des3_ede_dec_tv_template,
++ DES3_EDE_DEC_TEST_VECTORS);
+
+ test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
+
+ test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS);
+
+ //BLOWFISH
+- test_cipher ("blowfish", MODE_ECB, ENCRYPT, bf_enc_tv_template, BF_ENC_TEST_VECTORS);
+- test_cipher ("blowfish", MODE_ECB, DECRYPT, bf_dec_tv_template, BF_DEC_TEST_VECTORS);
+- test_cipher ("blowfish", MODE_CBC, ENCRYPT, bf_cbc_enc_tv_template, BF_CBC_ENC_TEST_VECTORS);
+- test_cipher ("blowfish", MODE_CBC, DECRYPT, bf_cbc_dec_tv_template, BF_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(blowfish)", ENCRYPT, bf_enc_tv_template,
++ BF_ENC_TEST_VECTORS);
++ test_cipher("ecb(blowfish)", DECRYPT, bf_dec_tv_template,
++ BF_DEC_TEST_VECTORS);
++ test_cipher("cbc(blowfish)", ENCRYPT, bf_cbc_enc_tv_template,
++ BF_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(blowfish)", DECRYPT, bf_cbc_dec_tv_template,
++ BF_CBC_DEC_TEST_VECTORS);
+
+ //TWOFISH
+- test_cipher ("twofish", MODE_ECB, ENCRYPT, tf_enc_tv_template, TF_ENC_TEST_VECTORS);
+- test_cipher ("twofish", MODE_ECB, DECRYPT, tf_dec_tv_template, TF_DEC_TEST_VECTORS);
+- test_cipher ("twofish", MODE_CBC, ENCRYPT, tf_cbc_enc_tv_template, TF_CBC_ENC_TEST_VECTORS);
+- test_cipher ("twofish", MODE_CBC, DECRYPT, tf_cbc_dec_tv_template, TF_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(twofish)", ENCRYPT, tf_enc_tv_template,
++ TF_ENC_TEST_VECTORS);
++ test_cipher("ecb(twofish)", DECRYPT, tf_dec_tv_template,
++ TF_DEC_TEST_VECTORS);
++ test_cipher("cbc(twofish)", ENCRYPT, tf_cbc_enc_tv_template,
++ TF_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(twofish)", DECRYPT, tf_cbc_dec_tv_template,
++ TF_CBC_DEC_TEST_VECTORS);
+
+ //SERPENT
+- test_cipher ("serpent", MODE_ECB, ENCRYPT, serpent_enc_tv_template, SERPENT_ENC_TEST_VECTORS);
+- test_cipher ("serpent", MODE_ECB, DECRYPT, serpent_dec_tv_template, SERPENT_DEC_TEST_VECTORS);
++ test_cipher("ecb(serpent)", ENCRYPT, serpent_enc_tv_template,
++ SERPENT_ENC_TEST_VECTORS);
++ test_cipher("ecb(serpent)", DECRYPT, serpent_dec_tv_template,
++ SERPENT_DEC_TEST_VECTORS);
+
+ //TNEPRES
+- test_cipher ("tnepres", MODE_ECB, ENCRYPT, tnepres_enc_tv_template, TNEPRES_ENC_TEST_VECTORS);
+- test_cipher ("tnepres", MODE_ECB, DECRYPT, tnepres_dec_tv_template, TNEPRES_DEC_TEST_VECTORS);
++ test_cipher("ecb(tnepres)", ENCRYPT, tnepres_enc_tv_template,
++ TNEPRES_ENC_TEST_VECTORS);
++ test_cipher("ecb(tnepres)", DECRYPT, tnepres_dec_tv_template,
++ TNEPRES_DEC_TEST_VECTORS);
+
+ //AES
+- test_cipher ("aes", MODE_ECB, ENCRYPT, aes_enc_tv_template, AES_ENC_TEST_VECTORS);
+- test_cipher ("aes", MODE_ECB, DECRYPT, aes_dec_tv_template, AES_DEC_TEST_VECTORS);
+- test_cipher ("aes", MODE_CBC, ENCRYPT, aes_cbc_enc_tv_template, AES_CBC_ENC_TEST_VECTORS);
+- test_cipher ("aes", MODE_CBC, DECRYPT, aes_cbc_dec_tv_template, AES_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(aes)", ENCRYPT, aes_enc_tv_template,
++ AES_ENC_TEST_VECTORS);
++ test_cipher("ecb(aes)", DECRYPT, aes_dec_tv_template,
++ AES_DEC_TEST_VECTORS);
++ test_cipher("cbc(aes)", ENCRYPT, aes_cbc_enc_tv_template,
++ AES_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(aes)", DECRYPT, aes_cbc_dec_tv_template,
++ AES_CBC_DEC_TEST_VECTORS);
+
+ //CAST5
+- test_cipher ("cast5", MODE_ECB, ENCRYPT, cast5_enc_tv_template, CAST5_ENC_TEST_VECTORS);
+- test_cipher ("cast5", MODE_ECB, DECRYPT, cast5_dec_tv_template, CAST5_DEC_TEST_VECTORS);
++ test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
++ CAST5_ENC_TEST_VECTORS);
++ test_cipher("ecb(cast5)", DECRYPT, cast5_dec_tv_template,
++ CAST5_DEC_TEST_VECTORS);
+
+ //CAST6
+- test_cipher ("cast6", MODE_ECB, ENCRYPT, cast6_enc_tv_template, CAST6_ENC_TEST_VECTORS);
+- test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS);
++ test_cipher("ecb(cast6)", ENCRYPT, cast6_enc_tv_template,
++ CAST6_ENC_TEST_VECTORS);
++ test_cipher("ecb(cast6)", DECRYPT, cast6_dec_tv_template,
++ CAST6_DEC_TEST_VECTORS);
+
+ //ARC4
+- test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS);
+- test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
++ test_cipher("ecb(arc4)", ENCRYPT, arc4_enc_tv_template,
++ ARC4_ENC_TEST_VECTORS);
++ test_cipher("ecb(arc4)", DECRYPT, arc4_dec_tv_template,
++ ARC4_DEC_TEST_VECTORS);
+
+ //TEA
+- test_cipher ("tea", MODE_ECB, ENCRYPT, tea_enc_tv_template, TEA_ENC_TEST_VECTORS);
+- test_cipher ("tea", MODE_ECB, DECRYPT, tea_dec_tv_template, TEA_DEC_TEST_VECTORS);
++ test_cipher("ecb(tea)", ENCRYPT, tea_enc_tv_template,
++ TEA_ENC_TEST_VECTORS);
++ test_cipher("ecb(tea)", DECRYPT, tea_dec_tv_template,
++ TEA_DEC_TEST_VECTORS);
+
+
+ //XTEA
+- test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS);
+- test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS);
++ test_cipher("ecb(xtea)", ENCRYPT, xtea_enc_tv_template,
++ XTEA_ENC_TEST_VECTORS);
++ test_cipher("ecb(xtea)", DECRYPT, xtea_dec_tv_template,
++ XTEA_DEC_TEST_VECTORS);
+
+ //KHAZAD
+- test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS);
+- test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS);
++ test_cipher("ecb(khazad)", ENCRYPT, khazad_enc_tv_template,
++ KHAZAD_ENC_TEST_VECTORS);
++ test_cipher("ecb(khazad)", DECRYPT, khazad_dec_tv_template,
++ KHAZAD_DEC_TEST_VECTORS);
+
+ //ANUBIS
+- test_cipher ("anubis", MODE_ECB, ENCRYPT, anubis_enc_tv_template, ANUBIS_ENC_TEST_VECTORS);
+- test_cipher ("anubis", MODE_ECB, DECRYPT, anubis_dec_tv_template, ANUBIS_DEC_TEST_VECTORS);
+- test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
+- test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
++ test_cipher("ecb(anubis)", ENCRYPT, anubis_enc_tv_template,
++ ANUBIS_ENC_TEST_VECTORS);
++ test_cipher("ecb(anubis)", DECRYPT, anubis_dec_tv_template,
++ ANUBIS_DEC_TEST_VECTORS);
++ test_cipher("cbc(anubis)", ENCRYPT, anubis_cbc_enc_tv_template,
++ ANUBIS_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(anubis)", DECRYPT, anubis_cbc_dec_tv_template,
++ ANUBIS_CBC_ENC_TEST_VECTORS);
+
+ //XETA
+- test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS);
+- test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS);
++ test_cipher("ecb(xeta)", ENCRYPT, xeta_enc_tv_template,
++ XETA_ENC_TEST_VECTORS);
++ test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template,
++ XETA_DEC_TEST_VECTORS);
+
+ test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
+ test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
+@@ -968,12 +969,13 @@ static void do_test(void)
+ test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
+ test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
+ test_deflate();
+- test_crc32c();
+-#ifdef CONFIG_CRYPTO_HMAC
+- test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
+- test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);
+- test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS);
+-#endif
++ test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
++ test_hash("hmac(md5)", hmac_md5_tv_template,
++ HMAC_MD5_TEST_VECTORS);
++ test_hash("hmac(sha1)", hmac_sha1_tv_template,
++ HMAC_SHA1_TEST_VECTORS);
++ test_hash("hmac(sha256)", hmac_sha256_tv_template,
++ HMAC_SHA256_TEST_VECTORS);
+
+ test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
+ break;
+@@ -987,15 +989,21 @@ static void do_test(void)
+ break;
+
+ case 3:
+- test_cipher ("des", MODE_ECB, ENCRYPT, des_enc_tv_template, DES_ENC_TEST_VECTORS);
+- test_cipher ("des", MODE_ECB, DECRYPT, des_dec_tv_template, DES_DEC_TEST_VECTORS);
+- test_cipher ("des", MODE_CBC, ENCRYPT, des_cbc_enc_tv_template, DES_CBC_ENC_TEST_VECTORS);
+- test_cipher ("des", MODE_CBC, DECRYPT, des_cbc_dec_tv_template, DES_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(des)", ENCRYPT, des_enc_tv_template,
++ DES_ENC_TEST_VECTORS);
++ test_cipher("ecb(des)", DECRYPT, des_dec_tv_template,
++ DES_DEC_TEST_VECTORS);
++ test_cipher("cbc(des)", ENCRYPT, des_cbc_enc_tv_template,
++ DES_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(des)", DECRYPT, des_cbc_dec_tv_template,
++ DES_CBC_DEC_TEST_VECTORS);
+ break;
+
+ case 4:
+- test_cipher ("des3_ede", MODE_ECB, ENCRYPT, des3_ede_enc_tv_template, DES3_EDE_ENC_TEST_VECTORS);
+- test_cipher ("des3_ede", MODE_ECB, DECRYPT, des3_ede_dec_tv_template, DES3_EDE_DEC_TEST_VECTORS);
++ test_cipher("ecb(des3_ede)", ENCRYPT, des3_ede_enc_tv_template,
++ DES3_EDE_ENC_TEST_VECTORS);
++ test_cipher("ecb(des3_ede)", DECRYPT, des3_ede_dec_tv_template,
++ DES3_EDE_DEC_TEST_VECTORS);
+ break;
+
+ case 5:
+@@ -1007,29 +1015,43 @@ static void do_test(void)
+ break;
+
+ case 7:
+- test_cipher ("blowfish", MODE_ECB, ENCRYPT, bf_enc_tv_template, BF_ENC_TEST_VECTORS);
+- test_cipher ("blowfish", MODE_ECB, DECRYPT, bf_dec_tv_template, BF_DEC_TEST_VECTORS);
+- test_cipher ("blowfish", MODE_CBC, ENCRYPT, bf_cbc_enc_tv_template, BF_CBC_ENC_TEST_VECTORS);
+- test_cipher ("blowfish", MODE_CBC, DECRYPT, bf_cbc_dec_tv_template, BF_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(blowfish)", ENCRYPT, bf_enc_tv_template,
++ BF_ENC_TEST_VECTORS);
++ test_cipher("ecb(blowfish)", DECRYPT, bf_dec_tv_template,
++ BF_DEC_TEST_VECTORS);
++ test_cipher("cbc(blowfish)", ENCRYPT, bf_cbc_enc_tv_template,
++ BF_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(blowfish)", DECRYPT, bf_cbc_dec_tv_template,
++ BF_CBC_DEC_TEST_VECTORS);
+ break;
+
+ case 8:
+- test_cipher ("twofish", MODE_ECB, ENCRYPT, tf_enc_tv_template, TF_ENC_TEST_VECTORS);
+- test_cipher ("twofish", MODE_ECB, DECRYPT, tf_dec_tv_template, TF_DEC_TEST_VECTORS);
+- test_cipher ("twofish", MODE_CBC, ENCRYPT, tf_cbc_enc_tv_template, TF_CBC_ENC_TEST_VECTORS);
+- test_cipher ("twofish", MODE_CBC, DECRYPT, tf_cbc_dec_tv_template, TF_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(twofish)", ENCRYPT, tf_enc_tv_template,
++ TF_ENC_TEST_VECTORS);
++ test_cipher("ecb(twofish)", DECRYPT, tf_dec_tv_template,
++ TF_DEC_TEST_VECTORS);
++ test_cipher("cbc(twofish)", ENCRYPT, tf_cbc_enc_tv_template,
++ TF_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(twofish)", DECRYPT, tf_cbc_dec_tv_template,
++ TF_CBC_DEC_TEST_VECTORS);
+ break;
+
+ case 9:
+- test_cipher ("serpent", MODE_ECB, ENCRYPT, serpent_enc_tv_template, SERPENT_ENC_TEST_VECTORS);
+- test_cipher ("serpent", MODE_ECB, DECRYPT, serpent_dec_tv_template, SERPENT_DEC_TEST_VECTORS);
++ test_cipher("ecb(serpent)", ENCRYPT, serpent_enc_tv_template,
++ SERPENT_ENC_TEST_VECTORS);
++ test_cipher("ecb(serpent)", DECRYPT, serpent_dec_tv_template,
++ SERPENT_DEC_TEST_VECTORS);
+ break;
+
+ case 10:
+- test_cipher ("aes", MODE_ECB, ENCRYPT, aes_enc_tv_template, AES_ENC_TEST_VECTORS);
+- test_cipher ("aes", MODE_ECB, DECRYPT, aes_dec_tv_template, AES_DEC_TEST_VECTORS);
+- test_cipher ("aes", MODE_CBC, ENCRYPT, aes_cbc_enc_tv_template, AES_CBC_ENC_TEST_VECTORS);
+- test_cipher ("aes", MODE_CBC, DECRYPT, aes_cbc_dec_tv_template, AES_CBC_DEC_TEST_VECTORS);
++ test_cipher("ecb(aes)", ENCRYPT, aes_enc_tv_template,
++ AES_ENC_TEST_VECTORS);
++ test_cipher("ecb(aes)", DECRYPT, aes_dec_tv_template,
++ AES_DEC_TEST_VECTORS);
++ test_cipher("cbc(aes)", ENCRYPT, aes_cbc_enc_tv_template,
++ AES_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(aes)", DECRYPT, aes_cbc_dec_tv_template,
++ AES_CBC_DEC_TEST_VECTORS);
+ break;
+
+ case 11:
+@@ -1045,18 +1067,24 @@ static void do_test(void)
+ break;
+
+ case 14:
+- test_cipher ("cast5", MODE_ECB, ENCRYPT, cast5_enc_tv_template, CAST5_ENC_TEST_VECTORS);
+- test_cipher ("cast5", MODE_ECB, DECRYPT, cast5_dec_tv_template, CAST5_DEC_TEST_VECTORS);
++ test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
++ CAST5_ENC_TEST_VECTORS);
++ test_cipher("ecb(cast5)", DECRYPT, cast5_dec_tv_template,
++ CAST5_DEC_TEST_VECTORS);
+ break;
+
+ case 15:
+- test_cipher ("cast6", MODE_ECB, ENCRYPT, cast6_enc_tv_template, CAST6_ENC_TEST_VECTORS);
+- test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS);
++ test_cipher("ecb(cast6)", ENCRYPT, cast6_enc_tv_template,
++ CAST6_ENC_TEST_VECTORS);
++ test_cipher("ecb(cast6)", DECRYPT, cast6_dec_tv_template,
++ CAST6_DEC_TEST_VECTORS);
+ break;
+
+ case 16:
+- test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS);
+- test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
++ test_cipher("ecb(arc4)", ENCRYPT, arc4_enc_tv_template,
++ ARC4_ENC_TEST_VECTORS);
++ test_cipher("ecb(arc4)", DECRYPT, arc4_dec_tv_template,
++ ARC4_DEC_TEST_VECTORS);
+ break;
+
+ case 17:
+@@ -1064,22 +1092,28 @@ static void do_test(void)
+ break;
+
+ case 18:
+- test_crc32c();
++ test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
+ break;
+
+ case 19:
+- test_cipher ("tea", MODE_ECB, ENCRYPT, tea_enc_tv_template, TEA_ENC_TEST_VECTORS);
+- test_cipher ("tea", MODE_ECB, DECRYPT, tea_dec_tv_template, TEA_DEC_TEST_VECTORS);
++ test_cipher("ecb(tea)", ENCRYPT, tea_enc_tv_template,
++ TEA_ENC_TEST_VECTORS);
++ test_cipher("ecb(tea)", DECRYPT, tea_dec_tv_template,
++ TEA_DEC_TEST_VECTORS);
+ break;
+
+ case 20:
+- test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS);
+- test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS);
++ test_cipher("ecb(xtea)", ENCRYPT, xtea_enc_tv_template,
++ XTEA_ENC_TEST_VECTORS);
++ test_cipher("ecb(xtea)", DECRYPT, xtea_dec_tv_template,
++ XTEA_DEC_TEST_VECTORS);
+ break;
+
+ case 21:
+- test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS);
+- test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS);
++ test_cipher("ecb(khazad)", ENCRYPT, khazad_enc_tv_template,
++ KHAZAD_ENC_TEST_VECTORS);
++ test_cipher("ecb(khazad)", DECRYPT, khazad_dec_tv_template,
++ KHAZAD_DEC_TEST_VECTORS);
+ break;
+
+ case 22:
+@@ -1095,15 +1129,21 @@ static void do_test(void)
+ break;
+
+ case 25:
+- test_cipher ("tnepres", MODE_ECB, ENCRYPT, tnepres_enc_tv_template, TNEPRES_ENC_TEST_VECTORS);
+- test_cipher ("tnepres", MODE_ECB, DECRYPT, tnepres_dec_tv_template, TNEPRES_DEC_TEST_VECTORS);
++ test_cipher("ecb(tnepres)", ENCRYPT, tnepres_enc_tv_template,
++ TNEPRES_ENC_TEST_VECTORS);
++ test_cipher("ecb(tnepres)", DECRYPT, tnepres_dec_tv_template,
++ TNEPRES_DEC_TEST_VECTORS);
+ break;
+
+ case 26:
+- test_cipher ("anubis", MODE_ECB, ENCRYPT, anubis_enc_tv_template, ANUBIS_ENC_TEST_VECTORS);
+- test_cipher ("anubis", MODE_ECB, DECRYPT, anubis_dec_tv_template, ANUBIS_DEC_TEST_VECTORS);
+- test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
+- test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
++ test_cipher("ecb(anubis)", ENCRYPT, anubis_enc_tv_template,
++ ANUBIS_ENC_TEST_VECTORS);
++ test_cipher("ecb(anubis)", DECRYPT, anubis_dec_tv_template,
++ ANUBIS_DEC_TEST_VECTORS);
++ test_cipher("cbc(anubis)", ENCRYPT, anubis_cbc_enc_tv_template,
++ ANUBIS_CBC_ENC_TEST_VECTORS);
++ test_cipher("cbc(anubis)", DECRYPT, anubis_cbc_dec_tv_template,
++ ANUBIS_CBC_ENC_TEST_VECTORS);
+ break;
+
+ case 27:
+@@ -1120,85 +1160,88 @@ static void do_test(void)
+ break;
+
+ case 30:
+- test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS);
+- test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS);
++ test_cipher("ecb(xeta)", ENCRYPT, xeta_enc_tv_template,
++ XETA_ENC_TEST_VECTORS);
++ test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template,
++ XETA_DEC_TEST_VECTORS);
+ break;
+
+-#ifdef CONFIG_CRYPTO_HMAC
+ case 100:
+- test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
++ test_hash("hmac(md5)", hmac_md5_tv_template,
++ HMAC_MD5_TEST_VECTORS);
+ break;
+
+ case 101:
+- test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);
++ test_hash("hmac(sha1)", hmac_sha1_tv_template,
++ HMAC_SHA1_TEST_VECTORS);
+ break;
+
+ case 102:
+- test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS);
++ test_hash("hmac(sha256)", hmac_sha256_tv_template,
++ HMAC_SHA256_TEST_VECTORS);
+ break;
+
+-#endif
+
+ case 200:
+- test_cipher_speed("aes", MODE_ECB, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
+ aes_speed_template);
+- test_cipher_speed("aes", MODE_ECB, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(aes)", DECRYPT, sec, NULL, 0,
+ aes_speed_template);
+- test_cipher_speed("aes", MODE_CBC, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(aes)", ENCRYPT, sec, NULL, 0,
+ aes_speed_template);
+- test_cipher_speed("aes", MODE_CBC, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(aes)", DECRYPT, sec, NULL, 0,
+ aes_speed_template);
+ break;
+
+ case 201:
+- test_cipher_speed("des3_ede", MODE_ECB, ENCRYPT, sec,
++ test_cipher_speed("ecb(des3_ede)", ENCRYPT, sec,
+ des3_ede_enc_tv_template,
+ DES3_EDE_ENC_TEST_VECTORS,
+ des3_ede_speed_template);
+- test_cipher_speed("des3_ede", MODE_ECB, DECRYPT, sec,
++ test_cipher_speed("ecb(des3_ede)", DECRYPT, sec,
+ des3_ede_dec_tv_template,
+ DES3_EDE_DEC_TEST_VECTORS,
+ des3_ede_speed_template);
+- test_cipher_speed("des3_ede", MODE_CBC, ENCRYPT, sec,
++ test_cipher_speed("cbc(des3_ede)", ENCRYPT, sec,
+ des3_ede_enc_tv_template,
+ DES3_EDE_ENC_TEST_VECTORS,
+ des3_ede_speed_template);
+- test_cipher_speed("des3_ede", MODE_CBC, DECRYPT, sec,
++ test_cipher_speed("cbc(des3_ede)", DECRYPT, sec,
+ des3_ede_dec_tv_template,
+ DES3_EDE_DEC_TEST_VECTORS,
+ des3_ede_speed_template);
+ break;
+
+ case 202:
+- test_cipher_speed("twofish", MODE_ECB, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(twofish)", ENCRYPT, sec, NULL, 0,
+ twofish_speed_template);
+- test_cipher_speed("twofish", MODE_ECB, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(twofish)", DECRYPT, sec, NULL, 0,
+ twofish_speed_template);
+- test_cipher_speed("twofish", MODE_CBC, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(twofish)", ENCRYPT, sec, NULL, 0,
+ twofish_speed_template);
+- test_cipher_speed("twofish", MODE_CBC, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(twofish)", DECRYPT, sec, NULL, 0,
+ twofish_speed_template);
+ break;
+
+ case 203:
+- test_cipher_speed("blowfish", MODE_ECB, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(blowfish)", ENCRYPT, sec, NULL, 0,
+ blowfish_speed_template);
+- test_cipher_speed("blowfish", MODE_ECB, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(blowfish)", DECRYPT, sec, NULL, 0,
+ blowfish_speed_template);
+- test_cipher_speed("blowfish", MODE_CBC, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(blowfish)", ENCRYPT, sec, NULL, 0,
+ blowfish_speed_template);
+- test_cipher_speed("blowfish", MODE_CBC, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(blowfish)", DECRYPT, sec, NULL, 0,
+ blowfish_speed_template);
+ break;
+
+ case 204:
+- test_cipher_speed("des", MODE_ECB, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(des)", ENCRYPT, sec, NULL, 0,
+ des_speed_template);
+- test_cipher_speed("des", MODE_ECB, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("ecb(des)", DECRYPT, sec, NULL, 0,
+ des_speed_template);
+- test_cipher_speed("des", MODE_CBC, ENCRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(des)", ENCRYPT, sec, NULL, 0,
+ des_speed_template);
+- test_cipher_speed("des", MODE_CBC, DECRYPT, sec, NULL, 0,
++ test_cipher_speed("cbc(des)", DECRYPT, sec, NULL, 0,
+ des_speed_template);
+ break;
+
+@@ -1206,51 +1249,51 @@ static void do_test(void)
+ /* fall through */
+
+ case 301:
+- test_digest_speed("md4", sec, generic_digest_speed_template);
++ test_hash_speed("md4", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 302:
+- test_digest_speed("md5", sec, generic_digest_speed_template);
++ test_hash_speed("md5", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 303:
+- test_digest_speed("sha1", sec, generic_digest_speed_template);
++ test_hash_speed("sha1", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 304:
+- test_digest_speed("sha256", sec, generic_digest_speed_template);
++ test_hash_speed("sha256", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 305:
+- test_digest_speed("sha384", sec, generic_digest_speed_template);
++ test_hash_speed("sha384", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 306:
+- test_digest_speed("sha512", sec, generic_digest_speed_template);
++ test_hash_speed("sha512", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 307:
+- test_digest_speed("wp256", sec, generic_digest_speed_template);
++ test_hash_speed("wp256", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 308:
+- test_digest_speed("wp384", sec, generic_digest_speed_template);
++ test_hash_speed("wp384", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 309:
+- test_digest_speed("wp512", sec, generic_digest_speed_template);
++ test_hash_speed("wp512", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 310:
+- test_digest_speed("tgr128", sec, generic_digest_speed_template);
++ test_hash_speed("tgr128", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 311:
+- test_digest_speed("tgr160", sec, generic_digest_speed_template);
++ test_hash_speed("tgr160", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 312:
+- test_digest_speed("tgr192", sec, generic_digest_speed_template);
++ test_hash_speed("tgr192", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
+ case 399:
+diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
+index 1fac560..a40c441 100644
+--- a/crypto/tcrypt.h
++++ b/crypto/tcrypt.h
+@@ -28,7 +28,7 @@
+ struct hash_testvec {
+ /* only used with keyed hash algorithms */
+ char key[128] __attribute__ ((__aligned__(4)));
+- char plaintext[128];
++ char plaintext[240];
+ char digest[MAX_DIGEST_SIZE];
+ unsigned char tap[MAX_TAP];
+ unsigned char psize;
+@@ -36,16 +36,6 @@ struct hash_testvec {
+ unsigned char ksize;
+ };
+
+-struct hmac_testvec {
+- char key[128];
+- char plaintext[128];
+- char digest[MAX_DIGEST_SIZE];
+- unsigned char tap[MAX_TAP];
+- unsigned char ksize;
+- unsigned char psize;
+- unsigned char np;
+-};
+-
+ struct cipher_testvec {
+ char key[MAX_KEYLEN] __attribute__ ((__aligned__(4)));
+ char iv[MAX_IVLEN];
+@@ -65,7 +55,7 @@ struct cipher_speed {
+ unsigned int blen;
+ };
+
+-struct digest_speed {
++struct hash_speed {
+ unsigned int blen; /* buffer length */
+ unsigned int plen; /* per-update length */
+ };
+@@ -697,14 +687,13 @@ static struct hash_testvec tgr128_tv_tem
+ },
+ };
+
+-#ifdef CONFIG_CRYPTO_HMAC
+ /*
+ * HMAC-MD5 test vectors from RFC2202
+ * (These need to be fixed to not use strlen).
+ */
+ #define HMAC_MD5_TEST_VECTORS 7
+
+-static struct hmac_testvec hmac_md5_tv_template[] =
++static struct hash_testvec hmac_md5_tv_template[] =
+ {
+ {
+ .key = { [0 ... 15] = 0x0b },
+@@ -768,7 +757,7 @@ static struct hmac_testvec hmac_md5_tv_t
+ */
+ #define HMAC_SHA1_TEST_VECTORS 7
+
+-static struct hmac_testvec hmac_sha1_tv_template[] = {
++static struct hash_testvec hmac_sha1_tv_template[] = {
+ {
+ .key = { [0 ... 19] = 0x0b },
+ .ksize = 20,
+@@ -833,7 +822,7 @@ static struct hmac_testvec hmac_sha1_tv_
+ */
+ #define HMAC_SHA256_TEST_VECTORS 10
+
+-static struct hmac_testvec hmac_sha256_tv_template[] = {
++static struct hash_testvec hmac_sha256_tv_template[] = {
+ {
+ .key = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+@@ -944,8 +933,6 @@ static struct hmac_testvec hmac_sha256_t
+ },
+ };
+
+-#endif /* CONFIG_CRYPTO_HMAC */
+-
+ /*
+ * DES test vectors.
+ */
+@@ -2897,6 +2884,183 @@ static struct hash_testvec michael_mic_t
+ };
+
+ /*
++ * CRC32C test vectors
++ */
++#define CRC32C_TEST_VECTORS 14
++
++static struct hash_testvec crc32c_tv_template[] = {
++ {
++ .psize = 0,
++ .digest = { 0x00, 0x00, 0x00, 0x00 }
++ },
++ {
++ .key = { 0x87, 0xa9, 0xcb, 0xed },
++ .ksize = 4,
++ .psize = 0,
++ .digest = { 0x78, 0x56, 0x34, 0x12 },
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
++ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
++ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
++ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 },
++ .psize = 40,
++ .digest = { 0x7f, 0x15, 0x2c, 0x0e }
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
++ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
++ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
++ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
++ 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50 },
++ .psize = 40,
++ .digest = { 0xf6, 0xeb, 0x80, 0xe9 }
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
++ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
++ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
++ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
++ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78 },
++ .psize = 40,
++ .digest = { 0xed, 0xbd, 0x74, 0xde }
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
++ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
++ 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
++ 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
++ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0 },
++ .psize = 40,
++ .digest = { 0x62, 0xc8, 0x79, 0xd5 }
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
++ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
++ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
++ 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
++ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8 },
++ .psize = 40,
++ .digest = { 0xd0, 0x9a, 0x97, 0xba }
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
++ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
++ 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
++ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
++ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0 },
++ .psize = 40,
++ .digest = { 0x13, 0xd9, 0x29, 0x2b }
++ },
++ {
++ .key = { 0x80, 0xea, 0xd3, 0xf1 },
++ .ksize = 4,
++ .plaintext = { 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
++ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
++ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
++ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
++ 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50 },
++ .psize = 40,
++ .digest = { 0x0c, 0xb5, 0xe2, 0xa2 }
++ },
++ {
++ .key = { 0xf3, 0x4a, 0x1d, 0x5d },
++ .ksize = 4,
++ .plaintext = { 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
++ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
++ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
++ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
++ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78 },
++ .psize = 40,
++ .digest = { 0xd1, 0x7f, 0xfb, 0xa6 }
++ },
++ {
++ .key = { 0x2e, 0x80, 0x04, 0x59 },
++ .ksize = 4,
++ .plaintext = { 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
++ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
++ 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
++ 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
++ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0 },
++ .psize = 40,
++ .digest = { 0x59, 0x33, 0xe6, 0x7a }
++ },
++ {
++ .key = { 0xa6, 0xcc, 0x19, 0x85 },
++ .ksize = 4,
++ .plaintext = { 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
++ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
++ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
++ 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
++ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8 },
++ .psize = 40,
++ .digest = { 0xbe, 0x03, 0x01, 0xd2 }
++ },
++ {
++ .key = { 0x41, 0xfc, 0xfe, 0x2d },
++ .ksize = 4,
++ .plaintext = { 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
++ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
++ 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
++ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
++ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0 },
++ .psize = 40,
++ .digest = { 0x75, 0xd3, 0xc5, 0x24 }
++ },
++ {
++ .key = { 0xff, 0xff, 0xff, 0xff },
++ .ksize = 4,
++ .plaintext = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
++ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
++ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
++ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
++ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
++ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
++ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
++ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
++ 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
++ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
++ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
++ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
++ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
++ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
++ 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
++ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
++ 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
++ 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
++ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0,
++ 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
++ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
++ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
++ 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
++ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
++ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
++ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
++ 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
++ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
++ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0 },
++ .psize = 240,
++ .digest = { 0x75, 0xd3, 0xc5, 0x24 },
++ .np = 2,
++ .tap = { 31, 209 }
++ },
++};
++
++/*
+ * Cipher speed tests
+ */
+ static struct cipher_speed aes_speed_template[] = {
+@@ -2983,7 +3147,7 @@ static struct cipher_speed des_speed_tem
+ /*
+ * Digest speed tests
+ */
+-static struct digest_speed generic_digest_speed_template[] = {
++static struct hash_speed generic_hash_speed_template[] = {
+ { .blen = 16, .plen = 16, },
+ { .blen = 64, .plen = 16, },
+ { .blen = 64, .plen = 64, },
+diff --git a/crypto/tea.c b/crypto/tea.c
+index 5367adc..1c54e26 100644
+--- a/crypto/tea.c
++++ b/crypto/tea.c
+@@ -46,16 +46,10 @@ struct xtea_ctx {
+ };
+
+ static int tea_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __le32 *key = (const __le32 *)in_key;
+-
+- if (key_len != 16)
+- {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL;
+- }
+
+ ctx->KEY[0] = le32_to_cpu(key[0]);
+ ctx->KEY[1] = le32_to_cpu(key[1]);
+@@ -125,16 +119,10 @@ static void tea_decrypt(struct crypto_tf
+ }
+
+ static int xtea_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
+ const __le32 *key = (const __le32 *)in_key;
+-
+- if (key_len != 16)
+- {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL;
+- }
+
+ ctx->KEY[0] = le32_to_cpu(key[0]);
+ ctx->KEY[1] = le32_to_cpu(key[1]);
+diff --git a/crypto/twofish.c b/crypto/twofish.c
+index ec24882..4979a2b 100644
+--- a/crypto/twofish.c
++++ b/crypto/twofish.c
+@@ -39,6 +39,7 @@
+ */
+
+ #include <asm/byteorder.h>
++#include <crypto/twofish.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+@@ -46,534 +47,6 @@
+ #include <linux/crypto.h>
+ #include <linux/bitops.h>
+
+-
+-/* The large precomputed tables for the Twofish cipher (twofish.c)
+- * Taken from the same source as twofish.c
+- * Marc Mutz <Marc at Mutz.com>
+- */
+-
+-/* These two tables are the q0 and q1 permutations, exactly as described in
+- * the Twofish paper. */
+-
+-static const u8 q0[256] = {
+- 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
+- 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
+- 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
+- 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
+- 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
+- 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
+- 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
+- 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
+- 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
+- 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
+- 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
+- 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
+- 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
+- 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
+- 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
+- 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
+- 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
+- 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
+- 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
+- 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
+- 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
+- 0x4A, 0x5E, 0xC1, 0xE0
+-};
+-
+-static const u8 q1[256] = {
+- 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
+- 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
+- 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
+- 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
+- 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
+- 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
+- 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
+- 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
+- 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
+- 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
+- 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
+- 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
+- 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
+- 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
+- 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
+- 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
+- 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
+- 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
+- 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
+- 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
+- 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
+- 0x55, 0x09, 0xBE, 0x91
+-};
+-
+-/* These MDS tables are actually tables of MDS composed with q0 and q1,
+- * because it is only ever used that way and we can save some time by
+- * precomputing. Of course the main saving comes from precomputing the
+- * GF(2^8) multiplication involved in the MDS matrix multiply; by looking
+- * things up in these tables we reduce the matrix multiply to four lookups
+- * and three XORs. Semi-formally, the definition of these tables is:
+- * mds[0][i] = MDS (q1[i] 0 0 0)^T mds[1][i] = MDS (0 q0[i] 0 0)^T
+- * mds[2][i] = MDS (0 0 q1[i] 0)^T mds[3][i] = MDS (0 0 0 q0[i])^T
+- * where ^T means "transpose", the matrix multiply is performed in GF(2^8)
+- * represented as GF(2)[x]/v(x) where v(x)=x^8+x^6+x^5+x^3+1 as described
+- * by Schneier et al, and I'm casually glossing over the byte/word
+- * conversion issues. */
+-
+-static const u32 mds[4][256] = {
+- {0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
+- 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
+- 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
+- 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
+- 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
+- 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
+- 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
+- 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
+- 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
+- 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
+- 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
+- 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
+- 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
+- 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
+- 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
+- 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
+- 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
+- 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
+- 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
+- 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
+- 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
+- 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
+- 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
+- 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
+- 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
+- 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
+- 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
+- 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
+- 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
+- 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
+- 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
+- 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
+- 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
+- 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
+- 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
+- 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
+- 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
+- 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
+- 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
+- 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
+- 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
+- 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
+- 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91},
+-
+- {0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
+- 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
+- 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
+- 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
+- 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
+- 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
+- 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
+- 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
+- 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
+- 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
+- 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
+- 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
+- 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
+- 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
+- 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
+- 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
+- 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
+- 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
+- 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
+- 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
+- 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
+- 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
+- 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
+- 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
+- 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
+- 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
+- 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
+- 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
+- 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
+- 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
+- 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
+- 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
+- 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
+- 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
+- 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
+- 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
+- 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
+- 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
+- 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
+- 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
+- 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
+- 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
+- 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8},
+-
+- {0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
+- 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
+- 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
+- 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
+- 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
+- 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
+- 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
+- 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
+- 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
+- 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
+- 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
+- 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
+- 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
+- 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
+- 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
+- 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
+- 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
+- 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
+- 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
+- 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
+- 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
+- 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
+- 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
+- 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
+- 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
+- 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
+- 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
+- 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
+- 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
+- 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
+- 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
+- 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
+- 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
+- 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
+- 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
+- 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
+- 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
+- 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
+- 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
+- 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
+- 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
+- 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
+- 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF},
+-
+- {0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
+- 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
+- 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
+- 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
+- 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
+- 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
+- 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
+- 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
+- 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
+- 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
+- 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
+- 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
+- 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
+- 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
+- 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
+- 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
+- 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
+- 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
+- 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
+- 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
+- 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
+- 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
+- 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
+- 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
+- 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
+- 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
+- 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
+- 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
+- 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
+- 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
+- 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
+- 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
+- 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
+- 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
+- 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
+- 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
+- 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
+- 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
+- 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
+- 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
+- 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
+- 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
+- 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8}
+-};
+-
+-/* The exp_to_poly and poly_to_exp tables are used to perform efficient
+- * operations in GF(2^8) represented as GF(2)[x]/w(x) where
+- * w(x)=x^8+x^6+x^3+x^2+1. We care about doing that because it's part of the
+- * definition of the RS matrix in the key schedule. Elements of that field
+- * are polynomials of degree not greater than 7 and all coefficients 0 or 1,
+- * which can be represented naturally by bytes (just substitute x=2). In that
+- * form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8)
+- * multiplication is inefficient without hardware support. To multiply
+- * faster, I make use of the fact x is a generator for the nonzero elements,
+- * so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
+- * some n in 0..254. Note that that caret is exponentiation in GF(2^8),
+- * *not* polynomial notation. So if I want to compute pq where p and q are
+- * in GF(2^8), I can just say:
+- * 1. if p=0 or q=0 then pq=0
+- * 2. otherwise, find m and n such that p=x^m and q=x^n
+- * 3. pq=(x^m)(x^n)=x^(m+n), so add m and n and find pq
+- * The translations in steps 2 and 3 are looked up in the tables
+- * poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this
+- * in action, look at the CALC_S macro. As additional wrinkles, note that
+- * one of my operands is always a constant, so the poly_to_exp lookup on it
+- * is done in advance; I included the original values in the comments so
+- * readers can have some chance of recognizing that this *is* the RS matrix
+- * from the Twofish paper. I've only included the table entries I actually
+- * need; I never do a lookup on a variable input of zero and the biggest
+- * exponents I'll ever see are 254 (variable) and 237 (constant), so they'll
+- * never sum to more than 491. I'm repeating part of the exp_to_poly table
+- * so that I don't have to do mod-255 reduction in the exponent arithmetic.
+- * Since I know my constant operands are never zero, I only have to worry
+- * about zero values in the variable operand, and I do it with a simple
+- * conditional branch. I know conditionals are expensive, but I couldn't
+- * see a non-horrible way of avoiding them, and I did manage to group the
+- * statements so that each if covers four group multiplications. */
+-
+-static const u8 poly_to_exp[255] = {
+- 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
+- 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
+- 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
+- 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
+- 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
+- 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
+- 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
+- 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
+- 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
+- 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
+- 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
+- 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
+- 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
+- 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
+- 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
+- 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
+- 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
+- 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
+- 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
+- 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
+- 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
+- 0x85, 0xC8, 0xA1
+-};
+-
+-static const u8 exp_to_poly[492] = {
+- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
+- 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
+- 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
+- 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
+- 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
+- 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
+- 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
+- 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
+- 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
+- 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
+- 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
+- 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
+- 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
+- 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
+- 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
+- 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
+- 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
+- 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
+- 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
+- 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
+- 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
+- 0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D,
+- 0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC,
+- 0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3,
+- 0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52,
+- 0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
+- 0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1,
+- 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A,
+- 0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11,
+- 0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51,
+- 0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66,
+- 0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB,
+- 0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19,
+- 0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D,
+- 0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56,
+- 0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE,
+- 0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9,
+- 0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE,
+- 0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41,
+- 0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E,
+- 0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB
+-};
+-
+-
+-/* The table constants are indices of
+- * S-box entries, preprocessed through q0 and q1. */
+-static const u8 calc_sb_tbl[512] = {
+- 0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4,
+- 0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8,
+- 0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B,
+- 0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B,
+- 0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD,
+- 0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1,
+- 0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B,
+- 0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F,
+- 0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B,
+- 0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D,
+- 0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E,
+- 0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5,
+- 0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14,
+- 0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3,
+- 0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54,
+- 0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51,
+- 0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A,
+- 0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96,
+- 0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10,
+- 0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C,
+- 0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7,
+- 0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70,
+- 0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB,
+- 0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8,
+- 0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF,
+- 0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC,
+- 0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF,
+- 0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2,
+- 0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82,
+- 0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9,
+- 0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97,
+- 0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17,
+- 0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D,
+- 0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3,
+- 0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C,
+- 0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E,
+- 0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F,
+- 0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49,
+- 0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21,
+- 0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9,
+- 0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD,
+- 0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01,
+- 0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F,
+- 0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48,
+- 0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E,
+- 0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19,
+- 0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57,
+- 0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64,
+- 0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE,
+- 0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5,
+- 0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44,
+- 0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69,
+- 0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15,
+- 0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E,
+- 0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34,
+- 0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC,
+- 0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B,
+- 0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB,
+- 0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52,
+- 0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9,
+- 0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4,
+- 0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2,
+- 0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56,
+- 0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91
+-};
+-
+-/* Macro to perform one column of the RS matrix multiplication. The
+- * parameters a, b, c, and d are the four bytes of output; i is the index
+- * of the key bytes, and w, x, y, and z, are the column of constants from
+- * the RS matrix, preprocessed through the poly_to_exp table. */
+-
+-#define CALC_S(a, b, c, d, i, w, x, y, z) \
+- if (key[i]) { \
+- tmp = poly_to_exp[key[i] - 1]; \
+- (a) ^= exp_to_poly[tmp + (w)]; \
+- (b) ^= exp_to_poly[tmp + (x)]; \
+- (c) ^= exp_to_poly[tmp + (y)]; \
+- (d) ^= exp_to_poly[tmp + (z)]; \
+- }
+-
+-/* Macros to calculate the key-dependent S-boxes for a 128-bit key using
+- * the S vector from CALC_S. CALC_SB_2 computes a single entry in all
+- * four S-boxes, where i is the index of the entry to compute, and a and b
+- * are the index numbers preprocessed through the q0 and q1 tables
+- * respectively. */
+-
+-#define CALC_SB_2(i, a, b) \
+- ctx->s[0][i] = mds[0][q0[(a) ^ sa] ^ se]; \
+- ctx->s[1][i] = mds[1][q0[(b) ^ sb] ^ sf]; \
+- ctx->s[2][i] = mds[2][q1[(a) ^ sc] ^ sg]; \
+- ctx->s[3][i] = mds[3][q1[(b) ^ sd] ^ sh]
+-
+-/* Macro exactly like CALC_SB_2, but for 192-bit keys. */
+-
+-#define CALC_SB192_2(i, a, b) \
+- ctx->s[0][i] = mds[0][q0[q0[(b) ^ sa] ^ se] ^ si]; \
+- ctx->s[1][i] = mds[1][q0[q1[(b) ^ sb] ^ sf] ^ sj]; \
+- ctx->s[2][i] = mds[2][q1[q0[(a) ^ sc] ^ sg] ^ sk]; \
+- ctx->s[3][i] = mds[3][q1[q1[(a) ^ sd] ^ sh] ^ sl];
+-
+-/* Macro exactly like CALC_SB_2, but for 256-bit keys. */
+-
+-#define CALC_SB256_2(i, a, b) \
+- ctx->s[0][i] = mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \
+- ctx->s[1][i] = mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \
+- ctx->s[2][i] = mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \
+- ctx->s[3][i] = mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp];
+-
+-/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes the
+- * last two stages of the h() function for a given index (either 2i or 2i+1).
+- * a, b, c, and d are the four bytes going into the last two stages. For
+- * 128-bit keys, this is the entire h() function and a and c are the index
+- * preprocessed through q0 and q1 respectively; for longer keys they are the
+- * output of previous stages. j is the index of the first key byte to use.
+- * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
+- * twice, doing the Pseudo-Hadamard Transform, and doing the necessary
+- * rotations. Its parameters are: a, the array to write the results into,
+- * j, the index of the first output entry, k and l, the preprocessed indices
+- * for index 2i, and m and n, the preprocessed indices for index 2i+1.
+- * CALC_K192_2 expands CALC_K_2 to handle 192-bit keys, by doing an
+- * additional lookup-and-XOR stage. The parameters a, b, c and d are the
+- * four bytes going into the last three stages. For 192-bit keys, c = d
+- * are the index preprocessed through q0, and a = b are the index
+- * preprocessed through q1; j is the index of the first key byte to use.
+- * CALC_K192 is identical to CALC_K but for using the CALC_K192_2 macro
+- * instead of CALC_K_2.
+- * CALC_K256_2 expands CALC_K192_2 to handle 256-bit keys, by doing an
+- * additional lookup-and-XOR stage. The parameters a and b are the index
+- * preprocessed through q0 and q1 respectively; j is the index of the first
+- * key byte to use. CALC_K256 is identical to CALC_K but for using the
+- * CALC_K256_2 macro instead of CALC_K_2. */
+-
+-#define CALC_K_2(a, b, c, d, j) \
+- mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \
+- ^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \
+- ^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \
+- ^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]]
+-
+-#define CALC_K(a, j, k, l, m, n) \
+- x = CALC_K_2 (k, l, k, l, 0); \
+- y = CALC_K_2 (m, n, m, n, 4); \
+- y = rol32(y, 8); \
+- x += y; y += x; ctx->a[j] = x; \
+- ctx->a[(j) + 1] = rol32(y, 9)
+-
+-#define CALC_K192_2(a, b, c, d, j) \
+- CALC_K_2 (q0[a ^ key[(j) + 16]], \
+- q1[b ^ key[(j) + 17]], \
+- q0[c ^ key[(j) + 18]], \
+- q1[d ^ key[(j) + 19]], j)
+-
+-#define CALC_K192(a, j, k, l, m, n) \
+- x = CALC_K192_2 (l, l, k, k, 0); \
+- y = CALC_K192_2 (n, n, m, m, 4); \
+- y = rol32(y, 8); \
+- x += y; y += x; ctx->a[j] = x; \
+- ctx->a[(j) + 1] = rol32(y, 9)
+-
+-#define CALC_K256_2(a, b, j) \
+- CALC_K192_2 (q1[b ^ key[(j) + 24]], \
+- q1[a ^ key[(j) + 25]], \
+- q0[a ^ key[(j) + 26]], \
+- q0[b ^ key[(j) + 27]], j)
+-
+-#define CALC_K256(a, j, k, l, m, n) \
+- x = CALC_K256_2 (k, l, 0); \
+- y = CALC_K256_2 (m, n, 4); \
+- y = rol32(y, 8); \
+- x += y; y += x; ctx->a[j] = x; \
+- ctx->a[(j) + 1] = rol32(y, 9)
+-
+-
+ /* Macros to compute the g() function in the encryption and decryption
+ * rounds. G1 is the straight g() function; G2 includes the 8-bit
+ * rotation for the high 32-bit word. */
+@@ -630,176 +103,7 @@ static const u8 calc_sb_tbl[512] = {
+ x ^= ctx->w[m]; \
+ dst[n] = cpu_to_le32(x)
+
+-#define TF_MIN_KEY_SIZE 16
+-#define TF_MAX_KEY_SIZE 32
+-#define TF_BLOCK_SIZE 16
+-
+-/* Structure for an expanded Twofish key. s contains the key-dependent
+- * S-boxes composed with the MDS matrix; w contains the eight "whitening"
+- * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
+- * that k[i] corresponds to what the Twofish paper calls K[i+8]. */
+-struct twofish_ctx {
+- u32 s[4][256], w[8], k[32];
+-};
+-
+-/* Perform the key setup. */
+-static int twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int key_len, u32 *flags)
+-{
+-
+- struct twofish_ctx *ctx = crypto_tfm_ctx(tfm);
+
+- int i, j, k;
+-
+- /* Temporaries for CALC_K. */
+- u32 x, y;
+-
+- /* The S vector used to key the S-boxes, split up into individual bytes.
+- * 128-bit keys use only sa through sh; 256-bit use all of them. */
+- u8 sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0;
+- u8 si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0;
+-
+- /* Temporary for CALC_S. */
+- u8 tmp;
+-
+- /* Check key length. */
+- if (key_len != 16 && key_len != 24 && key_len != 32)
+- {
+- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+- return -EINVAL; /* unsupported key length */
+- }
+-
+- /* Compute the first two words of the S vector. The magic numbers are
+- * the entries of the RS matrix, preprocessed through poly_to_exp. The
+- * numbers in the comments are the original (polynomial form) matrix
+- * entries. */
+- CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+- CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+- CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+- CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+- CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+- CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+- CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+- CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+- CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+- CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+- CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+- CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+- CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+- CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+- CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+- CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+-
+- if (key_len == 24 || key_len == 32) { /* 192- or 256-bit key */
+- /* Calculate the third word of the S vector */
+- CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+- CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+- CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+- CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+- CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+- CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+- CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+- CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+- }
+-
+- if (key_len == 32) { /* 256-bit key */
+- /* Calculate the fourth word of the S vector */
+- CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+- CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+- CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+- CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+- CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+- CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+- CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+- CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+-
+- /* Compute the S-boxes. */
+- for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+- CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+- }
+-
+- /* Calculate whitening and round subkeys. The constants are
+- * indices of subkeys, preprocessed through q0 and q1. */
+- CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+- CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+- CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+- CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+- CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+- CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+- CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+- CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+- CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+- CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+- CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
+- CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+- CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
+- CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+- CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+- CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
+- CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+- CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+- CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
+- CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+- } else if (key_len == 24) { /* 192-bit key */
+- /* Compute the S-boxes. */
+- for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+- CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+- }
+-
+- /* Calculate whitening and round subkeys. The constants are
+- * indices of subkeys, preprocessed through q0 and q1. */
+- CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+- CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+- CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+- CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+- CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+- CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+- CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+- CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+- CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+- CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+- CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71);
+- CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+- CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F);
+- CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+- CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+- CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F);
+- CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+- CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+- CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00);
+- CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+- } else { /* 128-bit key */
+- /* Compute the S-boxes. */
+- for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+- CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+- }
+-
+- /* Calculate whitening and round subkeys. The constants are
+- * indices of subkeys, preprocessed through q0 and q1. */
+- CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+- CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+- CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+- CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+- CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+- CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+- CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+- CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+- CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+- CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+- CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
+- CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+- CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
+- CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+- CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+- CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
+- CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+- CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+- CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
+- CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+- }
+-
+- return 0;
+-}
+
+ /* Encrypt one block. in and out may be the same. */
+ static void twofish_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+@@ -877,6 +181,8 @@ static void twofish_decrypt(struct crypt
+
+ static struct crypto_alg alg = {
+ .cra_name = "twofish",
++ .cra_driver_name = "twofish-generic",
++ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = TF_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct twofish_ctx),
+diff --git a/crypto/twofish_common.c b/crypto/twofish_common.c
+new file mode 100644
+index 0000000..b4b9c0c
+--- /dev/null
++++ b/crypto/twofish_common.c
+@@ -0,0 +1,744 @@
++/*
++ * Common Twofish algorithm parts shared between the c and assembler
++ * implementations
++ *
++ * Originally Twofish for GPG
++ * By Matthew Skala <mskala at ansuz.sooke.bc.ca>, July 26, 1998
++ * 256-bit key length added March 20, 1999
++ * Some modifications to reduce the text size by Werner Koch, April, 1998
++ * Ported to the kerneli patch by Marc Mutz <Marc at Mutz.com>
++ * Ported to CryptoAPI by Colin Slater <hoho at tacomeat.net>
++ *
++ * The original author has disclaimed all copyright interest in this
++ * code and thus put it in the public domain. The subsequent authors
++ * have put this under the GNU General Public License.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
++ * USA
++ *
++ * This code is a "clean room" implementation, written from the paper
++ * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
++ * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
++ * through http://www.counterpane.com/twofish.html
++ *
++ * For background information on multiplication in finite fields, used for
++ * the matrix operations in the key schedule, see the book _Contemporary
++ * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
++ * Third Edition.
++ */
++
++#include <crypto/twofish.h>
++#include <linux/bitops.h>
++#include <linux/crypto.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++
++
++/* The large precomputed tables for the Twofish cipher (twofish.c)
++ * Taken from the same source as twofish.c
++ * Marc Mutz <Marc at Mutz.com>
++ */
++
++/* These two tables are the q0 and q1 permutations, exactly as described in
++ * the Twofish paper. */
++
++static const u8 q0[256] = {
++ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
++ 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
++ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
++ 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
++ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
++ 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
++ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
++ 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
++ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
++ 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
++ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
++ 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
++ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
++ 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
++ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
++ 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
++ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
++ 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
++ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
++ 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
++ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
++ 0x4A, 0x5E, 0xC1, 0xE0
++};
++
++static const u8 q1[256] = {
++ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
++ 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
++ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
++ 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
++ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
++ 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
++ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
++ 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
++ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
++ 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
++ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
++ 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
++ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
++ 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
++ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
++ 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
++ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
++ 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
++ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
++ 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
++ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
++ 0x55, 0x09, 0xBE, 0x91
++};
++
++/* These MDS tables are actually tables of MDS composed with q0 and q1,
++ * because it is only ever used that way and we can save some time by
++ * precomputing. Of course the main saving comes from precomputing the
++ * GF(2^8) multiplication involved in the MDS matrix multiply; by looking
++ * things up in these tables we reduce the matrix multiply to four lookups
++ * and three XORs. Semi-formally, the definition of these tables is:
++ * mds[0][i] = MDS (q1[i] 0 0 0)^T mds[1][i] = MDS (0 q0[i] 0 0)^T
++ * mds[2][i] = MDS (0 0 q1[i] 0)^T mds[3][i] = MDS (0 0 0 q0[i])^T
++ * where ^T means "transpose", the matrix multiply is performed in GF(2^8)
++ * represented as GF(2)[x]/v(x) where v(x)=x^8+x^6+x^5+x^3+1 as described
++ * by Schneier et al, and I'm casually glossing over the byte/word
++ * conversion issues. */
++
++static const u32 mds[4][256] = {
++ {
++ 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
++ 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
++ 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
++ 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
++ 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
++ 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
++ 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
++ 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
++ 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
++ 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
++ 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
++ 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
++ 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
++ 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
++ 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
++ 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
++ 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
++ 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
++ 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
++ 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
++ 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
++ 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
++ 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
++ 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
++ 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
++ 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
++ 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
++ 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
++ 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
++ 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
++ 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
++ 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
++ 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
++ 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
++ 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
++ 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
++ 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
++ 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
++ 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
++ 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
++ 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
++ 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
++ 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91},
++
++ {
++ 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
++ 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
++ 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
++ 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
++ 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
++ 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
++ 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
++ 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
++ 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
++ 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
++ 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
++ 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
++ 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
++ 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
++ 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
++ 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
++ 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
++ 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
++ 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
++ 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
++ 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
++ 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
++ 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
++ 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
++ 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
++ 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
++ 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
++ 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
++ 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
++ 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
++ 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
++ 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
++ 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
++ 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
++ 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
++ 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
++ 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
++ 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
++ 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
++ 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
++ 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
++ 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
++ 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8},
++
++ {
++ 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
++ 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
++ 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
++ 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
++ 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
++ 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
++ 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
++ 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
++ 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
++ 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
++ 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
++ 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
++ 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
++ 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
++ 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
++ 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
++ 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
++ 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
++ 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
++ 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
++ 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
++ 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
++ 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
++ 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
++ 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
++ 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
++ 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
++ 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
++ 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
++ 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
++ 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
++ 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
++ 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
++ 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
++ 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
++ 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
++ 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
++ 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
++ 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
++ 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
++ 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
++ 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
++ 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF},
++
++ {
++ 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
++ 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
++ 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
++ 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
++ 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
++ 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
++ 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
++ 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
++ 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
++ 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
++ 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
++ 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
++ 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
++ 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
++ 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
++ 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
++ 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
++ 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
++ 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
++ 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
++ 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
++ 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
++ 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
++ 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
++ 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
++ 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
++ 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
++ 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
++ 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
++ 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
++ 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
++ 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
++ 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
++ 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
++ 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
++ 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
++ 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
++ 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
++ 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
++ 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
++ 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
++ 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
++ 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8}
++};
++
++/* The exp_to_poly and poly_to_exp tables are used to perform efficient
++ * operations in GF(2^8) represented as GF(2)[x]/w(x) where
++ * w(x)=x^8+x^6+x^3+x^2+1. We care about doing that because it's part of the
++ * definition of the RS matrix in the key schedule. Elements of that field
++ * are polynomials of degree not greater than 7 and all coefficients 0 or 1,
++ * which can be represented naturally by bytes (just substitute x=2). In that
++ * form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8)
++ * multiplication is inefficient without hardware support. To multiply
++ * faster, I make use of the fact x is a generator for the nonzero elements,
++ * so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
++ * some n in 0..254. Note that that caret is exponentiation in GF(2^8),
++ * *not* polynomial notation. So if I want to compute pq where p and q are
++ * in GF(2^8), I can just say:
++ * 1. if p=0 or q=0 then pq=0
++ * 2. otherwise, find m and n such that p=x^m and q=x^n
++ * 3. pq=(x^m)(x^n)=x^(m+n), so add m and n and find pq
++ * The translations in steps 2 and 3 are looked up in the tables
++ * poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this
++ * in action, look at the CALC_S macro. As additional wrinkles, note that
++ * one of my operands is always a constant, so the poly_to_exp lookup on it
++ * is done in advance; I included the original values in the comments so
++ * readers can have some chance of recognizing that this *is* the RS matrix
++ * from the Twofish paper. I've only included the table entries I actually
++ * need; I never do a lookup on a variable input of zero and the biggest
++ * exponents I'll ever see are 254 (variable) and 237 (constant), so they'll
++ * never sum to more than 491. I'm repeating part of the exp_to_poly table
++ * so that I don't have to do mod-255 reduction in the exponent arithmetic.
++ * Since I know my constant operands are never zero, I only have to worry
++ * about zero values in the variable operand, and I do it with a simple
++ * conditional branch. I know conditionals are expensive, but I couldn't
++ * see a non-horrible way of avoiding them, and I did manage to group the
++ * statements so that each if covers four group multiplications. */
++
++static const u8 poly_to_exp[255] = {
++ 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
++ 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
++ 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
++ 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
++ 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
++ 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
++ 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
++ 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
++ 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
++ 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
++ 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
++ 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
++ 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
++ 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
++ 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
++ 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
++ 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
++ 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
++ 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
++ 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
++ 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
++ 0x85, 0xC8, 0xA1
++};
++
++static const u8 exp_to_poly[492] = {
++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
++ 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
++ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
++ 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
++ 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
++ 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
++ 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
++ 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
++ 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
++ 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
++ 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
++ 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
++ 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
++ 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
++ 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
++ 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
++ 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
++ 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
++ 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
++ 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
++ 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
++ 0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D,
++ 0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC,
++ 0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3,
++ 0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52,
++ 0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
++ 0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1,
++ 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A,
++ 0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11,
++ 0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51,
++ 0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66,
++ 0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB,
++ 0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19,
++ 0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D,
++ 0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56,
++ 0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE,
++ 0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9,
++ 0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE,
++ 0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41,
++ 0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E,
++ 0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB
++};
++
++
++/* The table constants are indices of
++ * S-box entries, preprocessed through q0 and q1. */
++static const u8 calc_sb_tbl[512] = {
++ 0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4,
++ 0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8,
++ 0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B,
++ 0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B,
++ 0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD,
++ 0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1,
++ 0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B,
++ 0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F,
++ 0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B,
++ 0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D,
++ 0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E,
++ 0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5,
++ 0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14,
++ 0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3,
++ 0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54,
++ 0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51,
++ 0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A,
++ 0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96,
++ 0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10,
++ 0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C,
++ 0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7,
++ 0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70,
++ 0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB,
++ 0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8,
++ 0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF,
++ 0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC,
++ 0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF,
++ 0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2,
++ 0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82,
++ 0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9,
++ 0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97,
++ 0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17,
++ 0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D,
++ 0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3,
++ 0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C,
++ 0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E,
++ 0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F,
++ 0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49,
++ 0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21,
++ 0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9,
++ 0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD,
++ 0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01,
++ 0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F,
++ 0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48,
++ 0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E,
++ 0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19,
++ 0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57,
++ 0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64,
++ 0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE,
++ 0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5,
++ 0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44,
++ 0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69,
++ 0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15,
++ 0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E,
++ 0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34,
++ 0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC,
++ 0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B,
++ 0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB,
++ 0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52,
++ 0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9,
++ 0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4,
++ 0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2,
++ 0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56,
++ 0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91
++};
++
++/* Macro to perform one column of the RS matrix multiplication. The
++ * parameters a, b, c, and d are the four bytes of output; i is the index
++ * of the key bytes, and w, x, y, and z, are the column of constants from
++ * the RS matrix, preprocessed through the poly_to_exp table. */
++
++#define CALC_S(a, b, c, d, i, w, x, y, z) \
++ if (key[i]) { \
++ tmp = poly_to_exp[key[i] - 1]; \
++ (a) ^= exp_to_poly[tmp + (w)]; \
++ (b) ^= exp_to_poly[tmp + (x)]; \
++ (c) ^= exp_to_poly[tmp + (y)]; \
++ (d) ^= exp_to_poly[tmp + (z)]; \
++ }
++
++/* Macros to calculate the key-dependent S-boxes for a 128-bit key using
++ * the S vector from CALC_S. CALC_SB_2 computes a single entry in all
++ * four S-boxes, where i is the index of the entry to compute, and a and b
++ * are the index numbers preprocessed through the q0 and q1 tables
++ * respectively. */
++
++#define CALC_SB_2(i, a, b) \
++ ctx->s[0][i] = mds[0][q0[(a) ^ sa] ^ se]; \
++ ctx->s[1][i] = mds[1][q0[(b) ^ sb] ^ sf]; \
++ ctx->s[2][i] = mds[2][q1[(a) ^ sc] ^ sg]; \
++ ctx->s[3][i] = mds[3][q1[(b) ^ sd] ^ sh]
++
++/* Macro exactly like CALC_SB_2, but for 192-bit keys. */
++
++#define CALC_SB192_2(i, a, b) \
++ ctx->s[0][i] = mds[0][q0[q0[(b) ^ sa] ^ se] ^ si]; \
++ ctx->s[1][i] = mds[1][q0[q1[(b) ^ sb] ^ sf] ^ sj]; \
++ ctx->s[2][i] = mds[2][q1[q0[(a) ^ sc] ^ sg] ^ sk]; \
++ ctx->s[3][i] = mds[3][q1[q1[(a) ^ sd] ^ sh] ^ sl];
++
++/* Macro exactly like CALC_SB_2, but for 256-bit keys. */
++
++#define CALC_SB256_2(i, a, b) \
++ ctx->s[0][i] = mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \
++ ctx->s[1][i] = mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \
++ ctx->s[2][i] = mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \
++ ctx->s[3][i] = mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp];
++
++/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes the
++ * last two stages of the h() function for a given index (either 2i or 2i+1).
++ * a, b, c, and d are the four bytes going into the last two stages. For
++ * 128-bit keys, this is the entire h() function and a and c are the index
++ * preprocessed through q0 and q1 respectively; for longer keys they are the
++ * output of previous stages. j is the index of the first key byte to use.
++ * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
++ * twice, doing the Pseudo-Hadamard Transform, and doing the necessary
++ * rotations. Its parameters are: a, the array to write the results into,
++ * j, the index of the first output entry, k and l, the preprocessed indices
++ * for index 2i, and m and n, the preprocessed indices for index 2i+1.
++ * CALC_K192_2 expands CALC_K_2 to handle 192-bit keys, by doing an
++ * additional lookup-and-XOR stage. The parameters a, b, c and d are the
++ * four bytes going into the last three stages. For 192-bit keys, c = d
++ * are the index preprocessed through q0, and a = b are the index
++ * preprocessed through q1; j is the index of the first key byte to use.
++ * CALC_K192 is identical to CALC_K but for using the CALC_K192_2 macro
++ * instead of CALC_K_2.
++ * CALC_K256_2 expands CALC_K192_2 to handle 256-bit keys, by doing an
++ * additional lookup-and-XOR stage. The parameters a and b are the index
++ * preprocessed through q0 and q1 respectively; j is the index of the first
++ * key byte to use. CALC_K256 is identical to CALC_K but for using the
++ * CALC_K256_2 macro instead of CALC_K_2. */
++
++#define CALC_K_2(a, b, c, d, j) \
++ mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \
++ ^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \
++ ^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \
++ ^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]]
++
++#define CALC_K(a, j, k, l, m, n) \
++ x = CALC_K_2 (k, l, k, l, 0); \
++ y = CALC_K_2 (m, n, m, n, 4); \
++ y = rol32(y, 8); \
++ x += y; y += x; ctx->a[j] = x; \
++ ctx->a[(j) + 1] = rol32(y, 9)
++
++#define CALC_K192_2(a, b, c, d, j) \
++ CALC_K_2 (q0[a ^ key[(j) + 16]], \
++ q1[b ^ key[(j) + 17]], \
++ q0[c ^ key[(j) + 18]], \
++ q1[d ^ key[(j) + 19]], j)
++
++#define CALC_K192(a, j, k, l, m, n) \
++ x = CALC_K192_2 (l, l, k, k, 0); \
++ y = CALC_K192_2 (n, n, m, m, 4); \
++ y = rol32(y, 8); \
++ x += y; y += x; ctx->a[j] = x; \
++ ctx->a[(j) + 1] = rol32(y, 9)
++
++#define CALC_K256_2(a, b, j) \
++ CALC_K192_2 (q1[b ^ key[(j) + 24]], \
++ q1[a ^ key[(j) + 25]], \
++ q0[a ^ key[(j) + 26]], \
++ q0[b ^ key[(j) + 27]], j)
++
++#define CALC_K256(a, j, k, l, m, n) \
++ x = CALC_K256_2 (k, l, 0); \
++ y = CALC_K256_2 (m, n, 4); \
++ y = rol32(y, 8); \
++ x += y; y += x; ctx->a[j] = x; \
++ ctx->a[(j) + 1] = rol32(y, 9)
++
++/* Perform the key setup. */
++int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
++{
++
++ struct twofish_ctx *ctx = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
++
++ int i, j, k;
++
++ /* Temporaries for CALC_K. */
++ u32 x, y;
++
++ /* The S vector used to key the S-boxes, split up into individual bytes.
++ * 128-bit keys use only sa through sh; 256-bit use all of them. */
++ u8 sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0;
++ u8 si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0;
++
++ /* Temporary for CALC_S. */
++ u8 tmp;
++
++ /* Check key length. */
++ if (key_len % 8)
++ {
++ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++ return -EINVAL; /* unsupported key length */
++ }
++
++ /* Compute the first two words of the S vector. The magic numbers are
++ * the entries of the RS matrix, preprocessed through poly_to_exp. The
++ * numbers in the comments are the original (polynomial form) matrix
++ * entries. */
++ CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
++ CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
++ CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
++ CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
++ CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
++ CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
++ CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
++ CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
++ CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
++ CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
++ CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
++ CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
++ CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
++ CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
++ CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
++ CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
++
++ if (key_len == 24 || key_len == 32) { /* 192- or 256-bit key */
++ /* Calculate the third word of the S vector */
++ CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
++ CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
++ CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
++ CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
++ CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
++ CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
++ CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
++ CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
++ }
++
++ if (key_len == 32) { /* 256-bit key */
++ /* Calculate the fourth word of the S vector */
++ CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
++ CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
++ CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
++ CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
++ CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
++ CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
++ CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
++ CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
++
++ /* Compute the S-boxes. */
++ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
++ CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
++ }
++
++ /* Calculate whitening and round subkeys. The constants are
++ * indices of subkeys, preprocessed through q0 and q1. */
++ CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
++ CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
++ CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
++ CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
++ CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
++ CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
++ CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
++ CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
++ CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
++ CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
++ CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
++ CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
++ CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
++ CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
++ CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
++ CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
++ CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
++ CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
++ CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
++ CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
++ } else if (key_len == 24) { /* 192-bit key */
++ /* Compute the S-boxes. */
++ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
++ CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
++ }
++
++ /* Calculate whitening and round subkeys. The constants are
++ * indices of subkeys, preprocessed through q0 and q1. */
++ CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
++ CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
++ CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
++ CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
++ CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
++ CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
++ CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
++ CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
++ CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
++ CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
++ CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71);
++ CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
++ CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F);
++ CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
++ CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
++ CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F);
++ CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
++ CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
++ CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00);
++ CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
++ } else { /* 128-bit key */
++ /* Compute the S-boxes. */
++ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
++ CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
++ }
++
++ /* Calculate whitening and round subkeys. The constants are
++ * indices of subkeys, preprocessed through q0 and q1. */
++ CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
++ CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
++ CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
++ CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
++ CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
++ CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
++ CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
++ CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
++ CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
++ CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
++ CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
++ CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
++ CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
++ CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
++ CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
++ CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
++ CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
++ CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
++ CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
++ CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
++ }
++
++ return 0;
++}
++
++EXPORT_SYMBOL_GPL(twofish_setkey);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Twofish cipher common functions");
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index 8b11ceb..f394634 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -14,10 +14,16 @@ source "drivers/pnp/Kconfig"
+
+ source "drivers/block/Kconfig"
+
++# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4
++
++source "drivers/misc/Kconfig"
++
+ source "drivers/ide/Kconfig"
+
+ source "drivers/scsi/Kconfig"
+
++source "drivers/ata/Kconfig"
++
+ source "drivers/cdrom/Kconfig"
+
+ source "drivers/md/Kconfig"
+@@ -50,8 +56,6 @@ source "drivers/w1/Kconfig"
+
+ source "drivers/hwmon/Kconfig"
+
+-source "drivers/misc/Kconfig"
+-
+ source "drivers/mfd/Kconfig"
+
+ source "drivers/media/Kconfig"
+diff --git a/drivers/Makefile b/drivers/Makefile
+index fc2d744..4ac14da 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_PPC_PMAC) += macintosh/
+ obj-$(CONFIG_IDE) += ide/
+ obj-$(CONFIG_FC4) += fc4/
+ obj-$(CONFIG_SCSI) += scsi/
++obj-$(CONFIG_ATA) += ata/
+ obj-$(CONFIG_FUSION) += message/
+ obj-$(CONFIG_IEEE1394) += ieee1394/
+ obj-y += cdrom/
+diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
+index 3dd6b7b..7fde8f4 100644
+--- a/drivers/acorn/block/mfmhd.c
++++ b/drivers/acorn/block/mfmhd.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/drivers/block/mfmhd.c
++ * linux/drivers/acorn/block/mfmhd.c
+ *
+ * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd at cs.man.ac.uk)
+ *
+@@ -938,7 +938,7 @@ static void do_mfm_request(request_queue
+ mfm_request();
+ }
+
+-static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs)
++static void mfm_interrupt_handler(int unused, void *dev_id)
+ {
+ void (*handler) (void) = do_mfm;
+
+diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
+index c26c08b..bdb9c8b 100644
+--- a/drivers/acorn/char/i2c.c
++++ b/drivers/acorn/char/i2c.c
+@@ -308,7 +308,6 @@ static struct i2c_algo_bit_data ioc_data
+ .getsda = ioc_getsda,
+ .getscl = ioc_getscl,
+ .udelay = 80,
+- .mdelay = 80,
+ .timeout = 100
+ };
+
+diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
+index 56c5ba8..0f9d4be 100644
+--- a/drivers/acpi/Kconfig
++++ b/drivers/acpi/Kconfig
+@@ -253,7 +253,7 @@ config ACPI_CUSTOM_DSDT
+ depends on !STANDALONE
+ default n
+ help
+- Thist option is to load a custom ACPI DSDT
++ This option is to load a custom ACPI DSDT
+ If you don't know what that is, say N.
+
+ config ACPI_CUSTOM_DSDT_FILE
+@@ -310,7 +310,7 @@ config X86_PM_TIMER
+ The Power Management Timer is available on all ACPI-capable,
+ in most cases even if ACPI is unusable or blacklisted.
+
+- This timing source is not affected by powermanagement features
++ This timing source is not affected by power management features
+ like aggressive processor idling, throttling, frequency and/or
+ voltage scaling, unlike the commonly used Time Stamp Counter
+ (TSC) timing source.
+@@ -345,7 +345,7 @@ config ACPI_HOTPLUG_MEMORY
+ Enabling this driver assumes that your platform hardware
+ and firmware have support for hot-plugging physical memory. If
+ your system does not support physically adding or ripping out
+- memory DIMMs at some platfrom defined granularity (individually
++ memory DIMMs at some platform defined granularity (individually
+ or as a bank) at runtime, then you need not enable this driver.
+
+ If one selects "m," this driver can be loaded using the following
+diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
+index 1dda370..6bcd9e8 100644
+--- a/drivers/acpi/acpi_memhotplug.c
++++ b/drivers/acpi/acpi_memhotplug.c
+@@ -85,6 +85,8 @@ struct acpi_memory_device {
+ struct list_head res_list;
+ };
+
++static int acpi_hotmem_initialized;
++
+ static acpi_status
+ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
+ {
+@@ -238,6 +240,10 @@ static int acpi_memory_enable_device(str
+ num_enabled++;
+ continue;
+ }
++
++ if (node < 0)
++ node = memory_add_physaddr_to_nid(info->start_addr);
++
+ result = add_memory(node, info->start_addr, info->length);
+ if (result)
+ continue;
+@@ -410,7 +416,7 @@ static int acpi_memory_device_add(struct
+ /* Set the device state */
+ mem_device->state = MEMORY_POWER_ON_STATE;
+
+- printk(KERN_INFO "%s \n", acpi_device_name(device));
++ printk(KERN_DEBUG "%s \n", acpi_device_name(device));
+
+ return result;
+ }
+@@ -434,6 +440,15 @@ static int acpi_memory_device_start (str
+ struct acpi_memory_device *mem_device;
+ int result = 0;
+
++ /*
++ * Early boot code has recognized memory area by EFI/E820.
++ * If DSDT shows these memory devices on boot, hotplug is not necessary
++ * for them. So, it just returns until completion of this driver's
++ * start up.
++ */
++ if (!acpi_hotmem_initialized)
++ return 0;
++
+ mem_device = acpi_driver_data(device);
+
+ if (!acpi_memory_check_device(mem_device)) {
+@@ -533,6 +548,7 @@ static int __init acpi_memory_device_ini
+ return -ENODEV;
+ }
+
++ acpi_hotmem_initialized = 1;
+ return 0;
+ }
+
+diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
+index e9ee4c5..c7ac929 100644
+--- a/drivers/acpi/asus_acpi.c
++++ b/drivers/acpi/asus_acpi.c
+@@ -138,6 +138,7 @@ struct asus_hotk {
+ S2x, //S200 (J1 reported), Victor MP-XP7210
+ W1N, //W1000N
+ W5A, //W5A
++ W3V, //W3030V
+ xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
+ //(Centrino)
+ END_MODEL
+@@ -376,6 +377,17 @@ static struct model_data model_conf[END_
+ .display_get = "\\ADVG"},
+
+ {
++ .name = "W3V",
++ .mt_mled = "MLED",
++ .mt_wled = "WLED",
++ .mt_lcd_switch = xxN_PREFIX "_Q10",
++ .lcd_status = "\\BKLT",
++ .brightness_set = "SPLV",
++ .brightness_get = "GPLV",
++ .display_set = "SDSP",
++ .display_get = "\\INFB"},
++
++ {
+ .name = "xxN",
+ .mt_mled = "MLED",
+ /* WLED present, but not controlled by ACPI */
+@@ -555,11 +567,11 @@ static int
+ write_led(const char __user * buffer, unsigned long count,
+ char *ledname, int ledmask, int invert)
+ {
+- int value;
++ int rv, value;
+ int led_out = 0;
+
+- count = parse_arg(buffer, count, &value);
+- if (count > 0)
++ rv = parse_arg(buffer, count, &value);
++ if (rv > 0)
+ led_out = value ? 1 : 0;
+
+ hotk->status =
+@@ -572,7 +584,7 @@ write_led(const char __user * buffer, un
+ printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
+ ledname);
+
+- return count;
++ return rv;
+ }
+
+ /*
+@@ -607,20 +619,18 @@ static int
+ proc_write_ledd(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+ {
+- int value;
++ int rv, value;
+
+- count = parse_arg(buffer, count, &value);
+- if (count > 0) {
++ rv = parse_arg(buffer, count, &value);
++ if (rv > 0) {
+ if (!write_acpi_int
+ (hotk->handle, hotk->methods->mt_ledd, value, NULL))
+ printk(KERN_WARNING
+ "Asus ACPI: LED display write failed\n");
+ else
+ hotk->ledd_status = (u32) value;
+- } else if (count < 0)
+- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+-
+- return count;
++ }
++ return rv;
+ }
+
+ /*
+@@ -761,12 +771,12 @@ static int
+ proc_write_lcd(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+ {
+- int value;
++ int rv, value;
+
+- count = parse_arg(buffer, count, &value);
+- if (count > 0)
++ rv = parse_arg(buffer, count, &value);
++ if (rv > 0)
+ set_lcd_state(value);
+- return count;
++ return rv;
+ }
+
+ static int read_brightness(void)
+@@ -830,18 +840,15 @@ static int
+ proc_write_brn(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+ {
+- int value;
++ int rv, value;
+
+- count = parse_arg(buffer, count, &value);
+- if (count > 0) {
++ rv = parse_arg(buffer, count, &value);
++ if (rv > 0) {
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+ set_brightness(value);
+- } else if (count < 0) {
+- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+ }
+-
+- return count;
++ return rv;
+ }
+
+ static void set_display(int value)
+@@ -880,15 +887,12 @@ static int
+ proc_write_disp(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+ {
+- int value;
++ int rv, value;
+
+- count = parse_arg(buffer, count, &value);
+- if (count > 0)
++ rv = parse_arg(buffer, count, &value);
++ if (rv > 0)
+ set_display(value);
+- else if (count < 0)
+- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+-
+- return count;
++ return rv;
+ }
+
+ typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
+@@ -1097,6 +1101,8 @@ static int asus_model_match(char *model)
+ return A4G;
+ else if (strncmp(model, "W1N", 3) == 0)
+ return W1N;
++ else if (strncmp(model, "W3V", 3) == 0)
++ return W3V;
+ else if (strncmp(model, "W5A", 3) == 0)
+ return W5A;
+ else
+@@ -1200,9 +1206,10 @@ static int asus_hotk_get_info(void)
+ hotk->methods->mt_wled = NULL;
+ /* L5D's WLED is not controlled by ACPI */
+ else if (strncmp(string, "M2N", 3) == 0 ||
++ strncmp(string, "W3V", 3) == 0 ||
+ strncmp(string, "S1N", 3) == 0)
+ hotk->methods->mt_wled = "WLED";
+- /* M2N and S1N have a usable WLED */
++ /* M2N, S1N and W3V have a usable WLED */
+ else if (asus_info) {
+ if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
+ hotk->methods->mled_status = NULL;
+diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
+index 9810e2a..026e407 100644
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(str
+
+ static int acpi_battery_add(struct acpi_device *device);
+ static int acpi_battery_remove(struct acpi_device *device, int type);
++static int acpi_battery_resume(struct acpi_device *device, int status);
+
+ static struct acpi_driver acpi_battery_driver = {
+ .name = ACPI_BATTERY_DRIVER_NAME,
+@@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_d
+ .ids = ACPI_BATTERY_HID,
+ .ops = {
+ .add = acpi_battery_add,
++ .resume = acpi_battery_resume,
+ .remove = acpi_battery_remove,
+ },
+ };
+@@ -753,6 +755,18 @@ static int acpi_battery_remove(struct ac
+ return 0;
+ }
+
++/* this is needed to learn about changes made in suspended state */
++static int acpi_battery_resume(struct acpi_device *device, int state)
++{
++ struct acpi_battery *battery;
++
++ if (!device)
++ return -EINVAL;
++
++ battery = device->driver_data;
++ return acpi_battery_check(battery);
++}
++
+ static int __init acpi_battery_init(void)
+ {
+ int result;
+diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
+index a01ce67..4a9b7bf 100644
+--- a/drivers/acpi/cm_sbs.c
++++ b/drivers/acpi/cm_sbs.c
+@@ -67,7 +67,7 @@ void acpi_unlock_ac_dir(struct proc_dir_
+ lock_ac_dir_cnt--;
+ if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
+ remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
+- acpi_ac_dir = 0;
++ acpi_ac_dir = NULL;
+ }
+ mutex_unlock(&cm_sbs_mutex);
+ }
+@@ -99,7 +99,7 @@ void acpi_unlock_battery_dir(struct proc
+ if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
+ && acpi_battery_dir) {
+ remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
+- acpi_battery_dir = 0;
++ acpi_battery_dir = NULL;
+ }
+ mutex_unlock(&cm_sbs_mutex);
+ return;
+diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
+index e5d7963..e6d4b08 100644
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -45,206 +45,143 @@ ACPI_MODULE_NAME("acpi_ec")
+ #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver"
+ #define ACPI_EC_DEVICE_NAME "Embedded Controller"
+ #define ACPI_EC_FILE_INFO "info"
++
++/* EC status register */
+ #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_DELAY 50 /* Wait 50ms max. during EC ops */
+-#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+-#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
+-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
++
++/* EC commands */
+ #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
+-#define EC_POLL 0xFF
+-#define EC_INTR 0x00
++
++/* EC events */
++enum {
++ ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
++ ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
++};
++
++#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_UDELAY 100 /* Poll @ 100us increments */
++#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
++
++enum {
++ EC_INTR = 1, /* Output buffer full */
++ EC_POLL, /* Input buffer empty */
++};
++
+ static int acpi_ec_remove(struct acpi_device *device, int type);
+ static int acpi_ec_start(struct acpi_device *device);
+ static int acpi_ec_stop(struct acpi_device *device, int type);
+-static int acpi_ec_intr_add(struct acpi_device *device);
+-static int acpi_ec_poll_add(struct acpi_device *device);
++static int acpi_ec_add(struct acpi_device *device);
+
+ static struct acpi_driver acpi_ec_driver = {
+ .name = ACPI_EC_DRIVER_NAME,
+ .class = ACPI_EC_CLASS,
+ .ids = ACPI_EC_HID,
+ .ops = {
+- .add = acpi_ec_intr_add,
++ .add = acpi_ec_add,
+ .remove = acpi_ec_remove,
+ .start = acpi_ec_start,
+ .stop = acpi_ec_stop,
+ },
+ };
+-union acpi_ec {
+- struct {
+- u32 mode;
+- acpi_handle handle;
+- unsigned long uid;
+- unsigned long gpe_bit;
+- struct acpi_generic_address status_addr;
+- struct acpi_generic_address command_addr;
+- struct acpi_generic_address data_addr;
+- unsigned long global_lock;
+- } common;
+-
+- struct {
+- u32 mode;
+- acpi_handle handle;
+- unsigned long uid;
+- unsigned long gpe_bit;
+- struct acpi_generic_address status_addr;
+- struct acpi_generic_address command_addr;
+- struct acpi_generic_address data_addr;
+- unsigned long global_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;
+- } intr;
+-
+- struct {
+- u32 mode;
+- acpi_handle handle;
+- unsigned long uid;
+- unsigned long gpe_bit;
+- struct acpi_generic_address status_addr;
+- struct acpi_generic_address command_addr;
+- struct acpi_generic_address data_addr;
+- unsigned long global_lock;
+- struct semaphore sem;
+- } poll;
+-};
+
+-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
+-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
+-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data);
+-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data);
+-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data);
+-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data);
+-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data);
+-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data);
+-static void acpi_ec_gpe_poll_query(void *ec_cxt);
+-static void acpi_ec_gpe_intr_query(void *ec_cxt);
+-static u32 acpi_ec_gpe_poll_handler(void *data);
+-static u32 acpi_ec_gpe_intr_handler(void *data);
+-static acpi_status __init
+-acpi_fake_ecdt_poll_callback(acpi_handle handle,
+- u32 Level, void *context, void **retval);
+-
+-static acpi_status __init
+-acpi_fake_ecdt_intr_callback(acpi_handle handle,
+- u32 Level, void *context, void **retval);
+-
+-static int __init acpi_ec_poll_get_real_ecdt(void);
+-static int __init acpi_ec_intr_get_real_ecdt(void);
+ /* If we find an EC via the ECDT, we need to keep a ptr to its context */
+-static union acpi_ec *ec_ecdt;
++struct acpi_ec {
++ acpi_handle handle;
++ unsigned long uid;
++ unsigned long gpe_bit;
++ unsigned long command_addr;
++ unsigned long data_addr;
++ unsigned long global_lock;
++ struct semaphore sem;
++ unsigned int expect_event;
++ atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
++ wait_queue_head_t wait;
++} *ec_ecdt;
+
+ /* External interfaces use first EC only, so remember */
+ static struct acpi_device *first_ec;
+-static int acpi_ec_poll_mode = EC_INTR;
++static int acpi_ec_mode = EC_INTR;
+
+ /* --------------------------------------------------------------------------
+ Transaction Management
+ -------------------------------------------------------------------------- */
+
+-static u32 acpi_ec_read_status(union acpi_ec *ec)
++static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
+ {
+- u32 status = 0;
+-
+- acpi_hw_low_level_read(8, &status, &ec->common.status_addr);
+- return status;
++ return inb(ec->command_addr);
+ }
+
+-static int acpi_ec_wait(union acpi_ec *ec, u8 event)
++static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
+ {
+- if (acpi_ec_poll_mode)
+- return acpi_ec_poll_wait(ec, event);
+- else
+- return acpi_ec_intr_wait(ec, event);
++ return inb(ec->data_addr);
+ }
+
+-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event)
++static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
+ {
+- u32 acpi_ec_status = 0;
+- u32 i = ACPI_EC_UDELAY_COUNT;
++ outb(command, ec->command_addr);
++}
+
+- if (!ec)
+- return -EINVAL;
++static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
++{
++ outb(data, ec->data_addr);
++}
+
+- /* Poll the EC status register waiting for the event to occur. */
++static int acpi_ec_check_status(u8 status, u8 event)
++{
+ switch (event) {
+- case ACPI_EC_EVENT_OBF:
+- do {
+- acpi_hw_low_level_read(8, &acpi_ec_status,
+- &ec->common.status_addr);
+- if (acpi_ec_status & ACPI_EC_FLAG_OBF)
+- return 0;
+- udelay(ACPI_EC_UDELAY);
+- } while (--i > 0);
++ case ACPI_EC_EVENT_OBF_1:
++ if (status & ACPI_EC_FLAG_OBF)
++ return 1;
+ break;
+- case ACPI_EC_EVENT_IBE:
+- do {
+- acpi_hw_low_level_read(8, &acpi_ec_status,
+- &ec->common.status_addr);
+- if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
+- return 0;
+- udelay(ACPI_EC_UDELAY);
+- } while (--i > 0);
++ case ACPI_EC_EVENT_IBF_0:
++ if (!(status & ACPI_EC_FLAG_IBF))
++ return 1;
+ break;
+ default:
+- return -EINVAL;
++ break;
+ }
+
+- return -ETIME;
++ return 0;
+ }
+-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
+-{
+- int result = 0;
+-
+
+- ec->intr.expect_event = event;
+- smp_mb();
++static int acpi_ec_wait(struct acpi_ec *ec, u8 event)
++{
++ int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0;
++ long time_left;
+
+- switch (event) {
+- case ACPI_EC_EVENT_IBE:
+- if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) {
+- ec->intr.expect_event = 0;
+- return 0;
+- }
+- break;
+- default:
+- break;
++ ec->expect_event = event;
++ if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
++ ec->expect_event = 0;
++ return 0;
+ }
+
+- result = wait_event_timeout(ec->intr.wait,
+- !ec->intr.expect_event,
++ do {
++ if (acpi_ec_mode == EC_POLL) {
++ udelay(ACPI_EC_UDELAY);
++ } else {
++ time_left = wait_event_timeout(ec->wait,
++ !ec->expect_event,
+ msecs_to_jiffies(ACPI_EC_DELAY));
+-
+- ec->intr.expect_event = 0;
+- smp_mb();
+-
+- /*
+- * 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:
+- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
++ if (time_left > 0) {
++ ec->expect_event = 0;
++ return 0;
++ }
++ }
++ if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
++ ec->expect_event = 0;
+ return 0;
+- break;
++ }
++ } while (--i > 0);
+
+- case ACPI_EC_EVENT_IBE:
+- if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
+- return 0;
+- break;
+- }
++ ec->expect_event = 0;
+
+ return -ETIME;
+ }
+@@ -254,272 +191,150 @@ static int acpi_ec_intr_wait(union acpi_
+ * Note: samsung nv5000 doesn't work with ec burst mode.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=4980
+ */
+-int acpi_ec_enter_burst_mode(union acpi_ec *ec)
++int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
+ {
+- u32 tmp = 0;
+- int status = 0;
++ u8 tmp = 0;
++ u8 status = 0;
+
+
+ status = acpi_ec_read_status(ec);
+ if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
++ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (status)
+ goto end;
+- acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE,
+- &ec->common.command_addr);
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+- acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
++ acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
++ status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
++ tmp = acpi_ec_read_data(ec);
+ if (tmp != 0x90) { /* Burst ACK byte */
+ return -EINVAL;
+ }
+ }
+
+- atomic_set(&ec->intr.leaving_burst, 0);
++ atomic_set(&ec->leaving_burst, 0);
+ return 0;
+- end:
+- ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
++ end:
++ ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
+ return -1;
+ }
+
+-int acpi_ec_leave_burst_mode(union acpi_ec *ec)
++int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
+ {
+- int status = 0;
++ u8 status = 0;
+
+
+ status = acpi_ec_read_status(ec);
+ if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
+- status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
++ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if(status)
+ goto end;
+- acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
+- acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
+- }
+- atomic_set(&ec->intr.leaving_burst, 1);
++ acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
++ acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
++ }
++ atomic_set(&ec->leaving_burst, 1);
+ return 0;
+-end:
+- ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
++ end:
++ ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
+ return -1;
+ }
+ #endif /* ACPI_FUTURE_USAGE */
+
+-static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
+-{
+- if (acpi_ec_poll_mode)
+- return acpi_ec_poll_read(ec, address, data);
+- else
+- return acpi_ec_intr_read(ec, address, data);
+-}
+-static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
+-{
+- if (acpi_ec_poll_mode)
+- return acpi_ec_poll_write(ec, address, data);
+- else
+- return acpi_ec_intr_write(ec, address, data);
+-}
+-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
++static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
++ const u8 *wdata, unsigned wdata_len,
++ u8 *rdata, unsigned rdata_len)
+ {
+- acpi_status status = AE_OK;
+- int result = 0;
+- u32 glk = 0;
++ int result;
+
++ acpi_ec_write_cmd(ec, command);
+
+- if (!ec || !data)
+- return -EINVAL;
+-
+- *data = 0;
+-
+- if (ec->common.global_lock) {
+- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+- if (ACPI_FAILURE(status))
+- return -ENODEV;
++ for (; wdata_len > 0; wdata_len --) {
++ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
++ if (result)
++ return result;
++ acpi_ec_write_data(ec, *(wdata++));
+ }
+
+- if (down_interruptible(&ec->poll.sem)) {
+- result = -ERESTARTSYS;
+- goto end_nosem;
++ if (command == ACPI_EC_COMMAND_WRITE) {
++ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
++ if (result)
++ return result;
+ }
+-
+- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
+- &ec->common.command_addr);
+- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (result)
+- goto end;
+-
+- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
+- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+- if (result)
+- goto end;
+-
+- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+-
+- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
+- *data, address));
+-
+- end:
+- up(&ec->poll.sem);
+-end_nosem:
+- if (ec->common.global_lock)
+- acpi_release_global_lock(glk);
+-
+- return result;
+-}
+-
+-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
+-{
+- int result = 0;
+- acpi_status status = AE_OK;
+- u32 glk = 0;
+
++ for (; rdata_len > 0; rdata_len --) {
++ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
++ if (result)
++ return result;
+
+- if (!ec)
+- return -EINVAL;
+-
+- if (ec->common.global_lock) {
+- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+- if (ACPI_FAILURE(status))
+- return -ENODEV;
+- }
+-
+- if (down_interruptible(&ec->poll.sem)) {
+- result = -ERESTARTSYS;
+- goto end_nosem;
++ *(rdata++) = acpi_ec_read_data(ec);
+ }
+-
+- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
+- &ec->common.command_addr);
+- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (result)
+- goto end;
+-
+- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
+- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (result)
+- goto end;
+-
+- acpi_hw_low_level_write(8, data, &ec->common.data_addr);
+- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (result)
+- goto end;
+
+- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
+- data, address));
+-
+- end:
+- up(&ec->poll.sem);
+-end_nosem:
+- if (ec->common.global_lock)
+- acpi_release_global_lock(glk);
+-
+- return result;
++ return 0;
+ }
+
+-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
++static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
++ const u8 *wdata, unsigned wdata_len,
++ u8 *rdata, unsigned rdata_len)
+ {
+- int status = 0;
++ int status;
+ u32 glk;
+
+-
+- if (!ec || !data)
++ if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
+ return -EINVAL;
+
+- *data = 0;
++ if (rdata)
++ memset(rdata, 0, rdata_len);
+
+- if (ec->common.global_lock) {
++ if (ec->global_lock) {
+ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ }
++ down(&ec->sem);
+
+- WARN_ON(in_interrupt());
+- down(&ec->intr.sem);
+-
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
++ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (status) {
+ printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
+ goto end;
+ }
+- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
+- &ec->common.command_addr);
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
+- }
+
+- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
+- goto end;
+- }
+- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
+- *data, address));
++ status = acpi_ec_transaction_unlocked(ec, command,
++ wdata, wdata_len,
++ rdata, rdata_len);
+
+- end:
+- up(&ec->intr.sem);
++end:
++ up(&ec->sem);
+
+- if (ec->common.global_lock)
++ if (ec->global_lock)
+ acpi_release_global_lock(glk);
+
+ return status;
+ }
+
+-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
++static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+ {
+- int status = 0;
+- u32 glk;
+-
+-
+- if (!ec)
+- return -EINVAL;
+-
+- if (ec->common.global_lock) {
+- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+- if (ACPI_FAILURE(status))
+- return -ENODEV;
+- }
+-
+- WARN_ON(in_interrupt());
+- down(&ec->intr.sem);
+-
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
+- }
+- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
+- &ec->common.command_addr);
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
+- }
+-
+- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
+- }
+-
+- acpi_hw_low_level_write(8, data, &ec->common.data_addr);
++ int result;
++ u8 d;
+
+- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
+- data, address));
+-
+- up(&ec->intr.sem);
+-
+- if (ec->common.global_lock)
+- acpi_release_global_lock(glk);
++ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
++ &address, 1, &d, 1);
++ *data = d;
++ return result;
++}
+
+- return status;
++static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
++{
++ u8 wdata[2] = { address, data };
++ return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
++ wdata, 2, NULL, 0);
+ }
+
+ /*
+ * Externally callable EC access functions. For now, assume 1 EC only
+ */
+-int ec_read(u8 addr, u8 * val)
++int ec_read(u8 addr, u8 *val)
+ {
+- union acpi_ec *ec;
++ struct acpi_ec *ec;
+ int err;
+- u32 temp_data;
++ u8 temp_data;
+
+ if (!first_ec)
+ return -ENODEV;
+@@ -539,7 +354,7 @@ EXPORT_SYMBOL(ec_read);
+
+ int ec_write(u8 addr, u8 val)
+ {
+- union acpi_ec *ec;
++ struct acpi_ec *ec;
+ int err;
+
+ if (!first_ec)
+@@ -554,255 +369,106 @@ int ec_write(u8 addr, u8 val)
+
+ EXPORT_SYMBOL(ec_write);
+
+-static int acpi_ec_query(union acpi_ec *ec, u32 * data)
+-{
+- if (acpi_ec_poll_mode)
+- return acpi_ec_poll_query(ec, data);
+- else
+- return acpi_ec_intr_query(ec, data);
+-}
+-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
++extern int ec_transaction(u8 command,
++ const u8 *wdata, unsigned wdata_len,
++ u8 *rdata, unsigned rdata_len)
+ {
+- int result = 0;
+- acpi_status status = AE_OK;
+- u32 glk = 0;
+-
+-
+- if (!ec || !data)
+- return -EINVAL;
+-
+- *data = 0;
+-
+- if (ec->common.global_lock) {
+- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+- if (ACPI_FAILURE(status))
+- return -ENODEV;
+- }
++ struct acpi_ec *ec;
+
+- /*
+- * 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).
+- */
+- if (down_interruptible(&ec->poll.sem)) {
+- result = -ERESTARTSYS;
+- goto end_nosem;
+- }
+-
+- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
+- &ec->common.command_addr);
+- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+- if (result)
+- goto end;
+-
+- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+- if (!*data)
+- result = -ENODATA;
++ if (!first_ec)
++ return -ENODEV;
+
+- end:
+- up(&ec->poll.sem);
+-end_nosem:
+- if (ec->common.global_lock)
+- acpi_release_global_lock(glk);
++ ec = acpi_driver_data(first_ec);
+
+- return result;
++ return acpi_ec_transaction(ec, command, wdata,
++ wdata_len, rdata, rdata_len);
+ }
+-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
+-{
+- int status = 0;
+- u32 glk;
+-
+
+- if (!ec || !data)
+- return -EINVAL;
+- *data = 0;
+-
+- if (ec->common.global_lock) {
+- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+- if (ACPI_FAILURE(status))
+- return -ENODEV;
+- }
++EXPORT_SYMBOL(ec_transaction);
+
+- down(&ec->intr.sem);
++static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
++{
++ int result;
++ u8 d;
+
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "query EC, IB not empty\n");
+- 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).
+- */
+- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
+- &ec->common.command_addr);
+- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+- if (status) {
+- printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
+- goto end;
+- }
++ if (!ec || !data)
++ return -EINVAL;
+
+- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+- if (!*data)
+- status = -ENODATA;
++ /*
++ * 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).
++ */
+
+- end:
+- up(&ec->intr.sem);
++ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
++ if (result)
++ return result;
+
+- if (ec->common.global_lock)
+- acpi_release_global_lock(glk);
++ if (!d)
++ return -ENODATA;
+
+- return status;
++ *data = d;
++ return 0;
+ }
+
+ /* --------------------------------------------------------------------------
+ Event Management
+ -------------------------------------------------------------------------- */
+
+-union acpi_ec_query_data {
++struct acpi_ec_query_data {
+ acpi_handle handle;
+ u8 data;
+ };
+
+ static void acpi_ec_gpe_query(void *ec_cxt)
+ {
+- if (acpi_ec_poll_mode)
+- acpi_ec_gpe_poll_query(ec_cxt);
+- else
+- acpi_ec_gpe_intr_query(ec_cxt);
+-}
+-
+-static void acpi_ec_gpe_poll_query(void *ec_cxt)
+-{
+- union acpi_ec *ec = (union acpi_ec *)ec_cxt;
+- u32 value = 0;
+- 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'
+- };
+-
++ struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
++ u8 value = 0;
++ static char object_name[8];
+
+- if (!ec_cxt)
++ if (!ec)
+ goto end;
+
+- if (down_interruptible (&ec->poll.sem)) {
+- return;
+- }
+- acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
+- up(&ec->poll.sem);
+-
+- /* 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).
+- */
++ value = acpi_ec_read_status(ec);
++
+ if (!(value & ACPI_EC_FLAG_SCI))
+ 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));
++ snprintf(object_name, 8, "_Q%2.2X", value);
+
+- acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
+
+- end:
+- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+-}
+-static void acpi_ec_gpe_intr_query(void *ec_cxt)
+-{
+- union acpi_ec *ec = (union acpi_ec *)ec_cxt;
+- 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_evaluate_object(ec->handle, object_name, NULL, NULL);
+
+-
+- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
+- result = acpi_ec_query(ec, &value);
+-
+- if (result)
+- 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->common.handle, object_name, NULL, NULL);
+ end:
+- atomic_dec(&ec->intr.pending_gpe);
+- return;
++ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ }
+
+ static u32 acpi_ec_gpe_handler(void *data)
+ {
+- if (acpi_ec_poll_mode)
+- return acpi_ec_gpe_poll_handler(data);
+- else
+- return acpi_ec_gpe_intr_handler(data);
+-}
+-static u32 acpi_ec_gpe_poll_handler(void *data)
+-{
+ acpi_status status = AE_OK;
+- union acpi_ec *ec = (union acpi_ec *)data;
+-
+- if (!ec)
+- return ACPI_INTERRUPT_NOT_HANDLED;
+-
+- acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+-
+- status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
+-
+- if (status == AE_OK)
+- return ACPI_INTERRUPT_HANDLED;
+- else
+- return ACPI_INTERRUPT_NOT_HANDLED;
+-}
+-static u32 acpi_ec_gpe_intr_handler(void *data)
+-{
+- acpi_status status = AE_OK;
+- u32 value;
+- union acpi_ec *ec = (union acpi_ec *)data;
+-
+- if (!ec)
+- return ACPI_INTERRUPT_NOT_HANDLED;
++ u8 value;
++ struct acpi_ec *ec = (struct acpi_ec *)data;
+
+- acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
++ acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+ value = acpi_ec_read_status(ec);
+
+- switch (ec->intr.expect_event) {
+- case ACPI_EC_EVENT_OBF:
+- if (!(value & ACPI_EC_FLAG_OBF))
+- break;
+- ec->intr.expect_event = 0;
+- wake_up(&ec->intr.wait);
+- break;
+- case ACPI_EC_EVENT_IBE:
+- if ((value & ACPI_EC_FLAG_IBF))
+- break;
+- ec->intr.expect_event = 0;
+- wake_up(&ec->intr.wait);
+- break;
+- default:
+- break;
++ if (acpi_ec_mode == EC_INTR) {
++ if (acpi_ec_check_status(value, ec->expect_event)) {
++ ec->expect_event = 0;
++ wake_up(&ec->wait);
++ }
+ }
+
+ if (value & ACPI_EC_FLAG_SCI) {
+- atomic_add(1, &ec->intr.pending_gpe);
+- status = acpi_os_execute(OSL_EC_BURST_HANDLER,
+- acpi_ec_gpe_query, ec);
++ status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
+ return status == AE_OK ?
+ ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
+ }
+- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
++ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+ return status == AE_OK ?
+ ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
+ }
+@@ -833,7 +499,7 @@ acpi_ec_space_handler(u32 function,
+ void *handler_context, void *region_context)
+ {
+ int result = 0;
+- union acpi_ec *ec = NULL;
++ struct acpi_ec *ec = NULL;
+ u64 temp = *value;
+ acpi_integer f_v = 0;
+ int i = 0;
+@@ -843,18 +509,16 @@ acpi_ec_space_handler(u32 function,
+ return AE_BAD_PARAMETER;
+
+ if (bit_width != 8 && acpi_strict) {
+- printk(KERN_WARNING PREFIX
+- "acpi_ec_space_handler: bit_width should be 8\n");
+ return AE_BAD_PARAMETER;
+ }
+
+- ec = (union acpi_ec *)handler_context;
++ ec = (struct acpi_ec *)handler_context;
+
+ next_byte:
+ switch (function) {
+ case ACPI_READ:
+ temp = 0;
+- result = acpi_ec_read(ec, (u8) address, (u32 *) & temp);
++ result = acpi_ec_read(ec, (u8) address, (u8 *) &temp);
+ break;
+ case ACPI_WRITE:
+ result = acpi_ec_write(ec, (u8) address, (u8) temp);
+@@ -905,20 +569,20 @@ static struct proc_dir_entry *acpi_ec_di
+
+ static int acpi_ec_read_info(struct seq_file *seq, void *offset)
+ {
+- union acpi_ec *ec = (union acpi_ec *)seq->private;
++ struct acpi_ec *ec = (struct acpi_ec *)seq->private;
+
+
+ if (!ec)
+ goto end;
+
+ seq_printf(seq, "gpe bit: 0x%02x\n",
+- (u32) ec->common.gpe_bit);
++ (u32) ec->gpe_bit);
+ seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
+- (u32) ec->common.status_addr.address,
+- (u32) ec->common.data_addr.address);
++ (u32) ec->command_addr,
++ (u32) ec->data_addr);
+ seq_printf(seq, "use global lock: %s\n",
+- ec->common.global_lock ? "yes" : "no");
+- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
++ ec->global_lock ? "yes" : "no");
++ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+
+ end:
+ return 0;
+@@ -929,7 +593,7 @@ static int acpi_ec_info_open_fs(struct i
+ return single_open(file, acpi_ec_read_info, PDE(inode)->data);
+ }
+
+-static const struct file_operations acpi_ec_info_ops = {
++static struct file_operations acpi_ec_info_ops = {
+ .open = acpi_ec_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -978,101 +642,35 @@ static int acpi_ec_remove_fs(struct acpi
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+-static int acpi_ec_poll_add(struct acpi_device *device)
++static int acpi_ec_add(struct acpi_device *device)
+ {
+ int result = 0;
+ acpi_status status = AE_OK;
+- union acpi_ec *ec = NULL;
++ struct acpi_ec *ec = NULL;
+
+
+ if (!device)
+ return -EINVAL;
+
+- ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
++ ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec)
+ return -ENOMEM;
+- memset(ec, 0, sizeof(union acpi_ec));
+-
+- ec->common.handle = device->handle;
+- ec->common.uid = -1;
+- init_MUTEX(&ec->poll.sem);
+- strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
+- strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+- acpi_driver_data(device) = ec;
+-
+- /* Use the global lock for all EC transactions? */
+- acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
+- &ec->common.global_lock);
+-
+- /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+- http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+- if (ec_ecdt) {
+- acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
+- ACPI_ADR_SPACE_EC,
+- &acpi_ec_space_handler);
+-
+- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+- &acpi_ec_gpe_handler);
+-
+- kfree(ec_ecdt);
++ memset(ec, 0, sizeof(struct acpi_ec));
++
++ ec->handle = device->handle;
++ ec->uid = -1;
++ init_MUTEX(&ec->sem);
++ if (acpi_ec_mode == EC_INTR) {
++ atomic_set(&ec->leaving_burst, 1);
++ init_waitqueue_head(&ec->wait);
+ }
+-
+- /* Get GPE bit assignment (EC events). */
+- /* TODO: Add support for _GPE returning a package */
+- status =
+- acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
+- &ec->common.gpe_bit);
+- if (ACPI_FAILURE(status)) {
+- ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
+- result = -ENODEV;
+- goto end;
+- }
+-
+- result = acpi_ec_add_fs(device);
+- if (result)
+- goto end;
+-
+- printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n",
+- acpi_device_name(device), acpi_device_bid(device),
+- (u32) ec->common.gpe_bit);
+-
+- if (!first_ec)
+- first_ec = device;
+-
+- end:
+- if (result)
+- kfree(ec);
+-
+- return result;
+-}
+-static int acpi_ec_intr_add(struct acpi_device *device)
+-{
+- int result = 0;
+- acpi_status status = AE_OK;
+- union acpi_ec *ec = NULL;
+-
+-
+- if (!device)
+- return -EINVAL;
+-
+- ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+- if (!ec)
+- return -ENOMEM;
+- memset(ec, 0, sizeof(union acpi_ec));
+-
+- ec->common.handle = device->handle;
+- ec->common.uid = -1;
+- atomic_set(&ec->intr.pending_gpe, 0);
+- atomic_set(&ec->intr.leaving_burst, 1);
+- init_MUTEX(&ec->intr.sem);
+- init_waitqueue_head(&ec->intr.wait);
+ strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+ acpi_driver_data(device) = ec;
+
+ /* Use the global lock for all EC transactions? */
+- acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
+- &ec->common.global_lock);
++ acpi_evaluate_integer(ec->handle, "_GLK", NULL,
++ &ec->global_lock);
+
+ /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+ http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+@@ -1081,7 +679,7 @@ static int acpi_ec_intr_add(struct acpi_
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler);
+
+- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
++ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ &acpi_ec_gpe_handler);
+
+ kfree(ec_ecdt);
+@@ -1090,10 +688,10 @@ static int acpi_ec_intr_add(struct acpi_
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ status =
+- acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
+- &ec->common.gpe_bit);
++ acpi_evaluate_integer(ec->handle, "_GPE", NULL,
++ &ec->gpe_bit);
+ if (ACPI_FAILURE(status)) {
+- printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n");
++ ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment"));
+ result = -ENODEV;
+ goto end;
+ }
+@@ -1102,14 +700,14 @@ static int acpi_ec_intr_add(struct acpi_
+ if (result)
+ goto end;
+
+- printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n",
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
+ acpi_device_name(device), acpi_device_bid(device),
+- (u32) ec->common.gpe_bit);
++ (u32) ec->gpe_bit));
+
+ if (!first_ec)
+ first_ec = device;
+
+- end:
++ end:
+ if (result)
+ kfree(ec);
+
+@@ -1118,7 +716,7 @@ static int acpi_ec_intr_add(struct acpi_
+
+ static int acpi_ec_remove(struct acpi_device *device, int type)
+ {
+- union acpi_ec *ec = NULL;
++ struct acpi_ec *ec = NULL;
+
+
+ if (!device)
+@@ -1136,8 +734,7 @@ static int acpi_ec_remove(struct acpi_de
+ static acpi_status
+ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
+ {
+- union acpi_ec *ec = (union acpi_ec *)context;
+- struct acpi_generic_address *addr;
++ struct acpi_ec *ec = (struct acpi_ec *)context;
+
+ if (resource->type != ACPI_RESOURCE_TYPE_IO) {
+ return AE_OK;
+@@ -1148,26 +745,21 @@ acpi_ec_io_ports(struct acpi_resource *r
+ * the second address region returned is the status/command
+ * port.
+ */
+- if (ec->common.data_addr.register_bit_width == 0) {
+- addr = &ec->common.data_addr;
+- } else if (ec->common.command_addr.register_bit_width == 0) {
+- addr = &ec->common.command_addr;
++ if (ec->data_addr == 0) {
++ ec->data_addr = resource->data.io.minimum;
++ } else if (ec->command_addr == 0) {
++ ec->command_addr = resource->data.io.minimum;
+ } else {
+ return AE_CTRL_TERMINATE;
+ }
+
+- addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+- addr->register_bit_width = 8;
+- addr->register_bit_offset = 0;
+- addr->address = resource->data.io.minimum;
+-
+ return AE_OK;
+ }
+
+ static int acpi_ec_start(struct acpi_device *device)
+ {
+ acpi_status status = AE_OK;
+- union acpi_ec *ec = NULL;
++ struct acpi_ec *ec = NULL;
+
+
+ if (!device)
+@@ -1181,39 +773,35 @@ static int acpi_ec_start(struct acpi_dev
+ /*
+ * Get I/O port addresses. Convert to GAS format.
+ */
+- status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS,
++ status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
+ acpi_ec_io_ports, ec);
+- if (ACPI_FAILURE(status)
+- || ec->common.command_addr.register_bit_width == 0) {
+- printk(KERN_ERR PREFIX "Error getting I/O port addresses\n");
++ if (ACPI_FAILURE(status) || ec->command_addr == 0) {
++ ACPI_EXCEPTION((AE_INFO, status,
++ "Error getting I/O port addresses"));
+ return -ENODEV;
+ }
+
+- ec->common.status_addr = ec->common.command_addr;
+-
+- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
+- (u32) ec->common.gpe_bit,
+- (u32) ec->common.command_addr.address,
+- (u32) ec->common.data_addr.address));
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
++ ec->gpe_bit, ec->command_addr, ec->data_addr));
+
+ /*
+ * Install GPE handler
+ */
+- status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit,
++ status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
+ if (ACPI_FAILURE(status)) {
+ return -ENODEV;
+ }
+- acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
++ acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
++ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+
+- status = acpi_install_address_space_handler(ec->common.handle,
++ status = acpi_install_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler,
+ &acpi_ec_space_setup, ec);
+ if (ACPI_FAILURE(status)) {
+- acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
++ acpi_remove_gpe_handler(NULL, ec->gpe_bit,
+ &acpi_ec_gpe_handler);
+ return -ENODEV;
+ }
+@@ -1224,7 +812,7 @@ static int acpi_ec_start(struct acpi_dev
+ static int acpi_ec_stop(struct acpi_device *device, int type)
+ {
+ acpi_status status = AE_OK;
+- union acpi_ec *ec = NULL;
++ struct acpi_ec *ec = NULL;
+
+
+ if (!device)
+@@ -1232,14 +820,14 @@ static int acpi_ec_stop(struct acpi_devi
+
+ ec = acpi_driver_data(device);
+
+- status = acpi_remove_address_space_handler(ec->common.handle,
++ status = acpi_remove_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ status =
+- acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
++ acpi_remove_gpe_handler(NULL, ec->gpe_bit,
+ &acpi_ec_gpe_handler);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+@@ -1251,76 +839,30 @@ static acpi_status __init
+ acpi_fake_ecdt_callback(acpi_handle handle,
+ u32 Level, void *context, void **retval)
+ {
+-
+- if (acpi_ec_poll_mode)
+- return acpi_fake_ecdt_poll_callback(handle,
+- Level, context, retval);
+- else
+- return acpi_fake_ecdt_intr_callback(handle,
+- Level, context, retval);
+-}
+-
+-static acpi_status __init
+-acpi_fake_ecdt_poll_callback(acpi_handle handle,
+- u32 Level, void *context, void **retval)
+-{
+- acpi_status status;
+-
+- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+- acpi_ec_io_ports, ec_ecdt);
+- if (ACPI_FAILURE(status))
+- return status;
+- ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
+-
+- ec_ecdt->common.uid = -1;
+- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
+-
+- status =
+- acpi_evaluate_integer(handle, "_GPE", NULL,
+- &ec_ecdt->common.gpe_bit);
+- if (ACPI_FAILURE(status))
+- return status;
+- init_MUTEX(&ec_ecdt->poll.sem);
+- ec_ecdt->common.global_lock = TRUE;
+- ec_ecdt->common.handle = handle;
+-
+- printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
+- (u32) ec_ecdt->common.gpe_bit,
+- (u32) ec_ecdt->common.command_addr.address,
+- (u32) ec_ecdt->common.data_addr.address);
+-
+- return AE_CTRL_TERMINATE;
+-}
+-
+-static acpi_status __init
+-acpi_fake_ecdt_intr_callback(acpi_handle handle,
+- u32 Level, void *context, void **retval)
+-{
+ acpi_status status;
+
+- init_MUTEX(&ec_ecdt->intr.sem);
+- init_waitqueue_head(&ec_ecdt->intr.wait);
++ init_MUTEX(&ec_ecdt->sem);
++ if (acpi_ec_mode == EC_INTR) {
++ init_waitqueue_head(&ec_ecdt->wait);
++ }
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ acpi_ec_io_ports, ec_ecdt);
+ if (ACPI_FAILURE(status))
+ return status;
+- ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
+
+- ec_ecdt->common.uid = -1;
+- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
++ ec_ecdt->uid = -1;
++ acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
+
+ status =
+ acpi_evaluate_integer(handle, "_GPE", NULL,
+- &ec_ecdt->common.gpe_bit);
++ &ec_ecdt->gpe_bit);
+ if (ACPI_FAILURE(status))
+ return status;
+- ec_ecdt->common.global_lock = TRUE;
+- ec_ecdt->common.handle = handle;
++ ec_ecdt->global_lock = TRUE;
++ ec_ecdt->handle = handle;
+
+- printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
+- (u32) ec_ecdt->common.gpe_bit,
+- (u32) ec_ecdt->common.command_addr.address,
+- (u32) ec_ecdt->common.data_addr.address);
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
++ ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr));
+
+ return AE_CTRL_TERMINATE;
+ }
+@@ -1340,14 +882,14 @@ static int __init acpi_ec_fake_ecdt(void
+ acpi_status status;
+ int ret = 0;
+
+- printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
+
+- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
++ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec_ecdt) {
+ ret = -ENOMEM;
+ goto error;
+ }
+- memset(ec_ecdt, 0, sizeof(union acpi_ec));
++ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+
+ status = acpi_get_devices(ACPI_EC_HID,
+ acpi_fake_ecdt_callback, NULL, NULL);
+@@ -1355,24 +897,16 @@ static int __init acpi_ec_fake_ecdt(void
+ kfree(ec_ecdt);
+ ec_ecdt = NULL;
+ ret = -ENODEV;
++ ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
+ goto error;
+ }
+ return 0;
+- error:
+- printk(KERN_ERR PREFIX "Can't make an fake ECDT\n");
++ error:
+ return ret;
+ }
+
+ static int __init acpi_ec_get_real_ecdt(void)
+ {
+- if (acpi_ec_poll_mode)
+- return acpi_ec_poll_get_real_ecdt();
+- else
+- return acpi_ec_intr_get_real_ecdt();
+-}
+-
+-static int __init acpi_ec_poll_get_real_ecdt(void)
+-{
+ acpi_status status;
+ struct acpi_table_ecdt *ecdt_ptr;
+
+@@ -1382,80 +916,36 @@ static int __init acpi_ec_poll_get_real_
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+- printk(KERN_INFO PREFIX "Found ECDT\n");
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
+
+ /*
+ * Generate a temporary ec context to use until the namespace is scanned
+ */
+- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
++ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec_ecdt)
+ return -ENOMEM;
+- memset(ec_ecdt, 0, sizeof(union acpi_ec));
+-
+- ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
+- ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
+- ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
+- ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
+- init_MUTEX(&ec_ecdt->poll.sem);
+- /* use the GL just to be safe */
+- ec_ecdt->common.global_lock = TRUE;
+- ec_ecdt->common.uid = ecdt_ptr->uid;
++ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+
+- status =
+- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
+- if (ACPI_FAILURE(status)) {
+- goto error;
++ init_MUTEX(&ec_ecdt->sem);
++ if (acpi_ec_mode == EC_INTR) {
++ init_waitqueue_head(&ec_ecdt->wait);
+ }
+-
+- return 0;
+- error:
+- printk(KERN_ERR PREFIX "Could not use ECDT\n");
+- kfree(ec_ecdt);
+- ec_ecdt = NULL;
+-
+- return -ENODEV;
+-}
+-
+-static int __init acpi_ec_intr_get_real_ecdt(void)
+-{
+- acpi_status status;
+- struct acpi_table_ecdt *ecdt_ptr;
+-
+- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
+- (struct acpi_table_header **)
+- &ecdt_ptr);
+- if (ACPI_FAILURE(status))
+- return -ENODEV;
+-
+- printk(KERN_INFO PREFIX "Found ECDT\n");
+-
+- /*
+- * Generate a temporary ec context to use until the namespace is scanned
+- */
+- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+- if (!ec_ecdt)
+- return -ENOMEM;
+- memset(ec_ecdt, 0, sizeof(union acpi_ec));
+-
+- init_MUTEX(&ec_ecdt->intr.sem);
+- init_waitqueue_head(&ec_ecdt->intr.wait);
+- ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
+- ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
+- ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
+- ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
++ ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
++ ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
++ ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
+ /* use the GL just to be safe */
+- ec_ecdt->common.global_lock = TRUE;
+- ec_ecdt->common.uid = ecdt_ptr->uid;
++ ec_ecdt->global_lock = TRUE;
++ ec_ecdt->uid = ecdt_ptr->uid;
+
+ status =
+- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
++ acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+ if (ACPI_FAILURE(status)) {
+ goto error;
+ }
+
+ return 0;
+- error:
+- printk(KERN_ERR PREFIX "Could not use ECDT\n");
++ error:
++ ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
+ kfree(ec_ecdt);
+ ec_ecdt = NULL;
+
+@@ -1480,14 +970,14 @@ int __init acpi_ec_ecdt_probe(void)
+ /*
+ * Install GPE handler
+ */
+- status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
++ status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec_ecdt);
+ if (ACPI_FAILURE(status)) {
+ goto error;
+ }
+- acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+- acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR);
++ acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
++ acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
+
+ status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_EC,
+@@ -1495,7 +985,7 @@ int __init acpi_ec_ecdt_probe(void)
+ &acpi_ec_space_setup,
+ ec_ecdt);
+ if (ACPI_FAILURE(status)) {
+- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
++ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ &acpi_ec_gpe_handler);
+ goto error;
+ }
+@@ -1503,7 +993,7 @@ int __init acpi_ec_ecdt_probe(void)
+ return 0;
+
+ error:
+- printk(KERN_ERR PREFIX "Could not use ECDT\n");
++ ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
+ kfree(ec_ecdt);
+ ec_ecdt = NULL;
+
+@@ -1562,13 +1052,13 @@ static int __init acpi_ec_set_intr_mode(
+ return 0;
+
+ if (intr) {
+- acpi_ec_poll_mode = EC_INTR;
+- acpi_ec_driver.ops.add = acpi_ec_intr_add;
++ acpi_ec_mode = EC_INTR;
+ } else {
+- acpi_ec_poll_mode = EC_POLL;
+- acpi_ec_driver.ops.add = acpi_ec_poll_add;
++ acpi_ec_mode = EC_POLL;
+ }
+- printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling");
++ acpi_ec_driver.ops.add = acpi_ec_add;
++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));
++
+ return 1;
+ }
+
+diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
+index 6eef4ef..ee2a10b 100644
+--- a/drivers/acpi/events/evmisc.c
++++ b/drivers/acpi/events/evmisc.c
+@@ -342,20 +342,8 @@ static u32 acpi_ev_global_lock_handler(v
+ if (acquired) {
+
+ /* Got the lock, now wake all threads waiting for it */
+-
+ acpi_gbl_global_lock_acquired = TRUE;
+-
+- /* Run the Global Lock thread which will signal all waiting threads */
+-
+- status =
+- acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
+- acpi_ev_global_lock_thread, context);
+- if (ACPI_FAILURE(status)) {
+- ACPI_EXCEPTION((AE_INFO, status,
+- "Could not queue Global Lock thread"));
+-
+- return (ACPI_INTERRUPT_NOT_HANDLED);
+- }
++ acpi_ev_global_lock_thread(context);
+ }
+
+ return (ACPI_INTERRUPT_HANDLED);
+diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
+index 5b3c7a8..203d135 100644
+--- a/drivers/acpi/events/evrgnini.c
++++ b/drivers/acpi/events/evrgnini.c
+@@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_han
+ if (!
+ (ACPI_STRNCMP
+ (object_hID.value, PCI_ROOT_HID_STRING,
+- sizeof(PCI_ROOT_HID_STRING))
+- ||
+- !(ACPI_STRNCMP
+- (object_hID.value,
+- PCI_EXPRESS_ROOT_HID_STRING,
+- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
+- {
++ sizeof(PCI_ROOT_HID_STRING)))
++ ||
++ !(ACPI_STRNCMP
++ (object_hID.value,
++ PCI_EXPRESS_ROOT_HID_STRING,
++ sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
+
+ /* Install a handler for this PCI root bridge */
+
+diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
+index 3143f36..fa58c1e 100644
+--- a/drivers/acpi/hardware/hwregs.c
++++ b/drivers/acpi/hardware/hwregs.c
+@@ -665,8 +665,6 @@ acpi_status acpi_hw_register_write(u8 us
+
+ /*
+ * Perform a read first to preserve certain bits (per ACPI spec)
+- *
+- * Note: This includes SCI_EN, we never want to change this bit
+ */
+ status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_CONTROL,
+diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
+index 6809c28..6342e61 100644
+--- a/drivers/acpi/i2c_ec.c
++++ b/drivers/acpi/i2c_ec.c
+@@ -293,7 +293,7 @@ static u32 acpi_ec_smb_func(struct i2c_a
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
+ }
+
+-static struct i2c_algorithm acpi_ec_smbus_algorithm = {
++static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
+ .smbus_xfer = acpi_ec_smb_access,
+ .functionality = acpi_ec_smb_func,
+ };
+diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
+index 15fc124..003a987 100644
+--- a/drivers/acpi/ibm_acpi.c
++++ b/drivers/acpi/ibm_acpi.c
+@@ -1702,13 +1702,11 @@ static struct ibm_struct ibms[] = {
+ .name = "brightness",
+ .read = brightness_read,
+ .write = brightness_write,
+- .experimental = 1,
+ },
+ {
+ .name = "volume",
+ .read = volume_read,
+ .write = volume_write,
+- .experimental = 1,
+ },
+ {
+ .name = "fan",
+diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
+index ec6b7f9..2e17ec7 100644
+--- a/drivers/acpi/motherboard.c
++++ b/drivers/acpi/motherboard.c
+@@ -48,6 +48,12 @@ ACPI_MODULE_NAME("acpi_motherboard")
+ * the io ports if they really know they can use it, while
+ * still preventing hotplug PCI devices from using it.
+ */
++
++/*
++ * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
++ * and PNP0C02, redundant with acpi_reserve_io_ranges().
++ * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
++ */
+ static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
+ {
+ struct resource *requested_res = NULL;
+diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
+index 507f051..c84286c 100644
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -73,6 +73,7 @@ static unsigned int acpi_irq_irq;
+ static acpi_osd_handler acpi_irq_handler;
+ static void *acpi_irq_context;
+ static struct workqueue_struct *kacpid_wq;
++static struct workqueue_struct *kacpi_notify_wq;
+
+ acpi_status acpi_os_initialize(void)
+ {
+@@ -91,8 +92,9 @@ acpi_status acpi_os_initialize1(void)
+ return AE_NULL_ENTRY;
+ }
+ kacpid_wq = create_singlethread_workqueue("kacpid");
++ kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
+ BUG_ON(!kacpid_wq);
+-
++ BUG_ON(!kacpi_notify_wq);
+ return AE_OK;
+ }
+
+@@ -104,6 +106,7 @@ acpi_status acpi_os_terminate(void)
+ }
+
+ destroy_workqueue(kacpid_wq);
++ destroy_workqueue(kacpi_notify_wq);
+
+ return AE_OK;
+ }
+@@ -237,7 +240,7 @@ acpi_os_table_override(struct acpi_table
+ return AE_OK;
+ }
+
+-static irqreturn_t acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t acpi_irq(int irq, void *dev_id)
+ {
+ return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+ }
+@@ -566,10 +569,7 @@ void acpi_os_derive_pci_id(acpi_handle r
+
+ static void acpi_os_execute_deferred(void *context)
+ {
+- struct acpi_os_dpc *dpc = NULL;
+-
+-
+- dpc = (struct acpi_os_dpc *)context;
++ struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
+ if (!dpc) {
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+ return;
+@@ -604,14 +604,12 @@ acpi_status acpi_os_execute(acpi_execute
+ struct acpi_os_dpc *dpc;
+ struct work_struct *task;
+
+- ACPI_FUNCTION_TRACE("os_queue_for_execution");
+-
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Scheduling function [%p(%p)] for deferred execution.\n",
+ function, context));
+
+ if (!function)
+- return_ACPI_STATUS(AE_BAD_PARAMETER);
++ return AE_BAD_PARAMETER;
+
+ /*
+ * Allocate/initialize DPC structure. Note that this memory will be
+@@ -624,26 +622,20 @@ acpi_status acpi_os_execute(acpi_execute
+ * from the same memory.
+ */
+
+- dpc =
+- kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
+- GFP_ATOMIC);
++ dpc = kmalloc(sizeof(struct acpi_os_dpc) +
++ sizeof(struct work_struct), GFP_ATOMIC);
+ if (!dpc)
+- return_ACPI_STATUS(AE_NO_MEMORY);
+-
++ return AE_NO_MEMORY;
+ dpc->function = function;
+ dpc->context = context;
+-
+ task = (void *)(dpc + 1);
+ INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
+-
+- if (!queue_work(kacpid_wq, task)) {
+- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+- "Call to queue_work() failed.\n"));
+- kfree(dpc);
++ if (!queue_work((type == OSL_NOTIFY_HANDLER)?
++ kacpi_notify_wq : kacpid_wq, task)) {
+ status = AE_ERROR;
++ kfree(dpc);
+ }
+-
+- return_ACPI_STATUS(status);
++ return status;
+ }
+
+ EXPORT_SYMBOL(acpi_os_execute);
+@@ -1079,7 +1071,7 @@ acpi_status acpi_os_purge_cache(acpi_cac
+
+ acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
+ {
+- (void)kmem_cache_destroy(cache);
++ kmem_cache_destroy(cache);
+ return (AE_OK);
+ }
+
+diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
+index 7f3e7e7..d53bd98 100644
+--- a/drivers/acpi/pci_link.c
++++ b/drivers/acpi/pci_link.c
+@@ -307,7 +307,7 @@ static int acpi_pci_link_set(struct acpi
+ if (!link || !irq)
+ return -EINVAL;
+
+- resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC);
++ resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
+ if (!resource)
+ return -ENOMEM;
+
+diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
+index fec225d..fe67a8a 100644
+--- a/drivers/acpi/power.c
++++ b/drivers/acpi/power.c
+@@ -216,10 +216,8 @@ static int acpi_power_off_device(acpi_ha
+ {
+ int result = 0;
+ acpi_status status = AE_OK;
+- struct acpi_device *device = NULL;
+ struct acpi_power_resource *resource = NULL;
+
+-
+ result = acpi_power_get_context(handle, &resource);
+ if (result)
+ return result;
+@@ -230,13 +228,13 @@ static int acpi_power_off_device(acpi_ha
+ if (resource->references) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Resource [%s] is still in use, dereferencing\n",
+- device->pnp.bus_id));
++ resource->device->pnp.bus_id));
+ return 0;
+ }
+
+ if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
+- device->pnp.bus_id));
++ resource->device->pnp.bus_id));
+ return 0;
+ }
+
+@@ -251,8 +249,7 @@ static int acpi_power_off_device(acpi_ha
+ return -ENOEXEC;
+
+ /* Update the power resource's _device_ power state */
+- device = resource->device;
+- device->power.state = ACPI_STATE_D3;
++ resource->device->power.state = ACPI_STATE_D3;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
+ resource->name));
+diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
+index b13d644..1908e0d 100644
+--- a/drivers/acpi/processor_core.c
++++ b/drivers/acpi/processor_core.c
+@@ -519,7 +519,7 @@ static int acpi_processor_get_info(struc
+
+ static void *processor_device_array[NR_CPUS];
+
+-static int acpi_processor_start(struct acpi_device *device)
++static int __cpuinit acpi_processor_start(struct acpi_device *device)
+ {
+ int result = 0;
+ acpi_status status = AE_OK;
+diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
+index 7106606..65b3f05 100644
+--- a/drivers/acpi/processor_idle.c
++++ b/drivers/acpi/processor_idle.c
+@@ -38,6 +38,7 @@
+ #include <linux/dmi.h>
+ #include <linux/moduleparam.h>
+ #include <linux/sched.h> /* need_resched() */
++#include <linux/latency.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -218,6 +219,23 @@ static void acpi_safe_halt(void)
+
+ static atomic_t c3_cpu_count;
+
++/* Common C-state entry for C2, C3, .. */
++static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
++{
++ if (cstate->space_id == ACPI_CSTATE_FFH) {
++ /* Call into architectural FFH based C-state */
++ acpi_processor_ffh_cstate_enter(cstate);
++ } else {
++ int unused;
++ /* IO port based C-state */
++ inb(cstate->address);
++ /* Dummy wait op - must do something useless after P_LVL2 read
++ because chipsets cannot guarantee that STPCLK# signal
++ gets asserted in time to freeze execution properly. */
++ unused = inl(acpi_fadt.xpm_tmr_blk.address);
++ }
++}
++
+ static void acpi_processor_idle(void)
+ {
+ struct acpi_processor *pr = NULL;
+@@ -360,11 +378,7 @@ static void acpi_processor_idle(void)
+ /* Get start time (ticks) */
+ t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Invoke C2 */
+- inb(cx->address);
+- /* Dummy wait op - must do something useless after P_LVL2 read
+- because chipsets cannot guarantee that STPCLK# signal
+- gets asserted in time to freeze execution properly. */
+- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
++ acpi_cstate_enter(cx);
+ /* Get end time (ticks) */
+ t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+
+@@ -400,9 +414,7 @@ static void acpi_processor_idle(void)
+ /* Get start time (ticks) */
+ t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Invoke C3 */
+- inb(cx->address);
+- /* Dummy wait op (see above) */
+- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
++ acpi_cstate_enter(cx);
+ /* Get end time (ticks) */
+ t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ if (pr->flags.bm_check) {
+@@ -453,7 +465,8 @@ static void acpi_processor_idle(void)
+ */
+ if (cx->promotion.state &&
+ ((cx->promotion.state - pr->power.states) <= max_cstate)) {
+- if (sleep_ticks > cx->promotion.threshold.ticks) {
++ if (sleep_ticks > cx->promotion.threshold.ticks &&
++ cx->promotion.state->latency <= system_latency_constraint()) {
+ cx->promotion.count++;
+ cx->demotion.count = 0;
+ if (cx->promotion.count >=
+@@ -494,8 +507,10 @@ static void acpi_processor_idle(void)
+ end:
+ /*
+ * Demote if current state exceeds max_cstate
++ * or if the latency of the current state is unacceptable
+ */
+- if ((pr->power.state - pr->power.states) > max_cstate) {
++ if ((pr->power.state - pr->power.states) > max_cstate ||
++ pr->power.state->latency > system_latency_constraint()) {
+ if (cx->demotion.state)
+ next_state = cx->demotion.state;
+ }
+@@ -624,20 +639,16 @@ static int acpi_processor_get_power_info
+ return 0;
+ }
+
+-static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
++static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
+ {
+-
+- /* Zero initialize all the C-states info. */
+- memset(pr->power.states, 0, sizeof(pr->power.states));
+-
+- /* set the first C-State to C1 */
+- pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+-
+- /* the C0 state only exists as a filler in our array,
+- * and all processors need to support C1 */
++ if (!pr->power.states[ACPI_STATE_C1].valid) {
++ /* set the first C-State to C1 */
++ /* all processors need to support C1 */
++ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
++ pr->power.states[ACPI_STATE_C1].valid = 1;
++ }
++ /* the C0 state only exists as a filler in our array */
+ pr->power.states[ACPI_STATE_C0].valid = 1;
+- pr->power.states[ACPI_STATE_C1].valid = 1;
+-
+ return 0;
+ }
+
+@@ -654,12 +665,7 @@ static int acpi_processor_get_power_info
+ if (nocst)
+ return -ENODEV;
+
+- current_count = 1;
+-
+- /* Zero initialize C2 onwards and prepare for fresh CST lookup */
+- for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
+- memset(&(pr->power.states[i]), 0,
+- sizeof(struct acpi_processor_cx));
++ current_count = 0;
+
+ status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+@@ -714,22 +720,39 @@ static int acpi_processor_get_power_info
+ (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
+ continue;
+
+- cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
+- 0 : reg->address;
+-
+ /* There should be an easy way to extract an integer... */
+ obj = (union acpi_object *)&(element->package.elements[1]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.type = obj->integer.value;
+-
+- if ((cx.type != ACPI_STATE_C1) &&
+- (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
+- continue;
+-
+- if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
+- continue;
++ /*
++ * Some buggy BIOSes won't list C1 in _CST -
++ * Let acpi_processor_get_power_info_default() handle them later
++ */
++ if (i == 1 && cx.type != ACPI_STATE_C1)
++ current_count++;
++
++ cx.address = reg->address;
++ cx.index = current_count + 1;
++
++ cx.space_id = ACPI_CSTATE_SYSTEMIO;
++ if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
++ if (acpi_processor_ffh_cstate_probe
++ (pr->id, &cx, reg) == 0) {
++ cx.space_id = ACPI_CSTATE_FFH;
++ } else if (cx.type != ACPI_STATE_C1) {
++ /*
++ * C1 is a special case where FIXED_HARDWARE
++ * can be handled in non-MWAIT way as well.
++ * In that case, save this _CST entry info.
++ * That is, we retain space_id of SYSTEM_IO for
++ * halt based C1.
++ * Otherwise, ignore this info and continue.
++ */
++ continue;
++ }
++ }
+
+ obj = (union acpi_object *)&(element->package.elements[2]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+@@ -934,11 +957,17 @@ static int acpi_processor_get_power_info
+ /* NOTE: the idle thread may not be running while calling
+ * this function */
+
+- /* Adding C1 state */
+- acpi_processor_get_power_info_default_c1(pr);
++ /* Zero initialize all the C-states info. */
++ memset(pr->power.states, 0, sizeof(pr->power.states));
++
+ result = acpi_processor_get_power_info_cst(pr);
+ if (result == -ENODEV)
+- acpi_processor_get_power_info_fadt(pr);
++ result = acpi_processor_get_power_info_fadt(pr);
++
++ if (result)
++ return result;
++
++ acpi_processor_get_power_info_default(pr);
+
+ pr->power.count = acpi_processor_power_verify(pr);
+
+@@ -1009,9 +1038,11 @@ static int acpi_processor_power_seq_show
+
+ seq_printf(seq, "active state: C%zd\n"
+ "max_cstate: C%d\n"
+- "bus master activity: %08x\n",
++ "bus master activity: %08x\n"
++ "maximum allowed latency: %d usec\n",
+ pr->power.state ? pr->power.state - pr->power.states : 0,
+- max_cstate, (unsigned)pr->power.bm_activity);
++ max_cstate, (unsigned)pr->power.bm_activity,
++ system_latency_constraint());
+
+ seq_puts(seq, "states:\n");
+
+@@ -1077,7 +1108,31 @@ static const struct file_operations acpi
+ .release = single_release,
+ };
+
+-int acpi_processor_power_init(struct acpi_processor *pr,
++#ifdef CONFIG_SMP
++static void smp_callback(void *v)
++{
++ /* we already woke the CPU up, nothing more to do */
++}
++
++/*
++ * This function gets called when a part of the kernel has a new latency
++ * requirement. This means we need to get all processors out of their C-state,
++ * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
++ * wakes them all right up.
++ */
++static int acpi_processor_latency_notify(struct notifier_block *b,
++ unsigned long l, void *v)
++{
++ smp_call_function(smp_callback, NULL, 0, 1);
++ return NOTIFY_OK;
++}
++
++static struct notifier_block acpi_processor_latency_notifier = {
++ .notifier_call = acpi_processor_latency_notify,
++};
++#endif
++
++int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
+ struct acpi_device *device)
+ {
+ acpi_status status = 0;
+@@ -1093,6 +1148,9 @@ int acpi_processor_power_init(struct acp
+ "ACPI: processor limited to max C-state %d\n",
+ max_cstate);
+ first_run++;
++#ifdef CONFIG_SMP
++ register_latency_notifier(&acpi_processor_latency_notifier);
++#endif
+ }
+
+ if (!pr)
+@@ -1164,6 +1222,9 @@ int acpi_processor_power_exit(struct acp
+ * copies of pm_idle before proceeding.
+ */
+ cpu_idle_wait();
++#ifdef CONFIG_SMP
++ unregister_latency_notifier(&acpi_processor_latency_notifier);
++#endif
+ }
+
+ return 0;
+diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
+index 62bef0b..8908a97 100644
+--- a/drivers/acpi/sbs.c
++++ b/drivers/acpi/sbs.c
+@@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INF
+ static int update_time = UPDATE_TIME;
+ static int update_time2 = UPDATE_TIME2;
+
+-module_param(capacity_mode, int, CAPACITY_UNIT);
+-module_param(update_mode, int, UPDATE_MODE);
+-module_param(update_info_mode, int, UPDATE_INFO_MODE);
+-module_param(update_time, int, UPDATE_TIME);
+-module_param(update_time2, int, UPDATE_TIME2);
++module_param(capacity_mode, int, 0);
++module_param(update_mode, int, 0);
++module_param(update_info_mode, int, 0);
++module_param(update_time, int, 0);
++module_param(update_time2, int, 0);
+
+ static int acpi_sbs_add(struct acpi_device *device);
+ static int acpi_sbs_remove(struct acpi_device *device, int type);
+@@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_devi
+
+ int acpi_sbs_remove(struct acpi_device *device, int type)
+ {
+- struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
++ struct acpi_sbs *sbs = NULL;
+ int id;
+
+- if (!device || !sbs) {
++ if (!device) {
++ return -EINVAL;
++ }
++
++ sbs = (struct acpi_sbs *)acpi_driver_data(device);
++
++ if (!sbs) {
+ return -EINVAL;
+ }
+
+diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
+index 7856db7..11e2d44 100644
+--- a/drivers/acpi/tables/tbget.c
++++ b/drivers/acpi/tables/tbget.c
+@@ -324,7 +324,7 @@ acpi_tb_get_this_table(struct acpi_point
+
+ if (header->length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO,
+- "Table length (%X) is smaller than minimum (%X)",
++ "Table length (%X) is smaller than minimum (%zX)",
+ header->length, sizeof(struct acpi_table_header)));
+
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
+index 0ad3dbb..86a5fca 100644
+--- a/drivers/acpi/tables/tbrsdt.c
++++ b/drivers/acpi/tables/tbrsdt.c
+@@ -187,7 +187,7 @@ acpi_status acpi_tb_validate_rsdt(struct
+
+ if (table_ptr->length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO,
+- "RSDT/XSDT length (%X) is smaller than minimum (%X)",
++ "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
+ table_ptr->length,
+ sizeof(struct acpi_table_header)));
+
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+new file mode 100644
+index 0000000..03f6338
+--- /dev/null
++++ b/drivers/ata/Kconfig
+@@ -0,0 +1,488 @@
++#
++# SATA/PATA driver configuration
++#
++
++menu "Serial ATA (prod) and Parallel ATA (experimental) drivers"
++
++config ATA
++ tristate "ATA device support"
++ depends on BLOCK
++ depends on !(M32R || M68K) || BROKEN
++ depends on !SUN4 || BROKEN
++ select SCSI
++ ---help---
++ If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
++ any other ATA device under Linux, say Y and make sure that you know
++ the name of your ATA host adapter (the card inside your computer
++ that "speaks" the ATA protocol, also called ATA controller),
++ because you will be asked for it.
++
++if ATA
++
++config SATA_AHCI
++ tristate "AHCI SATA support"
++ depends on PCI
++ help
++ This option enables support for AHCI Serial ATA.
++
++ If unsure, say N.
++
++config SATA_SVW
++ tristate "ServerWorks Frodo / Apple K2 SATA support"
++ depends on PCI
++ help
++ This option enables support for Broadcom/Serverworks/Apple K2
++ SATA support.
++
++ If unsure, say N.
++
++config ATA_PIIX
++ tristate "Intel PIIX/ICH SATA support"
++ depends on PCI
++ help
++ This option enables support for ICH5/6/7/8 Serial ATA.
++ If PATA support was enabled previously, this enables
++ support for select Intel PIIX/ICH PATA host controllers.
++
++ If unsure, say N.
++
++config SATA_MV
++ tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the Marvell Serial ATA family.
++ Currently supports 88SX[56]0[48][01] chips.
++
++ If unsure, say N.
++
++config SATA_NV
++ tristate "NVIDIA SATA support"
++ depends on PCI
++ help
++ This option enables support for NVIDIA Serial ATA.
++
++ If unsure, say N.
++
++config PDC_ADMA
++ tristate "Pacific Digital ADMA support"
++ depends on PCI
++ help
++ This option enables support for Pacific Digital ADMA controllers
++
++ If unsure, say N.
++
++config SATA_QSTOR
++ tristate "Pacific Digital SATA QStor support"
++ depends on PCI
++ help
++ This option enables support for Pacific Digital Serial ATA QStor.
++
++ If unsure, say N.
++
++config SATA_PROMISE
++ tristate "Promise SATA TX2/TX4 support"
++ depends on PCI
++ help
++ This option enables support for Promise Serial ATA TX2/TX4.
++
++ If unsure, say N.
++
++config SATA_SX4
++ tristate "Promise SATA SX4 support"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for Promise Serial ATA SX4.
++
++ If unsure, say N.
++
++config SATA_SIL
++ tristate "Silicon Image SATA support"
++ depends on PCI
++ help
++ This option enables support for Silicon Image Serial ATA.
++
++ If unsure, say N.
++
++config SATA_SIL24
++ tristate "Silicon Image 3124/3132 SATA support"
++ depends on PCI
++ help
++ This option enables support for Silicon Image 3124/3132 Serial ATA.
++
++ If unsure, say N.
++
++config SATA_SIS
++ tristate "SiS 964/180 SATA support"
++ depends on PCI
++ help
++ This option enables support for SiS Serial ATA 964/180.
++
++ If unsure, say N.
++
++config SATA_ULI
++ tristate "ULi Electronics SATA support"
++ depends on PCI
++ help
++ This option enables support for ULi Electronics SATA.
++
++ If unsure, say N.
++
++config SATA_VIA
++ tristate "VIA SATA support"
++ depends on PCI
++ help
++ This option enables support for VIA Serial ATA.
++
++ If unsure, say N.
++
++config SATA_VITESSE
++ tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
++ depends on PCI
++ help
++ This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
++
++ If unsure, say N.
++
++config SATA_INTEL_COMBINED
++ bool
++ depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
++ default y
++
++config PATA_ALI
++ tristate "ALi PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the ALi ATA interfaces
++ found on the many ALi chipsets.
++
++ If unsure, say N.
++
++config PATA_AMD
++ tristate "AMD/NVidia PATA support (Experimental)"
++ depends on PCI
++ help
++ This option enables support for the AMD and NVidia PATA
++ interfaces found on the chipsets for Athlon/Athlon64.
++
++ If unsure, say N.
++
++config PATA_ARTOP
++ tristate "ARTOP 6210/6260 PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for ARTOP PATA controllers.
++
++ If unsure, say N.
++
++config PATA_ATIIXP
++ tristate "ATI PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the ATI ATA interfaces
++ found on the many ATI chipsets.
++
++ If unsure, say N.
++
++config PATA_CMD64X
++ tristate "CMD64x PATA support (Very Experimental)"
++ depends on PCI&& EXPERIMENTAL
++ help
++ This option enables support for the CMD64x series chips
++ except for the CMD640.
++
++ If unsure, say N.
++
++config PATA_CS5520
++ tristate "CS5510/5520 PATA support"
++ depends on PCI
++ help
++ This option enables support for the Cyrix 5510/5520
++ companion chip used with the MediaGX/Geode processor family.
++
++ If unsure, say N.
++
++config PATA_CS5530
++ tristate "CS5530 PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the Cyrix/NatSemi/AMD CS5530
++ companion chip used with the MediaGX/Geode processor family.
++
++ If unsure, say N.
++
++config PATA_CS5535
++ tristate "CS5535 PATA support (Experimental)"
++ depends on PCI && X86 && !X86_64 && EXPERIMENTAL
++ help
++ This option enables support for the NatSemi/AMD CS5535
++ companion chip used with the Geode processor family.
++
++ If unsure, say N.
++
++config PATA_CYPRESS
++ tristate "Cypress CY82C693 PATA support (Very Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the Cypress/Contaq CY82C693
++ chipset found in some Alpha systems
++
++ If unsure, say N.
++
++config PATA_EFAR
++ tristate "EFAR SLC90E66 support"
++ depends on PCI
++ help
++ This option enables support for the EFAR SLC90E66
++ IDE controller found on some older machines.
++
++ If unsure, say N.
++
++config ATA_GENERIC
++ tristate "Generic ATA support"
++ depends on PCI
++ help
++ This option enables support for generic BIOS configured
++ ATA controllers via the new ATA layer
++
++ If unsure, say N.
++
++config PATA_HPT366
++ tristate "HPT 366/368 PATA support (Very Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the HPT 366 and 368
++ PATA controllers via the new ATA layer.
++
++ If unsure, say N.
++
++config PATA_HPT37X
++ tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the majority of the later HPT
++ PATA controllers via the new ATA layer.
++
++ If unsure, say N.
++
++config PATA_HPT3X2N
++ tristate "HPT 372N/302N PATA support (Very Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the N variant HPT PATA
++ controllers via the new ATA layer
++
++ If unsure, say N.
++
++config PATA_HPT3X3
++ tristate "HPT 343/363 PATA support (Experimental)"
++ depends on PCI
++ help
++ This option enables support for the HPT 343/363
++ PATA controllers via the new ATA layer
++
++ If unsure, say N.
++
++config PATA_ISAPNP
++ tristate "ISA Plug and Play PATA support (Very Experimental)"
++ depends on EXPERIMENTAL && ISAPNP
++ help
++ This option enables support for ISA plug & play ATA
++ controllers such as those found on old soundcards.
++
++ If unsure, say N.
++
++config PATA_IT821X
++ tristate "IT821x PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the ITE 8211 and 8212
++ PATA controllers via the new ATA layer, including RAID
++ mode.
++
++ If unsure, say N.
++
++config PATA_JMICRON
++ tristate "JMicron PATA support"
++ depends on PCI
++ help
++ Enable support for the JMicron IDE controller, via the new
++ ATA layer.
++
++ If unsure, say N.
++
++config PATA_LEGACY
++ tristate "Legacy ISA PATA support (Experimental)"
++ depends on ISA && EXPERIMENTAL
++ help
++ This option enables support for ISA/VLB bus legacy PATA
++ ports and allows them to be accessed via the new ATA layer.
++
++ If unsure, say N.
++
++config PATA_TRIFLEX
++ tristate "Compaq Triflex PATA support"
++ depends on PCI
++ help
++ Enable support for the Compaq 'Triflex' IDE controller as found
++ on many Compaq Pentium-Pro systems, via the new ATA layer.
++
++ If unsure, say N.
++
++config PATA_MPIIX
++ tristate "Intel PATA MPIIX support"
++ depends on PCI
++ help
++ This option enables support for MPIIX PATA support.
++
++ If unsure, say N.
++
++config PATA_OLDPIIX
++ tristate "Intel PATA old PIIX support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for old(?) PIIX PATA support.
++
++ If unsure, say N.
++
++config PATA_NETCELL
++ tristate "NETCELL Revolution RAID support"
++ depends on PCI
++ help
++ This option enables support for the Netcell Revolution RAID
++ PATA controller.
++
++ If unsure, say N.
++
++config PATA_NS87410
++ tristate "Nat Semi NS87410 PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the National Semiconductor
++ NS87410 PCI-IDE controller.
++
++ If unsure, say N.
++
++config PATA_OPTI
++ tristate "OPTI621/6215 PATA support (Very Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables full PIO support for the early Opti ATA
++ controllers found on some old motherboards.
++
++ If unsure, say N.
++
++config PATA_OPTIDMA
++ tristate "OPTI FireStar PATA support (Veyr Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables DMA/PIO support for the later OPTi
++ controllers found on some old motherboards and in some
++ latops
++
++ If unsure, say N.
++
++config PATA_PCMCIA
++ tristate "PCMCIA PATA support"
++ depends on PCMCIA
++ help
++ This option enables support for PCMCIA ATA interfaces, including
++ compact flash card adapters via the new ATA layer.
++
++ If unsure, say N.
++
++config PATA_PDC_OLD
++ tristate "Older Promise PATA controller support (Very Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the Promise 20246, 20262, 20263,
++ 20265 and 20267 adapters.
++
++ If unsure, say N.
++
++config PATA_QDI
++ tristate "QDI VLB PATA support"
++ depends on ISA
++ help
++ Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
++
++config PATA_RADISYS
++ tristate "RADISYS 82600 PATA support (Very experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the RADISYS 82600
++ PATA controllers via the new ATA layer
++
++ If unsure, say N.
++
++config PATA_RZ1000
++ tristate "PC Tech RZ1000 PATA support"
++ depends on PCI
++ help
++ This option enables basic support for the PC Tech RZ1000/1
++ PATA controllers via the new ATA layer
++
++ If unsure, say N.
++
++config PATA_SC1200
++ tristate "SC1200 PATA support (Raving Lunatic)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the NatSemi/AMD SC1200 SoC
++ companion chip used with the Geode processor family.
++
++ If unsure, say N.
++
++config PATA_SERVERWORKS
++ tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for the Serverworks OSB4/CSB5/CSB6 and
++ HT1000 PATA controllers, via the new ATA layer.
++
++ If unsure, say N.
++
++config PATA_PDC2027X
++ tristate "Promise PATA 2027x support"
++ depends on PCI
++ help
++ This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
++
++ If unsure, say N.
++
++config PATA_SIL680
++ tristate "CMD / Silicon Image 680 PATA support"
++ depends on PCI
++ help
++ This option enables support for CMD / Silicon Image 680 PATA.
++
++ If unsure, say N.
++
++config PATA_SIS
++ tristate "SiS PATA support (Experimental)"
++ depends on PCI && EXPERIMENTAL
++ help
++ This option enables support for SiS PATA controllers
++
++ If unsure, say N.
++
++config PATA_VIA
++ tristate "VIA PATA support"
++ depends on PCI
++ help
++ This option enables support for the VIA PATA interfaces
++ found on the many VIA chipsets.
++
++ If unsure, say N.
++
++config PATA_WINBOND
++ tristate "Winbond SL82C105 PATA support"
++ depends on PCI
++ help
++ This option enables support for SL82C105 PATA devices found in the
++ Netwinder and some other systems
++
++ If unsure, say N.
++
++endif
++endmenu
++
+diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
+new file mode 100644
+index 0000000..72243a6
+--- /dev/null
++++ b/drivers/ata/Makefile
+@@ -0,0 +1,62 @@
++
++obj-$(CONFIG_ATA) += libata.o
++
++obj-$(CONFIG_SATA_AHCI) += ahci.o
++obj-$(CONFIG_SATA_SVW) += sata_svw.o
++obj-$(CONFIG_ATA_PIIX) += ata_piix.o
++obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
++obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
++obj-$(CONFIG_SATA_SIL) += sata_sil.o
++obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
++obj-$(CONFIG_SATA_VIA) += sata_via.o
++obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
++obj-$(CONFIG_SATA_SIS) += sata_sis.o
++obj-$(CONFIG_SATA_SX4) += sata_sx4.o
++obj-$(CONFIG_SATA_NV) += sata_nv.o
++obj-$(CONFIG_SATA_ULI) += sata_uli.o
++obj-$(CONFIG_SATA_MV) += sata_mv.o
++obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
++
++obj-$(CONFIG_PATA_ALI) += pata_ali.o
++obj-$(CONFIG_PATA_AMD) += pata_amd.o
++obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
++obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
++obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
++obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
++obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
++obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
++obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
++obj-$(CONFIG_PATA_EFAR) += pata_efar.o
++obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
++obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
++obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
++obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
++obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
++obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
++obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
++obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
++obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
++obj-$(CONFIG_PATA_OPTI) += pata_opti.o
++obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
++obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
++obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
++obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
++obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
++obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
++obj-$(CONFIG_PATA_QDI) += pata_qdi.o
++obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
++obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
++obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
++obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
++obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
++obj-$(CONFIG_PATA_VIA) += pata_via.o
++obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
++obj-$(CONFIG_PATA_SIS) += pata_sis.o
++obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
++# Should be last but one libata driver
++obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
++# Should be last libata driver
++obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
++
++libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
++
+diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
+new file mode 100644
+index 0000000..234197e
+--- /dev/null
++++ b/drivers/ata/ahci.c
+@@ -0,0 +1,1661 @@
++/*
++ * ahci.c - AHCI SATA support
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2004-2005 Red Hat, Inc.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * AHCI hardware documentation:
++ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
++ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/dma-mapping.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++
++#define DRV_NAME "ahci"
++#define DRV_VERSION "2.0"
++
++
++enum {
++ AHCI_PCI_BAR = 5,
++ AHCI_MAX_SG = 168, /* hardware max is 64K */
++ AHCI_DMA_BOUNDARY = 0xffffffff,
++ AHCI_USE_CLUSTERING = 0,
++ AHCI_MAX_CMDS = 32,
++ AHCI_CMD_SZ = 32,
++ AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
++ AHCI_RX_FIS_SZ = 256,
++ AHCI_CMD_TBL_CDB = 0x40,
++ AHCI_CMD_TBL_HDR_SZ = 0x80,
++ AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
++ AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
++ AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
++ AHCI_RX_FIS_SZ,
++ AHCI_IRQ_ON_SG = (1 << 31),
++ AHCI_CMD_ATAPI = (1 << 5),
++ AHCI_CMD_WRITE = (1 << 6),
++ AHCI_CMD_PREFETCH = (1 << 7),
++ AHCI_CMD_RESET = (1 << 8),
++ AHCI_CMD_CLR_BUSY = (1 << 10),
++
++ RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
++ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
++
++ board_ahci = 0,
++ board_ahci_vt8251 = 1,
++
++ /* global controller registers */
++ HOST_CAP = 0x00, /* host capabilities */
++ HOST_CTL = 0x04, /* global host control */
++ HOST_IRQ_STAT = 0x08, /* interrupt status */
++ HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
++ HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
++
++ /* HOST_CTL bits */
++ HOST_RESET = (1 << 0), /* reset controller; self-clear */
++ HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
++ HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
++
++ /* HOST_CAP bits */
++ HOST_CAP_SSC = (1 << 14), /* Slumber capable */
++ HOST_CAP_CLO = (1 << 24), /* Command List Override support */
++ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
++ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
++ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
++
++ /* registers for each SATA port */
++ PORT_LST_ADDR = 0x00, /* command list DMA addr */
++ PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
++ PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
++ PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
++ PORT_IRQ_STAT = 0x10, /* interrupt status */
++ PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
++ PORT_CMD = 0x18, /* port command */
++ PORT_TFDATA = 0x20, /* taskfile data */
++ PORT_SIG = 0x24, /* device TF signature */
++ PORT_CMD_ISSUE = 0x38, /* command issue */
++ PORT_SCR = 0x28, /* SATA phy register block */
++ PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
++ PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
++ PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
++ PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
++
++ /* PORT_IRQ_{STAT,MASK} bits */
++ PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
++ PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
++ PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
++ PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
++ PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
++ PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
++ PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
++ PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
++
++ PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
++ PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
++ PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
++ PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
++ PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
++ PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
++ PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
++ PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
++ PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
++
++ PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
++ PORT_IRQ_IF_ERR |
++ PORT_IRQ_CONNECT |
++ PORT_IRQ_PHYRDY |
++ PORT_IRQ_UNK_FIS,
++ PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
++ PORT_IRQ_TF_ERR |
++ PORT_IRQ_HBUS_DATA_ERR,
++ DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
++ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
++ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
++
++ /* PORT_CMD bits */
++ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
++ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
++ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
++ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
++ PORT_CMD_CLO = (1 << 3), /* Command list override */
++ PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
++ PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
++ PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
++
++ PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
++ PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
++ PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
++ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
++
++ /* hpriv->flags bits */
++ AHCI_FLAG_MSI = (1 << 0),
++
++ /* ap->flags bits */
++ AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
++ AHCI_FLAG_NO_NCQ = (1 << 25),
++};
++
++struct ahci_cmd_hdr {
++ u32 opts;
++ u32 status;
++ u32 tbl_addr;
++ u32 tbl_addr_hi;
++ u32 reserved[4];
++};
++
++struct ahci_sg {
++ u32 addr;
++ u32 addr_hi;
++ u32 reserved;
++ u32 flags_size;
++};
++
++struct ahci_host_priv {
++ unsigned long flags;
++ u32 cap; /* cache of HOST_CAP register */
++ u32 port_map; /* cache of HOST_PORTS_IMPL reg */
++};
++
++struct ahci_port_priv {
++ struct ahci_cmd_hdr *cmd_slot;
++ dma_addr_t cmd_slot_dma;
++ void *cmd_tbl;
++ dma_addr_t cmd_tbl_dma;
++ void *rx_fis;
++ dma_addr_t rx_fis_dma;
++};
++
++static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
++static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
++static void ahci_irq_clear(struct ata_port *ap);
++static int ahci_port_start(struct ata_port *ap);
++static void ahci_port_stop(struct ata_port *ap);
++static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
++static void ahci_qc_prep(struct ata_queued_cmd *qc);
++static u8 ahci_check_status(struct ata_port *ap);
++static void ahci_freeze(struct ata_port *ap);
++static void ahci_thaw(struct ata_port *ap);
++static void ahci_error_handler(struct ata_port *ap);
++static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
++static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
++static int ahci_port_resume(struct ata_port *ap);
++static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
++static int ahci_pci_device_resume(struct pci_dev *pdev);
++static void ahci_remove_one (struct pci_dev *pdev);
++
++static struct scsi_host_template ahci_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .change_queue_depth = ata_scsi_change_queue_depth,
++ .can_queue = AHCI_MAX_CMDS - 1,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = AHCI_MAX_SG,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = AHCI_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = AHCI_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++ .suspend = ata_scsi_device_suspend,
++ .resume = ata_scsi_device_resume,
++};
++
++static const struct ata_port_operations ahci_ops = {
++ .port_disable = ata_port_disable,
++
++ .check_status = ahci_check_status,
++ .check_altstatus = ahci_check_status,
++ .dev_select = ata_noop_dev_select,
++
++ .tf_read = ahci_tf_read,
++
++ .qc_prep = ahci_qc_prep,
++ .qc_issue = ahci_qc_issue,
++
++ .irq_handler = ahci_interrupt,
++ .irq_clear = ahci_irq_clear,
++
++ .scr_read = ahci_scr_read,
++ .scr_write = ahci_scr_write,
++
++ .freeze = ahci_freeze,
++ .thaw = ahci_thaw,
++
++ .error_handler = ahci_error_handler,
++ .post_internal_cmd = ahci_post_internal_cmd,
++
++ .port_suspend = ahci_port_suspend,
++ .port_resume = ahci_port_resume,
++
++ .port_start = ahci_port_start,
++ .port_stop = ahci_port_stop,
++};
++
++static const struct ata_port_info ahci_port_info[] = {
++ /* board_ahci */
++ {
++ .sht = &ahci_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
++ ATA_FLAG_SKIP_D2H_BSY,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &ahci_ops,
++ },
++ /* board_ahci_vt8251 */
++ {
++ .sht = &ahci_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
++ ATA_FLAG_SKIP_D2H_BSY |
++ AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &ahci_ops,
++ },
++};
++
++static const struct pci_device_id ahci_pci_tbl[] = {
++ /* Intel */
++ { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
++ { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
++ { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
++ { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
++ { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
++ { PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */
++ { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
++ { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
++ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
++ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
++ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
++ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
++ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
++ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
++ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
++
++ /* JMicron */
++ { PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */
++ { PCI_VDEVICE(JMICRON, 0x2361), board_ahci }, /* JMicron JMB361 */
++ { PCI_VDEVICE(JMICRON, 0x2363), board_ahci }, /* JMicron JMB363 */
++ { PCI_VDEVICE(JMICRON, 0x2365), board_ahci }, /* JMicron JMB365 */
++ { PCI_VDEVICE(JMICRON, 0x2366), board_ahci }, /* JMicron JMB366 */
++
++ /* ATI */
++ { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
++ { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
++
++ /* VIA */
++ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
++
++ /* NVIDIA */
++ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */
++
++ /* SiS */
++ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
++ { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
++ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
++
++ { } /* terminate list */
++};
++
++
++static struct pci_driver ahci_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = ahci_pci_tbl,
++ .probe = ahci_init_one,
++ .suspend = ahci_pci_device_suspend,
++ .resume = ahci_pci_device_resume,
++ .remove = ahci_remove_one,
++};
++
++
++static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
++{
++ return base + 0x100 + (port * 0x80);
++}
++
++static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
++{
++ return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
++}
++
++static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
++{
++ unsigned int sc_reg;
++
++ switch (sc_reg_in) {
++ case SCR_STATUS: sc_reg = 0; break;
++ case SCR_CONTROL: sc_reg = 1; break;
++ case SCR_ERROR: sc_reg = 2; break;
++ case SCR_ACTIVE: sc_reg = 3; break;
++ default:
++ return 0xffffffffU;
++ }
++
++ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++
++static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
++ u32 val)
++{
++ unsigned int sc_reg;
++
++ switch (sc_reg_in) {
++ case SCR_STATUS: sc_reg = 0; break;
++ case SCR_CONTROL: sc_reg = 1; break;
++ case SCR_ERROR: sc_reg = 2; break;
++ case SCR_ACTIVE: sc_reg = 3; break;
++ default:
++ return;
++ }
++
++ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++static void ahci_start_engine(void __iomem *port_mmio)
++{
++ u32 tmp;
++
++ /* start DMA */
++ tmp = readl(port_mmio + PORT_CMD);
++ tmp |= PORT_CMD_START;
++ writel(tmp, port_mmio + PORT_CMD);
++ readl(port_mmio + PORT_CMD); /* flush */
++}
++
++static int ahci_stop_engine(void __iomem *port_mmio)
++{
++ u32 tmp;
++
++ tmp = readl(port_mmio + PORT_CMD);
++
++ /* check if the HBA is idle */
++ if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
++ return 0;
++
++ /* setting HBA to idle */
++ tmp &= ~PORT_CMD_START;
++ writel(tmp, port_mmio + PORT_CMD);
++
++ /* wait for engine to stop. This could be as long as 500 msec */
++ tmp = ata_wait_register(port_mmio + PORT_CMD,
++ PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
++ if (tmp & PORT_CMD_LIST_ON)
++ return -EIO;
++
++ return 0;
++}
++
++static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
++ dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
++{
++ u32 tmp;
++
++ /* set FIS registers */
++ if (cap & HOST_CAP_64)
++ writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
++ writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
++
++ if (cap & HOST_CAP_64)
++ writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
++ writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
++
++ /* enable FIS reception */
++ tmp = readl(port_mmio + PORT_CMD);
++ tmp |= PORT_CMD_FIS_RX;
++ writel(tmp, port_mmio + PORT_CMD);
++
++ /* flush */
++ readl(port_mmio + PORT_CMD);
++}
++
++static int ahci_stop_fis_rx(void __iomem *port_mmio)
++{
++ u32 tmp;
++
++ /* disable FIS reception */
++ tmp = readl(port_mmio + PORT_CMD);
++ tmp &= ~PORT_CMD_FIS_RX;
++ writel(tmp, port_mmio + PORT_CMD);
++
++ /* wait for completion, spec says 500ms, give it 1000 */
++ tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
++ PORT_CMD_FIS_ON, 10, 1000);
++ if (tmp & PORT_CMD_FIS_ON)
++ return -EBUSY;
++
++ return 0;
++}
++
++static void ahci_power_up(void __iomem *port_mmio, u32 cap)
++{
++ u32 cmd;
++
++ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
++
++ /* spin up device */
++ if (cap & HOST_CAP_SSS) {
++ cmd |= PORT_CMD_SPIN_UP;
++ writel(cmd, port_mmio + PORT_CMD);
++ }
++
++ /* wake up link */
++ writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
++}
++
++static void ahci_power_down(void __iomem *port_mmio, u32 cap)
++{
++ u32 cmd, scontrol;
++
++ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
++
++ if (cap & HOST_CAP_SSC) {
++ /* enable transitions to slumber mode */
++ scontrol = readl(port_mmio + PORT_SCR_CTL);
++ if ((scontrol & 0x0f00) > 0x100) {
++ scontrol &= ~0xf00;
++ writel(scontrol, port_mmio + PORT_SCR_CTL);
++ }
++
++ /* put device into slumber mode */
++ writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
++
++ /* wait for the transition to complete */
++ ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
++ PORT_CMD_ICC_SLUMBER, 1, 50);
++ }
++
++ /* put device into listen mode */
++ if (cap & HOST_CAP_SSS) {
++ /* first set PxSCTL.DET to 0 */
++ scontrol = readl(port_mmio + PORT_SCR_CTL);
++ scontrol &= ~0xf;
++ writel(scontrol, port_mmio + PORT_SCR_CTL);
++
++ /* then set PxCMD.SUD to 0 */
++ cmd &= ~PORT_CMD_SPIN_UP;
++ writel(cmd, port_mmio + PORT_CMD);
++ }
++}
++
++static void ahci_init_port(void __iomem *port_mmio, u32 cap,
++ dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
++{
++ /* power up */
++ ahci_power_up(port_mmio, cap);
++
++ /* enable FIS reception */
++ ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
++
++ /* enable DMA */
++ ahci_start_engine(port_mmio);
++}
++
++static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
++{
++ int rc;
++
++ /* disable DMA */
++ rc = ahci_stop_engine(port_mmio);
++ if (rc) {
++ *emsg = "failed to stop engine";
++ return rc;
++ }
++
++ /* disable FIS reception */
++ rc = ahci_stop_fis_rx(port_mmio);
++ if (rc) {
++ *emsg = "failed stop FIS RX";
++ return rc;
++ }
++
++ /* put device into slumber mode */
++ ahci_power_down(port_mmio, cap);
++
++ return 0;
++}
++
++static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
++{
++ u32 cap_save, tmp;
++
++ cap_save = readl(mmio + HOST_CAP);
++ cap_save &= ( (1<<28) | (1<<17) );
++ cap_save |= (1 << 27);
++
++ /* global controller reset */
++ tmp = readl(mmio + HOST_CTL);
++ if ((tmp & HOST_RESET) == 0) {
++ writel(tmp | HOST_RESET, mmio + HOST_CTL);
++ readl(mmio + HOST_CTL); /* flush */
++ }
++
++ /* reset must complete within 1 second, or
++ * the hardware should be considered fried.
++ */
++ ssleep(1);
++
++ tmp = readl(mmio + HOST_CTL);
++ if (tmp & HOST_RESET) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "controller reset failed (0x%x)\n", tmp);
++ return -EIO;
++ }
++
++ writel(HOST_AHCI_EN, mmio + HOST_CTL);
++ (void) readl(mmio + HOST_CTL); /* flush */
++ writel(cap_save, mmio + HOST_CAP);
++ writel(0xf, mmio + HOST_PORTS_IMPL);
++ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
++
++ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
++ u16 tmp16;
++
++ /* configure PCS */
++ pci_read_config_word(pdev, 0x92, &tmp16);
++ tmp16 |= 0xf;
++ pci_write_config_word(pdev, 0x92, tmp16);
++ }
++
++ return 0;
++}
++
++static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
++ int n_ports, u32 cap)
++{
++ int i, rc;
++ u32 tmp;
++
++ for (i = 0; i < n_ports; i++) {
++ void __iomem *port_mmio = ahci_port_base(mmio, i);
++ const char *emsg = NULL;
++
++#if 0 /* BIOSen initialize this incorrectly */
++ if (!(hpriv->port_map & (1 << i)))
++ continue;
++#endif
++
++ /* make sure port is not active */
++ rc = ahci_deinit_port(port_mmio, cap, &emsg);
++ if (rc)
++ dev_printk(KERN_WARNING, &pdev->dev,
++ "%s (%d)\n", emsg, rc);
++
++ /* clear SError */
++ tmp = readl(port_mmio + PORT_SCR_ERR);
++ VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
++ writel(tmp, port_mmio + PORT_SCR_ERR);
++
++ /* clear port IRQ */
++ tmp = readl(port_mmio + PORT_IRQ_STAT);
++ VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
++ if (tmp)
++ writel(tmp, port_mmio + PORT_IRQ_STAT);
++
++ writel(1 << i, mmio + HOST_IRQ_STAT);
++ }
++
++ tmp = readl(mmio + HOST_CTL);
++ VPRINTK("HOST_CTL 0x%x\n", tmp);
++ writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
++ tmp = readl(mmio + HOST_CTL);
++ VPRINTK("HOST_CTL 0x%x\n", tmp);
++}
++
++static unsigned int ahci_dev_classify(struct ata_port *ap)
++{
++ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
++ struct ata_taskfile tf;
++ u32 tmp;
++
++ tmp = readl(port_mmio + PORT_SIG);
++ tf.lbah = (tmp >> 24) & 0xff;
++ tf.lbam = (tmp >> 16) & 0xff;
++ tf.lbal = (tmp >> 8) & 0xff;
++ tf.nsect = (tmp) & 0xff;
++
++ return ata_dev_classify(&tf);
++}
++
++static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
++ u32 opts)
++{
++ dma_addr_t cmd_tbl_dma;
++
++ cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
++
++ pp->cmd_slot[tag].opts = cpu_to_le32(opts);
++ pp->cmd_slot[tag].status = 0;
++ pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
++ pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
++}
++
++static int ahci_clo(struct ata_port *ap)
++{
++ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++ u32 tmp;
++
++ if (!(hpriv->cap & HOST_CAP_CLO))
++ return -EOPNOTSUPP;
++
++ tmp = readl(port_mmio + PORT_CMD);
++ tmp |= PORT_CMD_CLO;
++ writel(tmp, port_mmio + PORT_CMD);
++
++ tmp = ata_wait_register(port_mmio + PORT_CMD,
++ PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
++ if (tmp & PORT_CMD_CLO)
++ return -EIO;
++
++ return 0;
++}
++
++static int ahci_prereset(struct ata_port *ap)
++{
++ if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
++ (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
++ /* ATA_BUSY hasn't cleared, so send a CLO */
++ ahci_clo(ap);
++ }
++
++ return ata_std_prereset(ap);
++}
++
++static int ahci_softreset(struct ata_port *ap, unsigned int *class)
++{
++ struct ahci_port_priv *pp = ap->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ const u32 cmd_fis_len = 5; /* five dwords */
++ const char *reason = NULL;
++ struct ata_taskfile tf;
++ u32 tmp;
++ u8 *fis;
++ int rc;
++
++ DPRINTK("ENTER\n");
++
++ if (ata_port_offline(ap)) {
++ DPRINTK("PHY reports no device\n");
++ *class = ATA_DEV_NONE;
++ return 0;
++ }
++
++ /* prepare for SRST (AHCI-1.1 10.4.1) */
++ rc = ahci_stop_engine(port_mmio);
++ if (rc) {
++ reason = "failed to stop engine";
++ goto fail_restart;
++ }
++
++ /* check BUSY/DRQ, perform Command List Override if necessary */
++ if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
++ rc = ahci_clo(ap);
++
++ if (rc == -EOPNOTSUPP) {
++ reason = "port busy but CLO unavailable";
++ goto fail_restart;
++ } else if (rc) {
++ reason = "port busy but CLO failed";
++ goto fail_restart;
++ }
++ }
++
++ /* restart engine */
++ ahci_start_engine(port_mmio);
++
++ ata_tf_init(ap->device, &tf);
++ fis = pp->cmd_tbl;
++
++ /* issue the first D2H Register FIS */
++ ahci_fill_cmd_slot(pp, 0,
++ cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
++
++ tf.ctl |= ATA_SRST;
++ ata_tf_to_fis(&tf, fis, 0);
++ fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
++
++ writel(1, port_mmio + PORT_CMD_ISSUE);
++
++ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
++ if (tmp & 0x1) {
++ rc = -EIO;
++ reason = "1st FIS failed";
++ goto fail;
++ }
++
++ /* spec says at least 5us, but be generous and sleep for 1ms */
++ msleep(1);
++
++ /* issue the second D2H Register FIS */
++ ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
++
++ tf.ctl &= ~ATA_SRST;
++ ata_tf_to_fis(&tf, fis, 0);
++ fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
++
++ writel(1, port_mmio + PORT_CMD_ISSUE);
++ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
++
++ /* spec mandates ">= 2ms" before checking status.
++ * We wait 150ms, because that was the magic delay used for
++ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
++ * between when the ATA command register is written, and then
++ * status is checked. Because waiting for "a while" before
++ * checking status is fine, post SRST, we perform this magic
++ * delay here as well.
++ */
++ msleep(150);
++
++ *class = ATA_DEV_NONE;
++ if (ata_port_online(ap)) {
++ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
++ rc = -EIO;
++ reason = "device not ready";
++ goto fail;
++ }
++ *class = ahci_dev_classify(ap);
++ }
++
++ DPRINTK("EXIT, class=%u\n", *class);
++ return 0;
++
++ fail_restart:
++ ahci_start_engine(port_mmio);
++ fail:
++ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
++ return rc;
++}
++
++static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
++{
++ struct ahci_port_priv *pp = ap->private_data;
++ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
++ struct ata_taskfile tf;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ int rc;
++
++ DPRINTK("ENTER\n");
++
++ ahci_stop_engine(port_mmio);
++
++ /* clear D2H reception area to properly wait for D2H FIS */
++ ata_tf_init(ap->device, &tf);
++ tf.command = 0xff;
++ ata_tf_to_fis(&tf, d2h_fis, 0);
++
++ rc = sata_std_hardreset(ap, class);
++
++ ahci_start_engine(port_mmio);
++
++ if (rc == 0 && ata_port_online(ap))
++ *class = ahci_dev_classify(ap);
++ if (*class == ATA_DEV_UNKNOWN)
++ *class = ATA_DEV_NONE;
++
++ DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
++ return rc;
++}
++
++static void ahci_postreset(struct ata_port *ap, unsigned int *class)
++{
++ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
++ u32 new_tmp, tmp;
++
++ ata_std_postreset(ap, class);
++
++ /* Make sure port's ATAPI bit is set appropriately */
++ new_tmp = tmp = readl(port_mmio + PORT_CMD);
++ if (*class == ATA_DEV_ATAPI)
++ new_tmp |= PORT_CMD_ATAPI;
++ else
++ new_tmp &= ~PORT_CMD_ATAPI;
++ if (new_tmp != tmp) {
++ writel(new_tmp, port_mmio + PORT_CMD);
++ readl(port_mmio + PORT_CMD); /* flush */
++ }
++}
++
++static u8 ahci_check_status(struct ata_port *ap)
++{
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
++
++ return readl(mmio + PORT_TFDATA) & 0xFF;
++}
++
++static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct ahci_port_priv *pp = ap->private_data;
++ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
++
++ ata_tf_from_fis(d2h_fis, tf);
++}
++
++static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
++{
++ struct scatterlist *sg;
++ struct ahci_sg *ahci_sg;
++ unsigned int n_sg = 0;
++
++ VPRINTK("ENTER\n");
++
++ /*
++ * Next, the S/G list.
++ */
++ ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
++ ata_for_each_sg(sg, qc) {
++ dma_addr_t addr = sg_dma_address(sg);
++ u32 sg_len = sg_dma_len(sg);
++
++ ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
++ ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
++ ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
++
++ ahci_sg++;
++ n_sg++;
++ }
++
++ return n_sg;
++}
++
++static void ahci_qc_prep(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ahci_port_priv *pp = ap->private_data;
++ int is_atapi = is_atapi_taskfile(&qc->tf);
++ void *cmd_tbl;
++ u32 opts;
++ const u32 cmd_fis_len = 5; /* five dwords */
++ unsigned int n_elem;
++
++ /*
++ * Fill in command table information. First, the header,
++ * a SATA Register - Host to Device command FIS.
++ */
++ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
++
++ ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
++ if (is_atapi) {
++ memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
++ memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
++ }
++
++ n_elem = 0;
++ if (qc->flags & ATA_QCFLAG_DMAMAP)
++ n_elem = ahci_fill_sg(qc, cmd_tbl);
++
++ /*
++ * Fill in command slot information.
++ */
++ opts = cmd_fis_len | n_elem << 16;
++ if (qc->tf.flags & ATA_TFLAG_WRITE)
++ opts |= AHCI_CMD_WRITE;
++ if (is_atapi)
++ opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
++
++ ahci_fill_cmd_slot(pp, qc->tag, opts);
++}
++
++static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
++{
++ struct ahci_port_priv *pp = ap->private_data;
++ struct ata_eh_info *ehi = &ap->eh_info;
++ unsigned int err_mask = 0, action = 0;
++ struct ata_queued_cmd *qc;
++ u32 serror;
++
++ ata_ehi_clear_desc(ehi);
++
++ /* AHCI needs SError cleared; otherwise, it might lock up */
++ serror = ahci_scr_read(ap, SCR_ERROR);
++ ahci_scr_write(ap, SCR_ERROR, serror);
++
++ /* analyze @irq_stat */
++ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
++
++ if (irq_stat & PORT_IRQ_TF_ERR)
++ err_mask |= AC_ERR_DEV;
++
++ if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
++ err_mask |= AC_ERR_HOST_BUS;
++ action |= ATA_EH_SOFTRESET;
++ }
++
++ if (irq_stat & PORT_IRQ_IF_ERR) {
++ err_mask |= AC_ERR_ATA_BUS;
++ action |= ATA_EH_SOFTRESET;
++ ata_ehi_push_desc(ehi, ", interface fatal error");
++ }
++
++ if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
++ ata_ehi_hotplugged(ehi);
++ ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
++ "connection status changed" : "PHY RDY changed");
++ }
++
++ if (irq_stat & PORT_IRQ_UNK_FIS) {
++ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
++
++ err_mask |= AC_ERR_HSM;
++ action |= ATA_EH_SOFTRESET;
++ ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
++ unk[0], unk[1], unk[2], unk[3]);
++ }
++
++ /* okay, let's hand over to EH */
++ ehi->serror |= serror;
++ ehi->action |= action;
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc)
++ qc->err_mask |= err_mask;
++ else
++ ehi->err_mask |= err_mask;
++
++ if (irq_stat & PORT_IRQ_FREEZE)
++ ata_port_freeze(ap);
++ else
++ ata_port_abort(ap);
++}
++
++static void ahci_host_intr(struct ata_port *ap)
++{
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ struct ata_eh_info *ehi = &ap->eh_info;
++ u32 status, qc_active;
++ int rc;
++
++ status = readl(port_mmio + PORT_IRQ_STAT);
++ writel(status, port_mmio + PORT_IRQ_STAT);
++
++ if (unlikely(status & PORT_IRQ_ERROR)) {
++ ahci_error_intr(ap, status);
++ return;
++ }
++
++ if (ap->sactive)
++ qc_active = readl(port_mmio + PORT_SCR_ACT);
++ else
++ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
++
++ rc = ata_qc_complete_multiple(ap, qc_active, NULL);
++ if (rc > 0)
++ return;
++ if (rc < 0) {
++ ehi->err_mask |= AC_ERR_HSM;
++ ehi->action |= ATA_EH_SOFTRESET;
++ ata_port_freeze(ap);
++ return;
++ }
++
++ /* hmmm... a spurious interupt */
++
++ /* some devices send D2H reg with I bit set during NCQ command phase */
++ if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS))
++ return;
++
++ /* ignore interim PIO setup fis interrupts */
++ if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
++ return;
++
++ if (ata_ratelimit())
++ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
++ "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
++ status, ap->active_tag, ap->sactive);
++}
++
++static void ahci_irq_clear(struct ata_port *ap)
++{
++ /* TODO */
++}
++
++static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ struct ahci_host_priv *hpriv;
++ unsigned int i, handled = 0;
++ void __iomem *mmio;
++ u32 irq_stat, irq_ack = 0;
++
++ VPRINTK("ENTER\n");
++
++ hpriv = host->private_data;
++ mmio = host->mmio_base;
++
++ /* sigh. 0xffffffff is a valid return from h/w */
++ irq_stat = readl(mmio + HOST_IRQ_STAT);
++ irq_stat &= hpriv->port_map;
++ if (!irq_stat)
++ return IRQ_NONE;
++
++ spin_lock(&host->lock);
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap;
++
++ if (!(irq_stat & (1 << i)))
++ continue;
++
++ ap = host->ports[i];
++ if (ap) {
++ ahci_host_intr(ap);
++ VPRINTK("port %u\n", i);
++ } else {
++ VPRINTK("port %u (no irq)\n", i);
++ if (ata_ratelimit())
++ dev_printk(KERN_WARNING, host->dev,
++ "interrupt on disabled port %u\n", i);
++ }
++
++ irq_ack |= (1 << i);
++ }
++
++ if (irq_ack) {
++ writel(irq_ack, mmio + HOST_IRQ_STAT);
++ handled = 1;
++ }
++
++ spin_unlock(&host->lock);
++
++ VPRINTK("EXIT\n");
++
++ return IRQ_RETVAL(handled);
++}
++
++static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
++
++ if (qc->tf.protocol == ATA_PROT_NCQ)
++ writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
++ writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
++ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
++
++ return 0;
++}
++
++static void ahci_freeze(struct ata_port *ap)
++{
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++
++ /* turn IRQ off */
++ writel(0, port_mmio + PORT_IRQ_MASK);
++}
++
++static void ahci_thaw(struct ata_port *ap)
++{
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ u32 tmp;
++
++ /* clear IRQ */
++ tmp = readl(port_mmio + PORT_IRQ_STAT);
++ writel(tmp, port_mmio + PORT_IRQ_STAT);
++ writel(1 << ap->id, mmio + HOST_IRQ_STAT);
++
++ /* turn IRQ back on */
++ writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
++}
++
++static void ahci_error_handler(struct ata_port *ap)
++{
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++
++ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
++ /* restart engine */
++ ahci_stop_engine(port_mmio);
++ ahci_start_engine(port_mmio);
++ }
++
++ /* perform recovery */
++ ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
++ ahci_postreset);
++}
++
++static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++
++ if (qc->flags & ATA_QCFLAG_FAILED)
++ qc->err_mask |= AC_ERR_OTHER;
++
++ if (qc->err_mask) {
++ /* make DMA engine forget about the failed command */
++ ahci_stop_engine(port_mmio);
++ ahci_start_engine(port_mmio);
++ }
++}
++
++static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
++{
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++ struct ahci_port_priv *pp = ap->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ const char *emsg = NULL;
++ int rc;
++
++ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
++ if (rc) {
++ ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
++ ahci_init_port(port_mmio, hpriv->cap,
++ pp->cmd_slot_dma, pp->rx_fis_dma);
++ }
++
++ return rc;
++}
++
++static int ahci_port_resume(struct ata_port *ap)
++{
++ struct ahci_port_priv *pp = ap->private_data;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++
++ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
++
++ return 0;
++}
++
++static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
++{
++ struct ata_host *host = dev_get_drvdata(&pdev->dev);
++ void __iomem *mmio = host->mmio_base;
++ u32 ctl;
++
++ if (mesg.event == PM_EVENT_SUSPEND) {
++ /* AHCI spec rev1.1 section 8.3.3:
++ * Software must disable interrupts prior to requesting a
++ * transition of the HBA to D3 state.
++ */
++ ctl = readl(mmio + HOST_CTL);
++ ctl &= ~HOST_IRQ_EN;
++ writel(ctl, mmio + HOST_CTL);
++ readl(mmio + HOST_CTL); /* flush */
++ }
++
++ return ata_pci_device_suspend(pdev, mesg);
++}
++
++static int ahci_pci_device_resume(struct pci_dev *pdev)
++{
++ struct ata_host *host = dev_get_drvdata(&pdev->dev);
++ struct ahci_host_priv *hpriv = host->private_data;
++ void __iomem *mmio = host->mmio_base;
++ int rc;
++
++ ata_pci_device_do_resume(pdev);
++
++ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
++ rc = ahci_reset_controller(mmio, pdev);
++ if (rc)
++ return rc;
++
++ ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap);
++ }
++
++ ata_host_resume(host);
++
++ return 0;
++}
++
++static int ahci_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++ struct ahci_port_priv *pp;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ void *mem;
++ dma_addr_t mem_dma;
++ int rc;
++
++ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
++ if (!pp)
++ return -ENOMEM;
++ memset(pp, 0, sizeof(*pp));
++
++ rc = ata_pad_alloc(ap, dev);
++ if (rc) {
++ kfree(pp);
++ return rc;
++ }
++
++ mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
++ if (!mem) {
++ ata_pad_free(ap, dev);
++ kfree(pp);
++ return -ENOMEM;
++ }
++ memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
++
++ /*
++ * First item in chunk of DMA memory: 32-slot command table,
++ * 32 bytes each in size
++ */
++ pp->cmd_slot = mem;
++ pp->cmd_slot_dma = mem_dma;
++
++ mem += AHCI_CMD_SLOT_SZ;
++ mem_dma += AHCI_CMD_SLOT_SZ;
++
++ /*
++ * Second item: Received-FIS area
++ */
++ pp->rx_fis = mem;
++ pp->rx_fis_dma = mem_dma;
++
++ mem += AHCI_RX_FIS_SZ;
++ mem_dma += AHCI_RX_FIS_SZ;
++
++ /*
++ * Third item: data area for storing a single command
++ * and its scatter-gather table
++ */
++ pp->cmd_tbl = mem;
++ pp->cmd_tbl_dma = mem_dma;
++
++ ap->private_data = pp;
++
++ /* initialize port */
++ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
++
++ return 0;
++}
++
++static void ahci_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++ struct ahci_port_priv *pp = ap->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
++ const char *emsg = NULL;
++ int rc;
++
++ /* de-initialize port */
++ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
++ if (rc)
++ ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
++
++ ap->private_data = NULL;
++ dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
++ pp->cmd_slot, pp->cmd_slot_dma);
++ ata_pad_free(ap, dev);
++ kfree(pp);
++}
++
++static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
++ unsigned int port_idx)
++{
++ VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
++ base = ahci_port_base_ul(base, port_idx);
++ VPRINTK("base now==0x%lx\n", base);
++
++ port->cmd_addr = base;
++ port->scr_addr = base + PORT_SCR;
++
++ VPRINTK("EXIT\n");
++}
++
++static int ahci_host_init(struct ata_probe_ent *probe_ent)
++{
++ struct ahci_host_priv *hpriv = probe_ent->private_data;
++ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
++ void __iomem *mmio = probe_ent->mmio_base;
++ unsigned int i, using_dac;
++ int rc;
++
++ rc = ahci_reset_controller(mmio, pdev);
++ if (rc)
++ return rc;
++
++ hpriv->cap = readl(mmio + HOST_CAP);
++ hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
++ probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
++
++ VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
++ hpriv->cap, hpriv->port_map, probe_ent->n_ports);
++
++ using_dac = hpriv->cap & HOST_CAP_64;
++ if (using_dac &&
++ !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
++ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
++ if (rc) {
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "64-bit DMA enable failed\n");
++ return rc;
++ }
++ }
++ } else {
++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit DMA enable failed\n");
++ return rc;
++ }
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit consistent DMA enable failed\n");
++ return rc;
++ }
++ }
++
++ for (i = 0; i < probe_ent->n_ports; i++)
++ ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
++
++ ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
++
++ pci_set_master(pdev);
++
++ return 0;
++}
++
++static void ahci_print_info(struct ata_probe_ent *probe_ent)
++{
++ struct ahci_host_priv *hpriv = probe_ent->private_data;
++ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
++ void __iomem *mmio = probe_ent->mmio_base;
++ u32 vers, cap, impl, speed;
++ const char *speed_s;
++ u16 cc;
++ const char *scc_s;
++
++ vers = readl(mmio + HOST_VERSION);
++ cap = hpriv->cap;
++ impl = hpriv->port_map;
++
++ speed = (cap >> 20) & 0xf;
++ if (speed == 1)
++ speed_s = "1.5";
++ else if (speed == 2)
++ speed_s = "3";
++ else
++ speed_s = "?";
++
++ pci_read_config_word(pdev, 0x0a, &cc);
++ if (cc == 0x0101)
++ scc_s = "IDE";
++ else if (cc == 0x0106)
++ scc_s = "SATA";
++ else if (cc == 0x0104)
++ scc_s = "RAID";
++ else
++ scc_s = "unknown";
++
++ dev_printk(KERN_INFO, &pdev->dev,
++ "AHCI %02x%02x.%02x%02x "
++ "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
++ ,
++
++ (vers >> 24) & 0xff,
++ (vers >> 16) & 0xff,
++ (vers >> 8) & 0xff,
++ vers & 0xff,
++
++ ((cap >> 8) & 0x1f) + 1,
++ (cap & 0x1f) + 1,
++ speed_s,
++ impl,
++ scc_s);
++
++ dev_printk(KERN_INFO, &pdev->dev,
++ "flags: "
++ "%s%s%s%s%s%s"
++ "%s%s%s%s%s%s%s\n"
++ ,
++
++ cap & (1 << 31) ? "64bit " : "",
++ cap & (1 << 30) ? "ncq " : "",
++ cap & (1 << 28) ? "ilck " : "",
++ cap & (1 << 27) ? "stag " : "",
++ cap & (1 << 26) ? "pm " : "",
++ cap & (1 << 25) ? "led " : "",
++
++ cap & (1 << 24) ? "clo " : "",
++ cap & (1 << 19) ? "nz " : "",
++ cap & (1 << 18) ? "only " : "",
++ cap & (1 << 17) ? "pmp " : "",
++ cap & (1 << 15) ? "pio " : "",
++ cap & (1 << 14) ? "slum " : "",
++ cap & (1 << 13) ? "part " : ""
++ );
++}
++
++static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ struct ahci_host_priv *hpriv;
++ unsigned long base;
++ void __iomem *mmio_base;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++ int have_msi, pci_dev_busy = 0;
++ int rc;
++
++ VPRINTK("ENTER\n");
++
++ WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ /* JMicron-specific fixup: make sure we're in AHCI mode */
++ /* This is protected from races with ata_jmicron by the pci probe
++ locking */
++ if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
++ /* AHCI enable, AHCI on function 0 */
++ pci_write_config_byte(pdev, 0x41, 0xa1);
++ /* Function 1 is the PATA controller */
++ if (PCI_FUNC(pdev->devfn))
++ return -ENODEV;
++ }
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ if (pci_enable_msi(pdev) == 0)
++ have_msi = 1;
++ else {
++ pci_intx(pdev, 1);
++ have_msi = 0;
++ }
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_msi;
++ }
++
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++ base = (unsigned long) mmio_base;
++
++ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
++ if (!hpriv) {
++ rc = -ENOMEM;
++ goto err_out_iounmap;
++ }
++ memset(hpriv, 0, sizeof(*hpriv));
++
++ probe_ent->sht = ahci_port_info[board_idx].sht;
++ probe_ent->port_flags = ahci_port_info[board_idx].flags;
++ probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask;
++ probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = ahci_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++ probe_ent->private_data = hpriv;
++
++ if (have_msi)
++ hpriv->flags |= AHCI_FLAG_MSI;
++
++ /* initialize adapter */
++ rc = ahci_host_init(probe_ent);
++ if (rc)
++ goto err_out_hpriv;
++
++ if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
++ (hpriv->cap & HOST_CAP_NCQ))
++ probe_ent->port_flags |= ATA_FLAG_NCQ;
++
++ ahci_print_info(probe_ent);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_hpriv:
++ kfree(hpriv);
++err_out_iounmap:
++ pci_iounmap(pdev, mmio_base);
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_msi:
++ if (have_msi)
++ pci_disable_msi(pdev);
++ else
++ pci_intx(pdev, 0);
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++static void ahci_remove_one (struct pci_dev *pdev)
++{
++ struct device *dev = pci_dev_to_dev(pdev);
++ struct ata_host *host = dev_get_drvdata(dev);
++ struct ahci_host_priv *hpriv = host->private_data;
++ unsigned int i;
++ int have_msi;
++
++ for (i = 0; i < host->n_ports; i++)
++ ata_port_detach(host->ports[i]);
++
++ have_msi = hpriv->flags & AHCI_FLAG_MSI;
++ free_irq(host->irq, host);
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++
++ ata_scsi_release(ap->scsi_host);
++ scsi_host_put(ap->scsi_host);
++ }
++
++ kfree(hpriv);
++ pci_iounmap(pdev, host->mmio_base);
++ kfree(host);
++
++ if (have_msi)
++ pci_disable_msi(pdev);
++ else
++ pci_intx(pdev, 0);
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++ dev_set_drvdata(dev, NULL);
++}
++
++static int __init ahci_init(void)
++{
++ return pci_register_driver(&ahci_pci_driver);
++}
++
++static void __exit ahci_exit(void)
++{
++ pci_unregister_driver(&ahci_pci_driver);
++}
++
++
++MODULE_AUTHOR("Jeff Garzik");
++MODULE_DESCRIPTION("AHCI SATA low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ahci_init);
++module_exit(ahci_exit);
+diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
+new file mode 100644
+index 0000000..377425e
+--- /dev/null
++++ b/drivers/ata/ata_generic.c
+@@ -0,0 +1,252 @@
++/*
++ * ata_generic.c - Generic PATA/SATA controller driver.
++ * Copyright 2005 Red Hat Inc <alan at redhat.com>, all rights reserved.
++ *
++ * Elements from ide/pci/generic.c
++ * Copyright (C) 2001-2002 Andre Hedrick <andre at linux-ide.org>
++ * Portions (C) Copyright 2002 Red Hat Inc <alan at redhat.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public License
++ *
++ * Driver for PCI IDE interfaces implementing the standard bus mastering
++ * interface functionality. This assumes the BIOS did the drive set up and
++ * tuning for us. By default we do not grab all IDE class devices as they
++ * may have other drivers or need fixups to avoid problems. Instead we keep
++ * a default list of stuff without documentation/driver that appears to
++ * work.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "ata_generic"
++#define DRV_VERSION "0.2.6"
++
++/*
++ * A generic parallel ATA driver using libata
++ */
++
++/**
++ * generic_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int generic_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++
++/**
++ * generic_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ * @classes:
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++
++static void generic_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * generic_set_mode - mode setting
++ * @ap: interface to set up
++ *
++ * Use a non standard set_mode function. We don't want to be tuned.
++ * The BIOS configured everything. Our job is not to fiddle. We
++ * read the dma enabled bits from the PCI configuration of the device
++ * and respect them.
++ */
++
++static void generic_set_mode(struct ata_port *ap)
++{
++ int dma_enabled = 0;
++ int i;
++
++ /* Bits 5 and 6 indicate if DMA is active on master/slave */
++ if (ap->ioaddr.bmdma_addr)
++ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ if (ata_dev_enabled(dev)) {
++ /* We don't really care */
++ dev->pio_mode = XFER_PIO_0;
++ dev->dma_mode = XFER_MW_DMA_0;
++ /* We do need the right mode information for DMA or PIO
++ and this comes from the current configuration flags */
++ if (dma_enabled & (1 << (5 + i))) {
++ dev->xfer_mode = XFER_MW_DMA_0;
++ dev->xfer_shift = ATA_SHIFT_MWDMA;
++ dev->flags &= ~ATA_DFLAG_PIO;
++ } else {
++ dev->xfer_mode = XFER_PIO_0;
++ dev->xfer_shift = ATA_SHIFT_PIO;
++ dev->flags |= ATA_DFLAG_PIO;
++ }
++ }
++ }
++}
++
++static struct scsi_host_template generic_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations generic_port_ops = {
++ .set_mode = generic_set_mode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = generic_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int all_generic_ide; /* Set to claim all devices */
++
++/**
++ * ata_generic_init - attach generic IDE
++ * @dev: PCI device found
++ * @id: match entry
++ *
++ * Called each time a matching IDE interface is found. We check if the
++ * interface is one we wish to claim and if so we perform any chip
++ * specific hacks then let the ATA layer do the heavy lifting.
++ */
++
++static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ u16 command;
++ static struct ata_port_info info = {
++ .sht = &generic_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &generic_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ /* Don't use the generic entry unless instructed to do so */
++ if (id->driver_data == 1 && all_generic_ide == 0)
++ return -ENODEV;
++
++ /* Devices that need care */
++ if (dev->vendor == PCI_VENDOR_ID_UMC &&
++ dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
++ (!(PCI_FUNC(dev->devfn) & 1)))
++ return -ENODEV;
++
++ if (dev->vendor == PCI_VENDOR_ID_OPTI &&
++ dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
++ (!(PCI_FUNC(dev->devfn) & 1)))
++ return -ENODEV;
++
++ /* Don't re-enable devices in generic mode or we will break some
++ motherboards with disabled and unused IDE controllers */
++ pci_read_config_word(dev, PCI_COMMAND, &command);
++ if (!(command & PCI_COMMAND_IO))
++ return -ENODEV;
++
++ if (dev->vendor == PCI_VENDOR_ID_AL)
++ ata_pci_clear_simplex(dev);
++
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static struct pci_device_id ata_generic[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), },
++ { PCI_DEVICE(PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), },
++ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F), },
++ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A), },
++ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF), },
++ { PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), },
++ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), },
++ { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), },
++ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
++ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
++ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
++ /* Must come last. If you add entries adjust this table appropriately */
++ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
++ { 0, },
++};
++
++static struct pci_driver ata_generic_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = ata_generic,
++ .probe = ata_generic_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init ata_generic_init(void)
++{
++ return pci_module_init(&ata_generic_pci_driver);
++}
++
++
++static void __exit ata_generic_exit(void)
++{
++ pci_unregister_driver(&ata_generic_pci_driver);
++}
++
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for generic ATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, ata_generic);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ata_generic_init);
++module_exit(ata_generic_exit);
++
++module_param(all_generic_ide, int, 0);
+diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
+new file mode 100644
+index 0000000..720174d
+--- /dev/null
++++ b/drivers/ata/ata_piix.c
+@@ -0,0 +1,1229 @@
++/*
++ * ata_piix.c - Intel PATA/SATA controllers
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ *
++ * Copyright 2003-2005 Red Hat Inc
++ * Copyright 2003-2005 Jeff Garzik
++ *
++ *
++ * Copyright header from piix.c:
++ *
++ * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
++ * Copyright (C) 1998-2000 Andre Hedrick <andre at linux-ide.org>
++ * Copyright (C) 2003 Red Hat Inc <alan at 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, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available at http://developer.intel.com/
++ *
++ * Documentation
++ * Publically available from Intel web site. Errata documentation
++ * is also publically available. As an aide to anyone hacking on this
++ * driver the list of errata that are relevant is below.going back to
++ * PIIX4. Older device documentation is now a bit tricky to find.
++ *
++ * The chipsets all follow very much the same design. The orginal Triton
++ * series chipsets do _not_ support independant device timings, but this
++ * is fixed in Triton II. With the odd mobile exception the chips then
++ * change little except in gaining more modes until SATA arrives. This
++ * driver supports only the chips with independant timing (that is those
++ * with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix
++ * for the early chip drivers.
++ *
++ * Errata of note:
++ *
++ * Unfixable
++ * PIIX4 errata #9 - Only on ultra obscure hw
++ * ICH3 errata #13 - Not observed to affect real hw
++ * by Intel
++ *
++ * Things we must deal with
++ * PIIX4 errata #10 - BM IDE hang with non UDMA
++ * (must stop/start dma to recover)
++ * 440MX errata #15 - As PIIX4 errata #10
++ * PIIX4 errata #15 - Must not read control registers
++ * during a PIO transfer
++ * 440MX errata #13 - As PIIX4 errata #15
++ * ICH2 errata #21 - DMA mode 0 doesn't work right
++ * ICH0/1 errata #55 - As ICH2 errata #21
++ * ICH2 spec c #9 - Extra operations needed to handle
++ * drive hotswap [NOT YET SUPPORTED]
++ * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
++ * and must be dword aligned
++ * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
++ *
++ * Should have been BIOS fixed:
++ * 450NX: errata #19 - DMA hangs on old 450NX
++ * 450NX: errata #20 - DMA hangs on old 450NX
++ * 450NX: errata #25 - Corruption with DMA on old 450NX
++ * ICH3 errata #15 - IDE deadlock under high load
++ * (BIOS must set dev 31 fn 0 bit 23)
++ * ICH3 errata #18 - Don't use native mode
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "ata_piix"
++#define DRV_VERSION "2.00ac6"
++
++enum {
++ PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
++ ICH5_PMR = 0x90, /* port mapping register */
++ ICH5_PCS = 0x92, /* port control and status */
++ PIIX_SCC = 0x0A, /* sub-class code register */
++
++ PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */
++ PIIX_FLAG_SCR = (1 << 26), /* SCR available */
++ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
++ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
++
++ /* combined mode. if set, PATA is channel 0.
++ * if clear, PATA is channel 1.
++ */
++ PIIX_PORT_ENABLED = (1 << 0),
++ PIIX_PORT_PRESENT = (1 << 4),
++
++ PIIX_80C_PRI = (1 << 5) | (1 << 4),
++ PIIX_80C_SEC = (1 << 7) | (1 << 6),
++
++ /* controller IDs */
++ piix_pata_33 = 0, /* PIIX3 or 4 at 33Mhz */
++ ich_pata_33 = 1, /* ICH up to UDMA 33 only */
++ ich_pata_66 = 2, /* ICH up to 66 Mhz */
++ ich_pata_100 = 3, /* ICH up to UDMA 100 */
++ ich_pata_133 = 4, /* ICH up to UDMA 133 */
++ ich5_sata = 5,
++ esb_sata = 6,
++ ich6_sata = 7,
++ ich6_sata_ahci = 8,
++ ich6m_sata_ahci = 9,
++ ich8_sata_ahci = 10,
++
++ /* constants for mapping table */
++ P0 = 0, /* port 0 */
++ P1 = 1, /* port 1 */
++ P2 = 2, /* port 2 */
++ P3 = 3, /* port 3 */
++ IDE = -1, /* IDE */
++ NA = -2, /* not avaliable */
++ RV = -3, /* reserved */
++
++ PIIX_AHCI_DEVICE = 6,
++};
++
++struct piix_map_db {
++ const u32 mask;
++ const u16 port_enable;
++ const int present_shift;
++ const int map[][4];
++};
++
++struct piix_host_priv {
++ const int *map;
++ const struct piix_map_db *map_db;
++};
++
++static int piix_init_one (struct pci_dev *pdev,
++ const struct pci_device_id *ent);
++static void piix_host_stop(struct ata_host *host);
++static void piix_pata_error_handler(struct ata_port *ap);
++static void ich_pata_error_handler(struct ata_port *ap);
++static void piix_sata_error_handler(struct ata_port *ap);
++static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
++static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
++static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
++
++static unsigned int in_module_init = 1;
++
++static const struct pci_device_id piix_pci_tbl[] = {
++#ifdef ATA_ENABLE_PATA
++ /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
++ /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
++ { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
++ { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* Intel PIIX4 */
++ { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
++ /* Intel PIIX4 */
++ { 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
++ /* Intel PIIX */
++ { 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
++ /* Intel ICH (i810, i815, i840) UDMA 66*/
++ { 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 },
++ /* Intel ICH0 : UDMA 33*/
++ { 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 },
++ /* Intel ICH2M */
++ { 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */
++ { 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* Intel ICH3M */
++ { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* Intel ICH3 (E7500/1) UDMA 100 */
++ { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
++ { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* Intel ICH5 */
++ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
++ /* C-ICH (i810E2) */
++ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* ESB (855GME/875P + 6300ESB) UDMA 100 */
++ { 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* ICH6 (and 6) (i915) UDMA 100 */
++ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* ICH7/7-R (i945, i975) UDMA 100*/
++ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
++ { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++#endif
++
++ /* NOTE: The following PCI ids must be kept in sync with the
++ * list in drivers/pci/quirks.c.
++ */
++
++ /* 82801EB (ICH5) */
++ { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
++ /* 82801EB (ICH5) */
++ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
++ /* 6300ESB (ICH5 variant with broken PCS present bits) */
++ { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
++ /* 6300ESB pretending RAID */
++ { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
++ /* 82801FB/FW (ICH6/ICH6W) */
++ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
++ /* 82801FR/FRW (ICH6R/ICH6RW) */
++ { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
++ /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
++ { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
++ /* 82801GB/GR/GH (ICH7, identical to ICH6) */
++ { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
++ /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
++ { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
++ /* Enterprise Southbridge 2 (where's the datasheet?) */
++ { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
++ /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
++ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++ /* SATA Controller 2 IDE (ICH8, ditto) */
++ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++ /* Mobile SATA Controller IDE (ICH8M, ditto) */
++ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver piix_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = piix_pci_tbl,
++ .probe = piix_init_one,
++ .remove = ata_pci_remove_one,
++ .suspend = ata_pci_device_suspend,
++ .resume = ata_pci_device_resume,
++};
++
++static struct scsi_host_template piix_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++ .resume = ata_scsi_device_resume,
++ .suspend = ata_scsi_device_suspend,
++};
++
++static const struct ata_port_operations piix_pata_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = piix_set_piomode,
++ .set_dmamode = piix_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = piix_pata_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = piix_host_stop,
++};
++
++static const struct ata_port_operations ich_pata_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = piix_set_piomode,
++ .set_dmamode = ich_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ich_pata_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations piix_sata_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = piix_sata_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = piix_host_stop,
++};
++
++static const struct piix_map_db ich5_map_db = {
++ .mask = 0x7,
++ .port_enable = 0x3,
++ .present_shift = 4,
++ .map = {
++ /* PM PS SM SS MAP */
++ { P0, NA, P1, NA }, /* 000b */
++ { P1, NA, P0, NA }, /* 001b */
++ { RV, RV, RV, RV },
++ { RV, RV, RV, RV },
++ { P0, P1, IDE, IDE }, /* 100b */
++ { P1, P0, IDE, IDE }, /* 101b */
++ { IDE, IDE, P0, P1 }, /* 110b */
++ { IDE, IDE, P1, P0 }, /* 111b */
++ },
++};
++
++static const struct piix_map_db ich6_map_db = {
++ .mask = 0x3,
++ .port_enable = 0xf,
++ .present_shift = 4,
++ .map = {
++ /* PM PS SM SS MAP */
++ { P0, P2, P1, P3 }, /* 00b */
++ { IDE, IDE, P1, P3 }, /* 01b */
++ { P0, P2, IDE, IDE }, /* 10b */
++ { RV, RV, RV, RV },
++ },
++};
++
++static const struct piix_map_db ich6m_map_db = {
++ .mask = 0x3,
++ .port_enable = 0x5,
++ .present_shift = 4,
++
++ /* Map 01b isn't specified in the doc but some notebooks use
++ * it anyway. MAP 01b have been spotted on both ICH6M and
++ * ICH7M.
++ */
++ .map = {
++ /* PM PS SM SS MAP */
++ { P0, P2, RV, RV }, /* 00b */
++ { IDE, IDE, P1, P3 }, /* 01b */
++ { P0, P2, IDE, IDE }, /* 10b */
++ { RV, RV, RV, RV },
++ },
++};
++
++static const struct piix_map_db ich8_map_db = {
++ .mask = 0x3,
++ .port_enable = 0x3,
++ .present_shift = 8,
++ .map = {
++ /* PM PS SM SS MAP */
++ { P0, P2, P1, P3 }, /* 00b (hardwired when in AHCI) */
++ { RV, RV, RV, RV },
++ { IDE, IDE, NA, NA }, /* 10b (IDE mode) */
++ { RV, RV, RV, RV },
++ },
++};
++
++static const struct piix_map_db *piix_map_db_table[] = {
++ [ich5_sata] = &ich5_map_db,
++ [esb_sata] = &ich5_map_db,
++ [ich6_sata] = &ich6_map_db,
++ [ich6_sata_ahci] = &ich6_map_db,
++ [ich6m_sata_ahci] = &ich6m_map_db,
++ [ich8_sata_ahci] = &ich8_map_db,
++};
++
++static struct ata_port_info piix_port_info[] = {
++ /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
++ .udma_mask = ATA_UDMA_MASK_40C,
++ .port_ops = &piix_pata_ops,
++ },
++
++ /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
++ .pio_mask = 0x1f, /* pio 0-4 */
++ .mwdma_mask = 0x06, /* Check: maybe 0x07 */
++ .udma_mask = ATA_UDMA2, /* UDMA33 */
++ .port_ops = &ich_pata_ops,
++ },
++ /* ich_pata_66: 2 ICH controllers up to 66MHz */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
++ .pio_mask = 0x1f, /* pio 0-4 */
++ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */
++ .udma_mask = ATA_UDMA4,
++ .port_ops = &ich_pata_ops,
++ },
++
++ /* ich_pata_100: 3 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x06, /* mwdma1-2 */
++ .udma_mask = ATA_UDMA5, /* udma0-5 */
++ .port_ops = &ich_pata_ops,
++ },
++
++ /* ich_pata_133: 4 ICH with full UDMA6 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
++ .pio_mask = 0x1f, /* pio 0-4 */
++ .mwdma_mask = 0x06, /* Check: maybe 0x07 */
++ .udma_mask = ATA_UDMA6, /* UDMA133 */
++ .port_ops = &ich_pata_ops,
++ },
++
++ /* ich5_sata: 5 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR |
++ PIIX_FLAG_IGNORE_PCS,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &piix_sata_ops,
++ },
++
++ /* i6300esb_sata: 6 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SATA |
++ PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &piix_sata_ops,
++ },
++
++ /* ich6_sata: 7 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SATA |
++ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &piix_sata_ops,
++ },
++
++ /* ich6_sata_ahci: 8 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SATA |
++ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
++ PIIX_FLAG_AHCI,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &piix_sata_ops,
++ },
++
++ /* ich6m_sata_ahci: 9 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SATA |
++ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
++ PIIX_FLAG_AHCI,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &piix_sata_ops,
++ },
++
++ /* ich8_sata_ahci: 10 */
++ {
++ .sht = &piix_sht,
++ .flags = ATA_FLAG_SATA |
++ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
++ PIIX_FLAG_AHCI,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &piix_sata_ops,
++ },
++
++};
++
++static struct pci_bits piix_enable_bits[] = {
++ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
++ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
++};
++
++MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
++MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++static int force_pcs = 0;
++module_param(force_pcs, int, 0444);
++MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around "
++ "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)");
++
++/**
++ * piix_pata_cbl_detect - Probe host controller cable detect info
++ * @ap: Port for which cable detect info is desired
++ *
++ * Read 80c cable indicator from ATA PCI device's PCI config
++ * register. This register is normally set by firmware (BIOS).
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void ich_pata_cbl_detect(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 tmp, mask;
++
++ /* no 80c support in host controller? */
++ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
++ goto cbl40;
++
++ /* check BIOS cable detect results */
++ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
++ pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
++ if ((tmp & mask) == 0)
++ goto cbl40;
++
++ ap->cbl = ATA_CBL_PATA80;
++ return;
++
++cbl40:
++ ap->cbl = ATA_CBL_PATA40;
++}
++
++/**
++ * piix_pata_prereset - prereset for PATA host controller
++ * @ap: Target port
++ *
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++static int piix_pata_prereset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++static void piix_pata_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++
++/**
++ * ich_pata_prereset - prereset for PATA host controller
++ * @ap: Target port
++ *
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++static int ich_pata_prereset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) {
++ ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
++ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
++ return 0;
++ }
++
++ ich_pata_cbl_detect(ap);
++
++ return ata_std_prereset(ap);
++}
++
++static void ich_pata_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, ich_pata_prereset, ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * piix_sata_present_mask - determine present mask for SATA host controller
++ * @ap: Target port
++ *
++ * Reads SATA PCI device's PCI config register Port Configuration
++ * and Status (PCS) to determine port and device availability.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ *
++ * RETURNS:
++ * determined present_mask
++ */
++static unsigned int piix_sata_present_mask(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct piix_host_priv *hpriv = ap->host->private_data;
++ const unsigned int *map = hpriv->map;
++ int base = 2 * ap->port_no;
++ unsigned int present_mask = 0;
++ int port, i;
++ u16 pcs;
++
++ pci_read_config_word(pdev, ICH5_PCS, &pcs);
++ DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
++
++ for (i = 0; i < 2; i++) {
++ port = map[base + i];
++ if (port < 0)
++ continue;
++ if ((ap->flags & PIIX_FLAG_IGNORE_PCS) ||
++ (pcs & 1 << (hpriv->map_db->present_shift + port)))
++ present_mask |= 1 << i;
++ }
++
++ DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
++ ap->id, pcs, present_mask);
++
++ return present_mask;
++}
++
++/**
++ * piix_sata_softreset - reset SATA host port via ATA SRST
++ * @ap: port to reset
++ * @classes: resulting classes of attached devices
++ *
++ * Reset SATA host port via ATA SRST. On controllers with
++ * reliable PCS present bits, the bits are used to determine
++ * device presence.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes)
++{
++ unsigned int present_mask;
++ int i, rc;
++
++ present_mask = piix_sata_present_mask(ap);
++
++ rc = ata_std_softreset(ap, classes);
++ if (rc)
++ return rc;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ if (!(present_mask & (1 << i)))
++ classes[i] = ATA_DEV_NONE;
++ }
++
++ return 0;
++}
++
++static void piix_sata_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * piix_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set PIO mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio = adev->pio_mode - XFER_PIO_0;
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ unsigned int is_slave = (adev->devno != 0);
++ unsigned int master_port= ap->port_no ? 0x42 : 0x40;
++ unsigned int slave_port = 0x44;
++ u16 master_data;
++ u8 slave_data;
++ u8 udma_enable;
++ int control = 0;
++
++ /*
++ * See Intel Document 298600-004 for the timing programing rules
++ * for ICH controllers.
++ */
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ if (pio >= 2)
++ control |= 1; /* TIME1 enable */
++ if (ata_pio_need_iordy(adev))
++ control |= 2; /* IE enable */
++
++ /* Intel specifies that the PPE functionality is for disk only */
++ if (adev->class == ATA_DEV_ATA)
++ control |= 4; /* PPE enable */
++
++ pci_read_config_word(dev, master_port, &master_data);
++ if (is_slave) {
++ /* Enable SITRE (seperate slave timing register) */
++ master_data |= 0x4000;
++ /* enable PPE1, IE1 and TIME1 as needed */
++ master_data |= (control << 4);
++ pci_read_config_byte(dev, slave_port, &slave_data);
++ slave_data &= (ap->port_no ? 0x0f : 0xf0);
++ /* Load the timing nibble for this slave */
++ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
++ } else {
++ /* Master keeps the bits in a different format */
++ master_data &= 0xccf8;
++ /* Enable PPE, IE and TIME as appropriate */
++ master_data |= control;
++ master_data |=
++ (timings[pio][0] << 12) |
++ (timings[pio][1] << 8);
++ }
++ pci_write_config_word(dev, master_port, master_data);
++ if (is_slave)
++ pci_write_config_byte(dev, slave_port, slave_data);
++
++ /* Ensure the UDMA bit is off - it will be turned back on if
++ UDMA is selected */
++
++ if (ap->udma_mask) {
++ pci_read_config_byte(dev, 0x48, &udma_enable);
++ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
++ pci_write_config_byte(dev, 0x48, udma_enable);
++ }
++}
++
++/**
++ * do_pata_set_dmamode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Drive in question
++ * @udma: udma mode, 0 - 6
++ * @isich: set if the chip is an ICH device
++ *
++ * Set UDMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, int isich)
++{
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ u8 master_port = ap->port_no ? 0x42 : 0x40;
++ u16 master_data;
++ u8 speed = adev->dma_mode;
++ int devid = adev->devno + 2 * ap->port_no;
++ u8 udma_enable;
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ pci_read_config_word(dev, master_port, &master_data);
++ pci_read_config_byte(dev, 0x48, &udma_enable);
++
++ if (speed >= XFER_UDMA_0) {
++ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
++ u16 udma_timing;
++ u16 ideconf;
++ int u_clock, u_speed;
++
++ /*
++ * UDMA is handled by a combination of clock switching and
++ * selection of dividers
++ *
++ * Handy rule: Odd modes are UDMATIMx 01, even are 02
++ * except UDMA0 which is 00
++ */
++ u_speed = min(2 - (udma & 1), udma);
++ if (udma == 5)
++ u_clock = 0x1000; /* 100Mhz */
++ else if (udma > 2)
++ u_clock = 1; /* 66Mhz */
++ else
++ u_clock = 0; /* 33Mhz */
++
++ udma_enable |= (1 << devid);
++
++ /* Load the CT/RP selection */
++ pci_read_config_word(dev, 0x4A, &udma_timing);
++ udma_timing &= ~(3 << (4 * devid));
++ udma_timing |= u_speed << (4 * devid);
++ pci_write_config_word(dev, 0x4A, udma_timing);
++
++ if (isich) {
++ /* Select a 33/66/100Mhz clock */
++ pci_read_config_word(dev, 0x54, &ideconf);
++ ideconf &= ~(0x1001 << devid);
++ ideconf |= u_clock << devid;
++ /* For ICH or later we should set bit 10 for better
++ performance (WR_PingPong_En) */
++ pci_write_config_word(dev, 0x54, ideconf);
++ }
++ } else {
++ /*
++ * MWDMA is driven by the PIO timings. We must also enable
++ * IORDY unconditionally along with TIME1. PPE has already
++ * been set when the PIO timing was set.
++ */
++ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
++ unsigned int control;
++ u8 slave_data;
++ const unsigned int needed_pio[3] = {
++ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
++ };
++ int pio = needed_pio[mwdma] - XFER_PIO_0;
++
++ control = 3; /* IORDY|TIME1 */
++
++ /* If the drive MWDMA is faster than it can do PIO then
++ we must force PIO into PIO0 */
++
++ if (adev->pio_mode < needed_pio[mwdma])
++ /* Enable DMA timing only */
++ control |= 8; /* PIO cycles in PIO0 */
++
++ if (adev->devno) { /* Slave */
++ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
++ master_data |= control << 4;
++ pci_read_config_byte(dev, 0x44, &slave_data);
++ slave_data &= (0x0F + 0xE1 * ap->port_no);
++ /* Load the matching timing */
++ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
++ pci_write_config_byte(dev, 0x44, slave_data);
++ } else { /* Master */
++ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
++ and master timing bits */
++ master_data |= control;
++ master_data |=
++ (timings[pio][0] << 12) |
++ (timings[pio][1] << 8);
++ }
++ udma_enable &= ~(1 << devid);
++ pci_write_config_word(dev, master_port, master_data);
++ }
++ /* Don't scribble on 0x48 if the controller does not support UDMA */
++ if (ap->udma_mask)
++ pci_write_config_byte(dev, 0x48, udma_enable);
++}
++
++/**
++ * piix_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set MW/UDMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ do_pata_set_dmamode(ap, adev, 0);
++}
++
++/**
++ * ich_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set MW/UDMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ do_pata_set_dmamode(ap, adev, 1);
++}
++
++#define AHCI_PCI_BAR 5
++#define AHCI_GLOBAL_CTL 0x04
++#define AHCI_ENABLE (1 << 31)
++static int piix_disable_ahci(struct pci_dev *pdev)
++{
++ void __iomem *mmio;
++ u32 tmp;
++ int rc = 0;
++
++ /* BUG: pci_enable_device has not yet been called. This
++ * works because this device is usually set up by BIOS.
++ */
++
++ if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
++ !pci_resource_len(pdev, AHCI_PCI_BAR))
++ return 0;
++
++ mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
++ if (!mmio)
++ return -ENOMEM;
++
++ tmp = readl(mmio + AHCI_GLOBAL_CTL);
++ if (tmp & AHCI_ENABLE) {
++ tmp &= ~AHCI_ENABLE;
++ writel(tmp, mmio + AHCI_GLOBAL_CTL);
++
++ tmp = readl(mmio + AHCI_GLOBAL_CTL);
++ if (tmp & AHCI_ENABLE)
++ rc = -EIO;
++ }
++
++ pci_iounmap(pdev, mmio);
++ return rc;
++}
++
++/**
++ * piix_check_450nx_errata - Check for problem 450NX setup
++ * @ata_dev: the PCI device to check
++ *
++ * Check for the present of 450NX errata #19 and errata #25. If
++ * they are found return an error code so we can turn off DMA
++ */
++
++static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
++{
++ struct pci_dev *pdev = NULL;
++ u16 cfg;
++ u8 rev;
++ int no_piix_dma = 0;
++
++ while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL)
++ {
++ /* Look for 450NX PXB. Check for problem configurations
++ A PCI quirk checks bit 6 already */
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
++ pci_read_config_word(pdev, 0x41, &cfg);
++ /* Only on the original revision: IDE DMA can hang */
++ if (rev == 0x00)
++ no_piix_dma = 1;
++ /* On all revisions below 5 PXB bus lock must be disabled for IDE */
++ else if (cfg & (1<<14) && rev < 5)
++ no_piix_dma = 2;
++ }
++ if (no_piix_dma)
++ dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");
++ if (no_piix_dma == 2)
++ dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");
++ return no_piix_dma;
++}
++
++static void __devinit piix_init_pcs(struct pci_dev *pdev,
++ struct ata_port_info *pinfo,
++ const struct piix_map_db *map_db)
++{
++ u16 pcs, new_pcs;
++
++ pci_read_config_word(pdev, ICH5_PCS, &pcs);
++
++ new_pcs = pcs | map_db->port_enable;
++
++ if (new_pcs != pcs) {
++ DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs);
++ pci_write_config_word(pdev, ICH5_PCS, new_pcs);
++ msleep(150);
++ }
++
++ if (force_pcs == 1) {
++ dev_printk(KERN_INFO, &pdev->dev,
++ "force ignoring PCS (0x%x)\n", new_pcs);
++ pinfo[0].flags |= PIIX_FLAG_IGNORE_PCS;
++ pinfo[1].flags |= PIIX_FLAG_IGNORE_PCS;
++ } else if (force_pcs == 2) {
++ dev_printk(KERN_INFO, &pdev->dev,
++ "force honoring PCS (0x%x)\n", new_pcs);
++ pinfo[0].flags &= ~PIIX_FLAG_IGNORE_PCS;
++ pinfo[1].flags &= ~PIIX_FLAG_IGNORE_PCS;
++ }
++}
++
++static void __devinit piix_init_sata_map(struct pci_dev *pdev,
++ struct ata_port_info *pinfo,
++ const struct piix_map_db *map_db)
++{
++ struct piix_host_priv *hpriv = pinfo[0].private_data;
++ const unsigned int *map;
++ int i, invalid_map = 0;
++ u8 map_value;
++
++ pci_read_config_byte(pdev, ICH5_PMR, &map_value);
++
++ map = map_db->map[map_value & map_db->mask];
++
++ dev_printk(KERN_INFO, &pdev->dev, "MAP [");
++ for (i = 0; i < 4; i++) {
++ switch (map[i]) {
++ case RV:
++ invalid_map = 1;
++ printk(" XX");
++ break;
++
++ case NA:
++ printk(" --");
++ break;
++
++ case IDE:
++ WARN_ON((i & 1) || map[i + 1] != IDE);
++ pinfo[i / 2] = piix_port_info[ich_pata_100];
++ pinfo[i / 2].private_data = hpriv;
++ i++;
++ printk(" IDE IDE");
++ break;
++
++ default:
++ printk(" P%d", map[i]);
++ if (i & 1)
++ pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;
++ break;
++ }
++ }
++ printk(" ]\n");
++
++ if (invalid_map)
++ dev_printk(KERN_ERR, &pdev->dev,
++ "invalid MAP value %u\n", map_value);
++
++ hpriv->map = map;
++ hpriv->map_db = map_db;
++}
++
++/**
++ * piix_init_one - Register PIIX ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in piix_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer. We probe for combined mode (sigh),
++ * and then hand over control to libata, for it to do the rest.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_port_info port_info[2];
++ struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
++ struct piix_host_priv *hpriv;
++ unsigned long port_flags;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ /* no hotplugging support (FIXME) */
++ if (!in_module_init)
++ return -ENODEV;
++
++ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
++ if (!hpriv)
++ return -ENOMEM;
++
++ port_info[0] = piix_port_info[ent->driver_data];
++ port_info[1] = piix_port_info[ent->driver_data];
++ port_info[0].private_data = hpriv;
++ port_info[1].private_data = hpriv;
++
++ port_flags = port_info[0].flags;
++
++ if (port_flags & PIIX_FLAG_AHCI) {
++ u8 tmp;
++ pci_read_config_byte(pdev, PIIX_SCC, &tmp);
++ if (tmp == PIIX_AHCI_DEVICE) {
++ int rc = piix_disable_ahci(pdev);
++ if (rc)
++ return rc;
++ }
++ }
++
++ /* Initialize SATA map */
++ if (port_flags & ATA_FLAG_SATA) {
++ piix_init_sata_map(pdev, port_info,
++ piix_map_db_table[ent->driver_data]);
++ piix_init_pcs(pdev, port_info,
++ piix_map_db_table[ent->driver_data]);
++ }
++
++ /* On ICH5, some BIOSen disable the interrupt using the
++ * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
++ * On ICH6, this bit has the same effect, but only when
++ * MSI is disabled (and it is disabled, as we don't use
++ * message-signalled interrupts currently).
++ */
++ if (port_flags & PIIX_FLAG_CHECKINTR)
++ pci_intx(pdev, 1);
++
++ if (piix_check_450nx_errata(pdev)) {
++ /* This writes into the master table but it does not
++ really matter for this errata as we will apply it to
++ all the PIIX devices on the board */
++ port_info[0].mwdma_mask = 0;
++ port_info[0].udma_mask = 0;
++ port_info[1].mwdma_mask = 0;
++ port_info[1].udma_mask = 0;
++ }
++ return ata_pci_init_one(pdev, ppinfo, 2);
++}
++
++static void piix_host_stop(struct ata_host *host)
++{
++ struct piix_host_priv *hpriv = host->private_data;
++
++ ata_host_stop(host);
++
++ kfree(hpriv);
++}
++
++static int __init piix_init(void)
++{
++ int rc;
++
++ DPRINTK("pci_register_driver\n");
++ rc = pci_register_driver(&piix_pci_driver);
++ if (rc)
++ return rc;
++
++ in_module_init = 0;
++
++ DPRINTK("done\n");
++ return 0;
++}
++
++static void __exit piix_exit(void)
++{
++ pci_unregister_driver(&piix_pci_driver);
++}
++
++module_init(piix_init);
++module_exit(piix_exit);
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+new file mode 100644
+index 0000000..a8fd0c3
+--- /dev/null
++++ b/drivers/ata/libata-core.c
+@@ -0,0 +1,6180 @@
++/*
++ * libata-core.c - helper library for ATA
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
++ * Copyright 2003-2004 Jeff Garzik
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available from http://www.t13.org/ and
++ * http://www.sata-io.org/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/mm.h>
++#include <linux/highmem.h>
++#include <linux/spinlock.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/suspend.h>
++#include <linux/workqueue.h>
++#include <linux/jiffies.h>
++#include <linux/scatterlist.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <asm/byteorder.h>
++
++#include "libata.h"
++
++/* debounce timing parameters in msecs { interval, duration, timeout } */
++const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
++const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
++const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
++
++static unsigned int ata_dev_init_params(struct ata_device *dev,
++ u16 heads, u16 sectors);
++static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
++static void ata_dev_xfermask(struct ata_device *dev);
++
++static unsigned int ata_unique_id = 1;
++static struct workqueue_struct *ata_wq;
++
++struct workqueue_struct *ata_aux_wq;
++
++int atapi_enabled = 1;
++module_param(atapi_enabled, int, 0444);
++MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
++
++int atapi_dmadir = 0;
++module_param(atapi_dmadir, int, 0444);
++MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
++
++int libata_fua = 0;
++module_param_named(fua, libata_fua, int, 0444);
++MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
++
++static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
++module_param(ata_probe_timeout, int, 0444);
++MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
++
++MODULE_AUTHOR("Jeff Garzik");
++MODULE_DESCRIPTION("Library module for ATA devices");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++
++/**
++ * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
++ * @tf: Taskfile to convert
++ * @fis: Buffer into which data will output
++ * @pmp: Port multiplier port
++ *
++ * Converts a standard ATA taskfile to a Serial ATA
++ * FIS structure (Register - Host to Device).
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
++{
++ fis[0] = 0x27; /* Register - Host to Device FIS */
++ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
++ bit 7 indicates Command FIS */
++ fis[2] = tf->command;
++ fis[3] = tf->feature;
++
++ fis[4] = tf->lbal;
++ fis[5] = tf->lbam;
++ fis[6] = tf->lbah;
++ fis[7] = tf->device;
++
++ fis[8] = tf->hob_lbal;
++ fis[9] = tf->hob_lbam;
++ fis[10] = tf->hob_lbah;
++ fis[11] = tf->hob_feature;
++
++ fis[12] = tf->nsect;
++ fis[13] = tf->hob_nsect;
++ fis[14] = 0;
++ fis[15] = tf->ctl;
++
++ fis[16] = 0;
++ fis[17] = 0;
++ fis[18] = 0;
++ fis[19] = 0;
++}
++
++/**
++ * ata_tf_from_fis - Convert SATA FIS to ATA taskfile
++ * @fis: Buffer from which data will be input
++ * @tf: Taskfile to output
++ *
++ * Converts a serial ATA FIS structure to a standard ATA taskfile.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
++{
++ tf->command = fis[2]; /* status */
++ tf->feature = fis[3]; /* error */
++
++ tf->lbal = fis[4];
++ tf->lbam = fis[5];
++ tf->lbah = fis[6];
++ tf->device = fis[7];
++
++ tf->hob_lbal = fis[8];
++ tf->hob_lbam = fis[9];
++ tf->hob_lbah = fis[10];
++
++ tf->nsect = fis[12];
++ tf->hob_nsect = fis[13];
++}
++
++static const u8 ata_rw_cmds[] = {
++ /* pio multi */
++ ATA_CMD_READ_MULTI,
++ ATA_CMD_WRITE_MULTI,
++ ATA_CMD_READ_MULTI_EXT,
++ ATA_CMD_WRITE_MULTI_EXT,
++ 0,
++ 0,
++ 0,
++ ATA_CMD_WRITE_MULTI_FUA_EXT,
++ /* pio */
++ ATA_CMD_PIO_READ,
++ ATA_CMD_PIO_WRITE,
++ ATA_CMD_PIO_READ_EXT,
++ ATA_CMD_PIO_WRITE_EXT,
++ 0,
++ 0,
++ 0,
++ 0,
++ /* dma */
++ ATA_CMD_READ,
++ ATA_CMD_WRITE,
++ ATA_CMD_READ_EXT,
++ ATA_CMD_WRITE_EXT,
++ 0,
++ 0,
++ 0,
++ ATA_CMD_WRITE_FUA_EXT
++};
++
++/**
++ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
++ * @qc: command to examine and configure
++ *
++ * Examine the device configuration and tf->flags to calculate
++ * the proper read/write commands and protocol to use.
++ *
++ * LOCKING:
++ * caller.
++ */
++int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
++{
++ struct ata_taskfile *tf = &qc->tf;
++ struct ata_device *dev = qc->dev;
++ u8 cmd;
++
++ int index, fua, lba48, write;
++
++ fua = (tf->flags & ATA_TFLAG_FUA) ? 4 : 0;
++ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
++ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
++
++ if (dev->flags & ATA_DFLAG_PIO) {
++ tf->protocol = ATA_PROT_PIO;
++ index = dev->multi_count ? 0 : 8;
++ } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) {
++ /* Unable to use DMA due to host limitation */
++ tf->protocol = ATA_PROT_PIO;
++ index = dev->multi_count ? 0 : 8;
++ } else {
++ tf->protocol = ATA_PROT_DMA;
++ index = 16;
++ }
++
++ cmd = ata_rw_cmds[index + fua + lba48 + write];
++ if (cmd) {
++ tf->command = cmd;
++ return 0;
++ }
++ return -1;
++}
++
++/**
++ * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
++ * @pio_mask: pio_mask
++ * @mwdma_mask: mwdma_mask
++ * @udma_mask: udma_mask
++ *
++ * Pack @pio_mask, @mwdma_mask and @udma_mask into a single
++ * unsigned int xfer_mask.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Packed xfer_mask.
++ */
++static unsigned int ata_pack_xfermask(unsigned int pio_mask,
++ unsigned int mwdma_mask,
++ unsigned int udma_mask)
++{
++ return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
++ ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
++ ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
++}
++
++/**
++ * ata_unpack_xfermask - Unpack xfer_mask into pio, mwdma and udma masks
++ * @xfer_mask: xfer_mask to unpack
++ * @pio_mask: resulting pio_mask
++ * @mwdma_mask: resulting mwdma_mask
++ * @udma_mask: resulting udma_mask
++ *
++ * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
++ * Any NULL distination masks will be ignored.
++ */
++static void ata_unpack_xfermask(unsigned int xfer_mask,
++ unsigned int *pio_mask,
++ unsigned int *mwdma_mask,
++ unsigned int *udma_mask)
++{
++ if (pio_mask)
++ *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO;
++ if (mwdma_mask)
++ *mwdma_mask = (xfer_mask & ATA_MASK_MWDMA) >> ATA_SHIFT_MWDMA;
++ if (udma_mask)
++ *udma_mask = (xfer_mask & ATA_MASK_UDMA) >> ATA_SHIFT_UDMA;
++}
++
++static const struct ata_xfer_ent {
++ int shift, bits;
++ u8 base;
++} ata_xfer_tbl[] = {
++ { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
++ { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
++ { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
++ { -1, },
++};
++
++/**
++ * ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
++ * @xfer_mask: xfer_mask of interest
++ *
++ * Return matching XFER_* value for @xfer_mask. Only the highest
++ * bit of @xfer_mask is considered.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Matching XFER_* value, 0 if no match found.
++ */
++static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
++{
++ int highbit = fls(xfer_mask) - 1;
++ const struct ata_xfer_ent *ent;
++
++ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
++ if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
++ return ent->base + highbit - ent->shift;
++ return 0;
++}
++
++/**
++ * ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
++ * @xfer_mode: XFER_* of interest
++ *
++ * Return matching xfer_mask for @xfer_mode.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Matching xfer_mask, 0 if no match found.
++ */
++static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
++{
++ const struct ata_xfer_ent *ent;
++
++ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
++ if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
++ return 1 << (ent->shift + xfer_mode - ent->base);
++ return 0;
++}
++
++/**
++ * ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
++ * @xfer_mode: XFER_* of interest
++ *
++ * Return matching xfer_shift for @xfer_mode.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Matching xfer_shift, -1 if no match found.
++ */
++static int ata_xfer_mode2shift(unsigned int xfer_mode)
++{
++ const struct ata_xfer_ent *ent;
++
++ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
++ if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
++ return ent->shift;
++ return -1;
++}
++
++/**
++ * ata_mode_string - convert xfer_mask to string
++ * @xfer_mask: mask of bits supported; only highest bit counts.
++ *
++ * Determine string which represents the highest speed
++ * (highest bit in @modemask).
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Constant C string representing highest speed listed in
++ * @mode_mask, or the constant C string "<n/a>".
++ */
++static const char *ata_mode_string(unsigned int xfer_mask)
++{
++ static const char * const xfer_mode_str[] = {
++ "PIO0",
++ "PIO1",
++ "PIO2",
++ "PIO3",
++ "PIO4",
++ "PIO5",
++ "PIO6",
++ "MWDMA0",
++ "MWDMA1",
++ "MWDMA2",
++ "MWDMA3",
++ "MWDMA4",
++ "UDMA/16",
++ "UDMA/25",
++ "UDMA/33",
++ "UDMA/44",
++ "UDMA/66",
++ "UDMA/100",
++ "UDMA/133",
++ "UDMA7",
++ };
++ int highbit;
++
++ highbit = fls(xfer_mask) - 1;
++ if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
++ return xfer_mode_str[highbit];
++ return "<n/a>";
++}
++
++static const char *sata_spd_string(unsigned int spd)
++{
++ static const char * const spd_str[] = {
++ "1.5 Gbps",
++ "3.0 Gbps",
++ };
++
++ if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
++ return "<unknown>";
++ return spd_str[spd - 1];
++}
++
++void ata_dev_disable(struct ata_device *dev)
++{
++ if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
++ ata_dev_printk(dev, KERN_WARNING, "disabled\n");
++ dev->class++;
++ }
++}
++
++/**
++ * ata_pio_devchk - PATA device presence detection
++ * @ap: ATA channel to examine
++ * @device: Device to examine (starting at zero)
++ *
++ * This technique was originally described in
++ * Hale Landis's ATADRVR (www.ata-atapi.com), and
++ * later found its way into the ATA/ATAPI spec.
++ *
++ * Write a pattern to the ATA shadow registers,
++ * and if a device is present, it will respond by
++ * correctly storing and echoing back the
++ * ATA shadow register contents.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++static unsigned int ata_pio_devchk(struct ata_port *ap,
++ unsigned int device)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ u8 nsect, lbal;
++
++ ap->ops->dev_select(ap, device);
++
++ outb(0x55, ioaddr->nsect_addr);
++ outb(0xaa, ioaddr->lbal_addr);
++
++ outb(0xaa, ioaddr->nsect_addr);
++ outb(0x55, ioaddr->lbal_addr);
++
++ outb(0x55, ioaddr->nsect_addr);
++ outb(0xaa, ioaddr->lbal_addr);
++
++ nsect = inb(ioaddr->nsect_addr);
++ lbal = inb(ioaddr->lbal_addr);
++
++ if ((nsect == 0x55) && (lbal == 0xaa))
++ return 1; /* we found a device */
++
++ return 0; /* nothing found */
++}
++
++/**
++ * ata_mmio_devchk - PATA device presence detection
++ * @ap: ATA channel to examine
++ * @device: Device to examine (starting at zero)
++ *
++ * This technique was originally described in
++ * Hale Landis's ATADRVR (www.ata-atapi.com), and
++ * later found its way into the ATA/ATAPI spec.
++ *
++ * Write a pattern to the ATA shadow registers,
++ * and if a device is present, it will respond by
++ * correctly storing and echoing back the
++ * ATA shadow register contents.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++static unsigned int ata_mmio_devchk(struct ata_port *ap,
++ unsigned int device)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ u8 nsect, lbal;
++
++ ap->ops->dev_select(ap, device);
++
++ writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
++ writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
++
++ writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
++ writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
++
++ writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
++ writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
++
++ nsect = readb((void __iomem *) ioaddr->nsect_addr);
++ lbal = readb((void __iomem *) ioaddr->lbal_addr);
++
++ if ((nsect == 0x55) && (lbal == 0xaa))
++ return 1; /* we found a device */
++
++ return 0; /* nothing found */
++}
++
++/**
++ * ata_devchk - PATA device presence detection
++ * @ap: ATA channel to examine
++ * @device: Device to examine (starting at zero)
++ *
++ * Dispatch ATA device presence detection, depending
++ * on whether we are using PIO or MMIO to talk to the
++ * ATA shadow registers.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++static unsigned int ata_devchk(struct ata_port *ap,
++ unsigned int device)
++{
++ if (ap->flags & ATA_FLAG_MMIO)
++ return ata_mmio_devchk(ap, device);
++ return ata_pio_devchk(ap, device);
++}
++
++/**
++ * ata_dev_classify - determine device type based on ATA-spec signature
++ * @tf: ATA taskfile register set for device to be identified
++ *
++ * Determine from taskfile register contents whether a device is
++ * ATA or ATAPI, as per "Signature and persistence" section
++ * of ATA/PI spec (volume 1, sect 5.14).
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
++ * the event of failure.
++ */
++
++unsigned int ata_dev_classify(const struct ata_taskfile *tf)
++{
++ /* Apple's open source Darwin code hints that some devices only
++ * put a proper signature into the LBA mid/high registers,
++ * So, we only check those. It's sufficient for uniqueness.
++ */
++
++ if (((tf->lbam == 0) && (tf->lbah == 0)) ||
++ ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
++ DPRINTK("found ATA device by sig\n");
++ return ATA_DEV_ATA;
++ }
++
++ if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
++ ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
++ DPRINTK("found ATAPI device by sig\n");
++ return ATA_DEV_ATAPI;
++ }
++
++ DPRINTK("unknown device\n");
++ return ATA_DEV_UNKNOWN;
++}
++
++/**
++ * ata_dev_try_classify - Parse returned ATA device signature
++ * @ap: ATA channel to examine
++ * @device: Device to examine (starting at zero)
++ * @r_err: Value of error register on completion
++ *
++ * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
++ * an ATA/ATAPI-defined set of values is placed in the ATA
++ * shadow registers, indicating the results of device detection
++ * and diagnostics.
++ *
++ * Select the ATA device, and read the values from the ATA shadow
++ * registers. Then parse according to the Error register value,
++ * and the spec-defined values examined by ata_dev_classify().
++ *
++ * LOCKING:
++ * caller.
++ *
++ * RETURNS:
++ * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
++ */
++
++static unsigned int
++ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
++{
++ struct ata_taskfile tf;
++ unsigned int class;
++ u8 err;
++
++ ap->ops->dev_select(ap, device);
++
++ memset(&tf, 0, sizeof(tf));
++
++ ap->ops->tf_read(ap, &tf);
++ err = tf.feature;
++ if (r_err)
++ *r_err = err;
++
++ /* see if device passed diags: if master then continue and warn later */
++ if (err == 0 && device == 0)
++ /* diagnostic fail : do nothing _YET_ */
++ ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
++ else if (err == 1)
++ /* do nothing */ ;
++ else if ((device == 0) && (err == 0x81))
++ /* do nothing */ ;
++ else
++ return ATA_DEV_NONE;
++
++ /* determine if device is ATA or ATAPI */
++ class = ata_dev_classify(&tf);
++
++ if (class == ATA_DEV_UNKNOWN)
++ return ATA_DEV_NONE;
++ if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
++ return ATA_DEV_NONE;
++ return class;
++}
++
++/**
++ * ata_id_string - Convert IDENTIFY DEVICE page into string
++ * @id: IDENTIFY DEVICE results we will examine
++ * @s: string into which data is output
++ * @ofs: offset into identify device page
++ * @len: length of string to return. must be an even number.
++ *
++ * The strings in the IDENTIFY DEVICE page are broken up into
++ * 16-bit chunks. Run through the string, and output each
++ * 8-bit chunk linearly, regardless of platform.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++void ata_id_string(const u16 *id, unsigned char *s,
++ unsigned int ofs, unsigned int len)
++{
++ unsigned int c;
++
++ while (len > 0) {
++ c = id[ofs] >> 8;
++ *s = c;
++ s++;
++
++ c = id[ofs] & 0xff;
++ *s = c;
++ s++;
++
++ ofs++;
++ len -= 2;
++ }
++}
++
++/**
++ * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
++ * @id: IDENTIFY DEVICE results we will examine
++ * @s: string into which data is output
++ * @ofs: offset into identify device page
++ * @len: length of string to return. must be an odd number.
++ *
++ * This function is identical to ata_id_string except that it
++ * trims trailing spaces and terminates the resulting string with
++ * null. @len must be actual maximum length (even number) + 1.
++ *
++ * LOCKING:
++ * caller.
++ */
++void ata_id_c_string(const u16 *id, unsigned char *s,
++ unsigned int ofs, unsigned int len)
++{
++ unsigned char *p;
++
++ WARN_ON(!(len & 1));
++
++ ata_id_string(id, s, ofs, len - 1);
++
++ p = s + strnlen(s, len - 1);
++ while (p > s && p[-1] == ' ')
++ p--;
++ *p = '\0';
++}
++
++static u64 ata_id_n_sectors(const u16 *id)
++{
++ if (ata_id_has_lba(id)) {
++ if (ata_id_has_lba48(id))
++ return ata_id_u64(id, 100);
++ else
++ return ata_id_u32(id, 60);
++ } else {
++ if (ata_id_current_chs_valid(id))
++ return ata_id_u32(id, 57);
++ else
++ return id[1] * id[3] * id[6];
++ }
++}
++
++/**
++ * ata_noop_dev_select - Select device 0/1 on ATA bus
++ * @ap: ATA channel to manipulate
++ * @device: ATA device (numbered from zero) to select
++ *
++ * This function performs no actual function.
++ *
++ * May be used as the dev_select() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * caller.
++ */
++void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
++{
++}
++
++
++/**
++ * ata_std_dev_select - Select device 0/1 on ATA bus
++ * @ap: ATA channel to manipulate
++ * @device: ATA device (numbered from zero) to select
++ *
++ * Use the method defined in the ATA specification to
++ * make either device 0, or device 1, active on the
++ * ATA channel. Works with both PIO and MMIO.
++ *
++ * May be used as the dev_select() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++void ata_std_dev_select (struct ata_port *ap, unsigned int device)
++{
++ u8 tmp;
++
++ if (device == 0)
++ tmp = ATA_DEVICE_OBS;
++ else
++ tmp = ATA_DEVICE_OBS | ATA_DEV1;
++
++ if (ap->flags & ATA_FLAG_MMIO) {
++ writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
++ } else {
++ outb(tmp, ap->ioaddr.device_addr);
++ }
++ ata_pause(ap); /* needed; also flushes, for mmio */
++}
++
++/**
++ * ata_dev_select - Select device 0/1 on ATA bus
++ * @ap: ATA channel to manipulate
++ * @device: ATA device (numbered from zero) to select
++ * @wait: non-zero to wait for Status register BSY bit to clear
++ * @can_sleep: non-zero if context allows sleeping
++ *
++ * Use the method defined in the ATA specification to
++ * make either device 0, or device 1, active on the
++ * ATA channel.
++ *
++ * This is a high-level version of ata_std_dev_select(),
++ * which additionally provides the services of inserting
++ * the proper pauses and status polling, where needed.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++void ata_dev_select(struct ata_port *ap, unsigned int device,
++ unsigned int wait, unsigned int can_sleep)
++{
++ if (ata_msg_probe(ap))
++ ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
++ "device %u, wait %u\n", ap->id, device, wait);
++
++ if (wait)
++ ata_wait_idle(ap);
++
++ ap->ops->dev_select(ap, device);
++
++ if (wait) {
++ if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
++ msleep(150);
++ ata_wait_idle(ap);
++ }
++}
++
++/**
++ * ata_dump_id - IDENTIFY DEVICE info debugging output
++ * @id: IDENTIFY DEVICE page to dump
++ *
++ * Dump selected 16-bit words from the given IDENTIFY DEVICE
++ * page.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++static inline void ata_dump_id(const u16 *id)
++{
++ DPRINTK("49==0x%04x "
++ "53==0x%04x "
++ "63==0x%04x "
++ "64==0x%04x "
++ "75==0x%04x \n",
++ id[49],
++ id[53],
++ id[63],
++ id[64],
++ id[75]);
++ DPRINTK("80==0x%04x "
++ "81==0x%04x "
++ "82==0x%04x "
++ "83==0x%04x "
++ "84==0x%04x \n",
++ id[80],
++ id[81],
++ id[82],
++ id[83],
++ id[84]);
++ DPRINTK("88==0x%04x "
++ "93==0x%04x\n",
++ id[88],
++ id[93]);
++}
++
++/**
++ * ata_id_xfermask - Compute xfermask from the given IDENTIFY data
++ * @id: IDENTIFY data to compute xfer mask from
++ *
++ * Compute the xfermask for this device. This is not as trivial
++ * as it seems if we must consider early devices correctly.
++ *
++ * FIXME: pre IDE drive timing (do we care ?).
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Computed xfermask
++ */
++static unsigned int ata_id_xfermask(const u16 *id)
++{
++ unsigned int pio_mask, mwdma_mask, udma_mask;
++
++ /* Usual case. Word 53 indicates word 64 is valid */
++ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
++ pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
++ pio_mask <<= 3;
++ pio_mask |= 0x7;
++ } else {
++ /* If word 64 isn't valid then Word 51 high byte holds
++ * the PIO timing number for the maximum. Turn it into
++ * a mask.
++ */
++ u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF;
++ if (mode < 5) /* Valid PIO range */
++ pio_mask = (2 << mode) - 1;
++ else
++ pio_mask = 1;
++
++ /* But wait.. there's more. Design your standards by
++ * committee and you too can get a free iordy field to
++ * process. However its the speeds not the modes that
++ * are supported... Note drivers using the timing API
++ * will get this right anyway
++ */
++ }
++
++ mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
++
++ if (ata_id_is_cfa(id)) {
++ /*
++ * Process compact flash extended modes
++ */
++ int pio = id[163] & 0x7;
++ int dma = (id[163] >> 3) & 7;
++
++ if (pio)
++ pio_mask |= (1 << 5);
++ if (pio > 1)
++ pio_mask |= (1 << 6);
++ if (dma)
++ mwdma_mask |= (1 << 3);
++ if (dma > 1)
++ mwdma_mask |= (1 << 4);
++ }
++
++ udma_mask = 0;
++ if (id[ATA_ID_FIELD_VALID] & (1 << 2))
++ udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
++
++ return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
++}
++
++/**
++ * ata_port_queue_task - Queue port_task
++ * @ap: The ata_port to queue port_task for
++ * @fn: workqueue function to be scheduled
++ * @data: data value to pass to workqueue function
++ * @delay: delay time for workqueue function
++ *
++ * Schedule @fn(@data) for execution after @delay jiffies using
++ * port_task. There is one port_task per port and it's the
++ * user(low level driver)'s responsibility to make sure that only
++ * one task is active at any given time.
++ *
++ * libata core layer takes care of synchronization between
++ * port_task and EH. ata_port_queue_task() may be ignored for EH
++ * synchronization.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
++ unsigned long delay)
++{
++ int rc;
++
++ if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
++ return;
++
++ PREPARE_WORK(&ap->port_task, fn, data);
++
++ if (!delay)
++ rc = queue_work(ata_wq, &ap->port_task);
++ else
++ rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
++
++ /* rc == 0 means that another user is using port task */
++ WARN_ON(rc == 0);
++}
++
++/**
++ * ata_port_flush_task - Flush port_task
++ * @ap: The ata_port to flush port_task for
++ *
++ * After this function completes, port_task is guranteed not to
++ * be running or scheduled.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ */
++void ata_port_flush_task(struct ata_port *ap)
++{
++ unsigned long flags;
++
++ DPRINTK("ENTER\n");
++
++ spin_lock_irqsave(ap->lock, flags);
++ ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ DPRINTK("flush #1\n");
++ flush_workqueue(ata_wq);
++
++ /*
++ * At this point, if a task is running, it's guaranteed to see
++ * the FLUSH flag; thus, it will never queue pio tasks again.
++ * Cancel and flush.
++ */
++ if (!cancel_delayed_work(&ap->port_task)) {
++ if (ata_msg_ctl(ap))
++ ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
++ __FUNCTION__);
++ flush_workqueue(ata_wq);
++ }
++
++ spin_lock_irqsave(ap->lock, flags);
++ ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ if (ata_msg_ctl(ap))
++ ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
++}
++
++void ata_qc_complete_internal(struct ata_queued_cmd *qc)
++{
++ struct completion *waiting = qc->private_data;
++
++ complete(waiting);
++}
++
++/**
++ * ata_exec_internal - execute libata internal command
++ * @dev: Device to which the command is sent
++ * @tf: Taskfile registers for the command and the result
++ * @cdb: CDB for packet command
++ * @dma_dir: Data tranfer direction of the command
++ * @buf: Data buffer of the command
++ * @buflen: Length of data buffer
++ *
++ * Executes libata internal command with timeout. @tf contains
++ * command on entry and result on return. Timeout and error
++ * conditions are reported via return value. No recovery action
++ * is taken after a command times out. It's caller's duty to
++ * clean up after timeout.
++ *
++ * LOCKING:
++ * None. Should be called with kernel context, might sleep.
++ *
++ * RETURNS:
++ * Zero on success, AC_ERR_* mask on failure
++ */
++unsigned ata_exec_internal(struct ata_device *dev,
++ struct ata_taskfile *tf, const u8 *cdb,
++ int dma_dir, void *buf, unsigned int buflen)
++{
++ struct ata_port *ap = dev->ap;
++ u8 command = tf->command;
++ struct ata_queued_cmd *qc;
++ unsigned int tag, preempted_tag;
++ u32 preempted_sactive, preempted_qc_active;
++ DECLARE_COMPLETION_ONSTACK(wait);
++ unsigned long flags;
++ unsigned int err_mask;
++ int rc;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* no internal command while frozen */
++ if (ap->pflags & ATA_PFLAG_FROZEN) {
++ spin_unlock_irqrestore(ap->lock, flags);
++ return AC_ERR_SYSTEM;
++ }
++
++ /* initialize internal qc */
++
++ /* XXX: Tag 0 is used for drivers with legacy EH as some
++ * drivers choke if any other tag is given. This breaks
++ * ata_tag_internal() test for those drivers. Don't use new
++ * EH stuff without converting to it.
++ */
++ if (ap->ops->error_handler)
++ tag = ATA_TAG_INTERNAL;
++ else
++ tag = 0;
++
++ if (test_and_set_bit(tag, &ap->qc_allocated))
++ BUG();
++ qc = __ata_qc_from_tag(ap, tag);
++
++ qc->tag = tag;
++ qc->scsicmd = NULL;
++ qc->ap = ap;
++ qc->dev = dev;
++ ata_qc_reinit(qc);
++
++ preempted_tag = ap->active_tag;
++ preempted_sactive = ap->sactive;
++ preempted_qc_active = ap->qc_active;
++ ap->active_tag = ATA_TAG_POISON;
++ ap->sactive = 0;
++ ap->qc_active = 0;
++
++ /* prepare & issue qc */
++ qc->tf = *tf;
++ if (cdb)
++ memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
++ qc->flags |= ATA_QCFLAG_RESULT_TF;
++ qc->dma_dir = dma_dir;
++ if (dma_dir != DMA_NONE) {
++ ata_sg_init_one(qc, buf, buflen);
++ qc->nsect = buflen / ATA_SECT_SIZE;
++ }
++
++ qc->private_data = &wait;
++ qc->complete_fn = ata_qc_complete_internal;
++
++ ata_qc_issue(qc);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
++
++ ata_port_flush_task(ap);
++
++ if (!rc) {
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* We're racing with irq here. If we lose, the
++ * following test prevents us from completing the qc
++ * twice. If we win, the port is frozen and will be
++ * cleaned up by ->post_internal_cmd().
++ */
++ if (qc->flags & ATA_QCFLAG_ACTIVE) {
++ qc->err_mask |= AC_ERR_TIMEOUT;
++
++ if (ap->ops->error_handler)
++ ata_port_freeze(ap);
++ else
++ ata_qc_complete(qc);
++
++ if (ata_msg_warn(ap))
++ ata_dev_printk(dev, KERN_WARNING,
++ "qc timeout (cmd 0x%x)\n", command);
++ }
++
++ spin_unlock_irqrestore(ap->lock, flags);
++ }
++
++ /* do post_internal_cmd */
++ if (ap->ops->post_internal_cmd)
++ ap->ops->post_internal_cmd(qc);
++
++ if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
++ if (ata_msg_warn(ap))
++ ata_dev_printk(dev, KERN_WARNING,
++ "zero err_mask for failed "
++ "internal command, assuming AC_ERR_OTHER\n");
++ qc->err_mask |= AC_ERR_OTHER;
++ }
++
++ /* finish up */
++ spin_lock_irqsave(ap->lock, flags);
++
++ *tf = qc->result_tf;
++ err_mask = qc->err_mask;
++
++ ata_qc_free(qc);
++ ap->active_tag = preempted_tag;
++ ap->sactive = preempted_sactive;
++ ap->qc_active = preempted_qc_active;
++
++ /* XXX - Some LLDDs (sata_mv) disable port on command failure.
++ * Until those drivers are fixed, we detect the condition
++ * here, fail the command with AC_ERR_SYSTEM and reenable the
++ * port.
++ *
++ * Note that this doesn't change any behavior as internal
++ * command failure results in disabling the device in the
++ * higher layer for LLDDs without new reset/EH callbacks.
++ *
++ * Kill the following code as soon as those drivers are fixed.
++ */
++ if (ap->flags & ATA_FLAG_DISABLED) {
++ err_mask |= AC_ERR_SYSTEM;
++ ata_port_probe(ap);
++ }
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ return err_mask;
++}
++
++/**
++ * ata_do_simple_cmd - execute simple internal command
++ * @dev: Device to which the command is sent
++ * @cmd: Opcode to execute
++ *
++ * Execute a 'simple' command, that only consists of the opcode
++ * 'cmd' itself, without filling any other registers
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, AC_ERR_* mask on failure
++ */
++unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
++{
++ struct ata_taskfile tf;
++
++ ata_tf_init(dev, &tf);
++
++ tf.command = cmd;
++ tf.flags |= ATA_TFLAG_DEVICE;
++ tf.protocol = ATA_PROT_NODATA;
++
++ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
++}
++
++/**
++ * ata_pio_need_iordy - check if iordy needed
++ * @adev: ATA device
++ *
++ * Check if the current speed of the device requires IORDY. Used
++ * by various controllers for chip configuration.
++ */
++
++unsigned int ata_pio_need_iordy(const struct ata_device *adev)
++{
++ int pio;
++ int speed = adev->pio_mode - XFER_PIO_0;
++
++ if (speed < 2)
++ return 0;
++ if (speed > 2)
++ return 1;
++
++ /* If we have no drive specific rule, then PIO 2 is non IORDY */
++
++ if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
++ pio = adev->id[ATA_ID_EIDE_PIO];
++ /* Is the speed faster than the drive allows non IORDY ? */
++ if (pio) {
++ /* This is cycle times not frequency - watch the logic! */
++ if (pio > 240) /* PIO2 is 240nS per cycle */
++ return 1;
++ return 0;
++ }
++ }
++ return 0;
++}
++
++/**
++ * ata_dev_read_id - Read ID data from the specified device
++ * @dev: target device
++ * @p_class: pointer to class of the target device (may be changed)
++ * @post_reset: is this read ID post-reset?
++ * @id: buffer to read IDENTIFY data into
++ *
++ * Read ID data from the specified device. ATA_CMD_ID_ATA is
++ * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
++ * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
++ * for pre-ATA4 drives.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
++ int post_reset, u16 *id)
++{
++ struct ata_port *ap = dev->ap;
++ unsigned int class = *p_class;
++ struct ata_taskfile tf;
++ unsigned int err_mask = 0;
++ const char *reason;
++ int rc;
++
++ if (ata_msg_ctl(ap))
++ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
++ __FUNCTION__, ap->id, dev->devno);
++
++ ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
++
++ retry:
++ ata_tf_init(dev, &tf);
++
++ switch (class) {
++ case ATA_DEV_ATA:
++ tf.command = ATA_CMD_ID_ATA;
++ break;
++ case ATA_DEV_ATAPI:
++ tf.command = ATA_CMD_ID_ATAPI;
++ break;
++ default:
++ rc = -ENODEV;
++ reason = "unsupported class";
++ goto err_out;
++ }
++
++ tf.protocol = ATA_PROT_PIO;
++
++ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
++ id, sizeof(id[0]) * ATA_ID_WORDS);
++ if (err_mask) {
++ rc = -EIO;
++ reason = "I/O error";
++ goto err_out;
++ }
++
++ swap_buf_le16(id, ATA_ID_WORDS);
++
++ /* sanity check */
++ rc = -EINVAL;
++ reason = "device reports illegal type";
++
++ if (class == ATA_DEV_ATA) {
++ if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
++ goto err_out;
++ } else {
++ if (ata_id_is_ata(id))
++ goto err_out;
++ }
++
++ if (post_reset && class == ATA_DEV_ATA) {
++ /*
++ * The exact sequence expected by certain pre-ATA4 drives is:
++ * SRST RESET
++ * IDENTIFY
++ * INITIALIZE DEVICE PARAMETERS
++ * anything else..
++ * Some drives were very specific about that exact sequence.
++ */
++ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
++ err_mask = ata_dev_init_params(dev, id[3], id[6]);
++ if (err_mask) {
++ rc = -EIO;
++ reason = "INIT_DEV_PARAMS failed";
++ goto err_out;
++ }
++
++ /* current CHS translation info (id[53-58]) might be
++ * changed. reread the identify device info.
++ */
++ post_reset = 0;
++ goto retry;
++ }
++ }
++
++ *p_class = class;
++
++ return 0;
++
++ err_out:
++ if (ata_msg_warn(ap))
++ ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
++ "(%s, err_mask=0x%x)\n", reason, err_mask);
++ return rc;
++}
++
++static inline u8 ata_dev_knobble(struct ata_device *dev)
++{
++ return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
++}
++
++static void ata_dev_config_ncq(struct ata_device *dev,
++ char *desc, size_t desc_sz)
++{
++ struct ata_port *ap = dev->ap;
++ int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
++
++ if (!ata_id_has_ncq(dev->id)) {
++ desc[0] = '\0';
++ return;
++ }
++
++ if (ap->flags & ATA_FLAG_NCQ) {
++ hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1);
++ dev->flags |= ATA_DFLAG_NCQ;
++ }
++
++ if (hdepth >= ddepth)
++ snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
++ else
++ snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
++}
++
++static void ata_set_port_max_cmd_len(struct ata_port *ap)
++{
++ int i;
++
++ if (ap->scsi_host) {
++ unsigned int len = 0;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ len = max(len, ap->device[i].cdb_len);
++
++ ap->scsi_host->max_cmd_len = len;
++ }
++}
++
++/**
++ * ata_dev_configure - Configure the specified ATA/ATAPI device
++ * @dev: Target device to configure
++ * @print_info: Enable device info printout
++ *
++ * Configure @dev according to @dev->id. Generic and low-level
++ * driver specific fixups are also applied.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise
++ */
++int ata_dev_configure(struct ata_device *dev, int print_info)
++{
++ struct ata_port *ap = dev->ap;
++ const u16 *id = dev->id;
++ unsigned int xfer_mask;
++ char revbuf[7]; /* XYZ-99\0 */
++ int rc;
++
++ if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
++ ata_dev_printk(dev, KERN_INFO,
++ "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
++ __FUNCTION__, ap->id, dev->devno);
++ return 0;
++ }
++
++ if (ata_msg_probe(ap))
++ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
++ __FUNCTION__, ap->id, dev->devno);
++
++ /* print device capabilities */
++ if (ata_msg_probe(ap))
++ ata_dev_printk(dev, KERN_DEBUG,
++ "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
++ "85:%04x 86:%04x 87:%04x 88:%04x\n",
++ __FUNCTION__,
++ id[49], id[82], id[83], id[84],
++ id[85], id[86], id[87], id[88]);
++
++ /* initialize to-be-configured parameters */
++ dev->flags &= ~ATA_DFLAG_CFG_MASK;
++ dev->max_sectors = 0;
++ dev->cdb_len = 0;
++ dev->n_sectors = 0;
++ dev->cylinders = 0;
++ dev->heads = 0;
++ dev->sectors = 0;
++
++ /*
++ * common ATA, ATAPI feature tests
++ */
++
++ /* find max transfer mode; for printk only */
++ xfer_mask = ata_id_xfermask(id);
++
++ if (ata_msg_probe(ap))
++ ata_dump_id(id);
++
++ /* ATA-specific feature tests */
++ if (dev->class == ATA_DEV_ATA) {
++ if (ata_id_is_cfa(id)) {
++ if (id[162] & 1) /* CPRM may make this media unusable */
++ ata_dev_printk(dev, KERN_WARNING, "ata%u: device %u supports DRM functions and may not be fully accessable.\n",
++ ap->id, dev->devno);
++ snprintf(revbuf, 7, "CFA");
++ }
++ else
++ snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
++
++ dev->n_sectors = ata_id_n_sectors(id);
++
++ if (ata_id_has_lba(id)) {
++ const char *lba_desc;
++ char ncq_desc[20];
++
++ lba_desc = "LBA";
++ dev->flags |= ATA_DFLAG_LBA;
++ if (ata_id_has_lba48(id)) {
++ dev->flags |= ATA_DFLAG_LBA48;
++ lba_desc = "LBA48";
++ }
++
++ /* config NCQ */
++ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
++
++ /* print device info to dmesg */
++ if (ata_msg_drv(ap) && print_info)
++ ata_dev_printk(dev, KERN_INFO, "%s, "
++ "max %s, %Lu sectors: %s %s\n",
++ revbuf,
++ ata_mode_string(xfer_mask),
++ (unsigned long long)dev->n_sectors,
++ lba_desc, ncq_desc);
++ } else {
++ /* CHS */
++
++ /* Default translation */
++ dev->cylinders = id[1];
++ dev->heads = id[3];
++ dev->sectors = id[6];
++
++ if (ata_id_current_chs_valid(id)) {
++ /* Current CHS translation is valid. */
++ dev->cylinders = id[54];
++ dev->heads = id[55];
++ dev->sectors = id[56];
++ }
++
++ /* print device info to dmesg */
++ if (ata_msg_drv(ap) && print_info)
++ ata_dev_printk(dev, KERN_INFO, "%s, "
++ "max %s, %Lu sectors: CHS %u/%u/%u\n",
++ revbuf,
++ ata_mode_string(xfer_mask),
++ (unsigned long long)dev->n_sectors,
++ dev->cylinders, dev->heads,
++ dev->sectors);
++ }
++
++ if (dev->id[59] & 0x100) {
++ dev->multi_count = dev->id[59] & 0xff;
++ if (ata_msg_drv(ap) && print_info)
++ ata_dev_printk(dev, KERN_INFO,
++ "ata%u: dev %u multi count %u\n",
++ ap->id, dev->devno, dev->multi_count);
++ }
++
++ dev->cdb_len = 16;
++ }
++
++ /* ATAPI-specific feature tests */
++ else if (dev->class == ATA_DEV_ATAPI) {
++ char *cdb_intr_string = "";
++
++ rc = atapi_cdb_len(id);
++ if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
++ if (ata_msg_warn(ap))
++ ata_dev_printk(dev, KERN_WARNING,
++ "unsupported CDB len\n");
++ rc = -EINVAL;
++ goto err_out_nosup;
++ }
++ dev->cdb_len = (unsigned int) rc;
++
++ if (ata_id_cdb_intr(dev->id)) {
++ dev->flags |= ATA_DFLAG_CDB_INTR;
++ cdb_intr_string = ", CDB intr";
++ }
++
++ /* print device info to dmesg */
++ if (ata_msg_drv(ap) && print_info)
++ ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
++ ata_mode_string(xfer_mask),
++ cdb_intr_string);
++ }
++
++ if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
++ /* Let the user know. We don't want to disallow opens for
++ rescue purposes, or in case the vendor is just a blithering
++ idiot */
++ if (print_info) {
++ ata_dev_printk(dev, KERN_WARNING,
++"Drive reports diagnostics failure. This may indicate a drive\n");
++ ata_dev_printk(dev, KERN_WARNING,
++"fault or invalid emulation. Contact drive vendor for information.\n");
++ }
++ }
++
++ ata_set_port_max_cmd_len(ap);
++
++ /* limit bridge transfers to udma5, 200 sectors */
++ if (ata_dev_knobble(dev)) {
++ if (ata_msg_drv(ap) && print_info)
++ ata_dev_printk(dev, KERN_INFO,
++ "applying bridge limits\n");
++ dev->udma_mask &= ATA_UDMA5;
++ dev->max_sectors = ATA_MAX_SECTORS;
++ }
++
++ if (ap->ops->dev_config)
++ ap->ops->dev_config(ap, dev);
++
++ if (ata_msg_probe(ap))
++ ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
++ __FUNCTION__, ata_chk_status(ap));
++ return 0;
++
++err_out_nosup:
++ if (ata_msg_probe(ap))
++ ata_dev_printk(dev, KERN_DEBUG,
++ "%s: EXIT, err\n", __FUNCTION__);
++ return rc;
++}
++
++/**
++ * ata_bus_probe - Reset and probe ATA bus
++ * @ap: Bus to probe
++ *
++ * Master ATA bus probing function. Initiates a hardware-dependent
++ * bus reset, then attempts to identify any devices found on
++ * the bus.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * Zero on success, negative errno otherwise.
++ */
++
++int ata_bus_probe(struct ata_port *ap)
++{
++ unsigned int classes[ATA_MAX_DEVICES];
++ int tries[ATA_MAX_DEVICES];
++ int i, rc, down_xfermask;
++ struct ata_device *dev;
++
++ ata_port_probe(ap);
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ tries[i] = ATA_PROBE_MAX_TRIES;
++
++ retry:
++ down_xfermask = 0;
++
++ /* reset and determine device classes */
++ ap->ops->phy_reset(ap);
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++
++ if (!(ap->flags & ATA_FLAG_DISABLED) &&
++ dev->class != ATA_DEV_UNKNOWN)
++ classes[dev->devno] = dev->class;
++ else
++ classes[dev->devno] = ATA_DEV_NONE;
++
++ dev->class = ATA_DEV_UNKNOWN;
++ }
++
++ ata_port_probe(ap);
++
++ /* after the reset the device state is PIO 0 and the controller
++ state is undefined. Record the mode */
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ap->device[i].pio_mode = XFER_PIO_0;
++
++ /* read IDENTIFY page and configure devices */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++
++ if (tries[i])
++ dev->class = classes[i];
++
++ if (!ata_dev_enabled(dev))
++ continue;
++
++ rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
++ if (rc)
++ goto fail;
++
++ rc = ata_dev_configure(dev, 1);
++ if (rc)
++ goto fail;
++ }
++
++ /* configure transfer mode */
++ rc = ata_set_mode(ap, &dev);
++ if (rc) {
++ down_xfermask = 1;
++ goto fail;
++ }
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ if (ata_dev_enabled(&ap->device[i]))
++ return 0;
++
++ /* no device present, disable port */
++ ata_port_disable(ap);
++ ap->ops->port_disable(ap);
++ return -ENODEV;
++
++ fail:
++ switch (rc) {
++ case -EINVAL:
++ case -ENODEV:
++ tries[dev->devno] = 0;
++ break;
++ case -EIO:
++ sata_down_spd_limit(ap);
++ /* fall through */
++ default:
++ tries[dev->devno]--;
++ if (down_xfermask &&
++ ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
++ tries[dev->devno] = 0;
++ }
++
++ if (!tries[dev->devno]) {
++ ata_down_xfermask_limit(dev, 1);
++ ata_dev_disable(dev);
++ }
++
++ goto retry;
++}
++
++/**
++ * ata_port_probe - Mark port as enabled
++ * @ap: Port for which we indicate enablement
++ *
++ * Modify @ap data structure such that the system
++ * thinks that the entire port is enabled.
++ *
++ * LOCKING: host lock, or some other form of
++ * serialization.
++ */
++
++void ata_port_probe(struct ata_port *ap)
++{
++ ap->flags &= ~ATA_FLAG_DISABLED;
++}
++
++/**
++ * sata_print_link_status - Print SATA link status
++ * @ap: SATA port to printk link status about
++ *
++ * This function prints link speed and status of a SATA link.
++ *
++ * LOCKING:
++ * None.
++ */
++static void sata_print_link_status(struct ata_port *ap)
++{
++ u32 sstatus, scontrol, tmp;
++
++ if (sata_scr_read(ap, SCR_STATUS, &sstatus))
++ return;
++ sata_scr_read(ap, SCR_CONTROL, &scontrol);
++
++ if (ata_port_online(ap)) {
++ tmp = (sstatus >> 4) & 0xf;
++ ata_port_printk(ap, KERN_INFO,
++ "SATA link up %s (SStatus %X SControl %X)\n",
++ sata_spd_string(tmp), sstatus, scontrol);
++ } else {
++ ata_port_printk(ap, KERN_INFO,
++ "SATA link down (SStatus %X SControl %X)\n",
++ sstatus, scontrol);
++ }
++}
++
++/**
++ * __sata_phy_reset - Wake/reset a low-level SATA PHY
++ * @ap: SATA port associated with target SATA PHY.
++ *
++ * This function issues commands to standard SATA Sxxx
++ * PHY registers, to wake up the phy (and device), and
++ * clear any reset condition.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ */
++void __sata_phy_reset(struct ata_port *ap)
++{
++ u32 sstatus;
++ unsigned long timeout = jiffies + (HZ * 5);
++
++ if (ap->flags & ATA_FLAG_SATA_RESET) {
++ /* issue phy wake/reset */
++ sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
++ /* Couldn't find anything in SATA I/II specs, but
++ * AHCI-1.1 10.4.2 says at least 1 ms. */
++ mdelay(1);
++ }
++ /* phy wake/clear reset */
++ sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
++
++ /* wait for phy to become ready, if necessary */
++ do {
++ msleep(200);
++ sata_scr_read(ap, SCR_STATUS, &sstatus);
++ if ((sstatus & 0xf) != 1)
++ break;
++ } while (time_before(jiffies, timeout));
++
++ /* print link status */
++ sata_print_link_status(ap);
++
++ /* TODO: phy layer with polling, timeouts, etc. */
++ if (!ata_port_offline(ap))
++ ata_port_probe(ap);
++ else
++ ata_port_disable(ap);
++
++ if (ap->flags & ATA_FLAG_DISABLED)
++ return;
++
++ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
++ ata_port_disable(ap);
++ return;
++ }
++
++ ap->cbl = ATA_CBL_SATA;
++}
++
++/**
++ * sata_phy_reset - Reset SATA bus.
++ * @ap: SATA port associated with target SATA PHY.
++ *
++ * This function resets the SATA bus, and then probes
++ * the bus for devices.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ */
++void sata_phy_reset(struct ata_port *ap)
++{
++ __sata_phy_reset(ap);
++ if (ap->flags & ATA_FLAG_DISABLED)
++ return;
++ ata_bus_reset(ap);
++}
++
++/**
++ * ata_dev_pair - return other device on cable
++ * @adev: device
++ *
++ * Obtain the other device on the same cable, or if none is
++ * present NULL is returned
++ */
++
++struct ata_device *ata_dev_pair(struct ata_device *adev)
++{
++ struct ata_port *ap = adev->ap;
++ struct ata_device *pair = &ap->device[1 - adev->devno];
++ if (!ata_dev_enabled(pair))
++ return NULL;
++ return pair;
++}
++
++/**
++ * ata_port_disable - Disable port.
++ * @ap: Port to be disabled.
++ *
++ * Modify @ap data structure such that the system
++ * thinks that the entire port is disabled, and should
++ * never attempt to probe or communicate with devices
++ * on this port.
++ *
++ * LOCKING: host lock, or some other form of
++ * serialization.
++ */
++
++void ata_port_disable(struct ata_port *ap)
++{
++ ap->device[0].class = ATA_DEV_NONE;
++ ap->device[1].class = ATA_DEV_NONE;
++ ap->flags |= ATA_FLAG_DISABLED;
++}
++
++/**
++ * sata_down_spd_limit - adjust SATA spd limit downward
++ * @ap: Port to adjust SATA spd limit for
++ *
++ * Adjust SATA spd limit of @ap downward. Note that this
++ * function only adjusts the limit. The change must be applied
++ * using sata_set_spd().
++ *
++ * LOCKING:
++ * Inherited from caller.
++ *
++ * RETURNS:
++ * 0 on success, negative errno on failure
++ */
++int sata_down_spd_limit(struct ata_port *ap)
++{
++ u32 sstatus, spd, mask;
++ int rc, highbit;
++
++ rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
++ if (rc)
++ return rc;
++
++ mask = ap->sata_spd_limit;
++ if (mask <= 1)
++ return -EINVAL;
++ highbit = fls(mask) - 1;
++ mask &= ~(1 << highbit);
++
++ spd = (sstatus >> 4) & 0xf;
++ if (spd <= 1)
++ return -EINVAL;
++ spd--;
++ mask &= (1 << spd) - 1;
++ if (!mask)
++ return -EINVAL;
++
++ ap->sata_spd_limit = mask;
++
++ ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
++ sata_spd_string(fls(mask)));
++
++ return 0;
++}
++
++static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
++{
++ u32 spd, limit;
++
++ if (ap->sata_spd_limit == UINT_MAX)
++ limit = 0;
++ else
++ limit = fls(ap->sata_spd_limit);
++
++ spd = (*scontrol >> 4) & 0xf;
++ *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
++
++ return spd != limit;
++}
++
++/**
++ * sata_set_spd_needed - is SATA spd configuration needed
++ * @ap: Port in question
++ *
++ * Test whether the spd limit in SControl matches
++ * @ap->sata_spd_limit. This function is used to determine
++ * whether hardreset is necessary to apply SATA spd
++ * configuration.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ *
++ * RETURNS:
++ * 1 if SATA spd configuration is needed, 0 otherwise.
++ */
++int sata_set_spd_needed(struct ata_port *ap)
++{
++ u32 scontrol;
++
++ if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
++ return 0;
++
++ return __sata_set_spd_needed(ap, &scontrol);
++}
++
++/**
++ * sata_set_spd - set SATA spd according to spd limit
++ * @ap: Port to set SATA spd for
++ *
++ * Set SATA spd of @ap according to sata_spd_limit.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ *
++ * RETURNS:
++ * 0 if spd doesn't need to be changed, 1 if spd has been
++ * changed. Negative errno if SCR registers are inaccessible.
++ */
++int sata_set_spd(struct ata_port *ap)
++{
++ u32 scontrol;
++ int rc;
++
++ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
++ return rc;
++
++ if (!__sata_set_spd_needed(ap, &scontrol))
++ return 0;
++
++ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
++ return rc;
++
++ return 1;
++}
++
++/*
++ * This mode timing computation functionality is ported over from
++ * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
++ */
++/*
++ * PIO 0-4, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
++ * These were taken from ATA/ATAPI-6 standard, rev 0a, except
++ * for UDMA6, which is currently supported only by Maxtor drives.
++ *
++ * For PIO 5/6 MWDMA 3/4 see the CFA specification 3.0.
++ */
++
++static const struct ata_timing ata_timing[] = {
++
++ { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
++ { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
++ { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
++ { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
++
++ { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
++ { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
++ { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
++ { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
++ { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
++
++/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */
++
++ { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
++ { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
++ { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
++
++ { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
++ { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
++ { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
++
++ { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
++ { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
++ { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
++ { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
++
++ { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
++ { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
++ { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
++
++/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */
++
++ { 0xFF }
++};
++
++#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
++#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)
++
++static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
++{
++ q->setup = EZ(t->setup * 1000, T);
++ q->act8b = EZ(t->act8b * 1000, T);
++ q->rec8b = EZ(t->rec8b * 1000, T);
++ q->cyc8b = EZ(t->cyc8b * 1000, T);
++ q->active = EZ(t->active * 1000, T);
++ q->recover = EZ(t->recover * 1000, T);
++ q->cycle = EZ(t->cycle * 1000, T);
++ q->udma = EZ(t->udma * 1000, UT);
++}
++
++void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
++ struct ata_timing *m, unsigned int what)
++{
++ if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup);
++ if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b);
++ if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b);
++ if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
++ if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
++ if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
++ if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
++ if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
++}
++
++static const struct ata_timing* ata_timing_find_mode(unsigned short speed)
++{
++ const struct ata_timing *t;
++
++ for (t = ata_timing; t->mode != speed; t++)
++ if (t->mode == 0xFF)
++ return NULL;
++ return t;
++}
++
++int ata_timing_compute(struct ata_device *adev, unsigned short speed,
++ struct ata_timing *t, int T, int UT)
++{
++ const struct ata_timing *s;
++ struct ata_timing p;
++
++ /*
++ * Find the mode.
++ */
++
++ if (!(s = ata_timing_find_mode(speed)))
++ return -EINVAL;
++
++ memcpy(t, s, sizeof(*s));
++
++ /*
++ * If the drive is an EIDE drive, it can tell us it needs extended
++ * PIO/MW_DMA cycle timing.
++ */
++
++ if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
++ memset(&p, 0, sizeof(p));
++ if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
++ if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
++ else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
++ } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
++ p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
++ }
++ ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
++ }
++
++ /*
++ * Convert the timing to bus clock counts.
++ */
++
++ ata_timing_quantize(t, t, T, UT);
++
++ /*
++ * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
++ * S.M.A.R.T * and some other commands. We have to ensure that the
++ * DMA cycle timing is slower/equal than the fastest PIO timing.
++ */
++
++ if (speed > XFER_PIO_4) {
++ ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
++ ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
++ }
++
++ /*
++ * Lengthen active & recovery time so that cycle time is correct.
++ */
++
++ if (t->act8b + t->rec8b < t->cyc8b) {
++ t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
++ t->rec8b = t->cyc8b - t->act8b;
++ }
++
++ if (t->active + t->recover < t->cycle) {
++ t->active += (t->cycle - (t->active + t->recover)) / 2;
++ t->recover = t->cycle - t->active;
++ }
++
++ return 0;
++}
++
++/**
++ * ata_down_xfermask_limit - adjust dev xfer masks downward
++ * @dev: Device to adjust xfer masks
++ * @force_pio0: Force PIO0
++ *
++ * Adjust xfer masks of @dev downward. Note that this function
++ * does not apply the change. Invoking ata_set_mode() afterwards
++ * will apply the limit.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ *
++ * RETURNS:
++ * 0 on success, negative errno on failure
++ */
++int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
++{
++ unsigned long xfer_mask;
++ int highbit;
++
++ xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
++ dev->udma_mask);
++
++ if (!xfer_mask)
++ goto fail;
++ /* don't gear down to MWDMA from UDMA, go directly to PIO */
++ if (xfer_mask & ATA_MASK_UDMA)
++ xfer_mask &= ~ATA_MASK_MWDMA;
++
++ highbit = fls(xfer_mask) - 1;
++ xfer_mask &= ~(1 << highbit);
++ if (force_pio0)
++ xfer_mask &= 1 << ATA_SHIFT_PIO;
++ if (!xfer_mask)
++ goto fail;
++
++ ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
++ &dev->udma_mask);
++
++ ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
++ ata_mode_string(xfer_mask));
++
++ return 0;
++
++ fail:
++ return -EINVAL;
++}
++
++static int ata_dev_set_mode(struct ata_device *dev)
++{
++ unsigned int err_mask;
++ int rc;
++
++ dev->flags &= ~ATA_DFLAG_PIO;
++ if (dev->xfer_shift == ATA_SHIFT_PIO)
++ dev->flags |= ATA_DFLAG_PIO;
++
++ err_mask = ata_dev_set_xfermode(dev);
++ if (err_mask) {
++ ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
++ "(err_mask=0x%x)\n", err_mask);
++ return -EIO;
++ }
++
++ rc = ata_dev_revalidate(dev, 0);
++ if (rc)
++ return rc;
++
++ DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
++ dev->xfer_shift, (int)dev->xfer_mode);
++
++ ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
++ ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
++ return 0;
++}
++
++/**
++ * ata_set_mode - Program timings and issue SET FEATURES - XFER
++ * @ap: port on which timings will be programmed
++ * @r_failed_dev: out paramter for failed device
++ *
++ * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
++ * ata_set_mode() fails, pointer to the failing device is
++ * returned in @r_failed_dev.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * 0 on success, negative errno otherwise
++ */
++int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
++{
++ struct ata_device *dev;
++ int i, rc = 0, used_dma = 0, found = 0;
++
++ /* has private set_mode? */
++ if (ap->ops->set_mode) {
++ /* FIXME: make ->set_mode handle no device case and
++ * return error code and failing device on failure.
++ */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ if (ata_dev_ready(&ap->device[i])) {
++ ap->ops->set_mode(ap);
++ break;
++ }
++ }
++ return 0;
++ }
++
++ /* step 1: calculate xfer_mask */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ unsigned int pio_mask, dma_mask;
++
++ dev = &ap->device[i];
++
++ if (!ata_dev_enabled(dev))
++ continue;
++
++ ata_dev_xfermask(dev);
++
++ pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
++ dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
++ dev->pio_mode = ata_xfer_mask2mode(pio_mask);
++ dev->dma_mode = ata_xfer_mask2mode(dma_mask);
++
++ found = 1;
++ if (dev->dma_mode)
++ used_dma = 1;
++ }
++ if (!found)
++ goto out;
++
++ /* step 2: always set host PIO timings */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++ if (!ata_dev_enabled(dev))
++ continue;
++
++ if (!dev->pio_mode) {
++ ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ dev->xfer_mode = dev->pio_mode;
++ dev->xfer_shift = ATA_SHIFT_PIO;
++ if (ap->ops->set_piomode)
++ ap->ops->set_piomode(ap, dev);
++ }
++
++ /* step 3: set host DMA timings */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++
++ if (!ata_dev_enabled(dev) || !dev->dma_mode)
++ continue;
++
++ dev->xfer_mode = dev->dma_mode;
++ dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
++ if (ap->ops->set_dmamode)
++ ap->ops->set_dmamode(ap, dev);
++ }
++
++ /* step 4: update devices' xfer mode */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++
++ /* don't udpate suspended devices' xfer mode */
++ if (!ata_dev_ready(dev))
++ continue;
++
++ rc = ata_dev_set_mode(dev);
++ if (rc)
++ goto out;
++ }
++
++ /* Record simplex status. If we selected DMA then the other
++ * host channels are not permitted to do so.
++ */
++ if (used_dma && (ap->host->flags & ATA_HOST_SIMPLEX))
++ ap->host->simplex_claimed = 1;
++
++ /* step5: chip specific finalisation */
++ if (ap->ops->post_set_mode)
++ ap->ops->post_set_mode(ap);
++
++ out:
++ if (rc)
++ *r_failed_dev = dev;
++ return rc;
++}
++
++/**
++ * ata_tf_to_host - issue ATA taskfile to host controller
++ * @ap: port to which command is being issued
++ * @tf: ATA taskfile register set
++ *
++ * Issues ATA taskfile register set to ATA host controller,
++ * with proper synchronization with interrupt handler and
++ * other threads.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static inline void ata_tf_to_host(struct ata_port *ap,
++ const struct ata_taskfile *tf)
++{
++ ap->ops->tf_load(ap, tf);
++ ap->ops->exec_command(ap, tf);
++}
++
++/**
++ * ata_busy_sleep - sleep until BSY clears, or timeout
++ * @ap: port containing status register to be polled
++ * @tmout_pat: impatience timeout
++ * @tmout: overall timeout
++ *
++ * Sleep until ATA Status register bit BSY clears,
++ * or a timeout occurs.
++ *
++ * LOCKING: None.
++ */
++
++unsigned int ata_busy_sleep (struct ata_port *ap,
++ unsigned long tmout_pat, unsigned long tmout)
++{
++ unsigned long timer_start, timeout;
++ u8 status;
++
++ status = ata_busy_wait(ap, ATA_BUSY, 300);
++ timer_start = jiffies;
++ timeout = timer_start + tmout_pat;
++ while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
++ msleep(50);
++ status = ata_busy_wait(ap, ATA_BUSY, 3);
++ }
++
++ if (status & ATA_BUSY)
++ ata_port_printk(ap, KERN_WARNING,
++ "port is slow to respond, please be patient "
++ "(Status 0x%x)\n", status);
++
++ timeout = timer_start + tmout;
++ while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
++ msleep(50);
++ status = ata_chk_status(ap);
++ }
++
++ if (status & ATA_BUSY) {
++ ata_port_printk(ap, KERN_ERR, "port failed to respond "
++ "(%lu secs, Status 0x%x)\n",
++ tmout / HZ, status);
++ return 1;
++ }
++
++ return 0;
++}
++
++static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ unsigned int dev0 = devmask & (1 << 0);
++ unsigned int dev1 = devmask & (1 << 1);
++ unsigned long timeout;
++
++ /* if device 0 was found in ata_devchk, wait for its
++ * BSY bit to clear
++ */
++ if (dev0)
++ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
++
++ /* if device 1 was found in ata_devchk, wait for
++ * register access, then wait for BSY to clear
++ */
++ timeout = jiffies + ATA_TMOUT_BOOT;
++ while (dev1) {
++ u8 nsect, lbal;
++
++ ap->ops->dev_select(ap, 1);
++ if (ap->flags & ATA_FLAG_MMIO) {
++ nsect = readb((void __iomem *) ioaddr->nsect_addr);
++ lbal = readb((void __iomem *) ioaddr->lbal_addr);
++ } else {
++ nsect = inb(ioaddr->nsect_addr);
++ lbal = inb(ioaddr->lbal_addr);
++ }
++ if ((nsect == 1) && (lbal == 1))
++ break;
++ if (time_after(jiffies, timeout)) {
++ dev1 = 0;
++ break;
++ }
++ msleep(50); /* give drive a breather */
++ }
++ if (dev1)
++ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
++
++ /* is all this really necessary? */
++ ap->ops->dev_select(ap, 0);
++ if (dev1)
++ ap->ops->dev_select(ap, 1);
++ if (dev0)
++ ap->ops->dev_select(ap, 0);
++}
++
++static unsigned int ata_bus_softreset(struct ata_port *ap,
++ unsigned int devmask)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++
++ DPRINTK("ata%u: bus reset via SRST\n", ap->id);
++
++ /* software reset. causes dev0 to be selected */
++ if (ap->flags & ATA_FLAG_MMIO) {
++ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
++ udelay(20); /* FIXME: flush */
++ writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
++ udelay(20); /* FIXME: flush */
++ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
++ } else {
++ outb(ap->ctl, ioaddr->ctl_addr);
++ udelay(10);
++ outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
++ udelay(10);
++ outb(ap->ctl, ioaddr->ctl_addr);
++ }
++
++ /* spec mandates ">= 2ms" before checking status.
++ * We wait 150ms, because that was the magic delay used for
++ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
++ * between when the ATA command register is written, and then
++ * status is checked. Because waiting for "a while" before
++ * checking status is fine, post SRST, we perform this magic
++ * delay here as well.
++ *
++ * Old drivers/ide uses the 2mS rule and then waits for ready
++ */
++ msleep(150);
++
++ /* Before we perform post reset processing we want to see if
++ * the bus shows 0xFF because the odd clown forgets the D7
++ * pulldown resistor.
++ */
++ if (ata_check_status(ap) == 0xFF) {
++ ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n");
++ return AC_ERR_OTHER;
++ }
++
++ ata_bus_post_reset(ap, devmask);
++
++ return 0;
++}
++
++/**
++ * ata_bus_reset - reset host port and associated ATA channel
++ * @ap: port to reset
++ *
++ * This is typically the first time we actually start issuing
++ * commands to the ATA channel. We wait for BSY to clear, then
++ * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
++ * result. Determine what devices, if any, are on the channel
++ * by looking at the device 0/1 error register. Look at the signature
++ * stored in each device's taskfile registers, to determine if
++ * the device is ATA or ATAPI.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ * Obtains host lock.
++ *
++ * SIDE EFFECTS:
++ * Sets ATA_FLAG_DISABLED if bus reset fails.
++ */
++
++void ata_bus_reset(struct ata_port *ap)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
++ u8 err;
++ unsigned int dev0, dev1 = 0, devmask = 0;
++
++ DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
++
++ /* determine if device 0/1 are present */
++ if (ap->flags & ATA_FLAG_SATA_RESET)
++ dev0 = 1;
++ else {
++ dev0 = ata_devchk(ap, 0);
++ if (slave_possible)
++ dev1 = ata_devchk(ap, 1);
++ }
++
++ if (dev0)
++ devmask |= (1 << 0);
++ if (dev1)
++ devmask |= (1 << 1);
++
++ /* select device 0 again */
++ ap->ops->dev_select(ap, 0);
++
++ /* issue bus reset */
++ if (ap->flags & ATA_FLAG_SRST)
++ if (ata_bus_softreset(ap, devmask))
++ goto err_out;
++
++ /*
++ * determine by signature whether we have ATA or ATAPI devices
++ */
++ ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
++ if ((slave_possible) && (err != 0x81))
++ ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
++
++ /* re-enable interrupts */
++ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
++ ata_irq_on(ap);
++
++ /* is double-select really necessary? */
++ if (ap->device[1].class != ATA_DEV_NONE)
++ ap->ops->dev_select(ap, 1);
++ if (ap->device[0].class != ATA_DEV_NONE)
++ ap->ops->dev_select(ap, 0);
++
++ /* if no devices were detected, disable this port */
++ if ((ap->device[0].class == ATA_DEV_NONE) &&
++ (ap->device[1].class == ATA_DEV_NONE))
++ goto err_out;
++
++ if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
++ /* set up device control for ATA_FLAG_SATA_RESET */
++ if (ap->flags & ATA_FLAG_MMIO)
++ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
++ else
++ outb(ap->ctl, ioaddr->ctl_addr);
++ }
++
++ DPRINTK("EXIT\n");
++ return;
++
++err_out:
++ ata_port_printk(ap, KERN_ERR, "disabling port\n");
++ ap->ops->port_disable(ap);
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * sata_phy_debounce - debounce SATA phy status
++ * @ap: ATA port to debounce SATA phy status for
++ * @params: timing parameters { interval, duratinon, timeout } in msec
++ *
++ * Make sure SStatus of @ap reaches stable state, determined by
++ * holding the same value where DET is not 1 for @duration polled
++ * every @interval, before @timeout. Timeout constraints the
++ * beginning of the stable state. Because, after hot unplugging,
++ * DET gets stuck at 1 on some controllers, this functions waits
++ * until timeout then returns 0 if DET is stable at 1.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno on failure.
++ */
++int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
++{
++ unsigned long interval_msec = params[0];
++ unsigned long duration = params[1] * HZ / 1000;
++ unsigned long timeout = jiffies + params[2] * HZ / 1000;
++ unsigned long last_jiffies;
++ u32 last, cur;
++ int rc;
++
++ if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
++ return rc;
++ cur &= 0xf;
++
++ last = cur;
++ last_jiffies = jiffies;
++
++ while (1) {
++ msleep(interval_msec);
++ if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
++ return rc;
++ cur &= 0xf;
++
++ /* DET stable? */
++ if (cur == last) {
++ if (cur == 1 && time_before(jiffies, timeout))
++ continue;
++ if (time_after(jiffies, last_jiffies + duration))
++ return 0;
++ continue;
++ }
++
++ /* unstable, start over */
++ last = cur;
++ last_jiffies = jiffies;
++
++ /* check timeout */
++ if (time_after(jiffies, timeout))
++ return -EBUSY;
++ }
++}
++
++/**
++ * sata_phy_resume - resume SATA phy
++ * @ap: ATA port to resume SATA phy for
++ * @params: timing parameters { interval, duratinon, timeout } in msec
++ *
++ * Resume SATA phy of @ap and debounce it.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno on failure.
++ */
++int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
++{
++ u32 scontrol;
++ int rc;
++
++ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
++ return rc;
++
++ scontrol = (scontrol & 0x0f0) | 0x300;
++
++ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
++ return rc;
++
++ /* Some PHYs react badly if SStatus is pounded immediately
++ * after resuming. Delay 200ms before debouncing.
++ */
++ msleep(200);
++
++ return sata_phy_debounce(ap, params);
++}
++
++static void ata_wait_spinup(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ unsigned long end, secs;
++ int rc;
++
++ /* first, debounce phy if SATA */
++ if (ap->cbl == ATA_CBL_SATA) {
++ rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
++
++ /* if debounced successfully and offline, no need to wait */
++ if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
++ return;
++ }
++
++ /* okay, let's give the drive time to spin up */
++ end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
++ secs = ((end - jiffies) + HZ - 1) / HZ;
++
++ if (time_after(jiffies, end))
++ return;
++
++ if (secs > 5)
++ ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
++ "(%lu secs)\n", secs);
++
++ schedule_timeout_uninterruptible(end - jiffies);
++}
++
++/**
++ * ata_std_prereset - prepare for reset
++ * @ap: ATA port to be reset
++ *
++ * @ap is about to be reset. Initialize it.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++int ata_std_prereset(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ const unsigned long *timing = sata_ehc_deb_timing(ehc);
++ int rc;
++
++ /* handle link resume & hotplug spinup */
++ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
++ (ap->flags & ATA_FLAG_HRST_TO_RESUME))
++ ehc->i.action |= ATA_EH_HARDRESET;
++
++ if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
++ (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
++ ata_wait_spinup(ap);
++
++ /* if we're about to do hardreset, nothing more to do */
++ if (ehc->i.action & ATA_EH_HARDRESET)
++ return 0;
++
++ /* if SATA, resume phy */
++ if (ap->cbl == ATA_CBL_SATA) {
++ rc = sata_phy_resume(ap, timing);
++ if (rc && rc != -EOPNOTSUPP) {
++ /* phy resume failed */
++ ata_port_printk(ap, KERN_WARNING, "failed to resume "
++ "link for reset (errno=%d)\n", rc);
++ return rc;
++ }
++ }
++
++ /* Wait for !BSY if the controller can wait for the first D2H
++ * Reg FIS and we don't know that no device is attached.
++ */
++ if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
++ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
++
++ return 0;
++}
++
++/**
++ * ata_std_softreset - reset host port via ATA SRST
++ * @ap: port to reset
++ * @classes: resulting classes of attached devices
++ *
++ * Reset host port using ATA SRST.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
++{
++ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
++ unsigned int devmask = 0, err_mask;
++ u8 err;
++
++ DPRINTK("ENTER\n");
++
++ if (ata_port_offline(ap)) {
++ classes[0] = ATA_DEV_NONE;
++ goto out;
++ }
++
++ /* determine if device 0/1 are present */
++ if (ata_devchk(ap, 0))
++ devmask |= (1 << 0);
++ if (slave_possible && ata_devchk(ap, 1))
++ devmask |= (1 << 1);
++
++ /* select device 0 again */
++ ap->ops->dev_select(ap, 0);
++
++ /* issue bus reset */
++ DPRINTK("about to softreset, devmask=%x\n", devmask);
++ err_mask = ata_bus_softreset(ap, devmask);
++ if (err_mask) {
++ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
++ err_mask);
++ return -EIO;
++ }
++
++ /* determine by signature whether we have ATA or ATAPI devices */
++ classes[0] = ata_dev_try_classify(ap, 0, &err);
++ if (slave_possible && err != 0x81)
++ classes[1] = ata_dev_try_classify(ap, 1, &err);
++
++ out:
++ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
++ return 0;
++}
++
++/**
++ * sata_std_hardreset - reset host port via SATA phy reset
++ * @ap: port to reset
++ * @class: resulting class of attached device
++ *
++ * SATA phy-reset host port using DET bits of SControl register.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ const unsigned long *timing = sata_ehc_deb_timing(ehc);
++ u32 scontrol;
++ int rc;
++
++ DPRINTK("ENTER\n");
++
++ if (sata_set_spd_needed(ap)) {
++ /* SATA spec says nothing about how to reconfigure
++ * spd. To be on the safe side, turn off phy during
++ * reconfiguration. This works for at least ICH7 AHCI
++ * and Sil3124.
++ */
++ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
++ return rc;
++
++ scontrol = (scontrol & 0x0f0) | 0x304;
++
++ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
++ return rc;
++
++ sata_set_spd(ap);
++ }
++
++ /* issue phy wake/reset */
++ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
++ return rc;
++
++ scontrol = (scontrol & 0x0f0) | 0x301;
++
++ if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
++ return rc;
++
++ /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
++ * 10.4.2 says at least 1 ms.
++ */
++ msleep(1);
++
++ /* bring phy back */
++ sata_phy_resume(ap, timing);
++
++ /* TODO: phy layer with polling, timeouts, etc. */
++ if (ata_port_offline(ap)) {
++ *class = ATA_DEV_NONE;
++ DPRINTK("EXIT, link offline\n");
++ return 0;
++ }
++
++ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
++ ata_port_printk(ap, KERN_ERR,
++ "COMRESET failed (device not ready)\n");
++ return -EIO;
++ }
++
++ ap->ops->dev_select(ap, 0); /* probably unnecessary */
++
++ *class = ata_dev_try_classify(ap, 0, NULL);
++
++ DPRINTK("EXIT, class=%u\n", *class);
++ return 0;
++}
++
++/**
++ * ata_std_postreset - standard postreset callback
++ * @ap: the target ata_port
++ * @classes: classes of attached devices
++ *
++ * This function is invoked after a successful reset. Note that
++ * the device might have been reset more than once using
++ * different reset methods before postreset is invoked.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ */
++void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
++{
++ u32 serror;
++
++ DPRINTK("ENTER\n");
++
++ /* print link status */
++ sata_print_link_status(ap);
++
++ /* clear SError */
++ if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
++ sata_scr_write(ap, SCR_ERROR, serror);
++
++ /* re-enable interrupts */
++ if (!ap->ops->error_handler) {
++ /* FIXME: hack. create a hook instead */
++ if (ap->ioaddr.ctl_addr)
++ ata_irq_on(ap);
++ }
++
++ /* is double-select really necessary? */
++ if (classes[0] != ATA_DEV_NONE)
++ ap->ops->dev_select(ap, 1);
++ if (classes[1] != ATA_DEV_NONE)
++ ap->ops->dev_select(ap, 0);
++
++ /* bail out if no device is present */
++ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
++ DPRINTK("EXIT, no device\n");
++ return;
++ }
++
++ /* set up device control */
++ if (ap->ioaddr.ctl_addr) {
++ if (ap->flags & ATA_FLAG_MMIO)
++ writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
++ else
++ outb(ap->ctl, ap->ioaddr.ctl_addr);
++ }
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_dev_same_device - Determine whether new ID matches configured device
++ * @dev: device to compare against
++ * @new_class: class of the new device
++ * @new_id: IDENTIFY page of the new device
++ *
++ * Compare @new_class and @new_id against @dev and determine
++ * whether @dev is the device indicated by @new_class and
++ * @new_id.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 1 if @dev matches @new_class and @new_id, 0 otherwise.
++ */
++static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
++ const u16 *new_id)
++{
++ const u16 *old_id = dev->id;
++ unsigned char model[2][41], serial[2][21];
++ u64 new_n_sectors;
++
++ if (dev->class != new_class) {
++ ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
++ dev->class, new_class);
++ return 0;
++ }
++
++ ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
++ ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
++ ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
++ ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
++ new_n_sectors = ata_id_n_sectors(new_id);
++
++ if (strcmp(model[0], model[1])) {
++ ata_dev_printk(dev, KERN_INFO, "model number mismatch "
++ "'%s' != '%s'\n", model[0], model[1]);
++ return 0;
++ }
++
++ if (strcmp(serial[0], serial[1])) {
++ ata_dev_printk(dev, KERN_INFO, "serial number mismatch "
++ "'%s' != '%s'\n", serial[0], serial[1]);
++ return 0;
++ }
++
++ if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
++ ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
++ "%llu != %llu\n",
++ (unsigned long long)dev->n_sectors,
++ (unsigned long long)new_n_sectors);
++ return 0;
++ }
++
++ return 1;
++}
++
++/**
++ * ata_dev_revalidate - Revalidate ATA device
++ * @dev: device to revalidate
++ * @post_reset: is this revalidation after reset?
++ *
++ * Re-read IDENTIFY page and make sure @dev is still attached to
++ * the port.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, negative errno otherwise
++ */
++int ata_dev_revalidate(struct ata_device *dev, int post_reset)
++{
++ unsigned int class = dev->class;
++ u16 *id = (void *)dev->ap->sector_buf;
++ int rc;
++
++ if (!ata_dev_enabled(dev)) {
++ rc = -ENODEV;
++ goto fail;
++ }
++
++ /* read ID data */
++ rc = ata_dev_read_id(dev, &class, post_reset, id);
++ if (rc)
++ goto fail;
++
++ /* is the device still there? */
++ if (!ata_dev_same_device(dev, class, id)) {
++ rc = -ENODEV;
++ goto fail;
++ }
++
++ memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS);
++
++ /* configure device according to the new ID */
++ rc = ata_dev_configure(dev, 0);
++ if (rc == 0)
++ return 0;
++
++ fail:
++ ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
++ return rc;
++}
++
++static const char * const ata_dma_blacklist [] = {
++ "WDC AC11000H", NULL,
++ "WDC AC22100H", NULL,
++ "WDC AC32500H", NULL,
++ "WDC AC33100H", NULL,
++ "WDC AC31600H", NULL,
++ "WDC AC32100H", "24.09P07",
++ "WDC AC23200L", "21.10N21",
++ "Compaq CRD-8241B", NULL,
++ "CRD-8400B", NULL,
++ "CRD-8480B", NULL,
++ "CRD-8482B", NULL,
++ "CRD-84", NULL,
++ "SanDisk SDP3B", NULL,
++ "SanDisk SDP3B-64", NULL,
++ "SANYO CD-ROM CRD", NULL,
++ "HITACHI CDR-8", NULL,
++ "HITACHI CDR-8335", NULL,
++ "HITACHI CDR-8435", NULL,
++ "Toshiba CD-ROM XM-6202B", NULL,
++ "TOSHIBA CD-ROM XM-1702BC", NULL,
++ "CD-532E-A", NULL,
++ "E-IDE CD-ROM CR-840", NULL,
++ "CD-ROM Drive/F5A", NULL,
++ "WPI CDD-820", NULL,
++ "SAMSUNG CD-ROM SC-148C", NULL,
++ "SAMSUNG CD-ROM SC", NULL,
++ "SanDisk SDP3B-64", NULL,
++ "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,
++ "_NEC DV5800A", NULL,
++ "SAMSUNG CD-ROM SN-124", "N001"
++};
++
++static int ata_strim(char *s, size_t len)
++{
++ len = strnlen(s, len);
++
++ /* ATAPI specifies that empty space is blank-filled; remove blanks */
++ while ((len > 0) && (s[len - 1] == ' ')) {
++ len--;
++ s[len] = 0;
++ }
++ return len;
++}
++
++static int ata_dma_blacklisted(const struct ata_device *dev)
++{
++ unsigned char model_num[40];
++ unsigned char model_rev[16];
++ unsigned int nlen, rlen;
++ int i;
++
++ /* We don't support polling DMA.
++ * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
++ * if the LLDD handles only interrupts in the HSM_ST_LAST state.
++ */
++ if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
++ (dev->flags & ATA_DFLAG_CDB_INTR))
++ return 1;
++
++ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
++ sizeof(model_num));
++ ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
++ sizeof(model_rev));
++ nlen = ata_strim(model_num, sizeof(model_num));
++ rlen = ata_strim(model_rev, sizeof(model_rev));
++
++ for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) {
++ if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) {
++ if (ata_dma_blacklist[i+1] == NULL)
++ return 1;
++ if (!strncmp(ata_dma_blacklist[i], model_rev, rlen))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++/**
++ * ata_dev_xfermask - Compute supported xfermask of the given device
++ * @dev: Device to compute xfermask for
++ *
++ * Compute supported xfermask of @dev and store it in
++ * dev->*_mask. This function is responsible for applying all
++ * known limits including host controller limits, device
++ * blacklist, etc...
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_dev_xfermask(struct ata_device *dev)
++{
++ struct ata_port *ap = dev->ap;
++ struct ata_host *host = ap->host;
++ unsigned long xfer_mask;
++
++ /* controller modes available */
++ xfer_mask = ata_pack_xfermask(ap->pio_mask,
++ ap->mwdma_mask, ap->udma_mask);
++
++ /* Apply cable rule here. Don't apply it early because when
++ * we handle hot plug the cable type can itself change.
++ */
++ if (ap->cbl == ATA_CBL_PATA40)
++ xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
++
++ xfer_mask &= ata_pack_xfermask(dev->pio_mask,
++ dev->mwdma_mask, dev->udma_mask);
++ xfer_mask &= ata_id_xfermask(dev->id);
++
++ /*
++ * CFA Advanced TrueIDE timings are not allowed on a shared
++ * cable
++ */
++ if (ata_dev_pair(dev)) {
++ /* No PIO5 or PIO6 */
++ xfer_mask &= ~(0x03 << (ATA_SHIFT_PIO + 5));
++ /* No MWDMA3 or MWDMA 4 */
++ xfer_mask &= ~(0x03 << (ATA_SHIFT_MWDMA + 3));
++ }
++
++ if (ata_dma_blacklisted(dev)) {
++ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
++ ata_dev_printk(dev, KERN_WARNING,
++ "device is on DMA blacklist, disabling DMA\n");
++ }
++
++ if ((host->flags & ATA_HOST_SIMPLEX) && host->simplex_claimed) {
++ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
++ ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
++ "other device, disabling DMA\n");
++ }
++
++ if (ap->ops->mode_filter)
++ xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
++
++ ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
++ &dev->mwdma_mask, &dev->udma_mask);
++}
++
++/**
++ * ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command
++ * @dev: Device to which command will be sent
++ *
++ * Issue SET FEATURES - XFER MODE command to device @dev
++ * on port @ap.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * 0 on success, AC_ERR_* mask otherwise.
++ */
++
++static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
++{
++ struct ata_taskfile tf;
++ unsigned int err_mask;
++
++ /* set up set-features taskfile */
++ DPRINTK("set features - xfer mode\n");
++
++ ata_tf_init(dev, &tf);
++ tf.command = ATA_CMD_SET_FEATURES;
++ tf.feature = SETFEATURES_XFER;
++ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++ tf.protocol = ATA_PROT_NODATA;
++ tf.nsect = dev->xfer_mode;
++
++ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
++
++ DPRINTK("EXIT, err_mask=%x\n", err_mask);
++ return err_mask;
++}
++
++/**
++ * ata_dev_init_params - Issue INIT DEV PARAMS command
++ * @dev: Device to which command will be sent
++ * @heads: Number of heads (taskfile parameter)
++ * @sectors: Number of sectors (taskfile parameter)
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, AC_ERR_* mask otherwise.
++ */
++static unsigned int ata_dev_init_params(struct ata_device *dev,
++ u16 heads, u16 sectors)
++{
++ struct ata_taskfile tf;
++ unsigned int err_mask;
++
++ /* Number of sectors per track 1-255. Number of heads 1-16 */
++ if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
++ return AC_ERR_INVALID;
++
++ /* set up init dev params taskfile */
++ DPRINTK("init dev params \n");
++
++ ata_tf_init(dev, &tf);
++ tf.command = ATA_CMD_INIT_DEV_PARAMS;
++ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++ tf.protocol = ATA_PROT_NODATA;
++ tf.nsect = sectors;
++ tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
++
++ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
++
++ DPRINTK("EXIT, err_mask=%x\n", err_mask);
++ return err_mask;
++}
++
++/**
++ * ata_sg_clean - Unmap DMA memory associated with command
++ * @qc: Command containing DMA memory to be released
++ *
++ * Unmap all mapped DMA memory associated with this command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_sg_clean(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct scatterlist *sg = qc->__sg;
++ int dir = qc->dma_dir;
++ void *pad_buf = NULL;
++
++ WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
++ WARN_ON(sg == NULL);
++
++ if (qc->flags & ATA_QCFLAG_SINGLE)
++ WARN_ON(qc->n_elem > 1);
++
++ VPRINTK("unmapping %u sg elements\n", qc->n_elem);
++
++ /* if we padded the buffer out to 32-bit bound, and data
++ * xfer direction is from-device, we must copy from the
++ * pad buffer back into the supplied buffer
++ */
++ if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
++ pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
++
++ if (qc->flags & ATA_QCFLAG_SG) {
++ if (qc->n_elem)
++ dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
++ /* restore last sg */
++ sg[qc->orig_n_elem - 1].length += qc->pad_len;
++ if (pad_buf) {
++ struct scatterlist *psg = &qc->pad_sgent;
++ void *addr = kmap_atomic(psg->page, KM_IRQ0);
++ memcpy(addr + psg->offset, pad_buf, qc->pad_len);
++ kunmap_atomic(addr, KM_IRQ0);
++ }
++ } else {
++ if (qc->n_elem)
++ dma_unmap_single(ap->dev,
++ sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
++ dir);
++ /* restore sg */
++ sg->length += qc->pad_len;
++ if (pad_buf)
++ memcpy(qc->buf_virt + sg->length - qc->pad_len,
++ pad_buf, qc->pad_len);
++ }
++
++ qc->flags &= ~ATA_QCFLAG_DMAMAP;
++ qc->__sg = NULL;
++}
++
++/**
++ * ata_fill_sg - Fill PCI IDE PRD table
++ * @qc: Metadata associated with taskfile to be transferred
++ *
++ * Fill PCI IDE PRD (scatter-gather) table with segments
++ * associated with the current disk command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ */
++static void ata_fill_sg(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct scatterlist *sg;
++ unsigned int idx;
++
++ WARN_ON(qc->__sg == NULL);
++ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
++
++ idx = 0;
++ ata_for_each_sg(sg, qc) {
++ u32 addr, offset;
++ u32 sg_len, len;
++
++ /* determine if physical DMA addr spans 64K boundary.
++ * Note h/w doesn't support 64-bit, so we unconditionally
++ * truncate dma_addr_t to u32.
++ */
++ addr = (u32) sg_dma_address(sg);
++ sg_len = sg_dma_len(sg);
++
++ while (sg_len) {
++ offset = addr & 0xffff;
++ len = sg_len;
++ if ((offset + sg_len) > 0x10000)
++ len = 0x10000 - offset;
++
++ ap->prd[idx].addr = cpu_to_le32(addr);
++ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
++
++ idx++;
++ sg_len -= len;
++ addr += len;
++ }
++ }
++
++ if (idx)
++ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
++}
++/**
++ * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
++ * @qc: Metadata associated with taskfile to check
++ *
++ * 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.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS: 0 when ATAPI DMA can be used
++ * nonzero otherwise
++ */
++int ata_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ int rc = 0; /* Assume ATAPI DMA is OK by default */
++
++ if (ap->ops->check_atapi_dma)
++ rc = ap->ops->check_atapi_dma(qc);
++
++ return rc;
++}
++/**
++ * ata_qc_prep - Prepare taskfile for submission
++ * @qc: Metadata associated with taskfile to be prepared
++ *
++ * Prepare ATA taskfile for submission.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_qc_prep(struct ata_queued_cmd *qc)
++{
++ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
++ return;
++
++ ata_fill_sg(qc);
++}
++
++void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
++
++/**
++ * ata_sg_init_one - Associate command with memory buffer
++ * @qc: Command to be associated
++ * @buf: Memory buffer
++ * @buflen: Length of memory buffer, in bytes.
++ *
++ * Initialize the data-related elements of queued_cmd @qc
++ * to point to a single memory buffer, @buf of byte length @buflen.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
++{
++ struct scatterlist *sg;
++
++ qc->flags |= ATA_QCFLAG_SINGLE;
++
++ memset(&qc->sgent, 0, sizeof(qc->sgent));
++ qc->__sg = &qc->sgent;
++ qc->n_elem = 1;
++ qc->orig_n_elem = 1;
++ qc->buf_virt = buf;
++ qc->nbytes = buflen;
++
++ sg = qc->__sg;
++ sg_init_one(sg, buf, buflen);
++}
++
++/**
++ * ata_sg_init - Associate command with scatter-gather table.
++ * @qc: Command to be associated
++ * @sg: Scatter-gather table.
++ * @n_elem: Number of elements in s/g table.
++ *
++ * Initialize the data-related elements of queued_cmd @qc
++ * to point to a scatter-gather table @sg, containing @n_elem
++ * elements.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
++ unsigned int n_elem)
++{
++ qc->flags |= ATA_QCFLAG_SG;
++ qc->__sg = sg;
++ qc->n_elem = n_elem;
++ qc->orig_n_elem = n_elem;
++}
++
++/**
++ * ata_sg_setup_one - DMA-map the memory buffer associated with a command.
++ * @qc: Command with memory buffer to be mapped.
++ *
++ * DMA-map the memory buffer associated with queued_cmd @qc.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, negative on error.
++ */
++
++static int ata_sg_setup_one(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ int dir = qc->dma_dir;
++ struct scatterlist *sg = qc->__sg;
++ dma_addr_t dma_address;
++ int trim_sg = 0;
++
++ /* we must lengthen transfers to end on a 32-bit boundary */
++ qc->pad_len = sg->length & 3;
++ if (qc->pad_len) {
++ void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
++ struct scatterlist *psg = &qc->pad_sgent;
++
++ WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
++
++ memset(pad_buf, 0, ATA_DMA_PAD_SZ);
++
++ if (qc->tf.flags & ATA_TFLAG_WRITE)
++ memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
++ qc->pad_len);
++
++ sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
++ sg_dma_len(psg) = ATA_DMA_PAD_SZ;
++ /* trim sg */
++ sg->length -= qc->pad_len;
++ if (sg->length == 0)
++ trim_sg = 1;
++
++ DPRINTK("padding done, sg->length=%u pad_len=%u\n",
++ sg->length, qc->pad_len);
++ }
++
++ if (trim_sg) {
++ qc->n_elem--;
++ goto skip_map;
++ }
++
++ dma_address = dma_map_single(ap->dev, qc->buf_virt,
++ sg->length, dir);
++ if (dma_mapping_error(dma_address)) {
++ /* restore sg */
++ sg->length += qc->pad_len;
++ return -1;
++ }
++
++ sg_dma_address(sg) = dma_address;
++ sg_dma_len(sg) = sg->length;
++
++skip_map:
++ DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
++ qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
++
++ return 0;
++}
++
++/**
++ * ata_sg_setup - DMA-map the scatter-gather table associated with a command.
++ * @qc: Command with scatter-gather table to be mapped.
++ *
++ * DMA-map the scatter-gather table associated with queued_cmd @qc.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, negative on error.
++ *
++ */
++
++static int ata_sg_setup(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct scatterlist *sg = qc->__sg;
++ struct scatterlist *lsg = &sg[qc->n_elem - 1];
++ int n_elem, pre_n_elem, dir, trim_sg = 0;
++
++ VPRINTK("ENTER, ata%u\n", ap->id);
++ WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
++
++ /* we must lengthen transfers to end on a 32-bit boundary */
++ qc->pad_len = lsg->length & 3;
++ if (qc->pad_len) {
++ void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
++ struct scatterlist *psg = &qc->pad_sgent;
++ unsigned int offset;
++
++ WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
++
++ memset(pad_buf, 0, ATA_DMA_PAD_SZ);
++
++ /*
++ * psg->page/offset are used to copy to-be-written
++ * data in this function or read data in ata_sg_clean.
++ */
++ offset = lsg->offset + lsg->length - qc->pad_len;
++ psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
++ psg->offset = offset_in_page(offset);
++
++ if (qc->tf.flags & ATA_TFLAG_WRITE) {
++ void *addr = kmap_atomic(psg->page, KM_IRQ0);
++ memcpy(pad_buf, addr + psg->offset, qc->pad_len);
++ kunmap_atomic(addr, KM_IRQ0);
++ }
++
++ sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
++ sg_dma_len(psg) = ATA_DMA_PAD_SZ;
++ /* trim last sg */
++ lsg->length -= qc->pad_len;
++ if (lsg->length == 0)
++ trim_sg = 1;
++
++ DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
++ qc->n_elem - 1, lsg->length, qc->pad_len);
++ }
++
++ pre_n_elem = qc->n_elem;
++ if (trim_sg && pre_n_elem)
++ pre_n_elem--;
++
++ if (!pre_n_elem) {
++ n_elem = 0;
++ goto skip_map;
++ }
++
++ dir = qc->dma_dir;
++ n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir);
++ if (n_elem < 1) {
++ /* restore last sg */
++ lsg->length += qc->pad_len;
++ return -1;
++ }
++
++ DPRINTK("%d sg elements mapped\n", n_elem);
++
++skip_map:
++ qc->n_elem = n_elem;
++
++ return 0;
++}
++
++/**
++ * swap_buf_le16 - swap halves of 16-bit words in place
++ * @buf: Buffer to swap
++ * @buf_words: Number of 16-bit words in buffer.
++ *
++ * Swap halves of 16-bit words if needed to convert from
++ * little-endian byte order to native cpu byte order, or
++ * vice-versa.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void swap_buf_le16(u16 *buf, unsigned int buf_words)
++{
++#ifdef __BIG_ENDIAN
++ unsigned int i;
++
++ for (i = 0; i < buf_words; i++)
++ buf[i] = le16_to_cpu(buf[i]);
++#endif /* __BIG_ENDIAN */
++}
++
++/**
++ * ata_mmio_data_xfer - Transfer data by MMIO
++ * @adev: device for this I/O
++ * @buf: data buffer
++ * @buflen: buffer length
++ * @write_data: read/write
++ *
++ * Transfer data from/to the device data register by MMIO.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
++ unsigned int buflen, int write_data)
++{
++ struct ata_port *ap = adev->ap;
++ unsigned int i;
++ unsigned int words = buflen >> 1;
++ u16 *buf16 = (u16 *) buf;
++ void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
++
++ /* Transfer multiple of 2 bytes */
++ if (write_data) {
++ for (i = 0; i < words; i++)
++ writew(le16_to_cpu(buf16[i]), mmio);
++ } else {
++ for (i = 0; i < words; i++)
++ buf16[i] = cpu_to_le16(readw(mmio));
++ }
++
++ /* Transfer trailing 1 byte, if any. */
++ if (unlikely(buflen & 0x01)) {
++ u16 align_buf[1] = { 0 };
++ unsigned char *trailing_buf = buf + buflen - 1;
++
++ if (write_data) {
++ memcpy(align_buf, trailing_buf, 1);
++ writew(le16_to_cpu(align_buf[0]), mmio);
++ } else {
++ align_buf[0] = cpu_to_le16(readw(mmio));
++ memcpy(trailing_buf, align_buf, 1);
++ }
++ }
++}
++
++/**
++ * ata_pio_data_xfer - Transfer data by PIO
++ * @adev: device to target
++ * @buf: data buffer
++ * @buflen: buffer length
++ * @write_data: read/write
++ *
++ * Transfer data from/to the device data register by PIO.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
++ unsigned int buflen, int write_data)
++{
++ struct ata_port *ap = adev->ap;
++ unsigned int words = buflen >> 1;
++
++ /* Transfer multiple of 2 bytes */
++ if (write_data)
++ outsw(ap->ioaddr.data_addr, buf, words);
++ else
++ insw(ap->ioaddr.data_addr, buf, words);
++
++ /* Transfer trailing 1 byte, if any. */
++ if (unlikely(buflen & 0x01)) {
++ u16 align_buf[1] = { 0 };
++ unsigned char *trailing_buf = buf + buflen - 1;
++
++ if (write_data) {
++ memcpy(align_buf, trailing_buf, 1);
++ outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
++ } else {
++ align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
++ memcpy(trailing_buf, align_buf, 1);
++ }
++ }
++}
++
++/**
++ * ata_pio_data_xfer_noirq - Transfer data by PIO
++ * @adev: device to target
++ * @buf: data buffer
++ * @buflen: buffer length
++ * @write_data: read/write
++ *
++ * Transfer data from/to the device data register by PIO. Do the
++ * transfer with interrupts disabled.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
++ unsigned int buflen, int write_data)
++{
++ unsigned long flags;
++ local_irq_save(flags);
++ ata_pio_data_xfer(adev, buf, buflen, write_data);
++ local_irq_restore(flags);
++}
++
++
++/**
++ * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
++ * @qc: Command on going
++ *
++ * Transfer ATA_SECT_SIZE of data from/to the ATA device.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void ata_pio_sector(struct ata_queued_cmd *qc)
++{
++ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
++ struct scatterlist *sg = qc->__sg;
++ struct ata_port *ap = qc->ap;
++ struct page *page;
++ unsigned int offset;
++ unsigned char *buf;
++
++ if (qc->cursect == (qc->nsect - 1))
++ ap->hsm_task_state = HSM_ST_LAST;
++
++ page = sg[qc->cursg].page;
++ offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
++
++ /* get the current page and offset */
++ page = nth_page(page, (offset >> PAGE_SHIFT));
++ offset %= PAGE_SIZE;
++
++ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
++
++ if (PageHighMem(page)) {
++ unsigned long flags;
++
++ /* FIXME: use a bounce buffer */
++ local_irq_save(flags);
++ buf = kmap_atomic(page, KM_IRQ0);
++
++ /* do the actual data transfer */
++ ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
++
++ kunmap_atomic(buf, KM_IRQ0);
++ local_irq_restore(flags);
++ } else {
++ buf = page_address(page);
++ ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
++ }
++
++ qc->cursect++;
++ qc->cursg_ofs++;
++
++ if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
++ qc->cursg++;
++ qc->cursg_ofs = 0;
++ }
++}
++
++/**
++ * ata_pio_sectors - Transfer one or many 512-byte sectors.
++ * @qc: Command on going
++ *
++ * Transfer one or many ATA_SECT_SIZE of data from/to the
++ * ATA device for the DRQ request.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void ata_pio_sectors(struct ata_queued_cmd *qc)
++{
++ if (is_multi_taskfile(&qc->tf)) {
++ /* READ/WRITE MULTIPLE */
++ unsigned int nsect;
++
++ WARN_ON(qc->dev->multi_count == 0);
++
++ nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
++ while (nsect--)
++ ata_pio_sector(qc);
++ } else
++ ata_pio_sector(qc);
++}
++
++/**
++ * atapi_send_cdb - Write CDB bytes to hardware
++ * @ap: Port to which ATAPI device is attached.
++ * @qc: Taskfile currently active
++ *
++ * When device has indicated its readiness to accept
++ * a CDB, this function is called. Send the CDB.
++ *
++ * LOCKING:
++ * caller.
++ */
++
++static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
++{
++ /* send SCSI cdb */
++ DPRINTK("send cdb\n");
++ WARN_ON(qc->dev->cdb_len < 12);
++
++ ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
++ ata_altstatus(ap); /* flush */
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_ATAPI:
++ ap->hsm_task_state = HSM_ST;
++ break;
++ case ATA_PROT_ATAPI_NODATA:
++ ap->hsm_task_state = HSM_ST_LAST;
++ break;
++ case ATA_PROT_ATAPI_DMA:
++ ap->hsm_task_state = HSM_ST_LAST;
++ /* initiate bmdma */
++ ap->ops->bmdma_start(qc);
++ break;
++ }
++}
++
++/**
++ * __atapi_pio_bytes - Transfer data from/to the ATAPI device.
++ * @qc: Command on going
++ * @bytes: number of bytes
++ *
++ * Transfer Transfer data from/to the ATAPI device.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ *
++ */
++
++static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
++{
++ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
++ struct scatterlist *sg = qc->__sg;
++ struct ata_port *ap = qc->ap;
++ struct page *page;
++ unsigned char *buf;
++ unsigned int offset, count;
++
++ if (qc->curbytes + bytes >= qc->nbytes)
++ ap->hsm_task_state = HSM_ST_LAST;
++
++next_sg:
++ if (unlikely(qc->cursg >= qc->n_elem)) {
++ /*
++ * The end of qc->sg is reached and the device expects
++ * more data to transfer. In order not to overrun qc->sg
++ * and fulfill length specified in the byte count register,
++ * - for read case, discard trailing data from the device
++ * - for write case, padding zero data to the device
++ */
++ u16 pad_buf[1] = { 0 };
++ unsigned int words = bytes >> 1;
++ unsigned int i;
++
++ if (words) /* warning if bytes > 1 */
++ ata_dev_printk(qc->dev, KERN_WARNING,
++ "%u bytes trailing data\n", bytes);
++
++ for (i = 0; i < words; i++)
++ ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write);
++
++ ap->hsm_task_state = HSM_ST_LAST;
++ return;
++ }
++
++ sg = &qc->__sg[qc->cursg];
++
++ page = sg->page;
++ offset = sg->offset + qc->cursg_ofs;
++
++ /* get the current page and offset */
++ page = nth_page(page, (offset >> PAGE_SHIFT));
++ offset %= PAGE_SIZE;
++
++ /* don't overrun current sg */
++ count = min(sg->length - qc->cursg_ofs, bytes);
++
++ /* don't cross page boundaries */
++ count = min(count, (unsigned int)PAGE_SIZE - offset);
++
++ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
++
++ if (PageHighMem(page)) {
++ unsigned long flags;
++
++ /* FIXME: use bounce buffer */
++ local_irq_save(flags);
++ buf = kmap_atomic(page, KM_IRQ0);
++
++ /* do the actual data transfer */
++ ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
++
++ kunmap_atomic(buf, KM_IRQ0);
++ local_irq_restore(flags);
++ } else {
++ buf = page_address(page);
++ ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
++ }
++
++ bytes -= count;
++ qc->curbytes += count;
++ qc->cursg_ofs += count;
++
++ if (qc->cursg_ofs == sg->length) {
++ qc->cursg++;
++ qc->cursg_ofs = 0;
++ }
++
++ if (bytes)
++ goto next_sg;
++}
++
++/**
++ * atapi_pio_bytes - Transfer data from/to the ATAPI device.
++ * @qc: Command on going
++ *
++ * Transfer Transfer data from/to the ATAPI device.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void atapi_pio_bytes(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *dev = qc->dev;
++ unsigned int ireason, bc_lo, bc_hi, bytes;
++ int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
++
++ /* Abuse qc->result_tf for temp storage of intermediate TF
++ * here to save some kernel stack usage.
++ * For normal completion, qc->result_tf is not relevant. For
++ * error, qc->result_tf is later overwritten by ata_qc_complete().
++ * So, the correctness of qc->result_tf is not affected.
++ */
++ ap->ops->tf_read(ap, &qc->result_tf);
++ ireason = qc->result_tf.nsect;
++ bc_lo = qc->result_tf.lbam;
++ bc_hi = qc->result_tf.lbah;
++ bytes = (bc_hi << 8) | bc_lo;
++
++ /* shall be cleared to zero, indicating xfer of data */
++ if (ireason & (1 << 0))
++ goto err_out;
++
++ /* make sure transfer direction matches expected */
++ i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
++ if (do_write != i_write)
++ goto err_out;
++
++ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
++
++ __atapi_pio_bytes(qc, bytes);
++
++ return;
++
++err_out:
++ ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n");
++ qc->err_mask |= AC_ERR_HSM;
++ ap->hsm_task_state = HSM_ST_ERR;
++}
++
++/**
++ * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue.
++ * @ap: the target ata_port
++ * @qc: qc on going
++ *
++ * RETURNS:
++ * 1 if ok in workqueue, 0 otherwise.
++ */
++
++static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
++{
++ if (qc->tf.flags & ATA_TFLAG_POLLING)
++ return 1;
++
++ if (ap->hsm_task_state == HSM_ST_FIRST) {
++ if (qc->tf.protocol == ATA_PROT_PIO &&
++ (qc->tf.flags & ATA_TFLAG_WRITE))
++ return 1;
++
++ if (is_atapi_taskfile(&qc->tf) &&
++ !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
++ return 1;
++ }
++
++ return 0;
++}
++
++/**
++ * ata_hsm_qc_complete - finish a qc running on standard HSM
++ * @qc: Command to complete
++ * @in_wq: 1 if called from workqueue, 0 otherwise
++ *
++ * Finish @qc which is running on standard HSM.
++ *
++ * LOCKING:
++ * If @in_wq is zero, spin_lock_irqsave(host lock).
++ * Otherwise, none on entry and grabs host lock.
++ */
++static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
++{
++ struct ata_port *ap = qc->ap;
++ unsigned long flags;
++
++ if (ap->ops->error_handler) {
++ if (in_wq) {
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* EH might have kicked in while host lock is
++ * released.
++ */
++ qc = ata_qc_from_tag(ap, qc->tag);
++ if (qc) {
++ if (likely(!(qc->err_mask & AC_ERR_HSM))) {
++ ata_irq_on(ap);
++ ata_qc_complete(qc);
++ } else
++ ata_port_freeze(ap);
++ }
++
++ spin_unlock_irqrestore(ap->lock, flags);
++ } else {
++ if (likely(!(qc->err_mask & AC_ERR_HSM)))
++ ata_qc_complete(qc);
++ else
++ ata_port_freeze(ap);
++ }
++ } else {
++ if (in_wq) {
++ spin_lock_irqsave(ap->lock, flags);
++ ata_irq_on(ap);
++ ata_qc_complete(qc);
++ spin_unlock_irqrestore(ap->lock, flags);
++ } else
++ ata_qc_complete(qc);
++ }
++
++ ata_altstatus(ap); /* flush */
++}
++
++/**
++ * ata_hsm_move - move the HSM to the next state.
++ * @ap: the target ata_port
++ * @qc: qc on going
++ * @status: current device status
++ * @in_wq: 1 if called from workqueue, 0 otherwise
++ *
++ * RETURNS:
++ * 1 when poll next status needed, 0 otherwise.
++ */
++int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
++ u8 status, int in_wq)
++{
++ unsigned long flags = 0;
++ int poll_next;
++
++ WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
++
++ /* Make sure ata_qc_issue_prot() does not throw things
++ * like DMA polling into the workqueue. Notice that
++ * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
++ */
++ WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
++
++fsm_start:
++ DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
++ ap->id, qc->tf.protocol, ap->hsm_task_state, status);
++
++ switch (ap->hsm_task_state) {
++ case HSM_ST_FIRST:
++ /* Send first data block or PACKET CDB */
++
++ /* If polling, we will stay in the work queue after
++ * sending the data. Otherwise, interrupt handler
++ * takes over after sending the data.
++ */
++ poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
++
++ /* check device status */
++ if (unlikely((status & ATA_DRQ) == 0)) {
++ /* handle BSY=0, DRQ=0 as error */
++ if (likely(status & (ATA_ERR | ATA_DF)))
++ /* device stops HSM for abort/error */
++ qc->err_mask |= AC_ERR_DEV;
++ else
++ /* HSM violation. Let EH handle this */
++ qc->err_mask |= AC_ERR_HSM;
++
++ ap->hsm_task_state = HSM_ST_ERR;
++ goto fsm_start;
++ }
++
++ /* Device should not ask for data transfer (DRQ=1)
++ * when it finds something wrong.
++ * We ignore DRQ here and stop the HSM by
++ * changing hsm_task_state to HSM_ST_ERR and
++ * let the EH abort the command or reset the device.
++ */
++ if (unlikely(status & (ATA_ERR | ATA_DF))) {
++ printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
++ ap->id, status);
++ qc->err_mask |= AC_ERR_HSM;
++ ap->hsm_task_state = HSM_ST_ERR;
++ goto fsm_start;
++ }
++
++ /* Send the CDB (atapi) or the first data block (ata pio out).
++ * During the state transition, interrupt handler shouldn't
++ * be invoked before the data transfer is complete and
++ * hsm_task_state is changed. Hence, the following locking.
++ */
++ if (in_wq)
++ spin_lock_irqsave(ap->lock, flags);
++
++ if (qc->tf.protocol == ATA_PROT_PIO) {
++ /* PIO data out protocol.
++ * send first data block.
++ */
++
++ /* ata_pio_sectors() might change the state
++ * to HSM_ST_LAST. so, the state is changed here
++ * before ata_pio_sectors().
++ */
++ ap->hsm_task_state = HSM_ST;
++ ata_pio_sectors(qc);
++ ata_altstatus(ap); /* flush */
++ } else
++ /* send CDB */
++ atapi_send_cdb(ap, qc);
++
++ if (in_wq)
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* if polling, ata_pio_task() handles the rest.
++ * otherwise, interrupt handler takes over from here.
++ */
++ break;
++
++ case HSM_ST:
++ /* complete command or read/write the data register */
++ if (qc->tf.protocol == ATA_PROT_ATAPI) {
++ /* ATAPI PIO protocol */
++ if ((status & ATA_DRQ) == 0) {
++ /* No more data to transfer or device error.
++ * Device error will be tagged in HSM_ST_LAST.
++ */
++ ap->hsm_task_state = HSM_ST_LAST;
++ goto fsm_start;
++ }
++
++ /* Device should not ask for data transfer (DRQ=1)
++ * when it finds something wrong.
++ * We ignore DRQ here and stop the HSM by
++ * changing hsm_task_state to HSM_ST_ERR and
++ * let the EH abort the command or reset the device.
++ */
++ if (unlikely(status & (ATA_ERR | ATA_DF))) {
++ printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
++ ap->id, status);
++ qc->err_mask |= AC_ERR_HSM;
++ ap->hsm_task_state = HSM_ST_ERR;
++ goto fsm_start;
++ }
++
++ atapi_pio_bytes(qc);
++
++ if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
++ /* bad ireason reported by device */
++ goto fsm_start;
++
++ } else {
++ /* ATA PIO protocol */
++ if (unlikely((status & ATA_DRQ) == 0)) {
++ /* handle BSY=0, DRQ=0 as error */
++ if (likely(status & (ATA_ERR | ATA_DF)))
++ /* device stops HSM for abort/error */
++ qc->err_mask |= AC_ERR_DEV;
++ else
++ /* HSM violation. Let EH handle this */
++ qc->err_mask |= AC_ERR_HSM;
++
++ ap->hsm_task_state = HSM_ST_ERR;
++ goto fsm_start;
++ }
++
++ /* For PIO reads, some devices may ask for
++ * data transfer (DRQ=1) alone with ERR=1.
++ * We respect DRQ here and transfer one
++ * block of junk data before changing the
++ * hsm_task_state to HSM_ST_ERR.
++ *
++ * For PIO writes, ERR=1 DRQ=1 doesn't make
++ * sense since the data block has been
++ * transferred to the device.
++ */
++ if (unlikely(status & (ATA_ERR | ATA_DF))) {
++ /* data might be corrputed */
++ qc->err_mask |= AC_ERR_DEV;
++
++ if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
++ ata_pio_sectors(qc);
++ ata_altstatus(ap);
++ status = ata_wait_idle(ap);
++ }
++
++ if (status & (ATA_BUSY | ATA_DRQ))
++ qc->err_mask |= AC_ERR_HSM;
++
++ /* ata_pio_sectors() might change the
++ * state to HSM_ST_LAST. so, the state
++ * is changed after ata_pio_sectors().
++ */
++ ap->hsm_task_state = HSM_ST_ERR;
++ goto fsm_start;
++ }
++
++ ata_pio_sectors(qc);
++
++ if (ap->hsm_task_state == HSM_ST_LAST &&
++ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
++ /* all data read */
++ ata_altstatus(ap);
++ status = ata_wait_idle(ap);
++ goto fsm_start;
++ }
++ }
++
++ ata_altstatus(ap); /* flush */
++ poll_next = 1;
++ break;
++
++ case HSM_ST_LAST:
++ if (unlikely(!ata_ok(status))) {
++ qc->err_mask |= __ac_err_mask(status);
++ ap->hsm_task_state = HSM_ST_ERR;
++ goto fsm_start;
++ }
++
++ /* no more data to transfer */
++ DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
++ ap->id, qc->dev->devno, status);
++
++ WARN_ON(qc->err_mask);
++
++ ap->hsm_task_state = HSM_ST_IDLE;
++
++ /* complete taskfile transaction */
++ ata_hsm_qc_complete(qc, in_wq);
++
++ poll_next = 0;
++ break;
++
++ case HSM_ST_ERR:
++ /* make sure qc->err_mask is available to
++ * know what's wrong and recover
++ */
++ WARN_ON(qc->err_mask == 0);
++
++ ap->hsm_task_state = HSM_ST_IDLE;
++
++ /* complete taskfile transaction */
++ ata_hsm_qc_complete(qc, in_wq);
++
++ poll_next = 0;
++ break;
++ default:
++ poll_next = 0;
++ BUG();
++ }
++
++ return poll_next;
++}
++
++static void ata_pio_task(void *_data)
++{
++ struct ata_queued_cmd *qc = _data;
++ struct ata_port *ap = qc->ap;
++ u8 status;
++ int poll_next;
++
++fsm_start:
++ WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
++
++ /*
++ * This is purely heuristic. This is a fast path.
++ * Sometimes when we enter, BSY will be cleared in
++ * a chk-status or two. If not, the drive is probably seeking
++ * or something. Snooze for a couple msecs, then
++ * chk-status again. If still busy, queue delayed work.
++ */
++ status = ata_busy_wait(ap, ATA_BUSY, 5);
++ if (status & ATA_BUSY) {
++ msleep(2);
++ status = ata_busy_wait(ap, ATA_BUSY, 10);
++ if (status & ATA_BUSY) {
++ ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
++ return;
++ }
++ }
++
++ /* move the HSM */
++ poll_next = ata_hsm_move(ap, qc, status, 1);
++
++ /* another command or interrupt handler
++ * may be running at this point.
++ */
++ if (poll_next)
++ goto fsm_start;
++}
++
++/**
++ * ata_qc_new - Request an available ATA command, for queueing
++ * @ap: Port associated with device @dev
++ * @dev: Device from whom we request an available command structure
++ *
++ * LOCKING:
++ * None.
++ */
++
++static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
++{
++ struct ata_queued_cmd *qc = NULL;
++ unsigned int i;
++
++ /* no command while frozen */
++ if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
++ return NULL;
++
++ /* the last tag is reserved for internal command. */
++ for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
++ if (!test_and_set_bit(i, &ap->qc_allocated)) {
++ qc = __ata_qc_from_tag(ap, i);
++ break;
++ }
++
++ if (qc)
++ qc->tag = i;
++
++ return qc;
++}
++
++/**
++ * ata_qc_new_init - Request an available ATA command, and initialize it
++ * @dev: Device from whom we request an available command structure
++ *
++ * LOCKING:
++ * None.
++ */
++
++struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
++{
++ struct ata_port *ap = dev->ap;
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_new(ap);
++ if (qc) {
++ qc->scsicmd = NULL;
++ qc->ap = ap;
++ qc->dev = dev;
++
++ ata_qc_reinit(qc);
++ }
++
++ return qc;
++}
++
++/**
++ * ata_qc_free - free unused ata_queued_cmd
++ * @qc: Command to complete
++ *
++ * Designed to free unused ata_queued_cmd object
++ * in case something prevents using it.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_qc_free(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ unsigned int tag;
++
++ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
++
++ qc->flags = 0;
++ tag = qc->tag;
++ if (likely(ata_tag_valid(tag))) {
++ qc->tag = ATA_TAG_POISON;
++ clear_bit(tag, &ap->qc_allocated);
++ }
++}
++
++void __ata_qc_complete(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
++ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
++
++ if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
++ ata_sg_clean(qc);
++
++ /* command should be marked inactive atomically with qc completion */
++ if (qc->tf.protocol == ATA_PROT_NCQ)
++ ap->sactive &= ~(1 << qc->tag);
++ else
++ ap->active_tag = ATA_TAG_POISON;
++
++ /* atapi: mark qc as inactive to prevent the interrupt handler
++ * from completing the command twice later, before the error handler
++ * is called. (when rc != 0 and atapi request sense is needed)
++ */
++ qc->flags &= ~ATA_QCFLAG_ACTIVE;
++ ap->qc_active &= ~(1 << qc->tag);
++
++ /* call completion callback */
++ qc->complete_fn(qc);
++}
++
++/**
++ * ata_qc_complete - Complete an active ATA command
++ * @qc: Command to complete
++ * @err_mask: ATA Status register contents
++ *
++ * Indicate to the mid and upper layers that an ATA
++ * command has completed, with either an ok or not-ok status.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_qc_complete(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ /* XXX: New EH and old EH use different mechanisms to
++ * synchronize EH with regular execution path.
++ *
++ * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
++ * Normal execution path is responsible for not accessing a
++ * failed qc. libata core enforces the rule by returning NULL
++ * from ata_qc_from_tag() for failed qcs.
++ *
++ * Old EH depends on ata_qc_complete() nullifying completion
++ * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
++ * not synchronize with interrupt handler. Only PIO task is
++ * taken care of.
++ */
++ if (ap->ops->error_handler) {
++ WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
++
++ if (unlikely(qc->err_mask))
++ qc->flags |= ATA_QCFLAG_FAILED;
++
++ if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
++ if (!ata_tag_internal(qc->tag)) {
++ /* always fill result TF for failed qc */
++ ap->ops->tf_read(ap, &qc->result_tf);
++ ata_qc_schedule_eh(qc);
++ return;
++ }
++ }
++
++ /* read result TF if requested */
++ if (qc->flags & ATA_QCFLAG_RESULT_TF)
++ ap->ops->tf_read(ap, &qc->result_tf);
++
++ __ata_qc_complete(qc);
++ } else {
++ if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
++ return;
++
++ /* read result TF if failed or requested */
++ if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
++ ap->ops->tf_read(ap, &qc->result_tf);
++
++ __ata_qc_complete(qc);
++ }
++}
++
++/**
++ * ata_qc_complete_multiple - Complete multiple qcs successfully
++ * @ap: port in question
++ * @qc_active: new qc_active mask
++ * @finish_qc: LLDD callback invoked before completing a qc
++ *
++ * Complete in-flight commands. This functions is meant to be
++ * called from low-level driver's interrupt routine to complete
++ * requests normally. ap->qc_active and @qc_active is compared
++ * and commands are completed accordingly.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Number of completed commands on success, -errno otherwise.
++ */
++int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
++ void (*finish_qc)(struct ata_queued_cmd *))
++{
++ int nr_done = 0;
++ u32 done_mask;
++ int i;
++
++ done_mask = ap->qc_active ^ qc_active;
++
++ if (unlikely(done_mask & qc_active)) {
++ ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
++ "(%08x->%08x)\n", ap->qc_active, qc_active);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < ATA_MAX_QUEUE; i++) {
++ struct ata_queued_cmd *qc;
++
++ if (!(done_mask & (1 << i)))
++ continue;
++
++ if ((qc = ata_qc_from_tag(ap, i))) {
++ if (finish_qc)
++ finish_qc(qc);
++ ata_qc_complete(qc);
++ nr_done++;
++ }
++ }
++
++ return nr_done;
++}
++
++static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_NCQ:
++ case ATA_PROT_DMA:
++ case ATA_PROT_ATAPI_DMA:
++ return 1;
++
++ case ATA_PROT_ATAPI:
++ case ATA_PROT_PIO:
++ if (ap->flags & ATA_FLAG_PIO_DMA)
++ return 1;
++
++ /* fall through */
++
++ default:
++ return 0;
++ }
++
++ /* never reached */
++}
++
++/**
++ * ata_qc_issue - issue taskfile to device
++ * @qc: command to issue to device
++ *
++ * Prepare an ATA command to submission to device.
++ * This includes mapping the data into a DMA-able
++ * area, filling in the S/G table, and finally
++ * writing the taskfile to hardware, starting the command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_qc_issue(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ /* Make sure only one non-NCQ command is outstanding. The
++ * check is skipped for old EH because it reuses active qc to
++ * request ATAPI sense.
++ */
++ WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
++
++ if (qc->tf.protocol == ATA_PROT_NCQ) {
++ WARN_ON(ap->sactive & (1 << qc->tag));
++ ap->sactive |= 1 << qc->tag;
++ } else {
++ WARN_ON(ap->sactive);
++ ap->active_tag = qc->tag;
++ }
++
++ qc->flags |= ATA_QCFLAG_ACTIVE;
++ ap->qc_active |= 1 << qc->tag;
++
++ if (ata_should_dma_map(qc)) {
++ if (qc->flags & ATA_QCFLAG_SG) {
++ if (ata_sg_setup(qc))
++ goto sg_err;
++ } else if (qc->flags & ATA_QCFLAG_SINGLE) {
++ if (ata_sg_setup_one(qc))
++ goto sg_err;
++ }
++ } else {
++ qc->flags &= ~ATA_QCFLAG_DMAMAP;
++ }
++
++ ap->ops->qc_prep(qc);
++
++ qc->err_mask |= ap->ops->qc_issue(qc);
++ if (unlikely(qc->err_mask))
++ goto err;
++ return;
++
++sg_err:
++ qc->flags &= ~ATA_QCFLAG_DMAMAP;
++ qc->err_mask |= AC_ERR_SYSTEM;
++err:
++ ata_qc_complete(qc);
++}
++
++/**
++ * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
++ * @qc: command to issue to device
++ *
++ * Using various libata functions and hooks, this function
++ * starts an ATA command. ATA commands are grouped into
++ * classes called "protocols", and issuing each type of protocol
++ * is slightly different.
++ *
++ * May be used as the qc_issue() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, AC_ERR_* mask on failure
++ */
++
++unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ /* Use polling pio if the LLD doesn't handle
++ * interrupt driven pio and atapi CDB interrupt.
++ */
++ if (ap->flags & ATA_FLAG_PIO_POLLING) {
++ switch (qc->tf.protocol) {
++ case ATA_PROT_PIO:
++ case ATA_PROT_ATAPI:
++ case ATA_PROT_ATAPI_NODATA:
++ qc->tf.flags |= ATA_TFLAG_POLLING;
++ break;
++ case ATA_PROT_ATAPI_DMA:
++ if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
++ /* see ata_dma_blacklisted() */
++ BUG();
++ break;
++ default:
++ break;
++ }
++ }
++
++ /* select the device */
++ ata_dev_select(ap, qc->dev->devno, 1, 0);
++
++ /* start the command */
++ switch (qc->tf.protocol) {
++ case ATA_PROT_NODATA:
++ if (qc->tf.flags & ATA_TFLAG_POLLING)
++ ata_qc_set_polling(qc);
++
++ ata_tf_to_host(ap, &qc->tf);
++ ap->hsm_task_state = HSM_ST_LAST;
++
++ if (qc->tf.flags & ATA_TFLAG_POLLING)
++ ata_port_queue_task(ap, ata_pio_task, qc, 0);
++
++ break;
++
++ case ATA_PROT_DMA:
++ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
++
++ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
++ ap->ops->bmdma_setup(qc); /* set up bmdma */
++ ap->ops->bmdma_start(qc); /* initiate bmdma */
++ ap->hsm_task_state = HSM_ST_LAST;
++ break;
++
++ case ATA_PROT_PIO:
++ if (qc->tf.flags & ATA_TFLAG_POLLING)
++ ata_qc_set_polling(qc);
++
++ ata_tf_to_host(ap, &qc->tf);
++
++ if (qc->tf.flags & ATA_TFLAG_WRITE) {
++ /* PIO data out protocol */
++ ap->hsm_task_state = HSM_ST_FIRST;
++ ata_port_queue_task(ap, ata_pio_task, qc, 0);
++
++ /* always send first data block using
++ * the ata_pio_task() codepath.
++ */
++ } else {
++ /* PIO data in protocol */
++ ap->hsm_task_state = HSM_ST;
++
++ if (qc->tf.flags & ATA_TFLAG_POLLING)
++ ata_port_queue_task(ap, ata_pio_task, qc, 0);
++
++ /* if polling, ata_pio_task() handles the rest.
++ * otherwise, interrupt handler takes over from here.
++ */
++ }
++
++ break;
++
++ case ATA_PROT_ATAPI:
++ case ATA_PROT_ATAPI_NODATA:
++ if (qc->tf.flags & ATA_TFLAG_POLLING)
++ ata_qc_set_polling(qc);
++
++ ata_tf_to_host(ap, &qc->tf);
++
++ ap->hsm_task_state = HSM_ST_FIRST;
++
++ /* send cdb by polling if no cdb interrupt */
++ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
++ (qc->tf.flags & ATA_TFLAG_POLLING))
++ ata_port_queue_task(ap, ata_pio_task, qc, 0);
++ break;
++
++ case ATA_PROT_ATAPI_DMA:
++ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
++
++ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
++ ap->ops->bmdma_setup(qc); /* set up bmdma */
++ ap->hsm_task_state = HSM_ST_FIRST;
++
++ /* send cdb by polling if no cdb interrupt */
++ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
++ ata_port_queue_task(ap, ata_pio_task, qc, 0);
++ break;
++
++ default:
++ WARN_ON(1);
++ return AC_ERR_SYSTEM;
++ }
++
++ return 0;
++}
++
++/**
++ * ata_host_intr - Handle host interrupt for given (port, task)
++ * @ap: Port on which interrupt arrived (possibly...)
++ * @qc: Taskfile currently active in engine
++ *
++ * Handle host interrupt for given queued command. Currently,
++ * only DMA interrupts are handled. All other commands are
++ * handled via polling with interrupts disabled (nIEN bit).
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * One if interrupt was handled, zero if not (shared irq).
++ */
++
++inline unsigned int ata_host_intr (struct ata_port *ap,
++ struct ata_queued_cmd *qc)
++{
++ u8 status, host_stat = 0;
++
++ VPRINTK("ata%u: protocol %d task_state %d\n",
++ ap->id, qc->tf.protocol, ap->hsm_task_state);
++
++ /* Check whether we are expecting interrupt in this state */
++ switch (ap->hsm_task_state) {
++ case HSM_ST_FIRST:
++ /* Some pre-ATAPI-4 devices assert INTRQ
++ * at this state when ready to receive CDB.
++ */
++
++ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
++ * The flag was turned on only for atapi devices.
++ * No need to check is_atapi_taskfile(&qc->tf) again.
++ */
++ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
++ goto idle_irq;
++ break;
++ case HSM_ST_LAST:
++ if (qc->tf.protocol == ATA_PROT_DMA ||
++ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
++ /* check status of DMA engine */
++ host_stat = ap->ops->bmdma_status(ap);
++ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
++
++ /* if it's not our irq... */
++ if (!(host_stat & ATA_DMA_INTR))
++ goto idle_irq;
++
++ /* before we do anything else, clear DMA-Start bit */
++ ap->ops->bmdma_stop(qc);
++
++ if (unlikely(host_stat & ATA_DMA_ERR)) {
++ /* error when transfering data to/from memory */
++ qc->err_mask |= AC_ERR_HOST_BUS;
++ ap->hsm_task_state = HSM_ST_ERR;
++ }
++ }
++ break;
++ case HSM_ST:
++ break;
++ default:
++ goto idle_irq;
++ }
++
++ /* check altstatus */
++ status = ata_altstatus(ap);
++ if (status & ATA_BUSY)
++ goto idle_irq;
++
++ /* check main status, clearing INTRQ */
++ status = ata_chk_status(ap);
++ if (unlikely(status & ATA_BUSY))
++ goto idle_irq;
++
++ /* ack bmdma irq events */
++ ap->ops->irq_clear(ap);
++
++ ata_hsm_move(ap, qc, status, 0);
++ return 1; /* irq handled */
++
++idle_irq:
++ ap->stats.idle_irq++;
++
++#ifdef ATA_IRQ_TRAP
++ if ((ap->stats.idle_irq % 1000) == 0) {
++ ata_irq_ack(ap, 0); /* debug trap */
++ ata_port_printk(ap, KERN_WARNING, "irq trap\n");
++ return 1;
++ }
++#endif
++ return 0; /* irq not handled */
++}
++
++/**
++ * ata_interrupt - Default ATA host interrupt handler
++ * @irq: irq line (unused)
++ * @dev_instance: pointer to our ata_host information structure
++ *
++ * Default interrupt handler for PCI IDE devices. Calls
++ * ata_host_intr() for each port that is not disabled.
++ *
++ * LOCKING:
++ * Obtains host lock during operation.
++ *
++ * RETURNS:
++ * IRQ_NONE or IRQ_HANDLED.
++ */
++
++irqreturn_t ata_interrupt (int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ unsigned int i;
++ unsigned int handled = 0;
++ unsigned long flags;
++
++ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
++ spin_lock_irqsave(&host->lock, flags);
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap;
++
++ ap = host->ports[i];
++ if (ap &&
++ !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
++ (qc->flags & ATA_QCFLAG_ACTIVE))
++ handled |= ata_host_intr(ap, qc);
++ }
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ return IRQ_RETVAL(handled);
++}
++
++/**
++ * sata_scr_valid - test whether SCRs are accessible
++ * @ap: ATA port to test SCR accessibility for
++ *
++ * Test whether SCRs are accessible for @ap.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 1 if SCRs are accessible, 0 otherwise.
++ */
++int sata_scr_valid(struct ata_port *ap)
++{
++ return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
++}
++
++/**
++ * sata_scr_read - read SCR register of the specified port
++ * @ap: ATA port to read SCR for
++ * @reg: SCR to read
++ * @val: Place to store read value
++ *
++ * Read SCR register @reg of @ap into *@val. This function is
++ * guaranteed to succeed if the cable type of the port is SATA
++ * and the port implements ->scr_read.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success, negative errno on failure.
++ */
++int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
++{
++ if (sata_scr_valid(ap)) {
++ *val = ap->ops->scr_read(ap, reg);
++ return 0;
++ }
++ return -EOPNOTSUPP;
++}
++
++/**
++ * sata_scr_write - write SCR register of the specified port
++ * @ap: ATA port to write SCR for
++ * @reg: SCR to write
++ * @val: value to write
++ *
++ * Write @val to SCR register @reg of @ap. This function is
++ * guaranteed to succeed if the cable type of the port is SATA
++ * and the port implements ->scr_read.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success, negative errno on failure.
++ */
++int sata_scr_write(struct ata_port *ap, int reg, u32 val)
++{
++ if (sata_scr_valid(ap)) {
++ ap->ops->scr_write(ap, reg, val);
++ return 0;
++ }
++ return -EOPNOTSUPP;
++}
++
++/**
++ * sata_scr_write_flush - write SCR register of the specified port and flush
++ * @ap: ATA port to write SCR for
++ * @reg: SCR to write
++ * @val: value to write
++ *
++ * This function is identical to sata_scr_write() except that this
++ * function performs flush after writing to the register.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success, negative errno on failure.
++ */
++int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
++{
++ if (sata_scr_valid(ap)) {
++ ap->ops->scr_write(ap, reg, val);
++ ap->ops->scr_read(ap, reg);
++ return 0;
++ }
++ return -EOPNOTSUPP;
++}
++
++/**
++ * ata_port_online - test whether the given port is online
++ * @ap: ATA port to test
++ *
++ * Test whether @ap is online. Note that this function returns 0
++ * if online status of @ap cannot be obtained, so
++ * ata_port_online(ap) != !ata_port_offline(ap).
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 1 if the port online status is available and online.
++ */
++int ata_port_online(struct ata_port *ap)
++{
++ u32 sstatus;
++
++ if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
++ return 1;
++ return 0;
++}
++
++/**
++ * ata_port_offline - test whether the given port is offline
++ * @ap: ATA port to test
++ *
++ * Test whether @ap is offline. Note that this function returns
++ * 0 if offline status of @ap cannot be obtained, so
++ * ata_port_online(ap) != !ata_port_offline(ap).
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 1 if the port offline status is available and offline.
++ */
++int ata_port_offline(struct ata_port *ap)
++{
++ u32 sstatus;
++
++ if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
++ return 1;
++ return 0;
++}
++
++int ata_flush_cache(struct ata_device *dev)
++{
++ unsigned int err_mask;
++ u8 cmd;
++
++ if (!ata_try_flush_cache(dev))
++ return 0;
++
++ if (ata_id_has_flush_ext(dev->id))
++ cmd = ATA_CMD_FLUSH_EXT;
++ else
++ cmd = ATA_CMD_FLUSH;
++
++ err_mask = ata_do_simple_cmd(dev, cmd);
++ if (err_mask) {
++ ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
++ unsigned int action, unsigned int ehi_flags,
++ int wait)
++{
++ unsigned long flags;
++ int i, rc;
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++
++ /* Previous resume operation might still be in
++ * progress. Wait for PM_PENDING to clear.
++ */
++ if (ap->pflags & ATA_PFLAG_PM_PENDING) {
++ ata_port_wait_eh(ap);
++ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
++ }
++
++ /* request PM ops to EH */
++ spin_lock_irqsave(ap->lock, flags);
++
++ ap->pm_mesg = mesg;
++ if (wait) {
++ rc = 0;
++ ap->pm_result = &rc;
++ }
++
++ ap->pflags |= ATA_PFLAG_PM_PENDING;
++ ap->eh_info.action |= action;
++ ap->eh_info.flags |= ehi_flags;
++
++ ata_port_schedule_eh(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* wait and check result */
++ if (wait) {
++ ata_port_wait_eh(ap);
++ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
++ if (rc)
++ return rc;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * ata_host_suspend - suspend host
++ * @host: host to suspend
++ * @mesg: PM message
++ *
++ * Suspend @host. Actual operation is performed by EH. This
++ * function requests EH to perform PM operations and waits for EH
++ * to finish.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno on failure.
++ */
++int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
++{
++ int i, j, rc;
++
++ rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
++ if (rc)
++ goto fail;
++
++ /* EH is quiescent now. Fail if we have any ready device.
++ * This happens if hotplug occurs between completion of device
++ * suspension and here.
++ */
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++
++ for (j = 0; j < ATA_MAX_DEVICES; j++) {
++ struct ata_device *dev = &ap->device[j];
++
++ if (ata_dev_ready(dev)) {
++ ata_port_printk(ap, KERN_WARNING,
++ "suspend failed, device %d "
++ "still active\n", dev->devno);
++ rc = -EBUSY;
++ goto fail;
++ }
++ }
++ }
++
++ host->dev->power.power_state = mesg;
++ return 0;
++
++ fail:
++ ata_host_resume(host);
++ return rc;
++}
++
++/**
++ * ata_host_resume - resume host
++ * @host: host to resume
++ *
++ * Resume @host. Actual operation is performed by EH. This
++ * function requests EH to perform PM operations and returns.
++ * Note that all resume operations are performed parallely.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++void ata_host_resume(struct ata_host *host)
++{
++ ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
++ ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
++ host->dev->power.power_state = PMSG_ON;
++}
++
++/**
++ * ata_port_start - Set port up for dma.
++ * @ap: Port to initialize
++ *
++ * Called just after data structures for each port are
++ * initialized. Allocates space for PRD table.
++ *
++ * May be used as the port_start() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++int ata_port_start (struct ata_port *ap)
++{
++ struct device *dev = ap->dev;
++ int rc;
++
++ ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
++ if (!ap->prd)
++ return -ENOMEM;
++
++ rc = ata_pad_alloc(ap, dev);
++ if (rc) {
++ dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
++ return rc;
++ }
++
++ DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
++
++ return 0;
++}
++
++
++/**
++ * ata_port_stop - Undo ata_port_start()
++ * @ap: Port to shut down
++ *
++ * Frees the PRD table.
++ *
++ * May be used as the port_stop() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_port_stop (struct ata_port *ap)
++{
++ struct device *dev = ap->dev;
++
++ dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
++ ata_pad_free(ap, dev);
++}
++
++void ata_host_stop (struct ata_host *host)
++{
++ if (host->mmio_base)
++ iounmap(host->mmio_base);
++}
++
++/**
++ * ata_dev_init - Initialize an ata_device structure
++ * @dev: Device structure to initialize
++ *
++ * Initialize @dev in preparation for probing.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_dev_init(struct ata_device *dev)
++{
++ struct ata_port *ap = dev->ap;
++ unsigned long flags;
++
++ /* SATA spd limit is bound to the first device */
++ ap->sata_spd_limit = ap->hw_sata_spd_limit;
++
++ /* High bits of dev->flags are used to record warm plug
++ * requests which occur asynchronously. Synchronize using
++ * host lock.
++ */
++ spin_lock_irqsave(ap->lock, flags);
++ dev->flags &= ~ATA_DFLAG_INIT_MASK;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
++ sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
++ dev->pio_mask = UINT_MAX;
++ dev->mwdma_mask = UINT_MAX;
++ dev->udma_mask = UINT_MAX;
++}
++
++/**
++ * ata_port_init - Initialize an ata_port structure
++ * @ap: Structure to initialize
++ * @host: Collection of hosts to which @ap belongs
++ * @ent: Probe information provided by low-level driver
++ * @port_no: Port number associated with this ata_port
++ *
++ * Initialize a new ata_port structure.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_port_init(struct ata_port *ap, struct ata_host *host,
++ const struct ata_probe_ent *ent, unsigned int port_no)
++{
++ unsigned int i;
++
++ ap->lock = &host->lock;
++ ap->flags = ATA_FLAG_DISABLED;
++ ap->id = ata_unique_id++;
++ ap->ctl = ATA_DEVCTL_OBS;
++ ap->host = host;
++ ap->dev = ent->dev;
++ ap->port_no = port_no;
++ if (port_no == 1 && ent->pinfo2) {
++ ap->pio_mask = ent->pinfo2->pio_mask;
++ ap->mwdma_mask = ent->pinfo2->mwdma_mask;
++ ap->udma_mask = ent->pinfo2->udma_mask;
++ ap->flags |= ent->pinfo2->flags;
++ ap->ops = ent->pinfo2->port_ops;
++ } else {
++ ap->pio_mask = ent->pio_mask;
++ ap->mwdma_mask = ent->mwdma_mask;
++ ap->udma_mask = ent->udma_mask;
++ ap->flags |= ent->port_flags;
++ ap->ops = ent->port_ops;
++ }
++ ap->hw_sata_spd_limit = UINT_MAX;
++ ap->active_tag = ATA_TAG_POISON;
++ ap->last_ctl = 0xFF;
++
++#if defined(ATA_VERBOSE_DEBUG)
++ /* turn on all debugging levels */
++ ap->msg_enable = 0x00FF;
++#elif defined(ATA_DEBUG)
++ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
++#else
++ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
++#endif
++
++ INIT_WORK(&ap->port_task, NULL, NULL);
++ INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
++ INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
++ INIT_LIST_HEAD(&ap->eh_done_q);
++ init_waitqueue_head(&ap->eh_wait_q);
++
++ /* set cable type */
++ ap->cbl = ATA_CBL_NONE;
++ if (ap->flags & ATA_FLAG_SATA)
++ ap->cbl = ATA_CBL_SATA;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ dev->ap = ap;
++ dev->devno = i;
++ ata_dev_init(dev);
++ }
++
++#ifdef ATA_IRQ_TRAP
++ ap->stats.unhandled_irq = 1;
++ ap->stats.idle_irq = 1;
++#endif
++
++ memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
++}
++
++/**
++ * ata_port_init_shost - Initialize SCSI host associated with ATA port
++ * @ap: ATA port to initialize SCSI host for
++ * @shost: SCSI host associated with @ap
++ *
++ * Initialize SCSI host @shost associated with ATA port @ap.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
++{
++ ap->scsi_host = shost;
++
++ shost->unique_id = ap->id;
++ shost->max_id = 16;
++ shost->max_lun = 1;
++ shost->max_channel = 1;
++ shost->max_cmd_len = 12;
++}
++
++/**
++ * ata_port_add - Attach low-level ATA driver to system
++ * @ent: Information provided by low-level driver
++ * @host: Collections of ports to which we add
++ * @port_no: Port number associated with this host
++ *
++ * Attach low-level ATA driver to system.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * New ata_port on success, for NULL on error.
++ */
++static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
++ struct ata_host *host,
++ unsigned int port_no)
++{
++ struct Scsi_Host *shost;
++ struct ata_port *ap;
++
++ DPRINTK("ENTER\n");
++
++ if (!ent->port_ops->error_handler &&
++ !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
++ printk(KERN_ERR "ata%u: no reset mechanism available\n",
++ port_no);
++ return NULL;
++ }
++
++ shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
++ if (!shost)
++ return NULL;
++
++ shost->transportt = &ata_scsi_transport_template;
++
++ ap = ata_shost_to_port(shost);
++
++ ata_port_init(ap, host, ent, port_no);
++ ata_port_init_shost(ap, shost);
++
++ return ap;
++}
++
++/**
++ * ata_sas_host_init - Initialize a host struct
++ * @host: host to initialize
++ * @dev: device host is attached to
++ * @flags: host flags
++ * @ops: port_ops
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ */
++
++void ata_host_init(struct ata_host *host, struct device *dev,
++ unsigned long flags, const struct ata_port_operations *ops)
++{
++ spin_lock_init(&host->lock);
++ host->dev = dev;
++ host->flags = flags;
++ host->ops = ops;
++}
++
++/**
++ * ata_device_add - Register hardware device with ATA and SCSI layers
++ * @ent: Probe information describing hardware device to be registered
++ *
++ * This function processes the information provided in the probe
++ * information struct @ent, allocates the necessary ATA and SCSI
++ * host information structures, initializes them, and registers
++ * everything with requisite kernel subsystems.
++ *
++ * This function requests irqs, probes the ATA bus, and probes
++ * the SCSI bus.
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * Number of ports registered. Zero on error (no ports registered).
++ */
++int ata_device_add(const struct ata_probe_ent *ent)
++{
++ unsigned int i;
++ struct device *dev = ent->dev;
++ struct ata_host *host;
++ int rc;
++
++ DPRINTK("ENTER\n");
++
++ if (ent->irq == 0) {
++ dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
++ return 0;
++ }
++ /* alloc a container for our list of ATA ports (buses) */
++ host = kzalloc(sizeof(struct ata_host) +
++ (ent->n_ports * sizeof(void *)), GFP_KERNEL);
++ if (!host)
++ return 0;
++
++ ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
++ host->n_ports = ent->n_ports;
++ host->irq = ent->irq;
++ host->irq2 = ent->irq2;
++ host->mmio_base = ent->mmio_base;
++ host->private_data = ent->private_data;
++
++ /* register each port bound to this device */
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap;
++ unsigned long xfer_mode_mask;
++ int irq_line = ent->irq;
++
++ ap = ata_port_add(ent, host, i);
++ host->ports[i] = ap;
++ if (!ap)
++ goto err_out;
++
++ /* dummy? */
++ if (ent->dummy_port_mask & (1 << i)) {
++ ata_port_printk(ap, KERN_INFO, "DUMMY\n");
++ ap->ops = &ata_dummy_port_ops;
++ continue;
++ }
++
++ /* start port */
++ rc = ap->ops->port_start(ap);
++ if (rc) {
++ host->ports[i] = NULL;
++ scsi_host_put(ap->scsi_host);
++ goto err_out;
++ }
++
++ /* Report the secondary IRQ for second channel legacy */
++ if (i == 1 && ent->irq2)
++ irq_line = ent->irq2;
++
++ xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
++ (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
++ (ap->pio_mask << ATA_SHIFT_PIO);
++
++ /* print per-port info to dmesg */
++ ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
++ "ctl 0x%lX bmdma 0x%lX irq %d\n",
++ ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
++ ata_mode_string(xfer_mode_mask),
++ ap->ioaddr.cmd_addr,
++ ap->ioaddr.ctl_addr,
++ ap->ioaddr.bmdma_addr,
++ irq_line);
++
++ ata_chk_status(ap);
++ host->ops->irq_clear(ap);
++ ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
++ }
++
++ /* obtain irq, that may be shared between channels */
++ rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
++ DRV_NAME, host);
++ if (rc) {
++ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
++ ent->irq, rc);
++ goto err_out;
++ }
++
++ /* do we have a second IRQ for the other channel, eg legacy mode */
++ if (ent->irq2) {
++ /* We will get weird core code crashes later if this is true
++ so trap it now */
++ BUG_ON(ent->irq == ent->irq2);
++
++ rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags,
++ DRV_NAME, host);
++ if (rc) {
++ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
++ ent->irq2, rc);
++ goto err_out_free_irq;
++ }
++ }
++
++ /* perform each probe synchronously */
++ DPRINTK("probe begin\n");
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++ u32 scontrol;
++ int rc;
++
++ /* init sata_spd_limit to the current value */
++ if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
++ int spd = (scontrol >> 4) & 0xf;
++ ap->hw_sata_spd_limit &= (1 << spd) - 1;
++ }
++ ap->sata_spd_limit = ap->hw_sata_spd_limit;
++
++ rc = scsi_add_host(ap->scsi_host, dev);
++ if (rc) {
++ ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
++ /* FIXME: do something useful here */
++ /* FIXME: handle unconditional calls to
++ * scsi_scan_host and ata_host_remove, below,
++ * at the very least
++ */
++ }
++
++ if (ap->ops->error_handler) {
++ struct ata_eh_info *ehi = &ap->eh_info;
++ unsigned long flags;
++
++ ata_port_probe(ap);
++
++ /* kick EH for boot probing */
++ spin_lock_irqsave(ap->lock, flags);
++
++ ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
++ ehi->action |= ATA_EH_SOFTRESET;
++ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
++
++ ap->pflags |= ATA_PFLAG_LOADING;
++ ata_port_schedule_eh(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* wait for EH to finish */
++ ata_port_wait_eh(ap);
++ } else {
++ DPRINTK("ata%u: bus probe begin\n", ap->id);
++ rc = ata_bus_probe(ap);
++ DPRINTK("ata%u: bus probe end\n", ap->id);
++
++ if (rc) {
++ /* FIXME: do something useful here?
++ * Current libata behavior will
++ * tear down everything when
++ * the module is removed
++ * or the h/w is unplugged.
++ */
++ }
++ }
++ }
++
++ /* probes are done, now scan each port's disk(s) */
++ DPRINTK("host probe begin\n");
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++
++ ata_scsi_scan_host(ap);
++ }
++
++ dev_set_drvdata(dev, host);
++
++ VPRINTK("EXIT, returning %u\n", ent->n_ports);
++ return ent->n_ports; /* success */
++
++err_out_free_irq:
++ free_irq(ent->irq, host);
++err_out:
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++ if (ap) {
++ ap->ops->port_stop(ap);
++ scsi_host_put(ap->scsi_host);
++ }
++ }
++
++ kfree(host);
++ VPRINTK("EXIT, returning 0\n");
++ return 0;
++}
++
++/**
++ * ata_port_detach - Detach ATA port in prepration of device removal
++ * @ap: ATA port to be detached
++ *
++ * Detach all ATA devices and the associated SCSI devices of @ap;
++ * then, remove the associated SCSI host. @ap is guaranteed to
++ * be quiescent on return from this function.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++void ata_port_detach(struct ata_port *ap)
++{
++ unsigned long flags;
++ int i;
++
++ if (!ap->ops->error_handler)
++ goto skip_eh;
++
++ /* tell EH we're leaving & flush EH */
++ spin_lock_irqsave(ap->lock, flags);
++ ap->pflags |= ATA_PFLAG_UNLOADING;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ ata_port_wait_eh(ap);
++
++ /* EH is now guaranteed to see UNLOADING, so no new device
++ * will be attached. Disable all existing devices.
++ */
++ spin_lock_irqsave(ap->lock, flags);
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ata_dev_disable(&ap->device[i]);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* Final freeze & EH. All in-flight commands are aborted. EH
++ * will be skipped and retrials will be terminated with bad
++ * target.
++ */
++ spin_lock_irqsave(ap->lock, flags);
++ ata_port_freeze(ap); /* won't be thawed */
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ ata_port_wait_eh(ap);
++
++ /* Flush hotplug task. The sequence is similar to
++ * ata_port_flush_task().
++ */
++ flush_workqueue(ata_aux_wq);
++ cancel_delayed_work(&ap->hotplug_task);
++ flush_workqueue(ata_aux_wq);
++
++ skip_eh:
++ /* remove the associated SCSI host */
++ scsi_remove_host(ap->scsi_host);
++}
++
++/**
++ * ata_host_remove - PCI layer callback for device removal
++ * @host: ATA host set that was removed
++ *
++ * Unregister all objects associated with this host set. Free those
++ * objects.
++ *
++ * LOCKING:
++ * Inherited from calling layer (may sleep).
++ */
++
++void ata_host_remove(struct ata_host *host)
++{
++ unsigned int i;
++
++ for (i = 0; i < host->n_ports; i++)
++ ata_port_detach(host->ports[i]);
++
++ free_irq(host->irq, host);
++ if (host->irq2)
++ free_irq(host->irq2, host);
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++
++ ata_scsi_release(ap->scsi_host);
++
++ if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++
++ /* FIXME: Add -ac IDE pci mods to remove these special cases */
++ if (ioaddr->cmd_addr == ATA_PRIMARY_CMD)
++ release_region(ATA_PRIMARY_CMD, 8);
++ else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD)
++ release_region(ATA_SECONDARY_CMD, 8);
++ }
++
++ scsi_host_put(ap->scsi_host);
++ }
++
++ if (host->ops->host_stop)
++ host->ops->host_stop(host);
++
++ kfree(host);
++}
++
++/**
++ * ata_scsi_release - SCSI layer callback hook for host unload
++ * @shost: libata host to be unloaded
++ *
++ * Performs all duties necessary to shut down a libata port...
++ * Kill port kthread, disable port, and release resources.
++ *
++ * LOCKING:
++ * Inherited from SCSI layer.
++ *
++ * RETURNS:
++ * One.
++ */
++
++int ata_scsi_release(struct Scsi_Host *shost)
++{
++ struct ata_port *ap = ata_shost_to_port(shost);
++
++ DPRINTK("ENTER\n");
++
++ ap->ops->port_disable(ap);
++ ap->ops->port_stop(ap);
++
++ DPRINTK("EXIT\n");
++ return 1;
++}
++
++struct ata_probe_ent *
++ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
++{
++ struct ata_probe_ent *probe_ent;
++
++ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (!probe_ent) {
++ printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
++ kobject_name(&(dev->kobj)));
++ return NULL;
++ }
++
++ INIT_LIST_HEAD(&probe_ent->node);
++ probe_ent->dev = dev;
++
++ probe_ent->sht = port->sht;
++ probe_ent->port_flags = port->flags;
++ probe_ent->pio_mask = port->pio_mask;
++ probe_ent->mwdma_mask = port->mwdma_mask;
++ probe_ent->udma_mask = port->udma_mask;
++ probe_ent->port_ops = port->port_ops;
++ probe_ent->private_data = port->private_data;
++
++ return probe_ent;
++}
++
++/**
++ * ata_std_ports - initialize ioaddr with standard port offsets.
++ * @ioaddr: IO address structure to be initialized
++ *
++ * Utility function which initializes data_addr, error_addr,
++ * feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
++ * device_addr, status_addr, and command_addr to standard offsets
++ * relative to cmd_addr.
++ *
++ * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
++ */
++
++void ata_std_ports(struct ata_ioports *ioaddr)
++{
++ ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
++ ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
++ ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
++ ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
++ ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
++ ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
++ ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
++ ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
++ ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
++ ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
++}
++
++
++#ifdef CONFIG_PCI
++
++void ata_pci_host_stop (struct ata_host *host)
++{
++ struct pci_dev *pdev = to_pci_dev(host->dev);
++
++ pci_iounmap(pdev, host->mmio_base);
++}
++
++/**
++ * ata_pci_remove_one - PCI layer callback for device removal
++ * @pdev: PCI device that was removed
++ *
++ * PCI layer indicates to libata via this hook that
++ * hot-unplug or module unload event has occurred.
++ * Handle this by unregistering all objects associated
++ * with this PCI device. Free those objects. Then finally
++ * release PCI resources and disable device.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ */
++
++void ata_pci_remove_one (struct pci_dev *pdev)
++{
++ struct device *dev = pci_dev_to_dev(pdev);
++ struct ata_host *host = dev_get_drvdata(dev);
++
++ ata_host_remove(host);
++
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++ dev_set_drvdata(dev, NULL);
++}
++
++/* move to PCI subsystem */
++int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
++{
++ unsigned long tmp = 0;
++
++ switch (bits->width) {
++ case 1: {
++ u8 tmp8 = 0;
++ pci_read_config_byte(pdev, bits->reg, &tmp8);
++ tmp = tmp8;
++ break;
++ }
++ case 2: {
++ u16 tmp16 = 0;
++ pci_read_config_word(pdev, bits->reg, &tmp16);
++ tmp = tmp16;
++ break;
++ }
++ case 4: {
++ u32 tmp32 = 0;
++ pci_read_config_dword(pdev, bits->reg, &tmp32);
++ tmp = tmp32;
++ break;
++ }
++
++ default:
++ return -EINVAL;
++ }
++
++ tmp &= bits->mask;
++
++ return (tmp == bits->val) ? 1 : 0;
++}
++
++void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
++{
++ pci_save_state(pdev);
++
++ if (mesg.event == PM_EVENT_SUSPEND) {
++ pci_disable_device(pdev);
++ pci_set_power_state(pdev, PCI_D3hot);
++ }
++}
++
++void ata_pci_device_do_resume(struct pci_dev *pdev)
++{
++ pci_set_power_state(pdev, PCI_D0);
++ pci_restore_state(pdev);
++ pci_enable_device(pdev);
++ pci_set_master(pdev);
++}
++
++int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
++{
++ struct ata_host *host = dev_get_drvdata(&pdev->dev);
++ int rc = 0;
++
++ rc = ata_host_suspend(host, mesg);
++ if (rc)
++ return rc;
++
++ ata_pci_device_do_suspend(pdev, mesg);
++
++ return 0;
++}
++
++int ata_pci_device_resume(struct pci_dev *pdev)
++{
++ struct ata_host *host = dev_get_drvdata(&pdev->dev);
++
++ ata_pci_device_do_resume(pdev);
++ ata_host_resume(host);
++ return 0;
++}
++#endif /* CONFIG_PCI */
++
++
++static int __init ata_init(void)
++{
++ ata_probe_timeout *= HZ;
++ ata_wq = create_workqueue("ata");
++ if (!ata_wq)
++ return -ENOMEM;
++
++ ata_aux_wq = create_singlethread_workqueue("ata_aux");
++ if (!ata_aux_wq) {
++ destroy_workqueue(ata_wq);
++ return -ENOMEM;
++ }
++
++ printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
++ return 0;
++}
++
++static void __exit ata_exit(void)
++{
++ destroy_workqueue(ata_wq);
++ destroy_workqueue(ata_aux_wq);
++}
++
++module_init(ata_init);
++module_exit(ata_exit);
++
++static unsigned long ratelimit_time;
++static DEFINE_SPINLOCK(ata_ratelimit_lock);
++
++int ata_ratelimit(void)
++{
++ int rc;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ata_ratelimit_lock, flags);
++
++ if (time_after(jiffies, ratelimit_time)) {
++ rc = 1;
++ ratelimit_time = jiffies + (HZ/5);
++ } else
++ rc = 0;
++
++ spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
++
++ return rc;
++}
++
++/**
++ * ata_wait_register - wait until register value changes
++ * @reg: IO-mapped register
++ * @mask: Mask to apply to read register value
++ * @val: Wait condition
++ * @interval_msec: polling interval in milliseconds
++ * @timeout_msec: timeout in milliseconds
++ *
++ * Waiting for some bits of register to change is a common
++ * operation for ATA controllers. This function reads 32bit LE
++ * IO-mapped register @reg and tests for the following condition.
++ *
++ * (*@reg & mask) != val
++ *
++ * If the condition is met, it returns; otherwise, the process is
++ * repeated after @interval_msec until timeout.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * The final register value.
++ */
++u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
++ unsigned long interval_msec,
++ unsigned long timeout_msec)
++{
++ unsigned long timeout;
++ u32 tmp;
++
++ tmp = ioread32(reg);
++
++ /* Calculate timeout _after_ the first read to make sure
++ * preceding writes reach the controller before starting to
++ * eat away the timeout.
++ */
++ timeout = jiffies + (timeout_msec * HZ) / 1000;
++
++ while ((tmp & mask) == val && time_before(jiffies, timeout)) {
++ msleep(interval_msec);
++ tmp = ioread32(reg);
++ }
++
++ return tmp;
++}
++
++/*
++ * Dummy port_ops
++ */
++static void ata_dummy_noret(struct ata_port *ap) { }
++static int ata_dummy_ret0(struct ata_port *ap) { return 0; }
++static void ata_dummy_qc_noret(struct ata_queued_cmd *qc) { }
++
++static u8 ata_dummy_check_status(struct ata_port *ap)
++{
++ return ATA_DRDY;
++}
++
++static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
++{
++ return AC_ERR_SYSTEM;
++}
++
++const struct ata_port_operations ata_dummy_port_ops = {
++ .port_disable = ata_port_disable,
++ .check_status = ata_dummy_check_status,
++ .check_altstatus = ata_dummy_check_status,
++ .dev_select = ata_noop_dev_select,
++ .qc_prep = ata_noop_qc_prep,
++ .qc_issue = ata_dummy_qc_issue,
++ .freeze = ata_dummy_noret,
++ .thaw = ata_dummy_noret,
++ .error_handler = ata_dummy_noret,
++ .post_internal_cmd = ata_dummy_qc_noret,
++ .irq_clear = ata_dummy_noret,
++ .port_start = ata_dummy_ret0,
++ .port_stop = ata_dummy_noret,
++};
++
++/*
++ * libata is essentially a library of internal helper functions for
++ * low-level ATA host controller drivers. As such, the API/ABI is
++ * likely to change as new drivers are added and updated.
++ * Do not depend on ABI/API stability.
++ */
++
++EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
++EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
++EXPORT_SYMBOL_GPL(sata_deb_timing_long);
++EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
++EXPORT_SYMBOL_GPL(ata_std_bios_param);
++EXPORT_SYMBOL_GPL(ata_std_ports);
++EXPORT_SYMBOL_GPL(ata_host_init);
++EXPORT_SYMBOL_GPL(ata_device_add);
++EXPORT_SYMBOL_GPL(ata_port_detach);
++EXPORT_SYMBOL_GPL(ata_host_remove);
++EXPORT_SYMBOL_GPL(ata_sg_init);
++EXPORT_SYMBOL_GPL(ata_sg_init_one);
++EXPORT_SYMBOL_GPL(ata_hsm_move);
++EXPORT_SYMBOL_GPL(ata_qc_complete);
++EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
++EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
++EXPORT_SYMBOL_GPL(ata_tf_load);
++EXPORT_SYMBOL_GPL(ata_tf_read);
++EXPORT_SYMBOL_GPL(ata_noop_dev_select);
++EXPORT_SYMBOL_GPL(ata_std_dev_select);
++EXPORT_SYMBOL_GPL(ata_tf_to_fis);
++EXPORT_SYMBOL_GPL(ata_tf_from_fis);
++EXPORT_SYMBOL_GPL(ata_check_status);
++EXPORT_SYMBOL_GPL(ata_altstatus);
++EXPORT_SYMBOL_GPL(ata_exec_command);
++EXPORT_SYMBOL_GPL(ata_port_start);
++EXPORT_SYMBOL_GPL(ata_port_stop);
++EXPORT_SYMBOL_GPL(ata_host_stop);
++EXPORT_SYMBOL_GPL(ata_interrupt);
++EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
++EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
++EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
++EXPORT_SYMBOL_GPL(ata_qc_prep);
++EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
++EXPORT_SYMBOL_GPL(ata_bmdma_setup);
++EXPORT_SYMBOL_GPL(ata_bmdma_start);
++EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
++EXPORT_SYMBOL_GPL(ata_bmdma_status);
++EXPORT_SYMBOL_GPL(ata_bmdma_stop);
++EXPORT_SYMBOL_GPL(ata_bmdma_freeze);
++EXPORT_SYMBOL_GPL(ata_bmdma_thaw);
++EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh);
++EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
++EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
++EXPORT_SYMBOL_GPL(ata_port_probe);
++EXPORT_SYMBOL_GPL(sata_set_spd);
++EXPORT_SYMBOL_GPL(sata_phy_debounce);
++EXPORT_SYMBOL_GPL(sata_phy_resume);
++EXPORT_SYMBOL_GPL(sata_phy_reset);
++EXPORT_SYMBOL_GPL(__sata_phy_reset);
++EXPORT_SYMBOL_GPL(ata_bus_reset);
++EXPORT_SYMBOL_GPL(ata_std_prereset);
++EXPORT_SYMBOL_GPL(ata_std_softreset);
++EXPORT_SYMBOL_GPL(sata_std_hardreset);
++EXPORT_SYMBOL_GPL(ata_std_postreset);
++EXPORT_SYMBOL_GPL(ata_dev_classify);
++EXPORT_SYMBOL_GPL(ata_dev_pair);
++EXPORT_SYMBOL_GPL(ata_port_disable);
++EXPORT_SYMBOL_GPL(ata_ratelimit);
++EXPORT_SYMBOL_GPL(ata_wait_register);
++EXPORT_SYMBOL_GPL(ata_busy_sleep);
++EXPORT_SYMBOL_GPL(ata_port_queue_task);
++EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
++EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
++EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
++EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
++EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
++EXPORT_SYMBOL_GPL(ata_scsi_release);
++EXPORT_SYMBOL_GPL(ata_host_intr);
++EXPORT_SYMBOL_GPL(sata_scr_valid);
++EXPORT_SYMBOL_GPL(sata_scr_read);
++EXPORT_SYMBOL_GPL(sata_scr_write);
++EXPORT_SYMBOL_GPL(sata_scr_write_flush);
++EXPORT_SYMBOL_GPL(ata_port_online);
++EXPORT_SYMBOL_GPL(ata_port_offline);
++EXPORT_SYMBOL_GPL(ata_host_suspend);
++EXPORT_SYMBOL_GPL(ata_host_resume);
++EXPORT_SYMBOL_GPL(ata_id_string);
++EXPORT_SYMBOL_GPL(ata_id_c_string);
++EXPORT_SYMBOL_GPL(ata_scsi_simulate);
++
++EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
++EXPORT_SYMBOL_GPL(ata_timing_compute);
++EXPORT_SYMBOL_GPL(ata_timing_merge);
++
++#ifdef CONFIG_PCI
++EXPORT_SYMBOL_GPL(pci_test_config_bits);
++EXPORT_SYMBOL_GPL(ata_pci_host_stop);
++EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
++EXPORT_SYMBOL_GPL(ata_pci_init_one);
++EXPORT_SYMBOL_GPL(ata_pci_remove_one);
++EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
++EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
++EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
++EXPORT_SYMBOL_GPL(ata_pci_device_resume);
++EXPORT_SYMBOL_GPL(ata_pci_default_filter);
++EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
++#endif /* CONFIG_PCI */
++
++EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
++EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
++
++EXPORT_SYMBOL_GPL(ata_eng_timeout);
++EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
++EXPORT_SYMBOL_GPL(ata_port_abort);
++EXPORT_SYMBOL_GPL(ata_port_freeze);
++EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
++EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
++EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
++EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
++EXPORT_SYMBOL_GPL(ata_do_eh);
+diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
+new file mode 100644
+index 0000000..02b2b27
+--- /dev/null
++++ b/drivers/ata/libata-eh.c
+@@ -0,0 +1,2249 @@
++/*
++ * libata-eh.c - libata error handling
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2006 Tejun Heo <htejun at gmail.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, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
++ * USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available from http://www.t13.org/ and
++ * http://www.sata-io.org/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_eh.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_cmnd.h>
++#include "../scsi/scsi_transport_api.h"
++
++#include <linux/libata.h>
++
++#include "libata.h"
++
++static void __ata_port_freeze(struct ata_port *ap);
++static void ata_eh_finish(struct ata_port *ap);
++static void ata_eh_handle_port_suspend(struct ata_port *ap);
++static void ata_eh_handle_port_resume(struct ata_port *ap);
++
++static void ata_ering_record(struct ata_ering *ering, int is_io,
++ unsigned int err_mask)
++{
++ struct ata_ering_entry *ent;
++
++ WARN_ON(!err_mask);
++
++ ering->cursor++;
++ ering->cursor %= ATA_ERING_SIZE;
++
++ ent = &ering->ring[ering->cursor];
++ ent->is_io = is_io;
++ ent->err_mask = err_mask;
++ ent->timestamp = get_jiffies_64();
++}
++
++static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering)
++{
++ struct ata_ering_entry *ent = &ering->ring[ering->cursor];
++ if (!ent->err_mask)
++ return NULL;
++ return ent;
++}
++
++static int ata_ering_map(struct ata_ering *ering,
++ int (*map_fn)(struct ata_ering_entry *, void *),
++ void *arg)
++{
++ int idx, rc = 0;
++ struct ata_ering_entry *ent;
++
++ idx = ering->cursor;
++ do {
++ ent = &ering->ring[idx];
++ if (!ent->err_mask)
++ break;
++ rc = map_fn(ent, arg);
++ if (rc)
++ break;
++ idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE;
++ } while (idx != ering->cursor);
++
++ return rc;
++}
++
++static unsigned int ata_eh_dev_action(struct ata_device *dev)
++{
++ struct ata_eh_context *ehc = &dev->ap->eh_context;
++
++ return ehc->i.action | ehc->i.dev_action[dev->devno];
++}
++
++static void ata_eh_clear_action(struct ata_device *dev,
++ struct ata_eh_info *ehi, unsigned int action)
++{
++ int i;
++
++ if (!dev) {
++ ehi->action &= ~action;
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ehi->dev_action[i] &= ~action;
++ } else {
++ /* doesn't make sense for port-wide EH actions */
++ WARN_ON(!(action & ATA_EH_PERDEV_MASK));
++
++ /* break ehi->action into ehi->dev_action */
++ if (ehi->action & action) {
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ehi->dev_action[i] |= ehi->action & action;
++ ehi->action &= ~action;
++ }
++
++ /* turn off the specified per-dev action */
++ ehi->dev_action[dev->devno] &= ~action;
++ }
++}
++
++/**
++ * ata_scsi_timed_out - SCSI layer time out callback
++ * @cmd: timed out SCSI command
++ *
++ * Handles SCSI layer timeout. We race with normal completion of
++ * the qc for @cmd. If the qc is already gone, we lose and let
++ * the scsi command finish (EH_HANDLED). Otherwise, the qc has
++ * timed out and EH should be invoked. Prevent ata_qc_complete()
++ * from finishing it by setting EH_SCHEDULED and return
++ * EH_NOT_HANDLED.
++ *
++ * TODO: kill this function once old EH is gone.
++ *
++ * LOCKING:
++ * Called from timer context
++ *
++ * RETURNS:
++ * EH_HANDLED or EH_NOT_HANDLED
++ */
++enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct ata_port *ap = ata_shost_to_port(host);
++ unsigned long flags;
++ struct ata_queued_cmd *qc;
++ enum scsi_eh_timer_return ret;
++
++ DPRINTK("ENTER\n");
++
++ if (ap->ops->error_handler) {
++ ret = EH_NOT_HANDLED;
++ goto out;
++ }
++
++ ret = EH_HANDLED;
++ spin_lock_irqsave(ap->lock, flags);
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc) {
++ WARN_ON(qc->scsicmd != cmd);
++ qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
++ qc->err_mask |= AC_ERR_TIMEOUT;
++ ret = EH_NOT_HANDLED;
++ }
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ out:
++ DPRINTK("EXIT, ret=%d\n", ret);
++ return ret;
++}
++
++/**
++ * ata_scsi_error - SCSI layer error handler callback
++ * @host: SCSI host on which error occurred
++ *
++ * Handles SCSI-layer-thrown error events.
++ *
++ * LOCKING:
++ * Inherited from SCSI layer (none, can sleep)
++ *
++ * RETURNS:
++ * Zero.
++ */
++void ata_scsi_error(struct Scsi_Host *host)
++{
++ struct ata_port *ap = ata_shost_to_port(host);
++ int i, repeat_cnt = ATA_EH_MAX_REPEAT;
++ unsigned long flags;
++
++ DPRINTK("ENTER\n");
++
++ /* synchronize with port task */
++ ata_port_flush_task(ap);
++
++ /* synchronize with host lock and sort out timeouts */
++
++ /* For new EH, all qcs are finished in one of three ways -
++ * normal completion, error completion, and SCSI timeout.
++ * Both cmpletions can race against SCSI timeout. When normal
++ * completion wins, the qc never reaches EH. When error
++ * completion wins, the qc has ATA_QCFLAG_FAILED set.
++ *
++ * When SCSI timeout wins, things are a bit more complex.
++ * Normal or error completion can occur after the timeout but
++ * before this point. In such cases, both types of
++ * completions are honored. A scmd is determined to have
++ * timed out iff its associated qc is active and not failed.
++ */
++ if (ap->ops->error_handler) {
++ struct scsi_cmnd *scmd, *tmp;
++ int nr_timedout = 0;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
++ struct ata_queued_cmd *qc;
++
++ for (i = 0; i < ATA_MAX_QUEUE; i++) {
++ qc = __ata_qc_from_tag(ap, i);
++ if (qc->flags & ATA_QCFLAG_ACTIVE &&
++ qc->scsicmd == scmd)
++ break;
++ }
++
++ if (i < ATA_MAX_QUEUE) {
++ /* the scmd has an associated qc */
++ if (!(qc->flags & ATA_QCFLAG_FAILED)) {
++ /* which hasn't failed yet, timeout */
++ qc->err_mask |= AC_ERR_TIMEOUT;
++ qc->flags |= ATA_QCFLAG_FAILED;
++ nr_timedout++;
++ }
++ } else {
++ /* Normal completion occurred after
++ * SCSI timeout but before this point.
++ * Successfully complete it.
++ */
++ scmd->retries = scmd->allowed;
++ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
++ }
++ }
++
++ /* If we have timed out qcs. They belong to EH from
++ * this point but the state of the controller is
++ * unknown. Freeze the port to make sure the IRQ
++ * handler doesn't diddle with those qcs. This must
++ * be done atomically w.r.t. setting QCFLAG_FAILED.
++ */
++ if (nr_timedout)
++ __ata_port_freeze(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++ } else
++ spin_unlock_wait(ap->lock);
++
++ repeat:
++ /* invoke error handler */
++ if (ap->ops->error_handler) {
++ /* process port resume request */
++ ata_eh_handle_port_resume(ap);
++
++ /* fetch & clear EH info */
++ spin_lock_irqsave(ap->lock, flags);
++
++ memset(&ap->eh_context, 0, sizeof(ap->eh_context));
++ ap->eh_context.i = ap->eh_info;
++ memset(&ap->eh_info, 0, sizeof(ap->eh_info));
++
++ ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
++ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* invoke EH, skip if unloading or suspended */
++ if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
++ ap->ops->error_handler(ap);
++ else
++ ata_eh_finish(ap);
++
++ /* process port suspend request */
++ ata_eh_handle_port_suspend(ap);
++
++ /* Exception might have happend after ->error_handler
++ * recovered the port but before this point. Repeat
++ * EH in such case.
++ */
++ spin_lock_irqsave(ap->lock, flags);
++
++ if (ap->pflags & ATA_PFLAG_EH_PENDING) {
++ if (--repeat_cnt) {
++ ata_port_printk(ap, KERN_INFO,
++ "EH pending after completion, "
++ "repeating EH (cnt=%d)\n", repeat_cnt);
++ spin_unlock_irqrestore(ap->lock, flags);
++ goto repeat;
++ }
++ ata_port_printk(ap, KERN_ERR, "EH pending after %d "
++ "tries, giving up\n", ATA_EH_MAX_REPEAT);
++ }
++
++ /* this run is complete, make sure EH info is clear */
++ memset(&ap->eh_info, 0, sizeof(ap->eh_info));
++
++ /* Clear host_eh_scheduled while holding ap->lock such
++ * that if exception occurs after this point but
++ * before EH completion, SCSI midlayer will
++ * re-initiate EH.
++ */
++ host->host_eh_scheduled = 0;
++
++ spin_unlock_irqrestore(ap->lock, flags);
++ } else {
++ WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
++ ap->ops->eng_timeout(ap);
++ }
++
++ /* finish or retry handled scmd's and clean up */
++ WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
++
++ scsi_eh_flush_done_q(&ap->eh_done_q);
++
++ /* clean up */
++ spin_lock_irqsave(ap->lock, flags);
++
++ if (ap->pflags & ATA_PFLAG_LOADING)
++ ap->pflags &= ~ATA_PFLAG_LOADING;
++ else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
++ queue_work(ata_aux_wq, &ap->hotplug_task);
++
++ if (ap->pflags & ATA_PFLAG_RECOVERED)
++ ata_port_printk(ap, KERN_INFO, "EH complete\n");
++
++ ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
++
++ /* tell wait_eh that we're done */
++ ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
++ wake_up_all(&ap->eh_wait_q);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_port_wait_eh - Wait for the currently pending EH to complete
++ * @ap: Port to wait EH for
++ *
++ * Wait until the currently pending EH is complete.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++void ata_port_wait_eh(struct ata_port *ap)
++{
++ unsigned long flags;
++ DEFINE_WAIT(wait);
++
++ retry:
++ spin_lock_irqsave(ap->lock, flags);
++
++ while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
++ prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
++ spin_unlock_irqrestore(ap->lock, flags);
++ schedule();
++ spin_lock_irqsave(ap->lock, flags);
++ }
++ finish_wait(&ap->eh_wait_q, &wait);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* make sure SCSI EH is complete */
++ if (scsi_host_in_recovery(ap->scsi_host)) {
++ msleep(10);
++ goto retry;
++ }
++}
++
++/**
++ * ata_qc_timeout - Handle timeout of queued command
++ * @qc: Command that timed out
++ *
++ * Some part of the kernel (currently, only the SCSI layer)
++ * has noticed that the active command on port @ap has not
++ * completed after a specified length of time. Handle this
++ * condition by disabling DMA (if necessary) and completing
++ * transactions, with error if necessary.
++ *
++ * This also handles the case of the "lost interrupt", where
++ * for some reason (possibly hardware bug, possibly driver bug)
++ * an interrupt was not delivered to the driver, even though the
++ * transaction completed successfully.
++ *
++ * TODO: kill this function once old EH is gone.
++ *
++ * LOCKING:
++ * Inherited from SCSI layer (none, can sleep)
++ */
++static void ata_qc_timeout(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ u8 host_stat = 0, drv_stat;
++ unsigned long flags;
++
++ DPRINTK("ENTER\n");
++
++ ap->hsm_task_state = HSM_ST_IDLE;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ switch (qc->tf.protocol) {
++
++ case ATA_PROT_DMA:
++ case ATA_PROT_ATAPI_DMA:
++ host_stat = ap->ops->bmdma_status(ap);
++
++ /* before we do anything else, clear DMA-Start bit */
++ ap->ops->bmdma_stop(qc);
++
++ /* fall through */
++
++ default:
++ ata_altstatus(ap);
++ drv_stat = ata_chk_status(ap);
++
++ /* ack bmdma irq events */
++ ap->ops->irq_clear(ap);
++
++ ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, "
++ "stat 0x%x host_stat 0x%x\n",
++ qc->tf.command, drv_stat, host_stat);
++
++ /* complete taskfile transaction */
++ qc->err_mask |= AC_ERR_TIMEOUT;
++ break;
++ }
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ ata_eh_qc_complete(qc);
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_eng_timeout - Handle timeout of queued command
++ * @ap: Port on which timed-out command is active
++ *
++ * Some part of the kernel (currently, only the SCSI layer)
++ * has noticed that the active command on port @ap has not
++ * completed after a specified length of time. Handle this
++ * condition by disabling DMA (if necessary) and completing
++ * transactions, with error if necessary.
++ *
++ * This also handles the case of the "lost interrupt", where
++ * for some reason (possibly hardware bug, possibly driver bug)
++ * an interrupt was not delivered to the driver, even though the
++ * transaction completed successfully.
++ *
++ * TODO: kill this function once old EH is gone.
++ *
++ * LOCKING:
++ * Inherited from SCSI layer (none, can sleep)
++ */
++void ata_eng_timeout(struct ata_port *ap)
++{
++ DPRINTK("ENTER\n");
++
++ ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_qc_schedule_eh - schedule qc for error handling
++ * @qc: command to schedule error handling for
++ *
++ * Schedule error handling for @qc. EH will kick in as soon as
++ * other commands are drained.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ WARN_ON(!ap->ops->error_handler);
++
++ qc->flags |= ATA_QCFLAG_FAILED;
++ qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
++
++ /* The following will fail if timeout has already expired.
++ * ata_scsi_error() takes care of such scmds on EH entry.
++ * Note that ATA_QCFLAG_FAILED is unconditionally set after
++ * this function completes.
++ */
++ scsi_req_abort_cmd(qc->scsicmd);
++}
++
++/**
++ * ata_port_schedule_eh - schedule error handling without a qc
++ * @ap: ATA port to schedule EH for
++ *
++ * Schedule error handling for @ap. EH will kick in as soon as
++ * all commands are drained.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_port_schedule_eh(struct ata_port *ap)
++{
++ WARN_ON(!ap->ops->error_handler);
++
++ ap->pflags |= ATA_PFLAG_EH_PENDING;
++ scsi_schedule_eh(ap->scsi_host);
++
++ DPRINTK("port EH scheduled\n");
++}
++
++/**
++ * ata_port_abort - abort all qc's on the port
++ * @ap: ATA port to abort qc's for
++ *
++ * Abort all active qc's of @ap and schedule EH.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Number of aborted qc's.
++ */
++int ata_port_abort(struct ata_port *ap)
++{
++ int tag, nr_aborted = 0;
++
++ WARN_ON(!ap->ops->error_handler);
++
++ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
++ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
++
++ if (qc) {
++ qc->flags |= ATA_QCFLAG_FAILED;
++ ata_qc_complete(qc);
++ nr_aborted++;
++ }
++ }
++
++ if (!nr_aborted)
++ ata_port_schedule_eh(ap);
++
++ return nr_aborted;
++}
++
++/**
++ * __ata_port_freeze - freeze port
++ * @ap: ATA port to freeze
++ *
++ * This function is called when HSM violation or some other
++ * condition disrupts normal operation of the port. Frozen port
++ * is not allowed to perform any operation until the port is
++ * thawed, which usually follows a successful reset.
++ *
++ * ap->ops->freeze() callback can be used for freezing the port
++ * hardware-wise (e.g. mask interrupt and stop DMA engine). If a
++ * port cannot be frozen hardware-wise, the interrupt handler
++ * must ack and clear interrupts unconditionally while the port
++ * is frozen.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++static void __ata_port_freeze(struct ata_port *ap)
++{
++ WARN_ON(!ap->ops->error_handler);
++
++ if (ap->ops->freeze)
++ ap->ops->freeze(ap);
++
++ ap->pflags |= ATA_PFLAG_FROZEN;
++
++ DPRINTK("ata%u port frozen\n", ap->id);
++}
++
++/**
++ * ata_port_freeze - abort & freeze port
++ * @ap: ATA port to freeze
++ *
++ * Abort and freeze @ap.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Number of aborted commands.
++ */
++int ata_port_freeze(struct ata_port *ap)
++{
++ int nr_aborted;
++
++ WARN_ON(!ap->ops->error_handler);
++
++ nr_aborted = ata_port_abort(ap);
++ __ata_port_freeze(ap);
++
++ return nr_aborted;
++}
++
++/**
++ * ata_eh_freeze_port - EH helper to freeze port
++ * @ap: ATA port to freeze
++ *
++ * Freeze @ap.
++ *
++ * LOCKING:
++ * None.
++ */
++void ata_eh_freeze_port(struct ata_port *ap)
++{
++ unsigned long flags;
++
++ if (!ap->ops->error_handler)
++ return;
++
++ spin_lock_irqsave(ap->lock, flags);
++ __ata_port_freeze(ap);
++ spin_unlock_irqrestore(ap->lock, flags);
++}
++
++/**
++ * ata_port_thaw_port - EH helper to thaw port
++ * @ap: ATA port to thaw
++ *
++ * Thaw frozen port @ap.
++ *
++ * LOCKING:
++ * None.
++ */
++void ata_eh_thaw_port(struct ata_port *ap)
++{
++ unsigned long flags;
++
++ if (!ap->ops->error_handler)
++ return;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ ap->pflags &= ~ATA_PFLAG_FROZEN;
++
++ if (ap->ops->thaw)
++ ap->ops->thaw(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ DPRINTK("ata%u port thawed\n", ap->id);
++}
++
++static void ata_eh_scsidone(struct scsi_cmnd *scmd)
++{
++ /* nada */
++}
++
++static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct scsi_cmnd *scmd = qc->scsicmd;
++ unsigned long flags;
++
++ spin_lock_irqsave(ap->lock, flags);
++ qc->scsidone = ata_eh_scsidone;
++ __ata_qc_complete(qc);
++ WARN_ON(ata_tag_valid(qc->tag));
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
++}
++
++/**
++ * ata_eh_qc_complete - Complete an active ATA command from EH
++ * @qc: Command to complete
++ *
++ * Indicate to the mid and upper layers that an ATA command has
++ * completed. To be used from EH.
++ */
++void ata_eh_qc_complete(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *scmd = qc->scsicmd;
++ scmd->retries = scmd->allowed;
++ __ata_eh_qc_complete(qc);
++}
++
++/**
++ * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
++ * @qc: Command to retry
++ *
++ * Indicate to the mid and upper layers that an ATA command
++ * should be retried. To be used from EH.
++ *
++ * SCSI midlayer limits the number of retries to scmd->allowed.
++ * scmd->retries is decremented for commands which get retried
++ * due to unrelated failures (qc->err_mask is zero).
++ */
++void ata_eh_qc_retry(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *scmd = qc->scsicmd;
++ if (!qc->err_mask && scmd->retries)
++ scmd->retries--;
++ __ata_eh_qc_complete(qc);
++}
++
++/**
++ * ata_eh_detach_dev - detach ATA device
++ * @dev: ATA device to detach
++ *
++ * Detach @dev.
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_eh_detach_dev(struct ata_device *dev)
++{
++ struct ata_port *ap = dev->ap;
++ unsigned long flags;
++
++ ata_dev_disable(dev);
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ dev->flags &= ~ATA_DFLAG_DETACH;
++
++ if (ata_scsi_offline_dev(dev)) {
++ dev->flags |= ATA_DFLAG_DETACHED;
++ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
++ }
++
++ /* clear per-dev EH actions */
++ ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
++ ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++}
++
++/**
++ * ata_eh_about_to_do - about to perform eh_action
++ * @ap: target ATA port
++ * @dev: target ATA dev for per-dev action (can be NULL)
++ * @action: action about to be performed
++ *
++ * Called just before performing EH actions to clear related bits
++ * in @ap->eh_info such that eh actions are not unnecessarily
++ * repeated.
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
++ unsigned int action)
++{
++ unsigned long flags;
++ struct ata_eh_info *ehi = &ap->eh_info;
++ struct ata_eh_context *ehc = &ap->eh_context;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* Reset is represented by combination of actions and EHI
++ * flags. Suck in all related bits before clearing eh_info to
++ * avoid losing requested action.
++ */
++ if (action & ATA_EH_RESET_MASK) {
++ ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
++ ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
++
++ /* make sure all reset actions are cleared & clear EHI flags */
++ action |= ATA_EH_RESET_MASK;
++ ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
++ }
++
++ ata_eh_clear_action(dev, ehi, action);
++
++ if (!(ehc->i.flags & ATA_EHI_QUIET))
++ ap->pflags |= ATA_PFLAG_RECOVERED;
++
++ spin_unlock_irqrestore(ap->lock, flags);
++}
++
++/**
++ * ata_eh_done - EH action complete
++ * @ap: target ATA port
++ * @dev: target ATA dev for per-dev action (can be NULL)
++ * @action: action just completed
++ *
++ * Called right after performing EH actions to clear related bits
++ * in @ap->eh_context.
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
++ unsigned int action)
++{
++ /* if reset is complete, clear all reset actions & reset modifier */
++ if (action & ATA_EH_RESET_MASK) {
++ action |= ATA_EH_RESET_MASK;
++ ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
++ }
++
++ ata_eh_clear_action(dev, &ap->eh_context.i, action);
++}
++
++/**
++ * ata_err_string - convert err_mask to descriptive string
++ * @err_mask: error mask to convert to string
++ *
++ * Convert @err_mask to descriptive string. Errors are
++ * prioritized according to severity and only the most severe
++ * error is reported.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * Descriptive string for @err_mask
++ */
++static const char * ata_err_string(unsigned int err_mask)
++{
++ if (err_mask & AC_ERR_HOST_BUS)
++ return "host bus error";
++ if (err_mask & AC_ERR_ATA_BUS)
++ return "ATA bus error";
++ if (err_mask & AC_ERR_TIMEOUT)
++ return "timeout";
++ if (err_mask & AC_ERR_HSM)
++ return "HSM violation";
++ if (err_mask & AC_ERR_SYSTEM)
++ return "internal error";
++ if (err_mask & AC_ERR_MEDIA)
++ return "media error";
++ if (err_mask & AC_ERR_INVALID)
++ return "invalid argument";
++ if (err_mask & AC_ERR_DEV)
++ return "device error";
++ return "unknown error";
++}
++
++/**
++ * ata_read_log_page - read a specific log page
++ * @dev: target device
++ * @page: page to read
++ * @buf: buffer to store read page
++ * @sectors: number of sectors to read
++ *
++ * Read log page using READ_LOG_EXT command.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, AC_ERR_* mask otherwise.
++ */
++static unsigned int ata_read_log_page(struct ata_device *dev,
++ u8 page, void *buf, unsigned int sectors)
++{
++ struct ata_taskfile tf;
++ unsigned int err_mask;
++
++ DPRINTK("read log page - page %d\n", page);
++
++ ata_tf_init(dev, &tf);
++ tf.command = ATA_CMD_READ_LOG_EXT;
++ tf.lbal = page;
++ tf.nsect = sectors;
++ tf.hob_nsect = sectors >> 8;
++ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
++ tf.protocol = ATA_PROT_PIO;
++
++ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
++ buf, sectors * ATA_SECT_SIZE);
++
++ DPRINTK("EXIT, err_mask=%x\n", err_mask);
++ return err_mask;
++}
++
++/**
++ * ata_eh_read_log_10h - Read log page 10h for NCQ error details
++ * @dev: Device to read log page 10h from
++ * @tag: Resulting tag of the failed command
++ * @tf: Resulting taskfile registers of the failed command
++ *
++ * Read log page 10h to obtain NCQ error details and clear error
++ * condition.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++static int ata_eh_read_log_10h(struct ata_device *dev,
++ int *tag, struct ata_taskfile *tf)
++{
++ u8 *buf = dev->ap->sector_buf;
++ unsigned int err_mask;
++ u8 csum;
++ int i;
++
++ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
++ if (err_mask)
++ return -EIO;
++
++ csum = 0;
++ for (i = 0; i < ATA_SECT_SIZE; i++)
++ csum += buf[i];
++ if (csum)
++ ata_dev_printk(dev, KERN_WARNING,
++ "invalid checksum 0x%x on log page 10h\n", csum);
++
++ if (buf[0] & 0x80)
++ return -ENOENT;
++
++ *tag = buf[0] & 0x1f;
++
++ tf->command = buf[2];
++ tf->feature = buf[3];
++ tf->lbal = buf[4];
++ tf->lbam = buf[5];
++ tf->lbah = buf[6];
++ tf->device = buf[7];
++ tf->hob_lbal = buf[8];
++ tf->hob_lbam = buf[9];
++ tf->hob_lbah = buf[10];
++ tf->nsect = buf[12];
++ tf->hob_nsect = buf[13];
++
++ return 0;
++}
++
++/**
++ * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
++ * @dev: device to perform REQUEST_SENSE to
++ * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
++ *
++ * Perform ATAPI REQUEST_SENSE after the device reported CHECK
++ * SENSE. This function is EH helper.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, AC_ERR_* mask on failure
++ */
++static unsigned int atapi_eh_request_sense(struct ata_device *dev,
++ unsigned char *sense_buf)
++{
++ struct ata_port *ap = dev->ap;
++ struct ata_taskfile tf;
++ u8 cdb[ATAPI_CDB_LEN];
++
++ DPRINTK("ATAPI request sense\n");
++
++ ata_tf_init(dev, &tf);
++
++ /* FIXME: is this needed? */
++ memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
++
++ /* XXX: why tf_read here? */
++ ap->ops->tf_read(ap, &tf);
++
++ /* fill these in, for the case where they are -not- overwritten */
++ sense_buf[0] = 0x70;
++ sense_buf[2] = tf.feature >> 4;
++
++ memset(cdb, 0, ATAPI_CDB_LEN);
++ cdb[0] = REQUEST_SENSE;
++ cdb[4] = SCSI_SENSE_BUFFERSIZE;
++
++ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++ tf.command = ATA_CMD_PACKET;
++
++ /* is it pointless to prefer PIO for "safety reasons"? */
++ if (ap->flags & ATA_FLAG_PIO_DMA) {
++ tf.protocol = ATA_PROT_ATAPI_DMA;
++ tf.feature |= ATAPI_PKT_DMA;
++ } else {
++ tf.protocol = ATA_PROT_ATAPI;
++ tf.lbam = (8 * 1024) & 0xff;
++ tf.lbah = (8 * 1024) >> 8;
++ }
++
++ return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
++ sense_buf, SCSI_SENSE_BUFFERSIZE);
++}
++
++/**
++ * ata_eh_analyze_serror - analyze SError for a failed port
++ * @ap: ATA port to analyze SError for
++ *
++ * Analyze SError if available and further determine cause of
++ * failure.
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_eh_analyze_serror(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ u32 serror = ehc->i.serror;
++ unsigned int err_mask = 0, action = 0;
++
++ if (serror & SERR_PERSISTENT) {
++ err_mask |= AC_ERR_ATA_BUS;
++ action |= ATA_EH_HARDRESET;
++ }
++ if (serror &
++ (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
++ err_mask |= AC_ERR_ATA_BUS;
++ action |= ATA_EH_SOFTRESET;
++ }
++ if (serror & SERR_PROTOCOL) {
++ err_mask |= AC_ERR_HSM;
++ action |= ATA_EH_SOFTRESET;
++ }
++ if (serror & SERR_INTERNAL) {
++ err_mask |= AC_ERR_SYSTEM;
++ action |= ATA_EH_SOFTRESET;
++ }
++ if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
++ ata_ehi_hotplugged(&ehc->i);
++
++ ehc->i.err_mask |= err_mask;
++ ehc->i.action |= action;
++}
++
++/**
++ * ata_eh_analyze_ncq_error - analyze NCQ error
++ * @ap: ATA port to analyze NCQ error for
++ *
++ * Read log page 10h, determine the offending qc and acquire
++ * error status TF. For NCQ device errors, all LLDDs have to do
++ * is setting AC_ERR_DEV in ehi->err_mask. This function takes
++ * care of the rest.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++static void ata_eh_analyze_ncq_error(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ struct ata_device *dev = ap->device;
++ struct ata_queued_cmd *qc;
++ struct ata_taskfile tf;
++ int tag, rc;
++
++ /* if frozen, we can't do much */
++ if (ap->pflags & ATA_PFLAG_FROZEN)
++ return;
++
++ /* is it NCQ device error? */
++ if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
++ return;
++
++ /* has LLDD analyzed already? */
++ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
++ qc = __ata_qc_from_tag(ap, tag);
++
++ if (!(qc->flags & ATA_QCFLAG_FAILED))
++ continue;
++
++ if (qc->err_mask)
++ return;
++ }
++
++ /* okay, this error is ours */
++ rc = ata_eh_read_log_10h(dev, &tag, &tf);
++ if (rc) {
++ ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
++ "(errno=%d)\n", rc);
++ return;
++ }
++
++ if (!(ap->sactive & (1 << tag))) {
++ ata_port_printk(ap, KERN_ERR, "log page 10h reported "
++ "inactive tag %d\n", tag);
++ return;
++ }
++
++ /* we've got the perpetrator, condemn it */
++ qc = __ata_qc_from_tag(ap, tag);
++ memcpy(&qc->result_tf, &tf, sizeof(tf));
++ qc->err_mask |= AC_ERR_DEV;
++ ehc->i.err_mask &= ~AC_ERR_DEV;
++}
++
++/**
++ * ata_eh_analyze_tf - analyze taskfile of a failed qc
++ * @qc: qc to analyze
++ * @tf: Taskfile registers to analyze
++ *
++ * Analyze taskfile of @qc and further determine cause of
++ * failure. This function also requests ATAPI sense data if
++ * avaliable.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * Determined recovery action
++ */
++static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
++ const struct ata_taskfile *tf)
++{
++ unsigned int tmp, action = 0;
++ u8 stat = tf->command, err = tf->feature;
++
++ if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) {
++ qc->err_mask |= AC_ERR_HSM;
++ return ATA_EH_SOFTRESET;
++ }
++
++ if (!(qc->err_mask & AC_ERR_DEV))
++ return 0;
++
++ switch (qc->dev->class) {
++ case ATA_DEV_ATA:
++ if (err & ATA_ICRC)
++ qc->err_mask |= AC_ERR_ATA_BUS;
++ if (err & ATA_UNC)
++ qc->err_mask |= AC_ERR_MEDIA;
++ if (err & ATA_IDNF)
++ qc->err_mask |= AC_ERR_INVALID;
++ break;
++
++ case ATA_DEV_ATAPI:
++ tmp = atapi_eh_request_sense(qc->dev,
++ qc->scsicmd->sense_buffer);
++ if (!tmp) {
++ /* ATA_QCFLAG_SENSE_VALID is used to tell
++ * atapi_qc_complete() that sense data is
++ * already valid.
++ *
++ * TODO: interpret sense data and set
++ * appropriate err_mask.
++ */
++ qc->flags |= ATA_QCFLAG_SENSE_VALID;
++ } else
++ qc->err_mask |= tmp;
++ }
++
++ if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
++ action |= ATA_EH_SOFTRESET;
++
++ return action;
++}
++
++static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent)
++{
++ if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT))
++ return 1;
++
++ if (ent->is_io) {
++ if (ent->err_mask & AC_ERR_HSM)
++ return 1;
++ if ((ent->err_mask &
++ (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
++ return 2;
++ }
++
++ return 0;
++}
++
++struct speed_down_needed_arg {
++ u64 since;
++ int nr_errors[3];
++};
++
++static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg)
++{
++ struct speed_down_needed_arg *arg = void_arg;
++
++ if (ent->timestamp < arg->since)
++ return -1;
++
++ arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++;
++ return 0;
++}
++
++/**
++ * ata_eh_speed_down_needed - Determine wheter speed down is necessary
++ * @dev: Device of interest
++ *
++ * This function examines error ring of @dev and determines
++ * whether speed down is necessary. Speed down is necessary if
++ * there have been more than 3 of Cat-1 errors or 10 of Cat-2
++ * errors during last 15 minutes.
++ *
++ * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM
++ * violation for known supported commands.
++ *
++ * Cat-2 errors are unclassified DEV error for known supported
++ * command.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ *
++ * RETURNS:
++ * 1 if speed down is necessary, 0 otherwise
++ */
++static int ata_eh_speed_down_needed(struct ata_device *dev)
++{
++ const u64 interval = 15LLU * 60 * HZ;
++ static const int err_limits[3] = { -1, 3, 10 };
++ struct speed_down_needed_arg arg;
++ struct ata_ering_entry *ent;
++ int err_cat;
++ u64 j64;
++
++ ent = ata_ering_top(&dev->ering);
++ if (!ent)
++ return 0;
++
++ err_cat = ata_eh_categorize_ering_entry(ent);
++ if (err_cat == 0)
++ return 0;
++
++ memset(&arg, 0, sizeof(arg));
++
++ j64 = get_jiffies_64();
++ if (j64 >= interval)
++ arg.since = j64 - interval;
++ else
++ arg.since = 0;
++
++ ata_ering_map(&dev->ering, speed_down_needed_cb, &arg);
++
++ return arg.nr_errors[err_cat] > err_limits[err_cat];
++}
++
++/**
++ * ata_eh_speed_down - record error and speed down if necessary
++ * @dev: Failed device
++ * @is_io: Did the device fail during normal IO?
++ * @err_mask: err_mask of the error
++ *
++ * Record error and examine error history to determine whether
++ * adjusting transmission speed is necessary. It also sets
++ * transmission limits appropriately if such adjustment is
++ * necessary.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise
++ */
++static int ata_eh_speed_down(struct ata_device *dev, int is_io,
++ unsigned int err_mask)
++{
++ if (!err_mask)
++ return 0;
++
++ /* record error and determine whether speed down is necessary */
++ ata_ering_record(&dev->ering, is_io, err_mask);
++
++ if (!ata_eh_speed_down_needed(dev))
++ return 0;
++
++ /* speed down SATA link speed if possible */
++ if (sata_down_spd_limit(dev->ap) == 0)
++ return ATA_EH_HARDRESET;
++
++ /* lower transfer mode */
++ if (ata_down_xfermask_limit(dev, 0) == 0)
++ return ATA_EH_SOFTRESET;
++
++ ata_dev_printk(dev, KERN_ERR,
++ "speed down requested but no transfer mode left\n");
++ return 0;
++}
++
++/**
++ * ata_eh_autopsy - analyze error and determine recovery action
++ * @ap: ATA port to perform autopsy on
++ *
++ * Analyze why @ap failed and determine which recovery action is
++ * needed. This function also sets more detailed AC_ERR_* values
++ * and fills sense data for ATAPI CHECK SENSE.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++static void ata_eh_autopsy(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ unsigned int all_err_mask = 0;
++ int tag, is_io = 0;
++ u32 serror;
++ int rc;
++
++ DPRINTK("ENTER\n");
++
++ if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
++ return;
++
++ /* obtain and analyze SError */
++ rc = sata_scr_read(ap, SCR_ERROR, &serror);
++ if (rc == 0) {
++ ehc->i.serror |= serror;
++ ata_eh_analyze_serror(ap);
++ } else if (rc != -EOPNOTSUPP)
++ ehc->i.action |= ATA_EH_HARDRESET;
++
++ /* analyze NCQ failure */
++ ata_eh_analyze_ncq_error(ap);
++
++ /* any real error trumps AC_ERR_OTHER */
++ if (ehc->i.err_mask & ~AC_ERR_OTHER)
++ ehc->i.err_mask &= ~AC_ERR_OTHER;
++
++ all_err_mask |= ehc->i.err_mask;
++
++ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
++ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
++
++ if (!(qc->flags & ATA_QCFLAG_FAILED))
++ continue;
++
++ /* inherit upper level err_mask */
++ qc->err_mask |= ehc->i.err_mask;
++
++ /* analyze TF */
++ ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
++
++ /* DEV errors are probably spurious in case of ATA_BUS error */
++ if (qc->err_mask & AC_ERR_ATA_BUS)
++ qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA |
++ AC_ERR_INVALID);
++
++ /* any real error trumps unknown error */
++ if (qc->err_mask & ~AC_ERR_OTHER)
++ qc->err_mask &= ~AC_ERR_OTHER;
++
++ /* SENSE_VALID trumps dev/unknown error and revalidation */
++ if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
++ qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
++ ehc->i.action &= ~ATA_EH_REVALIDATE;
++ }
++
++ /* accumulate error info */
++ ehc->i.dev = qc->dev;
++ all_err_mask |= qc->err_mask;
++ if (qc->flags & ATA_QCFLAG_IO)
++ is_io = 1;
++ }
++
++ /* enforce default EH actions */
++ if (ap->pflags & ATA_PFLAG_FROZEN ||
++ all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
++ ehc->i.action |= ATA_EH_SOFTRESET;
++ else if (all_err_mask)
++ ehc->i.action |= ATA_EH_REVALIDATE;
++
++ /* if we have offending qcs and the associated failed device */
++ if (ehc->i.dev) {
++ /* speed down */
++ ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
++ all_err_mask);
++
++ /* perform per-dev EH action only on the offending device */
++ ehc->i.dev_action[ehc->i.dev->devno] |=
++ ehc->i.action & ATA_EH_PERDEV_MASK;
++ ehc->i.action &= ~ATA_EH_PERDEV_MASK;
++ }
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_eh_report - report error handling to user
++ * @ap: ATA port EH is going on
++ *
++ * Report EH to user.
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_eh_report(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ const char *frozen, *desc;
++ int tag, nr_failed = 0;
++
++ desc = NULL;
++ if (ehc->i.desc[0] != '\0')
++ desc = ehc->i.desc;
++
++ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
++ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
++
++ if (!(qc->flags & ATA_QCFLAG_FAILED))
++ continue;
++ if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
++ continue;
++
++ nr_failed++;
++ }
++
++ if (!nr_failed && !ehc->i.err_mask)
++ return;
++
++ frozen = "";
++ if (ap->pflags & ATA_PFLAG_FROZEN)
++ frozen = " frozen";
++
++ if (ehc->i.dev) {
++ ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
++ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
++ ehc->i.err_mask, ap->sactive, ehc->i.serror,
++ ehc->i.action, frozen);
++ if (desc)
++ ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
++ } else {
++ ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
++ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
++ ehc->i.err_mask, ap->sactive, ehc->i.serror,
++ ehc->i.action, frozen);
++ if (desc)
++ ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
++ }
++
++ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
++ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
++
++ if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
++ continue;
++
++ ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
++ "Emask 0x%x stat 0x%x err 0x%x (%s)\n",
++ qc->tag, qc->tf.command, qc->err_mask,
++ qc->result_tf.command, qc->result_tf.feature,
++ ata_err_string(qc->err_mask));
++ }
++}
++
++static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
++ unsigned int *classes)
++{
++ int i, rc;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ classes[i] = ATA_DEV_UNKNOWN;
++
++ rc = reset(ap, classes);
++ if (rc)
++ return rc;
++
++ /* If any class isn't ATA_DEV_UNKNOWN, consider classification
++ * is complete and convert all ATA_DEV_UNKNOWN to
++ * ATA_DEV_NONE.
++ */
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ if (classes[i] != ATA_DEV_UNKNOWN)
++ break;
++
++ if (i < ATA_MAX_DEVICES)
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ if (classes[i] == ATA_DEV_UNKNOWN)
++ classes[i] = ATA_DEV_NONE;
++
++ return 0;
++}
++
++static int ata_eh_followup_srst_needed(int rc, int classify,
++ const unsigned int *classes)
++{
++ if (rc == -EAGAIN)
++ return 1;
++ if (rc != 0)
++ return 0;
++ if (classify && classes[0] == ATA_DEV_UNKNOWN)
++ return 1;
++ return 0;
++}
++
++static int ata_eh_reset(struct ata_port *ap, int classify,
++ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
++ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ unsigned int *classes = ehc->classes;
++ int tries = ATA_EH_RESET_TRIES;
++ int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
++ unsigned int action;
++ ata_reset_fn_t reset;
++ int i, did_followup_srst, rc;
++
++ /* about to reset */
++ ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
++
++ /* Determine which reset to use and record in ehc->i.action.
++ * prereset() may examine and modify it.
++ */
++ action = ehc->i.action;
++ ehc->i.action &= ~ATA_EH_RESET_MASK;
++ if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
++ !(action & ATA_EH_HARDRESET))))
++ ehc->i.action |= ATA_EH_SOFTRESET;
++ else
++ ehc->i.action |= ATA_EH_HARDRESET;
++
++ if (prereset) {
++ rc = prereset(ap);
++ if (rc) {
++ if (rc == -ENOENT) {
++ ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n");
++ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
++ } else
++ ata_port_printk(ap, KERN_ERR,
++ "prereset failed (errno=%d)\n", rc);
++ return rc;
++ }
++ }
++
++ /* prereset() might have modified ehc->i.action */
++ if (ehc->i.action & ATA_EH_HARDRESET)
++ reset = hardreset;
++ else if (ehc->i.action & ATA_EH_SOFTRESET)
++ reset = softreset;
++ else {
++ /* prereset told us not to reset, bang classes and return */
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ classes[i] = ATA_DEV_NONE;
++ return 0;
++ }
++
++ /* did prereset() screw up? if so, fix up to avoid oopsing */
++ if (!reset) {
++ ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
++ "invalid reset type\n");
++ if (softreset)
++ reset = softreset;
++ else
++ reset = hardreset;
++ }
++
++ retry:
++ /* shut up during boot probing */
++ if (verbose)
++ ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
++ reset == softreset ? "soft" : "hard");
++
++ /* mark that this EH session started with reset */
++ ehc->i.flags |= ATA_EHI_DID_RESET;
++
++ rc = ata_do_reset(ap, reset, classes);
++
++ did_followup_srst = 0;
++ if (reset == hardreset &&
++ ata_eh_followup_srst_needed(rc, classify, classes)) {
++ /* okay, let's do follow-up softreset */
++ did_followup_srst = 1;
++ reset = softreset;
++
++ if (!reset) {
++ ata_port_printk(ap, KERN_ERR,
++ "follow-up softreset required "
++ "but no softreset avaliable\n");
++ return -EINVAL;
++ }
++
++ ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
++ rc = ata_do_reset(ap, reset, classes);
++
++ if (rc == 0 && classify &&
++ classes[0] == ATA_DEV_UNKNOWN) {
++ ata_port_printk(ap, KERN_ERR,
++ "classification failed\n");
++ return -EINVAL;
++ }
++ }
++
++ if (rc && --tries) {
++ const char *type;
++
++ if (reset == softreset) {
++ if (did_followup_srst)
++ type = "follow-up soft";
++ else
++ type = "soft";
++ } else
++ type = "hard";
++
++ ata_port_printk(ap, KERN_WARNING,
++ "%sreset failed, retrying in 5 secs\n", type);
++ ssleep(5);
++
++ if (reset == hardreset)
++ sata_down_spd_limit(ap);
++ if (hardreset)
++ reset = hardreset;
++ goto retry;
++ }
++
++ if (rc == 0) {
++ /* After the reset, the device state is PIO 0 and the
++ * controller state is undefined. Record the mode.
++ */
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ap->device[i].pio_mode = XFER_PIO_0;
++
++ if (postreset)
++ postreset(ap, classes);
++
++ /* reset successful, schedule revalidation */
++ ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
++ ehc->i.action |= ATA_EH_REVALIDATE;
++ }
++
++ return rc;
++}
++
++static int ata_eh_revalidate_and_attach(struct ata_port *ap,
++ struct ata_device **r_failed_dev)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ struct ata_device *dev;
++ unsigned long flags;
++ int i, rc = 0;
++
++ DPRINTK("ENTER\n");
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ unsigned int action;
++
++ dev = &ap->device[i];
++ action = ata_eh_dev_action(dev);
++
++ if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
++ if (ata_port_offline(ap)) {
++ rc = -EIO;
++ break;
++ }
++
++ ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
++ rc = ata_dev_revalidate(dev,
++ ehc->i.flags & ATA_EHI_DID_RESET);
++ if (rc)
++ break;
++
++ ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
++
++ /* schedule the scsi_rescan_device() here */
++ queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
++ } else if (dev->class == ATA_DEV_UNKNOWN &&
++ ehc->tries[dev->devno] &&
++ ata_class_enabled(ehc->classes[dev->devno])) {
++ dev->class = ehc->classes[dev->devno];
++
++ rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
++ if (rc == 0)
++ rc = ata_dev_configure(dev, 1);
++
++ if (rc) {
++ dev->class = ATA_DEV_UNKNOWN;
++ break;
++ }
++
++ spin_lock_irqsave(ap->lock, flags);
++ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
++ spin_unlock_irqrestore(ap->lock, flags);
++ }
++ }
++
++ if (rc)
++ *r_failed_dev = dev;
++
++ DPRINTK("EXIT\n");
++ return rc;
++}
++
++/**
++ * ata_eh_suspend - handle suspend EH action
++ * @ap: target host port
++ * @r_failed_dev: result parameter to indicate failing device
++ *
++ * Handle suspend EH action. Disk devices are spinned down and
++ * other types of devices are just marked suspended. Once
++ * suspended, no EH action to the device is allowed until it is
++ * resumed.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise
++ */
++static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
++{
++ struct ata_device *dev;
++ int i, rc = 0;
++
++ DPRINTK("ENTER\n");
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ unsigned long flags;
++ unsigned int action, err_mask;
++
++ dev = &ap->device[i];
++ action = ata_eh_dev_action(dev);
++
++ if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
++ continue;
++
++ WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
++
++ ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
++
++ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
++ /* flush cache */
++ rc = ata_flush_cache(dev);
++ if (rc)
++ break;
++
++ /* spin down */
++ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
++ if (err_mask) {
++ ata_dev_printk(dev, KERN_ERR, "failed to "
++ "spin down (err_mask=0x%x)\n",
++ err_mask);
++ rc = -EIO;
++ break;
++ }
++ }
++
++ spin_lock_irqsave(ap->lock, flags);
++ dev->flags |= ATA_DFLAG_SUSPENDED;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ ata_eh_done(ap, dev, ATA_EH_SUSPEND);
++ }
++
++ if (rc)
++ *r_failed_dev = dev;
++
++ DPRINTK("EXIT\n");
++ return 0;
++}
++
++/**
++ * ata_eh_prep_resume - prep for resume EH action
++ * @ap: target host port
++ *
++ * Clear SUSPENDED in preparation for scheduled resume actions.
++ * This allows other parts of EH to access the devices being
++ * resumed.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++static void ata_eh_prep_resume(struct ata_port *ap)
++{
++ struct ata_device *dev;
++ unsigned long flags;
++ int i;
++
++ DPRINTK("ENTER\n");
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ unsigned int action;
++
++ dev = &ap->device[i];
++ action = ata_eh_dev_action(dev);
++
++ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
++ continue;
++
++ spin_lock_irqsave(ap->lock, flags);
++ dev->flags &= ~ATA_DFLAG_SUSPENDED;
++ spin_unlock_irqrestore(ap->lock, flags);
++ }
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_eh_resume - handle resume EH action
++ * @ap: target host port
++ * @r_failed_dev: result parameter to indicate failing device
++ *
++ * Handle resume EH action. Target devices are already reset and
++ * revalidated. Spinning up is the only operation left.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise
++ */
++static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
++{
++ struct ata_device *dev;
++ int i, rc = 0;
++
++ DPRINTK("ENTER\n");
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ unsigned int action, err_mask;
++
++ dev = &ap->device[i];
++ action = ata_eh_dev_action(dev);
++
++ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
++ continue;
++
++ ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
++
++ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
++ err_mask = ata_do_simple_cmd(dev,
++ ATA_CMD_IDLEIMMEDIATE);
++ if (err_mask) {
++ ata_dev_printk(dev, KERN_ERR, "failed to "
++ "spin up (err_mask=0x%x)\n",
++ err_mask);
++ rc = -EIO;
++ break;
++ }
++ }
++
++ ata_eh_done(ap, dev, ATA_EH_RESUME);
++ }
++
++ if (rc)
++ *r_failed_dev = dev;
++
++ DPRINTK("EXIT\n");
++ return 0;
++}
++
++static int ata_port_nr_enabled(struct ata_port *ap)
++{
++ int i, cnt = 0;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ if (ata_dev_enabled(&ap->device[i]))
++ cnt++;
++ return cnt;
++}
++
++static int ata_port_nr_vacant(struct ata_port *ap)
++{
++ int i, cnt = 0;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ if (ap->device[i].class == ATA_DEV_UNKNOWN)
++ cnt++;
++ return cnt;
++}
++
++static int ata_eh_skip_recovery(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ int i;
++
++ /* skip if all possible devices are suspended */
++ for (i = 0; i < ata_port_max_devices(ap); i++) {
++ struct ata_device *dev = &ap->device[i];
++
++ if (!(dev->flags & ATA_DFLAG_SUSPENDED))
++ break;
++ }
++
++ if (i == ata_port_max_devices(ap))
++ return 1;
++
++ /* thaw frozen port, resume link and recover failed devices */
++ if ((ap->pflags & ATA_PFLAG_FROZEN) ||
++ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
++ return 0;
++
++ /* skip if class codes for all vacant slots are ATA_DEV_NONE */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++
++ if (dev->class == ATA_DEV_UNKNOWN &&
++ ehc->classes[dev->devno] != ATA_DEV_NONE)
++ return 0;
++ }
++
++ return 1;
++}
++
++/**
++ * ata_eh_recover - recover host port after error
++ * @ap: host port to recover
++ * @prereset: prereset method (can be NULL)
++ * @softreset: softreset method (can be NULL)
++ * @hardreset: hardreset method (can be NULL)
++ * @postreset: postreset method (can be NULL)
++ *
++ * This is the alpha and omega, eum and yang, heart and soul of
++ * libata exception handling. On entry, actions required to
++ * recover the port and hotplug requests are recorded in
++ * eh_context. This function executes all the operations with
++ * appropriate retrials and fallbacks to resurrect failed
++ * devices, detach goners and greet newcomers.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno on failure.
++ */
++static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
++ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
++ ata_postreset_fn_t postreset)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ struct ata_device *dev;
++ int down_xfermask, i, rc;
++
++ DPRINTK("ENTER\n");
++
++ /* prep for recovery */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++
++ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
++
++ /* process hotplug request */
++ if (dev->flags & ATA_DFLAG_DETACH)
++ ata_eh_detach_dev(dev);
++
++ if (!ata_dev_enabled(dev) &&
++ ((ehc->i.probe_mask & (1 << dev->devno)) &&
++ !(ehc->did_probe_mask & (1 << dev->devno)))) {
++ ata_eh_detach_dev(dev);
++ ata_dev_init(dev);
++ ehc->did_probe_mask |= (1 << dev->devno);
++ ehc->i.action |= ATA_EH_SOFTRESET;
++ }
++ }
++
++ retry:
++ down_xfermask = 0;
++ rc = 0;
++
++ /* if UNLOADING, finish immediately */
++ if (ap->pflags & ATA_PFLAG_UNLOADING)
++ goto out;
++
++ /* prep for resume */
++ ata_eh_prep_resume(ap);
++
++ /* skip EH if possible. */
++ if (ata_eh_skip_recovery(ap))
++ ehc->i.action = 0;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ehc->classes[i] = ATA_DEV_UNKNOWN;
++
++ /* reset */
++ if (ehc->i.action & ATA_EH_RESET_MASK) {
++ ata_eh_freeze_port(ap);
++
++ rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
++ softreset, hardreset, postreset);
++ if (rc) {
++ ata_port_printk(ap, KERN_ERR,
++ "reset failed, giving up\n");
++ goto out;
++ }
++
++ ata_eh_thaw_port(ap);
++ }
++
++ /* revalidate existing devices and attach new ones */
++ rc = ata_eh_revalidate_and_attach(ap, &dev);
++ if (rc)
++ goto dev_fail;
++
++ /* resume devices */
++ rc = ata_eh_resume(ap, &dev);
++ if (rc)
++ goto dev_fail;
++
++ /* configure transfer mode if the port has been reset */
++ if (ehc->i.flags & ATA_EHI_DID_RESET) {
++ rc = ata_set_mode(ap, &dev);
++ if (rc) {
++ down_xfermask = 1;
++ goto dev_fail;
++ }
++ }
++
++ /* suspend devices */
++ rc = ata_eh_suspend(ap, &dev);
++ if (rc)
++ goto dev_fail;
++
++ goto out;
++
++ dev_fail:
++ switch (rc) {
++ case -ENODEV:
++ /* device missing, schedule probing */
++ ehc->i.probe_mask |= (1 << dev->devno);
++ case -EINVAL:
++ ehc->tries[dev->devno] = 0;
++ break;
++ case -EIO:
++ sata_down_spd_limit(ap);
++ default:
++ ehc->tries[dev->devno]--;
++ if (down_xfermask &&
++ ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
++ ehc->tries[dev->devno] = 0;
++ }
++
++ if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
++ /* disable device if it has used up all its chances */
++ ata_dev_disable(dev);
++
++ /* detach if offline */
++ if (ata_port_offline(ap))
++ ata_eh_detach_dev(dev);
++
++ /* probe if requested */
++ if ((ehc->i.probe_mask & (1 << dev->devno)) &&
++ !(ehc->did_probe_mask & (1 << dev->devno))) {
++ ata_eh_detach_dev(dev);
++ ata_dev_init(dev);
++
++ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
++ ehc->did_probe_mask |= (1 << dev->devno);
++ ehc->i.action |= ATA_EH_SOFTRESET;
++ }
++ } else {
++ /* soft didn't work? be haaaaard */
++ if (ehc->i.flags & ATA_EHI_DID_RESET)
++ ehc->i.action |= ATA_EH_HARDRESET;
++ else
++ ehc->i.action |= ATA_EH_SOFTRESET;
++ }
++
++ if (ata_port_nr_enabled(ap)) {
++ ata_port_printk(ap, KERN_WARNING, "failed to recover some "
++ "devices, retrying in 5 secs\n");
++ ssleep(5);
++ } else {
++ /* no device left, repeat fast */
++ msleep(500);
++ }
++
++ goto retry;
++
++ out:
++ if (rc) {
++ for (i = 0; i < ATA_MAX_DEVICES; i++)
++ ata_dev_disable(&ap->device[i]);
++ }
++
++ DPRINTK("EXIT, rc=%d\n", rc);
++ return rc;
++}
++
++/**
++ * ata_eh_finish - finish up EH
++ * @ap: host port to finish EH for
++ *
++ * Recovery is complete. Clean up EH states and retry or finish
++ * failed qcs.
++ *
++ * LOCKING:
++ * None.
++ */
++static void ata_eh_finish(struct ata_port *ap)
++{
++ int tag;
++
++ /* retry or finish qcs */
++ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
++ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
++
++ if (!(qc->flags & ATA_QCFLAG_FAILED))
++ continue;
++
++ if (qc->err_mask) {
++ /* FIXME: Once EH migration is complete,
++ * generate sense data in this function,
++ * considering both err_mask and tf.
++ */
++ if (qc->err_mask & AC_ERR_INVALID)
++ ata_eh_qc_complete(qc);
++ else
++ ata_eh_qc_retry(qc);
++ } else {
++ if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
++ ata_eh_qc_complete(qc);
++ } else {
++ /* feed zero TF to sense generation */
++ memset(&qc->result_tf, 0, sizeof(qc->result_tf));
++ ata_eh_qc_retry(qc);
++ }
++ }
++ }
++}
++
++/**
++ * ata_do_eh - do standard error handling
++ * @ap: host port to handle error for
++ * @prereset: prereset method (can be NULL)
++ * @softreset: softreset method (can be NULL)
++ * @hardreset: hardreset method (can be NULL)
++ * @postreset: postreset method (can be NULL)
++ *
++ * Perform standard error handling sequence.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
++ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
++ ata_postreset_fn_t postreset)
++{
++ ata_eh_autopsy(ap);
++ ata_eh_report(ap);
++ ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
++ ata_eh_finish(ap);
++}
++
++/**
++ * ata_eh_handle_port_suspend - perform port suspend operation
++ * @ap: port to suspend
++ *
++ * Suspend @ap.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++static void ata_eh_handle_port_suspend(struct ata_port *ap)
++{
++ unsigned long flags;
++ int rc = 0;
++
++ /* are we suspending? */
++ spin_lock_irqsave(ap->lock, flags);
++ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
++ ap->pm_mesg.event == PM_EVENT_ON) {
++ spin_unlock_irqrestore(ap->lock, flags);
++ return;
++ }
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
++
++ /* suspend */
++ ata_eh_freeze_port(ap);
++
++ if (ap->ops->port_suspend)
++ rc = ap->ops->port_suspend(ap, ap->pm_mesg);
++
++ /* report result */
++ spin_lock_irqsave(ap->lock, flags);
++
++ ap->pflags &= ~ATA_PFLAG_PM_PENDING;
++ if (rc == 0)
++ ap->pflags |= ATA_PFLAG_SUSPENDED;
++ else
++ ata_port_schedule_eh(ap);
++
++ if (ap->pm_result) {
++ *ap->pm_result = rc;
++ ap->pm_result = NULL;
++ }
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ return;
++}
++
++/**
++ * ata_eh_handle_port_resume - perform port resume operation
++ * @ap: port to resume
++ *
++ * Resume @ap.
++ *
++ * This function also waits upto one second until all devices
++ * hanging off this port requests resume EH action. This is to
++ * prevent invoking EH and thus reset multiple times on resume.
++ *
++ * On DPM resume, where some of devices might not be resumed
++ * together, this may delay port resume upto one second, but such
++ * DPM resumes are rare and 1 sec delay isn't too bad.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++static void ata_eh_handle_port_resume(struct ata_port *ap)
++{
++ unsigned long timeout;
++ unsigned long flags;
++ int i, rc = 0;
++
++ /* are we resuming? */
++ spin_lock_irqsave(ap->lock, flags);
++ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
++ ap->pm_mesg.event != PM_EVENT_ON) {
++ spin_unlock_irqrestore(ap->lock, flags);
++ return;
++ }
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* spurious? */
++ if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
++ goto done;
++
++ if (ap->ops->port_resume)
++ rc = ap->ops->port_resume(ap);
++
++ /* give devices time to request EH */
++ timeout = jiffies + HZ; /* 1s max */
++ while (1) {
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ unsigned int action = ata_eh_dev_action(dev);
++
++ if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
++ !(action & ATA_EH_RESUME))
++ break;
++ }
++
++ if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
++ break;
++ msleep(10);
++ }
++
++ done:
++ spin_lock_irqsave(ap->lock, flags);
++ ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
++ if (ap->pm_result) {
++ *ap->pm_result = rc;
++ ap->pm_result = NULL;
++ }
++ spin_unlock_irqrestore(ap->lock, flags);
++}
+diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
+new file mode 100644
+index 0000000..7af2a4b
+--- /dev/null
++++ b/drivers/ata/libata-scsi.c
+@@ -0,0 +1,3364 @@
++/*
++ * libata-scsi.c - helper library for ATA
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
++ * Copyright 2003-2004 Jeff Garzik
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available from
++ * - http://www.t10.org/
++ * - http://www.t13.org/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/blkdev.h>
++#include <linux/spinlock.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_eh.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_tcq.h>
++#include <scsi/scsi_transport.h>
++#include <linux/libata.h>
++#include <linux/hdreg.h>
++#include <asm/uaccess.h>
++
++#include "libata.h"
++
++#define SECTOR_SIZE 512
++
++typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
++
++static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
++ const struct scsi_device *scsidev);
++static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
++ const struct scsi_device *scsidev);
++static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
++ unsigned int id, unsigned int lun);
++
++
++#define RW_RECOVERY_MPAGE 0x1
++#define RW_RECOVERY_MPAGE_LEN 12
++#define CACHE_MPAGE 0x8
++#define CACHE_MPAGE_LEN 20
++#define CONTROL_MPAGE 0xa
++#define CONTROL_MPAGE_LEN 12
++#define ALL_MPAGES 0x3f
++#define ALL_SUB_MPAGES 0xff
++
++
++static const u8 def_rw_recovery_mpage[] = {
++ RW_RECOVERY_MPAGE,
++ RW_RECOVERY_MPAGE_LEN - 2,
++ (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
++ (1 << 6), /* ARRE (auto read reallocation) */
++ 0, /* read retry count */
++ 0, 0, 0, 0,
++ 0, /* write retry count */
++ 0, 0, 0
++};
++
++static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = {
++ CACHE_MPAGE,
++ CACHE_MPAGE_LEN - 2,
++ 0, /* contains WCE, needs to be 0 for logic */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, /* contains DRA, needs to be 0 for logic */
++ 0, 0, 0, 0, 0, 0, 0
++};
++
++static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
++ CONTROL_MPAGE,
++ CONTROL_MPAGE_LEN - 2,
++ 2, /* DSENSE=0, GLTSD=1 */
++ 0, /* [QAM+QERR may be 1, see 05-359r1] */
++ 0, 0, 0, 0, 0xff, 0xff,
++ 0, 30 /* extended self test time, see 05-359r1 */
++};
++
++/*
++ * libata transport template. libata doesn't do real transport stuff.
++ * It just needs the eh_timed_out hook.
++ */
++struct scsi_transport_template ata_scsi_transport_template = {
++ .eh_strategy_handler = ata_scsi_error,
++ .eh_timed_out = ata_scsi_timed_out,
++ .user_scan = ata_scsi_user_scan,
++};
++
++
++static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
++{
++ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
++ /* "Invalid field in cbd" */
++ done(cmd);
++}
++
++/**
++ * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
++ * @sdev: SCSI device for which BIOS geometry is to be determined
++ * @bdev: block device associated with @sdev
++ * @capacity: capacity of SCSI device
++ * @geom: location to which geometry will be output
++ *
++ * Generic bios head/sector/cylinder calculator
++ * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS)
++ * mapping. Some situations may arise where the disk is not
++ * bootable if this is not used.
++ *
++ * LOCKING:
++ * Defined by the SCSI layer. We don't really care.
++ *
++ * RETURNS:
++ * Zero.
++ */
++int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
++ sector_t capacity, int geom[])
++{
++ geom[0] = 255;
++ geom[1] = 63;
++ sector_div(capacity, 255*63);
++ geom[2] = capacity;
++
++ return 0;
++}
++
++/**
++ * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
++ * @scsidev: Device to which we are issuing command
++ * @arg: User provided data for issuing command
++ *
++ * LOCKING:
++ * Defined by the SCSI layer. We don't really care.
++ *
++ * RETURNS:
++ * Zero on success, negative errno on error.
++ */
++
++int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
++{
++ int rc = 0;
++ u8 scsi_cmd[MAX_COMMAND_SIZE];
++ u8 args[4], *argbuf = NULL, *sensebuf = NULL;
++ int argsize = 0;
++ enum dma_data_direction data_dir;
++ int cmd_result;
++
++ if (arg == NULL)
++ return -EINVAL;
++
++ if (copy_from_user(args, arg, sizeof(args)))
++ return -EFAULT;
++
++ sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
++ if (!sensebuf)
++ return -ENOMEM;
++
++ memset(scsi_cmd, 0, sizeof(scsi_cmd));
++
++ if (args[3]) {
++ argsize = SECTOR_SIZE * args[3];
++ argbuf = kmalloc(argsize, GFP_KERNEL);
++ if (argbuf == NULL) {
++ rc = -ENOMEM;
++ goto error;
++ }
++
++ scsi_cmd[1] = (4 << 1); /* PIO Data-in */
++ scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
++ block count in sector count field */
++ data_dir = DMA_FROM_DEVICE;
++ } else {
++ scsi_cmd[1] = (3 << 1); /* Non-data */
++ scsi_cmd[2] = 0x20; /* cc but no off.line or data xfer */
++ data_dir = DMA_NONE;
++ }
++
++ scsi_cmd[0] = ATA_16;
++
++ scsi_cmd[4] = args[2];
++ if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
++ scsi_cmd[6] = args[3];
++ scsi_cmd[8] = args[1];
++ scsi_cmd[10] = 0x4f;
++ scsi_cmd[12] = 0xc2;
++ } else {
++ scsi_cmd[6] = args[1];
++ }
++ scsi_cmd[14] = args[0];
++
++ /* Good values for timeout and retries? Values below
++ from scsi_ioctl_send_command() for default case... */
++ cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
++ sensebuf, (10*HZ), 5, 0);
++
++ if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
++ u8 *desc = sensebuf + 8;
++ cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */
++
++ /* If we set cc then ATA pass-through will cause a
++ * check condition even if no error. Filter that. */
++ if (cmd_result & SAM_STAT_CHECK_CONDITION) {
++ struct scsi_sense_hdr sshdr;
++ scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
++ &sshdr);
++ if (sshdr.sense_key==0 &&
++ sshdr.asc==0 && sshdr.ascq==0)
++ cmd_result &= ~SAM_STAT_CHECK_CONDITION;
++ }
++
++ /* Send userspace a few ATA registers (same as drivers/ide) */
++ if (sensebuf[0] == 0x72 && /* format is "descriptor" */
++ desc[0] == 0x09 ) { /* code is "ATA Descriptor" */
++ args[0] = desc[13]; /* status */
++ args[1] = desc[3]; /* error */
++ args[2] = desc[5]; /* sector count (0:7) */
++ if (copy_to_user(arg, args, sizeof(args)))
++ rc = -EFAULT;
++ }
++ }
++
++
++ if (cmd_result) {
++ rc = -EIO;
++ goto error;
++ }
++
++ if ((argbuf)
++ && copy_to_user(arg + sizeof(args), argbuf, argsize))
++ rc = -EFAULT;
++error:
++ kfree(sensebuf);
++ kfree(argbuf);
++ return rc;
++}
++
++/**
++ * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
++ * @scsidev: Device to which we are issuing command
++ * @arg: User provided data for issuing command
++ *
++ * LOCKING:
++ * Defined by the SCSI layer. We don't really care.
++ *
++ * RETURNS:
++ * Zero on success, negative errno on error.
++ */
++int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
++{
++ int rc = 0;
++ u8 scsi_cmd[MAX_COMMAND_SIZE];
++ u8 args[7];
++ struct scsi_sense_hdr sshdr;
++
++ if (arg == NULL)
++ return -EINVAL;
++
++ if (copy_from_user(args, arg, sizeof(args)))
++ return -EFAULT;
++
++ memset(scsi_cmd, 0, sizeof(scsi_cmd));
++ scsi_cmd[0] = ATA_16;
++ scsi_cmd[1] = (3 << 1); /* Non-data */
++ /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
++ scsi_cmd[4] = args[1];
++ scsi_cmd[6] = args[2];
++ scsi_cmd[8] = args[3];
++ scsi_cmd[10] = args[4];
++ scsi_cmd[12] = args[5];
++ scsi_cmd[14] = args[0];
++
++ /* Good values for timeout and retries? Values below
++ from scsi_ioctl_send_command() for default case... */
++ if (scsi_execute_req(scsidev, scsi_cmd, DMA_NONE, NULL, 0, &sshdr,
++ (10*HZ), 5))
++ rc = -EIO;
++
++ /* Need code to retrieve data from check condition? */
++ return rc;
++}
++
++int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
++{
++ int val = -EINVAL, rc = -EINVAL;
++
++ switch (cmd) {
++ case ATA_IOC_GET_IO32:
++ val = 0;
++ if (copy_to_user(arg, &val, 1))
++ return -EFAULT;
++ return 0;
++
++ case ATA_IOC_SET_IO32:
++ val = (unsigned long) arg;
++ if (val != 0)
++ return -EINVAL;
++ return 0;
++
++ case HDIO_DRIVE_CMD:
++ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
++ return -EACCES;
++ return ata_cmd_ioctl(scsidev, arg);
++
++ case HDIO_DRIVE_TASK:
++ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
++ return -EACCES;
++ return ata_task_ioctl(scsidev, arg);
++
++ default:
++ rc = -ENOTTY;
++ break;
++ }
++
++ return rc;
++}
++
++/**
++ * ata_scsi_qc_new - acquire new ata_queued_cmd reference
++ * @dev: ATA device to which the new command is attached
++ * @cmd: SCSI command that originated this ATA command
++ * @done: SCSI command completion function
++ *
++ * Obtain a reference to an unused ata_queued_cmd structure,
++ * which is the basic libata structure representing a single
++ * ATA command sent to the hardware.
++ *
++ * If a command was available, fill in the SCSI-specific
++ * portions of the structure with information on the
++ * current command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Command allocated, or %NULL if none available.
++ */
++struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
++ struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
++{
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_new_init(dev);
++ if (qc) {
++ qc->scsicmd = cmd;
++ qc->scsidone = done;
++
++ if (cmd->use_sg) {
++ qc->__sg = (struct scatterlist *) cmd->request_buffer;
++ qc->n_elem = cmd->use_sg;
++ } else {
++ qc->__sg = &qc->sgent;
++ qc->n_elem = 1;
++ }
++ } else {
++ cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
++ done(cmd);
++ }
++
++ return qc;
++}
++
++/**
++ * ata_dump_status - user friendly display of error info
++ * @id: id of the port in question
++ * @tf: ptr to filled out taskfile
++ *
++ * Decode and dump the ATA error/status registers for the user so
++ * that they have some idea what really happened at the non
++ * make-believe layer.
++ *
++ * LOCKING:
++ * inherited from caller
++ */
++void ata_dump_status(unsigned id, struct ata_taskfile *tf)
++{
++ u8 stat = tf->command, err = tf->feature;
++
++ printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat);
++ if (stat & ATA_BUSY) {
++ printk("Busy }\n"); /* Data is not valid in this case */
++ } else {
++ if (stat & 0x40) printk("DriveReady ");
++ if (stat & 0x20) printk("DeviceFault ");
++ if (stat & 0x10) printk("SeekComplete ");
++ if (stat & 0x08) printk("DataRequest ");
++ if (stat & 0x04) printk("CorrectedError ");
++ if (stat & 0x02) printk("Index ");
++ if (stat & 0x01) printk("Error ");
++ printk("}\n");
++
++ if (err) {
++ printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err);
++ if (err & 0x04) printk("DriveStatusError ");
++ if (err & 0x80) {
++ if (err & 0x04) printk("BadCRC ");
++ else printk("Sector ");
++ }
++ if (err & 0x40) printk("UncorrectableError ");
++ if (err & 0x10) printk("SectorIdNotFound ");
++ if (err & 0x02) printk("TrackZeroNotFound ");
++ if (err & 0x01) printk("AddrMarkNotFound ");
++ printk("}\n");
++ }
++ }
++}
++
++/**
++ * ata_scsi_device_suspend - suspend ATA device associated with sdev
++ * @sdev: the SCSI device to suspend
++ * @mesg: target power management message
++ *
++ * Request suspend EH action on the ATA device associated with
++ * @sdev and wait for the operation to complete.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t mesg)
++{
++ struct ata_port *ap = ata_shost_to_port(sdev->host);
++ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
++ unsigned long flags;
++ unsigned int action;
++ int rc = 0;
++
++ if (!dev)
++ goto out;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* wait for the previous resume to complete */
++ while (dev->flags & ATA_DFLAG_SUSPENDED) {
++ spin_unlock_irqrestore(ap->lock, flags);
++ ata_port_wait_eh(ap);
++ spin_lock_irqsave(ap->lock, flags);
++ }
++
++ /* if @sdev is already detached, nothing to do */
++ if (sdev->sdev_state == SDEV_OFFLINE ||
++ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
++ goto out_unlock;
++
++ /* request suspend */
++ action = ATA_EH_SUSPEND;
++ if (mesg.event != PM_EVENT_SUSPEND)
++ action |= ATA_EH_PM_FREEZE;
++ ap->eh_info.dev_action[dev->devno] |= action;
++ ap->eh_info.flags |= ATA_EHI_QUIET;
++ ata_port_schedule_eh(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ /* wait for EH to do the job */
++ ata_port_wait_eh(ap);
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* If @sdev is still attached but the associated ATA device
++ * isn't suspended, the operation failed.
++ */
++ if (sdev->sdev_state != SDEV_OFFLINE &&
++ sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
++ !(dev->flags & ATA_DFLAG_SUSPENDED))
++ rc = -EIO;
++
++ out_unlock:
++ spin_unlock_irqrestore(ap->lock, flags);
++ out:
++ if (rc == 0)
++ sdev->sdev_gendev.power.power_state = mesg;
++ return rc;
++}
++
++/**
++ * ata_scsi_device_resume - resume ATA device associated with sdev
++ * @sdev: the SCSI device to resume
++ *
++ * Request resume EH action on the ATA device associated with
++ * @sdev and return immediately. This enables parallel
++ * wakeup/spinup of devices.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ *
++ * RETURNS:
++ * 0.
++ */
++int ata_scsi_device_resume(struct scsi_device *sdev)
++{
++ struct ata_port *ap = ata_shost_to_port(sdev->host);
++ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
++ struct ata_eh_info *ehi = &ap->eh_info;
++ unsigned long flags;
++ unsigned int action;
++
++ if (!dev)
++ goto out;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* if @sdev is already detached, nothing to do */
++ if (sdev->sdev_state == SDEV_OFFLINE ||
++ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
++ goto out_unlock;
++
++ /* request resume */
++ action = ATA_EH_RESUME;
++ if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
++ __ata_ehi_hotplugged(ehi);
++ else
++ action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
++ ehi->dev_action[dev->devno] |= action;
++
++ /* We don't want autopsy and verbose EH messages. Disable
++ * those if we're the only device on this link.
++ */
++ if (ata_port_max_devices(ap) == 1)
++ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
++
++ ata_port_schedule_eh(ap);
++
++ out_unlock:
++ spin_unlock_irqrestore(ap->lock, flags);
++ out:
++ sdev->sdev_gendev.power.power_state = PMSG_ON;
++ return 0;
++}
++
++/**
++ * ata_to_sense_error - convert ATA error to SCSI error
++ * @id: ATA device number
++ * @drv_stat: value contained in ATA status register
++ * @drv_err: value contained in ATA error register
++ * @sk: the sense key we'll fill out
++ * @asc: the additional sense code we'll fill out
++ * @ascq: the additional sense code qualifier we'll fill out
++ * @verbose: be verbose
++ *
++ * Converts an ATA error into a SCSI error. Fill out pointers to
++ * SK, ASC, and ASCQ bytes for later use in fixed or descriptor
++ * format sense blocks.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
++ u8 *ascq, int verbose)
++{
++ int i;
++
++ /* Based on the 3ware driver translation table */
++ static const unsigned char sense_table[][4] = {
++ /* BBD|ECC|ID|MAR */
++ {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
++ /* BBD|ECC|ID */
++ {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
++ /* ECC|MC|MARK */
++ {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error
++ /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */
++ {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error
++ /* MC|ID|ABRT|TRK0|MARK */
++ {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready
++ /* MCR|MARK */
++ {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready
++ /* Bad address mark */
++ {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field
++ /* TRK0 */
++ {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
++ /* Abort & !ICRC */
++ {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command
++ /* Media change request */
++ {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline
++ /* SRV */
++ {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found
++ /* Media change */
++ {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline
++ /* ECC */
++ {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error
++ /* BBD - block marked bad */
++ {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
++ {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
++ };
++ static const unsigned char stat_table[][4] = {
++ /* Must be first because BUSY means no other bits valid */
++ {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now
++ {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault
++ {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now
++ {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered
++ {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
++ };
++
++ /*
++ * Is this an error we can process/parse
++ */
++ if (drv_stat & ATA_BUSY) {
++ drv_err = 0; /* Ignore the err bits, they're invalid */
++ }
++
++ if (drv_err) {
++ /* Look for drv_err */
++ for (i = 0; sense_table[i][0] != 0xFF; i++) {
++ /* Look for best matches first */
++ if ((sense_table[i][0] & drv_err) ==
++ sense_table[i][0]) {
++ *sk = sense_table[i][1];
++ *asc = sense_table[i][2];
++ *ascq = sense_table[i][3];
++ goto translate_done;
++ }
++ }
++ /* No immediate match */
++ if (verbose)
++ printk(KERN_WARNING "ata%u: no sense translation for "
++ "error 0x%02x\n", id, drv_err);
++ }
++
++ /* Fall back to interpreting status bits */
++ for (i = 0; stat_table[i][0] != 0xFF; i++) {
++ if (stat_table[i][0] & drv_stat) {
++ *sk = stat_table[i][1];
++ *asc = stat_table[i][2];
++ *ascq = stat_table[i][3];
++ goto translate_done;
++ }
++ }
++ /* No error? Undecoded? */
++ if (verbose)
++ printk(KERN_WARNING "ata%u: no sense translation for "
++ "status: 0x%02x\n", id, drv_stat);
++
++ /* We need a sensible error return here, which is tricky, and one
++ that won't cause people to do things like return a disk wrongly */
++ *sk = ABORTED_COMMAND;
++ *asc = 0x00;
++ *ascq = 0x00;
++
++ translate_done:
++ if (verbose)
++ printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
++ "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
++ id, drv_stat, drv_err, *sk, *asc, *ascq);
++ return;
++}
++
++/*
++ * ata_gen_ata_desc_sense - Generate check condition sense block.
++ * @qc: Command that completed.
++ *
++ * This function is specific to the ATA descriptor format sense
++ * block specified for the ATA pass through commands. Regardless
++ * of whether the command errored or not, return a sense
++ * block. Copy all controller registers into the sense
++ * block. Clear sense key, ASC & ASCQ if there is no error.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ struct ata_taskfile *tf = &qc->result_tf;
++ unsigned char *sb = cmd->sense_buffer;
++ unsigned char *desc = sb + 8;
++ int verbose = qc->ap->ops->error_handler == NULL;
++
++ memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
++
++ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
++
++ /*
++ * Use ata_to_sense_error() to map status register bits
++ * onto sense key, asc & ascq.
++ */
++ if (qc->err_mask ||
++ tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
++ ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
++ &sb[1], &sb[2], &sb[3], verbose);
++ sb[1] &= 0x0f;
++ }
++
++ /*
++ * Sense data is current and format is descriptor.
++ */
++ sb[0] = 0x72;
++
++ desc[0] = 0x09;
++
++ /*
++ * Set length of additional sense data.
++ * Since we only populate descriptor 0, the total
++ * length is the same (fixed) length as descriptor 0.
++ */
++ desc[1] = sb[7] = 14;
++
++ /*
++ * Copy registers into sense buffer.
++ */
++ desc[2] = 0x00;
++ desc[3] = tf->feature; /* == error reg */
++ desc[5] = tf->nsect;
++ desc[7] = tf->lbal;
++ desc[9] = tf->lbam;
++ desc[11] = tf->lbah;
++ desc[12] = tf->device;
++ desc[13] = tf->command; /* == status reg */
++
++ /*
++ * Fill in Extend bit, and the high order bytes
++ * if applicable.
++ */
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ desc[2] |= 0x01;
++ desc[4] = tf->hob_nsect;
++ desc[6] = tf->hob_lbal;
++ desc[8] = tf->hob_lbam;
++ desc[10] = tf->hob_lbah;
++ }
++}
++
++/**
++ * ata_gen_fixed_sense - generate a SCSI fixed sense block
++ * @qc: Command that we are erroring out
++ *
++ * Leverage ata_to_sense_error() to give us the codes. Fit our
++ * LBA in here if there's room.
++ *
++ * LOCKING:
++ * inherited from caller
++ */
++void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ struct ata_taskfile *tf = &qc->result_tf;
++ unsigned char *sb = cmd->sense_buffer;
++ int verbose = qc->ap->ops->error_handler == NULL;
++
++ memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
++
++ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
++
++ /*
++ * Use ata_to_sense_error() to map status register bits
++ * onto sense key, asc & ascq.
++ */
++ if (qc->err_mask ||
++ tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
++ ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
++ &sb[2], &sb[12], &sb[13], verbose);
++ sb[2] &= 0x0f;
++ }
++
++ sb[0] = 0x70;
++ sb[7] = 0x0a;
++
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ /* TODO: find solution for LBA48 descriptors */
++ }
++
++ else if (tf->flags & ATA_TFLAG_LBA) {
++ /* A small (28b) LBA will fit in the 32b info field */
++ sb[0] |= 0x80; /* set valid bit */
++ sb[3] = tf->device & 0x0f;
++ sb[4] = tf->lbah;
++ sb[5] = tf->lbam;
++ sb[6] = tf->lbal;
++ }
++
++ else {
++ /* TODO: C/H/S */
++ }
++}
++
++static void ata_scsi_sdev_config(struct scsi_device *sdev)
++{
++ sdev->use_10_for_rw = 1;
++ sdev->use_10_for_ms = 1;
++}
++
++static void ata_scsi_dev_config(struct scsi_device *sdev,
++ struct ata_device *dev)
++{
++ unsigned int max_sectors;
++
++ /* TODO: 2048 is an arbitrary number, not the
++ * hardware maximum. This should be increased to
++ * 65534 when Jens Axboe's patch for dynamically
++ * determining max_sectors is merged.
++ */
++ max_sectors = ATA_MAX_SECTORS;
++ if (dev->flags & ATA_DFLAG_LBA48)
++ max_sectors = ATA_MAX_SECTORS_LBA48;
++ if (dev->max_sectors)
++ max_sectors = dev->max_sectors;
++
++ blk_queue_max_sectors(sdev->request_queue, max_sectors);
++
++ /*
++ * SATA DMA transfers must be multiples of 4 byte, so
++ * we need to pad ATAPI transfers using an extra sg.
++ * Decrement max hw segments accordingly.
++ */
++ if (dev->class == ATA_DEV_ATAPI) {
++ request_queue_t *q = sdev->request_queue;
++ blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
++ }
++
++ if (dev->flags & ATA_DFLAG_NCQ) {
++ int depth;
++
++ depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
++ depth = min(ATA_MAX_QUEUE - 1, depth);
++ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
++ }
++}
++
++/**
++ * ata_scsi_slave_config - Set SCSI device attributes
++ * @sdev: SCSI device to examine
++ *
++ * This is called before we actually start reading
++ * and writing to the device, to configure certain
++ * SCSI mid-layer behaviors.
++ *
++ * LOCKING:
++ * Defined by SCSI layer. We don't really care.
++ */
++
++int ata_scsi_slave_config(struct scsi_device *sdev)
++{
++ struct ata_port *ap = ata_shost_to_port(sdev->host);
++ struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
++
++ ata_scsi_sdev_config(sdev);
++
++ blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
++
++ if (dev)
++ ata_scsi_dev_config(sdev, dev);
++
++ return 0; /* scsi layer doesn't check return value, sigh */
++}
++
++/**
++ * ata_scsi_slave_destroy - SCSI device is about to be destroyed
++ * @sdev: SCSI device to be destroyed
++ *
++ * @sdev is about to be destroyed for hot/warm unplugging. If
++ * this unplugging was initiated by libata as indicated by NULL
++ * dev->sdev, this function doesn't have to do anything.
++ * Otherwise, SCSI layer initiated warm-unplug is in progress.
++ * Clear dev->sdev, schedule the device for ATA detach and invoke
++ * EH.
++ *
++ * LOCKING:
++ * Defined by SCSI layer. We don't really care.
++ */
++void ata_scsi_slave_destroy(struct scsi_device *sdev)
++{
++ struct ata_port *ap = ata_shost_to_port(sdev->host);
++ unsigned long flags;
++ struct ata_device *dev;
++
++ if (!ap->ops->error_handler)
++ return;
++
++ spin_lock_irqsave(ap->lock, flags);
++ dev = __ata_scsi_find_dev(ap, sdev);
++ if (dev && dev->sdev) {
++ /* SCSI device already in CANCEL state, no need to offline it */
++ dev->sdev = NULL;
++ dev->flags |= ATA_DFLAG_DETACH;
++ ata_port_schedule_eh(ap);
++ }
++ spin_unlock_irqrestore(ap->lock, flags);
++}
++
++/**
++ * ata_scsi_change_queue_depth - SCSI callback for queue depth config
++ * @sdev: SCSI device to configure queue depth for
++ * @queue_depth: new queue depth
++ *
++ * This is libata standard hostt->change_queue_depth callback.
++ * SCSI will call into this callback when user tries to set queue
++ * depth via sysfs.
++ *
++ * LOCKING:
++ * SCSI layer (we don't care)
++ *
++ * RETURNS:
++ * Newly configured queue depth.
++ */
++int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
++{
++ struct ata_port *ap = ata_shost_to_port(sdev->host);
++ struct ata_device *dev;
++ unsigned long flags;
++ int max_depth;
++
++ if (queue_depth < 1)
++ return sdev->queue_depth;
++
++ dev = ata_scsi_find_dev(ap, sdev);
++ if (!dev || !ata_dev_enabled(dev))
++ return sdev->queue_depth;
++
++ max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
++ max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
++ if (queue_depth > max_depth)
++ queue_depth = max_depth;
++
++ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
++
++ spin_lock_irqsave(ap->lock, flags);
++ if (queue_depth > 1)
++ dev->flags &= ~ATA_DFLAG_NCQ_OFF;
++ else
++ dev->flags |= ATA_DFLAG_NCQ_OFF;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ return queue_depth;
++}
++
++/**
++ * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
++ * @qc: Storage for translated ATA taskfile
++ * @scsicmd: SCSI command to translate
++ *
++ * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
++ * (to start). Perhaps these commands should be preceded by
++ * CHECK POWER MODE to see what power mode the device is already in.
++ * [See SAT revision 5 at www.t10.org]
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, non-zero on error.
++ */
++
++static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
++ const u8 *scsicmd)
++{
++ struct ata_taskfile *tf = &qc->tf;
++
++ tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
++ tf->protocol = ATA_PROT_NODATA;
++ if (scsicmd[1] & 0x1) {
++ ; /* ignore IMMED bit, violates sat-r05 */
++ }
++ if (scsicmd[4] & 0x2)
++ goto invalid_fld; /* LOEJ bit set not supported */
++ if (((scsicmd[4] >> 4) & 0xf) != 0)
++ goto invalid_fld; /* power conditions not supported */
++ if (scsicmd[4] & 0x1) {
++ tf->nsect = 1; /* 1 sector, lba=0 */
++
++ if (qc->dev->flags & ATA_DFLAG_LBA) {
++ tf->flags |= ATA_TFLAG_LBA;
++
++ tf->lbah = 0x0;
++ tf->lbam = 0x0;
++ tf->lbal = 0x0;
++ tf->device |= ATA_LBA;
++ } else {
++ /* CHS */
++ tf->lbal = 0x1; /* sect */
++ tf->lbam = 0x0; /* cyl low */
++ tf->lbah = 0x0; /* cyl high */
++ }
++
++ tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
++ } else {
++ tf->nsect = 0; /* time period value (0 implies now) */
++ tf->command = ATA_CMD_STANDBY;
++ /* Consider: ATA STANDBY IMMEDIATE command */
++ }
++ /*
++ * Standby and Idle condition timers could be implemented but that
++ * would require libata to implement the Power condition mode page
++ * and allow the user to change it. Changing mode pages requires
++ * MODE SELECT to be implemented.
++ */
++
++ return 0;
++
++invalid_fld:
++ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
++ /* "Invalid field in cbd" */
++ return 1;
++}
++
++
++/**
++ * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
++ * @qc: Storage for translated ATA taskfile
++ * @scsicmd: SCSI command to translate (ignored)
++ *
++ * Sets up an ATA taskfile to issue FLUSH CACHE or
++ * FLUSH CACHE EXT.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, non-zero on error.
++ */
++
++static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
++{
++ struct ata_taskfile *tf = &qc->tf;
++
++ tf->flags |= ATA_TFLAG_DEVICE;
++ tf->protocol = ATA_PROT_NODATA;
++
++ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
++ (ata_id_has_flush_ext(qc->dev->id)))
++ tf->command = ATA_CMD_FLUSH_EXT;
++ else
++ tf->command = ATA_CMD_FLUSH;
++
++ return 0;
++}
++
++/**
++ * scsi_6_lba_len - Get LBA and transfer length
++ * @scsicmd: SCSI command to translate
++ *
++ * Calculate LBA and transfer length for 6-byte commands.
++ *
++ * RETURNS:
++ * @plba: the LBA
++ * @plen: the transfer length
++ */
++
++static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
++{
++ u64 lba = 0;
++ u32 len = 0;
++
++ VPRINTK("six-byte command\n");
++
++ lba |= ((u64)scsicmd[2]) << 8;
++ lba |= ((u64)scsicmd[3]);
++
++ len |= ((u32)scsicmd[4]);
++
++ *plba = lba;
++ *plen = len;
++}
++
++/**
++ * scsi_10_lba_len - Get LBA and transfer length
++ * @scsicmd: SCSI command to translate
++ *
++ * Calculate LBA and transfer length for 10-byte commands.
++ *
++ * RETURNS:
++ * @plba: the LBA
++ * @plen: the transfer length
++ */
++
++static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
++{
++ u64 lba = 0;
++ u32 len = 0;
++
++ VPRINTK("ten-byte command\n");
++
++ lba |= ((u64)scsicmd[2]) << 24;
++ lba |= ((u64)scsicmd[3]) << 16;
++ lba |= ((u64)scsicmd[4]) << 8;
++ lba |= ((u64)scsicmd[5]);
++
++ len |= ((u32)scsicmd[7]) << 8;
++ len |= ((u32)scsicmd[8]);
++
++ *plba = lba;
++ *plen = len;
++}
++
++/**
++ * scsi_16_lba_len - Get LBA and transfer length
++ * @scsicmd: SCSI command to translate
++ *
++ * Calculate LBA and transfer length for 16-byte commands.
++ *
++ * RETURNS:
++ * @plba: the LBA
++ * @plen: the transfer length
++ */
++
++static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
++{
++ u64 lba = 0;
++ u32 len = 0;
++
++ VPRINTK("sixteen-byte command\n");
++
++ lba |= ((u64)scsicmd[2]) << 56;
++ lba |= ((u64)scsicmd[3]) << 48;
++ lba |= ((u64)scsicmd[4]) << 40;
++ lba |= ((u64)scsicmd[5]) << 32;
++ lba |= ((u64)scsicmd[6]) << 24;
++ lba |= ((u64)scsicmd[7]) << 16;
++ lba |= ((u64)scsicmd[8]) << 8;
++ lba |= ((u64)scsicmd[9]);
++
++ len |= ((u32)scsicmd[10]) << 24;
++ len |= ((u32)scsicmd[11]) << 16;
++ len |= ((u32)scsicmd[12]) << 8;
++ len |= ((u32)scsicmd[13]);
++
++ *plba = lba;
++ *plen = len;
++}
++
++/**
++ * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
++ * @qc: Storage for translated ATA taskfile
++ * @scsicmd: SCSI command to translate
++ *
++ * Converts SCSI VERIFY command to an ATA READ VERIFY command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, non-zero on error.
++ */
++
++static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
++{
++ struct ata_taskfile *tf = &qc->tf;
++ struct ata_device *dev = qc->dev;
++ u64 dev_sectors = qc->dev->n_sectors;
++ u64 block;
++ u32 n_block;
++
++ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++ tf->protocol = ATA_PROT_NODATA;
++
++ if (scsicmd[0] == VERIFY)
++ scsi_10_lba_len(scsicmd, &block, &n_block);
++ else if (scsicmd[0] == VERIFY_16)
++ scsi_16_lba_len(scsicmd, &block, &n_block);
++ else
++ goto invalid_fld;
++
++ if (!n_block)
++ goto nothing_to_do;
++ if (block >= dev_sectors)
++ goto out_of_range;
++ if ((block + n_block) > dev_sectors)
++ goto out_of_range;
++
++ if (dev->flags & ATA_DFLAG_LBA) {
++ tf->flags |= ATA_TFLAG_LBA;
++
++ if (lba_28_ok(block, n_block)) {
++ /* use LBA28 */
++ tf->command = ATA_CMD_VERIFY;
++ tf->device |= (block >> 24) & 0xf;
++ } else if (lba_48_ok(block, n_block)) {
++ if (!(dev->flags & ATA_DFLAG_LBA48))
++ goto out_of_range;
++
++ /* use LBA48 */
++ tf->flags |= ATA_TFLAG_LBA48;
++ tf->command = ATA_CMD_VERIFY_EXT;
++
++ tf->hob_nsect = (n_block >> 8) & 0xff;
++
++ tf->hob_lbah = (block >> 40) & 0xff;
++ tf->hob_lbam = (block >> 32) & 0xff;
++ tf->hob_lbal = (block >> 24) & 0xff;
++ } else
++ /* request too large even for LBA48 */
++ goto out_of_range;
++
++ tf->nsect = n_block & 0xff;
++
++ tf->lbah = (block >> 16) & 0xff;
++ tf->lbam = (block >> 8) & 0xff;
++ tf->lbal = block & 0xff;
++
++ tf->device |= ATA_LBA;
++ } else {
++ /* CHS */
++ u32 sect, head, cyl, track;
++
++ if (!lba_28_ok(block, n_block))
++ goto out_of_range;
++
++ /* Convert LBA to CHS */
++ track = (u32)block / dev->sectors;
++ cyl = track / dev->heads;
++ head = track % dev->heads;
++ sect = (u32)block % dev->sectors + 1;
++
++ DPRINTK("block %u track %u cyl %u head %u sect %u\n",
++ (u32)block, track, cyl, head, sect);
++
++ /* Check whether the converted CHS can fit.
++ Cylinder: 0-65535
++ Head: 0-15
++ Sector: 1-255*/
++ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
++ goto out_of_range;
++
++ tf->command = ATA_CMD_VERIFY;
++ tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
++ tf->lbal = sect;
++ tf->lbam = cyl;
++ tf->lbah = cyl >> 8;
++ tf->device |= head;
++ }
++
++ return 0;
++
++invalid_fld:
++ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
++ /* "Invalid field in cbd" */
++ return 1;
++
++out_of_range:
++ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
++ /* "Logical Block Address out of range" */
++ return 1;
++
++nothing_to_do:
++ qc->scsicmd->result = SAM_STAT_GOOD;
++ return 1;
++}
++
++/**
++ * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
++ * @qc: Storage for translated ATA taskfile
++ * @scsicmd: SCSI command to translate
++ *
++ * Converts any of six SCSI read/write commands into the
++ * ATA counterpart, including starting sector (LBA),
++ * sector count, and taking into account the device's LBA48
++ * support.
++ *
++ * Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
++ * %WRITE_16 are currently supported.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, non-zero on error.
++ */
++
++static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
++{
++ struct ata_taskfile *tf = &qc->tf;
++ struct ata_device *dev = qc->dev;
++ u64 block;
++ u32 n_block;
++
++ qc->flags |= ATA_QCFLAG_IO;
++ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++
++ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
++ scsicmd[0] == WRITE_16)
++ tf->flags |= ATA_TFLAG_WRITE;
++
++ /* Calculate the SCSI LBA, transfer length and FUA. */
++ switch (scsicmd[0]) {
++ case READ_10:
++ case WRITE_10:
++ scsi_10_lba_len(scsicmd, &block, &n_block);
++ if (unlikely(scsicmd[1] & (1 << 3)))
++ tf->flags |= ATA_TFLAG_FUA;
++ break;
++ case READ_6:
++ case WRITE_6:
++ scsi_6_lba_len(scsicmd, &block, &n_block);
++
++ /* for 6-byte r/w commands, transfer length 0
++ * means 256 blocks of data, not 0 block.
++ */
++ if (!n_block)
++ n_block = 256;
++ break;
++ case READ_16:
++ case WRITE_16:
++ scsi_16_lba_len(scsicmd, &block, &n_block);
++ if (unlikely(scsicmd[1] & (1 << 3)))
++ tf->flags |= ATA_TFLAG_FUA;
++ break;
++ default:
++ DPRINTK("no-byte command\n");
++ goto invalid_fld;
++ }
++
++ /* Check and compose ATA command */
++ if (!n_block)
++ /* For 10-byte and 16-byte SCSI R/W commands, transfer
++ * length 0 means transfer 0 block of data.
++ * However, for ATA R/W commands, sector count 0 means
++ * 256 or 65536 sectors, not 0 sectors as in SCSI.
++ *
++ * WARNING: one or two older ATA drives treat 0 as 0...
++ */
++ goto nothing_to_do;
++
++ if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
++ ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
++ /* yay, NCQ */
++ if (!lba_48_ok(block, n_block))
++ goto out_of_range;
++
++ tf->protocol = ATA_PROT_NCQ;
++ tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
++
++ if (tf->flags & ATA_TFLAG_WRITE)
++ tf->command = ATA_CMD_FPDMA_WRITE;
++ else
++ tf->command = ATA_CMD_FPDMA_READ;
++
++ qc->nsect = n_block;
++
++ tf->nsect = qc->tag << 3;
++ tf->hob_feature = (n_block >> 8) & 0xff;
++ tf->feature = n_block & 0xff;
++
++ tf->hob_lbah = (block >> 40) & 0xff;
++ tf->hob_lbam = (block >> 32) & 0xff;
++ tf->hob_lbal = (block >> 24) & 0xff;
++ tf->lbah = (block >> 16) & 0xff;
++ tf->lbam = (block >> 8) & 0xff;
++ tf->lbal = block & 0xff;
++
++ tf->device = 1 << 6;
++ if (tf->flags & ATA_TFLAG_FUA)
++ tf->device |= 1 << 7;
++ } else if (dev->flags & ATA_DFLAG_LBA) {
++ tf->flags |= ATA_TFLAG_LBA;
++
++ if (lba_28_ok(block, n_block)) {
++ /* use LBA28 */
++ tf->device |= (block >> 24) & 0xf;
++ } else if (lba_48_ok(block, n_block)) {
++ if (!(dev->flags & ATA_DFLAG_LBA48))
++ goto out_of_range;
++
++ /* use LBA48 */
++ tf->flags |= ATA_TFLAG_LBA48;
++
++ tf->hob_nsect = (n_block >> 8) & 0xff;
++
++ tf->hob_lbah = (block >> 40) & 0xff;
++ tf->hob_lbam = (block >> 32) & 0xff;
++ tf->hob_lbal = (block >> 24) & 0xff;
++ } else
++ /* request too large even for LBA48 */
++ goto out_of_range;
++
++ if (unlikely(ata_rwcmd_protocol(qc) < 0))
++ goto invalid_fld;
++
++ qc->nsect = n_block;
++ tf->nsect = n_block & 0xff;
++
++ tf->lbah = (block >> 16) & 0xff;
++ tf->lbam = (block >> 8) & 0xff;
++ tf->lbal = block & 0xff;
++
++ tf->device |= ATA_LBA;
++ } else {
++ /* CHS */
++ u32 sect, head, cyl, track;
++
++ /* The request -may- be too large for CHS addressing. */
++ if (!lba_28_ok(block, n_block))
++ goto out_of_range;
++
++ if (unlikely(ata_rwcmd_protocol(qc) < 0))
++ goto invalid_fld;
++
++ /* Convert LBA to CHS */
++ track = (u32)block / dev->sectors;
++ cyl = track / dev->heads;
++ head = track % dev->heads;
++ sect = (u32)block % dev->sectors + 1;
++
++ DPRINTK("block %u track %u cyl %u head %u sect %u\n",
++ (u32)block, track, cyl, head, sect);
++
++ /* Check whether the converted CHS can fit.
++ Cylinder: 0-65535
++ Head: 0-15
++ Sector: 1-255*/
++ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
++ goto out_of_range;
++
++ qc->nsect = n_block;
++ tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
++ tf->lbal = sect;
++ tf->lbam = cyl;
++ tf->lbah = cyl >> 8;
++ tf->device |= head;
++ }
++
++ return 0;
++
++invalid_fld:
++ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
++ /* "Invalid field in cbd" */
++ return 1;
++
++out_of_range:
++ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
++ /* "Logical Block Address out of range" */
++ return 1;
++
++nothing_to_do:
++ qc->scsicmd->result = SAM_STAT_GOOD;
++ return 1;
++}
++
++static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ u8 *cdb = cmd->cmnd;
++ int need_sense = (qc->err_mask != 0);
++
++ /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
++ * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
++ * cache
++ */
++ if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
++ ((qc->tf.feature == SETFEATURES_WC_ON) ||
++ (qc->tf.feature == SETFEATURES_WC_OFF))) {
++ qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
++ ata_port_schedule_eh(qc->ap);
++ }
++
++ /* For ATA pass thru (SAT) commands, generate a sense block if
++ * user mandated it or if there's an error. Note that if we
++ * generate because the user forced us to, a check condition
++ * is generated and the ATA register values are returned
++ * whether the command completed successfully or not. If there
++ * was no error, SK, ASC and ASCQ will all be zero.
++ */
++ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
++ ((cdb[2] & 0x20) || need_sense)) {
++ ata_gen_ata_desc_sense(qc);
++ } else {
++ if (!need_sense) {
++ cmd->result = SAM_STAT_GOOD;
++ } else {
++ /* TODO: decide which descriptor format to use
++ * for 48b LBA devices and call that here
++ * instead of the fixed desc, which is only
++ * good for smaller LBA (and maybe CHS?)
++ * devices.
++ */
++ ata_gen_fixed_sense(qc);
++ }
++ }
++
++ if (need_sense && !qc->ap->ops->error_handler)
++ ata_dump_status(qc->ap->id, &qc->result_tf);
++
++ qc->scsidone(cmd);
++
++ ata_qc_free(qc);
++}
++
++/**
++ * ata_scmd_need_defer - Check whether we need to defer scmd
++ * @dev: ATA device to which the command is addressed
++ * @is_io: Is the command IO (and thus possibly NCQ)?
++ *
++ * NCQ and non-NCQ commands cannot run together. As upper layer
++ * only knows the queue depth, we are responsible for maintaining
++ * exclusion. This function checks whether a new command can be
++ * issued to @dev.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * 1 if deferring is needed, 0 otherwise.
++ */
++static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
++{
++ struct ata_port *ap = dev->ap;
++
++ if (!(dev->flags & ATA_DFLAG_NCQ))
++ return 0;
++
++ if (is_io) {
++ if (!ata_tag_valid(ap->active_tag))
++ return 0;
++ } else {
++ if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
++ return 0;
++ }
++ return 1;
++}
++
++/**
++ * ata_scsi_translate - Translate then issue SCSI command to ATA device
++ * @dev: ATA device to which the command is addressed
++ * @cmd: SCSI command to execute
++ * @done: SCSI command completion function
++ * @xlat_func: Actor which translates @cmd to an ATA taskfile
++ *
++ * Our ->queuecommand() function has decided that the SCSI
++ * command issued can be directly translated into an ATA
++ * command, rather than handled internally.
++ *
++ * This function sets up an ata_queued_cmd structure for the
++ * SCSI command, and sends that ata_queued_cmd to the hardware.
++ *
++ * The xlat_func argument (actor) returns 0 if ready to execute
++ * ATA command, else 1 to finish translation. If 1 is returned
++ * then cmd->result (and possibly cmd->sense_buffer) are assumed
++ * to be set reflecting an error condition or clean (early)
++ * termination.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
++ * needs to be deferred.
++ */
++static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *),
++ ata_xlat_func_t xlat_func)
++{
++ struct ata_queued_cmd *qc;
++ u8 *scsicmd = cmd->cmnd;
++ int is_io = xlat_func == ata_scsi_rw_xlat;
++
++ VPRINTK("ENTER\n");
++
++ if (unlikely(ata_scmd_need_defer(dev, is_io)))
++ goto defer;
++
++ qc = ata_scsi_qc_new(dev, cmd, done);
++ if (!qc)
++ goto err_mem;
++
++ /* data is present; dma-map it */
++ if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
++ cmd->sc_data_direction == DMA_TO_DEVICE) {
++ if (unlikely(cmd->request_bufflen < 1)) {
++ ata_dev_printk(dev, KERN_WARNING,
++ "WARNING: zero len r/w req\n");
++ goto err_did;
++ }
++
++ if (cmd->use_sg)
++ ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
++ else
++ ata_sg_init_one(qc, cmd->request_buffer,
++ cmd->request_bufflen);
++
++ qc->dma_dir = cmd->sc_data_direction;
++ }
++
++ qc->complete_fn = ata_scsi_qc_complete;
++
++ if (xlat_func(qc, scsicmd))
++ goto early_finish;
++
++ /* select device, send command to hardware */
++ ata_qc_issue(qc);
++
++ VPRINTK("EXIT\n");
++ return 0;
++
++early_finish:
++ ata_qc_free(qc);
++ done(cmd);
++ DPRINTK("EXIT - early finish (good or error)\n");
++ return 0;
++
++err_did:
++ ata_qc_free(qc);
++err_mem:
++ cmd->result = (DID_ERROR << 16);
++ done(cmd);
++ DPRINTK("EXIT - internal\n");
++ return 0;
++
++defer:
++ DPRINTK("EXIT - defer\n");
++ return SCSI_MLQUEUE_DEVICE_BUSY;
++}
++
++/**
++ * ata_scsi_rbuf_get - Map response buffer.
++ * @cmd: SCSI command containing buffer to be mapped.
++ * @buf_out: Pointer to mapped area.
++ *
++ * Maps buffer contained within SCSI command @cmd.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Length of response buffer.
++ */
++
++static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
++{
++ u8 *buf;
++ unsigned int buflen;
++
++ if (cmd->use_sg) {
++ struct scatterlist *sg;
++
++ sg = (struct scatterlist *) cmd->request_buffer;
++ buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
++ buflen = sg->length;
++ } else {
++ buf = cmd->request_buffer;
++ buflen = cmd->request_bufflen;
++ }
++
++ *buf_out = buf;
++ return buflen;
++}
++
++/**
++ * ata_scsi_rbuf_put - Unmap response buffer.
++ * @cmd: SCSI command containing buffer to be unmapped.
++ * @buf: buffer to unmap
++ *
++ * Unmaps response buffer contained within @cmd.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
++{
++ if (cmd->use_sg) {
++ struct scatterlist *sg;
++
++ sg = (struct scatterlist *) cmd->request_buffer;
++ kunmap_atomic(buf - sg->offset, KM_USER0);
++ }
++}
++
++/**
++ * ata_scsi_rbuf_fill - wrapper for SCSI command simulators
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @actor: Callback hook for desired SCSI command simulator
++ *
++ * Takes care of the hard work of simulating a SCSI command...
++ * Mapping the response buffer, calling the command's handler,
++ * and handling the handler's return value. This return value
++ * indicates whether the handler wishes the SCSI command to be
++ * completed successfully (0), or not (in which case cmd->result
++ * and sense buffer are assumed to be set).
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
++ unsigned int (*actor) (struct ata_scsi_args *args,
++ u8 *rbuf, unsigned int buflen))
++{
++ u8 *rbuf;
++ unsigned int buflen, rc;
++ struct scsi_cmnd *cmd = args->cmd;
++
++ buflen = ata_scsi_rbuf_get(cmd, &rbuf);
++ memset(rbuf, 0, buflen);
++ rc = actor(args, rbuf, buflen);
++ ata_scsi_rbuf_put(cmd, rbuf);
++
++ if (rc == 0)
++ cmd->result = SAM_STAT_GOOD;
++ args->done(cmd);
++}
++
++/**
++ * ata_scsiop_inq_std - Simulate INQUIRY command
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Returns standard device identification data associated
++ * with non-VPD INQUIRY command output.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ u8 hdr[] = {
++ TYPE_DISK,
++ 0,
++ 0x5, /* claim SPC-3 version compatibility */
++ 2,
++ 95 - 4
++ };
++
++ /* set scsi removeable (RMB) bit per ata bit */
++ if (ata_id_removeable(args->id))
++ hdr[1] |= (1 << 7);
++
++ VPRINTK("ENTER\n");
++
++ memcpy(rbuf, hdr, sizeof(hdr));
++
++ if (buflen > 35) {
++ memcpy(&rbuf[8], "ATA ", 8);
++ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
++ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
++ if (rbuf[32] == 0 || rbuf[32] == ' ')
++ memcpy(&rbuf[32], "n/a ", 4);
++ }
++
++ if (buflen > 63) {
++ const u8 versions[] = {
++ 0x60, /* SAM-3 (no version claimed) */
++
++ 0x03,
++ 0x20, /* SBC-2 (no version claimed) */
++
++ 0x02,
++ 0x60 /* SPC-3 (no version claimed) */
++ };
++
++ memcpy(rbuf + 59, versions, sizeof(versions));
++ }
++
++ return 0;
++}
++
++/**
++ * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Returns list of inquiry VPD pages available.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ const u8 pages[] = {
++ 0x00, /* page 0x00, this page */
++ 0x80, /* page 0x80, unit serial no page */
++ 0x83 /* page 0x83, device ident page */
++ };
++ rbuf[3] = sizeof(pages); /* number of supported VPD pages */
++
++ if (buflen > 6)
++ memcpy(rbuf + 4, pages, sizeof(pages));
++
++ return 0;
++}
++
++/**
++ * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Returns ATA device serial number.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ const u8 hdr[] = {
++ 0,
++ 0x80, /* this page code */
++ 0,
++ ATA_SERNO_LEN, /* page len */
++ };
++ memcpy(rbuf, hdr, sizeof(hdr));
++
++ if (buflen > (ATA_SERNO_LEN + 4 - 1))
++ ata_id_string(args->id, (unsigned char *) &rbuf[4],
++ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
++
++ return 0;
++}
++
++/**
++ * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Yields two logical unit device identification designators:
++ * - vendor specific ASCII containing the ATA serial number
++ * - SAT defined "t10 vendor id based" containing ASCII vendor
++ * name ("ATA "), model and serial numbers.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ int num;
++ const int sat_model_serial_desc_len = 68;
++ const int ata_model_byte_len = 40;
++
++ rbuf[1] = 0x83; /* this page code */
++ num = 4;
++
++ if (buflen > (ATA_SERNO_LEN + num + 3)) {
++ /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
++ rbuf[num + 0] = 2;
++ rbuf[num + 3] = ATA_SERNO_LEN;
++ num += 4;
++ ata_id_string(args->id, (unsigned char *) rbuf + num,
++ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
++ num += ATA_SERNO_LEN;
++ }
++ if (buflen > (sat_model_serial_desc_len + num + 3)) {
++ /* SAT defined lu model and serial numbers descriptor */
++ /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
++ rbuf[num + 0] = 2;
++ rbuf[num + 1] = 1;
++ rbuf[num + 3] = sat_model_serial_desc_len;
++ num += 4;
++ memcpy(rbuf + num, "ATA ", 8);
++ num += 8;
++ ata_id_string(args->id, (unsigned char *) rbuf + num,
++ ATA_ID_PROD_OFS, ata_model_byte_len);
++ num += ata_model_byte_len;
++ ata_id_string(args->id, (unsigned char *) rbuf + num,
++ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
++ num += ATA_SERNO_LEN;
++ }
++ rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
++ return 0;
++}
++
++/**
++ * ata_scsiop_noop - Command handler that simply returns success.
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * No operation. Simply returns success to caller, to indicate
++ * that the caller should successfully complete this SCSI command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ VPRINTK("ENTER\n");
++ return 0;
++}
++
++/**
++ * ata_msense_push - Push data onto MODE SENSE data output buffer
++ * @ptr_io: (input/output) Location to store more output data
++ * @last: End of output data buffer
++ * @buf: Pointer to BLOB being added to output buffer
++ * @buflen: Length of BLOB
++ *
++ * Store MODE SENSE data on an output buffer.
++ *
++ * LOCKING:
++ * None.
++ */
++
++static void ata_msense_push(u8 **ptr_io, const u8 *last,
++ const u8 *buf, unsigned int buflen)
++{
++ u8 *ptr = *ptr_io;
++
++ if ((ptr + buflen - 1) > last)
++ return;
++
++ memcpy(ptr, buf, buflen);
++
++ ptr += buflen;
++
++ *ptr_io = ptr;
++}
++
++/**
++ * ata_msense_caching - Simulate MODE SENSE caching info page
++ * @id: device IDENTIFY data
++ * @ptr_io: (input/output) Location to store more output data
++ * @last: End of output data buffer
++ *
++ * Generate a caching info page, which conditionally indicates
++ * write caching to the SCSI layer, depending on device
++ * capabilities.
++ *
++ * LOCKING:
++ * None.
++ */
++
++static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
++ const u8 *last)
++{
++ u8 page[CACHE_MPAGE_LEN];
++
++ memcpy(page, def_cache_mpage, sizeof(page));
++ if (ata_id_wcache_enabled(id))
++ page[2] |= (1 << 2); /* write cache enable */
++ if (!ata_id_rahead_enabled(id))
++ page[12] |= (1 << 5); /* disable read ahead */
++
++ ata_msense_push(ptr_io, last, page, sizeof(page));
++ return sizeof(page);
++}
++
++/**
++ * ata_msense_ctl_mode - Simulate MODE SENSE control mode page
++ * @dev: Device associated with this MODE SENSE command
++ * @ptr_io: (input/output) Location to store more output data
++ * @last: End of output data buffer
++ *
++ * Generate a generic MODE SENSE control mode page.
++ *
++ * LOCKING:
++ * None.
++ */
++
++static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
++{
++ ata_msense_push(ptr_io, last, def_control_mpage,
++ sizeof(def_control_mpage));
++ return sizeof(def_control_mpage);
++}
++
++/**
++ * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
++ * @dev: Device associated with this MODE SENSE command
++ * @ptr_io: (input/output) Location to store more output data
++ * @last: End of output data buffer
++ *
++ * Generate a generic MODE SENSE r/w error recovery page.
++ *
++ * LOCKING:
++ * None.
++ */
++
++static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
++{
++
++ ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
++ sizeof(def_rw_recovery_mpage));
++ return sizeof(def_rw_recovery_mpage);
++}
++
++/*
++ * We can turn this into a real blacklist if it's needed, for now just
++ * blacklist any Maxtor BANC1G10 revision firmware
++ */
++static int ata_dev_supports_fua(u16 *id)
++{
++ unsigned char model[41], fw[9];
++
++ if (!libata_fua)
++ return 0;
++ if (!ata_id_has_fua(id))
++ return 0;
++
++ ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
++ ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
++
++ if (strcmp(model, "Maxtor"))
++ return 1;
++ if (strcmp(fw, "BANC1G10"))
++ return 1;
++
++ return 0; /* blacklisted */
++}
++
++/**
++ * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Simulate MODE SENSE commands. Assume this is invoked for direct
++ * access devices (e.g. disks) only. There should be no block
++ * descriptor for other device types.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ struct ata_device *dev = args->dev;
++ u8 *scsicmd = args->cmd->cmnd, *p, *last;
++ const u8 sat_blk_desc[] = {
++ 0, 0, 0, 0, /* number of blocks: sat unspecified */
++ 0,
++ 0, 0x2, 0x0 /* block length: 512 bytes */
++ };
++ u8 pg, spg;
++ unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
++ u8 dpofua;
++
++ VPRINTK("ENTER\n");
++
++ six_byte = (scsicmd[0] == MODE_SENSE);
++ ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */
++ /*
++ * LLBA bit in msense(10) ignored (compliant)
++ */
++
++ page_control = scsicmd[2] >> 6;
++ switch (page_control) {
++ case 0: /* current */
++ break; /* supported */
++ case 3: /* saved */
++ goto saving_not_supp;
++ case 1: /* changeable */
++ case 2: /* defaults */
++ default:
++ goto invalid_fld;
++ }
++
++ if (six_byte) {
++ output_len = 4 + (ebd ? 8 : 0);
++ alloc_len = scsicmd[4];
++ } else {
++ output_len = 8 + (ebd ? 8 : 0);
++ alloc_len = (scsicmd[7] << 8) + scsicmd[8];
++ }
++ minlen = (alloc_len < buflen) ? alloc_len : buflen;
++
++ p = rbuf + output_len;
++ last = rbuf + minlen - 1;
++
++ pg = scsicmd[2] & 0x3f;
++ spg = scsicmd[3];
++ /*
++ * No mode subpages supported (yet) but asking for _all_
++ * subpages may be valid
++ */
++ if (spg && (spg != ALL_SUB_MPAGES))
++ goto invalid_fld;
++
++ switch(pg) {
++ case RW_RECOVERY_MPAGE:
++ output_len += ata_msense_rw_recovery(&p, last);
++ break;
++
++ case CACHE_MPAGE:
++ output_len += ata_msense_caching(args->id, &p, last);
++ break;
++
++ case CONTROL_MPAGE: {
++ output_len += ata_msense_ctl_mode(&p, last);
++ break;
++ }
++
++ case ALL_MPAGES:
++ output_len += ata_msense_rw_recovery(&p, last);
++ output_len += ata_msense_caching(args->id, &p, last);
++ output_len += ata_msense_ctl_mode(&p, last);
++ break;
++
++ default: /* invalid page code */
++ goto invalid_fld;
++ }
++
++ if (minlen < 1)
++ return 0;
++
++ dpofua = 0;
++ if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
++ (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
++ dpofua = 1 << 4;
++
++ if (six_byte) {
++ output_len--;
++ rbuf[0] = output_len;
++ if (minlen > 2)
++ rbuf[2] |= dpofua;
++ if (ebd) {
++ if (minlen > 3)
++ rbuf[3] = sizeof(sat_blk_desc);
++ if (minlen > 11)
++ memcpy(rbuf + 4, sat_blk_desc,
++ sizeof(sat_blk_desc));
++ }
++ } else {
++ output_len -= 2;
++ rbuf[0] = output_len >> 8;
++ if (minlen > 1)
++ rbuf[1] = output_len;
++ if (minlen > 3)
++ rbuf[3] |= dpofua;
++ if (ebd) {
++ if (minlen > 7)
++ rbuf[7] = sizeof(sat_blk_desc);
++ if (minlen > 15)
++ memcpy(rbuf + 8, sat_blk_desc,
++ sizeof(sat_blk_desc));
++ }
++ }
++ return 0;
++
++invalid_fld:
++ ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);
++ /* "Invalid field in cbd" */
++ return 1;
++
++saving_not_supp:
++ ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
++ /* "Saving parameters not supported" */
++ return 1;
++}
++
++/**
++ * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Simulate READ CAPACITY commands.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ u64 n_sectors;
++ u32 tmp;
++
++ VPRINTK("ENTER\n");
++
++ if (ata_id_has_lba(args->id)) {
++ if (ata_id_has_lba48(args->id))
++ n_sectors = ata_id_u64(args->id, 100);
++ else
++ n_sectors = ata_id_u32(args->id, 60);
++ } else {
++ /* CHS default translation */
++ n_sectors = args->id[1] * args->id[3] * args->id[6];
++
++ if (ata_id_current_chs_valid(args->id))
++ /* CHS current translation */
++ n_sectors = ata_id_u32(args->id, 57);
++ }
++
++ n_sectors--; /* ATA TotalUserSectors - 1 */
++
++ 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);
++ rbuf[2] = tmp >> (8 * 1);
++ rbuf[3] = tmp;
++
++ /* sector size */
++ tmp = ATA_SECT_SIZE;
++ rbuf[6] = tmp >> 8;
++ rbuf[7] = tmp;
++
++ } else {
++ /* sector count, 64-bit */
++ 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);
++ rbuf[9] = tmp;
++
++ /* sector size */
++ tmp = ATA_SECT_SIZE;
++ rbuf[12] = tmp >> 8;
++ rbuf[13] = tmp;
++ }
++
++ return 0;
++}
++
++/**
++ * ata_scsiop_report_luns - Simulate REPORT LUNS command
++ * @args: device IDENTIFY data / SCSI command of interest.
++ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
++ * @buflen: Response buffer length.
++ *
++ * Simulate REPORT LUNS command.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen)
++{
++ VPRINTK("ENTER\n");
++ rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
++
++ return 0;
++}
++
++/**
++ * ata_scsi_set_sense - Set SCSI sense data and status
++ * @cmd: SCSI request to be handled
++ * @sk: SCSI-defined sense key
++ * @asc: SCSI-defined additional sense code
++ * @ascq: SCSI-defined additional sense code qualifier
++ *
++ * Helper function that builds a valid fixed format, current
++ * response code and the given sense key (sk), additional sense
++ * code (asc) and additional sense code qualifier (ascq) with
++ * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
++ * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
++ *
++ * LOCKING:
++ * Not required
++ */
++
++void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
++{
++ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
++
++ cmd->sense_buffer[0] = 0x70; /* fixed format, current */
++ cmd->sense_buffer[2] = sk;
++ cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
++ cmd->sense_buffer[12] = asc;
++ cmd->sense_buffer[13] = ascq;
++}
++
++/**
++ * ata_scsi_badcmd - End a SCSI request with an error
++ * @cmd: SCSI request to be handled
++ * @done: SCSI command completion function
++ * @asc: SCSI-defined additional sense code
++ * @ascq: SCSI-defined additional sense code qualifier
++ *
++ * Helper function that completes a SCSI command with
++ * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
++ * and the specified additional sense codes.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
++{
++ DPRINTK("ENTER\n");
++ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
++
++ done(cmd);
++}
++
++static void atapi_sense_complete(struct ata_queued_cmd *qc)
++{
++ if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
++ /* FIXME: not quite right; we don't want the
++ * translation of taskfile registers into
++ * a sense descriptors, since that's only
++ * correct for ATA, not ATAPI
++ */
++ ata_gen_ata_desc_sense(qc);
++ }
++
++ qc->scsidone(qc->scsicmd);
++ ata_qc_free(qc);
++}
++
++/* is it pointless to prefer PIO for "safety reasons"? */
++static inline int ata_pio_use_silly(struct ata_port *ap)
++{
++ return (ap->flags & ATA_FLAG_PIO_DMA);
++}
++
++static void atapi_request_sense(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct scsi_cmnd *cmd = qc->scsicmd;
++
++ DPRINTK("ATAPI request sense\n");
++
++ /* FIXME: is this needed? */
++ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++
++ ap->ops->tf_read(ap, &qc->tf);
++
++ /* fill these in, for the case where they are -not- overwritten */
++ cmd->sense_buffer[0] = 0x70;
++ cmd->sense_buffer[2] = qc->tf.feature >> 4;
++
++ ata_qc_reinit(qc);
++
++ ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
++ qc->dma_dir = DMA_FROM_DEVICE;
++
++ memset(&qc->cdb, 0, qc->dev->cdb_len);
++ qc->cdb[0] = REQUEST_SENSE;
++ qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
++
++ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++ qc->tf.command = ATA_CMD_PACKET;
++
++ if (ata_pio_use_silly(ap)) {
++ qc->tf.protocol = ATA_PROT_ATAPI_DMA;
++ qc->tf.feature |= ATAPI_PKT_DMA;
++ } else {
++ qc->tf.protocol = ATA_PROT_ATAPI;
++ qc->tf.lbam = (8 * 1024) & 0xff;
++ qc->tf.lbah = (8 * 1024) >> 8;
++ }
++ qc->nbytes = SCSI_SENSE_BUFFERSIZE;
++
++ qc->complete_fn = atapi_sense_complete;
++
++ ata_qc_issue(qc);
++
++ DPRINTK("EXIT\n");
++}
++
++static void atapi_qc_complete(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ unsigned int err_mask = qc->err_mask;
++
++ VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
++
++ /* handle completion from new EH */
++ if (unlikely(qc->ap->ops->error_handler &&
++ (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
++
++ if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
++ /* FIXME: not quite right; we don't want the
++ * translation of taskfile registers into a
++ * sense descriptors, since that's only
++ * correct for ATA, not ATAPI
++ */
++ ata_gen_ata_desc_sense(qc);
++ }
++
++ /* SCSI EH automatically locks door if sdev->locked is
++ * set. Sometimes door lock request continues to
++ * fail, for example, when no media is present. This
++ * creates a loop - SCSI EH issues door lock which
++ * fails and gets invoked again to acquire sense data
++ * for the failed command.
++ *
++ * If door lock fails, always clear sdev->locked to
++ * avoid this infinite loop.
++ */
++ if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
++ qc->dev->sdev->locked = 0;
++
++ qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
++ qc->scsidone(cmd);
++ ata_qc_free(qc);
++ return;
++ }
++
++ /* successful completion or old EH failure path */
++ if (unlikely(err_mask & AC_ERR_DEV)) {
++ cmd->result = SAM_STAT_CHECK_CONDITION;
++ atapi_request_sense(qc);
++ return;
++ } else if (unlikely(err_mask)) {
++ /* FIXME: not quite right; we don't want the
++ * translation of taskfile registers into
++ * a sense descriptors, since that's only
++ * correct for ATA, not ATAPI
++ */
++ ata_gen_ata_desc_sense(qc);
++ } else {
++ u8 *scsicmd = cmd->cmnd;
++
++ if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
++ u8 *buf = NULL;
++ unsigned int buflen;
++
++ buflen = ata_scsi_rbuf_get(cmd, &buf);
++
++ /* ATAPI devices typically report zero for their SCSI version,
++ * and sometimes deviate from the spec WRT response data
++ * format. If SCSI version is reported as zero like normal,
++ * then we make the following fixups: 1) Fake MMC-5 version,
++ * to indicate to the Linux scsi midlayer this is a modern
++ * device. 2) Ensure response data format / ATAPI information
++ * are always correct.
++ */
++ if (buf[2] == 0) {
++ buf[2] = 0x5;
++ buf[3] = 0x32;
++ }
++
++ ata_scsi_rbuf_put(cmd, buf);
++ }
++
++ cmd->result = SAM_STAT_GOOD;
++ }
++
++ qc->scsidone(cmd);
++ ata_qc_free(qc);
++}
++/**
++ * atapi_xlat - Initialize PACKET taskfile
++ * @qc: command structure to be initialized
++ * @scsicmd: SCSI CDB associated with this PACKET command
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Zero on success, non-zero on failure.
++ */
++
++static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
++{
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ struct ata_device *dev = qc->dev;
++ int using_pio = (dev->flags & ATA_DFLAG_PIO);
++ int nodata = (cmd->sc_data_direction == DMA_NONE);
++
++ if (!using_pio)
++ /* Check whether ATAPI DMA is safe */
++ if (ata_check_atapi_dma(qc))
++ using_pio = 1;
++
++ memcpy(&qc->cdb, scsicmd, dev->cdb_len);
++
++ qc->complete_fn = atapi_qc_complete;
++
++ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
++ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
++ qc->tf.flags |= ATA_TFLAG_WRITE;
++ DPRINTK("direction: write\n");
++ }
++
++ qc->tf.command = ATA_CMD_PACKET;
++
++ /* no data, or PIO data xfer */
++ if (using_pio || nodata) {
++ if (nodata)
++ qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
++ else
++ qc->tf.protocol = ATA_PROT_ATAPI;
++ qc->tf.lbam = (8 * 1024) & 0xff;
++ qc->tf.lbah = (8 * 1024) >> 8;
++ }
++
++ /* DMA data xfer */
++ else {
++ qc->tf.protocol = ATA_PROT_ATAPI_DMA;
++ qc->tf.feature |= ATAPI_PKT_DMA;
++
++ if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE))
++ /* some SATA bridges need us to indicate data xfer direction */
++ qc->tf.feature |= ATAPI_DMADIR;
++ }
++
++ qc->nbytes = cmd->request_bufflen;
++
++ return 0;
++}
++
++static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
++{
++ if (likely(id < ATA_MAX_DEVICES))
++ return &ap->device[id];
++ return NULL;
++}
++
++static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
++ const struct scsi_device *scsidev)
++{
++ /* skip commands not addressed to targets we simulate */
++ if (unlikely(scsidev->channel || scsidev->lun))
++ return NULL;
++
++ return ata_find_dev(ap, scsidev->id);
++}
++
++/**
++ * ata_scsi_dev_enabled - determine if device is enabled
++ * @dev: ATA device
++ *
++ * Determine if commands should be sent to the specified device.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * 0 if commands are not allowed / 1 if commands are allowed
++ */
++
++static int ata_scsi_dev_enabled(struct ata_device *dev)
++{
++ if (unlikely(!ata_dev_enabled(dev)))
++ return 0;
++
++ if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
++ if (unlikely(dev->class == ATA_DEV_ATAPI)) {
++ ata_dev_printk(dev, KERN_WARNING,
++ "WARNING: ATAPI is %s, device ignored.\n",
++ atapi_enabled ? "not supported with this driver" : "disabled");
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++/**
++ * ata_scsi_find_dev - lookup ata_device from scsi_cmnd
++ * @ap: ATA port to which the device is attached
++ * @scsidev: SCSI device from which we derive the ATA device
++ *
++ * Given various information provided in struct scsi_cmnd,
++ * map that onto an ATA bus, and using that mapping
++ * determine which ata_device is associated with the
++ * SCSI command to be sent.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * Associated ATA device, or %NULL if not found.
++ */
++static struct ata_device *
++ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
++{
++ struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
++
++ if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
++ return NULL;
++
++ return dev;
++}
++
++/*
++ * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value.
++ * @byte1: Byte 1 from pass-thru CDB.
++ *
++ * RETURNS:
++ * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise.
++ */
++static u8
++ata_scsi_map_proto(u8 byte1)
++{
++ switch((byte1 & 0x1e) >> 1) {
++ case 3: /* Non-data */
++ return ATA_PROT_NODATA;
++
++ case 6: /* DMA */
++ return ATA_PROT_DMA;
++
++ case 4: /* PIO Data-in */
++ case 5: /* PIO Data-out */
++ return ATA_PROT_PIO;
++
++ case 10: /* Device Reset */
++ case 0: /* Hard Reset */
++ case 1: /* SRST */
++ case 2: /* Bus Idle */
++ case 7: /* Packet */
++ case 8: /* DMA Queued */
++ case 9: /* Device Diagnostic */
++ case 11: /* UDMA Data-in */
++ case 12: /* UDMA Data-Out */
++ case 13: /* FPDMA */
++ default: /* Reserved */
++ break;
++ }
++
++ return ATA_PROT_UNKNOWN;
++}
++
++/**
++ * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
++ * @qc: command structure to be initialized
++ * @scsicmd: SCSI command to convert
++ *
++ * Handles either 12 or 16-byte versions of the CDB.
++ *
++ * RETURNS:
++ * Zero on success, non-zero on failure.
++ */
++static unsigned int
++ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
++{
++ struct ata_taskfile *tf = &(qc->tf);
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ struct ata_device *dev = qc->dev;
++
++ if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN)
++ goto invalid_fld;
++
++ /* We may not issue DMA commands if no DMA mode is set */
++ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
++ goto invalid_fld;
++
++ if (scsicmd[1] & 0xe0)
++ /* PIO multi not supported yet */
++ goto invalid_fld;
++
++ /*
++ * 12 and 16 byte CDBs use different offsets to
++ * provide the various register values.
++ */
++ if (scsicmd[0] == ATA_16) {
++ /*
++ * 16-byte CDB - may contain extended commands.
++ *
++ * If that is the case, copy the upper byte register values.
++ */
++ if (scsicmd[1] & 0x01) {
++ tf->hob_feature = scsicmd[3];
++ tf->hob_nsect = scsicmd[5];
++ tf->hob_lbal = scsicmd[7];
++ tf->hob_lbam = scsicmd[9];
++ tf->hob_lbah = scsicmd[11];
++ tf->flags |= ATA_TFLAG_LBA48;
++ } else
++ tf->flags &= ~ATA_TFLAG_LBA48;
++
++ /*
++ * Always copy low byte, device and command registers.
++ */
++ tf->feature = scsicmd[4];
++ tf->nsect = scsicmd[6];
++ tf->lbal = scsicmd[8];
++ tf->lbam = scsicmd[10];
++ tf->lbah = scsicmd[12];
++ tf->device = scsicmd[13];
++ tf->command = scsicmd[14];
++ } else {
++ /*
++ * 12-byte CDB - incapable of extended commands.
++ */
++ tf->flags &= ~ATA_TFLAG_LBA48;
++
++ tf->feature = scsicmd[3];
++ tf->nsect = scsicmd[4];
++ tf->lbal = scsicmd[5];
++ tf->lbam = scsicmd[6];
++ tf->lbah = scsicmd[7];
++ tf->device = scsicmd[8];
++ tf->command = scsicmd[9];
++ }
++ /*
++ * If slave is possible, enforce correct master/slave bit
++ */
++ if (qc->ap->flags & ATA_FLAG_SLAVE_POSS)
++ tf->device = qc->dev->devno ?
++ tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
++
++ /*
++ * Filter SET_FEATURES - XFER MODE command -- otherwise,
++ * SET_FEATURES - XFER MODE must be preceded/succeeded
++ * by an update to hardware-specific registers for each
++ * controller (i.e. the reason for ->set_piomode(),
++ * ->set_dmamode(), and ->post_set_mode() hooks).
++ */
++ if ((tf->command == ATA_CMD_SET_FEATURES)
++ && (tf->feature == SETFEATURES_XFER))
++ goto invalid_fld;
++
++ /*
++ * Set flags so that all registers will be written,
++ * and pass on write indication (used for PIO/DMA
++ * setup.)
++ */
++ tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE);
++
++ if (cmd->sc_data_direction == DMA_TO_DEVICE)
++ tf->flags |= ATA_TFLAG_WRITE;
++
++ /*
++ * Set transfer length.
++ *
++ * TODO: find out if we need to do more here to
++ * cover scatter/gather case.
++ */
++ qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE;
++
++ /* request result TF */
++ qc->flags |= ATA_QCFLAG_RESULT_TF;
++
++ return 0;
++
++ invalid_fld:
++ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00);
++ /* "Invalid field in cdb" */
++ return 1;
++}
++
++/**
++ * ata_get_xlat_func - check if SCSI to ATA translation is possible
++ * @dev: ATA device
++ * @cmd: SCSI command opcode to consider
++ *
++ * Look up the SCSI command given, and determine whether the
++ * SCSI command is to be translated or simulated.
++ *
++ * RETURNS:
++ * Pointer to translation function if possible, %NULL if not.
++ */
++
++static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
++{
++ switch (cmd) {
++ case READ_6:
++ case READ_10:
++ case READ_16:
++
++ case WRITE_6:
++ case WRITE_10:
++ case WRITE_16:
++ return ata_scsi_rw_xlat;
++
++ case SYNCHRONIZE_CACHE:
++ if (ata_try_flush_cache(dev))
++ return ata_scsi_flush_xlat;
++ break;
++
++ case VERIFY:
++ case VERIFY_16:
++ return ata_scsi_verify_xlat;
++
++ case ATA_12:
++ case ATA_16:
++ return ata_scsi_pass_thru;
++
++ case START_STOP:
++ return ata_scsi_start_stop_xlat;
++ }
++
++ return NULL;
++}
++
++/**
++ * ata_scsi_dump_cdb - dump SCSI command contents to dmesg
++ * @ap: ATA port to which the command was being sent
++ * @cmd: SCSI command to dump
++ *
++ * Prints the contents of a SCSI command via printk().
++ */
++
++static inline void ata_scsi_dump_cdb(struct ata_port *ap,
++ struct scsi_cmnd *cmd)
++{
++#ifdef ATA_DEBUG
++ struct scsi_device *scsidev = cmd->device;
++ u8 *scsicmd = cmd->cmnd;
++
++ DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
++ ap->id,
++ scsidev->channel, scsidev->id, scsidev->lun,
++ scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
++ scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
++ scsicmd[8]);
++#endif
++}
++
++static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *),
++ struct ata_device *dev)
++{
++ int rc = 0;
++
++ if (dev->class == ATA_DEV_ATA) {
++ ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
++ cmd->cmnd[0]);
++
++ if (xlat_func)
++ rc = ata_scsi_translate(dev, cmd, done, xlat_func);
++ else
++ ata_scsi_simulate(dev, cmd, done);
++ } else
++ rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
++
++ return rc;
++}
++
++/**
++ * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
++ * @cmd: SCSI command to be sent
++ * @done: Completion function, called when command is complete
++ *
++ * In some cases, this function translates SCSI commands into
++ * ATA taskfiles, and queues the taskfiles to be sent to
++ * hardware. In other cases, this function simulates a
++ * SCSI device by evaluating and responding to certain
++ * SCSI commands. This creates the overall effect of
++ * ATA and ATAPI devices appearing as SCSI devices.
++ *
++ * LOCKING:
++ * Releases scsi-layer-held lock, and obtains host lock.
++ *
++ * RETURNS:
++ * Return value from __ata_scsi_queuecmd() if @cmd can be queued,
++ * 0 otherwise.
++ */
++int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
++{
++ struct ata_port *ap;
++ struct ata_device *dev;
++ struct scsi_device *scsidev = cmd->device;
++ struct Scsi_Host *shost = scsidev->host;
++ int rc = 0;
++
++ ap = ata_shost_to_port(shost);
++
++ spin_unlock(shost->host_lock);
++ spin_lock(ap->lock);
++
++ ata_scsi_dump_cdb(ap, cmd);
++
++ dev = ata_scsi_find_dev(ap, scsidev);
++ if (likely(dev))
++ rc = __ata_scsi_queuecmd(cmd, done, dev);
++ else {
++ cmd->result = (DID_BAD_TARGET << 16);
++ done(cmd);
++ }
++
++ spin_unlock(ap->lock);
++ spin_lock(shost->host_lock);
++ return rc;
++}
++
++/**
++ * ata_scsi_simulate - simulate SCSI command on ATA device
++ * @dev: the target device
++ * @cmd: SCSI command being sent to device.
++ * @done: SCSI command completion function.
++ *
++ * Interprets and directly executes a select list of SCSI commands
++ * that can be handled internally.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
++{
++ struct ata_scsi_args args;
++ const u8 *scsicmd = cmd->cmnd;
++
++ args.dev = dev;
++ args.id = dev->id;
++ args.cmd = cmd;
++ args.done = done;
++
++ switch(scsicmd[0]) {
++ /* no-op's, complete with success */
++ case SYNCHRONIZE_CACHE:
++ case REZERO_UNIT:
++ case SEEK_6:
++ case SEEK_10:
++ case TEST_UNIT_READY:
++ case FORMAT_UNIT: /* FIXME: correct? */
++ case SEND_DIAGNOSTIC: /* FIXME: correct? */
++ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
++ break;
++
++ case INQUIRY:
++ if (scsicmd[1] & 2) /* is CmdDt set? */
++ ata_scsi_invalid_field(cmd, done);
++ else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
++ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
++ else if (scsicmd[2] == 0x00)
++ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
++ else if (scsicmd[2] == 0x80)
++ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
++ else if (scsicmd[2] == 0x83)
++ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
++ else
++ ata_scsi_invalid_field(cmd, done);
++ break;
++
++ case MODE_SENSE:
++ case MODE_SENSE_10:
++ ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
++ break;
++
++ case MODE_SELECT: /* unconditionally return */
++ case MODE_SELECT_10: /* bad-field-in-cdb */
++ ata_scsi_invalid_field(cmd, done);
++ break;
++
++ case READ_CAPACITY:
++ ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
++ break;
++
++ case SERVICE_ACTION_IN:
++ if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
++ ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
++ else
++ ata_scsi_invalid_field(cmd, done);
++ break;
++
++ case REPORT_LUNS:
++ ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
++ break;
++
++ /* mandatory commands we haven't implemented yet */
++ case REQUEST_SENSE:
++
++ /* all other commands */
++ default:
++ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
++ /* "Invalid command operation code" */
++ done(cmd);
++ break;
++ }
++}
++
++void ata_scsi_scan_host(struct ata_port *ap)
++{
++ unsigned int i;
++
++ if (ap->flags & ATA_FLAG_DISABLED)
++ return;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ struct scsi_device *sdev;
++
++ if (!ata_dev_enabled(dev) || dev->sdev)
++ continue;
++
++ sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
++ if (!IS_ERR(sdev)) {
++ dev->sdev = sdev;
++ scsi_device_put(sdev);
++ }
++ }
++}
++
++/**
++ * ata_scsi_offline_dev - offline attached SCSI device
++ * @dev: ATA device to offline attached SCSI device for
++ *
++ * This function is called from ata_eh_hotplug() and responsible
++ * for taking the SCSI device attached to @dev offline. This
++ * function is called with host lock which protects dev->sdev
++ * against clearing.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ * RETURNS:
++ * 1 if attached SCSI device exists, 0 otherwise.
++ */
++int ata_scsi_offline_dev(struct ata_device *dev)
++{
++ if (dev->sdev) {
++ scsi_device_set_state(dev->sdev, SDEV_OFFLINE);
++ return 1;
++ }
++ return 0;
++}
++
++/**
++ * ata_scsi_remove_dev - remove attached SCSI device
++ * @dev: ATA device to remove attached SCSI device for
++ *
++ * This function is called from ata_eh_scsi_hotplug() and
++ * responsible for removing the SCSI device attached to @dev.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++static void ata_scsi_remove_dev(struct ata_device *dev)
++{
++ struct ata_port *ap = dev->ap;
++ struct scsi_device *sdev;
++ unsigned long flags;
++
++ /* Alas, we need to grab scan_mutex to ensure SCSI device
++ * state doesn't change underneath us and thus
++ * scsi_device_get() always succeeds. The mutex locking can
++ * be removed if there is __scsi_device_get() interface which
++ * increments reference counts regardless of device state.
++ */
++ mutex_lock(&ap->scsi_host->scan_mutex);
++ spin_lock_irqsave(ap->lock, flags);
++
++ /* clearing dev->sdev is protected by host lock */
++ sdev = dev->sdev;
++ dev->sdev = NULL;
++
++ if (sdev) {
++ /* If user initiated unplug races with us, sdev can go
++ * away underneath us after the host lock and
++ * scan_mutex are released. Hold onto it.
++ */
++ if (scsi_device_get(sdev) == 0) {
++ /* The following ensures the attached sdev is
++ * offline on return from ata_scsi_offline_dev()
++ * regardless it wins or loses the race
++ * against this function.
++ */
++ scsi_device_set_state(sdev, SDEV_OFFLINE);
++ } else {
++ WARN_ON(1);
++ sdev = NULL;
++ }
++ }
++
++ spin_unlock_irqrestore(ap->lock, flags);
++ mutex_unlock(&ap->scsi_host->scan_mutex);
++
++ if (sdev) {
++ ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
++ sdev->sdev_gendev.bus_id);
++
++ scsi_remove_device(sdev);
++ scsi_device_put(sdev);
++ }
++}
++
++/**
++ * ata_scsi_hotplug - SCSI part of hotplug
++ * @data: Pointer to ATA port to perform SCSI hotplug on
++ *
++ * Perform SCSI part of hotplug. It's executed from a separate
++ * workqueue after EH completes. This is necessary because SCSI
++ * hot plugging requires working EH and hot unplugging is
++ * synchronized with hot plugging with a mutex.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++void ata_scsi_hotplug(void *data)
++{
++ struct ata_port *ap = data;
++ int i;
++
++ if (ap->pflags & ATA_PFLAG_UNLOADING) {
++ DPRINTK("ENTER/EXIT - unloading\n");
++ return;
++ }
++
++ DPRINTK("ENTER\n");
++
++ /* unplug detached devices */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ unsigned long flags;
++
++ if (!(dev->flags & ATA_DFLAG_DETACHED))
++ continue;
++
++ spin_lock_irqsave(ap->lock, flags);
++ dev->flags &= ~ATA_DFLAG_DETACHED;
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ ata_scsi_remove_dev(dev);
++ }
++
++ /* scan for new ones */
++ ata_scsi_scan_host(ap);
++
++ /* If we scanned while EH was in progress, scan would have
++ * failed silently. Requeue if there are enabled but
++ * unattached devices.
++ */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ if (ata_dev_enabled(dev) && !dev->sdev) {
++ queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
++ break;
++ }
++ }
++
++ DPRINTK("EXIT\n");
++}
++
++/**
++ * ata_scsi_user_scan - indication for user-initiated bus scan
++ * @shost: SCSI host to scan
++ * @channel: Channel to scan
++ * @id: ID to scan
++ * @lun: LUN to scan
++ *
++ * This function is called when user explicitly requests bus
++ * scan. Set probe pending flag and invoke EH.
++ *
++ * LOCKING:
++ * SCSI layer (we don't care)
++ *
++ * RETURNS:
++ * Zero.
++ */
++static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
++ unsigned int id, unsigned int lun)
++{
++ struct ata_port *ap = ata_shost_to_port(shost);
++ unsigned long flags;
++ int rc = 0;
++
++ if (!ap->ops->error_handler)
++ return -EOPNOTSUPP;
++
++ if ((channel != SCAN_WILD_CARD && channel != 0) ||
++ (lun != SCAN_WILD_CARD && lun != 0))
++ return -EINVAL;
++
++ spin_lock_irqsave(ap->lock, flags);
++
++ if (id == SCAN_WILD_CARD) {
++ ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
++ ap->eh_info.action |= ATA_EH_SOFTRESET;
++ } else {
++ struct ata_device *dev = ata_find_dev(ap, id);
++
++ if (dev) {
++ ap->eh_info.probe_mask |= 1 << dev->devno;
++ ap->eh_info.action |= ATA_EH_SOFTRESET;
++ ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
++ } else
++ rc = -EINVAL;
++ }
++
++ if (rc == 0)
++ ata_port_schedule_eh(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ return rc;
++}
++
++/**
++ * ata_scsi_dev_rescan - initiate scsi_rescan_device()
++ * @data: Pointer to ATA port to perform scsi_rescan_device()
++ *
++ * After ATA pass thru (SAT) commands are executed successfully,
++ * libata need to propagate the changes to SCSI layer. This
++ * function must be executed from ata_aux_wq such that sdev
++ * attach/detach don't race with rescan.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep).
++ */
++void ata_scsi_dev_rescan(void *data)
++{
++ struct ata_port *ap = data;
++ struct ata_device *dev;
++ unsigned int i;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ dev = &ap->device[i];
++
++ if (ata_dev_enabled(dev) && dev->sdev)
++ scsi_rescan_device(&(dev->sdev->sdev_gendev));
++ }
++}
++
++/**
++ * ata_sas_port_alloc - Allocate port for a SAS attached SATA device
++ * @host: ATA host container for all SAS ports
++ * @port_info: Information from low-level host driver
++ * @shost: SCSI host that the scsi device is attached to
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * ata_port pointer on success / NULL on failure.
++ */
++
++struct ata_port *ata_sas_port_alloc(struct ata_host *host,
++ struct ata_port_info *port_info,
++ struct Scsi_Host *shost)
++{
++ struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
++ struct ata_probe_ent *ent;
++
++ if (!ap)
++ return NULL;
++
++ ent = ata_probe_ent_alloc(host->dev, port_info);
++ if (!ent) {
++ kfree(ap);
++ return NULL;
++ }
++
++ ata_port_init(ap, host, ent, 0);
++ ap->lock = shost->host_lock;
++ kfree(ent);
++ return ap;
++}
++EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
++
++/**
++ * ata_sas_port_start - Set port up for dma.
++ * @ap: Port to initialize
++ *
++ * Called just after data structures for each port are
++ * initialized. Allocates DMA pad.
++ *
++ * May be used as the port_start() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++int ata_sas_port_start(struct ata_port *ap)
++{
++ return ata_pad_alloc(ap, ap->dev);
++}
++EXPORT_SYMBOL_GPL(ata_sas_port_start);
++
++/**
++ * ata_port_stop - Undo ata_sas_port_start()
++ * @ap: Port to shut down
++ *
++ * Frees the DMA pad.
++ *
++ * May be used as the port_stop() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++void ata_sas_port_stop(struct ata_port *ap)
++{
++ ata_pad_free(ap, ap->dev);
++}
++EXPORT_SYMBOL_GPL(ata_sas_port_stop);
++
++/**
++ * ata_sas_port_init - Initialize a SATA device
++ * @ap: SATA port to initialize
++ *
++ * LOCKING:
++ * PCI/etc. bus probe sem.
++ *
++ * RETURNS:
++ * Zero on success, non-zero on error.
++ */
++
++int ata_sas_port_init(struct ata_port *ap)
++{
++ int rc = ap->ops->port_start(ap);
++
++ if (!rc)
++ rc = ata_bus_probe(ap);
++
++ return rc;
++}
++EXPORT_SYMBOL_GPL(ata_sas_port_init);
++
++/**
++ * ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc
++ * @ap: SATA port to destroy
++ *
++ */
++
++void ata_sas_port_destroy(struct ata_port *ap)
++{
++ ap->ops->port_stop(ap);
++ kfree(ap);
++}
++EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
++
++/**
++ * ata_sas_slave_configure - Default slave_config routine for libata devices
++ * @sdev: SCSI device to configure
++ * @ap: ATA port to which SCSI device is attached
++ *
++ * RETURNS:
++ * Zero.
++ */
++
++int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
++{
++ ata_scsi_sdev_config(sdev);
++ ata_scsi_dev_config(sdev, ap->device);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
++
++/**
++ * ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
++ * @cmd: SCSI command to be sent
++ * @done: Completion function, called when command is complete
++ * @ap: ATA port to which the command is being sent
++ *
++ * RETURNS:
++ * Zero.
++ */
++
++int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
++ struct ata_port *ap)
++{
++ ata_scsi_dump_cdb(ap, cmd);
++
++ if (likely(ata_scsi_dev_enabled(ap->device)))
++ __ata_scsi_queuecmd(cmd, done, ap->device);
++ else {
++ cmd->result = (DID_BAD_TARGET << 16);
++ done(cmd);
++ }
++ return 0;
++}
++EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
+diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
+new file mode 100644
+index 0000000..7645f2b
+--- /dev/null
++++ b/drivers/ata/libata-sff.c
+@@ -0,0 +1,1130 @@
++/*
++ * libata-bmdma.c - helper library for PCI IDE BMDMA
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003-2006 Red Hat, Inc. All rights reserved.
++ * Copyright 2003-2006 Jeff Garzik
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available from http://www.t13.org/ and
++ * http://www.sata-io.org/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/libata.h>
++
++#include "libata.h"
++
++/**
++ * ata_tf_load_pio - send taskfile registers to host controller
++ * @ap: Port to which output is sent
++ * @tf: ATA taskfile register set
++ *
++ * Outputs ATA taskfile to standard ATA host controller.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
++
++ if (tf->ctl != ap->last_ctl) {
++ outb(tf->ctl, ioaddr->ctl_addr);
++ ap->last_ctl = tf->ctl;
++ ata_wait_idle(ap);
++ }
++
++ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
++ outb(tf->hob_feature, ioaddr->feature_addr);
++ outb(tf->hob_nsect, ioaddr->nsect_addr);
++ outb(tf->hob_lbal, ioaddr->lbal_addr);
++ outb(tf->hob_lbam, ioaddr->lbam_addr);
++ outb(tf->hob_lbah, ioaddr->lbah_addr);
++ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
++ tf->hob_feature,
++ tf->hob_nsect,
++ tf->hob_lbal,
++ tf->hob_lbam,
++ tf->hob_lbah);
++ }
++
++ if (is_addr) {
++ outb(tf->feature, ioaddr->feature_addr);
++ outb(tf->nsect, ioaddr->nsect_addr);
++ outb(tf->lbal, ioaddr->lbal_addr);
++ outb(tf->lbam, ioaddr->lbam_addr);
++ outb(tf->lbah, ioaddr->lbah_addr);
++ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
++ tf->feature,
++ tf->nsect,
++ tf->lbal,
++ tf->lbam,
++ tf->lbah);
++ }
++
++ if (tf->flags & ATA_TFLAG_DEVICE) {
++ outb(tf->device, ioaddr->device_addr);
++ VPRINTK("device 0x%X\n", tf->device);
++ }
++
++ ata_wait_idle(ap);
++}
++
++/**
++ * ata_tf_load_mmio - send taskfile registers to host controller
++ * @ap: Port to which output is sent
++ * @tf: ATA taskfile register set
++ *
++ * Outputs ATA taskfile to standard ATA host controller using MMIO.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
++
++ if (tf->ctl != ap->last_ctl) {
++ writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
++ ap->last_ctl = tf->ctl;
++ ata_wait_idle(ap);
++ }
++
++ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
++ writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
++ writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
++ writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
++ writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
++ writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
++ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
++ tf->hob_feature,
++ tf->hob_nsect,
++ tf->hob_lbal,
++ tf->hob_lbam,
++ tf->hob_lbah);
++ }
++
++ if (is_addr) {
++ writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
++ writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
++ writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
++ writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
++ writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
++ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
++ tf->feature,
++ tf->nsect,
++ tf->lbal,
++ tf->lbam,
++ tf->lbah);
++ }
++
++ if (tf->flags & ATA_TFLAG_DEVICE) {
++ writeb(tf->device, (void __iomem *) ioaddr->device_addr);
++ VPRINTK("device 0x%X\n", tf->device);
++ }
++
++ ata_wait_idle(ap);
++}
++
++
++/**
++ * ata_tf_load - send taskfile registers to host controller
++ * @ap: Port to which output is sent
++ * @tf: ATA taskfile register set
++ *
++ * Outputs ATA taskfile to standard ATA host controller using MMIO
++ * or PIO as indicated by the ATA_FLAG_MMIO flag.
++ * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
++ * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
++ * hob_lbal, hob_lbam, and hob_lbah.
++ *
++ * This function waits for idle (!BUSY and !DRQ) after writing
++ * registers. If the control register has a new value, this
++ * function also waits for idle after writing control and before
++ * writing the remaining registers.
++ *
++ * May be used as the tf_load() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ if (ap->flags & ATA_FLAG_MMIO)
++ ata_tf_load_mmio(ap, tf);
++ else
++ ata_tf_load_pio(ap, tf);
++}
++
++/**
++ * ata_exec_command_pio - issue ATA command to host controller
++ * @ap: port to which command is being issued
++ * @tf: ATA taskfile register set
++ *
++ * Issues PIO write to ATA command register, with proper
++ * synchronization with interrupt handler / other threads.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
++
++ outb(tf->command, ap->ioaddr.command_addr);
++ ata_pause(ap);
++}
++
++
++/**
++ * ata_exec_command_mmio - issue ATA command to host controller
++ * @ap: port to which command is being issued
++ * @tf: ATA taskfile register set
++ *
++ * Issues MMIO write to ATA command register, with proper
++ * synchronization with interrupt handler / other threads.
++ *
++ * FIXME: missing write posting for 400nS delay enforcement
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
++
++ writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
++ ata_pause(ap);
++}
++
++
++/**
++ * ata_exec_command - issue ATA command to host controller
++ * @ap: port to which command is being issued
++ * @tf: ATA taskfile register set
++ *
++ * Issues PIO/MMIO write to ATA command register, with proper
++ * synchronization with interrupt handler / other threads.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ if (ap->flags & ATA_FLAG_MMIO)
++ ata_exec_command_mmio(ap, tf);
++ else
++ ata_exec_command_pio(ap, tf);
++}
++
++/**
++ * ata_tf_read_pio - input device's ATA taskfile shadow registers
++ * @ap: Port from which input is read
++ * @tf: ATA taskfile register set for storing input
++ *
++ * Reads ATA taskfile registers for currently-selected device
++ * into @tf.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++
++ tf->command = ata_check_status(ap);
++ tf->feature = inb(ioaddr->error_addr);
++ tf->nsect = inb(ioaddr->nsect_addr);
++ tf->lbal = inb(ioaddr->lbal_addr);
++ tf->lbam = inb(ioaddr->lbam_addr);
++ tf->lbah = inb(ioaddr->lbah_addr);
++ tf->device = inb(ioaddr->device_addr);
++
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
++ tf->hob_feature = inb(ioaddr->error_addr);
++ tf->hob_nsect = inb(ioaddr->nsect_addr);
++ tf->hob_lbal = inb(ioaddr->lbal_addr);
++ tf->hob_lbam = inb(ioaddr->lbam_addr);
++ tf->hob_lbah = inb(ioaddr->lbah_addr);
++ }
++}
++
++/**
++ * ata_tf_read_mmio - input device's ATA taskfile shadow registers
++ * @ap: Port from which input is read
++ * @tf: ATA taskfile register set for storing input
++ *
++ * Reads ATA taskfile registers for currently-selected device
++ * into @tf via MMIO.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++
++static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++
++ tf->command = ata_check_status(ap);
++ tf->feature = readb((void __iomem *)ioaddr->error_addr);
++ tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
++ tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
++ tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
++ tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
++ tf->device = readb((void __iomem *)ioaddr->device_addr);
++
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
++ tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
++ tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
++ tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
++ tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
++ tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
++ }
++}
++
++
++/**
++ * ata_tf_read - input device's ATA taskfile shadow registers
++ * @ap: Port from which input is read
++ * @tf: ATA taskfile register set for storing input
++ *
++ * Reads ATA taskfile registers for currently-selected device
++ * into @tf.
++ *
++ * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
++ * is set, also reads the hob registers.
++ *
++ * May be used as the tf_read() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ if (ap->flags & ATA_FLAG_MMIO)
++ ata_tf_read_mmio(ap, tf);
++ else
++ ata_tf_read_pio(ap, tf);
++}
++
++/**
++ * ata_check_status_pio - Read device status reg & clear interrupt
++ * @ap: port where the device is
++ *
++ * Reads ATA taskfile status register for currently-selected device
++ * and return its value. This also clears pending interrupts
++ * from this device
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static u8 ata_check_status_pio(struct ata_port *ap)
++{
++ return inb(ap->ioaddr.status_addr);
++}
++
++/**
++ * ata_check_status_mmio - Read device status reg & clear interrupt
++ * @ap: port where the device is
++ *
++ * Reads ATA taskfile status register for currently-selected device
++ * via MMIO and return its value. This also clears pending interrupts
++ * from this device
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static u8 ata_check_status_mmio(struct ata_port *ap)
++{
++ return readb((void __iomem *) ap->ioaddr.status_addr);
++}
++
++
++/**
++ * ata_check_status - Read device status reg & clear interrupt
++ * @ap: port where the device is
++ *
++ * Reads ATA taskfile status register for currently-selected device
++ * and return its value. This also clears pending interrupts
++ * from this device
++ *
++ * May be used as the check_status() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++u8 ata_check_status(struct ata_port *ap)
++{
++ if (ap->flags & ATA_FLAG_MMIO)
++ return ata_check_status_mmio(ap);
++ return ata_check_status_pio(ap);
++}
++
++
++/**
++ * ata_altstatus - Read device alternate status reg
++ * @ap: port where the device is
++ *
++ * Reads ATA taskfile alternate status register for
++ * currently-selected device and return its value.
++ *
++ * Note: may NOT be used as the check_altstatus() entry in
++ * ata_port_operations.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++u8 ata_altstatus(struct ata_port *ap)
++{
++ if (ap->ops->check_altstatus)
++ return ap->ops->check_altstatus(ap);
++
++ if (ap->flags & ATA_FLAG_MMIO)
++ return readb((void __iomem *)ap->ioaddr.altstatus_addr);
++ return inb(ap->ioaddr.altstatus_addr);
++}
++
++/**
++ * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
++ * @qc: Info associated with this ATA transaction.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
++ u8 dmactl;
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++
++ /* load PRD table addr. */
++ mb(); /* make sure PRD table writes are visible to controller */
++ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
++
++ /* specify data direction, triple-check start bit is clear */
++ dmactl = readb(mmio + ATA_DMA_CMD);
++ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
++ if (!rw)
++ dmactl |= ATA_DMA_WR;
++ writeb(dmactl, mmio + ATA_DMA_CMD);
++
++ /* issue r/w command */
++ ap->ops->exec_command(ap, &qc->tf);
++}
++
++/**
++ * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
++ * @qc: Info associated with this ATA transaction.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++ u8 dmactl;
++
++ /* start host DMA transaction */
++ dmactl = readb(mmio + ATA_DMA_CMD);
++ writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
++
++ /* Strictly, one may wish to issue a readb() here, to
++ * flush the mmio write. However, control also passes
++ * to the hardware at this point, and it will interrupt
++ * us when we are to resume control. So, in effect,
++ * we don't care when the mmio write flushes.
++ * Further, a read of the DMA status register _immediately_
++ * following the write may not be what certain flaky hardware
++ * is expected, so I think it is best to not add a readb()
++ * without first all the MMIO ATA cards/mobos.
++ * Or maybe I'm just being paranoid.
++ */
++}
++
++/**
++ * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
++ * @qc: Info associated with this ATA transaction.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
++ u8 dmactl;
++
++ /* load PRD table addr. */
++ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
++
++ /* specify data direction, triple-check start bit is clear */
++ dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
++ if (!rw)
++ dmactl |= ATA_DMA_WR;
++ outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++
++ /* issue r/w command */
++ ap->ops->exec_command(ap, &qc->tf);
++}
++
++/**
++ * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
++ * @qc: Info associated with this ATA transaction.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ u8 dmactl;
++
++ /* start host DMA transaction */
++ dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++ outb(dmactl | ATA_DMA_START,
++ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++}
++
++
++/**
++ * ata_bmdma_start - Start a PCI IDE BMDMA transaction
++ * @qc: Info associated with this ATA transaction.
++ *
++ * Writes the ATA_DMA_START flag to the DMA command register.
++ *
++ * May be used as the bmdma_start() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_bmdma_start(struct ata_queued_cmd *qc)
++{
++ if (qc->ap->flags & ATA_FLAG_MMIO)
++ ata_bmdma_start_mmio(qc);
++ else
++ ata_bmdma_start_pio(qc);
++}
++
++
++/**
++ * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
++ * @qc: Info associated with this ATA transaction.
++ *
++ * Writes address of PRD table to device's PRD Table Address
++ * register, sets the DMA control register, and calls
++ * ops->exec_command() to start the transfer.
++ *
++ * May be used as the bmdma_setup() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++void ata_bmdma_setup(struct ata_queued_cmd *qc)
++{
++ if (qc->ap->flags & ATA_FLAG_MMIO)
++ ata_bmdma_setup_mmio(qc);
++ else
++ ata_bmdma_setup_pio(qc);
++}
++
++
++/**
++ * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
++ * @ap: Port associated with this ATA transaction.
++ *
++ * Clear interrupt and error flags in DMA status register.
++ *
++ * May be used as the irq_clear() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_bmdma_irq_clear(struct ata_port *ap)
++{
++ if (!ap->ioaddr.bmdma_addr)
++ return;
++
++ if (ap->flags & ATA_FLAG_MMIO) {
++ void __iomem *mmio =
++ ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
++ writeb(readb(mmio), mmio);
++ } else {
++ unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
++ outb(inb(addr), addr);
++ }
++}
++
++
++/**
++ * ata_bmdma_status - Read PCI IDE BMDMA status
++ * @ap: Port associated with this ATA transaction.
++ *
++ * Read and return BMDMA status register.
++ *
++ * May be used as the bmdma_status() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++u8 ata_bmdma_status(struct ata_port *ap)
++{
++ u8 host_stat;
++ if (ap->flags & ATA_FLAG_MMIO) {
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++ host_stat = readb(mmio + ATA_DMA_STATUS);
++ } else
++ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
++ return host_stat;
++}
++
++
++/**
++ * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
++ * @qc: Command we are ending DMA for
++ *
++ * Clears the ATA_DMA_START flag in the dma control register
++ *
++ * May be used as the bmdma_stop() entry in ata_port_operations.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++void ata_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ if (ap->flags & ATA_FLAG_MMIO) {
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++
++ /* clear start/stop bit */
++ writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
++ mmio + ATA_DMA_CMD);
++ } else {
++ /* clear start/stop bit */
++ outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
++ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++ }
++
++ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
++ ata_altstatus(ap); /* dummy read */
++}
++
++/**
++ * ata_bmdma_freeze - Freeze BMDMA controller port
++ * @ap: port to freeze
++ *
++ * Freeze BMDMA controller port.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_bmdma_freeze(struct ata_port *ap)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++
++ ap->ctl |= ATA_NIEN;
++ ap->last_ctl = ap->ctl;
++
++ if (ap->flags & ATA_FLAG_MMIO)
++ writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
++ else
++ outb(ap->ctl, ioaddr->ctl_addr);
++}
++
++/**
++ * ata_bmdma_thaw - Thaw BMDMA controller port
++ * @ap: port to thaw
++ *
++ * Thaw BMDMA controller port.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++void ata_bmdma_thaw(struct ata_port *ap)
++{
++ /* clear & re-enable interrupts */
++ ata_chk_status(ap);
++ ap->ops->irq_clear(ap);
++ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
++ ata_irq_on(ap);
++}
++
++/**
++ * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
++ * @ap: port to handle error for
++ * @prereset: prereset method (can be NULL)
++ * @softreset: softreset method (can be NULL)
++ * @hardreset: hardreset method (can be NULL)
++ * @postreset: postreset method (can be NULL)
++ *
++ * Handle error for ATA BMDMA controller. It can handle both
++ * PATA and SATA controllers. Many controllers should be able to
++ * use this EH as-is or with some added handling before and
++ * after.
++ *
++ * This function is intended to be used for constructing
++ * ->error_handler callback by low level drivers.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ */
++void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
++ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
++ ata_postreset_fn_t postreset)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ struct ata_queued_cmd *qc;
++ unsigned long flags;
++ int thaw = 0;
++
++ qc = __ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
++ qc = NULL;
++
++ /* reset PIO HSM and stop DMA engine */
++ spin_lock_irqsave(ap->lock, flags);
++
++ ap->hsm_task_state = HSM_ST_IDLE;
++
++ if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
++ qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
++ u8 host_stat;
++
++ host_stat = ata_bmdma_status(ap);
++
++ ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);
++
++ /* BMDMA controllers indicate host bus error by
++ * setting DMA_ERR bit and timing out. As it wasn't
++ * really a timeout event, adjust error mask and
++ * cancel frozen state.
++ */
++ if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
++ qc->err_mask = AC_ERR_HOST_BUS;
++ thaw = 1;
++ }
++
++ ap->ops->bmdma_stop(qc);
++ }
++
++ ata_altstatus(ap);
++ ata_chk_status(ap);
++ ap->ops->irq_clear(ap);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ if (thaw)
++ ata_eh_thaw_port(ap);
++
++ /* PIO and DMA engines have been stopped, perform recovery */
++ ata_do_eh(ap, prereset, softreset, hardreset, postreset);
++}
++
++/**
++ * ata_bmdma_error_handler - Stock error handler for BMDMA controller
++ * @ap: port to handle error for
++ *
++ * Stock error handler for BMDMA controller.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ */
++void ata_bmdma_error_handler(struct ata_port *ap)
++{
++ ata_reset_fn_t hardreset;
++
++ hardreset = NULL;
++ if (sata_scr_valid(ap))
++ hardreset = sata_std_hardreset;
++
++ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
++ ata_std_postreset);
++}
++
++/**
++ * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
++ * BMDMA controller
++ * @qc: internal command to clean up
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ */
++void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
++{
++ ata_bmdma_stop(qc);
++}
++
++#ifdef CONFIG_PCI
++/**
++ * ata_pci_init_native_mode - Initialize native-mode driver
++ * @pdev: pci device to be initialized
++ * @port: array[2] of pointers to port info structures.
++ * @ports: bitmap of ports present
++ *
++ * Utility function which allocates and initializes an
++ * ata_probe_ent structure for a standard dual-port
++ * PIO-based IDE controller. The returned ata_probe_ent
++ * structure can be passed to ata_device_add(). The returned
++ * ata_probe_ent structure should then be freed with kfree().
++ *
++ * The caller need only pass the address of the primary port, the
++ * secondary will be deduced automatically. If the device has non
++ * standard secondary port mappings this function can be called twice,
++ * once for each interface.
++ */
++
++struct ata_probe_ent *
++ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
++{
++ struct ata_probe_ent *probe_ent =
++ ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
++ int p = 0;
++ unsigned long bmdma;
++
++ if (!probe_ent)
++ return NULL;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++
++ if (ports & ATA_PORT_PRIMARY) {
++ probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
++ probe_ent->port[p].altstatus_addr =
++ probe_ent->port[p].ctl_addr =
++ pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
++ bmdma = pci_resource_start(pdev, 4);
++ if (bmdma) {
++ if (inb(bmdma + 2) & 0x80)
++ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
++ probe_ent->port[p].bmdma_addr = bmdma;
++ }
++ ata_std_ports(&probe_ent->port[p]);
++ p++;
++ }
++
++ if (ports & ATA_PORT_SECONDARY) {
++ probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
++ probe_ent->port[p].altstatus_addr =
++ probe_ent->port[p].ctl_addr =
++ pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
++ bmdma = pci_resource_start(pdev, 4);
++ if (bmdma) {
++ bmdma += 8;
++ if(inb(bmdma + 2) & 0x80)
++ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
++ probe_ent->port[p].bmdma_addr = bmdma;
++ }
++ ata_std_ports(&probe_ent->port[p]);
++ probe_ent->pinfo2 = port[1];
++ p++;
++ }
++
++ probe_ent->n_ports = p;
++ return probe_ent;
++}
++
++
++static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
++ struct ata_port_info **port, int port_mask)
++{
++ struct ata_probe_ent *probe_ent;
++ unsigned long bmdma = pci_resource_start(pdev, 4);
++
++ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
++ if (!probe_ent)
++ return NULL;
++
++ probe_ent->n_ports = 2;
++
++ if (port_mask & ATA_PORT_PRIMARY) {
++ probe_ent->irq = ATA_PRIMARY_IRQ;
++ probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
++ probe_ent->port[0].altstatus_addr =
++ probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
++ if (bmdma) {
++ probe_ent->port[0].bmdma_addr = bmdma;
++ if (inb(bmdma + 2) & 0x80)
++ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
++ }
++ ata_std_ports(&probe_ent->port[0]);
++ } else
++ probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
++
++ if (port_mask & ATA_PORT_SECONDARY) {
++ if (probe_ent->irq)
++ probe_ent->irq2 = ATA_SECONDARY_IRQ;
++ else
++ probe_ent->irq = ATA_SECONDARY_IRQ;
++ probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
++ probe_ent->port[1].altstatus_addr =
++ probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
++ if (bmdma) {
++ probe_ent->port[1].bmdma_addr = bmdma + 8;
++ if (inb(bmdma + 10) & 0x80)
++ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
++ }
++ ata_std_ports(&probe_ent->port[1]);
++
++ /* FIXME: could be pointing to stack area; must copy */
++ probe_ent->pinfo2 = port[1];
++ } else
++ probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
++
++ return probe_ent;
++}
++
++
++/**
++ * ata_pci_init_one - Initialize/register PCI IDE host controller
++ * @pdev: Controller to be initialized
++ * @port_info: Information from low-level host driver
++ * @n_ports: Number of ports attached to host controller
++ *
++ * This is a helper function which can be called from a driver's
++ * xxx_init_one() probe function if the hardware uses traditional
++ * IDE taskfile registers.
++ *
++ * This function calls pci_enable_device(), reserves its register
++ * regions, sets the dma mask, enables bus master mode, and calls
++ * ata_device_add()
++ *
++ * ASSUMPTION:
++ * Nobody makes a single channel controller that appears solely as
++ * the secondary legacy port on PCI.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, negative on errno-based value on error.
++ */
++
++int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
++ unsigned int n_ports)
++{
++ struct ata_probe_ent *probe_ent = NULL;
++ struct ata_port_info *port[2];
++ u8 mask;
++ unsigned int legacy_mode = 0;
++ int disable_dev_on_err = 1;
++ int rc;
++
++ DPRINTK("ENTER\n");
++
++ BUG_ON(n_ports < 1 || n_ports > 2);
++
++ port[0] = port_info[0];
++ if (n_ports > 1)
++ port[1] = port_info[1];
++ else
++ port[1] = port[0];
++
++ /* FIXME: Really for ATA it isn't safe because the device may be
++ multi-purpose and we want to leave it alone if it was already
++ enabled. Secondly for shared use as Arjan says we want refcounting
++
++ Checking dev->is_enabled is insufficient as this is not set at
++ boot for the primary video which is BIOS enabled
++ */
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
++ u8 tmp8;
++
++ /* TODO: What if one channel is in native mode ... */
++ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
++ mask = (1 << 2) | (1 << 0);
++ if ((tmp8 & mask) != mask)
++ legacy_mode = (1 << 3);
++#if defined(CONFIG_NO_ATA_LEGACY)
++ /* Some platforms with PCI limits cannot address compat
++ port space. In that case we punt if their firmware has
++ left a device in compatibility mode */
++ if (legacy_mode) {
++ printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
++ return -EOPNOTSUPP;
++ }
++#endif
++ }
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ disable_dev_on_err = 0;
++ goto err_out;
++ }
++
++ if (legacy_mode) {
++ if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
++ struct resource *conflict, res;
++ res.start = ATA_PRIMARY_CMD;
++ res.end = ATA_PRIMARY_CMD + 8 - 1;
++ conflict = ____request_resource(&ioport_resource, &res);
++ while (conflict->child)
++ conflict = ____request_resource(conflict, &res);
++ if (!strcmp(conflict->name, "libata"))
++ legacy_mode |= ATA_PORT_PRIMARY;
++ else {
++ disable_dev_on_err = 0;
++ printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
++ "ata: conflict with %s\n",
++ ATA_PRIMARY_CMD,
++ conflict->name);
++ }
++ } else
++ legacy_mode |= ATA_PORT_PRIMARY;
++
++ if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
++ struct resource *conflict, res;
++ res.start = ATA_SECONDARY_CMD;
++ res.end = ATA_SECONDARY_CMD + 8 - 1;
++ conflict = ____request_resource(&ioport_resource, &res);
++ while (conflict->child)
++ conflict = ____request_resource(conflict, &res);
++ if (!strcmp(conflict->name, "libata"))
++ legacy_mode |= ATA_PORT_SECONDARY;
++ else {
++ disable_dev_on_err = 0;
++ printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
++ "ata: conflict with %s\n",
++ ATA_SECONDARY_CMD,
++ conflict->name);
++ }
++ } else
++ legacy_mode |= ATA_PORT_SECONDARY;
++ }
++
++ /* we have legacy mode, but all ports are unavailable */
++ if (legacy_mode == (1 << 3)) {
++ rc = -EBUSY;
++ goto err_out_regions;
++ }
++
++ /* TODO: If we get no DMA mask we should fall back to PIO */
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ if (legacy_mode) {
++ probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
++ } else {
++ if (n_ports == 2)
++ probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
++ else
++ probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
++ }
++ if (!probe_ent) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ pci_set_master(pdev);
++
++ if (!ata_device_add(probe_ent)) {
++ rc = -ENODEV;
++ goto err_out_ent;
++ }
++
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_ent:
++ kfree(probe_ent);
++err_out_regions:
++ if (legacy_mode & ATA_PORT_PRIMARY)
++ release_region(ATA_PRIMARY_CMD, 8);
++ if (legacy_mode & ATA_PORT_SECONDARY)
++ release_region(ATA_SECONDARY_CMD, 8);
++ pci_release_regions(pdev);
++err_out:
++ if (disable_dev_on_err)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++/**
++ * ata_pci_clear_simplex - attempt to kick device out of simplex
++ * @pdev: PCI device
++ *
++ * Some PCI ATA devices report simplex mode but in fact can be told to
++ * enter non simplex mode. This implements the neccessary logic to
++ * perform the task on such devices. Calling it on other devices will
++ * have -undefined- behaviour.
++ */
++
++int ata_pci_clear_simplex(struct pci_dev *pdev)
++{
++ unsigned long bmdma = pci_resource_start(pdev, 4);
++ u8 simplex;
++
++ if (bmdma == 0)
++ return -ENOENT;
++
++ simplex = inb(bmdma + 0x02);
++ outb(simplex & 0x60, bmdma + 0x02);
++ simplex = inb(bmdma + 0x02);
++ if (simplex & 0x80)
++ return -EOPNOTSUPP;
++ return 0;
++}
++
++unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
++{
++ /* Filter out DMA modes if the device has been configured by
++ the BIOS as PIO only */
++
++ if (ap->ioaddr.bmdma_addr == 0)
++ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
++ return xfer_mask;
++}
++
++#endif /* CONFIG_PCI */
++
+diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
+new file mode 100644
+index 0000000..0ed263b
+--- /dev/null
++++ b/drivers/ata/libata.h
+@@ -0,0 +1,123 @@
++/*
++ * libata.h - helper library for ATA
++ *
++ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
++ * Copyright 2003-2004 Jeff Garzik
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ */
++
++#ifndef __LIBATA_H__
++#define __LIBATA_H__
++
++#define DRV_NAME "libata"
++#define DRV_VERSION "2.00" /* must be exactly four chars */
++
++struct ata_scsi_args {
++ struct ata_device *dev;
++ u16 *id;
++ struct scsi_cmnd *cmd;
++ void (*done)(struct scsi_cmnd *);
++};
++
++/* libata-core.c */
++extern struct workqueue_struct *ata_aux_wq;
++extern int atapi_enabled;
++extern int atapi_dmadir;
++extern int libata_fua;
++extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
++extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
++extern void ata_dev_disable(struct ata_device *dev);
++extern void ata_port_flush_task(struct ata_port *ap);
++extern unsigned ata_exec_internal(struct ata_device *dev,
++ struct ata_taskfile *tf, const u8 *cdb,
++ int dma_dir, void *buf, unsigned int buflen);
++extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
++extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
++ int post_reset, u16 *id);
++extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
++extern int ata_dev_configure(struct ata_device *dev, int print_info);
++extern int sata_down_spd_limit(struct ata_port *ap);
++extern int sata_set_spd_needed(struct ata_port *ap);
++extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
++extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
++extern void ata_qc_free(struct ata_queued_cmd *qc);
++extern void ata_qc_issue(struct ata_queued_cmd *qc);
++extern void __ata_qc_complete(struct ata_queued_cmd *qc);
++extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
++extern void ata_dev_select(struct ata_port *ap, unsigned int device,
++ unsigned int wait, unsigned int can_sleep);
++extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
++extern int ata_flush_cache(struct ata_device *dev);
++extern void ata_dev_init(struct ata_device *dev);
++extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
++extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
++extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
++ const struct ata_probe_ent *ent, unsigned int port_no);
++extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
++ const struct ata_port_info *port);
++
++
++/* libata-scsi.c */
++extern struct scsi_transport_template ata_scsi_transport_template;
++
++extern void ata_scsi_scan_host(struct ata_port *ap);
++extern int ata_scsi_offline_dev(struct ata_device *dev);
++extern void ata_scsi_hotplug(void *data);
++extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++
++extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++
++extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
++ unsigned int buflen);
++extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *),
++ u8 asc, u8 ascq);
++extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
++ u8 sk, u8 asc, u8 ascq);
++extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
++ unsigned int (*actor) (struct ata_scsi_args *args,
++ u8 *rbuf, unsigned int buflen));
++extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
++extern void ata_scsi_dev_rescan(void *data);
++extern int ata_bus_probe(struct ata_port *ap);
++
++/* libata-eh.c */
++extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
++extern void ata_scsi_error(struct Scsi_Host *host);
++extern void ata_port_wait_eh(struct ata_port *ap);
++extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
++
++#endif /* __LIBATA_H__ */
+diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
+new file mode 100644
+index 0000000..1d695df
+--- /dev/null
++++ b/drivers/ata/pata_ali.c
+@@ -0,0 +1,680 @@
++/*
++ * pata_ali.c - ALI 15x3 PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based in part upon
++ * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02
++ *
++ * Copyright (C) 1998-2000 Michel Aubry, Maintainer
++ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
++ * Copyright (C) 1999-2000 CJ, cjtsai at ali.com.tw, Maintainer
++ *
++ * Copyright (C) 1998-2000 Andre Hedrick (andre at linux-ide.org)
++ * May be copied or modified under the terms of the GNU General Public License
++ * Copyright (C) 2002 Alan Cox <alan at redhat.com>
++ * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang at ali.com.tw>
++ *
++ * Documentation
++ * Chipset documentation available under NDA only
++ *
++ * TODO/CHECK
++ * Cannot have ATAPI on both master & slave for rev < c2 (???) but
++ * otherwise should do atapi DMA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/dmi.h>
++
++#define DRV_NAME "pata_ali"
++#define DRV_VERSION "0.6.6"
++
++/*
++ * Cable special cases
++ */
++
++static struct dmi_system_id cable_dmi_table[] = {
++ {
++ .ident = "HP Pavilion N5430",
++ .matches = {
++ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
++ DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
++ },
++ },
++ { }
++};
++
++static int ali_cable_override(struct pci_dev *pdev)
++{
++ /* Fujitsu P2000 */
++ if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF)
++ return 1;
++ /* Systems by DMI */
++ if (dmi_check_system(cable_dmi_table))
++ return 1;
++ return 0;
++}
++
++/**
++ * ali_c2_cable_detect - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection for C2 and later revisions
++ */
++
++static int ali_c2_cable_detect(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 ata66;
++
++ /* Certain laptops use short but suitable cables and don't
++ implement the detect logic */
++
++ if (ali_cable_override(pdev))
++ return ATA_CBL_PATA80;
++
++ /* Host view cable detect 0x4A bit 0 primary bit 1 secondary
++ Bit set for 40 pin */
++ pci_read_config_byte(pdev, 0x4A, &ata66);
++ if (ata66 & (1 << ap->port_no))
++ return ATA_CBL_PATA40;
++ else
++ return ATA_CBL_PATA80;
++}
++
++/**
++ * ali_early_error_handler - reset for eary chip
++ * @ap: ATA port
++ *
++ * Handle the reset callback for the later chips with cable detect
++ */
++
++static int ali_c2_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ali_c2_cable_detect(ap);
++ return ata_std_prereset(ap);
++}
++
++static void ali_c2_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, ali_c2_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * ali_early_cable_detect - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection for older chipsets. This turns out to be
++ * rather easy to implement
++ */
++
++static int ali_early_cable_detect(struct ata_port *ap)
++{
++ return ATA_CBL_PATA40;
++}
++
++/**
++ * ali_early_probe_init - reset for early chip
++ * @ap: ATA port
++ *
++ * Handle the reset callback for the early (pre cable detect) chips.
++ */
++
++static int ali_early_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ali_early_cable_detect(ap);
++ return ata_std_prereset(ap);
++}
++
++static void ali_early_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, ali_early_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * ali_20_filter - filter for earlier ALI DMA
++ * @ap: ALi ATA port
++ * @adev: attached device
++ *
++ * Ensure that we do not do DMA on CD devices. We may be able to
++ * fix that later on. Also ensure we do not do UDMA on WDC drives
++ */
++
++static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
++{
++ char model_num[40];
++ /* No DMA on anything but a disk for now */
++ if (adev->class != ATA_DEV_ATA)
++ mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
++ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
++ if (strstr(model_num, "WDC"))
++ return mask &= ~ATA_MASK_UDMA;
++ return ata_pci_default_filter(ap, adev, mask);
++}
++
++/**
++ * ali_fifo_control - FIFO manager
++ * @ap: ALi channel to control
++ * @adev: device for FIFO control
++ * @on: 0 for off 1 for on
++ *
++ * Enable or disable the FIFO on a given device. Because of the way the
++ * ALi FIFO works it provides a boost on ATA disk but can be confused by
++ * ATAPI and we must therefore manage it.
++ */
++
++static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int on)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int pio_fifo = 0x54 + ap->port_no;
++ u8 fifo;
++ int shift = 4 * adev->devno;
++
++ /* ATA - FIFO on set nibble to 0x05, ATAPI - FIFO off, set nibble to
++ 0x00. Not all the docs agree but the behaviour we now use is the
++ one stated in the BIOS Programming Guide */
++
++ pci_read_config_byte(pdev, pio_fifo, &fifo);
++ fifo &= ~(0x0F << shift);
++ if (on)
++ fifo |= (on << shift);
++ pci_write_config_byte(pdev, pio_fifo, fifo);
++}
++
++/**
++ * ali_program_modes - load mode registers
++ * @ap: ALi channel to load
++ * @adev: Device the timing is for
++ * @cmd: Command timing
++ * @data: Data timing
++ * @ultra: UDMA timing or zero for off
++ *
++ * Loads the timing registers for cmd/data and disable UDMA if
++ * ultra is zero. If ultra is set then load and enable the UDMA
++ * timing but do not touch the command/data timing.
++ */
++
++static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, struct ata_timing *t, u8 ultra)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int cas = 0x58 + 4 * ap->port_no; /* Command timing */
++ int cbt = 0x59 + 4 * ap->port_no; /* Command timing */
++ int drwt = 0x5A + 4 * ap->port_no + adev->devno; /* R/W timing */
++ int udmat = 0x56 + ap->port_no; /* UDMA timing */
++ int shift = 4 * adev->devno;
++ u8 udma;
++
++ if (t != NULL) {
++ t->setup = FIT(t->setup, 1, 8) & 7;
++ t->act8b = FIT(t->act8b, 1, 8) & 7;
++ t->rec8b = FIT(t->rec8b, 1, 16) & 15;
++ t->active = FIT(t->active, 1, 8) & 7;
++ t->recover = FIT(t->recover, 1, 16) & 15;
++
++ pci_write_config_byte(pdev, cas, t->setup);
++ pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b);
++ pci_write_config_byte(pdev, drwt, (t->active << 4) | t->recover);
++ }
++
++ /* Set up the UDMA enable */
++ pci_read_config_byte(pdev, udmat, &udma);
++ udma &= ~(0x0F << shift);
++ udma |= ultra << shift;
++ pci_write_config_byte(pdev, udmat, udma);
++}
++
++/**
++ * ali_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the ALi registers for PIO mode. FIXME: add timings for
++ * PIO5.
++ */
++
++static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct ata_device *pair = ata_dev_pair(adev);
++ struct ata_timing t;
++ unsigned long T = 1000000000 / 33333; /* PCI clock based */
++
++ ata_timing_compute(adev, adev->pio_mode, &t, T, 1);
++ if (pair) {
++ struct ata_timing p;
++ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
++ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
++ if (pair->dma_mode) {
++ ata_timing_compute(pair, pair->dma_mode, &p, T, 1);
++ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
++ }
++ }
++
++ /* PIO FIFO is only permitted on ATA disk */
++ if (adev->class != ATA_DEV_ATA)
++ ali_fifo_control(ap, adev, 0x00);
++ ali_program_modes(ap, adev, &t, 0);
++ if (adev->class == ATA_DEV_ATA)
++ ali_fifo_control(ap, adev, 0x05);
++
++}
++
++/**
++ * ali_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * FIXME: MWDMA timings
++ */
++
++static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD };
++ struct ata_device *pair = ata_dev_pair(adev);
++ struct ata_timing t;
++ unsigned long T = 1000000000 / 33333; /* PCI clock based */
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++
++ if (adev->class == ATA_DEV_ATA)
++ ali_fifo_control(ap, adev, 0x08);
++
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ ali_program_modes(ap, adev, NULL, udma_timing[adev->dma_mode - XFER_UDMA_0]);
++ if (adev->dma_mode >= XFER_UDMA_3) {
++ u8 reg4b;
++ pci_read_config_byte(pdev, 0x4B, ®4b);
++ reg4b |= 1;
++ pci_write_config_byte(pdev, 0x4B, reg4b);
++ }
++ } else {
++ ata_timing_compute(adev, adev->dma_mode, &t, T, 1);
++ if (pair) {
++ struct ata_timing p;
++ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
++ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
++ if (pair->dma_mode) {
++ ata_timing_compute(pair, pair->dma_mode, &p, T, 1);
++ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
++ }
++ }
++ ali_program_modes(ap, adev, &t, 0);
++ }
++}
++
++/**
++ * ali_lock_sectors - Keep older devices to 255 sector mode
++ * @ap: ATA port
++ * @adev: Device
++ *
++ * Called during the bus probe for each device that is found. We use
++ * this call to lock the sector count of the device to 255 or less on
++ * older ALi controllers. If we didn't do this then large I/O's would
++ * require LBA48 commands which the older ALi requires are issued by
++ * slower PIO methods
++ */
++
++static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
++{
++ adev->max_sectors = 255;
++}
++
++static struct scsi_host_template ali_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ /* Keep LBA28 counts so large I/O's don't turn LBA48 and PIO
++ with older controllers. Not locked so will grow on C5 or later */
++ .max_sectors = 255,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++/*
++ * Port operations for PIO only ALi
++ */
++
++static struct ata_port_operations ali_early_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = ali_set_piomode,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ali_early_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Port operations for DMA capable ALi without cable
++ * detect
++ */
++static struct ata_port_operations ali_20_port_ops = {
++ .port_disable = ata_port_disable,
++
++ .set_piomode = ali_set_piomode,
++ .set_dmamode = ali_set_dmamode,
++ .mode_filter = ali_20_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .dev_config = ali_lock_sectors,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ali_early_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Port operations for DMA capable ALi with cable detect
++ */
++static struct ata_port_operations ali_c2_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = ali_set_piomode,
++ .set_dmamode = ali_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .dev_config = ali_lock_sectors,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ali_c2_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Port operations for DMA capable ALi with cable detect and LBA48
++ */
++static struct ata_port_operations ali_c5_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = ali_set_piomode,
++ .set_dmamode = ali_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ali_c2_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * ali_init_one - discovery callback
++ * @pdev: PCI device ID
++ * @id: PCI table info
++ *
++ * An ALi IDE interface has been discovered. Figure out what revision
++ * and perform configuration work before handing it to the ATA layer
++ */
++
++static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info_early = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .port_ops = &ali_early_port_ops
++ };
++ /* Revision 0x20 added DMA */
++ static struct ata_port_info info_20 = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &ali_20_port_ops
++ };
++ /* Revision 0x20 with support logic added UDMA */
++ static struct ata_port_info info_20_udma = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x07, /* UDMA33 */
++ .port_ops = &ali_20_port_ops
++ };
++ /* Revision 0xC2 adds UDMA66 */
++ static struct ata_port_info info_c2 = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f,
++ .port_ops = &ali_c2_port_ops
++ };
++ /* Revision 0xC3 is UDMA100 */
++ static struct ata_port_info info_c3 = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &ali_c2_port_ops
++ };
++ /* Revision 0xC4 is UDMA133 */
++ static struct ata_port_info info_c4 = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &ali_c2_port_ops
++ };
++ /* Revision 0xC5 is UDMA133 with LBA48 DMA */
++ static struct ata_port_info info_c5 = {
++ .sht = &ali_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &ali_c5_port_ops
++ };
++
++ static struct ata_port_info *port_info[2];
++ u8 rev, tmp;
++ struct pci_dev *north, *isa_bridge;
++
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
++
++ /*
++ * The chipset revision selects the driver operations and
++ * mode data.
++ */
++
++ if (rev < 0x20) {
++ port_info[0] = port_info[1] = &info_early;
++ } else if (rev < 0xC2) {
++ /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
++ pci_read_config_byte(pdev, 0x4B, &tmp);
++ /* Clear CD-ROM DMA write bit */
++ tmp &= 0x7F;
++ pci_write_config_byte(pdev, 0x4B, tmp);
++ port_info[0] = port_info[1] = &info_20;
++ } else if (rev == 0xC2) {
++ port_info[0] = port_info[1] = &info_c2;
++ } else if (rev == 0xC3) {
++ port_info[0] = port_info[1] = &info_c3;
++ } else if (rev == 0xC4) {
++ port_info[0] = port_info[1] = &info_c4;
++ } else
++ port_info[0] = port_info[1] = &info_c5;
++
++ if (rev >= 0xC2) {
++ /* Enable cable detection logic */
++ pci_read_config_byte(pdev, 0x4B, &tmp);
++ pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
++ }
++
++ north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0));
++ isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
++
++ if (north && north->vendor == PCI_VENDOR_ID_AL) {
++ /* Configure the ALi bridge logic. For non ALi rely on BIOS.
++ Set the south bridge enable bit */
++ pci_read_config_byte(isa_bridge, 0x79, &tmp);
++ if (rev == 0xC2)
++ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
++ else if (rev > 0xC2)
++ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
++ }
++
++ if (rev >= 0x20) {
++ if (rev < 0xC2) {
++ /* Are we paired with a UDMA capable chip */
++ pci_read_config_byte(isa_bridge, 0x5E, &tmp);
++ if ((tmp & 0x1E) == 0x12)
++ port_info[0] = port_info[1] = &info_20_udma;
++ }
++ /*
++ * CD_ROM DMA on (0x53 bit 0). Enable this even if we want
++ * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
++ * via 0x54/55.
++ */
++ pci_read_config_byte(pdev, 0x53, &tmp);
++ if (rev <= 0x20)
++ tmp &= ~0x02;
++ if (rev >= 0xc7)
++ tmp |= 0x03;
++ else
++ tmp |= 0x01; /* CD_ROM enable for DMA */
++ pci_write_config_byte(pdev, 0x53, tmp);
++ }
++
++ pci_dev_put(isa_bridge);
++ pci_dev_put(north);
++
++ ata_pci_clear_simplex(pdev);
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id ali[] = {
++ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
++ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), },
++
++ { },
++};
++
++static struct pci_driver ali_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = ali,
++ .probe = ali_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init ali_init(void)
++{
++ return pci_register_driver(&ali_pci_driver);
++}
++
++
++static void __exit ali_exit(void)
++{
++ pci_unregister_driver(&ali_pci_driver);
++}
++
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for ALi PATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, ali);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ali_init);
++module_exit(ali_exit);
+diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
+new file mode 100644
+index 0000000..5c47a9e
+--- /dev/null
++++ b/drivers/ata/pata_amd.c
+@@ -0,0 +1,711 @@
++/*
++ * pata_amd.c - AMD PATA for new ATA layer
++ * (C) 2005-2006 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based on pata-sil680. Errata information is taken from data sheets
++ * and the amd74xx.c driver by Vojtech Pavlik. Nvidia SATA devices are
++ * claimed by sata-nv.c.
++ *
++ * TODO:
++ * Variable system clock when/if it makes sense
++ * Power management on ports
++ *
++ *
++ * Documentation publically available.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_amd"
++#define DRV_VERSION "0.2.4"
++
++/**
++ * timing_setup - shared timing computation and load
++ * @ap: ATA port being set up
++ * @adev: drive being configured
++ * @offset: port offset
++ * @speed: target speed
++ * @clock: clock multiplier (number of times 33MHz for this part)
++ *
++ * Perform the actual timing set up for Nvidia or AMD PATA devices.
++ * The actual devices vary so they all call into this helper function
++ * providing the clock multipler and offset (because AMD and Nvidia put
++ * the ports at different locations).
++ */
++
++static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offset, int speed, int clock)
++{
++ static const unsigned char amd_cyc2udma[] = {
++ 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct ata_device *peer = ata_dev_pair(adev);
++ int dn = ap->port_no * 2 + adev->devno;
++ struct ata_timing at, apeer;
++ int T, UT;
++ const int amd_clock = 33333; /* KHz. */
++ u8 t;
++
++ T = 1000000000 / amd_clock;
++ UT = T / min_t(int, max_t(int, clock, 1), 2);
++
++ if (ata_timing_compute(adev, speed, &at, T, UT) < 0) {
++ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", speed);
++ return;
++ }
++
++ if (peer) {
++ /* This may be over conservative */
++ if (peer->dma_mode) {
++ ata_timing_compute(peer, peer->dma_mode, &apeer, T, UT);
++ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT);
++ }
++ ata_timing_compute(peer, peer->pio_mode, &apeer, T, UT);
++ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT);
++ }
++
++ if (speed == XFER_UDMA_5 && amd_clock <= 33333) at.udma = 1;
++ if (speed == XFER_UDMA_6 && amd_clock <= 33333) at.udma = 15;
++
++ /*
++ * Now do the setup work
++ */
++
++ /* Configure the address set up timing */
++ pci_read_config_byte(pdev, offset + 0x0C, &t);
++ t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
++ pci_write_config_byte(pdev, offset + 0x0C , t);
++
++ /* Configure the 8bit I/O timing */
++ pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)),
++ ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1));
++
++ /* Drive timing */
++ pci_write_config_byte(pdev, offset + 0x08 + (3 - dn),
++ ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1));
++
++ switch (clock) {
++ case 1:
++ t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03;
++ break;
++
++ case 2:
++ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03;
++ break;
++
++ case 3:
++ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03;
++ break;
++
++ case 4:
++ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03;
++ break;
++
++ default:
++ return;
++ }
++
++ /* UDMA timing */
++ pci_write_config_byte(pdev, offset + 0x10 + (3 - dn), t);
++}
++
++/**
++ * amd_probe_init - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection. The BIOS stores this in PCI config
++ * space for us.
++ */
++
++static int amd_pre_reset(struct ata_port *ap)
++{
++ static const u32 bitmask[2] = {0x03, 0xC0};
++ static const struct pci_bits amd_enable_bits[] = {
++ { 0x40, 1, 0x02, 0x02 },
++ { 0x40, 1, 0x01, 0x01 }
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 ata66;
++
++ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ pci_read_config_byte(pdev, 0x42, &ata66);
++ if (ata66 & bitmask[ap->port_no])
++ ap->cbl = ATA_CBL_PATA80;
++ else
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++
++}
++
++static void amd_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, amd_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++static int amd_early_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static struct pci_bits amd_enable_bits[] = {
++ { 0x40, 1, 0x02, 0x02 },
++ { 0x40, 1, 0x01, 0x01 }
++ };
++
++ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ /* No host side cable detection */
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++
++}
++
++static void amd_early_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, amd_early_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * amd33_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the AMD registers for PIO mode.
++ */
++
++static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->pio_mode, 1);
++}
++
++static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->pio_mode, 2);
++}
++
++static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->pio_mode, 3);
++}
++
++static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->pio_mode, 4);
++}
++
++/**
++ * amd33_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the MWDMA/UDMA modes for the AMD and Nvidia
++ * chipset.
++ */
++
++static void amd33_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->dma_mode, 1);
++}
++
++static void amd66_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->dma_mode, 2);
++}
++
++static void amd100_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->dma_mode, 3);
++}
++
++static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x40, adev->dma_mode, 4);
++}
++
++
++/**
++ * nv_probe_init - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection. The BIOS stores this in PCI config
++ * space for us.
++ */
++
++static int nv_pre_reset(struct ata_port *ap) {
++ static const u8 bitmask[2] = {0x03, 0xC0};
++ static const struct pci_bits nv_enable_bits[] = {
++ { 0x50, 1, 0x02, 0x02 },
++ { 0x50, 1, 0x01, 0x01 }
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 ata66;
++ u16 udma;
++
++ if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ pci_read_config_byte(pdev, 0x52, &ata66);
++ if (ata66 & bitmask[ap->port_no])
++ ap->cbl = ATA_CBL_PATA80;
++ else
++ ap->cbl = ATA_CBL_PATA40;
++
++ /* We now have to double check because the Nvidia boxes BIOS
++ doesn't always set the cable bits but does set mode bits */
++
++ pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
++ if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++static void nv_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, nv_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++/**
++ * nv100_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the AMD registers for PIO mode.
++ */
++
++static void nv100_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x50, adev->pio_mode, 3);
++}
++
++static void nv133_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x50, adev->pio_mode, 4);
++}
++
++/**
++ * nv100_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the MWDMA/UDMA modes for the AMD and Nvidia
++ * chipset.
++ */
++
++static void nv100_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x50, adev->dma_mode, 3);
++}
++
++static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ timing_setup(ap, adev, 0x50, adev->dma_mode, 4);
++}
++
++static struct scsi_host_template amd_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations amd33_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = amd33_set_piomode,
++ .set_dmamode = amd33_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = amd_early_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations amd66_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = amd66_set_piomode,
++ .set_dmamode = amd66_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = amd_early_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations amd100_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = amd100_set_piomode,
++ .set_dmamode = amd100_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = amd_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations amd133_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = amd133_set_piomode,
++ .set_dmamode = amd133_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = amd_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations nv100_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = nv100_set_piomode,
++ .set_dmamode = nv100_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = nv_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations nv133_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = nv133_set_piomode,
++ .set_dmamode = nv133_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = nv_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info[10] = {
++ { /* 0: AMD 7401 */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07, /* No SWDMA */
++ .udma_mask = 0x07, /* UDMA 33 */
++ .port_ops = &amd33_port_ops
++ },
++ { /* 1: Early AMD7409 - no swdma */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f, /* UDMA 66 */
++ .port_ops = &amd66_port_ops
++ },
++ { /* 2: AMD 7409, no swdma errata */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f, /* UDMA 66 */
++ .port_ops = &amd66_port_ops
++ },
++ { /* 3: AMD 7411 */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f, /* UDMA 100 */
++ .port_ops = &amd100_port_ops
++ },
++ { /* 4: AMD 7441 */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f, /* UDMA 100 */
++ .port_ops = &amd100_port_ops
++ },
++ { /* 5: AMD 8111*/
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f, /* UDMA 133, no swdma */
++ .port_ops = &amd133_port_ops
++ },
++ { /* 6: AMD 8111 UDMA 100 (Serenade) */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f, /* UDMA 100, no swdma */
++ .port_ops = &amd133_port_ops
++ },
++ { /* 7: Nvidia Nforce */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f, /* UDMA 100 */
++ .port_ops = &nv100_port_ops
++ },
++ { /* 8: Nvidia Nforce2 and later */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f, /* UDMA 133, no swdma */
++ .port_ops = &nv133_port_ops
++ },
++ { /* 9: AMD CS5536 (Geode companion) */
++ .sht = &amd_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f, /* UDMA 100 */
++ .port_ops = &amd100_port_ops
++ }
++ };
++ static struct ata_port_info *port_info[2];
++ static int printed_version;
++ int type = id->driver_data;
++ u8 rev;
++ u8 fifo;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
++ pci_read_config_byte(pdev, 0x41, &fifo);
++
++ /* Check for AMD7409 without swdma errata and if found adjust type */
++ if (type == 1 && rev > 0x7)
++ type = 2;
++
++ /* Check for AMD7411 */
++ if (type == 3)
++ /* FIFO is broken */
++ pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
++ else
++ pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
++
++ /* Serenade ? */
++ if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
++ pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
++ type = 6; /* UDMA 100 only */
++
++ if (type < 3)
++ ata_pci_clear_simplex(pdev);
++
++ /* And fire it up */
++
++ port_info[0] = port_info[1] = &info[type];
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id amd[] = {
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 3 },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 4 },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 5 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 7 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 8 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 8 },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 },
++
++ { },
++};
++
++static struct pci_driver amd_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = amd,
++ .probe = amd_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init amd_init(void)
++{
++ return pci_register_driver(&amd_pci_driver);
++}
++
++static void __exit amd_exit(void)
++{
++ pci_unregister_driver(&amd_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for AMD PATA IDE");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, amd);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(amd_init);
++module_exit(amd_exit);
+diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
+new file mode 100644
+index 0000000..690828e
+--- /dev/null
++++ b/drivers/ata/pata_artop.c
+@@ -0,0 +1,515 @@
++/*
++ * pata_artop.c - ARTOP ATA controller driver
++ *
++ * (C) 2006 Red Hat <alan at redhat.com>
++ *
++ * Based in part on drivers/ide/pci/aec62xx.c
++ * Copyright (C) 1999-2002 Andre Hedrick <andre at linux-ide.org>
++ * 865/865R fixes for Macintosh card version from a patch to the old
++ * driver by Thibaut VARENE <varenet at parisc-linux.org>
++ * When setting the PCI latency we must set 0x80 or higher for burst
++ * performance Alessandro Zummo <alessandro.zummo at towertech.it>
++ *
++ * TODO
++ * 850 serialization once the core supports it
++ * Investigate no_dsc on 850R
++ * Clock detect
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_artop"
++#define DRV_VERSION "0.4.2"
++
++/*
++ * The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
++ * get PCI bus speed functionality we leave this as 0. Its a variable
++ * for when we get the functionality and also for folks wanting to
++ * test stuff.
++ */
++
++static int clock = 0;
++
++static int artop6210_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ const struct pci_bits artop_enable_bits[] = {
++ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
++ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
++ };
++
++ if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * artop6210_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6210_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, artop6210_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * artop6260_pre_reset - check for 40/80 pin
++ * @ap: Port
++ *
++ * The ARTOP hardware reports the cable detect bits in register 0x49.
++ * Nothing complicated needed here.
++ */
++
++static int artop6260_pre_reset(struct ata_port *ap)
++{
++ static const struct pci_bits artop_enable_bits[] = {
++ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
++ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 tmp;
++
++ /* Odd numbered device ids are the units with enable bits (the -R cards) */
++ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ pci_read_config_byte(pdev, 0x49, &tmp);
++ if (tmp & (1 >> ap->port_no))
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * artop6260_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6260_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, artop6260_pre_reset,
++ ata_std_softreset, NULL,
++ ata_std_postreset);
++}
++
++/**
++ * artop6210_load_piomode - Load a set of PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device
++ * @pio: PIO mode
++ *
++ * Set PIO mode for device, in host controller PCI config space. This
++ * is used both to set PIO timings in PIO mode and also to set the
++ * matching PIO clocking for UDMA, as well as the MWDMA timings.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6210_load_piomode(struct ata_port *ap, struct ata_device *adev, unsigned int pio)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = adev->devno + 2 * ap->port_no;
++ const u16 timing[2][5] = {
++ { 0x0000, 0x000A, 0x0008, 0x0303, 0x0301 },
++ { 0x0700, 0x070A, 0x0708, 0x0403, 0x0401 }
++
++ };
++ /* Load the PIO timing active/recovery bits */
++ pci_write_config_word(pdev, 0x40 + 2 * dn, timing[clock][pio]);
++}
++
++/**
++ * artop6210_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring
++ *
++ * Set PIO mode for device, in host controller PCI config space. For
++ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In
++ * the event UDMA is used the later call to set_dmamode will set the
++ * bits as required.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6210_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = adev->devno + 2 * ap->port_no;
++ u8 ultra;
++
++ artop6210_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
++
++ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */
++ pci_read_config_byte(pdev, 0x54, &ultra);
++ ultra &= ~(3 << (2 * dn));
++ pci_write_config_byte(pdev, 0x54, ultra);
++}
++
++/**
++ * artop6260_load_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring
++ * @pio: PIO mode
++ *
++ * Set PIO mode for device, in host controller PCI config space. The
++ * ARTOP6260 and relatives store the timing data differently.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6260_load_piomode (struct ata_port *ap, struct ata_device *adev, unsigned int pio)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = adev->devno + 2 * ap->port_no;
++ const u8 timing[2][5] = {
++ { 0x00, 0x0A, 0x08, 0x33, 0x31 },
++ { 0x70, 0x7A, 0x78, 0x43, 0x41 }
++
++ };
++ /* Load the PIO timing active/recovery bits */
++ pci_write_config_byte(pdev, 0x40 + dn, timing[clock][pio]);
++}
++
++/**
++ * artop6260_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring
++ *
++ * Set PIO mode for device, in host controller PCI config space. For
++ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In
++ * the event UDMA is used the later call to set_dmamode will set the
++ * bits as required.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 ultra;
++
++ artop6260_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
++
++ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */
++ pci_read_config_byte(pdev, 0x44 + ap->port_no, &ultra);
++ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */
++ pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
++}
++
++/**
++ * artop6210_set_dmamode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set DMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6210_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = adev->devno + 2 * ap->port_no;
++ u8 ultra;
++
++ if (adev->dma_mode == XFER_MW_DMA_0)
++ pio = 1;
++ else
++ pio = 4;
++
++ /* Load the PIO timing active/recovery bits */
++ artop6210_load_piomode(ap, adev, pio);
++
++ pci_read_config_byte(pdev, 0x54, &ultra);
++ ultra &= ~(3 << (2 * dn));
++
++ /* Add ultra DMA bits if in UDMA mode */
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ u8 mode = (adev->dma_mode - XFER_UDMA_0) + 1 - clock;
++ if (mode == 0)
++ mode = 1;
++ ultra |= (mode << (2 * dn));
++ }
++ pci_write_config_byte(pdev, 0x54, ultra);
++}
++
++/**
++ * artop6260_set_dmamode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring
++ *
++ * Set DMA mode for device, in host controller PCI config space. The
++ * ARTOP6260 and relatives store the timing data differently.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void artop6260_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio = adev->pio_mode - XFER_PIO_0;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 ultra;
++
++ if (adev->dma_mode == XFER_MW_DMA_0)
++ pio = 1;
++ else
++ pio = 4;
++
++ /* Load the PIO timing active/recovery bits */
++ artop6260_load_piomode(ap, adev, pio);
++
++ /* Add ultra DMA bits if in UDMA mode */
++ pci_read_config_byte(pdev, 0x44 + ap->port_no, &ultra);
++ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ u8 mode = adev->dma_mode - XFER_UDMA_0 + 1 - clock;
++ if (mode == 0)
++ mode = 1;
++ ultra |= (mode << (4 * adev->devno));
++ }
++ pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
++}
++
++static struct scsi_host_template artop_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations artop6210_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = artop6210_set_piomode,
++ .set_dmamode = artop6210_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = artop6210_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations artop6260_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = artop6260_set_piomode,
++ .set_dmamode = artop6260_set_dmamode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = artop6260_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++
++/**
++ * artop_init_one - Register ARTOP ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in artop_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ static int printed_version;
++ static struct ata_port_info info_6210 = {
++ .sht = &artop_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = ATA_UDMA2,
++ .port_ops = &artop6210_ops,
++ };
++ static struct ata_port_info info_626x = {
++ .sht = &artop_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = ATA_UDMA4,
++ .port_ops = &artop6260_ops,
++ };
++ static struct ata_port_info info_626x_fast = {
++ .sht = &artop_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = ATA_UDMA5,
++ .port_ops = &artop6260_ops,
++ };
++ struct ata_port_info *port_info[2];
++ struct ata_port_info *info = NULL;
++ int ports = 2;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ if (id->driver_data == 0) { /* 6210 variant */
++ info = &info_6210;
++ /* BIOS may have left us in UDMA, clear it before libata probe */
++ pci_write_config_byte(pdev, 0x54, 0);
++ /* For the moment (also lacks dsc) */
++ printk(KERN_WARNING "ARTOP 6210 requires serialize functionality not yet supported by libata.\n");
++ printk(KERN_WARNING "Secondary ATA ports will not be activated.\n");
++ ports = 1;
++ }
++ else if (id->driver_data == 1) /* 6260 */
++ info = &info_626x;
++ else if (id->driver_data == 2) { /* 6260 or 6260 + fast */
++ unsigned long io = pci_resource_start(pdev, 4);
++ u8 reg;
++
++ info = &info_626x;
++ if (inb(io) & 0x10)
++ info = &info_626x_fast;
++ /* Mac systems come up with some registers not set as we
++ will need them */
++
++ /* Clear reset & test bits */
++ pci_read_config_byte(pdev, 0x49, ®);
++ pci_write_config_byte(pdev, 0x49, reg & ~ 0x30);
++
++ /* PCI latency must be > 0x80 for burst mode, tweak it
++ * if required.
++ */
++ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, ®);
++ if (reg <= 0x80)
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90);
++
++ /* Enable IRQ output and burst mode */
++ pci_read_config_byte(pdev, 0x4a, ®);
++ pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
++
++ }
++
++ BUG_ON(info == NULL);
++
++ port_info[0] = port_info[1] = info;
++ return ata_pci_init_one(pdev, port_info, ports);
++}
++
++static const struct pci_device_id artop_pci_tbl[] = {
++ { PCI_VDEVICE(ARTOP, 0x0005), 0 },
++ { PCI_VDEVICE(ARTOP, 0x0006), 1 },
++ { PCI_VDEVICE(ARTOP, 0x0007), 1 },
++ { PCI_VDEVICE(ARTOP, 0x0008), 2 },
++ { PCI_VDEVICE(ARTOP, 0x0009), 2 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver artop_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = artop_pci_tbl,
++ .probe = artop_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init artop_init(void)
++{
++ return pci_register_driver(&artop_pci_driver);
++}
++
++static void __exit artop_exit(void)
++{
++ pci_unregister_driver(&artop_pci_driver);
++}
++
++module_init(artop_init);
++module_exit(artop_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for ARTOP PATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, artop_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
+new file mode 100644
+index 0000000..1ce28d2
+--- /dev/null
++++ b/drivers/ata/pata_atiixp.c
+@@ -0,0 +1,304 @@
++/*
++ * pata_atiixp.c - ATI PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based on
++ *
++ * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004
++ *
++ * Copyright (C) 2003 ATI Inc. <hyu at ati.com>
++ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_atiixp"
++#define DRV_VERSION "0.4.3"
++
++enum {
++ ATIIXP_IDE_PIO_TIMING = 0x40,
++ ATIIXP_IDE_MWDMA_TIMING = 0x44,
++ ATIIXP_IDE_PIO_CONTROL = 0x48,
++ ATIIXP_IDE_PIO_MODE = 0x4a,
++ ATIIXP_IDE_UDMA_CONTROL = 0x54,
++ ATIIXP_IDE_UDMA_MODE = 0x56
++};
++
++static int atiixp_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static struct pci_bits atiixp_enable_bits[] = {
++ { 0x48, 1, 0x01, 0x00 },
++ { 0x48, 1, 0x08, 0x00 }
++ };
++
++ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++static void atiixp_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * atiixp_set_pio_timing - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called by both the pio and dma setup functions to set the controller
++ * timings for PIO transfers. We must load both the mode number and
++ * timing values into the controller.
++ */
++
++static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, int pio)
++{
++ static u8 pio_timings[5] = { 0x5D, 0x47, 0x34, 0x22, 0x20 };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = 2 * ap->port_no + adev->devno;
++
++ /* Check this is correct - the order is odd in both drivers */
++ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
++ u16 pio_mode_data, pio_timing_data;
++
++ pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
++ pio_mode_data &= ~(0x7 << (4 * dn));
++ pio_mode_data |= pio << (4 * dn);
++ pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
++
++ pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
++ pio_mode_data &= ~(0xFF << timing_shift);
++ pio_mode_data |= (pio_timings[pio] << timing_shift);
++ pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
++}
++
++/**
++ * atiixp_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup. We use a shared helper for this
++ * as the DMA setup must also adjust the PIO timing information.
++ */
++
++static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
++}
++
++/**
++ * atiixp_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the DMA mode setup. We use timing tables for most
++ * modes but must tune an appropriate PIO mode to match.
++ */
++
++static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static u8 mwdma_timings[5] = { 0x77, 0x21, 0x20 };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dma = adev->dma_mode;
++ int dn = 2 * ap->port_no + adev->devno;
++ int wanted_pio;
++
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ u16 udma_mode_data;
++
++ dma -= XFER_UDMA_0;
++
++ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_MODE, &udma_mode_data);
++ udma_mode_data &= ~(0x7 << (4 * dn));
++ udma_mode_data |= dma << (4 * dn);
++ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data);
++ } else {
++ u16 mwdma_timing_data;
++ /* Check this is correct - the order is odd in both drivers */
++ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
++
++ dma -= XFER_MW_DMA_0;
++
++ pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data);
++ mwdma_timing_data &= ~(0xFF << timing_shift);
++ mwdma_timing_data |= (mwdma_timings[dma] << timing_shift);
++ pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data);
++ }
++ /*
++ * We must now look at the PIO mode situation. We may need to
++ * adjust the PIO mode to keep the timings acceptable
++ */
++ if (adev->dma_mode >= XFER_MW_DMA_2)
++ wanted_pio = 4;
++ else if (adev->dma_mode == XFER_MW_DMA_1)
++ wanted_pio = 3;
++ else if (adev->dma_mode == XFER_MW_DMA_0)
++ wanted_pio = 0;
++ else BUG();
++
++ if (adev->pio_mode != wanted_pio)
++ atiixp_set_pio_timing(ap, adev, wanted_pio);
++}
++
++/**
++ * atiixp_bmdma_start - DMA start callback
++ * @qc: Command in progress
++ *
++ * When DMA begins we need to ensure that the UDMA control
++ * register for the channel is correctly set.
++ */
++
++static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = (2 * ap->port_no) + adev->devno;
++ u16 tmp16;
++
++ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
++ if (adev->dma_mode >= XFER_UDMA_0)
++ tmp16 |= (1 << dn);
++ else
++ tmp16 &= ~(1 << dn);
++ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
++ ata_bmdma_start(qc);
++}
++
++/**
++ * atiixp_dma_stop - DMA stop callback
++ * @qc: Command in progress
++ *
++ * DMA has completed. Clear the UDMA flag as the next operations will
++ * be PIO ones not UDMA data transfer.
++ */
++
++static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int dn = (2 * ap->port_no) + qc->dev->devno;
++ u16 tmp16;
++
++ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
++ tmp16 &= ~(1 << dn);
++ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
++ ata_bmdma_stop(qc);
++}
++
++static struct scsi_host_template atiixp_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations atiixp_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = atiixp_set_piomode,
++ .set_dmamode = atiixp_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = atiixp_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = atiixp_bmdma_start,
++ .bmdma_stop = atiixp_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &atiixp_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x06, /* No MWDMA0 support */
++ .udma_mask = 0x3F,
++ .port_ops = &atiixp_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id atiixp[] = {
++ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
++ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
++ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
++ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
++
++ { },
++};
++
++static struct pci_driver atiixp_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = atiixp,
++ .probe = atiixp_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init atiixp_init(void)
++{
++ return pci_register_driver(&atiixp_pci_driver);
++}
++
++
++static void __exit atiixp_exit(void)
++{
++ pci_unregister_driver(&atiixp_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, atiixp);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(atiixp_init);
++module_exit(atiixp_exit);
+diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
+new file mode 100644
+index 0000000..b9bbd1d
+--- /dev/null
++++ b/drivers/ata/pata_cmd64x.c
+@@ -0,0 +1,504 @@
++/*
++ * pata_cmd64x.c - ATI PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based upon
++ * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
++ *
++ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
++ * Note, this driver is not used at all on other systems because
++ * there the "BIOS" has done all of the following already.
++ * Due to massive hardware bugs, UltraDMA is only supported
++ * on the 646U2 and not on the 646U.
++ *
++ * Copyright (C) 1998 Eddie C. Dost (ecd at skynet.be)
++ * Copyright (C) 1998 David S. Miller (davem at redhat.com)
++ *
++ * Copyright (C) 1999-2002 Andre Hedrick <andre at linux-ide.org>
++ *
++ * TODO
++ * Testing work
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_cmd64x"
++#define DRV_VERSION "0.2.1"
++
++/*
++ * CMD64x specific registers definition.
++ */
++
++enum {
++ CFR = 0x50,
++ CFR_INTR_CH0 = 0x02,
++ CNTRL = 0x51,
++ CNTRL_DIS_RA0 = 0x40,
++ CNTRL_DIS_RA1 = 0x80,
++ CNTRL_ENA_2ND = 0x08,
++ CMDTIM = 0x52,
++ ARTTIM0 = 0x53,
++ DRWTIM0 = 0x54,
++ ARTTIM1 = 0x55,
++ DRWTIM1 = 0x56,
++ ARTTIM23 = 0x57,
++ ARTTIM23_DIS_RA2 = 0x04,
++ ARTTIM23_DIS_RA3 = 0x08,
++ ARTTIM23_INTR_CH1 = 0x10,
++ ARTTIM2 = 0x57,
++ ARTTIM3 = 0x57,
++ DRWTIM23 = 0x58,
++ DRWTIM2 = 0x58,
++ BRST = 0x59,
++ DRWTIM3 = 0x5b,
++ BMIDECR0 = 0x70,
++ MRDMODE = 0x71,
++ MRDMODE_INTR_CH0 = 0x04,
++ MRDMODE_INTR_CH1 = 0x08,
++ MRDMODE_BLK_CH0 = 0x10,
++ MRDMODE_BLK_CH1 = 0x20,
++ BMIDESR0 = 0x72,
++ UDIDETCR0 = 0x73,
++ DTPR0 = 0x74,
++ BMIDECR1 = 0x78,
++ BMIDECSR = 0x79,
++ BMIDESR1 = 0x7A,
++ UDIDETCR1 = 0x7B,
++ DTPR1 = 0x7C
++};
++
++static int cmd64x_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++static int cmd648_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 r;
++
++ /* Check cable detect bits */
++ pci_read_config_byte(pdev, BMIDECSR, &r);
++ if (r & (1 << ap->port_no))
++ ap->cbl = ATA_CBL_PATA80;
++ else
++ ap->cbl = ATA_CBL_PATA40;
++
++ return ata_std_prereset(ap);
++}
++
++static void cmd64x_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++static void cmd648_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * cmd64x_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup.
++ */
++
++static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct ata_timing t;
++ const unsigned long T = 1000000 / 33;
++ const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 };
++
++ u8 reg;
++
++ /* Port layout is not logical so use a table */
++ const u8 arttim_port[2][2] = {
++ { ARTTIM0, ARTTIM1 },
++ { ARTTIM23, ARTTIM23 }
++ };
++ const u8 drwtim_port[2][2] = {
++ { DRWTIM0, DRWTIM1 },
++ { DRWTIM2, DRWTIM3 }
++ };
++
++ int arttim = arttim_port[ap->port_no][adev->devno];
++ int drwtim = drwtim_port[ap->port_no][adev->devno];
++
++
++ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
++ printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
++ return;
++ }
++ if (ap->port_no) {
++ /* Slave has shared address setup */
++ struct ata_device *pair = ata_dev_pair(adev);
++
++ if (pair) {
++ struct ata_timing tp;
++ ata_timing_compute(pair, pair->pio_mode, &tp, T, 0);
++ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
++ }
++ }
++
++ printk(KERN_DEBUG DRV_NAME ": active %d recovery %d setup %d.\n",
++ t.active, t.recover, t.setup);
++ if (t.recover > 16) {
++ t.active += t.recover - 16;
++ t.recover = 16;
++ }
++ if (t.active > 16)
++ t.active = 16;
++
++ /* Now convert the clocks into values we can actually stuff into
++ the chip */
++
++ if (t.recover > 1)
++ t.recover--;
++ else
++ t.recover = 15;
++
++ if (t.setup > 4)
++ t.setup = 0xC0;
++ else
++ t.setup = setup_data[t.setup];
++
++ t.active &= 0x0F; /* 0 = 16 */
++
++ /* Load setup timing */
++ pci_read_config_byte(pdev, arttim, ®);
++ reg &= 0x3F;
++ reg |= t.setup;
++ pci_write_config_byte(pdev, arttim, reg);
++
++ /* Load active/recovery */
++ pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover);
++}
++
++/**
++ * cmd64x_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the DMA mode setup.
++ */
++
++static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u8 udma_data[] = {
++ 0x31, 0x21, 0x11, 0x25, 0x15, 0x05
++ };
++ static const u8 mwdma_data[] = {
++ 0x30, 0x20, 0x10
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 regU, regD;
++
++ int pciU = UDIDETCR0 + 8 * ap->port_no;
++ int pciD = BMIDESR0 + 8 * ap->port_no;
++ int shift = 2 * adev->devno;
++
++ pci_read_config_byte(pdev, pciD, ®D);
++ pci_read_config_byte(pdev, pciU, ®U);
++
++ regD &= ~(0x20 << shift);
++ regU &= ~(0x35 << shift);
++
++ if (adev->dma_mode >= XFER_UDMA_0)
++ regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
++ else
++ regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
++
++ regD |= 0x20 << adev->devno;
++
++ pci_write_config_byte(pdev, pciU, regU);
++ pci_write_config_byte(pdev, pciD, regD);
++}
++
++/**
++ * cmd648_dma_stop - DMA stop callback
++ * @qc: Command in progress
++ *
++ * DMA has completed.
++ */
++
++static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 dma_intr;
++ int dma_reg = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
++ int dma_mask = ap->port_no ? ARTTIM2 : CFR;
++
++ ata_bmdma_stop(qc);
++
++ pci_read_config_byte(pdev, dma_reg, &dma_intr);
++ pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask);
++}
++
++/**
++ * cmd646r1_dma_stop - DMA stop callback
++ * @qc: Command in progress
++ *
++ * Stub for now while investigating the r1 quirk in the old driver.
++ */
++
++static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ ata_bmdma_stop(qc);
++}
++
++static struct scsi_host_template cmd64x_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations cmd64x_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cmd64x_set_piomode,
++ .set_dmamode = cmd64x_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cmd64x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations cmd646r1_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cmd64x_set_piomode,
++ .set_dmamode = cmd64x_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cmd64x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = cmd646r1_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations cmd648_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cmd64x_set_piomode,
++ .set_dmamode = cmd64x_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cmd648_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = cmd648_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ u32 class_rev;
++
++ static struct ata_port_info cmd_info[6] = {
++ { /* CMD 643 - no UDMA */
++ .sht = &cmd64x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &cmd64x_port_ops
++ },
++ { /* CMD 646 with broken UDMA */
++ .sht = &cmd64x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &cmd64x_port_ops
++ },
++ { /* CMD 646 with working UDMA */
++ .sht = &cmd64x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA1,
++ .port_ops = &cmd64x_port_ops
++ },
++ { /* CMD 646 rev 1 */
++ .sht = &cmd64x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &cmd646r1_port_ops
++ },
++ { /* CMD 648 */
++ .sht = &cmd64x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA2,
++ .port_ops = &cmd648_port_ops
++ },
++ { /* CMD 649 */
++ .sht = &cmd64x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA3,
++ .port_ops = &cmd648_port_ops
++ }
++ };
++ static struct ata_port_info *port_info[2], *info;
++ u8 mrdmode;
++
++ info = &cmd_info[id->driver_data];
++
++ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
++ class_rev &= 0xFF;
++
++ if (id->driver_data == 0) /* 643 */
++ ata_pci_clear_simplex(pdev);
++
++ if (pdev->device == PCI_DEVICE_ID_CMD_646) {
++ /* Does UDMA work ? */
++ if (class_rev > 4)
++ info = &cmd_info[2];
++ /* Early rev with other problems ? */
++ else if (class_rev == 1)
++ info = &cmd_info[3];
++ }
++
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
++ pci_read_config_byte(pdev, MRDMODE, &mrdmode);
++ mrdmode &= ~ 0x30; /* IRQ set up */
++ mrdmode |= 0x02; /* Memory read line enable */
++ pci_write_config_byte(pdev, MRDMODE, mrdmode);
++
++ /* Force PIO 0 here.. */
++
++ /* PPC specific fixup copied from old driver */
++#ifdef CONFIG_PPC
++ pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
++#endif
++
++ port_info[0] = port_info[1] = info;
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id cmd64x[] = {
++ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
++ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
++ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
++ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
++
++ { },
++};
++
++static struct pci_driver cmd64x_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = cmd64x,
++ .probe = cmd64x_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init cmd64x_init(void)
++{
++ return pci_register_driver(&cmd64x_pci_driver);
++}
++
++static void __exit cmd64x_exit(void)
++{
++ pci_unregister_driver(&cmd64x_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, cmd64x);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(cmd64x_init);
++module_exit(cmd64x_exit);
+diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
+new file mode 100644
+index 0000000..2cd3c0f
+--- /dev/null
++++ b/drivers/ata/pata_cs5520.c
+@@ -0,0 +1,334 @@
++/*
++ * IDE tuning and bus mastering support for the CS5510/CS5520
++ * chipsets
++ *
++ * The CS5510/CS5520 are slightly unusual devices. Unlike the
++ * typical IDE controllers they do bus mastering with the drive in
++ * PIO mode and smarter silicon.
++ *
++ * The practical upshot of this is that we must always tune the
++ * drive for the right PIO mode. We must also ignore all the blacklists
++ * and the drive bus mastering DMA information. Also to confuse matters
++ * further we can do DMA on PIO only drives.
++ *
++ * DMA on the 5510 also requires we disable_hlt() during DMA on early
++ * revisions.
++ *
++ * *** This driver is strictly experimental ***
++ *
++ * (c) Copyright Red Hat Inc 2002
++ *
++ * 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.
++ *
++ * Documentation:
++ * Not publically available.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_cs5520"
++#define DRV_VERSION "0.6.2"
++
++struct pio_clocks
++{
++ int address;
++ int assert;
++ int recovery;
++};
++
++static const struct pio_clocks cs5520_pio_clocks[]={
++ {3, 6, 11},
++ {2, 5, 6},
++ {1, 4, 3},
++ {1, 3, 2},
++ {1, 2, 1}
++};
++
++/**
++ * cs5520_set_timings - program PIO timings
++ * @ap: ATA port
++ * @adev: ATA device
++ *
++ * Program the PIO mode timings for the controller according to the pio
++ * clocking table.
++ */
++
++static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int pio)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int slave = adev->devno;
++
++ pio -= XFER_PIO_0;
++
++ /* Channel command timing */
++ pci_write_config_byte(pdev, 0x62 + ap->port_no,
++ (cs5520_pio_clocks[pio].recovery << 4) |
++ (cs5520_pio_clocks[pio].assert));
++ /* FIXME: should these use address ? */
++ /* Read command timing */
++ pci_write_config_byte(pdev, 0x64 + 4*ap->port_no + slave,
++ (cs5520_pio_clocks[pio].recovery << 4) |
++ (cs5520_pio_clocks[pio].assert));
++ /* Write command timing */
++ pci_write_config_byte(pdev, 0x66 + 4*ap->port_no + slave,
++ (cs5520_pio_clocks[pio].recovery << 4) |
++ (cs5520_pio_clocks[pio].assert));
++}
++
++/**
++ * cs5520_enable_dma - turn on DMA bits
++ *
++ * Turn on the DMA bits for this disk. Needed because the BIOS probably
++ * has not done the work for us. Belongs in the core SATA code.
++ */
++
++static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
++{
++ /* Set the DMA enable/disable flag */
++ u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02);
++ reg |= 1<<(adev->devno + 5);
++ outb(reg, ap->ioaddr.bmdma_addr + 0x02);
++}
++
++/**
++ * cs5520_set_dmamode - program DMA timings
++ * @ap: ATA port
++ * @adev: ATA device
++ *
++ * Program the DMA mode timings for the controller according to the pio
++ * clocking table. Note that this device sets the DMA timings to PIO
++ * mode values. This may seem bizarre but the 5520 architecture talks
++ * PIO mode to the disk and DMA mode to the controller so the underlying
++ * transfers are PIO timed.
++ */
++
++static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 };
++ cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]);
++ cs5520_enable_dma(ap, adev);
++}
++
++/**
++ * cs5520_set_piomode - program PIO timings
++ * @ap: ATA port
++ * @adev: ATA device
++ *
++ * Program the PIO mode timings for the controller according to the pio
++ * clocking table. We know pio_mode will equal dma_mode because of the
++ * CS5520 architecture. At least once we turned DMA on and wrote a
++ * mode setter.
++ */
++
++static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ cs5520_set_timings(ap, adev, adev->pio_mode);
++}
++
++
++static int cs5520_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++static void cs5520_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++static struct scsi_host_template cs5520_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations cs5520_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cs5520_set_piomode,
++ .set_dmamode = cs5520_set_dmamode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cs5520_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ u8 pcicfg;
++ static struct ata_probe_ent probe[2];
++ int ports = 0;
++
++ /* IDE port enable bits */
++ pci_read_config_byte(dev, 0x60, &pcicfg);
++
++ /* Check if the ATA ports are enabled */
++ if ((pcicfg & 3) == 0)
++ return -ENODEV;
++
++ if ((pcicfg & 0x40) == 0) {
++ printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
++ pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
++ }
++
++ /* Perform set up for DMA */
++ if (pci_enable_device_bars(dev, 1<<2)) {
++ printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
++ return -ENODEV;
++ }
++ pci_set_master(dev);
++ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
++ printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
++ return -ENODEV;
++ }
++ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
++ printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
++ return -ENODEV;
++ }
++
++ /* We have to do our own plumbing as the PCI setup for this
++ chipset is non-standard so we can't punt to the libata code */
++
++ INIT_LIST_HEAD(&probe[0].node);
++ probe[0].dev = pci_dev_to_dev(dev);
++ probe[0].port_ops = &cs5520_port_ops;
++ probe[0].sht = &cs5520_sht;
++ probe[0].pio_mask = 0x1F;
++ probe[0].mwdma_mask = id->driver_data;
++ probe[0].irq = 14;
++ probe[0].irq_flags = 0;
++ probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
++ probe[0].n_ports = 1;
++ probe[0].port[0].cmd_addr = 0x1F0;
++ probe[0].port[0].ctl_addr = 0x3F6;
++ probe[0].port[0].altstatus_addr = 0x3F6;
++ probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2);
++
++ /* The secondary lurks at different addresses but is otherwise
++ the same beastie */
++
++ probe[1] = probe[0];
++ INIT_LIST_HEAD(&probe[1].node);
++ probe[1].irq = 15;
++ probe[1].port[0].cmd_addr = 0x170;
++ probe[1].port[0].ctl_addr = 0x376;
++ probe[1].port[0].altstatus_addr = 0x376;
++ probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8;
++
++ /* Let libata fill in the port details */
++ ata_std_ports(&probe[0].port[0]);
++ ata_std_ports(&probe[1].port[0]);
++
++ /* Now add the ports that are active */
++ if (pcicfg & 1)
++ ports += ata_device_add(&probe[0]);
++ if (pcicfg & 2)
++ ports += ata_device_add(&probe[1]);
++ if (ports)
++ return 0;
++ return -ENODEV;
++}
++
++/**
++ * cs5520_remove_one - device unload
++ * @pdev: PCI device being removed
++ *
++ * Handle an unplug/unload event for a PCI device. Unload the
++ * PCI driver but do not use the default handler as we manage
++ * resources ourself and *MUST NOT* disable the device as it has
++ * other functions.
++ */
++
++static void __devexit cs5520_remove_one(struct pci_dev *pdev)
++{
++ struct device *dev = pci_dev_to_dev(pdev);
++ struct ata_host *host = dev_get_drvdata(dev);
++
++ ata_host_remove(host);
++ dev_set_drvdata(dev, NULL);
++}
++
++/* For now keep DMA off. We can set it for all but A rev CS5510 once the
++ core ATA code can handle it */
++
++static const struct pci_device_id pata_cs5520[] = {
++ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
++ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
++
++ { },
++};
++
++static struct pci_driver cs5520_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = pata_cs5520,
++ .probe = cs5520_init_one,
++ .remove = cs5520_remove_one
++};
++
++static int __init cs5520_init(void)
++{
++ return pci_register_driver(&cs5520_pci_driver);
++}
++
++static void __exit cs5520_exit(void)
++{
++ pci_unregister_driver(&cs5520_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, pata_cs5520);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(cs5520_init);
++module_exit(cs5520_exit);
++
+diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
+new file mode 100644
+index 0000000..a07cc81
+--- /dev/null
++++ b/drivers/ata/pata_cs5530.c
+@@ -0,0 +1,386 @@
++/*
++ * pata-cs5530.c - CS5530 PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based upon cs5530.c by Mark Lord.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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
++ *
++ * Loosely based on the piix & svwks drivers.
++ *
++ * Documentation:
++ * Available from AMD web site.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/dmi.h>
++
++#define DRV_NAME "pata_cs5530"
++#define DRV_VERSION "0.6"
++
++/**
++ * cs5530_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Set our PIO requirements. This is fairly simple on the CS5530
++ * chips.
++ */
++
++static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const unsigned int cs5530_pio_timings[2][5] = {
++ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
++ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
++ };
++ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
++ u32 tuning;
++ int format;
++
++ /* Find out which table to use */
++ tuning = inl(base + 0x04);
++ format = (tuning & 0x80000000UL) ? 1 : 0;
++
++ /* Now load the right timing register */
++ if (adev->devno)
++ base += 0x08;
++
++ outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
++}
++
++/**
++ * cs5530_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * We cannot mix MWDMA and UDMA without reloading timings each switch
++ * master to slave. We track the last DMA setup in order to minimise
++ * reloads.
++ */
++
++static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
++ u32 tuning, timing = 0;
++ u8 reg;
++
++ /* Find out which table to use */
++ tuning = inl(base + 0x04);
++
++ switch(adev->dma_mode) {
++ case XFER_UDMA_0:
++ timing = 0x00921250;break;
++ case XFER_UDMA_1:
++ timing = 0x00911140;break;
++ case XFER_UDMA_2:
++ timing = 0x00911030;break;
++ case XFER_MW_DMA_0:
++ timing = 0x00077771;break;
++ case XFER_MW_DMA_1:
++ timing = 0x00012121;break;
++ case XFER_MW_DMA_2:
++ timing = 0x00002020;break;
++ default:
++ BUG();
++ }
++ /* Merge in the PIO format bit */
++ timing |= (tuning & 0x80000000UL);
++ if (adev->devno == 0) /* Master */
++ outl(timing, base + 0x04);
++ else {
++ if (timing & 0x00100000)
++ tuning |= 0x00100000; /* UDMA for both */
++ else
++ tuning &= ~0x00100000; /* MWDMA for both */
++ outl(tuning, base + 0x04);
++ outl(timing, base + 0x0C);
++ }
++
++ /* Set the DMA capable bit in the BMDMA area */
++ reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
++ reg |= (1 << (5 + adev->devno));
++ outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
++
++ /* Remember the last DMA setup we did */
++
++ ap->private_data = adev;
++}
++
++/**
++ * cs5530_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings if
++ * neccessary. Specifically we have a problem that there is only
++ * one MWDMA/UDMA bit.
++ */
++
++static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct ata_device *prev = ap->private_data;
++
++ /* See if the DMA settings could be wrong */
++ if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
++ /* Maybe, but do the channels match MWDMA/UDMA ? */
++ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
++ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
++ /* Switch the mode bits */
++ cs5530_set_dmamode(ap, adev);
++ }
++
++ return ata_qc_issue_prot(qc);
++}
++
++static int cs5530_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++static void cs5530_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++
++static struct scsi_host_template cs5530_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations cs5530_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cs5530_set_piomode,
++ .set_dmamode = cs5530_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cs5530_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = cs5530_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct dmi_system_id palmax_dmi_table[] = {
++ {
++ .ident = "Palmax PD1100",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Cyrix"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "Caddis"),
++ },
++ },
++ { }
++};
++
++static int cs5530_is_palmax(void)
++{
++ if (dmi_check_system(palmax_dmi_table)) {
++ printk(KERN_INFO "Palmax PD1100: Disabling DMA on docking port.\n");
++ return 1;
++ }
++ return 0;
++}
++
++/**
++ * cs5530_init_one - Initialise a CS5530
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Install a driver for the newly found CS5530 companion chip. Most of
++ * this is just housekeeping. We have to set the chip up correctly and
++ * turn off various bits of emulation magic.
++ */
++
++static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ int compiler_warning_pointless_fix;
++ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
++ static struct ata_port_info info = {
++ .sht = &cs5530_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x07,
++ .port_ops = &cs5530_port_ops
++ };
++ /* The docking connector doesn't do UDMA, and it seems not MWDMA */
++ static struct ata_port_info info_palmax_secondary = {
++ .sht = &cs5530_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .port_ops = &cs5530_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ dev = NULL;
++ while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
++ switch (dev->device) {
++ case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
++ master_0 = pci_dev_get(dev);
++ break;
++ case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
++ cs5530_0 = pci_dev_get(dev);
++ break;
++ }
++ }
++ if (!master_0) {
++ printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n");
++ goto fail_put;
++ }
++ if (!cs5530_0) {
++ printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
++ goto fail_put;
++ }
++
++ pci_set_master(cs5530_0);
++ compiler_warning_pointless_fix = pci_set_mwi(cs5530_0);
++
++ /*
++ * Set PCI CacheLineSize to 16-bytes:
++ * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
++ *
++ * Note: This value is constant because the 5530 is only a Geode companion
++ */
++
++ pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
++
++ /*
++ * Disable trapping of UDMA register accesses (Win98 hack):
++ * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
++ */
++
++ pci_write_config_word(cs5530_0, 0xd0, 0x5006);
++
++ /*
++ * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
++ * The other settings are what is necessary to get the register
++ * into a sane state for IDE DMA operation.
++ */
++
++ pci_write_config_byte(master_0, 0x40, 0x1e);
++
++ /*
++ * Set max PCI burst size (16-bytes seems to work best):
++ * 16bytes: set bit-1 at 0x41 (reg value of 0x16)
++ * all others: clear bit-1 at 0x41, and do:
++ * 128bytes: OR 0x00 at 0x41
++ * 256bytes: OR 0x04 at 0x41
++ * 512bytes: OR 0x08 at 0x41
++ * 1024bytes: OR 0x0c at 0x41
++ */
++
++ pci_write_config_byte(master_0, 0x41, 0x14);
++
++ /*
++ * These settings are necessary to get the chip
++ * into a sane state for IDE DMA operation.
++ */
++
++ pci_write_config_byte(master_0, 0x42, 0x00);
++ pci_write_config_byte(master_0, 0x43, 0xc1);
++
++ pci_dev_put(master_0);
++ pci_dev_put(cs5530_0);
++
++ if (cs5530_is_palmax())
++ port_info[1] = &info_palmax_secondary;
++
++ /* Now kick off ATA set up */
++ return ata_pci_init_one(dev, port_info, 2);
++
++fail_put:
++ if (master_0)
++ pci_dev_put(master_0);
++ if (cs5530_0)
++ pci_dev_put(cs5530_0);
++ return -ENODEV;
++}
++
++static const struct pci_device_id cs5530[] = {
++ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
++
++ { },
++};
++
++static struct pci_driver cs5530_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = cs5530,
++ .probe = cs5530_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init cs5530_init(void)
++{
++ return pci_register_driver(&cs5530_pci_driver);
++}
++
++static void __exit cs5530_exit(void)
++{
++ pci_unregister_driver(&cs5530_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, cs5530);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(cs5530_init);
++module_exit(cs5530_exit);
+diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
+new file mode 100644
+index 0000000..f8def3f
+--- /dev/null
++++ b/drivers/ata/pata_cs5535.c
+@@ -0,0 +1,290 @@
++/*
++ * pata-cs5535.c - CS5535 PATA for new ATA layer
++ * (C) 2005-2006 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based upon cs5535.c from AMD <Jens.Altmann at amd.com> as cleaned up and
++ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger at gmx.de
++ * and Alexander Kiausch <alex.kiausch at t-online.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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
++ *
++ * Loosely based on the piix & svwks drivers.
++ *
++ * Documentation:
++ * Available from AMD web site.
++ * TODO
++ * Review errata to see if serializing is neccessary
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <asm/msr.h>
++
++#define DRV_NAME "cs5535"
++#define DRV_VERSION "0.2.10"
++
++/*
++ * The Geode (Aka Athlon GX now) uses an internal MSR based
++ * bus system for control. Demented but there you go.
++ */
++
++#define MSR_ATAC_BASE 0x51300000
++#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0)
++#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01)
++#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02)
++#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03)
++#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04)
++#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05)
++#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08)
++#define ATAC_RESET (MSR_ATAC_BASE+0x10)
++#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20)
++#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21)
++#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22)
++#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23)
++#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24)
++
++#define ATAC_BM0_CMD_PRIM 0x00
++#define ATAC_BM0_STS_PRIM 0x02
++#define ATAC_BM0_PRD 0x04
++
++#define CS5535_CABLE_DETECT 0x48
++
++#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
++
++/**
++ * cs5535_pre_reset - detect cable type
++ * @ap: Port to detect on
++ *
++ * Perform cable detection for ATA66 capable cable. Return a libata
++ * cable type.
++ */
++
++static int cs5535_pre_reset(struct ata_port *ap)
++{
++ u8 cable;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable);
++ if (cable & 1)
++ ap->cbl = ATA_CBL_PATA80;
++ else
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * cs5535_error_handler - reset/probe
++ * @ap: Port to reset
++ *
++ * Reset and configure a port
++ */
++
++static void cs5535_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, cs5535_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * cs5535_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Set our PIO requirements. The CS5535 is pretty clean about all this
++ */
++
++static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u16 pio_timings[5] = {
++ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
++ };
++ static const u16 pio_cmd_timings[5] = {
++ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
++ };
++ u32 reg, dummy;
++ struct ata_device *pair = ata_dev_pair(adev);
++
++ int mode = adev->pio_mode - XFER_PIO_0;
++ int cmdmode = mode;
++
++ /* Command timing has to be for the lowest of the pair of devices */
++ if (pair) {
++ int pairmode = pair->pio_mode - XFER_PIO_0;
++ cmdmode = min(mode, pairmode);
++ /* Write the other drive timing register if it changed */
++ if (cmdmode < pairmode)
++ wrmsr(ATAC_CH0D0_PIO + 2 * pair->devno,
++ pio_cmd_timings[cmdmode] << 16 | pio_timings[pairmode], 0);
++ }
++ /* Write the drive timing register */
++ wrmsr(ATAC_CH0D0_PIO + 2 * adev->devno,
++ pio_cmd_timings[cmdmode] << 16 | pio_timings[mode], 0);
++
++ /* Set the PIO "format 1" bit in the DMA timing register */
++ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
++ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg | 0x80000000UL, 0);
++}
++
++/**
++ * cs5535_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ */
++
++static void cs5535_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u32 udma_timings[5] = {
++ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061
++ };
++ static const u32 mwdma_timings[3] = {
++ 0x7F0FFFF3, 0x7F035352, 0x7F024241
++ };
++ u32 reg, dummy;
++ int mode = adev->dma_mode;
++
++ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
++ reg &= 0x80000000UL;
++ if (mode >= XFER_UDMA_0)
++ reg |= udma_timings[mode - XFER_UDMA_0];
++ else
++ reg |= mwdma_timings[mode - XFER_MW_DMA_0];
++ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, 0);
++}
++
++static struct scsi_host_template cs5535_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations cs5535_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cs5535_set_piomode,
++ .set_dmamode = cs5535_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cs5535_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * cs5535_init_one - Initialise a CS5530
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Install a driver for the newly found CS5530 companion chip. Most of
++ * this is just housekeeping. We have to set the chip up correctly and
++ * turn off various bits of emulation magic.
++ */
++
++static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &cs5535_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f,
++ .port_ops = &cs5535_port_ops
++ };
++ struct ata_port_info *ports[1] = { &info };
++
++ u32 timings, dummy;
++
++ /* Check the BIOS set the initial timing clock. If not set the
++ timings for PIO0 */
++ rdmsr(ATAC_CH0D0_PIO, timings, dummy);
++ if (CS5535_BAD_PIO(timings))
++ wrmsr(ATAC_CH0D0_PIO, 0xF7F4F7F4UL, 0);
++ rdmsr(ATAC_CH0D1_PIO, timings, dummy);
++ if (CS5535_BAD_PIO(timings))
++ wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
++ return ata_pci_init_one(dev, ports, 1);
++}
++
++static const struct pci_device_id cs5535[] = {
++ { PCI_VDEVICE(NS, 0x002D), },
++
++ { },
++};
++
++static struct pci_driver cs5535_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = cs5535,
++ .probe = cs5535_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init cs5535_init(void)
++{
++ return pci_register_driver(&cs5535_pci_driver);
++}
++
++static void __exit cs5535_exit(void)
++{
++ pci_unregister_driver(&cs5535_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
++MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, cs5535);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(cs5535_init);
++module_exit(cs5535_exit);
+diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
+new file mode 100644
+index 0000000..247b436
+--- /dev/null
++++ b/drivers/ata/pata_cypress.c
+@@ -0,0 +1,228 @@
++/*
++ * pata_cypress.c - Cypress PATA for new ATA layer
++ * (C) 2006 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based heavily on
++ * linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_cypress"
++#define DRV_VERSION "0.1.2"
++
++/* here are the offset definitions for the registers */
++
++enum {
++ CY82_IDE_CMDREG = 0x04,
++ CY82_IDE_ADDRSETUP = 0x48,
++ CY82_IDE_MASTER_IOR = 0x4C,
++ CY82_IDE_MASTER_IOW = 0x4D,
++ CY82_IDE_SLAVE_IOR = 0x4E,
++ CY82_IDE_SLAVE_IOW = 0x4F,
++ CY82_IDE_MASTER_8BIT = 0x50,
++ CY82_IDE_SLAVE_8BIT = 0x51,
++
++ CY82_INDEX_PORT = 0x22,
++ CY82_DATA_PORT = 0x23,
++
++ CY82_INDEX_CTRLREG1 = 0x01,
++ CY82_INDEX_CHANNEL0 = 0x30,
++ CY82_INDEX_CHANNEL1 = 0x31,
++ CY82_INDEX_TIMEOUT = 0x32
++};
++
++static int cy82c693_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++static void cy82c693_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * cy82c693_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup.
++ */
++
++static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct ata_timing t;
++ const unsigned long T = 1000000 / 33;
++ short time_16, time_8;
++ u32 addr;
++
++ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 1) < 0) {
++ printk(KERN_ERR DRV_NAME ": mome computation failed.\n");
++ return;
++ }
++
++ time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4);
++ time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4);
++
++ if (adev->devno == 0) {
++ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
++
++ addr &= ~0x0F; /* Mask bits */
++ addr |= FIT(t.setup, 0, 15);
++
++ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
++ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
++ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOW, time_16);
++ pci_write_config_byte(pdev, CY82_IDE_MASTER_8BIT, time_8);
++ } else {
++ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
++
++ addr &= ~0xF0; /* Mask bits */
++ addr |= (FIT(t.setup, 0, 15) << 4);
++
++ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
++ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
++ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOW, time_16);
++ pci_write_config_byte(pdev, CY82_IDE_SLAVE_8BIT, time_8);
++ }
++}
++
++/**
++ * cy82c693_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the DMA mode setup.
++ */
++
++static void cy82c693_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ int reg = CY82_INDEX_CHANNEL0 + ap->port_no;
++
++ /* Be afraid, be very afraid. Magic registers in low I/O space */
++ outb(reg, 0x22);
++ outb(adev->dma_mode - XFER_MW_DMA_0, 0x23);
++
++ /* 0x50 gives the best behaviour on the Alpha's using this chip */
++ outb(CY82_INDEX_TIMEOUT, 0x22);
++ outb(0x50, 0x23);
++}
++
++static struct scsi_host_template cy82c693_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations cy82c693_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = cy82c693_set_piomode,
++ .set_dmamode = cy82c693_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = cy82c693_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &cy82c693_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &cy82c693_port_ops
++ };
++ static struct ata_port_info *port_info[1] = { &info };
++
++ /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2.
++ For the moment we don't handle the secondary. FIXME */
++
++ if (PCI_FUNC(pdev->devfn) != 1)
++ return -ENODEV;
++
++ return ata_pci_init_one(pdev, port_info, 1);
++}
++
++static const struct pci_device_id cy82c693[] = {
++ { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), },
++
++ { },
++};
++
++static struct pci_driver cy82c693_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = cy82c693,
++ .probe = cy82c693_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init cy82c693_init(void)
++{
++ return pci_register_driver(&cy82c693_pci_driver);
++}
++
++
++static void __exit cy82c693_exit(void)
++{
++ pci_unregister_driver(&cy82c693_pci_driver);
++}
++
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the CY82C693 PATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, cy82c693);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(cy82c693_init);
++module_exit(cy82c693_exit);
+diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
+new file mode 100644
+index 0000000..ef18c60
+--- /dev/null
++++ b/drivers/ata/pata_efar.c
+@@ -0,0 +1,338 @@
++/*
++ * pata_efar.c - EFAR PIIX clone controller driver
++ *
++ * (C) 2005 Red Hat <alan at redhat.com>
++ *
++ * Some parts based on ata_piix.c by Jeff Garzik and others.
++ *
++ * The EFAR is a PIIX4 clone with UDMA66 support. Unlike the later
++ * Intel ICH controllers the EFAR widened the UDMA mode register bits
++ * and doesn't require the funky clock selection.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_efar"
++#define DRV_VERSION "0.4.2"
++
++/**
++ * efar_pre_reset - check for 40/80 pin
++ * @ap: Port
++ *
++ * Perform cable detection for the EFAR ATA interface. This is
++ * different to the PIIX arrangement
++ */
++
++static int efar_pre_reset(struct ata_port *ap)
++{
++ static const struct pci_bits efar_enable_bits[] = {
++ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
++ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 tmp;
++
++ if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ pci_read_config_byte(pdev, 0x47, &tmp);
++ if (tmp & (2 >> ap->port_no))
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * efar_probe_reset - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void efar_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, efar_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * efar_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set PIO mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio = adev->pio_mode - XFER_PIO_0;
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
++ u16 idetm_data;
++ int control = 0;
++
++ /*
++ * See Intel Document 298600-004 for the timing programing rules
++ * for PIIX/ICH. The EFAR is a clone so very similar
++ */
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ if (pio > 2)
++ control |= 1; /* TIME1 enable */
++ if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
++ control |= 2; /* IE enable */
++ /* Intel specifies that the PPE functionality is for disk only */
++ if (adev->class == ATA_DEV_ATA)
++ control |= 4; /* PPE enable */
++
++ pci_read_config_word(dev, idetm_port, &idetm_data);
++
++ /* Enable PPE, IE and TIME as appropriate */
++
++ if (adev->devno == 0) {
++ idetm_data &= 0xCCF0;
++ idetm_data |= control;
++ idetm_data |= (timings[pio][0] << 12) |
++ (timings[pio][1] << 8);
++ } else {
++ int shift = 4 * ap->port_no;
++ u8 slave_data;
++
++ idetm_data &= 0xCC0F;
++ idetm_data |= (control << 4);
++
++ /* Slave timing in seperate register */
++ pci_read_config_byte(dev, 0x44, &slave_data);
++ slave_data &= 0x0F << shift;
++ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
++ pci_write_config_byte(dev, 0x44, slave_data);
++ }
++
++ idetm_data |= 0x4000; /* Ensure SITRE is enabled */
++ pci_write_config_word(dev, idetm_port, idetm_data);
++}
++
++/**
++ * efar_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ *
++ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ u8 master_port = ap->port_no ? 0x42 : 0x40;
++ u16 master_data;
++ u8 speed = adev->dma_mode;
++ int devid = adev->devno + 2 * ap->port_no;
++ u8 udma_enable;
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ pci_read_config_word(dev, master_port, &master_data);
++ pci_read_config_byte(dev, 0x48, &udma_enable);
++
++ if (speed >= XFER_UDMA_0) {
++ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
++ u16 udma_timing;
++
++ udma_enable |= (1 << devid);
++
++ /* Load the UDMA mode number */
++ pci_read_config_word(dev, 0x4A, &udma_timing);
++ udma_timing &= ~(7 << (4 * devid));
++ udma_timing |= udma << (4 * devid);
++ pci_write_config_word(dev, 0x4A, udma_timing);
++ } else {
++ /*
++ * MWDMA is driven by the PIO timings. We must also enable
++ * IORDY unconditionally along with TIME1. PPE has already
++ * been set when the PIO timing was set.
++ */
++ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
++ unsigned int control;
++ u8 slave_data;
++ const unsigned int needed_pio[3] = {
++ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
++ };
++ int pio = needed_pio[mwdma] - XFER_PIO_0;
++
++ control = 3; /* IORDY|TIME1 */
++
++ /* If the drive MWDMA is faster than it can do PIO then
++ we must force PIO into PIO0 */
++
++ if (adev->pio_mode < needed_pio[mwdma])
++ /* Enable DMA timing only */
++ control |= 8; /* PIO cycles in PIO0 */
++
++ if (adev->devno) { /* Slave */
++ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
++ master_data |= control << 4;
++ pci_read_config_byte(dev, 0x44, &slave_data);
++ slave_data &= (0x0F + 0xE1 * ap->port_no);
++ /* Load the matching timing */
++ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
++ pci_write_config_byte(dev, 0x44, slave_data);
++ } else { /* Master */
++ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
++ and master timing bits */
++ master_data |= control;
++ master_data |=
++ (timings[pio][0] << 12) |
++ (timings[pio][1] << 8);
++ }
++ udma_enable &= ~(1 << devid);
++ pci_write_config_word(dev, master_port, master_data);
++ }
++ pci_write_config_byte(dev, 0x48, udma_enable);
++}
++
++static struct scsi_host_template efar_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations efar_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = efar_set_piomode,
++ .set_dmamode = efar_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = efar_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++
++/**
++ * efar_init_one - Register EFAR ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in efar_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ static struct ata_port_info info = {
++ .sht = &efar_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma1-2 */
++ .udma_mask = 0x0f, /* UDMA 66 */
++ .port_ops = &efar_ops,
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id efar_pci_tbl[] = {
++ { PCI_VDEVICE(EFAR, 0x9130), },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver efar_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = efar_pci_tbl,
++ .probe = efar_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init efar_init(void)
++{
++ return pci_register_driver(&efar_pci_driver);
++}
++
++static void __exit efar_exit(void)
++{
++ pci_unregister_driver(&efar_pci_driver);
++}
++
++module_init(efar_init);
++module_exit(efar_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for EFAR PIIX clones");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, efar_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
+new file mode 100644
+index 0000000..6d3e4c0
+--- /dev/null
++++ b/drivers/ata/pata_hpt366.c
+@@ -0,0 +1,479 @@
++/*
++ * Libata driver for the highpoint 366 and 368 UDMA66 ATA controllers.
++ *
++ * This driver is heavily based upon:
++ *
++ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
++ *
++ * Copyright (C) 1999-2003 Andre Hedrick <andre at linux-ide.org>
++ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
++ * Portions Copyright (C) 2003 Red Hat Inc
++ *
++ *
++ * TODO
++ * Maybe PLL mode
++ * Look into engine reset on timeout errors. Should not be
++ * required.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_hpt366"
++#define DRV_VERSION "0.5"
++
++struct hpt_clock {
++ u8 xfer_speed;
++ u32 timing;
++};
++
++/* key for bus clock timings
++ * bit
++ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
++ * DMA. cycles = value + 1
++ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
++ * DMA. cycles = value + 1
++ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
++ * register access.
++ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
++ * register access.
++ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
++ * during task file register access.
++ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
++ * xfer.
++ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
++ * register access.
++ * 28 UDMA enable
++ * 29 DMA enable
++ * 30 PIO_MST enable. if set, the chip is in bus master mode during
++ * PIO.
++ * 31 FIFO enable.
++ */
++
++static const struct hpt_clock hpt366_40[] = {
++ { XFER_UDMA_4, 0x900fd943 },
++ { XFER_UDMA_3, 0x900ad943 },
++ { XFER_UDMA_2, 0x900bd943 },
++ { XFER_UDMA_1, 0x9008d943 },
++ { XFER_UDMA_0, 0x9008d943 },
++
++ { XFER_MW_DMA_2, 0xa008d943 },
++ { XFER_MW_DMA_1, 0xa010d955 },
++ { XFER_MW_DMA_0, 0xa010d9fc },
++
++ { XFER_PIO_4, 0xc008d963 },
++ { XFER_PIO_3, 0xc010d974 },
++ { XFER_PIO_2, 0xc010d997 },
++ { XFER_PIO_1, 0xc010d9c7 },
++ { XFER_PIO_0, 0xc018d9d9 },
++ { 0, 0x0120d9d9 }
++};
++
++static const struct hpt_clock hpt366_33[] = {
++ { XFER_UDMA_4, 0x90c9a731 },
++ { XFER_UDMA_3, 0x90cfa731 },
++ { XFER_UDMA_2, 0x90caa731 },
++ { XFER_UDMA_1, 0x90cba731 },
++ { XFER_UDMA_0, 0x90c8a731 },
++
++ { XFER_MW_DMA_2, 0xa0c8a731 },
++ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
++ { XFER_MW_DMA_0, 0xa0c8a797 },
++
++ { XFER_PIO_4, 0xc0c8a731 },
++ { XFER_PIO_3, 0xc0c8a742 },
++ { XFER_PIO_2, 0xc0d0a753 },
++ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
++ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
++ { 0, 0x0120a7a7 }
++};
++
++static const struct hpt_clock hpt366_25[] = {
++ { XFER_UDMA_4, 0x90c98521 },
++ { XFER_UDMA_3, 0x90cf8521 },
++ { XFER_UDMA_2, 0x90cf8521 },
++ { XFER_UDMA_1, 0x90cb8521 },
++ { XFER_UDMA_0, 0x90cb8521 },
++
++ { XFER_MW_DMA_2, 0xa0ca8521 },
++ { XFER_MW_DMA_1, 0xa0ca8532 },
++ { XFER_MW_DMA_0, 0xa0ca8575 },
++
++ { XFER_PIO_4, 0xc0ca8521 },
++ { XFER_PIO_3, 0xc0ca8532 },
++ { XFER_PIO_2, 0xc0ca8542 },
++ { XFER_PIO_1, 0xc0d08572 },
++ { XFER_PIO_0, 0xc0d08585 },
++ { 0, 0x01208585 }
++};
++
++static const char *bad_ata33[] = {
++ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
++ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
++ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
++ "Maxtor 90510D4",
++ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
++ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
++ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
++ NULL
++};
++
++static const char *bad_ata66_4[] = {
++ "IBM-DTLA-307075",
++ "IBM-DTLA-307060",
++ "IBM-DTLA-307045",
++ "IBM-DTLA-307030",
++ "IBM-DTLA-307020",
++ "IBM-DTLA-307015",
++ "IBM-DTLA-305040",
++ "IBM-DTLA-305030",
++ "IBM-DTLA-305020",
++ "IC35L010AVER07-0",
++ "IC35L020AVER07-0",
++ "IC35L030AVER07-0",
++ "IC35L040AVER07-0",
++ "IC35L060AVER07-0",
++ "WDC AC310200R",
++ NULL
++};
++
++static const char *bad_ata66_3[] = {
++ "WDC AC310200R",
++ NULL
++};
++
++static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
++{
++ unsigned char model_num[40];
++ char *s;
++ unsigned int len;
++ int i = 0;
++
++ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
++ s = &model_num[0];
++ len = strnlen(s, sizeof(model_num));
++
++ /* ATAPI specifies that empty space is blank-filled; remove blanks */
++ while ((len > 0) && (s[len - 1] == ' ')) {
++ len--;
++ s[len] = 0;
++ }
++
++ while(list[i] != NULL) {
++ if (!strncmp(list[i], s, len)) {
++ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
++ modestr, list[i]);
++ return 1;
++ }
++ i++;
++ }
++ return 0;
++}
++
++/**
++ * hpt366_filter - mode selection filter
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Block UDMA on devices that cause trouble with this controller.
++ */
++
++static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
++{
++ if (adev->class == ATA_DEV_ATA) {
++ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
++ mask &= ~ATA_MASK_UDMA;
++ if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3))
++ mask &= ~(0x07 << ATA_SHIFT_UDMA);
++ if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
++ mask &= ~(0x0F << ATA_SHIFT_UDMA);
++ }
++ return ata_pci_default_filter(ap, adev, mask);
++}
++
++/**
++ * hpt36x_find_mode - reset the hpt36x bus
++ * @ap: ATA port
++ * @speed: transfer mode
++ *
++ * Return the 32bit register programming information for this channel
++ * that matches the speed provided.
++ */
++
++static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
++{
++ struct hpt_clock *clocks = ap->host->private_data;
++
++ while(clocks->xfer_speed) {
++ if (clocks->xfer_speed == speed)
++ return clocks->timing;
++ clocks++;
++ }
++ BUG();
++ return 0xffffffffU; /* silence compiler warning */
++}
++
++static int hpt36x_pre_reset(struct ata_port *ap)
++{
++ u8 ata66;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ pci_read_config_byte(pdev, 0x5A, &ata66);
++ if (ata66 & (1 << ap->port_no))
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * hpt36x_error_handler - reset the hpt36x bus
++ * @ap: ATA port to reset
++ *
++ * Perform the reset handling for the 366/368
++ */
++
++static void hpt36x_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, hpt36x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * hpt366_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Perform PIO mode setup.
++ */
++
++static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ if (fast & 0x80) {
++ fast &= ~0x80;
++ pci_write_config_byte(pdev, addr2, fast);
++ }
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt36x_find_mode(ap, adev->pio_mode);
++ mode &= ~0x8000000; /* No FIFO in PIO */
++ mode &= ~0x30070000; /* Leave config bits alone */
++ reg &= 0x30070000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt366_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * Set up the channel for MWDMA or UDMA modes. Much the same as with
++ * PIO, load the mode number and then set MWDMA or UDMA flag.
++ */
++
++static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ if (fast & 0x80) {
++ fast &= ~0x80;
++ pci_write_config_byte(pdev, addr2, fast);
++ }
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt36x_find_mode(ap, adev->dma_mode);
++ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
++ mode &= ~0xC0000000; /* Leave config bits alone */
++ reg &= 0xC0000000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++static struct scsi_host_template hpt36x_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++/*
++ * Configuration for HPT366/68
++ */
++
++static struct ata_port_operations hpt366_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt366_set_piomode,
++ .set_dmamode = hpt366_set_dmamode,
++ .mode_filter = hpt366_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt36x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * hpt36x_init_one - Initialise an HPT366/368
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Initialise an HPT36x device. There are some interesting complications
++ * here. Firstly the chip may report 366 and be one of several variants.
++ * Secondly all the timings depend on the clock for the chip which we must
++ * detect and look up
++ *
++ * This is the known chip mappings. It may be missing a couple of later
++ * releases.
++ *
++ * Chip version PCI Rev Notes
++ * HPT366 4 (HPT366) 0 UDMA66
++ * HPT366 4 (HPT366) 1 UDMA66
++ * HPT368 4 (HPT366) 2 UDMA66
++ * HPT37x/30x 4 (HPT366) 3+ Other driver
++ *
++ */
++
++static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info_hpt366 = {
++ .sht = &hpt36x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f,
++ .port_ops = &hpt366_port_ops
++ };
++ struct ata_port_info *port_info[2] = {&info_hpt366, &info_hpt366};
++
++ u32 class_rev;
++ u32 reg1;
++ u8 drive_fast;
++
++ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
++ class_rev &= 0xFF;
++
++ /* May be a later chip in disguise. Check */
++ /* Newer chips are not in the HPT36x driver. Ignore them */
++ if (class_rev > 2)
++ return -ENODEV;
++
++ 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, 0x51, &drive_fast);
++ if (drive_fast & 0x80)
++ pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
++
++ pci_read_config_dword(dev, 0x40, ®1);
++
++ /* PCI clocking determines the ATA timing values to use */
++ /* info_hpt366 is safe against re-entry so we can scribble on it */
++ switch((reg1 & 0x700) >> 8) {
++ case 5:
++ info_hpt366.private_data = &hpt366_40;
++ break;
++ case 9:
++ info_hpt366.private_data = &hpt366_25;
++ break;
++ default:
++ info_hpt366.private_data = &hpt366_33;
++ break;
++ }
++ /* Now kick off ATA set up */
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id hpt36x[] = {
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
++
++ { },
++};
++
++static struct pci_driver hpt36x_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = hpt36x,
++ .probe = hpt36x_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init hpt36x_init(void)
++{
++ return pci_register_driver(&hpt36x_pci_driver);
++}
++
++
++static void __exit hpt36x_exit(void)
++{
++ pci_unregister_driver(&hpt36x_pci_driver);
++}
++
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, hpt36x);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(hpt36x_init);
++module_exit(hpt36x_exit);
+diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
+new file mode 100644
+index 0000000..7350443
+--- /dev/null
++++ b/drivers/ata/pata_hpt37x.c
+@@ -0,0 +1,1256 @@
++/*
++ * Libata driver for the highpoint 37x and 30x UDMA66 ATA controllers.
++ *
++ * This driver is heavily based upon:
++ *
++ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
++ *
++ * Copyright (C) 1999-2003 Andre Hedrick <andre at linux-ide.org>
++ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
++ * Portions Copyright (C) 2003 Red Hat Inc
++ *
++ * TODO
++ * PLL mode
++ * Look into engine reset on timeout errors. Should not be
++ * required.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_hpt37x"
++#define DRV_VERSION "0.5"
++
++struct hpt_clock {
++ u8 xfer_speed;
++ u32 timing;
++};
++
++struct hpt_chip {
++ const char *name;
++ unsigned int base;
++ struct hpt_clock const *clocks[4];
++};
++
++/* key for bus clock timings
++ * bit
++ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
++ * DMA. cycles = value + 1
++ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
++ * DMA. cycles = value + 1
++ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
++ * register access.
++ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
++ * register access.
++ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
++ * during task file register access.
++ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
++ * xfer.
++ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
++ * register access.
++ * 28 UDMA enable
++ * 29 DMA enable
++ * 30 PIO_MST enable. if set, the chip is in bus master mode during
++ * PIO.
++ * 31 FIFO enable.
++ */
++
++/* from highpoint documentation. these are old values */
++static const struct hpt_clock hpt370_timings_33[] = {
++/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
++ { XFER_UDMA_5, 0x16454e31 },
++ { XFER_UDMA_4, 0x16454e31 },
++ { XFER_UDMA_3, 0x166d4e31 },
++ { XFER_UDMA_2, 0x16494e31 },
++ { XFER_UDMA_1, 0x164d4e31 },
++ { XFER_UDMA_0, 0x16514e31 },
++
++ { XFER_MW_DMA_2, 0x26514e21 },
++ { XFER_MW_DMA_1, 0x26514e33 },
++ { XFER_MW_DMA_0, 0x26514e97 },
++
++ { XFER_PIO_4, 0x06514e21 },
++ { XFER_PIO_3, 0x06514e22 },
++ { XFER_PIO_2, 0x06514e33 },
++ { XFER_PIO_1, 0x06914e43 },
++ { XFER_PIO_0, 0x06914e57 },
++ { 0, 0x06514e57 }
++};
++
++static const struct hpt_clock hpt370_timings_66[] = {
++ { XFER_UDMA_5, 0x14846231 },
++ { XFER_UDMA_4, 0x14886231 },
++ { XFER_UDMA_3, 0x148c6231 },
++ { XFER_UDMA_2, 0x148c6231 },
++ { XFER_UDMA_1, 0x14906231 },
++ { XFER_UDMA_0, 0x14986231 },
++
++ { XFER_MW_DMA_2, 0x26514e21 },
++ { XFER_MW_DMA_1, 0x26514e33 },
++ { XFER_MW_DMA_0, 0x26514e97 },
++
++ { XFER_PIO_4, 0x06514e21 },
++ { XFER_PIO_3, 0x06514e22 },
++ { XFER_PIO_2, 0x06514e33 },
++ { XFER_PIO_1, 0x06914e43 },
++ { XFER_PIO_0, 0x06914e57 },
++ { 0, 0x06514e57 }
++};
++
++/* these are the current (4 sep 2001) timings from highpoint */
++static const struct hpt_clock hpt370a_timings_33[] = {
++ { XFER_UDMA_5, 0x12446231 },
++ { XFER_UDMA_4, 0x12446231 },
++ { XFER_UDMA_3, 0x126c6231 },
++ { XFER_UDMA_2, 0x12486231 },
++ { XFER_UDMA_1, 0x124c6233 },
++ { XFER_UDMA_0, 0x12506297 },
++
++ { XFER_MW_DMA_2, 0x22406c31 },
++ { XFER_MW_DMA_1, 0x22406c33 },
++ { XFER_MW_DMA_0, 0x22406c97 },
++
++ { XFER_PIO_4, 0x06414e31 },
++ { XFER_PIO_3, 0x06414e42 },
++ { XFER_PIO_2, 0x06414e53 },
++ { XFER_PIO_1, 0x06814e93 },
++ { XFER_PIO_0, 0x06814ea7 },
++ { 0, 0x06814ea7 }
++};
++
++/* 2x 33MHz timings */
++static const struct hpt_clock hpt370a_timings_66[] = {
++ { XFER_UDMA_5, 0x1488e673 },
++ { XFER_UDMA_4, 0x1488e673 },
++ { XFER_UDMA_3, 0x1498e673 },
++ { XFER_UDMA_2, 0x1490e673 },
++ { XFER_UDMA_1, 0x1498e677 },
++ { XFER_UDMA_0, 0x14a0e73f },
++
++ { XFER_MW_DMA_2, 0x2480fa73 },
++ { XFER_MW_DMA_1, 0x2480fa77 },
++ { XFER_MW_DMA_0, 0x2480fb3f },
++
++ { XFER_PIO_4, 0x0c82be73 },
++ { XFER_PIO_3, 0x0c82be95 },
++ { XFER_PIO_2, 0x0c82beb7 },
++ { XFER_PIO_1, 0x0d02bf37 },
++ { XFER_PIO_0, 0x0d02bf5f },
++ { 0, 0x0d02bf5f }
++};
++
++static const struct hpt_clock hpt370a_timings_50[] = {
++ { XFER_UDMA_5, 0x12848242 },
++ { XFER_UDMA_4, 0x12ac8242 },
++ { XFER_UDMA_3, 0x128c8242 },
++ { XFER_UDMA_2, 0x120c8242 },
++ { XFER_UDMA_1, 0x12148254 },
++ { XFER_UDMA_0, 0x121882ea },
++
++ { XFER_MW_DMA_2, 0x22808242 },
++ { XFER_MW_DMA_1, 0x22808254 },
++ { XFER_MW_DMA_0, 0x228082ea },
++
++ { XFER_PIO_4, 0x0a81f442 },
++ { XFER_PIO_3, 0x0a81f443 },
++ { XFER_PIO_2, 0x0a81f454 },
++ { XFER_PIO_1, 0x0ac1f465 },
++ { XFER_PIO_0, 0x0ac1f48a },
++ { 0, 0x0ac1f48a }
++};
++
++static const struct hpt_clock hpt372_timings_33[] = {
++ { XFER_UDMA_6, 0x1c81dc62 },
++ { XFER_UDMA_5, 0x1c6ddc62 },
++ { XFER_UDMA_4, 0x1c8ddc62 },
++ { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
++ { XFER_UDMA_2, 0x1c91dc62 },
++ { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
++ { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
++
++ { XFER_MW_DMA_2, 0x2c829262 },
++ { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
++ { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
++
++ { XFER_PIO_4, 0x0c829c62 },
++ { XFER_PIO_3, 0x0c829c84 },
++ { XFER_PIO_2, 0x0c829ca6 },
++ { XFER_PIO_1, 0x0d029d26 },
++ { XFER_PIO_0, 0x0d029d5e },
++ { 0, 0x0d029d5e }
++};
++
++static const struct hpt_clock hpt372_timings_50[] = {
++ { XFER_UDMA_5, 0x12848242 },
++ { XFER_UDMA_4, 0x12ac8242 },
++ { XFER_UDMA_3, 0x128c8242 },
++ { XFER_UDMA_2, 0x120c8242 },
++ { XFER_UDMA_1, 0x12148254 },
++ { XFER_UDMA_0, 0x121882ea },
++
++ { XFER_MW_DMA_2, 0x22808242 },
++ { XFER_MW_DMA_1, 0x22808254 },
++ { XFER_MW_DMA_0, 0x228082ea },
++
++ { XFER_PIO_4, 0x0a81f442 },
++ { XFER_PIO_3, 0x0a81f443 },
++ { XFER_PIO_2, 0x0a81f454 },
++ { XFER_PIO_1, 0x0ac1f465 },
++ { XFER_PIO_0, 0x0ac1f48a },
++ { 0, 0x0a81f443 }
++};
++
++static const struct hpt_clock hpt372_timings_66[] = {
++ { XFER_UDMA_6, 0x1c869c62 },
++ { XFER_UDMA_5, 0x1cae9c62 },
++ { XFER_UDMA_4, 0x1c8a9c62 },
++ { XFER_UDMA_3, 0x1c8e9c62 },
++ { XFER_UDMA_2, 0x1c929c62 },
++ { XFER_UDMA_1, 0x1c9a9c62 },
++ { XFER_UDMA_0, 0x1c829c62 },
++
++ { XFER_MW_DMA_2, 0x2c829c62 },
++ { XFER_MW_DMA_1, 0x2c829c66 },
++ { XFER_MW_DMA_0, 0x2c829d2e },
++
++ { XFER_PIO_4, 0x0c829c62 },
++ { XFER_PIO_3, 0x0c829c84 },
++ { XFER_PIO_2, 0x0c829ca6 },
++ { XFER_PIO_1, 0x0d029d26 },
++ { XFER_PIO_0, 0x0d029d5e },
++ { 0, 0x0d029d26 }
++};
++
++static const struct hpt_clock hpt374_timings_33[] = {
++ { XFER_UDMA_6, 0x12808242 },
++ { XFER_UDMA_5, 0x12848242 },
++ { XFER_UDMA_4, 0x12ac8242 },
++ { XFER_UDMA_3, 0x128c8242 },
++ { XFER_UDMA_2, 0x120c8242 },
++ { XFER_UDMA_1, 0x12148254 },
++ { XFER_UDMA_0, 0x121882ea },
++
++ { XFER_MW_DMA_2, 0x22808242 },
++ { XFER_MW_DMA_1, 0x22808254 },
++ { XFER_MW_DMA_0, 0x228082ea },
++
++ { XFER_PIO_4, 0x0a81f442 },
++ { XFER_PIO_3, 0x0a81f443 },
++ { XFER_PIO_2, 0x0a81f454 },
++ { XFER_PIO_1, 0x0ac1f465 },
++ { XFER_PIO_0, 0x0ac1f48a },
++ { 0, 0x06814e93 }
++};
++
++static const struct hpt_chip hpt370 = {
++ "HPT370",
++ 48,
++ {
++ hpt370_timings_33,
++ NULL,
++ NULL,
++ hpt370_timings_66
++ }
++};
++
++static const struct hpt_chip hpt370a = {
++ "HPT370A",
++ 48,
++ {
++ hpt370a_timings_33,
++ NULL,
++ hpt370a_timings_50,
++ hpt370a_timings_66
++ }
++};
++
++static const struct hpt_chip hpt372 = {
++ "HPT372",
++ 55,
++ {
++ hpt372_timings_33,
++ NULL,
++ hpt372_timings_50,
++ hpt372_timings_66
++ }
++};
++
++static const struct hpt_chip hpt302 = {
++ "HPT302",
++ 66,
++ {
++ hpt372_timings_33,
++ NULL,
++ hpt372_timings_50,
++ hpt372_timings_66
++ }
++};
++
++static const struct hpt_chip hpt371 = {
++ "HPT371",
++ 66,
++ {
++ hpt372_timings_33,
++ NULL,
++ hpt372_timings_50,
++ hpt372_timings_66
++ }
++};
++
++static const struct hpt_chip hpt372a = {
++ "HPT372A",
++ 66,
++ {
++ hpt372_timings_33,
++ NULL,
++ hpt372_timings_50,
++ hpt372_timings_66
++ }
++};
++
++static const struct hpt_chip hpt374 = {
++ "HPT374",
++ 48,
++ {
++ hpt374_timings_33,
++ NULL,
++ NULL,
++ NULL
++ }
++};
++
++/**
++ * hpt37x_find_mode - reset the hpt37x bus
++ * @ap: ATA port
++ * @speed: transfer mode
++ *
++ * Return the 32bit register programming information for this channel
++ * that matches the speed provided.
++ */
++
++static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
++{
++ struct hpt_clock *clocks = ap->host->private_data;
++
++ while(clocks->xfer_speed) {
++ if (clocks->xfer_speed == speed)
++ return clocks->timing;
++ clocks++;
++ }
++ BUG();
++ return 0xffffffffU; /* silence compiler warning */
++}
++
++static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
++{
++ unsigned char model_num[40];
++ char *s;
++ unsigned int len;
++ int i = 0;
++
++ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
++ sizeof(model_num));
++ s = &model_num[0];
++ len = strnlen(s, sizeof(model_num));
++
++ /* ATAPI specifies that empty space is blank-filled; remove blanks */
++ while ((len > 0) && (s[len - 1] == ' ')) {
++ len--;
++ s[len] = 0;
++ }
++
++ while(list[i] != NULL) {
++ if (!strncmp(list[i], s, len)) {
++ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
++ modestr, list[i]);
++ return 1;
++ }
++ i++;
++ }
++ return 0;
++}
++
++static const char *bad_ata33[] = {
++ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
++ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
++ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
++ "Maxtor 90510D4",
++ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
++ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
++ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
++ NULL
++};
++
++static const char *bad_ata100_5[] = {
++ "IBM-DTLA-307075",
++ "IBM-DTLA-307060",
++ "IBM-DTLA-307045",
++ "IBM-DTLA-307030",
++ "IBM-DTLA-307020",
++ "IBM-DTLA-307015",
++ "IBM-DTLA-305040",
++ "IBM-DTLA-305030",
++ "IBM-DTLA-305020",
++ "IC35L010AVER07-0",
++ "IC35L020AVER07-0",
++ "IC35L030AVER07-0",
++ "IC35L040AVER07-0",
++ "IC35L060AVER07-0",
++ "WDC AC310200R",
++ NULL
++};
++
++/**
++ * hpt370_filter - mode selection filter
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Block UDMA on devices that cause trouble with this controller.
++ */
++
++static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
++{
++ if (adev->class != ATA_DEV_ATA) {
++ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
++ mask &= ~ATA_MASK_UDMA;
++ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
++ mask &= ~(0x1F << ATA_SHIFT_UDMA);
++ }
++ return ata_pci_default_filter(ap, adev, mask);
++}
++
++/**
++ * hpt370a_filter - mode selection filter
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Block UDMA on devices that cause trouble with this controller.
++ */
++
++static unsigned long hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
++{
++ if (adev->class != ATA_DEV_ATA) {
++ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
++ mask &= ~ (0x1F << ATA_SHIFT_UDMA);
++ }
++ return ata_pci_default_filter(ap, adev, mask);
++}
++
++/**
++ * hpt37x_pre_reset - reset the hpt37x bus
++ * @ap: ATA port to reset
++ *
++ * Perform the initial reset handling for the 370/372 and 374 func 0
++ */
++
++static int hpt37x_pre_reset(struct ata_port *ap)
++{
++ u8 scr2, ata66;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ pci_read_config_byte(pdev, 0x5B, &scr2);
++ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
++ /* Cable register now active */
++ pci_read_config_byte(pdev, 0x5A, &ata66);
++ /* Restore state */
++ pci_write_config_byte(pdev, 0x5B, scr2);
++
++ if (ata66 & (1 << ap->port_no))
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++
++ /* Reset the state machine */
++ pci_write_config_byte(pdev, 0x50, 0x37);
++ pci_write_config_byte(pdev, 0x54, 0x37);
++ udelay(100);
++
++ return ata_std_prereset(ap);
++}
++
++/**
++ * hpt37x_error_handler - reset the hpt374
++ * @ap: ATA port to reset
++ *
++ * Perform probe for HPT37x, except for HPT374 channel 2
++ */
++
++static void hpt37x_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++static int hpt374_pre_reset(struct ata_port *ap)
++{
++ u16 mcr3, mcr6;
++ u8 ata66;
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ /* Do the extra channel work */
++ pci_read_config_word(pdev, 0x52, &mcr3);
++ pci_read_config_word(pdev, 0x56, &mcr6);
++ /* Set bit 15 of 0x52 to enable TCBLID as input
++ Set bit 15 of 0x56 to enable FCBLID as input
++ */
++ pci_write_config_word(pdev, 0x52, mcr3 | 0x8000);
++ pci_write_config_word(pdev, 0x56, mcr6 | 0x8000);
++ pci_read_config_byte(pdev, 0x5A, &ata66);
++ /* Reset TCBLID/FCBLID to output */
++ pci_write_config_word(pdev, 0x52, mcr3);
++ pci_write_config_word(pdev, 0x56, mcr6);
++
++ if (ata66 & (1 << ap->port_no))
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++
++ /* Reset the state machine */
++ pci_write_config_byte(pdev, 0x50, 0x37);
++ pci_write_config_byte(pdev, 0x54, 0x37);
++ udelay(100);
++
++ return ata_std_prereset(ap);
++}
++
++/**
++ * hpt374_error_handler - reset the hpt374
++ * @classes:
++ *
++ * The 374 cable detect is a little different due to the extra
++ * channels. The function 0 channels work like usual but function 1
++ * is special
++ */
++
++static void hpt374_error_handler(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (!(PCI_FUNC(pdev->devfn) & 1))
++ hpt37x_error_handler(ap);
++ else
++ ata_bmdma_drive_eh(ap, hpt374_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * hpt370_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Perform PIO mode setup.
++ */
++
++static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ fast &= ~0x02;
++ fast |= 0x01;
++ pci_write_config_byte(pdev, addr2, fast);
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt37x_find_mode(ap, adev->pio_mode);
++ mode &= ~0x8000000; /* No FIFO in PIO */
++ mode &= ~0x30070000; /* Leave config bits alone */
++ reg &= 0x30070000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt370_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * Set up the channel for MWDMA or UDMA modes. Much the same as with
++ * PIO, load the mode number and then set MWDMA or UDMA flag.
++ */
++
++static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ fast &= ~0x02;
++ fast |= 0x01;
++ pci_write_config_byte(pdev, addr2, fast);
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt37x_find_mode(ap, adev->dma_mode);
++ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
++ mode &= ~0xC0000000; /* Leave config bits alone */
++ reg &= 0xC0000000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt370_bmdma_start - DMA engine begin
++ * @qc: ATA command
++ *
++ * The 370 and 370A want us to reset the DMA engine each time we
++ * use it. The 372 and later are fine.
++ */
++
++static void hpt370_bmdma_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
++ udelay(10);
++ ata_bmdma_start(qc);
++}
++
++/**
++ * hpt370_bmdma_end - DMA engine stop
++ * @qc: ATA command
++ *
++ * Work around the HPT370 DMA engine.
++ */
++
++static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2);
++ u8 dma_cmd;
++ unsigned long bmdma = ap->ioaddr.bmdma_addr;
++
++ if (dma_stat & 0x01) {
++ udelay(20);
++ dma_stat = inb(bmdma + 2);
++ }
++ if (dma_stat & 0x01) {
++ /* Clear the engine */
++ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
++ udelay(10);
++ /* Stop DMA */
++ dma_cmd = inb(bmdma );
++ outb(dma_cmd & 0xFE, bmdma);
++ /* Clear Error */
++ dma_stat = inb(bmdma + 2);
++ outb(dma_stat | 0x06 , bmdma + 2);
++ /* Clear the engine */
++ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
++ udelay(10);
++ }
++ ata_bmdma_stop(qc);
++}
++
++/**
++ * hpt372_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Perform PIO mode setup.
++ */
++
++static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ fast &= ~0x07;
++ pci_write_config_byte(pdev, addr2, fast);
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt37x_find_mode(ap, adev->pio_mode);
++
++ printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
++ mode &= ~0x80000000; /* No FIFO in PIO */
++ mode &= ~0x30070000; /* Leave config bits alone */
++ reg &= 0x30070000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt372_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * Set up the channel for MWDMA or UDMA modes. Much the same as with
++ * PIO, load the mode number and then set MWDMA or UDMA flag.
++ */
++
++static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ fast &= ~0x07;
++ pci_write_config_byte(pdev, addr2, fast);
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt37x_find_mode(ap, adev->dma_mode);
++ printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
++ mode &= ~0xC0000000; /* Leave config bits alone */
++ mode |= 0x80000000; /* FIFO in MWDMA or UDMA */
++ reg &= 0xC0000000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt37x_bmdma_end - DMA engine stop
++ * @qc: ATA command
++ *
++ * Clean up after the HPT372 and later DMA engine
++ */
++
++static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int mscreg = 0x50 + 2 * ap->port_no;
++ u8 bwsr_stat, msc_stat;
++
++ pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
++ pci_read_config_byte(pdev, mscreg, &msc_stat);
++ if (bwsr_stat & (1 << ap->port_no))
++ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30);
++ ata_bmdma_stop(qc);
++}
++
++
++static struct scsi_host_template hpt37x_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++/*
++ * Configuration for HPT370
++ */
++
++static struct ata_port_operations hpt370_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt370_set_piomode,
++ .set_dmamode = hpt370_set_dmamode,
++ .mode_filter = hpt370_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt37x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = hpt370_bmdma_start,
++ .bmdma_stop = hpt370_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Configuration for HPT370A. Close to 370 but less filters
++ */
++
++static struct ata_port_operations hpt370a_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt370_set_piomode,
++ .set_dmamode = hpt370_set_dmamode,
++ .mode_filter = hpt370a_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt37x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = hpt370_bmdma_start,
++ .bmdma_stop = hpt370_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Configuration for HPT372, HPT371, HPT302. Slightly different PIO
++ * and DMA mode setting functionality.
++ */
++
++static struct ata_port_operations hpt372_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt372_set_piomode,
++ .set_dmamode = hpt372_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt37x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = hpt37x_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Configuration for HPT374. Mode setting works like 372 and friends
++ * but we have a different cable detection procedure.
++ */
++
++static struct ata_port_operations hpt374_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt372_set_piomode,
++ .set_dmamode = hpt372_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt374_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = hpt37x_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * htp37x_clock_slot - Turn timing to PC clock entry
++ * @freq: Reported frequency timing
++ * @base: Base timing
++ *
++ * Turn the timing data intoa clock slot (0 for 33, 1 for 40, 2 for 50
++ * and 3 for 66Mhz)
++ */
++
++static int hpt37x_clock_slot(unsigned int freq, unsigned int base)
++{
++ unsigned int f = (base * freq) / 192; /* Mhz */
++ if (f < 40)
++ return 0; /* 33Mhz slot */
++ if (f < 45)
++ return 1; /* 40Mhz slot */
++ if (f < 55)
++ return 2; /* 50Mhz slot */
++ return 3; /* 60Mhz slot */
++}
++
++/**
++ * hpt37x_calibrate_dpll - Calibrate the DPLL loop
++ * @dev: PCI device
++ *
++ * Perform a calibration cycle on the HPT37x DPLL. Returns 1 if this
++ * succeeds
++ */
++
++static int hpt37x_calibrate_dpll(struct pci_dev *dev)
++{
++ u8 reg5b;
++ u32 reg5c;
++ int tries;
++
++ for(tries = 0; tries < 0x5000; tries++) {
++ udelay(50);
++ pci_read_config_byte(dev, 0x5b, ®5b);
++ if (reg5b & 0x80) {
++ /* See if it stays set */
++ for(tries = 0; tries < 0x1000; tries ++) {
++ pci_read_config_byte(dev, 0x5b, ®5b);
++ /* Failed ? */
++ if ((reg5b & 0x80) == 0)
++ return 0;
++ }
++ /* Turn off tuning, we have the DPLL set */
++ pci_read_config_dword(dev, 0x5c, ®5c);
++ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
++ return 1;
++ }
++ }
++ /* Never went stable */
++ return 0;
++}
++/**
++ * hpt37x_init_one - Initialise an HPT37X/302
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Initialise an HPT37x device. There are some interesting complications
++ * here. Firstly the chip may report 366 and be one of several variants.
++ * Secondly all the timings depend on the clock for the chip which we must
++ * detect and look up
++ *
++ * This is the known chip mappings. It may be missing a couple of later
++ * releases.
++ *
++ * Chip version PCI Rev Notes
++ * HPT366 4 (HPT366) 0 Other driver
++ * HPT366 4 (HPT366) 1 Other driver
++ * HPT368 4 (HPT366) 2 Other driver
++ * HPT370 4 (HPT366) 3 UDMA100
++ * HPT370A 4 (HPT366) 4 UDMA100
++ * HPT372 4 (HPT366) 5 UDMA133 (1)
++ * HPT372N 4 (HPT366) 6 Other driver
++ * HPT372A 5 (HPT372) 1 UDMA133 (1)
++ * HPT372N 5 (HPT372) 2 Other driver
++ * HPT302 6 (HPT302) 1 UDMA133
++ * HPT302N 6 (HPT302) 2 Other driver
++ * HPT371 7 (HPT371) * UDMA133
++ * HPT374 8 (HPT374) * UDMA133 4 channel
++ * HPT372N 9 (HPT372N) * Other driver
++ *
++ * (1) UDMA133 support depends on the bus clock
++ */
++
++static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ /* HPT370 - UDMA100 */
++ static struct ata_port_info info_hpt370 = {
++ .sht = &hpt37x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &hpt370_port_ops
++ };
++ /* HPT370A - UDMA100 */
++ static struct ata_port_info info_hpt370a = {
++ .sht = &hpt37x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &hpt370a_port_ops
++ };
++ /* HPT371, 372 and friends - UDMA133 */
++ static struct ata_port_info info_hpt372 = {
++ .sht = &hpt37x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &hpt372_port_ops
++ };
++ /* HPT371, 372 and friends - UDMA100 at 50MHz clock */
++ static struct ata_port_info info_hpt372_50 = {
++ .sht = &hpt37x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &hpt372_port_ops
++ };
++ /* HPT374 - UDMA133 */
++ static struct ata_port_info info_hpt374 = {
++ .sht = &hpt37x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &hpt374_port_ops
++ };
++
++ static const int MHz[4] = { 33, 40, 50, 66 };
++
++ struct ata_port_info *port_info[2];
++ struct ata_port_info *port;
++
++ u8 irqmask;
++ u32 class_rev;
++ u32 freq;
++
++ const struct hpt_chip *chip_table;
++ int clock_slot;
++
++ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
++ class_rev &= 0xFF;
++
++ if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
++ /* May be a later chip in disguise. Check */
++ /* Older chips are in the HPT366 driver. Ignore them */
++ if (class_rev < 3)
++ return -ENODEV;
++ /* N series chips have their own driver. Ignore */
++ if (class_rev == 6)
++ return -ENODEV;
++
++ switch(class_rev) {
++ case 3:
++ port = &info_hpt370;
++ chip_table = &hpt370;
++ break;
++ case 4:
++ port = &info_hpt370a;
++ chip_table = &hpt370a;
++ break;
++ case 5:
++ port = &info_hpt372;
++ chip_table = &hpt372;
++ break;
++ default:
++ printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype please report (%d).\n", class_rev);
++ return -ENODEV;
++ }
++ } else {
++ switch(dev->device) {
++ case PCI_DEVICE_ID_TTI_HPT372:
++ /* 372N if rev >= 2*/
++ if (class_rev >= 2)
++ return -ENODEV;
++ port = &info_hpt372;
++ chip_table = &hpt372a;
++ break;
++ case PCI_DEVICE_ID_TTI_HPT302:
++ /* 302N if rev > 1 */
++ if (class_rev > 1)
++ return -ENODEV;
++ port = &info_hpt372;
++ /* Check this */
++ chip_table = &hpt302;
++ break;
++ case PCI_DEVICE_ID_TTI_HPT371:
++ port = &info_hpt372;
++ chip_table = &hpt371;
++ break;
++ case PCI_DEVICE_ID_TTI_HPT374:
++ chip_table = &hpt374;
++ port = &info_hpt374;
++ break;
++ default:
++ printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device);
++ return -ENODEV;
++ }
++ }
++ /* Ok so this is a chip we support */
++
++ 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, 0x5A, &irqmask);
++ irqmask &= ~0x10;
++ pci_write_config_byte(dev, 0x5a, irqmask);
++
++ /*
++ * default to pci clock. make sure MA15/16 are set to output
++ * 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.
++ */
++
++ pci_write_config_byte(dev, 0x5b, 0x23);
++
++ pci_read_config_dword(dev, 0x70, &freq);
++ if ((freq >> 12) != 0xABCDE) {
++ int i;
++ u8 sr;
++ u32 total = 0;
++
++ printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n");
++
++ /* This is the process the HPT371 BIOS is reported to use */
++ for(i = 0; i < 128; i++) {
++ pci_read_config_byte(dev, 0x78, &sr);
++ total += sr;
++ udelay(15);
++ }
++ freq = total / 128;
++ }
++ freq &= 0x1FF;
++
++ /*
++ * Turn the frequency check into a band and then find a timing
++ * table to match it.
++ */
++
++ clock_slot = hpt37x_clock_slot(freq, chip_table->base);
++ if (chip_table->clocks[clock_slot] == NULL) {
++ /*
++ * We need to try PLL mode instead
++ */
++ unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192;
++ unsigned int f_high = f_low + 2;
++ int adjust;
++
++ for(adjust = 0; adjust < 8; adjust++) {
++ if (hpt37x_calibrate_dpll(dev))
++ break;
++ /* See if it'll settle at a fractionally different clock */
++ if ((adjust & 3) == 3) {
++ f_low --;
++ f_high ++;
++ }
++ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
++ }
++ if (adjust == 8) {
++ printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
++ return -ENODEV;
++ }
++ /* Check if this works for all cases */
++ port->private_data = (void *)hpt370_timings_66;
++
++ printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]);
++ } else {
++ port->private_data = (void *)chip_table->clocks[clock_slot];
++ /*
++ * Perform a final fixup. The 371 and 372 clock determines
++ * if UDMA133 is available.
++ */
++
++ if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */
++ printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n");
++ if (port == &info_hpt372)
++ port = &info_hpt372_50;
++ else BUG();
++ }
++ printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
++ }
++ port_info[0] = port_info[1] = port;
++ /* Now kick off ATA set up */
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id hpt37x[] = {
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
++
++ { },
++};
++
++static struct pci_driver hpt37x_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = hpt37x,
++ .probe = hpt37x_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init hpt37x_init(void)
++{
++ return pci_register_driver(&hpt37x_pci_driver);
++}
++
++static void __exit hpt37x_exit(void)
++{
++ pci_unregister_driver(&hpt37x_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, hpt37x);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(hpt37x_init);
++module_exit(hpt37x_exit);
+diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
+new file mode 100644
+index 0000000..58cfb2b
+--- /dev/null
++++ b/drivers/ata/pata_hpt3x2n.c
+@@ -0,0 +1,596 @@
++/*
++ * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers.
++ *
++ * This driver is heavily based upon:
++ *
++ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
++ *
++ * Copyright (C) 1999-2003 Andre Hedrick <andre at linux-ide.org>
++ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
++ * Portions Copyright (C) 2003 Red Hat Inc
++ *
++ *
++ * TODO
++ * 371N
++ * Work out best PLL policy
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_hpt3x2n"
++#define DRV_VERSION "0.3"
++
++enum {
++ HPT_PCI_FAST = (1 << 31),
++ PCI66 = (1 << 1),
++ USE_DPLL = (1 << 0)
++};
++
++struct hpt_clock {
++ u8 xfer_speed;
++ u32 timing;
++};
++
++struct hpt_chip {
++ const char *name;
++ struct hpt_clock *clocks[3];
++};
++
++/* key for bus clock timings
++ * bit
++ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
++ * DMA. cycles = value + 1
++ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
++ * DMA. cycles = value + 1
++ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
++ * register access.
++ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
++ * register access.
++ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
++ * during task file register access.
++ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
++ * xfer.
++ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
++ * register access.
++ * 28 UDMA enable
++ * 29 DMA enable
++ * 30 PIO_MST enable. if set, the chip is in bus master mode during
++ * PIO.
++ * 31 FIFO enable.
++ */
++
++/* 66MHz DPLL clocks */
++
++static struct hpt_clock hpt3x2n_clocks[] = {
++ { XFER_UDMA_7, 0x1c869c62 },
++ { XFER_UDMA_6, 0x1c869c62 },
++ { XFER_UDMA_5, 0x1c8a9c62 },
++ { XFER_UDMA_4, 0x1c8a9c62 },
++ { XFER_UDMA_3, 0x1c8e9c62 },
++ { XFER_UDMA_2, 0x1c929c62 },
++ { XFER_UDMA_1, 0x1c9a9c62 },
++ { XFER_UDMA_0, 0x1c829c62 },
++
++ { XFER_MW_DMA_2, 0x2c829c62 },
++ { XFER_MW_DMA_1, 0x2c829c66 },
++ { XFER_MW_DMA_0, 0x2c829d2c },
++
++ { XFER_PIO_4, 0x0c829c62 },
++ { XFER_PIO_3, 0x0c829c84 },
++ { XFER_PIO_2, 0x0c829ca6 },
++ { XFER_PIO_1, 0x0d029d26 },
++ { XFER_PIO_0, 0x0d029d5e },
++ { 0, 0x0d029d5e }
++};
++
++/**
++ * hpt3x2n_find_mode - reset the hpt3x2n bus
++ * @ap: ATA port
++ * @speed: transfer mode
++ *
++ * Return the 32bit register programming information for this channel
++ * that matches the speed provided. For the moment the clocks table
++ * is hard coded but easy to change. This will be needed if we use
++ * different DPLLs
++ */
++
++static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
++{
++ struct hpt_clock *clocks = hpt3x2n_clocks;
++
++ while(clocks->xfer_speed) {
++ if (clocks->xfer_speed == speed)
++ return clocks->timing;
++ clocks++;
++ }
++ BUG();
++ return 0xffffffffU; /* silence compiler warning */
++}
++
++/**
++ * hpt3x2n_pre_reset - reset the hpt3x2n bus
++ * @ap: ATA port to reset
++ *
++ * Perform the initial reset handling for the 3x2n series controllers.
++ * Reset the hardware and state machine, obtain the cable type.
++ */
++
++static int hpt3xn_pre_reset(struct ata_port *ap)
++{
++ u8 scr2, ata66;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ pci_read_config_byte(pdev, 0x5B, &scr2);
++ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
++ /* Cable register now active */
++ pci_read_config_byte(pdev, 0x5A, &ata66);
++ /* Restore state */
++ pci_write_config_byte(pdev, 0x5B, scr2);
++
++ if (ata66 & (1 << ap->port_no))
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++
++ /* Reset the state machine */
++ pci_write_config_byte(pdev, 0x50, 0x37);
++ pci_write_config_byte(pdev, 0x54, 0x37);
++ udelay(100);
++
++ return ata_std_prereset(ap);
++}
++
++/**
++ * hpt3x2n_error_handler - probe the hpt3x2n bus
++ * @ap: ATA port to reset
++ *
++ * Perform the probe reset handling for the 3x2N
++ */
++
++static void hpt3x2n_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, hpt3xn_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * hpt3x2n_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Perform PIO mode setup.
++ */
++
++static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ fast &= ~0x07;
++ pci_write_config_byte(pdev, addr2, fast);
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt3x2n_find_mode(ap, adev->pio_mode);
++ mode &= ~0x8000000; /* No FIFO in PIO */
++ mode &= ~0x30070000; /* Leave config bits alone */
++ reg &= 0x30070000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt3x2n_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * Set up the channel for MWDMA or UDMA modes. Much the same as with
++ * PIO, load the mode number and then set MWDMA or UDMA flag.
++ */
++
++static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 addr1, addr2;
++ u32 reg;
++ u32 mode;
++ u8 fast;
++
++ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
++ addr2 = 0x51 + 4 * ap->port_no;
++
++ /* Fast interrupt prediction disable, hold off interrupt disable */
++ pci_read_config_byte(pdev, addr2, &fast);
++ fast &= ~0x07;
++ pci_write_config_byte(pdev, addr2, fast);
++
++ pci_read_config_dword(pdev, addr1, ®);
++ mode = hpt3x2n_find_mode(ap, adev->dma_mode);
++ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
++ mode &= ~0xC0000000; /* Leave config bits alone */
++ reg &= 0xC0000000; /* Strip timing bits */
++ pci_write_config_dword(pdev, addr1, reg | mode);
++}
++
++/**
++ * hpt3x2n_bmdma_end - DMA engine stop
++ * @qc: ATA command
++ *
++ * Clean up after the HPT3x2n and later DMA engine
++ */
++
++static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int mscreg = 0x50 + 2 * ap->port_no;
++ u8 bwsr_stat, msc_stat;
++
++ pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
++ pci_read_config_byte(pdev, mscreg, &msc_stat);
++ if (bwsr_stat & (1 << ap->port_no))
++ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30);
++ ata_bmdma_stop(qc);
++}
++
++/**
++ * hpt3x2n_set_clock - clock control
++ * @ap: ATA port
++ * @source: 0x21 or 0x23 for PLL or PCI sourced clock
++ *
++ * Switch the ATA bus clock between the PLL and PCI clock sources
++ * while correctly isolating the bus and resetting internal logic
++ *
++ * We must use the DPLL for
++ * - writing
++ * - second channel UDMA7 (SATA ports) or higher
++ * - 66MHz PCI
++ *
++ * or we will underclock the device and get reduced performance.
++ */
++
++static void hpt3x2n_set_clock(struct ata_port *ap, int source)
++{
++ unsigned long bmdma = ap->ioaddr.bmdma_addr;
++
++ /* Tristate the bus */
++ outb(0x80, bmdma+0x73);
++ outb(0x80, bmdma+0x77);
++
++ /* Switch clock and reset channels */
++ outb(source, bmdma+0x7B);
++ outb(0xC0, bmdma+0x79);
++
++ /* Reset state machines */
++ outb(0x37, bmdma+0x70);
++ outb(0x37, bmdma+0x74);
++
++ /* Complete reset */
++ outb(0x00, bmdma+0x79);
++
++ /* Reconnect channels to bus */
++ outb(0x00, bmdma+0x73);
++ outb(0x00, bmdma+0x77);
++}
++
++/* Check if our partner interface is busy */
++
++static int hpt3x2n_pair_idle(struct ata_port *ap)
++{
++ struct ata_host *host = ap->host;
++ struct ata_port *pair = host->ports[ap->port_no ^ 1];
++
++ if (pair->hsm_task_state == HSM_ST_IDLE)
++ return 1;
++ return 0;
++}
++
++static int hpt3x2n_use_dpll(struct ata_port *ap, int reading)
++{
++ long flags = (long)ap->host->private_data;
++ /* See if we should use the DPLL */
++ if (reading == 0)
++ return USE_DPLL; /* Needed for write */
++ if (flags & PCI66)
++ return USE_DPLL; /* Needed at 66Mhz */
++ return 0;
++}
++
++static unsigned int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_taskfile *tf = &qc->tf;
++ struct ata_port *ap = qc->ap;
++ int flags = (long)ap->host->private_data;
++
++ if (hpt3x2n_pair_idle(ap)) {
++ int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE));
++ if ((flags & USE_DPLL) != dpll) {
++ if (dpll == 1)
++ hpt3x2n_set_clock(ap, 0x21);
++ else
++ hpt3x2n_set_clock(ap, 0x23);
++ }
++ }
++ return ata_qc_issue_prot(qc);
++}
++
++static struct scsi_host_template hpt3x2n_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++/*
++ * Configuration for HPT3x2n.
++ */
++
++static struct ata_port_operations hpt3x2n_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt3x2n_set_piomode,
++ .set_dmamode = hpt3x2n_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt3x2n_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = hpt3x2n_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = hpt3x2n_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * hpt3xn_calibrate_dpll - Calibrate the DPLL loop
++ * @dev: PCI device
++ *
++ * Perform a calibration cycle on the HPT3xN DPLL. Returns 1 if this
++ * succeeds
++ */
++
++static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
++{
++ u8 reg5b;
++ u32 reg5c;
++ int tries;
++
++ for(tries = 0; tries < 0x5000; tries++) {
++ udelay(50);
++ pci_read_config_byte(dev, 0x5b, ®5b);
++ if (reg5b & 0x80) {
++ /* See if it stays set */
++ for(tries = 0; tries < 0x1000; tries ++) {
++ pci_read_config_byte(dev, 0x5b, ®5b);
++ /* Failed ? */
++ if ((reg5b & 0x80) == 0)
++ return 0;
++ }
++ /* Turn off tuning, we have the DPLL set */
++ pci_read_config_dword(dev, 0x5c, ®5c);
++ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
++ return 1;
++ }
++ }
++ /* Never went stable */
++ return 0;
++}
++
++static int hpt3x2n_pci_clock(struct pci_dev *pdev)
++{
++ unsigned long freq;
++ u32 fcnt;
++
++ pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt);
++ if ((fcnt >> 12) != 0xABCDE) {
++ printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
++ return 33; /* Not BIOS set */
++ }
++ fcnt &= 0x1FF;
++
++ freq = (fcnt * 77) / 192;
++
++ /* Clamp to bands */
++ if (freq < 40)
++ return 33;
++ if (freq < 45)
++ return 40;
++ if (freq < 55)
++ return 50;
++ return 66;
++}
++
++/**
++ * hpt3x2n_init_one - Initialise an HPT37X/302
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Initialise an HPT3x2n device. There are some interesting complications
++ * here. Firstly the chip may report 366 and be one of several variants.
++ * Secondly all the timings depend on the clock for the chip which we must
++ * detect and look up
++ *
++ * This is the known chip mappings. It may be missing a couple of later
++ * releases.
++ *
++ * Chip version PCI Rev Notes
++ * HPT372 4 (HPT366) 5 Other driver
++ * HPT372N 4 (HPT366) 6 UDMA133
++ * HPT372 5 (HPT372) 1 Other driver
++ * HPT372N 5 (HPT372) 2 UDMA133
++ * HPT302 6 (HPT302) * Other driver
++ * HPT302N 6 (HPT302) > 1 UDMA133
++ * HPT371 7 (HPT371) * Other driver
++ * HPT371N 7 (HPT371) > 1 UDMA133
++ * HPT374 8 (HPT374) * Other driver
++ * HPT372N 9 (HPT372N) * UDMA133
++ *
++ * (1) UDMA133 support depends on the bus clock
++ *
++ * To pin down HPT371N
++ */
++
++static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ /* HPT372N and friends - UDMA133 */
++ static struct ata_port_info info = {
++ .sht = &hpt3x2n_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &hpt3x2n_port_ops
++ };
++ struct ata_port_info *port_info[2];
++ struct ata_port_info *port = &info;
++
++ u8 irqmask;
++ u32 class_rev;
++
++ unsigned int pci_mhz;
++ unsigned int f_low, f_high;
++ int adjust;
++
++ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
++ class_rev &= 0xFF;
++
++ switch(dev->device) {
++ case PCI_DEVICE_ID_TTI_HPT366:
++ if (class_rev < 6)
++ return -ENODEV;
++ break;
++ case PCI_DEVICE_ID_TTI_HPT372:
++ /* 372N if rev >= 1*/
++ if (class_rev == 0)
++ return -ENODEV;
++ break;
++ case PCI_DEVICE_ID_TTI_HPT302:
++ if (class_rev < 2)
++ return -ENODEV;
++ break;
++ case PCI_DEVICE_ID_TTI_HPT372N:
++ break;
++ default:
++ printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);
++ return -ENODEV;
++ }
++
++ /* Ok so this is a chip we support */
++
++ 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, 0x5A, &irqmask);
++ irqmask &= ~0x10;
++ pci_write_config_byte(dev, 0x5a, irqmask);
++
++ /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
++ 50 for UDMA100. Right now we always use 66 */
++
++ pci_mhz = hpt3x2n_pci_clock(dev);
++
++ f_low = (pci_mhz * 48) / 66; /* PCI Mhz for 66Mhz DPLL */
++ f_high = f_low + 2; /* Tolerance */
++
++ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
++ /* PLL clock */
++ pci_write_config_byte(dev, 0x5B, 0x21);
++
++ /* Unlike the 37x we don't try jiggling the frequency */
++ for(adjust = 0; adjust < 8; adjust++) {
++ if (hpt3xn_calibrate_dpll(dev))
++ break;
++ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
++ }
++ if (adjust == 8)
++ printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n");
++
++ /* Set our private data up. We only need a few flags so we use
++ it directly */
++ port->private_data = NULL;
++ if (pci_mhz > 60)
++ port->private_data = (void *)PCI66;
++
++ /* Now kick off ATA set up */
++ port_info[0] = port_info[1] = port;
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id hpt3x2n[] = {
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
++
++ { },
++};
++
++static struct pci_driver hpt3x2n_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = hpt3x2n,
++ .probe = hpt3x2n_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init hpt3x2n_init(void)
++{
++ return pci_register_driver(&hpt3x2n_pci_driver);
++}
++
++static void __exit hpt3x2n_exit(void)
++{
++ pci_unregister_driver(&hpt3x2n_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, hpt3x2n);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(hpt3x2n_init);
++module_exit(hpt3x2n_exit);
+diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
+new file mode 100644
+index 0000000..3334d72
+--- /dev/null
++++ b/drivers/ata/pata_hpt3x3.c
+@@ -0,0 +1,227 @@
++/*
++ * pata_hpt3x3 - HPT3x3 driver
++ * (c) Copyright 2005-2006 Red Hat
++ *
++ * Was pata_hpt34x but the naming was confusing as it supported the
++ * 343 and 363 so it has been renamed.
++ *
++ * Based on:
++ * linux/drivers/ide/pci/hpt34x.c Version 0.40 Sept 10, 2002
++ * Copyright (C) 1998-2000 Andre Hedrick <andre at linux-ide.org>
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_hpt3x3"
++#define DRV_VERSION "0.4.1"
++
++static int hpt3x3_probe_init(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * hpt3x3_probe_reset - reset the hpt3x3 bus
++ * @ap: ATA port to reset
++ *
++ * Perform the housekeeping when doing an ATA bus reeset. We just
++ * need to force the cable type.
++ */
++
++static void hpt3x3_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * hpt3x3_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Set our PIO requirements. This is fairly simple on the HPT3x3 as
++ * all we have to do is clear the MWDMA and UDMA bits then load the
++ * mode number.
++ */
++
++static void hpt3x3_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 r1, r2;
++ int dn = 2 * ap->port_no + adev->devno;
++
++ pci_read_config_dword(pdev, 0x44, &r1);
++ pci_read_config_dword(pdev, 0x48, &r2);
++ /* Load the PIO timing number */
++ r1 &= ~(7 << (3 * dn));
++ r1 |= (adev->pio_mode - XFER_PIO_0) << (3 * dn);
++ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
++
++ pci_write_config_dword(pdev, 0x44, r1);
++ pci_write_config_dword(pdev, 0x48, r2);
++}
++
++/**
++ * hpt3x3_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * Set up the channel for MWDMA or UDMA modes. Much the same as with
++ * PIO, load the mode number and then set MWDMA or UDMA flag.
++ */
++
++static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 r1, r2;
++ int dn = 2 * ap->port_no + adev->devno;
++ int mode_num = adev->dma_mode & 0x0F;
++
++ pci_read_config_dword(pdev, 0x44, &r1);
++ pci_read_config_dword(pdev, 0x48, &r2);
++ /* Load the timing number */
++ r1 &= ~(7 << (3 * dn));
++ r1 |= (mode_num << (3 * dn));
++ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
++
++ if (adev->dma_mode >= XFER_UDMA_0)
++ r2 |= 0x01 << dn; /* Ultra mode */
++ else
++ r2 |= 0x10 << dn; /* MWDMA */
++
++ pci_write_config_dword(pdev, 0x44, r1);
++ pci_write_config_dword(pdev, 0x48, r2);
++}
++
++static struct scsi_host_template hpt3x3_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations hpt3x3_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = hpt3x3_set_piomode,
++ .set_dmamode = hpt3x3_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = hpt3x3_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * hpt3x3_init_one - Initialise an HPT343/363
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Perform basic initialisation. The chip has a quirk that it won't
++ * function unless it is at XX00. The old ATA driver touched this up
++ * but we leave it for pci quirks to do properly.
++ */
++
++static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &hpt3x3_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x07,
++ .port_ops = &hpt3x3_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++ u16 cmd;
++
++ /* Initialize the board */
++ pci_write_config_word(dev, 0x80, 0x00);
++ /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ if (cmd & PCI_COMMAND_MEMORY)
++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
++ else
++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
++
++ /* Now kick off ATA set up */
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id hpt3x3[] = {
++ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
++
++ { },
++};
++
++static struct pci_driver hpt3x3_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = hpt3x3,
++ .probe = hpt3x3_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init hpt3x3_init(void)
++{
++ return pci_register_driver(&hpt3x3_pci_driver);
++}
++
++
++static void __exit hpt3x3_exit(void)
++{
++ pci_unregister_driver(&hpt3x3_pci_driver);
++}
++
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the Highpoint HPT343/363");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, hpt3x3);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(hpt3x3_init);
++module_exit(hpt3x3_exit);
+diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
+new file mode 100644
+index 0000000..640b8b0
+--- /dev/null
++++ b/drivers/ata/pata_isapnp.c
+@@ -0,0 +1,156 @@
++
++/*
++ * pata-isapnp.c - ISA PnP PATA controller driver.
++ * Copyright 2005/2006 Red Hat Inc <alan at redhat.com>, all rights reserved.
++ *
++ * Based in part on ide-pnp.c by Andrey Panin <pazke at donpac.ru>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/isapnp.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/ata.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_isapnp"
++#define DRV_VERSION "0.1.5"
++
++static struct scsi_host_template isapnp_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations isapnp_port_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * isapnp_init_one - attach an isapnp interface
++ * @idev: PnP device
++ * @dev_id: matching detect line
++ *
++ * Register an ISA bus IDE interface. Such interfaces are PIO 0 and
++ * non shared IRQ.
++ */
++
++static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
++{
++ struct ata_probe_ent ae;
++
++ if (pnp_port_valid(idev, 0) == 0)
++ return -ENODEV;
++
++ /* FIXME: Should selected polled PIO here not fail */
++ if (pnp_irq_valid(idev, 0) == 0)
++ return -ENODEV;
++
++ memset(&ae, 0, sizeof(struct ata_probe_ent));
++ INIT_LIST_HEAD(&ae.node);
++ ae.dev = &idev->dev;
++ ae.port_ops = &isapnp_port_ops;
++ ae.sht = &isapnp_sht;
++ ae.n_ports = 1;
++ ae.pio_mask = 1; /* ISA so PIO 0 cycles */
++ ae.irq = pnp_irq(idev, 0);
++ ae.irq_flags = 0;
++ ae.port_flags = ATA_FLAG_SLAVE_POSS;
++ ae.port[0].cmd_addr = pnp_port_start(idev, 0);
++
++ if (pnp_port_valid(idev, 1) == 0) {
++ ae.port[0].altstatus_addr = pnp_port_start(idev, 1);
++ ae.port[0].ctl_addr = pnp_port_start(idev, 1);
++ ae.port_flags |= ATA_FLAG_SRST;
++ }
++ ata_std_ports(&ae.port[0]);
++
++ if (ata_device_add(&ae) == 0)
++ return -ENODEV;
++ return 0;
++}
++
++/**
++ * isapnp_remove_one - unplug an isapnp interface
++ * @idev: PnP device
++ *
++ * Remove a previously configured PnP ATA port. Called only on module
++ * unload events as the core does not currently deal with ISAPnP docking.
++ */
++
++static void isapnp_remove_one(struct pnp_dev *idev)
++{
++ struct device *dev = &idev->dev;
++ struct ata_host *host = dev_get_drvdata(dev);
++
++ ata_host_remove(host);
++ dev_set_drvdata(dev, NULL);
++}
++
++static struct pnp_device_id isapnp_devices[] = {
++ /* Generic ESDI/IDE/ATA compatible hard disk controller */
++ {.id = "PNP0600", .driver_data = 0},
++ {.id = ""}
++};
++
++static struct pnp_driver isapnp_driver = {
++ .name = DRV_NAME,
++ .id_table = isapnp_devices,
++ .probe = isapnp_init_one,
++ .remove = isapnp_remove_one,
++};
++
++static int __init isapnp_init(void)
++{
++ return pnp_register_driver(&isapnp_driver);
++}
++
++static void __exit isapnp_exit(void)
++{
++ pnp_unregister_driver(&isapnp_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for ISA PnP ATA");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(isapnp_init);
++module_exit(isapnp_exit);
+diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
+new file mode 100644
+index 0000000..18ff3e5
+--- /dev/null
++++ b/drivers/ata/pata_it821x.c
+@@ -0,0 +1,846 @@
++/*
++ * ata-it821x.c - IT821x PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based upon
++ *
++ * it821x.c
++ *
++ * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
++ *
++ * Copyright (C) 2004 Red Hat <alan at 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 and other speed filtering
++ * - Command filter in smart mode
++ * - RAID configuration ioctls
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++
++#define DRV_NAME "pata_it821x"
++#define DRV_VERSION "0.3.2"
++
++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) */
++ u16 last_device; /* Master or slave loaded ? */
++};
++
++#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_pre_reset - probe
++ * @ap: ATA port
++ *
++ * Set the cable type
++ */
++
++static int it821x_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * it821x_error_handler - probe/reset
++ * @ap: ATA port
++ *
++ * Set the cable type and trigger a probe
++ */
++
++static void it821x_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * it821x_program - program the PIO/MWDMA registers
++ * @ap: ATA port
++ * @adev: Device to program
++ * @timing: Timing value (66Mhz in top 8bits, 50 in the low 8)
++ *
++ * Program the PIO/MWDMA timing for this channel according to the
++ * current clock. These share the same register so are managed by
++ * the DMA start/stop sequence as with the old driver.
++ */
++
++static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 timing)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct it821x_dev *itdev = ap->private_data;
++ int channel = ap->port_no;
++ u8 conf;
++
++ /* Program PIO/MWDMA timing bits */
++ if (itdev->clock_mode == ATA_66)
++ conf = timing >> 8;
++ else
++ conf = timing & 0xFF;
++ pci_write_config_byte(pdev, 0x54 + 4 * channel, conf);
++}
++
++
++/**
++ * it821x_program_udma - program the UDMA registers
++ * @ap: ATA port
++ * @adev: ATA device to update
++ * @timing: Timing bits. Top 8 are for 66Mhz bottom for 50Mhz
++ *
++ * Program the UDMA timing for this drive according to the
++ * current clock. Handles the dual clocks and also knows about
++ * the errata on the 0x10 revision. The UDMA errata is partly handled
++ * here and partly in start_dma.
++ */
++
++static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev, u16 timing)
++{
++ struct it821x_dev *itdev = ap->private_data;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int channel = ap->port_no;
++ int unit = adev->devno;
++ 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(pdev, 0x56 + 4 * channel + unit, conf);
++ else {
++ /* Early revision must be programmed for both together */
++ pci_write_config_byte(pdev, 0x56 + 4 * channel, conf);
++ pci_write_config_byte(pdev, 0x56 + 4 * channel + 1, conf);
++ }
++}
++
++/**
++ * it821x_clock_strategy
++ * @ap: ATA interface
++ * @adev: ATA device being updated
++ *
++ * Select between the 50 and 66Mhz base clocks to get the best
++ * results for this interface.
++ */
++
++static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct it821x_dev *itdev = ap->private_data;
++ u8 unit = adev->devno;
++ struct ata_device *pair = ata_dev_pair(adev);
++
++ int clock, altclock;
++ u8 v;
++ int sel = 0;
++
++ /* Look for the most wanted clocking */
++ 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(pdev, 0x50, &v);
++ v &= ~(1 << (1 + ap->port_no));
++ v |= sel << (1 + ap->port_no);
++ pci_write_config_byte(pdev, 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(ap, pair, itdev->udma[1-unit]);
++ it821x_program(ap, 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(ap, adev, itdev->udma[unit]);
++ it821x_program(ap, adev, itdev->pio[unit]);
++ }
++}
++
++/**
++ * it821x_passthru_set_piomode - set PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Configure for PIO mode. This is complicated as the register is
++ * shared by PIO and MWDMA and for both channels.
++ */
++
++static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ /* Spec says 89 ref driver uses 88 */
++ static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
++ static const u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
++
++ struct it821x_dev *itdev = ap->private_data;
++ int unit = adev->devno;
++ int mode_wanted = adev->pio_mode - XFER_PIO_0;
++
++ /* 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(ap, adev);
++ it821x_program(ap, adev, itdev->pio[unit]);
++}
++
++/**
++ * it821x_passthru_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Set up the DMA modes. The actions taken depend heavily on the mode
++ * to use. If UDMA is used as is hopefully the usual case then the
++ * timing register is private and we need only consider the clock. If
++ * we are using MWDMA then we have to manage the setting ourself as
++ * we switch devices and mode.
++ */
++
++static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
++ static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
++ static const u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
++ static const u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct it821x_dev *itdev = ap->private_data;
++ int channel = ap->port_no;
++ int unit = adev->devno;
++ u8 conf;
++
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ int mode_wanted = adev->dma_mode - XFER_UDMA_0;
++
++ 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(pdev, 0x50, &conf);
++ if (itdev->timing10)
++ conf &= channel ? 0x9F: 0xE7;
++ else
++ conf &= ~ (1 << (3 + 2 * channel + unit));
++ pci_write_config_byte(pdev, 0x50, conf);
++ it821x_clock_strategy(ap, adev);
++ it821x_program_udma(ap, adev, itdev->udma[unit]);
++ } else {
++ int mode_wanted = adev->dma_mode - XFER_MW_DMA_0;
++
++ 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(pdev, 0x50, &conf);
++ if (itdev->timing10)
++ conf |= channel ? 0x60: 0x18;
++ else
++ conf |= 1 << (3 + 2 * channel + unit);
++ pci_write_config_byte(pdev, 0x50, conf);
++ it821x_clock_strategy(ap, adev);
++ }
++}
++
++/**
++ * it821x_passthru_dma_start - DMA start callback
++ * @qc: Command in progress
++ *
++ * Usually drivers set the DMA timing at the point the set_dmamode call
++ * is made. IT821x however requires we load new timings on the
++ * transitions in some cases.
++ */
++
++static void it821x_passthru_bmdma_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct it821x_dev *itdev = ap->private_data;
++ int unit = adev->devno;
++
++ if (itdev->mwdma[unit] != MWDMA_OFF)
++ it821x_program(ap, adev, itdev->mwdma[unit]);
++ else if (itdev->udma[unit] != UDMA_OFF && itdev->timing10)
++ it821x_program_udma(ap, adev, itdev->udma[unit]);
++ ata_bmdma_start(qc);
++}
++
++/**
++ * it821x_passthru_dma_stop - DMA stop callback
++ * @qc: ATA command
++ *
++ * We loaded new timings in dma_start, as a result we need to restore
++ * the PIO timings in dma_stop so that the next command issue gets the
++ * right clock values.
++ */
++
++static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct it821x_dev *itdev = ap->private_data;
++ int unit = adev->devno;
++
++ ata_bmdma_stop(qc);
++ if (itdev->mwdma[unit] != MWDMA_OFF)
++ it821x_program(ap, adev, itdev->pio[unit]);
++}
++
++
++/**
++ * it821x_passthru_dev_select - Select master/slave
++ * @ap: ATA port
++ * @device: Device number (not pointer)
++ *
++ * Device selection hook. If neccessary perform clock switching
++ */
++
++static void it821x_passthru_dev_select(struct ata_port *ap,
++ unsigned int device)
++{
++ struct it821x_dev *itdev = ap->private_data;
++ if (itdev && device != itdev->last_device) {
++ struct ata_device *adev = &ap->device[device];
++ it821x_program(ap, adev, itdev->pio[adev->devno]);
++ itdev->last_device = device;
++ }
++ ata_std_dev_select(ap, device);
++}
++
++/**
++ * it821x_smart_qc_issue_prot - wrap qc issue prot
++ * @qc: command
++ *
++ * Wrap the command issue sequence for the IT821x. We need to
++ * perform out own device selection timing loads before the
++ * usual happenings kick off
++ */
++
++static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ switch(qc->tf.command)
++ {
++ /* Commands the firmware supports */
++ case ATA_CMD_READ:
++ case ATA_CMD_READ_EXT:
++ case ATA_CMD_WRITE:
++ case ATA_CMD_WRITE_EXT:
++ case ATA_CMD_PIO_READ:
++ case ATA_CMD_PIO_READ_EXT:
++ case ATA_CMD_PIO_WRITE:
++ case ATA_CMD_PIO_WRITE_EXT:
++ case ATA_CMD_READ_MULTI:
++ case ATA_CMD_READ_MULTI_EXT:
++ case ATA_CMD_WRITE_MULTI:
++ case ATA_CMD_WRITE_MULTI_EXT:
++ case ATA_CMD_ID_ATA:
++ /* Arguably should just no-op this one */
++ case ATA_CMD_SET_FEATURES:
++ return ata_qc_issue_prot(qc);
++ }
++ printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
++ return AC_ERR_INVALID;
++}
++
++/**
++ * it821x_passthru_qc_issue_prot - wrap qc issue prot
++ * @qc: command
++ *
++ * Wrap the command issue sequence for the IT821x. We need to
++ * perform out own device selection timing loads before the
++ * usual happenings kick off
++ */
++
++static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ it821x_passthru_dev_select(qc->ap, qc->dev->devno);
++ return ata_qc_issue_prot(qc);
++}
++
++/**
++ * it821x_smart_set_mode - mode setting
++ * @ap: interface to set up
++ *
++ * Use a non standard set_mode function. We don't want to be tuned.
++ * The BIOS configured everything. Our job is not to fiddle. We
++ * read the dma enabled bits from the PCI configuration of the device
++ * and respect them.
++ */
++
++static void it821x_smart_set_mode(struct ata_port *ap)
++{
++ int dma_enabled = 0;
++ int i;
++
++ /* Bits 5 and 6 indicate if DMA is active on master/slave */
++ /* It is possible that BMDMA isn't allocated */
++ if (ap->ioaddr.bmdma_addr)
++ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ if (ata_dev_enabled(dev)) {
++ /* We don't really care */
++ dev->pio_mode = XFER_PIO_0;
++ dev->dma_mode = XFER_MW_DMA_0;
++ /* We do need the right mode information for DMA or PIO
++ and this comes from the current configuration flags */
++ if (dma_enabled & (1 << (5 + i))) {
++ dev->xfer_mode = XFER_MW_DMA_0;
++ dev->xfer_shift = ATA_SHIFT_MWDMA;
++ dev->flags &= ~ATA_DFLAG_PIO;
++ } else {
++ dev->xfer_mode = XFER_PIO_0;
++ dev->xfer_shift = ATA_SHIFT_PIO;
++ dev->flags |= ATA_DFLAG_PIO;
++ }
++ }
++ }
++}
++
++/**
++ * it821x_dev_config - Called each device identify
++ * @ap: ATA port
++ * @adev: Device that has just been identified
++ *
++ * Perform the initial setup needed for each device that is chip
++ * special. In our case we need to lock the sector count to avoid
++ * blowing the brains out of the firmware with large LBA48 requests
++ *
++ * FIXME: When FUA appears we need to block FUA too. And SMART and
++ * basically we need to filter commands for this chip.
++ */
++
++static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned char model_num[40];
++ char *s;
++ unsigned int len;
++
++ /* This block ought to be a library routine as it is in several
++ drivers now */
++
++ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS,
++ sizeof(model_num));
++ s = &model_num[0];
++ len = strnlen(s, sizeof(model_num));
++
++ /* ATAPI specifies that empty space is blank-filled; remove blanks */
++ while ((len > 0) && (s[len - 1] == ' ')) {
++ len--;
++ s[len] = 0;
++ }
++
++ if (adev->max_sectors > 255)
++ adev->max_sectors = 255;
++
++ if (strstr(model_num, "Integrated Technology Express")) {
++ /* RAID mode */
++ printk(KERN_INFO "IT821x %sRAID%d volume",
++ adev->id[147]?"Bootable ":"",
++ adev->id[129]);
++ if (adev->id[129] != 1)
++ printk("(%dK stripe)", adev->id[146]);
++ printk(".\n");
++ }
++}
++
++
++/**
++ * it821x_check_atapi_dma - ATAPI DMA handler
++ * @qc: Command we are about to issue
++ *
++ * Decide if this ATAPI command can be issued by DMA on this
++ * controller. Return 0 if it can be.
++ */
++
++static int it821x_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct it821x_dev *itdev = ap->private_data;
++
++ /* No ATAPI DMA in smart mode */
++ if (itdev->smart)
++ return -EOPNOTSUPP;
++ /* No ATAPI DMA on rev 10 */
++ if (itdev->timing10)
++ return -EOPNOTSUPP;
++ /* Cool */
++ return 0;
++}
++
++
++/**
++ * it821x_port_start - port setup
++ * @ap: ATA port being set up
++ *
++ * The it821x needs to maintain private data structures and also to
++ * use the standard PCI interface which lacks support for this
++ * functionality. We instead set up the private data on the port
++ * start hook, and tear it down on port stop
++ */
++
++static int it821x_port_start(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct it821x_dev *itdev;
++ u8 conf;
++
++ int ret = ata_port_start(ap);
++ if (ret < 0)
++ return ret;
++
++ ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
++ if (ap->private_data == NULL) {
++ ata_port_stop(ap);
++ return -ENOMEM;
++ }
++
++ itdev = ap->private_data;
++ memset(itdev, 0, sizeof(struct it821x_dev));
++
++ pci_read_config_byte(pdev, 0x50, &conf);
++
++ if (conf & 1) {
++ itdev->smart = 1;
++ /* Long I/O's although allowed in LBA48 space cause the
++ onboard firmware to enter the twighlight zone */
++ /* No ATAPI DMA in this mode either */
++ }
++ /* Pull the current clocks from 0x50 */
++ if (conf & (1 << (1 + ap->port_no)))
++ itdev->clock_mode = ATA_50;
++ else
++ itdev->clock_mode = ATA_66;
++
++ itdev->want[0][1] = ATA_ANY;
++ itdev->want[1][1] = ATA_ANY;
++ itdev->last_device = -1;
++
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &conf);
++ if (conf == 0x10) {
++ itdev->timing10 = 1;
++ /* Need to disable ATAPI DMA for this case */
++ if (!itdev->smart)
++ printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n");
++ }
++
++ return 0;
++}
++
++/**
++ * it821x_port_stop - port shutdown
++ * @ap: ATA port being removed
++ *
++ * Release the private objects we added in it821x_port_start
++ */
++
++static void it821x_port_stop(struct ata_port *ap) {
++ kfree(ap->private_data);
++ ap->private_data = NULL; /* We want an OOPS if we reuse this
++ too late! */
++ ata_port_stop(ap);
++}
++
++static struct scsi_host_template it821x_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ /* 255 sectors to begin with. This is locked in smart mode but not
++ in pass through */
++ .max_sectors = 255,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations it821x_smart_port_ops = {
++ .set_mode = it821x_smart_set_mode,
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .mode_filter = ata_pci_default_filter,
++
++ .check_status = ata_check_status,
++ .check_atapi_dma= it821x_check_atapi_dma,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .dev_config = it821x_dev_config,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = it821x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = it821x_smart_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = it821x_port_start,
++ .port_stop = it821x_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations it821x_passthru_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = it821x_passthru_set_piomode,
++ .set_dmamode = it821x_passthru_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .check_atapi_dma= it821x_check_atapi_dma,
++ .dev_select = it821x_passthru_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = it821x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = it821x_passthru_bmdma_start,
++ .bmdma_stop = it821x_passthru_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = it821x_passthru_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_clear = ata_bmdma_irq_clear,
++ .irq_handler = ata_interrupt,
++
++ .port_start = it821x_port_start,
++ .port_stop = it821x_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static void __devinit it821x_disable_raid(struct pci_dev *pdev)
++{
++ /* Reset local CPU, and set BIOS not ready */
++ pci_write_config_byte(pdev, 0x5E, 0x01);
++
++ /* Set to bypass mode, and reset PCI bus */
++ pci_write_config_byte(pdev, 0x50, 0x00);
++ pci_write_config_word(pdev, PCI_COMMAND,
++ PCI_COMMAND_PARITY | PCI_COMMAND_IO |
++ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
++ pci_write_config_word(pdev, 0x40, 0xA0F3);
++
++ pci_write_config_dword(pdev,0x4C, 0x02040204);
++ pci_write_config_byte(pdev, 0x42, 0x36);
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
++}
++
++
++static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ u8 conf;
++
++ static struct ata_port_info info_smart = {
++ .sht = &it821x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &it821x_smart_port_ops
++ };
++ static struct ata_port_info info_passthru = {
++ .sht = &it821x_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &it821x_passthru_port_ops
++ };
++ static struct ata_port_info *port_info[2];
++
++ static char *mode[2] = { "pass through", "smart" };
++
++ /* Force the card into bypass mode if so requested */
++ if (it8212_noraid) {
++ printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n");
++ it821x_disable_raid(pdev);
++ }
++ pci_read_config_byte(pdev, 0x50, &conf);
++ conf &= 1;
++
++ printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]);
++ if (conf == 0)
++ port_info[0] = port_info[1] = &info_passthru;
++ else
++ port_info[0] = port_info[1] = &info_smart;
++
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id it821x[] = {
++ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
++ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
++
++ { },
++};
++
++static struct pci_driver it821x_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = it821x,
++ .probe = it821x_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init it821x_init(void)
++{
++ return pci_register_driver(&it821x_pci_driver);
++}
++
++static void __exit it821x_exit(void)
++{
++ pci_unregister_driver(&it821x_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, it821x);
++MODULE_VERSION(DRV_VERSION);
++
++
++module_param_named(noraid, it8212_noraid, int, S_IRUGO);
++MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
++
++module_init(it821x_init);
++module_exit(it821x_exit);
+diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
+new file mode 100644
+index 0000000..52a2bdf
+--- /dev/null
++++ b/drivers/ata/pata_jmicron.c
+@@ -0,0 +1,266 @@
++/*
++ * pata_jmicron.c - JMicron ATA driver for non AHCI mode. This drives the
++ * PATA port of the controller. The SATA ports are
++ * driven by AHCI in the usual configuration although
++ * this driver can handle other setups if we need it.
++ *
++ * (c) 2006 Red Hat <alan at redhat.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_jmicron"
++#define DRV_VERSION "0.1.2"
++
++typedef enum {
++ PORT_PATA0 = 0,
++ PORT_PATA1 = 1,
++ PORT_SATA = 2,
++} port_type;
++
++/**
++ * jmicron_pre_reset - check for 40/80 pin
++ * @ap: Port
++ *
++ * Perform the PATA port setup we need.
++
++ * On the Jmicron 361/363 there is a single PATA port that can be mapped
++ * either as primary or secondary (or neither). We don't do any policy
++ * and setup here. We assume that has been done by init_one and the
++ * BIOS.
++ */
++
++static int jmicron_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 control;
++ u32 control5;
++ int port_mask = 1<< (4 * ap->port_no);
++ int port = ap->port_no;
++ port_type port_map[2];
++
++ /* Check if our port is enabled */
++ pci_read_config_dword(pdev, 0x40, &control);
++ if ((control & port_mask) == 0)
++ return -ENOENT;
++
++ /* There are two basic mappings. One has the two SATA ports merged
++ as master/slave and the secondary as PATA, the other has only the
++ SATA port mapped */
++ if (control & (1 << 23)) {
++ port_map[0] = PORT_SATA;
++ port_map[1] = PORT_PATA0;
++ } else {
++ port_map[0] = PORT_SATA;
++ port_map[1] = PORT_SATA;
++ }
++
++ /* The 365/366 may have this bit set to map the second PATA port
++ as the internal primary channel */
++ pci_read_config_dword(pdev, 0x80, &control5);
++ if (control5 & (1<<24))
++ port_map[0] = PORT_PATA1;
++
++ /* The two ports may then be logically swapped by the firmware */
++ if (control & (1 << 22))
++ port = port ^ 1;
++
++ /*
++ * Now we know which physical port we are talking about we can
++ * actually do our cable checking etc. Thankfully we don't need
++ * to do the plumbing for other cases.
++ */
++ switch (port_map[port])
++ {
++ case PORT_PATA0:
++ if (control & (1 << 5))
++ return 0;
++ if (control & (1 << 3)) /* 40/80 pin primary */
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++ break;
++ case PORT_PATA1:
++ /* Bit 21 is set if the port is enabled */
++ if ((control5 & (1 << 21)) == 0)
++ return 0;
++ if (control5 & (1 << 19)) /* 40/80 pin secondary */
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++ break;
++ case PORT_SATA:
++ ap->cbl = ATA_CBL_SATA;
++ break;
++ }
++ return ata_std_prereset(ap);
++}
++
++/**
++ * jmicron_error_handler - Setup and error handler
++ * @ap: Port to handle
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void jmicron_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/* No PIO or DMA methods needed for this device */
++
++static struct scsi_host_template jmicron_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ /* Special handling needed if you have sector or LBA48 limits */
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ /* Use standard CHS mapping rules */
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations jmicron_ops = {
++ .port_disable = ata_port_disable,
++
++ /* Task file is PCI ATA format, use helpers */
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = jmicron_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ /* BMDMA handling is PCI ATA format, use helpers */
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ /* IRQ-related hooks */
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ /* Generic PATA PCI ATA helpers */
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++
++/**
++ * jmicron_init_one - Register Jmicron ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in jmicron_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &jmicron_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++
++ .port_ops = &jmicron_ops,
++ };
++ struct ata_port_info *port_info[2] = { &info, &info };
++
++ u32 reg;
++
++ if (id->driver_data != 368) {
++ /* Put the controller into AHCI mode in case the AHCI driver
++ has not yet been loaded. This can be done with either
++ function present */
++
++ /* FIXME: We may want a way to override this in future */
++ pci_write_config_byte(pdev, 0x41, 0xa1);
++ }
++
++ /* PATA controller is fn 1, AHCI is fn 0 */
++ if (PCI_FUNC(pdev->devfn) != 1)
++ return -ENODEV;
++
++ if ( id->driver_data == 365 || id->driver_data == 366) {
++ /* The 365/66 have two PATA channels, redirect the second */
++ pci_read_config_dword(pdev, 0x80, ®);
++ reg |= (1 << 24); /* IDE1 to PATA IDE secondary */
++ pci_write_config_dword(pdev, 0x80, reg);
++ }
++
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id jmicron_pci_tbl[] = {
++ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
++ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
++ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
++ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
++ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
++
++ { } /* terminate list */
++};
++
++static struct pci_driver jmicron_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = jmicron_pci_tbl,
++ .probe = jmicron_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init jmicron_init(void)
++{
++ return pci_register_driver(&jmicron_pci_driver);
++}
++
++static void __exit jmicron_exit(void)
++{
++ pci_unregister_driver(&jmicron_pci_driver);
++}
++
++module_init(jmicron_init);
++module_exit(jmicron_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for Jmicron PATA ports");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
+new file mode 100644
+index 0000000..10231ef
+--- /dev/null
++++ b/drivers/ata/pata_legacy.c
+@@ -0,0 +1,949 @@
++/*
++ * pata-legacy.c - Legacy port PATA/SATA controller driver.
++ * Copyright 2005/2006 Red Hat <alan at redhat.com>, 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, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * An ATA driver for the legacy ATA ports.
++ *
++ * Data Sources:
++ * Opti 82C465/82C611 support: Data sheets at opti-inc.com
++ * HT6560 series:
++ * Promise 20230/20620:
++ * http://www.ryston.cz/petr/vlb/pdc20230b.html
++ * http://www.ryston.cz/petr/vlb/pdc20230c.html
++ * http://www.ryston.cz/petr/vlb/pdc20630.html
++ *
++ * Unsupported but docs exist:
++ * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
++ * Winbond W83759A
++ *
++ * This driver handles legacy (that is "ISA/VLB side") IDE ports found
++ * on PC class systems. There are three hybrid devices that are exceptions
++ * The Cyrix 5510/5520 where a pre SFF ATA device is on the bridge and
++ * the MPIIX where the tuning is PCI side but the IDE is "ISA side".
++ *
++ * Specific support is included for the ht6560a/ht6560b/opti82c611a/
++ * opti82c465mv/promise 20230c/20630
++ *
++ * Use the autospeed and pio_mask options with:
++ * Appian ADI/2 aka CLPD7220 or AIC25VL01.
++ * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with
++ * Goldstar GM82C711, PIC-1288A-125, UMC 82C871F, Winbond W83759,
++ * Winbond W83759A, Promise PDC20230-B
++ *
++ * For now use autospeed and pio_mask as above with the W83759A. This may
++ * change.
++ *
++ * TODO
++ * Merge existing pata_qdi driver
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/ata.h>
++#include <linux/libata.h>
++#include <linux/platform_device.h>
++
++#define DRV_NAME "pata_legacy"
++#define DRV_VERSION "0.5.3"
++
++#define NR_HOST 6
++
++static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
++static int legacy_irq[NR_HOST] = { 15, 14, 11, 10, 8, 12 };
++
++struct legacy_data {
++ unsigned long timing;
++ u8 clock[2];
++ u8 last;
++ int fast;
++ struct platform_device *platform_dev;
++
++};
++
++static struct legacy_data legacy_data[NR_HOST];
++static struct ata_host *legacy_host[NR_HOST];
++static int nr_legacy_host;
++
++
++static int probe_all; /* Set to check all ISA port ranges */
++static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */
++static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */
++static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */
++static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */
++static int autospeed; /* Chip present which snoops speed changes */
++static int pio_mask = 0x1F; /* PIO range for autospeed devices */
++
++/**
++ * legacy_set_mode - mode setting
++ * @ap: IDE interface
++ *
++ * Use a non standard set_mode function. We don't want to be tuned.
++ *
++ * The BIOS configured everything. Our job is not to fiddle. Just use
++ * whatever PIO the hardware is using and leave it at that. When we
++ * get some kind of nice user driven API for control then we can
++ * expand on this as per hdparm in the base kernel.
++ */
++
++static void legacy_set_mode(struct ata_port *ap)
++{
++ int i;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ if (ata_dev_enabled(dev)) {
++ dev->pio_mode = XFER_PIO_0;
++ dev->xfer_mode = XFER_PIO_0;
++ dev->xfer_shift = ATA_SHIFT_PIO;
++ dev->flags |= ATA_DFLAG_PIO;
++ }
++ }
++}
++
++static struct scsi_host_template legacy_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++/*
++ * These ops are used if the user indicates the hardware
++ * snoops the commands to decide on the mode and handles the
++ * mode selection "magically" itself. Several legacy controllers
++ * do this. The mode range can be set if it is not 0x1F by setting
++ * pio_mask as well.
++ */
++
++static struct ata_port_operations simple_port_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer_noirq,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations legacy_port_ops = {
++ .set_mode = legacy_set_mode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer_noirq,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Promise 20230C and 20620 support
++ *
++ * This controller supports PIO0 to PIO2. We set PIO timings conservatively to
++ * allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to
++ * controller and PIO'd to the host and not supported.
++ */
++
++static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ int tries = 5;
++ int pio = adev->pio_mode - XFER_PIO_0;
++ u8 rt;
++ unsigned long flags;
++
++ /* Safe as UP only. Force I/Os to occur together */
++
++ local_irq_save(flags);
++
++ /* Unlock the control interface */
++ do
++ {
++ inb(0x1F5);
++ outb(inb(0x1F2) | 0x80, 0x1F2);
++ inb(0x1F2);
++ inb(0x3F6);
++ inb(0x3F6);
++ inb(0x1F2);
++ inb(0x1F2);
++ }
++ while((inb(0x1F2) & 0x80) && --tries);
++
++ local_irq_restore(flags);
++
++ outb(inb(0x1F4) & 0x07, 0x1F4);
++
++ rt = inb(0x1F3);
++ rt &= 0x07 << (3 * adev->devno);
++ if (pio)
++ rt |= (1 + 3 * pio) << (3 * adev->devno);
++
++ udelay(100);
++ outb(inb(0x1F2) | 0x01, 0x1F2);
++ udelay(100);
++ inb(0x1F5);
++
++}
++
++static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
++{
++ struct ata_port *ap = adev->ap;
++ int slop = buflen & 3;
++ unsigned long flags;
++
++ if (ata_id_has_dword_io(adev->id)) {
++ local_irq_save(flags);
++
++ /* Perform the 32bit I/O synchronization sequence */
++ inb(ap->ioaddr.nsect_addr);
++ inb(ap->ioaddr.nsect_addr);
++ inb(ap->ioaddr.nsect_addr);
++
++ /* Now the data */
++
++ if (write_data)
++ outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
++ else
++ insl(ap->ioaddr.data_addr, buf, buflen >> 2);
++
++ if (unlikely(slop)) {
++ u32 pad;
++ if (write_data) {
++ memcpy(&pad, buf + buflen - slop, slop);
++ outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
++ } else {
++ pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
++ memcpy(buf + buflen - slop, &pad, slop);
++ }
++ }
++ local_irq_restore(flags);
++ }
++ else
++ ata_pio_data_xfer_noirq(adev, buf, buflen, write_data);
++}
++
++static struct ata_port_operations pdc20230_port_ops = {
++ .set_piomode = pdc20230_set_piomode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = pdc_data_xfer_vlb,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Holtek 6560A support
++ *
++ * This controller supports PIO0 to PIO2 (no IORDY even though higher timings
++ * can be loaded).
++ */
++
++static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ u8 active, recover;
++ struct ata_timing t;
++
++ /* Get the timing data in cycles. For now play safe at 50Mhz */
++ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
++
++ active = FIT(t.active, 2, 15);
++ recover = FIT(t.recover, 4, 15);
++
++ inb(0x3E6);
++ inb(0x3E6);
++ inb(0x3E6);
++ inb(0x3E6);
++
++ outb(recover << 4 | active, ap->ioaddr.device_addr);
++ inb(ap->ioaddr.status_addr);
++}
++
++static struct ata_port_operations ht6560a_port_ops = {
++ .set_piomode = ht6560a_set_piomode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Holtek 6560B support
++ *
++ * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting
++ * unless we see an ATAPI device in which case we force it off.
++ *
++ * FIXME: need to implement 2nd channel support.
++ */
++
++static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ u8 active, recover;
++ struct ata_timing t;
++
++ /* Get the timing data in cycles. For now play safe at 50Mhz */
++ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
++
++ active = FIT(t.active, 2, 15);
++ recover = FIT(t.recover, 2, 16);
++ recover &= 0x15;
++
++ inb(0x3E6);
++ inb(0x3E6);
++ inb(0x3E6);
++ inb(0x3E6);
++
++ outb(recover << 4 | active, ap->ioaddr.device_addr);
++
++ if (adev->class != ATA_DEV_ATA) {
++ u8 rconf = inb(0x3E6);
++ if (rconf & 0x24) {
++ rconf &= ~ 0x24;
++ outb(rconf, 0x3E6);
++ }
++ }
++ inb(ap->ioaddr.status_addr);
++}
++
++static struct ata_port_operations ht6560b_port_ops = {
++ .set_piomode = ht6560b_set_piomode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Opti core chipset helpers
++ */
++
++/**
++ * opti_syscfg - read OPTI chipset configuration
++ * @reg: Configuration register to read
++ *
++ * Returns the value of an OPTI system board configuration register.
++ */
++
++static u8 opti_syscfg(u8 reg)
++{
++ unsigned long flags;
++ u8 r;
++
++ /* Uniprocessor chipset and must force cycles adjancent */
++ local_irq_save(flags);
++ outb(reg, 0x22);
++ r = inb(0x24);
++ local_irq_restore(flags);
++ return r;
++}
++
++/*
++ * Opti 82C611A
++ *
++ * This controller supports PIO0 to PIO3.
++ */
++
++static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ u8 active, recover, setup;
++ struct ata_timing t;
++ struct ata_device *pair = ata_dev_pair(adev);
++ int clock;
++ int khz[4] = { 50000, 40000, 33000, 25000 };
++ u8 rc;
++
++ /* Enter configuration mode */
++ inw(ap->ioaddr.error_addr);
++ inw(ap->ioaddr.error_addr);
++ outb(3, ap->ioaddr.nsect_addr);
++
++ /* Read VLB clock strapping */
++ clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03];
++
++ /* Get the timing data in cycles */
++ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
++
++ /* Setup timing is shared */
++ if (pair) {
++ struct ata_timing tp;
++ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);
++
++ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
++ }
++
++ active = FIT(t.active, 2, 17) - 2;
++ recover = FIT(t.recover, 1, 16) - 1;
++ setup = FIT(t.setup, 1, 4) - 1;
++
++ /* Select the right timing bank for write timing */
++ rc = inb(ap->ioaddr.lbal_addr);
++ rc &= 0x7F;
++ rc |= (adev->devno << 7);
++ outb(rc, ap->ioaddr.lbal_addr);
++
++ /* Write the timings */
++ outb(active << 4 | recover, ap->ioaddr.error_addr);
++
++ /* Select the right bank for read timings, also
++ load the shared timings for address */
++ rc = inb(ap->ioaddr.device_addr);
++ rc &= 0xC0;
++ rc |= adev->devno; /* Index select */
++ rc |= (setup << 4) | 0x04;
++ outb(rc, ap->ioaddr.device_addr);
++
++ /* Load the read timings */
++ outb(active << 4 | recover, ap->ioaddr.data_addr);
++
++ /* Ensure the timing register mode is right */
++ rc = inb (ap->ioaddr.lbal_addr);
++ rc &= 0x73;
++ rc |= 0x84;
++ outb(rc, ap->ioaddr.lbal_addr);
++
++ /* Exit command mode */
++ outb(0x83, ap->ioaddr.nsect_addr);
++}
++
++
++static struct ata_port_operations opti82c611a_port_ops = {
++ .set_piomode = opti82c611a_set_piomode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/*
++ * Opti 82C465MV
++ *
++ * This controller supports PIO0 to PIO3. Unlike the 611A the MVB
++ * version is dual channel but doesn't have a lot of unique registers.
++ */
++
++static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ u8 active, recover, setup;
++ struct ata_timing t;
++ struct ata_device *pair = ata_dev_pair(adev);
++ int clock;
++ int khz[4] = { 50000, 40000, 33000, 25000 };
++ u8 rc;
++ u8 sysclk;
++
++ /* Get the clock */
++ sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
++
++ /* Enter configuration mode */
++ inw(ap->ioaddr.error_addr);
++ inw(ap->ioaddr.error_addr);
++ outb(3, ap->ioaddr.nsect_addr);
++
++ /* Read VLB clock strapping */
++ clock = 1000000000 / khz[sysclk];
++
++ /* Get the timing data in cycles */
++ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
++
++ /* Setup timing is shared */
++ if (pair) {
++ struct ata_timing tp;
++ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);
++
++ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
++ }
++
++ active = FIT(t.active, 2, 17) - 2;
++ recover = FIT(t.recover, 1, 16) - 1;
++ setup = FIT(t.setup, 1, 4) - 1;
++
++ /* Select the right timing bank for write timing */
++ rc = inb(ap->ioaddr.lbal_addr);
++ rc &= 0x7F;
++ rc |= (adev->devno << 7);
++ outb(rc, ap->ioaddr.lbal_addr);
++
++ /* Write the timings */
++ outb(active << 4 | recover, ap->ioaddr.error_addr);
++
++ /* Select the right bank for read timings, also
++ load the shared timings for address */
++ rc = inb(ap->ioaddr.device_addr);
++ rc &= 0xC0;
++ rc |= adev->devno; /* Index select */
++ rc |= (setup << 4) | 0x04;
++ outb(rc, ap->ioaddr.device_addr);
++
++ /* Load the read timings */
++ outb(active << 4 | recover, ap->ioaddr.data_addr);
++
++ /* Ensure the timing register mode is right */
++ rc = inb (ap->ioaddr.lbal_addr);
++ rc &= 0x73;
++ rc |= 0x84;
++ outb(rc, ap->ioaddr.lbal_addr);
++
++ /* Exit command mode */
++ outb(0x83, ap->ioaddr.nsect_addr);
++
++ /* We need to know this for quad device on the MVB */
++ ap->host->private_data = ap;
++}
++
++/**
++ * opt82c465mv_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings. The
++ * MVB has a single set of timing registers and these are shared
++ * across channels. As there are two registers we really ought to
++ * track the last two used values as a sort of register window. For
++ * now we just reload on a channel switch. On the single channel
++ * setup this condition never fires so we do nothing extra.
++ *
++ * FIXME: dual channel needs ->serialize support
++ */
++
++static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++
++ /* If timings are set and for the wrong channel (2nd test is
++ due to a libata shortcoming and will eventually go I hope) */
++ if (ap->host->private_data != ap->host
++ && ap->host->private_data != NULL)
++ opti82c46x_set_piomode(ap, adev);
++
++ return ata_qc_issue_prot(qc);
++}
++
++static struct ata_port_operations opti82c46x_port_ops = {
++ .set_piomode = opti82c46x_set_piomode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = opti82c46x_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++
++/**
++ * legacy_init_one - attach a legacy interface
++ * @port: port number
++ * @io: I/O port start
++ * @ctrl: control port
++ * @irq: interrupt line
++ *
++ * Register an ISA bus IDE interface. Such interfaces are PIO and we
++ * assume do not support IRQ sharing.
++ */
++
++static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
++{
++ struct legacy_data *ld = &legacy_data[nr_legacy_host];
++ struct ata_probe_ent ae;
++ struct platform_device *pdev;
++ int ret = -EBUSY;
++ struct ata_port_operations *ops = &legacy_port_ops;
++ int pio_modes = pio_mask;
++ u32 mask = (1 << port);
++
++ if (request_region(io, 8, "pata_legacy") == NULL)
++ return -EBUSY;
++ if (request_region(ctrl, 1, "pata_legacy") == NULL)
++ goto fail_io;
++
++ pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
++ if (pdev == NULL)
++ goto fail_dev;
++
++ if (ht6560a & mask) {
++ ops = &ht6560a_port_ops;
++ pio_modes = 0x07;
++ }
++ if (ht6560b & mask) {
++ ops = &ht6560b_port_ops;
++ pio_modes = 0x1F;
++ }
++ if (opti82c611a & mask) {
++ ops = &opti82c611a_port_ops;
++ pio_modes = 0x0F;
++ }
++ if (opti82c46x & mask) {
++ ops = &opti82c46x_port_ops;
++ pio_modes = 0x0F;
++ }
++
++ /* Probe for automatically detectable controllers */
++
++ if (io == 0x1F0 && ops == &legacy_port_ops) {
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ /* Probes */
++ inb(0x1F5);
++ outb(inb(0x1F2) | 0x80, 0x1F2);
++ inb(0x1F2);
++ inb(0x3F6);
++ inb(0x3F6);
++ inb(0x1F2);
++ inb(0x1F2);
++
++ if ((inb(0x1F2) & 0x80) == 0) {
++ /* PDC20230c or 20630 ? */
++ printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");
++ pio_modes = 0x07;
++ ops = &pdc20230_port_ops;
++ udelay(100);
++ inb(0x1F5);
++ } else {
++ outb(0x55, 0x1F2);
++ inb(0x1F2);
++ inb(0x1F2);
++ if (inb(0x1F2) == 0x00) {
++ printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n");
++ }
++ }
++ local_irq_restore(flags);
++ }
++
++
++ /* Chip does mode setting by command snooping */
++ if (ops == &legacy_port_ops && (autospeed & mask))
++ ops = &simple_port_ops;
++ memset(&ae, 0, sizeof(struct ata_probe_ent));
++ INIT_LIST_HEAD(&ae.node);
++ ae.dev = &pdev->dev;
++ ae.port_ops = ops;
++ ae.sht = &legacy_sht;
++ ae.n_ports = 1;
++ ae.pio_mask = pio_modes;
++ ae.irq = irq;
++ ae.irq_flags = 0;
++ ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
++ ae.port[0].cmd_addr = io;
++ ae.port[0].altstatus_addr = ctrl;
++ ae.port[0].ctl_addr = ctrl;
++ ata_std_ports(&ae.port[0]);
++ ae.private_data = ld;
++
++ ret = ata_device_add(&ae);
++ if (ret == 0) {
++ ret = -ENODEV;
++ goto fail;
++ }
++ legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
++ ld->platform_dev = pdev;
++ return 0;
++
++fail:
++ platform_device_unregister(pdev);
++fail_dev:
++ release_region(ctrl, 1);
++fail_io:
++ release_region(io, 8);
++ return ret;
++}
++
++/**
++ * legacy_check_special_cases - ATA special cases
++ * @p: PCI device to check
++ * @master: set this if we find an ATA master
++ * @master: set this if we find an ATA secondary
++ *
++ * A small number of vendors implemented early PCI ATA interfaces on bridge logic
++ * without the ATA interface being PCI visible. Where we have a matching PCI driver
++ * we must skip the relevant device here. If we don't know about it then the legacy
++ * driver is the right driver anyway.
++ */
++
++static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary)
++{
++ /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */
++ if (p->vendor == 0x1078 && p->device == 0x0000) {
++ *primary = *secondary = 1;
++ return;
++ }
++ /* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */
++ if (p->vendor == 0x1078 && p->device == 0x0002) {
++ *primary = *secondary = 1;
++ return;
++ }
++ /* Intel MPIIX - PIO ATA on non PCI side of bridge */
++ if (p->vendor == 0x8086 && p->device == 0x1234) {
++ u16 r;
++ pci_read_config_word(p, 0x6C, &r);
++ if (r & 0x8000) { /* ATA port enabled */
++ if (r & 0x4000)
++ *secondary = 1;
++ else
++ *primary = 1;
++ }
++ return;
++ }
++}
++
++
++/**
++ * legacy_init - attach legacy interfaces
++ *
++ * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects.
++ * Right now we do not scan the ide0 and ide1 address but should do so
++ * for non PCI systems or systems with no PCI IDE legacy mode devices.
++ * If you fix that note there are special cases to consider like VLB
++ * drivers and CS5510/20.
++ */
++
++static __init int legacy_init(void)
++{
++ int i;
++ int ct = 0;
++ int primary = 0;
++ int secondary = 0;
++ int last_port = NR_HOST;
++
++ struct pci_dev *p = NULL;
++
++ for_each_pci_dev(p) {
++ int r;
++ /* Check for any overlap of the system ATA mappings. Native mode controllers
++ stuck on these addresses or some devices in 'raid' mode won't be found by
++ the storage class test */
++ for (r = 0; r < 6; r++) {
++ if (pci_resource_start(p, r) == 0x1f0)
++ primary = 1;
++ if (pci_resource_start(p, r) == 0x170)
++ secondary = 1;
++ }
++ /* Check for special cases */
++ legacy_check_special_cases(p, &primary, &secondary);
++
++ /* If PCI bus is present then don't probe for tertiary legacy ports */
++ if (probe_all == 0)
++ last_port = 2;
++ }
++
++ /* If an OPTI 82C46X is present find out where the channels are */
++ if (opti82c46x) {
++ static const char *optis[4] = {
++ "3/463MV", "5MV",
++ "5MVA", "5MVB"
++ };
++ u8 chans = 1;
++ u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
++
++ opti82c46x = 3; /* Assume master and slave first */
++ printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]);
++ if (ctrl == 3)
++ chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
++ ctrl = opti_syscfg(0xAC);
++ /* Check enabled and this port is the 465MV port. On the
++ MVB we may have two channels */
++ if (ctrl & 8) {
++ if (ctrl & 4)
++ opti82c46x = 2; /* Slave */
++ else
++ opti82c46x = 1; /* Master */
++ if (chans == 2)
++ opti82c46x = 3; /* Master and Slave */
++ } /* Slave only */
++ else if (chans == 1)
++ opti82c46x = 1;
++ }
++
++ for (i = 0; i < last_port; i++) {
++ /* Skip primary if we have seen a PCI one */
++ if (i == 0 && primary == 1)
++ continue;
++ /* Skip secondary if we have seen a PCI one */
++ if (i == 1 && secondary == 1)
++ continue;
++ if (legacy_init_one(i, legacy_port[i],
++ legacy_port[i] + 0x0206,
++ legacy_irq[i]) == 0)
++ ct++;
++ }
++ if (ct != 0)
++ return 0;
++ return -ENODEV;
++}
++
++static __exit void legacy_exit(void)
++{
++ int i;
++
++ for (i = 0; i < nr_legacy_host; i++) {
++ struct legacy_data *ld = &legacy_data[i];
++ struct ata_port *ap =legacy_host[i]->ports[0];
++ unsigned long io = ap->ioaddr.cmd_addr;
++ unsigned long ctrl = ap->ioaddr.ctl_addr;
++ ata_host_remove(legacy_host[i]);
++ platform_device_unregister(ld->platform_dev);
++ if (ld->timing)
++ release_region(ld->timing, 2);
++ release_region(io, 8);
++ release_region(ctrl, 1);
++ }
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for legacy ATA");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_param(probe_all, int, 0);
++module_param(autospeed, int, 0);
++module_param(ht6560a, int, 0);
++module_param(ht6560b, int, 0);
++module_param(opti82c611a, int, 0);
++module_param(opti82c46x, int, 0);
++module_param(pio_mask, int, 0);
++
++module_init(legacy_init);
++module_exit(legacy_exit);
++
+diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
+new file mode 100644
+index 0000000..9dfe3e9
+--- /dev/null
++++ b/drivers/ata/pata_mpiix.c
+@@ -0,0 +1,307 @@
++/*
++ * pata_mpiix.c - Intel MPIIX PATA for new ATA layer
++ * (C) 2005-2006 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * The MPIIX is different enough to the PIIX4 and friends that we give it
++ * a separate driver. The old ide/pci code handles this by just not tuning
++ * MPIIX at all.
++ *
++ * The MPIIX also differs in another important way from the majority of PIIX
++ * devices. The chip is a bridge (pardon the pun) between the old world of
++ * ISA IDE and PCI IDE. Although the ATA timings are PCI configured the actual
++ * IDE controller is not decoded in PCI space and the chip does not claim to
++ * be IDE class PCI. This requires slightly non-standard probe logic compared
++ * with PCI IDE and also that we do not disable the device when our driver is
++ * unloaded (as it has many other functions).
++ *
++ * The driver conciously keeps this logic internally to avoid pushing quirky
++ * PATA history into the clean libata layer.
++ *
++ * Thinkpad specific note: If you boot an MPIIX using a thinkpad with a PCMCIA
++ * hard disk present this driver will not detect it. This is not a bug. In this
++ * configuration the secondary port of the MPIIX is disabled and the addresses
++ * are decoded by the PCMCIA bridge and therefore are for a generic IDE driver
++ * to operate.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_mpiix"
++#define DRV_VERSION "0.7.2"
++
++enum {
++ IDETIM = 0x6C, /* IDE control register */
++ IORDY = (1 << 1),
++ PPE = (1 << 2),
++ FTIM = (1 << 0),
++ ENABLED = (1 << 15),
++ SECONDARY = (1 << 14)
++};
++
++static int mpiix_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static const struct pci_bits mpiix_enable_bits[] = {
++ { 0x6D, 1, 0x80, 0x80 },
++ { 0x6F, 1, 0x80, 0x80 }
++ };
++
++ if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no]))
++ return -ENOENT;
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * mpiix_error_handler - probe reset
++ * @ap: ATA port
++ *
++ * Perform the ATA probe and bus reset sequence plus specific handling
++ * for this hardware. The MPIIX has the enable bits in a different place
++ * to PIIX4 and friends. As a pure PIO device it has no cable detect
++ */
++
++static void mpiix_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, mpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * mpiix_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup. The MPIIX allows us to program the
++ * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether
++ * prefetching or iordy are used.
++ *
++ * This would get very ugly because we can only program timing for one
++ * device at a time, the other gets PIO0. Fortunately libata calls
++ * our qc_issue_prot command before a command is issued so we can
++ * flip the timings back and forth to reduce the pain.
++ */
++
++static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ int control = 0;
++ int pio = adev->pio_mode - XFER_PIO_0;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u16 idetim;
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ pci_read_config_word(pdev, IDETIM, &idetim);
++ /* Mask the IORDY/TIME/PPE0 bank for this device */
++ if (adev->class == ATA_DEV_ATA)
++ control |= PPE; /* PPE enable for disk */
++ if (ata_pio_need_iordy(adev))
++ control |= IORDY; /* IORDY */
++ if (pio > 0)
++ control |= FTIM; /* This drive is on the fast timing bank */
++
++ /* Mask out timing and clear both TIME bank selects */
++ idetim &= 0xCCEE;
++ idetim &= ~(0x07 << (2 * adev->devno));
++ idetim |= (control << (2 * adev->devno));
++
++ idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
++ pci_write_config_word(pdev, IDETIM, idetim);
++
++ /* We use ap->private_data as a pointer to the device currently
++ loaded for timing */
++ ap->private_data = adev;
++}
++
++/**
++ * mpiix_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings if
++ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
++ * that, even if we get this wrong, cycles to the other device will
++ * be made PIO0.
++ */
++
++static unsigned int mpiix_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++
++ /* If modes have been configured and the channel data is not loaded
++ then load it. We have to check if pio_mode is set as the core code
++ does not set adev->pio_mode to XFER_PIO_0 while probing as would be
++ logical */
++
++ if (adev->pio_mode && adev != ap->private_data)
++ mpiix_set_piomode(ap, adev);
++
++ return ata_qc_issue_prot(qc);
++}
++
++static struct scsi_host_template mpiix_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations mpiix_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = mpiix_set_piomode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = mpiix_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = mpiix_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ /* Single threaded by the PCI probe logic */
++ static struct ata_probe_ent probe[2];
++ static int printed_version;
++ u16 idetim;
++ int enabled;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
++
++ /* MPIIX has many functions which can be turned on or off according
++ to other devices present. Make sure IDE is enabled before we try
++ and use it */
++
++ pci_read_config_word(dev, IDETIM, &idetim);
++ if (!(idetim & ENABLED))
++ return -ENODEV;
++
++ /* We do our own plumbing to avoid leaking special cases for whacko
++ ancient hardware into the core code. There are two issues to
++ worry about. #1 The chip is a bridge so if in legacy mode and
++ without BARs set fools the setup. #2 If you pci_disable_device
++ the MPIIX your box goes castors up */
++
++ INIT_LIST_HEAD(&probe[0].node);
++ probe[0].dev = pci_dev_to_dev(dev);
++ probe[0].port_ops = &mpiix_port_ops;
++ probe[0].sht = &mpiix_sht;
++ probe[0].pio_mask = 0x1F;
++ probe[0].irq = 14;
++ probe[0].irq_flags = SA_SHIRQ;
++ probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
++ probe[0].n_ports = 1;
++ probe[0].port[0].cmd_addr = 0x1F0;
++ probe[0].port[0].ctl_addr = 0x3F6;
++ probe[0].port[0].altstatus_addr = 0x3F6;
++
++ /* The secondary lurks at different addresses but is otherwise
++ the same beastie */
++
++ INIT_LIST_HEAD(&probe[1].node);
++ probe[1] = probe[0];
++ probe[1].irq = 15;
++ probe[1].port[0].cmd_addr = 0x170;
++ probe[1].port[0].ctl_addr = 0x376;
++ probe[1].port[0].altstatus_addr = 0x376;
++
++ /* Let libata fill in the port details */
++ ata_std_ports(&probe[0].port[0]);
++ ata_std_ports(&probe[1].port[0]);
++
++ /* Now add the port that is active */
++ enabled = (idetim & SECONDARY) ? 1 : 0;
++
++ if (ata_device_add(&probe[enabled]))
++ return 0;
++ return -ENODEV;
++}
++
++/**
++ * mpiix_remove_one - device unload
++ * @pdev: PCI device being removed
++ *
++ * Handle an unplug/unload event for a PCI device. Unload the
++ * PCI driver but do not use the default handler as we *MUST NOT*
++ * disable the device as it has other functions.
++ */
++
++static void __devexit mpiix_remove_one(struct pci_dev *pdev)
++{
++ struct device *dev = pci_dev_to_dev(pdev);
++ struct ata_host *host = dev_get_drvdata(dev);
++
++ ata_host_remove(host);
++ dev_set_drvdata(dev, NULL);
++}
++
++static const struct pci_device_id mpiix[] = {
++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
++
++ { },
++};
++
++static struct pci_driver mpiix_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = mpiix,
++ .probe = mpiix_init_one,
++ .remove = mpiix_remove_one
++};
++
++static int __init mpiix_init(void)
++{
++ return pci_register_driver(&mpiix_pci_driver);
++}
++
++static void __exit mpiix_exit(void)
++{
++ pci_unregister_driver(&mpiix_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, mpiix);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(mpiix_init);
++module_exit(mpiix_exit);
+diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
+new file mode 100644
+index 0000000..f5672de
+--- /dev/null
++++ b/drivers/ata/pata_netcell.c
+@@ -0,0 +1,175 @@
++/*
++ * pata_netcell.c - Netcell PATA driver
++ *
++ * (c) 2006 Red Hat <alan at redhat.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_netcell"
++#define DRV_VERSION "0.1.5"
++
++/**
++ * netcell_probe_init - check for 40/80 pin
++ * @ap: Port
++ *
++ * Cables are handled by the RAID controller. Report 80 pin.
++ */
++
++static int netcell_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * netcell_probe_reset - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void netcell_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/* No PIO or DMA methods needed for this device */
++
++static struct scsi_host_template netcell_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ /* Special handling needed if you have sector or LBA48 limits */
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ /* Use standard CHS mapping rules */
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations netcell_ops = {
++ .port_disable = ata_port_disable,
++
++ /* Task file is PCI ATA format, use helpers */
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = netcell_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ /* BMDMA handling is PCI ATA format, use helpers */
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ /* IRQ-related hooks */
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ /* Generic PATA PCI ATA helpers */
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++
++/**
++ * netcell_init_one - Register Netcell ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in netcell_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ static struct ata_port_info info = {
++ .sht = &netcell_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ /* Actually we don't really care about these as the
++ firmware deals with it */
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* UDMA 133 */
++ .port_ops = &netcell_ops,
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ /* Any chip specific setup/optimisation/messages here */
++ ata_pci_clear_simplex(pdev);
++
++ /* And let the library code do the work */
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id netcell_pci_tbl[] = {
++ { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver netcell_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = netcell_pci_tbl,
++ .probe = netcell_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init netcell_init(void)
++{
++ return pci_register_driver(&netcell_pci_driver);
++}
++
++static void __exit netcell_exit(void)
++{
++ pci_unregister_driver(&netcell_pci_driver);
++}
++
++module_init(netcell_init);
++module_exit(netcell_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for Netcell PATA RAID");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, netcell_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
+new file mode 100644
+index 0000000..2a3dbee
+--- /dev/null
++++ b/drivers/ata/pata_ns87410.c
+@@ -0,0 +1,232 @@
++/*
++ * pata_ns87410.c - National Semiconductor 87410 PATA for new ATA layer
++ * (C) 2006 Red Hat Inc
++ * Alan Cox <alan at 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, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_ns87410"
++#define DRV_VERSION "0.4.2"
++
++/**
++ * ns87410_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int ns87410_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static const struct pci_bits ns87410_enable_bits[] = {
++ { 0x43, 1, 0x08, 0x08 },
++ { 0x47, 1, 0x08, 0x08 }
++ };
++
++ if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
++ return -ENOENT;
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * ns87410_error_handler - probe reset
++ * @ap: ATA port
++ *
++ * Perform the ATA probe and bus reset sequence plus specific handling
++ * for this hardware. The MPIIX has the enable bits in a different place
++ * to PIIX4 and friends. As a pure PIO device it has no cable detect
++ */
++
++static void ns87410_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, ns87410_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * ns87410_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program timing data. This is kept per channel not per device,
++ * and only affects the data port.
++ */
++
++static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int port = 0x40 + 4 * ap->port_no;
++ u8 idetcr, idefr;
++ struct ata_timing at;
++
++ static const u8 activebits[15] = {
++ 0, 1, 2, 3, 4,
++ 5, 5, 6, 6, 6,
++ 6, 7, 7, 7, 7
++ };
++
++ static const u8 recoverbits[12] = {
++ 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7
++ };
++
++ pci_read_config_byte(pdev, port + 3, &idefr);
++
++ if (ata_pio_need_iordy(adev))
++ idefr |= 0x04; /* IORDY enable */
++ else
++ idefr &= ~0x04;
++
++ if (ata_timing_compute(adev, adev->pio_mode, &at, 30303, 1) < 0) {
++ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", adev->pio_mode);
++ return;
++ }
++
++ at.active = FIT(at.active, 2, 16) - 2;
++ at.setup = FIT(at.setup, 1, 4) - 1;
++ at.recover = FIT(at.recover, 1, 12) - 1;
++
++ idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active];
++
++ pci_write_config_byte(pdev, port, idetcr);
++ pci_write_config_byte(pdev, port + 3, idefr);
++ /* We use ap->private_data as a pointer to the device currently
++ loaded for timing */
++ ap->private_data = adev;
++}
++
++/**
++ * ns87410_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings if
++ * neccessary.
++ */
++
++static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++
++ /* If modes have been configured and the channel data is not loaded
++ then load it. We have to check if pio_mode is set as the core code
++ does not set adev->pio_mode to XFER_PIO_0 while probing as would be
++ logical */
++
++ if (adev->pio_mode && adev != ap->private_data)
++ ns87410_set_piomode(ap, adev);
++
++ return ata_qc_issue_prot(qc);
++}
++
++static struct scsi_host_template ns87410_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations ns87410_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = ns87410_set_piomode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ns87410_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ns87410_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &ns87410_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x0F,
++ .port_ops = &ns87410_port_ops
++ };
++ static struct ata_port_info *port_info[2] = {&info, &info};
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id ns87410[] = {
++ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), },
++
++ { },
++};
++
++static struct pci_driver ns87410_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = ns87410,
++ .probe = ns87410_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init ns87410_init(void)
++{
++ return pci_register_driver(&ns87410_pci_driver);
++}
++
++static void __exit ns87410_exit(void)
++{
++ pci_unregister_driver(&ns87410_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, ns87410);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ns87410_init);
++module_exit(ns87410_exit);
+diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
+new file mode 100644
+index 0000000..fc947df
+--- /dev/null
++++ b/drivers/ata/pata_oldpiix.c
+@@ -0,0 +1,336 @@
++/*
++ * pata_oldpiix.c - Intel PATA/SATA controllers
++ *
++ * (C) 2005 Red Hat <alan at redhat.com>
++ *
++ * Some parts based on ata_piix.c by Jeff Garzik and others.
++ *
++ * Early PIIX differs significantly from the later PIIX as it lacks
++ * SITRE and the slave timing registers. This means that you have to
++ * set timing per channel, or be clever. Libata tells us whenever it
++ * does drive selection and we use this to reload the timings.
++ *
++ * Because of these behaviour differences PIIX gets its own driver module.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_oldpiix"
++#define DRV_VERSION "0.5.2"
++
++/**
++ * oldpiix_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int oldpiix_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static const struct pci_bits oldpiix_enable_bits[] = {
++ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
++ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
++ };
++
++ if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
++ return -ENOENT;
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * oldpiix_pata_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ * @classes:
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void oldpiix_pata_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, oldpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * oldpiix_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set PIO mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio = adev->pio_mode - XFER_PIO_0;
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
++ u16 idetm_data;
++ int control = 0;
++
++ /*
++ * See Intel Document 298600-004 for the timing programing rules
++ * for PIIX/ICH. Note that the early PIIX does not have the slave
++ * timing port at 0x44.
++ */
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ if (pio > 2)
++ control |= 1; /* TIME1 enable */
++ if (ata_pio_need_iordy(adev))
++ control |= 2; /* IE IORDY */
++
++ /* Intel specifies that the PPE functionality is for disk only */
++ if (adev->class == ATA_DEV_ATA)
++ control |= 4; /* PPE enable */
++
++ pci_read_config_word(dev, idetm_port, &idetm_data);
++
++ /* Enable PPE, IE and TIME as appropriate. Clear the other
++ drive timing bits */
++ if (adev->devno == 0) {
++ idetm_data &= 0xCCE0;
++ idetm_data |= control;
++ } else {
++ idetm_data &= 0xCC0E;
++ idetm_data |= (control << 4);
++ }
++ idetm_data |= (timings[pio][0] << 12) |
++ (timings[pio][1] << 8);
++ pci_write_config_word(dev, idetm_port, idetm_data);
++
++ /* Track which port is configured */
++ ap->private_data = adev;
++}
++
++/**
++ * oldpiix_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ * @isich: True if the device is an ICH and has IOCFG registers
++ *
++ * Set MWDMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ u8 idetm_port = ap->port_no ? 0x42 : 0x40;
++ u16 idetm_data;
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
++
++ /*
++ * MWDMA is driven by the PIO timings. We must also enable
++ * IORDY unconditionally along with TIME1. PPE has already
++ * been set when the PIO timing was set.
++ */
++
++ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
++ unsigned int control;
++ const unsigned int needed_pio[3] = {
++ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
++ };
++ int pio = needed_pio[mwdma] - XFER_PIO_0;
++
++ pci_read_config_word(dev, idetm_port, &idetm_data);
++
++ control = 3; /* IORDY|TIME0 */
++ /* Intel specifies that the PPE functionality is for disk only */
++ if (adev->class == ATA_DEV_ATA)
++ control |= 4; /* PPE enable */
++
++ /* If the drive MWDMA is faster than it can do PIO then
++ we must force PIO into PIO0 */
++
++ if (adev->pio_mode < needed_pio[mwdma])
++ /* Enable DMA timing only */
++ control |= 8; /* PIO cycles in PIO0 */
++
++ /* Mask out the relevant control and timing bits we will load. Also
++ clear the other drive TIME register as a precaution */
++ if (adev->devno == 0) {
++ idetm_data &= 0xCCE0;
++ idetm_data |= control;
++ } else {
++ idetm_data &= 0xCC0E;
++ idetm_data |= (control << 4);
++ }
++ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
++ pci_write_config_word(dev, idetm_port, idetm_data);
++
++ /* Track which port is configured */
++ ap->private_data = adev;
++}
++
++/**
++ * oldpiix_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings if
++ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
++ * that, even if we get this wrong, cycles to the other device will
++ * be made PIO0.
++ */
++
++static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++
++ if (adev != ap->private_data) {
++ if (adev->dma_mode)
++ oldpiix_set_dmamode(ap, adev);
++ else if (adev->pio_mode)
++ oldpiix_set_piomode(ap, adev);
++ }
++ return ata_qc_issue_prot(qc);
++}
++
++
++static struct scsi_host_template oldpiix_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations oldpiix_pata_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = oldpiix_set_piomode,
++ .set_dmamode = oldpiix_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = oldpiix_pata_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = oldpiix_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++
++/**
++ * oldpiix_init_one - Register PIIX ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in oldpiix_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer. We probe for combined mode (sigh),
++ * and then hand over control to libata, for it to do the rest.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ static struct ata_port_info info = {
++ .sht = &oldpiix_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma1-2 */
++ .port_ops = &oldpiix_pata_ops,
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id oldpiix_pci_tbl[] = {
++ { PCI_VDEVICE(INTEL, 0x1230), },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver oldpiix_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = oldpiix_pci_tbl,
++ .probe = oldpiix_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init oldpiix_init(void)
++{
++ return pci_register_driver(&oldpiix_pci_driver);
++}
++
++static void __exit oldpiix_exit(void)
++{
++ pci_unregister_driver(&oldpiix_pci_driver);
++}
++
++module_init(oldpiix_init);
++module_exit(oldpiix_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for early PIIX series controllers");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, oldpiix_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
+new file mode 100644
+index 0000000..a7320ba
+--- /dev/null
++++ b/drivers/ata/pata_opti.c
+@@ -0,0 +1,290 @@
++/*
++ * pata_opti.c - ATI PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based on
++ * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002
++ *
++ * Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
++ *
++ * Authors:
++ * Jaromir Koutek <miri at punknet.cz>,
++ * Jan Harkes <jaharkes at cwi.nl>,
++ * Mark Lord <mlord at pobox.com>
++ * Some parts of code are from ali14xx.c and from rz1000.c.
++ *
++ * Also consulted the FreeBSD prototype driver by Kevin Day to try
++ * and resolve some confusions. Further documentation can be found in
++ * Ralf Brown's interrupt list
++ *
++ * If you have other variants of the Opti range (Viper/Vendetta) please
++ * try this driver with those PCI idents and report back. For the later
++ * chips see the pata_optidma driver
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_opti"
++#define DRV_VERSION "0.2.5"
++
++enum {
++ READ_REG = 0, /* index of Read cycle timing register */
++ WRITE_REG = 1, /* index of Write cycle timing register */
++ CNTRL_REG = 3, /* index of Control register */
++ STRAP_REG = 5, /* index of Strap register */
++ MISC_REG = 6 /* index of Miscellaneous register */
++};
++
++/**
++ * opti_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int opti_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static const struct pci_bits opti_enable_bits[] = {
++ { 0x45, 1, 0x80, 0x00 },
++ { 0x40, 1, 0x08, 0x00 }
++ };
++
++ if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * opti_probe_reset - probe reset
++ * @ap: ATA port
++ *
++ * Perform the ATA probe and bus reset sequence plus specific handling
++ * for this hardware. The Opti needs little handling - we have no UDMA66
++ * capability that needs cable detection. All we must do is check the port
++ * is enabled.
++ */
++
++static void opti_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, opti_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * opti_write_reg - control register setup
++ * @ap: ATA port
++ * @value: value
++ * @reg: control register number
++ *
++ * The Opti uses magic 'trapdoor' register accesses to do configuration
++ * rather than using PCI space as other controllers do. The double inw
++ * on the error register activates configuration mode. We can then write
++ * the control register
++ */
++
++static void opti_write_reg(struct ata_port *ap, u8 val, int reg)
++{
++ unsigned long regio = ap->ioaddr.cmd_addr;
++
++ /* These 3 unlock the control register access */
++ inw(regio + 1);
++ inw(regio + 1);
++ outb(3, regio + 2);
++
++ /* Do the I/O */
++ outb(val, regio + reg);
++
++ /* Relock */
++ outb(0x83, regio + 2);
++}
++
++#if 0
++/**
++ * opti_read_reg - control register read
++ * @ap: ATA port
++ * @reg: control register number
++ *
++ * The Opti uses magic 'trapdoor' register accesses to do configuration
++ * rather than using PCI space as other controllers do. The double inw
++ * on the error register activates configuration mode. We can then read
++ * the control register
++ */
++
++static u8 opti_read_reg(struct ata_port *ap, int reg)
++{
++ unsigned long regio = ap->ioaddr.cmd_addr;
++ u8 ret;
++ inw(regio + 1);
++ inw(regio + 1);
++ outb(3, regio + 2);
++ ret = inb(regio + reg);
++ outb(0x83, regio + 2);
++}
++#endif
++
++/**
++ * opti_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup. Timing numbers are taken from
++ * the FreeBSD driver then pre computed to keep the code clean. There
++ * are two tables depending on the hardware clock speed.
++ */
++
++static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct ata_device *pair = ata_dev_pair(adev);
++ int clock;
++ int pio = adev->pio_mode - XFER_PIO_0;
++ unsigned long regio = ap->ioaddr.cmd_addr;
++ u8 addr;
++
++ /* Address table precomputed with prefetch off and a DCLK of 2 */
++ static const u8 addr_timing[2][5] = {
++ { 0x30, 0x20, 0x20, 0x10, 0x10 },
++ { 0x20, 0x20, 0x10, 0x10, 0x10 }
++ };
++ static const u8 data_rec_timing[2][5] = {
++ { 0x6B, 0x56, 0x42, 0x32, 0x31 },
++ { 0x58, 0x44, 0x32, 0x22, 0x21 }
++ };
++
++ outb(0xff, regio + 5);
++ clock = inw(regio + 5) & 1;
++
++ /*
++ * As with many controllers the address setup time is shared
++ * and must suit both devices if present.
++ */
++
++ addr = addr_timing[clock][pio];
++ if (pair) {
++ /* Hardware constraint */
++ u8 pair_addr = addr_timing[clock][pair->pio_mode - XFER_PIO_0];
++ if (pair_addr > addr)
++ addr = pair_addr;
++ }
++
++ /* Commence primary programming sequence */
++ opti_write_reg(ap, adev->devno, MISC_REG);
++ opti_write_reg(ap, data_rec_timing[clock][pio], READ_REG);
++ opti_write_reg(ap, data_rec_timing[clock][pio], WRITE_REG);
++ opti_write_reg(ap, addr, MISC_REG);
++
++ /* Programming sequence complete, override strapping */
++ opti_write_reg(ap, 0x85, CNTRL_REG);
++}
++
++static struct scsi_host_template opti_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations opti_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = opti_set_piomode,
++/* .set_dmamode = opti_set_dmamode, */
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = opti_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &opti_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .port_ops = &opti_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++ static int printed_version;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
++
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id opti[] = {
++ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
++ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
++
++ { },
++};
++
++static struct pci_driver opti_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = opti,
++ .probe = opti_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init opti_init(void)
++{
++ return pci_register_driver(&opti_pci_driver);
++}
++
++static void __exit opti_exit(void)
++{
++ pci_unregister_driver(&opti_pci_driver);
++}
++
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Opti 621/621X");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, opti);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(opti_init);
++module_exit(opti_exit);
+diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
+new file mode 100644
+index 0000000..c6906b4
+--- /dev/null
++++ b/drivers/ata/pata_optidma.c
+@@ -0,0 +1,544 @@
++/*
++ * pata_optidma.c - Opti DMA PATA for new ATA layer
++ * (C) 2006 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * The Opti DMA controllers are related to the older PIO PCI controllers
++ * and indeed the VLB ones. The main differences are that the timing
++ * numbers are now based off PCI clocks not VLB and differ, and that
++ * MWDMA is supported.
++ *
++ * This driver should support Viper-N+, FireStar, FireStar Plus.
++ *
++ * These devices support virtual DMA for read (aka the CS5520). Later
++ * chips support UDMA33, but only if the rest of the board logic does,
++ * so you have to get this right. We don't support the virtual DMA
++ * but we do handle UDMA.
++ *
++ * Bits that are worth knowing
++ * Most control registers are shadowed into I/O registers
++ * 0x1F5 bit 0 tells you if the PCI/VLB clock is 33 or 25Mhz
++ * Virtual DMA registers *move* between rev 0x02 and rev 0x10
++ * UDMA requires a 66MHz FSB
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_optidma"
++#define DRV_VERSION "0.2.2"
++
++enum {
++ READ_REG = 0, /* index of Read cycle timing register */
++ WRITE_REG = 1, /* index of Write cycle timing register */
++ CNTRL_REG = 3, /* index of Control register */
++ STRAP_REG = 5, /* index of Strap register */
++ MISC_REG = 6 /* index of Miscellaneous register */
++};
++
++static int pci_clock; /* 0 = 33 1 = 25 */
++
++/**
++ * optidma_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int optidma_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static const struct pci_bits optidma_enable_bits = {
++ 0x40, 1, 0x08, 0x00
++ };
++
++ if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
++ return -ENOENT;
++
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * optidma_probe_reset - probe reset
++ * @ap: ATA port
++ *
++ * Perform the ATA probe and bus reset sequence plus specific handling
++ * for this hardware. The Opti needs little handling - we have no UDMA66
++ * capability that needs cable detection. All we must do is check the port
++ * is enabled.
++ */
++
++static void optidma_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, optidma_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * optidma_unlock - unlock control registers
++ * @ap: ATA port
++ *
++ * Unlock the control register block for this adapter. Registers must not
++ * be unlocked in a situation where libata might look at them.
++ */
++
++static void optidma_unlock(struct ata_port *ap)
++{
++ unsigned long regio = ap->ioaddr.cmd_addr;
++
++ /* These 3 unlock the control register access */
++ inw(regio + 1);
++ inw(regio + 1);
++ outb(3, regio + 2);
++}
++
++/**
++ * optidma_lock - issue temporary relock
++ * @ap: ATA port
++ *
++ * Re-lock the configuration register settings.
++ */
++
++static void optidma_lock(struct ata_port *ap)
++{
++ unsigned long regio = ap->ioaddr.cmd_addr;
++
++ /* Relock */
++ outb(0x83, regio + 2);
++}
++
++/**
++ * optidma_set_mode - set mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ * @mode: Mode to set
++ *
++ * Called to do the DMA or PIO mode setup. Timing numbers are all
++ * pre computed to keep the code clean. There are two tables depending
++ * on the hardware clock speed.
++ *
++ * WARNING: While we do this the IDE registers vanish. If we take an
++ * IRQ here we depend on the host set locking to avoid catastrophe.
++ */
++
++static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
++{
++ struct ata_device *pair = ata_dev_pair(adev);
++ int pio = adev->pio_mode - XFER_PIO_0;
++ int dma = adev->dma_mode - XFER_MW_DMA_0;
++ unsigned long regio = ap->ioaddr.cmd_addr;
++ u8 addr;
++
++ /* Address table precomputed with a DCLK of 2 */
++ static const u8 addr_timing[2][5] = {
++ { 0x30, 0x20, 0x20, 0x10, 0x10 },
++ { 0x20, 0x20, 0x10, 0x10, 0x10 }
++ };
++ static const u8 data_rec_timing[2][5] = {
++ { 0x59, 0x46, 0x30, 0x20, 0x20 },
++ { 0x46, 0x32, 0x20, 0x20, 0x10 }
++ };
++ static const u8 dma_data_rec_timing[2][3] = {
++ { 0x76, 0x20, 0x20 },
++ { 0x54, 0x20, 0x10 }
++ };
++
++ /* Switch from IDE to control mode */
++ optidma_unlock(ap);
++
++
++ /*
++ * As with many controllers the address setup time is shared
++ * and must suit both devices if present. FIXME: Check if we
++ * need to look at slowest of PIO/DMA mode of either device
++ */
++
++ if (mode >= XFER_MW_DMA_0)
++ addr = 0;
++ else
++ addr = addr_timing[pci_clock][pio];
++
++ if (pair) {
++ u8 pair_addr;
++ /* Hardware constraint */
++ if (pair->dma_mode)
++ pair_addr = 0;
++ else
++ pair_addr = addr_timing[pci_clock][pair->pio_mode - XFER_PIO_0];
++ if (pair_addr > addr)
++ addr = pair_addr;
++ }
++
++ /* Commence primary programming sequence */
++ /* First we load the device number into the timing select */
++ outb(adev->devno, regio + MISC_REG);
++ /* Now we load the data timings into read data/write data */
++ if (mode < XFER_MW_DMA_0) {
++ outb(data_rec_timing[pci_clock][pio], regio + READ_REG);
++ outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
++ } else if (mode < XFER_UDMA_0) {
++ outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
++ outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
++ }
++ /* Finally we load the address setup into the misc register */
++ outb(addr | adev->devno, regio + MISC_REG);
++
++ /* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */
++ outb(0x85, regio + CNTRL_REG);
++
++ /* Switch back to IDE mode */
++ optidma_lock(ap);
++
++ /* Note: at this point our programming is incomplete. We are
++ not supposed to program PCI 0x43 "things we hacked onto the chip"
++ until we've done both sets of PIO/DMA timings */
++}
++
++/**
++ * optiplus_set_mode - DMA setup for Firestar Plus
++ * @ap: ATA port
++ * @adev: device
++ * @mode: desired mode
++ *
++ * The Firestar plus has additional UDMA functionality for UDMA0-2 and
++ * requires we do some additional work. Because the base work we must do
++ * is mostly shared we wrap the Firestar setup functionality in this
++ * one
++ */
++
++static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 udcfg;
++ u8 udslave;
++ int dev2 = 2 * adev->devno;
++ int unit = 2 * ap->port_no + adev->devno;
++ int udma = mode - XFER_UDMA_0;
++
++ pci_read_config_byte(pdev, 0x44, &udcfg);
++ if (mode <= XFER_UDMA_0) {
++ udcfg &= ~(1 << unit);
++ optidma_set_mode(ap, adev, adev->dma_mode);
++ } else {
++ udcfg |= (1 << unit);
++ if (ap->port_no) {
++ pci_read_config_byte(pdev, 0x45, &udslave);
++ udslave &= ~(0x03 << dev2);
++ udslave |= (udma << dev2);
++ pci_write_config_byte(pdev, 0x45, udslave);
++ } else {
++ udcfg &= ~(0x30 << dev2);
++ udcfg |= (udma << dev2);
++ }
++ }
++ pci_write_config_byte(pdev, 0x44, udcfg);
++}
++
++/**
++ * optidma_set_pio_mode - PIO setup callback
++ * @ap: ATA port
++ * @adev: Device
++ *
++ * The libata core provides separate functions for handling PIO and
++ * DMA programming. The architecture of the Firestar makes it easier
++ * for us to have a common function so we provide wrappers
++ */
++
++static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
++{
++ optidma_set_mode(ap, adev, adev->pio_mode);
++}
++
++/**
++ * optidma_set_dma_mode - DMA setup callback
++ * @ap: ATA port
++ * @adev: Device
++ *
++ * The libata core provides separate functions for handling PIO and
++ * DMA programming. The architecture of the Firestar makes it easier
++ * for us to have a common function so we provide wrappers
++ */
++
++static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
++{
++ optidma_set_mode(ap, adev, adev->dma_mode);
++}
++
++/**
++ * optiplus_set_pio_mode - PIO setup callback
++ * @ap: ATA port
++ * @adev: Device
++ *
++ * The libata core provides separate functions for handling PIO and
++ * DMA programming. The architecture of the Firestar makes it easier
++ * for us to have a common function so we provide wrappers
++ */
++
++static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
++{
++ optiplus_set_mode(ap, adev, adev->pio_mode);
++}
++
++/**
++ * optiplus_set_dma_mode - DMA setup callback
++ * @ap: ATA port
++ * @adev: Device
++ *
++ * The libata core provides separate functions for handling PIO and
++ * DMA programming. The architecture of the Firestar makes it easier
++ * for us to have a common function so we provide wrappers
++ */
++
++static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
++{
++ optiplus_set_mode(ap, adev, adev->dma_mode);
++}
++
++/**
++ * optidma_make_bits - PCI setup helper
++ * @adev: ATA device
++ *
++ * Turn the ATA device setup into PCI configuration bits
++ * for register 0x43 and return the two bits needed.
++ */
++
++static u8 optidma_make_bits43(struct ata_device *adev)
++{
++ static const u8 bits43[5] = {
++ 0, 0, 0, 1, 2
++ };
++ if (!ata_dev_enabled(adev))
++ return 0;
++ if (adev->dma_mode)
++ return adev->dma_mode - XFER_MW_DMA_0;
++ return bits43[adev->pio_mode - XFER_PIO_0];
++}
++
++/**
++ * optidma_post_set_mode - finalize PCI setup
++ * @ap: port to set up
++ *
++ * Finalise the configuration by writing the nibble of extra bits
++ * of data into the chip.
++ */
++
++static void optidma_post_set_mode(struct ata_port *ap)
++{
++ u8 r;
++ int nybble = 4 * ap->port_no;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ pci_read_config_byte(pdev, 0x43, &r);
++
++ r &= (0x0F << nybble);
++ r |= (optidma_make_bits43(&ap->device[0]) +
++ (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
++
++ pci_write_config_byte(pdev, 0x43, r);
++}
++
++static struct scsi_host_template optidma_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations optidma_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = optidma_set_pio_mode,
++ .set_dmamode = optidma_set_dma_mode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .error_handler = optidma_error_handler,
++ .post_set_mode = optidma_post_set_mode,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations optiplus_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = optiplus_set_pio_mode,
++ .set_dmamode = optiplus_set_dma_mode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .error_handler = optidma_error_handler,
++ .post_set_mode = optidma_post_set_mode,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * optiplus_with_udma - Look for UDMA capable setup
++ * @pdev; ATA controller
++ */
++
++static int optiplus_with_udma(struct pci_dev *pdev)
++{
++ u8 r;
++ int ret = 0;
++ int ioport = 0x22;
++ struct pci_dev *dev1;
++
++ /* Find function 1 */
++ dev1 = pci_get_device(0x1045, 0xC701, NULL);
++ if(dev1 == NULL)
++ return 0;
++
++ /* Rev must be >= 0x10 */
++ pci_read_config_byte(dev1, 0x08, &r);
++ if (r < 0x10)
++ goto done_nomsg;
++ /* Read the chipset system configuration to check our mode */
++ pci_read_config_byte(dev1, 0x5F, &r);
++ ioport |= (r << 8);
++ outb(0x10, ioport);
++ /* Must be 66Mhz sync */
++ if ((inb(ioport + 2) & 1) == 0)
++ goto done;
++
++ /* Check the ATA arbitration/timing is suitable */
++ pci_read_config_byte(pdev, 0x42, &r);
++ if ((r & 0x36) != 0x36)
++ goto done;
++ pci_read_config_byte(dev1, 0x52, &r);
++ if (r & 0x80) /* IDEDIR disabled */
++ ret = 1;
++done:
++ printk(KERN_WARNING "UDMA not supported in this configuration.\n");
++done_nomsg: /* Wrong chip revision */
++ pci_dev_put(dev1);
++ return ret;
++}
++
++static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info_82c700 = {
++ .sht = &optidma_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &optidma_port_ops
++ };
++ static struct ata_port_info info_82c700_udma = {
++ .sht = &optidma_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x07,
++ .port_ops = &optiplus_port_ops
++ };
++ static struct ata_port_info *port_info[2];
++ struct ata_port_info *info = &info_82c700;
++ static int printed_version;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
++
++ /* Fixed location chipset magic */
++ inw(0x1F1);
++ inw(0x1F1);
++ pci_clock = inb(0x1F5) & 1; /* 0 = 33Mhz, 1 = 25Mhz */
++
++ if (optiplus_with_udma(dev))
++ info = &info_82c700_udma;
++
++ port_info[0] = port_info[1] = info;
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id optidma[] = {
++ { PCI_VDEVICE(OPTI, 0xD568), }, /* Opti 82C700 */
++
++ { },
++};
++
++static struct pci_driver optidma_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = optidma,
++ .probe = optidma_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init optidma_init(void)
++{
++ return pci_register_driver(&optidma_pci_driver);
++}
++
++static void __exit optidma_exit(void)
++{
++ pci_unregister_driver(&optidma_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, optidma);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(optidma_init);
++module_exit(optidma_exit);
+diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
+new file mode 100644
+index 0000000..e93ea27
+--- /dev/null
++++ b/drivers/ata/pata_pcmcia.c
+@@ -0,0 +1,395 @@
++/*
++ * pata_pcmcia.c - PCMCIA PATA controller driver.
++ * Copyright 2005-2006 Red Hat Inc <alan at redhat.com>, all rights reserved.
++ * PCMCIA ident update Copyright 2006 Marcin Juszkiewicz
++ * <openembedded at hrw.one.pl>
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Heavily based upon ide-cs.c
++ * The initial developer of the original code is David A. Hinds
++ * <dahinds at users.sourceforge.net>. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/ata.h>
++#include <linux/libata.h>
++
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++#include <pcmcia/ciscode.h>
++
++
++#define DRV_NAME "pata_pcmcia"
++#define DRV_VERSION "0.2.11"
++
++/*
++ * Private data structure to glue stuff together
++ */
++
++struct ata_pcmcia_info {
++ struct pcmcia_device *pdev;
++ int ndev;
++ dev_node_t node;
++};
++
++static struct scsi_host_template pcmcia_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations pcmcia_port_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer_noirq,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++#define CS_CHECK(fn, ret) \
++do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
++
++/**
++ * pcmcia_init_one - attach a PCMCIA interface
++ * @pdev: pcmcia device
++ *
++ * Register a PCMCIA IDE interface. Such interfaces are PIO 0 and
++ * shared IRQ.
++ */
++
++static int pcmcia_init_one(struct pcmcia_device *pdev)
++{
++ struct ata_probe_ent ae;
++ struct ata_pcmcia_info *info;
++ tuple_t tuple;
++ struct {
++ unsigned short buf[128];
++ cisparse_t parse;
++ config_info_t conf;
++ cistpl_cftable_entry_t dflt;
++ } *stk = NULL;
++ cistpl_cftable_entry_t *cfg;
++ int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
++ unsigned long io_base, ctl_base;
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (info == NULL)
++ return -ENOMEM;
++
++ /* Glue stuff together. FIXME: We may be able to get rid of info with care */
++ info->pdev = pdev;
++ pdev->priv = info;
++
++ /* Set up attributes in order to probe card and get resources */
++ pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
++ pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
++ pdev->io.IOAddrLines = 3;
++ pdev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
++ pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
++ pdev->conf.Attributes = CONF_ENABLE_IRQ;
++ pdev->conf.IntType = INT_MEMORY_AND_IO;
++
++ /* Allocate resoure probing structures */
++
++ stk = kzalloc(sizeof(*stk), GFP_KERNEL);
++ if (!stk)
++ goto out1;
++
++ cfg = &stk->parse.cftable_entry;
++
++ /* Tuples we are walking */
++ tuple.TupleData = (cisdata_t *)&stk->buf;
++ tuple.TupleOffset = 0;
++ tuple.TupleDataMax = 255;
++ tuple.Attributes = 0;
++ tuple.DesiredTuple = CISTPL_CONFIG;
++
++ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
++ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple));
++ CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, &stk->parse));
++ pdev->conf.ConfigBase = stk->parse.config.base;
++ pdev->conf.Present = stk->parse.config.rmask[0];
++
++ /* See if we have a manufacturer identifier. Use it to set is_kme for
++ vendor quirks */
++ tuple.DesiredTuple = CISTPL_MANFID;
++ if (!pcmcia_get_first_tuple(pdev, &tuple) && !pcmcia_get_tuple_data(pdev, &tuple) && !pcmcia_parse_tuple(pdev, &tuple, &stk->parse))
++ is_kme = ((stk->parse.manfid.manf == MANFID_KME) && ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || (stk->parse.manfid.card == PRODID_KME_KXLC005_B)));
++
++ /* Not sure if this is right... look up the current Vcc */
++ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
++/* link->conf.Vcc = stk->conf.Vcc; */
++
++ pass = io_base = ctl_base = 0;
++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++ tuple.Attributes = 0;
++ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
++
++ /* Now munch the resources looking for a suitable set */
++ while (1) {
++ if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
++ goto next_entry;
++ if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
++ goto next_entry;
++ /* Check for matching Vcc, unless we're desperate */
++ if (!pass) {
++ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
++ if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
++ goto next_entry;
++ } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
++ if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
++ goto next_entry;
++ }
++ }
++
++ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
++ pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
++ else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
++ pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
++
++ if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
++ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
++ pdev->conf.ConfigIndex = cfg->index;
++ pdev->io.BasePort1 = io->win[0].base;
++ pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
++ if (!(io->flags & CISTPL_IO_16BIT))
++ pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++ if (io->nwin == 2) {
++ pdev->io.NumPorts1 = 8;
++ pdev->io.BasePort2 = io->win[1].base;
++ pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
++ if (pcmcia_request_io(pdev, &pdev->io) != 0)
++ goto next_entry;
++ io_base = pdev->io.BasePort1;
++ ctl_base = pdev->io.BasePort2;
++ } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
++ pdev->io.NumPorts1 = io->win[0].len;
++ pdev->io.NumPorts2 = 0;
++ if (pcmcia_request_io(pdev, &pdev->io) != 0)
++ goto next_entry;
++ io_base = pdev->io.BasePort1;
++ ctl_base = pdev->io.BasePort1 + 0x0e;
++ } else goto next_entry;
++ /* If we've got this far, we're done */
++ break;
++ }
++next_entry:
++ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
++ memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
++ if (pass) {
++ CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
++ } else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
++ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
++ memset(&stk->dflt, 0, sizeof(stk->dflt));
++ pass++;
++ }
++ }
++
++ CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
++ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
++
++ /* Success. Disable the IRQ nIEN line, do quirks */
++ outb(0x02, ctl_base);
++ if (is_kme)
++ outb(0x81, ctl_base + 0x01);
++
++ /* FIXME: Could be more ports at base + 0x10 but we only deal with
++ one right now */
++ if (pdev->io.NumPorts1 >= 0x20)
++ printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n");
++
++ /*
++ * Having done the PCMCIA plumbing the ATA side is relatively
++ * sane.
++ */
++
++ memset(&ae, 0, sizeof(struct ata_probe_ent));
++ INIT_LIST_HEAD(&ae.node);
++ ae.dev = &pdev->dev;
++ ae.port_ops = &pcmcia_port_ops;
++ ae.sht = &pcmcia_sht;
++ ae.n_ports = 1;
++ ae.pio_mask = 1; /* ISA so PIO 0 cycles */
++ ae.irq = pdev->irq.AssignedIRQ;
++ ae.irq_flags = SA_SHIRQ;
++ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
++ ae.port[0].cmd_addr = io_base;
++ ae.port[0].altstatus_addr = ctl_base;
++ ae.port[0].ctl_addr = ctl_base;
++ ata_std_ports(&ae.port[0]);
++
++ if (ata_device_add(&ae) == 0)
++ goto failed;
++
++ info->ndev = 1;
++ kfree(stk);
++ return 0;
++
++cs_failed:
++ cs_error(pdev, last_fn, last_ret);
++failed:
++ kfree(stk);
++ info->ndev = 0;
++ pcmcia_disable_device(pdev);
++out1:
++ kfree(info);
++ return ret;
++}
++
++/**
++ * pcmcia_remove_one - unplug an pcmcia interface
++ * @pdev: pcmcia device
++ *
++ * A PCMCIA ATA device has been unplugged. Perform the needed
++ * cleanup. Also called on module unload for any active devices.
++ */
++
++static void pcmcia_remove_one(struct pcmcia_device *pdev)
++{
++ struct ata_pcmcia_info *info = pdev->priv;
++ struct device *dev = &pdev->dev;
++
++ if (info != NULL) {
++ /* If we have attached the device to the ATA layer, detach it */
++ if (info->ndev) {
++ struct ata_host *host = dev_get_drvdata(dev);
++ ata_host_remove(host);
++ dev_set_drvdata(dev, NULL);
++ }
++ info->ndev = 0;
++ pdev->priv = NULL;
++ }
++ pcmcia_disable_device(pdev);
++ kfree(info);
++}
++
++static struct pcmcia_device_id pcmcia_devices[] = {
++ PCMCIA_DEVICE_FUNC_ID(4),
++ PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
++ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
++ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
++ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
++ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
++ PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
++ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
++ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
++ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */
++ 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+GAME", 0x6f58c983, 0x63c13aaf),
++ 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("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
++ PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
++ PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
++ 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("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
++ PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 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("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
++ PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
++ PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
++ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
++ PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
++ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
++ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
++ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
++ PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
++ PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
++ PCMCIA_DEVICE_NULL,
++};
++
++MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices);
++
++static struct pcmcia_driver pcmcia_driver = {
++ .owner = THIS_MODULE,
++ .drv = {
++ .name = DRV_NAME,
++ },
++ .id_table = pcmcia_devices,
++ .probe = pcmcia_init_one,
++ .remove = pcmcia_remove_one,
++};
++
++static int __init pcmcia_init(void)
++{
++ return pcmcia_register_driver(&pcmcia_driver);
++}
++
++static void __exit pcmcia_exit(void)
++{
++ pcmcia_unregister_driver(&pcmcia_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for PCMCIA ATA");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(pcmcia_init);
++module_exit(pcmcia_exit);
+diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
+new file mode 100644
+index 0000000..d894d99
+--- /dev/null
++++ b/drivers/ata/pata_pdc2027x.c
+@@ -0,0 +1,868 @@
++/*
++ * Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277.
++ *
++ * 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.
++ *
++ * Ported to libata by:
++ * Albert Lee <albertcc at tw.ibm.com> IBM Corporation
++ *
++ * Copyright (C) 1998-2002 Andre Hedrick <andre at linux-ide.org>
++ * Portions Copyright (C) 1999 Promise Technology, Inc.
++ *
++ * Author: Frank Tiernan (frankt at promise.com)
++ * Released under terms of General Public License
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware information only available under NDA.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++
++#define DRV_NAME "pata_pdc2027x"
++#define DRV_VERSION "0.74-ac5"
++#undef PDC_DEBUG
++
++#ifdef PDC_DEBUG
++#define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
++#else
++#define PDPRINTK(fmt, args...)
++#endif
++
++enum {
++ PDC_UDMA_100 = 0,
++ PDC_UDMA_133 = 1,
++
++ PDC_100_MHZ = 100000000,
++ PDC_133_MHZ = 133333333,
++
++ PDC_SYS_CTL = 0x1100,
++ PDC_ATA_CTL = 0x1104,
++ PDC_GLOBAL_CTL = 0x1108,
++ PDC_CTCR0 = 0x110C,
++ PDC_CTCR1 = 0x1110,
++ PDC_BYTE_COUNT = 0x1120,
++ PDC_PLL_CTL = 0x1202,
++};
++
++static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
++static void pdc2027x_remove_one(struct pci_dev *pdev);
++static void pdc2027x_error_handler(struct ata_port *ap);
++static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
++static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
++static void pdc2027x_post_set_mode(struct ata_port *ap);
++static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
++
++/*
++ * ATA Timing Tables based on 133MHz controller clock.
++ * These tables are only used when the controller is in 133MHz clock.
++ * If the controller is in 100MHz clock, the ASIC hardware will
++ * set the timing registers automatically when "set feature" command
++ * is issued to the device. However, if the controller clock is 133MHz,
++ * the following tables must be used.
++ */
++static struct pdc2027x_pio_timing {
++ u8 value0, value1, value2;
++} pdc2027x_pio_timing_tbl [] = {
++ { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */
++ { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */
++ { 0x23, 0x26, 0x64 }, /* PIO mode 2 */
++ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
++ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
++};
++
++static struct pdc2027x_mdma_timing {
++ u8 value0, value1;
++} pdc2027x_mdma_timing_tbl [] = {
++ { 0xdf, 0x5f }, /* MDMA mode 0 */
++ { 0x6b, 0x27 }, /* MDMA mode 1 */
++ { 0x69, 0x25 }, /* MDMA mode 2 */
++};
++
++static struct pdc2027x_udma_timing {
++ u8 value0, value1, value2;
++} pdc2027x_udma_timing_tbl [] = {
++ { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
++ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */
++ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */
++ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */
++ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */
++ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */
++ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
++};
++
++static const struct pci_device_id pdc2027x_pci_tbl[] = {
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), PDC_UDMA_133 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver pdc2027x_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = pdc2027x_pci_tbl,
++ .probe = pdc2027x_init_one,
++ .remove = __devexit_p(pdc2027x_remove_one),
++};
++
++static struct scsi_host_template pdc2027x_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations pdc2027x_pata100_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .check_atapi_dma = pdc2027x_check_atapi_dma,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = pdc2027x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static struct ata_port_operations pdc2027x_pata133_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = pdc2027x_set_piomode,
++ .set_dmamode = pdc2027x_set_dmamode,
++ .post_set_mode = pdc2027x_post_set_mode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .check_atapi_dma = pdc2027x_check_atapi_dma,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = pdc2027x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static struct ata_port_info pdc2027x_port_info[] = {
++ /* PDC_UDMA_100 */
++ {
++ .sht = &pdc2027x_sht,
++ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
++ ATA_FLAG_MMIO,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = ATA_UDMA5, /* udma0-5 */
++ .port_ops = &pdc2027x_pata100_ops,
++ },
++ /* PDC_UDMA_133 */
++ {
++ .sht = &pdc2027x_sht,
++ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
++ ATA_FLAG_MMIO,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = ATA_UDMA6, /* udma0-6 */
++ .port_ops = &pdc2027x_pata133_ops,
++ },
++};
++
++MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee");
++MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl);
++
++/**
++ * port_mmio - Get the MMIO address of PDC2027x extended registers
++ * @ap: Port
++ * @offset: offset from mmio base
++ */
++static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset)
++{
++ return ap->host->mmio_base + ap->port_no * 0x100 + offset;
++}
++
++/**
++ * dev_mmio - Get the MMIO address of PDC2027x extended registers
++ * @ap: Port
++ * @adev: device
++ * @offset: offset from mmio base
++ */
++static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *adev, unsigned int offset)
++{
++ u8 adj = (adev->devno) ? 0x08 : 0x00;
++ return port_mmio(ap, offset) + adj;
++}
++
++/**
++ * pdc2027x_pata_cbl_detect - Probe host controller cable detect info
++ * @ap: Port for which cable detect info is desired
++ *
++ * Read 80c cable indicator from Promise extended register.
++ * This register is latched when the system is reset.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++static void pdc2027x_cbl_detect(struct ata_port *ap)
++{
++ u32 cgcr;
++
++ /* check cable detect results */
++ cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
++ if (cgcr & (1 << 26))
++ goto cbl40;
++
++ PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
++
++ ap->cbl = ATA_CBL_PATA80;
++ return;
++
++cbl40:
++ printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
++ ap->cbl = ATA_CBL_PATA40;
++ ap->udma_mask &= ATA_UDMA_MASK_40C;
++}
++
++/**
++ * pdc2027x_port_enabled - Check PDC ATA control register to see whether the port is enabled.
++ * @ap: Port to check
++ */
++static inline int pdc2027x_port_enabled(struct ata_port *ap)
++{
++ return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
++}
++
++/**
++ * pdc2027x_prereset - prereset for PATA host controller
++ * @ap: Target port
++ *
++ * Probeinit including cable detection.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static int pdc2027x_prereset(struct ata_port *ap)
++{
++ /* Check whether port enabled */
++ if (!pdc2027x_port_enabled(ap))
++ return -ENOENT;
++ pdc2027x_cbl_detect(ap);
++ return ata_std_prereset(ap);
++}
++
++/**
++ * pdc2027x_error_handler - Perform reset on PATA port and classify
++ * @ap: Port to reset
++ *
++ * Reset PATA phy and classify attached devices.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void pdc2027x_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, pdc2027x_prereset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * pdc2027x_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port to configure
++ * @adev: um
++ * @pio: PIO mode, 0 - 4
++ *
++ * Set PIO mode for device.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio = adev->pio_mode - XFER_PIO_0;
++ u32 ctcr0, ctcr1;
++
++ PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode);
++
++ /* Sanity check */
++ if (pio > 4) {
++ printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio);
++ return;
++
++ }
++
++ /* Set the PIO timing registers using value table for 133MHz */
++ PDPRINTK("Set pio regs... \n");
++
++ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
++ ctcr0 &= 0xffff0000;
++ ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
++ (pdc2027x_pio_timing_tbl[pio].value1 << 8);
++ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
++
++ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
++ ctcr1 &= 0x00ffffff;
++ ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
++ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
++
++ PDPRINTK("Set pio regs done\n");
++
++ PDPRINTK("Set to pio mode[%u] \n", pio);
++}
++
++/**
++ * pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings
++ * @ap: Port to configure
++ * @adev: um
++ * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6
++ *
++ * Set UDMA mode for device.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int dma_mode = adev->dma_mode;
++ u32 ctcr0, ctcr1;
++
++ if ((dma_mode >= XFER_UDMA_0) &&
++ (dma_mode <= XFER_UDMA_6)) {
++ /* Set the UDMA timing registers with value table for 133MHz */
++ unsigned int udma_mode = dma_mode & 0x07;
++
++ if (dma_mode == XFER_UDMA_2) {
++ /*
++ * Turn off tHOLD.
++ * If tHOLD is '1', the hardware will add half clock for data hold time.
++ * This code segment seems to be no effect. tHOLD will be overwritten below.
++ */
++ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
++ writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
++ }
++
++ PDPRINTK("Set udma regs... \n");
++
++ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
++ ctcr1 &= 0xff000000;
++ ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
++ (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
++ (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
++ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
++
++ PDPRINTK("Set udma regs done\n");
++
++ PDPRINTK("Set to udma mode[%u] \n", udma_mode);
++
++ } else if ((dma_mode >= XFER_MW_DMA_0) &&
++ (dma_mode <= XFER_MW_DMA_2)) {
++ /* Set the MDMA timing registers with value table for 133MHz */
++ unsigned int mdma_mode = dma_mode & 0x07;
++
++ PDPRINTK("Set mdma regs... \n");
++ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
++
++ ctcr0 &= 0x0000ffff;
++ ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
++ (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
++
++ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
++ PDPRINTK("Set mdma regs done\n");
++
++ PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
++ } else {
++ printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode);
++ }
++}
++
++/**
++ * pdc2027x_post_set_mode - Set the timing registers back to correct values.
++ * @ap: Port to configure
++ *
++ * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
++ * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
++ * This function overwrites the possibly incorrect values set by the hardware to be correct.
++ */
++static void pdc2027x_post_set_mode(struct ata_port *ap)
++{
++ int i;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++
++ if (ata_dev_enabled(dev)) {
++
++ pdc2027x_set_piomode(ap, dev);
++
++ /*
++ * Enable prefetch if the device support PIO only.
++ */
++ if (dev->xfer_shift == ATA_SHIFT_PIO) {
++ u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
++ ctcr1 |= (1 << 25);
++ writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
++
++ PDPRINTK("Turn on prefetch\n");
++ } else {
++ pdc2027x_set_dmamode(ap, dev);
++ }
++ }
++ }
++}
++
++/**
++ * pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command
++ * @qc: Metadata associated with taskfile to check
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ *
++ * RETURNS: 0 when ATAPI DMA can be used
++ * 1 otherwise
++ */
++static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++ struct scsi_cmnd *cmd = qc->scsicmd;
++ u8 *scsicmd = cmd->cmnd;
++ int rc = 1; /* atapi dma off by default */
++
++ /*
++ * This workaround is from Promise's GPL driver.
++ * If ATAPI DMA is used for commands not in the
++ * following white list, say MODE_SENSE and REQUEST_SENSE,
++ * pdc2027x might hit the irq lost problem.
++ */
++ switch (scsicmd[0]) {
++ case READ_10:
++ case WRITE_10:
++ case READ_12:
++ case WRITE_12:
++ case READ_6:
++ case WRITE_6:
++ case 0xad: /* READ_DVD_STRUCTURE */
++ case 0xbe: /* READ_CD */
++ /* ATAPI DMA is ok */
++ rc = 0;
++ break;
++ default:
++ ;
++ }
++
++ return rc;
++}
++
++/**
++ * pdc_read_counter - Read the ctr counter
++ * @probe_ent: for the port address
++ */
++
++static long pdc_read_counter(struct ata_probe_ent *probe_ent)
++{
++ long counter;
++ int retry = 1;
++ u32 bccrl, bccrh, bccrlv, bccrhv;
++
++retry:
++ bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
++ bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
++ rmb();
++
++ /* Read the counter values again for verification */
++ bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
++ bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
++ rmb();
++
++ counter = (bccrh << 15) | bccrl;
++
++ PDPRINTK("bccrh [%X] bccrl [%X]\n", bccrh, bccrl);
++ PDPRINTK("bccrhv[%X] bccrlv[%X]\n", bccrhv, bccrlv);
++
++ /*
++ * The 30-bit decreasing counter are read by 2 pieces.
++ * Incorrect value may be read when both bccrh and bccrl are changing.
++ * Ex. When 7900 decrease to 78FF, wrong value 7800 might be read.
++ */
++ if (retry && !(bccrh == bccrhv && bccrl >= bccrlv)) {
++ retry--;
++ PDPRINTK("rereading counter\n");
++ goto retry;
++ }
++
++ return counter;
++}
++
++/**
++ * adjust_pll - Adjust the PLL input clock in Hz.
++ *
++ * @pdc_controller: controller specific information
++ * @probe_ent: For the port address
++ * @pll_clock: The input of PLL in HZ
++ */
++static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
++{
++
++ u16 pll_ctl;
++ long pll_clock_khz = pll_clock / 1000;
++ long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
++ long ratio = pout_required / pll_clock_khz;
++ int F, R;
++
++ /* Sanity check */
++ if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) {
++ printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz);
++ return;
++ }
++
++#ifdef PDC_DEBUG
++ PDPRINTK("pout_required is %ld\n", pout_required);
++
++ /* Show the current clock value of PLL control register
++ * (maybe already configured by the firmware)
++ */
++ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
++
++ PDPRINTK("pll_ctl[%X]\n", pll_ctl);
++#endif
++
++ /*
++ * Calculate the ratio of F, R and OD
++ * POUT = (F + 2) / (( R + 2) * NO)
++ */
++ if (ratio < 8600L) { /* 8.6x */
++ /* Using NO = 0x01, R = 0x0D */
++ R = 0x0d;
++ } else if (ratio < 12900L) { /* 12.9x */
++ /* Using NO = 0x01, R = 0x08 */
++ R = 0x08;
++ } else if (ratio < 16100L) { /* 16.1x */
++ /* Using NO = 0x01, R = 0x06 */
++ R = 0x06;
++ } else if (ratio < 64000L) { /* 64x */
++ R = 0x00;
++ } else {
++ /* Invalid ratio */
++ printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio);
++ return;
++ }
++
++ F = (ratio * (R+2)) / 1000 - 2;
++
++ if (unlikely(F < 0 || F > 127)) {
++ /* Invalid F */
++ printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F);
++ return;
++ }
++
++ PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio);
++
++ pll_ctl = (R << 8) | F;
++
++ PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
++
++ writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL);
++ readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */
++
++ /* Wait the PLL circuit to be stable */
++ mdelay(30);
++
++#ifdef PDC_DEBUG
++ /*
++ * Show the current clock value of PLL control register
++ * (maybe configured by the firmware)
++ */
++ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
++
++ PDPRINTK("pll_ctl[%X]\n", pll_ctl);
++#endif
++
++ return;
++}
++
++/**
++ * detect_pll_input_clock - Detect the PLL input clock in Hz.
++ * @probe_ent: for the port address
++ * Ex. 16949000 on 33MHz PCI bus for pdc20275.
++ * Half of the PCI clock.
++ */
++static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
++{
++ u32 scr;
++ long start_count, end_count;
++ long pll_clock;
++
++ /* Read current counter value */
++ start_count = pdc_read_counter(probe_ent);
++
++ /* Start the test mode */
++ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
++ PDPRINTK("scr[%X]\n", scr);
++ writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
++ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
++
++ /* Let the counter run for 100 ms. */
++ mdelay(100);
++
++ /* Read the counter values again */
++ end_count = pdc_read_counter(probe_ent);
++
++ /* Stop the test mode */
++ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
++ PDPRINTK("scr[%X]\n", scr);
++ writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
++ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
++
++ /* calculate the input clock in Hz */
++ pll_clock = (start_count - end_count) * 10;
++
++ PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);
++ PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock);
++
++ return pll_clock;
++}
++
++/**
++ * pdc_hardware_init - Initialize the hardware.
++ * @pdev: instance of pci_dev found
++ * @pdc_controller: controller specific information
++ * @pe: for the port address
++ */
++static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
++{
++ long pll_clock;
++
++ /*
++ * Detect PLL input clock rate.
++ * On some system, where PCI bus is running at non-standard clock rate.
++ * Ex. 25MHz or 40MHz, we have to adjust the cycle_time.
++ * The pdc20275 controller employs PLL circuit to help correct timing registers setting.
++ */
++ pll_clock = pdc_detect_pll_input_clock(pe);
++
++ if (pll_clock < 0) /* counter overflow? Try again. */
++ pll_clock = pdc_detect_pll_input_clock(pe);
++
++ dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
++
++ /* Adjust PLL control register */
++ pdc_adjust_pll(pe, pll_clock, board_idx);
++
++ return 0;
++}
++
++/**
++ * pdc_ata_setup_port - setup the mmio address
++ * @port: ata ioports to setup
++ * @base: base address
++ */
++static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr =
++ port->data_addr = base;
++ port->feature_addr =
++ port->error_addr = base + 0x05;
++ port->nsect_addr = base + 0x0a;
++ port->lbal_addr = base + 0x0f;
++ port->lbam_addr = base + 0x10;
++ port->lbah_addr = base + 0x15;
++ port->device_addr = base + 0x1a;
++ port->command_addr =
++ port->status_addr = base + 0x1f;
++ port->altstatus_addr =
++ port->ctl_addr = base + 0x81a;
++}
++
++/**
++ * pdc2027x_init_one - PCI probe function
++ * Called when an instance of PCI adapter is inserted.
++ * This function checks whether the hardware is supported,
++ * initialize hardware and register an instance of ata_host to
++ * libata by providing struct ata_probe_ent and ata_device_add().
++ * (implements struct pci_driver.probe() )
++ *
++ * @pdev: instance of pci_dev found
++ * @ent: matching entry in the id_tbl[]
++ */
++static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++
++ struct ata_probe_ent *probe_ent = NULL;
++ unsigned long base;
++ void __iomem *mmio_base;
++ int rc;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc)
++ goto err_out;
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ /* Prepare the probe entry */
++ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, 5, 0);
++ if (!mmio_base) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++
++ base = (unsigned long) mmio_base;
++
++ probe_ent->sht = pdc2027x_port_info[board_idx].sht;
++ probe_ent->port_flags = pdc2027x_port_info[board_idx].flags;
++ probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
++ probe_ent->mwdma_mask = pdc2027x_port_info[board_idx].mwdma_mask;
++ probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = SA_SHIRQ;
++ probe_ent->mmio_base = mmio_base;
++
++ pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0);
++ probe_ent->port[0].bmdma_addr = base + 0x1000;
++ pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0);
++ probe_ent->port[1].bmdma_addr = base + 0x1008;
++
++ probe_ent->n_ports = 2;
++
++ pci_set_master(pdev);
++ //pci_enable_intx(pdev);
++
++ /* initialize adapter */
++ if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
++ goto err_out_free_ent;
++
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ pci_disable_device(pdev);
++ return rc;
++}
++
++/**
++ * pdc2027x_remove_one - Called to remove a single instance of the
++ * adapter.
++ *
++ * @dev: The PCI device to remove.
++ * FIXME: module load/unload not working yet
++ */
++static void __devexit pdc2027x_remove_one(struct pci_dev *pdev)
++{
++ ata_pci_remove_one(pdev);
++}
++
++/**
++ * pdc2027x_init - Called after this module is loaded into the kernel.
++ */
++static int __init pdc2027x_init(void)
++{
++ return pci_module_init(&pdc2027x_pci_driver);
++}
++
++/**
++ * pdc2027x_exit - Called before this module unloaded from the kernel
++ */
++static void __exit pdc2027x_exit(void)
++{
++ pci_unregister_driver(&pdc2027x_pci_driver);
++}
++
++module_init(pdc2027x_init);
++module_exit(pdc2027x_exit);
+diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
+new file mode 100644
+index 0000000..5ba9eb2
+--- /dev/null
++++ b/drivers/ata/pata_pdc202xx_old.c
+@@ -0,0 +1,422 @@
++/*
++ * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based in part on linux/drivers/ide/pci/pdc202xx_old.c
++ *
++ * First cut with LBA48/ATAPI
++ *
++ * TODO:
++ * Channel interlock/reset on both required ?
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_pdc202xx_old"
++#define DRV_VERSION "0.2.1"
++
++/**
++ * pdc2024x_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int pdc2024x_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++
++static void pdc2024x_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++
++static int pdc2026x_pre_reset(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u16 cis;
++
++ pci_read_config_word(pdev, 0x50, &cis);
++ if (cis & (1 << (10 + ap->port_no)))
++ ap->cbl = ATA_CBL_PATA80;
++ else
++ ap->cbl = ATA_CBL_PATA40;
++
++ return ata_std_prereset(ap);
++}
++
++static void pdc2026x_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * pdc_configure_piomode - set chip PIO timing
++ * @ap: ATA interface
++ * @adev: ATA device
++ * @pio: PIO mode
++ *
++ * Called to do the PIO mode setup. Our timing registers are shared
++ * so a configure_dmamode call will undo any work we do here and vice
++ * versa
++ */
++
++static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
++ static u16 pio_timing[5] = {
++ 0x0913, 0x050C , 0x0308, 0x0206, 0x0104
++ };
++ u8 r_ap, r_bp;
++
++ pci_read_config_byte(pdev, port, &r_ap);
++ pci_read_config_byte(pdev, port + 1, &r_bp);
++ r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */
++ r_bp &= ~0x07;
++ r_ap |= (pio_timing[pio] >> 8);
++ r_bp |= (pio_timing[pio] & 0xFF);
++
++ if (ata_pio_need_iordy(adev))
++ r_ap |= 0x20; /* IORDY enable */
++ if (adev->class == ATA_DEV_ATA)
++ r_ap |= 0x10; /* FIFO enable */
++ pci_write_config_byte(pdev, port, r_ap);
++ pci_write_config_byte(pdev, port + 1, r_bp);
++}
++
++/**
++ * pdc_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup. Our timing registers are shared
++ * but we want to set the PIO timing by default.
++ */
++
++static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
++}
++
++/**
++ * pdc_configure_dmamode - set DMA mode in chip
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Load DMA cycle times into the chip ready for a DMA transfer
++ * to occur.
++ */
++
++static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
++ static u8 udma_timing[6][2] = {
++ { 0x60, 0x03 }, /* 33 Mhz Clock */
++ { 0x40, 0x02 },
++ { 0x20, 0x01 },
++ { 0x40, 0x02 }, /* 66 Mhz Clock */
++ { 0x20, 0x01 },
++ { 0x20, 0x01 }
++ };
++ u8 r_bp, r_cp;
++
++ pci_read_config_byte(pdev, port + 1, &r_bp);
++ pci_read_config_byte(pdev, port + 2, &r_cp);
++
++ r_bp &= ~0xF0;
++ r_cp &= ~0x0F;
++
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ int speed = adev->dma_mode - XFER_UDMA_0;
++ r_bp |= udma_timing[speed][0];
++ r_cp |= udma_timing[speed][1];
++
++ } else {
++ int speed = adev->dma_mode - XFER_MW_DMA_0;
++ r_bp |= 0x60;
++ r_cp |= (5 - speed);
++ }
++ pci_write_config_byte(pdev, port + 1, r_bp);
++ pci_write_config_byte(pdev, port + 2, r_cp);
++
++}
++
++/**
++ * pdc2026x_bmdma_start - DMA engine begin
++ * @qc: ATA command
++ *
++ * In UDMA3 or higher we have to clock switch for the duration of the
++ * DMA transfer sequence.
++ */
++
++static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct ata_taskfile *tf = &qc->tf;
++ int sel66 = ap->port_no ? 0x08: 0x02;
++
++ unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
++ unsigned long clock = master + 0x11;
++ unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
++
++ u32 len;
++
++ /* Check we keep host level locking here */
++ if (adev->dma_mode >= XFER_UDMA_2)
++ outb(inb(clock) | sel66, clock);
++ else
++ outb(inb(clock) & ~sel66, clock);
++
++ /* The DMA clocks may have been trashed by a reset. FIXME: make conditional
++ and move to qc_issue ? */
++ pdc_set_dmamode(ap, qc->dev);
++
++ /* Cases the state machine will not complete correctly without help */
++ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA)
++ {
++ if (tf->flags & ATA_TFLAG_LBA48)
++ len = qc->nsect * 512;
++ else
++ len = qc->nbytes;
++
++ if (tf->flags & ATA_TFLAG_WRITE)
++ len |= 0x06000000;
++ else
++ len |= 0x05000000;
++
++ outl(len, atapi_reg);
++ }
++
++ /* Activate DMA */
++ ata_bmdma_start(qc);
++}
++
++/**
++ * pdc2026x_bmdma_end - DMA engine stop
++ * @qc: ATA command
++ *
++ * After a DMA completes we need to put the clock back to 33MHz for
++ * PIO timings.
++ */
++
++static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct ata_taskfile *tf = &qc->tf;
++
++ int sel66 = ap->port_no ? 0x08: 0x02;
++ /* The clock bits are in the same register for both channels */
++ unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
++ unsigned long clock = master + 0x11;
++ unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
++
++ /* Cases the state machine will not complete correctly */
++ if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
++ outl(0, atapi_reg);
++ outb(inb(clock) & ~sel66, clock);
++ }
++ /* Check we keep host level locking here */
++ /* Flip back to 33Mhz for PIO */
++ if (adev->dma_mode >= XFER_UDMA_2)
++ outb(inb(clock) & ~sel66, clock);
++
++ ata_bmdma_stop(qc);
++}
++
++/**
++ * pdc2026x_dev_config - device setup hook
++ * @ap: ATA port
++ * @adev: newly found device
++ *
++ * Perform chip specific early setup. We need to lock the transfer
++ * sizes to 8bit to avoid making the state engine on the 2026x cards
++ * barf.
++ */
++
++static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
++{
++ adev->max_sectors = 256;
++}
++
++static struct scsi_host_template pdc_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations pdc2024x_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = pdc_set_piomode,
++ .set_dmamode = pdc_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = pdc2024x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations pdc2026x_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = pdc_set_piomode,
++ .set_dmamode = pdc_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .dev_config = pdc2026x_dev_config,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = pdc2026x_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = pdc2026x_bmdma_start,
++ .bmdma_stop = pdc2026x_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info[3] = {
++ {
++ .sht = &pdc_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA2,
++ .port_ops = &pdc2024x_port_ops
++ },
++ {
++ .sht = &pdc_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA4,
++ .port_ops = &pdc2026x_port_ops
++ },
++ {
++ .sht = &pdc_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA5,
++ .port_ops = &pdc2026x_port_ops
++ }
++
++ };
++ static struct ata_port_info *port_info[2];
++
++ port_info[0] = port_info[1] = &info[id->driver_data];
++
++ if (dev->device == PCI_DEVICE_ID_PROMISE_20265) {
++ struct pci_dev *bridge = dev->bus->self;
++ /* Don't grab anything behind a Promise I2O RAID */
++ if (bridge && bridge->vendor == PCI_VENDOR_ID_INTEL) {
++ if( bridge->device == PCI_DEVICE_ID_INTEL_I960)
++ return -ENODEV;
++ if( bridge->device == PCI_DEVICE_ID_INTEL_I960RM)
++ return -ENODEV;
++ }
++ }
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id pdc[] = {
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
++ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
++
++ { },
++};
++
++static struct pci_driver pdc_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = pdc,
++ .probe = pdc_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init pdc_init(void)
++{
++ return pci_register_driver(&pdc_pci_driver);
++}
++
++static void __exit pdc_exit(void)
++{
++ pci_unregister_driver(&pdc_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, pdc);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(pdc_init);
++module_exit(pdc_exit);
+diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
+new file mode 100644
+index 0000000..2c3cc0c
+--- /dev/null
++++ b/drivers/ata/pata_qdi.c
+@@ -0,0 +1,403 @@
++/*
++ * pata_qdi.c - QDI VLB ATA controllers
++ * (C) 2006 Red Hat <alan at redhat.com>
++ *
++ * This driver mostly exists as a proof of concept for non PCI devices under
++ * libata. While the QDI6580 was 'neat' in 1993 it is no longer terribly
++ * useful.
++ *
++ * Tuning code written from the documentation at
++ * http://www.ryston.cz/petr/vlb/qd6500.html
++ * http://www.ryston.cz/petr/vlb/qd6580.html
++ *
++ * Probe code based on drivers/ide/legacy/qd65xx.c
++ * Rewritten from the work of Colten Edwards <pje120 at cs.usask.ca> by
++ * Samuel Thibault <samuel.thibault at fnac.net>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/platform_device.h>
++
++#define DRV_NAME "pata_qdi"
++#define DRV_VERSION "0.2.4"
++
++#define NR_HOST 4 /* Two 6580s */
++
++struct qdi_data {
++ unsigned long timing;
++ u8 clock[2];
++ u8 last;
++ int fast;
++ struct platform_device *platform_dev;
++
++};
++
++static struct ata_host *qdi_host[NR_HOST];
++static struct qdi_data qdi_data[NR_HOST];
++static int nr_qdi_host;
++
++#ifdef MODULE
++static int probe_qdi = 1;
++#else
++static int probe_qdi;
++#endif
++
++static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct ata_timing t;
++ struct qdi_data *qdi = ap->host->private_data;
++ int active, recovery;
++ u8 timing;
++
++ /* Get the timing data in cycles */
++ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
++
++ if (qdi->fast) {
++ active = 8 - FIT(t.active, 1, 8);
++ recovery = 18 - FIT(t.recover, 3, 18);
++ } else {
++ active = 9 - FIT(t.active, 2, 9);
++ recovery = 15 - FIT(t.recover, 0, 15);
++ }
++ timing = (recovery << 4) | active | 0x08;
++
++ qdi->clock[adev->devno] = timing;
++
++ outb(timing, qdi->timing);
++}
++
++static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct ata_timing t;
++ struct qdi_data *qdi = ap->host->private_data;
++ int active, recovery;
++ u8 timing;
++
++ /* Get the timing data in cycles */
++ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
++
++ if (qdi->fast) {
++ active = 8 - FIT(t.active, 1, 8);
++ recovery = 18 - FIT(t.recover, 3, 18);
++ } else {
++ active = 9 - FIT(t.active, 2, 9);
++ recovery = 15 - FIT(t.recover, 0, 15);
++ }
++ timing = (recovery << 4) | active | 0x08;
++
++ qdi->clock[adev->devno] = timing;
++
++ outb(timing, qdi->timing);
++
++ /* Clear the FIFO */
++ if (adev->class != ATA_DEV_ATA)
++ outb(0x5F, (qdi->timing & 0xFFF0) + 3);
++}
++
++/**
++ * qdi_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings.
++ */
++
++static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct qdi_data *qdi = ap->host->private_data;
++
++ if (qdi->clock[adev->devno] != qdi->last) {
++ if (adev->pio_mode) {
++ qdi->last = qdi->clock[adev->devno];
++ outb(qdi->clock[adev->devno], qdi->timing);
++ }
++ }
++ return ata_qc_issue_prot(qc);
++}
++
++static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
++{
++ struct ata_port *ap = adev->ap;
++ int slop = buflen & 3;
++
++ if (ata_id_has_dword_io(adev->id)) {
++ if (write_data)
++ outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
++ else
++ insl(ap->ioaddr.data_addr, buf, buflen >> 2);
++
++ if (unlikely(slop)) {
++ u32 pad;
++ if (write_data) {
++ memcpy(&pad, buf + buflen - slop, slop);
++ outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
++ } else {
++ pad = cpu_to_le32(inl(ap->ioaddr.data_addr));
++ memcpy(buf + buflen - slop, &pad, slop);
++ }
++ }
++ } else
++ ata_pio_data_xfer(adev, buf, buflen, write_data);
++}
++
++static struct scsi_host_template qdi_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations qdi6500_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = qdi6500_set_piomode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = qdi_qc_issue_prot,
++
++ .data_xfer = qdi_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations qdi6580_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = qdi6580_set_piomode,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = qdi_qc_issue_prot,
++
++ .data_xfer = qdi_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * qdi_init_one - attach a qdi interface
++ * @type: Type to display
++ * @io: I/O port start
++ * @irq: interrupt line
++ * @fast: True if on a > 33Mhz VLB
++ *
++ * Register an ISA bus IDE interface. Such interfaces are PIO and we
++ * assume do not support IRQ sharing.
++ */
++
++static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
++{
++ struct ata_probe_ent ae;
++ struct platform_device *pdev;
++ int ret;
++
++ unsigned long ctrl = io + 0x206;
++
++ /*
++ * Fill in a probe structure first of all
++ */
++
++ pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0);
++ if (pdev == NULL)
++ return -ENOMEM;
++
++ memset(&ae, 0, sizeof(struct ata_probe_ent));
++ INIT_LIST_HEAD(&ae.node);
++ ae.dev = &pdev->dev;
++
++ if (type == 6580) {
++ ae.port_ops = &qdi6580_port_ops;
++ ae.pio_mask = 0x1F;
++ } else {
++ ae.port_ops = &qdi6500_port_ops;
++ ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
++ }
++
++ ae.sht = &qdi_sht;
++ ae.n_ports = 1;
++ ae.irq = irq;
++ ae.irq_flags = 0;
++ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
++ ae.port[0].cmd_addr = io;
++ ae.port[0].altstatus_addr = ctrl;
++ ae.port[0].ctl_addr = ctrl;
++ ata_std_ports(&ae.port[0]);
++
++ /*
++ * Hook in a private data structure per channel
++ */
++ ae.private_data = &qdi_data[nr_qdi_host];
++
++ qdi_data[nr_qdi_host].timing = port;
++ qdi_data[nr_qdi_host].fast = fast;
++ qdi_data[nr_qdi_host].platform_dev = pdev;
++
++ printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
++ ret = ata_device_add(&ae);
++ if (ret == 0) {
++ platform_device_unregister(pdev);
++ return -ENODEV;
++ }
++
++ qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
++ return 0;
++}
++
++/**
++ * qdi_init - attach qdi interfaces
++ *
++ * Attach qdi IDE interfaces by scanning the ports it may occupy.
++ */
++
++static __init int qdi_init(void)
++{
++ unsigned long flags;
++ static const unsigned long qd_port[2] = { 0x30, 0xB0 };
++ static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
++ static const int ide_irq[2] = { 14, 15 };
++
++ int ct = 0;
++ int i;
++
++ if (probe_qdi == 0)
++ return -ENODEV;
++
++ /*
++ * Check each possible QD65xx base address
++ */
++
++ for (i = 0; i < 2; i++) {
++ unsigned long port = qd_port[i];
++ u8 r, res;
++
++
++ if (request_region(port, 2, "pata_qdi")) {
++ /* Check for a card */
++ local_irq_save(flags);
++ r = inb_p(port);
++ outb_p(0x19, port);
++ res = inb_p(port);
++ outb_p(r, port);
++ local_irq_restore(flags);
++
++ /* Fail */
++ if (res == 0x19)
++ {
++ release_region(port, 2);
++ continue;
++ }
++
++ /* Passes the presence test */
++ r = inb_p(port + 1); /* Check port agrees with port set */
++ if ((r & 2) >> 1 != i) {
++ release_region(port, 2);
++ continue;
++ }
++
++ /* Check card type */
++ if ((r & 0xF0) == 0xC0) {
++ /* QD6500: single channel */
++ if (r & 8) {
++ /* Disabled ? */
++ release_region(port, 2);
++ continue;
++ }
++ ct += qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
++ }
++ if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
++ /* QD6580: dual channel */
++ if (!request_region(port + 2 , 2, "pata_qdi"))
++ {
++ release_region(port, 2);
++ continue;
++ }
++ res = inb(port + 3);
++ if (res & 1) {
++ /* Single channel mode */
++ ct += qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
++ } else {
++ /* Dual channel mode */
++ ct += qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04);
++ ct += qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04);
++ }
++ }
++ }
++ }
++ if (ct != 0)
++ return 0;
++ return -ENODEV;
++}
++
++static __exit void qdi_exit(void)
++{
++ int i;
++
++ for (i = 0; i < nr_qdi_host; i++) {
++ ata_host_remove(qdi_host[i]);
++ /* Free the control resource. The 6580 dual channel has the resources
++ * claimed as a pair of 2 byte resources so we need no special cases...
++ */
++ release_region(qdi_data[i].timing, 2);
++ platform_device_unregister(qdi_data[i].platform_dev);
++ }
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for qdi ATA");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(qdi_init);
++module_exit(qdi_exit);
++
++module_param(probe_qdi, int, 0);
++
+diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
+new file mode 100644
+index 0000000..1af83d7
+--- /dev/null
++++ b/drivers/ata/pata_radisys.c
+@@ -0,0 +1,333 @@
++/*
++ * pata_radisys.c - Intel PATA/SATA controllers
++ *
++ * (C) 2006 Red Hat <alan at redhat.com>
++ *
++ * Some parts based on ata_piix.c by Jeff Garzik and others.
++ *
++ * A PIIX relative, this device has a single ATA channel and no
++ * slave timings, SITRE or PPE. In that sense it is a close relative
++ * of the original PIIX. It does however support UDMA 33/66 per channel
++ * although no other modes/timings. Also lacking is 32bit I/O on the ATA
++ * port.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_radisys"
++#define DRV_VERSION "0.4.1"
++
++/**
++ * radisys_probe_init - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int radisys_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA80;
++ return ata_std_prereset(ap);
++}
++
++
++/**
++ * radisys_pata_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ * @classes:
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void radisys_pata_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * radisys_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: um
++ *
++ * Set PIO mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ unsigned int pio = adev->pio_mode - XFER_PIO_0;
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ u16 idetm_data;
++ int control = 0;
++
++ /*
++ * See Intel Document 298600-004 for the timing programing rules
++ * for PIIX/ICH. Note that the early PIIX does not have the slave
++ * timing port at 0x44. The Radisys is a relative of the PIIX
++ * but not the same so be careful.
++ */
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 }, /* Check me */
++ { 0, 0 },
++ { 1, 1 },
++ { 2, 2 },
++ { 3, 3 }, };
++
++ if (pio > 0)
++ control |= 1; /* TIME1 enable */
++ if (ata_pio_need_iordy(adev))
++ control |= 2; /* IE IORDY */
++
++ pci_read_config_word(dev, 0x40, &idetm_data);
++
++ /* Enable IE and TIME as appropriate. Clear the other
++ drive timing bits */
++ idetm_data &= 0xCCCC;
++ idetm_data |= (control << (4 * adev->devno));
++ idetm_data |= (timings[pio][0] << 12) |
++ (timings[pio][1] << 8);
++ pci_write_config_word(dev, 0x40, idetm_data);
++
++ /* Track which port is configured */
++ ap->private_data = adev;
++}
++
++/**
++ * radisys_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ * @isich: True if the device is an ICH and has IOCFG registers
++ *
++ * Set MWDMA mode for device, in host controller PCI config space.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *dev = to_pci_dev(ap->host->dev);
++ u16 idetm_data;
++ u8 udma_enable;
++
++ static const /* ISP RTC */
++ u8 timings[][2] = { { 0, 0 },
++ { 0, 0 },
++ { 1, 1 },
++ { 2, 2 },
++ { 3, 3 }, };
++
++ /*
++ * MWDMA is driven by the PIO timings. We must also enable
++ * IORDY unconditionally.
++ */
++
++ pci_read_config_word(dev, 0x40, &idetm_data);
++ pci_read_config_byte(dev, 0x48, &udma_enable);
++
++ if (adev->dma_mode < XFER_UDMA_0) {
++ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
++ const unsigned int needed_pio[3] = {
++ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
++ };
++ int pio = needed_pio[mwdma] - XFER_PIO_0;
++ int control = 3; /* IORDY|TIME0 */
++
++ /* If the drive MWDMA is faster than it can do PIO then
++ we must force PIO0 for PIO cycles. */
++
++ if (adev->pio_mode < needed_pio[mwdma])
++ control = 1;
++
++ /* Mask out the relevant control and timing bits we will load. Also
++ clear the other drive TIME register as a precaution */
++
++ idetm_data &= 0xCCCC;
++ idetm_data |= control << (4 * adev->devno);
++ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
++
++ udma_enable &= ~(1 << adev->devno);
++ } else {
++ u8 udma_mode;
++
++ /* UDMA66 on: UDMA 33 and 66 are switchable via register 0x4A */
++
++ pci_read_config_byte(dev, 0x4A, &udma_mode);
++
++ if (adev->xfer_mode == XFER_UDMA_2)
++ udma_mode &= ~ (1 << adev->devno);
++ else /* UDMA 4 */
++ udma_mode |= (1 << adev->devno);
++
++ pci_write_config_byte(dev, 0x4A, udma_mode);
++
++ udma_enable |= (1 << adev->devno);
++ }
++ pci_write_config_word(dev, 0x40, idetm_data);
++ pci_write_config_byte(dev, 0x48, udma_enable);
++
++ /* Track which port is configured */
++ ap->private_data = adev;
++}
++
++/**
++ * radisys_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings if
++ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
++ * that, even if we get this wrong, cycles to the other device will
++ * be made PIO0.
++ */
++
++static unsigned int radisys_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++
++ if (adev != ap->private_data) {
++ /* UDMA timing is not shared */
++ if (adev->dma_mode < XFER_UDMA_0) {
++ if (adev->dma_mode)
++ radisys_set_dmamode(ap, adev);
++ else if (adev->pio_mode)
++ radisys_set_piomode(ap, adev);
++ }
++ }
++ return ata_qc_issue_prot(qc);
++}
++
++
++static struct scsi_host_template radisys_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations radisys_pata_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = radisys_set_piomode,
++ .set_dmamode = radisys_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = radisys_pata_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = radisys_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++
++/**
++ * radisys_init_one - Register PIIX ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in radisys_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer. We probe for combined mode (sigh),
++ * and then hand over control to libata, for it to do the rest.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ static struct ata_port_info info = {
++ .sht = &radisys_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma1-2 */
++ .udma_mask = 0x14, /* UDMA33/66 only */
++ .port_ops = &radisys_pata_ops,
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id radisys_pci_tbl[] = {
++ { PCI_VDEVICE(RADISYS, 0x8201), },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver radisys_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = radisys_pci_tbl,
++ .probe = radisys_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init radisys_init(void)
++{
++ return pci_register_driver(&radisys_pci_driver);
++}
++
++static void __exit radisys_exit(void)
++{
++ pci_unregister_driver(&radisys_pci_driver);
++}
++
++module_init(radisys_init);
++module_exit(radisys_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for Radisys R82600 controllers");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, radisys_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
+new file mode 100644
+index 0000000..4533b63
+--- /dev/null
++++ b/drivers/ata/pata_rz1000.c
+@@ -0,0 +1,205 @@
++/*
++ * RZ1000/1001 driver based upon
++ *
++ * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003
++ * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
++ * Principal Author: mlord at pobox.com (Mark Lord)
++ *
++ * See linux/MAINTAINERS for address of current maintainer.
++ *
++ * This file provides support for disabling the buggy read-ahead
++ * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_rz1000"
++#define DRV_VERSION "0.2.2"
++
++
++/**
++ * rz1000_prereset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generics
++ */
++
++static int rz1000_prereset(struct ata_port *ap)
++{
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++/**
++ * rz1000_error_handler - probe reset
++ * @ap: ATA port
++ *
++ * Perform the ATA standard reset sequence
++ */
++
++static void rz1000_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * rz1000_set_mode - mode setting function
++ * @ap: ATA interface
++ *
++ * Use a non standard set_mode function. We don't want to be tuned. We
++ * would prefer to be BIOS generic but for the fact our hardware is
++ * whacked out.
++ */
++
++static void rz1000_set_mode(struct ata_port *ap)
++{
++ int i;
++
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++ if (ata_dev_enabled(dev)) {
++ /* We don't really care */
++ dev->pio_mode = XFER_PIO_0;
++ dev->xfer_mode = XFER_PIO_0;
++ dev->xfer_shift = ATA_SHIFT_PIO;
++ dev->flags |= ATA_DFLAG_PIO;
++ }
++ }
++}
++
++
++static struct scsi_host_template rz1000_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations rz1000_port_ops = {
++ .set_mode = rz1000_set_mode,
++
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = rz1000_error_handler,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = rz1000_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * rz1000_init_one - Register RZ1000 ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in rz1000_pci_tbl matching with @pdev
++ *
++ * Configure an RZ1000 interface. This doesn't require much special
++ * handling except that we *MUST* kill the chipset readahead or the
++ * user may experience data corruption.
++ */
++
++static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_port_info *port_info[2];
++ u16 reg;
++ static struct ata_port_info info = {
++ .sht = &rz1000_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .port_ops = &rz1000_port_ops
++ };
++
++ if (!printed_version++)
++ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
++
++ /* Be exceptionally paranoid as we must be sure to apply the fix */
++ if (pci_read_config_word(pdev, 0x40, ®) != 0)
++ goto fail;
++ reg &= 0xDFFF;
++ if (pci_write_config_word(pdev, 0x40, reg) != 0)
++ goto fail;
++ printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n");
++
++ port_info[0] = &info;
++ port_info[1] = &info;
++ return ata_pci_init_one(pdev, port_info, 2);
++fail:
++ printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
++ /* Not safe to use so skip */
++ return -ENODEV;
++}
++
++static const struct pci_device_id pata_rz1000[] = {
++ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
++ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
++
++ { },
++};
++
++static struct pci_driver rz1000_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = pata_rz1000,
++ .probe = rz1000_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init rz1000_init(void)
++{
++ return pci_register_driver(&rz1000_pci_driver);
++}
++
++static void __exit rz1000_exit(void)
++{
++ pci_unregister_driver(&rz1000_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for RZ1000 PCI ATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, pata_rz1000);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(rz1000_init);
++module_exit(rz1000_exit);
++
+diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
+new file mode 100644
+index 0000000..067d9d2
+--- /dev/null
++++ b/drivers/ata/pata_sc1200.c
+@@ -0,0 +1,286 @@
++/*
++ * New ATA layer SC1200 driver Alan Cox <alan at redhat.com>
++ *
++ * TODO: Mode selection filtering
++ * TODO: Can't enable second channel until ATA core has serialize
++ * TODO: Needs custom DMA cleanup code
++ *
++ * Based very heavily on
++ *
++ * linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003
++ *
++ * Copyright (C) 2000-2002 Mark Lord <mlord at pobox.com>
++ * May be copied or modified under the terms of the GNU General Public License
++ *
++ * Development of this chipset driver was funded
++ * by the nice folks at National Semiconductor.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sc1200"
++#define DRV_VERSION "0.2.3"
++
++#define SC1200_REV_A 0x00
++#define SC1200_REV_B1 0x01
++#define SC1200_REV_B3 0x02
++#define SC1200_REV_C1 0x03
++#define SC1200_REV_D1 0x04
++
++/**
++ * sc1200_clock - PCI clock
++ *
++ * Return the PCI bus clocking for the SC1200 chipset configuration
++ * in use. We return 0 for 33MHz 1 for 48MHz and 2 for 66Mhz
++ */
++
++static int sc1200_clock(void)
++{
++ /* Magic registers that give us the chipset data */
++ u8 chip_id = inb(0x903C);
++ u8 silicon_rev = inb(0x903D);
++ u16 pci_clock;
++
++ if (chip_id == 0x04 && silicon_rev < SC1200_REV_B1)
++ return 0; /* 33 MHz mode */
++
++ /* Clock generator configuration 0x901E its 8/9 are the PCI clocking
++ 0/3 is 33Mhz 1 is 48 2 is 66 */
++
++ pci_clock = inw(0x901E);
++ pci_clock >>= 8;
++ pci_clock &= 0x03;
++ if (pci_clock == 3)
++ pci_clock = 0;
++ return pci_clock;
++}
++
++/**
++ * sc1200_set_piomode - PIO setup
++ * @ap: ATA interface
++ * @adev: device on the interface
++ *
++ * Set our PIO requirements. This is fairly simple on the SC1200
++ */
++
++static void sc1200_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u32 pio_timings[4][5] = {
++ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz
++ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz
++ {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz
++ {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131} // format1, 66Mhz
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 format;
++ unsigned int reg = 0x40 + 0x10 * ap->port_no;
++ int mode = adev->pio_mode - XFER_PIO_0;
++
++ pci_read_config_dword(pdev, reg + 4, &format);
++ format >>= 31;
++ format += sc1200_clock();
++ pci_write_config_dword(pdev, reg + 8 * adev->devno,
++ pio_timings[format][mode]);
++}
++
++/**
++ * sc1200_set_dmamode - DMA timing setup
++ * @ap: ATA interface
++ * @adev: Device being configured
++ *
++ * We cannot mix MWDMA and UDMA without reloading timings each switch
++ * master to slave.
++ */
++
++static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u32 udma_timing[3][3] = {
++ { 0x00921250, 0x00911140, 0x00911030 },
++ { 0x00932470, 0x00922260, 0x00922140 },
++ { 0x009436A1, 0x00933481, 0x00923261 }
++ };
++
++ static const u32 mwdma_timing[3][3] = {
++ { 0x00077771, 0x00012121, 0x00002020 },
++ { 0x000BBBB2, 0x00024241, 0x00013131 },
++ { 0x000FFFF3, 0x00035352, 0x00015151 }
++ };
++
++ int clock = sc1200_clock();
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned int reg = 0x40 + 0x10 * ap->port_no;
++ int mode = adev->dma_mode;
++ u32 format;
++
++ if (mode >= XFER_UDMA_0)
++ format = udma_timing[clock][mode - XFER_UDMA_0];
++ else
++ format = mwdma_timing[clock][mode - XFER_MW_DMA_0];
++
++ if (adev->devno == 0) {
++ u32 timings;
++
++ pci_read_config_dword(pdev, reg + 4, &timings);
++ timings &= 0x80000000UL;
++ timings |= format;
++ pci_write_config_dword(pdev, reg + 4, timings);
++ } else
++ pci_write_config_dword(pdev, reg + 12, format);
++}
++
++/**
++ * sc1200_qc_issue_prot - command issue
++ * @qc: command pending
++ *
++ * Called when the libata layer is about to issue a command. We wrap
++ * this interface so that we can load the correct ATA timings if
++ * neccessary. Specifically we have a problem that there is only
++ * one MWDMA/UDMA bit.
++ */
++
++static unsigned int sc1200_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_device *adev = qc->dev;
++ struct ata_device *prev = ap->private_data;
++
++ /* See if the DMA settings could be wrong */
++ if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
++ /* Maybe, but do the channels match MWDMA/UDMA ? */
++ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
++ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
++ /* Switch the mode bits */
++ sc1200_set_dmamode(ap, adev);
++ }
++
++ return ata_qc_issue_prot(qc);
++}
++
++static struct scsi_host_template sc1200_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations sc1200_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sc1200_set_piomode,
++ .set_dmamode = sc1200_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = ata_bmdma_error_handler,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = sc1200_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * sc1200_init_one - Initialise an SC1200
++ * @dev: PCI device
++ * @id: Entry in match table
++ *
++ * Just throw the needed data at the libata helper and it does all
++ * our work.
++ */
++
++static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &sc1200_sht,
++ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x07,
++ .port_ops = &sc1200_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++
++ /* Can't enable port 2 yet, see top comments */
++ return ata_pci_init_one(dev, port_info, 1);
++}
++
++static const struct pci_device_id sc1200[] = {
++ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
++
++ { },
++};
++
++static struct pci_driver sc1200_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sc1200,
++ .probe = sc1200_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init sc1200_init(void)
++{
++ return pci_register_driver(&sc1200_pci_driver);
++}
++
++static void __exit sc1200_exit(void)
++{
++ pci_unregister_driver(&sc1200_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox, Mark Lord");
++MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sc1200);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(sc1200_init);
++module_exit(sc1200_exit);
+diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
+new file mode 100644
+index 0000000..5bbf76e
+--- /dev/null
++++ b/drivers/ata/pata_serverworks.c
+@@ -0,0 +1,590 @@
++/*
++ * ata-serverworks.c - Serverworks PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based upon
++ *
++ * serverworks.c
++ *
++ * Copyright (C) 1998-2000 Michel Aubry
++ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
++ * Copyright (C) 1998-2000 Andre Hedrick <andre at linux-ide.org>
++ * Portions copyright (c) 2001 Sun Microsystems
++ *
++ *
++ * RCC/ServerWorks IDE driver for Linux
++ *
++ * OSB4: `Open South Bridge' IDE Interface (fn 1)
++ * supports UDMA mode 2 (33 MB/s)
++ *
++ * CSB5: `Champion South Bridge' IDE Interface (fn 1)
++ * all revisions support UDMA mode 4 (66 MB/s)
++ * revision A2.0 and up support UDMA mode 5 (100 MB/s)
++ *
++ * *** The CSB5 does not provide ANY register ***
++ * *** to detect 80-conductor cable presence. ***
++ *
++ * CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
++ *
++ * Documentation:
++ * Available under NDA only. Errata info very hard to get.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_serverworks"
++#define DRV_VERSION "0.3.7"
++
++#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
++#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
++
++/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
++ * can overrun their FIFOs when used with the CSB5 */
++
++static const char *csb_bad_ata100[] = {
++ "ST320011A",
++ "ST340016A",
++ "ST360021A",
++ "ST380021A",
++ NULL
++};
++
++/**
++ * dell_cable - Dell serverworks cable detection
++ * @ap: ATA port to do cable detect
++ *
++ * Dell hide the 40/80 pin select for their interfaces in the top two
++ * bits of the subsystem ID.
++ */
++
++static int dell_cable(struct ata_port *ap) {
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
++ return ATA_CBL_PATA80;
++ return ATA_CBL_PATA40;
++}
++
++/**
++ * sun_cable - Sun Cobalt 'Alpine' cable detection
++ * @ap: ATA port to do cable select
++ *
++ * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the
++ * subsystem ID the same as dell. We could use one function but we may
++ * need to extend the Dell one in future
++ */
++
++static int sun_cable(struct ata_port *ap) {
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
++ return ATA_CBL_PATA80;
++ return ATA_CBL_PATA40;
++}
++
++/**
++ * osb4_cable - OSB4 cable detect
++ * @ap: ATA port to check
++ *
++ * The OSB4 isn't UDMA66 capable so this is easy
++ */
++
++static int osb4_cable(struct ata_port *ap) {
++ return ATA_CBL_PATA40;
++}
++
++/**
++ * csb4_cable - CSB5/6 cable detect
++ * @ap: ATA port to check
++ *
++ * Serverworks default arrangement is to use the drive side detection
++ * only.
++ */
++
++static int csb_cable(struct ata_port *ap) {
++ return ATA_CBL_PATA80;
++}
++
++struct sv_cable_table {
++ int device;
++ int subvendor;
++ int (*cable_detect)(struct ata_port *ap);
++};
++
++/*
++ * Note that we don't copy the old serverworks code because the old
++ * code contains obvious mistakes
++ */
++
++static struct sv_cable_table cable_detect[] = {
++ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, osb4_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable },
++ { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable },
++ { }
++};
++
++/**
++ * serverworks_pre_reset - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection according to the device and subvendor
++ * identifications
++ */
++
++static int serverworks_pre_reset(struct ata_port *ap) {
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct sv_cable_table *cb = cable_detect;
++
++ while(cb->device) {
++ if (cb->device == pdev->device &&
++ (cb->subvendor == pdev->subsystem_vendor ||
++ cb->subvendor == PCI_ANY_ID)) {
++ ap->cbl = cb->cable_detect(ap);
++ return ata_std_prereset(ap);
++ }
++ cb++;
++ }
++
++ BUG();
++ return -1; /* kill compiler warning */
++}
++
++static void serverworks_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * serverworks_is_csb - Check for CSB or OSB
++ * @pdev: PCI device to check
++ *
++ * Returns true if the device being checked is known to be a CSB
++ * series device.
++ */
++
++static u8 serverworks_is_csb(struct pci_dev *pdev)
++{
++ switch (pdev->device) {
++ case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
++ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
++ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
++ case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
++ return 1;
++ default:
++ break;
++ }
++ return 0;
++}
++
++/**
++ * serverworks_osb4_filter - mode selection filter
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Filter the offered modes for the device to apply controller
++ * specific rules. OSB4 requires no UDMA for disks due to a FIFO
++ * bug we hit.
++ */
++
++static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
++{
++ if (adev->class == ATA_DEV_ATA)
++ mask &= ~ATA_MASK_UDMA;
++ return ata_pci_default_filter(ap, adev, mask);
++}
++
++
++/**
++ * serverworks_csb_filter - mode selection filter
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Check the blacklist and disable UDMA5 if matched
++ */
++
++static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
++{
++ const char *p;
++ char model_num[40];
++ int len, i;
++
++ /* Disk, UDMA */
++ if (adev->class != ATA_DEV_ATA)
++ return ata_pci_default_filter(ap, adev, mask);
++
++ /* Actually do need to check */
++ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
++ /* Precuationary - why not do this in the libata core ?? */
++
++ len = strlen(model_num);
++ while ((len > 0) && (model_num[len - 1] == ' ')) {
++ len--;
++ model_num[len] = 0;
++ }
++
++ for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
++ if (!strncmp(p, model_num, len))
++ mask &= ~(0x1F << ATA_SHIFT_UDMA);
++ }
++ return ata_pci_default_filter(ap, adev, mask);
++}
++
++
++/**
++ * serverworks_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the OSB4/CSB5 timing registers for PIO. The PIO register
++ * load is done as a simple lookup.
++ */
++static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
++ int offset = 1 + (2 * ap->port_no) - adev->devno;
++ int devbits = (2 * ap->port_no + adev->devno) * 4;
++ u16 csb5_pio;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int pio = adev->pio_mode - XFER_PIO_0;
++
++ pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]);
++
++ /* The OSB4 just requires the timing but the CSB series want the
++ mode number as well */
++ if (serverworks_is_csb(pdev)) {
++ pci_read_config_word(pdev, 0x4A, &csb5_pio);
++ csb5_pio &= ~(0x0F << devbits);
++ pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits));
++ }
++}
++
++/**
++ * serverworks_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5
++ * chipset. The MWDMA mode values are pulled from a lookup table
++ * while the chipset uses mode number for UDMA.
++ */
++
++static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static const u8 dma_mode[] = { 0x77, 0x21, 0x20 };
++ int offset = 1 + 2 * ap->port_no - adev->devno;
++ int devbits = (2 * ap->port_no + adev->devno);
++ u8 ultra;
++ u8 ultra_cfg;
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ pci_read_config_byte(pdev, 0x54, &ultra_cfg);
++
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ pci_write_config_byte(pdev, 0x44 + offset, 0x20);
++
++ pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra);
++ ultra &= ~(0x0F << (ap->port_no * 4));
++ ultra |= (adev->dma_mode - XFER_UDMA_0)
++ << (ap->port_no * 4);
++ pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra);
++
++ ultra_cfg |= (1 << devbits);
++ } else {
++ pci_write_config_byte(pdev, 0x44 + offset,
++ dma_mode[adev->dma_mode - XFER_MW_DMA_0]);
++ ultra_cfg &= ~(1 << devbits);
++ }
++ pci_write_config_byte(pdev, 0x54, ultra_cfg);
++}
++
++static struct scsi_host_template serverworks_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations serverworks_osb4_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = serverworks_set_piomode,
++ .set_dmamode = serverworks_set_dmamode,
++ .mode_filter = serverworks_osb4_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = serverworks_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations serverworks_csb_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = serverworks_set_piomode,
++ .set_dmamode = serverworks_set_dmamode,
++ .mode_filter = serverworks_csb_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = serverworks_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int serverworks_fixup_osb4(struct pci_dev *pdev)
++{
++ u32 reg;
++ struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
++ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
++ if (isa_dev) {
++ pci_read_config_dword(isa_dev, 0x64, ®);
++ reg &= ~0x00002000; /* disable 600ns interrupt mask */
++ if (!(reg & 0x00004000))
++ printk(KERN_DEBUG DRV_NAME ": UDMA not BIOS enabled.\n");
++ reg |= 0x00004000; /* enable UDMA/33 support */
++ pci_write_config_dword(isa_dev, 0x64, reg);
++ pci_dev_put(isa_dev);
++ return 0;
++ }
++ printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n");
++ return -ENODEV;
++}
++
++static int serverworks_fixup_csb(struct pci_dev *pdev)
++{
++ u8 rev;
++ u8 btr;
++
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
++
++ /* Third Channel Test */
++ if (!(PCI_FUNC(pdev->devfn) & 1)) {
++ struct pci_dev * findev = NULL;
++ u32 reg4c = 0;
++ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
++ PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
++ if (findev) {
++ pci_read_config_dword(findev, 0x4C, ®4c);
++ reg4c &= ~0x000007FF;
++ reg4c |= 0x00000040;
++ reg4c |= 0x00000020;
++ pci_write_config_dword(findev, 0x4C, reg4c);
++ pci_dev_put(findev);
++ }
++ } else {
++ struct pci_dev * findev = NULL;
++ u8 reg41 = 0;
++
++ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
++ PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
++ if (findev) {
++ pci_read_config_byte(findev, 0x41, ®41);
++ reg41 &= ~0x40;
++ pci_write_config_byte(findev, 0x41, reg41);
++ pci_dev_put(findev);
++ }
++ }
++ /* setup the UDMA Control register
++ *
++ * 1. clear bit 6 to enable DMA
++ * 2. enable DMA modes with bits 0-1
++ * 00 : legacy
++ * 01 : udma2
++ * 10 : udma2/udma4
++ * 11 : udma2/udma4/udma5
++ */
++ pci_read_config_byte(pdev, 0x5A, &btr);
++ btr &= ~0x40;
++ if (!(PCI_FUNC(pdev->devfn) & 1))
++ btr |= 0x2;
++ else
++ btr |= (rev >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
++ pci_write_config_byte(pdev, 0x5A, btr);
++
++ return btr;
++}
++
++static void serverworks_fixup_ht1000(struct pci_dev *pdev)
++{
++ u8 btr;
++ /* Setup HT1000 SouthBridge Controller - Single Channel Only */
++ pci_read_config_byte(pdev, 0x5A, &btr);
++ btr &= ~0x40;
++ btr |= 0x3;
++ pci_write_config_byte(pdev, 0x5A, btr);
++}
++
++
++static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ int ports = 2;
++ static struct ata_port_info info[4] = {
++ { /* OSB4 */
++ .sht = &serverworks_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x07,
++ .port_ops = &serverworks_osb4_port_ops
++ }, { /* OSB4 no UDMA */
++ .sht = &serverworks_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x00,
++ .port_ops = &serverworks_osb4_port_ops
++ }, { /* CSB5 */
++ .sht = &serverworks_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f,
++ .port_ops = &serverworks_csb_port_ops
++ }, { /* CSB5 - later revisions*/
++ .sht = &serverworks_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &serverworks_csb_port_ops
++ }
++ };
++ static struct ata_port_info *port_info[2];
++ struct ata_port_info *devinfo = &info[id->driver_data];
++
++ /* Force master latency timer to 64 PCI clocks */
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
++
++ /* OSB4 : South Bridge and IDE */
++ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
++ /* Select non UDMA capable OSB4 if we can't do fixups */
++ if ( serverworks_fixup_osb4(pdev) < 0)
++ devinfo = &info[1];
++ }
++ /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
++ else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
++ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
++ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
++
++ /* If the returned btr is the newer revision then
++ select the right info block */
++ if (serverworks_fixup_csb(pdev) == 3)
++ devinfo = &info[3];
++
++ /* Is this the 3rd channel CSB6 IDE ? */
++ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)
++ ports = 1;
++ }
++ /* setup HT1000E */
++ else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
++ serverworks_fixup_ht1000(pdev);
++
++ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
++ ata_pci_clear_simplex(pdev);
++
++ port_info[0] = port_info[1] = devinfo;
++ return ata_pci_init_one(pdev, port_info, ports);
++}
++
++static const struct pci_device_id serverworks[] = {
++ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
++ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
++ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
++ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
++ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
++
++ { },
++};
++
++static struct pci_driver serverworks_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = serverworks,
++ .probe = serverworks_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init serverworks_init(void)
++{
++ return pci_register_driver(&serverworks_pci_driver);
++}
++
++static void __exit serverworks_exit(void)
++{
++ pci_unregister_driver(&serverworks_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, serverworks);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(serverworks_init);
++module_exit(serverworks_exit);
+diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
+new file mode 100644
+index 0000000..4a2b72b
+--- /dev/null
++++ b/drivers/ata/pata_sil680.c
+@@ -0,0 +1,380 @@
++/*
++ * pata_sil680.c - SIL680 PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based upon
++ *
++ * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003
++ *
++ * Copyright (C) 2001-2002 Andre Hedrick <andre at linux-ide.org>
++ * Copyright (C) 2003 Red Hat <alan at redhat.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public License
++ *
++ * Documentation publically available.
++ *
++ * If you have strange problems with nVidia chipset systems please
++ * see the SI support documentation and update your system BIOS
++ * if neccessary
++ *
++ * TODO
++ * If we know all our devices are LBA28 (or LBA28 sized) we could use
++ * the command fifo mode.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_sil680"
++#define DRV_VERSION "0.3.2"
++
++/**
++ * sil680_selreg - return register base
++ * @hwif: interface
++ * @r: config offset
++ *
++ * Turn a config register offset into the right address in either
++ * PCI space or MMIO space to access the control register in question
++ * Thankfully this is a configuration operation so isnt performance
++ * criticial.
++ */
++
++static unsigned long sil680_selreg(struct ata_port *ap, int r)
++{
++ unsigned long base = 0xA0 + r;
++ base += (ap->port_no << 4);
++ return base;
++}
++
++/**
++ * sil680_seldev - return register base
++ * @hwif: interface
++ * @r: config offset
++ *
++ * Turn a config register offset into the right address in either
++ * PCI space or MMIO space to access the control register in question
++ * including accounting for the unit shift.
++ */
++
++static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
++{
++ unsigned long base = 0xA0 + r;
++ base += (ap->port_no << 4);
++ base |= adev->devno ? 2 : 0;
++ return base;
++}
++
++
++/**
++ * sil680_cable_detect - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection. The SIL680 stores this in PCI config
++ * space for us.
++ */
++
++static int sil680_cable_detect(struct ata_port *ap) {
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned long addr = sil680_selreg(ap, 0);
++ u8 ata66;
++ pci_read_config_byte(pdev, addr, &ata66);
++ if (ata66 & 1)
++ return ATA_CBL_PATA80;
++ else
++ return ATA_CBL_PATA40;
++}
++
++static int sil680_pre_reset(struct ata_port *ap)
++{
++ ap->cbl = sil680_cable_detect(ap);
++ return ata_std_prereset(ap);
++}
++
++/**
++ * sil680_bus_reset - reset the SIL680 bus
++ * @ap: ATA port to reset
++ *
++ * Perform the SIL680 housekeeping when doing an ATA bus reset
++ */
++
++static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned long addr = sil680_selreg(ap, 0);
++ u8 reset;
++
++ pci_read_config_byte(pdev, addr, &reset);
++ pci_write_config_byte(pdev, addr, reset | 0x03);
++ udelay(25);
++ pci_write_config_byte(pdev, addr, reset);
++ return ata_std_softreset(ap, classes);
++}
++
++static void sil680_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset);
++}
++
++/**
++ * sil680_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the SIL680 registers for PIO mode. Note that the task speed
++ * registers are shared between the devices so we must pick the lowest
++ * mode for command work.
++ */
++
++static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 };
++ static u16 speed_t[5] = { 0x328A, 0x1281, 0x1281, 0x10C3, 0x10C1 };
++
++ unsigned long tfaddr = sil680_selreg(ap, 0x02);
++ unsigned long addr = sil680_seldev(ap, adev, 0x04);
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int pio = adev->pio_mode - XFER_PIO_0;
++ int lowest_pio = pio;
++ u16 reg;
++
++ struct ata_device *pair = ata_dev_pair(adev);
++
++ if (pair != NULL && adev->pio_mode > pair->pio_mode)
++ lowest_pio = pair->pio_mode - XFER_PIO_0;
++
++ pci_write_config_word(pdev, addr, speed_p[pio]);
++ pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]);
++
++ pci_read_config_word(pdev, tfaddr-2, ®);
++ reg &= ~0x0200; /* Clear IORDY */
++ if (ata_pio_need_iordy(adev))
++ reg |= 0x0200; /* Enable IORDY */
++ pci_write_config_word(pdev, tfaddr-2, reg);
++}
++
++/**
++ * sil680_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Program the MWDMA/UDMA modes for the sil680 k
++ * chipset. The MWDMA mode values are pulled from a lookup table
++ * while the chipset uses mode number for UDMA.
++ */
++
++static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ static u8 ultra_table[2][7] = {
++ { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01, 0xFF }, /* 100MHz */
++ { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }, /* 133Mhz */
++ };
++ static u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned long ma = sil680_seldev(ap, adev, 0x08);
++ unsigned long ua = sil680_seldev(ap, adev, 0x0C);
++ unsigned long addr_mask = 0x80 + 4 * ap->port_no;
++ int port_shift = adev->devno * 4;
++ u8 scsc, mode;
++ u16 multi, ultra;
++
++ pci_read_config_byte(pdev, 0x8A, &scsc);
++ pci_read_config_byte(pdev, addr_mask, &mode);
++ pci_read_config_word(pdev, ma, &multi);
++ pci_read_config_word(pdev, ua, &ultra);
++
++ /* Mask timing bits */
++ ultra &= ~0x3F;
++ mode &= ~(0x03 << port_shift);
++
++ /* Extract scsc */
++ scsc = (scsc & 0x30) ? 1: 0;
++
++ if (adev->dma_mode >= XFER_UDMA_0) {
++ multi = 0x10C1;
++ ultra |= ultra_table[scsc][adev->dma_mode - XFER_UDMA_0];
++ mode |= (0x03 << port_shift);
++ } else {
++ multi = dma_table[adev->dma_mode - XFER_MW_DMA_0];
++ mode |= (0x02 << port_shift);
++ }
++ pci_write_config_byte(pdev, addr_mask, mode);
++ pci_write_config_word(pdev, ma, multi);
++ pci_write_config_word(pdev, ua, ultra);
++}
++
++static struct scsi_host_template sil680_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations sil680_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sil680_set_piomode,
++ .set_dmamode = sil680_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = sil680_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &sil680_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &sil680_port_ops
++ };
++ static struct ata_port_info info_slow = {
++ .sht = &sil680_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &sil680_port_ops
++ };
++ static struct ata_port_info *port_info[2] = {&info, &info};
++ static int printed_version;
++ u32 class_rev = 0;
++ u8 tmpbyte = 0;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
++ class_rev &= 0xff;
++ /* FIXME: double check */
++ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
++
++ pci_write_config_byte(pdev, 0x80, 0x00);
++ pci_write_config_byte(pdev, 0x84, 0x00);
++
++ pci_read_config_byte(pdev, 0x8A, &tmpbyte);
++
++ printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n",
++ tmpbyte & 1, tmpbyte & 0x30);
++
++ switch(tmpbyte & 0x30) {
++ case 0x00:
++ /* 133 clock attempt to force it on */
++ pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10);
++ break;
++ case 0x30:
++ /* if clocking is disabled */
++ /* 133 clock attempt to force it on */
++ pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20);
++ break;
++ case 0x10:
++ /* 133 already */
++ break;
++ case 0x20:
++ /* BIOS set PCI x2 clocking */
++ break;
++ }
++
++ pci_read_config_byte(pdev, 0x8A, &tmpbyte);
++ printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n",
++ tmpbyte & 1, tmpbyte & 0x30);
++ if ((tmpbyte & 0x30) == 0)
++ port_info[0] = port_info[1] = &info_slow;
++
++ pci_write_config_byte(pdev, 0xA1, 0x72);
++ pci_write_config_word(pdev, 0xA2, 0x328A);
++ pci_write_config_dword(pdev, 0xA4, 0x62DD62DD);
++ pci_write_config_dword(pdev, 0xA8, 0x43924392);
++ pci_write_config_dword(pdev, 0xAC, 0x40094009);
++ pci_write_config_byte(pdev, 0xB1, 0x72);
++ pci_write_config_word(pdev, 0xB2, 0x328A);
++ pci_write_config_dword(pdev, 0xB4, 0x62DD62DD);
++ pci_write_config_dword(pdev, 0xB8, 0x43924392);
++ pci_write_config_dword(pdev, 0xBC, 0x40094009);
++
++ switch(tmpbyte & 0x30) {
++ case 0x00: printk(KERN_INFO "sil680: 100MHz clock.\n");break;
++ case 0x10: printk(KERN_INFO "sil680: 133MHz clock.\n");break;
++ case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break;
++ /* This last case is _NOT_ ok */
++ case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n");
++ return -EIO;
++ }
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id sil680[] = {
++ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
++
++ { },
++};
++
++static struct pci_driver sil680_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sil680,
++ .probe = sil680_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init sil680_init(void)
++{
++ return pci_register_driver(&sil680_pci_driver);
++}
++
++static void __exit sil680_exit(void)
++{
++ pci_unregister_driver(&sil680_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for SI680 PATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sil680);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(sil680_init);
++module_exit(sil680_exit);
+diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
+new file mode 100644
+index 0000000..b9ffafb
+--- /dev/null
++++ b/drivers/ata/pata_sis.c
+@@ -0,0 +1,1022 @@
++/*
++ * pata_sis.c - SiS ATA driver
++ *
++ * (C) 2005 Red Hat <alan at redhat.com>
++ *
++ * Based upon linux/drivers/ide/pci/sis5513.c
++ * Copyright (C) 1999-2000 Andre Hedrick <andre at linux-ide.org>
++ * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton at inet6.fr>, Maintainer
++ * Copyright (C) 2003 Vojtech Pavlik <vojtech at suse.cz>
++ * SiS Taiwan : for direct support and hardware.
++ * Daniela Engert : for initial ATA100 advices and numerous others.
++ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt :
++ * for checking code correctness, providing patches.
++ * Original tests and design on the SiS620 chipset.
++ * ATA100 tests and design on the SiS735 chipset.
++ * ATA16/33 support from specs
++ * ATA133 support for SiS961/962 by L.C. Chang <lcchang at sis.com.tw>
++ *
++ *
++ * TODO
++ * Check MWDMA on drives that don't support MWDMA speed pio cycles ?
++ * More Testing
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <linux/ata.h>
++
++#define DRV_NAME "pata_sis"
++#define DRV_VERSION "0.4.4"
++
++struct sis_chipset {
++ u16 device; /* PCI host ID */
++ struct ata_port_info *info; /* Info block */
++ /* Probably add family, cable detect type etc here to clean
++ up code later */
++};
++
++/**
++ * sis_port_base - return PCI configuration base for dev
++ * @adev: device
++ *
++ * Returns the base of the PCI configuration registers for this port
++ * number.
++ */
++
++static int sis_port_base(struct ata_device *adev)
++{
++ return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno);
++}
++
++/**
++ * sis_133_pre_reset - check for 40/80 pin
++ * @ap: Port
++ *
++ * Perform cable detection for the later UDMA133 capable
++ * SiS chipset.
++ */
++
++static int sis_133_pre_reset(struct ata_port *ap)
++{
++ static const struct pci_bits sis_enable_bits[] = {
++ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
++ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u16 tmp;
++
++ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
++ return -ENOENT;
++
++ /* The top bit of this register is the cable detect bit */
++ pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
++ if (tmp & 0x8000)
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++
++ return ata_std_prereset(ap);
++}
++
++/**
++ * sis_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_133_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, sis_133_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++
++/**
++ * sis_66_pre_reset - check for 40/80 pin
++ * @ap: Port
++ *
++ * Perform cable detection on the UDMA66, UDMA100 and early UDMA133
++ * SiS IDE controllers.
++ */
++
++static int sis_66_pre_reset(struct ata_port *ap)
++{
++ static const struct pci_bits sis_enable_bits[] = {
++ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
++ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 tmp;
++
++ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
++ ata_port_disable(ap);
++ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
++ return 0;
++ }
++ /* Older chips keep cable detect in bits 4/5 of reg 0x48 */
++ pci_read_config_byte(pdev, 0x48, &tmp);
++ tmp >>= ap->port_no;
++ if (tmp & 0x10)
++ ap->cbl = ATA_CBL_PATA40;
++ else
++ ap->cbl = ATA_CBL_PATA80;
++
++ return ata_std_prereset(ap);
++}
++
++/**
++ * sis_66_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ * @classes:
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_66_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, sis_66_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * sis_old_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int sis_old_pre_reset(struct ata_port *ap)
++{
++ static const struct pci_bits sis_enable_bits[] = {
++ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
++ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
++ ata_port_disable(ap);
++ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
++ return 0;
++ }
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++
++/**
++ * sis_old_error_handler - Probe specified port on PATA host controller
++ * @ap: Port to probe
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_old_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * sis_set_fifo - Set RWP fifo bits for this device
++ * @ap: Port
++ * @adev: Device
++ *
++ * SIS chipsets implement prefetch/postwrite bits for each device
++ * on both channels. This functionality is not ATAPI compatible and
++ * must be configured according to the class of device present
++ */
++
++static void sis_set_fifo(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 fifoctrl;
++ u8 mask = 0x11;
++
++ mask <<= (2 * ap->port_no);
++ mask <<= adev->devno;
++
++ /* This holds various bits including the FIFO control */
++ pci_read_config_byte(pdev, 0x4B, &fifoctrl);
++ fifoctrl &= ~mask;
++
++ /* Enable for ATA (disk) only */
++ if (adev->class == ATA_DEV_ATA)
++ fifoctrl |= mask;
++ pci_write_config_byte(pdev, 0x4B, fifoctrl);
++}
++
++/**
++ * sis_old_set_piomode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring for.
++ *
++ * Set PIO mode for device, in host controller PCI config space. This
++ * function handles PIO set up for all chips that are pre ATA100 and
++ * also early ATA100 devices.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int port = sis_port_base(adev);
++ u8 t1, t2;
++ int speed = adev->pio_mode - XFER_PIO_0;
++
++ const u8 active[] = { 0x00, 0x07, 0x04, 0x03, 0x01 };
++ const u8 recovery[] = { 0x00, 0x06, 0x04, 0x03, 0x03 };
++
++ sis_set_fifo(ap, adev);
++
++ pci_read_config_byte(pdev, port, &t1);
++ pci_read_config_byte(pdev, port + 1, &t2);
++
++ t1 &= ~0x0F; /* Clear active/recovery timings */
++ t2 &= ~0x07;
++
++ t1 |= active[speed];
++ t2 |= recovery[speed];
++
++ pci_write_config_byte(pdev, port, t1);
++ pci_write_config_byte(pdev, port + 1, t2);
++}
++
++/**
++ * sis_100_set_pioode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring for.
++ *
++ * Set PIO mode for device, in host controller PCI config space. This
++ * function handles PIO set up for ATA100 devices and early ATA133.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int port = sis_port_base(adev);
++ int speed = adev->pio_mode - XFER_PIO_0;
++
++ const u8 actrec[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
++
++ sis_set_fifo(ap, adev);
++
++ pci_write_config_byte(pdev, port, actrec[speed]);
++}
++
++/**
++ * sis_133_set_pioode - Initialize host controller PATA PIO timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device we are configuring for.
++ *
++ * Set PIO mode for device, in host controller PCI config space. This
++ * function handles PIO set up for the later ATA133 devices.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int port = 0x40;
++ u32 t1;
++ u32 reg54;
++ int speed = adev->pio_mode - XFER_PIO_0;
++
++ const u32 timing133[] = {
++ 0x28269000, /* Recovery << 24 | Act << 16 | Ini << 12 */
++ 0x0C266000,
++ 0x04263000,
++ 0x0C0A3000,
++ 0x05093000
++ };
++ const u32 timing100[] = {
++ 0x1E1C6000, /* Recovery << 24 | Act << 16 | Ini << 12 */
++ 0x091C4000,
++ 0x031C2000,
++ 0x09072000,
++ 0x04062000
++ };
++
++ sis_set_fifo(ap, adev);
++
++ /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
++ pci_read_config_dword(pdev, 0x54, ®54);
++ if (reg54 & 0x40000000)
++ port = 0x70;
++ port += 8 * ap->port_no + 4 * adev->devno;
++
++ pci_read_config_dword(pdev, port, &t1);
++ t1 &= 0xC0C00FFF; /* Mask out timing */
++
++ if (t1 & 0x08) /* 100 or 133 ? */
++ t1 |= timing133[speed];
++ else
++ t1 |= timing100[speed];
++ pci_write_config_byte(pdev, port, t1);
++}
++
++/**
++ * sis_old_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ *
++ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
++ * Handles pre UDMA and UDMA33 devices. Supports MWDMA as well unlike
++ * the old ide/pci driver.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int speed = adev->dma_mode - XFER_MW_DMA_0;
++ int drive_pci = sis_port_base(adev);
++ u16 timing;
++
++ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
++ const u16 udma_bits[] = { 0xE000, 0xC000, 0xA000 };
++
++ pci_read_config_word(pdev, drive_pci, &timing);
++
++ if (adev->dma_mode < XFER_UDMA_0) {
++ /* bits 3-0 hold recovery timing bits 8-10 active timing and
++ the higer bits are dependant on the device */
++ timing &= ~ 0x870F;
++ timing |= mwdma_bits[speed];
++ pci_write_config_word(pdev, drive_pci, timing);
++ } else {
++ /* Bit 15 is UDMA on/off, bit 13-14 are cycle time */
++ speed = adev->dma_mode - XFER_UDMA_0;
++ timing &= ~0x6000;
++ timing |= udma_bits[speed];
++ }
++}
++
++/**
++ * sis_66_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ *
++ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
++ * Handles UDMA66 and early UDMA100 devices. Supports MWDMA as well unlike
++ * the old ide/pci driver.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int speed = adev->dma_mode - XFER_MW_DMA_0;
++ int drive_pci = sis_port_base(adev);
++ u16 timing;
++
++ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
++ const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000};
++
++ pci_read_config_word(pdev, drive_pci, &timing);
++
++ if (adev->dma_mode < XFER_UDMA_0) {
++ /* bits 3-0 hold recovery timing bits 8-10 active timing and
++ the higer bits are dependant on the device, bit 15 udma */
++ timing &= ~ 0x870F;
++ timing |= mwdma_bits[speed];
++ } else {
++ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
++ speed = adev->dma_mode - XFER_UDMA_0;
++ timing &= ~0x6000;
++ timing |= udma_bits[speed];
++ }
++ pci_write_config_word(pdev, drive_pci, timing);
++}
++
++/**
++ * sis_100_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ *
++ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
++ * Handles UDMA66 and early UDMA100 devices.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int speed = adev->dma_mode - XFER_MW_DMA_0;
++ int drive_pci = sis_port_base(adev);
++ u16 timing;
++
++ const u16 udma_bits[] = { 0x8B00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
++
++ pci_read_config_word(pdev, drive_pci, &timing);
++
++ if (adev->dma_mode < XFER_UDMA_0) {
++ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
++ } else {
++ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
++ speed = adev->dma_mode - XFER_UDMA_0;
++ timing &= ~0x0F00;
++ timing |= udma_bits[speed];
++ }
++ pci_write_config_word(pdev, drive_pci, timing);
++}
++
++/**
++ * sis_133_early_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ *
++ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
++ * Handles early SiS 961 bridges. Supports MWDMA as well unlike
++ * the old ide/pci driver.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int speed = adev->dma_mode - XFER_MW_DMA_0;
++ int drive_pci = sis_port_base(adev);
++ u16 timing;
++
++ const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
++
++ pci_read_config_word(pdev, drive_pci, &timing);
++
++ if (adev->dma_mode < XFER_UDMA_0) {
++ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
++ } else {
++ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
++ speed = adev->dma_mode - XFER_UDMA_0;
++ timing &= ~0x0F00;
++ timing |= udma_bits[speed];
++ }
++ pci_write_config_word(pdev, drive_pci, timing);
++}
++
++/**
++ * sis_133_set_dmamode - Initialize host controller PATA DMA timings
++ * @ap: Port whose timings we are configuring
++ * @adev: Device to program
++ *
++ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
++ * Handles early SiS 961 bridges. Supports MWDMA as well unlike
++ * the old ide/pci driver.
++ *
++ * LOCKING:
++ * None (inherited from caller).
++ */
++
++static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ int speed = adev->dma_mode - XFER_MW_DMA_0;
++ int port = 0x40;
++ u32 t1;
++ u32 reg54;
++
++ /* bits 4- cycle time 8 - cvs time */
++ const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
++ const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
++
++ /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
++ pci_read_config_dword(pdev, 0x54, ®54);
++ if (reg54 & 0x40000000)
++ port = 0x70;
++ port += (8 * ap->port_no) + (4 * adev->devno);
++
++ pci_read_config_dword(pdev, port, &t1);
++
++ if (adev->dma_mode < XFER_UDMA_0) {
++ t1 &= ~0x00000004;
++ /* FIXME: need data sheet to add MWDMA here. Also lacking on
++ ide/pci driver */
++ } else {
++ speed = adev->dma_mode - XFER_UDMA_0;
++ /* if & 8 no UDMA133 - need info for ... */
++ t1 &= ~0x00000FF0;
++ t1 |= 0x00000004;
++ if (t1 & 0x08)
++ t1 |= timing_u133[speed];
++ else
++ t1 |= timing_u100[speed];
++ }
++ pci_write_config_dword(pdev, port, t1);
++}
++
++static struct scsi_host_template sis_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations sis_133_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sis_133_set_piomode,
++ .set_dmamode = sis_133_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = sis_133_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations sis_133_early_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sis_100_set_piomode,
++ .set_dmamode = sis_133_early_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = sis_66_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations sis_100_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sis_100_set_piomode,
++ .set_dmamode = sis_100_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = sis_66_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations sis_66_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sis_old_set_piomode,
++ .set_dmamode = sis_66_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = sis_66_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations sis_old_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sis_old_set_piomode,
++ .set_dmamode = sis_old_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = sis_old_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static struct ata_port_info sis_info = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07,
++ .udma_mask = 0,
++ .port_ops = &sis_old_ops,
++};
++static struct ata_port_info sis_info33 = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07,
++ .udma_mask = ATA_UDMA2, /* UDMA 33 */
++ .port_ops = &sis_old_ops,
++};
++static struct ata_port_info sis_info66 = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = ATA_UDMA4, /* UDMA 66 */
++ .port_ops = &sis_66_ops,
++};
++static struct ata_port_info sis_info100 = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = ATA_UDMA5,
++ .port_ops = &sis_100_ops,
++};
++static struct ata_port_info sis_info100_early = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .udma_mask = ATA_UDMA5,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .port_ops = &sis_66_ops,
++};
++static struct ata_port_info sis_info133 = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = ATA_UDMA6,
++ .port_ops = &sis_133_ops,
++};
++static struct ata_port_info sis_info133_early = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = ATA_UDMA6,
++ .port_ops = &sis_133_early_ops,
++};
++
++
++static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
++{
++ u16 regw;
++ u8 reg;
++
++ if (sis->info == &sis_info133) {
++ pci_read_config_word(pdev, 0x50, ®w);
++ if (regw & 0x08)
++ pci_write_config_word(pdev, 0x50, regw & ~0x08);
++ pci_read_config_word(pdev, 0x52, ®w);
++ if (regw & 0x08)
++ pci_write_config_word(pdev, 0x52, regw & ~0x08);
++ return;
++ }
++
++ if (sis->info == &sis_info133_early || sis->info == &sis_info100) {
++ /* Fix up latency */
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
++ /* Set compatibility bit */
++ pci_read_config_byte(pdev, 0x49, ®);
++ if (!(reg & 0x01))
++ pci_write_config_byte(pdev, 0x49, reg | 0x01);
++ return;
++ }
++
++ if (sis->info == &sis_info66 || sis->info == &sis_info100_early) {
++ /* Fix up latency */
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
++ /* Set compatibility bit */
++ pci_read_config_byte(pdev, 0x52, ®);
++ if (!(reg & 0x04))
++ pci_write_config_byte(pdev, 0x52, reg | 0x04);
++ return;
++ }
++
++ if (sis->info == &sis_info33) {
++ pci_read_config_byte(pdev, PCI_CLASS_PROG, ®);
++ if (( reg & 0x0F ) != 0x00)
++ pci_write_config_byte(pdev, PCI_CLASS_PROG, reg & 0xF0);
++ /* Fall through to ATA16 fixup below */
++ }
++
++ if (sis->info == &sis_info || sis->info == &sis_info33) {
++ /* force per drive recovery and active timings
++ needed on ATA_33 and below chips */
++ pci_read_config_byte(pdev, 0x52, ®);
++ if (!(reg & 0x08))
++ pci_write_config_byte(pdev, 0x52, reg|0x08);
++ return;
++ }
++
++ BUG();
++}
++
++/**
++ * sis_init_one - Register SiS ATA PCI device with kernel services
++ * @pdev: PCI device to register
++ * @ent: Entry in sis_pci_tbl matching with @pdev
++ *
++ * Called from kernel PCI layer. We probe for combined mode (sigh),
++ * and then hand over control to libata, for it to do the rest.
++ *
++ * LOCKING:
++ * Inherited from PCI layer (may sleep).
++ *
++ * RETURNS:
++ * Zero on success, or -ERRNO value.
++ */
++
++static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ static struct ata_port_info *port_info[2];
++ struct ata_port_info *port;
++ struct pci_dev *host = NULL;
++ struct sis_chipset *chipset = NULL;
++
++ static struct sis_chipset sis_chipsets[] = {
++
++ { 0x0968, &sis_info133 },
++ { 0x0966, &sis_info133 },
++ { 0x0965, &sis_info133 },
++ { 0x0745, &sis_info100 },
++ { 0x0735, &sis_info100 },
++ { 0x0733, &sis_info100 },
++ { 0x0635, &sis_info100 },
++ { 0x0633, &sis_info100 },
++
++ { 0x0730, &sis_info100_early }, /* 100 with ATA 66 layout */
++ { 0x0550, &sis_info100_early }, /* 100 with ATA 66 layout */
++
++ { 0x0640, &sis_info66 },
++ { 0x0630, &sis_info66 },
++ { 0x0620, &sis_info66 },
++ { 0x0540, &sis_info66 },
++ { 0x0530, &sis_info66 },
++
++ { 0x5600, &sis_info33 },
++ { 0x5598, &sis_info33 },
++ { 0x5597, &sis_info33 },
++ { 0x5591, &sis_info33 },
++ { 0x5582, &sis_info33 },
++ { 0x5581, &sis_info33 },
++
++ { 0x5596, &sis_info },
++ { 0x5571, &sis_info },
++ { 0x5517, &sis_info },
++ { 0x5511, &sis_info },
++
++ {0}
++ };
++ static struct sis_chipset sis133_early = {
++ 0x0, &sis_info133_early
++ };
++ static struct sis_chipset sis133 = {
++ 0x0, &sis_info133
++ };
++ static struct sis_chipset sis100_early = {
++ 0x0, &sis_info100_early
++ };
++ static struct sis_chipset sis100 = {
++ 0x0, &sis_info100
++ };
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "version " DRV_VERSION "\n");
++
++ /* We have to find the bridge first */
++
++ for (chipset = &sis_chipsets[0]; chipset->device; chipset++) {
++ host = pci_get_device(PCI_VENDOR_ID_SI, chipset->device, NULL);
++ if (host != NULL) {
++ if (chipset->device == 0x630) { /* SIS630 */
++ u8 host_rev;
++ pci_read_config_byte(host, PCI_REVISION_ID, &host_rev);
++ if (host_rev >= 0x30) /* 630 ET */
++ chipset = &sis100_early;
++ }
++ break;
++ }
++ }
++
++ /* Look for concealed bridges */
++ if (host == NULL) {
++ /* Second check */
++ u32 idemisc;
++ u16 trueid;
++
++ /* Disable ID masking and register remapping then
++ see what the real ID is */
++
++ pci_read_config_dword(pdev, 0x54, &idemisc);
++ pci_write_config_dword(pdev, 0x54, idemisc & 0x7fffffff);
++ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid);
++ pci_write_config_dword(pdev, 0x54, idemisc);
++
++ switch(trueid) {
++ case 0x5518: /* SIS 962/963 */
++ chipset = &sis133;
++ if ((idemisc & 0x40000000) == 0) {
++ pci_write_config_dword(pdev, 0x54, idemisc | 0x40000000);
++ printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n");
++ }
++ break;
++ case 0x0180: /* SIS 965/965L */
++ chipset = &sis133;
++ break;
++ case 0x1180: /* SIS 966/966L */
++ chipset = &sis133;
++ break;
++ }
++ }
++
++ /* Further check */
++ if (chipset == NULL) {
++ struct pci_dev *lpc_bridge;
++ u16 trueid;
++ u8 prefctl;
++ u8 idecfg;
++ u8 sbrev;
++
++ /* Try the second unmasking technique */
++ pci_read_config_byte(pdev, 0x4a, &idecfg);
++ pci_write_config_byte(pdev, 0x4a, idecfg | 0x10);
++ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid);
++ pci_write_config_byte(pdev, 0x4a, idecfg);
++
++ switch(trueid) {
++ case 0x5517:
++ lpc_bridge = pci_get_slot(pdev->bus, 0x10); /* Bus 0 Dev 2 Fn 0 */
++ if (lpc_bridge == NULL)
++ break;
++ pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
++ pci_read_config_byte(pdev, 0x49, &prefctl);
++ pci_dev_put(lpc_bridge);
++
++ if (sbrev == 0x10 && (prefctl & 0x80)) {
++ chipset = &sis133_early;
++ break;
++ }
++ chipset = &sis100;
++ break;
++ }
++ }
++ pci_dev_put(host);
++
++ /* No chipset info, no support */
++ if (chipset == NULL)
++ return -ENODEV;
++
++ port = chipset->info;
++ port->private_data = chipset;
++
++ sis_fixup(pdev, chipset);
++
++ port_info[0] = port_info[1] = port;
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id sis_pci_tbl[] = {
++ { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */
++ { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */
++
++ { }
++};
++
++static struct pci_driver sis_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sis_pci_tbl,
++ .probe = sis_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init sis_init(void)
++{
++ return pci_register_driver(&sis_pci_driver);
++}
++
++static void __exit sis_exit(void)
++{
++ pci_unregister_driver(&sis_pci_driver);
++}
++
++module_init(sis_init);
++module_exit(sis_exit);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("SCSI low-level driver for SiS ATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+new file mode 100644
+index 0000000..08a6dc8
+--- /dev/null
++++ b/drivers/ata/pata_sl82c105.c
+@@ -0,0 +1,384 @@
++/*
++ * pata_sl82c105.c - SL82C105 PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Based in part on linux/drivers/ide/pci/sl82c105.c
++ * SL82C105/Winbond 553 IDE driver
++ *
++ * and in part on the documentation and errata sheet
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_sl82c105"
++#define DRV_VERSION "0.2.3"
++
++enum {
++ /*
++ * SL82C105 PCI config register 0x40 bits.
++ */
++ CTRL_IDE_IRQB = (1 << 30),
++ CTRL_IDE_IRQA = (1 << 28),
++ CTRL_LEGIRQ = (1 << 11),
++ CTRL_P1F16 = (1 << 5),
++ CTRL_P1EN = (1 << 4),
++ CTRL_P0F16 = (1 << 1),
++ CTRL_P0EN = (1 << 0)
++};
++
++/**
++ * sl82c105_pre_reset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int sl82c105_pre_reset(struct ata_port *ap)
++{
++ static const struct pci_bits sl82c105_enable_bits[] = {
++ { 0x40, 1, 0x01, 0x01 },
++ { 0x40, 1, 0x10, 0x10 }
++ };
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
++ return -ENOENT;
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++
++static void sl82c105_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, sl82c105_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++
++/**
++ * sl82c105_configure_piomode - set chip PIO timing
++ * @ap: ATA interface
++ * @adev: ATA device
++ * @pio: PIO mode
++ *
++ * Called to do the PIO mode setup. Our timing registers are shared
++ * so a configure_dmamode call will undo any work we do here and vice
++ * versa
++ */
++
++static void sl82c105_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static u16 pio_timing[5] = {
++ 0x50D, 0x407, 0x304, 0x242, 0x240
++ };
++ u16 dummy;
++ int timing = 0x44 + (8 * ap->port_no) + (4 * adev->devno);
++
++ pci_write_config_word(pdev, timing, pio_timing[pio]);
++ /* Can we lose this oddity of the old driver */
++ pci_read_config_word(pdev, timing, &dummy);
++}
++
++/**
++ * sl82c105_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the PIO mode setup. Our timing registers are shared
++ * but we want to set the PIO timing by default.
++ */
++
++static void sl82c105_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ sl82c105_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
++}
++
++/**
++ * sl82c105_configure_dmamode - set DMA mode in chip
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Load DMA cycle times into the chip ready for a DMA transfer
++ * to occur.
++ */
++
++static void sl82c105_configure_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ static u16 dma_timing[3] = {
++ 0x707, 0x201, 0x200
++ };
++ u16 dummy;
++ int timing = 0x44 + (8 * ap->port_no) + (4 * adev->devno);
++ int dma = adev->dma_mode - XFER_MW_DMA_0;
++
++ pci_write_config_word(pdev, timing, dma_timing[dma]);
++ /* Can we lose this oddity of the old driver */
++ pci_read_config_word(pdev, timing, &dummy);
++}
++
++/**
++ * sl82c105_set_dmamode - set initial DMA mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Called to do the DMA mode setup. This replaces the PIO timings
++ * for the device in question. Set appropriate PIO timings not DMA
++ * timings at this point.
++ */
++
++static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ switch(adev->dma_mode) {
++ case XFER_MW_DMA_0:
++ sl82c105_configure_piomode(ap, adev, 1);
++ break;
++ case XFER_MW_DMA_1:
++ sl82c105_configure_piomode(ap, adev, 3);
++ break;
++ case XFER_MW_DMA_2:
++ sl82c105_configure_piomode(ap, adev, 3);
++ break;
++ default:
++ BUG();
++ }
++}
++
++/**
++ * sl82c105_reset_engine - Reset the DMA engine
++ * @ap: ATA interface
++ *
++ * The sl82c105 has some serious problems with the DMA engine
++ * when transfers don't run as expected or ATAPI is used. The
++ * recommended fix is to reset the engine each use using a chip
++ * test register.
++ */
++
++static void sl82c105_reset_engine(struct ata_port *ap)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u16 val;
++
++ pci_read_config_word(pdev, 0x7E, &val);
++ pci_write_config_word(pdev, 0x7E, val | 4);
++ pci_write_config_word(pdev, 0x7E, val & ~4);
++}
++
++/**
++ * sl82c105_bmdma_start - DMA engine begin
++ * @qc: ATA command
++ *
++ * Reset the DMA engine each use as recommended by the errata
++ * document.
++ *
++ * FIXME: if we switch clock at BMDMA start/end we might get better
++ * PIO performance on DMA capable devices.
++ */
++
++static void sl82c105_bmdma_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ sl82c105_reset_engine(ap);
++
++ /* Set the clocks for DMA */
++ sl82c105_configure_dmamode(ap, qc->dev);
++ /* Activate DMA */
++ ata_bmdma_start(qc);
++}
++
++/**
++ * sl82c105_bmdma_end - DMA engine stop
++ * @qc: ATA command
++ *
++ * Reset the DMA engine each use as recommended by the errata
++ * document.
++ *
++ * This function is also called to turn off DMA when a timeout occurs
++ * during DMA operation. In both cases we need to reset the engine,
++ * so no actual eng_timeout handler is required.
++ *
++ * We assume bmdma_stop is always called if bmdma_start as called. If
++ * not then we may need to wrap qc_issue.
++ */
++
++static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ ata_bmdma_stop(qc);
++ sl82c105_reset_engine(ap);
++
++ /* This will redo the initial setup of the DMA device to matching
++ PIO timings */
++ sl82c105_set_dmamode(ap, qc->dev);
++}
++
++static struct scsi_host_template sl82c105_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations sl82c105_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = sl82c105_set_piomode,
++ .set_dmamode = sl82c105_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .error_handler = sl82c105_error_handler,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = sl82c105_bmdma_start,
++ .bmdma_stop = sl82c105_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * sl82c105_bridge_revision - find bridge version
++ * @pdev: PCI device for the ATA function
++ *
++ * Locates the PCI bridge associated with the ATA function and
++ * providing it is a Winbond 553 reports the revision. If it cannot
++ * find a revision or the right device it returns -1
++ */
++
++static int sl82c105_bridge_revision(struct pci_dev *pdev)
++{
++ struct pci_dev *bridge;
++ u8 rev;
++
++ /*
++ * The bridge should be part of the same device, but function 0.
++ */
++ bridge = pci_get_slot(pdev->bus,
++ PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
++ if (!bridge)
++ return -1;
++
++ /*
++ * Make sure it is a Winbond 553 and is an ISA bridge.
++ */
++ if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
++ bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
++ bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) {
++ pci_dev_put(bridge);
++ return -1;
++ }
++ /*
++ * We need to find function 0's revision, not function 1
++ */
++ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
++
++ pci_dev_put(bridge);
++ return rev;
++}
++
++
++static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info_dma = {
++ .sht = &sl82c105_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &sl82c105_port_ops
++ };
++ static struct ata_port_info info_early = {
++ .sht = &sl82c105_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .port_ops = &sl82c105_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info_early, &info_early };
++ u32 val;
++ int rev;
++
++ rev = sl82c105_bridge_revision(dev);
++
++ if (rev == -1)
++ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Unable to find bridge, disabling DMA.\n");
++ else if (rev <= 5)
++ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Early bridge revision, no DMA available.\n");
++ else {
++ port_info[0] = &info_dma;
++ port_info[1] = &info_dma;
++ }
++
++ pci_read_config_dword(dev, 0x40, &val);
++ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
++ pci_write_config_dword(dev, 0x40, val);
++
++
++ return ata_pci_init_one(dev, port_info, 1); /* For now */
++}
++
++static const struct pci_device_id sl82c105[] = {
++ { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
++
++ { },
++};
++
++static struct pci_driver sl82c105_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sl82c105,
++ .probe = sl82c105_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init sl82c105_init(void)
++{
++ return pci_register_driver(&sl82c105_pci_driver);
++}
++
++static void __exit sl82c105_exit(void)
++{
++ pci_unregister_driver(&sl82c105_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Sl82c105");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sl82c105);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(sl82c105_init);
++module_exit(sl82c105_exit);
+diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
+new file mode 100644
+index 0000000..9640f80
+--- /dev/null
++++ b/drivers/ata/pata_triflex.c
+@@ -0,0 +1,280 @@
++/*
++ * pata_triflex.c - Compaq PATA for new ATA layer
++ * (C) 2005 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * based upon
++ *
++ * triflex.c
++ *
++ * IDE Chipset driver for the Compaq TriFlex IDE controller.
++ *
++ * Known to work with the Compaq Workstation 5x00 series.
++ *
++ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
++ * Author: Torben Mathiasen <torben.mathiasen at hp.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.
++ *
++ * 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
++ *
++ * Loosely based on the piix & svwks drivers.
++ *
++ * Documentation:
++ * Not publically available.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_triflex"
++#define DRV_VERSION "0.2.5"
++
++/**
++ * triflex_prereset - probe begin
++ * @ap: ATA port
++ *
++ * Set up cable type and use generic probe init
++ */
++
++static int triflex_prereset(struct ata_port *ap)
++{
++ static const struct pci_bits triflex_enable_bits[] = {
++ { 0x80, 1, 0x01, 0x01 },
++ { 0x80, 1, 0x02, 0x02 }
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
++ return -ENOENT;
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++
++
++static void triflex_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, triflex_prereset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * triflex_load_timing - timing configuration
++ * @ap: ATA interface
++ * @adev: Device on the bus
++ * @speed: speed to configure
++ *
++ * The Triflex has one set of timings per device per channel. This
++ * means we must do some switching. As the PIO and DMA timings don't
++ * match we have to do some reloading unlike PIIX devices where tuning
++ * tricks can avoid it.
++ */
++
++static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 timing = 0;
++ u32 triflex_timing, old_triflex_timing;
++ int channel_offset = ap->port_no ? 0x74: 0x70;
++ unsigned int is_slave = (adev->devno != 0);
++
++
++ pci_read_config_dword(pdev, channel_offset, &old_triflex_timing);
++ triflex_timing = old_triflex_timing;
++
++ switch(speed)
++ {
++ case XFER_MW_DMA_2:
++ timing = 0x0103;break;
++ case XFER_MW_DMA_1:
++ timing = 0x0203;break;
++ case XFER_MW_DMA_0:
++ timing = 0x0808;break;
++ case XFER_SW_DMA_2:
++ case XFER_SW_DMA_1:
++ case XFER_SW_DMA_0:
++ timing = 0x0F0F;break;
++ case XFER_PIO_4:
++ timing = 0x0202;break;
++ case XFER_PIO_3:
++ timing = 0x0204;break;
++ case XFER_PIO_2:
++ timing = 0x0404;break;
++ case XFER_PIO_1:
++ timing = 0x0508;break;
++ case XFER_PIO_0:
++ timing = 0x0808;break;
++ default:
++ BUG();
++ }
++ triflex_timing &= ~ (0xFFFF << (16 * is_slave));
++ triflex_timing |= (timing << (16 * is_slave));
++
++ if (triflex_timing != old_triflex_timing)
++ pci_write_config_dword(pdev, channel_offset, triflex_timing);
++}
++
++/**
++ * triflex_set_piomode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * Use the timing loader to set up the PIO mode. We have to do this
++ * because DMA start/stop will only be called once DMA occurs. If there
++ * has been no DMA then the PIO timings are still needed.
++ */
++static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ triflex_load_timing(ap, adev, adev->pio_mode);
++}
++
++/**
++ * triflex_dma_start - DMA start callback
++ * @qc: Command in progress
++ *
++ * Usually drivers set the DMA timing at the point the set_dmamode call
++ * is made. Triflex however requires we load new timings on the
++ * transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc).
++ * We load the DMA timings just before starting DMA and then restore
++ * the PIO timing when the DMA is finished.
++ */
++
++static void triflex_bmdma_start(struct ata_queued_cmd *qc)
++{
++ triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode);
++ ata_bmdma_start(qc);
++}
++
++/**
++ * triflex_dma_stop - DMA stop callback
++ * @ap: ATA interface
++ * @adev: ATA device
++ *
++ * We loaded new timings in dma_start, as a result we need to restore
++ * the PIO timings in dma_stop so that the next command issue gets the
++ * right clock values.
++ */
++
++static void triflex_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ ata_bmdma_stop(qc);
++ triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode);
++}
++
++static struct scsi_host_template triflex_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations triflex_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = triflex_set_piomode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = triflex_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = triflex_bmdma_start,
++ .bmdma_stop = triflex_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ static struct ata_port_info info = {
++ .sht = &triflex_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &triflex_port_ops
++ };
++ static struct ata_port_info *port_info[2] = { &info, &info };
++ static int printed_version;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
++
++ return ata_pci_init_one(dev, port_info, 2);
++}
++
++static const struct pci_device_id triflex[] = {
++ { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
++
++ { },
++};
++
++static struct pci_driver triflex_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = triflex,
++ .probe = triflex_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init triflex_init(void)
++{
++ return pci_register_driver(&triflex_pci_driver);
++}
++
++static void __exit triflex_exit(void)
++{
++ pci_unregister_driver(&triflex_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, triflex);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(triflex_init);
++module_exit(triflex_exit);
+diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
+new file mode 100644
+index 0000000..1e7be9e
+--- /dev/null
++++ b/drivers/ata/pata_via.c
+@@ -0,0 +1,564 @@
++/*
++ * pata_via.c - VIA PATA for new ATA layer
++ * (C) 2005-2006 Red Hat Inc
++ * Alan Cox <alan at redhat.com>
++ *
++ * Documentation
++ * Most chipset documentation available under NDA only
++ *
++ * VIA version guide
++ * VIA VT82C561 - early design, uses ata_generic currently
++ * VIA VT82C576 - MWDMA, 33Mhz
++ * VIA VT82C586 - MWDMA, 33Mhz
++ * VIA VT82C586a - Added UDMA to 33Mhz
++ * VIA VT82C586b - UDMA33
++ * VIA VT82C596a - Nonfunctional UDMA66
++ * VIA VT82C596b - Working UDMA66
++ * VIA VT82C686 - Nonfunctional UDMA66
++ * VIA VT82C686a - Working UDMA66
++ * VIA VT82C686b - Updated to UDMA100
++ * VIA VT8231 - UDMA100
++ * VIA VT8233 - UDMA100
++ * VIA VT8233a - UDMA133
++ * VIA VT8233c - UDMA100
++ * VIA VT8235 - UDMA133
++ * VIA VT8237 - UDMA133
++ *
++ * Most registers remain compatible across chips. Others start reserved
++ * and acquire sensible semantics if set to 1 (eg cable detect). A few
++ * exceptions exist, notably around the FIFO settings.
++ *
++ * One additional quirk of the VIA design is that like ALi they use few
++ * PCI IDs for a lot of chips.
++ *
++ * Based heavily on:
++ *
++ * Version 3.38
++ *
++ * VIA IDE driver for Linux. Supported southbridges:
++ *
++ * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
++ * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
++ * vt8235, vt8237
++ *
++ * Copyright (c) 2000-2002 Vojtech Pavlik
++ *
++ * Based on the work of:
++ * Michel Aubry
++ * Jeff Garzik
++ * Andre Hedrick
++
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pata_via"
++#define DRV_VERSION "0.1.14"
++
++/*
++ * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
++ * driver.
++ */
++
++enum {
++ VIA_UDMA = 0x007,
++ VIA_UDMA_NONE = 0x000,
++ VIA_UDMA_33 = 0x001,
++ VIA_UDMA_66 = 0x002,
++ VIA_UDMA_100 = 0x003,
++ VIA_UDMA_133 = 0x004,
++ VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */
++ VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */
++ VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */
++ VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */
++ VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */
++ VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */
++ VIA_NO_ENABLES = 0x400, /* Has no enablebits */
++};
++
++/*
++ * VIA SouthBridge chips.
++ */
++
++static const struct via_isa_bridge {
++ const char *name;
++ u16 id;
++ u8 rev_min;
++ u8 rev_max;
++ u16 flags;
++} via_isa_bridges[] = {
++ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
++ { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
++ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
++ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
++ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
++ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
++ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
++ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 },
++ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 },
++ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 },
++ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 },
++ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
++ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 },
++ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
++ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
++ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
++ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
++ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
++ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
++ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
++ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
++ { NULL }
++};
++
++/**
++ * via_cable_detect - cable detection
++ * @ap: ATA port
++ *
++ * Perform cable detection. Actually for the VIA case the BIOS
++ * already did this for us. We read the values provided by the
++ * BIOS. If you are using an 8235 in a non-PC configuration you
++ * may need to update this code.
++ *
++ * Hotplug also impacts on this.
++ */
++
++static int via_cable_detect(struct ata_port *ap) {
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 ata66;
++
++ pci_read_config_dword(pdev, 0x50, &ata66);
++ /* Check both the drive cable reporting bits, we might not have
++ two drives */
++ if (ata66 & (0x10100000 >> (16 * ap->port_no)))
++ return ATA_CBL_PATA80;
++ else
++ return ATA_CBL_PATA40;
++}
++
++static int via_pre_reset(struct ata_port *ap)
++{
++ const struct via_isa_bridge *config = ap->host->private_data;
++
++ if (!(config->flags & VIA_NO_ENABLES)) {
++ static const struct pci_bits via_enable_bits[] = {
++ { 0x40, 1, 0x02, 0x02 },
++ { 0x40, 1, 0x01, 0x01 }
++ };
++
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++
++ if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no]))
++ return -ENOENT;
++ }
++
++ if ((config->flags & VIA_UDMA) >= VIA_UDMA_66)
++ ap->cbl = via_cable_detect(ap);
++ else
++ ap->cbl = ATA_CBL_PATA40;
++ return ata_std_prereset(ap);
++}
++
++
++/**
++ * via_error_handler - reset for VIA chips
++ * @ap: ATA port
++ *
++ * Handle the reset callback for the later chips with cable detect
++ */
++
++static void via_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, via_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
++}
++
++/**
++ * via_do_set_mode - set initial PIO mode data
++ * @ap: ATA interface
++ * @adev: ATA device
++ * @mode: ATA mode being programmed
++ * @tdiv: Clocks per PCI clock
++ * @set_ast: Set to program address setup
++ * @udma_type: UDMA mode/format of registers
++ *
++ * Program the VIA registers for DMA and PIO modes. Uses the ata timing
++ * support in order to compute modes.
++ *
++ * FIXME: Hotplug will require we serialize multiple mode changes
++ * on the two channels.
++ */
++
++static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ struct ata_device *peer = ata_dev_pair(adev);
++ struct ata_timing t, p;
++ static int via_clock = 33333; /* Bus clock in kHZ - ought to be tunable one day */
++ unsigned long T = 1000000000 / via_clock;
++ unsigned long UT = T/tdiv;
++ int ut;
++ int offset = 3 - (2*ap->port_no) - adev->devno;
++
++
++ /* Calculate the timing values we require */
++ ata_timing_compute(adev, mode, &t, T, UT);
++
++ /* We share 8bit timing so we must merge the constraints */
++ if (peer) {
++ if (peer->pio_mode) {
++ ata_timing_compute(peer, peer->pio_mode, &p, T, UT);
++ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT);
++ }
++ }
++
++ /* Address setup is programmable but breaks on UDMA133 setups */
++ if (set_ast) {
++ u8 setup; /* 2 bits per drive */
++ int shift = 2 * offset;
++
++ pci_read_config_byte(pdev, 0x4C, &setup);
++ setup &= ~(3 << shift);
++ setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
++ pci_write_config_byte(pdev, 0x4C, setup);
++ }
++
++ /* Load the PIO mode bits */
++ pci_write_config_byte(pdev, 0x4F - ap->port_no,
++ ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1));
++ pci_write_config_byte(pdev, 0x48 + offset,
++ ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1));
++
++ /* Load the UDMA bits according to type */
++ switch(udma_type) {
++ default:
++ /* BUG() ? */
++ /* fall through */
++ case 33:
++ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03;
++ break;
++ case 66:
++ ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f;
++ break;
++ case 100:
++ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
++ break;
++ case 133:
++ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
++ break;
++ }
++ /* Set UDMA unless device is not UDMA capable */
++ if (udma_type)
++ pci_write_config_byte(pdev, 0x50 + offset, ut);
++}
++
++static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++ const struct via_isa_bridge *config = ap->host->private_data;
++ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
++ int mode = config->flags & VIA_UDMA;
++ static u8 tclock[5] = { 1, 1, 2, 3, 4 };
++ static u8 udma[5] = { 0, 33, 66, 100, 133 };
++
++ via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]);
++}
++
++static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
++{
++ const struct via_isa_bridge *config = ap->host->private_data;
++ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
++ int mode = config->flags & VIA_UDMA;
++ static u8 tclock[5] = { 1, 1, 2, 3, 4 };
++ static u8 udma[5] = { 0, 33, 66, 100, 133 };
++
++ via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);
++}
++
++static struct scsi_host_template via_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .max_sectors = ATA_MAX_SECTORS,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .bios_param = ata_std_bios_param,
++};
++
++static struct ata_port_operations via_port_ops = {
++ .port_disable = ata_port_disable,
++ .set_piomode = via_set_piomode,
++ .set_dmamode = via_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = via_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++static struct ata_port_operations via_port_ops_noirq = {
++ .port_disable = ata_port_disable,
++ .set_piomode = via_set_piomode,
++ .set_dmamode = via_set_dmamode,
++ .mode_filter = ata_pci_default_filter,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = via_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++
++ .data_xfer = ata_pio_data_xfer_noirq,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop
++};
++
++/**
++ * via_init_one - discovery callback
++ * @pdev: PCI device ID
++ * @id: PCI table info
++ *
++ * A VIA IDE interface has been discovered. Figure out what revision
++ * and perform configuration work before handing it to the ATA layer
++ */
++
++static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ /* Early VIA without UDMA support */
++ static struct ata_port_info via_mwdma_info = {
++ .sht = &via_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &via_port_ops
++ };
++ /* Ditto with IRQ masking required */
++ static struct ata_port_info via_mwdma_info_borked = {
++ .sht = &via_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .port_ops = &via_port_ops_noirq,
++ };
++ /* VIA UDMA 33 devices (and borked 66) */
++ static struct ata_port_info via_udma33_info = {
++ .sht = &via_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7,
++ .port_ops = &via_port_ops
++ };
++ /* VIA UDMA 66 devices */
++ static struct ata_port_info via_udma66_info = {
++ .sht = &via_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x1f,
++ .port_ops = &via_port_ops
++ };
++ /* VIA UDMA 100 devices */
++ static struct ata_port_info via_udma100_info = {
++ .sht = &via_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x3f,
++ .port_ops = &via_port_ops
++ };
++ /* UDMA133 with bad AST (All current 133) */
++ static struct ata_port_info via_udma133_info = {
++ .sht = &via_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f, /* FIXME: should check north bridge */
++ .port_ops = &via_port_ops
++ };
++ struct ata_port_info *port_info[2], *type;
++ struct pci_dev *isa = NULL;
++ const struct via_isa_bridge *config;
++ static int printed_version;
++ u8 t;
++ u8 enable;
++ u32 timing;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ /* To find out how the IDE will behave and what features we
++ actually have to look at the bridge not the IDE controller */
++ for (config = via_isa_bridges; config->id; config++)
++ if ((isa = pci_get_device(PCI_VENDOR_ID_VIA +
++ !!(config->flags & VIA_BAD_ID),
++ config->id, NULL))) {
++
++ pci_read_config_byte(isa, PCI_REVISION_ID, &t);
++ if (t >= config->rev_min &&
++ t <= config->rev_max)
++ break;
++ pci_dev_put(isa);
++ }
++
++ if (!config->id) {
++ printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n");
++ return -ENODEV;
++ }
++ pci_dev_put(isa);
++
++ /* 0x40 low bits indicate enabled channels */
++ pci_read_config_byte(pdev, 0x40 , &enable);
++ enable &= 3;
++ if (enable == 0) {
++ return -ENODEV;
++ }
++
++ /* Initialise the FIFO for the enabled channels. */
++ if (config->flags & VIA_SET_FIFO) {
++ u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
++ u8 fifo;
++
++ pci_read_config_byte(pdev, 0x43, &fifo);
++
++ /* Clear PREQ# until DDACK# for errata */
++ if (config->flags & VIA_BAD_PREQ)
++ fifo &= 0x7F;
++ else
++ fifo &= 0x9f;
++ /* Turn on FIFO for enabled channels */
++ fifo |= fifo_setting[enable];
++ pci_write_config_byte(pdev, 0x43, fifo);
++ }
++ /* Clock set up */
++ switch(config->flags & VIA_UDMA) {
++ case VIA_UDMA_NONE:
++ if (config->flags & VIA_NO_UNMASK)
++ type = &via_mwdma_info_borked;
++ else
++ type = &via_mwdma_info;
++ break;
++ case VIA_UDMA_33:
++ type = &via_udma33_info;
++ break;
++ case VIA_UDMA_66:
++ type = &via_udma66_info;
++ /* The 66 MHz devices require we enable the clock */
++ pci_read_config_dword(pdev, 0x50, &timing);
++ timing |= 0x80008;
++ pci_write_config_dword(pdev, 0x50, timing);
++ break;
++ case VIA_UDMA_100:
++ type = &via_udma100_info;
++ break;
++ case VIA_UDMA_133:
++ type = &via_udma133_info;
++ break;
++ default:
++ WARN_ON(1);
++ return -ENODEV;
++ }
++
++ if (config->flags & VIA_BAD_CLK66) {
++ /* Disable the 66MHz clock on problem devices */
++ pci_read_config_dword(pdev, 0x50, &timing);
++ timing &= ~0x80008;
++ pci_write_config_dword(pdev, 0x50, timing);
++ }
++
++ /* We have established the device type, now fire it up */
++ type->private_data = (void *)config;
++
++ port_info[0] = port_info[1] = type;
++ return ata_pci_init_one(pdev, port_info, 2);
++}
++
++static const struct pci_device_id via[] = {
++ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), },
++ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), },
++ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), },
++ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
++
++ { },
++};
++
++static struct pci_driver via_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = via,
++ .probe = via_init_one,
++ .remove = ata_pci_remove_one
++};
++
++static int __init via_init(void)
++{
++ return pci_register_driver(&via_pci_driver);
++}
++
++static void __exit via_exit(void)
++{
++ pci_unregister_driver(&via_pci_driver);
++}
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("low-level driver for VIA PATA");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, via);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(via_init);
++module_exit(via_exit);
+diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
+new file mode 100644
+index 0000000..9021e34
+--- /dev/null
++++ b/drivers/ata/pdc_adma.c
+@@ -0,0 +1,738 @@
++/*
++ * pdc_adma.c - Pacific Digital Corporation ADMA
++ *
++ * Maintained by: Mark Lord <mlord at pobox.com>
++ *
++ * Copyright 2005 Mark Lord
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ *
++ * Supports ATA disks in single-packet ADMA mode.
++ * Uses PIO for everything else.
++ *
++ * TODO: Use ADMA transfers for ATAPI devices, when possible.
++ * This requires careful attention to a number of quirks of the chip.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <asm/io.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "pdc_adma"
++#define DRV_VERSION "0.04"
++
++/* macro to calculate base address for ATA regs */
++#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
++
++/* macro to calculate base address for ADMA regs */
++#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
++
++enum {
++ ADMA_PORTS = 2,
++ ADMA_CPB_BYTES = 40,
++ ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16,
++ ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES,
++
++ ADMA_DMA_BOUNDARY = 0xffffffff,
++
++ /* global register offsets */
++ ADMA_MODE_LOCK = 0x00c7,
++
++ /* per-channel register offsets */
++ ADMA_CONTROL = 0x0000, /* ADMA control */
++ ADMA_STATUS = 0x0002, /* ADMA status */
++ ADMA_CPB_COUNT = 0x0004, /* CPB count */
++ ADMA_CPB_CURRENT = 0x000c, /* current CPB address */
++ ADMA_CPB_NEXT = 0x000c, /* next CPB address */
++ ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */
++ ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */
++ ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */
++
++ /* ADMA_CONTROL register bits */
++ aNIEN = (1 << 8), /* irq mask: 1==masked */
++ aGO = (1 << 7), /* packet trigger ("Go!") */
++ aRSTADM = (1 << 5), /* ADMA logic reset */
++ aPIOMD4 = 0x0003, /* PIO mode 4 */
++
++ /* ADMA_STATUS register bits */
++ aPSD = (1 << 6),
++ aUIRQ = (1 << 4),
++ aPERR = (1 << 0),
++
++ /* CPB bits */
++ cDONE = (1 << 0),
++ cVLD = (1 << 0),
++ cDAT = (1 << 2),
++ cIEN = (1 << 3),
++
++ /* PRD bits */
++ pORD = (1 << 4),
++ pDIRO = (1 << 5),
++ pEND = (1 << 7),
++
++ /* ATA register flags */
++ rIGN = (1 << 5),
++ rEND = (1 << 7),
++
++ /* ATA register addresses */
++ ADMA_REGS_CONTROL = 0x0e,
++ ADMA_REGS_SECTOR_COUNT = 0x12,
++ ADMA_REGS_LBA_LOW = 0x13,
++ ADMA_REGS_LBA_MID = 0x14,
++ ADMA_REGS_LBA_HIGH = 0x15,
++ ADMA_REGS_DEVICE = 0x16,
++ ADMA_REGS_COMMAND = 0x17,
++
++ /* PCI device IDs */
++ board_1841_idx = 0, /* ADMA 2-port controller */
++};
++
++typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t;
++
++struct adma_port_priv {
++ u8 *pkt;
++ dma_addr_t pkt_dma;
++ adma_state_t state;
++};
++
++static int adma_ata_init_one (struct pci_dev *pdev,
++ const struct pci_device_id *ent);
++static irqreturn_t adma_intr (int irq, void *dev_instance);
++static int adma_port_start(struct ata_port *ap);
++static void adma_host_stop(struct ata_host *host);
++static void adma_port_stop(struct ata_port *ap);
++static void adma_phy_reset(struct ata_port *ap);
++static void adma_qc_prep(struct ata_queued_cmd *qc);
++static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
++static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
++static void adma_bmdma_stop(struct ata_queued_cmd *qc);
++static u8 adma_bmdma_status(struct ata_port *ap);
++static void adma_irq_clear(struct ata_port *ap);
++static void adma_eng_timeout(struct ata_port *ap);
++
++static struct scsi_host_template adma_ata_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ENABLE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ADMA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations adma_ata_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .check_atapi_dma = adma_check_atapi_dma,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .phy_reset = adma_phy_reset,
++ .qc_prep = adma_qc_prep,
++ .qc_issue = adma_qc_issue,
++ .eng_timeout = adma_eng_timeout,
++ .data_xfer = ata_mmio_data_xfer,
++ .irq_handler = adma_intr,
++ .irq_clear = adma_irq_clear,
++ .port_start = adma_port_start,
++ .port_stop = adma_port_stop,
++ .host_stop = adma_host_stop,
++ .bmdma_stop = adma_bmdma_stop,
++ .bmdma_status = adma_bmdma_status,
++};
++
++static struct ata_port_info adma_port_info[] = {
++ /* board_1841_idx */
++ {
++ .sht = &adma_ata_sht,
++ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
++ ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
++ ATA_FLAG_PIO_POLLING,
++ .pio_mask = 0x10, /* pio4 */
++ .udma_mask = 0x1f, /* udma0-4 */
++ .port_ops = &adma_ata_ops,
++ },
++};
++
++static const struct pci_device_id adma_ata_pci_tbl[] = {
++ { PCI_VDEVICE(PDC, 0x1841), board_1841_idx },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver adma_ata_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = adma_ata_pci_tbl,
++ .probe = adma_ata_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int adma_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++ return 1; /* ATAPI DMA not yet supported */
++}
++
++static void adma_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ /* nothing */
++}
++
++static u8 adma_bmdma_status(struct ata_port *ap)
++{
++ return 0;
++}
++
++static void adma_irq_clear(struct ata_port *ap)
++{
++ /* nothing */
++}
++
++static void adma_reset_engine(void __iomem *chan)
++{
++ /* reset ADMA to idle state */
++ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
++ udelay(2);
++ writew(aPIOMD4, chan + ADMA_CONTROL);
++ udelay(2);
++}
++
++static void adma_reinit_engine(struct ata_port *ap)
++{
++ struct adma_port_priv *pp = ap->private_data;
++ void __iomem *mmio_base = ap->host->mmio_base;
++ void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
++
++ /* mask/clear ATA interrupts */
++ writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr);
++ ata_check_status(ap);
++
++ /* reset the ADMA engine */
++ adma_reset_engine(chan);
++
++ /* set in-FIFO threshold to 0x100 */
++ writew(0x100, chan + ADMA_FIFO_IN);
++
++ /* set CPB pointer */
++ writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT);
++
++ /* set out-FIFO threshold to 0x100 */
++ writew(0x100, chan + ADMA_FIFO_OUT);
++
++ /* set CPB count */
++ writew(1, chan + ADMA_CPB_COUNT);
++
++ /* read/discard ADMA status */
++ readb(chan + ADMA_STATUS);
++}
++
++static inline void adma_enter_reg_mode(struct ata_port *ap)
++{
++ void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
++
++ writew(aPIOMD4, chan + ADMA_CONTROL);
++ readb(chan + ADMA_STATUS); /* flush */
++}
++
++static void adma_phy_reset(struct ata_port *ap)
++{
++ struct adma_port_priv *pp = ap->private_data;
++
++ pp->state = adma_state_idle;
++ adma_reinit_engine(ap);
++ ata_port_probe(ap);
++ ata_bus_reset(ap);
++}
++
++static void adma_eng_timeout(struct ata_port *ap)
++{
++ struct adma_port_priv *pp = ap->private_data;
++
++ if (pp->state != adma_state_idle) /* healthy paranoia */
++ pp->state = adma_state_mmio;
++ adma_reinit_engine(ap);
++ ata_eng_timeout(ap);
++}
++
++static int adma_fill_sg(struct ata_queued_cmd *qc)
++{
++ struct scatterlist *sg;
++ struct ata_port *ap = qc->ap;
++ struct adma_port_priv *pp = ap->private_data;
++ u8 *buf = pp->pkt;
++ int i = (2 + buf[3]) * 8;
++ u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
++
++ ata_for_each_sg(sg, qc) {
++ u32 addr;
++ u32 len;
++
++ addr = (u32)sg_dma_address(sg);
++ *(__le32 *)(buf + i) = cpu_to_le32(addr);
++ i += 4;
++
++ len = sg_dma_len(sg) >> 3;
++ *(__le32 *)(buf + i) = cpu_to_le32(len);
++ i += 4;
++
++ if (ata_sg_is_last(sg, qc))
++ pFLAGS |= pEND;
++ buf[i++] = pFLAGS;
++ buf[i++] = qc->dev->dma_mode & 0xf;
++ buf[i++] = 0; /* pPKLW */
++ buf[i++] = 0; /* reserved */
++
++ *(__le32 *)(buf + i)
++ = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
++ i += 4;
++
++ VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4,
++ (unsigned long)addr, len);
++ }
++ return i;
++}
++
++static void adma_qc_prep(struct ata_queued_cmd *qc)
++{
++ struct adma_port_priv *pp = qc->ap->private_data;
++ u8 *buf = pp->pkt;
++ u32 pkt_dma = (u32)pp->pkt_dma;
++ int i = 0;
++
++ VPRINTK("ENTER\n");
++
++ adma_enter_reg_mode(qc->ap);
++ if (qc->tf.protocol != ATA_PROT_DMA) {
++ ata_qc_prep(qc);
++ return;
++ }
++
++ buf[i++] = 0; /* Response flags */
++ buf[i++] = 0; /* reserved */
++ buf[i++] = cVLD | cDAT | cIEN;
++ i++; /* cLEN, gets filled in below */
++
++ *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */
++ i += 4; /* cNCPB */
++ i += 4; /* cPRD, gets filled in below */
++
++ buf[i++] = 0; /* reserved */
++ buf[i++] = 0; /* reserved */
++ buf[i++] = 0; /* reserved */
++ buf[i++] = 0; /* reserved */
++
++ /* ATA registers; must be a multiple of 4 */
++ buf[i++] = qc->tf.device;
++ buf[i++] = ADMA_REGS_DEVICE;
++ if ((qc->tf.flags & ATA_TFLAG_LBA48)) {
++ buf[i++] = qc->tf.hob_nsect;
++ buf[i++] = ADMA_REGS_SECTOR_COUNT;
++ buf[i++] = qc->tf.hob_lbal;
++ buf[i++] = ADMA_REGS_LBA_LOW;
++ buf[i++] = qc->tf.hob_lbam;
++ buf[i++] = ADMA_REGS_LBA_MID;
++ buf[i++] = qc->tf.hob_lbah;
++ buf[i++] = ADMA_REGS_LBA_HIGH;
++ }
++ buf[i++] = qc->tf.nsect;
++ buf[i++] = ADMA_REGS_SECTOR_COUNT;
++ buf[i++] = qc->tf.lbal;
++ buf[i++] = ADMA_REGS_LBA_LOW;
++ buf[i++] = qc->tf.lbam;
++ buf[i++] = ADMA_REGS_LBA_MID;
++ buf[i++] = qc->tf.lbah;
++ buf[i++] = ADMA_REGS_LBA_HIGH;
++ buf[i++] = 0;
++ buf[i++] = ADMA_REGS_CONTROL;
++ buf[i++] = rIGN;
++ buf[i++] = 0;
++ buf[i++] = qc->tf.command;
++ buf[i++] = ADMA_REGS_COMMAND | rEND;
++
++ buf[3] = (i >> 3) - 2; /* cLEN */
++ *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */
++
++ i = adma_fill_sg(qc);
++ wmb(); /* flush PRDs and pkt to memory */
++#if 0
++ /* dump out CPB + PRDs for debug */
++ {
++ int j, len = 0;
++ static char obuf[2048];
++ for (j = 0; j < i; ++j) {
++ len += sprintf(obuf+len, "%02x ", buf[j]);
++ if ((j & 7) == 7) {
++ printk("%s\n", obuf);
++ len = 0;
++ }
++ }
++ if (len)
++ printk("%s\n", obuf);
++ }
++#endif
++}
++
++static inline void adma_packet_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
++
++ VPRINTK("ENTER, ap %p\n", ap);
++
++ /* fire up the ADMA engine */
++ writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
++}
++
++static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
++{
++ struct adma_port_priv *pp = qc->ap->private_data;
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ pp->state = adma_state_pkt;
++ adma_packet_start(qc);
++ return 0;
++
++ case ATA_PROT_ATAPI_DMA:
++ BUG();
++ break;
++
++ default:
++ break;
++ }
++
++ pp->state = adma_state_mmio;
++ return ata_qc_issue_prot(qc);
++}
++
++static inline unsigned int adma_intr_pkt(struct ata_host *host)
++{
++ unsigned int handled = 0, port_no;
++ u8 __iomem *mmio_base = host->mmio_base;
++
++ for (port_no = 0; port_no < host->n_ports; ++port_no) {
++ struct ata_port *ap = host->ports[port_no];
++ struct adma_port_priv *pp;
++ struct ata_queued_cmd *qc;
++ void __iomem *chan = ADMA_REGS(mmio_base, port_no);
++ u8 status = readb(chan + ADMA_STATUS);
++
++ if (status == 0)
++ continue;
++ handled = 1;
++ adma_enter_reg_mode(ap);
++ if (ap->flags & ATA_FLAG_DISABLED)
++ continue;
++ pp = ap->private_data;
++ if (!pp || pp->state != adma_state_pkt)
++ continue;
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
++ if ((status & (aPERR | aPSD | aUIRQ)))
++ qc->err_mask |= AC_ERR_OTHER;
++ else if (pp->pkt[0] != cDONE)
++ qc->err_mask |= AC_ERR_OTHER;
++
++ ata_qc_complete(qc);
++ }
++ }
++ return handled;
++}
++
++static inline unsigned int adma_intr_mmio(struct ata_host *host)
++{
++ unsigned int handled = 0, port_no;
++
++ for (port_no = 0; port_no < host->n_ports; ++port_no) {
++ struct ata_port *ap;
++ ap = host->ports[port_no];
++ if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
++ struct ata_queued_cmd *qc;
++ struct adma_port_priv *pp = ap->private_data;
++ if (!pp || pp->state != adma_state_mmio)
++ continue;
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
++
++ /* check main status, clearing INTRQ */
++ u8 status = ata_check_status(ap);
++ if ((status & ATA_BUSY))
++ continue;
++ DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
++ ap->id, qc->tf.protocol, status);
++
++ /* complete taskfile transaction */
++ pp->state = adma_state_idle;
++ qc->err_mask |= ac_err_mask(status);
++ ata_qc_complete(qc);
++ handled = 1;
++ }
++ }
++ }
++ return handled;
++}
++
++static irqreturn_t adma_intr(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ unsigned int handled = 0;
++
++ VPRINTK("ENTER\n");
++
++ spin_lock(&host->lock);
++ handled = adma_intr_pkt(host) | adma_intr_mmio(host);
++ spin_unlock(&host->lock);
++
++ VPRINTK("EXIT\n");
++
++ return IRQ_RETVAL(handled);
++}
++
++static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr =
++ port->data_addr = base + 0x000;
++ port->error_addr =
++ port->feature_addr = base + 0x004;
++ port->nsect_addr = base + 0x008;
++ port->lbal_addr = base + 0x00c;
++ port->lbam_addr = base + 0x010;
++ port->lbah_addr = base + 0x014;
++ port->device_addr = base + 0x018;
++ port->status_addr =
++ port->command_addr = base + 0x01c;
++ port->altstatus_addr =
++ port->ctl_addr = base + 0x038;
++}
++
++static int adma_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct adma_port_priv *pp;
++ int rc;
++
++ rc = ata_port_start(ap);
++ if (rc)
++ return rc;
++ adma_enter_reg_mode(ap);
++ rc = -ENOMEM;
++ pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
++ if (!pp)
++ goto err_out;
++ pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
++ GFP_KERNEL);
++ if (!pp->pkt)
++ goto err_out_kfree;
++ /* paranoia? */
++ if ((pp->pkt_dma & 7) != 0) {
++ printk("bad alignment for pp->pkt_dma: %08x\n",
++ (u32)pp->pkt_dma);
++ dma_free_coherent(dev, ADMA_PKT_BYTES,
++ pp->pkt, pp->pkt_dma);
++ goto err_out_kfree;
++ }
++ memset(pp->pkt, 0, ADMA_PKT_BYTES);
++ ap->private_data = pp;
++ adma_reinit_engine(ap);
++ return 0;
++
++err_out_kfree:
++ kfree(pp);
++err_out:
++ ata_port_stop(ap);
++ return rc;
++}
++
++static void adma_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct adma_port_priv *pp = ap->private_data;
++
++ adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no));
++ if (pp != NULL) {
++ ap->private_data = NULL;
++ if (pp->pkt != NULL)
++ dma_free_coherent(dev, ADMA_PKT_BYTES,
++ pp->pkt, pp->pkt_dma);
++ kfree(pp);
++ }
++ ata_port_stop(ap);
++}
++
++static void adma_host_stop(struct ata_host *host)
++{
++ unsigned int port_no;
++
++ for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
++ adma_reset_engine(ADMA_REGS(host->mmio_base, port_no));
++
++ ata_pci_host_stop(host);
++}
++
++static void adma_host_init(unsigned int chip_id,
++ struct ata_probe_ent *probe_ent)
++{
++ unsigned int port_no;
++ void __iomem *mmio_base = probe_ent->mmio_base;
++
++ /* enable/lock aGO operation */
++ writeb(7, mmio_base + ADMA_MODE_LOCK);
++
++ /* reset the ADMA logic */
++ for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
++ adma_reset_engine(ADMA_REGS(mmio_base, port_no));
++}
++
++static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
++{
++ int rc;
++
++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit DMA enable failed\n");
++ return rc;
++ }
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit consistent DMA enable failed\n");
++ return rc;
++ }
++ return 0;
++}
++
++static int adma_ata_init_one(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ void __iomem *mmio_base;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++ int rc, port_no;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc)
++ goto err_out;
++
++ if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
++ rc = -ENODEV;
++ goto err_out_regions;
++ }
++
++ mmio_base = pci_iomap(pdev, 4, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ rc = adma_set_dma_masks(pdev, mmio_base);
++ if (rc)
++ goto err_out_iounmap;
++
++ probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_iounmap;
++ }
++
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ probe_ent->sht = adma_port_info[board_idx].sht;
++ probe_ent->port_flags = adma_port_info[board_idx].flags;
++ probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
++ probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
++ probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = adma_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++ probe_ent->n_ports = ADMA_PORTS;
++
++ for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
++ adma_ata_setup_port(&probe_ent->port[port_no],
++ ADMA_ATA_REGS((unsigned long)mmio_base, port_no));
++ }
++
++ pci_set_master(pdev);
++
++ /* initialize adapter */
++ adma_host_init(board_idx, probe_ent);
++
++ rc = ata_device_add(probe_ent);
++ kfree(probe_ent);
++ if (rc != ADMA_PORTS)
++ goto err_out_iounmap;
++ return 0;
++
++err_out_iounmap:
++ pci_iounmap(pdev, mmio_base);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ pci_disable_device(pdev);
++ return rc;
++}
++
++static int __init adma_ata_init(void)
++{
++ return pci_register_driver(&adma_ata_pci_driver);
++}
++
++static void __exit adma_ata_exit(void)
++{
++ pci_unregister_driver(&adma_ata_pci_driver);
++}
++
++MODULE_AUTHOR("Mark Lord");
++MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(adma_ata_init);
++module_exit(adma_ata_exit);
+diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
+new file mode 100644
+index 0000000..1b8e0eb
+--- /dev/null
++++ b/drivers/ata/sata_mv.c
+@@ -0,0 +1,2465 @@
++/*
++ * sata_mv.c - Marvell SATA support
++ *
++ * Copyright 2005: EMC Corporation, all rights reserved.
++ * Copyright 2005 Red Hat, Inc. All rights reserved.
++ *
++ * Please ALWAYS copy linux-ide at vger.kernel.org on emails.
++ *
++ * 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 of the License.
++ *
++ * 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/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/dma-mapping.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++
++#define DRV_NAME "sata_mv"
++#define DRV_VERSION "0.7"
++
++enum {
++ /* BAR's are enumerated in terms of pci_resource_start() terms */
++ MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */
++ MV_IO_BAR = 2, /* offset 0x18: IO space */
++ MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */
++
++ MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
++ MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
++
++ MV_PCI_REG_BASE = 0,
++ MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
++ MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
++ MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
++ MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
++ MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
++ MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
++
++ MV_SATAHC0_REG_BASE = 0x20000,
++ MV_FLASH_CTL = 0x1046c,
++ MV_GPIO_PORT_CTL = 0x104f0,
++ MV_RESET_CFG = 0x180d8,
++
++ MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
++ MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
++ MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
++ MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
++
++ MV_USE_Q_DEPTH = ATA_DEF_QUEUE,
++
++ MV_MAX_Q_DEPTH = 32,
++ MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1,
++
++ /* CRQB needs alignment on a 1KB boundary. Size == 1KB
++ * CRPB needs alignment on a 256B boundary. Size == 256B
++ * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
++ * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
++ */
++ MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH),
++ MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH),
++ MV_MAX_SG_CT = 176,
++ MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
++ MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
++
++ MV_PORTS_PER_HC = 4,
++ /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
++ MV_PORT_HC_SHIFT = 2,
++ /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
++ MV_PORT_MASK = 3,
++
++ /* Host Flags */
++ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
++ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
++ MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
++ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
++ MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
++
++ CRQB_FLAG_READ = (1 << 0),
++ CRQB_TAG_SHIFT = 1,
++ CRQB_CMD_ADDR_SHIFT = 8,
++ CRQB_CMD_CS = (0x2 << 11),
++ CRQB_CMD_LAST = (1 << 15),
++
++ CRPB_FLAG_STATUS_SHIFT = 8,
++
++ EPRD_FLAG_END_OF_TBL = (1 << 31),
++
++ /* PCI interface registers */
++
++ PCI_COMMAND_OFS = 0xc00,
++
++ PCI_MAIN_CMD_STS_OFS = 0xd30,
++ STOP_PCI_MASTER = (1 << 2),
++ PCI_MASTER_EMPTY = (1 << 3),
++ GLOB_SFT_RST = (1 << 4),
++
++ MV_PCI_MODE = 0xd00,
++ MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
++ MV_PCI_DISC_TIMER = 0xd04,
++ MV_PCI_MSI_TRIGGER = 0xc38,
++ MV_PCI_SERR_MASK = 0xc28,
++ MV_PCI_XBAR_TMOUT = 0x1d04,
++ MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
++ MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
++ MV_PCI_ERR_ATTRIBUTE = 0x1d48,
++ MV_PCI_ERR_COMMAND = 0x1d50,
++
++ PCI_IRQ_CAUSE_OFS = 0x1d58,
++ PCI_IRQ_MASK_OFS = 0x1d5c,
++ PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
++
++ HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
++ HC_MAIN_IRQ_MASK_OFS = 0x1d64,
++ PORT0_ERR = (1 << 0), /* shift by port # */
++ PORT0_DONE = (1 << 1), /* shift by port # */
++ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
++ HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
++ PCI_ERR = (1 << 18),
++ TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
++ TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
++ PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
++ GPIO_INT = (1 << 22),
++ SELF_INT = (1 << 23),
++ TWSI_INT = (1 << 24),
++ HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
++ HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
++ PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
++ HC_MAIN_RSVD),
++
++ /* SATAHC registers */
++ HC_CFG_OFS = 0,
++
++ HC_IRQ_CAUSE_OFS = 0x14,
++ CRPB_DMA_DONE = (1 << 0), /* shift by port # */
++ HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
++ DEV_IRQ = (1 << 8), /* shift by port # */
++
++ /* Shadow block registers */
++ SHD_BLK_OFS = 0x100,
++ SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
++
++ /* SATA registers */
++ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
++ SATA_ACTIVE_OFS = 0x350,
++ PHY_MODE3 = 0x310,
++ PHY_MODE4 = 0x314,
++ PHY_MODE2 = 0x330,
++ MV5_PHY_MODE = 0x74,
++ MV5_LT_MODE = 0x30,
++ MV5_PHY_CTL = 0x0C,
++ SATA_INTERFACE_CTL = 0x050,
++
++ MV_M2_PREAMP_MASK = 0x7e0,
++
++ /* Port registers */
++ EDMA_CFG_OFS = 0,
++ EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */
++ EDMA_CFG_NCQ = (1 << 5),
++ EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
++ EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
++ EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
++
++ EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
++ EDMA_ERR_IRQ_MASK_OFS = 0xc,
++ EDMA_ERR_D_PAR = (1 << 0),
++ EDMA_ERR_PRD_PAR = (1 << 1),
++ EDMA_ERR_DEV = (1 << 2),
++ EDMA_ERR_DEV_DCON = (1 << 3),
++ EDMA_ERR_DEV_CON = (1 << 4),
++ EDMA_ERR_SERR = (1 << 5),
++ EDMA_ERR_SELF_DIS = (1 << 7),
++ EDMA_ERR_BIST_ASYNC = (1 << 8),
++ EDMA_ERR_CRBQ_PAR = (1 << 9),
++ EDMA_ERR_CRPB_PAR = (1 << 10),
++ EDMA_ERR_INTRL_PAR = (1 << 11),
++ EDMA_ERR_IORDY = (1 << 12),
++ EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
++ EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
++ EDMA_ERR_LNK_DATA_RX = (0xf << 17),
++ EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
++ EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
++ EDMA_ERR_TRANS_PROTO = (1 << 31),
++ EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
++ EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
++ EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
++ EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
++ EDMA_ERR_LNK_DATA_RX |
++ EDMA_ERR_LNK_DATA_TX |
++ EDMA_ERR_TRANS_PROTO),
++
++ EDMA_REQ_Q_BASE_HI_OFS = 0x10,
++ EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
++
++ EDMA_REQ_Q_OUT_PTR_OFS = 0x18,
++ EDMA_REQ_Q_PTR_SHIFT = 5,
++
++ EDMA_RSP_Q_BASE_HI_OFS = 0x1c,
++ EDMA_RSP_Q_IN_PTR_OFS = 0x20,
++ EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
++ EDMA_RSP_Q_PTR_SHIFT = 3,
++
++ EDMA_CMD_OFS = 0x28,
++ EDMA_EN = (1 << 0),
++ EDMA_DS = (1 << 1),
++ ATA_RST = (1 << 2),
++
++ EDMA_IORDY_TMOUT = 0x34,
++ EDMA_ARB_CFG = 0x38,
++
++ /* Host private flags (hp_flags) */
++ MV_HP_FLAG_MSI = (1 << 0),
++ MV_HP_ERRATA_50XXB0 = (1 << 1),
++ MV_HP_ERRATA_50XXB2 = (1 << 2),
++ MV_HP_ERRATA_60X1B2 = (1 << 3),
++ MV_HP_ERRATA_60X1C0 = (1 << 4),
++ MV_HP_ERRATA_XX42A0 = (1 << 5),
++ MV_HP_50XX = (1 << 6),
++ MV_HP_GEN_IIE = (1 << 7),
++
++ /* Port private flags (pp_flags) */
++ MV_PP_FLAG_EDMA_EN = (1 << 0),
++ MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
++};
++
++#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
++#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
++#define IS_GEN_I(hpriv) IS_50XX(hpriv)
++#define IS_GEN_II(hpriv) IS_60XX(hpriv)
++#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
++
++enum {
++ /* Our DMA boundary is determined by an ePRD being unable to handle
++ * anything larger than 64KB
++ */
++ MV_DMA_BOUNDARY = 0xffffU,
++
++ EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
++
++ EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
++};
++
++enum chip_type {
++ chip_504x,
++ chip_508x,
++ chip_5080,
++ chip_604x,
++ chip_608x,
++ chip_6042,
++ chip_7042,
++};
++
++/* Command ReQuest Block: 32B */
++struct mv_crqb {
++ __le32 sg_addr;
++ __le32 sg_addr_hi;
++ __le16 ctrl_flags;
++ __le16 ata_cmd[11];
++};
++
++struct mv_crqb_iie {
++ __le32 addr;
++ __le32 addr_hi;
++ __le32 flags;
++ __le32 len;
++ __le32 ata_cmd[4];
++};
++
++/* Command ResPonse Block: 8B */
++struct mv_crpb {
++ __le16 id;
++ __le16 flags;
++ __le32 tmstmp;
++};
++
++/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
++struct mv_sg {
++ __le32 addr;
++ __le32 flags_size;
++ __le32 addr_hi;
++ __le32 reserved;
++};
++
++struct mv_port_priv {
++ struct mv_crqb *crqb;
++ dma_addr_t crqb_dma;
++ struct mv_crpb *crpb;
++ dma_addr_t crpb_dma;
++ struct mv_sg *sg_tbl;
++ dma_addr_t sg_tbl_dma;
++ u32 pp_flags;
++};
++
++struct mv_port_signal {
++ u32 amps;
++ u32 pre;
++};
++
++struct mv_host_priv;
++struct mv_hw_ops {
++ void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port);
++ void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
++ void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
++ void __iomem *mmio);
++ int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int n_hc);
++ void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
++ void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
++};
++
++struct mv_host_priv {
++ u32 hp_flags;
++ struct mv_port_signal signal[8];
++ const struct mv_hw_ops *ops;
++};
++
++static void mv_irq_clear(struct ata_port *ap);
++static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
++static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
++static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
++static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
++static void mv_phy_reset(struct ata_port *ap);
++static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
++static void mv_host_stop(struct ata_host *host);
++static int mv_port_start(struct ata_port *ap);
++static void mv_port_stop(struct ata_port *ap);
++static void mv_qc_prep(struct ata_queued_cmd *qc);
++static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
++static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
++static irqreturn_t mv_interrupt(int irq, void *dev_instance);
++static void mv_eng_timeout(struct ata_port *ap);
++static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
++
++static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port);
++static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
++static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
++ void __iomem *mmio);
++static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int n_hc);
++static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
++static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
++
++static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port);
++static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
++static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
++ void __iomem *mmio);
++static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int n_hc);
++static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
++static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
++static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port_no);
++static void mv_stop_and_reset(struct ata_port *ap);
++
++static struct scsi_host_template mv_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = MV_USE_Q_DEPTH,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = MV_MAX_SG_CT / 2,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = MV_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations mv5_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .phy_reset = mv_phy_reset,
++
++ .qc_prep = mv_qc_prep,
++ .qc_issue = mv_qc_issue,
++ .data_xfer = ata_mmio_data_xfer,
++
++ .eng_timeout = mv_eng_timeout,
++
++ .irq_handler = mv_interrupt,
++ .irq_clear = mv_irq_clear,
++
++ .scr_read = mv5_scr_read,
++ .scr_write = mv5_scr_write,
++
++ .port_start = mv_port_start,
++ .port_stop = mv_port_stop,
++ .host_stop = mv_host_stop,
++};
++
++static const struct ata_port_operations mv6_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .phy_reset = mv_phy_reset,
++
++ .qc_prep = mv_qc_prep,
++ .qc_issue = mv_qc_issue,
++ .data_xfer = ata_mmio_data_xfer,
++
++ .eng_timeout = mv_eng_timeout,
++
++ .irq_handler = mv_interrupt,
++ .irq_clear = mv_irq_clear,
++
++ .scr_read = mv_scr_read,
++ .scr_write = mv_scr_write,
++
++ .port_start = mv_port_start,
++ .port_stop = mv_port_stop,
++ .host_stop = mv_host_stop,
++};
++
++static const struct ata_port_operations mv_iie_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .phy_reset = mv_phy_reset,
++
++ .qc_prep = mv_qc_prep_iie,
++ .qc_issue = mv_qc_issue,
++ .data_xfer = ata_mmio_data_xfer,
++
++ .eng_timeout = mv_eng_timeout,
++
++ .irq_handler = mv_interrupt,
++ .irq_clear = mv_irq_clear,
++
++ .scr_read = mv_scr_read,
++ .scr_write = mv_scr_write,
++
++ .port_start = mv_port_start,
++ .port_stop = mv_port_stop,
++ .host_stop = mv_host_stop,
++};
++
++static const struct ata_port_info mv_port_info[] = {
++ { /* chip_504x */
++ .sht = &mv_sht,
++ .flags = MV_COMMON_FLAGS,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv5_ops,
++ },
++ { /* chip_508x */
++ .sht = &mv_sht,
++ .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv5_ops,
++ },
++ { /* chip_5080 */
++ .sht = &mv_sht,
++ .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv5_ops,
++ },
++ { /* chip_604x */
++ .sht = &mv_sht,
++ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv6_ops,
++ },
++ { /* chip_608x */
++ .sht = &mv_sht,
++ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
++ MV_FLAG_DUAL_HC),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv6_ops,
++ },
++ { /* chip_6042 */
++ .sht = &mv_sht,
++ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv_iie_ops,
++ },
++ { /* chip_7042 */
++ .sht = &mv_sht,
++ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
++ MV_FLAG_DUAL_HC),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &mv_iie_ops,
++ },
++};
++
++static const struct pci_device_id mv_pci_tbl[] = {
++ { PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
++ { PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
++ { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
++ { PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
++
++ { PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
++ { PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
++ { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
++ { PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
++ { PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
++
++ { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver mv_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = mv_pci_tbl,
++ .probe = mv_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static const struct mv_hw_ops mv5xxx_ops = {
++ .phy_errata = mv5_phy_errata,
++ .enable_leds = mv5_enable_leds,
++ .read_preamp = mv5_read_preamp,
++ .reset_hc = mv5_reset_hc,
++ .reset_flash = mv5_reset_flash,
++ .reset_bus = mv5_reset_bus,
++};
++
++static const struct mv_hw_ops mv6xxx_ops = {
++ .phy_errata = mv6_phy_errata,
++ .enable_leds = mv6_enable_leds,
++ .read_preamp = mv6_read_preamp,
++ .reset_hc = mv6_reset_hc,
++ .reset_flash = mv6_reset_flash,
++ .reset_bus = mv_reset_pci_bus,
++};
++
++/*
++ * module options
++ */
++static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
++
++
++/*
++ * Functions
++ */
++
++static inline void writelfl(unsigned long data, void __iomem *addr)
++{
++ writel(data, addr);
++ (void) readl(addr); /* flush to avoid PCI posted write */
++}
++
++static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
++{
++ return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
++}
++
++static inline unsigned int mv_hc_from_port(unsigned int port)
++{
++ return port >> MV_PORT_HC_SHIFT;
++}
++
++static inline unsigned int mv_hardport_from_port(unsigned int port)
++{
++ return port & MV_PORT_MASK;
++}
++
++static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
++ unsigned int port)
++{
++ return mv_hc_base(base, mv_hc_from_port(port));
++}
++
++static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
++{
++ return mv_hc_base_from_port(base, port) +
++ MV_SATAHC_ARBTR_REG_SZ +
++ (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
++}
++
++static inline void __iomem *mv_ap_base(struct ata_port *ap)
++{
++ return mv_port_base(ap->host->mmio_base, ap->port_no);
++}
++
++static inline int mv_get_hc_count(unsigned long port_flags)
++{
++ return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
++}
++
++static void mv_irq_clear(struct ata_port *ap)
++{
++}
++
++/**
++ * mv_start_dma - Enable eDMA engine
++ * @base: port base address
++ * @pp: port private data
++ *
++ * Verify the local cache of the eDMA state is accurate with a
++ * WARN_ON.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
++{
++ if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
++ writelfl(EDMA_EN, base + EDMA_CMD_OFS);
++ pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
++ }
++ WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
++}
++
++/**
++ * mv_stop_dma - Disable eDMA engine
++ * @ap: ATA channel to manipulate
++ *
++ * Verify the local cache of the eDMA state is accurate with a
++ * WARN_ON.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_stop_dma(struct ata_port *ap)
++{
++ void __iomem *port_mmio = mv_ap_base(ap);
++ struct mv_port_priv *pp = ap->private_data;
++ u32 reg;
++ int i;
++
++ if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
++ /* Disable EDMA if active. The disable bit auto clears.
++ */
++ writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
++ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
++ } else {
++ WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
++ }
++
++ /* now properly wait for the eDMA to stop */
++ for (i = 1000; i > 0; i--) {
++ reg = readl(port_mmio + EDMA_CMD_OFS);
++ if (!(EDMA_EN & reg)) {
++ break;
++ }
++ udelay(100);
++ }
++
++ if (EDMA_EN & reg) {
++ ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
++ /* FIXME: Consider doing a reset here to recover */
++ }
++}
++
++#ifdef ATA_DEBUG
++static void mv_dump_mem(void __iomem *start, unsigned bytes)
++{
++ int b, w;
++ for (b = 0; b < bytes; ) {
++ DPRINTK("%p: ", start + b);
++ for (w = 0; b < bytes && w < 4; w++) {
++ printk("%08x ",readl(start + b));
++ b += sizeof(u32);
++ }
++ printk("\n");
++ }
++}
++#endif
++
++static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
++{
++#ifdef ATA_DEBUG
++ int b, w;
++ u32 dw;
++ for (b = 0; b < bytes; ) {
++ DPRINTK("%02x: ", b);
++ for (w = 0; b < bytes && w < 4; w++) {
++ (void) pci_read_config_dword(pdev,b,&dw);
++ printk("%08x ",dw);
++ b += sizeof(u32);
++ }
++ printk("\n");
++ }
++#endif
++}
++static void mv_dump_all_regs(void __iomem *mmio_base, int port,
++ struct pci_dev *pdev)
++{
++#ifdef ATA_DEBUG
++ void __iomem *hc_base = mv_hc_base(mmio_base,
++ port >> MV_PORT_HC_SHIFT);
++ void __iomem *port_base;
++ int start_port, num_ports, p, start_hc, num_hcs, hc;
++
++ if (0 > port) {
++ start_hc = start_port = 0;
++ num_ports = 8; /* shld be benign for 4 port devs */
++ num_hcs = 2;
++ } else {
++ start_hc = port >> MV_PORT_HC_SHIFT;
++ start_port = port;
++ num_ports = num_hcs = 1;
++ }
++ DPRINTK("All registers for port(s) %u-%u:\n", start_port,
++ num_ports > 1 ? num_ports - 1 : start_port);
++
++ if (NULL != pdev) {
++ DPRINTK("PCI config space regs:\n");
++ mv_dump_pci_cfg(pdev, 0x68);
++ }
++ DPRINTK("PCI regs:\n");
++ mv_dump_mem(mmio_base+0xc00, 0x3c);
++ mv_dump_mem(mmio_base+0xd00, 0x34);
++ mv_dump_mem(mmio_base+0xf00, 0x4);
++ mv_dump_mem(mmio_base+0x1d00, 0x6c);
++ for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
++ hc_base = mv_hc_base(mmio_base, hc);
++ DPRINTK("HC regs (HC %i):\n", hc);
++ mv_dump_mem(hc_base, 0x1c);
++ }
++ for (p = start_port; p < start_port + num_ports; p++) {
++ port_base = mv_port_base(mmio_base, p);
++ DPRINTK("EDMA regs (port %i):\n",p);
++ mv_dump_mem(port_base, 0x54);
++ DPRINTK("SATA regs (port %i):\n",p);
++ mv_dump_mem(port_base+0x300, 0x60);
++ }
++#endif
++}
++
++static unsigned int mv_scr_offset(unsigned int sc_reg_in)
++{
++ unsigned int ofs;
++
++ switch (sc_reg_in) {
++ case SCR_STATUS:
++ case SCR_CONTROL:
++ case SCR_ERROR:
++ ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
++ break;
++ case SCR_ACTIVE:
++ ofs = SATA_ACTIVE_OFS; /* active is not with the others */
++ break;
++ default:
++ ofs = 0xffffffffU;
++ break;
++ }
++ return ofs;
++}
++
++static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
++{
++ unsigned int ofs = mv_scr_offset(sc_reg_in);
++
++ if (0xffffffffU != ofs) {
++ return readl(mv_ap_base(ap) + ofs);
++ } else {
++ return (u32) ofs;
++ }
++}
++
++static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
++{
++ unsigned int ofs = mv_scr_offset(sc_reg_in);
++
++ if (0xffffffffU != ofs) {
++ writelfl(val, mv_ap_base(ap) + ofs);
++ }
++}
++
++/**
++ * mv_host_stop - Host specific cleanup/stop routine.
++ * @host: host data structure
++ *
++ * Disable ints, cleanup host memory, call general purpose
++ * host_stop.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_host_stop(struct ata_host *host)
++{
++ struct mv_host_priv *hpriv = host->private_data;
++ struct pci_dev *pdev = to_pci_dev(host->dev);
++
++ if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
++ pci_disable_msi(pdev);
++ } else {
++ pci_intx(pdev, 0);
++ }
++ kfree(hpriv);
++ ata_host_stop(host);
++}
++
++static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
++{
++ dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
++}
++
++static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
++{
++ u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
++
++ /* set up non-NCQ EDMA configuration */
++ cfg &= ~0x1f; /* clear queue depth */
++ cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */
++ cfg &= ~(1 << 9); /* disable equeue */
++
++ if (IS_GEN_I(hpriv))
++ cfg |= (1 << 8); /* enab config burst size mask */
++
++ else if (IS_GEN_II(hpriv))
++ cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
++
++ else if (IS_GEN_IIE(hpriv)) {
++ cfg |= (1 << 23); /* dis RX PM port mask */
++ cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
++ cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
++ cfg |= (1 << 18); /* enab early completion */
++ cfg |= (1 << 17); /* enab host q cache */
++ cfg |= (1 << 22); /* enab cutthrough */
++ }
++
++ writelfl(cfg, port_mmio + EDMA_CFG_OFS);
++}
++
++/**
++ * mv_port_start - Port specific init/start routine.
++ * @ap: ATA channel to manipulate
++ *
++ * Allocate and point to DMA memory, init port private memory,
++ * zero indices.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static int mv_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct mv_host_priv *hpriv = ap->host->private_data;
++ struct mv_port_priv *pp;
++ void __iomem *port_mmio = mv_ap_base(ap);
++ void *mem;
++ dma_addr_t mem_dma;
++ int rc = -ENOMEM;
++
++ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
++ if (!pp)
++ goto err_out;
++ memset(pp, 0, sizeof(*pp));
++
++ mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
++ GFP_KERNEL);
++ if (!mem)
++ goto err_out_pp;
++ memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
++
++ rc = ata_pad_alloc(ap, dev);
++ if (rc)
++ goto err_out_priv;
++
++ /* First item in chunk of DMA memory:
++ * 32-slot command request table (CRQB), 32 bytes each in size
++ */
++ pp->crqb = mem;
++ pp->crqb_dma = mem_dma;
++ mem += MV_CRQB_Q_SZ;
++ mem_dma += MV_CRQB_Q_SZ;
++
++ /* Second item:
++ * 32-slot command response table (CRPB), 8 bytes each in size
++ */
++ pp->crpb = mem;
++ pp->crpb_dma = mem_dma;
++ mem += MV_CRPB_Q_SZ;
++ mem_dma += MV_CRPB_Q_SZ;
++
++ /* Third item:
++ * Table of scatter-gather descriptors (ePRD), 16 bytes each
++ */
++ pp->sg_tbl = mem;
++ pp->sg_tbl_dma = mem_dma;
++
++ mv_edma_cfg(hpriv, port_mmio);
++
++ writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
++ writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
++ port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
++
++ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
++ writelfl(pp->crqb_dma & 0xffffffff,
++ port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
++ else
++ writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
++
++ writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
++
++ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
++ writelfl(pp->crpb_dma & 0xffffffff,
++ port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
++ else
++ writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
++
++ writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
++ port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
++
++ /* Don't turn on EDMA here...do it before DMA commands only. Else
++ * we'll be unable to send non-data, PIO, etc due to restricted access
++ * to shadow regs.
++ */
++ ap->private_data = pp;
++ return 0;
++
++err_out_priv:
++ mv_priv_free(pp, dev);
++err_out_pp:
++ kfree(pp);
++err_out:
++ return rc;
++}
++
++/**
++ * mv_port_stop - Port specific cleanup/stop routine.
++ * @ap: ATA channel to manipulate
++ *
++ * Stop DMA, cleanup port memory.
++ *
++ * LOCKING:
++ * This routine uses the host lock to protect the DMA stop.
++ */
++static void mv_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct mv_port_priv *pp = ap->private_data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ap->host->lock, flags);
++ mv_stop_dma(ap);
++ spin_unlock_irqrestore(&ap->host->lock, flags);
++
++ ap->private_data = NULL;
++ ata_pad_free(ap, dev);
++ mv_priv_free(pp, dev);
++ kfree(pp);
++}
++
++/**
++ * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
++ * @qc: queued command whose SG list to source from
++ *
++ * Populate the SG list and mark the last entry.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_fill_sg(struct ata_queued_cmd *qc)
++{
++ struct mv_port_priv *pp = qc->ap->private_data;
++ unsigned int i = 0;
++ struct scatterlist *sg;
++
++ ata_for_each_sg(sg, qc) {
++ dma_addr_t addr;
++ u32 sg_len, len, offset;
++
++ addr = sg_dma_address(sg);
++ sg_len = sg_dma_len(sg);
++
++ while (sg_len) {
++ offset = addr & MV_DMA_BOUNDARY;
++ len = sg_len;
++ if ((offset + sg_len) > 0x10000)
++ len = 0x10000 - offset;
++
++ pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
++ pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
++ pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
++
++ sg_len -= len;
++ addr += len;
++
++ if (!sg_len && ata_sg_is_last(sg, qc))
++ pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
++
++ i++;
++ }
++ }
++}
++
++static inline unsigned mv_inc_q_index(unsigned index)
++{
++ return (index + 1) & MV_MAX_Q_DEPTH_MASK;
++}
++
++static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
++{
++ u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
++ (last ? CRQB_CMD_LAST : 0);
++ *cmdw = cpu_to_le16(tmp);
++}
++
++/**
++ * mv_qc_prep - Host specific command preparation.
++ * @qc: queued command to prepare
++ *
++ * This routine simply redirects to the general purpose routine
++ * if command is not DMA. Else, it handles prep of the CRQB
++ * (command request block), does some sanity checking, and calls
++ * the SG load routine.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_qc_prep(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct mv_port_priv *pp = ap->private_data;
++ __le16 *cw;
++ struct ata_taskfile *tf;
++ u16 flags = 0;
++ unsigned in_index;
++
++ if (ATA_PROT_DMA != qc->tf.protocol)
++ return;
++
++ /* Fill in command request block
++ */
++ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
++ flags |= CRQB_FLAG_READ;
++ WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
++ flags |= qc->tag << CRQB_TAG_SHIFT;
++
++ /* get current queue index from hardware */
++ in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
++ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
++
++ pp->crqb[in_index].sg_addr =
++ cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
++ pp->crqb[in_index].sg_addr_hi =
++ cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
++ pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
++
++ cw = &pp->crqb[in_index].ata_cmd[0];
++ tf = &qc->tf;
++
++ /* Sadly, the CRQB cannot accomodate all registers--there are
++ * only 11 bytes...so we must pick and choose required
++ * registers based on the command. So, we drop feature and
++ * hob_feature for [RW] DMA commands, but they are needed for
++ * NCQ. NCQ will drop hob_nsect.
++ */
++ switch (tf->command) {
++ case ATA_CMD_READ:
++ case ATA_CMD_READ_EXT:
++ case ATA_CMD_WRITE:
++ case ATA_CMD_WRITE_EXT:
++ case ATA_CMD_WRITE_FUA_EXT:
++ mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
++ break;
++#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */
++ case ATA_CMD_FPDMA_READ:
++ case ATA_CMD_FPDMA_WRITE:
++ mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
++ mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
++ break;
++#endif /* FIXME: remove this line when NCQ added */
++ default:
++ /* The only other commands EDMA supports in non-queued and
++ * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
++ * of which are defined/used by Linux. If we get here, this
++ * driver needs work.
++ *
++ * FIXME: modify libata to give qc_prep a return value and
++ * return error here.
++ */
++ BUG_ON(tf->command);
++ break;
++ }
++ mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
++ mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
++ mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
++ mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
++ mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
++ mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
++ mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
++ mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
++ mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */
++
++ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
++ return;
++ mv_fill_sg(qc);
++}
++
++/**
++ * mv_qc_prep_iie - Host specific command preparation.
++ * @qc: queued command to prepare
++ *
++ * This routine simply redirects to the general purpose routine
++ * if command is not DMA. Else, it handles prep of the CRQB
++ * (command request block), does some sanity checking, and calls
++ * the SG load routine.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct mv_port_priv *pp = ap->private_data;
++ struct mv_crqb_iie *crqb;
++ struct ata_taskfile *tf;
++ unsigned in_index;
++ u32 flags = 0;
++
++ if (ATA_PROT_DMA != qc->tf.protocol)
++ return;
++
++ /* Fill in Gen IIE command request block
++ */
++ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
++ flags |= CRQB_FLAG_READ;
++
++ WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
++ flags |= qc->tag << CRQB_TAG_SHIFT;
++
++ /* get current queue index from hardware */
++ in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
++ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
++
++ crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
++ crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
++ crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
++ crqb->flags = cpu_to_le32(flags);
++
++ tf = &qc->tf;
++ crqb->ata_cmd[0] = cpu_to_le32(
++ (tf->command << 16) |
++ (tf->feature << 24)
++ );
++ crqb->ata_cmd[1] = cpu_to_le32(
++ (tf->lbal << 0) |
++ (tf->lbam << 8) |
++ (tf->lbah << 16) |
++ (tf->device << 24)
++ );
++ crqb->ata_cmd[2] = cpu_to_le32(
++ (tf->hob_lbal << 0) |
++ (tf->hob_lbam << 8) |
++ (tf->hob_lbah << 16) |
++ (tf->hob_feature << 24)
++ );
++ crqb->ata_cmd[3] = cpu_to_le32(
++ (tf->nsect << 0) |
++ (tf->hob_nsect << 8)
++ );
++
++ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
++ return;
++ mv_fill_sg(qc);
++}
++
++/**
++ * mv_qc_issue - Initiate a command to the host
++ * @qc: queued command to start
++ *
++ * This routine simply redirects to the general purpose routine
++ * if command is not DMA. Else, it sanity checks our local
++ * caches of the request producer/consumer indices then enables
++ * DMA and bumps the request producer index.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
++{
++ void __iomem *port_mmio = mv_ap_base(qc->ap);
++ struct mv_port_priv *pp = qc->ap->private_data;
++ unsigned in_index;
++ u32 in_ptr;
++
++ if (ATA_PROT_DMA != qc->tf.protocol) {
++ /* We're about to send a non-EDMA capable command to the
++ * port. Turn off EDMA so there won't be problems accessing
++ * shadow block, etc registers.
++ */
++ mv_stop_dma(qc->ap);
++ return ata_qc_issue_prot(qc);
++ }
++
++ in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
++ in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
++
++ /* until we do queuing, the queue should be empty at this point */
++ WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
++ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
++
++ in_index = mv_inc_q_index(in_index); /* now incr producer index */
++
++ mv_start_dma(port_mmio, pp);
++
++ /* and write the request in pointer to kick the EDMA to life */
++ in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
++ in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
++ writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
++
++ return 0;
++}
++
++/**
++ * mv_get_crpb_status - get status from most recently completed cmd
++ * @ap: ATA channel to manipulate
++ *
++ * This routine is for use when the port is in DMA mode, when it
++ * will be using the CRPB (command response block) method of
++ * returning command completion information. We check indices
++ * are good, grab status, and bump the response consumer index to
++ * prove that we're up to date.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static u8 mv_get_crpb_status(struct ata_port *ap)
++{
++ void __iomem *port_mmio = mv_ap_base(ap);
++ struct mv_port_priv *pp = ap->private_data;
++ unsigned out_index;
++ u32 out_ptr;
++ u8 ata_status;
++
++ out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
++ out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
++
++ ata_status = le16_to_cpu(pp->crpb[out_index].flags)
++ >> CRPB_FLAG_STATUS_SHIFT;
++
++ /* increment our consumer index... */
++ out_index = mv_inc_q_index(out_index);
++
++ /* and, until we do NCQ, there should only be 1 CRPB waiting */
++ WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
++ >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
++
++ /* write out our inc'd consumer index so EDMA knows we're caught up */
++ out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
++ out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
++ writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
++
++ /* Return ATA status register for completed CRPB */
++ return ata_status;
++}
++
++/**
++ * mv_err_intr - Handle error interrupts on the port
++ * @ap: ATA channel to manipulate
++ * @reset_allowed: bool: 0 == don't trigger from reset here
++ *
++ * In most cases, just clear the interrupt and move on. However,
++ * some cases require an eDMA reset, which is done right before
++ * the COMRESET in mv_phy_reset(). The SERR case requires a
++ * clear of pending errors in the SATA SERROR register. Finally,
++ * if the port disabled DMA, update our cached copy to match.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_err_intr(struct ata_port *ap, int reset_allowed)
++{
++ void __iomem *port_mmio = mv_ap_base(ap);
++ u32 edma_err_cause, serr = 0;
++
++ edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
++
++ if (EDMA_ERR_SERR & edma_err_cause) {
++ sata_scr_read(ap, SCR_ERROR, &serr);
++ sata_scr_write_flush(ap, SCR_ERROR, serr);
++ }
++ if (EDMA_ERR_SELF_DIS & edma_err_cause) {
++ struct mv_port_priv *pp = ap->private_data;
++ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
++ }
++ DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
++ "SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
++
++ /* Clear EDMA now that SERR cleanup done */
++ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
++
++ /* check for fatal here and recover if needed */
++ if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
++ mv_stop_and_reset(ap);
++}
++
++/**
++ * mv_host_intr - Handle all interrupts on the given host controller
++ * @host: host specific structure
++ * @relevant: port error bits relevant to this host controller
++ * @hc: which host controller we're to look at
++ *
++ * Read then write clear the HC interrupt status then walk each
++ * port connected to the HC and see if it needs servicing. Port
++ * success ints are reported in the HC interrupt status reg, the
++ * port error ints are reported in the higher level main
++ * interrupt status register and thus are passed in via the
++ * 'relevant' argument.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
++{
++ void __iomem *mmio = host->mmio_base;
++ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
++ struct ata_queued_cmd *qc;
++ u32 hc_irq_cause;
++ int shift, port, port0, hard_port, handled;
++ unsigned int err_mask;
++
++ if (hc == 0) {
++ port0 = 0;
++ } else {
++ port0 = MV_PORTS_PER_HC;
++ }
++
++ /* we'll need the HC success int register in most cases */
++ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
++ if (hc_irq_cause) {
++ writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
++ }
++
++ VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
++ hc,relevant,hc_irq_cause);
++
++ for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
++ u8 ata_status = 0;
++ struct ata_port *ap = host->ports[port];
++ struct mv_port_priv *pp = ap->private_data;
++
++ hard_port = mv_hardport_from_port(port); /* range 0..3 */
++ handled = 0; /* ensure ata_status is set if handled++ */
++
++ /* Note that DEV_IRQ might happen spuriously during EDMA,
++ * and should be ignored in such cases.
++ * The cause of this is still under investigation.
++ */
++ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
++ /* EDMA: check for response queue interrupt */
++ if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
++ ata_status = mv_get_crpb_status(ap);
++ handled = 1;
++ }
++ } else {
++ /* PIO: check for device (drive) interrupt */
++ if ((DEV_IRQ << hard_port) & hc_irq_cause) {
++ ata_status = readb((void __iomem *)
++ ap->ioaddr.status_addr);
++ handled = 1;
++ /* ignore spurious intr if drive still BUSY */
++ if (ata_status & ATA_BUSY) {
++ ata_status = 0;
++ handled = 0;
++ }
++ }
++ }
++
++ if (ap && (ap->flags & ATA_FLAG_DISABLED))
++ continue;
++
++ err_mask = ac_err_mask(ata_status);
++
++ shift = port << 1; /* (port * 2) */
++ if (port >= MV_PORTS_PER_HC) {
++ shift++; /* skip bit 8 in the HC Main IRQ reg */
++ }
++ if ((PORT0_ERR << shift) & relevant) {
++ mv_err_intr(ap, 1);
++ err_mask |= AC_ERR_OTHER;
++ handled = 1;
++ }
++
++ if (handled) {
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
++ VPRINTK("port %u IRQ found for qc, "
++ "ata_status 0x%x\n", port,ata_status);
++ /* mark qc status appropriately */
++ if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
++ qc->err_mask |= err_mask;
++ ata_qc_complete(qc);
++ }
++ }
++ }
++ }
++ VPRINTK("EXIT\n");
++}
++
++/**
++ * mv_interrupt -
++ * @irq: unused
++ * @dev_instance: private data; in this case the host structure
++ * @regs: unused
++ *
++ * Read the read only register to determine if any host
++ * controllers have pending interrupts. If so, call lower level
++ * routine to handle. Also check for PCI errors which are only
++ * reported here.
++ *
++ * LOCKING:
++ * This routine holds the host lock while processing pending
++ * interrupts.
++ */
++static irqreturn_t mv_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ unsigned int hc, handled = 0, n_hcs;
++ void __iomem *mmio = host->mmio_base;
++ struct mv_host_priv *hpriv;
++ u32 irq_stat;
++
++ irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
++
++ /* check the cases where we either have nothing pending or have read
++ * a bogus register value which can indicate HW removal or PCI fault
++ */
++ if (!irq_stat || (0xffffffffU == irq_stat)) {
++ return IRQ_NONE;
++ }
++
++ n_hcs = mv_get_hc_count(host->ports[0]->flags);
++ spin_lock(&host->lock);
++
++ for (hc = 0; hc < n_hcs; hc++) {
++ u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
++ if (relevant) {
++ mv_host_intr(host, relevant, hc);
++ handled++;
++ }
++ }
++
++ hpriv = host->private_data;
++ if (IS_60XX(hpriv)) {
++ /* deal with the interrupt coalescing bits */
++ if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
++ writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
++ writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
++ writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
++ }
++ }
++
++ if (PCI_ERR & irq_stat) {
++ printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
++ readl(mmio + PCI_IRQ_CAUSE_OFS));
++
++ DPRINTK("All regs @ PCI error\n");
++ mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
++
++ writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
++ handled++;
++ }
++ spin_unlock(&host->lock);
++
++ return IRQ_RETVAL(handled);
++}
++
++static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
++{
++ void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
++ unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
++
++ return hc_mmio + ofs;
++}
++
++static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
++{
++ unsigned int ofs;
++
++ switch (sc_reg_in) {
++ case SCR_STATUS:
++ case SCR_ERROR:
++ case SCR_CONTROL:
++ ofs = sc_reg_in * sizeof(u32);
++ break;
++ default:
++ ofs = 0xffffffffU;
++ break;
++ }
++ return ofs;
++}
++
++static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
++{
++ void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
++ unsigned int ofs = mv5_scr_offset(sc_reg_in);
++
++ if (ofs != 0xffffffffU)
++ return readl(mmio + ofs);
++ else
++ return (u32) ofs;
++}
++
++static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
++{
++ void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
++ unsigned int ofs = mv5_scr_offset(sc_reg_in);
++
++ if (ofs != 0xffffffffU)
++ writelfl(val, mmio + ofs);
++}
++
++static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
++{
++ u8 rev_id;
++ int early_5080;
++
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
++
++ early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
++
++ if (!early_5080) {
++ u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
++ tmp |= (1 << 0);
++ writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
++ }
++
++ mv_reset_pci_bus(pdev, mmio);
++}
++
++static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
++{
++ writel(0x0fcfffff, mmio + MV_FLASH_CTL);
++}
++
++static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
++ void __iomem *mmio)
++{
++ void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
++ u32 tmp;
++
++ tmp = readl(phy_mmio + MV5_PHY_MODE);
++
++ hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */
++ hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */
++}
++
++static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
++{
++ u32 tmp;
++
++ writel(0, mmio + MV_GPIO_PORT_CTL);
++
++ /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
++
++ tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
++ tmp |= ~(1 << 0);
++ writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
++}
++
++static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port)
++{
++ void __iomem *phy_mmio = mv5_phy_base(mmio, port);
++ const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
++ u32 tmp;
++ int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
++
++ if (fix_apm_sq) {
++ tmp = readl(phy_mmio + MV5_LT_MODE);
++ tmp |= (1 << 19);
++ writel(tmp, phy_mmio + MV5_LT_MODE);
++
++ tmp = readl(phy_mmio + MV5_PHY_CTL);
++ tmp &= ~0x3;
++ tmp |= 0x1;
++ writel(tmp, phy_mmio + MV5_PHY_CTL);
++ }
++
++ tmp = readl(phy_mmio + MV5_PHY_MODE);
++ tmp &= ~mask;
++ tmp |= hpriv->signal[port].pre;
++ tmp |= hpriv->signal[port].amps;
++ writel(tmp, phy_mmio + MV5_PHY_MODE);
++}
++
++
++#undef ZERO
++#define ZERO(reg) writel(0, port_mmio + (reg))
++static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port)
++{
++ void __iomem *port_mmio = mv_port_base(mmio, port);
++
++ writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
++
++ mv_channel_reset(hpriv, mmio, port);
++
++ ZERO(0x028); /* command */
++ writel(0x11f, port_mmio + EDMA_CFG_OFS);
++ ZERO(0x004); /* timer */
++ ZERO(0x008); /* irq err cause */
++ ZERO(0x00c); /* irq err mask */
++ ZERO(0x010); /* rq bah */
++ ZERO(0x014); /* rq inp */
++ ZERO(0x018); /* rq outp */
++ ZERO(0x01c); /* respq bah */
++ ZERO(0x024); /* respq outp */
++ ZERO(0x020); /* respq inp */
++ ZERO(0x02c); /* test control */
++ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
++}
++#undef ZERO
++
++#define ZERO(reg) writel(0, hc_mmio + (reg))
++static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int hc)
++{
++ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
++ u32 tmp;
++
++ ZERO(0x00c);
++ ZERO(0x010);
++ ZERO(0x014);
++ ZERO(0x018);
++
++ tmp = readl(hc_mmio + 0x20);
++ tmp &= 0x1c1c1c1c;
++ tmp |= 0x03030303;
++ writel(tmp, hc_mmio + 0x20);
++}
++#undef ZERO
++
++static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int n_hc)
++{
++ unsigned int hc, port;
++
++ for (hc = 0; hc < n_hc; hc++) {
++ for (port = 0; port < MV_PORTS_PER_HC; port++)
++ mv5_reset_hc_port(hpriv, mmio,
++ (hc * MV_PORTS_PER_HC) + port);
++
++ mv5_reset_one_hc(hpriv, mmio, hc);
++ }
++
++ return 0;
++}
++
++#undef ZERO
++#define ZERO(reg) writel(0, mmio + (reg))
++static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
++{
++ u32 tmp;
++
++ tmp = readl(mmio + MV_PCI_MODE);
++ tmp &= 0xff00ffff;
++ writel(tmp, mmio + MV_PCI_MODE);
++
++ ZERO(MV_PCI_DISC_TIMER);
++ ZERO(MV_PCI_MSI_TRIGGER);
++ writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
++ ZERO(HC_MAIN_IRQ_MASK_OFS);
++ ZERO(MV_PCI_SERR_MASK);
++ ZERO(PCI_IRQ_CAUSE_OFS);
++ ZERO(PCI_IRQ_MASK_OFS);
++ ZERO(MV_PCI_ERR_LOW_ADDRESS);
++ ZERO(MV_PCI_ERR_HIGH_ADDRESS);
++ ZERO(MV_PCI_ERR_ATTRIBUTE);
++ ZERO(MV_PCI_ERR_COMMAND);
++}
++#undef ZERO
++
++static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
++{
++ u32 tmp;
++
++ mv5_reset_flash(hpriv, mmio);
++
++ tmp = readl(mmio + MV_GPIO_PORT_CTL);
++ tmp &= 0x3;
++ tmp |= (1 << 5) | (1 << 6);
++ writel(tmp, mmio + MV_GPIO_PORT_CTL);
++}
++
++/**
++ * mv6_reset_hc - Perform the 6xxx global soft reset
++ * @mmio: base address of the HBA
++ *
++ * This routine only applies to 6xxx parts.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int n_hc)
++{
++ void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
++ int i, rc = 0;
++ u32 t;
++
++ /* Following procedure defined in PCI "main command and status
++ * register" table.
++ */
++ t = readl(reg);
++ writel(t | STOP_PCI_MASTER, reg);
++
++ for (i = 0; i < 1000; i++) {
++ udelay(1);
++ t = readl(reg);
++ if (PCI_MASTER_EMPTY & t) {
++ break;
++ }
++ }
++ if (!(PCI_MASTER_EMPTY & t)) {
++ printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
++ rc = 1;
++ goto done;
++ }
++
++ /* set reset */
++ i = 5;
++ do {
++ writel(t | GLOB_SFT_RST, reg);
++ t = readl(reg);
++ udelay(1);
++ } while (!(GLOB_SFT_RST & t) && (i-- > 0));
++
++ if (!(GLOB_SFT_RST & t)) {
++ printk(KERN_ERR DRV_NAME ": can't set global reset\n");
++ rc = 1;
++ goto done;
++ }
++
++ /* clear reset and *reenable the PCI master* (not mentioned in spec) */
++ i = 5;
++ do {
++ writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
++ t = readl(reg);
++ udelay(1);
++ } while ((GLOB_SFT_RST & t) && (i-- > 0));
++
++ if (GLOB_SFT_RST & t) {
++ printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
++ rc = 1;
++ }
++done:
++ return rc;
++}
++
++static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
++ void __iomem *mmio)
++{
++ void __iomem *port_mmio;
++ u32 tmp;
++
++ tmp = readl(mmio + MV_RESET_CFG);
++ if ((tmp & (1 << 0)) == 0) {
++ hpriv->signal[idx].amps = 0x7 << 8;
++ hpriv->signal[idx].pre = 0x1 << 5;
++ return;
++ }
++
++ port_mmio = mv_port_base(mmio, idx);
++ tmp = readl(port_mmio + PHY_MODE2);
++
++ hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */
++ hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */
++}
++
++static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
++{
++ writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
++}
++
++static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port)
++{
++ void __iomem *port_mmio = mv_port_base(mmio, port);
++
++ u32 hp_flags = hpriv->hp_flags;
++ int fix_phy_mode2 =
++ hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
++ int fix_phy_mode4 =
++ hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
++ u32 m2, tmp;
++
++ if (fix_phy_mode2) {
++ m2 = readl(port_mmio + PHY_MODE2);
++ m2 &= ~(1 << 16);
++ m2 |= (1 << 31);
++ writel(m2, port_mmio + PHY_MODE2);
++
++ udelay(200);
++
++ m2 = readl(port_mmio + PHY_MODE2);
++ m2 &= ~((1 << 16) | (1 << 31));
++ writel(m2, port_mmio + PHY_MODE2);
++
++ udelay(200);
++ }
++
++ /* who knows what this magic does */
++ tmp = readl(port_mmio + PHY_MODE3);
++ tmp &= ~0x7F800000;
++ tmp |= 0x2A800000;
++ writel(tmp, port_mmio + PHY_MODE3);
++
++ if (fix_phy_mode4) {
++ u32 m4;
++
++ m4 = readl(port_mmio + PHY_MODE4);
++
++ if (hp_flags & MV_HP_ERRATA_60X1B2)
++ tmp = readl(port_mmio + 0x310);
++
++ m4 = (m4 & ~(1 << 1)) | (1 << 0);
++
++ writel(m4, port_mmio + PHY_MODE4);
++
++ if (hp_flags & MV_HP_ERRATA_60X1B2)
++ writel(tmp, port_mmio + 0x310);
++ }
++
++ /* Revert values of pre-emphasis and signal amps to the saved ones */
++ m2 = readl(port_mmio + PHY_MODE2);
++
++ m2 &= ~MV_M2_PREAMP_MASK;
++ m2 |= hpriv->signal[port].amps;
++ m2 |= hpriv->signal[port].pre;
++ m2 &= ~(1 << 16);
++
++ /* according to mvSata 3.6.1, some IIE values are fixed */
++ if (IS_GEN_IIE(hpriv)) {
++ m2 &= ~0xC30FF01F;
++ m2 |= 0x0000900F;
++ }
++
++ writel(m2, port_mmio + PHY_MODE2);
++}
++
++static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
++ unsigned int port_no)
++{
++ void __iomem *port_mmio = mv_port_base(mmio, port_no);
++
++ writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
++
++ if (IS_60XX(hpriv)) {
++ u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
++ ifctl |= (1 << 7); /* enable gen2i speed */
++ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
++ writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
++ }
++
++ udelay(25); /* allow reset propagation */
++
++ /* Spec never mentions clearing the bit. Marvell's driver does
++ * clear the bit, however.
++ */
++ writelfl(0, port_mmio + EDMA_CMD_OFS);
++
++ hpriv->ops->phy_errata(hpriv, mmio, port_no);
++
++ if (IS_50XX(hpriv))
++ mdelay(1);
++}
++
++static void mv_stop_and_reset(struct ata_port *ap)
++{
++ struct mv_host_priv *hpriv = ap->host->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++
++ mv_stop_dma(ap);
++
++ mv_channel_reset(hpriv, mmio, ap->port_no);
++
++ __mv_phy_reset(ap, 0);
++}
++
++static inline void __msleep(unsigned int msec, int can_sleep)
++{
++ if (can_sleep)
++ msleep(msec);
++ else
++ mdelay(msec);
++}
++
++/**
++ * __mv_phy_reset - Perform eDMA reset followed by COMRESET
++ * @ap: ATA channel to manipulate
++ *
++ * Part of this is taken from __sata_phy_reset and modified to
++ * not sleep since this routine gets called from interrupt level.
++ *
++ * LOCKING:
++ * Inherited from caller. This is coded to safe to call at
++ * interrupt level, i.e. it does not sleep.
++ */
++static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
++{
++ struct mv_port_priv *pp = ap->private_data;
++ struct mv_host_priv *hpriv = ap->host->private_data;
++ void __iomem *port_mmio = mv_ap_base(ap);
++ struct ata_taskfile tf;
++ struct ata_device *dev = &ap->device[0];
++ unsigned long timeout;
++ int retry = 5;
++ u32 sstatus;
++
++ VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
++
++ DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
++ "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
++ mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
++
++ /* Issue COMRESET via SControl */
++comreset_retry:
++ sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
++ __msleep(1, can_sleep);
++
++ sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
++ __msleep(20, can_sleep);
++
++ timeout = jiffies + msecs_to_jiffies(200);
++ do {
++ sata_scr_read(ap, SCR_STATUS, &sstatus);
++ if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
++ break;
++
++ __msleep(1, can_sleep);
++ } while (time_before(jiffies, timeout));
++
++ /* work around errata */
++ if (IS_60XX(hpriv) &&
++ (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
++ (retry-- > 0))
++ goto comreset_retry;
++
++ DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
++ "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
++ mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
++
++ if (ata_port_online(ap)) {
++ ata_port_probe(ap);
++ } else {
++ sata_scr_read(ap, SCR_STATUS, &sstatus);
++ ata_port_printk(ap, KERN_INFO,
++ "no device found (phy stat %08x)\n", sstatus);
++ ata_port_disable(ap);
++ return;
++ }
++ ap->cbl = ATA_CBL_SATA;
++
++ /* even after SStatus reflects that device is ready,
++ * it seems to take a while for link to be fully
++ * established (and thus Status no longer 0x80/0x7F),
++ * so we poll a bit for that, here.
++ */
++ retry = 20;
++ while (1) {
++ u8 drv_stat = ata_check_status(ap);
++ if ((drv_stat != 0x80) && (drv_stat != 0x7f))
++ break;
++ __msleep(500, can_sleep);
++ if (retry-- <= 0)
++ break;
++ }
++
++ tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
++ tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
++ tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
++ tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
++
++ dev->class = ata_dev_classify(&tf);
++ if (!ata_dev_enabled(dev)) {
++ VPRINTK("Port disabled post-sig: No device present.\n");
++ ata_port_disable(ap);
++ }
++
++ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
++
++ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
++
++ VPRINTK("EXIT\n");
++}
++
++static void mv_phy_reset(struct ata_port *ap)
++{
++ __mv_phy_reset(ap, 1);
++}
++
++/**
++ * mv_eng_timeout - Routine called by libata when SCSI times out I/O
++ * @ap: ATA channel to manipulate
++ *
++ * Intent is to clear all pending error conditions, reset the
++ * chip/bus, fail the command, and move on.
++ *
++ * LOCKING:
++ * This routine holds the host lock while failing the command.
++ */
++static void mv_eng_timeout(struct ata_port *ap)
++{
++ struct ata_queued_cmd *qc;
++ unsigned long flags;
++
++ ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
++ DPRINTK("All regs @ start of eng_timeout\n");
++ mv_dump_all_regs(ap->host->mmio_base, ap->port_no,
++ to_pci_dev(ap->host->dev));
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
++ ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
++
++ spin_lock_irqsave(&ap->host->lock, flags);
++ mv_err_intr(ap, 0);
++ mv_stop_and_reset(ap);
++ spin_unlock_irqrestore(&ap->host->lock, flags);
++
++ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
++ if (qc->flags & ATA_QCFLAG_ACTIVE) {
++ qc->err_mask |= AC_ERR_TIMEOUT;
++ ata_eh_qc_complete(qc);
++ }
++}
++
++/**
++ * mv_port_init - Perform some early initialization on a single port.
++ * @port: libata data structure storing shadow register addresses
++ * @port_mmio: base address of the port
++ *
++ * Initialize shadow register mmio addresses, clear outstanding
++ * interrupts on the port, and unmask interrupts for the future
++ * start of the port.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
++{
++ unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
++ unsigned serr_ofs;
++
++ /* PIO related setup
++ */
++ port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
++ port->error_addr =
++ port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
++ port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
++ port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
++ port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
++ port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
++ port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
++ port->status_addr =
++ port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
++ /* special case: control/altstatus doesn't have ATA_REG_ address */
++ port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
++
++ /* unused: */
++ port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
++
++ /* Clear any currently outstanding port interrupt conditions */
++ serr_ofs = mv_scr_offset(SCR_ERROR);
++ writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
++ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
++
++ /* unmask all EDMA error interrupts */
++ writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
++
++ VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
++ readl(port_mmio + EDMA_CFG_OFS),
++ readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
++ readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
++}
++
++static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
++ unsigned int board_idx)
++{
++ u8 rev_id;
++ u32 hp_flags = hpriv->hp_flags;
++
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
++
++ switch(board_idx) {
++ case chip_5080:
++ hpriv->ops = &mv5xxx_ops;
++ hp_flags |= MV_HP_50XX;
++
++ switch (rev_id) {
++ case 0x1:
++ hp_flags |= MV_HP_ERRATA_50XXB0;
++ break;
++ case 0x3:
++ hp_flags |= MV_HP_ERRATA_50XXB2;
++ break;
++ default:
++ dev_printk(KERN_WARNING, &pdev->dev,
++ "Applying 50XXB2 workarounds to unknown rev\n");
++ hp_flags |= MV_HP_ERRATA_50XXB2;
++ break;
++ }
++ break;
++
++ case chip_504x:
++ case chip_508x:
++ hpriv->ops = &mv5xxx_ops;
++ hp_flags |= MV_HP_50XX;
++
++ switch (rev_id) {
++ case 0x0:
++ hp_flags |= MV_HP_ERRATA_50XXB0;
++ break;
++ case 0x3:
++ hp_flags |= MV_HP_ERRATA_50XXB2;
++ break;
++ default:
++ dev_printk(KERN_WARNING, &pdev->dev,
++ "Applying B2 workarounds to unknown rev\n");
++ hp_flags |= MV_HP_ERRATA_50XXB2;
++ break;
++ }
++ break;
++
++ case chip_604x:
++ case chip_608x:
++ hpriv->ops = &mv6xxx_ops;
++
++ switch (rev_id) {
++ case 0x7:
++ hp_flags |= MV_HP_ERRATA_60X1B2;
++ break;
++ case 0x9:
++ hp_flags |= MV_HP_ERRATA_60X1C0;
++ break;
++ default:
++ dev_printk(KERN_WARNING, &pdev->dev,
++ "Applying B2 workarounds to unknown rev\n");
++ hp_flags |= MV_HP_ERRATA_60X1B2;
++ break;
++ }
++ break;
++
++ case chip_7042:
++ case chip_6042:
++ hpriv->ops = &mv6xxx_ops;
++
++ hp_flags |= MV_HP_GEN_IIE;
++
++ switch (rev_id) {
++ case 0x0:
++ hp_flags |= MV_HP_ERRATA_XX42A0;
++ break;
++ case 0x1:
++ hp_flags |= MV_HP_ERRATA_60X1C0;
++ break;
++ default:
++ dev_printk(KERN_WARNING, &pdev->dev,
++ "Applying 60X1C0 workarounds to unknown rev\n");
++ hp_flags |= MV_HP_ERRATA_60X1C0;
++ break;
++ }
++ break;
++
++ default:
++ printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
++ return 1;
++ }
++
++ hpriv->hp_flags = hp_flags;
++
++ return 0;
++}
++
++/**
++ * mv_init_host - Perform some early initialization of the host.
++ * @pdev: host PCI device
++ * @probe_ent: early data struct representing the host
++ *
++ * If possible, do an early global reset of the host. Then do
++ * our port init and clear/unmask all/relevant host interrupts.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
++ unsigned int board_idx)
++{
++ int rc = 0, n_hc, port, hc;
++ void __iomem *mmio = probe_ent->mmio_base;
++ struct mv_host_priv *hpriv = probe_ent->private_data;
++
++ /* global interrupt mask */
++ writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
++
++ rc = mv_chip_id(pdev, hpriv, board_idx);
++ if (rc)
++ goto done;
++
++ n_hc = mv_get_hc_count(probe_ent->port_flags);
++ probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
++
++ for (port = 0; port < probe_ent->n_ports; port++)
++ hpriv->ops->read_preamp(hpriv, port, mmio);
++
++ rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
++ if (rc)
++ goto done;
++
++ hpriv->ops->reset_flash(hpriv, mmio);
++ hpriv->ops->reset_bus(pdev, mmio);
++ hpriv->ops->enable_leds(hpriv, mmio);
++
++ for (port = 0; port < probe_ent->n_ports; port++) {
++ if (IS_60XX(hpriv)) {
++ void __iomem *port_mmio = mv_port_base(mmio, port);
++
++ u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
++ ifctl |= (1 << 7); /* enable gen2i speed */
++ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
++ writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
++ }
++
++ hpriv->ops->phy_errata(hpriv, mmio, port);
++ }
++
++ for (port = 0; port < probe_ent->n_ports; port++) {
++ void __iomem *port_mmio = mv_port_base(mmio, port);
++ mv_port_init(&probe_ent->port[port], port_mmio);
++ }
++
++ for (hc = 0; hc < n_hc; hc++) {
++ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
++
++ VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
++ "(before clear)=0x%08x\n", hc,
++ readl(hc_mmio + HC_CFG_OFS),
++ readl(hc_mmio + HC_IRQ_CAUSE_OFS));
++
++ /* Clear any currently outstanding hc interrupt conditions */
++ writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
++ }
++
++ /* Clear any currently outstanding host interrupt conditions */
++ writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
++
++ /* and unmask interrupt generation for host regs */
++ writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
++ writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
++
++ VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
++ "PCI int cause/mask=0x%08x/0x%08x\n",
++ readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
++ readl(mmio + HC_MAIN_IRQ_MASK_OFS),
++ readl(mmio + PCI_IRQ_CAUSE_OFS),
++ readl(mmio + PCI_IRQ_MASK_OFS));
++
++done:
++ return rc;
++}
++
++/**
++ * mv_print_info - Dump key info to kernel log for perusal.
++ * @probe_ent: early data struct representing the host
++ *
++ * FIXME: complete this.
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static void mv_print_info(struct ata_probe_ent *probe_ent)
++{
++ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
++ struct mv_host_priv *hpriv = probe_ent->private_data;
++ u8 rev_id, scc;
++ const char *scc_s;
++
++ /* Use this to determine the HW stepping of the chip so we know
++ * what errata to workaround
++ */
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
++
++ pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
++ if (scc == 0)
++ scc_s = "SCSI";
++ else if (scc == 0x01)
++ scc_s = "RAID";
++ else
++ scc_s = "unknown";
++
++ dev_printk(KERN_INFO, &pdev->dev,
++ "%u slots %u ports %s mode IRQ via %s\n",
++ (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
++ scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
++}
++
++/**
++ * mv_init_one - handle a positive probe of a Marvell host
++ * @pdev: PCI device found
++ * @ent: PCI device ID entry for the matched host
++ *
++ * LOCKING:
++ * Inherited from caller.
++ */
++static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version = 0;
++ struct ata_probe_ent *probe_ent = NULL;
++ struct mv_host_priv *hpriv;
++ unsigned int board_idx = (unsigned int)ent->driver_data;
++ void __iomem *mmio_base;
++ int pci_dev_busy = 0, rc;
++
++ if (!printed_version++)
++ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc) {
++ return rc;
++ }
++ pci_set_master(pdev);
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++
++ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
++ if (!hpriv) {
++ rc = -ENOMEM;
++ goto err_out_iounmap;
++ }
++ memset(hpriv, 0, sizeof(*hpriv));
++
++ probe_ent->sht = mv_port_info[board_idx].sht;
++ probe_ent->port_flags = mv_port_info[board_idx].flags;
++ probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
++ probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = mv_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++ probe_ent->private_data = hpriv;
++
++ /* initialize adapter */
++ rc = mv_init_host(pdev, probe_ent, board_idx);
++ if (rc) {
++ goto err_out_hpriv;
++ }
++
++ /* Enable interrupts */
++ if (msi && pci_enable_msi(pdev) == 0) {
++ hpriv->hp_flags |= MV_HP_FLAG_MSI;
++ } else {
++ pci_intx(pdev, 1);
++ }
++
++ mv_dump_pci_cfg(pdev, 0x68);
++ mv_print_info(probe_ent);
++
++ if (ata_device_add(probe_ent) == 0) {
++ rc = -ENODEV; /* No devices discovered */
++ goto err_out_dev_add;
++ }
++
++ kfree(probe_ent);
++ return 0;
++
++err_out_dev_add:
++ if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
++ pci_disable_msi(pdev);
++ } else {
++ pci_intx(pdev, 0);
++ }
++err_out_hpriv:
++ kfree(hpriv);
++err_out_iounmap:
++ pci_iounmap(pdev, mmio_base);
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy) {
++ pci_disable_device(pdev);
++ }
++
++ return rc;
++}
++
++static int __init mv_init(void)
++{
++ return pci_register_driver(&mv_pci_driver);
++}
++
++static void __exit mv_exit(void)
++{
++ pci_unregister_driver(&mv_pci_driver);
++}
++
++MODULE_AUTHOR("Brett Russ");
++MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_param(msi, int, 0444);
++MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
++
++module_init(mv_init);
++module_exit(mv_exit);
+diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
+new file mode 100644
+index 0000000..d65ebfd
+--- /dev/null
++++ b/drivers/ata/sata_nv.c
+@@ -0,0 +1,580 @@
++/*
++ * sata_nv.c - NVIDIA nForce SATA
++ *
++ * Copyright 2004 NVIDIA Corp. All rights reserved.
++ * Copyright 2004 Andrew Chew
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * No hardware documentation available outside of NVIDIA.
++ * This driver programs the NVIDIA SATA controller in a similar
++ * fashion as with other PCI IDE BMDMA controllers, with a few
++ * NV-specific details such as register offsets, SATA phy location,
++ * hotplug info, etc.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sata_nv"
++#define DRV_VERSION "2.0"
++
++enum {
++ NV_PORTS = 2,
++ NV_PIO_MASK = 0x1f,
++ NV_MWDMA_MASK = 0x07,
++ NV_UDMA_MASK = 0x7f,
++ NV_PORT0_SCR_REG_OFFSET = 0x00,
++ NV_PORT1_SCR_REG_OFFSET = 0x40,
++
++ /* INT_STATUS/ENABLE */
++ NV_INT_STATUS = 0x10,
++ NV_INT_ENABLE = 0x11,
++ NV_INT_STATUS_CK804 = 0x440,
++ NV_INT_ENABLE_CK804 = 0x441,
++
++ /* INT_STATUS/ENABLE bits */
++ NV_INT_DEV = 0x01,
++ NV_INT_PM = 0x02,
++ NV_INT_ADDED = 0x04,
++ NV_INT_REMOVED = 0x08,
++
++ NV_INT_PORT_SHIFT = 4, /* each port occupies 4 bits */
++
++ NV_INT_ALL = 0x0f,
++ NV_INT_MASK = NV_INT_DEV |
++ NV_INT_ADDED | NV_INT_REMOVED,
++
++ /* INT_CONFIG */
++ NV_INT_CONFIG = 0x12,
++ NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI
++
++ // For PCI config register 20
++ NV_MCP_SATA_CFG_20 = 0x50,
++ NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04,
++};
++
++static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static void nv_ck804_host_stop(struct ata_host *host);
++static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
++static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
++static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
++static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++
++static void nv_nf2_freeze(struct ata_port *ap);
++static void nv_nf2_thaw(struct ata_port *ap);
++static void nv_ck804_freeze(struct ata_port *ap);
++static void nv_ck804_thaw(struct ata_port *ap);
++static void nv_error_handler(struct ata_port *ap);
++
++enum nv_host_type
++{
++ GENERIC,
++ NFORCE2,
++ NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
++ CK804
++};
++
++static const struct pci_device_id nv_pci_tbl[] = {
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), NFORCE2 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), NFORCE3 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), NFORCE3 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA), CK804 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
++ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
++ { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC }, /* MCP65 */
++ { PCI_VDEVICE(NVIDIA, 0x0550), GENERIC }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0551), GENERIC }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0552), GENERIC }, /* MCP67 */
++ { PCI_VDEVICE(NVIDIA, 0x0553), GENERIC }, /* MCP67 */
++ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
++ PCI_ANY_ID, PCI_ANY_ID,
++ PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
++ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
++ PCI_ANY_ID, PCI_ANY_ID,
++ PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver nv_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = nv_pci_tbl,
++ .probe = nv_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static struct scsi_host_template nv_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations nv_generic_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .exec_command = ata_exec_command,
++ .check_status = ata_check_status,
++ .dev_select = ata_std_dev_select,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = nv_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .data_xfer = ata_pio_data_xfer,
++ .irq_handler = nv_generic_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = nv_scr_read,
++ .scr_write = nv_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static const struct ata_port_operations nv_nf2_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .exec_command = ata_exec_command,
++ .check_status = ata_check_status,
++ .dev_select = ata_std_dev_select,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .freeze = nv_nf2_freeze,
++ .thaw = nv_nf2_thaw,
++ .error_handler = nv_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .data_xfer = ata_pio_data_xfer,
++ .irq_handler = nv_nf2_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = nv_scr_read,
++ .scr_write = nv_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static const struct ata_port_operations nv_ck804_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .exec_command = ata_exec_command,
++ .check_status = ata_check_status,
++ .dev_select = ata_std_dev_select,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .freeze = nv_ck804_freeze,
++ .thaw = nv_ck804_thaw,
++ .error_handler = nv_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .data_xfer = ata_pio_data_xfer,
++ .irq_handler = nv_ck804_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = nv_scr_read,
++ .scr_write = nv_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = nv_ck804_host_stop,
++};
++
++static struct ata_port_info nv_port_info[] = {
++ /* generic */
++ {
++ .sht = &nv_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
++ .pio_mask = NV_PIO_MASK,
++ .mwdma_mask = NV_MWDMA_MASK,
++ .udma_mask = NV_UDMA_MASK,
++ .port_ops = &nv_generic_ops,
++ },
++ /* nforce2/3 */
++ {
++ .sht = &nv_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
++ .pio_mask = NV_PIO_MASK,
++ .mwdma_mask = NV_MWDMA_MASK,
++ .udma_mask = NV_UDMA_MASK,
++ .port_ops = &nv_nf2_ops,
++ },
++ /* ck804 */
++ {
++ .sht = &nv_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
++ .pio_mask = NV_PIO_MASK,
++ .mwdma_mask = NV_MWDMA_MASK,
++ .udma_mask = NV_UDMA_MASK,
++ .port_ops = &nv_ck804_ops,
++ },
++};
++
++MODULE_AUTHOR("NVIDIA");
++MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ unsigned int i;
++ unsigned int handled = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap;
++
++ ap = host->ports[i];
++ if (ap &&
++ !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
++ handled += ata_host_intr(ap, qc);
++ else
++ // No request pending? Clear interrupt status
++ // anyway, in case there's one pending.
++ ap->ops->check_status(ap);
++ }
++
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ return IRQ_RETVAL(handled);
++}
++
++static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
++{
++ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
++ int handled;
++
++ /* freeze if hotplugged */
++ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
++ ata_port_freeze(ap);
++ return 1;
++ }
++
++ /* bail out if not our interrupt */
++ if (!(irq_stat & NV_INT_DEV))
++ return 0;
++
++ /* DEV interrupt w/ no active qc? */
++ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
++ ata_check_status(ap);
++ return 1;
++ }
++
++ /* handle interrupt */
++ handled = ata_host_intr(ap, qc);
++ if (unlikely(!handled)) {
++ /* spurious, clear it */
++ ata_check_status(ap);
++ }
++
++ return 1;
++}
++
++static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
++{
++ int i, handled = 0;
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++
++ if (ap && !(ap->flags & ATA_FLAG_DISABLED))
++ handled += nv_host_intr(ap, irq_stat);
++
++ irq_stat >>= NV_INT_PORT_SHIFT;
++ }
++
++ return IRQ_RETVAL(handled);
++}
++
++static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ u8 irq_stat;
++ irqreturn_t ret;
++
++ spin_lock(&host->lock);
++ irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
++ ret = nv_do_interrupt(host, irq_stat);
++ spin_unlock(&host->lock);
++
++ return ret;
++}
++
++static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ u8 irq_stat;
++ irqreturn_t ret;
++
++ spin_lock(&host->lock);
++ irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804);
++ ret = nv_do_interrupt(host, irq_stat);
++ spin_unlock(&host->lock);
++
++ return ret;
++}
++
++static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++
++ return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++ if (sc_reg > SCR_CONTROL)
++ return;
++
++ iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++static void nv_nf2_freeze(struct ata_port *ap)
++{
++ unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
++ int shift = ap->port_no * NV_INT_PORT_SHIFT;
++ u8 mask;
++
++ mask = inb(scr_addr + NV_INT_ENABLE);
++ mask &= ~(NV_INT_ALL << shift);
++ outb(mask, scr_addr + NV_INT_ENABLE);
++}
++
++static void nv_nf2_thaw(struct ata_port *ap)
++{
++ unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
++ int shift = ap->port_no * NV_INT_PORT_SHIFT;
++ u8 mask;
++
++ outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
++
++ mask = inb(scr_addr + NV_INT_ENABLE);
++ mask |= (NV_INT_MASK << shift);
++ outb(mask, scr_addr + NV_INT_ENABLE);
++}
++
++static void nv_ck804_freeze(struct ata_port *ap)
++{
++ void __iomem *mmio_base = ap->host->mmio_base;
++ int shift = ap->port_no * NV_INT_PORT_SHIFT;
++ u8 mask;
++
++ mask = readb(mmio_base + NV_INT_ENABLE_CK804);
++ mask &= ~(NV_INT_ALL << shift);
++ writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
++}
++
++static void nv_ck804_thaw(struct ata_port *ap)
++{
++ void __iomem *mmio_base = ap->host->mmio_base;
++ int shift = ap->port_no * NV_INT_PORT_SHIFT;
++ u8 mask;
++
++ writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804);
++
++ mask = readb(mmio_base + NV_INT_ENABLE_CK804);
++ mask |= (NV_INT_MASK << shift);
++ writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
++}
++
++static int nv_hardreset(struct ata_port *ap, unsigned int *class)
++{
++ unsigned int dummy;
++
++ /* SATA hardreset fails to retrieve proper device signature on
++ * some controllers. Don't classify on hardreset. For more
++ * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
++ */
++ return sata_std_hardreset(ap, &dummy);
++}
++
++static void nv_error_handler(struct ata_port *ap)
++{
++ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
++ nv_hardreset, ata_std_postreset);
++}
++
++static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version = 0;
++ struct ata_port_info *ppi[2];
++ struct ata_probe_ent *probe_ent;
++ int pci_dev_busy = 0;
++ int rc;
++ u32 bar;
++ unsigned long base;
++
++ // Make sure this is a SATA controller by counting the number of bars
++ // (NVIDIA SATA controllers will always have six bars). Otherwise,
++ // it's an IDE controller and we ignore it.
++ for (bar=0; bar<6; bar++)
++ if (pci_resource_start(pdev, bar) == 0)
++ return -ENODEV;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ goto err_out;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out_disable;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ rc = -ENOMEM;
++
++ ppi[0] = ppi[1] = &nv_port_info[ent->driver_data];
++ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
++ if (!probe_ent)
++ goto err_out_regions;
++
++ probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
++ if (!probe_ent->mmio_base) {
++ rc = -EIO;
++ goto err_out_free_ent;
++ }
++
++ base = (unsigned long)probe_ent->mmio_base;
++
++ probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
++ probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
++
++ /* enable SATA space for CK804 */
++ if (ent->driver_data == CK804) {
++ u8 regval;
++
++ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val);
++ regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
++ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
++ }
++
++ pci_set_master(pdev);
++
++ rc = ata_device_add(probe_ent);
++ if (rc != NV_PORTS)
++ goto err_out_iounmap;
++
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_iounmap:
++ pci_iounmap(pdev, probe_ent->mmio_base);
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out_disable:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++err_out:
++ return rc;
++}
++
++static void nv_ck804_host_stop(struct ata_host *host)
++{
++ struct pci_dev *pdev = to_pci_dev(host->dev);
++ u8 regval;
++
++ /* disable SATA space for CK804 */
++ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val);
++ regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
++ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
++
++ ata_pci_host_stop(host);
++}
++
++static int __init nv_init(void)
++{
++ return pci_register_driver(&nv_pci_driver);
++}
++
++static void __exit nv_exit(void)
++{
++ pci_unregister_driver(&nv_pci_driver);
++}
++
++module_init(nv_init);
++module_exit(nv_exit);
+diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
+new file mode 100644
+index 0000000..72eda51
+--- /dev/null
++++ b/drivers/ata/sata_promise.c
+@@ -0,0 +1,828 @@
++/*
++ * sata_promise.c - Promise SATA
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003-2004 Red Hat, Inc.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware information only available under NDA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++#include "sata_promise.h"
++
++#define DRV_NAME "sata_promise"
++#define DRV_VERSION "1.04"
++
++
++enum {
++ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
++ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
++ PDC_TBG_MODE = 0x41, /* TBG mode */
++ PDC_FLASH_CTL = 0x44, /* Flash control register */
++ PDC_PCI_CTL = 0x48, /* PCI control and status register */
++ PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
++ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
++ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
++ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
++ PDC_SLEW_CTL = 0x470, /* slew rate control reg */
++
++ PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
++ (1<<8) | (1<<9) | (1<<10),
++
++ board_2037x = 0, /* FastTrak S150 TX2plus */
++ board_20319 = 1, /* FastTrak S150 TX4 */
++ board_20619 = 2, /* FastTrak TX4000 */
++ board_20771 = 3, /* FastTrak TX2300 */
++ board_2057x = 4, /* SATAII150 Tx2plus */
++ board_40518 = 5, /* SATAII150 Tx4 */
++
++ PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
++
++ PDC_RESET = (1 << 11), /* HDMA reset */
++
++ PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
++ ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
++ ATA_FLAG_PIO_POLLING,
++};
++
++
++struct pdc_port_priv {
++ u8 *pkt;
++ dma_addr_t pkt_dma;
++};
++
++struct pdc_host_priv {
++ int hotplug_offset;
++};
++
++static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
++static void pdc_eng_timeout(struct ata_port *ap);
++static int pdc_port_start(struct ata_port *ap);
++static void pdc_port_stop(struct ata_port *ap);
++static void pdc_pata_phy_reset(struct ata_port *ap);
++static void pdc_sata_phy_reset(struct ata_port *ap);
++static void pdc_qc_prep(struct ata_queued_cmd *qc);
++static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
++static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
++static void pdc_irq_clear(struct ata_port *ap);
++static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
++static void pdc_host_stop(struct ata_host *host);
++
++
++static struct scsi_host_template pdc_ata_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations pdc_sata_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = pdc_tf_load_mmio,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = pdc_exec_command_mmio,
++ .dev_select = ata_std_dev_select,
++
++ .phy_reset = pdc_sata_phy_reset,
++
++ .qc_prep = pdc_qc_prep,
++ .qc_issue = pdc_qc_issue_prot,
++ .eng_timeout = pdc_eng_timeout,
++ .data_xfer = ata_mmio_data_xfer,
++ .irq_handler = pdc_interrupt,
++ .irq_clear = pdc_irq_clear,
++
++ .scr_read = pdc_sata_scr_read,
++ .scr_write = pdc_sata_scr_write,
++ .port_start = pdc_port_start,
++ .port_stop = pdc_port_stop,
++ .host_stop = pdc_host_stop,
++};
++
++static const struct ata_port_operations pdc_pata_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = pdc_tf_load_mmio,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = pdc_exec_command_mmio,
++ .dev_select = ata_std_dev_select,
++
++ .phy_reset = pdc_pata_phy_reset,
++
++ .qc_prep = pdc_qc_prep,
++ .qc_issue = pdc_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++ .eng_timeout = pdc_eng_timeout,
++ .irq_handler = pdc_interrupt,
++ .irq_clear = pdc_irq_clear,
++
++ .port_start = pdc_port_start,
++ .port_stop = pdc_port_stop,
++ .host_stop = pdc_host_stop,
++};
++
++static const struct ata_port_info pdc_port_info[] = {
++ /* board_2037x */
++ {
++ .sht = &pdc_ata_sht,
++ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_sata_ops,
++ },
++
++ /* board_20319 */
++ {
++ .sht = &pdc_ata_sht,
++ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_sata_ops,
++ },
++
++ /* board_20619 */
++ {
++ .sht = &pdc_ata_sht,
++ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_pata_ops,
++ },
++
++ /* board_20771 */
++ {
++ .sht = &pdc_ata_sht,
++ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_sata_ops,
++ },
++
++ /* board_2057x */
++ {
++ .sht = &pdc_ata_sht,
++ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_sata_ops,
++ },
++
++ /* board_40518 */
++ {
++ .sht = &pdc_ata_sht,
++ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_sata_ops,
++ },
++};
++
++static const struct pci_device_id pdc_ata_pci_tbl[] = {
++ { PCI_VDEVICE(PROMISE, 0x3371), board_2037x },
++ { PCI_VDEVICE(PROMISE, 0x3570), board_2037x },
++ { PCI_VDEVICE(PROMISE, 0x3571), board_2037x },
++ { PCI_VDEVICE(PROMISE, 0x3373), board_2037x },
++ { PCI_VDEVICE(PROMISE, 0x3375), board_2037x },
++ { PCI_VDEVICE(PROMISE, 0x3376), board_2037x },
++ { PCI_VDEVICE(PROMISE, 0x3574), board_2057x },
++ { PCI_VDEVICE(PROMISE, 0x3d75), board_2057x },
++ { PCI_VDEVICE(PROMISE, 0x3d73), board_2037x },
++
++ { PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
++ { PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
++ { PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
++ { PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
++ { PCI_VDEVICE(PROMISE, 0x3d17), board_20319 },
++ { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
++
++ { PCI_VDEVICE(PROMISE, 0x6629), board_20619 },
++
++/* TODO: remove all associated board_20771 code, as it completely
++ * duplicates board_2037x code, unless reason for separation can be
++ * divined.
++ */
++#if 0
++ { PCI_VDEVICE(PROMISE, 0x3570), board_20771 },
++#endif
++ { PCI_VDEVICE(PROMISE, 0x3577), board_20771 },
++
++ { } /* terminate list */
++};
++
++
++static struct pci_driver pdc_ata_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = pdc_ata_pci_tbl,
++ .probe = pdc_ata_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++
++static int pdc_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct pdc_port_priv *pp;
++ int rc;
++
++ rc = ata_port_start(ap);
++ if (rc)
++ return rc;
++
++ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
++ if (!pp) {
++ rc = -ENOMEM;
++ goto err_out;
++ }
++
++ pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
++ if (!pp->pkt) {
++ rc = -ENOMEM;
++ goto err_out_kfree;
++ }
++
++ ap->private_data = pp;
++
++ return 0;
++
++err_out_kfree:
++ kfree(pp);
++err_out:
++ ata_port_stop(ap);
++ return rc;
++}
++
++
++static void pdc_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct pdc_port_priv *pp = ap->private_data;
++
++ ap->private_data = NULL;
++ dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
++ kfree(pp);
++ ata_port_stop(ap);
++}
++
++
++static void pdc_host_stop(struct ata_host *host)
++{
++ struct pdc_host_priv *hp = host->private_data;
++
++ ata_pci_host_stop(host);
++
++ kfree(hp);
++}
++
++
++static void pdc_reset_port(struct ata_port *ap)
++{
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
++ unsigned int i;
++ u32 tmp;
++
++ for (i = 11; i > 0; i--) {
++ tmp = readl(mmio);
++ if (tmp & PDC_RESET)
++ break;
++
++ udelay(100);
++
++ tmp |= PDC_RESET;
++ writel(tmp, mmio);
++ }
++
++ tmp &= ~PDC_RESET;
++ writel(tmp, mmio);
++ readl(mmio); /* flush */
++}
++
++static void pdc_sata_phy_reset(struct ata_port *ap)
++{
++ pdc_reset_port(ap);
++ sata_phy_reset(ap);
++}
++
++static void pdc_pata_cbl_detect(struct ata_port *ap)
++{
++ u8 tmp;
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
++
++ tmp = readb(mmio);
++
++ if (tmp & 0x01) {
++ ap->cbl = ATA_CBL_PATA40;
++ ap->udma_mask &= ATA_UDMA_MASK_40C;
++ } else
++ ap->cbl = ATA_CBL_PATA80;
++}
++
++static void pdc_pata_phy_reset(struct ata_port *ap)
++{
++ pdc_pata_cbl_detect(ap);
++ pdc_reset_port(ap);
++ ata_port_probe(ap);
++ ata_bus_reset(ap);
++}
++
++static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++
++static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
++ u32 val)
++{
++ if (sc_reg > SCR_CONTROL)
++ return;
++ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++static void pdc_qc_prep(struct ata_queued_cmd *qc)
++{
++ struct pdc_port_priv *pp = qc->ap->private_data;
++ unsigned int i;
++
++ VPRINTK("ENTER\n");
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ ata_qc_prep(qc);
++ /* fall through */
++
++ case ATA_PROT_NODATA:
++ i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
++ qc->dev->devno, pp->pkt);
++
++ if (qc->tf.flags & ATA_TFLAG_LBA48)
++ i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
++ else
++ i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
++
++ pdc_pkt_footer(&qc->tf, pp->pkt, i);
++ break;
++
++ default:
++ break;
++ }
++}
++
++static void pdc_eng_timeout(struct ata_port *ap)
++{
++ struct ata_host *host = ap->host;
++ u8 drv_stat;
++ struct ata_queued_cmd *qc;
++ unsigned long flags;
++
++ DPRINTK("ENTER\n");
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ case ATA_PROT_NODATA:
++ ata_port_printk(ap, KERN_ERR, "command timeout\n");
++ drv_stat = ata_wait_idle(ap);
++ qc->err_mask |= __ac_err_mask(drv_stat);
++ break;
++
++ default:
++ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
++
++ ata_port_printk(ap, KERN_ERR,
++ "unknown timeout, cmd 0x%x stat 0x%x\n",
++ qc->tf.command, drv_stat);
++
++ qc->err_mask |= ac_err_mask(drv_stat);
++ break;
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ ata_eh_qc_complete(qc);
++ DPRINTK("EXIT\n");
++}
++
++static inline unsigned int pdc_host_intr( struct ata_port *ap,
++ struct ata_queued_cmd *qc)
++{
++ unsigned int handled = 0;
++ u32 tmp;
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
++
++ tmp = readl(mmio);
++ if (tmp & PDC_ERR_MASK) {
++ qc->err_mask |= AC_ERR_DEV;
++ pdc_reset_port(ap);
++ }
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ case ATA_PROT_NODATA:
++ qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
++ ata_qc_complete(qc);
++ handled = 1;
++ break;
++
++ default:
++ ap->stats.idle_irq++;
++ break;
++ }
++
++ return handled;
++}
++
++static void pdc_irq_clear(struct ata_port *ap)
++{
++ struct ata_host *host = ap->host;
++ void __iomem *mmio = host->mmio_base;
++
++ readl(mmio + PDC_INT_SEQMASK);
++}
++
++static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ struct ata_port *ap;
++ u32 mask = 0;
++ unsigned int i, tmp;
++ unsigned int handled = 0;
++ void __iomem *mmio_base;
++
++ VPRINTK("ENTER\n");
++
++ if (!host || !host->mmio_base) {
++ VPRINTK("QUICK EXIT\n");
++ return IRQ_NONE;
++ }
++
++ mmio_base = host->mmio_base;
++
++ /* reading should also clear interrupts */
++ mask = readl(mmio_base + PDC_INT_SEQMASK);
++
++ if (mask == 0xffffffff) {
++ VPRINTK("QUICK EXIT 2\n");
++ return IRQ_NONE;
++ }
++
++ spin_lock(&host->lock);
++
++ mask &= 0xffff; /* only 16 tags possible */
++ if (!mask) {
++ VPRINTK("QUICK EXIT 3\n");
++ goto done_irq;
++ }
++
++ writel(mask, mmio_base + PDC_INT_SEQMASK);
++
++ for (i = 0; i < host->n_ports; i++) {
++ VPRINTK("port %u\n", i);
++ ap = host->ports[i];
++ tmp = mask & (1 << (i + 1));
++ if (tmp && ap &&
++ !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
++ handled += pdc_host_intr(ap, qc);
++ }
++ }
++
++ VPRINTK("EXIT\n");
++
++done_irq:
++ spin_unlock(&host->lock);
++ return IRQ_RETVAL(handled);
++}
++
++static inline void pdc_packet_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pdc_port_priv *pp = ap->private_data;
++ unsigned int port_no = ap->port_no;
++ u8 seq = (u8) (port_no + 1);
++
++ VPRINTK("ENTER, ap %p\n", ap);
++
++ writel(0x00000001, ap->host->mmio_base + (seq * 4));
++ readl(ap->host->mmio_base + (seq * 4)); /* flush */
++
++ pp->pkt[2] = seq;
++ wmb(); /* flush PRD, pkt writes */
++ writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
++ readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
++}
++
++static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ case ATA_PROT_NODATA:
++ pdc_packet_start(qc);
++ return 0;
++
++ case ATA_PROT_ATAPI_DMA:
++ BUG();
++ break;
++
++ default:
++ break;
++ }
++
++ return ata_qc_issue_prot(qc);
++}
++
++static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ WARN_ON (tf->protocol == ATA_PROT_DMA ||
++ tf->protocol == ATA_PROT_NODATA);
++ ata_tf_load(ap, tf);
++}
++
++
++static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ WARN_ON (tf->protocol == ATA_PROT_DMA ||
++ tf->protocol == ATA_PROT_NODATA);
++ ata_exec_command(ap, tf);
++}
++
++
++static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr = base;
++ port->data_addr = base;
++ port->feature_addr =
++ port->error_addr = base + 0x4;
++ port->nsect_addr = base + 0x8;
++ port->lbal_addr = base + 0xc;
++ port->lbam_addr = base + 0x10;
++ port->lbah_addr = base + 0x14;
++ port->device_addr = base + 0x18;
++ port->command_addr =
++ port->status_addr = base + 0x1c;
++ port->altstatus_addr =
++ port->ctl_addr = base + 0x38;
++}
++
++
++static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
++{
++ void __iomem *mmio = pe->mmio_base;
++ struct pdc_host_priv *hp = pe->private_data;
++ int hotplug_offset = hp->hotplug_offset;
++ u32 tmp;
++
++ /*
++ * Except for the hotplug stuff, this is voodoo from the
++ * Promise driver. Label this entire section
++ * "TODO: figure out why we do this"
++ */
++
++ /* change FIFO_SHD to 8 dwords, enable BMR_BURST */
++ tmp = readl(mmio + PDC_FLASH_CTL);
++ tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
++ writel(tmp, mmio + PDC_FLASH_CTL);
++
++ /* clear plug/unplug flags for all ports */
++ tmp = readl(mmio + hotplug_offset);
++ writel(tmp | 0xff, mmio + hotplug_offset);
++
++ /* mask plug/unplug ints */
++ tmp = readl(mmio + hotplug_offset);
++ writel(tmp | 0xff0000, mmio + hotplug_offset);
++
++ /* reduce TBG clock to 133 Mhz. */
++ tmp = readl(mmio + PDC_TBG_MODE);
++ tmp &= ~0x30000; /* clear bit 17, 16*/
++ tmp |= 0x10000; /* set bit 17:16 = 0:1 */
++ writel(tmp, mmio + PDC_TBG_MODE);
++
++ readl(mmio + PDC_TBG_MODE); /* flush */
++ msleep(10);
++
++ /* adjust slew rate control register. */
++ tmp = readl(mmio + PDC_SLEW_CTL);
++ tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
++ tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
++ writel(tmp, mmio + PDC_SLEW_CTL);
++}
++
++static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ struct pdc_host_priv *hp;
++ unsigned long base;
++ void __iomem *mmio_base;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++ int pci_dev_busy = 0;
++ int rc;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, 3, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++ base = (unsigned long) mmio_base;
++
++ hp = kzalloc(sizeof(*hp), GFP_KERNEL);
++ if (hp == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++
++ /* Set default hotplug offset */
++ hp->hotplug_offset = PDC_SATA_PLUG_CSR;
++ probe_ent->private_data = hp;
++
++ probe_ent->sht = pdc_port_info[board_idx].sht;
++ probe_ent->port_flags = pdc_port_info[board_idx].flags;
++ probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
++ probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
++ probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++
++ pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
++ pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
++
++ probe_ent->port[0].scr_addr = base + 0x400;
++ probe_ent->port[1].scr_addr = base + 0x500;
++
++ /* notice 4-port boards */
++ switch (board_idx) {
++ case board_40518:
++ /* Override hotplug offset for SATAII150 */
++ hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
++ /* Fall through */
++ case board_20319:
++ probe_ent->n_ports = 4;
++
++ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
++ pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
++
++ probe_ent->port[2].scr_addr = base + 0x600;
++ probe_ent->port[3].scr_addr = base + 0x700;
++ break;
++ case board_2057x:
++ /* Override hotplug offset for SATAII150 */
++ hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
++ /* Fall through */
++ case board_2037x:
++ probe_ent->n_ports = 2;
++ break;
++ case board_20771:
++ probe_ent->n_ports = 2;
++ break;
++ case board_20619:
++ probe_ent->n_ports = 4;
++
++ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
++ pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
++
++ probe_ent->port[2].scr_addr = base + 0x600;
++ probe_ent->port[3].scr_addr = base + 0x700;
++ break;
++ default:
++ BUG();
++ break;
++ }
++
++ pci_set_master(pdev);
++
++ /* initialize adapter */
++ pdc_host_init(board_idx, probe_ent);
++
++ /* FIXME: Need any other frees than hp? */
++ if (!ata_device_add(probe_ent))
++ kfree(hp);
++
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++
++static int __init pdc_ata_init(void)
++{
++ return pci_register_driver(&pdc_ata_pci_driver);
++}
++
++
++static void __exit pdc_ata_exit(void)
++{
++ pci_unregister_driver(&pdc_ata_pci_driver);
++}
++
++
++MODULE_AUTHOR("Jeff Garzik");
++MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(pdc_ata_init);
++module_exit(pdc_ata_exit);
+diff --git a/drivers/ata/sata_promise.h b/drivers/ata/sata_promise.h
+new file mode 100644
+index 0000000..6ee5e19
+--- /dev/null
++++ b/drivers/ata/sata_promise.h
+@@ -0,0 +1,157 @@
++/*
++ * sata_promise.h - Promise SATA common definitions and inline funcs
++ *
++ * Copyright 2003-2004 Red Hat, Inc.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ */
++
++#ifndef __SATA_PROMISE_H__
++#define __SATA_PROMISE_H__
++
++#include <linux/ata.h>
++
++enum pdc_packet_bits {
++ PDC_PKT_READ = (1 << 2),
++ PDC_PKT_NODATA = (1 << 3),
++
++ PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
++ PDC_PKT_CLEAR_BSY = (1 << 4),
++ PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
++ PDC_LAST_REG = (1 << 3),
++
++ PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
++};
++
++static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
++ dma_addr_t sg_table,
++ unsigned int devno, u8 *buf)
++{
++ u8 dev_reg;
++ u32 *buf32 = (u32 *) buf;
++
++ /* set control bits (byte 0), zero delay seq id (byte 3),
++ * and seq id (byte 2)
++ */
++ switch (tf->protocol) {
++ case ATA_PROT_DMA:
++ if (!(tf->flags & ATA_TFLAG_WRITE))
++ buf32[0] = cpu_to_le32(PDC_PKT_READ);
++ else
++ buf32[0] = 0;
++ break;
++
++ case ATA_PROT_NODATA:
++ buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
++ break;
++
++ default:
++ BUG();
++ break;
++ }
++
++ buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
++ buf32[2] = 0; /* no next-packet */
++
++ if (devno == 0)
++ dev_reg = ATA_DEVICE_OBS;
++ else
++ dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
++
++ /* select device */
++ buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
++ buf[13] = dev_reg;
++
++ /* device control register */
++ buf[14] = (1 << 5) | PDC_REG_DEVCTL;
++ buf[15] = tf->ctl;
++
++ return 16; /* offset of next byte */
++}
++
++static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
++ unsigned int i)
++{
++ if (tf->flags & ATA_TFLAG_DEVICE) {
++ buf[i++] = (1 << 5) | ATA_REG_DEVICE;
++ buf[i++] = tf->device;
++ }
++
++ /* and finally the command itself; also includes end-of-pkt marker */
++ buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
++ buf[i++] = tf->command;
++
++ return i;
++}
++
++static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
++{
++ /* the "(1 << 5)" should be read "(count << 5)" */
++
++ /* ATA command block registers */
++ buf[i++] = (1 << 5) | ATA_REG_FEATURE;
++ buf[i++] = tf->feature;
++
++ buf[i++] = (1 << 5) | ATA_REG_NSECT;
++ buf[i++] = tf->nsect;
++
++ buf[i++] = (1 << 5) | ATA_REG_LBAL;
++ buf[i++] = tf->lbal;
++
++ buf[i++] = (1 << 5) | ATA_REG_LBAM;
++ buf[i++] = tf->lbam;
++
++ buf[i++] = (1 << 5) | ATA_REG_LBAH;
++ buf[i++] = tf->lbah;
++
++ return i;
++}
++
++static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
++{
++ /* the "(2 << 5)" should be read "(count << 5)" */
++
++ /* ATA command block registers */
++ buf[i++] = (2 << 5) | ATA_REG_FEATURE;
++ buf[i++] = tf->hob_feature;
++ buf[i++] = tf->feature;
++
++ buf[i++] = (2 << 5) | ATA_REG_NSECT;
++ buf[i++] = tf->hob_nsect;
++ buf[i++] = tf->nsect;
++
++ buf[i++] = (2 << 5) | ATA_REG_LBAL;
++ buf[i++] = tf->hob_lbal;
++ buf[i++] = tf->lbal;
++
++ buf[i++] = (2 << 5) | ATA_REG_LBAM;
++ buf[i++] = tf->hob_lbam;
++ buf[i++] = tf->lbam;
++
++ buf[i++] = (2 << 5) | ATA_REG_LBAH;
++ buf[i++] = tf->hob_lbah;
++ buf[i++] = tf->lbah;
++
++ return i;
++}
++
++
++#endif /* __SATA_PROMISE_H__ */
+diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
+new file mode 100644
+index 0000000..710909d
+--- /dev/null
++++ b/drivers/ata/sata_qstor.c
+@@ -0,0 +1,729 @@
++/*
++ * sata_qstor.c - Pacific Digital Corporation QStor SATA
++ *
++ * Maintained by: Mark Lord <mlord at pobox.com>
++ *
++ * Copyright 2005 Pacific Digital Corporation.
++ * (OSL/GPL code release authorized by Jalil Fadavi).
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <asm/io.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sata_qstor"
++#define DRV_VERSION "0.06"
++
++enum {
++ QS_PORTS = 4,
++ QS_MAX_PRD = LIBATA_MAX_PRD,
++ QS_CPB_ORDER = 6,
++ QS_CPB_BYTES = (1 << QS_CPB_ORDER),
++ QS_PRD_BYTES = QS_MAX_PRD * 16,
++ QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES,
++
++ /* global register offsets */
++ QS_HCF_CNFG3 = 0x0003, /* host configuration offset */
++ QS_HID_HPHY = 0x0004, /* host physical interface info */
++ QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */
++ QS_HST_SFF = 0x0100, /* host status fifo offset */
++ QS_HVS_SERD3 = 0x0393, /* PHY enable offset */
++
++ /* global control bits */
++ QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */
++ QS_CNFG3_GSRST = 0x01, /* global chip reset */
++ QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/
++
++ /* per-channel register offsets */
++ QS_CCF_CPBA = 0x0710, /* chan CPB base address */
++ QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */
++ QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */
++ QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */
++ QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */
++ QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */
++ QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */
++ QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */
++ QS_CCT_CFF = 0x0a00, /* chan command fifo offset */
++
++ /* channel control bits */
++ QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */
++ QS_CTR0_CLER = (1 << 2), /* clear channel errors */
++ QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */
++ QS_CTR1_RCHN = (1 << 4), /* reset channel logic */
++ QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */
++
++ /* pkt sub-field headers */
++ QS_HCB_HDR = 0x01, /* Host Control Block header */
++ QS_DCB_HDR = 0x02, /* Device Control Block header */
++
++ /* pkt HCB flag bits */
++ QS_HF_DIRO = (1 << 0), /* data DIRection Out */
++ QS_HF_DAT = (1 << 3), /* DATa pkt */
++ QS_HF_IEN = (1 << 4), /* Interrupt ENable */
++ QS_HF_VLD = (1 << 5), /* VaLiD pkt */
++
++ /* pkt DCB flag bits */
++ QS_DF_PORD = (1 << 2), /* Pio OR Dma */
++ QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */
++
++ /* PCI device IDs */
++ board_2068_idx = 0, /* QStor 4-port SATA/RAID */
++};
++
++enum {
++ QS_DMA_BOUNDARY = ~0UL
++};
++
++typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
++
++struct qs_port_priv {
++ u8 *pkt;
++ dma_addr_t pkt_dma;
++ qs_state_t state;
++};
++
++static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static irqreturn_t qs_intr (int irq, void *dev_instance);
++static int qs_port_start(struct ata_port *ap);
++static void qs_host_stop(struct ata_host *host);
++static void qs_port_stop(struct ata_port *ap);
++static void qs_phy_reset(struct ata_port *ap);
++static void qs_qc_prep(struct ata_queued_cmd *qc);
++static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
++static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
++static void qs_bmdma_stop(struct ata_queued_cmd *qc);
++static u8 qs_bmdma_status(struct ata_port *ap);
++static void qs_irq_clear(struct ata_port *ap);
++static void qs_eng_timeout(struct ata_port *ap);
++
++static struct scsi_host_template qs_ata_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = QS_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .use_clustering = ENABLE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = QS_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations qs_ata_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .check_atapi_dma = qs_check_atapi_dma,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .phy_reset = qs_phy_reset,
++ .qc_prep = qs_qc_prep,
++ .qc_issue = qs_qc_issue,
++ .data_xfer = ata_mmio_data_xfer,
++ .eng_timeout = qs_eng_timeout,
++ .irq_handler = qs_intr,
++ .irq_clear = qs_irq_clear,
++ .scr_read = qs_scr_read,
++ .scr_write = qs_scr_write,
++ .port_start = qs_port_start,
++ .port_stop = qs_port_stop,
++ .host_stop = qs_host_stop,
++ .bmdma_stop = qs_bmdma_stop,
++ .bmdma_status = qs_bmdma_status,
++};
++
++static const struct ata_port_info qs_port_info[] = {
++ /* board_2068_idx */
++ {
++ .sht = &qs_ata_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_SATA_RESET |
++ //FIXME ATA_FLAG_SRST |
++ ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
++ .pio_mask = 0x10, /* pio4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &qs_ata_ops,
++ },
++};
++
++static const struct pci_device_id qs_ata_pci_tbl[] = {
++ { PCI_VDEVICE(PDC, 0x2068), board_2068_idx },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver qs_ata_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = qs_ata_pci_tbl,
++ .probe = qs_ata_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++ return 1; /* ATAPI DMA not supported */
++}
++
++static void qs_bmdma_stop(struct ata_queued_cmd *qc)
++{
++ /* nothing */
++}
++
++static u8 qs_bmdma_status(struct ata_port *ap)
++{
++ return 0;
++}
++
++static void qs_irq_clear(struct ata_port *ap)
++{
++ /* nothing */
++}
++
++static inline void qs_enter_reg_mode(struct ata_port *ap)
++{
++ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
++
++ writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
++ readb(chan + QS_CCT_CTR0); /* flush */
++}
++
++static inline void qs_reset_channel_logic(struct ata_port *ap)
++{
++ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
++
++ writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
++ readb(chan + QS_CCT_CTR0); /* flush */
++ qs_enter_reg_mode(ap);
++}
++
++static void qs_phy_reset(struct ata_port *ap)
++{
++ struct qs_port_priv *pp = ap->private_data;
++
++ pp->state = qs_state_idle;
++ qs_reset_channel_logic(ap);
++ sata_phy_reset(ap);
++}
++
++static void qs_eng_timeout(struct ata_port *ap)
++{
++ struct qs_port_priv *pp = ap->private_data;
++
++ if (pp->state != qs_state_idle) /* healthy paranoia */
++ pp->state = qs_state_mmio;
++ qs_reset_channel_logic(ap);
++ ata_eng_timeout(ap);
++}
++
++static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return ~0U;
++ return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
++}
++
++static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++ if (sc_reg > SCR_CONTROL)
++ return;
++ writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
++}
++
++static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
++{
++ struct scatterlist *sg;
++ struct ata_port *ap = qc->ap;
++ struct qs_port_priv *pp = ap->private_data;
++ unsigned int nelem;
++ u8 *prd = pp->pkt + QS_CPB_BYTES;
++
++ WARN_ON(qc->__sg == NULL);
++ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
++
++ nelem = 0;
++ ata_for_each_sg(sg, qc) {
++ u64 addr;
++ u32 len;
++
++ addr = sg_dma_address(sg);
++ *(__le64 *)prd = cpu_to_le64(addr);
++ prd += sizeof(u64);
++
++ len = sg_dma_len(sg);
++ *(__le32 *)prd = cpu_to_le32(len);
++ prd += sizeof(u64);
++
++ VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
++ (unsigned long long)addr, len);
++ nelem++;
++ }
++
++ return nelem;
++}
++
++static void qs_qc_prep(struct ata_queued_cmd *qc)
++{
++ struct qs_port_priv *pp = qc->ap->private_data;
++ u8 dflags = QS_DF_PORD, *buf = pp->pkt;
++ u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
++ u64 addr;
++ unsigned int nelem;
++
++ VPRINTK("ENTER\n");
++
++ qs_enter_reg_mode(qc->ap);
++ if (qc->tf.protocol != ATA_PROT_DMA) {
++ ata_qc_prep(qc);
++ return;
++ }
++
++ nelem = qs_fill_sg(qc);
++
++ if ((qc->tf.flags & ATA_TFLAG_WRITE))
++ hflags |= QS_HF_DIRO;
++ if ((qc->tf.flags & ATA_TFLAG_LBA48))
++ dflags |= QS_DF_ELBA;
++
++ /* host control block (HCB) */
++ buf[ 0] = QS_HCB_HDR;
++ buf[ 1] = hflags;
++ *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
++ *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem);
++ addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
++ *(__le64 *)(&buf[16]) = cpu_to_le64(addr);
++
++ /* device control block (DCB) */
++ buf[24] = QS_DCB_HDR;
++ buf[28] = dflags;
++
++ /* frame information structure (FIS) */
++ ata_tf_to_fis(&qc->tf, &buf[32], 0);
++}
++
++static inline void qs_packet_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
++
++ VPRINTK("ENTER, ap %p\n", ap);
++
++ writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
++ wmb(); /* flush PRDs and pkt to memory */
++ writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
++ readl(chan + QS_CCT_CFF); /* flush */
++}
++
++static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
++{
++ struct qs_port_priv *pp = qc->ap->private_data;
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++
++ pp->state = qs_state_pkt;
++ qs_packet_start(qc);
++ return 0;
++
++ case ATA_PROT_ATAPI_DMA:
++ BUG();
++ break;
++
++ default:
++ break;
++ }
++
++ pp->state = qs_state_mmio;
++ return ata_qc_issue_prot(qc);
++}
++
++static inline unsigned int qs_intr_pkt(struct ata_host *host)
++{
++ unsigned int handled = 0;
++ u8 sFFE;
++ u8 __iomem *mmio_base = host->mmio_base;
++
++ do {
++ u32 sff0 = readl(mmio_base + QS_HST_SFF);
++ u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
++ u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */
++ sFFE = sff1 >> 31; /* empty flag */
++
++ if (sEVLD) {
++ u8 sDST = sff0 >> 16; /* dev status */
++ u8 sHST = sff1 & 0x3f; /* host status */
++ unsigned int port_no = (sff1 >> 8) & 0x03;
++ struct ata_port *ap = host->ports[port_no];
++
++ DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
++ sff1, sff0, port_no, sHST, sDST);
++ handled = 1;
++ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++ struct qs_port_priv *pp = ap->private_data;
++ if (!pp || pp->state != qs_state_pkt)
++ continue;
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
++ switch (sHST) {
++ case 0: /* successful CPB */
++ case 3: /* device error */
++ pp->state = qs_state_idle;
++ qs_enter_reg_mode(qc->ap);
++ qc->err_mask |= ac_err_mask(sDST);
++ ata_qc_complete(qc);
++ break;
++ default:
++ break;
++ }
++ }
++ }
++ }
++ } while (!sFFE);
++ return handled;
++}
++
++static inline unsigned int qs_intr_mmio(struct ata_host *host)
++{
++ unsigned int handled = 0, port_no;
++
++ for (port_no = 0; port_no < host->n_ports; ++port_no) {
++ struct ata_port *ap;
++ ap = host->ports[port_no];
++ if (ap &&
++ !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++ struct qs_port_priv *pp = ap->private_data;
++ if (!pp || pp->state != qs_state_mmio)
++ continue;
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
++
++ /* check main status, clearing INTRQ */
++ u8 status = ata_check_status(ap);
++ if ((status & ATA_BUSY))
++ continue;
++ DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
++ ap->id, qc->tf.protocol, status);
++
++ /* complete taskfile transaction */
++ pp->state = qs_state_idle;
++ qc->err_mask |= ac_err_mask(status);
++ ata_qc_complete(qc);
++ handled = 1;
++ }
++ }
++ }
++ return handled;
++}
++
++static irqreturn_t qs_intr(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ unsigned int handled = 0;
++
++ VPRINTK("ENTER\n");
++
++ spin_lock(&host->lock);
++ handled = qs_intr_pkt(host) | qs_intr_mmio(host);
++ spin_unlock(&host->lock);
++
++ VPRINTK("EXIT\n");
++
++ return IRQ_RETVAL(handled);
++}
++
++static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr =
++ port->data_addr = base + 0x400;
++ port->error_addr =
++ port->feature_addr = base + 0x408; /* hob_feature = 0x409 */
++ port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */
++ port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */
++ port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */
++ port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */
++ port->device_addr = base + 0x430;
++ port->status_addr =
++ port->command_addr = base + 0x438;
++ port->altstatus_addr =
++ port->ctl_addr = base + 0x440;
++ port->scr_addr = base + 0xc00;
++}
++
++static int qs_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct qs_port_priv *pp;
++ void __iomem *mmio_base = ap->host->mmio_base;
++ void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
++ u64 addr;
++ int rc;
++
++ rc = ata_port_start(ap);
++ if (rc)
++ return rc;
++ qs_enter_reg_mode(ap);
++ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
++ if (!pp) {
++ rc = -ENOMEM;
++ goto err_out;
++ }
++ pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
++ GFP_KERNEL);
++ if (!pp->pkt) {
++ rc = -ENOMEM;
++ goto err_out_kfree;
++ }
++ memset(pp->pkt, 0, QS_PKT_BYTES);
++ ap->private_data = pp;
++
++ addr = (u64)pp->pkt_dma;
++ writel((u32) addr, chan + QS_CCF_CPBA);
++ writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
++ return 0;
++
++err_out_kfree:
++ kfree(pp);
++err_out:
++ ata_port_stop(ap);
++ return rc;
++}
++
++static void qs_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct qs_port_priv *pp = ap->private_data;
++
++ if (pp != NULL) {
++ ap->private_data = NULL;
++ if (pp->pkt != NULL)
++ dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
++ pp->pkt_dma);
++ kfree(pp);
++ }
++ ata_port_stop(ap);
++}
++
++static void qs_host_stop(struct ata_host *host)
++{
++ void __iomem *mmio_base = host->mmio_base;
++ struct pci_dev *pdev = to_pci_dev(host->dev);
++
++ writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
++ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
++
++ pci_iounmap(pdev, mmio_base);
++}
++
++static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
++{
++ void __iomem *mmio_base = pe->mmio_base;
++ unsigned int port_no;
++
++ writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
++ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
++
++ /* reset each channel in turn */
++ for (port_no = 0; port_no < pe->n_ports; ++port_no) {
++ u8 __iomem *chan = mmio_base + (port_no * 0x4000);
++ writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
++ writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
++ readb(chan + QS_CCT_CTR0); /* flush */
++ }
++ writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
++
++ for (port_no = 0; port_no < pe->n_ports; ++port_no) {
++ u8 __iomem *chan = mmio_base + (port_no * 0x4000);
++ /* set FIFO depths to same settings as Windows driver */
++ writew(32, chan + QS_CFC_HUFT);
++ writew(32, chan + QS_CFC_HDFT);
++ writew(10, chan + QS_CFC_DUFT);
++ writew( 8, chan + QS_CFC_DDFT);
++ /* set CPB size in bytes, as a power of two */
++ writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP);
++ }
++ writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
++}
++
++/*
++ * The QStor understands 64-bit buses, and uses 64-bit fields
++ * for DMA pointers regardless of bus width. We just have to
++ * make sure our DMA masks are set appropriately for whatever
++ * bridge lies between us and the QStor, and then the DMA mapping
++ * code will ensure we only ever "see" appropriate buffer addresses.
++ * If we're 32-bit limited somewhere, then our 64-bit fields will
++ * just end up with zeros in the upper 32-bits, without any special
++ * logic required outside of this routine (below).
++ */
++static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
++{
++ u32 bus_info = readl(mmio_base + QS_HID_HPHY);
++ int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
++
++ if (have_64bit_bus &&
++ !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
++ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
++ if (rc) {
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "64-bit DMA enable failed\n");
++ return rc;
++ }
++ }
++ } else {
++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit DMA enable failed\n");
++ return rc;
++ }
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit consistent DMA enable failed\n");
++ return rc;
++ }
++ }
++ return 0;
++}
++
++static int qs_ata_init_one(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ void __iomem *mmio_base;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++ int rc, port_no;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc)
++ goto err_out;
++
++ if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
++ rc = -ENODEV;
++ goto err_out_regions;
++ }
++
++ mmio_base = pci_iomap(pdev, 4, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ rc = qs_set_dma_masks(pdev, mmio_base);
++ if (rc)
++ goto err_out_iounmap;
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_iounmap;
++ }
++
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ probe_ent->sht = qs_port_info[board_idx].sht;
++ probe_ent->port_flags = qs_port_info[board_idx].flags;
++ probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
++ probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
++ probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = qs_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++ probe_ent->n_ports = QS_PORTS;
++
++ for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
++ unsigned long chan = (unsigned long)mmio_base +
++ (port_no * 0x4000);
++ qs_ata_setup_port(&probe_ent->port[port_no], chan);
++ }
++
++ pci_set_master(pdev);
++
++ /* initialize adapter */
++ qs_host_init(board_idx, probe_ent);
++
++ rc = ata_device_add(probe_ent);
++ kfree(probe_ent);
++ if (rc != QS_PORTS)
++ goto err_out_iounmap;
++ return 0;
++
++err_out_iounmap:
++ pci_iounmap(pdev, mmio_base);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ pci_disable_device(pdev);
++ return rc;
++}
++
++static int __init qs_ata_init(void)
++{
++ return pci_register_driver(&qs_ata_pci_driver);
++}
++
++static void __exit qs_ata_exit(void)
++{
++ pci_unregister_driver(&qs_ata_pci_driver);
++}
++
++MODULE_AUTHOR("Mark Lord");
++MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(qs_ata_init);
++module_exit(qs_ata_exit);
+diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
+new file mode 100644
+index 0000000..ca8d993
+--- /dev/null
++++ b/drivers/ata/sata_sil.c
+@@ -0,0 +1,727 @@
++/*
++ * sata_sil.c - Silicon Image SATA
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003-2005 Red Hat, Inc.
++ * Copyright 2003 Benjamin Herrenschmidt
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Documentation for SiI 3112:
++ * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
++ *
++ * Other errata and documentation available under NDA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sata_sil"
++#define DRV_VERSION "2.0"
++
++enum {
++ /*
++ * host flags
++ */
++ SIL_FLAG_NO_SATA_IRQ = (1 << 28),
++ SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
++ SIL_FLAG_MOD15WRITE = (1 << 30),
++
++ SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
++
++ /*
++ * Controller IDs
++ */
++ sil_3112 = 0,
++ sil_3112_no_sata_irq = 1,
++ sil_3512 = 2,
++ sil_3114 = 3,
++
++ /*
++ * Register offsets
++ */
++ SIL_SYSCFG = 0x48,
++
++ /*
++ * Register bits
++ */
++ /* SYSCFG */
++ SIL_MASK_IDE0_INT = (1 << 22),
++ SIL_MASK_IDE1_INT = (1 << 23),
++ SIL_MASK_IDE2_INT = (1 << 24),
++ SIL_MASK_IDE3_INT = (1 << 25),
++ SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
++ SIL_MASK_4PORT = SIL_MASK_2PORT |
++ SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
++
++ /* BMDMA/BMDMA2 */
++ SIL_INTR_STEERING = (1 << 1),
++
++ SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */
++ SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */
++ SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */
++ SIL_DMA_ACTIVE = (1 << 16), /* DMA running */
++ SIL_DMA_ERROR = (1 << 17), /* PCI bus error */
++ SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */
++ SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */
++ SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */
++ SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */
++ SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */
++
++ /* SIEN */
++ SIL_SIEN_N = (1 << 16), /* triggered by SError.N */
++
++ /*
++ * Others
++ */
++ SIL_QUIRK_MOD15WRITE = (1 << 0),
++ SIL_QUIRK_UDMA5MAX = (1 << 1),
++};
++
++static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++#ifdef CONFIG_PM
++static int sil_pci_device_resume(struct pci_dev *pdev);
++#endif
++static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
++static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++static void sil_post_set_mode (struct ata_port *ap);
++static irqreturn_t sil_interrupt(int irq, void *dev_instance);
++static void sil_freeze(struct ata_port *ap);
++static void sil_thaw(struct ata_port *ap);
++
++
++static const struct pci_device_id sil_pci_tbl[] = {
++ { PCI_VDEVICE(CMD, 0x3112), sil_3112 },
++ { PCI_VDEVICE(CMD, 0x0240), sil_3112 },
++ { PCI_VDEVICE(CMD, 0x3512), sil_3512 },
++ { PCI_VDEVICE(CMD, 0x3114), sil_3114 },
++ { PCI_VDEVICE(ATI, 0x436e), sil_3112 },
++ { PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },
++ { PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq },
++
++ { } /* terminate list */
++};
++
++
++/* TODO firmware versions should be added - eric */
++static const struct sil_drivelist {
++ const char * product;
++ unsigned int quirk;
++} sil_blacklist [] = {
++ { "ST320012AS", SIL_QUIRK_MOD15WRITE },
++ { "ST330013AS", SIL_QUIRK_MOD15WRITE },
++ { "ST340017AS", SIL_QUIRK_MOD15WRITE },
++ { "ST360015AS", SIL_QUIRK_MOD15WRITE },
++ { "ST380023AS", SIL_QUIRK_MOD15WRITE },
++ { "ST3120023AS", SIL_QUIRK_MOD15WRITE },
++ { "ST340014ASL", SIL_QUIRK_MOD15WRITE },
++ { "ST360014ASL", SIL_QUIRK_MOD15WRITE },
++ { "ST380011ASL", SIL_QUIRK_MOD15WRITE },
++ { "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
++ { "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
++ { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
++ { }
++};
++
++static struct pci_driver sil_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sil_pci_tbl,
++ .probe = sil_init_one,
++ .remove = ata_pci_remove_one,
++#ifdef CONFIG_PM
++ .suspend = ata_pci_device_suspend,
++ .resume = sil_pci_device_resume,
++#endif
++};
++
++static struct scsi_host_template sil_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++ .suspend = ata_scsi_device_suspend,
++ .resume = ata_scsi_device_resume,
++};
++
++static const struct ata_port_operations sil_ops = {
++ .port_disable = ata_port_disable,
++ .dev_config = sil_dev_config,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .post_set_mode = sil_post_set_mode,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++ .freeze = sil_freeze,
++ .thaw = sil_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .irq_handler = sil_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = sil_scr_read,
++ .scr_write = sil_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static const struct ata_port_info sil_port_info[] = {
++ /* sil_3112 */
++ {
++ .sht = &sil_sht,
++ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil_ops,
++ },
++ /* sil_3112_no_sata_irq */
++ {
++ .sht = &sil_sht,
++ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
++ SIL_FLAG_NO_SATA_IRQ,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil_ops,
++ },
++ /* sil_3512 */
++ {
++ .sht = &sil_sht,
++ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil_ops,
++ },
++ /* sil_3114 */
++ {
++ .sht = &sil_sht,
++ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil_ops,
++ },
++};
++
++/* per-port register offsets */
++/* TODO: we can probably calculate rather than use a table */
++static const struct {
++ unsigned long tf; /* ATA taskfile register block */
++ unsigned long ctl; /* ATA control/altstatus register block */
++ unsigned long bmdma; /* DMA register block */
++ unsigned long bmdma2; /* DMA register block #2 */
++ unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
++ unsigned long scr; /* SATA control register block */
++ unsigned long sien; /* SATA Interrupt Enable register */
++ unsigned long xfer_mode;/* data transfer mode register */
++ unsigned long sfis_cfg; /* SATA FIS reception config register */
++} sil_port[] = {
++ /* port 0 ... */
++ { 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
++ { 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
++ { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
++ { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
++ /* ... port 3 */
++};
++
++MODULE_AUTHOR("Jeff Garzik");
++MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++static int slow_down = 0;
++module_param(slow_down, int, 0444);
++MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
++
++
++static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
++{
++ u8 cache_line = 0;
++ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
++ return cache_line;
++}
++
++static void sil_post_set_mode (struct ata_port *ap)
++{
++ struct ata_host *host = ap->host;
++ struct ata_device *dev;
++ void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode;
++ u32 tmp, dev_mode[2];
++ unsigned int i;
++
++ for (i = 0; i < 2; i++) {
++ dev = &ap->device[i];
++ if (!ata_dev_enabled(dev))
++ dev_mode[i] = 0; /* PIO0/1/2 */
++ else if (dev->flags & ATA_DFLAG_PIO)
++ dev_mode[i] = 1; /* PIO3/4 */
++ else
++ dev_mode[i] = 3; /* UDMA */
++ /* value 2 indicates MDMA */
++ }
++
++ tmp = readl(addr);
++ tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
++ tmp |= dev_mode[0];
++ tmp |= (dev_mode[1] << 4);
++ writel(tmp, addr);
++ readl(addr); /* flush */
++}
++
++static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
++{
++ unsigned long offset = ap->ioaddr.scr_addr;
++
++ switch (sc_reg) {
++ case SCR_STATUS:
++ return offset + 4;
++ case SCR_ERROR:
++ return offset + 8;
++ case SCR_CONTROL:
++ return offset;
++ default:
++ /* do nothing */
++ break;
++ }
++
++ return 0;
++}
++
++static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
++ if (mmio)
++ return readl(mmio);
++ return 0xffffffffU;
++}
++
++static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++ void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
++ if (mmio)
++ writel(val, mmio);
++}
++
++static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
++{
++ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
++ u8 status;
++
++ if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
++ u32 serror;
++
++ /* SIEN doesn't mask SATA IRQs on some 3112s. Those
++ * controllers continue to assert IRQ as long as
++ * SError bits are pending. Clear SError immediately.
++ */
++ serror = sil_scr_read(ap, SCR_ERROR);
++ sil_scr_write(ap, SCR_ERROR, serror);
++
++ /* Trigger hotplug and accumulate SError only if the
++ * port isn't already frozen. Otherwise, PHY events
++ * during hardreset makes controllers with broken SIEN
++ * repeat probing needlessly.
++ */
++ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
++ ata_ehi_hotplugged(&ap->eh_info);
++ ap->eh_info.serror |= serror;
++ }
++
++ goto freeze;
++ }
++
++ if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
++ goto freeze;
++
++ /* Check whether we are expecting interrupt in this state */
++ switch (ap->hsm_task_state) {
++ case HSM_ST_FIRST:
++ /* Some pre-ATAPI-4 devices assert INTRQ
++ * at this state when ready to receive CDB.
++ */
++
++ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
++ * The flag was turned on only for atapi devices.
++ * No need to check is_atapi_taskfile(&qc->tf) again.
++ */
++ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
++ goto err_hsm;
++ break;
++ case HSM_ST_LAST:
++ if (qc->tf.protocol == ATA_PROT_DMA ||
++ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
++ /* clear DMA-Start bit */
++ ap->ops->bmdma_stop(qc);
++
++ if (bmdma2 & SIL_DMA_ERROR) {
++ qc->err_mask |= AC_ERR_HOST_BUS;
++ ap->hsm_task_state = HSM_ST_ERR;
++ }
++ }
++ break;
++ case HSM_ST:
++ break;
++ default:
++ goto err_hsm;
++ }
++
++ /* check main status, clearing INTRQ */
++ status = ata_chk_status(ap);
++ if (unlikely(status & ATA_BUSY))
++ goto err_hsm;
++
++ /* ack bmdma irq events */
++ ata_bmdma_irq_clear(ap);
++
++ /* kick HSM in the ass */
++ ata_hsm_move(ap, qc, status, 0);
++
++ return;
++
++ err_hsm:
++ qc->err_mask |= AC_ERR_HSM;
++ freeze:
++ ata_port_freeze(ap);
++}
++
++static irqreturn_t sil_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ void __iomem *mmio_base = host->mmio_base;
++ int handled = 0;
++ int i;
++
++ spin_lock(&host->lock);
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++ u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
++
++ if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
++ continue;
++
++ /* turn off SATA_IRQ if not supported */
++ if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
++ bmdma2 &= ~SIL_DMA_SATA_IRQ;
++
++ if (bmdma2 == 0xffffffff ||
++ !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
++ continue;
++
++ sil_host_intr(ap, bmdma2);
++ handled = 1;
++ }
++
++ spin_unlock(&host->lock);
++
++ return IRQ_RETVAL(handled);
++}
++
++static void sil_freeze(struct ata_port *ap)
++{
++ void __iomem *mmio_base = ap->host->mmio_base;
++ u32 tmp;
++
++ /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
++ writel(0, mmio_base + sil_port[ap->port_no].sien);
++
++ /* plug IRQ */
++ tmp = readl(mmio_base + SIL_SYSCFG);
++ tmp |= SIL_MASK_IDE0_INT << ap->port_no;
++ writel(tmp, mmio_base + SIL_SYSCFG);
++ readl(mmio_base + SIL_SYSCFG); /* flush */
++}
++
++static void sil_thaw(struct ata_port *ap)
++{
++ void __iomem *mmio_base = ap->host->mmio_base;
++ u32 tmp;
++
++ /* clear IRQ */
++ ata_chk_status(ap);
++ ata_bmdma_irq_clear(ap);
++
++ /* turn on SATA IRQ if supported */
++ if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
++ writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
++
++ /* turn on IRQ */
++ tmp = readl(mmio_base + SIL_SYSCFG);
++ tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
++ writel(tmp, mmio_base + SIL_SYSCFG);
++}
++
++/**
++ * sil_dev_config - Apply device/host-specific errata fixups
++ * @ap: Port containing device to be examined
++ * @dev: Device to be examined
++ *
++ * After the IDENTIFY [PACKET] DEVICE step is complete, and a
++ * device is known to be present, this function is called.
++ * We apply two errata fixups which are specific to Silicon Image,
++ * a Seagate and a Maxtor fixup.
++ *
++ * For certain Seagate devices, we must limit the maximum sectors
++ * to under 8K.
++ *
++ * For certain Maxtor devices, we must not program the drive
++ * beyond udma5.
++ *
++ * Both fixups are unfairly pessimistic. As soon as I get more
++ * information on these errata, I will create a more exhaustive
++ * list, and apply the fixups to only the specific
++ * devices/hosts/firmwares that need it.
++ *
++ * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
++ * The Maxtor quirk is in the blacklist, but I'm keeping the original
++ * pessimistic fix for the following reasons...
++ * - There seems to be less info on it, only one device gleaned off the
++ * Windows driver, maybe only one is affected. More info would be greatly
++ * appreciated.
++ * - But then again UDMA5 is hardly anything to complain about
++ */
++static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
++{
++ unsigned int n, quirks = 0;
++ unsigned char model_num[41];
++
++ ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
++
++ for (n = 0; sil_blacklist[n].product; n++)
++ if (!strcmp(sil_blacklist[n].product, model_num)) {
++ quirks = sil_blacklist[n].quirk;
++ break;
++ }
++
++ /* limit requests to 15 sectors */
++ if (slow_down ||
++ ((ap->flags & SIL_FLAG_MOD15WRITE) &&
++ (quirks & SIL_QUIRK_MOD15WRITE))) {
++ ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix "
++ "(mod15write workaround)\n");
++ dev->max_sectors = 15;
++ return;
++ }
++
++ /* limit to udma5 */
++ if (quirks & SIL_QUIRK_UDMA5MAX) {
++ ata_dev_printk(dev, KERN_INFO,
++ "applying Maxtor errata fix %s\n", model_num);
++ dev->udma_mask &= ATA_UDMA5;
++ return;
++ }
++}
++
++static void sil_init_controller(struct pci_dev *pdev,
++ int n_ports, unsigned long port_flags,
++ void __iomem *mmio_base)
++{
++ u8 cls;
++ u32 tmp;
++ int i;
++
++ /* Initialize FIFO PCI bus arbitration */
++ cls = sil_get_device_cache_line(pdev);
++ if (cls) {
++ cls >>= 3;
++ cls++; /* cls = (line_size/8)+1 */
++ for (i = 0; i < n_ports; i++)
++ writew(cls << 8 | cls,
++ mmio_base + sil_port[i].fifo_cfg);
++ } else
++ dev_printk(KERN_WARNING, &pdev->dev,
++ "cache line size not set. Driver may not function\n");
++
++ /* Apply R_ERR on DMA activate FIS errata workaround */
++ if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
++ int cnt;
++
++ for (i = 0, cnt = 0; i < n_ports; i++) {
++ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
++ if ((tmp & 0x3) != 0x01)
++ continue;
++ if (!cnt)
++ dev_printk(KERN_INFO, &pdev->dev,
++ "Applying R_ERR on DMA activate "
++ "FIS errata fix\n");
++ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
++ cnt++;
++ }
++ }
++
++ if (n_ports == 4) {
++ /* flip the magic "make 4 ports work" bit */
++ tmp = readl(mmio_base + sil_port[2].bmdma);
++ if ((tmp & SIL_INTR_STEERING) == 0)
++ writel(tmp | SIL_INTR_STEERING,
++ mmio_base + sil_port[2].bmdma);
++ }
++}
++
++static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ unsigned long base;
++ void __iomem *mmio_base;
++ int rc;
++ unsigned int i;
++ int pci_dev_busy = 0;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ INIT_LIST_HEAD(&probe_ent->node);
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
++ probe_ent->sht = sil_port_info[ent->driver_data].sht;
++ probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
++ probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
++ probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
++ probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
++
++ mmio_base = pci_iomap(pdev, 5, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++
++ probe_ent->mmio_base = mmio_base;
++
++ base = (unsigned long) mmio_base;
++
++ for (i = 0; i < probe_ent->n_ports; i++) {
++ probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
++ probe_ent->port[i].altstatus_addr =
++ probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
++ probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
++ probe_ent->port[i].scr_addr = base + sil_port[i].scr;
++ ata_std_ports(&probe_ent->port[i]);
++ }
++
++ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
++ mmio_base);
++
++ pci_set_master(pdev);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++#ifdef CONFIG_PM
++static int sil_pci_device_resume(struct pci_dev *pdev)
++{
++ struct ata_host *host = dev_get_drvdata(&pdev->dev);
++
++ ata_pci_device_do_resume(pdev);
++ sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
++ host->mmio_base);
++ ata_host_resume(host);
++
++ return 0;
++}
++#endif
++
++static int __init sil_init(void)
++{
++ return pci_register_driver(&sil_pci_driver);
++}
++
++static void __exit sil_exit(void)
++{
++ pci_unregister_driver(&sil_pci_driver);
++}
++
++
++module_init(sil_init);
++module_exit(sil_exit);
+diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
+new file mode 100644
+index 0000000..169e200
+--- /dev/null
++++ b/drivers/ata/sata_sil24.c
+@@ -0,0 +1,1228 @@
++/*
++ * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers
++ *
++ * Copyright 2005 Tejun Heo
++ *
++ * Based on preview driver from Silicon Image.
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++
++#define DRV_NAME "sata_sil24"
++#define DRV_VERSION "0.3"
++
++/*
++ * Port request block (PRB) 32 bytes
++ */
++struct sil24_prb {
++ __le16 ctrl;
++ __le16 prot;
++ __le32 rx_cnt;
++ u8 fis[6 * 4];
++};
++
++/*
++ * Scatter gather entry (SGE) 16 bytes
++ */
++struct sil24_sge {
++ __le64 addr;
++ __le32 cnt;
++ __le32 flags;
++};
++
++/*
++ * Port multiplier
++ */
++struct sil24_port_multiplier {
++ __le32 diag;
++ __le32 sactive;
++};
++
++enum {
++ /*
++ * Global controller registers (128 bytes @ BAR0)
++ */
++ /* 32 bit regs */
++ HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */
++ HOST_CTRL = 0x40,
++ HOST_IRQ_STAT = 0x44,
++ HOST_PHY_CFG = 0x48,
++ HOST_BIST_CTRL = 0x50,
++ HOST_BIST_PTRN = 0x54,
++ HOST_BIST_STAT = 0x58,
++ HOST_MEM_BIST_STAT = 0x5c,
++ HOST_FLASH_CMD = 0x70,
++ /* 8 bit regs */
++ HOST_FLASH_DATA = 0x74,
++ HOST_TRANSITION_DETECT = 0x75,
++ HOST_GPIO_CTRL = 0x76,
++ HOST_I2C_ADDR = 0x78, /* 32 bit */
++ HOST_I2C_DATA = 0x7c,
++ HOST_I2C_XFER_CNT = 0x7e,
++ HOST_I2C_CTRL = 0x7f,
++
++ /* HOST_SLOT_STAT bits */
++ HOST_SSTAT_ATTN = (1 << 31),
++
++ /* HOST_CTRL bits */
++ HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */
++ HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */
++ HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
++ HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
++ HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
++ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
++
++ /*
++ * Port registers
++ * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
++ */
++ PORT_REGS_SIZE = 0x2000,
++
++ PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */
++ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
++
++ PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
++ /* 32 bit regs */
++ PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */
++ PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */
++ PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */
++ PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */
++ PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */
++ PORT_ACTIVATE_UPPER_ADDR= 0x101c,
++ PORT_EXEC_FIFO = 0x1020, /* command execution fifo */
++ PORT_CMD_ERR = 0x1024, /* command error number */
++ PORT_FIS_CFG = 0x1028,
++ PORT_FIFO_THRES = 0x102c,
++ /* 16 bit regs */
++ PORT_DECODE_ERR_CNT = 0x1040,
++ PORT_DECODE_ERR_THRESH = 0x1042,
++ PORT_CRC_ERR_CNT = 0x1044,
++ PORT_CRC_ERR_THRESH = 0x1046,
++ PORT_HSHK_ERR_CNT = 0x1048,
++ PORT_HSHK_ERR_THRESH = 0x104a,
++ /* 32 bit regs */
++ PORT_PHY_CFG = 0x1050,
++ PORT_SLOT_STAT = 0x1800,
++ PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */
++ PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */
++ PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */
++ PORT_SCONTROL = 0x1f00,
++ PORT_SSTATUS = 0x1f04,
++ PORT_SERROR = 0x1f08,
++ PORT_SACTIVE = 0x1f0c,
++
++ /* PORT_CTRL_STAT bits */
++ PORT_CS_PORT_RST = (1 << 0), /* port reset */
++ PORT_CS_DEV_RST = (1 << 1), /* device reset */
++ PORT_CS_INIT = (1 << 2), /* port initialize */
++ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */
++ PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */
++ PORT_CS_RESUME = (1 << 6), /* port resume */
++ PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */
++ PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */
++ PORT_CS_RDY = (1 << 31), /* port ready to accept commands */
++
++ /* PORT_IRQ_STAT/ENABLE_SET/CLR */
++ /* bits[11:0] are masked */
++ PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */
++ PORT_IRQ_ERROR = (1 << 1), /* command execution error */
++ PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */
++ PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */
++ PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */
++ PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */
++ PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */
++ PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */
++ PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */
++ PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */
++ PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */
++ PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
++
++ DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
++ PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
++ PORT_IRQ_UNK_FIS,
++
++ /* bits[27:16] are unmasked (raw) */
++ PORT_IRQ_RAW_SHIFT = 16,
++ PORT_IRQ_MASKED_MASK = 0x7ff,
++ PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT),
++
++ /* ENABLE_SET/CLR specific, intr steering - 2 bit field */
++ PORT_IRQ_STEER_SHIFT = 30,
++ PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT),
++
++ /* PORT_CMD_ERR constants */
++ PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */
++ PORT_CERR_SDB = 2, /* Error bit in SDB FIS */
++ PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */
++ PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */
++ PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */
++ PORT_CERR_DIRECTION = 6, /* Data direction mismatch */
++ PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */
++ PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */
++ PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */
++ PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */
++ PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */
++ PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */
++ PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */
++ PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */
++ PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */
++ PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */
++ PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */
++ PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */
++ PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */
++ PORT_CERR_XFR_MSTABRT = 34, /* PSD ecode 10 - master abort */
++ PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */
++ PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */
++
++ /* bits of PRB control field */
++ PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */
++ PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */
++ PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */
++ PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */
++ PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */
++
++ /* PRB protocol field */
++ PRB_PROT_PACKET = (1 << 0),
++ PRB_PROT_TCQ = (1 << 1),
++ PRB_PROT_NCQ = (1 << 2),
++ PRB_PROT_READ = (1 << 3),
++ PRB_PROT_WRITE = (1 << 4),
++ PRB_PROT_TRANSPARENT = (1 << 5),
++
++ /*
++ * Other constants
++ */
++ SGE_TRM = (1 << 31), /* Last SGE in chain */
++ SGE_LNK = (1 << 30), /* linked list
++ Points to SGT, not SGE */
++ SGE_DRD = (1 << 29), /* discard data read (/dev/null)
++ data address ignored */
++
++ SIL24_MAX_CMDS = 31,
++
++ /* board id */
++ BID_SIL3124 = 0,
++ BID_SIL3132 = 1,
++ BID_SIL3131 = 2,
++
++ /* host flags */
++ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
++ ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY,
++ SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
++
++ IRQ_STAT_4PORTS = 0xf,
++};
++
++struct sil24_ata_block {
++ struct sil24_prb prb;
++ struct sil24_sge sge[LIBATA_MAX_PRD];
++};
++
++struct sil24_atapi_block {
++ struct sil24_prb prb;
++ u8 cdb[16];
++ struct sil24_sge sge[LIBATA_MAX_PRD - 1];
++};
++
++union sil24_cmd_block {
++ struct sil24_ata_block ata;
++ struct sil24_atapi_block atapi;
++};
++
++static struct sil24_cerr_info {
++ unsigned int err_mask, action;
++ const char *desc;
++} sil24_cerr_db[] = {
++ [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
++ "device error" },
++ [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
++ "device error via D2H FIS" },
++ [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
++ "device error via SDB FIS" },
++ [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
++ "error in data FIS" },
++ [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
++ "failed to transmit command FIS" },
++ [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
++ "protocol mismatch" },
++ [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
++ "data directon mismatch" },
++ [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
++ "ran out of SGEs while writing" },
++ [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
++ "ran out of SGEs while reading" },
++ [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
++ "invalid data directon for ATAPI CDB" },
++ [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
++ "SGT no on qword boundary" },
++ [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI target abort while fetching SGT" },
++ [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI master abort while fetching SGT" },
++ [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI parity error while fetching SGT" },
++ [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
++ "PRB not on qword boundary" },
++ [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI target abort while fetching PRB" },
++ [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI master abort while fetching PRB" },
++ [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI parity error while fetching PRB" },
++ [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "undefined error while transferring data" },
++ [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI target abort while transferring data" },
++ [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI master abort while transferring data" },
++ [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
++ "PCI parity error while transferring data" },
++ [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
++ "FIS received while sending service FIS" },
++};
++
++/*
++ * ap->private_data
++ *
++ * The preview driver always returned 0 for status. We emulate it
++ * here from the previous interrupt.
++ */
++struct sil24_port_priv {
++ union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
++ dma_addr_t cmd_block_dma; /* DMA base addr for them */
++ struct ata_taskfile tf; /* Cached taskfile registers */
++};
++
++/* ap->host->private_data */
++struct sil24_host_priv {
++ void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
++ void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
++};
++
++static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
++static u8 sil24_check_status(struct ata_port *ap);
++static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
++static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
++static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
++static void sil24_qc_prep(struct ata_queued_cmd *qc);
++static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
++static void sil24_irq_clear(struct ata_port *ap);
++static irqreturn_t sil24_interrupt(int irq, void *dev_instance);
++static void sil24_freeze(struct ata_port *ap);
++static void sil24_thaw(struct ata_port *ap);
++static void sil24_error_handler(struct ata_port *ap);
++static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
++static int sil24_port_start(struct ata_port *ap);
++static void sil24_port_stop(struct ata_port *ap);
++static void sil24_host_stop(struct ata_host *host);
++static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
++#ifdef CONFIG_PM
++static int sil24_pci_device_resume(struct pci_dev *pdev);
++#endif
++
++static const struct pci_device_id sil24_pci_tbl[] = {
++ { PCI_VDEVICE(CMD, 0x3124), BID_SIL3124 },
++ { PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
++ { PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
++ { PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
++ { PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver sil24_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sil24_pci_tbl,
++ .probe = sil24_init_one,
++ .remove = ata_pci_remove_one, /* safe? */
++#ifdef CONFIG_PM
++ .suspend = ata_pci_device_suspend,
++ .resume = sil24_pci_device_resume,
++#endif
++};
++
++static struct scsi_host_template sil24_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .change_queue_depth = ata_scsi_change_queue_depth,
++ .can_queue = SIL24_MAX_CMDS,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++ .suspend = ata_scsi_device_suspend,
++ .resume = ata_scsi_device_resume,
++};
++
++static const struct ata_port_operations sil24_ops = {
++ .port_disable = ata_port_disable,
++
++ .dev_config = sil24_dev_config,
++
++ .check_status = sil24_check_status,
++ .check_altstatus = sil24_check_status,
++ .dev_select = ata_noop_dev_select,
++
++ .tf_read = sil24_tf_read,
++
++ .qc_prep = sil24_qc_prep,
++ .qc_issue = sil24_qc_issue,
++
++ .irq_handler = sil24_interrupt,
++ .irq_clear = sil24_irq_clear,
++
++ .scr_read = sil24_scr_read,
++ .scr_write = sil24_scr_write,
++
++ .freeze = sil24_freeze,
++ .thaw = sil24_thaw,
++ .error_handler = sil24_error_handler,
++ .post_internal_cmd = sil24_post_internal_cmd,
++
++ .port_start = sil24_port_start,
++ .port_stop = sil24_port_stop,
++ .host_stop = sil24_host_stop,
++};
++
++/*
++ * Use bits 30-31 of port_flags to encode available port numbers.
++ * Current maxium is 4.
++ */
++#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
++#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
++
++static struct ata_port_info sil24_port_info[] = {
++ /* sil_3124 */
++ {
++ .sht = &sil24_sht,
++ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
++ SIL24_FLAG_PCIX_IRQ_WOC,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil24_ops,
++ },
++ /* sil_3132 */
++ {
++ .sht = &sil24_sht,
++ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil24_ops,
++ },
++ /* sil_3131/sil_3531 */
++ {
++ .sht = &sil24_sht,
++ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x3f, /* udma0-5 */
++ .port_ops = &sil24_ops,
++ },
++};
++
++static int sil24_tag(int tag)
++{
++ if (unlikely(ata_tag_internal(tag)))
++ return 0;
++ return tag;
++}
++
++static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++
++ if (dev->cdb_len == 16)
++ writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
++ else
++ writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
++}
++
++static inline void sil24_update_tf(struct ata_port *ap)
++{
++ struct sil24_port_priv *pp = ap->private_data;
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ struct sil24_prb __iomem *prb = port;
++ u8 fis[6 * 4];
++
++ memcpy_fromio(fis, prb->fis, 6 * 4);
++ ata_tf_from_fis(fis, &pp->tf);
++}
++
++static u8 sil24_check_status(struct ata_port *ap)
++{
++ struct sil24_port_priv *pp = ap->private_data;
++ return pp->tf.command;
++}
++
++static int sil24_scr_map[] = {
++ [SCR_CONTROL] = 0,
++ [SCR_STATUS] = 1,
++ [SCR_ERROR] = 2,
++ [SCR_ACTIVE] = 3,
++};
++
++static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
++{
++ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
++ if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
++ void __iomem *addr;
++ addr = scr_addr + sil24_scr_map[sc_reg] * 4;
++ return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
++ }
++ return 0xffffffffU;
++}
++
++static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
++{
++ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
++ if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
++ void __iomem *addr;
++ addr = scr_addr + sil24_scr_map[sc_reg] * 4;
++ writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
++ }
++}
++
++static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct sil24_port_priv *pp = ap->private_data;
++ *tf = pp->tf;
++}
++
++static int sil24_init_port(struct ata_port *ap)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ u32 tmp;
++
++ writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
++ ata_wait_register(port + PORT_CTRL_STAT,
++ PORT_CS_INIT, PORT_CS_INIT, 10, 100);
++ tmp = ata_wait_register(port + PORT_CTRL_STAT,
++ PORT_CS_RDY, 0, 10, 100);
++
++ if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
++ return -EIO;
++ return 0;
++}
++
++static int sil24_softreset(struct ata_port *ap, unsigned int *class)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ struct sil24_port_priv *pp = ap->private_data;
++ struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
++ dma_addr_t paddr = pp->cmd_block_dma;
++ u32 mask, irq_stat;
++ const char *reason;
++
++ DPRINTK("ENTER\n");
++
++ if (ata_port_offline(ap)) {
++ DPRINTK("PHY reports no device\n");
++ *class = ATA_DEV_NONE;
++ goto out;
++ }
++
++ /* put the port into known state */
++ if (sil24_init_port(ap)) {
++ reason ="port not ready";
++ goto err;
++ }
++
++ /* do SRST */
++ prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
++ prb->fis[1] = 0; /* no PM yet */
++
++ writel((u32)paddr, port + PORT_CMD_ACTIVATE);
++ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
++
++ mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
++ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
++ 100, ATA_TMOUT_BOOT / HZ * 1000);
++
++ writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
++ irq_stat >>= PORT_IRQ_RAW_SHIFT;
++
++ if (!(irq_stat & PORT_IRQ_COMPLETE)) {
++ if (irq_stat & PORT_IRQ_ERROR)
++ reason = "SRST command error";
++ else
++ reason = "timeout";
++ goto err;
++ }
++
++ sil24_update_tf(ap);
++ *class = ata_dev_classify(&pp->tf);
++
++ if (*class == ATA_DEV_UNKNOWN)
++ *class = ATA_DEV_NONE;
++
++ out:
++ DPRINTK("EXIT, class=%u\n", *class);
++ return 0;
++
++ err:
++ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
++ return -EIO;
++}
++
++static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ const char *reason;
++ int tout_msec, rc;
++ u32 tmp;
++
++ /* sil24 does the right thing(tm) without any protection */
++ sata_set_spd(ap);
++
++ tout_msec = 100;
++ if (ata_port_online(ap))
++ tout_msec = 5000;
++
++ writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
++ tmp = ata_wait_register(port + PORT_CTRL_STAT,
++ PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
++
++ /* SStatus oscillates between zero and valid status after
++ * DEV_RST, debounce it.
++ */
++ rc = sata_phy_debounce(ap, sata_deb_timing_long);
++ if (rc) {
++ reason = "PHY debouncing failed";
++ goto err;
++ }
++
++ if (tmp & PORT_CS_DEV_RST) {
++ if (ata_port_offline(ap))
++ return 0;
++ reason = "link not ready";
++ goto err;
++ }
++
++ /* Sil24 doesn't store signature FIS after hardreset, so we
++ * can't wait for BSY to clear. Some devices take a long time
++ * to get ready and those devices will choke if we don't wait
++ * for BSY clearance here. Tell libata to perform follow-up
++ * softreset.
++ */
++ return -EAGAIN;
++
++ err:
++ ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
++ return -EIO;
++}
++
++static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
++ struct sil24_sge *sge)
++{
++ struct scatterlist *sg;
++ unsigned int idx = 0;
++
++ ata_for_each_sg(sg, qc) {
++ sge->addr = cpu_to_le64(sg_dma_address(sg));
++ sge->cnt = cpu_to_le32(sg_dma_len(sg));
++ if (ata_sg_is_last(sg, qc))
++ sge->flags = cpu_to_le32(SGE_TRM);
++ else
++ sge->flags = 0;
++
++ sge++;
++ idx++;
++ }
++}
++
++static void sil24_qc_prep(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct sil24_port_priv *pp = ap->private_data;
++ union sil24_cmd_block *cb;
++ struct sil24_prb *prb;
++ struct sil24_sge *sge;
++ u16 ctrl = 0;
++
++ cb = &pp->cmd_block[sil24_tag(qc->tag)];
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_PIO:
++ case ATA_PROT_DMA:
++ case ATA_PROT_NCQ:
++ case ATA_PROT_NODATA:
++ prb = &cb->ata.prb;
++ sge = cb->ata.sge;
++ break;
++
++ case ATA_PROT_ATAPI:
++ case ATA_PROT_ATAPI_DMA:
++ case ATA_PROT_ATAPI_NODATA:
++ prb = &cb->atapi.prb;
++ sge = cb->atapi.sge;
++ memset(cb->atapi.cdb, 0, 32);
++ memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
++
++ if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
++ if (qc->tf.flags & ATA_TFLAG_WRITE)
++ ctrl = PRB_CTRL_PACKET_WRITE;
++ else
++ ctrl = PRB_CTRL_PACKET_READ;
++ }
++ break;
++
++ default:
++ prb = NULL; /* shut up, gcc */
++ sge = NULL;
++ BUG();
++ }
++
++ prb->ctrl = cpu_to_le16(ctrl);
++ ata_tf_to_fis(&qc->tf, prb->fis, 0);
++
++ if (qc->flags & ATA_QCFLAG_DMAMAP)
++ sil24_fill_sg(qc, sge);
++}
++
++static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct sil24_port_priv *pp = ap->private_data;
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ unsigned int tag = sil24_tag(qc->tag);
++ dma_addr_t paddr;
++ void __iomem *activate;
++
++ paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
++ activate = port + PORT_CMD_ACTIVATE + tag * 8;
++
++ writel((u32)paddr, activate);
++ writel((u64)paddr >> 32, activate + 4);
++
++ return 0;
++}
++
++static void sil24_irq_clear(struct ata_port *ap)
++{
++ /* unused */
++}
++
++static void sil24_freeze(struct ata_port *ap)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++
++ /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
++ * PORT_IRQ_ENABLE instead.
++ */
++ writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
++}
++
++static void sil24_thaw(struct ata_port *ap)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ u32 tmp;
++
++ /* clear IRQ */
++ tmp = readl(port + PORT_IRQ_STAT);
++ writel(tmp, port + PORT_IRQ_STAT);
++
++ /* turn IRQ back on */
++ writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET);
++}
++
++static void sil24_error_intr(struct ata_port *ap)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ struct ata_eh_info *ehi = &ap->eh_info;
++ int freeze = 0;
++ u32 irq_stat;
++
++ /* on error, we need to clear IRQ explicitly */
++ irq_stat = readl(port + PORT_IRQ_STAT);
++ writel(irq_stat, port + PORT_IRQ_STAT);
++
++ /* first, analyze and record host port events */
++ ata_ehi_clear_desc(ehi);
++
++ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
++
++ if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
++ ata_ehi_hotplugged(ehi);
++ ata_ehi_push_desc(ehi, ", %s",
++ irq_stat & PORT_IRQ_PHYRDY_CHG ?
++ "PHY RDY changed" : "device exchanged");
++ freeze = 1;
++ }
++
++ if (irq_stat & PORT_IRQ_UNK_FIS) {
++ ehi->err_mask |= AC_ERR_HSM;
++ ehi->action |= ATA_EH_SOFTRESET;
++ ata_ehi_push_desc(ehi , ", unknown FIS");
++ freeze = 1;
++ }
++
++ /* deal with command error */
++ if (irq_stat & PORT_IRQ_ERROR) {
++ struct sil24_cerr_info *ci = NULL;
++ unsigned int err_mask = 0, action = 0;
++ struct ata_queued_cmd *qc;
++ u32 cerr;
++
++ /* analyze CMD_ERR */
++ cerr = readl(port + PORT_CMD_ERR);
++ if (cerr < ARRAY_SIZE(sil24_cerr_db))
++ ci = &sil24_cerr_db[cerr];
++
++ if (ci && ci->desc) {
++ err_mask |= ci->err_mask;
++ action |= ci->action;
++ ata_ehi_push_desc(ehi, ", %s", ci->desc);
++ } else {
++ err_mask |= AC_ERR_OTHER;
++ action |= ATA_EH_SOFTRESET;
++ ata_ehi_push_desc(ehi, ", unknown command error %d",
++ cerr);
++ }
++
++ /* record error info */
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc) {
++ sil24_update_tf(ap);
++ qc->err_mask |= err_mask;
++ } else
++ ehi->err_mask |= err_mask;
++
++ ehi->action |= action;
++ }
++
++ /* freeze or abort */
++ if (freeze)
++ ata_port_freeze(ap);
++ else
++ ata_port_abort(ap);
++}
++
++static void sil24_finish_qc(struct ata_queued_cmd *qc)
++{
++ if (qc->flags & ATA_QCFLAG_RESULT_TF)
++ sil24_update_tf(qc->ap);
++}
++
++static inline void sil24_host_intr(struct ata_port *ap)
++{
++ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
++ u32 slot_stat, qc_active;
++ int rc;
++
++ slot_stat = readl(port + PORT_SLOT_STAT);
++
++ if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
++ sil24_error_intr(ap);
++ return;
++ }
++
++ if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
++ writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
++
++ qc_active = slot_stat & ~HOST_SSTAT_ATTN;
++ rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
++ if (rc > 0)
++ return;
++ if (rc < 0) {
++ struct ata_eh_info *ehi = &ap->eh_info;
++ ehi->err_mask |= AC_ERR_HSM;
++ ehi->action |= ATA_EH_SOFTRESET;
++ ata_port_freeze(ap);
++ return;
++ }
++
++ if (ata_ratelimit())
++ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
++ "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
++ slot_stat, ap->active_tag, ap->sactive);
++}
++
++static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ struct sil24_host_priv *hpriv = host->private_data;
++ unsigned handled = 0;
++ u32 status;
++ int i;
++
++ status = readl(hpriv->host_base + HOST_IRQ_STAT);
++
++ if (status == 0xffffffff) {
++ printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, "
++ "PCI fault or device removal?\n");
++ goto out;
++ }
++
++ if (!(status & IRQ_STAT_4PORTS))
++ goto out;
++
++ spin_lock(&host->lock);
++
++ for (i = 0; i < host->n_ports; i++)
++ if (status & (1 << i)) {
++ struct ata_port *ap = host->ports[i];
++ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
++ sil24_host_intr(host->ports[i]);
++ handled++;
++ } else
++ printk(KERN_ERR DRV_NAME
++ ": interrupt from disabled port %d\n", i);
++ }
++
++ spin_unlock(&host->lock);
++ out:
++ return IRQ_RETVAL(handled);
++}
++
++static void sil24_error_handler(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++
++ if (sil24_init_port(ap)) {
++ ata_eh_freeze_port(ap);
++ ehc->i.action |= ATA_EH_HARDRESET;
++ }
++
++ /* perform recovery */
++ ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
++ ata_std_postreset);
++}
++
++static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++
++ if (qc->flags & ATA_QCFLAG_FAILED)
++ qc->err_mask |= AC_ERR_OTHER;
++
++ /* make DMA engine forget about the failed command */
++ if (qc->err_mask)
++ sil24_init_port(ap);
++}
++
++static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
++{
++ const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
++
++ dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
++}
++
++static int sil24_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct sil24_port_priv *pp;
++ union sil24_cmd_block *cb;
++ size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
++ dma_addr_t cb_dma;
++ int rc = -ENOMEM;
++
++ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
++ if (!pp)
++ goto err_out;
++
++ pp->tf.command = ATA_DRDY;
++
++ cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
++ if (!cb)
++ goto err_out_pp;
++ memset(cb, 0, cb_size);
++
++ rc = ata_pad_alloc(ap, dev);
++ if (rc)
++ goto err_out_pad;
++
++ pp->cmd_block = cb;
++ pp->cmd_block_dma = cb_dma;
++
++ ap->private_data = pp;
++
++ return 0;
++
++err_out_pad:
++ sil24_cblk_free(pp, dev);
++err_out_pp:
++ kfree(pp);
++err_out:
++ return rc;
++}
++
++static void sil24_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct sil24_port_priv *pp = ap->private_data;
++
++ sil24_cblk_free(pp, dev);
++ ata_pad_free(ap, dev);
++ kfree(pp);
++}
++
++static void sil24_host_stop(struct ata_host *host)
++{
++ struct sil24_host_priv *hpriv = host->private_data;
++ struct pci_dev *pdev = to_pci_dev(host->dev);
++
++ pci_iounmap(pdev, hpriv->host_base);
++ pci_iounmap(pdev, hpriv->port_base);
++ kfree(hpriv);
++}
++
++static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
++ unsigned long port_flags,
++ void __iomem *host_base,
++ void __iomem *port_base)
++{
++ u32 tmp;
++ int i;
++
++ /* GPIO off */
++ writel(0, host_base + HOST_FLASH_CMD);
++
++ /* clear global reset & mask interrupts during initialization */
++ writel(0, host_base + HOST_CTRL);
++
++ /* init ports */
++ for (i = 0; i < n_ports; i++) {
++ void __iomem *port = port_base + i * PORT_REGS_SIZE;
++
++ /* Initial PHY setting */
++ writel(0x20c, port + PORT_PHY_CFG);
++
++ /* Clear port RST */
++ tmp = readl(port + PORT_CTRL_STAT);
++ if (tmp & PORT_CS_PORT_RST) {
++ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
++ tmp = ata_wait_register(port + PORT_CTRL_STAT,
++ PORT_CS_PORT_RST,
++ PORT_CS_PORT_RST, 10, 100);
++ if (tmp & PORT_CS_PORT_RST)
++ dev_printk(KERN_ERR, &pdev->dev,
++ "failed to clear port RST\n");
++ }
++
++ /* Configure IRQ WoC */
++ if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC)
++ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
++ else
++ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
++
++ /* Zero error counters. */
++ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
++ writel(0x8000, port + PORT_CRC_ERR_THRESH);
++ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
++ writel(0x0000, port + PORT_DECODE_ERR_CNT);
++ writel(0x0000, port + PORT_CRC_ERR_CNT);
++ writel(0x0000, port + PORT_HSHK_ERR_CNT);
++
++ /* Always use 64bit activation */
++ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
++
++ /* Clear port multiplier enable and resume bits */
++ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
++ }
++
++ /* Turn on interrupts */
++ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
++}
++
++static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version = 0;
++ unsigned int board_id = (unsigned int)ent->driver_data;
++ struct ata_port_info *pinfo = &sil24_port_info[board_id];
++ struct ata_probe_ent *probe_ent = NULL;
++ struct sil24_host_priv *hpriv = NULL;
++ void __iomem *host_base = NULL;
++ void __iomem *port_base = NULL;
++ int i, rc;
++ u32 tmp;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc)
++ goto out_disable;
++
++ rc = -ENOMEM;
++ /* map mmio registers */
++ host_base = pci_iomap(pdev, 0, 0);
++ if (!host_base)
++ goto out_free;
++ port_base = pci_iomap(pdev, 2, 0);
++ if (!port_base)
++ goto out_free;
++
++ /* allocate & init probe_ent and hpriv */
++ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (!probe_ent)
++ goto out_free;
++
++ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
++ if (!hpriv)
++ goto out_free;
++
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ probe_ent->sht = pinfo->sht;
++ probe_ent->port_flags = pinfo->flags;
++ probe_ent->pio_mask = pinfo->pio_mask;
++ probe_ent->mwdma_mask = pinfo->mwdma_mask;
++ probe_ent->udma_mask = pinfo->udma_mask;
++ probe_ent->port_ops = pinfo->port_ops;
++ probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->flags);
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->private_data = hpriv;
++
++ hpriv->host_base = host_base;
++ hpriv->port_base = port_base;
++
++ /*
++ * Configure the device
++ */
++ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
++ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
++ if (rc) {
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "64-bit DMA enable failed\n");
++ goto out_free;
++ }
++ }
++ } else {
++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit DMA enable failed\n");
++ goto out_free;
++ }
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "32-bit consistent DMA enable failed\n");
++ goto out_free;
++ }
++ }
++
++ /* Apply workaround for completion IRQ loss on PCI-X errata */
++ if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
++ tmp = readl(host_base + HOST_CTRL);
++ if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
++ dev_printk(KERN_INFO, &pdev->dev,
++ "Applying completion IRQ loss on PCI-X "
++ "errata fix\n");
++ else
++ probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
++ }
++
++ for (i = 0; i < probe_ent->n_ports; i++) {
++ unsigned long portu =
++ (unsigned long)port_base + i * PORT_REGS_SIZE;
++
++ probe_ent->port[i].cmd_addr = portu;
++ probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
++
++ ata_std_ports(&probe_ent->port[i]);
++ }
++
++ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
++ host_base, port_base);
++
++ pci_set_master(pdev);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++
++ kfree(probe_ent);
++ return 0;
++
++ out_free:
++ if (host_base)
++ pci_iounmap(pdev, host_base);
++ if (port_base)
++ pci_iounmap(pdev, port_base);
++ kfree(probe_ent);
++ kfree(hpriv);
++ pci_release_regions(pdev);
++ out_disable:
++ pci_disable_device(pdev);
++ return rc;
++}
++
++#ifdef CONFIG_PM
++static int sil24_pci_device_resume(struct pci_dev *pdev)
++{
++ struct ata_host *host = dev_get_drvdata(&pdev->dev);
++ struct sil24_host_priv *hpriv = host->private_data;
++
++ ata_pci_device_do_resume(pdev);
++
++ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
++ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
++
++ sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
++ hpriv->host_base, hpriv->port_base);
++
++ ata_host_resume(host);
++
++ return 0;
++}
++#endif
++
++static int __init sil24_init(void)
++{
++ return pci_register_driver(&sil24_pci_driver);
++}
++
++static void __exit sil24_exit(void)
++{
++ pci_unregister_driver(&sil24_pci_driver);
++}
++
++MODULE_AUTHOR("Tejun Heo");
++MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sil24_pci_tbl);
++
++module_init(sil24_init);
++module_exit(sil24_exit);
+diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
+new file mode 100644
+index 0000000..9d1235b
+--- /dev/null
++++ b/drivers/ata/sata_sis.c
+@@ -0,0 +1,346 @@
++/*
++ * sata_sis.c - Silicon Integrated Systems SATA
++ *
++ * Maintained by: Uwe Koziolek
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2004 Uwe Koziolek
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available under NDA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sata_sis"
++#define DRV_VERSION "0.6"
++
++enum {
++ sis_180 = 0,
++ SIS_SCR_PCI_BAR = 5,
++
++ /* PCI configuration registers */
++ SIS_GENCTL = 0x54, /* IDE General Control register */
++ SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */
++ SIS180_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */
++ SIS182_SATA1_OFS = 0x20, /* offset from sata0->sata1 phy regs */
++ SIS_PMR = 0x90, /* port mapping register */
++ SIS_PMR_COMBINED = 0x30,
++
++ /* random bits */
++ SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */
++
++ GENCTL_IOMAPPED_SCR = (1 << 26), /* if set, SCRs are in IO space */
++};
++
++static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++
++static const struct pci_device_id sis_pci_tbl[] = {
++ { PCI_VDEVICE(SI, 0x180), sis_180 },
++ { PCI_VDEVICE(SI, 0x181), sis_180 },
++ { PCI_VDEVICE(SI, 0x182), sis_180 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver sis_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = sis_pci_tbl,
++ .probe = sis_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static struct scsi_host_template sis_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = ATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations sis_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = sis_scr_read,
++ .scr_write = sis_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static struct ata_port_info sis_port_info = {
++ .sht = &sis_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x7,
++ .udma_mask = 0x7f,
++ .port_ops = &sis_ops,
++};
++
++
++MODULE_AUTHOR("Uwe Koziolek");
++MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
++{
++ unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
++
++ if (port_no) {
++ if (device == 0x182)
++ addr += SIS182_SATA1_OFS;
++ else
++ addr += SIS180_SATA1_OFS;
++ }
++
++ return addr;
++}
++
++static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
++ u32 val, val2 = 0;
++ u8 pmr;
++
++ if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
++ return 0xffffffff;
++
++ pci_read_config_byte(pdev, SIS_PMR, &pmr);
++
++ pci_read_config_dword(pdev, cfg_addr, &val);
++
++ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
++ pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
++
++ return val|val2;
++}
++
++static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
++ u8 pmr;
++
++ if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
++ return;
++
++ pci_read_config_byte(pdev, SIS_PMR, &pmr);
++
++ pci_write_config_dword(pdev, cfg_addr, val);
++
++ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
++ pci_write_config_dword(pdev, cfg_addr+0x10, val);
++}
++
++static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u32 val, val2 = 0;
++ u8 pmr;
++
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++
++ if (ap->flags & SIS_FLAG_CFGSCR)
++ return sis_scr_cfg_read(ap, sc_reg);
++
++ pci_read_config_byte(pdev, SIS_PMR, &pmr);
++
++ val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
++
++ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
++ val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
++
++ return val | val2;
++}
++
++static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ u8 pmr;
++
++ if (sc_reg > SCR_CONTROL)
++ return;
++
++ pci_read_config_byte(pdev, SIS_PMR, &pmr);
++
++ if (ap->flags & SIS_FLAG_CFGSCR)
++ sis_scr_cfg_write(ap, sc_reg, val);
++ else {
++ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
++ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
++ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
++ }
++}
++
++static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ int rc;
++ u32 genctl;
++ struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
++ int pci_dev_busy = 0;
++ u8 pmr;
++ u8 port2_start;
++
++ if (!printed_version++)
++ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ /* check and see if the SCRs are in IO space or PCI cfg space */
++ pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
++ if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
++ pi.flags |= SIS_FLAG_CFGSCR;
++
++ /* if hardware thinks SCRs are in IO space, but there are
++ * no IO resources assigned, change to PCI cfg space.
++ */
++ if ((!(pi.flags & SIS_FLAG_CFGSCR)) &&
++ ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
++ (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
++ genctl &= ~GENCTL_IOMAPPED_SCR;
++ pci_write_config_dword(pdev, SIS_GENCTL, genctl);
++ pi.flags |= SIS_FLAG_CFGSCR;
++ }
++
++ pci_read_config_byte(pdev, SIS_PMR, &pmr);
++ if (ent->device != 0x182) {
++ if ((pmr & SIS_PMR_COMBINED) == 0) {
++ dev_printk(KERN_INFO, &pdev->dev,
++ "Detected SiS 180/181 chipset in SATA mode\n");
++ port2_start = 64;
++ }
++ else {
++ dev_printk(KERN_INFO, &pdev->dev,
++ "Detected SiS 180/181 chipset in combined mode\n");
++ port2_start=0;
++ }
++ }
++ else {
++ dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n");
++ port2_start = 0x20;
++ }
++
++ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
++ if (!probe_ent) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
++ probe_ent->port[0].scr_addr =
++ pci_resource_start(pdev, SIS_SCR_PCI_BAR);
++ probe_ent->port[1].scr_addr =
++ pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
++ }
++
++ pci_set_master(pdev);
++ pci_intx(pdev, 1);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_regions:
++ pci_release_regions(pdev);
++
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++
++}
++
++static int __init sis_init(void)
++{
++ return pci_register_driver(&sis_pci_driver);
++}
++
++static void __exit sis_exit(void)
++{
++ pci_unregister_driver(&sis_pci_driver);
++}
++
++module_init(sis_init);
++module_exit(sis_exit);
++
+diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
+new file mode 100644
+index 0000000..db32d15
+--- /dev/null
++++ b/drivers/ata/sata_svw.c
+@@ -0,0 +1,505 @@
++/*
++ * sata_svw.c - ServerWorks / Apple K2 SATA
++ *
++ * Maintained by: Benjamin Herrenschmidt <benh at kernel.crashing.org> and
++ * Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003 Benjamin Herrenschmidt <benh at kernel.crashing.org>
++ *
++ * Bits from Jeff Garzik, Copyright RedHat, Inc.
++ *
++ * This driver probably works with non-Apple versions of the
++ * Broadcom chipset...
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available under NDA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#ifdef CONFIG_PPC_OF
++#include <asm/prom.h>
++#include <asm/pci-bridge.h>
++#endif /* CONFIG_PPC_OF */
++
++#define DRV_NAME "sata_svw"
++#define DRV_VERSION "2.0"
++
++enum {
++ /* Taskfile registers offsets */
++ K2_SATA_TF_CMD_OFFSET = 0x00,
++ K2_SATA_TF_DATA_OFFSET = 0x00,
++ K2_SATA_TF_ERROR_OFFSET = 0x04,
++ K2_SATA_TF_NSECT_OFFSET = 0x08,
++ K2_SATA_TF_LBAL_OFFSET = 0x0c,
++ K2_SATA_TF_LBAM_OFFSET = 0x10,
++ K2_SATA_TF_LBAH_OFFSET = 0x14,
++ K2_SATA_TF_DEVICE_OFFSET = 0x18,
++ K2_SATA_TF_CMDSTAT_OFFSET = 0x1c,
++ K2_SATA_TF_CTL_OFFSET = 0x20,
++
++ /* DMA base */
++ K2_SATA_DMA_CMD_OFFSET = 0x30,
++
++ /* SCRs base */
++ K2_SATA_SCR_STATUS_OFFSET = 0x40,
++ K2_SATA_SCR_ERROR_OFFSET = 0x44,
++ K2_SATA_SCR_CONTROL_OFFSET = 0x48,
++
++ /* Others */
++ K2_SATA_SICR1_OFFSET = 0x80,
++ K2_SATA_SICR2_OFFSET = 0x84,
++ K2_SATA_SIM_OFFSET = 0x88,
++
++ /* Port stride */
++ K2_SATA_PORT_OFFSET = 0x100,
++};
++
++static u8 k2_stat_check_status(struct ata_port *ap);
++
++
++static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++ return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++
++static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
++ u32 val)
++{
++ if (sc_reg > SCR_CONTROL)
++ return;
++ writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++
++static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
++
++ if (tf->ctl != ap->last_ctl) {
++ writeb(tf->ctl, ioaddr->ctl_addr);
++ ap->last_ctl = tf->ctl;
++ ata_wait_idle(ap);
++ }
++ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
++ writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
++ writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
++ writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
++ writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
++ writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
++ } else if (is_addr) {
++ writew(tf->feature, ioaddr->feature_addr);
++ writew(tf->nsect, ioaddr->nsect_addr);
++ writew(tf->lbal, ioaddr->lbal_addr);
++ writew(tf->lbam, ioaddr->lbam_addr);
++ writew(tf->lbah, ioaddr->lbah_addr);
++ }
++
++ if (tf->flags & ATA_TFLAG_DEVICE)
++ writeb(tf->device, ioaddr->device_addr);
++
++ ata_wait_idle(ap);
++}
++
++
++static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ u16 nsect, lbal, lbam, lbah, feature;
++
++ tf->command = k2_stat_check_status(ap);
++ tf->device = readw(ioaddr->device_addr);
++ feature = readw(ioaddr->error_addr);
++ nsect = readw(ioaddr->nsect_addr);
++ lbal = readw(ioaddr->lbal_addr);
++ lbam = readw(ioaddr->lbam_addr);
++ lbah = readw(ioaddr->lbah_addr);
++
++ tf->feature = feature;
++ tf->nsect = nsect;
++ tf->lbal = lbal;
++ tf->lbam = lbam;
++ tf->lbah = lbah;
++
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ tf->hob_feature = feature >> 8;
++ tf->hob_nsect = nsect >> 8;
++ tf->hob_lbal = lbal >> 8;
++ tf->hob_lbam = lbam >> 8;
++ tf->hob_lbah = lbah >> 8;
++ }
++}
++
++/**
++ * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
++ * @qc: Info associated with this ATA transaction.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
++ u8 dmactl;
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++ /* load PRD table addr. */
++ mb(); /* make sure PRD table writes are visible to controller */
++ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
++
++ /* specify data direction, triple-check start bit is clear */
++ dmactl = readb(mmio + ATA_DMA_CMD);
++ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
++ if (!rw)
++ dmactl |= ATA_DMA_WR;
++ writeb(dmactl, mmio + ATA_DMA_CMD);
++
++ /* issue r/w command if this is not a ATA DMA command*/
++ if (qc->tf.protocol != ATA_PROT_DMA)
++ ap->ops->exec_command(ap, &qc->tf);
++}
++
++/**
++ * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
++ * @qc: Info associated with this ATA transaction.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ */
++
++static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++ u8 dmactl;
++
++ /* start host DMA transaction */
++ dmactl = readb(mmio + ATA_DMA_CMD);
++ writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
++ /* There is a race condition in certain SATA controllers that can
++ be seen when the r/w command is given to the controller before the
++ host DMA is started. On a Read command, the controller would initiate
++ the command to the drive even before it sees the DMA start. When there
++ are very fast drives connected to the controller, or when the data request
++ hits in the drive cache, there is the possibility that the drive returns a part
++ or all of the requested data to the controller before the DMA start is issued.
++ In this case, the controller would become confused as to what to do with the data.
++ In the worst case when all the data is returned back to the controller, the
++ controller could hang. In other cases it could return partial data returning
++ in data corruption. This problem has been seen in PPC systems and can also appear
++ on an system with very fast disks, where the SATA controller is sitting behind a
++ number of bridges, and hence there is significant latency between the r/w command
++ and the start command. */
++ /* issue r/w command if the access is to ATA*/
++ if (qc->tf.protocol == ATA_PROT_DMA)
++ ap->ops->exec_command(ap, &qc->tf);
++}
++
++
++static u8 k2_stat_check_status(struct ata_port *ap)
++{
++ return readl((void *) ap->ioaddr.status_addr);
++}
++
++#ifdef CONFIG_PPC_OF
++/*
++ * k2_sata_proc_info
++ * inout : decides on the direction of the dataflow and the meaning of the
++ * variables
++ * buffer: If inout==FALSE data is being written to it else read from it
++ * *start: If inout==FALSE start of the valid data in the buffer
++ * offset: If inout==FALSE offset from the beginning of the imaginary file
++ * from which we start writing into the buffer
++ * length: If inout==FALSE max number of bytes to be written into the buffer
++ * else number of bytes in the buffer
++ */
++static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
++ off_t offset, int count, int inout)
++{
++ struct ata_port *ap;
++ struct device_node *np;
++ int len, index;
++
++ /* Find the ata_port */
++ ap = ata_shost_to_port(shost);
++ if (ap == NULL)
++ return 0;
++
++ /* Find the OF node for the PCI device proper */
++ np = pci_device_to_OF_node(to_pci_dev(ap->host->dev));
++ if (np == NULL)
++ return 0;
++
++ /* Match it to a port node */
++ index = (ap == ap->host->ports[0]) ? 0 : 1;
++ for (np = np->child; np != NULL; np = np->sibling) {
++ const u32 *reg = get_property(np, "reg", NULL);
++ if (!reg)
++ continue;
++ if (index == *reg)
++ break;
++ }
++ if (np == NULL)
++ return 0;
++
++ len = sprintf(page, "devspec: %s\n", np->full_name);
++
++ return len;
++}
++#endif /* CONFIG_PPC_OF */
++
++
++static struct scsi_host_template k2_sata_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++#ifdef CONFIG_PPC_OF
++ .proc_info = k2_sata_proc_info,
++#endif
++ .bios_param = ata_std_bios_param,
++};
++
++
++static const struct ata_port_operations k2_sata_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = k2_sata_tf_load,
++ .tf_read = k2_sata_tf_read,
++ .check_status = k2_stat_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++ .bmdma_setup = k2_bmdma_setup_mmio,
++ .bmdma_start = k2_bmdma_start_mmio,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = k2_sata_scr_read,
++ .scr_write = k2_sata_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
++ port->data_addr = base + K2_SATA_TF_DATA_OFFSET;
++ port->feature_addr =
++ port->error_addr = base + K2_SATA_TF_ERROR_OFFSET;
++ port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET;
++ port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET;
++ port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET;
++ port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET;
++ port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET;
++ port->command_addr =
++ port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET;
++ port->altstatus_addr =
++ port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET;
++ port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET;
++ port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET;
++}
++
++
++static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ unsigned long base;
++ void __iomem *mmio_base;
++ int pci_dev_busy = 0;
++ int rc;
++ int i;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ /*
++ * If this driver happens to only be useful on Apple's K2, then
++ * we should check that here as it has a normal Serverworks ID
++ */
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++ /*
++ * Check if we have resources mapped at all (second function may
++ * have been disabled by firmware)
++ */
++ if (pci_resource_len(pdev, 5) == 0)
++ return -ENODEV;
++
++ /* Request PCI regions */
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, 5, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++ base = (unsigned long) mmio_base;
++
++ /* Clear a magic bit in SCR1 according to Darwin, those help
++ * some funky seagate drives (though so far, those were already
++ * set by the firmware on the machines I had access to)
++ */
++ writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
++ mmio_base + K2_SATA_SICR1_OFFSET);
++
++ /* Clear SATA error & interrupts we don't use */
++ writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
++ writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
++
++ probe_ent->sht = &k2_sata_sht;
++ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_MMIO;
++ probe_ent->port_ops = &k2_sata_ops;
++ probe_ent->n_ports = 4;
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++
++ /* We don't care much about the PIO/UDMA masks, but the core won't like us
++ * if we don't fill these
++ */
++ probe_ent->pio_mask = 0x1f;
++ probe_ent->mwdma_mask = 0x7;
++ probe_ent->udma_mask = 0x7f;
++
++ /* different controllers have different number of ports - currently 4 or 8 */
++ /* All ports are on the same function. Multi-function device is no
++ * longer available. This should not be seen in any system. */
++ for (i = 0; i < ent->driver_data; i++)
++ k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
++
++ pci_set_master(pdev);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++/* 0x240 is device ID for Apple K2 device
++ * 0x241 is device ID for Serverworks Frodo4
++ * 0x242 is device ID for Serverworks Frodo8
++ * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA
++ * controller
++ * */
++static const struct pci_device_id k2_sata_pci_tbl[] = {
++ { PCI_VDEVICE(SERVERWORKS, 0x0240), 4 },
++ { PCI_VDEVICE(SERVERWORKS, 0x0241), 4 },
++ { PCI_VDEVICE(SERVERWORKS, 0x0242), 8 },
++ { PCI_VDEVICE(SERVERWORKS, 0x024a), 4 },
++ { PCI_VDEVICE(SERVERWORKS, 0x024b), 4 },
++
++ { }
++};
++
++static struct pci_driver k2_sata_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = k2_sata_pci_tbl,
++ .probe = k2_sata_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init k2_sata_init(void)
++{
++ return pci_register_driver(&k2_sata_pci_driver);
++}
++
++static void __exit k2_sata_exit(void)
++{
++ pci_unregister_driver(&k2_sata_pci_driver);
++}
++
++MODULE_AUTHOR("Benjamin Herrenschmidt");
++MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(k2_sata_init);
++module_exit(k2_sata_exit);
+diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
+new file mode 100644
+index 0000000..ae7992d
+--- /dev/null
++++ b/drivers/ata/sata_sx4.c
+@@ -0,0 +1,1501 @@
++/*
++ * sata_sx4.c - Promise SATA
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2003-2004 Red Hat, Inc.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available under NDA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++#include "sata_promise.h"
++
++#define DRV_NAME "sata_sx4"
++#define DRV_VERSION "0.9"
++
++
++enum {
++ PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
++
++ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
++ PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
++ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
++ PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
++
++ PDC_20621_SEQCTL = 0x400,
++ PDC_20621_SEQMASK = 0x480,
++ PDC_20621_GENERAL_CTL = 0x484,
++ PDC_20621_PAGE_SIZE = (32 * 1024),
++
++ /* chosen, not constant, values; we design our own DIMM mem map */
++ PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
++ PDC_20621_DIMM_BASE = 0x00200000,
++ PDC_20621_DIMM_DATA = (64 * 1024),
++ PDC_DIMM_DATA_STEP = (256 * 1024),
++ PDC_DIMM_WINDOW_STEP = (8 * 1024),
++ PDC_DIMM_HOST_PRD = (6 * 1024),
++ PDC_DIMM_HOST_PKT = (128 * 0),
++ PDC_DIMM_HPKT_PRD = (128 * 1),
++ PDC_DIMM_ATA_PKT = (128 * 2),
++ PDC_DIMM_APKT_PRD = (128 * 3),
++ PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
++ PDC_PAGE_WINDOW = 0x40,
++ PDC_PAGE_DATA = PDC_PAGE_WINDOW +
++ (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
++ PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
++
++ PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
++
++ PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
++ (1<<23),
++
++ board_20621 = 0, /* FastTrak S150 SX4 */
++
++ PDC_RESET = (1 << 11), /* HDMA reset */
++
++ PDC_MAX_HDMA = 32,
++ PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
++
++ PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
++ PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
++ PDC_MAX_DIMM_MODULE = 0x02,
++ PDC_I2C_CONTROL_OFFSET = 0x48,
++ PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
++ PDC_DIMM0_CONTROL_OFFSET = 0x80,
++ PDC_DIMM1_CONTROL_OFFSET = 0x84,
++ PDC_SDRAM_CONTROL_OFFSET = 0x88,
++ PDC_I2C_WRITE = 0x00000000,
++ PDC_I2C_READ = 0x00000040,
++ PDC_I2C_START = 0x00000080,
++ PDC_I2C_MASK_INT = 0x00000020,
++ PDC_I2C_COMPLETE = 0x00010000,
++ PDC_I2C_NO_ACK = 0x00100000,
++ PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
++ PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
++ PDC_DIMM_SPD_ROW_NUM = 3,
++ PDC_DIMM_SPD_COLUMN_NUM = 4,
++ PDC_DIMM_SPD_MODULE_ROW = 5,
++ PDC_DIMM_SPD_TYPE = 11,
++ PDC_DIMM_SPD_FRESH_RATE = 12,
++ PDC_DIMM_SPD_BANK_NUM = 17,
++ PDC_DIMM_SPD_CAS_LATENCY = 18,
++ PDC_DIMM_SPD_ATTRIBUTE = 21,
++ PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
++ PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
++ PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
++ PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
++ PDC_DIMM_SPD_SYSTEM_FREQ = 126,
++ PDC_CTL_STATUS = 0x08,
++ PDC_DIMM_WINDOW_CTLR = 0x0C,
++ PDC_TIME_CONTROL = 0x3C,
++ PDC_TIME_PERIOD = 0x40,
++ PDC_TIME_COUNTER = 0x44,
++ PDC_GENERAL_CTLR = 0x484,
++ PCI_PLL_INIT = 0x8A531824,
++ PCI_X_TCOUNT = 0xEE1E5CFF
++};
++
++
++struct pdc_port_priv {
++ u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
++ u8 *pkt;
++ dma_addr_t pkt_dma;
++};
++
++struct pdc_host_priv {
++ void __iomem *dimm_mmio;
++
++ unsigned int doing_hdma;
++ unsigned int hdma_prod;
++ unsigned int hdma_cons;
++ struct {
++ struct ata_queued_cmd *qc;
++ unsigned int seq;
++ unsigned long pkt_ofs;
++ } hdma[32];
++};
++
++
++static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance);
++static void pdc_eng_timeout(struct ata_port *ap);
++static void pdc_20621_phy_reset (struct ata_port *ap);
++static int pdc_port_start(struct ata_port *ap);
++static void pdc_port_stop(struct ata_port *ap);
++static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
++static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
++static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
++static void pdc20621_host_stop(struct ata_host *host);
++static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
++static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
++static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
++ u32 device, u32 subaddr, u32 *pdata);
++static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
++static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
++#ifdef ATA_VERBOSE_DEBUG
++static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
++ void *psource, u32 offset, u32 size);
++#endif
++static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
++ void *psource, u32 offset, u32 size);
++static void pdc20621_irq_clear(struct ata_port *ap);
++static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
++
++
++static struct scsi_host_template pdc_sata_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations pdc_20621_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = pdc_tf_load_mmio,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = pdc_exec_command_mmio,
++ .dev_select = ata_std_dev_select,
++ .phy_reset = pdc_20621_phy_reset,
++ .qc_prep = pdc20621_qc_prep,
++ .qc_issue = pdc20621_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++ .eng_timeout = pdc_eng_timeout,
++ .irq_handler = pdc20621_interrupt,
++ .irq_clear = pdc20621_irq_clear,
++ .port_start = pdc_port_start,
++ .port_stop = pdc_port_stop,
++ .host_stop = pdc20621_host_stop,
++};
++
++static const struct ata_port_info pdc_port_info[] = {
++ /* board_20621 */
++ {
++ .sht = &pdc_sata_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_SRST | ATA_FLAG_MMIO |
++ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .mwdma_mask = 0x07, /* mwdma0-2 */
++ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
++ .port_ops = &pdc_20621_ops,
++ },
++
++};
++
++static const struct pci_device_id pdc_sata_pci_tbl[] = {
++ { PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver pdc_sata_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = pdc_sata_pci_tbl,
++ .probe = pdc_sata_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++
++static void pdc20621_host_stop(struct ata_host *host)
++{
++ struct pci_dev *pdev = to_pci_dev(host->dev);
++ struct pdc_host_priv *hpriv = host->private_data;
++ void __iomem *dimm_mmio = hpriv->dimm_mmio;
++
++ pci_iounmap(pdev, dimm_mmio);
++ kfree(hpriv);
++
++ pci_iounmap(pdev, host->mmio_base);
++}
++
++static int pdc_port_start(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct pdc_port_priv *pp;
++ int rc;
++
++ rc = ata_port_start(ap);
++ if (rc)
++ return rc;
++
++ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
++ if (!pp) {
++ rc = -ENOMEM;
++ goto err_out;
++ }
++ memset(pp, 0, sizeof(*pp));
++
++ pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
++ if (!pp->pkt) {
++ rc = -ENOMEM;
++ goto err_out_kfree;
++ }
++
++ ap->private_data = pp;
++
++ return 0;
++
++err_out_kfree:
++ kfree(pp);
++err_out:
++ ata_port_stop(ap);
++ return rc;
++}
++
++
++static void pdc_port_stop(struct ata_port *ap)
++{
++ struct device *dev = ap->host->dev;
++ struct pdc_port_priv *pp = ap->private_data;
++
++ ap->private_data = NULL;
++ dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
++ kfree(pp);
++ ata_port_stop(ap);
++}
++
++
++static void pdc_20621_phy_reset (struct ata_port *ap)
++{
++ VPRINTK("ENTER\n");
++ ap->cbl = ATA_CBL_SATA;
++ ata_port_probe(ap);
++ ata_bus_reset(ap);
++}
++
++static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
++ unsigned int portno,
++ unsigned int total_len)
++{
++ u32 addr;
++ unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
++ u32 *buf32 = (u32 *) buf;
++
++ /* output ATA packet S/G table */
++ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
++ (PDC_DIMM_DATA_STEP * portno);
++ VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
++ buf32[dw] = cpu_to_le32(addr);
++ buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
++
++ VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
++ PDC_20621_DIMM_BASE +
++ (PDC_DIMM_WINDOW_STEP * portno) +
++ PDC_DIMM_APKT_PRD,
++ buf32[dw], buf32[dw + 1]);
++}
++
++static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
++ unsigned int portno,
++ unsigned int total_len)
++{
++ u32 addr;
++ unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
++ u32 *buf32 = (u32 *) buf;
++
++ /* output Host DMA packet S/G table */
++ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
++ (PDC_DIMM_DATA_STEP * portno);
++
++ buf32[dw] = cpu_to_le32(addr);
++ buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
++
++ VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
++ PDC_20621_DIMM_BASE +
++ (PDC_DIMM_WINDOW_STEP * portno) +
++ PDC_DIMM_HPKT_PRD,
++ buf32[dw], buf32[dw + 1]);
++}
++
++static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
++ unsigned int devno, u8 *buf,
++ unsigned int portno)
++{
++ unsigned int i, dw;
++ u32 *buf32 = (u32 *) buf;
++ u8 dev_reg;
++
++ unsigned int dimm_sg = PDC_20621_DIMM_BASE +
++ (PDC_DIMM_WINDOW_STEP * portno) +
++ PDC_DIMM_APKT_PRD;
++ VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
++
++ i = PDC_DIMM_ATA_PKT;
++
++ /*
++ * Set up ATA packet
++ */
++ if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
++ buf[i++] = PDC_PKT_READ;
++ else if (tf->protocol == ATA_PROT_NODATA)
++ buf[i++] = PDC_PKT_NODATA;
++ else
++ buf[i++] = 0;
++ buf[i++] = 0; /* reserved */
++ buf[i++] = portno + 1; /* seq. id */
++ buf[i++] = 0xff; /* delay seq. id */
++
++ /* dimm dma S/G, and next-pkt */
++ dw = i >> 2;
++ if (tf->protocol == ATA_PROT_NODATA)
++ buf32[dw] = 0;
++ else
++ buf32[dw] = cpu_to_le32(dimm_sg);
++ buf32[dw + 1] = 0;
++ i += 8;
++
++ if (devno == 0)
++ dev_reg = ATA_DEVICE_OBS;
++ else
++ dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
++
++ /* select device */
++ buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
++ buf[i++] = dev_reg;
++
++ /* device control register */
++ buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
++ buf[i++] = tf->ctl;
++
++ return i;
++}
++
++static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
++ unsigned int portno)
++{
++ unsigned int dw;
++ u32 tmp, *buf32 = (u32 *) buf;
++
++ unsigned int host_sg = PDC_20621_DIMM_BASE +
++ (PDC_DIMM_WINDOW_STEP * portno) +
++ PDC_DIMM_HOST_PRD;
++ unsigned int dimm_sg = PDC_20621_DIMM_BASE +
++ (PDC_DIMM_WINDOW_STEP * portno) +
++ PDC_DIMM_HPKT_PRD;
++ VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
++ VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
++
++ dw = PDC_DIMM_HOST_PKT >> 2;
++
++ /*
++ * Set up Host DMA packet
++ */
++ if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
++ tmp = PDC_PKT_READ;
++ else
++ tmp = 0;
++ tmp |= ((portno + 1 + 4) << 16); /* seq. id */
++ tmp |= (0xff << 24); /* delay seq. id */
++ buf32[dw + 0] = cpu_to_le32(tmp);
++ buf32[dw + 1] = cpu_to_le32(host_sg);
++ buf32[dw + 2] = cpu_to_le32(dimm_sg);
++ buf32[dw + 3] = 0;
++
++ VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
++ PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
++ PDC_DIMM_HOST_PKT,
++ buf32[dw + 0],
++ buf32[dw + 1],
++ buf32[dw + 2],
++ buf32[dw + 3]);
++}
++
++static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
++{
++ struct scatterlist *sg;
++ struct ata_port *ap = qc->ap;
++ struct pdc_port_priv *pp = ap->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++ struct pdc_host_priv *hpriv = ap->host->private_data;
++ void __iomem *dimm_mmio = hpriv->dimm_mmio;
++ unsigned int portno = ap->port_no;
++ unsigned int i, idx, total_len = 0, sgt_len;
++ u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
++
++ WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
++
++ VPRINTK("ata%u: ENTER\n", ap->id);
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ /*
++ * Build S/G table
++ */
++ idx = 0;
++ ata_for_each_sg(sg, qc) {
++ buf[idx++] = cpu_to_le32(sg_dma_address(sg));
++ buf[idx++] = cpu_to_le32(sg_dma_len(sg));
++ total_len += sg_dma_len(sg);
++ }
++ buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
++ sgt_len = idx * 4;
++
++ /*
++ * Build ATA, host DMA packets
++ */
++ pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
++ pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
++
++ pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
++ i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
++
++ if (qc->tf.flags & ATA_TFLAG_LBA48)
++ i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
++ else
++ i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
++
++ pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
++
++ /* copy three S/G tables and two packets to DIMM MMIO window */
++ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
++ &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
++ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
++ PDC_DIMM_HOST_PRD,
++ &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
++
++ /* force host FIFO dump */
++ writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
++
++ readl(dimm_mmio); /* MMIO PCI posting flush */
++
++ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
++}
++
++static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pdc_port_priv *pp = ap->private_data;
++ void __iomem *mmio = ap->host->mmio_base;
++ struct pdc_host_priv *hpriv = ap->host->private_data;
++ void __iomem *dimm_mmio = hpriv->dimm_mmio;
++ unsigned int portno = ap->port_no;
++ unsigned int i;
++
++ VPRINTK("ata%u: ENTER\n", ap->id);
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
++
++ if (qc->tf.flags & ATA_TFLAG_LBA48)
++ i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
++ else
++ i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
++
++ pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
++
++ /* copy three S/G tables and two packets to DIMM MMIO window */
++ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
++ &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
++
++ /* force host FIFO dump */
++ writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
++
++ readl(dimm_mmio); /* MMIO PCI posting flush */
++
++ VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
++}
++
++static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
++{
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ pdc20621_dma_prep(qc);
++ break;
++ case ATA_PROT_NODATA:
++ pdc20621_nodata_prep(qc);
++ break;
++ default:
++ break;
++ }
++}
++
++static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
++ unsigned int seq,
++ u32 pkt_ofs)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_host *host = ap->host;
++ void __iomem *mmio = host->mmio_base;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
++ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
++
++ writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
++ readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
++}
++
++static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
++ unsigned int seq,
++ u32 pkt_ofs)
++{
++ struct ata_port *ap = qc->ap;
++ struct pdc_host_priv *pp = ap->host->private_data;
++ unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
++
++ if (!pp->doing_hdma) {
++ __pdc20621_push_hdma(qc, seq, pkt_ofs);
++ pp->doing_hdma = 1;
++ return;
++ }
++
++ pp->hdma[idx].qc = qc;
++ pp->hdma[idx].seq = seq;
++ pp->hdma[idx].pkt_ofs = pkt_ofs;
++ pp->hdma_prod++;
++}
++
++static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct pdc_host_priv *pp = ap->host->private_data;
++ unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
++
++ /* if nothing on queue, we're done */
++ if (pp->hdma_prod == pp->hdma_cons) {
++ pp->doing_hdma = 0;
++ return;
++ }
++
++ __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
++ pp->hdma[idx].pkt_ofs);
++ pp->hdma_cons++;
++}
++
++#ifdef ATA_VERBOSE_DEBUG
++static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ unsigned int port_no = ap->port_no;
++ struct pdc_host_priv *hpriv = ap->host->private_data;
++ void *dimm_mmio = hpriv->dimm_mmio;
++
++ dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
++ dimm_mmio += PDC_DIMM_HOST_PKT;
++
++ printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
++ printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
++ printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
++ printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
++}
++#else
++static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
++#endif /* ATA_VERBOSE_DEBUG */
++
++static void pdc20621_packet_start(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ata_host *host = ap->host;
++ unsigned int port_no = ap->port_no;
++ void __iomem *mmio = host->mmio_base;
++ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
++ u8 seq = (u8) (port_no + 1);
++ unsigned int port_ofs;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ VPRINTK("ata%u: ENTER\n", ap->id);
++
++ wmb(); /* flush PRD, pkt writes */
++
++ port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
++
++ /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
++ if (rw && qc->tf.protocol == ATA_PROT_DMA) {
++ seq += 4;
++
++ pdc20621_dump_hdma(qc);
++ pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
++ VPRINTK("queued ofs 0x%x (%u), seq %u\n",
++ port_ofs + PDC_DIMM_HOST_PKT,
++ port_ofs + PDC_DIMM_HOST_PKT,
++ seq);
++ } else {
++ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
++ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
++
++ writel(port_ofs + PDC_DIMM_ATA_PKT,
++ (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
++ readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
++ VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
++ port_ofs + PDC_DIMM_ATA_PKT,
++ port_ofs + PDC_DIMM_ATA_PKT,
++ seq);
++ }
++}
++
++static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ case ATA_PROT_NODATA:
++ pdc20621_packet_start(qc);
++ return 0;
++
++ case ATA_PROT_ATAPI_DMA:
++ BUG();
++ break;
++
++ default:
++ break;
++ }
++
++ return ata_qc_issue_prot(qc);
++}
++
++static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
++ struct ata_queued_cmd *qc,
++ unsigned int doing_hdma,
++ void __iomem *mmio)
++{
++ unsigned int port_no = ap->port_no;
++ unsigned int port_ofs =
++ PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
++ u8 status;
++ unsigned int handled = 0;
++
++ VPRINTK("ENTER\n");
++
++ if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
++ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
++
++ /* step two - DMA from DIMM to host */
++ if (doing_hdma) {
++ VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
++ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
++ /* get drive status; clear intr; complete txn */
++ qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
++ ata_qc_complete(qc);
++ pdc20621_pop_hdma(qc);
++ }
++
++ /* step one - exec ATA command */
++ else {
++ u8 seq = (u8) (port_no + 1 + 4);
++ VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
++ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
++
++ /* submit hdma pkt */
++ pdc20621_dump_hdma(qc);
++ pdc20621_push_hdma(qc, seq,
++ port_ofs + PDC_DIMM_HOST_PKT);
++ }
++ handled = 1;
++
++ } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
++
++ /* step one - DMA from host to DIMM */
++ if (doing_hdma) {
++ u8 seq = (u8) (port_no + 1);
++ VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
++ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
++
++ /* submit ata pkt */
++ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
++ readl(mmio + PDC_20621_SEQCTL + (seq * 4));
++ writel(port_ofs + PDC_DIMM_ATA_PKT,
++ (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
++ readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
++ }
++
++ /* step two - execute ATA command */
++ else {
++ VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
++ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
++ /* get drive status; clear intr; complete txn */
++ qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
++ ata_qc_complete(qc);
++ pdc20621_pop_hdma(qc);
++ }
++ handled = 1;
++
++ /* command completion, but no data xfer */
++ } else if (qc->tf.protocol == ATA_PROT_NODATA) {
++
++ status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
++ DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
++ qc->err_mask |= ac_err_mask(status);
++ ata_qc_complete(qc);
++ handled = 1;
++
++ } else {
++ ap->stats.idle_irq++;
++ }
++
++ return handled;
++}
++
++static void pdc20621_irq_clear(struct ata_port *ap)
++{
++ struct ata_host *host = ap->host;
++ void __iomem *mmio = host->mmio_base;
++
++ mmio += PDC_CHIP0_OFS;
++
++ readl(mmio + PDC_20621_SEQMASK);
++}
++
++static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ struct ata_port *ap;
++ u32 mask = 0;
++ unsigned int i, tmp, port_no;
++ unsigned int handled = 0;
++ void __iomem *mmio_base;
++
++ VPRINTK("ENTER\n");
++
++ if (!host || !host->mmio_base) {
++ VPRINTK("QUICK EXIT\n");
++ return IRQ_NONE;
++ }
++
++ mmio_base = host->mmio_base;
++
++ /* reading should also clear interrupts */
++ mmio_base += PDC_CHIP0_OFS;
++ mask = readl(mmio_base + PDC_20621_SEQMASK);
++ VPRINTK("mask == 0x%x\n", mask);
++
++ if (mask == 0xffffffff) {
++ VPRINTK("QUICK EXIT 2\n");
++ return IRQ_NONE;
++ }
++ mask &= 0xffff; /* only 16 tags possible */
++ if (!mask) {
++ VPRINTK("QUICK EXIT 3\n");
++ return IRQ_NONE;
++ }
++
++ spin_lock(&host->lock);
++
++ for (i = 1; i < 9; i++) {
++ port_no = i - 1;
++ if (port_no > 3)
++ port_no -= 4;
++ if (port_no >= host->n_ports)
++ ap = NULL;
++ else
++ ap = host->ports[port_no];
++ tmp = mask & (1 << i);
++ VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
++ if (tmp && ap &&
++ !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
++ handled += pdc20621_host_intr(ap, qc, (i > 4),
++ mmio_base);
++ }
++ }
++
++ spin_unlock(&host->lock);
++
++ VPRINTK("mask == 0x%x\n", mask);
++
++ VPRINTK("EXIT\n");
++
++ return IRQ_RETVAL(handled);
++}
++
++static void pdc_eng_timeout(struct ata_port *ap)
++{
++ u8 drv_stat;
++ struct ata_host *host = ap->host;
++ struct ata_queued_cmd *qc;
++ unsigned long flags;
++
++ DPRINTK("ENTER\n");
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ case ATA_PROT_NODATA:
++ ata_port_printk(ap, KERN_ERR, "command timeout\n");
++ qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
++ break;
++
++ default:
++ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
++
++ ata_port_printk(ap, KERN_ERR,
++ "unknown timeout, cmd 0x%x stat 0x%x\n",
++ qc->tf.command, drv_stat);
++
++ qc->err_mask |= ac_err_mask(drv_stat);
++ break;
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ ata_eh_qc_complete(qc);
++ DPRINTK("EXIT\n");
++}
++
++static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ WARN_ON (tf->protocol == ATA_PROT_DMA ||
++ tf->protocol == ATA_PROT_NODATA);
++ ata_tf_load(ap, tf);
++}
++
++
++static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ WARN_ON (tf->protocol == ATA_PROT_DMA ||
++ tf->protocol == ATA_PROT_NODATA);
++ ata_exec_command(ap, tf);
++}
++
++
++static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr = base;
++ port->data_addr = base;
++ port->feature_addr =
++ port->error_addr = base + 0x4;
++ port->nsect_addr = base + 0x8;
++ port->lbal_addr = base + 0xc;
++ port->lbam_addr = base + 0x10;
++ port->lbah_addr = base + 0x14;
++ port->device_addr = base + 0x18;
++ port->command_addr =
++ port->status_addr = base + 0x1c;
++ port->altstatus_addr =
++ port->ctl_addr = base + 0x38;
++}
++
++
++#ifdef ATA_VERBOSE_DEBUG
++static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
++ u32 offset, u32 size)
++{
++ u32 window_size;
++ u16 idx;
++ u8 page_mask;
++ long dist;
++ void __iomem *mmio = pe->mmio_base;
++ struct pdc_host_priv *hpriv = pe->private_data;
++ void __iomem *dimm_mmio = hpriv->dimm_mmio;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ page_mask = 0x00;
++ window_size = 0x2000 * 4; /* 32K byte uchar size */
++ idx = (u16) (offset / window_size);
++
++ writel(0x01, mmio + PDC_GENERAL_CTLR);
++ readl(mmio + PDC_GENERAL_CTLR);
++ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
++ readl(mmio + PDC_DIMM_WINDOW_CTLR);
++
++ offset -= (idx * window_size);
++ idx++;
++ dist = ((long) (window_size - (offset + size))) >= 0 ? size :
++ (long) (window_size - offset);
++ memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
++ dist);
++
++ psource += dist;
++ size -= dist;
++ for (; (long) size >= (long) window_size ;) {
++ writel(0x01, mmio + PDC_GENERAL_CTLR);
++ readl(mmio + PDC_GENERAL_CTLR);
++ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
++ readl(mmio + PDC_DIMM_WINDOW_CTLR);
++ memcpy_fromio((char *) psource, (char *) (dimm_mmio),
++ window_size / 4);
++ psource += window_size;
++ size -= window_size;
++ idx ++;
++ }
++
++ if (size) {
++ writel(0x01, mmio + PDC_GENERAL_CTLR);
++ readl(mmio + PDC_GENERAL_CTLR);
++ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
++ readl(mmio + PDC_DIMM_WINDOW_CTLR);
++ memcpy_fromio((char *) psource, (char *) (dimm_mmio),
++ size / 4);
++ }
++}
++#endif
++
++
++static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
++ u32 offset, u32 size)
++{
++ u32 window_size;
++ u16 idx;
++ u8 page_mask;
++ long dist;
++ void __iomem *mmio = pe->mmio_base;
++ struct pdc_host_priv *hpriv = pe->private_data;
++ void __iomem *dimm_mmio = hpriv->dimm_mmio;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ page_mask = 0x00;
++ window_size = 0x2000 * 4; /* 32K byte uchar size */
++ idx = (u16) (offset / window_size);
++
++ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
++ readl(mmio + PDC_DIMM_WINDOW_CTLR);
++ offset -= (idx * window_size);
++ idx++;
++ dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
++ (long) (window_size - offset);
++ memcpy_toio(dimm_mmio + offset / 4, psource, dist);
++ writel(0x01, mmio + PDC_GENERAL_CTLR);
++ readl(mmio + PDC_GENERAL_CTLR);
++
++ psource += dist;
++ size -= dist;
++ for (; (long) size >= (long) window_size ;) {
++ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
++ readl(mmio + PDC_DIMM_WINDOW_CTLR);
++ memcpy_toio(dimm_mmio, psource, window_size / 4);
++ writel(0x01, mmio + PDC_GENERAL_CTLR);
++ readl(mmio + PDC_GENERAL_CTLR);
++ psource += window_size;
++ size -= window_size;
++ idx ++;
++ }
++
++ if (size) {
++ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
++ readl(mmio + PDC_DIMM_WINDOW_CTLR);
++ memcpy_toio(dimm_mmio, psource, size / 4);
++ writel(0x01, mmio + PDC_GENERAL_CTLR);
++ readl(mmio + PDC_GENERAL_CTLR);
++ }
++}
++
++
++static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
++ u32 subaddr, u32 *pdata)
++{
++ void __iomem *mmio = pe->mmio_base;
++ u32 i2creg = 0;
++ u32 status;
++ u32 count =0;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ i2creg |= device << 24;
++ i2creg |= subaddr << 16;
++
++ /* Set the device and subaddress */
++ writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
++ readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
++
++ /* Write Control to perform read operation, mask int */
++ writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
++ mmio + PDC_I2C_CONTROL_OFFSET);
++
++ for (count = 0; count <= 1000; count ++) {
++ status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
++ if (status & PDC_I2C_COMPLETE) {
++ status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
++ break;
++ } else if (count == 1000)
++ return 0;
++ }
++
++ *pdata = (status >> 8) & 0x000000ff;
++ return 1;
++}
++
++
++static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
++{
++ u32 data=0 ;
++ if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
++ PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
++ if (data == 100)
++ return 100;
++ } else
++ return 0;
++
++ if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
++ if(data <= 0x75)
++ return 133;
++ } else
++ return 0;
++
++ return 0;
++}
++
++
++static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
++{
++ u32 spd0[50];
++ u32 data = 0;
++ int size, i;
++ u8 bdimmsize;
++ void __iomem *mmio = pe->mmio_base;
++ static const struct {
++ unsigned int reg;
++ unsigned int ofs;
++ } pdc_i2c_read_data [] = {
++ { PDC_DIMM_SPD_TYPE, 11 },
++ { PDC_DIMM_SPD_FRESH_RATE, 12 },
++ { PDC_DIMM_SPD_COLUMN_NUM, 4 },
++ { PDC_DIMM_SPD_ATTRIBUTE, 21 },
++ { PDC_DIMM_SPD_ROW_NUM, 3 },
++ { PDC_DIMM_SPD_BANK_NUM, 17 },
++ { PDC_DIMM_SPD_MODULE_ROW, 5 },
++ { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
++ { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
++ { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
++ { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
++ { PDC_DIMM_SPD_CAS_LATENCY, 18 },
++ };
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
++ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
++ pdc_i2c_read_data[i].reg,
++ &spd0[pdc_i2c_read_data[i].ofs]);
++
++ data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
++ data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
++ ((((spd0[27] + 9) / 10) - 1) << 8) ;
++ data |= (((((spd0[29] > spd0[28])
++ ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
++ data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
++
++ if (spd0[18] & 0x08)
++ data |= ((0x03) << 14);
++ else if (spd0[18] & 0x04)
++ data |= ((0x02) << 14);
++ else if (spd0[18] & 0x01)
++ data |= ((0x01) << 14);
++ else
++ data |= (0 << 14);
++
++ /*
++ Calculate the size of bDIMMSize (power of 2) and
++ merge the DIMM size by program start/end address.
++ */
++
++ bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
++ size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
++ data |= (((size / 16) - 1) << 16);
++ data |= (0 << 23);
++ data |= 8;
++ writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
++ readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
++ return size;
++}
++
++
++static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
++{
++ u32 data, spd0;
++ int error, i;
++ void __iomem *mmio = pe->mmio_base;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ /*
++ Set To Default : DIMM Module Global Control Register (0x022259F1)
++ DIMM Arbitration Disable (bit 20)
++ DIMM Data/Control Output Driving Selection (bit12 - bit15)
++ Refresh Enable (bit 17)
++ */
++
++ data = 0x022259F1;
++ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
++ readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
++
++ /* Turn on for ECC */
++ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
++ PDC_DIMM_SPD_TYPE, &spd0);
++ if (spd0 == 0x02) {
++ data |= (0x01 << 16);
++ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
++ readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
++ printk(KERN_ERR "Local DIMM ECC Enabled\n");
++ }
++
++ /* DIMM Initialization Select/Enable (bit 18/19) */
++ data &= (~(1<<18));
++ data |= (1<<19);
++ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
++
++ error = 1;
++ for (i = 1; i <= 10; i++) { /* polling ~5 secs */
++ data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
++ if (!(data & (1<<19))) {
++ error = 0;
++ break;
++ }
++ msleep(i*100);
++ }
++ return error;
++}
++
++
++static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
++{
++ int speed, size, length;
++ u32 addr,spd0,pci_status;
++ u32 tmp=0;
++ u32 time_period=0;
++ u32 tcount=0;
++ u32 ticks=0;
++ u32 clock=0;
++ u32 fparam=0;
++ void __iomem *mmio = pe->mmio_base;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ /* Initialize PLL based upon PCI Bus Frequency */
++
++ /* Initialize Time Period Register */
++ writel(0xffffffff, mmio + PDC_TIME_PERIOD);
++ time_period = readl(mmio + PDC_TIME_PERIOD);
++ VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
++
++ /* Enable timer */
++ writel(0x00001a0, mmio + PDC_TIME_CONTROL);
++ readl(mmio + PDC_TIME_CONTROL);
++
++ /* Wait 3 seconds */
++ msleep(3000);
++
++ /*
++ When timer is enabled, counter is decreased every internal
++ clock cycle.
++ */
++
++ tcount = readl(mmio + PDC_TIME_COUNTER);
++ VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
++
++ /*
++ If SX4 is on PCI-X bus, after 3 seconds, the timer counter
++ register should be >= (0xffffffff - 3x10^8).
++ */
++ if(tcount >= PCI_X_TCOUNT) {
++ ticks = (time_period - tcount);
++ VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
++
++ clock = (ticks / 300000);
++ VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
++
++ clock = (clock * 33);
++ VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
++
++ /* PLL F Param (bit 22:16) */
++ fparam = (1400000 / clock) - 2;
++ VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
++
++ /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
++ pci_status = (0x8a001824 | (fparam << 16));
++ } else
++ pci_status = PCI_PLL_INIT;
++
++ /* Initialize PLL. */
++ VPRINTK("pci_status: 0x%x\n", pci_status);
++ writel(pci_status, mmio + PDC_CTL_STATUS);
++ readl(mmio + PDC_CTL_STATUS);
++
++ /*
++ Read SPD of DIMM by I2C interface,
++ and program the DIMM Module Controller.
++ */
++ if (!(speed = pdc20621_detect_dimm(pe))) {
++ printk(KERN_ERR "Detect Local DIMM Fail\n");
++ return 1; /* DIMM error */
++ }
++ VPRINTK("Local DIMM Speed = %d\n", speed);
++
++ /* Programming DIMM0 Module Control Register (index_CID0:80h) */
++ size = pdc20621_prog_dimm0(pe);
++ VPRINTK("Local DIMM Size = %dMB\n",size);
++
++ /* Programming DIMM Module Global Control Register (index_CID0:88h) */
++ if (pdc20621_prog_dimm_global(pe)) {
++ printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
++ return 1;
++ }
++
++#ifdef ATA_VERBOSE_DEBUG
++ {
++ u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
++ 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
++ '1','.','1','0',
++ '9','8','0','3','1','6','1','2',0,0};
++ u8 test_parttern2[40] = {0};
++
++ pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
++ pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
++
++ pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
++ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
++ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
++ test_parttern2[1], &(test_parttern2[2]));
++ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
++ 40);
++ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
++ test_parttern2[1], &(test_parttern2[2]));
++
++ pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
++ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
++ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
++ test_parttern2[1], &(test_parttern2[2]));
++ }
++#endif
++
++ /* ECC initiliazation. */
++
++ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
++ PDC_DIMM_SPD_TYPE, &spd0);
++ if (spd0 == 0x02) {
++ VPRINTK("Start ECC initialization\n");
++ addr = 0;
++ length = size * 1024 * 1024;
++ while (addr < length) {
++ pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
++ sizeof(u32));
++ addr += sizeof(u32);
++ }
++ VPRINTK("Finish ECC initialization\n");
++ }
++ return 0;
++}
++
++
++static void pdc_20621_init(struct ata_probe_ent *pe)
++{
++ u32 tmp;
++ void __iomem *mmio = pe->mmio_base;
++
++ /* hard-code chip #0 */
++ mmio += PDC_CHIP0_OFS;
++
++ /*
++ * Select page 0x40 for our 32k DIMM window
++ */
++ tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
++ tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
++ writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
++
++ /*
++ * Reset Host DMA
++ */
++ tmp = readl(mmio + PDC_HDMA_CTLSTAT);
++ tmp |= PDC_RESET;
++ writel(tmp, mmio + PDC_HDMA_CTLSTAT);
++ readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
++
++ udelay(10);
++
++ tmp = readl(mmio + PDC_HDMA_CTLSTAT);
++ tmp &= ~PDC_RESET;
++ writel(tmp, mmio + PDC_HDMA_CTLSTAT);
++ readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
++}
++
++static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ unsigned long base;
++ void __iomem *mmio_base;
++ void __iomem *dimm_mmio = NULL;
++ struct pdc_host_priv *hpriv = NULL;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++ int pci_dev_busy = 0;
++ int rc;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, 3, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++ base = (unsigned long) mmio_base;
++
++ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
++ if (!hpriv) {
++ rc = -ENOMEM;
++ goto err_out_iounmap;
++ }
++ memset(hpriv, 0, sizeof(*hpriv));
++
++ dimm_mmio = pci_iomap(pdev, 4, 0);
++ if (!dimm_mmio) {
++ kfree(hpriv);
++ rc = -ENOMEM;
++ goto err_out_iounmap;
++ }
++
++ hpriv->dimm_mmio = dimm_mmio;
++
++ probe_ent->sht = pdc_port_info[board_idx].sht;
++ probe_ent->port_flags = pdc_port_info[board_idx].flags;
++ probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
++ probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
++ probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
++ probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
++
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++
++ probe_ent->private_data = hpriv;
++ base += PDC_CHIP0_OFS;
++
++ probe_ent->n_ports = 4;
++ pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
++ pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
++ pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
++ pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
++
++ pci_set_master(pdev);
++
++ /* initialize adapter */
++ /* initialize local dimm */
++ if (pdc20621_dimm_init(probe_ent)) {
++ rc = -ENOMEM;
++ goto err_out_iounmap_dimm;
++ }
++ pdc_20621_init(probe_ent);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_iounmap_dimm: /* only get to this label if 20621 */
++ kfree(hpriv);
++ pci_iounmap(pdev, dimm_mmio);
++err_out_iounmap:
++ pci_iounmap(pdev, mmio_base);
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++
++static int __init pdc_sata_init(void)
++{
++ return pci_register_driver(&pdc_sata_pci_driver);
++}
++
++
++static void __exit pdc_sata_exit(void)
++{
++ pci_unregister_driver(&pdc_sata_pci_driver);
++}
++
++
++MODULE_AUTHOR("Jeff Garzik");
++MODULE_DESCRIPTION("Promise SATA low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(pdc_sata_init);
++module_exit(pdc_sata_exit);
+diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
+new file mode 100644
+index 0000000..5c603ca
+--- /dev/null
++++ b/drivers/ata/sata_uli.c
+@@ -0,0 +1,300 @@
++/*
++ * sata_uli.c - ULi Electronics SATA
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available under NDA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sata_uli"
++#define DRV_VERSION "1.0"
++
++enum {
++ uli_5289 = 0,
++ uli_5287 = 1,
++ uli_5281 = 2,
++
++ uli_max_ports = 4,
++
++ /* PCI configuration registers */
++ ULI5287_BASE = 0x90, /* sata0 phy SCR registers */
++ ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */
++ ULI5281_BASE = 0x60, /* sata0 phy SCR registers */
++ ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */
++};
++
++struct uli_priv {
++ unsigned int scr_cfg_addr[uli_max_ports];
++};
++
++static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++
++static const struct pci_device_id uli_pci_tbl[] = {
++ { PCI_VDEVICE(AL, 0x5289), uli_5289 },
++ { PCI_VDEVICE(AL, 0x5287), uli_5287 },
++ { PCI_VDEVICE(AL, 0x5281), uli_5281 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver uli_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = uli_pci_tbl,
++ .probe = uli_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static struct scsi_host_template uli_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations uli_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .scr_read = uli_scr_read,
++ .scr_write = uli_scr_write,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static struct ata_port_info uli_port_info = {
++ .sht = &uli_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
++ .pio_mask = 0x1f, /* pio0-4 */
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &uli_ops,
++};
++
++
++MODULE_AUTHOR("Peer Chen");
++MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
++{
++ struct uli_priv *hpriv = ap->host->private_data;
++ return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
++}
++
++static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
++ u32 val;
++
++ pci_read_config_dword(pdev, cfg_addr, &val);
++ return val;
++}
++
++static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
++{
++ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
++ unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
++
++ pci_write_config_dword(pdev, cfg_addr, val);
++}
++
++static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++
++ return uli_scr_cfg_read(ap, sc_reg);
++}
++
++static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++ if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
++ return;
++
++ uli_scr_cfg_write(ap, sc_reg, val);
++}
++
++static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent;
++ struct ata_port_info *ppi[2];
++ int rc;
++ unsigned int board_idx = (unsigned int) ent->driver_data;
++ int pci_dev_busy = 0;
++ struct uli_priv *hpriv;
++
++ if (!printed_version++)
++ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ ppi[0] = ppi[1] = &uli_port_info;
++ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
++ if (!probe_ent) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
++ if (!hpriv) {
++ rc = -ENOMEM;
++ goto err_out_probe_ent;
++ }
++
++ probe_ent->private_data = hpriv;
++
++ switch (board_idx) {
++ case uli_5287:
++ hpriv->scr_cfg_addr[0] = ULI5287_BASE;
++ hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
++ probe_ent->n_ports = 4;
++
++ probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
++ probe_ent->port[2].altstatus_addr =
++ probe_ent->port[2].ctl_addr =
++ (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
++ probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
++ hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
++
++ probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
++ probe_ent->port[3].altstatus_addr =
++ probe_ent->port[3].ctl_addr =
++ (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
++ probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
++ hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
++
++ ata_std_ports(&probe_ent->port[2]);
++ ata_std_ports(&probe_ent->port[3]);
++ break;
++
++ case uli_5289:
++ hpriv->scr_cfg_addr[0] = ULI5287_BASE;
++ hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
++ break;
++
++ case uli_5281:
++ hpriv->scr_cfg_addr[0] = ULI5281_BASE;
++ hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS;
++ break;
++
++ default:
++ BUG();
++ break;
++ }
++
++ pci_set_master(pdev);
++ pci_intx(pdev, 1);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_probe_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++
++}
++
++static int __init uli_init(void)
++{
++ return pci_register_driver(&uli_pci_driver);
++}
++
++static void __exit uli_exit(void)
++{
++ pci_unregister_driver(&uli_pci_driver);
++}
++
++
++module_init(uli_init);
++module_exit(uli_exit);
+diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
+new file mode 100644
+index 0000000..f4455a1
+--- /dev/null
++++ b/drivers/ata/sata_via.c
+@@ -0,0 +1,503 @@
++/*
++ * sata_via.c - VIA Serial ATA controllers
++ *
++ * Maintained by: Jeff Garzik <jgarzik at pobox.com>
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ on emails.
++ *
++ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
++ * Copyright 2003-2004 Jeff Garzik
++ *
++ *
++ * 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Hardware documentation available under NDA.
++ *
++ *
++ * To-do list:
++ * - VT6421 PATA support
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++#include <asm/io.h>
++
++#define DRV_NAME "sata_via"
++#define DRV_VERSION "2.0"
++
++enum board_ids_enum {
++ vt6420,
++ vt6421,
++};
++
++enum {
++ SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
++ SATA_INT_GATE = 0x41, /* SATA interrupt gating */
++ SATA_NATIVE_MODE = 0x42, /* Native mode enable */
++ SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
++
++ PORT0 = (1 << 1),
++ PORT1 = (1 << 0),
++ ALL_PORTS = PORT0 | PORT1,
++ N_PORTS = 2,
++
++ NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
++
++ SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
++ SATA_2DEV = (1 << 5), /* SATA is master/slave */
++};
++
++static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++static void vt6420_error_handler(struct ata_port *ap);
++
++static const struct pci_device_id svia_pci_tbl[] = {
++ { PCI_VDEVICE(VIA, 0x0591), vt6420 },
++ { PCI_VDEVICE(VIA, 0x3149), vt6420 },
++ { PCI_VDEVICE(VIA, 0x3249), vt6421 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver svia_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = svia_pci_tbl,
++ .probe = svia_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static struct scsi_host_template svia_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++static const struct ata_port_operations vt6420_sata_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = vt6420_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static const struct ata_port_operations vt6421_sata_ops = {
++ .port_disable = ata_port_disable,
++
++ .tf_load = ata_tf_load,
++ .tf_read = ata_tf_read,
++ .check_status = ata_check_status,
++ .exec_command = ata_exec_command,
++ .dev_select = ata_std_dev_select,
++
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_pio_data_xfer,
++
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++
++ .irq_handler = ata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++
++ .scr_read = svia_scr_read,
++ .scr_write = svia_scr_write,
++
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_host_stop,
++};
++
++static struct ata_port_info vt6420_port_info = {
++ .sht = &svia_sht,
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
++ .pio_mask = 0x1f,
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f,
++ .port_ops = &vt6420_sata_ops,
++};
++
++MODULE_AUTHOR("Jeff Garzik");
++MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++ return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
++}
++
++static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++ if (sc_reg > SCR_CONTROL)
++ return;
++ outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
++}
++
++/**
++ * vt6420_prereset - prereset for vt6420
++ * @ap: target ATA port
++ *
++ * SCR registers on vt6420 are pieces of shit and may hang the
++ * whole machine completely if accessed with the wrong timing.
++ * To avoid such catastrophe, vt6420 doesn't provide generic SCR
++ * access operations, but uses SStatus and SControl only during
++ * boot probing in controlled way.
++ *
++ * As the old (pre EH update) probing code is proven to work, we
++ * strictly follow the access pattern.
++ *
++ * LOCKING:
++ * Kernel thread context (may sleep)
++ *
++ * RETURNS:
++ * 0 on success, -errno otherwise.
++ */
++static int vt6420_prereset(struct ata_port *ap)
++{
++ struct ata_eh_context *ehc = &ap->eh_context;
++ unsigned long timeout = jiffies + (HZ * 5);
++ u32 sstatus, scontrol;
++ int online;
++
++ /* don't do any SCR stuff if we're not loading */
++ if (!ATA_PFLAG_LOADING)
++ goto skip_scr;
++
++ /* Resume phy. This is the old resume sequence from
++ * __sata_phy_reset().
++ */
++ svia_scr_write(ap, SCR_CONTROL, 0x300);
++ svia_scr_read(ap, SCR_CONTROL); /* flush */
++
++ /* wait for phy to become ready, if necessary */
++ do {
++ msleep(200);
++ if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
++ break;
++ } while (time_before(jiffies, timeout));
++
++ /* open code sata_print_link_status() */
++ sstatus = svia_scr_read(ap, SCR_STATUS);
++ scontrol = svia_scr_read(ap, SCR_CONTROL);
++
++ online = (sstatus & 0xf) == 0x3;
++
++ ata_port_printk(ap, KERN_INFO,
++ "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
++ online ? "up" : "down", sstatus, scontrol);
++
++ /* SStatus is read one more time */
++ svia_scr_read(ap, SCR_STATUS);
++
++ if (!online) {
++ /* tell EH to bail */
++ ehc->i.action &= ~ATA_EH_RESET_MASK;
++ return 0;
++ }
++
++ skip_scr:
++ /* wait for !BSY */
++ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
++
++ return 0;
++}
++
++static void vt6420_error_handler(struct ata_port *ap)
++{
++ return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset,
++ NULL, ata_std_postreset);
++}
++
++static const unsigned int svia_bar_sizes[] = {
++ 8, 4, 8, 4, 16, 256
++};
++
++static const unsigned int vt6421_bar_sizes[] = {
++ 16, 16, 16, 16, 32, 128
++};
++
++static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
++{
++ return addr + (port * 128);
++}
++
++static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
++{
++ return addr + (port * 64);
++}
++
++static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
++ struct pci_dev *pdev,
++ unsigned int port)
++{
++ unsigned long reg_addr = pci_resource_start(pdev, port);
++ unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
++ unsigned long scr_addr;
++
++ probe_ent->port[port].cmd_addr = reg_addr;
++ probe_ent->port[port].altstatus_addr =
++ probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
++ probe_ent->port[port].bmdma_addr = bmdma_addr;
++
++ scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
++ probe_ent->port[port].scr_addr = scr_addr;
++
++ ata_std_ports(&probe_ent->port[port]);
++}
++
++static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
++{
++ struct ata_probe_ent *probe_ent;
++ struct ata_port_info *ppi[2];
++
++ ppi[0] = ppi[1] = &vt6420_port_info;
++ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
++ if (!probe_ent)
++ return NULL;
++
++ probe_ent->port[0].scr_addr =
++ svia_scr_addr(pci_resource_start(pdev, 5), 0);
++ probe_ent->port[1].scr_addr =
++ svia_scr_addr(pci_resource_start(pdev, 5), 1);
++
++ return probe_ent;
++}
++
++static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
++{
++ struct ata_probe_ent *probe_ent;
++ unsigned int i;
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (!probe_ent)
++ return NULL;
++
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ probe_ent->sht = &svia_sht;
++ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
++ probe_ent->port_ops = &vt6421_sata_ops;
++ probe_ent->n_ports = N_PORTS;
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->pio_mask = 0x1f;
++ probe_ent->mwdma_mask = 0x07;
++ probe_ent->udma_mask = 0x7f;
++
++ for (i = 0; i < N_PORTS; i++)
++ vt6421_init_addrs(probe_ent, pdev, i);
++
++ return probe_ent;
++}
++
++static void svia_configure(struct pci_dev *pdev)
++{
++ u8 tmp8;
++
++ pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
++ dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n",
++ (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
++
++ /* make sure SATA channels are enabled */
++ pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
++ if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "enabling SATA channels (0x%x)\n",
++ (int) tmp8);
++ tmp8 |= ALL_PORTS;
++ pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
++ }
++
++ /* make sure interrupts for each channel sent to us */
++ pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
++ if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "enabling SATA channel interrupts (0x%x)\n",
++ (int) tmp8);
++ tmp8 |= ALL_PORTS;
++ pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
++ }
++
++ /* make sure native mode is enabled */
++ pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
++ if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
++ dev_printk(KERN_DEBUG, &pdev->dev,
++ "enabling SATA channel native mode (0x%x)\n",
++ (int) tmp8);
++ tmp8 |= NATIVE_MODE_ALL;
++ pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
++ }
++}
++
++static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ unsigned int i;
++ int rc;
++ struct ata_probe_ent *probe_ent;
++ int board_id = (int) ent->driver_data;
++ const int *bar_sizes;
++ int pci_dev_busy = 0;
++ u8 tmp8;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ if (board_id == vt6420) {
++ pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
++ if (tmp8 & SATA_2DEV) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "SATA master/slave not supported (0x%x)\n",
++ (int) tmp8);
++ rc = -EIO;
++ goto err_out_regions;
++ }
++
++ bar_sizes = &svia_bar_sizes[0];
++ } else {
++ bar_sizes = &vt6421_bar_sizes[0];
++ }
++
++ for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
++ if ((pci_resource_start(pdev, i) == 0) ||
++ (pci_resource_len(pdev, i) < bar_sizes[i])) {
++ dev_printk(KERN_ERR, &pdev->dev,
++ "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
++ i,
++ (unsigned long long)pci_resource_start(pdev, i),
++ (unsigned long long)pci_resource_len(pdev, i));
++ rc = -ENODEV;
++ goto err_out_regions;
++ }
++
++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ if (board_id == vt6420)
++ probe_ent = vt6420_init_probe_ent(pdev);
++ else
++ probe_ent = vt6421_init_probe_ent(pdev);
++
++ if (!probe_ent) {
++ dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++
++ svia_configure(pdev);
++
++ pci_set_master(pdev);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++static int __init svia_init(void)
++{
++ return pci_register_driver(&svia_pci_driver);
++}
++
++static void __exit svia_exit(void)
++{
++ pci_unregister_driver(&svia_pci_driver);
++}
++
++module_init(svia_init);
++module_exit(svia_exit);
++
+diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
+new file mode 100644
+index 0000000..e654b99
+--- /dev/null
++++ b/drivers/ata/sata_vsc.c
+@@ -0,0 +1,477 @@
++/*
++ * sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
++ *
++ * Maintained by: Jeremy Higdon @ SGI
++ * Please ALWAYS copy linux-ide at vger.kernel.org
++ * on emails.
++ *
++ * Copyright 2004 SGI
++ *
++ * Bits from Jeff Garzik, Copyright RedHat, 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, 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; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * libata documentation is available via 'make {ps|pdf}docs',
++ * as Documentation/DocBook/libata.*
++ *
++ * Vitesse hardware documentation presumably available under NDA.
++ * Intel 31244 (same hardware interface) documentation presumably
++ * available from http://developer.intel.com/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <linux/libata.h>
++
++#define DRV_NAME "sata_vsc"
++#define DRV_VERSION "2.0"
++
++enum {
++ /* Interrupt register offsets (from chip base address) */
++ VSC_SATA_INT_STAT_OFFSET = 0x00,
++ VSC_SATA_INT_MASK_OFFSET = 0x04,
++
++ /* Taskfile registers offsets */
++ VSC_SATA_TF_CMD_OFFSET = 0x00,
++ VSC_SATA_TF_DATA_OFFSET = 0x00,
++ VSC_SATA_TF_ERROR_OFFSET = 0x04,
++ VSC_SATA_TF_FEATURE_OFFSET = 0x06,
++ VSC_SATA_TF_NSECT_OFFSET = 0x08,
++ VSC_SATA_TF_LBAL_OFFSET = 0x0c,
++ VSC_SATA_TF_LBAM_OFFSET = 0x10,
++ VSC_SATA_TF_LBAH_OFFSET = 0x14,
++ VSC_SATA_TF_DEVICE_OFFSET = 0x18,
++ VSC_SATA_TF_STATUS_OFFSET = 0x1c,
++ VSC_SATA_TF_COMMAND_OFFSET = 0x1d,
++ VSC_SATA_TF_ALTSTATUS_OFFSET = 0x28,
++ VSC_SATA_TF_CTL_OFFSET = 0x29,
++
++ /* DMA base */
++ VSC_SATA_UP_DESCRIPTOR_OFFSET = 0x64,
++ VSC_SATA_UP_DATA_BUFFER_OFFSET = 0x6C,
++ VSC_SATA_DMA_CMD_OFFSET = 0x70,
++
++ /* SCRs base */
++ VSC_SATA_SCR_STATUS_OFFSET = 0x100,
++ VSC_SATA_SCR_ERROR_OFFSET = 0x104,
++ VSC_SATA_SCR_CONTROL_OFFSET = 0x108,
++
++ /* Port stride */
++ VSC_SATA_PORT_OFFSET = 0x200,
++
++ /* Error interrupt status bit offsets */
++ VSC_SATA_INT_ERROR_CRC = 0x40,
++ VSC_SATA_INT_ERROR_T = 0x20,
++ VSC_SATA_INT_ERROR_P = 0x10,
++ VSC_SATA_INT_ERROR_R = 0x8,
++ VSC_SATA_INT_ERROR_E = 0x4,
++ VSC_SATA_INT_ERROR_M = 0x2,
++ VSC_SATA_INT_PHY_CHANGE = 0x1,
++ VSC_SATA_INT_ERROR = (VSC_SATA_INT_ERROR_CRC | VSC_SATA_INT_ERROR_T | \
++ VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \
++ VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \
++ VSC_SATA_INT_PHY_CHANGE),
++};
++
++
++#define is_vsc_sata_int_err(port_idx, int_status) \
++ (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
++
++
++static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++ if (sc_reg > SCR_CONTROL)
++ return 0xffffffffU;
++ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++
++static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
++ u32 val)
++{
++ if (sc_reg > SCR_CONTROL)
++ return;
++ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
++}
++
++
++static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
++{
++ void __iomem *mask_addr;
++ u8 mask;
++
++ mask_addr = ap->host->mmio_base +
++ VSC_SATA_INT_MASK_OFFSET + ap->port_no;
++ mask = readb(mask_addr);
++ if (ctl & ATA_NIEN)
++ mask |= 0x80;
++ else
++ mask &= 0x7F;
++ writeb(mask, mask_addr);
++}
++
++
++static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
++
++ /*
++ * The only thing the ctl register is used for is SRST.
++ * That is not enabled or disabled via tf_load.
++ * However, if ATA_NIEN is changed, then we need to change the interrupt register.
++ */
++ if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
++ ap->last_ctl = tf->ctl;
++ vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
++ }
++ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
++ writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
++ writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
++ writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
++ writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
++ writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
++ } else if (is_addr) {
++ writew(tf->feature, ioaddr->feature_addr);
++ writew(tf->nsect, ioaddr->nsect_addr);
++ writew(tf->lbal, ioaddr->lbal_addr);
++ writew(tf->lbam, ioaddr->lbam_addr);
++ writew(tf->lbah, ioaddr->lbah_addr);
++ }
++
++ if (tf->flags & ATA_TFLAG_DEVICE)
++ writeb(tf->device, ioaddr->device_addr);
++
++ ata_wait_idle(ap);
++}
++
++
++static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct ata_ioports *ioaddr = &ap->ioaddr;
++ u16 nsect, lbal, lbam, lbah, feature;
++
++ tf->command = ata_check_status(ap);
++ tf->device = readw(ioaddr->device_addr);
++ feature = readw(ioaddr->error_addr);
++ nsect = readw(ioaddr->nsect_addr);
++ lbal = readw(ioaddr->lbal_addr);
++ lbam = readw(ioaddr->lbam_addr);
++ lbah = readw(ioaddr->lbah_addr);
++
++ tf->feature = feature;
++ tf->nsect = nsect;
++ tf->lbal = lbal;
++ tf->lbam = lbam;
++ tf->lbah = lbah;
++
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ tf->hob_feature = feature >> 8;
++ tf->hob_nsect = nsect >> 8;
++ tf->hob_lbal = lbal >> 8;
++ tf->hob_lbam = lbam >> 8;
++ tf->hob_lbah = lbah >> 8;
++ }
++}
++
++
++/*
++ * vsc_sata_interrupt
++ *
++ * Read the interrupt register and process for the devices that have them pending.
++ */
++static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
++{
++ struct ata_host *host = dev_instance;
++ unsigned int i;
++ unsigned int handled = 0;
++ u32 int_status;
++
++ spin_lock(&host->lock);
++
++ int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET);
++
++ for (i = 0; i < host->n_ports; i++) {
++ if (int_status & ((u32) 0xFF << (8 * i))) {
++ struct ata_port *ap;
++
++ ap = host->ports[i];
++
++ if (is_vsc_sata_int_err(i, int_status)) {
++ u32 err_status;
++ printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
++ err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
++ vsc_sata_scr_write(ap, SCR_ERROR, err_status);
++ handled++;
++ }
++
++ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
++ struct ata_queued_cmd *qc;
++
++ qc = ata_qc_from_tag(ap, ap->active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
++ handled += ata_host_intr(ap, qc);
++ else if (is_vsc_sata_int_err(i, int_status)) {
++ /*
++ * On some chips (i.e. Intel 31244), an error
++ * interrupt will sneak in at initialization
++ * time (phy state changes). Clearing the SCR
++ * error register is not required, but it prevents
++ * the phy state change interrupts from recurring
++ * later.
++ */
++ u32 err_status;
++ err_status = vsc_sata_scr_read(ap, SCR_ERROR);
++ printk(KERN_DEBUG "%s: clearing interrupt, "
++ "status %x; sata err status %x\n",
++ __FUNCTION__,
++ int_status, err_status);
++ vsc_sata_scr_write(ap, SCR_ERROR, err_status);
++ /* Clear interrupt status */
++ ata_chk_status(ap);
++ handled++;
++ }
++ }
++ }
++ }
++
++ spin_unlock(&host->lock);
++
++ return IRQ_RETVAL(handled);
++}
++
++
++static struct scsi_host_template vsc_sata_sht = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .ioctl = ata_scsi_ioctl,
++ .queuecommand = ata_scsi_queuecmd,
++ .can_queue = ATA_DEF_QUEUE,
++ .this_id = ATA_SHT_THIS_ID,
++ .sg_tablesize = LIBATA_MAX_PRD,
++ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
++ .emulated = ATA_SHT_EMULATED,
++ .use_clustering = ATA_SHT_USE_CLUSTERING,
++ .proc_name = DRV_NAME,
++ .dma_boundary = ATA_DMA_BOUNDARY,
++ .slave_configure = ata_scsi_slave_config,
++ .slave_destroy = ata_scsi_slave_destroy,
++ .bios_param = ata_std_bios_param,
++};
++
++
++static const struct ata_port_operations vsc_sata_ops = {
++ .port_disable = ata_port_disable,
++ .tf_load = vsc_sata_tf_load,
++ .tf_read = vsc_sata_tf_read,
++ .exec_command = ata_exec_command,
++ .check_status = ata_check_status,
++ .dev_select = ata_std_dev_select,
++ .bmdma_setup = ata_bmdma_setup,
++ .bmdma_start = ata_bmdma_start,
++ .bmdma_stop = ata_bmdma_stop,
++ .bmdma_status = ata_bmdma_status,
++ .qc_prep = ata_qc_prep,
++ .qc_issue = ata_qc_issue_prot,
++ .data_xfer = ata_mmio_data_xfer,
++ .freeze = ata_bmdma_freeze,
++ .thaw = ata_bmdma_thaw,
++ .error_handler = ata_bmdma_error_handler,
++ .post_internal_cmd = ata_bmdma_post_internal_cmd,
++ .irq_handler = vsc_sata_interrupt,
++ .irq_clear = ata_bmdma_irq_clear,
++ .scr_read = vsc_sata_scr_read,
++ .scr_write = vsc_sata_scr_write,
++ .port_start = ata_port_start,
++ .port_stop = ata_port_stop,
++ .host_stop = ata_pci_host_stop,
++};
++
++static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++ port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
++ port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
++ port->error_addr = base + VSC_SATA_TF_ERROR_OFFSET;
++ port->feature_addr = base + VSC_SATA_TF_FEATURE_OFFSET;
++ port->nsect_addr = base + VSC_SATA_TF_NSECT_OFFSET;
++ port->lbal_addr = base + VSC_SATA_TF_LBAL_OFFSET;
++ port->lbam_addr = base + VSC_SATA_TF_LBAM_OFFSET;
++ port->lbah_addr = base + VSC_SATA_TF_LBAH_OFFSET;
++ port->device_addr = base + VSC_SATA_TF_DEVICE_OFFSET;
++ port->status_addr = base + VSC_SATA_TF_STATUS_OFFSET;
++ port->command_addr = base + VSC_SATA_TF_COMMAND_OFFSET;
++ port->altstatus_addr = base + VSC_SATA_TF_ALTSTATUS_OFFSET;
++ port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET;
++ port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET;
++ port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET;
++ writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
++ writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
++}
++
++
++static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ static int printed_version;
++ struct ata_probe_ent *probe_ent = NULL;
++ unsigned long base;
++ int pci_dev_busy = 0;
++ void __iomem *mmio_base;
++ int rc;
++
++ if (!printed_version++)
++ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
++
++ rc = pci_enable_device(pdev);
++ if (rc)
++ return rc;
++
++ /*
++ * Check if we have needed resource mapped.
++ */
++ if (pci_resource_len(pdev, 0) == 0) {
++ rc = -ENODEV;
++ goto err_out;
++ }
++
++ rc = pci_request_regions(pdev, DRV_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ /*
++ * Use 32 bit DMA mask, because 64 bit address support is poor.
++ */
++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc)
++ goto err_out_regions;
++ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ if (rc)
++ goto err_out_regions;
++
++ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++ if (probe_ent == NULL) {
++ rc = -ENOMEM;
++ goto err_out_regions;
++ }
++ memset(probe_ent, 0, sizeof(*probe_ent));
++ probe_ent->dev = pci_dev_to_dev(pdev);
++ INIT_LIST_HEAD(&probe_ent->node);
++
++ mmio_base = pci_iomap(pdev, 0, 0);
++ if (mmio_base == NULL) {
++ rc = -ENOMEM;
++ goto err_out_free_ent;
++ }
++ base = (unsigned long) mmio_base;
++
++ /*
++ * Due to a bug in the chip, the default cache line size can't be used
++ */
++ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
++
++ probe_ent->sht = &vsc_sata_sht;
++ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++ ATA_FLAG_MMIO;
++ probe_ent->port_ops = &vsc_sata_ops;
++ probe_ent->n_ports = 4;
++ probe_ent->irq = pdev->irq;
++ probe_ent->irq_flags = IRQF_SHARED;
++ probe_ent->mmio_base = mmio_base;
++
++ /* We don't care much about the PIO/UDMA masks, but the core won't like us
++ * if we don't fill these
++ */
++ probe_ent->pio_mask = 0x1f;
++ probe_ent->mwdma_mask = 0x07;
++ probe_ent->udma_mask = 0x7f;
++
++ /* We have 4 ports per PCI function */
++ vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
++ vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
++ vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
++ vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
++
++ pci_set_master(pdev);
++
++ /*
++ * Config offset 0x98 is "Extended Control and Status Register 0"
++ * Default value is (1 << 28). All bits except bit 28 are reserved in
++ * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity.
++ * If bit 28 is clear, each port has its own LED.
++ */
++ pci_write_config_dword(pdev, 0x98, 0);
++
++ /* FIXME: check ata_device_add return value */
++ ata_device_add(probe_ent);
++ kfree(probe_ent);
++
++ return 0;
++
++err_out_free_ent:
++ kfree(probe_ent);
++err_out_regions:
++ pci_release_regions(pdev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(pdev);
++ return rc;
++}
++
++static const struct pci_device_id vsc_sata_pci_tbl[] = {
++ { PCI_VENDOR_ID_VITESSE, 0x7174,
++ PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
++ { PCI_VENDOR_ID_INTEL, 0x3200,
++ PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
++
++ { } /* terminate list */
++};
++
++static struct pci_driver vsc_sata_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = vsc_sata_pci_tbl,
++ .probe = vsc_sata_init_one,
++ .remove = ata_pci_remove_one,
++};
++
++static int __init vsc_sata_init(void)
++{
++ return pci_register_driver(&vsc_sata_pci_driver);
++}
++
++static void __exit vsc_sata_exit(void)
++{
++ pci_unregister_driver(&vsc_sata_pci_driver);
++}
++
++MODULE_AUTHOR("Jeremy Higdon");
++MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(vsc_sata_init);
++module_exit(vsc_sata_exit);
+diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
+index 6cc93de..ac2c108 100644
+--- a/drivers/atm/adummy.c
++++ b/drivers/atm/adummy.c
+@@ -113,15 +113,13 @@ static int __init adummy_init(void)
+
+ printk(KERN_ERR "adummy: version %s\n", DRV_VERSION);
+
+- adummy_dev = (struct adummy_dev *) kmalloc(sizeof(struct adummy_dev),
++ adummy_dev = kzalloc(sizeof(struct adummy_dev),
+ GFP_KERNEL);
+ if (!adummy_dev) {
+- printk(KERN_ERR DEV_LABEL ": kmalloc() failed\n");
++ printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n");
+ err = -ENOMEM;
+ goto out;
+ }
+- memset(adummy_dev, 0, sizeof(struct adummy_dev));
+-
+ atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL);
+ if (!atm_dev) {
+ printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
+diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
+index 4521a24..9fffa7a 100644
+--- a/drivers/atm/ambassador.c
++++ b/drivers/atm/ambassador.c
+@@ -861,18 +861,11 @@ static inline void interrupts_off (amb_d
+
+ /********** interrupt handling **********/
+
+-static irqreturn_t interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *pt_regs) {
+- amb_dev * dev = (amb_dev *) dev_id;
+- (void) pt_regs;
++static irqreturn_t interrupt_handler(int irq, void *dev_id) {
++ amb_dev * dev = dev_id;
+
+ PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
+
+- if (!dev_id) {
+- PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq);
+- return IRQ_NONE;
+- }
+-
+ {
+ u32 interrupt = rd_plain (dev, offsetof(amb_mem, interrupt));
+
+@@ -915,8 +908,8 @@ static irqreturn_t interrupt_handler(int
+
+ /********** make rate (not quite as much fun as Horizon) **********/
+
+-static unsigned int make_rate (unsigned int rate, rounding r,
+- u16 * bits, unsigned int * actual) {
++static int make_rate (unsigned int rate, rounding r,
++ u16 * bits, unsigned int * actual) {
+ unsigned char exp = -1; // hush gcc
+ unsigned int man = -1; // hush gcc
+
+@@ -2459,8 +2452,8 @@ static int __init amb_module_init (void)
+ static void __exit amb_module_exit (void)
+ {
+ PRINTD (DBG_FLOW|DBG_INIT, "cleanup_module");
+-
+- return pci_unregister_driver(&amb_driver);
++
++ pci_unregister_driver(&amb_driver);
+ }
+
+ module_init(amb_module_init);
+diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
+index df359a6..bc1b13c 100644
+--- a/drivers/atm/eni.c
++++ b/drivers/atm/eni.c
+@@ -1488,7 +1488,7 @@ static void bug_int(struct atm_dev *dev,
+ }
+
+
+-static irqreturn_t eni_int(int irq,void *dev_id,struct pt_regs *regs)
++static irqreturn_t eni_int(int irq,void *dev_id)
+ {
+ struct atm_dev *dev;
+ struct eni_dev *eni_dev;
+diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
+index 38fc054..697ad82 100644
+--- a/drivers/atm/firestream.c
++++ b/drivers/atm/firestream.c
+@@ -1002,6 +1002,10 @@ static int fs_open(struct atm_vcc *atm_v
+ r = ROUND_UP;
+ }
+ error = make_rate (pcr, r, &tmc0, NULL);
++ if (error) {
++ kfree(tc);
++ return error;
++ }
+ }
+ fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr);
+ }
+@@ -1546,7 +1550,7 @@ static void __devexit free_freepool (str
+
+
+
+-static irqreturn_t fs_irq (int irq, void *dev_id, struct pt_regs * pt_regs)
++static irqreturn_t fs_irq (int irq, void *dev_id)
+ {
+ int i;
+ u32 status;
+@@ -1784,7 +1788,7 @@ static int __devinit fs_init (struct fs_
+ write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1);
+ dev->nchannels = FS155_NR_CHANNELS;
+ }
+- dev->atm_vccs = kmalloc (dev->nchannels * sizeof (struct atm_vcc *),
++ dev->atm_vccs = kcalloc (dev->nchannels, sizeof (struct atm_vcc *),
+ GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%Zd)\n",
+ dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *));
+@@ -1794,9 +1798,8 @@ static int __devinit fs_init (struct fs_
+ /* XXX Clean up..... */
+ return 1;
+ }
+- memset (dev->atm_vccs, 0, dev->nchannels * sizeof (struct atm_vcc *));
+
+- dev->tx_inuse = kmalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
++ dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n",
+ dev->atm_vccs, dev->nchannels / 8);
+
+@@ -1805,8 +1808,6 @@ static int __devinit fs_init (struct fs_
+ /* XXX Clean up..... */
+ return 1;
+ }
+- memset (dev->tx_inuse, 0, dev->nchannels / 8);
+-
+ /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
+ /* -- RAS2 : FS50 only: Default is OK. */
+
+@@ -1893,14 +1894,11 @@ static int __devinit firestream_init_one
+ if (pci_enable_device(pci_dev))
+ goto err_out;
+
+- fs_dev = kmalloc (sizeof (struct fs_dev), GFP_KERNEL);
++ fs_dev = kzalloc (sizeof (struct fs_dev), GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%Zd)\n",
+ fs_dev, sizeof (struct fs_dev));
+ if (!fs_dev)
+ goto err_out;
+-
+- memset (fs_dev, 0, sizeof (struct fs_dev));
+-
+ atm_dev = atm_dev_register("fs", &ops, -1, NULL);
+ if (!atm_dev)
+ goto err_out_free_fs_dev;
+diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
+index 9862213..3a7b21f 100644
+--- a/drivers/atm/fore200e.c
++++ b/drivers/atm/fore200e.c
+@@ -1328,7 +1328,7 @@ fore200e_irq(struct fore200e* fore200e)
+
+
+ static irqreturn_t
+-fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
++fore200e_interrupt(int irq, void* dev)
+ {
+ struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev);
+
+diff --git a/drivers/atm/he.c b/drivers/atm/he.c
+index ffcb9fd..c7314a7 100644
+--- a/drivers/atm/he.c
++++ b/drivers/atm/he.c
+@@ -109,7 +109,7 @@ static int he_open(struct atm_vcc *vcc);
+ static void he_close(struct atm_vcc *vcc);
+ static int he_send(struct atm_vcc *vcc, struct sk_buff *skb);
+ static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);
+-static irqreturn_t he_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t he_irq_handler(int irq, void *dev_id);
+ static void he_tasklet(unsigned long data);
+ static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page);
+ static int he_start(struct atm_dev *dev);
+@@ -383,14 +383,12 @@ he_init_one(struct pci_dev *pci_dev, con
+ }
+ pci_set_drvdata(pci_dev, atm_dev);
+
+- he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev),
++ he_dev = kzalloc(sizeof(struct he_dev),
+ GFP_KERNEL);
+ if (!he_dev) {
+ err = -ENOMEM;
+ goto init_one_failure;
+ }
+- memset(he_dev, 0, sizeof(struct he_dev));
+-
+ he_dev->pci_dev = pci_dev;
+ he_dev->atm_dev = atm_dev;
+ he_dev->atm_dev->dev_data = he_dev;
+@@ -454,7 +452,7 @@ rate_to_atmf(unsigned rate) /* cps to a
+ return (NONZERO | (exp << 9) | (rate & 0x1ff));
+ }
+
+-static void __init
++static void __devinit
+ he_init_rx_lbfp0(struct he_dev *he_dev)
+ {
+ unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
+@@ -485,7 +483,7 @@ he_init_rx_lbfp0(struct he_dev *he_dev)
+ he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
+ }
+
+-static void __init
++static void __devinit
+ he_init_rx_lbfp1(struct he_dev *he_dev)
+ {
+ unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
+@@ -516,7 +514,7 @@ he_init_rx_lbfp1(struct he_dev *he_dev)
+ he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
+ }
+
+-static void __init
++static void __devinit
+ he_init_tx_lbfp(struct he_dev *he_dev)
+ {
+ unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
+@@ -546,7 +544,7 @@ he_init_tx_lbfp(struct he_dev *he_dev)
+ he_writel(he_dev, lbufd_index - 1, TLBF_T);
+ }
+
+-static int __init
++static int __devinit
+ he_init_tpdrq(struct he_dev *he_dev)
+ {
+ he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev,
+@@ -568,7 +566,7 @@ he_init_tpdrq(struct he_dev *he_dev)
+ return 0;
+ }
+
+-static void __init
++static void __devinit
+ he_init_cs_block(struct he_dev *he_dev)
+ {
+ unsigned clock, rate, delta;
+@@ -664,7 +662,7 @@ he_init_cs_block(struct he_dev *he_dev)
+
+ }
+
+-static int __init
++static int __devinit
+ he_init_cs_block_rcm(struct he_dev *he_dev)
+ {
+ unsigned (*rategrid)[16][16];
+@@ -785,7 +783,7 @@ he_init_cs_block_rcm(struct he_dev *he_d
+ return 0;
+ }
+
+-static int __init
++static int __devinit
+ he_init_group(struct he_dev *he_dev, int group)
+ {
+ int i;
+@@ -955,7 +953,7 @@ he_init_group(struct he_dev *he_dev, int
+ return 0;
+ }
+
+-static int __init
++static int __devinit
+ he_init_irq(struct he_dev *he_dev)
+ {
+ int i;
+@@ -1912,7 +1910,7 @@ he_service_rbrq(struct he_dev *he_dev, i
+ skb->tail = skb->data + skb->len;
+ #ifdef USE_CHECKSUM_HW
+ if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) {
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = TCP_CKSUM(skb->data,
+ he_vcc->pdu_len);
+ }
+@@ -2218,7 +2216,7 @@ he_tasklet(unsigned long data)
+ }
+
+ static irqreturn_t
+-he_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++he_irq_handler(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct he_dev *he_dev = (struct he_dev * )dev_id;
+diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
+index d1113e8..4dc1010 100644
+--- a/drivers/atm/horizon.c
++++ b/drivers/atm/horizon.c
+@@ -1382,24 +1382,13 @@ static inline void rx_data_av_handler (h
+
+ /********** interrupt handler **********/
+
+-static irqreturn_t interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *pt_regs) {
++static irqreturn_t interrupt_handler(int irq, void *dev_id) {
+ hrz_dev * dev = (hrz_dev *) dev_id;
+ u32 int_source;
+ unsigned int irq_ok;
+- (void) pt_regs;
+
+ PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id);
+
+- if (!dev_id) {
+- PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq);
+- return IRQ_NONE;
+- }
+- if (irq != dev->irq) {
+- PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq);
+- return IRQ_NONE;
+- }
+-
+ // definitely for us
+ irq_ok = 0;
+ while ((int_source = rd_regl (dev, INT_SOURCE_REG_OFF)
+@@ -1800,7 +1789,7 @@ static inline void CLOCK_IT (const hrz_d
+ WRITE_IT_WAIT(dev, ctrl | SEEPROM_SK);
+ }
+
+-static u16 __init read_bia (const hrz_dev * dev, u16 addr)
++static u16 __devinit read_bia (const hrz_dev * dev, u16 addr)
+ {
+ u32 ctrl = rd_regl (dev, CONTROL_0_REG);
+
+@@ -2719,7 +2708,7 @@ static int __devinit hrz_probe(struct pc
+ goto out_disable;
+ }
+
+- dev = kmalloc(sizeof(hrz_dev), GFP_KERNEL);
++ dev = kzalloc(sizeof(hrz_dev), GFP_KERNEL);
+ if (!dev) {
+ // perhaps we should be nice: deregister all adapters and abort?
+ PRINTD(DBG_ERR, "out of memory");
+@@ -2727,8 +2716,6 @@ static int __devinit hrz_probe(struct pc
+ goto out_release;
+ }
+
+- memset(dev, 0, sizeof(hrz_dev));
+-
+ pci_set_drvdata(pci_dev, dev);
+
+ // grab IRQ and install handler - move this someplace more sensible
+@@ -2945,8 +2932,8 @@ static int __init hrz_module_init (void)
+
+ static void __exit hrz_module_exit (void) {
+ PRINTD (DBG_FLOW, "cleanup_module");
+-
+- return pci_unregister_driver(&hrz_driver);
++
++ pci_unregister_driver(&hrz_driver);
+ }
+
+ module_init(hrz_module_init);
+diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
+index b0369bb..87b17c3 100644
+--- a/drivers/atm/idt77252.c
++++ b/drivers/atm/idt77252.c
+@@ -642,11 +642,9 @@ alloc_scq(struct idt77252_dev *card, int
+ {
+ struct scq_info *scq;
+
+- scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL);
++ scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL);
+ if (!scq)
+ return NULL;
+- memset(scq, 0, sizeof(struct scq_info));
+-
+ scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE,
+ &scq->paddr);
+ if (scq->base == NULL) {
+@@ -2142,11 +2140,9 @@ idt77252_init_est(struct vc_map *vc, int
+ {
+ struct rate_estimator *est;
+
+- est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL);
++ est = kzalloc(sizeof(struct rate_estimator), GFP_KERNEL);
+ if (!est)
+ return NULL;
+- memset(est, 0, sizeof(*est));
+-
+ est->maxcps = pcr < 0 ? -pcr : pcr;
+ est->cps = est->maxcps;
+ est->avcps = est->cps << 5;
+@@ -2451,14 +2447,12 @@ idt77252_open(struct atm_vcc *vcc)
+
+ index = VPCI2VC(card, vpi, vci);
+ if (!card->vcs[index]) {
+- card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
++ card->vcs[index] = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
+ if (!card->vcs[index]) {
+ printk("%s: can't alloc vc in open()\n", card->name);
+ up(&card->mutex);
+ return -ENOMEM;
+ }
+- memset(card->vcs[index], 0, sizeof(struct vc_map));
+-
+ card->vcs[index]->card = card;
+ card->vcs[index]->index = index;
+
+@@ -2780,7 +2774,7 @@ idt77252_collect_stat(struct idt77252_de
+ }
+
+ static irqreturn_t
+-idt77252_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++idt77252_interrupt(int irq, void *dev_id)
+ {
+ struct idt77252_dev *card = dev_id;
+ u32 stat;
+@@ -2926,13 +2920,11 @@ open_card_oam(struct idt77252_dev *card)
+ for (vci = 3; vci < 5; vci++) {
+ index = VPCI2VC(card, vpi, vci);
+
+- vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
++ vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
+ if (!vc) {
+ printk("%s: can't alloc vc\n", card->name);
+ return -ENOMEM;
+ }
+- memset(vc, 0, sizeof(struct vc_map));
+-
+ vc->index = index;
+ card->vcs[index] = vc;
+
+@@ -2995,12 +2987,11 @@ open_card_ubr0(struct idt77252_dev *card
+ {
+ struct vc_map *vc;
+
+- vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
++ vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
+ if (!vc) {
+ printk("%s: can't alloc vc\n", card->name);
+ return -ENOMEM;
+ }
+- memset(vc, 0, sizeof(struct vc_map));
+ card->vcs[0] = vc;
+ vc->class = SCHED_UBR0;
+
+@@ -3695,14 +3686,12 @@ idt77252_init_one(struct pci_dev *pcidev
+ goto err_out_disable_pdev;
+ }
+
+- card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
++ card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
+ if (!card) {
+ printk("idt77252-%d: can't allocate private data\n", index);
+ err = -ENOMEM;
+ goto err_out_disable_pdev;
+ }
+- memset(card, 0, sizeof(struct idt77252_dev));
+-
+ card->revision = revision;
+ card->index = index;
+ card->pcidev = pcidev;
+diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
+index f20b0b2..9ed1c60 100644
+--- a/drivers/atm/iphase.c
++++ b/drivers/atm/iphase.c
+@@ -2195,7 +2195,7 @@ err_out:
+ return -ENOMEM;
+ }
+
+-static irqreturn_t ia_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ia_int(int irq, void *dev_id)
+ {
+ struct atm_dev *dev;
+ IADEV *iadev;
+diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
+index fe60a59..2678255 100644
+--- a/drivers/atm/lanai.c
++++ b/drivers/atm/lanai.c
+@@ -1482,16 +1482,10 @@ static inline void vcc_table_deallocate(
+ static inline struct lanai_vcc *new_lanai_vcc(void)
+ {
+ struct lanai_vcc *lvcc;
+- lvcc = (struct lanai_vcc *) kmalloc(sizeof(*lvcc), GFP_KERNEL);
++ lvcc = kzalloc(sizeof(*lvcc), GFP_KERNEL);
+ if (likely(lvcc != NULL)) {
+- lvcc->vbase = NULL;
+- lvcc->rx.atmvcc = lvcc->tx.atmvcc = NULL;
+- lvcc->nref = 0;
+- memset(&lvcc->stats, 0, sizeof lvcc->stats);
+- lvcc->rx.buf.start = lvcc->tx.buf.start = NULL;
+ skb_queue_head_init(&lvcc->tx.backlog);
+ #ifdef DEBUG
+- lvcc->tx.unqueue = NULL;
+ lvcc->vci = -1;
+ #endif
+ }
+@@ -1896,13 +1890,11 @@ static inline void lanai_int_1(struct la
+ reg_write(lanai, ack, IntAck_Reg);
+ }
+
+-static irqreturn_t lanai_int(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t lanai_int(int irq, void *devid)
+ {
+- struct lanai_dev *lanai = (struct lanai_dev *) devid;
++ struct lanai_dev *lanai = devid;
+ u32 reason;
+
+- (void) irq; (void) regs; /* unused variables */
+-
+ #ifdef USE_POWERDOWN
+ /*
+ * If we're powered down we shouldn't be generating any interrupts -
+diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
+index b803689..bd09045 100644
+--- a/drivers/atm/nicstar.c
++++ b/drivers/atm/nicstar.c
+@@ -214,7 +214,7 @@ static void __devinit ns_init_card_error
+ static scq_info *get_scq(int size, u32 scd);
+ static void free_scq(scq_info *scq, struct atm_vcc *vcc);
+ static void push_rxbufs(ns_dev *, struct sk_buff *);
+-static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ns_irq_handler(int irq, void *dev_id);
+ static int ns_open(struct atm_vcc *vcc);
+ static void ns_close(struct atm_vcc *vcc);
+ static void fill_tst(ns_dev *card, int n, vc_map *vc);
+@@ -1194,7 +1194,7 @@ static void push_rxbufs(ns_dev *card, st
+
+
+
+-static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ns_irq_handler(int irq, void *dev_id)
+ {
+ u32 stat_r;
+ ns_dev *card;
+@@ -2759,7 +2759,7 @@ static int ns_ioctl(struct atm_dev *dev,
+ {
+ ns_dev *card;
+ pool_levels pl;
+- int btype;
++ long btype;
+ unsigned long flags;
+
+ card = dev->dev_data;
+@@ -2859,7 +2859,7 @@ static int ns_ioctl(struct atm_dev *dev,
+ case NS_ADJBUFLEV:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+- btype = (int) arg; /* an int is the same size as a pointer */
++ btype = (long) arg; /* a long is the same size as a pointer or bigger */
+ switch (btype)
+ {
+ case NS_BUFTYPE_SMALL:
+diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
+index 2c65e82..7df0f37 100644
+--- a/drivers/atm/zatm.c
++++ b/drivers/atm/zatm.c
+@@ -603,9 +603,8 @@ static int start_rx(struct atm_dev *dev)
+ DPRINTK("start_rx\n");
+ zatm_dev = ZATM_DEV(dev);
+ size = sizeof(struct atm_vcc *)*zatm_dev->chans;
+- zatm_dev->rx_map = (struct atm_vcc **) kmalloc(size,GFP_KERNEL);
++ zatm_dev->rx_map = kzalloc(size,GFP_KERNEL);
+ if (!zatm_dev->rx_map) return -ENOMEM;
+- memset(zatm_dev->rx_map,0,size);
+ /* set VPI/VCI split (use all VCIs and give what's left to VPIs) */
+ zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR);
+ /* prepare free buffer pools */
+@@ -801,6 +800,7 @@ static int alloc_shaper(struct atm_dev *
+ i = m = 1;
+ zatm_dev->ubr_ref_cnt++;
+ zatm_dev->ubr = shaper;
++ *pcr = 0;
+ }
+ else {
+ if (min) {
+@@ -951,9 +951,8 @@ static int open_tx_first(struct atm_vcc
+ skb_queue_head_init(&zatm_vcc->tx_queue);
+ init_waitqueue_head(&zatm_vcc->tx_wait);
+ /* initialize ring */
+- zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL);
++ zatm_vcc->ring = kzalloc(RING_SIZE,GFP_KERNEL);
+ if (!zatm_vcc->ring) return -ENOMEM;
+- memset(zatm_vcc->ring,0,RING_SIZE);
+ loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS;
+ loop[0] = uPD98401_TXPD_V;
+ loop[1] = loop[2] = 0;
+@@ -1013,7 +1012,7 @@ static int start_tx(struct atm_dev *dev)
+ /*------------------------------- interrupts --------------------------------*/
+
+
+-static irqreturn_t zatm_int(int irq,void *dev_id,struct pt_regs *regs)
++static irqreturn_t zatm_int(int irq,void *dev_id)
+ {
+ struct atm_dev *dev;
+ struct zatm_dev *zatm_dev;
+diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
+index 0b4e224..1429f3a 100644
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -37,8 +37,8 @@ config DEBUG_DRIVER
+
+ If you are unsure about this, say N here.
+
+-endmenu
+-
+ config SYS_HYPERVISOR
+ bool
+ default n
++
++endmenu
+diff --git a/drivers/base/Makefile b/drivers/base/Makefile
+index b539e5e..7bbb9ee 100644
+--- a/drivers/base/Makefile
++++ b/drivers/base/Makefile
+@@ -8,7 +8,7 @@ obj-y += power/
+ obj-$(CONFIG_ISA) += isa.o
+ obj-$(CONFIG_FW_LOADER) += firmware_class.o
+ obj-$(CONFIG_NUMA) += node.o
+-obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
++obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
+ obj-$(CONFIG_SMP) += topology.o
+ obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
+
+diff --git a/drivers/base/base.h b/drivers/base/base.h
+index c3b8dc9..d26644a 100644
+--- a/drivers/base/base.h
++++ b/drivers/base/base.h
+@@ -16,7 +16,7 @@ extern int cpu_dev_init(void);
+ extern int attribute_container_init(void);
+
+ extern int bus_add_device(struct device * dev);
+-extern void bus_attach_device(struct device * dev);
++extern int bus_attach_device(struct device * dev);
+ extern void bus_remove_device(struct device * dev);
+ extern struct bus_type *get_bus(struct bus_type * bus);
+ extern void put_bus(struct bus_type * bus);
+diff --git a/drivers/base/bus.c b/drivers/base/bus.c
+index 2e954d0..7d8a7ce 100644
+--- a/drivers/base/bus.c
++++ b/drivers/base/bus.c
+@@ -371,12 +371,31 @@ int bus_add_device(struct device * dev)
+ if (bus) {
+ pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
+ error = device_add_attrs(bus, dev);
+- if (!error) {
+- sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
+- sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem");
+- sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
+- }
++ if (error)
++ goto out_put;
++ error = sysfs_create_link(&bus->devices.kobj,
++ &dev->kobj, dev->bus_id);
++ if (error)
++ goto out_id;
++ error = sysfs_create_link(&dev->kobj,
++ &dev->bus->subsys.kset.kobj, "subsystem");
++ if (error)
++ goto out_subsys;
++ error = sysfs_create_link(&dev->kobj,
++ &dev->bus->subsys.kset.kobj, "bus");
++ if (error)
++ goto out_deprecated;
+ }
++ return 0;
++
++out_deprecated:
++ sysfs_remove_link(&dev->kobj, "subsystem");
++out_subsys:
++ sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
++out_id:
++ device_remove_attrs(bus, dev);
++out_put:
++ put_bus(dev->bus);
+ return error;
+ }
+
+@@ -384,16 +403,24 @@ int bus_add_device(struct device * dev)
+ * bus_attach_device - add device to bus
+ * @dev: device tried to attach to a driver
+ *
++ * - Add device to bus's list of devices.
+ * - Try to attach to driver.
+ */
+-void bus_attach_device(struct device * dev)
++int bus_attach_device(struct device * dev)
+ {
+- struct bus_type * bus = dev->bus;
++ struct bus_type *bus = dev->bus;
++ int ret = 0;
+
+ if (bus) {
+- device_attach(dev);
+- klist_add_tail(&dev->knode_bus, &bus->klist_devices);
++ dev->is_registered = 1;
++ ret = device_attach(dev);
++ if (ret >= 0) {
++ klist_add_tail(&dev->knode_bus, &bus->klist_devices);
++ ret = 0;
++ } else
++ dev->is_registered = 0;
+ }
++ return ret;
+ }
+
+ /**
+@@ -412,7 +439,10 @@ void bus_remove_device(struct device * d
+ sysfs_remove_link(&dev->kobj, "bus");
+ sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
+ device_remove_attrs(dev->bus, dev);
+- klist_remove(&dev->knode_bus);
++ if (dev->is_registered) {
++ dev->is_registered = 0;
++ klist_del(&dev->knode_bus);
++ }
+ pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
+ device_release_driver(dev);
+ put_bus(dev->bus);
+@@ -455,10 +485,17 @@ static void driver_remove_attrs(struct b
+ * Thanks to drivers making their tables __devinit, we can't allow manual
+ * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled.
+ */
+-static void add_bind_files(struct device_driver *drv)
++static int __must_check add_bind_files(struct device_driver *drv)
+ {
+- driver_create_file(drv, &driver_attr_unbind);
+- driver_create_file(drv, &driver_attr_bind);
++ int ret;
++
++ ret = driver_create_file(drv, &driver_attr_unbind);
++ if (ret == 0) {
++ ret = driver_create_file(drv, &driver_attr_bind);
++ if (ret)
++ driver_remove_file(drv, &driver_attr_unbind);
++ }
++ return ret;
+ }
+
+ static void remove_bind_files(struct device_driver *drv)
+@@ -467,7 +504,7 @@ static void remove_bind_files(struct dev
+ driver_remove_file(drv, &driver_attr_unbind);
+ }
+ #else
+-static inline void add_bind_files(struct device_driver *drv) {}
++static inline int add_bind_files(struct device_driver *drv) { return 0; }
+ static inline void remove_bind_files(struct device_driver *drv) {}
+ #endif
+
+@@ -476,35 +513,49 @@ static inline void remove_bind_files(str
+ * @drv: driver.
+ *
+ */
+-int bus_add_driver(struct device_driver * drv)
++int bus_add_driver(struct device_driver *drv)
+ {
+ struct bus_type * bus = get_bus(drv->bus);
+ int error = 0;
+
+- if (bus) {
+- pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
+- error = kobject_set_name(&drv->kobj, "%s", drv->name);
+- if (error) {
+- put_bus(bus);
+- return error;
+- }
+- drv->kobj.kset = &bus->drivers;
+- if ((error = kobject_register(&drv->kobj))) {
+- put_bus(bus);
+- return error;
+- }
+-
+- driver_attach(drv);
+- klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
+- module_add_driver(drv->owner, drv);
+-
+- driver_add_attrs(bus, drv);
+- add_bind_files(drv);
++ if (!bus)
++ return 0;
++
++ pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
++ error = kobject_set_name(&drv->kobj, "%s", drv->name);
++ if (error)
++ goto out_put_bus;
++ drv->kobj.kset = &bus->drivers;
++ if ((error = kobject_register(&drv->kobj)))
++ goto out_put_bus;
++
++ error = driver_attach(drv);
++ if (error)
++ goto out_unregister;
++ klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
++ module_add_driver(drv->owner, drv);
++
++ error = driver_add_attrs(bus, drv);
++ if (error) {
++ /* How the hell do we get out of this pickle? Give up */
++ printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
++ __FUNCTION__, drv->name);
++ }
++ error = add_bind_files(drv);
++ if (error) {
++ /* Ditto */
++ printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
++ __FUNCTION__, drv->name);
+ }
++
++ return error;
++out_unregister:
++ kobject_unregister(&drv->kobj);
++out_put_bus:
++ put_bus(bus);
+ return error;
+ }
+
+-
+ /**
+ * bus_remove_driver - delete driver from bus's knowledge.
+ * @drv: driver.
+@@ -516,30 +567,36 @@ int bus_add_driver(struct device_driver
+
+ void bus_remove_driver(struct device_driver * drv)
+ {
+- if (drv->bus) {
+- remove_bind_files(drv);
+- driver_remove_attrs(drv->bus, drv);
+- klist_remove(&drv->knode_bus);
+- pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
+- driver_detach(drv);
+- module_remove_driver(drv);
+- kobject_unregister(&drv->kobj);
+- put_bus(drv->bus);
+- }
++ if (!drv->bus)
++ return;
++
++ remove_bind_files(drv);
++ driver_remove_attrs(drv->bus, drv);
++ klist_remove(&drv->knode_bus);
++ pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
++ driver_detach(drv);
++ module_remove_driver(drv);
++ kobject_unregister(&drv->kobj);
++ put_bus(drv->bus);
+ }
+
+
+ /* Helper for bus_rescan_devices's iter */
+-static int bus_rescan_devices_helper(struct device *dev, void *data)
++static int __must_check bus_rescan_devices_helper(struct device *dev,
++ void *data)
+ {
++ int ret = 0;
++
+ if (!dev->driver) {
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
+- device_attach(dev);
++ ret = device_attach(dev);
+ if (dev->parent)
+ up(&dev->parent->sem);
++ if (ret > 0)
++ ret = 0;
+ }
+- return 0;
++ return ret < 0 ? ret : 0;
+ }
+
+ /**
+@@ -550,9 +607,9 @@ static int bus_rescan_devices_helper(str
+ * attached and rescan it against existing drivers to see if it matches
+ * any by calling device_attach() for the unbound devices.
+ */
+-void bus_rescan_devices(struct bus_type * bus)
++int bus_rescan_devices(struct bus_type * bus)
+ {
+- bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
++ return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
+ }
+
+ /**
+@@ -564,7 +621,7 @@ void bus_rescan_devices(struct bus_type
+ * to use if probing criteria changed during a devices lifetime and
+ * driver attachment should change accordingly.
+ */
+-void device_reprobe(struct device *dev)
++int device_reprobe(struct device *dev)
+ {
+ if (dev->driver) {
+ if (dev->parent) /* Needed for USB */
+@@ -573,14 +630,14 @@ void device_reprobe(struct device *dev)
+ if (dev->parent)
+ up(&dev->parent->sem);
+ }
+-
+- bus_rescan_devices_helper(dev, NULL);
++ return bus_rescan_devices_helper(dev, NULL);
+ }
+ EXPORT_SYMBOL_GPL(device_reprobe);
+
+-struct bus_type * get_bus(struct bus_type * bus)
++struct bus_type *get_bus(struct bus_type *bus)
+ {
+- return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL;
++ return bus ? container_of(subsys_get(&bus->subsys),
++ struct bus_type, subsys) : NULL;
+ }
+
+ void put_bus(struct bus_type * bus)
+@@ -655,22 +712,6 @@ static void klist_devices_put(struct kli
+ put_device(dev);
+ }
+
+-static void klist_drivers_get(struct klist_node *n)
+-{
+- struct device_driver *drv = container_of(n, struct device_driver,
+- knode_bus);
+-
+- get_driver(drv);
+-}
+-
+-static void klist_drivers_put(struct klist_node *n)
+-{
+- struct device_driver *drv = container_of(n, struct device_driver,
+- knode_bus);
+-
+- put_driver(drv);
+-}
+-
+ /**
+ * bus_register - register a bus with the system.
+ * @bus: bus.
+@@ -706,12 +747,16 @@ int bus_register(struct bus_type * bus)
+ goto bus_drivers_fail;
+
+ klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
+- klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put);
+- bus_add_attrs(bus);
++ klist_init(&bus->klist_drivers, NULL, NULL);
++ retval = bus_add_attrs(bus);
++ if (retval)
++ goto bus_attrs_fail;
+
+ pr_debug("bus type '%s' registered\n", bus->name);
+ return 0;
+
++bus_attrs_fail:
++ kset_unregister(&bus->drivers);
+ bus_drivers_fail:
+ kset_unregister(&bus->devices);
+ bus_devices_fail:
+diff --git a/drivers/base/class.c b/drivers/base/class.c
+index de89083..0ff267a 100644
+--- a/drivers/base/class.c
++++ b/drivers/base/class.c
+@@ -19,6 +19,8 @@
+ #include <linux/slab.h>
+ #include "base.h"
+
++extern struct subsystem devices_subsys;
++
+ #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
+ #define to_class(obj) container_of(obj, struct class, subsys.kset.kobj)
+
+@@ -197,7 +199,7 @@ static int class_device_create_uevent(st
+ * Note, the pointer created here is to be destroyed when finished by
+ * making a call to class_destroy().
+ */
+-struct class *class_create(struct module *owner, char *name)
++struct class *class_create(struct module *owner, const char *name)
+ {
+ struct class *cls;
+ int retval;
+@@ -226,7 +228,7 @@ error:
+
+ /**
+ * class_destroy - destroys a struct class structure
+- * @cs: pointer to the struct class that is to be destroyed
++ * @cls: pointer to the struct class that is to be destroyed
+ *
+ * Note, the pointer to be destroyed must have been created with a call
+ * to class_create().
+@@ -361,7 +363,7 @@ static int class_uevent(struct kset *kse
+ pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
+
+ if (class_dev->dev) {
+- /* add physical device, backing this device */
++ /* add device, backing this class device (deprecated) */
+ struct device *dev = class_dev->dev;
+ char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+
+@@ -560,7 +562,10 @@ int class_device_add(struct class_device
+ goto out2;
+
+ /* add the needed attributes to this device */
+- sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem");
++ error = sysfs_create_link(&class_dev->kobj,
++ &parent_class->subsys.kset.kobj, "subsystem");
++ if (error)
++ goto out3;
+ class_dev->uevent_attr.attr.name = "uevent";
+ class_dev->uevent_attr.attr.mode = S_IWUSR;
+ class_dev->uevent_attr.attr.owner = parent_class->owner;
+@@ -656,9 +661,9 @@ int class_device_register(struct class_d
+
+ /**
+ * class_device_create - creates a class device and registers it with sysfs
+- * @cs: pointer to the struct class that this device should be registered to.
++ * @cls: pointer to the struct class that this device should be registered to.
+ * @parent: pointer to the parent struct class_device of this new device, if any.
+- * @dev: the dev_t for the char device to be added.
++ * @devt: the dev_t for the char device to be added.
+ * @device: a pointer to a struct device that is assiociated with this class device.
+ * @fmt: string for the class device's name
+ *
+@@ -679,7 +684,8 @@ int class_device_register(struct class_d
+ struct class_device *class_device_create(struct class *cls,
+ struct class_device *parent,
+ dev_t devt,
+- struct device *device, char *fmt, ...)
++ struct device *device,
++ const char *fmt, ...)
+ {
+ va_list args;
+ struct class_device *class_dev = NULL;
+@@ -763,7 +769,7 @@ void class_device_unregister(struct clas
+ /**
+ * class_device_destroy - removes a class device that was created with class_device_create()
+ * @cls: the pointer to the struct class that this device was registered * with.
+- * @dev: the dev_t of the device that was previously registered.
++ * @devt: the dev_t of the device that was previously registered.
+ *
+ * This call unregisters and cleans up a class device that was created with a
+ * call to class_device_create()
+@@ -839,6 +845,7 @@ int class_interface_register(struct clas
+ {
+ struct class *parent;
+ struct class_device *class_dev;
++ struct device *dev;
+
+ if (!class_intf || !class_intf->class)
+ return -ENODEV;
+@@ -853,6 +860,10 @@ int class_interface_register(struct clas
+ list_for_each_entry(class_dev, &parent->children, node)
+ class_intf->add(class_dev, class_intf);
+ }
++ if (class_intf->add_dev) {
++ list_for_each_entry(dev, &parent->devices, node)
++ class_intf->add_dev(dev, class_intf);
++ }
+ up(&parent->sem);
+
+ return 0;
+@@ -862,6 +873,7 @@ void class_interface_unregister(struct c
+ {
+ struct class * parent = class_intf->class;
+ struct class_device *class_dev;
++ struct device *dev;
+
+ if (!parent)
+ return;
+@@ -872,12 +884,31 @@ void class_interface_unregister(struct c
+ list_for_each_entry(class_dev, &parent->children, node)
+ class_intf->remove(class_dev, class_intf);
+ }
++ if (class_intf->remove_dev) {
++ list_for_each_entry(dev, &parent->devices, node)
++ class_intf->remove_dev(dev, class_intf);
++ }
+ up(&parent->sem);
+
+ class_put(parent);
+ }
+
++int virtual_device_parent(struct device *dev)
++{
++ if (!dev->class)
++ return -ENODEV;
++
++ if (!dev->class->virtual_dir) {
++ static struct kobject *virtual_dir = NULL;
++
++ if (!virtual_dir)
++ virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
++ dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
++ }
+
++ dev->kobj.parent = dev->class->virtual_dir;
++ return 0;
++}
+
+ int __init classes_init(void)
+ {
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index be6b5bc..68ad11a 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -3,6 +3,8 @@
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
++ * Copyright (c) 2006 Greg Kroah-Hartman <gregkh at suse.de>
++ * Copyright (c) 2006 Novell, Inc.
+ *
+ * This file is released under the GPLv2
+ *
+@@ -42,7 +44,7 @@ const char *dev_driver_string(struct dev
+ return dev->driver ? dev->driver->name :
+ (dev->bus ? dev->bus->name : "");
+ }
+-EXPORT_SYMBOL_GPL(dev_driver_string);
++EXPORT_SYMBOL(dev_driver_string);
+
+ #define to_dev(obj) container_of(obj, struct device, kobj)
+ #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+@@ -92,6 +94,8 @@ static void device_release(struct kobjec
+
+ if (dev->release)
+ dev->release(dev);
++ else if (dev->class && dev->class->dev_release)
++ dev->class->dev_release(dev);
+ else {
+ printk(KERN_ERR "Device '%s' does not have a release() function, "
+ "it is broken and must be fixed.\n",
+@@ -149,17 +153,21 @@ static int dev_uevent(struct kset *kset,
+ "MINOR=%u", MINOR(dev->devt));
+ }
+
+- /* add bus name of physical device */
++ /* add bus name (same as SUBSYSTEM, deprecated) */
+ if (dev->bus)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVBUS=%s", dev->bus->name);
+
+- /* add driver name of physical device */
+- if (dev->driver)
++ /* add driver name (PHYSDEV* values are deprecated)*/
++ if (dev->driver) {
++ add_uevent_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "DRIVER=%s", dev->driver->name);
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", dev->driver->name);
++ }
+
+ /* terminate, set to next free slot, shrink available space */
+ envp[i] = NULL;
+@@ -177,6 +185,15 @@ static int dev_uevent(struct kset *kset,
+ }
+ }
+
++ if (dev->class && dev->class->dev_uevent) {
++ /* have the class specific function add its stuff */
++ retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
++ if (retval) {
++ pr_debug("%s - dev_uevent() returned %d\n",
++ __FUNCTION__, retval);
++ }
++ }
++
+ return retval;
+ }
+
+@@ -193,6 +210,72 @@ static ssize_t store_uevent(struct devic
+ return count;
+ }
+
++static int device_add_groups(struct device *dev)
++{
++ int i;
++ int error = 0;
++
++ if (dev->groups) {
++ for (i = 0; dev->groups[i]; i++) {
++ error = sysfs_create_group(&dev->kobj, dev->groups[i]);
++ if (error) {
++ while (--i >= 0)
++ sysfs_remove_group(&dev->kobj, dev->groups[i]);
++ goto out;
++ }
++ }
++ }
++out:
++ return error;
++}
++
++static void device_remove_groups(struct device *dev)
++{
++ int i;
++ if (dev->groups) {
++ for (i = 0; dev->groups[i]; i++) {
++ sysfs_remove_group(&dev->kobj, dev->groups[i]);
++ }
++ }
++}
++
++static int device_add_attrs(struct device *dev)
++{
++ struct class *class = dev->class;
++ int error = 0;
++ int i;
++
++ if (!class)
++ return 0;
++
++ if (class->dev_attrs) {
++ for (i = 0; attr_name(class->dev_attrs[i]); i++) {
++ error = device_create_file(dev, &class->dev_attrs[i]);
++ if (error)
++ break;
++ }
++ }
++ if (error)
++ while (--i >= 0)
++ device_remove_file(dev, &class->dev_attrs[i]);
++ return error;
++}
++
++static void device_remove_attrs(struct device *dev)
++{
++ struct class *class = dev->class;
++ int i;
++
++ if (!class)
++ return;
++
++ if (class->dev_attrs) {
++ for (i = 0; attr_name(class->dev_attrs[i]); i++)
++ device_remove_file(dev, &class->dev_attrs[i]);
++ }
++}
++
++
+ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
+ char *buf)
+ {
+@@ -236,6 +319,32 @@ void device_remove_file(struct device *
+ }
+ }
+
++/**
++ * device_create_bin_file - create sysfs binary attribute file for device.
++ * @dev: device.
++ * @attr: device binary attribute descriptor.
++ */
++int device_create_bin_file(struct device *dev, struct bin_attribute *attr)
++{
++ int error = -EINVAL;
++ if (dev)
++ error = sysfs_create_bin_file(&dev->kobj, attr);
++ return error;
++}
++EXPORT_SYMBOL_GPL(device_create_bin_file);
++
++/**
++ * device_remove_bin_file - remove sysfs binary attribute file
++ * @dev: device.
++ * @attr: device binary attribute descriptor.
++ */
++void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
++{
++ if (dev)
++ sysfs_remove_bin_file(&dev->kobj, attr);
++}
++EXPORT_SYMBOL_GPL(device_remove_bin_file);
++
+ static void klist_children_get(struct klist_node *n)
+ {
+ struct device *dev = container_of(n, struct device, knode_parent);
+@@ -289,12 +398,20 @@ int device_add(struct device *dev)
+ {
+ struct device *parent = NULL;
+ char *class_name = NULL;
++ struct class_interface *class_intf;
+ int error = -EINVAL;
+
+ dev = get_device(dev);
+ if (!dev || !strlen(dev->bus_id))
+ goto Error;
+
++ /* if this is a class device, and has no parent, create one */
++ if ((dev->class) && (dev->parent == NULL)) {
++ error = virtual_device_parent(dev);
++ if (error)
++ goto Error;
++ }
++
+ parent = get_device(dev->parent);
+
+ pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
+@@ -307,19 +424,25 @@ int device_add(struct device *dev)
+ if ((error = kobject_add(&dev->kobj)))
+ goto Error;
+
++ /* notify platform of device entry */
++ if (platform_notify)
++ platform_notify(dev);
++
+ dev->uevent_attr.attr.name = "uevent";
+ dev->uevent_attr.attr.mode = S_IWUSR;
+ if (dev->driver)
+ dev->uevent_attr.attr.owner = dev->driver->owner;
+ dev->uevent_attr.store = store_uevent;
+- device_create_file(dev, &dev->uevent_attr);
++ error = device_create_file(dev, &dev->uevent_attr);
++ if (error)
++ goto attrError;
+
+ if (MAJOR(dev->devt)) {
+ struct device_attribute *attr;
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ if (!attr) {
+ error = -ENOMEM;
+- goto PMError;
++ goto ueventattrError;
+ }
+ attr->attr.name = "dev";
+ attr->attr.mode = S_IRUGO;
+@@ -329,7 +452,7 @@ int device_add(struct device *dev)
+ error = device_create_file(dev, attr);
+ if (error) {
+ kfree(attr);
+- goto attrError;
++ goto ueventattrError;
+ }
+
+ dev->devt_attr = attr;
+@@ -340,42 +463,57 @@ int device_add(struct device *dev)
+ "subsystem");
+ sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+ dev->bus_id);
+-
+- sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
+- class_name = make_class_name(dev->class->name, &dev->kobj);
+- sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
++ if (parent) {
++ sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
++ class_name = make_class_name(dev->class->name, &dev->kobj);
++ sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
++ }
+ }
+
++ if ((error = device_add_attrs(dev)))
++ goto AttrsError;
++ if ((error = device_add_groups(dev)))
++ goto GroupError;
+ if ((error = device_pm_add(dev)))
+ goto PMError;
+ if ((error = bus_add_device(dev)))
+ goto BusError;
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
+- bus_attach_device(dev);
++ if ((error = bus_attach_device(dev)))
++ goto AttachError;
+ if (parent)
+ klist_add_tail(&dev->knode_parent, &parent->klist_children);
+
+ if (dev->class) {
+- /* tie the class to the device */
+ down(&dev->class->sem);
++ /* tie the class to the device */
+ list_add_tail(&dev->node, &dev->class->devices);
++
++ /* notify any interfaces that the device is here */
++ list_for_each_entry(class_intf, &dev->class->interfaces, node)
++ if (class_intf->add_dev)
++ class_intf->add_dev(dev, class_intf);
+ up(&dev->class->sem);
+ }
+-
+- /* notify platform of device entry */
+- if (platform_notify)
+- platform_notify(dev);
+ Done:
+ kfree(class_name);
+ put_device(dev);
+ return error;
++ AttachError:
++ bus_remove_device(dev);
+ BusError:
+ device_pm_remove(dev);
+ PMError:
++ device_remove_groups(dev);
++ GroupError:
++ device_remove_attrs(dev);
++ AttrsError:
+ if (dev->devt_attr) {
+ device_remove_file(dev, dev->devt_attr);
+ kfree(dev->devt_attr);
+ }
++ ueventattrError:
++ device_remove_file(dev, &dev->uevent_attr);
+ attrError:
+ kobject_uevent(&dev->kobj, KOBJ_REMOVE);
+ kobject_del(&dev->kobj);
+@@ -449,6 +587,7 @@ void device_del(struct device * dev)
+ {
+ struct device * parent = dev->parent;
+ char *class_name = NULL;
++ struct class_interface *class_intf;
+
+ if (parent)
+ klist_del(&dev->knode_parent);
+@@ -458,14 +597,23 @@ void device_del(struct device * dev)
+ sysfs_remove_link(&dev->kobj, "subsystem");
+ sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id);
+ class_name = make_class_name(dev->class->name, &dev->kobj);
+- sysfs_remove_link(&dev->kobj, "device");
+- sysfs_remove_link(&dev->parent->kobj, class_name);
++ if (parent) {
++ sysfs_remove_link(&dev->kobj, "device");
++ sysfs_remove_link(&dev->parent->kobj, class_name);
++ }
+ kfree(class_name);
+ down(&dev->class->sem);
++ /* notify any interfaces that the device is now gone */
++ list_for_each_entry(class_intf, &dev->class->interfaces, node)
++ if (class_intf->remove_dev)
++ class_intf->remove_dev(dev, class_intf);
++ /* remove the device from the class list */
+ list_del_init(&dev->node);
+ up(&dev->class->sem);
+ }
+ device_remove_file(dev, &dev->uevent_attr);
++ device_remove_groups(dev);
++ device_remove_attrs(dev);
+
+ /* Notify the platform of the removal, in case they
+ * need to do anything...
+@@ -579,7 +727,7 @@ static void device_create_release(struct
+ * been created with a call to class_create().
+ */
+ struct device *device_create(struct class *class, struct device *parent,
+- dev_t devt, char *fmt, ...)
++ dev_t devt, const char *fmt, ...)
+ {
+ va_list args;
+ struct device *dev = NULL;
+@@ -587,10 +735,6 @@ struct device *device_create(struct clas
+
+ if (class == NULL || IS_ERR(class))
+ goto error;
+- if (parent == NULL) {
+- printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__);
+- goto error;
+- }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+@@ -644,3 +788,61 @@ void device_destroy(struct class *class,
+ device_unregister(dev);
+ }
+ EXPORT_SYMBOL_GPL(device_destroy);
++
++/**
++ * device_rename - renames a device
++ * @dev: the pointer to the struct device to be renamed
++ * @new_name: the new name of the device
++ */
++int device_rename(struct device *dev, char *new_name)
++{
++ char *old_class_name = NULL;
++ char *new_class_name = NULL;
++ char *old_symlink_name = NULL;
++ int error;
++
++ dev = get_device(dev);
++ if (!dev)
++ return -EINVAL;
++
++ pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name);
++
++ if ((dev->class) && (dev->parent))
++ old_class_name = make_class_name(dev->class->name, &dev->kobj);
++
++ if (dev->class) {
++ old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
++ if (!old_symlink_name) {
++ error = -ENOMEM;
++ goto out_free_old_class;
++ }
++ strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
++ }
++
++ strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
++
++ error = kobject_rename(&dev->kobj, new_name);
++
++ if (old_class_name) {
++ new_class_name = make_class_name(dev->class->name, &dev->kobj);
++ if (new_class_name) {
++ sysfs_create_link(&dev->parent->kobj, &dev->kobj,
++ new_class_name);
++ sysfs_remove_link(&dev->parent->kobj, old_class_name);
++ }
++ }
++ if (dev->class) {
++ sysfs_remove_link(&dev->class->subsys.kset.kobj,
++ old_symlink_name);
++ sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
++ dev->bus_id);
++ }
++ put_device(dev);
++
++ kfree(new_class_name);
++ kfree(old_symlink_name);
++ out_free_old_class:
++ kfree(old_class_name);
++
++ return error;
++}
+diff --git a/drivers/base/dd.c b/drivers/base/dd.c
+index 889c711..c5d6bb4 100644
+--- a/drivers/base/dd.c
++++ b/drivers/base/dd.c
+@@ -17,6 +17,8 @@
+
+ #include <linux/device.h>
+ #include <linux/module.h>
++#include <linux/kthread.h>
++#include <linux/wait.h>
+
+ #include "base.h"
+ #include "power/power.h"
+@@ -38,66 +40,75 @@
+ *
+ * This function must be called with @dev->sem held.
+ */
+-void device_bind_driver(struct device * dev)
++int device_bind_driver(struct device *dev)
+ {
+- if (klist_node_attached(&dev->knode_driver))
+- return;
++ int ret;
++
++ if (klist_node_attached(&dev->knode_driver)) {
++ printk(KERN_WARNING "%s: device %s already bound\n",
++ __FUNCTION__, kobject_name(&dev->kobj));
++ return 0;
++ }
+
+ pr_debug("bound device '%s' to driver '%s'\n",
+ dev->bus_id, dev->driver->name);
+ klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
+- sysfs_create_link(&dev->driver->kobj, &dev->kobj,
++ ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
+ kobject_name(&dev->kobj));
+- sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
++ if (ret == 0) {
++ ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj,
++ "driver");
++ if (ret)
++ sysfs_remove_link(&dev->driver->kobj,
++ kobject_name(&dev->kobj));
++ }
++ return ret;
+ }
+
+-/**
+- * driver_probe_device - attempt to bind device & driver.
+- * @drv: driver.
+- * @dev: device.
+- *
+- * First, we call the bus's match function, if one present, which
+- * should compare the device IDs the driver supports with the
+- * device IDs of the device. Note we don't do this ourselves
+- * because we don't know the format of the ID structures, nor what
+- * is to be considered a match and what is not.
+- *
+- * This function returns 1 if a match is found, an error if one
+- * occurs (that is not -ENODEV or -ENXIO), and 0 otherwise.
+- *
+- * This function must be called with @dev->sem held. When called
+- * for a USB interface, @dev->parent->sem must be held as well.
+- */
+-int driver_probe_device(struct device_driver * drv, struct device * dev)
++struct stupid_thread_structure {
++ struct device_driver *drv;
++ struct device *dev;
++};
++
++static atomic_t probe_count = ATOMIC_INIT(0);
++static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
++
++static int really_probe(void *void_data)
+ {
++ struct stupid_thread_structure *data = void_data;
++ struct device_driver *drv = data->drv;
++ struct device *dev = data->dev;
+ int ret = 0;
+
+- if (drv->bus->match && !drv->bus->match(dev, drv))
+- goto Done;
++ atomic_inc(&probe_count);
++ pr_debug("%s: Probing driver %s with device %s\n",
++ drv->bus->name, drv->name, dev->bus_id);
+
+- pr_debug("%s: Matched Device %s with Driver %s\n",
+- drv->bus->name, dev->bus_id, drv->name);
+ dev->driver = drv;
+ if (dev->bus->probe) {
+ ret = dev->bus->probe(dev);
+ if (ret) {
+ dev->driver = NULL;
+- goto ProbeFailed;
++ goto probe_failed;
+ }
+ } else if (drv->probe) {
+ ret = drv->probe(dev);
+ if (ret) {
+ dev->driver = NULL;
+- goto ProbeFailed;
++ goto probe_failed;
+ }
+ }
+- device_bind_driver(dev);
++ if (device_bind_driver(dev)) {
++ printk(KERN_ERR "%s: device_bind_driver(%s) failed\n",
++ __FUNCTION__, dev->bus_id);
++ /* How does undo a ->probe? We're screwed. */
++ }
+ ret = 1;
+ pr_debug("%s: Bound Device %s to Driver %s\n",
+ drv->bus->name, dev->bus_id, drv->name);
+- goto Done;
++ goto done;
+
+- ProbeFailed:
++probe_failed:
+ if (ret == -ENODEV || ret == -ENXIO) {
+ /* Driver matched, but didn't support device
+ * or device not found.
+@@ -110,7 +121,74 @@ int driver_probe_device(struct device_dr
+ "%s: probe of %s failed with error %d\n",
+ drv->name, dev->bus_id, ret);
+ }
+- Done:
++done:
++ kfree(data);
++ atomic_dec(&probe_count);
++ wake_up(&probe_waitqueue);
++ return ret;
++}
++
++/**
++ * driver_probe_done
++ * Determine if the probe sequence is finished or not.
++ *
++ * Should somehow figure out how to use a semaphore, not an atomic variable...
++ */
++int driver_probe_done(void)
++{
++ pr_debug("%s: probe_count = %d\n", __FUNCTION__,
++ atomic_read(&probe_count));
++ if (atomic_read(&probe_count))
++ return -EBUSY;
++ return 0;
++}
++
++/**
++ * driver_probe_device - attempt to bind device & driver together
++ * @drv: driver to bind a device to
++ * @dev: device to try to bind to the driver
++ *
++ * First, we call the bus's match function, if one present, which should
++ * compare the device IDs the driver supports with the device IDs of the
++ * device. Note we don't do this ourselves because we don't know the
++ * format of the ID structures, nor what is to be considered a match and
++ * what is not.
++ *
++ * This function returns 1 if a match is found, an error if one occurs
++ * (that is not -ENODEV or -ENXIO), and 0 otherwise.
++ *
++ * This function must be called with @dev->sem held. When called for a
++ * USB interface, @dev->parent->sem must be held as well.
++ */
++int driver_probe_device(struct device_driver * drv, struct device * dev)
++{
++ struct stupid_thread_structure *data;
++ struct task_struct *probe_task;
++ int ret = 0;
++
++ if (!device_is_registered(dev))
++ return -ENODEV;
++ if (drv->bus->match && !drv->bus->match(dev, drv))
++ goto done;
++
++ pr_debug("%s: Matched Device %s with Driver %s\n",
++ drv->bus->name, dev->bus_id, drv->name);
++
++ data = kmalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++ data->drv = drv;
++ data->dev = dev;
++
++ if (drv->multithread_probe) {
++ probe_task = kthread_run(really_probe, data,
++ "probe-%s", dev->bus_id);
++ if (IS_ERR(probe_task))
++ ret = really_probe(data);
++ } else
++ ret = really_probe(data);
++
++done:
+ return ret;
+ }
+
+@@ -139,8 +217,9 @@ int device_attach(struct device * dev)
+
+ down(&dev->sem);
+ if (dev->driver) {
+- device_bind_driver(dev);
+- ret = 1;
++ ret = device_bind_driver(dev);
++ if (ret == 0)
++ ret = 1;
+ } else
+ ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+ up(&dev->sem);
+@@ -182,9 +261,9 @@ static int __driver_attach(struct device
+ * returns 0 and the @dev->driver is set, we've found a
+ * compatible pair.
+ */
+-void driver_attach(struct device_driver * drv)
++int driver_attach(struct device_driver * drv)
+ {
+- bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
++ return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
+ }
+
+ /**
+@@ -262,6 +341,32 @@ void driver_detach(struct device_driver
+ }
+ }
+
++#ifdef CONFIG_PCI_MULTITHREAD_PROBE
++static int __init wait_for_probes(void)
++{
++ DEFINE_WAIT(wait);
++
++ printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__,
++ atomic_read(&probe_count));
++ if (!atomic_read(&probe_count))
++ return 0;
++ while (atomic_read(&probe_count)) {
++ prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE);
++ if (atomic_read(&probe_count))
++ schedule();
++ }
++ finish_wait(&probe_waitqueue, &wait);
++ return 0;
++}
++
++core_initcall_sync(wait_for_probes);
++postcore_initcall_sync(wait_for_probes);
++arch_initcall_sync(wait_for_probes);
++subsys_initcall_sync(wait_for_probes);
++fs_initcall_sync(wait_for_probes);
++device_initcall_sync(wait_for_probes);
++late_initcall_sync(wait_for_probes);
++#endif
+
+ EXPORT_SYMBOL_GPL(device_bind_driver);
+ EXPORT_SYMBOL_GPL(device_release_driver);
+diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
+index 33c5cce..b2efbd4 100644
+--- a/drivers/base/dmapool.c
++++ b/drivers/base/dmapool.c
+@@ -141,11 +141,20 @@ dma_pool_create (const char *name, struc
+ init_waitqueue_head (&retval->waitq);
+
+ if (dev) {
++ int ret;
++
+ down (&pools_lock);
+ if (list_empty (&dev->dma_pools))
+- device_create_file (dev, &dev_attr_pools);
++ ret = device_create_file (dev, &dev_attr_pools);
++ else
++ ret = 0;
+ /* note: not currently insisting "name" be unique */
+- list_add (&retval->pools, &dev->dma_pools);
++ if (!ret)
++ list_add (&retval->pools, &dev->dma_pools);
++ else {
++ kfree(retval);
++ retval = NULL;
++ }
+ up (&pools_lock);
+ } else
+ INIT_LIST_HEAD (&retval->pools);
+diff --git a/drivers/base/driver.c b/drivers/base/driver.c
+index 562600d..1214cbd 100644
+--- a/drivers/base/driver.c
++++ b/drivers/base/driver.c
+@@ -142,20 +142,6 @@ void put_driver(struct device_driver * d
+ kobject_put(&drv->kobj);
+ }
+
+-static void klist_devices_get(struct klist_node *n)
+-{
+- struct device *dev = container_of(n, struct device, knode_driver);
+-
+- get_device(dev);
+-}
+-
+-static void klist_devices_put(struct klist_node *n)
+-{
+- struct device *dev = container_of(n, struct device, knode_driver);
+-
+- put_device(dev);
+-}
+-
+ /**
+ * driver_register - register driver with bus
+ * @drv: driver to register
+@@ -175,7 +161,7 @@ int driver_register(struct device_driver
+ (drv->bus->shutdown && drv->shutdown)) {
+ printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
+ }
+- klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);
++ klist_init(&drv->klist_devices, NULL, NULL);
+ init_completion(&drv->unloaded);
+ return bus_add_driver(drv);
+ }
+diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
+index 5d6c011..1461569 100644
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -16,6 +16,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/bitops.h>
+ #include <linux/mutex.h>
++#include <linux/kthread.h>
+
+ #include <linux/firmware.h>
+ #include "base.h"
+@@ -511,7 +512,6 @@ request_firmware_work_func(void *arg)
+ WARN_ON(1);
+ return 0;
+ }
+- daemonize("%s/%s", "firmware", fw_work->name);
+ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+ fw_work->uevent);
+ if (ret < 0)
+@@ -546,9 +546,9 @@ request_firmware_nowait(
+ const char *name, struct device *device, void *context,
+ void (*cont)(const struct firmware *fw, void *context))
+ {
++ struct task_struct *task;
+ struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
+ GFP_ATOMIC);
+- int ret;
+
+ if (!fw_work)
+ return -ENOMEM;
+@@ -566,14 +566,14 @@ request_firmware_nowait(
+ .uevent = uevent,
+ };
+
+- ret = kernel_thread(request_firmware_work_func, fw_work,
+- CLONE_FS | CLONE_FILES);
++ task = kthread_run(request_firmware_work_func, fw_work,
++ "firmware/%s", name);
+
+- if (ret < 0) {
++ if (IS_ERR(task)) {
+ fw_work->cont(NULL, fw_work->context);
+ module_put(fw_work->module);
+ kfree(fw_work);
+- return ret;
++ return PTR_ERR(task);
+ }
+ return 0;
+ }
+@@ -602,7 +602,7 @@ firmware_class_exit(void)
+ class_unregister(&firmware_class);
+ }
+
+-module_init(firmware_class_init);
++fs_initcall(firmware_class_init);
+ module_exit(firmware_class_exit);
+
+ EXPORT_SYMBOL(release_firmware);
+diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c
+index 0c85e9d..7080b41 100644
+--- a/drivers/base/hypervisor.c
++++ b/drivers/base/hypervisor.c
+@@ -1,8 +1,9 @@
+ /*
+ * hypervisor.c - /sys/hypervisor subsystem.
+ *
+- * This file is released under the GPLv2
++ * Copyright (C) IBM Corp. 2006
+ *
++ * This file is released under the GPLv2
+ */
+
+ #include <linux/kobject.h>
+diff --git a/drivers/base/node.c b/drivers/base/node.c
+index e9b0957..001e6f6 100644
+--- a/drivers/base/node.c
++++ b/drivers/base/node.c
+@@ -54,10 +54,12 @@ static ssize_t node_read_meminfo(struct
+ "Node %d MemUsed: %8lu kB\n"
+ "Node %d Active: %8lu kB\n"
+ "Node %d Inactive: %8lu kB\n"
++#ifdef CONFIG_HIGHMEM
+ "Node %d HighTotal: %8lu kB\n"
+ "Node %d HighFree: %8lu kB\n"
+ "Node %d LowTotal: %8lu kB\n"
+ "Node %d LowFree: %8lu kB\n"
++#endif
+ "Node %d Dirty: %8lu kB\n"
+ "Node %d Writeback: %8lu kB\n"
+ "Node %d FilePages: %8lu kB\n"
+@@ -66,16 +68,20 @@ static ssize_t node_read_meminfo(struct
+ "Node %d PageTables: %8lu kB\n"
+ "Node %d NFS_Unstable: %8lu kB\n"
+ "Node %d Bounce: %8lu kB\n"
+- "Node %d Slab: %8lu kB\n",
++ "Node %d Slab: %8lu kB\n"
++ "Node %d SReclaimable: %8lu kB\n"
++ "Node %d SUnreclaim: %8lu kB\n",
+ nid, K(i.totalram),
+ nid, K(i.freeram),
+ nid, K(i.totalram - i.freeram),
+ nid, K(active),
+ nid, K(inactive),
++#ifdef CONFIG_HIGHMEM
+ nid, K(i.totalhigh),
+ nid, K(i.freehigh),
+ nid, K(i.totalram - i.totalhigh),
+ nid, K(i.freeram - i.freehigh),
++#endif
+ nid, K(node_page_state(nid, NR_FILE_DIRTY)),
+ nid, K(node_page_state(nid, NR_WRITEBACK)),
+ nid, K(node_page_state(nid, NR_FILE_PAGES)),
+@@ -84,7 +90,10 @@ static ssize_t node_read_meminfo(struct
+ nid, K(node_page_state(nid, NR_PAGETABLE)),
+ nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
+ nid, K(node_page_state(nid, NR_BOUNCE)),
+- nid, K(node_page_state(nid, NR_SLAB)));
++ nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
++ node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
++ nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
++ nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
+ n += hugetlb_report_node_meminfo(nid, buf + n);
+ return n;
+ }
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index 2b8755d..940ce41 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -505,12 +505,36 @@ static int platform_match(struct device
+ return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
+ }
+
+-static int platform_suspend(struct device * dev, pm_message_t state)
++static int platform_suspend(struct device *dev, pm_message_t mesg)
+ {
+ int ret = 0;
+
+ if (dev->driver && dev->driver->suspend)
+- ret = dev->driver->suspend(dev, state);
++ ret = dev->driver->suspend(dev, mesg);
++
++ return ret;
++}
++
++static int platform_suspend_late(struct device *dev, pm_message_t mesg)
++{
++ struct platform_driver *drv = to_platform_driver(dev->driver);
++ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++ int ret = 0;
++
++ if (dev->driver && drv->suspend_late)
++ ret = drv->suspend_late(pdev, mesg);
++
++ return ret;
++}
++
++static int platform_resume_early(struct device *dev)
++{
++ struct platform_driver *drv = to_platform_driver(dev->driver);
++ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++ int ret = 0;
++
++ if (dev->driver && drv->resume_early)
++ ret = drv->resume_early(pdev);
+
+ return ret;
+ }
+@@ -531,6 +555,8 @@ struct bus_type platform_bus_type = {
+ .match = platform_match,
+ .uevent = platform_uevent,
+ .suspend = platform_suspend,
++ .suspend_late = platform_suspend_late,
++ .resume_early = platform_resume_early,
+ .resume = platform_resume,
+ };
+ EXPORT_SYMBOL_GPL(platform_bus_type);
+diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
+index 826093e..020be36 100644
+--- a/drivers/base/power/resume.c
++++ b/drivers/base/power/resume.c
+@@ -38,13 +38,35 @@ int resume_device(struct device * dev)
+ dev_dbg(dev,"resuming\n");
+ error = dev->bus->resume(dev);
+ }
++ if (dev->class && dev->class->resume) {
++ dev_dbg(dev,"class resume\n");
++ error = dev->class->resume(dev);
++ }
+ up(&dev->sem);
+ TRACE_RESUME(error);
+ return error;
+ }
+
+
++static int resume_device_early(struct device * dev)
++{
++ int error = 0;
+
++ TRACE_DEVICE(dev);
++ TRACE_RESUME(0);
++ if (dev->bus && dev->bus->resume_early) {
++ dev_dbg(dev,"EARLY resume\n");
++ error = dev->bus->resume_early(dev);
++ }
++ TRACE_RESUME(error);
++ return error;
++}
++
++/*
++ * Resume the devices that have either not gone through
++ * the late suspend, or that did go through it but also
++ * went through the early resume
++ */
+ void dpm_resume(void)
+ {
+ down(&dpm_list_sem);
+@@ -74,6 +96,7 @@ void dpm_resume(void)
+
+ void device_resume(void)
+ {
++ might_sleep();
+ down(&dpm_sem);
+ dpm_resume();
+ up(&dpm_sem);
+@@ -83,12 +106,12 @@ EXPORT_SYMBOL_GPL(device_resume);
+
+
+ /**
+- * device_power_up_irq - Power on some devices.
++ * dpm_power_up - Power on some devices.
+ *
+ * Walk the dpm_off_irq list and power each device up. This
+ * is used for devices that required they be powered down with
+- * interrupts disabled. As devices are powered on, they are moved to
+- * the dpm_suspended list.
++ * interrupts disabled. As devices are powered on, they are moved
++ * to the dpm_active list.
+ *
+ * Interrupts must be disabled when calling this.
+ */
+@@ -99,16 +122,14 @@ void dpm_power_up(void)
+ struct list_head * entry = dpm_off_irq.next;
+ struct device * dev = to_device(entry);
+
+- get_device(dev);
+- list_move_tail(entry, &dpm_active);
+- resume_device(dev);
+- put_device(dev);
++ list_move_tail(entry, &dpm_off);
++ resume_device_early(dev);
+ }
+ }
+
+
+ /**
+- * device_pm_power_up - Turn on all devices that need special attention.
++ * device_power_up - Turn on all devices that need special attention.
+ *
+ * Power on system devices then devices that required we shut them down
+ * with interrupts disabled.
+diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
+index 69509e0..ece136b 100644
+--- a/drivers/base/power/suspend.c
++++ b/drivers/base/power/suspend.c
+@@ -34,6 +34,7 @@ static inline char *suspend_verb(u32 eve
+ switch (event) {
+ case PM_EVENT_SUSPEND: return "suspend";
+ case PM_EVENT_FREEZE: return "freeze";
++ case PM_EVENT_PRETHAW: return "prethaw";
+ default: return "(unknown suspend event)";
+ }
+ }
+@@ -65,7 +66,19 @@ int suspend_device(struct device * dev,
+
+ dev->power.prev_state = dev->power.power_state;
+
+- if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
++ if (dev->class && dev->class->suspend && !dev->power.power_state.event) {
++ dev_dbg(dev, "class %s%s\n",
++ suspend_verb(state.event),
++ ((state.event == PM_EVENT_SUSPEND)
++ && device_may_wakeup(dev))
++ ? ", may wakeup"
++ : ""
++ );
++ error = dev->class->suspend(dev, state);
++ suspend_report_result(dev->class->suspend, error);
++ }
++
++ if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
+ dev_dbg(dev, "%s%s\n",
+ suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND)
+@@ -81,15 +94,42 @@ int suspend_device(struct device * dev,
+ }
+
+
++/*
++ * This is called with interrupts off, only a single CPU
++ * running. We can't do down() on a semaphore (and we don't
++ * need the protection)
++ */
++static int suspend_device_late(struct device *dev, pm_message_t state)
++{
++ int error = 0;
++
++ if (dev->bus && dev->bus->suspend_late && !dev->power.power_state.event) {
++ dev_dbg(dev, "LATE %s%s\n",
++ suspend_verb(state.event),
++ ((state.event == PM_EVENT_SUSPEND)
++ && device_may_wakeup(dev))
++ ? ", may wakeup"
++ : ""
++ );
++ error = dev->bus->suspend_late(dev, state);
++ suspend_report_result(dev->bus->suspend_late, error);
++ }
++ return error;
++}
++
+ /**
+ * device_suspend - Save state and stop all devices in system.
+ * @state: Power state to put each device in.
+ *
+ * Walk the dpm_active list, call ->suspend() for each device, and move
+- * it to dpm_off.
+- * Check the return value for each. If it returns 0, then we move the
+- * the device to the dpm_off list. If it returns -EAGAIN, we move it to
+- * the dpm_off_irq list. If we get a different error, try and back out.
++ * it to the dpm_off list.
++ *
++ * (For historical reasons, if it returns -EAGAIN, that used to mean
++ * that the device would be called again with interrupts disabled.
++ * These days, we use the "suspend_late()" callback for that, so we
++ * print a warning and consider it an error).
++ *
++ * If we get a different error, try and back out.
+ *
+ * If we hit a failure with any of the devices, call device_resume()
+ * above to bring the suspended devices back to life.
+@@ -100,6 +140,7 @@ int device_suspend(pm_message_t state)
+ {
+ int error = 0;
+
++ might_sleep();
+ down(&dpm_sem);
+ down(&dpm_list_sem);
+ while (!list_empty(&dpm_active) && error == 0) {
+@@ -115,39 +156,27 @@ int device_suspend(pm_message_t state)
+
+ /* Check if the device got removed */
+ if (!list_empty(&dev->power.entry)) {
+- /* Move it to the dpm_off or dpm_off_irq list */
++ /* Move it to the dpm_off list */
+ if (!error)
+ list_move(&dev->power.entry, &dpm_off);
+- else if (error == -EAGAIN) {
+- list_move(&dev->power.entry, &dpm_off_irq);
+- error = 0;
+- }
+ }
+ if (error)
+ printk(KERN_ERR "Could not suspend device %s: "
+- "error %d\n", kobject_name(&dev->kobj), error);
++ "error %d%s\n",
++ kobject_name(&dev->kobj), error,
++ error == -EAGAIN ? " (please convert to suspend_late)" : "");
+ put_device(dev);
+ }
+ up(&dpm_list_sem);
+- if (error) {
+- /* we failed... before resuming, bring back devices from
+- * dpm_off_irq list back to main dpm_off list, we do want
+- * to call resume() on them, in case they partially suspended
+- * despite returning -EAGAIN
+- */
+- while (!list_empty(&dpm_off_irq)) {
+- struct list_head * entry = dpm_off_irq.next;
+- list_move(entry, &dpm_off);
+- }
++ if (error)
+ dpm_resume();
+- }
++
+ up(&dpm_sem);
+ return error;
+ }
+
+ EXPORT_SYMBOL_GPL(device_suspend);
+
+-
+ /**
+ * device_power_down - Shut down special devices.
+ * @state: Power state to enter.
+@@ -162,14 +191,17 @@ int device_power_down(pm_message_t state
+ int error = 0;
+ struct device * dev;
+
+- list_for_each_entry_reverse(dev, &dpm_off_irq, power.entry) {
+- if ((error = suspend_device(dev, state)))
+- break;
++ while (!list_empty(&dpm_off)) {
++ struct list_head * entry = dpm_off.prev;
++
++ dev = to_device(entry);
++ error = suspend_device_late(dev, state);
++ if (error)
++ goto Error;
++ list_move(&dev->power.entry, &dpm_off_irq);
+ }
+- if (error)
+- goto Error;
+- if ((error = sysdev_suspend(state)))
+- goto Error;
++
++ error = sysdev_suspend(state);
+ Done:
+ return error;
+ Error:
+diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
+index 40d7242..2d47517 100644
+--- a/drivers/base/power/sysfs.c
++++ b/drivers/base/power/sysfs.c
+@@ -7,22 +7,29 @@
+ #include "power.h"
+
+
++#ifdef CONFIG_PM_SYSFS_DEPRECATED
++
+ /**
+ * state - Control current power state of device
+ *
+ * show() returns the current power state of the device. '0' indicates
+- * the device is on. Other values (1-3) indicate the device is in a low
++ * the device is on. Other values (2) indicate the device is in some low
+ * power state.
+ *
+- * store() sets the current power state, which is an integer value
+- * between 0-3. If the device is on ('0'), and the value written is
+- * greater than 0, then the device is placed directly into the low-power
+- * state (via its driver's ->suspend() method).
+- * If the device is currently in a low-power state, and the value is 0,
+- * the device is powered back on (via the ->resume() method).
+- * If the device is in a low-power state, and a different low-power state
+- * is requested, the device is first resumed, then suspended into the new
+- * low-power state.
++ * store() sets the current power state, which is an integer valued
++ * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early()
++ * methods fail this operation; those methods couldn't be called.
++ * Otherwise,
++ *
++ * - If the recorded dev->power.power_state.event matches the
++ * target value, nothing is done.
++ * - If the recorded event code is nonzero, the device is reactivated
++ * by calling bus.resume() and/or class.resume().
++ * - If the target value is nonzero, the device is suspended by
++ * calling class.suspend() and/or bus.suspend() with event code
++ * PM_EVENT_SUSPEND.
++ *
++ * This mechanism is DEPRECATED and should only be used for testing.
+ */
+
+ static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
+@@ -38,6 +45,10 @@ static ssize_t state_store(struct device
+ pm_message_t state;
+ int error = -EINVAL;
+
++ /* disallow incomplete suspend sequences */
++ if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
++ return error;
++
+ state.event = PM_EVENT_SUSPEND;
+ /* Older apps expected to write "3" here - confused with PCI D3 */
+ if ((n == 1) && !strcmp(buf, "3"))
+@@ -57,6 +68,8 @@ static ssize_t state_store(struct device
+ static DEVICE_ATTR(state, 0644, state_show, state_store);
+
+
++#endif /* CONFIG_PM_SYSFS_DEPRECATED */
++
+ /*
+ * wakeup - Report/change current wakeup option for device
+ *
+@@ -130,7 +143,9 @@ static DEVICE_ATTR(wakeup, 0644, wake_sh
+
+
+ static struct attribute * power_attrs[] = {
++#ifdef CONFIG_PM_SYSFS_DEPRECATED
+ &dev_attr_state.attr,
++#endif
+ &dev_attr_wakeup.attr,
+ NULL,
+ };
+diff --git a/drivers/base/topology.c b/drivers/base/topology.c
+index 3ef9d51..28dccb7 100644
+--- a/drivers/base/topology.c
++++ b/drivers/base/topology.c
+@@ -97,8 +97,7 @@ static struct attribute_group topology_a
+ /* Add/Remove cpu_topology interface for CPU device */
+ static int __cpuinit topology_add_dev(struct sys_device * sys_dev)
+ {
+- sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
+- return 0;
++ return sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
+ }
+
+ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
+diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
+index 4cd23c3..742d074 100644
+--- a/drivers/block/DAC960.c
++++ b/drivers/block/DAC960.c
+@@ -770,7 +770,7 @@ static void DAC960_P_QueueCommand(DAC960
+ static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
+ {
+ DAC960_Controller_T *Controller = Command->Controller;
+- DECLARE_COMPLETION(Completion);
++ DECLARE_COMPLETION_ONSTACK(Completion);
+ unsigned long flags;
+ Command->Completion = &Completion;
+
+@@ -2698,8 +2698,7 @@ DAC960_DetectController(struct pci_dev *
+ {
+ struct DAC960_privdata *privdata =
+ (struct DAC960_privdata *)entry->driver_data;
+- irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *) =
+- privdata->InterruptHandler;
++ irq_handler_t InterruptHandler = privdata->InterruptHandler;
+ unsigned int MemoryWindowSize = privdata->MemoryWindowSize;
+ DAC960_Controller_T *Controller = NULL;
+ unsigned char DeviceFunction = PCI_Device->devfn;
+@@ -3331,7 +3330,7 @@ static int DAC960_process_queue(DAC960_C
+ Command->DmaDirection = PCI_DMA_TODEVICE;
+ Command->CommandType = DAC960_WriteCommand;
+ }
+- Command->Completion = Request->waiting;
++ Command->Completion = Request->end_io_data;
+ Command->LogicalDriveNumber = (long)Request->rq_disk->private_data;
+ Command->BlockNumber = Request->sector;
+ Command->BlockCount = Request->nr_sectors;
+@@ -5253,10 +5252,9 @@ static void DAC960_V2_ProcessCompletedCo
+ */
+
+ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+ unsigned long flags;
+@@ -5295,10 +5293,9 @@ static irqreturn_t DAC960_GEM_InterruptH
+ */
+
+ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+ unsigned long flags;
+@@ -5338,10 +5335,9 @@ static irqreturn_t DAC960_BA_InterruptHa
+ */
+
+ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+ unsigned long flags;
+@@ -5381,10 +5377,9 @@ static irqreturn_t DAC960_LP_InterruptHa
+ */
+
+ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+ unsigned long flags;
+@@ -5420,10 +5415,9 @@ static irqreturn_t DAC960_LA_InterruptHa
+ */
+
+ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+ unsigned long flags;
+@@ -5459,10 +5453,9 @@ static irqreturn_t DAC960_PG_InterruptHa
+ */
+
+ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ unsigned long flags;
+
+@@ -5498,10 +5491,9 @@ static irqreturn_t DAC960_PD_InterruptHa
+ */
+
+ static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel,
+- void *DeviceIdentifier,
+- struct pt_regs *InterruptRegisters)
++ void *DeviceIdentifier)
+ {
+- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
++ DAC960_Controller_T *Controller = DeviceIdentifier;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ unsigned long flags;
+
+@@ -7115,7 +7107,7 @@ static struct pci_device_id DAC960_id_ta
+ {
+ .vendor = PCI_VENDOR_ID_MYLEX,
+ .device = PCI_DEVICE_ID_MYLEX_DAC960_GEM,
+- .subvendor = PCI_ANY_ID,
++ .subvendor = PCI_VENDOR_ID_MYLEX,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (unsigned long) &DAC960_GEM_privdata,
+ },
+diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
+index a82f37f..6148073 100644
+--- a/drivers/block/DAC960.h
++++ b/drivers/block/DAC960.h
+@@ -71,7 +71,7 @@
+ Define a Boolean data type.
+ */
+
+-typedef enum { false, true } __attribute__ ((packed)) boolean;
++typedef bool boolean;
+
+
+ /*
+@@ -2175,7 +2175,7 @@ static char
+ struct DAC960_privdata {
+ DAC960_HardwareType_T HardwareType;
+ DAC960_FirmwareType_T FirmwareType;
+- irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *);
++ irq_handler_t InterruptHandler;
+ unsigned int MemoryWindowSize;
+ };
+
+@@ -4379,8 +4379,8 @@ static inline void DAC960_P_To_PD_Transl
+ static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState)
+ {
+ memcpy(DeviceState + 2, DeviceState + 3, 1);
+- memcpy(DeviceState + 4, DeviceState + 5, 2);
+- memcpy(DeviceState + 6, DeviceState + 8, 4);
++ memmove(DeviceState + 4, DeviceState + 5, 2);
++ memmove(DeviceState + 6, DeviceState + 8, 4);
+ }
+
+ static inline
+@@ -4412,12 +4412,12 @@ static void DAC960_FinalizeController(DA
+ static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
+ static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *);
+ static void DAC960_RequestFunction(struct request_queue *);
+-static irqreturn_t DAC960_BA_InterruptHandler(int, void *, struct pt_regs *);
+-static irqreturn_t DAC960_LP_InterruptHandler(int, void *, struct pt_regs *);
+-static irqreturn_t DAC960_LA_InterruptHandler(int, void *, struct pt_regs *);
+-static irqreturn_t DAC960_PG_InterruptHandler(int, void *, struct pt_regs *);
+-static irqreturn_t DAC960_PD_InterruptHandler(int, void *, struct pt_regs *);
+-static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *);
++static irqreturn_t DAC960_BA_InterruptHandler(int, void *);
++static irqreturn_t DAC960_LP_InterruptHandler(int, void *);
++static irqreturn_t DAC960_LA_InterruptHandler(int, void *);
++static irqreturn_t DAC960_PG_InterruptHandler(int, void *);
++static irqreturn_t DAC960_PD_InterruptHandler(int, void *);
++static irqreturn_t DAC960_P_InterruptHandler(int, void *);
+ static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
+ static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
+ static void DAC960_MonitoringTimerFunction(unsigned long);
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index b5382ce..17dc222 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -2,6 +2,8 @@
+ # Block device driver configuration
+ #
+
++if BLOCK
++
+ menu "Block devices"
+
+ config BLK_DEV_FD
+@@ -205,8 +207,7 @@ config BLK_DEV_UMEM
+ module will be called umem.
+
+ The umem driver has not yet been allocated a MAJOR number, so
+- one is chosen dynamically. Use "devfs" or look in /proc/devices
+- for the device number
++ one is chosen dynamically.
+
+ config BLK_DEV_UBD
+ bool "Virtual block device"
+@@ -405,7 +406,7 @@ config BLK_DEV_RAM_BLOCKSIZE
+ depends on BLK_DEV_RAM
+ default "1024"
+ help
+- The default value is 1024 kilobytes. PAGE_SIZE is a much more
++ The default value is 1024 bytes. PAGE_SIZE is a much more
+ efficient choice however. The default is kept to ensure initrd
+ setups function - apparently needed by the rd_load_image routine
+ that supposes the filesystem in the image uses a 1024 blocksize.
+@@ -468,3 +469,5 @@ config ATA_OVER_ETH
+ devices like the Coraid EtherDrive (R) Storage Blade.
+
+ endmenu
++
++endif
+diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
+index 0b80fbb..706cdc6 100644
+--- a/drivers/block/acsi.c
++++ b/drivers/block/acsi.c
+@@ -346,7 +346,7 @@ static int acsicmd_dma( const char *cmd,
+ rwflag, int enable);
+ static int acsi_reqsense( char *buffer, int targ, int lun);
+ static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip);
+-static irqreturn_t acsi_interrupt (int irq, void *data, struct pt_regs *fp);
++static irqreturn_t acsi_interrupt (int irq, void *data);
+ static void unexpected_acsi_interrupt( void );
+ static void bad_rw_intr( void );
+ static void read_intr( void );
+@@ -726,7 +726,7 @@ static void acsi_print_error(const unsig
+ *
+ *******************************************************************/
+
+-static irqreturn_t acsi_interrupt(int irq, void *data, struct pt_regs *fp )
++static irqreturn_t acsi_interrupt(int irq, void *data )
+
+ { void (*acsi_irq_handler)(void) = do_acsi;
+
+diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
+index 4030a8f..8e41c87 100644
+--- a/drivers/block/acsi_slm.c
++++ b/drivers/block/acsi_slm.c
+@@ -246,7 +246,7 @@ static int slm_getstats( char *buffer, i
+ static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t
+ *ppos );
+ static void start_print( int device );
+-static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp);
++static irqreturn_t slm_interrupt(int irc, void *data);
+ static void slm_test_ready( unsigned long dummy );
+ static void set_dma_addr( unsigned long paddr );
+ static unsigned long get_dma_addr( void );
+@@ -452,7 +452,7 @@ static void start_print( int device )
+
+ /* Only called when an error happened or at the end of a page */
+
+-static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp)
++static irqreturn_t slm_interrupt(int irc, void *data)
+
+ { unsigned long addr;
+ int stat;
+diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
+index 2641597..5d65621 100644
+--- a/drivers/block/amiflop.c
++++ b/drivers/block/amiflop.c
+@@ -209,7 +209,7 @@ static int fd_device[4] = { 0, 0, 0, 0 }
+
+ /* Milliseconds timer */
+
+-static irqreturn_t ms_isr(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t ms_isr(int irq, void *dummy)
+ {
+ ms_busy = -1;
+ wake_up(&ms_wait);
+@@ -560,7 +560,7 @@ static unsigned long fd_get_drive_id(int
+ return (id);
+ }
+
+-static irqreturn_t fd_block_done(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t fd_block_done(int irq, void *dummy)
+ {
+ if (block_flag)
+ custom.dsklen = 0x4000;
+@@ -1709,10 +1709,13 @@ static struct kobject *floppy_find(dev_t
+ return get_disk(unit[drive].gendisk);
+ }
+
+-int __init amiga_floppy_init(void)
++static int __init amiga_floppy_init(void)
+ {
+ int i, ret;
+
++ if (!MACH_IS_AMIGA)
++ return -ENXIO;
++
+ if (!AMIGAHW_PRESENT(AMI_FLOPPY))
+ return -ENXIO;
+
+@@ -1809,15 +1812,9 @@ out_blkdev:
+ return ret;
+ }
+
++module_init(amiga_floppy_init);
+ #ifdef MODULE
+
+-int init_module(void)
+-{
+- if (!MACH_IS_AMIGA)
+- return -ENXIO;
+- return amiga_floppy_init();
+-}
+-
+ #if 0 /* not safe to unload */
+ void cleanup_module(void)
+ {
+diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
+index 6eebcb7..6d11122 100644
+--- a/drivers/block/aoe/aoe.h
++++ b/drivers/block/aoe/aoe.h
+@@ -1,5 +1,5 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+-#define VERSION "22"
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
++#define VERSION "32"
+ #define AOE_MAJOR 152
+ #define DEVICE_NAME "aoe"
+
+@@ -65,7 +65,7 @@ struct aoe_atahdr {
+ struct aoe_cfghdr {
+ __be16 bufcnt;
+ __be16 fwver;
+- unsigned char res;
++ unsigned char scnt;
+ unsigned char aoeccmd;
+ unsigned char cslen[2];
+ };
+@@ -78,12 +78,14 @@ enum {
+ DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */
+ DEVFL_PAUSE = (1<<5),
+ DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
++ DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */
++ DEVFL_KICKME = (1<<8),
+
+ BUFFL_FAIL = 1,
+ };
+
+ enum {
+- MAXATADATA = 1024,
++ DEFAULTBCNT = 2 * 512, /* 2 sectors */
+ NPERSHELF = 16, /* number of slots per shelf address */
+ FREETAG = -1,
+ MIN_BUFS = 8,
+@@ -107,11 +109,9 @@ struct frame {
+ ulong waited;
+ struct buf *buf;
+ char *bufaddr;
+- int writedatalen;
+- int ndata;
+-
+- /* largest possible */
+- unsigned char data[sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr)];
++ ulong bcnt;
++ sector_t lba;
++ struct sk_buff *skb;
+ };
+
+ struct aoedev {
+@@ -121,9 +121,12 @@ struct aoedev {
+ ulong sysminor;
+ ulong aoemajor;
+ ulong aoeminor;
+- ulong nopen; /* (bd_openers isn't available without sleeping) */
+- ulong rttavg; /* round trip average of requests/responses */
++ u16 nopen; /* (bd_openers isn't available without sleeping) */
++ u16 lasttag; /* last tag sent */
++ u16 rttavg; /* round trip average of requests/responses */
++ u16 mintimer;
+ u16 fw_ver; /* version of blade's firmware */
++ u16 maxbcnt;
+ struct work_struct work;/* disk create work struct */
+ struct gendisk *gd;
+ request_queue_t blkq;
+@@ -137,8 +140,8 @@ struct aoedev {
+ mempool_t *bufpool; /* for deadlock-free Buf allocation */
+ struct list_head bufq; /* queue of bios to work on */
+ struct buf *inprocess; /* the one we're currently working on */
+- ulong lasttag; /* last tag sent */
+- ulong nframes; /* number of frames below */
++ ushort lostjumbo;
++ ushort nframes; /* number of frames below */
+ struct frame *frames;
+ };
+
+@@ -157,6 +160,7 @@ void aoecmd_cfg(ushort aoemajor, unsigne
+ void aoecmd_ata_rsp(struct sk_buff *);
+ void aoecmd_cfg_rsp(struct sk_buff *);
+ void aoecmd_sleepwork(void *vp);
++struct sk_buff *new_skb(ulong);
+
+ int aoedev_init(void);
+ void aoedev_exit(void);
+diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
+index 393b86a..d433f27 100644
+--- a/drivers/block/aoe/aoeblk.c
++++ b/drivers/block/aoe/aoeblk.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+ /*
+ * aoeblk.c
+ * block device routines
+@@ -14,7 +14,6 @@
+
+ static kmem_cache_t *buf_pool_cache;
+
+-/* add attributes for our block devices in sysfs */
+ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
+ {
+ struct aoedev *d = disk->private_data;
+@@ -64,21 +63,26 @@ static struct disk_attribute disk_attr_f
+ .show = aoedisk_show_fwver
+ };
+
+-static void
++static struct attribute *aoe_attrs[] = {
++ &disk_attr_state.attr,
++ &disk_attr_mac.attr,
++ &disk_attr_netif.attr,
++ &disk_attr_fwver.attr,
++};
++
++static const struct attribute_group attr_group = {
++ .attrs = aoe_attrs,
++};
++
++static int
+ aoedisk_add_sysfs(struct aoedev *d)
+ {
+- sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr);
+- sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr);
+- sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr);
+- sysfs_create_file(&d->gd->kobj, &disk_attr_fwver.attr);
++ return sysfs_create_group(&d->gd->kobj, &attr_group);
+ }
+ void
+ aoedisk_rm_sysfs(struct aoedev *d)
+ {
+- sysfs_remove_link(&d->gd->kobj, "state");
+- sysfs_remove_link(&d->gd->kobj, "mac");
+- sysfs_remove_link(&d->gd->kobj, "netif");
+- sysfs_remove_link(&d->gd->kobj, "firmware-version");
++ sysfs_remove_group(&d->gd->kobj, &attr_group);
+ }
+
+ static int
+@@ -132,8 +136,7 @@ aoeblk_make_request(request_queue_t *q,
+ d = bio->bi_bdev->bd_disk->private_data;
+ buf = mempool_alloc(d->bufpool, GFP_NOIO);
+ if (buf == NULL) {
+- printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation "
+- "failure\n");
++ printk(KERN_INFO "aoe: buf allocation failure\n");
+ bio_endio(bio, bio->bi_size, -ENOMEM);
+ return 0;
+ }
+@@ -143,14 +146,15 @@ aoeblk_make_request(request_queue_t *q,
+ buf->bio = bio;
+ buf->resid = bio->bi_size;
+ buf->sector = bio->bi_sector;
+- buf->bv = buf->bio->bi_io_vec;
++ buf->bv = &bio->bi_io_vec[bio->bi_idx];
++ WARN_ON(buf->bv->bv_len == 0);
+ buf->bv_resid = buf->bv->bv_len;
+ buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
+
+ spin_lock_irqsave(&d->lock, flags);
+
+ if ((d->flags & DEVFL_UP) == 0) {
+- printk(KERN_INFO "aoe: aoeblk_make_request: device %ld.%ld is not up\n",
++ printk(KERN_INFO "aoe: device %ld.%ld is not up\n",
+ d->aoemajor, d->aoeminor);
+ spin_unlock_irqrestore(&d->lock, flags);
+ mempool_free(buf, d->bufpool);
+@@ -176,7 +180,7 @@ aoeblk_getgeo(struct block_device *bdev,
+ struct aoedev *d = bdev->bd_disk->private_data;
+
+ if ((d->flags & DEVFL_UP) == 0) {
+- printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n");
++ printk(KERN_ERR "aoe: disk not up\n");
+ return -ENODEV;
+ }
+
+@@ -203,8 +207,8 @@ aoeblk_gdalloc(void *vp)
+
+ gd = alloc_disk(AOE_PARTITIONS);
+ if (gd == NULL) {
+- printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
+- "structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
++ printk(KERN_ERR "aoe: cannot allocate disk structure for %ld.%ld\n",
++ d->aoemajor, d->aoeminor);
+ spin_lock_irqsave(&d->lock, flags);
+ d->flags &= ~DEVFL_GDALLOC;
+ spin_unlock_irqrestore(&d->lock, flags);
+@@ -213,8 +217,8 @@ aoeblk_gdalloc(void *vp)
+
+ d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
+ if (d->bufpool == NULL) {
+- printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool "
+- "for %ld.%ld\n", d->aoemajor, d->aoeminor);
++ printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%ld\n",
++ d->aoemajor, d->aoeminor);
+ put_disk(gd);
+ spin_lock_irqsave(&d->lock, flags);
+ d->flags &= ~DEVFL_GDALLOC;
+diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
+index 1bc1cf9..e22b4c9 100644
+--- a/drivers/block/aoe/aoechr.c
++++ b/drivers/block/aoe/aoechr.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+ /*
+ * aoechr.c
+ * AoE character device driver
+@@ -15,7 +15,6 @@ enum {
+ MINOR_INTERFACES,
+ MINOR_REVALIDATE,
+ MSGSZ = 2048,
+- NARGS = 10,
+ NMSG = 100, /* message backlog to retain */
+ };
+
+@@ -56,9 +55,8 @@ static int
+ interfaces(const char __user *str, size_t size)
+ {
+ if (set_aoe_iflist(str, size)) {
+- printk(KERN_CRIT
+- "%s: could not set interface list: %s\n",
+- __FUNCTION__, "too many interfaces");
++ printk(KERN_ERR
++ "aoe: could not set interface list: too many interfaces\n");
+ return -EINVAL;
+ }
+ return 0;
+@@ -81,8 +79,7 @@ revalidate(const char __user *str, size_
+ /* should be e%d.%d format */
+ n = sscanf(buf, "e%d.%d", &major, &minor);
+ if (n != 2) {
+- printk(KERN_ERR "aoe: %s: invalid device specification\n",
+- __FUNCTION__);
++ printk(KERN_ERR "aoe: invalid device specification\n");
+ return -EINVAL;
+ }
+ d = aoedev_by_aoeaddr(major, minor);
+@@ -90,6 +87,7 @@ revalidate(const char __user *str, size_
+ return -EINVAL;
+
+ spin_lock_irqsave(&d->lock, flags);
++ d->flags &= ~DEVFL_MAXBCNT;
+ d->flags |= DEVFL_PAUSE;
+ spin_unlock_irqrestore(&d->lock, flags);
+ aoecmd_cfg(major, minor);
+@@ -116,7 +114,7 @@ bail: spin_unlock_irqrestore(&emsgs_loc
+
+ mp = kmalloc(n, GFP_ATOMIC);
+ if (mp == NULL) {
+- printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ld\n", n);
++ printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n);
+ goto bail;
+ }
+
+@@ -141,7 +139,7 @@ aoechr_write(struct file *filp, const ch
+
+ switch ((unsigned long) filp->private_data) {
+ default:
+- printk(KERN_INFO "aoe: aoechr_write: can't write to that file.\n");
++ printk(KERN_INFO "aoe: can't write to that file.\n");
+ break;
+ case MINOR_DISCOVER:
+ ret = discover();
+@@ -250,7 +248,7 @@ aoechr_init(void)
+
+ n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
+ if (n < 0) {
+- printk(KERN_ERR "aoe: aoechr_init: can't register char device\n");
++ printk(KERN_ERR "aoe: can't register char device\n");
+ return n;
+ }
+ sema_init(&emsgs_sema, 0);
+diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
+index 39da28d..8a13b1a 100644
+--- a/drivers/block/aoe/aoecmd.c
++++ b/drivers/block/aoe/aoecmd.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+ /*
+ * aoecmd.c
+ * Filesystem request handling methods
+@@ -15,17 +15,19 @@
+ #define TIMERTICK (HZ / 10)
+ #define MINTIMER (2 * TIMERTICK)
+ #define MAXTIMER (HZ << 1)
+-#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */
+
+-static struct sk_buff *
+-new_skb(struct net_device *if_dev, ulong len)
++static int aoe_deadsecs = 60 * 3;
++module_param(aoe_deadsecs, int, 0644);
++MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev.");
++
++struct sk_buff *
++new_skb(ulong len)
+ {
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb) {
+ skb->nh.raw = skb->mac.raw = skb->data;
+- skb->dev = if_dev;
+ skb->protocol = __constant_htons(ETH_P_AOE);
+ skb->priority = 0;
+ skb_put(skb, len);
+@@ -40,29 +42,6 @@ new_skb(struct net_device *if_dev, ulong
+ return skb;
+ }
+
+-static struct sk_buff *
+-skb_prepare(struct aoedev *d, struct frame *f)
+-{
+- struct sk_buff *skb;
+- char *p;
+-
+- skb = new_skb(d->ifp, f->ndata + f->writedatalen);
+- if (!skb) {
+- printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n");
+- return NULL;
+- }
+-
+- p = skb->mac.raw;
+- memcpy(p, f->data, f->ndata);
+-
+- if (f->writedatalen) {
+- p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr);
+- memcpy(p, f->bufaddr, f->writedatalen);
+- }
+-
+- return skb;
+-}
+-
+ static struct frame *
+ getframe(struct aoedev *d, int tag)
+ {
+@@ -107,6 +86,17 @@ aoehdr_atainit(struct aoedev *d, struct
+ return host_tag;
+ }
+
++static inline void
++put_lba(struct aoe_atahdr *ah, sector_t lba)
++{
++ ah->lba0 = lba;
++ ah->lba1 = lba >>= 8;
++ ah->lba2 = lba >>= 8;
++ ah->lba3 = lba >>= 8;
++ ah->lba4 = lba >>= 8;
++ ah->lba5 = lba >>= 8;
++}
++
+ static void
+ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
+ {
+@@ -125,29 +115,27 @@ aoecmd_ata_rw(struct aoedev *d, struct f
+
+ sector = buf->sector;
+ bcnt = buf->bv_resid;
+- if (bcnt > MAXATADATA)
+- bcnt = MAXATADATA;
++ if (bcnt > d->maxbcnt)
++ bcnt = d->maxbcnt;
+
+ /* initialize the headers & frame */
+- h = (struct aoe_hdr *) f->data;
++ skb = f->skb;
++ h = (struct aoe_hdr *) skb->mac.raw;
+ ah = (struct aoe_atahdr *) (h+1);
+- f->ndata = sizeof *h + sizeof *ah;
+- memset(h, 0, f->ndata);
++ skb->len = sizeof *h + sizeof *ah;
++ memset(h, 0, ETH_ZLEN);
+ f->tag = aoehdr_atainit(d, h);
+ f->waited = 0;
+ f->buf = buf;
+ f->bufaddr = buf->bufaddr;
++ f->bcnt = bcnt;
++ f->lba = sector;
+
+ /* set up ata header */
+ ah->scnt = bcnt >> 9;
+- ah->lba0 = sector;
+- ah->lba1 = sector >>= 8;
+- ah->lba2 = sector >>= 8;
+- ah->lba3 = sector >>= 8;
++ put_lba(ah, sector);
+ if (d->flags & DEVFL_EXT) {
+ ah->aflags |= AOEAFL_EXT;
+- ah->lba4 = sector >>= 8;
+- ah->lba5 = sector >>= 8;
+ } else {
+ extbit = 0;
+ ah->lba3 &= 0x0f;
+@@ -155,11 +143,14 @@ aoecmd_ata_rw(struct aoedev *d, struct f
+ }
+
+ if (bio_data_dir(buf->bio) == WRITE) {
++ skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
++ offset_in_page(f->bufaddr), bcnt);
+ ah->aflags |= AOEAFL_WRITE;
+- f->writedatalen = bcnt;
++ skb->len += bcnt;
++ skb->data_len = bcnt;
+ } else {
++ skb->len = ETH_ZLEN;
+ writebit = 0;
+- f->writedatalen = 0;
+ }
+
+ ah->cmdstat = WIN_READ | writebit | extbit;
+@@ -168,26 +159,27 @@ aoecmd_ata_rw(struct aoedev *d, struct f
+ buf->nframesout += 1;
+ buf->bufaddr += bcnt;
+ buf->bv_resid -= bcnt;
+-/* printk(KERN_INFO "aoe: bv_resid=%ld\n", buf->bv_resid); */
++/* printk(KERN_DEBUG "aoe: bv_resid=%ld\n", buf->bv_resid); */
+ buf->resid -= bcnt;
+ buf->sector += bcnt >> 9;
+ if (buf->resid == 0) {
+ d->inprocess = NULL;
+ } else if (buf->bv_resid == 0) {
+ buf->bv++;
++ WARN_ON(buf->bv->bv_len == 0);
+ buf->bv_resid = buf->bv->bv_len;
+ buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
+ }
+
+- skb = skb_prepare(d, f);
+- if (skb) {
+- skb->next = NULL;
+- if (d->sendq_hd)
+- d->sendq_tl->next = skb;
+- else
+- d->sendq_hd = skb;
+- d->sendq_tl = skb;
+- }
++ skb->dev = d->ifp;
++ skb = skb_clone(skb, GFP_ATOMIC);
++ if (skb == NULL)
++ return;
++ if (d->sendq_hd)
++ d->sendq_tl->next = skb;
++ else
++ d->sendq_hd = skb;
++ d->sendq_tl = skb;
+ }
+
+ /* some callers cannot sleep, and they can call this function,
+@@ -209,11 +201,12 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
+ if (!is_aoe_netif(ifp))
+ continue;
+
+- skb = new_skb(ifp, sizeof *h + sizeof *ch);
++ skb = new_skb(sizeof *h + sizeof *ch);
+ if (skb == NULL) {
+- printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
++ printk(KERN_INFO "aoe: skb alloc failure\n");
+ continue;
+ }
++ skb->dev = ifp;
+ if (sl_tail == NULL)
+ sl_tail = skb;
+ h = (struct aoe_hdr *) skb->mac.raw;
+@@ -237,6 +230,29 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
+ return sl;
+ }
+
++static struct frame *
++freeframe(struct aoedev *d)
++{
++ struct frame *f, *e;
++ int n = 0;
++
++ f = d->frames;
++ e = f + d->nframes;
++ for (; f<e; f++) {
++ if (f->tag != FREETAG)
++ continue;
++ if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) {
++ skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
++ return f;
++ }
++ n++;
++ }
++ if (n == d->nframes) /* wait for network layer */
++ d->flags |= DEVFL_KICKME;
++
++ return NULL;
++}
++
+ /* enters with d->lock held */
+ void
+ aoecmd_work(struct aoedev *d)
+@@ -252,7 +268,7 @@ aoecmd_work(struct aoedev *d)
+ }
+
+ loop:
+- f = getframe(d, FREETAG);
++ f = freeframe(d);
+ if (f == NULL)
+ return;
+ if (d->inprocess == NULL) {
+@@ -260,7 +276,7 @@ loop:
+ return;
+ buf = container_of(d->bufq.next, struct buf, bufs);
+ list_del(d->bufq.next);
+-/*printk(KERN_INFO "aoecmd_work: bi_size=%ld\n", buf->bio->bi_size); */
++/*printk(KERN_DEBUG "aoe: bi_size=%ld\n", buf->bio->bi_size); */
+ d->inprocess = buf;
+ }
+ aoecmd_ata_rw(d, f);
+@@ -272,6 +288,7 @@ rexmit(struct aoedev *d, struct frame *f
+ {
+ struct sk_buff *skb;
+ struct aoe_hdr *h;
++ struct aoe_atahdr *ah;
+ char buf[128];
+ u32 n;
+
+@@ -283,21 +300,41 @@ rexmit(struct aoedev *d, struct frame *f
+ d->aoemajor, d->aoeminor, f->tag, jiffies, n);
+ aoechr_error(buf);
+
+- h = (struct aoe_hdr *) f->data;
++ skb = f->skb;
++ h = (struct aoe_hdr *) skb->mac.raw;
++ ah = (struct aoe_atahdr *) (h+1);
+ f->tag = n;
+ h->tag = cpu_to_be32(n);
+ memcpy(h->dst, d->addr, sizeof h->dst);
+ memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
+
+- skb = skb_prepare(d, f);
+- if (skb) {
+- skb->next = NULL;
+- if (d->sendq_hd)
+- d->sendq_tl->next = skb;
+- else
+- d->sendq_hd = skb;
+- d->sendq_tl = skb;
++ n = DEFAULTBCNT / 512;
++ if (ah->scnt > n) {
++ ah->scnt = n;
++ if (ah->aflags & AOEAFL_WRITE) {
++ skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
++ offset_in_page(f->bufaddr), DEFAULTBCNT);
++ skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT;
++ skb->data_len = DEFAULTBCNT;
++ }
++ if (++d->lostjumbo > (d->nframes << 1))
++ if (d->maxbcnt != DEFAULTBCNT) {
++ printk(KERN_INFO "aoe: e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n",
++ d->aoemajor, d->aoeminor, d->ifp->name);
++ d->maxbcnt = DEFAULTBCNT;
++ d->flags |= DEVFL_MAXBCNT;
++ }
+ }
++
++ skb->dev = d->ifp;
++ skb = skb_clone(skb, GFP_ATOMIC);
++ if (skb == NULL)
++ return;
++ if (d->sendq_hd)
++ d->sendq_tl->next = skb;
++ else
++ d->sendq_hd = skb;
++ d->sendq_tl = skb;
+ }
+
+ static int
+@@ -340,13 +377,17 @@ rexmit_timer(ulong vp)
+ if (f->tag != FREETAG && tsince(f->tag) >= timeout) {
+ n = f->waited += timeout;
+ n /= HZ;
+- if (n > MAXWAIT) { /* waited too long. device failure. */
++ if (n > aoe_deadsecs) { /* waited too long for response */
+ aoedev_downdev(d);
+ break;
+ }
+ rexmit(d, f);
+ }
+ }
++ if (d->flags & DEVFL_KICKME) {
++ d->flags &= ~DEVFL_KICKME;
++ aoecmd_work(d);
++ }
+
+ sl = d->sendq_hd;
+ d->sendq_hd = d->sendq_tl = NULL;
+@@ -431,8 +472,8 @@ ataid_complete(struct aoedev *d, unsigne
+ }
+
+ if (d->ssize != ssize)
+- printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
+- "sectors\n", (unsigned long long)mac_addr(d->addr),
++ printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n",
++ (unsigned long long)mac_addr(d->addr),
+ d->aoemajor, d->aoeminor,
+ d->fw_ver, (long long)ssize);
+ d->ssize = ssize;
+@@ -442,11 +483,9 @@ ataid_complete(struct aoedev *d, unsigne
+ d->flags |= DEVFL_NEWSIZE;
+ } else {
+ if (d->flags & DEVFL_GDALLOC) {
+- printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n",
+- __FUNCTION__,
+- "can't schedule work for",
++ printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n",
+ d->aoemajor, d->aoeminor,
+- "it's already on! (This really shouldn't happen).\n");
++ "it's already on! This shouldn't happen.\n");
+ return;
+ }
+ d->flags |= DEVFL_GDALLOC;
+@@ -460,8 +499,15 @@ calc_rttavg(struct aoedev *d, int rtt)
+ register long n;
+
+ n = rtt;
+- if (n < MINTIMER)
+- n = MINTIMER;
++ if (n < 0) {
++ n = -rtt;
++ if (n < MINTIMER)
++ n = MINTIMER;
++ else if (n > MAXTIMER)
++ n = MAXTIMER;
++ d->mintimer += (n - d->mintimer) >> 1;
++ } else if (n < d->mintimer)
++ n = d->mintimer;
+ else if (n > MAXTIMER)
+ n = MAXTIMER;
+
+@@ -474,7 +520,7 @@ void
+ aoecmd_ata_rsp(struct sk_buff *skb)
+ {
+ struct aoedev *d;
+- struct aoe_hdr *hin;
++ struct aoe_hdr *hin, *hout;
+ struct aoe_atahdr *ahin, *ahout;
+ struct frame *f;
+ struct buf *buf;
+@@ -497,8 +543,10 @@ aoecmd_ata_rsp(struct sk_buff *skb)
+
+ spin_lock_irqsave(&d->lock, flags);
+
+- f = getframe(d, be32_to_cpu(hin->tag));
++ n = be32_to_cpu(hin->tag);
++ f = getframe(d, n);
+ if (f == NULL) {
++ calc_rttavg(d, -tsince(n));
+ spin_unlock_irqrestore(&d->lock, flags);
+ snprintf(ebuf, sizeof ebuf,
+ "%15s e%d.%d tag=%08x@%08lx\n",
+@@ -514,26 +562,27 @@ aoecmd_ata_rsp(struct sk_buff *skb)
+ calc_rttavg(d, tsince(f->tag));
+
+ ahin = (struct aoe_atahdr *) (hin+1);
+- ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
++ hout = (struct aoe_hdr *) f->skb->mac.raw;
++ ahout = (struct aoe_atahdr *) (hout+1);
+ buf = f->buf;
+
+ if (ahout->cmdstat == WIN_IDENTIFY)
+ d->flags &= ~DEVFL_PAUSE;
+ if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
+- printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
+- "stat=%2.2Xh from e%ld.%ld\n",
++ printk(KERN_ERR
++ "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n",
+ ahout->cmdstat, ahin->cmdstat,
+ d->aoemajor, d->aoeminor);
+ if (buf)
+ buf->flags |= BUFFL_FAIL;
+ } else {
++ n = ahout->scnt << 9;
+ switch (ahout->cmdstat) {
+ case WIN_READ:
+ case WIN_READ_EXT:
+- n = ahout->scnt << 9;
+ if (skb->len - sizeof *hin - sizeof *ahin < n) {
+- printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt "
+- "ata data size in read. skb->len=%d\n",
++ printk(KERN_ERR
++ "aoe: runt data size in read. skb->len=%d\n",
+ skb->len);
+ /* fail frame f? just returning will rexmit. */
+ spin_unlock_irqrestore(&d->lock, flags);
+@@ -542,22 +591,49 @@ aoecmd_ata_rsp(struct sk_buff *skb)
+ memcpy(f->bufaddr, ahin+1, n);
+ case WIN_WRITE:
+ case WIN_WRITE_EXT:
++ if (f->bcnt -= n) {
++ skb = f->skb;
++ f->bufaddr += n;
++ put_lba(ahout, f->lba += ahout->scnt);
++ n = f->bcnt;
++ if (n > DEFAULTBCNT)
++ n = DEFAULTBCNT;
++ ahout->scnt = n >> 9;
++ if (ahout->aflags & AOEAFL_WRITE) {
++ skb_fill_page_desc(skb, 0,
++ virt_to_page(f->bufaddr),
++ offset_in_page(f->bufaddr), n);
++ skb->len = sizeof *hout + sizeof *ahout + n;
++ skb->data_len = n;
++ }
++ f->tag = newtag(d);
++ hout->tag = cpu_to_be32(f->tag);
++ skb->dev = d->ifp;
++ skb = skb_clone(skb, GFP_ATOMIC);
++ spin_unlock_irqrestore(&d->lock, flags);
++ if (skb)
++ aoenet_xmit(skb);
++ return;
++ }
++ if (n > DEFAULTBCNT)
++ d->lostjumbo = 0;
+ break;
+ case WIN_IDENTIFY:
+ if (skb->len - sizeof *hin - sizeof *ahin < 512) {
+- printk(KERN_INFO "aoe: aoecmd_ata_rsp: runt data size "
+- "in ataid. skb->len=%d\n", skb->len);
++ printk(KERN_INFO
++ "aoe: runt data size in ataid. skb->len=%d\n",
++ skb->len);
+ spin_unlock_irqrestore(&d->lock, flags);
+ return;
+ }
+ ataid_complete(d, (char *) (ahin+1));
+ break;
+ default:
+- printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
+- "outbound ata command %2.2Xh for %d.%d\n",
+- ahout->cmdstat,
+- be16_to_cpu(hin->major),
+- hin->minor);
++ printk(KERN_INFO
++ "aoe: unrecognized ata command %2.2Xh for %d.%d\n",
++ ahout->cmdstat,
++ be16_to_cpu(hin->major),
++ hin->minor);
+ }
+ }
+
+@@ -612,33 +688,32 @@ aoecmd_ata_id(struct aoedev *d)
+ struct frame *f;
+ struct sk_buff *skb;
+
+- f = getframe(d, FREETAG);
++ f = freeframe(d);
+ if (f == NULL) {
+- printk(KERN_CRIT "aoe: aoecmd_ata_id: can't get a frame. "
+- "This shouldn't happen.\n");
++ printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n");
+ return NULL;
+ }
+
+ /* initialize the headers & frame */
+- h = (struct aoe_hdr *) f->data;
++ skb = f->skb;
++ h = (struct aoe_hdr *) skb->mac.raw;
+ ah = (struct aoe_atahdr *) (h+1);
+- f->ndata = sizeof *h + sizeof *ah;
+- memset(h, 0, f->ndata);
++ skb->len = ETH_ZLEN;
++ memset(h, 0, ETH_ZLEN);
+ f->tag = aoehdr_atainit(d, h);
+ f->waited = 0;
+- f->writedatalen = 0;
+
+ /* set up ata header */
+ ah->scnt = 1;
+ ah->cmdstat = WIN_IDENTIFY;
+ ah->lba3 = 0xa0;
+
+- skb = skb_prepare(d, f);
++ skb->dev = d->ifp;
+
+ d->rttavg = MAXTIMER;
+ d->timer.function = rexmit_timer;
+
+- return skb;
++ return skb_clone(skb, GFP_ATOMIC);
+ }
+
+ void
+@@ -648,9 +723,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
+ struct aoe_hdr *h;
+ struct aoe_cfghdr *ch;
+ ulong flags, sysminor, aoemajor;
+- u16 bufcnt;
+ struct sk_buff *sl;
+ enum { MAXFRAMES = 16 };
++ u16 n;
+
+ h = (struct aoe_hdr *) skb->mac.raw;
+ ch = (struct aoe_cfghdr *) (h+1);
+@@ -661,26 +736,25 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
+ */
+ aoemajor = be16_to_cpu(h->major);
+ if (aoemajor == 0xfff) {
+- printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf "
+- "address is all ones. Check shelf dip switches\n");
++ printk(KERN_ERR "aoe: Warning: shelf address is all ones. "
++ "Check shelf dip switches.\n");
+ return;
+ }
+
+ sysminor = SYSMINOR(aoemajor, h->minor);
+ if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
+- printk(KERN_INFO
+- "aoe: e%ld.%d: minor number too large\n",
++ printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",
+ aoemajor, (int) h->minor);
+ return;
+ }
+
+- bufcnt = be16_to_cpu(ch->bufcnt);
+- if (bufcnt > MAXFRAMES) /* keep it reasonable */
+- bufcnt = MAXFRAMES;
++ n = be16_to_cpu(ch->bufcnt);
++ if (n > MAXFRAMES) /* keep it reasonable */
++ n = MAXFRAMES;
+
+- d = aoedev_by_sysminor_m(sysminor, bufcnt);
++ d = aoedev_by_sysminor_m(sysminor, n);
+ if (d == NULL) {
+- printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n");
++ printk(KERN_INFO "aoe: device sysminor_m failure\n");
+ return;
+ }
+
+@@ -689,6 +763,20 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
+ /* permit device to migrate mac and network interface */
+ d->ifp = skb->dev;
+ memcpy(d->addr, h->src, sizeof d->addr);
++ if (!(d->flags & DEVFL_MAXBCNT)) {
++ n = d->ifp->mtu;
++ n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr);
++ n /= 512;
++ if (n > ch->scnt)
++ n = ch->scnt;
++ n = n ? n * 512 : DEFAULTBCNT;
++ if (n != d->maxbcnt) {
++ printk(KERN_INFO
++ "aoe: e%ld.%ld: setting %d byte data frames on %s\n",
++ d->aoemajor, d->aoeminor, n, d->ifp->name);
++ d->maxbcnt = n;
++ }
++ }
+
+ /* don't change users' perspective */
+ if (d->nopen && !(d->flags & DEVFL_PAUSE)) {
+@@ -696,6 +784,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
+ return;
+ }
+ d->flags |= DEVFL_PAUSE; /* force pause */
++ d->mintimer = MINTIMER;
+ d->fw_ver = be16_to_cpu(ch->fwver);
+
+ /* check for already outstanding ataid */
+diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
+index ed4258a..6125921 100644
+--- a/drivers/block/aoe/aoedev.c
++++ b/drivers/block/aoe/aoedev.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+ /*
+ * aoedev.c
+ * AoE device utility functions; maintains device list.
+@@ -20,11 +20,8 @@ aoedev_isbusy(struct aoedev *d)
+ f = d->frames;
+ e = f + d->nframes;
+ do {
+- if (f->tag != FREETAG) {
+- printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n",
+- d->aoemajor, d->aoeminor);
++ if (f->tag != FREETAG)
+ return 1;
+- }
+ } while (++f < e);
+
+ return 0;
+@@ -66,22 +63,32 @@ aoedev_newdev(ulong nframes)
+ struct frame *f, *e;
+
+ d = kzalloc(sizeof *d, GFP_ATOMIC);
+- if (d == NULL)
+- return NULL;
+ f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
+- if (f == NULL) {
+- kfree(d);
++ switch (!d || !f) {
++ case 0:
++ d->nframes = nframes;
++ d->frames = f;
++ e = f + nframes;
++ for (; f<e; f++) {
++ f->tag = FREETAG;
++ f->skb = new_skb(ETH_ZLEN);
++ if (!f->skb)
++ break;
++ }
++ if (f == e)
++ break;
++ while (f > d->frames) {
++ f--;
++ dev_kfree_skb(f->skb);
++ }
++ default:
++ if (f)
++ kfree(f);
++ if (d)
++ kfree(d);
+ return NULL;
+ }
+-
+ INIT_WORK(&d->work, aoecmd_sleepwork, d);
+-
+- d->nframes = nframes;
+- d->frames = f;
+- e = f + nframes;
+- for (; f<e; f++)
+- f->tag = FREETAG;
+-
+ spin_lock_init(&d->lock);
+ init_timer(&d->timer);
+ d->timer.data = (ulong) d;
+@@ -114,6 +121,7 @@ aoedev_downdev(struct aoedev *d)
+ mempool_free(buf, d->bufpool);
+ bio_endio(bio, bio->bi_size, -EIO);
+ }
++ skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
+ }
+ d->inprocess = NULL;
+
+@@ -148,7 +156,7 @@ aoedev_by_sysminor_m(ulong sysminor, ulo
+ d = aoedev_newdev(bufcnt);
+ if (d == NULL) {
+ spin_unlock_irqrestore(&devlist_lock, flags);
+- printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
++ printk(KERN_INFO "aoe: aoedev_newdev failure.\n");
+ return NULL;
+ }
+ d->sysminor = sysminor;
+@@ -163,11 +171,19 @@ aoedev_by_sysminor_m(ulong sysminor, ulo
+ static void
+ aoedev_freedev(struct aoedev *d)
+ {
++ struct frame *f, *e;
++
+ if (d->gd) {
+ aoedisk_rm_sysfs(d);
+ del_gendisk(d->gd);
+ put_disk(d->gd);
+ }
++ f = d->frames;
++ e = f + d->nframes;
++ for (; f<e; f++) {
++ skb_shinfo(f->skb)->nr_frags = 0;
++ dev_kfree_skb(f->skb);
++ }
+ kfree(d->frames);
+ if (d->bufpool)
+ mempool_destroy(d->bufpool);
+diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c
+index de08491..a04b7d6 100644
+--- a/drivers/block/aoe/aoemain.c
++++ b/drivers/block/aoe/aoemain.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+ /*
+ * aoemain.c
+ * Module initialization routines, discover timer
+@@ -84,13 +84,11 @@ aoe_init(void)
+ goto net_fail;
+ ret = register_blkdev(AOE_MAJOR, DEVICE_NAME);
+ if (ret < 0) {
+- printk(KERN_ERR "aoe: aoeblk_init: can't register major\n");
++ printk(KERN_ERR "aoe: can't register major\n");
+ goto blkreg_fail;
+ }
+
+- printk(KERN_INFO
+- "aoe: aoe_init: AoE v%s initialised.\n",
+- VERSION);
++ printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION);
+ discover_timer(TINIT);
+ return 0;
+
+@@ -103,7 +101,7 @@ aoe_init(void)
+ chr_fail:
+ aoedev_exit();
+
+- printk(KERN_INFO "aoe: aoe_init: initialisation failure.\n");
++ printk(KERN_INFO "aoe: initialisation failure.\n");
+ return ret;
+ }
+
+diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
+index c1434ed..9626e0f 100644
+--- a/drivers/block/aoe/aoenet.c
++++ b/drivers/block/aoe/aoenet.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
++/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+ /*
+ * aoenet.c
+ * Ethernet portion of AoE driver
+@@ -74,7 +74,7 @@ set_aoe_iflist(const char __user *user_s
+ return -EINVAL;
+
+ if (copy_from_user(aoe_iflist, user_str, size)) {
+- printk(KERN_INFO "aoe: %s: copy from user failed\n", __FUNCTION__);
++ printk(KERN_INFO "aoe: copy from user failed\n");
+ return -EFAULT;
+ }
+ aoe_iflist[size] = 0x00;
+@@ -132,8 +132,7 @@ aoenet_rcv(struct sk_buff *skb, struct n
+ if (n > NECODES)
+ n = 0;
+ if (net_ratelimit())
+- printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; "
+- "ecode=%d '%s'\n",
++ printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n",
+ be16_to_cpu(h->major), h->minor,
+ h->err, aoe_errlist[n]);
+ goto exit;
+@@ -147,7 +146,7 @@ aoenet_rcv(struct sk_buff *skb, struct n
+ aoecmd_cfg_rsp(skb);
+ break;
+ default:
+- printk(KERN_INFO "aoe: aoenet_rcv: unknown cmd %d\n", h->cmd);
++ printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
+ }
+ exit:
+ dev_kfree_skb(skb);
+diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
+index c396509..14d6b94 100644
+--- a/drivers/block/ataflop.c
++++ b/drivers/block/ataflop.c
+@@ -342,7 +342,7 @@ static void fd_select_drive( int drive )
+ static void fd_deselect( void );
+ static void fd_motor_off_timer( unsigned long dummy );
+ static void check_change( unsigned long dummy );
+-static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t floppy_irq (int irq, void *dummy);
+ static void fd_error( void );
+ static int do_format(int drive, int type, struct atari_format_descr *desc);
+ static void do_fd_action( int drive );
+@@ -573,7 +573,7 @@ static inline void copy_buffer(void *fro
+
+ static void (*FloppyIRQHandler)( int status ) = NULL;
+
+-static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t floppy_irq (int irq, void *dummy)
+ {
+ unsigned char status;
+ void (*handler)( int );
+diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
+index 2cd3391..6ffe2b2 100644
+--- a/drivers/block/cciss.c
++++ b/drivers/block/cciss.c
+@@ -20,7 +20,6 @@
+ *
+ */
+
+-#include <linux/config.h> /* CONFIG_PROC_FS */
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/types.h>
+@@ -131,7 +130,7 @@ static struct board_type products[] = {
+ static ctlr_info_t *hba[MAX_CTLR];
+
+ static void do_cciss_request(request_queue_t *q);
+-static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t do_cciss_intr(int irq, void *dev_id);
+ static int cciss_open(struct inode *inode, struct file *filep);
+ static int cciss_release(struct inode *inode, struct file *filep);
+ static int cciss_ioctl(struct inode *inode, struct file *filep,
+@@ -144,13 +143,13 @@ static int rebuild_lun_table(ctlr_info_t
+ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+ int clear_all);
+
+-static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
+- int withirq, unsigned int *total_size,
+- unsigned int *block_size);
+-static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
+- unsigned int total_size,
+- unsigned int block_size,
+- InquiryData_struct *inq_buff,
++static void cciss_read_capacity(int ctlr, int logvol, int withirq,
++ sector_t *total_size, unsigned int *block_size);
++static void cciss_read_capacity_16(int ctlr, int logvol, int withirq,
++ sector_t *total_size, unsigned int *block_size);
++static void cciss_geometry_inquiry(int ctlr, int logvol,
++ int withirq, sector_t total_size,
++ unsigned int block_size, InquiryData_struct *inq_buff,
+ drive_info_struct *drv);
+ static void cciss_getgeometry(int cntl_num);
+ static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
+@@ -879,7 +878,7 @@ static int cciss_ioctl(struct inode *ino
+ char *buff = NULL;
+ u64bit temp64;
+ unsigned long flags;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+
+ if (!arg)
+ return -EINVAL;
+@@ -997,7 +996,7 @@ static int cciss_ioctl(struct inode *ino
+ BYTE sg_used = 0;
+ int status = 0;
+ int i;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ __u32 left;
+ __u32 sz;
+ BYTE __user *data_ptr;
+@@ -1229,7 +1228,6 @@ static inline void complete_buffers(stru
+ int nr_sectors = bio_sectors(bio);
+
+ bio->bi_next = NULL;
+- blk_finished_io(len);
+ bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
+ bio = xbh;
+ }
+@@ -1326,10 +1324,9 @@ static void cciss_update_drive_info(int
+ {
+ ctlr_info_t *h = hba[ctlr];
+ struct gendisk *disk;
+- ReadCapdata_struct *size_buff = NULL;
+ InquiryData_struct *inq_buff = NULL;
+ unsigned int block_size;
+- unsigned int total_size;
++ sector_t total_size;
+ unsigned long flags = 0;
+ int ret = 0;
+
+@@ -1348,15 +1345,25 @@ static void cciss_update_drive_info(int
+ return;
+
+ /* Get information about the disk and modify the driver structure */
+- size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+- if (size_buff == NULL)
+- goto mem_msg;
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL)
+ goto mem_msg;
+
+- cciss_read_capacity(ctlr, drv_index, size_buff, 1,
++ cciss_read_capacity(ctlr, drv_index, 1,
+ &total_size, &block_size);
++
++ /* total size = last LBA + 1 */
++ /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */
++ /* so we assume this volume this must be >2TB in size */
++ if (total_size == (__u32) 0) {
++ cciss_read_capacity_16(ctlr, drv_index, 1,
++ &total_size, &block_size);
++ h->cciss_read = CCISS_READ_16;
++ h->cciss_write = CCISS_WRITE_16;
++ } else {
++ h->cciss_read = CCISS_READ_10;
++ h->cciss_write = CCISS_WRITE_10;
++ }
+ cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
+ inq_buff, &h->drv[drv_index]);
+
+@@ -1392,7 +1399,6 @@ static void cciss_update_drive_info(int
+ }
+
+ freeret:
+- kfree(size_buff);
+ kfree(inq_buff);
+ return;
+ mem_msg:
+@@ -1717,6 +1723,22 @@ static int fill_cmd(CommandList_struct *
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = cmd;
+ break;
++ case CCISS_READ_CAPACITY_16:
++ c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
++ c->Header.LUN.LogDev.Mode = 1;
++ c->Request.CDBLen = 16;
++ c->Request.Type.Attribute = ATTR_SIMPLE;
++ c->Request.Type.Direction = XFER_READ;
++ c->Request.Timeout = 0;
++ c->Request.CDB[0] = cmd;
++ c->Request.CDB[1] = 0x10;
++ c->Request.CDB[10] = (size >> 24) & 0xFF;
++ c->Request.CDB[11] = (size >> 16) & 0xFF;
++ c->Request.CDB[12] = (size >> 8) & 0xFF;
++ c->Request.CDB[13] = size & 0xFF;
++ c->Request.Timeout = 0;
++ c->Request.CDB[0] = cmd;
++ break;
+ case CCISS_CACHE_FLUSH:
+ c->Request.CDBLen = 12;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+@@ -1750,6 +1772,7 @@ static int fill_cmd(CommandList_struct *
+ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
+ c->Request.CDB[0] = cmd; /* reset */
+ c->Request.CDB[1] = 0x04; /* reset a LUN */
++ break;
+ case 3: /* No-Op message */
+ c->Request.CDBLen = 1;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+@@ -1792,7 +1815,7 @@ static int sendcmd_withirq(__u8 cmd,
+ u64bit buff_dma_handle;
+ unsigned long flags;
+ int return_status;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+
+ if ((c = cmd_alloc(h, 0)) == NULL)
+ return -ENOMEM;
+@@ -1893,12 +1916,14 @@ static int sendcmd_withirq(__u8 cmd,
+ }
+
+ static void cciss_geometry_inquiry(int ctlr, int logvol,
+- int withirq, unsigned int total_size,
++ int withirq, sector_t total_size,
+ unsigned int block_size,
+ InquiryData_struct *inq_buff,
+ drive_info_struct *drv)
+ {
+ int return_code;
++ unsigned long t;
++
+ memset(inq_buff, 0, sizeof(InquiryData_struct));
+ if (withirq)
+ return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
+@@ -1913,59 +1938,98 @@ static void cciss_geometry_inquiry(int c
+ printk(KERN_WARNING
+ "cciss: reading geometry failed, volume "
+ "does not support reading geometry\n");
+- drv->block_size = block_size;
+- drv->nr_blocks = total_size;
+ drv->heads = 255;
+ drv->sectors = 32; // Sectors per track
+- drv->cylinders = total_size / 255 / 32;
+ } else {
+- unsigned int t;
+-
+- drv->block_size = block_size;
+- drv->nr_blocks = total_size;
+ drv->heads = inq_buff->data_byte[6];
+ drv->sectors = inq_buff->data_byte[7];
+ drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8;
+ drv->cylinders += inq_buff->data_byte[5];
+ drv->raid_level = inq_buff->data_byte[8];
+- t = drv->heads * drv->sectors;
+- if (t > 1) {
+- drv->cylinders = total_size / t;
+- }
++ }
++ drv->block_size = block_size;
++ drv->nr_blocks = total_size;
++ t = drv->heads * drv->sectors;
++ if (t > 1) {
++ unsigned rem = sector_div(total_size, t);
++ if (rem)
++ total_size++;
++ drv->cylinders = total_size;
+ }
+ } else { /* Get geometry failed */
+ printk(KERN_WARNING "cciss: reading geometry failed\n");
+ }
+- printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n",
++ printk(KERN_INFO " heads=%d, sectors=%d, cylinders=%d\n\n",
+ drv->heads, drv->sectors, drv->cylinders);
+ }
+
+ static void
+-cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
+- int withirq, unsigned int *total_size,
++cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
+ unsigned int *block_size)
+ {
++ ReadCapdata_struct *buf;
+ int return_code;
+- memset(buf, 0, sizeof(*buf));
++ buf = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
++ if (buf == NULL) {
++ printk(KERN_WARNING "cciss: out of memory\n");
++ return;
++ }
++ memset(buf, 0, sizeof(ReadCapdata_struct));
+ if (withirq)
+ return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
+- ctlr, buf, sizeof(*buf), 1,
+- logvol, 0, TYPE_CMD);
++ ctlr, buf, sizeof(ReadCapdata_struct),
++ 1, logvol, 0, TYPE_CMD);
+ else
+ return_code = sendcmd(CCISS_READ_CAPACITY,
+- ctlr, buf, sizeof(*buf), 1, logvol, 0,
+- NULL, TYPE_CMD);
++ ctlr, buf, sizeof(ReadCapdata_struct),
++ 1, logvol, 0, NULL, TYPE_CMD);
++ if (return_code == IO_OK) {
++ *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1;
++ *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
++ } else { /* read capacity command failed */
++ printk(KERN_WARNING "cciss: read capacity failed\n");
++ *total_size = 0;
++ *block_size = BLOCK_SIZE;
++ }
++ if (*total_size != (__u32) 0)
++ printk(KERN_INFO " blocks= %llu block_size= %d\n",
++ (unsigned long long)*total_size, *block_size);
++ kfree(buf);
++ return;
++}
++
++static void
++cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, unsigned int *block_size)
++{
++ ReadCapdata_struct_16 *buf;
++ int return_code;
++ buf = kmalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
++ if (buf == NULL) {
++ printk(KERN_WARNING "cciss: out of memory\n");
++ return;
++ }
++ memset(buf, 0, sizeof(ReadCapdata_struct_16));
++ if (withirq) {
++ return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
++ ctlr, buf, sizeof(ReadCapdata_struct_16),
++ 1, logvol, 0, TYPE_CMD);
++ }
++ else {
++ return_code = sendcmd(CCISS_READ_CAPACITY_16,
++ ctlr, buf, sizeof(ReadCapdata_struct_16),
++ 1, logvol, 0, NULL, TYPE_CMD);
++ }
+ if (return_code == IO_OK) {
+- *total_size =
+- be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
+- *block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
++ *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1;
++ *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
+ } else { /* read capacity command failed */
+ printk(KERN_WARNING "cciss: read capacity failed\n");
+ *total_size = 0;
+ *block_size = BLOCK_SIZE;
+ }
+- printk(KERN_INFO " blocks= %u block_size= %d\n",
+- *total_size, *block_size);
++ printk(KERN_INFO " blocks= %llu block_size= %d\n",
++ (unsigned long long)*total_size, *block_size);
++ kfree(buf);
+ return;
+ }
+
+@@ -1976,8 +2040,7 @@ static int cciss_revalidate(struct gendi
+ int logvol;
+ int FOUND = 0;
+ unsigned int block_size;
+- unsigned int total_size;
+- ReadCapdata_struct *size_buff = NULL;
++ sector_t total_size;
+ InquiryData_struct *inq_buff = NULL;
+
+ for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+@@ -1990,27 +2053,24 @@ static int cciss_revalidate(struct gendi
+ if (!FOUND)
+ return 1;
+
+- size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+- if (size_buff == NULL) {
+- printk(KERN_WARNING "cciss: out of memory\n");
+- return 1;
+- }
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
+- kfree(size_buff);
+ return 1;
+ }
+-
+- cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
+- &block_size);
++ if (h->cciss_read == CCISS_READ_10) {
++ cciss_read_capacity(h->ctlr, logvol, 1,
++ &total_size, &block_size);
++ } else {
++ cciss_read_capacity_16(h->ctlr, logvol, 1,
++ &total_size, &block_size);
++ }
+ cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
+ inq_buff, drv);
+
+ blk_queue_hardsect_size(drv->queue, drv->block_size);
+ set_capacity(disk, drv->nr_blocks);
+
+- kfree(size_buff);
+ kfree(inq_buff);
+ return 0;
+ }
+@@ -2236,7 +2296,7 @@ static int sendcmd(__u8 cmd, int ctlr, v
+ #ifdef CONFIG_CISS_SCSI_TAPE
+ /* if we saved some commands for later, process them now. */
+ if (info_p->scsi_rejects.ncompletions > 0)
+- do_cciss_intr(0, info_p, NULL);
++ do_cciss_intr(0, info_p);
+ #endif
+ cmd_free(info_p, c, 1);
+ return status;
+@@ -2419,7 +2479,8 @@ static void do_cciss_request(request_que
+ {
+ ctlr_info_t *h = q->queuedata;
+ CommandList_struct *c;
+- int start_blk, seg;
++ sector_t start_blk;
++ int seg;
+ struct request *creq;
+ u64bit temp64;
+ struct scatterlist tmp_sg[MAXSGENTRIES];
+@@ -2463,10 +2524,10 @@ static void do_cciss_request(request_que
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction =
+- (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
++ (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] =
+- (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
++ (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
+ start_blk = creq->sector;
+ #ifdef CCISS_DEBUG
+ printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
+@@ -2500,15 +2561,33 @@ static void do_cciss_request(request_que
+ #endif /* CCISS_DEBUG */
+
+ c->Header.SGList = c->Header.SGTotal = seg;
+- c->Request.CDB[1] = 0;
+- c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
+- c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+- c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+- c->Request.CDB[5] = start_blk & 0xff;
+- c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
+- c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+- c->Request.CDB[8] = creq->nr_sectors & 0xff;
+- c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
++ if(h->cciss_read == CCISS_READ_10) {
++ c->Request.CDB[1] = 0;
++ c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
++ c->Request.CDB[3] = (start_blk >> 16) & 0xff;
++ c->Request.CDB[4] = (start_blk >> 8) & 0xff;
++ c->Request.CDB[5] = start_blk & 0xff;
++ c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
++ c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
++ c->Request.CDB[8] = creq->nr_sectors & 0xff;
++ c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
++ } else {
++ c->Request.CDBLen = 16;
++ c->Request.CDB[1]= 0;
++ c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
++ c->Request.CDB[3]= (start_blk >> 48) & 0xff;
++ c->Request.CDB[4]= (start_blk >> 40) & 0xff;
++ c->Request.CDB[5]= (start_blk >> 32) & 0xff;
++ c->Request.CDB[6]= (start_blk >> 24) & 0xff;
++ c->Request.CDB[7]= (start_blk >> 16) & 0xff;
++ c->Request.CDB[8]= (start_blk >> 8) & 0xff;
++ c->Request.CDB[9]= start_blk & 0xff;
++ c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
++ c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
++ c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
++ c->Request.CDB[13]= creq->nr_sectors & 0xff;
++ c->Request.CDB[14] = c->Request.CDB[15] = 0;
++ }
+
+ spin_lock_irq(q->queue_lock);
+
+@@ -2518,9 +2597,9 @@ static void do_cciss_request(request_que
+ h->maxQsinceinit = h->Qdepth;
+
+ goto queue;
+- full:
++full:
+ blk_stop_queue(q);
+- startio:
++startio:
+ /* We will already have the driver lock here so not need
+ * to lock it.
+ */
+@@ -2569,7 +2648,7 @@ static inline long interrupt_not_for_us(
+ #endif
+ }
+
+-static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t do_cciss_intr(int irq, void *dev_id)
+ {
+ ctlr_info_t *h = dev_id;
+ CommandList_struct *c;
+@@ -2948,31 +3027,23 @@ static int cciss_pci_init(ctlr_info_t *c
+ static void cciss_getgeometry(int cntl_num)
+ {
+ ReportLunData_struct *ld_buff;
+- ReadCapdata_struct *size_buff;
+ InquiryData_struct *inq_buff;
+ int return_code;
+ int i;
+ int listlength = 0;
+ __u32 lunid = 0;
+ int block_size;
+- int total_size;
++ sector_t total_size;
+
+ ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+ if (ld_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return;
+ }
+- size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+- if (size_buff == NULL) {
+- printk(KERN_ERR "cciss: out of memory\n");
+- kfree(ld_buff);
+- return;
+- }
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+- kfree(size_buff);
+ return;
+ }
+ /* Get the firmware version */
+@@ -3027,7 +3098,6 @@ static void cciss_getgeometry(int cntl_n
+ #endif /* CCISS_DEBUG */
+
+ hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
+-// for(i=0; i< hba[cntl_num]->num_luns; i++)
+ for (i = 0; i < CISS_MAX_LUN; i++) {
+ if (i < hba[cntl_num]->num_luns) {
+ lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+@@ -3046,8 +3116,26 @@ static void cciss_getgeometry(int cntl_n
+ ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+ hba[cntl_num]->drv[i].LunID);
+ #endif /* CCISS_DEBUG */
+- cciss_read_capacity(cntl_num, i, size_buff, 0,
++
++ /* testing to see if 16-byte CDBs are already being used */
++ if(hba[cntl_num]->cciss_read == CCISS_READ_16) {
++ cciss_read_capacity_16(cntl_num, i, 0,
+ &total_size, &block_size);
++ goto geo_inq;
++ }
++ cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size);
++
++ /* total_size = last LBA + 1 */
++ if(total_size == (__u32) 0) {
++ cciss_read_capacity_16(cntl_num, i, 0,
++ &total_size, &block_size);
++ hba[cntl_num]->cciss_read = CCISS_READ_16;
++ hba[cntl_num]->cciss_write = CCISS_WRITE_16;
++ } else {
++ hba[cntl_num]->cciss_read = CCISS_READ_10;
++ hba[cntl_num]->cciss_write = CCISS_WRITE_10;
++ }
++geo_inq:
+ cciss_geometry_inquiry(cntl_num, i, 0, total_size,
+ block_size, inq_buff,
+ &hba[cntl_num]->drv[i]);
+@@ -3057,7 +3145,6 @@ static void cciss_getgeometry(int cntl_n
+ }
+ }
+ kfree(ld_buff);
+- kfree(size_buff);
+ kfree(inq_buff);
+ }
+
+diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
+index 868e0d8..562235c 100644
+--- a/drivers/block/cciss.h
++++ b/drivers/block/cciss.h
+@@ -76,6 +76,9 @@ struct ctlr_info
+ unsigned int intr[4];
+ unsigned int msix_vector;
+ unsigned int msi_vector;
++ BYTE cciss_read;
++ BYTE cciss_write;
++ BYTE cciss_read_capacity;
+
+ // information about each logical volume
+ drive_info_struct drv[CISS_MAX_LUN];
+diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
+index 53fea54..4af7c4c 100644
+--- a/drivers/block/cciss_cmd.h
++++ b/drivers/block/cciss_cmd.h
+@@ -118,11 +118,34 @@ typedef struct _ReadCapdata_struct
+ BYTE block_size[4]; // Size of blocks in bytes
+ } ReadCapdata_struct;
+
+-// 12 byte commands not implemented in firmware yet.
+-// #define CCISS_READ 0xa8 // Read(12)
+-// #define CCISS_WRITE 0xaa // Write(12)
+- #define CCISS_READ 0x28 // Read(10)
+- #define CCISS_WRITE 0x2a // Write(10)
++#define CCISS_READ_CAPACITY_16 0x9e /* Read Capacity 16 */
++
++/* service action to differentiate a 16 byte read capacity from
++ other commands that use the 0x9e SCSI op code */
++
++#define CCISS_READ_CAPACITY_16_SERVICE_ACT 0x10
++
++typedef struct _ReadCapdata_struct_16
++{
++ BYTE total_size[8]; /* Total size in blocks */
++ BYTE block_size[4]; /* Size of blocks in bytes */
++ BYTE prot_en:1; /* protection enable bit */
++ BYTE rto_en:1; /* reference tag own enable bit */
++ BYTE reserved:6; /* reserved bits */
++ BYTE reserved2[18]; /* reserved bytes per spec */
++} ReadCapdata_struct_16;
++
++/* Define the supported read/write commands for cciss based controllers */
++
++#define CCISS_READ_10 0x28 /* Read(10) */
++#define CCISS_WRITE_10 0x2a /* Write(10) */
++#define CCISS_READ_16 0x88 /* Read(16) */
++#define CCISS_WRITE_16 0x8a /* Write(16) */
++
++/* Define the CDB lengths supported by cciss based controllers */
++
++#define CDB_LEN10 10
++#define CDB_LEN16 16
+
+ // BMIC commands
+ #define BMIC_READ 0x26
+diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
+index afdff32..bb15051 100644
+--- a/drivers/block/cciss_scsi.c
++++ b/drivers/block/cciss_scsi.c
+@@ -251,10 +251,6 @@ scsi_cmd_stack_free(int ctlr)
+ stk->pool = NULL;
+ }
+
+-/* scsi_device_types comes from scsi.h */
+-#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
+- "Unknown" : scsi_device_types[n]
+-
+ #if 0
+ static int xmargin=8;
+ static int amargin=60;
+@@ -389,7 +385,7 @@ cciss_scsi_add_entry(int ctlr, int hostn
+ time anyway (the scsi layer's inquiries will show that info) */
+ if (hostno != -1)
+ printk("cciss%d: %s device c%db%dt%dl%d added.\n",
+- ctlr, DEVICETYPE(sd->devtype), hostno,
++ ctlr, scsi_device_type(sd->devtype), hostno,
+ sd->bus, sd->target, sd->lun);
+ return 0;
+ }
+@@ -407,7 +403,7 @@ cciss_scsi_remove_entry(int ctlr, int ho
+ ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
+ ccissscsi[ctlr].ndevices--;
+ printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+- ctlr, DEVICETYPE(sd.devtype), hostno,
++ ctlr, scsi_device_type(sd.devtype), hostno,
+ sd.bus, sd.target, sd.lun);
+ }
+
+@@ -458,7 +454,7 @@ adjust_cciss_scsi_table(int ctlr, int ho
+ if (found == 0) { /* device no longer present. */
+ changes++;
+ /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+- ctlr, DEVICETYPE(csd->devtype), hostno,
++ ctlr, scsi_device_type(csd->devtype), hostno,
+ csd->bus, csd->target, csd->lun); */
+ cciss_scsi_remove_entry(ctlr, hostno, i);
+ /* note, i not incremented */
+@@ -468,7 +464,7 @@ adjust_cciss_scsi_table(int ctlr, int ho
+ printk("cciss%d: device c%db%dt%dl%d type changed "
+ "(device type now %s).\n",
+ ctlr, hostno, csd->bus, csd->target, csd->lun,
+- DEVICETYPE(csd->devtype));
++ scsi_device_type(csd->devtype));
+ csd->devtype = sd[j].devtype;
+ i++; /* so just move along. */
+ } else /* device is same as it ever was, */
+@@ -770,7 +766,7 @@ cciss_scsi_do_simple_cmd(ctlr_info_t *c,
+ int direction)
+ {
+ unsigned long flags;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+
+ cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl
+ cp->scsi_cmd = NULL;
+@@ -1098,7 +1094,7 @@ cciss_update_non_disk_devices(int cntl_n
+ if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
+ printk(KERN_INFO "cciss%d: %s ignored, "
+ "too many devices.\n", cntl_num,
+- DEVICETYPE(devtype));
++ scsi_device_type(devtype));
+ break;
+ }
+ memcpy(¤tsd[ncurrent].scsi3addr[0],
+diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
+index 78082ed..570d2f0 100644
+--- a/drivers/block/cpqarray.c
++++ b/drivers/block/cpqarray.c
+@@ -19,7 +19,6 @@
+ * Questions/Comments/Bugfixes to iss_storagedev at hp.com
+ *
+ */
+-#include <linux/config.h> /* CONFIG_PROC_FS */
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/pci.h>
+@@ -170,7 +169,7 @@ static inline cmdlist_t *removeQ(cmdlist
+ static inline void complete_buffers(struct bio *bio, int ok);
+ static inline void complete_command(cmdlist_t *cmd, int timeout);
+
+-static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t do_ida_intr(int irq, void *dev_id);
+ static void ida_timer(unsigned long tdata);
+ static int ida_revalidate(struct gendisk *disk);
+ static int revalidate_allvol(ctlr_info_t *host);
+@@ -989,7 +988,6 @@ static inline void complete_buffers(stru
+ xbh = bio->bi_next;
+ bio->bi_next = NULL;
+
+- blk_finished_io(nr_sectors);
+ bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO);
+
+ bio = xbh;
+@@ -1044,7 +1042,7 @@ static inline void complete_command(cmdl
+ * Find the command on the completion queue, remove it, tell the OS and
+ * try to queue up more IO
+ */
+-static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t do_ida_intr(int irq, void *dev_id)
+ {
+ ctlr_info_t *h = dev_id;
+ cmdlist_t *c;
+diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
+index 3d4261c..4053503 100644
+--- a/drivers/block/cryptoloop.c
++++ b/drivers/block/cryptoloop.c
+@@ -40,11 +40,13 @@ static int
+ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
+ {
+ int err = -EINVAL;
++ int cipher_len;
++ int mode_len;
+ char cms[LO_NAME_SIZE]; /* cipher-mode string */
+ char *cipher;
+ char *mode;
+ char *cmsp = cms; /* c-m string pointer */
+- struct crypto_tfm *tfm = NULL;
++ struct crypto_blkcipher *tfm;
+
+ /* encryption breaks for non sector aligned offsets */
+
+@@ -53,20 +55,39 @@ cryptoloop_init(struct loop_device *lo,
+
+ strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE);
+ cms[LO_NAME_SIZE - 1] = 0;
+- cipher = strsep(&cmsp, "-");
+- mode = strsep(&cmsp, "-");
+-
+- if (mode == NULL || strcmp(mode, "cbc") == 0)
+- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC |
+- CRYPTO_TFM_REQ_MAY_SLEEP);
+- else if (strcmp(mode, "ecb") == 0)
+- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB |
+- CRYPTO_TFM_REQ_MAY_SLEEP);
+- if (tfm == NULL)
++
++ cipher = cmsp;
++ cipher_len = strcspn(cmsp, "-");
++
++ mode = cmsp + cipher_len;
++ mode_len = 0;
++ if (*mode) {
++ mode++;
++ mode_len = strcspn(mode, "-");
++ }
++
++ if (!mode_len) {
++ mode = "cbc";
++ mode_len = 3;
++ }
++
++ if (cipher_len + mode_len + 3 > LO_NAME_SIZE)
+ return -EINVAL;
+
+- err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key,
+- info->lo_encrypt_key_size);
++ memmove(cms, mode, mode_len);
++ cmsp = cms + mode_len;
++ *cmsp++ = '(';
++ memcpy(cmsp, info->lo_crypt_name, cipher_len);
++ cmsp += cipher_len;
++ *cmsp++ = ')';
++ *cmsp = 0;
++
++ tfm = crypto_alloc_blkcipher(cms, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm))
++ return PTR_ERR(tfm);
++
++ err = crypto_blkcipher_setkey(tfm, info->lo_encrypt_key,
++ info->lo_encrypt_key_size);
+
+ if (err != 0)
+ goto out_free_tfm;
+@@ -75,99 +96,49 @@ cryptoloop_init(struct loop_device *lo,
+ return 0;
+
+ out_free_tfm:
+- crypto_free_tfm(tfm);
++ crypto_free_blkcipher(tfm);
+
+ out:
+ return err;
+ }
+
+
+-typedef int (*encdec_ecb_t)(struct crypto_tfm *tfm,
++typedef int (*encdec_cbc_t)(struct blkcipher_desc *desc,
+ struct scatterlist *sg_out,
+ struct scatterlist *sg_in,
+ unsigned int nsg);
+
+-
+-static int
+-cryptoloop_transfer_ecb(struct loop_device *lo, int cmd,
+- struct page *raw_page, unsigned raw_off,
+- struct page *loop_page, unsigned loop_off,
+- int size, sector_t IV)
+-{
+- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+- struct scatterlist sg_out = { NULL, };
+- struct scatterlist sg_in = { NULL, };
+-
+- encdec_ecb_t encdecfunc;
+- struct page *in_page, *out_page;
+- unsigned in_offs, out_offs;
+-
+- if (cmd == READ) {
+- in_page = raw_page;
+- in_offs = raw_off;
+- out_page = loop_page;
+- out_offs = loop_off;
+- encdecfunc = tfm->crt_u.cipher.cit_decrypt;
+- } else {
+- in_page = loop_page;
+- in_offs = loop_off;
+- out_page = raw_page;
+- out_offs = raw_off;
+- encdecfunc = tfm->crt_u.cipher.cit_encrypt;
+- }
+-
+- while (size > 0) {
+- const int sz = min(size, LOOP_IV_SECTOR_SIZE);
+-
+- sg_in.page = in_page;
+- sg_in.offset = in_offs;
+- sg_in.length = sz;
+-
+- sg_out.page = out_page;
+- sg_out.offset = out_offs;
+- sg_out.length = sz;
+-
+- encdecfunc(tfm, &sg_out, &sg_in, sz);
+-
+- size -= sz;
+- in_offs += sz;
+- out_offs += sz;
+- }
+-
+- return 0;
+-}
+-
+-typedef int (*encdec_cbc_t)(struct crypto_tfm *tfm,
+- struct scatterlist *sg_out,
+- struct scatterlist *sg_in,
+- unsigned int nsg, u8 *iv);
+-
+ static int
+-cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
+- struct page *raw_page, unsigned raw_off,
+- struct page *loop_page, unsigned loop_off,
+- int size, sector_t IV)
++cryptoloop_transfer(struct loop_device *lo, int cmd,
++ struct page *raw_page, unsigned raw_off,
++ struct page *loop_page, unsigned loop_off,
++ int size, sector_t IV)
+ {
+- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
++ struct crypto_blkcipher *tfm = lo->key_data;
++ struct blkcipher_desc desc = {
++ .tfm = tfm,
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
++ };
+ struct scatterlist sg_out = { NULL, };
+ struct scatterlist sg_in = { NULL, };
+
+ encdec_cbc_t encdecfunc;
+ struct page *in_page, *out_page;
+ unsigned in_offs, out_offs;
++ int err;
+
+ if (cmd == READ) {
+ in_page = raw_page;
+ in_offs = raw_off;
+ out_page = loop_page;
+ out_offs = loop_off;
+- encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv;
++ encdecfunc = crypto_blkcipher_crt(tfm)->decrypt;
+ } else {
+ in_page = loop_page;
+ in_offs = loop_off;
+ out_page = raw_page;
+ out_offs = raw_off;
+- encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv;
++ encdecfunc = crypto_blkcipher_crt(tfm)->encrypt;
+ }
+
+ while (size > 0) {
+@@ -183,7 +154,10 @@ cryptoloop_transfer_cbc(struct loop_devi
+ sg_out.offset = out_offs;
+ sg_out.length = sz;
+
+- encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv);
++ desc.info = iv;
++ err = encdecfunc(&desc, &sg_out, &sg_in, sz);
++ if (err)
++ return err;
+
+ IV++;
+ size -= sz;
+@@ -195,32 +169,6 @@ cryptoloop_transfer_cbc(struct loop_devi
+ }
+
+ static int
+-cryptoloop_transfer(struct loop_device *lo, int cmd,
+- struct page *raw_page, unsigned raw_off,
+- struct page *loop_page, unsigned loop_off,
+- int size, sector_t IV)
+-{
+- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+- if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB)
+- {
+- lo->transfer = cryptoloop_transfer_ecb;
+- return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off,
+- loop_page, loop_off, size, IV);
+- }
+- if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC)
+- {
+- lo->transfer = cryptoloop_transfer_cbc;
+- return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off,
+- loop_page, loop_off, size, IV);
+- }
+-
+- /* This is not supposed to happen */
+-
+- printk( KERN_ERR "cryptoloop: unsupported cipher mode in cryptoloop_transfer!\n");
+- return -EINVAL;
+-}
+-
+-static int
+ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
+ {
+ return -EINVAL;
+@@ -229,9 +177,9 @@ cryptoloop_ioctl(struct loop_device *lo,
+ static int
+ cryptoloop_release(struct loop_device *lo)
+ {
+- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
++ struct crypto_blkcipher *tfm = lo->key_data;
+ if (tfm != NULL) {
+- crypto_free_tfm(tfm);
++ crypto_free_blkcipher(tfm);
+ lo->key_data = NULL;
+ return 0;
+ }
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index ad1d706..9e6d3a8 100644
+--- a/drivers/block/floppy.c
++++ b/drivers/block/floppy.c
+@@ -221,7 +221,7 @@ static DEFINE_SPINLOCK(floppy_lock);
+ static struct completion device_release;
+
+ static unsigned short virtual_dma_port = 0x3f0;
+-irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t floppy_interrupt(int irq, void *dev_id);
+ static int set_dor(int fdc, char mask, char data);
+
+ #define K_64 0x10000 /* 64KB */
+@@ -1726,7 +1726,7 @@ static void print_result(char *message,
+ }
+
+ /* interrupt handler. Note that this can be called externally on the Sparc */
+-irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t floppy_interrupt(int irq, void *dev_id)
+ {
+ void (*handler) (void) = do_floppy;
+ int do_print;
+@@ -2991,8 +2991,8 @@ static void do_fd_request(request_queue_
+ if (usage_count == 0) {
+ printk("warning: usage count=0, current_req=%p exiting\n",
+ current_req);
+- printk("sect=%ld flags=%lx\n", (long)current_req->sector,
+- current_req->flags);
++ printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector,
++ current_req->cmd_type, current_req->cmd_flags);
+ return;
+ }
+ if (test_bit(0, &fdc_busy)) {
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index 7b3b94d..beab6d2 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -66,12 +66,14 @@
+ #include <linux/swap.h>
+ #include <linux/slab.h>
+ #include <linux/loop.h>
++#include <linux/compat.h>
+ #include <linux/suspend.h>
+ #include <linux/writeback.h>
+ #include <linux/buffer_head.h> /* for invalidate_bdev() */
+ #include <linux/completion.h>
+ #include <linux/highmem.h>
+ #include <linux/gfp.h>
++#include <linux/kthread.h>
+
+ #include <asm/uaccess.h>
+
+@@ -293,7 +295,7 @@ fail:
+ * and do_lo_send_write().
+ */
+ static int __do_lo_send_write(struct file *file,
+- u8 __user *buf, const int len, loff_t pos)
++ u8 *buf, const int len, loff_t pos)
+ {
+ ssize_t bw;
+ mm_segment_t old_fs = get_fs();
+@@ -322,7 +324,7 @@ static int do_lo_send_direct_write(struc
+ struct bio_vec *bvec, int bsize, loff_t pos, struct page *page)
+ {
+ ssize_t bw = __do_lo_send_write(lo->lo_backing_file,
+- (u8 __user *)kmap(bvec->bv_page) + bvec->bv_offset,
++ kmap(bvec->bv_page) + bvec->bv_offset,
+ bvec->bv_len, pos);
+ kunmap(bvec->bv_page);
+ cond_resched();
+@@ -349,7 +351,7 @@ static int do_lo_send_write(struct loop_
+ bvec->bv_offset, bvec->bv_len, pos >> 9);
+ if (likely(!ret))
+ return __do_lo_send_write(lo->lo_backing_file,
+- (u8 __user *)page_address(page), bvec->bv_len,
++ page_address(page), bvec->bv_len,
+ pos);
+ printk(KERN_ERR "loop: Transfer error at byte offset %llu, "
+ "length %i.\n", (unsigned long long)pos, bvec->bv_len);
+@@ -522,15 +524,12 @@ static int loop_make_request(request_que
+ goto out;
+ if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY)))
+ goto out;
+- lo->lo_pending++;
+ loop_add_bio(lo, old_bio);
++ wake_up(&lo->lo_event);
+ spin_unlock_irq(&lo->lo_lock);
+- complete(&lo->lo_bh_done);
+ return 0;
+
+ out:
+- if (lo->lo_pending == 0)
+- complete(&lo->lo_bh_done);
+ spin_unlock_irq(&lo->lo_lock);
+ bio_io_error(old_bio, old_bio->bi_size);
+ return 0;
+@@ -570,14 +569,18 @@ static inline void loop_handle_bio(struc
+ * to avoid blocking in our make_request_fn. it also does loop decrypting
+ * on reads for block backed loop, as that is too heavy to do from
+ * b_end_io context where irqs may be disabled.
++ *
++ * Loop explanation: loop_clr_fd() sets lo_state to Lo_rundown before
++ * calling kthread_stop(). Therefore once kthread_should_stop() is
++ * true, make_request will not place any more requests. Therefore
++ * once kthread_should_stop() is true and lo_bio is NULL, we are
++ * done with the loop.
+ */
+ static int loop_thread(void *data)
+ {
+ struct loop_device *lo = data;
+ struct bio *bio;
+
+- daemonize("loop%d", lo->lo_number);
+-
+ /*
+ * loop can be used in an encrypted device,
+ * hence, it mustn't be stopped at all
+@@ -587,47 +590,21 @@ static int loop_thread(void *data)
+
+ set_user_nice(current, -20);
+
+- lo->lo_state = Lo_bound;
+- lo->lo_pending = 1;
++ while (!kthread_should_stop() || lo->lo_bio) {
+
+- /*
+- * complete it, we are running
+- */
+- complete(&lo->lo_done);
+-
+- for (;;) {
+- int pending;
++ wait_event_interruptible(lo->lo_event,
++ lo->lo_bio || kthread_should_stop());
+
+- if (wait_for_completion_interruptible(&lo->lo_bh_done))
++ if (!lo->lo_bio)
+ continue;
+-
+ spin_lock_irq(&lo->lo_lock);
+-
+- /*
+- * could be completed because of tear-down, not pending work
+- */
+- if (unlikely(!lo->lo_pending)) {
+- spin_unlock_irq(&lo->lo_lock);
+- break;
+- }
+-
+ bio = loop_get_bio(lo);
+- lo->lo_pending--;
+- pending = lo->lo_pending;
+ spin_unlock_irq(&lo->lo_lock);
+
+ BUG_ON(!bio);
+ loop_handle_bio(lo, bio);
+-
+- /*
+- * upped both for pending work and tear-down, lo_pending
+- * will hit zero then
+- */
+- if (unlikely(!pending))
+- break;
+ }
+
+- complete(&lo->lo_done);
+ return 0;
+ }
+
+@@ -662,7 +639,8 @@ static void do_loop_switch(struct loop_d
+
+ mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
+ lo->lo_backing_file = file;
+- lo->lo_blocksize = mapping->host->i_blksize;
++ lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
++ mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
+ lo->old_gfp_mask = mapping_gfp_mask(mapping);
+ mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+ complete(&p->wait);
+@@ -794,7 +772,9 @@ static int loop_set_fd(struct loop_devic
+ if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
+ lo_flags |= LO_FLAGS_READ_ONLY;
+
+- lo_blocksize = inode->i_blksize;
++ lo_blocksize = S_ISBLK(inode->i_mode) ?
++ inode->i_bdev->bd_block_size : PAGE_SIZE;
++
+ error = 0;
+ } else {
+ goto out_putf;
+@@ -837,12 +817,26 @@ static int loop_set_fd(struct loop_devic
+
+ set_blocksize(bdev, lo_blocksize);
+
+- error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
+- if (error < 0)
+- goto out_putf;
+- wait_for_completion(&lo->lo_done);
++ lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
++ lo->lo_number);
++ if (IS_ERR(lo->lo_thread)) {
++ error = PTR_ERR(lo->lo_thread);
++ goto out_clr;
++ }
++ lo->lo_state = Lo_bound;
++ wake_up_process(lo->lo_thread);
+ return 0;
+
++out_clr:
++ lo->lo_thread = NULL;
++ lo->lo_device = NULL;
++ lo->lo_backing_file = NULL;
++ lo->lo_flags = 0;
++ set_capacity(disks[lo->lo_number], 0);
++ invalidate_bdev(bdev, 0);
++ bd_set_size(bdev, 0);
++ mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
++ lo->lo_state = Lo_unbound;
+ out_putf:
+ fput(file);
+ out:
+@@ -904,12 +898,9 @@ static int loop_clr_fd(struct loop_devic
+
+ spin_lock_irq(&lo->lo_lock);
+ lo->lo_state = Lo_rundown;
+- lo->lo_pending--;
+- if (!lo->lo_pending)
+- complete(&lo->lo_bh_done);
+ spin_unlock_irq(&lo->lo_lock);
+
+- wait_for_completion(&lo->lo_done);
++ kthread_stop(lo->lo_thread);
+
+ lo->lo_backing_file = NULL;
+
+@@ -922,6 +913,7 @@ static int loop_clr_fd(struct loop_devic
+ lo->lo_sizelimit = 0;
+ lo->lo_encrypt_key_size = 0;
+ lo->lo_flags = 0;
++ lo->lo_thread = NULL;
+ memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
+ memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
+ memset(lo->lo_file_name, 0, LO_NAME_SIZE);
+@@ -1174,6 +1166,162 @@ static int lo_ioctl(struct inode * inode
+ return err;
+ }
+
++#ifdef CONFIG_COMPAT
++struct compat_loop_info {
++ compat_int_t lo_number; /* ioctl r/o */
++ compat_dev_t lo_device; /* ioctl r/o */
++ compat_ulong_t lo_inode; /* ioctl r/o */
++ compat_dev_t lo_rdevice; /* ioctl r/o */
++ compat_int_t lo_offset;
++ compat_int_t lo_encrypt_type;
++ compat_int_t lo_encrypt_key_size; /* ioctl w/o */
++ compat_int_t lo_flags; /* ioctl r/o */
++ char lo_name[LO_NAME_SIZE];
++ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
++ compat_ulong_t lo_init[2];
++ char reserved[4];
++};
++
++/*
++ * Transfer 32-bit compatibility structure in userspace to 64-bit loop info
++ * - noinlined to reduce stack space usage in main part of driver
++ */
++static noinline int
++loop_info64_from_compat(const struct compat_loop_info __user *arg,
++ struct loop_info64 *info64)
++{
++ struct compat_loop_info info;
++
++ if (copy_from_user(&info, arg, sizeof(info)))
++ return -EFAULT;
++
++ memset(info64, 0, sizeof(*info64));
++ info64->lo_number = info.lo_number;
++ info64->lo_device = info.lo_device;
++ info64->lo_inode = info.lo_inode;
++ info64->lo_rdevice = info.lo_rdevice;
++ info64->lo_offset = info.lo_offset;
++ info64->lo_sizelimit = 0;
++ info64->lo_encrypt_type = info.lo_encrypt_type;
++ info64->lo_encrypt_key_size = info.lo_encrypt_key_size;
++ info64->lo_flags = info.lo_flags;
++ info64->lo_init[0] = info.lo_init[0];
++ info64->lo_init[1] = info.lo_init[1];
++ if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
++ memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE);
++ else
++ memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE);
++ memcpy(info64->lo_encrypt_key, info.lo_encrypt_key, LO_KEY_SIZE);
++ return 0;
++}
++
++/*
++ * Transfer 64-bit loop info to 32-bit compatibility structure in userspace
++ * - noinlined to reduce stack space usage in main part of driver
++ */
++static noinline int
++loop_info64_to_compat(const struct loop_info64 *info64,
++ struct compat_loop_info __user *arg)
++{
++ struct compat_loop_info info;
++
++ memset(&info, 0, sizeof(info));
++ info.lo_number = info64->lo_number;
++ info.lo_device = info64->lo_device;
++ info.lo_inode = info64->lo_inode;
++ info.lo_rdevice = info64->lo_rdevice;
++ info.lo_offset = info64->lo_offset;
++ info.lo_encrypt_type = info64->lo_encrypt_type;
++ info.lo_encrypt_key_size = info64->lo_encrypt_key_size;
++ info.lo_flags = info64->lo_flags;
++ info.lo_init[0] = info64->lo_init[0];
++ info.lo_init[1] = info64->lo_init[1];
++ if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
++ memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
++ else
++ memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE);
++ memcpy(info.lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
++
++ /* error in case values were truncated */
++ if (info.lo_device != info64->lo_device ||
++ info.lo_rdevice != info64->lo_rdevice ||
++ info.lo_inode != info64->lo_inode ||
++ info.lo_offset != info64->lo_offset ||
++ info.lo_init[0] != info64->lo_init[0] ||
++ info.lo_init[1] != info64->lo_init[1])
++ return -EOVERFLOW;
++
++ if (copy_to_user(arg, &info, sizeof(info)))
++ return -EFAULT;
++ return 0;
++}
++
++static int
++loop_set_status_compat(struct loop_device *lo,
++ const struct compat_loop_info __user *arg)
++{
++ struct loop_info64 info64;
++ int ret;
++
++ ret = loop_info64_from_compat(arg, &info64);
++ if (ret < 0)
++ return ret;
++ return loop_set_status(lo, &info64);
++}
++
++static int
++loop_get_status_compat(struct loop_device *lo,
++ struct compat_loop_info __user *arg)
++{
++ struct loop_info64 info64;
++ int err = 0;
++
++ if (!arg)
++ err = -EINVAL;
++ if (!err)
++ err = loop_get_status(lo, &info64);
++ if (!err)
++ err = loop_info64_to_compat(&info64, arg);
++ return err;
++}
++
++static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
++ int err;
++
++ lock_kernel();
++ switch(cmd) {
++ case LOOP_SET_STATUS:
++ mutex_lock(&lo->lo_ctl_mutex);
++ err = loop_set_status_compat(
++ lo, (const struct compat_loop_info __user *) arg);
++ mutex_unlock(&lo->lo_ctl_mutex);
++ break;
++ case LOOP_GET_STATUS:
++ mutex_lock(&lo->lo_ctl_mutex);
++ err = loop_get_status_compat(
++ lo, (struct compat_loop_info __user *) arg);
++ mutex_unlock(&lo->lo_ctl_mutex);
++ break;
++ case LOOP_CLR_FD:
++ case LOOP_GET_STATUS64:
++ case LOOP_SET_STATUS64:
++ arg = (unsigned long) compat_ptr(arg);
++ case LOOP_SET_FD:
++ case LOOP_CHANGE_FD:
++ err = lo_ioctl(inode, file, cmd, arg);
++ break;
++ default:
++ err = -ENOIOCTLCMD;
++ break;
++ }
++ unlock_kernel();
++ return err;
++}
++#endif
++
+ static int lo_open(struct inode *inode, struct file *file)
+ {
+ struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
+@@ -1201,6 +1349,9 @@ static struct block_device_operations lo
+ .open = lo_open,
+ .release = lo_release,
+ .ioctl = lo_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = lo_compat_ioctl,
++#endif
+ };
+
+ /*
+@@ -1284,9 +1435,9 @@ static int __init loop_init(void)
+ if (!lo->lo_queue)
+ goto out_mem4;
+ mutex_init(&lo->lo_ctl_mutex);
+- init_completion(&lo->lo_done);
+- init_completion(&lo->lo_bh_done);
+ lo->lo_number = i;
++ lo->lo_thread = NULL;
++ init_waitqueue_head(&lo->lo_event);
+ spin_lock_init(&lo->lo_lock);
+ disk->major = LOOP_MAJOR;
+ disk->first_minor = i;
+diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
+index bdbade9..9d1035e 100644
+--- a/drivers/block/nbd.c
++++ b/drivers/block/nbd.c
+@@ -407,10 +407,10 @@ static void do_nbd_request(request_queue
+ struct nbd_device *lo;
+
+ blkdev_dequeue_request(req);
+- dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%lx)\n",
+- req->rq_disk->disk_name, req, req->flags);
++ dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
++ req->rq_disk->disk_name, req, req->cmd_type);
+
+- if (!(req->flags & REQ_CMD))
++ if (!blk_fs_request(req))
+ goto error_out;
+
+ lo = req->rq_disk->private_data;
+@@ -489,7 +489,7 @@ static int nbd_ioctl(struct inode *inode
+ switch (cmd) {
+ case NBD_DISCONNECT:
+ printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
+- sreq.flags = REQ_SPECIAL;
++ sreq.cmd_type = REQ_TYPE_SPECIAL;
+ nbd_cmd(&sreq) = NBD_CMD_DISC;
+ /*
+ * Set these to sane values in case server implementation
+diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
+index 2403721..40a11e5 100644
+--- a/drivers/block/paride/pd.c
++++ b/drivers/block/paride/pd.c
+@@ -437,7 +437,7 @@ static char *pd_buf; /* buffer for requ
+
+ static enum action do_pd_io_start(void)
+ {
+- if (pd_req->flags & REQ_SPECIAL) {
++ if (blk_special_request(pd_req)) {
+ phase = pd_special;
+ return pd_special();
+ }
+@@ -713,20 +713,18 @@ static void do_pd_request(request_queue_
+ static int pd_special_command(struct pd_unit *disk,
+ enum action (*func)(struct pd_unit *disk))
+ {
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ struct request rq;
+ int err = 0;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.errors = 0;
+- rq.rq_status = RQ_ACTIVE;
+ rq.rq_disk = disk->gd;
+ rq.ref_count = 1;
+- rq.waiting = &wait;
++ rq.end_io_data = &wait;
+ rq.end_io = blk_end_sync_rq;
+ blk_insert_request(disk->gd->queue, &rq, 0, func);
+ wait_for_completion(&wait);
+- rq.waiting = NULL;
+ if (rq.errors)
+ err = -EIO;
+ blk_put_request(&rq);
+diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
+index 451b996..f2904f6 100644
+--- a/drivers/block/pktcdvd.c
++++ b/drivers/block/pktcdvd.c
+@@ -62,6 +62,8 @@
+
+ #include <asm/uaccess.h>
+
++#define DRIVER_NAME "pktcdvd"
++
+ #if PACKET_DEBUG
+ #define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
+ #else
+@@ -80,7 +82,7 @@
+
+ static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
+ static struct proc_dir_entry *pkt_proc;
+-static int pkt_major;
++static int pktdev_major;
+ static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
+ static mempool_t *psd_pool;
+
+@@ -89,7 +91,7 @@ static void pkt_bio_finished(struct pktc
+ {
+ BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
+ if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
+- VPRINTK("pktcdvd: queue empty\n");
++ VPRINTK(DRIVER_NAME": queue empty\n");
+ atomic_set(&pd->iosched.attention, 1);
+ wake_up(&pd->wqueue);
+ }
+@@ -348,7 +350,7 @@ static int pkt_generic_packet(struct pkt
+ char sense[SCSI_SENSE_BUFFERSIZE];
+ request_queue_t *q;
+ struct request *rq;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ int err = 0;
+
+ q = bdev_get_queue(pd->bdev);
+@@ -365,17 +367,17 @@ static int pkt_generic_packet(struct pkt
+ rq->sense = sense;
+ memset(sense, 0, sizeof(sense));
+ rq->sense_len = 0;
+- rq->flags |= REQ_BLOCK_PC | REQ_HARDBARRIER;
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
++ rq->cmd_flags |= REQ_HARDBARRIER;
+ if (cgc->quiet)
+- rq->flags |= REQ_QUIET;
++ rq->cmd_flags |= REQ_QUIET;
+ memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
+ if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
+ memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
+ rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+
+ rq->ref_count++;
+- rq->flags |= REQ_NOMERGE;
+- rq->waiting = &wait;
++ rq->end_io_data = &wait;
+ rq->end_io = blk_end_sync_rq;
+ elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+ generic_unplug_device(q);
+@@ -400,7 +402,7 @@ static void pkt_dump_sense(struct packet
+ int i;
+ struct request_sense *sense = cgc->sense;
+
+- printk("pktcdvd:");
++ printk(DRIVER_NAME":");
+ for (i = 0; i < CDROM_PACKET_SIZE; i++)
+ printk(" %02x", cgc->cmd[i]);
+ printk(" - ");
+@@ -528,7 +530,7 @@ static void pkt_iosched_process_queue(st
+ need_write_seek = 0;
+ if (need_write_seek && reads_queued) {
+ if (atomic_read(&pd->cdrw.pending_bios) > 0) {
+- VPRINTK("pktcdvd: write, waiting\n");
++ VPRINTK(DRIVER_NAME": write, waiting\n");
+ break;
+ }
+ pkt_flush_cache(pd);
+@@ -537,7 +539,7 @@ static void pkt_iosched_process_queue(st
+ } else {
+ if (!reads_queued && writes_queued) {
+ if (atomic_read(&pd->cdrw.pending_bios) > 0) {
+- VPRINTK("pktcdvd: read, waiting\n");
++ VPRINTK(DRIVER_NAME": read, waiting\n");
+ break;
+ }
+ pd->iosched.writing = 1;
+@@ -600,7 +602,7 @@ static int pkt_set_segment_merging(struc
+ set_bit(PACKET_MERGE_SEGS, &pd->flags);
+ return 0;
+ } else {
+- printk("pktcdvd: cdrom max_phys_segments too small\n");
++ printk(DRIVER_NAME": cdrom max_phys_segments too small\n");
+ return -EIO;
+ }
+ }
+@@ -1049,7 +1051,7 @@ static void pkt_start_write(struct pktcd
+ for (f = 0; f < pkt->frames; f++)
+ if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
+ BUG();
+- VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt);
++ VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt);
+
+ atomic_set(&pkt->io_wait, 1);
+ pkt->w_bio->bi_rw = WRITE;
+@@ -1286,7 +1288,7 @@ work_to_do:
+
+ static void pkt_print_settings(struct pktcdvd_device *pd)
+ {
+- printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
++ printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
+ printk("%u blocks, ", pd->settings.size >> 2);
+ printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2');
+ }
+@@ -1471,7 +1473,7 @@ static int pkt_set_write_settings(struct
+ /*
+ * paranoia
+ */
+- printk("pktcdvd: write mode wrong %d\n", wp->data_block_type);
++ printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type);
+ return 1;
+ }
+ wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
+@@ -1515,7 +1517,7 @@ static int pkt_writable_track(struct pkt
+ if (ti->rt == 1 && ti->blank == 0)
+ return 1;
+
+- printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
++ printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+ return 0;
+ }
+
+@@ -1533,7 +1535,7 @@ static int pkt_writable_disc(struct pktc
+ case 0x12: /* DVD-RAM */
+ return 1;
+ default:
+- VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
++ VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile);
+ return 0;
+ }
+
+@@ -1542,22 +1544,22 @@ static int pkt_writable_disc(struct pktc
+ * but i'm not sure, should we leave this to user apps? probably.
+ */
+ if (di->disc_type == 0xff) {
+- printk("pktcdvd: Unknown disc. No track?\n");
++ printk(DRIVER_NAME": Unknown disc. No track?\n");
+ return 0;
+ }
+
+ if (di->disc_type != 0x20 && di->disc_type != 0) {
+- printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
++ printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type);
+ return 0;
+ }
+
+ if (di->erasable == 0) {
+- printk("pktcdvd: Disc not erasable\n");
++ printk(DRIVER_NAME": Disc not erasable\n");
+ return 0;
+ }
+
+ if (di->border_status == PACKET_SESSION_RESERVED) {
+- printk("pktcdvd: Can't write to last track (reserved)\n");
++ printk(DRIVER_NAME": Can't write to last track (reserved)\n");
+ return 0;
+ }
+
+@@ -1593,12 +1595,12 @@ static int pkt_probe_settings(struct pkt
+
+ track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
+ if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
+- printk("pktcdvd: failed get_track\n");
++ printk(DRIVER_NAME": failed get_track\n");
+ return ret;
+ }
+
+ if (!pkt_writable_track(pd, &ti)) {
+- printk("pktcdvd: can't write to this track\n");
++ printk(DRIVER_NAME": can't write to this track\n");
+ return -EROFS;
+ }
+
+@@ -1608,11 +1610,11 @@ static int pkt_probe_settings(struct pkt
+ */
+ pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
+ if (pd->settings.size == 0) {
+- printk("pktcdvd: detected zero packet size!\n");
++ printk(DRIVER_NAME": detected zero packet size!\n");
+ return -ENXIO;
+ }
+ if (pd->settings.size > PACKET_MAX_SECTORS) {
+- printk("pktcdvd: packet size is too big\n");
++ printk(DRIVER_NAME": packet size is too big\n");
+ return -EROFS;
+ }
+ pd->settings.fp = ti.fp;
+@@ -1654,7 +1656,7 @@ static int pkt_probe_settings(struct pkt
+ pd->settings.block_mode = PACKET_BLOCK_MODE2;
+ break;
+ default:
+- printk("pktcdvd: unknown data mode\n");
++ printk(DRIVER_NAME": unknown data mode\n");
+ return -EROFS;
+ }
+ return 0;
+@@ -1688,10 +1690,10 @@ static int pkt_write_caching(struct pktc
+ cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
+ ret = pkt_mode_select(pd, &cgc);
+ if (ret) {
+- printk("pktcdvd: write caching control failed\n");
++ printk(DRIVER_NAME": write caching control failed\n");
+ pkt_dump_sense(&cgc);
+ } else if (!ret && set)
+- printk("pktcdvd: enabled write caching on %s\n", pd->name);
++ printk(DRIVER_NAME": enabled write caching on %s\n", pd->name);
+ return ret;
+ }
+
+@@ -1805,11 +1807,11 @@ static int pkt_media_speed(struct pktcdv
+ }
+
+ if (!buf[6] & 0x40) {
+- printk("pktcdvd: Disc type is not CD-RW\n");
++ printk(DRIVER_NAME": Disc type is not CD-RW\n");
+ return 1;
+ }
+ if (!buf[6] & 0x4) {
+- printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");
++ printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
+ return 1;
+ }
+
+@@ -1829,14 +1831,14 @@ static int pkt_media_speed(struct pktcdv
+ *speed = us_clv_to_speed[sp];
+ break;
+ default:
+- printk("pktcdvd: Unknown disc sub-type %d\n",st);
++ printk(DRIVER_NAME": Unknown disc sub-type %d\n",st);
+ return 1;
+ }
+ if (*speed) {
+- printk("pktcdvd: Max. media speed: %d\n",*speed);
++ printk(DRIVER_NAME": Max. media speed: %d\n",*speed);
+ return 0;
+ } else {
+- printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);
++ printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st);
+ return 1;
+ }
+ }
+@@ -1847,7 +1849,7 @@ static int pkt_perform_opc(struct pktcdv
+ struct request_sense sense;
+ int ret;
+
+- VPRINTK("pktcdvd: Performing OPC\n");
++ VPRINTK(DRIVER_NAME": Performing OPC\n");
+
+ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+ cgc.sense = &sense;
+@@ -1865,12 +1867,12 @@ static int pkt_open_write(struct pktcdvd
+ unsigned int write_speed, media_write_speed, read_speed;
+
+ if ((ret = pkt_probe_settings(pd))) {
+- VPRINTK("pktcdvd: %s failed probe\n", pd->name);
++ VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name);
+ return ret;
+ }
+
+ if ((ret = pkt_set_write_settings(pd))) {
+- DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);
++ DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name);
+ return -EIO;
+ }
+
+@@ -1882,26 +1884,26 @@ static int pkt_open_write(struct pktcdvd
+ case 0x13: /* DVD-RW */
+ case 0x1a: /* DVD+RW */
+ case 0x12: /* DVD-RAM */
+- DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
++ DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed);
+ break;
+ default:
+ if ((ret = pkt_media_speed(pd, &media_write_speed)))
+ media_write_speed = 16;
+ write_speed = min(write_speed, media_write_speed * 177);
+- DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);
++ DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176);
+ break;
+ }
+ read_speed = write_speed;
+
+ if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
+- DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
++ DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name);
+ return -EIO;
+ }
+ pd->write_speed = write_speed;
+ pd->read_speed = read_speed;
+
+ if ((ret = pkt_perform_opc(pd))) {
+- DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);
++ DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name);
+ }
+
+ return 0;
+@@ -1929,7 +1931,7 @@ static int pkt_open_dev(struct pktcdvd_d
+ goto out_putdev;
+
+ if ((ret = pkt_get_last_written(pd, &lba))) {
+- printk("pktcdvd: pkt_get_last_written failed\n");
++ printk(DRIVER_NAME": pkt_get_last_written failed\n");
+ goto out_unclaim;
+ }
+
+@@ -1959,11 +1961,11 @@ static int pkt_open_dev(struct pktcdvd_d
+
+ if (write) {
+ if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
+- printk("pktcdvd: not enough memory for buffers\n");
++ printk(DRIVER_NAME": not enough memory for buffers\n");
+ ret = -ENOMEM;
+ goto out_unclaim;
+ }
+- printk("pktcdvd: %lukB available on disc\n", lba << 1);
++ printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
+ }
+
+ return 0;
+@@ -1983,7 +1985,7 @@ out:
+ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
+ {
+ if (flush && pkt_flush_cache(pd))
+- DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
++ DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name);
+
+ pkt_lock_door(pd, 0);
+
+@@ -2006,7 +2008,7 @@ static int pkt_open(struct inode *inode,
+ struct pktcdvd_device *pd = NULL;
+ int ret;
+
+- VPRINTK("pktcdvd: entering open\n");
++ VPRINTK(DRIVER_NAME": entering open\n");
+
+ mutex_lock(&ctl_mutex);
+ pd = pkt_find_dev_from_minor(iminor(inode));
+@@ -2040,7 +2042,7 @@ static int pkt_open(struct inode *inode,
+ out_dec:
+ pd->refcnt--;
+ out:
+- VPRINTK("pktcdvd: failed open (%d)\n", ret);
++ VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
+ mutex_unlock(&ctl_mutex);
+ return ret;
+ }
+@@ -2088,7 +2090,7 @@ static int pkt_make_request(request_queu
+
+ pd = q->queuedata;
+ if (!pd) {
+- printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
++ printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+ goto end_io;
+ }
+
+@@ -2110,13 +2112,13 @@ static int pkt_make_request(request_queu
+ }
+
+ if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
+- printk("pktcdvd: WRITE for ro device %s (%llu)\n",
++ printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n",
+ pd->name, (unsigned long long)bio->bi_sector);
+ goto end_io;
+ }
+
+ if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
+- printk("pktcdvd: wrong bio size\n");
++ printk(DRIVER_NAME": wrong bio size\n");
+ goto end_io;
+ }
+
+@@ -2319,7 +2321,7 @@ static int pkt_new_dev(struct pktcdvd_de
+ struct block_device *bdev;
+
+ if (pd->pkt_dev == dev) {
+- printk("pktcdvd: Recursive setup not allowed\n");
++ printk(DRIVER_NAME": Recursive setup not allowed\n");
+ return -EBUSY;
+ }
+ for (i = 0; i < MAX_WRITERS; i++) {
+@@ -2327,11 +2329,11 @@ static int pkt_new_dev(struct pktcdvd_de
+ if (!pd2)
+ continue;
+ if (pd2->bdev->bd_dev == dev) {
+- printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b));
++ printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b));
+ return -EBUSY;
+ }
+ if (pd2->pkt_dev == dev) {
+- printk("pktcdvd: Can't chain pktcdvd devices\n");
++ printk(DRIVER_NAME": Can't chain pktcdvd devices\n");
+ return -EBUSY;
+ }
+ }
+@@ -2354,7 +2356,7 @@ static int pkt_new_dev(struct pktcdvd_de
+ atomic_set(&pd->cdrw.pending_bios, 0);
+ pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
+ if (IS_ERR(pd->cdrw.thread)) {
+- printk("pktcdvd: can't start kernel thread\n");
++ printk(DRIVER_NAME": can't start kernel thread\n");
+ ret = -ENOMEM;
+ goto out_mem;
+ }
+@@ -2364,7 +2366,7 @@ static int pkt_new_dev(struct pktcdvd_de
+ proc->data = pd;
+ proc->proc_fops = &pkt_proc_fops;
+ }
+- DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
++ DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+ return 0;
+
+ out_mem:
+@@ -2401,7 +2403,7 @@ static int pkt_ioctl(struct inode *inode
+ return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
+
+ default:
+- VPRINTK("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
++ VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
+ return -ENOTTY;
+ }
+
+@@ -2446,7 +2448,7 @@ static int pkt_setup_dev(struct pkt_ctrl
+ if (!pkt_devs[idx])
+ break;
+ if (idx == MAX_WRITERS) {
+- printk("pktcdvd: max %d writers supported\n", MAX_WRITERS);
++ printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
+ return -EBUSY;
+ }
+
+@@ -2470,15 +2472,15 @@ static int pkt_setup_dev(struct pkt_ctrl
+
+ spin_lock_init(&pd->lock);
+ spin_lock_init(&pd->iosched.lock);
+- sprintf(pd->name, "pktcdvd%d", idx);
++ sprintf(pd->name, DRIVER_NAME"%d", idx);
+ init_waitqueue_head(&pd->wqueue);
+ pd->bio_queue = RB_ROOT;
+
+- disk->major = pkt_major;
++ disk->major = pktdev_major;
+ disk->first_minor = idx;
+ disk->fops = &pktcdvd_ops;
+ disk->flags = GENHD_FL_REMOVABLE;
+- sprintf(disk->disk_name, "pktcdvd%d", idx);
++ sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
+ disk->private_data = pd;
+ disk->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!disk->queue)
+@@ -2520,7 +2522,7 @@ static int pkt_remove_dev(struct pkt_ctr
+ break;
+ }
+ if (idx == MAX_WRITERS) {
+- DPRINTK("pktcdvd: dev not setup\n");
++ DPRINTK(DRIVER_NAME": dev not setup\n");
+ return -ENXIO;
+ }
+
+@@ -2533,7 +2535,7 @@ static int pkt_remove_dev(struct pkt_ctr
+ blkdev_put(pd->bdev);
+
+ remove_proc_entry(pd->name, pkt_proc);
+- DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
++ DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
+
+ del_gendisk(pd->disk);
+ blk_cleanup_queue(pd->disk->queue);
+@@ -2610,7 +2612,7 @@ static struct file_operations pkt_ctl_fo
+
+ static struct miscdevice pkt_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+- .name = "pktcdvd",
++ .name = DRIVER_NAME,
+ .fops = &pkt_ctl_fops
+ };
+
+@@ -2623,28 +2625,28 @@ static int __init pkt_init(void)
+ if (!psd_pool)
+ return -ENOMEM;
+
+- ret = register_blkdev(pkt_major, "pktcdvd");
++ ret = register_blkdev(pktdev_major, DRIVER_NAME);
+ if (ret < 0) {
+- printk("pktcdvd: Unable to register block device\n");
++ printk(DRIVER_NAME": Unable to register block device\n");
+ goto out2;
+ }
+- if (!pkt_major)
+- pkt_major = ret;
++ if (!pktdev_major)
++ pktdev_major = ret;
+
+ ret = misc_register(&pkt_misc);
+ if (ret) {
+- printk("pktcdvd: Unable to register misc device\n");
++ printk(DRIVER_NAME": Unable to register misc device\n");
+ goto out;
+ }
+
+ mutex_init(&ctl_mutex);
+
+- pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
++ pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
+
+ return 0;
+
+ out:
+- unregister_blkdev(pkt_major, "pktcdvd");
++ unregister_blkdev(pktdev_major, DRIVER_NAME);
+ out2:
+ mempool_destroy(psd_pool);
+ return ret;
+@@ -2652,9 +2654,9 @@ out2:
+
+ static void __exit pkt_exit(void)
+ {
+- remove_proc_entry("pktcdvd", proc_root_driver);
++ remove_proc_entry(DRIVER_NAME, proc_root_driver);
+ misc_deregister(&pkt_misc);
+- unregister_blkdev(pkt_major, "pktcdvd");
++ unregister_blkdev(pktdev_major, DRIVER_NAME);
+ mempool_destroy(psd_pool);
+ }
+
+diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
+index 5537974..688a4fb 100644
+--- a/drivers/block/ps2esdi.c
++++ b/drivers/block/ps2esdi.c
+@@ -75,8 +75,7 @@ static int ps2esdi_out_cmd_blk(u_short *
+
+ static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode);
+
+-static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id);
+ static void (*current_int_handler) (u_int) = NULL;
+ static void ps2esdi_normal_interrupt_handler(u_int);
+ static void ps2esdi_initial_reset_int_handler(u_int);
+@@ -687,8 +686,7 @@ static void ps2esdi_prep_dma(char *buffe
+
+
+
+-static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id)
+ {
+ u_int int_ret_code;
+
+diff --git a/drivers/block/rd.c b/drivers/block/rd.c
+index a3f64bf..485aa87 100644
+--- a/drivers/block/rd.c
++++ b/drivers/block/rd.c
+@@ -432,6 +432,12 @@ static int __init rd_init(void)
+ rd_disks[i] = alloc_disk(1);
+ if (!rd_disks[i])
+ goto out;
++
++ rd_queue[i] = blk_alloc_queue(GFP_KERNEL);
++ if (!rd_queue[i]) {
++ put_disk(rd_disks[i]);
++ goto out;
++ }
+ }
+
+ if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) {
+@@ -442,10 +448,6 @@ static int __init rd_init(void)
+ for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) {
+ struct gendisk *disk = rd_disks[i];
+
+- rd_queue[i] = blk_alloc_queue(GFP_KERNEL);
+- if (!rd_queue[i])
+- goto out_queue;
+-
+ blk_queue_make_request(rd_queue[i], &rd_make_request);
+ blk_queue_hardsect_size(rd_queue[i], rd_blocksize);
+
+@@ -466,8 +468,6 @@ static int __init rd_init(void)
+ CONFIG_BLK_DEV_RAM_COUNT, rd_size, rd_blocksize);
+
+ return 0;
+-out_queue:
+- unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
+ out:
+ while (i--) {
+ put_disk(rd_disks[i]);
+diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
+index cc42e76..1a65979 100644
+--- a/drivers/block/swim3.c
++++ b/drivers/block/swim3.c
+@@ -238,8 +238,8 @@ static void scan_timeout(unsigned long d
+ static void seek_timeout(unsigned long data);
+ static void settle_timeout(unsigned long data);
+ static void xfer_timeout(unsigned long data);
+-static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
++static irqreturn_t swim3_interrupt(int irq, void *dev_id);
++/*static void fd_dma_interrupt(int irq, void *dev_id);*/
+ static int grab_drive(struct floppy_state *fs, enum swim_state state,
+ int interruptible);
+ static void release_drive(struct floppy_state *fs);
+@@ -319,8 +319,8 @@ static void start_request(struct floppy_
+ printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+ req->rq_disk->disk_name, req->cmd,
+ (long)req->sector, req->nr_sectors, req->buffer);
+- printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
+- req->rq_status, req->errors, req->current_nr_sectors);
++ printk(" errors=%d current_nr_sectors=%ld\n",
++ req->errors, req->current_nr_sectors);
+ #endif
+
+ if (req->sector < 0 || req->sector >= fs->total_secs) {
+@@ -624,7 +624,7 @@ static void xfer_timeout(unsigned long d
+ start_request(fs);
+ }
+
+-static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t swim3_interrupt(int irq, void *dev_id)
+ {
+ struct floppy_state *fs = (struct floppy_state *) dev_id;
+ struct swim3 __iomem *sw = fs->swim3;
+@@ -636,7 +636,7 @@ static irqreturn_t swim3_interrupt(int i
+ intr = in_8(&sw->intr);
+ err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
+ if ((intr & ERROR_INTR) && fs->state != do_transfer)
+- printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
++ printk(KERN_ERR "swim3_interrupt, state=%d, dir=%x, intr=%x, err=%x\n",
+ fs->state, rq_data_dir(fd_req), intr, err);
+ switch (fs->state) {
+ case locating:
+@@ -742,7 +742,7 @@ static irqreturn_t swim3_interrupt(int i
+ if ((stat & ACTIVE) == 0 || resid != 0) {
+ /* musta been an error */
+ printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
+- printk(KERN_ERR " state=%d, dir=%lx, intr=%x, err=%x\n",
++ printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n",
+ fs->state, rq_data_dir(fd_req), intr, err);
+ end_request(fd_req, 0);
+ fs->state = idle;
+@@ -777,7 +777,7 @@ static irqreturn_t swim3_interrupt(int i
+ }
+
+ /*
+-static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void fd_dma_interrupt(int irq, void *dev_id)
+ {
+ }
+ */
+diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
+index 89e3c2f..ed7b06c 100644
+--- a/drivers/block/swim_iop.c
++++ b/drivers/block/swim_iop.c
+@@ -94,7 +94,7 @@ static char *drive_names[7] = {
+ int swimiop_init(void);
+ static void swimiop_init_request(struct swim_iop_req *);
+ static int swimiop_send_request(struct swim_iop_req *);
+-static void swimiop_receive(struct iop_msg *, struct pt_regs *);
++static void swimiop_receive(struct iop_msg *);
+ static void swimiop_status_update(int, struct swim_drvstatus *);
+ static int swimiop_eject(struct floppy_state *fs);
+
+@@ -257,7 +257,7 @@ static int swimiop_send_request(struct s
+ * 2. An unsolicited message was received from the IOP.
+ */
+
+-void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs)
++void swimiop_receive(struct iop_msg *msg)
+ {
+ struct swim_iop_req *req;
+ struct swimmsg_status *sm;
+@@ -529,8 +529,8 @@ static void start_request(struct floppy_
+ printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+ CURRENT->rq_disk->disk_name, CURRENT->cmd,
+ CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer);
+- printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
+- CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
++ printk(" errors=%d current_nr_sectors=%ld\n",
++ CURRENT->errors, CURRENT->current_nr_sectors);
+ #endif
+
+ if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
+diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
+index c6beee1..47d6975 100644
+--- a/drivers/block/sx8.c
++++ b/drivers/block/sx8.c
+@@ -1200,7 +1200,7 @@ static inline void carm_handle_responses
+ host->resp_idx += work;
+ }
+
+-static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs)
++static irqreturn_t carm_interrupt(int irq, void *__host)
+ {
+ struct carm_host *host = __host;
+ void __iomem *mmio;
+diff --git a/drivers/block/ub.c b/drivers/block/ub.c
+index d62b49f..0d5c73f 100644
+--- a/drivers/block/ub.c
++++ b/drivers/block/ub.c
+@@ -358,11 +358,11 @@ static void ub_cmd_build_block(struct ub
+ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
+ struct ub_scsi_cmd *cmd, struct ub_request *urq);
+ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+-static void ub_end_rq(struct request *rq, int uptodate);
++static void ub_end_rq(struct request *rq, unsigned int status);
+ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
+ struct ub_request *urq, struct ub_scsi_cmd *cmd);
+ static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+-static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
++static void ub_urb_complete(struct urb *urb);
+ static void ub_scsi_action(unsigned long _dev);
+ static void ub_scsi_dispatch(struct ub_dev *sc);
+ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+@@ -639,9 +639,15 @@ static int ub_request_fn_1(struct ub_lun
+ struct ub_request *urq;
+ int n_elem;
+
+- if (atomic_read(&sc->poison) || lun->changed) {
++ if (atomic_read(&sc->poison)) {
++ blkdev_dequeue_request(rq);
++ ub_end_rq(rq, DID_NO_CONNECT << 16);
++ return 0;
++ }
++
++ if (lun->changed && !blk_pc_request(rq)) {
+ blkdev_dequeue_request(rq);
+- ub_end_rq(rq, 0);
++ ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
+ return 0;
+ }
+
+@@ -693,7 +699,7 @@ static int ub_request_fn_1(struct ub_lun
+
+ drop:
+ ub_put_cmd(lun, cmd);
+- ub_end_rq(rq, 0);
++ ub_end_rq(rq, DID_ERROR << 16);
+ return 0;
+ }
+
+@@ -761,47 +767,53 @@ static void ub_rw_cmd_done(struct ub_dev
+ struct ub_lun *lun = cmd->lun;
+ struct ub_request *urq = cmd->back;
+ struct request *rq;
+- int uptodate;
++ unsigned int scsi_status;
+
+ rq = urq->rq;
+
+ if (cmd->error == 0) {
+- uptodate = 1;
+-
+ if (blk_pc_request(rq)) {
+ if (cmd->act_len >= rq->data_len)
+ rq->data_len = 0;
+ else
+ rq->data_len -= cmd->act_len;
+ }
++ scsi_status = 0;
+ } else {
+- uptodate = 0;
+-
+ if (blk_pc_request(rq)) {
+ /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
+ memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
+ rq->sense_len = UB_SENSE_SIZE;
+ if (sc->top_sense[0] != 0)
+- rq->errors = SAM_STAT_CHECK_CONDITION;
++ scsi_status = SAM_STAT_CHECK_CONDITION;
+ else
+- rq->errors = DID_ERROR << 16;
++ scsi_status = DID_ERROR << 16;
+ } else {
+ if (cmd->error == -EIO) {
+ if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
+ return;
+ }
++ scsi_status = SAM_STAT_CHECK_CONDITION;
+ }
+ }
+
+ urq->rq = NULL;
+
+ ub_put_cmd(lun, cmd);
+- ub_end_rq(rq, uptodate);
++ ub_end_rq(rq, scsi_status);
+ blk_start_queue(lun->disk->queue);
+ }
+
+-static void ub_end_rq(struct request *rq, int uptodate)
++static void ub_end_rq(struct request *rq, unsigned int scsi_status)
+ {
++ int uptodate;
++
++ if (scsi_status == 0) {
++ uptodate = 1;
++ } else {
++ uptodate = 0;
++ rq->errors = scsi_status;
++ }
+ end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
+ end_that_request_last(rq, uptodate);
+ }
+@@ -947,7 +959,7 @@ static void ub_urb_timeout(unsigned long
+ * the sc->lock taken) and from an interrupt (while we do NOT have
+ * the sc->lock taken). Therefore, bounce this off to a tasklet.
+ */
+-static void ub_urb_complete(struct urb *urb, struct pt_regs *pt)
++static void ub_urb_complete(struct urb *urb)
+ {
+ struct ub_dev *sc = urb->context;
+
+@@ -1911,7 +1923,7 @@ err_alloc:
+
+ /*
+ */
+-static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt)
++static void ub_probe_urb_complete(struct urb *urb)
+ {
+ struct completion *cop = urb->context;
+ complete(cop);
+diff --git a/drivers/block/umem.c b/drivers/block/umem.c
+index 5d8925b..30f16bd 100644
+--- a/drivers/block/umem.c
++++ b/drivers/block/umem.c
+@@ -552,7 +552,8 @@ static void process_page(unsigned long d
+ static int mm_make_request(request_queue_t *q, struct bio *bio)
+ {
+ struct cardinfo *card = q->queuedata;
+- pr_debug("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size);
++ pr_debug("mm_make_request %llu %u\n",
++ (unsigned long long)bio->bi_sector, bio->bi_size);
+
+ bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/
+ spin_lock_irq(&card->lock);
+@@ -570,7 +571,7 @@ static int mm_make_request(request_queue
+ -- mm_interrupt
+ -----------------------------------------------------------------------------------
+ */
+-static irqreturn_t mm_interrupt(int irq, void *__card, struct pt_regs *regs)
++static irqreturn_t mm_interrupt(int irq, void *__card)
+ {
+ struct cardinfo *card = (struct cardinfo *) __card;
+ unsigned int dma_status;
+diff --git a/drivers/block/xd.c b/drivers/block/xd.c
+index e828e4c..0d97b7e 100644
+--- a/drivers/block/xd.c
++++ b/drivers/block/xd.c
+@@ -48,9 +48,9 @@
+ #include <linux/blkdev.h>
+ #include <linux/blkpg.h>
+ #include <linux/delay.h>
++#include <linux/io.h>
+
+ #include <asm/system.h>
+-#include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/dma.h>
+
+@@ -313,7 +313,7 @@ static void do_xd_request (request_queue
+ int res = 0;
+ int retry;
+
+- if (!(req->flags & REQ_CMD)) {
++ if (!blk_fs_request(req)) {
+ end_request(req, 0);
+ continue;
+ }
+@@ -462,8 +462,7 @@ static void xd_recalibrate (u_char drive
+ }
+
+ /* xd_interrupt_handler: interrupt service routine */
+-static irqreturn_t xd_interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t xd_interrupt_handler(int irq, void *dev_id)
+ {
+ if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
+ #ifdef DEBUG_OTHER
+diff --git a/drivers/block/xd.h b/drivers/block/xd.h
+index 71ac2e3..82e090f 100644
+--- a/drivers/block/xd.h
++++ b/drivers/block/xd.h
+@@ -109,8 +109,7 @@ static int xd_ioctl (struct inode *inode
+ static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
+ static void xd_recalibrate (u_char drive);
+
+-static irqreturn_t xd_interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t xd_interrupt_handler(int irq, void *dev_id);
+ static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
+ static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
+ static void xd_watchdog (unsigned long unused);
+diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
+index 82ddbdd..7cc2685 100644
+--- a/drivers/block/z2ram.c
++++ b/drivers/block/z2ram.c
+@@ -329,7 +329,7 @@ static struct kobject *z2_find(dev_t dev
+
+ static struct request_queue *z2_queue;
+
+-int __init
++static int __init
+ z2_init(void)
+ {
+ int ret;
+@@ -370,26 +370,7 @@ err:
+ return ret;
+ }
+
+-#if defined(MODULE)
+-
+-MODULE_LICENSE("GPL");
+-
+-int
+-init_module( void )
+-{
+- int error;
+-
+- error = z2_init();
+- if ( error == 0 )
+- {
+- printk( KERN_INFO DEVICE_NAME ": loaded as module\n" );
+- }
+-
+- return error;
+-}
+-
+-void
+-cleanup_module( void )
++static void __exit z2_exit(void)
+ {
+ int i, j;
+ blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256);
+@@ -425,4 +406,7 @@ cleanup_module( void )
+
+ return;
+ }
+-#endif
++
++module_init(z2_init);
++module_exit(z2_exit);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
+index 13ba729..5167517 100644
+--- a/drivers/bluetooth/bcm203x.c
++++ b/drivers/bluetooth/bcm203x.c
+@@ -29,7 +29,6 @@
+ #include <linux/slab.h>
+ #include <linux/types.h>
+ #include <linux/errno.h>
+-#include <linux/timer.h>
+
+ #include <linux/device.h>
+ #include <linux/firmware.h>
+@@ -43,7 +42,7 @@
+ #define BT_DBG(D...)
+ #endif
+
+-#define VERSION "1.0"
++#define VERSION "1.1"
+
+ static int ignore = 0;
+
+@@ -72,7 +71,7 @@ struct bcm203x_data {
+
+ unsigned long state;
+
+- struct timer_list timer;
++ struct work_struct work;
+
+ struct urb *urb;
+ unsigned char *buffer;
+@@ -82,7 +81,7 @@ struct bcm203x_data {
+ unsigned int fw_sent;
+ };
+
+-static void bcm203x_complete(struct urb *urb, struct pt_regs *regs)
++static void bcm203x_complete(struct urb *urb)
+ {
+ struct bcm203x_data *data = urb->context;
+ struct usb_device *udev = urb->dev;
+@@ -105,7 +104,7 @@ static void bcm203x_complete(struct urb
+
+ data->state = BCM203X_SELECT_MEMORY;
+
+- mod_timer(&data->timer, jiffies + (HZ / 10));
++ schedule_work(&data->work);
+ break;
+
+ case BCM203X_SELECT_MEMORY:
+@@ -158,9 +157,9 @@ static void bcm203x_complete(struct urb
+ }
+ }
+
+-static void bcm203x_timer(unsigned long user_data)
++static void bcm203x_work(void *user_data)
+ {
+- struct bcm203x_data *data = (struct bcm203x_data *) user_data;
++ struct bcm203x_data *data = user_data;
+
+ if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
+ BT_ERR("Can't submit URB");
+@@ -247,13 +246,11 @@ static int bcm203x_probe(struct usb_inte
+
+ release_firmware(firmware);
+
+- init_timer(&data->timer);
+- data->timer.function = bcm203x_timer;
+- data->timer.data = (unsigned long) data;
++ INIT_WORK(&data->work, bcm203x_work, (void *) data);
+
+ usb_set_intfdata(intf, data);
+
+- mod_timer(&data->timer, jiffies + HZ);
++ schedule_work(&data->work);
+
+ return 0;
+ }
+diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
+index 23f9621..31ade99 100644
+--- a/drivers/bluetooth/bfusb.c
++++ b/drivers/bluetooth/bfusb.c
+@@ -2,7 +2,7 @@
+ *
+ * AVM BlueFRITZ! USB driver
+ *
+- * Copyright (C) 2003 Marcel Holtmann <marcel at holtmann.org>
++ * Copyright (C) 2003-2006 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+@@ -59,7 +59,6 @@ static struct usb_device_id bfusb_table[
+
+ MODULE_DEVICE_TABLE(usb, bfusb_table);
+
+-
+ #define BFUSB_MAX_BLOCK_SIZE 256
+
+ #define BFUSB_BLOCK_TIMEOUT 3000
+@@ -70,7 +69,7 @@ MODULE_DEVICE_TABLE(usb, bfusb_table);
+ #define BFUSB_MAX_BULK_TX 2
+ #define BFUSB_MAX_BULK_RX 2
+
+-struct bfusb {
++struct bfusb_data {
+ struct hci_dev *hdev;
+
+ unsigned long state;
+@@ -92,137 +91,136 @@ struct bfusb {
+ struct sk_buff_head completed_q;
+ };
+
+-struct bfusb_scb {
++struct bfusb_data_scb {
+ struct urb *urb;
+ };
+
+-static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs);
+-static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs);
++static void bfusb_tx_complete(struct urb *urb);
++static void bfusb_rx_complete(struct urb *urb);
+
+-static struct urb *bfusb_get_completed(struct bfusb *bfusb)
++static struct urb *bfusb_get_completed(struct bfusb_data *data)
+ {
+ struct sk_buff *skb;
+ struct urb *urb = NULL;
+
+- BT_DBG("bfusb %p", bfusb);
++ BT_DBG("bfusb %p", data);
+
+- skb = skb_dequeue(&bfusb->completed_q);
++ skb = skb_dequeue(&data->completed_q);
+ if (skb) {
+- urb = ((struct bfusb_scb *) skb->cb)->urb;
++ urb = ((struct bfusb_data_scb *) skb->cb)->urb;
+ kfree_skb(skb);
+ }
+
+ return urb;
+ }
+
+-static void bfusb_unlink_urbs(struct bfusb *bfusb)
++static void bfusb_unlink_urbs(struct bfusb_data *data)
+ {
+ struct sk_buff *skb;
+ struct urb *urb;
+
+- BT_DBG("bfusb %p", bfusb);
++ BT_DBG("bfusb %p", data);
+
+- while ((skb = skb_dequeue(&bfusb->pending_q))) {
+- urb = ((struct bfusb_scb *) skb->cb)->urb;
++ while ((skb = skb_dequeue(&data->pending_q))) {
++ urb = ((struct bfusb_data_scb *) skb->cb)->urb;
+ usb_kill_urb(urb);
+- skb_queue_tail(&bfusb->completed_q, skb);
++ skb_queue_tail(&data->completed_q, skb);
+ }
+
+- while ((urb = bfusb_get_completed(bfusb)))
++ while ((urb = bfusb_get_completed(data)))
+ usb_free_urb(urb);
+ }
+
+-
+-static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
++static int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb)
+ {
+- struct bfusb_scb *scb = (void *) skb->cb;
+- struct urb *urb = bfusb_get_completed(bfusb);
++ struct bfusb_data_scb *scb = (void *) skb->cb;
++ struct urb *urb = bfusb_get_completed(data);
+ int err, pipe;
+
+- BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
++ BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len);
+
+ if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
+ return -ENOMEM;
+
+- pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
++ pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
+
+- usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, skb->len,
++ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len,
+ bfusb_tx_complete, skb);
+
+ scb->urb = urb;
+
+- skb_queue_tail(&bfusb->pending_q, skb);
++ skb_queue_tail(&data->pending_q, skb);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ BT_ERR("%s bulk tx submit failed urb %p err %d",
+- bfusb->hdev->name, urb, err);
+- skb_unlink(skb, &bfusb->pending_q);
++ data->hdev->name, urb, err);
++ skb_unlink(skb, &data->pending_q);
+ usb_free_urb(urb);
+ } else
+- atomic_inc(&bfusb->pending_tx);
++ atomic_inc(&data->pending_tx);
+
+ return err;
+ }
+
+-static void bfusb_tx_wakeup(struct bfusb *bfusb)
++static void bfusb_tx_wakeup(struct bfusb_data *data)
+ {
+ struct sk_buff *skb;
+
+- BT_DBG("bfusb %p", bfusb);
++ BT_DBG("bfusb %p", data);
+
+- if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
+- set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
++ if (test_and_set_bit(BFUSB_TX_PROCESS, &data->state)) {
++ set_bit(BFUSB_TX_WAKEUP, &data->state);
+ return;
+ }
+
+ do {
+- clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
++ clear_bit(BFUSB_TX_WAKEUP, &data->state);
+
+- while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
+- (skb = skb_dequeue(&bfusb->transmit_q))) {
+- if (bfusb_send_bulk(bfusb, skb) < 0) {
+- skb_queue_head(&bfusb->transmit_q, skb);
++ while ((atomic_read(&data->pending_tx) < BFUSB_MAX_BULK_TX) &&
++ (skb = skb_dequeue(&data->transmit_q))) {
++ if (bfusb_send_bulk(data, skb) < 0) {
++ skb_queue_head(&data->transmit_q, skb);
+ break;
+ }
+ }
+
+- } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
++ } while (test_bit(BFUSB_TX_WAKEUP, &data->state));
+
+- clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
++ clear_bit(BFUSB_TX_PROCESS, &data->state);
+ }
+
+-static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs)
++static void bfusb_tx_complete(struct urb *urb)
+ {
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+- struct bfusb *bfusb = (struct bfusb *) skb->dev;
++ struct bfusb_data *data = (struct bfusb_data *) skb->dev;
+
+- BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
++ BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
+
+- atomic_dec(&bfusb->pending_tx);
++ atomic_dec(&data->pending_tx);
+
+- if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
++ if (!test_bit(HCI_RUNNING, &data->hdev->flags))
+ return;
+
+ if (!urb->status)
+- bfusb->hdev->stat.byte_tx += skb->len;
++ data->hdev->stat.byte_tx += skb->len;
+ else
+- bfusb->hdev->stat.err_tx++;
++ data->hdev->stat.err_tx++;
+
+- read_lock(&bfusb->lock);
++ read_lock(&data->lock);
+
+- skb_unlink(skb, &bfusb->pending_q);
+- skb_queue_tail(&bfusb->completed_q, skb);
++ skb_unlink(skb, &data->pending_q);
++ skb_queue_tail(&data->completed_q, skb);
+
+- bfusb_tx_wakeup(bfusb);
++ bfusb_tx_wakeup(data);
+
+- read_unlock(&bfusb->lock);
++ read_unlock(&data->lock);
+ }
+
+
+-static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
++static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb)
+ {
+- struct bfusb_scb *scb;
++ struct bfusb_data_scb *scb;
+ struct sk_buff *skb;
+ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
+
+@@ -231,28 +229,29 @@ static int bfusb_rx_submit(struct bfusb
+ if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
+ return -ENOMEM;
+
+- if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
++ skb = bt_skb_alloc(size, GFP_ATOMIC);
++ if (!skb) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+- skb->dev = (void *) bfusb;
++ skb->dev = (void *) data;
+
+- scb = (struct bfusb_scb *) skb->cb;
++ scb = (struct bfusb_data_scb *) skb->cb;
+ scb->urb = urb;
+
+- pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
++ pipe = usb_rcvbulkpipe(data->udev, data->bulk_in_ep);
+
+- usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size,
++ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, size,
+ bfusb_rx_complete, skb);
+
+- skb_queue_tail(&bfusb->pending_q, skb);
++ skb_queue_tail(&data->pending_q, skb);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ BT_ERR("%s bulk rx submit failed urb %p err %d",
+- bfusb->hdev->name, urb, err);
+- skb_unlink(skb, &bfusb->pending_q);
++ data->hdev->name, urb, err);
++ skb_unlink(skb, &data->pending_q);
+ kfree_skb(skb);
+ usb_free_urb(urb);
+ }
+@@ -260,15 +259,15 @@ static int bfusb_rx_submit(struct bfusb
+ return err;
+ }
+
+-static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
++static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
+ {
+- BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
++ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);
+
+ if (hdr & 0x10) {
+- BT_ERR("%s error in block", bfusb->hdev->name);
+- if (bfusb->reassembly)
+- kfree_skb(bfusb->reassembly);
+- bfusb->reassembly = NULL;
++ BT_ERR("%s error in block", data->hdev->name);
++ if (data->reassembly)
++ kfree_skb(data->reassembly);
++ data->reassembly = NULL;
+ return -EIO;
+ }
+
+@@ -277,46 +276,46 @@ static inline int bfusb_recv_block(struc
+ unsigned char pkt_type;
+ int pkt_len = 0;
+
+- if (bfusb->reassembly) {
+- BT_ERR("%s unexpected start block", bfusb->hdev->name);
+- kfree_skb(bfusb->reassembly);
+- bfusb->reassembly = NULL;
++ if (data->reassembly) {
++ BT_ERR("%s unexpected start block", data->hdev->name);
++ kfree_skb(data->reassembly);
++ data->reassembly = NULL;
+ }
+
+ if (len < 1) {
+- BT_ERR("%s no packet type found", bfusb->hdev->name);
++ BT_ERR("%s no packet type found", data->hdev->name);
+ return -EPROTO;
+ }
+
+- pkt_type = *data++; len--;
++ pkt_type = *buf++; len--;
+
+ switch (pkt_type) {
+ case HCI_EVENT_PKT:
+ if (len >= HCI_EVENT_HDR_SIZE) {
+- struct hci_event_hdr *hdr = (struct hci_event_hdr *) data;
++ struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
+ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
+ } else {
+- BT_ERR("%s event block is too short", bfusb->hdev->name);
++ BT_ERR("%s event block is too short", data->hdev->name);
+ return -EILSEQ;
+ }
+ break;
+
+ case HCI_ACLDATA_PKT:
+ if (len >= HCI_ACL_HDR_SIZE) {
+- struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data;
++ struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
+ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
+ } else {
+- BT_ERR("%s data block is too short", bfusb->hdev->name);
++ BT_ERR("%s data block is too short", data->hdev->name);
+ return -EILSEQ;
+ }
+ break;
+
+ case HCI_SCODATA_PKT:
+ if (len >= HCI_SCO_HDR_SIZE) {
+- struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data;
++ struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
+ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
+ } else {
+- BT_ERR("%s audio block is too short", bfusb->hdev->name);
++ BT_ERR("%s audio block is too short", data->hdev->name);
+ return -EILSEQ;
+ }
+ break;
+@@ -324,51 +323,51 @@ static inline int bfusb_recv_block(struc
+
+ skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
+ if (!skb) {
+- BT_ERR("%s no memory for the packet", bfusb->hdev->name);
++ BT_ERR("%s no memory for the packet", data->hdev->name);
+ return -ENOMEM;
+ }
+
+- skb->dev = (void *) bfusb->hdev;
++ skb->dev = (void *) data->hdev;
+ bt_cb(skb)->pkt_type = pkt_type;
+
+- bfusb->reassembly = skb;
++ data->reassembly = skb;
+ } else {
+- if (!bfusb->reassembly) {
+- BT_ERR("%s unexpected continuation block", bfusb->hdev->name);
++ if (!data->reassembly) {
++ BT_ERR("%s unexpected continuation block", data->hdev->name);
+ return -EIO;
+ }
+ }
+
+ if (len > 0)
+- memcpy(skb_put(bfusb->reassembly, len), data, len);
++ memcpy(skb_put(data->reassembly, len), buf, len);
+
+ if (hdr & 0x08) {
+- hci_recv_frame(bfusb->reassembly);
+- bfusb->reassembly = NULL;
++ hci_recv_frame(data->reassembly);
++ data->reassembly = NULL;
+ }
+
+ return 0;
+ }
+
+-static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
++static void bfusb_rx_complete(struct urb *urb)
+ {
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+- struct bfusb *bfusb = (struct bfusb *) skb->dev;
++ struct bfusb_data *data = (struct bfusb_data *) skb->dev;
+ unsigned char *buf = urb->transfer_buffer;
+ int count = urb->actual_length;
+ int err, hdr, len;
+
+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
+
+- read_lock(&bfusb->lock);
++ read_lock(&data->lock);
+
+- if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
++ if (!test_bit(HCI_RUNNING, &data->hdev->flags))
+ goto unlock;
+
+ if (urb->status || !count)
+ goto resubmit;
+
+- bfusb->hdev->stat.byte_rx += count;
++ data->hdev->stat.byte_rx += count;
+
+ skb_put(skb, count);
+
+@@ -387,90 +386,89 @@ static void bfusb_rx_complete(struct urb
+
+ if (count < len) {
+ BT_ERR("%s block extends over URB buffer ranges",
+- bfusb->hdev->name);
++ data->hdev->name);
+ }
+
+ if ((hdr & 0xe1) == 0xc1)
+- bfusb_recv_block(bfusb, hdr, buf, len);
++ bfusb_recv_block(data, hdr, buf, len);
+
+ count -= len;
+ buf += len;
+ }
+
+- skb_unlink(skb, &bfusb->pending_q);
++ skb_unlink(skb, &data->pending_q);
+ kfree_skb(skb);
+
+- bfusb_rx_submit(bfusb, urb);
++ bfusb_rx_submit(data, urb);
+
+- read_unlock(&bfusb->lock);
++ read_unlock(&data->lock);
+
+ return;
+
+ resubmit:
+- urb->dev = bfusb->udev;
++ urb->dev = data->udev;
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ BT_ERR("%s bulk resubmit failed urb %p err %d",
+- bfusb->hdev->name, urb, err);
++ data->hdev->name, urb, err);
+ }
+
+ unlock:
+- read_unlock(&bfusb->lock);
++ read_unlock(&data->lock);
+ }
+
+-
+ static int bfusb_open(struct hci_dev *hdev)
+ {
+- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++ struct bfusb_data *data = hdev->driver_data;
+ unsigned long flags;
+ int i, err;
+
+- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++ BT_DBG("hdev %p bfusb %p", hdev, data);
+
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+- write_lock_irqsave(&bfusb->lock, flags);
++ write_lock_irqsave(&data->lock, flags);
+
+- err = bfusb_rx_submit(bfusb, NULL);
++ err = bfusb_rx_submit(data, NULL);
+ if (!err) {
+ for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
+- bfusb_rx_submit(bfusb, NULL);
++ bfusb_rx_submit(data, NULL);
+ } else {
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ }
+
+- write_unlock_irqrestore(&bfusb->lock, flags);
++ write_unlock_irqrestore(&data->lock, flags);
+
+ return err;
+ }
+
+ static int bfusb_flush(struct hci_dev *hdev)
+ {
+- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++ struct bfusb_data *data = hdev->driver_data;
+
+- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++ BT_DBG("hdev %p bfusb %p", hdev, data);
+
+- skb_queue_purge(&bfusb->transmit_q);
++ skb_queue_purge(&data->transmit_q);
+
+ return 0;
+ }
+
+ static int bfusb_close(struct hci_dev *hdev)
+ {
+- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++ struct bfusb_data *data = hdev->driver_data;
+ unsigned long flags;
+
+- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++ BT_DBG("hdev %p bfusb %p", hdev, data);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+- write_lock_irqsave(&bfusb->lock, flags);
+- write_unlock_irqrestore(&bfusb->lock, flags);
++ write_lock_irqsave(&data->lock, flags);
++ write_unlock_irqrestore(&data->lock, flags);
+
+- bfusb_unlink_urbs(bfusb);
++ bfusb_unlink_urbs(data);
+ bfusb_flush(hdev);
+
+ return 0;
+@@ -479,7 +477,7 @@ static int bfusb_close(struct hci_dev *h
+ static int bfusb_send_frame(struct sk_buff *skb)
+ {
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+- struct bfusb *bfusb;
++ struct bfusb_data *data;
+ struct sk_buff *nskb;
+ unsigned char buf[3];
+ int sent = 0, size, count;
+@@ -494,7 +492,7 @@ static int bfusb_send_frame(struct sk_bu
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+- bfusb = (struct bfusb *) hdev->driver_data;
++ data = hdev->driver_data;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+@@ -514,12 +512,13 @@ static int bfusb_send_frame(struct sk_bu
+ count = skb->len;
+
+ /* Max HCI frame size seems to be 1511 + 1 */
+- if (!(nskb = bt_skb_alloc(count + 32, GFP_ATOMIC))) {
++ nskb = bt_skb_alloc(count + 32, GFP_ATOMIC);
++ if (!nskb) {
+ BT_ERR("Can't allocate memory for new packet");
+ return -ENOMEM;
+ }
+
+- nskb->dev = (void *) bfusb;
++ nskb->dev = (void *) data;
+
+ while (count) {
+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
+@@ -536,18 +535,18 @@ static int bfusb_send_frame(struct sk_bu
+ }
+
+ /* Don't send frame with multiple size of bulk max packet */
+- if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
++ if ((nskb->len % data->bulk_pkt_size) == 0) {
+ buf[0] = 0xdd;
+ buf[1] = 0x00;
+ memcpy(skb_put(nskb, 2), buf, 2);
+ }
+
+- read_lock(&bfusb->lock);
++ read_lock(&data->lock);
+
+- skb_queue_tail(&bfusb->transmit_q, nskb);
+- bfusb_tx_wakeup(bfusb);
++ skb_queue_tail(&data->transmit_q, nskb);
++ bfusb_tx_wakeup(data);
+
+- read_unlock(&bfusb->lock);
++ read_unlock(&data->lock);
+
+ kfree_skb(skb);
+
+@@ -556,11 +555,11 @@ static int bfusb_send_frame(struct sk_bu
+
+ static void bfusb_destruct(struct hci_dev *hdev)
+ {
+- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++ struct bfusb_data *data = hdev->driver_data;
+
+- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++ BT_DBG("hdev %p bfusb %p", hdev, data);
+
+- kfree(bfusb);
++ kfree(data);
+ }
+
+ static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+@@ -568,25 +567,24 @@ static int bfusb_ioctl(struct hci_dev *h
+ return -ENOIOCTLCMD;
+ }
+
+-
+-static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
++static int bfusb_load_firmware(struct bfusb_data *data, unsigned char *firmware, int count)
+ {
+ unsigned char *buf;
+ int err, pipe, len, size, sent = 0;
+
+- BT_DBG("bfusb %p udev %p", bfusb, bfusb->udev);
++ BT_DBG("bfusb %p udev %p", data, data->udev);
+
+ BT_INFO("BlueFRITZ! USB loading firmware");
+
+- pipe = usb_sndctrlpipe(bfusb->udev, 0);
++ pipe = usb_sndctrlpipe(data->udev, 0);
+
+- if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
++ if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ 0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
+ BT_ERR("Can't change to loading configuration");
+ return -EBUSY;
+ }
+
+- bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
++ data->udev->toggle[0] = data->udev->toggle[1] = 0;
+
+ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
+ if (!buf) {
+@@ -594,14 +592,14 @@ static int bfusb_load_firmware(struct bf
+ return -ENOMEM;
+ }
+
+- pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
++ pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
+
+ while (count) {
+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
+
+ memcpy(buf, firmware + sent, size);
+
+- err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
++ err = usb_bulk_msg(data->udev, pipe, buf, size,
+ &len, BFUSB_BLOCK_TIMEOUT);
+
+ if (err || (len != size)) {
+@@ -613,21 +611,23 @@ static int bfusb_load_firmware(struct bf
+ count -= size;
+ }
+
+- if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
+- &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
++ err = usb_bulk_msg(data->udev, pipe, NULL, 0,
++ &len, BFUSB_BLOCK_TIMEOUT);
++ if (err < 0) {
+ BT_ERR("Error in null packet request");
+ goto error;
+ }
+
+- pipe = usb_sndctrlpipe(bfusb->udev, 0);
++ pipe = usb_sndctrlpipe(data->udev, 0);
+
+- if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
+- 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
++ err = usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
++ 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
++ if (err < 0) {
+ BT_ERR("Can't change to running configuration");
+ goto error;
+ }
+
+- bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
++ data->udev->toggle[0] = data->udev->toggle[1] = 0;
+
+ BT_INFO("BlueFRITZ! USB device ready");
+
+@@ -637,9 +637,9 @@ static int bfusb_load_firmware(struct bf
+ error:
+ kfree(buf);
+
+- pipe = usb_sndctrlpipe(bfusb->udev, 0);
++ pipe = usb_sndctrlpipe(data->udev, 0);
+
+- usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
++ usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ 0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+ return err;
+@@ -652,7 +652,7 @@ static int bfusb_probe(struct usb_interf
+ struct usb_host_endpoint *bulk_out_ep;
+ struct usb_host_endpoint *bulk_in_ep;
+ struct hci_dev *hdev;
+- struct bfusb *bfusb;
++ struct bfusb_data *data;
+
+ BT_DBG("intf %p id %p", intf, id);
+
+@@ -672,23 +672,24 @@ static int bfusb_probe(struct usb_interf
+ }
+
+ /* Initialize control structure and load firmware */
+- if (!(bfusb = kzalloc(sizeof(struct bfusb), GFP_KERNEL))) {
++ data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
++ if (!data) {
+ BT_ERR("Can't allocate memory for control structure");
+ goto done;
+ }
+
+- bfusb->udev = udev;
+- bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
+- bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
+- bfusb->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
++ data->udev = udev;
++ data->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
++ data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
++ data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
+
+- rwlock_init(&bfusb->lock);
++ rwlock_init(&data->lock);
+
+- bfusb->reassembly = NULL;
++ data->reassembly = NULL;
+
+- skb_queue_head_init(&bfusb->transmit_q);
+- skb_queue_head_init(&bfusb->pending_q);
+- skb_queue_head_init(&bfusb->completed_q);
++ skb_queue_head_init(&data->transmit_q);
++ skb_queue_head_init(&data->pending_q);
++ skb_queue_head_init(&data->completed_q);
+
+ if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
+ BT_ERR("Firmware request failed");
+@@ -697,7 +698,7 @@ static int bfusb_probe(struct usb_interf
+
+ BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
+
+- if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
++ if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
+ BT_ERR("Firmware loading failed");
+ goto release;
+ }
+@@ -711,10 +712,10 @@ static int bfusb_probe(struct usb_interf
+ goto error;
+ }
+
+- bfusb->hdev = hdev;
++ data->hdev = hdev;
+
+ hdev->type = HCI_USB;
+- hdev->driver_data = bfusb;
++ hdev->driver_data = data;
+ SET_HCIDEV_DEV(hdev, &intf->dev);
+
+ hdev->open = bfusb_open;
+@@ -732,7 +733,7 @@ static int bfusb_probe(struct usb_interf
+ goto error;
+ }
+
+- usb_set_intfdata(intf, bfusb);
++ usb_set_intfdata(intf, data);
+
+ return 0;
+
+@@ -740,7 +741,7 @@ release:
+ release_firmware(firmware);
+
+ error:
+- kfree(bfusb);
++ kfree(data);
+
+ done:
+ return -EIO;
+@@ -748,8 +749,8 @@ done:
+
+ static void bfusb_disconnect(struct usb_interface *intf)
+ {
+- struct bfusb *bfusb = usb_get_intfdata(intf);
+- struct hci_dev *hdev = bfusb->hdev;
++ struct bfusb_data *data = usb_get_intfdata(intf);
++ struct hci_dev *hdev = data->hdev;
+
+ BT_DBG("intf %p", intf);
+
+@@ -779,7 +780,8 @@ static int __init bfusb_init(void)
+
+ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
+
+- if ((err = usb_register(&bfusb_driver)) < 0)
++ err = usb_register(&bfusb_driver);
++ if (err < 0)
+ BT_ERR("Failed to register BlueFRITZ! USB driver");
+
+ return err;
+diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
+index 8eebf9c..cbc0725 100644
+--- a/drivers/bluetooth/bluecard_cs.c
++++ b/drivers/bluetooth/bluecard_cs.c
+@@ -282,7 +282,7 @@ static void bluecard_write_wakeup(blueca
+ clear_bit(ready_bit, &(info->tx_state));
+
+ if (bt_cb(skb)->pkt_type & 0x80) {
+- DECLARE_WAIT_QUEUE_HEAD(wq);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+ DEFINE_WAIT(wait);
+
+ unsigned char baud_reg;
+@@ -497,7 +497,7 @@ static void bluecard_receive(bluecard_in
+ }
+
+
+-static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
+ {
+ bluecard_info_t *info = dev_inst;
+ unsigned int iobase;
+diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
+index e0231dc..9fca651 100644
+--- a/drivers/bluetooth/bpa10x.c
++++ b/drivers/bluetooth/bpa10x.c
+@@ -263,7 +263,7 @@ static void bpa10x_wakeup(struct bpa10x_
+ }
+ }
+
+-static void bpa10x_complete(struct urb *urb, struct pt_regs *regs)
++static void bpa10x_complete(struct urb *urb)
+ {
+ struct bpa10x_data *data = urb->context;
+ unsigned char *buf = urb->transfer_buffer;
+diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
+index df7bb01..3a96a0b 100644
+--- a/drivers/bluetooth/bt3c_cs.c
++++ b/drivers/bluetooth/bt3c_cs.c
+@@ -338,7 +338,7 @@ static void bt3c_receive(bt3c_info_t *in
+ }
+
+
+-static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
+ {
+ bt3c_info_t *info = dev_inst;
+ unsigned int iobase;
+diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
+index 746ccca..3b29086 100644
+--- a/drivers/bluetooth/btuart_cs.c
++++ b/drivers/bluetooth/btuart_cs.c
+@@ -288,7 +288,7 @@ static void btuart_receive(btuart_info_t
+ }
+
+
+-static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
+ {
+ btuart_info_t *info = dev_inst;
+ unsigned int iobase;
+diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
+index 0e99def..07eafbc 100644
+--- a/drivers/bluetooth/dtl1_cs.c
++++ b/drivers/bluetooth/dtl1_cs.c
+@@ -291,7 +291,7 @@ static void dtl1_receive(dtl1_info_t *in
+ }
+
+
+-static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
+ {
+ dtl1_info_t *info = dev_inst;
+ unsigned int iobase;
+@@ -711,6 +711,7 @@ static void dtl1_release(struct pcmcia_d
+
+ static struct pcmcia_device_id dtl1_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
++ PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
+ PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
+ PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
+ PCMCIA_DEVICE_NULL
+diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
+index 93ba25b..420b645 100644
+--- a/drivers/bluetooth/hci_ldisc.c
++++ b/drivers/bluetooth/hci_ldisc.c
+@@ -241,15 +241,11 @@ static int hci_uart_send_frame(struct sk
+
+ static void hci_uart_destruct(struct hci_dev *hdev)
+ {
+- struct hci_uart *hu;
+-
+ if (!hdev)
+ return;
+
+ BT_DBG("%s", hdev->name);
+-
+- hu = (struct hci_uart *) hdev->driver_data;
+- kfree(hu);
++ kfree(hdev->driver_data);
+ }
+
+ /* ------ LDISC part ------ */
+@@ -272,7 +268,7 @@ static int hci_uart_tty_open(struct tty_
+ return -EEXIST;
+
+ if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
+- BT_ERR("Can't allocate controll structure");
++ BT_ERR("Can't allocate control structure");
+ return -ENFILE;
+ }
+
+@@ -360,7 +356,7 @@ static void hci_uart_tty_wakeup(struct t
+ *
+ * Return Value: None
+ */
+-static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
++static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
+ {
+ struct hci_uart *hu = (void *)tty->disc_data;
+
+@@ -375,7 +371,8 @@ static void hci_uart_tty_receive(struct
+ hu->hdev->stat.byte_rx += count;
+ spin_unlock(&hu->rx_lock);
+
+- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver->unthrottle)
++ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
++ tty->driver->unthrottle)
+ tty->driver->unthrottle(tty);
+ }
+
+diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
+index e2d4bea..fdea58a 100644
+--- a/drivers/bluetooth/hci_usb.c
++++ b/drivers/bluetooth/hci_usb.c
+@@ -96,6 +96,9 @@ static struct usb_device_id bluetooth_id
+ /* Ericsson with non-standard id */
+ { USB_DEVICE(0x0bdb, 0x1002) },
+
++ /* Canyon CN-BTU1 with HID interfaces */
++ { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET },
++
+ { } /* Terminating entry */
+ };
+
+@@ -115,6 +118,9 @@ static struct usb_device_id blacklist_id
+ /* IBM/Lenovo ThinkPad with Broadcom chip */
+ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
+
++ /* ANYCOM Bluetooth USB-200 and USB-250 */
++ { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
++
+ /* Microsoft Wireless Transceiver for Bluetooth 2.0 */
+ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
+
+@@ -173,8 +179,8 @@ static struct _urb *_urb_dequeue(struct
+ return _urb;
+ }
+
+-static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs);
+-static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs);
++static void hci_usb_rx_complete(struct urb *urb);
++static void hci_usb_tx_complete(struct urb *urb);
+
+ #define __pending_tx(husb, type) (&husb->pending_tx[type-1])
+ #define __pending_q(husb, type) (&husb->pending_q[type-1])
+@@ -729,7 +735,7 @@ static inline int __recv_frame(struct hc
+ return 0;
+ }
+
+-static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs)
++static void hci_usb_rx_complete(struct urb *urb)
+ {
+ struct _urb *_urb = container_of(urb, struct _urb, urb);
+ struct hci_usb *husb = (void *) urb->context;
+@@ -783,7 +789,7 @@ unlock:
+ read_unlock(&husb->completion_lock);
+ }
+
+-static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
++static void hci_usb_tx_complete(struct urb *urb)
+ {
+ struct _urb *_urb = container_of(urb, struct _urb, urb);
+ struct hci_usb *husb = (void *) urb->context;
+diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
+index aac67a3..a278d98 100644
+--- a/drivers/bluetooth/hci_vhci.c
++++ b/drivers/bluetooth/hci_vhci.c
+@@ -2,9 +2,9 @@
+ *
+ * Bluetooth virtual HCI driver
+ *
+- * Copyright (C) 2000-2001 Qualcomm Incorporated
+- * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk at qualcomm.com>
+- * Copyright (C) 2004-2005 Marcel Holtmann <marcel at holtmann.org>
++ * Copyright (C) 2000-2001 Qualcomm Incorporated
++ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk at qualcomm.com>
++ * Copyright (C) 2004-2006 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+@@ -72,21 +72,21 @@ static int vhci_open_dev(struct hci_dev
+
+ static int vhci_close_dev(struct hci_dev *hdev)
+ {
+- struct vhci_data *vhci = hdev->driver_data;
++ struct vhci_data *data = hdev->driver_data;
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+- skb_queue_purge(&vhci->readq);
++ skb_queue_purge(&data->readq);
+
+ return 0;
+ }
+
+ static int vhci_flush(struct hci_dev *hdev)
+ {
+- struct vhci_data *vhci = hdev->driver_data;
++ struct vhci_data *data = hdev->driver_data;
+
+- skb_queue_purge(&vhci->readq);
++ skb_queue_purge(&data->readq);
+
+ return 0;
+ }
+@@ -94,7 +94,7 @@ static int vhci_flush(struct hci_dev *hd
+ static int vhci_send_frame(struct sk_buff *skb)
+ {
+ struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+- struct vhci_data *vhci;
++ struct vhci_data *data;
+
+ if (!hdev) {
+ BT_ERR("Frame for unknown HCI device (hdev=NULL)");
+@@ -104,15 +104,15 @@ static int vhci_send_frame(struct sk_buf
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+- vhci = hdev->driver_data;
++ data = hdev->driver_data;
+
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+- skb_queue_tail(&vhci->readq, skb);
++ skb_queue_tail(&data->readq, skb);
+
+- if (vhci->flags & VHCI_FASYNC)
+- kill_fasync(&vhci->fasync, SIGIO, POLL_IN);
++ if (data->flags & VHCI_FASYNC)
++ kill_fasync(&data->fasync, SIGIO, POLL_IN);
+
+- wake_up_interruptible(&vhci->read_wait);
++ wake_up_interruptible(&data->read_wait);
+
+ return 0;
+ }
+@@ -122,7 +122,7 @@ static void vhci_destruct(struct hci_dev
+ kfree(hdev->driver_data);
+ }
+
+-static inline ssize_t vhci_get_user(struct vhci_data *vhci,
++static inline ssize_t vhci_get_user(struct vhci_data *data,
+ const char __user *buf, size_t count)
+ {
+ struct sk_buff *skb;
+@@ -139,7 +139,7 @@ static inline ssize_t vhci_get_user(stru
+ return -EFAULT;
+ }
+
+- skb->dev = (void *) vhci->hdev;
++ skb->dev = (void *) data->hdev;
+ bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
+ skb_pull(skb, 1);
+
+@@ -148,7 +148,7 @@ static inline ssize_t vhci_get_user(stru
+ return count;
+ }
+
+-static inline ssize_t vhci_put_user(struct vhci_data *vhci,
++static inline ssize_t vhci_put_user(struct vhci_data *data,
+ struct sk_buff *skb, char __user *buf, int count)
+ {
+ char __user *ptr = buf;
+@@ -161,42 +161,43 @@ static inline ssize_t vhci_put_user(stru
+
+ total += len;
+
+- vhci->hdev->stat.byte_tx += len;
++ data->hdev->stat.byte_tx += len;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+- vhci->hdev->stat.cmd_tx++;
++ data->hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+- vhci->hdev->stat.acl_tx++;
++ data->hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+- vhci->hdev->stat.cmd_tx++;
++ data->hdev->stat.cmd_tx++;
+ break;
+ };
+
+ return total;
+ }
+
+-static loff_t vhci_llseek(struct file * file, loff_t offset, int origin)
++static loff_t vhci_llseek(struct file *file, loff_t offset, int origin)
+ {
+ return -ESPIPE;
+ }
+
+-static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, loff_t *pos)
++static ssize_t vhci_read(struct file *file,
++ char __user *buf, size_t count, loff_t *pos)
+ {
+ DECLARE_WAITQUEUE(wait, current);
+- struct vhci_data *vhci = file->private_data;
++ struct vhci_data *data = file->private_data;
+ struct sk_buff *skb;
+ ssize_t ret = 0;
+
+- add_wait_queue(&vhci->read_wait, &wait);
++ add_wait_queue(&data->read_wait, &wait);
+ while (count) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+- skb = skb_dequeue(&vhci->readq);
++ skb = skb_dequeue(&data->readq);
+ if (!skb) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+@@ -213,7 +214,7 @@ static ssize_t vhci_read(struct file * f
+ }
+
+ if (access_ok(VERIFY_WRITE, buf, count))
+- ret = vhci_put_user(vhci, skb, buf, count);
++ ret = vhci_put_user(data, skb, buf, count);
+ else
+ ret = -EFAULT;
+
+@@ -221,7 +222,7 @@ static ssize_t vhci_read(struct file * f
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+- remove_wait_queue(&vhci->read_wait, &wait);
++ remove_wait_queue(&data->read_wait, &wait);
+
+ return ret;
+ }
+@@ -229,21 +230,21 @@ static ssize_t vhci_read(struct file * f
+ static ssize_t vhci_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *pos)
+ {
+- struct vhci_data *vhci = file->private_data;
++ struct vhci_data *data = file->private_data;
+
+ if (!access_ok(VERIFY_READ, buf, count))
+ return -EFAULT;
+
+- return vhci_get_user(vhci, buf, count);
++ return vhci_get_user(data, buf, count);
+ }
+
+ static unsigned int vhci_poll(struct file *file, poll_table *wait)
+ {
+- struct vhci_data *vhci = file->private_data;
++ struct vhci_data *data = file->private_data;
+
+- poll_wait(file, &vhci->read_wait, wait);
++ poll_wait(file, &data->read_wait, wait);
+
+- if (!skb_queue_empty(&vhci->readq))
++ if (!skb_queue_empty(&data->readq))
+ return POLLIN | POLLRDNORM;
+
+ return POLLOUT | POLLWRNORM;
+@@ -257,26 +258,26 @@ static int vhci_ioctl(struct inode *inod
+
+ static int vhci_open(struct inode *inode, struct file *file)
+ {
+- struct vhci_data *vhci;
++ struct vhci_data *data;
+ struct hci_dev *hdev;
+
+- vhci = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
+- if (!vhci)
++ data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
++ if (!data)
+ return -ENOMEM;
+
+- skb_queue_head_init(&vhci->readq);
+- init_waitqueue_head(&vhci->read_wait);
++ skb_queue_head_init(&data->readq);
++ init_waitqueue_head(&data->read_wait);
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+- kfree(vhci);
++ kfree(data);
+ return -ENOMEM;
+ }
+
+- vhci->hdev = hdev;
++ data->hdev = hdev;
+
+- hdev->type = HCI_VHCI;
+- hdev->driver_data = vhci;
++ hdev->type = HCI_VIRTUAL;
++ hdev->driver_data = data;
+
+ hdev->open = vhci_open_dev;
+ hdev->close = vhci_close_dev;
+@@ -288,20 +289,20 @@ static int vhci_open(struct inode *inode
+
+ if (hci_register_dev(hdev) < 0) {
+ BT_ERR("Can't register HCI device");
+- kfree(vhci);
++ kfree(data);
+ hci_free_dev(hdev);
+ return -EBUSY;
+ }
+
+- file->private_data = vhci;
++ file->private_data = data;
+
+ return nonseekable_open(inode, file);
+ }
+
+ static int vhci_release(struct inode *inode, struct file *file)
+ {
+- struct vhci_data *vhci = file->private_data;
+- struct hci_dev *hdev = vhci->hdev;
++ struct vhci_data *data = file->private_data;
++ struct hci_dev *hdev = data->hdev;
+
+ if (hci_unregister_dev(hdev) < 0) {
+ BT_ERR("Can't unregister HCI device %s", hdev->name);
+@@ -316,17 +317,17 @@ static int vhci_release(struct inode *in
+
+ static int vhci_fasync(int fd, struct file *file, int on)
+ {
+- struct vhci_data *vhci = file->private_data;
++ struct vhci_data *data = file->private_data;
+ int err;
+
+- err = fasync_helper(fd, file, on, &vhci->fasync);
++ err = fasync_helper(fd, file, on, &data->fasync);
+ if (err < 0)
+ return err;
+
+ if (on)
+- vhci->flags |= VHCI_FASYNC;
++ data->flags |= VHCI_FASYNC;
+ else
+- vhci->flags &= ~VHCI_FASYNC;
++ data->flags &= ~VHCI_FASYNC;
+
+ return 0;
+ }
+diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig
+index ff5652d..4b12e90 100644
+--- a/drivers/cdrom/Kconfig
++++ b/drivers/cdrom/Kconfig
+@@ -3,7 +3,7 @@
+ #
+
+ menu "Old CD-ROM drivers (not SCSI, not IDE)"
+- depends on ISA
++ depends on ISA && BLOCK
+
+ config CD_NO_IDESCSI
+ bool "Support non-SCSI/IDE/ATAPI CDROM drives"
+diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
+index d239cf8..7ea0f48 100644
+--- a/drivers/cdrom/cdrom.c
++++ b/drivers/cdrom/cdrom.c
+@@ -1,4 +1,4 @@
+-/* linux/drivers/cdrom/cdrom.c.
++/* linux/drivers/cdrom/cdrom.c
+ Copyright (c) 1996, 1997 David A. van Leeuwen.
+ Copyright (c) 1997, 1998 Erik Andersen <andersee at debian.org>
+ Copyright (c) 1998, 1999 Jens Axboe <axboe at image.dk>
+@@ -703,7 +703,7 @@ static int cdrom_has_defect_mgt(struct c
+ {
+ struct packet_command cgc;
+ char buffer[16];
+- __u16 *feature_code;
++ __be16 *feature_code;
+ int ret;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+@@ -716,7 +716,7 @@ static int cdrom_has_defect_mgt(struct c
+ if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
+ return ret;
+
+- feature_code = (__u16 *) &buffer[sizeof(struct feature_header)];
++ feature_code = (__be16 *) &buffer[sizeof(struct feature_header)];
+ if (be16_to_cpu(*feature_code) == CDF_HWDM)
+ return 0;
+
+@@ -2129,7 +2129,7 @@ static int cdrom_read_cdda_bpc(struct cd
+ rq->cmd[9] = 0xf8;
+
+ rq->cmd_len = 12;
+- rq->flags |= REQ_BLOCK_PC;
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->timeout = 60 * HZ;
+ bio = rq->bio;
+
+@@ -2963,7 +2963,7 @@ static int mmc_ioctl(struct cdrom_device
+ how much data is available for transfer. buffer[1] is
+ unfortunately ambigious and the only reliable way seem
+ to be to simply skip over the block descriptor... */
+- offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6));
++ offset = 8 + be16_to_cpu(*(__be16 *)(buffer+6));
+
+ if (offset + 16 > sizeof(buffer))
+ return -E2BIG;
+diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
+index 37bdb01..2157c58 100644
+--- a/drivers/cdrom/cdu31a.c
++++ b/drivers/cdrom/cdu31a.c
+@@ -513,7 +513,7 @@ static inline void write_cmd(unsigned ch
+ outb(cmd, sony_cd_cmd_reg);
+ }
+
+-static irqreturn_t cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cdu31a_interrupt(int irq, void *dev_id)
+ {
+ unsigned char val;
+
+@@ -1338,8 +1338,10 @@ static void do_cdu31a_request(request_qu
+ }
+
+ /* WTF??? */
+- if (!(req->flags & REQ_CMD))
++ if (!blk_fs_request(req)) {
++ end_request(req, 0);
+ continue;
++ }
+ if (rq_data_dir(req) == WRITE) {
+ end_request(req, 0);
+ continue;
+diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
+index 9b05ddd..e6d8e9e 100644
+--- a/drivers/cdrom/cm206.c
++++ b/drivers/cdrom/cm206.c
+@@ -359,7 +359,7 @@ static struct tasklet_struct cm206_taskl
+ as there seems so reason for this to happen.
+ */
+
+-static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cm206_interrupt(int sig, void *dev_id)
+ {
+ volatile ush fool;
+ cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error,
+diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
+index dcd1ab6..f574962 100644
+--- a/drivers/cdrom/mcdx.c
++++ b/drivers/cdrom/mcdx.c
+@@ -845,15 +845,11 @@ static void mcdx_delay(struct s_drive_st
+ }
+ }
+
+-static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mcdx_intr(int irq, void *dev_id)
+ {
+ struct s_drive_stuff *stuffp = dev_id;
+ unsigned char b;
+
+- if (stuffp == NULL) {
+- xwarn("mcdx: no device for intr %d\n", irq);
+- return IRQ_NONE;
+- }
+ #ifdef AK2
+ if (!stuffp->busy && stuffp->pending)
+ stuffp->int_err = 1;
+diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
+index 30ab562..f77ada9 100644
+--- a/drivers/cdrom/sonycd535.c
++++ b/drivers/cdrom/sonycd535.c
+@@ -322,7 +322,7 @@ disable_interrupts(void)
+ }
+
+ static irqreturn_t
+-cdu535_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++cdu535_interrupt(int irq, void *dev_id)
+ {
+ disable_interrupts();
+ if (waitqueue_active(&cdu535_irq_wait)) {
+diff --git a/drivers/char/.gitignore b/drivers/char/.gitignore
+index 73dfdce..83683a2 100644
+--- a/drivers/char/.gitignore
++++ b/drivers/char/.gitignore
+@@ -1,3 +1,2 @@
+ consolemap_deftbl.c
+ defkeymap.c
+-qtronixmap.c
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index c40e487..39a9f8c 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -371,36 +371,6 @@ config AU1000_SERIAL_CONSOLE
+ If you have an Alchemy AU1000 processor (MIPS based) and you want
+ to use a console on a serial port, say Y. Otherwise, say N.
+
+-config QTRONIX_KEYBOARD
+- bool "Enable Qtronix 990P Keyboard Support"
+- depends on IT8712
+- help
+- Images of Qtronix keyboards are at
+- <http://www.qtronix.com/keyboard.html>.
+-
+-config IT8172_CIR
+- bool
+- depends on QTRONIX_KEYBOARD
+- default y
+-
+-config IT8172_SCR0
+- bool "Enable Smart Card Reader 0 Support "
+- depends on IT8712
+- help
+- Say Y here to support smart-card reader 0 (SCR0) on the Integrated
+- Technology Express, Inc. ITE8172 SBC. Vendor page at
+- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
+- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+-
+-config IT8172_SCR1
+- bool "Enable Smart Card Reader 1 Support "
+- depends on IT8712
+- help
+- Say Y here to support smart-card reader 1 (SCR1) on the Integrated
+- Technology Express, Inc. ITE8172 SBC. Vendor page at
+- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
+- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+-
+ config A2232
+ tristate "Commodore A2232 serial support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
+@@ -439,6 +409,14 @@ config SGI_MBCS
+ If you have an SGI Altix with an attached SABrick
+ say Y or M here, otherwise say N.
+
++config MSPEC
++ tristate "Memory special operations driver"
++ depends on IA64
++ help
++ If you have an ia64 and you want to enable memory special
++ operations support (formerly known as fetchop), say Y here,
++ otherwise say N.
++
+ source "drivers/serial/Kconfig"
+
+ config UNIX98_PTYS
+@@ -495,6 +473,21 @@ config LEGACY_PTY_COUNT
+ When not in use, each legacy PTY occupies 12 bytes on 32-bit
+ architectures and 24 bytes on 64-bit architectures.
+
++config BRIQ_PANEL
++ tristate 'Total Impact briQ front panel driver'
++ depends on PPC_CHRP
++ ---help---
++ The briQ is a small footprint CHRP computer with a frontpanel VFD, a
++ tristate led and two switches. It is the size of a CDROM drive.
++
++ If you have such one and want anything showing on the VFD then you
++ must answer Y here.
++
++ To compile this driver as a module, choose M here: the
++ module will be called briq_panel.
++
++ It's safe to say N here.
++
+ config PRINTER
+ tristate "Parallel printer support"
+ depends on PARPORT
+@@ -596,6 +589,13 @@ config HVC_CONSOLE
+ console. This driver allows each pSeries partition to have a console
+ which is accessed via the HMC.
+
++config HVC_ISERIES
++ bool "iSeries Hypervisor Virtual Console support"
++ depends on PPC_ISERIES && !VIOCONS
++ select HVC_DRIVER
++ help
++ iSeries machines support a hypervisor virtual console.
++
+ config HVC_RTAS
+ bool "IBM RTAS Console support"
+ depends on PPC_RTAS
+@@ -717,7 +717,7 @@ config NVRAM
+
+ config RTC
+ tristate "Enhanced Real Time Clock Support"
+- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM
++ depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH
+ ---help---
+ If you say Y here and create a character special file /dev/rtc with
+ major number 10 and minor number 135 using mknod ("man mknod"), you
+@@ -801,14 +801,6 @@ config DS1302
+ will get access to the real time clock (or hardware clock) built
+ into your computer.
+
+-config S3C2410_RTC
+- bool "S3C2410 RTC Driver"
+- depends on ARCH_S3C2410
+- help
+- RTC (Realtime Clock) driver for the clock inbuilt into the
+- Samsung S3C2410. This can provide periodic interrupt rates
+- from 1Hz to 64Hz for user programs, and wakeup from Alarm.
+-
+ config COBALT_LCD
+ bool "Support for Cobalt LCD"
+ depends on MIPS_COBALT
+@@ -984,6 +976,7 @@ config GPIO_VR41XX
+
+ config RAW_DRIVER
+ tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)"
++ depends on BLOCK
+ help
+ The raw driver permits block devices to be bound to /dev/raw/rawN.
+ Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
+@@ -1053,7 +1046,7 @@ source "drivers/char/tpm/Kconfig"
+
+ config TELCLOCK
+ tristate "Telecom clock driver for MPBL0010 ATCA SBC"
+- depends on EXPERIMENTAL
++ depends on EXPERIMENTAL && X86
+ default n
+ help
+ The telecom clock device is specific to the MPBL0010 ATCA computer and
+diff --git a/drivers/char/Makefile b/drivers/char/Makefile
+index 6e0f446..777cad0 100644
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -42,15 +42,18 @@ obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += am
+ obj-$(CONFIG_SX) += sx.o generic_serial.o
+ obj-$(CONFIG_RIO) += rio/ generic_serial.o
+ obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
++obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
+ obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+ obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
+ obj-$(CONFIG_RAW_DRIVER) += raw.o
+ obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
++obj-$(CONFIG_MSPEC) += mspec.o
+ obj-$(CONFIG_MMTIMER) += mmtimer.o
+ obj-$(CONFIG_VIOCONS) += viocons.o
+ obj-$(CONFIG_VIOTAPE) += viotape.o
+ obj-$(CONFIG_HVCS) += hvcs.o
+ obj-$(CONFIG_SGI_MBCS) += mbcs.o
++obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
+
+ obj-$(CONFIG_PRINTER) += lp.o
+ obj-$(CONFIG_TIPAR) += tipar.o
+@@ -66,7 +69,6 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
+ obj-$(CONFIG_SGI_DS1286) += ds1286.o
+ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
+ obj-$(CONFIG_DS1302) += ds1302.o
+-obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
+ ifeq ($(CONFIG_GENERIC_NVRAM),y)
+ obj-$(CONFIG_NVRAM) += generic_nvram.o
+ else
+@@ -100,7 +102,7 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangche
+ obj-$(CONFIG_TCG_TPM) += tpm/
+
+ # Files generated that shall be removed upon make clean
+-clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
++clean-files := consolemap_deftbl.c defkeymap.c
+
+ quiet_cmd_conmk = CONMK $@
+ cmd_conmk = scripts/conmakehash $< > $@
+@@ -110,8 +112,6 @@ $(obj)/consolemap_deftbl.c: $(src)/$(FON
+
+ $(obj)/defkeymap.o: $(obj)/defkeymap.c
+
+-$(obj)/qtronixmap.o: $(obj)/qtronixmap.c
+-
+ # Uncomment if you're changing the keymap and have an appropriate
+ # loadkeys version for the map. By default, we'll use the shipped
+ # versions.
+@@ -119,7 +119,7 @@ $(obj)/qtronixmap.o: $(obj)/qtronixmap.c
+
+ ifdef GENERATE_KEYMAP
+
+-$(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
++$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map
+ loadkeys --mktable $< > $@.tmp
+ sed -e 's/^static *//' $@.tmp > $@
+ rm $@.tmp
+diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
+index 22f8cf2..c603bf2 100644
+--- a/drivers/char/agp/Kconfig
++++ b/drivers/char/agp/Kconfig
+@@ -1,6 +1,6 @@
+ config AGP
+ tristate "/dev/agpgart (AGP Support)"
+- depends on ALPHA || IA64 || PPC || X86
++ depends on ALPHA || IA64 || PARISC || PPC || X86
+ depends on PCI
+ ---help---
+ AGP (Accelerated Graphics Port) is a bus system mainly used to
+@@ -122,6 +122,14 @@ config AGP_HP_ZX1
+ This option gives you AGP GART support for the HP ZX1 chipset
+ for IA64 processors.
+
++config AGP_PARISC
++ tristate "HP Quicksilver AGP support"
++ depends on AGP && PARISC && 64BIT
++ help
++ This option gives you AGP GART support for the HP Quicksilver
++ AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000
++ workstation...)
++
+ config AGP_ALPHA_CORE
+ tristate "Alpha AGP support"
+ depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
+diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
+index d33a22f..3e58160 100644
+--- a/drivers/char/agp/Makefile
++++ b/drivers/char/agp/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_AGP_AMD64) += amd64-agp.o
+ obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o
+ obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o
+ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
++obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
+ obj-$(CONFIG_AGP_I460) += i460-agp.o
+ obj-$(CONFIG_AGP_INTEL) += intel-agp.o
+ obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
+diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
+index 3c623b6..8b3317f 100644
+--- a/drivers/char/agp/agp.h
++++ b/drivers/char/agp/agp.h
+@@ -117,7 +117,7 @@ struct agp_bridge_driver {
+ };
+
+ struct agp_bridge_data {
+- struct agp_version *version;
++ const struct agp_version *version;
+ struct agp_bridge_driver *driver;
+ struct vm_operations_struct *vm_ops;
+ void *previous_size;
+diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
+index 8cd5298..00b17ae 100644
+--- a/drivers/char/agp/amd64-agp.c
++++ b/drivers/char/agp/amd64-agp.c
+@@ -409,7 +409,7 @@ static int __devinit uli_agp_init(struct
+ int i;
+ unsigned size = amd64_fetch_size();
+ printk(KERN_INFO "Setting up ULi AGP.\n");
+- dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0));
++ dev1 = pci_get_slot (pdev->bus,PCI_DEVFN(0,0));
+ if (dev1 == NULL) {
+ printk(KERN_INFO PFX "Detected a ULi chipset, "
+ "but could not fine the secondary device.\n");
+@@ -442,6 +442,8 @@ static int __devinit uli_agp_init(struct
+ enuscr= httfea+ (size * 1024 * 1024) - 1;
+ pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea);
+ pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr);
++
++ pci_dev_put(dev1);
+ return 0;
+ }
+
+@@ -466,7 +468,7 @@ static int __devinit nforce3_agp_init(st
+
+ printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n");
+
+- dev1 = pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(11, 0));
++ dev1 = pci_get_slot(pdev->bus, PCI_DEVFN(11, 0));
+ if (dev1 == NULL) {
+ printk(KERN_INFO PFX "agpgart: Detected an NVIDIA "
+ "nForce3 chipset, but could not find "
+@@ -510,6 +512,8 @@ static int __devinit nforce3_agp_init(st
+ pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase);
+ pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit);
+
++ pci_dev_put(dev1);
++
+ return 0;
+ }
+
+diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
+index 509adc4..d59e037 100644
+--- a/drivers/char/agp/backend.c
++++ b/drivers/char/agp/backend.c
+@@ -44,7 +44,7 @@
+ * past 0.99 at all due to some boolean logic error. */
+ #define AGPGART_VERSION_MAJOR 0
+ #define AGPGART_VERSION_MINOR 101
+-static struct agp_version agp_current_version =
++static const struct agp_version agp_current_version =
+ {
+ .major = AGPGART_VERSION_MAJOR,
+ .minor = AGPGART_VERSION_MINOR,
+diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
+index b788b0a..30f730f 100644
+--- a/drivers/char/agp/efficeon-agp.c
++++ b/drivers/char/agp/efficeon-agp.c
+@@ -337,13 +337,6 @@ static struct agp_bridge_driver efficeon
+ .agp_destroy_page = agp_generic_destroy_page,
+ };
+
+-
+-static int agp_efficeon_resume(struct pci_dev *pdev)
+-{
+- printk(KERN_DEBUG PFX "agp_efficeon_resume()\n");
+- return efficeon_configure();
+-}
+-
+ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
+@@ -414,11 +407,18 @@ static void __devexit agp_efficeon_remov
+ agp_put_bridge(bridge);
+ }
+
++#ifdef CONFIG_PM
+ static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state)
+ {
+ return 0;
+ }
+
++static int agp_efficeon_resume(struct pci_dev *pdev)
++{
++ printk(KERN_DEBUG PFX "agp_efficeon_resume()\n");
++ return efficeon_configure();
++}
++#endif
+
+ static struct pci_device_id agp_efficeon_pci_table[] = {
+ {
+@@ -439,8 +439,10 @@ static struct pci_driver agp_efficeon_pc
+ .id_table = agp_efficeon_pci_table,
+ .probe = agp_efficeon_probe,
+ .remove = agp_efficeon_remove,
++#ifdef CONFIG_PM
+ .suspend = agp_efficeon_suspend,
+ .resume = agp_efficeon_resume,
++#endif
+ };
+
+ static int __init agp_efficeon_init(void)
+diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
+index d9c5a91..0f2ed2a 100644
+--- a/drivers/char/agp/frontend.c
++++ b/drivers/char/agp/frontend.c
+@@ -151,35 +151,12 @@ static void agp_add_seg_to_client(struct
+ client->segments = seg;
+ }
+
+-/* Originally taken from linux/mm/mmap.c from the array
+- * protection_map.
+- * The original really should be exported to modules, or
+- * some routine which does the conversion for you
+- */
+-
+-static const pgprot_t my_protect_map[16] =
+-{
+- __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
+- __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
+-};
+-
+ static pgprot_t agp_convert_mmap_flags(int prot)
+ {
+-#define _trans(x,bit1,bit2) \
+-((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
+-
+ unsigned long prot_bits;
+- pgprot_t temp;
+-
+- prot_bits = _trans(prot, PROT_READ, VM_READ) |
+- _trans(prot, PROT_WRITE, VM_WRITE) |
+- _trans(prot, PROT_EXEC, VM_EXEC);
+-
+- prot_bits |= VM_SHARED;
+
+- temp = my_protect_map[prot_bits & 0x0000000f];
+-
+- return temp;
++ prot_bits = calc_vm_prot_bits(prot) | VM_SHARED;
++ return vm_get_page_prot(prot_bits);
+ }
+
+ static int agp_create_segment(struct agp_client *client, struct agp_region *region)
+diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
+index cc5ea34..c392001 100644
+--- a/drivers/char/agp/generic.c
++++ b/drivers/char/agp/generic.c
+@@ -568,25 +568,37 @@ static void agp_v3_parse_one(u32 *reques
+ *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
+ goto done;
+
++ } else if (*requested_mode & AGPSTAT3_4X) {
++ *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
++ *bridge_agpstat |= AGPSTAT3_4X;
++ goto done;
++
+ } else {
+
+ /*
+- * If we didn't specify AGPx8, we can only do x4.
+- * If the hardware can't do x4, we're up shit creek, and never
+- * should have got this far.
++ * If we didn't specify an AGP mode, we see if both
++ * the graphics card, and the bridge can do x8, and use if so.
++ * If not, we fall back to x4 mode.
+ */
+- *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+- if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X))
+- *bridge_agpstat |= AGPSTAT3_4X;
+- else {
+- printk(KERN_INFO PFX "Badness. Don't know which AGP mode to set. "
+- "[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n",
+- origbridge, origvga, *bridge_agpstat, *vga_agpstat);
+- if (!(*bridge_agpstat & AGPSTAT3_4X))
+- printk(KERN_INFO PFX "Bridge couldn't do AGP x4.\n");
+- if (!(*vga_agpstat & AGPSTAT3_4X))
+- printk(KERN_INFO PFX "Graphic card couldn't do AGP x4.\n");
+- return;
++ if ((*bridge_agpstat & AGPSTAT3_8X) && (*vga_agpstat & AGPSTAT3_8X)) {
++ printk(KERN_INFO PFX "No AGP mode specified. Setting to highest mode "
++ "supported by bridge & card (x8).\n");
++ *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
++ *vga_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
++ } else {
++ printk(KERN_INFO PFX "Fell back to AGPx4 mode because");
++ if (!(*bridge_agpstat & AGPSTAT3_8X)) {
++ printk(KERN_INFO PFX "bridge couldn't do x8. bridge_agpstat:%x (orig=%x)\n",
++ *bridge_agpstat, origbridge);
++ *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
++ *bridge_agpstat |= AGPSTAT3_4X;
++ }
++ if (!(*vga_agpstat & AGPSTAT3_8X)) {
++ printk(KERN_INFO PFX "graphics card couldn't do x8. vga_agpstat:%x (orig=%x)\n",
++ *vga_agpstat, origvga);
++ *vga_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
++ *vga_agpstat |= AGPSTAT3_4X;
++ }
+ }
+ }
+
+diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
+index 61ac380..d1ede7d 100644
+--- a/drivers/char/agp/intel-agp.c
++++ b/drivers/char/agp/intel-agp.c
+@@ -2,14 +2,6 @@
+ * Intel AGPGART routines.
+ */
+
+-/*
+- * Intel(R) 855GM/852GM and 865G support added by David Dawes
+- * <dawes at tungstengraphics.com>.
+- *
+- * Intel(R) 915G/915GM support added by Alan Hourihane
+- * <alanh at tungstengraphics.com>.
+- */
+-
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/init.h>
+@@ -17,6 +9,21 @@
+ #include <linux/agp_backend.h>
+ #include "agp.h"
+
++#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
++#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972
++#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980
++#define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982
++#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990
++#define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992
++#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0
++#define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2
++
++#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \
++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB)
++
++
+ /* Intel 815 register */
+ #define INTEL_815_APCONT 0x51
+ #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
+@@ -40,6 +47,8 @@
+ #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)
+ #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
+
++/* Intel 965G registers */
++#define I965_MSAC 0x62
+
+ /* Intel 7505 registers */
+ #define INTEL_I7505_APSIZE 0x74
+@@ -354,6 +363,7 @@ static struct aper_size_info_fixed intel
+ /* The 64M mode still requires a 128k gatt */
+ {64, 16384, 5},
+ {256, 65536, 6},
++ {512, 131072, 7},
+ };
+
+ static struct _intel_i830_private {
+@@ -377,7 +387,11 @@ static void intel_i830_init_gtt_entries(
+ /* We obtain the size of the GTT, which is also stored (for some
+ * reason) at the top of stolen memory. Then we add 4KB to that
+ * for the video BIOS popup, which is also stored in there. */
+- size = agp_bridge->driver->fetch_size() + 4;
++
++ if (IS_I965)
++ size = 512 + 4;
++ else
++ size = agp_bridge->driver->fetch_size() + 4;
+
+ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+@@ -423,7 +437,7 @@ static void intel_i830_init_gtt_entries(
+ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
+- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB)
++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 )
+ gtt_entries = MB(48) - KB(size);
+ else
+ gtt_entries = 0;
+@@ -433,7 +447,7 @@ static void intel_i830_init_gtt_entries(
+ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
+- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB)
++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965)
+ gtt_entries = MB(64) - KB(size);
+ else
+ gtt_entries = 0;
+@@ -791,6 +805,77 @@ static int intel_i915_create_gatt_table(
+
+ return 0;
+ }
++static int intel_i965_fetch_size(void)
++{
++ struct aper_size_info_fixed *values;
++ u32 offset = 0;
++ u8 temp;
++
++#define I965_512MB_ADDRESS_MASK (3<<1)
++
++ values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
++
++ pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp);
++ temp &= I965_512MB_ADDRESS_MASK;
++ switch (temp) {
++ case 0x00:
++ offset = 0; /* 128MB */
++ break;
++ case 0x06:
++ offset = 3; /* 512MB */
++ break;
++ default:
++ case 0x02:
++ offset = 2; /* 256MB */
++ break;
++ }
++
++ agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
++
++ return values[offset].size;
++}
++
++/* The intel i965 automatically initializes the agp aperture during POST.
+++ * Use the memory already set aside for in the GTT.
+++ */
++static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
++{
++ int page_order;
++ struct aper_size_info_fixed *size;
++ int num_entries;
++ u32 temp;
++
++ size = agp_bridge->current_size;
++ page_order = size->page_order;
++ num_entries = size->num_entries;
++ agp_bridge->gatt_table_real = NULL;
++
++ pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp);
++
++ temp &= 0xfff00000;
++ intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024);
++
++ if (!intel_i830_private.gtt)
++ return -ENOMEM;
++
++
++ intel_i830_private.registers = ioremap(temp,128 * 4096);
++ if (!intel_i830_private.registers)
++ return -ENOMEM;
++
++ temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000;
++ global_cache_flush(); /* FIXME: ? */
++
++ /* we have to call this as early as possible after the MMIO base address is known */
++ intel_i830_init_gtt_entries();
++
++ agp_bridge->gatt_table = NULL;
++
++ agp_bridge->gatt_bus_addr = temp;
++
++ return 0;
++}
++
+
+ static int intel_fetch_size(void)
+ {
+@@ -1307,7 +1392,7 @@ static struct agp_bridge_driver intel_83
+ .owner = THIS_MODULE,
+ .aperture_sizes = intel_i830_sizes,
+ .size_type = FIXED_APER_SIZE,
+- .num_aperture_sizes = 3,
++ .num_aperture_sizes = 4,
+ .needs_scratch_page = TRUE,
+ .configure = intel_i830_configure,
+ .fetch_size = intel_i830_fetch_size,
+@@ -1469,7 +1554,7 @@ static struct agp_bridge_driver intel_91
+ .owner = THIS_MODULE,
+ .aperture_sizes = intel_i830_sizes,
+ .size_type = FIXED_APER_SIZE,
+- .num_aperture_sizes = 3,
++ .num_aperture_sizes = 4,
+ .needs_scratch_page = TRUE,
+ .configure = intel_i915_configure,
+ .fetch_size = intel_i915_fetch_size,
+@@ -1489,6 +1574,29 @@ static struct agp_bridge_driver intel_91
+ .agp_destroy_page = agp_generic_destroy_page,
+ };
+
++static struct agp_bridge_driver intel_i965_driver = {
++ .owner = THIS_MODULE,
++ .aperture_sizes = intel_i830_sizes,
++ .size_type = FIXED_APER_SIZE,
++ .num_aperture_sizes = 4,
++ .needs_scratch_page = TRUE,
++ .configure = intel_i915_configure,
++ .fetch_size = intel_i965_fetch_size,
++ .cleanup = intel_i915_cleanup,
++ .tlb_flush = intel_i810_tlbflush,
++ .mask_memory = intel_i810_mask_memory,
++ .masks = intel_i810_masks,
++ .agp_enable = intel_i810_agp_enable,
++ .cache_flush = global_cache_flush,
++ .create_gatt_table = intel_i965_create_gatt_table,
++ .free_gatt_table = intel_i830_free_gatt_table,
++ .insert_memory = intel_i915_insert_entries,
++ .remove_memory = intel_i915_remove_entries,
++ .alloc_by_type = intel_i830_alloc_by_type,
++ .free_by_type = intel_i810_free_by_type,
++ .agp_alloc_page = agp_generic_alloc_page,
++ .agp_destroy_page = agp_generic_destroy_page,
++};
+
+ static struct agp_bridge_driver intel_7505_driver = {
+ .owner = THIS_MODULE,
+@@ -1684,6 +1792,35 @@ static int __devinit agp_intel_probe(str
+ bridge->driver = &intel_845_driver;
+ name = "945GM";
+ break;
++ case PCI_DEVICE_ID_INTEL_82946GZ_HB:
++ if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG))
++ bridge->driver = &intel_i965_driver;
++ else
++ bridge->driver = &intel_845_driver;
++ name = "946GZ";
++ break;
++ case PCI_DEVICE_ID_INTEL_82965G_1_HB:
++ if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG))
++ bridge->driver = &intel_i965_driver;
++ else
++ bridge->driver = &intel_845_driver;
++ name = "965G";
++ break;
++ case PCI_DEVICE_ID_INTEL_82965Q_HB:
++ if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG))
++ bridge->driver = &intel_i965_driver;
++ else
++ bridge->driver = &intel_845_driver;
++ name = "965Q";
++ break;
++ case PCI_DEVICE_ID_INTEL_82965G_HB:
++ if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG))
++ bridge->driver = &intel_i965_driver;
++ else
++ bridge->driver = &intel_845_driver;
++ name = "965G";
++ break;
++
+ case PCI_DEVICE_ID_INTEL_7505_0:
+ bridge->driver = &intel_7505_driver;
+ name = "E7505";
+@@ -1766,6 +1903,7 @@ static void __devexit agp_intel_remove(s
+ agp_put_bridge(bridge);
+ }
+
++#ifdef CONFIG_PM
+ static int agp_intel_resume(struct pci_dev *pdev)
+ {
+ struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+@@ -1786,9 +1924,12 @@ static int agp_intel_resume(struct pci_d
+ intel_i830_configure();
+ else if (bridge->driver == &intel_810_driver)
+ intel_i810_configure();
++ else if (bridge->driver == &intel_i965_driver)
++ intel_i915_configure();
+
+ return 0;
+ }
++#endif
+
+ static struct pci_device_id agp_intel_pci_table[] = {
+ #define ID(x) \
+@@ -1825,6 +1966,10 @@ static struct pci_device_id agp_intel_pc
+ ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
+ ID(PCI_DEVICE_ID_INTEL_82945G_HB),
+ ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
++ ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
++ ID(PCI_DEVICE_ID_INTEL_82965G_1_HB),
++ ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
++ ID(PCI_DEVICE_ID_INTEL_82965G_HB),
+ { }
+ };
+
+@@ -1835,7 +1980,9 @@ static struct pci_driver agp_intel_pci_d
+ .id_table = agp_intel_pci_table,
+ .probe = agp_intel_probe,
+ .remove = __devexit_p(agp_intel_remove),
++#ifdef CONFIG_PM
+ .resume = agp_intel_resume,
++#endif
+ };
+
+ static int __init agp_intel_init(void)
+diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
+new file mode 100644
+index 0000000..17c50b0
+--- /dev/null
++++ b/drivers/char/agp/parisc-agp.c
+@@ -0,0 +1,416 @@
++/*
++ * HP Quicksilver AGP GART routines
++ *
++ * Copyright (c) 2006, Kyle McMartin <kyle at parisc-linux.org>
++ *
++ * Based on drivers/char/agpgart/hp-agp.c which is
++ * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
++ * Bjorn Helgaas <bjorn.helgaas at hp.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/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/klist.h>
++#include <linux/agp_backend.h>
++
++#include <asm-parisc/parisc-device.h>
++#include <asm-parisc/ropes.h>
++
++#include "agp.h"
++
++#define DRVNAME "quicksilver"
++#define DRVPFX DRVNAME ": "
++
++#ifndef log2
++#define log2(x) ffz(~(x))
++#endif
++
++#define AGP8X_MODE_BIT 3
++#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
++
++static struct _parisc_agp_info {
++ void __iomem *ioc_regs;
++ void __iomem *lba_regs;
++
++ int lba_cap_offset;
++
++ u64 *gatt;
++ u64 gatt_entries;
++
++ u64 gart_base;
++ u64 gart_size;
++
++ int io_page_size;
++ int io_pages_per_kpage;
++} parisc_agp_info;
++
++static struct gatt_mask parisc_agp_masks[] =
++{
++ {
++ .mask = SBA_PDIR_VALID_BIT,
++ .type = 0
++ }
++};
++
++static struct aper_size_info_fixed parisc_agp_sizes[] =
++{
++ {0, 0, 0}, /* filled in by parisc_agp_fetch_size() */
++};
++
++static int
++parisc_agp_fetch_size(void)
++{
++ int size;
++
++ size = parisc_agp_info.gart_size / MB(1);
++ parisc_agp_sizes[0].size = size;
++ agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
++
++ return size;
++}
++
++static int
++parisc_agp_configure(void)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++
++ agp_bridge->gart_bus_addr = info->gart_base;
++ agp_bridge->capndx = info->lba_cap_offset;
++ agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
++
++ return 0;
++}
++
++static void
++parisc_agp_tlbflush(struct agp_memory *mem)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++
++ writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
++ readq(info->ioc_regs+IOC_PCOM); /* flush */
++}
++
++static int
++parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int i;
++
++ for (i = 0; i < info->gatt_entries; i++) {
++ info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
++ }
++
++ return 0;
++}
++
++static int
++parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++
++ info->gatt[0] = SBA_AGPGART_COOKIE;
++
++ return 0;
++}
++
++static int
++parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int i, k;
++ off_t j, io_pg_start;
++ int io_pg_count;
++
++ if (type != 0 || mem->type != 0) {
++ return -EINVAL;
++ }
++
++ io_pg_start = info->io_pages_per_kpage * pg_start;
++ io_pg_count = info->io_pages_per_kpage * mem->page_count;
++ if ((io_pg_start + io_pg_count) > info->gatt_entries) {
++ return -EINVAL;
++ }
++
++ j = io_pg_start;
++ while (j < (io_pg_start + io_pg_count)) {
++ if (info->gatt[j])
++ return -EBUSY;
++ j++;
++ }
++
++ if (mem->is_flushed == FALSE) {
++ global_cache_flush();
++ mem->is_flushed = TRUE;
++ }
++
++ for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
++ unsigned long paddr;
++
++ paddr = mem->memory[i];
++ for (k = 0;
++ k < info->io_pages_per_kpage;
++ k++, j++, paddr += info->io_page_size) {
++ info->gatt[j] =
++ agp_bridge->driver->mask_memory(agp_bridge,
++ paddr, type);
++ }
++ }
++
++ agp_bridge->driver->tlb_flush(mem);
++
++ return 0;
++}
++
++static int
++parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int i, io_pg_start, io_pg_count;
++
++ if (type != 0 || mem->type != 0) {
++ return -EINVAL;
++ }
++
++ io_pg_start = info->io_pages_per_kpage * pg_start;
++ io_pg_count = info->io_pages_per_kpage * mem->page_count;
++ for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
++ info->gatt[i] = agp_bridge->scratch_page;
++ }
++
++ agp_bridge->driver->tlb_flush(mem);
++ return 0;
++}
++
++static unsigned long
++parisc_agp_mask_memory(struct agp_bridge_data *bridge,
++ unsigned long addr, int type)
++{
++ return SBA_PDIR_VALID_BIT | addr;
++}
++
++static void
++parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ u32 command;
++
++ command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
++
++ command = agp_collect_device_status(bridge, mode, command);
++ command |= 0x00000100;
++
++ writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
++
++ agp_device_command(command, (mode & AGP8X_MODE) != 0);
++}
++
++struct agp_bridge_driver parisc_agp_driver = {
++ .owner = THIS_MODULE,
++ .size_type = FIXED_APER_SIZE,
++ .configure = parisc_agp_configure,
++ .fetch_size = parisc_agp_fetch_size,
++ .tlb_flush = parisc_agp_tlbflush,
++ .mask_memory = parisc_agp_mask_memory,
++ .masks = parisc_agp_masks,
++ .agp_enable = parisc_agp_enable,
++ .cache_flush = global_cache_flush,
++ .create_gatt_table = parisc_agp_create_gatt_table,
++ .free_gatt_table = parisc_agp_free_gatt_table,
++ .insert_memory = parisc_agp_insert_memory,
++ .remove_memory = parisc_agp_remove_memory,
++ .alloc_by_type = agp_generic_alloc_by_type,
++ .free_by_type = agp_generic_free_by_type,
++ .agp_alloc_page = agp_generic_alloc_page,
++ .agp_destroy_page = agp_generic_destroy_page,
++ .cant_use_aperture = 1,
++};
++
++static int __init
++agp_ioc_init(void __iomem *ioc_regs)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ u64 *iova_base, *io_pdir, io_tlb_ps;
++ int io_tlb_shift;
++
++ printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
++
++ info->ioc_regs = ioc_regs;
++
++ io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
++ switch (io_tlb_ps) {
++ case 0: io_tlb_shift = 12; break;
++ case 1: io_tlb_shift = 13; break;
++ case 2: io_tlb_shift = 14; break;
++ case 3: io_tlb_shift = 16; break;
++ default:
++ printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
++ "configuration 0x%llx\n", io_tlb_ps);
++ info->gatt = NULL;
++ info->gatt_entries = 0;
++ return -ENODEV;
++ }
++ info->io_page_size = 1 << io_tlb_shift;
++ info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
++
++ iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
++ info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
++
++ info->gart_size = PLUTO_GART_SIZE;
++ info->gatt_entries = info->gart_size / info->io_page_size;
++
++ io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
++ info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
++
++ if (info->gatt[0] != SBA_AGPGART_COOKIE) {
++ info->gatt = NULL;
++ info->gatt_entries = 0;
++ printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
++ "GART disabled\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int
++lba_find_capability(int cap)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ u16 status;
++ u8 pos, id;
++ int ttl = 48;
++
++ status = readw(info->lba_regs + PCI_STATUS);
++ if (!(status & PCI_STATUS_CAP_LIST))
++ return 0;
++ pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
++ while (ttl-- && pos >= 0x40) {
++ pos &= ~3;
++ id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
++ if (id == 0xff)
++ break;
++ if (id == cap)
++ return pos;
++ pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
++ }
++ return 0;
++}
++
++static int __init
++agp_lba_init(void __iomem *lba_hpa)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int cap;
++
++ info->lba_regs = lba_hpa;
++ info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
++
++ cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
++ if (cap != PCI_CAP_ID_AGP) {
++ printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
++ cap, info->lba_cap_offset);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int __init
++parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
++{
++ struct pci_dev *fake_bridge_dev = NULL;
++ struct agp_bridge_data *bridge;
++ int error = 0;
++
++ fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
++ if (!fake_bridge_dev) {
++ error = -ENOMEM;
++ goto fail;
++ }
++
++ error = agp_ioc_init(ioc_hpa);
++ if (error)
++ goto fail;
++
++ error = agp_lba_init(lba_hpa);
++ if (error)
++ goto fail;
++
++ bridge = agp_alloc_bridge();
++ if (!bridge) {
++ error = -ENOMEM;
++ goto fail;
++ }
++ bridge->driver = &parisc_agp_driver;
++
++ fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
++ fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
++ bridge->dev = fake_bridge_dev;
++
++ error = agp_add_bridge(bridge);
++
++fail:
++ return error;
++}
++
++static struct device *next_device(struct klist_iter *i) {
++ struct klist_node * n = klist_next(i);
++ return n ? container_of(n, struct device, knode_parent) : NULL;
++}
++
++static int
++parisc_agp_init(void)
++{
++ extern struct sba_device *sba_list;
++
++ int err = -1;
++ struct parisc_device *sba = NULL, *lba = NULL;
++ struct lba_device *lbadev = NULL;
++ struct device *dev = NULL;
++ struct klist_iter i;
++
++ if (!sba_list)
++ goto out;
++
++ /* Find our parent Pluto */
++ sba = sba_list->dev;
++ if (!IS_PLUTO(sba)) {
++ printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
++ goto out;
++ }
++
++ /* Now search our Pluto for our precious AGP device... */
++ klist_iter_init(&sba->dev.klist_children, &i);
++ while ((dev = next_device(&i))) {
++ struct parisc_device *padev = to_parisc_device(dev);
++ if (IS_QUICKSILVER(padev))
++ lba = padev;
++ }
++ klist_iter_exit(&i);
++
++ if (!lba) {
++ printk(KERN_INFO DRVPFX "No AGP devices found.\n");
++ goto out;
++ }
++
++ lbadev = parisc_get_drvdata(lba);
++
++ /* w00t, let's go find our cookies... */
++ parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
++
++ return 0;
++
++out:
++ return err;
++}
++
++module_init(parisc_agp_init);
++
++MODULE_AUTHOR("Kyle McMartin <kyle at parisc-linux.org>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
+index 1de1b12..dffc193 100644
+--- a/drivers/char/agp/uninorth-agp.c
++++ b/drivers/char/agp/uninorth-agp.c
+@@ -27,32 +27,42 @@
+ static int uninorth_rev;
+ static int is_u3;
+
++static char __devinitdata *aperture = NULL;
+
+ static int uninorth_fetch_size(void)
+ {
+- int i;
+- u32 temp;
+- struct aper_size_info_32 *values;
+-
+- pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp);
+- temp &= ~(0xfffff000);
+- values = A_SIZE_32(agp_bridge->driver->aperture_sizes);
+-
+- for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
+- if (temp == values[i].size_value) {
+- agp_bridge->previous_size =
+- agp_bridge->current_size = (void *) (values + i);
+- agp_bridge->aperture_size_idx = i;
+- return values[i].size;
++ int i, size = 0;
++ struct aper_size_info_32 *values =
++ A_SIZE_32(agp_bridge->driver->aperture_sizes);
++
++ if (aperture) {
++ char *save = aperture;
++
++ size = memparse(aperture, &aperture) >> 20;
++ aperture = save;
++
++ for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++)
++ if (size == values[i].size)
++ break;
++
++ if (i == agp_bridge->driver->num_aperture_sizes) {
++ printk(KERN_ERR PFX "Invalid aperture size, using"
++ " default\n");
++ size = 0;
++ aperture = NULL;
+ }
+ }
+
+- agp_bridge->previous_size =
+- agp_bridge->current_size = (void *) (values + 1);
+- agp_bridge->aperture_size_idx = 1;
+- return values[1].size;
++ if (!size) {
++ for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++)
++ if (values[i].size == 32)
++ break;
++ }
+
+- return 0;
++ agp_bridge->previous_size =
++ agp_bridge->current_size = (void *)(values + i);
++ agp_bridge->aperture_size_idx = i;
++ return values[i].size;
+ }
+
+ static void uninorth_tlbflush(struct agp_memory *mem)
+@@ -601,8 +611,8 @@ static int __devinit agp_uninorth_probe(
+ uninorth_node = of_find_node_by_name(NULL, "u3");
+ }
+ if (uninorth_node) {
+- int *revprop = (int *)
+- get_property(uninorth_node, "device-rev", NULL);
++ const int *revprop = get_property(uninorth_node,
++ "device-rev", NULL);
+ if (revprop != NULL)
+ uninorth_rev = *revprop & 0x3f;
+ of_node_put(uninorth_node);
+@@ -683,5 +693,11 @@ static void __exit agp_uninorth_cleanup(
+ module_init(agp_uninorth_init);
+ module_exit(agp_uninorth_cleanup);
+
++module_param(aperture, charp, 0);
++MODULE_PARM_DESC(aperture,
++ "Aperture size, must be power of two between 4MB and an\n"
++ "\t\tupper limit specific to the UniNorth revision.\n"
++ "\t\tDefault: 32M");
++
+ MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
+index b8ec25d..c149ac9 100644
+--- a/drivers/char/agp/via-agp.c
++++ b/drivers/char/agp/via-agp.c
+@@ -9,7 +9,7 @@
+ #include <linux/agp_backend.h>
+ #include "agp.h"
+
+-static struct pci_device_id agp_via_pci_table[];
++static const struct pci_device_id agp_via_pci_table[];
+
+ #define VIA_GARTCTRL 0x80
+ #define VIA_APSIZE 0x84
+@@ -485,7 +485,7 @@ static int agp_via_resume(struct pci_dev
+ #endif /* CONFIG_PM */
+
+ /* must be the same order as name table above */
+-static struct pci_device_id agp_via_pci_table[] = {
++static const struct pci_device_id agp_via_pci_table[] = {
+ #define ID(x) \
+ { \
+ .class = (PCI_CLASS_BRIDGE_HOST << 8), \
+diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
+index 9d6713a..66086fa 100644
+--- a/drivers/char/amiserial.c
++++ b/drivers/char/amiserial.c
+@@ -112,17 +112,6 @@ static struct serial_state rs_table[1];
+
+ #define NR_PORTS ARRAY_SIZE(rs_table)
+
+-/*
+- * 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;
+-
+ #include <asm/uaccess.h>
+
+ #define serial_isroot() (capable(CAP_SYS_ADMIN))
+@@ -458,7 +447,7 @@ static void check_modem_status(struct as
+ }
+ }
+
+-static irqreturn_t ser_vbl_int( int irq, void *data, struct pt_regs *regs)
++static irqreturn_t ser_vbl_int( int irq, void *data)
+ {
+ /* vbl is just a periodic interrupt we tie into to update modem status */
+ struct async_struct * info = IRQ_ports;
+@@ -471,7 +460,7 @@ static irqreturn_t ser_vbl_int( int irq,
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t ser_rx_int(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ser_rx_int(int irq, void *dev_id)
+ {
+ struct async_struct * info;
+
+@@ -491,7 +480,7 @@ static irqreturn_t ser_rx_int(int irq, v
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t ser_tx_int(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ser_tx_int(int irq, void *dev_id)
+ {
+ struct async_struct * info;
+
+@@ -912,7 +901,7 @@ static int rs_write(struct tty_struct *
+ if (serial_paranoia_check(info, tty->name, "rs_write"))
+ return 0;
+
+- if (!info->xmit.buf || !tmp_buf)
++ if (!info->xmit.buf)
+ return 0;
+
+ local_save_flags(flags);
+@@ -1778,7 +1767,6 @@ static int rs_open(struct tty_struct *tt
+ {
+ struct async_struct *info;
+ int retval, line;
+- unsigned long page;
+
+ line = tty->index;
+ if ((line < 0) || (line >= NR_PORTS)) {
+@@ -1798,17 +1786,6 @@ static int rs_open(struct tty_struct *tt
+ #endif
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+- 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
+ */
+@@ -1958,7 +1935,7 @@ static void show_serial_version(void)
+ }
+
+
+-static struct tty_operations serial_ops = {
++static const struct tty_operations serial_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+@@ -2090,11 +2067,6 @@ static __exit void rs_exit(void)
+ kfree(info);
+ }
+
+- if (tmp_buf) {
+- free_page((unsigned long) tmp_buf);
+- tmp_buf = NULL;
+- }
+-
+ release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
+ }
+
+diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
+index 10a389d..1f0b752 100644
+--- a/drivers/char/applicom.c
++++ b/drivers/char/applicom.c
+@@ -110,7 +110,7 @@ static ssize_t ac_read (struct file *, c
+ static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *);
+ static int ac_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+-static irqreturn_t ac_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t ac_interrupt(int, void *);
+
+ static const struct file_operations ac_fops = {
+ .owner = THIS_MODULE,
+@@ -617,7 +617,7 @@ static ssize_t ac_read (struct file *fil
+ }
+ }
+
+-static irqreturn_t ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t ac_interrupt(int vec, void *dev_instance)
+ {
+ unsigned int i;
+ unsigned int FlagInt;
+diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
+new file mode 100644
+index 0000000..9f8082f
+--- /dev/null
++++ b/drivers/char/briq_panel.c
+@@ -0,0 +1,270 @@
++/*
++ * Drivers for the Total Impact PPC based computer "BRIQ"
++ * by Dr. Karsten Jeppesen
++ *
++ */
++
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/tty.h>
++#include <linux/timer.h>
++#include <linux/kernel.h>
++#include <linux/wait.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/prom.h>
++
++#define BRIQ_PANEL_MINOR 156
++#define BRIQ_PANEL_VFD_IOPORT 0x0390
++#define BRIQ_PANEL_LED_IOPORT 0x0398
++#define BRIQ_PANEL_VER "1.1 (04/20/2002)"
++#define BRIQ_PANEL_MSG0 "Loading Linux"
++
++static int vfd_is_open;
++static unsigned char vfd[40];
++static int vfd_cursor;
++static unsigned char ledpb, led;
++
++static void update_vfd(void)
++{
++ int i;
++
++ /* cursor home */
++ outb(0x02, BRIQ_PANEL_VFD_IOPORT);
++ for (i=0; i<20; i++)
++ outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
++
++ /* cursor to next line */
++ outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
++ for (i=20; i<40; i++)
++ outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
++
++}
++
++static void set_led(char state)
++{
++ if (state == 'R')
++ led = 0x01;
++ else if (state == 'G')
++ led = 0x02;
++ else if (state == 'Y')
++ led = 0x03;
++ else if (state == 'X')
++ led = 0x00;
++ outb(led, BRIQ_PANEL_LED_IOPORT);
++}
++
++static int briq_panel_open(struct inode *ino, struct file *filep)
++{
++ /* enforce single access */
++ if (vfd_is_open)
++ return -EBUSY;
++ vfd_is_open = 1;
++
++ return 0;
++}
++
++static int briq_panel_release(struct inode *ino, struct file *filep)
++{
++ if (!vfd_is_open)
++ return -ENODEV;
++
++ vfd_is_open = 0;
++
++ return 0;
++}
++
++static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ unsigned short c;
++ unsigned char cp;
++
++#if 0 /* Can't seek (pread) on this device */
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++#endif
++
++ if (!vfd_is_open)
++ return -ENODEV;
++
++ c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
++ set_led(' ');
++ /* upper button released */
++ if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
++ cp = ' ';
++ ledpb = c;
++ if (copy_to_user(buf, &cp, 1))
++ return -EFAULT;
++ return 1;
++ }
++ /* lower button released */
++ else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
++ cp = '\r';
++ ledpb = c;
++ if (copy_to_user(buf, &cp, 1))
++ return -EFAULT;
++ return 1;
++ } else {
++ ledpb = c;
++ return 0;
++ }
++}
++
++static void scroll_vfd( void )
++{
++ int i;
++
++ for (i=0; i<20; i++) {
++ vfd[i] = vfd[i+20];
++ vfd[i+20] = ' ';
++ }
++ vfd_cursor = 20;
++}
++
++static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
++ loff_t *ppos)
++{
++ size_t indx = len;
++ int i, esc = 0;
++
++#if 0 /* Can't seek (pwrite) on this device */
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++#endif
++
++ if (!vfd_is_open)
++ return -EBUSY;
++
++ for (;;) {
++ char c;
++ if (!indx)
++ break;
++ if (get_user(c, buf))
++ return -EFAULT;
++ if (esc) {
++ set_led(c);
++ esc = 0;
++ } else if (c == 27) {
++ esc = 1;
++ } else if (c == 12) {
++ /* do a form feed */
++ for (i=0; i<40; i++)
++ vfd[i] = ' ';
++ vfd_cursor = 0;
++ } else if (c == 10) {
++ if (vfd_cursor < 20)
++ vfd_cursor = 20;
++ else if (vfd_cursor < 40)
++ vfd_cursor = 40;
++ else if (vfd_cursor < 60)
++ vfd_cursor = 60;
++ if (vfd_cursor > 59)
++ scroll_vfd();
++ } else {
++ /* just a character */
++ if (vfd_cursor > 39)
++ scroll_vfd();
++ vfd[vfd_cursor++] = c;
++ }
++ indx--;
++ buf++;
++ }
++ update_vfd();
++
++ return len;
++}
++
++static struct file_operations briq_panel_fops = {
++ .owner = THIS_MODULE,
++ .read = briq_panel_read,
++ .write = briq_panel_write,
++ .open = briq_panel_open,
++ .release = briq_panel_release,
++};
++
++static struct miscdevice briq_panel_miscdev = {
++ BRIQ_PANEL_MINOR,
++ "briq_panel",
++ &briq_panel_fops
++};
++
++static int __init briq_panel_init(void)
++{
++ struct device_node *root = find_path_device("/");
++ const char *machine;
++ int i;
++
++ machine = get_property(root, "model", NULL);
++ if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
++ return -ENODEV;
++
++ printk(KERN_INFO
++ "briq_panel: v%s Dr. Karsten Jeppesen (kj at totalimpact.com)\n",
++ BRIQ_PANEL_VER);
++
++ if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
++ return -EBUSY;
++
++ if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
++ release_region(BRIQ_PANEL_VFD_IOPORT, 4);
++ return -EBUSY;
++ }
++ ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
++
++ if (misc_register(&briq_panel_miscdev) < 0) {
++ release_region(BRIQ_PANEL_VFD_IOPORT, 4);
++ release_region(BRIQ_PANEL_LED_IOPORT, 2);
++ return -EBUSY;
++ }
++
++ outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */
++ outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */
++ outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */
++ outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */
++ for (i=0; i<40; i++)
++ vfd[i]=' ';
++#ifndef MODULE
++ vfd[0] = 'L';
++ vfd[1] = 'o';
++ vfd[2] = 'a';
++ vfd[3] = 'd';
++ vfd[4] = 'i';
++ vfd[5] = 'n';
++ vfd[6] = 'g';
++ vfd[7] = ' ';
++ vfd[8] = '.';
++ vfd[9] = '.';
++ vfd[10] = '.';
++#endif /* !MODULE */
++
++ update_vfd();
++
++ return 0;
++}
++
++static void __exit briq_panel_exit(void)
++{
++ misc_deregister(&briq_panel_miscdev);
++ release_region(BRIQ_PANEL_VFD_IOPORT, 4);
++ release_region(BRIQ_PANEL_LED_IOPORT, 2);
++}
++
++module_init(briq_panel_init);
++module_exit(briq_panel_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Karsten Jeppesen <karsten at jeppesens.com>");
++MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");
+diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
+index c1c6728..e608dad 100644
+--- a/drivers/char/cyclades.c
++++ b/drivers/char/cyclades.c
+@@ -748,18 +748,6 @@ static struct cyclades_port cy_port[NR_P
+ static int cy_next_channel; /* next minor available */
+
+ /*
+- * 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. This buffer is
+- * allocated when the first cy_open occurs.
+- */
+-static unsigned char *tmp_buf;
+-
+-/*
+ * This is used to look up the divisor speeds and the timeouts
+ * We're normally limited to 15 distinct baud rates. The extra
+ * are accessed via settings in info->flags.
+@@ -1069,7 +1057,7 @@ detect_isa_irq(void __iomem *address)
+ received, out buffer empty, modem change, etc.
+ */
+ static irqreturn_t
+-cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++cyy_interrupt(int irq, void *dev_id)
+ {
+ struct tty_struct *tty;
+ int status;
+@@ -1814,7 +1802,7 @@ cyz_handle_cmd(struct cyclades_card *cin
+
+ #ifdef CONFIG_CYZ_INTR
+ static irqreturn_t
+-cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++cyz_interrupt(int irq, void *dev_id)
+ {
+ struct cyclades_card *cinfo;
+
+@@ -2466,7 +2454,6 @@ cy_open(struct tty_struct *tty, struct f
+ {
+ struct cyclades_port *info;
+ int retval, line;
+- unsigned long page;
+
+ line = tty->index;
+ if ((line < 0) || (NR_PORTS <= line)){
+@@ -2545,15 +2532,6 @@ cy_open(struct tty_struct *tty, struct f
+ printk("cyc:cy_open (%d): incrementing count to %d\n",
+ current->pid, info->count);
+ #endif
+- 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
+@@ -2832,7 +2810,7 @@ cy_write(struct tty_struct * tty, const
+ return 0;
+ }
+
+- if (!info->xmit_buf || !tmp_buf)
++ if (!info->xmit_buf)
+ return 0;
+
+ CY_LOCK(info, flags);
+@@ -5205,7 +5183,7 @@ done:
+ extra ports are ignored.
+ */
+
+-static struct tty_operations cy_ops = {
++static const struct tty_operations cy_ops = {
+ .open = cy_open,
+ .close = cy_close,
+ .write = cy_write,
+@@ -5490,10 +5468,6 @@ cy_cleanup_module(void)
+ #endif
+ }
+ }
+- if (tmp_buf) {
+- free_page((unsigned long) tmp_buf);
+- tmp_buf = NULL;
+- }
+ } /* cy_cleanup_module */
+
+ module_init(cy_init);
+diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
+index 5278c38..ef833a1 100644
+--- a/drivers/char/drm/Kconfig
++++ b/drivers/char/drm/Kconfig
+@@ -60,7 +60,9 @@ config DRM_I830
+ Choose this option if you have a system that has Intel 830M, 845G,
+ 852GM, 855GM or 865G integrated graphics. If M is selected, the
+ module will be called i830. AGP support is required for this driver
+- to work. This driver will eventually be replaced by the i915 one.
++ to work. This driver is used by the older X releases X.org 6.7 and
++ XFree86 4.3. If unsure, build this and i915 as modules and the X server
++ will load the correct one.
+
+ config DRM_I915
+ tristate "i915 driver"
+@@ -68,8 +70,9 @@ config DRM_I915
+ Choose this option if you have a system that has Intel 830M, 845G,
+ 852GM, 855GM 865G or 915G integrated graphics. If M is selected, the
+ module will be called i915. AGP support is required for this driver
+- to work. This driver will eventually replace the I830 driver, when
+- later release of X start to use the new DDX and DRI.
++ to work. This driver is used by the Intel driver in X.org 6.8 and
++ XFree86 4.4 and above. If unsure, build this and i830 as modules and
++ the X server will load the correct one.
+
+ endchoice
+
+diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
+index 9d180c4..3ad0f64 100644
+--- a/drivers/char/drm/Makefile
++++ b/drivers/char/drm/Makefile
+@@ -6,7 +6,7 @@ drm-objs := drm_auth.o drm_bufs.o drm
+ drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
+ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
+ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
+- drm_sysfs.o
++ drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
+
+ tdfx-objs := tdfx_drv.o
+ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
+@@ -16,9 +16,9 @@ i830-objs := i830_drv.o i830_dma.o i83
+ 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 r300_cmdbuf.o
+ ffb-objs := ffb_drv.o ffb_context.o
+-sis-objs := sis_drv.o sis_ds.o sis_mm.o
++sis-objs := sis_drv.o sis_mm.o
+ savage-objs := savage_drv.o savage_bci.o savage_state.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 via_dmablit.o
++via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
+
+ ifeq ($(CONFIG_COMPAT),y)
+ drm-objs += drm_ioc32.o
+diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
+index d2a5618..7690a59 100644
+--- a/drivers/char/drm/drmP.h
++++ b/drivers/char/drm/drmP.h
+@@ -79,6 +79,7 @@
+ #define __OS_HAS_MTRR (defined(CONFIG_MTRR))
+
+ #include "drm_os_linux.h"
++#include "drm_hashtab.h"
+
+ /***********************************************************************/
+ /** \name DRM template customization defaults */
+@@ -104,7 +105,7 @@
+ #define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then
+ also include looping detection. */
+
+-#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */
++#define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */
+ #define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */
+ #define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */
+ #define DRM_LOOPING_LIMIT 5000000
+@@ -134,19 +135,12 @@
+ #define DRM_MEM_CTXBITMAP 18
+ #define DRM_MEM_STUB 19
+ #define DRM_MEM_SGLISTS 20
+-#define DRM_MEM_CTXLIST 21
++#define DRM_MEM_CTXLIST 21
++#define DRM_MEM_MM 22
++#define DRM_MEM_HASHTAB 23
+
+ #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+-
+-/*@}*/
+-
+-/***********************************************************************/
+-/** \name Backward compatibility section */
+-/*@{*/
+-
+-#define DRM_RPR_ARG(vma) vma,
+-
+-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
++#define DRM_MAP_HASH_OFFSET 0x10000000
+
+ /*@}*/
+
+@@ -211,8 +205,6 @@
+ /*@{*/
+
+ #define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x)
+-#define DRM_MIN(a,b) min(a,b)
+-#define DRM_MAX(a,b) max(a,b)
+
+ #define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
+ #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
+@@ -286,7 +278,8 @@ typedef struct drm_devstate {
+ } drm_devstate_t;
+
+ typedef struct drm_magic_entry {
+- drm_magic_t magic;
++ drm_hash_item_t hash_item;
++ struct list_head head;
+ struct drm_file *priv;
+ struct drm_magic_entry *next;
+ } drm_magic_entry_t;
+@@ -493,6 +486,7 @@ typedef struct drm_sigdata {
+ */
+ typedef struct drm_map_list {
+ struct list_head head; /**< list head */
++ drm_hash_item_t hash;
+ drm_map_t *map; /**< mapping */
+ unsigned int user_token;
+ } drm_map_list_t;
+@@ -527,6 +521,22 @@ typedef struct ati_pcigart_info {
+ drm_local_map_t mapping;
+ } drm_ati_pcigart_info;
+
++/*
++ * Generic memory manager structs
++ */
++typedef struct drm_mm_node {
++ struct list_head fl_entry;
++ struct list_head ml_entry;
++ int free;
++ unsigned long start;
++ unsigned long size;
++ void *private;
++} drm_mm_node_t;
++
++typedef struct drm_mm {
++ drm_mm_node_t root_node;
++} drm_mm_t;
++
+ /**
+ * DRM driver structure. This structure represent the common code for
+ * a family of cards. There will one drm_device for each card present
+@@ -646,13 +656,15 @@ typedef struct drm_device {
+ /*@{ */
+ drm_file_t *file_first; /**< file list head */
+ drm_file_t *file_last; /**< file list tail */
+- drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */
++ drm_open_hash_t magiclist; /**< magic hash table */
++ struct list_head magicfree;
+ /*@} */
+
+ /** \name Memory management */
+ /*@{ */
+ drm_map_list_t *maplist; /**< Linked list of regions */
+ int map_count; /**< Number of mappable regions */
++ drm_open_hash_t map_hash; /**< User token hash table for maps */
+
+ /** \name Context handle management */
+ /*@{ */
+@@ -711,10 +723,8 @@ typedef struct drm_device {
+ drm_agp_head_t *agp; /**< AGP data */
+
+ struct pci_dev *pdev; /**< PCI device structure */
+- int pci_domain; /**< PCI bus domain number */
+- int pci_bus; /**< PCI bus number */
+- int pci_slot; /**< PCI slot number */
+- int pci_func; /**< PCI function number */
++ int pci_vendor; /**< PCI vendor id */
++ int pci_device; /**< PCI device id */
+ #ifdef __alpha__
+ struct pci_controller *hose;
+ #endif
+@@ -736,6 +746,12 @@ static __inline__ int drm_core_check_fea
+ return ((dev->driver->driver_features & feature) ? 1 : 0);
+ }
+
++#ifdef __alpha__
++#define drm_get_pci_domain(dev) dev->hose->bus->number
++#else
++#define drm_get_pci_domain(dev) 0
++#endif
++
+ #if __OS_HAS_AGP
+ static inline int drm_core_has_AGP(struct drm_device *dev)
+ {
+@@ -1011,6 +1027,18 @@ extern struct class_device *drm_sysfs_de
+ drm_head_t *head);
+ extern void drm_sysfs_device_remove(struct class_device *class_dev);
+
++/*
++ * Basic memory manager support (drm_mm.c)
++ */
++extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
++ unsigned long size,
++ unsigned alignment);
++extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
++extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
++ unsigned alignment, int best_match);
++extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
++extern void drm_mm_takedown(drm_mm_t *mm);
++
+ /* Inline replacements for DRM_IOREMAP macros */
+ static __inline__ void drm_core_ioremap(struct drm_map *map,
+ struct drm_device *dev)
+diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
+index 2a37586..c7b19d3 100644
+--- a/drivers/char/drm/drm_auth.c
++++ b/drivers/char/drm/drm_auth.c
+@@ -36,20 +36,6 @@
+ #include "drmP.h"
+
+ /**
+- * Generate a hash key from a magic.
+- *
+- * \param magic magic.
+- * \return hash key.
+- *
+- * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be
+- * a power of 2.
+- */
+-static int drm_hash_magic(drm_magic_t magic)
+-{
+- return magic & (DRM_HASH_SIZE - 1);
+-}
+-
+-/**
+ * Find the file with the given magic number.
+ *
+ * \param dev DRM device.
+@@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_dev
+ {
+ drm_file_t *retval = NULL;
+ drm_magic_entry_t *pt;
+- int hash = drm_hash_magic(magic);
++ drm_hash_item_t *hash;
+
+ mutex_lock(&dev->struct_mutex);
+- for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+- if (pt->magic == magic) {
+- retval = pt->priv;
+- break;
+- }
++ if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
++ pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
++ retval = pt->priv;
+ }
+ mutex_unlock(&dev->struct_mutex);
+ return retval;
+@@ -90,28 +74,20 @@ static drm_file_t *drm_find_file(drm_dev
+ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
+ drm_magic_t magic)
+ {
+- int hash;
+ drm_magic_entry_t *entry;
+
+ DRM_DEBUG("%d\n", magic);
+
+- hash = drm_hash_magic(magic);
+ entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
+ if (!entry)
+ return -ENOMEM;
+ memset(entry, 0, sizeof(*entry));
+- entry->magic = magic;
+ entry->priv = priv;
+- entry->next = NULL;
+
++ entry->hash_item.key = (unsigned long)magic;
+ mutex_lock(&dev->struct_mutex);
+- if (dev->magiclist[hash].tail) {
+- dev->magiclist[hash].tail->next = entry;
+- dev->magiclist[hash].tail = entry;
+- } else {
+- dev->magiclist[hash].head = entry;
+- dev->magiclist[hash].tail = entry;
+- }
++ drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
++ list_add_tail(&entry->head, &dev->magicfree);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+@@ -128,34 +104,24 @@ static int drm_add_magic(drm_device_t *
+ */
+ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
+ {
+- drm_magic_entry_t *prev = NULL;
+ drm_magic_entry_t *pt;
+- int hash;
++ drm_hash_item_t *hash;
+
+ DRM_DEBUG("%d\n", magic);
+- hash = drm_hash_magic(magic);
+
+ mutex_lock(&dev->struct_mutex);
+- for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+- if (pt->magic == magic) {
+- if (dev->magiclist[hash].head == pt) {
+- dev->magiclist[hash].head = pt->next;
+- }
+- if (dev->magiclist[hash].tail == pt) {
+- dev->magiclist[hash].tail = prev;
+- }
+- if (prev) {
+- prev->next = pt->next;
+- }
+- mutex_unlock(&dev->struct_mutex);
+- return 0;
+- }
++ if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
++ mutex_unlock(&dev->struct_mutex);
++ return -EINVAL;
+ }
++ pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
++ drm_ht_remove_item(&dev->magiclist, hash);
++ list_del(&pt->head);
+ mutex_unlock(&dev->struct_mutex);
+
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+
+- return -EINVAL;
++ return 0;
+ }
+
+ /**
+diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
+index 006b06d..6eafff1 100644
+--- a/drivers/char/drm/drm_bufs.c
++++ b/drivers/char/drm/drm_bufs.c
+@@ -65,43 +65,29 @@ static drm_map_list_t *drm_find_matching
+ return NULL;
+ }
+
+-/*
+- * Used to allocate 32-bit handles for mappings.
+- */
+-#define START_RANGE 0x10000000
+-#define END_RANGE 0x40000000
+-
+-#ifdef _LP64
+-static __inline__ unsigned int HandleID(unsigned long lhandle,
+- drm_device_t *dev)
++static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
++ unsigned long user_token, int hashed_handle)
+ {
+- static unsigned int map32_handle = START_RANGE;
+- unsigned int hash;
+-
+- if (lhandle & 0xffffffff00000000) {
+- hash = map32_handle;
+- map32_handle += PAGE_SIZE;
+- if (map32_handle > END_RANGE)
+- map32_handle = START_RANGE;
+- } else
+- hash = lhandle;
+-
+- while (1) {
+- drm_map_list_t *_entry;
+- list_for_each_entry(_entry, &dev->maplist->head, head) {
+- if (_entry->user_token == hash)
+- break;
+- }
+- if (&_entry->head == &dev->maplist->head)
+- return hash;
++ int use_hashed_handle;
++#if (BITS_PER_LONG == 64)
++ use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
++#elif (BITS_PER_LONG == 32)
++ use_hashed_handle = hashed_handle;
++#else
++#error Unsupported long size. Neither 64 nor 32 bits.
++#endif
+
+- hash += PAGE_SIZE;
+- map32_handle += PAGE_SIZE;
++ if (!use_hashed_handle) {
++ int ret;
++ hash->key = user_token;
++ ret = drm_ht_insert_item(&dev->map_hash, hash);
++ if (ret != -EINVAL)
++ return ret;
+ }
++ return drm_ht_just_insert_please(&dev->map_hash, hash,
++ user_token, 32 - PAGE_SHIFT - 3,
++ PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+ }
+-#else
+-# define HandleID(x,dev) (unsigned int)(x)
+-#endif
+
+ /**
+ * Ioctl to specify a range of memory that is available for mapping by a non-root process.
+@@ -123,6 +109,8 @@ static int drm_addmap_core(drm_device_t
+ drm_map_t *map;
+ drm_map_list_t *list;
+ drm_dma_handle_t *dmah;
++ unsigned long user_token;
++ int ret;
+
+ map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+ if (!map)
+@@ -249,6 +237,8 @@ static int drm_addmap_core(drm_device_t
+
+ list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
+ if (!list) {
++ if (map->type == _DRM_REGISTERS)
++ drm_ioremapfree(map->handle, map->size, dev);
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
+@@ -257,11 +247,22 @@ static int drm_addmap_core(drm_device_t
+
+ mutex_lock(&dev->struct_mutex);
+ list_add(&list->head, &dev->maplist->head);
++
+ /* Assign a 32-bit handle */
+ /* We do it here so that dev->struct_mutex protects the increment */
+- list->user_token = HandleID(map->type == _DRM_SHM
+- ? (unsigned long)map->handle
+- : map->offset, dev);
++ user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
++ map->offset;
++ ret = drm_map_handle(dev, &list->hash, user_token, 0);
++ if (ret) {
++ if (map->type == _DRM_REGISTERS)
++ drm_ioremapfree(map->handle, map->size, dev);
++ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
++ drm_free(list, sizeof(*list), DRM_MEM_MAPS);
++ mutex_unlock(&dev->struct_mutex);
++ return ret;
++ }
++
++ list->user_token = list->hash.key;
+ mutex_unlock(&dev->struct_mutex);
+
+ *maplist = list;
+@@ -346,6 +347,7 @@ int drm_rmmap_locked(drm_device_t *dev,
+
+ if (r_list->map == map) {
+ list_del(list);
++ drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+ drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+ break;
+ }
+@@ -441,8 +443,10 @@ int drm_rmmap_ioctl(struct inode *inode,
+ return -EINVAL;
+ }
+
+- if (!map)
++ if (!map) {
++ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
++ }
+
+ /* Register and framebuffer maps are permanent */
+ if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
+diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
+index 3c0b882..b366c5b 100644
+--- a/drivers/char/drm/drm_drv.c
++++ b/drivers/char/drm/drm_drv.c
+@@ -118,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+ };
+
+-#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls )
++#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
+
+ /**
+ * Take down the DRM device.
+@@ -155,12 +155,13 @@ int drm_lastclose(drm_device_t * dev)
+ del_timer(&dev->timer);
+
+ /* Clear pid list */
+- for (i = 0; i < DRM_HASH_SIZE; i++) {
+- for (pt = dev->magiclist[i].head; pt; pt = next) {
+- next = pt->next;
++ if (dev->magicfree.next) {
++ list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
++ list_del(&pt->head);
++ drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+ }
+- dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
++ drm_ht_remove(&dev->magiclist);
+ }
+
+ /* Clear AGP information */
+@@ -299,6 +300,7 @@ static void drm_cleanup(drm_device_t * d
+ if (dev->maplist) {
+ drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+ dev->maplist = NULL;
++ drm_ht_remove(&dev->map_hash);
+ }
+
+ drm_ctxbitmap_cleanup(dev);
+diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
+index b7f7951..898f47d 100644
+--- a/drivers/char/drm/drm_fops.c
++++ b/drivers/char/drm/drm_fops.c
+@@ -53,6 +53,8 @@ static int drm_setup(drm_device_t * dev)
+ return ret;
+ }
+
++ dev->magicfree.next = NULL;
++
+ /* prebuild the SAREA */
+ i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
+ if (i != 0)
+@@ -69,13 +71,11 @@ static int drm_setup(drm_device_t * dev)
+ return i;
+ }
+
+- for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
++ for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
+ atomic_set(&dev->counts[i], 0);
+
+- for (i = 0; i < DRM_HASH_SIZE; i++) {
+- dev->magiclist[i].head = NULL;
+- dev->magiclist[i].tail = NULL;
+- }
++ drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
++ INIT_LIST_HEAD(&dev->magicfree);
+
+ dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
+ if (dev->ctxlist == NULL)
+diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
+new file mode 100644
+index 0000000..a0b2d68
+--- /dev/null
++++ b/drivers/char/drm/drm_hashtab.c
+@@ -0,0 +1,190 @@
++/**************************************************************************
++ *
++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
++ * 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.
++ *
++ *
++ **************************************************************************/
++/*
++ * Simple open hash tab implementation.
++ *
++ * Authors:
++ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
++ */
++
++#include "drmP.h"
++#include "drm_hashtab.h"
++#include <linux/hash.h>
++
++int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
++{
++ unsigned int i;
++
++ ht->size = 1 << order;
++ ht->order = order;
++ ht->fill = 0;
++ ht->table = vmalloc(ht->size*sizeof(*ht->table));
++ if (!ht->table) {
++ DRM_ERROR("Out of memory for hash table\n");
++ return -ENOMEM;
++ }
++ for (i=0; i< ht->size; ++i) {
++ INIT_HLIST_HEAD(&ht->table[i]);
++ }
++ return 0;
++}
++
++void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
++{
++ drm_hash_item_t *entry;
++ struct hlist_head *h_list;
++ struct hlist_node *list;
++ unsigned int hashed_key;
++ int count = 0;
++
++ hashed_key = hash_long(key, ht->order);
++ DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
++ h_list = &ht->table[hashed_key];
++ hlist_for_each(list, h_list) {
++ entry = hlist_entry(list, drm_hash_item_t, head);
++ DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
++ }
++}
++
++static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht,
++ unsigned long key)
++{
++ drm_hash_item_t *entry;
++ struct hlist_head *h_list;
++ struct hlist_node *list;
++ unsigned int hashed_key;
++
++ hashed_key = hash_long(key, ht->order);
++ h_list = &ht->table[hashed_key];
++ hlist_for_each(list, h_list) {
++ entry = hlist_entry(list, drm_hash_item_t, head);
++ if (entry->key == key)
++ return list;
++ if (entry->key > key)
++ break;
++ }
++ return NULL;
++}
++
++
++int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
++{
++ drm_hash_item_t *entry;
++ struct hlist_head *h_list;
++ struct hlist_node *list, *parent;
++ unsigned int hashed_key;
++ unsigned long key = item->key;
++
++ hashed_key = hash_long(key, ht->order);
++ h_list = &ht->table[hashed_key];
++ parent = NULL;
++ hlist_for_each(list, h_list) {
++ entry = hlist_entry(list, drm_hash_item_t, head);
++ if (entry->key == key)
++ return -EINVAL;
++ if (entry->key > key)
++ break;
++ parent = list;
++ }
++ if (parent) {
++ hlist_add_after(parent, &item->head);
++ } else {
++ hlist_add_head(&item->head, h_list);
++ }
++ return 0;
++}
++
++/*
++ * Just insert an item and return any "bits" bit key that hasn't been
++ * used before.
++ */
++int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
++ unsigned long seed, int bits, int shift,
++ unsigned long add)
++{
++ int ret;
++ unsigned long mask = (1 << bits) - 1;
++ unsigned long first, unshifted_key;
++
++ unshifted_key = hash_long(seed, bits);
++ first = unshifted_key;
++ do {
++ item->key = (unshifted_key << shift) + add;
++ ret = drm_ht_insert_item(ht, item);
++ if (ret)
++ unshifted_key = (unshifted_key + 1) & mask;
++ } while(ret && (unshifted_key != first));
++
++ if (ret) {
++ DRM_ERROR("Available key bit space exhausted\n");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key,
++ drm_hash_item_t **item)
++{
++ struct hlist_node *list;
++
++ list = drm_ht_find_key(ht, key);
++ if (!list)
++ return -EINVAL;
++
++ *item = hlist_entry(list, drm_hash_item_t, head);
++ return 0;
++}
++
++int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
++{
++ struct hlist_node *list;
++
++ list = drm_ht_find_key(ht, key);
++ if (list) {
++ hlist_del_init(list);
++ ht->fill--;
++ return 0;
++ }
++ return -EINVAL;
++}
++
++int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
++{
++ hlist_del_init(&item->head);
++ ht->fill--;
++ return 0;
++}
++
++void drm_ht_remove(drm_open_hash_t *ht)
++{
++ if (ht->table) {
++ vfree(ht->table);
++ ht->table = NULL;
++ }
++}
++
+diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
+new file mode 100644
+index 0000000..40afec0
+--- /dev/null
++++ b/drivers/char/drm/drm_hashtab.h
+@@ -0,0 +1,67 @@
++/**************************************************************************
++ *
++ * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
++ * 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.
++ *
++ *
++ **************************************************************************/
++/*
++ * Simple open hash tab implementation.
++ *
++ * Authors:
++ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
++ */
++
++#ifndef DRM_HASHTAB_H
++#define DRM_HASHTAB_H
++
++#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
++
++typedef struct drm_hash_item{
++ struct hlist_node head;
++ unsigned long key;
++} drm_hash_item_t;
++
++typedef struct drm_open_hash{
++ unsigned int size;
++ unsigned int order;
++ unsigned int fill;
++ struct hlist_head *table;
++} drm_open_hash_t;
++
++
++extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order);
++extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item);
++extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
++ unsigned long seed, int bits, int shift,
++ unsigned long add);
++extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item);
++
++extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key);
++extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key);
++extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item);
++extern void drm_ht_remove(drm_open_hash_t *ht);
++
++
++#endif
++
+diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
+index e9e2db1..d4f8745 100644
+--- a/drivers/char/drm/drm_ioc32.c
++++ b/drivers/char/drm/drm_ioc32.c
+@@ -1051,7 +1051,7 @@ long drm_compat_ioctl(struct file *filp,
+ drm_ioctl_compat_t *fn;
+ int ret;
+
+- if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
++ if (nr >= ARRAY_SIZE(drm_compat_ioctls))
+ return -ENOTTY;
+
+ fn = drm_compat_ioctls[nr];
+diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
+index 555f323..5658955 100644
+--- a/drivers/char/drm/drm_ioctl.c
++++ b/drivers/char/drm/drm_ioctl.c
+@@ -127,9 +127,10 @@ int drm_setunique(struct inode *inode, s
+ domain = bus >> 8;
+ bus &= 0xff;
+
+- if ((domain != dev->pci_domain) ||
+- (bus != dev->pci_bus) ||
+- (slot != dev->pci_slot) || (func != dev->pci_func))
++ if ((domain != drm_get_pci_domain(dev)) ||
++ (bus != dev->pdev->bus->number) ||
++ (slot != PCI_SLOT(dev->pdev->devfn)) ||
++ (func != PCI_FUNC(dev->pdev->devfn)))
+ return -EINVAL;
+
+ return 0;
+@@ -140,15 +141,17 @@ static int drm_set_busid(drm_device_t *
+ int len;
+
+ if (dev->unique != NULL)
+- return EBUSY;
++ return 0;
+
+ dev->unique_len = 40;
+ dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
+ if (dev->unique == NULL)
+- return ENOMEM;
++ return -ENOMEM;
+
+ len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
+- dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
++ drm_get_pci_domain(dev), dev->pdev->bus->number,
++ PCI_SLOT(dev->pdev->devfn),
++ PCI_FUNC(dev->pdev->devfn));
+
+ if (len > dev->unique_len)
+ DRM_ERROR("Unique buffer overflowed\n");
+@@ -157,7 +160,7 @@ static int drm_set_busid(drm_device_t *
+ drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
+ 2, DRM_MEM_DRIVER);
+ if (dev->devname == NULL)
+- return ENOMEM;
++ return -ENOMEM;
+
+ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+ dev->unique);
+@@ -330,27 +333,32 @@ int drm_setversion(DRM_IOCTL_ARGS)
+ drm_set_version_t retv;
+ int if_version;
+ drm_set_version_t __user *argp = (void __user *)data;
++ int ret;
+
+- DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv));
++ if (copy_from_user(&sv, argp, sizeof(sv)))
++ return -EFAULT;
+
+ retv.drm_di_major = DRM_IF_MAJOR;
+ retv.drm_di_minor = DRM_IF_MINOR;
+ retv.drm_dd_major = dev->driver->major;
+ retv.drm_dd_minor = dev->driver->minor;
+
+- DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv));
++ if (copy_to_user(argp, &retv, sizeof(retv)))
++ return -EFAULT;
+
+ if (sv.drm_di_major != -1) {
+ if (sv.drm_di_major != DRM_IF_MAJOR ||
+ sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
+- return EINVAL;
++ return -EINVAL;
+ if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
+- dev->if_version = DRM_MAX(if_version, dev->if_version);
++ dev->if_version = max(if_version, dev->if_version);
+ if (sv.drm_di_minor >= 1) {
+ /*
+ * Version 1.1 includes tying of DRM to specific device
+ */
+- drm_set_busid(dev);
++ ret = drm_set_busid(dev);
++ if (ret)
++ return ret;
+ }
+ }
+
+@@ -358,7 +366,7 @@ int drm_setversion(DRM_IOCTL_ARGS)
+ if (sv.drm_dd_major != dev->driver->major ||
+ sv.drm_dd_minor < 0
+ || sv.drm_dd_minor > dev->driver->minor)
+- return EINVAL;
++ return -EINVAL;
+
+ if (dev->driver->set_version)
+ dev->driver->set_version(dev, &sv);
+diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
+index ebdb718..4553a3a 100644
+--- a/drivers/char/drm/drm_irq.c
++++ b/drivers/char/drm/drm_irq.c
+@@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode
+ if (copy_from_user(&p, argp, sizeof(p)))
+ return -EFAULT;
+
+- if ((p.busnum >> 8) != dev->pci_domain ||
+- (p.busnum & 0xff) != dev->pci_bus ||
+- p.devnum != dev->pci_slot || p.funcnum != dev->pci_func)
++ if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
++ (p.busnum & 0xff) != dev->pdev->bus->number ||
++ p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
+ return -EINVAL;
+
+ p.irq = dev->irq;
+@@ -255,7 +255,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
+ if (!dev->irq)
+ return -EINVAL;
+
+- DRM_COPY_FROM_USER_IOCTL(vblwait, argp, sizeof(vblwait));
++ if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
++ return -EFAULT;
+
+ switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
+ case _DRM_VBLANK_RELATIVE:
+@@ -329,7 +330,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
+ }
+
+ done:
+- DRM_COPY_TO_USER_IOCTL(argp, vblwait, sizeof(vblwait));
++ if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
++ return -EFAULT;
+
+ return ret;
+ }
+diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
+new file mode 100644
+index 0000000..617526b
+--- /dev/null
++++ b/drivers/char/drm/drm_mm.c
+@@ -0,0 +1,201 @@
++/**************************************************************************
++ *
++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
++ * 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.
++ *
++ *
++ **************************************************************************/
++
++/*
++ * Generic simple memory manager implementation. Intended to be used as a base
++ * class implementation for more advanced memory managers.
++ *
++ * Note that the algorithm used is quite simple and there might be substantial
++ * performance gains if a smarter free list is implemented. Currently it is just an
++ * unordered stack of free regions. This could easily be improved if an RB-tree
++ * is used instead. At least if we expect heavy fragmentation.
++ *
++ * Aligned allocations can also see improvement.
++ *
++ * Authors:
++ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
++ */
++
++#include "drmP.h"
++
++drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
++ unsigned long size, unsigned alignment)
++{
++
++ drm_mm_node_t *child;
++
++ if (alignment)
++ size += alignment - 1;
++
++ if (parent->size == size) {
++ list_del_init(&parent->fl_entry);
++ parent->free = 0;
++ return parent;
++ } else {
++ child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
++ if (!child)
++ return NULL;
++
++ INIT_LIST_HEAD(&child->ml_entry);
++ INIT_LIST_HEAD(&child->fl_entry);
++
++ child->free = 0;
++ child->size = size;
++ child->start = parent->start;
++
++ list_add_tail(&child->ml_entry, &parent->ml_entry);
++ parent->size -= size;
++ parent->start += size;
++ }
++ return child;
++}
++
++/*
++ * Put a block. Merge with the previous and / or next block if they are free.
++ * Otherwise add to the free stack.
++ */
++
++void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
++{
++
++ drm_mm_node_t *list_root = &mm->root_node;
++ struct list_head *cur_head = &cur->ml_entry;
++ struct list_head *root_head = &list_root->ml_entry;
++ drm_mm_node_t *prev_node = NULL;
++ drm_mm_node_t *next_node;
++
++ int merged = 0;
++
++ if (cur_head->prev != root_head) {
++ prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
++ if (prev_node->free) {
++ prev_node->size += cur->size;
++ merged = 1;
++ }
++ }
++ if (cur_head->next != root_head) {
++ next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry);
++ if (next_node->free) {
++ if (merged) {
++ prev_node->size += next_node->size;
++ list_del(&next_node->ml_entry);
++ list_del(&next_node->fl_entry);
++ drm_free(next_node, sizeof(*next_node),
++ DRM_MEM_MM);
++ } else {
++ next_node->size += cur->size;
++ next_node->start = cur->start;
++ merged = 1;
++ }
++ }
++ }
++ if (!merged) {
++ cur->free = 1;
++ list_add(&cur->fl_entry, &list_root->fl_entry);
++ } else {
++ list_del(&cur->ml_entry);
++ drm_free(cur, sizeof(*cur), DRM_MEM_MM);
++ }
++}
++
++drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
++ unsigned long size,
++ unsigned alignment, int best_match)
++{
++ struct list_head *list;
++ const struct list_head *free_stack = &mm->root_node.fl_entry;
++ drm_mm_node_t *entry;
++ drm_mm_node_t *best;
++ unsigned long best_size;
++
++ best = NULL;
++ best_size = ~0UL;
++
++ if (alignment)
++ size += alignment - 1;
++
++ list_for_each(list, free_stack) {
++ entry = list_entry(list, drm_mm_node_t, fl_entry);
++ if (entry->size >= size) {
++ if (!best_match)
++ return entry;
++ if (size < best_size) {
++ best = entry;
++ best_size = entry->size;
++ }
++ }
++ }
++
++ return best;
++}
++
++int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
++{
++ drm_mm_node_t *child;
++
++ INIT_LIST_HEAD(&mm->root_node.ml_entry);
++ INIT_LIST_HEAD(&mm->root_node.fl_entry);
++ child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
++ if (!child)
++ return -ENOMEM;
++
++ INIT_LIST_HEAD(&child->ml_entry);
++ INIT_LIST_HEAD(&child->fl_entry);
++
++ child->start = start;
++ child->size = size;
++ child->free = 1;
++
++ list_add(&child->fl_entry, &mm->root_node.fl_entry);
++ list_add(&child->ml_entry, &mm->root_node.ml_entry);
++
++ return 0;
++}
++
++EXPORT_SYMBOL(drm_mm_init);
++
++void drm_mm_takedown(drm_mm_t * mm)
++{
++ struct list_head *bnode = mm->root_node.fl_entry.next;
++ drm_mm_node_t *entry;
++
++ entry = list_entry(bnode, drm_mm_node_t, fl_entry);
++
++ if (entry->ml_entry.next != &mm->root_node.ml_entry ||
++ entry->fl_entry.next != &mm->root_node.fl_entry) {
++ DRM_ERROR("Memory manager not clean. Delaying takedown\n");
++ return;
++ }
++
++ list_del(&entry->fl_entry);
++ list_del(&entry->ml_entry);
++
++ drm_free(entry, sizeof(*entry), DRM_MEM_MM);
++}
++
++EXPORT_SYMBOL(drm_mm_takedown);
+diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
+index 695115d..2908b72 100644
+--- a/drivers/char/drm/drm_os_linux.h
++++ b/drivers/char/drm/drm_os_linux.h
+@@ -38,7 +38,7 @@
+ drm_device_t *dev = priv->head->dev
+
+ /** IRQ handler arguments and return type and values */
+-#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs
++#define DRM_IRQ_ARGS int irq, void *arg
+
+ /** AGP types */
+ #if __OS_HAS_AGP
+diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
+index b1bb3c7..09398d5 100644
+--- a/drivers/char/drm/drm_pciids.h
++++ b/drivers/char/drm/drm_pciids.h
+@@ -3,13 +3,13 @@
+ Please contact dri-devel at lists.sf.net to add new cards to this list
+ */
+ #define radeon_PCI_IDS \
+- {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
+- {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
++ {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \
++ {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
+ {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+ {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+ {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+@@ -25,35 +25,35 @@
+ {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+ {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+ {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+- {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
++ {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
+ {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+ {0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+- {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
++ {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+ {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+- {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
++ {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+ {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+ {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+@@ -62,16 +62,16 @@
+ {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+ {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+ {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+- {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
+- {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
+- {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
+- {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
++ {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
++ {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
++ {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
++ {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+ {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+ {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+ {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+@@ -80,59 +80,59 @@
+ {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+ {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+ {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+- {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
+- {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
++ {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
++ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+ {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+ {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+- {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
+- {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
+- {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
++ {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
++ {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
++ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0, 0, 0}
+
+ #define r128_PCI_IDS \
+@@ -209,6 +209,7 @@
+ {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
+ {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0, 0, 0}
+
+@@ -227,6 +228,10 @@
+ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0, 0, 0}
+
+ #define i810_PCI_IDS \
+@@ -285,5 +290,9 @@
+ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
++ {0x8086, 0x29a2, 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 362a270..62d5fe1 100644
+--- a/drivers/char/drm/drm_proc.c
++++ b/drivers/char/drm/drm_proc.c
+@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char
+ vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+ vma->vm_flags & VM_LOCKED ? 'l' : '-',
+ vma->vm_flags & VM_IO ? 'i' : '-',
+- VM_OFFSET(vma));
++ vma->vm_pgoff << PAGE_SHIFT);
+
+ #if defined(__i386__)
+ pgprot = pgprot_val(vma->vm_page_prot);
+diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
+new file mode 100644
+index 0000000..425c823
+--- /dev/null
++++ b/drivers/char/drm/drm_sman.c
+@@ -0,0 +1,352 @@
++/**************************************************************************
++ *
++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
++ * 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 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.
++ *
++ * The above copyright notice and this permission notice (including the
++ * next paragraph) shall be included in all copies or substantial portions
++ * of the Software.
++ *
++ *
++ **************************************************************************/
++/*
++ * Simple memory manager interface that keeps track on allocate regions on a
++ * per "owner" basis. All regions associated with an "owner" can be released
++ * with a simple call. Typically if the "owner" exists. The owner is any
++ * "unsigned long" identifier. Can typically be a pointer to a file private
++ * struct or a context identifier.
++ *
++ * Authors:
++ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
++ */
++
++#include "drm_sman.h"
++
++typedef struct drm_owner_item {
++ drm_hash_item_t owner_hash;
++ struct list_head sman_list;
++ struct list_head mem_blocks;
++} drm_owner_item_t;
++
++void drm_sman_takedown(drm_sman_t * sman)
++{
++ drm_ht_remove(&sman->user_hash_tab);
++ drm_ht_remove(&sman->owner_hash_tab);
++ if (sman->mm)
++ drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
++ DRM_MEM_MM);
++}
++
++EXPORT_SYMBOL(drm_sman_takedown);
++
++int
++drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
++ unsigned int user_order, unsigned int owner_order)
++{
++ int ret = 0;
++
++ sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm),
++ DRM_MEM_MM);
++ if (!sman->mm) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ sman->num_managers = num_managers;
++ INIT_LIST_HEAD(&sman->owner_items);
++ ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
++ if (ret)
++ goto out1;
++ ret = drm_ht_create(&sman->user_hash_tab, user_order);
++ if (!ret)
++ goto out;
++
++ drm_ht_remove(&sman->owner_hash_tab);
++out1:
++ drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
++out:
++ return ret;
++}
++
++EXPORT_SYMBOL(drm_sman_init);
++
++static void *drm_sman_mm_allocate(void *private, unsigned long size,
++ unsigned alignment)
++{
++ drm_mm_t *mm = (drm_mm_t *) private;
++ drm_mm_node_t *tmp;
++
++ tmp = drm_mm_search_free(mm, size, alignment, 1);
++ if (!tmp) {
++ return NULL;
++ }
++ tmp = drm_mm_get_block(tmp, size, alignment);
++ return tmp;
++}
++
++static void drm_sman_mm_free(void *private, void *ref)
++{
++ drm_mm_t *mm = (drm_mm_t *) private;
++ drm_mm_node_t *node = (drm_mm_node_t *) ref;
++
++ drm_mm_put_block(mm, node);
++}
++
++static void drm_sman_mm_destroy(void *private)
++{
++ drm_mm_t *mm = (drm_mm_t *) private;
++ drm_mm_takedown(mm);
++ drm_free(mm, sizeof(*mm), DRM_MEM_MM);
++}
++
++static unsigned long drm_sman_mm_offset(void *private, void *ref)
++{
++ drm_mm_node_t *node = (drm_mm_node_t *) ref;
++ return node->start;
++}
++
++int
++drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
++ unsigned long start, unsigned long size)
++{
++ drm_sman_mm_t *sman_mm;
++ drm_mm_t *mm;
++ int ret;
++
++ BUG_ON(manager >= sman->num_managers);
++
++ sman_mm = &sman->mm[manager];
++ mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
++ if (!mm) {
++ return -ENOMEM;
++ }
++ sman_mm->private = mm;
++ ret = drm_mm_init(mm, start, size);
++
++ if (ret) {
++ drm_free(mm, sizeof(*mm), DRM_MEM_MM);
++ return ret;
++ }
++
++ sman_mm->allocate = drm_sman_mm_allocate;
++ sman_mm->free = drm_sman_mm_free;
++ sman_mm->destroy = drm_sman_mm_destroy;
++ sman_mm->offset = drm_sman_mm_offset;
++
++ return 0;
++}
++
++EXPORT_SYMBOL(drm_sman_set_range);
++
++int
++drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
++ drm_sman_mm_t * allocator)
++{
++ BUG_ON(manager >= sman->num_managers);
++ sman->mm[manager] = *allocator;
++
++ return 0;
++}
++
++static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman,
++ unsigned long owner)
++{
++ int ret;
++ drm_hash_item_t *owner_hash_item;
++ drm_owner_item_t *owner_item;
++
++ ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
++ if (!ret) {
++ return drm_hash_entry(owner_hash_item, drm_owner_item_t,
++ owner_hash);
++ }
++
++ owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
++ if (!owner_item)
++ goto out;
++
++ INIT_LIST_HEAD(&owner_item->mem_blocks);
++ owner_item->owner_hash.key = owner;
++ if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
++ goto out1;
++
++ list_add_tail(&owner_item->sman_list, &sman->owner_items);
++ return owner_item;
++
++out1:
++ drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
++out:
++ return NULL;
++}
++
++drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager,
++ unsigned long size, unsigned alignment,
++ unsigned long owner)
++{
++ void *tmp;
++ drm_sman_mm_t *sman_mm;
++ drm_owner_item_t *owner_item;
++ drm_memblock_item_t *memblock;
++
++ BUG_ON(manager >= sman->num_managers);
++
++ sman_mm = &sman->mm[manager];
++ tmp = sman_mm->allocate(sman_mm->private, size, alignment);
++
++ if (!tmp) {
++ return NULL;
++ }
++
++ memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
++
++ if (!memblock)
++ goto out;
++
++ memblock->mm_info = tmp;
++ memblock->mm = sman_mm;
++ memblock->sman = sman;
++
++ if (drm_ht_just_insert_please
++ (&sman->user_hash_tab, &memblock->user_hash,
++ (unsigned long)memblock, 32, 0, 0))
++ goto out1;
++
++ owner_item = drm_sman_get_owner_item(sman, owner);
++ if (!owner_item)
++ goto out2;
++
++ list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
++
++ return memblock;
++
++out2:
++ drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
++out1:
++ drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
++out:
++ sman_mm->free(sman_mm->private, tmp);
++
++ return NULL;
++}
++
++EXPORT_SYMBOL(drm_sman_alloc);
++
++static void drm_sman_free(drm_memblock_item_t *item)
++{
++ drm_sman_t *sman = item->sman;
++
++ list_del(&item->owner_list);
++ drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
++ item->mm->free(item->mm->private, item->mm_info);
++ drm_free(item, sizeof(*item), DRM_MEM_MM);
++}
++
++int drm_sman_free_key(drm_sman_t *sman, unsigned int key)
++{
++ drm_hash_item_t *hash_item;
++ drm_memblock_item_t *memblock_item;
++
++ if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
++ return -EINVAL;
++
++ memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash);
++ drm_sman_free(memblock_item);
++ return 0;
++}
++
++EXPORT_SYMBOL(drm_sman_free_key);
++
++static void drm_sman_remove_owner(drm_sman_t *sman,
++ drm_owner_item_t *owner_item)
++{
++ list_del(&owner_item->sman_list);
++ drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
++ drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
++}
++
++int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner)
++{
++
++ drm_hash_item_t *hash_item;
++ drm_owner_item_t *owner_item;
++
++ if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
++ return -1;
++ }
++
++ owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
++ if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
++ drm_sman_remove_owner(sman, owner_item);
++ return -1;
++ }
++
++ return 0;
++}
++
++EXPORT_SYMBOL(drm_sman_owner_clean);
++
++static void drm_sman_do_owner_cleanup(drm_sman_t *sman,
++ drm_owner_item_t *owner_item)
++{
++ drm_memblock_item_t *entry, *next;
++
++ list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
++ owner_list) {
++ drm_sman_free(entry);
++ }
++ drm_sman_remove_owner(sman, owner_item);
++}
++
++void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner)
++{
++
++ drm_hash_item_t *hash_item;
++ drm_owner_item_t *owner_item;
++
++ if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
++
++ return;
++ }
++
++ owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
++ drm_sman_do_owner_cleanup(sman, owner_item);
++}
++
++EXPORT_SYMBOL(drm_sman_owner_cleanup);
++
++void drm_sman_cleanup(drm_sman_t *sman)
++{
++ drm_owner_item_t *entry, *next;
++ unsigned int i;
++ drm_sman_mm_t *sman_mm;
++
++ list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
++ drm_sman_do_owner_cleanup(sman, entry);
++ }
++ if (sman->mm) {
++ for (i = 0; i < sman->num_managers; ++i) {
++ sman_mm = &sman->mm[i];
++ if (sman_mm->private) {
++ sman_mm->destroy(sman_mm->private);
++ sman_mm->private = NULL;
++ }
++ }
++ }
++}
++
++EXPORT_SYMBOL(drm_sman_cleanup);
+diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h
+new file mode 100644
+index 0000000..ddc732a
+--- /dev/null
++++ b/drivers/char/drm/drm_sman.h
+@@ -0,0 +1,176 @@
++/**************************************************************************
++ *
++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
++ * 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.
++ *
++ *
++ **************************************************************************/
++/*
++ * Simple memory MANager interface that keeps track on allocate regions on a
++ * per "owner" basis. All regions associated with an "owner" can be released
++ * with a simple call. Typically if the "owner" exists. The owner is any
++ * "unsigned long" identifier. Can typically be a pointer to a file private
++ * struct or a context identifier.
++ *
++ * Authors:
++ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
++ */
++
++#ifndef DRM_SMAN_H
++#define DRM_SMAN_H
++
++#include "drmP.h"
++#include "drm_hashtab.h"
++
++/*
++ * A class that is an abstration of a simple memory allocator.
++ * The sman implementation provides a default such allocator
++ * using the drm_mm.c implementation. But the user can replace it.
++ * See the SiS implementation, which may use the SiS FB kernel module
++ * for memory management.
++ */
++
++typedef struct drm_sman_mm {
++ /* private info. If allocated, needs to be destroyed by the destroy
++ function */
++ void *private;
++
++ /* Allocate a memory block with given size and alignment.
++ Return an opaque reference to the memory block */
++
++ void *(*allocate) (void *private, unsigned long size,
++ unsigned alignment);
++
++ /* Free a memory block. "ref" is the opaque reference that we got from
++ the "alloc" function */
++
++ void (*free) (void *private, void *ref);
++
++ /* Free all resources associated with this allocator */
++
++ void (*destroy) (void *private);
++
++ /* Return a memory offset from the opaque reference returned from the
++ "alloc" function */
++
++ unsigned long (*offset) (void *private, void *ref);
++} drm_sman_mm_t;
++
++typedef struct drm_memblock_item {
++ struct list_head owner_list;
++ drm_hash_item_t user_hash;
++ void *mm_info;
++ drm_sman_mm_t *mm;
++ struct drm_sman *sman;
++} drm_memblock_item_t;
++
++typedef struct drm_sman {
++ drm_sman_mm_t *mm;
++ int num_managers;
++ drm_open_hash_t owner_hash_tab;
++ drm_open_hash_t user_hash_tab;
++ struct list_head owner_items;
++} drm_sman_t;
++
++/*
++ * Take down a memory manager. This function should only be called after a
++ * successful init and after a call to drm_sman_cleanup.
++ */
++
++extern void drm_sman_takedown(drm_sman_t * sman);
++
++/*
++ * Allocate structures for a manager.
++ * num_managers are the number of memory pools to manage. (VRAM, AGP, ....)
++ * user_order is the log2 of the number of buckets in the user hash table.
++ * set this to approximately log2 of the max number of memory regions
++ * that will be allocated for _all_ pools together.
++ * owner_order is the log2 of the number of buckets in the owner hash table.
++ * set this to approximately log2 of
++ * the number of client file connections that will
++ * be using the manager.
++ *
++ */
++
++extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
++ unsigned int user_order, unsigned int owner_order);
++
++/*
++ * Initialize a drm_mm.c allocator. Should be called only once for each
++ * manager unless a customized allogator is used.
++ */
++
++extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
++ unsigned long start, unsigned long size);
++
++/*
++ * Initialize a customized allocator for one of the managers.
++ * (See the SiS module). The object pointed to by "allocator" is copied,
++ * so it can be destroyed after this call.
++ */
++
++extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger,
++ drm_sman_mm_t * allocator);
++
++/*
++ * Allocate a memory block. Aligment is not implemented yet.
++ */
++
++extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman,
++ unsigned int manager,
++ unsigned long size,
++ unsigned alignment,
++ unsigned long owner);
++/*
++ * Free a memory block identified by its user hash key.
++ */
++
++extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
++
++/*
++ * returns 1 iff there are no stale memory blocks associated with this owner.
++ * Typically called to determine if we need to idle the hardware and call
++ * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all
++ * resources associated with owner.
++ */
++
++extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
++
++/*
++ * Frees all stale memory blocks associated with this owner. Note that this
++ * requires that the hardware is finished with all blocks, so the graphics engine
++ * should be idled before this call is made. This function also frees
++ * any resources associated with "owner" and should be called when owner
++ * is not going to be referenced anymore.
++ */
++
++extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner);
++
++/*
++ * Frees all stale memory blocks associated with the memory manager.
++ * See idling above.
++ */
++
++extern void drm_sman_cleanup(drm_sman_t * sman);
++
++#endif
+diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
+index 9a842a3..7b1d4e8 100644
+--- a/drivers/char/drm/drm_stub.c
++++ b/drivers/char/drm/drm_stub.c
+@@ -65,22 +65,22 @@ static int drm_fill_in_dev(drm_device_t
+ mutex_init(&dev->ctxlist_mutex);
+
+ dev->pdev = pdev;
++ dev->pci_device = pdev->device;
++ dev->pci_vendor = pdev->vendor;
+
+ #ifdef __alpha__
+ dev->hose = pdev->sysdata;
+- dev->pci_domain = dev->hose->bus->number;
+-#else
+- dev->pci_domain = 0;
+ #endif
+- dev->pci_bus = pdev->bus->number;
+- dev->pci_slot = PCI_SLOT(pdev->devfn);
+- dev->pci_func = PCI_FUNC(pdev->devfn);
+ dev->irq = pdev->irq;
+
+ dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+ if (dev->maplist == NULL)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&dev->maplist->head);
++ if (drm_ht_create(&dev->map_hash, 12)) {
++ drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
++ return -ENOMEM;
++ }
+
+ /* the DRM has 6 basic counters */
+ dev->counters = 6;
+diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
+index 51ad98c..ba4b8de 100644
+--- a/drivers/char/drm/drm_sysfs.c
++++ b/drivers/char/drm/drm_sysfs.c
+@@ -42,13 +42,24 @@ static CLASS_ATTR(version, S_IRUGO, vers
+ struct class *drm_sysfs_create(struct module *owner, char *name)
+ {
+ struct class *class;
++ int err;
+
+ class = class_create(owner, name);
+- if (!class)
+- return class;
++ if (!class) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ err = class_create_file(class, &class_attr_version);
++ if (err)
++ goto err_out_class;
+
+- class_create_file(class, &class_attr_version);
+ return class;
++
++err_out_class:
++ class_destroy(class);
++err_out:
++ return ERR_PTR(err);
+ }
+
+ /**
+@@ -96,20 +107,36 @@ static struct class_device_attribute cla
+ struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head)
+ {
+ struct class_device *class_dev;
+- int i;
++ int i, j, err;
+
+ class_dev = class_device_create(cs, NULL,
+ MKDEV(DRM_MAJOR, head->minor),
+ &(head->dev->pdev)->dev,
+ "card%d", head->minor);
+- if (!class_dev)
+- return NULL;
++ if (!class_dev) {
++ err = -ENOMEM;
++ goto err_out;
++ }
+
+ class_set_devdata(class_dev, head);
+
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_create_file(class_dev, &class_device_attrs[i]);
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
++ err = class_device_create_file(class_dev,
++ &class_device_attrs[i]);
++ if (err)
++ goto err_out_files;
++ }
++
+ return class_dev;
++
++err_out_files:
++ if (i > 0)
++ for (j = 0; j < i; j++)
++ class_device_remove_file(class_dev,
++ &class_device_attrs[i]);
++ class_device_unregister(class_dev);
++err_out:
++ return ERR_PTR(err);
+ }
+
+ /**
+diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
+index ffd0800..b40ae43 100644
+--- a/drivers/char/drm/drm_vm.c
++++ b/drivers/char/drm/drm_vm.c
+@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm
+ drm_device_t *dev = priv->head->dev;
+ drm_map_t *map = NULL;
+ drm_map_list_t *r_list;
+- struct list_head *list;
++ drm_hash_item_t *hash;
+
+ /*
+ * Find the right map
+@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm
+ if (!dev->agp || !dev->agp->cant_use_aperture)
+ goto vm_nopage_error;
+
+- list_for_each(list, &dev->maplist->head) {
+- r_list = list_entry(list, drm_map_list_t, head);
+- map = r_list->map;
+- if (!map)
+- continue;
+- if (r_list->user_token == VM_OFFSET(vma))
+- break;
+- }
++ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
++ goto vm_nopage_error;
++
++ r_list = drm_hash_entry(hash, drm_map_list_t, hash);
++ map = r_list->map;
+
+ if (map && map->type == _DRM_AGP) {
+ unsigned long offset = address - vma->vm_start;
+@@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *fil
+ dev = priv->head->dev;
+ dma = dev->dma;
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+- vma->vm_start, vma->vm_end, VM_OFFSET(vma));
++ vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+
+ /* Length must match exact page count */
+ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
+@@ -521,12 +518,11 @@ int drm_mmap(struct file *filp, struct v
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ drm_map_t *map = NULL;
+- drm_map_list_t *r_list;
+ unsigned long offset = 0;
+- struct list_head *list;
++ drm_hash_item_t *hash;
+
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+- vma->vm_start, vma->vm_end, VM_OFFSET(vma));
++ vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+
+ if (!priv->authenticated)
+ return -EACCES;
+@@ -535,7 +531,7 @@ int drm_mmap(struct file *filp, struct v
+ * the AGP mapped at physical address 0
+ * --BenH.
+ */
+- if (!VM_OFFSET(vma)
++ if (!(vma->vm_pgoff << PAGE_SHIFT)
+ #if __OS_HAS_AGP
+ && (!dev->agp
+ || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
+@@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct v
+ )
+ return drm_mmap_dma(filp, vma);
+
+- /* A sequential search of a linked list is
+- fine here because: 1) there will only be
+- about 5-10 entries in the list and, 2) a
+- DRI client only has to do this mapping
+- once, so it doesn't have to be optimized
+- for performance, even if the list was a
+- bit longer. */
+- list_for_each(list, &dev->maplist->head) {
+-
+- r_list = list_entry(list, drm_map_list_t, head);
+- map = r_list->map;
+- if (!map)
+- continue;
+- if (r_list->user_token == VM_OFFSET(vma))
+- break;
++ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
++ DRM_ERROR("Could not find map\n");
++ return -EINVAL;
+ }
+
++ map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
+ if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+ return -EPERM;
+
+@@ -620,7 +605,7 @@ int drm_mmap(struct file *filp, struct v
+ offset = dev->driver->get_reg_ofs(dev);
+ #ifdef __sparc__
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+- if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
++ if (io_remap_pfn_range(vma, vma->vm_start,
+ (map->offset + offset) >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
+index c658dde..fa2de70 100644
+--- a/drivers/char/drm/i810_dma.c
++++ b/drivers/char/drm/i810_dma.c
+@@ -106,7 +106,7 @@ static int i810_mmap_buffers(struct file
+ unlock_kernel();
+
+ if (io_remap_pfn_range(vma, vma->vm_start,
+- VM_OFFSET(vma) >> PAGE_SHIFT,
++ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+@@ -141,10 +141,10 @@ static int i810_map_buffer(drm_buf_t * b
+ MAP_SHARED, buf->bus_address);
+ dev_priv->mmap_buffer = NULL;
+ filp->f_op = old_fops;
+- if ((unsigned long)buf_priv->virtual > -1024UL) {
++ if (IS_ERR(buf_priv->virtual)) {
+ /* Real error */
+ DRM_ERROR("mmap error\n");
+- retcode = (signed int)buf_priv->virtual;
++ retcode = PTR_ERR(buf_priv->virtual);
+ buf_priv->virtual = NULL;
+ }
+ up_write(¤t->mm->mmap_sem);
+@@ -808,7 +808,7 @@ static void i810_dma_dispatch_vertex(drm
+ ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2)));
+
+ if (used & 4) {
+- *(u32 *) ((u32) buf_priv->kernel_virtual + used) = 0;
++ *(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0;
+ used += 4;
+ }
+
+@@ -1166,7 +1166,7 @@ static void i810_dma_dispatch_mc(drm_dev
+
+ if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+ if (used & 4) {
+- *(u32 *) ((u32) buf_priv->virtual + used) = 0;
++ *(u32 *) ((char *) buf_priv->virtual + used) = 0;
+ used += 4;
+ }
+
+diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
+index b0f815d..4f0e574 100644
+--- a/drivers/char/drm/i830_dma.c
++++ b/drivers/char/drm/i830_dma.c
+@@ -108,7 +108,7 @@ static int i830_mmap_buffers(struct file
+ unlock_kernel();
+
+ if (io_remap_pfn_range(vma, vma->vm_start,
+- VM_OFFSET(vma) >> PAGE_SHIFT,
++ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+@@ -146,7 +146,7 @@ static int i830_map_buffer(drm_buf_t * b
+ if (IS_ERR((void *)virtual)) { /* ugh */
+ /* Real error */
+ DRM_ERROR("mmap error\n");
+- retcode = virtual;
++ retcode = PTR_ERR((void *)virtual);
+ buf_priv->virtual = NULL;
+ } else {
+ buf_priv->virtual = (void __user *)virtual;
+diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
+index a94233b..fb7913f 100644
+--- a/drivers/char/drm/i915_dma.c
++++ b/drivers/char/drm/i915_dma.c
+@@ -31,6 +31,11 @@
+ #include "i915_drm.h"
+ #include "i915_drv.h"
+
++#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
++ dev->pci_device == 0x2982 || \
++ dev->pci_device == 0x2992 || \
++ dev->pci_device == 0x29A2)
++
+ /* 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
+@@ -255,7 +260,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
+ retcode = i915_dma_resume(dev);
+ break;
+ default:
+- retcode = -EINVAL;
++ retcode = DRM_ERR(EINVAL);
+ break;
+ }
+
+@@ -347,7 +352,7 @@ static int i915_emit_cmds(drm_device_t *
+ if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
+ return DRM_ERR(EINVAL);
+
+- BEGIN_LP_RING(((dwords+1)&~1));
++ BEGIN_LP_RING((dwords+1)&~1);
+
+ for (i = 0; i < dwords;) {
+ int cmd, sz;
+@@ -386,7 +391,7 @@ static int i915_emit_box(drm_device_t *
+ RING_LOCALS;
+
+ if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
+- return EFAULT;
++ return DRM_ERR(EFAULT);
+ }
+
+ if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
+@@ -395,24 +400,40 @@ static int i915_emit_box(drm_device_t *
+ return DRM_ERR(EINVAL);
+ }
+
+- BEGIN_LP_RING(6);
+- OUT_RING(GFX_OP_DRAWRECT_INFO);
+- OUT_RING(DR1);
+- OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+- OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+- OUT_RING(DR4);
+- OUT_RING(0);
+- ADVANCE_LP_RING();
++ if (IS_I965G(dev)) {
++ BEGIN_LP_RING(4);
++ OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
++ OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
++ OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
++ OUT_RING(DR4);
++ ADVANCE_LP_RING();
++ } else {
++ BEGIN_LP_RING(6);
++ OUT_RING(GFX_OP_DRAWRECT_INFO);
++ OUT_RING(DR1);
++ OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
++ OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
++ OUT_RING(DR4);
++ OUT_RING(0);
++ ADVANCE_LP_RING();
++ }
+
+ return 0;
+ }
+
++/* XXX: Emitting the counter should really be moved to part of the IRQ
++ * emit. For now, do it in both places:
++ */
++
+ static void i915_emit_breadcrumb(drm_device_t *dev)
+ {
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+- dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
++ dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
++
++ if (dev_priv->counter > 0x7FFFFFFFUL)
++ dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+
+ BEGIN_LP_RING(4);
+ OUT_RING(CMD_STORE_DWORD_IDX);
+diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
+index 5aa3e0e..6af83e6 100644
+--- a/drivers/char/drm/i915_drm.h
++++ b/drivers/char/drm/i915_drm.h
+@@ -98,6 +98,12 @@ typedef struct _drm_i915_sarea {
+ int rotated_size;
+ int rotated_pitch;
+ int virtualX, virtualY;
++
++ unsigned int front_tiled;
++ unsigned int back_tiled;
++ unsigned int depth_tiled;
++ unsigned int rotated_tiled;
++ unsigned int rotated2_tiled;
+ } drm_i915_sarea_t;
+
+ /* Flags for perf_boxes
+diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
+index 2d56503..fdc2bf1 100644
+--- a/drivers/char/drm/i915_drv.h
++++ b/drivers/char/drm/i915_drv.h
+@@ -146,9 +146,9 @@ extern void i915_mem_release(drm_device_
+ #define BEGIN_LP_RING(n) do { \
+ if (I915_VERBOSE) \
+ DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
+- n, __FUNCTION__); \
+- if (dev_priv->ring.space < n*4) \
+- i915_wait_ring(dev, n*4, __FUNCTION__); \
++ (n), __FUNCTION__); \
++ if (dev_priv->ring.space < (n)*4) \
++ i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ outcount = 0; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+@@ -157,7 +157,7 @@ extern void i915_mem_release(drm_device_
+
+ #define OUT_RING(n) do { \
+ if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+- *(volatile unsigned int *)(virt + outring) = n; \
++ *(volatile unsigned int *)(virt + outring) = (n); \
+ outcount++; \
+ outring += 4; \
+ outring &= ringmask; \
+@@ -254,6 +254,8 @@ extern int i915_wait_ring(drm_device_t *
+ #define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+ #define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+
++#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
++
+ #define MI_BATCH_BUFFER ((0x30<<23)|1)
+ #define MI_BATCH_BUFFER_START (0x31<<23)
+ #define MI_BATCH_BUFFER_END (0xA<<23)
+diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
+index cd96cfa..0d4a162 100644
+--- a/drivers/char/drm/i915_irq.c
++++ b/drivers/char/drm/i915_irq.c
+@@ -71,21 +71,27 @@ irqreturn_t i915_driver_irq_handler(DRM_
+ static int i915_emit_irq(drm_device_t * dev)
+ {
+ drm_i915_private_t *dev_priv = dev->dev_private;
+- u32 ret;
+ RING_LOCALS;
+
+ i915_kernel_lost_context(dev);
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+- ret = dev_priv->counter;
++ dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+
+- BEGIN_LP_RING(2);
++ if (dev_priv->counter > 0x7FFFFFFFUL)
++ dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
++
++ BEGIN_LP_RING(6);
++ OUT_RING(CMD_STORE_DWORD_IDX);
++ OUT_RING(20);
++ OUT_RING(dev_priv->counter);
++ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(GFX_OP_USER_INTERRUPT);
+ ADVANCE_LP_RING();
+-
+- return ret;
++
++ return dev_priv->counter;
+ }
+
+ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
+diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
+index e30f556..be49dbb 100644
+--- a/drivers/char/drm/mga_drv.c
++++ b/drivers/char/drm/mga_drv.c
+@@ -47,6 +47,7 @@ static struct drm_driver driver = {
+ DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
+ DRIVER_IRQ_VBL,
++ .dev_priv_size = sizeof(drm_mga_buf_priv_t),
+ .load = mga_driver_load,
+ .unload = mga_driver_unload,
+ .lastclose = mga_driver_lastclose,
+diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
+index 26bdf2c..d14477b 100644
+--- a/drivers/char/drm/r300_cmdbuf.c
++++ b/drivers/char/drm/r300_cmdbuf.c
+@@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_m
+ return 0;
+ }
+
++static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
++ drm_radeon_kcmd_buffer_t *cmdbuf)
++{
++ u32 *cmd = (u32 *) cmdbuf->buf;
++ int count, ret;
++ RING_LOCALS;
++
++ count=(cmd[0]>>16) & 0x3fff;
++
++ if ((cmd[1] & 0x8000ffff) != 0x80000810) {
++ DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
++ return DRM_ERR(EINVAL);
++ }
++ ret = r300_check_offset(dev_priv, cmd[2]);
++ if (ret) {
++ DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
++ return DRM_ERR(EINVAL);
++ }
++
++ BEGIN_RING(count+2);
++ OUT_RING(cmd[0]);
++ OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
++ ADVANCE_RING();
++
++ cmdbuf->buf += (count+2)*4;
++ cmdbuf->bufsz -= (count+2)*4;
++
++ return 0;
++}
++
+ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
+ drm_radeon_kcmd_buffer_t *cmdbuf)
+ {
+@@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_pack
+ case RADEON_CNTL_BITBLT_MULTI:
+ return r300_emit_bitblt_multi(dev_priv, cmdbuf);
+
++ case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
++ return r300_emit_indx_buffer(dev_priv, cmdbuf);
+ case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
+ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
+ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
+- case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
+ case RADEON_WAIT_FOR_IDLE:
+ case RADEON_CP_NOP:
+ /* these packets are safe */
+diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
+index 5ad43ba..5ed9656 100644
+--- a/drivers/char/drm/radeon_cp.c
++++ b/drivers/char/drm/radeon_cp.c
+@@ -864,13 +864,13 @@ static int radeon_do_pixcache_flush(drm_
+
+ dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
+
+- tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT);
+- tmp |= RADEON_RB2D_DC_FLUSH_ALL;
+- RADEON_WRITE(RADEON_RB2D_DSTCACHE_CTLSTAT, tmp);
++ tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
++ tmp |= RADEON_RB3D_DC_FLUSH_ALL;
++ RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
+
+ for (i = 0; i < dev_priv->usec_timeout; i++) {
+- if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT)
+- & RADEON_RB2D_DC_BUSY)) {
++ if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
++ & RADEON_RB3D_DC_BUSY)) {
+ return 0;
+ }
+ DRM_UDELAY(1);
+@@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(d
+ | (dev_priv->fb_location >> 16));
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
+ RADEON_WRITE(RADEON_MC_AGP_LOCATION,
+ (((dev_priv->gart_vm_start - 1 +
+@@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(d
+ dev_priv->ring.tail = cur_read_ptr;
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
+ dev_priv->ring_rptr->offset
+ - dev->agp->base + dev_priv->gart_vm_start);
+@@ -1258,6 +1258,13 @@ static void radeon_test_writeback(drm_ra
+ dev_priv->writeback_works = 0;
+ DRM_INFO("writeback forced off\n");
+ }
++
++ if (!dev_priv->writeback_works) {
++ /* Disable writeback to avoid unnecessary bus master transfer */
++ RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) |
++ RADEON_RB_NO_UPDATE);
++ RADEON_WRITE(RADEON_SCRATCH_UMSK, 0);
++ }
+ }
+
+ /* Enable or disable PCI-E GART on the chip */
+@@ -1295,7 +1302,7 @@ static void radeon_set_pcigart(drm_radeo
+ {
+ u32 tmp;
+
+- if (dev_priv->flags & CHIP_IS_PCIE) {
++ if (dev_priv->flags & RADEON_IS_PCIE) {
+ radeon_set_pciegart(dev_priv, on);
+ return;
+ }
+@@ -1333,20 +1340,22 @@ static int radeon_do_init_cp(drm_device_
+ DRM_DEBUG("\n");
+
+ /* if we require new memory map but we don't have it fail */
+- if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
+- {
+- DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
++ if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
++ DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
+ radeon_do_cleanup_cp(dev);
+ return DRM_ERR(EINVAL);
+ }
+
+- if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
+- {
++ if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
+ DRM_DEBUG("Forcing AGP card to PCI mode\n");
+- dev_priv->flags &= ~CHIP_IS_AGP;
++ dev_priv->flags &= ~RADEON_IS_AGP;
++ } else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
++ && !init->is_pci) {
++ DRM_DEBUG("Restoring AGP flag\n");
++ dev_priv->flags |= RADEON_IS_AGP;
+ }
+
+- if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) {
++ if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
+ DRM_ERROR("PCI GART memory not allocated!\n");
+ radeon_do_cleanup_cp(dev);
+ return DRM_ERR(EINVAL);
+@@ -1489,7 +1498,7 @@ static int radeon_do_init_cp(drm_device_
+ init->sarea_priv_offset);
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ drm_core_ioremap(dev_priv->cp_ring, dev);
+ drm_core_ioremap(dev_priv->ring_rptr, dev);
+ drm_core_ioremap(dev->agp_buffer_map, dev);
+@@ -1548,7 +1557,7 @@ static int radeon_do_init_cp(drm_device_
+ * align it down.
+ */
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ base = dev->agp->base;
+ /* Check if valid */
+ if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
+@@ -1578,7 +1587,7 @@ static int radeon_do_init_cp(drm_device_
+ }
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP)
++ if (dev_priv->flags & RADEON_IS_AGP)
+ dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
+ - dev->agp->base
+ + dev_priv->gart_vm_start);
+@@ -1604,7 +1613,7 @@ static int radeon_do_init_cp(drm_device_
+ dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ /* Turn off PCI GART */
+ radeon_set_pcigart(dev_priv, 0);
+ } else
+@@ -1624,7 +1633,7 @@ static int radeon_do_init_cp(drm_device_
+ dev_priv->gart_info.mapping.handle;
+
+ dev_priv->gart_info.is_pcie =
+- !!(dev_priv->flags & CHIP_IS_PCIE);
++ !!(dev_priv->flags & RADEON_IS_PCIE);
+ dev_priv->gart_info.gart_table_location =
+ DRM_ATI_GART_FB;
+
+@@ -1636,7 +1645,7 @@ static int radeon_do_init_cp(drm_device_
+ DRM_ATI_GART_MAIN;
+ dev_priv->gart_info.addr = NULL;
+ dev_priv->gart_info.bus_addr = 0;
+- if (dev_priv->flags & CHIP_IS_PCIE) {
++ if (dev_priv->flags & RADEON_IS_PCIE) {
+ DRM_ERROR
+ ("Cannot use PCI Express without GART in FB memory\n");
+ radeon_do_cleanup_cp(dev);
+@@ -1678,7 +1687,7 @@ static int radeon_do_cleanup_cp(drm_devi
+ drm_irq_uninstall(dev);
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ if (dev_priv->cp_ring != NULL) {
+ drm_core_ioremapfree(dev_priv->cp_ring, dev);
+ dev_priv->cp_ring = NULL;
+@@ -1733,7 +1742,7 @@ static int radeon_do_resume_cp(drm_devic
+ DRM_DEBUG("Starting radeon_do_resume_cp()\n");
+
+ #if __OS_HAS_AGP
+- if (dev_priv->flags & CHIP_IS_AGP) {
++ if (dev_priv->flags & RADEON_IS_AGP) {
+ /* Turn off PCI GART */
+ radeon_set_pcigart(dev_priv, 0);
+ } else
+@@ -2177,13 +2186,15 @@ int radeon_driver_load(struct drm_device
+ dev->dev_private = (void *)dev_priv;
+ dev_priv->flags = flags;
+
+- switch (flags & CHIP_FAMILY_MASK) {
++ switch (flags & RADEON_FAMILY_MASK) {
+ case CHIP_R100:
+ case CHIP_RV200:
+ case CHIP_R200:
+ case CHIP_R300:
++ case CHIP_R350:
+ case CHIP_R420:
+- dev_priv->flags |= CHIP_HAS_HIERZ;
++ case CHIP_RV410:
++ dev_priv->flags |= RADEON_HAS_HIERZ;
+ break;
+ default:
+ /* all other chips have no hierarchical z buffer */
+@@ -2191,13 +2202,14 @@ int radeon_driver_load(struct drm_device
+ }
+
+ if (drm_device_is_agp(dev))
+- dev_priv->flags |= CHIP_IS_AGP;
+-
+- if (drm_device_is_pcie(dev))
+- dev_priv->flags |= CHIP_IS_PCIE;
++ dev_priv->flags |= RADEON_IS_AGP;
++ else if (drm_device_is_pcie(dev))
++ dev_priv->flags |= RADEON_IS_PCIE;
++ else
++ dev_priv->flags |= RADEON_IS_PCI;
+
+ DRM_DEBUG("%s card detected\n",
+- ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI"))));
++ ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
+ return ret;
+ }
+
+diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
+index eb985c2..2eb652e 100644
+--- a/drivers/char/drm/radeon_drv.c
++++ b/drivers/char/drm/radeon_drv.c
+@@ -44,7 +44,7 @@ module_param_named(no_wb, radeon_no_wb,
+ static int dri_library_name(struct drm_device *dev, char *buf)
+ {
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+- int family = dev_priv->flags & CHIP_FAMILY_MASK;
++ int family = dev_priv->flags & RADEON_FAMILY_MASK;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (family < CHIP_R200) ? "radeon" :
+diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
+index e5a256f..f45cd7f 100644
+--- a/drivers/char/drm/radeon_drv.h
++++ b/drivers/char/drm/radeon_drv.h
+@@ -133,15 +133,16 @@ enum radeon_cp_microcode_version {
+ * Chip flags
+ */
+ enum radeon_chip_flags {
+- CHIP_FAMILY_MASK = 0x0000ffffUL,
+- CHIP_FLAGS_MASK = 0xffff0000UL,
+- CHIP_IS_MOBILITY = 0x00010000UL,
+- CHIP_IS_IGP = 0x00020000UL,
+- CHIP_SINGLE_CRTC = 0x00040000UL,
+- CHIP_IS_AGP = 0x00080000UL,
+- CHIP_HAS_HIERZ = 0x00100000UL,
+- CHIP_IS_PCIE = 0x00200000UL,
+- CHIP_NEW_MEMMAP = 0x00400000UL,
++ RADEON_FAMILY_MASK = 0x0000ffffUL,
++ RADEON_FLAGS_MASK = 0xffff0000UL,
++ RADEON_IS_MOBILITY = 0x00010000UL,
++ RADEON_IS_IGP = 0x00020000UL,
++ RADEON_SINGLE_CRTC = 0x00040000UL,
++ RADEON_IS_AGP = 0x00080000UL,
++ RADEON_HAS_HIERZ = 0x00100000UL,
++ RADEON_IS_PCIE = 0x00200000UL,
++ RADEON_NEW_MEMMAP = 0x00400000UL,
++ RADEON_IS_PCI = 0x00800000UL,
+ };
+
+ #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \
+@@ -424,6 +425,8 @@ extern int r300_do_cp_cmdbuf(drm_device_
+ #define RADEON_RB3D_COLOROFFSET 0x1c40
+ #define RADEON_RB3D_COLORPITCH 0x1c48
+
++#define RADEON_SRC_X_Y 0x1590
++
+ #define RADEON_DP_GUI_MASTER_CNTL 0x146c
+ # define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
+ # define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
+@@ -441,6 +444,7 @@ extern int r300_do_cp_cmdbuf(drm_device_
+ # define RADEON_ROP3_S 0x00cc0000
+ # define RADEON_ROP3_P 0x00f00000
+ #define RADEON_DP_WRITE_MASK 0x16cc
++#define RADEON_SRC_PITCH_OFFSET 0x1428
+ #define RADEON_DST_PITCH_OFFSET 0x142c
+ #define RADEON_DST_PITCH_OFFSET_C 0x1c80
+ # define RADEON_DST_TILE_LINEAR (0 << 30)
+@@ -545,6 +549,11 @@ extern int r300_do_cp_cmdbuf(drm_device_
+ # define RADEON_RB3D_ZC_FREE (1 << 2)
+ # define RADEON_RB3D_ZC_FLUSH_ALL 0x5
+ # define RADEON_RB3D_ZC_BUSY (1 << 31)
++#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c
++# define RADEON_RB3D_DC_FLUSH (3 << 0)
++# define RADEON_RB3D_DC_FREE (3 << 2)
++# define RADEON_RB3D_DC_FLUSH_ALL 0xf
++# define RADEON_RB3D_DC_BUSY (1 << 31)
+ #define RADEON_RB3D_ZSTENCILCNTL 0x1c2c
+ # define RADEON_Z_TEST_MASK (7 << 4)
+ # define RADEON_Z_TEST_ALWAYS (7 << 4)
+@@ -681,6 +690,7 @@ extern int r300_do_cp_cmdbuf(drm_device_
+ #define RADEON_CP_RB_BASE 0x0700
+ #define RADEON_CP_RB_CNTL 0x0704
+ # define RADEON_BUF_SWAP_32BIT (2 << 16)
++# define RADEON_RB_NO_UPDATE (1 << 27)
+ #define RADEON_CP_RB_RPTR_ADDR 0x070c
+ #define RADEON_CP_RB_RPTR 0x0710
+ #define RADEON_CP_RB_WPTR 0x0714
+@@ -986,13 +996,13 @@ do { \
+ } while (0)
+
+ #define RADEON_FLUSH_CACHE() do { \
+- OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \
+- OUT_RING( RADEON_RB2D_DC_FLUSH ); \
++ OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
++ OUT_RING( RADEON_RB3D_DC_FLUSH ); \
+ } while (0)
+
+ #define RADEON_PURGE_CACHE() do { \
+- OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \
+- OUT_RING( RADEON_RB2D_DC_FLUSH_ALL ); \
++ OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
++ OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \
+ } while (0)
+
+ #define RADEON_FLUSH_ZCACHE() do { \
+diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
+index 39a7f68..6e04fdd 100644
+--- a/drivers/char/drm/radeon_state.c
++++ b/drivers/char/drm/radeon_state.c
+@@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_f
+ drm_file_t * filp_priv,
+ u32 *offset)
+ {
+- u32 off = *offset;
++ u64 off = *offset;
++ u32 fb_start = dev_priv->fb_location;
++ u32 fb_end = fb_start + dev_priv->fb_size - 1;
++ u32 gart_start = dev_priv->gart_vm_start;
++ u32 gart_end = gart_start + dev_priv->gart_size - 1;
+ struct drm_radeon_driver_file_fields *radeon_priv;
+
+ /* Hrm ... the story of the offset ... So this function converts
+@@ -62,10 +66,8 @@ static __inline__ int radeon_check_and_f
+ /* First, the best case, the offset already lands in either the
+ * framebuffer or the GART mapped space
+ */
+- if ((off >= dev_priv->fb_location &&
+- off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+- (off >= dev_priv->gart_vm_start &&
+- off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
++ if ((off >= fb_start && off <= fb_end) ||
++ (off >= gart_start && off <= gart_end))
+ return 0;
+
+ /* Ok, that didn't happen... now check if we have a zero based
+@@ -78,16 +80,13 @@ static __inline__ int radeon_check_and_f
+ }
+
+ /* Finally, assume we aimed at a GART offset if beyond the fb */
+- if (off > (dev_priv->fb_location + dev_priv->fb_size))
+- off = off - (dev_priv->fb_location + dev_priv->fb_size) +
+- dev_priv->gart_vm_start;
++ if (off > fb_end)
++ off = off - fb_end - 1 + gart_start;
+
+ /* Now recheck and fail if out of bounds */
+- if ((off >= dev_priv->fb_location &&
+- off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+- (off >= dev_priv->gart_vm_start &&
+- off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
+- DRM_DEBUG("offset fixed up to 0x%x\n", off);
++ if ((off >= fb_start && off <= fb_end) ||
++ (off >= gart_start && off <= gart_end)) {
++ DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
+ *offset = off;
+ return 0;
+ }
+@@ -276,6 +275,8 @@ static __inline__ int radeon_check_and_f
+ unsigned int *cmdsz)
+ {
+ u32 *cmd = (u32 *) cmdbuf->buf;
++ u32 offset, narrays;
++ int count, i, k;
+
+ *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+
+@@ -289,10 +290,106 @@ static __inline__ int radeon_check_and_f
+ return DRM_ERR(EINVAL);
+ }
+
+- /* Check client state and fix it up if necessary */
+- if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */
+- u32 offset;
++ switch(cmd[0] & 0xff00) {
++ /* XXX Are there old drivers needing other packets? */
+
++ case RADEON_3D_DRAW_IMMD:
++ case RADEON_3D_DRAW_VBUF:
++ case RADEON_3D_DRAW_INDX:
++ case RADEON_WAIT_FOR_IDLE:
++ case RADEON_CP_NOP:
++ case RADEON_3D_CLEAR_ZMASK:
++/* case RADEON_CP_NEXT_CHAR:
++ case RADEON_CP_PLY_NEXTSCAN:
++ case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
++ /* these packets are safe */
++ break;
++
++ case RADEON_CP_3D_DRAW_IMMD_2:
++ case RADEON_CP_3D_DRAW_VBUF_2:
++ case RADEON_CP_3D_DRAW_INDX_2:
++ case RADEON_3D_CLEAR_HIZ:
++ /* safe but r200 only */
++ if (dev_priv->microcode_version != UCODE_R200) {
++ DRM_ERROR("Invalid 3d packet for r100-class chip\n");
++ return DRM_ERR(EINVAL);
++ }
++ break;
++
++ case RADEON_3D_LOAD_VBPNTR:
++ count = (cmd[0] >> 16) & 0x3fff;
++
++ if (count > 18) { /* 12 arrays max */
++ DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
++ count);
++ return DRM_ERR(EINVAL);
++ }
++
++ /* carefully check packet contents */
++ narrays = cmd[1] & ~0xc000;
++ k = 0;
++ i = 2;
++ while ((k < narrays) && (i < (count + 2))) {
++ i++; /* skip attribute field */
++ if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
++ DRM_ERROR
++ ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
++ k, i);
++ return DRM_ERR(EINVAL);
++ }
++ k++;
++ i++;
++ if (k == narrays)
++ break;
++ /* have one more to process, they come in pairs */
++ if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
++ DRM_ERROR
++ ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
++ k, i);
++ return DRM_ERR(EINVAL);
++ }
++ k++;
++ i++;
++ }
++ /* do the counts match what we expect ? */
++ if ((k != narrays) || (i != (count + 2))) {
++ DRM_ERROR
++ ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
++ k, i, narrays, count + 1);
++ return DRM_ERR(EINVAL);
++ }
++ break;
++
++ case RADEON_3D_RNDR_GEN_INDX_PRIM:
++ if (dev_priv->microcode_version != UCODE_R100) {
++ DRM_ERROR("Invalid 3d packet for r200-class chip\n");
++ return DRM_ERR(EINVAL);
++ }
++ if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
++ DRM_ERROR("Invalid rndr_gen_indx offset\n");
++ return DRM_ERR(EINVAL);
++ }
++ break;
++
++ case RADEON_CP_INDX_BUFFER:
++ if (dev_priv->microcode_version != UCODE_R200) {
++ DRM_ERROR("Invalid 3d packet for r100-class chip\n");
++ return DRM_ERR(EINVAL);
++ }
++ if ((cmd[1] & 0x8000ffff) != 0x80000810) {
++ DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
++ return DRM_ERR(EINVAL);
++ }
++ if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
++ DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
++ return DRM_ERR(EINVAL);
++ }
++ break;
++
++ case RADEON_CNTL_HOSTDATA_BLT:
++ case RADEON_CNTL_PAINT_MULTI:
++ case RADEON_CNTL_BITBLT_MULTI:
++ /* MSB of opcode: next DWORD GUI_CNTL */
+ if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+ | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
+ offset = cmd[2] << 10;
+@@ -314,6 +411,11 @@ static __inline__ int radeon_check_and_f
+ }
+ cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
+ }
++ break;
++
++ default:
++ DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
++ return DRM_ERR(EINVAL);
+ }
+
+ return 0;
+@@ -869,7 +971,7 @@ static void radeon_cp_dispatch_clear(drm
+ */
+ dev_priv->sarea_priv->ctx_owner = 0;
+
+- if ((dev_priv->flags & CHIP_HAS_HIERZ)
++ if ((dev_priv->flags & RADEON_HAS_HIERZ)
+ && (flags & RADEON_USE_HIERZ)) {
+ /* FIXME : reverse engineer that for Rx00 cards */
+ /* FIXME : the mask supposedly contains low-res z values. So can't set
+@@ -914,7 +1016,7 @@ static void radeon_cp_dispatch_clear(drm
+ for (i = 0; i < nbox; i++) {
+ int tileoffset, nrtilesx, nrtilesy, j;
+ /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
+- if ((dev_priv->flags & CHIP_HAS_HIERZ)
++ if ((dev_priv->flags & RADEON_HAS_HIERZ)
+ && !(dev_priv->microcode_version == UCODE_R200)) {
+ /* FIXME : figure this out for r200 (when hierz is enabled). Or
+ maybe r200 actually doesn't need to put the low-res z value into
+@@ -998,7 +1100,7 @@ static void radeon_cp_dispatch_clear(drm
+ }
+
+ /* TODO don't always clear all hi-level z tiles */
+- if ((dev_priv->flags & CHIP_HAS_HIERZ)
++ if ((dev_priv->flags & RADEON_HAS_HIERZ)
+ && (dev_priv->microcode_version == UCODE_R200)
+ && (flags & RADEON_USE_HIERZ))
+ /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
+@@ -1270,9 +1372,9 @@ static void radeon_cp_dispatch_swap(drm_
+
+ DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
+
+- BEGIN_RING(7);
++ BEGIN_RING(9);
+
+- OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
++ OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
+ OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+ RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+ RADEON_GMC_BRUSH_NONE |
+@@ -1284,6 +1386,7 @@ static void radeon_cp_dispatch_swap(drm_
+
+ /* Make this work even if front & back are flipped:
+ */
++ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
+ if (dev_priv->current_page == 0) {
+ OUT_RING(dev_priv->back_pitch_offset);
+ OUT_RING(dev_priv->front_pitch_offset);
+@@ -1292,6 +1395,7 @@ static void radeon_cp_dispatch_swap(drm_
+ OUT_RING(dev_priv->back_pitch_offset);
+ }
+
++ OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
+ OUT_RING((x << 16) | y);
+ OUT_RING((x << 16) | y);
+ OUT_RING((w << 16) | h);
+@@ -2987,16 +3091,21 @@ static int radeon_cp_getparam(DRM_IOCTL_
+ case RADEON_PARAM_GART_TEX_HANDLE:
+ value = dev_priv->gart_textures_offset;
+ break;
+-
++ case RADEON_PARAM_SCRATCH_OFFSET:
++ if (!dev_priv->writeback_works)
++ return DRM_ERR(EINVAL);
++ value = RADEON_SCRATCH_REG_OFFSET;
++ break;
+ case RADEON_PARAM_CARD_TYPE:
+- if (dev_priv->flags & CHIP_IS_PCIE)
++ if (dev_priv->flags & RADEON_IS_PCIE)
+ value = RADEON_CARD_PCIE;
+- else if (dev_priv->flags & CHIP_IS_AGP)
++ else if (dev_priv->flags & RADEON_IS_AGP)
+ value = RADEON_CARD_AGP;
+ else
+ value = RADEON_CARD_PCI;
+ break;
+ default:
++ DRM_DEBUG("Invalid parameter %d\n", param.param);
+ return DRM_ERR(EINVAL);
+ }
+
+diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
+index 59c7520..a9a84f8 100644
+--- a/drivers/char/drm/savage_bci.c
++++ b/drivers/char/drm/savage_bci.c
+@@ -728,6 +728,7 @@ static int savage_do_init_bci(drm_device
+ dev_priv->status = NULL;
+ }
+ if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) {
++ dev->agp_buffer_token = init->buffers_offset;
+ dev->agp_buffer_map = drm_core_findmap(dev,
+ init->buffers_offset);
+ if (!dev->agp_buffer_map) {
+diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
+index ef2581d..1ca1e9c 100644
+--- a/drivers/char/drm/savage_state.c
++++ b/drivers/char/drm/savage_state.c
+@@ -994,7 +994,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
+ if (cmdbuf.size) {
+ kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);
+ if (kcmd_addr == NULL)
+- return ENOMEM;
++ return DRM_ERR(ENOMEM);
+
+ if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,
+ cmdbuf.size * 8))
+diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
+index 5e9dc86..3d5b321 100644
+--- a/drivers/char/drm/sis_drv.c
++++ b/drivers/char/drm/sis_drv.c
+@@ -35,11 +35,44 @@ static struct pci_device_id pciidlist[]
+ sisdrv_PCI_IDS
+ };
+
++static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
++{
++ drm_sis_private_t *dev_priv;
++ int ret;
++
++ dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
++ if (dev_priv == NULL)
++ return DRM_ERR(ENOMEM);
++
++ dev->dev_private = (void *)dev_priv;
++ dev_priv->chipset = chipset;
++ ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
++ if (ret) {
++ drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER);
++ }
++
++ return ret;
++}
++
++static int sis_driver_unload(drm_device_t *dev)
++{
++ drm_sis_private_t *dev_priv = dev->dev_private;
++
++ drm_sman_takedown(&dev_priv->sman);
++ drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
++
++ return 0;
++}
++
+ static struct drm_driver driver = {
+ .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
+- .context_ctor = sis_init_context,
+- .context_dtor = sis_final_context,
+- .reclaim_buffers = drm_core_reclaim_buffers,
++ .load = sis_driver_load,
++ .unload = sis_driver_unload,
++ .context_dtor = NULL,
++ .dma_quiescent = sis_idle,
++ .reclaim_buffers = NULL,
++ .reclaim_buffers_locked = sis_reclaim_buffers_locked,
++ .lastclose = sis_lastclose,
+ .get_map_ofs = drm_core_get_map_ofs,
+ .get_reg_ofs = drm_core_get_reg_ofs,
+ .ioctls = sis_ioctls,
+diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
+index e218e52..2b8d6f6 100644
+--- a/drivers/char/drm/sis_drv.h
++++ b/drivers/char/drm/sis_drv.h
+@@ -31,23 +31,39 @@
+ /* General customization:
+ */
+
+-#define DRIVER_AUTHOR "SIS"
++#define DRIVER_AUTHOR "SIS, Tungsten Graphics"
+ #define DRIVER_NAME "sis"
+ #define DRIVER_DESC "SIS 300/630/540"
+-#define DRIVER_DATE "20030826"
++#define DRIVER_DATE "20060704"
+ #define DRIVER_MAJOR 1
+-#define DRIVER_MINOR 1
+-#define DRIVER_PATCHLEVEL 0
++#define DRIVER_MINOR 2
++#define DRIVER_PATCHLEVEL 1
+
+-#include "sis_ds.h"
++enum sis_family {
++ SIS_OTHER = 0,
++ SIS_CHIP_315 = 1,
++};
++
++#include "drm_sman.h"
++
++#define SIS_BASE (dev_priv->mmio)
++#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg);
++#define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val);
+
+ typedef struct drm_sis_private {
+- memHeap_t *AGPHeap;
+- memHeap_t *FBHeap;
++ drm_local_map_t *mmio;
++ unsigned int idle_fault;
++ drm_sman_t sman;
++ unsigned int chipset;
++ int vram_initialized;
++ int agp_initialized;
++ unsigned long vram_offset;
++ unsigned long agp_offset;
+ } drm_sis_private_t;
+
+-extern int sis_init_context(drm_device_t * dev, int context);
+-extern int sis_final_context(drm_device_t * dev, int context);
++extern int sis_idle(drm_device_t *dev);
++extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
++extern void sis_lastclose(drm_device_t *dev);
+
+ extern drm_ioctl_desc_t sis_ioctls[];
+ extern int sis_max_ioctl;
+diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c
+deleted file mode 100644
+index 2e485d4..0000000
+--- a/drivers/char/drm/sis_ds.c
++++ /dev/null
+@@ -1,299 +0,0 @@
+-/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
+- * Created: Mon Jan 4 10:05:05 1999 by sclin at sis.com.tw
+- *
+- * 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, 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
+- * PRECISION INSIGHT 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:
+- * Sung-Ching Lin <sclin at sis.com.tw>
+- *
+- */
+-
+-#include "drmP.h"
+-#include "drm.h"
+-#include "sis_ds.h"
+-
+-/* Set Data Structure, not check repeated value
+- * temporarily used
+- */
+-
+-set_t *setInit(void)
+-{
+- int i;
+- set_t *set;
+-
+- set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
+- if (set != NULL) {
+- 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 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 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 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 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 setDestroy(set_t * set)
+-{
+- drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
+-
+- return 1;
+-}
+-
+-/*
+- * GLX Hardware Device Driver common code
+- * Copyright (C) 1999 Wittawat Yamwong
+- *
+- * 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 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
+- * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS 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.
+- *
+- */
+-
+-#define ISFREE(bptr) ((bptr)->free)
+-
+-memHeap_t *mmInit(int ofs, int size)
+-{
+- PMemBlock blocks;
+-
+- if (size <= 0)
+- return NULL;
+-
+- blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
+- if (blocks != NULL) {
+- blocks->ofs = ofs;
+- blocks->size = size;
+- blocks->free = 1;
+- return (memHeap_t *) blocks;
+- } else
+- return NULL;
+-}
+-
+-/* Checks if a pointer 'b' is part of the heap 'heap' */
+-int mmBlockInHeap(memHeap_t * heap, PMemBlock b)
+-{
+- TMemBlock *p;
+-
+- if (heap == NULL || b == NULL)
+- return 0;
+-
+- p = heap;
+- while (p != NULL && p != b) {
+- p = p->next;
+- }
+- if (p == b)
+- return 1;
+- 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 mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch)
+-{
+- int mask, startofs, endofs;
+- TMemBlock *p;
+-
+- if (heap == NULL || align2 < 0 || size <= 0)
+- return NULL;
+-
+- mask = (1 << align2) - 1;
+- startofs = 0;
+- p = (TMemBlock *) heap;
+- while (p != NULL) {
+- 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 == NULL)
+- 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 mmFreeMem(PMemBlock b)
+-{
+- TMemBlock *p, *prev;
+-
+- if (b == NULL)
+- return 0;
+- if (b->heap == NULL)
+- return -1;
+-
+- p = b->heap;
+- prev = NULL;
+- while (p != NULL && p != b) {
+- prev = p;
+- p = p->next;
+- }
+- if (p == NULL || p->free || p->reserved)
+- return -1;
+-
+- p->free = 1;
+- Join2Blocks(p);
+- if (prev)
+- Join2Blocks(prev);
+- return 0;
+-}
+diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h
+deleted file mode 100644
+index 94f2b47..0000000
+--- a/drivers/char/drm/sis_ds.h
++++ /dev/null
+@@ -1,146 +0,0 @@
+-/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+- * Created: Mon Jan 4 10:05:05 1999 by sclin at sis.com.tw
+- */
+-/*
+- * 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, 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
+- * PRECISION INSIGHT 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:
+- * Sung-Ching Lin <sclin at sis.com.tw>
+- *
+- */
+-
+-#ifndef __SIS_DS_H__
+-#define __SIS_DS_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 *setInit(void);
+-int setAdd(set_t * set, ITEM_TYPE item);
+-int setDel(set_t * set, ITEM_TYPE item);
+-int setFirst(set_t * set, ITEM_TYPE * item);
+-int setNext(set_t * set, ITEM_TYPE * item);
+-int setDestroy(set_t * set);
+-
+-/*
+- * GLX Hardware Device Driver common code
+- * Copyright (C) 1999 Wittawat Yamwong
+- *
+- * 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 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
+- * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS 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.
+- *
+- */
+-
+-struct mem_block_t {
+- struct mem_block_t *next;
+- struct mem_block_t *heap;
+- int ofs, size;
+- int align;
+- unsigned int free:1;
+- unsigned 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 *mmInit(int ofs, int size);
+-
+-/*
+- * Allocate 'size' bytes with 2^align2 bytes alignment,
+- * restrict the search to free memory after 'startSearch'
+- * depth and back buffers should be in different 4mb banks
+- * to get better page hits if possible
+- * input: size = size of block
+- * align2 = 2^align2 bytes alignment
+- * startSearch = linear offset from start of heap to begin search
+- * return: pointer to the allocated block, 0 if error
+- */
+-PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch);
+-
+-/*
+- * Returns 1 if the block 'b' is part of the heap 'heap'
+- */
+-int mmBlockInHeap(PMemBlock heap, PMemBlock b);
+-
+-/*
+- * Free block starts at offset
+- * input: pointer to a block
+- * return: 0 if OK, -1 if error
+- */
+-int mmFreeMem(PMemBlock b);
+-
+-/* For debuging purpose. */
+-void mmDumpMemInfo(memHeap_t * mmInit);
+-
+-#endif /* __SIS_DS_H__ */
+diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
+index 5e9936b..d26f5db 100644
+--- a/drivers/char/drm/sis_mm.c
++++ b/drivers/char/drm/sis_mm.c
+@@ -1,414 +1,348 @@
+-/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
+- * Created: Mon Jan 4 10:05:05 1999 by sclin at sis.com.tw
++/**************************************************************************
+ *
+- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+- * All rights reserved.
++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
++ * 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:
++ * 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 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
+- * PRECISION INSIGHT 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.
++ * 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:
+- * Sung-Ching Lin <sclin at sis.com.tw>
+ *
++ **************************************************************************/
++
++/*
++ * Authors:
++ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+ #include "drmP.h"
+ #include "sis_drm.h"
+ #include "sis_drv.h"
+-#include "sis_ds.h"
+-#if defined(__linux__) && defined(CONFIG_FB_SIS)
++
+ #include <video/sisfb.h>
+-#endif
+
+-#define MAX_CONTEXT 100
+ #define VIDEO_TYPE 0
+ #define AGP_TYPE 1
+
+-typedef struct {
+- int used;
+- int context;
+- set_t *sets[2]; /* 0 for video, 1 for AGP */
+-} sis_context_t;
+
+-static sis_context_t global_ppriv[MAX_CONTEXT];
++#if defined(CONFIG_FB_SIS)
++/* fb management via fb device */
+
+-static int add_alloc_set(int context, int type, unsigned int val)
+-{
+- int i, retval = 0;
++#define SIS_MM_ALIGN_SHIFT 0
++#define SIS_MM_ALIGN_MASK 0
+
+- for (i = 0; i < MAX_CONTEXT; i++) {
+- if (global_ppriv[i].used && global_ppriv[i].context == context) {
+- retval = setAdd(global_ppriv[i].sets[type], val);
+- break;
+- }
+- }
+- return retval;
+-}
+-
+-static int del_alloc_set(int context, int type, unsigned int val)
++static void *sis_sman_mm_allocate(void *private, unsigned long size,
++ unsigned alignment)
+ {
+- int i, retval = 0;
++ struct sis_memreq req;
+
+- for (i = 0; i < MAX_CONTEXT; i++) {
+- if (global_ppriv[i].used && global_ppriv[i].context == context) {
+- retval = setDel(global_ppriv[i].sets[type], val);
+- break;
+- }
+- }
+- return retval;
++ req.size = size;
++ sis_malloc(&req);
++ if (req.size == 0)
++ return NULL;
++ else
++ return (void *)~req.offset;
+ }
+
+-/* fb management via fb device */
+-#if defined(__linux__) && defined(CONFIG_FB_SIS)
+-
+-static int sis_fb_init(DRM_IOCTL_ARGS)
++static void sis_sman_mm_free(void *private, void *ref)
+ {
+- return 0;
++ sis_free(~((unsigned long)ref));
+ }
+
+-static int sis_fb_alloc(DRM_IOCTL_ARGS)
++static void sis_sman_mm_destroy(void *private)
+ {
+- drm_sis_mem_t fb;
+- struct sis_memreq req;
+- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
+- int retval = 0;
+-
+- DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
+-
+- req.size = fb.size;
+- sis_malloc(&req);
+- if (req.offset) {
+- /* TODO */
+- fb.offset = req.offset;
+- fb.free = req.offset;
+- if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
+- DRM_DEBUG("adding to allocation set fails\n");
+- sis_free(req.offset);
+- retval = DRM_ERR(EINVAL);
+- }
+- } else {
+- fb.offset = 0;
+- fb.size = 0;
+- fb.free = 0;
+- }
+-
+- DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
+-
+- DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
+-
+- return retval;
++ ;
+ }
+
+-static int sis_fb_free(DRM_IOCTL_ARGS)
++static unsigned long sis_sman_mm_offset(void *private, void *ref)
+ {
+- drm_sis_mem_t fb;
+- int retval = 0;
+-
+- DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
+-
+- if (!fb.free)
+- return DRM_ERR(EINVAL);
++ return ~((unsigned long)ref);
++}
+
+- if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
+- retval = DRM_ERR(EINVAL);
+- sis_free(fb.free);
++#else /* CONFIG_FB_SIS */
+
+- DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
++#define SIS_MM_ALIGN_SHIFT 4
++#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
+
+- return retval;
+-}
++#endif /* CONFIG_FB_SIS */
+
+-#else
+-
+-/* Called by the X Server to initialize the FB heap. Allocations will fail
+- * unless this is called. Offset is the beginning of the heap from the
+- * framebuffer offset (MaxXFBMem in XFree86).
+- *
+- * Memory layout according to Thomas Winischofer:
+- * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
+- *
+- * X driver/sisfb HW- Command-
+- * framebuffer memory DRI heap Cursor queue
+- */
+ static int sis_fb_init(DRM_IOCTL_ARGS)
+ {
+ DRM_DEVICE;
+ drm_sis_private_t *dev_priv = dev->dev_private;
+ drm_sis_fb_t fb;
++ int ret;
+
+ DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
+
+- if (dev_priv == NULL) {
+- dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
+- DRM_MEM_DRIVER);
+- dev_priv = dev->dev_private;
+- if (dev_priv == NULL)
+- return ENOMEM;
++ mutex_lock(&dev->struct_mutex);
++#if defined(CONFIG_FB_SIS)
++ {
++ drm_sman_mm_t sman_mm;
++ sman_mm.private = (void *)0xFFFFFFFF;
++ sman_mm.allocate = sis_sman_mm_allocate;
++ sman_mm.free = sis_sman_mm_free;
++ sman_mm.destroy = sis_sman_mm_destroy;
++ sman_mm.offset = sis_sman_mm_offset;
++ ret =
++ drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
+ }
++#else
++ ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
++ fb.size >> SIS_MM_ALIGN_SHIFT);
++#endif
+
+- if (dev_priv->FBHeap != NULL)
+- return DRM_ERR(EINVAL);
++ if (ret) {
++ DRM_ERROR("VRAM memory manager initialisation error\n");
++ mutex_unlock(&dev->struct_mutex);
++ return ret;
++ }
+
+- dev_priv->FBHeap = mmInit(fb.offset, fb.size);
++ dev_priv->vram_initialized = 1;
++ dev_priv->vram_offset = fb.offset;
+
++ mutex_unlock(&dev->struct_mutex);
+ DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+
+ return 0;
+ }
+
+-static int sis_fb_alloc(DRM_IOCTL_ARGS)
++static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
++ unsigned long data, int pool)
+ {
+- DRM_DEVICE;
+ drm_sis_private_t *dev_priv = dev->dev_private;
+- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
+- drm_sis_mem_t fb;
+- PMemBlock block;
++ drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
++ drm_sis_mem_t mem;
+ int retval = 0;
++ drm_memblock_item_t *item;
++
++ DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
+
+- if (dev_priv == NULL || dev_priv->FBHeap == NULL)
++ mutex_lock(&dev->struct_mutex);
++
++ if (0 == ((pool == 0) ? dev_priv->vram_initialized :
++ dev_priv->agp_initialized)) {
++ DRM_ERROR
++ ("Attempt to allocate from uninitialized memory manager.\n");
+ return DRM_ERR(EINVAL);
++ }
+
+- DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
+-
+- block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
+- if (block) {
+- /* TODO */
+- fb.offset = block->ofs;
+- fb.free = (unsigned long)block;
+- if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
+- DRM_DEBUG("adding to allocation set fails\n");
+- mmFreeMem((PMemBlock) fb.free);
+- retval = DRM_ERR(EINVAL);
+- }
++ mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
++ item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
++ (unsigned long)priv);
++
++ mutex_unlock(&dev->struct_mutex);
++ if (item) {
++ mem.offset = ((pool == 0) ?
++ dev_priv->vram_offset : dev_priv->agp_offset) +
++ (item->mm->
++ offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
++ mem.free = item->user_hash.key;
++ mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
+ } else {
+- fb.offset = 0;
+- fb.size = 0;
+- fb.free = 0;
++ mem.offset = 0;
++ mem.size = 0;
++ mem.free = 0;
++ retval = DRM_ERR(ENOMEM);
+ }
+
+- DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
++ DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
+
+- DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
++ DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
++ mem.offset);
+
+ return retval;
+ }
+
+-static int sis_fb_free(DRM_IOCTL_ARGS)
++static int sis_drm_free(DRM_IOCTL_ARGS)
+ {
+ DRM_DEVICE;
+ drm_sis_private_t *dev_priv = dev->dev_private;
+- drm_sis_mem_t fb;
++ drm_sis_mem_t mem;
++ int ret;
+
+- if (dev_priv == NULL || dev_priv->FBHeap == NULL)
+- return DRM_ERR(EINVAL);
++ DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
++ sizeof(mem));
+
+- DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
++ mutex_lock(&dev->struct_mutex);
++ ret = drm_sman_free_key(&dev_priv->sman, mem.free);
++ mutex_unlock(&dev->struct_mutex);
++ DRM_DEBUG("free = 0x%lx\n", mem.free);
+
+- if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free))
+- return DRM_ERR(EINVAL);
+-
+- if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
+- return DRM_ERR(EINVAL);
+- mmFreeMem((PMemBlock) fb.free);
+-
+- DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
+-
+- return 0;
++ return ret;
+ }
+
+-#endif
+-
+-/* agp memory management */
++static int sis_fb_alloc(DRM_IOCTL_ARGS)
++{
++ DRM_DEVICE;
++ return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
++}
+
+ static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
+ {
+ DRM_DEVICE;
+ drm_sis_private_t *dev_priv = dev->dev_private;
+ drm_sis_agp_t agp;
+-
+- if (dev_priv == NULL) {
+- dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
+- DRM_MEM_DRIVER);
+- dev_priv = dev->dev_private;
+- if (dev_priv == NULL)
+- return ENOMEM;
+- }
+-
+- if (dev_priv->AGPHeap != NULL)
+- return DRM_ERR(EINVAL);
++ int ret;
++ dev_priv = dev->dev_private;
+
+ DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
+ sizeof(agp));
++ mutex_lock(&dev->struct_mutex);
++ ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
++ agp.size >> SIS_MM_ALIGN_SHIFT);
++
++ if (ret) {
++ DRM_ERROR("AGP memory manager initialisation error\n");
++ mutex_unlock(&dev->struct_mutex);
++ return ret;
++ }
+
+- dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
++ dev_priv->agp_initialized = 1;
++ dev_priv->agp_offset = agp.offset;
++ mutex_unlock(&dev->struct_mutex);
+
+ DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+-
+ return 0;
+ }
+
+ static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
+ {
+ DRM_DEVICE;
+- drm_sis_private_t *dev_priv = dev->dev_private;
+- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
+- drm_sis_mem_t agp;
+- PMemBlock block;
+- int retval = 0;
+
+- if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
+- return DRM_ERR(EINVAL);
++ return sis_drm_alloc(dev, priv, data, AGP_TYPE);
++}
+
+- DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
+-
+- block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
+- if (block) {
+- /* TODO */
+- agp.offset = block->ofs;
+- agp.free = (unsigned long)block;
+- if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
+- DRM_DEBUG("adding to allocation set fails\n");
+- mmFreeMem((PMemBlock) agp.free);
+- retval = -1;
++static drm_local_map_t *sis_reg_init(drm_device_t *dev)
++{
++ drm_map_list_t *entry;
++ drm_local_map_t *map;
++
++ list_for_each_entry(entry, &dev->maplist->head, head) {
++ map = entry->map;
++ if (!map)
++ continue;
++ if (map->type == _DRM_REGISTERS) {
++ return map;
+ }
+- } else {
+- agp.offset = 0;
+- agp.size = 0;
+- agp.free = 0;
+ }
+-
+- DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
+-
+- DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
+-
+- return retval;
++ return NULL;
+ }
+
+-static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
++int sis_idle(drm_device_t *dev)
+ {
+- DRM_DEVICE;
+ drm_sis_private_t *dev_priv = dev->dev_private;
+- drm_sis_mem_t agp;
+-
+- if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
+- return DRM_ERR(EINVAL);
++ uint32_t idle_reg;
++ unsigned long end;
++ int i;
+
+- DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
+- sizeof(agp));
++ if (dev_priv->idle_fault)
++ return 0;
+
+- if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
+- return DRM_ERR(EINVAL);
++ if (dev_priv->mmio == NULL) {
++ dev_priv->mmio = sis_reg_init(dev);
++ if (dev_priv->mmio == NULL) {
++ DRM_ERROR("Could not find register map.\n");
++ return 0;
++ }
++ }
++
++ /*
++ * Implement a device switch here if needed
++ */
++
++ if (dev_priv->chipset != SIS_CHIP_315)
++ return 0;
++
++ /*
++ * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
++ * because its polling frequency is too low.
++ */
++
++ end = jiffies + (DRM_HZ * 3);
++
++ for (i=0; i<4; ++i) {
++ do {
++ idle_reg = SIS_READ(0x85cc);
++ } while ( !time_after_eq(jiffies, end) &&
++ ((idle_reg & 0x80000000) != 0x80000000));
++ }
+
+- mmFreeMem((PMemBlock) agp.free);
+- if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
+- return DRM_ERR(EINVAL);
++ if (time_after_eq(jiffies, end)) {
++ DRM_ERROR("Graphics engine idle timeout. "
++ "Disabling idle check\n");
++ dev_priv->idle_fault = 1;
++ }
+
+- DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
++ /*
++ * The caller never sees an error code. It gets trapped
++ * in libdrm.
++ */
+
+ return 0;
+ }
+
+-int sis_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;
+- }
++void sis_lastclose(struct drm_device *dev)
++{
++ drm_sis_private_t *dev_priv = dev->dev_private;
+
+- 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] = setInit();
+- global_ppriv[i].sets[1] = 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;
+- }
+- }
++ if (!dev_priv)
++ return;
+
+- return 1;
++ mutex_lock(&dev->struct_mutex);
++ drm_sman_cleanup(&dev_priv->sman);
++ dev_priv->vram_initialized = 0;
++ dev_priv->agp_initialized = 0;
++ dev_priv->mmio = NULL;
++ mutex_unlock(&dev->struct_mutex);
+ }
+
+-int sis_final_context(struct drm_device *dev, int context)
++void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+ {
+- int i;
++ drm_sis_private_t *dev_priv = dev->dev_private;
++ drm_file_t *priv = filp->private_data;
+
+- for (i = 0; i < MAX_CONTEXT; i++) {
+- if (global_ppriv[i].used &&
+- (global_ppriv[i].context == context))
+- break;
++ mutex_lock(&dev->struct_mutex);
++ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
++ mutex_unlock(&dev->struct_mutex);
++ return;
+ }
+
+- 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 = setFirst(set, &item);
+- while (retval) {
+- DRM_DEBUG("free video memory 0x%lx\n", item);
+-#if defined(__linux__) && defined(CONFIG_FB_SIS)
+- sis_free(item);
+-#else
+- mmFreeMem((PMemBlock) item);
+-#endif
+- retval = setNext(set, &item);
+- }
+- setDestroy(set);
+-
+- /* AGP Memory */
+- set = global_ppriv[i].sets[1];
+- retval = setFirst(set, &item);
+- while (retval) {
+- DRM_DEBUG("free agp memory 0x%lx\n", item);
+- mmFreeMem((PMemBlock) item);
+- retval = setNext(set, &item);
+- }
+- setDestroy(set);
+-
+- global_ppriv[i].used = 0;
++ if (dev->driver->dma_quiescent) {
++ dev->driver->dma_quiescent(dev);
+ }
+
+- return 1;
++ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
++ mutex_unlock(&dev->struct_mutex);
++ return;
+ }
+
+ drm_ioctl_desc_t sis_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
+- [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, DRM_AUTH},
+- [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
++ [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
++ [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
++ {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
+- [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, DRM_AUTH},
+- [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}
++ [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
++ [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
++ {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
+ };
+
+ int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
+diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
+index 78a81a4..60c1695 100644
+--- a/drivers/char/drm/via_dmablit.c
++++ b/drivers/char/drm/via_dmablit.c
+@@ -41,9 +41,9 @@
+
+ #include <linux/pagemap.h>
+
+-#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
+-#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
+-#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
++#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
++#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
++#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
+
+ typedef struct _drm_via_descriptor {
+ uint32_t mem_addr;
+@@ -121,19 +121,19 @@ via_map_blit_for_device(struct pci_dev *
+
+ while (line_len > 0) {
+
+- remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
++ remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
+ line_len -= remaining_len;
+
+ if (mode == 1) {
+- desc_ptr->mem_addr =
++ desc_ptr->mem_addr =
+ dma_map_page(&pdev->dev,
+ vsg->pages[VIA_PFN(cur_mem) -
+ VIA_PFN(first_addr)],
+ VIA_PGOFF(cur_mem), remaining_len,
+ vsg->direction);
+- desc_ptr->dev_addr = cur_fb;
++ desc_ptr->dev_addr = cur_fb;
+
+- desc_ptr->size = remaining_len;
++ desc_ptr->size = remaining_len;
+ desc_ptr->next = (uint32_t) next;
+ next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr),
+ DMA_TO_DEVICE);
+@@ -162,7 +162,7 @@ via_map_blit_for_device(struct pci_dev *
+
+ /*
+ * Function that frees up all resources for a blit. It is usable even if the
+- * blit info has only be partially built as long as the status enum is consistent
++ * blit info has only been partially built as long as the status enum is consistent
+ * with the actual status of the used resources.
+ */
+
+@@ -238,8 +238,11 @@ via_lock_all_dma_pages(drm_via_sg_info_t
+ return DRM_ERR(ENOMEM);
+ memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
+ down_read(¤t->mm->mmap_sem);
+- ret = get_user_pages(current, current->mm, (unsigned long) xfer->mem_addr,
+- vsg->num_pages, vsg->direction, 0, vsg->pages, NULL);
++ ret = get_user_pages(current, current->mm,
++ (unsigned long)xfer->mem_addr,
++ vsg->num_pages,
++ (vsg->direction == DMA_FROM_DEVICE),
++ 0, vsg->pages, NULL);
+
+ up_read(¤t->mm->mmap_sem);
+ if (ret != vsg->num_pages) {
+@@ -475,9 +478,15 @@ via_dmablit_timer(unsigned long data)
+ if (!timer_pending(&blitq->poll_timer)) {
+ blitq->poll_timer.expires = jiffies+1;
+ add_timer(&blitq->poll_timer);
+- }
+- via_dmablit_handler(dev, engine, 0);
+
++ /*
++ * Rerun handler to delete timer if engines are off, and
++ * to shorten abort latency. This is a little nasty.
++ */
++
++ via_dmablit_handler(dev, engine, 0);
++
++ }
+ }
+
+
+@@ -597,15 +606,27 @@ via_build_sg_info(drm_device_t *dev, drm
+ * (Not a big limitation anyway.)
+ */
+
+- if (((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) ||
+- (xfer->mem_stride > 2048*4)) {
++ if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
+ DRM_ERROR("Too large system memory stride. Stride: %d, "
+ "Length: %d\n", xfer->mem_stride, xfer->line_length);
+ return DRM_ERR(EINVAL);
+ }
+
+- if (xfer->num_lines > 2048) {
+- DRM_ERROR("Too many PCI DMA bitblt lines.\n");
++ if ((xfer->mem_stride == xfer->line_length) &&
++ (xfer->fb_stride == xfer->line_length)) {
++ xfer->mem_stride *= xfer->num_lines;
++ xfer->line_length = xfer->mem_stride;
++ xfer->fb_stride = xfer->mem_stride;
++ xfer->num_lines = 1;
++ }
++
++ /*
++ * Don't lock an arbitrary large number of pages, since that causes a
++ * DOS security hole.
++ */
++
++ if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
++ DRM_ERROR("Too large PCI DMA bitblt.\n");
+ return DRM_ERR(EINVAL);
+ }
+
+@@ -628,16 +649,17 @@ via_build_sg_info(drm_device_t *dev, drm
+
+ #ifdef VIA_BUGFREE
+ if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
+- ((xfer->mem_stride & 3) != (xfer->fb_stride & 3))) {
++ ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
+ DRM_ERROR("Invalid DRM bitblt alignment.\n");
+- return DRM_ERR(EINVAL);
++ return DRM_ERR(EINVAL);
+ }
+ #else
+ if ((((unsigned long)xfer->mem_addr & 15) ||
+- ((unsigned long)xfer->fb_addr & 3)) || (xfer->mem_stride & 15) ||
+- (xfer->fb_stride & 3)) {
++ ((unsigned long)xfer->fb_addr & 3)) ||
++ ((xfer->num_lines > 1) &&
++ ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
+ DRM_ERROR("Invalid DRM bitblt alignment.\n");
+- return DRM_ERR(EINVAL);
++ return DRM_ERR(EINVAL);
+ }
+ #endif
+
+@@ -715,7 +737,7 @@ via_dmablit(drm_device_t *dev, drm_via_d
+ drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
+ drm_via_sg_info_t *vsg;
+ drm_via_blitq_t *blitq;
+- int ret;
++ int ret;
+ int engine;
+ unsigned long irqsave;
+
+@@ -756,7 +778,7 @@ via_dmablit(drm_device_t *dev, drm_via_d
+
+ /*
+ * Sync on a previously submitted blit. Note that the X server use signals extensively, and
+- * that there is a very big proability that this IOCTL will be interrupted by a signal. In that
++ * that there is a very big probability that this IOCTL will be interrupted by a signal. In that
+ * case it returns with -EAGAIN for the signal to be delivered.
+ * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
+ */
+diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h
+index 47f0b5b..e4ee97d 100644
+--- a/drivers/char/drm/via_drm.h
++++ b/drivers/char/drm/via_drm.h
+@@ -250,6 +250,12 @@ typedef struct drm_via_blitsync {
+ unsigned engine;
+ } drm_via_blitsync_t;
+
++/* - * Below,"flags" is currently unused but will be used for possible future
++ * extensions like kernel space bounce buffers for bad alignments and
++ * blit engine busy-wait polling for better latency in the absence of
++ * interrupts.
++ */
++
+ typedef struct drm_via_dmablit {
+ uint32_t num_lines;
+ uint32_t line_length;
+@@ -260,7 +266,7 @@ typedef struct drm_via_dmablit {
+ unsigned char *mem_addr;
+ uint32_t mem_stride;
+
+- int bounce_buffer;
++ uint32_t flags;
+ int to_fb;
+
+ drm_via_blitsync_t sync;
+diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
+index b3d364d..bb9dde8 100644
+--- a/drivers/char/drm/via_drv.c
++++ b/drivers/char/drm/via_drv.c
+@@ -43,7 +43,6 @@ static struct drm_driver driver = {
+ DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+ .load = via_driver_load,
+ .unload = via_driver_unload,
+- .context_ctor = via_init_context,
+ .context_dtor = via_final_context,
+ .vblank_wait = via_driver_vblank_wait,
+ .irq_preinstall = via_driver_irq_preinstall,
+@@ -53,6 +52,8 @@ static struct drm_driver driver = {
+ .dma_quiescent = via_driver_dma_quiescent,
+ .dri_library_name = dri_library_name,
+ .reclaim_buffers = drm_core_reclaim_buffers,
++ .reclaim_buffers_locked = via_reclaim_buffers_locked,
++ .lastclose = via_lastclose,
+ .get_map_ofs = drm_core_get_map_ofs,
+ .get_reg_ofs = drm_core_get_reg_ofs,
+ .ioctls = via_ioctls,
+diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
+index 52bcc7b..d21b5b7 100644
+--- a/drivers/char/drm/via_drv.h
++++ b/drivers/char/drm/via_drv.h
+@@ -24,15 +24,16 @@
+ #ifndef _VIA_DRV_H_
+ #define _VIA_DRV_H_
+
++#include "drm_sman.h"
+ #define DRIVER_AUTHOR "Various"
+
+ #define DRIVER_NAME "via"
+ #define DRIVER_DESC "VIA Unichrome / Pro"
+-#define DRIVER_DATE "20051116"
++#define DRIVER_DATE "20060529"
+
+ #define DRIVER_MAJOR 2
+-#define DRIVER_MINOR 7
+-#define DRIVER_PATCHLEVEL 4
++#define DRIVER_MINOR 10
++#define DRIVER_PATCHLEVEL 0
+
+ #include "via_verifier.h"
+
+@@ -85,6 +86,12 @@ typedef struct drm_via_private {
+ uint32_t irq_enable_mask;
+ uint32_t irq_pending_mask;
+ int *irq_map;
++ unsigned int idle_fault;
++ drm_sman_t sman;
++ int vram_initialized;
++ int agp_initialized;
++ unsigned long vram_offset;
++ unsigned long agp_offset;
+ drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
+ } drm_via_private_t;
+
+@@ -135,6 +142,9 @@ extern void via_init_futex(drm_via_priva
+ extern void via_cleanup_futex(drm_via_private_t * dev_priv);
+ extern void via_release_futex(drm_via_private_t * dev_priv, int context);
+
++extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
++extern void via_lastclose(drm_device_t *dev);
++
+ extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
+ extern void via_init_dmablit(drm_device_t *dev);
+
+diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c
+deleted file mode 100644
+index 9429736..0000000
+--- a/drivers/char/drm/via_ds.c
++++ /dev/null
+@@ -1,273 +0,0 @@
+-/*
+- * 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 "drmP.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 NULL;
+-
+- 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 NULL;
+-}
+-
+-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
+deleted file mode 100644
+index d2bb9f3..0000000
+--- a/drivers/char/drm/via_ds.h
++++ /dev/null
+@@ -1,104 +0,0 @@
+-/*
+- * 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;
+- unsigned int free:1;
+- unsigned 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_map.c b/drivers/char/drm/via_map.c
+index c6a08e9..782011e 100644
+--- a/drivers/char/drm/via_map.c
++++ b/drivers/char/drm/via_map.c
+@@ -98,6 +98,7 @@ int via_map_init(DRM_IOCTL_ARGS)
+ int via_driver_load(drm_device_t *dev, unsigned long chipset)
+ {
+ drm_via_private_t *dev_priv;
++ int ret = 0;
+
+ dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+ if (dev_priv == NULL)
+@@ -108,13 +109,19 @@ int via_driver_load(drm_device_t *dev, u
+ if (chipset == VIA_PRO_GROUP_A)
+ dev_priv->pro_group_a = 1;
+
+- return 0;
++ ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
++ if (ret) {
++ drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
++ }
++ return ret;
+ }
+
+ int via_driver_unload(drm_device_t *dev)
+ {
+ drm_via_private_t *dev_priv = dev->dev_private;
+
++ drm_sman_takedown(&dev_priv->sman);
++
+ drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+
+ return 0;
+diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
+index 33e0cb1..2fcf057 100644
+--- a/drivers/char/drm/via_mm.c
++++ b/drivers/char/drm/via_mm.c
+@@ -1,6 +1,6 @@
+ /*
+- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
++ * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
++ * 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"),
+@@ -16,347 +16,194 @@
+ * 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,
++ * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR 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: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
++ */
++
+ #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];
++#include "drm_sman.h"
+
+-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 long 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 long 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;
++#define VIA_MM_ALIGN_SHIFT 4
++#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
+
+ int via_agp_init(DRM_IOCTL_ARGS)
+ {
++ DRM_DEVICE;
+ drm_via_agp_t agp;
++ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
++ int ret;
+
+ DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
+ sizeof(agp));
++ mutex_lock(&dev->struct_mutex);
++ ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
++ agp.size >> VIA_MM_ALIGN_SHIFT);
++
++ if (ret) {
++ DRM_ERROR("AGP memory manager initialisation error\n");
++ mutex_unlock(&dev->struct_mutex);
++ return ret;
++ }
+
+- AgpHeap = via_mmInit(agp.offset, agp.size);
+-
+- DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset,
+- (unsigned long)agp.size);
++ dev_priv->agp_initialized = 1;
++ dev_priv->agp_offset = agp.offset;
++ mutex_unlock(&dev->struct_mutex);
+
++ DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+ return 0;
+ }
+
+-/* fb memory management */
+-static memHeap_t *FBHeap = NULL;
+-
+ int via_fb_init(DRM_IOCTL_ARGS)
+ {
++ DRM_DEVICE;
+ drm_via_fb_t fb;
++ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
++ int ret;
+
+ DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
+
+- FBHeap = via_mmInit(fb.offset, fb.size);
++ mutex_lock(&dev->struct_mutex);
++ ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
++ fb.size >> VIA_MM_ALIGN_SHIFT);
+
+- DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset,
+- (unsigned long)fb.size);
++ if (ret) {
++ DRM_ERROR("VRAM memory manager initialisation error\n");
++ mutex_unlock(&dev->struct_mutex);
++ return ret;
++ }
+
+- return 0;
+-}
++ dev_priv->vram_initialized = 1;
++ dev_priv->vram_offset = fb.offset;
+
+-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;
+- }
+- }
++ mutex_unlock(&dev->struct_mutex);
++ DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
++
++ 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;
+ }
+
++void via_lastclose(struct drm_device *dev)
++{
++ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
++
++ if (!dev_priv)
++ return;
++
++ mutex_lock(&dev->struct_mutex);
++ drm_sman_cleanup(&dev_priv->sman);
++ dev_priv->vram_initialized = 0;
++ dev_priv->agp_initialized = 0;
++ mutex_unlock(&dev->struct_mutex);
++}
++
+ int via_mem_alloc(DRM_IOCTL_ARGS)
+ {
++ DRM_DEVICE;
++
+ drm_via_mem_t mem;
++ int retval = 0;
++ drm_memblock_item_t *item;
++ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
++ unsigned long tmpSize;
+
+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
+ sizeof(mem));
+
+- switch (mem.type) {
+- case VIA_MEM_VIDEO:
+- if (via_fb_alloc(&mem) < 0)
+- return -EFAULT;
+- DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
+- sizeof(mem));
+- return 0;
+- case VIA_MEM_AGP:
+- if (via_agp_alloc(&mem) < 0)
+- return -EFAULT;
+- DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
+- sizeof(mem));
+- return 0;
++ if (mem.type > VIA_MEM_AGP) {
++ DRM_ERROR("Unknown memory type allocation\n");
++ return DRM_ERR(EINVAL);
+ }
+-
+- 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, VIA_MEM_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;
++ mutex_lock(&dev->struct_mutex);
++ if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
++ dev_priv->agp_initialized)) {
++ DRM_ERROR
++ ("Attempt to allocate from uninitialized memory manager.\n");
++ mutex_unlock(&dev->struct_mutex);
++ return DRM_ERR(EINVAL);
+ }
+
+- 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, VIA_MEM_AGP, agp.free)) {
+- DRM_DEBUG("adding to allocation set fails\n");
+- via_mmFreeMem((PMemBlock) agp.free);
+- retval = -1;
+- }
++ tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
++ item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
++ (unsigned long)priv);
++ mutex_unlock(&dev->struct_mutex);
++ if (item) {
++ mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
++ dev_priv->vram_offset : dev_priv->agp_offset) +
++ (item->mm->
++ offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
++ mem.index = item->user_hash.key;
+ } else {
+- agp.offset = 0;
+- agp.size = 0;
+- agp.free = 0;
++ mem.offset = 0;
++ mem.size = 0;
++ mem.index = 0;
++ DRM_DEBUG("Video memory allocation failed\n");
++ retval = DRM_ERR(ENOMEM);
+ }
++ DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
+
+- 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_DEVICE;
++ drm_via_private_t *dev_priv = dev->dev_private;
+ drm_via_mem_t mem;
++ int ret;
+
+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
+ sizeof(mem));
+
+- switch (mem.type) {
++ mutex_lock(&dev->struct_mutex);
++ ret = drm_sman_free_key(&dev_priv->sman, mem.index);
++ mutex_unlock(&dev->struct_mutex);
++ DRM_DEBUG("free = 0x%lx\n", mem.index);
+
+- case VIA_MEM_VIDEO:
+- if (via_fb_free(&mem) == 0)
+- return 0;
+- break;
+- case VIA_MEM_AGP:
+- if (via_agp_free(&mem) == 0)
+- return 0;
+- break;
+- }
+-
+- return -EFAULT;
++ return ret;
+ }
+
+-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, VIA_MEM_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)
++void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+ {
+- drm_via_mm_t agp;
+-
+- int retval = 0;
++ drm_via_private_t *dev_priv = dev->dev_private;
++ drm_file_t *priv = filp->private_data;
+
+- agp.free = mem->index;
+- agp.context = mem->context;
+-
+- if (!agp.free)
+- return -1;
+-
+- via_mmFreeMem((PMemBlock) agp.free);
+-
+- if (!del_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
+- retval = -1;
++ mutex_lock(&dev->struct_mutex);
++ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
++ mutex_unlock(&dev->struct_mutex);
++ return;
+ }
+
+- DRM_DEBUG("free agp, free = %ld\n", agp.free);
++ if (dev->driver->dma_quiescent) {
++ dev->driver->dma_quiescent(dev);
++ }
+
+- return retval;
++ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
++ mutex_unlock(&dev->struct_mutex);
++ return;
+ }
+diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
+index 21c8229..6d58b03 100644
+--- a/drivers/char/ds1286.c
++++ b/drivers/char/ds1286.c
+@@ -104,7 +104,7 @@ static int ds1286_ioctl(struct inode *in
+ switch (cmd) {
+ case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
+ {
+- unsigned int flags;
++ unsigned long flags;
+ unsigned char val;
+
+ if (!capable(CAP_SYS_TIME))
+@@ -120,7 +120,7 @@ static int ds1286_ioctl(struct inode *in
+ }
+ case RTC_AIE_ON: /* Allow alarm interrupts. */
+ {
+- unsigned int flags;
++ unsigned long flags;
+ unsigned char val;
+
+ if (!capable(CAP_SYS_TIME))
+@@ -136,7 +136,7 @@ static int ds1286_ioctl(struct inode *in
+ }
+ case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */
+ {
+- unsigned int flags;
++ unsigned long flags;
+ unsigned char val;
+
+ if (!capable(CAP_SYS_TIME))
+@@ -152,7 +152,7 @@ static int ds1286_ioctl(struct inode *in
+ }
+ case RTC_WIE_ON: /* Allow watchdog interrupts. */
+ {
+- unsigned int flags;
++ unsigned long flags;
+ unsigned char val;
+
+ if (!capable(CAP_SYS_TIME))
+@@ -434,7 +434,7 @@ static inline unsigned char ds1286_is_up
+ static void ds1286_get_time(struct rtc_time *rtc_tm)
+ {
+ unsigned char save_control;
+- unsigned int flags;
++ unsigned long flags;
+ unsigned long uip_watchdog = jiffies;
+
+ /*
+@@ -494,7 +494,8 @@ static int ds1286_set_time(struct rtc_ti
+ {
+ unsigned char mon, day, hrs, min, sec, leap_yr;
+ unsigned char save_control;
+- unsigned int yrs, flags;
++ unsigned int yrs;
++ unsigned long flags;
+
+
+ yrs = rtc_tm->tm_year + 1900;
+@@ -552,7 +553,7 @@ static int ds1286_set_time(struct rtc_ti
+ static void ds1286_get_alm_time(struct rtc_time *alm_tm)
+ {
+ unsigned char cmd;
+- unsigned int flags;
++ unsigned long flags;
+
+ /*
+ * Only the values that we read from the RTC are set. That
+diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
+index abac18b..77f58ed 100644
+--- a/drivers/char/ec3104_keyb.c
++++ b/drivers/char/ec3104_keyb.c
+@@ -370,7 +370,7 @@ static void e5_receive(struct e5_struct
+ }
+ }
+
+-static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs)
++static void ec3104_keyb_interrupt(int irq, void *data)
+ {
+ struct e5_struct *k = &ec3104_keyb;
+ u8 msr, lsr;
+diff --git a/drivers/char/epca.c b/drivers/char/epca.c
+index 86d290e..706733c 100644
+--- a/drivers/char/epca.c
++++ b/drivers/char/epca.c
+@@ -1113,11 +1113,8 @@ static void __exit epca_module_exit(void
+ ch = card_ptr[crd];
+ for (count = 0; count < bd->numports; count++, ch++)
+ { /* Begin for each port */
+- if (ch) {
+- if (ch->tty)
+- tty_hangup(ch->tty);
+- kfree(ch->tmp_buf);
+- }
++ if (ch && ch->tty)
++ tty_hangup(ch->tty);
+ } /* End for each port */
+ } /* End for each card */
+ pci_unregister_driver (&epca_driver);
+@@ -1125,7 +1122,7 @@ static void __exit epca_module_exit(void
+
+ module_exit(epca_module_exit);
+
+-static struct tty_operations pc_ops = {
++static const struct tty_operations pc_ops = {
+ .open = pc_open,
+ .close = pc_close,
+ .write = pc_write,
+@@ -1160,6 +1157,7 @@ static int __init pc_init(void)
+ int crd;
+ struct board_info *bd;
+ unsigned char board_id = 0;
++ int err = -ENOMEM;
+
+ int pci_boards_found, pci_count;
+
+@@ -1167,13 +1165,11 @@ static int __init pc_init(void)
+
+ pc_driver = alloc_tty_driver(MAX_ALLOC);
+ if (!pc_driver)
+- return -ENOMEM;
++ goto out1;
+
+ pc_info = alloc_tty_driver(MAX_ALLOC);
+- if (!pc_info) {
+- put_tty_driver(pc_driver);
+- return -ENOMEM;
+- }
++ if (!pc_info)
++ goto out2;
+
+ /* -----------------------------------------------------------------------
+ If epca_setup has not been ran by LILO set num_cards to defaults; copy
+@@ -1373,11 +1369,17 @@ static int __init pc_init(void)
+
+ } /* End for each card */
+
+- if (tty_register_driver(pc_driver))
+- panic("Couldn't register Digi PC/ driver");
++ err = tty_register_driver(pc_driver);
++ if (err) {
++ printk(KERN_ERR "Couldn't register Digi PC/ driver");
++ goto out3;
++ }
+
+- if (tty_register_driver(pc_info))
+- panic("Couldn't register Digi PC/ info ");
++ err = tty_register_driver(pc_info);
++ if (err) {
++ printk(KERN_ERR "Couldn't register Digi PC/ info ");
++ goto out4;
++ }
+
+ /* -------------------------------------------------------------------
+ Start up the poller to check for events on all enabled boards
+@@ -1388,6 +1390,15 @@ static int __init pc_init(void)
+ mod_timer(&epca_timer, jiffies + HZ/25);
+ return 0;
+
++out4:
++ tty_unregister_driver(pc_driver);
++out3:
++ put_tty_driver(pc_info);
++out2:
++ put_tty_driver(pc_driver);
++out1:
++ return err;
++
+ } /* End pc_init */
+
+ /* ------------------ Begin post_fep_init ---------------------- */
+@@ -1635,16 +1646,6 @@ static void post_fep_init(unsigned int c
+ init_waitqueue_head(&ch->close_wait);
+
+ spin_unlock_irqrestore(&epca_lock, flags);
+-
+- ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
+- if (!ch->tmp_buf) {
+- printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
+- release_region((int)bd->port, 4);
+- while(i-- > 0)
+- kfree((ch--)->tmp_buf);
+- return;
+- } else
+- memset((void *)ch->tmp_buf,0,ch->txbufsize);
+ } /* End for each port */
+
+ printk(KERN_INFO
+diff --git a/drivers/char/epca.h b/drivers/char/epca.h
+index 456d6c8..a297238 100644
+--- a/drivers/char/epca.h
++++ b/drivers/char/epca.h
+@@ -130,7 +130,6 @@ struct channel
+ unsigned long c_oflag;
+ unsigned char __iomem *txptr;
+ unsigned char __iomem *rxptr;
+- unsigned char *tmp_buf;
+ struct board_info *board;
+ struct board_chan __iomem *brdchan;
+ struct digi_struct digiext;
+diff --git a/drivers/char/esp.c b/drivers/char/esp.c
+index afcd83d..15a4ea8 100644
+--- a/drivers/char/esp.c
++++ b/drivers/char/esp.c
+@@ -615,8 +615,7 @@ static inline void check_modem_status(st
+ /*
+ * This is the serial driver's interrupt routine
+ */
+-static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
+ {
+ struct esp_struct * info;
+ unsigned err_status;
+@@ -2376,7 +2375,7 @@ static inline int autoconfig(struct esp_
+ return (port_detected);
+ }
+
+-static struct tty_operations esp_ops = {
++static const struct tty_operations esp_ops = {
+ .open = esp_open,
+ .close = rs_close,
+ .write = rs_write,
+diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
+index 65c9d2e..bbcf918 100644
+--- a/drivers/char/ftape/lowlevel/fdc-io.c
++++ b/drivers/char/ftape/lowlevel/fdc-io.c
+@@ -26,7 +26,6 @@
+ * Linux.
+ */
+
+-#include <linux/config.h> /* for CONFIG_FT_* */
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/ioport.h>
+@@ -1244,7 +1243,7 @@ static int fdc_config(void)
+ TRACE_EXIT 0;
+ }
+
+-static irqreturn_t ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ftape_interrupt(int irq, void *dev_id)
+ {
+ void (*handler) (void) = *fdc.hook;
+ int handled = 0;
+diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c
+index a61ef50..dab6346 100644
+--- a/drivers/char/ftape/zftape/zftape-rw.c
++++ b/drivers/char/ftape/zftape/zftape-rw.c
+@@ -24,7 +24,6 @@
+ * zftape.
+ */
+
+-#include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
+ #include <linux/errno.h>
+ #include <linux/mm.h>
+
+diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h
+index 14c07f0..1ceec22 100644
+--- a/drivers/char/ftape/zftape/zftape-rw.h
++++ b/drivers/char/ftape/zftape/zftape-rw.h
+@@ -28,7 +28,6 @@
+ *
+ */
+
+-#include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
+ #include "../zftape/zftape-buffers.h"
+
+ #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape)
+diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
+index 5e59c0b..87127e4 100644
+--- a/drivers/char/generic_serial.c
++++ b/drivers/char/generic_serial.c
+@@ -33,8 +33,6 @@
+
+ #define DEBUG
+
+-static char * tmp_buf;
+-
+ static int gs_debug;
+
+ #ifdef DEBUG
+@@ -205,7 +203,7 @@ int gs_write(struct tty_struct * tty,
+ if (!tty) return -EIO;
+
+ port = tty->driver_data;
+- if (!port || !port->xmit_buf || !tmp_buf)
++ if (!port || !port->xmit_buf)
+ return -EIO;
+
+ local_save_flags(flags);
+@@ -746,11 +744,9 @@ void gs_set_termios (struct tty_struct *
+ gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
+ }
+
+-#if 0
+ /* This is an optimization that is only allowed for dumb cards */
+ /* Smart cards require knowledge of iflags and oflags too: that
+ might change hardware cooking mode.... */
+-#endif
+ if (old_termios) {
+ if( (tiosp->c_iflag == old_termios->c_iflag)
+ && (tiosp->c_oflag == old_termios->c_oflag)
+@@ -774,14 +770,7 @@ void gs_set_termios (struct tty_struct *
+ if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
+ }
+
+- baudrate = tiosp->c_cflag & CBAUD;
+- if (baudrate & CBAUDEX) {
+- baudrate &= ~CBAUDEX;
+- if ((baudrate < 1) || (baudrate > 4))
+- tiosp->c_cflag &= ~CBAUDEX;
+- else
+- baudrate += 15;
+- }
++ baudrate = tty_get_baud_rate(tty);
+
+ baudrate = gs_baudrates[baudrate];
+ if ((tiosp->c_cflag & CBAUD) == B38400) {
+@@ -846,24 +835,9 @@ void gs_set_termios (struct tty_struct *
+ int gs_init_port(struct gs_port *port)
+ {
+ unsigned long flags;
+- unsigned long page;
+
+ func_enter ();
+
+- if (!tmp_buf) {
+- page = get_zeroed_page(GFP_KERNEL);
+- spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */
+- if (tmp_buf)
+- free_page(page);
+- else
+- tmp_buf = (unsigned char *) page;
+- spin_unlock_irqrestore (&port->driver_lock, flags);
+- if (!tmp_buf) {
+- func_exit ();
+- return -ENOMEM;
+- }
+- }
+-
+ if (port->flags & ASYNC_INITIALIZED) {
+ func_exit ();
+ return 0;
+diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
+index d69f2ad..1aa93a7 100644
+--- a/drivers/char/hangcheck-timer.c
++++ b/drivers/char/hangcheck-timer.c
+@@ -159,7 +159,7 @@ static void hangcheck_fire(unsigned long
+ if (hangcheck_dump_tasks) {
+ printk(KERN_CRIT "Hangcheck: Task state:\n");
+ #ifdef CONFIG_MAGIC_SYSRQ
+- handle_sysrq('t', NULL, NULL);
++ handle_sysrq('t', NULL);
+ #endif /* CONFIG_MAGIC_SYSRQ */
+ }
+ if (hangcheck_reboot) {
+diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
+index 8afba33..091a11c 100644
+--- a/drivers/char/hpet.c
++++ b/drivers/char/hpet.c
+@@ -116,7 +116,7 @@ static inline void writeq(unsigned long
+ }
+ #endif
+
+-static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t hpet_interrupt(int irq, void *data)
+ {
+ struct hpet_dev *devp;
+ unsigned long isr;
+@@ -868,8 +868,8 @@ int hpet_alloc(struct hpet_data *hdp)
+ do_div(temp, period);
+ hpetp->hp_tick_freq = temp; /* ticks per second */
+
+- printk(KERN_INFO "hpet%d: at MMIO 0x%lx (virtual 0x%p), IRQ%s",
+- hpetp->hp_which, hdp->hd_phys_address, hdp->hd_address,
++ printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s",
++ hpetp->hp_which, hdp->hd_phys_address,
+ hpetp->hp_ntimer > 1 ? "s" : "");
+ for (i = 0; i < hpetp->hp_ntimer; i++)
+ printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
+diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
+index 613d67f..9902ffa 100644
+--- a/drivers/char/hvc_console.c
++++ b/drivers/char/hvc_console.c
+@@ -80,7 +80,8 @@ struct hvc_struct {
+ struct tty_struct *tty;
+ unsigned int count;
+ int do_wakeup;
+- char outbuf[N_OUTBUF] __ALIGNED__;
++ char *outbuf;
++ int outbuf_size;
+ int n_outbuf;
+ uint32_t vtermno;
+ struct hv_ops *ops;
+@@ -293,7 +294,7 @@ static int hvc_poll(struct hvc_struct *h
+ * 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)
++static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
+ {
+ /* if hvc_poll request a repoll, then kick the hvcd thread */
+ if (hvc_poll(dev_instance))
+@@ -319,10 +320,8 @@ static int hvc_open(struct tty_struct *t
+ struct kobject *kobjp;
+
+ /* Auto increments kobject reference if found. */
+- if (!(hp = hvc_get_by_index(tty->index))) {
+- printk(KERN_WARNING "hvc_console: tty open failed, no vty associated with tty.\n");
++ if (!(hp = hvc_get_by_index(tty->index)))
+ return -ENODEV;
+- }
+
+ spin_lock_irqsave(&hp->lock, flags);
+ /* Check and then increment for fast path open. */
+@@ -505,7 +504,7 @@ static int hvc_write(struct tty_struct *
+ if (hp->n_outbuf > 0)
+ hvc_push(hp);
+
+- while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) {
++ while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
+ if (rsize > count)
+ rsize = count;
+ memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
+@@ -538,7 +537,7 @@ static int hvc_write_room(struct tty_str
+ if (!hp)
+ return -1;
+
+- return N_OUTBUF - hp->n_outbuf;
++ return hp->outbuf_size - hp->n_outbuf;
+ }
+
+ static int hvc_chars_in_buffer(struct tty_struct *tty)
+@@ -622,7 +621,7 @@ static int hvc_poll(struct hvc_struct *h
+ sysrq_pressed = 1;
+ continue;
+ } else if (sysrq_pressed) {
+- handle_sysrq(buf[i], NULL, tty);
++ handle_sysrq(buf[i], tty);
+ sysrq_pressed = 0;
+ continue;
+ }
+@@ -697,7 +696,7 @@ int khvcd(void *unused)
+ return 0;
+ }
+
+-static struct tty_operations hvc_ops = {
++static const struct tty_operations hvc_ops = {
+ .open = hvc_open,
+ .close = hvc_close,
+ .write = hvc_write,
+@@ -729,12 +728,13 @@ static struct kobj_type hvc_kobj_type =
+ };
+
+ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
+- struct hv_ops *ops)
++ struct hv_ops *ops, int outbuf_size)
+ {
+ struct hvc_struct *hp;
+ int i;
+
+- hp = kmalloc(sizeof(*hp), GFP_KERNEL);
++ hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
++ GFP_KERNEL);
+ if (!hp)
+ return ERR_PTR(-ENOMEM);
+
+@@ -743,6 +743,8 @@ struct hvc_struct __devinit *hvc_alloc(u
+ hp->vtermno = vtermno;
+ hp->irq = irq;
+ hp->ops = ops;
++ hp->outbuf_size = outbuf_size;
++ hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
+
+ kobject_init(&hp->kobj);
+ hp->kobj.ktype = &hvc_kobj_type;
+diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
+index 96b7401..8c59818 100644
+--- a/drivers/char/hvc_console.h
++++ b/drivers/char/hvc_console.h
+@@ -56,7 +56,7 @@ extern int hvc_instantiate(uint32_t vter
+
+ /* 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);
++ struct hv_ops *ops, int outbuf_size);
+ /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+ extern int __devexit hvc_remove(struct hvc_struct *hp);
+
+diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
+new file mode 100644
+index 0000000..f144a94
+--- /dev/null
++++ b/drivers/char/hvc_iseries.c
+@@ -0,0 +1,593 @@
++/*
++ * iSeries vio driver interface to hvc_console.c
++ *
++ * This code is based heavily on hvc_vio.c and viocons.c
++ *
++ * Copyright (C) 2006 Stephen Rothwell, IBM Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <stdarg.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/spinlock.h>
++#include <linux/console.h>
++
++#include <asm/hvconsole.h>
++#include <asm/vio.h>
++#include <asm/prom.h>
++#include <asm/firmware.h>
++#include <asm/iseries/vio.h>
++#include <asm/iseries/hv_call.h>
++#include <asm/iseries/hv_lp_config.h>
++#include <asm/iseries/hv_lp_event.h>
++
++#include "hvc_console.h"
++
++#define VTTY_PORTS 10
++
++static DEFINE_SPINLOCK(consolelock);
++static DEFINE_SPINLOCK(consoleloglock);
++
++static const char hvc_driver_name[] = "hvc_console";
++
++#define IN_BUF_SIZE 200
++
++/*
++ * Our port information.
++ */
++static struct port_info {
++ HvLpIndex lp;
++ u64 seq; /* sequence number of last HV send */
++ u64 ack; /* last ack from HV */
++ struct hvc_struct *hp;
++ int in_start;
++ int in_end;
++ unsigned char in_buf[IN_BUF_SIZE];
++} port_info[VTTY_PORTS] = {
++ [ 0 ... VTTY_PORTS - 1 ] = {
++ .lp = HvLpIndexInvalid
++ }
++};
++
++#define viochar_is_console(pi) ((pi) == &port_info[0])
++
++static struct vio_device_id hvc_driver_table[] __devinitdata = {
++ {"serial", "IBM,iSeries-vty"},
++ { "", "" }
++};
++MODULE_DEVICE_TABLE(vio, hvc_driver_table);
++
++static void hvlog(char *fmt, ...)
++{
++ int i;
++ unsigned long flags;
++ va_list args;
++ static char buf[256];
++
++ spin_lock_irqsave(&consoleloglock, flags);
++ va_start(args, fmt);
++ i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
++ va_end(args);
++ buf[i++] = '\r';
++ HvCall_writeLogBuffer(buf, i);
++ spin_unlock_irqrestore(&consoleloglock, flags);
++}
++
++/*
++ * Initialize the common fields in a charLpEvent
++ */
++static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
++{
++ struct HvLpEvent *hev = &viochar->event;
++
++ memset(viochar, 0, sizeof(struct viocharlpevent));
++
++ hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
++ HV_LP_EVENT_INT;
++ hev->xType = HvLpEvent_Type_VirtualIo;
++ hev->xSubtype = viomajorsubtype_chario | viochardata;
++ hev->xSourceLp = HvLpConfig_getLpIndex();
++ hev->xTargetLp = lp;
++ hev->xSizeMinus1 = sizeof(struct viocharlpevent);
++ hev->xSourceInstanceId = viopath_sourceinst(lp);
++ hev->xTargetInstanceId = viopath_targetinst(lp);
++}
++
++static int get_chars(uint32_t vtermno, char *buf, int count)
++{
++ struct port_info *pi;
++ int n = 0;
++ unsigned long flags;
++
++ if (vtermno >= VTTY_PORTS)
++ return -EINVAL;
++ if (count == 0)
++ return 0;
++
++ pi = &port_info[vtermno];
++ spin_lock_irqsave(&consolelock, flags);
++
++ if (pi->in_end == 0)
++ goto done;
++
++ n = pi->in_end - pi->in_start;
++ if (n > count)
++ n = count;
++ memcpy(buf, &pi->in_buf[pi->in_start], n);
++ pi->in_start += n;
++ if (pi->in_start == pi->in_end) {
++ pi->in_start = 0;
++ pi->in_end = 0;
++ }
++done:
++ spin_unlock_irqrestore(&consolelock, flags);
++ return n;
++}
++
++static int put_chars(uint32_t vtermno, const char *buf, int count)
++{
++ struct viocharlpevent *viochar;
++ struct port_info *pi;
++ HvLpEvent_Rc hvrc;
++ unsigned long flags;
++ int sent = 0;
++
++ if (vtermno >= VTTY_PORTS)
++ return -EINVAL;
++
++ pi = &port_info[vtermno];
++
++ spin_lock_irqsave(&consolelock, flags);
++
++ if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
++ HvCall_writeLogBuffer(buf, count);
++ sent = count;
++ goto done;
++ }
++
++ viochar = vio_get_event_buffer(viomajorsubtype_chario);
++ if (viochar == NULL) {
++ hvlog("\n\rviocons: Can't get viochar buffer.");
++ goto done;
++ }
++
++ while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
++ int len;
++
++ len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
++
++ if (viochar_is_console(pi))
++ HvCall_writeLogBuffer(buf, len);
++
++ init_data_event(viochar, pi->lp);
++
++ viochar->len = len;
++ viochar->event.xCorrelationToken = pi->seq++;
++ viochar->event.xSizeMinus1 =
++ offsetof(struct viocharlpevent, data) + len;
++
++ memcpy(viochar->data, buf, len);
++
++ hvrc = HvCallEvent_signalLpEvent(&viochar->event);
++ if (hvrc)
++ hvlog("\n\rerror sending event! return code %d\n\r",
++ (int)hvrc);
++ sent += len;
++ count -= len;
++ buf += len;
++ }
++
++ vio_free_event_buffer(viomajorsubtype_chario, viochar);
++done:
++ spin_unlock_irqrestore(&consolelock, flags);
++ return sent;
++}
++
++static struct hv_ops hvc_get_put_ops = {
++ .get_chars = get_chars,
++ .put_chars = put_chars,
++};
++
++static int __devinit hvc_vio_probe(struct vio_dev *vdev,
++ const struct vio_device_id *id)
++{
++ struct hvc_struct *hp;
++ struct port_info *pi;
++
++ /* probed with invalid parameters. */
++ if (!vdev || !id)
++ return -EPERM;
++
++ if (vdev->unit_address >= VTTY_PORTS)
++ return -ENODEV;
++
++ pi = &port_info[vdev->unit_address];
++
++ hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
++ VIOCHAR_MAX_DATA);
++ if (IS_ERR(hp))
++ return PTR_ERR(hp);
++ pi->hp = hp;
++ dev_set_drvdata(&vdev->dev, pi);
++
++ return 0;
++}
++
++static int __devexit hvc_vio_remove(struct vio_dev *vdev)
++{
++ struct port_info *pi = dev_get_drvdata(&vdev->dev);
++ struct hvc_struct *hp = pi->hp;
++
++ return hvc_remove(hp);
++}
++
++static struct vio_driver hvc_vio_driver = {
++ .id_table = hvc_driver_table,
++ .probe = hvc_vio_probe,
++ .remove = hvc_vio_remove,
++ .driver = {
++ .name = hvc_driver_name,
++ .owner = THIS_MODULE,
++ }
++};
++
++static void hvc_open_event(struct HvLpEvent *event)
++{
++ unsigned long flags;
++ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
++ u8 port = cevent->virtual_device;
++ struct port_info *pi;
++ int reject = 0;
++
++ if (hvlpevent_is_ack(event)) {
++ if (port >= VTTY_PORTS)
++ return;
++
++ spin_lock_irqsave(&consolelock, flags);
++
++ pi = &port_info[port];
++ if (event->xRc == HvLpEvent_Rc_Good) {
++ pi->seq = pi->ack = 0;
++ /*
++ * This line allows connections from the primary
++ * partition but once one is connected from the
++ * primary partition nothing short of a reboot
++ * of linux will allow access from the hosting
++ * partition again without a required iSeries fix.
++ */
++ pi->lp = event->xTargetLp;
++ }
++
++ spin_unlock_irqrestore(&consolelock, flags);
++ if (event->xRc != HvLpEvent_Rc_Good)
++ printk(KERN_WARNING
++ "hvc: handle_open_event: event->xRc == (%d).\n",
++ event->xRc);
++
++ if (event->xCorrelationToken != 0) {
++ atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
++ atomic_set(aptr, 1);
++ } else
++ printk(KERN_WARNING
++ "hvc: weird...got open ack without atomic\n");
++ return;
++ }
++
++ /* This had better require an ack, otherwise complain */
++ if (!hvlpevent_need_ack(event)) {
++ printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
++ return;
++ }
++
++ spin_lock_irqsave(&consolelock, flags);
++
++ /* Make sure this is a good virtual tty */
++ if (port >= VTTY_PORTS) {
++ event->xRc = HvLpEvent_Rc_SubtypeError;
++ cevent->subtype_result_code = viorc_openRejected;
++ /*
++ * Flag state here since we can't printk while holding
++ * the consolelock spinlock.
++ */
++ reject = 1;
++ } else {
++ pi = &port_info[port];
++ if ((pi->lp != HvLpIndexInvalid) &&
++ (pi->lp != event->xSourceLp)) {
++ /*
++ * If this is tty is already connected to a different
++ * partition, fail.
++ */
++ event->xRc = HvLpEvent_Rc_SubtypeError;
++ cevent->subtype_result_code = viorc_openRejected;
++ reject = 2;
++ } else {
++ pi->lp = event->xSourceLp;
++ event->xRc = HvLpEvent_Rc_Good;
++ cevent->subtype_result_code = viorc_good;
++ pi->seq = pi->ack = 0;
++ }
++ }
++
++ spin_unlock_irqrestore(&consolelock, flags);
++
++ if (reject == 1)
++ printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
++ else if (reject == 2)
++ printk(KERN_WARNING "hvc: open rejected: console in exclusive "
++ "use by another partition.\n");
++
++ /* Return the acknowledgement */
++ HvCallEvent_ackLpEvent(event);
++}
++
++/*
++ * Handle a close charLpEvent. This should ONLY be an Interrupt because the
++ * virtual console should never actually issue a close event to the hypervisor
++ * because the virtual console never goes away. A close event coming from the
++ * hypervisor simply means that there are no client consoles connected to the
++ * virtual console.
++ */
++static void hvc_close_event(struct HvLpEvent *event)
++{
++ unsigned long flags;
++ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
++ u8 port = cevent->virtual_device;
++
++ if (!hvlpevent_is_int(event)) {
++ printk(KERN_WARNING
++ "hvc: got unexpected close acknowlegement\n");
++ return;
++ }
++
++ if (port >= VTTY_PORTS) {
++ printk(KERN_WARNING
++ "hvc: close message from invalid virtual device.\n");
++ return;
++ }
++
++ /* For closes, just mark the console partition invalid */
++ spin_lock_irqsave(&consolelock, flags);
++
++ if (port_info[port].lp == event->xSourceLp)
++ port_info[port].lp = HvLpIndexInvalid;
++
++ spin_unlock_irqrestore(&consolelock, flags);
++}
++
++static void hvc_data_event(struct HvLpEvent *event)
++{
++ unsigned long flags;
++ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
++ struct port_info *pi;
++ int n;
++ u8 port = cevent->virtual_device;
++
++ if (port >= VTTY_PORTS) {
++ printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
++ port);
++ return;
++ }
++ if (cevent->len == 0)
++ return;
++
++ /*
++ * Change 05/01/2003 - Ryan Arnold: If a partition other than
++ * the current exclusive partition tries to send us data
++ * events then just drop them on the floor because we don't
++ * want his stinking data. He isn't authorized to receive
++ * data because he wasn't the first one to get the console,
++ * therefore he shouldn't be allowed to send data either.
++ * This will work without an iSeries fix.
++ */
++ pi = &port_info[port];
++ if (pi->lp != event->xSourceLp)
++ return;
++
++ spin_lock_irqsave(&consolelock, flags);
++
++ n = IN_BUF_SIZE - pi->in_end;
++ if (n > cevent->len)
++ n = cevent->len;
++ if (n > 0) {
++ memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
++ pi->in_end += n;
++ }
++ spin_unlock_irqrestore(&consolelock, flags);
++ if (n == 0)
++ printk(KERN_WARNING "hvc: input buffer overflow\n");
++}
++
++static void hvc_ack_event(struct HvLpEvent *event)
++{
++ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
++ unsigned long flags;
++ u8 port = cevent->virtual_device;
++
++ if (port >= VTTY_PORTS) {
++ printk(KERN_WARNING "hvc: data on invalid virtual device\n");
++ return;
++ }
++
++ spin_lock_irqsave(&consolelock, flags);
++ port_info[port].ack = event->xCorrelationToken;
++ spin_unlock_irqrestore(&consolelock, flags);
++}
++
++static void hvc_config_event(struct HvLpEvent *event)
++{
++ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
++
++ if (cevent->data[0] == 0x01)
++ printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
++ cevent->data[1], cevent->data[2],
++ cevent->data[3], cevent->data[4]);
++ else
++ printk(KERN_WARNING "hvc: unknown config event\n");
++}
++
++static void hvc_handle_event(struct HvLpEvent *event)
++{
++ int charminor;
++
++ if (event == NULL)
++ return;
++
++ charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
++ switch (charminor) {
++ case viocharopen:
++ hvc_open_event(event);
++ break;
++ case viocharclose:
++ hvc_close_event(event);
++ break;
++ case viochardata:
++ hvc_data_event(event);
++ break;
++ case viocharack:
++ hvc_ack_event(event);
++ break;
++ case viocharconfig:
++ hvc_config_event(event);
++ break;
++ default:
++ if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
++ event->xRc = HvLpEvent_Rc_InvalidSubtype;
++ HvCallEvent_ackLpEvent(event);
++ }
++ }
++}
++
++static int send_open(HvLpIndex remoteLp, void *sem)
++{
++ return HvCallEvent_signalLpEventFast(remoteLp,
++ HvLpEvent_Type_VirtualIo,
++ viomajorsubtype_chario | viocharopen,
++ HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
++ viopath_sourceinst(remoteLp),
++ viopath_targetinst(remoteLp),
++ (u64)(unsigned long)sem, VIOVERSION << 16,
++ 0, 0, 0, 0);
++}
++
++static int hvc_vio_init(void)
++{
++ atomic_t wait_flag;
++ int rc;
++
++ if (!firmware_has_feature(FW_FEATURE_ISERIES))
++ return -EIO;
++
++ /* +2 for fudge */
++ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
++ viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
++ if (rc)
++ printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
++
++ if (viopath_hostLp == HvLpIndexInvalid)
++ vio_set_hostlp();
++
++ /*
++ * And if the primary is not the same as the hosting LP, open to the
++ * hosting lp
++ */
++ if ((viopath_hostLp != HvLpIndexInvalid) &&
++ (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
++ printk(KERN_INFO "hvc: open path to hosting (%d)\n",
++ viopath_hostLp);
++ rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
++ VIOCHAR_WINDOW + 2); /* +2 for fudge */
++ if (rc)
++ printk(KERN_WARNING
++ "error opening to partition %d: %d\n",
++ viopath_hostLp, rc);
++ }
++
++ if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
++ printk(KERN_WARNING
++ "hvc: error seting handler for console events!\n");
++
++ /*
++ * First, try to open the console to the hosting lp.
++ * Wait on a semaphore for the response.
++ */
++ atomic_set(&wait_flag, 0);
++ if ((viopath_isactive(viopath_hostLp)) &&
++ (send_open(viopath_hostLp, &wait_flag) == 0)) {
++ printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
++ while (atomic_read(&wait_flag) == 0)
++ mb();
++ atomic_set(&wait_flag, 0);
++ }
++
++ /*
++ * If we don't have an active console, try the primary
++ */
++ if ((!viopath_isactive(port_info[0].lp)) &&
++ (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
++ (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
++ printk(KERN_INFO "hvc: opening console to primary partition\n");
++ while (atomic_read(&wait_flag) == 0)
++ mb();
++ }
++
++ /* 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")) {
++ const uint32_t *vtermno;
++
++ /* We have statically defined space for only a certain number
++ * of console adapters.
++ */
++ if ((num_found >= MAX_NR_HVC_CONSOLES) ||
++ (num_found >= VTTY_PORTS))
++ break;
++
++ vtermno = get_property(vty, "reg", NULL);
++ if (!vtermno)
++ continue;
++
++ if (!device_is_compatible(vty, "IBM,iSeries-vty"))
++ continue;
++
++ if (num_found == 0)
++ add_preferred_console("hvc", 0, NULL);
++ hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
++ ++num_found;
++ }
++
++ return num_found;
++}
++console_initcall(hvc_find_vtys);
+diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
+index 57106e0..4b97eaf 100644
+--- a/drivers/char/hvc_rtas.c
++++ b/drivers/char/hvc_rtas.c
+@@ -94,7 +94,7 @@ static int hvc_rtas_init(void)
+
+ /* Allocate an hvc_struct for the console device we instantiated
+ * earlier. Save off hp so that we can return it on exit */
+- hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops);
++ hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+
+diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
+index 9add81c..f9c0084 100644
+--- a/drivers/char/hvc_vio.c
++++ b/drivers/char/hvc_vio.c
+@@ -35,6 +35,7 @@
+ #include <asm/hvconsole.h>
+ #include <asm/vio.h>
+ #include <asm/prom.h>
++#include <asm/firmware.h>
+
+ #include "hvc_console.h"
+
+@@ -90,7 +91,8 @@ static int __devinit hvc_vio_probe(struc
+ if (!vdev || !id)
+ return -EPERM;
+
+- hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops);
++ hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
++ MAX_VIO_PUT_CHARS);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ dev_set_drvdata(&vdev->dev, hp);
+@@ -119,6 +121,9 @@ static int hvc_vio_init(void)
+ {
+ int rc;
+
++ if (firmware_has_feature(FW_FEATURE_ISERIES))
++ return -EIO;
++
+ /* Register as a vio device to receive callbacks */
+ rc = vio_register_driver(&hvc_vio_driver);
+
+@@ -140,7 +145,7 @@ static int hvc_find_vtys(void)
+
+ for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
+ vty = of_find_node_by_name(vty, "vty")) {
+- uint32_t *vtermno;
++ const uint32_t *vtermno;
+
+ /* We have statically defined space for only a certain number
+ * of console adapters.
+@@ -148,7 +153,7 @@ static int hvc_find_vtys(void)
+ if (num_found >= MAX_NR_HVC_CONSOLES)
+ break;
+
+- vtermno = (uint32_t *)get_property(vty, "reg", NULL);
++ vtermno = get_property(vty, "reg", NULL);
+ if (!vtermno)
+ continue;
+
+diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
+index 4589ff3..8728255 100644
+--- a/drivers/char/hvcs.c
++++ b/drivers/char/hvcs.c
+@@ -313,8 +313,7 @@ static DEFINE_SPINLOCK(hvcs_structs_lock
+
+ static void hvcs_unthrottle(struct tty_struct *tty);
+ static void hvcs_throttle(struct tty_struct *tty);
+-static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
++static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance);
+
+ static int hvcs_write(struct tty_struct *tty,
+ const unsigned char *buf, int count);
+@@ -387,8 +386,7 @@ static void hvcs_throttle(struct tty_str
+ * handler taking any further interrupts because they are disabled which means
+ * the hvcs_struct will always be valid in this handler.
+ */
+-static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
+ {
+ struct hvcs_struct *hvcsd = dev_instance;
+
+@@ -1306,7 +1304,7 @@ static int hvcs_chars_in_buffer(struct t
+ return hvcsd->chars_in_buffer;
+ }
+
+-static struct tty_operations hvcs_ops = {
++static const struct tty_operations hvcs_ops = {
+ .open = hvcs_open,
+ .close = hvcs_close,
+ .hangup = hvcs_hangup,
+diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
+index 017f755..2cf63e7 100644
+--- a/drivers/char/hvsi.c
++++ b/drivers/char/hvsi.c
+@@ -406,7 +406,7 @@ static void hvsi_insert_chars(struct hvs
+ hp->sysrq = 1;
+ continue;
+ } else if (hp->sysrq) {
+- handle_sysrq(c, NULL, hp->tty);
++ handle_sysrq(c, hp->tty);
+ hp->sysrq = 0;
+ continue;
+ }
+@@ -555,7 +555,7 @@ static void hvsi_send_overflow(struct hv
+ * must get all pending data because we only get an irq on empty->non-empty
+ * transition
+ */
+-static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t hvsi_interrupt(int irq, void *arg)
+ {
+ struct hvsi_struct *hp = (struct hvsi_struct *)arg;
+ struct tty_struct *flip;
+@@ -616,7 +616,7 @@ static int __init poll_for_state(struct
+ unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+
+ for (;;) {
+- hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */
++ hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */
+
+ if (hp->state == state)
+ return 0;
+@@ -1130,7 +1130,7 @@ static int hvsi_tiocmset(struct tty_stru
+ }
+
+
+-static struct tty_operations hvsi_ops = {
++static const struct tty_operations hvsi_ops = {
+ .open = hvsi_open,
+ .close = hvsi_close,
+ .write = hvsi_write,
+@@ -1274,11 +1274,10 @@ static int __init hvsi_console_init(void
+ vty != NULL;
+ vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
+ struct hvsi_struct *hp;
+- uint32_t *vtermno;
+- uint32_t *irq;
++ const uint32_t *vtermno, *irq;
+
+- vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+- irq = (uint32_t *)get_property(vty, "interrupts", NULL);
++ vtermno = get_property(vty, "reg", NULL);
++ irq = get_property(vty, "interrupts", NULL);
+ if (!vtermno || !irq)
+ continue;
+
+diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
+index ccd7e71..8efbc9c 100644
+--- a/drivers/char/hw_random/intel-rng.c
++++ b/drivers/char/hw_random/intel-rng.c
+@@ -50,6 +50,43 @@
+ #define INTEL_RNG_ADDR_LEN 3
+
+ /*
++ * LPC bridge PCI config space registers
++ */
++#define FWH_DEC_EN1_REG_OLD 0xe3
++#define FWH_DEC_EN1_REG_NEW 0xd9 /* high byte of 16-bit register */
++#define FWH_F8_EN_MASK 0x80
++
++#define BIOS_CNTL_REG_OLD 0x4e
++#define BIOS_CNTL_REG_NEW 0xdc
++#define BIOS_CNTL_WRITE_ENABLE_MASK 0x01
++#define BIOS_CNTL_LOCK_ENABLE_MASK 0x02
++
++/*
++ * Magic address at which Intel Firmware Hubs get accessed
++ */
++#define INTEL_FWH_ADDR 0xffff0000
++#define INTEL_FWH_ADDR_LEN 2
++
++/*
++ * Intel Firmware Hub command codes (write to any address inside the device)
++ */
++#define INTEL_FWH_RESET_CMD 0xff /* aka READ_ARRAY */
++#define INTEL_FWH_READ_ID_CMD 0x90
++
++/*
++ * Intel Firmware Hub Read ID command result addresses
++ */
++#define INTEL_FWH_MANUFACTURER_CODE_ADDRESS 0x000000
++#define INTEL_FWH_DEVICE_CODE_ADDRESS 0x000001
++
++/*
++ * Intel Firmware Hub Read ID command result values
++ */
++#define INTEL_FWH_MANUFACTURER_CODE 0x89
++#define INTEL_FWH_DEVICE_CODE_8M 0xac
++#define INTEL_FWH_DEVICE_CODE_4M 0xad
++
++/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+@@ -58,12 +95,50 @@
+ * want to register another driver on the same PCI id.
+ */
+ static const struct pci_device_id pci_tbl[] = {
+- { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+- { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+- { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+- { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+- { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+- { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
++/* AA
++ { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
++ { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */
++/* AB
++ { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
++ { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */
++/* ??
++ { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
++/* BAM, CAM, DBM, FBM, GxM
++ { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
++ { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */
++ { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */
++ { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */
++ { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */
++ { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */
++ { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */
++/* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx
++ { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
++ { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */
++ { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */
++ { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */
++ { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */
++ { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */
++ { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */
++ { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
++ { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */
++/* E
++ { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
++ { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E */
+ { 0, }, /* terminate list */
+ };
+ MODULE_DEVICE_TABLE(pci, pci_tbl);
+@@ -138,22 +213,115 @@ static struct hwrng intel_rng = {
+ };
+
+
++#ifdef CONFIG_SMP
++static char __initdata waitflag;
++
++static void __init intel_init_wait(void *unused)
++{
++ while (waitflag)
++ cpu_relax();
++}
++#endif
++
+ static int __init mod_init(void)
+ {
+ int err = -ENODEV;
++ unsigned i;
++ struct pci_dev *dev = NULL;
+ void __iomem *mem;
+- u8 hw_status;
++ unsigned long flags;
++ u8 bios_cntl_off, fwh_dec_en1_off;
++ u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
++ u8 hw_status, mfc, dvc;
+
+- if (!pci_dev_present(pci_tbl))
++ for (i = 0; !dev && pci_tbl[i].vendor; ++i)
++ dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
++
++ if (!dev)
+ goto out; /* Device not found. */
+
++ /* Check for Intel 82802 */
++ if (dev->device < 0x2640) {
++ fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
++ bios_cntl_off = BIOS_CNTL_REG_OLD;
++ } else {
++ fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
++ bios_cntl_off = BIOS_CNTL_REG_NEW;
++ }
++
++ pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
++ pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
++
++ mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
++ if (mem == NULL) {
++ pci_dev_put(dev);
++ err = -EBUSY;
++ goto out;
++ }
++
++ /*
++ * Since the BIOS code/data is going to disappear from its normal
++ * location with the Read ID command, all activity on the system
++ * must be stopped until the state is back to normal.
++ */
++#ifdef CONFIG_SMP
++ set_mb(waitflag, 1);
++ if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
++ set_mb(waitflag, 0);
++ pci_dev_put(dev);
++ printk(KERN_ERR PFX "cannot run on all processors\n");
++ err = -EAGAIN;
++ goto err_unmap;
++ }
++#endif
++ local_irq_save(flags);
++
++ if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
++ pci_write_config_byte(dev,
++ fwh_dec_en1_off,
++ fwh_dec_en1_val | FWH_F8_EN_MASK);
++ if (!(bios_cntl_val &
++ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
++ pci_write_config_byte(dev,
++ bios_cntl_off,
++ bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
++
++ writeb(INTEL_FWH_RESET_CMD, mem);
++ writeb(INTEL_FWH_READ_ID_CMD, mem);
++ mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
++ dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
++ writeb(INTEL_FWH_RESET_CMD, mem);
++
++ if (!(bios_cntl_val &
++ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
++ pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
++ if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
++ pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
++
++ local_irq_restore(flags);
++#ifdef CONFIG_SMP
++ /* Tell other CPUs to resume. */
++ set_mb(waitflag, 0);
++#endif
++
++ iounmap(mem);
++ pci_dev_put(dev);
++
++ if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
++ (dvc != INTEL_FWH_DEVICE_CODE_8M &&
++ dvc != INTEL_FWH_DEVICE_CODE_4M)) {
++ printk(KERN_ERR PFX "FWH not detected\n");
++ err = -ENODEV;
++ goto out;
++ }
++
+ err = -ENOMEM;
+ mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
+ if (!mem)
+ goto out;
+ intel_rng.priv = (unsigned long)mem;
+
+- /* Check for Intel 82802 */
++ /* Check for Random Number Generator */
+ err = -ENODEV;
+ hw_status = hwstatus_get(mem);
+ if ((hw_status & INTEL_RNG_PRESENT) == 0)
+diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
+index ef71022..c9caff5 100644
+--- a/drivers/char/hw_random/ixp4xx-rng.c
++++ b/drivers/char/hw_random/ixp4xx-rng.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/char/rng/ixp4xx-rng.c
++ * drivers/char/hw_random/ixp4xx-rng.c
+ *
+ * RNG driver for Intel IXP4xx family of NPUs
+ *
+@@ -15,7 +15,6 @@
+ */
+
+ #include <linux/kernel.h>
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
+index a01d796..e13dd18 100644
+--- a/drivers/char/hw_random/omap-rng.c
++++ b/drivers/char/hw_random/omap-rng.c
+@@ -1,5 +1,5 @@
+ /*
+- * driver/char/hw_random/omap-rng.c
++ * drivers/char/hw_random/omap-rng.c
+ *
+ * RNG driver for TI OMAP CPU family
+ *
+diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
+index fc944d3..54d93f0 100644
+--- a/drivers/char/ip2/i2lib.c
++++ b/drivers/char/ip2/i2lib.c
+@@ -1007,7 +1007,7 @@ i2InputAvailable(i2ChanStrPtr pCh)
+ // applications that one cannot break out of.
+ //******************************************************************************
+ static int
+-i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
++i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
+ {
+ i2eBordStrPtr pB;
+ unsigned char *pInsert;
+@@ -1020,7 +1020,7 @@ i2Output(i2ChanStrPtr pCh, const char *p
+
+ int bailout = 10;
+
+- ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user );
++ ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, 0 );
+
+ // Ensure channel structure seems real
+ if ( !i2Validate ( pCh ) )
+@@ -1087,12 +1087,7 @@ i2Output(i2ChanStrPtr pCh, const char *p
+ DATA_COUNT_OF(pInsert) = amountToMove;
+
+ // Move the data
+- if ( user ) {
+- rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource,
+- amountToMove );
+- } else {
+- memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
+- }
++ memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
+ // Adjust pointers and indices
+ pSource += amountToMove;
+ pCh->Obuf_char_count += amountToMove;
+diff --git a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h
+index 952e113..e559e9b 100644
+--- a/drivers/char/ip2/i2lib.h
++++ b/drivers/char/ip2/i2lib.h
+@@ -332,7 +332,7 @@ static int i2QueueCommands(int, i2ChanS
+ static int i2GetStatus(i2ChanStrPtr, int);
+ static int i2Input(i2ChanStrPtr);
+ static int i2InputFlush(i2ChanStrPtr);
+-static int i2Output(i2ChanStrPtr, const char *, int, int);
++static int i2Output(i2ChanStrPtr, const char *, int);
+ static int i2OutputFree(i2ChanStrPtr);
+ static int i2ServiceBoard(i2eBordStrPtr);
+ static void i2DrainOutput(i2ChanStrPtr, int);
+diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
+index 7907ae8..a3f32d4 100644
+--- a/drivers/char/ip2/ip2main.c
++++ b/drivers/char/ip2/ip2main.c
+@@ -190,7 +190,7 @@ static int ip2_tiocmset(struct tty_stru
+
+ static void set_irq(int, int);
+ static void ip2_interrupt_bh(i2eBordStrPtr pB);
+-static irqreturn_t ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t ip2_interrupt(int irq, void *dev_id);
+ static void ip2_poll(unsigned long arg);
+ static inline void service_all_boards(void);
+ static void do_input(void *p);
+@@ -436,6 +436,7 @@ cleanup_module(void)
+ #ifdef CONFIG_PCI
+ if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
+ pci_disable_device(ip2config.pci_dev[i]);
++ pci_dev_put(ip2config.pci_dev[i]);
+ ip2config.pci_dev[i] = NULL;
+ }
+ #endif
+@@ -457,7 +458,7 @@ cleanup_module(void)
+ }
+ #endif /* MODULE */
+
+-static struct tty_operations ip2_ops = {
++static const struct tty_operations ip2_ops = {
+ .open = ip2_open,
+ .close = ip2_close,
+ .write = ip2_write,
+@@ -505,6 +506,7 @@ ip2_loadmain(int *iop, int *irqp, unsign
+ static int loaded;
+ i2eBordStrPtr pB = NULL;
+ int rc = -1;
++ static struct pci_dev *pci_dev_i = NULL;
+
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
+
+@@ -588,8 +590,7 @@ ip2_loadmain(int *iop, int *irqp, unsign
+ case PCI:
+ #ifdef CONFIG_PCI
+ {
+- struct pci_dev *pci_dev_i = NULL;
+- pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
++ pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
+ PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
+ if (pci_dev_i != NULL) {
+ unsigned int addr;
+@@ -600,7 +601,7 @@ ip2_loadmain(int *iop, int *irqp, unsign
+ break;
+ }
+ ip2config.type[i] = PCI;
+- ip2config.pci_dev[i] = pci_dev_i;
++ ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
+ status =
+ pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
+ if ( addr & 1 ) {
+@@ -641,6 +642,9 @@ ip2_loadmain(int *iop, int *irqp, unsign
+ break;
+ } /* switch */
+ } /* for */
++ if (pci_dev_i)
++ pci_dev_put(pci_dev_i);
++
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( ip2config.addr[i] ) {
+ pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL);
+@@ -775,8 +779,6 @@ retry:
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
+ goto out;
+
+-out_class:
+- class_destroy(ip2_class);
+ out_chrdev:
+ unregister_chrdev(IP2_IPL_MAJOR, "ip2");
+ out:
+@@ -1152,10 +1154,9 @@ ip2_interrupt_bh(i2eBordStrPtr pB)
+
+
+ /******************************************************************************/
+-/* Function: ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) */
++/* Function: ip2_interrupt(int irq, void *dev_id) */
+ /* Parameters: irq - interrupt number */
+ /* pointer to optional device ID structure */
+-/* pointer to register structure */
+ /* Returns: Nothing */
+ /* */
+ /* Description: */
+@@ -1171,7 +1172,7 @@ ip2_interrupt_bh(i2eBordStrPtr pB)
+ /* */
+ /******************************************************************************/
+ static irqreturn_t
+-ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++ip2_interrupt(int irq, void *dev_id)
+ {
+ int i;
+ i2eBordStrPtr pB;
+@@ -1235,7 +1236,7 @@ ip2_poll(unsigned long arg)
+ // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
+ // It will NOT poll boards handled by hard interrupts.
+ // The issue of queued BH interrups is handled in ip2_interrupt().
+- ip2_interrupt(0, NULL, NULL);
++ ip2_interrupt(0, NULL);
+
+ PollTimer.expires = POLL_TIMEOUT;
+ add_timer( &PollTimer );
+@@ -1703,7 +1704,7 @@ ip2_write( PTTY tty, const unsigned char
+
+ /* This is the actual move bit. Make sure it does what we need!!!!! */
+ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+- bytesSent = i2Output( pCh, pData, count, 0 );
++ bytesSent = i2Output( pCh, pData, count);
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+
+ ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
+@@ -1763,7 +1764,7 @@ ip2_flush_chars( PTTY tty )
+ //
+ // We may need to restart i2Output if it does not fullfill this request
+ //
+- strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 );
++ strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
+ if ( strip != pCh->Pbuf_stuff ) {
+ memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
+ }
+diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
+index 68d7c61..81fcf0c 100644
+--- a/drivers/char/ipmi/ipmi_devintf.c
++++ b/drivers/char/ipmi/ipmi_devintf.c
+@@ -377,7 +377,8 @@ static int ipmi_ioctl(struct inode *ino
+ break;
+ }
+
+- rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
++ rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
++ IPMI_CHAN_ALL);
+ break;
+ }
+
+@@ -390,7 +391,36 @@ static int ipmi_ioctl(struct inode *ino
+ break;
+ }
+
+- rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
++ rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
++ IPMI_CHAN_ALL);
++ break;
++ }
++
++ case IPMICTL_REGISTER_FOR_CMD_CHANS:
++ {
++ struct ipmi_cmdspec_chans val;
++
++ if (copy_from_user(&val, arg, sizeof(val))) {
++ rv = -EFAULT;
++ break;
++ }
++
++ rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
++ val.chans);
++ break;
++ }
++
++ case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
++ {
++ struct ipmi_cmdspec_chans val;
++
++ if (copy_from_user(&val, arg, sizeof(val))) {
++ rv = -EFAULT;
++ break;
++ }
++
++ rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
++ val.chans);
+ break;
+ }
+
+diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
+index 843d34c..34a4fd1 100644
+--- a/drivers/char/ipmi/ipmi_msghandler.c
++++ b/drivers/char/ipmi/ipmi_msghandler.c
+@@ -96,6 +96,7 @@ struct cmd_rcvr
+ ipmi_user_t user;
+ unsigned char netfn;
+ unsigned char cmd;
++ unsigned int chans;
+
+ /*
+ * This is used to form a linked lised during mass deletion.
+@@ -953,24 +954,41 @@ int ipmi_set_gets_events(ipmi_user_t use
+
+ static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
+ unsigned char netfn,
+- unsigned char cmd)
++ unsigned char cmd,
++ unsigned char chan)
+ {
+ struct cmd_rcvr *rcvr;
+
+ list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
++ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
++ && (rcvr->chans & (1 << chan)))
+ return rcvr;
+ }
+ return NULL;
+ }
+
++static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
++ unsigned char netfn,
++ unsigned char cmd,
++ unsigned int chans)
++{
++ struct cmd_rcvr *rcvr;
++
++ list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
++ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
++ && (rcvr->chans & chans))
++ return 0;
++ }
++ return 1;
++}
++
+ int ipmi_register_for_cmd(ipmi_user_t user,
+ unsigned char netfn,
+- unsigned char cmd)
++ unsigned char cmd,
++ unsigned int chans)
+ {
+ ipmi_smi_t intf = user->intf;
+ struct cmd_rcvr *rcvr;
+- struct cmd_rcvr *entry;
+ int rv = 0;
+
+
+@@ -979,12 +997,12 @@ int ipmi_register_for_cmd(ipmi_user_t
+ return -ENOMEM;
+ rcvr->cmd = cmd;
+ rcvr->netfn = netfn;
++ rcvr->chans = chans;
+ rcvr->user = user;
+
+ mutex_lock(&intf->cmd_rcvrs_mutex);
+ /* Make sure the command/netfn is not already registered. */
+- entry = find_cmd_rcvr(intf, netfn, cmd);
+- if (entry) {
++ if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
+ rv = -EBUSY;
+ goto out_unlock;
+ }
+@@ -1001,24 +1019,39 @@ int ipmi_register_for_cmd(ipmi_user_t
+
+ int ipmi_unregister_for_cmd(ipmi_user_t user,
+ unsigned char netfn,
+- unsigned char cmd)
++ unsigned char cmd,
++ unsigned int chans)
+ {
+ ipmi_smi_t intf = user->intf;
+ struct cmd_rcvr *rcvr;
++ struct cmd_rcvr *rcvrs = NULL;
++ int i, rv = -ENOENT;
+
+ mutex_lock(&intf->cmd_rcvrs_mutex);
+- /* Make sure the command/netfn is not already registered. */
+- rcvr = find_cmd_rcvr(intf, netfn, cmd);
+- if ((rcvr) && (rcvr->user == user)) {
+- list_del_rcu(&rcvr->link);
+- mutex_unlock(&intf->cmd_rcvrs_mutex);
+- synchronize_rcu();
++ for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
++ if (((1 << i) & chans) == 0)
++ continue;
++ rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
++ if (rcvr == NULL)
++ continue;
++ if (rcvr->user == user) {
++ rv = 0;
++ rcvr->chans &= ~chans;
++ if (rcvr->chans == 0) {
++ list_del_rcu(&rcvr->link);
++ rcvr->next = rcvrs;
++ rcvrs = rcvr;
++ }
++ }
++ }
++ mutex_unlock(&intf->cmd_rcvrs_mutex);
++ synchronize_rcu();
++ while (rcvrs) {
++ rcvr = rcvrs;
++ rcvrs = rcvr->next;
+ kfree(rcvr);
+- return 0;
+- } else {
+- mutex_unlock(&intf->cmd_rcvrs_mutex);
+- return -ENOENT;
+ }
++ return rv;
+ }
+
+ void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
+@@ -1895,13 +1928,8 @@ static ssize_t guid_show(struct device *
+ (long long) bmc->guid[8]);
+ }
+
+-static void
+-cleanup_bmc_device(struct kref *ref)
++static void remove_files(struct bmc_device *bmc)
+ {
+- struct bmc_device *bmc;
+-
+- bmc = container_of(ref, struct bmc_device, refcount);
+-
+ device_remove_file(&bmc->dev->dev,
+ &bmc->device_id_attr);
+ device_remove_file(&bmc->dev->dev,
+@@ -1918,12 +1946,23 @@ cleanup_bmc_device(struct kref *ref)
+ &bmc->manufacturer_id_attr);
+ device_remove_file(&bmc->dev->dev,
+ &bmc->product_id_attr);
++
+ if (bmc->id.aux_firmware_revision_set)
+ device_remove_file(&bmc->dev->dev,
+ &bmc->aux_firmware_rev_attr);
+ if (bmc->guid_set)
+ device_remove_file(&bmc->dev->dev,
+ &bmc->guid_attr);
++}
++
++static void
++cleanup_bmc_device(struct kref *ref)
++{
++ struct bmc_device *bmc;
++
++ bmc = container_of(ref, struct bmc_device, refcount);
++
++ remove_files(bmc);
+ platform_device_unregister(bmc->dev);
+ kfree(bmc);
+ }
+@@ -1944,6 +1983,79 @@ static void ipmi_bmc_unregister(ipmi_smi
+ mutex_unlock(&ipmidriver_mutex);
+ }
+
++static int create_files(struct bmc_device *bmc)
++{
++ int err;
++
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->device_id_attr);
++ if (err) goto out;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->provides_dev_sdrs_attr);
++ if (err) goto out_devid;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->revision_attr);
++ if (err) goto out_sdrs;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->firmware_rev_attr);
++ if (err) goto out_rev;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->version_attr);
++ if (err) goto out_firm;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->add_dev_support_attr);
++ if (err) goto out_version;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->manufacturer_id_attr);
++ if (err) goto out_add_dev;
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->product_id_attr);
++ if (err) goto out_manu;
++ if (bmc->id.aux_firmware_revision_set) {
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->aux_firmware_rev_attr);
++ if (err) goto out_prod_id;
++ }
++ if (bmc->guid_set) {
++ err = device_create_file(&bmc->dev->dev,
++ &bmc->guid_attr);
++ if (err) goto out_aux_firm;
++ }
++
++ return 0;
++
++out_aux_firm:
++ if (bmc->id.aux_firmware_revision_set)
++ device_remove_file(&bmc->dev->dev,
++ &bmc->aux_firmware_rev_attr);
++out_prod_id:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->product_id_attr);
++out_manu:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->manufacturer_id_attr);
++out_add_dev:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->add_dev_support_attr);
++out_version:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->version_attr);
++out_firm:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->firmware_rev_attr);
++out_rev:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->revision_attr);
++out_sdrs:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->provides_dev_sdrs_attr);
++out_devid:
++ device_remove_file(&bmc->dev->dev,
++ &bmc->device_id_attr);
++out:
++ return err;
++}
++
+ static int ipmi_bmc_register(ipmi_smi_t intf)
+ {
+ int rv;
+@@ -2018,7 +2130,6 @@ static int ipmi_bmc_register(ipmi_smi_t
+ bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
+ bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
+
+-
+ bmc->revision_attr.attr.name = "revision";
+ bmc->revision_attr.attr.owner = THIS_MODULE;
+ bmc->revision_attr.attr.mode = S_IRUGO;
+@@ -2060,28 +2171,14 @@ static int ipmi_bmc_register(ipmi_smi_t
+ bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
+ bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
+
+- device_create_file(&bmc->dev->dev,
+- &bmc->device_id_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->provides_dev_sdrs_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->revision_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->firmware_rev_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->version_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->add_dev_support_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->manufacturer_id_attr);
+- device_create_file(&bmc->dev->dev,
+- &bmc->product_id_attr);
+- if (bmc->id.aux_firmware_revision_set)
+- device_create_file(&bmc->dev->dev,
+- &bmc->aux_firmware_rev_attr);
+- if (bmc->guid_set)
+- device_create_file(&bmc->dev->dev,
+- &bmc->guid_attr);
++ rv = create_files(bmc);
++ if (rv) {
++ mutex_lock(&ipmidriver_mutex);
++ platform_device_unregister(bmc->dev);
++ mutex_unlock(&ipmidriver_mutex);
++
++ return rv;
++ }
+
+ printk(KERN_INFO
+ "ipmi: Found new BMC (man_id: 0x%6.6x, "
+@@ -2548,6 +2645,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_
+ int rv = 0;
+ unsigned char netfn;
+ unsigned char cmd;
++ unsigned char chan;
+ ipmi_user_t user = NULL;
+ struct ipmi_ipmb_addr *ipmb_addr;
+ struct ipmi_recv_msg *recv_msg;
+@@ -2568,9 +2666,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_
+
+ netfn = msg->rsp[4] >> 2;
+ cmd = msg->rsp[8];
++ chan = msg->rsp[3] & 0xf;
+
+ rcu_read_lock();
+- rcvr = find_cmd_rcvr(intf, netfn, cmd);
++ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+ if (rcvr) {
+ user = rcvr->user;
+ kref_get(&user->refcount);
+@@ -2728,6 +2827,7 @@ static int handle_lan_get_msg_cmd(ipmi_s
+ int rv = 0;
+ unsigned char netfn;
+ unsigned char cmd;
++ unsigned char chan;
+ ipmi_user_t user = NULL;
+ struct ipmi_lan_addr *lan_addr;
+ struct ipmi_recv_msg *recv_msg;
+@@ -2748,9 +2848,10 @@ static int handle_lan_get_msg_cmd(ipmi_s
+
+ netfn = msg->rsp[6] >> 2;
+ cmd = msg->rsp[10];
++ chan = msg->rsp[3] & 0xf;
+
+ rcu_read_lock();
+- rcvr = find_cmd_rcvr(intf, netfn, cmd);
++ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+ if (rcvr) {
+ user = rcvr->user;
+ kref_get(&user->refcount);
+diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
+index abca98b..157fa81 100644
+--- a/drivers/char/ipmi/ipmi_si_intf.c
++++ b/drivers/char/ipmi/ipmi_si_intf.c
+@@ -217,6 +217,11 @@ struct smi_info
+ struct list_head link;
+ };
+
++#define SI_MAX_PARMS 4
++
++static int force_kipmid[SI_MAX_PARMS];
++static int num_force_kipmid;
++
+ static int try_smi_init(struct smi_info *smi);
+
+ static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
+@@ -867,7 +872,7 @@ static void smi_timeout(unsigned long da
+ add_timer(&(smi_info->si_timer));
+ }
+
+-static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t si_irq_handler(int irq, void *data)
+ {
+ struct smi_info *smi_info = data;
+ unsigned long flags;
+@@ -894,20 +899,21 @@ static irqreturn_t si_irq_handler(int ir
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t si_bt_irq_handler(int irq, void *data)
+ {
+ struct smi_info *smi_info = data;
+ /* We need to clear the IRQ flag for the BT interface. */
+ smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG,
+ IPMI_BT_INTMASK_CLEAR_IRQ_BIT
+ | IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
+- return si_irq_handler(irq, data, regs);
++ return si_irq_handler(irq, data);
+ }
+
+ static int smi_start_processing(void *send_info,
+ ipmi_smi_t intf)
+ {
+ struct smi_info *new_smi = send_info;
++ int enable = 0;
+
+ new_smi->intf = intf;
+
+@@ -916,7 +922,19 @@ static int smi_start_processing(void
+ new_smi->last_timeout_jiffies = jiffies;
+ mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+
+- if (new_smi->si_type != SI_BT) {
++ /*
++ * Check if the user forcefully enabled the daemon.
++ */
++ if (new_smi->intf_num < num_force_kipmid)
++ enable = force_kipmid[new_smi->intf_num];
++ /*
++ * The BT interface is efficient enough to not need a thread,
++ * and there is no need for a thread if we have interrupts.
++ */
++ else if ((new_smi->si_type != SI_BT) && (!new_smi->irq))
++ enable = 1;
++
++ if (enable) {
+ new_smi->thread = kthread_run(ipmi_thread, new_smi,
+ "kipmi%d", new_smi->intf_num);
+ if (IS_ERR(new_smi->thread)) {
+@@ -944,7 +962,6 @@ static struct ipmi_smi_handlers handlers
+ /* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+ a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */
+
+-#define SI_MAX_PARMS 4
+ static LIST_HEAD(smi_infos);
+ static DEFINE_MUTEX(smi_infos_lock);
+ static int smi_num; /* Used to sequence the SMIs */
+@@ -1017,6 +1034,10 @@ MODULE_PARM_DESC(slave_addrs, "Set the d
+ " the controller. Normally this is 0x20, but can be"
+ " overridden by this parm. This is an array indexed"
+ " by interface number.");
++module_param_array(force_kipmid, int, &num_force_kipmid, 0);
++MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or"
++ " disabled(0). Normally the IPMI driver auto-detects"
++ " this, but the value may be overridden by this parm.");
+
+
+ #define IPMI_IO_ADDR_SPACE 0
+@@ -1730,6 +1751,7 @@ static void __devinit dmi_find_bmc(void)
+ int rv;
+
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
++ memset(&data, 0, sizeof(data));
+ rv = decode_dmi((struct dmi_header *) dev->device_data, &data);
+ if (!rv)
+ try_init_dmi(&data);
+@@ -1767,7 +1789,7 @@ static int __devinit ipmi_pci_probe(stru
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+- return ENOMEM;
++ return -ENOMEM;
+
+ info->addr_source = "PCI";
+
+@@ -1788,7 +1810,7 @@ static int __devinit ipmi_pci_probe(stru
+ kfree(info);
+ printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n",
+ pci_name(pdev), class_type);
+- return ENOMEM;
++ return -ENOMEM;
+ }
+
+ rv = pci_enable_device(pdev);
+@@ -1845,7 +1867,7 @@ static int ipmi_pci_resume(struct pci_de
+
+ static struct pci_device_id ipmi_pci_devices[] = {
+ { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
+- { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE) }
++ { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }
+ };
+ MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
+
+diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
+index accaaf1..73f759e 100644
+--- a/drivers/char/ipmi/ipmi_watchdog.c
++++ b/drivers/char/ipmi/ipmi_watchdog.c
+@@ -903,7 +903,7 @@ static void ipmi_register_watchdog(int i
+
+ #ifdef HAVE_NMI_HANDLER
+ static int
+-ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
++ipmi_nmi(void *dev_id, int cpu, int handled)
+ {
+ /* If we are not expecting a timeout, ignore it. */
+ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
+index 913be23..e9e9bf3 100644
+--- a/drivers/char/isicom.c
++++ b/drivers/char/isicom.c
+@@ -546,7 +546,7 @@ static void isicom_bottomhalf(void *data
+ * Main interrupt handler routine
+ */
+
+-static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t isicom_interrupt(int irq, void *dev_id)
+ {
+ struct isi_board *card = dev_id;
+ struct isi_port *port;
+@@ -1550,7 +1550,7 @@ static void isicom_unregister_ioregion(s
+ board->base = 0;
+ }
+
+-static struct tty_operations isicom_ops = {
++static const struct tty_operations isicom_ops = {
+ .open = isicom_open,
+ .close = isicom_close,
+ .write = isicom_write,
+@@ -1756,9 +1756,12 @@ static int __devinit load_firmware(struc
+ if (retval)
+ goto end;
+
++ retval = -EIO;
++
+ for (frame = (struct stframe *)fw->data;
+ frame < (struct stframe *)(fw->data + fw->size);
+- frame++) {
++ frame = (struct stframe *)((u8 *)(frame + 1) +
++ frame->count)) {
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+@@ -1797,23 +1800,12 @@ static int __devinit load_firmware(struc
+ }
+ }
+
+- retval = -EIO;
+-
+- if (WaitTillCardIsFree(base))
+- goto errrelfw;
+-
+- outw(0xf2, base);
+- outw(0x800, base);
+- outw(0x0, base);
+- outw(0x0, base);
+- InterruptTheCard(base);
+- outw(0x0, base + 0x4); /* for ISI4608 cards */
+-
+ /* XXX: should we test it by reading it back and comparing with original like
+ * in load firmware package? */
+- for (frame = (struct stframe*)fw->data;
+- frame < (struct stframe*)(fw->data + fw->size);
+- frame++) {
++ for (frame = (struct stframe *)fw->data;
++ frame < (struct stframe *)(fw->data + fw->size);
++ frame = (struct stframe *)((u8 *)(frame + 1) +
++ frame->count)) {
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+@@ -1863,6 +1855,17 @@ static int __devinit load_firmware(struc
+ }
+ }
+
++ /* xfer ctrl */
++ if (WaitTillCardIsFree(base))
++ goto errrelfw;
++
++ outw(0xf2, base);
++ outw(0x800, base);
++ outw(0x0, base);
++ outw(0x0, base);
++ InterruptTheCard(base);
++ outw(0x0, base + 0x4); /* for ISI4608 cards */
++
+ board->status |= FIRMWARE_LOADED;
+ retval = 0;
+
+diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
+index 84dfc42..ffdf9df 100644
+--- a/drivers/char/istallion.c
++++ b/drivers/char/istallion.c
+@@ -612,16 +612,6 @@ MODULE_DEVICE_TABLE(pci, istallion_pci_t
+ #define MINOR2BRD(min) (((min) & 0xc0) >> 6)
+ #define MINOR2PORT(min) ((min) & 0x3f)
+
+-/*
+- * Define a baud rate table that converts termios baud rate selector
+- * into the actual baud rate value. All baud rate calculations are based
+- * on the actual baud rate required.
+- */
+-static unsigned int stli_baudrates[] = {
+- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+-};
+-
+ /*****************************************************************************/
+
+ /*
+@@ -696,37 +686,37 @@ static stlibrd_t *stli_allocbrd(void);
+ static void stli_ecpinit(stlibrd_t *brdp);
+ static void stli_ecpenable(stlibrd_t *brdp);
+ static void stli_ecpdisable(stlibrd_t *brdp);
+-static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_ecpreset(stlibrd_t *brdp);
+ static void stli_ecpintr(stlibrd_t *brdp);
+ static void stli_ecpeiinit(stlibrd_t *brdp);
+ static void stli_ecpeienable(stlibrd_t *brdp);
+ static void stli_ecpeidisable(stlibrd_t *brdp);
+-static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_ecpeireset(stlibrd_t *brdp);
+ static void stli_ecpmcenable(stlibrd_t *brdp);
+ static void stli_ecpmcdisable(stlibrd_t *brdp);
+-static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_ecpmcreset(stlibrd_t *brdp);
+ static void stli_ecppciinit(stlibrd_t *brdp);
+-static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_ecppcireset(stlibrd_t *brdp);
+
+ static void stli_onbinit(stlibrd_t *brdp);
+ static void stli_onbenable(stlibrd_t *brdp);
+ static void stli_onbdisable(stlibrd_t *brdp);
+-static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_onbreset(stlibrd_t *brdp);
+ static void stli_onbeinit(stlibrd_t *brdp);
+ static void stli_onbeenable(stlibrd_t *brdp);
+ static void stli_onbedisable(stlibrd_t *brdp);
+-static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_onbereset(stlibrd_t *brdp);
+ static void stli_bbyinit(stlibrd_t *brdp);
+-static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_bbyreset(stlibrd_t *brdp);
+ static void stli_stalinit(stlibrd_t *brdp);
+-static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
++static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+ static void stli_stalreset(stlibrd_t *brdp);
+
+ static stliport_t *stli_getport(int brdnr, int panelnr, int portnr);
+@@ -1576,7 +1566,7 @@ static void stli_flushchars(struct tty_s
+
+ len = MIN(len, cooksize);
+ count = 0;
+- shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);
++ shbuf = EBRDGETMEMPTR(brdp, portp->txoffset);
+ buf = stli_txcookbuf;
+
+ while (len > 0) {
+@@ -2747,15 +2737,7 @@ static void stli_mkasyport(stliport_t *p
+ /*
+ * Start of by setting the baud, char size, parity and stop bit info.
+ */
+- pp->baudout = tiosp->c_cflag & CBAUD;
+- if (pp->baudout & CBAUDEX) {
+- pp->baudout &= ~CBAUDEX;
+- if ((pp->baudout < 1) || (pp->baudout > 4))
+- tiosp->c_cflag &= ~CBAUDEX;
+- else
+- pp->baudout += 15;
+- }
+- pp->baudout = stli_baudrates[pp->baudout];
++ pp->baudout = tty_get_baud_rate(portp->tty);
+ if ((tiosp->c_cflag & CBAUD) == B38400) {
+ if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ pp->baudout = 57600;
+@@ -2966,9 +2948,9 @@ static void stli_ecpdisable(stlibrd_t *b
+
+ /*****************************************************************************/
+
+-static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+ unsigned char val;
+
+ if (offset > brdp->memsize) {
+@@ -3040,9 +3022,9 @@ static void stli_ecpeidisable(stlibrd_t
+
+ /*****************************************************************************/
+
+-static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+ unsigned char val;
+
+ if (offset > brdp->memsize) {
+@@ -3092,9 +3074,9 @@ static void stli_ecpmcdisable(stlibrd_t
+
+ /*****************************************************************************/
+
+-static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+ unsigned char val;
+
+ if (offset > brdp->memsize) {
+@@ -3137,9 +3119,9 @@ static void stli_ecppciinit(stlibrd_t *b
+
+ /*****************************************************************************/
+
+-static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+ unsigned char val;
+
+ if (offset > brdp->memsize) {
+@@ -3203,9 +3185,9 @@ static void stli_onbdisable(stlibrd_t *b
+
+ /*****************************************************************************/
+
+-static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+
+ if (offset > brdp->memsize) {
+ printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+@@ -3268,9 +3250,9 @@ static void stli_onbedisable(stlibrd_t *
+
+ /*****************************************************************************/
+
+-static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+ unsigned char val;
+
+ if (offset > brdp->memsize) {
+@@ -3318,9 +3300,9 @@ static void stli_bbyinit(stlibrd_t *brdp
+
+ /*****************************************************************************/
+
+-static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+- void *ptr;
++ void __iomem *ptr;
+ unsigned char val;
+
+ BUG_ON(offset > brdp->memsize);
+@@ -3355,7 +3337,7 @@ static void stli_stalinit(stlibrd_t *brd
+
+ /*****************************************************************************/
+
+-static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
++static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+ {
+ BUG_ON(offset > brdp->memsize);
+ return brdp->membase + (offset % STAL_PAGESIZE);
+@@ -3488,7 +3470,7 @@ static int stli_initecp(stlibrd_t *brdp)
+ */
+ EBRDENABLE(brdp);
+ sigsp = (cdkecpsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+- memcpy(&sig, sigsp, sizeof(cdkecpsig_t));
++ memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t));
+ EBRDDISABLE(brdp);
+
+ if (sig.magic != cpu_to_le32(ECP_MAGIC))
+@@ -3894,7 +3876,7 @@ static int stli_eisamemprobe(stlibrd_t *
+ continue;
+
+ if (brdp->brdtype == BRD_ECPE) {
+- ecpsigp = (cdkecpsig_t __iomem *) stli_ecpeigetmemptr(brdp,
++ ecpsigp = stli_ecpeigetmemptr(brdp,
+ CDK_SIGADDR, __LINE__);
+ memcpy_fromio(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
+ if (ecpsig.magic == cpu_to_le32(ECP_MAGIC))
+@@ -4202,7 +4184,7 @@ static int stli_initbrds(void)
+ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp)
+ {
+ unsigned long flags;
+- void *memptr;
++ void __iomem *memptr;
+ stlibrd_t *brdp;
+ int brdnr, size, n;
+ void *p;
+@@ -4232,7 +4214,7 @@ static ssize_t stli_memread(struct file
+ while (size > 0) {
+ spin_lock_irqsave(&brd_lock, flags);
+ EBRDENABLE(brdp);
+- memptr = (void *) EBRDGETMEMPTR(brdp, off);
++ memptr = EBRDGETMEMPTR(brdp, off);
+ n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = MIN(n, PAGE_SIZE);
+ memcpy_fromio(p, memptr, n);
+@@ -4265,7 +4247,7 @@ out:
+ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp)
+ {
+ unsigned long flags;
+- void *memptr;
++ void __iomem *memptr;
+ stlibrd_t *brdp;
+ char __user *chbuf;
+ int brdnr, size, n;
+@@ -4305,7 +4287,7 @@ static ssize_t stli_memwrite(struct file
+ }
+ spin_lock_irqsave(&brd_lock, flags);
+ EBRDENABLE(brdp);
+- memptr = (void *) EBRDGETMEMPTR(brdp, off);
++ memptr = EBRDGETMEMPTR(brdp, off);
+ memcpy_toio(memptr, p, n);
+ EBRDDISABLE(brdp);
+ spin_unlock_irqrestore(&brd_lock, flags);
+@@ -4654,7 +4636,7 @@ static int stli_memioctl(struct inode *i
+ return rc;
+ }
+
+-static struct tty_operations stli_ops = {
++static const struct tty_operations stli_ops = {
+ .open = stli_open,
+ .close = stli_close,
+ .write = stli_write,
+diff --git a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c
+deleted file mode 100644
+index cde562d..0000000
+--- a/drivers/char/ite_gpio.c
++++ /dev/null
+@@ -1,419 +0,0 @@
+-/*
+- * FILE NAME ite_gpio.c
+- *
+- * BRIEF MODULE DESCRIPTION
+- * API for ITE GPIO device.
+- * Driver for ITE GPIO device.
+- *
+- * Author: MontaVista Software, Inc. <source at mvista.com>
+- * Hai-Pao Fan <haipao at mvista.com>
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the
+- * Free Software Foundation; either version 2 of the License, or (at your
+- * option) any later version.
+- *
+- * 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/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/miscdevice.h>
+-#include <linux/init.h>
+-#include <linux/ioport.h>
+-#include <asm/uaccess.h>
+-#include <asm/addrspace.h>
+-#include <asm/it8172/it8172_int.h>
+-#include <linux/sched.h>
+-#include <linux/ite_gpio.h>
+-
+-#define ite_gpio_base 0x14013800
+-
+-#define ITE_GPADR (*(volatile __u8 *)(0x14013800 + KSEG1))
+-#define ITE_GPBDR (*(volatile __u8 *)(0x14013808 + KSEG1))
+-#define ITE_GPCDR (*(volatile __u8 *)(0x14013810 + KSEG1))
+-#define ITE_GPACR (*(volatile __u16 *)(0x14013802 + KSEG1))
+-#define ITE_GPBCR (*(volatile __u16 *)(0x1401380a + KSEG1))
+-#define ITE_GPCCR (*(volatile __u16 *)(0x14013812 + KSEG1))
+-#define ITE_GPAICR (*(volatile __u16 *)(0x14013804 + KSEG1))
+-#define ITE_GPBICR (*(volatile __u16 *)(0x1401380c + KSEG1))
+-#define ITE_GPCICR (*(volatile __u16 *)(0x14013814 + KSEG1))
+-#define ITE_GPAISR (*(volatile __u8 *)(0x14013806 + KSEG1))
+-#define ITE_GPBISR (*(volatile __u8 *)(0x1401380e + KSEG1))
+-#define ITE_GPCISR (*(volatile __u8 *)(0x14013816 + KSEG1))
+-#define ITE_GCR (*(volatile __u8 *)(0x14013818 + KSEG1))
+-
+-#define MAX_GPIO_LINE 21
+-static int ite_gpio_irq=IT8172_GPIO_IRQ;
+-
+-static long ite_irq_counter[MAX_GPIO_LINE];
+-wait_queue_head_t ite_gpio_wait[MAX_GPIO_LINE];
+-static int ite_gpio_irq_pending[MAX_GPIO_LINE];
+-
+-static int ite_gpio_debug=0;
+-#define DEB(x) if (ite_gpio_debug>=1) x
+-
+-int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data)
+-{
+- DEB(printk("ite_gpio_in mask=0x%x\n",mask));
+-
+- switch (device) {
+- case ITE_GPIO_PORTA:
+- ITE_GPACR = (__u16)mask; /* 0xffff */
+- *data = ITE_GPADR;
+- break;
+- case ITE_GPIO_PORTB:
+- ITE_GPBCR = (__u16)mask; /* 0xffff */
+- *data = ITE_GPBDR;
+- break;
+- case ITE_GPIO_PORTC:
+- ITE_GPCCR = (__u16)mask; /* 0x03ff */
+- *data = ITE_GPCDR;
+- break;
+- default:
+- return -EFAULT;
+- }
+-
+- return 0;
+-}
+-
+-
+-int ite_gpio_out(__u32 device, __u32 mask, __u32 data)
+-{
+- switch (device) {
+- case ITE_GPIO_PORTA:
+- ITE_GPACR = (__u16)mask; /* 0x5555 */
+- ITE_GPADR = (__u8)data;
+- break;
+- case ITE_GPIO_PORTB:
+- ITE_GPBCR = (__u16)mask; /* 0x5555 */
+- ITE_GPBDR = (__u8)data;
+- break;
+- case ITE_GPIO_PORTC:
+- ITE_GPCCR = (__u16)mask; /* 0x0155 */
+- ITE_GPCDR = (__u8)data;
+- break;
+- default:
+- return -EFAULT;
+- }
+-
+- return 0;
+-}
+-
+-int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data)
+-{
+- switch (device) {
+- case ITE_GPIO_PORTA:
+- ITE_GPAICR = (ITE_GPAICR & ~mask) | (data & mask);
+- break;
+- case ITE_GPIO_PORTB:
+- ITE_GPBICR = (ITE_GPBICR & ~mask) | (data & mask);
+- break;
+- case ITE_GPIO_PORTC:
+- ITE_GPCICR = (ITE_GPCICR & ~mask) | (data & mask);
+- break;
+- default:
+- return -EFAULT;
+- }
+-
+- return 0;
+-}
+-
+-int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data)
+-{
+- int ret=-1;
+-
+- if ((MAX_GPIO_LINE > *data) && (*data >= 0))
+- ret=ite_gpio_irq_pending[*data];
+-
+- DEB(printk("ite_gpio_in_status %d ret=%d\n",*data, ret));
+-
+- switch (device) {
+- case ITE_GPIO_PORTA:
+- *data = ITE_GPAISR & mask;
+- break;
+- case ITE_GPIO_PORTB:
+- *data = ITE_GPBISR & mask;
+- break;
+- case ITE_GPIO_PORTC:
+- *data = ITE_GPCISR & mask;
+- break;
+- default:
+- return -EFAULT;
+- }
+-
+- return ret;
+-}
+-
+-int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data)
+-{
+- switch (device) {
+- case ITE_GPIO_PORTA:
+- ITE_GPAISR = (ITE_GPAISR & ~mask) | (data & mask);
+- break;
+- case ITE_GPIO_PORTB:
+- ITE_GPBISR = (ITE_GPBISR & ~mask) | (data & mask);
+- break;
+- case ITE_GPIO_PORTC:
+- ITE_GPCISR = (ITE_GPCISR & ~mask) | (data & mask);
+- break;
+- default:
+- return -EFAULT;
+- }
+-
+- return 0;
+-}
+-
+-int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data)
+-{
+- ITE_GCR = (ITE_GCR & ~mask) | (data & mask);
+-
+- return 0;
+-}
+-
+-int ite_gpio_int_wait (__u32 device, __u32 mask, __u32 data)
+-{
+- int i,line=0, ret=0;
+- unsigned long flags;
+-
+- switch (device) {
+- case ITE_GPIO_PORTA:
+- line = data & mask;
+- break;
+- case ITE_GPIO_PORTB:
+- line = (data & mask) <<8;
+- break;
+- case ITE_GPIO_PORTC:
+- line = (data & mask) <<16;
+- break;
+- }
+- for (i=MAX_GPIO_LINE-1; i >= 0; i--) {
+- if ( (line) & (1 << i))
+- break;
+- }
+-
+- DEB(printk("wait device=0x%d mask=0x%x data=0x%x index %d\n",
+- device, mask, data, i));
+-
+- if (line & ~(1<<i))
+- return -EFAULT;
+-
+- if (ite_gpio_irq_pending[i]==1)
+- return -EFAULT;
+-
+- save_flags (flags);
+- cli();
+- ite_gpio_irq_pending[i] = 1;
+- ret = interruptible_sleep_on_timeout(&ite_gpio_wait[i], 3*HZ);
+- restore_flags (flags);
+- ite_gpio_irq_pending[i] = 0;
+-
+- return ret;
+-}
+-
+-EXPORT_SYMBOL(ite_gpio_in);
+-EXPORT_SYMBOL(ite_gpio_out);
+-EXPORT_SYMBOL(ite_gpio_int_ctrl);
+-EXPORT_SYMBOL(ite_gpio_in_status);
+-EXPORT_SYMBOL(ite_gpio_out_status);
+-EXPORT_SYMBOL(ite_gpio_gen_ctrl);
+-EXPORT_SYMBOL(ite_gpio_int_wait);
+-
+-static int ite_gpio_open(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-
+-static int ite_gpio_release(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-
+-static int ite_gpio_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- static struct ite_gpio_ioctl_data ioctl_data;
+-
+- if (copy_from_user(&ioctl_data, (struct ite_gpio_ioctl_data *)arg,
+- sizeof(ioctl_data)))
+- return -EFAULT;
+- if ((ioctl_data.device < ITE_GPIO_PORTA) ||
+- (ioctl_data.device > ITE_GPIO_PORTC) )
+- return -EFAULT;
+-
+- switch(cmd) {
+- case ITE_GPIO_IN:
+- if (ite_gpio_in(ioctl_data.device, ioctl_data.mask,
+- &ioctl_data.data))
+- return -EFAULT;
+-
+- if (copy_to_user((struct ite_gpio_ioctl_data *)arg,
+- &ioctl_data, sizeof(ioctl_data)))
+- return -EFAULT;
+- break;
+-
+- case ITE_GPIO_OUT:
+- return ite_gpio_out(ioctl_data.device,
+- ioctl_data.mask, ioctl_data.data);
+- break;
+-
+- case ITE_GPIO_INT_CTRL:
+- return ite_gpio_int_ctrl(ioctl_data.device,
+- ioctl_data.mask, ioctl_data.data);
+- break;
+-
+- case ITE_GPIO_IN_STATUS:
+- if (ite_gpio_in_status(ioctl_data.device, ioctl_data.mask,
+- &ioctl_data.data))
+- return -EFAULT;
+- if (copy_to_user((struct ite_gpio_ioctl_data *)arg,
+- &ioctl_data, sizeof(ioctl_data)))
+- return -EFAULT;
+- break;
+-
+- case ITE_GPIO_OUT_STATUS:
+- return ite_gpio_out_status(ioctl_data.device,
+- ioctl_data.mask, ioctl_data.data);
+- break;
+-
+- case ITE_GPIO_GEN_CTRL:
+- return ite_gpio_gen_ctrl(ioctl_data.device,
+- ioctl_data.mask, ioctl_data.data);
+- break;
+-
+- case ITE_GPIO_INT_WAIT:
+- return ite_gpio_int_wait(ioctl_data.device,
+- ioctl_data.mask, ioctl_data.data);
+- break;
+-
+- default:
+- return -ENOIOCTLCMD;
+-
+- }
+-
+- return 0;
+-}
+-
+-static void ite_gpio_irq_handler(int this_irq, void *dev_id,
+- struct pt_regs *regs)
+-{
+- int i,line;
+-
+- line = ITE_GPCISR & 0x1f;
+- for (i=4; i >=0; i--) {
+- if ( line & (1 << i)) {
+- ++ite_irq_counter[i+16];
+- ite_gpio_irq_pending[i+16] = 2;
+- wake_up_interruptible(&ite_gpio_wait[i+16]);
+-
+-DEB(printk("interrupt 0x%x %d\n", &ite_gpio_wait[i+16], i+16));
+-
+- ITE_GPCISR = ITE_GPCISR & (1<<i);
+- return;
+- }
+- }
+- line = ITE_GPBISR;
+- for (i=7; i >= 0; i--) {
+- if ( line & (1 << i)) {
+- ++ite_irq_counter[i+8];
+- ite_gpio_irq_pending[i+8] = 2;
+- wake_up_interruptible(&ite_gpio_wait[i+8]);
+-
+-DEB(printk("interrupt 0x%x %d\n",ITE_GPBISR, i+8));
+-
+- ITE_GPBISR = ITE_GPBISR & (1<<i);
+- return;
+- }
+- }
+- line = ITE_GPAISR;
+- for (i=7; i >= 0; i--) {
+- if ( line & (1 << i)) {
+- ++ite_irq_counter[i];
+- ite_gpio_irq_pending[i] = 2;
+- wake_up_interruptible(&ite_gpio_wait[i]);
+-
+-DEB(printk("interrupt 0x%x %d\n",ITE_GPAISR, i));
+-
+- ITE_GPAISR = ITE_GPAISR & (1<<i);
+- return;
+- }
+- }
+-}
+-
+-static const struct file_operations ite_gpio_fops = {
+- .owner = THIS_MODULE,
+- .ioctl = ite_gpio_ioctl,
+- .open = ite_gpio_open,
+- .release = ite_gpio_release,
+-};
+-
+-static struct miscdevice ite_gpio_miscdev = {
+- MISC_DYNAMIC_MINOR,
+- "ite_gpio",
+- &ite_gpio_fops
+-};
+-
+-int __init ite_gpio_init(void)
+-{
+- int i;
+-
+- if (misc_register(&ite_gpio_miscdev))
+- return -ENODEV;
+-
+- if (!request_region(ite_gpio_base, 0x1c, "ITE GPIO"))
+- {
+- misc_deregister(&ite_gpio_miscdev);
+- return -EIO;
+- }
+-
+- /* initialize registers */
+- ITE_GPACR = 0xffff;
+- ITE_GPBCR = 0xffff;
+- ITE_GPCCR = 0xffff;
+- ITE_GPAICR = 0x00ff;
+- ITE_GPBICR = 0x00ff;
+- ITE_GPCICR = 0x00ff;
+- ITE_GCR = 0;
+-
+- for (i = 0; i < MAX_GPIO_LINE; i++) {
+- ite_gpio_irq_pending[i]=0;
+- init_waitqueue_head(&ite_gpio_wait[i]);
+- }
+-
+- if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, IRQF_SHARED, "gpio", 0) < 0) {
+- misc_deregister(&ite_gpio_miscdev);
+- release_region(ite_gpio_base, 0x1c);
+- return 0;
+- }
+-
+- printk("GPIO at 0x%x (irq = %d)\n", ite_gpio_base, ite_gpio_irq);
+-
+- return 0;
+-}
+-
+-static void __exit ite_gpio_exit(void)
+-{
+- misc_deregister(&ite_gpio_miscdev);
+-}
+-
+-module_init(ite_gpio_init);
+-module_exit(ite_gpio_exit);
+-
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
+index 3e90aac..20b6c8b 100644
+--- a/drivers/char/keyboard.c
++++ b/drivers/char/keyboard.c
+@@ -32,6 +32,7 @@
+ #include <linux/string.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
++#include <linux/irq.h>
+
+ #include <linux/kbd_kern.h>
+ #include <linux/kbd_diacr.h>
+@@ -77,7 +78,7 @@ void compute_shiftstate(void);
+ k_slock, k_dead2, k_brl, k_ignore
+
+ typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
+- char up_flag, struct pt_regs *regs);
++ char up_flag);
+ static k_handler_fn K_HANDLERS;
+ static k_handler_fn *k_handler[16] = { K_HANDLERS };
+
+@@ -88,7 +89,7 @@ static k_handler_fn *k_handler[16] = { K
+ fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\
+ fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num
+
+-typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs);
++typedef void (fn_handler_fn)(struct vc_data *vc);
+ static fn_handler_fn FN_HANDLERS;
+ static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
+
+@@ -108,7 +109,11 @@ const int NR_TYPES = ARRAY_SIZE(max_vals
+ struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+ static struct kbd_struct *kbd = kbd_table;
+
+-int spawnpid, spawnsig;
++struct vt_spawn_console vt_spawn_con = {
++ .lock = SPIN_LOCK_UNLOCKED,
++ .pid = NULL,
++ .sig = 0,
++};
+
+ /*
+ * Variables exported for vt.c
+@@ -424,7 +429,7 @@ static unsigned int handle_diacr(struct
+ /*
+ * Special function handlers
+ */
+-static void fn_enter(struct vc_data *vc, struct pt_regs *regs)
++static void fn_enter(struct vc_data *vc)
+ {
+ if (diacr) {
+ if (kbd->kbdmode == VC_UNICODE)
+@@ -438,27 +443,28 @@ static void fn_enter(struct vc_data *vc,
+ put_queue(vc, 10);
+ }
+
+-static void fn_caps_toggle(struct vc_data *vc, struct pt_regs *regs)
++static void fn_caps_toggle(struct vc_data *vc)
+ {
+ if (rep)
+ return;
+ chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+ }
+
+-static void fn_caps_on(struct vc_data *vc, struct pt_regs *regs)
++static void fn_caps_on(struct vc_data *vc)
+ {
+ if (rep)
+ return;
+ set_vc_kbd_led(kbd, VC_CAPSLOCK);
+ }
+
+-static void fn_show_ptregs(struct vc_data *vc, struct pt_regs *regs)
++static void fn_show_ptregs(struct vc_data *vc)
+ {
++ struct pt_regs *regs = get_irq_regs();
+ if (regs)
+ show_regs(regs);
+ }
+
+-static void fn_hold(struct vc_data *vc, struct pt_regs *regs)
++static void fn_hold(struct vc_data *vc)
+ {
+ struct tty_struct *tty = vc->vc_tty;
+
+@@ -476,12 +482,12 @@ static void fn_hold(struct vc_data *vc,
+ stop_tty(tty);
+ }
+
+-static void fn_num(struct vc_data *vc, struct pt_regs *regs)
++static void fn_num(struct vc_data *vc)
+ {
+ if (vc_kbd_mode(kbd,VC_APPLIC))
+ applkey(vc, 'P', 1);
+ else
+- fn_bare_num(vc, regs);
++ fn_bare_num(vc);
+ }
+
+ /*
+@@ -490,19 +496,19 @@ static void fn_num(struct vc_data *vc, s
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+-static void fn_bare_num(struct vc_data *vc, struct pt_regs *regs)
++static void fn_bare_num(struct vc_data *vc)
+ {
+ if (!rep)
+ chg_vc_kbd_led(kbd, VC_NUMLOCK);
+ }
+
+-static void fn_lastcons(struct vc_data *vc, struct pt_regs *regs)
++static void fn_lastcons(struct vc_data *vc)
+ {
+ /* switch to the last used console, ChN */
+ set_console(last_console);
+ }
+
+-static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs)
++static void fn_dec_console(struct vc_data *vc)
+ {
+ int i, cur = fg_console;
+
+@@ -519,7 +525,7 @@ static void fn_dec_console(struct vc_dat
+ set_console(i);
+ }
+
+-static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs)
++static void fn_inc_console(struct vc_data *vc)
+ {
+ int i, cur = fg_console;
+
+@@ -536,7 +542,7 @@ static void fn_inc_console(struct vc_dat
+ set_console(i);
+ }
+
+-static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs)
++static void fn_send_intr(struct vc_data *vc)
+ {
+ struct tty_struct *tty = vc->vc_tty;
+
+@@ -546,44 +552,48 @@ static void fn_send_intr(struct vc_data
+ con_schedule_flip(tty);
+ }
+
+-static void fn_scroll_forw(struct vc_data *vc, struct pt_regs *regs)
++static void fn_scroll_forw(struct vc_data *vc)
+ {
+ scrollfront(vc, 0);
+ }
+
+-static void fn_scroll_back(struct vc_data *vc, struct pt_regs *regs)
++static void fn_scroll_back(struct vc_data *vc)
+ {
+ scrollback(vc, 0);
+ }
+
+-static void fn_show_mem(struct vc_data *vc, struct pt_regs *regs)
++static void fn_show_mem(struct vc_data *vc)
+ {
+ show_mem();
+ }
+
+-static void fn_show_state(struct vc_data *vc, struct pt_regs *regs)
++static void fn_show_state(struct vc_data *vc)
+ {
+ show_state();
+ }
+
+-static void fn_boot_it(struct vc_data *vc, struct pt_regs *regs)
++static void fn_boot_it(struct vc_data *vc)
+ {
+ ctrl_alt_del();
+ }
+
+-static void fn_compose(struct vc_data *vc, struct pt_regs *regs)
++static void fn_compose(struct vc_data *vc)
+ {
+ dead_key_next = 1;
+ }
+
+-static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs)
++static void fn_spawn_con(struct vc_data *vc)
+ {
+- if (spawnpid)
+- if (kill_proc(spawnpid, spawnsig, 1))
+- spawnpid = 0;
++ spin_lock(&vt_spawn_con.lock);
++ if (vt_spawn_con.pid)
++ if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
++ put_pid(vt_spawn_con.pid);
++ vt_spawn_con.pid = NULL;
++ }
++ spin_unlock(&vt_spawn_con.lock);
+ }
+
+-static void fn_SAK(struct vc_data *vc, struct pt_regs *regs)
++static void fn_SAK(struct vc_data *vc)
+ {
+ struct tty_struct *tty = vc->vc_tty;
+
+@@ -596,7 +606,7 @@ static void fn_SAK(struct vc_data *vc, s
+ reset_vc(vc);
+ }
+
+-static void fn_null(struct vc_data *vc, struct pt_regs *regs)
++static void fn_null(struct vc_data *vc)
+ {
+ compute_shiftstate();
+ }
+@@ -604,11 +614,11 @@ static void fn_null(struct vc_data *vc,
+ /*
+ * Special key handlers
+ */
+-static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ }
+
+-static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ if (up_flag)
+ return;
+@@ -618,15 +628,15 @@ static void k_spec(struct vc_data *vc, u
+ kbd->kbdmode == VC_MEDIUMRAW) &&
+ value != KVAL(K_SAK))
+ return; /* SAK is allowed even in raw mode */
+- fn_handler[value](vc, regs);
++ fn_handler[value](vc);
+ }
+
+-static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n");
+ }
+
+-static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs)
++static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
+ {
+ if (up_flag)
+ return; /* no action, if this is a key release */
+@@ -650,41 +660,41 @@ static void k_unicode(struct vc_data *vc
+ * dead keys modifying the same character. Very useful
+ * for Vietnamese.
+ */
+-static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs)
++static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
+ {
+ if (up_flag)
+ return;
+ diacr = (diacr ? handle_diacr(vc, value) : value);
+ }
+
+-static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+- k_unicode(vc, value, up_flag, regs);
++ k_unicode(vc, value, up_flag);
+ }
+
+-static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+- k_deadunicode(vc, value, up_flag, regs);
++ k_deadunicode(vc, value, up_flag);
+ }
+
+ /*
+ * Obsolete - for backwards compatibility only
+ */
+-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+ value = ret_diacr[value];
+- k_deadunicode(vc, value, up_flag, regs);
++ k_deadunicode(vc, value, up_flag);
+ }
+
+-static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ if (up_flag)
+ return;
+ set_console(value);
+ }
+
+-static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ unsigned v;
+
+@@ -698,7 +708,7 @@ static void k_fn(struct vc_data *vc, uns
+ printk(KERN_ERR "k_fn called with value=%d\n", value);
+ }
+
+-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ static const char *cur_chars = "BDCA";
+
+@@ -707,7 +717,7 @@ static void k_cur(struct vc_data *vc, un
+ applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+ }
+
+-static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ static const char pad_chars[] = "0123456789+-*/\015,.?()#";
+ static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
+@@ -725,34 +735,34 @@ static void k_pad(struct vc_data *vc, un
+ switch (value) {
+ case KVAL(K_PCOMMA):
+ case KVAL(K_PDOT):
+- k_fn(vc, KVAL(K_REMOVE), 0, regs);
++ k_fn(vc, KVAL(K_REMOVE), 0);
+ return;
+ case KVAL(K_P0):
+- k_fn(vc, KVAL(K_INSERT), 0, regs);
++ k_fn(vc, KVAL(K_INSERT), 0);
+ return;
+ case KVAL(K_P1):
+- k_fn(vc, KVAL(K_SELECT), 0, regs);
++ k_fn(vc, KVAL(K_SELECT), 0);
+ return;
+ case KVAL(K_P2):
+- k_cur(vc, KVAL(K_DOWN), 0, regs);
++ k_cur(vc, KVAL(K_DOWN), 0);
+ return;
+ case KVAL(K_P3):
+- k_fn(vc, KVAL(K_PGDN), 0, regs);
++ k_fn(vc, KVAL(K_PGDN), 0);
+ return;
+ case KVAL(K_P4):
+- k_cur(vc, KVAL(K_LEFT), 0, regs);
++ k_cur(vc, KVAL(K_LEFT), 0);
+ return;
+ case KVAL(K_P6):
+- k_cur(vc, KVAL(K_RIGHT), 0, regs);
++ k_cur(vc, KVAL(K_RIGHT), 0);
+ return;
+ case KVAL(K_P7):
+- k_fn(vc, KVAL(K_FIND), 0, regs);
++ k_fn(vc, KVAL(K_FIND), 0);
+ return;
+ case KVAL(K_P8):
+- k_cur(vc, KVAL(K_UP), 0, regs);
++ k_cur(vc, KVAL(K_UP), 0);
+ return;
+ case KVAL(K_P9):
+- k_fn(vc, KVAL(K_PGUP), 0, regs);
++ k_fn(vc, KVAL(K_PGUP), 0);
+ return;
+ case KVAL(K_P5):
+ applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
+@@ -764,7 +774,7 @@ static void k_pad(struct vc_data *vc, un
+ put_queue(vc, 10);
+ }
+
+-static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ int old_state = shift_state;
+
+@@ -805,7 +815,7 @@ static void k_shift(struct vc_data *vc,
+ }
+ }
+
+-static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ if (up_flag)
+ return;
+@@ -817,7 +827,7 @@ static void k_meta(struct vc_data *vc, u
+ put_queue(vc, value | 0x80);
+ }
+
+-static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ int base;
+
+@@ -839,16 +849,16 @@ static void k_ascii(struct vc_data *vc,
+ npadch = npadch * base + value;
+ }
+
+-static void k_lock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ if (up_flag || rep)
+ return;
+ chg_vc_kbd_lock(kbd, value);
+ }
+
+-static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+- k_shift(vc, value, up_flag, regs);
++ k_shift(vc, value, up_flag);
+ if (up_flag || rep)
+ return;
+ chg_vc_kbd_slock(kbd, value);
+@@ -868,25 +878,25 @@ static unsigned brl_nbchords = 1;
+ MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
+ module_param(brl_nbchords, uint, 0644);
+
+-static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs)
++static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
+ {
+ static unsigned long chords;
+ static unsigned committed;
+
+ if (!brl_nbchords)
+- k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs);
++ k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
+ else {
+ committed |= pattern;
+ chords++;
+ if (chords == brl_nbchords) {
+- k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs);
++ k_unicode(vc, BRL_UC_ROW | committed, up_flag);
+ chords = 0;
+ committed = 0;
+ }
+ }
+ }
+
+-static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
++static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
+ {
+ static unsigned pressed,committing;
+ static unsigned long releasestart;
+@@ -898,7 +908,7 @@ static void k_brl(struct vc_data *vc, un
+ }
+
+ if (!value) {
+- k_unicode(vc, BRL_UC_ROW, up_flag, regs);
++ k_unicode(vc, BRL_UC_ROW, up_flag);
+ return;
+ }
+
+@@ -915,13 +925,13 @@ static void k_brl(struct vc_data *vc, un
+ pressed &= ~(1 << (value - 1));
+ if (!pressed) {
+ if (committing) {
+- k_brlcommit(vc, committing, 0, regs);
++ k_brlcommit(vc, committing, 0);
+ committing = 0;
+ }
+ }
+ } else {
+ if (committing) {
+- k_brlcommit(vc, committing, 0, regs);
++ k_brlcommit(vc, committing, 0);
+ committing = 0;
+ }
+ pressed &= ~(1 << (value - 1));
+@@ -1125,8 +1135,7 @@ static void kbd_rawcode(unsigned char da
+ put_queue(vc, data);
+ }
+
+-static void kbd_keycode(unsigned int keycode, int down,
+- int hw_raw, struct pt_regs *regs)
++static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+ {
+ struct vc_data *vc = vc_cons[fg_console].d;
+ unsigned short keysym, *key_map;
+@@ -1173,7 +1182,7 @@ static void kbd_keycode(unsigned int key
+ if (sysrq_down && !down && keycode == sysrq_alt_use)
+ sysrq_down = 0;
+ if (sysrq_down && down && !rep) {
+- handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
++ handle_sysrq(kbd_sysrq_xlate[keycode], tty);
+ return;
+ }
+ #endif
+@@ -1259,7 +1268,7 @@ static void kbd_keycode(unsigned int key
+ }
+ }
+
+- (*k_handler[type])(vc, keysym & 0xff, !down, regs);
++ (*k_handler[type])(vc, keysym & 0xff, !down);
+
+ if (type != KT_SLOCK)
+ kbd->slockstate = 0;
+@@ -1271,7 +1280,7 @@ static void kbd_event(struct input_handl
+ if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
+ kbd_rawcode(value);
+ if (event_type == EV_KEY)
+- kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs);
++ kbd_keycode(event_code, value, HW_RAW(handle->dev));
+ tasklet_schedule(&keyboard_tasklet);
+ do_poke_blanked_console = 1;
+ schedule_console_callback();
+@@ -1285,7 +1294,7 @@ static void kbd_event(struct input_handl
+ */
+ static struct input_handle *kbd_connect(struct input_handler *handler,
+ struct input_dev *dev,
+- struct input_device_id *id)
++ const struct input_device_id *id)
+ {
+ struct input_handle *handle;
+ int i;
+@@ -1334,7 +1343,7 @@ static void kbd_start(struct input_handl
+ tasklet_enable(&keyboard_tasklet);
+ }
+
+-static struct input_device_id kbd_ids[] = {
++static const struct input_device_id kbd_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT(EV_KEY) },
+@@ -1362,6 +1371,7 @@ static struct input_handler kbd_handler
+ int __init kbd_init(void)
+ {
+ int i;
++ int error;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ kbd_table[i].ledflagstate = KBD_DEFLEDS;
+@@ -1373,7 +1383,9 @@ int __init kbd_init(void)
+ kbd_table[i].kbdmode = VC_XLATE;
+ }
+
+- input_register_handler(&kbd_handler);
++ error = input_register_handler(&kbd_handler);
++ if (error)
++ return error;
+
+ tasklet_enable(&keyboard_tasklet);
+ tasklet_schedule(&keyboard_tasklet);
+diff --git a/drivers/char/lp.c b/drivers/char/lp.c
+index f875fda..1ecea7d 100644
+--- a/drivers/char/lp.c
++++ b/drivers/char/lp.c
+@@ -906,7 +906,7 @@ static int __init lp_init (void)
+ lp_class = class_create(THIS_MODULE, "printer");
+ if (IS_ERR(lp_class)) {
+ err = PTR_ERR(lp_class);
+- goto out_devfs;
++ goto out_reg;
+ }
+
+ if (parport_register_driver (&lp_driver)) {
+@@ -927,7 +927,7 @@ static int __init lp_init (void)
+
+ out_class:
+ class_destroy(lp_class);
+-out_devfs:
++out_reg:
+ unregister_chrdev(LP_MAJOR, "lp");
+ return err;
+ }
+diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
+index 0385650..0afb7ba 100644
+--- a/drivers/char/mbcs.c
++++ b/drivers/char/mbcs.c
+@@ -22,6 +22,7 @@
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/mm.h>
++#include <linux/fs.h>
+ #include <linux/uio.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -447,15 +448,15 @@ loff_t mbcs_sram_llseek(struct file * fi
+ loff_t newpos;
+
+ switch (whence) {
+- case 0: /* SEEK_SET */
++ case SEEK_SET:
+ newpos = off;
+ break;
+
+- case 1: /* SEEK_CUR */
++ case SEEK_CUR:
+ newpos = filp->f_pos + off;
+ break;
+
+- case 2: /* SEEK_END */
++ case SEEK_END:
+ newpos = MBCS_SRAM_SIZE + off;
+ break;
+
+@@ -515,11 +516,10 @@ int mbcs_gscr_mmap(struct file *fp, stru
+ * mbcs_completion_intr_handler - Primary completion handler.
+ * @irq: irq
+ * @arg: soft struct for device
+- * @ep: regs
+ *
+ */
+ static irqreturn_t
+-mbcs_completion_intr_handler(int irq, void *arg, struct pt_regs *ep)
++mbcs_completion_intr_handler(int irq, void *arg)
+ {
+ struct mbcs_soft *soft = (struct mbcs_soft *)arg;
+ void *mmr_base;
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index 917b204..5547337 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -26,6 +26,7 @@
+ #include <linux/backing-dev.h>
+ #include <linux/bootmem.h>
+ #include <linux/pipe_fs_i.h>
++#include <linux/pfn.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -238,6 +239,32 @@ static pgprot_t phys_mem_access_prot(str
+ }
+ #endif
+
++#ifndef CONFIG_MMU
++static unsigned long get_unmapped_area_mem(struct file *file,
++ unsigned long addr,
++ unsigned long len,
++ unsigned long pgoff,
++ unsigned long flags)
++{
++ if (!valid_mmap_phys_addr_range(pgoff, len))
++ return (unsigned long) -EINVAL;
++ return pgoff;
++}
++
++/* can't do an in-place private mapping if there's no MMU */
++static inline int private_mapping_ok(struct vm_area_struct *vma)
++{
++ return vma->vm_flags & VM_MAYSHARE;
++}
++#else
++#define get_unmapped_area_mem NULL
++
++static inline int private_mapping_ok(struct vm_area_struct *vma)
++{
++ return 1;
++}
++#endif
++
+ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+ {
+ size_t size = vma->vm_end - vma->vm_start;
+@@ -245,6 +272,9 @@ static int mmap_mem(struct file * file,
+ if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
+ return -EINVAL;
+
++ if (!private_mapping_ok(vma))
++ return -ENOSYS;
++
+ vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
+ size,
+ vma->vm_page_prot);
+@@ -263,8 +293,8 @@ static int mmap_kmem(struct file * file,
+ {
+ unsigned long pfn;
+
+- /* Turn a kernel-virtual address into a physical page frame */
+- pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
++ /* Turn a pfn offset into an absolute pfn */
++ pfn = PFN_DOWN(virt_to_phys((void *)PAGE_OFFSET)) + vma->vm_pgoff;
+
+ /*
+ * RED-PEN: on some architectures there is more mapped memory
+@@ -522,7 +552,7 @@ static ssize_t write_kmem(struct file *
+ return virtr + wrote;
+ }
+
+-#if defined(CONFIG_ISA) || !defined(__mc68000__)
++#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+ static ssize_t read_port(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+ {
+@@ -782,6 +812,7 @@ static const struct file_operations mem_
+ .write = write_mem,
+ .mmap = mmap_mem,
+ .open = open_mem,
++ .get_unmapped_area = get_unmapped_area_mem,
+ };
+
+ static const struct file_operations kmem_fops = {
+@@ -790,6 +821,7 @@ static const struct file_operations kmem
+ .write = write_kmem,
+ .mmap = mmap_kmem,
+ .open = open_kmem,
++ .get_unmapped_area = get_unmapped_area_mem,
+ };
+
+ static const struct file_operations null_fops = {
+@@ -799,7 +831,7 @@ static const struct file_operations null
+ .splice_write = splice_write_null,
+ };
+
+-#if defined(CONFIG_ISA) || !defined(__mc68000__)
++#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+ static const struct file_operations port_fops = {
+ .llseek = memory_lseek,
+ .read = read_port,
+@@ -815,6 +847,10 @@ static const struct file_operations zero
+ .mmap = mmap_zero,
+ };
+
++/*
++ * capabilities for /dev/zero
++ * - permits private mappings, "copies" are taken of the source of zeros
++ */
+ static struct backing_dev_info zero_bdi = {
+ .capabilities = BDI_CAP_MAP_COPY,
+ };
+@@ -862,14 +898,18 @@ static int memory_open(struct inode * in
+ switch (iminor(inode)) {
+ case 1:
+ filp->f_op = &mem_fops;
++ filp->f_mapping->backing_dev_info =
++ &directly_mappable_cdev_bdi;
+ break;
+ case 2:
+ filp->f_op = &kmem_fops;
++ filp->f_mapping->backing_dev_info =
++ &directly_mappable_cdev_bdi;
+ break;
+ case 3:
+ filp->f_op = &null_fops;
+ break;
+-#if defined(CONFIG_ISA) || !defined(__mc68000__)
++#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+ case 4:
+ filp->f_op = &port_fops;
+ break;
+@@ -916,7 +956,7 @@ static const struct {
+ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
+ {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
+ {3, "null", S_IRUGO | S_IWUGO, &null_fops},
+-#if defined(CONFIG_ISA) || !defined(__mc68000__)
++#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+ {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
+ #endif
+ {5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
+diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
+index 1f0f2b6..22b9905 100644
+--- a/drivers/char/mmtimer.c
++++ b/drivers/char/mmtimer.c
+@@ -422,7 +422,6 @@ static int inline reschedule_periodic_ti
+ * mmtimer_interrupt - timer interrupt handler
+ * @irq: irq received
+ * @dev_id: device the irq came from
+- * @regs: register state upon receipt of the interrupt
+ *
+ * Called when one of the comarators matches the counter, This
+ * routine will send signals to processes that have requested
+@@ -433,7 +432,7 @@ static int inline reschedule_periodic_ti
+ * registers.
+ */
+ static irqreturn_t
+-mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++mmtimer_interrupt(int irq, void *dev_id)
+ {
+ int i;
+ unsigned long expires = 0;
+diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
+index a369dd6..96cb1f0 100644
+--- a/drivers/char/moxa.c
++++ b/drivers/char/moxa.c
+@@ -130,6 +130,7 @@ static moxa_isa_board_conf moxa_isa_boar
+ typedef struct _moxa_pci_devinfo {
+ ushort busNum;
+ ushort devNum;
++ struct pci_dev *pdev;
+ } moxa_pci_devinfo;
+
+ typedef struct _moxa_board_conf {
+@@ -260,7 +261,7 @@ static void MoxaPortEnable(int);
+ static void MoxaPortDisable(int);
+ static long MoxaPortGetMaxBaud(int);
+ static long MoxaPortSetBaud(int, long);
+-static int MoxaPortSetTermio(int, struct termios *);
++static int MoxaPortSetTermio(int, struct termios *, speed_t);
+ static int MoxaPortGetLineOut(int, int *, int *);
+ static void MoxaPortLineCtrl(int, int, int);
+ static void MoxaPortFlowCtrl(int, int, int, int, int, int);
+@@ -281,7 +282,7 @@ static int moxa_get_serial_info(struct m
+ static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *);
+ static void MoxaSetFifo(int port, int enable);
+
+-static struct tty_operations moxa_ops = {
++static const struct tty_operations moxa_ops = {
+ .open = moxa_open,
+ .close = moxa_close,
+ .write = moxa_write,
+@@ -324,6 +325,9 @@ static int moxa_get_PCI_conf(struct pci_
+ board->busType = MOXA_BUS_TYPE_PCI;
+ board->pciInfo.busNum = p->bus->number;
+ board->pciInfo.devNum = p->devfn >> 3;
++ board->pciInfo.pdev = p;
++ /* don't lose the reference in the next pci_get_device iteration */
++ pci_dev_get(p);
+
+ return (0);
+ }
+@@ -493,6 +497,11 @@ static void __exit moxa_exit(void)
+ if (tty_unregister_driver(moxaDriver))
+ printk("Couldn't unregister MOXA Intellio family serial driver\n");
+ put_tty_driver(moxaDriver);
++
++ for (i = 0; i < MAX_BOARDS; i++)
++ if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI)
++ pci_dev_put(moxa_boards[i].pciInfo.pdev);
++
+ if (verbose)
+ printk("Done\n");
+ }
+@@ -986,7 +995,7 @@ static void set_tty_param(struct tty_str
+ if (ts->c_iflag & IXANY)
+ xany = 1;
+ MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
+- MoxaPortSetTermio(ch->port, ts);
++ MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
+ }
+
+ static int block_till_ready(struct tty_struct *tty, struct file *filp,
+@@ -1900,9 +1909,10 @@ int MoxaPortsOfCard(int cardno)
+ *
+ * Function 12: Configure the port.
+ * Syntax:
+- * int MoxaPortSetTermio(int port, struct termios *termio);
++ * int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud);
+ * int port : port number (0 - 127)
+ * struct termios * termio : termio structure pointer
++ * speed_t baud : baud rate
+ *
+ * return: -1 : this port is invalid or termio == NULL
+ * 0 : setting O.K.
+@@ -2182,11 +2192,10 @@ long MoxaPortSetBaud(int port, long baud
+ return (baud);
+ }
+
+-int MoxaPortSetTermio(int port, struct termios *termio)
++int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud)
+ {
+ void __iomem *ofsAddr;
+ tcflag_t cflag;
+- long baud;
+ tcflag_t mode = 0;
+
+ if (moxaChkPort[port] == 0 || termio == 0)
+@@ -2222,77 +2231,9 @@ int MoxaPortSetTermio(int port, struct t
+
+ moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+
+- cflag &= (CBAUD | CBAUDEX);
+-#ifndef B921600
+-#define B921600 (B460800+1)
+-#endif
+- switch (cflag) {
+- case B921600:
+- baud = 921600L;
+- break;
+- case B460800:
+- baud = 460800L;
+- break;
+- case B230400:
+- baud = 230400L;
+- break;
+- case B115200:
+- baud = 115200L;
+- break;
+- case B57600:
+- baud = 57600L;
+- break;
+- case B38400:
+- baud = 38400L;
+- break;
+- case B19200:
+- baud = 19200L;
+- break;
+- case B9600:
+- baud = 9600L;
+- break;
+- case B4800:
+- baud = 4800L;
+- break;
+- case B2400:
+- baud = 2400L;
+- break;
+- case B1800:
+- baud = 1800L;
+- break;
+- case B1200:
+- baud = 1200L;
+- break;
+- case B600:
+- baud = 600L;
+- break;
+- case B300:
+- baud = 300L;
+- break;
+- case B200:
+- baud = 200L;
+- break;
+- case B150:
+- baud = 150L;
+- break;
+- case B134:
+- baud = 134L;
+- break;
+- case B110:
+- baud = 110L;
+- break;
+- case B75:
+- baud = 75L;
+- break;
+- case B50:
+- baud = 50L;
+- break;
+- default:
+- baud = 0;
+- }
+ if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+ (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+- if (baud == 921600L)
++ if (baud >= 921600L)
+ return (-1);
+ }
+ MoxaPortSetBaud(port, baud);
+diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
+new file mode 100644
+index 0000000..5c0dec3
+--- /dev/null
++++ b/drivers/char/mspec.c
+@@ -0,0 +1,420 @@
++/*
++ * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights
++ * reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License
++ * as published by the Free Software Foundation.
++ */
++
++/*
++ * SN Platform Special Memory (mspec) Support
++ *
++ * This driver exports the SN special memory (mspec) facility to user
++ * processes.
++ * There are three types of memory made available thru this driver:
++ * fetchops, uncached and cached.
++ *
++ * Fetchops are atomic memory operations that are implemented in the
++ * memory controller on SGI SN hardware.
++ *
++ * Uncached are used for memory write combining feature of the ia64
++ * cpu.
++ *
++ * Cached are used for areas of memory that are used as cached addresses
++ * on our partition and used as uncached addresses from other partitions.
++ * Due to a design constraint of the SN2 Shub, you can not have processors
++ * on the same FSB perform both a cached and uncached reference to the
++ * same cache line. These special memory cached regions prevent the
++ * kernel from ever dropping in a TLB entry and therefore prevent the
++ * processor from ever speculating a cache line from this page.
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/miscdevice.h>
++#include <linux/spinlock.h>
++#include <linux/mm.h>
++#include <linux/vmalloc.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/numa.h>
++#include <asm/page.h>
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/atomic.h>
++#include <asm/tlbflush.h>
++#include <asm/uncached.h>
++#include <asm/sn/addrs.h>
++#include <asm/sn/arch.h>
++#include <asm/sn/mspec.h>
++#include <asm/sn/sn_cpuid.h>
++#include <asm/sn/io.h>
++#include <asm/sn/bte.h>
++#include <asm/sn/shubio.h>
++
++
++#define FETCHOP_ID "SGI Fetchop,"
++#define CACHED_ID "Cached,"
++#define UNCACHED_ID "Uncached"
++#define REVISION "4.0"
++#define MSPEC_BASENAME "mspec"
++
++/*
++ * Page types allocated by the device.
++ */
++enum {
++ MSPEC_FETCHOP = 1,
++ MSPEC_CACHED,
++ MSPEC_UNCACHED
++};
++
++static int is_sn2;
++
++/*
++ * One of these structures is allocated when an mspec region is mmaped. The
++ * structure is pointed to by the vma->vm_private_data field in the vma struct.
++ * This structure is used to record the addresses of the mspec pages.
++ */
++struct vma_data {
++ atomic_t refcnt; /* Number of vmas sharing the data. */
++ spinlock_t lock; /* Serialize access to the vma. */
++ int count; /* Number of pages allocated. */
++ int type; /* Type of pages allocated. */
++ unsigned long maddr[0]; /* Array of MSPEC addresses. */
++};
++
++/* used on shub2 to clear FOP cache in the HUB */
++static unsigned long scratch_page[MAX_NUMNODES];
++#define SH2_AMO_CACHE_ENTRIES 4
++
++static inline int
++mspec_zero_block(unsigned long addr, int len)
++{
++ int status;
++
++ if (is_sn2) {
++ if (is_shub2()) {
++ int nid;
++ void *p;
++ int i;
++
++ nid = nasid_to_cnodeid(get_node_number(__pa(addr)));
++ p = (void *)TO_AMO(scratch_page[nid]);
++
++ for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) {
++ FETCHOP_LOAD_OP(p, FETCHOP_LOAD);
++ p += FETCHOP_VAR_SIZE;
++ }
++ }
++
++ status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len,
++ BTE_WACQUIRE | BTE_ZERO_FILL, NULL);
++ } else {
++ memset((char *) addr, 0, len);
++ status = 0;
++ }
++ return status;
++}
++
++/*
++ * mspec_open
++ *
++ * Called when a device mapping is created by a means other than mmap
++ * (via fork, etc.). Increments the reference count on the underlying
++ * mspec data so it is not freed prematurely.
++ */
++static void
++mspec_open(struct vm_area_struct *vma)
++{
++ struct vma_data *vdata;
++
++ vdata = vma->vm_private_data;
++ atomic_inc(&vdata->refcnt);
++}
++
++/*
++ * mspec_close
++ *
++ * Called when unmapping a device mapping. Frees all mspec pages
++ * belonging to the vma.
++ */
++static void
++mspec_close(struct vm_area_struct *vma)
++{
++ struct vma_data *vdata;
++ int i, pages, result, vdata_size;
++
++ vdata = vma->vm_private_data;
++ if (!atomic_dec_and_test(&vdata->refcnt))
++ return;
++
++ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++ vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
++ for (i = 0; i < pages; i++) {
++ if (vdata->maddr[i] == 0)
++ continue;
++ /*
++ * Clear the page before sticking it back
++ * into the pool.
++ */
++ result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE);
++ if (!result)
++ uncached_free_page(vdata->maddr[i]);
++ else
++ printk(KERN_WARNING "mspec_close(): "
++ "failed to zero page %i\n",
++ result);
++ }
++
++ if (vdata_size <= PAGE_SIZE)
++ kfree(vdata);
++ else
++ vfree(vdata);
++}
++
++
++/*
++ * mspec_nopfn
++ *
++ * Creates a mspec page and maps it to user space.
++ */
++static unsigned long
++mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
++{
++ unsigned long paddr, maddr;
++ unsigned long pfn;
++ int index;
++ struct vma_data *vdata = vma->vm_private_data;
++
++ index = (address - vma->vm_start) >> PAGE_SHIFT;
++ maddr = (volatile unsigned long) vdata->maddr[index];
++ if (maddr == 0) {
++ maddr = uncached_alloc_page(numa_node_id());
++ if (maddr == 0)
++ return NOPFN_OOM;
++
++ spin_lock(&vdata->lock);
++ if (vdata->maddr[index] == 0) {
++ vdata->count++;
++ vdata->maddr[index] = maddr;
++ } else {
++ uncached_free_page(maddr);
++ maddr = vdata->maddr[index];
++ }
++ spin_unlock(&vdata->lock);
++ }
++
++ if (vdata->type == MSPEC_FETCHOP)
++ paddr = TO_AMO(maddr);
++ else
++ paddr = __pa(TO_CAC(maddr));
++
++ pfn = paddr >> PAGE_SHIFT;
++
++ return pfn;
++}
++
++static struct vm_operations_struct mspec_vm_ops = {
++ .open = mspec_open,
++ .close = mspec_close,
++ .nopfn = mspec_nopfn
++};
++
++/*
++ * mspec_mmap
++ *
++ * Called when mmaping the device. Initializes the vma with a fault handler
++ * and private data structure necessary to allocate, track, and free the
++ * underlying pages.
++ */
++static int
++mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
++{
++ struct vma_data *vdata;
++ int pages, vdata_size;
++
++ if (vma->vm_pgoff != 0)
++ return -EINVAL;
++
++ if ((vma->vm_flags & VM_SHARED) == 0)
++ return -EINVAL;
++
++ if ((vma->vm_flags & VM_WRITE) == 0)
++ return -EPERM;
++
++ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++ vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
++ if (vdata_size <= PAGE_SIZE)
++ vdata = kmalloc(vdata_size, GFP_KERNEL);
++ else
++ vdata = vmalloc(vdata_size);
++ if (!vdata)
++ return -ENOMEM;
++ memset(vdata, 0, vdata_size);
++
++ vdata->type = type;
++ spin_lock_init(&vdata->lock);
++ vdata->refcnt = ATOMIC_INIT(1);
++ vma->vm_private_data = vdata;
++
++ vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP);
++ if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++ vma->vm_ops = &mspec_vm_ops;
++
++ return 0;
++}
++
++static int
++fetchop_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ return mspec_mmap(file, vma, MSPEC_FETCHOP);
++}
++
++static int
++cached_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ return mspec_mmap(file, vma, MSPEC_CACHED);
++}
++
++static int
++uncached_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ return mspec_mmap(file, vma, MSPEC_UNCACHED);
++}
++
++static struct file_operations fetchop_fops = {
++ .owner = THIS_MODULE,
++ .mmap = fetchop_mmap
++};
++
++static struct miscdevice fetchop_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "sgi_fetchop",
++ .fops = &fetchop_fops
++};
++
++static struct file_operations cached_fops = {
++ .owner = THIS_MODULE,
++ .mmap = cached_mmap
++};
++
++static struct miscdevice cached_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "mspec_cached",
++ .fops = &cached_fops
++};
++
++static struct file_operations uncached_fops = {
++ .owner = THIS_MODULE,
++ .mmap = uncached_mmap
++};
++
++static struct miscdevice uncached_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "mspec_uncached",
++ .fops = &uncached_fops
++};
++
++/*
++ * mspec_init
++ *
++ * Called at boot time to initialize the mspec facility.
++ */
++static int __init
++mspec_init(void)
++{
++ int ret;
++ int nid;
++
++ /*
++ * The fetchop device only works on SN2 hardware, uncached and cached
++ * memory drivers should both be valid on all ia64 hardware
++ */
++ if (ia64_platform_is("sn2")) {
++ is_sn2 = 1;
++ if (is_shub2()) {
++ ret = -ENOMEM;
++ for_each_online_node(nid) {
++ int actual_nid;
++ int nasid;
++ unsigned long phys;
++
++ scratch_page[nid] = uncached_alloc_page(nid);
++ if (scratch_page[nid] == 0)
++ goto free_scratch_pages;
++ phys = __pa(scratch_page[nid]);
++ nasid = get_node_number(phys);
++ actual_nid = nasid_to_cnodeid(nasid);
++ if (actual_nid != nid)
++ goto free_scratch_pages;
++ }
++ }
++
++ ret = misc_register(&fetchop_miscdev);
++ if (ret) {
++ printk(KERN_ERR
++ "%s: failed to register device %i\n",
++ FETCHOP_ID, ret);
++ goto free_scratch_pages;
++ }
++ }
++ ret = misc_register(&cached_miscdev);
++ if (ret) {
++ printk(KERN_ERR "%s: failed to register device %i\n",
++ CACHED_ID, ret);
++ if (is_sn2)
++ misc_deregister(&fetchop_miscdev);
++ goto free_scratch_pages;
++ }
++ ret = misc_register(&uncached_miscdev);
++ if (ret) {
++ printk(KERN_ERR "%s: failed to register device %i\n",
++ UNCACHED_ID, ret);
++ misc_deregister(&cached_miscdev);
++ if (is_sn2)
++ misc_deregister(&fetchop_miscdev);
++ goto free_scratch_pages;
++ }
++
++ printk(KERN_INFO "%s %s initialized devices: %s %s %s\n",
++ MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "",
++ CACHED_ID, UNCACHED_ID);
++
++ return 0;
++
++ free_scratch_pages:
++ for_each_node(nid) {
++ if (scratch_page[nid] != 0)
++ uncached_free_page(scratch_page[nid]);
++ }
++ return ret;
++}
++
++static void __exit
++mspec_exit(void)
++{
++ int nid;
++
++ misc_deregister(&uncached_miscdev);
++ misc_deregister(&cached_miscdev);
++ if (is_sn2) {
++ misc_deregister(&fetchop_miscdev);
++
++ for_each_node(nid) {
++ if (scratch_page[nid] != 0)
++ uncached_free_page(scratch_page[nid]);
++ }
++ }
++}
++
++module_init(mspec_init);
++module_exit(mspec_exit);
++
++MODULE_AUTHOR("Silicon Graphics, Inc. <linux-altix at sgi.com>");
++MODULE_DESCRIPTION("Driver for SGI SN special memory operations");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/char/mwave/README b/drivers/char/mwave/README
+index 70f8d19..480251f 100644
+--- a/drivers/char/mwave/README
++++ b/drivers/char/mwave/README
+@@ -41,10 +41,7 @@ Example to enable the 3780i DSP using tt
+ Accessing the driver
+ --------------------
+
+-You must also create a node for the driver. Without devfs:
++You must also create a node for the driver:
+ mkdir -p /dev/modems
+ mknod --mode=660 /dev/modems/mwave c 10 219
+-With devfs:
+- mkdir -p /dev/modems
+- ln -s ../misc/mwave /dev/modems/mwave
+
+diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
+index 39a2e66..8d14823 100644
+--- a/drivers/char/mwave/mwavedd.c
++++ b/drivers/char/mwave/mwavedd.c
+@@ -297,7 +297,7 @@ static int mwave_ioctl(struct inode *ino
+ " ipcnum %x, usIntCount %x\n",
+ ipcnum,
+ pDrvData->IPCs[ipcnum].usIntCount);
+- if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
++ if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
+ PRINTK_ERROR(KERN_ERR_MWAVE
+ "mwavedd::mwave_ioctl:"
+ " IOCTL_MW_GET_IPC: Error:"
+@@ -355,7 +355,7 @@ static int mwave_ioctl(struct inode *ino
+ "mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
+ " ipcnum %x\n",
+ ipcnum);
+- if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
++ if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
+ PRINTK_ERROR(KERN_ERR_MWAVE
+ "mwavedd::mwave_ioctl:"
+ " IOCTL_MW_UNREGISTER_IPC:"
+diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
+index cc3e54d..f282976 100644
+--- a/drivers/char/mwave/tp3780i.c
++++ b/drivers/char/mwave/tp3780i.c
+@@ -95,14 +95,14 @@ static void EnableSRAM(THINKPAD_BD_DATA
+ }
+
+
+-static irqreturn_t UartInterrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t UartInterrupt(int irq, void *dev_id)
+ {
+ PRINTK_3(TRACE_TP3780I,
+ "tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id);
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t DspInterrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t DspInterrupt(int irq, void *dev_id)
+ {
+ pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
+ DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings;
+diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
+index 556abd3..048d911 100644
+--- a/drivers/char/mxser.c
++++ b/drivers/char/mxser.c
+@@ -407,7 +407,7 @@ static void mxser_stop(struct tty_struct
+ static void mxser_start(struct tty_struct *);
+ static void mxser_hangup(struct tty_struct *);
+ static void mxser_rs_break(struct tty_struct *, int);
+-static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t mxser_interrupt(int, void *);
+ static void mxser_receive_chars(struct mxser_struct *, int *);
+ static void mxser_transmit_chars(struct mxser_struct *);
+ static void mxser_check_modem_status(struct mxser_struct *, int);
+@@ -453,7 +453,7 @@ static int CheckIsMoxaMust(int io)
+
+ /* above is modified by Victor Yu. 08-15-2002 */
+
+-static struct tty_operations mxser_ops = {
++static const struct tty_operations mxser_ops = {
+ .open = mxser_open,
+ .close = mxser_close,
+ .write = mxser_write,
+@@ -1916,7 +1916,7 @@ static void mxser_rs_break(struct tty_st
+ /*
+ * This is the serial driver's generic interrupt routine
+ */
+-static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mxser_interrupt(int irq, void *dev_id)
+ {
+ int status, iir, i;
+ struct mxser_struct *info;
+@@ -2554,71 +2554,7 @@ static int mxser_change_speed(struct mxs
+ #define B921600 (B460800 +1)
+ #endif
+ if (mxser_set_baud_method[info->port] == 0) {
+- switch (cflag & (CBAUD | CBAUDEX)) {
+- case B921600:
+- baud = 921600;
+- break;
+- case B460800:
+- baud = 460800;
+- break;
+- case B230400:
+- baud = 230400;
+- break;
+- case B115200:
+- baud = 115200;
+- break;
+- case B57600:
+- baud = 57600;
+- break;
+- case B38400:
+- baud = 38400;
+- break;
+- case B19200:
+- baud = 19200;
+- break;
+- case B9600:
+- baud = 9600;
+- break;
+- case B4800:
+- baud = 4800;
+- break;
+- case B2400:
+- baud = 2400;
+- break;
+- case B1800:
+- baud = 1800;
+- break;
+- case B1200:
+- baud = 1200;
+- break;
+- case B600:
+- baud = 600;
+- break;
+- case B300:
+- baud = 300;
+- break;
+- case B200:
+- baud = 200;
+- break;
+- case B150:
+- baud = 150;
+- break;
+- case B134:
+- baud = 134;
+- break;
+- case B110:
+- baud = 110;
+- break;
+- case B75:
+- baud = 75;
+- break;
+- case B50:
+- baud = 50;
+- break;
+- default:
+- baud = 0;
+- break;
+- }
++ baud = tty_get_baud_rate(info->tty);
+ mxser_set_baud(info, baud);
+ }
+
+diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
+index 7719bd7..4d47d79 100644
+--- a/drivers/char/nsc_gpio.c
++++ b/drivers/char/nsc_gpio.c
+@@ -7,7 +7,6 @@
+ Copyright (c) 2005 Jim Cromie <jim.cromie at gmail.com>
+ */
+
+-#include <linux/config.h>
+ #include <linux/fs.h>
+ #include <linux/module.h>
+ #include <linux/errno.h>
+diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
+index 7c57ebf..2d26497 100644
+--- a/drivers/char/nwbutton.c
++++ b/drivers/char/nwbutton.c
+@@ -127,9 +127,8 @@ static void button_consume_callbacks (in
+ static void button_sequence_finished (unsigned long parameters)
+ {
+ #ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */
+- if (button_press_count == reboot_count) {
+- kill_proc (1, SIGINT, 1); /* Ask init to reboot us */
+- }
++ if (button_press_count == reboot_count)
++ kill_cad_pid(SIGINT, 1); /* Ask init to reboot us */
+ #endif /* CONFIG_NWBUTTON_REBOOT */
+ button_consume_callbacks (button_press_count);
+ bcount = sprintf (button_output_buffer, "%d\n", button_press_count);
+@@ -145,7 +144,7 @@ static void button_sequence_finished (un
+ * increments the counter.
+ */
+
+-static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t button_handler (int irq, void *dev_id)
+ {
+ if (button_press_count) {
+ del_timer (&button_timer);
+diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h
+index ddb7b92..c3ebc16 100644
+--- a/drivers/char/nwbutton.h
++++ b/drivers/char/nwbutton.h
+@@ -25,7 +25,7 @@ struct button_callback {
+ /* Function prototypes: */
+
+ static void button_sequence_finished (unsigned long parameters);
+-static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t button_handler (int irq, void *dev_id);
+ int button_init (void);
+ int button_add_callback (void (*callback) (void), int count);
+ int button_del_callback (void (*callback) (void));
+diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
+index 84e5a68..ecfaf18 100644
+--- a/drivers/char/pc8736x_gpio.c
++++ b/drivers/char/pc8736x_gpio.c
+@@ -188,16 +188,6 @@ static void pc8736x_gpio_set(unsigned mi
+ pc8736x_gpio_shadow[port] = val;
+ }
+
+-static void pc8736x_gpio_set_high(unsigned index)
+-{
+- pc8736x_gpio_set(index, 1);
+-}
+-
+-static void pc8736x_gpio_set_low(unsigned index)
+-{
+- pc8736x_gpio_set(index, 0);
+-}
+-
+ static int pc8736x_gpio_current(unsigned minor)
+ {
+ int port, bit;
+diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
+index 00f574c..1a0bc30 100644
+--- a/drivers/char/pcmcia/synclink_cs.c
++++ b/drivers/char/pcmcia/synclink_cs.c
+@@ -35,7 +35,6 @@
+
+ #define MAX_DEVICE_COUNT 4
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+@@ -57,7 +56,6 @@
+ #include <linux/netdevice.h>
+ #include <linux/vmalloc.h>
+ #include <linux/init.h>
+-#include <asm/serial.h>
+ #include <linux/delay.h>
+ #include <linux/ioctl.h>
+
+@@ -418,7 +416,7 @@ static void rx_reset_buffers(MGSLPC_INFO
+ static int rx_alloc_buffers(MGSLPC_INFO *info);
+ static void rx_free_buffers(MGSLPC_INFO *info);
+
+-static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t mgslpc_isr(int irq, void *dev_id);
+
+ /*
+ * Bottom half interrupt handlers
+@@ -1236,9 +1234,8 @@ static void ri_change(MGSLPC_INFO *info)
+ *
+ * irq interrupt number that caused interrupt
+ * dev_id device ID supplied during interrupt registration
+- * regs interrupted processor context
+ */
+-static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t mgslpc_isr(int irq, void *dev_id)
+ {
+ MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id;
+ unsigned short isr;
+@@ -3010,7 +3007,7 @@ static struct pcmcia_driver mgslpc_drive
+ .resume = mgslpc_resume,
+ };
+
+-static struct tty_operations mgslpc_ops = {
++static const struct tty_operations mgslpc_ops = {
+ .open = mgslpc_open,
+ .close = mgslpc_close,
+ .write = mgslpc_write,
+diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
+index 520d2cf..efc485e 100644
+--- a/drivers/char/ppdev.c
++++ b/drivers/char/ppdev.c
+@@ -269,7 +269,7 @@ static ssize_t pp_write (struct file * f
+ return bytes_written;
+ }
+
+-static void pp_irq (int irq, void * private, struct pt_regs * unused)
++static void pp_irq (int irq, void * private)
+ {
+ struct pp_struct * pp = (struct pp_struct *) private;
+
+diff --git a/drivers/char/pty.c b/drivers/char/pty.c
+index 34dd4c3..80d3eed 100644
+--- a/drivers/char/pty.c
++++ b/drivers/char/pty.c
+@@ -224,7 +224,7 @@ static void pty_set_termios(struct tty_s
+ tty->termios->c_cflag |= (CS8 | CREAD);
+ }
+
+-static struct tty_operations pty_ops = {
++static const struct tty_operations pty_ops = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c
+deleted file mode 100644
+index 9d134e9..0000000
+--- a/drivers/char/qtronix.c
++++ /dev/null
+@@ -1,605 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Qtronix 990P infrared keyboard driver.
+- *
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at mvista.com
+- *
+- *
+- * The bottom portion of this driver was take from
+- * pc_keyb.c Please see that file for copyrights.
+- *
+- * 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.
+- */
+-
+-
+-/*
+- * NOTE:
+- *
+- * This driver has only been tested with the Consumer IR
+- * port of the ITE 8172 system controller.
+- *
+- * You do not need this driver if you are using the ps/2 or
+- * USB adapter that the keyboard ships with. You only need
+- * this driver if your board has a IR port and the keyboard
+- * data is being sent directly to the IR. In that case,
+- * you also need some low-level IR support. See it8172_cir.c.
+- *
+- */
+-
+-#ifdef CONFIG_QTRONIX_KEYBOARD
+-
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/pci.h>
+-#include <linux/kernel.h>
+-
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_int.h>
+-#include <asm/it8172/it8172_cir.h>
+-
+-#include <linux/spinlock.h>
+-#include <linux/sched.h>
+-#include <linux/interrupt.h>
+-#include <linux/tty.h>
+-#include <linux/mm.h>
+-#include <linux/signal.h>
+-#include <linux/init.h>
+-#include <linux/kbd_ll.h>
+-#include <linux/delay.h>
+-#include <linux/poll.h>
+-#include <linux/miscdevice.h>
+-#include <linux/slab.h>
+-#include <linux/kbd_kern.h>
+-#include <linux/smp_lock.h>
+-#include <asm/io.h>
+-#include <linux/pc_keyb.h>
+-
+-#include <asm/keyboard.h>
+-#include <linux/bitops.h>
+-#include <asm/uaccess.h>
+-#include <asm/irq.h>
+-#include <asm/system.h>
+-
+-#define leading1 0
+-#define leading2 0xF
+-
+-#define KBD_CIR_PORT 0
+-#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
+-
+-static int data_index;
+-struct cir_port *cir;
+-static unsigned char kbdbytes[5];
+-static unsigned char cir_data[32]; /* we only need 16 chars */
+-
+-static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+-static int handle_data(unsigned char *p_data);
+-static inline void handle_mouse_event(unsigned char scancode);
+-static inline void handle_keyboard_event(unsigned char scancode, int down);
+-static int __init psaux_init(void);
+-
+-static struct aux_queue *queue; /* Mouse data buffer. */
+-static int aux_count = 0;
+-
+-/*
+- * Keys accessed through the 'Fn' key
+- * The Fn key does not produce a key-up sequence. So, the first
+- * time the user presses it, it will be key-down event. The key
+- * stays down until the user presses it again.
+- */
+-#define NUM_FN_KEYS 56
+-static unsigned char fn_keys[NUM_FN_KEYS] = {
+- 0,0,0,0,0,0,0,0, /* 0 7 */
+- 8,9,10,93,0,0,0,0, /* 8 15 */
+- 0,0,0,0,0,0,0,5, /* 16 23 */
+- 6,7,91,0,0,0,0,0, /* 24 31 */
+- 0,0,0,0,0,2,3,4, /* 32 39 */
+- 92,0,0,0,0,0,0,0, /* 40 47 */
+- 0,0,0,0,11,0,94,95 /* 48 55 */
+-
+-};
+-
+-void __init init_qtronix_990P_kbd(void)
+-{
+- int retval;
+-
+- cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);
+- if (!cir) {
+- printk("Unable to initialize Qtronix keyboard\n");
+- return;
+- }
+-
+- /*
+- * revisit
+- * this should be programmable, somehow by the, by the user.
+- */
+- cir->port = KBD_CIR_PORT;
+- cir->baud_rate = 0x1d;
+- cir->rdwos = 0;
+- cir->rxdcr = 0x3;
+- cir->hcfs = 0;
+- cir->fifo_tl = 0;
+- cir->cfq = 0x1d;
+- cir_port_init(cir);
+-
+- retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler,
+- (unsigned long )(IRQF_DISABLED|IRQF_SHARED),
+- (const char *)"Qtronix IR Keyboard", (void *)cir);
+-
+- if (retval) {
+- printk("unable to allocate cir %d irq %d\n",
+- cir->port, IT8172_CIR0_IRQ);
+- }
+-#ifdef CONFIG_PSMOUSE
+- psaux_init();
+-#endif
+-}
+-
+-static inline unsigned char BitReverse(unsigned short key)
+-{
+- unsigned char rkey = 0;
+- rkey |= (key & 0x1) << 7;
+- rkey |= (key & 0x2) << 5;
+- rkey |= (key & 0x4) << 3;
+- rkey |= (key & 0x8) << 1;
+- rkey |= (key & 0x10) >> 1;
+- rkey |= (key & 0x20) >> 3;
+- rkey |= (key & 0x40) >> 5;
+- rkey |= (key & 0x80) >> 7;
+- return rkey;
+-
+-}
+-
+-
+-static inline u_int8_t UpperByte(u_int8_t data)
+-{
+- return (data >> 4);
+-}
+-
+-
+-static inline u_int8_t LowerByte(u_int8_t data)
+-{
+- return (data & 0xF);
+-}
+-
+-
+-int CheckSumOk(u_int8_t byte1, u_int8_t byte2,
+- u_int8_t byte3, u_int8_t byte4, u_int8_t byte5)
+-{
+- u_int8_t CheckSum;
+-
+- CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;
+- if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )
+- return 0;
+- else
+- return 1;
+-}
+-
+-
+-static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct cir_port *cir;
+- int j;
+- unsigned char int_status;
+-
+- cir = (struct cir_port *)dev_id;
+- int_status = get_int_status(cir);
+- if (int_status & 0x4) {
+- clear_fifo(cir);
+- return;
+- }
+-
+- while (cir_get_rx_count(cir)) {
+-
+- cir_data[data_index] = cir_read_data(cir);
+-
+- if (data_index == 0) {/* expecting first byte */
+- if (cir_data[data_index] != leading1) {
+- //printk("!leading byte %x\n", cir_data[data_index]);
+- set_rx_active(cir);
+- clear_fifo(cir);
+- continue;
+- }
+- }
+- if (data_index == 1) {
+- if ((cir_data[data_index] & 0xf) != leading2) {
+- set_rx_active(cir);
+- data_index = 0; /* start over */
+- clear_fifo(cir);
+- continue;
+- }
+- }
+-
+- if ( (cir_data[data_index] == 0xff)) { /* last byte */
+- //printk("data_index %d\n", data_index);
+- set_rx_active(cir);
+-#if 0
+- for (j=0; j<=data_index; j++) {
+- printk("rx_data %d: %x\n", j, cir_data[j]);
+- }
+-#endif
+- data_index = 0;
+- handle_data(cir_data);
+- return;
+- }
+- else if (data_index>16) {
+- set_rx_active(cir);
+-#if 0
+- printk("warning: data_index %d\n", data_index);
+- for (j=0; j<=data_index; j++) {
+- printk("rx_data %d: %x\n", j, cir_data[j]);
+- }
+-#endif
+- data_index = 0;
+- clear_fifo(cir);
+- return;
+- }
+- data_index++;
+- }
+-}
+-
+-
+-#define NUM_KBD_BYTES 5
+-static int handle_data(unsigned char *p_data)
+-{
+- u_int32_t bit_bucket;
+- u_int32_t i, j;
+- u_int32_t got_bits, next_byte;
+- int down = 0;
+-
+- /* Reorganize the bit stream */
+- for (i=0; i<16; i++)
+- p_data[i] = BitReverse(~p_data[i]);
+-
+- /*
+- * We've already previously checked that p_data[0]
+- * is equal to leading1 and that (p_data[1] & 0xf)
+- * is equal to leading2. These twelve bits are the
+- * leader code. We can now throw them away (the 12
+- * bits) and continue parsing the stream.
+- */
+- bit_bucket = p_data[1] << 12;
+- got_bits = 4;
+- next_byte = 2;
+-
+- /*
+- * Process four bits at a time
+- */
+- for (i=0; i<NUM_KBD_BYTES; i++) {
+-
+- kbdbytes[i]=0;
+-
+- for (j=0; j<8; j++) /* 8 bits per byte */
+- {
+- if (got_bits < 4) {
+- bit_bucket |= (p_data[next_byte++] << (8 - got_bits));
+- got_bits += 8;
+- }
+-
+- if ((bit_bucket & 0xF000) == 0x8000) {
+- /* Convert 1000b to 1 */
+- kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);
+- got_bits -= 4;
+- bit_bucket = bit_bucket << 4;
+- }
+- else if ((bit_bucket & 0xC000) == 0x8000) {
+- /* Convert 10b to 0 */
+- kbdbytes[i] = kbdbytes[i] >> 1;
+- got_bits -= 2;
+- bit_bucket = bit_bucket << 2;
+- }
+- else {
+- /* bad serial stream */
+- return 1;
+- }
+-
+- if (next_byte > 16) {
+- //printk("error: too many bytes\n");
+- return 1;
+- }
+- }
+- }
+-
+-
+- if (!CheckSumOk(kbdbytes[0], kbdbytes[1],
+- kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
+- //printk("checksum failed\n");
+- return 1;
+- }
+-
+- if (kbdbytes[1] & 0x08) {
+- //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);
+- handle_mouse_event(kbdbytes[1]);
+- handle_mouse_event(kbdbytes[2]);
+- handle_mouse_event(kbdbytes[3]);
+- }
+- else {
+- if (kbdbytes[2] == 0) down = 1;
+-#if 0
+- if (down)
+- printk("down %d\n", kbdbytes[3]);
+- else
+- printk("up %d\n", kbdbytes[3]);
+-#endif
+- handle_keyboard_event(kbdbytes[3], down);
+- }
+- return 0;
+-}
+-
+-
+-DEFINE_SPINLOCK(kbd_controller_lock);
+-static unsigned char handle_kbd_event(void);
+-
+-
+-int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+-{
+- printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
+- return 0;
+-}
+-
+-int kbd_getkeycode(unsigned int scancode)
+-{
+- return scancode;
+-}
+-
+-
+-int kbd_translate(unsigned char scancode, unsigned char *keycode,
+- char raw_mode)
+-{
+- static int prev_scancode = 0;
+-
+- if (scancode == 0x00 || scancode == 0xff) {
+- prev_scancode = 0;
+- return 0;
+- }
+-
+- /* todo */
+- if (!prev_scancode && scancode == 160) { /* Fn key down */
+- //printk("Fn key down\n");
+- prev_scancode = 160;
+- return 0;
+- }
+- else if (prev_scancode && scancode == 160) { /* Fn key up */
+- //printk("Fn key up\n");
+- prev_scancode = 0;
+- return 0;
+- }
+-
+- /* todo */
+- if (prev_scancode == 160) {
+- if (scancode <= NUM_FN_KEYS) {
+- *keycode = fn_keys[scancode];
+- //printk("fn keycode %d\n", *keycode);
+- }
+- else
+- return 0;
+- }
+- else if (scancode <= 127) {
+- *keycode = scancode;
+- }
+- else
+- return 0;
+-
+-
+- return 1;
+-}
+-
+-char kbd_unexpected_up(unsigned char keycode)
+-{
+- //printk("kbd_unexpected_up\n");
+- return 0;
+-}
+-
+-static unsigned char kbd_exists = 1;
+-
+-static inline void handle_keyboard_event(unsigned char scancode, int down)
+-{
+- kbd_exists = 1;
+- handle_scancode(scancode, down);
+- tasklet_schedule(&keyboard_tasklet);
+-}
+-
+-
+-void kbd_leds(unsigned char leds)
+-{
+-}
+-
+-/* dummy */
+-void kbd_init_hw(void)
+-{
+-}
+-
+-
+-
+-static inline void handle_mouse_event(unsigned char scancode)
+-{
+- if(scancode == AUX_RECONNECT){
+- queue->head = queue->tail = 0; /* Flush input queue */
+- // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
+- return;
+- }
+-
+- if (aux_count) {
+- int head = queue->head;
+-
+- queue->buf[head] = scancode;
+- head = (head + 1) & (AUX_BUF_SIZE-1);
+- if (head != queue->tail) {
+- queue->head = head;
+- kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+- wake_up_interruptible(&queue->proc_list);
+- }
+- }
+-}
+-
+-static unsigned char get_from_queue(void)
+-{
+- unsigned char result;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&kbd_controller_lock, flags);
+- result = queue->buf[queue->tail];
+- queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+- spin_unlock_irqrestore(&kbd_controller_lock, flags);
+- return result;
+-}
+-
+-
+-static inline int queue_empty(void)
+-{
+- return queue->head == queue->tail;
+-}
+-
+-static int fasync_aux(int fd, struct file *filp, int on)
+-{
+- int retval;
+-
+- //printk("fasync_aux\n");
+- retval = fasync_helper(fd, filp, on, &queue->fasync);
+- if (retval < 0)
+- return retval;
+- return 0;
+-}
+-
+-
+-/*
+- * Random magic cookie for the aux device
+- */
+-#define AUX_DEV ((void *)queue)
+-
+-static int release_aux(struct inode * inode, struct file * file)
+-{
+- fasync_aux(-1, file, 0);
+- aux_count--;
+- return 0;
+-}
+-
+-static int open_aux(struct inode * inode, struct file * file)
+-{
+- if (aux_count++) {
+- return 0;
+- }
+- queue->head = queue->tail = 0; /* Flush input queue */
+- return 0;
+-}
+-
+-/*
+- * Put bytes from input queue to buffer.
+- */
+-
+-static ssize_t read_aux(struct file * file, char * buffer,
+- size_t count, loff_t *ppos)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t i = count;
+- unsigned char c;
+-
+- if (queue_empty()) {
+- if (file->f_flags & O_NONBLOCK)
+- return -EAGAIN;
+- add_wait_queue(&queue->proc_list, &wait);
+-repeat:
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (queue_empty() && !signal_pending(current)) {
+- schedule();
+- goto repeat;
+- }
+- current->state = TASK_RUNNING;
+- remove_wait_queue(&queue->proc_list, &wait);
+- }
+- while (i > 0 && !queue_empty()) {
+- c = get_from_queue();
+- put_user(c, buffer++);
+- i--;
+- }
+- if (count-i) {
+- struct inode *inode = file->f_dentry->d_inode;
+- inode->i_atime = current_fs_time(inode->i_sb);
+- return count-i;
+- }
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/*
+- * Write to the aux device.
+- */
+-
+-static ssize_t write_aux(struct file * file, const char * buffer,
+- size_t count, loff_t *ppos)
+-{
+- /*
+- * The ITE boards this was tested on did not have the
+- * transmit wires connected.
+- */
+- return count;
+-}
+-
+-static unsigned int aux_poll(struct file *file, poll_table * wait)
+-{
+- poll_wait(file, &queue->proc_list, wait);
+- if (!queue_empty())
+- return POLLIN | POLLRDNORM;
+- return 0;
+-}
+-
+-struct file_operations psaux_fops = {
+- .read = read_aux,
+- .write = write_aux,
+- .poll = aux_poll,
+- .open = open_aux,
+- .release = release_aux,
+- .fasync = fasync_aux,
+-};
+-
+-/*
+- * Initialize driver.
+- */
+-static struct miscdevice psaux_mouse = {
+- PSMOUSE_MINOR, "psaux", &psaux_fops
+-};
+-
+-static int __init psaux_init(void)
+-{
+- int retval;
+-
+- retval = misc_register(&psaux_mouse);
+- if(retval < 0)
+- return retval;
+-
+- queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+- if (!queue) {
+- misc_deregister(&psaux_mouse);
+- return -ENOMEM;
+- }
+-
+- memset(queue, 0, sizeof(*queue));
+- queue->head = queue->tail = 0;
+- init_waitqueue_head(&queue->proc_list);
+-
+- return 0;
+-}
+-module_init(init_qtronix_990P_kbd);
+-#endif
+diff --git a/drivers/char/qtronixmap.c_shipped b/drivers/char/qtronixmap.c_shipped
+deleted file mode 100644
+index 1e2b92b..0000000
+--- a/drivers/char/qtronixmap.c_shipped
++++ /dev/null
+@@ -1,265 +0,0 @@
+-
+-/* Do not edit this file! It was automatically generated by */
+-/* loadkeys --mktable defkeymap.map > defkeymap.c */
+-
+-#include <linux/types.h>
+-#include <linux/keyboard.h>
+-#include <linux/kd.h>
+-
+-u_short plain_map[NR_KEYS] = {
+- 0xf200, 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+- 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f,
+- 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75,
+- 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf207, 0xfb61,
+- 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c,
+- 0xf03b, 0xf027, 0xf060, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78,
+- 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200,
+- 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
+- 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-u_short shift_map[NR_KEYS] = {
+- 0xf200, 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+- 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f,
+- 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55,
+- 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf207, 0xfb41,
+- 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c,
+- 0xf03a, 0xf022, 0xf07e, 0xf201, 0xf700, 0xf200, 0xfb5a, 0xfb58,
+- 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf20b, 0xf20a, 0xf200,
+- 0xf200, 0xf602, 0xf213, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200,
+- 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
+- 0xf112, 0xf113, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-u_short altgr_map[NR_KEYS] = {
+- 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+- 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75,
+- 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf207, 0xfb61,
+- 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c,
+- 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78,
+- 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+- 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
+- 0xf514, 0xf515, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-u_short ctrl_map[NR_KEYS] = {
+- 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+- 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008,
+- 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015,
+- 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf207, 0xf001,
+- 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c,
+- 0xf007, 0xf000, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018,
+- 0xf003, 0xf016, 0xf002, 0xf00e, 0xf20e, 0xf07f, 0xf200, 0xf200,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf000, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+- 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
+- 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-u_short shift_ctrl_map[NR_KEYS] = {
+- 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015,
+- 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf207, 0xf001,
+- 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c,
+- 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018,
+- 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-u_short alt_map[NR_KEYS] = {
+- 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+- 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf200, 0xf87f,
+- 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875,
+- 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf207, 0xf861,
+- 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf83b,
+- 0xf827, 0xf860, 0xf200, 0xf80d, 0xf700, 0xf200, 0xf87a, 0xf878,
+- 0xf863, 0xf876, 0xf862, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf200,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf820, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf210,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+- 0xf200, 0xf211, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+- 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
+- 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-u_short ctrl_alt_map[NR_KEYS] = {
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815,
+- 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf207, 0xf801,
+- 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c,
+- 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf81a, 0xf818,
+- 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+- 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
+- 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+-};
+-
+-ushort *key_maps[MAX_NR_KEYMAPS] = {
+- plain_map, shift_map, altgr_map, 0,
+- ctrl_map, shift_ctrl_map, 0, 0,
+- alt_map, 0, 0, 0,
+- ctrl_alt_map, 0
+-};
+-
+-unsigned int keymap_count = 7;
+-
+-
+-/*
+- * Philosophy: most people do not define more strings, but they who do
+- * often want quite a lot of string space. So, we statically allocate
+- * the default and allocate dynamically in chunks of 512 bytes.
+- */
+-
+-char func_buf[] = {
+- '\033', '[', '[', 'A', 0,
+- '\033', '[', '[', 'B', 0,
+- '\033', '[', '[', 'C', 0,
+- '\033', '[', '[', 'D', 0,
+- '\033', '[', '[', 'E', 0,
+- '\033', '[', '1', '7', '~', 0,
+- '\033', '[', '1', '8', '~', 0,
+- '\033', '[', '1', '9', '~', 0,
+- '\033', '[', '2', '0', '~', 0,
+- '\033', '[', '2', '1', '~', 0,
+- '\033', '[', '2', '3', '~', 0,
+- '\033', '[', '2', '4', '~', 0,
+- '\033', '[', '2', '5', '~', 0,
+- '\033', '[', '2', '6', '~', 0,
+- '\033', '[', '2', '8', '~', 0,
+- '\033', '[', '2', '9', '~', 0,
+- '\033', '[', '3', '1', '~', 0,
+- '\033', '[', '3', '2', '~', 0,
+- '\033', '[', '3', '3', '~', 0,
+- '\033', '[', '3', '4', '~', 0,
+- '\033', '[', '1', '~', 0,
+- '\033', '[', '2', '~', 0,
+- '\033', '[', '3', '~', 0,
+- '\033', '[', '4', '~', 0,
+- '\033', '[', '5', '~', 0,
+- '\033', '[', '6', '~', 0,
+- '\033', '[', 'M', 0,
+- '\033', '[', 'P', 0,
+-};
+-
+-
+-char *funcbufptr = func_buf;
+-int funcbufsize = sizeof(func_buf);
+-int funcbufleft = 0; /* space left */
+-
+-char *func_table[MAX_NR_FUNC] = {
+- func_buf + 0,
+- func_buf + 5,
+- func_buf + 10,
+- func_buf + 15,
+- func_buf + 20,
+- func_buf + 25,
+- func_buf + 31,
+- func_buf + 37,
+- func_buf + 43,
+- func_buf + 49,
+- func_buf + 55,
+- func_buf + 61,
+- func_buf + 67,
+- func_buf + 73,
+- func_buf + 79,
+- func_buf + 85,
+- func_buf + 91,
+- func_buf + 97,
+- func_buf + 103,
+- func_buf + 109,
+- func_buf + 115,
+- func_buf + 120,
+- func_buf + 125,
+- func_buf + 130,
+- func_buf + 135,
+- func_buf + 140,
+- func_buf + 145,
+- 0,
+- 0,
+- func_buf + 149,
+- 0,
+-};
+-
+-struct kbdiacr accent_table[MAX_DIACR] = {
+- {'`', 'A', 'À'}, {'`', 'a', 'à'},
+- {'\'', 'A', 'Á'}, {'\'', 'a', 'á'},
+- {'^', 'A', 'Â'}, {'^', 'a', 'â'},
+- {'~', 'A', 'Ã'}, {'~', 'a', 'ã'},
+- {'"', 'A', 'Ä'}, {'"', 'a', 'ä'},
+- {'O', 'A', 'Å'}, {'o', 'a', 'å'},
+- {'0', 'A', 'Å'}, {'0', 'a', 'å'},
+- {'A', 'A', 'Å'}, {'a', 'a', 'å'},
+- {'A', 'E', 'Æ'}, {'a', 'e', 'æ'},
+- {',', 'C', 'Ç'}, {',', 'c', 'ç'},
+- {'`', 'E', 'È'}, {'`', 'e', 'è'},
+- {'\'', 'E', 'É'}, {'\'', 'e', 'é'},
+- {'^', 'E', 'Ê'}, {'^', 'e', 'ê'},
+- {'"', 'E', 'Ë'}, {'"', 'e', 'ë'},
+- {'`', 'I', 'Ì'}, {'`', 'i', 'ì'},
+- {'\'', 'I', 'Í'}, {'\'', 'i', 'í'},
+- {'^', 'I', 'Î'}, {'^', 'i', 'î'},
+- {'"', 'I', 'Ï'}, {'"', 'i', 'ï'},
+- {'-', 'D', 'Ð'}, {'-', 'd', 'ð'},
+- {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'},
+- {'`', 'O', 'Ò'}, {'`', 'o', 'ò'},
+- {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'},
+- {'^', 'O', 'Ô'}, {'^', 'o', 'ô'},
+- {'~', 'O', 'Õ'}, {'~', 'o', 'õ'},
+- {'"', 'O', 'Ö'}, {'"', 'o', 'ö'},
+- {'/', 'O', 'Ø'}, {'/', 'o', 'ø'},
+- {'`', 'U', 'Ù'}, {'`', 'u', 'ù'},
+- {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'},
+- {'^', 'U', 'Û'}, {'^', 'u', 'û'},
+- {'"', 'U', 'Ü'}, {'"', 'u', 'ü'},
+- {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'},
+- {'T', 'H', 'Þ'}, {'t', 'h', 'þ'},
+- {'s', 's', 'ß'}, {'"', 'y', 'ÿ'},
+- {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'},
+-};
+-
+-unsigned int accent_table_size = 68;
+diff --git a/drivers/char/qtronixmap.map b/drivers/char/qtronixmap.map
+deleted file mode 100644
+index 8d1ff5c..0000000
+--- a/drivers/char/qtronixmap.map
++++ /dev/null
+@@ -1,287 +0,0 @@
+-# Default kernel keymap. This uses 7 modifier combinations.
+-keymaps 0-2,4-5,8,12
+-# Change the above line into
+-# keymaps 0-2,4-6,8,12
+-# in case you want the entries
+-# altgr control keycode 83 = Boot
+-# altgr control keycode 111 = Boot
+-# below.
+-#
+-# In fact AltGr is used very little, and one more keymap can
+-# be saved by mapping AltGr to Alt (and adapting a few entries):
+-# keycode 100 = Alt
+-#
+-keycode 1 = grave asciitilde
+- alt keycode 1 = Meta_Escape
+-keycode 2 = one exclam
+- alt keycode 2 = Meta_one
+-keycode 3 = two at at
+- control keycode 3 = nul
+- shift control keycode 3 = nul
+- alt keycode 3 = Meta_two
+-keycode 4 = three numbersign
+- control keycode 4 = Escape
+- alt keycode 4 = Meta_three
+-keycode 5 = four dollar dollar
+- control keycode 5 = Control_backslash
+- alt keycode 5 = Meta_four
+-keycode 6 = five percent
+- control keycode 6 = Control_bracketright
+- alt keycode 6 = Meta_five
+-keycode 7 = six asciicircum
+- control keycode 7 = Control_asciicircum
+- alt keycode 7 = Meta_six
+-keycode 8 = seven ampersand braceleft
+- control keycode 8 = Control_underscore
+- alt keycode 8 = Meta_seven
+-keycode 9 = eight asterisk bracketleft
+- control keycode 9 = Delete
+- alt keycode 9 = Meta_eight
+-keycode 10 = nine parenleft bracketright
+- alt keycode 10 = Meta_nine
+-keycode 11 = zero parenright braceright
+- alt keycode 11 = Meta_zero
+-keycode 12 = minus underscore backslash
+- control keycode 12 = Control_underscore
+- shift control keycode 12 = Control_underscore
+- alt keycode 12 = Meta_minus
+-keycode 13 = equal plus
+- alt keycode 13 = Meta_equal
+-keycode 15 = Delete Delete
+- control keycode 15 = BackSpace
+- alt keycode 15 = Meta_Delete
+-keycode 16 = Tab Tab
+- alt keycode 16 = Meta_Tab
+-keycode 17 = q
+-keycode 18 = w
+-keycode 19 = e
+-keycode 20 = r
+-keycode 21 = t
+-keycode 22 = y
+-keycode 23 = u
+-keycode 24 = i
+-keycode 25 = o
+-keycode 26 = p
+-keycode 27 = bracketleft braceleft
+- control keycode 27 = Escape
+- alt keycode 27 = Meta_bracketleft
+-keycode 28 = bracketright braceright
+- control keycode 28 = Control_bracketright
+- alt keycode 28 = Meta_bracketright
+-keycode 29 = backslash bar
+- control keycode 29 = Control_backslash
+- alt keycode 29 = Meta_backslash
+-keycode 30 = Caps_Lock
+-keycode 31 = a
+-keycode 32 = s
+-keycode 33 = d
+-keycode 34 = f
+-keycode 35 = g
+-keycode 36 = h
+-keycode 37 = j
+-keycode 38 = k
+-keycode 39 = l
+-keycode 40 = semicolon colon
+- alt keycode 39 = Meta_semicolon
+-keycode 41 = apostrophe quotedbl
+- control keycode 40 = Control_g
+- alt keycode 40 = Meta_apostrophe
+-keycode 42 = grave asciitilde
+- control keycode 41 = nul
+- alt keycode 41 = Meta_grave
+-keycode 43 = Return
+- alt keycode 43 = Meta_Control_m
+-keycode 44 = Shift
+-keycode 46 = z
+-keycode 47 = x
+-keycode 48 = c
+-keycode 49 = v
+-keycode 50 = b
+-keycode 51 = n
+-keycode 52 = m
+-keycode 53 = comma less
+- alt keycode 51 = Meta_comma
+-keycode 54 = period greater
+- control keycode 52 = Compose
+- alt keycode 52 = Meta_period
+-keycode 55 = slash question
+- control keycode 53 = Delete
+- alt keycode 53 = Meta_slash
+-keycode 57 = Shift
+-keycode 58 = Control
+-keycode 60 = Alt
+-keycode 61 = space space
+- control keycode 61 = nul
+- alt keycode 61 = Meta_space
+-keycode 62 = Alt
+-
+-keycode 75 = Insert
+-keycode 76 = Delete
+-
+-keycode 83 = Up
+-keycode 84 = Down
+-
+-keycode 85 = Prior
+- shift keycode 85 = Scroll_Backward
+-keycode 86 = Next
+- shift keycode 86 = Scroll_Forward
+-keycode 89 = Right
+- alt keycode 89 = Incr_Console
+-keycode 79 = Left
+- alt keycode 79 = Decr_Console
+-
+-keycode 90 = Num_Lock
+- shift keycode 90 = Bare_Num_Lock
+-
+-keycode 91 = minus
+-keycode 92 = plus
+-keycode 93 = KP_Multiply
+-keycode 94 = period
+-keycode 95 = KP_Divide
+-
+-keycode 107 = Select
+-keycode 108 = Down
+-
+-keycode 110 = Escape Escape
+- alt keycode 1 = Meta_Escape
+-
+-keycode 112 = F1 F11 Console_13
+- control keycode 112 = F1
+- alt keycode 112 = Console_1
+- control alt keycode 112 = Console_1
+-keycode 113 = F2 F12 Console_14
+- control keycode 113 = F2
+- alt keycode 113 = Console_2
+- control alt keycode 113 = Console_2
+-keycode 114 = F3 F13 Console_15
+- control keycode 114 = F3
+- alt keycode 114 = Console_3
+- control alt keycode 114 = Console_3
+-keycode 115 = F4 F14 Console_16
+- control keycode 115 = F4
+- alt keycode 115 = Console_4
+- control alt keycode 115 = Console_4
+-keycode 116 = F5 F15 Console_17
+- control keycode 116 = F5
+- alt keycode 116 = Console_5
+- control alt keycode 116 = Console_5
+-keycode 117 = F6 F16 Console_18
+- control keycode 117 = F6
+- alt keycode 117 = Console_6
+- control alt keycode 117 = Console_6
+-keycode 118 = F7 F17 Console_19
+- control keycode 118 = F7
+- alt keycode 118 = Console_7
+- control alt keycode 118 = Console_7
+-keycode 119 = F8 F18 Console_20
+- control keycode 119 = F8
+- alt keycode 119 = Console_8
+- control alt keycode 119 = Console_8
+-keycode 120 = F9 F19 Console_21
+- control keycode 120 = F9
+- alt keycode 120 = Console_9
+- control alt keycode 120 = Console_9
+-keycode 121 = F10 F20 Console_22
+- control keycode 121 = F10
+- alt keycode 121 = Console_10
+- control alt keycode 121 = Console_10
+-
+-keycode 126 = Pause
+-
+-
+-string F1 = "\033[[A"
+-string F2 = "\033[[B"
+-string F3 = "\033[[C"
+-string F4 = "\033[[D"
+-string F5 = "\033[[E"
+-string F6 = "\033[17~"
+-string F7 = "\033[18~"
+-string F8 = "\033[19~"
+-string F9 = "\033[20~"
+-string F10 = "\033[21~"
+-string F11 = "\033[23~"
+-string F12 = "\033[24~"
+-string F13 = "\033[25~"
+-string F14 = "\033[26~"
+-string F15 = "\033[28~"
+-string F16 = "\033[29~"
+-string F17 = "\033[31~"
+-string F18 = "\033[32~"
+-string F19 = "\033[33~"
+-string F20 = "\033[34~"
+-string Find = "\033[1~"
+-string Insert = "\033[2~"
+-string Remove = "\033[3~"
+-string Select = "\033[4~"
+-string Prior = "\033[5~"
+-string Next = "\033[6~"
+-string Macro = "\033[M"
+-string Pause = "\033[P"
+-compose '`' 'A' to 'À'
+-compose '`' 'a' to 'à'
+-compose '\'' 'A' to 'Á'
+-compose '\'' 'a' to 'á'
+-compose '^' 'A' to 'Â'
+-compose '^' 'a' to 'â'
+-compose '~' 'A' to 'Ã'
+-compose '~' 'a' to 'ã'
+-compose '"' 'A' to 'Ä'
+-compose '"' 'a' to 'ä'
+-compose 'O' 'A' to 'Å'
+-compose 'o' 'a' to 'å'
+-compose '0' 'A' to 'Å'
+-compose '0' 'a' to 'å'
+-compose 'A' 'A' to 'Å'
+-compose 'a' 'a' to 'å'
+-compose 'A' 'E' to 'Æ'
+-compose 'a' 'e' to 'æ'
+-compose ',' 'C' to 'Ç'
+-compose ',' 'c' to 'ç'
+-compose '`' 'E' to 'È'
+-compose '`' 'e' to 'è'
+-compose '\'' 'E' to 'É'
+-compose '\'' 'e' to 'é'
+-compose '^' 'E' to 'Ê'
+-compose '^' 'e' to 'ê'
+-compose '"' 'E' to 'Ë'
+-compose '"' 'e' to 'ë'
+-compose '`' 'I' to 'Ì'
+-compose '`' 'i' to 'ì'
+-compose '\'' 'I' to 'Í'
+-compose '\'' 'i' to 'í'
+-compose '^' 'I' to 'Î'
+-compose '^' 'i' to 'î'
+-compose '"' 'I' to 'Ï'
+-compose '"' 'i' to 'ï'
+-compose '-' 'D' to 'Ð'
+-compose '-' 'd' to 'ð'
+-compose '~' 'N' to 'Ñ'
+-compose '~' 'n' to 'ñ'
+-compose '`' 'O' to 'Ò'
+-compose '`' 'o' to 'ò'
+-compose '\'' 'O' to 'Ó'
+-compose '\'' 'o' to 'ó'
+-compose '^' 'O' to 'Ô'
+-compose '^' 'o' to 'ô'
+-compose '~' 'O' to 'Õ'
+-compose '~' 'o' to 'õ'
+-compose '"' 'O' to 'Ö'
+-compose '"' 'o' to 'ö'
+-compose '/' 'O' to 'Ø'
+-compose '/' 'o' to 'ø'
+-compose '`' 'U' to 'Ù'
+-compose '`' 'u' to 'ù'
+-compose '\'' 'U' to 'Ú'
+-compose '\'' 'u' to 'ú'
+-compose '^' 'U' to 'Û'
+-compose '^' 'u' to 'û'
+-compose '"' 'U' to 'Ü'
+-compose '"' 'u' to 'ü'
+-compose '\'' 'Y' to 'Ý'
+-compose '\'' 'y' to 'ý'
+-compose 'T' 'H' to 'Þ'
+-compose 't' 'h' to 'þ'
+-compose 's' 's' to 'ß'
+-compose '"' 'y' to 'ÿ'
+-compose 's' 'z' to 'ß'
+-compose 'i' 'j' to 'ÿ'
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 4c3a5ca..eb6b13f 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -645,6 +645,7 @@ void add_input_randomness(unsigned int t
+ add_timer_randomness(&input_timer_state,
+ (type << 4) ^ code ^ (code >> 4) ^ value);
+ }
++EXPORT_SYMBOL_GPL(add_input_randomness);
+
+ void add_interrupt_randomness(int irq)
+ {
+@@ -655,6 +656,7 @@ void add_interrupt_randomness(int irq)
+ add_timer_randomness(irq_timer_state[irq], 0x100 + irq);
+ }
+
++#ifdef CONFIG_BLOCK
+ void add_disk_randomness(struct gendisk *disk)
+ {
+ if (!disk || !disk->random)
+@@ -667,6 +669,7 @@ void add_disk_randomness(struct gendisk
+ }
+
+ EXPORT_SYMBOL(add_disk_randomness);
++#endif
+
+ #define EXTRACT_SIZE 10
+
+@@ -887,8 +890,8 @@ static void init_std_data(struct entropy
+
+ do_gettimeofday(&tv);
+ add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4);
+- add_entropy_words(r, (__u32 *)&system_utsname,
+- sizeof(system_utsname)/4);
++ add_entropy_words(r, (__u32 *)utsname(),
++ sizeof(*(utsname()))/4);
+ }
+
+ static int __init rand_initialize(void)
+@@ -918,6 +921,7 @@ void rand_initialize_irq(int irq)
+ }
+ }
+
++#ifdef CONFIG_BLOCK
+ void rand_initialize_disk(struct gendisk *disk)
+ {
+ struct timer_rand_state *state;
+@@ -932,6 +936,7 @@ void rand_initialize_disk(struct gendisk
+ disk->random = state;
+ }
+ }
++#endif
+
+ static ssize_t
+ random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
+diff --git a/drivers/char/raw.c b/drivers/char/raw.c
+index 579868a..89b718e 100644
+--- a/drivers/char/raw.c
++++ b/drivers/char/raw.c
+@@ -238,39 +238,14 @@ out:
+ return err;
+ }
+
+-static ssize_t raw_file_write(struct file *file, const char __user *buf,
+- size_t count, loff_t *ppos)
+-{
+- struct iovec local_iov = {
+- .iov_base = (char __user *)buf,
+- .iov_len = count
+- };
+-
+- return generic_file_write_nolock(file, &local_iov, 1, ppos);
+-}
+-
+-static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos)
+-{
+- struct iovec local_iov = {
+- .iov_base = (char __user *)buf,
+- .iov_len = count
+- };
+-
+- return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+-}
+-
+-
+ static const struct file_operations raw_fops = {
+- .read = generic_file_read,
++ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+- .write = raw_file_write,
+- .aio_write = raw_file_aio_write,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write_nolock,
+ .open = raw_open,
+ .release= raw_release,
+ .ioctl = raw_ioctl,
+- .readv = generic_file_readv,
+- .writev = generic_file_writev,
+ .owner = THIS_MODULE,
+ };
+
+@@ -288,31 +263,34 @@ static struct cdev raw_cdev = {
+ static int __init raw_init(void)
+ {
+ dev_t dev = MKDEV(RAW_MAJOR, 0);
++ int ret;
+
+- if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw"))
++ ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw");
++ if (ret)
+ goto error;
+
+ cdev_init(&raw_cdev, &raw_fops);
+- if (cdev_add(&raw_cdev, dev, MAX_RAW_MINORS)) {
++ ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS);
++ if (ret) {
+ kobject_put(&raw_cdev.kobj);
+- unregister_chrdev_region(dev, MAX_RAW_MINORS);
+- goto error;
++ goto error_region;
+ }
+
+ raw_class = class_create(THIS_MODULE, "raw");
+ if (IS_ERR(raw_class)) {
+ printk(KERN_ERR "Error creating raw class.\n");
+ cdev_del(&raw_cdev);
+- unregister_chrdev_region(dev, MAX_RAW_MINORS);
+- goto error;
++ ret = PTR_ERR(raw_class);
++ goto error_region;
+ }
+ class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
+
+ return 0;
+
++error_region:
++ unregister_chrdev_region(dev, MAX_RAW_MINORS);
+ error:
+- printk(KERN_ERR "error register raw device\n");
+- return 1;
++ return ret;
+ }
+
+ static void __exit raw_exit(void)
+diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h
+index 6b03918..9e7283b 100644
+--- a/drivers/char/rio/func.h
++++ b/drivers/char/rio/func.h
+@@ -88,7 +88,7 @@ void RIOHostReset(unsigned int, struct D
+
+ /* riointr.c */
+ void RIOTxEnable(char *);
+-void RIOServiceHost(struct rio_info *, struct Host *, int);
++void RIOServiceHost(struct rio_info *, struct Host *);
+ int riotproc(struct rio_info *, struct ttystatics *, int, int);
+
+ /* rioparam.c */
+diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h
+index ee2ddea..23d0681 100644
+--- a/drivers/char/rio/host.h
++++ b/drivers/char/rio/host.h
+@@ -44,6 +44,7 @@
+ ** the host.
+ */
+ struct Host {
++ struct pci_dev *pdev;
+ unsigned char Type; /* RIO_EISA, RIO_MCA, ... */
+ unsigned char Ivec; /* POLLED or ivec number */
+ unsigned char Mode; /* Control stuff */
+diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
+index 3fa80aa..7ac68cb 100644
+--- a/drivers/char/rio/rio_linux.c
++++ b/drivers/char/rio/rio_linux.c
+@@ -363,12 +363,12 @@ static void rio_reset_interrupt(struct H
+ }
+
+
+-static irqreturn_t rio_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t rio_interrupt(int irq, void *ptr)
+ {
+ struct Host *HostP;
+ func_enter();
+
+- HostP = (struct Host *) ptr; /* &p->RIOHosts[(long)ptr]; */
++ HostP = ptr; /* &p->RIOHosts[(long)ptr]; */
+ rio_dprintk(RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
+
+ /* AAargh! The order in which to do these things is essential and
+@@ -402,7 +402,7 @@ static irqreturn_t rio_interrupt(int irq
+ return IRQ_HANDLED;
+ }
+
+- RIOServiceHost(p, HostP, irq);
++ RIOServiceHost(p, HostP);
+
+ rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", ptr, HostP->Type);
+
+@@ -417,7 +417,7 @@ static void rio_pollfunc(unsigned long d
+ {
+ func_enter();
+
+- rio_interrupt(0, &p->RIOHosts[data], NULL);
++ rio_interrupt(0, &p->RIOHosts[data]);
+ p->RIOHosts[data].timer.expires = jiffies + rio_poll;
+ add_timer(&p->RIOHosts[data].timer);
+
+@@ -727,7 +727,7 @@ static struct vpd_prom *get_VPD_PROM(str
+ return &vpdp;
+ }
+
+-static struct tty_operations rio_ops = {
++static const struct tty_operations rio_ops = {
+ .open = riotopen,
+ .close = gs_close,
+ .write = gs_write,
+@@ -1017,6 +1017,10 @@ static int __init rio_init(void)
+ rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+ fix_rio_pci(pdev);
++
++ p->RIOHosts[p->RIONumHosts].pdev = pdev;
++ pci_dev_get(pdev);
++
+ p->RIOLastPCISearch = 0;
+ p->RIONumHosts++;
+ found++;
+@@ -1066,6 +1070,9 @@ static int __init rio_init(void)
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
+ rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+
++ p->RIOHosts[p->RIONumHosts].pdev = pdev;
++ pci_dev_get(pdev);
++
+ p->RIOLastPCISearch = 0;
+ p->RIONumHosts++;
+ found++;
+@@ -1181,6 +1188,8 @@ static void __exit rio_exit(void)
+ }
+ /* It is safe/allowed to del_timer a non-active timer */
+ del_timer(&hp->timer);
++ if (hp->Type == RIO_PCI)
++ pci_dev_put(hp->pdev);
+ }
+
+ if (misc_deregister(&rio_fw_device) < 0) {
+diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
+index 052e812..7ce7761 100644
+--- a/drivers/char/rio/rioctrl.c
++++ b/drivers/char/rio/rioctrl.c
+@@ -662,7 +662,7 @@ int riocontrol(struct rio_info *p, dev_t
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+- if (portStats.port >= RIO_PORTS) {
++ if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+@@ -702,7 +702,7 @@ int riocontrol(struct rio_info *p, dev_t
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+- if (portStats.port >= RIO_PORTS) {
++ if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
+index 0bd0904..eeda40c 100644
+--- a/drivers/char/rio/riointr.c
++++ b/drivers/char/rio/riointr.c
+@@ -181,7 +181,7 @@ static int RupIntr;
+ static int RxIntr;
+ static int TxIntr;
+
+-void RIOServiceHost(struct rio_info *p, struct Host *HostP, int From)
++void RIOServiceHost(struct rio_info *p, struct Host *HostP)
+ {
+ rio_spin_lock(&HostP->HostLock);
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
+index f1c94f7..5ab32b3 100644
+--- a/drivers/char/riscom8.c
++++ b/drivers/char/riscom8.c
+@@ -81,7 +81,6 @@
+
+ static struct riscom_board * IRQ_to_board[16];
+ static struct tty_driver *riscom_driver;
+-static unsigned char * tmp_buf;
+
+ static unsigned long baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+@@ -551,7 +550,7 @@ static inline void rc_check_modem(struct
+ }
+
+ /* The main interrupt processing routine */
+-static irqreturn_t rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++static irqreturn_t rc_interrupt(int irq, void * dev_id)
+ {
+ unsigned char status;
+ unsigned char ack;
+@@ -560,11 +559,10 @@ static irqreturn_t rc_interrupt(int irq,
+ int handled = 0;
+
+ bp = IRQ_to_board[irq];
+-
+- if (!bp || !(bp->flags & RC_BOARD_ACTIVE)) {
++
++ if (!(bp->flags & RC_BOARD_ACTIVE))
+ return IRQ_NONE;
+- }
+-
++
+ while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
+ (RC_BSR_TOUT | RC_BSR_TINT |
+ RC_BSR_MINT | RC_BSR_RINT))) {
+@@ -675,26 +673,12 @@ static void rc_change_speed(struct risco
+ port->COR2 = 0;
+ port->MSVR = MSVR_RTS;
+
+- baud = C_BAUD(tty);
+-
+- if (baud & CBAUDEX) {
+- baud &= ~CBAUDEX;
+- if (baud < 1 || baud > 2)
+- port->tty->termios->c_cflag &= ~CBAUDEX;
+- else
+- baud += 15;
+- }
+- if (baud == 15) {
+- if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+- baud ++;
+- if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+- baud += 2;
+- }
++ baud = tty_get_baud_rate(tty);
+
+ /* Select port on the board */
+ rc_out(bp, CD180_CAR, port_No(port));
+
+- if (!baud_table[baud]) {
++ if (!baud) {
+ /* Drop DTR & exit */
+ bp->DTR |= (1u << port_No(port));
+ rc_out(bp, RC_DTR, bp->DTR);
+@@ -710,7 +694,7 @@ static void rc_change_speed(struct risco
+ */
+
+ /* Set baud rate for port */
+- tmp = (((RC_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
++ tmp = (((RC_OSCFREQ + baud/2) / baud +
+ CD180_TPC/2) / CD180_TPC);
+
+ rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
+@@ -718,7 +702,7 @@ static void rc_change_speed(struct risco
+ rc_out(bp, CD180_RBPRL, tmp & 0xff);
+ rc_out(bp, CD180_TBPRL, tmp & 0xff);
+
+- baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */
++ baud = (baud + 5) / 10; /* Estimated CPS */
+
+ /* Two timer ticks seems enough to wakeup something like SLIP driver */
+ tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
+@@ -1138,7 +1122,7 @@ static int rc_write(struct tty_struct *
+
+ bp = port_Board(port);
+
+- if (!tty || !port->xmit_buf || !tmp_buf)
++ if (!tty || !port->xmit_buf)
+ return 0;
+
+ save_flags(flags);
+@@ -1597,7 +1581,7 @@ static void do_softint(void *private_)
+ }
+ }
+
+-static struct tty_operations riscom_ops = {
++static const struct tty_operations riscom_ops = {
+ .open = rc_open,
+ .close = rc_close,
+ .write = rc_write,
+@@ -1626,11 +1610,6 @@ static inline int rc_init_drivers(void)
+ if (!riscom_driver)
+ return -ENOMEM;
+
+- if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
+- printk(KERN_ERR "rc: Couldn't get free page.\n");
+- put_tty_driver(riscom_driver);
+- return 1;
+- }
+ memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
+ riscom_driver->owner = THIS_MODULE;
+ riscom_driver->name = "ttyL";
+@@ -1643,7 +1622,6 @@ static inline int rc_init_drivers(void)
+ riscom_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(riscom_driver, &riscom_ops);
+ if ((error = tty_register_driver(riscom_driver))) {
+- free_page((unsigned long)tmp_buf);
+ put_tty_driver(riscom_driver);
+ printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
+ "error = %d\n",
+@@ -1671,7 +1649,6 @@ static void rc_release_drivers(void)
+
+ save_flags(flags);
+ cli();
+- free_page((unsigned long)tmp_buf);
+ tty_unregister_driver(riscom_driver);
+ put_tty_driver(riscom_driver);
+ restore_flags(flags);
+diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
+index 0ac1318..bac8005 100644
+--- a/drivers/char/rocket.c
++++ b/drivers/char/rocket.c
+@@ -2334,7 +2334,7 @@ static int __init init_ISA(int i)
+ return (1);
+ }
+
+-static struct tty_operations rocket_ops = {
++static const struct tty_operations rocket_ops = {
+ .open = rp_open,
+ .close = rp_close,
+ .write = rp_write,
+diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
+index 6e6a7c7..66a7385 100644
+--- a/drivers/char/rtc.c
++++ b/drivers/char/rtc.c
+@@ -35,13 +35,13 @@
+ * 1.09a Pete Zaitcev: Sun SPARC
+ * 1.09b Jeff Garzik: Modularize, init cleanup
+ * 1.09c Jeff Garzik: SMP cleanup
+- * 1.10 Paul Barton-Davis: add support for async I/O
++ * 1.10 Paul Barton-Davis: add support for async I/O
+ * 1.10a Andrea Arcangeli: Alpha updates
+ * 1.10b Andrew Morton: SMP lock fix
+ * 1.10c Cesar Barros: SMP locking fixes and cleanup
+ * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit
+ * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness.
+- * 1.11 Takashi Iwai: Kernel access functions
++ * 1.11 Takashi Iwai: Kernel access functions
+ * rtc_register/rtc_unregister/rtc_control
+ * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
+ * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
+@@ -113,9 +113,9 @@ static int rtc_has_irq = 1;
+ #define hpet_set_rtc_irq_bit(arg) 0
+ #define hpet_rtc_timer_init() do { } while (0)
+ #define hpet_rtc_dropped_irq() 0
+-static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;}
++static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) {return 0;}
+ #else
+-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+ #endif
+
+ /*
+@@ -209,11 +209,12 @@ static const unsigned char days_in_mo[]
+ */
+ static inline unsigned char rtc_is_updating(void)
+ {
++ unsigned long flags;
+ unsigned char uip;
+
+- spin_lock_irq(&rtc_lock);
++ spin_lock_irqsave(&rtc_lock, flags);
+ uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+- spin_unlock_irq(&rtc_lock);
++ spin_unlock_irqrestore(&rtc_lock, flags);
+ return uip;
+ }
+
+@@ -228,7 +229,7 @@ static inline unsigned char rtc_is_updat
+ * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
+ */
+
+-irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t rtc_interrupt(int irq, void *dev_id)
+ {
+ /*
+ * Can be an alarm interrupt, update complete interrupt,
+@@ -914,7 +915,7 @@ static const struct file_operations rtc_
+ };
+
+ #if defined(RTC_IRQ) && !defined(__sparc__)
+-static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs);
++static irq_handler_t rtc_int_handler_ptr;
+ #endif
+
+ static int __init rtc_init(void)
+@@ -1261,10 +1262,8 @@ void rtc_get_rtc_time(struct rtc_time *r
+ * Once the read clears, read the RTC time (again via ioctl). Easy.
+ */
+
+- while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) {
+- barrier();
++ while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100)
+ cpu_relax();
+- }
+
+ /*
+ * Only the values that we read from the RTC are set. We leave
+diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
+deleted file mode 100644
+index 5458ef1..0000000
+--- a/drivers/char/s3c2410-rtc.c
++++ /dev/null
+@@ -1,591 +0,0 @@
+-/* drivers/char/s3c2410_rtc.c
+- *
+- * Copyright (c) 2004 Simtec Electronics <linux at simtec.co.uk>
+- * http://www.simtec.co.uk/products/SWLINUX/
+- *
+- * 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.
+- *
+- * S3C2410 Internal RTC Driver
+- *
+- * Changelog:
+- * 08-Nov-2004 BJD Initial creation
+- * 12-Nov-2004 BJD Added periodic IRQ and PM code
+- * 22-Nov-2004 BJD Sign-test on alarm code to check for <0
+- * 10-Mar-2005 LCVR Changed S3C2410_VA_RTC to S3C24XX_VA_RTC
+-*/
+-
+-#include <linux/module.h>
+-#include <linux/fs.h>
+-#include <linux/string.h>
+-#include <linux/init.h>
+-#include <linux/platform_device.h>
+-#include <linux/interrupt.h>
+-#include <linux/rtc.h>
+-#include <linux/bcd.h>
+-#include <linux/clk.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/rtc.h>
+-
+-#include <asm/mach/time.h>
+-
+-#include <asm/arch/regs-rtc.h>
+-
+-/* need this for the RTC_AF definitions */
+-#include <linux/mc146818rtc.h>
+-
+-#undef S3C24XX_VA_RTC
+-#define S3C24XX_VA_RTC s3c2410_rtc_base
+-
+-static struct resource *s3c2410_rtc_mem;
+-
+-static void __iomem *s3c2410_rtc_base;
+-static int s3c2410_rtc_alarmno = NO_IRQ;
+-static int s3c2410_rtc_tickno = NO_IRQ;
+-static int s3c2410_rtc_freq = 1;
+-
+-static DEFINE_SPINLOCK(s3c2410_rtc_pie_lock);
+-
+-/* IRQ Handlers */
+-
+-static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
+-{
+- rtc_update(1, RTC_AF | RTC_IRQF);
+- return IRQ_HANDLED;
+-}
+-
+-static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r)
+-{
+- rtc_update(1, RTC_PF | RTC_IRQF);
+- return IRQ_HANDLED;
+-}
+-
+-/* Update control registers */
+-static void s3c2410_rtc_setaie(int to)
+-{
+- unsigned int tmp;
+-
+- pr_debug("%s: aie=%d\n", __FUNCTION__, to);
+-
+- tmp = readb(S3C2410_RTCALM);
+-
+- if (to)
+- tmp |= S3C2410_RTCALM_ALMEN;
+- else
+- tmp &= ~S3C2410_RTCALM_ALMEN;
+-
+-
+- writeb(tmp, S3C2410_RTCALM);
+-}
+-
+-static void s3c2410_rtc_setpie(int to)
+-{
+- unsigned int tmp;
+-
+- pr_debug("%s: pie=%d\n", __FUNCTION__, to);
+-
+- spin_lock_irq(&s3c2410_rtc_pie_lock);
+- tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
+-
+- if (to)
+- tmp |= S3C2410_TICNT_ENABLE;
+-
+- writeb(tmp, S3C2410_TICNT);
+- spin_unlock_irq(&s3c2410_rtc_pie_lock);
+-}
+-
+-static void s3c2410_rtc_setfreq(int freq)
+-{
+- unsigned int tmp;
+-
+- spin_lock_irq(&s3c2410_rtc_pie_lock);
+- tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
+-
+- s3c2410_rtc_freq = freq;
+-
+- tmp |= (128 / freq)-1;
+-
+- writeb(tmp, S3C2410_TICNT);
+- spin_unlock_irq(&s3c2410_rtc_pie_lock);
+-}
+-
+-/* Time read/write */
+-
+-static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
+-{
+- unsigned int have_retried = 0;
+-
+- retry_get_time:
+- rtc_tm->tm_min = readb(S3C2410_RTCMIN);
+- rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
+- rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
+- rtc_tm->tm_mon = readb(S3C2410_RTCMON);
+- rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
+- rtc_tm->tm_sec = readb(S3C2410_RTCSEC);
+-
+- /* the only way to work out wether the system was mid-update
+- * when we read it is to check the second counter, and if it
+- * is zero, then we re-try the entire read
+- */
+-
+- if (rtc_tm->tm_sec == 0 && !have_retried) {
+- have_retried = 1;
+- goto retry_get_time;
+- }
+-
+- pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
+- rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+- rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+-
+- BCD_TO_BIN(rtc_tm->tm_sec);
+- BCD_TO_BIN(rtc_tm->tm_min);
+- BCD_TO_BIN(rtc_tm->tm_hour);
+- BCD_TO_BIN(rtc_tm->tm_mday);
+- BCD_TO_BIN(rtc_tm->tm_mon);
+- BCD_TO_BIN(rtc_tm->tm_year);
+-
+- rtc_tm->tm_year += 100;
+- rtc_tm->tm_mon -= 1;
+-
+- return 0;
+-}
+-
+-
+-static int s3c2410_rtc_settime(struct rtc_time *tm)
+-{
+- /* the rtc gets round the y2k problem by just not supporting it */
+-
+- if (tm->tm_year < 100)
+- return -EINVAL;
+-
+- writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC);
+- writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN);
+- writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
+- writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
+- writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
+- writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);
+-
+- return 0;
+-}
+-
+-static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
+-{
+- struct rtc_time *alm_tm = &alrm->time;
+- unsigned int alm_en;
+-
+- alm_tm->tm_sec = readb(S3C2410_ALMSEC);
+- alm_tm->tm_min = readb(S3C2410_ALMMIN);
+- alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
+- alm_tm->tm_mon = readb(S3C2410_ALMMON);
+- alm_tm->tm_mday = readb(S3C2410_ALMDATE);
+- alm_tm->tm_year = readb(S3C2410_ALMYEAR);
+-
+- alm_en = readb(S3C2410_RTCALM);
+-
+- pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
+- alm_en,
+- alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+- alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+-
+-
+- /* decode the alarm enable field */
+-
+- if (alm_en & S3C2410_RTCALM_SECEN) {
+- BCD_TO_BIN(alm_tm->tm_sec);
+- } else {
+- alm_tm->tm_sec = 0xff;
+- }
+-
+- if (alm_en & S3C2410_RTCALM_MINEN) {
+- BCD_TO_BIN(alm_tm->tm_min);
+- } else {
+- alm_tm->tm_min = 0xff;
+- }
+-
+- if (alm_en & S3C2410_RTCALM_HOUREN) {
+- BCD_TO_BIN(alm_tm->tm_hour);
+- } else {
+- alm_tm->tm_hour = 0xff;
+- }
+-
+- if (alm_en & S3C2410_RTCALM_DAYEN) {
+- BCD_TO_BIN(alm_tm->tm_mday);
+- } else {
+- alm_tm->tm_mday = 0xff;
+- }
+-
+- if (alm_en & S3C2410_RTCALM_MONEN) {
+- BCD_TO_BIN(alm_tm->tm_mon);
+- alm_tm->tm_mon -= 1;
+- } else {
+- alm_tm->tm_mon = 0xff;
+- }
+-
+- if (alm_en & S3C2410_RTCALM_YEAREN) {
+- BCD_TO_BIN(alm_tm->tm_year);
+- } else {
+- alm_tm->tm_year = 0xffff;
+- }
+-
+- /* todo - set alrm->enabled ? */
+-
+- return 0;
+-}
+-
+-static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
+-{
+- struct rtc_time *tm = &alrm->time;
+- unsigned int alrm_en;
+-
+- pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
+- alrm->enabled,
+- tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
+- tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
+-
+- if (alrm->enabled || 1) {
+- alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
+- writeb(0x00, S3C2410_RTCALM);
+-
+- if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
+- alrm_en |= S3C2410_RTCALM_SECEN;
+- writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
+- }
+-
+- if (tm->tm_min < 60 && tm->tm_min >= 0) {
+- alrm_en |= S3C2410_RTCALM_MINEN;
+- writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
+- }
+-
+- if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
+- alrm_en |= S3C2410_RTCALM_HOUREN;
+- writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
+- }
+-
+- pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
+-
+- writeb(alrm_en, S3C2410_RTCALM);
+- enable_irq_wake(s3c2410_rtc_alarmno);
+- } else {
+- alrm_en = readb(S3C2410_RTCALM);
+- alrm_en &= ~S3C2410_RTCALM_ALMEN;
+- writeb(alrm_en, S3C2410_RTCALM);
+- disable_irq_wake(s3c2410_rtc_alarmno);
+- }
+-
+- return 0;
+-}
+-
+-static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg)
+-{
+- switch (cmd) {
+- case RTC_AIE_OFF:
+- case RTC_AIE_ON:
+- s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
+- return 0;
+-
+- case RTC_PIE_OFF:
+- case RTC_PIE_ON:
+- s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
+- return 0;
+-
+- case RTC_IRQP_READ:
+- return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg);
+-
+- case RTC_IRQP_SET:
+- if (arg < 1 || arg > 64)
+- return -EINVAL;
+-
+- if (!capable(CAP_SYS_RESOURCE))
+- return -EACCES;
+-
+- /* check for power of 2 */
+-
+- if ((arg & (arg-1)) != 0)
+- return -EINVAL;
+-
+- pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
+-
+- s3c2410_rtc_setfreq(arg);
+- return 0;
+-
+- case RTC_UIE_ON:
+- case RTC_UIE_OFF:
+- return -EINVAL;
+- }
+-
+- return -EINVAL;
+-}
+-
+-static int s3c2410_rtc_proc(char *buf)
+-{
+- unsigned int rtcalm = readb(S3C2410_RTCALM);
+- unsigned int ticnt = readb (S3C2410_TICNT);
+- char *p = buf;
+-
+- p += sprintf(p, "alarm_IRQ\t: %s\n",
+- (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
+- p += sprintf(p, "periodic_IRQ\t: %s\n",
+- (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+- p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq);
+-
+- return p - buf;
+-}
+-
+-static int s3c2410_rtc_open(void)
+-{
+- int ret;
+-
+- ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq,
+- IRQF_DISABLED, "s3c2410-rtc alarm", NULL);
+-
+- if (ret)
+- printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno);
+-
+- ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq,
+- IRQF_DISABLED, "s3c2410-rtc tick", NULL);
+-
+- if (ret) {
+- printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno);
+- goto tick_err;
+- }
+-
+- return ret;
+-
+- tick_err:
+- free_irq(s3c2410_rtc_alarmno, NULL);
+- return ret;
+-}
+-
+-static void s3c2410_rtc_release(void)
+-{
+- /* do not clear AIE here, it may be needed for wake */
+-
+- s3c2410_rtc_setpie(0);
+- free_irq(s3c2410_rtc_alarmno, NULL);
+- free_irq(s3c2410_rtc_tickno, NULL);
+-}
+-
+-static struct rtc_ops s3c2410_rtcops = {
+- .owner = THIS_MODULE,
+- .open = s3c2410_rtc_open,
+- .release = s3c2410_rtc_release,
+- .ioctl = s3c2410_rtc_ioctl,
+- .read_time = s3c2410_rtc_gettime,
+- .set_time = s3c2410_rtc_settime,
+- .read_alarm = s3c2410_rtc_getalarm,
+- .set_alarm = s3c2410_rtc_setalarm,
+- .proc = s3c2410_rtc_proc,
+-};
+-
+-static void s3c2410_rtc_enable(struct platform_device *pdev, int en)
+-{
+- unsigned int tmp;
+-
+- if (s3c2410_rtc_base == NULL)
+- return;
+-
+- if (!en) {
+- tmp = readb(S3C2410_RTCCON);
+- writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);
+-
+- tmp = readb(S3C2410_TICNT);
+- writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
+- } else {
+- /* re-enable the device, and check it is ok */
+-
+- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
+- dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
+-
+- tmp = readb(S3C2410_RTCCON);
+- writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
+- }
+-
+- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
+- dev_info(&pdev->dev, "removing S3C2410_RTCCON_CNTSEL\n");
+-
+- tmp = readb(S3C2410_RTCCON);
+- writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
+- }
+-
+- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
+- dev_info(&pdev->dev, "removing S3C2410_RTCCON_CLKRST\n");
+-
+- tmp = readb(S3C2410_RTCCON);
+- writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
+- }
+- }
+-}
+-
+-static int s3c2410_rtc_remove(struct platform_device *dev)
+-{
+- unregister_rtc(&s3c2410_rtcops);
+-
+- s3c2410_rtc_setpie(0);
+- s3c2410_rtc_setaie(0);
+-
+- if (s3c2410_rtc_mem != NULL) {
+- pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n");
+- iounmap(s3c2410_rtc_base);
+- release_resource(s3c2410_rtc_mem);
+- kfree(s3c2410_rtc_mem);
+- }
+-
+- return 0;
+-}
+-
+-static int s3c2410_rtc_probe(struct platform_device *pdev)
+-{
+- struct resource *res;
+- int ret;
+-
+- pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
+-
+- /* find the IRQs */
+-
+- s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
+- if (s3c2410_rtc_tickno < 0) {
+- dev_err(&pdev->dev, "no irq for rtc tick\n");
+- return -ENOENT;
+- }
+-
+- s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
+- if (s3c2410_rtc_alarmno < 0) {
+- dev_err(&pdev->dev, "no irq for alarm\n");
+- return -ENOENT;
+- }
+-
+- pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
+- s3c2410_rtc_tickno, s3c2410_rtc_alarmno);
+-
+- /* get the memory region */
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (res == NULL) {
+- dev_err(&pdev->dev, "failed to get memory region resource\n");
+- return -ENOENT;
+- }
+-
+- s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,
+- pdev->name);
+-
+- if (s3c2410_rtc_mem == NULL) {
+- dev_err(&pdev->dev, "failed to reserve memory region\n");
+- ret = -ENOENT;
+- goto exit_err;
+- }
+-
+- s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
+- if (s3c2410_rtc_base == NULL) {
+- dev_err(&pdev->dev, "failed ioremap()\n");
+- ret = -EINVAL;
+- goto exit_err;
+- }
+-
+- s3c2410_rtc_mem = res;
+- pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);
+-
+- pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
+-
+- /* check to see if everything is setup correctly */
+-
+- s3c2410_rtc_enable(pdev, 1);
+-
+- pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
+-
+- s3c2410_rtc_setfreq(s3c2410_rtc_freq);
+-
+- /* register RTC and exit */
+-
+- register_rtc(&s3c2410_rtcops);
+- return 0;
+-
+- exit_err:
+- dev_err(&pdev->dev, "error %d during initialisation\n", ret);
+-
+- return ret;
+-}
+-
+-#ifdef CONFIG_PM
+-
+-/* S3C2410 RTC Power management control */
+-
+-static struct timespec s3c2410_rtc_delta;
+-
+-static int ticnt_save;
+-
+-static int s3c2410_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+-{
+- struct rtc_time tm;
+- struct timespec time;
+-
+- time.tv_nsec = 0;
+-
+- /* save TICNT for anyone using periodic interrupts */
+-
+- ticnt_save = readb(S3C2410_TICNT);
+-
+- /* calculate time delta for suspend */
+-
+- s3c2410_rtc_gettime(&tm);
+- rtc_tm_to_time(&tm, &time.tv_sec);
+- save_time_delta(&s3c2410_rtc_delta, &time);
+- s3c2410_rtc_enable(pdev, 0);
+-
+- return 0;
+-}
+-
+-static int s3c2410_rtc_resume(struct platform_device *pdev)
+-{
+- struct rtc_time tm;
+- struct timespec time;
+-
+- time.tv_nsec = 0;
+-
+- s3c2410_rtc_enable(pdev, 1);
+- s3c2410_rtc_gettime(&tm);
+- rtc_tm_to_time(&tm, &time.tv_sec);
+- restore_time_delta(&s3c2410_rtc_delta, &time);
+-
+- writeb(ticnt_save, S3C2410_TICNT);
+- return 0;
+-}
+-#else
+-#define s3c2410_rtc_suspend NULL
+-#define s3c2410_rtc_resume NULL
+-#endif
+-
+-static struct platform_driver s3c2410_rtcdrv = {
+- .probe = s3c2410_rtc_probe,
+- .remove = s3c2410_rtc_remove,
+- .suspend = s3c2410_rtc_suspend,
+- .resume = s3c2410_rtc_resume,
+- .driver = {
+- .name = "s3c2410-rtc",
+- .owner = THIS_MODULE,
+- },
+-};
+-
+-static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";
+-
+-static int __init s3c2410_rtc_init(void)
+-{
+- printk(banner);
+- return platform_driver_register(&s3c2410_rtcdrv);
+-}
+-
+-static void __exit s3c2410_rtc_exit(void)
+-{
+- platform_driver_unregister(&s3c2410_rtcdrv);
+-}
+-
+-module_init(s3c2410_rtc_init);
+-module_exit(s3c2410_rtc_exit);
+-
+-MODULE_DESCRIPTION("S3C24XX RTC Driver");
+-MODULE_AUTHOR("Ben Dooks, <ben at simtec.co.uk>");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c
+index b956c7b..99e5272 100644
+--- a/drivers/char/scx200_gpio.c
++++ b/drivers/char/scx200_gpio.c
+@@ -44,7 +44,7 @@ struct nsc_gpio_ops scx200_gpio_ops = {
+ .gpio_change = scx200_gpio_change,
+ .gpio_current = scx200_gpio_current
+ };
+-EXPORT_SYMBOL(scx200_gpio_ops);
++EXPORT_SYMBOL_GPL(scx200_gpio_ops);
+
+ static int scx200_gpio_open(struct inode *inode, struct file *file)
+ {
+@@ -69,7 +69,7 @@ static const struct file_operations scx2
+ .release = scx200_gpio_release,
+ };
+
+-struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
++static struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
+
+ static int __init scx200_gpio_init(void)
+ {
+diff --git a/drivers/char/selection.c b/drivers/char/selection.c
+index 71093a9..74cff83 100644
+--- a/drivers/char/selection.c
++++ b/drivers/char/selection.c
+@@ -33,7 +33,7 @@ extern void poke_blanked_console(void);
+
+ /* Variables for selection control. */
+ /* Use a dynamic buffer, instead of static (Dec 1994) */
+-struct vc_data *sel_cons; /* must not be disallocated */
++struct vc_data *sel_cons; /* must not be deallocated */
+ static volatile int sel_start = -1; /* cleared by clear_selection */
+ static int sel_end;
+ static int sel_buffer_lth;
+diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
+index 510bd3e..4217d38 100644
+--- a/drivers/char/ser_a2232.c
++++ b/drivers/char/ser_a2232.c
+@@ -111,7 +111,7 @@
+
+ /***************************** Prototypes ***************************/
+ /* The interrupt service routine */
+-static irqreturn_t a2232_vbl_inter(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t a2232_vbl_inter(int irq, void *data);
+ /* Initialize the port structures */
+ static void a2232_init_portstructs(void);
+ /* Initialize and register TTY drivers. */
+@@ -504,7 +504,7 @@ static int a2232_open(struct tty_struct
+ }
+ /*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/
+
+-static irqreturn_t a2232_vbl_inter(int irq, void *data, struct pt_regs *fp)
++static irqreturn_t a2232_vbl_inter(int irq, void *data)
+ {
+ #if A2232_IOBUFLEN != 256
+ #error "Re-Implement a2232_vbl_inter()!"
+@@ -661,7 +661,7 @@ static void a2232_init_portstructs(void)
+ }
+ }
+
+-static struct tty_operations a2232_ops = {
++static const struct tty_operations a2232_ops = {
+ .open = a2232_open,
+ .close = gs_close,
+ .write = gs_write,
+diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
+index 21a710c..3af7f09 100644
+--- a/drivers/char/serial167.c
++++ b/drivers/char/serial167.c
+@@ -62,6 +62,7 @@
+ #include <linux/console.h>
+ #include <linux/module.h>
+ #include <linux/bitops.h>
++#include <linux/tty_flip.h>
+
+ #include <asm/system.h>
+ #include <asm/io.h>
+@@ -119,17 +120,6 @@ struct cyclades_port cy_port[] = {
+ #define NR_PORTS ARRAY_SIZE(cy_port)
+
+ /*
+- * 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 = 0;
+-
+-/*
+ * This is used to look up the divisor speeds and the timeouts
+ * We're normally limited to 15 distinct baud rates. The extra
+ * are accessed via settings in info->flags.
+@@ -381,7 +371,7 @@ cy_sched_event(struct cyclades_port *inf
+ received, out buffer empty, modem change, etc.
+ */
+ static irqreturn_t
+-cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++cd2401_rxerr_interrupt(int irq, void *dev_id)
+ {
+ struct tty_struct *tty;
+ struct cyclades_port *info;
+@@ -438,8 +428,9 @@ cd2401_rxerr_interrupt(int irq, void *de
+ overflowing, we still loose
+ the next incoming character.
+ */
+- tty_insert_flip_char(tty, data, TTY_NORMAL);
+- }
++ if (tty_buffer_request_room(tty, 1) != 0){
++ tty_insert_flip_char(tty, data, TTY_FRAME);
++ }
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* else if(data & CyTIMEOUT) */
+@@ -448,21 +439,21 @@ cd2401_rxerr_interrupt(int irq, void *de
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
+ }
+ }else{
+- tty_insert_flip_char(tty, data, TTY_NORMAL);
++ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ }
+ }else{
+ /* there was a software buffer overrun
+ and nothing could be done about it!!! */
+ }
+ }
+- schedule_delayed_work(&tty->flip.work, 1);
++ tty_schedule_flip(tty);
+ /* end of service */
+ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
+ return IRQ_HANDLED;
+ } /* cy_rxerr_interrupt */
+
+ static irqreturn_t
+-cd2401_modem_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++cd2401_modem_interrupt(int irq, void *dev_id)
+ {
+ struct cyclades_port *info;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+@@ -517,7 +508,7 @@ cd2401_modem_interrupt(int irq, void *de
+ } /* cy_modem_interrupt */
+
+ static irqreturn_t
+-cd2401_tx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++cd2401_tx_interrupt(int irq, void *dev_id)
+ {
+ struct cyclades_port *info;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+@@ -637,7 +628,7 @@ cd2401_tx_interrupt(int irq, void *dev_i
+ } /* cy_tx_interrupt */
+
+ static irqreturn_t
+-cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++cd2401_rx_interrupt(int irq, void *dev_id)
+ {
+ struct tty_struct *tty;
+ struct cyclades_port *info;
+@@ -646,6 +637,7 @@ cd2401_rx_interrupt(int irq, void *dev_i
+ char data;
+ int char_count;
+ int save_cnt;
++ int len;
+
+ /* determine the channel and change to that context */
+ channel = (u_short ) (base_addr[CyLICR] >> 2);
+@@ -678,14 +670,15 @@ cd2401_rx_interrupt(int irq, void *dev_i
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
+ #endif
+- while(char_count--){
++ len = tty_buffer_request_room(tty, char_count);
++ while(len--){
+ data = base_addr[CyRDR];
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ #ifdef CYCLOM_16Y_HACK
+ udelay(10L);
+ #endif
+ }
+- schedule_delayed_work(&tty->flip.work, 1);
++ tty_schedule_flip(tty);
+ }
+ /* end of service */
+ base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
+@@ -846,7 +839,7 @@ shutdown(struct cyclades_port * info)
+ local_irq_save(flags);
+ if (info->xmit_buf){
+ free_page((unsigned long) info->xmit_buf);
+- info->xmit_buf = 0;
++ info->xmit_buf = NULL;
+ }
+
+ base_addr[CyCAR] = (u_char)channel;
+@@ -1132,7 +1125,7 @@ cy_put_char(struct tty_struct *tty, unsi
+ if (serial_paranoia_check(info, tty->name, "cy_put_char"))
+ return;
+
+- if (!tty || !info->xmit_buf)
++ if (!info->xmit_buf)
+ return;
+
+ local_irq_save(flags);
+@@ -1198,7 +1191,7 @@ cy_write(struct tty_struct * tty,
+ return 0;
+ }
+
+- if (!tty || !info->xmit_buf || !tmp_buf){
++ if (!info->xmit_buf){
+ return 0;
+ }
+
+@@ -1361,7 +1354,7 @@ cy_unthrottle(struct tty_struct * tty)
+
+ static int
+ get_serial_info(struct cyclades_port * info,
+- struct serial_struct * retinfo)
++ struct serial_struct __user * retinfo)
+ {
+ struct serial_struct tmp;
+
+@@ -1383,7 +1376,7 @@ get_serial_info(struct cyclades_port * i
+
+ static int
+ set_serial_info(struct cyclades_port * info,
+- struct serial_struct * new_info)
++ struct serial_struct __user * new_info)
+ {
+ struct serial_struct new_serial;
+ struct cyclades_port old_info;
+@@ -1433,7 +1426,6 @@ cy_tiocmget(struct tty_struct *tty, stru
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ unsigned long flags;
+ unsigned char status;
+- unsigned int result;
+
+ channel = info->line;
+
+@@ -1457,7 +1449,6 @@ cy_tiocmset(struct tty_struct *tty, stru
+ int channel;
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ unsigned long flags;
+- unsigned int arg;
+
+ channel = info->line;
+
+@@ -1512,7 +1503,7 @@ send_break( struct cyclades_port * info,
+ } /* send_break */
+
+ static int
+-get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
++get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon)
+ {
+
+ if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
+@@ -1525,7 +1516,7 @@ get_mon_info(struct cyclades_port * info
+ }
+
+ static int
+-set_threshold(struct cyclades_port * info, unsigned long *arg)
++set_threshold(struct cyclades_port * info, unsigned long __user *arg)
+ {
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ unsigned long value;
+@@ -1542,7 +1533,7 @@ set_threshold(struct cyclades_port * inf
+ }
+
+ static int
+-get_threshold(struct cyclades_port * info, unsigned long *value)
++get_threshold(struct cyclades_port * info, unsigned long __user *value)
+ {
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ int channel;
+@@ -1555,7 +1546,7 @@ get_threshold(struct cyclades_port * inf
+ }
+
+ static int
+-set_default_threshold(struct cyclades_port * info, unsigned long *arg)
++set_default_threshold(struct cyclades_port * info, unsigned long __user *arg)
+ {
+ unsigned long value;
+
+@@ -1567,13 +1558,13 @@ set_default_threshold(struct cyclades_po
+ }
+
+ static int
+-get_default_threshold(struct cyclades_port * info, unsigned long *value)
++get_default_threshold(struct cyclades_port * info, unsigned long __user *value)
+ {
+ return put_user(info->default_threshold,value);
+ }
+
+ static int
+-set_timeout(struct cyclades_port * info, unsigned long *arg)
++set_timeout(struct cyclades_port * info, unsigned long __user *arg)
+ {
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ int channel;
+@@ -1590,7 +1581,7 @@ set_timeout(struct cyclades_port * info,
+ }
+
+ static int
+-get_timeout(struct cyclades_port * info, unsigned long *value)
++get_timeout(struct cyclades_port * info, unsigned long __user *value)
+ {
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ int channel;
+@@ -1610,7 +1601,7 @@ set_default_timeout(struct cyclades_port
+ }
+
+ static int
+-get_default_timeout(struct cyclades_port * info, unsigned long *value)
++get_default_timeout(struct cyclades_port * info, unsigned long __user *value)
+ {
+ return put_user(info->default_timeout,value);
+ }
+@@ -1622,6 +1613,7 @@ cy_ioctl(struct tty_struct *tty, struct
+ unsigned long val;
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ int ret_val = 0;
++ void __user *argp = (void __user *)arg;
+
+ #ifdef SERIAL_DEBUG_OTHER
+ printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
+@@ -1629,28 +1621,28 @@ cy_ioctl(struct tty_struct *tty, struct
+
+ switch (cmd) {
+ case CYGETMON:
+- ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
++ ret_val = get_mon_info(info, argp);
+ break;
+ case CYGETTHRESH:
+- ret_val = get_threshold(info, (unsigned long *)arg);
++ ret_val = get_threshold(info, argp);
+ break;
+ case CYSETTHRESH:
+- ret_val = set_threshold(info, (unsigned long *)arg);
++ ret_val = set_threshold(info, argp);
+ break;
+ case CYGETDEFTHRESH:
+- ret_val = get_default_threshold(info, (unsigned long *)arg);
++ ret_val = get_default_threshold(info, argp);
+ break;
+ case CYSETDEFTHRESH:
+- ret_val = set_default_threshold(info, (unsigned long *)arg);
++ ret_val = set_default_threshold(info, argp);
+ break;
+ case CYGETTIMEOUT:
+- ret_val = get_timeout(info, (unsigned long *)arg);
++ ret_val = get_timeout(info, argp);
+ break;
+ case CYSETTIMEOUT:
+- ret_val = set_timeout(info, (unsigned long *)arg);
++ ret_val = set_timeout(info, argp);
+ break;
+ case CYGETDEFTIMEOUT:
+- ret_val = get_default_timeout(info, (unsigned long *)arg);
++ ret_val = get_default_timeout(info, argp);
+ break;
+ case CYSETDEFTIMEOUT:
+ ret_val = set_default_timeout(info, (unsigned long)arg);
+@@ -1673,21 +1665,20 @@ cy_ioctl(struct tty_struct *tty, struct
+
+ /* The following commands are incompletely implemented!!! */
+ case TIOCGSOFTCAR:
+- ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
++ ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
+ break;
+ case TIOCSSOFTCAR:
+- ret_val = get_user(val, (unsigned long *) arg);
++ ret_val = get_user(val, (unsigned long __user *) argp);
+ if (ret_val)
+ break;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
+ break;
+ case TIOCGSERIAL:
+- ret_val = get_serial_info(info, (struct serial_struct *) arg);
++ ret_val = get_serial_info(info, argp);
+ break;
+ case TIOCSSERIAL:
+- ret_val = set_serial_info(info,
+- (struct serial_struct *) arg);
++ ret_val = set_serial_info(info, argp);
+ break;
+ default:
+ ret_val = -ENOIOCTLCMD;
+@@ -1782,7 +1773,7 @@ cy_close(struct tty_struct * tty, struct
+ tty->driver->flush_buffer(tty);
+ tty_ldisc_flush(tty);
+ info->event = 0;
+- info->tty = 0;
++ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ msleep_interruptible(jiffies_to_msecs(info->close_delay));
+@@ -1983,13 +1974,6 @@ cy_open(struct tty_struct *tty, struct f
+ tty->driver_data = info;
+ info->tty = tty;
+
+- if (!tmp_buf) {
+- tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
+- if (!tmp_buf){
+- return -ENOMEM;
+- }
+- }
+-
+ /*
+ * Start up serial port
+ */
+@@ -2158,7 +2142,7 @@ mvme167_serial_console_setup(int cflag)
+ rcor >> 5, rbpr);
+ } /* serial_console_init */
+
+-static struct tty_operations cy_ops = {
++static const struct tty_operations cy_ops = {
+ .open = cy_open,
+ .close = cy_close,
+ .write = cy_write,
+@@ -2266,7 +2250,7 @@ scrn[1] = '\0';
+ info->card = index;
+ info->line = port_num;
+ info->flags = STD_COM_FLAGS;
+- info->tty = 0;
++ info->tty = NULL;
+ info->xmit_fifo_size = 12;
+ info->cor1 = CyPARITY_NONE|Cy_8_BITS;
+ info->cor2 = CyETC;
+diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
+index 07e0b75..52753e7 100644
+--- a/drivers/char/snsc.c
++++ b/drivers/char/snsc.c
+@@ -34,7 +34,7 @@
+ #define SCDRV_TIMEOUT 1000
+
+ static irqreturn_t
+-scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs)
++scdrv_interrupt(int irq, void *subch_data)
+ {
+ struct subch_data_s *sd = subch_data;
+ unsigned long flags;
+diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
+index d12d4f6..2f56e8c 100644
+--- a/drivers/char/snsc_event.c
++++ b/drivers/char/snsc_event.c
+@@ -36,7 +36,7 @@ DECLARE_TASKLET(sn_sysctl_event, scdrv_e
+ * destination.
+ */
+ static irqreturn_t
+-scdrv_event_interrupt(int irq, void *subch_data, struct pt_regs *regs)
++scdrv_event_interrupt(int irq, void *subch_data)
+ {
+ struct subch_data_s *sd = subch_data;
+ unsigned long flags;
+@@ -220,7 +220,7 @@ scdrv_dispatch_event(char *event, int le
+ " Sending SIGPWR to init...\n");
+
+ /* give a SIGPWR signal to init proc */
+- kill_proc(1, SIGPWR, 0);
++ kill_cad_pid(SIGPWR, 0);
+ } else {
+ /* print to system log */
+ printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
+diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
+index d4e434d..c084149 100644
+--- a/drivers/char/sonypi.c
++++ b/drivers/char/sonypi.c
+@@ -826,7 +826,7 @@ static void sonypi_report_input_event(u8
+ }
+
+ /* Interrupt handler: some event is available */
+-static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sonypi_irq(int irq, void *dev_id)
+ {
+ u8 v1, v2, event = 0;
+ int i, j;
+diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
+index a1d303f..7e1bd95 100644
+--- a/drivers/char/specialix.c
++++ b/drivers/char/specialix.c
+@@ -182,12 +182,6 @@ static int sx_poll = HZ;
+ #define RS_EVENT_WRITE_WAKEUP 0
+
+ static struct tty_driver *specialix_driver;
+-static unsigned char * tmp_buf;
+-
+-static unsigned long baud_table[] = {
+- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+- 9600, 19200, 38400, 57600, 115200, 0,
+-};
+
+ static struct specialix_board sx_board[SX_NBOARD] = {
+ { 0, SX_IOBASE1, 9, },
+@@ -201,7 +195,7 @@ static struct specialix_port sx_port[SX_
+
+ #ifdef SPECIALIX_TIMER
+ static struct timer_list missed_irq_timer;
+-static irqreturn_t sx_interrupt(int irq, void * dev_id, struct pt_regs * regs);
++static irqreturn_t sx_interrupt(int irq, void * dev_id);
+ #endif
+
+
+@@ -898,7 +892,7 @@ static inline void sx_check_modem(struct
+
+
+ /* The main interrupt processing routine */
+-static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sx_interrupt(int irq, void *dev_id)
+ {
+ unsigned char status;
+ unsigned char ack;
+@@ -913,7 +907,7 @@ static irqreturn_t sx_interrupt(int irq,
+ spin_lock_irqsave(&bp->lock, flags);
+
+ dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
+- if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
++ if (!(bp->flags & SX_BOARD_ACTIVE)) {
+ dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit();
+@@ -1087,24 +1081,16 @@ static void sx_change_speed(struct speci
+ port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
+- baud = C_BAUD(tty);
++ baud = tty_get_baud_rate(tty);
+
+- if (baud & CBAUDEX) {
+- baud &= ~CBAUDEX;
+- if (baud < 1 || baud > 2)
+- port->tty->termios->c_cflag &= ~CBAUDEX;
+- else
+- baud += 15;
+- }
+- if (baud == 15) {
++ if (baud == 38400) {
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+- baud ++;
++ baud = 57600;
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+- baud += 2;
++ baud = 115200;
+ }
+
+-
+- if (!baud_table[baud]) {
++ if (!baud) {
+ /* Drop DTR & exit */
+ dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
+ if (!SX_CRTSCTS (tty)) {
+@@ -1134,7 +1120,7 @@ static void sx_change_speed(struct speci
+ "This is an untested option, please be carefull.\n",
+ port_No (port), tmp);
+ else
+- tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
++ tmp = (((SX_OSCFREQ + baud/2) / baud +
+ CD186x_TPC/2) / CD186x_TPC);
+
+ if ((tmp < 0x10) && time_before(again, jiffies)) {
+@@ -1159,11 +1145,9 @@ static void sx_change_speed(struct speci
+ sx_out(bp, CD186x_RBPRL, tmp & 0xff);
+ sx_out(bp, CD186x_TBPRL, tmp & 0xff);
+ spin_unlock_irqrestore(&bp->lock, flags);
+- if (port->custom_divisor) {
++ if (port->custom_divisor)
+ baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
+- baud = ( baud + 5 ) / 10;
+- } else
+- baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */
++ baud = (baud + 5) / 10; /* Estimated CPS */
+
+ /* Two timer ticks seems enough to wakeup something like SLIP driver */
+ tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO;
+@@ -1682,7 +1666,7 @@ static int sx_write(struct tty_struct *
+
+ bp = port_Board(port);
+
+- if (!port->xmit_buf || !tmp_buf) {
++ if (!port->xmit_buf) {
+ func_exit();
+ return 0;
+ }
+@@ -2372,7 +2356,7 @@ static void do_softint(void *private_)
+ func_exit();
+ }
+
+-static struct tty_operations sx_ops = {
++static const struct tty_operations sx_ops = {
+ .open = sx_open,
+ .close = sx_close,
+ .write = sx_write,
+@@ -2406,12 +2390,6 @@ static int sx_init_drivers(void)
+ return 1;
+ }
+
+- if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
+- printk(KERN_ERR "sx: Couldn't get free page.\n");
+- put_tty_driver(specialix_driver);
+- func_exit();
+- return 1;
+- }
+ specialix_driver->owner = THIS_MODULE;
+ specialix_driver->name = "ttyW";
+ specialix_driver->major = SPECIALIX_NORMAL_MAJOR;
+@@ -2425,7 +2403,6 @@ static int sx_init_drivers(void)
+
+ if ((error = tty_register_driver(specialix_driver))) {
+ put_tty_driver(specialix_driver);
+- free_page((unsigned long)tmp_buf);
+ printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
+ error);
+ func_exit();
+@@ -2451,7 +2428,6 @@ static void sx_release_drivers(void)
+ {
+ func_enter();
+
+- free_page((unsigned long)tmp_buf);
+ tty_unregister_driver(specialix_driver);
+ put_tty_driver(specialix_driver);
+ func_exit();
+diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
+index 3beb220..522e88e 100644
+--- a/drivers/char/stallion.c
++++ b/drivers/char/stallion.c
+@@ -1927,13 +1927,12 @@ stl_readdone:
+ * calls off to the approrpriate board interrupt handlers.
+ */
+
+-static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t stl_intr(int irq, void *dev_id)
+ {
+ stlbrd_t *brdp = (stlbrd_t *) dev_id;
+
+ #ifdef DEBUG
+- printk("stl_intr(brdp=%x,irq=%d,regs=%x)\n", (int) brdp, irq,
+- (int) regs);
++ printk("stl_intr(brdp=%x,irq=%d)\n", (int) brdp, irq);
+ #endif
+
+ return IRQ_RETVAL((* brdp->isr)(brdp));
+@@ -2993,7 +2992,7 @@ static int stl_memioctl(struct inode *ip
+ return(rc);
+ }
+
+-static struct tty_operations stl_ops = {
++static const struct tty_operations stl_ops = {
+ .open = stl_open,
+ .close = stl_close,
+ .write = stl_write,
+diff --git a/drivers/char/sx.c b/drivers/char/sx.c
+index e1cd2bc..cc10af0 100644
+--- a/drivers/char/sx.c
++++ b/drivers/char/sx.c
+@@ -203,9 +203,7 @@
+ #define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $"
+ #define RCS_REV "$Revision: 1.33 $"
+
+-
+ #include <linux/module.h>
+-#include <linux/config.h>
+ #include <linux/kdev_t.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -1194,7 +1192,7 @@ static inline void sx_check_modem_signal
+ * Small, elegant, clear.
+ */
+
+-static irqreturn_t sx_interrupt (int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t sx_interrupt (int irq, void *ptr)
+ {
+ struct sx_board *board = ptr;
+ struct sx_port *port;
+@@ -1302,7 +1300,7 @@ static void sx_pollfunc (unsigned long d
+
+ func_enter ();
+
+- sx_interrupt (0, board, NULL);
++ sx_interrupt (0, board);
+
+ init_timer(&board->timer);
+
+@@ -2226,7 +2224,7 @@ static int probe_si (struct sx_board *bo
+ return 1;
+ }
+
+-static struct tty_operations sx_ops = {
++static const struct tty_operations sx_ops = {
+ .break_ctl = sx_break,
+ .open = sx_open,
+ .close = gs_close,
+@@ -2604,7 +2602,7 @@ static void __exit sx_exit (void)
+ }
+ }
+ if (misc_deregister(&sx_fw_device) < 0) {
+- printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n");
++ printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+ }
+ sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
+ if (sx_initialized)
+diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
+index 78b1b1a..06784ad 100644
+--- a/drivers/char/synclink.c
++++ b/drivers/char/synclink.c
+@@ -63,7 +63,6 @@
+ #define MAX_PCI_DEVICES 10
+ #define MAX_TOTAL_DEVICES 20
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+@@ -87,7 +86,6 @@
+
+ #include <linux/vmalloc.h>
+ #include <linux/init.h>
+-#include <asm/serial.h>
+
+ #include <linux/delay.h>
+ #include <linux/ioctl.h>
+@@ -135,8 +133,8 @@ static MGSL_PARAMS default_params = {
+ };
+
+ #define SHARED_MEM_ADDRESS_SIZE 0x40000
+-#define BUFFERLISTSIZE (PAGE_SIZE)
+-#define DMABUFFERSIZE (PAGE_SIZE)
++#define BUFFERLISTSIZE 4096
++#define DMABUFFERSIZE 4096
+ #define MAXRXFRAMES 7
+
+ typedef struct _DMABUFFERENTRY
+@@ -1700,11 +1698,10 @@ static void mgsl_isr_transmit_dma( struc
+ *
+ * irq interrupt number that caused interrupt
+ * dev_id device ID supplied during interrupt registration
+- * regs interrupted processor context
+ *
+ * Return Value: None
+ */
+-static irqreturn_t mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t mgsl_interrupt(int irq, void *dev_id)
+ {
+ struct mgsl_struct * info;
+ u16 UscVector;
+@@ -4360,7 +4357,7 @@ static struct mgsl_struct* mgsl_allocate
+
+ } /* end of mgsl_allocate_device()*/
+
+-static struct tty_operations mgsl_ops = {
++static const struct tty_operations mgsl_ops = {
+ .open = mgsl_open,
+ .close = mgsl_close,
+ .write = mgsl_write,
+diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
+index 2f07b08..d4334c7 100644
+--- a/drivers/char/synclink_gt.c
++++ b/drivers/char/synclink_gt.c
+@@ -1,5 +1,5 @@
+ /*
+- * $Id: synclink_gt.c,v 4.25 2006/02/06 21:20:33 paulkf Exp $
++ * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $
+ *
+ * Device driver for Microgate SyncLink GT serial adapters.
+ *
+@@ -91,12 +91,12 @@
+ * module identification
+ */
+ static char *driver_name = "SyncLink GT";
+-static char *driver_version = "$Revision: 4.25 $";
++static char *driver_version = "$Revision: 4.36 $";
+ static char *tty_driver_name = "synclink_gt";
+ static char *tty_dev_prefix = "ttySLG";
+ MODULE_LICENSE("GPL");
+ #define MGSL_MAGIC 0x5401
+-#define MAX_DEVICES 12
++#define MAX_DEVICES 32
+
+ static struct pci_device_id pci_table[] = {
+ {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+@@ -461,7 +461,7 @@ static int adapter_test(struct slgt_inf
+ static void reset_adapter(struct slgt_info *info);
+ static void reset_port(struct slgt_info *info);
+ static void async_mode(struct slgt_info *info);
+-static void hdlc_mode(struct slgt_info *info);
++static void sync_mode(struct slgt_info *info);
+
+ static void rx_stop(struct slgt_info *info);
+ static void rx_start(struct slgt_info *info);
+@@ -491,7 +491,7 @@ static void isr_serial(struct slgt_info
+ static void isr_rdma(struct slgt_info *info);
+ static void isr_txeom(struct slgt_info *info, unsigned short status);
+ static void isr_tdma(struct slgt_info *info);
+-static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t slgt_interrupt(int irq, void *dev_id);
+
+ static int alloc_dma_bufs(struct slgt_info *info);
+ static void free_dma_bufs(struct slgt_info *info);
+@@ -881,7 +881,9 @@ static int write(struct tty_struct *tty,
+ if (!count)
+ goto cleanup;
+
+- if (info->params.mode == MGSL_MODE_RAW) {
++ if (info->params.mode == MGSL_MODE_RAW ||
++ info->params.mode == MGSL_MODE_MONOSYNC ||
++ info->params.mode == MGSL_MODE_BISYNC) {
+ unsigned int bufs_needed = (count/DMABUFSIZE);
+ unsigned int bufs_free = free_tbuf_count(info);
+ if (count % DMABUFSIZE)
+@@ -1897,6 +1899,8 @@ static void bh_handler(void* context)
+ while(rx_get_frame(info));
+ break;
+ case MGSL_MODE_RAW:
++ case MGSL_MODE_MONOSYNC:
++ case MGSL_MODE_BISYNC:
+ while(rx_get_buf(info));
+ break;
+ }
+@@ -2213,9 +2217,8 @@ static void isr_gpio(struct slgt_info *i
+ *
+ * irq interrupt number
+ * dev_id device ID supplied during interrupt registration
+- * regs interrupted processor context
+ */
+-static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t slgt_interrupt(int irq, void *dev_id)
+ {
+ struct slgt_info *info;
+ unsigned int gsr;
+@@ -2362,10 +2365,9 @@ static void program_hw(struct slgt_info
+ rx_stop(info);
+ tx_stop(info);
+
+- if (info->params.mode == MGSL_MODE_HDLC ||
+- info->params.mode == MGSL_MODE_RAW ||
++ if (info->params.mode != MGSL_MODE_ASYNC ||
+ info->netcount)
+- hdlc_mode(info);
++ sync_mode(info);
+ else
+ async_mode(info);
+
+@@ -2564,6 +2566,10 @@ static int rx_enable(struct slgt_info *i
+ if (enable) {
+ if (!info->rx_enabled)
+ rx_start(info);
++ else if (enable == 2) {
++ /* force hunt mode (write 1 to RCR[3]) */
++ wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3);
++ }
+ } else {
+ if (info->rx_enabled)
+ rx_stop(info);
+@@ -3434,7 +3440,7 @@ static void __devexit remove_one(struct
+ {
+ }
+
+-static struct tty_operations ops = {
++static const struct tty_operations ops = {
+ .open = open,
+ .close = close,
+ .write = write,
+@@ -3748,7 +3754,7 @@ static void tx_start(struct slgt_info *i
+ {
+ if (!info->tx_enabled) {
+ wr_reg16(info, TCR,
+- (unsigned short)(rd_reg16(info, TCR) | BIT1));
++ (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2));
+ info->tx_enabled = TRUE;
+ }
+
+@@ -3775,13 +3781,18 @@ static void tx_start(struct slgt_info *i
+ tdma_reset(info);
+ /* set 1st descriptor address */
+ wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+- if (info->params.mode == MGSL_MODE_RAW)
++ switch(info->params.mode) {
++ case MGSL_MODE_RAW:
++ case MGSL_MODE_MONOSYNC:
++ case MGSL_MODE_BISYNC:
+ wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
+- else
++ break;
++ default:
+ wr_reg32(info, TDCSR, BIT0); /* DMA enable */
++ }
+ }
+
+- if (info->params.mode != MGSL_MODE_RAW) {
++ if (info->params.mode == MGSL_MODE_HDLC) {
+ info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
+ add_timer(&info->tx_timer);
+ }
+@@ -3814,7 +3825,6 @@ static void tx_stop(struct slgt_info *in
+ /* reset and disable transmitter */
+ val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */
+ wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
+- wr_reg16(info, TCR, val); /* clear reset */
+
+ slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
+
+@@ -3982,7 +3992,7 @@ static void async_mode(struct slgt_info
+ enable_loopback(info);
+ }
+
+-static void hdlc_mode(struct slgt_info *info)
++static void sync_mode(struct slgt_info *info)
+ {
+ unsigned short val;
+
+@@ -3992,7 +4002,7 @@ static void hdlc_mode(struct slgt_info *
+
+ /* TCR (tx control)
+ *
+- * 15..13 mode, 000=HDLC 001=raw sync
++ * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
+ * 12..10 encoding
+ * 09 CRC enable
+ * 08 CRC32
+@@ -4006,8 +4016,11 @@ static void hdlc_mode(struct slgt_info *
+ */
+ val = 0;
+
+- if (info->params.mode == MGSL_MODE_RAW)
+- val |= BIT13;
++ switch(info->params.mode) {
++ case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
++ case MGSL_MODE_BISYNC: val |= BIT15; break;
++ case MGSL_MODE_RAW: val |= BIT13; break;
++ }
+ if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+ val |= BIT7;
+
+@@ -4058,7 +4071,7 @@ static void hdlc_mode(struct slgt_info *
+
+ /* RCR (rx control)
+ *
+- * 15..13 mode, 000=HDLC 001=raw sync
++ * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
+ * 12..10 encoding
+ * 09 CRC enable
+ * 08 CRC32
+@@ -4069,8 +4082,11 @@ static void hdlc_mode(struct slgt_info *
+ */
+ val = 0;
+
+- if (info->params.mode == MGSL_MODE_RAW)
+- val |= BIT13;
++ switch(info->params.mode) {
++ case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
++ case MGSL_MODE_BISYNC: val |= BIT15; break;
++ case MGSL_MODE_RAW: val |= BIT13; break;
++ }
+
+ switch(info->params.encoding)
+ {
+@@ -4309,10 +4325,15 @@ static void free_rbufs(struct slgt_info
+ while(!done) {
+ /* reset current buffer for reuse */
+ info->rbufs[i].status = 0;
+- if (info->params.mode == MGSL_MODE_RAW)
++ switch(info->params.mode) {
++ case MGSL_MODE_RAW:
++ case MGSL_MODE_MONOSYNC:
++ case MGSL_MODE_BISYNC:
+ set_desc_count(info->rbufs[i], info->raw_rx_size);
+- else
++ break;
++ default:
+ set_desc_count(info->rbufs[i], DMABUFSIZE);
++ }
+
+ if (i == last)
+ done = 1;
+@@ -4477,13 +4498,24 @@ cleanup:
+ static int rx_get_buf(struct slgt_info *info)
+ {
+ unsigned int i = info->rbuf_current;
++ unsigned int count;
+
+ if (!desc_complete(info->rbufs[i]))
+ return 0;
+- DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx");
+- DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i])));
+- ldisc_receive_buf(info->tty, info->rbufs[i].buf,
+- info->flag_buf, desc_count(info->rbufs[i]));
++ count = desc_count(info->rbufs[i]);
++ switch(info->params.mode) {
++ case MGSL_MODE_MONOSYNC:
++ case MGSL_MODE_BISYNC:
++ /* ignore residue in byte synchronous modes */
++ if (desc_residue(info->rbufs[i]))
++ count--;
++ break;
++ }
++ DBGDATA(info, info->rbufs[i].buf, count, "rx");
++ DBGINFO(("rx_get_buf size=%d\n", count));
++ if (count)
++ ldisc_receive_buf(info->tty, info->rbufs[i].buf,
++ info->flag_buf, count);
+ free_rbufs(info, i, i);
+ return 1;
+ }
+@@ -4549,8 +4581,13 @@ static void tx_load(struct slgt_info *in
+ size -= count;
+ buf += count;
+
+- if (!size && info->params.mode != MGSL_MODE_RAW)
+- set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */
++ /*
++ * set EOF bit for last buffer of HDLC frame or
++ * for every buffer in raw mode
++ */
++ if ((!size && info->params.mode == MGSL_MODE_HDLC) ||
++ info->params.mode == MGSL_MODE_RAW)
++ set_desc_eof(*d, 1);
+ else
+ set_desc_eof(*d, 0);
+
+diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
+index 66f3754..3e932b6 100644
+--- a/drivers/char/synclinkmp.c
++++ b/drivers/char/synclinkmp.c
+@@ -2596,8 +2596,7 @@ void isr_io_pin( SLMP_INFO *info, u16 st
+ * dev_id device ID supplied during interrupt registration
+ * regs interrupted processor context
+ */
+-static irqreturn_t synclinkmp_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t synclinkmp_interrupt(int irq, void *dev_id)
+ {
+ SLMP_INFO * info;
+ unsigned char status, status0, status1=0;
+@@ -3929,7 +3928,7 @@ void device_init(int adapter_num, struct
+ }
+ }
+
+-static struct tty_operations ops = {
++static const struct tty_operations ops = {
+ .open = open,
+ .close = close,
+ .write = write,
+diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
+index ee3ca8f..5f49280 100644
+--- a/drivers/char/sysrq.c
++++ b/drivers/char/sysrq.c
+@@ -35,14 +35,15 @@
+ #include <linux/vt_kern.h>
+ #include <linux/workqueue.h>
+ #include <linux/kexec.h>
++#include <linux/irq.h>
+
+ #include <asm/ptrace.h>
++#include <asm/irq_regs.h>
+
+ /* Whether we react on sysrq keys or just ignore them */
+ int sysrq_enabled = 1;
+
+-static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_loglevel(int key, struct tty_struct *tty)
+ {
+ int i;
+ i = key - '0';
+@@ -58,8 +59,7 @@ static struct sysrq_key_op sysrq_logleve
+ };
+
+ #ifdef CONFIG_VT
+-static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_SAK(int key, struct tty_struct *tty)
+ {
+ if (tty)
+ do_SAK(tty);
+@@ -76,8 +76,7 @@ static struct sysrq_key_op sysrq_SAK_op
+ #endif
+
+ #ifdef CONFIG_VT
+-static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_unraw(int key, struct tty_struct *tty)
+ {
+ struct kbd_struct *kbd = &kbd_table[fg_console];
+
+@@ -95,10 +94,9 @@ static struct sysrq_key_op sysrq_unraw_o
+ #endif /* CONFIG_VT */
+
+ #ifdef CONFIG_KEXEC
+-static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_crashdump(int key, struct tty_struct *tty)
+ {
+- crash_kexec(pt_regs);
++ crash_kexec(get_irq_regs());
+ }
+ static struct sysrq_key_op sysrq_crashdump_op = {
+ .handler = sysrq_handle_crashdump,
+@@ -110,9 +108,9 @@ static struct sysrq_key_op sysrq_crashdu
+ #define sysrq_crashdump_op (*(struct sysrq_key_op *)0)
+ #endif
+
+-static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_reboot(int key, struct tty_struct *tty)
+ {
++ lockdep_off();
+ local_irq_enable();
+ emergency_restart();
+ }
+@@ -123,8 +121,7 @@ static struct sysrq_key_op sysrq_reboot_
+ .enable_mask = SYSRQ_ENABLE_BOOT,
+ };
+
+-static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_sync(int key, struct tty_struct *tty)
+ {
+ emergency_sync();
+ }
+@@ -135,8 +132,7 @@ static struct sysrq_key_op sysrq_sync_op
+ .enable_mask = SYSRQ_ENABLE_SYNC,
+ };
+
+-static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_mountro(int key, struct tty_struct *tty)
+ {
+ emergency_remount();
+ }
+@@ -148,8 +144,7 @@ static struct sysrq_key_op sysrq_mountro
+ };
+
+ #ifdef CONFIG_LOCKDEP
+-static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_showlocks(int key, struct tty_struct *tty)
+ {
+ debug_show_all_locks();
+ }
+@@ -163,11 +158,11 @@ static struct sysrq_key_op sysrq_showloc
+ #define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
+ #endif
+
+-static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_showregs(int key, struct tty_struct *tty)
+ {
+- if (pt_regs)
+- show_regs(pt_regs);
++ struct pt_regs *regs = get_irq_regs();
++ if (regs)
++ show_regs(regs);
+ }
+ static struct sysrq_key_op sysrq_showregs_op = {
+ .handler = sysrq_handle_showregs,
+@@ -176,8 +171,7 @@ static struct sysrq_key_op sysrq_showreg
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+ };
+
+-static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_showstate(int key, struct tty_struct *tty)
+ {
+ show_state();
+ }
+@@ -188,8 +182,7 @@ static struct sysrq_key_op sysrq_showsta
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+ };
+
+-static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_showmem(int key, struct tty_struct *tty)
+ {
+ show_mem();
+ }
+@@ -208,14 +201,13 @@ static void send_sig_all(int sig)
+ struct task_struct *p;
+
+ for_each_process(p) {
+- if (p->mm && p->pid != 1)
++ if (p->mm && !is_init(p))
+ /* Not swapper, init nor kernel thread */
+ force_sig(sig, p);
+ }
+ }
+
+-static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_term(int key, struct tty_struct *tty)
+ {
+ send_sig_all(SIGTERM);
+ console_loglevel = 8;
+@@ -235,8 +227,7 @@ static void moom_callback(void *ignored)
+
+ static DECLARE_WORK(moom_work, moom_callback, NULL);
+
+-static void sysrq_handle_moom(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_moom(int key, struct tty_struct *tty)
+ {
+ schedule_work(&moom_work);
+ }
+@@ -246,8 +237,7 @@ static struct sysrq_key_op sysrq_moom_op
+ .action_msg = "Manual OOM execution",
+ };
+
+-static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_kill(int key, struct tty_struct *tty)
+ {
+ send_sig_all(SIGKILL);
+ console_loglevel = 8;
+@@ -259,8 +249,7 @@ static struct sysrq_key_op sysrq_kill_op
+ .enable_mask = SYSRQ_ENABLE_SIGNAL,
+ };
+
+-static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void sysrq_handle_unrt(int key, struct tty_struct *tty)
+ {
+ normalize_rt_tasks();
+ }
+@@ -360,8 +349,7 @@ static void __sysrq_put_key_op(int key,
+ * This is the non-locking version of handle_sysrq. It must/can only be called
+ * by sysrq key handlers, as they are inside of the lock
+ */
+-void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
+- int check_mask)
++void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
+ {
+ struct sysrq_key_op *op_p;
+ int orig_log_level;
+@@ -383,7 +371,7 @@ void __handle_sysrq(int key, struct pt_r
+ (sysrq_enabled & op_p->enable_mask)) {
+ printk("%s\n", op_p->action_msg);
+ console_loglevel = orig_log_level;
+- op_p->handler(key, pt_regs, tty);
++ op_p->handler(key, tty);
+ } else {
+ printk("This sysrq operation is disabled.\n");
+ }
+@@ -412,11 +400,11 @@ void __handle_sysrq(int key, struct pt_r
+ * This function is called by the keyboard handler when SysRq is pressed
+ * and any other keycode arrives.
+ */
+-void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
++void handle_sysrq(int key, struct tty_struct *tty)
+ {
+ if (!sysrq_enabled)
+ return;
+- __handle_sysrq(key, pt_regs, tty, 1);
++ __handle_sysrq(key, tty, 1);
+ }
+ EXPORT_SYMBOL(handle_sysrq);
+
+diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
+index d30dc09..9df0ca1 100644
+--- a/drivers/char/tipar.c
++++ b/drivers/char/tipar.c
+@@ -224,14 +224,16 @@ probe_ti_parallel(int minor)
+ {
+ int i;
+ int seq[] = { 0x00, 0x20, 0x10, 0x30 };
++ int data;
+
+ for (i = 3; i >= 0; i--) {
+ outbyte(3, minor);
+ outbyte(i, minor);
+ udelay(delay);
++ data = inbyte(minor) & 0x30;
+ pr_debug("tipar: Probing -> %i: 0x%02x 0x%02x\n", i,
+- data & 0x30, seq[i]);
+- if ((inbyte(minor) & 0x30) != seq[i]) {
++ data, seq[i]);
++ if (data != seq[i]) {
+ outbyte(3, minor);
+ return -1;
+ }
+diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
+index d2c5ba4..2444a0e 100644
+--- a/drivers/char/tlclk.c
++++ b/drivers/char/tlclk.c
+@@ -193,7 +193,7 @@ static DEFINE_SPINLOCK(event_lock);
+
+ static int tlclk_major = TLCLK_MAJOR;
+
+-static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t tlclk_interrupt(int irq, void *dev_id);
+
+ static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+@@ -856,7 +856,7 @@ static void switchover_timeout(unsigned
+ wake_up(&wq);
+ }
+
+-static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
+ {
+ unsigned long flags;
+
+diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
+index a082a2e..6ad2d3b 100644
+--- a/drivers/char/tpm/tpm.c
++++ b/drivers/char/tpm/tpm.c
+@@ -1153,7 +1153,14 @@ struct tpm_chip *tpm_register_hardware(s
+
+ spin_unlock(&driver_lock);
+
+- sysfs_create_group(&dev->kobj, chip->vendor.attr_group);
++ if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
++ list_del(&chip->list);
++ put_device(dev);
++ clear_bit(chip->dev_num, dev_mask);
++ kfree(chip);
++ kfree(devname);
++ return NULL;
++ }
+
+ chip->bios_dir = tpm_bios_log_setup(devname);
+
+diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
+index ad8ffe4..1ab0896 100644
+--- a/drivers/char/tpm/tpm_atmel.c
++++ b/drivers/char/tpm/tpm_atmel.c
+@@ -184,7 +184,9 @@ static int __init init_atmel(void)
+ unsigned long base;
+ struct tpm_chip *chip;
+
+- driver_register(&atml_drv);
++ rc = driver_register(&atml_drv);
++ if (rc)
++ return rc;
+
+ if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) {
+ rc = -ENODEV;
+@@ -195,10 +197,8 @@ static int __init init_atmel(void)
+ (atmel_request_region
+ (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
+
+-
+- if (IS_ERR
+- (pdev =
+- platform_device_register_simple("tpm_atmel", -1, NULL, 0))) {
++ pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0);
++ if (IS_ERR(pdev)) {
+ rc = PTR_ERR(pdev);
+ goto err_rel_reg;
+ }
+diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
+index 2e68eeb..aefd683 100644
+--- a/drivers/char/tpm/tpm_atmel.h
++++ b/drivers/char/tpm/tpm_atmel.h
+@@ -37,7 +37,7 @@ static void __iomem * atmel_get_base_add
+ {
+ struct device_node *dn;
+ unsigned long address, size;
+- unsigned int *reg;
++ const unsigned int *reg;
+ int reglen;
+ int naddrc;
+ int nsizec;
+@@ -52,7 +52,7 @@ static void __iomem * atmel_get_base_add
+ return NULL;
+ }
+
+- reg = (unsigned int *) get_property(dn, "reg", ®len);
++ reg = get_property(dn, "reg", ®len);
+ naddrc = prom_n_addr_cells(dn);
+ nsizec = prom_n_size_cells(dn);
+
+diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
+index 26287aa..608f730 100644
+--- a/drivers/char/tpm/tpm_nsc.c
++++ b/drivers/char/tpm/tpm_nsc.c
+@@ -284,7 +284,7 @@ static struct device_driver nsc_drv = {
+ static int __init init_nsc(void)
+ {
+ int rc = 0;
+- int lo, hi;
++ int lo, hi, err;
+ int nscAddrBase = TPM_ADDR;
+ struct tpm_chip *chip;
+ unsigned long base;
+@@ -297,7 +297,9 @@ static int __init init_nsc(void)
+ return -ENODEV;
+ }
+
+- driver_register(&nsc_drv);
++ err = driver_register(&nsc_drv);
++ if (err)
++ return err;
+
+ hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+ lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
+index ee7ac6f..483f3f6 100644
+--- a/drivers/char/tpm/tpm_tis.c
++++ b/drivers/char/tpm/tpm_tis.c
+@@ -377,7 +377,7 @@ static struct tpm_vendor_specific tpm_ti
+ .fops = &tis_ops,},
+ };
+
+-static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tis_int_probe(int irq, void *dev_id)
+ {
+ struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+ u32 interrupt;
+@@ -397,7 +397,7 @@ static irqreturn_t tis_int_probe(int irq
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tis_int_handler(int irq, void *dev_id)
+ {
+ struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+ u32 interrupt;
+diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
+index bb0d919..e90ea39 100644
+--- a/drivers/char/tty_io.c
++++ b/drivers/char/tty_io.c
+@@ -129,6 +129,7 @@ LIST_HEAD(tty_drivers); /* linked list
+ /* Semaphore to protect creating and releasing a tty. This is shared with
+ vt.c for deeply disgusting hack reasons */
+ DEFINE_MUTEX(tty_mutex);
++EXPORT_SYMBOL(tty_mutex);
+
+ #ifdef CONFIG_UNIX98_PTYS
+ extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
+@@ -160,17 +161,11 @@ static void release_mem(struct tty_struc
+ * been initialized in any way but has been zeroed
+ *
+ * Locking: none
+- * FIXME: use kzalloc
+ */
+
+ static struct tty_struct *alloc_tty_struct(void)
+ {
+- struct tty_struct *tty;
+-
+- tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
+- if (tty)
+- memset(tty, 0, sizeof(struct tty_struct));
+- return tty;
++ return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
+ }
+
+ static void tty_buffer_free_all(struct tty_struct *);
+@@ -483,10 +478,9 @@ int tty_insert_flip_string(struct tty_st
+ tb->used += space;
+ copied += space;
+ chars += space;
+- }
+- /* There is a small chance that we need to split the data over
+- several buffers. If this is the case we must loop */
+- while (unlikely(size > copied));
++ /* There is a small chance that we need to split the data over
++ several buffers. If this is the case we must loop */
++ } while (unlikely(size > copied));
+ return copied;
+ }
+ EXPORT_SYMBOL(tty_insert_flip_string);
+@@ -521,10 +515,9 @@ int tty_insert_flip_string_flags(struct
+ copied += space;
+ chars += space;
+ flags += space;
+- }
+- /* There is a small chance that we need to split the data over
+- several buffers. If this is the case we must loop */
+- while (unlikely(size > copied));
++ /* There is a small chance that we need to split the data over
++ several buffers. If this is the case we must loop */
++ } while (unlikely(size > copied));
+ return copied;
+ }
+ EXPORT_SYMBOL(tty_insert_flip_string_flags);
+@@ -626,9 +619,9 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_strin
+
+ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+ {
+- down(&tty->termios_sem);
++ mutex_lock(&tty->termios_mutex);
+ tty->termios->c_line = num;
+- up(&tty->termios_sem);
++ mutex_unlock(&tty->termios_mutex);
+ }
+
+ /*
+@@ -1346,9 +1339,9 @@ static void do_tty_hangup(void *data)
+ */
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ {
+- down(&tty->termios_sem);
++ mutex_lock(&tty->termios_mutex);
+ *tty->termios = tty->driver->init_termios;
+- up(&tty->termios_sem);
++ mutex_unlock(&tty->termios_mutex);
+ }
+
+ /* Defer ldisc switch */
+@@ -2072,8 +2065,9 @@ fail_no_mem:
+
+ /* call the tty release_mem routine to clean out this slot */
+ release_mem_out:
+- printk(KERN_INFO "init_dev: ldisc open failed, "
+- "clearing slot %d\n", idx);
++ if (printk_ratelimit())
++ printk(KERN_INFO "init_dev: ldisc open failed, "
++ "clearing slot %d\n", idx);
+ release_mem(tty, idx);
+ goto end_init;
+ }
+@@ -2726,6 +2720,8 @@ static int tty_fasync(int fd, struct fil
+ * Locking:
+ * Called functions take tty_ldisc_lock
+ * current->signal->tty check is safe without locks
++ *
++ * FIXME: may race normal receive processing
+ */
+
+ static int tiocsti(struct tty_struct *tty, char __user *p)
+@@ -2748,18 +2744,21 @@ static int tiocsti(struct tty_struct *tt
+ * @tty; tty
+ * @arg: user buffer for result
+ *
+- * Copies the kernel idea of the window size into the user buffer. No
+- * locking is done.
++ * Copies the kernel idea of the window size into the user buffer.
+ *
+- * FIXME: Returning random values racing a window size set is wrong
+- * should lock here against that
++ * Locking: tty->termios_sem is taken to ensure the winsize data
++ * is consistent.
+ */
+
+ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
+ {
+- if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
+- return -EFAULT;
+- return 0;
++ int err;
++
++ mutex_lock(&tty->termios_mutex);
++ err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
++ mutex_unlock(&tty->termios_mutex);
++
++ return err ? -EFAULT: 0;
+ }
+
+ /**
+@@ -2772,12 +2771,11 @@ static int tiocgwinsz(struct tty_struct
+ * actually has driver level meaning and triggers a VC resize.
+ *
+ * Locking:
+- * The console_sem is used to ensure we do not try and resize
+- * the console twice at once.
+- * FIXME: Two racing size sets may leave the console and kernel
+- * parameters disagreeing. Is this exploitable ?
+- * FIXME: Random values racing a window size get is wrong
+- * should lock here against that
++ * Called function use the console_sem is used to ensure we do
++ * not try and resize the console twice at once.
++ * The tty->termios_sem is used to ensure we don't double
++ * resize and get confused. Lock order - tty->termios.sem before
++ * console sem
+ */
+
+ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
+@@ -2787,17 +2785,18 @@ static int tiocswinsz(struct tty_struct
+
+ if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+ return -EFAULT;
++
++ mutex_lock(&tty->termios_mutex);
+ if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
+- return 0;
++ goto done;
++
+ #ifdef CONFIG_VT
+ if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
+- int rc;
+-
+- acquire_console_sem();
+- rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row);
+- release_console_sem();
+- if (rc)
+- return -ENXIO;
++ if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col,
++ tmp_ws.ws_row)) {
++ mutex_unlock(&tty->termios_mutex);
++ return -ENXIO;
++ }
+ }
+ #endif
+ if (tty->pgrp > 0)
+@@ -2806,6 +2805,8 @@ static int tiocswinsz(struct tty_struct
+ kill_pg(real_tty->pgrp, SIGWINCH, 1);
+ tty->winsize = tmp_ws;
+ real_tty->winsize = tmp_ws;
++done:
++ mutex_unlock(&tty->termios_mutex);
+ return 0;
+ }
+
+@@ -2880,9 +2881,7 @@ static int fionbio(struct file *file, in
+ * Locking:
+ * Takes tasklist lock internally to walk sessions
+ * Takes task_lock() when updating signal->tty
+- *
+- * FIXME: tty_mutex is needed to protect signal->tty references.
+- * FIXME: why task_lock on the signal->tty reference ??
++ * Takes tty_mutex() to protect tty instance
+ *
+ */
+
+@@ -2917,9 +2916,11 @@ static int tiocsctty(struct tty_struct *
+ } else
+ return -EPERM;
+ }
++ mutex_lock(&tty_mutex);
+ task_lock(current);
+ current->signal->tty = tty;
+ task_unlock(current);
++ mutex_unlock(&tty_mutex);
+ current->signal->tty_old_pgrp = 0;
+ tty->session = current->signal->session;
+ tty->pgrp = process_group(current);
+@@ -2959,8 +2960,6 @@ static int tiocgpgrp(struct tty_struct *
+ * permitted where the tty session is our session.
+ *
+ * Locking: None
+- *
+- * FIXME: current->signal->tty referencing is unsafe.
+ */
+
+ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+@@ -3039,19 +3038,20 @@ static int tiocsetd(struct tty_struct *t
+ * timed break functionality.
+ *
+ * Locking:
+- * None
++ * atomic_write_lock serializes
+ *
+- * FIXME:
+- * What if two overlap
+ */
+
+ static int send_break(struct tty_struct *tty, unsigned int duration)
+ {
++ if (mutex_lock_interruptible(&tty->atomic_write_lock))
++ return -EINTR;
+ tty->driver->break_ctl(tty, -1);
+ if (!signal_pending(current)) {
+ msleep_interruptible(duration);
+ }
+ tty->driver->break_ctl(tty, 0);
++ mutex_unlock(&tty->atomic_write_lock);
+ if (signal_pending(current))
+ return -EINTR;
+ return 0;
+@@ -3144,6 +3144,8 @@ int tty_ioctl(struct inode * inode, stru
+ if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+ return -EINVAL;
+
++ /* CHECKME: is this safe as one end closes ? */
++
+ real_tty = tty;
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver->subtype == PTY_TYPE_MASTER)
+@@ -3580,7 +3582,7 @@ static void initialize_tty_struct(struct
+ tty_buffer_init(tty);
+ INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
+ init_MUTEX(&tty->buf.pty_sem);
+- init_MUTEX(&tty->termios_sem);
++ mutex_init(&tty->termios_mutex);
+ init_waitqueue_head(&tty->write_wait);
+ init_waitqueue_head(&tty->read_wait);
+ INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
+@@ -3678,7 +3680,8 @@ void put_tty_driver(struct tty_driver *d
+ kfree(driver);
+ }
+
+-void tty_set_operations(struct tty_driver *driver, struct tty_operations *op)
++void tty_set_operations(struct tty_driver *driver,
++ const struct tty_operations *op)
+ {
+ driver->open = op->open;
+ driver->close = op->close;
+diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
+index 4ad47d3..3b6fa7b 100644
+--- a/drivers/char/tty_ioctl.c
++++ b/drivers/char/tty_ioctl.c
+@@ -20,6 +20,7 @@
+ #include <linux/mm.h>
+ #include <linux/module.h>
+ #include <linux/bitops.h>
++#include <linux/mutex.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -131,7 +132,7 @@ static void change_termios(struct tty_st
+
+ /* FIXME: we need to decide on some locking/ordering semantics
+ for the set_termios notification eventually */
+- down(&tty->termios_sem);
++ mutex_lock(&tty->termios_mutex);
+
+ *tty->termios = *new_termios;
+ unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+@@ -176,7 +177,7 @@ static void change_termios(struct tty_st
+ (ld->set_termios)(tty, &old_termios);
+ tty_ldisc_deref(ld);
+ }
+- up(&tty->termios_sem);
++ mutex_unlock(&tty->termios_mutex);
+ }
+
+ /**
+@@ -284,13 +285,13 @@ static int get_sgttyb(struct tty_struct
+ {
+ struct sgttyb tmp;
+
+- down(&tty->termios_sem);
++ mutex_lock(&tty->termios_mutex);
+ tmp.sg_ispeed = 0;
+ tmp.sg_ospeed = 0;
+ tmp.sg_erase = tty->termios->c_cc[VERASE];
+ tmp.sg_kill = tty->termios->c_cc[VKILL];
+ tmp.sg_flags = get_sgflags(tty);
+- up(&tty->termios_sem);
++ mutex_unlock(&tty->termios_mutex);
+
+ return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+ }
+@@ -345,12 +346,12 @@ static int set_sgttyb(struct tty_struct
+ if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
+ return -EFAULT;
+
+- down(&tty->termios_sem);
++ mutex_lock(&tty->termios_mutex);
+ termios = *tty->termios;
+ termios.c_cc[VERASE] = tmp.sg_erase;
+ termios.c_cc[VKILL] = tmp.sg_kill;
+ set_sgflags(&termios, tmp.sg_flags);
+- up(&tty->termios_sem);
++ mutex_unlock(&tty->termios_mutex);
+ change_termios(tty, &termios);
+ return 0;
+ }
+@@ -422,24 +423,28 @@ static int set_ltchars(struct tty_struct
+ *
+ * Send a high priority character to the tty even if stopped
+ *
+- * Locking: none
+- *
+- * FIXME: overlapping calls with start/stop tty lose state of tty
++ * Locking: none for xchar method, write ordering for write method.
+ */
+
+-static void send_prio_char(struct tty_struct *tty, char ch)
++static int send_prio_char(struct tty_struct *tty, char ch)
+ {
+ int was_stopped = tty->stopped;
+
+ if (tty->driver->send_xchar) {
+ tty->driver->send_xchar(tty, ch);
+- return;
++ return 0;
+ }
++
++ if (mutex_lock_interruptible(&tty->atomic_write_lock))
++ return -ERESTARTSYS;
++
+ if (was_stopped)
+ start_tty(tty);
+ tty->driver->write(tty, &ch, 1);
+ if (was_stopped)
+ stop_tty(tty);
++ mutex_unlock(&tty->atomic_write_lock);
++ return 0;
+ }
+
+ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
+@@ -513,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty,
+ break;
+ case TCIOFF:
+ if (STOP_CHAR(tty) != __DISABLED_CHAR)
+- send_prio_char(tty, STOP_CHAR(tty));
++ return send_prio_char(tty, STOP_CHAR(tty));
+ break;
+ case TCION:
+ if (START_CHAR(tty) != __DISABLED_CHAR)
+- send_prio_char(tty, START_CHAR(tty));
++ return send_prio_char(tty, START_CHAR(tty));
+ break;
+ default:
+ return -EINVAL;
+@@ -592,11 +597,11 @@ int n_tty_ioctl(struct tty_struct * tty,
+ case TIOCSSOFTCAR:
+ if (get_user(arg, (unsigned int __user *) arg))
+ return -EFAULT;
+- down(&tty->termios_sem);
++ mutex_lock(&tty->termios_mutex);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+- up(&tty->termios_sem);
++ mutex_unlock(&tty->termios_mutex);
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
+index a9247b5..bd7a98c 100644
+--- a/drivers/char/vc_screen.c
++++ b/drivers/char/vc_screen.c
+@@ -474,14 +474,15 @@ static const struct file_operations vcs_
+
+ static struct class *vc_class;
+
+-void vcs_make_devfs(struct tty_struct *tty)
++void vcs_make_sysfs(struct tty_struct *tty)
+ {
+ class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
+ NULL, "vcs%u", tty->index + 1);
+ class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
+ NULL, "vcsa%u", tty->index + 1);
+ }
+-void vcs_remove_devfs(struct tty_struct *tty)
++
++void vcs_remove_sysfs(struct tty_struct *tty)
+ {
+ class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
+ class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
+diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
+index 766f786..6d2e314 100644
+--- a/drivers/char/viocons.c
++++ b/drivers/char/viocons.c
+@@ -43,7 +43,6 @@
+ #include <linux/sysrq.h>
+
+ #include <asm/iseries/vio.h>
+-
+ #include <asm/iseries/hv_lp_event.h>
+ #include <asm/iseries/hv_call_event.h>
+ #include <asm/iseries/hv_lp_config.h>
+@@ -67,35 +66,6 @@ static int vio_sysrq_pressed;
+ extern int sysrq_enabled;
+ #endif
+
+-/*
+- * The structure of the events that flow between us and OS/400. You can't
+- * mess with this unless the OS/400 side changes too
+- */
+-struct viocharlpevent {
+- struct HvLpEvent event;
+- u32 reserved;
+- u16 version;
+- u16 subtype_result_code;
+- u8 virtual_device;
+- u8 len;
+- u8 data[VIOCHAR_MAX_DATA];
+-};
+-
+-#define VIOCHAR_WINDOW 10
+-#define VIOCHAR_HIGHWATERMARK 3
+-
+-enum viocharsubtype {
+- viocharopen = 0x0001,
+- viocharclose = 0x0002,
+- viochardata = 0x0003,
+- viocharack = 0x0004,
+- viocharconfig = 0x0005
+-};
+-
+-enum viochar_rc {
+- viochar_rc_ebusy = 1
+-};
+-
+ #define VIOCHAR_NUM_BUF 16
+
+ /*
+@@ -977,7 +947,7 @@ static void vioHandleData(struct HvLpEve
+ */
+ continue;
+ } else if (vio_sysrq_pressed) {
+- handle_sysrq(cevent->data[index], NULL, tty);
++ handle_sysrq(cevent->data[index], tty);
+ vio_sysrq_pressed = 0;
+ /*
+ * continue because we don't want to add
+@@ -1077,7 +1047,7 @@ static int send_open(HvLpIndex remoteLp,
+ 0, 0, 0, 0);
+ }
+
+-static struct tty_operations serial_ops = {
++static const struct tty_operations serial_ops = {
+ .open = viotty_open,
+ .close = viotty_close,
+ .write = viotty_write,
+@@ -1183,6 +1153,7 @@ static int __init viocons_init(void)
+ port_info[i].magic = VIOTTY_MAGIC;
+ }
+ HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
++ add_preferred_console("viocons", 0, NULL);
+ register_console(&viocons_early);
+ return 0;
+ }
+diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
+index b72b204..73c78bf 100644
+--- a/drivers/char/viotape.c
++++ b/drivers/char/viotape.c
+@@ -940,7 +940,6 @@ static void vioHandleTapeEvent(struct Hv
+
+ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
+ {
+- char tapename[32];
+ int i = vdev->unit_address;
+ int j;
+
+@@ -956,10 +955,9 @@ static int viotape_probe(struct vio_dev
+ "iseries!vt%d", i);
+ class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+ NULL, "iseries!nvt%d", i);
+- sprintf(tapename, "iseries/vt%d", i);
+- printk(VIOTAPE_KERN_INFO "tape %s is iSeries "
++ printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
+ "resource %10.10s type %4.4s, model %3.3s\n",
+- tapename, viotape_unitinfo[i].rsrcname,
++ i, viotape_unitinfo[i].rsrcname,
+ viotape_unitinfo[i].type, viotape_unitinfo[i].model);
+ return 0;
+ }
+diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
+index bfe5ea9..d0b94dd 100644
+--- a/drivers/char/vme_scc.c
++++ b/drivers/char/vme_scc.c
+@@ -81,10 +81,10 @@ static int scc_ioctl(struct tty_struct *
+ unsigned int cmd, unsigned long arg);
+ static void scc_throttle(struct tty_struct *tty);
+ static void scc_unthrottle(struct tty_struct *tty);
+-static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp);
+-static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp);
+-static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp);
+-static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t scc_tx_int(int irq, void *data);
++static irqreturn_t scc_rx_int(int irq, void *data);
++static irqreturn_t scc_stat_int(int irq, void *data);
++static irqreturn_t scc_spcond_int(int irq, void *data);
+ static void scc_setsignals(struct scc_port *port, int dtr, int rts);
+ static void scc_break_ctl(struct tty_struct *tty, int break_state);
+
+@@ -113,7 +113,7 @@ static struct real_driver scc_real_drive
+ };
+
+
+-static struct tty_operations scc_ops = {
++static const struct tty_operations scc_ops = {
+ .open = scc_open,
+ .close = gs_close,
+ .write = gs_write,
+@@ -419,7 +419,7 @@ module_init(vme_scc_init);
+ * Interrupt handlers
+ *--------------------------------------------------------------------------*/
+
+-static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp)
++static irqreturn_t scc_rx_int(int irq, void *data)
+ {
+ unsigned char ch;
+ struct scc_port *port = data;
+@@ -440,7 +440,7 @@ static irqreturn_t scc_rx_int(int irq, v
+ */
+ if (SCCread(INT_PENDING_REG) &
+ (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
+- scc_spcond_int (irq, data, fp);
++ scc_spcond_int (irq, data);
+ return IRQ_HANDLED;
+ }
+
+@@ -451,7 +451,7 @@ static irqreturn_t scc_rx_int(int irq, v
+ }
+
+
+-static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp)
++static irqreturn_t scc_spcond_int(int irq, void *data)
+ {
+ struct scc_port *port = data;
+ struct tty_struct *tty = port->gs.tty;
+@@ -496,7 +496,7 @@ static irqreturn_t scc_spcond_int(int ir
+ }
+
+
+-static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp)
++static irqreturn_t scc_tx_int(int irq, void *data)
+ {
+ struct scc_port *port = data;
+ SCC_ACCESS_INIT(port);
+@@ -538,7 +538,7 @@ static irqreturn_t scc_tx_int(int irq, v
+ }
+
+
+-static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp)
++static irqreturn_t scc_stat_int(int irq, void *data)
+ {
+ struct scc_port *port = data;
+ unsigned channel = port->channel;
+@@ -593,7 +593,7 @@ static void scc_enable_tx_interrupts(voi
+ local_irq_save(flags);
+ SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
+ /* restart the transmitter */
+- scc_tx_int (0, port, 0);
++ scc_tx_int (0, port);
+ local_irq_restore(flags);
+ }
+
+diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
+index 8116a47..8e79493 100644
+--- a/drivers/char/vr41xx_giu.c
++++ b/drivers/char/vr41xx_giu.c
+@@ -221,7 +221,7 @@ static struct hw_interrupt_type giuint_h
+ .end = end_giuint_high_irq,
+ };
+
+-static int giu_get_irq(unsigned int irq, struct pt_regs *regs)
++static int giu_get_irq(unsigned int irq)
+ {
+ uint16_t pendl, pendh, maskl, maskh;
+ int i;
+diff --git a/drivers/char/vt.c b/drivers/char/vt.c
+index da7e66a..8e4413f 100644
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -63,6 +63,13 @@
+ *
+ * Removed console_lock, enabled interrupts across all console operations
+ * 13 March 2001, Andrew Morton
++ *
++ * Fixed UTF-8 mode so alternate charset modes always work according
++ * to control sequences interpreted in do_con_trol function
++ * preserving backward VT100 semigraphics compatibility,
++ * malformed UTF sequences represented as sequences of replacement glyphs,
++ * original codes or '?' as a last resort if replacement glyph is undefined
++ * by Adam Tla/lka <atlka at pg.gda.pl>, Aug 2006
+ */
+
+ #include <linux/module.h>
+@@ -99,7 +106,8 @@
+ #define MAX_NR_CON_DRIVER 16
+
+ #define CON_DRIVER_FLAG_MODULE 1
+-#define CON_DRIVER_FLAG_INIT 2
++#define CON_DRIVER_FLAG_INIT 2
++#define CON_DRIVER_FLAG_ATTR 4
+
+ struct con_driver {
+ const struct consw *con;
+@@ -128,16 +136,8 @@ const struct consw *conswitchp;
+ #define DEFAULT_BELL_PITCH 750
+ #define DEFAULT_BELL_DURATION (HZ/8)
+
+-extern void vcs_make_devfs(struct tty_struct *tty);
+-extern void vcs_remove_devfs(struct tty_struct *tty);
+-
+-extern void console_map_init(void);
+-#ifdef CONFIG_PROM_CONSOLE
+-extern void prom_con_init(void);
+-#endif
+-#ifdef CONFIG_MDA_CONSOLE
+-extern int mda_console_init(void);
+-#endif
++extern void vcs_make_sysfs(struct tty_struct *tty);
++extern void vcs_remove_sysfs(struct tty_struct *tty);
+
+ struct vc vc_cons [MAX_NR_CONSOLES];
+
+@@ -730,7 +730,8 @@ int vc_allocate(unsigned int currcons) /
+ visual_init(vc, currcons, 1);
+ if (!*vc->vc_uni_pagedir_loc)
+ con_set_default_unimap(vc);
+- vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
++ if (!vc->vc_kmalloced)
++ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+ if (!vc->vc_screenbuf) {
+ kfree(vc);
+ vc_cons[currcons].d = NULL;
+@@ -878,14 +879,24 @@ int vc_resize(struct vc_data *vc, unsign
+ return err;
+ }
+
++int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
++{
++ int rc;
++
++ acquire_console_sem();
++ rc = vc_resize(vc, cols, lines);
++ release_console_sem();
++ return rc;
++}
+
+-void vc_disallocate(unsigned int currcons)
++void vc_deallocate(unsigned int currcons)
+ {
+ WARN_CONSOLE_UNLOCKED();
+
+ if (vc_cons_allocated(currcons)) {
+ struct vc_data *vc = vc_cons[currcons].d;
+ vc->vc_sw->con_deinit(vc);
++ put_pid(vc->vt_pid);
+ module_put(vc->vc_sw->owner);
+ if (vc->vc_kmalloced)
+ kfree(vc->vc_screenbuf);
+@@ -2005,17 +2016,23 @@ static int do_con_write(struct tty_struc
+ /* Do no translation at all in control states */
+ if (vc->vc_state != ESnormal) {
+ tc = c;
+- } else if (vc->vc_utf) {
++ } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
+ /* Combine UTF-8 into Unicode */
+- /* Incomplete characters silently ignored */
++ /* Malformed sequences as sequences of replacement glyphs */
++rescan_last_byte:
+ if(c > 0x7f) {
+- if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) {
+- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+- vc->vc_utf_count--;
+- if (vc->vc_utf_count == 0)
+- tc = c = vc->vc_utf_char;
+- else continue;
++ if (vc->vc_utf_count) {
++ if ((c & 0xc0) == 0x80) {
++ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
++ if (--vc->vc_utf_count) {
++ vc->vc_npar++;
++ continue;
++ }
++ tc = c = vc->vc_utf_char;
++ } else
++ goto replacement_glyph;
+ } else {
++ vc->vc_npar = 0;
+ if ((c & 0xe0) == 0xc0) {
+ vc->vc_utf_count = 1;
+ vc->vc_utf_char = (c & 0x1f);
+@@ -2032,14 +2049,15 @@ static int do_con_write(struct tty_struc
+ vc->vc_utf_count = 5;
+ vc->vc_utf_char = (c & 0x01);
+ } else
+- vc->vc_utf_count = 0;
++ goto replacement_glyph;
+ continue;
+ }
+ } else {
++ if (vc->vc_utf_count)
++ goto replacement_glyph;
+ tc = c;
+- vc->vc_utf_count = 0;
+ }
+- } else { /* no utf */
++ } else { /* no utf or alternate charset mode */
+ tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
+ }
+
+@@ -2054,31 +2072,33 @@ static int do_con_write(struct tty_struc
+ * direct-to-font zone in UTF-8 mode.
+ */
+ ok = tc && (c >= 32 ||
+- (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS
+- : CTRL_ACTION) >> c) & 1)))
++ !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
++ vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
+ && (c != 127 || vc->vc_disp_ctrl)
+ && (c != 128+27);
+
+ if (vc->vc_state == ESnormal && ok) {
+ /* Now try to find out how to display it */
+ tc = conv_uni_to_pc(vc, tc);
+- if ( tc == -4 ) {
++ if (tc & ~charmask) {
++ if ( tc == -4 ) {
+ /* If we got -4 (not found) then see if we have
+ defined a replacement character (U+FFFD) */
+- tc = conv_uni_to_pc(vc, 0xfffd);
+-
+- /* One reason for the -4 can be that we just
+- did a clear_unimap();
+- try at least to show something. */
+- if (tc == -4)
+- tc = c;
+- } else if ( tc == -3 ) {
+- /* Bad hash table -- hope for the best */
+- tc = c;
+- }
+- if (tc & ~charmask)
+- continue; /* Conversion failed */
++replacement_glyph:
++ tc = conv_uni_to_pc(vc, 0xfffd);
++ if (!(tc & ~charmask))
++ goto display_glyph;
++ } else if ( tc != -3 )
++ continue; /* nothing to display */
++ /* no hash table or no replacement --
++ * hope for the best */
++ if ( c & ~charmask )
++ tc = '?';
++ else
++ tc = c;
++ }
+
++display_glyph:
+ if (vc->vc_need_wrap || vc->vc_decim)
+ FLUSH
+ if (vc->vc_need_wrap) {
+@@ -2102,6 +2122,15 @@ static int do_con_write(struct tty_struc
+ vc->vc_x++;
+ draw_to = (vc->vc_pos += 2);
+ }
++ if (vc->vc_utf_count) {
++ if (vc->vc_npar) {
++ vc->vc_npar--;
++ goto display_glyph;
++ }
++ vc->vc_utf_count = 0;
++ c = orig;
++ goto rescan_last_byte;
++ }
+ continue;
+ }
+ FLUSH
+@@ -2498,7 +2527,7 @@ static int con_open(struct tty_struct *t
+ tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+ }
+ release_console_sem();
+- vcs_make_devfs(tty);
++ vcs_make_sysfs(tty);
+ return ret;
+ }
+ }
+@@ -2511,7 +2540,7 @@ static int con_open(struct tty_struct *t
+ * and taking a ref against the tty while we're in the process of forgetting
+ * about it and cleaning things up.
+ *
+- * This is because vcs_remove_devfs() can sleep and will drop the BKL.
++ * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
+ */
+ static void con_close(struct tty_struct *tty, struct file *filp)
+ {
+@@ -2524,7 +2553,7 @@ static void con_close(struct tty_struct
+ vc->vc_tty = NULL;
+ tty->driver_data = NULL;
+ release_console_sem();
+- vcs_remove_devfs(tty);
++ vcs_remove_sysfs(tty);
+ mutex_unlock(&tty_mutex);
+ /*
+ * tty_mutex is released, but we still hold BKL, so there is
+@@ -2639,7 +2668,7 @@ static int __init con_init(void)
+ }
+ console_initcall(con_init);
+
+-static struct tty_operations con_ops = {
++static const struct tty_operations con_ops = {
+ .open = con_open,
+ .close = con_close,
+ .write = con_write,
+@@ -3034,22 +3063,37 @@ static struct class_device_attribute cla
+ static int vtconsole_init_class_device(struct con_driver *con)
+ {
+ int i;
++ int error = 0;
+
++ con->flag |= CON_DRIVER_FLAG_ATTR;
+ class_set_devdata(con->class_dev, con);
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_create_file(con->class_dev,
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
++ error = class_device_create_file(con->class_dev,
+ &class_device_attrs[i]);
++ if (error)
++ break;
++ }
+
+- return 0;
++ if (error) {
++ while (--i >= 0)
++ class_device_remove_file(con->class_dev,
++ &class_device_attrs[i]);
++ con->flag &= ~CON_DRIVER_FLAG_ATTR;
++ }
++
++ return error;
+ }
+
+ static void vtconsole_deinit_class_device(struct con_driver *con)
+ {
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_remove_file(con->class_dev,
+- &class_device_attrs[i]);
++ if (con->flag & CON_DRIVER_FLAG_ATTR) {
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
++ class_device_remove_file(con->class_dev,
++ &class_device_attrs[i]);
++ con->flag &= ~CON_DRIVER_FLAG_ATTR;
++ }
+ }
+
+ /**
+@@ -3148,6 +3192,7 @@ int register_con_driver(const struct con
+ } else {
+ vtconsole_init_class_device(con_driver);
+ }
++
+ err:
+ release_console_sem();
+ module_put(owner);
+@@ -3765,6 +3810,7 @@ EXPORT_SYMBOL(default_blu);
+ EXPORT_SYMBOL(update_region);
+ EXPORT_SYMBOL(redraw_screen);
+ EXPORT_SYMBOL(vc_resize);
++EXPORT_SYMBOL(vc_lock_resize);
+ EXPORT_SYMBOL(fg_console);
+ EXPORT_SYMBOL(console_blank_hook);
+ EXPORT_SYMBOL(console_blanked);
+diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
+index a5628a8..ac5d60e 100644
+--- a/drivers/char/vt_ioctl.c
++++ b/drivers/char/vt_ioctl.c
+@@ -96,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __
+ if (!perm)
+ return -EPERM;
+ if (!i && v == K_NOSUCHMAP) {
+- /* disallocate map */
++ /* deallocate map */
+ key_map = key_maps[s];
+ if (s && key_map) {
+ key_maps[s] = NULL;
+@@ -645,13 +645,16 @@ int vt_ioctl(struct tty_struct *tty, str
+ */
+ case KDSIGACCEPT:
+ {
+- extern int spawnpid, spawnsig;
+ if (!perm || !capable(CAP_KILL))
+ return -EPERM;
+ if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
+ return -EINVAL;
+- spawnpid = current->pid;
+- spawnsig = arg;
++
++ spin_lock_irq(&vt_spawn_con.lock);
++ put_pid(vt_spawn_con.pid);
++ vt_spawn_con.pid = get_pid(task_pid(current));
++ vt_spawn_con.sig = arg;
++ spin_unlock_irq(&vt_spawn_con.lock);
+ return 0;
+ }
+
+@@ -669,7 +672,7 @@ int vt_ioctl(struct tty_struct *tty, str
+ vc->vt_mode = tmp;
+ /* the frsig is ignored, so we set it to 0 */
+ vc->vt_mode.frsig = 0;
+- vc->vt_pid = current->pid;
++ put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current))));
+ /* no switch is required -- saw at shade.msu.ru */
+ vc->vt_newvt = -1;
+ release_console_sem();
+@@ -819,20 +822,20 @@ int vt_ioctl(struct tty_struct *tty, str
+ if (arg > MAX_NR_CONSOLES)
+ return -ENXIO;
+ if (arg == 0) {
+- /* disallocate all unused consoles, but leave 0 */
++ /* deallocate all unused consoles, but leave 0 */
+ acquire_console_sem();
+ for (i=1; i<MAX_NR_CONSOLES; i++)
+ if (! VT_BUSY(i))
+- vc_disallocate(i);
++ vc_deallocate(i);
+ release_console_sem();
+ } else {
+- /* disallocate a single console, if possible */
++ /* deallocate a single console, if possible */
+ arg--;
+ if (VT_BUSY(arg))
+ return -EBUSY;
+ if (arg) { /* leave 0 */
+ acquire_console_sem();
+- vc_disallocate(arg);
++ vc_deallocate(arg);
+ release_console_sem();
+ }
+ }
+@@ -847,11 +850,8 @@ int vt_ioctl(struct tty_struct *tty, str
+ if (get_user(ll, &vtsizes->v_rows) ||
+ get_user(cc, &vtsizes->v_cols))
+ return -EFAULT;
+- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+- acquire_console_sem();
+- vc_resize(vc_cons[i].d, cc, ll);
+- release_console_sem();
+- }
++ for (i = 0; i < MAX_NR_CONSOLES; i++)
++ vc_lock_resize(vc_cons[i].d, cc, ll);
+ return 0;
+ }
+
+@@ -1063,7 +1063,7 @@ void reset_vc(struct vc_data *vc)
+ vc->vt_mode.relsig = 0;
+ vc->vt_mode.acqsig = 0;
+ vc->vt_mode.frsig = 0;
+- vc->vt_pid = -1;
++ put_pid(xchg(&vc->vt_pid, NULL));
+ vc->vt_newvt = -1;
+ if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
+ reset_palette(vc);
+@@ -1114,7 +1114,7 @@ static void complete_change_console(stru
+ * tell us if the process has gone or something else
+ * is awry
+ */
+- if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
++ if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
+ /*
+ * The controlling process has died, so we revert back to
+ * normal operation. In this case, we'll also change back
+@@ -1174,7 +1174,7 @@ void change_console(struct vc_data *new_
+ * tell us if the process has gone or something else
+ * is awry
+ */
+- if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
++ if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
+ /*
+ * It worked. Mark the vt to switch to and
+ * return. The process needs to send us a
+diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
+index fff89c2..0187b11 100644
+--- a/drivers/char/watchdog/Kconfig
++++ b/drivers/char/watchdog/Kconfig
+@@ -13,7 +13,7 @@ config WATCHDOG
+ subsequently opening the file and then failing to write to it for
+ longer than 1 minute will result in rebooting the machine. This
+ could be useful for a networked machine that needs to come back
+- online as fast as possible after a lock-up. There's both a watchdog
++ on-line as fast as possible after a lock-up. There's both a watchdog
+ implementation entirely in software (which can sometimes fail to
+ reboot the machine) and a driver for hardware watchdog boards, which
+ are more robust and can also keep track of the temperature inside
+@@ -60,7 +60,7 @@ config SOFT_WATCHDOG
+
+ # ARM Architecture
+
+-config AT91_WATCHDOG
++config AT91RM9200_WATCHDOG
+ tristate "AT91RM9200 watchdog"
+ depends on WATCHDOG && ARCH_AT91RM9200
+ help
+@@ -71,7 +71,7 @@ config 21285_WATCHDOG
+ tristate "DC21285 watchdog"
+ depends on WATCHDOG && FOOTBRIDGE
+ help
+- The Intel Footbridge chip contains a builtin watchdog circuit. Say Y
++ The Intel Footbridge chip contains a built-in watchdog circuit. Say Y
+ here if you wish to use this. Alternatively say M to compile the
+ driver as a module, which will be called wdt285.
+
+@@ -165,6 +165,24 @@ config EP93XX_WATCHDOG
+ To compile this driver as a module, choose M here: the
+ module will be called ep93xx_wdt.
+
++config OMAP_WATCHDOG
++ tristate "OMAP Watchdog"
++ depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX)
++ help
++ Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
++ enable the OMAP1610/OMAP1710 watchdog timer.
++
++config PNX4008_WATCHDOG
++ tristate "PNX4008 Watchdog"
++ depends on WATCHDOG && ARCH_PNX4008
++ help
++ Say Y here if to include support for the watchdog timer
++ in the PNX4008 processor.
++ This driver can be built as a module by choosing M. The module
++ will be called pnx4008_wdt.
++
++ Say N if you are unsure.
++
+ # X86 (i386 + ia64 + x86_64) Architecture
+
+ config ACQUIRE_WDT
+@@ -251,11 +269,11 @@ config IB700_WDT
+ Most people will say N.
+
+ config IBMASR
+- tristate "IBM Automatic Server Restart"
+- depends on WATCHDOG && X86
+- help
++ tristate "IBM Automatic Server Restart"
++ depends on WATCHDOG && X86
++ help
+ This is the driver for the IBM Automatic Server Restart watchdog
+- timer builtin into some eServer xSeries machines.
++ timer built-in into some eServer xSeries machines.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ibmasr.
+@@ -298,6 +316,30 @@ config I8XX_TCO
+ To compile this driver as a module, choose M here: the
+ module will be called i8xx_tco.
+
++ Note: This driver will be removed in the near future. Please
++ use the Intel TCO Timer/Watchdog driver.
++
++config ITCO_WDT
++ tristate "Intel TCO Timer/Watchdog"
++ depends on WATCHDOG && (X86 || IA64) && PCI
++ ---help---
++ Hardware driver for the intel TCO timer based watchdog devices.
++ These drivers are included in the Intel 82801 I/O Controller
++ Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB
++ controller hub.
++
++ The TCO (Total Cost of Ownership) timer is a watchdog timer
++ that will reboot the machine after its second expiration. The
++ expiration time can be configured with the "heartbeat" parameter.
++
++ On some motherboards the driver may fail to reset the chipset's
++ NO_REBOOT flag which prevents the watchdog from rebooting the
++ machine. If this is the case you will get a kernel message like
++ "failed to reset NO_REBOOT flag, reboot disabled by hardware".
++
++ To compile this driver as a module, choose M here: the
++ module will be called iTCO_wdt.
++
+ config SC1200_WDT
+ tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
+ depends on WATCHDOG && X86
+@@ -356,6 +398,26 @@ config CPU5_WDT
+ To compile this driver as a module, choose M here: the
+ module will be called cpu5wdt.
+
++config SMSC37B787_WDT
++ tristate "Winbond SMsC37B787 Watchdog Timer"
++ depends on WATCHDOG && X86
++ ---help---
++ This is the driver for the hardware watchdog component on the
++ Winbond SMsC37B787 chipset as used on the NetRunner Mainboard
++ from Vision Systems and maybe others.
++
++ This watchdog simply watches your kernel to make sure it doesn't
++ freeze, and if it does, it reboots your computer after a certain
++ amount of time.
++
++ Usually a userspace daemon will notify the kernel WDT driver that
++ userspace is still alive, at regular intervals.
++
++ To compile this driver as a module, choose M here: the
++ module will be called smsc37b787_wdt.
++
++ Most people will say N.
++
+ config W83627HF_WDT
+ tristate "W83627HF Watchdog Timer"
+ depends on WATCHDOG && X86
+@@ -371,6 +433,21 @@ config W83627HF_WDT
+
+ Most people will say N.
+
++config W83697HF_WDT
++ tristate "W83697HF/W83697HG Watchdog Timer"
++ depends on WATCHDOG && X86
++ ---help---
++ This is the driver for the hardware watchdog on the W83697HF/HG
++ chipset as used in Dedibox/VIA motherboards (and likely others).
++ This watchdog simply watches your kernel to make sure it doesn't
++ freeze, and if it does, it reboots your computer after a certain
++ amount of time.
++
++ To compile this driver as a module, choose M here: the
++ module will be called w83697hf_wdt.
++
++ Most people will say N.
++
+ config W83877F_WDT
+ tristate "W83877F (EMACS) Watchdog Timer"
+ depends on WATCHDOG && X86
+@@ -404,7 +481,7 @@ config MACHZ_WDT
+ depends on WATCHDOG && X86
+ ---help---
+ If you are using a ZF Micro MachZ processor, say Y here, otherwise
+- N. This is the driver for the watchdog timer builtin on that
++ N. This is the driver for the watchdog timer built-in on that
+ processor using ZF-Logic interface. This watchdog simply watches
+ your kernel to make sure it doesn't freeze, and if it does, it
+ reboots your computer after a certain amount of time.
+@@ -433,7 +510,6 @@ config SBC_EPX_C3_WATCHDOG
+ To compile this driver as a module, choose M here: the
+ module will be called sbc_epx_c3.
+
+-
+ # PowerPC Architecture
+
+ config 8xx_WDT
+@@ -463,7 +539,7 @@ config WATCHDOG_RTAS
+ help
+ This driver adds watchdog support for the RTAS watchdog.
+
+- To compile this driver as a module, choose M here. The module
++ To compile this driver as a module, choose M here. The module
+ will be called wdrtas.
+
+ # MIPS Architecture
+@@ -510,6 +586,14 @@ config SH_WDT
+ To compile this driver as a module, choose M here: the
+ module will be called shwdt.
+
++config SH_WDT_MMAP
++ bool "Allow mmap of SH WDT"
++ default n
++ depends on SH_WDT
++ help
++ If you say Y here, user applications will be able to mmap the
++ WDT/CPG registers.
++
+ # SPARC64 Architecture
+
+ config WATCHDOG_CP1XXX
+diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
+index 6ab77b6..3644049 100644
+--- a/drivers/char/watchdog/Makefile
++++ b/drivers/char/watchdog/Makefile
+@@ -23,7 +23,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
+ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+
+ # ARM Architecture
+-obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o
++obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
++obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
+ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
+ obj-$(CONFIG_977_WATCHDOG) += wdt977.o
+ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+@@ -32,6 +33,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c241
+ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
+ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
++obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+
+ # X86 (i386 + ia64 + x86_64) Architecture
+ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+@@ -45,12 +47,15 @@ obj-$(CONFIG_IBMASR) += ibmasr.o
+ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+ obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
+ obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
++obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
+ obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
+ obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+ obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
+ obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
++obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
+ obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
++obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
+ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
+ obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
+index c77fe3c..154d67e 100644
+--- a/drivers/char/watchdog/acquirewdt.c
++++ b/drivers/char/watchdog/acquirewdt.c
+@@ -183,7 +183,7 @@ static int acq_ioctl(struct inode *inode
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
+index 8069be4..9d73276 100644
+--- a/drivers/char/watchdog/advantechwdt.c
++++ b/drivers/char/watchdog/advantechwdt.c
+@@ -176,7 +176,7 @@ advwdt_ioctl(struct inode *inode, struct
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ return 0;
+ }
+diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
+index c5c94e4..01b0d13 100644
+--- a/drivers/char/watchdog/alim1535_wdt.c
++++ b/drivers/char/watchdog/alim1535_wdt.c
+@@ -236,7 +236,7 @@ static int ali_ioctl(struct inode *inode
+ return put_user(timeout, p);
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+@@ -330,17 +330,20 @@ static int __init ali_find_watchdog(void
+ u32 wdog;
+
+ /* Check for a 1535 series bridge */
+- pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
++ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
+ if(pdev == NULL)
+ return -ENODEV;
++ pci_dev_put(pdev);
+
+ /* Check for the a 7101 PMU */
+- pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
++ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
+ if(pdev == NULL)
+ return -ENODEV;
+
+- if(pci_enable_device(pdev))
++ if(pci_enable_device(pdev)) {
++ pci_dev_put(pdev);
+ return -EIO;
++ }
+
+ ali_pci = pdev;
+
+@@ -447,6 +450,7 @@ static void __exit watchdog_exit(void)
+ /* Deregister */
+ unregister_reboot_notifier(&ali_notifier);
+ misc_deregister(&ali_miscdev);
++ pci_dev_put(ali_pci);
+ }
+
+ module_init(watchdog_init);
+diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
+index ffd7684..bf25d0a 100644
+--- a/drivers/char/watchdog/alim7101_wdt.c
++++ b/drivers/char/watchdog/alim7101_wdt.c
+@@ -77,7 +77,8 @@ static struct pci_dev *alim7101_pmu;
+
+ static int nowayout = WATCHDOG_NOWAYOUT;
+ module_param(nowayout, int, 0);
+-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
++ __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")");
+
+ /*
+ * Whack the dog
+@@ -277,7 +278,7 @@ static int fop_ioctl(struct inode *inode
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+@@ -333,6 +334,7 @@ static void __exit alim7101_wdt_unload(v
+ /* Deregister */
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
++ pci_dev_put(alim7101_pmu);
+ }
+
+ static int __init alim7101_wdt_init(void)
+@@ -342,7 +344,8 @@ static int __init alim7101_wdt_init(void
+ char tmp;
+
+ printk(KERN_INFO PFX "Steve Hill <steve at navaho.co.uk>.\n");
+- alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL);
++ alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
++ NULL);
+ if (!alim7101_pmu) {
+ printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n");
+ return -EBUSY;
+@@ -351,21 +354,23 @@ static int __init alim7101_wdt_init(void
+ /* Set the WDT in the PMU to 1 second */
+ pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
+
+- ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
++ ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
++ NULL);
+ if (!ali1543_south) {
+ printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n");
+- return -EBUSY;
++ goto err_out;
+ }
+ pci_read_config_byte(ali1543_south, 0x5e, &tmp);
++ pci_dev_put(ali1543_south);
+ if ((tmp & 0x1e) == 0x00) {
+ if (!use_gpio) {
+ printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
+- return -EBUSY;
++ goto err_out;
+ }
+ nowayout = 1;
+ } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
+ printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
+- return -EBUSY;
++ goto err_out;
+ }
+
+ if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
+@@ -404,12 +409,23 @@ static int __init alim7101_wdt_init(void
+ err_out_miscdev:
+ misc_deregister(&wdt_miscdev);
+ err_out:
++ pci_dev_put(alim7101_pmu);
+ return rc;
+ }
+
+ module_init(alim7101_wdt_init);
+ module_exit(alim7101_wdt_unload);
+
++static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
++};
++
++MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl);
++
+ MODULE_AUTHOR("Steve Hill");
+ MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c
+deleted file mode 100644
+index cc26671..0000000
+--- a/drivers/char/watchdog/at91_wdt.c
++++ /dev/null
+@@ -1,287 +0,0 @@
+-/*
+- * Watchdog driver for Atmel AT91RM9200 (Thunder)
+- *
+- * Copyright (C) 2003 SAN People (Pty) 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.
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/fs.h>
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <linux/miscdevice.h>
+-#include <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/platform_device.h>
+-#include <linux/types.h>
+-#include <linux/watchdog.h>
+-#include <asm/bitops.h>
+-#include <asm/uaccess.h>
+-
+-
+-#define WDT_DEFAULT_TIME 5 /* seconds */
+-#define WDT_MAX_TIME 256 /* seconds */
+-
+-static int wdt_time = WDT_DEFAULT_TIME;
+-static int nowayout = WATCHDOG_NOWAYOUT;
+-
+-module_param(wdt_time, int, 0);
+-MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
+-
+-#ifdef CONFIG_WATCHDOG_NOWAYOUT
+-module_param(nowayout, int, 0);
+-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+-#endif
+-
+-
+-static unsigned long at91wdt_busy;
+-
+-/* ......................................................................... */
+-
+-/*
+- * Disable the watchdog.
+- */
+-static void inline at91_wdt_stop(void)
+-{
+- at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
+-}
+-
+-/*
+- * Enable and reset the watchdog.
+- */
+-static void inline at91_wdt_start(void)
+-{
+- at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
+- at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+-}
+-
+-/*
+- * Reload the watchdog timer. (ie, pat the watchdog)
+- */
+-static void inline at91_wdt_reload(void)
+-{
+- at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+-}
+-
+-/* ......................................................................... */
+-
+-/*
+- * Watchdog device is opened, and watchdog starts running.
+- */
+-static int at91_wdt_open(struct inode *inode, struct file *file)
+-{
+- if (test_and_set_bit(0, &at91wdt_busy))
+- return -EBUSY;
+-
+- at91_wdt_start();
+- return nonseekable_open(inode, file);
+-}
+-
+-/*
+- * Close the watchdog device.
+- * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
+- * disabled.
+- */
+-static int at91_wdt_close(struct inode *inode, struct file *file)
+-{
+- if (!nowayout)
+- at91_wdt_stop(); /* Disable the watchdog when file is closed */
+-
+- clear_bit(0, &at91wdt_busy);
+- return 0;
+-}
+-
+-/*
+- * Change the watchdog time interval.
+- */
+-static int at91_wdt_settimeout(int new_time)
+-{
+- /*
+- * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
+- *
+- * Since WDV is a 16-bit counter, the maximum period is
+- * 65536 / 0.256 = 256 seconds.
+- */
+- if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+- return -EINVAL;
+-
+- /* Set new watchdog time. It will be used when at91_wdt_start() is called. */
+- wdt_time = new_time;
+- return 0;
+-}
+-
+-static struct watchdog_info at91_wdt_info = {
+- .identity = "at91 watchdog",
+- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+-};
+-
+-/*
+- * Handle commands from user-space.
+- */
+-static int at91_wdt_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+- int new_value;
+-
+- switch(cmd) {
+- case WDIOC_KEEPALIVE:
+- at91_wdt_reload(); /* pat the watchdog */
+- return 0;
+-
+- case WDIOC_GETSUPPORT:
+- return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
+-
+- case WDIOC_SETTIMEOUT:
+- if (get_user(new_value, p))
+- return -EFAULT;
+-
+- if (at91_wdt_settimeout(new_value))
+- return -EINVAL;
+-
+- /* Enable new time value */
+- at91_wdt_start();
+-
+- /* Return current value */
+- return put_user(wdt_time, p);
+-
+- case WDIOC_GETTIMEOUT:
+- return put_user(wdt_time, p);
+-
+- case WDIOC_GETSTATUS:
+- case WDIOC_GETBOOTSTATUS:
+- return put_user(0, p);
+-
+- case WDIOC_SETOPTIONS:
+- if (get_user(new_value, p))
+- return -EFAULT;
+-
+- if (new_value & WDIOS_DISABLECARD)
+- at91_wdt_stop();
+- if (new_value & WDIOS_ENABLECARD)
+- at91_wdt_start();
+- return 0;
+-
+- default:
+- return -ENOIOCTLCMD;
+- }
+-}
+-
+-/*
+- * Pat the watchdog whenever device is written to.
+- */
+-static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+-{
+- at91_wdt_reload(); /* pat the watchdog */
+- return len;
+-}
+-
+-/* ......................................................................... */
+-
+-static const struct file_operations at91wdt_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = at91_wdt_ioctl,
+- .open = at91_wdt_open,
+- .release = at91_wdt_close,
+- .write = at91_wdt_write,
+-};
+-
+-static struct miscdevice at91wdt_miscdev = {
+- .minor = WATCHDOG_MINOR,
+- .name = "watchdog",
+- .fops = &at91wdt_fops,
+-};
+-
+-static int __init at91wdt_probe(struct platform_device *pdev)
+-{
+- int res;
+-
+- if (at91wdt_miscdev.dev)
+- return -EBUSY;
+- at91wdt_miscdev.dev = &pdev->dev;
+-
+- res = misc_register(&at91wdt_miscdev);
+- if (res)
+- return res;
+-
+- printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
+- return 0;
+-}
+-
+-static int __exit at91wdt_remove(struct platform_device *pdev)
+-{
+- int res;
+-
+- res = misc_deregister(&at91wdt_miscdev);
+- if (!res)
+- at91wdt_miscdev.dev = NULL;
+-
+- return res;
+-}
+-
+-static void at91wdt_shutdown(struct platform_device *pdev)
+-{
+- at91_wdt_stop();
+-}
+-
+-#ifdef CONFIG_PM
+-
+-static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+-{
+- at91_wdt_stop();
+- return 0;
+-}
+-
+-static int at91wdt_resume(struct platform_device *pdev)
+-{
+- if (at91wdt_busy)
+- at91_wdt_start();
+- return 0;
+-}
+-
+-#else
+-#define at91wdt_suspend NULL
+-#define at91wdt_resume NULL
+-#endif
+-
+-static struct platform_driver at91wdt_driver = {
+- .probe = at91wdt_probe,
+- .remove = __exit_p(at91wdt_remove),
+- .shutdown = at91wdt_shutdown,
+- .suspend = at91wdt_suspend,
+- .resume = at91wdt_resume,
+- .driver = {
+- .name = "at91_wdt",
+- .owner = THIS_MODULE,
+- },
+-};
+-
+-static int __init at91_wdt_init(void)
+-{
+- /* Check that the heartbeat value is within range; if not reset to the default */
+- if (at91_wdt_settimeout(wdt_time)) {
+- at91_wdt_settimeout(WDT_DEFAULT_TIME);
+- pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
+- }
+-
+- return platform_driver_register(&at91wdt_driver);
+-}
+-
+-static void __exit at91_wdt_exit(void)
+-{
+- platform_driver_unregister(&at91wdt_driver);
+-}
+-
+-module_init(at91_wdt_init);
+-module_exit(at91_wdt_exit);
+-
+-MODULE_AUTHOR("Andrew Victor");
+-MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/char/watchdog/at91rm9200_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c
+new file mode 100644
+index 0000000..4e7a114
+--- /dev/null
++++ b/drivers/char/watchdog/at91rm9200_wdt.c
+@@ -0,0 +1,287 @@
++/*
++ * Watchdog driver for Atmel AT91RM9200 (Thunder)
++ *
++ * Copyright (C) 2003 SAN People (Pty) 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.
++ */
++
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/watchdog.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++
++
++#define WDT_DEFAULT_TIME 5 /* seconds */
++#define WDT_MAX_TIME 256 /* seconds */
++
++static int wdt_time = WDT_DEFAULT_TIME;
++static int nowayout = WATCHDOG_NOWAYOUT;
++
++module_param(wdt_time, int, 0);
++MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
++
++#ifdef CONFIG_WATCHDOG_NOWAYOUT
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
++#endif
++
++
++static unsigned long at91wdt_busy;
++
++/* ......................................................................... */
++
++/*
++ * Disable the watchdog.
++ */
++static void inline at91_wdt_stop(void)
++{
++ at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
++}
++
++/*
++ * Enable and reset the watchdog.
++ */
++static void inline at91_wdt_start(void)
++{
++ at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
++ at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
++}
++
++/*
++ * Reload the watchdog timer. (ie, pat the watchdog)
++ */
++static void inline at91_wdt_reload(void)
++{
++ at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
++}
++
++/* ......................................................................... */
++
++/*
++ * Watchdog device is opened, and watchdog starts running.
++ */
++static int at91_wdt_open(struct inode *inode, struct file *file)
++{
++ if (test_and_set_bit(0, &at91wdt_busy))
++ return -EBUSY;
++
++ at91_wdt_start();
++ return nonseekable_open(inode, file);
++}
++
++/*
++ * Close the watchdog device.
++ * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
++ * disabled.
++ */
++static int at91_wdt_close(struct inode *inode, struct file *file)
++{
++ if (!nowayout)
++ at91_wdt_stop(); /* Disable the watchdog when file is closed */
++
++ clear_bit(0, &at91wdt_busy);
++ return 0;
++}
++
++/*
++ * Change the watchdog time interval.
++ */
++static int at91_wdt_settimeout(int new_time)
++{
++ /*
++ * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
++ *
++ * Since WDV is a 16-bit counter, the maximum period is
++ * 65536 / 0.256 = 256 seconds.
++ */
++ if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
++ return -EINVAL;
++
++ /* Set new watchdog time. It will be used when at91_wdt_start() is called. */
++ wdt_time = new_time;
++ return 0;
++}
++
++static struct watchdog_info at91_wdt_info = {
++ .identity = "at91 watchdog",
++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
++};
++
++/*
++ * Handle commands from user-space.
++ */
++static int at91_wdt_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ void __user *argp = (void __user *)arg;
++ int __user *p = argp;
++ int new_value;
++
++ switch(cmd) {
++ case WDIOC_KEEPALIVE:
++ at91_wdt_reload(); /* pat the watchdog */
++ return 0;
++
++ case WDIOC_GETSUPPORT:
++ return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
++
++ case WDIOC_SETTIMEOUT:
++ if (get_user(new_value, p))
++ return -EFAULT;
++
++ if (at91_wdt_settimeout(new_value))
++ return -EINVAL;
++
++ /* Enable new time value */
++ at91_wdt_start();
++
++ /* Return current value */
++ return put_user(wdt_time, p);
++
++ case WDIOC_GETTIMEOUT:
++ return put_user(wdt_time, p);
++
++ case WDIOC_GETSTATUS:
++ case WDIOC_GETBOOTSTATUS:
++ return put_user(0, p);
++
++ case WDIOC_SETOPTIONS:
++ if (get_user(new_value, p))
++ return -EFAULT;
++
++ if (new_value & WDIOS_DISABLECARD)
++ at91_wdt_stop();
++ if (new_value & WDIOS_ENABLECARD)
++ at91_wdt_start();
++ return 0;
++
++ default:
++ return -ENOTTY;
++ }
++}
++
++/*
++ * Pat the watchdog whenever device is written to.
++ */
++static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
++{
++ at91_wdt_reload(); /* pat the watchdog */
++ return len;
++}
++
++/* ......................................................................... */
++
++static const struct file_operations at91wdt_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .ioctl = at91_wdt_ioctl,
++ .open = at91_wdt_open,
++ .release = at91_wdt_close,
++ .write = at91_wdt_write,
++};
++
++static struct miscdevice at91wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &at91wdt_fops,
++};
++
++static int __init at91wdt_probe(struct platform_device *pdev)
++{
++ int res;
++
++ if (at91wdt_miscdev.dev)
++ return -EBUSY;
++ at91wdt_miscdev.dev = &pdev->dev;
++
++ res = misc_register(&at91wdt_miscdev);
++ if (res)
++ return res;
++
++ printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
++ return 0;
++}
++
++static int __exit at91wdt_remove(struct platform_device *pdev)
++{
++ int res;
++
++ res = misc_deregister(&at91wdt_miscdev);
++ if (!res)
++ at91wdt_miscdev.dev = NULL;
++
++ return res;
++}
++
++static void at91wdt_shutdown(struct platform_device *pdev)
++{
++ at91_wdt_stop();
++}
++
++#ifdef CONFIG_PM
++
++static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
++{
++ at91_wdt_stop();
++ return 0;
++}
++
++static int at91wdt_resume(struct platform_device *pdev)
++{
++ if (at91wdt_busy)
++ at91_wdt_start();
++ return 0;
++}
++
++#else
++#define at91wdt_suspend NULL
++#define at91wdt_resume NULL
++#endif
++
++static struct platform_driver at91wdt_driver = {
++ .probe = at91wdt_probe,
++ .remove = __exit_p(at91wdt_remove),
++ .shutdown = at91wdt_shutdown,
++ .suspend = at91wdt_suspend,
++ .resume = at91wdt_resume,
++ .driver = {
++ .name = "at91_wdt",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init at91_wdt_init(void)
++{
++ /* Check that the heartbeat value is within range; if not reset to the default */
++ if (at91_wdt_settimeout(wdt_time)) {
++ at91_wdt_settimeout(WDT_DEFAULT_TIME);
++ pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
++ }
++
++ return platform_driver_register(&at91wdt_driver);
++}
++
++static void __exit at91_wdt_exit(void)
++{
++ platform_driver_unregister(&at91wdt_driver);
++}
++
++module_init(at91_wdt_init);
++module_exit(at91_wdt_exit);
++
++MODULE_AUTHOR("Andrew Victor");
++MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
+index e3cefc5..4889022 100644
+--- a/drivers/char/watchdog/booke_wdt.c
++++ b/drivers/char/watchdog/booke_wdt.c
+@@ -125,7 +125,7 @@ static int booke_wdt_ioctl (struct inode
+ return -EINVAL;
+ return 0;
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ return 0;
+diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
+index 04c7e49..00bdabb 100644
+--- a/drivers/char/watchdog/cpu5wdt.c
++++ b/drivers/char/watchdog/cpu5wdt.c
+@@ -183,7 +183,7 @@ static int cpu5wdt_ioctl(struct inode *i
+ }
+ break;
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ return 0;
+ }
+diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
+index 77c8a95..01cf123 100644
+--- a/drivers/char/watchdog/ep93xx_wdt.c
++++ b/drivers/char/watchdog/ep93xx_wdt.c
+@@ -144,7 +144,7 @@ static int
+ ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+ {
+- int ret = -ENOIOCTLCMD;
++ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
+index 62dbccb..e228d6e 100644
+--- a/drivers/char/watchdog/eurotechwdt.c
++++ b/drivers/char/watchdog/eurotechwdt.c
+@@ -153,7 +153,7 @@ static void eurwdt_activate_timer(void)
+ * Kernel methods.
+ */
+
+-static irqreturn_t eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
+ {
+ printk(KERN_CRIT "timeout WDT timeout\n");
+
+@@ -240,7 +240,7 @@ static int eurwdt_ioctl(struct inode *in
+
+ switch(cmd) {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
+index 870539e..fb64df4 100644
+--- a/drivers/char/watchdog/i6300esb.c
++++ b/drivers/char/watchdog/i6300esb.c
+@@ -315,7 +315,7 @@ static int esb_ioctl (struct inode *inod
+ return put_user(heartbeat, p);
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
+index 8385dd3..e0627d7 100644
+--- a/drivers/char/watchdog/i8xx_tco.c
++++ b/drivers/char/watchdog/i8xx_tco.c
+@@ -356,7 +356,7 @@ static int i8xx_tco_ioctl (struct inode
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+@@ -406,18 +406,18 @@ static struct notifier_block i8xx_tco_no
+ * want to register another driver on the same PCI id.
+ */
+ static struct pci_device_id i8xx_tco_pci_tbl[] = {
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, },
+- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, },
+- { 0, }, /* End of list */
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) },
++ { 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_82801E_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1) },
++ { }, /* End of list */
+ };
+ MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
+
+@@ -434,12 +434,11 @@ static unsigned char __init i8xx_tco_get
+ * Find the PCI device
+ */
+
+- while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
++ for_each_pci_dev(dev)
+ if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
+ i8xx_tco_pci = dev;
+ break;
+ }
+- }
+
+ if (i8xx_tco_pci) {
+ /*
+@@ -454,6 +453,7 @@ static unsigned char __init i8xx_tco_get
+ /* Something's wrong here, ACPIBASE has to be set */
+ if (badr == 0x0001 || badr == 0x0000) {
+ printk (KERN_ERR PFX "failed to get TCOBASE address\n");
++ pci_dev_put(i8xx_tco_pci);
+ return 0;
+ }
+
+@@ -465,6 +465,7 @@ static unsigned char __init i8xx_tco_get
+ pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
+ if (val1 & 0x02) {
+ printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
++ pci_dev_put(i8xx_tco_pci);
+ return 0; /* Cannot reset NO_REBOOT bit */
+ }
+ }
+@@ -476,6 +477,7 @@ static unsigned char __init i8xx_tco_get
+ if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
+ printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ SMI_EN + 1);
++ pci_dev_put(i8xx_tco_pci);
+ return 0;
+ }
+ val1 = inb (SMI_EN + 1);
+@@ -542,6 +544,7 @@ unreg_notifier:
+ unreg_region:
+ release_region (TCOBASE, 0x10);
+ out:
++ pci_dev_put(i8xx_tco_pci);
+ return ret;
+ }
+
+@@ -555,6 +558,8 @@ static void __exit watchdog_cleanup (voi
+ misc_deregister (&i8xx_tco_miscdev);
+ unregister_reboot_notifier(&i8xx_tco_notifier);
+ release_region (TCOBASE, 0x10);
++
++ pci_dev_put(i8xx_tco_pci);
+ }
+
+ module_init(watchdog_init);
+diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
+new file mode 100644
+index 0000000..b6f29cb
+--- /dev/null
++++ b/drivers/char/watchdog/iTCO_wdt.c
+@@ -0,0 +1,749 @@
++/*
++ * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
++ *
++ * (c) Copyright 2006 Wim Van Sebroeck <wim at iguana.be>.
++ *
++ * 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.
++ *
++ * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
++ * provide warranty for any of this software. This material is
++ * provided "AS-IS" and at no charge.
++ *
++ * The TCO watchdog is implemented in the following I/O controller hubs:
++ * (See the intel documentation on http://developer.intel.com.)
++ * 82801AA (ICH) : document number 290655-003, 290677-014,
++ * 82801AB (ICHO) : document number 290655-003, 290677-014,
++ * 82801BA (ICH2) : document number 290687-002, 298242-027,
++ * 82801BAM (ICH2-M) : document number 290687-002, 298242-027,
++ * 82801CA (ICH3-S) : document number 290733-003, 290739-013,
++ * 82801CAM (ICH3-M) : document number 290716-001, 290718-007,
++ * 82801DB (ICH4) : document number 290744-001, 290745-020,
++ * 82801DBM (ICH4-M) : document number 252337-001, 252663-005,
++ * 82801E (C-ICH) : document number 273599-001, 273645-002,
++ * 82801EB (ICH5) : document number 252516-001, 252517-003,
++ * 82801ER (ICH5R) : document number 252516-001, 252517-003,
++ * 82801FB (ICH6) : document number 301473-002, 301474-007,
++ * 82801FR (ICH6R) : document number 301473-002, 301474-007,
++ * 82801FBM (ICH6-M) : document number 301473-002, 301474-007,
++ * 82801FW (ICH6W) : document number 301473-001, 301474-007,
++ * 82801FRW (ICH6RW) : document number 301473-001, 301474-007,
++ * 82801GB (ICH7) : document number 307013-002, 307014-009,
++ * 82801GR (ICH7R) : document number 307013-002, 307014-009,
++ * 82801GDH (ICH7DH) : document number 307013-002, 307014-009,
++ * 82801GBM (ICH7-M) : document number 307013-002, 307014-009,
++ * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
++ * 82801HB (ICH8) : document number 313056-002, 313057-004,
++ * 82801HR (ICH8R) : document number 313056-002, 313057-004,
++ * 82801HH (ICH8DH) : document number 313056-002, 313057-004,
++ * 82801HO (ICH8DO) : document number 313056-002, 313057-004,
++ * 6300ESB (6300ESB) : document number 300641-003
++ */
++
++/*
++ * Includes, defines, variables, module parameters, ...
++ */
++
++/* Module and version information */
++#define DRV_NAME "iTCO_wdt"
++#define DRV_VERSION "1.00"
++#define DRV_RELDATE "08-Oct-2006"
++#define PFX DRV_NAME ": "
++
++/* Includes */
++#include <linux/module.h> /* For module specific items */
++#include <linux/moduleparam.h> /* For new moduleparam's */
++#include <linux/types.h> /* For standard types (like size_t) */
++#include <linux/errno.h> /* For the -ENODEV/... values */
++#include <linux/kernel.h> /* For printk/panic/... */
++#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
++#include <linux/watchdog.h> /* For the watchdog specific items */
++#include <linux/init.h> /* For __init/__exit/... */
++#include <linux/fs.h> /* For file operations */
++#include <linux/platform_device.h> /* For platform_driver framework */
++#include <linux/pci.h> /* For pci functions */
++#include <linux/ioport.h> /* For io-port access */
++#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
++
++#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
++#include <asm/io.h> /* For inb/outb/... */
++
++/* TCO related info */
++enum iTCO_chipsets {
++ TCO_ICH = 0, /* ICH */
++ TCO_ICH0, /* ICH0 */
++ TCO_ICH2, /* ICH2 */
++ TCO_ICH2M, /* ICH2-M */
++ TCO_ICH3, /* ICH3-S */
++ TCO_ICH3M, /* ICH3-M */
++ TCO_ICH4, /* ICH4 */
++ TCO_ICH4M, /* ICH4-M */
++ TCO_CICH, /* C-ICH */
++ TCO_ICH5, /* ICH5 & ICH5R */
++ TCO_6300ESB, /* 6300ESB */
++ TCO_ICH6, /* ICH6 & ICH6R */
++ TCO_ICH6M, /* ICH6-M */
++ TCO_ICH6W, /* ICH6W & ICH6RW */
++ TCO_ICH7, /* ICH7 & ICH7R */
++ TCO_ICH7M, /* ICH7-M */
++ TCO_ICH7MDH, /* ICH7-M DH */
++ TCO_ICH8, /* ICH8 & ICH8R */
++ TCO_ICH8DH, /* ICH8DH */
++ TCO_ICH8DO, /* ICH8DO */
++};
++
++static struct {
++ char *name;
++ unsigned int iTCO_version;
++} iTCO_chipset_info[] __devinitdata = {
++ {"ICH", 1},
++ {"ICH0", 1},
++ {"ICH2", 1},
++ {"ICH2-M", 1},
++ {"ICH3-S", 1},
++ {"ICH3-M", 1},
++ {"ICH4", 1},
++ {"ICH4-M", 1},
++ {"C-ICH", 1},
++ {"ICH5 or ICH5R", 1},
++ {"6300ESB", 1},
++ {"ICH6 or ICH6R", 2},
++ {"ICH6-M", 2},
++ {"ICH6W or ICH6RW", 2},
++ {"ICH7 or ICH7R", 2},
++ {"ICH7-M", 2},
++ {"ICH7-M DH", 2},
++ {"ICH8 or ICH8R", 2},
++ {"ICH8DH", 2},
++ {"ICH8DO", 2},
++ {NULL,0}
++};
++
++/*
++ * This data only exists for exporting the supported PCI ids
++ * via MODULE_DEVICE_TABLE. We do not actually register a
++ * pci_driver, because the I/O Controller Hub has also other
++ * functions that probably will be registered by other drivers.
++ */
++static struct pci_device_id iTCO_wdt_pci_tbl[] = {
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
++ { 0, }, /* End of list */
++};
++MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
++
++/* Address definitions for the TCO */
++#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */
++#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */
++
++#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
++#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */
++#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
++#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
++#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
++#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
++#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
++#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
++#define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */
++
++/* internal variables */
++static unsigned long is_active;
++static char expect_release;
++static struct { /* this is private data for the iTCO_wdt device */
++ unsigned int iTCO_version; /* TCO version/generation */
++ unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
++ unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */
++ spinlock_t io_lock; /* the lock for io operations */
++ struct pci_dev *pdev; /* the PCI-device */
++} iTCO_wdt_private;
++
++static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */
++
++/* module parameters */
++#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
++static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
++module_param(heartbeat, int, 0);
++MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
++
++/*
++ * Some TCO specific functions
++ */
++
++static inline unsigned int seconds_to_ticks(int seconds)
++{
++ /* the internal timer is stored as ticks which decrement
++ * every 0.6 seconds */
++ return (seconds * 10) / 6;
++}
++
++static void iTCO_wdt_set_NO_REBOOT_bit(void)
++{
++ u32 val32;
++
++ /* Set the NO_REBOOT bit: this disables reboots */
++ if (iTCO_wdt_private.iTCO_version == 2) {
++ val32 = readl(iTCO_wdt_private.gcs);
++ val32 |= 0x00000020;
++ writel(val32, iTCO_wdt_private.gcs);
++ } else if (iTCO_wdt_private.iTCO_version == 1) {
++ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
++ val32 |= 0x00000002;
++ pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
++ }
++}
++
++static int iTCO_wdt_unset_NO_REBOOT_bit(void)
++{
++ int ret = 0;
++ u32 val32;
++
++ /* Unset the NO_REBOOT bit: this enables reboots */
++ if (iTCO_wdt_private.iTCO_version == 2) {
++ val32 = readl(iTCO_wdt_private.gcs);
++ val32 &= 0xffffffdf;
++ writel(val32, iTCO_wdt_private.gcs);
++
++ val32 = readl(iTCO_wdt_private.gcs);
++ if (val32 & 0x00000020)
++ ret = -EIO;
++ } else if (iTCO_wdt_private.iTCO_version == 1) {
++ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
++ val32 &= 0xfffffffd;
++ pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
++
++ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
++ if (val32 & 0x00000002)
++ ret = -EIO;
++ }
++
++ return ret; /* returns: 0 = OK, -EIO = Error */
++}
++
++static int iTCO_wdt_start(void)
++{
++ unsigned int val;
++
++ spin_lock(&iTCO_wdt_private.io_lock);
++
++ /* disable chipset's NO_REBOOT bit */
++ if (iTCO_wdt_unset_NO_REBOOT_bit()) {
++ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
++ return -EIO;
++ }
++
++ /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
++ val = inw(TCO1_CNT);
++ val &= 0xf7ff;
++ outw(val, TCO1_CNT);
++ val = inw(TCO1_CNT);
++ spin_unlock(&iTCO_wdt_private.io_lock);
++
++ if (val & 0x0800)
++ return -1;
++ return 0;
++}
++
++static int iTCO_wdt_stop(void)
++{
++ unsigned int val;
++
++ spin_lock(&iTCO_wdt_private.io_lock);
++
++ /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
++ val = inw(TCO1_CNT);
++ val |= 0x0800;
++ outw(val, TCO1_CNT);
++ val = inw(TCO1_CNT);
++
++ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
++ iTCO_wdt_set_NO_REBOOT_bit();
++
++ spin_unlock(&iTCO_wdt_private.io_lock);
++
++ if ((val & 0x0800) == 0)
++ return -1;
++ return 0;
++}
++
++static int iTCO_wdt_keepalive(void)
++{
++ spin_lock(&iTCO_wdt_private.io_lock);
++
++ /* Reload the timer by writing to the TCO Timer Counter register */
++ if (iTCO_wdt_private.iTCO_version == 2) {
++ outw(0x01, TCO_RLD);
++ } else if (iTCO_wdt_private.iTCO_version == 1) {
++ outb(0x01, TCO_RLD);
++ }
++
++ spin_unlock(&iTCO_wdt_private.io_lock);
++ return 0;
++}
++
++static int iTCO_wdt_set_heartbeat(int t)
++{
++ unsigned int val16;
++ unsigned char val8;
++ unsigned int tmrval;
++
++ tmrval = seconds_to_ticks(t);
++ /* from the specs: */
++ /* "Values of 0h-3h are ignored and should not be attempted" */
++ if (tmrval < 0x04)
++ return -EINVAL;
++ if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
++ ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
++ return -EINVAL;
++
++ /* Write new heartbeat to watchdog */
++ if (iTCO_wdt_private.iTCO_version == 2) {
++ spin_lock(&iTCO_wdt_private.io_lock);
++ val16 = inw(TCOv2_TMR);
++ val16 &= 0xfc00;
++ val16 |= tmrval;
++ outw(val16, TCOv2_TMR);
++ val16 = inw(TCOv2_TMR);
++ spin_unlock(&iTCO_wdt_private.io_lock);
++
++ if ((val16 & 0x3ff) != tmrval)
++ return -EINVAL;
++ } else if (iTCO_wdt_private.iTCO_version == 1) {
++ spin_lock(&iTCO_wdt_private.io_lock);
++ val8 = inb(TCOv1_TMR);
++ val8 &= 0xc0;
++ val8 |= (tmrval & 0xff);
++ outb(val8, TCOv1_TMR);
++ val8 = inb(TCOv1_TMR);
++ spin_unlock(&iTCO_wdt_private.io_lock);
++
++ if ((val8 & 0x3f) != tmrval)
++ return -EINVAL;
++ }
++
++ heartbeat = t;
++ return 0;
++}
++
++static int iTCO_wdt_get_timeleft (int *time_left)
++{
++ unsigned int val16;
++ unsigned char val8;
++
++ /* read the TCO Timer */
++ if (iTCO_wdt_private.iTCO_version == 2) {
++ spin_lock(&iTCO_wdt_private.io_lock);
++ val16 = inw(TCO_RLD);
++ val16 &= 0x3ff;
++ spin_unlock(&iTCO_wdt_private.io_lock);
++
++ *time_left = (val16 * 6) / 10;
++ } else if (iTCO_wdt_private.iTCO_version == 1) {
++ spin_lock(&iTCO_wdt_private.io_lock);
++ val8 = inb(TCO_RLD);
++ val8 &= 0x3f;
++ spin_unlock(&iTCO_wdt_private.io_lock);
++
++ *time_left = (val8 * 6) / 10;
++ } else
++ return -EINVAL;
++ return 0;
++}
++
++/*
++ * /dev/watchdog handling
++ */
++
++static int iTCO_wdt_open (struct inode *inode, struct file *file)
++{
++ /* /dev/watchdog can only be opened once */
++ if (test_and_set_bit(0, &is_active))
++ return -EBUSY;
++
++ /*
++ * Reload and activate timer
++ */
++ iTCO_wdt_keepalive();
++ iTCO_wdt_start();
++ return nonseekable_open(inode, file);
++}
++
++static int iTCO_wdt_release (struct inode *inode, struct file *file)
++{
++ /*
++ * Shut off the timer.
++ */
++ if (expect_release == 42) {
++ iTCO_wdt_stop();
++ } else {
++ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
++ iTCO_wdt_keepalive();
++ }
++ clear_bit(0, &is_active);
++ expect_release = 0;
++ return 0;
++}
++
++static ssize_t iTCO_wdt_write (struct file *file, const char __user *data,
++ size_t len, loff_t * ppos)
++{
++ /* See if we got the magic character 'V' and reload the timer */
++ if (len) {
++ if (!nowayout) {
++ size_t i;
++
++ /* note: just in case someone wrote the magic character
++ * five months ago... */
++ expect_release = 0;
++
++ /* scan to see whether or not we got the magic character */
++ for (i = 0; i != len; i++) {
++ char c;
++ if (get_user(c, data+i))
++ return -EFAULT;
++ if (c == 'V')
++ expect_release = 42;
++ }
++ }
++
++ /* someone wrote to us, we should reload the timer */
++ iTCO_wdt_keepalive();
++ }
++ return len;
++}
++
++static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int new_options, retval = -EINVAL;
++ int new_heartbeat;
++ void __user *argp = (void __user *)arg;
++ int __user *p = argp;
++ static struct watchdog_info ident = {
++ .options = WDIOF_SETTIMEOUT |
++ WDIOF_KEEPALIVEPING |
++ WDIOF_MAGICCLOSE,
++ .firmware_version = 0,
++ .identity = DRV_NAME,
++ };
++
++ switch (cmd) {
++ case WDIOC_GETSUPPORT:
++ return copy_to_user(argp, &ident,
++ sizeof (ident)) ? -EFAULT : 0;
++
++ case WDIOC_GETSTATUS:
++ case WDIOC_GETBOOTSTATUS:
++ return put_user(0, p);
++
++ case WDIOC_KEEPALIVE:
++ iTCO_wdt_keepalive();
++ return 0;
++
++ case WDIOC_SETOPTIONS:
++ {
++ if (get_user(new_options, p))
++ return -EFAULT;
++
++ if (new_options & WDIOS_DISABLECARD) {
++ iTCO_wdt_stop();
++ retval = 0;
++ }
++
++ if (new_options & WDIOS_ENABLECARD) {
++ iTCO_wdt_keepalive();
++ iTCO_wdt_start();
++ retval = 0;
++ }
++
++ return retval;
++ }
++
++ case WDIOC_SETTIMEOUT:
++ {
++ if (get_user(new_heartbeat, p))
++ return -EFAULT;
++
++ if (iTCO_wdt_set_heartbeat(new_heartbeat))
++ return -EINVAL;
++
++ iTCO_wdt_keepalive();
++ /* Fall */
++ }
++
++ case WDIOC_GETTIMEOUT:
++ return put_user(heartbeat, p);
++
++ case WDIOC_GETTIMELEFT:
++ {
++ int time_left;
++
++ if (iTCO_wdt_get_timeleft(&time_left))
++ return -EINVAL;
++
++ return put_user(time_left, p);
++ }
++
++ default:
++ return -ENOTTY;
++ }
++}
++
++/*
++ * Kernel Interfaces
++ */
++
++static struct file_operations iTCO_wdt_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = iTCO_wdt_write,
++ .ioctl = iTCO_wdt_ioctl,
++ .open = iTCO_wdt_open,
++ .release = iTCO_wdt_release,
++};
++
++static struct miscdevice iTCO_wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &iTCO_wdt_fops,
++};
++
++/*
++ * Init & exit routines
++ */
++
++static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev)
++{
++ int ret;
++ u32 base_address;
++ unsigned long RCBA;
++ unsigned long val32;
++
++ /*
++ * Find the ACPI/PM base I/O address which is the base
++ * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
++ * ACPIBASE is bits [15:7] from 0x40-0x43
++ */
++ pci_read_config_dword(pdev, 0x40, &base_address);
++ base_address &= 0x00007f80;
++ if (base_address == 0x00000000) {
++ /* Something's wrong here, ACPIBASE has to be set */
++ printk(KERN_ERR PFX "failed to get TCOBASE address\n");
++ pci_dev_put(pdev);
++ return -ENODEV;
++ }
++ iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version;
++ iTCO_wdt_private.ACPIBASE = base_address;
++ iTCO_wdt_private.pdev = pdev;
++
++ /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */
++ /* To get access to it you have to read RCBA from PCI Config space 0xf0
++ and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */
++ if (iTCO_wdt_private.iTCO_version == 2) {
++ pci_read_config_dword(pdev, 0xf0, &base_address);
++ RCBA = base_address & 0xffffc000;
++ iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4);
++ }
++
++ /* Check chipset's NO_REBOOT bit */
++ if (iTCO_wdt_unset_NO_REBOOT_bit()) {
++ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
++ ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
++ goto out;
++ }
++
++ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
++ iTCO_wdt_set_NO_REBOOT_bit();
++
++ /* Set the TCO_EN bit in SMI_EN register */
++ if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
++ printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
++ SMI_EN );
++ ret = -EIO;
++ goto out;
++ }
++ val32 = inl(SMI_EN);
++ val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
++ outl(val32, SMI_EN);
++ release_region(SMI_EN, 4);
++
++ /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */
++ if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) {
++ printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n",
++ TCOBASE);
++ ret = -EIO;
++ goto out;
++ }
++
++ printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
++ iTCO_chipset_info[ent->driver_data].name,
++ iTCO_chipset_info[ent->driver_data].iTCO_version,
++ TCOBASE);
++
++ /* Clear out the (probably old) status */
++ outb(0, TCO1_STS);
++ outb(3, TCO2_STS);
++
++ /* Make sure the watchdog is not running */
++ iTCO_wdt_stop();
++
++ /* Check that the heartbeat value is within it's range ; if not reset to the default */
++ if (iTCO_wdt_set_heartbeat(heartbeat)) {
++ iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
++ printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n",
++ heartbeat);
++ }
++
++ ret = misc_register(&iTCO_wdt_miscdev);
++ if (ret != 0) {
++ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++ WATCHDOG_MINOR, ret);
++ goto unreg_region;
++ }
++
++ printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
++ heartbeat, nowayout);
++
++ return 0;
++
++unreg_region:
++ release_region (TCOBASE, 0x20);
++out:
++ if (iTCO_wdt_private.iTCO_version == 2)
++ iounmap(iTCO_wdt_private.gcs);
++ pci_dev_put(iTCO_wdt_private.pdev);
++ iTCO_wdt_private.ACPIBASE = 0;
++ return ret;
++}
++
++static void iTCO_wdt_cleanup(void)
++{
++ /* Stop the timer before we leave */
++ if (!nowayout)
++ iTCO_wdt_stop();
++
++ /* Deregister */
++ misc_deregister(&iTCO_wdt_miscdev);
++ release_region(TCOBASE, 0x20);
++ if (iTCO_wdt_private.iTCO_version == 2)
++ iounmap(iTCO_wdt_private.gcs);
++ pci_dev_put(iTCO_wdt_private.pdev);
++ iTCO_wdt_private.ACPIBASE = 0;
++}
++
++static int iTCO_wdt_probe(struct platform_device *dev)
++{
++ int found = 0;
++ struct pci_dev *pdev = NULL;
++ const struct pci_device_id *ent;
++
++ spin_lock_init(&iTCO_wdt_private.io_lock);
++
++ for_each_pci_dev(pdev) {
++ ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
++ if (ent) {
++ if (!(iTCO_wdt_init(pdev, ent, dev))) {
++ found++;
++ break;
++ }
++ }
++ }
++
++ if (!found) {
++ printk(KERN_INFO PFX "No card detected\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int iTCO_wdt_remove(struct platform_device *dev)
++{
++ if (iTCO_wdt_private.ACPIBASE)
++ iTCO_wdt_cleanup();
++
++ return 0;
++}
++
++static void iTCO_wdt_shutdown(struct platform_device *dev)
++{
++ iTCO_wdt_stop();
++}
++
++#define iTCO_wdt_suspend NULL
++#define iTCO_wdt_resume NULL
++
++static struct platform_driver iTCO_wdt_driver = {
++ .probe = iTCO_wdt_probe,
++ .remove = iTCO_wdt_remove,
++ .shutdown = iTCO_wdt_shutdown,
++ .suspend = iTCO_wdt_suspend,
++ .resume = iTCO_wdt_resume,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = DRV_NAME,
++ },
++};
++
++static int __init iTCO_wdt_init_module(void)
++{
++ int err;
++
++ printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n",
++ DRV_VERSION, DRV_RELDATE);
++
++ err = platform_driver_register(&iTCO_wdt_driver);
++ if (err)
++ return err;
++
++ iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
++ if (IS_ERR(iTCO_wdt_platform_device)) {
++ err = PTR_ERR(iTCO_wdt_platform_device);
++ goto unreg_platform_driver;
++ }
++
++ return 0;
++
++unreg_platform_driver:
++ platform_driver_unregister(&iTCO_wdt_driver);
++ return err;
++}
++
++static void __exit iTCO_wdt_cleanup_module(void)
++{
++ platform_device_unregister(iTCO_wdt_platform_device);
++ platform_driver_unregister(&iTCO_wdt_driver);
++ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
++}
++
++module_init(iTCO_wdt_init_module);
++module_exit(iTCO_wdt_cleanup_module);
++
++MODULE_AUTHOR("Wim Van Sebroeck <wim at iguana.be>");
++MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
++MODULE_VERSION(DRV_VERSION);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
+index fd95f73..c1ed209 100644
+--- a/drivers/char/watchdog/ib700wdt.c
++++ b/drivers/char/watchdog/ib700wdt.c
+@@ -199,7 +199,7 @@ ibwdt_ioctl(struct inode *inode, struct
+ break;
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ return 0;
+ }
+diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
+index 26ceee7..dd6760f 100644
+--- a/drivers/char/watchdog/ibmasr.c
++++ b/drivers/char/watchdog/ibmasr.c
+@@ -295,7 +295,7 @@ static int asr_ioctl(struct inode *inode
+ }
+ }
+
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ static int asr_open(struct inode *inode, struct file *file)
+diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
+index dacc1c2..0bc2393 100644
+--- a/drivers/char/watchdog/indydog.c
++++ b/drivers/char/watchdog/indydog.c
+@@ -112,7 +112,7 @@ static int indydog_ioctl(struct inode *i
+
+ switch (cmd) {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((struct watchdog_info *)arg,
+ &ident, sizeof(ident)))
+diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
+index 6929088..fd955db 100644
+--- a/drivers/char/watchdog/ixp2000_wdt.c
++++ b/drivers/char/watchdog/ixp2000_wdt.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/watchdog/ixp2000_wdt.c
++ * drivers/char/watchdog/ixp2000_wdt.c
+ *
+ * Watchdog driver for Intel IXP2000 network processors
+ *
+@@ -107,7 +107,7 @@ static int
+ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+ {
+- int ret = -ENOIOCTLCMD;
++ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
+index 9db5cf2..5864bb8 100644
+--- a/drivers/char/watchdog/ixp4xx_wdt.c
++++ b/drivers/char/watchdog/ixp4xx_wdt.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/watchdog/ixp4xx_wdt.c
++ * drivers/char/watchdog/ixp4xx_wdt.c
+ *
+ * Watchdog driver for Intel IXP4xx network processors
+ *
+@@ -102,7 +102,7 @@ static int
+ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+ {
+- int ret = -ENOIOCTLCMD;
++ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
+index 23734e0..276577d 100644
+--- a/drivers/char/watchdog/machzwd.c
++++ b/drivers/char/watchdog/machzwd.c
+@@ -329,7 +329,7 @@ static int zf_ioctl(struct inode *inode,
+ break;
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ return 0;
+@@ -426,8 +426,7 @@ static int __init zf_init(void)
+ printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
+
+ ret = zf_get_ZFL_version();
+- printk("%#x\n", ret);
+- if((!ret) || (ret != 0xffff)){
++ if ((!ret) || (ret == 0xffff)) {
+ printk(KERN_WARNING PFX ": no ZF-Logic found\n");
+ return -ENODEV;
+ }
+diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
+index ae94332..c2dac0a 100644
+--- a/drivers/char/watchdog/mixcomwd.c
++++ b/drivers/char/watchdog/mixcomwd.c
+@@ -185,7 +185,7 @@ static int mixcomwd_ioctl(struct inode *
+ mixcomwd_ping();
+ break;
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ return 0;
+ }
+diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
+index a480903..18ca752 100644
+--- a/drivers/char/watchdog/mpc83xx_wdt.c
++++ b/drivers/char/watchdog/mpc83xx_wdt.c
+@@ -125,7 +125,7 @@ static int mpc83xx_wdt_ioctl(struct inod
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout_sec, p);
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
+index 35dd9e6..8aaed10 100644
+--- a/drivers/char/watchdog/mpc8xx_wdt.c
++++ b/drivers/char/watchdog/mpc8xx_wdt.c
+@@ -126,7 +126,7 @@ static int mpc8xx_wdt_ioctl(struct inode
+ break;
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ return 0;
+diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
+index 54b3c56..3404a9c 100644
+--- a/drivers/char/watchdog/mpcore_wdt.c
++++ b/drivers/char/watchdog/mpcore_wdt.c
+@@ -64,7 +64,7 @@ MODULE_PARM_DESC(mpcore_noboot, "MPcore
+ * This is the interrupt handler. Note that we only use this
+ * in testing mode, so don't actually do a reboot here.
+ */
+-static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
+ {
+ struct mpcore_wdt *wdt = arg;
+
+@@ -221,7 +221,7 @@ static int mpcore_wdt_ioctl(struct inode
+ } uarg;
+
+ if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
+@@ -271,7 +271,7 @@ static int mpcore_wdt_ioctl(struct inode
+ break;
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
+index 5c8fab3..b887cdb 100644
+--- a/drivers/char/watchdog/mv64x60_wdt.c
++++ b/drivers/char/watchdog/mv64x60_wdt.c
+@@ -160,7 +160,7 @@ static int mv64x60_wdt_ioctl(struct inod
+ break;
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ return 0;
+diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
+new file mode 100644
+index 0000000..5dbd7dc
+--- /dev/null
++++ b/drivers/char/watchdog/omap_wdt.c
+@@ -0,0 +1,390 @@
++/*
++ * linux/drivers/char/watchdog/omap_wdt.c
++ *
++ * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
++ *
++ * Author: MontaVista Software, Inc.
++ * <gdavis at mvista.com> or <source at mvista.com>
++ *
++ * 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.
++ *
++ * History:
++ *
++ * 20030527: George G. Davis <gdavis at mvista.com>
++ * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
++ * (c) Copyright 2000 Oleg Drokin <green at crimea.edu>
++ * Based on SoftDog driver by Alan Cox <alan at redhat.com>
++ *
++ * Copyright (c) 2004 Texas Instruments.
++ * 1. Modified to support OMAP1610 32-KHz watchdog timer
++ * 2. Ported to 2.6 kernel
++ *
++ * Copyright (c) 2005 David Brownell
++ * Use the driver model and standard identifiers; handle bigger timeouts.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/moduleparam.h>
++#include <linux/clk.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/bitops.h>
++
++#include <asm/arch/prcm.h>
++
++#include "omap_wdt.h"
++
++static unsigned timer_margin;
++module_param(timer_margin, uint, 0);
++MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
++
++static int omap_wdt_users;
++static struct clk *armwdt_ck = NULL;
++static struct clk *mpu_wdt_ick = NULL;
++static struct clk *mpu_wdt_fck = NULL;
++
++static unsigned int wdt_trgr_pattern = 0x1234;
++
++static void omap_wdt_ping(void)
++{
++ /* wait for posted write to complete */
++ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
++ cpu_relax();
++ wdt_trgr_pattern = ~wdt_trgr_pattern;
++ omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
++ /* wait for posted write to complete */
++ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
++ cpu_relax();
++ /* reloaded WCRR from WLDR */
++}
++
++static void omap_wdt_enable(void)
++{
++ /* Sequence to enable the watchdog */
++ omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
++ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
++ cpu_relax();
++ omap_writel(0x4444, OMAP_WATCHDOG_SPR);
++ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
++ cpu_relax();
++}
++
++static void omap_wdt_disable(void)
++{
++ /* sequence required to disable watchdog */
++ omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
++ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
++ cpu_relax();
++ omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
++ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
++ cpu_relax();
++}
++
++static void omap_wdt_adjust_timeout(unsigned new_timeout)
++{
++ if (new_timeout < TIMER_MARGIN_MIN)
++ new_timeout = TIMER_MARGIN_DEFAULT;
++ if (new_timeout > TIMER_MARGIN_MAX)
++ new_timeout = TIMER_MARGIN_MAX;
++ timer_margin = new_timeout;
++}
++
++static void omap_wdt_set_timeout(void)
++{
++ u32 pre_margin = GET_WLDR_VAL(timer_margin);
++
++ /* just count up at 32 KHz */
++ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
++ cpu_relax();
++ omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
++ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
++ cpu_relax();
++}
++
++/*
++ * Allow only one task to hold it open
++ */
++
++static int omap_wdt_open(struct inode *inode, struct file *file)
++{
++ if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
++ return -EBUSY;
++
++ if (cpu_is_omap16xx())
++ clk_enable(armwdt_ck); /* Enable the clock */
++
++ if (cpu_is_omap24xx()) {
++ clk_enable(mpu_wdt_ick); /* Enable the interface clock */
++ clk_enable(mpu_wdt_fck); /* Enable the functional clock */
++ }
++
++ /* initialize prescaler */
++ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
++ cpu_relax();
++ omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
++ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
++ cpu_relax();
++
++ omap_wdt_set_timeout();
++ omap_wdt_enable();
++ return 0;
++}
++
++static int omap_wdt_release(struct inode *inode, struct file *file)
++{
++ /*
++ * Shut off the timer unless NOWAYOUT is defined.
++ */
++#ifndef CONFIG_WATCHDOG_NOWAYOUT
++ omap_wdt_disable();
++
++ if (cpu_is_omap16xx()) {
++ clk_disable(armwdt_ck); /* Disable the clock */
++ clk_put(armwdt_ck);
++ armwdt_ck = NULL;
++ }
++
++ if (cpu_is_omap24xx()) {
++ clk_disable(mpu_wdt_ick); /* Disable the clock */
++ clk_disable(mpu_wdt_fck); /* Disable the clock */
++ clk_put(mpu_wdt_ick);
++ clk_put(mpu_wdt_fck);
++ mpu_wdt_ick = NULL;
++ mpu_wdt_fck = NULL;
++ }
++#else
++ printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
++#endif
++ omap_wdt_users = 0;
++ return 0;
++}
++
++static ssize_t
++omap_wdt_write(struct file *file, const char __user *data,
++ size_t len, loff_t *ppos)
++{
++ /* Refresh LOAD_TIME. */
++ if (len)
++ omap_wdt_ping();
++ return len;
++}
++
++static int
++omap_wdt_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int new_margin;
++ static struct watchdog_info ident = {
++ .identity = "OMAP Watchdog",
++ .options = WDIOF_SETTIMEOUT,
++ .firmware_version = 0,
++ };
++
++ switch (cmd) {
++ default:
++ return -ENOIOCTLCMD;
++ case WDIOC_GETSUPPORT:
++ return copy_to_user((struct watchdog_info __user *)arg, &ident,
++ sizeof(ident));
++ case WDIOC_GETSTATUS:
++ return put_user(0, (int __user *)arg);
++ case WDIOC_GETBOOTSTATUS:
++ if (cpu_is_omap16xx())
++ return put_user(omap_readw(ARM_SYSST),
++ (int __user *)arg);
++ if (cpu_is_omap24xx())
++ return put_user(omap_prcm_get_reset_sources(),
++ (int __user *)arg);
++ case WDIOC_KEEPALIVE:
++ omap_wdt_ping();
++ return 0;
++ case WDIOC_SETTIMEOUT:
++ if (get_user(new_margin, (int __user *)arg))
++ return -EFAULT;
++ omap_wdt_adjust_timeout(new_margin);
++
++ omap_wdt_disable();
++ omap_wdt_set_timeout();
++ omap_wdt_enable();
++
++ omap_wdt_ping();
++ /* Fall */
++ case WDIOC_GETTIMEOUT:
++ return put_user(timer_margin, (int __user *)arg);
++ }
++}
++
++static struct file_operations omap_wdt_fops = {
++ .owner = THIS_MODULE,
++ .write = omap_wdt_write,
++ .ioctl = omap_wdt_ioctl,
++ .open = omap_wdt_open,
++ .release = omap_wdt_release,
++};
++
++static struct miscdevice omap_wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &omap_wdt_fops
++};
++
++static int __init omap_wdt_probe(struct platform_device *pdev)
++{
++ struct resource *res, *mem;
++ int ret;
++
++ /* reserve static register mappings */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -ENOENT;
++
++ mem = request_mem_region(res->start, res->end - res->start + 1,
++ pdev->name);
++ if (mem == NULL)
++ return -EBUSY;
++
++ platform_set_drvdata(pdev, mem);
++
++ omap_wdt_users = 0;
++
++ if (cpu_is_omap16xx()) {
++ armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
++ if (IS_ERR(armwdt_ck)) {
++ ret = PTR_ERR(armwdt_ck);
++ armwdt_ck = NULL;
++ goto fail;
++ }
++ }
++
++ if (cpu_is_omap24xx()) {
++ mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
++ if (IS_ERR(mpu_wdt_ick)) {
++ ret = PTR_ERR(mpu_wdt_ick);
++ mpu_wdt_ick = NULL;
++ goto fail;
++ }
++ mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
++ if (IS_ERR(mpu_wdt_fck)) {
++ ret = PTR_ERR(mpu_wdt_fck);
++ mpu_wdt_fck = NULL;
++ goto fail;
++ }
++ }
++
++ omap_wdt_disable();
++ omap_wdt_adjust_timeout(timer_margin);
++
++ omap_wdt_miscdev.dev = &pdev->dev;
++ ret = misc_register(&omap_wdt_miscdev);
++ if (ret)
++ goto fail;
++
++ pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
++
++ /* autogate OCP interface clock */
++ omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
++ return 0;
++
++fail:
++ if (armwdt_ck)
++ clk_put(armwdt_ck);
++ if (mpu_wdt_ick)
++ clk_put(mpu_wdt_ick);
++ if (mpu_wdt_fck)
++ clk_put(mpu_wdt_fck);
++ release_resource(mem);
++ return ret;
++}
++
++static void omap_wdt_shutdown(struct platform_device *pdev)
++{
++ omap_wdt_disable();
++}
++
++static int omap_wdt_remove(struct platform_device *pdev)
++{
++ struct resource *mem = platform_get_drvdata(pdev);
++ misc_deregister(&omap_wdt_miscdev);
++ release_resource(mem);
++ if (armwdt_ck)
++ clk_put(armwdt_ck);
++ if (mpu_wdt_ick)
++ clk_put(mpu_wdt_ick);
++ if (mpu_wdt_fck)
++ clk_put(mpu_wdt_fck);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++
++/* REVISIT ... not clear this is the best way to handle system suspend; and
++ * it's very inappropriate for selective device suspend (e.g. suspending this
++ * through sysfs rather than by stopping the watchdog daemon). Also, this
++ * may not play well enough with NOWAYOUT...
++ */
++
++static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ if (omap_wdt_users)
++ omap_wdt_disable();
++ return 0;
++}
++
++static int omap_wdt_resume(struct platform_device *pdev)
++{
++ if (omap_wdt_users) {
++ omap_wdt_enable();
++ omap_wdt_ping();
++ }
++ return 0;
++}
++
++#else
++#define omap_wdt_suspend NULL
++#define omap_wdt_resume NULL
++#endif
++
++static struct platform_driver omap_wdt_driver = {
++ .probe = omap_wdt_probe,
++ .remove = omap_wdt_remove,
++ .shutdown = omap_wdt_shutdown,
++ .suspend = omap_wdt_suspend,
++ .resume = omap_wdt_resume,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "omap_wdt",
++ },
++};
++
++static int __init omap_wdt_init(void)
++{
++ return platform_driver_register(&omap_wdt_driver);
++}
++
++static void __exit omap_wdt_exit(void)
++{
++ platform_driver_unregister(&omap_wdt_driver);
++}
++
++module_init(omap_wdt_init);
++module_exit(omap_wdt_exit);
++
++MODULE_AUTHOR("George G. Davis");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/char/watchdog/omap_wdt.h b/drivers/char/watchdog/omap_wdt.h
+new file mode 100644
+index 0000000..52a532a
+--- /dev/null
++++ b/drivers/char/watchdog/omap_wdt.h
+@@ -0,0 +1,64 @@
++/*
++ * linux/drivers/char/watchdog/omap_wdt.h
++ *
++ * BRIEF MODULE DESCRIPTION
++ * OMAP Watchdog timer register definitions
++ *
++ * Copyright (C) 2004 Texas Instruments.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS 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.
++ */
++
++#ifndef _OMAP_WATCHDOG_H
++#define _OMAP_WATCHDOG_H
++
++#define OMAP1610_WATCHDOG_BASE 0xfffeb000
++#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
++
++#ifdef CONFIG_ARCH_OMAP24XX
++#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
++#else
++#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
++#define RM_RSTST_WKUP 0
++#endif
++
++#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
++#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
++#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
++#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
++#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
++#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
++#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
++#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
++#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
++
++/* Using the prescaler, the OMAP watchdog could go for many
++ * months before firing. These limits work without scaling,
++ * with the 60 second default assumed by most tools and docs.
++ */
++#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
++#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
++#define TIMER_MARGIN_MIN 1
++
++#define PTV 0 /* prescale */
++#define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
++
++#endif /* _OMAP_WATCHDOG_H */
+diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
+index cd7d1b6..8e1e6e4 100644
+--- a/drivers/char/watchdog/pcwd.c
++++ b/drivers/char/watchdog/pcwd.c
+@@ -49,7 +49,6 @@
+ * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
+ */
+
+-#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+ #include <linux/module.h> /* For module specific items */
+ #include <linux/moduleparam.h> /* For new moduleparam's */
+ #include <linux/types.h> /* For standard types (like size_t) */
+@@ -572,7 +571,7 @@ static int pcwd_ioctl(struct inode *inod
+
+ switch(cmd) {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ if(copy_to_user(argp, &ident, sizeof(ident)))
+diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
+index c7cfd6d..f4872c8 100644
+--- a/drivers/char/watchdog/pcwd_pci.c
++++ b/drivers/char/watchdog/pcwd_pci.c
+@@ -31,7 +31,6 @@
+ * Includes, defines, variables, module parameters, ...
+ */
+
+-#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+ #include <linux/module.h> /* For module specific items */
+ #include <linux/moduleparam.h> /* For new moduleparam's */
+ #include <linux/types.h> /* For standard types (like size_t) */
+@@ -541,7 +540,7 @@ static int pcipcwd_ioctl(struct inode *i
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
+index b7ae73d..bda4533 100644
+--- a/drivers/char/watchdog/pcwd_usb.c
++++ b/drivers/char/watchdog/pcwd_usb.c
+@@ -158,7 +158,7 @@ static struct usb_driver usb_pcwd_driver
+ };
+
+
+-static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs)
++static void usb_pcwd_intr_done(struct urb *urb)
+ {
+ struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context;
+ unsigned char *data = usb_pcwd->intr_buffer;
+@@ -445,7 +445,7 @@ static int usb_pcwd_ioctl(struct inode *
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
+new file mode 100644
+index 0000000..3a55fc6
+--- /dev/null
++++ b/drivers/char/watchdog/pnx4008_wdt.c
+@@ -0,0 +1,361 @@
++/*
++ * drivers/char/watchdog/pnx4008_wdt.c
++ *
++ * Watchdog driver for PNX4008 board
++ *
++ * Authors: Dmitry Chigirev <source at mvista.com>,
++ * Vitaly Wool <vitalywool at gmail.com>
++ * Based on sa1100 driver,
++ * Copyright (C) 2000 Oleg Drokin <green at crimea.edu>
++ *
++ * 2005-2006 (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/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/init.h>
++#include <linux/bitops.h>
++#include <linux/ioport.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/spinlock.h>
++
++#include <asm/hardware.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++
++#define MODULE_NAME "PNX4008-WDT: "
++
++/* WatchDog Timer - Chapter 23 Page 207 */
++
++#define DEFAULT_HEARTBEAT 19
++#define MAX_HEARTBEAT 60
++
++/* Watchdog timer register set definition */
++#define WDTIM_INT(p) ((p) + 0x0)
++#define WDTIM_CTRL(p) ((p) + 0x4)
++#define WDTIM_COUNTER(p) ((p) + 0x8)
++#define WDTIM_MCTRL(p) ((p) + 0xC)
++#define WDTIM_MATCH0(p) ((p) + 0x10)
++#define WDTIM_EMR(p) ((p) + 0x14)
++#define WDTIM_PULSE(p) ((p) + 0x18)
++#define WDTIM_RES(p) ((p) + 0x1C)
++
++/* WDTIM_INT bit definitions */
++#define MATCH_INT 1
++
++/* WDTIM_CTRL bit definitions */
++#define COUNT_ENAB 1
++#define RESET_COUNT (1<<1)
++#define DEBUG_EN (1<<2)
++
++/* WDTIM_MCTRL bit definitions */
++#define MR0_INT 1
++#undef RESET_COUNT0
++#define RESET_COUNT0 (1<<2)
++#define STOP_COUNT0 (1<<2)
++#define M_RES1 (1<<3)
++#define M_RES2 (1<<4)
++#define RESFRC1 (1<<5)
++#define RESFRC2 (1<<6)
++
++/* WDTIM_EMR bit definitions */
++#define EXT_MATCH0 1
++#define MATCH_OUTPUT_HIGH (2<<4) /*a MATCH_CTRL setting */
++
++/* WDTIM_RES bit definitions */
++#define WDOG_RESET 1 /* read only */
++
++#define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++static int heartbeat = DEFAULT_HEARTBEAT;
++
++static spinlock_t io_lock;
++static unsigned long wdt_status;
++#define WDT_IN_USE 0
++#define WDT_OK_TO_CLOSE 1
++#define WDT_REGION_INITED 2
++#define WDT_DEVICE_INITED 3
++
++static unsigned long boot_status;
++
++static struct resource *wdt_mem;
++static void __iomem *wdt_base;
++struct clk *wdt_clk;
++
++static void wdt_enable(void)
++{
++ spin_lock(&io_lock);
++
++ if (wdt_clk)
++ clk_set_rate(wdt_clk, 1);
++
++ /* stop counter, initiate counter reset */
++ __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
++ /*wait for reset to complete. 100% guarantee event */
++ while (__raw_readl(WDTIM_COUNTER(wdt_base)))
++ cpu_relax();
++ /* internal and external reset, stop after that */
++ __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
++ WDTIM_MCTRL(wdt_base));
++ /* configure match output */
++ __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
++ /* clear interrupt, just in case */
++ __raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
++ /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
++ __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
++ __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
++ /*enable counter, stop when debugger active */
++ __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
++
++ spin_unlock(&io_lock);
++}
++
++static void wdt_disable(void)
++{
++ spin_lock(&io_lock);
++
++ __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
++ if (wdt_clk)
++ clk_set_rate(wdt_clk, 0);
++
++ spin_unlock(&io_lock);
++}
++
++static int pnx4008_wdt_open(struct inode *inode, struct file *file)
++{
++ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
++ return -EBUSY;
++
++ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
++
++ wdt_enable();
++
++ return nonseekable_open(inode, file);
++}
++
++static ssize_t
++pnx4008_wdt_write(struct file *file, const char *data, size_t len,
++ loff_t * ppos)
++{
++ /* Can't seek (pwrite) on this device */
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++
++ if (len) {
++ if (!nowayout) {
++ size_t i;
++
++ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
++
++ for (i = 0; i != len; i++) {
++ char c;
++
++ if (get_user(c, data + i))
++ return -EFAULT;
++ if (c == 'V')
++ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
++ }
++ }
++ wdt_enable();
++ }
++
++ return len;
++}
++
++static struct watchdog_info ident = {
++ .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
++ WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
++ .identity = "PNX4008 Watchdog",
++};
++
++static int
++pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -ENOTTY;
++ int time;
++
++ switch (cmd) {
++ case WDIOC_GETSUPPORT:
++ ret = copy_to_user((struct watchdog_info *)arg, &ident,
++ sizeof(ident)) ? -EFAULT : 0;
++ break;
++
++ case WDIOC_GETSTATUS:
++ ret = put_user(0, (int *)arg);
++ break;
++
++ case WDIOC_GETBOOTSTATUS:
++ ret = put_user(boot_status, (int *)arg);
++ break;
++
++ case WDIOC_SETTIMEOUT:
++ ret = get_user(time, (int *)arg);
++ if (ret)
++ break;
++
++ if (time <= 0 || time > MAX_HEARTBEAT) {
++ ret = -EINVAL;
++ break;
++ }
++
++ heartbeat = time;
++ wdt_enable();
++ /* Fall through */
++
++ case WDIOC_GETTIMEOUT:
++ ret = put_user(heartbeat, (int *)arg);
++ break;
++
++ case WDIOC_KEEPALIVE:
++ wdt_enable();
++ ret = 0;
++ break;
++ }
++ return ret;
++}
++
++static int pnx4008_wdt_release(struct inode *inode, struct file *file)
++{
++ if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
++ printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
++
++ wdt_disable();
++ clear_bit(WDT_IN_USE, &wdt_status);
++ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
++
++ return 0;
++}
++
++static struct file_operations pnx4008_wdt_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = pnx4008_wdt_write,
++ .ioctl = pnx4008_wdt_ioctl,
++ .open = pnx4008_wdt_open,
++ .release = pnx4008_wdt_release,
++};
++
++static struct miscdevice pnx4008_wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &pnx4008_wdt_fops,
++};
++
++static int pnx4008_wdt_probe(struct platform_device *pdev)
++{
++ int ret = 0, size;
++ struct resource *res;
++
++ spin_lock_init(&io_lock);
++
++ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
++ heartbeat = DEFAULT_HEARTBEAT;
++
++ printk(KERN_INFO MODULE_NAME
++ "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ printk(KERN_INFO MODULE_NAME
++ "failed to get memory region resouce\n");
++ return -ENOENT;
++ }
++
++ size = res->end - res->start + 1;
++ wdt_mem = request_mem_region(res->start, size, pdev->name);
++
++ if (wdt_mem == NULL) {
++ printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
++ return -ENOENT;
++ }
++ wdt_base = (void __iomem *)IO_ADDRESS(res->start);
++
++ wdt_clk = clk_get(&pdev->dev, "wdt_ck");
++ if (!wdt_clk) {
++ release_resource(wdt_mem);
++ kfree(wdt_mem);
++ goto out;
++ } else
++ clk_set_rate(wdt_clk, 1);
++
++ ret = misc_register(&pnx4008_wdt_miscdev);
++ if (ret < 0) {
++ printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
++ release_resource(wdt_mem);
++ kfree(wdt_mem);
++ clk_set_rate(wdt_clk, 0);
++ } else {
++ boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
++ WDIOF_CARDRESET : 0;
++ wdt_disable(); /*disable for now */
++ set_bit(WDT_DEVICE_INITED, &wdt_status);
++ }
++
++out:
++ return ret;
++}
++
++static int pnx4008_wdt_remove(struct platform_device *pdev)
++{
++ misc_deregister(&pnx4008_wdt_miscdev);
++ if (wdt_clk) {
++ clk_set_rate(wdt_clk, 0);
++ clk_put(wdt_clk);
++ wdt_clk = NULL;
++ }
++ if (wdt_mem) {
++ release_resource(wdt_mem);
++ kfree(wdt_mem);
++ wdt_mem = NULL;
++ }
++ return 0;
++}
++
++static struct platform_driver platform_wdt_driver = {
++ .driver = {
++ .name = "watchdog",
++ },
++ .probe = pnx4008_wdt_probe,
++ .remove = pnx4008_wdt_remove,
++};
++
++static int __init pnx4008_wdt_init(void)
++{
++ return platform_driver_register(&platform_wdt_driver);
++}
++
++static void __exit pnx4008_wdt_exit(void)
++{
++ return platform_driver_unregister(&platform_wdt_driver);
++}
++
++module_init(pnx4008_wdt_init);
++module_exit(pnx4008_wdt_exit);
++
++MODULE_AUTHOR("MontaVista Software, Inc. <source at mvista.com>");
++MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
++
++module_param(heartbeat, int, 0);
++MODULE_PARM_DESC(heartbeat,
++ "Watchdog heartbeat period in seconds from 1 to "
++ __MODULE_STRING(MAX_HEARTBEAT) ", default "
++ __MODULE_STRING(DEFAULT_HEARTBEAT));
++
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout,
++ "Set to 1 to keep watchdog running after device release");
++
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
+index be978e8..18cb050 100644
+--- a/drivers/char/watchdog/s3c2410_wdt.c
++++ b/drivers/char/watchdog/s3c2410_wdt.c
+@@ -62,7 +62,7 @@
+ #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
+ #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
+
+-static int nowayout = WATCHDOG_NOWAYOUT;
++static int nowayout = WATCHDOG_NOWAYOUT;
+ static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
+ static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
+ static int soft_noboot = 0;
+@@ -213,11 +213,10 @@ static int s3c2410wdt_open(struct inode
+ if(down_trylock(&open_lock))
+ return -EBUSY;
+
+- if (nowayout) {
++ if (nowayout)
+ __module_get(THIS_MODULE);
+- } else {
+- allow_close = CLOSE_STATE_ALLOW;
+- }
++
++ allow_close = CLOSE_STATE_NOT;
+
+ /* start the timer */
+ s3c2410wdt_start();
+@@ -230,6 +229,7 @@ static int s3c2410wdt_release(struct ino
+ * Shut off the timer.
+ * Lock it in if it's a module and we set nowayout
+ */
++
+ if (allow_close == CLOSE_STATE_ALLOW) {
+ s3c2410wdt_stop();
+ } else {
+@@ -288,7 +288,7 @@ static int s3c2410wdt_ioctl(struct inode
+
+ switch (cmd) {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &s3c2410_wdt_ident,
+@@ -336,8 +336,7 @@ static struct miscdevice s3c2410wdt_misc
+
+ /* interrupt handler code */
+
+-static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
+- struct pt_regs *regs)
++static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
+ {
+ printk(KERN_INFO PFX "Watchdog timer expired!\n");
+
+@@ -381,18 +380,21 @@ static int s3c2410wdt_probe(struct platf
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ printk(KERN_INFO PFX "failed to get irq resource\n");
++ iounmap(wdt_base);
+ return -ENOENT;
+ }
+
+ ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
+ if (ret != 0) {
+ printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
++ iounmap(wdt_base);
+ return ret;
+ }
+
+ wdt_clock = clk_get(&pdev->dev, "watchdog");
+ if (wdt_clock == NULL) {
+ printk(KERN_INFO PFX "failed to find watchdog clock source\n");
++ iounmap(wdt_base);
+ return -ENOENT;
+ }
+
+@@ -416,6 +418,7 @@ static int s3c2410wdt_probe(struct platf
+ if (ret) {
+ printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
+ WATCHDOG_MINOR, ret);
++ iounmap(wdt_base);
+ return ret;
+ }
+
+@@ -452,6 +455,7 @@ static int s3c2410wdt_remove(struct plat
+ wdt_clock = NULL;
+ }
+
++ iounmap(wdt_base);
+ misc_deregister(&s3c2410wdt_miscdev);
+ return 0;
+ }
+diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
+index 1fc16d9..33c1137 100644
+--- a/drivers/char/watchdog/sa1100_wdt.c
++++ b/drivers/char/watchdog/sa1100_wdt.c
+@@ -90,7 +90,7 @@ static struct watchdog_info ident = {
+ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+- int ret = -ENOIOCTLCMD;
++ int ret = -ENOTTY;
+ int time;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
+index 4663c2f..c7b2045 100644
+--- a/drivers/char/watchdog/sbc60xxwdt.c
++++ b/drivers/char/watchdog/sbc60xxwdt.c
+@@ -235,7 +235,7 @@ static int fop_ioctl(struct inode *inode
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+ case WDIOC_GETSTATUS:
+diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
+index bfc475d..8882b42 100644
+--- a/drivers/char/watchdog/sbc_epx_c3.c
++++ b/drivers/char/watchdog/sbc_epx_c3.c
+@@ -141,7 +141,7 @@ static int epx_c3_ioctl(struct inode *in
+
+ return retval;
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
+index 7c3cf29..e323983 100644
+--- a/drivers/char/watchdog/sc1200wdt.c
++++ b/drivers/char/watchdog/sc1200wdt.c
+@@ -180,7 +180,7 @@ static int sc1200wdt_ioctl(struct inode
+
+ switch (cmd) {
+ default:
+- return -ENOIOCTLCMD; /* Keep Pavel Machek amused ;) */
++ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &ident, sizeof ident))
+@@ -392,7 +392,7 @@ static int __init sc1200wdt_init(void)
+ if (io == -1) {
+ printk(KERN_ERR PFX "io parameter must be specified\n");
+ ret = -EINVAL;
+- goto out_clean;
++ goto out_pnp;
+ }
+
+ #if defined CONFIG_PNP
+@@ -405,7 +405,7 @@ static int __init sc1200wdt_init(void)
+ if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
+ printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+ ret = -EBUSY;
+- goto out_clean;
++ goto out_pnp;
+ }
+
+ ret = sc1200wdt_probe();
+@@ -435,6 +435,11 @@ out_rbt:
+ out_io:
+ release_region(io, io_len);
+
++out_pnp:
++#if defined CONFIG_PNP
++ if (isapnp)
++ pnp_unregister_driver(&scl200wdt_pnp_driver);
++#endif
+ goto out_clean;
+ }
+
+diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
+index 2c7c9db..caec37b 100644
+--- a/drivers/char/watchdog/sc520_wdt.c
++++ b/drivers/char/watchdog/sc520_wdt.c
+@@ -290,7 +290,7 @@ static int fop_ioctl(struct inode *inode
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+ case WDIOC_GETSTATUS:
+diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
+index c561299..fc0e034 100644
+--- a/drivers/char/watchdog/scx200_wdt.c
++++ b/drivers/char/watchdog/scx200_wdt.c
+@@ -166,7 +166,7 @@ static int scx200_wdt_ioctl(struct inode
+
+ switch (cmd) {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ if(copy_to_user(argp, &ident, sizeof(ident)))
+ return -EFAULT;
+diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
+index 1355038..dc40362 100644
+--- a/drivers/char/watchdog/shwdt.c
++++ b/drivers/char/watchdog/shwdt.c
+@@ -27,7 +27,7 @@
+ #include <linux/notifier.h>
+ #include <linux/ioport.h>
+ #include <linux/fs.h>
+-
++#include <linux/mm.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/watchdog.h>
+@@ -125,7 +125,6 @@ static void sh_wdt_start(void)
+
+ /**
+ * sh_wdt_stop - Stop the Watchdog
+- *
+ * Stops the watchdog.
+ */
+ static void sh_wdt_stop(void)
+@@ -141,22 +140,20 @@ static void sh_wdt_stop(void)
+
+ /**
+ * sh_wdt_keepalive - Keep the Userspace Watchdog Alive
+- *
+ * The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
+ */
+-static void sh_wdt_keepalive(void)
++static inline void sh_wdt_keepalive(void)
+ {
+ next_heartbeat = jiffies + (heartbeat * HZ);
+ }
+
+ /**
+ * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
+- *
+ * Set the Userspace Watchdog heartbeat
+ */
+ static int sh_wdt_set_heartbeat(int t)
+ {
+- if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
++ if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */
+ return -EINVAL;
+
+ heartbeat = t;
+@@ -165,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t)
+
+ /**
+ * sh_wdt_ping - Ping the Watchdog
+- *
+ * @data: Unused
+ *
+ * Clears overflow bit, resets timer counter.
+@@ -182,14 +178,13 @@ static void sh_wdt_ping(unsigned long da
+ sh_wdt_write_cnt(0);
+
+ mod_timer(&timer, next_ping_period(clock_division_ratio));
+- } else {
+- printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+- }
++ } else
++ printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
++ "the watchdog\n");
+ }
+
+ /**
+ * sh_wdt_open - Open the Device
+- *
+ * @inode: inode of device
+ * @file: file handle of device
+ *
+@@ -209,7 +204,6 @@ static int sh_wdt_open(struct inode *ino
+
+ /**
+ * sh_wdt_close - Close the Device
+- *
+ * @inode: inode of device
+ * @file: file handle of device
+ *
+@@ -220,7 +214,8 @@ static int sh_wdt_close(struct inode *in
+ if (shwdt_expect_close == 42) {
+ sh_wdt_stop();
+ } else {
+- printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
++ printk(KERN_CRIT PFX "Unexpected close, not "
++ "stopping watchdog!\n");
+ sh_wdt_keepalive();
+ }
+
+@@ -232,7 +227,6 @@ static int sh_wdt_close(struct inode *in
+
+ /**
+ * sh_wdt_write - Write to Device
+- *
+ * @file: file handle of device
+ * @buf: buffer to write
+ * @count: length of buffer
+@@ -264,8 +258,56 @@ static ssize_t sh_wdt_write(struct file
+ }
+
+ /**
+- * sh_wdt_ioctl - Query Device
++ * sh_wdt_mmap - map WDT/CPG registers into userspace
++ * @file: file structure for the device
++ * @vma: VMA to map the registers into
++ *
++ * A simple mmap() implementation for the corner cases where the counter
++ * needs to be mapped in userspace directly. Due to the relatively small
++ * size of the area, neighbouring registers not necessarily tied to the
++ * CPG will also be accessible through the register page, so this remains
++ * configurable for users that really know what they're doing.
+ *
++ * Additionaly, the register page maps in the CPG register base relative
++ * to the nearest page-aligned boundary, which requires that userspace do
++ * the appropriate CPU subtype math for calculating the page offset for
++ * the counter value.
++ */
++static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int ret = -ENOSYS;
++
++#ifdef CONFIG_SH_WDT_MMAP
++ unsigned long addr;
++
++ /* Only support the simple cases where we map in a register page. */
++ if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
++ return -EINVAL;
++
++ /*
++ * Pick WTCNT as the start, it's usually the first register after the
++ * FRQCR, and neither one are generally page-aligned out of the box.
++ */
++ addr = WTCNT & ~(PAGE_SIZE - 1);
++
++ vma->vm_flags |= VM_IO;
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++ if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
++ PAGE_SIZE, vma->vm_page_prot)) {
++ printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n",
++ __FUNCTION__);
++ return -EAGAIN;
++ }
++
++ ret = 0;
++#endif
++
++ return ret;
++}
++
++/**
++ * sh_wdt_ioctl - Query Device
+ * @inode: inode of device
+ * @file: file handle of device
+ * @cmd: watchdog command
+@@ -318,7 +360,7 @@ static int sh_wdt_ioctl(struct inode *in
+
+ return retval;
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+
+ return 0;
+@@ -326,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *in
+
+ /**
+ * sh_wdt_notify_sys - Notifier Handler
+- *
+ * @this: notifier block
+ * @code: notifier event
+ * @unused: unused
+@@ -337,9 +378,8 @@ static int sh_wdt_ioctl(struct inode *in
+ static int sh_wdt_notify_sys(struct notifier_block *this,
+ unsigned long code, void *unused)
+ {
+- if (code == SYS_DOWN || code == SYS_HALT) {
++ if (code == SYS_DOWN || code == SYS_HALT)
+ sh_wdt_stop();
+- }
+
+ return NOTIFY_DONE;
+ }
+@@ -351,10 +391,12 @@ static const struct file_operations sh_w
+ .ioctl = sh_wdt_ioctl,
+ .open = sh_wdt_open,
+ .release = sh_wdt_close,
++ .mmap = sh_wdt_mmap,
+ };
+
+ static struct watchdog_info sh_wdt_info = {
+- .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
++ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
++ WDIOF_MAGICCLOSE,
+ .firmware_version = 1,
+ .identity = "SH WDT",
+ };
+@@ -371,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev
+
+ /**
+ * sh_wdt_init - Initialize module
+- *
+ * Registers the device and notifier handler. Actual device
+ * initialization is handled by sh_wdt_open().
+ */
+@@ -381,15 +422,15 @@ static int __init sh_wdt_init(void)
+
+ if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
+ clock_division_ratio = WTCSR_CKS_4096;
+- printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
+- clock_division_ratio);
++ printk(KERN_INFO PFX "clock_division_ratio value must "
++ "be 0x5<=x<=0x7, using %d\n", clock_division_ratio);
+ }
+
+- if (sh_wdt_set_heartbeat(heartbeat))
+- {
++ rc = sh_wdt_set_heartbeat(heartbeat);
++ if (unlikely(rc)) {
+ heartbeat = WATCHDOG_HEARTBEAT;
+- printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n",
+- heartbeat);
++ printk(KERN_INFO PFX "heartbeat value must "
++ "be 1<=x<=3600, using %d\n", heartbeat);
+ }
+
+ init_timer(&timer);
+@@ -397,15 +438,16 @@ static int __init sh_wdt_init(void)
+ timer.data = 0;
+
+ rc = register_reboot_notifier(&sh_wdt_notifier);
+- if (rc) {
+- printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc);
++ if (unlikely(rc)) {
++ printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n",
++ rc);
+ return rc;
+ }
+
+ rc = misc_register(&sh_wdt_miscdev);
+- if (rc) {
+- printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
+- sh_wdt_miscdev.minor, rc);
++ if (unlikely(rc)) {
++ printk(KERN_ERR PFX "Can't register miscdev on "
++ "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc);
+ unregister_reboot_notifier(&sh_wdt_notifier);
+ return rc;
+ }
+@@ -418,7 +460,6 @@ static int __init sh_wdt_init(void)
+
+ /**
+ * sh_wdt_exit - Deinitialize module
+- *
+ * Unregisters the device and notifier handler. Actual device
+ * deinitialization is handled by sh_wdt_close().
+ */
+@@ -434,14 +475,13 @@ MODULE_LICENSE("GPL");
+ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+ module_param(clock_division_ratio, int, 0);
+-MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
++MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")");
+
+ module_param(heartbeat, int, 0);
+ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+ module_param(nowayout, int, 0);
+-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+ module_init(sh_wdt_init);
+ module_exit(sh_wdt_exit);
+-
+diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c
+new file mode 100644
+index 0000000..9f56913
+--- /dev/null
++++ b/drivers/char/watchdog/smsc37b787_wdt.c
+@@ -0,0 +1,627 @@
++/*
++ * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x
++ *
++ * Based on acquirewdt.c by Alan Cox <alan at redhat.com>
++ * and some other existing drivers
++ *
++ * 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 authors do NOT admit liability nor provide warranty for
++ * any of this software. This material is provided "AS-IS" in
++ * the hope that it may be useful for others.
++ *
++ * (C) Copyright 2003-2006 Sven Anders <anders at anduras.de>
++ *
++ * History:
++ * 2003 - Created version 1.0 for Linux 2.4.x.
++ * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
++ * features. Released version 1.1
++ *
++ * Theory of operation:
++ *
++ * A Watchdog Timer (WDT) is a hardware circuit that can
++ * reset the computer system in case of a software fault.
++ * You probably knew that already.
++ *
++ * Usually a userspace daemon will notify the kernel WDT driver
++ * via the /dev/watchdog special device file that userspace is
++ * still alive, at regular intervals. When such a notification
++ * occurs, the driver will usually tell the hardware watchdog
++ * that everything is in order, and that the watchdog should wait
++ * for yet another little while to reset the system.
++ * If userspace fails (RAM error, kernel bug, whatever), the
++ * notifications cease to occur, and the hardware watchdog will
++ * reset the system (causing a reboot) after the timeout occurs.
++ *
++ * Create device with:
++ * mknod /dev/watchdog c 10 130
++ *
++ * For an example userspace keep-alive daemon, see:
++ * Documentation/watchdog/watchdog.txt
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/ioport.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++
++/* enable support for minutes as units? */
++/* (does not always work correctly, so disabled by default!) */
++#define SMSC_SUPPORT_MINUTES
++#undef SMSC_SUPPORT_MINUTES
++
++#define MAX_TIMEOUT 255
++
++#define UNIT_SECOND 0
++#define UNIT_MINUTE 1
++
++#define MODNAME "smsc37b787_wdt: "
++#define VERSION "1.1"
++
++#define IOPORT 0x3F0
++#define IOPORT_SIZE 2
++#define IODEV_NO 8
++
++static int unit = UNIT_SECOND; /* timer's unit */
++static int timeout = 60; /* timeout value: default is 60 "units" */
++static unsigned long timer_enabled = 0; /* is the timer enabled? */
++
++static char expect_close; /* is the close expected? */
++
++static spinlock_t io_lock; /* to guard the watchdog from io races */
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++
++/* -- Low level function ----------------------------------------*/
++
++/* unlock the IO chip */
++
++static inline void open_io_config(void)
++{
++ outb(0x55, IOPORT);
++ mdelay(1);
++ outb(0x55, IOPORT);
++}
++
++/* lock the IO chip */
++static inline void close_io_config(void)
++{
++ outb(0xAA, IOPORT);
++}
++
++/* select the IO device */
++static inline void select_io_device(unsigned char devno)
++{
++ outb(0x07, IOPORT);
++ outb(devno, IOPORT+1);
++}
++
++/* write to the control register */
++static inline void write_io_cr(unsigned char reg, unsigned char data)
++{
++ outb(reg, IOPORT);
++ outb(data, IOPORT+1);
++}
++
++/* read from the control register */
++static inline char read_io_cr(unsigned char reg)
++{
++ outb(reg, IOPORT);
++ return inb(IOPORT+1);
++}
++
++/* -- Medium level functions ------------------------------------*/
++
++static inline void gpio_bit12(unsigned char reg)
++{
++ // -- General Purpose I/O Bit 1.2 --
++ // Bit 0, In/Out: 0 = Output, 1 = Input
++ // Bit 1, Polarity: 0 = No Invert, 1 = Invert
++ // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
++ // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
++ // 11 = Either Edge Triggered Intr. 2
++ // Bit 5/6 (Reserved)
++ // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
++ write_io_cr(0xE2, reg);
++}
++
++static inline void gpio_bit13(unsigned char reg)
++{
++ // -- General Purpose I/O Bit 1.3 --
++ // Bit 0, In/Out: 0 = Output, 1 = Input
++ // Bit 1, Polarity: 0 = No Invert, 1 = Invert
++ // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
++ // Bit 3, Function select: 0 = GPI/O, 1 = LED
++ // Bit 4-6 (Reserved)
++ // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
++ write_io_cr(0xE3, reg);
++}
++
++static inline void wdt_timer_units(unsigned char new_units)
++{
++ // -- Watchdog timer units --
++ // Bit 0-6 (Reserved)
++ // Bit 7, WDT Time-out Value Units Select
++ // (0 = Minutes, 1 = Seconds)
++ write_io_cr(0xF1, new_units);
++}
++
++static inline void wdt_timeout_value(unsigned char new_timeout)
++{
++ // -- Watchdog Timer Time-out Value --
++ // Bit 0-7 Binary coded units (0=Disabled, 1..255)
++ write_io_cr(0xF2, new_timeout);
++}
++
++static inline void wdt_timer_conf(unsigned char conf)
++{
++ // -- Watchdog timer configuration --
++ // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O
++ // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
++ // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr.
++ // Bit 3 Reset the timer
++ // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled)
++ // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
++ // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
++ write_io_cr(0xF3, conf);
++}
++
++static inline void wdt_timer_ctrl(unsigned char reg)
++{
++ // -- Watchdog timer control --
++ // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured
++ // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz
++ // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning)
++ // Bit 3 P20 Force Timeout enabled:
++ // 0 = P20 activity does not generate the WD timeout event
++ // 1 = P20 Allows rising edge of P20, from the keyboard
++ // controller, to force the WD timeout event.
++ // Bit 4 (Reserved)
++ // -- Soft power management --
++ // Bit 5 Stop Counter: 1 = Stop software power down counter
++ // set via register 0xB8, (self-cleaning)
++ // (Upon read: 0 = Counter running, 1 = Counter stopped)
++ // Bit 6 Restart Counter: 1 = Restart software power down counter
++ // set via register 0xB8, (self-cleaning)
++ // Bit 7 SPOFF: 1 = Force software power down (self-cleaning)
++
++ write_io_cr(0xF4, reg);
++}
++
++/* -- Higher level functions ------------------------------------*/
++
++/* initialize watchdog */
++
++static void wb_smsc_wdt_initialize(void)
++{
++ unsigned char old;
++
++ spin_lock(&io_lock);
++ open_io_config();
++ select_io_device(IODEV_NO);
++
++ // enable the watchdog
++ gpio_bit13(0x08); // Select pin 80 = LED not GPIO
++ gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert
++
++ // disable the timeout
++ wdt_timeout_value(0);
++
++ // reset control register
++ wdt_timer_ctrl(0x00);
++
++ // reset configuration register
++ wdt_timer_conf(0x00);
++
++ // read old (timer units) register
++ old = read_io_cr(0xF1) & 0x7F;
++ if (unit == UNIT_SECOND) old |= 0x80; // set to seconds
++
++ // set the watchdog timer units
++ wdt_timer_units(old);
++
++ close_io_config();
++ spin_unlock(&io_lock);
++}
++
++/* shutdown the watchdog */
++
++static void wb_smsc_wdt_shutdown(void)
++{
++ spin_lock(&io_lock);
++ open_io_config();
++ select_io_device(IODEV_NO);
++
++ // disable the watchdog
++ gpio_bit13(0x09);
++ gpio_bit12(0x09);
++
++ // reset watchdog config register
++ wdt_timer_conf(0x00);
++
++ // reset watchdog control register
++ wdt_timer_ctrl(0x00);
++
++ // disable timeout
++ wdt_timeout_value(0x00);
++
++ close_io_config();
++ spin_unlock(&io_lock);
++}
++
++/* set timeout => enable watchdog */
++
++static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
++{
++ spin_lock(&io_lock);
++ open_io_config();
++ select_io_device(IODEV_NO);
++
++ // set Power LED to blink, if we enable the timeout
++ wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
++
++ // set timeout value
++ wdt_timeout_value(new_timeout);
++
++ close_io_config();
++ spin_unlock(&io_lock);
++}
++
++/* get timeout */
++
++static unsigned char wb_smsc_wdt_get_timeout(void)
++{
++ unsigned char set_timeout;
++
++ spin_lock(&io_lock);
++ open_io_config();
++ select_io_device(IODEV_NO);
++ set_timeout = read_io_cr(0xF2);
++ close_io_config();
++ spin_unlock(&io_lock);
++
++ return set_timeout;
++}
++
++/* disable watchdog */
++
++static void wb_smsc_wdt_disable(void)
++{
++ // set the timeout to 0 to disable the watchdog
++ wb_smsc_wdt_set_timeout(0);
++}
++
++/* enable watchdog by setting the current timeout */
++
++static void wb_smsc_wdt_enable(void)
++{
++ // set the current timeout...
++ wb_smsc_wdt_set_timeout(timeout);
++}
++
++/* reset the timer */
++
++static void wb_smsc_wdt_reset_timer(void)
++{
++ spin_lock(&io_lock);
++ open_io_config();
++ select_io_device(IODEV_NO);
++
++ // reset the timer
++ wdt_timeout_value(timeout);
++ wdt_timer_conf(0x08);
++
++ close_io_config();
++ spin_unlock(&io_lock);
++}
++
++/* return, if the watchdog is enabled (timeout is set...) */
++
++static int wb_smsc_wdt_status(void)
++{
++ return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
++}
++
++
++/* -- File operations -------------------------------------------*/
++
++/* open => enable watchdog and set initial timeout */
++
++static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
++{
++ /* /dev/watchdog can only be opened once */
++
++ if (test_and_set_bit(0, &timer_enabled))
++ return -EBUSY;
++
++ if (nowayout)
++ __module_get(THIS_MODULE);
++
++ /* Reload and activate timer */
++ wb_smsc_wdt_enable();
++
++ printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
++
++ return nonseekable_open(inode, file);
++}
++
++/* close => shut off the timer */
++
++static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
++{
++ /* Shut off the timer. */
++
++ if (expect_close == 42) {
++ wb_smsc_wdt_disable();
++ printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n");
++ } else {
++ printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n");
++ wb_smsc_wdt_reset_timer();
++ }
++
++ clear_bit(0, &timer_enabled);
++ expect_close = 0;
++ return 0;
++}
++
++/* write => update the timer to keep the machine alive */
++
++static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
++ size_t len, loff_t *ppos)
++{
++ /* See if we got the magic character 'V' and reload the timer */
++ if (len) {
++ if (!nowayout) {
++ size_t i;
++
++ /* reset expect flag */
++ expect_close = 0;
++
++ /* scan to see whether or not we got the magic character */
++ for (i = 0; i != len; i++) {
++ char c;
++ if (get_user(c, data+i))
++ return -EFAULT;
++ if (c == 'V')
++ expect_close = 42;
++ }
++ }
++
++ /* someone wrote to us, we should reload the timer */
++ wb_smsc_wdt_reset_timer();
++ }
++ return len;
++}
++
++/* ioctl => control interface */
++
++static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int new_timeout;
++
++ union {
++ struct watchdog_info __user *ident;
++ int __user *i;
++ } uarg;
++
++ static struct watchdog_info ident = {
++ .options = WDIOF_KEEPALIVEPING |
++ WDIOF_SETTIMEOUT |
++ WDIOF_MAGICCLOSE,
++ .firmware_version = 0,
++ .identity = "SMsC 37B787 Watchdog"
++ };
++
++ uarg.i = (int __user *)arg;
++
++ switch (cmd) {
++ default:
++ return -ENOTTY;
++
++ case WDIOC_GETSUPPORT:
++ return copy_to_user(uarg.ident, &ident,
++ sizeof(ident)) ? -EFAULT : 0;
++
++ case WDIOC_GETSTATUS:
++ return put_user(wb_smsc_wdt_status(), uarg.i);
++
++ case WDIOC_GETBOOTSTATUS:
++ return put_user(0, uarg.i);
++
++ case WDIOC_KEEPALIVE:
++ wb_smsc_wdt_reset_timer();
++ return 0;
++
++ case WDIOC_SETTIMEOUT:
++ if (get_user(new_timeout, uarg.i))
++ return -EFAULT;
++
++ // the API states this is given in secs
++ if (unit == UNIT_MINUTE)
++ new_timeout /= 60;
++
++ if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
++ return -EINVAL;
++
++ timeout = new_timeout;
++ wb_smsc_wdt_set_timeout(timeout);
++
++ // fall through and return the new timeout...
++
++ case WDIOC_GETTIMEOUT:
++
++ new_timeout = timeout;
++
++ if (unit == UNIT_MINUTE)
++ new_timeout *= 60;
++
++ return put_user(new_timeout, uarg.i);
++
++ case WDIOC_SETOPTIONS:
++ {
++ int options, retval = -EINVAL;
++
++ if (get_user(options, uarg.i))
++ return -EFAULT;
++
++ if (options & WDIOS_DISABLECARD) {
++ wb_smsc_wdt_disable();
++ retval = 0;
++ }
++
++ if (options & WDIOS_ENABLECARD) {
++ wb_smsc_wdt_enable();
++ retval = 0;
++ }
++
++ return retval;
++ }
++ }
++}
++
++/* -- Notifier funtions -----------------------------------------*/
++
++static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
++{
++ if (code == SYS_DOWN || code == SYS_HALT)
++ {
++ // set timeout to 0, to avoid possible race-condition
++ timeout = 0;
++ wb_smsc_wdt_disable();
++ }
++ return NOTIFY_DONE;
++}
++
++/* -- Module's structures ---------------------------------------*/
++
++static struct file_operations wb_smsc_wdt_fops =
++{
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = wb_smsc_wdt_write,
++ .ioctl = wb_smsc_wdt_ioctl,
++ .open = wb_smsc_wdt_open,
++ .release = wb_smsc_wdt_release,
++};
++
++static struct notifier_block wb_smsc_wdt_notifier =
++{
++ .notifier_call = wb_smsc_wdt_notify_sys,
++};
++
++static struct miscdevice wb_smsc_wdt_miscdev =
++{
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &wb_smsc_wdt_fops,
++};
++
++/* -- Module init functions -------------------------------------*/
++
++/* module's "constructor" */
++
++static int __init wb_smsc_wdt_init(void)
++{
++ int ret;
++
++ spin_lock_init(&io_lock);
++
++ printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n");
++
++ if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
++ printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT);
++ ret = -EBUSY;
++ goto out_pnp;
++ }
++
++ // set new maximum, if it's too big
++ if (timeout > MAX_TIMEOUT)
++ timeout = MAX_TIMEOUT;
++
++ // init the watchdog timer
++ wb_smsc_wdt_initialize();
++
++ ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
++ if (ret) {
++ printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret);
++ goto out_io;
++ }
++
++ ret = misc_register(&wb_smsc_wdt_miscdev);
++ if (ret) {
++ printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
++ goto out_rbt;
++ }
++
++ // output info
++ printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
++ printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout);
++
++ // ret = 0
++
++out_clean:
++ return ret;
++
++out_rbt:
++ unregister_reboot_notifier(&wb_smsc_wdt_notifier);
++
++out_io:
++ release_region(IOPORT, IOPORT_SIZE);
++
++out_pnp:
++ goto out_clean;
++}
++
++/* module's "destructor" */
++
++static void __exit wb_smsc_wdt_exit(void)
++{
++ /* Stop the timer before we leave */
++ if (!nowayout)
++ {
++ wb_smsc_wdt_shutdown();
++ printk(KERN_INFO MODNAME "Watchdog disabled.\n");
++ }
++
++ misc_deregister(&wb_smsc_wdt_miscdev);
++ unregister_reboot_notifier(&wb_smsc_wdt_notifier);
++ release_region(IOPORT, IOPORT_SIZE);
++
++ printk("SMsC 37B787 watchdog component driver removed.\n");
++}
++
++module_init(wb_smsc_wdt_init);
++module_exit(wb_smsc_wdt_exit);
++
++MODULE_AUTHOR("Sven Anders <anders at anduras.de>");
++MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")");
++MODULE_LICENSE("GPL");
++
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
++
++#ifdef SMSC_SUPPORT_MINUTES
++module_param(unit, int, 0);
++MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0");
++#endif
++
++module_param(timeout, int, 0);
++MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
++
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
+index ef8da51..4067e1f 100644
+--- a/drivers/char/watchdog/softdog.c
++++ b/drivers/char/watchdog/softdog.c
+@@ -203,7 +203,7 @@ static int softdog_ioctl(struct inode *i
+ };
+ switch (cmd) {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
+index 13f16d4..07d4bff 100644
+--- a/drivers/char/watchdog/w83627hf_wdt.c
++++ b/drivers/char/watchdog/w83627hf_wdt.c
+@@ -33,6 +33,7 @@
+ #include <linux/notifier.h>
+ #include <linux/reboot.h>
+ #include <linux/init.h>
++#include <linux/spinlock.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -44,6 +45,7 @@
+
+ static unsigned long wdt_is_open;
+ static char expect_close;
++static spinlock_t io_lock;
+
+ /* You must set this - there is no sane way to probe for this board. */
+ static int wdt_io = 0x2E;
+@@ -110,12 +112,16 @@ w83627hf_init(void)
+ static void
+ wdt_ctrl(int timeout)
+ {
++ spin_lock(&io_lock);
++
+ w83627hf_select_wd_register();
+
+ outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+ outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */
+
+ w83627hf_unselect_wd_register();
++
++ spin_unlock(&io_lock);
+ }
+
+ static int
+@@ -223,7 +229,7 @@ wdt_ioctl(struct inode *inode, struct fi
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ return 0;
+ }
+@@ -303,6 +309,8 @@ wdt_init(void)
+ {
+ int ret;
+
++ spin_lock_init(&io_lock);
++
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
+
+ if (wdt_set_heartbeat(timeout)) {
+diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c
+new file mode 100644
+index 0000000..7768b55
+--- /dev/null
++++ b/drivers/char/watchdog/w83697hf_wdt.c
+@@ -0,0 +1,450 @@
++/*
++ * w83697hf/hg WDT driver
++ *
++ * (c) Copyright 2006 Samuel Tardieu <sam at rfc1149.net>
++ * (c) Copyright 2006 Marcus Junker <junker at anduras.de>
++ *
++ * Based on w83627hf_wdt.c which is based on advantechwdt.c
++ * which is based on wdt.c.
++ * Original copyright messages:
++ *
++ * (c) Copyright 2003 Pádraig Brady <P at draigBrady.com>
++ *
++ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm at linux.org.pl>
++ *
++ * (c) Copyright 1996 Alan Cox <alan at redhat.com>, All Rights Reserved.
++ * http://www.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.
++ *
++ * Neither Marcus Junker nor ANDURAS AG admit liability nor provide
++ * warranty for any of this software. This material is provided
++ * "AS-IS" and at no charge.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/fs.h>
++#include <linux/ioport.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++
++#define WATCHDOG_NAME "w83697hf/hg WDT"
++#define PFX WATCHDOG_NAME ": "
++#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
++
++static unsigned long wdt_is_open;
++static char expect_close;
++static spinlock_t io_lock;
++
++/* You must set this - there is no sane way to probe for this board. */
++static int wdt_io = 0x2e;
++module_param(wdt_io, int, 0);
++MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)");
++
++static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
++module_param(timeout, int, 0);
++MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
++
++/*
++ * Kernel methods.
++ */
++
++#define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */
++#define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */
++#define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */
++
++static inline void
++w83697hf_unlock(void)
++{
++ outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */
++ outb_p(0x87, W83697HF_EFER); /* Again according to manual */
++}
++
++static inline void
++w83697hf_lock(void)
++{
++ outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */
++}
++
++/*
++ * The three functions w83697hf_get_reg(), w83697hf_set_reg() and
++ * w83697hf_write_timeout() must be called with the device unlocked.
++ */
++
++static unsigned char
++w83697hf_get_reg(unsigned char reg)
++{
++ outb_p(reg, W83697HF_EFIR);
++ return inb_p(W83697HF_EFDR);
++}
++
++static void
++w83697hf_set_reg(unsigned char reg, unsigned char data)
++{
++ outb_p(reg, W83697HF_EFIR);
++ outb_p(data, W83697HF_EFDR);
++}
++
++static void
++w83697hf_write_timeout(int timeout)
++{
++ w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */
++}
++
++static void
++w83697hf_select_wdt(void)
++{
++ w83697hf_unlock();
++ w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */
++}
++
++static inline void
++w83697hf_deselect_wdt(void)
++{
++ w83697hf_lock();
++}
++
++static void
++w83697hf_init(void)
++{
++ unsigned char bbuf;
++
++ w83697hf_select_wdt();
++
++ bbuf = w83697hf_get_reg(0x29);
++ bbuf &= ~0x60;
++ bbuf |= 0x20;
++ w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
++
++ bbuf = w83697hf_get_reg(0xF3);
++ bbuf &= ~0x04;
++ w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */
++
++ w83697hf_deselect_wdt();
++}
++
++static int
++wdt_ping(void)
++{
++ spin_lock(&io_lock);
++ w83697hf_select_wdt();
++
++ w83697hf_write_timeout(timeout);
++
++ w83697hf_deselect_wdt();
++ spin_unlock(&io_lock);
++ return 0;
++}
++
++static int
++wdt_enable(void)
++{
++ spin_lock(&io_lock);
++ w83697hf_select_wdt();
++
++ w83697hf_write_timeout(timeout);
++ w83697hf_set_reg(0x30, 1); /* Enable timer */
++
++ w83697hf_deselect_wdt();
++ spin_unlock(&io_lock);
++ return 0;
++}
++
++static int
++wdt_disable(void)
++{
++ spin_lock(&io_lock);
++ w83697hf_select_wdt();
++
++ w83697hf_set_reg(0x30, 0); /* Disable timer */
++ w83697hf_write_timeout(0);
++
++ w83697hf_deselect_wdt();
++ spin_unlock(&io_lock);
++ return 0;
++}
++
++static int
++wdt_set_heartbeat(int t)
++{
++ if ((t < 1) || (t > 255))
++ return -EINVAL;
++
++ timeout = t;
++ return 0;
++}
++
++static ssize_t
++wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
++{
++ if (count) {
++ if (!nowayout) {
++ size_t i;
++
++ expect_close = 0;
++
++ for (i = 0; i != count; i++) {
++ char c;
++ if (get_user(c, buf+i))
++ return -EFAULT;
++ if (c == 'V')
++ expect_close = 42;
++ }
++ }
++ wdt_ping();
++ }
++ return count;
++}
++
++static int
++wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ void __user *argp = (void __user *)arg;
++ int __user *p = argp;
++ int new_timeout;
++ static struct watchdog_info ident = {
++ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
++ .firmware_version = 1,
++ .identity = "W83697HF WDT",
++ };
++
++ switch (cmd) {
++ case WDIOC_GETSUPPORT:
++ if (copy_to_user(argp, &ident, sizeof(ident)))
++ return -EFAULT;
++ break;
++
++ case WDIOC_GETSTATUS:
++ case WDIOC_GETBOOTSTATUS:
++ return put_user(0, p);
++
++ case WDIOC_KEEPALIVE:
++ wdt_ping();
++ break;
++
++ case WDIOC_SETTIMEOUT:
++ if (get_user(new_timeout, p))
++ return -EFAULT;
++ if (wdt_set_heartbeat(new_timeout))
++ return -EINVAL;
++ wdt_ping();
++ /* Fall */
++
++ case WDIOC_GETTIMEOUT:
++ return put_user(timeout, p);
++
++ case WDIOC_SETOPTIONS:
++ {
++ int options, retval = -EINVAL;
++
++ if (get_user(options, p))
++ return -EFAULT;
++
++ if (options & WDIOS_DISABLECARD) {
++ wdt_disable();
++ retval = 0;
++ }
++
++ if (options & WDIOS_ENABLECARD) {
++ wdt_enable();
++ retval = 0;
++ }
++
++ return retval;
++ }
++
++ default:
++ return -ENOTTY;
++ }
++ return 0;
++}
++
++static int
++wdt_open(struct inode *inode, struct file *file)
++{
++ if (test_and_set_bit(0, &wdt_is_open))
++ return -EBUSY;
++ /*
++ * Activate
++ */
++
++ wdt_enable();
++ return nonseekable_open(inode, file);
++}
++
++static int
++wdt_close(struct inode *inode, struct file *file)
++{
++ if (expect_close == 42) {
++ wdt_disable();
++ } else {
++ printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
++ wdt_ping();
++ }
++ expect_close = 0;
++ clear_bit(0, &wdt_is_open);
++ return 0;
++}
++
++/*
++ * Notifier for system down
++ */
++
++static int
++wdt_notify_sys(struct notifier_block *this, unsigned long code,
++ void *unused)
++{
++ if (code == SYS_DOWN || code == SYS_HALT) {
++ /* Turn the WDT off */
++ wdt_disable();
++ }
++ return NOTIFY_DONE;
++}
++
++/*
++ * Kernel Interfaces
++ */
++
++static struct file_operations wdt_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = wdt_write,
++ .ioctl = wdt_ioctl,
++ .open = wdt_open,
++ .release = wdt_close,
++};
++
++static struct miscdevice wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &wdt_fops,
++};
++
++/*
++ * The WDT needs to learn about soft shutdowns in order to
++ * turn the timebomb registers off.
++ */
++
++static struct notifier_block wdt_notifier = {
++ .notifier_call = wdt_notify_sys,
++};
++
++static int
++w83697hf_check_wdt(void)
++{
++ if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
++ printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io);
++ return -EIO;
++ }
++
++ printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io);
++ w83697hf_unlock();
++ if (w83697hf_get_reg(0x20) == 0x60) {
++ printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io);
++ w83697hf_lock();
++ return 0;
++ }
++ w83697hf_lock(); /* Reprotect in case it was a compatible device */
++
++ printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
++ release_region(wdt_io, 2);
++ return -EIO;
++}
++
++static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
++
++static int __init
++wdt_init(void)
++{
++ int ret, i, found = 0;
++
++ spin_lock_init(&io_lock);
++
++ printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
++
++ if (wdt_io == 0) {
++ /* we will autodetect the W83697HF/HG watchdog */
++ for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) {
++ wdt_io = w83697hf_ioports[i];
++ if (!w83697hf_check_wdt())
++ found++;
++ }
++ } else {
++ if (!w83697hf_check_wdt())
++ found++;
++ }
++
++ if (!found) {
++ printk (KERN_ERR PFX "No W83697HF/HG could be found\n");
++ ret = -EIO;
++ goto out;
++ }
++
++ w83697hf_init();
++ wdt_disable(); /* Disable watchdog until first use */
++
++ if (wdt_set_heartbeat(timeout)) {
++ wdt_set_heartbeat(WATCHDOG_TIMEOUT);
++ printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
++ WATCHDOG_TIMEOUT);
++ }
++
++ ret = register_reboot_notifier(&wdt_notifier);
++ if (ret != 0) {
++ printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++ ret);
++ goto unreg_regions;
++ }
++
++ ret = misc_register(&wdt_miscdev);
++ if (ret != 0) {
++ printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++ WATCHDOG_MINOR, ret);
++ goto unreg_reboot;
++ }
++
++ printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
++ timeout, nowayout);
++
++out:
++ return ret;
++unreg_reboot:
++ unregister_reboot_notifier(&wdt_notifier);
++unreg_regions:
++ release_region(wdt_io, 2);
++ goto out;
++}
++
++static void __exit
++wdt_exit(void)
++{
++ misc_deregister(&wdt_miscdev);
++ unregister_reboot_notifier(&wdt_notifier);
++ release_region(wdt_io, 2);
++}
++
++module_init(wdt_init);
++module_exit(wdt_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Marcus Junker <junker at anduras.de>, Samuel Tardieu <sam at rfc1149.net>");
++MODULE_DESCRIPTION("w83697hf/hg WDT driver");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
+index ccf6c09..b0e5f84 100644
+--- a/drivers/char/watchdog/w83877f_wdt.c
++++ b/drivers/char/watchdog/w83877f_wdt.c
+@@ -252,7 +252,7 @@ static int fop_ioctl(struct inode *inode
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+ case WDIOC_GETSTATUS:
+diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
+index 98f4e17..2c8d5d8 100644
+--- a/drivers/char/watchdog/w83977f_wdt.c
++++ b/drivers/char/watchdog/w83977f_wdt.c
+@@ -393,7 +393,7 @@ static int wdt_ioctl(struct inode *inode
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
+diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
+index 2bb6a9d..163e028 100644
+--- a/drivers/char/watchdog/wafer5823wdt.c
++++ b/drivers/char/watchdog/wafer5823wdt.c
+@@ -174,7 +174,7 @@ static int wafwdt_ioctl(struct inode *in
+ }
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ return 0;
+ }
+diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c
+index 5c38cdf..1d64e27 100644
+--- a/drivers/char/watchdog/wdrtas.c
++++ b/drivers/char/watchdog/wdrtas.c
+@@ -385,7 +385,7 @@ wdrtas_ioctl(struct inode *inode, struct
+ return put_user(wdrtas_interval, argp);
+
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ }
+ }
+
+diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
+index 70be81e..517fbd8 100644
+--- a/drivers/char/watchdog/wdt.c
++++ b/drivers/char/watchdog/wdt.c
+@@ -225,14 +225,13 @@ static int wdt_get_temperature(int *temp
+ * wdt_interrupt:
+ * @irq: Interrupt number
+ * @dev_id: Unused as we don't allow multiple devices.
+- * @regs: Unused.
+ *
+ * Handle an interrupt from the board. These are raised when the status
+ * map changes in what the board considers an interesting way. That means
+ * a failure condition occurring.
+ */
+
+-static irqreturn_t wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wdt_interrupt(int irq, void *dev_id)
+ {
+ /*
+ * Read the status register see what is up and
+@@ -341,7 +340,7 @@ static int wdt_ioctl(struct inode *inode
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c
+index 6555fb8..e4cf661 100644
+--- a/drivers/char/watchdog/wdt285.c
++++ b/drivers/char/watchdog/wdt285.c
+@@ -46,7 +46,7 @@ static unsigned long timer_alive;
+ /*
+ * If the timer expires..
+ */
+-static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs)
++static void watchdog_fire(int irq, void *dev_id)
+ {
+ printk(KERN_CRIT "Watchdog: Would Reboot.\n");
+ *CSR_TIMER4_CNTL = 0;
+@@ -137,7 +137,7 @@ watchdog_ioctl(struct inode *inode, stru
+ unsigned long arg)
+ {
+ unsigned int new_margin;
+- int ret = -ENOIOCTLCMD;
++ int ret = -ENOTTY;
+
+ switch(cmd) {
+ case WDIOC_GETSUPPORT:
+diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
+index a0935bc..6253041 100644
+--- a/drivers/char/watchdog/wdt977.c
++++ b/drivers/char/watchdog/wdt977.c
+@@ -361,7 +361,7 @@ static int wdt977_ioctl(struct inode *in
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(uarg.ident, &ident,
+diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
+index 5918ca2..ce1261c 100644
+--- a/drivers/char/watchdog/wdt_pci.c
++++ b/drivers/char/watchdog/wdt_pci.c
+@@ -270,14 +270,13 @@ static int wdtpci_get_temperature(int *t
+ * wdtpci_interrupt:
+ * @irq: Interrupt number
+ * @dev_id: Unused as we don't allow multiple devices.
+- * @regs: Unused.
+ *
+ * Handle an interrupt from the board. These are raised when the status
+ * map changes in what the board considers an interesting way. That means
+ * a failure condition occurring.
+ */
+
+-static irqreturn_t wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
+ {
+ /*
+ * Read the status register see what is up and
+@@ -386,7 +385,7 @@ static int wdtpci_ioctl(struct inode *in
+ switch(cmd)
+ {
+ default:
+- return -ENOIOCTLCMD;
++ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
+index 7ad3be8..7fcb77a 100644
+--- a/drivers/clocksource/acpi_pm.c
++++ b/drivers/clocksource/acpi_pm.c
+@@ -54,8 +54,8 @@ static cycle_t acpi_pm_read_verified(voi
+ v1 = read_pmtmr();
+ v2 = read_pmtmr();
+ v3 = read_pmtmr();
+- } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+- || (v3 > v1 && v3 < v2));
++ } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
++ || (v3 > v1 && v3 < v2)));
+
+ return (cycle_t)v2;
+ }
+@@ -138,6 +138,8 @@ static void __devinit acpi_pm_check_gray
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
+ acpi_pm_check_graylist);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
++ acpi_pm_check_graylist);
+ #endif
+
+
+diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
+index d418b82..22915cc 100644
+--- a/drivers/clocksource/scx200_hrt.c
++++ b/drivers/clocksource/scx200_hrt.c
+@@ -63,7 +63,7 @@ static struct clocksource cs_hrt = {
+
+ static int __init init_hrt_clocksource(void)
+ {
+- /* Make sure scx200 has initializedd the configuration block */
++ /* Make sure scx200 has initialized the configuration block */
+ if (!scx200_cb_present())
+ return -ENODEV;
+
+@@ -76,7 +76,7 @@ static int __init init_hrt_clocksource(v
+ }
+
+ /* write timer config */
+- outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0,
++ outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0),
+ scx200_cb_base + SCx200_TMCNFG_OFFSET);
+
+ if (mhz27) {
+diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
+index b3df613..86e69b7 100644
+--- a/drivers/cpufreq/cpufreq.c
++++ b/drivers/cpufreq/cpufreq.c
+@@ -32,7 +32,7 @@
+ #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)
+
+ /**
+- * The "cpufreq driver" - the arch- or hardware-dependend low
++ * The "cpufreq driver" - the arch- or hardware-dependent low
+ * level driver of CPUFreq support, and its spinlock. This lock
+ * also protects the cpufreq_cpu_data array.
+ */
+@@ -52,8 +52,14 @@ static void handle_update(void *data);
+ * The mutex locks both lists.
+ */
+ static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
+-static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
++static struct srcu_notifier_head cpufreq_transition_notifier_list;
+
++static int __init init_cpufreq_transition_notifier_list(void)
++{
++ srcu_init_notifier_head(&cpufreq_transition_notifier_list);
++ return 0;
++}
++core_initcall(init_cpufreq_transition_notifier_list);
+
+ static LIST_HEAD(cpufreq_governor_list);
+ static DEFINE_MUTEX (cpufreq_governor_mutex);
+@@ -262,14 +268,14 @@ void cpufreq_notify_transition(struct cp
+ freqs->old = policy->cur;
+ }
+ }
+- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
++ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_PRECHANGE, freqs);
+ adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
+ break;
+
+ case CPUFREQ_POSTCHANGE:
+ adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
++ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_POSTCHANGE, freqs);
+ if (likely(policy) && likely(policy->cpu == freqs->cpu))
+ policy->cur = freqs->new;
+@@ -994,7 +1000,7 @@ static int cpufreq_suspend(struct sys_de
+ unsigned int cur_freq = 0;
+ struct cpufreq_policy *cpu_policy;
+
+- dprintk("resuming cpu %u\n", cpu);
++ dprintk("suspending cpu %u\n", cpu);
+
+ if (!cpu_online(cpu))
+ return 0;
+@@ -1049,7 +1055,7 @@ static int cpufreq_suspend(struct sys_de
+ freqs.old = cpu_policy->cur;
+ freqs.new = cur_freq;
+
+- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
++ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_SUSPENDCHANGE, &freqs);
+ adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
+
+@@ -1130,7 +1136,7 @@ static int cpufreq_resume(struct sys_dev
+ freqs.old = cpu_policy->cur;
+ freqs.new = cur_freq;
+
+- blocking_notifier_call_chain(
++ srcu_notifier_call_chain(
+ &cpufreq_transition_notifier_list,
+ CPUFREQ_RESUMECHANGE, &freqs);
+ adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
+@@ -1176,7 +1182,7 @@ int cpufreq_register_notifier(struct not
+
+ switch (list) {
+ case CPUFREQ_TRANSITION_NOTIFIER:
+- ret = blocking_notifier_chain_register(
++ ret = srcu_notifier_chain_register(
+ &cpufreq_transition_notifier_list, nb);
+ break;
+ case CPUFREQ_POLICY_NOTIFIER:
+@@ -1208,7 +1214,7 @@ int cpufreq_unregister_notifier(struct n
+
+ switch (list) {
+ case CPUFREQ_TRANSITION_NOTIFIER:
+- ret = blocking_notifier_chain_unregister(
++ ret = srcu_notifier_chain_unregister(
+ &cpufreq_transition_notifier_list, nb);
+ break;
+ case CPUFREQ_POLICY_NOTIFIER:
+diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
+index 52cf1f0..bf8aa45 100644
+--- a/drivers/cpufreq/cpufreq_ondemand.c
++++ b/drivers/cpufreq/cpufreq_ondemand.c
+@@ -55,6 +55,10 @@ struct cpu_dbs_info_s {
+ struct cpufreq_policy *cur_policy;
+ struct work_struct work;
+ unsigned int enable;
++ struct cpufreq_frequency_table *freq_table;
++ unsigned int freq_lo;
++ unsigned int freq_lo_jiffies;
++ unsigned int freq_hi_jiffies;
+ };
+ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+
+@@ -72,15 +76,15 @@ static DEFINE_MUTEX(dbs_mutex);
+
+ static struct workqueue_struct *kondemand_wq;
+
+-struct dbs_tuners {
++static struct dbs_tuners {
+ unsigned int sampling_rate;
+ unsigned int up_threshold;
+ unsigned int ignore_nice;
+-};
+-
+-static struct dbs_tuners dbs_tuners_ins = {
++ unsigned int powersave_bias;
++} dbs_tuners_ins = {
+ .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+ .ignore_nice = 0,
++ .powersave_bias = 0,
+ };
+
+ static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
+@@ -96,6 +100,70 @@ static inline cputime64_t get_cpu_idle_t
+ return retval;
+ }
+
++/*
++ * Find right freq to be set now with powersave_bias on.
++ * Returns the freq_hi to be used right now and will set freq_hi_jiffies,
++ * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
++ */
++static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
++ unsigned int freq_next,
++ unsigned int relation)
++{
++ unsigned int freq_req, freq_reduc, freq_avg;
++ unsigned int freq_hi, freq_lo;
++ unsigned int index = 0;
++ unsigned int jiffies_total, jiffies_hi, jiffies_lo;
++ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu);
++
++ if (!dbs_info->freq_table) {
++ dbs_info->freq_lo = 0;
++ dbs_info->freq_lo_jiffies = 0;
++ return freq_next;
++ }
++
++ cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
++ relation, &index);
++ freq_req = dbs_info->freq_table[index].frequency;
++ freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000;
++ freq_avg = freq_req - freq_reduc;
++
++ /* Find freq bounds for freq_avg in freq_table */
++ index = 0;
++ cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
++ CPUFREQ_RELATION_H, &index);
++ freq_lo = dbs_info->freq_table[index].frequency;
++ index = 0;
++ cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
++ CPUFREQ_RELATION_L, &index);
++ freq_hi = dbs_info->freq_table[index].frequency;
++
++ /* Find out how long we have to be in hi and lo freqs */
++ if (freq_hi == freq_lo) {
++ dbs_info->freq_lo = 0;
++ dbs_info->freq_lo_jiffies = 0;
++ return freq_lo;
++ }
++ jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
++ jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
++ jiffies_hi += ((freq_hi - freq_lo) / 2);
++ jiffies_hi /= (freq_hi - freq_lo);
++ jiffies_lo = jiffies_total - jiffies_hi;
++ dbs_info->freq_lo = freq_lo;
++ dbs_info->freq_lo_jiffies = jiffies_lo;
++ dbs_info->freq_hi_jiffies = jiffies_hi;
++ return freq_hi;
++}
++
++static void ondemand_powersave_bias_init(void)
++{
++ int i;
++ for_each_online_cpu(i) {
++ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, i);
++ dbs_info->freq_table = cpufreq_frequency_get_table(i);
++ dbs_info->freq_lo = 0;
++ }
++}
++
+ /************************** sysfs interface ************************/
+ static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+ {
+@@ -124,6 +192,7 @@ static ssize_t show_##file_name \
+ show_one(sampling_rate, sampling_rate);
+ show_one(up_threshold, up_threshold);
+ show_one(ignore_nice_load, ignore_nice);
++show_one(powersave_bias, powersave_bias);
+
+ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+@@ -198,6 +267,27 @@ static ssize_t store_ignore_nice_load(st
+ return count;
+ }
+
++static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
++ const char *buf, size_t count)
++{
++ unsigned int input;
++ int ret;
++ ret = sscanf(buf, "%u", &input);
++
++ if (ret != 1)
++ return -EINVAL;
++
++ if (input > 1000)
++ input = 1000;
++
++ mutex_lock(&dbs_mutex);
++ dbs_tuners_ins.powersave_bias = input;
++ ondemand_powersave_bias_init();
++ mutex_unlock(&dbs_mutex);
++
++ return count;
++}
++
+ #define define_one_rw(_name) \
+ static struct freq_attr _name = \
+ __ATTR(_name, 0644, show_##_name, store_##_name)
+@@ -205,6 +295,7 @@ __ATTR(_name, 0644, show_##_name, store_
+ define_one_rw(sampling_rate);
+ define_one_rw(up_threshold);
+ define_one_rw(ignore_nice_load);
++define_one_rw(powersave_bias);
+
+ static struct attribute * dbs_attributes[] = {
+ &sampling_rate_max.attr,
+@@ -212,6 +303,7 @@ static struct attribute * dbs_attributes
+ &sampling_rate.attr,
+ &up_threshold.attr,
+ &ignore_nice_load.attr,
++ &powersave_bias.attr,
+ NULL
+ };
+
+@@ -234,6 +326,7 @@ static void dbs_check_cpu(struct cpu_dbs
+ if (!this_dbs_info->enable)
+ return;
+
++ this_dbs_info->freq_lo = 0;
+ policy = this_dbs_info->cur_policy;
+ cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
+ total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
+@@ -274,11 +367,18 @@ static void dbs_check_cpu(struct cpu_dbs
+ /* Check for frequency increase */
+ if (load > dbs_tuners_ins.up_threshold) {
+ /* if we are already at full speed then break out early */
+- if (policy->cur == policy->max)
+- return;
+-
+- __cpufreq_driver_target(policy, policy->max,
+- CPUFREQ_RELATION_H);
++ if (!dbs_tuners_ins.powersave_bias) {
++ if (policy->cur == policy->max)
++ return;
++
++ __cpufreq_driver_target(policy, policy->max,
++ CPUFREQ_RELATION_H);
++ } else {
++ int freq = powersave_bias_target(policy, policy->max,
++ CPUFREQ_RELATION_H);
++ __cpufreq_driver_target(policy, freq,
++ CPUFREQ_RELATION_L);
++ }
+ return;
+ }
+
+@@ -293,37 +393,64 @@ static void dbs_check_cpu(struct cpu_dbs
+ * policy. To be safe, we focus 10 points under the threshold.
+ */
+ if (load < (dbs_tuners_ins.up_threshold - 10)) {
+- unsigned int freq_next;
+- freq_next = (policy->cur * load) /
++ unsigned int freq_next = (policy->cur * load) /
+ (dbs_tuners_ins.up_threshold - 10);
+-
+- __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
++ if (!dbs_tuners_ins.powersave_bias) {
++ __cpufreq_driver_target(policy, freq_next,
++ CPUFREQ_RELATION_L);
++ } else {
++ int freq = powersave_bias_target(policy, freq_next,
++ CPUFREQ_RELATION_L);
++ __cpufreq_driver_target(policy, freq,
++ CPUFREQ_RELATION_L);
++ }
+ }
+ }
+
++/* Sampling types */
++enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
++
+ static void do_dbs_timer(void *data)
+ {
+ unsigned int cpu = smp_processor_id();
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
++ /* We want all CPUs to do sampling nearly on same jiffy */
++ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
++ delay -= jiffies % delay;
+
+ if (!dbs_info->enable)
+ return;
+-
+- lock_cpu_hotplug();
+- dbs_check_cpu(dbs_info);
+- unlock_cpu_hotplug();
+- queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work,
+- usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
++ /* Common NORMAL_SAMPLE setup */
++ INIT_WORK(&dbs_info->work, do_dbs_timer, (void *)DBS_NORMAL_SAMPLE);
++ if (!dbs_tuners_ins.powersave_bias ||
++ (unsigned long) data == DBS_NORMAL_SAMPLE) {
++ lock_cpu_hotplug();
++ dbs_check_cpu(dbs_info);
++ unlock_cpu_hotplug();
++ if (dbs_info->freq_lo) {
++ /* Setup timer for SUB_SAMPLE */
++ INIT_WORK(&dbs_info->work, do_dbs_timer,
++ (void *)DBS_SUB_SAMPLE);
++ delay = dbs_info->freq_hi_jiffies;
++ }
++ } else {
++ __cpufreq_driver_target(dbs_info->cur_policy,
++ dbs_info->freq_lo,
++ CPUFREQ_RELATION_H);
++ }
++ queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
+ }
+
+ static inline void dbs_timer_init(unsigned int cpu)
+ {
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
++ /* We want all CPUs to do sampling nearly on same jiffy */
++ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
++ delay -= jiffies % delay;
+
+- INIT_WORK(&dbs_info->work, do_dbs_timer, 0);
+- queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work,
+- usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+- return;
++ ondemand_powersave_bias_init();
++ INIT_WORK(&dbs_info->work, do_dbs_timer, NULL);
++ queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
+ }
+
+ static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
+diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
+index 25eee53..c2ecc59 100644
+--- a/drivers/cpufreq/cpufreq_stats.c
++++ b/drivers/cpufreq/cpufreq_stats.c
+@@ -350,12 +350,10 @@ __init cpufreq_stats_init(void)
+ }
+
+ register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
+- lock_cpu_hotplug();
+ for_each_online_cpu(cpu) {
+ cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
+ (void *)(long)cpu);
+ }
+- unlock_cpu_hotplug();
+ return 0;
+ }
+ static void
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 4263935..adb5541 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -2,22 +2,53 @@ menu "Hardware crypto devices"
+
+ config CRYPTO_DEV_PADLOCK
+ tristate "Support for VIA PadLock ACE"
+- depends on CRYPTO && X86_32
++ depends on X86_32
++ select CRYPTO_ALGAPI
++ default m
+ help
+ Some VIA processors come with an integrated crypto engine
+ (so called VIA PadLock ACE, Advanced Cryptography Engine)
+- that provides instructions for very fast {en,de}cryption
+- with some algorithms.
++ that provides instructions for very fast cryptographic
++ operations with supported algorithms.
+
+ The instructions are used only when the CPU supports them.
+- Otherwise software encryption is used. If you are unsure,
+- say Y.
++ Otherwise software encryption is used.
++
++ Selecting M for this option will compile a helper module
++ padlock.ko that should autoload all below configured
++ algorithms. Don't worry if your hardware does not support
++ some or all of them. In such case padlock.ko will
++ simply write a single line into the kernel log informing
++ about its failure but everything will keep working fine.
++
++ If you are unsure, say M. The compiled module will be
++ called padlock.ko
+
+ config CRYPTO_DEV_PADLOCK_AES
+- bool "Support for AES in VIA PadLock"
++ tristate "PadLock driver for AES algorithm"
+ depends on CRYPTO_DEV_PADLOCK
+- default y
++ select CRYPTO_BLKCIPHER
++ default m
+ help
+ Use VIA PadLock for AES algorithm.
+
++ Available in VIA C3 and newer CPUs.
++
++ If unsure say M. The compiled module will be
++ called padlock-aes.ko
++
++config CRYPTO_DEV_PADLOCK_SHA
++ tristate "PadLock driver for SHA1 and SHA256 algorithms"
++ depends on CRYPTO_DEV_PADLOCK
++ select CRYPTO_SHA1
++ select CRYPTO_SHA256
++ default m
++ help
++ Use VIA PadLock for SHA1/SHA256 algorithms.
++
++ Available in VIA C7 and newer processors.
++
++ If unsure say M. The compiled module will be
++ called padlock-sha.ko
++
+ endmenu
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index 45426ca..4c3d0ec 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -1,7 +1,3 @@
+-
+ obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o
+-
+-padlock-objs-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
+-
+-padlock-objs := padlock-generic.o $(padlock-objs-y)
+-
++obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
++obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
+diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
+index b643d71..d4501dc 100644
+--- a/drivers/crypto/padlock-aes.c
++++ b/drivers/crypto/padlock-aes.c
+@@ -43,11 +43,11 @@
+ * ---------------------------------------------------------------------------
+ */
+
++#include <crypto/algapi.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+ #include <linux/errno.h>
+-#include <linux/crypto.h>
+ #include <linux/interrupt.h>
+ #include <linux/kernel.h>
+ #include <asm/byteorder.h>
+@@ -59,6 +59,17 @@
+ #define AES_EXTENDED_KEY_SIZE 64 /* in uint32_t units */
+ #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
+
++/* Control word. */
++struct cword {
++ unsigned int __attribute__ ((__packed__))
++ rounds:4,
++ algo:3,
++ keygen:1,
++ interm:1,
++ encdec:1,
++ ksize:2;
++} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
++
+ /* Whenever making any changes to the following
+ * structure *make sure* you keep E, d_data
+ * and cword aligned on 16 Bytes boundaries!!! */
+@@ -286,9 +297,9 @@ aes_hw_extkey_available(uint8_t key_len)
+ return 0;
+ }
+
+-static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
++static inline struct aes_ctx *aes_ctx_common(void *ctx)
+ {
+- unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
++ unsigned long addr = (unsigned long)ctx;
+ unsigned long align = PADLOCK_ALIGNMENT;
+
+ if (align <= crypto_tfm_ctx_alignment())
+@@ -296,16 +307,27 @@ static inline struct aes_ctx *aes_ctx(st
+ return (struct aes_ctx *)ALIGN(addr, align);
+ }
+
++static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
++{
++ return aes_ctx_common(crypto_tfm_ctx(tfm));
++}
++
++static inline struct aes_ctx *blk_aes_ctx(struct crypto_blkcipher *tfm)
++{
++ return aes_ctx_common(crypto_blkcipher_ctx(tfm));
++}
++
+ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+- unsigned int key_len, u32 *flags)
++ unsigned int key_len)
+ {
+ struct aes_ctx *ctx = aes_ctx(tfm);
+ const __le32 *key = (const __le32 *)in_key;
++ u32 *flags = &tfm->crt_flags;
+ uint32_t i, t, u, v, w;
+ uint32_t P[AES_EXTENDED_KEY_SIZE];
+ uint32_t rounds;
+
+- if (key_len != 16 && key_len != 24 && key_len != 32) {
++ if (key_len % 8) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+@@ -430,80 +452,212 @@ static void aes_decrypt(struct crypto_tf
+ 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)
++static struct crypto_alg aes_alg = {
++ .cra_name = "aes",
++ .cra_driver_name = "aes-padlock",
++ .cra_priority = PADLOCK_CRA_PRIORITY,
++ .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 = {
++ .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 ecb_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
+ {
+- struct aes_ctx *ctx = aes_ctx(desc->tfm);
+- padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt,
+- nbytes / AES_BLOCK_SIZE);
+- return nbytes & ~(AES_BLOCK_SIZE - 1);
++ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
++ ctx->E, &ctx->cword.encrypt,
++ nbytes / AES_BLOCK_SIZE);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
+ }
+
+-static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int ecb_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
+ {
+- struct aes_ctx *ctx = aes_ctx(desc->tfm);
+- padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt,
+- nbytes / AES_BLOCK_SIZE);
+- return nbytes & ~(AES_BLOCK_SIZE - 1);
++ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
++ ctx->D, &ctx->cword.decrypt,
++ nbytes / AES_BLOCK_SIZE);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
+ }
+
+-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(desc->tfm);
+- u8 *iv;
++static struct crypto_alg ecb_aes_alg = {
++ .cra_name = "ecb(aes)",
++ .cra_driver_name = "ecb-aes-padlock",
++ .cra_priority = PADLOCK_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct aes_ctx),
++ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .setkey = aes_set_key,
++ .encrypt = ecb_aes_encrypt,
++ .decrypt = ecb_aes_decrypt,
++ }
++ }
++};
+
+- iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info,
+- &ctx->cword.encrypt, nbytes / AES_BLOCK_SIZE);
+- memcpy(desc->info, iv, AES_BLOCK_SIZE);
++static int cbc_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = padlock_xcrypt_cbc(walk.src.virt.addr,
++ walk.dst.virt.addr, ctx->E,
++ walk.iv, &ctx->cword.encrypt,
++ nbytes / AES_BLOCK_SIZE);
++ memcpy(walk.iv, iv, AES_BLOCK_SIZE);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
+
+- return nbytes & ~(AES_BLOCK_SIZE - 1);
++ return err;
+ }
+
+-static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+- const u8 *in, unsigned int nbytes)
++static int cbc_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes)
+ {
+- struct aes_ctx *ctx = aes_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);
++ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ padlock_xcrypt_cbc(walk.src.virt.addr, walk.dst.virt.addr,
++ ctx->D, walk.iv, &ctx->cword.decrypt,
++ nbytes / AES_BLOCK_SIZE);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
+ }
+
+-static struct crypto_alg aes_alg = {
+- .cra_name = "aes",
+- .cra_driver_name = "aes-padlock",
+- .cra_priority = 300,
+- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++static struct crypto_alg cbc_aes_alg = {
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "cbc-aes-padlock",
++ .cra_priority = PADLOCK_COMPOSITE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
++ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+- .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
++ .cra_list = LIST_HEAD_INIT(cbc_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,
+- .cia_encrypt_ecb = aes_encrypt_ecb,
+- .cia_decrypt_ecb = aes_decrypt_ecb,
+- .cia_encrypt_cbc = aes_encrypt_cbc,
+- .cia_decrypt_cbc = aes_decrypt_cbc,
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = aes_set_key,
++ .encrypt = cbc_aes_encrypt,
++ .decrypt = cbc_aes_decrypt,
+ }
+ }
+ };
+
+-int __init padlock_init_aes(void)
++static int __init padlock_init(void)
+ {
+- printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
++ int ret;
++
++ if (!cpu_has_xcrypt) {
++ printk(KERN_ERR PFX "VIA PadLock not detected.\n");
++ return -ENODEV;
++ }
++
++ if (!cpu_has_xcrypt_enabled) {
++ printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
++ return -ENODEV;
++ }
+
+ gen_tabs();
+- return crypto_register_alg(&aes_alg);
++ if ((ret = crypto_register_alg(&aes_alg)))
++ goto aes_err;
++
++ if ((ret = crypto_register_alg(&ecb_aes_alg)))
++ goto ecb_aes_err;
++
++ if ((ret = crypto_register_alg(&cbc_aes_alg)))
++ goto cbc_aes_err;
++
++ printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
++
++out:
++ return ret;
++
++cbc_aes_err:
++ crypto_unregister_alg(&ecb_aes_alg);
++ecb_aes_err:
++ crypto_unregister_alg(&aes_alg);
++aes_err:
++ printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
++ goto out;
+ }
+
+-void __exit padlock_fini_aes(void)
++static void __exit padlock_fini(void)
+ {
++ crypto_unregister_alg(&cbc_aes_alg);
++ crypto_unregister_alg(&ecb_aes_alg);
+ crypto_unregister_alg(&aes_alg);
+ }
++
++module_init(padlock_init);
++module_exit(padlock_fini);
++
++MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Michal Ludvig");
++
++MODULE_ALIAS("aes-padlock");
+diff --git a/drivers/crypto/padlock-generic.c b/drivers/crypto/padlock-generic.c
+deleted file mode 100644
+index 18cf0e8..0000000
+--- a/drivers/crypto/padlock-generic.c
++++ /dev/null
+@@ -1,63 +0,0 @@
+-/*
+- * Cryptographic API.
+- *
+- * Support for VIA PadLock hardware crypto engine.
+- *
+- * Copyright (c) 2004 Michal Ludvig <michal at logix.cz>
+- *
+- * 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/init.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/crypto.h>
+-#include <asm/byteorder.h>
+-#include "padlock.h"
+-
+-static int __init
+-padlock_init(void)
+-{
+- int ret = -ENOSYS;
+-
+- if (!cpu_has_xcrypt) {
+- printk(KERN_ERR PFX "VIA PadLock not detected.\n");
+- return -ENODEV;
+- }
+-
+- if (!cpu_has_xcrypt_enabled) {
+- printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+- return -ENODEV;
+- }
+-
+-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
+- if ((ret = padlock_init_aes())) {
+- printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
+- return ret;
+- }
+-#endif
+-
+- if (ret == -ENOSYS)
+- printk(KERN_ERR PFX "Hmm, VIA PadLock was compiled without any algorithm.\n");
+-
+- return ret;
+-}
+-
+-static void __exit
+-padlock_fini(void)
+-{
+-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
+- padlock_fini_aes();
+-#endif
+-}
+-
+-module_init(padlock_init);
+-module_exit(padlock_fini);
+-
+-MODULE_DESCRIPTION("VIA PadLock crypto engine support.");
+-MODULE_LICENSE("Dual BSD/GPL");
+-MODULE_AUTHOR("Michal Ludvig");
+diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
+new file mode 100644
+index 0000000..a781fd2
+--- /dev/null
++++ b/drivers/crypto/padlock-sha.c
+@@ -0,0 +1,318 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for VIA PadLock hardware crypto engine.
++ *
++ * Copyright (c) 2006 Michal Ludvig <michal at logix.cz>
++ *
++ * 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 <crypto/algapi.h>
++#include <linux/err.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/cryptohash.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/scatterlist.h>
++#include "padlock.h"
++
++#define SHA1_DEFAULT_FALLBACK "sha1-generic"
++#define SHA1_DIGEST_SIZE 20
++#define SHA1_HMAC_BLOCK_SIZE 64
++
++#define SHA256_DEFAULT_FALLBACK "sha256-generic"
++#define SHA256_DIGEST_SIZE 32
++#define SHA256_HMAC_BLOCK_SIZE 64
++
++struct padlock_sha_ctx {
++ char *data;
++ size_t used;
++ int bypass;
++ void (*f_sha_padlock)(const char *in, char *out, int count);
++ struct hash_desc fallback;
++};
++
++static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm)
++{
++ return crypto_tfm_ctx(tfm);
++}
++
++/* We'll need aligned address on the stack */
++#define NEAREST_ALIGNED(ptr) \
++ ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT))
++
++static struct crypto_alg sha1_alg, sha256_alg;
++
++static void padlock_sha_bypass(struct crypto_tfm *tfm)
++{
++ if (ctx(tfm)->bypass)
++ return;
++
++ crypto_hash_init(&ctx(tfm)->fallback);
++ if (ctx(tfm)->data && ctx(tfm)->used) {
++ struct scatterlist sg;
++
++ sg_set_buf(&sg, ctx(tfm)->data, ctx(tfm)->used);
++ crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length);
++ }
++
++ ctx(tfm)->used = 0;
++ ctx(tfm)->bypass = 1;
++}
++
++static void padlock_sha_init(struct crypto_tfm *tfm)
++{
++ ctx(tfm)->used = 0;
++ ctx(tfm)->bypass = 0;
++}
++
++static void padlock_sha_update(struct crypto_tfm *tfm,
++ const uint8_t *data, unsigned int length)
++{
++ /* Our buffer is always one page. */
++ if (unlikely(!ctx(tfm)->bypass &&
++ (ctx(tfm)->used + length > PAGE_SIZE)))
++ padlock_sha_bypass(tfm);
++
++ if (unlikely(ctx(tfm)->bypass)) {
++ struct scatterlist sg;
++ sg_set_buf(&sg, (uint8_t *)data, length);
++ crypto_hash_update(&ctx(tfm)->fallback, &sg, length);
++ return;
++ }
++
++ memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length);
++ ctx(tfm)->used += length;
++}
++
++static inline void padlock_output_block(uint32_t *src,
++ uint32_t *dst, size_t count)
++{
++ while (count--)
++ *dst++ = swab32(*src++);
++}
++
++static void padlock_do_sha1(const char *in, char *out, int count)
++{
++ /* We can't store directly to *out as it may be unaligned. */
++ /* BTW Don't reduce the buffer size below 128 Bytes!
++ * PadLock microcode needs it that big. */
++ char buf[128+16];
++ char *result = NEAREST_ALIGNED(buf);
++
++ ((uint32_t *)result)[0] = 0x67452301;
++ ((uint32_t *)result)[1] = 0xEFCDAB89;
++ ((uint32_t *)result)[2] = 0x98BADCFE;
++ ((uint32_t *)result)[3] = 0x10325476;
++ ((uint32_t *)result)[4] = 0xC3D2E1F0;
++
++ asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
++ : "+S"(in), "+D"(result)
++ : "c"(count), "a"(0));
++
++ padlock_output_block((uint32_t *)result, (uint32_t *)out, 5);
++}
++
++static void padlock_do_sha256(const char *in, char *out, int count)
++{
++ /* We can't store directly to *out as it may be unaligned. */
++ /* BTW Don't reduce the buffer size below 128 Bytes!
++ * PadLock microcode needs it that big. */
++ char buf[128+16];
++ char *result = NEAREST_ALIGNED(buf);
++
++ ((uint32_t *)result)[0] = 0x6A09E667;
++ ((uint32_t *)result)[1] = 0xBB67AE85;
++ ((uint32_t *)result)[2] = 0x3C6EF372;
++ ((uint32_t *)result)[3] = 0xA54FF53A;
++ ((uint32_t *)result)[4] = 0x510E527F;
++ ((uint32_t *)result)[5] = 0x9B05688C;
++ ((uint32_t *)result)[6] = 0x1F83D9AB;
++ ((uint32_t *)result)[7] = 0x5BE0CD19;
++
++ asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
++ : "+S"(in), "+D"(result)
++ : "c"(count), "a"(0));
++
++ padlock_output_block((uint32_t *)result, (uint32_t *)out, 8);
++}
++
++static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out)
++{
++ if (unlikely(ctx(tfm)->bypass)) {
++ crypto_hash_final(&ctx(tfm)->fallback, out);
++ ctx(tfm)->bypass = 0;
++ return;
++ }
++
++ /* Pass the input buffer to PadLock microcode... */
++ ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used);
++
++ ctx(tfm)->used = 0;
++}
++
++static int padlock_cra_init(struct crypto_tfm *tfm)
++{
++ const char *fallback_driver_name = tfm->__crt_alg->cra_name;
++ struct crypto_hash *fallback_tfm;
++
++ /* For now we'll allocate one page. This
++ * could eventually be configurable one day. */
++ ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL);
++ if (!ctx(tfm)->data)
++ return -ENOMEM;
++
++ /* Allocate a fallback and abort if it failed. */
++ fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
++ CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK);
++ if (IS_ERR(fallback_tfm)) {
++ printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n",
++ fallback_driver_name);
++ free_page((unsigned long)(ctx(tfm)->data));
++ return PTR_ERR(fallback_tfm);
++ }
++
++ ctx(tfm)->fallback.tfm = fallback_tfm;
++ return 0;
++}
++
++static int padlock_sha1_cra_init(struct crypto_tfm *tfm)
++{
++ ctx(tfm)->f_sha_padlock = padlock_do_sha1;
++
++ return padlock_cra_init(tfm);
++}
++
++static int padlock_sha256_cra_init(struct crypto_tfm *tfm)
++{
++ ctx(tfm)->f_sha_padlock = padlock_do_sha256;
++
++ return padlock_cra_init(tfm);
++}
++
++static void padlock_cra_exit(struct crypto_tfm *tfm)
++{
++ if (ctx(tfm)->data) {
++ free_page((unsigned long)(ctx(tfm)->data));
++ ctx(tfm)->data = NULL;
++ }
++
++ crypto_free_hash(ctx(tfm)->fallback.tfm);
++ ctx(tfm)->fallback.tfm = NULL;
++}
++
++static struct crypto_alg sha1_alg = {
++ .cra_name = "sha1",
++ .cra_driver_name = "sha1-padlock",
++ .cra_priority = PADLOCK_CRA_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list),
++ .cra_init = padlock_sha1_cra_init,
++ .cra_exit = padlock_cra_exit,
++ .cra_u = {
++ .digest = {
++ .dia_digestsize = SHA1_DIGEST_SIZE,
++ .dia_init = padlock_sha_init,
++ .dia_update = padlock_sha_update,
++ .dia_final = padlock_sha_final,
++ }
++ }
++};
++
++static struct crypto_alg sha256_alg = {
++ .cra_name = "sha256",
++ .cra_driver_name = "sha256-padlock",
++ .cra_priority = PADLOCK_CRA_PRIORITY,
++ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA256_HMAC_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list),
++ .cra_init = padlock_sha256_cra_init,
++ .cra_exit = padlock_cra_exit,
++ .cra_u = {
++ .digest = {
++ .dia_digestsize = SHA256_DIGEST_SIZE,
++ .dia_init = padlock_sha_init,
++ .dia_update = padlock_sha_update,
++ .dia_final = padlock_sha_final,
++ }
++ }
++};
++
++static void __init padlock_sha_check_fallbacks(void)
++{
++ if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK))
++ printk(KERN_WARNING PFX
++ "Couldn't load fallback module for sha1.\n");
++
++ if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK))
++ printk(KERN_WARNING PFX
++ "Couldn't load fallback module for sha256.\n");
++}
++
++static int __init padlock_init(void)
++{
++ int rc = -ENODEV;
++
++ if (!cpu_has_phe) {
++ printk(KERN_ERR PFX "VIA PadLock Hash Engine not detected.\n");
++ return -ENODEV;
++ }
++
++ if (!cpu_has_phe_enabled) {
++ printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
++ return -ENODEV;
++ }
++
++ padlock_sha_check_fallbacks();
++
++ rc = crypto_register_alg(&sha1_alg);
++ if (rc)
++ goto out;
++
++ rc = crypto_register_alg(&sha256_alg);
++ if (rc)
++ goto out_unreg1;
++
++ printk(KERN_NOTICE PFX "Using VIA PadLock ACE for SHA1/SHA256 algorithms.\n");
++
++ return 0;
++
++out_unreg1:
++ crypto_unregister_alg(&sha1_alg);
++out:
++ printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n");
++ return rc;
++}
++
++static void __exit padlock_fini(void)
++{
++ crypto_unregister_alg(&sha1_alg);
++ crypto_unregister_alg(&sha256_alg);
++}
++
++module_init(padlock_init);
++module_exit(padlock_fini);
++
++MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Michal Ludvig");
++
++MODULE_ALIAS("sha1-padlock");
++MODULE_ALIAS("sha256-padlock");
+diff --git a/drivers/crypto/padlock.c b/drivers/crypto/padlock.c
+new file mode 100644
+index 0000000..d6d7dd5
+--- /dev/null
++++ b/drivers/crypto/padlock.c
+@@ -0,0 +1,58 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for VIA PadLock hardware crypto engine.
++ *
++ * Copyright (c) 2006 Michal Ludvig <michal at logix.cz>
++ *
++ * 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/init.h>
++#include <linux/errno.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/scatterlist.h>
++#include "padlock.h"
++
++static int __init padlock_init(void)
++{
++ int success = 0;
++
++ if (crypto_has_cipher("aes-padlock", 0, 0))
++ success++;
++
++ if (crypto_has_hash("sha1-padlock", 0, 0))
++ success++;
++
++ if (crypto_has_hash("sha256-padlock", 0, 0))
++ success++;
++
++ if (!success) {
++ printk(KERN_WARNING PFX "No VIA PadLock drivers have been loaded.\n");
++ return -ENODEV;
++ }
++
++ printk(KERN_NOTICE PFX "%d drivers are available.\n", success);
++
++ return 0;
++}
++
++static void __exit padlock_fini(void)
++{
++}
++
++module_init(padlock_init);
++module_exit(padlock_fini);
++
++MODULE_DESCRIPTION("Load all configured PadLock algorithms.");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Michal Ludvig");
++
+diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h
+index b78489b..b728e45 100644
+--- a/drivers/crypto/padlock.h
++++ b/drivers/crypto/padlock.h
+@@ -15,22 +15,9 @@
+
+ #define PADLOCK_ALIGNMENT 16
+
+-/* Control word. */
+-struct cword {
+- unsigned int __attribute__ ((__packed__))
+- rounds:4,
+- algo:3,
+- keygen:1,
+- interm:1,
+- encdec:1,
+- ksize:2;
+-} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
+-
+ #define PFX "padlock: "
+
+-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
+-int padlock_init_aes(void);
+-void padlock_fini_aes(void);
+-#endif
++#define PADLOCK_CRA_PRIORITY 300
++#define PADLOCK_COMPOSITE_PRIORITY 400
+
+ #endif /* _CRYPTO_PADLOCK_H */
+diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
+index dbd4d6c..0358419 100644
+--- a/drivers/dma/ioatdma.c
++++ b/drivers/dma/ioatdma.c
+@@ -80,7 +80,7 @@ static int enumerate_dma_channels(struct
+
+ static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
+ struct ioat_dma_chan *ioat_chan,
+- int flags)
++ gfp_t flags)
+ {
+ struct ioat_dma_descriptor *desc;
+ struct ioat_desc_sw *desc_sw;
+@@ -563,7 +563,7 @@ static struct pci_driver ioat_pci_drv =
+ .remove = __devexit_p(ioat_remove),
+ };
+
+-static irqreturn_t ioat_do_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t ioat_do_interrupt(int irq, void *data)
+ {
+ struct ioat_device *instance = data;
+ unsigned long attnstatus;
+@@ -686,7 +686,7 @@ static int __devinit ioat_probe(struct p
+ {
+ int err;
+ unsigned long mmio_start, mmio_len;
+- void *reg_base;
++ void __iomem *reg_base;
+ struct ioat_device *device;
+
+ err = pci_enable_device(pdev);
+diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
+index a5d3b36..62b26a9 100644
+--- a/drivers/dma/ioatdma.h
++++ b/drivers/dma/ioatdma.h
+@@ -44,7 +44,7 @@ extern struct list_head dma_client_list;
+
+ struct ioat_device {
+ struct pci_dev *pdev;
+- void *reg_base;
++ void __iomem *reg_base;
+ struct pci_pool *dma_pool;
+ struct pci_pool *completion_pool;
+
+@@ -73,7 +73,7 @@ struct ioat_device {
+
+ struct ioat_dma_chan {
+
+- void *reg_base;
++ void __iomem *reg_base;
+
+ dma_cookie_t completed_cookie;
+ unsigned long last_completion;
+diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
+index 4bde30b..75e9e38 100644
+--- a/drivers/edac/edac_mc.c
++++ b/drivers/edac/edac_mc.c
+@@ -230,34 +230,43 @@ static struct kobj_type ktype_memctrl =
+ */
+ static int edac_sysfs_memctrl_setup(void)
+ {
+- int err=0;
++ int err = 0;
+
+ debugf1("%s()\n", __func__);
+
+ /* create the /sys/devices/system/edac directory */
+ err = sysdev_class_register(&edac_class);
+
+- if (!err) {
+- /* Init the MC's kobject */
+- memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
+- edac_memctrl_kobj.parent = &edac_class.kset.kobj;
+- edac_memctrl_kobj.ktype = &ktype_memctrl;
++ if (err) {
++ debugf1("%s() error=%d\n", __func__, err);
++ return err;
++ }
+
+- /* generate sysfs "..../edac/mc" */
+- err = kobject_set_name(&edac_memctrl_kobj,"mc");
++ /* Init the MC's kobject */
++ memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
++ edac_memctrl_kobj.parent = &edac_class.kset.kobj;
++ edac_memctrl_kobj.ktype = &ktype_memctrl;
+
+- if (!err) {
+- /* FIXME: maybe new sysdev_create_subdir() */
+- err = kobject_register(&edac_memctrl_kobj);
++ /* generate sysfs "..../edac/mc" */
++ err = kobject_set_name(&edac_memctrl_kobj,"mc");
+
+- if (err)
+- debugf1("Failed to register '.../edac/mc'\n");
+- else
+- debugf1("Registered '.../edac/mc' kobject\n");
+- }
+- } else
+- debugf1("%s() error=%d\n", __func__, err);
++ if (err)
++ goto fail;
++
++ /* FIXME: maybe new sysdev_create_subdir() */
++ err = kobject_register(&edac_memctrl_kobj);
++
++ if (err) {
++ debugf1("Failed to register '.../edac/mc'\n");
++ goto fail;
++ }
+
++ debugf1("Registered '.../edac/mc' kobject\n");
++
++ return 0;
++
++fail:
++ sysdev_class_unregister(&edac_class);
+ return err;
+ }
+
+diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
+index 6078e2f..d944647 100644
+--- a/drivers/eisa/eisa-bus.c
++++ b/drivers/eisa/eisa-bus.c
+@@ -128,9 +128,23 @@ static int eisa_bus_match (struct device
+ return 0;
+ }
+
++static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
++ char *buffer, int buffer_size)
++{
++ struct eisa_device *edev = to_eisa_device(dev);
++ int i = 0;
++ int length = 0;
++
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
++ envp[i] = NULL;
++ return 0;
++}
++
+ struct bus_type eisa_bus_type = {
+ .name = "eisa",
+ .match = eisa_bus_match,
++ .uevent = eisa_bus_uevent,
+ };
+
+ int eisa_driver_register (struct eisa_driver *edrv)
+@@ -160,6 +174,14 @@ static ssize_t eisa_show_state (struct d
+
+ static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL);
+
++static ssize_t eisa_show_modalias (struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct eisa_device *edev = to_eisa_device (dev);
++ return sprintf (buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
++}
++
++static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL);
++
+ static int __init eisa_init_device (struct eisa_root_device *root,
+ struct eisa_device *edev,
+ int slot)
+@@ -204,13 +226,26 @@ static int __init eisa_init_device (stru
+
+ static int __init eisa_register_device (struct eisa_device *edev)
+ {
+- if (device_register (&edev->dev))
+- return -1;
++ int rc = device_register (&edev->dev);
++ if (rc)
++ return rc;
+
+- device_create_file (&edev->dev, &dev_attr_signature);
+- device_create_file (&edev->dev, &dev_attr_enabled);
++ rc = device_create_file (&edev->dev, &dev_attr_signature);
++ if (rc) goto err_devreg;
++ rc = device_create_file (&edev->dev, &dev_attr_enabled);
++ if (rc) goto err_sig;
++ rc = device_create_file (&edev->dev, &dev_attr_modalias);
++ if (rc) goto err_enab;
+
+ return 0;
++
++err_enab:
++ device_remove_file (&edev->dev, &dev_attr_enabled);
++err_sig:
++ device_remove_file (&edev->dev, &dev_attr_signature);
++err_devreg:
++ device_unregister(&edev->dev);
++ return rc;
+ }
+
+ static int __init eisa_request_resources (struct eisa_root_device *root,
+diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
+index 1a159e8..ca4e67a 100644
+--- a/drivers/fc4/fc.c
++++ b/drivers/fc4/fc.c
+@@ -70,9 +70,9 @@
+
+ #define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp))
+ #define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->device->host->hostdata[0]))
+-#define SC_FCMND(fcmnd) ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp)))
++#define SC_FCMND(fcmnd) ((struct scsi_cmnd *)((long)fcmnd - (long)&(((struct scsi_cmnd *)0)->SCp)))
+
+-static int fcp_scsi_queue_it(fc_channel *, Scsi_Cmnd *, fcp_cmnd *, int);
++static int fcp_scsi_queue_it(fc_channel *, struct scsi_cmnd *, fcp_cmnd *, int);
+ void fcp_queue_empty(fc_channel *);
+
+ static void fcp_scsi_insert_queue (fc_channel *fc, fcp_cmnd *fcmd)
+@@ -378,14 +378,14 @@ void fcp_register(fc_channel *fc, u8 typ
+ printk ("FC: %segistering unknown type %02x\n", unregister ? "Unr" : "R", type);
+ }
+
+-static void fcp_scsi_done(Scsi_Cmnd *SCpnt);
++static void fcp_scsi_done(struct scsi_cmnd *SCpnt);
+
+ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hdr *fch)
+ {
+ fcp_cmnd *fcmd;
+ fcp_rsp *rsp;
+ int host_status;
+- Scsi_Cmnd *SCpnt;
++ struct scsi_cmnd *SCpnt;
+ int sense_len;
+ int rsp_status;
+
+@@ -757,13 +757,14 @@ void fcp_release(fc_channel *fcchain, in
+ }
+
+
+-static void fcp_scsi_done (Scsi_Cmnd *SCpnt)
++static void fcp_scsi_done(struct scsi_cmnd *SCpnt)
+ {
+ if (FCP_CMND(SCpnt)->done)
+ FCP_CMND(SCpnt)->done(SCpnt);
+ }
+
+-static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare)
++static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt,
++ fcp_cmnd *fcmd, int prepare)
+ {
+ long i;
+ fcp_cmd *cmd;
+@@ -837,7 +838,8 @@ static int fcp_scsi_queue_it(fc_channel
+ return 0;
+ }
+
+-int fcp_scsi_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *))
++int fcp_scsi_queuecommand(struct scsi_cmnd *SCpnt,
++ void (* done)(struct scsi_cmnd *))
+ {
+ fcp_cmnd *fcmd = FCP_CMND(SCpnt);
+ fc_channel *fc = FC_SCMND(SCpnt);
+@@ -873,7 +875,7 @@ void fcp_queue_empty(fc_channel *fc)
+ }
+ }
+
+-int fcp_scsi_abort(Scsi_Cmnd *SCpnt)
++int fcp_scsi_abort(struct scsi_cmnd *SCpnt)
+ {
+ /* Internal bookkeeping only. Lose 1 cmd_slots slot. */
+ fcp_cmnd *fcmd = FCP_CMND(SCpnt);
+@@ -910,7 +912,7 @@ int fcp_scsi_abort(Scsi_Cmnd *SCpnt)
+ }
+
+ #if 0
+-void fcp_scsi_reset_done(Scsi_Cmnd *SCpnt)
++void fcp_scsi_reset_done(struct scsi_cmnd *SCpnt)
+ {
+ fc_channel *fc = FC_SCMND(SCpnt);
+
+@@ -921,7 +923,7 @@ void fcp_scsi_reset_done(Scsi_Cmnd *SCpn
+
+ #define FCP_RESET_TIMEOUT (2*HZ)
+
+-int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
++int fcp_scsi_dev_reset(struct scsi_cmnd *SCpnt)
+ {
+ #if 0 /* broken junk, but if davem wants to compile this driver, let him.. */
+ unsigned long flags;
+@@ -931,7 +933,7 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
+ DECLARE_MUTEX_LOCKED(sem);
+
+ if (!fc->rst_pkt) {
+- fc->rst_pkt = (Scsi_Cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL);
++ fc->rst_pkt = (struct scsi_cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL);
+ if (!fc->rst_pkt) return FAILED;
+
+ fcmd = FCP_CMND(fc->rst_pkt);
+@@ -974,7 +976,6 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
+ */
+
+ fc->rst_pkt->device->host->eh_action = &sem;
+- fc->rst_pkt->request->rq_status = RQ_SCSI_BUSY;
+
+ fc->rst_pkt->done = fcp_scsi_reset_done;
+
+@@ -1000,7 +1001,7 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
+ return SUCCESS;
+ }
+
+-static int __fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
++static int __fcp_scsi_host_reset(struct scsi_cmnd *SCpnt)
+ {
+ fc_channel *fc = FC_SCMND(SCpnt);
+ fcp_cmnd *fcmd = FCP_CMND(SCpnt);
+@@ -1021,7 +1022,7 @@ static int __fcp_scsi_host_reset(Scsi_Cm
+ else return FAILED;
+ }
+
+-int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
++int fcp_scsi_host_reset(struct scsi_cmnd *SCpnt)
+ {
+ unsigned long flags;
+ int rc;
+diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h
+index c397c84..1ac6133 100644
+--- a/drivers/fc4/fcp_impl.h
++++ b/drivers/fc4/fcp_impl.h
+@@ -39,7 +39,7 @@ struct _fc_channel;
+ typedef struct fcp_cmnd {
+ struct fcp_cmnd *next;
+ struct fcp_cmnd *prev;
+- void (*done)(Scsi_Cmnd *);
++ void (*done)(struct scsi_cmnd *);
+ unsigned short proto;
+ unsigned short token;
+ unsigned int did;
+@@ -94,14 +94,14 @@ typedef struct _fc_channel {
+ long *scsi_bitmap;
+ long scsi_bitmap_end;
+ int scsi_free;
+- int (*encode_addr)(Scsi_Cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *);
++ int (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *);
+ fcp_cmnd *scsi_que;
+ char scsi_name[4];
+ fcp_cmnd **cmd_slots;
+ int channels;
+ int targets;
+ long *ages;
+- Scsi_Cmnd *rst_pkt;
++ struct scsi_cmnd *rst_pkt;
+ fcp_posmap *posmap;
+ /* LOGIN stuff */
+ fcp_cmnd *login;
+@@ -155,9 +155,10 @@ int fc_do_prli(fc_channel *, unsigned ch
+ for_each_fc_channel(fc) \
+ if (fc->state == FC_STATE_ONLINE)
+
+-int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+-int fcp_scsi_abort(Scsi_Cmnd *);
+-int fcp_scsi_dev_reset(Scsi_Cmnd *);
+-int fcp_scsi_host_reset(Scsi_Cmnd *);
++int fcp_scsi_queuecommand(struct scsi_cmnd *,
++ void (* done) (struct scsi_cmnd *));
++int fcp_scsi_abort(struct scsi_cmnd *);
++int fcp_scsi_dev_reset(struct scsi_cmnd *);
++int fcp_scsi_host_reset(struct scsi_cmnd *);
+
+ #endif /* !(_FCP_SCSI_H) */
+diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
+index 3b07e0c..b09dfc7 100644
+--- a/drivers/fc4/soc.c
++++ b/drivers/fc4/soc.c
+@@ -334,7 +334,7 @@ update_out:
+ }
+ }
+
+-static irqreturn_t soc_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t soc_intr(int irq, void *dev_id)
+ {
+ u32 cmd;
+ unsigned long flags;
+diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
+index 2b75edc..a6b1ae2 100644
+--- a/drivers/fc4/socal.c
++++ b/drivers/fc4/socal.c
+@@ -404,7 +404,7 @@ update_out:
+ }
+ }
+
+-static irqreturn_t socal_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t socal_intr(int irq, void *dev_id)
+ {
+ u32 cmd;
+ unsigned long flags;
+diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
+index 731c3d5..88f4621 100644
+--- a/drivers/firmware/Kconfig
++++ b/drivers/firmware/Kconfig
+@@ -64,7 +64,7 @@ config DELL_RBU
+ help
+ Say m if you want to have the option of updating the BIOS for your
+ DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
+- supporting application to comunicate with the BIOS regarding the new
++ supporting application to communicate with the BIOS regarding the new
+ image for the image update to take effect.
+ See <file:Documentation/dell_rbu.txt> for more details on the driver.
+
+diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
+index 339f405..1865b56 100644
+--- a/drivers/firmware/dcdbas.c
++++ b/drivers/firmware/dcdbas.c
+@@ -8,7 +8,7 @@
+ *
+ * See Documentation/dcdbas.txt for more information.
+ *
+- * Copyright (C) 1995-2005 Dell Inc.
++ * Copyright (C) 1995-2006 Dell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+@@ -40,7 +40,7 @@
+ #include "dcdbas.h"
+
+ #define DRIVER_NAME "dcdbas"
+-#define DRIVER_VERSION "5.6.0-2"
++#define DRIVER_VERSION "5.6.0-3.2"
+ #define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
+
+ static struct platform_device *dcdbas_pdev;
+@@ -175,6 +175,9 @@ static ssize_t smi_data_write(struct kob
+ {
+ ssize_t ret;
+
++ if ((pos + count) > MAX_SMI_DATA_BUF_SIZE)
++ return -EINVAL;
++
+ mutex_lock(&smi_data_lock);
+
+ ret = smi_data_buf_realloc(pos + count);
+@@ -559,7 +562,7 @@ static int __devinit dcdbas_probe(struct
+ while (--i >= 0)
+ sysfs_remove_bin_file(&dev->dev.kobj,
+ dcdbas_bin_attrs[i]);
+- sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
++ sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
+ return error;
+ }
+ }
+diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
+index 23b0866..08b1617 100644
+--- a/drivers/firmware/dell_rbu.c
++++ b/drivers/firmware/dell_rbu.c
+@@ -227,7 +227,7 @@ static int packetize_data(void *data, si
+ int packet_length;
+ u8 *temp;
+ u8 *end = (u8 *) data + length;
+- pr_debug("packetize_data: data length %d\n", length);
++ pr_debug("packetize_data: data length %zd\n", length);
+ if (!rbu_data.packetsize) {
+ printk(KERN_WARNING
+ "dell_rbu: packetsize not specified\n");
+@@ -249,7 +249,7 @@ static int packetize_data(void *data, si
+ if ((rc = create_packet(temp, packet_length)))
+ return rc;
+
+- pr_debug("%lu:%lu\n", temp, (end - temp));
++ pr_debug("%p:%td\n", temp, (end - temp));
+ temp += packet_length;
+ }
+
+@@ -718,14 +718,27 @@ static int __init dcdrbu_init(void)
+ return -EIO;
+ }
+
+- sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
+- sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
+- sysfs_create_bin_file(&rbu_device->dev.kobj,
++ rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
++ if (rc)
++ goto out_devreg;
++ rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
++ if (rc)
++ goto out_data;
++ rc = sysfs_create_bin_file(&rbu_device->dev.kobj,
+ &rbu_packet_size_attr);
++ if (rc)
++ goto out_imtype;
+
+ rbu_data.entry_created = 0;
+- return rc;
++ return 0;
+
++out_imtype:
++ sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
++out_data:
++ sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
++out_devreg:
++ platform_device_unregister(rbu_device);
++ return rc;
+ }
+
+ static __exit void dcdrbu_exit(void)
+diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
+index b9e3886..37deee6 100644
+--- a/drivers/firmware/dmi_scan.c
++++ b/drivers/firmware/dmi_scan.c
+@@ -123,6 +123,26 @@ static void __init dmi_save_devices(stru
+ dev->type = *d++ & 0x7f;
+ dev->name = dmi_string(dm, *d);
+ dev->device_data = NULL;
++ list_add(&dev->list, &dmi_devices);
++ }
++}
++
++static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
++{
++ int i, count = *(u8 *)(dm + 1);
++ struct dmi_device *dev;
++
++ for (i = 1; i <= count; i++) {
++ dev = dmi_alloc(sizeof(*dev));
++ if (!dev) {
++ printk(KERN_ERR
++ "dmi_save_oem_strings_devices: out of memory.\n");
++ break;
++ }
++
++ dev->type = DMI_DEV_TYPE_OEM_STRING;
++ dev->name = dmi_string(dm, i);
++ dev->device_data = NULL;
+
+ list_add(&dev->list, &dmi_devices);
+ }
+@@ -181,6 +201,9 @@ static void __init dmi_decode(struct dmi
+ case 10: /* Onboard Devices Information */
+ dmi_save_devices(dm);
+ break;
++ case 11: /* OEM Strings */
++ dmi_save_oem_strings_devices(dm);
++ break;
+ case 38: /* IPMI Device Information */
+ dmi_save_ipmi_device(dm);
+ }
+@@ -303,6 +326,26 @@ char *dmi_get_system_info(int field)
+ }
+ EXPORT_SYMBOL(dmi_get_system_info);
+
++
++/**
++ * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
++ * @str: Case sensitive Name
++ */
++int dmi_name_in_vendors(char *str)
++{
++ static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
++ DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
++ DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE };
++ int i;
++ for (i = 0; fields[i] != DMI_NONE; i++) {
++ int f = fields[i];
++ if (dmi_ident[f] && strstr(dmi_ident[f], str))
++ return 1;
++ }
++ return 0;
++}
++EXPORT_SYMBOL(dmi_name_in_vendors);
++
+ /**
+ * dmi_find_device - find onboard device by type/name
+ * @type: device type or %DMI_DEV_TYPE_ANY to match all device types
+diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
+index b4502ed..5c261e1 100644
+--- a/drivers/firmware/edd.c
++++ b/drivers/firmware/edd.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/i386/kernel/edd.c
++ * linux/drivers/firmware/edd.c
+ * Copyright (C) 2002, 2003, 2004 Dell Inc.
+ * by Matt Domsch <Matt_Domsch at dell.com>
+ * disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
+diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
+index 8ebce1c..5ab5e39 100644
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -639,7 +639,12 @@ efivar_create_sysfs_entry(unsigned long
+
+ kobject_set_name(&new_efivar->kobj, "%s", short_name);
+ kobj_set_kset_s(new_efivar, vars_subsys);
+- kobject_register(&new_efivar->kobj);
++ i = kobject_register(&new_efivar->kobj);
++ if (i) {
++ kfree(short_name);
++ kfree(new_efivar);
++ return 1;
++ }
+
+ kfree(short_name);
+ short_name = NULL;
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index 0e31a0c..e76d919 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -53,7 +53,7 @@ config SENSORS_ADM1021
+
+ config SENSORS_ADM1025
+ tristate "Analog Devices ADM1025 and compatibles"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ select HWMON_VID
+ help
+ If you say yes here you get support for Analog Devices ADM1025
+@@ -94,6 +94,18 @@ config SENSORS_ADM9240
+ This driver can also be built as a module. If so, the module
+ will be called adm9240.
+
++config SENSORS_K8TEMP
++ tristate "AMD Athlon64/FX or Opteron temperature sensor"
++ depends on HWMON && X86 && PCI && EXPERIMENTAL
++ help
++ If you say yes here you get support for the temperature
++ sensor(s) inside your CPU. Supported is whole AMD K8
++ microarchitecture. Please note that you will need at least
++ lm-sensors 2.10.1 for proper userspace support.
++
++ This driver can also be built as a module. If so, the module
++ will be called k8temp.
++
+ config SENSORS_ASB100
+ tristate "Asus ASB100 Bach"
+ depends on HWMON && I2C && EXPERIMENTAL
+@@ -121,7 +133,7 @@ config SENSORS_ATXP1
+
+ config SENSORS_DS1621
+ tristate "Dallas Semiconductor DS1621 and DS1625"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS1621 and DS1625 sensor chips.
+@@ -141,7 +153,7 @@ config SENSORS_F71805F
+
+ config SENSORS_FSCHER
+ tristate "FSC Hermes"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for Fujitsu Siemens
+ Computers Hermes sensor chips.
+@@ -151,7 +163,7 @@ config SENSORS_FSCHER
+
+ config SENSORS_FSCPOS
+ tristate "FSC Poseidon"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for Fujitsu Siemens
+ Computers Poseidon sensor chips.
+@@ -171,7 +183,7 @@ config SENSORS_GL518SM
+
+ config SENSORS_GL520SM
+ tristate "Genesys Logic GL520SM"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ select HWMON_VID
+ help
+ If you say yes here you get support for Genesys Logic GL520SM
+@@ -186,15 +198,15 @@ config SENSORS_IT87
+ select I2C_ISA
+ select HWMON_VID
+ help
+- If you say yes here you get support for ITE IT87xx sensor chips
+- and clones: SiS960.
++ If you say yes here you get support for ITE IT8705F, IT8712F,
++ IT8716F and IT8718F sensor chips, and the SiS960 clone.
+
+ 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
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for the National Semiconductor
+ LM63 remote diode digital temperature sensor with integrated fan
+@@ -231,7 +243,7 @@ config SENSORS_LM75
+
+ config SENSORS_LM77
+ tristate "National Semiconductor LM77"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for National Semiconductor LM77
+ sensor chips.
+@@ -241,7 +253,7 @@ config SENSORS_LM77
+
+ config SENSORS_LM78
+ tristate "National Semiconductor LM78 and compatibles"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ select I2C_ISA
+ select HWMON_VID
+ help
+@@ -284,7 +296,7 @@ config SENSORS_LM85
+
+ config SENSORS_LM87
+ tristate "National Semiconductor LM87"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ select HWMON_VID
+ help
+ If you say yes here you get support for National Semiconductor LM87
+@@ -309,7 +321,7 @@ config SENSORS_LM90
+
+ config SENSORS_LM92
+ tristate "National Semiconductor LM92 and compatibles"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for National Semiconductor LM92
+ and Maxim MAX6635 sensor chips.
+@@ -319,7 +331,7 @@ config SENSORS_LM92
+
+ config SENSORS_MAX1619
+ tristate "Maxim MAX1619 sensor chip"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ help
+ If you say yes here you get support for MAX1619 sensor chip.
+
+@@ -354,13 +366,13 @@ config SENSORS_SIS5595
+
+ config SENSORS_SMSC47M1
+ tristate "SMSC LPC47M10x and compatibles"
+- depends on HWMON && I2C && EXPERIMENTAL
++ depends on HWMON && I2C
+ 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, LPC47M192 and
+- LPC47M997 chips.
++ LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x,
++ LPC47M192 and LPC47M997 chips.
+
+ The temperature and voltage sensor features of the LPC47M192
+ and LPC47M997 are supported by another driver, select also
+@@ -407,8 +419,19 @@ config SENSORS_VIA686A
+ This driver can also be built as a module. If so, the module
+ will be called via686a.
+
++config SENSORS_VT1211
++ tristate "VIA VT1211"
++ depends on HWMON && EXPERIMENTAL
++ select HWMON_VID
++ help
++ If you say yes here then you get support for hardware monitoring
++ features of the VIA VT1211 Super-I/O chip.
++
++ This driver can also be built as a module. If so, the module
++ will be called vt1211.
++
+ config SENSORS_VT8231
+- tristate "VT8231"
++ tristate "VIA VT8231"
+ depends on HWMON && I2C && PCI && EXPERIMENTAL
+ select HWMON_VID
+ select I2C_ISA
+diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
+index 3141584..af01cc6 100644
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm
+ obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
+ obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
+ obj-$(CONFIG_SENSORS_IT87) += it87.o
++obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
+ obj-$(CONFIG_SENSORS_LM63) += lm63.o
+ obj-$(CONFIG_SENSORS_LM70) += lm70.o
+ obj-$(CONFIG_SENSORS_LM75) += lm75.o
+@@ -45,6 +46,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc4
+ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
+ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+ obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
++obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
+ obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
+ obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
+ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
+diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
+index 35ad1b0..e5cb0fd 100644
+--- a/drivers/hwmon/abituguru.c
++++ b/drivers/hwmon/abituguru.c
+@@ -1354,13 +1354,39 @@ LEAVE_UPDATE:
+ return NULL;
+ }
+
++#ifdef CONFIG_PM
++static int abituguru_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct abituguru_data *data = platform_get_drvdata(pdev);
++ /* make sure all communications with the uguru are done and no new
++ ones are started */
++ mutex_lock(&data->update_lock);
++ return 0;
++}
++
++static int abituguru_resume(struct platform_device *pdev)
++{
++ struct abituguru_data *data = platform_get_drvdata(pdev);
++ /* See if the uGuru is still ready */
++ if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT)
++ data->uguru_ready = 0;
++ mutex_unlock(&data->update_lock);
++ return 0;
++}
++#else
++#define abituguru_suspend NULL
++#define abituguru_resume NULL
++#endif /* CONFIG_PM */
++
+ static struct platform_driver abituguru_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = ABIT_UGURU_NAME,
+ },
+- .probe = abituguru_probe,
+- .remove = __devexit_p(abituguru_remove),
++ .probe = abituguru_probe,
++ .remove = __devexit_p(abituguru_remove),
++ .suspend = abituguru_suspend,
++ .resume = abituguru_resume,
+ };
+
+ static int __init abituguru_detect(void)
+diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
+index 2b6e74d..c466329 100644
+--- a/drivers/hwmon/adm1021.c
++++ b/drivers/hwmon/adm1021.c
+@@ -190,6 +190,21 @@ static int adm1021_attach_adapter(struct
+ return i2c_probe(adapter, &addr_data, adm1021_detect);
+ }
+
++static struct attribute *adm1021_attributes[] = {
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_min.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group adm1021_group = {
++ .attrs = adm1021_attributes,
++};
++
+ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+ int i;
+@@ -287,22 +302,19 @@ static int adm1021_detect(struct i2c_ada
+ adm1021_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
++ goto error2;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto error2;
++ goto error3;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+-
+ return 0;
+
++error3:
++ sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
+ error2:
+ i2c_detach_client(new_client);
+ error1:
+@@ -326,6 +338,7 @@ static int adm1021_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &adm1021_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
+index a4c859c..8c56288 100644
+--- a/drivers/hwmon/adm1025.c
++++ b/drivers/hwmon/adm1025.c
+@@ -315,6 +315,49 @@ static int adm1025_attach_adapter(struct
+ return i2c_probe(adapter, &addr_data, adm1025_detect);
+ }
+
++static struct attribute *adm1025_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in5_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in5_max.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp2_min.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ NULL
++};
++
++static const struct attribute_group adm1025_group = {
++ .attrs = adm1025_attributes,
++};
++
++static struct attribute *adm1025_attributes_opt[] = {
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++ NULL
++};
++
++static const struct attribute_group adm1025_group_opt = {
++ .attrs = adm1025_attributes_opt,
++};
++
+ /*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+@@ -415,46 +458,31 @@ static int adm1025_detect(struct i2c_ada
+ adm1025_init_client(new_client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group)))
+ goto exit_detach;
+- }
+-
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in5_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in5_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_in5_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+- device_create_file(&new_client->dev, &dev_attr_vrm);
+
+ /* Pin 11 is either in4 (+12V) or VID4 */
+ if (!(config & 0x20)) {
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in4_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_max)))
++ goto exit_remove;
++ }
++
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove;
+ }
+
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &adm1025_group);
++ sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -511,6 +539,8 @@ static int adm1025_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &adm1025_group);
++ sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
+index 6d4f8b8..b4618b2 100644
+--- a/drivers/hwmon/adm1026.c
++++ b/drivers/hwmon/adm1026.c
+@@ -323,15 +323,6 @@ static int adm1026_attach_adapter(struct
+ return i2c_probe(adapter, &addr_data, adm1026_detect);
+ }
+
+-static int adm1026_detach_client(struct i2c_client *client)
+-{
+- struct adm1026_data *data = i2c_get_clientdata(client);
+- hwmon_device_unregister(data->class_dev);
+- i2c_detach_client(client);
+- kfree(data);
+- return 0;
+-}
+-
+ static int adm1026_read_value(struct i2c_client *client, u8 reg)
+ {
+ int res;
+@@ -1450,6 +1441,135 @@ static DEVICE_ATTR(temp1_auto_point2_pwm
+ static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+ static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+
++static struct attribute *adm1026_attributes[] = {
++ &sensor_dev_attr_in0_input.dev_attr.attr,
++ &sensor_dev_attr_in0_max.dev_attr.attr,
++ &sensor_dev_attr_in0_min.dev_attr.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in5_input.dev_attr.attr,
++ &sensor_dev_attr_in5_max.dev_attr.attr,
++ &sensor_dev_attr_in5_min.dev_attr.attr,
++ &sensor_dev_attr_in6_input.dev_attr.attr,
++ &sensor_dev_attr_in6_max.dev_attr.attr,
++ &sensor_dev_attr_in6_min.dev_attr.attr,
++ &sensor_dev_attr_in7_input.dev_attr.attr,
++ &sensor_dev_attr_in7_max.dev_attr.attr,
++ &sensor_dev_attr_in7_min.dev_attr.attr,
++ &sensor_dev_attr_in8_input.dev_attr.attr,
++ &sensor_dev_attr_in8_max.dev_attr.attr,
++ &sensor_dev_attr_in8_min.dev_attr.attr,
++ &sensor_dev_attr_in9_input.dev_attr.attr,
++ &sensor_dev_attr_in9_max.dev_attr.attr,
++ &sensor_dev_attr_in9_min.dev_attr.attr,
++ &sensor_dev_attr_in10_input.dev_attr.attr,
++ &sensor_dev_attr_in10_max.dev_attr.attr,
++ &sensor_dev_attr_in10_min.dev_attr.attr,
++ &sensor_dev_attr_in11_input.dev_attr.attr,
++ &sensor_dev_attr_in11_max.dev_attr.attr,
++ &sensor_dev_attr_in11_min.dev_attr.attr,
++ &sensor_dev_attr_in12_input.dev_attr.attr,
++ &sensor_dev_attr_in12_max.dev_attr.attr,
++ &sensor_dev_attr_in12_min.dev_attr.attr,
++ &sensor_dev_attr_in13_input.dev_attr.attr,
++ &sensor_dev_attr_in13_max.dev_attr.attr,
++ &sensor_dev_attr_in13_min.dev_attr.attr,
++ &sensor_dev_attr_in14_input.dev_attr.attr,
++ &sensor_dev_attr_in14_max.dev_attr.attr,
++ &sensor_dev_attr_in14_min.dev_attr.attr,
++ &sensor_dev_attr_in15_input.dev_attr.attr,
++ &sensor_dev_attr_in15_max.dev_attr.attr,
++ &sensor_dev_attr_in15_min.dev_attr.attr,
++ &sensor_dev_attr_in16_input.dev_attr.attr,
++ &sensor_dev_attr_in16_max.dev_attr.attr,
++ &sensor_dev_attr_in16_min.dev_attr.attr,
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_div.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_div.dev_attr.attr,
++ &sensor_dev_attr_fan2_min.dev_attr.attr,
++ &sensor_dev_attr_fan3_input.dev_attr.attr,
++ &sensor_dev_attr_fan3_div.dev_attr.attr,
++ &sensor_dev_attr_fan3_min.dev_attr.attr,
++ &sensor_dev_attr_fan4_input.dev_attr.attr,
++ &sensor_dev_attr_fan4_div.dev_attr.attr,
++ &sensor_dev_attr_fan4_min.dev_attr.attr,
++ &sensor_dev_attr_fan5_input.dev_attr.attr,
++ &sensor_dev_attr_fan5_div.dev_attr.attr,
++ &sensor_dev_attr_fan5_min.dev_attr.attr,
++ &sensor_dev_attr_fan6_input.dev_attr.attr,
++ &sensor_dev_attr_fan6_div.dev_attr.attr,
++ &sensor_dev_attr_fan6_min.dev_attr.attr,
++ &sensor_dev_attr_fan7_input.dev_attr.attr,
++ &sensor_dev_attr_fan7_div.dev_attr.attr,
++ &sensor_dev_attr_fan7_min.dev_attr.attr,
++ &sensor_dev_attr_fan8_input.dev_attr.attr,
++ &sensor_dev_attr_fan8_div.dev_attr.attr,
++ &sensor_dev_attr_fan8_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_min.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_min.dev_attr.attr,
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_offset.dev_attr.attr,
++ &sensor_dev_attr_temp2_offset.dev_attr.attr,
++ &sensor_dev_attr_temp3_offset.dev_attr.attr,
++ &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
++ &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
++ &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
++ &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
++ &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
++ &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit.dev_attr.attr,
++ &sensor_dev_attr_temp3_crit.dev_attr.attr,
++ &dev_attr_temp1_crit_enable.attr,
++ &dev_attr_temp2_crit_enable.attr,
++ &dev_attr_temp3_crit_enable.attr,
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_alarm_mask.attr,
++ &dev_attr_gpio.attr,
++ &dev_attr_gpio_mask.attr,
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_pwm3.attr,
++ &dev_attr_pwm1_enable.attr,
++ &dev_attr_pwm2_enable.attr,
++ &dev_attr_pwm3_enable.attr,
++ &dev_attr_temp1_auto_point1_pwm.attr,
++ &dev_attr_temp2_auto_point1_pwm.attr,
++ &dev_attr_temp3_auto_point1_pwm.attr,
++ &dev_attr_temp1_auto_point2_pwm.attr,
++ &dev_attr_temp2_auto_point2_pwm.attr,
++ &dev_attr_temp3_auto_point2_pwm.attr,
++ &dev_attr_analog_out.attr,
++ NULL
++};
++
++static const struct attribute_group adm1026_group = {
++ .attrs = adm1026_attributes,
++};
++
+ static int adm1026_detect(struct i2c_adapter *adapter, int address,
+ int kind)
+ {
+@@ -1554,145 +1674,20 @@ static int adm1026_detect(struct i2c_ada
+ adm1026_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
++ goto exitdetach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exitdetach;
++ goto exitremove;
+ }
+
+- device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_auto_point1_temp.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_auto_point1_temp.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp3_auto_point1_temp.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_auto_point2_temp.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_auto_point2_temp.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp3_auto_point2_temp.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
+- device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
+- device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+- device_create_file(&new_client->dev, &dev_attr_vrm);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_alarm_mask);
+- device_create_file(&new_client->dev, &dev_attr_gpio);
+- device_create_file(&new_client->dev, &dev_attr_gpio_mask);
+- device_create_file(&new_client->dev, &dev_attr_pwm1);
+- device_create_file(&new_client->dev, &dev_attr_pwm2);
+- device_create_file(&new_client->dev, &dev_attr_pwm3);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
+- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
+- device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm);
+- device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm);
+- device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm);
+- device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm);
+- device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm);
+- device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm);
+- device_create_file(&new_client->dev, &dev_attr_analog_out);
+ return 0;
+
+ /* Error out and cleanup code */
++exitremove:
++ sysfs_remove_group(&new_client->dev.kobj, &adm1026_group);
+ exitdetach:
+ i2c_detach_client(new_client);
+ exitfree:
+@@ -1700,6 +1695,17 @@ exitfree:
+ exit:
+ return err;
+ }
++
++static int adm1026_detach_client(struct i2c_client *client)
++{
++ struct adm1026_data *data = i2c_get_clientdata(client);
++ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &adm1026_group);
++ i2c_detach_client(client);
++ kfree(data);
++ return 0;
++}
++
+ static int __init sm_adm1026_init(void)
+ {
+ return i2c_add_driver(&adm1026_driver);
+diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
+index 3bf2da6..122683f 100644
+--- a/drivers/hwmon/adm1031.c
++++ b/drivers/hwmon/adm1031.c
+@@ -730,6 +730,61 @@ static int adm1031_attach_adapter(struct
+ return i2c_probe(adapter, &addr_data, adm1031_detect);
+ }
+
++static struct attribute *adm1031_attributes[] = {
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_pwm1.attr,
++ &dev_attr_auto_fan1_channel.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_crit.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_min.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_crit.attr,
++
++ &dev_attr_auto_temp1_off.attr,
++ &dev_attr_auto_temp1_min.attr,
++ &dev_attr_auto_temp1_max.attr,
++
++ &dev_attr_auto_temp2_off.attr,
++ &dev_attr_auto_temp2_min.attr,
++ &dev_attr_auto_temp2_max.attr,
++
++ &dev_attr_auto_fan1_min_pwm.attr,
++
++ &dev_attr_alarms.attr,
++
++ NULL
++};
++
++static const struct attribute_group adm1031_group = {
++ .attrs = adm1031_attributes,
++};
++
++static struct attribute *adm1031_attributes_opt[] = {
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_div.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_auto_fan2_channel.attr,
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp3_min.attr,
++ &dev_attr_temp3_max.attr,
++ &dev_attr_temp3_crit.attr,
++ &dev_attr_auto_temp3_off.attr,
++ &dev_attr_auto_temp3_min.attr,
++ &dev_attr_auto_temp3_max.attr,
++ &dev_attr_auto_fan2_min_pwm.attr,
++ NULL
++};
++
++static const struct attribute_group adm1031_group_opt = {
++ .attrs = adm1031_attributes_opt,
++};
++
+ /* This function is called by i2c_probe */
+ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+@@ -789,57 +844,26 @@ static int adm1031_detect(struct i2c_ada
+ adm1031_init_client(new_client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group)))
+ goto exit_detach;
+- }
+-
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_pwm1);
+- device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+-
+- device_create_file(&new_client->dev, &dev_attr_auto_temp1_off);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp1_max);
+-
+- device_create_file(&new_client->dev, &dev_attr_auto_temp2_off);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp2_max);
+-
+- device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm);
+-
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+
+ if (kind == adm1031) {
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_pwm2);
+- device_create_file(&new_client->dev,
+- &dev_attr_auto_fan2_channel);
+- device_create_file(&new_client->dev, &dev_attr_temp3_input);
+- device_create_file(&new_client->dev, &dev_attr_temp3_min);
+- device_create_file(&new_client->dev, &dev_attr_temp3_max);
+- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp3_off);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp3_min);
+- device_create_file(&new_client->dev, &dev_attr_auto_temp3_max);
+- device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm);
++ if ((err = sysfs_create_group(&new_client->dev.kobj,
++ &adm1031_group_opt)))
++ goto exit_remove;
++ }
++
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove;
+ }
+
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &adm1031_group);
++ sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -854,6 +878,8 @@ static int adm1031_detach_client(struct
+ int ret;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &adm1031_group);
++ sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
+ if ((ret = i2c_detach_client(client)) != 0) {
+ return ret;
+ }
+diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
+index 43f6991..aad594a 100644
+--- a/drivers/hwmon/adm9240.c
++++ b/drivers/hwmon/adm9240.c
+@@ -5,7 +5,7 @@
+ * Copyright (C) 1999 Frodo Looijaard <frodol at dds.nl>
+ * Philip Edelbrock <phil at netroedge.com>
+ * Copyright (C) 2003 Michiel Rook <michiel at grendelproject.nl>
+- * Copyright (C) 2005 Grant Coady <gcoady at gmail.com> with valuable
++ * Copyright (C) 2005 Grant Coady <gcoady.lk at gmail.com> with valuable
+ * guidance from Jean Delvare
+ *
+ * Driver supports Analog Devices ADM9240
+@@ -465,6 +465,45 @@ static ssize_t chassis_clear(struct devi
+ }
+ static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
+
++static struct attribute *adm9240_attributes[] = {
++ &sensor_dev_attr_in0_input.dev_attr.attr,
++ &sensor_dev_attr_in0_min.dev_attr.attr,
++ &sensor_dev_attr_in0_max.dev_attr.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ &sensor_dev_attr_in5_input.dev_attr.attr,
++ &sensor_dev_attr_in5_min.dev_attr.attr,
++ &sensor_dev_attr_in5_max.dev_attr.attr,
++ &dev_attr_temp1_input.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_div.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_div.dev_attr.attr,
++ &sensor_dev_attr_fan2_min.dev_attr.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_aout_output.attr,
++ &dev_attr_chassis_clear.attr,
++ &dev_attr_cpu0_vid.attr,
++ NULL
++};
++
++static const struct attribute_group adm9240_group = {
++ .attrs = adm9240_attributes,
++};
++
+
+ /*** sensor chip detect and driver install ***/
+
+@@ -548,72 +587,19 @@ static int adm9240_detect(struct i2c_ada
+ adm9240_init_client(new_client);
+
+ /* populate sysfs filesystem */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in0_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in0_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in0_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in1_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in1_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in2_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in2_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in2_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in3_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in3_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in3_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in4_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in4_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in4_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in5_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in5_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_in5_max.dev_attr);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_max_hyst.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan1_div.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan1_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan2_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan2_div.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan2_min.dev_attr);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_aout_output);
+- device_create_file(&new_client->dev, &dev_attr_chassis_clear);
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+-
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -635,6 +621,7 @@ static int adm9240_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &adm9240_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+@@ -787,7 +774,7 @@ static void __exit sensors_adm9240_exit(
+ }
+
+ MODULE_AUTHOR("Michiel Rook <michiel at grendelproject.nl>, "
+- "Grant Coady <gcoady at gmail.com> and others");
++ "Grant Coady <gcoady.lk at gmail.com> and others");
+ MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
+ MODULE_LICENSE("GPL");
+
+diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
+index facc1cc..57b1c7b 100644
+--- a/drivers/hwmon/asb100.c
++++ b/drivers/hwmon/asb100.c
+@@ -298,12 +298,6 @@ sysfs_in(4);
+ sysfs_in(5);
+ sysfs_in(6);
+
+-#define device_create_file_in(client, offset) do { \
+- device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+- device_create_file(&client->dev, &dev_attr_in##offset##_min); \
+- device_create_file(&client->dev, &dev_attr_in##offset##_max); \
+-} while (0)
+-
+ /* 3 Fans */
+ static ssize_t show_fan(struct device *dev, char *buf, int nr)
+ {
+@@ -421,12 +415,6 @@ sysfs_fan(1);
+ sysfs_fan(2);
+ sysfs_fan(3);
+
+-#define device_create_file_fan(client, offset) do { \
+- device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+- device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
+- device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
+-} while (0)
+-
+ /* 4 Temp. Sensors */
+ static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
+ {
+@@ -515,12 +503,6 @@ sysfs_temp(3);
+ sysfs_temp(4);
+
+ /* VID */
+-#define device_create_file_temp(client, num) do { \
+- device_create_file(&client->dev, &dev_attr_temp##num##_input); \
+- device_create_file(&client->dev, &dev_attr_temp##num##_max); \
+- device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \
+-} while (0)
+-
+ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct asb100_data *data = asb100_update_device(dev);
+@@ -528,8 +510,6 @@ static ssize_t show_vid(struct device *d
+ }
+
+ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+-#define device_create_file_vid(client) \
+-device_create_file(&client->dev, &dev_attr_cpu0_vid)
+
+ /* VRM */
+ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -549,8 +529,6 @@ static ssize_t set_vrm(struct device *de
+
+ /* Alarms */
+ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+-#define device_create_file_vrm(client) \
+-device_create_file(&client->dev, &dev_attr_vrm);
+
+ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -559,8 +537,6 @@ static ssize_t show_alarms(struct device
+ }
+
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+-#define device_create_file_alarms(client) \
+-device_create_file(&client->dev, &dev_attr_alarms)
+
+ /* 1 PWM */
+ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -607,10 +583,65 @@ static ssize_t set_pwm_enable1(struct de
+ static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
+ static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable1, set_pwm_enable1);
+-#define device_create_file_pwm1(client) do { \
+- device_create_file(&new_client->dev, &dev_attr_pwm1); \
+- device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \
+-} while (0)
++
++static struct attribute *asb100_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++ &dev_attr_in5_input.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in5_max.attr,
++ &dev_attr_in6_input.attr,
++ &dev_attr_in6_min.attr,
++ &dev_attr_in6_max.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++ &dev_attr_fan3_input.attr,
++ &dev_attr_fan3_min.attr,
++ &dev_attr_fan3_div.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_max_hyst.attr,
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp3_max.attr,
++ &dev_attr_temp3_max_hyst.attr,
++ &dev_attr_temp4_input.attr,
++ &dev_attr_temp4_max.attr,
++ &dev_attr_temp4_max_hyst.attr,
++
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm1_enable.attr,
++
++ NULL
++};
++
++static const struct attribute_group asb100_group = {
++ .attrs = asb100_attributes,
++};
+
+ /* This function is called when:
+ asb100_driver is inserted (when this module is loaded), for each
+@@ -810,38 +841,19 @@ static int asb100_detect(struct i2c_adap
+ data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
++ goto ERROR3;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto ERROR3;
++ goto ERROR4;
+ }
+
+- device_create_file_in(new_client, 0);
+- device_create_file_in(new_client, 1);
+- device_create_file_in(new_client, 2);
+- device_create_file_in(new_client, 3);
+- device_create_file_in(new_client, 4);
+- device_create_file_in(new_client, 5);
+- device_create_file_in(new_client, 6);
+-
+- device_create_file_fan(new_client, 1);
+- device_create_file_fan(new_client, 2);
+- device_create_file_fan(new_client, 3);
+-
+- device_create_file_temp(new_client, 1);
+- device_create_file_temp(new_client, 2);
+- device_create_file_temp(new_client, 3);
+- device_create_file_temp(new_client, 4);
+-
+- device_create_file_vid(new_client);
+- device_create_file_vrm(new_client);
+-
+- device_create_file_alarms(new_client);
+-
+- device_create_file_pwm1(new_client);
+-
+ return 0;
+
++ERROR4:
++ sysfs_remove_group(&new_client->dev.kobj, &asb100_group);
+ ERROR3:
+ i2c_detach_client(data->lm75[1]);
+ i2c_detach_client(data->lm75[0]);
+@@ -861,8 +873,10 @@ static int asb100_detach_client(struct i
+ int err;
+
+ /* main client */
+- if (data)
++ if (data) {
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &asb100_group);
++ }
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
+index 728a1e8..0ccdd07 100644
+--- a/drivers/hwmon/atxp1.c
++++ b/drivers/hwmon/atxp1.c
+@@ -27,6 +27,7 @@
+ #include <linux/hwmon-vid.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
+@@ -116,8 +117,7 @@ static ssize_t atxp1_storevcore(struct d
+ {
+ struct atxp1_data *data;
+ struct i2c_client *client;
+- char vid;
+- char cvid;
++ int vid, cvid;
+ unsigned int vcore;
+
+ client = to_i2c_client(dev);
+@@ -251,6 +251,17 @@ static ssize_t atxp1_storegpio2(struct d
+ */
+ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
+
++static struct attribute *atxp1_attributes[] = {
++ &dev_attr_gpio1.attr,
++ &dev_attr_gpio2.attr,
++ &dev_attr_cpu0_vid.attr,
++ NULL
++};
++
++static const struct attribute_group atxp1_group = {
++ .attrs = atxp1_attributes,
++};
++
+
+ static int atxp1_attach_adapter(struct i2c_adapter *adapter)
+ {
+@@ -320,21 +331,23 @@ static int atxp1_detect(struct i2c_adapt
+ goto exit_free;
+ }
+
++ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_gpio1);
+- device_create_file(&new_client->dev, &dev_attr_gpio2);
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+-
+ dev_info(&new_client->dev, "Using VRM: %d.%d\n",
+ data->vrm / 10, data->vrm % 10);
+
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -349,6 +362,7 @@ static int atxp1_detach_client(struct i2
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &atxp1_group);
+
+ err = i2c_detach_client(client);
+
+diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
+index 478eb4b..c849c0c 100644
+--- a/drivers/hwmon/ds1621.c
++++ b/drivers/hwmon/ds1621.c
+@@ -29,6 +29,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+ #include "lm75.h"
+
+ /* Addresses to scan */
+@@ -178,6 +179,18 @@ static DEVICE_ATTR(temp1_input, S_IRUGO
+ static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
+ static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+
++static struct attribute *ds1621_attributes[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group ds1621_group = {
++ .attrs = ds1621_attributes,
++};
++
+
+ static int ds1621_attach_adapter(struct i2c_adapter *adapter)
+ {
+@@ -253,21 +266,19 @@ static int ds1621_detect(struct i2c_adap
+ ds1621_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+-
+ return 0;
+
+-/* OK, this is not exactly good programming practice, usually. But it is
+- very code-efficient in this case. */
++ exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -282,6 +293,7 @@ static int ds1621_detach_client(struct i
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &ds1621_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
+index fd72440..de17a72 100644
+--- a/drivers/hwmon/f71805f.c
++++ b/drivers/hwmon/f71805f.c
+@@ -1,7 +1,7 @@
+ /*
+ * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated
+ * hardware monitoring features
+- * Copyright (C) 2005 Jean Delvare <khali at linux-fr.org>
++ * Copyright (C) 2005-2006 Jean Delvare <khali at linux-fr.org>
+ *
+ * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
+ * complete hardware monitoring features: voltage, fan and temperature
+@@ -31,6 +31,7 @@
+ #include <linux/hwmon-sysfs.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+ #include <asm/io.h>
+
+ static struct platform_device *pdev;
+@@ -147,7 +148,7 @@ struct f71805f_data {
+ u8 temp_high[3];
+ u8 temp_hyst[3];
+ u8 temp_mode;
+- u8 alarms[3];
++ unsigned long alarms;
+ };
+
+ static inline long in_from_reg(u8 reg)
+@@ -311,10 +312,9 @@ static struct f71805f_data *f71805f_upda
+ data->temp[nr] = f71805f_read8(data,
+ F71805F_REG_TEMP(nr));
+ }
+- for (nr = 0; nr < 3; nr++) {
+- data->alarms[nr] = f71805f_read8(data,
+- F71805F_REG_STATUS(nr));
+- }
++ data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0))
++ + (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8)
++ + (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+@@ -557,8 +557,7 @@ static ssize_t show_alarms_in(struct dev
+ {
+ struct f71805f_data *data = f71805f_update_device(dev);
+
+- return sprintf(buf, "%d\n", data->alarms[0] |
+- ((data->alarms[1] & 0x01) << 8));
++ return sprintf(buf, "%lu\n", data->alarms & 0x1ff);
+ }
+
+ static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
+@@ -566,7 +565,7 @@ static ssize_t show_alarms_fan(struct de
+ {
+ struct f71805f_data *data = f71805f_update_device(dev);
+
+- return sprintf(buf, "%d\n", data->alarms[2] & 0x07);
++ return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07);
+ }
+
+ static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
+@@ -574,7 +573,17 @@ static ssize_t show_alarms_temp(struct d
+ {
+ struct f71805f_data *data = f71805f_update_device(dev);
+
+- return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07);
++ return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07);
++}
++
++static ssize_t show_alarm(struct device *dev, struct device_attribute
++ *devattr, char *buf)
++{
++ struct f71805f_data *data = f71805f_update_device(dev);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ int bitnr = attr->index;
++
++ return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1);
+ }
+
+ static ssize_t show_name(struct device *dev, struct device_attribute
+@@ -585,88 +594,189 @@ static ssize_t show_name(struct device *
+ return sprintf(buf, "%s\n", data->name);
+ }
+
+-static struct device_attribute f71805f_dev_attr[] = {
+- __ATTR(in0_input, S_IRUGO, show_in0, NULL),
+- __ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max),
+- __ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min),
+- __ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL),
+- __ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL),
+- __ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL),
+- __ATTR(name, S_IRUGO, show_name, NULL),
++static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL);
++static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max);
++static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min);
++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
++static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 1);
++static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 1);
++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
++static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 2);
++static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 2);
++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
++static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 3);
++static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 3);
++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
++static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 4);
++static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 4);
++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
++static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 5);
++static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 5);
++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
++static SENSOR_DEVICE_ATTR(in6_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 6);
++static SENSOR_DEVICE_ATTR(in6_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 6);
++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
++static SENSOR_DEVICE_ATTR(in7_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 7);
++static SENSOR_DEVICE_ATTR(in7_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 7);
++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
++static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR,
++ show_in_max, set_in_max, 8);
++static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR,
++ show_in_min, set_in_min, 8);
++
++static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
++static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
++ show_fan_min, set_fan_min, 0);
++static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
++static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
++ show_fan_min, set_fan_min, 1);
++static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
++static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
++ show_fan_min, set_fan_min, 2);
++
++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
++ show_temp_max, set_temp_max, 0);
++static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
++ show_temp_hyst, set_temp_hyst, 0);
++static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
++static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
++ show_temp_max, set_temp_max, 1);
++static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
++ show_temp_hyst, set_temp_hyst, 1);
++static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
++static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
++static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
++ show_temp_max, set_temp_max, 2);
++static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
++ show_temp_hyst, set_temp_hyst, 2);
++static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
++
++static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
++static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
++static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
++static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
++static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
++static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
++static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
++static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
++static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
++static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11);
++static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12);
++static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
++static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
++static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
++static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
++static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL);
++static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL);
++static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
++
++static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
++
++static struct attribute *f71805f_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in0_min.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in5_input.dev_attr.attr,
++ &sensor_dev_attr_in5_max.dev_attr.attr,
++ &sensor_dev_attr_in5_min.dev_attr.attr,
++ &sensor_dev_attr_in6_input.dev_attr.attr,
++ &sensor_dev_attr_in6_max.dev_attr.attr,
++ &sensor_dev_attr_in6_min.dev_attr.attr,
++ &sensor_dev_attr_in7_input.dev_attr.attr,
++ &sensor_dev_attr_in7_max.dev_attr.attr,
++ &sensor_dev_attr_in7_min.dev_attr.attr,
++ &sensor_dev_attr_in8_input.dev_attr.attr,
++ &sensor_dev_attr_in8_max.dev_attr.attr,
++ &sensor_dev_attr_in8_min.dev_attr.attr,
++
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp1_type.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp2_type.dev_attr.attr,
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp3_type.dev_attr.attr,
++
++ &sensor_dev_attr_in0_alarm.dev_attr.attr,
++ &sensor_dev_attr_in1_alarm.dev_attr.attr,
++ &sensor_dev_attr_in2_alarm.dev_attr.attr,
++ &sensor_dev_attr_in3_alarm.dev_attr.attr,
++ &sensor_dev_attr_in4_alarm.dev_attr.attr,
++ &sensor_dev_attr_in5_alarm.dev_attr.attr,
++ &sensor_dev_attr_in6_alarm.dev_attr.attr,
++ &sensor_dev_attr_in7_alarm.dev_attr.attr,
++ &sensor_dev_attr_in8_alarm.dev_attr.attr,
++ &dev_attr_alarms_in.attr,
++ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
++ &dev_attr_alarms_temp.attr,
++ &dev_attr_alarms_fan.attr,
++
++ &dev_attr_name.attr,
++ NULL
+ };
+
+-static struct sensor_device_attribute f71805f_sensor_attr[] = {
+- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+- SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 1),
+- SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 1),
+- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+- SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 2),
+- SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 2),
+- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+- SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 3),
+- SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 3),
+- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+- SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 4),
+- SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 4),
+- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+- SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 5),
+- SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 5),
+- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+- SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 6),
+- SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 6),
+- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+- SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 7),
+- SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 7),
+- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+- SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR,
+- show_in_max, set_in_max, 8),
+- SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR,
+- show_in_min, set_in_min, 8),
+-
+- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+- SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+- show_temp_max, set_temp_max, 0),
+- SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+- show_temp_hyst, set_temp_hyst, 0),
+- SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+- SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+- show_temp_max, set_temp_max, 1),
+- SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+- show_temp_hyst, set_temp_hyst, 1),
+- SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+- SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+- SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+- show_temp_max, set_temp_max, 2),
+- SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
+- show_temp_hyst, set_temp_hyst, 2),
+- SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
++static const struct attribute_group f71805f_group = {
++ .attrs = f71805f_attributes,
+ };
+
+-static struct sensor_device_attribute f71805f_fan_attr[] = {
+- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+- SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+- show_fan_min, set_fan_min, 0),
+- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+- SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+- show_fan_min, set_fan_min, 1),
+- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+- SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+- show_fan_min, set_fan_min, 2),
++static struct attribute *f71805f_attributes_fan[3][4] = {
++ {
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_min.dev_attr.attr,
++ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_fan3_input.dev_attr.attr,
++ &sensor_dev_attr_fan3_min.dev_attr.attr,
++ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
++ NULL
++ }
++};
++
++static const struct attribute_group f71805f_group_fan[3] = {
++ { .attrs = f71805f_attributes_fan[0] },
++ { .attrs = f71805f_attributes_fan[1] },
++ { .attrs = f71805f_attributes_fan[2] },
+ };
+
+ /*
+@@ -714,43 +824,35 @@ static int __devinit f71805f_probe(struc
+
+ platform_set_drvdata(pdev, data);
+
+- data->class_dev = hwmon_device_register(&pdev->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
+- dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+- goto exit_free;
+- }
+-
+ /* Initialize the F71805F chip */
+ f71805f_init_device(data);
+
+ /* Register sysfs interface files */
+- for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) {
+- err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]);
+- if (err)
+- goto exit_class;
+- }
+- for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) {
+- err = device_create_file(&pdev->dev,
+- &f71805f_sensor_attr[i].dev_attr);
+- if (err)
+- goto exit_class;
+- }
+- for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) {
+- if (!(data->fan_enabled & (1 << (i / 2))))
++ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
++ goto exit_free;
++ for (i = 0; i < 3; i++) {
++ if (!(data->fan_enabled & (1 << i)))
+ continue;
+- err = device_create_file(&pdev->dev,
+- &f71805f_fan_attr[i].dev_attr);
+- if (err)
+- goto exit_class;
++ if ((err = sysfs_create_group(&pdev->dev.kobj,
++ &f71805f_group_fan[i])))
++ goto exit_remove_files;
++ }
++
++ data->class_dev = hwmon_device_register(&pdev->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
++ goto exit_remove_files;
+ }
+
+ return 0;
+
+-exit_class:
+- dev_err(&pdev->dev, "Sysfs interface creation failed\n");
+- hwmon_device_unregister(data->class_dev);
++exit_remove_files:
++ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
++ for (i = 0; i < 3; i++)
++ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
+ exit_free:
++ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ exit:
+ return err;
+@@ -759,9 +861,13 @@ exit:
+ static int __devexit f71805f_remove(struct platform_device *pdev)
+ {
+ struct f71805f_data *data = platform_get_drvdata(pdev);
++ int i;
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
++ for (i = 0; i < 3; i++)
++ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
+ kfree(data);
+
+ return 0;
+diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
+index 6bc76b4..1971775 100644
+--- a/drivers/hwmon/fscher.c
++++ b/drivers/hwmon/fscher.c
+@@ -34,6 +34,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /*
+ * Addresses to scan
+@@ -240,47 +241,45 @@ sysfs_alarms(FSCHER_REG_EVENTS)
+ sysfs_control(FSCHER_REG_CONTROL)
+ sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET)
+
+-#define device_create_file_fan(client, offset) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_fan##offset##_status); \
+- device_create_file(&client->dev, &dev_attr_pwm##offset); \
+- device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
+- device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+-} while (0)
+-
+-#define device_create_file_temp(client, offset) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_temp##offset##_status); \
+- device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
+-} while (0)
+-
+-#define device_create_file_in(client, offset) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+-} while (0)
+-
+-#define device_create_file_revision(client) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_revision); \
+-} while (0)
+-
+-#define device_create_file_alarms(client) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_alarms); \
+-} while (0)
+-
+-#define device_create_file_control(client) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_control); \
+-} while (0)
+-
+-#define device_create_file_watchdog(client) \
+-do { \
+- device_create_file(&client->dev, &dev_attr_watchdog_status); \
+- device_create_file(&client->dev, &dev_attr_watchdog_control); \
+- device_create_file(&client->dev, &dev_attr_watchdog_preset); \
+-} while (0)
+-
++static struct attribute *fscher_attributes[] = {
++ &dev_attr_revision.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_control.attr,
++
++ &dev_attr_watchdog_status.attr,
++ &dev_attr_watchdog_control.attr,
++ &dev_attr_watchdog_preset.attr,
++
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++
++ &dev_attr_fan1_status.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan1_input.attr,
++ &dev_attr_pwm1.attr,
++ &dev_attr_fan2_status.attr,
++ &dev_attr_fan2_div.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_fan3_status.attr,
++ &dev_attr_fan3_div.attr,
++ &dev_attr_fan3_input.attr,
++ &dev_attr_pwm3.attr,
++
++ &dev_attr_temp1_status.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_status.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp3_status.attr,
++ &dev_attr_temp3_input.attr,
++ NULL
++};
++
++static const struct attribute_group fscher_group = {
++ .attrs = fscher_attributes,
++};
++
+ /*
+ * Real code
+ */
+@@ -342,31 +341,19 @@ static int fscher_detect(struct i2c_adap
+ fscher_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file_revision(new_client);
+- device_create_file_alarms(new_client);
+- device_create_file_control(new_client);
+- device_create_file_watchdog(new_client);
+-
+- device_create_file_in(new_client, 0);
+- device_create_file_in(new_client, 1);
+- device_create_file_in(new_client, 2);
+-
+- device_create_file_fan(new_client, 1);
+- device_create_file_fan(new_client, 2);
+- device_create_file_fan(new_client, 3);
+-
+- device_create_file_temp(new_client, 1);
+- device_create_file_temp(new_client, 2);
+- device_create_file_temp(new_client, 3);
+-
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -381,6 +368,7 @@ static int fscher_detach_client(struct i
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &fscher_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
+index 6dc4846..ea506a7 100644
+--- a/drivers/hwmon/fscpos.c
++++ b/drivers/hwmon/fscpos.c
+@@ -38,6 +38,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /*
+ * Addresses to scan
+@@ -432,6 +433,44 @@ static DEVICE_ATTR(in0_input, S_IRUGO, s
+ static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
+ static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
+
++static struct attribute *fscpos_attributes[] = {
++ &dev_attr_event.attr,
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++
++ &dev_attr_wdog_control.attr,
++ &dev_attr_wdog_preset.attr,
++ &dev_attr_wdog_state.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_status.attr,
++ &dev_attr_temp1_reset.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_status.attr,
++ &dev_attr_temp2_reset.attr,
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp3_status.attr,
++ &dev_attr_temp3_reset.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_status.attr,
++ &dev_attr_fan1_ripple.attr,
++ &dev_attr_pwm1.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_status.attr,
++ &dev_attr_fan2_ripple.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_fan3_input.attr,
++ &dev_attr_fan3_status.attr,
++ &dev_attr_fan3_ripple.attr,
++ NULL
++};
++
++static const struct attribute_group fscpos_group = {
++ .attrs = fscpos_attributes,
++};
++
+ static int fscpos_attach_adapter(struct i2c_adapter *adapter)
+ {
+ if (!(adapter->class & I2C_CLASS_HWMON))
+@@ -497,42 +536,19 @@ static int fscpos_detect(struct i2c_adap
+ dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_event);
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_wdog_control);
+- device_create_file(&new_client->dev, &dev_attr_wdog_preset);
+- device_create_file(&new_client->dev, &dev_attr_wdog_state);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_status);
+- device_create_file(&new_client->dev, &dev_attr_temp1_reset);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_status);
+- device_create_file(&new_client->dev, &dev_attr_temp2_reset);
+- device_create_file(&new_client->dev, &dev_attr_temp3_input);
+- device_create_file(&new_client->dev, &dev_attr_temp3_status);
+- device_create_file(&new_client->dev, &dev_attr_temp3_reset);
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_status);
+- device_create_file(&new_client->dev, &dev_attr_fan1_ripple);
+- device_create_file(&new_client->dev, &dev_attr_pwm1);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_status);
+- device_create_file(&new_client->dev, &dev_attr_fan2_ripple);
+- device_create_file(&new_client->dev, &dev_attr_pwm2);
+- device_create_file(&new_client->dev, &dev_attr_fan3_input);
+- device_create_file(&new_client->dev, &dev_attr_fan3_status);
+- device_create_file(&new_client->dev, &dev_attr_fan3_ripple);
+-
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -547,6 +563,7 @@ static int fscpos_detach_client(struct i
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &fscpos_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
+index 6606aab..c103640 100644
+--- a/drivers/hwmon/gl518sm.c
++++ b/drivers/hwmon/gl518sm.c
+@@ -44,6 +44,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /* Addresses to scan */
+ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+@@ -340,6 +341,42 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|
+ static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO,
+ show_beep_mask, set_beep_mask);
+
++static struct attribute *gl518_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_max.attr,
++
++ &dev_attr_fan1_auto.attr,
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++
++ &dev_attr_alarms.attr,
++ &dev_attr_beep_enable.attr,
++ &dev_attr_beep_mask.attr,
++ NULL
++};
++
++static const struct attribute_group gl518_group = {
++ .attrs = gl518_attributes,
++};
++
+ /*
+ * Real code
+ */
+@@ -420,43 +457,19 @@ static int gl518_detect(struct i2c_adapt
+ gl518_init_client((struct i2c_client *) new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_fan1_auto);
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_beep_enable);
+- device_create_file(&new_client->dev, &dev_attr_beep_mask);
+-
+ return 0;
+
+-/* OK, this is not exactly good programming practice, usually. But it is
+- very code-efficient in this case. */
+-
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &gl518_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -490,6 +503,7 @@ static int gl518_detach_client(struct i2
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &gl518_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
+index 14e810f..ebe7b9a 100644
+--- a/drivers/hwmon/gl520sm.c
++++ b/drivers/hwmon/gl520sm.c
+@@ -30,6 +30,7 @@
+ #include <linux/hwmon-vid.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /* Type of the extra sensor */
+ static unsigned short extra_sensor_type;
+@@ -190,55 +191,29 @@ static DEVICE_ATTR(type##item, S_IRUGO,
+ #define sysfs_vid(n) \
+ sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
+
+-#define device_create_file_vid(client, n) \
+-device_create_file(&client->dev, &dev_attr_cpu##n##_vid)
+-
+ #define sysfs_in(n) \
+ sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
+ sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
+ sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
+
+-#define device_create_file_in(client, n) \
+-({device_create_file(&client->dev, &dev_attr_in##n##_input); \
+-device_create_file(&client->dev, &dev_attr_in##n##_min); \
+-device_create_file(&client->dev, &dev_attr_in##n##_max);})
+-
+ #define sysfs_fan(n) \
+ sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
+ sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
+ sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
+
+-#define device_create_file_fan(client, n) \
+-({device_create_file(&client->dev, &dev_attr_fan##n##_input); \
+-device_create_file(&client->dev, &dev_attr_fan##n##_min); \
+-device_create_file(&client->dev, &dev_attr_fan##n##_div);})
+-
+ #define sysfs_fan_off(n) \
+ sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
+
+-#define device_create_file_fan_off(client, n) \
+-device_create_file(&client->dev, &dev_attr_fan##n##_off)
+-
+ #define sysfs_temp(n) \
+ sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
+ sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
+ sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
+
+-#define device_create_file_temp(client, n) \
+-({device_create_file(&client->dev, &dev_attr_temp##n##_input); \
+-device_create_file(&client->dev, &dev_attr_temp##n##_max); \
+-device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);})
+-
+ #define sysfs_alarms() \
+ sysfs_ro(alarms, , GL520_REG_ALARMS) \
+ sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
+ sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
+
+-#define device_create_file_alarms(client) \
+-({device_create_file(&client->dev, &dev_attr_alarms); \
+-device_create_file(&client->dev, &dev_attr_beep_enable); \
+-device_create_file(&client->dev, &dev_attr_beep_mask);})
+-
+
+ sysfs_vid(0)
+
+@@ -511,6 +486,59 @@ static ssize_t set_beep_mask(struct i2c_
+ return count;
+ }
+
++static struct attribute *gl520_attributes[] = {
++ &dev_attr_cpu0_vid.attr,
++
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in3_max.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan1_off.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++
++ &dev_attr_alarms.attr,
++ &dev_attr_beep_enable.attr,
++ &dev_attr_beep_mask.attr,
++ NULL
++};
++
++static const struct attribute_group gl520_group = {
++ .attrs = gl520_attributes,
++};
++
++static struct attribute *gl520_attributes_opt[] = {
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_max_hyst.attr,
++ NULL
++};
++
++static const struct attribute_group gl520_group_opt = {
++ .attrs = gl520_attributes_opt,
++};
++
+
+ /*
+ * Real code
+@@ -572,33 +600,39 @@ static int gl520_detect(struct i2c_adapt
+ gl520_init_client(new_client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group)))
+ goto exit_detach;
+- }
+-
+- device_create_file_vid(new_client, 0);
+
+- device_create_file_in(new_client, 0);
+- device_create_file_in(new_client, 1);
+- device_create_file_in(new_client, 2);
+- device_create_file_in(new_client, 3);
+- if (!data->two_temps)
+- device_create_file_in(new_client, 4);
+-
+- device_create_file_fan(new_client, 1);
+- device_create_file_fan(new_client, 2);
+- device_create_file_fan_off(new_client, 1);
++ if (data->two_temps) {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_temp2_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp2_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp2_max_hyst)))
++ goto exit_remove_files;
++ } else {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in4_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_max)))
++ goto exit_remove_files;
++ }
+
+- device_create_file_temp(new_client, 1);
+- if (data->two_temps)
+- device_create_file_temp(new_client, 2);
+
+- device_create_file_alarms(new_client);
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove_files;
++ }
+
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &gl520_group);
++ sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -652,6 +686,8 @@ static int gl520_detach_client(struct i2
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &gl520_group);
++ sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
+index 42b6328..26be4ea 100644
+--- a/drivers/hwmon/hdaps.c
++++ b/drivers/hwmon/hdaps.c
+@@ -537,6 +537,7 @@ static int __init hdaps_init(void)
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
+ HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"),
++ HDAPS_DMI_MATCH_LENOVO("ThinkPad T60"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"),
+ HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"),
+@@ -587,7 +588,9 @@ static int __init hdaps_init(void)
+ input_set_abs_params(hdaps_idev, ABS_Y,
+ -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
+
+- input_register_device(hdaps_idev);
++ ret = input_register_device(hdaps_idev);
++ if (ret)
++ goto out_idev;
+
+ /* start up our timer for the input device */
+ init_timer(&hdaps_timer);
+@@ -598,6 +601,8 @@ static int __init hdaps_init(void)
+ printk(KERN_INFO "hdaps: driver successfully loaded.\n");
+ return 0;
+
++out_idev:
++ input_free_device(hdaps_idev);
+ out_group:
+ sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
+ out_device:
+diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
+index 06df92b..323ef06 100644
+--- a/drivers/hwmon/it87.c
++++ b/drivers/hwmon/it87.c
+@@ -4,10 +4,12 @@
+
+ Supports: IT8705F Super I/O chip w/LPC interface
+ IT8712F Super I/O chip w/LPC interface & SMBus
++ IT8716F Super I/O chip w/LPC interface
++ IT8718F Super I/O chip w/LPC interface
+ Sis950 A clone of the IT8705F
+
+ Copyright (C) 2001 Chris Gauthron <chrisg at 0-in.com>
+- Largely inspired by lm78.c of the same package
++ Copyright (C) 2005-2006 Jean Delvare <khali at linux-fr.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
+@@ -24,13 +26,6 @@
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+-/*
+- djg at pdp8.net David Gesswein 7/18/01
+- Modified to fix bug with not all alarms enabled.
+- Added ability to read battery voltage and select temperature sensor
+- type at module load time.
+-*/
+-
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -42,6 +37,7 @@
+ #include <linux/hwmon-vid.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+ #include <asm/io.h>
+
+
+@@ -50,12 +46,13 @@ static unsigned short normal_i2c[] = { 0
+ static unsigned short isa_address;
+
+ /* Insmod parameters */
+-I2C_CLIENT_INSMOD_2(it87, it8712);
++I2C_CLIENT_INSMOD_4(it87, it8712, it8716, it8718);
+
+ #define REG 0x2e /* The register to read/write */
+ #define DEV 0x07 /* Register: Logical device select */
+ #define VAL 0x2f /* The value to read/write */
+ #define PME 0x04 /* The device with the fan registers in it */
++#define GPIO 0x07 /* The device with the IT8718F VID value in it */
+ #define DEVID 0x20 /* Register: Device ID */
+ #define DEVREV 0x22 /* Register: Device Revision */
+
+@@ -77,10 +74,10 @@ static int superio_inw(int reg)
+ }
+
+ static inline void
+-superio_select(void)
++superio_select(int ldn)
+ {
+ outb(DEV, REG);
+- outb(PME, VAL);
++ outb(ldn, VAL);
+ }
+
+ static inline void
+@@ -99,20 +96,27 @@ superio_exit(void)
+ outb(0x02, VAL);
+ }
+
++/* Logical device 4 registers */
+ #define IT8712F_DEVID 0x8712
+ #define IT8705F_DEVID 0x8705
++#define IT8716F_DEVID 0x8716
++#define IT8718F_DEVID 0x8718
+ #define IT87_ACT_REG 0x30
+ #define IT87_BASE_REG 0x60
+
++/* Logical device 7 registers (IT8712F and later) */
++#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
++#define IT87_SIO_VID_REG 0xfc /* VID value */
++
+ /* Update battery voltage after every reading if true */
+ static int update_vbat;
+
+ /* Not all BIOSes properly configure the PWM registers */
+ static int fix_pwm_polarity;
+
+-/* Chip Type */
+-
++/* Values read from Super-I/O config space */
+ static u16 chip_type;
++static u8 vid_value;
+
+ /* Many IT87 constants specified below */
+
+@@ -131,13 +135,21 @@ static u16 chip_type;
+ #define IT87_REG_ALARM2 0x02
+ #define IT87_REG_ALARM3 0x03
+
++/* The IT8718F has the VID value in a different register, in Super-I/O
++ configuration space. */
+ #define IT87_REG_VID 0x0a
++/* Warning: register 0x0b is used for something completely different in
++ new chips/revisions. I suspect only 16-bit tachometer mode will work
++ for these. */
+ #define IT87_REG_FAN_DIV 0x0b
++#define IT87_REG_FAN_16BIT 0x0c
+
+ /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
+
+ #define IT87_REG_FAN(nr) (0x0d + (nr))
+ #define IT87_REG_FAN_MIN(nr) (0x10 + (nr))
++#define IT87_REG_FANX(nr) (0x18 + (nr))
++#define IT87_REG_FANX_MIN(nr) (0x1b + (nr))
+ #define IT87_REG_FAN_MAIN_CTRL 0x13
+ #define IT87_REG_FAN_CTL 0x14
+ #define IT87_REG_PWM(nr) (0x15 + (nr))
+@@ -169,7 +181,16 @@ static inline u8 FAN_TO_REG(long rpm, in
+ 254);
+ }
+
++static inline u16 FAN16_TO_REG(long rpm)
++{
++ if (rpm == 0)
++ return 0xffff;
++ return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
++}
++
+ #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
++/* The divider is fixed to 2 in 16-bit mode */
++#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2))
+
+ #define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\
+ ((val)+500)/1000),-128,127))
+@@ -181,7 +202,7 @@ static inline u8 FAN_TO_REG(long rpm, in
+ static int DIV_TO_REG(int val)
+ {
+ int answer = 0;
+- while ((val >>= 1) != 0)
++ while (answer < 7 && (val >>= 1))
+ answer++;
+ return answer;
+ }
+@@ -203,10 +224,11 @@ struct it87_data {
+ unsigned long last_updated; /* In jiffies */
+
+ u8 in[9]; /* Register value */
+- u8 in_max[9]; /* Register value */
+- u8 in_min[9]; /* Register value */
+- u8 fan[3]; /* Register value */
+- u8 fan_min[3]; /* Register value */
++ u8 in_max[8]; /* Register value */
++ u8 in_min[8]; /* Register value */
++ u8 has_fan; /* Bitfield, fans enabled */
++ u16 fan[3]; /* Register values, possibly combined */
++ u16 fan_min[3]; /* Register values, possibly combined */
+ u8 temp[3]; /* Register value */
+ u8 temp_high[3]; /* Register value */
+ u8 temp_low[3]; /* Register value */
+@@ -243,6 +265,7 @@ static struct i2c_driver it87_driver = {
+
+ static struct i2c_driver it87_isa_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "it87-isa",
+ },
+ .attach_adapter = it87_isa_attach_adapter,
+@@ -544,15 +567,15 @@ static ssize_t set_fan_div(struct device
+
+ struct i2c_client *client = to_i2c_client(dev);
+ struct it87_data *data = i2c_get_clientdata(client);
+- int val = simple_strtol(buf, NULL, 10);
+- int i, min[3];
++ unsigned long val = simple_strtoul(buf, NULL, 10);
++ int min;
+ u8 old;
+
+ mutex_lock(&data->update_lock);
+ old = it87_read_value(client, IT87_REG_FAN_DIV);
+
+- for (i = 0; i < 3; i++)
+- min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i]));
++ /* Save fan min limit */
++ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
+
+ switch (nr) {
+ case 0:
+@@ -572,10 +595,10 @@ static ssize_t set_fan_div(struct device
+ val |= 0x1 << 6;
+ it87_write_value(client, IT87_REG_FAN_DIV, val);
+
+- for (i = 0; i < 3; i++) {
+- data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
+- it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
+- }
++ /* Restore fan min limit */
++ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
++ it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
++
+ mutex_unlock(&data->update_lock);
+ return count;
+ }
+@@ -656,6 +679,59 @@ show_pwm_offset(1);
+ show_pwm_offset(2);
+ show_pwm_offset(3);
+
++/* A different set of callbacks for 16-bit fans */
++static ssize_t show_fan16(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct it87_data *data = it87_update_device(dev);
++ return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr]));
++}
++
++static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct it87_data *data = it87_update_device(dev);
++ return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr]));
++}
++
++static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct it87_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ data->fan_min[nr] = FAN16_TO_REG(val);
++ it87_write_value(client, IT87_REG_FAN_MIN(nr),
++ data->fan_min[nr] & 0xff);
++ it87_write_value(client, IT87_REG_FANX_MIN(nr),
++ data->fan_min[nr] >> 8);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++/* We want to use the same sysfs file names as 8-bit fans, but we need
++ different variable names, so we have to use SENSOR_ATTR instead of
++ SENSOR_DEVICE_ATTR. */
++#define show_fan16_offset(offset) \
++static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
++ = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \
++ show_fan16, NULL, offset - 1); \
++static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
++ = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
++ show_fan16_min, set_fan16_min, offset - 1)
++
++show_fan16_offset(1);
++show_fan16_offset(2);
++show_fan16_offset(3);
++
+ /* Alarms */
+ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -683,8 +759,6 @@ store_vrm_reg(struct device *dev, struct
+ return count;
+ }
+ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+-#define device_create_file_vrm(client) \
+-device_create_file(&client->dev, &dev_attr_vrm)
+
+ static ssize_t
+ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -693,8 +767,88 @@ show_vid_reg(struct device *dev, struct
+ return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+ }
+ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+-#define device_create_file_vid(client) \
+-device_create_file(&client->dev, &dev_attr_cpu0_vid)
++
++static struct attribute *it87_attributes[] = {
++ &sensor_dev_attr_in0_input.dev_attr.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in5_input.dev_attr.attr,
++ &sensor_dev_attr_in6_input.dev_attr.attr,
++ &sensor_dev_attr_in7_input.dev_attr.attr,
++ &sensor_dev_attr_in8_input.dev_attr.attr,
++ &sensor_dev_attr_in0_min.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in5_min.dev_attr.attr,
++ &sensor_dev_attr_in6_min.dev_attr.attr,
++ &sensor_dev_attr_in7_min.dev_attr.attr,
++ &sensor_dev_attr_in0_max.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ &sensor_dev_attr_in5_max.dev_attr.attr,
++ &sensor_dev_attr_in6_max.dev_attr.attr,
++ &sensor_dev_attr_in7_max.dev_attr.attr,
++
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_min.dev_attr.attr,
++ &sensor_dev_attr_temp2_min.dev_attr.attr,
++ &sensor_dev_attr_temp3_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_type.dev_attr.attr,
++ &sensor_dev_attr_temp2_type.dev_attr.attr,
++ &sensor_dev_attr_temp3_type.dev_attr.attr,
++
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group it87_group = {
++ .attrs = it87_attributes,
++};
++
++static struct attribute *it87_attributes_opt[] = {
++ &sensor_dev_attr_fan1_input16.dev_attr.attr,
++ &sensor_dev_attr_fan1_min16.dev_attr.attr,
++ &sensor_dev_attr_fan2_input16.dev_attr.attr,
++ &sensor_dev_attr_fan2_min16.dev_attr.attr,
++ &sensor_dev_attr_fan3_input16.dev_attr.attr,
++ &sensor_dev_attr_fan3_min16.dev_attr.attr,
++
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++ &sensor_dev_attr_fan1_div.dev_attr.attr,
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_min.dev_attr.attr,
++ &sensor_dev_attr_fan2_div.dev_attr.attr,
++ &sensor_dev_attr_fan3_input.dev_attr.attr,
++ &sensor_dev_attr_fan3_min.dev_attr.attr,
++ &sensor_dev_attr_fan3_div.dev_attr.attr,
++
++ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
++ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
++ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
++ &sensor_dev_attr_pwm1.dev_attr.attr,
++ &sensor_dev_attr_pwm2.dev_attr.attr,
++ &sensor_dev_attr_pwm3.dev_attr.attr,
++
++ &dev_attr_vrm.attr,
++ &dev_attr_cpu0_vid.attr,
++ NULL
++};
++
++static const struct attribute_group it87_group_opt = {
++ .attrs = it87_attributes_opt,
++};
+
+ /* This function is called when:
+ * it87_driver is inserted (when this module is loaded), for each
+@@ -720,10 +874,12 @@ static int __init it87_find(unsigned sho
+ superio_enter();
+ chip_type = superio_inw(DEVID);
+ if (chip_type != IT8712F_DEVID
++ && chip_type != IT8716F_DEVID
++ && chip_type != IT8718F_DEVID
+ && chip_type != IT8705F_DEVID)
+ goto exit;
+
+- superio_select();
++ superio_select(PME);
+ if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
+ pr_info("it87: Device not activated, skipping\n");
+ goto exit;
+@@ -739,6 +895,21 @@ static int __init it87_find(unsigned sho
+ pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
+ chip_type, *address, superio_inb(DEVREV) & 0x0f);
+
++ /* Read GPIO config and VID value from LDN 7 (GPIO) */
++ if (chip_type != IT8705F_DEVID) {
++ int reg;
++
++ superio_select(GPIO);
++ if (chip_type == it8718)
++ vid_value = superio_inb(IT87_SIO_VID_REG);
++
++ reg = superio_inb(IT87_SIO_PINX2_REG);
++ if (reg & (1 << 0))
++ pr_info("it87: in3 is VCC (+5V)\n");
++ if (reg & (1 << 1))
++ pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
++ }
++
+ exit:
+ superio_exit();
+ return err;
+@@ -799,8 +970,19 @@ static int it87_detect(struct i2c_adapte
+ i = it87_read_value(new_client, IT87_REG_CHIPID);
+ if (i == 0x90) {
+ kind = it87;
+- if ((is_isa) && (chip_type == IT8712F_DEVID))
+- kind = it8712;
++ if (is_isa) {
++ switch (chip_type) {
++ case IT8712F_DEVID:
++ kind = it8712;
++ break;
++ case IT8716F_DEVID:
++ kind = it8716;
++ break;
++ case IT8718F_DEVID:
++ kind = it8718;
++ break;
++ }
++ }
+ }
+ else {
+ if (kind == 0)
+@@ -817,6 +999,10 @@ static int it87_detect(struct i2c_adapte
+ name = "it87";
+ } else if (kind == it8712) {
+ name = "it8712";
++ } else if (kind == it8716) {
++ name = "it8716";
++ } else if (kind == it8718) {
++ name = "it8718";
+ }
+
+ /* Fill in the remaining client fields and put it into the global list */
+@@ -841,76 +1027,103 @@ static int it87_detect(struct i2c_adapte
+ it87_init_client(new_client, data);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
+ goto ERROR3;
++
++ /* Do not create fan files for disabled fans */
++ if (data->type == it8716 || data->type == it8718) {
++ /* 16-bit tachometers */
++ if (data->has_fan & (1 << 0)) {
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_input16.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_min16.dev_attr)))
++ goto ERROR4;
++ }
++ if (data->has_fan & (1 << 1)) {
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_input16.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_min16.dev_attr)))
++ goto ERROR4;
++ }
++ if (data->has_fan & (1 << 2)) {
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan3_input16.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan3_min16.dev_attr)))
++ goto ERROR4;
++ }
++ } else {
++ /* 8-bit tachometers with clock divider */
++ if (data->has_fan & (1 << 0)) {
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_input.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_min.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_div.dev_attr)))
++ goto ERROR4;
++ }
++ if (data->has_fan & (1 << 1)) {
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_input.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_min.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_div.dev_attr)))
++ goto ERROR4;
++ }
++ if (data->has_fan & (1 << 2)) {
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan3_input.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan3_min.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan3_div.dev_attr)))
++ goto ERROR4;
++ }
+ }
+
+- device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+ if (enable_pwm_interface) {
+- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
+- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
++ if ((err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_pwm1_enable.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_pwm2_enable.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_pwm3_enable.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_pwm1.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_pwm2.dev_attr))
++ || (err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_pwm3.dev_attr)))
++ goto ERROR4;
+ }
+
+- if (data->type == it8712) {
++ if (data->type == it8712 || data->type == it8716
++ || data->type == it8718) {
+ data->vrm = vid_which_vrm();
+- device_create_file_vrm(new_client);
+- device_create_file_vid(new_client);
++ /* VID reading from Super-I/O config space if available */
++ data->vid = vid_value;
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_vrm))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_cpu0_vid)))
++ goto ERROR4;
++ }
++
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto ERROR4;
+ }
+
+ return 0;
+
++ERROR4:
++ sysfs_remove_group(&new_client->dev.kobj, &it87_group);
++ sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
+ ERROR3:
+ i2c_detach_client(new_client);
+ ERROR2:
+@@ -928,6 +1141,8 @@ static int it87_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &it87_group);
++ sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+@@ -1044,6 +1259,22 @@ static void it87_init_client(struct i2c_
+ data->manual_pwm_ctl[i] = 0xff;
+ }
+
++ /* Some chips seem to have default value 0xff for all limit
++ * registers. For low voltage limits it makes no sense and triggers
++ * alarms, so change to 0 instead. For high temperature limits, it
++ * means -1 degree C, which surprisingly doesn't trigger an alarm,
++ * but is still confusing, so change to 127 degrees C. */
++ for (i = 0; i < 8; i++) {
++ tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
++ if (tmp == 0xff)
++ it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
++ }
++ for (i = 0; i < 3; i++) {
++ tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
++ if (tmp == 0xff)
++ it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
++ }
++
+ /* Check if temperature channnels are reset manually or by some reason */
+ tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+ if ((tmp & 0x3f) == 0) {
+@@ -1067,6 +1298,18 @@ static void it87_init_client(struct i2c_
+ data->fan_main_ctrl |= 0x70;
+ it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ }
++ data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
++
++ /* Set tachometers to 16-bit mode if needed */
++ if (data->type == it8716 || data->type == it8718) {
++ tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
++ if (~tmp & 0x07 & data->has_fan) {
++ dev_dbg(&client->dev,
++ "Setting fan1-3 to 16-bit mode\n");
++ it87_write_value(client, IT87_REG_FAN_16BIT,
++ tmp | 0x07);
++ }
++ }
+
+ /* Set current fan mode registers and the default settings for the
+ * other mode registers */
+@@ -1117,18 +1360,26 @@ static struct it87_data *it87_update_dev
+ data->in_max[i] =
+ it87_read_value(client, IT87_REG_VIN_MAX(i));
+ }
++ /* in8 (battery) has no limit registers */
+ data->in[8] =
+ it87_read_value(client, IT87_REG_VIN(8));
+- /* Temperature sensor doesn't have limit registers, set
+- to min and max value */
+- data->in_min[8] = 0;
+- data->in_max[8] = 255;
+
+ for (i = 0; i < 3; i++) {
+- data->fan[i] =
+- it87_read_value(client, IT87_REG_FAN(i));
++ /* Skip disabled fans */
++ if (!(data->has_fan & (1 << i)))
++ continue;
++
+ data->fan_min[i] =
+ it87_read_value(client, IT87_REG_FAN_MIN(i));
++ data->fan[i] = it87_read_value(client,
++ IT87_REG_FAN(i));
++ /* Add high byte if in 16-bit mode */
++ if (data->type == it8716 || data->type == it8718) {
++ data->fan[i] |= it87_read_value(client,
++ IT87_REG_FANX(i)) << 8;
++ data->fan_min[i] |= it87_read_value(client,
++ IT87_REG_FANX_MIN(i)) << 8;
++ }
+ }
+ for (i = 0; i < 3; i++) {
+ data->temp[i] =
+@@ -1139,10 +1390,14 @@ static struct it87_data *it87_update_dev
+ it87_read_value(client, IT87_REG_TEMP_LOW(i));
+ }
+
+- i = it87_read_value(client, IT87_REG_FAN_DIV);
+- data->fan_div[0] = i & 0x07;
+- data->fan_div[1] = (i >> 3) & 0x07;
+- data->fan_div[2] = (i & 0x40) ? 3 : 1;
++ /* Newer chips don't have clock dividers */
++ if ((data->has_fan & 0x07) && data->type != it8716
++ && data->type != it8718) {
++ i = it87_read_value(client, IT87_REG_FAN_DIV);
++ data->fan_div[0] = i & 0x07;
++ data->fan_div[1] = (i >> 3) & 0x07;
++ data->fan_div[2] = (i & 0x40) ? 3 : 1;
++ }
+
+ data->alarms =
+ it87_read_value(client, IT87_REG_ALARM1) |
+@@ -1152,9 +1407,11 @@ static struct it87_data *it87_update_dev
+
+ data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+ /* The 8705 does not have VID capability */
+- if (data->type == it8712) {
++ if (data->type == it8712 || data->type == it8716) {
+ data->vid = it87_read_value(client, IT87_REG_VID);
+- data->vid &= 0x1f;
++ /* The older IT8712F revisions had only 5 VID pins,
++ but we assume it is always safe to read 6 bits. */
++ data->vid &= 0x3f;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+@@ -1192,8 +1449,9 @@ static void __exit sm_it87_exit(void)
+ }
+
+
+-MODULE_AUTHOR("Chris Gauthron <chrisg at 0-in.com>");
+-MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
++MODULE_AUTHOR("Chris Gauthron <chrisg at 0-in.com>, "
++ "Jean Delvare <khali at linux-fr.org>");
++MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
+ module_param(update_vbat, bool, 0);
+ MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
+ module_param(fix_pwm_polarity, bool, 0);
+diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
+new file mode 100644
+index 0000000..f58b64e
+--- /dev/null
++++ b/drivers/hwmon/k8temp.c
+@@ -0,0 +1,294 @@
++/*
++ * k8temp.c - Linux kernel module for hardware monitoring
++ *
++ * Copyright (C) 2006 Rudolf Marek <r.marek at sh.cvut.cz>
++ *
++ * Inspired from the w83785 and amd756 drivers.
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/jiffies.h>
++#include <linux/pci.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/err.h>
++#include <linux/mutex.h>
++
++#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000)
++#define REG_TEMP 0xe4
++#define SEL_PLACE 0x40
++#define SEL_CORE 0x04
++
++struct k8temp_data {
++ struct class_device *class_dev;
++ struct mutex update_lock;
++ const char *name;
++ char valid; /* zero until following fields are valid */
++ unsigned long last_updated; /* in jiffies */
++
++ /* registers values */
++ u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
++ u32 temp[2][2]; /* core, place */
++};
++
++static struct k8temp_data *k8temp_update_device(struct device *dev)
++{
++ struct k8temp_data *data = dev_get_drvdata(dev);
++ struct pci_dev *pdev = to_pci_dev(dev);
++ u8 tmp;
++
++ mutex_lock(&data->update_lock);
++
++ if (!data->valid
++ || time_after(jiffies, data->last_updated + HZ)) {
++ pci_read_config_byte(pdev, REG_TEMP, &tmp);
++ tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
++ pci_write_config_byte(pdev, REG_TEMP, tmp);
++ pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
++
++ if (data->sensorsp & SEL_PLACE) {
++ tmp |= SEL_PLACE; /* Select sensor 1, core0 */
++ pci_write_config_byte(pdev, REG_TEMP, tmp);
++ pci_read_config_dword(pdev, REG_TEMP,
++ &data->temp[0][1]);
++ }
++
++ if (data->sensorsp & SEL_CORE) {
++ tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */
++ tmp |= SEL_CORE;
++ pci_write_config_byte(pdev, REG_TEMP, tmp);
++ pci_read_config_dword(pdev, REG_TEMP,
++ &data->temp[1][0]);
++
++ if (data->sensorsp & SEL_PLACE) {
++ tmp |= SEL_PLACE; /* Select sensor 1, core1 */
++ pci_write_config_byte(pdev, REG_TEMP, tmp);
++ pci_read_config_dword(pdev, REG_TEMP,
++ &data->temp[1][1]);
++ }
++ }
++
++ data->last_updated = jiffies;
++ data->valid = 1;
++ }
++
++ mutex_unlock(&data->update_lock);
++ return data;
++}
++
++/*
++ * Sysfs stuff
++ */
++
++static ssize_t show_name(struct device *dev, struct device_attribute
++ *devattr, char *buf)
++{
++ struct k8temp_data *data = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%s\n", data->name);
++}
++
++
++static ssize_t show_temp(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr =
++ to_sensor_dev_attr_2(devattr);
++ int core = attr->nr;
++ int place = attr->index;
++ struct k8temp_data *data = k8temp_update_device(dev);
++
++ return sprintf(buf, "%d\n",
++ TEMP_FROM_REG(data->temp[core][place]));
++}
++
++/* core, place */
++
++static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
++static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
++static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
++static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
++static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
++
++static struct pci_device_id k8temp_ids[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
++ { 0 },
++};
++
++MODULE_DEVICE_TABLE(pci, k8temp_ids);
++
++static int __devinit k8temp_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ int err;
++ u8 scfg;
++ u32 temp;
++ struct k8temp_data *data;
++ u32 cpuid = cpuid_eax(1);
++
++ /* this feature should be available since SH-C0 core */
++ if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) {
++ err = -ENODEV;
++ goto exit;
++ }
++
++ if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++ pci_read_config_byte(pdev, REG_TEMP, &scfg);
++ scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
++ pci_write_config_byte(pdev, REG_TEMP, scfg);
++ pci_read_config_byte(pdev, REG_TEMP, &scfg);
++
++ if (scfg & (SEL_PLACE | SEL_CORE)) {
++ dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n");
++ err = -ENODEV;
++ goto exit_free;
++ }
++
++ scfg |= (SEL_PLACE | SEL_CORE);
++ pci_write_config_byte(pdev, REG_TEMP, scfg);
++
++ /* now we know if we can change core and/or sensor */
++ pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp);
++
++ if (data->sensorsp & SEL_PLACE) {
++ scfg &= ~SEL_CORE; /* Select sensor 1, core0 */
++ pci_write_config_byte(pdev, REG_TEMP, scfg);
++ pci_read_config_dword(pdev, REG_TEMP, &temp);
++ scfg |= SEL_CORE; /* prepare for next selection */
++ if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
++ data->sensorsp &= ~SEL_PLACE;
++ }
++
++ if (data->sensorsp & SEL_CORE) {
++ scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */
++ pci_write_config_byte(pdev, REG_TEMP, scfg);
++ pci_read_config_dword(pdev, REG_TEMP, &temp);
++ if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
++ data->sensorsp &= ~SEL_CORE;
++ }
++
++ data->name = "k8temp";
++ mutex_init(&data->update_lock);
++ dev_set_drvdata(&pdev->dev, data);
++
++ /* Register sysfs hooks */
++ err = device_create_file(&pdev->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ if (err)
++ goto exit_remove;
++
++ /* sensor can be changed and reports something */
++ if (data->sensorsp & SEL_PLACE) {
++ err = device_create_file(&pdev->dev,
++ &sensor_dev_attr_temp2_input.dev_attr);
++ if (err)
++ goto exit_remove;
++ }
++
++ /* core can be changed and reports something */
++ if (data->sensorsp & SEL_CORE) {
++ err = device_create_file(&pdev->dev,
++ &sensor_dev_attr_temp3_input.dev_attr);
++ if (err)
++ goto exit_remove;
++ if (data->sensorsp & SEL_PLACE)
++ err = device_create_file(&pdev->dev,
++ &sensor_dev_attr_temp4_input.
++ dev_attr);
++ if (err)
++ goto exit_remove;
++ }
++
++ err = device_create_file(&pdev->dev, &dev_attr_name);
++ if (err)
++ goto exit_remove;
++
++ data->class_dev = hwmon_device_register(&pdev->dev);
++
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove;
++ }
++
++ return 0;
++
++exit_remove:
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp2_input.dev_attr);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp3_input.dev_attr);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp4_input.dev_attr);
++ device_remove_file(&pdev->dev, &dev_attr_name);
++exit_free:
++ dev_set_drvdata(&pdev->dev, NULL);
++ kfree(data);
++exit:
++ return err;
++}
++
++static void __devexit k8temp_remove(struct pci_dev *pdev)
++{
++ struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
++
++ hwmon_device_unregister(data->class_dev);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp2_input.dev_attr);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp3_input.dev_attr);
++ device_remove_file(&pdev->dev,
++ &sensor_dev_attr_temp4_input.dev_attr);
++ device_remove_file(&pdev->dev, &dev_attr_name);
++ dev_set_drvdata(&pdev->dev, NULL);
++ kfree(data);
++}
++
++static struct pci_driver k8temp_driver = {
++ .name = "k8temp",
++ .id_table = k8temp_ids,
++ .probe = k8temp_probe,
++ .remove = __devexit_p(k8temp_remove),
++};
++
++static int __init k8temp_init(void)
++{
++ return pci_register_driver(&k8temp_driver);
++}
++
++static void __exit k8temp_exit(void)
++{
++ pci_unregister_driver(&k8temp_driver);
++}
++
++MODULE_AUTHOR("Rudolf Marek <r.marek at sh.cvut.cz>");
++MODULE_DESCRIPTION("AMD K8 core temperature monitor");
++MODULE_LICENSE("GPL");
++
++module_init(k8temp_init)
++module_exit(k8temp_exit)
+diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
+index 071f0fc..d69f3cf 100644
+--- a/drivers/hwmon/lm63.c
++++ b/drivers/hwmon/lm63.c
+@@ -1,7 +1,7 @@
+ /*
+ * lm63.c - driver for the National Semiconductor LM63 temperature sensor
+ * with integrated fan control
+- * Copyright (C) 2004-2005 Jean Delvare <khali at linux-fr.org>
++ * Copyright (C) 2004-2006 Jean Delvare <khali at linux-fr.org>
+ * Based on the lm90 driver.
+ *
+ * The LM63 is a sensor chip made by National Semiconductor. It measures
+@@ -46,6 +46,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /*
+ * Addresses to scan
+@@ -330,6 +331,16 @@ static ssize_t show_alarms(struct device
+ return sprintf(buf, "%u\n", data->alarms);
+ }
+
++static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr,
++ char *buf)
++{
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct lm63_data *data = lm63_update_device(dev);
++ int bitnr = attr->index;
++
++ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
++}
++
+ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
+ set_fan, 1);
+@@ -350,8 +361,52 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_
+ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
+ set_temp2_crit_hyst);
+
++/* Individual alarm files */
++static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
++static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
++static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
++static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
++static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
++/* Raw alarm file for compatibility */
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
++static struct attribute *lm63_attributes[] = {
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm1_enable.attr,
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit.dev_attr.attr,
++ &dev_attr_temp2_crit_hyst.attr,
++
++ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
++ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group lm63_group = {
++ .attrs = lm63_attributes,
++};
++
++static struct attribute *lm63_attributes_fan1[] = {
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++
++ &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
++ NULL
++};
++
++static const struct attribute_group lm63_group_fan1 = {
++ .attrs = lm63_attributes_fan1,
++};
++
+ /*
+ * Real code
+ */
+@@ -438,37 +493,26 @@ static int lm63_detect(struct i2c_adapte
+ lm63_init_client(new_client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj,
++ &lm63_group)))
+ goto exit_detach;
++ if (data->config & 0x04) { /* tachometer enabled */
++ if ((err = sysfs_create_group(&new_client->dev.kobj,
++ &lm63_group_fan1)))
++ goto exit_remove_files;
+ }
+
+- if (data->config & 0x04) { /* tachometer enabled */
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_fan1_min.dev_attr);
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove_files;
+ }
+- device_create_file(&new_client->dev, &dev_attr_pwm1);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_crit.dev_attr);
+- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
++ sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -518,6 +562,8 @@ static int lm63_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm63_group);
++ sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
+index fc25b90..7c65b8b 100644
+--- a/drivers/hwmon/lm75.c
++++ b/drivers/hwmon/lm75.c
+@@ -112,6 +112,18 @@ static int lm75_attach_adapter(struct i2
+ return i2c_probe(adapter, &addr_data, lm75_detect);
+ }
+
++static struct attribute *lm75_attributes[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm75_group = {
++ .attrs = lm75_attributes,
++};
++
+ /* This function is called by i2c_probe */
+ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+@@ -199,18 +211,19 @@ static int lm75_detect(struct i2c_adapte
+ lm75_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+-
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -223,6 +236,7 @@ static int lm75_detach_client(struct i2c
+ {
+ struct lm75_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm75_group);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
+index 459cc97..dd969f1 100644
+--- a/drivers/hwmon/lm77.c
++++ b/drivers/hwmon/lm77.c
+@@ -212,6 +212,23 @@ static int lm77_attach_adapter(struct i2
+ return i2c_probe(adapter, &addr_data, lm77_detect);
+ }
+
++static struct attribute *lm77_attributes[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_crit.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_crit_hyst.attr,
++ &dev_attr_temp1_min_hyst.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_alarms.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm77_group = {
++ .attrs = lm77_attributes,
++};
++
+ /* This function is called by i2c_probe */
+ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+@@ -317,22 +334,19 @@ static int lm77_detect(struct i2c_adapte
+ lm77_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -345,6 +359,7 @@ static int lm77_detach_client(struct i2c
+ {
+ struct lm77_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm77_group);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
+index a6ce7ab..73bc2ff 100644
+--- a/drivers/hwmon/lm78.c
++++ b/drivers/hwmon/lm78.c
+@@ -175,6 +175,7 @@ static struct i2c_driver lm78_driver = {
+
+ static struct i2c_driver lm78_isa_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "lm78-isa",
+ },
+ .attach_adapter = lm78_isa_attach_adapter,
+@@ -481,6 +482,50 @@ static int lm78_isa_attach_adapter(struc
+ return lm78_detect(adapter, isa_address, -1);
+ }
+
++static struct attribute *lm78_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++ &dev_attr_in5_input.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in5_max.attr,
++ &dev_attr_in6_input.attr,
++ &dev_attr_in6_min.attr,
++ &dev_attr_in6_max.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++ &dev_attr_fan3_input.attr,
++ &dev_attr_fan3_min.attr,
++ &dev_attr_fan3_div.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_cpu0_vid.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm78_group = {
++ .attrs = lm78_attributes,
++};
++
+ /* This function is called by i2c_probe */
+ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+@@ -615,50 +660,19 @@ static int lm78_detect(struct i2c_adapte
+ }
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
++ goto ERROR3;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto ERROR3;
++ goto ERROR4;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
+- device_create_file(&new_client->dev, &dev_attr_in5_input);
+- device_create_file(&new_client->dev, &dev_attr_in5_min);
+- device_create_file(&new_client->dev, &dev_attr_in5_max);
+- device_create_file(&new_client->dev, &dev_attr_in6_input);
+- device_create_file(&new_client->dev, &dev_attr_in6_min);
+- device_create_file(&new_client->dev, &dev_attr_in6_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+- device_create_file(&new_client->dev, &dev_attr_fan3_input);
+- device_create_file(&new_client->dev, &dev_attr_fan3_min);
+- device_create_file(&new_client->dev, &dev_attr_fan3_div);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+-
+ return 0;
+
++ERROR4:
++ sysfs_remove_group(&new_client->dev.kobj, &lm78_group);
+ ERROR3:
+ i2c_detach_client(new_client);
+ ERROR2:
+@@ -676,6 +690,7 @@ static int lm78_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm78_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+@@ -800,18 +815,18 @@ static int __init sm_lm78_init(void)
+ if (res)
+ return res;
+
+- res = i2c_isa_add_driver(&lm78_isa_driver);
+- if (res) {
+- i2c_del_driver(&lm78_driver);
+- return res;
+- }
++ /* Don't exit if this one fails, we still want the I2C variants
++ to work! */
++ if (i2c_isa_add_driver(&lm78_isa_driver))
++ isa_address = 0;
+
+ return 0;
+ }
+
+ static void __exit sm_lm78_exit(void)
+ {
+- i2c_isa_del_driver(&lm78_isa_driver);
++ if (isa_address)
++ i2c_isa_del_driver(&lm78_isa_driver);
+ i2c_del_driver(&lm78_driver);
+ }
+
+diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
+index b4ccdfc..064516d 100644
+--- a/drivers/hwmon/lm80.c
++++ b/drivers/hwmon/lm80.c
+@@ -394,6 +394,48 @@ static int lm80_attach_adapter(struct i2
+ return i2c_probe(adapter, &addr_data, lm80_detect);
+ }
+
++static struct attribute *lm80_attributes[] = {
++ &dev_attr_in0_min.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in6_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in4_max.attr,
++ &dev_attr_in5_max.attr,
++ &dev_attr_in6_max.attr,
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in4_input.attr,
++ &dev_attr_in5_input.attr,
++ &dev_attr_in6_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_div.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_temp1_crit.attr,
++ &dev_attr_temp1_crit_hyst.attr,
++ &dev_attr_alarms.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm80_group = {
++ .attrs = lm80_attributes,
++};
++
+ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+ int i, cur;
+@@ -452,48 +494,19 @@ static int lm80_detect(struct i2c_adapte
+ data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
++ goto error_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto error_detach;
++ goto error_remove;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in5_min);
+- device_create_file(&new_client->dev, &dev_attr_in6_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
+- device_create_file(&new_client->dev, &dev_attr_in5_max);
+- device_create_file(&new_client->dev, &dev_attr_in6_max);
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in5_input);
+- device_create_file(&new_client->dev, &dev_attr_in6_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+-
+ return 0;
+
++error_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &lm80_group);
+ error_detach:
+ i2c_detach_client(new_client);
+ error_free:
+@@ -508,7 +521,7 @@ static int lm80_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
+-
++ sysfs_remove_group(&client->dev.kobj, &lm80_group);
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
+index 2137d78..feb87b4 100644
+--- a/drivers/hwmon/lm83.c
++++ b/drivers/hwmon/lm83.c
+@@ -1,7 +1,7 @@
+ /*
+ * lm83.c - Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring
+- * Copyright (C) 2003-2005 Jean Delvare <khali at linux-fr.org>
++ * Copyright (C) 2003-2006 Jean Delvare <khali at linux-fr.org>
+ *
+ * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
+ * a sensor chip made by National Semiconductor. It reports up to four
+@@ -40,6 +40,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /*
+ * Addresses to scan
+@@ -191,6 +192,16 @@ static ssize_t show_alarms(struct device
+ return sprintf(buf, "%d\n", data->alarms);
+ }
+
++static ssize_t show_alarm(struct device *dev, struct device_attribute
++ *devattr, char *buf)
++{
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct lm83_data *data = lm83_update_device(dev);
++ int bitnr = attr->index;
++
++ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
++}
++
+ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+ static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+ static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+@@ -208,8 +219,64 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_
+ static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, 8);
+ static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
++
++/* Individual alarm files */
++static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
++static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
++static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
++static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
++static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
++static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
++static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
++static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
++static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
++static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
++/* Raw alarm file for compatibility */
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
++static struct attribute *lm83_attributes[] = {
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit.dev_attr.attr,
++ &sensor_dev_attr_temp3_crit.dev_attr.attr,
++
++ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
++ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group lm83_group = {
++ .attrs = lm83_attributes,
++};
++
++static struct attribute *lm83_attributes_opt[] = {
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp4_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp4_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit.dev_attr.attr,
++ &sensor_dev_attr_temp4_crit.dev_attr.attr,
++
++ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp4_input_fault.dev_attr.attr,
++ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
++ NULL
++};
++
++static const struct attribute_group lm83_group_opt = {
++ .attrs = lm83_attributes_opt,
++};
++
+ /*
+ * Real code
+ */
+@@ -318,59 +385,32 @@ static int lm83_detect(struct i2c_adapte
+ goto exit_free;
+
+ /*
+- * Initialize the LM83 chip
+- * (Nothing to do for this one.)
+- */
+-
+- /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
+- goto exit_detach;
+- }
+-
+- /*
++ * Register sysfs hooks
+ * The LM82 can only monitor one external diode which is
+ * at the same register as the LM83 temp3 entry - so we
+ * declare 1 and 3 common, and then 2 and 4 only for the LM83.
+ */
+
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp3_input.dev_attr);
+-
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp3_max.dev_attr);
+-
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_crit.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp3_crit.dev_attr);
+-
+- device_create_file(&new_client->dev, &dev_attr_alarms);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
++ goto exit_detach;
+
+ if (kind == lm83) {
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp4_input.dev_attr);
+-
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp4_max.dev_attr);
+-
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_crit.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp4_crit.dev_attr);
++ if ((err = sysfs_create_group(&new_client->dev.kobj,
++ &lm83_group_opt)))
++ goto exit_remove_files;
++ }
++
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove_files;
+ }
+
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
++ sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -385,6 +425,8 @@ static int lm83_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm83_group);
++ sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
+index 342e966..2c3293c 100644
+--- a/drivers/hwmon/lm85.c
++++ b/drivers/hwmon/lm85.c
+@@ -1025,6 +1025,89 @@ static int lm85_attach_adapter(struct i2
+ return i2c_probe(adapter, &addr_data, lm85_detect);
+ }
+
++static struct attribute *lm85_attributes[] = {
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan3_input.attr,
++ &dev_attr_fan4_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan3_min.attr,
++ &dev_attr_fan4_min.attr,
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_pwm3.attr,
++ &dev_attr_pwm1_enable.attr,
++ &dev_attr_pwm2_enable.attr,
++ &dev_attr_pwm3_enable.attr,
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp2_min.attr,
++ &dev_attr_temp3_min.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp3_max.attr,
++ &dev_attr_vrm.attr,
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_pwm1_auto_channels.attr,
++ &dev_attr_pwm2_auto_channels.attr,
++ &dev_attr_pwm3_auto_channels.attr,
++ &dev_attr_pwm1_auto_pwm_min.attr,
++ &dev_attr_pwm2_auto_pwm_min.attr,
++ &dev_attr_pwm3_auto_pwm_min.attr,
++ &dev_attr_pwm1_auto_pwm_minctl.attr,
++ &dev_attr_pwm2_auto_pwm_minctl.attr,
++ &dev_attr_pwm3_auto_pwm_minctl.attr,
++ &dev_attr_pwm1_auto_pwm_freq.attr,
++ &dev_attr_pwm2_auto_pwm_freq.attr,
++ &dev_attr_pwm3_auto_pwm_freq.attr,
++ &dev_attr_temp1_auto_temp_off.attr,
++ &dev_attr_temp2_auto_temp_off.attr,
++ &dev_attr_temp3_auto_temp_off.attr,
++ &dev_attr_temp1_auto_temp_min.attr,
++ &dev_attr_temp2_auto_temp_min.attr,
++ &dev_attr_temp3_auto_temp_min.attr,
++ &dev_attr_temp1_auto_temp_max.attr,
++ &dev_attr_temp2_auto_temp_max.attr,
++ &dev_attr_temp3_auto_temp_max.attr,
++ &dev_attr_temp1_auto_temp_crit.attr,
++ &dev_attr_temp2_auto_temp_crit.attr,
++ &dev_attr_temp3_auto_temp_crit.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm85_group = {
++ .attrs = lm85_attributes,
++};
++
++static struct attribute *lm85_attributes_opt[] = {
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm85_group_opt = {
++ .attrs = lm85_attributes_opt,
++};
++
+ static int lm85_detect(struct i2c_adapter *adapter, int address,
+ int kind)
+ {
+@@ -1163,87 +1246,33 @@ static int lm85_detect(struct i2c_adapte
+ lm85_init_client(new_client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm85_group)))
+ goto ERROR2;
+- }
+-
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan3_input);
+- device_create_file(&new_client->dev, &dev_attr_fan4_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan3_min);
+- device_create_file(&new_client->dev, &dev_attr_fan4_min);
+- device_create_file(&new_client->dev, &dev_attr_pwm1);
+- device_create_file(&new_client->dev, &dev_attr_pwm2);
+- device_create_file(&new_client->dev, &dev_attr_pwm3);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
+- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp3_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_temp3_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_temp3_max);
+- device_create_file(&new_client->dev, &dev_attr_vrm);
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels);
+- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min);
+- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl);
+- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq);
+- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq);
+- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off);
+- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off);
+- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off);
+- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min);
+- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max);
+- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit);
+
+ /* The ADT7463 has an optional VRM 10 mode where pin 21 is used
+ as a sixth digital VID input rather than an analog input. */
+ data->vid = lm85_read_value(new_client, LM85_REG_VID);
+- if (!(kind == adt7463 && (data->vid & 0x80))) {
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
++ if (!(kind == adt7463 && (data->vid & 0x80)))
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in4_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_max)))
++ goto ERROR3;
++
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto ERROR3;
+ }
+
+ return 0;
+
+ /* Error out and cleanup code */
++ ERROR3:
++ sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
++ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
+ ERROR2:
+ i2c_detach_client(new_client);
+ ERROR1:
+@@ -1256,6 +1285,8 @@ static int lm85_detach_client(struct i2c
+ {
+ struct lm85_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm85_group);
++ sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
+index e6c1b63..3ce8254 100644
+--- a/drivers/hwmon/lm87.c
++++ b/drivers/hwmon/lm87.c
+@@ -542,6 +542,78 @@ static int lm87_attach_adapter(struct i2
+ return i2c_probe(adapter, &addr_data, lm87_detect);
+ }
+
++static struct attribute *lm87_attributes[] = {
++ &dev_attr_in1_input.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp1_crit.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_min.attr,
++ &dev_attr_temp2_crit.attr,
++
++ &dev_attr_alarms.attr,
++ &dev_attr_aout_output.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm87_group = {
++ .attrs = lm87_attributes,
++};
++
++static struct attribute *lm87_attributes_opt[] = {
++ &dev_attr_in6_input.attr,
++ &dev_attr_in6_min.attr,
++ &dev_attr_in6_max.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++
++ &dev_attr_in7_input.attr,
++ &dev_attr_in7_min.attr,
++ &dev_attr_in7_max.attr,
++
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp3_max.attr,
++ &dev_attr_temp3_min.attr,
++ &dev_attr_temp3_crit.attr,
++
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in5_input.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in5_max.attr,
++
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm87_group_opt = {
++ .attrs = lm87_attributes_opt,
++};
++
+ /*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+@@ -609,77 +681,90 @@ static int lm87_detect(struct i2c_adapte
+ data->in_scale[7] = 1875;
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
+ goto exit_detach;
+- }
+-
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
+
+ if (data->channel & CHAN_NO_FAN(0)) {
+- device_create_file(&new_client->dev, &dev_attr_in6_input);
+- device_create_file(&new_client->dev, &dev_attr_in6_min);
+- device_create_file(&new_client->dev, &dev_attr_in6_max);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in6_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in6_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in6_max)))
++ goto exit_remove;
+ } else {
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_fan1_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan1_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan1_div)))
++ goto exit_remove;
+ }
++
+ if (data->channel & CHAN_NO_FAN(1)) {
+- device_create_file(&new_client->dev, &dev_attr_in7_input);
+- device_create_file(&new_client->dev, &dev_attr_in7_min);
+- device_create_file(&new_client->dev, &dev_attr_in7_max);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in7_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in7_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in7_max)))
++ goto exit_remove;
+ } else {
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_fan2_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan2_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan2_div)))
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+-
+ if (data->channel & CHAN_TEMP3) {
+- device_create_file(&new_client->dev, &dev_attr_temp3_input);
+- device_create_file(&new_client->dev, &dev_attr_temp3_max);
+- device_create_file(&new_client->dev, &dev_attr_temp3_min);
+- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_crit)))
++ goto exit_remove;
+ } else {
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in5_input);
+- device_create_file(&new_client->dev, &dev_attr_in5_min);
+- device_create_file(&new_client->dev, &dev_attr_in5_max);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in0_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in0_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in0_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in5_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in5_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in5_max)))
++ goto exit_remove;
+ }
+
+ if (!(data->channel & CHAN_NO_VID)) {
+- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+- device_create_file(&new_client->dev, &dev_attr_vrm);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_cpu0_vid))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_vrm)))
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- device_create_file(&new_client->dev, &dev_attr_aout_output);
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove;
++ }
+
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
++ sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -732,6 +817,8 @@ static int lm87_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm87_group);
++ sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
+index d9eeaf7..6882ce7 100644
+--- a/drivers/hwmon/lm90.c
++++ b/drivers/hwmon/lm90.c
+@@ -1,7 +1,7 @@
+ /*
+ * lm90.c - Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring
+- * Copyright (C) 2003-2005 Jean Delvare <khali at linux-fr.org>
++ * Copyright (C) 2003-2006 Jean Delvare <khali at linux-fr.org>
+ *
+ * Based on the lm83 driver. The LM90 is a sensor chip made by National
+ * Semiconductor. It reports up to two temperatures (its own plus up to
+@@ -79,6 +79,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /*
+ * Addresses to scan
+@@ -327,6 +328,16 @@ static ssize_t show_alarms(struct device
+ return sprintf(buf, "%d\n", data->alarms);
+ }
+
++static ssize_t show_alarm(struct device *dev, struct device_attribute
++ *devattr, char *buf)
++{
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct lm90_data *data = lm90_update_device(dev);
++ int bitnr = attr->index;
++
++ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
++}
++
+ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
+ static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
+ static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
+@@ -344,8 +355,45 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_
+ static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
+ set_temphyst, 3);
+ static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
++
++/* Individual alarm files */
++static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
++static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
++static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
++static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
++static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
++static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
++/* Raw alarm file for compatibility */
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
++static struct attribute *lm90_attributes[] = {
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_min.dev_attr.attr,
++ &sensor_dev_attr_temp2_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
++
++ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
++ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group lm90_group = {
++ .attrs = lm90_attributes,
++};
++
+ /* pec used for ADM1032 only */
+ static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
+ char *buf)
+@@ -569,39 +617,25 @@ static int lm90_detect(struct i2c_adapte
+ lm90_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
++ goto exit_detach;
++ if (new_client->flags & I2C_CLIENT_PEC) {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_pec)))
++ goto exit_remove_files;
++ }
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_min.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_crit.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_crit.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_crit_hyst.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_crit_hyst.dev_attr);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+-
+- if (new_client->flags & I2C_CLIENT_PEC)
+- device_create_file(&new_client->dev, &dev_attr_pec);
+-
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
++ device_remove_file(&new_client->dev, &dev_attr_pec);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -634,6 +668,8 @@ static int lm90_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm90_group);
++ device_remove_file(&client->dev, &dev_attr_pec);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
+index 197f772..30b5363 100644
+--- a/drivers/hwmon/lm92.c
++++ b/drivers/hwmon/lm92.c
+@@ -288,6 +288,23 @@ static int max6635_check(struct i2c_clie
+ return 1;
+ }
+
++static struct attribute *lm92_attributes[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_crit.attr,
++ &dev_attr_temp1_crit_hyst.attr,
++ &dev_attr_temp1_min.attr,
++ &dev_attr_temp1_min_hyst.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_alarms.attr,
++
++ NULL
++};
++
++static const struct attribute_group lm92_group = {
++ .attrs = lm92_attributes,
++};
++
+ /* The following function does more than just detection. If detection
+ succeeds, it also registers the new chip. */
+ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
+@@ -359,23 +376,19 @@ static int lm92_detect(struct i2c_adapte
+ lm92_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min);
+- device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+-
+ return 0;
+
++exit_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -397,6 +410,7 @@ static int lm92_detach_client(struct i2c
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &lm92_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
+index b4135b5..2f58f65 100644
+--- a/drivers/hwmon/max1619.c
++++ b/drivers/hwmon/max1619.c
+@@ -34,6 +34,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
+ 0x29, 0x2a, 0x2b,
+@@ -172,6 +173,22 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IW
+ set_temp_hyst2);
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
++static struct attribute *max1619_attributes[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_min.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_crit.attr,
++ &dev_attr_temp2_crit_hyst.attr,
++
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group max1619_group = {
++ .attrs = max1619_attributes,
++};
++
+ /*
+ * Real code
+ */
+@@ -273,22 +290,19 @@ static int max1619_detect(struct i2c_ada
+ max1619_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_min);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+-
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -318,6 +332,7 @@ static int max1619_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &max1619_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
+index ae05e48..3b8b819 100644
+--- a/drivers/hwmon/pc87360.c
++++ b/drivers/hwmon/pc87360.c
+@@ -238,6 +238,7 @@ static struct pc87360_data *pc87360_upda
+
+ static struct i2c_driver pc87360_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "pc87360",
+ },
+ .attach_adapter = pc87360_detect,
+@@ -327,6 +328,12 @@ static struct sensor_device_attribute fa
+ SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
+ };
+
++#define FAN_UNIT_ATTRS(X) \
++ &fan_input[X].dev_attr.attr, \
++ &fan_status[X].dev_attr.attr, \
++ &fan_div[X].dev_attr.attr, \
++ &fan_min[X].dev_attr.attr
++
+ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
+ {
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+@@ -359,6 +366,19 @@ static struct sensor_device_attribute pw
+ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
+ };
+
++static struct attribute * pc8736x_fan_attr_array[] = {
++ FAN_UNIT_ATTRS(0),
++ FAN_UNIT_ATTRS(1),
++ FAN_UNIT_ATTRS(2),
++ &pwm[0].dev_attr.attr,
++ &pwm[1].dev_attr.attr,
++ &pwm[2].dev_attr.attr,
++ NULL
++};
++static const struct attribute_group pc8736x_fan_group = {
++ .attrs = pc8736x_fan_attr_array,
++};
++
+ static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+ {
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+@@ -471,6 +491,61 @@ static struct sensor_device_attribute in
+ SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
+ };
+
++#define VIN_UNIT_ATTRS(X) \
++ &in_input[X].dev_attr.attr, \
++ &in_status[X].dev_attr.attr, \
++ &in_min[X].dev_attr.attr, \
++ &in_max[X].dev_attr.attr
++
++static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct pc87360_data *data = pc87360_update_device(dev);
++ return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
++}
++static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
++
++static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct pc87360_data *data = pc87360_update_device(dev);
++ return sprintf(buf, "%u\n", data->vrm);
++}
++static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct pc87360_data *data = i2c_get_clientdata(client);
++ data->vrm = simple_strtoul(buf, NULL, 10);
++ return count;
++}
++static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
++
++static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct pc87360_data *data = pc87360_update_device(dev);
++ return sprintf(buf, "%u\n", data->in_alarms);
++}
++static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
++
++static struct attribute *pc8736x_vin_attr_array[] = {
++ VIN_UNIT_ATTRS(0),
++ VIN_UNIT_ATTRS(1),
++ VIN_UNIT_ATTRS(2),
++ VIN_UNIT_ATTRS(3),
++ VIN_UNIT_ATTRS(4),
++ VIN_UNIT_ATTRS(5),
++ VIN_UNIT_ATTRS(6),
++ VIN_UNIT_ATTRS(7),
++ VIN_UNIT_ATTRS(8),
++ VIN_UNIT_ATTRS(9),
++ VIN_UNIT_ATTRS(10),
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ &dev_attr_alarms_in.attr,
++ NULL
++};
++static const struct attribute_group pc8736x_vin_group = {
++ .attrs = pc8736x_vin_attr_array,
++};
++
+ static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
+ {
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+@@ -589,33 +664,22 @@ static struct sensor_device_attribute th
+ show_therm_crit, set_therm_crit, 2+11),
+ };
+
+-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+-{
+- struct pc87360_data *data = pc87360_update_device(dev);
+- return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+-}
+-static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+-
+-static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+-{
+- struct pc87360_data *data = pc87360_update_device(dev);
+- return sprintf(buf, "%u\n", data->vrm);
+-}
+-static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+-{
+- struct i2c_client *client = to_i2c_client(dev);
+- struct pc87360_data *data = i2c_get_clientdata(client);
+- data->vrm = simple_strtoul(buf, NULL, 10);
+- return count;
+-}
+-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+-
+-static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+-{
+- struct pc87360_data *data = pc87360_update_device(dev);
+- return sprintf(buf, "%u\n", data->in_alarms);
+-}
+-static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
++#define THERM_UNIT_ATTRS(X) \
++ &therm_input[X].dev_attr.attr, \
++ &therm_status[X].dev_attr.attr, \
++ &therm_min[X].dev_attr.attr, \
++ &therm_max[X].dev_attr.attr, \
++ &therm_crit[X].dev_attr.attr
++
++static struct attribute * pc8736x_therm_attr_array[] = {
++ THERM_UNIT_ATTRS(0),
++ THERM_UNIT_ATTRS(1),
++ THERM_UNIT_ATTRS(2),
++ NULL
++};
++static const struct attribute_group pc8736x_therm_group = {
++ .attrs = pc8736x_therm_attr_array,
++};
+
+ static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
+ {
+@@ -735,6 +799,25 @@ static ssize_t show_temp_alarms(struct d
+ }
+ static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
+
++#define TEMP_UNIT_ATTRS(X) \
++ &temp_input[X].dev_attr.attr, \
++ &temp_status[X].dev_attr.attr, \
++ &temp_min[X].dev_attr.attr, \
++ &temp_max[X].dev_attr.attr, \
++ &temp_crit[X].dev_attr.attr
++
++static struct attribute * pc8736x_temp_attr_array[] = {
++ TEMP_UNIT_ATTRS(0),
++ TEMP_UNIT_ATTRS(1),
++ TEMP_UNIT_ATTRS(2),
++ /* include the few miscellaneous atts here */
++ &dev_attr_alarms_temp.attr,
++ NULL
++};
++static const struct attribute_group pc8736x_temp_group = {
++ .attrs = pc8736x_temp_attr_array,
++};
++
+ /*
+ * Device detection, registration and update
+ */
+@@ -935,60 +1018,69 @@ static int pc87360_detect(struct i2c_ada
+ pc87360_init_client(client, use_thermistors);
+ }
+
+- /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ /* Register all-or-nothing sysfs groups */
++
++ if (data->innr &&
++ (err = sysfs_create_group(&client->dev.kobj,
++ &pc8736x_vin_group)))
+ goto ERROR3;
+- }
+
+- if (data->innr) {
+- for (i = 0; i < 11; i++) {
+- device_create_file(dev, &in_input[i].dev_attr);
+- device_create_file(dev, &in_min[i].dev_attr);
+- device_create_file(dev, &in_max[i].dev_attr);
+- device_create_file(dev, &in_status[i].dev_attr);
+- }
+- device_create_file(dev, &dev_attr_cpu0_vid);
+- device_create_file(dev, &dev_attr_vrm);
+- device_create_file(dev, &dev_attr_alarms_in);
+- }
++ if (data->innr == 14 &&
++ (err = sysfs_create_group(&client->dev.kobj,
++ &pc8736x_therm_group)))
++ goto ERROR3;
++
++ /* create device attr-files for varying sysfs groups */
+
+ if (data->tempnr) {
+ for (i = 0; i < data->tempnr; i++) {
+- device_create_file(dev, &temp_input[i].dev_attr);
+- device_create_file(dev, &temp_min[i].dev_attr);
+- device_create_file(dev, &temp_max[i].dev_attr);
+- device_create_file(dev, &temp_crit[i].dev_attr);
+- device_create_file(dev, &temp_status[i].dev_attr);
+- }
+- device_create_file(dev, &dev_attr_alarms_temp);
+- }
+-
+- if (data->innr == 14) {
+- for (i = 0; i < 3; i++) {
+- device_create_file(dev, &therm_input[i].dev_attr);
+- device_create_file(dev, &therm_min[i].dev_attr);
+- device_create_file(dev, &therm_max[i].dev_attr);
+- device_create_file(dev, &therm_crit[i].dev_attr);
+- device_create_file(dev, &therm_status[i].dev_attr);
++ if ((err = device_create_file(dev,
++ &temp_input[i].dev_attr))
++ || (err = device_create_file(dev,
++ &temp_min[i].dev_attr))
++ || (err = device_create_file(dev,
++ &temp_max[i].dev_attr))
++ || (err = device_create_file(dev,
++ &temp_crit[i].dev_attr))
++ || (err = device_create_file(dev,
++ &temp_status[i].dev_attr)))
++ goto ERROR3;
+ }
++ if ((err = device_create_file(dev, &dev_attr_alarms_temp)))
++ goto ERROR3;
+ }
+
+ for (i = 0; i < data->fannr; i++) {
+- if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
+- device_create_file(dev, &fan_input[i].dev_attr);
+- device_create_file(dev, &fan_min[i].dev_attr);
+- device_create_file(dev, &fan_div[i].dev_attr);
+- device_create_file(dev, &fan_status[i].dev_attr);
+- }
+- if (FAN_CONFIG_CONTROL(data->fan_conf, i))
+- device_create_file(dev, &pwm[i].dev_attr);
++ if (FAN_CONFIG_MONITOR(data->fan_conf, i)
++ && ((err = device_create_file(dev,
++ &fan_input[i].dev_attr))
++ || (err = device_create_file(dev,
++ &fan_min[i].dev_attr))
++ || (err = device_create_file(dev,
++ &fan_div[i].dev_attr))
++ || (err = device_create_file(dev,
++ &fan_status[i].dev_attr))))
++ goto ERROR3;
++
++ if (FAN_CONFIG_CONTROL(data->fan_conf, i)
++ && (err = device_create_file(dev, &pwm[i].dev_attr)))
++ goto ERROR3;
+ }
+
++ data->class_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto ERROR3;
++ }
+ return 0;
+
+ ERROR3:
++ /* can still remove groups whose members were added individually */
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
++
+ i2c_detach_client(client);
+ ERROR2:
+ for (i = 0; i < 3; i++) {
+@@ -1008,6 +1100,11 @@ static int pc87360_detach_client(struct
+
+ hwmon_device_unregister(data->class_dev);
+
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
++ sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
++
+ if ((i = i2c_detach_client(client)))
+ return i;
+
+diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
+index 063f71c..95a4b5d 100644
+--- a/drivers/hwmon/sis5595.c
++++ b/drivers/hwmon/sis5595.c
+@@ -61,6 +61,7 @@
+ #include <linux/init.h>
+ #include <linux/jiffies.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+ #include <asm/io.h>
+
+
+@@ -200,6 +201,7 @@ static void sis5595_init_client(struct i
+
+ static struct i2c_driver sis5595_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "sis5595",
+ },
+ .attach_adapter = sis5595_detect,
+@@ -472,6 +474,50 @@ static ssize_t show_alarms(struct device
+ return sprintf(buf, "%d\n", data->alarms);
+ }
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
++
++static struct attribute *sis5595_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in3_max.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group sis5595_group = {
++ .attrs = sis5595_attributes,
++};
++
++static struct attribute *sis5595_attributes_opt[] = {
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ NULL
++};
++
++static const struct attribute_group sis5595_group_opt = {
++ .attrs = sis5595_attributes_opt,
++};
+
+ /* This is called when the module is loaded */
+ static int sis5595_detect(struct i2c_adapter *adapter)
+@@ -565,43 +611,37 @@ static int sis5595_detect(struct i2c_ada
+ }
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
++ goto exit_detach;
++ if (data->maxins == 4) {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in4_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in4_max)))
++ goto exit_remove_files;
++ } else {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_temp1_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp1_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp1_max_hyst)))
++ goto exit_remove_files;
++ }
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- if (data->maxins == 4) {
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
+- }
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+- if (data->maxins == 3) {
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- }
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
++ sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -618,6 +658,8 @@ static int sis5595_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &sis5595_group);
++ sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
+index b608618..72b0e2d 100644
+--- a/drivers/hwmon/smsc47b397.c
++++ b/drivers/hwmon/smsc47b397.c
+@@ -176,9 +176,6 @@ sysfs_temp(2);
+ sysfs_temp(3);
+ sysfs_temp(4);
+
+-#define device_create_file_temp(client, num) \
+- device_create_file(&client->dev, &dev_attr_temp##num##_input)
+-
+ /* FAN: 1 RPM/bit
+ REG: count of 90kHz pulses / revolution */
+ static int fan_from_reg(u16 reg)
+@@ -205,8 +202,22 @@ sysfs_fan(2);
+ sysfs_fan(3);
+ sysfs_fan(4);
+
+-#define device_create_file_fan(client, num) \
+- device_create_file(&client->dev, &dev_attr_fan##num##_input)
++static struct attribute *smsc47b397_attributes[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp4_input.attr,
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan3_input.attr,
++ &dev_attr_fan4_input.attr,
++
++ NULL
++};
++
++static const struct attribute_group smsc47b397_group = {
++ .attrs = smsc47b397_attributes,
++};
+
+ static int smsc47b397_detach_client(struct i2c_client *client)
+ {
+@@ -214,6 +225,7 @@ static int smsc47b397_detach_client(stru
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+@@ -228,6 +240,7 @@ static int smsc47b397_detect(struct i2c_
+
+ static struct i2c_driver smsc47b397_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "smsc47b397",
+ },
+ .attach_adapter = smsc47b397_detect,
+@@ -267,24 +280,19 @@ static int smsc47b397_detect(struct i2c_
+ if ((err = i2c_attach_client(new_client)))
+ goto error_free;
+
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group)))
++ goto error_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto error_detach;
++ goto error_remove;
+ }
+
+- device_create_file_temp(new_client, 1);
+- device_create_file_temp(new_client, 2);
+- device_create_file_temp(new_client, 3);
+- device_create_file_temp(new_client, 4);
+-
+- device_create_file_fan(new_client, 1);
+- device_create_file_fan(new_client, 2);
+- device_create_file_fan(new_client, 3);
+- device_create_file_fan(new_client, 4);
+-
+ return 0;
+
++error_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
+ error_detach:
+ i2c_detach_client(new_client);
+ error_free:
+diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
+index 825e8f7..beb881c 100644
+--- a/drivers/hwmon/smsc47m1.c
++++ b/drivers/hwmon/smsc47m1.c
+@@ -2,8 +2,8 @@
+ smsc47m1.c - Part of lm_sensors, Linux kernel modules
+ for hardware monitoring
+
+- Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x,
+- LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
++ Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
++ LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
+
+ Copyright (C) 2002 Mark D. Studebaker <mdsxyz123 at yahoo.com>
+ Copyright (C) 2004 Jean Delvare <khali at linux-fr.org>
+@@ -35,6 +35,7 @@
+ #include <linux/err.h>
+ #include <linux/init.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+ #include <asm/io.h>
+
+ /* Address is autodetected, there is no default value */
+@@ -128,6 +129,7 @@ static struct smsc47m1_data *smsc47m1_up
+
+ static struct i2c_driver smsc47m1_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "smsc47m1",
+ },
+ .attach_adapter = smsc47m1_detect,
+@@ -346,6 +348,30 @@ fan_present(2);
+
+ static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+
++/* Almost all sysfs files may or may not be created depending on the chip
++ setup so we create them individually. It is still convenient to define a
++ group to remove them all at once. */
++static struct attribute *smsc47m1_attributes[] = {
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm1_enable.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_pwm2_enable.attr,
++
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group smsc47m1_group = {
++ .attrs = smsc47m1_attributes,
++};
++
+ static int __init smsc47m1_find(unsigned short *addr)
+ {
+ u8 val;
+@@ -354,8 +380,8 @@ static int __init smsc47m1_find(unsigned
+ val = superio_inb(SUPERIO_REG_DEVID);
+
+ /*
+- * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
+- * 0x5F) and LPC47B27x (device id 0x51) have fan control.
++ * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
++ * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
+ * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
+ * can do much more besides (device id 0x60).
+ * The LPC47M997 is undocumented, but seems to be compatible with
+@@ -364,7 +390,8 @@ static int __init smsc47m1_find(unsigned
+ if (val == 0x51)
+ printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
+ else if (val == 0x59)
+- printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n");
++ printk(KERN_INFO "smsc47m1: Found SMSC "
++ "LPC47M10x/LPC47M112/LPC47M13x\n");
+ else if (val == 0x5F)
+ printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
+ else if (val == 0x60)
+@@ -428,7 +455,8 @@ static int smsc47m1_detect(struct i2c_ad
+ pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
+ == 0x04;
+ if (!(fan1 || fan2 || pwm1 || pwm2)) {
+- dev_warn(&new_client->dev, "Device is not configured, will not use\n");
++ dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
++ "will not use\n", new_client->addr);
+ err = -ENODEV;
+ goto error_free;
+ }
+@@ -445,46 +473,62 @@ static int smsc47m1_detect(struct i2c_ad
+ smsc47m1_update_device(&new_client->dev, 1);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
+- goto error_detach;
+- }
+-
+ if (fan1) {
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_fan1_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan1_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan1_div)))
++ goto error_remove_files;
+ } else
+ dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
+ "skipping\n");
+
+ if (fan2) {
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_fan2_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan2_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan2_div)))
++ goto error_remove_files;
+ } else
+ dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
+ "skipping\n");
+
+ if (pwm1) {
+- device_create_file(&new_client->dev, &dev_attr_pwm1);
+- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_pwm1))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_pwm1_enable)))
++ goto error_remove_files;
+ } else
+ dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
+ "skipping\n");
+ if (pwm2) {
+- device_create_file(&new_client->dev, &dev_attr_pwm2);
+- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_pwm2))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_pwm2_enable)))
++ goto error_remove_files;
+ } else
+ dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
+ "skipping\n");
+
+- device_create_file(&new_client->dev, &dev_attr_alarms);
++ if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
++ goto error_remove_files;
++
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto error_remove_files;
++ }
+
+ return 0;
+
+-error_detach:
++error_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
+ i2c_detach_client(new_client);
+ error_free:
+ kfree(data);
+@@ -499,6 +543,7 @@ static int smsc47m1_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
+index bdc4570..a6833f4 100644
+--- a/drivers/hwmon/smsc47m192.c
++++ b/drivers/hwmon/smsc47m192.c
+@@ -30,6 +30,7 @@
+ #include <linux/hwmon-sysfs.h>
+ #include <linux/hwmon-vid.h>
+ #include <linux/err.h>
++#include <linux/sysfs.h>
+
+ /* Addresses to scan */
+ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+@@ -370,6 +371,75 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_I
+ static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
+ static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
+
++static struct attribute *smsc47m192_attributes[] = {
++ &sensor_dev_attr_in0_input.dev_attr.attr,
++ &sensor_dev_attr_in0_min.dev_attr.attr,
++ &sensor_dev_attr_in0_max.dev_attr.attr,
++ &sensor_dev_attr_in0_alarm.dev_attr.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ &sensor_dev_attr_in1_alarm.dev_attr.attr,
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ &sensor_dev_attr_in2_alarm.dev_attr.attr,
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ &sensor_dev_attr_in3_alarm.dev_attr.attr,
++ &sensor_dev_attr_in5_input.dev_attr.attr,
++ &sensor_dev_attr_in5_min.dev_attr.attr,
++ &sensor_dev_attr_in5_max.dev_attr.attr,
++ &sensor_dev_attr_in5_alarm.dev_attr.attr,
++ &sensor_dev_attr_in6_input.dev_attr.attr,
++ &sensor_dev_attr_in6_min.dev_attr.attr,
++ &sensor_dev_attr_in6_max.dev_attr.attr,
++ &sensor_dev_attr_in6_alarm.dev_attr.attr,
++ &sensor_dev_attr_in7_input.dev_attr.attr,
++ &sensor_dev_attr_in7_min.dev_attr.attr,
++ &sensor_dev_attr_in7_max.dev_attr.attr,
++ &sensor_dev_attr_in7_alarm.dev_attr.attr,
++
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_offset.dev_attr.attr,
++ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_min.dev_attr.attr,
++ &sensor_dev_attr_temp2_offset.dev_attr.attr,
++ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_min.dev_attr.attr,
++ &sensor_dev_attr_temp3_offset.dev_attr.attr,
++ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
++ &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
++
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ NULL
++};
++
++static const struct attribute_group smsc47m192_group = {
++ .attrs = smsc47m192_attributes,
++};
++
++static struct attribute *smsc47m192_attributes_in4[] = {
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ &sensor_dev_attr_in4_alarm.dev_attr.attr,
++ NULL
++};
++
++static const struct attribute_group smsc47m192_group_in4 = {
++ .attrs = smsc47m192_attributes_in4,
++};
++
+ /* This function is called when:
+ * smsc47m192_driver is inserted (when this module is loaded), for each
+ available adapter
+@@ -471,80 +541,28 @@ static int smsc47m192_detect(struct i2c_
+ smsc47m192_init_client(client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
+ goto exit_detach;
+- }
+-
+- device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
+
+ /* Pin 110 is either in4 (+12V) or VID4 */
+ config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
+ if (!(config & 0x20)) {
+- device_create_file(&client->dev,
+- &sensor_dev_attr_in4_input.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_in4_min.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_in4_max.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_in4_alarm.dev_attr);
++ if ((err = sysfs_create_group(&client->dev.kobj,
++ &smsc47m192_group_in4)))
++ goto exit_remove_files;
++ }
++
++ data->class_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove_files;
+ }
+- device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_temp1_offset.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_temp2_offset.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_temp2_input_fault.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_temp3_offset.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
+- device_create_file(&client->dev,
+- &sensor_dev_attr_temp3_input_fault.dev_attr);
+- device_create_file(&client->dev, &dev_attr_cpu0_vid);
+- device_create_file(&client->dev, &dev_attr_vrm);
+
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
++ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
+ exit_detach:
+ i2c_detach_client(client);
+ exit_free:
+@@ -559,6 +577,8 @@ static int smsc47m192_detach_client(stru
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
++ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
+index 166298f..f8acada 100644
+--- a/drivers/hwmon/via686a.c
++++ b/drivers/hwmon/via686a.c
+@@ -40,6 +40,7 @@
+ #include <linux/err.h>
+ #include <linux/init.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+ #include <asm/io.h>
+
+
+@@ -570,10 +571,53 @@ static ssize_t show_alarms(struct device
+ }
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
++static struct attribute *via686a_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in4_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in4_max.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp3_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_temp2_max_hyst.attr,
++ &dev_attr_temp3_max_hyst.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group via686a_group = {
++ .attrs = via686a_attributes,
++};
++
+ /* The driver. I choose to use type i2c_driver, as at is identical to both
+ smbus_driver and isa_driver, and clients could be of either kind */
+ static struct i2c_driver via686a_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "via686a",
+ },
+ .attach_adapter = via686a_detect,
+@@ -649,46 +693,19 @@ static int via686a_detect(struct i2c_ada
+ via686a_init_client(new_client);
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
++ goto exit_detach;
++
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove_files;
+ }
+
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+- device_create_file(&new_client->dev, &dev_attr_in4_input);
+- device_create_file(&new_client->dev, &dev_attr_in0_min);
+- device_create_file(&new_client->dev, &dev_attr_in1_min);
+- device_create_file(&new_client->dev, &dev_attr_in2_min);
+- device_create_file(&new_client->dev, &dev_attr_in3_min);
+- device_create_file(&new_client->dev, &dev_attr_in4_min);
+- device_create_file(&new_client->dev, &dev_attr_in0_max);
+- device_create_file(&new_client->dev, &dev_attr_in1_max);
+- device_create_file(&new_client->dev, &dev_attr_in2_max);
+- device_create_file(&new_client->dev, &dev_attr_in3_max);
+- device_create_file(&new_client->dev, &dev_attr_in4_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_input);
+- device_create_file(&new_client->dev, &dev_attr_temp2_input);
+- device_create_file(&new_client->dev, &dev_attr_temp3_input);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max);
+- device_create_file(&new_client->dev, &dev_attr_temp3_max);
+- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst);
+- device_create_file(&new_client->dev, &dev_attr_fan1_input);
+- device_create_file(&new_client->dev, &dev_attr_fan2_input);
+- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+- device_create_file(&new_client->dev, &dev_attr_fan2_min);
+- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+- device_create_file(&new_client->dev, &dev_attr_alarms);
+-
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
+ exit_detach:
+ i2c_detach_client(new_client);
+ exit_free:
+@@ -704,6 +721,7 @@ static int via686a_detach_client(struct
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &via686a_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
+new file mode 100644
+index 0000000..25cc560
+--- /dev/null
++++ b/drivers/hwmon/vt1211.c
+@@ -0,0 +1,1355 @@
++/*
++ * vt1211.c - driver for the VIA VT1211 Super-I/O chip integrated hardware
++ * monitoring features
++ * Copyright (C) 2006 Juerg Haefliger <juergh at gmail.com>
++ *
++ * This driver is based on the driver for kernel 2.4 by Mark D. Studebaker
++ * and its port to kernel 2.6 by Lars Ekman.
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/jiffies.h>
++#include <linux/platform_device.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon-vid.h>
++#include <linux/err.h>
++#include <linux/mutex.h>
++#include <asm/io.h>
++
++static int uch_config = -1;
++module_param(uch_config, int, 0);
++MODULE_PARM_DESC(uch_config, "Initialize the universal channel configuration");
++
++static int int_mode = -1;
++module_param(int_mode, int, 0);
++MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
++
++static struct platform_device *pdev;
++
++#define DRVNAME "vt1211"
++
++/* ---------------------------------------------------------------------
++ * Registers
++ *
++ * The sensors are defined as follows.
++ *
++ * Sensor Voltage Mode Temp Mode Notes (from the datasheet)
++ * -------- ------------ --------- --------------------------
++ * Reading 1 temp1 Intel thermal diode
++ * Reading 3 temp2 Internal thermal diode
++ * UCH1/Reading2 in0 temp3 NTC type thermistor
++ * UCH2 in1 temp4 +2.5V
++ * UCH3 in2 temp5 VccP
++ * UCH4 in3 temp6 +5V
++ * UCH5 in4 temp7 +12V
++ * 3.3V in5 Internal VDD (+3.3V)
++ *
++ * --------------------------------------------------------------------- */
++
++/* Voltages (in) numbered 0-5 (ix) */
++#define VT1211_REG_IN(ix) (0x21 + (ix))
++#define VT1211_REG_IN_MIN(ix) ((ix) == 0 ? 0x3e : 0x2a + 2 * (ix))
++#define VT1211_REG_IN_MAX(ix) ((ix) == 0 ? 0x3d : 0x29 + 2 * (ix))
++
++/* Temperatures (temp) numbered 0-6 (ix) */
++static u8 regtemp[] = {0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
++static u8 regtempmax[] = {0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31};
++static u8 regtemphyst[] = {0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32};
++
++/* Fans numbered 0-1 (ix) */
++#define VT1211_REG_FAN(ix) (0x29 + (ix))
++#define VT1211_REG_FAN_MIN(ix) (0x3b + (ix))
++#define VT1211_REG_FAN_DIV 0x47
++
++/* PWMs numbered 0-1 (ix) */
++/* Auto points numbered 0-3 (ap) */
++#define VT1211_REG_PWM(ix) (0x60 + (ix))
++#define VT1211_REG_PWM_CLK 0x50
++#define VT1211_REG_PWM_CTL 0x51
++#define VT1211_REG_PWM_AUTO_TEMP(ap) (0x55 - (ap))
++#define VT1211_REG_PWM_AUTO_PWM(ix, ap) (0x58 + 2 * (ix) - (ap))
++
++/* Miscellaneous registers */
++#define VT1211_REG_CONFIG 0x40
++#define VT1211_REG_ALARM1 0x41
++#define VT1211_REG_ALARM2 0x42
++#define VT1211_REG_VID 0x45
++#define VT1211_REG_UCH_CONFIG 0x4a
++#define VT1211_REG_TEMP1_CONFIG 0x4b
++#define VT1211_REG_TEMP2_CONFIG 0x4c
++
++/* In, temp & fan alarm bits */
++static const u8 bitalarmin[] = {11, 0, 1, 3, 8, 2, 9};
++static const u8 bitalarmtemp[] = {4, 15, 11, 0, 1, 3, 8};
++static const u8 bitalarmfan[] = {6, 7};
++
++/* ---------------------------------------------------------------------
++ * Data structures and manipulation thereof
++ * --------------------------------------------------------------------- */
++
++struct vt1211_data {
++ unsigned short addr;
++ const char *name;
++ struct class_device *class_dev;
++
++ struct mutex update_lock;
++ char valid; /* !=0 if following fields are valid */
++ unsigned long last_updated; /* In jiffies */
++
++ /* Register values */
++ u8 in[6];
++ u8 in_max[6];
++ u8 in_min[6];
++ u8 temp[7];
++ u8 temp_max[7];
++ u8 temp_hyst[7];
++ u8 fan[2];
++ u8 fan_min[2];
++ u8 fan_div[2];
++ u8 fan_ctl;
++ u8 pwm[2];
++ u8 pwm_ctl[2];
++ u8 pwm_clk;
++ u8 pwm_auto_temp[4];
++ u8 pwm_auto_pwm[2][4];
++ u8 vid; /* Read once at init time */
++ u8 vrm;
++ u8 uch_config; /* Read once at init time */
++ u16 alarms;
++};
++
++/* ix = [0-5] */
++#define ISVOLT(ix, uch_config) ((ix) > 4 ? 1 : \
++ !(((uch_config) >> ((ix) + 2)) & 1))
++
++/* ix = [0-6] */
++#define ISTEMP(ix, uch_config) ((ix) < 2 ? 1 : \
++ ((uch_config) >> (ix)) & 1)
++
++/* in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the
++ driver according to the VT1211 BIOS porting guide */
++#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \
++ (((reg) - 3) * 15882 + 479) / 958 : \
++ (((reg) - 3) * 10000 + 479) / 958)
++#define IN_TO_REG(ix, val) (SENSORS_LIMIT((ix) == 5 ? \
++ ((val) * 958 + 7941) / 15882 + 3 : \
++ ((val) * 958 + 5000) / 10000 + 3, 0, 255))
++
++/* temp1 (ix = 0) is an intel thermal diode which is scaled in user space.
++ temp2 (ix = 1) is the internal temp diode so it's scaled in the driver
++ according to some measurements that I took on an EPIA M10000.
++ temp3-7 are thermistor based so the driver returns the voltage measured at
++ the pin (range 0V - 2.2V). */
++#define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \
++ (ix) == 1 ? (reg) < 51 ? 0 : \
++ ((reg) - 51) * 1000 : \
++ ((253 - (reg)) * 2200 + 105) / 210)
++#define TEMP_TO_REG(ix, val) SENSORS_LIMIT( \
++ ((ix) == 0 ? ((val) + 500) / 1000 : \
++ (ix) == 1 ? ((val) + 500) / 1000 + 51 : \
++ 253 - ((val) * 210 + 1100) / 2200), 0, 255)
++
++#define DIV_FROM_REG(reg) (1 << (reg))
++
++#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \
++ 1310720 / (reg) / DIV_FROM_REG(div))
++#define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \
++ SENSORS_LIMIT((1310720 / (val) / \
++ DIV_FROM_REG(div)), 1, 254))
++
++/* ---------------------------------------------------------------------
++ * Super-I/O constants and functions
++ * --------------------------------------------------------------------- */
++
++/* Configuration & data index port registers */
++#define SIO_REG_CIP 0x2e
++#define SIO_REG_DIP 0x2f
++
++/* Configuration registers */
++#define SIO_VT1211_LDN 0x07 /* logical device number */
++#define SIO_VT1211_DEVID 0x20 /* device ID */
++#define SIO_VT1211_DEVREV 0x21 /* device revision */
++#define SIO_VT1211_ACTIVE 0x30 /* HW monitor active */
++#define SIO_VT1211_BADDR 0x60 /* base I/O address */
++#define SIO_VT1211_ID 0x3c /* VT1211 device ID */
++
++/* VT1211 logical device numbers */
++#define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */
++
++static inline void superio_outb(int reg, int val)
++{
++ outb(reg, SIO_REG_CIP);
++ outb(val, SIO_REG_DIP);
++}
++
++static inline int superio_inb(int reg)
++{
++ outb(reg, SIO_REG_CIP);
++ return inb(SIO_REG_DIP);
++}
++
++static inline void superio_select(int ldn)
++{
++ outb(SIO_VT1211_LDN, SIO_REG_CIP);
++ outb(ldn, SIO_REG_DIP);
++}
++
++static inline void superio_enter(void)
++{
++ outb(0x87, SIO_REG_CIP);
++ outb(0x87, SIO_REG_CIP);
++}
++
++static inline void superio_exit(void)
++{
++ outb(0xaa, SIO_REG_CIP);
++}
++
++/* ---------------------------------------------------------------------
++ * Device I/O access
++ * --------------------------------------------------------------------- */
++
++static inline u8 vt1211_read8(struct vt1211_data *data, u8 reg)
++{
++ return inb(data->addr + reg);
++}
++
++static inline void vt1211_write8(struct vt1211_data *data, u8 reg, u8 val)
++{
++ outb(val, data->addr + reg);
++}
++
++static struct vt1211_data *vt1211_update_device(struct device *dev)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ int ix, val;
++
++ mutex_lock(&data->update_lock);
++
++ /* registers cache is refreshed after 1 second */
++ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
++ /* read VID */
++ data->vid = vt1211_read8(data, VT1211_REG_VID) & 0x1f;
++
++ /* voltage (in) registers */
++ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
++ if (ISVOLT(ix, data->uch_config)) {
++ data->in[ix] = vt1211_read8(data,
++ VT1211_REG_IN(ix));
++ data->in_min[ix] = vt1211_read8(data,
++ VT1211_REG_IN_MIN(ix));
++ data->in_max[ix] = vt1211_read8(data,
++ VT1211_REG_IN_MAX(ix));
++ }
++ }
++
++ /* temp registers */
++ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
++ if (ISTEMP(ix, data->uch_config)) {
++ data->temp[ix] = vt1211_read8(data,
++ regtemp[ix]);
++ data->temp_max[ix] = vt1211_read8(data,
++ regtempmax[ix]);
++ data->temp_hyst[ix] = vt1211_read8(data,
++ regtemphyst[ix]);
++ }
++ }
++
++ /* fan & pwm registers */
++ for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
++ data->fan[ix] = vt1211_read8(data,
++ VT1211_REG_FAN(ix));
++ data->fan_min[ix] = vt1211_read8(data,
++ VT1211_REG_FAN_MIN(ix));
++ data->pwm[ix] = vt1211_read8(data,
++ VT1211_REG_PWM(ix));
++ }
++ val = vt1211_read8(data, VT1211_REG_FAN_DIV);
++ data->fan_div[0] = (val >> 4) & 3;
++ data->fan_div[1] = (val >> 6) & 3;
++ data->fan_ctl = val & 0xf;
++
++ val = vt1211_read8(data, VT1211_REG_PWM_CTL);
++ data->pwm_ctl[0] = val & 0xf;
++ data->pwm_ctl[1] = (val >> 4) & 0xf;
++
++ data->pwm_clk = vt1211_read8(data, VT1211_REG_PWM_CLK);
++
++ /* pwm & temp auto point registers */
++ data->pwm_auto_pwm[0][1] = vt1211_read8(data,
++ VT1211_REG_PWM_AUTO_PWM(0, 1));
++ data->pwm_auto_pwm[0][2] = vt1211_read8(data,
++ VT1211_REG_PWM_AUTO_PWM(0, 2));
++ data->pwm_auto_pwm[1][1] = vt1211_read8(data,
++ VT1211_REG_PWM_AUTO_PWM(1, 1));
++ data->pwm_auto_pwm[1][2] = vt1211_read8(data,
++ VT1211_REG_PWM_AUTO_PWM(1, 2));
++ for (ix = 0; ix < ARRAY_SIZE(data->pwm_auto_temp); ix++) {
++ data->pwm_auto_temp[ix] = vt1211_read8(data,
++ VT1211_REG_PWM_AUTO_TEMP(ix));
++ }
++
++ /* alarm registers */
++ data->alarms = (vt1211_read8(data, VT1211_REG_ALARM2) << 8) |
++ vt1211_read8(data, VT1211_REG_ALARM1);
++
++ data->last_updated = jiffies;
++ data->valid = 1;
++ }
++
++ mutex_unlock(&data->update_lock);
++
++ return data;
++}
++
++/* ---------------------------------------------------------------------
++ * Voltage sysfs interfaces
++ * ix = [0-5]
++ * --------------------------------------------------------------------- */
++
++#define SHOW_IN_INPUT 0
++#define SHOW_SET_IN_MIN 1
++#define SHOW_SET_IN_MAX 2
++#define SHOW_IN_ALARM 3
++
++static ssize_t show_in(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ int res;
++
++ switch (fn) {
++ case SHOW_IN_INPUT:
++ res = IN_FROM_REG(ix, data->in[ix]);
++ break;
++ case SHOW_SET_IN_MIN:
++ res = IN_FROM_REG(ix, data->in_min[ix]);
++ break;
++ case SHOW_SET_IN_MAX:
++ res = IN_FROM_REG(ix, data->in_max[ix]);
++ break;
++ case SHOW_IN_ALARM:
++ res = (data->alarms >> bitalarmin[ix]) & 1;
++ break;
++ default:
++ res = 0;
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++
++ return sprintf(buf, "%d\n", res);
++}
++
++static ssize_t set_in(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ long val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ switch (fn) {
++ case SHOW_SET_IN_MIN:
++ data->in_min[ix] = IN_TO_REG(ix, val);
++ vt1211_write8(data, VT1211_REG_IN_MIN(ix), data->in_min[ix]);
++ break;
++ case SHOW_SET_IN_MAX:
++ data->in_max[ix] = IN_TO_REG(ix, val);
++ vt1211_write8(data, VT1211_REG_IN_MAX(ix), data->in_max[ix]);
++ break;
++ default:
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++ mutex_unlock(&data->update_lock);
++
++ return count;
++}
++
++/* ---------------------------------------------------------------------
++ * Temperature sysfs interfaces
++ * ix = [0-6]
++ * --------------------------------------------------------------------- */
++
++#define SHOW_TEMP_INPUT 0
++#define SHOW_SET_TEMP_MAX 1
++#define SHOW_SET_TEMP_MAX_HYST 2
++#define SHOW_TEMP_ALARM 3
++
++static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ int res;
++
++ switch (fn) {
++ case SHOW_TEMP_INPUT:
++ res = TEMP_FROM_REG(ix, data->temp[ix]);
++ break;
++ case SHOW_SET_TEMP_MAX:
++ res = TEMP_FROM_REG(ix, data->temp_max[ix]);
++ break;
++ case SHOW_SET_TEMP_MAX_HYST:
++ res = TEMP_FROM_REG(ix, data->temp_hyst[ix]);
++ break;
++ case SHOW_TEMP_ALARM:
++ res = (data->alarms >> bitalarmtemp[ix]) & 1;
++ break;
++ default:
++ res = 0;
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++
++ return sprintf(buf, "%d\n", res);
++}
++
++static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ long val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ switch (fn) {
++ case SHOW_SET_TEMP_MAX:
++ data->temp_max[ix] = TEMP_TO_REG(ix, val);
++ vt1211_write8(data, regtempmax[ix],
++ data->temp_max[ix]);
++ break;
++ case SHOW_SET_TEMP_MAX_HYST:
++ data->temp_hyst[ix] = TEMP_TO_REG(ix, val);
++ vt1211_write8(data, regtemphyst[ix],
++ data->temp_hyst[ix]);
++ break;
++ default:
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++ mutex_unlock(&data->update_lock);
++
++ return count;
++}
++
++/* ---------------------------------------------------------------------
++ * Fan sysfs interfaces
++ * ix = [0-1]
++ * --------------------------------------------------------------------- */
++
++#define SHOW_FAN_INPUT 0
++#define SHOW_SET_FAN_MIN 1
++#define SHOW_SET_FAN_DIV 2
++#define SHOW_FAN_ALARM 3
++
++static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ int res;
++
++ switch (fn) {
++ case SHOW_FAN_INPUT:
++ res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]);
++ break;
++ case SHOW_SET_FAN_MIN:
++ res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]);
++ break;
++ case SHOW_SET_FAN_DIV:
++ res = DIV_FROM_REG(data->fan_div[ix]);
++ break;
++ case SHOW_FAN_ALARM:
++ res = (data->alarms >> bitalarmfan[ix]) & 1;
++ break;
++ default:
++ res = 0;
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++
++ return sprintf(buf, "%d\n", res);
++}
++
++static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ long val = simple_strtol(buf, NULL, 10);
++ int reg;
++
++ mutex_lock(&data->update_lock);
++
++ /* sync the data cache */
++ reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
++ data->fan_div[0] = (reg >> 4) & 3;
++ data->fan_div[1] = (reg >> 6) & 3;
++ data->fan_ctl = reg & 0xf;
++
++ switch (fn) {
++ case SHOW_SET_FAN_MIN:
++ data->fan_min[ix] = RPM_TO_REG(val, data->fan_div[ix]);
++ vt1211_write8(data, VT1211_REG_FAN_MIN(ix),
++ data->fan_min[ix]);
++ break;
++ case SHOW_SET_FAN_DIV:
++ switch (val) {
++ case 1: data->fan_div[ix] = 0; break;
++ case 2: data->fan_div[ix] = 1; break;
++ case 4: data->fan_div[ix] = 2; break;
++ case 8: data->fan_div[ix] = 3; break;
++ default:
++ count = -EINVAL;
++ dev_warn(dev, "fan div value %ld not "
++ "supported. Choose one of 1, 2, "
++ "4, or 8.\n", val);
++ goto EXIT;
++ }
++ vt1211_write8(data, VT1211_REG_FAN_DIV,
++ ((data->fan_div[1] << 6) |
++ (data->fan_div[0] << 4) |
++ data->fan_ctl));
++ break;
++ default:
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++
++EXIT:
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++/* ---------------------------------------------------------------------
++ * PWM sysfs interfaces
++ * ix = [0-1]
++ * --------------------------------------------------------------------- */
++
++#define SHOW_PWM 0
++#define SHOW_SET_PWM_ENABLE 1
++#define SHOW_SET_PWM_FREQ 2
++#define SHOW_SET_PWM_AUTO_CHANNELS_TEMP 3
++
++static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ int res;
++
++ switch (fn) {
++ case SHOW_PWM:
++ res = data->pwm[ix];
++ break;
++ case SHOW_SET_PWM_ENABLE:
++ res = ((data->pwm_ctl[ix] >> 3) & 1) ? 2 : 0;
++ break;
++ case SHOW_SET_PWM_FREQ:
++ res = 90000 >> (data->pwm_clk & 7);
++ break;
++ case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
++ res = (data->pwm_ctl[ix] & 7) + 1;
++ break;
++ default:
++ res = 0;
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++
++ return sprintf(buf, "%d\n", res);
++}
++
++static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int fn = sensor_attr_2->nr;
++ long val = simple_strtol(buf, NULL, 10);
++ int tmp, reg;
++
++ mutex_lock(&data->update_lock);
++
++ switch (fn) {
++ case SHOW_SET_PWM_ENABLE:
++ /* sync the data cache */
++ reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
++ data->fan_div[0] = (reg >> 4) & 3;
++ data->fan_div[1] = (reg >> 6) & 3;
++ data->fan_ctl = reg & 0xf;
++ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
++ data->pwm_ctl[0] = reg & 0xf;
++ data->pwm_ctl[1] = (reg >> 4) & 0xf;
++ switch (val) {
++ case 0:
++ data->pwm_ctl[ix] &= 7;
++ /* disable SmartGuardian if both PWM outputs are
++ * disabled */
++ if ((data->pwm_ctl[ix ^ 1] & 1) == 0) {
++ data->fan_ctl &= 0xe;
++ }
++ break;
++ case 2:
++ data->pwm_ctl[ix] |= 8;
++ data->fan_ctl |= 1;
++ break;
++ default:
++ count = -EINVAL;
++ dev_warn(dev, "pwm mode %ld not supported. "
++ "Choose one of 0 or 2.\n", val);
++ goto EXIT;
++ }
++ vt1211_write8(data, VT1211_REG_PWM_CTL,
++ ((data->pwm_ctl[1] << 4) |
++ data->pwm_ctl[0]));
++ vt1211_write8(data, VT1211_REG_FAN_DIV,
++ ((data->fan_div[1] << 6) |
++ (data->fan_div[0] << 4) |
++ data->fan_ctl));
++ break;
++ case SHOW_SET_PWM_FREQ:
++ val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000);
++ /* calculate tmp = log2(val) */
++ tmp = 0;
++ for (val >>= 1; val > 0; val >>= 1) {
++ tmp++;
++ }
++ /* sync the data cache */
++ reg = vt1211_read8(data, VT1211_REG_PWM_CLK);
++ data->pwm_clk = (reg & 0xf8) | tmp;
++ vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk);
++ break;
++ case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
++ if ((val < 1) || (val > 7)) {
++ count = -EINVAL;
++ dev_warn(dev, "temp channel %ld not supported. "
++ "Choose a value between 1 and 7.\n", val);
++ goto EXIT;
++ }
++ if (!ISTEMP(val - 1, data->uch_config)) {
++ count = -EINVAL;
++ dev_warn(dev, "temp channel %ld is not available.\n",
++ val);
++ goto EXIT;
++ }
++ /* sync the data cache */
++ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
++ data->pwm_ctl[0] = reg & 0xf;
++ data->pwm_ctl[1] = (reg >> 4) & 0xf;
++ data->pwm_ctl[ix] = (data->pwm_ctl[ix] & 8) | (val - 1);
++ vt1211_write8(data, VT1211_REG_PWM_CTL,
++ ((data->pwm_ctl[1] << 4) | data->pwm_ctl[0]));
++ break;
++ default:
++ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
++ }
++
++EXIT:
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++/* ---------------------------------------------------------------------
++ * PWM auto point definitions
++ * ix = [0-1]
++ * ap = [0-3]
++ * --------------------------------------------------------------------- */
++
++/*
++ * pwm[ix+1]_auto_point[ap+1]_temp mapping table:
++ * Note that there is only a single set of temp auto points that controls both
++ * PWM controllers. We still create 2 sets of sysfs files to make it look
++ * more consistent even though they map to the same registers.
++ *
++ * ix ap : description
++ * -------------------
++ * 0 0 : pwm1/2 off temperature (pwm_auto_temp[0])
++ * 0 1 : pwm1/2 low speed temperature (pwm_auto_temp[1])
++ * 0 2 : pwm1/2 high speed temperature (pwm_auto_temp[2])
++ * 0 3 : pwm1/2 full speed temperature (pwm_auto_temp[3])
++ * 1 0 : pwm1/2 off temperature (pwm_auto_temp[0])
++ * 1 1 : pwm1/2 low speed temperature (pwm_auto_temp[1])
++ * 1 2 : pwm1/2 high speed temperature (pwm_auto_temp[2])
++ * 1 3 : pwm1/2 full speed temperature (pwm_auto_temp[3])
++ */
++
++static ssize_t show_pwm_auto_point_temp(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int ap = sensor_attr_2->nr;
++
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7,
++ data->pwm_auto_temp[ap]));
++}
++
++static ssize_t set_pwm_auto_point_temp(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int ap = sensor_attr_2->nr;
++ long val = simple_strtol(buf, NULL, 10);
++ int reg;
++
++ mutex_lock(&data->update_lock);
++
++ /* sync the data cache */
++ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
++ data->pwm_ctl[0] = reg & 0xf;
++ data->pwm_ctl[1] = (reg >> 4) & 0xf;
++
++ data->pwm_auto_temp[ap] = TEMP_TO_REG(data->pwm_ctl[ix] & 7, val);
++ vt1211_write8(data, VT1211_REG_PWM_AUTO_TEMP(ap),
++ data->pwm_auto_temp[ap]);
++ mutex_unlock(&data->update_lock);
++
++ return count;
++}
++
++/*
++ * pwm[ix+1]_auto_point[ap+1]_pwm mapping table:
++ * Note that the PWM auto points 0 & 3 are hard-wired in the VT1211 and can't
++ * be changed.
++ *
++ * ix ap : description
++ * -------------------
++ * 0 0 : pwm1 off (pwm_auto_pwm[0][0], hard-wired to 0)
++ * 0 1 : pwm1 low speed duty cycle (pwm_auto_pwm[0][1])
++ * 0 2 : pwm1 high speed duty cycle (pwm_auto_pwm[0][2])
++ * 0 3 : pwm1 full speed (pwm_auto_pwm[0][3], hard-wired to 255)
++ * 1 0 : pwm2 off (pwm_auto_pwm[1][0], hard-wired to 0)
++ * 1 1 : pwm2 low speed duty cycle (pwm_auto_pwm[1][1])
++ * 1 2 : pwm2 high speed duty cycle (pwm_auto_pwm[1][2])
++ * 1 3 : pwm2 full speed (pwm_auto_pwm[1][3], hard-wired to 255)
++*/
++
++static ssize_t show_pwm_auto_point_pwm(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int ap = sensor_attr_2->nr;
++
++ return sprintf(buf, "%d\n", data->pwm_auto_pwm[ix][ap]);
++}
++
++static ssize_t set_pwm_auto_point_pwm(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ struct sensor_device_attribute_2 *sensor_attr_2 =
++ to_sensor_dev_attr_2(attr);
++ int ix = sensor_attr_2->index;
++ int ap = sensor_attr_2->nr;
++ long val = simple_strtol(buf, NULL, 10);
++
++ if ((val < 0) || (val > 255)) {
++ dev_err(dev, "pwm value %ld is out of range. "
++ "Choose a value between 0 and 255." , val);
++ return -EINVAL;
++ }
++
++ mutex_lock(&data->update_lock);
++ data->pwm_auto_pwm[ix][ap] = val;
++ vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
++ data->pwm_auto_pwm[ix][ap]);
++ mutex_unlock(&data->update_lock);
++
++ return count;
++}
++
++/* ---------------------------------------------------------------------
++ * Miscellaneous sysfs interfaces (VRM, VID, name, and (legacy) alarms)
++ * --------------------------------------------------------------------- */
++
++static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%d\n", data->vrm);
++}
++
++static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++ long val = simple_strtol(buf, NULL, 10);
++
++ data->vrm = val;
++
++ return count;
++}
++
++static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
++}
++
++static ssize_t show_name(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct vt1211_data *data = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%s\n", data->name);
++}
++
++static ssize_t show_alarms(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct vt1211_data *data = vt1211_update_device(dev);
++
++ return sprintf(buf, "%d\n", data->alarms);
++}
++
++/* ---------------------------------------------------------------------
++ * Device attribute structs
++ * --------------------------------------------------------------------- */
++
++#define SENSOR_ATTR_IN_INPUT(ix) \
++ SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \
++ show_in, NULL, SHOW_IN_INPUT, ix)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_in_input[] = {
++ SENSOR_ATTR_IN_INPUT(0),
++ SENSOR_ATTR_IN_INPUT(1),
++ SENSOR_ATTR_IN_INPUT(2),
++ SENSOR_ATTR_IN_INPUT(3),
++ SENSOR_ATTR_IN_INPUT(4),
++ SENSOR_ATTR_IN_INPUT(5),
++};
++
++#define SENSOR_ATTR_IN_MIN(ix) \
++ SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
++ show_in, set_in, SHOW_SET_IN_MIN, ix)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_in_min[] = {
++ SENSOR_ATTR_IN_MIN(0),
++ SENSOR_ATTR_IN_MIN(1),
++ SENSOR_ATTR_IN_MIN(2),
++ SENSOR_ATTR_IN_MIN(3),
++ SENSOR_ATTR_IN_MIN(4),
++ SENSOR_ATTR_IN_MIN(5),
++};
++
++#define SENSOR_ATTR_IN_MAX(ix) \
++ SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
++ show_in, set_in, SHOW_SET_IN_MAX, ix)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_in_max[] = {
++ SENSOR_ATTR_IN_MAX(0),
++ SENSOR_ATTR_IN_MAX(1),
++ SENSOR_ATTR_IN_MAX(2),
++ SENSOR_ATTR_IN_MAX(3),
++ SENSOR_ATTR_IN_MAX(4),
++ SENSOR_ATTR_IN_MAX(5),
++};
++
++#define SENSOR_ATTR_IN_ALARM(ix) \
++ SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \
++ show_in, NULL, SHOW_IN_ALARM, ix)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_in_alarm[] = {
++ SENSOR_ATTR_IN_ALARM(0),
++ SENSOR_ATTR_IN_ALARM(1),
++ SENSOR_ATTR_IN_ALARM(2),
++ SENSOR_ATTR_IN_ALARM(3),
++ SENSOR_ATTR_IN_ALARM(4),
++ SENSOR_ATTR_IN_ALARM(5),
++};
++
++#define SENSOR_ATTR_TEMP_INPUT(ix) \
++ SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \
++ show_temp, NULL, SHOW_TEMP_INPUT, ix-1)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_temp_input[] = {
++ SENSOR_ATTR_TEMP_INPUT(1),
++ SENSOR_ATTR_TEMP_INPUT(2),
++ SENSOR_ATTR_TEMP_INPUT(3),
++ SENSOR_ATTR_TEMP_INPUT(4),
++ SENSOR_ATTR_TEMP_INPUT(5),
++ SENSOR_ATTR_TEMP_INPUT(6),
++ SENSOR_ATTR_TEMP_INPUT(7),
++};
++
++#define SENSOR_ATTR_TEMP_MAX(ix) \
++ SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
++ show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_temp_max[] = {
++ SENSOR_ATTR_TEMP_MAX(1),
++ SENSOR_ATTR_TEMP_MAX(2),
++ SENSOR_ATTR_TEMP_MAX(3),
++ SENSOR_ATTR_TEMP_MAX(4),
++ SENSOR_ATTR_TEMP_MAX(5),
++ SENSOR_ATTR_TEMP_MAX(6),
++ SENSOR_ATTR_TEMP_MAX(7),
++};
++
++#define SENSOR_ATTR_TEMP_MAX_HYST(ix) \
++ SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \
++ show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_temp_max_hyst[] = {
++ SENSOR_ATTR_TEMP_MAX_HYST(1),
++ SENSOR_ATTR_TEMP_MAX_HYST(2),
++ SENSOR_ATTR_TEMP_MAX_HYST(3),
++ SENSOR_ATTR_TEMP_MAX_HYST(4),
++ SENSOR_ATTR_TEMP_MAX_HYST(5),
++ SENSOR_ATTR_TEMP_MAX_HYST(6),
++ SENSOR_ATTR_TEMP_MAX_HYST(7),
++};
++
++#define SENSOR_ATTR_TEMP_ALARM(ix) \
++ SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \
++ show_temp, NULL, SHOW_TEMP_ALARM, ix-1)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_temp_alarm[] = {
++ SENSOR_ATTR_TEMP_ALARM(1),
++ SENSOR_ATTR_TEMP_ALARM(2),
++ SENSOR_ATTR_TEMP_ALARM(3),
++ SENSOR_ATTR_TEMP_ALARM(4),
++ SENSOR_ATTR_TEMP_ALARM(5),
++ SENSOR_ATTR_TEMP_ALARM(6),
++ SENSOR_ATTR_TEMP_ALARM(7),
++};
++
++#define SENSOR_ATTR_FAN(ix) \
++ SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \
++ show_fan, NULL, SHOW_FAN_INPUT, ix-1), \
++ SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
++ show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \
++ SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \
++ show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \
++ SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \
++ show_fan, NULL, SHOW_FAN_ALARM, ix-1)
++
++#define SENSOR_ATTR_PWM(ix) \
++ SENSOR_ATTR_2(pwm##ix, S_IRUGO, \
++ show_pwm, NULL, SHOW_PWM, ix-1), \
++ SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \
++ show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \
++ SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \
++ show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1)
++
++#define SENSOR_ATTR_PWM_FREQ(ix) \
++ SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
++ show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1)
++
++#define SENSOR_ATTR_PWM_FREQ_RO(ix) \
++ SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \
++ show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1)
++
++#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \
++ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \
++ show_pwm_auto_point_temp, set_pwm_auto_point_temp, \
++ ap-1, ix-1)
++
++#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \
++ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \
++ show_pwm_auto_point_temp, NULL, \
++ ap-1, ix-1)
++
++#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \
++ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \
++ show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \
++ ap-1, ix-1)
++
++#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \
++ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \
++ show_pwm_auto_point_pwm, NULL, \
++ ap-1, ix-1)
++
++static struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = {
++ SENSOR_ATTR_FAN(1),
++ SENSOR_ATTR_FAN(2),
++ SENSOR_ATTR_PWM(1),
++ SENSOR_ATTR_PWM(2),
++ SENSOR_ATTR_PWM_FREQ(1),
++ SENSOR_ATTR_PWM_FREQ_RO(2),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3),
++ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3),
++ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4),
++};
++
++static struct device_attribute vt1211_sysfs_misc[] = {
++ __ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm),
++ __ATTR(cpu0_vid, S_IRUGO, show_vid, NULL),
++ __ATTR(name, S_IRUGO, show_name, NULL),
++ __ATTR(alarms, S_IRUGO, show_alarms, NULL),
++};
++
++/* ---------------------------------------------------------------------
++ * Device registration and initialization
++ * --------------------------------------------------------------------- */
++
++static void __devinit vt1211_init_device(struct vt1211_data *data)
++{
++ /* set VRM */
++ data->vrm = vid_which_vrm();
++
++ /* Read (and initialize) UCH config */
++ data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG);
++ if (uch_config > -1) {
++ data->uch_config = (data->uch_config & 0x83) |
++ (uch_config << 2);
++ vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config);
++ }
++
++ /* Initialize the interrupt mode (if request at module load time).
++ * The VT1211 implements 3 different modes for clearing interrupts:
++ * 0: Clear INT when status register is read. Regenerate INT as long
++ * as temp stays above hysteresis limit.
++ * 1: Clear INT when status register is read. DON'T regenerate INT
++ * until temp falls below hysteresis limit and exceeds hot limit
++ * again.
++ * 2: Clear INT when temp falls below max limit.
++ *
++ * The driver only allows to force mode 0 since that's the only one
++ * that makes sense for 'sensors' */
++ if (int_mode == 0) {
++ vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0);
++ vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0);
++ }
++
++ /* Fill in some hard wired values into our data struct */
++ data->pwm_auto_pwm[0][3] = 255;
++ data->pwm_auto_pwm[1][3] = 255;
++}
++
++static void vt1211_remove_sysfs(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {
++ device_remove_file(dev,
++ &vt1211_sysfs_in_input[i].dev_attr);
++ device_remove_file(dev,
++ &vt1211_sysfs_in_min[i].dev_attr);
++ device_remove_file(dev,
++ &vt1211_sysfs_in_max[i].dev_attr);
++ device_remove_file(dev,
++ &vt1211_sysfs_in_alarm[i].dev_attr);
++ }
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {
++ device_remove_file(dev,
++ &vt1211_sysfs_temp_input[i].dev_attr);
++ device_remove_file(dev,
++ &vt1211_sysfs_temp_max[i].dev_attr);
++ device_remove_file(dev,
++ &vt1211_sysfs_temp_max_hyst[i].dev_attr);
++ device_remove_file(dev,
++ &vt1211_sysfs_temp_alarm[i].dev_attr);
++ }
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
++ device_remove_file(dev,
++ &vt1211_sysfs_fan_pwm[i].dev_attr);
++ }
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
++ device_remove_file(dev, &vt1211_sysfs_misc[i]);
++ }
++}
++
++static int __devinit vt1211_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct vt1211_data *data;
++ struct resource *res;
++ int i, err;
++
++ if (!(data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL))) {
++ err = -ENOMEM;
++ dev_err(dev, "Out of memory\n");
++ goto EXIT;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
++ data->addr = res->start;
++ data->name = DRVNAME;
++ mutex_init(&data->update_lock);
++
++ platform_set_drvdata(pdev, data);
++
++ /* Initialize the VT1211 chip */
++ vt1211_init_device(data);
++
++ /* Create sysfs interface files */
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {
++ if (ISVOLT(i, data->uch_config)) {
++ if ((err = device_create_file(dev,
++ &vt1211_sysfs_in_input[i].dev_attr)) ||
++ (err = device_create_file(dev,
++ &vt1211_sysfs_in_min[i].dev_attr)) ||
++ (err = device_create_file(dev,
++ &vt1211_sysfs_in_max[i].dev_attr)) ||
++ (err = device_create_file(dev,
++ &vt1211_sysfs_in_alarm[i].dev_attr))) {
++ goto EXIT_DEV_REMOVE;
++ }
++ }
++ }
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {
++ if (ISTEMP(i, data->uch_config)) {
++ if ((err = device_create_file(dev,
++ &vt1211_sysfs_temp_input[i].dev_attr)) ||
++ (err = device_create_file(dev,
++ &vt1211_sysfs_temp_max[i].dev_attr)) ||
++ (err = device_create_file(dev,
++ &vt1211_sysfs_temp_max_hyst[i].dev_attr)) ||
++ (err = device_create_file(dev,
++ &vt1211_sysfs_temp_alarm[i].dev_attr))) {
++ goto EXIT_DEV_REMOVE;
++ }
++ }
++ }
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
++ err = device_create_file(dev,
++ &vt1211_sysfs_fan_pwm[i].dev_attr);
++ if (err) {
++ goto EXIT_DEV_REMOVE;
++ }
++ }
++ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
++ err = device_create_file(dev,
++ &vt1211_sysfs_misc[i]);
++ if (err) {
++ goto EXIT_DEV_REMOVE;
++ }
++ }
++
++ /* Register device */
++ data->class_dev = hwmon_device_register(dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ dev_err(dev, "Class registration failed (%d)\n", err);
++ goto EXIT_DEV_REMOVE_SILENT;
++ }
++
++ return 0;
++
++EXIT_DEV_REMOVE:
++ dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
++EXIT_DEV_REMOVE_SILENT:
++ vt1211_remove_sysfs(pdev);
++ platform_set_drvdata(pdev, NULL);
++ kfree(data);
++EXIT:
++ return err;
++}
++
++static int __devexit vt1211_remove(struct platform_device *pdev)
++{
++ struct vt1211_data *data = platform_get_drvdata(pdev);
++
++ hwmon_device_unregister(data->class_dev);
++ vt1211_remove_sysfs(pdev);
++ platform_set_drvdata(pdev, NULL);
++ kfree(data);
++
++ return 0;
++}
++
++static struct platform_driver vt1211_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = DRVNAME,
++ },
++ .probe = vt1211_probe,
++ .remove = __devexit_p(vt1211_remove),
++};
++
++static int __init vt1211_device_add(unsigned short address)
++{
++ struct resource res = {
++ .start = address,
++ .end = address + 0x7f,
++ .flags = IORESOURCE_IO,
++ };
++ int err;
++
++ pdev = platform_device_alloc(DRVNAME, address);
++ if (!pdev) {
++ err = -ENOMEM;
++ printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n",
++ err);
++ goto EXIT;
++ }
++
++ res.name = pdev->name;
++ err = platform_device_add_resources(pdev, &res, 1);
++ if (err) {
++ printk(KERN_ERR DRVNAME ": Device resource addition failed "
++ "(%d)\n", err);
++ goto EXIT_DEV_PUT;
++ }
++
++ err = platform_device_add(pdev);
++ if (err) {
++ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
++ err);
++ goto EXIT_DEV_PUT;
++ }
++
++ return 0;
++
++EXIT_DEV_PUT:
++ platform_device_put(pdev);
++EXIT:
++ return err;
++}
++
++static int __init vt1211_find(unsigned short *address)
++{
++ int err = -ENODEV;
++
++ superio_enter();
++
++ if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) {
++ goto EXIT;
++ }
++
++ superio_select(SIO_VT1211_LDN_HWMON);
++
++ if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) {
++ printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
++ "skipping\n");
++ goto EXIT;
++ }
++
++ *address = ((superio_inb(SIO_VT1211_BADDR) << 8) |
++ (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00;
++ if (*address == 0) {
++ printk(KERN_WARNING DRVNAME ": Base address is not set, "
++ "skipping\n");
++ goto EXIT;
++ }
++
++ err = 0;
++ printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
++ "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV));
++
++EXIT:
++ superio_exit();
++ return err;
++}
++
++static int __init vt1211_init(void)
++{
++ int err;
++ unsigned short address = 0;
++
++ err = vt1211_find(&address);
++ if (err) {
++ goto EXIT;
++ }
++
++ if ((uch_config < -1) || (uch_config > 31)) {
++ err = -EINVAL;
++ printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. "
++ "Choose a value between 0 and 31.\n", uch_config);
++ goto EXIT;
++ }
++
++ if ((int_mode < -1) || (int_mode > 0)) {
++ err = -EINVAL;
++ printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. "
++ "Only mode 0 is supported.\n", int_mode);
++ goto EXIT;
++ }
++
++ err = platform_driver_register(&vt1211_driver);
++ if (err) {
++ goto EXIT;
++ }
++
++ /* Sets global pdev as a side effect */
++ err = vt1211_device_add(address);
++ if (err) {
++ goto EXIT_DRV_UNREGISTER;
++ }
++
++ return 0;
++
++EXIT_DRV_UNREGISTER:
++ platform_driver_unregister(&vt1211_driver);
++EXIT:
++ return err;
++}
++
++static void __exit vt1211_exit(void)
++{
++ platform_device_unregister(pdev);
++ platform_driver_unregister(&vt1211_driver);
++}
++
++MODULE_AUTHOR("Juerg Haefliger <juergh at gmail.com>");
++MODULE_DESCRIPTION("VT1211 sensors");
++MODULE_LICENSE("GPL");
++
++module_init(vt1211_init);
++module_exit(vt1211_exit);
+diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
+index 686f3de..93f93d4 100644
+--- a/drivers/hwmon/vt8231.c
++++ b/drivers/hwmon/vt8231.c
+@@ -451,37 +451,6 @@ define_temperature_sysfs(4);
+ define_temperature_sysfs(5);
+ define_temperature_sysfs(6);
+
+-#define CFG_INFO_TEMP(id) { &sensor_dev_attr_temp##id##_input.dev_attr, \
+- &sensor_dev_attr_temp##id##_max_hyst.dev_attr, \
+- &sensor_dev_attr_temp##id##_max.dev_attr }
+-#define CFG_INFO_VOLT(id) { &sensor_dev_attr_in##id##_input.dev_attr, \
+- &sensor_dev_attr_in##id##_min.dev_attr, \
+- &sensor_dev_attr_in##id##_max.dev_attr }
+-
+-struct str_device_attr_table {
+- struct device_attribute *input;
+- struct device_attribute *min;
+- struct device_attribute *max;
+-};
+-
+-static struct str_device_attr_table cfg_info_temp[] = {
+- { &dev_attr_temp1_input, &dev_attr_temp1_max_hyst, &dev_attr_temp1_max },
+- CFG_INFO_TEMP(2),
+- CFG_INFO_TEMP(3),
+- CFG_INFO_TEMP(4),
+- CFG_INFO_TEMP(5),
+- CFG_INFO_TEMP(6)
+-};
+-
+-static struct str_device_attr_table cfg_info_volt[] = {
+- CFG_INFO_VOLT(0),
+- CFG_INFO_VOLT(1),
+- CFG_INFO_VOLT(2),
+- CFG_INFO_VOLT(3),
+- CFG_INFO_VOLT(4),
+- { &dev_attr_in5_input, &dev_attr_in5_min, &dev_attr_in5_max }
+-};
+-
+ /* Fans */
+ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -585,8 +554,110 @@ static ssize_t show_alarms(struct device
+
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
++static struct attribute *vt8231_attributes_temps[6][4] = {
++ {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_temp1_max.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_temp4_input.dev_attr.attr,
++ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp4_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_temp5_input.dev_attr.attr,
++ &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp5_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_temp6_input.dev_attr.attr,
++ &sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp6_max.dev_attr.attr,
++ NULL
++ }
++};
++
++static const struct attribute_group vt8231_group_temps[6] = {
++ { .attrs = vt8231_attributes_temps[0] },
++ { .attrs = vt8231_attributes_temps[1] },
++ { .attrs = vt8231_attributes_temps[2] },
++ { .attrs = vt8231_attributes_temps[3] },
++ { .attrs = vt8231_attributes_temps[4] },
++ { .attrs = vt8231_attributes_temps[5] },
++};
++
++static struct attribute *vt8231_attributes_volts[6][4] = {
++ {
++ &sensor_dev_attr_in0_input.dev_attr.attr,
++ &sensor_dev_attr_in0_min.dev_attr.attr,
++ &sensor_dev_attr_in0_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ NULL
++ }, {
++ &dev_attr_in5_input.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in5_max.attr,
++ NULL
++ }
++};
++
++static const struct attribute_group vt8231_group_volts[6] = {
++ { .attrs = vt8231_attributes_volts[0] },
++ { .attrs = vt8231_attributes_volts[1] },
++ { .attrs = vt8231_attributes_volts[2] },
++ { .attrs = vt8231_attributes_volts[3] },
++ { .attrs = vt8231_attributes_volts[4] },
++ { .attrs = vt8231_attributes_volts[5] },
++};
++
++static struct attribute *vt8231_attributes[] = {
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++ &sensor_dev_attr_fan2_min.dev_attr.attr,
++ &sensor_dev_attr_fan1_div.dev_attr.attr,
++ &sensor_dev_attr_fan2_div.dev_attr.attr,
++ &dev_attr_alarms.attr,
++ NULL
++};
++
++static const struct attribute_group vt8231_group = {
++ .attrs = vt8231_attributes,
++};
++
+ static struct i2c_driver vt8231_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "vt8231",
+ },
+ .attach_adapter = vt8231_detect,
+@@ -670,43 +741,43 @@ int vt8231_detect(struct i2c_adapter *ad
+ vt8231_init_client(client);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
+ goto exit_detach;
+- }
+
+ /* Must update device information to find out the config field */
+ data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
+
+- for (i = 0; i < ARRAY_SIZE(cfg_info_temp); i++) {
++ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
+ if (ISTEMP(i, data->uch_config)) {
+- device_create_file(&client->dev,
+- cfg_info_temp[i].input);
+- device_create_file(&client->dev, cfg_info_temp[i].max);
+- device_create_file(&client->dev, cfg_info_temp[i].min);
++ if ((err = sysfs_create_group(&client->dev.kobj,
++ &vt8231_group_temps[i])))
++ goto exit_remove_files;
+ }
+ }
+
+- for (i = 0; i < ARRAY_SIZE(cfg_info_volt); i++) {
++ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
+ if (ISVOLT(i, data->uch_config)) {
+- device_create_file(&client->dev,
+- cfg_info_volt[i].input);
+- device_create_file(&client->dev, cfg_info_volt[i].max);
+- device_create_file(&client->dev, cfg_info_volt[i].min);
++ if ((err = sysfs_create_group(&client->dev.kobj,
++ &vt8231_group_volts[i])))
++ goto exit_remove_files;
+ }
+ }
+
+- device_create_file(&client->dev, &sensor_dev_attr_fan1_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_fan2_input.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_fan1_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_fan2_min.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_fan1_div.dev_attr);
+- device_create_file(&client->dev, &sensor_dev_attr_fan2_div.dev_attr);
+-
+- device_create_file(&client->dev, &dev_attr_alarms);
++ data->class_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove_files;
++ }
+ return 0;
+
++exit_remove_files:
++ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
++ sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
++
++ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
++ sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
++
++ sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+ exit_detach:
+ i2c_detach_client(client);
+ exit_free:
+@@ -719,10 +790,18 @@ exit_release:
+ static int vt8231_detach_client(struct i2c_client *client)
+ {
+ struct vt8231_data *data = i2c_get_clientdata(client);
+- int err;
++ int err, i;
+
+ hwmon_device_unregister(data->class_dev);
+
++ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
++ sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
++
++ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
++ sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
++
++ sysfs_remove_group(&client->dev.kobj, &vt8231_group);
++
+ if ((err = i2c_detach_client(client))) {
+ return err;
+ }
+diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
+index 40301bc..2257806 100644
+--- a/drivers/hwmon/w83627ehf.c
++++ b/drivers/hwmon/w83627ehf.c
+@@ -2,6 +2,9 @@
+ w83627ehf - Driver for the hardware monitoring functionality of
+ the Winbond W83627EHF Super-I/O chip
+ Copyright (C) 2005 Jean Delvare <khali at linux-fr.org>
++ Copyright (C) 2006 Yuan Mu (Winbond),
++ Rudolf Marek <r.marek at sh.cvut.cz>
++ David Hubbard <david.c.hubbard at gmail.com>
+
+ Shamelessly ripped from the w83627hf driver
+ Copyright (C) 2003 Mark Studebaker
+@@ -29,8 +32,8 @@
+
+ Supports the following chips:
+
+- Chip #vin #fan #pwm #temp chip_id man_id
+- w83627ehf 10 5 - 3 0x88 0x5ca3
++ Chip #vin #fan #pwm #temp chip_id man_id
++ w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3
+ */
+
+ #include <linux/module.h>
+@@ -145,10 +148,44 @@ static const u16 W83627EHF_REG_TEMP_CONF
+ #define W83627EHF_REG_ALARM2 0x45A
+ #define W83627EHF_REG_ALARM3 0x45B
+
++/* SmartFan registers */
++/* DC or PWM output fan configuration */
++static const u8 W83627EHF_REG_PWM_ENABLE[] = {
++ 0x04, /* SYS FAN0 output mode and PWM mode */
++ 0x04, /* CPU FAN0 output mode and PWM mode */
++ 0x12, /* AUX FAN mode */
++ 0x62, /* CPU fan1 mode */
++};
++
++static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
++static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
++
++/* FAN Duty Cycle, be used to control */
++static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
++static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
++static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
++
++
++/* Advanced Fan control, some values are common for all fans */
++static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
++static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
++
+ /*
+ * Conversions
+ */
+
++/* 1 is PWM mode, output in ms */
++static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
++{
++ return mode ? 100 * reg : 400 * reg;
++}
++
++static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
++{
++ return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
++ (msec + 200) / 400), 1, 255);
++}
++
+ static inline unsigned int
+ fan_from_reg(u8 reg, unsigned int div)
+ {
+@@ -170,12 +207,12 @@ temp1_from_reg(s8 reg)
+ }
+
+ static inline s8
+-temp1_to_reg(int temp)
++temp1_to_reg(int temp, int min, int max)
+ {
+- if (temp <= -128000)
+- return -128;
+- if (temp >= 127000)
+- return 127;
++ if (temp <= min)
++ return min / 1000;
++ if (temp >= max)
++ return max / 1000;
+ if (temp < 0)
+ return (temp - 500) / 1000;
+ return (temp + 500) / 1000;
+@@ -223,6 +260,16 @@ struct w83627ehf_data {
+ s16 temp_max[2];
+ s16 temp_max_hyst[2];
+ u32 alarms;
++
++ u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
++ u8 pwm_enable[4]; /* 1->manual
++ 2->thermal cruise (also called SmartFan I) */
++ u8 pwm[4];
++ u8 target_temp[4];
++ u8 tolerance[4];
++
++ u8 fan_min_output[4]; /* minimum fan speed */
++ u8 fan_stop_time[4];
+ };
+
+ static inline int is_word_sized(u16 reg)
+@@ -307,6 +354,8 @@ static void w83627ehf_write_fan_div(stru
+ case 0:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
+ | ((data->fan_div[0] & 0x03) << 4);
++ /* fan5 input control bit is write only, compute the value */
++ reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
+ w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
+ | ((data->fan_div[0] & 0x04) << 3);
+@@ -315,6 +364,8 @@ static void w83627ehf_write_fan_div(stru
+ case 1:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
+ | ((data->fan_div[1] & 0x03) << 6);
++ /* fan5 input control bit is write only, compute the value */
++ reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
+ w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
+ | ((data->fan_div[1] & 0x04) << 4);
+@@ -349,6 +400,7 @@ static struct w83627ehf_data *w83627ehf_
+ {
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
++ int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+ int i;
+
+ mutex_lock(&data->update_lock);
+@@ -416,6 +468,34 @@ static struct w83627ehf_data *w83627ehf_
+ }
+ }
+
++ for (i = 0; i < 4; i++) {
++ /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
++ if (i != 1) {
++ pwmcfg = w83627ehf_read_value(client,
++ W83627EHF_REG_PWM_ENABLE[i]);
++ tolerance = w83627ehf_read_value(client,
++ W83627EHF_REG_TOLERANCE[i]);
++ }
++ data->pwm_mode[i] =
++ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
++ ? 0 : 1;
++ data->pwm_enable[i] =
++ ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
++ & 3) + 1;
++ data->pwm[i] = w83627ehf_read_value(client,
++ W83627EHF_REG_PWM[i]);
++ data->fan_min_output[i] = w83627ehf_read_value(client,
++ W83627EHF_REG_FAN_MIN_OUTPUT[i]);
++ data->fan_stop_time[i] = w83627ehf_read_value(client,
++ W83627EHF_REG_FAN_STOP_TIME[i]);
++ data->target_temp[i] =
++ w83627ehf_read_value(client,
++ W83627EHF_REG_TARGET[i]) &
++ (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
++ data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
++ & 0x0f;
++ }
++
+ /* Measured temperatures and limits */
+ data->temp1 = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP1);
+@@ -546,14 +626,6 @@ static struct sensor_device_attribute sd
+ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+ };
+
+-static void device_create_file_in(struct device *dev, int i)
+-{
+- device_create_file(dev, &sda_in_input[i].dev_attr);
+- device_create_file(dev, &sda_in_alarm[i].dev_attr);
+- device_create_file(dev, &sda_in_min[i].dev_attr);
+- device_create_file(dev, &sda_in_max[i].dev_attr);
+-}
+-
+ #define show_fan_reg(reg) \
+ static ssize_t \
+ show_##reg(struct device *dev, struct device_attribute *attr, \
+@@ -681,14 +753,6 @@ static struct sensor_device_attribute sd
+ SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+ };
+
+-static void device_create_file_fan(struct device *dev, int i)
+-{
+- device_create_file(dev, &sda_fan_input[i].dev_attr);
+- device_create_file(dev, &sda_fan_alarm[i].dev_attr);
+- device_create_file(dev, &sda_fan_div[i].dev_attr);
+- device_create_file(dev, &sda_fan_min[i].dev_attr);
+-}
+-
+ #define show_temp1_reg(reg) \
+ static ssize_t \
+ show_##reg(struct device *dev, struct device_attribute *attr, \
+@@ -711,7 +775,7 @@ store_temp1_##reg(struct device *dev, st
+ u32 val = simple_strtoul(buf, NULL, 10); \
+ \
+ mutex_lock(&data->update_lock); \
+- data->temp1_##reg = temp1_to_reg(val); \
++ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
+ w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
+ data->temp1_##reg); \
+ mutex_unlock(&data->update_lock); \
+@@ -777,10 +841,309 @@ static struct sensor_device_attribute sd
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+ };
+
++#define show_pwm_reg(reg) \
++static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ return sprintf(buf, "%d\n", data->reg[nr]); \
++}
++
++show_pwm_reg(pwm_mode)
++show_pwm_reg(pwm_enable)
++show_pwm_reg(pwm)
++
++static ssize_t
++store_pwm_mode(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct w83627ehf_data *data = i2c_get_clientdata(client);
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ u32 val = simple_strtoul(buf, NULL, 10);
++ u16 reg;
++
++ if (val > 1)
++ return -EINVAL;
++ mutex_lock(&data->update_lock);
++ reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
++ data->pwm_mode[nr] = val;
++ reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
++ if (!val)
++ reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
++ w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static ssize_t
++store_pwm(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct w83627ehf_data *data = i2c_get_clientdata(client);
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
++
++ mutex_lock(&data->update_lock);
++ data->pwm[nr] = val;
++ w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static ssize_t
++store_pwm_enable(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct w83627ehf_data *data = i2c_get_clientdata(client);
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ u32 val = simple_strtoul(buf, NULL, 10);
++ u16 reg;
++
++ if (!val || (val > 2)) /* only modes 1 and 2 are supported */
++ return -EINVAL;
++ mutex_lock(&data->update_lock);
++ reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
++ data->pwm_enable[nr] = val;
++ reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
++ reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
++ w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++
++#define show_tol_temp(reg) \
++static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
++}
++
++show_tol_temp(tolerance)
++show_tol_temp(target_temp)
++
++static ssize_t
++store_target_temp(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct w83627ehf_data *data = i2c_get_clientdata(client);
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
++
++ mutex_lock(&data->update_lock);
++ data->target_temp[nr] = val;
++ w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static ssize_t
++store_tolerance(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct w83627ehf_data *data = i2c_get_clientdata(client);
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ u16 reg;
++ /* Limit the temp to 0C - 15C */
++ u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
++
++ mutex_lock(&data->update_lock);
++ reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
++ data->tolerance[nr] = val;
++ if (nr == 1)
++ reg = (reg & 0x0f) | (val << 4);
++ else
++ reg = (reg & 0xf0) | val;
++ w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static struct sensor_device_attribute sda_pwm[] = {
++ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
++ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
++ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
++ SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
++};
++
++static struct sensor_device_attribute sda_pwm_mode[] = {
++ SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
++ store_pwm_mode, 0),
++ SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
++ store_pwm_mode, 1),
++ SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
++ store_pwm_mode, 2),
++ SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
++ store_pwm_mode, 3),
++};
++
++static struct sensor_device_attribute sda_pwm_enable[] = {
++ SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
++ store_pwm_enable, 0),
++ SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
++ store_pwm_enable, 1),
++ SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
++ store_pwm_enable, 2),
++ SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
++ store_pwm_enable, 3),
++};
++
++static struct sensor_device_attribute sda_target_temp[] = {
++ SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
++ store_target_temp, 0),
++ SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
++ store_target_temp, 1),
++ SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
++ store_target_temp, 2),
++ SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
++ store_target_temp, 3),
++};
++
++static struct sensor_device_attribute sda_tolerance[] = {
++ SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
++ store_tolerance, 0),
++ SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
++ store_tolerance, 1),
++ SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
++ store_tolerance, 2),
++ SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
++ store_tolerance, 3),
++};
++
++/* Smart Fan registers */
++
++#define fan_functions(reg, REG) \
++static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ return sprintf(buf, "%d\n", data->reg[nr]); \
++}\
++static ssize_t \
++store_##reg(struct device *dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{\
++ struct i2c_client *client = to_i2c_client(dev); \
++ struct w83627ehf_data *data = i2c_get_clientdata(client); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
++ mutex_lock(&data->update_lock); \
++ data->reg[nr] = val; \
++ w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
++ mutex_unlock(&data->update_lock); \
++ return count; \
++}
++
++fan_functions(fan_min_output, FAN_MIN_OUTPUT)
++
++#define fan_time_functions(reg, REG) \
++static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ return sprintf(buf, "%d\n", \
++ step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
++} \
++\
++static ssize_t \
++store_##reg(struct device *dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct i2c_client *client = to_i2c_client(dev); \
++ struct w83627ehf_data *data = i2c_get_clientdata(client); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
++ data->pwm_mode[nr]); \
++ mutex_lock(&data->update_lock); \
++ data->reg[nr] = val; \
++ w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
++ mutex_unlock(&data->update_lock); \
++ return count; \
++} \
++
++fan_time_functions(fan_stop_time, FAN_STOP_TIME)
++
++
++static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
++ SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
++ store_fan_stop_time, 3),
++ SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
++ store_fan_min_output, 3),
++};
++
++static struct sensor_device_attribute sda_sf3_arrays[] = {
++ SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
++ store_fan_stop_time, 0),
++ SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
++ store_fan_stop_time, 1),
++ SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
++ store_fan_stop_time, 2),
++ SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
++ store_fan_min_output, 0),
++ SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
++ store_fan_min_output, 1),
++ SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
++ store_fan_min_output, 2),
++};
++
+ /*
+ * Driver and client management
+ */
+
++static void w83627ehf_device_remove_files(struct device *dev)
++{
++ /* some entries in the following arrays may not have been used in
++ * device_create_file(), but device_remove_file() will ignore them */
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
++ device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
++ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
++ device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
++ for (i = 0; i < 10; i++) {
++ device_remove_file(dev, &sda_in_input[i].dev_attr);
++ device_remove_file(dev, &sda_in_alarm[i].dev_attr);
++ device_remove_file(dev, &sda_in_min[i].dev_attr);
++ device_remove_file(dev, &sda_in_max[i].dev_attr);
++ }
++ for (i = 0; i < 5; i++) {
++ device_remove_file(dev, &sda_fan_input[i].dev_attr);
++ device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
++ device_remove_file(dev, &sda_fan_div[i].dev_attr);
++ device_remove_file(dev, &sda_fan_min[i].dev_attr);
++ }
++ for (i = 0; i < 4; i++) {
++ device_remove_file(dev, &sda_pwm[i].dev_attr);
++ device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
++ device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
++ device_remove_file(dev, &sda_target_temp[i].dev_attr);
++ device_remove_file(dev, &sda_tolerance[i].dev_attr);
++ }
++ for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
++ device_remove_file(dev, &sda_temp[i].dev_attr);
++}
++
+ static struct i2c_driver w83627ehf_driver;
+
+ static void w83627ehf_init_client(struct i2c_client *client)
+@@ -810,6 +1173,7 @@ static int w83627ehf_detect(struct i2c_a
+ struct i2c_client *client;
+ struct w83627ehf_data *data;
+ struct device *dev;
++ u8 fan4pin, fan5pin;
+ int i, err = 0;
+
+ if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
+@@ -848,35 +1212,90 @@ static int w83627ehf_detect(struct i2c_a
+ data->fan_min[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_MIN[i]);
+
++ /* fan4 and fan5 share some pins with the GPIO and serial flash */
++
++ superio_enter();
++ fan5pin = superio_inb(0x24) & 0x2;
++ fan4pin = superio_inb(0x29) & 0x6;
++ superio_exit();
++
+ /* It looks like fan4 and fan5 pins can be alternatively used
+- as fan on/off switches */
++ as fan on/off switches, but fan5 control is write only :/
++ We assume that if the serial interface is disabled, designers
++ connected fan5 as input unless they are emitting log 1, which
++ is not the default. */
++
+ data->has_fan = 0x07; /* fan1, fan2 and fan3 */
+ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+- if (i & (1 << 2))
++ if ((i & (1 << 2)) && (!fan4pin))
+ data->has_fan |= (1 << 3);
+- if (i & (1 << 0))
++ if (!(i & (1 << 1)) && (!fan5pin))
+ data->has_fan |= (1 << 4);
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
+- goto exit_detach;
+- }
++ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
++ if ((err = device_create_file(dev,
++ &sda_sf3_arrays[i].dev_attr)))
++ goto exit_remove;
++
++ /* if fan4 is enabled create the sf3 files for it */
++ if (data->has_fan & (1 << 3))
++ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
++ if ((err = device_create_file(dev,
++ &sda_sf3_arrays_fan4[i].dev_attr)))
++ goto exit_remove;
++ }
+
+ for (i = 0; i < 10; i++)
+- device_create_file_in(dev, i);
++ if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_in_alarm[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_in_min[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_in_max[i].dev_attr)))
++ goto exit_remove;
+
+ for (i = 0; i < 5; i++) {
+- if (data->has_fan & (1 << i))
+- device_create_file_fan(dev, i);
++ if (data->has_fan & (1 << i)) {
++ if ((err = device_create_file(dev,
++ &sda_fan_input[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_fan_alarm[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_fan_div[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_fan_min[i].dev_attr)))
++ goto exit_remove;
++ if (i < 4 && /* w83627ehf only has 4 pwm */
++ ((err = device_create_file(dev,
++ &sda_pwm[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_pwm_mode[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_pwm_enable[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_target_temp[i].dev_attr))
++ || (err = device_create_file(dev,
++ &sda_tolerance[i].dev_attr))))
++ goto exit_remove;
++ }
+ }
++
+ for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
+- device_create_file(dev, &sda_temp[i].dev_attr);
++ if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
++ goto exit_remove;
++
++ data->class_dev = hwmon_device_register(dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove;
++ }
+
+ return 0;
+
+-exit_detach:
++exit_remove:
++ w83627ehf_device_remove_files(dev);
+ i2c_detach_client(client);
+ exit_free:
+ kfree(data);
+@@ -892,6 +1311,7 @@ static int w83627ehf_detach_client(struc
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
++ w83627ehf_device_remove_files(&client->dev);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+@@ -903,6 +1323,7 @@ static int w83627ehf_detach_client(struc
+
+ static struct i2c_driver w83627ehf_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "w83627ehf",
+ },
+ .attach_adapter = w83627ehf_detect,
+diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
+index 79368d5..dfdc29c 100644
+--- a/drivers/hwmon/w83627hf.c
++++ b/drivers/hwmon/w83627hf.c
+@@ -339,6 +339,7 @@ static void w83627hf_init_client(struct
+
+ static struct i2c_driver w83627hf_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "w83627hf",
+ },
+ .attach_adapter = w83627hf_detect,
+@@ -511,13 +512,6 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_
+ static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
+ show_regs_in_max0, store_regs_in_max0);
+
+-#define device_create_file_in(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
+-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
+-} while (0)
+-
+ #define show_fan_reg(reg) \
+ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+ { \
+@@ -575,12 +569,6 @@ sysfs_fan_min_offset(2);
+ sysfs_fan_offset(3);
+ sysfs_fan_min_offset(3);
+
+-#define device_create_file_fan(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
+-} while (0)
+-
+ #define show_temp_reg(reg) \
+ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+ { \
+@@ -655,13 +643,6 @@ sysfs_temp_offsets(1);
+ sysfs_temp_offsets(2);
+ sysfs_temp_offsets(3);
+
+-#define device_create_file_temp(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
+-} while (0)
+-
+ static ssize_t
+ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -669,8 +650,6 @@ show_vid_reg(struct device *dev, struct
+ return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+ }
+ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+-#define device_create_file_vid(client) \
+-device_create_file(&client->dev, &dev_attr_cpu0_vid)
+
+ static ssize_t
+ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -691,8 +670,6 @@ store_vrm_reg(struct device *dev, struct
+ return count;
+ }
+ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+-#define device_create_file_vrm(client) \
+-device_create_file(&client->dev, &dev_attr_vrm)
+
+ static ssize_t
+ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -701,8 +678,6 @@ show_alarms_reg(struct device *dev, stru
+ return sprintf(buf, "%ld\n", (long) data->alarms);
+ }
+ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+-#define device_create_file_alarms(client) \
+-device_create_file(&client->dev, &dev_attr_alarms)
+
+ #define show_beep_reg(REG, reg) \
+ static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
+@@ -765,12 +740,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO |
+ sysfs_beep(ENABLE, enable);
+ sysfs_beep(MASK, mask);
+
+-#define device_create_file_beep(client) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_beep_enable); \
+-device_create_file(&client->dev, &dev_attr_beep_mask); \
+-} while (0)
+-
+ static ssize_t
+ show_fan_div_reg(struct device *dev, char *buf, int nr)
+ {
+@@ -836,11 +805,6 @@ sysfs_fan_div(1);
+ sysfs_fan_div(2);
+ sysfs_fan_div(3);
+
+-#define device_create_file_fan_div(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
+-} while (0)
+-
+ static ssize_t
+ show_pwm_reg(struct device *dev, char *buf, int nr)
+ {
+@@ -895,11 +859,6 @@ sysfs_pwm(1);
+ sysfs_pwm(2);
+ sysfs_pwm(3);
+
+-#define device_create_file_pwm(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_pwm##offset); \
+-} while (0)
+-
+ static ssize_t
+ show_sensor_reg(struct device *dev, char *buf, int nr)
+ {
+@@ -971,12 +930,6 @@ sysfs_sensor(1);
+ sysfs_sensor(2);
+ sysfs_sensor(3);
+
+-#define device_create_file_sensor(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
+-} while (0)
+-
+-
+ static int __init w83627hf_find(int sioaddr, unsigned short *addr)
+ {
+ u16 val;
+@@ -1008,6 +961,85 @@ static int __init w83627hf_find(int sioa
+ return 0;
+ }
+
++static struct attribute *w83627hf_attributes[] = {
++ &dev_attr_in0_input.attr,
++ &dev_attr_in0_min.attr,
++ &dev_attr_in0_max.attr,
++ &dev_attr_in2_input.attr,
++ &dev_attr_in2_min.attr,
++ &dev_attr_in2_max.attr,
++ &dev_attr_in3_input.attr,
++ &dev_attr_in3_min.attr,
++ &dev_attr_in3_max.attr,
++ &dev_attr_in4_input.attr,
++ &dev_attr_in4_min.attr,
++ &dev_attr_in4_max.attr,
++ &dev_attr_in7_input.attr,
++ &dev_attr_in7_min.attr,
++ &dev_attr_in7_max.attr,
++ &dev_attr_in8_input.attr,
++ &dev_attr_in8_min.attr,
++ &dev_attr_in8_max.attr,
++
++ &dev_attr_fan1_input.attr,
++ &dev_attr_fan1_min.attr,
++ &dev_attr_fan1_div.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_min.attr,
++ &dev_attr_fan2_div.attr,
++
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_max.attr,
++ &dev_attr_temp1_max_hyst.attr,
++ &dev_attr_temp1_type.attr,
++ &dev_attr_temp2_input.attr,
++ &dev_attr_temp2_max.attr,
++ &dev_attr_temp2_max_hyst.attr,
++ &dev_attr_temp2_type.attr,
++
++ &dev_attr_alarms.attr,
++ &dev_attr_beep_enable.attr,
++ &dev_attr_beep_mask.attr,
++
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm2.attr,
++
++ NULL
++};
++
++static const struct attribute_group w83627hf_group = {
++ .attrs = w83627hf_attributes,
++};
++
++static struct attribute *w83627hf_attributes_opt[] = {
++ &dev_attr_in1_input.attr,
++ &dev_attr_in1_min.attr,
++ &dev_attr_in1_max.attr,
++ &dev_attr_in5_input.attr,
++ &dev_attr_in5_min.attr,
++ &dev_attr_in5_max.attr,
++ &dev_attr_in6_input.attr,
++ &dev_attr_in6_min.attr,
++ &dev_attr_in6_max.attr,
++
++ &dev_attr_fan3_input.attr,
++ &dev_attr_fan3_min.attr,
++ &dev_attr_fan3_div.attr,
++
++ &dev_attr_temp3_input.attr,
++ &dev_attr_temp3_max.attr,
++ &dev_attr_temp3_max_hyst.attr,
++ &dev_attr_temp3_type.attr,
++
++ &dev_attr_pwm3.attr,
++
++ NULL
++};
++
++static const struct attribute_group w83627hf_group_opt = {
++ .attrs = w83627hf_attributes_opt,
++};
++
+ static int w83627hf_detect(struct i2c_adapter *adapter)
+ {
+ int val, kind;
+@@ -1107,62 +1139,72 @@ static int w83627hf_detect(struct i2c_ad
+ data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
+ data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
+
+- /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ /* Register common device attributes */
++ if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
+ goto ERROR3;
+- }
+-
+- device_create_file_in(new_client, 0);
+- if (kind != w83697hf)
+- device_create_file_in(new_client, 1);
+- device_create_file_in(new_client, 2);
+- device_create_file_in(new_client, 3);
+- device_create_file_in(new_client, 4);
+- if (kind == w83627hf || kind == w83697hf) {
+- device_create_file_in(new_client, 5);
+- device_create_file_in(new_client, 6);
+- }
+- device_create_file_in(new_client, 7);
+- device_create_file_in(new_client, 8);
+-
+- device_create_file_fan(new_client, 1);
+- device_create_file_fan(new_client, 2);
+- if (kind != w83697hf)
+- device_create_file_fan(new_client, 3);
+-
+- device_create_file_temp(new_client, 1);
+- device_create_file_temp(new_client, 2);
+- if (kind != w83697hf)
+- device_create_file_temp(new_client, 3);
+
+- if (kind != w83697hf && data->vid != 0xff) {
+- device_create_file_vid(new_client);
+- device_create_file_vrm(new_client);
+- }
++ /* Register chip-specific device attributes */
++ if (kind == w83627hf || kind == w83697hf)
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in5_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in5_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in5_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in6_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in6_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in6_max)))
++ goto ERROR4;
+
+- device_create_file_fan_div(new_client, 1);
+- device_create_file_fan_div(new_client, 2);
+ if (kind != w83697hf)
+- device_create_file_fan_div(new_client, 3);
+-
+- device_create_file_alarms(new_client);
+-
+- device_create_file_beep(new_client);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in1_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in1_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_in1_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan3_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan3_min))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_fan3_div))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_input))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_max))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_max_hyst))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_temp3_type)))
++ goto ERROR4;
++
++ if (kind != w83697hf && data->vid != 0xff)
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_cpu0_vid))
++ || (err = device_create_file(&new_client->dev,
++ &dev_attr_vrm)))
++ goto ERROR4;
+
+- device_create_file_pwm(new_client, 1);
+- device_create_file_pwm(new_client, 2);
+ if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
+- device_create_file_pwm(new_client, 3);
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_pwm3)))
++ goto ERROR4;
+
+- device_create_file_sensor(new_client, 1);
+- device_create_file_sensor(new_client, 2);
+- if (kind != w83697hf)
+- device_create_file_sensor(new_client, 3);
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto ERROR4;
++ }
+
+ return 0;
+
++ ERROR4:
++ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
++ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
+ ERROR3:
+ i2c_detach_client(new_client);
+ ERROR2:
+@@ -1180,6 +1222,9 @@ static int w83627hf_detach_client(struct
+
+ hwmon_device_unregister(data->class_dev);
+
++ sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
++ sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
++
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
+index 7be469e..1232171 100644
+--- a/drivers/hwmon/w83781d.c
++++ b/drivers/hwmon/w83781d.c
+@@ -41,6 +41,7 @@
+ #include <linux/i2c-isa.h>
+ #include <linux/hwmon.h>
+ #include <linux/hwmon-vid.h>
++#include <linux/sysfs.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
+ #include <asm/io.h>
+@@ -288,6 +289,7 @@ static struct i2c_driver w83781d_driver
+
+ static struct i2c_driver w83781d_isa_driver = {
+ .driver = {
++ .owner = THIS_MODULE,
+ .name = "w83781d-isa",
+ },
+ .attach_adapter = w83781d_isa_attach_adapter,
+@@ -359,13 +361,6 @@ sysfs_in_offsets(6);
+ sysfs_in_offsets(7);
+ sysfs_in_offsets(8);
+
+-#define device_create_file_in(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
+-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
+-} while (0)
+-
+ #define show_fan_reg(reg) \
+ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+ { \
+@@ -420,12 +415,6 @@ sysfs_fan_min_offset(2);
+ sysfs_fan_offset(3);
+ sysfs_fan_min_offset(3);
+
+-#define device_create_file_fan(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
+-} while (0)
+-
+ #define show_temp_reg(reg) \
+ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+ { \
+@@ -496,13 +485,6 @@ sysfs_temp_offsets(1);
+ sysfs_temp_offsets(2);
+ sysfs_temp_offsets(3);
+
+-#define device_create_file_temp(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
+-} while (0)
+-
+ static ssize_t
+ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -510,10 +492,8 @@ show_vid_reg(struct device *dev, struct
+ return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+ }
+
+-static
+-DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+-#define device_create_file_vid(client) \
+-device_create_file(&client->dev, &dev_attr_cpu0_vid);
++static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
++
+ static ssize_t
+ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -534,10 +514,8 @@ store_vrm_reg(struct device *dev, struct
+ return count;
+ }
+
+-static
+-DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+-#define device_create_file_vrm(client) \
+-device_create_file(&client->dev, &dev_attr_vrm);
++static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
++
+ static ssize_t
+ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -545,10 +523,8 @@ show_alarms_reg(struct device *dev, stru
+ return sprintf(buf, "%u\n", data->alarms);
+ }
+
+-static
+-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+-#define device_create_file_alarms(client) \
+-device_create_file(&client->dev, &dev_attr_alarms);
++static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
++
+ static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct w83781d_data *data = w83781d_update_device(dev);
+@@ -614,12 +590,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO |
+ sysfs_beep(ENABLE, enable);
+ sysfs_beep(MASK, mask);
+
+-#define device_create_file_beep(client) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_beep_enable); \
+-device_create_file(&client->dev, &dev_attr_beep_mask); \
+-} while (0)
+-
+ static ssize_t
+ show_fan_div_reg(struct device *dev, char *buf, int nr)
+ {
+@@ -685,11 +655,6 @@ sysfs_fan_div(1);
+ sysfs_fan_div(2);
+ sysfs_fan_div(3);
+
+-#define device_create_file_fan_div(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
+-} while (0)
+-
+ static ssize_t
+ show_pwm_reg(struct device *dev, char *buf, int nr)
+ {
+@@ -786,16 +751,6 @@ sysfs_pwmenable(2); /* only PWM2 can be
+ sysfs_pwm(3);
+ sysfs_pwm(4);
+
+-#define device_create_file_pwm(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_pwm##offset); \
+-} while (0)
+-
+-#define device_create_file_pwmenable(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \
+-} while (0)
+-
+ static ssize_t
+ show_sensor_reg(struct device *dev, char *buf, int nr)
+ {
+@@ -864,11 +819,6 @@ sysfs_sensor(1);
+ sysfs_sensor(2);
+ sysfs_sensor(3);
+
+-#define device_create_file_sensor(client, offset) \
+-do { \
+-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
+-} while (0)
+-
+ /* This function is called when:
+ * w83781d_driver is inserted (when this module is loaded), for each
+ available adapter
+@@ -993,11 +943,69 @@ ERROR_SC_0:
+ return err;
+ }
+
++#define IN_UNIT_ATTRS(X) \
++ &dev_attr_in##X##_input.attr, \
++ &dev_attr_in##X##_min.attr, \
++ &dev_attr_in##X##_max.attr
++
++#define FAN_UNIT_ATTRS(X) \
++ &dev_attr_fan##X##_input.attr, \
++ &dev_attr_fan##X##_min.attr, \
++ &dev_attr_fan##X##_div.attr
++
++#define TEMP_UNIT_ATTRS(X) \
++ &dev_attr_temp##X##_input.attr, \
++ &dev_attr_temp##X##_max.attr, \
++ &dev_attr_temp##X##_max_hyst.attr
++
++static struct attribute* w83781d_attributes[] = {
++ IN_UNIT_ATTRS(0),
++ IN_UNIT_ATTRS(2),
++ IN_UNIT_ATTRS(3),
++ IN_UNIT_ATTRS(4),
++ IN_UNIT_ATTRS(5),
++ IN_UNIT_ATTRS(6),
++ FAN_UNIT_ATTRS(1),
++ FAN_UNIT_ATTRS(2),
++ FAN_UNIT_ATTRS(3),
++ TEMP_UNIT_ATTRS(1),
++ TEMP_UNIT_ATTRS(2),
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_beep_mask.attr,
++ &dev_attr_beep_enable.attr,
++ NULL
++};
++static const struct attribute_group w83781d_group = {
++ .attrs = w83781d_attributes,
++};
++
++static struct attribute *w83781d_attributes_opt[] = {
++ IN_UNIT_ATTRS(1),
++ IN_UNIT_ATTRS(7),
++ IN_UNIT_ATTRS(8),
++ TEMP_UNIT_ATTRS(3),
++ &dev_attr_pwm1.attr,
++ &dev_attr_pwm2.attr,
++ &dev_attr_pwm2_enable.attr,
++ &dev_attr_pwm3.attr,
++ &dev_attr_pwm4.attr,
++ &dev_attr_temp1_type.attr,
++ &dev_attr_temp2_type.attr,
++ &dev_attr_temp3_type.attr,
++ NULL
++};
++static const struct attribute_group w83781d_group_opt = {
++ .attrs = w83781d_attributes_opt,
++};
++
+ static int
+ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
+ {
+ int i = 0, val1 = 0, val2;
+- struct i2c_client *new_client;
++ struct i2c_client *client;
++ struct device *dev;
+ struct w83781d_data *data;
+ int err;
+ const char *client_name = "";
+@@ -1074,13 +1082,14 @@ w83781d_detect(struct i2c_adapter *adapt
+ goto ERROR1;
+ }
+
+- new_client = &data->client;
+- i2c_set_clientdata(new_client, data);
+- new_client->addr = address;
++ client = &data->client;
++ i2c_set_clientdata(client, data);
++ client->addr = address;
+ mutex_init(&data->lock);
+- new_client->adapter = adapter;
+- new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
+- new_client->flags = 0;
++ client->adapter = adapter;
++ client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
++ client->flags = 0;
++ dev = &client->dev;
+
+ /* Now, we do the remaining detection. */
+
+@@ -1089,20 +1098,20 @@ w83781d_detect(struct i2c_adapter *adapt
+ force_*=... parameter, and the Winbond will be reset to the right
+ bank. */
+ if (kind < 0) {
+- if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) {
+- dev_dbg(&new_client->dev, "Detection failed at step "
+- "3\n");
++ if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
++ dev_dbg(&adapter->dev, "Detection of w83781d chip "
++ "failed at step 3\n");
+ err = -ENODEV;
+ goto ERROR2;
+ }
+- val1 = w83781d_read_value(new_client, W83781D_REG_BANK);
+- val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
++ val1 = w83781d_read_value(client, W83781D_REG_BANK);
++ val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
+ /* Check for Winbond or Asus ID if in bank 0 */
+ if ((!(val1 & 0x07)) &&
+ (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
+ || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
+- dev_dbg(&new_client->dev, "Detection failed at step "
+- "4\n");
++ dev_dbg(&adapter->dev, "Detection of w83781d chip "
++ "failed at step 4\n");
+ err = -ENODEV;
+ goto ERROR2;
+ }
+@@ -1111,9 +1120,9 @@ w83781d_detect(struct i2c_adapter *adapt
+ if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
+ ((val1 & 0x80) && (val2 == 0x5c)))) {
+ if (w83781d_read_value
+- (new_client, W83781D_REG_I2C_ADDR) != address) {
+- dev_dbg(&new_client->dev, "Detection failed "
+- "at step 5\n");
++ (client, W83781D_REG_I2C_ADDR) != address) {
++ dev_dbg(&adapter->dev, "Detection of w83781d "
++ "chip failed at step 5\n");
+ err = -ENODEV;
+ goto ERROR2;
+ }
+@@ -1122,27 +1131,26 @@ w83781d_detect(struct i2c_adapter *adapt
+
+ /* We have either had a force parameter, or we have already detected the
+ Winbond. Put it now into bank 0 and Vendor ID High Byte */
+- w83781d_write_value(new_client, W83781D_REG_BANK,
+- (w83781d_read_value(new_client,
+- W83781D_REG_BANK) & 0x78) |
+- 0x80);
++ w83781d_write_value(client, W83781D_REG_BANK,
++ (w83781d_read_value(client, W83781D_REG_BANK)
++ & 0x78) | 0x80);
+
+ /* Determine the chip type. */
+ if (kind <= 0) {
+ /* get vendor ID */
+- val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
++ val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
+ if (val2 == 0x5c)
+ vendid = winbond;
+ else if (val2 == 0x12)
+ vendid = asus;
+ else {
+- dev_dbg(&new_client->dev, "Chip was made by neither "
+- "Winbond nor Asus?\n");
++ dev_dbg(&adapter->dev, "w83781d chip vendor is "
++ "neither Winbond nor Asus\n");
+ err = -ENODEV;
+ goto ERROR2;
+ }
+
+- val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID);
++ val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
+ if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
+ kind = w83781d;
+ else if (val1 == 0x30 && vendid == winbond)
+@@ -1156,10 +1164,9 @@ w83781d_detect(struct i2c_adapter *adapt
+ kind = as99127f;
+ else {
+ if (kind == 0)
+- dev_warn(&new_client->dev, "Ignoring 'force' "
++ dev_warn(&adapter->dev, "Ignoring 'force' "
+ "parameter for unknown chip at "
+- "adapter %d, address 0x%02x\n",
+- i2c_adapter_id(adapter), address);
++ "address 0x%02x\n", address);
+ err = -EINVAL;
+ goto ERROR2;
+ }
+@@ -1178,20 +1185,20 @@ w83781d_detect(struct i2c_adapter *adapt
+ }
+
+ /* Fill in the remaining client fields and put into the global list */
+- strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
++ strlcpy(client->name, client_name, I2C_NAME_SIZE);
+ data->type = kind;
+
+ data->valid = 0;
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+- if ((err = i2c_attach_client(new_client)))
++ if ((err = i2c_attach_client(client)))
+ goto ERROR2;
+
+ /* attach secondary i2c lm75-like clients */
+ if (!is_isa) {
+ if ((err = w83781d_detect_subclients(adapter, address,
+- kind, new_client)))
++ kind, client)))
+ goto ERROR3;
+ } else {
+ data->lm75[0] = NULL;
+@@ -1199,11 +1206,11 @@ w83781d_detect(struct i2c_adapter *adapt
+ }
+
+ /* Initialize the chip */
+- w83781d_init_client(new_client);
++ w83781d_init_client(client);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 1; i <= 3; i++) {
+- data->fan_min[i - 1] = w83781d_read_value(new_client,
++ data->fan_min[i - 1] = w83781d_read_value(client,
+ W83781D_REG_FAN_MIN(i));
+ }
+ if (kind != w83781d && kind != as99127f)
+@@ -1211,65 +1218,68 @@ w83781d_detect(struct i2c_adapter *adapt
+ data->pwmenable[i] = 1;
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(&new_client->dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
+ goto ERROR4;
+- }
+
+- device_create_file_in(new_client, 0);
+- if (kind != w83783s)
+- device_create_file_in(new_client, 1);
+- device_create_file_in(new_client, 2);
+- device_create_file_in(new_client, 3);
+- device_create_file_in(new_client, 4);
+- device_create_file_in(new_client, 5);
+- device_create_file_in(new_client, 6);
++ if (kind != w83783s) {
++ if ((err = device_create_file(dev, &dev_attr_in1_input))
++ || (err = device_create_file(dev, &dev_attr_in1_min))
++ || (err = device_create_file(dev, &dev_attr_in1_max)))
++ goto ERROR4;
++ }
+ if (kind != as99127f && kind != w83781d && kind != w83783s) {
+- device_create_file_in(new_client, 7);
+- device_create_file_in(new_client, 8);
++ if ((err = device_create_file(dev, &dev_attr_in7_input))
++ || (err = device_create_file(dev, &dev_attr_in7_min))
++ || (err = device_create_file(dev, &dev_attr_in7_max))
++ || (err = device_create_file(dev, &dev_attr_in8_input))
++ || (err = device_create_file(dev, &dev_attr_in8_min))
++ || (err = device_create_file(dev, &dev_attr_in8_max)))
++ goto ERROR4;
++ }
++ if (kind != w83783s) {
++ if ((err = device_create_file(dev, &dev_attr_temp3_input))
++ || (err = device_create_file(dev, &dev_attr_temp3_max))
++ || (err = device_create_file(dev,
++ &dev_attr_temp3_max_hyst)))
++ goto ERROR4;
+ }
+-
+- device_create_file_fan(new_client, 1);
+- device_create_file_fan(new_client, 2);
+- device_create_file_fan(new_client, 3);
+-
+- device_create_file_temp(new_client, 1);
+- device_create_file_temp(new_client, 2);
+- if (kind != w83783s)
+- device_create_file_temp(new_client, 3);
+-
+- device_create_file_vid(new_client);
+- device_create_file_vrm(new_client);
+-
+- device_create_file_fan_div(new_client, 1);
+- device_create_file_fan_div(new_client, 2);
+- device_create_file_fan_div(new_client, 3);
+-
+- device_create_file_alarms(new_client);
+-
+- device_create_file_beep(new_client);
+
+ if (kind != w83781d && kind != as99127f) {
+- device_create_file_pwm(new_client, 1);
+- device_create_file_pwm(new_client, 2);
+- device_create_file_pwmenable(new_client, 2);
++ if ((err = device_create_file(dev, &dev_attr_pwm1))
++ || (err = device_create_file(dev, &dev_attr_pwm2))
++ || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
++ goto ERROR4;
+ }
+ if (kind == w83782d && !is_isa) {
+- device_create_file_pwm(new_client, 3);
+- device_create_file_pwm(new_client, 4);
++ if ((err = device_create_file(dev, &dev_attr_pwm3))
++ || (err = device_create_file(dev, &dev_attr_pwm4)))
++ goto ERROR4;
+ }
+
+ if (kind != as99127f && kind != w83781d) {
+- device_create_file_sensor(new_client, 1);
+- device_create_file_sensor(new_client, 2);
+- if (kind != w83783s)
+- device_create_file_sensor(new_client, 3);
++ if ((err = device_create_file(dev, &dev_attr_temp1_type))
++ || (err = device_create_file(dev,
++ &dev_attr_temp2_type)))
++ goto ERROR4;
++ if (kind != w83783s) {
++ if ((err = device_create_file(dev,
++ &dev_attr_temp3_type)))
++ goto ERROR4;
++ }
++ }
++
++ data->class_dev = hwmon_device_register(dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto ERROR4;
+ }
+
+ return 0;
+
+ ERROR4:
++ sysfs_remove_group(&dev->kobj, &w83781d_group);
++ sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
++
+ if (data->lm75[1]) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+@@ -1279,7 +1289,7 @@ ERROR4:
+ kfree(data->lm75[0]);
+ }
+ ERROR3:
+- i2c_detach_client(new_client);
++ i2c_detach_client(client);
+ ERROR2:
+ kfree(data);
+ ERROR1:
+@@ -1296,9 +1306,11 @@ w83781d_detach_client(struct i2c_client
+ int err;
+
+ /* main client */
+- if (data)
++ if (data) {
+ hwmon_device_unregister(data->class_dev);
+-
++ sysfs_remove_group(&client->dev.kobj, &w83781d_group);
++ sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
++ }
+ if (i2c_is_isa_client(client))
+ release_region(client->addr, W83781D_EXTENT);
+
+@@ -1675,11 +1687,10 @@ sensors_w83781d_init(void)
+ if (res)
+ return res;
+
+- res = i2c_isa_add_driver(&w83781d_isa_driver);
+- if (res) {
+- i2c_del_driver(&w83781d_driver);
+- return res;
+- }
++ /* Don't exit if this one fails, we still want the I2C variants
++ to work! */
++ if (i2c_isa_add_driver(&w83781d_isa_driver))
++ isa_address = 0;
+
+ return 0;
+ }
+@@ -1687,7 +1698,8 @@ sensors_w83781d_init(void)
+ static void __exit
+ sensors_w83781d_exit(void)
+ {
+- i2c_isa_del_driver(&w83781d_isa_driver);
++ if (isa_address)
++ i2c_isa_del_driver(&w83781d_isa_driver);
+ i2c_del_driver(&w83781d_driver);
+ }
+
+diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
+index eec43ab..9e5f885 100644
+--- a/drivers/hwmon/w83791d.c
++++ b/drivers/hwmon/w83791d.c
+@@ -27,12 +27,11 @@
+
+ The w83791d chip appears to be part way between the 83781d and the
+ 83792d. Thus, this file is derived from both the w83792d.c and
+- w83781d.c files, but its output is more along the lines of the
+- 83781d (which means there are no changes to the user-mode sensors
+- program which treats the 83791d as an 83781d).
++ w83781d.c files.
++
++ The w83791g chip is the same as the w83791d but lead-free.
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -747,6 +746,52 @@ static ssize_t store_vrm_reg(struct devi
+
+ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
++#define IN_UNIT_ATTRS(X) \
++ &sda_in_input[X].dev_attr.attr, \
++ &sda_in_min[X].dev_attr.attr, \
++ &sda_in_max[X].dev_attr.attr
++
++#define FAN_UNIT_ATTRS(X) \
++ &sda_fan_input[X].dev_attr.attr, \
++ &sda_fan_min[X].dev_attr.attr, \
++ &sda_fan_div[X].dev_attr.attr
++
++#define TEMP_UNIT_ATTRS(X) \
++ &sda_temp_input[X].dev_attr.attr, \
++ &sda_temp_max[X].dev_attr.attr, \
++ &sda_temp_max_hyst[X].dev_attr.attr
++
++static struct attribute *w83791d_attributes[] = {
++ IN_UNIT_ATTRS(0),
++ IN_UNIT_ATTRS(1),
++ IN_UNIT_ATTRS(2),
++ IN_UNIT_ATTRS(3),
++ IN_UNIT_ATTRS(4),
++ IN_UNIT_ATTRS(5),
++ IN_UNIT_ATTRS(6),
++ IN_UNIT_ATTRS(7),
++ IN_UNIT_ATTRS(8),
++ IN_UNIT_ATTRS(9),
++ FAN_UNIT_ATTRS(0),
++ FAN_UNIT_ATTRS(1),
++ FAN_UNIT_ATTRS(2),
++ FAN_UNIT_ATTRS(3),
++ FAN_UNIT_ATTRS(4),
++ TEMP_UNIT_ATTRS(0),
++ TEMP_UNIT_ATTRS(1),
++ TEMP_UNIT_ATTRS(2),
++ &dev_attr_alarms.attr,
++ &sda_beep_ctrl[0].dev_attr.attr,
++ &sda_beep_ctrl[1].dev_attr.attr,
++ &dev_attr_cpu0_vid.attr,
++ &dev_attr_vrm.attr,
++ NULL
++};
++
++static const struct attribute_group w83791d_group = {
++ .attrs = w83791d_attributes,
++};
++
+ /* This function is called when:
+ * w83791d_driver is inserted (when this module is loaded), for each
+ available adapter
+@@ -968,41 +1013,20 @@ static int w83791d_detect(struct i2c_ada
+ }
+
+ /* Register sysfs hooks */
++ if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group)))
++ goto error3;
++
++ /* Everything is ready, now register the working device */
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto error3;
+- }
+-
+- for (i = 0; i < NUMBER_OF_VIN; i++) {
+- device_create_file(dev, &sda_in_input[i].dev_attr);
+- device_create_file(dev, &sda_in_min[i].dev_attr);
+- device_create_file(dev, &sda_in_max[i].dev_attr);
++ goto error4;
+ }
+
+- for (i = 0; i < NUMBER_OF_FANIN; i++) {
+- device_create_file(dev, &sda_fan_input[i].dev_attr);
+- device_create_file(dev, &sda_fan_div[i].dev_attr);
+- device_create_file(dev, &sda_fan_min[i].dev_attr);
+- }
+-
+- for (i = 0; i < NUMBER_OF_TEMPIN; i++) {
+- device_create_file(dev, &sda_temp_input[i].dev_attr);
+- device_create_file(dev, &sda_temp_max[i].dev_attr);
+- device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
+- }
+-
+- device_create_file(dev, &dev_attr_alarms);
+-
+- for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) {
+- device_create_file(dev, &sda_beep_ctrl[i].dev_attr);
+- }
+-
+- device_create_file(dev, &dev_attr_cpu0_vid);
+- device_create_file(dev, &dev_attr_vrm);
+-
+ return 0;
+
++error4:
++ sysfs_remove_group(&client->dev.kobj, &w83791d_group);
+ error3:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+@@ -1026,8 +1050,10 @@ static int w83791d_detach_client(struct
+ int err;
+
+ /* main client */
+- if (data)
++ if (data) {
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &w83791d_group);
++ }
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+@@ -1172,6 +1198,7 @@ static struct w83791d_data *w83791d_upda
+ (w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
+ (w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
+
++ /* Extract global beep enable flag */
+ data->beep_enable =
+ (data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
+
+diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
+index 7576ec9..4e10826 100644
+--- a/drivers/hwmon/w83792d.c
++++ b/drivers/hwmon/w83792d.c
+@@ -43,6 +43,7 @@
+ #include <linux/hwmon-sysfs.h>
+ #include <linux/err.h>
+ #include <linux/mutex.h>
++#include <linux/sysfs.h>
+
+ /* Addresses to scan */
+ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+@@ -381,41 +382,6 @@ static ssize_t store_in_##reg (struct de
+ store_in_reg(MIN, min);
+ store_in_reg(MAX, max);
+
+-static struct sensor_device_attribute sda_in_input[] = {
+- SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+-};
+-static struct sensor_device_attribute sda_in_min[] = {
+- SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+- SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+- SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+- SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+- SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+- SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+- SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+- SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+- SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+-};
+-static struct sensor_device_attribute sda_in_max[] = {
+- SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+- SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+- SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+- SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+- SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+- SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+- SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+- SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+- SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+-};
+-
+-
+ #define show_fan_reg(reg) \
+ static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+@@ -499,35 +465,6 @@ store_fan_div(struct device *dev, struct
+ return count;
+ }
+
+-static struct sensor_device_attribute sda_fan_input[] = {
+- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1),
+- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2),
+- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3),
+- SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4),
+- SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5),
+- SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6),
+- SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7),
+-};
+-static struct sensor_device_attribute sda_fan_min[] = {
+- SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1),
+- SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2),
+- SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3),
+- SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4),
+- SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5),
+- SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6),
+- SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7),
+-};
+-static struct sensor_device_attribute sda_fan_div[] = {
+- SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1),
+- SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2),
+- SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3),
+- SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4),
+- SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5),
+- SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6),
+- SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7),
+-};
+-
+-
+ /* read/write the temperature1, includes measured value and limits */
+
+ static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
+@@ -595,24 +532,6 @@ static ssize_t store_temp23(struct devic
+ return count;
+ }
+
+-static struct sensor_device_attribute_2 sda_temp_input[] = {
+- SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
+- SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
+- SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
+-};
+-
+-static struct sensor_device_attribute_2 sda_temp_max[] = {
+- SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1),
+- SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2),
+- SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2),
+-};
+-
+-static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+- SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2),
+- SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4),
+- SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4),
+-};
+-
+ /* get reatime status of all sensors items: voltage, temp, fan */
+ static ssize_t
+ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -621,9 +540,6 @@ show_alarms_reg(struct device *dev, stru
+ return sprintf(buf, "%d\n", data->alarms);
+ }
+
+-static
+-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+-
+ static ssize_t
+ show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -715,21 +631,6 @@ store_pwmenable(struct device *dev, stru
+ return count;
+ }
+
+-static struct sensor_device_attribute sda_pwm[] = {
+- SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+- SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+- SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+-};
+-static struct sensor_device_attribute sda_pwm_enable[] = {
+- SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+- show_pwmenable, store_pwmenable, 1),
+- SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+- show_pwmenable, store_pwmenable, 2),
+- SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+- show_pwmenable, store_pwmenable, 3),
+-};
+-
+-
+ static ssize_t
+ show_pwm_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -767,16 +668,6 @@ store_pwm_mode(struct device *dev, struc
+ return count;
+ }
+
+-static struct sensor_device_attribute sda_pwm_mode[] = {
+- SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
+- show_pwm_mode, store_pwm_mode, 0),
+- SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
+- show_pwm_mode, store_pwm_mode, 1),
+- SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
+- show_pwm_mode, store_pwm_mode, 2),
+-};
+-
+-
+ static ssize_t
+ show_regs_chassis(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -785,8 +676,6 @@ show_regs_chassis(struct device *dev, st
+ return sprintf(buf, "%d\n", data->chassis);
+ }
+
+-static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
+-
+ static ssize_t
+ show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -815,9 +704,6 @@ store_chassis_clear(struct device *dev,
+ return count;
+ }
+
+-static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
+- show_chassis_clear, store_chassis_clear);
+-
+ /* For Smart Fan I / Thermal Cruise */
+ static ssize_t
+ show_thermal_cruise(struct device *dev, struct device_attribute *attr,
+@@ -853,15 +739,6 @@ store_thermal_cruise(struct device *dev,
+ return count;
+ }
+
+-static struct sensor_device_attribute sda_thermal_cruise[] = {
+- SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
+- show_thermal_cruise, store_thermal_cruise, 1),
+- SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
+- show_thermal_cruise, store_thermal_cruise, 2),
+- SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
+- show_thermal_cruise, store_thermal_cruise, 3),
+-};
+-
+ /* For Smart Fan I/Thermal Cruise and Smart Fan II */
+ static ssize_t
+ show_tolerance(struct device *dev, struct device_attribute *attr,
+@@ -901,15 +778,6 @@ store_tolerance(struct device *dev, stru
+ return count;
+ }
+
+-static struct sensor_device_attribute sda_tolerance[] = {
+- SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO,
+- show_tolerance, store_tolerance, 1),
+- SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO,
+- show_tolerance, store_tolerance, 2),
+- SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO,
+- show_tolerance, store_tolerance, 3),
+-};
+-
+ /* For Smart Fan II */
+ static ssize_t
+ show_sf2_point(struct device *dev, struct device_attribute *attr,
+@@ -946,36 +814,6 @@ store_sf2_point(struct device *dev, stru
+ return count;
+ }
+
+-static struct sensor_device_attribute_2 sda_sf2_point[] = {
+- SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 1, 1),
+- SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 2, 1),
+- SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 3, 1),
+- SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 4, 1),
+-
+- SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 1, 2),
+- SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 2, 2),
+- SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 3, 2),
+- SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 4, 2),
+-
+- SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 1, 3),
+- SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 2, 3),
+- SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 3, 3),
+- SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_point, store_sf2_point, 4, 3),
+-};
+-
+-
+ static ssize_t
+ show_sf2_level(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -1016,29 +854,6 @@ store_sf2_level(struct device *dev, stru
+ return count;
+ }
+
+-static struct sensor_device_attribute_2 sda_sf2_level[] = {
+- SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 1, 1),
+- SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 2, 1),
+- SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 3, 1),
+-
+- SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 1, 2),
+- SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 2, 2),
+- SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 3, 2),
+-
+- SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 1, 3),
+- SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 2, 3),
+- SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
+- show_sf2_level, store_sf2_level, 3, 3),
+-};
+-
+ /* This function is called when:
+ * w83792d_driver is inserted (when this module is loaded), for each
+ available adapter
+@@ -1139,12 +954,297 @@ ERROR_SC_0:
+ return err;
+ }
+
+-static void device_create_file_fan(struct device *dev, int i)
+-{
+- device_create_file(dev, &sda_fan_input[i].dev_attr);
+- device_create_file(dev, &sda_fan_div[i].dev_attr);
+- device_create_file(dev, &sda_fan_min[i].dev_attr);
+-}
++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
++static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 0);
++static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 1);
++static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 2);
++static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 3);
++static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 4);
++static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 5);
++static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 6);
++static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 7);
++static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
++ show_in_min, store_in_min, 8);
++static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 0);
++static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 1);
++static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 2);
++static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 3);
++static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 4);
++static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 5);
++static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 6);
++static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 7);
++static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
++ show_in_max, store_in_max, 8);
++static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0);
++static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0);
++static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0);
++static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
++ show_temp1, store_temp1, 0, 1);
++static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23,
++ store_temp23, 0, 2);
++static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23,
++ store_temp23, 1, 2);
++static SENSOR_DEVICE_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
++ show_temp1, store_temp1, 0, 2);
++static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
++ show_temp23, store_temp23, 0, 4);
++static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
++ show_temp23, store_temp23, 1, 4);
++static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
++static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
++static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
++ show_chassis_clear, store_chassis_clear);
++static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
++static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
++static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
++static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
++ show_pwmenable, store_pwmenable, 1);
++static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
++ show_pwmenable, store_pwmenable, 2);
++static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
++ show_pwmenable, store_pwmenable, 3);
++static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
++ show_pwm_mode, store_pwm_mode, 0);
++static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
++ show_pwm_mode, store_pwm_mode, 1);
++static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
++ show_pwm_mode, store_pwm_mode, 2);
++static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO,
++ show_tolerance, store_tolerance, 1);
++static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO,
++ show_tolerance, store_tolerance, 2);
++static SENSOR_DEVICE_ATTR(tolerance3, S_IWUSR | S_IRUGO,
++ show_tolerance, store_tolerance, 3);
++static SENSOR_DEVICE_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
++ show_thermal_cruise, store_thermal_cruise, 1);
++static SENSOR_DEVICE_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
++ show_thermal_cruise, store_thermal_cruise, 2);
++static SENSOR_DEVICE_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
++ show_thermal_cruise, store_thermal_cruise, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 1, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 2, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 3, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 4, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 1, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 2, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 3, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 4, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 1, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 2, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 3, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_point, store_sf2_point, 4, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 1, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 2, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 3, 1);
++static SENSOR_DEVICE_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 1, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 2, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 3, 2);
++static SENSOR_DEVICE_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 1, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 2, 3);
++static SENSOR_DEVICE_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
++ show_sf2_level, store_sf2_level, 3, 3);
++static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1);
++static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2);
++static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3);
++static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4);
++static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5);
++static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6);
++static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7);
++static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 1);
++static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 2);
++static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 3);
++static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 4);
++static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 5);
++static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 6);
++static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
++ show_fan_min, store_fan_min, 7);
++static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 1);
++static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 2);
++static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 3);
++static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 4);
++static SENSOR_DEVICE_ATTR(fan5_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 5);
++static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 6);
++static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
++ show_fan_div, store_fan_div, 7);
++
++static struct attribute *w83792d_attributes_fan[4][4] = {
++ {
++ &sensor_dev_attr_fan4_input.dev_attr.attr,
++ &sensor_dev_attr_fan4_min.dev_attr.attr,
++ &sensor_dev_attr_fan4_div.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_fan5_input.dev_attr.attr,
++ &sensor_dev_attr_fan5_min.dev_attr.attr,
++ &sensor_dev_attr_fan5_div.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_fan6_input.dev_attr.attr,
++ &sensor_dev_attr_fan6_min.dev_attr.attr,
++ &sensor_dev_attr_fan6_div.dev_attr.attr,
++ NULL
++ }, {
++ &sensor_dev_attr_fan7_input.dev_attr.attr,
++ &sensor_dev_attr_fan7_min.dev_attr.attr,
++ &sensor_dev_attr_fan7_div.dev_attr.attr,
++ NULL
++ }
++};
++
++static const struct attribute_group w83792d_group_fan[4] = {
++ { .attrs = w83792d_attributes_fan[0] },
++ { .attrs = w83792d_attributes_fan[1] },
++ { .attrs = w83792d_attributes_fan[2] },
++ { .attrs = w83792d_attributes_fan[3] },
++};
++
++static struct attribute *w83792d_attributes[] = {
++ &sensor_dev_attr_in0_input.dev_attr.attr,
++ &sensor_dev_attr_in0_max.dev_attr.attr,
++ &sensor_dev_attr_in0_min.dev_attr.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_max.dev_attr.attr,
++ &sensor_dev_attr_in1_min.dev_attr.attr,
++ &sensor_dev_attr_in2_input.dev_attr.attr,
++ &sensor_dev_attr_in2_max.dev_attr.attr,
++ &sensor_dev_attr_in2_min.dev_attr.attr,
++ &sensor_dev_attr_in3_input.dev_attr.attr,
++ &sensor_dev_attr_in3_max.dev_attr.attr,
++ &sensor_dev_attr_in3_min.dev_attr.attr,
++ &sensor_dev_attr_in4_input.dev_attr.attr,
++ &sensor_dev_attr_in4_max.dev_attr.attr,
++ &sensor_dev_attr_in4_min.dev_attr.attr,
++ &sensor_dev_attr_in5_input.dev_attr.attr,
++ &sensor_dev_attr_in5_max.dev_attr.attr,
++ &sensor_dev_attr_in5_min.dev_attr.attr,
++ &sensor_dev_attr_in6_input.dev_attr.attr,
++ &sensor_dev_attr_in6_max.dev_attr.attr,
++ &sensor_dev_attr_in6_min.dev_attr.attr,
++ &sensor_dev_attr_in7_input.dev_attr.attr,
++ &sensor_dev_attr_in7_max.dev_attr.attr,
++ &sensor_dev_attr_in7_min.dev_attr.attr,
++ &sensor_dev_attr_in8_input.dev_attr.attr,
++ &sensor_dev_attr_in8_max.dev_attr.attr,
++ &sensor_dev_attr_in8_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp3_input.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
++ &sensor_dev_attr_pwm1.dev_attr.attr,
++ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
++ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
++ &sensor_dev_attr_pwm2.dev_attr.attr,
++ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
++ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
++ &sensor_dev_attr_pwm3.dev_attr.attr,
++ &sensor_dev_attr_pwm3_mode.dev_attr.attr,
++ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_chassis.attr,
++ &dev_attr_chassis_clear.attr,
++ &sensor_dev_attr_tolerance1.dev_attr.attr,
++ &sensor_dev_attr_thermal_cruise1.dev_attr.attr,
++ &sensor_dev_attr_tolerance2.dev_attr.attr,
++ &sensor_dev_attr_thermal_cruise2.dev_attr.attr,
++ &sensor_dev_attr_tolerance3.dev_attr.attr,
++ &sensor_dev_attr_thermal_cruise3.dev_attr.attr,
++ &sensor_dev_attr_sf2_point1_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_point2_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_point3_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_point4_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_point1_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_point2_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_point3_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_point4_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_point1_fan3.dev_attr.attr,
++ &sensor_dev_attr_sf2_point2_fan3.dev_attr.attr,
++ &sensor_dev_attr_sf2_point3_fan3.dev_attr.attr,
++ &sensor_dev_attr_sf2_point4_fan3.dev_attr.attr,
++ &sensor_dev_attr_sf2_level1_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_level2_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_level3_fan1.dev_attr.attr,
++ &sensor_dev_attr_sf2_level1_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_level2_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_level3_fan2.dev_attr.attr,
++ &sensor_dev_attr_sf2_level1_fan3.dev_attr.attr,
++ &sensor_dev_attr_sf2_level2_fan3.dev_attr.attr,
++ &sensor_dev_attr_sf2_level3_fan3.dev_attr.attr,
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_min.dev_attr.attr,
++ &sensor_dev_attr_fan1_div.dev_attr.attr,
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_min.dev_attr.attr,
++ &sensor_dev_attr_fan2_div.dev_attr.attr,
++ &sensor_dev_attr_fan3_input.dev_attr.attr,
++ &sensor_dev_attr_fan3_min.dev_attr.attr,
++ &sensor_dev_attr_fan3_div.dev_attr.attr,
++ NULL
++};
++
++static const struct attribute_group w83792d_group = {
++ .attrs = w83792d_attributes,
++};
+
+ static int
+ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
+@@ -1268,59 +1368,46 @@ w83792d_detect(struct i2c_adapter *adapt
+ }
+
+ /* Register sysfs hooks */
+- data->class_dev = hwmon_device_register(dev);
+- if (IS_ERR(data->class_dev)) {
+- err = PTR_ERR(data->class_dev);
++ if ((err = sysfs_create_group(&dev->kobj, &w83792d_group)))
+ goto ERROR3;
+- }
+- for (i = 0; i < 9; i++) {
+- device_create_file(dev, &sda_in_input[i].dev_attr);
+- device_create_file(dev, &sda_in_max[i].dev_attr);
+- device_create_file(dev, &sda_in_min[i].dev_attr);
+- }
+- for (i = 0; i < 3; i++)
+- device_create_file_fan(dev, i);
+
+ /* Read GPIO enable register to check if pins for fan 4,5 are used as
+ GPIO */
+ val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN);
++
+ if (!(val1 & 0x40))
+- device_create_file_fan(dev, 3);
++ if ((err = sysfs_create_group(&dev->kobj,
++ &w83792d_group_fan[0])))
++ goto exit_remove_files;
++
+ if (!(val1 & 0x20))
+- device_create_file_fan(dev, 4);
++ if ((err = sysfs_create_group(&dev->kobj,
++ &w83792d_group_fan[1])))
++ goto exit_remove_files;
+
+ val1 = w83792d_read_value(client, W83792D_REG_PIN);
+ if (val1 & 0x40)
+- device_create_file_fan(dev, 5);
++ if ((err = sysfs_create_group(&dev->kobj,
++ &w83792d_group_fan[2])))
++ goto exit_remove_files;
++
+ if (val1 & 0x04)
+- device_create_file_fan(dev, 6);
+-
+- for (i = 0; i < 3; i++) {
+- device_create_file(dev, &sda_temp_input[i].dev_attr);
+- device_create_file(dev, &sda_temp_max[i].dev_attr);
+- device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
+- device_create_file(dev, &sda_thermal_cruise[i].dev_attr);
+- device_create_file(dev, &sda_tolerance[i].dev_attr);
+- }
++ if ((err = sysfs_create_group(&dev->kobj,
++ &w83792d_group_fan[3])))
++ goto exit_remove_files;
+
+- for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) {
+- device_create_file(dev, &sda_pwm[i].dev_attr);
+- device_create_file(dev, &sda_pwm_enable[i].dev_attr);
+- device_create_file(dev, &sda_pwm_mode[i].dev_attr);
++ data->class_dev = hwmon_device_register(dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_remove_files;
+ }
+
+- device_create_file(dev, &dev_attr_alarms);
+- device_create_file(dev, &dev_attr_chassis);
+- device_create_file(dev, &dev_attr_chassis_clear);
+-
+- for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++)
+- device_create_file(dev, &sda_sf2_point[i].dev_attr);
+-
+- for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++)
+- device_create_file(dev, &sda_sf2_level[i].dev_attr);
+-
+ return 0;
+
++exit_remove_files:
++ sysfs_remove_group(&dev->kobj, &w83792d_group);
++ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
++ sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
+ ERROR3:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+@@ -1342,11 +1429,16 @@ static int
+ w83792d_detach_client(struct i2c_client *client)
+ {
+ struct w83792d_data *data = i2c_get_clientdata(client);
+- int err;
++ int err, i;
+
+ /* main client */
+- if (data)
++ if (data) {
+ hwmon_device_unregister(data->class_dev);
++ sysfs_remove_group(&client->dev.kobj, &w83792d_group);
++ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
++ sysfs_remove_group(&client->dev.kobj,
++ &w83792d_group_fan[i]);
++ }
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
+index 3f2bac1..a3fcace 100644
+--- a/drivers/hwmon/w83l785ts.c
++++ b/drivers/hwmon/w83l785ts.c
+@@ -236,21 +236,30 @@ static int w83l785ts_detect(struct i2c_a
+ * Nothing yet, assume it is already started.
+ */
+
++ err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ if (err)
++ goto exit_remove;
++
++ err = device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp1_max.dev_attr);
++ if (err)
++ goto exit_remove;
++
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+- goto exit_detach;
++ goto exit_remove;
+ }
+
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp1_max.dev_attr);
+-
+ return 0;
+
+-exit_detach:
++exit_remove:
++ device_remove_file(&new_client->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ device_remove_file(&new_client->dev,
++ &sensor_dev_attr_temp1_max.dev_attr);
+ i2c_detach_client(new_client);
+ exit_free:
+ kfree(data);
+@@ -264,7 +273,10 @@ static int w83l785ts_detach_client(struc
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
+-
++ device_remove_file(&client->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ device_remove_file(&client->dev,
++ &sensor_dev_attr_temp1_max.dev_attr);
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
+index 24383af..11935f6 100644
+--- a/drivers/i2c/Kconfig
++++ b/drivers/i2c/Kconfig
+@@ -1,5 +1,5 @@
+ #
+-# Character device configuration
++# I2C subsystem configuration
+ #
+
+ menu "I2C support"
+diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
+index 3040801..c034820 100644
+--- a/drivers/i2c/algos/Kconfig
++++ b/drivers/i2c/algos/Kconfig
+@@ -53,12 +53,6 @@ config I2C_ALGO8XX
+ tristate "MPC8xx CPM I2C interface"
+ depends on 8xx && I2C
+
+-config I2C_ALGO_SIBYTE
+- tristate "SiByte SMBus interface"
+- depends on SIBYTE_SB1xxx_SOC && I2C
+- help
+- Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+-
+ config I2C_ALGO_SGI
+ tristate "I2C SGI interfaces"
+ depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
+diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
+index 867fe1f..208be04 100644
+--- a/drivers/i2c/algos/Makefile
++++ b/drivers/i2c/algos/Makefile
+@@ -6,7 +6,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bi
+ obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
+ obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
+ obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
+-obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o
+ obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
+
+ ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
+diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
+index ab230c0..21c36bf 100644
+--- a/drivers/i2c/algos/i2c-algo-bit.c
++++ b/drivers/i2c/algos/i2c-algo-bit.c
+@@ -76,17 +76,15 @@ static inline void scllo(struct i2c_algo
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+-static inline int sclhi(struct i2c_algo_bit_data *adap)
++static int sclhi(struct i2c_algo_bit_data *adap)
+ {
+ unsigned long start;
+
+ setscl(adap,1);
+
+ /* Not all adapters have scl sense line... */
+- if (adap->getscl == NULL ) {
+- udelay(adap->udelay);
+- return 0;
+- }
++ if (!adap->getscl)
++ goto done;
+
+ start=jiffies;
+ while (! getscl(adap) ) {
+@@ -101,6 +99,8 @@ static inline int sclhi(struct i2c_algo_
+ cond_resched();
+ }
+ DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
++
++done:
+ udelay(adap->udelay);
+ return 0;
+ }
+@@ -121,7 +121,6 @@ static void i2c_repstart(struct i2c_algo
+ DEBPROTO(printk(" Sr "));
+ setsda(adap,1);
+ sclhi(adap);
+- udelay(adap->udelay);
+
+ sdalo(adap);
+ scllo(adap);
+@@ -306,7 +305,7 @@ bailout:
+ * 0 chip did not answer
+ * -x transmission error
+ */
+-static inline int try_address(struct i2c_adapter *i2c_adap,
++static int try_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+ {
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+@@ -354,15 +353,11 @@ static int sendbytes(struct i2c_adapter
+ return (retval<0)? retval : -EFAULT;
+ /* got a better one ?? */
+ }
+-#if 0
+- /* from asm/delay.h */
+- __delay(adap->mdelay * (loops_per_sec / 1000) );
+-#endif
+ }
+ return wrcount;
+ }
+
+-static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
++static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ {
+ int inval;
+ int rdcount=0; /* counts bytes read */
+@@ -412,7 +407,7 @@ static inline int readbytes(struct i2c_a
+ * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
+ * -ETIMEDOUT, for example if the lines are stuck...)
+ */
+-static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
++static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ {
+ unsigned short flags = msg->flags;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+@@ -517,7 +512,7 @@ static u32 bit_func(struct i2c_adapter *
+
+ /* -----exported algorithm data: ------------------------------------- */
+
+-static struct i2c_algorithm i2c_bit_algo = {
++static const struct i2c_algorithm i2c_bit_algo = {
+ .master_xfer = bit_xfer,
+ .functionality = bit_func,
+ };
+diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
+index b88a6fc..9081c9f 100644
+--- a/drivers/i2c/algos/i2c-algo-pca.c
++++ b/drivers/i2c/algos/i2c-algo-pca.c
+@@ -355,7 +355,7 @@ static int pca_init(struct i2c_algo_pca_
+ return 0;
+ }
+
+-static struct i2c_algorithm pca_algo = {
++static const struct i2c_algorithm pca_algo = {
+ .master_xfer = pca_xfer,
+ .functionality = pca_func,
+ };
+diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
+index 5b24930..3b20033 100644
+--- a/drivers/i2c/algos/i2c-algo-pcf.c
++++ b/drivers/i2c/algos/i2c-algo-pcf.c
+@@ -458,7 +458,7 @@ static u32 pcf_func(struct i2c_adapter *
+
+ /* -----exported algorithm data: ------------------------------------- */
+
+-static struct i2c_algorithm pcf_algo = {
++static const struct i2c_algorithm pcf_algo = {
+ .master_xfer = pcf_xfer,
+ .functionality = pcf_func,
+ };
+diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
+index 932c4fa..490d999 100644
+--- a/drivers/i2c/algos/i2c-algo-sgi.c
++++ b/drivers/i2c/algos/i2c-algo-sgi.c
+@@ -157,7 +157,7 @@ static u32 sgi_func(struct i2c_adapter *
+ return I2C_FUNC_SMBUS_EMUL;
+ }
+
+-static struct i2c_algorithm sgi_algo = {
++static const struct i2c_algorithm sgi_algo = {
+ .master_xfer = sgi_xfer,
+ .functionality = sgi_func,
+ };
+diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
+deleted file mode 100644
+index 32d41c6..0000000
+--- a/drivers/i2c/algos/i2c-algo-sibyte.c
++++ /dev/null
+@@ -1,215 +0,0 @@
+-/* ------------------------------------------------------------------------- */
+-/* i2c-algo-sibyte.c i2c driver algorithms for bit-shift adapters */
+-/* ------------------------------------------------------------------------- */
+-/* Copyright (C) 2001,2002,2003 Broadcom Corporation
+- Copyright (C) 1995-2000 Simon G. Vogl
+-
+- 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. */
+-/* ------------------------------------------------------------------------- */
+-
+-/* With some changes from Kyösti Mälkki <kmalkki at cc.hut.fi> and even
+- Frodo Looijaard <frodol at dds.nl>. */
+-
+-/* Ported for SiByte SOCs by Broadcom Corporation. */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-
+-#include <asm/io.h>
+-#include <asm/sibyte/sb1250_regs.h>
+-#include <asm/sibyte/sb1250_smbus.h>
+-
+-#include <linux/i2c.h>
+-#include <linux/i2c-algo-sibyte.h>
+-
+-/* ----- global defines ----------------------------------------------- */
+-#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+-
+-/* ----- global variables --------------------------------------------- */
+-
+-/* module parameters:
+- */
+-static int bit_scan; /* have a look at what's hanging 'round */
+-
+-
+-static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+- unsigned short flags, char read_write,
+- u8 command, int size, union i2c_smbus_data * data)
+-{
+- struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+- int data_bytes = 0;
+- int error;
+-
+- while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+- ;
+-
+- switch (size) {
+- case I2C_SMBUS_QUICK:
+- csr_out32((V_SMB_ADDR(addr) | (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+- V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+- break;
+- case I2C_SMBUS_BYTE:
+- if (read_write == I2C_SMBUS_READ) {
+- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+- SMB_CSR(adap, R_SMB_START));
+- data_bytes = 1;
+- } else {
+- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+- SMB_CSR(adap, R_SMB_START));
+- }
+- break;
+- case I2C_SMBUS_BYTE_DATA:
+- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+- if (read_write == I2C_SMBUS_READ) {
+- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+- SMB_CSR(adap, R_SMB_START));
+- data_bytes = 1;
+- } else {
+- csr_out32(V_SMB_LB(data->byte), SMB_CSR(adap, R_SMB_DATA));
+- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+- SMB_CSR(adap, R_SMB_START));
+- }
+- break;
+- case I2C_SMBUS_WORD_DATA:
+- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+- if (read_write == I2C_SMBUS_READ) {
+- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+- SMB_CSR(adap, R_SMB_START));
+- data_bytes = 2;
+- } else {
+- csr_out32(V_SMB_LB(data->word & 0xff), SMB_CSR(adap, R_SMB_DATA));
+- csr_out32(V_SMB_MB(data->word >> 8), SMB_CSR(adap, R_SMB_DATA));
+- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+- SMB_CSR(adap, R_SMB_START));
+- }
+- break;
+- default:
+- return -1; /* XXXKW better error code? */
+- }
+-
+- while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+- ;
+-
+- error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+- if (error & M_SMB_ERROR) {
+- /* Clear error bit by writing a 1 */
+- csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+- return -1; /* XXXKW better error code? */
+- }
+-
+- if (data_bytes == 1)
+- data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+- if (data_bytes == 2)
+- data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+-
+- return 0;
+-}
+-
+-static int algo_control(struct i2c_adapter *adapter,
+- unsigned int cmd, unsigned long arg)
+-{
+- return 0;
+-}
+-
+-static u32 bit_func(struct i2c_adapter *adap)
+-{
+- return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+-}
+-
+-
+-/* -----exported algorithm data: ------------------------------------- */
+-
+-static struct i2c_algorithm i2c_sibyte_algo = {
+- .smbus_xfer = smbus_xfer,
+- .algo_control = algo_control, /* ioctl */
+- .functionality = bit_func,
+-};
+-
+-/*
+- * registering functions to load algorithms at runtime
+- */
+-int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+-{
+- int i;
+- struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+-
+- /* register new adapter to i2c module... */
+- i2c_adap->algo = &i2c_sibyte_algo;
+-
+- /* Set the frequency to 100 kHz */
+- csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+- csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+-
+- /* scan bus */
+- if (bit_scan) {
+- union i2c_smbus_data data;
+- int rc;
+- printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
+- i2c_adap->name);
+- for (i = 0x00; i < 0x7f; i++) {
+- /* XXXKW is this a realistic probe? */
+- rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
+- I2C_SMBUS_BYTE_DATA, &data);
+- if (!rc) {
+- printk("(%02x)",i);
+- } else
+- printk(".");
+- }
+- printk("\n");
+- }
+-
+- return i2c_add_adapter(i2c_adap);
+-}
+-
+-
+-int i2c_sibyte_del_bus(struct i2c_adapter *adap)
+-{
+- int res;
+-
+- if ((res = i2c_del_adapter(adap)) < 0)
+- return res;
+-
+- return 0;
+-}
+-
+-int __init i2c_algo_sibyte_init (void)
+-{
+- printk("i2c-algo-sibyte.o: i2c SiByte algorithm module\n");
+- return 0;
+-}
+-
+-
+-EXPORT_SYMBOL(i2c_sibyte_add_bus);
+-EXPORT_SYMBOL(i2c_sibyte_del_bus);
+-
+-#ifdef MODULE
+-MODULE_AUTHOR("Kip Walker, Broadcom Corp.");
+-MODULE_DESCRIPTION("SiByte I2C-Bus algorithm");
+-module_param(bit_scan, int, 0);
+-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+-MODULE_LICENSE("GPL");
+-
+-int init_module(void)
+-{
+- return i2c_algo_sibyte_init();
+-}
+-
+-void cleanup_module(void)
+-{
+-}
+-#endif
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 884320e..510816c 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -75,11 +75,11 @@ config I2C_AMD8111
+ will be called i2c-amd8111.
+
+ config I2C_AU1550
+- tristate "Au1550 SMBus interface"
+- depends on I2C && SOC_AU1550
++ tristate "Au1550/Au1200 SMBus interface"
++ depends on I2C && (SOC_AU1550 || SOC_AU1200)
+ help
+ If you say yes to this option, support will be included for the
+- Au1550 SMBus interface.
++ Au1550 and Au1200 SMBus interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-au1550.
+@@ -196,7 +196,7 @@ config I2C_IBM_IIC
+
+ config I2C_IOP3XX
+ tristate "Intel IOP3xx and IXP4xx on-chip I2C interface"
+- depends on (ARCH_IOP3XX || ARCH_IXP4XX) && I2C
++ depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX) && I2C
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Intel IOP3xx I/O Processors or IXP4xx Network Processors.
+@@ -287,6 +287,16 @@ config I2C_OCORES
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
++config I2C_OMAP
++ tristate "OMAP I2C adapter"
++ depends on I2C && ARCH_OMAP
++ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
++ help
++ If you say yes to this option, support will be included for the
++ I2C interface on the Texas Instruments OMAP1/2 family of processors.
++ Like OMAP1510/1610/1710/5912 and OMAP242x.
++ For details see http://www.ti.com/omap.
++
+ config I2C_PARPORT
+ tristate "Parallel port adapter"
+ depends on I2C && PARPORT
+@@ -323,10 +333,10 @@ config I2C_PARPORT_LIGHT
+
+ This driver is a light version of i2c-parport. It doesn't depend
+ on the parport driver, and uses direct I/O access instead. This
+- might be prefered on embedded systems where wasting memory for
++ might be preferred on embedded systems where wasting memory for
+ the clean but heavy parport handling is not an option. The
+ drawback is a reduced portability and the impossibility to
+- dasiy-chain other parallel port devices.
++ daisy-chain other parallel port devices.
+
+ Don't say Y here if you said Y or M to i2c-parport. Saying M to
+ both is possible but both modules should not be loaded at the same
+@@ -482,19 +492,19 @@ config I2C_VIA
+ will be called i2c-via.
+
+ config I2C_VIAPRO
+- tristate "VIA 82C596/82C686/823x"
++ tristate "VIA 82C596/82C686/82xx"
+ depends on I2C && PCI
+ help
+ If you say yes to this option, support will be included for the VIA
+- 82C596/82C686/823x I2C interfaces. Specifically, the following
++ 82C596/82C686/82xx I2C interfaces. Specifically, the following
+ chipsets are supported:
+- 82C596A/B
+- 82C686A/B
+- 8231
+- 8233
+- 8233A
+- 8235
+- 8237
++ VT82C596A/B
++ VT82C686A/B
++ VT8231
++ VT8233/A
++ VT8235
++ VT8237R/A
++ VT8251
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-viapro.
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index ac56df5..493c872 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -24,6 +24,7 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
+ obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+ obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+ obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
++obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
+ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
+ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
+diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
+index d3ef46a..e75d339 100644
+--- a/drivers/i2c/busses/i2c-ali1535.c
++++ b/drivers/i2c/busses/i2c-ali1535.c
+@@ -468,7 +468,7 @@ static u32 ali1535_func(struct i2c_adapt
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ali1535_access,
+ .functionality = ali1535_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
+index e6f6320..33fbb47 100644
+--- a/drivers/i2c/busses/i2c-ali1563.c
++++ b/drivers/i2c/busses/i2c-ali1563.c
+@@ -367,7 +367,7 @@ static void ali1563_shutdown(struct pci_
+ release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
+ }
+
+-static struct i2c_algorithm ali1563_algorithm = {
++static const struct i2c_algorithm ali1563_algorithm = {
+ .smbus_xfer = ali1563_access,
+ .functionality = ali1563_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
+index 7a5c094..3f11b6e 100644
+--- a/drivers/i2c/busses/i2c-ali15x3.c
++++ b/drivers/i2c/busses/i2c-ali15x3.c
+@@ -463,7 +463,7 @@ static u32 ali15x3_func(struct i2c_adapt
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ali15x3_access,
+ .functionality = ali15x3_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
+index 1750ded..2d21afd 100644
+--- a/drivers/i2c/busses/i2c-amd756.c
++++ b/drivers/i2c/busses/i2c-amd756.c
+@@ -294,7 +294,7 @@ static u32 amd756_func(struct i2c_adapte
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = amd756_access,
+ .functionality = amd756_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
+index e5ef560..0fbc718 100644
+--- a/drivers/i2c/busses/i2c-amd8111.c
++++ b/drivers/i2c/busses/i2c-amd8111.c
+@@ -316,7 +316,7 @@ static u32 amd8111_func(struct i2c_adapt
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = amd8111_access,
+ .functionality = amd8111_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
+index d06edce..d7e7c35 100644
+--- a/drivers/i2c/busses/i2c-au1550.c
++++ b/drivers/i2c/busses/i2c-au1550.c
+@@ -34,8 +34,7 @@
+ #include <linux/errno.h>
+ #include <linux/i2c.h>
+
+-#include <asm/mach-au1x00/au1000.h>
+-#include <asm/mach-pb1x00/pb1550.h>
++#include <asm/mach-au1x00/au1xxx.h>
+ #include <asm/mach-au1x00/au1xxx_psc.h>
+
+ #include "i2c-au1550.h"
+@@ -118,13 +117,19 @@ do_address(struct i2c_au1550_data *adap,
+
+ /* Reset the FIFOs, clear events.
+ */
+- sp->psc_smbpcr = PSC_SMBPCR_DC;
++ stat = sp->psc_smbstat;
+ sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
+ au_sync();
+- do {
+- stat = sp->psc_smbpcr;
++
++ if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
++ sp->psc_smbpcr = PSC_SMBPCR_DC;
+ au_sync();
+- } while ((stat & PSC_SMBPCR_DC) != 0);
++ do {
++ stat = sp->psc_smbpcr;
++ au_sync();
++ } while ((stat & PSC_SMBPCR_DC) != 0);
++ udelay(50);
++ }
+
+ /* Write out the i2c chip address and specify operation
+ */
+@@ -279,10 +284,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap
+ static u32
+ au1550_func(struct i2c_adapter *adap)
+ {
+- return I2C_FUNC_I2C;
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ }
+
+-static struct i2c_algorithm au1550_algo = {
++static const struct i2c_algorithm au1550_algo = {
+ .master_xfer = au1550_xfer,
+ .functionality = au1550_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
+index 59f8308..a591fe6 100644
+--- a/drivers/i2c/busses/i2c-elektor.c
++++ b/drivers/i2c/busses/i2c-elektor.c
+@@ -131,7 +131,7 @@ static void pcf_isa_waitforpin(void) {
+ }
+
+
+-static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
++static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
+ spin_lock(&lock);
+ pcf_pending = 1;
+ spin_unlock(&lock);
+@@ -196,7 +196,6 @@ static struct i2c_algo_pcf_data pcf_isa_
+ .getclock = pcf_isa_getclock,
+ .waitforpin = pcf_isa_waitforpin,
+ .udelay = 10,
+- .mdelay = 10,
+ .timeout = 100,
+ };
+
+diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
+index e0cb3b0..457d48a 100644
+--- a/drivers/i2c/busses/i2c-hydra.c
++++ b/drivers/i2c/busses/i2c-hydra.c
+@@ -99,7 +99,6 @@ static struct i2c_algo_bit_data hydra_bi
+ .getsda = hydra_bit_getsda,
+ .getscl = hydra_bit_getscl,
+ .udelay = 5,
+- .mdelay = 5,
+ .timeout = HZ
+ };
+
+diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
+index 7be1d0a..bbb2fbe 100644
+--- a/drivers/i2c/busses/i2c-i801.c
++++ b/drivers/i2c/busses/i2c-i801.c
+@@ -434,7 +434,7 @@ static u32 i801_func(struct i2c_adapter
+ | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = i801_access,
+ .functionality = i801_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
+index 748be30..b66fb6b 100644
+--- a/drivers/i2c/busses/i2c-i810.c
++++ b/drivers/i2c/busses/i2c-i810.c
+@@ -166,7 +166,6 @@ static struct i2c_algo_bit_data i810_i2c
+ .getsda = bit_i810i2c_getsda,
+ .getscl = bit_i810i2c_getscl,
+ .udelay = CYCLE_DELAY,
+- .mdelay = CYCLE_DELAY,
+ .timeout = TIMEOUT,
+ };
+
+@@ -182,7 +181,6 @@ static struct i2c_algo_bit_data i810_ddc
+ .getsda = bit_i810ddc_getsda,
+ .getscl = bit_i810ddc_getscl,
+ .udelay = CYCLE_DELAY,
+- .mdelay = CYCLE_DELAY,
+ .timeout = TIMEOUT,
+ };
+
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
+index 0599bbd..781a99c 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.c
++++ b/drivers/i2c/busses/i2c-ibm_iic.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/i2c/i2c-ibm_iic.c
++ * drivers/i2c/busses/i2c-ibm_iic.c
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+@@ -320,7 +320,7 @@ err:
+ /*
+ * IIC interrupt handler
+ */
+-static irqreturn_t iic_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t iic_handler(int irq, void *dev_id)
+ {
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+@@ -625,7 +625,7 @@ static u32 iic_func(struct i2c_adapter *
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+ }
+
+-static struct i2c_algorithm iic_algo = {
++static const struct i2c_algorithm iic_algo = {
+ .master_xfer = iic_xfer,
+ .functionality = iic_func
+ };
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
+index 2b3219d..59d7b43 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.h
++++ b/drivers/i2c/busses/i2c-ibm_iic.h
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/i2c/i2c-ibm_iic.h
++ * drivers/i2c/busses/i2c-ibm_iic.h
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
+index 48c5693..d108ab4 100644
+--- a/drivers/i2c/busses/i2c-iop3xx.c
++++ b/drivers/i2c/busses/i2c-iop3xx.c
+@@ -82,14 +82,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx
+
+ /*
+ * Every time unit enable is asserted, GPOD needs to be cleared
+- * on IOP321 to avoid data corruption on the bus.
++ * on IOP3XX to avoid data corruption on the bus.
+ */
+-#ifdef CONFIG_ARCH_IOP321
+-#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
+-#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
+-
+- *IOP321_GPOD &= (iop3xx_adap->id == 0) ? ~IOP321_GPOD_I2C0 :
+- ~IOP321_GPOD_I2C1;
++#ifdef CONFIG_PLAT_IOP
++ if (iop3xx_adap->id == 0) {
++ gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
++ gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
++ } else {
++ gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
++ gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
++ }
+ #endif
+ /* NB SR bits not same position as CR IE bits :-( */
+ iop3xx_adap->SR_enabled =
+@@ -118,7 +120,7 @@ iop3xx_i2c_transaction_cleanup(struct i2
+ * Then it passes the SR flags of interest to BH via adap data
+ */
+ static irqreturn_t
+-iop3xx_i2c_irq_handler(int this_irq, void *dev_id, struct pt_regs *regs)
++iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
+ {
+ struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
+ u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
+@@ -401,7 +403,7 @@ iop3xx_i2c_func(struct i2c_adapter *adap
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ }
+
+-static struct i2c_algorithm iop3xx_i2c_algo = {
++static const struct i2c_algorithm iop3xx_i2c_algo = {
+ .master_xfer = iop3xx_i2c_master_xfer,
+ .algo_control = iop3xx_i2c_algo_control,
+ .functionality = iop3xx_i2c_func,
+diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
+index c3e1d3e..8ed59a2 100644
+--- a/drivers/i2c/busses/i2c-isa.c
++++ b/drivers/i2c/busses/i2c-isa.c
+@@ -43,7 +43,7 @@
+ static u32 isa_func(struct i2c_adapter *adapter);
+
+ /* This is the actual algorithm we define */
+-static struct i2c_algorithm isa_algorithm = {
++static const struct i2c_algorithm isa_algorithm = {
+ .functionality = isa_func,
+ };
+
+@@ -89,9 +89,14 @@ int i2c_isa_add_driver(struct i2c_driver
+ dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
+
+ /* Now look for clients */
+- driver->attach_adapter(&isa_adapter);
+-
+- return 0;
++ res = driver->attach_adapter(&isa_adapter);
++ if (res) {
++ dev_dbg(&isa_adapter.dev,
++ "Driver %s failed to attach adapter, unregistering\n",
++ driver->driver.name);
++ driver_unregister(&driver->driver);
++ }
++ return res;
+ }
+
+ int i2c_isa_del_driver(struct i2c_driver *driver)
+@@ -125,6 +130,8 @@ int i2c_isa_del_driver(struct i2c_driver
+
+ static int __init i2c_isa_init(void)
+ {
++ int err;
++
+ mutex_init(&isa_adapter.clist_lock);
+ INIT_LIST_HEAD(&isa_adapter.clients);
+
+@@ -133,8 +140,16 @@ static int __init i2c_isa_init(void)
+ sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
+ isa_adapter.dev.driver = &i2c_adapter_driver;
+ isa_adapter.dev.release = &i2c_adapter_dev_release;
+- device_register(&isa_adapter.dev);
+- device_create_file(&isa_adapter.dev, &dev_attr_name);
++ err = device_register(&isa_adapter.dev);
++ if (err) {
++ printk(KERN_ERR "i2c-isa: Failed to register device\n");
++ goto exit;
++ }
++ err = device_create_file(&isa_adapter.dev, &dev_attr_name);
++ if (err) {
++ printk(KERN_ERR "i2c-isa: Failed to create name file\n");
++ goto exit_unregister;
++ }
+
+ /* Add this adapter to the i2c_adapter class */
+ memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
+@@ -142,11 +157,24 @@ static int __init i2c_isa_init(void)
+ isa_adapter.class_dev.class = &i2c_adapter_class;
+ strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
+ BUS_ID_SIZE);
+- class_device_register(&isa_adapter.class_dev);
++ err = class_device_register(&isa_adapter.class_dev);
++ if (err) {
++ printk(KERN_ERR "i2c-isa: Failed to register class device\n");
++ goto exit_remove_name;
++ }
+
+ dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
+
+ return 0;
++
++exit_remove_name:
++ device_remove_file(&isa_adapter.dev, &dev_attr_name);
++exit_unregister:
++ init_completion(&isa_adapter.dev_released); /* Needed? */
++ device_unregister(&isa_adapter.dev);
++ wait_for_completion(&isa_adapter.dev_released);
++exit:
++ return err;
+ }
+
+ static void __exit i2c_isa_exit(void)
+diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
+index d82e6da..f7d7186 100644
+--- a/drivers/i2c/busses/i2c-ite.c
++++ b/drivers/i2c/busses/i2c-ite.c
+@@ -109,7 +109,7 @@ static int iic_ite_getclock(void *data)
+ static void iic_ite_waitforpin(void) {
+ DEFINE_WAIT(wait);
+ int timeout = 2;
+- long flags;
++ unsigned long flags;
+
+ /* If interrupts are enabled (which they are), then put the process to
+ * sleep. This process will be awakened by two events -- either the
+@@ -140,8 +140,7 @@ static void iic_ite_waitforpin(void) {
+ }
+
+
+-static irqreturn_t iic_ite_handler(int this_irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t iic_ite_handler(int this_irq, void *dev_id)
+ {
+ spin_lock(&lock);
+ iic_pending = 1;
+diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
+index cd6f45d..dd3f4cd 100644
+--- a/drivers/i2c/busses/i2c-ixp2000.c
++++ b/drivers/i2c/busses/i2c-ixp2000.c
+@@ -114,7 +114,6 @@ static int ixp2000_i2c_probe(struct plat
+ drv_data->algo_data.getsda = ixp2000_bit_getsda;
+ drv_data->algo_data.getscl = ixp2000_bit_getscl;
+ drv_data->algo_data.udelay = 6;
+- drv_data->algo_data.mdelay = 6;
+ drv_data->algo_data.timeout = 100;
+
+ drv_data->adapter.id = I2C_HW_B_IXP2000,
+diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
+index 2ed0711..1ce01fb 100644
+--- a/drivers/i2c/busses/i2c-ixp4xx.c
++++ b/drivers/i2c/busses/i2c-ixp4xx.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/i2c/i2c-adap-ixp4xx.c
++ * drivers/i2c/busses/i2c-ixp4xx.c
+ *
+ * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
+ * an on board I2C controller but provide 16 GPIO pins that are often
+@@ -122,7 +122,6 @@ static int ixp4xx_i2c_probe(struct platf
+ drv_data->algo_data.getsda = ixp4xx_bit_getsda;
+ drv_data->algo_data.getscl = ixp4xx_bit_getscl;
+ drv_data->algo_data.udelay = 10;
+- drv_data->algo_data.mdelay = 10;
+ drv_data->algo_data.timeout = 100;
+
+ drv_data->adapter.id = I2C_HW_B_IXP4XX;
+diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
+index 377ab40..ee65aa1 100644
+--- a/drivers/i2c/busses/i2c-mpc.c
++++ b/drivers/i2c/busses/i2c-mpc.c
+@@ -63,7 +63,7 @@ static __inline__ void writeccr(struct m
+ writeb(x, i2c->base + MPC_I2C_CR);
+ }
+
+-static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+ {
+ struct mpc_i2c *i2c = dev_id;
+ if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+@@ -272,7 +272,7 @@ static u32 mpc_functionality(struct i2c_
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ }
+
+-static struct i2c_algorithm mpc_algo = {
++static const struct i2c_algorithm mpc_algo = {
+ .master_xfer = mpc_xfer,
+ .functionality = mpc_functionality,
+ };
+diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
+index ac5cde1..bbc8e3a 100644
+--- a/drivers/i2c/busses/i2c-mv64xxx.c
++++ b/drivers/i2c/busses/i2c-mv64xxx.c
+@@ -278,7 +278,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c
+ }
+
+ static int
+-mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs)
++mv64xxx_i2c_intr(int irq, void *dev_id)
+ {
+ struct mv64xxx_i2c_data *drv_data = dev_id;
+ unsigned long flags;
+@@ -431,7 +431,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *ada
+ return num;
+ }
+
+-static struct i2c_algorithm mv64xxx_i2c_algo = {
++static const struct i2c_algorithm mv64xxx_i2c_algo = {
+ .master_xfer = mv64xxx_i2c_xfer,
+ .functionality = mv64xxx_i2c_functionality,
+ };
+diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
+index 604b49e..e0292e4 100644
+--- a/drivers/i2c/busses/i2c-nforce2.c
++++ b/drivers/i2c/busses/i2c-nforce2.c
+@@ -109,7 +109,7 @@ static s32 nforce2_access(struct i2c_ada
+ static u32 nforce2_func(struct i2c_adapter *adapter);
+
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = nforce2_access,
+ .functionality = nforce2_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
+index 5928240..f28a76d 100644
+--- a/drivers/i2c/busses/i2c-ocores.c
++++ b/drivers/i2c/busses/i2c-ocores.c
+@@ -9,7 +9,6 @@
+ * kind, whether express or implied.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+@@ -144,7 +143,7 @@ static void ocores_process(struct ocores
+ }
+ }
+
+-static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ocores_isr(int irq, void *dev_id)
+ {
+ struct ocores_i2c *i2c = dev_id;
+
+@@ -199,7 +198,7 @@ static u32 ocores_func(struct i2c_adapte
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ }
+
+-static struct i2c_algorithm ocores_algorithm = {
++static const struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
+new file mode 100644
+index 0000000..dec04da
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-omap.c
+@@ -0,0 +1,676 @@
++/*
++ * TI OMAP I2C master mode driver
++ *
++ * Copyright (C) 2003 MontaVista Software, Inc.
++ * Copyright (C) 2004 Texas Instruments.
++ *
++ * Updated to work with multiple I2C interfaces on 24xx by
++ * Tony Lindgren <tony at atomide.com> and Imre Deak <imre.deak at nokia.com>
++ * Copyright (C) 2005 Nokia Corporation
++ *
++ * Cleaned up by Juha Yrjölä <juha.yrjola at nokia.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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++
++#include <asm/io.h>
++
++/* timeout waiting for the controller to respond */
++#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
++
++#define OMAP_I2C_REV_REG 0x00
++#define OMAP_I2C_IE_REG 0x04
++#define OMAP_I2C_STAT_REG 0x08
++#define OMAP_I2C_IV_REG 0x0c
++#define OMAP_I2C_SYSS_REG 0x10
++#define OMAP_I2C_BUF_REG 0x14
++#define OMAP_I2C_CNT_REG 0x18
++#define OMAP_I2C_DATA_REG 0x1c
++#define OMAP_I2C_SYSC_REG 0x20
++#define OMAP_I2C_CON_REG 0x24
++#define OMAP_I2C_OA_REG 0x28
++#define OMAP_I2C_SA_REG 0x2c
++#define OMAP_I2C_PSC_REG 0x30
++#define OMAP_I2C_SCLL_REG 0x34
++#define OMAP_I2C_SCLH_REG 0x38
++#define OMAP_I2C_SYSTEST_REG 0x3c
++
++/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
++#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
++#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
++#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
++#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
++#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
++
++/* I2C Status Register (OMAP_I2C_STAT): */
++#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
++#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
++#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
++#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
++#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
++#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
++#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
++#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
++#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
++#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
++#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
++
++/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
++#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
++#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
++
++/* I2C Configuration Register (OMAP_I2C_CON): */
++#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
++#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
++#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
++#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
++#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
++#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
++#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
++#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
++#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
++
++/* I2C System Test Register (OMAP_I2C_SYSTEST): */
++#ifdef DEBUG
++#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
++#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
++#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
++#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
++#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
++#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
++#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
++#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
++#endif
++
++/* I2C System Status register (OMAP_I2C_SYSS): */
++#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
++
++/* I2C System Configuration Register (OMAP_I2C_SYSC): */
++#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
++
++/* REVISIT: Use platform_data instead of module parameters */
++/* Fast Mode = 400 kHz, Standard = 100 kHz */
++static int clock = 100; /* Default: 100 kHz */
++module_param(clock, int, 0);
++MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
++
++struct omap_i2c_dev {
++ struct device *dev;
++ void __iomem *base; /* virtual */
++ int irq;
++ struct clk *iclk; /* Interface clock */
++ struct clk *fclk; /* Functional clock */
++ struct completion cmd_complete;
++ struct resource *ioarea;
++ u16 cmd_err;
++ u8 *buf;
++ size_t buf_len;
++ struct i2c_adapter adapter;
++ unsigned rev1:1;
++};
++
++static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
++ int reg, u16 val)
++{
++ __raw_writew(val, i2c_dev->base + reg);
++}
++
++static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
++{
++ return __raw_readw(i2c_dev->base + reg);
++}
++
++static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
++{
++ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
++ dev->iclk = clk_get(dev->dev, "i2c_ick");
++ if (IS_ERR(dev->iclk)) {
++ dev->iclk = NULL;
++ return -ENODEV;
++ }
++ }
++
++ dev->fclk = clk_get(dev->dev, "i2c_fck");
++ if (IS_ERR(dev->fclk)) {
++ if (dev->iclk != NULL) {
++ clk_put(dev->iclk);
++ dev->iclk = NULL;
++ }
++ dev->fclk = NULL;
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
++{
++ clk_put(dev->fclk);
++ dev->fclk = NULL;
++ if (dev->iclk != NULL) {
++ clk_put(dev->iclk);
++ dev->iclk = NULL;
++ }
++}
++
++static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
++{
++ if (dev->iclk != NULL)
++ clk_enable(dev->iclk);
++ clk_enable(dev->fclk);
++}
++
++static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
++{
++ if (dev->iclk != NULL)
++ clk_disable(dev->iclk);
++ clk_disable(dev->fclk);
++}
++
++static int omap_i2c_init(struct omap_i2c_dev *dev)
++{
++ u16 psc = 0;
++ unsigned long fclk_rate = 12000000;
++ unsigned long timeout;
++
++ if (!dev->rev1) {
++ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
++ /* For some reason we need to set the EN bit before the
++ * reset done bit gets set. */
++ timeout = jiffies + OMAP_I2C_TIMEOUT;
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
++ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
++ OMAP_I2C_SYSS_RDONE)) {
++ if (time_after(jiffies, timeout)) {
++ dev_warn(dev->dev, "timeout waiting"
++ "for controller reset\n");
++ return -ETIMEDOUT;
++ }
++ msleep(1);
++ }
++ }
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
++
++ if (cpu_class_is_omap1()) {
++ struct clk *armxor_ck;
++
++ armxor_ck = clk_get(NULL, "armxor_ck");
++ if (IS_ERR(armxor_ck))
++ dev_warn(dev->dev, "Could not get armxor_ck\n");
++ else {
++ fclk_rate = clk_get_rate(armxor_ck);
++ clk_put(armxor_ck);
++ }
++ /* TRM for 5912 says the I2C clock must be prescaled to be
++ * between 7 - 12 MHz. The XOR input clock is typically
++ * 12, 13 or 19.2 MHz. So we should have code that produces:
++ *
++ * XOR MHz Divider Prescaler
++ * 12 1 0
++ * 13 2 1
++ * 19.2 2 1
++ */
++ if (fclk_rate > 16000000)
++ psc = (fclk_rate + 8000000) / 12000000;
++ }
++
++ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
++ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
++
++ /* Program desired operating rate */
++ fclk_rate /= (psc + 1) * 1000;
++ if (psc > 2)
++ psc = 2;
++
++ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
++ fclk_rate / (clock * 2) - 7 + psc);
++ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
++ fclk_rate / (clock * 2) - 7 + psc);
++
++ /* Take the I2C module out of reset: */
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
++
++ /* Enable interrupts */
++ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
++ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
++ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
++ OMAP_I2C_IE_AL));
++ return 0;
++}
++
++/*
++ * Waiting on Bus Busy
++ */
++static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
++{
++ unsigned long timeout;
++
++ timeout = jiffies + OMAP_I2C_TIMEOUT;
++ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
++ if (time_after(jiffies, timeout)) {
++ dev_warn(dev->dev, "timeout waiting for bus ready\n");
++ return -ETIMEDOUT;
++ }
++ msleep(1);
++ }
++
++ return 0;
++}
++
++/*
++ * Low level master read/write transaction.
++ */
++static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
++ struct i2c_msg *msg, int stop)
++{
++ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
++ int r;
++ u16 w;
++
++ dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
++ msg->addr, msg->len, msg->flags, stop);
++
++ if (msg->len == 0)
++ return -EINVAL;
++
++ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
++
++ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
++ dev->buf = msg->buf;
++ dev->buf_len = msg->len;
++
++ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
++
++ init_completion(&dev->cmd_complete);
++ dev->cmd_err = 0;
++
++ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
++ if (msg->flags & I2C_M_TEN)
++ w |= OMAP_I2C_CON_XA;
++ if (!(msg->flags & I2C_M_RD))
++ w |= OMAP_I2C_CON_TRX;
++ if (stop)
++ w |= OMAP_I2C_CON_STP;
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
++
++ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
++ OMAP_I2C_TIMEOUT);
++ dev->buf_len = 0;
++ if (r < 0)
++ return r;
++ if (r == 0) {
++ dev_err(dev->dev, "controller timed out\n");
++ omap_i2c_init(dev);
++ return -ETIMEDOUT;
++ }
++
++ if (likely(!dev->cmd_err))
++ return 0;
++
++ /* We have an error */
++ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
++ OMAP_I2C_STAT_XUDF)) {
++ omap_i2c_init(dev);
++ return -EIO;
++ }
++
++ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
++ if (msg->flags & I2C_M_IGNORE_NAK)
++ return 0;
++ if (stop) {
++ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
++ w |= OMAP_I2C_CON_STP;
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
++ }
++ return -EREMOTEIO;
++ }
++ return -EIO;
++}
++
++
++/*
++ * Prepare controller for a transaction and call omap_i2c_xfer_msg
++ * to do the work during IRQ processing.
++ */
++static int
++omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
++{
++ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
++ int i;
++ int r;
++
++ omap_i2c_enable_clocks(dev);
++
++ /* REVISIT: initialize and use adap->retries. This is an optional
++ * feature */
++ if ((r = omap_i2c_wait_for_bb(dev)) < 0)
++ goto out;
++
++ for (i = 0; i < num; i++) {
++ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
++ if (r != 0)
++ break;
++ }
++
++ if (r == 0)
++ r = num;
++out:
++ omap_i2c_disable_clocks(dev);
++ return r;
++}
++
++static u32
++omap_i2c_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
++}
++
++static inline void
++omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
++{
++ dev->cmd_err |= err;
++ complete(&dev->cmd_complete);
++}
++
++static inline void
++omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
++{
++ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
++}
++
++static irqreturn_t
++omap_i2c_rev1_isr(int this_irq, void *dev_id)
++{
++ struct omap_i2c_dev *dev = dev_id;
++ u16 iv, w;
++
++ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
++ switch (iv) {
++ case 0x00: /* None */
++ break;
++ case 0x01: /* Arbitration lost */
++ dev_err(dev->dev, "Arbitration lost\n");
++ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
++ break;
++ case 0x02: /* No acknowledgement */
++ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
++ break;
++ case 0x03: /* Register access ready */
++ omap_i2c_complete_cmd(dev, 0);
++ break;
++ case 0x04: /* Receive data ready */
++ if (dev->buf_len) {
++ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
++ *dev->buf++ = w;
++ dev->buf_len--;
++ if (dev->buf_len) {
++ *dev->buf++ = w >> 8;
++ dev->buf_len--;
++ }
++ } else
++ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
++ break;
++ case 0x05: /* Transmit data ready */
++ if (dev->buf_len) {
++ w = *dev->buf++;
++ dev->buf_len--;
++ if (dev->buf_len) {
++ w |= *dev->buf++ << 8;
++ dev->buf_len--;
++ }
++ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
++ } else
++ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
++ break;
++ default:
++ return IRQ_NONE;
++ }
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t
++omap_i2c_isr(int this_irq, void *dev_id)
++{
++ struct omap_i2c_dev *dev = dev_id;
++ u16 bits;
++ u16 stat, w;
++ int count = 0;
++
++ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
++ while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
++ dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
++ if (count++ == 100) {
++ dev_warn(dev->dev, "Too much work in one IRQ\n");
++ break;
++ }
++
++ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
++
++ if (stat & OMAP_I2C_STAT_ARDY) {
++ omap_i2c_complete_cmd(dev, 0);
++ continue;
++ }
++ if (stat & OMAP_I2C_STAT_RRDY) {
++ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
++ if (dev->buf_len) {
++ *dev->buf++ = w;
++ dev->buf_len--;
++ if (dev->buf_len) {
++ *dev->buf++ = w >> 8;
++ dev->buf_len--;
++ }
++ } else
++ dev_err(dev->dev, "RRDY IRQ while no data"
++ "requested\n");
++ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
++ continue;
++ }
++ if (stat & OMAP_I2C_STAT_XRDY) {
++ w = 0;
++ if (dev->buf_len) {
++ w = *dev->buf++;
++ dev->buf_len--;
++ if (dev->buf_len) {
++ w |= *dev->buf++ << 8;
++ dev->buf_len--;
++ }
++ } else
++ dev_err(dev->dev, "XRDY IRQ while no"
++ "data to send\n");
++ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
++ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
++ continue;
++ }
++ if (stat & OMAP_I2C_STAT_ROVR) {
++ dev_err(dev->dev, "Receive overrun\n");
++ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
++ }
++ if (stat & OMAP_I2C_STAT_XUDF) {
++ dev_err(dev->dev, "Transmit overflow\n");
++ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
++ }
++ if (stat & OMAP_I2C_STAT_NACK) {
++ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
++ OMAP_I2C_CON_STP);
++ }
++ if (stat & OMAP_I2C_STAT_AL) {
++ dev_err(dev->dev, "Arbitration lost\n");
++ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
++ }
++ }
++
++ return count ? IRQ_HANDLED : IRQ_NONE;
++}
++
++static const struct i2c_algorithm omap_i2c_algo = {
++ .master_xfer = omap_i2c_xfer,
++ .functionality = omap_i2c_func,
++};
++
++static int
++omap_i2c_probe(struct platform_device *pdev)
++{
++ struct omap_i2c_dev *dev;
++ struct i2c_adapter *adap;
++ struct resource *mem, *irq, *ioarea;
++ int r;
++
++ /* NOTE: driver uses the static register mapping */
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem) {
++ dev_err(&pdev->dev, "no mem resource?\n");
++ return -ENODEV;
++ }
++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!irq) {
++ dev_err(&pdev->dev, "no irq resource?\n");
++ return -ENODEV;
++ }
++
++ ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
++ pdev->name);
++ if (!ioarea) {
++ dev_err(&pdev->dev, "I2C region already claimed\n");
++ return -EBUSY;
++ }
++
++ if (clock > 200)
++ clock = 400; /* Fast mode */
++ else
++ clock = 100; /* Standard mode */
++
++ dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
++ if (!dev) {
++ r = -ENOMEM;
++ goto err_release_region;
++ }
++
++ dev->dev = &pdev->dev;
++ dev->irq = irq->start;
++ dev->base = (void __iomem *) IO_ADDRESS(mem->start);
++ platform_set_drvdata(pdev, dev);
++
++ if ((r = omap_i2c_get_clocks(dev)) != 0)
++ goto err_free_mem;
++
++ omap_i2c_enable_clocks(dev);
++
++ if (cpu_is_omap15xx())
++ dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
++
++ /* reset ASAP, clearing any IRQs */
++ omap_i2c_init(dev);
++
++ r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
++ 0, pdev->name, dev);
++
++ if (r) {
++ dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
++ goto err_unuse_clocks;
++ }
++ r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
++ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
++ pdev->id, r >> 4, r & 0xf, clock);
++
++ adap = &dev->adapter;
++ i2c_set_adapdata(adap, dev);
++ adap->owner = THIS_MODULE;
++ adap->class = I2C_CLASS_HWMON;
++ strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
++ adap->algo = &omap_i2c_algo;
++ adap->dev.parent = &pdev->dev;
++
++ /* i2c device drivers may be active on return from add_adapter() */
++ r = i2c_add_adapter(adap);
++ if (r) {
++ dev_err(dev->dev, "failure adding adapter\n");
++ goto err_free_irq;
++ }
++
++ omap_i2c_disable_clocks(dev);
++
++ return 0;
++
++err_free_irq:
++ free_irq(dev->irq, dev);
++err_unuse_clocks:
++ omap_i2c_disable_clocks(dev);
++ omap_i2c_put_clocks(dev);
++err_free_mem:
++ platform_set_drvdata(pdev, NULL);
++ kfree(dev);
++err_release_region:
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
++ release_mem_region(mem->start, (mem->end - mem->start) + 1);
++
++ return r;
++}
++
++static int
++omap_i2c_remove(struct platform_device *pdev)
++{
++ struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
++ struct resource *mem;
++
++ platform_set_drvdata(pdev, NULL);
++
++ free_irq(dev->irq, dev);
++ i2c_del_adapter(&dev->adapter);
++ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
++ omap_i2c_put_clocks(dev);
++ kfree(dev);
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(mem->start, (mem->end - mem->start) + 1);
++ return 0;
++}
++
++static struct platform_driver omap_i2c_driver = {
++ .probe = omap_i2c_probe,
++ .remove = omap_i2c_remove,
++ .driver = {
++ .name = "i2c_omap",
++ .owner = THIS_MODULE,
++ },
++};
++
++/* I2C may be needed to bring up other drivers */
++static int __init
++omap_i2c_init_driver(void)
++{
++ return platform_driver_register(&omap_i2c_driver);
++}
++subsys_initcall(omap_i2c_init_driver);
++
++static void __exit omap_i2c_exit_driver(void)
++{
++ platform_driver_unregister(&omap_i2c_driver);
++}
++module_exit(omap_i2c_exit_driver);
++
++MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
++MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
+index e09ebbb..5eb2bd2 100644
+--- a/drivers/i2c/busses/i2c-parport-light.c
++++ b/drivers/i2c/busses/i2c-parport-light.c
+@@ -103,7 +103,6 @@ static struct i2c_algo_bit_data parport_
+ .getsda = parport_getsda,
+ .getscl = parport_getscl,
+ .udelay = 50,
+- .mdelay = 50,
+ .timeout = HZ,
+ };
+
+diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
+index 934bd55..48a8294 100644
+--- a/drivers/i2c/busses/i2c-parport.c
++++ b/drivers/i2c/busses/i2c-parport.c
+@@ -138,7 +138,6 @@ static struct i2c_algo_bit_data parport_
+ .getsda = parport_getsda,
+ .getscl = parport_getscl,
+ .udelay = 60,
+- .mdelay = 60,
+ .timeout = HZ,
+ };
+
+diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
+index d9b4ddb..407840b 100644
+--- a/drivers/i2c/busses/i2c-pca-isa.c
++++ b/drivers/i2c/busses/i2c-pca-isa.c
+@@ -99,7 +99,7 @@ static int pca_isa_waitforinterrupt(stru
+ return ret;
+ }
+
+-static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
++static irqreturn_t pca_handler(int this_irq, void *dev_id) {
+ wake_up_interruptible(&pca_wait);
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
+index 8f2f65b..30c7a1b 100644
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -376,7 +376,7 @@ static u32 piix4_func(struct i2c_adapter
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = piix4_access,
+ .functionality = piix4_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
+index 53bb435..648d555 100644
+--- a/drivers/i2c/busses/i2c-powermac.c
++++ b/drivers/i2c/busses/i2c-powermac.c
+@@ -175,16 +175,16 @@ static u32 i2c_powermac_func(struct i2c_
+ }
+
+ /* For now, we only handle smbus */
+-static struct i2c_algorithm i2c_powermac_algorithm = {
++static const struct i2c_algorithm i2c_powermac_algorithm = {
+ .smbus_xfer = i2c_powermac_smbus_xfer,
+ .master_xfer = i2c_powermac_master_xfer,
+ .functionality = i2c_powermac_func,
+ };
+
+
+-static int i2c_powermac_remove(struct device *dev)
++static int i2c_powermac_remove(struct platform_device *dev)
+ {
+- struct i2c_adapter *adapter = dev_get_drvdata(dev);
++ struct i2c_adapter *adapter = platform_get_drvdata(dev);
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
+ int rc;
+
+@@ -195,19 +195,20 @@ static int i2c_powermac_remove(struct de
+ if (rc)
+ printk("i2c-powermac.c: Failed to remove bus %s !\n",
+ adapter->name);
+- dev_set_drvdata(dev, NULL);
++ platform_set_drvdata(dev, NULL);
+ kfree(adapter);
+
+ return 0;
+ }
+
+
+-static int i2c_powermac_probe(struct device *dev)
++static int __devexit i2c_powermac_probe(struct platform_device *dev)
+ {
+- struct pmac_i2c_bus *bus = dev->platform_data;
++ struct pmac_i2c_bus *bus = dev->dev.platform_data;
+ struct device_node *parent = NULL;
+ struct i2c_adapter *adapter;
+- char name[32], *basename;
++ char name[32];
++ const char *basename;
+ int rc;
+
+ if (bus == NULL)
+@@ -245,11 +246,11 @@ static int i2c_powermac_probe(struct dev
+ printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
+ return -ENOMEM;
+ }
+- dev_set_drvdata(dev, adapter);
++ platform_set_drvdata(dev, adapter);
+ strcpy(adapter->name, name);
+ adapter->algo = &i2c_powermac_algorithm;
+ i2c_set_adapdata(adapter, bus);
+- adapter->dev.parent = dev;
++ adapter->dev.parent = &dev->dev;
+ pmac_i2c_attach_adapter(bus, adapter);
+ rc = i2c_add_adapter(adapter);
+ if (rc) {
+@@ -264,23 +265,25 @@ static int i2c_powermac_probe(struct dev
+ }
+
+
+-static struct device_driver i2c_powermac_driver = {
+- .name = "i2c-powermac",
+- .bus = &platform_bus_type,
++static struct platform_driver i2c_powermac_driver = {
+ .probe = i2c_powermac_probe,
+- .remove = i2c_powermac_remove,
++ .remove = __devexit_p(i2c_powermac_remove),
++ .driver = {
++ .name = "i2c-powermac",
++ .bus = &platform_bus_type,
++ },
+ };
+
+ static int __init i2c_powermac_init(void)
+ {
+- driver_register(&i2c_powermac_driver);
++ platform_driver_register(&i2c_powermac_driver);
+ return 0;
+ }
+
+
+ static void __exit i2c_powermac_cleanup(void)
+ {
+- driver_unregister(&i2c_powermac_driver);
++ platform_driver_unregister(&i2c_powermac_driver);
+ }
+
+ module_init(i2c_powermac_init);
+diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
+index 9479525..7745e21 100644
+--- a/drivers/i2c/busses/i2c-prosavage.c
++++ b/drivers/i2c/busses/i2c-prosavage.c
+@@ -180,7 +180,6 @@ static int i2c_register_bus(struct pci_d
+ p->algo.getsda = bit_s3via_getsda;
+ p->algo.getscl = bit_s3via_getscl;
+ p->algo.udelay = CYCLE_DELAY;
+- p->algo.mdelay = CYCLE_DELAY;
+ p->algo.timeout = TIMEOUT;
+ p->algo.data = p;
+ p->mmvga = mmvga;
+diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
+index ee114b4..c95a6c1 100644
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -272,7 +272,8 @@ static int i2c_pxa_wait_slave(struct pxa
+ dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, (long)jiffies, ISR, ICR, IBMR);
+
+- if ((ISR & (ISR_UB|ISR_IBB|ISR_SAD)) == ISR_SAD ||
++ if ((ISR & (ISR_UB|ISR_IBB)) == 0 ||
++ (ISR & ISR_SAD) != 0 ||
+ (ICR & ICR_SCLE) == 0) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+@@ -492,7 +493,10 @@ static void i2c_pxa_slave_txempty(struct
+ if (isr & ISR_BED) {
+ /* what should we do here? */
+ } else {
+- int ret = i2c->slave->read(i2c->slave->data);
++ int ret = 0;
++
++ if (i2c->slave != NULL)
++ ret = i2c->slave->read(i2c->slave->data);
+
+ IDBR = ret;
+ ICR |= ICR_TB; /* allow next byte */
+@@ -850,7 +854,7 @@ static void i2c_pxa_irq_rxfull(struct px
+ ICR = icr;
+ }
+
+-static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
+ {
+ struct pxa_i2c *i2c = dev_id;
+ u32 isr = ISR;
+@@ -926,7 +930,7 @@ static u32 i2c_pxa_functionality(struct
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ }
+
+-static struct i2c_algorithm i2c_pxa_algorithm = {
++static const struct i2c_algorithm i2c_pxa_algorithm = {
+ .master_xfer = i2c_pxa_xfer,
+ .functionality = i2c_pxa_functionality,
+ };
+diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
+index 0ebec3c..8764df0 100644
+--- a/drivers/i2c/busses/i2c-rpx.c
++++ b/drivers/i2c/busses/i2c-rpx.c
+@@ -55,10 +55,10 @@ rpx_iic_init(struct i2c_algo_8xx_data *d
+ data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
+ }
+
+-static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
++static int rpx_install_isr(int irq, void (*func)(void *), void *data)
+ {
+ /* install interrupt handler */
+- cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
++ cpm_install_handler(irq, func, data);
+
+ return 0;
+ }
+diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
+index 5d2950e..4ca6de2 100644
+--- a/drivers/i2c/busses/i2c-s3c2410.c
++++ b/drivers/i2c/busses/i2c-s3c2410.c
+@@ -423,8 +423,7 @@ static int i2s_s3c_irq_nextbyte(struct s
+ * top level IRQ servicing routine
+ */
+
+-static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
+ {
+ struct s3c24xx_i2c *i2c = dev_id;
+ unsigned long status;
+@@ -566,7 +565,7 @@ static u32 s3c24xx_i2c_func(struct i2c_a
+
+ /* i2c bus registration info */
+
+-static struct i2c_algorithm s3c24xx_i2c_algorithm = {
++static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
+ .master_xfer = s3c24xx_i2c_xfer,
+ .functionality = s3c24xx_i2c_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
+index 0c85182..209f47e 100644
+--- a/drivers/i2c/busses/i2c-savage4.c
++++ b/drivers/i2c/busses/i2c-savage4.c
+@@ -140,7 +140,6 @@ static struct i2c_algo_bit_data sav_i2c_
+ .getsda = bit_savi2c_getsda,
+ .getscl = bit_savi2c_getscl,
+ .udelay = CYCLE_DELAY,
+- .mdelay = CYCLE_DELAY,
+ .timeout = TIMEOUT
+ };
+
+diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
+index fa503ed..0ca599d 100644
+--- a/drivers/i2c/busses/i2c-sibyte.c
++++ b/drivers/i2c/busses/i2c-sibyte.c
+@@ -1,6 +1,7 @@
+ /*
+ * Copyright (C) 2004 Steven J. Hill
+ * Copyright (C) 2001,2002,2003 Broadcom Corporation
++ * Copyright (C) 1995-2000 Simon G. Vogl
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -17,11 +18,162 @@
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
++#include <linux/kernel.h>
+ #include <linux/module.h>
+-#include <linux/i2c-algo-sibyte.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <asm/io.h>
+ #include <asm/sibyte/sb1250_regs.h>
+ #include <asm/sibyte/sb1250_smbus.h>
+
++
++struct i2c_algo_sibyte_data {
++ void *data; /* private data */
++ int bus; /* which bus */
++ void *reg_base; /* CSR base */
++};
++
++/* ----- global defines ----------------------------------------------- */
++#define SMB_CSR(a,r) ((long)(a->reg_base + r))
++
++/* ----- global variables --------------------------------------------- */
++
++/* module parameters:
++ */
++static int bit_scan; /* have a look at what's hanging 'round */
++module_param(bit_scan, int, 0);
++MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
++
++
++static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
++ unsigned short flags, char read_write,
++ u8 command, int size, union i2c_smbus_data * data)
++{
++ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
++ int data_bytes = 0;
++ int error;
++
++ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
++ ;
++
++ switch (size) {
++ case I2C_SMBUS_QUICK:
++ csr_out32((V_SMB_ADDR(addr) |
++ (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
++ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
++ break;
++ case I2C_SMBUS_BYTE:
++ if (read_write == I2C_SMBUS_READ) {
++ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
++ SMB_CSR(adap, R_SMB_START));
++ data_bytes = 1;
++ } else {
++ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
++ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
++ SMB_CSR(adap, R_SMB_START));
++ }
++ break;
++ case I2C_SMBUS_BYTE_DATA:
++ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
++ if (read_write == I2C_SMBUS_READ) {
++ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
++ SMB_CSR(adap, R_SMB_START));
++ data_bytes = 1;
++ } else {
++ csr_out32(V_SMB_LB(data->byte),
++ SMB_CSR(adap, R_SMB_DATA));
++ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
++ SMB_CSR(adap, R_SMB_START));
++ }
++ break;
++ case I2C_SMBUS_WORD_DATA:
++ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
++ if (read_write == I2C_SMBUS_READ) {
++ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
++ SMB_CSR(adap, R_SMB_START));
++ data_bytes = 2;
++ } else {
++ csr_out32(V_SMB_LB(data->word & 0xff),
++ SMB_CSR(adap, R_SMB_DATA));
++ csr_out32(V_SMB_MB(data->word >> 8),
++ SMB_CSR(adap, R_SMB_DATA));
++ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
++ SMB_CSR(adap, R_SMB_START));
++ }
++ break;
++ default:
++ return -1; /* XXXKW better error code? */
++ }
++
++ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
++ ;
++
++ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
++ if (error & M_SMB_ERROR) {
++ /* Clear error bit by writing a 1 */
++ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
++ return -1; /* XXXKW better error code? */
++ }
++
++ if (data_bytes == 1)
++ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
++ if (data_bytes == 2)
++ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
++
++ return 0;
++}
++
++static u32 bit_func(struct i2c_adapter *adap)
++{
++ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
++}
++
++
++/* -----exported algorithm data: ------------------------------------- */
++
++static const struct i2c_algorithm i2c_sibyte_algo = {
++ .smbus_xfer = smbus_xfer,
++ .functionality = bit_func,
++};
++
++/*
++ * registering functions to load algorithms at runtime
++ */
++int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
++{
++ int i;
++ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
++
++ /* register new adapter to i2c module... */
++ i2c_adap->algo = &i2c_sibyte_algo;
++
++ /* Set the frequency to 100 kHz */
++ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
++ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
++
++ /* scan bus */
++ if (bit_scan) {
++ union i2c_smbus_data data;
++ int rc;
++ printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
++ i2c_adap->name);
++ for (i = 0x00; i < 0x7f; i++) {
++ /* XXXKW is this a realistic probe? */
++ rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
++ I2C_SMBUS_BYTE_DATA, &data);
++ if (!rc) {
++ printk("(%02x)",i);
++ } else
++ printk(".");
++ }
++ printk("\n");
++ }
++
++ return i2c_add_adapter(i2c_adap);
++}
++
++
+ static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
+ { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
+ { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
+@@ -58,13 +210,13 @@ static int __init i2c_sibyte_init(void)
+
+ static void __exit i2c_sibyte_exit(void)
+ {
+- i2c_sibyte_del_bus(&sibyte_board_adapter[0]);
+- i2c_sibyte_del_bus(&sibyte_board_adapter[1]);
++ i2c_del_adapter(&sibyte_board_adapter[0]);
++ i2c_del_adapter(&sibyte_board_adapter[1]);
+ }
+
+ module_init(i2c_sibyte_init);
+ module_exit(i2c_sibyte_exit);
+
+-MODULE_AUTHOR("Kip Walker <kwalker at broadcom.com>, Steven J. Hill <sjhill at realitydiluted.com>");
++MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill at realitydiluted.com>");
+ MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
+index b57ab74..38bbfd8 100644
+--- a/drivers/i2c/busses/i2c-sis5595.c
++++ b/drivers/i2c/busses/i2c-sis5595.c
+@@ -358,7 +358,7 @@ static u32 sis5595_func(struct i2c_adapt
+ I2C_FUNC_SMBUS_PROC_CALL;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis5595_access,
+ .functionality = sis5595_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
+index acb75e2..dec0baf 100644
+--- a/drivers/i2c/busses/i2c-sis630.c
++++ b/drivers/i2c/busses/i2c-sis630.c
+@@ -450,7 +450,7 @@ exit:
+ }
+
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis630_access,
+ .functionality = sis630_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
+index 1a73c05..7fd07fb 100644
+--- a/drivers/i2c/busses/i2c-sis96x.c
++++ b/drivers/i2c/busses/i2c-sis96x.c
+@@ -242,7 +242,7 @@ static u32 sis96x_func(struct i2c_adapte
+ I2C_FUNC_SMBUS_PROC_CALL;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis96x_access,
+ .functionality = sis96x_func,
+ };
+diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
+index 73f481e..a54adc5 100644
+--- a/drivers/i2c/busses/i2c-stub.c
++++ b/drivers/i2c/busses/i2c-stub.c
+@@ -27,6 +27,10 @@
+ #include <linux/errno.h>
+ #include <linux/i2c.h>
+
++static unsigned short chip_addr;
++module_param(chip_addr, ushort, S_IRUGO);
++MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
++
+ static u8 stub_pointer;
+ static u8 stub_bytes[256];
+ static u16 stub_words[256];
+@@ -37,6 +41,9 @@ static s32 stub_xfer(struct i2c_adapter
+ {
+ s32 ret;
+
++ if (addr != chip_addr)
++ return -ENODEV;
++
+ switch (size) {
+
+ case I2C_SMBUS_QUICK:
+@@ -108,7 +115,7 @@ static u32 stub_func(struct i2c_adapter
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .functionality = stub_func,
+ .smbus_xfer = stub_xfer,
+ };
+@@ -122,7 +129,17 @@ static struct i2c_adapter stub_adapter =
+
+ static int __init i2c_stub_init(void)
+ {
+- printk(KERN_INFO "i2c-stub loaded\n");
++ if (!chip_addr) {
++ printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
++ return -ENODEV;
++ }
++ if (chip_addr < 0x03 || chip_addr > 0x77) {
++ printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
++ chip_addr);
++ return -EINVAL;
++ }
++
++ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
+ return i2c_add_adapter(&stub_adapter);
+ }
+
+diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
+index 484bbac..910e200 100644
+--- a/drivers/i2c/busses/i2c-via.c
++++ b/drivers/i2c/busses/i2c-via.c
+@@ -81,7 +81,6 @@ static struct i2c_algo_bit_data bit_data
+ .getsda = bit_via_getsda,
+ .getscl = bit_via_getscl,
+ .udelay = 5,
+- .mdelay = 5,
+ .timeout = HZ
+ };
+
+diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
+index 47e52bf..efc6bbf 100644
+--- a/drivers/i2c/busses/i2c-viapro.c
++++ b/drivers/i2c/busses/i2c-viapro.c
+@@ -34,6 +34,8 @@
+ VT8233A 0x3147 yes?
+ VT8235 0x3177 yes
+ VT8237R 0x3227 yes
++ VT8237A 0x3337 yes
++ VT8251 0x3287 yes
+
+ Note: we assume there can only be one device, with one SMBus interface.
+ */
+@@ -297,7 +299,7 @@ static u32 vt596_func(struct i2c_adapter
+ return func;
+ }
+
+-static struct i2c_algorithm smbus_algorithm = {
++static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = vt596_access,
+ .functionality = vt596_func,
+ };
+@@ -381,7 +383,9 @@ found:
+ dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
+
+ switch (pdev->device) {
++ case PCI_DEVICE_ID_VIA_8251:
+ case PCI_DEVICE_ID_VIA_8237:
++ case PCI_DEVICE_ID_VIA_8237A:
+ case PCI_DEVICE_ID_VIA_8235:
+ case PCI_DEVICE_ID_VIA_8233A:
+ case PCI_DEVICE_ID_VIA_8233_0:
+@@ -432,8 +436,12 @@ static struct pci_device_id vt596_ids[]
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
+ .driver_data = SMBBA3 },
++ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
++ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
+ .driver_data = SMBBA1 },
++ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
++ .driver_data = SMBBA3 },
+ { 0, }
+ };
+
+diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
+index b675773..6c8d251 100644
+--- a/drivers/i2c/busses/i2c-voodoo3.c
++++ b/drivers/i2c/busses/i2c-voodoo3.c
+@@ -160,7 +160,6 @@ static struct i2c_algo_bit_data voo_i2c_
+ .getsda = bit_vooi2c_getsda,
+ .getscl = bit_vooi2c_getscl,
+ .udelay = CYCLE_DELAY,
+- .mdelay = CYCLE_DELAY,
+ .timeout = TIMEOUT
+ };
+
+@@ -177,7 +176,6 @@ static struct i2c_algo_bit_data voo_ddc_
+ .getsda = bit_vooddc_getsda,
+ .getscl = bit_vooddc_getscl,
+ .udelay = CYCLE_DELAY,
+- .mdelay = CYCLE_DELAY,
+ .timeout = TIMEOUT
+ };
+
+diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
+index eae9e81..32aab0d 100644
+--- a/drivers/i2c/busses/scx200_acb.c
++++ b/drivers/i2c/busses/scx200_acb.c
+@@ -383,7 +383,7 @@ static u32 scx200_acb_func(struct i2c_ad
+ }
+
+ /* For now, we only handle combined mode (smbus) */
+-static struct i2c_algorithm scx200_acb_algorithm = {
++static const struct i2c_algorithm scx200_acb_algorithm = {
+ .smbus_xfer = scx200_acb_smbus_xfer,
+ .functionality = scx200_acb_func,
+ };
+diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
+index cb3ef5a..8ddbae4 100644
+--- a/drivers/i2c/busses/scx200_i2c.c
++++ b/drivers/i2c/busses/scx200_i2c.c
+@@ -1,4 +1,4 @@
+-/* linux/drivers/i2c/scx200_i2c.c
++/* linux/drivers/i2c/busses/scx200_i2c.c
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel at nano-system.com>
+
+@@ -71,12 +71,12 @@ static int scx200_i2c_getsda(void *data)
+ */
+
+ static struct i2c_algo_bit_data scx200_i2c_data = {
+- NULL,
+- scx200_i2c_setsda,
+- scx200_i2c_setscl,
+- scx200_i2c_getsda,
+- scx200_i2c_getscl,
+- 10, 10, 100, /* waits, timeout */
++ .setsda = scx200_i2c_setsda,
++ .setscl = scx200_i2c_setscl,
++ .getsda = scx200_i2c_getsda,
++ .getscl = scx200_i2c_getscl,
++ .udelay = 10,
++ .timeout = 100,
+ };
+
+ static struct i2c_adapter scx200_i2c_ops = {
+diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
+index 13c1082..cec3a0c 100644
+--- a/drivers/i2c/chips/eeprom.c
++++ b/drivers/i2c/chips/eeprom.c
+@@ -209,10 +209,14 @@ static int eeprom_detect(struct i2c_adap
+ }
+
+ /* create the sysfs eeprom file */
+- sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
++ err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
++ if (err)
++ goto exit_detach;
+
+ return 0;
+
++exit_detach:
++ i2c_detach_client(new_client);
+ exit_kfree:
+ kfree(data);
+ exit:
+@@ -223,6 +227,8 @@ static int eeprom_detach_client(struct i
+ {
+ int err;
+
++ sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
++
+ err = i2c_detach_client(client);
+ if (err)
+ return err;
+diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
+index f92505b..ccdf3e9 100644
+--- a/drivers/i2c/chips/isp1301_omap.c
++++ b/drivers/i2c/chips/isp1301_omap.c
+@@ -30,7 +30,7 @@
+ #include <linux/usb_ch9.h>
+ #include <linux/usb_gadget.h>
+ #include <linux/usb.h>
+-#include <linux/usb_otg.h>
++#include <linux/usb/otg.h>
+ #include <linux/i2c.h>
+ #include <linux/workqueue.h>
+
+@@ -669,7 +669,7 @@ pulldown:
+ dump_regs(isp, "otg->isp1301");
+ }
+
+-static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs)
++static irqreturn_t omap_otg_irq(int irq, void *_isp)
+ {
+ u16 otg_irq = OTG_IRQ_SRC_REG;
+ u32 otg_ctrl;
+@@ -1181,7 +1181,7 @@ isp1301_work(void *data)
+ isp->working = 0;
+ }
+
+-static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs)
++static irqreturn_t isp1301_irq(int irq, void *isp)
+ {
+ isp1301_defer_work(isp, WORK_UPDATE_OTG);
+ return IRQ_HANDLED;
+diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
+index 88d2dde..76645c1 100644
+--- a/drivers/i2c/chips/max6875.c
++++ b/drivers/i2c/chips/max6875.c
+@@ -199,8 +199,7 @@ static int max6875_detect(struct i2c_ada
+ mutex_init(&data->update_lock);
+
+ /* Init fake client data */
+- /* set the client data to the i2c_client so that it will get freed */
+- i2c_set_clientdata(fake_client, fake_client);
++ i2c_set_clientdata(fake_client, NULL);
+ fake_client->addr = address | 1;
+ fake_client->adapter = adapter;
+ fake_client->driver = &max6875_driver;
+@@ -214,13 +213,17 @@ static int max6875_detect(struct i2c_ada
+ goto exit_kfree2;
+
+ if ((err = i2c_attach_client(fake_client)) != 0)
+- goto exit_detach;
++ goto exit_detach1;
+
+- sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
++ err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
++ if (err)
++ goto exit_detach2;
+
+ return 0;
+
+-exit_detach:
++exit_detach2:
++ i2c_detach_client(fake_client);
++exit_detach1:
+ i2c_detach_client(real_client);
+ exit_kfree2:
+ kfree(fake_client);
+@@ -229,14 +232,24 @@ exit_kfree1:
+ return err;
+ }
+
++/* Will be called for both the real client and the fake client */
+ static int max6875_detach_client(struct i2c_client *client)
+ {
+ int err;
++ struct max6875_data *data = i2c_get_clientdata(client);
++
++ /* data is NULL for the fake client */
++ if (data)
++ sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
+
+ err = i2c_detach_client(client);
+ if (err)
+ return err;
+- kfree(i2c_get_clientdata(client));
++
++ if (data) /* real client */
++ kfree(data);
++ else /* fake client */
++ kfree(client);
+ return 0;
+ }
+
+diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c
+index cb22280..f43c4e7 100644
+--- a/drivers/i2c/chips/pca9539.c
++++ b/drivers/i2c/chips/pca9539.c
+@@ -148,11 +148,16 @@ static int pca9539_detect(struct i2c_ada
+ if ((err = i2c_attach_client(new_client)))
+ goto exit_kfree;
+
+- /* Register sysfs hooks (don't care about failure) */
+- sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group);
++ /* Register sysfs hooks */
++ err = sysfs_create_group(&new_client->dev.kobj,
++ &pca9539_defattr_group);
++ if (err)
++ goto exit_detach;
+
+ return 0;
+
++exit_detach:
++ i2c_detach_client(new_client);
+ exit_kfree:
+ kfree(data);
+ exit:
+@@ -163,6 +168,8 @@ static int pca9539_detach_client(struct
+ {
+ int err;
+
++ sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
++
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
+index c3e6449..32b2542 100644
+--- a/drivers/i2c/chips/pcf8574.c
++++ b/drivers/i2c/chips/pcf8574.c
+@@ -105,6 +105,16 @@ static ssize_t set_write(struct device *
+
+ static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+
++static struct attribute *pcf8574_attributes[] = {
++ &dev_attr_read.attr,
++ &dev_attr_write.attr,
++ NULL
++};
++
++static const struct attribute_group pcf8574_attr_group = {
++ .attrs = pcf8574_attributes,
++};
++
+ /*
+ * Real code
+ */
+@@ -166,13 +176,13 @@ static int pcf8574_detect(struct i2c_ada
+ pcf8574_init_client(new_client);
+
+ /* Register sysfs hooks */
+- device_create_file(&new_client->dev, &dev_attr_read);
+- device_create_file(&new_client->dev, &dev_attr_write);
++ err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
++ if (err)
++ goto exit_detach;
+ return 0;
+
+-/* OK, this is not exactly good programming practice, usually. But it is
+- very code-efficient in this case. */
+-
++ exit_detach:
++ i2c_detach_client(new_client);
+ exit_free:
+ kfree(data);
+ exit:
+@@ -183,6 +193,8 @@ static int pcf8574_detach_client(struct
+ {
+ int err;
+
++ sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
++
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
+index 925a6b3..4dc3637 100644
+--- a/drivers/i2c/chips/pcf8591.c
++++ b/drivers/i2c/chips/pcf8591.c
+@@ -158,6 +158,28 @@ static ssize_t set_out0_enable(struct de
+ static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
+ show_out0_enable, set_out0_enable);
+
++static struct attribute *pcf8591_attributes[] = {
++ &dev_attr_out0_enable.attr,
++ &dev_attr_out0_output.attr,
++ &dev_attr_in0_input.attr,
++ &dev_attr_in1_input.attr,
++ NULL
++};
++
++static const struct attribute_group pcf8591_attr_group = {
++ .attrs = pcf8591_attributes,
++};
++
++static struct attribute *pcf8591_attributes_opt[] = {
++ &dev_attr_in2_input.attr,
++ &dev_attr_in3_input.attr,
++ NULL
++};
++
++static const struct attribute_group pcf8591_attr_group_opt = {
++ .attrs = pcf8591_attributes_opt,
++};
++
+ /*
+ * Real code
+ */
+@@ -211,24 +233,31 @@ static int pcf8591_detect(struct i2c_ada
+ pcf8591_init_client(new_client);
+
+ /* Register sysfs hooks */
+- device_create_file(&new_client->dev, &dev_attr_out0_enable);
+- device_create_file(&new_client->dev, &dev_attr_out0_output);
+- device_create_file(&new_client->dev, &dev_attr_in0_input);
+- device_create_file(&new_client->dev, &dev_attr_in1_input);
++ err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group);
++ if (err)
++ goto exit_detach;
+
+ /* Register input2 if not in "two differential inputs" mode */
+- if (input_mode != 3 )
+- device_create_file(&new_client->dev, &dev_attr_in2_input);
+-
++ if (input_mode != 3) {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in2_input)))
++ goto exit_sysfs_remove;
++ }
++
+ /* Register input3 only in "four single ended inputs" mode */
+- if (input_mode == 0)
+- device_create_file(&new_client->dev, &dev_attr_in3_input);
+-
++ if (input_mode == 0) {
++ if ((err = device_create_file(&new_client->dev,
++ &dev_attr_in3_input)))
++ goto exit_sysfs_remove;
++ }
++
+ return 0;
+-
+- /* OK, this is not exactly good programming practice, usually. But it is
+- very code-efficient in this case. */
+
++exit_sysfs_remove:
++ sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt);
++ sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group);
++exit_detach:
++ i2c_detach_client(new_client);
+ exit_kfree:
+ kfree(data);
+ exit:
+@@ -239,6 +268,9 @@ static int pcf8591_detach_client(struct
+ {
+ int err;
+
++ sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
++ sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
++
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
+index 0be6fd6..60bef94 100644
+--- a/drivers/i2c/chips/tps65010.c
++++ b/drivers/i2c/chips/tps65010.c
+@@ -305,7 +305,7 @@ static int dbg_show(struct seq_file *s,
+
+ static int dbg_tps_open(struct inode *inode, struct file *file)
+ {
+- return single_open(file, dbg_show, inode->u.generic_ip);
++ return single_open(file, dbg_show, inode->i_private);
+ }
+
+ static struct file_operations debug_fops = {
+@@ -446,7 +446,7 @@ static void tps65010_work(void *_tps)
+ mutex_unlock(&tps->lock);
+ }
+
+-static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs)
++static irqreturn_t tps65010_irq(int irq, void *_tps)
+ {
+ struct tps65010 *tps = _tps;
+
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index 9cb277d..7ca81f4 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -183,15 +183,21 @@ int i2c_add_adapter(struct i2c_adapter *
+ sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
+ adap->dev.driver = &i2c_adapter_driver;
+ adap->dev.release = &i2c_adapter_dev_release;
+- device_register(&adap->dev);
+- device_create_file(&adap->dev, &dev_attr_name);
++ res = device_register(&adap->dev);
++ if (res)
++ goto out_list;
++ res = device_create_file(&adap->dev, &dev_attr_name);
++ if (res)
++ goto out_unregister;
+
+ /* Add this adapter to the i2c_adapter class */
+ memset(&adap->class_dev, 0x00, sizeof(struct class_device));
+ adap->class_dev.dev = &adap->dev;
+ adap->class_dev.class = &i2c_adapter_class;
+ strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
+- class_device_register(&adap->class_dev);
++ res = class_device_register(&adap->class_dev);
++ if (res)
++ goto out_remove_name;
+
+ dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
+@@ -206,6 +212,17 @@ int i2c_add_adapter(struct i2c_adapter *
+ out_unlock:
+ mutex_unlock(&core_lists);
+ return res;
++
++out_remove_name:
++ device_remove_file(&adap->dev, &dev_attr_name);
++out_unregister:
++ init_completion(&adap->dev_released); /* Needed? */
++ device_unregister(&adap->dev);
++ wait_for_completion(&adap->dev_released);
++out_list:
++ list_del(&adap->list);
++ idr_remove(&i2c_adapter_idr, adap->nr);
++ goto out_unlock;
+ }
+
+
+@@ -394,23 +411,15 @@ int i2c_check_addr(struct i2c_adapter *a
+ int i2c_attach_client(struct i2c_client *client)
+ {
+ struct i2c_adapter *adapter = client->adapter;
++ int res = 0;
+
+ mutex_lock(&adapter->clist_lock);
+ if (__i2c_check_addr(client->adapter, client->addr)) {
+- mutex_unlock(&adapter->clist_lock);
+- return -EBUSY;
++ res = -EBUSY;
++ goto out_unlock;
+ }
+ list_add_tail(&client->list,&adapter->clients);
+- mutex_unlock(&adapter->clist_lock);
+
+- if (adapter->client_register) {
+- if (adapter->client_register(client)) {
+- dev_dbg(&adapter->dev, "client_register "
+- "failed for client [%s] at 0x%02x\n",
+- client->name, client->addr);
+- }
+- }
+-
+ client->usage_count = 0;
+
+ client->dev.parent = &client->adapter->dev;
+@@ -422,10 +431,35 @@ int i2c_attach_client(struct i2c_client
+ "%d-%04x", i2c_adapter_id(adapter), client->addr);
+ dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+ client->name, client->dev.bus_id);
+- device_register(&client->dev);
+- device_create_file(&client->dev, &dev_attr_client_name);
+-
++ res = device_register(&client->dev);
++ if (res)
++ goto out_list;
++ res = device_create_file(&client->dev, &dev_attr_client_name);
++ if (res)
++ goto out_unregister;
++ mutex_unlock(&adapter->clist_lock);
++
++ if (adapter->client_register) {
++ if (adapter->client_register(client)) {
++ dev_dbg(&adapter->dev, "client_register "
++ "failed for client [%s] at 0x%02x\n",
++ client->name, client->addr);
++ }
++ }
++
+ return 0;
++
++out_unregister:
++ init_completion(&client->released); /* Needed? */
++ device_unregister(&client->dev);
++ wait_for_completion(&client->released);
++out_list:
++ list_del(&client->list);
++ dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
++ "(%d)\n", client->name, client->addr, res);
++out_unlock:
++ mutex_unlock(&adapter->clist_lock);
++ return res;
+ }
+
+
+@@ -674,11 +708,16 @@ static int i2c_probe_address(struct i2c_
+
+ /* Finally call the custom detection function */
+ err = found_proc(adapter, addr, kind);
+-
+ /* -ENODEV can be returned if there is a chip at the given address
+ but it isn't supported by this chip driver. We catch it here as
+ this isn't an error. */
+- return (err == -ENODEV) ? 0 : err;
++ if (err == -ENODEV)
++ err = 0;
++
++ if (err)
++ dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
++ addr, err);
++ return err;
+ }
+
+ int i2c_probe(struct i2c_adapter *adapter,
+@@ -868,7 +907,7 @@ s32 i2c_smbus_read_byte(struct i2c_clien
+ I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
+ return -1;
+ else
+- return 0x0FF & data.byte;
++ return data.byte;
+ }
+
+ s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
+@@ -884,7 +923,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_
+ I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
+ return -1;
+ else
+- return 0x0FF & data.byte;
++ return data.byte;
+ }
+
+ s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
+@@ -903,7 +942,7 @@ s32 i2c_smbus_read_word_data(struct i2c_
+ I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
+ return -1;
+ else
+- return 0x0FFFF & data.word;
++ return data.word;
+ }
+
+ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
+@@ -1006,7 +1045,7 @@ static s32 i2c_smbus_xfer_emulated(struc
+ else {
+ msg[0].len=3;
+ msgbuf0[1] = data->word & 0xff;
+- msgbuf0[2] = (data->word >> 8) & 0xff;
++ msgbuf0[2] = data->word >> 8;
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+@@ -1015,7 +1054,7 @@ static s32 i2c_smbus_xfer_emulated(struc
+ msg[0].len = 3;
+ msg[1].len = 2;
+ msgbuf0[1] = data->word & 0xff;
+- msgbuf0[2] = (data->word >> 8) & 0xff;
++ msgbuf0[2] = data->word >> 8;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index 58ccddd..3f86903 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -32,43 +32,35 @@
+ #include <linux/slab.h>
+ #include <linux/smp_lock.h>
+ #include <linux/init.h>
++#include <linux/list.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-dev.h>
+-#include <linux/platform_device.h>
+ #include <asm/uaccess.h>
+
+-static struct i2c_client i2cdev_client_template;
++static struct i2c_driver i2cdev_driver;
+
+ struct i2c_dev {
+- int minor;
++ struct list_head list;
+ struct i2c_adapter *adap;
+ struct class_device *class_dev;
+ };
+-#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
+
+ #define I2C_MINORS 256
+-static struct i2c_dev *i2c_dev_array[I2C_MINORS];
+-static DEFINE_SPINLOCK(i2c_dev_array_lock);
++static LIST_HEAD(i2c_dev_list);
++static DEFINE_SPINLOCK(i2c_dev_list_lock);
+
+ static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+ {
+ struct i2c_dev *i2c_dev;
+
+- spin_lock(&i2c_dev_array_lock);
+- i2c_dev = i2c_dev_array[index];
+- spin_unlock(&i2c_dev_array_lock);
+- return i2c_dev;
+-}
+-
+-static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
+-{
+- struct i2c_dev *i2c_dev = NULL;
+-
+- spin_lock(&i2c_dev_array_lock);
+- if ((i2c_dev_array[adap->nr]) &&
+- (i2c_dev_array[adap->nr]->adap == adap))
+- i2c_dev = i2c_dev_array[adap->nr];
+- spin_unlock(&i2c_dev_array_lock);
++ spin_lock(&i2c_dev_list_lock);
++ list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
++ if (i2c_dev->adap->nr == index)
++ goto found;
++ }
++ i2c_dev = NULL;
++found:
++ spin_unlock(&i2c_dev_list_lock);
+ return i2c_dev;
+ }
+
+@@ -76,30 +68,28 @@ static struct i2c_dev *get_free_i2c_dev(
+ {
+ struct i2c_dev *i2c_dev;
+
++ if (adap->nr >= I2C_MINORS) {
++ printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
++ adap->nr);
++ return ERR_PTR(-ENODEV);
++ }
++
+ i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+ return ERR_PTR(-ENOMEM);
++ i2c_dev->adap = adap;
+
+- spin_lock(&i2c_dev_array_lock);
+- if (i2c_dev_array[adap->nr]) {
+- spin_unlock(&i2c_dev_array_lock);
+- dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n");
+- goto error;
+- }
+- i2c_dev->minor = adap->nr;
+- i2c_dev_array[adap->nr] = i2c_dev;
+- spin_unlock(&i2c_dev_array_lock);
++ spin_lock(&i2c_dev_list_lock);
++ list_add_tail(&i2c_dev->list, &i2c_dev_list);
++ spin_unlock(&i2c_dev_list_lock);
+ return i2c_dev;
+-error:
+- kfree(i2c_dev);
+- return ERR_PTR(-ENODEV);
+ }
+
+ static void return_i2c_dev(struct i2c_dev *i2c_dev)
+ {
+- spin_lock(&i2c_dev_array_lock);
+- i2c_dev_array[i2c_dev->minor] = NULL;
+- spin_unlock(&i2c_dev_array_lock);
++ spin_lock(&i2c_dev_list_lock);
++ list_del(&i2c_dev->list);
++ spin_unlock(&i2c_dev_list_lock);
+ }
+
+ static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
+@@ -375,12 +365,13 @@ static int i2cdev_open(struct inode *ino
+ if (!adap)
+ return -ENODEV;
+
+- client = kmalloc(sizeof(*client), GFP_KERNEL);
++ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client) {
+ i2c_put_adapter(adap);
+ return -ENOMEM;
+ }
+- memcpy(client, &i2cdev_client_template, sizeof(*client));
++ snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
++ client->driver = &i2cdev_driver;
+
+ /* registered with adapter, passed as client to user */
+ client->adapter = adap;
+@@ -415,41 +406,47 @@ static struct class *i2c_dev_class;
+ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
+ {
+ struct i2c_dev *i2c_dev;
+- struct device *dev;
++ int res;
+
+ i2c_dev = get_free_i2c_dev(adap);
+ if (IS_ERR(i2c_dev))
+ return PTR_ERR(i2c_dev);
+
+- pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+- adap->name, i2c_dev->minor);
+-
+ /* register this i2c device with the driver core */
+- i2c_dev->adap = adap;
+- dev = &adap->dev;
+ i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
+- MKDEV(I2C_MAJOR, i2c_dev->minor),
+- dev, "i2c-%d", i2c_dev->minor);
+- if (!i2c_dev->class_dev)
++ MKDEV(I2C_MAJOR, adap->nr),
++ &adap->dev, "i2c-%d",
++ adap->nr);
++ if (!i2c_dev->class_dev) {
++ res = -ENODEV;
+ goto error;
+- class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
++ }
++ res = class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
++ if (res)
++ goto error_destroy;
++
++ pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
++ adap->name, adap->nr);
+ return 0;
++error_destroy:
++ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+ error:
+ return_i2c_dev(i2c_dev);
+ kfree(i2c_dev);
+- return -ENODEV;
++ return res;
+ }
+
+ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
+ {
+ struct i2c_dev *i2c_dev;
+
+- i2c_dev = i2c_dev_get_by_adapter(adap);
+- if (!i2c_dev)
+- return -ENODEV;
++ i2c_dev = i2c_dev_get_by_minor(adap->nr);
++ if (!i2c_dev) /* attach_adapter must have failed */
++ return 0;
+
++ class_device_remove_file(i2c_dev->class_dev, &class_device_attr_name);
+ return_i2c_dev(i2c_dev);
+- class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
++ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+ kfree(i2c_dev);
+
+ pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
+@@ -471,12 +468,6 @@ static struct i2c_driver i2cdev_driver =
+ .detach_client = i2cdev_detach_client,
+ };
+
+-static struct i2c_client i2cdev_client_template = {
+- .name = "I2C /dev entry",
+- .addr = -1,
+- .driver = &i2cdev_driver,
+-};
+-
+ static int __init i2c_dev_init(void)
+ {
+ int res;
+diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
+index b6fb167..0c68d0f 100644
+--- a/drivers/ide/Kconfig
++++ b/drivers/ide/Kconfig
+@@ -4,6 +4,8 @@
+ # Andre Hedrick <andre at linux-ide.org>
+ #
+
++if BLOCK
++
+ menu "ATA/ATAPI/MFM/RLL support"
+
+ config IDE
+@@ -54,7 +56,7 @@ if IDE
+
+ config IDE_MAX_HWIFS
+ int "Max IDE interfaces"
+- depends on ALPHA || SUPERH || IA64
++ depends on ALPHA || SUPERH || IA64 || EMBEDDED
+ default 4
+ help
+ This is the maximum number of IDE hardware interfaces that will
+@@ -592,6 +594,12 @@ config BLK_DEV_HPT366
+ ide-probe at boot. It is reported to support DVD II drives, by the
+ manufacturer.
+
++config BLK_DEV_JMICRON
++ tristate "JMicron JMB36x support"
++ help
++ Basic support for the JMicron ATA controllers. For full support
++ use the libata drivers.
++
+ config BLK_DEV_SC1200
+ tristate "National SCx200 chipset support"
+ help
+@@ -606,15 +614,6 @@ config BLK_DEV_PIIX
+ the kernel to change PIO, DMA and UDMA speeds and to configure
+ the chip to optimum performance.
+
+-config BLK_DEV_IT8172
+- bool "IT8172 IDE support"
+- depends on (MIPS_ITE8172 || MIPS_IVR)
+- help
+- Say Y here to support the on-board IDE controller on the Integrated
+- Technology Express, Inc. ITE8172 SBC. Vendor page at
+- <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
+@@ -1082,3 +1081,5 @@ config BLK_DEV_HD
+ endif
+
+ endmenu
++
++endif
+diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
+index 1595599..608ca87 100644
+--- a/drivers/ide/h8300/ide-h8300.c
++++ b/drivers/ide/h8300/ide-h8300.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/ide/ide-h8300.c
++ * drivers/ide/h8300/ide-h8300.c
+ * H8/300 generic IDE interface
+ */
+
+diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
+index 654d4cd..bddfebd 100644
+--- a/drivers/ide/ide-cd.c
++++ b/drivers/ide/ide-cd.c
+@@ -372,7 +372,7 @@ static int cdrom_log_sense(ide_drive_t *
+ {
+ int log = 0;
+
+- if (!sense || !rq || (rq->flags & REQ_QUIET))
++ if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
+ return 0;
+
+ switch (sense->sense_key) {
+@@ -597,7 +597,7 @@ static void cdrom_prepare_request(ide_dr
+ struct cdrom_info *cd = drive->driver_data;
+
+ ide_init_drive_cmd(rq);
+- rq->flags = REQ_PC;
++ rq->cmd_type = REQ_TYPE_ATA_PC;
+ rq->rq_disk = cd->disk;
+ }
+
+@@ -617,7 +617,7 @@ static void cdrom_queue_request_sense(id
+ rq->cmd[0] = GPCMD_REQUEST_SENSE;
+ rq->cmd[4] = rq->data_len = 18;
+
+- rq->flags = REQ_SENSE;
++ rq->cmd_type = REQ_TYPE_SENSE;
+
+ /* NOTE! Save the failed command in "rq->buffer" */
+ rq->buffer = (void *) failed_command;
+@@ -630,10 +630,10 @@ static void cdrom_end_request (ide_drive
+ struct request *rq = HWGROUP(drive)->rq;
+ int nsectors = rq->hard_cur_sectors;
+
+- if ((rq->flags & REQ_SENSE) && uptodate) {
++ if (blk_sense_request(rq) && uptodate) {
+ /*
+- * For REQ_SENSE, "rq->buffer" points to the original failed
+- * request
++ * For REQ_TYPE_SENSE, "rq->buffer" points to the original
++ * failed request
+ */
+ struct request *failed = (struct request *) rq->buffer;
+ struct cdrom_info *info = drive->driver_data;
+@@ -706,17 +706,17 @@ static int cdrom_decode_status(ide_drive
+ return 1;
+ }
+
+- if (rq->flags & REQ_SENSE) {
++ if (blk_sense_request(rq)) {
+ /* We got an error trying to get sense info
+ from the drive (probably while trying
+ to recover from a former error). Just give up. */
+
+- rq->flags |= REQ_FAILED;
++ rq->cmd_flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ ide_error(drive, "request sense failure", stat);
+ return 1;
+
+- } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
++ } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
+ /* All other functions, except for READ. */
+ unsigned long flags;
+
+@@ -724,7 +724,7 @@ static int cdrom_decode_status(ide_drive
+ * if we have an error, pass back CHECK_CONDITION as the
+ * scsi status byte
+ */
+- if ((rq->flags & REQ_BLOCK_PC) && !rq->errors)
++ if (!rq->errors)
+ rq->errors = SAM_STAT_CHECK_CONDITION;
+
+ /* Check for tray open. */
+@@ -735,12 +735,12 @@ static int cdrom_decode_status(ide_drive
+ cdrom_saw_media_change (drive);
+ /*printk("%s: media changed\n",drive->name);*/
+ return 0;
+- } else if (!(rq->flags & REQ_QUIET)) {
++ } else if (!(rq->cmd_flags & REQ_QUIET)) {
+ /* Otherwise, print an error. */
+ ide_dump_status(drive, "packet command error", stat);
+ }
+
+- rq->flags |= REQ_FAILED;
++ rq->cmd_flags |= REQ_FAILED;
+
+ /*
+ * instead of playing games with moving completions around,
+@@ -881,7 +881,7 @@ static int cdrom_timer_expiry(ide_drive_
+ wait = ATAPI_WAIT_PC;
+ break;
+ default:
+- if (!(rq->flags & REQ_QUIET))
++ if (!(rq->cmd_flags & REQ_QUIET))
+ printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]);
+ wait = 0;
+ break;
+@@ -1124,7 +1124,7 @@ static ide_startstop_t cdrom_read_intr (
+ if (rq->current_nr_sectors > 0) {
+ printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
+ drive->name, rq->current_nr_sectors);
+- rq->flags |= REQ_FAILED;
++ rq->cmd_flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ } else
+ cdrom_end_request(drive, 1);
+@@ -1456,7 +1456,7 @@ static ide_startstop_t cdrom_pc_intr (id
+ printk ("%s: cdrom_pc_intr: data underrun %d\n",
+ drive->name, pc->buflen);
+ */
+- rq->flags |= REQ_FAILED;
++ rq->cmd_flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ }
+ return ide_stopped;
+@@ -1509,7 +1509,7 @@ static ide_startstop_t cdrom_pc_intr (id
+ rq->data += thislen;
+ rq->data_len -= thislen;
+
+- if (rq->flags & REQ_SENSE)
++ if (blk_sense_request(rq))
+ rq->sense_len += thislen;
+ } else {
+ confused:
+@@ -1517,7 +1517,7 @@ confused:
+ "appears confused (ireason = 0x%02x). "
+ "Trying to recover by ending request.\n",
+ drive->name, ireason);
+- rq->flags |= REQ_FAILED;
++ rq->cmd_flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+@@ -1546,7 +1546,7 @@ static ide_startstop_t cdrom_do_packet_c
+ struct cdrom_info *info = drive->driver_data;
+
+ info->dma = 0;
+- rq->flags &= ~REQ_FAILED;
++ rq->cmd_flags &= ~REQ_FAILED;
+ len = rq->data_len;
+
+ /* Start sending the command to the drive. */
+@@ -1558,7 +1558,7 @@ static int cdrom_queue_packet_command(id
+ {
+ struct request_sense sense;
+ int retries = 10;
+- unsigned int flags = rq->flags;
++ unsigned int flags = rq->cmd_flags;
+
+ if (rq->sense == NULL)
+ rq->sense = &sense;
+@@ -1567,14 +1567,14 @@ static int cdrom_queue_packet_command(id
+ do {
+ int error;
+ unsigned long time = jiffies;
+- rq->flags = flags;
++ rq->cmd_flags = flags;
+
+ error = ide_do_drive_cmd(drive, rq, ide_wait);
+ time = jiffies - time;
+
+ /* FIXME: we should probably abort/retry or something
+ * in case of failure */
+- if (rq->flags & REQ_FAILED) {
++ if (rq->cmd_flags & REQ_FAILED) {
+ /* The request failed. Retry if it was due to a unit
+ attention status
+ (usually means media was changed). */
+@@ -1596,10 +1596,10 @@ static int cdrom_queue_packet_command(id
+ }
+
+ /* End of retry loop. */
+- } while ((rq->flags & REQ_FAILED) && retries >= 0);
++ } while ((rq->cmd_flags & REQ_FAILED) && retries >= 0);
+
+ /* Return an error if the command failed. */
+- return (rq->flags & REQ_FAILED) ? -EIO : 0;
++ return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
+ }
+
+ /*
+@@ -1963,7 +1963,7 @@ static ide_startstop_t cdrom_do_block_pc
+ {
+ struct cdrom_info *info = drive->driver_data;
+
+- rq->flags |= REQ_QUIET;
++ rq->cmd_flags |= REQ_QUIET;
+
+ info->dma = 0;
+
+@@ -2023,11 +2023,12 @@ ide_do_rw_cdrom (ide_drive_t *drive, str
+ }
+ info->last_block = block;
+ return action;
+- } else if (rq->flags & (REQ_PC | REQ_SENSE)) {
++ } else if (rq->cmd_type == REQ_TYPE_SENSE ||
++ rq->cmd_type == REQ_TYPE_ATA_PC) {
+ return cdrom_do_packet_command(drive);
+- } else if (rq->flags & REQ_BLOCK_PC) {
++ } else if (blk_pc_request(rq)) {
+ return cdrom_do_block_pc(drive, rq);
+- } else if (rq->flags & REQ_SPECIAL) {
++ } else if (blk_special_request(rq)) {
+ /*
+ * right now this can only be a reset...
+ */
+@@ -2105,7 +2106,7 @@ static int cdrom_check_status(ide_drive_
+
+ req.sense = sense;
+ req.cmd[0] = GPCMD_TEST_UNIT_READY;
+- req.flags |= REQ_QUIET;
++ req.cmd_flags |= REQ_QUIET;
+
+ #if ! STANDARD_ATAPI
+ /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
+@@ -2207,7 +2208,7 @@ static int cdrom_read_capacity(ide_drive
+ req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+ req.data = (char *)&capbuf;
+ req.data_len = sizeof(capbuf);
+- req.flags |= REQ_QUIET;
++ req.cmd_flags |= REQ_QUIET;
+
+ stat = cdrom_queue_packet_command(drive, &req);
+ if (stat == 0) {
+@@ -2230,7 +2231,7 @@ static int cdrom_read_tocentry(ide_drive
+ req.sense = sense;
+ req.data = buf;
+ req.data_len = buflen;
+- req.flags |= REQ_QUIET;
++ req.cmd_flags |= REQ_QUIET;
+ req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+ req.cmd[6] = trackno;
+ req.cmd[7] = (buflen >> 8);
+@@ -2531,7 +2532,7 @@ static int ide_cdrom_packet(struct cdrom
+ req.timeout = cgc->timeout;
+
+ if (cgc->quiet)
+- req.flags |= REQ_QUIET;
++ req.cmd_flags |= REQ_QUIET;
+
+ req.sense = cgc->sense;
+ cgc->stat = cdrom_queue_packet_command(drive, &req);
+@@ -2629,7 +2630,8 @@ int ide_cdrom_reset (struct cdrom_device
+ int ret;
+
+ cdrom_prepare_request(drive, &req);
+- req.flags = REQ_SPECIAL | REQ_QUIET;
++ req.cmd_type = REQ_TYPE_SPECIAL;
++ req.cmd_flags = REQ_QUIET;
+ ret = ide_do_drive_cmd(drive, &req, ide_wait);
+
+ /*
+@@ -3116,9 +3118,9 @@ static int ide_cdrom_prep_pc(struct requ
+
+ static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq)
+ {
+- if (rq->flags & REQ_CMD)
++ if (blk_fs_request(rq))
+ return ide_cdrom_prep_fs(q, rq);
+- else if (rq->flags & REQ_BLOCK_PC)
++ else if (blk_pc_request(rq))
+ return ide_cdrom_prep_pc(rq);
+
+ return 0;
+diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
+index 7cf3eb0..0a05a37 100644
+--- a/drivers/ide/ide-disk.c
++++ b/drivers/ide/ide-disk.c
+@@ -699,7 +699,8 @@ static void idedisk_prepare_flush(reques
+ rq->cmd[0] = WIN_FLUSH_CACHE;
+
+
+- rq->flags |= REQ_DRIVE_TASK;
++ rq->cmd_type = REQ_TYPE_ATA_TASK;
++ rq->cmd_flags |= REQ_SOFTBARRIER;
+ rq->buffer = rq->cmd;
+ }
+
+@@ -740,7 +741,7 @@ static int set_multcount(ide_drive_t *dr
+ if (drive->special.b.set_multmode)
+ return -EBUSY;
+ ide_init_drive_cmd (&rq);
+- rq.flags = REQ_DRIVE_CMD;
++ rq.cmd_type = REQ_TYPE_ATA_CMD;
+ drive->mult_req = arg;
+ drive->special.b.set_multmode = 1;
+ (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
+index 7c3a13e..56efed6 100644
+--- a/drivers/ide/ide-dma.c
++++ b/drivers/ide/ide-dma.c
+@@ -145,14 +145,12 @@ int ide_in_drive_list(struct hd_driveid
+ {
+ for ( ; drive_table->id_model ; drive_table++)
+ if ((!strcmp(drive_table->id_model, id->model)) &&
+- ((strstr(drive_table->id_firmware, id->fw_rev)) ||
++ ((strstr(id->fw_rev, drive_table->id_firmware)) ||
+ (!strcmp(drive_table->id_firmware, "ALL"))))
+ return 1;
+ return 0;
+ }
+
+-EXPORT_SYMBOL_GPL(ide_in_drive_list);
+-
+ /**
+ * ide_dma_intr - IDE DMA interrupt handler
+ * @drive: the drive the interrupt is for
+@@ -205,7 +203,7 @@ int ide_build_sglist(ide_drive_t *drive,
+ ide_hwif_t *hwif = HWIF(drive);
+ struct scatterlist *sg = hwif->sg_table;
+
+- BUG_ON((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256);
++ BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256);
+
+ ide_map_sg(drive, rq);
+
+@@ -798,26 +796,23 @@ static int ide_release_dma_engine(ide_hw
+
+ static int ide_release_iomio_dma(ide_hwif_t *hwif)
+ {
+- if ((hwif->dma_extra) && (hwif->channel == 0))
+- release_region((hwif->dma_base + 16), hwif->dma_extra);
+ release_region(hwif->dma_base, 8);
+- if (hwif->dma_base2)
+- release_region(hwif->dma_base, 8);
++ if (hwif->extra_ports)
++ release_region(hwif->extra_base, hwif->extra_ports);
+ return 1;
+ }
+
+ /*
+ * Needed for allowing full modular support of ide-driver
+ */
+-int ide_release_dma (ide_hwif_t *hwif)
++int ide_release_dma(ide_hwif_t *hwif)
+ {
++ ide_release_dma_engine(hwif);
++
+ if (hwif->mmio == 2)
+ return 1;
+- if (hwif->chipset == ide_etrax100)
+- return 1;
+-
+- ide_release_dma_engine(hwif);
+- return ide_release_iomio_dma(hwif);
++ else
++ return ide_release_iomio_dma(hwif);
+ }
+
+ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
+@@ -829,10 +824,9 @@ static int ide_allocate_dma_engine(ide_h
+ if (hwif->dmatable_cpu)
+ return 0;
+
+- printk(KERN_ERR "%s: -- Error, unable to allocate%s DMA table(s).\n",
+- hwif->cds->name, !hwif->dmatable_cpu ? " CPU" : "");
++ printk(KERN_ERR "%s: -- Error, unable to allocate DMA table.\n",
++ hwif->cds->name);
+
+- ide_release_dma_engine(hwif);
+ return 1;
+ }
+
+@@ -840,9 +834,7 @@ static int ide_mapped_mmio_dma(ide_hwif_
+ {
+ printk(KERN_INFO " %s: MMIO-DMA ", hwif->name);
+
+- hwif->dma_base = base;
+- if (hwif->cds->extra && hwif->channel == 0)
+- hwif->dma_extra = hwif->cds->extra;
++ hwif->dma_base = base;
+
+ if(hwif->mate)
+ hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+@@ -854,29 +846,33 @@ static int ide_mapped_mmio_dma(ide_hwif_
+ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+ {
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx",
+- hwif->name, base, base + ports - 1);
++ hwif->name, base, base + ports - 1);
++
+ if (!request_region(base, ports, hwif->name)) {
+ printk(" -- Error, ports in use.\n");
+ return 1;
+ }
++
+ hwif->dma_base = base;
+- if ((hwif->cds->extra) && (hwif->channel == 0)) {
+- request_region(base+16, hwif->cds->extra, hwif->cds->name);
+- hwif->dma_extra = hwif->cds->extra;
++
++ if (hwif->cds->extra) {
++ hwif->extra_base = base + (hwif->channel ? 8 : 16);
++
++ if (!hwif->mate || !hwif->mate->extra_ports) {
++ if (!request_region(hwif->extra_base,
++ hwif->cds->extra, hwif->cds->name)) {
++ printk(" -- Error, extra ports in use.\n");
++ release_region(base, ports);
++ return 1;
++ }
++ hwif->extra_ports = hwif->cds->extra;
++ }
+ }
+-
++
+ if(hwif->mate)
+- hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
++ hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base:base;
+ else
+ hwif->dma_master = base;
+- if (hwif->dma_base2) {
+- if (!request_region(hwif->dma_base2, ports, hwif->name))
+- {
+- printk(" -- Error, secondary ports in use.\n");
+- release_region(base, ports);
+- return 1;
+- }
+- }
+ return 0;
+ }
+
+diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
+index adbe9f7..8ccee9c 100644
+--- a/drivers/ide/ide-floppy.c
++++ b/drivers/ide/ide-floppy.c
+@@ -588,7 +588,7 @@ static int idefloppy_do_end_request(ide_
+ /* Why does this happen? */
+ if (!rq)
+ return 0;
+- if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
++ if (!blk_special_request(rq)) {
+ /* our real local end request function */
+ ide_end_request(drive, uptodate, nsecs);
+ return 0;
+@@ -689,7 +689,7 @@ static void idefloppy_queue_pc_head (ide
+
+ ide_init_drive_cmd(rq);
+ rq->buffer = (char *) pc;
+- rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ;
++ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->rq_disk = floppy->disk;
+ (void) ide_do_drive_cmd(drive, rq, ide_preempt);
+ }
+@@ -1250,7 +1250,7 @@ static void idefloppy_create_rw_cmd (ide
+ pc->callback = &idefloppy_rw_callback;
+ pc->rq = rq;
+ pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
+- if (rq->flags & REQ_RW)
++ if (rq->cmd_flags & REQ_RW)
+ set_bit(PC_WRITING, &pc->flags);
+ pc->buffer = NULL;
+ pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
+@@ -1281,8 +1281,7 @@ static ide_startstop_t idefloppy_do_requ
+ idefloppy_pc_t *pc;
+ unsigned long block = (unsigned long)block_s;
+
+- debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
+- rq->rq_status,
++ debug_log(KERN_INFO "dev: %s, flags: %lx, errors: %d\n",
+ rq->rq_disk ? rq->rq_disk->disk_name : "?",
+ rq->flags, rq->errors);
+ debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+@@ -1303,7 +1302,7 @@ static ide_startstop_t idefloppy_do_requ
+ idefloppy_do_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+- if (rq->flags & REQ_CMD) {
++ if (blk_fs_request(rq)) {
+ if (((long)rq->sector % floppy->bs_factor) ||
+ (rq->nr_sectors % floppy->bs_factor)) {
+ printk("%s: unsupported r/w request size\n",
+@@ -1313,9 +1312,9 @@ static ide_startstop_t idefloppy_do_requ
+ }
+ pc = idefloppy_next_pc_storage(drive);
+ idefloppy_create_rw_cmd(floppy, pc, rq, block);
+- } else if (rq->flags & REQ_SPECIAL) {
++ } else if (blk_special_request(rq)) {
+ pc = (idefloppy_pc_t *) rq->buffer;
+- } else if (rq->flags & REQ_BLOCK_PC) {
++ } else if (blk_pc_request(rq)) {
+ pc = idefloppy_next_pc_storage(drive);
+ if (idefloppy_blockpc_cmd(floppy, pc, rq)) {
+ idefloppy_do_end_request(drive, 0, 0);
+@@ -1343,7 +1342,7 @@ static int idefloppy_queue_pc_tail (ide_
+
+ ide_init_drive_cmd (&rq);
+ rq.buffer = (char *) pc;
+- rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ;
++ rq.cmd_type = REQ_TYPE_SPECIAL;
+ rq.rq_disk = floppy->disk;
+
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
+index fb67952..2614f41 100644
+--- a/drivers/ide/ide-io.c
++++ b/drivers/ide/ide-io.c
+@@ -59,8 +59,6 @@ static int __ide_end_request(ide_drive_t
+ {
+ int ret = 1;
+
+- BUG_ON(!(rq->flags & REQ_STARTED));
+-
+ /*
+ * if failfast is set on a request, override number of sectors and
+ * complete the whole request right now
+@@ -82,7 +80,8 @@ static int __ide_end_request(ide_drive_t
+
+ if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ add_disk_randomness(rq->rq_disk);
+- blkdev_dequeue_request(rq);
++ if (!list_empty(&rq->queuelist))
++ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ end_that_request_last(rq, uptodate);
+ ret = 0;
+@@ -135,13 +134,14 @@ enum {
+ ide_pm_flush_cache = ide_pm_state_start_suspend,
+ idedisk_pm_standby,
+
+- idedisk_pm_idle = ide_pm_state_start_resume,
++ idedisk_pm_restore_pio = ide_pm_state_start_resume,
++ idedisk_pm_idle,
+ ide_pm_restore_dma,
+ };
+
+ static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
+ {
+- struct request_pm_state *pm = rq->end_io_data;
++ struct request_pm_state *pm = rq->data;
+
+ if (drive->media != ide_disk)
+ return;
+@@ -156,7 +156,10 @@ static void ide_complete_power_step(ide_
+ case idedisk_pm_standby: /* Suspend step 2 (standby) complete */
+ pm->pm_step = ide_pm_state_completed;
+ break;
+- case idedisk_pm_idle: /* Resume step 1 (idle) complete */
++ case idedisk_pm_restore_pio: /* Resume step 1 complete */
++ pm->pm_step = idedisk_pm_idle;
++ break;
++ case idedisk_pm_idle: /* Resume step 2 (idle) complete */
+ pm->pm_step = ide_pm_restore_dma;
+ break;
+ }
+@@ -164,14 +167,17 @@ static void ide_complete_power_step(ide_
+
+ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
+ {
+- struct request_pm_state *pm = rq->end_io_data;
++ struct request_pm_state *pm = rq->data;
+ ide_task_t *args = rq->special;
+
+ memset(args, 0, sizeof(*args));
+
+ if (drive->media != ide_disk) {
+- /* skip idedisk_pm_idle for ATAPI devices */
+- if (pm->pm_step == idedisk_pm_idle)
++ /*
++ * skip idedisk_pm_restore_pio and idedisk_pm_idle for ATAPI
++ * devices
++ */
++ if (pm->pm_step == idedisk_pm_restore_pio)
+ pm->pm_step = ide_pm_restore_dma;
+ }
+
+@@ -198,13 +204,19 @@ static ide_startstop_t ide_start_power_s
+ args->handler = &task_no_data_intr;
+ return do_rw_taskfile(drive, args);
+
+- case idedisk_pm_idle: /* Resume step 1 (idle) */
++ case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */
++ if (drive->hwif->tuneproc != NULL)
++ drive->hwif->tuneproc(drive, 255);
++ ide_complete_power_step(drive, rq, 0, 0);
++ return ide_stopped;
++
++ case idedisk_pm_idle: /* Resume step 2 (idle) */
+ args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
+ args->command_type = IDE_DRIVE_TASK_NO_DATA;
+ args->handler = task_no_data_intr;
+ return do_rw_taskfile(drive, args);
+
+- case ide_pm_restore_dma: /* Resume step 2 (restore DMA) */
++ case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */
+ /*
+ * Right now, all we do is call hwif->ide_dma_check(drive),
+ * we could be smarter and check for current xfer_speed
+@@ -244,7 +256,7 @@ int ide_end_dequeued_request(ide_drive_t
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+- BUG_ON(!(rq->flags & REQ_STARTED));
++ BUG_ON(!blk_rq_started(rq));
+
+ /*
+ * if failfast is set on a request, override number of sectors and
+@@ -366,7 +378,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
+ rq = HWGROUP(drive)->rq;
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+- if (rq->flags & REQ_DRIVE_CMD) {
++ if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
+ u8 *args = (u8 *) rq->buffer;
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+@@ -376,7 +388,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
+ args[1] = err;
+ args[2] = hwif->INB(IDE_NSECTOR_REG);
+ }
+- } else if (rq->flags & REQ_DRIVE_TASK) {
++ } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
+ u8 *args = (u8 *) rq->buffer;
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+@@ -390,7 +402,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
+ args[5] = hwif->INB(IDE_HCYL_REG);
+ args[6] = hwif->INB(IDE_SELECT_REG);
+ }
+- } else if (rq->flags & REQ_DRIVE_TASKFILE) {
++ } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ ide_task_t *args = (ide_task_t *) rq->special;
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+@@ -421,7 +433,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
+ }
+ }
+ } else if (blk_pm_request(rq)) {
+- struct request_pm_state *pm = rq->end_io_data;
++ struct request_pm_state *pm = rq->data;
+ #ifdef DEBUG_PM
+ printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
+ drive->name, rq->pm->pm_step, stat, err);
+@@ -587,7 +599,7 @@ ide_startstop_t ide_error (ide_drive_t *
+ return ide_stopped;
+
+ /* retry only "normal" I/O: */
+- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
++ if (!blk_fs_request(rq)) {
+ rq->errors = 1;
+ ide_end_drive_cmd(drive, stat, err);
+ return ide_stopped;
+@@ -638,7 +650,7 @@ ide_startstop_t ide_abort(ide_drive_t *d
+ return ide_stopped;
+
+ /* retry only "normal" I/O: */
+- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
++ if (!blk_fs_request(rq)) {
+ rq->errors = 1;
+ ide_end_drive_cmd(drive, BUSY_STAT, 0);
+ return ide_stopped;
+@@ -808,7 +820,7 @@ void ide_map_sg(ide_drive_t *drive, stru
+ if (hwif->sg_mapped) /* needed by ide-scsi */
+ return;
+
+- if ((rq->flags & REQ_DRIVE_TASKFILE) == 0) {
++ if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) {
+ hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
+ } else {
+ sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);
+@@ -844,7 +856,7 @@ static ide_startstop_t execute_drive_cmd
+ struct request *rq)
+ {
+ ide_hwif_t *hwif = HWIF(drive);
+- if (rq->flags & REQ_DRIVE_TASKFILE) {
++ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ ide_task_t *args = rq->special;
+
+ if (!args)
+@@ -866,7 +878,7 @@ static ide_startstop_t execute_drive_cmd
+ if (args->tf_out_flags.all != 0)
+ return flagged_taskfile(drive, args);
+ return do_rw_taskfile(drive, args);
+- } else if (rq->flags & REQ_DRIVE_TASK) {
++ } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
+ u8 *args = rq->buffer;
+ u8 sel;
+
+@@ -892,7 +904,7 @@ static ide_startstop_t execute_drive_cmd
+ hwif->OUTB(sel, IDE_SELECT_REG);
+ ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ return ide_started;
+- } else if (rq->flags & REQ_DRIVE_CMD) {
++ } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
+ u8 *args = rq->buffer;
+
+ if (!args)
+@@ -933,7 +945,7 @@ done:
+
+ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
+ {
+- struct request_pm_state *pm = rq->end_io_data;
++ struct request_pm_state *pm = rq->data;
+
+ if (blk_pm_suspend_request(rq) &&
+ pm->pm_step == ide_pm_state_start_suspend)
+@@ -980,7 +992,7 @@ static ide_startstop_t start_request (id
+ ide_startstop_t startstop;
+ sector_t block;
+
+- BUG_ON(!(rq->flags & REQ_STARTED));
++ BUG_ON(!blk_rq_started(rq));
+
+ #ifdef DEBUG
+ printk("%s: start_request: current=0x%08lx\n",
+@@ -1013,12 +1025,12 @@ static ide_startstop_t start_request (id
+ if (!drive->special.all) {
+ ide_driver_t *drv;
+
+- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
+- return execute_drive_cmd(drive, rq);
+- else if (rq->flags & REQ_DRIVE_TASKFILE)
++ if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
++ rq->cmd_type == REQ_TYPE_ATA_TASK ||
++ rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+ return execute_drive_cmd(drive, rq);
+ else if (blk_pm_request(rq)) {
+- struct request_pm_state *pm = rq->end_io_data;
++ struct request_pm_state *pm = rq->data;
+ #ifdef DEBUG_PM
+ printk("%s: start_power_step(step: %d)\n",
+ drive->name, rq->pm->pm_step);
+@@ -1264,7 +1276,7 @@ static void ide_do_request (ide_hwgroup_
+ * We count how many times we loop here to make sure we service
+ * all drives in the hwgroup without looping for ever
+ */
+- if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) {
++ if (drive->blocked && !blk_pm_request(rq) && !(rq->cmd_flags & REQ_PREEMPT)) {
+ drive = drive->next ? drive->next : hwgroup->drive;
+ if (loops++ < 4 && !blk_queue_plugged(drive->queue))
+ goto again;
+@@ -1346,6 +1358,10 @@ static ide_startstop_t ide_dma_timeout_r
+ * make sure request is sane
+ */
+ rq = HWGROUP(drive)->rq;
++
++ if (!rq)
++ goto out;
++
+ HWGROUP(drive)->rq = NULL;
+
+ rq->errors = 0;
+@@ -1546,7 +1562,7 @@ static void unexpected_intr (int irq, id
+ * on the hwgroup and the process begins again.
+ */
+
+-irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t ide_intr (int irq, void *dev_id)
+ {
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
+@@ -1670,7 +1686,7 @@ irqreturn_t ide_intr (int irq, void *dev
+ void ide_init_drive_cmd (struct request *rq)
+ {
+ memset(rq, 0, sizeof(*rq));
+- rq->flags = REQ_DRIVE_CMD;
++ rq->cmd_type = REQ_TYPE_ATA_CMD;
+ rq->ref_count = 1;
+ }
+
+@@ -1710,7 +1726,6 @@ int ide_do_drive_cmd (ide_drive_t *drive
+ int must_wait = (action == ide_wait || action == ide_head_wait);
+
+ rq->errors = 0;
+- rq->rq_status = RQ_ACTIVE;
+
+ /*
+ * we need to hold an extra reference to request for safe inspection
+@@ -1718,7 +1733,7 @@ int ide_do_drive_cmd (ide_drive_t *drive
+ */
+ if (must_wait) {
+ rq->ref_count++;
+- rq->waiting = &wait;
++ rq->end_io_data = &wait;
+ rq->end_io = blk_end_sync_rq;
+ }
+
+@@ -1727,7 +1742,7 @@ int ide_do_drive_cmd (ide_drive_t *drive
+ hwgroup->rq = NULL;
+ if (action == ide_preempt || action == ide_head_wait) {
+ where = ELEVATOR_INSERT_FRONT;
+- rq->flags |= REQ_PREEMPT;
++ rq->cmd_flags |= REQ_PREEMPT;
+ }
+ __elv_add_request(drive->queue, rq, where, 0);
+ ide_do_request(hwgroup, IDE_NO_IRQ);
+@@ -1736,7 +1751,6 @@ int ide_do_drive_cmd (ide_drive_t *drive
+ err = 0;
+ if (must_wait) {
+ wait_for_completion(&wait);
+- rq->waiting = NULL;
+ if (rq->errors)
+ err = -EIO;
+
+diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
+index 77703ac..badde63 100644
+--- a/drivers/ide/ide-iops.c
++++ b/drivers/ide/ide-iops.c
+@@ -998,6 +998,7 @@ static ide_startstop_t atapi_reset_pollf
+ }
+ /* done polling */
+ hwgroup->polling = 0;
++ hwgroup->resetting = 0;
+ return ide_stopped;
+ }
+
+@@ -1057,6 +1058,7 @@ static ide_startstop_t reset_pollfunc (i
+ }
+ }
+ hwgroup->polling = 0; /* done polling */
++ hwgroup->resetting = 0; /* done reset attempt */
+ return ide_stopped;
+ }
+
+@@ -1143,6 +1145,7 @@ static ide_startstop_t do_reset1 (ide_dr
+
+ /* For an ATAPI device, first try an ATAPI SRST. */
+ if (drive->media != ide_disk && !do_not_try_atapi) {
++ hwgroup->resetting = 1;
+ pre_reset(drive);
+ SELECT_DRIVE(drive);
+ udelay (20);
+@@ -1168,6 +1171,7 @@ static ide_startstop_t do_reset1 (ide_dr
+ return ide_stopped;
+ }
+
++ hwgroup->resetting = 1;
+ /*
+ * Note that we also set nIEN while resetting the device,
+ * to mask unwanted interrupts from the interface during the reset.
+diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
+index 1feff23..8237d89 100644
+--- a/drivers/ide/ide-lib.c
++++ b/drivers/ide/ide-lib.c
+@@ -71,75 +71,96 @@ EXPORT_SYMBOL(ide_xfer_verbose);
+ /**
+ * ide_dma_speed - compute DMA speed
+ * @drive: drive
+- * @mode; intended mode
++ * @mode: modes available
+ *
+ * Checks the drive capabilities and returns the speed to use
+- * for the transfer. Returns -1 if the requested mode is unknown
+- * (eg PIO)
++ * for the DMA transfer. Returns 0 if the drive is incapable
++ * of DMA transfers.
+ */
+
+ u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
+ {
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
++ u8 ultra_mask, mwdma_mask, swdma_mask;
+ u8 speed = 0;
+
+ if (drive->media != ide_disk && hwif->atapi_dma == 0)
+ return 0;
+
+- switch(mode) {
+- case 0x04:
+- if ((id->dma_ultra & 0x0040) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_6; break; }
+- case 0x03:
+- if ((id->dma_ultra & 0x0020) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_5; break; }
+- case 0x02:
+- if ((id->dma_ultra & 0x0010) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_4; break; }
+- if ((id->dma_ultra & 0x0008) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_3; break; }
+- case 0x01:
+- if ((id->dma_ultra & 0x0004) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_2; break; }
+- if ((id->dma_ultra & 0x0002) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_1; break; }
+- if ((id->dma_ultra & 0x0001) &&
+- (id->dma_ultra & hwif->ultra_mask))
+- { speed = XFER_UDMA_0; break; }
+- case 0x00:
+- if ((id->dma_mword & 0x0004) &&
+- (id->dma_mword & hwif->mwdma_mask))
+- { speed = XFER_MW_DMA_2; break; }
+- if ((id->dma_mword & 0x0002) &&
+- (id->dma_mword & hwif->mwdma_mask))
+- { speed = XFER_MW_DMA_1; break; }
+- if ((id->dma_mword & 0x0001) &&
+- (id->dma_mword & hwif->mwdma_mask))
+- { speed = XFER_MW_DMA_0; break; }
+- if ((id->dma_1word & 0x0004) &&
+- (id->dma_1word & hwif->swdma_mask))
+- { speed = XFER_SW_DMA_2; break; }
+- if ((id->dma_1word & 0x0002) &&
+- (id->dma_1word & hwif->swdma_mask))
+- { speed = XFER_SW_DMA_1; break; }
+- if ((id->dma_1word & 0x0001) &&
+- (id->dma_1word & hwif->swdma_mask))
+- { speed = XFER_SW_DMA_0; break; }
+- }
++ /* Capable of UltraDMA modes? */
++ ultra_mask = id->dma_ultra & hwif->ultra_mask;
++
++ if (!(id->field_valid & 4))
++ mode = 0; /* fallback to MW/SW DMA if no UltraDMA */
++
++ switch (mode) {
++ case 4:
++ if (ultra_mask & 0x40) {
++ speed = XFER_UDMA_6;
++ break;
++ }
++ case 3:
++ if (ultra_mask & 0x20) {
++ speed = XFER_UDMA_5;
++ break;
++ }
++ case 2:
++ if (ultra_mask & 0x10) {
++ speed = XFER_UDMA_4;
++ break;
++ }
++ if (ultra_mask & 0x08) {
++ speed = XFER_UDMA_3;
++ break;
++ }
++ case 1:
++ if (ultra_mask & 0x04) {
++ speed = XFER_UDMA_2;
++ break;
++ }
++ if (ultra_mask & 0x02) {
++ speed = XFER_UDMA_1;
++ break;
++ }
++ if (ultra_mask & 0x01) {
++ speed = XFER_UDMA_0;
++ break;
++ }
++ case 0:
++ mwdma_mask = id->dma_mword & hwif->mwdma_mask;
+
+-// printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
+-// __FUNCTION__, drive->name, mode, speed);
++ if (mwdma_mask & 0x04) {
++ speed = XFER_MW_DMA_2;
++ break;
++ }
++ if (mwdma_mask & 0x02) {
++ speed = XFER_MW_DMA_1;
++ break;
++ }
++ if (mwdma_mask & 0x01) {
++ speed = XFER_MW_DMA_0;
++ break;
++ }
++
++ swdma_mask = id->dma_1word & hwif->swdma_mask;
++
++ if (swdma_mask & 0x04) {
++ speed = XFER_SW_DMA_2;
++ break;
++ }
++ if (swdma_mask & 0x02) {
++ speed = XFER_SW_DMA_1;
++ break;
++ }
++ if (swdma_mask & 0x01) {
++ speed = XFER_SW_DMA_0;
++ break;
++ }
++ }
+
+ return speed;
+ }
+-
+ EXPORT_SYMBOL(ide_dma_speed);
+
+
+@@ -456,13 +477,14 @@ static void ide_dump_opcode(ide_drive_t
+ spin_unlock(&ide_lock);
+ if (!rq)
+ return;
+- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
++ if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
++ rq->cmd_type == REQ_TYPE_ATA_TASK) {
+ char *args = rq->buffer;
+ if (args) {
+ opcode = args[0];
+ found = 1;
+ }
+- } else if (rq->flags & REQ_DRIVE_TASKFILE) {
++ } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ ide_task_t *args = rq->special;
+ if (args) {
+ task_struct_t *tf = (task_struct_t *) args->tfRegister;
+diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
+index 9cadf01..dad9c47 100644
+--- a/drivers/ide/ide-probe.c
++++ b/drivers/ide/ide-probe.c
+@@ -623,6 +623,8 @@ static void hwif_release_dev (struct dev
+
+ static void hwif_register (ide_hwif_t *hwif)
+ {
++ int ret;
++
+ /* register with global device tree */
+ strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
+ hwif->gendev.driver_data = hwif;
+@@ -634,7 +636,10 @@ static void hwif_register (ide_hwif_t *h
+ hwif->gendev.parent = NULL;
+ }
+ hwif->gendev.release = hwif_release_dev;
+- device_register(&hwif->gendev);
++ ret = device_register(&hwif->gendev);
++ if (ret < 0)
++ printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
++ __FUNCTION__, ret);
+ }
+
+ static int wait_hwif_ready(ide_hwif_t *hwif)
+@@ -884,13 +889,19 @@ int probe_hwif_init_with_fixup(ide_hwif_
+
+ if (hwif->present) {
+ u16 unit = 0;
++ int ret;
++
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ /* For now don't attach absent drives, we may
+ want them on default or a new "empty" class
+ for hotplug reprobing ? */
+ if (drive->present) {
+- device_register(&drive->gendev);
++ ret = device_register(&drive->gendev);
++ if (ret < 0)
++ printk(KERN_WARNING "IDE: %s: "
++ "device_register error: %d\n",
++ __FUNCTION__, ret);
+ }
+ }
+ }
+@@ -1409,8 +1420,14 @@ int ideprobe_init (void)
+ if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
+ hwif->chipset = ide_generic;
+ for (unit = 0; unit < MAX_DRIVES; ++unit)
+- if (hwif->drives[unit].present)
+- device_register(&hwif->drives[unit].gendev);
++ if (hwif->drives[unit].present) {
++ int ret = device_register(
++ &hwif->drives[unit].gendev);
++ if (ret < 0)
++ printk(KERN_WARNING "IDE: %s: "
++ "device_register error: %d\n",
++ __FUNCTION__, ret);
++ }
+ }
+ }
+ return 0;
+diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
+index 41b74b1..aa049da 100644
+--- a/drivers/ide/ide-proc.c
++++ b/drivers/ide/ide-proc.c
+@@ -326,15 +326,24 @@ static int ide_replace_subdriver(ide_dri
+ {
+ struct device *dev = &drive->gendev;
+ int ret = 1;
++ int err;
+
+ down_write(&dev->bus->subsys.rwsem);
+ device_release_driver(dev);
+ /* FIXME: device can still be in use by previous driver */
+ strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
+- device_attach(dev);
++ err = device_attach(dev);
++ if (err < 0)
++ printk(KERN_WARNING "IDE: %s: device_attach error: %d\n",
++ __FUNCTION__, err);
+ drive->driver_req[0] = 0;
+- if (dev->driver == NULL)
+- device_attach(dev);
++ if (dev->driver == NULL) {
++ err = device_attach(dev);
++ if (err < 0)
++ printk(KERN_WARNING
++ "IDE: %s: device_attach(2) error: %d\n",
++ __FUNCTION__, err);
++ }
+ if (dev->driver && !strcmp(dev->driver->name, driver))
+ ret = 0;
+ up_write(&dev->bus->subsys.rwsem);
+@@ -526,7 +535,12 @@ static int proc_print_driver(struct devi
+
+ static int ide_drivers_show(struct seq_file *s, void *p)
+ {
+- bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
++ int err;
++
++ err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
++ if (err < 0)
++ printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
++ __FUNCTION__, err);
+ return 0;
+ }
+
+diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
+index 7067ab9..e2f4bb5 100644
+--- a/drivers/ide/ide-tape.c
++++ b/drivers/ide/ide-tape.c
+@@ -1776,7 +1776,7 @@ static void idetape_create_request_sense
+ static void idetape_init_rq(struct request *rq, u8 cmd)
+ {
+ memset(rq, 0, sizeof(*rq));
+- rq->flags = REQ_SPECIAL;
++ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd[0] = cmd;
+ }
+
+@@ -2423,8 +2423,8 @@ static ide_startstop_t idetape_do_reques
+ #if IDETAPE_DEBUG_LOG
+ #if 0
+ if (tape->debug_level >= 5)
+- printk(KERN_INFO "ide-tape: rq_status: %d, "
+- "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status,
++ printk(KERN_INFO "ide-tape: %d, "
++ "dev: %s, cmd: %ld, errors: %d\n",
+ rq->rq_disk->disk_name, rq->cmd[0], rq->errors);
+ #endif
+ if (tape->debug_level >= 2)
+@@ -2433,12 +2433,12 @@ static ide_startstop_t idetape_do_reques
+ rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+ #endif /* IDETAPE_DEBUG_LOG */
+
+- if ((rq->flags & REQ_SPECIAL) == 0) {
++ if (!blk_special_request(rq)) {
+ /*
+ * We do not support buffer cache originated requests.
+ */
+ printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
+- "request queue (%ld)\n", drive->name, rq->flags);
++ "request queue (%d)\n", drive->name, rq->cmd_type);
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+@@ -2764,16 +2764,16 @@ static void idetape_add_stage_tail (ide_
+ */
+ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
+ {
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ idetape_tape_t *tape = drive->driver_data;
+
+ #if IDETAPE_DEBUG_BUGS
+- if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) {
++ if (rq == NULL || !blk_special_request(rq)) {
+ printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+ return;
+ }
+ #endif /* IDETAPE_DEBUG_BUGS */
+- rq->waiting = &wait;
++ rq->end_io_data = &wait;
+ rq->end_io = blk_end_sync_rq;
+ spin_unlock_irq(&tape->spinlock);
+ wait_for_completion(&wait);
+diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
+index 97a9244..30175c7 100644
+--- a/drivers/ide/ide-taskfile.c
++++ b/drivers/ide/ide-taskfile.c
+@@ -363,7 +363,7 @@ static ide_startstop_t task_error(ide_dr
+
+ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+ {
+- if (rq->flags & REQ_DRIVE_TASKFILE) {
++ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ ide_task_t *task = rq->special;
+
+ if (task->tf_out_flags.all) {
+@@ -474,7 +474,7 @@ static int ide_diag_taskfile(ide_drive_t
+ struct request rq;
+
+ memset(&rq, 0, sizeof(rq));
+- rq.flags = REQ_DRIVE_TASKFILE;
++ rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+ rq.buffer = buf;
+
+ /*
+@@ -499,7 +499,7 @@ static int ide_diag_taskfile(ide_drive_t
+ rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
+
+ if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+- rq.flags |= REQ_RW;
++ rq.cmd_flags |= REQ_RW;
+ }
+
+ rq.special = args;
+@@ -524,8 +524,8 @@ int ide_taskfile_ioctl (ide_drive_t *dri
+ task_ioreg_t *hobsptr = args.hobRegister;
+ int err = 0;
+ int tasksize = sizeof(struct ide_task_request_s);
+- int taskin = 0;
+- int taskout = 0;
++ unsigned int taskin = 0;
++ unsigned int taskout = 0;
+ u8 io_32bit = drive->io_32bit;
+ char __user *buf = (char __user *)arg;
+
+@@ -538,8 +538,13 @@ int ide_taskfile_ioctl (ide_drive_t *dri
+ return -EFAULT;
+ }
+
+- taskout = (int) req_task->out_size;
+- taskin = (int) req_task->in_size;
++ taskout = req_task->out_size;
++ taskin = req_task->in_size;
++
++ if (taskin > 65536 || taskout > 65536) {
++ err = -EINVAL;
++ goto abort;
++ }
+
+ if (taskout) {
+ int outtotal = tasksize;
+@@ -737,7 +742,7 @@ static int ide_wait_cmd_task(ide_drive_t
+ struct request rq;
+
+ ide_init_drive_cmd(&rq);
+- rq.flags = REQ_DRIVE_TASK;
++ rq.cmd_type = REQ_TYPE_ATA_TASK;
+ rq.buffer = buf;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+ }
+diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
+index defd4b4..287a662 100644
+--- a/drivers/ide/ide.c
++++ b/drivers/ide/ide.c
+@@ -450,7 +450,7 @@ void ide_hwif_release_regions(ide_hwif_t
+ * @hwif: hwif to update
+ * @tmp_hwif: template
+ *
+- * Restore hwif to a previous state by copying most settngs
++ * Restore hwif to a previous state by copying most settings
+ * from the template.
+ */
+
+@@ -539,9 +539,10 @@ static void ide_hwif_restore(ide_hwif_t
+ hwif->dma_vendor3 = tmp_hwif->dma_vendor3;
+ hwif->dma_prdtable = tmp_hwif->dma_prdtable;
+
+- hwif->dma_extra = tmp_hwif->dma_extra;
+ hwif->config_data = tmp_hwif->config_data;
+ hwif->select_data = tmp_hwif->select_data;
++ hwif->extra_base = tmp_hwif->extra_base;
++ hwif->extra_ports = tmp_hwif->extra_ports;
+ hwif->autodma = tmp_hwif->autodma;
+ hwif->udma_four = tmp_hwif->udma_four;
+ hwif->no_dsc = tmp_hwif->no_dsc;
+@@ -550,7 +551,7 @@ static void ide_hwif_restore(ide_hwif_t
+ }
+
+ /**
+- * ide_unregister - free an ide interface
++ * ide_unregister - free an IDE interface
+ * @index: index of interface (will change soon to a pointer)
+ *
+ * Perform the final unregister of an IDE interface. At the moment
+@@ -563,8 +564,8 @@ static void ide_hwif_restore(ide_hwif_t
+ * deadlocking the IDE layer. The shutdown callback is called
+ * before we take the lock and free resources. It is up to the
+ * caller to be sure there is no pending I/O here, and that
+- * the interfce will not be reopened (present/vanishing locking
+- * isnt yet done btw). After we commit to the final kill we
++ * the interface will not be reopened (present/vanishing locking
++ * isn't yet done BTW). After we commit to the final kill we
+ * call the cleanup callback with the ide locks held.
+ *
+ * Unregister restores the hwif structures to the default state.
+@@ -674,6 +675,9 @@ void ide_unregister(unsigned int index)
+ hwif->dma_status = 0;
+ hwif->dma_vendor3 = 0;
+ hwif->dma_prdtable = 0;
++
++ hwif->extra_base = 0;
++ hwif->extra_ports = 0;
+ }
+
+ /* copy original settings */
+@@ -1207,7 +1211,7 @@ int system_bus_clock (void)
+
+ EXPORT_SYMBOL(system_bus_clock);
+
+-static int generic_ide_suspend(struct device *dev, pm_message_t state)
++static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
+ {
+ ide_drive_t *drive = dev->driver_data;
+ struct request rq;
+@@ -1217,11 +1221,13 @@ static int generic_ide_suspend(struct de
+ memset(&rq, 0, sizeof(rq));
+ memset(&rqpm, 0, sizeof(rqpm));
+ memset(&args, 0, sizeof(args));
+- rq.flags = REQ_PM_SUSPEND;
++ rq.cmd_type = REQ_TYPE_PM_SUSPEND;
+ rq.special = &args;
+- rq.end_io_data = &rqpm;
++ rq.data = &rqpm;
+ rqpm.pm_step = ide_pm_state_start_suspend;
+- rqpm.pm_state = state.event;
++ if (mesg.event == PM_EVENT_PRETHAW)
++ mesg.event = PM_EVENT_FREEZE;
++ rqpm.pm_state = mesg.event;
+
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+ }
+@@ -1236,9 +1242,9 @@ static int generic_ide_resume(struct dev
+ memset(&rq, 0, sizeof(rq));
+ memset(&rqpm, 0, sizeof(rqpm));
+ memset(&args, 0, sizeof(args));
+- rq.flags = REQ_PM_RESUME;
++ rq.cmd_type = REQ_TYPE_PM_RESUME;
+ rq.special = &args;
+- rq.end_io_data = &rqpm;
++ rq.data = &rqpm;
+ rqpm.pm_step = ide_pm_state_start_resume;
+ rqpm.pm_state = PM_EVENT_ON;
+
+@@ -1358,6 +1364,11 @@ int generic_ide_ioctl(ide_drive_t *drive
+
+ spin_lock_irqsave(&ide_lock, flags);
+
++ if (HWGROUP(drive)->resetting) {
++ spin_unlock_irqrestore(&ide_lock, flags);
++ return -EBUSY;
++ }
++
+ ide_abort(drive, "drive reset");
+
+ BUG_ON(HWGROUP(drive)->handler);
+@@ -1991,10 +2002,16 @@ EXPORT_SYMBOL_GPL(ide_bus_type);
+ */
+ static int __init ide_init(void)
+ {
++ int ret;
++
+ printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
+ system_bus_speed = ide_system_bus_speed();
+
+- bus_register(&ide_bus_type);
++ ret = bus_register(&ide_bus_type);
++ if (ret < 0) {
++ printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
++ return ret;
++ }
+
+ init_ide_data();
+
+diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
+index aebecd8..b1d5291 100644
+--- a/drivers/ide/legacy/hd.c
++++ b/drivers/ide/legacy/hd.c
+@@ -626,7 +626,7 @@ repeat:
+ req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ",
+ cyl, head, sec, nsect, req->buffer);
+ #endif
+- if (req->flags & REQ_CMD) {
++ if (blk_fs_request(req)) {
+ switch (rq_data_dir(req)) {
+ case READ:
+ hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr);
+@@ -673,7 +673,7 @@ static int hd_getgeo(struct block_device
+ * be forgotten about...
+ */
+
+-static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hd_interrupt(int irq, void *dev_id)
+ {
+ void (*handler)(void) = do_hd;
+
+diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
+index 602797a..bef4759 100644
+--- a/drivers/ide/legacy/ide-cs.c
++++ b/drivers/ide/legacy/ide-cs.c
+@@ -120,7 +120,7 @@ static int ide_probe(struct pcmcia_devic
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = 3;
+- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
++ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+@@ -398,12 +398,17 @@ static struct pcmcia_device_id ide_ids[]
+ 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("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
+ PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 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("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
++ PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
++ PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
++ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+ PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
+diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
+index d655da7..b1730d7 100644
+--- a/drivers/ide/legacy/macide.c
++++ b/drivers/ide/legacy/macide.c
+@@ -78,7 +78,7 @@ int macide_ack_intr(ide_hwif_t* hwif)
+ }
+
+ #ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+-static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void macide_mediabay_interrupt(int irq, void *dev_id)
+ {
+ int state = baboon->mb_status & 0x04;
+
+diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
+index 71f27e9..c7854ea 100644
+--- a/drivers/ide/mips/au1xxx-ide.c
++++ b/drivers/ide/mips/au1xxx-ide.c
+@@ -476,13 +476,13 @@ static int auide_dma_lostirq(ide_drive_t
+ return 0;
+ }
+
+-static void auide_ddma_tx_callback(int irq, void *param, struct pt_regs *regs)
++static void auide_ddma_tx_callback(int irq, void *param)
+ {
+ _auide_hwif *ahwif = (_auide_hwif*)param;
+ ahwif->drive->waiting_for_dma = 0;
+ }
+
+-static void auide_ddma_rx_callback(int irq, void *param, struct pt_regs *regs)
++static void auide_ddma_rx_callback(int irq, void *param)
+ {
+ _auide_hwif *ahwif = (_auide_hwif*)param;
+ ahwif->drive->waiting_for_dma = 0;
+diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
+index 66f6064..09c9e79 100644
+--- a/drivers/ide/mips/swarm.c
++++ b/drivers/ide/mips/swarm.c
+@@ -4,6 +4,7 @@
+ * Author: Manish Lachwani, mlachwani at mvista.com
+ * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
+ * Author: Maciej W. Rozycki <macro at mips.com>
++ * Copyright (c) 2006 Maciej W. Rozycki
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -127,6 +128,7 @@ static int __devinit swarm_ide_probe(str
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ hwif->irq = hwif->hw.irq;
+
++ probe_hwif_init(hwif);
+ dev_set_drvdata(dev, hwif);
+
+ return 0;
+diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
+index f35d684..fef0896 100644
+--- a/drivers/ide/pci/Makefile
++++ b/drivers/ide/pci/Makefile
+@@ -12,8 +12,8 @@ obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c
+ 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_JMICRON) += jmicron.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/amd74xx.c b/drivers/ide/pci/amd74xx.c
+index 2b0ea8b..753fe0e 100644
+--- a/drivers/ide/pci/amd74xx.c
++++ b/drivers/ide/pci/amd74xx.c
+@@ -75,6 +75,7 @@ static struct amd_ide_chip {
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, AMD_UDMA_133 },
++ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 },
+ { 0 }
+ };
+@@ -491,7 +492,8 @@ static ide_pci_device_t amd74xx_chipsets
+ /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
+ /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
+ /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"),
+- /* 19 */ DECLARE_AMD_DEV("AMD5536"),
++ /* 19 */ DECLARE_NV_DEV("NFORCE-MCP67"),
++ /* 20 */ DECLARE_AMD_DEV("AMD5536"),
+ };
+
+ static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+@@ -530,7 +532,8 @@ static struct pci_device_id amd74xx_pci_
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 },
++ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 },
++ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20 },
+ { 0, },
+ };
+ MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
+diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
+index a574de5..d55b938 100644
+--- a/drivers/ide/pci/atiixp.c
++++ b/drivers/ide/pci/atiixp.c
+@@ -318,6 +318,20 @@ static void __devinit init_hwif_atiixp(i
+ hwif->drives[0].autodma = hwif->autodma;
+ }
+
++static void __devinit init_hwif_sb600_legacy(ide_hwif_t *hwif)
++{
++
++ hwif->atapi_dma = 1;
++ hwif->ultra_mask = 0x7f;
++ hwif->mwdma_mask = 0x07;
++ hwif->swdma_mask = 0x07;
++
++ if (!noautodma)
++ hwif->autodma = 1;
++ hwif->drives[0].autodma = hwif->autodma;
++ hwif->drives[1].autodma = hwif->autodma;
++}
++
+ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
+ { /* 0 */
+ .name = "ATIIXP",
+@@ -326,6 +340,12 @@ static ide_pci_device_t atiixp_pci_info[
+ .autodma = AUTODMA,
+ .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
+ .bootable = ON_BOARD,
++ },{ /* 1 */
++ .name = "ATI SB600 SATA Legacy IDE",
++ .init_hwif = init_hwif_sb600_legacy,
++ .channels = 2,
++ .autodma = AUTODMA,
++ .bootable = ON_BOARD,
+ }
+ };
+
+@@ -348,6 +368,7 @@ static struct pci_device_id atiixp_pci_t
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, PCI_ANY_ID, PCI_ANY_ID, (PCI_CLASS_STORAGE_IDE<<8)|0x8a, 0xffff05, 1},
+ { 0, },
+ };
+ MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
+diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
+index 380bb28..ae405fa 100644
+--- a/drivers/ide/pci/cs5530.c
++++ b/drivers/ide/pci/cs5530.c
+@@ -222,23 +222,23 @@ static unsigned int __devinit init_chips
+ unsigned long flags;
+
+ dev = NULL;
+- while ((dev = pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
++ while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
+ switch (dev->device) {
+ case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+- master_0 = dev;
++ master_0 = pci_dev_get(dev);
+ break;
+ case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+- cs5530_0 = dev;
++ cs5530_0 = pci_dev_get(dev);
+ break;
+ }
+ }
+ if (!master_0) {
+ printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
+- return 0;
++ goto out;
+ }
+ if (!cs5530_0) {
+ printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
+- return 0;
++ goto out;
+ }
+
+ spin_lock_irqsave(&ide_lock, flags);
+@@ -296,6 +296,9 @@ static unsigned int __devinit init_chips
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
++out:
++ pci_dev_put(master_0);
++ pci_dev_put(cs5530_0);
+ return 0;
+ }
+
+diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
+index 120929f..64330c4 100644
+--- a/drivers/ide/pci/cy82c693.c
++++ b/drivers/ide/pci/cy82c693.c
+@@ -281,7 +281,7 @@ static void cy82c693_tune_drive (ide_dri
+
+ /* select primary or secondary channel */
+ if (hwif->index > 0) { /* drive is on the secondary channel */
+- dev = pci_find_slot(dev->bus->number, dev->devfn+1);
++ dev = pci_get_slot(dev->bus, dev->devfn+1);
+ if (!dev) {
+ printk(KERN_ERR "%s: tune_drive: "
+ "Cannot find secondary interface!\n",
+@@ -500,8 +500,9 @@ static int __devinit cy82c693_init_one(s
+ Function 1 is primary IDE channel, function 2 - secondary. */
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+ PCI_FUNC(dev->devfn) == 1) {
+- dev2 = pci_find_slot(dev->bus->number, dev->devfn + 1);
++ dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
+ ret = ide_setup_pci_devices(dev, dev2, d);
++ /* We leak pci refs here but thats ok - we can't be unloaded */
+ }
+ return ret;
+ }
+diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
+index 78810ba..9f30688 100644
+--- a/drivers/ide/pci/generic.c
++++ b/drivers/ide/pci/generic.c
+@@ -23,7 +23,6 @@
+
+ #undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+ #include <linux/types.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -41,6 +40,10 @@
+
+ static int ide_generic_all; /* Set to claim all devices */
+
++/*
++ * the module_param_named() was added for the modular case
++ * the __setup() is left as compatibility for existing setups
++ */
+ #ifndef MODULE
+ static int __init ide_generic_all_on(char *unused)
+ {
+@@ -50,6 +53,8 @@ static int __init ide_generic_all_on(cha
+ }
+ __setup("all-generic-ide", ide_generic_all_on);
+ #endif
++module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
++MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
+
+ static void __devinit init_hwif_generic (ide_hwif_t *hwif)
+ {
+@@ -242,13 +247,17 @@ static int __devinit generic_init_one(st
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ goto out;
+
+- if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1)
+- goto out;
++ if (dev->vendor == PCI_VENDOR_ID_JMICRON) {
++ if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 && PCI_FUNC(dev->devfn) != 1)
++ goto out;
++ }
+
+- pci_read_config_word(dev, PCI_COMMAND, &command);
+- if (!(command & PCI_COMMAND_IO)) {
+- printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
+- goto out;
++ if (dev->vendor != PCI_VENDOR_ID_JMICRON) {
++ pci_read_config_word(dev, PCI_COMMAND, &command);
++ if (!(command & PCI_COMMAND_IO)) {
++ printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
++ goto out;
++ }
+ }
+ ret = ide_setup_pci_device(dev, d);
+ out:
+diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
+deleted file mode 100644
+index 0fc89fa..0000000
+--- a/drivers/ide/pci/it8172.c
++++ /dev/null
+@@ -1,307 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * IT8172 IDE controller support
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at 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.
+- *
+- * 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/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/ioport.h>
+-#include <linux/pci.h>
+-#include <linux/hdreg.h>
+-#include <linux/ide.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-
+-#include <asm/io.h>
+-#include <asm/it8172/it8172_int.h>
+-
+-/*
+- * Prototypes
+- */
+-static u8 it8172_ratemask (ide_drive_t *drive)
+-{
+- return 1;
+-}
+-
+-static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
+-{
+- ide_hwif_t *hwif = HWIF(drive);
+- struct pci_dev *dev = hwif->pci_dev;
+- int is_slave = (&hwif->drives[1] == drive);
+- unsigned long flags;
+- u16 drive_enables;
+- u32 drive_timing;
+-
+- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+- spin_lock_irqsave(&ide_lock, flags);
+- pci_read_config_word(dev, 0x40, &drive_enables);
+- pci_read_config_dword(dev, 0x44, &drive_timing);
+-
+- /*
+- * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+- * are being left at the default values of 8 PCI clocks (242 nsec
+- * for a 33 MHz clock). These can be safely shortened at higher
+- * PIO modes. The DIOR/DIOW pulse width and recovery times only
+- * apply to PIO modes, not to the DMA modes.
+- */
+-
+- /*
+- * Enable port 0x44. The IT8172G spec is confused; it calls
+- * this register the "Slave IDE Timing Register", but in fact,
+- * it controls timing for both master and slave drives.
+- */
+- drive_enables |= 0x4000;
+-
+- if (is_slave) {
+- drive_enables &= 0xc006;
+- if (pio > 1)
+- /* enable prefetch and IORDY sample-point */
+- drive_enables |= 0x0060;
+- } else {
+- drive_enables &= 0xc060;
+- if (pio > 1)
+- /* enable prefetch and IORDY sample-point */
+- drive_enables |= 0x0006;
+- }
+-
+- pci_write_config_word(dev, 0x40, drive_enables);
+- spin_unlock_irqrestore(&ide_lock, flags);
+-}
+-
+-static u8 it8172_dma_2_pio (u8 xfer_rate)
+-{
+- switch(xfer_rate) {
+- case XFER_UDMA_5:
+- case XFER_UDMA_4:
+- case XFER_UDMA_3:
+- case XFER_UDMA_2:
+- case XFER_UDMA_1:
+- case XFER_UDMA_0:
+- case XFER_MW_DMA_2:
+- case XFER_PIO_4:
+- return 4;
+- case XFER_MW_DMA_1:
+- case XFER_PIO_3:
+- return 3;
+- case XFER_SW_DMA_2:
+- case XFER_PIO_2:
+- return 2;
+- case XFER_MW_DMA_0:
+- case XFER_SW_DMA_1:
+- case XFER_SW_DMA_0:
+- case XFER_PIO_1:
+- case XFER_PIO_0:
+- case XFER_PIO_SLOW:
+- default:
+- return 0;
+- }
+-}
+-
+-static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+-{
+- ide_hwif_t *hwif = HWIF(drive);
+- struct pci_dev *dev = hwif->pci_dev;
+- u8 speed = ide_rate_filter(it8172_ratemask(drive), xferspeed);
+- int a_speed = 3 << (drive->dn * 4);
+- int u_flag = 1 << drive->dn;
+- int u_speed = 0;
+- u8 reg48, reg4a;
+-
+- pci_read_config_byte(dev, 0x48, ®48);
+- pci_read_config_byte(dev, 0x4a, ®4a);
+-
+- /*
+- * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+- * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
+- * transfers on some drives, even though both numbers meet the minimum
+- * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
+- * So the faster times are just commented out here. The good news is
+- * that the slower cycle time has very little affect on transfer
+- * performance.
+- */
+-
+- switch(speed) {
+- case XFER_UDMA_4:
+- case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break;
+- case XFER_UDMA_5:
+- case XFER_UDMA_3:
+- case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break;
+- case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+- case XFER_MW_DMA_2:
+- case XFER_MW_DMA_1:
+- case XFER_MW_DMA_0:
+- case XFER_SW_DMA_2: break;
+- case XFER_PIO_4:
+- case XFER_PIO_3:
+- case XFER_PIO_2:
+- case XFER_PIO_0: break;
+- default: return -1;
+- }
+-
+- if (speed >= XFER_UDMA_0) {
+- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+- reg4a &= ~a_speed;
+- pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+- } else {
+- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+- pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+- }
+-
+- it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+- return (ide_config_drive_speed(drive, speed));
+-}
+-
+-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+-{
+- u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
+-
+- if (!(speed)) {
+- u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+- speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+- }
+-
+- (void) it8172_tune_chipset(drive, speed);
+- return ide_dma_enable(drive);
+-}
+-
+-static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
+-{
+- ide_hwif_t *hwif = HWIF(drive);
+- struct hd_driveid *id = drive->id;
+-
+- drive->init_speed = 0;
+-
+- if (id && (id->capability & 1) && drive->autodma) {
+-
+- if (ide_use_dma(drive)) {
+- if (it8172_config_chipset_for_dma(drive))
+- return hwif->ide_dma_on(drive);
+- }
+-
+- goto fast_ata_pio;
+-
+- } else if ((id->capability & 8) || (id->field_valid & 2)) {
+-fast_ata_pio:
+- it8172_tune_drive(drive, 5);
+- return hwif->ide_dma_off_quietly(drive);
+- }
+- /* IORDY not supported */
+- return 0;
+-}
+-
+-static unsigned int __devinit init_chipset_it8172 (struct pci_dev *dev, const char *name)
+-{
+- unsigned char progif;
+-
+- /*
+- * Place both IDE interfaces into PCI "native" mode
+- */
+- pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+- pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);
+-
+- return IT8172_IDE_IRQ;
+-}
+-
+-
+-static void __devinit init_hwif_it8172 (ide_hwif_t *hwif)
+-{
+- struct pci_dev* dev = hwif->pci_dev;
+- unsigned long cmdBase, ctrlBase;
+-
+- hwif->autodma = 0;
+- hwif->tuneproc = &it8172_tune_drive;
+- hwif->speedproc = &it8172_tune_chipset;
+-
+- cmdBase = dev->resource[0].start;
+- ctrlBase = dev->resource[1].start;
+-
+- ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+- hwif->noprobe = 0;
+-
+- if (!hwif->dma_base) {
+- hwif->drives[0].autotune = 1;
+- hwif->drives[1].autotune = 1;
+- return;
+- }
+-
+- hwif->atapi_dma = 1;
+- hwif->ultra_mask = 0x07;
+- hwif->mwdma_mask = 0x06;
+- hwif->swdma_mask = 0x04;
+-
+- hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
+- if (!noautodma)
+- hwif->autodma = 1;
+- hwif->drives[0].autodma = hwif->autodma;
+- hwif->drives[1].autodma = hwif->autodma;
+-}
+-
+-static ide_pci_device_t it8172_chipsets[] __devinitdata = {
+- { /* 0 */
+- .name = "IT8172G",
+- .init_chipset = init_chipset_it8172,
+- .init_hwif = init_hwif_it8172,
+- .channels = 2,
+- .autodma = AUTODMA,
+- .enablebits = {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+- .bootable = ON_BOARD,
+- }
+-};
+-
+-static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+-{
+- if ((!(PCI_FUNC(dev->devfn) & 1) ||
+- (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+- return -ENODEV; /* IT8172 is more than an IDE controller */
+- return ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]);
+-}
+-
+-static struct pci_device_id it8172_pci_tbl[] = {
+- { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+- { 0, },
+-};
+-MODULE_DEVICE_TABLE(pci, it8172_pci_tbl);
+-
+-static struct pci_driver driver = {
+- .name = "IT8172_IDE",
+- .id_table = it8172_pci_tbl,
+- .probe = it8172_init_one,
+-};
+-
+-static int it8172_ide_init(void)
+-{
+- return ide_pci_register_driver(&driver);
+-}
+-
+-module_init(it8172_ide_init);
+-
+-MODULE_AUTHOR("SteveL at mvista.com");
+-MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
+new file mode 100644
+index 0000000..c1cec23
+--- /dev/null
++++ b/drivers/ide/pci/jmicron.c
+@@ -0,0 +1,268 @@
++
++/*
++ * Copyright (C) 2006 Red Hat <alan at redhat.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public License
++ */
++
++#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>
++
++typedef enum {
++ PORT_PATA0 = 0,
++ PORT_PATA1 = 1,
++ PORT_SATA = 2,
++} port_type;
++
++/**
++ * jmicron_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 jmicron_ratemask(ide_drive_t *drive)
++{
++ u8 mode = 4;
++ if (!eighty_ninty_three(drive))
++ mode = min(mode, (u8)1);
++ return mode;
++}
++
++/**
++ * ata66_jmicron - Cable check
++ * @hwif: IDE port
++ *
++ * Return 1 if the cable is 80pin
++ */
++
++static int __devinit ata66_jmicron(ide_hwif_t *hwif)
++{
++ struct pci_dev *pdev = hwif->pci_dev;
++
++ u32 control;
++ u32 control5;
++
++ int port = hwif->channel;
++ port_type port_map[2];
++
++ pci_read_config_dword(pdev, 0x40, &control);
++
++ /* There are two basic mappings. One has the two SATA ports merged
++ as master/slave and the secondary as PATA, the other has only the
++ SATA port mapped */
++ if (control & (1 << 23)) {
++ port_map[0] = PORT_SATA;
++ port_map[1] = PORT_PATA0;
++ } else {
++ port_map[0] = PORT_SATA;
++ port_map[1] = PORT_SATA;
++ }
++
++ /* The 365/366 may have this bit set to map the second PATA port
++ as the internal primary channel */
++ pci_read_config_dword(pdev, 0x80, &control5);
++ if (control5 & (1<<24))
++ port_map[0] = PORT_PATA1;
++
++ /* The two ports may then be logically swapped by the firmware */
++ if (control & (1 << 22))
++ port = port ^ 1;
++
++ /*
++ * Now we know which physical port we are talking about we can
++ * actually do our cable checking etc. Thankfully we don't need
++ * to do the plumbing for other cases.
++ */
++ switch (port_map[port])
++ {
++ case PORT_PATA0:
++ if (control & (1 << 3)) /* 40/80 pin primary */
++ return 1;
++ return 0;
++ case PORT_PATA1:
++ if (control5 & (1 << 19)) /* 40/80 pin secondary */
++ return 0;
++ return 1;
++ case PORT_SATA:
++ return 1;
++ }
++}
++
++static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
++{
++ return;
++}
++
++/**
++ * config_jmicron_chipset_for_pio - set drive timings
++ * @drive: drive to tune
++ * @speed we want
++ *
++ */
++
++static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
++{
++ u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
++ if (set_speed)
++ (void) ide_config_drive_speed(drive, speed);
++}
++
++/**
++ * jmicron_tune_chipset - set controller timings
++ * @drive: Drive to set up
++ * @xferspeed: speed we want to achieve
++ *
++ * As the JMicron snoops for timings all we actually need to do is
++ * make sure we don't set an invalid mode. We do need to honour
++ * the cable detect here.
++ */
++
++static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
++{
++
++ u8 speed = ide_rate_filter(jmicron_ratemask(drive), xferspeed);
++
++ return ide_config_drive_speed(drive, speed);
++}
++
++/**
++ * config_chipset_for_dma - configure for DMA
++ * @drive: drive to configure
++ *
++ * As the JMicron snoops for timings all we actually need to do is
++ * make sure we don't set an invalid mode.
++ */
++
++static int config_chipset_for_dma (ide_drive_t *drive)
++{
++ u8 speed = ide_dma_speed(drive, jmicron_ratemask(drive));
++
++ config_jmicron_chipset_for_pio(drive, !speed);
++ jmicron_tune_chipset(drive, speed);
++ return ide_dma_enable(drive);
++}
++
++/**
++ * jmicron_configure_drive_for_dma - set up for DMA transfers
++ * @drive: drive we are going to set up
++ *
++ * As the JMicron snoops for timings all we actually need to do is
++ * make sure we don't set an invalid mode.
++ */
++
++static int jmicron_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_jmicron_chipset_for_pio(drive, 1);
++ return hwif->ide_dma_off_quietly(drive);
++}
++
++/**
++ * init_hwif_jmicron - set up hwif structs
++ * @hwif: interface to set up
++ *
++ * Minimal set up is required for the Jmicron hardware.
++ */
++
++static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
++{
++ hwif->speedproc = &jmicron_tune_chipset;
++ hwif->tuneproc = &jmicron_tuneproc;
++
++ hwif->drives[0].autotune = 1;
++ hwif->drives[1].autotune = 1;
++
++ if (!hwif->dma_base)
++ goto fallback;
++
++ hwif->atapi_dma = 1;
++ hwif->ultra_mask = 0x7f;
++ hwif->mwdma_mask = 0x07;
++
++ hwif->ide_dma_check = &jmicron_config_drive_for_dma;
++ if (!(hwif->udma_four))
++ hwif->udma_four = ata66_jmicron(hwif);
++
++ hwif->autodma = 1;
++ hwif->drives[0].autodma = hwif->autodma;
++ hwif->drives[1].autodma = hwif->autodma;
++ return;
++fallback:
++ hwif->autodma = 0;
++ return;
++}
++
++#define DECLARE_JMB_DEV(name_str) \
++ { \
++ .name = name_str, \
++ .init_hwif = init_hwif_jmicron, \
++ .channels = 2, \
++ .autodma = AUTODMA, \
++ .bootable = ON_BOARD, \
++ .enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
++ }
++
++static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
++ /* 0 */ DECLARE_JMB_DEV("JMB361"),
++ /* 1 */ DECLARE_JMB_DEV("JMB363"),
++ /* 2 */ DECLARE_JMB_DEV("JMB365"),
++ /* 3 */ DECLARE_JMB_DEV("JMB366"),
++ /* 4 */ DECLARE_JMB_DEV("JMB368"),
++};
++
++/**
++ * jmicron_init_one - pci layer discovery entry
++ * @dev: PCI device
++ * @id: ident table entry
++ *
++ * Called by the PCI code when it finds a Jmicron controller.
++ * We then use the IDE PCI generic helper to do most of the work.
++ */
++
++static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]);
++ return 0;
++}
++
++static struct pci_device_id jmicron_pci_tbl[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 0},
++ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 1},
++ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 2},
++ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 3},
++ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 4},
++ { 0, },
++};
++
++MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
++
++static struct pci_driver driver = {
++ .name = "JMicron IDE",
++ .id_table = jmicron_pci_tbl,
++ .probe = jmicron_init_one,
++};
++
++static int __init jmicron_ide_init(void)
++{
++ return ide_pci_register_driver(&driver);
++}
++
++module_init(jmicron_ide_init);
++
++MODULE_AUTHOR("Alan Cox");
++MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
+index b46022a..184cdac 100644
+--- a/drivers/ide/pci/pdc202xx_old.c
++++ b/drivers/ide/pci/pdc202xx_old.c
+@@ -154,7 +154,8 @@ static int pdc202xx_tune_chipset (ide_dr
+ u8 AP, BP, CP, DP;
+ u8 TA = 0, TB = 0, TC = 0;
+
+- if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
++ if (drive->media != ide_disk &&
++ drive->media != ide_cdrom && speed < XFER_SW_DMA_0)
+ return -1;
+
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+@@ -330,14 +331,12 @@ static int config_chipset_for_dma (ide_d
+
+ chipset_is_set:
+
+- if (drive->media == ide_disk) {
+- pci_read_config_byte(dev, (drive_pci), &AP);
+- if (id->capability & 4) /* IORDY_EN */
+- pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+- pci_read_config_byte(dev, (drive_pci), &AP);
+- if (drive->media == ide_disk) /* PREFETCH_EN */
+- pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+- }
++ pci_read_config_byte(dev, (drive_pci), &AP);
++ if (id->capability & 4) /* IORDY_EN */
++ pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
++ pci_read_config_byte(dev, (drive_pci), &AP);
++ if (drive->media == ide_disk) /* PREFETCH_EN */
++ pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+
+ speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+@@ -385,7 +384,7 @@ static void pdc202xx_old_ide_dma_start(i
+ {
+ if (drive->current_speed > XFER_UDMA_2)
+ pdc_old_enable_66MHz_clock(drive->hwif);
+- if (drive->addressing == 1) {
++ if (drive->media != ide_disk || drive->addressing == 1) {
+ struct request *rq = HWGROUP(drive)->rq;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long high_16 = hwif->dma_master;
+@@ -405,7 +404,7 @@ static void pdc202xx_old_ide_dma_start(i
+
+ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+ {
+- if (drive->addressing == 1) {
++ if (drive->media != ide_disk || drive->addressing == 1) {
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long high_16 = hwif->dma_master;
+ unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
+@@ -519,6 +518,7 @@ static void __devinit init_hwif_pdc202xx
+ hwif->ultra_mask = 0x3f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
++ hwif->atapi_dma = 1;
+
+ hwif->err_stops_fifo = 1;
+
+diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
+index 50332dd..cdc3aab 100644
+--- a/drivers/ide/pci/piix.c
++++ b/drivers/ide/pci/piix.c
+@@ -222,13 +222,15 @@ static void piix_tune_drive (ide_drive_t
+ u16 master_data;
+ u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
++ int control = 0;
+
+ /* ISP RTC */
+- u8 timings[][2] = { { 0, 0 },
+- { 0, 0 },
+- { 1, 0 },
+- { 2, 1 },
+- { 2, 3 }, };
++ static const u8 timings[][2]= {
++ { 0, 0 },
++ { 0, 0 },
++ { 1, 0 },
++ { 2, 1 },
++ { 2, 3 }, };
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+
+@@ -239,19 +241,30 @@ static void piix_tune_drive (ide_drive_t
+ */
+ spin_lock_irqsave(&tune_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
++
++ if (pio >= 2)
++ control |= 1; /* Programmable timing on */
++ if (drive->media == ide_disk)
++ control |= 4; /* Prefetch, post write */
++ if (pio >= 3)
++ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data = master_data | 0x4000;
+- if (pio > 1)
++ if (pio > 1) {
+ /* enable PPE, IE and TIME */
+- master_data = master_data | 0x0070;
++ master_data = master_data | (control << 4);
++ } else {
++ master_data &= ~0x0070;
++ }
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+ slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+ } else {
+ master_data = master_data & 0xccf8;
+- if (pio > 1)
++ if (pio > 1) {
+ /* enable PPE, IE and TIME */
+- master_data = master_data | 0x0007;
++ master_data = master_data | control;
++ }
+ master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+@@ -615,7 +628,7 @@ static void __devinit piix_check_450nx(v
+ struct pci_dev *pdev = NULL;
+ u16 cfg;
+ u8 rev;
+- while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
++ while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
+ {
+ /* Look for 450NX PXB. Check for problem configurations
+ A PCI quirk checks bit 6 already */
+diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
+index 608cd76..5f6950c 100644
+--- a/drivers/ide/pci/rz1000.c
++++ b/drivers/ide/pci/rz1000.c
+@@ -17,7 +17,6 @@
+
+ #undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+ #include <linux/types.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
+index fc2b549..ff80937 100644
+--- a/drivers/ide/pci/sc1200.c
++++ b/drivers/ide/pci/sc1200.c
+@@ -323,6 +323,7 @@ static void sc1200_tuneproc (ide_drive_t
+ }
+ }
+
++#ifdef CONFIG_PM
+ static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+ {
+ int h;
+@@ -451,6 +452,7 @@ static int sc1200_resume (struct pci_dev
+ }
+ return 0;
+ }
++#endif
+
+ /*
+ * This gets invoked by the IDE driver once for each channel,
+@@ -499,8 +501,10 @@ static struct pci_driver driver = {
+ .name = "SC1200_IDE",
+ .id_table = sc1200_pci_tbl,
+ .probe = sc1200_init_one,
++#ifdef CONFIG_PM
+ .suspend = sc1200_suspend,
+ .resume = sc1200_resume,
++#endif
+ };
+
+ static int sc1200_ide_init(void)
+diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
+index f063d95..057548d 100644
+--- a/drivers/ide/pci/serverworks.c
++++ b/drivers/ide/pci/serverworks.c
+@@ -359,7 +359,7 @@ static unsigned int __devinit init_chips
+
+ /* OSB4 : South Bridge and IDE */
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+- isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
++ isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ if (isa_dev) {
+ pci_read_config_dword(isa_dev, 0x64, ®);
+@@ -380,7 +380,7 @@ static unsigned int __devinit init_chips
+ if (!(PCI_FUNC(dev->devfn) & 1)) {
+ struct pci_dev * findev = NULL;
+ u32 reg4c = 0;
+- findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
++ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+ if (findev) {
+ pci_read_config_dword(findev, 0x4C, ®4c);
+@@ -388,6 +388,7 @@ static unsigned int __devinit init_chips
+ reg4c |= 0x00000040;
+ reg4c |= 0x00000020;
+ pci_write_config_dword(findev, 0x4C, reg4c);
++ pci_dev_put(findev);
+ }
+ outb_p(0x06, 0x0c00);
+ dev->irq = inb_p(0x0c01);
+@@ -395,12 +396,13 @@ static unsigned int __devinit init_chips
+ struct pci_dev * findev = NULL;
+ u8 reg41 = 0;
+
+- findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
++ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+ if (findev) {
+ pci_read_config_byte(findev, 0x41, ®41);
+ reg41 &= ~0x40;
+ pci_write_config_byte(findev, 0x41, reg41);
++ pci_dev_put(findev);
+ }
+ /*
+ * This is a device pin issue on CSB6.
+diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
+index d8a0d87..244f7eb 100644
+--- a/drivers/ide/pci/sgiioc4.c
++++ b/drivers/ide/pci/sgiioc4.c
+@@ -220,7 +220,7 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
+ ide_hwif_t *hwif = HWIF(drive);
+ u64 dma_base = hwif->dma_base;
+ int dma_stat = 0;
+- unsigned long *ending_dma = (unsigned long *) hwif->dma_base2;
++ unsigned long *ending_dma = ide_get_hwifdata(hwif);
+
+ hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+
+@@ -369,6 +369,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsig
+ {
+ void __iomem *virt_dma_base;
+ int num_ports = sizeof (ioc4_dma_regs_t);
++ void *pad;
+
+ printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
+ dma_base, dma_base + num_ports - 1);
+@@ -400,17 +401,14 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsig
+
+ hwif->sg_max_nents = IOC4_PRD_ENTRIES;
+
+- hwif->dma_base2 = (unsigned long)
+- pci_alloc_consistent(hwif->pci_dev,
+- IOC4_IDE_CACHELINE_SIZE,
+- (dma_addr_t *) &(hwif->dma_status));
++ pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE,
++ (dma_addr_t *) &(hwif->dma_status));
+
+- if (!hwif->dma_base2)
+- goto dma_base2alloc_failure;
+-
+- return;
++ if (pad) {
++ ide_set_hwifdata(hwif, pad);
++ return;
++ }
+
+-dma_base2alloc_failure:
+ pci_free_consistent(hwif->pci_dev,
+ IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
+ hwif->dmatable_cpu, hwif->dmatable_dma);
+@@ -476,7 +474,7 @@ sgiioc4_configure_for_dma(int dma_direct
+ hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4);
+
+ /* Address of the Ending DMA */
+- memset((unsigned int *) hwif->dma_base2, 0, IOC4_IDE_CACHELINE_SIZE);
++ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE);
+ ending_dma_addr = cpu_to_le32(hwif->dma_status);
+ hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4);
+
+@@ -776,7 +774,7 @@ ioc4_ide_exit(void)
+ ioc4_unregister_submodule(&ioc4_ide_submodule);
+ }
+
+-module_init(ioc4_ide_init);
++late_initcall(ioc4_ide_init); /* Call only after IDE init is done */
+ module_exit(ioc4_ide_exit);
+
+ MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
+diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
+index 20b3929..697f566 100644
+--- a/drivers/ide/pci/siimage.c
++++ b/drivers/ide/pci/siimage.c
+@@ -898,7 +898,6 @@ static void __devinit init_mmio_iops_sii
+ base = (unsigned long) addr;
+
+ hwif->dma_base = base + (ch ? 0x08 : 0x00);
+- hwif->dma_base2 = base + (ch ? 0x18 : 0x10);
+ hwif->mmio = 2;
+ }
+
+diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
+index f03196c..92edf76 100644
+--- a/drivers/ide/pci/sis5513.c
++++ b/drivers/ide/pci/sis5513.c
+@@ -739,7 +739,7 @@ static unsigned int __devinit init_chips
+
+ for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) {
+
+- host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
++ host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
+
+ if (!host)
+ continue;
+@@ -753,6 +753,7 @@ static unsigned int __devinit init_chips
+ if (hostrev >= 0x30)
+ chipset_family = ATA_100a;
+ }
++ pci_dev_put(host);
+
+ printk(KERN_INFO "SIS5513: %s %s controller\n",
+ SiSHostChipInfo[i].name, chipset_capability[chipset_family]);
+diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
+index 9b7589e..2af634d 100644
+--- a/drivers/ide/pci/via82cxxx.c
++++ b/drivers/ide/pci/via82cxxx.c
+@@ -248,7 +248,7 @@ static struct via_isa_bridge *via_config
+ u8 t;
+
+ for (via_config = via_isa_bridges; via_config->id; via_config++)
+- if ((*isa = pci_find_device(PCI_VENDOR_ID_VIA +
++ if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
+ !!(via_config->flags & VIA_BAD_ID),
+ via_config->id, NULL))) {
+
+@@ -256,6 +256,7 @@ static struct via_isa_bridge *via_config
+ if (t >= via_config->rev_min &&
+ t <= via_config->rev_max)
+ break;
++ pci_dev_put(*isa);
+ }
+
+ return via_config;
+@@ -283,6 +284,7 @@ static unsigned int __devinit init_chips
+ via_config = via_config_find(&isa);
+ if (!via_config->id) {
+ printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
++ pci_dev_put(isa);
+ return -ENODEV;
+ }
+
+@@ -361,6 +363,7 @@ static unsigned int __devinit init_chips
+ via_dma[via_config->flags & VIA_UDMA],
+ pci_name(dev));
+
++ pci_dev_put(isa);
+ return 0;
+ }
+
+diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
+index ebf961f..91c5344 100644
+--- a/drivers/ide/ppc/pmac.c
++++ b/drivers/ide/ppc/pmac.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/ide/ide-pmac.c
++ * linux/drivers/ide/ppc/pmac.c
+ *
+ * Support for IDE interfaces on PowerMacs.
+ * These IDE interfaces are memory-mapped and have a DBDMA channel
+@@ -1154,7 +1154,7 @@ static int
+ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+ {
+ struct device_node *np = pmif->node;
+- int *bidp;
++ const int *bidp;
+
+ pmif->cable_80 = 0;
+ pmif->broken_dma = pmif->broken_dma_warn = 0;
+@@ -1176,14 +1176,14 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
+ pmif->broken_dma = 1;
+ }
+
+- bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
++ bidp = get_property(np, "AAPL,bus-id", NULL);
+ pmif->aapl_bus_id = bidp ? *bidp : 0;
+
+ /* Get cable type from device-tree */
+ if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6) {
+- char* cable = get_property(np, "cable-type", NULL);
++ const char* cable = get_property(np, "cable-type", NULL);
+ if (cable && !strncmp(cable, "80-", 3))
+ pmif->cable_80 = 1;
+ }
+@@ -1326,7 +1326,7 @@ pmac_ide_macio_attach(struct macio_dev *
+ if (macio_irq_count(mdev) == 0) {
+ printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n",
+ i, mdev->ofdev.node->full_name);
+- irq = 13;
++ irq = irq_create_mapping(NULL, 13);
+ } else
+ irq = macio_irq(mdev, 0);
+
+@@ -1369,15 +1369,16 @@ pmac_ide_macio_attach(struct macio_dev *
+ }
+
+ static int
+-pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t state)
++pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
+ {
+ ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
+ int rc = 0;
+
+- if (state.event != mdev->ofdev.dev.power.power_state.event && state.event >= PM_EVENT_SUSPEND) {
++ if (mesg.event != mdev->ofdev.dev.power.power_state.event
++ && mesg.event == PM_EVENT_SUSPEND) {
+ rc = pmac_ide_do_suspend(hwif);
+ if (rc == 0)
+- mdev->ofdev.dev.power.power_state = state;
++ mdev->ofdev.dev.power.power_state = mesg;
+ }
+
+ return rc;
+@@ -1473,15 +1474,16 @@ pmac_ide_pci_attach(struct pci_dev *pdev
+ }
+
+ static int
+-pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t state)
++pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+ {
+ ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
+ int rc = 0;
+
+- if (state.event != pdev->dev.power.power_state.event && state.event >= 2) {
++ if (mesg.event != pdev->dev.power.power_state.event
++ && mesg.event == PM_EVENT_SUSPEND) {
+ rc = pmac_ide_do_suspend(hwif);
+ if (rc == 0)
+- pdev->dev.power.power_state = state;
++ pdev->dev.power.power_state = mesg;
+ }
+
+ return rc;
+diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
+index eb09452..0719b64 100644
+--- a/drivers/ide/setup-pci.c
++++ b/drivers/ide/setup-pci.c
+@@ -101,7 +101,7 @@ static ide_hwif_t *ide_match_hwif(unsign
+ return hwif; /* pick an unused entry */
+ }
+ }
+- for (h = 0; h < 2; ++h) {
++ for (h = 0; h < 2 && h < MAX_HWIFS; ++h) {
+ hwif = ide_hwifs + h;
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* pick an unused entry */
+@@ -795,24 +795,6 @@ int __ide_pci_register_driver(struct pci
+ EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
+
+ /**
+- * ide_unregister_pci_driver - unregister an IDE driver
+- * @driver: driver to remove
+- *
+- * Unregister a currently installed IDE driver. Returns are the same
+- * as for pci_unregister_driver
+- */
+-
+-void ide_pci_unregister_driver(struct pci_driver *driver)
+-{
+- if(!pre_init)
+- pci_unregister_driver(driver);
+- else
+- list_del(&driver->node);
+-}
+-
+-EXPORT_SYMBOL_GPL(ide_pci_unregister_driver);
+-
+-/**
+ * ide_scan_pcidev - find an IDE driver for a device
+ * @dev: PCI device to check
+ *
+diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
+index 1867375..672b92e 100644
+--- a/drivers/ieee1394/Kconfig
++++ b/drivers/ieee1394/Kconfig
+@@ -120,12 +120,19 @@ config IEEE1394_VIDEO1394
+ this option only if you have an IEEE 1394 video device connected to
+ an OHCI-1394 card.
+
++comment "SBP-2 support (for storage devices) requires SCSI"
++ depends on IEEE1394 && SCSI=n
++
+ config IEEE1394_SBP2
+ tristate "SBP-2 support (Harddisks etc.)"
+ depends on IEEE1394 && SCSI && (PCI || BROKEN)
+ help
+- This option enables you to use SBP-2 devices connected to your IEEE
+- 1394 bus. SBP-2 devices include harddrives and DVD devices.
++ This option enables you to use SBP-2 devices connected to an IEEE
++ 1394 bus. SBP-2 devices include storage devices like harddisks and
++ DVD drives, also some other FireWire devices like scanners.
++
++ You should also enable support for disks, CD-ROMs, etc. in the SCSI
++ configuration section.
+
+ config IEEE1394_SBP2_PHYS_DMA
+ bool "Enable replacement for physical DMA in SBP2"
+@@ -133,7 +140,7 @@ config IEEE1394_SBP2_PHYS_DMA
+ help
+ This builds sbp2 for use with non-OHCI host adapters which do not
+ support physical DMA or for when ohci1394 is run with phys_dma=0.
+- Physical DMA is data movement without assistence of the drivers'
++ Physical DMA is data movement without assistance of the drivers'
+ interrupt handlers. This option includes the interrupt handlers
+ that are required in absence of this hardware feature.
+
+diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
+index 149573d..ab0c80f 100644
+--- a/drivers/ieee1394/csr.c
++++ b/drivers/ieee1394/csr.c
+@@ -17,11 +17,13 @@
+ *
+ */
+
+-#include <linux/string.h>
++#include <linux/jiffies.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/param.h>
+ #include <linux/spinlock.h>
++#include <linux/string.h>
+
+ #include "csr1212.h"
+ #include "ieee1394_types.h"
+@@ -149,31 +151,18 @@ static void host_reset(struct hpsb_host
+
+ /*
+ * HI == seconds (bits 0:2)
+- * LO == fraction units of 1/8000 of a second, as per 1394 (bits 19:31)
+- *
+- * Convert to units and then to HZ, for comparison to jiffies.
+- *
+- * By default this will end up being 800 units, or 100ms (125usec per
+- * unit).
++ * LO == fractions of a second in units of 125usec (bits 19:31)
+ *
+- * NOTE: The spec says 1/8000, but also says we can compute based on 1/8192
+- * like CSR specifies. Should make our math less complex.
++ * Convert SPLIT_TIMEOUT to jiffies.
++ * The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
+ */
+ static inline void calculate_expire(struct csr_control *csr)
+ {
+- unsigned long units;
+-
+- /* Take the seconds, and convert to units */
+- units = (unsigned long)(csr->split_timeout_hi & 0x07) << 13;
+-
+- /* Add in the fractional units */
+- units += (unsigned long)(csr->split_timeout_lo >> 19);
+-
+- /* Convert to jiffies */
+- csr->expire = (unsigned long)(units * HZ) >> 13UL;
++ unsigned long usecs =
++ (csr->split_timeout_hi & 0x07) * USEC_PER_SEC +
++ (csr->split_timeout_lo >> 19) * 125L;
+
+- /* Just to keep from rounding low */
+- csr->expire++;
++ csr->expire = usecs_to_jiffies(usecs > 100000L ? usecs : 100000L);
+
+ HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
+ }
+diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
+index ea9aa4f..f115465 100644
+--- a/drivers/ieee1394/csr.h
++++ b/drivers/ieee1394/csr.h
+@@ -1,75 +1,73 @@
+-
+ #ifndef _IEEE1394_CSR_H
+ #define _IEEE1394_CSR_H
+
+-#ifdef CONFIG_PREEMPT
+-#include <linux/sched.h>
+-#endif
++#include <linux/spinlock_types.h>
+
+ #include "csr1212.h"
++#include "ieee1394_types.h"
+
+-#define CSR_REGISTER_BASE 0xfffff0000000ULL
++#define CSR_REGISTER_BASE 0xfffff0000000ULL
+
+ /* register offsets relative to CSR_REGISTER_BASE */
+-#define CSR_STATE_CLEAR 0x0
+-#define CSR_STATE_SET 0x4
+-#define CSR_NODE_IDS 0x8
+-#define CSR_RESET_START 0xc
+-#define CSR_SPLIT_TIMEOUT_HI 0x18
+-#define CSR_SPLIT_TIMEOUT_LO 0x1c
+-#define CSR_CYCLE_TIME 0x200
+-#define CSR_BUS_TIME 0x204
+-#define CSR_BUSY_TIMEOUT 0x210
+-#define CSR_BUS_MANAGER_ID 0x21c
+-#define CSR_BANDWIDTH_AVAILABLE 0x220
+-#define CSR_CHANNELS_AVAILABLE 0x224
+-#define CSR_CHANNELS_AVAILABLE_HI 0x224
+-#define CSR_CHANNELS_AVAILABLE_LO 0x228
+-#define CSR_BROADCAST_CHANNEL 0x234
+-#define CSR_CONFIG_ROM 0x400
+-#define CSR_CONFIG_ROM_END 0x800
+-#define CSR_FCP_COMMAND 0xB00
+-#define CSR_FCP_RESPONSE 0xD00
+-#define CSR_FCP_END 0xF00
+-#define CSR_TOPOLOGY_MAP 0x1000
+-#define CSR_TOPOLOGY_MAP_END 0x1400
+-#define CSR_SPEED_MAP 0x2000
+-#define CSR_SPEED_MAP_END 0x3000
++#define CSR_STATE_CLEAR 0x0
++#define CSR_STATE_SET 0x4
++#define CSR_NODE_IDS 0x8
++#define CSR_RESET_START 0xc
++#define CSR_SPLIT_TIMEOUT_HI 0x18
++#define CSR_SPLIT_TIMEOUT_LO 0x1c
++#define CSR_CYCLE_TIME 0x200
++#define CSR_BUS_TIME 0x204
++#define CSR_BUSY_TIMEOUT 0x210
++#define CSR_BUS_MANAGER_ID 0x21c
++#define CSR_BANDWIDTH_AVAILABLE 0x220
++#define CSR_CHANNELS_AVAILABLE 0x224
++#define CSR_CHANNELS_AVAILABLE_HI 0x224
++#define CSR_CHANNELS_AVAILABLE_LO 0x228
++#define CSR_BROADCAST_CHANNEL 0x234
++#define CSR_CONFIG_ROM 0x400
++#define CSR_CONFIG_ROM_END 0x800
++#define CSR_FCP_COMMAND 0xB00
++#define CSR_FCP_RESPONSE 0xD00
++#define CSR_FCP_END 0xF00
++#define CSR_TOPOLOGY_MAP 0x1000
++#define CSR_TOPOLOGY_MAP_END 0x1400
++#define CSR_SPEED_MAP 0x2000
++#define CSR_SPEED_MAP_END 0x3000
+
+ /* IEEE 1394 bus specific Configuration ROM Key IDs */
+ #define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
+
+-/* IEEE 1394 Bus Inforamation Block specifics */
++/* IEEE 1394 Bus Information Block specifics */
+ #define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
+
+-#define CSR_IRMC_SHIFT 31
+-#define CSR_CMC_SHIFT 30
+-#define CSR_ISC_SHIFT 29
+-#define CSR_BMC_SHIFT 28
+-#define CSR_PMC_SHIFT 27
+-#define CSR_CYC_CLK_ACC_SHIFT 16
+-#define CSR_MAX_REC_SHIFT 12
+-#define CSR_MAX_ROM_SHIFT 8
+-#define CSR_GENERATION_SHIFT 4
++#define CSR_IRMC_SHIFT 31
++#define CSR_CMC_SHIFT 30
++#define CSR_ISC_SHIFT 29
++#define CSR_BMC_SHIFT 28
++#define CSR_PMC_SHIFT 27
++#define CSR_CYC_CLK_ACC_SHIFT 16
++#define CSR_MAX_REC_SHIFT 12
++#define CSR_MAX_ROM_SHIFT 8
++#define CSR_GENERATION_SHIFT 4
+
+ #define CSR_SET_BUS_INFO_GENERATION(csr, gen) \
+ ((csr)->bus_info_data[2] = \
+ cpu_to_be32((be32_to_cpu((csr)->bus_info_data[2]) & \
+- ~(0xf << CSR_GENERATION_SHIFT)) | \
++ ~(0xf << CSR_GENERATION_SHIFT)) | \
+ (gen) << CSR_GENERATION_SHIFT))
+
+ struct csr_control {
+- spinlock_t lock;
+-
+- quadlet_t state;
+- quadlet_t node_ids;
+- quadlet_t split_timeout_hi, split_timeout_lo;
+- unsigned long expire; // Calculated from split_timeout
+- quadlet_t cycle_time;
+- quadlet_t bus_time;
+- quadlet_t bus_manager_id;
+- quadlet_t bandwidth_available;
+- quadlet_t channels_available_hi, channels_available_lo;
++ spinlock_t lock;
++
++ quadlet_t state;
++ quadlet_t node_ids;
++ quadlet_t split_timeout_hi, split_timeout_lo;
++ unsigned long expire; /* Calculated from split_timeout */
++ quadlet_t cycle_time;
++ quadlet_t bus_time;
++ quadlet_t bus_manager_id;
++ quadlet_t bandwidth_available;
++ quadlet_t channels_available_hi, channels_available_lo;
+ quadlet_t broadcast_channel;
+
+ /* Bus Info */
+@@ -84,8 +82,8 @@ struct csr_control {
+
+ struct csr1212_csr *rom;
+
+- quadlet_t topology_map[256];
+- quadlet_t speed_map[1024];
++ quadlet_t topology_map[256];
++ quadlet_t speed_map[1024];
+ };
+
+ extern struct csr1212_bus_ops csr_bus_ops;
+@@ -93,4 +91,9 @@ extern struct csr1212_bus_ops csr_bus_op
+ int init_csr(void);
+ void cleanup_csr(void);
+
++/* hpsb_update_config_rom() is deprecated */
++struct hpsb_host;
++int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
++ size_t size, unsigned char rom_version);
++
+ #endif /* _IEEE1394_CSR_H */
+diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
+index ca5167d..c68f328 100644
+--- a/drivers/ieee1394/dma.c
++++ b/drivers/ieee1394/dma.c
+@@ -7,10 +7,13 @@
+ * directory of the kernel sources for details.
+ */
+
++#include <linux/mm.h>
+ #include <linux/module.h>
+-#include <linux/vmalloc.h>
++#include <linux/pci.h>
+ #include <linux/slab.h>
+-#include <linux/mm.h>
++#include <linux/vmalloc.h>
++#include <asm/scatterlist.h>
++
+ #include "dma.h"
+
+ /* dma_prog_region */
+diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
+index 061550a..a1682ab 100644
+--- a/drivers/ieee1394/dma.h
++++ b/drivers/ieee1394/dma.h
+@@ -10,69 +10,91 @@
+ #ifndef IEEE1394_DMA_H
+ #define IEEE1394_DMA_H
+
+-#include <linux/pci.h>
+-#include <asm/scatterlist.h>
+-
+-/* struct dma_prog_region
+-
+- a small, physically-contiguous DMA buffer with random-access,
+- synchronous usage characteristics
+-*/
+-
++#include <asm/types.h>
++
++struct pci_dev;
++struct scatterlist;
++struct vm_area_struct;
++
++/**
++ * struct dma_prog_region - small contiguous DMA buffer
++ * @kvirt: kernel virtual address
++ * @dev: PCI device
++ * @n_pages: number of kernel pages
++ * @bus_addr: base bus address
++ *
++ * a small, physically contiguous DMA buffer with random-access, synchronous
++ * usage characteristics
++ */
+ struct dma_prog_region {
+- unsigned char *kvirt; /* kernel virtual address */
+- struct pci_dev *dev; /* PCI device */
+- unsigned int n_pages; /* # of kernel pages */
+- dma_addr_t bus_addr; /* base bus address */
++ unsigned char *kvirt;
++ struct pci_dev *dev;
++ unsigned int n_pages;
++ dma_addr_t bus_addr;
+ };
+
+ /* clear out all fields but do not allocate any memory */
+ void dma_prog_region_init(struct dma_prog_region *prog);
+-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev);
++int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
++ struct pci_dev *dev);
+ void dma_prog_region_free(struct dma_prog_region *prog);
+
+-static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset)
++static inline dma_addr_t dma_prog_region_offset_to_bus(
++ struct dma_prog_region *prog, unsigned long offset)
+ {
+ return prog->bus_addr + offset;
+ }
+
+-/* struct dma_region
+-
+- a large, non-physically-contiguous DMA buffer with streaming,
+- asynchronous usage characteristics
+-*/
+-
++/**
++ * struct dma_region - large non-contiguous DMA buffer
++ * @virt: kernel virtual address
++ * @dev: PCI device
++ * @n_pages: number of kernel pages
++ * @n_dma_pages: number of IOMMU pages
++ * @sglist: IOMMU mapping
++ * @direction: PCI_DMA_TODEVICE, etc.
++ *
++ * a large, non-physically-contiguous DMA buffer with streaming, asynchronous
++ * usage characteristics
++ */
+ struct dma_region {
+- unsigned char *kvirt; /* kernel virtual address */
+- struct pci_dev *dev; /* PCI device */
+- unsigned int n_pages; /* # of kernel pages */
+- unsigned int n_dma_pages; /* # of IOMMU pages */
+- struct scatterlist *sglist; /* IOMMU mapping */
+- int direction; /* PCI_DMA_TODEVICE, etc */
++ unsigned char *kvirt;
++ struct pci_dev *dev;
++ unsigned int n_pages;
++ unsigned int n_dma_pages;
++ struct scatterlist *sglist;
++ int direction;
+ };
+
+ /* clear out all fields but do not allocate anything */
+ void dma_region_init(struct dma_region *dma);
+
+ /* allocate the buffer and map it to the IOMMU */
+-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction);
++int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
++ struct pci_dev *dev, int direction);
+
+ /* unmap and free the buffer */
+ void dma_region_free(struct dma_region *dma);
+
+ /* sync the CPU's view of the buffer */
+-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len);
++void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
++ unsigned long len);
++
+ /* sync the IO bus' view of the buffer */
+-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len);
++void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
++ unsigned long len);
+
+ /* map the buffer into a user space process */
+-int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma);
++int dma_region_mmap(struct dma_region *dma, struct file *file,
++ struct vm_area_struct *vma);
+
+ /* macro to index into a DMA region (or dma_prog_region) */
+-#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) )
++#define dma_region_i(_dma, _type, _index) \
++ ( ((_type*) ((_dma)->kvirt)) + (_index) )
+
+ /* return the DMA bus address of the byte with the given offset
+- relative to the beginning of the dma_region */
+-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset);
++ * relative to the beginning of the dma_region */
++dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
++ unsigned long offset);
+
+ #endif /* IEEE1394_DMA_H */
+diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
+index 80b5ac7..7d1d284 100644
+--- a/drivers/ieee1394/dv1394-private.h
++++ b/drivers/ieee1394/dv1394-private.h
+@@ -460,7 +460,7 @@ struct video_card {
+ int dma_running;
+
+ /*
+- 3) the sleeping semaphore 'sem' - this is used from process context only,
++ 3) the sleeping mutex 'mtx' - this is used from process context only,
+ to serialize various operations on the video_card. Even though only one
+ open() is allowed, we still need to prevent multiple threads of execution
+ from entering calls like read, write, ioctl, etc.
+@@ -468,9 +468,9 @@ struct video_card {
+ I honestly can't think of a good reason to use dv1394 from several threads
+ at once, but we need to serialize anyway to prevent oopses =).
+
+- NOTE: if you need both spinlock and sem, take sem first to avoid deadlock!
++ NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
+ */
+- struct semaphore sem;
++ struct mutex mtx;
+
+ /* people waiting for buffer space, please form a line here... */
+ wait_queue_head_t waitq;
+diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
+index 87532dd..6c72f04 100644
+--- a/drivers/ieee1394/dv1394.c
++++ b/drivers/ieee1394/dv1394.c
+@@ -95,6 +95,7 @@
+ #include <linux/fs.h>
+ #include <linux/poll.h>
+ #include <linux/smp_lock.h>
++#include <linux/mutex.h>
+ #include <linux/bitops.h>
+ #include <asm/byteorder.h>
+ #include <asm/atomic.h>
+@@ -110,15 +111,15 @@
+ #include <linux/compat.h>
+ #include <linux/cdev.h>
+
++#include "dv1394.h"
++#include "dv1394-private.h"
++#include "highlevel.h"
++#include "hosts.h"
+ #include "ieee1394.h"
++#include "ieee1394_core.h"
++#include "ieee1394_hotplug.h"
+ #include "ieee1394_types.h"
+ #include "nodemgr.h"
+-#include "hosts.h"
+-#include "ieee1394_core.h"
+-#include "highlevel.h"
+-#include "dv1394.h"
+-#include "dv1394-private.h"
+-
+ #include "ohci1394.h"
+
+ /* DEBUG LEVELS:
+@@ -136,13 +137,13 @@
+ #if DV1394_DEBUG_LEVEL >= 2
+ #define irq_printk( args... ) printk( args )
+ #else
+-#define irq_printk( args... )
++#define irq_printk( args... ) do {} while (0)
+ #endif
+
+ #if DV1394_DEBUG_LEVEL >= 1
+ #define debug_printk( args... ) printk( args)
+ #else
+-#define debug_printk( args... )
++#define debug_printk( args... ) do {} while (0)
+ #endif
+
+ /* issue a dummy PCI read to force the preceding write
+@@ -247,7 +248,7 @@ static void frame_delete(struct frame *f
+
+ Frame_prepare() must be called OUTSIDE the video->spinlock.
+ However, frame_prepare() must still be serialized, so
+- it should be called WITH the video->sem taken.
++ it should be called WITH the video->mtx taken.
+ */
+
+ static void frame_prepare(struct video_card *video, unsigned int this_frame)
+@@ -1271,7 +1272,7 @@ static int dv1394_mmap(struct file *file
+ int retval = -EINVAL;
+
+ /* serialize mmap */
+- down(&video->sem);
++ mutex_lock(&video->mtx);
+
+ if ( ! video_card_initialized(video) ) {
+ retval = do_dv1394_init_default(video);
+@@ -1281,7 +1282,7 @@ static int dv1394_mmap(struct file *file
+
+ retval = dma_region_mmap(&video->dv_buf, file, vma);
+ out:
+- up(&video->sem);
++ mutex_unlock(&video->mtx);
+ return retval;
+ }
+
+@@ -1337,17 +1338,17 @@ static ssize_t dv1394_write(struct file
+
+ /* serialize this to prevent multi-threaded mayhem */
+ if (file->f_flags & O_NONBLOCK) {
+- if (down_trylock(&video->sem))
++ if (!mutex_trylock(&video->mtx))
+ return -EAGAIN;
+ } else {
+- if (down_interruptible(&video->sem))
++ if (mutex_lock_interruptible(&video->mtx))
+ return -ERESTARTSYS;
+ }
+
+ if ( !video_card_initialized(video) ) {
+ ret = do_dv1394_init_default(video);
+ if (ret) {
+- up(&video->sem);
++ mutex_unlock(&video->mtx);
+ return ret;
+ }
+ }
+@@ -1418,7 +1419,7 @@ static ssize_t dv1394_write(struct file
+
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+- up(&video->sem);
++ mutex_unlock(&video->mtx);
+ return ret;
+ }
+
+@@ -1434,17 +1435,17 @@ static ssize_t dv1394_read(struct file *
+
+ /* serialize this to prevent multi-threaded mayhem */
+ if (file->f_flags & O_NONBLOCK) {
+- if (down_trylock(&video->sem))
++ if (!mutex_trylock(&video->mtx))
+ return -EAGAIN;
+ } else {
+- if (down_interruptible(&video->sem))
++ if (mutex_lock_interruptible(&video->mtx))
+ return -ERESTARTSYS;
+ }
+
+ if ( !video_card_initialized(video) ) {
+ ret = do_dv1394_init_default(video);
+ if (ret) {
+- up(&video->sem);
++ mutex_unlock(&video->mtx);
+ return ret;
+ }
+ video->continuity_counter = -1;
+@@ -1526,7 +1527,7 @@ static ssize_t dv1394_read(struct file *
+
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+- up(&video->sem);
++ mutex_unlock(&video->mtx);
+ return ret;
+ }
+
+@@ -1547,12 +1548,12 @@ static long dv1394_ioctl(struct file *fi
+
+ /* serialize this to prevent multi-threaded mayhem */
+ if (file->f_flags & O_NONBLOCK) {
+- if (down_trylock(&video->sem)) {
++ if (!mutex_trylock(&video->mtx)) {
+ unlock_kernel();
+ return -EAGAIN;
+ }
+ } else {
+- if (down_interruptible(&video->sem)) {
++ if (mutex_lock_interruptible(&video->mtx)) {
+ unlock_kernel();
+ return -ERESTARTSYS;
+ }
+@@ -1778,7 +1779,7 @@ static long dv1394_ioctl(struct file *fi
+ }
+
+ out:
+- up(&video->sem);
++ mutex_unlock(&video->mtx);
+ unlock_kernel();
+ return ret;
+ }
+@@ -2253,7 +2254,7 @@ static int dv1394_init(struct ti_ohci *o
+ clear_bit(0, &video->open);
+ spin_lock_init(&video->spinlock);
+ video->dma_running = 0;
+- init_MUTEX(&video->sem);
++ mutex_init(&video->mtx);
+ init_waitqueue_head(&video->waitq);
+ video->fasync = NULL;
+
+diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
+index 2d5b57b..31e5cc4 100644
+--- a/drivers/ieee1394/eth1394.c
++++ b/drivers/ieee1394/eth1394.c
+@@ -64,19 +64,20 @@
+ #include <linux/ethtool.h>
+ #include <asm/uaccess.h>
+ #include <asm/delay.h>
+-#include <asm/semaphore.h>
++#include <asm/unaligned.h>
+ #include <net/arp.h>
+
++#include "config_roms.h"
+ #include "csr1212.h"
+-#include "ieee1394_types.h"
++#include "eth1394.h"
++#include "highlevel.h"
++#include "ieee1394.h"
+ #include "ieee1394_core.h"
++#include "ieee1394_hotplug.h"
+ #include "ieee1394_transactions.h"
+-#include "ieee1394.h"
+-#include "highlevel.h"
++#include "ieee1394_types.h"
+ #include "iso.h"
+ #include "nodemgr.h"
+-#include "eth1394.h"
+-#include "config_roms.h"
+
+ #define ETH1394_PRINT_G(level, fmt, args...) \
+ printk(level "%s: " fmt, driver_name, ## args)
+@@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct
+ int i;
+ struct eth1394_priv *priv = netdev_priv(dev);
+ struct hpsb_host *host = priv->host;
+- u64 guid = *((u64*)&(host->csr.rom->bus_info_data[3]));
++ u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3]));
+ u16 maxpayload = 1 << (host->csr.max_rec + 1);
+ int max_speed = IEEE1394_SPEED_MAX;
+
+@@ -514,8 +515,8 @@ static void ether1394_reset_priv (struct
+ ETHER1394_GASP_OVERHEAD)));
+
+ /* Set our hardware address while we're at it */
+- *(u64*)dev->dev_addr = guid;
+- *(u64*)dev->broadcast = ~0x0ULL;
++ memcpy(dev->dev_addr, &guid, sizeof(u64));
++ memset(dev->broadcast, 0xff, sizeof(u64));
+ }
+
+ spin_unlock_irqrestore (&priv->lock, flags);
+@@ -894,6 +895,7 @@ static inline u16 ether1394_parse_encap(
+ u16 maxpayload;
+ struct eth1394_node_ref *node;
+ struct eth1394_node_info *node_info;
++ __be64 guid;
+
+ /* Sanity check. MacOSX seems to be sending us 131 in this
+ * field (atleast on my Panther G5). Not sure why. */
+@@ -902,8 +904,9 @@ static inline u16 ether1394_parse_encap(
+
+ maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1)));
+
++ guid = get_unaligned(&arp1394->s_uniq_id);
+ node = eth1394_find_node_guid(&priv->ip_node_list,
+- be64_to_cpu(arp1394->s_uniq_id));
++ be64_to_cpu(guid));
+ if (!node) {
+ return 0;
+ }
+@@ -931,10 +934,9 @@ static inline u16 ether1394_parse_encap(
+ arp_ptr += arp->ar_pln; /* skip over sender IP addr */
+
+ if (arp->ar_op == htons(ARPOP_REQUEST))
+- /* just set ARP req target unique ID to 0 */
+- *((u64*)arp_ptr) = 0;
++ memset(arp_ptr, 0, sizeof(u64));
+ else
+- *((u64*)arp_ptr) = *((u64*)dev->dev_addr);
++ memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
+ }
+
+ /* Now add the ethernet header. */
+@@ -1675,8 +1677,10 @@ static int ether1394_tx (struct sk_buff
+ if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
+ priv->bc_dgl++;
+ } else {
++ __be64 guid = get_unaligned((u64 *)eth->h_dest);
++
+ node = eth1394_find_node_guid(&priv->ip_node_list,
+- be64_to_cpu(*(u64*)eth->h_dest));
++ be64_to_cpu(guid));
+ if (!node) {
+ ret = -EAGAIN;
+ goto fail;
+diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
+index e119fb8..50f2dd2 100644
+--- a/drivers/ieee1394/highlevel.h
++++ b/drivers/ieee1394/highlevel.h
+@@ -1,60 +1,61 @@
+-
+ #ifndef IEEE1394_HIGHLEVEL_H
+ #define IEEE1394_HIGHLEVEL_H
+
++#include <linux/list.h>
++#include <linux/spinlock_types.h>
++#include <linux/types.h>
+
+-struct hpsb_address_serve {
+- struct list_head host_list; /* per host list */
++struct module;
+
+- struct list_head hl_list; /* hpsb_highlevel list */
++#include "ieee1394_types.h"
+
+- struct hpsb_address_ops *op;
++struct hpsb_host;
+
++/* internal to ieee1394 core */
++struct hpsb_address_serve {
++ struct list_head host_list; /* per host list */
++ struct list_head hl_list; /* hpsb_highlevel list */
++ struct hpsb_address_ops *op;
+ struct hpsb_host *host;
+-
+- /* first address handled and first address behind, quadlet aligned */
+- u64 start, end;
++ u64 start; /* first address handled, quadlet aligned */
++ u64 end; /* first address behind, quadlet aligned */
+ };
+
+-
+-/*
+- * The above structs are internal to highlevel driver handling. Only the
+- * following structures are of interest to actual highlevel drivers.
+- */
++/* Only the following structures are of interest to actual highlevel drivers. */
+
+ struct hpsb_highlevel {
+ struct module *owner;
+ const char *name;
+
+- /* Any of the following pointers can legally be NULL, except for
+- * iso_receive which can only be NULL when you don't request
+- * channels. */
++ /* Any of the following pointers can legally be NULL, except for
++ * iso_receive which can only be NULL when you don't request
++ * channels. */
+
+- /* New host initialized. Will also be called during
+- * hpsb_register_highlevel for all hosts already installed. */
+- void (*add_host) (struct hpsb_host *host);
++ /* New host initialized. Will also be called during
++ * hpsb_register_highlevel for all hosts already installed. */
++ void (*add_host)(struct hpsb_host *host);
+
+- /* Host about to be removed. Will also be called during
+- * hpsb_unregister_highlevel once for each host. */
+- void (*remove_host) (struct hpsb_host *host);
++ /* Host about to be removed. Will also be called during
++ * hpsb_unregister_highlevel once for each host. */
++ void (*remove_host)(struct hpsb_host *host);
+
+- /* Host experienced bus reset with possible configuration changes.
++ /* Host experienced bus reset with possible configuration changes.
+ * Note that this one may occur during interrupt/bottom half handling.
+ * You can not expect to be able to do stock hpsb_reads. */
+- void (*host_reset) (struct hpsb_host *host);
++ void (*host_reset)(struct hpsb_host *host);
+
+- /* An isochronous packet was received. Channel contains the channel
+- * number for your convenience, it is also contained in the included
+- * packet header (first quadlet, CRCs are missing). You may get called
+- * for channel/host combinations you did not request. */
+- void (*iso_receive) (struct hpsb_host *host, int channel,
+- quadlet_t *data, size_t length);
++ /* An isochronous packet was received. Channel contains the channel
++ * number for your convenience, it is also contained in the included
++ * packet header (first quadlet, CRCs are missing). You may get called
++ * for channel/host combinations you did not request. */
++ void (*iso_receive)(struct hpsb_host *host, int channel,
++ quadlet_t *data, size_t length);
+
+- /* A write request was received on either the FCP_COMMAND (direction =
+- * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
+- * contains the cts field (first byte of data). */
+- void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction,
+- int cts, u8 *data, size_t length);
++ /* A write request was received on either the FCP_COMMAND (direction =
++ * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
++ * contains the cts field (first byte of data). */
++ void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
++ int cts, u8 *data, size_t length);
+
+ /* These are initialized by the subsystem when the
+ * hpsb_higlevel is registered. */
+@@ -67,61 +68,62 @@ struct hpsb_highlevel {
+ };
+
+ struct hpsb_address_ops {
+- /*
+- * Null function pointers will make the respective operation complete
+- * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
+- * registers (just leave everything but read NULL).
+- *
+- * All functions shall return appropriate IEEE 1394 rcodes.
+- */
+-
+- /* These functions have to implement block reads for themselves. */
+- /* These functions either return a response code
+- or a negative number. In the first case a response will be generated; in the
+- later case, no response will be sent and the driver, that handled the request
+- will send the response itself
+- */
+- int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+- u64 addr, size_t length, u16 flags);
+- int (*write) (struct hpsb_host *host, int nodeid, int destid,
+- quadlet_t *data, u64 addr, size_t length, u16 flags);
+-
+- /* Lock transactions: write results of ext_tcode operation into
+- * *store. */
+- int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
+- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
+- int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
+- u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
++ /*
++ * Null function pointers will make the respective operation complete
++ * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
++ * registers (just leave everything but read NULL).
++ *
++ * All functions shall return appropriate IEEE 1394 rcodes.
++ */
++
++ /* These functions have to implement block reads for themselves.
++ *
++ * These functions either return a response code or a negative number.
++ * In the first case a response will be generated. In the latter case,
++ * no response will be sent and the driver which handled the request
++ * will send the response itself. */
++ int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
++ u64 addr, size_t length, u16 flags);
++ int (*write)(struct hpsb_host *host, int nodeid, int destid,
++ quadlet_t *data, u64 addr, size_t length, u16 flags);
++
++ /* Lock transactions: write results of ext_tcode operation into
++ * *store. */
++ int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
++ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
++ u16 flags);
++ int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
++ u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
++ u16 flags);
+ };
+
+-
+ void highlevel_add_host(struct hpsb_host *host);
+ void highlevel_remove_host(struct hpsb_host *host);
+ void highlevel_host_reset(struct hpsb_host *host);
+
+-
+-/* these functions are called to handle transactions. They are called, when
+- a packet arrives. The flags argument contains the second word of the first header
+- quadlet of the incoming packet (containing transaction label, retry code,
+- transaction code and priority). These functions either return a response code
+- or a negative number. In the first case a response will be generated; in the
+- later case, no response will be sent and the driver, that handled the request
+- will send the response itself.
+-*/
+-int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
+- u64 addr, unsigned int length, u16 flags);
+-int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
+- void *data, u64 addr, unsigned int length, u16 flags);
++/*
++ * These functions are called to handle transactions. They are called when a
++ * packet arrives. The flags argument contains the second word of the first
++ * header quadlet of the incoming packet (containing transaction label, retry
++ * code, transaction code and priority). These functions either return a
++ * response code or a negative number. In the first case a response will be
++ * generated. In the latter case, no response will be sent and the driver which
++ * handled the request will send the response itself.
++ */
++int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
++ unsigned int length, u16 flags);
++int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
++ u64 addr, unsigned int length, u16 flags);
+ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
++ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
++ u16 flags);
+ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+- u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
++ u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
++ u16 flags);
+
+-void highlevel_iso_receive(struct hpsb_host *host, void *data,
+- size_t length);
++void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length);
+ void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+- void *data, size_t length);
+-
++ void *data, size_t length);
+
+ /*
+ * Register highlevel driver. The name pointer has to stay valid at all times
+@@ -132,13 +134,15 @@ void hpsb_unregister_highlevel(struct hp
+
+ /*
+ * Register handlers for host address spaces. Start and end are 48 bit pointers
+- * and have to be quadlet aligned (end points to the first address behind the
+- * handled addresses. This function can be called multiple times for a single
+- * hpsb_highlevel to implement sparse register sets. The requested region must
+- * not overlap any previously allocated region, otherwise registering will fail.
++ * and have to be quadlet aligned. Argument "end" points to the first address
++ * behind the handled addresses. This function can be called multiple times for
++ * a single hpsb_highlevel to implement sparse register sets. The requested
++ * region must not overlap any previously allocated region, otherwise
++ * registering will fail.
+ *
+- * It returns true for successful allocation. There is no unregister function,
+- * all address spaces are deallocated together with the hpsb_highlevel.
++ * It returns true for successful allocation. Address spaces can be
++ * unregistered with hpsb_unregister_addrspace. All remaining address spaces
++ * are automatically deallocated together with the hpsb_highlevel.
+ */
+ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
+ struct hpsb_host *host,
+@@ -146,20 +150,18 @@ u64 hpsb_allocate_and_register_addrspace
+ u64 size, u64 alignment,
+ u64 start, u64 end);
+ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
+- struct hpsb_address_ops *ops, u64 start, u64 end);
+-
++ struct hpsb_address_ops *ops, u64 start, u64 end);
+ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
+- u64 start);
++ u64 start);
+
+ /*
+ * Enable or disable receving a certain isochronous channel through the
+ * iso_receive op.
+ */
+ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
+- unsigned int channel);
++ unsigned int channel);
+ void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
+- unsigned int channel);
+-
++ unsigned int channel);
+
+ /* Retrieve a hostinfo pointer bound to this driver/host */
+ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
+@@ -172,19 +174,24 @@ void *hpsb_create_hostinfo(struct hpsb_h
+ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
+
+ /* Set an alternate lookup key for the hostinfo bound to this driver/host */
+-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key);
++void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
++ unsigned long key);
+
+-/* Retrieve the alternate lookup key for the hostinfo bound to this driver/host */
+-unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host);
++/* Retrieve the alternate lookup key for the hostinfo bound to this
++ * driver/host */
++unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl,
++ struct hpsb_host *host);
+
+ /* Retrieve a hostinfo pointer bound to this driver using its alternate key */
+ void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
+
+ /* Set the hostinfo pointer to something useful. Usually follows a call to
+ * hpsb_create_hostinfo, where the size is 0. */
+-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *data);
++int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
++ void *data);
+
+ /* Retrieve hpsb_host using a highlevel handle and a key */
+-struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key);
++struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl,
++ unsigned long key);
+
+ #endif /* IEEE1394_HIGHLEVEL_H */
+diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
+index 4feead4..d90a3a1 100644
+--- a/drivers/ieee1394/hosts.c
++++ b/drivers/ieee1394/hosts.c
+@@ -90,6 +90,16 @@ static int alloc_hostnum_cb(struct hpsb_
+ return 0;
+ }
+
++/*
++ * The pending_packet_queue is special in that it's processed
++ * from hardirq context too (such as hpsb_bus_reset()). Hence
++ * split the lock class from the usual networking skb-head
++ * lock class by using a separate key for it:
++ */
++static struct lock_class_key pending_packet_queue_key;
++
++static DEFINE_MUTEX(host_num_alloc);
++
+ /**
+ * hpsb_alloc_host - allocate a new host controller.
+ * @drv: the driver that will manage the host controller
+@@ -105,16 +115,6 @@ static int alloc_hostnum_cb(struct hpsb_
+ * Return Value: a pointer to the &hpsb_host if successful, %NULL if
+ * no memory was available.
+ */
+-static DEFINE_MUTEX(host_num_alloc);
+-
+-/*
+- * The pending_packet_queue is special in that it's processed
+- * from hardirq context too (such as hpsb_bus_reset()). Hence
+- * split the lock class from the usual networking skb-head
+- * lock class by using a separate key for it:
+- */
+-static struct lock_class_key pending_packet_queue_key;
+-
+ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
+ struct device *dev)
+ {
+@@ -143,9 +143,6 @@ struct hpsb_host *hpsb_alloc_host(struct
+ for (i = 2; i < 16; i++)
+ h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
+
+- for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
+- HPSB_TPOOL_INIT(&h->tpool[i]);
+-
+ atomic_set(&h->generation, 0);
+
+ INIT_WORK(&h->delayed_reset, delayed_reset_bus, h);
+diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
+index 9ad4b24..bc6dbfa 100644
+--- a/drivers/ieee1394/hosts.h
++++ b/drivers/ieee1394/hosts.h
+@@ -2,17 +2,19 @@
+ #define _IEEE1394_HOSTS_H
+
+ #include <linux/device.h>
+-#include <linux/wait.h>
+ #include <linux/list.h>
+-#include <linux/timer.h>
+ #include <linux/skbuff.h>
++#include <linux/timer.h>
++#include <linux/types.h>
++#include <linux/workqueue.h>
++#include <asm/atomic.h>
+
+-#include <asm/semaphore.h>
++struct pci_dev;
++struct module;
+
+ #include "ieee1394_types.h"
+ #include "csr.h"
+
+-
+ struct hpsb_packet;
+ struct hpsb_iso;
+
+@@ -33,7 +35,6 @@ struct hpsb_host {
+ int node_count; /* number of identified nodes on this bus */
+ int selfid_count; /* total number of SelfIDs received */
+ int nodes_active; /* number of nodes with active link layer */
+- u8 speed[ALL_NODES]; /* speed between each node and local node */
+
+ nodeid_t node_id; /* node ID of this host */
+ nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
+@@ -53,31 +54,29 @@ struct hpsb_host {
+ int reset_retries;
+ quadlet_t *topology_map;
+ u8 *speed_map;
+- struct csr_control csr;
+-
+- /* Per node tlabel pool allocation */
+- struct hpsb_tlabel_pool tpool[ALL_NODES];
+
++ int id;
+ struct hpsb_host_driver *driver;
+-
+ struct pci_dev *pdev;
+-
+- int id;
+-
+ struct device device;
+ struct class_device class_dev;
+
+ int update_config_rom;
+ struct work_struct delayed_reset;
+-
+ unsigned int config_roms;
+
+ struct list_head addr_space;
+ u64 low_addr_space; /* upper bound of physical DMA area */
+ u64 middle_addr_space; /* upper bound of posted write area */
+-};
+
++ u8 speed[ALL_NODES]; /* speed between each node and local node */
++
++ /* per node tlabel allocation */
++ u8 next_tl[ALL_NODES];
++ struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
+
++ struct csr_control csr;
++};
+
+ enum devctl_cmd {
+ /* Host is requested to reset its bus and cancel all outstanding async
+@@ -112,7 +111,7 @@ enum devctl_cmd {
+
+ enum isoctl_cmd {
+ /* rawiso API - see iso.h for the meanings of these commands
+- (they correspond exactly to the hpsb_iso_* API functions)
++ * (they correspond exactly to the hpsb_iso_* API functions)
+ * INIT = allocate resources
+ * START = begin transmission/reception
+ * STOP = halt transmission/reception
+@@ -160,7 +159,8 @@ struct hpsb_host_driver {
+ /* The hardware driver may optionally support a function that is used
+ * to set the hardware ConfigROM if the hardware supports handling
+ * reads to the ConfigROM on its own. */
+- void (*set_hw_config_rom) (struct hpsb_host *host, quadlet_t *config_rom);
++ void (*set_hw_config_rom)(struct hpsb_host *host,
++ quadlet_t *config_rom);
+
+ /* This function shall implement packet transmission based on
+ * packet->type. It shall CRC both parts of the packet (unless
+@@ -170,20 +170,21 @@ struct hpsb_host_driver {
+ * called. Return 0 on success, negative errno on failure.
+ * NOTE: The function must be callable in interrupt context.
+ */
+- int (*transmit_packet) (struct hpsb_host *host,
+- struct hpsb_packet *packet);
++ int (*transmit_packet)(struct hpsb_host *host,
++ struct hpsb_packet *packet);
+
+ /* This function requests miscellanous services from the driver, see
+ * above for command codes and expected actions. Return -1 for unknown
+ * command, though that should never happen.
+ */
+- int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg);
++ int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
+
+ /* ISO transmission/reception functions. Return 0 on success, -1
+ * (or -EXXX errno code) on failure. If the low-level driver does not
+ * support the new ISO API, set isoctl to NULL.
+ */
+- int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg);
++ int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
++ unsigned long arg);
+
+ /* This function is mainly to redirect local CSR reads/locks to the iso
+ * management registers (bus manager id, bandwidth available, channels
+@@ -196,19 +197,11 @@ struct hpsb_host_driver {
+ quadlet_t data, quadlet_t compare);
+ };
+
+-
+ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
+ struct device *dev);
+ int hpsb_add_host(struct hpsb_host *host);
+ void hpsb_remove_host(struct hpsb_host *h);
+
+-/* The following 2 functions are deprecated and will be removed when the
+- * raw1394/libraw1394 update is complete. */
+-int hpsb_update_config_rom(struct hpsb_host *host,
+- const quadlet_t *new_rom, size_t size, unsigned char rom_version);
+-int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
+- size_t buffersize, size_t *rom_size, unsigned char *rom_version);
+-
+ /* Updates the configuration rom image of a host. rom_version must be the
+ * current version, otherwise it will fail with return value -1. If this
+ * host does not support config-rom-update, it will return -EINVAL.
+diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h
+index 1567039..8f20750 100644
+--- a/drivers/ieee1394/ieee1394-ioctl.h
++++ b/drivers/ieee1394/ieee1394-ioctl.h
+@@ -1,5 +1,7 @@
+-/* Base file for all ieee1394 ioctl's. Linux-1394 has allocated base '#'
+- * with a range of 0x00-0x3f. */
++/*
++ * Base file for all ieee1394 ioctl's.
++ * Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
++ */
+
+ #ifndef __IEEE1394_IOCTL_H
+ #define __IEEE1394_IOCTL_H
+@@ -96,8 +98,7 @@
+ _IOW ('#', 0x27, struct raw1394_iso_packets)
+ #define RAW1394_IOC_ISO_XMIT_SYNC \
+ _IO ('#', 0x28)
+-#define RAW1394_IOC_ISO_RECV_FLUSH \
++#define RAW1394_IOC_ISO_RECV_FLUSH \
+ _IO ('#', 0x29)
+
+-
+ #endif /* __IEEE1394_IOCTL_H */
+diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
+index 936d776..4049207 100644
+--- a/drivers/ieee1394/ieee1394.h
++++ b/drivers/ieee1394/ieee1394.h
+@@ -5,77 +5,78 @@
+ #ifndef _IEEE1394_IEEE1394_H
+ #define _IEEE1394_IEEE1394_H
+
+-#define TCODE_WRITEQ 0x0
+-#define TCODE_WRITEB 0x1
+-#define TCODE_WRITE_RESPONSE 0x2
+-#define TCODE_READQ 0x4
+-#define TCODE_READB 0x5
+-#define TCODE_READQ_RESPONSE 0x6
+-#define TCODE_READB_RESPONSE 0x7
+-#define TCODE_CYCLE_START 0x8
+-#define TCODE_LOCK_REQUEST 0x9
+-#define TCODE_ISO_DATA 0xa
+-#define TCODE_STREAM_DATA 0xa
+-#define TCODE_LOCK_RESPONSE 0xb
+-
+-#define RCODE_COMPLETE 0x0
+-#define RCODE_CONFLICT_ERROR 0x4
+-#define RCODE_DATA_ERROR 0x5
+-#define RCODE_TYPE_ERROR 0x6
+-#define RCODE_ADDRESS_ERROR 0x7
+-
+-#define EXTCODE_MASK_SWAP 0x1
+-#define EXTCODE_COMPARE_SWAP 0x2
+-#define EXTCODE_FETCH_ADD 0x3
+-#define EXTCODE_LITTLE_ADD 0x4
+-#define EXTCODE_BOUNDED_ADD 0x5
+-#define EXTCODE_WRAP_ADD 0x6
+-
+-#define ACK_COMPLETE 0x1
+-#define ACK_PENDING 0x2
+-#define ACK_BUSY_X 0x4
+-#define ACK_BUSY_A 0x5
+-#define ACK_BUSY_B 0x6
+-#define ACK_TARDY 0xb
+-#define ACK_CONFLICT_ERROR 0xc
+-#define ACK_DATA_ERROR 0xd
+-#define ACK_TYPE_ERROR 0xe
+-#define ACK_ADDRESS_ERROR 0xf
++#define TCODE_WRITEQ 0x0
++#define TCODE_WRITEB 0x1
++#define TCODE_WRITE_RESPONSE 0x2
++#define TCODE_READQ 0x4
++#define TCODE_READB 0x5
++#define TCODE_READQ_RESPONSE 0x6
++#define TCODE_READB_RESPONSE 0x7
++#define TCODE_CYCLE_START 0x8
++#define TCODE_LOCK_REQUEST 0x9
++#define TCODE_ISO_DATA 0xa
++#define TCODE_STREAM_DATA 0xa
++#define TCODE_LOCK_RESPONSE 0xb
++
++#define RCODE_COMPLETE 0x0
++#define RCODE_CONFLICT_ERROR 0x4
++#define RCODE_DATA_ERROR 0x5
++#define RCODE_TYPE_ERROR 0x6
++#define RCODE_ADDRESS_ERROR 0x7
++
++#define EXTCODE_MASK_SWAP 0x1
++#define EXTCODE_COMPARE_SWAP 0x2
++#define EXTCODE_FETCH_ADD 0x3
++#define EXTCODE_LITTLE_ADD 0x4
++#define EXTCODE_BOUNDED_ADD 0x5
++#define EXTCODE_WRAP_ADD 0x6
++
++#define ACK_COMPLETE 0x1
++#define ACK_PENDING 0x2
++#define ACK_BUSY_X 0x4
++#define ACK_BUSY_A 0x5
++#define ACK_BUSY_B 0x6
++#define ACK_TARDY 0xb
++#define ACK_CONFLICT_ERROR 0xc
++#define ACK_DATA_ERROR 0xd
++#define ACK_TYPE_ERROR 0xe
++#define ACK_ADDRESS_ERROR 0xf
+
+ /* Non-standard "ACK codes" for internal use */
+-#define ACKX_NONE (-1)
+-#define ACKX_SEND_ERROR (-2)
+-#define ACKX_ABORTED (-3)
+-#define ACKX_TIMEOUT (-4)
+-
+-
+-#define IEEE1394_SPEED_100 0x00
+-#define IEEE1394_SPEED_200 0x01
+-#define IEEE1394_SPEED_400 0x02
+-#define IEEE1394_SPEED_800 0x03
+-#define IEEE1394_SPEED_1600 0x04
+-#define IEEE1394_SPEED_3200 0x05
++#define ACKX_NONE (-1)
++#define ACKX_SEND_ERROR (-2)
++#define ACKX_ABORTED (-3)
++#define ACKX_TIMEOUT (-4)
++
++#define IEEE1394_SPEED_100 0x00
++#define IEEE1394_SPEED_200 0x01
++#define IEEE1394_SPEED_400 0x02
++#define IEEE1394_SPEED_800 0x03
++#define IEEE1394_SPEED_1600 0x04
++#define IEEE1394_SPEED_3200 0x05
++
+ /* The current highest tested speed supported by the subsystem */
+-#define IEEE1394_SPEED_MAX IEEE1394_SPEED_800
++#define IEEE1394_SPEED_MAX IEEE1394_SPEED_800
+
+ /* Maps speed values above to a string representation */
+ extern const char *hpsb_speedto_str[];
+
+-
+ /* 1394a cable PHY packets */
+-#define SELFID_PWRCL_NO_POWER 0x0
+-#define SELFID_PWRCL_PROVIDE_15W 0x1
+-#define SELFID_PWRCL_PROVIDE_30W 0x2
+-#define SELFID_PWRCL_PROVIDE_45W 0x3
+-#define SELFID_PWRCL_USE_1W 0x4
+-#define SELFID_PWRCL_USE_3W 0x5
+-#define SELFID_PWRCL_USE_6W 0x6
+-#define SELFID_PWRCL_USE_10W 0x7
+-
+-#define SELFID_PORT_CHILD 0x3
+-#define SELFID_PORT_PARENT 0x2
+-#define SELFID_PORT_NCONN 0x1
+-#define SELFID_PORT_NONE 0x0
++#define SELFID_PWRCL_NO_POWER 0x0
++#define SELFID_PWRCL_PROVIDE_15W 0x1
++#define SELFID_PWRCL_PROVIDE_30W 0x2
++#define SELFID_PWRCL_PROVIDE_45W 0x3
++#define SELFID_PWRCL_USE_1W 0x4
++#define SELFID_PWRCL_USE_3W 0x5
++#define SELFID_PWRCL_USE_6W 0x6
++#define SELFID_PWRCL_USE_10W 0x7
++
++#define SELFID_PORT_CHILD 0x3
++#define SELFID_PORT_PARENT 0x2
++#define SELFID_PORT_NCONN 0x1
++#define SELFID_PORT_NONE 0x0
++
++#define SELFID_SPEED_UNKNOWN 0x3 /* 1394b PHY */
+
+ #define PHYPACKET_LINKON 0x40000000
+ #define PHYPACKET_PHYCONFIG_R 0x00800000
+@@ -91,76 +92,76 @@ extern const char *hpsb_speedto_str[];
+
+ #define EXTPHYPACKET_TYPEMASK 0xC0FC0000
+
+-#define PHYPACKET_PORT_SHIFT 24
+-#define PHYPACKET_GAPCOUNT_SHIFT 16
++#define PHYPACKET_PORT_SHIFT 24
++#define PHYPACKET_GAPCOUNT_SHIFT 16
+
+ /* 1394a PHY register map bitmasks */
+-#define PHY_00_PHYSICAL_ID 0xFC
+-#define PHY_00_R 0x02 /* Root */
+-#define PHY_00_PS 0x01 /* Power Status*/
+-#define PHY_01_RHB 0x80 /* Root Hold-Off */
+-#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
+-#define PHY_01_GAP_COUNT 0x3F
+-#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
+-#define PHY_02_TOTAL_PORTS 0x1F
+-#define PHY_03_MAX_SPEED 0xE0
+-#define PHY_03_DELAY 0x0F
+-#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
+-#define PHY_04_CONTENDER 0x40
+-#define PHY_04_JITTER 0x38
+-#define PHY_04_PWR_CLASS 0x07 /* Power Class */
+-#define PHY_05_WATCHDOG 0x80
+-#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
+-#define PHY_05_LOOP 0x20 /* Loop Detect */
+-#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
+-#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
+-#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
+-#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
+-#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
++#define PHY_00_PHYSICAL_ID 0xFC
++#define PHY_00_R 0x02 /* Root */
++#define PHY_00_PS 0x01 /* Power Status*/
++#define PHY_01_RHB 0x80 /* Root Hold-Off */
++#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
++#define PHY_01_GAP_COUNT 0x3F
++#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
++#define PHY_02_TOTAL_PORTS 0x1F
++#define PHY_03_MAX_SPEED 0xE0
++#define PHY_03_DELAY 0x0F
++#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
++#define PHY_04_CONTENDER 0x40
++#define PHY_04_JITTER 0x38
++#define PHY_04_PWR_CLASS 0x07 /* Power Class */
++#define PHY_05_WATCHDOG 0x80
++#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
++#define PHY_05_LOOP 0x20 /* Loop Detect */
++#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
++#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
++#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
++#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
++#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
+
+ #include <asm/byteorder.h>
+
+ #ifdef __BIG_ENDIAN_BITFIELD
+
+ struct selfid {
+- u32 packet_identifier:2; /* always binary 10 */
+- u32 phy_id:6;
+- /* byte */
+- u32 extended:1; /* if true is struct ext_selfid */
+- u32 link_active:1;
+- u32 gap_count:6;
+- /* byte */
+- u32 speed:2;
+- u32 phy_delay:2;
+- u32 contender:1;
+- u32 power_class:3;
+- /* byte */
+- u32 port0:2;
+- u32 port1:2;
+- u32 port2:2;
+- u32 initiated_reset:1;
+- u32 more_packets:1;
++ u32 packet_identifier:2; /* always binary 10 */
++ u32 phy_id:6;
++ /* byte */
++ u32 extended:1; /* if true is struct ext_selfid */
++ u32 link_active:1;
++ u32 gap_count:6;
++ /* byte */
++ u32 speed:2;
++ u32 phy_delay:2;
++ u32 contender:1;
++ u32 power_class:3;
++ /* byte */
++ u32 port0:2;
++ u32 port1:2;
++ u32 port2:2;
++ u32 initiated_reset:1;
++ u32 more_packets:1;
+ } __attribute__((packed));
+
+ struct ext_selfid {
+- u32 packet_identifier:2; /* always binary 10 */
+- u32 phy_id:6;
+- /* byte */
+- u32 extended:1; /* if false is struct selfid */
+- u32 seq_nr:3;
+- u32 reserved:2;
+- u32 porta:2;
+- /* byte */
+- u32 portb:2;
+- u32 portc:2;
+- u32 portd:2;
+- u32 porte:2;
+- /* byte */
+- u32 portf:2;
+- u32 portg:2;
+- u32 porth:2;
+- u32 reserved2:1;
+- u32 more_packets:1;
++ u32 packet_identifier:2; /* always binary 10 */
++ u32 phy_id:6;
++ /* byte */
++ u32 extended:1; /* if false is struct selfid */
++ u32 seq_nr:3;
++ u32 reserved:2;
++ u32 porta:2;
++ /* byte */
++ u32 portb:2;
++ u32 portc:2;
++ u32 portd:2;
++ u32 porte:2;
++ /* byte */
++ u32 portf:2;
++ u32 portg:2;
++ u32 porth:2;
++ u32 reserved2:1;
++ u32 more_packets:1;
+ } __attribute__((packed));
+
+ #elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
+@@ -171,49 +172,48 @@ struct ext_selfid {
+ */
+
+ struct selfid {
+- u32 phy_id:6;
+- u32 packet_identifier:2; /* always binary 10 */
+- /* byte */
+- u32 gap_count:6;
+- u32 link_active:1;
+- u32 extended:1; /* if true is struct ext_selfid */
+- /* byte */
+- u32 power_class:3;
+- u32 contender:1;
+- u32 phy_delay:2;
+- u32 speed:2;
+- /* byte */
+- u32 more_packets:1;
+- u32 initiated_reset:1;
+- u32 port2:2;
+- u32 port1:2;
+- u32 port0:2;
++ u32 phy_id:6;
++ u32 packet_identifier:2; /* always binary 10 */
++ /* byte */
++ u32 gap_count:6;
++ u32 link_active:1;
++ u32 extended:1; /* if true is struct ext_selfid */
++ /* byte */
++ u32 power_class:3;
++ u32 contender:1;
++ u32 phy_delay:2;
++ u32 speed:2;
++ /* byte */
++ u32 more_packets:1;
++ u32 initiated_reset:1;
++ u32 port2:2;
++ u32 port1:2;
++ u32 port0:2;
+ } __attribute__((packed));
+
+ struct ext_selfid {
+- u32 phy_id:6;
+- u32 packet_identifier:2; /* always binary 10 */
+- /* byte */
+- u32 porta:2;
+- u32 reserved:2;
+- u32 seq_nr:3;
+- u32 extended:1; /* if false is struct selfid */
+- /* byte */
+- u32 porte:2;
+- u32 portd:2;
+- u32 portc:2;
+- u32 portb:2;
+- /* byte */
+- u32 more_packets:1;
+- u32 reserved2:1;
+- u32 porth:2;
+- u32 portg:2;
+- u32 portf:2;
++ u32 phy_id:6;
++ u32 packet_identifier:2; /* always binary 10 */
++ /* byte */
++ u32 porta:2;
++ u32 reserved:2;
++ u32 seq_nr:3;
++ u32 extended:1; /* if false is struct selfid */
++ /* byte */
++ u32 porte:2;
++ u32 portd:2;
++ u32 portc:2;
++ u32 portb:2;
++ /* byte */
++ u32 more_packets:1;
++ u32 reserved2:1;
++ u32 porth:2;
++ u32 portg:2;
++ u32 portf:2;
+ } __attribute__((packed));
+
+ #else
+ #error What? PDP endian?
+ #endif /* __BIG_ENDIAN_BITFIELD */
+
+-
+ #endif /* _IEEE1394_IEEE1394_H */
+diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
+index f43739c..5fccf9f 100644
+--- a/drivers/ieee1394/ieee1394_core.c
++++ b/drivers/ieee1394/ieee1394_core.c
+@@ -35,7 +35,6 @@
+ #include <linux/kthread.h>
+
+ #include <asm/byteorder.h>
+-#include <asm/semaphore.h>
+
+ #include "ieee1394_types.h"
+ #include "ieee1394.h"
+@@ -86,7 +85,7 @@ static void dump_packet(const char *text
+ printk("\n");
+ }
+ #else
+-#define dump_packet(a,b,c,d)
++#define dump_packet(a,b,c,d) do {} while (0)
+ #endif
+
+ static void abort_requests(struct hpsb_host *host);
+@@ -355,10 +354,12 @@ static void build_speed_map(struct hpsb_
+ }
+ }
+
++#if SELFID_SPEED_UNKNOWN != IEEE1394_SPEED_MAX
+ /* assume maximum speed for 1394b PHYs, nodemgr will correct it */
+ for (n = 0; n < nodecount; n++)
+- if (speedcap[n] == 3)
++ if (speedcap[n] == SELFID_SPEED_UNKNOWN)
+ speedcap[n] = IEEE1394_SPEED_MAX;
++#endif
+ }
+
+
+@@ -1169,7 +1170,7 @@ static void __exit ieee1394_cleanup(void
+ unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
+ }
+
+-module_init(ieee1394_init);
++fs_initcall(ieee1394_init); /* same as ohci1394 */
+ module_exit(ieee1394_cleanup);
+
+ /* Exported symbols */
+diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
+index 0ecbf33..af4a78a 100644
+--- a/drivers/ieee1394/ieee1394_core.h
++++ b/drivers/ieee1394/ieee1394_core.h
+@@ -1,12 +1,15 @@
+-
+ #ifndef _IEEE1394_CORE_H
+ #define _IEEE1394_CORE_H
+
+-#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/list.h>
++#include <linux/skbuff.h>
++#include <linux/types.h>
+ #include <asm/atomic.h>
+-#include <asm/semaphore.h>
+-#include "hosts.h"
+
++#include "hosts.h"
++#include "ieee1394_types.h"
+
+ struct hpsb_packet {
+ /* This struct is basically read-only for hosts with the exception of
+@@ -58,7 +61,6 @@ struct hpsb_packet {
+ size_t header_size;
+ size_t data_size;
+
+-
+ struct hpsb_host *host;
+ unsigned int generation;
+
+@@ -80,7 +82,7 @@ struct hpsb_packet {
+
+ /* Set a task for when a packet completes */
+ void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
+- void (*routine)(void *), void *data);
++ void (*routine)(void *), void *data);
+
+ static inline struct hpsb_packet *driver_packet(struct list_head *l)
+ {
+@@ -92,7 +94,6 @@ void abort_timedouts(unsigned long __opa
+ struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
+ void hpsb_free_packet(struct hpsb_packet *packet);
+
+-
+ /*
+ * Generation counter for the complete 1394 subsystem. Generation gets
+ * incremented on every change in the subsystem (e.g. bus reset).
+@@ -204,10 +205,14 @@ void hpsb_packet_received(struct hpsb_ho
+ #define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
+
+ #define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
+-#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)
+-#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
+-#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16)
+-#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
++#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, \
++ IEEE1394_MINOR_BLOCK_RAW1394 * 16)
++#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, \
++ IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
++#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, \
++ IEEE1394_MINOR_BLOCK_DV1394 * 16)
++#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
++ IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
+
+ /* return the index (within a minor number block) of a file */
+ static inline unsigned char ieee1394_file_to_instance(struct file *file)
+@@ -223,4 +228,3 @@ extern struct class hpsb_host_class;
+ extern struct class *hpsb_protocol_class;
+
+ #endif /* _IEEE1394_CORE_H */
+-
+diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h
+index 5be70d3..dd5500e 100644
+--- a/drivers/ieee1394/ieee1394_hotplug.h
++++ b/drivers/ieee1394/ieee1394_hotplug.h
+@@ -1,33 +1,19 @@
+ #ifndef _IEEE1394_HOTPLUG_H
+ #define _IEEE1394_HOTPLUG_H
+
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/mod_devicetable.h>
+-
+ /* Unit spec id and sw version entry for some protocols */
+ #define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
+ #define AVC_SW_VERSION_ENTRY 0x00010001
+ #define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
+ #define CAMERA_SW_VERSION_ENTRY 0x00000100
+
+-/* Check to make sure this all isn't already defined */
+-#ifndef IEEE1394_MATCH_VENDOR_ID
+-
+-#define IEEE1394_MATCH_VENDOR_ID 0x0001
+-#define IEEE1394_MATCH_MODEL_ID 0x0002
+-#define IEEE1394_MATCH_SPECIFIER_ID 0x0004
+-#define IEEE1394_MATCH_VERSION 0x0008
+-
+-struct ieee1394_device_id {
+- u32 match_flags;
+- u32 vendor_id;
+- u32 model_id;
+- u32 specifier_id;
+- u32 version;
+- void *driver_data;
+-};
+-
+-#endif
++/* /include/linux/mod_devicetable.h defines:
++ * IEEE1394_MATCH_VENDOR_ID
++ * IEEE1394_MATCH_MODEL_ID
++ * IEEE1394_MATCH_SPECIFIER_ID
++ * IEEE1394_MATCH_VERSION
++ * struct ieee1394_device_id
++ */
++#include <linux/mod_devicetable.h>
+
+ #endif /* _IEEE1394_HOTPLUG_H */
+diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
+index a114b91..0833fc9 100644
+--- a/drivers/ieee1394/ieee1394_transactions.c
++++ b/drivers/ieee1394/ieee1394_transactions.c
+@@ -9,19 +9,17 @@
+ * directory of the kernel sources for details.
+ */
+
+-#include <linux/sched.h>
+ #include <linux/bitops.h>
+-#include <linux/smp_lock.h>
+-#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/wait.h>
+
++#include <asm/bug.h>
+ #include <asm/errno.h>
+
+ #include "ieee1394.h"
+ #include "ieee1394_types.h"
+ #include "hosts.h"
+ #include "ieee1394_core.h"
+-#include "highlevel.h"
+-#include "nodemgr.h"
+ #include "ieee1394_transactions.h"
+
+ #define PREP_ASYNC_HEAD_ADDRESS(tc) \
+@@ -31,6 +29,13 @@
+ packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
+ packet->header[2] = addr & 0xffffffff
+
++#ifndef HPSB_DEBUG_TLABELS
++static
++#endif
++spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
++
++static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
++
+ static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
+ {
+ PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
+@@ -114,9 +119,41 @@ static void fill_async_stream_packet(str
+ packet->tcode = TCODE_ISO_DATA;
+ }
+
++/* same as hpsb_get_tlabel, except that it returns immediately */
++static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
++{
++ unsigned long flags, *tp;
++ u8 *next;
++ int tlabel, n = NODEID_TO_NODE(packet->node_id);
++
++ /* Broadcast transactions are complete once the request has been sent.
++ * Use the same transaction label for all broadcast transactions. */
++ if (unlikely(n == ALL_NODES)) {
++ packet->tlabel = 0;
++ return 0;
++ }
++ tp = packet->host->tl_pool[n].map;
++ next = &packet->host->next_tl[n];
++
++ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
++ tlabel = find_next_zero_bit(tp, 64, *next);
++ if (tlabel > 63)
++ tlabel = find_first_zero_bit(tp, 64);
++ if (tlabel > 63) {
++ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
++ return -EAGAIN;
++ }
++ __set_bit(tlabel, tp);
++ *next = (tlabel + 1) & 63;
++ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
++
++ packet->tlabel = tlabel;
++ return 0;
++}
++
+ /**
+ * hpsb_get_tlabel - allocate a transaction label
+- * @packet: the packet who's tlabel/tpool we set
++ * @packet: the packet whose tlabel and tl_pool we set
+ *
+ * Every asynchronous transaction on the 1394 bus needs a transaction
+ * label to match the response to the request. This label has to be
+@@ -130,42 +167,25 @@ static void fill_async_stream_packet(str
+ * Return value: Zero on success, otherwise non-zero. A non-zero return
+ * generally means there are no available tlabels. If this is called out
+ * of interrupt or atomic context, then it will sleep until can return a
+- * tlabel.
++ * tlabel or a signal is received.
+ */
+ int hpsb_get_tlabel(struct hpsb_packet *packet)
+ {
+- unsigned long flags;
+- struct hpsb_tlabel_pool *tp;
+- int n = NODEID_TO_NODE(packet->node_id);
+-
+- if (unlikely(n == ALL_NODES))
+- return 0;
+- tp = &packet->host->tpool[n];
+-
+- if (irqs_disabled() || in_atomic()) {
+- if (down_trylock(&tp->count))
+- return 1;
+- } else {
+- down(&tp->count);
+- }
+-
+- spin_lock_irqsave(&tp->lock, flags);
+-
+- packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
+- if (packet->tlabel > 63)
+- packet->tlabel = find_first_zero_bit(tp->pool, 64);
+- tp->next = (packet->tlabel + 1) % 64;
+- /* Should _never_ happen */
+- BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
+- tp->allocations++;
+- spin_unlock_irqrestore(&tp->lock, flags);
+-
+- return 0;
++ if (irqs_disabled() || in_atomic())
++ return hpsb_get_tlabel_atomic(packet);
++
++ /* NB: The macro wait_event_interruptible() is called with a condition
++ * argument with side effect. This is only possible because the side
++ * effect does not occur until the condition became true, and
++ * wait_event_interruptible() won't evaluate the condition again after
++ * that. */
++ return wait_event_interruptible(tlabel_wq,
++ !hpsb_get_tlabel_atomic(packet));
+ }
+
+ /**
+ * hpsb_free_tlabel - free an allocated transaction label
+- * @packet: packet whos tlabel/tpool needs to be cleared
++ * @packet: packet whose tlabel and tl_pool needs to be cleared
+ *
+ * Frees the transaction label allocated with hpsb_get_tlabel(). The
+ * tlabel has to be freed after the transaction is complete (i.e. response
+@@ -176,21 +196,20 @@ int hpsb_get_tlabel(struct hpsb_packet *
+ */
+ void hpsb_free_tlabel(struct hpsb_packet *packet)
+ {
+- unsigned long flags;
+- struct hpsb_tlabel_pool *tp;
+- int n = NODEID_TO_NODE(packet->node_id);
++ unsigned long flags, *tp;
++ int tlabel, n = NODEID_TO_NODE(packet->node_id);
+
+ if (unlikely(n == ALL_NODES))
+ return;
+- tp = &packet->host->tpool[n];
++ tp = packet->host->tl_pool[n].map;
++ tlabel = packet->tlabel;
++ BUG_ON(tlabel > 63 || tlabel < 0);
+
+- BUG_ON(packet->tlabel > 63 || packet->tlabel < 0);
++ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
++ BUG_ON(!__test_and_clear_bit(tlabel, tp));
++ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+
+- spin_lock_irqsave(&tp->lock, flags);
+- BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool));
+- spin_unlock_irqrestore(&tp->lock, flags);
+-
+- up(&tp->count);
++ wake_up_interruptible(&tlabel_wq);
+ }
+
+ int hpsb_packet_success(struct hpsb_packet *packet)
+@@ -214,7 +233,7 @@ int hpsb_packet_success(struct hpsb_pack
+ packet->node_id);
+ return -EAGAIN;
+ }
+- HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__);
++ BUG();
+
+ case ACK_BUSY_X:
+ case ACK_BUSY_A:
+@@ -261,8 +280,7 @@ int hpsb_packet_success(struct hpsb_pack
+ packet->ack_code, packet->node_id, packet->tcode);
+ return -EAGAIN;
+ }
+-
+- HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
++ BUG();
+ }
+
+ struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
+diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
+index 45ba784..c1369c4 100644
+--- a/drivers/ieee1394/ieee1394_transactions.h
++++ b/drivers/ieee1394/ieee1394_transactions.h
+@@ -1,32 +1,32 @@
+ #ifndef _IEEE1394_TRANSACTIONS_H
+ #define _IEEE1394_TRANSACTIONS_H
+
+-#include "ieee1394_core.h"
++#include <linux/types.h>
+
++#include "ieee1394_types.h"
++
++struct hpsb_packet;
++struct hpsb_host;
+
+-/*
+- * Get and free transaction labels.
+- */
+ int hpsb_get_tlabel(struct hpsb_packet *packet);
+ void hpsb_free_tlabel(struct hpsb_packet *packet);
+-
+ struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr, size_t length);
+ struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
+- u64 addr, int extcode, quadlet_t *data,
++ u64 addr, int extcode, quadlet_t *data,
+ quadlet_t arg);
+-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+- u64 addr, int extcode, octlet_t *data,
+- octlet_t arg);
+-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
+- quadlet_t data) ;
+-struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
+- int length, int channel,
+- int tag, int sync);
+-struct hpsb_packet *hpsb_make_writepacket (struct hpsb_host *host, nodeid_t node,
+- u64 addr, quadlet_t *buffer, size_t length);
++struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
++ nodeid_t node, u64 addr, int extcode,
++ octlet_t *data, octlet_t arg);
++struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
++struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, int length,
++ int channel, int tag, int sync);
++struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
++ nodeid_t node, u64 addr,
++ quadlet_t *buffer, size_t length);
+ struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
+- int length, int channel, int tag, int sync);
++ int length, int channel, int tag,
++ int sync);
+
+ /*
+ * hpsb_packet_success - Make sense of the ack and reply codes and
+@@ -40,9 +40,8 @@ struct hpsb_packet *hpsb_make_streampack
+ */
+ int hpsb_packet_success(struct hpsb_packet *packet);
+
+-
+ /*
+- * The generic read, write and lock functions. All recognize the local node ID
++ * The generic read and write functions. All recognize the local node ID
+ * and act accordingly. Read and write automatically use quadlet commands if
+ * length == 4 and and block commands otherwise (however, they do not yet
+ * support lengths that are not a multiple of 4). You must explicitly specifiy
+@@ -54,4 +53,8 @@ int hpsb_read(struct hpsb_host *host, no
+ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+ u64 addr, quadlet_t *buffer, size_t length);
+
++#ifdef HPSB_DEBUG_TLABELS
++extern spinlock_t hpsb_tlabel_lock;
++#endif
++
+ #endif /* _IEEE1394_TRANSACTIONS_H */
+diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
+index 3165609..9803aaa 100644
+--- a/drivers/ieee1394/ieee1394_types.h
++++ b/drivers/ieee1394/ieee1394_types.h
+@@ -1,37 +1,11 @@
+-
+ #ifndef _IEEE1394_TYPES_H
+ #define _IEEE1394_TYPES_H
+
+ #include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/list.h>
+-#include <linux/init.h>
+-#include <linux/spinlock.h>
+ #include <linux/string.h>
+-
+-#include <asm/semaphore.h>
++#include <linux/types.h>
+ #include <asm/byteorder.h>
+
+-
+-/* Transaction Label handling */
+-struct hpsb_tlabel_pool {
+- DECLARE_BITMAP(pool, 64);
+- spinlock_t lock;
+- u8 next;
+- u32 allocations;
+- struct semaphore count;
+-};
+-
+-#define HPSB_TPOOL_INIT(_tp) \
+-do { \
+- bitmap_zero((_tp)->pool, 64); \
+- spin_lock_init(&(_tp)->lock); \
+- (_tp)->next = 0; \
+- (_tp)->allocations = 0; \
+- sema_init(&(_tp)->count, 63); \
+-} while (0)
+-
+-
+ typedef u32 quadlet_t;
+ typedef u64 octlet_t;
+ typedef u16 nodeid_t;
+@@ -54,46 +28,40 @@ typedef u16 arm_length_t;
+ #define NODE_BUS_ARGS(__host, __nodeid) \
+ __host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
+
+-#define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args)
++#define HPSB_PRINT(level, fmt, args...) \
++ printk(level "ieee1394: " fmt "\n" , ## args)
+
+-#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
+-#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
+-#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
+-#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
+-#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
++#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
++#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
++#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
++#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
++#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
+
+ #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+-#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
++#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
++#define HPSB_DEBUG_TLABELS
+ #else
+-#define HPSB_VERBOSE(fmt, args...)
++#define HPSB_VERBOSE(fmt, args...) do {} while (0)
+ #endif
+
+-#define HPSB_PANIC(fmt, args...) panic("ieee1394: " fmt "\n" , ## args)
+-
+-#define HPSB_TRACE() HPSB_PRINT(KERN_INFO, "TRACE - %s, %s(), line %d", __FILE__, __FUNCTION__, __LINE__)
+-
+-
+ #ifdef __BIG_ENDIAN
+
+-static __inline__ void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
++static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
+ {
+- void *tmp = dest;
++ void *tmp = dest;
+ u32 *src = (u32 *)__src;
+
+- count /= 4;
+-
+- while (count--) {
+- *dest++ = swab32p(src++);
+- }
+-
+- return tmp;
++ count /= 4;
++ while (count--)
++ *dest++ = swab32p(src++);
++ return tmp;
+ }
+
+ #else
+
+ static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
+ {
+- return memcpy(dest, src, count);
++ return memcpy(dest, src, count);
+ }
+
+ #endif /* __BIG_ENDIAN */
+diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
+index f26680e..08bd15d 100644
+--- a/drivers/ieee1394/iso.c
++++ b/drivers/ieee1394/iso.c
+@@ -9,8 +9,11 @@
+ * directory of the kernel sources for details.
+ */
+
+-#include <linux/slab.h>
++#include <linux/pci.h>
+ #include <linux/sched.h>
++#include <linux/slab.h>
++
++#include "hosts.h"
+ #include "iso.h"
+
+ void hpsb_iso_stop(struct hpsb_iso *iso)
+diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
+index 3efc60b..1210a97 100644
+--- a/drivers/ieee1394/iso.h
++++ b/drivers/ieee1394/iso.h
+@@ -12,33 +12,40 @@
+ #ifndef IEEE1394_ISO_H
+ #define IEEE1394_ISO_H
+
+-#include "hosts.h"
++#include <linux/spinlock_types.h>
++#include <asm/atomic.h>
++#include <asm/types.h>
++
+ #include "dma.h"
+
+-/* high-level ISO interface */
++struct hpsb_host;
+
+-/* This API sends and receives isochronous packets on a large,
+- virtually-contiguous kernel memory buffer. The buffer may be mapped
+- into a user-space process for zero-copy transmission and reception.
++/* high-level ISO interface */
+
+- There are no explicit boundaries between packets in the buffer. A
+- packet may be transmitted or received at any location. However,
+- low-level drivers may impose certain restrictions on alignment or
+- size of packets. (e.g. in OHCI no packet may cross a page boundary,
+- and packets should be quadlet-aligned)
+-*/
++/*
++ * This API sends and receives isochronous packets on a large,
++ * virtually-contiguous kernel memory buffer. The buffer may be mapped
++ * into a user-space process for zero-copy transmission and reception.
++ *
++ * There are no explicit boundaries between packets in the buffer. A
++ * packet may be transmitted or received at any location. However,
++ * low-level drivers may impose certain restrictions on alignment or
++ * size of packets. (e.g. in OHCI no packet may cross a page boundary,
++ * and packets should be quadlet-aligned)
++ */
+
+ /* Packet descriptor - the API maintains a ring buffer of these packet
+- descriptors in kernel memory (hpsb_iso.infos[]). */
+-
++ * descriptors in kernel memory (hpsb_iso.infos[]). */
+ struct hpsb_iso_packet_info {
+ /* offset of data payload relative to the first byte of the buffer */
+ __u32 offset;
+
+- /* length of the data payload, in bytes (not including the isochronous header) */
++ /* length of the data payload, in bytes (not including the isochronous
++ * header) */
+ __u16 len;
+
+- /* (recv only) the cycle number (mod 8000) on which the packet was received */
++ /* (recv only) the cycle number (mod 8000) on which the packet was
++ * received */
+ __u16 cycle;
+
+ /* (recv only) channel on which the packet was received */
+@@ -48,12 +55,10 @@ struct hpsb_iso_packet_info {
+ __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.
+- */
++ /* 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;
+ };
+
+@@ -75,8 +80,8 @@ struct hpsb_iso {
+ void *hostdata;
+
+ /* a function to be called (from interrupt context) after
+- outgoing packets have been sent, or incoming packets have
+- arrived */
++ * outgoing packets have been sent, or incoming packets have
++ * arrived */
+ void (*callback)(struct hpsb_iso*);
+
+ /* wait for buffer space */
+@@ -88,7 +93,7 @@ struct hpsb_iso {
+
+
+ /* greatest # of packets between interrupts - controls
+- the maximum latency of the buffer */
++ * the maximum latency of the buffer */
+ int irq_interval;
+
+ /* the buffer for packet data payloads */
+@@ -112,8 +117,8 @@ struct hpsb_iso {
+ int pkt_dma;
+
+ /* how many packets, starting at first_packet:
+- (transmit) are ready to be filled with data
+- (receive) contain received data */
++ * (transmit) are ready to be filled with data
++ * (receive) contain received data */
+ int n_ready_packets;
+
+ /* how many times the buffer has overflowed or underflowed */
+@@ -134,7 +139,7 @@ struct hpsb_iso {
+ int start_cycle;
+
+ /* cycle at which next packet will be transmitted,
+- -1 if not known */
++ * -1 if not known */
+ int xmit_cycle;
+
+ /* ringbuffer of packet descriptors in regular kernel memory
+@@ -170,25 +175,30 @@ int hpsb_iso_recv_unlisten_channel(struc
+ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
+
+ /* start/stop DMA */
+-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer);
+-int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync);
++int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
++ int prebuffer);
++int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
++ int tag_mask, int sync);
+ void hpsb_iso_stop(struct hpsb_iso *iso);
+
+ /* deallocate buffer and DMA context */
+ void hpsb_iso_shutdown(struct hpsb_iso *iso);
+
+-/* queue a packet for transmission. 'offset' is relative to the beginning of the
+- DMA buffer, where the packet's data payload should already have been placed */
+-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy);
++/* queue a packet for transmission.
++ * 'offset' is relative to the beginning of the DMA buffer, where the packet's
++ * data payload should already have been placed. */
++int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
++ u8 tag, u8 sy);
+
+ /* wait until all queued packets have been transmitted to the bus */
+ int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
+
+ /* N packets have been read out of the buffer, re-use the buffer space */
+-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets);
++int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
++ unsigned int n_packets);
+
+ /* check for arrival of new packets immediately (even if irq_interval
+- has not yet been reached) */
++ * has not yet been reached) */
+ int hpsb_iso_recv_flush(struct hpsb_iso *iso);
+
+ /* returns # of packets ready to send or receive */
+@@ -197,14 +207,15 @@ int hpsb_iso_n_ready(struct hpsb_iso *is
+ /* the following are callbacks available to low-level drivers */
+
+ /* call after a packet has been transmitted to the bus (interrupt context is OK)
+- 'cycle' is the _exact_ cycle the packet was sent on
+- 'error' should be non-zero if some sort of error occurred when sending the packet
+-*/
++ * 'cycle' is the _exact_ cycle the packet was sent on
++ * 'error' should be non-zero if some sort of error occurred when sending the
++ * packet */
+ 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 total_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 d541b50..8e7b83f 100644
+--- a/drivers/ieee1394/nodemgr.c
++++ b/drivers/ieee1394/nodemgr.c
+@@ -12,26 +12,23 @@
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/slab.h>
+-#include <linux/smp_lock.h>
+-#include <linux/interrupt.h>
+-#include <linux/kmod.h>
+-#include <linux/completion.h>
+ #include <linux/delay.h>
+-#include <linux/pci.h>
++#include <linux/kthread.h>
+ #include <linux/moduleparam.h>
+ #include <asm/atomic.h>
+
+-#include "ieee1394_types.h"
++#include "csr.h"
++#include "highlevel.h"
++#include "hosts.h"
+ #include "ieee1394.h"
+ #include "ieee1394_core.h"
+-#include "hosts.h"
++#include "ieee1394_hotplug.h"
++#include "ieee1394_types.h"
+ #include "ieee1394_transactions.h"
+-#include "highlevel.h"
+-#include "csr.h"
+ #include "nodemgr.h"
+
+ static int ignore_drivers;
+-module_param(ignore_drivers, int, 0444);
++module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);
+ MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
+
+ struct nodemgr_csr_info {
+@@ -71,7 +68,7 @@ static int nodemgr_check_speed(struct no
+ u8 i, *speed, old_speed, good_speed;
+ int ret;
+
+- speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid);
++ speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
+ old_speed = *speed;
+ good_speed = IEEE1394_SPEED_MAX + 1;
+
+@@ -161,16 +158,12 @@ static struct csr1212_bus_ops nodemgr_cs
+ * but now we are much simpler because of the LDM.
+ */
+
+-static DECLARE_MUTEX(nodemgr_serialize);
++static DEFINE_MUTEX(nodemgr_serialize);
+
+ struct host_info {
+ struct hpsb_host *host;
+ struct list_head list;
+- struct completion exited;
+- struct semaphore reset_sem;
+- int pid;
+- char daemon_name[15];
+- int kill_me;
++ struct task_struct *thread;
+ };
+
+ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
+@@ -334,34 +327,44 @@ static ssize_t fw_show_ne_bus_options(st
+ static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
+
+
+-/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
+- * here, therefore displayed values may be occasionally wrong. */
+-static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
++#ifdef HPSB_DEBUG_TLABELS
++static ssize_t fw_show_ne_tlabels_free(struct device *dev,
++ struct device_attribute *attr, char *buf)
+ {
+ struct node_entry *ne = container_of(dev, struct node_entry, device);
+- return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
+-}
+-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
++ unsigned long flags;
++ unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
++ int tf;
+
++ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
++ tf = 64 - bitmap_weight(tp, 64);
++ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+
+-static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf)
+-{
+- struct node_entry *ne = container_of(dev, struct node_entry, device);
+- return sprintf(buf, "%u\n", ne->tpool->allocations);
++ return sprintf(buf, "%d\n", tf);
+ }
+-static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL);
++static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
+
+
+-static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf)
++static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
++ struct device_attribute *attr, char *buf)
+ {
+ struct node_entry *ne = container_of(dev, struct node_entry, device);
++ unsigned long flags;
++ unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
++ u64 tm;
++
++ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+ #if (BITS_PER_LONG <= 32)
+- return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]);
++ tm = ((u64)tp[0] << 32) + tp[1];
+ #else
+- return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]);
++ tm = tp[0];
+ #endif
++ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
++
++ return sprintf(buf, "0x%016llx\n", tm);
+ }
+ static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
++#endif /* HPSB_DEBUG_TLABELS */
+
+
+ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+@@ -408,26 +411,11 @@ static ssize_t fw_get_destroy_node(struc
+ }
+ static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node);
+
+-static int nodemgr_rescan_bus_thread(void *__unused)
+-{
+- /* No userlevel access needed */
+- daemonize("kfwrescan");
+-
+- bus_rescan_devices(&ieee1394_bus_type);
+-
+- return 0;
+-}
+
+ static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count)
+ {
+- int state = simple_strtoul(buf, NULL, 10);
+-
+- /* Don't wait for this, or care about errors. Root could do
+- * something stupid and spawn this a lot of times, but that's
+- * root's fault. */
+- if (state == 1)
+- kernel_thread(nodemgr_rescan_bus_thread, NULL, CLONE_KERNEL);
+-
++ if (simple_strtoul(buf, NULL, 10) == 1)
++ bus_rescan_devices(&ieee1394_bus_type);
+ return count;
+ }
+ static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
+@@ -483,9 +471,10 @@ static struct device_attribute *const fw
+ &dev_attr_ne_vendor_id,
+ &dev_attr_ne_nodeid,
+ &dev_attr_bus_options,
++#ifdef HPSB_DEBUG_TLABELS
+ &dev_attr_tlabels_free,
+- &dev_attr_tlabels_allocations,
+ &dev_attr_tlabels_mask,
++#endif
+ };
+
+
+@@ -804,8 +793,6 @@ static struct node_entry *nodemgr_create
+ if (!ne)
+ return NULL;
+
+- ne->tpool = &host->tpool[nodeid & NODE_MASK];
+-
+ ne->host = host;
+ ne->nodeid = nodeid;
+ ne->generation = generation;
+@@ -1251,6 +1238,7 @@ static void nodemgr_node_scan_one(struct
+ octlet_t guid;
+ struct csr1212_csr *csr;
+ struct nodemgr_csr_info *ci;
++ u8 *speed;
+
+ ci = kmalloc(sizeof(*ci), GFP_KERNEL);
+ if (!ci)
+@@ -1259,8 +1247,12 @@ static void nodemgr_node_scan_one(struct
+ ci->host = host;
+ ci->nodeid = nodeid;
+ ci->generation = generation;
+- ci->speed_unverified =
+- host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100;
++
++ /* Prepare for speed probe which occurs when reading the ROM */
++ speed = &(host->speed[NODEID_TO_NODE(nodeid)]);
++ if (*speed > host->csr.lnk_spd)
++ *speed = host->csr.lnk_spd;
++ ci->speed_unverified = *speed > IEEE1394_SPEED_100;
+
+ /* We need to detect when the ConfigROM's generation has changed,
+ * so we only update the node's info when it needs to be. */
+@@ -1300,8 +1292,6 @@ static void nodemgr_node_scan_one(struct
+ nodemgr_create_node(guid, csr, hi, nodeid, generation);
+ else
+ nodemgr_update_node(ne, csr, hi, nodeid, generation);
+-
+- return;
+ }
+
+
+@@ -1326,6 +1316,7 @@ static void nodemgr_node_scan(struct hos
+ }
+
+
++/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */
+ static void nodemgr_suspend_ne(struct node_entry *ne)
+ {
+ struct class_device *cdev;
+@@ -1361,6 +1352,7 @@ static void nodemgr_resume_ne(struct nod
+ ne->in_limbo = 0;
+ device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
+
++ down_read(&nodemgr_ud_class.subsys.rwsem);
+ down_read(&ne->device.bus->subsys.rwsem);
+ list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
+ ud = container_of(cdev, struct unit_directory, class_dev);
+@@ -1372,21 +1364,21 @@ static void nodemgr_resume_ne(struct nod
+ ud->device.driver->resume(&ud->device);
+ }
+ up_read(&ne->device.bus->subsys.rwsem);
++ up_read(&nodemgr_ud_class.subsys.rwsem);
+
+ HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
+ NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+ }
+
+
++/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */
+ static void nodemgr_update_pdrv(struct node_entry *ne)
+ {
+ struct unit_directory *ud;
+ struct hpsb_protocol_driver *pdrv;
+- struct class *class = &nodemgr_ud_class;
+ struct class_device *cdev;
+
+- down_read(&class->subsys.rwsem);
+- list_for_each_entry(cdev, &class->children, node) {
++ list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
+ ud = container_of(cdev, struct unit_directory, class_dev);
+ if (ud->ne != ne || !ud->device.driver)
+ continue;
+@@ -1399,7 +1391,6 @@ static void nodemgr_update_pdrv(struct n
+ up_write(&ud->device.bus->subsys.rwsem);
+ }
+ }
+- up_read(&class->subsys.rwsem);
+ }
+
+
+@@ -1430,6 +1421,8 @@ static void nodemgr_irm_write_bc(struct
+ }
+
+
++/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader because the
++ * calls to nodemgr_update_pdrv() and nodemgr_suspend_ne() here require it. */
+ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation)
+ {
+ struct device *dev;
+@@ -1492,9 +1485,8 @@ static void nodemgr_node_probe(struct ho
+ /* If we had a bus reset while we were scanning the bus, it is
+ * possible that we did not probe all nodes. In that case, we
+ * skip the clean up for now, since we could remove nodes that
+- * were still on the bus. The bus reset increased hi->reset_sem,
+- * so there's a bus scan pending which will do the clean up
+- * eventually.
++ * were still on the bus. Another bus scan is pending which will
++ * do the clean up eventually.
+ *
+ * Now let's tell the bus to rescan our devices. This may seem
+ * like overhead, but the driver-model core will only scan a
+@@ -1622,41 +1614,37 @@ static int nodemgr_host_thread(void *__h
+ {
+ struct host_info *hi = (struct host_info *)__hi;
+ struct hpsb_host *host = hi->host;
+- int reset_cycles = 0;
+-
+- /* No userlevel access needed */
+- daemonize(hi->daemon_name);
++ unsigned int g, generation = 0;
++ int i, reset_cycles = 0;
+
+ /* Setup our device-model entries */
+ nodemgr_create_host_dev_files(host);
+
+- /* Sit and wait for a signal to probe the nodes on the bus. This
+- * happens when we get a bus reset. */
+- while (1) {
+- unsigned int generation = 0;
+- int i;
++ for (;;) {
++ /* Sleep until next bus reset */
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (get_hpsb_generation(host) == generation)
++ schedule();
++ __set_current_state(TASK_RUNNING);
++
++ /* Thread may have been woken up to freeze or to exit */
++ if (try_to_freeze())
++ continue;
++ if (kthread_should_stop())
++ goto exit;
+
+- if (down_interruptible(&hi->reset_sem) ||
+- down_interruptible(&nodemgr_serialize)) {
++ if (mutex_lock_interruptible(&nodemgr_serialize)) {
+ if (try_to_freeze())
+ continue;
+- printk("NodeMgr: received unexpected signal?!\n" );
+- break;
+- }
+-
+- if (hi->kill_me) {
+- up(&nodemgr_serialize);
+- break;
++ goto exit;
+ }
+
+ /* Pause for 1/4 second in 1/16 second intervals,
+ * to make sure things settle down. */
++ g = get_hpsb_generation(host);
+ for (i = 0; i < 4 ; i++) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (msleep_interruptible(63)) {
+- up(&nodemgr_serialize);
+- goto caught_signal;
+- }
++ if (msleep_interruptible(63) || kthread_should_stop())
++ goto unlock_exit;
+
+ /* Now get the generation in which the node ID's we collect
+ * are valid. During the bus scan we will use this generation
+@@ -1667,20 +1655,14 @@ static int nodemgr_host_thread(void *__h
+
+ /* If we get a reset before we are done waiting, then
+ * start the the waiting over again */
+- while (!down_trylock(&hi->reset_sem))
+- i = 0;
+-
+- /* Check the kill_me again */
+- if (hi->kill_me) {
+- up(&nodemgr_serialize);
+- goto caught_signal;
+- }
++ if (generation != g)
++ g = generation, i = 0;
+ }
+
+ if (!nodemgr_check_irm_capability(host, reset_cycles) ||
+ !nodemgr_do_irm_duties(host, reset_cycles)) {
+ reset_cycles++;
+- up(&nodemgr_serialize);
++ mutex_unlock(&nodemgr_serialize);
+ continue;
+ }
+ reset_cycles = 0;
+@@ -1698,13 +1680,13 @@ static int nodemgr_host_thread(void *__h
+ /* Update some of our sysfs symlinks */
+ nodemgr_update_host_dev_links(host);
+
+- up(&nodemgr_serialize);
++ mutex_unlock(&nodemgr_serialize);
+ }
+-
+-caught_signal:
++unlock_exit:
++ mutex_unlock(&nodemgr_serialize);
++exit:
+ HPSB_VERBOSE("NodeMgr: Exiting thread");
+-
+- complete_and_exit(&hi->exited, 0);
++ return 0;
+ }
+
+ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
+@@ -1764,41 +1746,27 @@ static void nodemgr_add_host(struct hpsb
+ struct host_info *hi;
+
+ hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));
+-
+ if (!hi) {
+- HPSB_ERR ("NodeMgr: out of memory in add host");
++ HPSB_ERR("NodeMgr: out of memory in add host");
+ return;
+ }
+-
+ hi->host = host;
+- init_completion(&hi->exited);
+- sema_init(&hi->reset_sem, 0);
+-
+- sprintf(hi->daemon_name, "knodemgrd_%d", host->id);
+-
+- hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_KERNEL);
+-
+- if (hi->pid < 0) {
+- HPSB_ERR ("NodeMgr: failed to start %s thread for %s",
+- hi->daemon_name, host->driver->name);
++ hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d",
++ host->id);
++ if (IS_ERR(hi->thread)) {
++ HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
+ hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
+- return;
+ }
+-
+- return;
+ }
+
+ static void nodemgr_host_reset(struct hpsb_host *host)
+ {
+ struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
+
+- if (hi != NULL) {
+- HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name);
+- up(&hi->reset_sem);
+- } else
+- HPSB_ERR ("NodeMgr: could not process reset of unused host");
+-
+- return;
++ if (hi) {
++ HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
++ wake_up_process(hi->thread);
++ }
+ }
+
+ static void nodemgr_remove_host(struct hpsb_host *host)
+@@ -1806,18 +1774,9 @@ static void nodemgr_remove_host(struct h
+ struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
+
+ if (hi) {
+- if (hi->pid >= 0) {
+- hi->kill_me = 1;
+- mb();
+- up(&hi->reset_sem);
+- wait_for_completion(&hi->exited);
+- nodemgr_remove_host_dev(&host->device);
+- }
+- } else
+- HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",
+- host->driver->name);
+-
+- return;
++ kthread_stop(hi->thread);
++ nodemgr_remove_host_dev(&host->device);
++ }
+ }
+
+ static struct hpsb_highlevel nodemgr_highlevel = {
+diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
+index 0b26616..0e1e7d9 100644
+--- a/drivers/ieee1394/nodemgr.h
++++ b/drivers/ieee1394/nodemgr.h
+@@ -21,9 +21,15 @@
+ #define _IEEE1394_NODEMGR_H
+
+ #include <linux/device.h>
+-#include "csr1212.h"
++#include <asm/types.h>
++
+ #include "ieee1394_core.h"
+-#include "ieee1394_hotplug.h"
++#include "ieee1394_types.h"
++
++struct csr1212_csr;
++struct csr1212_keyval;
++struct hpsb_host;
++struct ieee1394_device_id;
+
+ /* '1' '3' '9' '4' in ASCII */
+ #define IEEE1394_BUSID_MAGIC __constant_cpu_to_be32(0x31333934)
+@@ -44,7 +50,6 @@ struct bus_options {
+ u16 max_rec; /* Maximum packet size node can receive */
+ };
+
+-
+ #define UNIT_DIRECTORY_VENDOR_ID 0x01
+ #define UNIT_DIRECTORY_MODEL_ID 0x02
+ #define UNIT_DIRECTORY_SPECIFIER_ID 0x04
+@@ -59,8 +64,8 @@ struct bus_options {
+ * unit directory for each of these protocols.
+ */
+ struct unit_directory {
+- struct node_entry *ne; /* The node which this directory belongs to */
+- octlet_t address; /* Address of the unit directory on the node */
++ struct node_entry *ne; /* The node which this directory belongs to */
++ octlet_t address; /* Address of the unit directory on the node */
+ u8 flags; /* Indicates which entries were read */
+
+ quadlet_t vendor_id;
+@@ -79,11 +84,10 @@ struct unit_directory {
+ int length; /* Number of quadlets */
+
+ struct device device;
+-
+ struct class_device class_dev;
+
+ struct csr1212_keyval *ud_kv;
+- u32 lun; /* logical unit number immediate value */
++ u32 lun; /* logical unit number immediate value */
+ };
+
+ struct node_entry {
+@@ -103,10 +107,8 @@ struct node_entry {
+ const char *vendor_oui;
+
+ u32 capabilities;
+- struct hpsb_tlabel_pool *tpool;
+
+ struct device device;
+-
+ struct class_device class_dev;
+
+ /* Means this node is not attached anymore */
+@@ -153,8 +155,8 @@ static inline int hpsb_node_entry_valid(
+ /*
+ * This will fill in the given, pre-initialised hpsb_packet with the current
+ * information from the node entry (host, node ID, generation number). It will
+- * return false if the node owning the GUID is not accessible (and not modify the
+- * hpsb_packet) and return true otherwise.
++ * return false if the node owning the GUID is not accessible (and not modify
++ * the hpsb_packet) and return true otherwise.
+ *
+ * Note that packet sending may still fail in hpsb_send_packet if a bus reset
+ * happens while you are trying to set up the packet (due to obsolete generation
+@@ -170,16 +172,13 @@ int hpsb_node_write(struct node_entry *n
+ int hpsb_node_lock(struct node_entry *ne, u64 addr,
+ int extcode, quadlet_t *data, quadlet_t arg);
+
+-
+ /* Iterate the hosts, calling a given function with supplied data for each
+ * host. */
+ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *));
+
+-
+ int init_ieee1394_nodemgr(void);
+ void cleanup_ieee1394_nodemgr(void);
+
+-
+ /* The template for a host device */
+ extern struct device nodemgr_dev_template_host;
+
+diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
+index 448df27..6e8ea91 100644
+--- a/drivers/ieee1394/ohci1394.c
++++ b/drivers/ieee1394/ohci1394.c
+@@ -136,7 +136,7 @@
+ #define DBGMSG(fmt, args...) \
+ printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
+ #else
+-#define DBGMSG(fmt, args...)
++#define DBGMSG(fmt, args...) do {} while (0)
+ #endif
+
+ #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
+@@ -148,8 +148,8 @@ printk(KERN_INFO "%s: fw-host%d: " fmt "
+ --global_outstanding_dmas, ## args)
+ static int global_outstanding_dmas = 0;
+ #else
+-#define OHCI_DMA_ALLOC(fmt, args...)
+-#define OHCI_DMA_FREE(fmt, args...)
++#define OHCI_DMA_ALLOC(fmt, args...) do {} while (0)
++#define OHCI_DMA_FREE(fmt, args...) do {} while (0)
+ #endif
+
+ /* print general (card independent) information */
+@@ -181,36 +181,35 @@ static int alloc_dma_trm_ctx(struct ti_o
+ static void ohci1394_pci_remove(struct pci_dev *pdev);
+
+ #ifndef __LITTLE_ENDIAN
+-static unsigned hdr_sizes[] =
+-{
++const static size_t hdr_sizes[] = {
+ 3, /* TCODE_WRITEQ */
+ 4, /* TCODE_WRITEB */
+ 3, /* TCODE_WRITE_RESPONSE */
+- 0, /* ??? */
++ 0, /* reserved */
+ 3, /* TCODE_READQ */
+ 4, /* TCODE_READB */
+ 3, /* TCODE_READQ_RESPONSE */
+ 4, /* TCODE_READB_RESPONSE */
+- 1, /* TCODE_CYCLE_START (???) */
++ 1, /* TCODE_CYCLE_START */
+ 4, /* TCODE_LOCK_REQUEST */
+ 2, /* TCODE_ISO_DATA */
+ 4, /* TCODE_LOCK_RESPONSE */
++ /* rest is reserved or link-internal */
+ };
+
+-/* Swap headers */
+-static inline void packet_swab(quadlet_t *data, int tcode)
++static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode)
+ {
+- size_t size = hdr_sizes[tcode];
++ size_t size;
+
+- if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0)
++ if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes)))
+ return;
+
++ size = hdr_sizes[tcode];
+ while (size--)
+- data[size] = swab32(data[size]);
++ data[size] = le32_to_cpu(data[size]);
+ }
+ #else
+-/* Don't waste cycles on same sex byte swaps */
+-#define packet_swab(w,x)
++#define header_le32_to_cpu(w,x) do {} while (0)
+ #endif /* !LITTLE_ENDIAN */
+
+ /***********************************
+@@ -701,7 +700,7 @@ static void insert_packet(struct ti_ohci
+ d->prg_cpu[idx]->data[2] = packet->header[2];
+ d->prg_cpu[idx]->data[3] = packet->header[3];
+ }
+- packet_swab(d->prg_cpu[idx]->data, packet->tcode);
++ header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
+ }
+
+ if (packet->data_size) { /* block transmit */
+@@ -777,7 +776,7 @@ static void insert_packet(struct ti_ohci
+ d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
+ (packet->header[0] & 0xFFFF);
+ d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
+- packet_swab(d->prg_cpu[idx]->data, packet->tcode);
++ header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
+
+ d->prg_cpu[idx]->begin.control =
+ cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+@@ -2302,8 +2301,7 @@ static void ohci_schedule_iso_tasklets(s
+ spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
+ }
+
+-static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
+- struct pt_regs *regs_are_unused)
++static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
+ {
+ quadlet_t event, node_id;
+ struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
+@@ -2598,8 +2596,9 @@ static const int TCODE_SIZE[16] = {20, 0
+ * Determine the length of a packet in the buffer
+ * Optimization suggested by Pascal Drolet <pascal.drolet at informission.ca>
+ */
+-static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
+- int offset, unsigned char tcode, int noswap)
++static inline int packet_length(struct dma_rcv_ctx *d, int idx,
++ quadlet_t *buf_ptr, int offset,
++ unsigned char tcode, int noswap)
+ {
+ int length = -1;
+
+@@ -2730,7 +2729,7 @@ static void dma_rcv_tasklet (unsigned lo
+ * bus reset. We always ignore it. */
+ if (tcode != OHCI1394_TCODE_PHY) {
+ if (!ohci->no_swap_incoming)
+- packet_swab(d->spb, tcode);
++ header_le32_to_cpu(d->spb, tcode);
+ DBGMSG("Packet received from node"
+ " %d ack=0x%02X spd=%d tcode=0x%X"
+ " length=%d ctx=%d tlabel=%d",
+@@ -2738,7 +2737,7 @@ static void dma_rcv_tasklet (unsigned lo
+ (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
+ (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
+ tcode, length, d->ctx,
+- (cond_le32_to_cpu(d->spb[0], ohci->no_swap_incoming)>>10)&0x3f);
++ (d->spb[0]>>10)&0x3f);
+
+ ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
+ == 0x11) ? 1 : 0;
+@@ -3529,9 +3528,10 @@ static void ohci1394_pci_remove(struct p
+ put_device(dev);
+ }
+
+-
++#ifdef CONFIG_PM
+ static int ohci1394_pci_resume (struct pci_dev *pdev)
+ {
++/* PowerMac resume code comes first */
+ #ifdef CONFIG_PPC_PMAC
+ if (machine_is(powermac)) {
+ struct device_node *of_node;
+@@ -3543,17 +3543,32 @@ static int ohci1394_pci_resume (struct p
+ }
+ #endif /* CONFIG_PPC_PMAC */
+
++ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+- pci_enable_device(pdev);
+-
+- return 0;
++ return pci_enable_device(pdev);
+ }
+
+-
+ static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+ {
+- pci_save_state(pdev);
++ int err;
++
++ printk(KERN_INFO "%s does not fully support suspend and resume yet\n",
++ OHCI1394_DRIVER_NAME);
+
++ err = pci_save_state(pdev);
++ if (err) {
++ printk(KERN_ERR "%s: pci_save_state failed with %d\n",
++ OHCI1394_DRIVER_NAME, err);
++ return err;
++ }
++ err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
++#ifdef OHCI1394_DEBUG
++ if (err)
++ printk(KERN_DEBUG "%s: pci_set_power_state failed with %d\n",
++ OHCI1394_DRIVER_NAME, err);
++#endif /* OHCI1394_DEBUG */
++
++/* PowerMac suspend code comes last */
+ #ifdef CONFIG_PPC_PMAC
+ if (machine_is(powermac)) {
+ struct device_node *of_node;
+@@ -3563,11 +3578,11 @@ static int ohci1394_pci_suspend (struct
+ if (of_node)
+ pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0);
+ }
+-#endif
++#endif /* CONFIG_PPC_PMAC */
+
+ return 0;
+ }
+-
++#endif /* CONFIG_PM */
+
+ #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
+
+@@ -3590,8 +3605,10 @@ static struct pci_driver ohci1394_pci_dr
+ .id_table = ohci1394_pci_tbl,
+ .probe = ohci1394_pci_probe,
+ .remove = ohci1394_pci_remove,
++#ifdef CONFIG_PM
+ .resume = ohci1394_pci_resume,
+ .suspend = ohci1394_pci_suspend,
++#endif
+ };
+
+ /***********************************
+@@ -3718,5 +3735,7 @@ static int __init ohci1394_init(void)
+ return pci_register_driver(&ohci1394_pci_driver);
+ }
+
+-module_init(ohci1394_init);
++/* Register before most other device drivers.
++ * Useful for remote debugging via physical DMA, e.g. using firescope. */
++fs_initcall(ohci1394_init);
+ module_exit(ohci1394_cleanup);
+diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
+index e6f4123..0a7412e 100644
+--- a/drivers/ieee1394/pcilynx.c
++++ b/drivers/ieee1394/pcilynx.c
+@@ -137,7 +137,6 @@ static struct i2c_algo_bit_data bit_data
+ .getsda = bit_getsda,
+ .getscl = bit_getscl,
+ .udelay = 5,
+- .mdelay = 5,
+ .timeout = 100,
+ };
+
+@@ -840,8 +839,7 @@ static int lynx_devctl(struct hpsb_host
+ ********************************************************/
+
+
+-static irqreturn_t lynx_irq_handler(int irq, void *dev_id,
+- struct pt_regs *regs_are_unused)
++static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
+ {
+ struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
+ struct hpsb_host *host = lynx->host;
+diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h
+index c93587b..c7731d1 100644
+--- a/drivers/ieee1394/raw1394-private.h
++++ b/drivers/ieee1394/raw1394-private.h
+@@ -29,9 +29,8 @@ struct file_info {
+
+ struct list_head req_pending;
+ struct list_head req_complete;
+- struct semaphore complete_sem;
+ spinlock_t reqlists_lock;
+- wait_queue_head_t poll_wait_complete;
++ wait_queue_head_t wait_complete;
+
+ struct list_head addr_list;
+
+diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
+index 571ea68..5ec4f5e 100644
+--- a/drivers/ieee1394/raw1394.c
++++ b/drivers/ieee1394/raw1394.c
+@@ -44,14 +44,15 @@
+ #include <linux/compat.h>
+
+ #include "csr1212.h"
++#include "highlevel.h"
++#include "hosts.h"
+ #include "ieee1394.h"
+-#include "ieee1394_types.h"
+ #include "ieee1394_core.h"
+-#include "nodemgr.h"
+-#include "hosts.h"
+-#include "highlevel.h"
+-#include "iso.h"
++#include "ieee1394_hotplug.h"
+ #include "ieee1394_transactions.h"
++#include "ieee1394_types.h"
++#include "iso.h"
++#include "nodemgr.h"
+ #include "raw1394.h"
+ #include "raw1394-private.h"
+
+@@ -66,7 +67,7 @@
+ #define DBGMSG(fmt, args...) \
+ printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
+ #else
+-#define DBGMSG(fmt, args...)
++#define DBGMSG(fmt, args...) do {} while (0)
+ #endif
+
+ static LIST_HEAD(host_info_list);
+@@ -132,10 +133,9 @@ static void free_pending_request(struct
+ static void __queue_complete_req(struct pending_request *req)
+ {
+ struct file_info *fi = req->file_info;
+- list_move_tail(&req->list, &fi->req_complete);
+
+- up(&fi->complete_sem);
+- wake_up_interruptible(&fi->poll_wait_complete);
++ list_move_tail(&req->list, &fi->req_complete);
++ wake_up(&fi->wait_complete);
+ }
+
+ static void queue_complete_req(struct pending_request *req)
+@@ -463,13 +463,36 @@ raw1394_compat_read(const char __user *b
+
+ #endif
+
++/* get next completed request (caller must hold fi->reqlists_lock) */
++static inline struct pending_request *__next_complete_req(struct file_info *fi)
++{
++ struct list_head *lh;
++ struct pending_request *req = NULL;
++
++ if (!list_empty(&fi->req_complete)) {
++ lh = fi->req_complete.next;
++ list_del(lh);
++ req = list_entry(lh, struct pending_request, list);
++ }
++ return req;
++}
++
++/* atomically get next completed request */
++static struct pending_request *next_complete_req(struct file_info *fi)
++{
++ unsigned long flags;
++ struct pending_request *req;
++
++ spin_lock_irqsave(&fi->reqlists_lock, flags);
++ req = __next_complete_req(fi);
++ spin_unlock_irqrestore(&fi->reqlists_lock, flags);
++ return req;
++}
+
+ static ssize_t raw1394_read(struct file *file, char __user * buffer,
+ size_t count, loff_t * offset_is_ignored)
+ {
+- unsigned long flags;
+ struct file_info *fi = (struct file_info *)file->private_data;
+- struct list_head *lh;
+ struct pending_request *req;
+ ssize_t ret;
+
+@@ -487,22 +510,21 @@ static ssize_t raw1394_read(struct file
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+- if (down_trylock(&fi->complete_sem)) {
++ if (!(req = next_complete_req(fi)))
+ return -EAGAIN;
+- }
+ } else {
+- if (down_interruptible(&fi->complete_sem)) {
++ /*
++ * NB: We call the macro wait_event_interruptible() with a
++ * condition argument with side effect. This is only possible
++ * because the side effect does not occur until the condition
++ * became true, and wait_event_interruptible() won't evaluate
++ * the condition again after that.
++ */
++ if (wait_event_interruptible(fi->wait_complete,
++ (req = next_complete_req(fi))))
+ return -ERESTARTSYS;
+- }
+ }
+
+- spin_lock_irqsave(&fi->reqlists_lock, flags);
+- lh = fi->req_complete.next;
+- list_del(lh);
+- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
+-
+- req = list_entry(lh, struct pending_request, list);
+-
+ if (req->req.length) {
+ if (copy_to_user(int2ptr(req->req.recvb), req->data,
+ req->req.length)) {
+@@ -1752,6 +1774,7 @@ static int arm_register(struct file_info
+ addr->notification_options |= addr->client_transactions;
+ addr->recvb = req->req.recvb;
+ addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
++
+ spin_lock_irqsave(&host_info_lock, flags);
+ hi = find_host_info(fi->host);
+ same_host = 0;
+@@ -1777,9 +1800,9 @@ static int arm_register(struct file_info
+ }
+ if (same_host) {
+ /* addressrange occupied by same host */
++ spin_unlock_irqrestore(&host_info_lock, flags);
+ vfree(addr->addr_space_buffer);
+ kfree(addr);
+- spin_unlock_irqrestore(&host_info_lock, flags);
+ return (-EALREADY);
+ }
+ /* another host with valid address-entry containing same addressrange */
+@@ -1807,6 +1830,8 @@ static int arm_register(struct file_info
+ }
+ }
+ }
++ spin_unlock_irqrestore(&host_info_lock, flags);
++
+ if (another_host) {
+ DBGMSG("another hosts entry is valid -> SUCCESS");
+ if (copy_to_user(int2ptr(req->req.recvb),
+@@ -1815,11 +1840,11 @@ static int arm_register(struct file_info
+ " address-range-entry is invalid -> EFAULT !!!\n");
+ vfree(addr->addr_space_buffer);
+ kfree(addr);
+- spin_unlock_irqrestore(&host_info_lock, flags);
+ return (-EFAULT);
+ }
+ free_pending_request(req); /* immediate success or fail */
+ /* INSERT ENTRY */
++ spin_lock_irqsave(&host_info_lock, flags);
+ list_add_tail(&addr->addr_list, &fi->addr_list);
+ spin_unlock_irqrestore(&host_info_lock, flags);
+ return sizeof(struct raw1394_request);
+@@ -1830,15 +1855,15 @@ static int arm_register(struct file_info
+ req->req.address + req->req.length);
+ if (retval) {
+ /* INSERT ENTRY */
++ spin_lock_irqsave(&host_info_lock, flags);
+ list_add_tail(&addr->addr_list, &fi->addr_list);
++ spin_unlock_irqrestore(&host_info_lock, flags);
+ } else {
+ DBGMSG("arm_register failed errno: %d \n", retval);
+ vfree(addr->addr_space_buffer);
+ kfree(addr);
+- spin_unlock_irqrestore(&host_info_lock, flags);
+ return (-EALREADY);
+ }
+- spin_unlock_irqrestore(&host_info_lock, flags);
+ free_pending_request(req); /* immediate success or fail */
+ return sizeof(struct raw1394_request);
+ }
+@@ -1904,10 +1929,10 @@ static int arm_unregister(struct file_in
+ if (another_host) {
+ DBGMSG("delete entry from list -> success");
+ list_del(&addr->addr_list);
++ spin_unlock_irqrestore(&host_info_lock, flags);
+ vfree(addr->addr_space_buffer);
+ kfree(addr);
+ free_pending_request(req); /* immediate success or fail */
+- spin_unlock_irqrestore(&host_info_lock, flags);
+ return sizeof(struct raw1394_request);
+ }
+ retval =
+@@ -1949,23 +1974,19 @@ static int arm_get_buf(struct file_info
+ (arm_addr->end > req->req.address)) {
+ if (req->req.address + req->req.length <= arm_addr->end) {
+ offset = req->req.address - arm_addr->start;
++ spin_unlock_irqrestore(&host_info_lock, flags);
+
+ DBGMSG
+ ("arm_get_buf copy_to_user( %08X, %p, %u )",
+ (u32) req->req.recvb,
+ arm_addr->addr_space_buffer + offset,
+ (u32) req->req.length);
+-
+ if (copy_to_user
+ (int2ptr(req->req.recvb),
+ arm_addr->addr_space_buffer + offset,
+- req->req.length)) {
+- spin_unlock_irqrestore(&host_info_lock,
+- flags);
++ req->req.length))
+ return (-EFAULT);
+- }
+
+- spin_unlock_irqrestore(&host_info_lock, flags);
+ /* We have to free the request, because we
+ * queue no response, and therefore nobody
+ * will free it. */
+@@ -2005,24 +2026,23 @@ static int arm_set_buf(struct file_info
+ (arm_addr->end > req->req.address)) {
+ if (req->req.address + req->req.length <= arm_addr->end) {
+ offset = req->req.address - arm_addr->start;
++ spin_unlock_irqrestore(&host_info_lock, flags);
+
+ DBGMSG
+ ("arm_set_buf copy_from_user( %p, %08X, %u )",
+ arm_addr->addr_space_buffer + offset,
+ (u32) req->req.sendb,
+ (u32) req->req.length);
+-
+ if (copy_from_user
+ (arm_addr->addr_space_buffer + offset,
+ int2ptr(req->req.sendb),
+- req->req.length)) {
+- spin_unlock_irqrestore(&host_info_lock,
+- flags);
++ req->req.length))
+ return (-EFAULT);
+- }
+
+- spin_unlock_irqrestore(&host_info_lock, flags);
+- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
++ /* We have to free the request, because we
++ * queue no response, and therefore nobody
++ * will free it. */
++ free_pending_request(req);
+ return sizeof(struct raw1394_request);
+ } else {
+ DBGMSG("arm_set_buf request exceeded mapping");
+@@ -2744,7 +2764,7 @@ static unsigned int raw1394_poll(struct
+ unsigned int mask = POLLOUT | POLLWRNORM;
+ unsigned long flags;
+
+- poll_wait(file, &fi->poll_wait_complete, pt);
++ poll_wait(file, &fi->wait_complete, pt);
+
+ spin_lock_irqsave(&fi->reqlists_lock, flags);
+ if (!list_empty(&fi->req_complete)) {
+@@ -2769,9 +2789,8 @@ static int raw1394_open(struct inode *in
+ fi->state = opened;
+ INIT_LIST_HEAD(&fi->req_pending);
+ INIT_LIST_HEAD(&fi->req_complete);
+- sema_init(&fi->complete_sem, 0);
+ spin_lock_init(&fi->reqlists_lock);
+- init_waitqueue_head(&fi->poll_wait_complete);
++ init_waitqueue_head(&fi->wait_complete);
+ INIT_LIST_HEAD(&fi->addr_list);
+
+ file->private_data = fi;
+@@ -2784,7 +2803,7 @@ static int raw1394_release(struct inode
+ struct file_info *fi = file->private_data;
+ struct list_head *lh;
+ struct pending_request *req;
+- int done = 0, i, fail = 0;
++ int i, fail;
+ int retval = 0;
+ struct list_head *entry;
+ struct arm_addr *addr = NULL;
+@@ -2864,25 +2883,28 @@ static int raw1394_release(struct inode
+ "error(s) occurred \n");
+ }
+
+- while (!done) {
++ for (;;) {
++ /* This locked section guarantees that neither
++ * complete nor pending requests exist once i!=0 */
+ spin_lock_irqsave(&fi->reqlists_lock, flags);
+-
+- while (!list_empty(&fi->req_complete)) {
+- lh = fi->req_complete.next;
+- list_del(lh);
+-
+- req = list_entry(lh, struct pending_request, list);
+-
++ while ((req = __next_complete_req(fi)))
+ free_pending_request(req);
+- }
+-
+- if (list_empty(&fi->req_pending))
+- done = 1;
+
++ i = list_empty(&fi->req_pending);
+ spin_unlock_irqrestore(&fi->reqlists_lock, flags);
+
+- if (!done)
+- down_interruptible(&fi->complete_sem);
++ if (i)
++ break;
++ /*
++ * Sleep until more requests can be freed.
++ *
++ * NB: We call the macro wait_event() with a condition argument
++ * with side effect. This is only possible because the side
++ * effect does not occur until the condition became true, and
++ * wait_event() won't evaluate the condition again after that.
++ */
++ wait_event(fi->wait_complete, (req = next_complete_req(fi)));
++ free_pending_request(req);
+ }
+
+ /* Remove any sub-trees left by user space programs */
+diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
+index b08755e..6986ac1 100644
+--- a/drivers/ieee1394/sbp2.c
++++ b/drivers/ieee1394/sbp2.c
+@@ -38,31 +38,36 @@
+ * but the code needs additional debugging.
+ */
+
++#include <linux/blkdev.h>
++#include <linux/compiler.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/gfp.h>
++#include <linux/init.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+-#include <linux/string.h>
+-#include <linux/stringify.h>
+-#include <linux/slab.h>
+-#include <linux/interrupt.h>
+-#include <linux/fs.h>
+-#include <linux/poll.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <linux/types.h>
+-#include <linux/delay.h>
+-#include <linux/sched.h>
+-#include <linux/blkdev.h>
+-#include <linux/smp_lock.h>
+-#include <linux/init.h>
+ #include <linux/pci.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/stringify.h>
++#include <linux/types.h>
++#include <linux/wait.h>
+
+-#include <asm/current.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+ #include <asm/byteorder.h>
+-#include <asm/atomic.h>
+-#include <asm/system.h>
++#include <asm/errno.h>
++#include <asm/param.h>
+ #include <asm/scatterlist.h>
++#include <asm/system.h>
++#include <asm/types.h>
++
++#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
++#include <asm/io.h> /* for bus_to_virt */
++#endif
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -71,13 +76,14 @@
+ #include <scsi/scsi_host.h>
+
+ #include "csr1212.h"
++#include "highlevel.h"
++#include "hosts.h"
+ #include "ieee1394.h"
+-#include "ieee1394_types.h"
+ #include "ieee1394_core.h"
+-#include "nodemgr.h"
+-#include "hosts.h"
+-#include "highlevel.h"
++#include "ieee1394_hotplug.h"
+ #include "ieee1394_transactions.h"
++#include "ieee1394_types.h"
++#include "nodemgr.h"
+ #include "sbp2.h"
+
+ /*
+@@ -173,11 +179,6 @@ MODULE_PARM_DESC(workarounds, "Work arou
+ ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
+ ", or a combination)");
+
+-/* legacy parameter */
+-static int force_inquiry_hack;
+-module_param(force_inquiry_hack, int, 0644);
+-MODULE_PARM_DESC(force_inquiry_hack, "Deprecated, use 'workarounds'");
+-
+ /*
+ * Export information about protocols/devices supported by this driver.
+ */
+@@ -208,9 +209,9 @@ static u32 global_outstanding_command_or
+ #define outstanding_orb_incr global_outstanding_command_orbs++
+ #define outstanding_orb_decr global_outstanding_command_orbs--
+ #else
+-#define SBP2_ORB_DEBUG(fmt, args...)
+-#define outstanding_orb_incr
+-#define outstanding_orb_decr
++#define SBP2_ORB_DEBUG(fmt, args...) do {} while (0)
++#define outstanding_orb_incr do {} while (0)
++#define outstanding_orb_decr do {} while (0)
+ #endif
+
+ #ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
+@@ -222,8 +223,8 @@ static u32 global_outstanding_command_or
+ --global_outstanding_dmas, ## args)
+ static u32 global_outstanding_dmas = 0;
+ #else
+-#define SBP2_DMA_ALLOC(fmt, args...)
+-#define SBP2_DMA_FREE(fmt, args...)
++#define SBP2_DMA_ALLOC(fmt, args...) do {} while (0)
++#define SBP2_DMA_FREE(fmt, args...) do {} while (0)
+ #endif
+
+ #if CONFIG_IEEE1394_SBP2_DEBUG >= 2
+@@ -237,7 +238,7 @@ static u32 global_outstanding_dmas = 0;
+ #define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args)
+ #define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args)
+ #else
+-#define SBP2_DEBUG(fmt, args...)
++#define SBP2_DEBUG(fmt, args...) do {} while (0)
+ #define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)
+ #define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args)
+ #define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args)
+@@ -356,7 +357,7 @@ static const struct {
+ /*
+ * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
+ */
+-static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
++static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
+ {
+ u32 *temp = buffer;
+
+@@ -369,7 +370,7 @@ static __inline__ void sbp2util_be32_to_
+ /*
+ * Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
+ */
+-static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
++static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
+ {
+ u32 *temp = buffer;
+
+@@ -380,8 +381,8 @@ static __inline__ void sbp2util_cpu_to_b
+ }
+ #else /* BIG_ENDIAN */
+ /* Why waste the cpu cycles? */
+-#define sbp2util_be32_to_cpu_buffer(x,y)
+-#define sbp2util_cpu_to_be32_buffer(x,y)
++#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
++#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
+ #endif
+
+ #ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP
+@@ -417,24 +418,26 @@ static void sbp2util_packet_dump(void *b
+ return;
+ }
+ #else
+-#define sbp2util_packet_dump(w,x,y,z)
++#define sbp2util_packet_dump(w,x,y,z) do {} while (0)
+ #endif
+
++static DECLARE_WAIT_QUEUE_HEAD(access_wq);
++
+ /*
+- * Goofy routine that basically does a down_timeout function.
++ * Waits for completion of an SBP-2 access request.
++ * Returns nonzero if timed out or prematurely interrupted.
+ */
+-static int sbp2util_down_timeout(atomic_t *done, int timeout)
++static int sbp2util_access_timeout(struct scsi_id_instance_data *scsi_id,
++ int timeout)
+ {
+- int i;
++ long leftover = wait_event_interruptible_timeout(
++ access_wq, scsi_id->access_complete, timeout);
+
+- for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
+- if (msleep_interruptible(100)) /* 100ms */
+- return 1;
+- }
+- return (i > 0) ? 0 : 1;
++ scsi_id->access_complete = 0;
++ return leftover <= 0;
+ }
+
+-/* Free's an allocated packet */
++/* Frees an allocated packet */
+ static void sbp2_free_packet(struct hpsb_packet *packet)
+ {
+ hpsb_free_tlabel(packet);
+@@ -468,6 +471,44 @@ static int sbp2util_node_write_no_wait(s
+ return 0;
+ }
+
++static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id,
++ u64 offset, quadlet_t *data, size_t len)
++{
++ /*
++ * There is a small window after a bus reset within which the node
++ * entry's generation is current but the reconnect wasn't completed.
++ */
++ if (unlikely(atomic_read(&scsi_id->state) == SBP2LU_STATE_IN_RESET))
++ return;
++
++ if (hpsb_node_write(scsi_id->ne,
++ scsi_id->sbp2_command_block_agent_addr + offset,
++ data, len))
++ SBP2_ERR("sbp2util_notify_fetch_agent failed.");
++ /*
++ * Now accept new SCSI commands, unless a bus reset happended during
++ * hpsb_node_write.
++ */
++ if (likely(atomic_read(&scsi_id->state) != SBP2LU_STATE_IN_RESET))
++ scsi_unblock_requests(scsi_id->scsi_host);
++}
++
++static void sbp2util_write_orb_pointer(void *p)
++{
++ quadlet_t data[2];
++
++ data[0] = ORB_SET_NODE_ID(
++ ((struct scsi_id_instance_data *)p)->hi->host->node_id);
++ data[1] = ((struct scsi_id_instance_data *)p)->last_orb_dma;
++ sbp2util_cpu_to_be32_buffer(data, 8);
++ sbp2util_notify_fetch_agent(p, SBP2_ORB_POINTER_OFFSET, data, 8);
++}
++
++static void sbp2util_write_doorbell(void *p)
++{
++ sbp2util_notify_fetch_agent(p, SBP2_DOORBELL_OFFSET, NULL, 4);
++}
++
+ /*
+ * This function is called to create a pool of command orbs used for
+ * command processing. It is called when a new sbp2 device is detected.
+@@ -492,7 +533,7 @@ static int sbp2util_create_command_orb_p
+ command->command_orb_dma =
+ pci_map_single(hi->host->pdev, &command->command_orb,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
+ SBP2_DMA_ALLOC("single command orb DMA");
+ command->sge_dma =
+ pci_map_single(hi->host->pdev,
+@@ -525,7 +566,7 @@ static void sbp2util_remove_command_orb_
+ /* Release our generic DMA's */
+ pci_unmap_single(host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
+ SBP2_DMA_FREE("single command orb DMA");
+ pci_unmap_single(host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+@@ -715,6 +756,7 @@ static int sbp2_remove(struct device *de
+ sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);
+ /* scsi_remove_device() will trigger shutdown functions of SCSI
+ * highlevel drivers which would deadlock if blocked. */
++ atomic_set(&scsi_id->state, SBP2LU_STATE_IN_SHUTDOWN);
+ scsi_unblock_requests(scsi_id->scsi_host);
+ }
+ sdev = scsi_id->sdev;
+@@ -766,10 +808,12 @@ static int sbp2_update(struct unit_direc
+ */
+ sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
+
+- /* Make sure we unblock requests (since this is likely after a bus
+- * reset). */
+- scsi_unblock_requests(scsi_id->scsi_host);
+-
++ /* Accept new commands unless there was another bus reset in the
++ * meantime. */
++ if (hpsb_node_entry_valid(scsi_id->ne)) {
++ atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
++ scsi_unblock_requests(scsi_id->scsi_host);
++ }
+ return 0;
+ }
+
+@@ -794,11 +838,12 @@ static struct scsi_id_instance_data *sbp
+ scsi_id->speed_code = IEEE1394_SPEED_100;
+ scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
+ scsi_id->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
+- atomic_set(&scsi_id->sbp2_login_complete, 0);
+ INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
+ INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
+ INIT_LIST_HEAD(&scsi_id->scsi_list);
+ spin_lock_init(&scsi_id->sbp2_command_orb_lock);
++ atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
++ INIT_WORK(&scsi_id->protocol_work, NULL, NULL);
+
+ ud->device.driver_data = scsi_id;
+
+@@ -881,11 +926,14 @@ static void sbp2_host_reset(struct hpsb_
+ struct scsi_id_instance_data *scsi_id;
+
+ hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
+-
+- if (hi) {
+- list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
++ if (!hi)
++ return;
++ list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
++ if (likely(atomic_read(&scsi_id->state) !=
++ SBP2LU_STATE_IN_SHUTDOWN)) {
++ atomic_set(&scsi_id->state, SBP2LU_STATE_IN_RESET);
+ scsi_block_requests(scsi_id->scsi_host);
+- }
++ }
+ }
+
+ /*
+@@ -970,8 +1018,7 @@ static int sbp2_start_device(struct scsi
+ * connected to the sbp2 device being removed. That host would
+ * have a certain amount of time to relogin before the sbp2 device
+ * allows someone else to login instead. One second makes sense. */
+- msleep_interruptible(1000);
+- if (signal_pending(current)) {
++ if (msleep_interruptible(1000)) {
+ sbp2_remove_device(scsi_id);
+ return -EINTR;
+ }
+@@ -1036,7 +1083,7 @@ static void sbp2_remove_device(struct sc
+ scsi_remove_host(scsi_id->scsi_host);
+ scsi_host_put(scsi_id->scsi_host);
+ }
+-
++ flush_scheduled_work();
+ sbp2util_remove_command_orb_pool(scsi_id);
+
+ list_del(&scsi_id->scsi_list);
+@@ -1182,17 +1229,14 @@ static int sbp2_query_logins(struct scsi
+ "sbp2 query logins orb", scsi_id->query_logins_orb_dma);
+
+ memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
+- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
+
+ data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+ data[1] = scsi_id->query_logins_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+
+- atomic_set(&scsi_id->sbp2_login_complete, 0);
+-
+ hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
+
+- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
++ if (sbp2util_access_timeout(scsi_id, 2*HZ)) {
+ SBP2_INFO("Error querying logins to SBP-2 device - timed out");
+ return -EIO;
+ }
+@@ -1202,11 +1246,8 @@ static int sbp2_query_logins(struct scsi
+ return -EIO;
+ }
+
+- if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
+- STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
+- STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
+-
+- SBP2_INFO("Error querying logins to SBP-2 device - timed out");
++ if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) {
++ SBP2_INFO("Error querying logins to SBP-2 device - failed");
+ return -EIO;
+ }
+
+@@ -1278,21 +1319,18 @@ static int sbp2_login_device(struct scsi
+ "sbp2 login orb", scsi_id->login_orb_dma);
+
+ memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
+- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
+
+ data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+ data[1] = scsi_id->login_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+
+- atomic_set(&scsi_id->sbp2_login_complete, 0);
+-
+ hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
+
+ /*
+ * Wait for login status (up to 20 seconds)...
+ */
+- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) {
+- SBP2_ERR("Error logging into SBP-2 device - login timed-out");
++ if (sbp2util_access_timeout(scsi_id, 20*HZ)) {
++ SBP2_ERR("Error logging into SBP-2 device - timed out");
+ return -EIO;
+ }
+
+@@ -1300,18 +1338,12 @@ static int sbp2_login_device(struct scsi
+ * Sanity. Make sure status returned matches login orb.
+ */
+ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
+- SBP2_ERR("Error logging into SBP-2 device - login timed-out");
++ SBP2_ERR("Error logging into SBP-2 device - timed out");
+ return -EIO;
+ }
+
+- /*
+- * Check status
+- */
+- if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
+- STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
+- STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
+-
+- SBP2_ERR("Error logging into SBP-2 device - login failed");
++ if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) {
++ SBP2_ERR("Error logging into SBP-2 device - failed");
+ return -EIO;
+ }
+
+@@ -1335,9 +1367,7 @@ static int sbp2_login_device(struct scsi
+ scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;
+
+ SBP2_INFO("Logged into SBP-2 device");
+-
+ return 0;
+-
+ }
+
+ /*
+@@ -1387,21 +1417,17 @@ static int sbp2_logout_device(struct scs
+ data[1] = scsi_id->logout_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+
+- atomic_set(&scsi_id->sbp2_login_complete, 0);
+-
+ error = hpsb_node_write(scsi_id->ne,
+ scsi_id->sbp2_management_agent_addr, data, 8);
+ if (error)
+ return error;
+
+ /* Wait for device to logout...1 second. */
+- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ))
++ if (sbp2util_access_timeout(scsi_id, HZ))
+ return -EIO;
+
+ SBP2_INFO("Logged out of SBP-2 device");
+-
+ return 0;
+-
+ }
+
+ /*
+@@ -1445,20 +1471,10 @@ static int sbp2_reconnect_device(struct
+ sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb),
+ "sbp2 reconnect orb", scsi_id->reconnect_orb_dma);
+
+- /*
+- * Initialize status fifo
+- */
+- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
+-
+- /*
+- * Ok, let's write to the target's management agent register
+- */
+ data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+ data[1] = scsi_id->reconnect_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+
+- atomic_set(&scsi_id->sbp2_login_complete, 0);
+-
+ error = hpsb_node_write(scsi_id->ne,
+ scsi_id->sbp2_management_agent_addr, data, 8);
+ if (error)
+@@ -1467,8 +1483,8 @@ static int sbp2_reconnect_device(struct
+ /*
+ * Wait for reconnect status (up to 1 second)...
+ */
+- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {
+- SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
++ if (sbp2util_access_timeout(scsi_id, HZ)) {
++ SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
+ return -EIO;
+ }
+
+@@ -1476,25 +1492,17 @@ static int sbp2_reconnect_device(struct
+ * Sanity. Make sure status returned matches reconnect orb.
+ */
+ if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
+- SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
++ SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
+ return -EIO;
+ }
+
+- /*
+- * Check status
+- */
+- if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
+- STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
+- STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
+-
+- SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed");
++ if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) {
++ SBP2_ERR("Error reconnecting to SBP-2 device - failed");
+ return -EIO;
+ }
+
+ HPSB_DEBUG("Reconnected to SBP-2 device");
+-
+ return 0;
+-
+ }
+
+ /*
+@@ -1592,11 +1600,6 @@ static void sbp2_parse_unit_directory(st
+ }
+
+ workarounds = sbp2_default_workarounds;
+- if (force_inquiry_hack) {
+- SBP2_WARN("force_inquiry_hack is deprecated. "
+- "Use parameter 'workarounds' instead.");
+- workarounds |= SBP2_WORKAROUND_INQUIRY_36;
+- }
+
+ if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
+ for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
+@@ -1705,9 +1708,14 @@ static int sbp2_agent_reset(struct scsi_
+ quadlet_t data;
+ u64 addr;
+ int retval;
++ unsigned long flags;
+
+ SBP2_DEBUG_ENTER();
+
++ cancel_delayed_work(&scsi_id->protocol_work);
++ if (wait)
++ flush_scheduled_work();
++
+ data = ntohl(SBP2_AGENT_RESET_DATA);
+ addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
+
+@@ -1724,7 +1732,9 @@ static int sbp2_agent_reset(struct scsi_
+ /*
+ * Need to make sure orb pointer is written on next command
+ */
++ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
+ scsi_id->last_orb = NULL;
++ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
+
+ return 0;
+ }
+@@ -1961,13 +1971,17 @@ static void sbp2_create_command_orb(stru
+ /*
+ * This function is called in order to begin a regular SBP-2 command.
+ */
+-static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
++static void sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
+ struct sbp2_command_info *command)
+ {
+ struct sbp2scsi_host_info *hi = scsi_id->hi;
+ struct sbp2_command_orb *command_orb = &command->command_orb;
+- struct node_entry *ne = scsi_id->ne;
+- u64 addr;
++ struct sbp2_command_orb *last_orb;
++ dma_addr_t last_orb_dma;
++ u64 addr = scsi_id->sbp2_command_block_agent_addr;
++ quadlet_t data[2];
++ size_t length;
++ unsigned long flags;
+
+ outstanding_orb_incr;
+ SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
+@@ -1975,73 +1989,70 @@ static int sbp2_link_orb_command(struct
+
+ pci_dma_sync_single_for_device(hi->host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_device(hi->host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
+ /*
+ * Check to see if there are any previous orbs to use
+ */
+- if (scsi_id->last_orb == NULL) {
+- quadlet_t data[2];
+-
++ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
++ last_orb = scsi_id->last_orb;
++ last_orb_dma = scsi_id->last_orb_dma;
++ if (!last_orb) {
+ /*
+- * Ok, let's write to the target's management agent register
++ * last_orb == NULL means: We know that the target's fetch agent
++ * is not active right now.
+ */
+- addr = scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET;
++ addr += SBP2_ORB_POINTER_OFFSET;
+ data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+ data[1] = command->command_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+-
+- SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);
+-
+- if (sbp2util_node_write_no_wait(ne, addr, data, 8) < 0) {
+- SBP2_ERR("sbp2util_node_write_no_wait failed.\n");
+- return -EIO;
+- }
+-
+- SBP2_ORB_DEBUG("write command agent complete");
+-
+- scsi_id->last_orb = command_orb;
+- scsi_id->last_orb_dma = command->command_orb_dma;
+-
++ length = 8;
+ } else {
+- quadlet_t data;
+-
+ /*
+- * We have an orb already sent (maybe or maybe not
+- * processed) that we can append this orb to. So do so,
+- * and ring the doorbell. Have to be very careful
+- * modifying these next orb pointers, as they are accessed
+- * both by the sbp2 device and us.
++ * last_orb != NULL means: We know that the target's fetch agent
++ * is (very probably) not dead or in reset state right now.
++ * We have an ORB already sent that we can append a new one to.
++ * The target's fetch agent may or may not have read this
++ * previous ORB yet.
+ */
+- scsi_id->last_orb->next_ORB_lo =
+- cpu_to_be32(command->command_orb_dma);
++ pci_dma_sync_single_for_cpu(hi->host->pdev, last_orb_dma,
++ sizeof(struct sbp2_command_orb),
++ PCI_DMA_TODEVICE);
++ last_orb->next_ORB_lo = cpu_to_be32(command->command_orb_dma);
++ wmb();
+ /* Tells hardware that this pointer is valid */
+- scsi_id->last_orb->next_ORB_hi = 0x0;
+- pci_dma_sync_single_for_device(hi->host->pdev,
+- scsi_id->last_orb_dma,
++ last_orb->next_ORB_hi = 0;
++ pci_dma_sync_single_for_device(hi->host->pdev, last_orb_dma,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
++ addr += SBP2_DOORBELL_OFFSET;
++ data[0] = 0;
++ length = 4;
++ }
++ scsi_id->last_orb = command_orb;
++ scsi_id->last_orb_dma = command->command_orb_dma;
++ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
+
++ SBP2_ORB_DEBUG("write to %s register, command orb %p",
++ last_orb ? "DOORBELL" : "ORB_POINTER", command_orb);
++ if (sbp2util_node_write_no_wait(scsi_id->ne, addr, data, length)) {
+ /*
+- * Ring the doorbell
++ * sbp2util_node_write_no_wait failed. We certainly ran out
++ * of transaction labels, perhaps just because there were no
++ * context switches which gave khpsbpkt a chance to collect
++ * free tlabels. Try again in non-atomic context. If necessary,
++ * the workqueue job will sleep to guaranteedly get a tlabel.
++ * We do not accept new commands until the job is over.
+ */
+- data = cpu_to_be32(command->command_orb_dma);
+- addr = scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET;
+-
+- SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);
+-
+- if (sbp2util_node_write_no_wait(ne, addr, &data, 4) < 0) {
+- SBP2_ERR("sbp2util_node_write_no_wait failed");
+- return -EIO;
+- }
+-
+- scsi_id->last_orb = command_orb;
+- scsi_id->last_orb_dma = command->command_orb_dma;
+-
++ scsi_block_requests(scsi_id->scsi_host);
++ PREPARE_WORK(&scsi_id->protocol_work,
++ last_orb ? sbp2util_write_doorbell:
++ sbp2util_write_orb_pointer,
++ scsi_id);
++ schedule_work(&scsi_id->protocol_work);
+ }
+- return 0;
+ }
+
+ /*
+@@ -2078,11 +2089,6 @@ static int sbp2_send_command(struct scsi
+ "sbp2 command orb", command->command_orb_dma);
+
+ /*
+- * Initialize status fifo
+- */
+- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
+-
+- /*
+ * Link up the orb, and ring the doorbell if needed
+ */
+ sbp2_link_orb_command(scsi_id, command);
+@@ -2123,12 +2129,14 @@ static unsigned int sbp2_status_to_sense
+ /*
+ * This function deals with status writes from the SBP-2 device
+ */
+-static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
+- quadlet_t *data, u64 addr, size_t length, u16 fl)
++static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
++ int destid, quadlet_t *data, u64 addr,
++ size_t length, u16 fl)
+ {
+ struct sbp2scsi_host_info *hi;
+ struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
+ struct scsi_cmnd *SCpnt = NULL;
++ struct sbp2_status_block *sb;
+ u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
+ struct sbp2_command_info *command;
+ unsigned long flags;
+@@ -2137,18 +2145,19 @@ static int sbp2_handle_status_write(stru
+
+ sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr);
+
+- if (!host) {
++ if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) {
++ SBP2_ERR("Wrong size of status block");
++ return RCODE_ADDRESS_ERROR;
++ }
++ if (unlikely(!host)) {
+ SBP2_ERR("host is NULL - this is bad!");
+ return RCODE_ADDRESS_ERROR;
+ }
+-
+ hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
+-
+- if (!hi) {
++ if (unlikely(!hi)) {
+ SBP2_ERR("host info is NULL - this is bad!");
+ return RCODE_ADDRESS_ERROR;
+ }
+-
+ /*
+ * Find our scsi_id structure by looking at the status fifo address
+ * written to by the sbp2 device.
+@@ -2160,32 +2169,35 @@ static int sbp2_handle_status_write(stru
+ break;
+ }
+ }
+-
+- if (!scsi_id) {
++ if (unlikely(!scsi_id)) {
+ SBP2_ERR("scsi_id is NULL - device is gone?");
+ return RCODE_ADDRESS_ERROR;
+ }
+
+ /*
+- * Put response into scsi_id status fifo...
++ * Put response into scsi_id status fifo buffer. The first two bytes
++ * come in big endian bit order. Often the target writes only a
++ * truncated status block, minimally the first two quadlets. The rest
++ * is implied to be zeros.
+ */
+- memcpy(&scsi_id->status_block, data, length);
++ sb = &scsi_id->status_block;
++ memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
++ memcpy(sb, data, length);
++ sbp2util_be32_to_cpu_buffer(sb, 8);
+
+ /*
+- * Byte swap first two quadlets (8 bytes) of status for processing
++ * Ignore unsolicited status. Handle command ORB status.
+ */
+- sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8);
+-
+- /*
+- * Handle command ORB status here if necessary. First, need to match status with command.
+- */
+- command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo);
++ if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2))
++ command = NULL;
++ else
++ command = sbp2util_find_command_for_orb(scsi_id,
++ sb->ORB_offset_lo);
+ if (command) {
+-
+ SBP2_DEBUG("Found status for command ORB");
+ pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
+@@ -2194,7 +2206,12 @@ static int sbp2_handle_status_write(stru
+ outstanding_orb_decr;
+
+ /*
+- * Matched status with command, now grab scsi command pointers and check status
++ * Matched status with command, now grab scsi command pointers
++ * and check status.
++ */
++ /*
++ * FIXME: If the src field in the status is 1, the ORB DMA must
++ * not be reused until status for a subsequent ORB is received.
+ */
+ SCpnt = command->Current_SCpnt;
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
+@@ -2202,61 +2219,64 @@ static int sbp2_handle_status_write(stru
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
+
+ if (SCpnt) {
+-
++ u32 h = sb->ORB_offset_hi_misc;
++ u32 r = STATUS_GET_RESP(h);
++
++ if (r != RESP_STATUS_REQUEST_COMPLETE) {
++ SBP2_WARN("resp 0x%x, sbp_status 0x%x",
++ r, STATUS_GET_SBP_STATUS(h));
++ scsi_status =
++ r == RESP_STATUS_TRANSPORT_FAILURE ?
++ SBP2_SCSI_STATUS_BUSY :
++ SBP2_SCSI_STATUS_COMMAND_TERMINATED;
++ }
+ /*
+- * See if the target stored any scsi status information
++ * See if the target stored any scsi status information.
+ */
+- if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) {
+- /*
+- * Translate SBP-2 status to SCSI sense data
+- */
++ if (STATUS_GET_LEN(h) > 1) {
+ SBP2_DEBUG("CHECK CONDITION");
+- scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
++ scsi_status = sbp2_status_to_sense_data(
++ (unchar *)sb, SCpnt->sense_buffer);
+ }
+-
+ /*
+- * Check to see if the dead bit is set. If so, we'll have to initiate
+- * a fetch agent reset.
++ * Check to see if the dead bit is set. If so, we'll
++ * have to initiate a fetch agent reset.
+ */
+- if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) {
+-
+- /*
+- * Initiate a fetch agent reset.
+- */
+- SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
++ if (STATUS_TEST_DEAD(h)) {
++ SBP2_DEBUG("Dead bit set - "
++ "initiating fetch agent reset");
+ sbp2_agent_reset(scsi_id, 0);
+ }
+-
+ SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
+ }
+
+ /*
+- * Check here to see if there are no commands in-use. If there are none, we can
+- * null out last orb so that next time around we write directly to the orb pointer...
+- * Quick start saves one 1394 bus transaction.
++ * Check here to see if there are no commands in-use. If there
++ * are none, we know that the fetch agent left the active state
++ * _and_ that we did not reactivate it yet. Therefore clear
++ * last_orb so that next time we write directly to the
++ * ORB_POINTER register. That way the fetch agent does not need
++ * to refetch the next_ORB.
+ */
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
+- if (list_empty(&scsi_id->sbp2_command_orb_inuse)) {
++ if (list_empty(&scsi_id->sbp2_command_orb_inuse))
+ scsi_id->last_orb = NULL;
+- }
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
+
+ } else {
+-
+ /*
+ * It's probably a login/logout/reconnect status.
+ */
+- if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+- (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+- (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+- (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
+- atomic_set(&scsi_id->sbp2_login_complete, 1);
++ if ((sb->ORB_offset_lo == scsi_id->reconnect_orb_dma) ||
++ (sb->ORB_offset_lo == scsi_id->login_orb_dma) ||
++ (sb->ORB_offset_lo == scsi_id->query_logins_orb_dma) ||
++ (sb->ORB_offset_lo == scsi_id->logout_orb_dma)) {
++ scsi_id->access_complete = 1;
++ wake_up_interruptible(&access_wq);
+ }
+ }
+
+ if (SCpnt) {
+-
+- /* Complete the SCSI command. */
+ SBP2_DEBUG("Completing SCSI command");
+ sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
+ command->Current_done);
+@@ -2372,7 +2392,7 @@ static void sbp2scsi_complete_all_comman
+ command = list_entry(lh, struct sbp2_command_info, list);
+ pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
+@@ -2495,6 +2515,7 @@ static int sbp2scsi_slave_alloc(struct s
+ (struct scsi_id_instance_data *)sdev->host->hostdata[0];
+
+ scsi_id->sdev = sdev;
++ sdev->allow_restart = 1;
+
+ if (scsi_id->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+ sdev->inquiry_len = 36;
+@@ -2508,16 +2529,12 @@ static int sbp2scsi_slave_configure(stru
+
+ blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
+ sdev->use_10_for_rw = 1;
+- sdev->use_10_for_ms = 1;
+
+ if (sdev->type == TYPE_DISK &&
+ scsi_id->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
+ sdev->skip_ms_page_8 = 1;
+ if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
+ sdev->fix_capacity = 1;
+- if (scsi_id->ne->guid_vendor_id == 0x0010b9 && /* Maxtor's OUI */
+- (sdev->type == TYPE_DISK || sdev->type == TYPE_RBC))
+- sdev->allow_restart = 1;
+ return 0;
+ }
+
+@@ -2555,7 +2572,7 @@ static int sbp2scsi_abort(struct scsi_cm
+ pci_dma_sync_single_for_cpu(hi->host->pdev,
+ command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+- PCI_DMA_BIDIRECTIONAL);
++ PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_cpu(hi->host->pdev,
+ command->sge_dma,
+ sizeof(command->scatter_gather_element),
+@@ -2571,7 +2588,7 @@ static int sbp2scsi_abort(struct scsi_cm
+ /*
+ * Initiate a fetch agent reset.
+ */
+- sbp2_agent_reset(scsi_id, 0);
++ sbp2_agent_reset(scsi_id, 1);
+ sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
+ }
+
+@@ -2590,7 +2607,7 @@ static int sbp2scsi_reset(struct scsi_cm
+
+ if (sbp2util_node_is_available(scsi_id)) {
+ SBP2_ERR("Generating sbp2 fetch agent reset");
+- sbp2_agent_reset(scsi_id, 0);
++ sbp2_agent_reset(scsi_id, 1);
+ }
+
+ return SUCCESS;
+diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
+index b22ce1a..abbe48e 100644
+--- a/drivers/ieee1394/sbp2.h
++++ b/drivers/ieee1394/sbp2.h
+@@ -46,8 +46,8 @@
+ #define ORB_SET_DIRECTION(value) ((value & 0x1) << 27)
+
+ struct sbp2_command_orb {
+- volatile u32 next_ORB_hi;
+- volatile u32 next_ORB_lo;
++ u32 next_ORB_hi;
++ u32 next_ORB_lo;
+ u32 data_descriptor_hi;
+ u32 data_descriptor_lo;
+ u32 misc;
+@@ -180,12 +180,14 @@ struct sbp2_unrestricted_page_table {
+
+ #define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff
+
+-#define STATUS_GET_ORB_OFFSET_HI(value) (value & 0xffff)
+-#define STATUS_GET_SBP_STATUS(value) ((value >> 16) & 0xff)
+-#define STATUS_GET_LENGTH(value) ((value >> 24) & 0x7)
+-#define STATUS_GET_DEAD_BIT(value) ((value >> 27) & 0x1)
+-#define STATUS_GET_RESP(value) ((value >> 28) & 0x3)
+-#define STATUS_GET_SRC(value) ((value >> 30) & 0x3)
++#define STATUS_GET_SRC(value) (((value) >> 30) & 0x3)
++#define STATUS_GET_RESP(value) (((value) >> 28) & 0x3)
++#define STATUS_GET_LEN(value) (((value) >> 24) & 0x7)
++#define STATUS_GET_SBP_STATUS(value) (((value) >> 16) & 0xff)
++#define STATUS_GET_ORB_OFFSET_HI(value) ((value) & 0x0000ffff)
++#define STATUS_TEST_DEAD(value) ((value) & 0x08000000)
++/* test 'resp' | 'dead' | 'sbp2_status' */
++#define STATUS_TEST_RDS(value) ((value) & 0x38ff0000)
+
+ struct sbp2_status_block {
+ u32 ORB_offset_hi_misc;
+@@ -318,9 +320,9 @@ struct scsi_id_instance_data {
+ u64 status_fifo_addr;
+
+ /*
+- * Variable used for logins, reconnects, logouts, query logins
++ * Waitqueue flag for logins, reconnects, logouts, query logins
+ */
+- atomic_t sbp2_login_complete;
++ int access_complete:1;
+
+ /*
+ * Pool of command orbs, so we can have more than overlapped command per id
+@@ -344,6 +346,16 @@ struct scsi_id_instance_data {
+
+ /* Device specific workarounds/brokeness */
+ unsigned workarounds;
++
++ atomic_t state;
++ struct work_struct protocol_work;
++};
++
++/* For use in scsi_id_instance_data.state */
++enum sbp2lu_state_types {
++ SBP2LU_STATE_RUNNING, /* all normal */
++ SBP2LU_STATE_IN_RESET, /* between bus reset and reconnect */
++ SBP2LU_STATE_IN_SHUTDOWN /* when sbp2_remove was called */
+ };
+
+ /* Sbp2 host data structure (one per IEEE1394 host) */
+@@ -390,11 +402,6 @@ static int sbp2_logout_device(struct scs
+ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
+ quadlet_t *data, u64 addr, size_t length, u16 flags);
+ static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait);
+-static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
+- struct sbp2_command_info *command);
+-static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
+- struct scsi_cmnd *SCpnt,
+- void (*done)(struct scsi_cmnd *));
+ static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status,
+ unchar *sense_data);
+ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
+diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
+index c6e3f02..9bc6505 100644
+--- a/drivers/ieee1394/video1394.c
++++ b/drivers/ieee1394/video1394.c
+@@ -49,16 +49,16 @@
+ #include <linux/compat.h>
+ #include <linux/cdev.h>
+
+-#include "ieee1394.h"
+-#include "ieee1394_types.h"
++#include "dma.h"
++#include "highlevel.h"
+ #include "hosts.h"
++#include "ieee1394.h"
+ #include "ieee1394_core.h"
+-#include "highlevel.h"
+-#include "video1394.h"
++#include "ieee1394_hotplug.h"
++#include "ieee1394_types.h"
+ #include "nodemgr.h"
+-#include "dma.h"
+-
+ #include "ohci1394.h"
++#include "video1394.h"
+
+ #define ISO_CHANNELS 64
+
+@@ -129,7 +129,7 @@ struct file_ctx {
+ #define DBGMSG(card, fmt, args...) \
+ printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
+ #else
+-#define DBGMSG(card, fmt, args...)
++#define DBGMSG(card, fmt, args...) do {} while (0)
+ #endif
+
+ /* print general (card independent) information */
+@@ -1181,7 +1181,8 @@ static int video1394_mmap(struct file *f
+
+ lock_kernel();
+ if (ctx->current_ctx == NULL) {
+- PRINT(KERN_ERR, ctx->ohci->host->id, "Current iso context not set");
++ PRINT(KERN_ERR, ctx->ohci->host->id,
++ "Current iso context not set");
+ } else
+ res = dma_region_mmap(&ctx->current_ctx->dma, file, vma);
+ unlock_kernel();
+@@ -1189,6 +1190,40 @@ static int video1394_mmap(struct file *f
+ return res;
+ }
+
++static unsigned int video1394_poll(struct file *file, poll_table *pt)
++{
++ struct file_ctx *ctx;
++ unsigned int mask = 0;
++ unsigned long flags;
++ struct dma_iso_ctx *d;
++ int i;
++
++ lock_kernel();
++ ctx = file->private_data;
++ d = ctx->current_ctx;
++ if (d == NULL) {
++ PRINT(KERN_ERR, ctx->ohci->host->id,
++ "Current iso context not set");
++ mask = POLLERR;
++ goto done;
++ }
++
++ poll_wait(file, &d->waitq, pt);
++
++ spin_lock_irqsave(&d->lock, flags);
++ for (i = 0; i < d->num_desc; i++) {
++ if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
++ mask |= POLLIN | POLLRDNORM;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&d->lock, flags);
++done:
++ unlock_kernel();
++
++ return mask;
++}
++
+ static int video1394_open(struct inode *inode, struct file *file)
+ {
+ int i = ieee1394_file_to_instance(file);
+@@ -1257,6 +1292,7 @@ static struct file_operations video1394_
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = video1394_compat_ioctl,
+ #endif
++ .poll = video1394_poll,
+ .mmap = video1394_mmap,
+ .open = video1394_open,
+ .release = video1394_release
+diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
+index 69a53d4..9edface 100644
+--- a/drivers/infiniband/Kconfig
++++ b/drivers/infiniband/Kconfig
+@@ -14,7 +14,7 @@ config INFINIBAND_USER_MAD
+ ---help---
+ Userspace InfiniBand Management Datagram (MAD) support. This
+ is the kernel side of the userspace MAD support, which allows
+- userspace processes to send and receive MADs. You will also
++ userspace processes to send and receive MADs. You will also
+ need libibumad from <http://www.openib.org>.
+
+ config INFINIBAND_USER_ACCESS
+@@ -36,6 +36,8 @@ config INFINIBAND_ADDR_TRANS
+
+ source "drivers/infiniband/hw/mthca/Kconfig"
+ source "drivers/infiniband/hw/ipath/Kconfig"
++source "drivers/infiniband/hw/ehca/Kconfig"
++source "drivers/infiniband/hw/amso1100/Kconfig"
+
+ source "drivers/infiniband/ulp/ipoib/Kconfig"
+
+diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
+index c7ff58c..2b5d109 100644
+--- a/drivers/infiniband/Makefile
++++ b/drivers/infiniband/Makefile
+@@ -1,6 +1,8 @@
+ obj-$(CONFIG_INFINIBAND) += core/
+ obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/
+-obj-$(CONFIG_IPATH_CORE) += hw/ipath/
++obj-$(CONFIG_INFINIBAND_IPATH) += hw/ipath/
++obj-$(CONFIG_INFINIBAND_EHCA) += hw/ehca/
++obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
+ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
+ obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
+ obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
+diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
+index 68e73ec..163d991 100644
+--- a/drivers/infiniband/core/Makefile
++++ b/drivers/infiniband/core/Makefile
+@@ -1,7 +1,7 @@
+ infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o
+
+ obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \
+- ib_cm.o $(infiniband-y)
++ ib_cm.o iw_cm.o $(infiniband-y)
+ obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o
+ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o
+
+@@ -14,6 +14,8 @@ ib_sa-y := sa_query.o
+
+ ib_cm-y := cm.o
+
++iw_cm-y := iwcm.o
++
+ rdma_cm-y := cma.o
+
+ ib_addr-y := addr.o
+diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
+index 1205e80..e11187e 100644
+--- a/drivers/infiniband/core/addr.c
++++ b/drivers/infiniband/core/addr.c
+@@ -47,6 +47,7 @@ struct addr_req {
+ struct sockaddr src_addr;
+ struct sockaddr dst_addr;
+ struct rdma_dev_addr *addr;
++ struct rdma_addr_client *client;
+ void *context;
+ void (*callback)(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context);
+@@ -61,12 +62,35 @@ static LIST_HEAD(req_list);
+ static DECLARE_WORK(work, process_req, NULL);
+ static struct workqueue_struct *addr_wq;
+
+-static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
+- unsigned char *dst_dev_addr)
++void rdma_addr_register_client(struct rdma_addr_client *client)
++{
++ atomic_set(&client->refcount, 1);
++ init_completion(&client->comp);
++}
++EXPORT_SYMBOL(rdma_addr_register_client);
++
++static inline void put_client(struct rdma_addr_client *client)
++{
++ if (atomic_dec_and_test(&client->refcount))
++ complete(&client->comp);
++}
++
++void rdma_addr_unregister_client(struct rdma_addr_client *client)
++{
++ put_client(client);
++ wait_for_completion(&client->comp);
++}
++EXPORT_SYMBOL(rdma_addr_unregister_client);
++
++int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
++ const unsigned char *dst_dev_addr)
+ {
+ switch (dev->type) {
+ case ARPHRD_INFINIBAND:
+- dev_addr->dev_type = IB_NODE_CA;
++ dev_addr->dev_type = RDMA_NODE_IB_CA;
++ break;
++ case ARPHRD_ETHER:
++ dev_addr->dev_type = RDMA_NODE_RNIC;
+ break;
+ default:
+ return -EADDRNOTAVAIL;
+@@ -78,18 +102,19 @@ static int copy_addr(struct rdma_dev_add
+ memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
+ return 0;
+ }
++EXPORT_SYMBOL(rdma_copy_addr);
+
+ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
+ {
+ struct net_device *dev;
+- u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
++ __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ int ret;
+
+ dev = ip_dev_find(ip);
+ if (!dev)
+ return -EADDRNOTAVAIL;
+
+- ret = copy_addr(dev_addr, dev, NULL);
++ ret = rdma_copy_addr(dev_addr, dev, NULL);
+ dev_put(dev);
+ return ret;
+ }
+@@ -161,7 +186,7 @@ static int addr_resolve_remote(struct so
+
+ /* If the device does ARP internally, return 'done' */
+ if (rt->idev->dev->flags & IFF_NOARP) {
+- copy_addr(addr, rt->idev->dev, NULL);
++ rdma_copy_addr(addr, rt->idev->dev, NULL);
+ goto put;
+ }
+
+@@ -181,7 +206,7 @@ static int addr_resolve_remote(struct so
+ src_in->sin_addr.s_addr = rt->rt_src;
+ }
+
+- ret = copy_addr(addr, neigh->dev, neigh->ha);
++ ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
+ release:
+ neigh_release(neigh);
+ put:
+@@ -225,6 +250,7 @@ static void process_req(void *data)
+ list_del(&req->list);
+ req->callback(req->status, &req->src_addr, req->addr,
+ req->context);
++ put_client(req->client);
+ kfree(req);
+ }
+ }
+@@ -235,7 +261,7 @@ static int addr_resolve_local(struct soc
+ {
+ struct net_device *dev;
+ u32 src_ip = src_in->sin_addr.s_addr;
+- u32 dst_ip = dst_in->sin_addr.s_addr;
++ __be32 dst_ip = dst_in->sin_addr.s_addr;
+ int ret;
+
+ dev = ip_dev_find(dst_ip);
+@@ -245,7 +271,7 @@ static int addr_resolve_local(struct soc
+ if (ZERONET(src_ip)) {
+ src_in->sin_family = dst_in->sin_family;
+ src_in->sin_addr.s_addr = dst_ip;
+- ret = copy_addr(addr, dev, dev->dev_addr);
++ ret = rdma_copy_addr(addr, dev, dev->dev_addr);
+ } else if (LOOPBACK(src_ip)) {
+ ret = rdma_translate_ip((struct sockaddr *)dst_in, addr);
+ if (!ret)
+@@ -260,7 +286,8 @@ static int addr_resolve_local(struct soc
+ return ret;
+ }
+
+-int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
++int rdma_resolve_ip(struct rdma_addr_client *client,
++ struct sockaddr *src_addr, struct sockaddr *dst_addr,
+ struct rdma_dev_addr *addr, int timeout_ms,
+ void (*callback)(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context),
+@@ -281,6 +308,8 @@ int rdma_resolve_ip(struct sockaddr *src
+ req->addr = addr;
+ req->callback = callback;
+ req->context = context;
++ req->client = client;
++ atomic_inc(&client->refcount);
+
+ src_in = (struct sockaddr_in *) &req->src_addr;
+ dst_in = (struct sockaddr_in *) &req->dst_addr;
+@@ -301,6 +330,7 @@ int rdma_resolve_ip(struct sockaddr *src
+ break;
+ default:
+ ret = req->status;
++ atomic_dec(&client->refcount);
+ kfree(req);
+ break;
+ }
+@@ -327,10 +357,10 @@ void rdma_addr_cancel(struct rdma_dev_ad
+ }
+ EXPORT_SYMBOL(rdma_addr_cancel);
+
+-static int netevent_callback(struct notifier_block *self, unsigned long event,
++static int netevent_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
+ {
+- if (event == NETEVENT_NEIGH_UPDATE) {
++ if (event == NETEVENT_NEIGH_UPDATE) {
+ struct neighbour *neigh = ctx;
+
+ if (neigh->dev->type == ARPHRD_INFINIBAND &&
+diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
+index 75313ad..20e9f64 100644
+--- a/drivers/infiniband/core/cache.c
++++ b/drivers/infiniband/core/cache.c
+@@ -62,12 +62,13 @@ struct ib_update_work {
+
+ static inline int start_port(struct ib_device *device)
+ {
+- return device->node_type == IB_NODE_SWITCH ? 0 : 1;
++ return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
+ }
+
+ static inline int end_port(struct ib_device *device)
+ {
+- return device->node_type == IB_NODE_SWITCH ? 0 : device->phys_port_cnt;
++ return (device->node_type == RDMA_NODE_IB_SWITCH) ?
++ 0 : device->phys_port_cnt;
+ }
+
+ int ib_get_cached_gid(struct ib_device *device,
+diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
+index 0de335b..25b1018 100644
+--- a/drivers/infiniband/core/cm.c
++++ b/drivers/infiniband/core/cm.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
++ * Copyright (c) 2004-2006 Intel Corporation. All rights reserved.
+ * Copyright (c) 2004 Topspin Corporation. All rights reserved.
+ * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+@@ -41,6 +41,7 @@
+ #include <linux/idr.h>
+ #include <linux/interrupt.h>
+ #include <linux/pci.h>
++#include <linux/random.h>
+ #include <linux/rbtree.h>
+ #include <linux/spinlock.h>
+ #include <linux/workqueue.h>
+@@ -73,6 +74,8 @@ static struct ib_cm {
+ struct rb_root remote_id_table;
+ struct rb_root remote_sidr_table;
+ struct idr local_id_table;
++ __be32 random_id_operand;
++ struct list_head timewait_list;
+ struct workqueue_struct *wq;
+ } cm;
+
+@@ -110,6 +113,7 @@ struct cm_work {
+
+ struct cm_timewait_info {
+ struct cm_work work; /* Must be first. */
++ struct list_head list;
+ struct rb_node remote_qp_node;
+ struct rb_node remote_id_node;
+ __be64 remote_ca_guid;
+@@ -177,7 +181,7 @@ static int cm_alloc_msg(struct cm_id_pri
+ if (IS_ERR(ah))
+ return PTR_ERR(ah);
+
+- m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
++ m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
+ cm_id_priv->av.pkey_index,
+ 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
+ GFP_ATOMIC);
+@@ -299,15 +303,17 @@ static int cm_init_av_by_path(struct ib_
+ static int cm_alloc_id(struct cm_id_private *cm_id_priv)
+ {
+ unsigned long flags;
+- int ret;
++ int ret, id;
+ static int next_id;
+
+ do {
+ spin_lock_irqsave(&cm.lock, flags);
+- ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++,
+- (__force int *) &cm_id_priv->id.local_id);
++ ret = idr_get_new_above(&cm.local_id_table, cm_id_priv,
++ next_id++, &id);
+ spin_unlock_irqrestore(&cm.lock, flags);
+ } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
++
++ cm_id_priv->id.local_id = (__force __be32) (id ^ cm.random_id_operand);
+ return ret;
+ }
+
+@@ -316,7 +322,8 @@ static void cm_free_id(__be32 local_id)
+ unsigned long flags;
+
+ spin_lock_irqsave(&cm.lock, flags);
+- idr_remove(&cm.local_id_table, (__force int) local_id);
++ idr_remove(&cm.local_id_table,
++ (__force int) (local_id ^ cm.random_id_operand));
+ spin_unlock_irqrestore(&cm.lock, flags);
+ }
+
+@@ -324,7 +331,8 @@ static struct cm_id_private * cm_get_id(
+ {
+ struct cm_id_private *cm_id_priv;
+
+- cm_id_priv = idr_find(&cm.local_id_table, (__force int) local_id);
++ cm_id_priv = idr_find(&cm.local_id_table,
++ (__force int) (local_id ^ cm.random_id_operand));
+ if (cm_id_priv) {
+ if (cm_id_priv->id.remote_id == remote_id)
+ atomic_inc(&cm_id_priv->refcount);
+@@ -641,13 +649,6 @@ static inline int cm_convert_to_ms(int i
+
+ static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
+ {
+- unsigned long flags;
+-
+- if (!timewait_info->inserted_remote_id &&
+- !timewait_info->inserted_remote_qp)
+- return;
+-
+- spin_lock_irqsave(&cm.lock, flags);
+ if (timewait_info->inserted_remote_id) {
+ rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table);
+ timewait_info->inserted_remote_id = 0;
+@@ -657,7 +658,6 @@ static void cm_cleanup_timewait(struct c
+ rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);
+ timewait_info->inserted_remote_qp = 0;
+ }
+- spin_unlock_irqrestore(&cm.lock, flags);
+ }
+
+ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
+@@ -678,6 +678,12 @@ static struct cm_timewait_info * cm_crea
+ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
+ {
+ int wait_time;
++ unsigned long flags;
++
++ spin_lock_irqsave(&cm.lock, flags);
++ cm_cleanup_timewait(cm_id_priv->timewait_info);
++ list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list);
++ spin_unlock_irqrestore(&cm.lock, flags);
+
+ /*
+ * The cm_id could be destroyed by the user before we exit timewait.
+@@ -693,9 +699,13 @@ static void cm_enter_timewait(struct cm_
+
+ static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
+ {
++ unsigned long flags;
++
+ cm_id_priv->id.state = IB_CM_IDLE;
+ if (cm_id_priv->timewait_info) {
++ spin_lock_irqsave(&cm.lock, flags);
+ cm_cleanup_timewait(cm_id_priv->timewait_info);
++ spin_unlock_irqrestore(&cm.lock, flags);
+ kfree(cm_id_priv->timewait_info);
+ cm_id_priv->timewait_info = NULL;
+ }
+@@ -1299,6 +1309,7 @@ static struct cm_id_private * cm_match_r
+ if (timewait_info) {
+ cur_cm_id_priv = cm_get_id(timewait_info->work.local_id,
+ timewait_info->work.remote_id);
++ cm_cleanup_timewait(cm_id_priv->timewait_info);
+ spin_unlock_irqrestore(&cm.lock, flags);
+ if (cur_cm_id_priv) {
+ cm_dup_req_handler(work, cur_cm_id_priv);
+@@ -1307,7 +1318,8 @@ static struct cm_id_private * cm_match_r
+ cm_issue_rej(work->port, work->mad_recv_wc,
+ IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
+ NULL, 0);
+- goto error;
++ listen_cm_id_priv = NULL;
++ goto out;
+ }
+
+ /* Find matching listen request. */
+@@ -1315,21 +1327,20 @@ static struct cm_id_private * cm_match_r
+ req_msg->service_id,
+ req_msg->private_data);
+ if (!listen_cm_id_priv) {
++ cm_cleanup_timewait(cm_id_priv->timewait_info);
+ spin_unlock_irqrestore(&cm.lock, flags);
+ cm_issue_rej(work->port, work->mad_recv_wc,
+ IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
+ NULL, 0);
+- goto error;
++ goto out;
+ }
+ atomic_inc(&listen_cm_id_priv->refcount);
+ atomic_inc(&cm_id_priv->refcount);
+ cm_id_priv->id.state = IB_CM_REQ_RCVD;
+ atomic_inc(&cm_id_priv->work_count);
+ spin_unlock_irqrestore(&cm.lock, flags);
++out:
+ return listen_cm_id_priv;
+-
+-error: cm_cleanup_timewait(cm_id_priv->timewait_info);
+- return NULL;
+ }
+
+ static int cm_req_handler(struct cm_work *work)
+@@ -1354,7 +1365,7 @@ static int cm_req_handler(struct cm_work
+ id.local_id);
+ if (IS_ERR(cm_id_priv->timewait_info)) {
+ ret = PTR_ERR(cm_id_priv->timewait_info);
+- goto error1;
++ goto destroy;
+ }
+ cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id;
+ cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid;
+@@ -1363,7 +1374,8 @@ static int cm_req_handler(struct cm_work
+ listen_cm_id_priv = cm_match_req(work, cm_id_priv);
+ if (!listen_cm_id_priv) {
+ ret = -EINVAL;
+- goto error2;
++ kfree(cm_id_priv->timewait_info);
++ goto destroy;
+ }
+
+ cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
+@@ -1373,12 +1385,22 @@ static int cm_req_handler(struct cm_work
+
+ cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
+ ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
+- if (ret)
+- goto error3;
++ if (ret) {
++ ib_get_cached_gid(work->port->cm_dev->device,
++ work->port->port_num, 0, &work->path[0].sgid);
++ ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
++ &work->path[0].sgid, sizeof work->path[0].sgid,
++ NULL, 0);
++ goto rejected;
++ }
+ if (req_msg->alt_local_lid) {
+ ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av);
+- if (ret)
+- goto error3;
++ if (ret) {
++ ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID,
++ &work->path[0].sgid,
++ sizeof work->path[0].sgid, NULL, 0);
++ goto rejected;
++ }
+ }
+ cm_id_priv->tid = req_msg->hdr.tid;
+ cm_id_priv->timeout_ms = cm_convert_to_ms(
+@@ -1400,12 +1422,11 @@ static int cm_req_handler(struct cm_work
+ cm_deref_id(listen_cm_id_priv);
+ return 0;
+
+-error3: atomic_dec(&cm_id_priv->refcount);
++rejected:
++ atomic_dec(&cm_id_priv->refcount);
+ cm_deref_id(listen_cm_id_priv);
+- cm_cleanup_timewait(cm_id_priv->timewait_info);
+-error2: kfree(cm_id_priv->timewait_info);
+- cm_id_priv->timewait_info = NULL;
+-error1: ib_destroy_cm_id(&cm_id_priv->id);
++destroy:
++ ib_destroy_cm_id(cm_id);
+ return ret;
+ }
+
+@@ -1881,6 +1902,32 @@ out: spin_unlock_irqrestore(&cm_id_priv-
+ }
+ EXPORT_SYMBOL(ib_send_cm_drep);
+
++static int cm_issue_drep(struct cm_port *port,
++ struct ib_mad_recv_wc *mad_recv_wc)
++{
++ struct ib_mad_send_buf *msg = NULL;
++ struct cm_dreq_msg *dreq_msg;
++ struct cm_drep_msg *drep_msg;
++ int ret;
++
++ ret = cm_alloc_response_msg(port, mad_recv_wc, &msg);
++ if (ret)
++ return ret;
++
++ dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad;
++ drep_msg = (struct cm_drep_msg *) msg->mad;
++
++ cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid);
++ drep_msg->remote_comm_id = dreq_msg->local_comm_id;
++ drep_msg->local_comm_id = dreq_msg->remote_comm_id;
++
++ ret = ib_post_send_mad(msg, NULL);
++ if (ret)
++ cm_free_msg(msg);
++
++ return ret;
++}
++
+ static int cm_dreq_handler(struct cm_work *work)
+ {
+ struct cm_id_private *cm_id_priv;
+@@ -1892,8 +1939,10 @@ static int cm_dreq_handler(struct cm_wor
+ dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad;
+ cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
+ dreq_msg->local_comm_id);
+- if (!cm_id_priv)
++ if (!cm_id_priv) {
++ cm_issue_drep(work->port, work->mad_recv_wc);
+ return -EINVAL;
++ }
+
+ work->cm_event.private_data = &dreq_msg->private_data;
+
+@@ -2072,8 +2121,9 @@ static struct cm_id_private * cm_acquire
+ spin_unlock_irqrestore(&cm.lock, flags);
+ return NULL;
+ }
+- cm_id_priv = idr_find(&cm.local_id_table,
+- (__force int) timewait_info->work.local_id);
++ cm_id_priv = idr_find(&cm.local_id_table, (__force int)
++ (timewait_info->work.local_id ^
++ cm.random_id_operand));
+ if (cm_id_priv) {
+ if (cm_id_priv->id.remote_id == remote_id)
+ atomic_inc(&cm_id_priv->refcount);
+@@ -2582,28 +2632,29 @@ static int cm_timewait_handler(struct cm
+ {
+ struct cm_timewait_info *timewait_info;
+ struct cm_id_private *cm_id_priv;
+- unsigned long flags;
+ int ret;
+
+ timewait_info = (struct cm_timewait_info *)work;
+- cm_cleanup_timewait(timewait_info);
++ spin_lock_irq(&cm.lock);
++ list_del(&timewait_info->list);
++ spin_unlock_irq(&cm.lock);
+
+ cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
+ timewait_info->work.remote_id);
+ if (!cm_id_priv)
+ return -EINVAL;
+
+- spin_lock_irqsave(&cm_id_priv->lock, flags);
++ spin_lock_irq(&cm_id_priv->lock);
+ if (cm_id_priv->id.state != IB_CM_TIMEWAIT ||
+ cm_id_priv->remote_qpn != timewait_info->remote_qpn) {
+- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ spin_unlock_irq(&cm_id_priv->lock);
+ goto out;
+ }
+ cm_id_priv->id.state = IB_CM_IDLE;
+ ret = atomic_inc_and_test(&cm_id_priv->work_count);
+ if (!ret)
+ list_add_tail(&work->list, &cm_id_priv->work_list);
+- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ spin_unlock_irq(&cm_id_priv->lock);
+
+ if (ret)
+ cm_process_work(cm_id_priv, work);
+@@ -3125,7 +3176,8 @@ static int cm_init_qp_init_attr(struct c
+ qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE;
+ if (cm_id_priv->responder_resources)
+- qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ;
++ qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ |
++ IB_ACCESS_REMOTE_ATOMIC;
+ qp_attr->pkey_index = cm_id_priv->av.pkey_index;
+ qp_attr->port_num = cm_id_priv->av.port->port_num;
+ ret = 0;
+@@ -3262,6 +3314,9 @@ static void cm_add_one(struct ib_device
+ int ret;
+ u8 i;
+
++ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
++ return;
++
+ cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
+ device->phys_port_cnt, GFP_KERNEL);
+ if (!cm_dev)
+@@ -3349,7 +3404,9 @@ static int __init ib_cm_init(void)
+ cm.remote_qp_table = RB_ROOT;
+ cm.remote_sidr_table = RB_ROOT;
+ idr_init(&cm.local_id_table);
++ get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand);
+ idr_pre_get(&cm.local_id_table, GFP_KERNEL);
++ INIT_LIST_HEAD(&cm.timewait_list);
+
+ cm.wq = create_workqueue("ib_cm");
+ if (!cm.wq)
+@@ -3367,7 +3424,20 @@ error:
+
+ static void __exit ib_cm_cleanup(void)
+ {
++ struct cm_timewait_info *timewait_info, *tmp;
++
++ spin_lock_irq(&cm.lock);
++ list_for_each_entry(timewait_info, &cm.timewait_list, list)
++ cancel_delayed_work(&timewait_info->work.work);
++ spin_unlock_irq(&cm.lock);
++
+ destroy_workqueue(cm.wq);
++
++ list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) {
++ list_del(&timewait_info->list);
++ kfree(timewait_info);
++ }
++
+ ib_unregister_client(&cm_client);
+ idr_destroy(&cm.local_id_table);
+ }
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index 5d625a8..845090b 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -35,6 +35,7 @@
+ #include <linux/mutex.h>
+ #include <linux/random.h>
+ #include <linux/idr.h>
++#include <linux/inetdevice.h>
+
+ #include <net/tcp.h>
+
+@@ -43,6 +44,7 @@
+ #include <rdma/ib_cache.h>
+ #include <rdma/ib_cm.h>
+ #include <rdma/ib_sa.h>
++#include <rdma/iw_cm.h>
+
+ MODULE_AUTHOR("Sean Hefty");
+ MODULE_DESCRIPTION("Generic RDMA CM Agent");
+@@ -60,6 +62,8 @@ static struct ib_client cma_client = {
+ .remove = cma_remove_one
+ };
+
++static struct ib_sa_client sa_client;
++static struct rdma_addr_client addr_client;
+ static LIST_HEAD(dev_list);
+ static LIST_HEAD(listen_any_list);
+ static DEFINE_MUTEX(lock);
+@@ -124,6 +128,7 @@ struct rdma_id_private {
+ int query_id;
+ union {
+ struct ib_cm_id *ib;
++ struct iw_cm_id *iw;
+ } cm_id;
+
+ u32 seq_num;
+@@ -259,15 +264,24 @@ static void cma_detach_from_dev(struct r
+ id_priv->cma_dev = NULL;
+ }
+
+-static int cma_acquire_ib_dev(struct rdma_id_private *id_priv)
++static int cma_acquire_dev(struct rdma_id_private *id_priv)
+ {
++ enum rdma_node_type dev_type = id_priv->id.route.addr.dev_addr.dev_type;
+ struct cma_device *cma_dev;
+ union ib_gid gid;
+ int ret = -ENODEV;
+
+- ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid),
++ switch (rdma_node_get_transport(dev_type)) {
++ case RDMA_TRANSPORT_IB:
++ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
++ break;
++ case RDMA_TRANSPORT_IWARP:
++ iw_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
++ break;
++ default:
++ return -ENODEV;
++ }
+
+- mutex_lock(&lock);
+ list_for_each_entry(cma_dev, &dev_list, list) {
+ ret = ib_find_cached_gid(cma_dev->device, &gid,
+ &id_priv->id.port_num, NULL);
+@@ -276,20 +290,9 @@ static int cma_acquire_ib_dev(struct rdm
+ break;
+ }
+ }
+- mutex_unlock(&lock);
+ return ret;
+ }
+
+-static int cma_acquire_dev(struct rdma_id_private *id_priv)
+-{
+- switch (id_priv->id.route.addr.dev_addr.dev_type) {
+- case IB_NODE_CA:
+- return cma_acquire_ib_dev(id_priv);
+- default:
+- return -ENODEV;
+- }
+-}
+-
+ static void cma_deref_id(struct rdma_id_private *id_priv)
+ {
+ if (atomic_dec_and_test(&id_priv->refcount))
+@@ -347,6 +350,16 @@ static int cma_init_ib_qp(struct rdma_id
+ IB_QP_PKEY_INDEX | IB_QP_PORT);
+ }
+
++static int cma_init_iw_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
++{
++ struct ib_qp_attr qp_attr;
++
++ qp_attr.qp_state = IB_QPS_INIT;
++ qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE;
++
++ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS);
++}
++
+ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
+ struct ib_qp_init_attr *qp_init_attr)
+ {
+@@ -362,10 +375,13 @@ int rdma_create_qp(struct rdma_cm_id *id
+ if (IS_ERR(qp))
+ return PTR_ERR(qp);
+
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ ret = cma_init_ib_qp(id_priv, qp);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = cma_init_iw_qp(id_priv, qp);
++ break;
+ default:
+ ret = -ENOSYS;
+ break;
+@@ -451,13 +467,17 @@ int rdma_init_qp_attr(struct rdma_cm_id
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+- switch (id_priv->id.device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
+ qp_attr_mask);
+ if (qp_attr->qp_state == IB_QPS_RTR)
+ qp_attr->rq_psn = id_priv->seq_num;
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
++ qp_attr_mask);
++ break;
+ default:
+ ret = -ENOSYS;
+ break;
+@@ -590,8 +610,8 @@ static int cma_notify_user(struct rdma_i
+
+ static void cma_cancel_route(struct rdma_id_private *id_priv)
+ {
+- switch (id_priv->id.device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ if (id_priv->query)
+ ib_sa_cancel_query(id_priv->query_id, id_priv->query);
+ break;
+@@ -611,11 +631,15 @@ static void cma_destroy_listen(struct rd
+ cma_exch(id_priv, CMA_DESTROYING);
+
+ if (id_priv->cma_dev) {
+- switch (id_priv->id.device->node_type) {
+- case IB_NODE_CA:
+- if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
++ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
++ case RDMA_TRANSPORT_IB:
++ if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
++ iw_destroy_cm_id(id_priv->cm_id.iw);
++ break;
+ default:
+ break;
+ }
+@@ -689,19 +713,25 @@ void rdma_destroy_id(struct rdma_cm_id *
+ state = cma_exch(id_priv, CMA_DESTROYING);
+ cma_cancel_operation(id_priv, state);
+
++ mutex_lock(&lock);
+ if (id_priv->cma_dev) {
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
+- if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
++ mutex_unlock(&lock);
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
++ if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
++ iw_destroy_cm_id(id_priv->cm_id.iw);
++ break;
+ default:
+ break;
+ }
+- mutex_lock(&lock);
++ mutex_lock(&lock);
+ cma_detach_from_dev(id_priv);
+- mutex_unlock(&lock);
+ }
++ mutex_unlock(&lock);
+
+ cma_release_port(id_priv);
+ cma_deref_id(id_priv);
+@@ -845,23 +875,25 @@ static struct rdma_id_private *cma_new_i
+ __u16 port;
+ u8 ip_ver;
+
++ if (cma_get_net_info(ib_event->private_data, listen_id->ps,
++ &ip_ver, &port, &src, &dst))
++ goto err;
++
+ id = rdma_create_id(listen_id->event_handler, listen_id->context,
+ listen_id->ps);
+ if (IS_ERR(id))
+- return NULL;
++ goto err;
++
++ cma_save_net_info(&id->route.addr, &listen_id->route.addr,
++ ip_ver, port, src, dst);
+
+ rt = &id->route;
+ rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
+- rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL);
++ rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths,
++ GFP_KERNEL);
+ if (!rt->path_rec)
+- goto err;
+-
+- if (cma_get_net_info(ib_event->private_data, listen_id->ps,
+- &ip_ver, &port, &src, &dst))
+- goto err;
++ goto destroy_id;
+
+- cma_save_net_info(&id->route.addr, &listen_id->route.addr,
+- ip_ver, port, src, dst);
+ rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path;
+ if (rt->num_paths == 2)
+ rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
+@@ -869,13 +901,15 @@ static struct rdma_id_private *cma_new_i
+ ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
+ ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
+ ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
+- rt->addr.dev_addr.dev_type = IB_NODE_CA;
++ rt->addr.dev_addr.dev_type = RDMA_NODE_IB_CA;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ id_priv->state = CMA_CONNECT;
+ return id_priv;
+-err:
++
++destroy_id:
+ rdma_destroy_id(id);
++err:
+ return NULL;
+ }
+
+@@ -898,9 +932,12 @@ static int cma_req_handler(struct ib_cm_
+ }
+
+ atomic_inc(&conn_id->dev_remove);
+- ret = cma_acquire_ib_dev(conn_id);
++ mutex_lock(&lock);
++ ret = cma_acquire_dev(conn_id);
++ mutex_unlock(&lock);
+ if (ret) {
+ ret = -ENODEV;
++ cma_exch(conn_id, CMA_DESTROYING);
+ cma_release_remove(conn_id);
+ rdma_destroy_id(&conn_id->id);
+ goto out;
+@@ -982,6 +1019,130 @@ static void cma_set_compare_data(enum rd
+ }
+ }
+
++static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
++{
++ struct rdma_id_private *id_priv = iw_id->context;
++ enum rdma_cm_event_type event = 0;
++ struct sockaddr_in *sin;
++ int ret = 0;
++
++ atomic_inc(&id_priv->dev_remove);
++
++ switch (iw_event->event) {
++ case IW_CM_EVENT_CLOSE:
++ event = RDMA_CM_EVENT_DISCONNECTED;
++ break;
++ case IW_CM_EVENT_CONNECT_REPLY:
++ sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
++ *sin = iw_event->local_addr;
++ sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
++ *sin = iw_event->remote_addr;
++ if (iw_event->status)
++ event = RDMA_CM_EVENT_REJECTED;
++ else
++ event = RDMA_CM_EVENT_ESTABLISHED;
++ break;
++ case IW_CM_EVENT_ESTABLISHED:
++ event = RDMA_CM_EVENT_ESTABLISHED;
++ break;
++ default:
++ BUG_ON(1);
++ }
++
++ ret = cma_notify_user(id_priv, event, iw_event->status,
++ iw_event->private_data,
++ iw_event->private_data_len);
++ if (ret) {
++ /* Destroy the CM ID by returning a non-zero value. */
++ id_priv->cm_id.iw = NULL;
++ cma_exch(id_priv, CMA_DESTROYING);
++ cma_release_remove(id_priv);
++ rdma_destroy_id(&id_priv->id);
++ return ret;
++ }
++
++ cma_release_remove(id_priv);
++ return ret;
++}
++
++static int iw_conn_req_handler(struct iw_cm_id *cm_id,
++ struct iw_cm_event *iw_event)
++{
++ struct rdma_cm_id *new_cm_id;
++ struct rdma_id_private *listen_id, *conn_id;
++ struct sockaddr_in *sin;
++ struct net_device *dev = NULL;
++ int ret;
++
++ listen_id = cm_id->context;
++ atomic_inc(&listen_id->dev_remove);
++ if (!cma_comp(listen_id, CMA_LISTEN)) {
++ ret = -ECONNABORTED;
++ goto out;
++ }
++
++ /* Create a new RDMA id for the new IW CM ID */
++ new_cm_id = rdma_create_id(listen_id->id.event_handler,
++ listen_id->id.context,
++ RDMA_PS_TCP);
++ if (!new_cm_id) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ conn_id = container_of(new_cm_id, struct rdma_id_private, id);
++ atomic_inc(&conn_id->dev_remove);
++ conn_id->state = CMA_CONNECT;
++
++ dev = ip_dev_find(iw_event->local_addr.sin_addr.s_addr);
++ if (!dev) {
++ ret = -EADDRNOTAVAIL;
++ cma_release_remove(conn_id);
++ rdma_destroy_id(new_cm_id);
++ goto out;
++ }
++ ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL);
++ if (ret) {
++ cma_release_remove(conn_id);
++ rdma_destroy_id(new_cm_id);
++ goto out;
++ }
++
++ mutex_lock(&lock);
++ ret = cma_acquire_dev(conn_id);
++ mutex_unlock(&lock);
++ if (ret) {
++ cma_release_remove(conn_id);
++ rdma_destroy_id(new_cm_id);
++ goto out;
++ }
++
++ conn_id->cm_id.iw = cm_id;
++ cm_id->context = conn_id;
++ cm_id->cm_handler = cma_iw_handler;
++
++ sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
++ *sin = iw_event->local_addr;
++ sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
++ *sin = iw_event->remote_addr;
++
++ ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0,
++ iw_event->private_data,
++ iw_event->private_data_len);
++ if (ret) {
++ /* User wants to destroy the CM ID */
++ conn_id->cm_id.iw = NULL;
++ cma_exch(conn_id, CMA_DESTROYING);
++ cma_release_remove(conn_id);
++ rdma_destroy_id(&conn_id->id);
++ }
++
++out:
++ if (dev)
++ dev_put(dev);
++ cma_release_remove(listen_id);
++ return ret;
++}
++
+ static int cma_ib_listen(struct rdma_id_private *id_priv)
+ {
+ struct ib_cm_compare_data compare_data;
+@@ -1011,6 +1172,30 @@ static int cma_ib_listen(struct rdma_id_
+ return ret;
+ }
+
++static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
++{
++ int ret;
++ struct sockaddr_in *sin;
++
++ id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device,
++ iw_conn_req_handler,
++ id_priv);
++ if (IS_ERR(id_priv->cm_id.iw))
++ return PTR_ERR(id_priv->cm_id.iw);
++
++ sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
++ id_priv->cm_id.iw->local_addr = *sin;
++
++ ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
++
++ if (ret) {
++ iw_destroy_cm_id(id_priv->cm_id.iw);
++ id_priv->cm_id.iw = NULL;
++ }
++
++ return ret;
++}
++
+ static int cma_listen_handler(struct rdma_cm_id *id,
+ struct rdma_cm_event *event)
+ {
+@@ -1087,12 +1272,17 @@ int rdma_listen(struct rdma_cm_id *id, i
+
+ id_priv->backlog = backlog;
+ if (id->device) {
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ ret = cma_ib_listen(id_priv);
+ if (ret)
+ goto err;
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = cma_iw_listen(id_priv, backlog);
++ if (ret)
++ goto err;
++ break;
+ default:
+ ret = -ENOSYS;
+ goto err;
+@@ -1123,6 +1313,7 @@ static void cma_query_handler(int status
+ work->old_state = CMA_ROUTE_QUERY;
+ work->new_state = CMA_ADDR_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
++ work->event.status = status;
+ }
+
+ queue_work(cma_wq, &work->work);
+@@ -1140,7 +1331,7 @@ static int cma_query_ib_route(struct rdm
+ path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
+ path_rec.numb_path = 1;
+
+- id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device,
++ id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
+ id_priv->id.port_num, &path_rec,
+ IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
+ IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH,
+@@ -1231,6 +1422,23 @@ err:
+ }
+ EXPORT_SYMBOL(rdma_set_ib_paths);
+
++static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
++{
++ struct cma_work *work;
++
++ work = kzalloc(sizeof *work, GFP_KERNEL);
++ if (!work)
++ return -ENOMEM;
++
++ work->id = id_priv;
++ INIT_WORK(&work->work, cma_work_handler, work);
++ work->old_state = CMA_ROUTE_QUERY;
++ work->new_state = CMA_ROUTE_RESOLVED;
++ work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
++ queue_work(cma_wq, &work->work);
++ return 0;
++}
++
+ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
+ {
+ struct rdma_id_private *id_priv;
+@@ -1241,10 +1449,13 @@ int rdma_resolve_route(struct rdma_cm_id
+ return -EINVAL;
+
+ atomic_inc(&id_priv->refcount);
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ ret = cma_resolve_ib_route(id_priv, timeout_ms);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = cma_resolve_iw_route(id_priv, timeout_ms);
++ break;
+ default:
+ ret = -ENOSYS;
+ break;
+@@ -1309,16 +1520,26 @@ static void addr_handler(int status, str
+ enum rdma_cm_event_type event;
+
+ atomic_inc(&id_priv->dev_remove);
+- if (!id_priv->cma_dev && !status)
++
++ /*
++ * Grab mutex to block rdma_destroy_id() from removing the device while
++ * we're trying to acquire it.
++ */
++ mutex_lock(&lock);
++ if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) {
++ mutex_unlock(&lock);
++ goto out;
++ }
++
++ if (!status && !id_priv->cma_dev)
+ status = cma_acquire_dev(id_priv);
++ mutex_unlock(&lock);
+
+ if (status) {
+- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND))
++ if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
+ goto out;
+ event = RDMA_CM_EVENT_ADDR_ERROR;
+ } else {
+- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
+- goto out;
+ memcpy(&id_priv->id.route.addr.src_addr, src_addr,
+ ip_addr_size(src_addr));
+ event = RDMA_CM_EVENT_ADDR_RESOLVED;
+@@ -1405,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id
+ if (cma_any_addr(dst_addr))
+ ret = cma_resolve_loopback(id_priv);
+ else
+- ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr,
+- &id->route.addr.dev_addr,
++ ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr,
++ dst_addr, &id->route.addr.dev_addr,
+ timeout_ms, addr_handler, id_priv);
+ if (ret)
+ goto err;
+@@ -1492,7 +1713,7 @@ static int cma_use_port(struct idr *ps,
+ hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
+ if (cma_any_addr(&cur_id->id.route.addr.src_addr))
+ return -EADDRNOTAVAIL;
+-
++
+ cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr;
+ if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr)
+ return -EADDRINUSE;
+@@ -1542,19 +1763,29 @@ int rdma_bind_addr(struct rdma_cm_id *id
+
+ if (!cma_any_addr(addr)) {
+ ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
+- if (!ret)
+- ret = cma_acquire_dev(id_priv);
+ if (ret)
+- goto err;
++ goto err1;
++
++ mutex_lock(&lock);
++ ret = cma_acquire_dev(id_priv);
++ mutex_unlock(&lock);
++ if (ret)
++ goto err1;
+ }
+
+ memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
+ ret = cma_get_port(id_priv);
+ if (ret)
+- goto err;
++ goto err2;
+
+ return 0;
+-err:
++err2:
++ if (!cma_any_addr(addr)) {
++ mutex_lock(&lock);
++ cma_detach_from_dev(id_priv);
++ mutex_unlock(&lock);
++ }
++err1:
+ cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
+ return ret;
+ }
+@@ -1645,10 +1876,58 @@ static int cma_connect_ib(struct rdma_id
+
+ ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
+ out:
++ if (ret && !IS_ERR(id_priv->cm_id.ib)) {
++ ib_destroy_cm_id(id_priv->cm_id.ib);
++ id_priv->cm_id.ib = NULL;
++ }
++
+ kfree(private_data);
+ return ret;
+ }
+
++static int cma_connect_iw(struct rdma_id_private *id_priv,
++ struct rdma_conn_param *conn_param)
++{
++ struct iw_cm_id *cm_id;
++ struct sockaddr_in* sin;
++ int ret;
++ struct iw_cm_conn_param iw_param;
++
++ cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv);
++ if (IS_ERR(cm_id)) {
++ ret = PTR_ERR(cm_id);
++ goto out;
++ }
++
++ id_priv->cm_id.iw = cm_id;
++
++ sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
++ cm_id->local_addr = *sin;
++
++ sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
++ cm_id->remote_addr = *sin;
++
++ ret = cma_modify_qp_rtr(&id_priv->id);
++ if (ret)
++ goto out;
++
++ iw_param.ord = conn_param->initiator_depth;
++ iw_param.ird = conn_param->responder_resources;
++ iw_param.private_data = conn_param->private_data;
++ iw_param.private_data_len = conn_param->private_data_len;
++ if (id_priv->id.qp)
++ iw_param.qpn = id_priv->qp_num;
++ else
++ iw_param.qpn = conn_param->qp_num;
++ ret = iw_cm_connect(cm_id, &iw_param);
++out:
++ if (ret && !IS_ERR(cm_id)) {
++ iw_destroy_cm_id(cm_id);
++ id_priv->cm_id.iw = NULL;
++ }
++ return ret;
++}
++
+ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+ {
+ struct rdma_id_private *id_priv;
+@@ -1664,10 +1943,13 @@ int rdma_connect(struct rdma_cm_id *id,
+ id_priv->srq = conn_param->srq;
+ }
+
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ ret = cma_connect_ib(id_priv, conn_param);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = cma_connect_iw(id_priv, conn_param);
++ break;
+ default:
+ ret = -ENOSYS;
+ break;
+@@ -1708,6 +1990,28 @@ static int cma_accept_ib(struct rdma_id_
+ return ib_send_cm_rep(id_priv->cm_id.ib, &rep);
+ }
+
++static int cma_accept_iw(struct rdma_id_private *id_priv,
++ struct rdma_conn_param *conn_param)
++{
++ struct iw_cm_conn_param iw_param;
++ int ret;
++
++ ret = cma_modify_qp_rtr(&id_priv->id);
++ if (ret)
++ return ret;
++
++ iw_param.ord = conn_param->initiator_depth;
++ iw_param.ird = conn_param->responder_resources;
++ iw_param.private_data = conn_param->private_data;
++ iw_param.private_data_len = conn_param->private_data_len;
++ if (id_priv->id.qp) {
++ iw_param.qpn = id_priv->qp_num;
++ } else
++ iw_param.qpn = conn_param->qp_num;
++
++ return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
++}
++
+ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+ {
+ struct rdma_id_private *id_priv;
+@@ -1723,13 +2027,16 @@ int rdma_accept(struct rdma_cm_id *id, s
+ id_priv->srq = conn_param->srq;
+ }
+
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ if (conn_param)
+ ret = cma_accept_ib(id_priv, conn_param);
+ else
+ ret = cma_rep_recv(id_priv);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = cma_accept_iw(id_priv, conn_param);
++ break;
+ default:
+ ret = -ENOSYS;
+ break;
+@@ -1756,12 +2063,16 @@ int rdma_reject(struct rdma_cm_id *id, c
+ if (!cma_comp(id_priv, CMA_CONNECT))
+ return -EINVAL;
+
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
+ ret = ib_send_cm_rej(id_priv->cm_id.ib,
+ IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
+ private_data, private_data_len);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = iw_cm_reject(id_priv->cm_id.iw,
++ private_data, private_data_len);
++ break;
+ default:
+ ret = -ENOSYS;
+ break;
+@@ -1780,17 +2091,20 @@ int rdma_disconnect(struct rdma_cm_id *i
+ !cma_comp(id_priv, CMA_DISCONNECT))
+ return -EINVAL;
+
+- ret = cma_modify_qp_err(id);
+- if (ret)
+- goto out;
+-
+- switch (id->device->node_type) {
+- case IB_NODE_CA:
++ switch (rdma_node_get_transport(id->device->node_type)) {
++ case RDMA_TRANSPORT_IB:
++ ret = cma_modify_qp_err(id);
++ if (ret)
++ goto out;
+ /* Initiate or respond to a disconnect. */
+ if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
+ ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
+ break;
++ case RDMA_TRANSPORT_IWARP:
++ ret = iw_cm_disconnect(id_priv->cm_id.iw, 0);
++ break;
+ default:
++ ret = -EINVAL;
+ break;
+ }
+ out:
+@@ -1849,12 +2163,9 @@ static int cma_remove_id_dev(struct rdma
+
+ static void cma_process_remove(struct cma_device *cma_dev)
+ {
+- struct list_head remove_list;
+ struct rdma_id_private *id_priv;
+ int ret;
+
+- INIT_LIST_HEAD(&remove_list);
+-
+ mutex_lock(&lock);
+ while (!list_empty(&cma_dev->id_list)) {
+ id_priv = list_entry(cma_dev->id_list.next,
+@@ -1865,8 +2176,7 @@ static void cma_process_remove(struct cm
+ continue;
+ }
+
+- list_del(&id_priv->list);
+- list_add_tail(&id_priv->list, &remove_list);
++ list_del_init(&id_priv->list);
+ atomic_inc(&id_priv->refcount);
+ mutex_unlock(&lock);
+
+@@ -1907,12 +2217,17 @@ static int cma_init(void)
+ if (!cma_wq)
+ return -ENOMEM;
+
++ ib_sa_register_client(&sa_client);
++ rdma_addr_register_client(&addr_client);
++
+ ret = ib_register_client(&cma_client);
+ if (ret)
+ goto err;
+ return 0;
+
+ err:
++ rdma_addr_unregister_client(&addr_client);
++ ib_sa_unregister_client(&sa_client);
+ destroy_workqueue(cma_wq);
+ return ret;
+ }
+@@ -1920,6 +2235,8 @@ err:
+ static void cma_cleanup(void)
+ {
+ ib_unregister_client(&cma_client);
++ rdma_addr_unregister_client(&addr_client);
++ ib_sa_unregister_client(&sa_client);
+ destroy_workqueue(cma_wq);
+ idr_destroy(&sdp_ps);
+ idr_destroy(&tcp_ps);
+diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
+index b2f3cb9..63d2a39 100644
+--- a/drivers/infiniband/core/device.c
++++ b/drivers/infiniband/core/device.c
+@@ -385,7 +385,7 @@ void *ib_get_client_data(struct ib_devic
+ EXPORT_SYMBOL(ib_get_client_data);
+
+ /**
+- * ib_set_client_data - Get IB client context
++ * ib_set_client_data - Set IB client context
+ * @device:Device to set context for
+ * @client:Client to set context for
+ * @data:Context to set
+@@ -505,7 +505,7 @@ int ib_query_port(struct ib_device *devi
+ u8 port_num,
+ struct ib_port_attr *port_attr)
+ {
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ if (port_num)
+ return -EINVAL;
+ } else if (port_num < 1 || port_num > device->phys_port_cnt)
+@@ -580,7 +580,7 @@ int ib_modify_port(struct ib_device *dev
+ u8 port_num, int port_modify_mask,
+ struct ib_port_modify *port_modify)
+ {
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ if (port_num)
+ return -EINVAL;
+ } else if (port_num < 1 || port_num > device->phys_port_cnt)
+diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
+new file mode 100644
+index 0000000..c3fb304
+--- /dev/null
++++ b/drivers/infiniband/core/iwcm.c
+@@ -0,0 +1,1019 @@
++/*
++ * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
++ * Copyright (c) 2004 Topspin Corporation. All rights reserved.
++ * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
++ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
++ * Copyright (c) 2005 Network Appliance, 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
++ * 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.
++ *
++ */
++#include <linux/dma-mapping.h>
++#include <linux/err.h>
++#include <linux/idr.h>
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/rbtree.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/completion.h>
++
++#include <rdma/iw_cm.h>
++#include <rdma/ib_addr.h>
++
++#include "iwcm.h"
++
++MODULE_AUTHOR("Tom Tucker");
++MODULE_DESCRIPTION("iWARP CM");
++MODULE_LICENSE("Dual BSD/GPL");
++
++static struct workqueue_struct *iwcm_wq;
++struct iwcm_work {
++ struct work_struct work;
++ struct iwcm_id_private *cm_id;
++ struct list_head list;
++ struct iw_cm_event event;
++ struct list_head free_list;
++};
++
++/*
++ * The following services provide a mechanism for pre-allocating iwcm_work
++ * elements. The design pre-allocates them based on the cm_id type:
++ * LISTENING IDS: Get enough elements preallocated to handle the
++ * listen backlog.
++ * ACTIVE IDS: 4: CONNECT_REPLY, ESTABLISHED, DISCONNECT, CLOSE
++ * PASSIVE IDS: 3: ESTABLISHED, DISCONNECT, CLOSE
++ *
++ * Allocating them in connect and listen avoids having to deal
++ * with allocation failures on the event upcall from the provider (which
++ * is called in the interrupt context).
++ *
++ * One exception is when creating the cm_id for incoming connection requests.
++ * There are two cases:
++ * 1) in the event upcall, cm_event_handler(), for a listening cm_id. If
++ * the backlog is exceeded, then no more connection request events will
++ * be processed. cm_event_handler() returns -ENOMEM in this case. Its up
++ * to the provider to reject the connectino request.
++ * 2) in the connection request workqueue handler, cm_conn_req_handler().
++ * If work elements cannot be allocated for the new connect request cm_id,
++ * then IWCM will call the provider reject method. This is ok since
++ * cm_conn_req_handler() runs in the workqueue thread context.
++ */
++
++static struct iwcm_work *get_work(struct iwcm_id_private *cm_id_priv)
++{
++ struct iwcm_work *work;
++
++ if (list_empty(&cm_id_priv->work_free_list))
++ return NULL;
++ work = list_entry(cm_id_priv->work_free_list.next, struct iwcm_work,
++ free_list);
++ list_del_init(&work->free_list);
++ return work;
++}
++
++static void put_work(struct iwcm_work *work)
++{
++ list_add(&work->free_list, &work->cm_id->work_free_list);
++}
++
++static void dealloc_work_entries(struct iwcm_id_private *cm_id_priv)
++{
++ struct list_head *e, *tmp;
++
++ list_for_each_safe(e, tmp, &cm_id_priv->work_free_list)
++ kfree(list_entry(e, struct iwcm_work, free_list));
++}
++
++static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count)
++{
++ struct iwcm_work *work;
++
++ BUG_ON(!list_empty(&cm_id_priv->work_free_list));
++ while (count--) {
++ work = kmalloc(sizeof(struct iwcm_work), GFP_KERNEL);
++ if (!work) {
++ dealloc_work_entries(cm_id_priv);
++ return -ENOMEM;
++ }
++ work->cm_id = cm_id_priv;
++ INIT_LIST_HEAD(&work->list);
++ put_work(work);
++ }
++ return 0;
++}
++
++/*
++ * Save private data from incoming connection requests in the
++ * cm_id_priv so the low level driver doesn't have to. Adjust
++ * the event ptr to point to the local copy.
++ */
++static int copy_private_data(struct iwcm_id_private *cm_id_priv,
++ struct iw_cm_event *event)
++{
++ void *p;
++
++ p = kmalloc(event->private_data_len, GFP_ATOMIC);
++ if (!p)
++ return -ENOMEM;
++ memcpy(p, event->private_data, event->private_data_len);
++ event->private_data = p;
++ return 0;
++}
++
++/*
++ * Release a reference on cm_id. If the last reference is being removed
++ * and iw_destroy_cm_id is waiting, wake up the waiting thread.
++ */
++static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
++{
++ int ret = 0;
++
++ BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
++ if (atomic_dec_and_test(&cm_id_priv->refcount)) {
++ BUG_ON(!list_empty(&cm_id_priv->work_list));
++ if (waitqueue_active(&cm_id_priv->destroy_comp.wait)) {
++ BUG_ON(cm_id_priv->state != IW_CM_STATE_DESTROYING);
++ BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY,
++ &cm_id_priv->flags));
++ ret = 1;
++ }
++ complete(&cm_id_priv->destroy_comp);
++ }
++
++ return ret;
++}
++
++static void add_ref(struct iw_cm_id *cm_id)
++{
++ struct iwcm_id_private *cm_id_priv;
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ atomic_inc(&cm_id_priv->refcount);
++}
++
++static void rem_ref(struct iw_cm_id *cm_id)
++{
++ struct iwcm_id_private *cm_id_priv;
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ iwcm_deref_id(cm_id_priv);
++}
++
++static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
++
++struct iw_cm_id *iw_create_cm_id(struct ib_device *device,
++ iw_cm_handler cm_handler,
++ void *context)
++{
++ struct iwcm_id_private *cm_id_priv;
++
++ cm_id_priv = kzalloc(sizeof(*cm_id_priv), GFP_KERNEL);
++ if (!cm_id_priv)
++ return ERR_PTR(-ENOMEM);
++
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ cm_id_priv->id.device = device;
++ cm_id_priv->id.cm_handler = cm_handler;
++ cm_id_priv->id.context = context;
++ cm_id_priv->id.event_handler = cm_event_handler;
++ cm_id_priv->id.add_ref = add_ref;
++ cm_id_priv->id.rem_ref = rem_ref;
++ spin_lock_init(&cm_id_priv->lock);
++ atomic_set(&cm_id_priv->refcount, 1);
++ init_waitqueue_head(&cm_id_priv->connect_wait);
++ init_completion(&cm_id_priv->destroy_comp);
++ INIT_LIST_HEAD(&cm_id_priv->work_list);
++ INIT_LIST_HEAD(&cm_id_priv->work_free_list);
++
++ return &cm_id_priv->id;
++}
++EXPORT_SYMBOL(iw_create_cm_id);
++
++
++static int iwcm_modify_qp_err(struct ib_qp *qp)
++{
++ struct ib_qp_attr qp_attr;
++
++ if (!qp)
++ return -EINVAL;
++
++ qp_attr.qp_state = IB_QPS_ERR;
++ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
++}
++
++/*
++ * This is really the RDMAC CLOSING state. It is most similar to the
++ * IB SQD QP state.
++ */
++static int iwcm_modify_qp_sqd(struct ib_qp *qp)
++{
++ struct ib_qp_attr qp_attr;
++
++ BUG_ON(qp == NULL);
++ qp_attr.qp_state = IB_QPS_SQD;
++ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
++}
++
++/*
++ * CM_ID <-- CLOSING
++ *
++ * Block if a passive or active connection is currenlty being processed. Then
++ * process the event as follows:
++ * - If we are ESTABLISHED, move to CLOSING and modify the QP state
++ * based on the abrupt flag
++ * - If the connection is already in the CLOSING or IDLE state, the peer is
++ * disconnecting concurrently with us and we've already seen the
++ * DISCONNECT event -- ignore the request and return 0
++ * - Disconnect on a listening endpoint returns -EINVAL
++ */
++int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt)
++{
++ struct iwcm_id_private *cm_id_priv;
++ unsigned long flags;
++ int ret = 0;
++ struct ib_qp *qp = NULL;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ /* Wait if we're currently in a connect or accept downcall */
++ wait_event(cm_id_priv->connect_wait,
++ !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ switch (cm_id_priv->state) {
++ case IW_CM_STATE_ESTABLISHED:
++ cm_id_priv->state = IW_CM_STATE_CLOSING;
++
++ /* QP could be <nul> for user-mode client */
++ if (cm_id_priv->qp)
++ qp = cm_id_priv->qp;
++ else
++ ret = -EINVAL;
++ break;
++ case IW_CM_STATE_LISTEN:
++ ret = -EINVAL;
++ break;
++ case IW_CM_STATE_CLOSING:
++ /* remote peer closed first */
++ case IW_CM_STATE_IDLE:
++ /* accept or connect returned !0 */
++ break;
++ case IW_CM_STATE_CONN_RECV:
++ /*
++ * App called disconnect before/without calling accept after
++ * connect_request event delivered.
++ */
++ break;
++ case IW_CM_STATE_CONN_SENT:
++ /* Can only get here if wait above fails */
++ default:
++ BUG();
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ if (qp) {
++ if (abrupt)
++ ret = iwcm_modify_qp_err(qp);
++ else
++ ret = iwcm_modify_qp_sqd(qp);
++
++ /*
++ * If both sides are disconnecting the QP could
++ * already be in ERR or SQD states
++ */
++ ret = 0;
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(iw_cm_disconnect);
++
++/*
++ * CM_ID <-- DESTROYING
++ *
++ * Clean up all resources associated with the connection and release
++ * the initial reference taken by iw_create_cm_id.
++ */
++static void destroy_cm_id(struct iw_cm_id *cm_id)
++{
++ struct iwcm_id_private *cm_id_priv;
++ unsigned long flags;
++ int ret;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ /*
++ * Wait if we're currently in a connect or accept downcall. A
++ * listening endpoint should never block here.
++ */
++ wait_event(cm_id_priv->connect_wait,
++ !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ switch (cm_id_priv->state) {
++ case IW_CM_STATE_LISTEN:
++ cm_id_priv->state = IW_CM_STATE_DESTROYING;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ /* destroy the listening endpoint */
++ ret = cm_id->device->iwcm->destroy_listen(cm_id);
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ break;
++ case IW_CM_STATE_ESTABLISHED:
++ cm_id_priv->state = IW_CM_STATE_DESTROYING;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ /* Abrupt close of the connection */
++ (void)iwcm_modify_qp_err(cm_id_priv->qp);
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ break;
++ case IW_CM_STATE_IDLE:
++ case IW_CM_STATE_CLOSING:
++ cm_id_priv->state = IW_CM_STATE_DESTROYING;
++ break;
++ case IW_CM_STATE_CONN_RECV:
++ /*
++ * App called destroy before/without calling accept after
++ * receiving connection request event notification.
++ */
++ cm_id_priv->state = IW_CM_STATE_DESTROYING;
++ break;
++ case IW_CM_STATE_CONN_SENT:
++ case IW_CM_STATE_DESTROYING:
++ default:
++ BUG();
++ break;
++ }
++ if (cm_id_priv->qp) {
++ cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp);
++ cm_id_priv->qp = NULL;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ (void)iwcm_deref_id(cm_id_priv);
++}
++
++/*
++ * This function is only called by the application thread and cannot
++ * be called by the event thread. The function will wait for all
++ * references to be released on the cm_id and then kfree the cm_id
++ * object.
++ */
++void iw_destroy_cm_id(struct iw_cm_id *cm_id)
++{
++ struct iwcm_id_private *cm_id_priv;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags));
++
++ destroy_cm_id(cm_id);
++
++ wait_for_completion(&cm_id_priv->destroy_comp);
++
++ dealloc_work_entries(cm_id_priv);
++
++ kfree(cm_id_priv);
++}
++EXPORT_SYMBOL(iw_destroy_cm_id);
++
++/*
++ * CM_ID <-- LISTEN
++ *
++ * Start listening for connect requests. Generates one CONNECT_REQUEST
++ * event for each inbound connect request.
++ */
++int iw_cm_listen(struct iw_cm_id *cm_id, int backlog)
++{
++ struct iwcm_id_private *cm_id_priv;
++ unsigned long flags;
++ int ret = 0;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++
++ ret = alloc_work_entries(cm_id_priv, backlog);
++ if (ret)
++ return ret;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ switch (cm_id_priv->state) {
++ case IW_CM_STATE_IDLE:
++ cm_id_priv->state = IW_CM_STATE_LISTEN;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ ret = cm_id->device->iwcm->create_listen(cm_id, backlog);
++ if (ret)
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(iw_cm_listen);
++
++/*
++ * CM_ID <-- IDLE
++ *
++ * Rejects an inbound connection request. No events are generated.
++ */
++int iw_cm_reject(struct iw_cm_id *cm_id,
++ const void *private_data,
++ u8 private_data_len)
++{
++ struct iwcm_id_private *cm_id_priv;
++ unsigned long flags;
++ int ret;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ if (cm_id_priv->state != IW_CM_STATE_CONN_RECV) {
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ wake_up_all(&cm_id_priv->connect_wait);
++ return -EINVAL;
++ }
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ ret = cm_id->device->iwcm->reject(cm_id, private_data,
++ private_data_len);
++
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ wake_up_all(&cm_id_priv->connect_wait);
++
++ return ret;
++}
++EXPORT_SYMBOL(iw_cm_reject);
++
++/*
++ * CM_ID <-- ESTABLISHED
++ *
++ * Accepts an inbound connection request and generates an ESTABLISHED
++ * event. Callers of iw_cm_disconnect and iw_destroy_cm_id will block
++ * until the ESTABLISHED event is received from the provider.
++ */
++int iw_cm_accept(struct iw_cm_id *cm_id,
++ struct iw_cm_conn_param *iw_param)
++{
++ struct iwcm_id_private *cm_id_priv;
++ struct ib_qp *qp;
++ unsigned long flags;
++ int ret;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ if (cm_id_priv->state != IW_CM_STATE_CONN_RECV) {
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ wake_up_all(&cm_id_priv->connect_wait);
++ return -EINVAL;
++ }
++ /* Get the ib_qp given the QPN */
++ qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
++ if (!qp) {
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ return -EINVAL;
++ }
++ cm_id->device->iwcm->add_ref(qp);
++ cm_id_priv->qp = qp;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ ret = cm_id->device->iwcm->accept(cm_id, iw_param);
++ if (ret) {
++ /* An error on accept precludes provider events */
++ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ if (cm_id_priv->qp) {
++ cm_id->device->iwcm->rem_ref(qp);
++ cm_id_priv->qp = NULL;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ wake_up_all(&cm_id_priv->connect_wait);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(iw_cm_accept);
++
++/*
++ * Active Side: CM_ID <-- CONN_SENT
++ *
++ * If successful, results in the generation of a CONNECT_REPLY
++ * event. iw_cm_disconnect and iw_cm_destroy will block until the
++ * CONNECT_REPLY event is received from the provider.
++ */
++int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
++{
++ struct iwcm_id_private *cm_id_priv;
++ int ret = 0;
++ unsigned long flags;
++ struct ib_qp *qp;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++
++ ret = alloc_work_entries(cm_id_priv, 4);
++ if (ret)
++ return ret;
++
++ set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++
++ if (cm_id_priv->state != IW_CM_STATE_IDLE) {
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ wake_up_all(&cm_id_priv->connect_wait);
++ return -EINVAL;
++ }
++
++ /* Get the ib_qp given the QPN */
++ qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
++ if (!qp) {
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ return -EINVAL;
++ }
++ cm_id->device->iwcm->add_ref(qp);
++ cm_id_priv->qp = qp;
++ cm_id_priv->state = IW_CM_STATE_CONN_SENT;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ ret = cm_id->device->iwcm->connect(cm_id, iw_param);
++ if (ret) {
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ if (cm_id_priv->qp) {
++ cm_id->device->iwcm->rem_ref(qp);
++ cm_id_priv->qp = NULL;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ wake_up_all(&cm_id_priv->connect_wait);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(iw_cm_connect);
++
++/*
++ * Passive Side: new CM_ID <-- CONN_RECV
++ *
++ * Handles an inbound connect request. The function creates a new
++ * iw_cm_id to represent the new connection and inherits the client
++ * callback function and other attributes from the listening parent.
++ *
++ * The work item contains a pointer to the listen_cm_id and the event. The
++ * listen_cm_id contains the client cm_handler, context and
++ * device. These are copied when the device is cloned. The event
++ * contains the new four tuple.
++ *
++ * An error on the child should not affect the parent, so this
++ * function does not return a value.
++ */
++static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
++ struct iw_cm_event *iw_event)
++{
++ unsigned long flags;
++ struct iw_cm_id *cm_id;
++ struct iwcm_id_private *cm_id_priv;
++ int ret;
++
++ /*
++ * The provider should never generate a connection request
++ * event with a bad status.
++ */
++ BUG_ON(iw_event->status);
++
++ /*
++ * We could be destroying the listening id. If so, ignore this
++ * upcall.
++ */
++ spin_lock_irqsave(&listen_id_priv->lock, flags);
++ if (listen_id_priv->state != IW_CM_STATE_LISTEN) {
++ spin_unlock_irqrestore(&listen_id_priv->lock, flags);
++ return;
++ }
++ spin_unlock_irqrestore(&listen_id_priv->lock, flags);
++
++ cm_id = iw_create_cm_id(listen_id_priv->id.device,
++ listen_id_priv->id.cm_handler,
++ listen_id_priv->id.context);
++ /* If the cm_id could not be created, ignore the request */
++ if (IS_ERR(cm_id))
++ return;
++
++ cm_id->provider_data = iw_event->provider_data;
++ cm_id->local_addr = iw_event->local_addr;
++ cm_id->remote_addr = iw_event->remote_addr;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ cm_id_priv->state = IW_CM_STATE_CONN_RECV;
++
++ ret = alloc_work_entries(cm_id_priv, 3);
++ if (ret) {
++ iw_cm_reject(cm_id, NULL, 0);
++ iw_destroy_cm_id(cm_id);
++ return;
++ }
++
++ /* Call the client CM handler */
++ ret = cm_id->cm_handler(cm_id, iw_event);
++ if (ret) {
++ set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
++ destroy_cm_id(cm_id);
++ if (atomic_read(&cm_id_priv->refcount)==0)
++ kfree(cm_id);
++ }
++
++ if (iw_event->private_data_len)
++ kfree(iw_event->private_data);
++}
++
++/*
++ * Passive Side: CM_ID <-- ESTABLISHED
++ *
++ * The provider generated an ESTABLISHED event which means that
++ * the MPA negotion has completed successfully and we are now in MPA
++ * FPDU mode.
++ *
++ * This event can only be received in the CONN_RECV state. If the
++ * remote peer closed, the ESTABLISHED event would be received followed
++ * by the CLOSE event. If the app closes, it will block until we wake
++ * it up after processing this event.
++ */
++static int cm_conn_est_handler(struct iwcm_id_private *cm_id_priv,
++ struct iw_cm_event *iw_event)
++{
++ unsigned long flags;
++ int ret = 0;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++
++ /*
++ * We clear the CONNECT_WAIT bit here to allow the callback
++ * function to call iw_cm_disconnect. Calling iw_destroy_cm_id
++ * from a callback handler is not allowed.
++ */
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
++ cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
++ wake_up_all(&cm_id_priv->connect_wait);
++
++ return ret;
++}
++
++/*
++ * Active Side: CM_ID <-- ESTABLISHED
++ *
++ * The app has called connect and is waiting for the established event to
++ * post it's requests to the server. This event will wake up anyone
++ * blocked in iw_cm_disconnect or iw_destroy_id.
++ */
++static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
++ struct iw_cm_event *iw_event)
++{
++ unsigned long flags;
++ int ret = 0;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ /*
++ * Clear the connect wait bit so a callback function calling
++ * iw_cm_disconnect will not wait and deadlock this thread
++ */
++ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
++ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
++ if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) {
++ cm_id_priv->id.local_addr = iw_event->local_addr;
++ cm_id_priv->id.remote_addr = iw_event->remote_addr;
++ cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
++ } else {
++ /* REJECTED or RESET */
++ cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp);
++ cm_id_priv->qp = NULL;
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
++
++ if (iw_event->private_data_len)
++ kfree(iw_event->private_data);
++
++ /* Wake up waiters on connect complete */
++ wake_up_all(&cm_id_priv->connect_wait);
++
++ return ret;
++}
++
++/*
++ * CM_ID <-- CLOSING
++ *
++ * If in the ESTABLISHED state, move to CLOSING.
++ */
++static void cm_disconnect_handler(struct iwcm_id_private *cm_id_priv,
++ struct iw_cm_event *iw_event)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ if (cm_id_priv->state == IW_CM_STATE_ESTABLISHED)
++ cm_id_priv->state = IW_CM_STATE_CLOSING;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++}
++
++/*
++ * CM_ID <-- IDLE
++ *
++ * If in the ESTBLISHED or CLOSING states, the QP will have have been
++ * moved by the provider to the ERR state. Disassociate the CM_ID from
++ * the QP, move to IDLE, and remove the 'connected' reference.
++ *
++ * If in some other state, the cm_id was destroyed asynchronously.
++ * This is the last reference that will result in waking up
++ * the app thread blocked in iw_destroy_cm_id.
++ */
++static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
++ struct iw_cm_event *iw_event)
++{
++ unsigned long flags;
++ int ret = 0;
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++
++ if (cm_id_priv->qp) {
++ cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp);
++ cm_id_priv->qp = NULL;
++ }
++ switch (cm_id_priv->state) {
++ case IW_CM_STATE_ESTABLISHED:
++ case IW_CM_STATE_CLOSING:
++ cm_id_priv->state = IW_CM_STATE_IDLE;
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ break;
++ case IW_CM_STATE_DESTROYING:
++ break;
++ default:
++ BUG();
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ return ret;
++}
++
++static int process_event(struct iwcm_id_private *cm_id_priv,
++ struct iw_cm_event *iw_event)
++{
++ int ret = 0;
++
++ switch (iw_event->event) {
++ case IW_CM_EVENT_CONNECT_REQUEST:
++ cm_conn_req_handler(cm_id_priv, iw_event);
++ break;
++ case IW_CM_EVENT_CONNECT_REPLY:
++ ret = cm_conn_rep_handler(cm_id_priv, iw_event);
++ break;
++ case IW_CM_EVENT_ESTABLISHED:
++ ret = cm_conn_est_handler(cm_id_priv, iw_event);
++ break;
++ case IW_CM_EVENT_DISCONNECT:
++ cm_disconnect_handler(cm_id_priv, iw_event);
++ break;
++ case IW_CM_EVENT_CLOSE:
++ ret = cm_close_handler(cm_id_priv, iw_event);
++ break;
++ default:
++ BUG();
++ }
++
++ return ret;
++}
++
++/*
++ * Process events on the work_list for the cm_id. If the callback
++ * function requests that the cm_id be deleted, a flag is set in the
++ * cm_id flags to indicate that when the last reference is
++ * removed, the cm_id is to be destroyed. This is necessary to
++ * distinguish between an object that will be destroyed by the app
++ * thread asleep on the destroy_comp list vs. an object destroyed
++ * here synchronously when the last reference is removed.
++ */
++static void cm_work_handler(void *arg)
++{
++ struct iwcm_work *work = arg, lwork;
++ struct iwcm_id_private *cm_id_priv = work->cm_id;
++ unsigned long flags;
++ int empty;
++ int ret = 0;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ empty = list_empty(&cm_id_priv->work_list);
++ while (!empty) {
++ work = list_entry(cm_id_priv->work_list.next,
++ struct iwcm_work, list);
++ list_del_init(&work->list);
++ empty = list_empty(&cm_id_priv->work_list);
++ lwork = *work;
++ put_work(work);
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++
++ ret = process_event(cm_id_priv, &work->event);
++ if (ret) {
++ set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
++ destroy_cm_id(&cm_id_priv->id);
++ }
++ BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
++ if (iwcm_deref_id(cm_id_priv))
++ return;
++
++ if (atomic_read(&cm_id_priv->refcount)==0 &&
++ test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) {
++ dealloc_work_entries(cm_id_priv);
++ kfree(cm_id_priv);
++ return;
++ }
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++}
++
++/*
++ * This function is called on interrupt context. Schedule events on
++ * the iwcm_wq thread to allow callback functions to downcall into
++ * the CM and/or block. Events are queued to a per-CM_ID
++ * work_list. If this is the first event on the work_list, the work
++ * element is also queued on the iwcm_wq thread.
++ *
++ * Each event holds a reference on the cm_id. Until the last posted
++ * event has been delivered and processed, the cm_id cannot be
++ * deleted.
++ *
++ * Returns:
++ * 0 - the event was handled.
++ * -ENOMEM - the event was not handled due to lack of resources.
++ */
++static int cm_event_handler(struct iw_cm_id *cm_id,
++ struct iw_cm_event *iw_event)
++{
++ struct iwcm_work *work;
++ struct iwcm_id_private *cm_id_priv;
++ unsigned long flags;
++ int ret = 0;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ work = get_work(cm_id_priv);
++ if (!work) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ INIT_WORK(&work->work, cm_work_handler, work);
++ work->cm_id = cm_id_priv;
++ work->event = *iw_event;
++
++ if ((work->event.event == IW_CM_EVENT_CONNECT_REQUEST ||
++ work->event.event == IW_CM_EVENT_CONNECT_REPLY) &&
++ work->event.private_data_len) {
++ ret = copy_private_data(cm_id_priv, &work->event);
++ if (ret) {
++ put_work(work);
++ goto out;
++ }
++ }
++
++ atomic_inc(&cm_id_priv->refcount);
++ if (list_empty(&cm_id_priv->work_list)) {
++ list_add_tail(&work->list, &cm_id_priv->work_list);
++ queue_work(iwcm_wq, &work->work);
++ } else
++ list_add_tail(&work->list, &cm_id_priv->work_list);
++out:
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ return ret;
++}
++
++static int iwcm_init_qp_init_attr(struct iwcm_id_private *cm_id_priv,
++ struct ib_qp_attr *qp_attr,
++ int *qp_attr_mask)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ switch (cm_id_priv->state) {
++ case IW_CM_STATE_IDLE:
++ case IW_CM_STATE_CONN_SENT:
++ case IW_CM_STATE_CONN_RECV:
++ case IW_CM_STATE_ESTABLISHED:
++ *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
++ qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
++ IB_ACCESS_REMOTE_WRITE|
++ IB_ACCESS_REMOTE_READ;
++ ret = 0;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ return ret;
++}
++
++static int iwcm_init_qp_rts_attr(struct iwcm_id_private *cm_id_priv,
++ struct ib_qp_attr *qp_attr,
++ int *qp_attr_mask)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&cm_id_priv->lock, flags);
++ switch (cm_id_priv->state) {
++ case IW_CM_STATE_IDLE:
++ case IW_CM_STATE_CONN_SENT:
++ case IW_CM_STATE_CONN_RECV:
++ case IW_CM_STATE_ESTABLISHED:
++ *qp_attr_mask = 0;
++ ret = 0;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
++ return ret;
++}
++
++int iw_cm_init_qp_attr(struct iw_cm_id *cm_id,
++ struct ib_qp_attr *qp_attr,
++ int *qp_attr_mask)
++{
++ struct iwcm_id_private *cm_id_priv;
++ int ret;
++
++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
++ switch (qp_attr->qp_state) {
++ case IB_QPS_INIT:
++ case IB_QPS_RTR:
++ ret = iwcm_init_qp_init_attr(cm_id_priv,
++ qp_attr, qp_attr_mask);
++ break;
++ case IB_QPS_RTS:
++ ret = iwcm_init_qp_rts_attr(cm_id_priv,
++ qp_attr, qp_attr_mask);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++EXPORT_SYMBOL(iw_cm_init_qp_attr);
++
++static int __init iw_cm_init(void)
++{
++ iwcm_wq = create_singlethread_workqueue("iw_cm_wq");
++ if (!iwcm_wq)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void __exit iw_cm_cleanup(void)
++{
++ destroy_workqueue(iwcm_wq);
++}
++
++module_init(iw_cm_init);
++module_exit(iw_cm_cleanup);
+diff --git a/drivers/infiniband/core/iwcm.h b/drivers/infiniband/core/iwcm.h
+new file mode 100644
+index 0000000..3f6cc82
+--- /dev/null
++++ b/drivers/infiniband/core/iwcm.h
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (c) 2005 Network Appliance, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 IWCM_H
++#define IWCM_H
++
++enum iw_cm_state {
++ IW_CM_STATE_IDLE, /* unbound, inactive */
++ IW_CM_STATE_LISTEN, /* listen waiting for connect */
++ IW_CM_STATE_CONN_RECV, /* inbound waiting for user accept */
++ IW_CM_STATE_CONN_SENT, /* outbound waiting for peer accept */
++ IW_CM_STATE_ESTABLISHED, /* established */
++ IW_CM_STATE_CLOSING, /* disconnect */
++ IW_CM_STATE_DESTROYING /* object being deleted */
++};
++
++struct iwcm_id_private {
++ struct iw_cm_id id;
++ enum iw_cm_state state;
++ unsigned long flags;
++ struct ib_qp *qp;
++ struct completion destroy_comp;
++ wait_queue_head_t connect_wait;
++ struct list_head work_list;
++ spinlock_t lock;
++ atomic_t refcount;
++ struct list_head work_free_list;
++};
++
++#define IWCM_F_CALLBACK_DESTROY 1
++#define IWCM_F_CONNECT_WAIT 2
++
++#endif /* IWCM_H */
+diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
+index 1c3cfbb..493f4c6 100644
+--- a/drivers/infiniband/core/mad.c
++++ b/drivers/infiniband/core/mad.c
+@@ -1246,8 +1246,8 @@ static int find_vendor_oui(struct ib_mad
+ int i;
+
+ for (i = 0; i < MAX_MGMT_OUI; i++)
+- /* Is there matching OUI for this vendor class ? */
+- if (!memcmp(vendor_class->oui[i], oui, 3))
++ /* Is there matching OUI for this vendor class ? */
++ if (!memcmp(vendor_class->oui[i], oui, 3))
+ return i;
+
+ return -1;
+@@ -2237,7 +2237,7 @@ static void cancel_mads(struct ib_mad_ag
+ list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr,
+ &mad_agent_priv->send_list, agent_list) {
+ if (mad_send_wr->status == IB_WC_SUCCESS) {
+- mad_send_wr->status = IB_WC_WR_FLUSH_ERR;
++ mad_send_wr->status = IB_WC_WR_FLUSH_ERR;
+ mad_send_wr->refcount -= (mad_send_wr->timeout > 0);
+ }
+ }
+@@ -2528,10 +2528,10 @@ static int ib_mad_post_receive_mads(stru
+ }
+ }
+ sg_list.addr = dma_map_single(qp_info->port_priv->
+- device->dma_device,
++ device->dma_device,
+ &mad_priv->grh,
+ sizeof *mad_priv -
+- sizeof mad_priv->header,
++ sizeof mad_priv->header,
+ DMA_FROM_DEVICE);
+ pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr);
+ recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
+@@ -2606,7 +2606,7 @@ static int ib_mad_port_start(struct ib_m
+ struct ib_qp *qp;
+
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+- if (!attr) {
++ if (!attr) {
+ printk(KERN_ERR PFX "Couldn't kmalloc ib_qp_attr\n");
+ return -ENOMEM;
+ }
+@@ -2876,7 +2876,10 @@ static void ib_mad_init_device(struct ib
+ {
+ int start, end, i;
+
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
++ return;
++
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ start = 0;
+ end = 0;
+ } else {
+@@ -2923,7 +2926,7 @@ static void ib_mad_remove_device(struct
+ {
+ int i, num_ports, cur_port;
+
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ num_ports = 1;
+ cur_port = 0;
+ } else {
+@@ -2984,10 +2987,7 @@ error1:
+ static void __exit ib_mad_cleanup_module(void)
+ {
+ ib_unregister_client(&mad_client);
+-
+- if (kmem_cache_destroy(ib_mad_cache)) {
+- printk(KERN_DEBUG PFX "Failed to destroy ib_mad cache\n");
+- }
++ kmem_cache_destroy(ib_mad_cache);
+ }
+
+ module_init(ib_mad_init_module);
+diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
+index d147f3b..d06b590 100644
+--- a/drivers/infiniband/core/mad_priv.h
++++ b/drivers/infiniband/core/mad_priv.h
+@@ -38,8 +38,8 @@
+ #define __IB_MAD_PRIV_H__
+
+ #include <linux/completion.h>
++#include <linux/err.h>
+ #include <linux/pci.h>
+-#include <linux/kthread.h>
+ #include <linux/workqueue.h>
+ #include <rdma/ib_mad.h>
+ #include <rdma/ib_smi.h>
+diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
+index ebcd5b1..1ef79d0 100644
+--- a/drivers/infiniband/core/mad_rmpp.c
++++ b/drivers/infiniband/core/mad_rmpp.c
+@@ -33,8 +33,6 @@
+ * $Id: mad_rmpp.c 1921 2005-03-02 22:58:44Z sean.hefty $
+ */
+
+-#include <linux/dma-mapping.h>
+-
+ #include "mad_priv.h"
+ #include "mad_rmpp.h"
+
+@@ -60,6 +58,7 @@ struct mad_rmpp_recv {
+ int last_ack;
+ int seg_num;
+ int newwin;
++ int repwin;
+
+ __be64 tid;
+ u32 src_qp;
+@@ -170,6 +169,32 @@ static struct ib_mad_send_buf *alloc_res
+ return msg;
+ }
+
++static void ack_ds_ack(struct ib_mad_agent_private *agent,
++ struct ib_mad_recv_wc *recv_wc)
++{
++ struct ib_mad_send_buf *msg;
++ struct ib_rmpp_mad *rmpp_mad;
++ int ret;
++
++ msg = alloc_response_msg(&agent->agent, recv_wc);
++ if (IS_ERR(msg))
++ return;
++
++ rmpp_mad = msg->mad;
++ memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
++
++ rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
++ ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
++ rmpp_mad->rmpp_hdr.seg_num = 0;
++ rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(1);
++
++ ret = ib_post_send_mad(msg, NULL);
++ if (ret) {
++ ib_destroy_ah(msg->ah);
++ ib_free_send_mad(msg);
++ }
++}
++
+ void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)
+ {
+ struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad;
+@@ -271,6 +296,7 @@ create_rmpp_recv(struct ib_mad_agent_pri
+ rmpp_recv->newwin = 1;
+ rmpp_recv->seg_num = 1;
+ rmpp_recv->last_ack = 0;
++ rmpp_recv->repwin = 1;
+
+ mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
+ rmpp_recv->tid = mad_hdr->tid;
+@@ -365,7 +391,7 @@ static inline int window_size(struct ib_
+ static struct ib_mad_recv_buf * find_seg_location(struct list_head *rmpp_list,
+ int seg_num)
+ {
+- struct ib_mad_recv_buf *seg_buf;
++ struct ib_mad_recv_buf *seg_buf;
+ int cur_seg_num;
+
+ list_for_each_entry_reverse(seg_buf, rmpp_list, list) {
+@@ -591,6 +617,16 @@ static inline void adjust_last_ack(struc
+ break;
+ }
+
++static void process_ds_ack(struct ib_mad_agent_private *agent,
++ struct ib_mad_recv_wc *mad_recv_wc, int newwin)
++{
++ struct mad_rmpp_recv *rmpp_recv;
++
++ rmpp_recv = find_rmpp_recv(agent, mad_recv_wc);
++ if (rmpp_recv && rmpp_recv->state == RMPP_STATE_COMPLETE)
++ rmpp_recv->repwin = newwin;
++}
++
+ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
+ struct ib_mad_recv_wc *mad_recv_wc)
+ {
+@@ -616,8 +652,18 @@ static void process_rmpp_ack(struct ib_m
+
+ spin_lock_irqsave(&agent->lock, flags);
+ mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
+- if (!mad_send_wr)
+- goto out; /* Unmatched ACK */
++ if (!mad_send_wr) {
++ if (!seg_num)
++ process_ds_ack(agent, mad_recv_wc, newwin);
++ goto out; /* Unmatched or DS RMPP ACK */
++ }
++
++ if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) &&
++ (mad_send_wr->timeout)) {
++ spin_unlock_irqrestore(&agent->lock, flags);
++ ack_ds_ack(agent, mad_recv_wc);
++ return; /* Repeated ACK for DS RMPP transaction */
++ }
+
+ if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
+ (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
+@@ -656,6 +702,9 @@ static void process_rmpp_ack(struct ib_m
+ if (mad_send_wr->refcount == 1)
+ ib_reset_mad_timeout(mad_send_wr,
+ mad_send_wr->send_buf.timeout_ms);
++ spin_unlock_irqrestore(&agent->lock, flags);
++ ack_ds_ack(agent, mad_recv_wc);
++ return;
+ } else if (mad_send_wr->refcount == 1 &&
+ mad_send_wr->seg_num < mad_send_wr->newwin &&
+ mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {
+@@ -772,6 +821,39 @@ out:
+ return NULL;
+ }
+
++static int init_newwin(struct ib_mad_send_wr_private *mad_send_wr)
++{
++ struct ib_mad_agent_private *agent = mad_send_wr->mad_agent_priv;
++ struct ib_mad_hdr *mad_hdr = mad_send_wr->send_buf.mad;
++ struct mad_rmpp_recv *rmpp_recv;
++ struct ib_ah_attr ah_attr;
++ unsigned long flags;
++ int newwin = 1;
++
++ if (!(mad_hdr->method & IB_MGMT_METHOD_RESP))
++ goto out;
++
++ spin_lock_irqsave(&agent->lock, flags);
++ list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {
++ if (rmpp_recv->tid != mad_hdr->tid ||
++ rmpp_recv->mgmt_class != mad_hdr->mgmt_class ||
++ rmpp_recv->class_version != mad_hdr->class_version ||
++ (rmpp_recv->method & IB_MGMT_METHOD_RESP))
++ continue;
++
++ if (ib_query_ah(mad_send_wr->send_buf.ah, &ah_attr))
++ continue;
++
++ if (rmpp_recv->slid == ah_attr.dlid) {
++ newwin = rmpp_recv->repwin;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&agent->lock, flags);
++out:
++ return newwin;
++}
++
+ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
+ {
+ struct ib_rmpp_mad *rmpp_mad;
+@@ -787,7 +869,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_
+ return IB_RMPP_RESULT_INTERNAL;
+ }
+
+- mad_send_wr->newwin = 1;
++ mad_send_wr->newwin = init_newwin(mad_send_wr);
+
+ /* We need to wait for the final ACK even if there isn't a response */
+ mad_send_wr->refcount += (mad_send_wr->timeout == 0);
+diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
+index d6b8422..1706d3c 100644
+--- a/drivers/infiniband/core/sa_query.c
++++ b/drivers/infiniband/core/sa_query.c
+@@ -1,6 +1,7 @@
+ /*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
++ * Copyright (c) 2006 Intel Corporation. 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
+@@ -75,6 +76,7 @@ struct ib_sa_device {
+ struct ib_sa_query {
+ void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *);
+ void (*release)(struct ib_sa_query *);
++ struct ib_sa_client *client;
+ struct ib_sa_port *port;
+ struct ib_mad_send_buf *mad_buf;
+ struct ib_sa_sm_ah *sm_ah;
+@@ -415,6 +417,31 @@ static void ib_sa_event(struct ib_event_
+ }
+ }
+
++void ib_sa_register_client(struct ib_sa_client *client)
++{
++ atomic_set(&client->users, 1);
++ init_completion(&client->comp);
++}
++EXPORT_SYMBOL(ib_sa_register_client);
++
++static inline void ib_sa_client_get(struct ib_sa_client *client)
++{
++ atomic_inc(&client->users);
++}
++
++static inline void ib_sa_client_put(struct ib_sa_client *client)
++{
++ if (atomic_dec_and_test(&client->users))
++ complete(&client->comp);
++}
++
++void ib_sa_unregister_client(struct ib_sa_client *client)
++{
++ ib_sa_client_put(client);
++ wait_for_completion(&client->comp);
++}
++EXPORT_SYMBOL(ib_sa_unregister_client);
++
+ /**
+ * ib_sa_cancel_query - try to cancel an SA query
+ * @id:ID of query to cancel
+@@ -557,6 +584,7 @@ static void ib_sa_path_rec_release(struc
+
+ /**
+ * ib_sa_path_rec_get - Start a Path get query
++ * @client:SA client
+ * @device:device to send query on
+ * @port_num: port number to send query on
+ * @rec:Path Record to send in query
+@@ -579,7 +607,8 @@ static void ib_sa_path_rec_release(struc
+ * error code. Otherwise it is a query ID that can be used to cancel
+ * the query.
+ */
+-int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
++int ib_sa_path_rec_get(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ struct ib_sa_path_rec *rec,
+ ib_sa_comp_mask comp_mask,
+ int timeout_ms, gfp_t gfp_mask,
+@@ -614,8 +643,10 @@ int ib_sa_path_rec_get(struct ib_device
+ goto err1;
+ }
+
+- query->callback = callback;
+- query->context = context;
++ ib_sa_client_get(client);
++ query->sa_query.client = client;
++ query->callback = callback;
++ query->context = context;
+
+ mad = query->sa_query.mad_buf->mad;
+ init_mad(mad, agent);
+@@ -639,6 +670,7 @@ int ib_sa_path_rec_get(struct ib_device
+
+ err2:
+ *sa_query = NULL;
++ ib_sa_client_put(query->sa_query.client);
+ ib_free_send_mad(query->sa_query.mad_buf);
+
+ err1:
+@@ -671,6 +703,7 @@ static void ib_sa_service_rec_release(st
+
+ /**
+ * ib_sa_service_rec_query - Start Service Record operation
++ * @client:SA client
+ * @device:device to send request on
+ * @port_num: port number to send request on
+ * @method:SA method - should be get, set, or delete
+@@ -695,7 +728,8 @@ static void ib_sa_service_rec_release(st
+ * error code. Otherwise it is a request ID that can be used to cancel
+ * the query.
+ */
+-int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
++int ib_sa_service_rec_query(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num, u8 method,
+ struct ib_sa_service_rec *rec,
+ ib_sa_comp_mask comp_mask,
+ int timeout_ms, gfp_t gfp_mask,
+@@ -735,8 +769,10 @@ int ib_sa_service_rec_query(struct ib_de
+ goto err1;
+ }
+
+- query->callback = callback;
+- query->context = context;
++ ib_sa_client_get(client);
++ query->sa_query.client = client;
++ query->callback = callback;
++ query->context = context;
+
+ mad = query->sa_query.mad_buf->mad;
+ init_mad(mad, agent);
+@@ -761,6 +797,7 @@ int ib_sa_service_rec_query(struct ib_de
+
+ err2:
+ *sa_query = NULL;
++ ib_sa_client_put(query->sa_query.client);
+ ib_free_send_mad(query->sa_query.mad_buf);
+
+ err1:
+@@ -791,7 +828,8 @@ static void ib_sa_mcmember_rec_release(s
+ kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query));
+ }
+
+-int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
++int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ u8 method,
+ struct ib_sa_mcmember_rec *rec,
+ ib_sa_comp_mask comp_mask,
+@@ -827,8 +865,10 @@ int ib_sa_mcmember_rec_query(struct ib_d
+ goto err1;
+ }
+
+- query->callback = callback;
+- query->context = context;
++ ib_sa_client_get(client);
++ query->sa_query.client = client;
++ query->callback = callback;
++ query->context = context;
+
+ mad = query->sa_query.mad_buf->mad;
+ init_mad(mad, agent);
+@@ -853,6 +893,7 @@ int ib_sa_mcmember_rec_query(struct ib_d
+
+ err2:
+ *sa_query = NULL;
++ ib_sa_client_put(query->sa_query.client);
+ ib_free_send_mad(query->sa_query.mad_buf);
+
+ err1:
+@@ -887,8 +928,9 @@ static void send_handler(struct ib_mad_a
+ idr_remove(&query_idr, query->id);
+ spin_unlock_irqrestore(&idr_lock, flags);
+
+- ib_free_send_mad(mad_send_wc->send_buf);
++ ib_free_send_mad(mad_send_wc->send_buf);
+ kref_put(&query->sm_ah->ref, free_sm_ah);
++ ib_sa_client_put(query->client);
+ query->release(query);
+ }
+
+@@ -919,7 +961,10 @@ static void ib_sa_add_one(struct ib_devi
+ struct ib_sa_device *sa_dev;
+ int s, e, i;
+
+- if (device->node_type == IB_NODE_SWITCH)
++ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
++ return;
++
++ if (device->node_type == RDMA_NODE_IB_SWITCH)
+ s = e = 0;
+ else {
+ s = 1;
+diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
+index 35852e7..54b81e1 100644
+--- a/drivers/infiniband/core/smi.c
++++ b/drivers/infiniband/core/smi.c
+@@ -64,7 +64,7 @@ int smi_handle_dr_smp_send(struct ib_smp
+
+ /* C14-9:2 */
+ if (hop_ptr && hop_ptr < hop_cnt) {
+- if (node_type != IB_NODE_SWITCH)
++ if (node_type != RDMA_NODE_IB_SWITCH)
+ return 0;
+
+ /* smp->return_path set when received */
+@@ -77,7 +77,7 @@ int smi_handle_dr_smp_send(struct ib_smp
+ if (hop_ptr == hop_cnt) {
+ /* smp->return_path set when received */
+ smp->hop_ptr++;
+- return (node_type == IB_NODE_SWITCH ||
++ return (node_type == RDMA_NODE_IB_SWITCH ||
+ smp->dr_dlid == IB_LID_PERMISSIVE);
+ }
+
+@@ -95,7 +95,7 @@ int smi_handle_dr_smp_send(struct ib_smp
+
+ /* C14-13:2 */
+ if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
+- if (node_type != IB_NODE_SWITCH)
++ if (node_type != RDMA_NODE_IB_SWITCH)
+ return 0;
+
+ smp->hop_ptr--;
+@@ -107,7 +107,7 @@ int smi_handle_dr_smp_send(struct ib_smp
+ if (hop_ptr == 1) {
+ smp->hop_ptr--;
+ /* C14-13:3 -- SMPs destined for SM shouldn't be here */
+- return (node_type == IB_NODE_SWITCH ||
++ return (node_type == RDMA_NODE_IB_SWITCH ||
+ smp->dr_slid == IB_LID_PERMISSIVE);
+ }
+
+@@ -142,7 +142,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
+
+ /* C14-9:2 -- intermediate hop */
+ if (hop_ptr && hop_ptr < hop_cnt) {
+- if (node_type != IB_NODE_SWITCH)
++ if (node_type != RDMA_NODE_IB_SWITCH)
+ return 0;
+
+ smp->return_path[hop_ptr] = port_num;
+@@ -156,7 +156,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
+ smp->return_path[hop_ptr] = port_num;
+ /* smp->hop_ptr updated when sending */
+
+- return (node_type == IB_NODE_SWITCH ||
++ return (node_type == RDMA_NODE_IB_SWITCH ||
+ smp->dr_dlid == IB_LID_PERMISSIVE);
+ }
+
+@@ -175,7 +175,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
+
+ /* C14-13:2 */
+ if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
+- if (node_type != IB_NODE_SWITCH)
++ if (node_type != RDMA_NODE_IB_SWITCH)
+ return 0;
+
+ /* smp->hop_ptr updated when sending */
+@@ -190,7 +190,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
+ return 1;
+ }
+ /* smp->hop_ptr updated when sending */
+- return (node_type == IB_NODE_SWITCH);
++ return (node_type == RDMA_NODE_IB_SWITCH);
+ }
+
+ /* C14-13:4 -- hop_ptr = 0 -> give to SM */
+diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
+index 21f9282..709323c 100644
+--- a/drivers/infiniband/core/sysfs.c
++++ b/drivers/infiniband/core/sysfs.c
+@@ -68,7 +68,7 @@ struct port_table_attribute {
+ int index;
+ };
+
+-static inline int ibdev_is_alive(const struct ib_device *dev)
++static inline int ibdev_is_alive(const struct ib_device *dev)
+ {
+ return dev->reg_state == IB_DEV_REGISTERED;
+ }
+@@ -589,10 +589,11 @@ static ssize_t show_node_type(struct cla
+ return -ENODEV;
+
+ switch (dev->node_type) {
+- case IB_NODE_CA: return sprintf(buf, "%d: CA\n", dev->node_type);
+- case IB_NODE_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type);
+- case IB_NODE_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type);
+- default: return sprintf(buf, "%d: <unknown>\n", dev->node_type);
++ case RDMA_NODE_IB_CA: return sprintf(buf, "%d: CA\n", dev->node_type);
++ case RDMA_NODE_RNIC: return sprintf(buf, "%d: RNIC\n", dev->node_type);
++ case RDMA_NODE_IB_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type);
++ case RDMA_NODE_IB_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type);
++ default: return sprintf(buf, "%d: <unknown>\n", dev->node_type);
+ }
+ }
+
+@@ -708,7 +709,7 @@ int ib_device_register_sysfs(struct ib_d
+ if (ret)
+ goto err_put;
+
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ ret = add_port(device, 0);
+ if (ret)
+ goto err_put;
+diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
+index c1c6fda..ad4f4d5 100644
+--- a/drivers/infiniband/core/ucm.c
++++ b/drivers/infiniband/core/ucm.c
+@@ -309,9 +309,9 @@ static int ib_ucm_event_process(struct i
+ info = evt->param.apr_rcvd.apr_info;
+ break;
+ case IB_CM_SIDR_REQ_RECEIVED:
+- uvt->resp.u.sidr_req_resp.pkey =
++ uvt->resp.u.sidr_req_resp.pkey =
+ evt->param.sidr_req_rcvd.pkey;
+- uvt->resp.u.sidr_req_resp.port =
++ uvt->resp.u.sidr_req_resp.port =
+ evt->param.sidr_req_rcvd.port;
+ uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE;
+ break;
+@@ -1237,7 +1237,7 @@ static struct class ucm_class = {
+ static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+ {
+ struct ib_ucm_device *dev;
+-
++
+ dev = container_of(class_dev, struct ib_ucm_device, class_dev);
+ return sprintf(buf, "%s\n", dev->ib_dev->name);
+ }
+@@ -1247,7 +1247,8 @@ static void ib_ucm_add_one(struct ib_dev
+ {
+ struct ib_ucm_device *ucm_dev;
+
+- if (!device->alloc_ucontext)
++ if (!device->alloc_ucontext ||
++ rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
+ ucm_dev = kzalloc(sizeof *ucm_dev, GFP_KERNEL);
+diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
+index 1273f88..807fbd6 100644
+--- a/drivers/infiniband/core/user_mad.c
++++ b/drivers/infiniband/core/user_mad.c
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
++ * Copyright (c) 2005 Voltaire, Inc. 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
+@@ -1032,7 +1032,10 @@ static void ib_umad_add_one(struct ib_de
+ struct ib_umad_device *umad_dev;
+ int s, e, i;
+
+- if (device->node_type == IB_NODE_SWITCH)
++ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
++ return;
++
++ if (device->node_type == RDMA_NODE_IB_SWITCH)
+ s = e = 0;
+ else {
+ s = 1;
+diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
+index 30923eb..743247e 100644
+--- a/drivers/infiniband/core/uverbs_cmd.c
++++ b/drivers/infiniband/core/uverbs_cmd.c
+@@ -155,7 +155,7 @@ static struct ib_uobject *__idr_get_uobj
+ }
+
+ static struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
+- struct ib_ucontext *context)
++ struct ib_ucontext *context, int nested)
+ {
+ struct ib_uobject *uobj;
+
+@@ -163,7 +163,10 @@ static struct ib_uobject *idr_read_uobj(
+ if (!uobj)
+ return NULL;
+
+- down_read(&uobj->mutex);
++ if (nested)
++ down_read_nested(&uobj->mutex, SINGLE_DEPTH_NESTING);
++ else
++ down_read(&uobj->mutex);
+ if (!uobj->live) {
+ put_uobj_read(uobj);
+ return NULL;
+@@ -190,17 +193,18 @@ static struct ib_uobject *idr_write_uobj
+ return uobj;
+ }
+
+-static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context)
++static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context,
++ int nested)
+ {
+ struct ib_uobject *uobj;
+
+- uobj = idr_read_uobj(idr, id, context);
++ uobj = idr_read_uobj(idr, id, context, nested);
+ return uobj ? uobj->object : NULL;
+ }
+
+ static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context)
+ {
+- return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context);
++ return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context, 0);
+ }
+
+ static void put_pd_read(struct ib_pd *pd)
+@@ -208,9 +212,9 @@ static void put_pd_read(struct ib_pd *pd
+ put_uobj_read(pd->uobject);
+ }
+
+-static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context)
++static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested)
+ {
+- return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context);
++ return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context, nested);
+ }
+
+ static void put_cq_read(struct ib_cq *cq)
+@@ -220,7 +224,7 @@ static void put_cq_read(struct ib_cq *cq
+
+ static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
+ {
+- return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context);
++ return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0);
+ }
+
+ static void put_ah_read(struct ib_ah *ah)
+@@ -230,7 +234,7 @@ static void put_ah_read(struct ib_ah *ah
+
+ static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
+ {
+- return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context);
++ return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
+ }
+
+ static void put_qp_read(struct ib_qp *qp)
+@@ -240,7 +244,7 @@ static void put_qp_read(struct ib_qp *qp
+
+ static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
+ {
+- return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context);
++ return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0);
+ }
+
+ static void put_srq_read(struct ib_srq *srq)
+@@ -837,7 +841,6 @@ ssize_t ib_uverbs_create_cq(struct ib_uv
+ err_copy:
+ idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject);
+
+-
+ err_free:
+ ib_destroy_cq(cq);
+
+@@ -867,7 +870,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uv
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+- cq = idr_read_cq(cmd.cq_handle, file->ucontext);
++ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+ if (!cq)
+ return -EINVAL;
+
+@@ -875,11 +878,10 @@ ssize_t ib_uverbs_resize_cq(struct ib_uv
+ if (ret)
+ goto out;
+
+- memset(&resp, 0, sizeof resp);
+ resp.cqe = cq->cqe;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+- &resp, sizeof resp))
++ &resp, sizeof resp.cqe))
+ ret = -EFAULT;
+
+ out:
+@@ -894,7 +896,6 @@ ssize_t ib_uverbs_poll_cq(struct ib_uver
+ {
+ struct ib_uverbs_poll_cq cmd;
+ struct ib_uverbs_poll_cq_resp *resp;
+- struct ib_uobject *uobj;
+ struct ib_cq *cq;
+ struct ib_wc *wc;
+ int ret = 0;
+@@ -915,16 +916,15 @@ ssize_t ib_uverbs_poll_cq(struct ib_uver
+ goto out_wc;
+ }
+
+- uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
+- if (!uobj) {
++ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
++ if (!cq) {
+ ret = -EINVAL;
+ goto out;
+ }
+- cq = uobj->object;
+
+ resp->count = ib_poll_cq(cq, cmd.ne, wc);
+
+- put_uobj_read(uobj);
++ put_cq_read(cq);
+
+ for (i = 0; i < resp->count; i++) {
+ resp->wc[i].wr_id = wc[i].wr_id;
+@@ -959,21 +959,19 @@ ssize_t ib_uverbs_req_notify_cq(struct i
+ int out_len)
+ {
+ struct ib_uverbs_req_notify_cq cmd;
+- struct ib_uobject *uobj;
+ struct ib_cq *cq;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+- uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
+- if (!uobj)
++ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
++ if (!cq)
+ return -EINVAL;
+- cq = uobj->object;
+
+ ib_req_notify_cq(cq, cmd.solicited_only ?
+ IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
+
+- put_uobj_read(uobj);
++ put_cq_read(cq);
+
+ return in_len;
+ }
+@@ -1064,9 +1062,9 @@ ssize_t ib_uverbs_create_qp(struct ib_uv
+
+ srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL;
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+- scq = idr_read_cq(cmd.send_cq_handle, file->ucontext);
++ scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, 0);
+ rcq = cmd.recv_cq_handle == cmd.send_cq_handle ?
+- scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext);
++ scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1);
+
+ if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) {
+ ret = -EINVAL;
+@@ -1216,7 +1214,7 @@ ssize_t ib_uverbs_query_qp(struct ib_uve
+ resp.qp_access_flags = attr->qp_access_flags;
+ resp.pkey_index = attr->pkey_index;
+ resp.alt_pkey_index = attr->alt_pkey_index;
+- resp.en_sqd_async_notify = attr->en_sqd_async_notify;
++ resp.sq_draining = attr->sq_draining;
+ resp.max_rd_atomic = attr->max_rd_atomic;
+ resp.max_dest_rd_atomic = attr->max_dest_rd_atomic;
+ resp.min_rnr_timer = attr->min_rnr_timer;
+@@ -1274,6 +1272,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uv
+ int out_len)
+ {
+ struct ib_uverbs_modify_qp cmd;
++ struct ib_udata udata;
+ struct ib_qp *qp;
+ struct ib_qp_attr *attr;
+ int ret;
+@@ -1281,6 +1280,9 @@ ssize_t ib_uverbs_modify_qp(struct ib_uv
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
++ INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
++ out_len);
++
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+@@ -1337,7 +1339,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uv
+ 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);
++ ret = qp->device->modify_qp(qp, attr, cmd.attr_mask, &udata);
+
+ put_qp_read(qp);
+
+@@ -1674,7 +1676,6 @@ ssize_t ib_uverbs_post_recv(struct ib_uv
+ break;
+ }
+
+-
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ ret = -EFAULT;
+@@ -1724,7 +1725,6 @@ ssize_t ib_uverbs_post_srq_recv(struct i
+ break;
+ }
+
+-
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ ret = -EFAULT;
+@@ -2055,6 +2055,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_u
+ int out_len)
+ {
+ struct ib_uverbs_modify_srq cmd;
++ struct ib_udata udata;
+ struct ib_srq *srq;
+ struct ib_srq_attr attr;
+ int ret;
+@@ -2062,6 +2063,9 @@ ssize_t ib_uverbs_modify_srq(struct ib_u
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
++ INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
++ out_len);
++
+ srq = idr_read_srq(cmd.srq_handle, file->ucontext);
+ if (!srq)
+ return -EINVAL;
+@@ -2069,7 +2073,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_u
+ attr.max_wr = cmd.max_wr;
+ attr.srq_limit = cmd.srq_limit;
+
+- ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
++ ret = srq->device->modify_srq(srq, &attr, cmd.attr_mask, &udata);
+
+ put_srq_read(srq);
+
+diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
+index 468999c..8b5dd36 100644
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -79,6 +79,23 @@ enum ib_rate mult_to_ib_rate(int mult)
+ }
+ EXPORT_SYMBOL(mult_to_ib_rate);
+
++enum rdma_transport_type
++rdma_node_get_transport(enum rdma_node_type node_type)
++{
++ switch (node_type) {
++ case RDMA_NODE_IB_CA:
++ case RDMA_NODE_IB_SWITCH:
++ case RDMA_NODE_IB_ROUTER:
++ return RDMA_TRANSPORT_IB;
++ case RDMA_NODE_RNIC:
++ return RDMA_TRANSPORT_IWARP;
++ default:
++ BUG();
++ return 0;
++ }
++}
++EXPORT_SYMBOL(rdma_node_get_transport);
++
+ /* Protection domains */
+
+ struct ib_pd *ib_alloc_pd(struct ib_device *device)
+@@ -231,7 +248,7 @@ int ib_modify_srq(struct ib_srq *srq,
+ struct ib_srq_attr *srq_attr,
+ enum ib_srq_attr_mask srq_attr_mask)
+ {
+- return srq->device->modify_srq(srq, srq_attr, srq_attr_mask);
++ return srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL);
+ }
+ EXPORT_SYMBOL(ib_modify_srq);
+
+@@ -547,7 +564,7 @@ int ib_modify_qp(struct ib_qp *qp,
+ struct ib_qp_attr *qp_attr,
+ int qp_attr_mask)
+ {
+- return qp->device->modify_qp(qp, qp_attr, qp_attr_mask);
++ return qp->device->modify_qp(qp, qp_attr, qp_attr_mask, NULL);
+ }
+ EXPORT_SYMBOL(ib_modify_qp);
+
+diff --git a/drivers/infiniband/hw/amso1100/Kbuild b/drivers/infiniband/hw/amso1100/Kbuild
+new file mode 100644
+index 0000000..06964c4
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/Kbuild
+@@ -0,0 +1,8 @@
++ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG
++EXTRA_CFLAGS += -DDEBUG
++endif
++
++obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
++
++iw_c2-y := c2.o c2_provider.o c2_rnic.o c2_alloc.o c2_mq.o c2_ae.o c2_vq.o \
++ c2_intr.o c2_cq.o c2_qp.o c2_cm.o c2_mm.o c2_pd.o
+diff --git a/drivers/infiniband/hw/amso1100/Kconfig b/drivers/infiniband/hw/amso1100/Kconfig
+new file mode 100644
+index 0000000..809cb14
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/Kconfig
+@@ -0,0 +1,15 @@
++config INFINIBAND_AMSO1100
++ tristate "Ammasso 1100 HCA support"
++ depends on PCI && INET && INFINIBAND
++ ---help---
++ This is a low-level driver for the Ammasso 1100 host
++ channel adapter (HCA).
++
++config INFINIBAND_AMSO1100_DEBUG
++ bool "Verbose debugging output"
++ depends on INFINIBAND_AMSO1100
++ default n
++ ---help---
++ This option causes the amso1100 driver to produce a bunch of
++ debug messages. Select this if you are developing the driver
++ or trying to diagnose a problem.
+diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
+new file mode 100644
+index 0000000..9e7bd94
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2.c
+@@ -0,0 +1,1255 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/pci.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/if_vlan.h>
++#include <linux/crc32.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/byteorder.h>
++
++#include <rdma/ib_smi.h>
++#include "c2.h"
++#include "c2_provider.h"
++
++MODULE_AUTHOR("Tom Tucker <tom at opengridcomputing.com>");
++MODULE_DESCRIPTION("Ammasso AMSO1100 Low-level iWARP Driver");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_VERSION(DRV_VERSION);
++
++static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
++ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
++
++static int debug = -1; /* defaults above */
++module_param(debug, int, 0);
++MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
++
++static int c2_up(struct net_device *netdev);
++static int c2_down(struct net_device *netdev);
++static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
++static void c2_tx_interrupt(struct net_device *netdev);
++static void c2_rx_interrupt(struct net_device *netdev);
++static irqreturn_t c2_interrupt(int irq, void *dev_id);
++static void c2_tx_timeout(struct net_device *netdev);
++static int c2_change_mtu(struct net_device *netdev, int new_mtu);
++static void c2_reset(struct c2_port *c2_port);
++static struct net_device_stats *c2_get_stats(struct net_device *netdev);
++
++static struct pci_device_id c2_pci_table[] = {
++ { PCI_DEVICE(0x18b8, 0xb001) },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(pci, c2_pci_table);
++
++static void c2_print_macaddr(struct net_device *netdev)
++{
++ pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, "
++ "IRQ %u\n", netdev->name,
++ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
++ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5],
++ netdev->irq);
++}
++
++static void c2_set_rxbufsize(struct c2_port *c2_port)
++{
++ struct net_device *netdev = c2_port->netdev;
++
++ if (netdev->mtu > RX_BUF_SIZE)
++ c2_port->rx_buf_size =
++ netdev->mtu + ETH_HLEN + sizeof(struct c2_rxp_hdr) +
++ NET_IP_ALIGN;
++ else
++ c2_port->rx_buf_size = sizeof(struct c2_rxp_hdr) + RX_BUF_SIZE;
++}
++
++/*
++ * Allocate TX ring elements and chain them together.
++ * One-to-one association of adapter descriptors with ring elements.
++ */
++static int c2_tx_ring_alloc(struct c2_ring *tx_ring, void *vaddr,
++ dma_addr_t base, void __iomem * mmio_txp_ring)
++{
++ struct c2_tx_desc *tx_desc;
++ struct c2_txp_desc __iomem *txp_desc;
++ struct c2_element *elem;
++ int i;
++
++ tx_ring->start = kmalloc(sizeof(*elem) * tx_ring->count, GFP_KERNEL);
++ if (!tx_ring->start)
++ return -ENOMEM;
++
++ elem = tx_ring->start;
++ tx_desc = vaddr;
++ txp_desc = mmio_txp_ring;
++ for (i = 0; i < tx_ring->count; i++, elem++, tx_desc++, txp_desc++) {
++ tx_desc->len = 0;
++ tx_desc->status = 0;
++
++ /* Set TXP_HTXD_UNINIT */
++ __raw_writeq(cpu_to_be64(0x1122334455667788ULL),
++ (void __iomem *) txp_desc + C2_TXP_ADDR);
++ __raw_writew(0, (void __iomem *) txp_desc + C2_TXP_LEN);
++ __raw_writew(cpu_to_be16(TXP_HTXD_UNINIT),
++ (void __iomem *) txp_desc + C2_TXP_FLAGS);
++
++ elem->skb = NULL;
++ elem->ht_desc = tx_desc;
++ elem->hw_desc = txp_desc;
++
++ if (i == tx_ring->count - 1) {
++ elem->next = tx_ring->start;
++ tx_desc->next_offset = base;
++ } else {
++ elem->next = elem + 1;
++ tx_desc->next_offset =
++ base + (i + 1) * sizeof(*tx_desc);
++ }
++ }
++
++ tx_ring->to_use = tx_ring->to_clean = tx_ring->start;
++
++ return 0;
++}
++
++/*
++ * Allocate RX ring elements and chain them together.
++ * One-to-one association of adapter descriptors with ring elements.
++ */
++static int c2_rx_ring_alloc(struct c2_ring *rx_ring, void *vaddr,
++ dma_addr_t base, void __iomem * mmio_rxp_ring)
++{
++ struct c2_rx_desc *rx_desc;
++ struct c2_rxp_desc __iomem *rxp_desc;
++ struct c2_element *elem;
++ int i;
++
++ rx_ring->start = kmalloc(sizeof(*elem) * rx_ring->count, GFP_KERNEL);
++ if (!rx_ring->start)
++ return -ENOMEM;
++
++ elem = rx_ring->start;
++ rx_desc = vaddr;
++ rxp_desc = mmio_rxp_ring;
++ for (i = 0; i < rx_ring->count; i++, elem++, rx_desc++, rxp_desc++) {
++ rx_desc->len = 0;
++ rx_desc->status = 0;
++
++ /* Set RXP_HRXD_UNINIT */
++ __raw_writew(cpu_to_be16(RXP_HRXD_OK),
++ (void __iomem *) rxp_desc + C2_RXP_STATUS);
++ __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_COUNT);
++ __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_LEN);
++ __raw_writeq(cpu_to_be64(0x99aabbccddeeffULL),
++ (void __iomem *) rxp_desc + C2_RXP_ADDR);
++ __raw_writew(cpu_to_be16(RXP_HRXD_UNINIT),
++ (void __iomem *) rxp_desc + C2_RXP_FLAGS);
++
++ elem->skb = NULL;
++ elem->ht_desc = rx_desc;
++ elem->hw_desc = rxp_desc;
++
++ if (i == rx_ring->count - 1) {
++ elem->next = rx_ring->start;
++ rx_desc->next_offset = base;
++ } else {
++ elem->next = elem + 1;
++ rx_desc->next_offset =
++ base + (i + 1) * sizeof(*rx_desc);
++ }
++ }
++
++ rx_ring->to_use = rx_ring->to_clean = rx_ring->start;
++
++ return 0;
++}
++
++/* Setup buffer for receiving */
++static inline int c2_rx_alloc(struct c2_port *c2_port, struct c2_element *elem)
++{
++ struct c2_dev *c2dev = c2_port->c2dev;
++ struct c2_rx_desc *rx_desc = elem->ht_desc;
++ struct sk_buff *skb;
++ dma_addr_t mapaddr;
++ u32 maplen;
++ struct c2_rxp_hdr *rxp_hdr;
++
++ skb = dev_alloc_skb(c2_port->rx_buf_size);
++ if (unlikely(!skb)) {
++ pr_debug("%s: out of memory for receive\n",
++ c2_port->netdev->name);
++ return -ENOMEM;
++ }
++
++ /* Zero out the rxp hdr in the sk_buff */
++ memset(skb->data, 0, sizeof(*rxp_hdr));
++
++ skb->dev = c2_port->netdev;
++
++ maplen = c2_port->rx_buf_size;
++ mapaddr =
++ pci_map_single(c2dev->pcidev, skb->data, maplen,
++ PCI_DMA_FROMDEVICE);
++
++ /* Set the sk_buff RXP_header to RXP_HRXD_READY */
++ rxp_hdr = (struct c2_rxp_hdr *) skb->data;
++ rxp_hdr->flags = RXP_HRXD_READY;
++
++ __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
++ __raw_writew(cpu_to_be16((u16) maplen - sizeof(*rxp_hdr)),
++ elem->hw_desc + C2_RXP_LEN);
++ __raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_RXP_ADDR);
++ __raw_writew(cpu_to_be16(RXP_HRXD_READY), elem->hw_desc + C2_RXP_FLAGS);
++
++ elem->skb = skb;
++ elem->mapaddr = mapaddr;
++ elem->maplen = maplen;
++ rx_desc->len = maplen;
++
++ return 0;
++}
++
++/*
++ * Allocate buffers for the Rx ring
++ * For receive: rx_ring.to_clean is next received frame
++ */
++static int c2_rx_fill(struct c2_port *c2_port)
++{
++ struct c2_ring *rx_ring = &c2_port->rx_ring;
++ struct c2_element *elem;
++ int ret = 0;
++
++ elem = rx_ring->start;
++ do {
++ if (c2_rx_alloc(c2_port, elem)) {
++ ret = 1;
++ break;
++ }
++ } while ((elem = elem->next) != rx_ring->start);
++
++ rx_ring->to_clean = rx_ring->start;
++ return ret;
++}
++
++/* Free all buffers in RX ring, assumes receiver stopped */
++static void c2_rx_clean(struct c2_port *c2_port)
++{
++ struct c2_dev *c2dev = c2_port->c2dev;
++ struct c2_ring *rx_ring = &c2_port->rx_ring;
++ struct c2_element *elem;
++ struct c2_rx_desc *rx_desc;
++
++ elem = rx_ring->start;
++ do {
++ rx_desc = elem->ht_desc;
++ rx_desc->len = 0;
++
++ __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
++ __raw_writew(0, elem->hw_desc + C2_RXP_COUNT);
++ __raw_writew(0, elem->hw_desc + C2_RXP_LEN);
++ __raw_writeq(cpu_to_be64(0x99aabbccddeeffULL),
++ elem->hw_desc + C2_RXP_ADDR);
++ __raw_writew(cpu_to_be16(RXP_HRXD_UNINIT),
++ elem->hw_desc + C2_RXP_FLAGS);
++
++ if (elem->skb) {
++ pci_unmap_single(c2dev->pcidev, elem->mapaddr,
++ elem->maplen, PCI_DMA_FROMDEVICE);
++ dev_kfree_skb(elem->skb);
++ elem->skb = NULL;
++ }
++ } while ((elem = elem->next) != rx_ring->start);
++}
++
++static inline int c2_tx_free(struct c2_dev *c2dev, struct c2_element *elem)
++{
++ struct c2_tx_desc *tx_desc = elem->ht_desc;
++
++ tx_desc->len = 0;
++
++ pci_unmap_single(c2dev->pcidev, elem->mapaddr, elem->maplen,
++ PCI_DMA_TODEVICE);
++
++ if (elem->skb) {
++ dev_kfree_skb_any(elem->skb);
++ elem->skb = NULL;
++ }
++
++ return 0;
++}
++
++/* Free all buffers in TX ring, assumes transmitter stopped */
++static void c2_tx_clean(struct c2_port *c2_port)
++{
++ struct c2_ring *tx_ring = &c2_port->tx_ring;
++ struct c2_element *elem;
++ struct c2_txp_desc txp_htxd;
++ int retry;
++ unsigned long flags;
++
++ spin_lock_irqsave(&c2_port->tx_lock, flags);
++
++ elem = tx_ring->start;
++
++ do {
++ retry = 0;
++ do {
++ txp_htxd.flags =
++ readw(elem->hw_desc + C2_TXP_FLAGS);
++
++ if (txp_htxd.flags == TXP_HTXD_READY) {
++ retry = 1;
++ __raw_writew(0,
++ elem->hw_desc + C2_TXP_LEN);
++ __raw_writeq(0,
++ elem->hw_desc + C2_TXP_ADDR);
++ __raw_writew(cpu_to_be16(TXP_HTXD_DONE),
++ elem->hw_desc + C2_TXP_FLAGS);
++ c2_port->netstats.tx_dropped++;
++ break;
++ } else {
++ __raw_writew(0,
++ elem->hw_desc + C2_TXP_LEN);
++ __raw_writeq(cpu_to_be64(0x1122334455667788ULL),
++ elem->hw_desc + C2_TXP_ADDR);
++ __raw_writew(cpu_to_be16(TXP_HTXD_UNINIT),
++ elem->hw_desc + C2_TXP_FLAGS);
++ }
++
++ c2_tx_free(c2_port->c2dev, elem);
++
++ } while ((elem = elem->next) != tx_ring->start);
++ } while (retry);
++
++ c2_port->tx_avail = c2_port->tx_ring.count - 1;
++ c2_port->c2dev->cur_tx = tx_ring->to_use - tx_ring->start;
++
++ if (c2_port->tx_avail > MAX_SKB_FRAGS + 1)
++ netif_wake_queue(c2_port->netdev);
++
++ spin_unlock_irqrestore(&c2_port->tx_lock, flags);
++}
++
++/*
++ * Process transmit descriptors marked 'DONE' by the firmware,
++ * freeing up their unneeded sk_buffs.
++ */
++static void c2_tx_interrupt(struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++ struct c2_dev *c2dev = c2_port->c2dev;
++ struct c2_ring *tx_ring = &c2_port->tx_ring;
++ struct c2_element *elem;
++ struct c2_txp_desc txp_htxd;
++
++ spin_lock(&c2_port->tx_lock);
++
++ for (elem = tx_ring->to_clean; elem != tx_ring->to_use;
++ elem = elem->next) {
++ txp_htxd.flags =
++ be16_to_cpu(readw(elem->hw_desc + C2_TXP_FLAGS));
++
++ if (txp_htxd.flags != TXP_HTXD_DONE)
++ break;
++
++ if (netif_msg_tx_done(c2_port)) {
++ /* PCI reads are expensive in fast path */
++ txp_htxd.len =
++ be16_to_cpu(readw(elem->hw_desc + C2_TXP_LEN));
++ pr_debug("%s: tx done slot %3Zu status 0x%x len "
++ "%5u bytes\n",
++ netdev->name, elem - tx_ring->start,
++ txp_htxd.flags, txp_htxd.len);
++ }
++
++ c2_tx_free(c2dev, elem);
++ ++(c2_port->tx_avail);
++ }
++
++ tx_ring->to_clean = elem;
++
++ if (netif_queue_stopped(netdev)
++ && c2_port->tx_avail > MAX_SKB_FRAGS + 1)
++ netif_wake_queue(netdev);
++
++ spin_unlock(&c2_port->tx_lock);
++}
++
++static void c2_rx_error(struct c2_port *c2_port, struct c2_element *elem)
++{
++ struct c2_rx_desc *rx_desc = elem->ht_desc;
++ struct c2_rxp_hdr *rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data;
++
++ if (rxp_hdr->status != RXP_HRXD_OK ||
++ rxp_hdr->len > (rx_desc->len - sizeof(*rxp_hdr))) {
++ pr_debug("BAD RXP_HRXD\n");
++ pr_debug(" rx_desc : %p\n", rx_desc);
++ pr_debug(" index : %Zu\n",
++ elem - c2_port->rx_ring.start);
++ pr_debug(" len : %u\n", rx_desc->len);
++ pr_debug(" rxp_hdr : %p [PA %p]\n", rxp_hdr,
++ (void *) __pa((unsigned long) rxp_hdr));
++ pr_debug(" flags : 0x%x\n", rxp_hdr->flags);
++ pr_debug(" status: 0x%x\n", rxp_hdr->status);
++ pr_debug(" len : %u\n", rxp_hdr->len);
++ pr_debug(" rsvd : 0x%x\n", rxp_hdr->rsvd);
++ }
++
++ /* Setup the skb for reuse since we're dropping this pkt */
++ elem->skb->tail = elem->skb->data = elem->skb->head;
++
++ /* Zero out the rxp hdr in the sk_buff */
++ memset(elem->skb->data, 0, sizeof(*rxp_hdr));
++
++ /* Write the descriptor to the adapter's rx ring */
++ __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
++ __raw_writew(0, elem->hw_desc + C2_RXP_COUNT);
++ __raw_writew(cpu_to_be16((u16) elem->maplen - sizeof(*rxp_hdr)),
++ elem->hw_desc + C2_RXP_LEN);
++ __raw_writeq(cpu_to_be64(elem->mapaddr), elem->hw_desc + C2_RXP_ADDR);
++ __raw_writew(cpu_to_be16(RXP_HRXD_READY), elem->hw_desc + C2_RXP_FLAGS);
++
++ pr_debug("packet dropped\n");
++ c2_port->netstats.rx_dropped++;
++}
++
++static void c2_rx_interrupt(struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++ struct c2_dev *c2dev = c2_port->c2dev;
++ struct c2_ring *rx_ring = &c2_port->rx_ring;
++ struct c2_element *elem;
++ struct c2_rx_desc *rx_desc;
++ struct c2_rxp_hdr *rxp_hdr;
++ struct sk_buff *skb;
++ dma_addr_t mapaddr;
++ u32 maplen, buflen;
++ unsigned long flags;
++
++ spin_lock_irqsave(&c2dev->lock, flags);
++
++ /* Begin where we left off */
++ rx_ring->to_clean = rx_ring->start + c2dev->cur_rx;
++
++ for (elem = rx_ring->to_clean; elem->next != rx_ring->to_clean;
++ elem = elem->next) {
++ rx_desc = elem->ht_desc;
++ mapaddr = elem->mapaddr;
++ maplen = elem->maplen;
++ skb = elem->skb;
++ rxp_hdr = (struct c2_rxp_hdr *) skb->data;
++
++ if (rxp_hdr->flags != RXP_HRXD_DONE)
++ break;
++ buflen = rxp_hdr->len;
++
++ /* Sanity check the RXP header */
++ if (rxp_hdr->status != RXP_HRXD_OK ||
++ buflen > (rx_desc->len - sizeof(*rxp_hdr))) {
++ c2_rx_error(c2_port, elem);
++ continue;
++ }
++
++ /*
++ * Allocate and map a new skb for replenishing the host
++ * RX desc
++ */
++ if (c2_rx_alloc(c2_port, elem)) {
++ c2_rx_error(c2_port, elem);
++ continue;
++ }
++
++ /* Unmap the old skb */
++ pci_unmap_single(c2dev->pcidev, mapaddr, maplen,
++ PCI_DMA_FROMDEVICE);
++
++ prefetch(skb->data);
++
++ /*
++ * Skip past the leading 8 bytes comprising of the
++ * "struct c2_rxp_hdr", prepended by the adapter
++ * to the usual Ethernet header ("struct ethhdr"),
++ * to the start of the raw Ethernet packet.
++ *
++ * Fix up the various fields in the sk_buff before
++ * passing it up to netif_rx(). The transfer size
++ * (in bytes) specified by the adapter len field of
++ * the "struct rxp_hdr_t" does NOT include the
++ * "sizeof(struct c2_rxp_hdr)".
++ */
++ skb->data += sizeof(*rxp_hdr);
++ skb->tail = skb->data + buflen;
++ skb->len = buflen;
++ skb->dev = netdev;
++ skb->protocol = eth_type_trans(skb, netdev);
++
++ netif_rx(skb);
++
++ netdev->last_rx = jiffies;
++ c2_port->netstats.rx_packets++;
++ c2_port->netstats.rx_bytes += buflen;
++ }
++
++ /* Save where we left off */
++ rx_ring->to_clean = elem;
++ c2dev->cur_rx = elem - rx_ring->start;
++ C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
++
++ spin_unlock_irqrestore(&c2dev->lock, flags);
++}
++
++/*
++ * Handle netisr0 TX & RX interrupts.
++ */
++static irqreturn_t c2_interrupt(int irq, void *dev_id)
++{
++ unsigned int netisr0, dmaisr;
++ int handled = 0;
++ struct c2_dev *c2dev = (struct c2_dev *) dev_id;
++
++ /* Process CCILNET interrupts */
++ netisr0 = readl(c2dev->regs + C2_NISR0);
++ if (netisr0) {
++
++ /*
++ * There is an issue with the firmware that always
++ * provides the status of RX for both TX & RX
++ * interrupts. So process both queues here.
++ */
++ c2_rx_interrupt(c2dev->netdev);
++ c2_tx_interrupt(c2dev->netdev);
++
++ /* Clear the interrupt */
++ writel(netisr0, c2dev->regs + C2_NISR0);
++ handled++;
++ }
++
++ /* Process RNIC interrupts */
++ dmaisr = readl(c2dev->regs + C2_DISR);
++ if (dmaisr) {
++ writel(dmaisr, c2dev->regs + C2_DISR);
++ c2_rnic_interrupt(c2dev);
++ handled++;
++ }
++
++ if (handled) {
++ return IRQ_HANDLED;
++ } else {
++ return IRQ_NONE;
++ }
++}
++
++static int c2_up(struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++ struct c2_dev *c2dev = c2_port->c2dev;
++ struct c2_element *elem;
++ struct c2_rxp_hdr *rxp_hdr;
++ struct in_device *in_dev;
++ size_t rx_size, tx_size;
++ int ret, i;
++ unsigned int netimr0;
++
++ if (netif_msg_ifup(c2_port))
++ pr_debug("%s: enabling interface\n", netdev->name);
++
++ /* Set the Rx buffer size based on MTU */
++ c2_set_rxbufsize(c2_port);
++
++ /* Allocate DMA'able memory for Tx/Rx host descriptor rings */
++ rx_size = c2_port->rx_ring.count * sizeof(struct c2_rx_desc);
++ tx_size = c2_port->tx_ring.count * sizeof(struct c2_tx_desc);
++
++ c2_port->mem_size = tx_size + rx_size;
++ c2_port->mem = pci_alloc_consistent(c2dev->pcidev, c2_port->mem_size,
++ &c2_port->dma);
++ if (c2_port->mem == NULL) {
++ pr_debug("Unable to allocate memory for "
++ "host descriptor rings\n");
++ return -ENOMEM;
++ }
++
++ memset(c2_port->mem, 0, c2_port->mem_size);
++
++ /* Create the Rx host descriptor ring */
++ if ((ret =
++ c2_rx_ring_alloc(&c2_port->rx_ring, c2_port->mem, c2_port->dma,
++ c2dev->mmio_rxp_ring))) {
++ pr_debug("Unable to create RX ring\n");
++ goto bail0;
++ }
++
++ /* Allocate Rx buffers for the host descriptor ring */
++ if (c2_rx_fill(c2_port)) {
++ pr_debug("Unable to fill RX ring\n");
++ goto bail1;
++ }
++
++ /* Create the Tx host descriptor ring */
++ if ((ret = c2_tx_ring_alloc(&c2_port->tx_ring, c2_port->mem + rx_size,
++ c2_port->dma + rx_size,
++ c2dev->mmio_txp_ring))) {
++ pr_debug("Unable to create TX ring\n");
++ goto bail1;
++ }
++
++ /* Set the TX pointer to where we left off */
++ c2_port->tx_avail = c2_port->tx_ring.count - 1;
++ c2_port->tx_ring.to_use = c2_port->tx_ring.to_clean =
++ c2_port->tx_ring.start + c2dev->cur_tx;
++
++ /* missing: Initialize MAC */
++
++ BUG_ON(c2_port->tx_ring.to_use != c2_port->tx_ring.to_clean);
++
++ /* Reset the adapter, ensures the driver is in sync with the RXP */
++ c2_reset(c2_port);
++
++ /* Reset the READY bit in the sk_buff RXP headers & adapter HRXDQ */
++ for (i = 0, elem = c2_port->rx_ring.start; i < c2_port->rx_ring.count;
++ i++, elem++) {
++ rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data;
++ rxp_hdr->flags = 0;
++ __raw_writew(cpu_to_be16(RXP_HRXD_READY),
++ elem->hw_desc + C2_RXP_FLAGS);
++ }
++
++ /* Enable network packets */
++ netif_start_queue(netdev);
++
++ /* Enable IRQ */
++ writel(0, c2dev->regs + C2_IDIS);
++ netimr0 = readl(c2dev->regs + C2_NIMR0);
++ netimr0 &= ~(C2_PCI_HTX_INT | C2_PCI_HRX_INT);
++ writel(netimr0, c2dev->regs + C2_NIMR0);
++
++ /* Tell the stack to ignore arp requests for ipaddrs bound to
++ * other interfaces. This is needed to prevent the host stack
++ * from responding to arp requests to the ipaddr bound on the
++ * rdma interface.
++ */
++ in_dev = in_dev_get(netdev);
++ in_dev->cnf.arp_ignore = 1;
++ in_dev_put(in_dev);
++
++ return 0;
++
++ bail1:
++ c2_rx_clean(c2_port);
++ kfree(c2_port->rx_ring.start);
++
++ bail0:
++ pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem,
++ c2_port->dma);
++
++ return ret;
++}
++
++static int c2_down(struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++ struct c2_dev *c2dev = c2_port->c2dev;
++
++ if (netif_msg_ifdown(c2_port))
++ pr_debug("%s: disabling interface\n",
++ netdev->name);
++
++ /* Wait for all the queued packets to get sent */
++ c2_tx_interrupt(netdev);
++
++ /* Disable network packets */
++ netif_stop_queue(netdev);
++
++ /* Disable IRQs by clearing the interrupt mask */
++ writel(1, c2dev->regs + C2_IDIS);
++ writel(0, c2dev->regs + C2_NIMR0);
++
++ /* missing: Stop transmitter */
++
++ /* missing: Stop receiver */
++
++ /* Reset the adapter, ensures the driver is in sync with the RXP */
++ c2_reset(c2_port);
++
++ /* missing: Turn off LEDs here */
++
++ /* Free all buffers in the host descriptor rings */
++ c2_tx_clean(c2_port);
++ c2_rx_clean(c2_port);
++
++ /* Free the host descriptor rings */
++ kfree(c2_port->rx_ring.start);
++ kfree(c2_port->tx_ring.start);
++ pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem,
++ c2_port->dma);
++
++ return 0;
++}
++
++static void c2_reset(struct c2_port *c2_port)
++{
++ struct c2_dev *c2dev = c2_port->c2dev;
++ unsigned int cur_rx = c2dev->cur_rx;
++
++ /* Tell the hardware to quiesce */
++ C2_SET_CUR_RX(c2dev, cur_rx | C2_PCI_HRX_QUI);
++
++ /*
++ * The hardware will reset the C2_PCI_HRX_QUI bit once
++ * the RXP is quiesced. Wait 2 seconds for this.
++ */
++ ssleep(2);
++
++ cur_rx = C2_GET_CUR_RX(c2dev);
++
++ if (cur_rx & C2_PCI_HRX_QUI)
++ pr_debug("c2_reset: failed to quiesce the hardware!\n");
++
++ cur_rx &= ~C2_PCI_HRX_QUI;
++
++ c2dev->cur_rx = cur_rx;
++
++ pr_debug("Current RX: %u\n", c2dev->cur_rx);
++}
++
++static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++ struct c2_dev *c2dev = c2_port->c2dev;
++ struct c2_ring *tx_ring = &c2_port->tx_ring;
++ struct c2_element *elem;
++ dma_addr_t mapaddr;
++ u32 maplen;
++ unsigned long flags;
++ unsigned int i;
++
++ spin_lock_irqsave(&c2_port->tx_lock, flags);
++
++ if (unlikely(c2_port->tx_avail < (skb_shinfo(skb)->nr_frags + 1))) {
++ netif_stop_queue(netdev);
++ spin_unlock_irqrestore(&c2_port->tx_lock, flags);
++
++ pr_debug("%s: Tx ring full when queue awake!\n",
++ netdev->name);
++ return NETDEV_TX_BUSY;
++ }
++
++ maplen = skb_headlen(skb);
++ mapaddr =
++ pci_map_single(c2dev->pcidev, skb->data, maplen, PCI_DMA_TODEVICE);
++
++ elem = tx_ring->to_use;
++ elem->skb = skb;
++ elem->mapaddr = mapaddr;
++ elem->maplen = maplen;
++
++ /* Tell HW to xmit */
++ __raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR);
++ __raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN);
++ __raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS);
++
++ c2_port->netstats.tx_packets++;
++ c2_port->netstats.tx_bytes += maplen;
++
++ /* Loop thru additional data fragments and queue them */
++ if (skb_shinfo(skb)->nr_frags) {
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++ maplen = frag->size;
++ mapaddr =
++ pci_map_page(c2dev->pcidev, frag->page,
++ frag->page_offset, maplen,
++ PCI_DMA_TODEVICE);
++
++ elem = elem->next;
++ elem->skb = NULL;
++ elem->mapaddr = mapaddr;
++ elem->maplen = maplen;
++
++ /* Tell HW to xmit */
++ __raw_writeq(cpu_to_be64(mapaddr),
++ elem->hw_desc + C2_TXP_ADDR);
++ __raw_writew(cpu_to_be16(maplen),
++ elem->hw_desc + C2_TXP_LEN);
++ __raw_writew(cpu_to_be16(TXP_HTXD_READY),
++ elem->hw_desc + C2_TXP_FLAGS);
++
++ c2_port->netstats.tx_packets++;
++ c2_port->netstats.tx_bytes += maplen;
++ }
++ }
++
++ tx_ring->to_use = elem->next;
++ c2_port->tx_avail -= (skb_shinfo(skb)->nr_frags + 1);
++
++ if (c2_port->tx_avail <= MAX_SKB_FRAGS + 1) {
++ netif_stop_queue(netdev);
++ if (netif_msg_tx_queued(c2_port))
++ pr_debug("%s: transmit queue full\n",
++ netdev->name);
++ }
++
++ spin_unlock_irqrestore(&c2_port->tx_lock, flags);
++
++ netdev->trans_start = jiffies;
++
++ return NETDEV_TX_OK;
++}
++
++static struct net_device_stats *c2_get_stats(struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++
++ return &c2_port->netstats;
++}
++
++static void c2_tx_timeout(struct net_device *netdev)
++{
++ struct c2_port *c2_port = netdev_priv(netdev);
++
++ if (netif_msg_timer(c2_port))
++ pr_debug("%s: tx timeout\n", netdev->name);
++
++ c2_tx_clean(c2_port);
++}
++
++static int c2_change_mtu(struct net_device *netdev, int new_mtu)
++{
++ int ret = 0;
++
++ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
++ return -EINVAL;
++
++ netdev->mtu = new_mtu;
++
++ if (netif_running(netdev)) {
++ c2_down(netdev);
++
++ c2_up(netdev);
++ }
++
++ return ret;
++}
++
++/* Initialize network device */
++static struct net_device *c2_devinit(struct c2_dev *c2dev,
++ void __iomem * mmio_addr)
++{
++ struct c2_port *c2_port = NULL;
++ struct net_device *netdev = alloc_etherdev(sizeof(*c2_port));
++
++ if (!netdev) {
++ pr_debug("c2_port etherdev alloc failed");
++ return NULL;
++ }
++
++ SET_MODULE_OWNER(netdev);
++ SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
++
++ netdev->open = c2_up;
++ netdev->stop = c2_down;
++ netdev->hard_start_xmit = c2_xmit_frame;
++ netdev->get_stats = c2_get_stats;
++ netdev->tx_timeout = c2_tx_timeout;
++ netdev->change_mtu = c2_change_mtu;
++ netdev->watchdog_timeo = C2_TX_TIMEOUT;
++ netdev->irq = c2dev->pcidev->irq;
++
++ c2_port = netdev_priv(netdev);
++ c2_port->netdev = netdev;
++ c2_port->c2dev = c2dev;
++ c2_port->msg_enable = netif_msg_init(debug, default_msg);
++ c2_port->tx_ring.count = C2_NUM_TX_DESC;
++ c2_port->rx_ring.count = C2_NUM_RX_DESC;
++
++ spin_lock_init(&c2_port->tx_lock);
++
++ /* Copy our 48-bit ethernet hardware address */
++ memcpy_fromio(netdev->dev_addr, mmio_addr + C2_REGS_ENADDR, 6);
++
++ /* Validate the MAC address */
++ if (!is_valid_ether_addr(netdev->dev_addr)) {
++ pr_debug("Invalid MAC Address\n");
++ c2_print_macaddr(netdev);
++ free_netdev(netdev);
++ return NULL;
++ }
++
++ c2dev->netdev = netdev;
++
++ return netdev;
++}
++
++static int __devinit c2_probe(struct pci_dev *pcidev,
++ const struct pci_device_id *ent)
++{
++ int ret = 0, i;
++ unsigned long reg0_start, reg0_flags, reg0_len;
++ unsigned long reg2_start, reg2_flags, reg2_len;
++ unsigned long reg4_start, reg4_flags, reg4_len;
++ unsigned kva_map_size;
++ struct net_device *netdev = NULL;
++ struct c2_dev *c2dev = NULL;
++ void __iomem *mmio_regs = NULL;
++
++ printk(KERN_INFO PFX "AMSO1100 Gigabit Ethernet driver v%s loaded\n",
++ DRV_VERSION);
++
++ /* Enable PCI device */
++ ret = pci_enable_device(pcidev);
++ if (ret) {
++ printk(KERN_ERR PFX "%s: Unable to enable PCI device\n",
++ pci_name(pcidev));
++ goto bail0;
++ }
++
++ reg0_start = pci_resource_start(pcidev, BAR_0);
++ reg0_len = pci_resource_len(pcidev, BAR_0);
++ reg0_flags = pci_resource_flags(pcidev, BAR_0);
++
++ reg2_start = pci_resource_start(pcidev, BAR_2);
++ reg2_len = pci_resource_len(pcidev, BAR_2);
++ reg2_flags = pci_resource_flags(pcidev, BAR_2);
++
++ reg4_start = pci_resource_start(pcidev, BAR_4);
++ reg4_len = pci_resource_len(pcidev, BAR_4);
++ reg4_flags = pci_resource_flags(pcidev, BAR_4);
++
++ pr_debug("BAR0 size = 0x%lX bytes\n", reg0_len);
++ pr_debug("BAR2 size = 0x%lX bytes\n", reg2_len);
++ pr_debug("BAR4 size = 0x%lX bytes\n", reg4_len);
++
++ /* Make sure PCI base addr are MMIO */
++ if (!(reg0_flags & IORESOURCE_MEM) ||
++ !(reg2_flags & IORESOURCE_MEM) || !(reg4_flags & IORESOURCE_MEM)) {
++ printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
++ ret = -ENODEV;
++ goto bail1;
++ }
++
++ /* Check for weird/broken PCI region reporting */
++ if ((reg0_len < C2_REG0_SIZE) ||
++ (reg2_len < C2_REG2_SIZE) || (reg4_len < C2_REG4_SIZE)) {
++ printk(KERN_ERR PFX "Invalid PCI region sizes\n");
++ ret = -ENODEV;
++ goto bail1;
++ }
++
++ /* Reserve PCI I/O and memory resources */
++ ret = pci_request_regions(pcidev, DRV_NAME);
++ if (ret) {
++ printk(KERN_ERR PFX "%s: Unable to request regions\n",
++ pci_name(pcidev));
++ goto bail1;
++ }
++
++ if ((sizeof(dma_addr_t) > 4)) {
++ ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK);
++ if (ret < 0) {
++ printk(KERN_ERR PFX "64b DMA configuration failed\n");
++ goto bail2;
++ }
++ } else {
++ ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
++ if (ret < 0) {
++ printk(KERN_ERR PFX "32b DMA configuration failed\n");
++ goto bail2;
++ }
++ }
++
++ /* Enables bus-mastering on the device */
++ pci_set_master(pcidev);
++
++ /* Remap the adapter PCI registers in BAR4 */
++ mmio_regs = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET,
++ sizeof(struct c2_adapter_pci_regs));
++ if (mmio_regs == 0UL) {
++ printk(KERN_ERR PFX
++ "Unable to remap adapter PCI registers in BAR4\n");
++ ret = -EIO;
++ goto bail2;
++ }
++
++ /* Validate PCI regs magic */
++ for (i = 0; i < sizeof(c2_magic); i++) {
++ if (c2_magic[i] != readb(mmio_regs + C2_REGS_MAGIC + i)) {
++ printk(KERN_ERR PFX "Downlevel Firmware boot loader "
++ "[%d/%Zd: got 0x%x, exp 0x%x]. Use the cc_flash "
++ "utility to update your boot loader\n",
++ i + 1, sizeof(c2_magic),
++ readb(mmio_regs + C2_REGS_MAGIC + i),
++ c2_magic[i]);
++ printk(KERN_ERR PFX "Adapter not claimed\n");
++ iounmap(mmio_regs);
++ ret = -EIO;
++ goto bail2;
++ }
++ }
++
++ /* Validate the adapter version */
++ if (be32_to_cpu(readl(mmio_regs + C2_REGS_VERS)) != C2_VERSION) {
++ printk(KERN_ERR PFX "Version mismatch "
++ "[fw=%u, c2=%u], Adapter not claimed\n",
++ be32_to_cpu(readl(mmio_regs + C2_REGS_VERS)),
++ C2_VERSION);
++ ret = -EINVAL;
++ iounmap(mmio_regs);
++ goto bail2;
++ }
++
++ /* Validate the adapter IVN */
++ if (be32_to_cpu(readl(mmio_regs + C2_REGS_IVN)) != C2_IVN) {
++ printk(KERN_ERR PFX "Downlevel FIrmware level. You should be using "
++ "the OpenIB device support kit. "
++ "[fw=0x%x, c2=0x%x], Adapter not claimed\n",
++ be32_to_cpu(readl(mmio_regs + C2_REGS_IVN)),
++ C2_IVN);
++ ret = -EINVAL;
++ iounmap(mmio_regs);
++ goto bail2;
++ }
++
++ /* Allocate hardware structure */
++ c2dev = (struct c2_dev *) ib_alloc_device(sizeof(*c2dev));
++ if (!c2dev) {
++ printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n",
++ pci_name(pcidev));
++ ret = -ENOMEM;
++ iounmap(mmio_regs);
++ goto bail2;
++ }
++
++ memset(c2dev, 0, sizeof(*c2dev));
++ spin_lock_init(&c2dev->lock);
++ c2dev->pcidev = pcidev;
++ c2dev->cur_tx = 0;
++
++ /* Get the last RX index */
++ c2dev->cur_rx =
++ (be32_to_cpu(readl(mmio_regs + C2_REGS_HRX_CUR)) -
++ 0xffffc000) / sizeof(struct c2_rxp_desc);
++
++ /* Request an interrupt line for the driver */
++ ret = request_irq(pcidev->irq, c2_interrupt, SA_SHIRQ, DRV_NAME, c2dev);
++ if (ret) {
++ printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
++ pci_name(pcidev), pcidev->irq);
++ iounmap(mmio_regs);
++ goto bail3;
++ }
++
++ /* Set driver specific data */
++ pci_set_drvdata(pcidev, c2dev);
++
++ /* Initialize network device */
++ if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) {
++ iounmap(mmio_regs);
++ goto bail4;
++ }
++
++ /* Save off the actual size prior to unmapping mmio_regs */
++ kva_map_size = be32_to_cpu(readl(mmio_regs + C2_REGS_PCI_WINSIZE));
++
++ /* Unmap the adapter PCI registers in BAR4 */
++ iounmap(mmio_regs);
++
++ /* Register network device */
++ ret = register_netdev(netdev);
++ if (ret) {
++ printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n",
++ ret);
++ goto bail5;
++ }
++
++ /* Disable network packets */
++ netif_stop_queue(netdev);
++
++ /* Remap the adapter HRXDQ PA space to kernel VA space */
++ c2dev->mmio_rxp_ring = ioremap_nocache(reg4_start + C2_RXP_HRXDQ_OFFSET,
++ C2_RXP_HRXDQ_SIZE);
++ if (c2dev->mmio_rxp_ring == 0UL) {
++ printk(KERN_ERR PFX "Unable to remap MMIO HRXDQ region\n");
++ ret = -EIO;
++ goto bail6;
++ }
++
++ /* Remap the adapter HTXDQ PA space to kernel VA space */
++ c2dev->mmio_txp_ring = ioremap_nocache(reg4_start + C2_TXP_HTXDQ_OFFSET,
++ C2_TXP_HTXDQ_SIZE);
++ if (c2dev->mmio_txp_ring == 0UL) {
++ printk(KERN_ERR PFX "Unable to remap MMIO HTXDQ region\n");
++ ret = -EIO;
++ goto bail7;
++ }
++
++ /* Save off the current RX index in the last 4 bytes of the TXP Ring */
++ C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
++
++ /* Remap the PCI registers in adapter BAR0 to kernel VA space */
++ c2dev->regs = ioremap_nocache(reg0_start, reg0_len);
++ if (c2dev->regs == 0UL) {
++ printk(KERN_ERR PFX "Unable to remap BAR0\n");
++ ret = -EIO;
++ goto bail8;
++ }
++
++ /* Remap the PCI registers in adapter BAR4 to kernel VA space */
++ c2dev->pa = reg4_start + C2_PCI_REGS_OFFSET;
++ c2dev->kva = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET,
++ kva_map_size);
++ if (c2dev->kva == 0UL) {
++ printk(KERN_ERR PFX "Unable to remap BAR4\n");
++ ret = -EIO;
++ goto bail9;
++ }
++
++ /* Print out the MAC address */
++ c2_print_macaddr(netdev);
++
++ ret = c2_rnic_init(c2dev);
++ if (ret) {
++ printk(KERN_ERR PFX "c2_rnic_init failed: %d\n", ret);
++ goto bail10;
++ }
++
++ c2_register_device(c2dev);
++
++ return 0;
++
++ bail10:
++ iounmap(c2dev->kva);
++
++ bail9:
++ iounmap(c2dev->regs);
++
++ bail8:
++ iounmap(c2dev->mmio_txp_ring);
++
++ bail7:
++ iounmap(c2dev->mmio_rxp_ring);
++
++ bail6:
++ unregister_netdev(netdev);
++
++ bail5:
++ free_netdev(netdev);
++
++ bail4:
++ free_irq(pcidev->irq, c2dev);
++
++ bail3:
++ ib_dealloc_device(&c2dev->ibdev);
++
++ bail2:
++ pci_release_regions(pcidev);
++
++ bail1:
++ pci_disable_device(pcidev);
++
++ bail0:
++ return ret;
++}
++
++static void __devexit c2_remove(struct pci_dev *pcidev)
++{
++ struct c2_dev *c2dev = pci_get_drvdata(pcidev);
++ struct net_device *netdev = c2dev->netdev;
++
++ /* Unregister with OpenIB */
++ c2_unregister_device(c2dev);
++
++ /* Clean up the RNIC resources */
++ c2_rnic_term(c2dev);
++
++ /* Remove network device from the kernel */
++ unregister_netdev(netdev);
++
++ /* Free network device */
++ free_netdev(netdev);
++
++ /* Free the interrupt line */
++ free_irq(pcidev->irq, c2dev);
++
++ /* missing: Turn LEDs off here */
++
++ /* Unmap adapter PA space */
++ iounmap(c2dev->kva);
++ iounmap(c2dev->regs);
++ iounmap(c2dev->mmio_txp_ring);
++ iounmap(c2dev->mmio_rxp_ring);
++
++ /* Free the hardware structure */
++ ib_dealloc_device(&c2dev->ibdev);
++
++ /* Release reserved PCI I/O and memory resources */
++ pci_release_regions(pcidev);
++
++ /* Disable PCI device */
++ pci_disable_device(pcidev);
++
++ /* Clear driver specific data */
++ pci_set_drvdata(pcidev, NULL);
++}
++
++static struct pci_driver c2_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = c2_pci_table,
++ .probe = c2_probe,
++ .remove = __devexit_p(c2_remove),
++};
++
++static int __init c2_init_module(void)
++{
++ return pci_register_driver(&c2_pci_driver);
++}
++
++static void __exit c2_exit_module(void)
++{
++ pci_unregister_driver(&c2_pci_driver);
++}
++
++module_init(c2_init_module);
++module_exit(c2_exit_module);
+diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/infiniband/hw/amso1100/c2.h
+new file mode 100644
+index 0000000..1b17dcd
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2.h
+@@ -0,0 +1,551 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 __C2_H
++#define __C2_H
++
++#include <linux/netdevice.h>
++#include <linux/spinlock.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/dma-mapping.h>
++#include <linux/idr.h>
++#include <asm/semaphore.h>
++
++#include "c2_provider.h"
++#include "c2_mq.h"
++#include "c2_status.h"
++
++#define DRV_NAME "c2"
++#define DRV_VERSION "1.1"
++#define PFX DRV_NAME ": "
++
++#define BAR_0 0
++#define BAR_2 2
++#define BAR_4 4
++
++#define RX_BUF_SIZE (1536 + 8)
++#define ETH_JUMBO_MTU 9000
++#define C2_MAGIC "CEPHEUS"
++#define C2_VERSION 4
++#define C2_IVN (18 & 0x7fffffff)
++
++#define C2_REG0_SIZE (16 * 1024)
++#define C2_REG2_SIZE (2 * 1024 * 1024)
++#define C2_REG4_SIZE (256 * 1024 * 1024)
++#define C2_NUM_TX_DESC 341
++#define C2_NUM_RX_DESC 256
++#define C2_PCI_REGS_OFFSET (0x10000)
++#define C2_RXP_HRXDQ_OFFSET (((C2_REG4_SIZE)/2))
++#define C2_RXP_HRXDQ_SIZE (4096)
++#define C2_TXP_HTXDQ_OFFSET (((C2_REG4_SIZE)/2) + C2_RXP_HRXDQ_SIZE)
++#define C2_TXP_HTXDQ_SIZE (4096)
++#define C2_TX_TIMEOUT (6*HZ)
++
++/* CEPHEUS */
++static const u8 c2_magic[] = {
++ 0x43, 0x45, 0x50, 0x48, 0x45, 0x55, 0x53
++};
++
++enum adapter_pci_regs {
++ C2_REGS_MAGIC = 0x0000,
++ C2_REGS_VERS = 0x0008,
++ C2_REGS_IVN = 0x000C,
++ C2_REGS_PCI_WINSIZE = 0x0010,
++ C2_REGS_Q0_QSIZE = 0x0014,
++ C2_REGS_Q0_MSGSIZE = 0x0018,
++ C2_REGS_Q0_POOLSTART = 0x001C,
++ C2_REGS_Q0_SHARED = 0x0020,
++ C2_REGS_Q1_QSIZE = 0x0024,
++ C2_REGS_Q1_MSGSIZE = 0x0028,
++ C2_REGS_Q1_SHARED = 0x0030,
++ C2_REGS_Q2_QSIZE = 0x0034,
++ C2_REGS_Q2_MSGSIZE = 0x0038,
++ C2_REGS_Q2_SHARED = 0x0040,
++ C2_REGS_ENADDR = 0x004C,
++ C2_REGS_RDMA_ENADDR = 0x0054,
++ C2_REGS_HRX_CUR = 0x006C,
++};
++
++struct c2_adapter_pci_regs {
++ char reg_magic[8];
++ u32 version;
++ u32 ivn;
++ u32 pci_window_size;
++ u32 q0_q_size;
++ u32 q0_msg_size;
++ u32 q0_pool_start;
++ u32 q0_shared;
++ u32 q1_q_size;
++ u32 q1_msg_size;
++ u32 q1_pool_start;
++ u32 q1_shared;
++ u32 q2_q_size;
++ u32 q2_msg_size;
++ u32 q2_pool_start;
++ u32 q2_shared;
++ u32 log_start;
++ u32 log_size;
++ u8 host_enaddr[8];
++ u8 rdma_enaddr[8];
++ u32 crash_entry;
++ u32 crash_ready[2];
++ u32 fw_txd_cur;
++ u32 fw_hrxd_cur;
++ u32 fw_rxd_cur;
++};
++
++enum pci_regs {
++ C2_HISR = 0x0000,
++ C2_DISR = 0x0004,
++ C2_HIMR = 0x0008,
++ C2_DIMR = 0x000C,
++ C2_NISR0 = 0x0010,
++ C2_NISR1 = 0x0014,
++ C2_NIMR0 = 0x0018,
++ C2_NIMR1 = 0x001C,
++ C2_IDIS = 0x0020,
++};
++
++enum {
++ C2_PCI_HRX_INT = 1 << 8,
++ C2_PCI_HTX_INT = 1 << 17,
++ C2_PCI_HRX_QUI = 1 << 31,
++};
++
++/*
++ * Cepheus registers in BAR0.
++ */
++struct c2_pci_regs {
++ u32 hostisr;
++ u32 dmaisr;
++ u32 hostimr;
++ u32 dmaimr;
++ u32 netisr0;
++ u32 netisr1;
++ u32 netimr0;
++ u32 netimr1;
++ u32 int_disable;
++};
++
++/* TXP flags */
++enum c2_txp_flags {
++ TXP_HTXD_DONE = 0,
++ TXP_HTXD_READY = 1 << 0,
++ TXP_HTXD_UNINIT = 1 << 1,
++};
++
++/* RXP flags */
++enum c2_rxp_flags {
++ RXP_HRXD_UNINIT = 0,
++ RXP_HRXD_READY = 1 << 0,
++ RXP_HRXD_DONE = 1 << 1,
++};
++
++/* RXP status */
++enum c2_rxp_status {
++ RXP_HRXD_ZERO = 0,
++ RXP_HRXD_OK = 1 << 0,
++ RXP_HRXD_BUF_OV = 1 << 1,
++};
++
++/* TXP descriptor fields */
++enum txp_desc {
++ C2_TXP_FLAGS = 0x0000,
++ C2_TXP_LEN = 0x0002,
++ C2_TXP_ADDR = 0x0004,
++};
++
++/* RXP descriptor fields */
++enum rxp_desc {
++ C2_RXP_FLAGS = 0x0000,
++ C2_RXP_STATUS = 0x0002,
++ C2_RXP_COUNT = 0x0004,
++ C2_RXP_LEN = 0x0006,
++ C2_RXP_ADDR = 0x0008,
++};
++
++struct c2_txp_desc {
++ u16 flags;
++ u16 len;
++ u64 addr;
++} __attribute__ ((packed));
++
++struct c2_rxp_desc {
++ u16 flags;
++ u16 status;
++ u16 count;
++ u16 len;
++ u64 addr;
++} __attribute__ ((packed));
++
++struct c2_rxp_hdr {
++ u16 flags;
++ u16 status;
++ u16 len;
++ u16 rsvd;
++} __attribute__ ((packed));
++
++struct c2_tx_desc {
++ u32 len;
++ u32 status;
++ dma_addr_t next_offset;
++};
++
++struct c2_rx_desc {
++ u32 len;
++ u32 status;
++ dma_addr_t next_offset;
++};
++
++struct c2_alloc {
++ u32 last;
++ u32 max;
++ spinlock_t lock;
++ unsigned long *table;
++};
++
++struct c2_array {
++ struct {
++ void **page;
++ int used;
++ } *page_list;
++};
++
++/*
++ * The MQ shared pointer pool is organized as a linked list of
++ * chunks. Each chunk contains a linked list of free shared pointers
++ * that can be allocated to a given user mode client.
++ *
++ */
++struct sp_chunk {
++ struct sp_chunk *next;
++ dma_addr_t dma_addr;
++ DECLARE_PCI_UNMAP_ADDR(mapping);
++ u16 head;
++ u16 shared_ptr[0];
++};
++
++struct c2_pd_table {
++ u32 last;
++ u32 max;
++ spinlock_t lock;
++ unsigned long *table;
++};
++
++struct c2_qp_table {
++ struct idr idr;
++ spinlock_t lock;
++ int last;
++};
++
++struct c2_element {
++ struct c2_element *next;
++ void *ht_desc; /* host descriptor */
++ void __iomem *hw_desc; /* hardware descriptor */
++ struct sk_buff *skb;
++ dma_addr_t mapaddr;
++ u32 maplen;
++};
++
++struct c2_ring {
++ struct c2_element *to_clean;
++ struct c2_element *to_use;
++ struct c2_element *start;
++ unsigned long count;
++};
++
++struct c2_dev {
++ struct ib_device ibdev;
++ void __iomem *regs;
++ void __iomem *mmio_txp_ring; /* remapped adapter memory for hw rings */
++ void __iomem *mmio_rxp_ring;
++ spinlock_t lock;
++ struct pci_dev *pcidev;
++ struct net_device *netdev;
++ struct net_device *pseudo_netdev;
++ unsigned int cur_tx;
++ unsigned int cur_rx;
++ u32 adapter_handle;
++ int device_cap_flags;
++ void __iomem *kva; /* KVA device memory */
++ unsigned long pa; /* PA device memory */
++ void **qptr_array;
++
++ kmem_cache_t *host_msg_cache;
++
++ struct list_head cca_link; /* adapter list */
++ struct list_head eh_wakeup_list; /* event wakeup list */
++ wait_queue_head_t req_vq_wo;
++
++ /* Cached RNIC properties */
++ struct ib_device_attr props;
++
++ struct c2_pd_table pd_table;
++ struct c2_qp_table qp_table;
++ int ports; /* num of GigE ports */
++ int devnum;
++ spinlock_t vqlock; /* sync vbs req MQ */
++
++ /* Verbs Queues */
++ struct c2_mq req_vq; /* Verbs Request MQ */
++ struct c2_mq rep_vq; /* Verbs Reply MQ */
++ struct c2_mq aeq; /* Async Events MQ */
++
++ /* Kernel client MQs */
++ struct sp_chunk *kern_mqsp_pool;
++
++ /* Device updates these values when posting messages to a host
++ * target queue */
++ u16 req_vq_shared;
++ u16 rep_vq_shared;
++ u16 aeq_shared;
++ u16 irq_claimed;
++
++ /*
++ * Shared host target pages for user-accessible MQs.
++ */
++ int hthead; /* index of first free entry */
++ void *htpages; /* kernel vaddr */
++ int htlen; /* length of htpages memory */
++ void *htuva; /* user mapped vaddr */
++ spinlock_t htlock; /* serialize allocation */
++
++ u64 adapter_hint_uva; /* access to the activity FIFO */
++
++ // spinlock_t aeq_lock;
++ // spinlock_t rnic_lock;
++
++ u16 *hint_count;
++ dma_addr_t hint_count_dma;
++ u16 hints_read;
++
++ int init; /* TRUE if it's ready */
++ char ae_cache_name[16];
++ char vq_cache_name[16];
++};
++
++struct c2_port {
++ u32 msg_enable;
++ struct c2_dev *c2dev;
++ struct net_device *netdev;
++
++ spinlock_t tx_lock;
++ u32 tx_avail;
++ struct c2_ring tx_ring;
++ struct c2_ring rx_ring;
++
++ void *mem; /* PCI memory for host rings */
++ dma_addr_t dma;
++ unsigned long mem_size;
++
++ u32 rx_buf_size;
++
++ struct net_device_stats netstats;
++};
++
++/*
++ * Activity FIFO registers in BAR0.
++ */
++#define PCI_BAR0_HOST_HINT 0x100
++#define PCI_BAR0_ADAPTER_HINT 0x2000
++
++/*
++ * Ammasso PCI vendor id and Cepheus PCI device id.
++ */
++#define CQ_ARMED 0x01
++#define CQ_WAIT_FOR_DMA 0x80
++
++/*
++ * The format of a hint is as follows:
++ * Lower 16 bits are the count of hints for the queue.
++ * Next 15 bits are the qp_index
++ * Upper most bit depends on who reads it:
++ * If read by producer, then it means Full (1) or Not-Full (0)
++ * If read by consumer, then it means Empty (1) or Not-Empty (0)
++ */
++#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
++#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
++#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
++
++
++/*
++ * The following defines the offset in SDRAM for the c2_adapter_pci_regs_t
++ * struct.
++ */
++#define C2_ADAPTER_PCI_REGS_OFFSET 0x10000
++
++#ifndef readq
++static inline u64 readq(const void __iomem * addr)
++{
++ u64 ret = readl(addr + 4);
++ ret <<= 32;
++ ret |= readl(addr);
++
++ return ret;
++}
++#endif
++
++#ifndef writeq
++static inline void __raw_writeq(u64 val, void __iomem * addr)
++{
++ __raw_writel((u32) (val), addr);
++ __raw_writel((u32) (val >> 32), (addr + 4));
++}
++#endif
++
++#define C2_SET_CUR_RX(c2dev, cur_rx) \
++ __raw_writel(cpu_to_be32(cur_rx), c2dev->mmio_txp_ring + 4092)
++
++#define C2_GET_CUR_RX(c2dev) \
++ be32_to_cpu(readl(c2dev->mmio_txp_ring + 4092))
++
++static inline struct c2_dev *to_c2dev(struct ib_device *ibdev)
++{
++ return container_of(ibdev, struct c2_dev, ibdev);
++}
++
++static inline int c2_errno(void *reply)
++{
++ switch (c2_wr_get_result(reply)) {
++ case C2_OK:
++ return 0;
++ case CCERR_NO_BUFS:
++ case CCERR_INSUFFICIENT_RESOURCES:
++ case CCERR_ZERO_RDMA_READ_RESOURCES:
++ return -ENOMEM;
++ case CCERR_MR_IN_USE:
++ case CCERR_QP_IN_USE:
++ return -EBUSY;
++ case CCERR_ADDR_IN_USE:
++ return -EADDRINUSE;
++ case CCERR_ADDR_NOT_AVAIL:
++ return -EADDRNOTAVAIL;
++ case CCERR_CONN_RESET:
++ return -ECONNRESET;
++ case CCERR_NOT_IMPLEMENTED:
++ case CCERR_INVALID_WQE:
++ return -ENOSYS;
++ case CCERR_QP_NOT_PRIVILEGED:
++ return -EPERM;
++ case CCERR_STACK_ERROR:
++ return -EPROTO;
++ case CCERR_ACCESS_VIOLATION:
++ case CCERR_BASE_AND_BOUNDS_VIOLATION:
++ return -EFAULT;
++ case CCERR_STAG_STATE_NOT_INVALID:
++ case CCERR_INVALID_ADDRESS:
++ case CCERR_INVALID_CQ:
++ case CCERR_INVALID_EP:
++ case CCERR_INVALID_MODIFIER:
++ case CCERR_INVALID_MTU:
++ case CCERR_INVALID_PD_ID:
++ case CCERR_INVALID_QP:
++ case CCERR_INVALID_RNIC:
++ case CCERR_INVALID_STAG:
++ return -EINVAL;
++ default:
++ return -EAGAIN;
++ }
++}
++
++/* Device */
++extern int c2_register_device(struct c2_dev *c2dev);
++extern void c2_unregister_device(struct c2_dev *c2dev);
++extern int c2_rnic_init(struct c2_dev *c2dev);
++extern void c2_rnic_term(struct c2_dev *c2dev);
++extern void c2_rnic_interrupt(struct c2_dev *c2dev);
++extern int c2_del_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask);
++extern int c2_add_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask);
++
++/* QPs */
++extern int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd,
++ struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp);
++extern void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp);
++extern struct ib_qp *c2_get_qp(struct ib_device *device, int qpn);
++extern int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
++ struct ib_qp_attr *attr, int attr_mask);
++extern int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
++ int ord, int ird);
++extern int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
++ struct ib_send_wr **bad_wr);
++extern int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
++ struct ib_recv_wr **bad_wr);
++extern void __devinit c2_init_qp_table(struct c2_dev *c2dev);
++extern void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev);
++extern void c2_set_qp_state(struct c2_qp *, int);
++extern struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn);
++
++/* PDs */
++extern int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd);
++extern void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd);
++extern int __devinit c2_init_pd_table(struct c2_dev *c2dev);
++extern void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev);
++
++/* CQs */
++extern int c2_init_cq(struct c2_dev *c2dev, int entries,
++ struct c2_ucontext *ctx, struct c2_cq *cq);
++extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
++extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
++extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
++extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
++extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
++
++/* CM */
++extern int c2_llp_connect(struct iw_cm_id *cm_id,
++ struct iw_cm_conn_param *iw_param);
++extern int c2_llp_accept(struct iw_cm_id *cm_id,
++ struct iw_cm_conn_param *iw_param);
++extern int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata,
++ u8 pdata_len);
++extern int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog);
++extern int c2_llp_service_destroy(struct iw_cm_id *cm_id);
++
++/* MM */
++extern int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
++ int page_size, int pbl_depth, u32 length,
++ u32 off, u64 *va, enum c2_acf acf,
++ struct c2_mr *mr);
++extern int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index);
++
++/* AE */
++extern void c2_ae_event(struct c2_dev *c2dev, u32 mq_index);
++
++/* MQSP Allocator */
++extern int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
++ struct sp_chunk **root);
++extern void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root);
++extern u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
++ dma_addr_t *dma_addr, gfp_t gfp_mask);
++extern void c2_free_mqsp(u16 * mqsp);
++#endif
+diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c
+new file mode 100644
+index 0000000..a31439b
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_ae.c
+@@ -0,0 +1,319 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++#include "c2.h"
++#include <rdma/iw_cm.h>
++#include "c2_status.h"
++#include "c2_ae.h"
++
++static int c2_convert_cm_status(u32 c2_status)
++{
++ switch (c2_status) {
++ case C2_CONN_STATUS_SUCCESS:
++ return 0;
++ case C2_CONN_STATUS_REJECTED:
++ return -ENETRESET;
++ case C2_CONN_STATUS_REFUSED:
++ return -ECONNREFUSED;
++ case C2_CONN_STATUS_TIMEDOUT:
++ return -ETIMEDOUT;
++ case C2_CONN_STATUS_NETUNREACH:
++ return -ENETUNREACH;
++ case C2_CONN_STATUS_HOSTUNREACH:
++ return -EHOSTUNREACH;
++ case C2_CONN_STATUS_INVALID_RNIC:
++ return -EINVAL;
++ case C2_CONN_STATUS_INVALID_QP:
++ return -EINVAL;
++ case C2_CONN_STATUS_INVALID_QP_STATE:
++ return -EINVAL;
++ case C2_CONN_STATUS_ADDR_NOT_AVAIL:
++ return -EADDRNOTAVAIL;
++ default:
++ printk(KERN_ERR PFX
++ "%s - Unable to convert CM status: %d\n",
++ __FUNCTION__, c2_status);
++ return -EIO;
++ }
++}
++
++static const char* to_event_str(int event)
++{
++ static const char* event_str[] = {
++ "CCAE_REMOTE_SHUTDOWN",
++ "CCAE_ACTIVE_CONNECT_RESULTS",
++ "CCAE_CONNECTION_REQUEST",
++ "CCAE_LLP_CLOSE_COMPLETE",
++ "CCAE_TERMINATE_MESSAGE_RECEIVED",
++ "CCAE_LLP_CONNECTION_RESET",
++ "CCAE_LLP_CONNECTION_LOST",
++ "CCAE_LLP_SEGMENT_SIZE_INVALID",
++ "CCAE_LLP_INVALID_CRC",
++ "CCAE_LLP_BAD_FPDU",
++ "CCAE_INVALID_DDP_VERSION",
++ "CCAE_INVALID_RDMA_VERSION",
++ "CCAE_UNEXPECTED_OPCODE",
++ "CCAE_INVALID_DDP_QUEUE_NUMBER",
++ "CCAE_RDMA_READ_NOT_ENABLED",
++ "CCAE_RDMA_WRITE_NOT_ENABLED",
++ "CCAE_RDMA_READ_TOO_SMALL",
++ "CCAE_NO_L_BIT",
++ "CCAE_TAGGED_INVALID_STAG",
++ "CCAE_TAGGED_BASE_BOUNDS_VIOLATION",
++ "CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION",
++ "CCAE_TAGGED_INVALID_PD",
++ "CCAE_WRAP_ERROR",
++ "CCAE_BAD_CLOSE",
++ "CCAE_BAD_LLP_CLOSE",
++ "CCAE_INVALID_MSN_RANGE",
++ "CCAE_INVALID_MSN_GAP",
++ "CCAE_IRRQ_OVERFLOW",
++ "CCAE_IRRQ_MSN_GAP",
++ "CCAE_IRRQ_MSN_RANGE",
++ "CCAE_IRRQ_INVALID_STAG",
++ "CCAE_IRRQ_BASE_BOUNDS_VIOLATION",
++ "CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION",
++ "CCAE_IRRQ_INVALID_PD",
++ "CCAE_IRRQ_WRAP_ERROR",
++ "CCAE_CQ_SQ_COMPLETION_OVERFLOW",
++ "CCAE_CQ_RQ_COMPLETION_ERROR",
++ "CCAE_QP_SRQ_WQE_ERROR",
++ "CCAE_QP_LOCAL_CATASTROPHIC_ERROR",
++ "CCAE_CQ_OVERFLOW",
++ "CCAE_CQ_OPERATION_ERROR",
++ "CCAE_SRQ_LIMIT_REACHED",
++ "CCAE_QP_RQ_LIMIT_REACHED",
++ "CCAE_SRQ_CATASTROPHIC_ERROR",
++ "CCAE_RNIC_CATASTROPHIC_ERROR"
++ };
++
++ if (event < CCAE_REMOTE_SHUTDOWN ||
++ event > CCAE_RNIC_CATASTROPHIC_ERROR)
++ return "<invalid event>";
++
++ event -= CCAE_REMOTE_SHUTDOWN;
++ return event_str[event];
++}
++
++static const char *to_qp_state_str(int state)
++{
++ switch (state) {
++ case C2_QP_STATE_IDLE:
++ return "C2_QP_STATE_IDLE";
++ case C2_QP_STATE_CONNECTING:
++ return "C2_QP_STATE_CONNECTING";
++ case C2_QP_STATE_RTS:
++ return "C2_QP_STATE_RTS";
++ case C2_QP_STATE_CLOSING:
++ return "C2_QP_STATE_CLOSING";
++ case C2_QP_STATE_TERMINATE:
++ return "C2_QP_STATE_TERMINATE";
++ case C2_QP_STATE_ERROR:
++ return "C2_QP_STATE_ERROR";
++ default:
++ return "<invalid QP state>";
++ };
++}
++
++void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
++{
++ struct c2_mq *mq = c2dev->qptr_array[mq_index];
++ union c2wr *wr;
++ void *resource_user_context;
++ struct iw_cm_event cm_event;
++ struct ib_event ib_event;
++ enum c2_resource_indicator resource_indicator;
++ enum c2_event_id event_id;
++ unsigned long flags;
++ int status;
++
++ /*
++ * retreive the message
++ */
++ wr = c2_mq_consume(mq);
++ if (!wr)
++ return;
++
++ memset(&ib_event, 0, sizeof(ib_event));
++ memset(&cm_event, 0, sizeof(cm_event));
++
++ event_id = c2_wr_get_id(wr);
++ resource_indicator = be32_to_cpu(wr->ae.ae_generic.resource_type);
++ resource_user_context =
++ (void *) (unsigned long) wr->ae.ae_generic.user_context;
++
++ status = cm_event.status = c2_convert_cm_status(c2_wr_get_result(wr));
++
++ pr_debug("event received c2_dev=%p, event_id=%d, "
++ "resource_indicator=%d, user_context=%p, status = %d\n",
++ c2dev, event_id, resource_indicator, resource_user_context,
++ status);
++
++ switch (resource_indicator) {
++ case C2_RES_IND_QP:{
++
++ struct c2_qp *qp = (struct c2_qp *)resource_user_context;
++ struct iw_cm_id *cm_id = qp->cm_id;
++ struct c2wr_ae_active_connect_results *res;
++
++ if (!cm_id) {
++ pr_debug("event received, but cm_id is <nul>, qp=%p!\n",
++ qp);
++ goto ignore_it;
++ }
++ pr_debug("%s: event = %s, user_context=%llx, "
++ "resource_type=%x, "
++ "resource=%x, qp_state=%s\n",
++ __FUNCTION__,
++ to_event_str(event_id),
++ (unsigned long long) be64_to_cpu(wr->ae.ae_generic.user_context),
++ be32_to_cpu(wr->ae.ae_generic.resource_type),
++ be32_to_cpu(wr->ae.ae_generic.resource),
++ to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state)));
++
++ c2_set_qp_state(qp, be32_to_cpu(wr->ae.ae_generic.qp_state));
++
++ switch (event_id) {
++ case CCAE_ACTIVE_CONNECT_RESULTS:
++ res = &wr->ae.ae_active_connect_results;
++ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
++ cm_event.local_addr.sin_addr.s_addr = res->laddr;
++ cm_event.remote_addr.sin_addr.s_addr = res->raddr;
++ cm_event.local_addr.sin_port = res->lport;
++ cm_event.remote_addr.sin_port = res->rport;
++ if (status == 0) {
++ cm_event.private_data_len =
++ be32_to_cpu(res->private_data_length);
++ cm_event.private_data = res->private_data;
++ } else {
++ spin_lock_irqsave(&qp->lock, flags);
++ if (qp->cm_id) {
++ qp->cm_id->rem_ref(qp->cm_id);
++ qp->cm_id = NULL;
++ }
++ spin_unlock_irqrestore(&qp->lock, flags);
++ cm_event.private_data_len = 0;
++ cm_event.private_data = NULL;
++ }
++ if (cm_id->event_handler)
++ cm_id->event_handler(cm_id, &cm_event);
++ break;
++ case CCAE_TERMINATE_MESSAGE_RECEIVED:
++ case CCAE_CQ_SQ_COMPLETION_OVERFLOW:
++ ib_event.device = &c2dev->ibdev;
++ ib_event.element.qp = &qp->ibqp;
++ ib_event.event = IB_EVENT_QP_REQ_ERR;
++
++ if (qp->ibqp.event_handler)
++ qp->ibqp.event_handler(&ib_event,
++ qp->ibqp.
++ qp_context);
++ break;
++ case CCAE_BAD_CLOSE:
++ case CCAE_LLP_CLOSE_COMPLETE:
++ case CCAE_LLP_CONNECTION_RESET:
++ case CCAE_LLP_CONNECTION_LOST:
++ BUG_ON(cm_id->event_handler==(void*)0x6b6b6b6b);
++
++ spin_lock_irqsave(&qp->lock, flags);
++ if (qp->cm_id) {
++ qp->cm_id->rem_ref(qp->cm_id);
++ qp->cm_id = NULL;
++ }
++ spin_unlock_irqrestore(&qp->lock, flags);
++ cm_event.event = IW_CM_EVENT_CLOSE;
++ cm_event.status = 0;
++ if (cm_id->event_handler)
++ cm_id->event_handler(cm_id, &cm_event);
++ break;
++ default:
++ BUG_ON(1);
++ pr_debug("%s:%d Unexpected event_id=%d on QP=%p, "
++ "CM_ID=%p\n",
++ __FUNCTION__, __LINE__,
++ event_id, qp, cm_id);
++ break;
++ }
++ break;
++ }
++
++ case C2_RES_IND_EP:{
++
++ struct c2wr_ae_connection_request *req =
++ &wr->ae.ae_connection_request;
++ struct iw_cm_id *cm_id =
++ (struct iw_cm_id *)resource_user_context;
++
++ pr_debug("C2_RES_IND_EP event_id=%d\n", event_id);
++ if (event_id != CCAE_CONNECTION_REQUEST) {
++ pr_debug("%s: Invalid event_id: %d\n",
++ __FUNCTION__, event_id);
++ break;
++ }
++ cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
++ cm_event.provider_data = (void*)(unsigned long)req->cr_handle;
++ cm_event.local_addr.sin_addr.s_addr = req->laddr;
++ cm_event.remote_addr.sin_addr.s_addr = req->raddr;
++ cm_event.local_addr.sin_port = req->lport;
++ cm_event.remote_addr.sin_port = req->rport;
++ cm_event.private_data_len =
++ be32_to_cpu(req->private_data_length);
++ cm_event.private_data = req->private_data;
++
++ if (cm_id->event_handler)
++ cm_id->event_handler(cm_id, &cm_event);
++ break;
++ }
++
++ case C2_RES_IND_CQ:{
++ struct c2_cq *cq =
++ (struct c2_cq *) resource_user_context;
++
++ pr_debug("IB_EVENT_CQ_ERR\n");
++ ib_event.device = &c2dev->ibdev;
++ ib_event.element.cq = &cq->ibcq;
++ ib_event.event = IB_EVENT_CQ_ERR;
++
++ if (cq->ibcq.event_handler)
++ cq->ibcq.event_handler(&ib_event,
++ cq->ibcq.cq_context);
++ }
++
++ default:
++ printk("Bad resource indicator = %d\n",
++ resource_indicator);
++ break;
++ }
++
++ ignore_it:
++ c2_mq_free(mq);
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_ae.h b/drivers/infiniband/hw/amso1100/c2_ae.h
+new file mode 100644
+index 0000000..3a065c3
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_ae.h
+@@ -0,0 +1,108 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 _C2_AE_H_
++#define _C2_AE_H_
++
++/*
++ * WARNING: If you change this file, also bump C2_IVN_BASE
++ * in common/include/clustercore/c2_ivn.h.
++ */
++
++/*
++ * Asynchronous Event Identifiers
++ *
++ * These start at 0x80 only so it's obvious from inspection that
++ * they are not work-request statuses. This isn't critical.
++ *
++ * NOTE: these event id's must fit in eight bits.
++ */
++enum c2_event_id {
++ CCAE_REMOTE_SHUTDOWN = 0x80,
++ CCAE_ACTIVE_CONNECT_RESULTS,
++ CCAE_CONNECTION_REQUEST,
++ CCAE_LLP_CLOSE_COMPLETE,
++ CCAE_TERMINATE_MESSAGE_RECEIVED,
++ CCAE_LLP_CONNECTION_RESET,
++ CCAE_LLP_CONNECTION_LOST,
++ CCAE_LLP_SEGMENT_SIZE_INVALID,
++ CCAE_LLP_INVALID_CRC,
++ CCAE_LLP_BAD_FPDU,
++ CCAE_INVALID_DDP_VERSION,
++ CCAE_INVALID_RDMA_VERSION,
++ CCAE_UNEXPECTED_OPCODE,
++ CCAE_INVALID_DDP_QUEUE_NUMBER,
++ CCAE_RDMA_READ_NOT_ENABLED,
++ CCAE_RDMA_WRITE_NOT_ENABLED,
++ CCAE_RDMA_READ_TOO_SMALL,
++ CCAE_NO_L_BIT,
++ CCAE_TAGGED_INVALID_STAG,
++ CCAE_TAGGED_BASE_BOUNDS_VIOLATION,
++ CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION,
++ CCAE_TAGGED_INVALID_PD,
++ CCAE_WRAP_ERROR,
++ CCAE_BAD_CLOSE,
++ CCAE_BAD_LLP_CLOSE,
++ CCAE_INVALID_MSN_RANGE,
++ CCAE_INVALID_MSN_GAP,
++ CCAE_IRRQ_OVERFLOW,
++ CCAE_IRRQ_MSN_GAP,
++ CCAE_IRRQ_MSN_RANGE,
++ CCAE_IRRQ_INVALID_STAG,
++ CCAE_IRRQ_BASE_BOUNDS_VIOLATION,
++ CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION,
++ CCAE_IRRQ_INVALID_PD,
++ CCAE_IRRQ_WRAP_ERROR,
++ CCAE_CQ_SQ_COMPLETION_OVERFLOW,
++ CCAE_CQ_RQ_COMPLETION_ERROR,
++ CCAE_QP_SRQ_WQE_ERROR,
++ CCAE_QP_LOCAL_CATASTROPHIC_ERROR,
++ CCAE_CQ_OVERFLOW,
++ CCAE_CQ_OPERATION_ERROR,
++ CCAE_SRQ_LIMIT_REACHED,
++ CCAE_QP_RQ_LIMIT_REACHED,
++ CCAE_SRQ_CATASTROPHIC_ERROR,
++ CCAE_RNIC_CATASTROPHIC_ERROR
++/* WARNING If you add more id's, make sure their values fit in eight bits. */
++};
++
++/*
++ * Resource Indicators and Identifiers
++ */
++enum c2_resource_indicator {
++ C2_RES_IND_QP = 1,
++ C2_RES_IND_EP,
++ C2_RES_IND_CQ,
++ C2_RES_IND_SRQ,
++};
++
++#endif /* _C2_AE_H_ */
+diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/infiniband/hw/amso1100/c2_alloc.c
+new file mode 100644
+index 0000000..0315f99
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_alloc.c
+@@ -0,0 +1,143 @@
++/*
++ * Copyright (c) 2004 Topspin Communications. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/bitmap.h>
++
++#include "c2.h"
++
++static int c2_alloc_mqsp_chunk(struct c2_dev *c2dev, gfp_t gfp_mask,
++ struct sp_chunk **head)
++{
++ int i;
++ struct sp_chunk *new_head;
++ dma_addr_t dma_addr;
++
++ new_head = dma_alloc_coherent(&c2dev->pcidev->dev, PAGE_SIZE,
++ &dma_addr, gfp_mask);
++ if (new_head == NULL)
++ return -ENOMEM;
++
++ new_head->dma_addr = dma_addr;
++ pci_unmap_addr_set(new_head, mapping, new_head->dma_addr);
++
++ new_head->next = NULL;
++ new_head->head = 0;
++
++ /* build list where each index is the next free slot */
++ for (i = 0;
++ i < (PAGE_SIZE - sizeof(struct sp_chunk) -
++ sizeof(u16)) / sizeof(u16) - 1;
++ i++) {
++ new_head->shared_ptr[i] = i + 1;
++ }
++ /* terminate list */
++ new_head->shared_ptr[i] = 0xFFFF;
++
++ *head = new_head;
++ return 0;
++}
++
++int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
++ struct sp_chunk **root)
++{
++ return c2_alloc_mqsp_chunk(c2dev, gfp_mask, root);
++}
++
++void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root)
++{
++ struct sp_chunk *next;
++
++ while (root) {
++ next = root->next;
++ dma_free_coherent(&c2dev->pcidev->dev, PAGE_SIZE, root,
++ pci_unmap_addr(root, mapping));
++ root = next;
++ }
++}
++
++u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
++ dma_addr_t *dma_addr, gfp_t gfp_mask)
++{
++ u16 mqsp;
++
++ while (head) {
++ mqsp = head->head;
++ if (mqsp != 0xFFFF) {
++ head->head = head->shared_ptr[mqsp];
++ break;
++ } else if (head->next == NULL) {
++ if (c2_alloc_mqsp_chunk(c2dev, gfp_mask, &head->next) ==
++ 0) {
++ head = head->next;
++ mqsp = head->head;
++ head->head = head->shared_ptr[mqsp];
++ break;
++ } else
++ return NULL;
++ } else
++ head = head->next;
++ }
++ if (head) {
++ *dma_addr = head->dma_addr +
++ ((unsigned long) &(head->shared_ptr[mqsp]) -
++ (unsigned long) head);
++ pr_debug("%s addr %p dma_addr %llx\n", __FUNCTION__,
++ &(head->shared_ptr[mqsp]), (unsigned long long) *dma_addr);
++ return &(head->shared_ptr[mqsp]);
++ }
++ return NULL;
++}
++
++void c2_free_mqsp(u16 * mqsp)
++{
++ struct sp_chunk *head;
++ u16 idx;
++
++ /* The chunk containing this ptr begins at the page boundary */
++ head = (struct sp_chunk *) ((unsigned long) mqsp & PAGE_MASK);
++
++ /* Link head to new mqsp */
++ *mqsp = head->head;
++
++ /* Compute the shared_ptr index */
++ idx = ((unsigned long) mqsp & ~PAGE_MASK) >> 1;
++ idx -= (unsigned long) &(((struct sp_chunk *) 0)->shared_ptr[0]) >> 1;
++
++ /* Point this index at the head */
++ head->shared_ptr[idx] = head->head;
++
++ /* Point head at this index */
++ head->head = idx;
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_cm.c b/drivers/infiniband/hw/amso1100/c2_cm.c
+new file mode 100644
+index 0000000..75b93e9
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_cm.c
+@@ -0,0 +1,451 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ *
++ */
++#include "c2.h"
++#include "c2_wr.h"
++#include "c2_vq.h"
++#include <rdma/iw_cm.h>
++
++int c2_llp_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
++{
++ struct c2_dev *c2dev = to_c2dev(cm_id->device);
++ struct ib_qp *ibqp;
++ struct c2_qp *qp;
++ struct c2wr_qp_connect_req *wr; /* variable size needs a malloc. */
++ struct c2_vq_req *vq_req;
++ int err;
++
++ ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
++ if (!ibqp)
++ return -EINVAL;
++ qp = to_c2qp(ibqp);
++
++ /* Associate QP <--> CM_ID */
++ cm_id->provider_data = qp;
++ cm_id->add_ref(cm_id);
++ qp->cm_id = cm_id;
++
++ /*
++ * only support the max private_data length
++ */
++ if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
++ err = -EINVAL;
++ goto bail0;
++ }
++ /*
++ * Set the rdma read limits
++ */
++ err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
++ if (err)
++ goto bail0;
++
++ /*
++ * Create and send a WR_QP_CONNECT...
++ */
++ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
++ if (!wr) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ c2_wr_set_id(wr, CCWR_QP_CONNECT);
++ wr->hdr.context = 0;
++ wr->rnic_handle = c2dev->adapter_handle;
++ wr->qp_handle = qp->adapter_handle;
++
++ wr->remote_addr = cm_id->remote_addr.sin_addr.s_addr;
++ wr->remote_port = cm_id->remote_addr.sin_port;
++
++ /*
++ * Move any private data from the callers's buf into
++ * the WR.
++ */
++ if (iw_param->private_data) {
++ wr->private_data_length =
++ cpu_to_be32(iw_param->private_data_len);
++ memcpy(&wr->private_data[0], iw_param->private_data,
++ iw_param->private_data_len);
++ } else
++ wr->private_data_length = 0;
++
++ /*
++ * Send WR to adapter. NOTE: There is no synch reply from
++ * the adapter.
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) wr);
++ vq_req_free(c2dev, vq_req);
++
++ bail1:
++ kfree(wr);
++ bail0:
++ if (err) {
++ /*
++ * If we fail, release reference on QP and
++ * disassociate QP from CM_ID
++ */
++ cm_id->provider_data = NULL;
++ qp->cm_id = NULL;
++ cm_id->rem_ref(cm_id);
++ }
++ return err;
++}
++
++int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog)
++{
++ struct c2_dev *c2dev;
++ struct c2wr_ep_listen_create_req wr;
++ struct c2wr_ep_listen_create_rep *reply;
++ struct c2_vq_req *vq_req;
++ int err;
++
++ c2dev = to_c2dev(cm_id->device);
++ if (c2dev == NULL)
++ return -EINVAL;
++
++ /*
++ * Allocate verbs request.
++ */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ /*
++ * Build the WR
++ */
++ c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE);
++ wr.hdr.context = (u64) (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.local_addr = cm_id->local_addr.sin_addr.s_addr;
++ wr.local_port = cm_id->local_addr.sin_port;
++ wr.backlog = cpu_to_be32(backlog);
++ wr.user_context = (u64) (unsigned long) cm_id;
++
++ /*
++ * Reference the request struct. Dereferenced in the int handler.
++ */
++ vq_req_get(c2dev, vq_req);
++
++ /*
++ * Send WR to adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ /*
++ * Wait for reply from adapter
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail0;
++
++ /*
++ * Process reply
++ */
++ reply =
++ (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ if ((err = c2_errno(reply)) != 0)
++ goto bail1;
++
++ /*
++ * Keep the adapter handle. Used in subsequent destroy
++ */
++ cm_id->provider_data = (void*)(unsigned long) reply->ep_handle;
++
++ /*
++ * free vq stuff
++ */
++ vq_repbuf_free(c2dev, reply);
++ vq_req_free(c2dev, vq_req);
++
++ return 0;
++
++ bail1:
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++
++int c2_llp_service_destroy(struct iw_cm_id *cm_id)
++{
++
++ struct c2_dev *c2dev;
++ struct c2wr_ep_listen_destroy_req wr;
++ struct c2wr_ep_listen_destroy_rep *reply;
++ struct c2_vq_req *vq_req;
++ int err;
++
++ c2dev = to_c2dev(cm_id->device);
++ if (c2dev == NULL)
++ return -EINVAL;
++
++ /*
++ * Allocate verbs request.
++ */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ /*
++ * Build the WR
++ */
++ c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.ep_handle = (u32)(unsigned long)cm_id->provider_data;
++
++ /*
++ * reference the request struct. dereferenced in the int handler.
++ */
++ vq_req_get(c2dev, vq_req);
++
++ /*
++ * Send WR to adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ /*
++ * Wait for reply from adapter
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail0;
++
++ /*
++ * Process reply
++ */
++ reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++ if ((err = c2_errno(reply)) != 0)
++ goto bail1;
++
++ bail1:
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
++{
++ struct c2_dev *c2dev = to_c2dev(cm_id->device);
++ struct c2_qp *qp;
++ struct ib_qp *ibqp;
++ struct c2wr_cr_accept_req *wr; /* variable length WR */
++ struct c2_vq_req *vq_req;
++ struct c2wr_cr_accept_rep *reply; /* VQ Reply msg ptr. */
++ int err;
++
++ ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
++ if (!ibqp)
++ return -EINVAL;
++ qp = to_c2qp(ibqp);
++
++ /* Set the RDMA read limits */
++ err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
++ if (err)
++ goto bail0;
++
++ /* Allocate verbs request. */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++ vq_req->qp = qp;
++ vq_req->cm_id = cm_id;
++ vq_req->event = IW_CM_EVENT_ESTABLISHED;
++
++ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
++ if (!wr) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ /* Build the WR */
++ c2_wr_set_id(wr, CCWR_CR_ACCEPT);
++ wr->hdr.context = (unsigned long) vq_req;
++ wr->rnic_handle = c2dev->adapter_handle;
++ wr->ep_handle = (u32) (unsigned long) cm_id->provider_data;
++ wr->qp_handle = qp->adapter_handle;
++
++ /* Replace the cr_handle with the QP after accept */
++ cm_id->provider_data = qp;
++ cm_id->add_ref(cm_id);
++ qp->cm_id = cm_id;
++
++ cm_id->provider_data = qp;
++
++ /* Validate private_data length */
++ if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
++ err = -EINVAL;
++ goto bail1;
++ }
++
++ if (iw_param->private_data) {
++ wr->private_data_length = cpu_to_be32(iw_param->private_data_len);
++ memcpy(&wr->private_data[0],
++ iw_param->private_data, iw_param->private_data_len);
++ } else
++ wr->private_data_length = 0;
++
++ /* Reference the request struct. Dereferenced in the int handler. */
++ vq_req_get(c2dev, vq_req);
++
++ /* Send WR to adapter */
++ err = vq_send_wr(c2dev, (union c2wr *) wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail1;
++ }
++
++ /* Wait for reply from adapter */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail1;
++
++ /* Check that reply is present */
++ reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ err = c2_errno(reply);
++ vq_repbuf_free(c2dev, reply);
++
++ if (!err)
++ c2_set_qp_state(qp, C2_QP_STATE_RTS);
++ bail1:
++ kfree(wr);
++ vq_req_free(c2dev, vq_req);
++ bail0:
++ if (err) {
++ /*
++ * If we fail, release reference on QP and
++ * disassociate QP from CM_ID
++ */
++ cm_id->provider_data = NULL;
++ qp->cm_id = NULL;
++ cm_id->rem_ref(cm_id);
++ }
++ return err;
++}
++
++int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
++{
++ struct c2_dev *c2dev;
++ struct c2wr_cr_reject_req wr;
++ struct c2_vq_req *vq_req;
++ struct c2wr_cr_reject_rep *reply;
++ int err;
++
++ c2dev = to_c2dev(cm_id->device);
++
++ /*
++ * Allocate verbs request.
++ */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ /*
++ * Build the WR
++ */
++ c2_wr_set_id(&wr, CCWR_CR_REJECT);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.ep_handle = (u32) (unsigned long) cm_id->provider_data;
++
++ /*
++ * reference the request struct. dereferenced in the int handler.
++ */
++ vq_req_get(c2dev, vq_req);
++
++ /*
++ * Send WR to adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ /*
++ * Wait for reply from adapter
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail0;
++
++ /*
++ * Process reply
++ */
++ reply = (struct c2wr_cr_reject_rep *) (unsigned long)
++ vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++ err = c2_errno(reply);
++ /*
++ * free vq stuff
++ */
++ vq_repbuf_free(c2dev, reply);
++
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
+new file mode 100644
+index 0000000..05c9154
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_cq.c
+@@ -0,0 +1,427 @@
++/*
++ * 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.
++ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
++ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ *
++ */
++#include "c2.h"
++#include "c2_vq.h"
++#include "c2_status.h"
++
++#define C2_CQ_MSG_SIZE ((sizeof(struct c2wr_ce) + 32-1) & ~(32-1))
++
++static struct c2_cq *c2_cq_get(struct c2_dev *c2dev, int cqn)
++{
++ struct c2_cq *cq;
++ unsigned long flags;
++
++ spin_lock_irqsave(&c2dev->lock, flags);
++ cq = c2dev->qptr_array[cqn];
++ if (!cq) {
++ spin_unlock_irqrestore(&c2dev->lock, flags);
++ return NULL;
++ }
++ atomic_inc(&cq->refcount);
++ spin_unlock_irqrestore(&c2dev->lock, flags);
++ return cq;
++}
++
++static void c2_cq_put(struct c2_cq *cq)
++{
++ if (atomic_dec_and_test(&cq->refcount))
++ wake_up(&cq->wait);
++}
++
++void c2_cq_event(struct c2_dev *c2dev, u32 mq_index)
++{
++ struct c2_cq *cq;
++
++ cq = c2_cq_get(c2dev, mq_index);
++ if (!cq) {
++ printk("discarding events on destroyed CQN=%d\n", mq_index);
++ return;
++ }
++
++ (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
++ c2_cq_put(cq);
++}
++
++void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index)
++{
++ struct c2_cq *cq;
++ struct c2_mq *q;
++
++ cq = c2_cq_get(c2dev, mq_index);
++ if (!cq)
++ return;
++
++ spin_lock_irq(&cq->lock);
++ q = &cq->mq;
++ if (q && !c2_mq_empty(q)) {
++ u16 priv = q->priv;
++ struct c2wr_ce *msg;
++
++ while (priv != be16_to_cpu(*q->shared)) {
++ msg = (struct c2wr_ce *)
++ (q->msg_pool.host + priv * q->msg_size);
++ if (msg->qp_user_context == (u64) (unsigned long) qp) {
++ msg->qp_user_context = (u64) 0;
++ }
++ priv = (priv + 1) % q->q_size;
++ }
++ }
++ spin_unlock_irq(&cq->lock);
++ c2_cq_put(cq);
++}
++
++static inline enum ib_wc_status c2_cqe_status_to_openib(u8 status)
++{
++ switch (status) {
++ case C2_OK:
++ return IB_WC_SUCCESS;
++ case CCERR_FLUSHED:
++ return IB_WC_WR_FLUSH_ERR;
++ case CCERR_BASE_AND_BOUNDS_VIOLATION:
++ return IB_WC_LOC_PROT_ERR;
++ case CCERR_ACCESS_VIOLATION:
++ return IB_WC_LOC_ACCESS_ERR;
++ case CCERR_TOTAL_LENGTH_TOO_BIG:
++ return IB_WC_LOC_LEN_ERR;
++ case CCERR_INVALID_WINDOW:
++ return IB_WC_MW_BIND_ERR;
++ default:
++ return IB_WC_GENERAL_ERR;
++ }
++}
++
++
++static inline int c2_poll_one(struct c2_dev *c2dev,
++ struct c2_cq *cq, struct ib_wc *entry)
++{
++ struct c2wr_ce *ce;
++ struct c2_qp *qp;
++ int is_recv = 0;
++
++ ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
++ if (!ce) {
++ return -EAGAIN;
++ }
++
++ /*
++ * if the qp returned is null then this qp has already
++ * been freed and we are unable process the completion.
++ * try pulling the next message
++ */
++ while ((qp =
++ (struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) {
++ c2_mq_free(&cq->mq);
++ ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
++ if (!ce)
++ return -EAGAIN;
++ }
++
++ entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
++ entry->wr_id = ce->hdr.context;
++ entry->qp_num = ce->handle;
++ entry->wc_flags = 0;
++ entry->slid = 0;
++ entry->sl = 0;
++ entry->src_qp = 0;
++ entry->dlid_path_bits = 0;
++ entry->pkey_index = 0;
++
++ switch (c2_wr_get_id(ce)) {
++ case C2_WR_TYPE_SEND:
++ entry->opcode = IB_WC_SEND;
++ break;
++ case C2_WR_TYPE_RDMA_WRITE:
++ entry->opcode = IB_WC_RDMA_WRITE;
++ break;
++ case C2_WR_TYPE_RDMA_READ:
++ entry->opcode = IB_WC_RDMA_READ;
++ break;
++ case C2_WR_TYPE_BIND_MW:
++ entry->opcode = IB_WC_BIND_MW;
++ break;
++ case C2_WR_TYPE_RECV:
++ entry->byte_len = be32_to_cpu(ce->bytes_rcvd);
++ entry->opcode = IB_WC_RECV;
++ is_recv = 1;
++ break;
++ default:
++ break;
++ }
++
++ /* consume the WQEs */
++ if (is_recv)
++ c2_mq_lconsume(&qp->rq_mq, 1);
++ else
++ c2_mq_lconsume(&qp->sq_mq,
++ be32_to_cpu(c2_wr_get_wqe_count(ce)) + 1);
++
++ /* free the message */
++ c2_mq_free(&cq->mq);
++
++ return 0;
++}
++
++int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
++{
++ struct c2_dev *c2dev = to_c2dev(ibcq->device);
++ struct c2_cq *cq = to_c2cq(ibcq);
++ unsigned long flags;
++ int npolled, err;
++
++ spin_lock_irqsave(&cq->lock, flags);
++
++ for (npolled = 0; npolled < num_entries; ++npolled) {
++
++ err = c2_poll_one(c2dev, cq, entry + npolled);
++ if (err)
++ break;
++ }
++
++ spin_unlock_irqrestore(&cq->lock, flags);
++
++ return npolled;
++}
++
++int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
++{
++ struct c2_mq_shared __iomem *shared;
++ struct c2_cq *cq;
++
++ cq = to_c2cq(ibcq);
++ shared = cq->mq.peer;
++
++ if (notify == IB_CQ_NEXT_COMP)
++ writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
++ else if (notify == IB_CQ_SOLICITED)
++ writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
++ else
++ return -EINVAL;
++
++ writeb(CQ_WAIT_FOR_DMA | CQ_ARMED, &shared->armed);
++
++ /*
++ * Now read back shared->armed to make the PCI
++ * write synchronous. This is necessary for
++ * correct cq notification semantics.
++ */
++ readb(&shared->armed);
++
++ return 0;
++}
++
++static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)
++{
++ dma_free_coherent(&c2dev->pcidev->dev, mq->q_size * mq->msg_size,
++ mq->msg_pool.host, pci_unmap_addr(mq, mapping));
++}
++
++static int c2_alloc_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq, int q_size,
++ int msg_size)
++{
++ u8 *pool_start;
++
++ pool_start = dma_alloc_coherent(&c2dev->pcidev->dev, q_size * msg_size,
++ &mq->host_dma, GFP_KERNEL);
++ if (!pool_start)
++ return -ENOMEM;
++
++ c2_mq_rep_init(mq,
++ 0, /* index (currently unknown) */
++ q_size,
++ msg_size,
++ pool_start,
++ NULL, /* peer (currently unknown) */
++ C2_MQ_HOST_TARGET);
++
++ pci_unmap_addr_set(mq, mapping, mq->host_dma);
++
++ return 0;
++}
++
++int c2_init_cq(struct c2_dev *c2dev, int entries,
++ struct c2_ucontext *ctx, struct c2_cq *cq)
++{
++ struct c2wr_cq_create_req wr;
++ struct c2wr_cq_create_rep *reply;
++ unsigned long peer_pa;
++ struct c2_vq_req *vq_req;
++ int err;
++
++ might_sleep();
++
++ cq->ibcq.cqe = entries - 1;
++ cq->is_kernel = !ctx;
++
++ /* Allocate a shared pointer */
++ cq->mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &cq->mq.shared_dma, GFP_KERNEL);
++ if (!cq->mq.shared)
++ return -ENOMEM;
++
++ /* Allocate pages for the message pool */
++ err = c2_alloc_cq_buf(c2dev, &cq->mq, entries + 1, C2_CQ_MSG_SIZE);
++ if (err)
++ goto bail0;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_CQ_CREATE);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.msg_size = cpu_to_be32(cq->mq.msg_size);
++ wr.depth = cpu_to_be32(cq->mq.q_size);
++ wr.shared_ht = cpu_to_be64(cq->mq.shared_dma);
++ wr.msg_pool = cpu_to_be64(cq->mq.host_dma);
++ wr.user_context = (u64) (unsigned long) (cq);
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail2;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail2;
++
++ reply = (struct c2wr_cq_create_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail2;
++ }
++
++ if ((err = c2_errno(reply)) != 0)
++ goto bail3;
++
++ cq->adapter_handle = reply->cq_handle;
++ cq->mq.index = be32_to_cpu(reply->mq_index);
++
++ peer_pa = c2dev->pa + be32_to_cpu(reply->adapter_shared);
++ cq->mq.peer = ioremap_nocache(peer_pa, PAGE_SIZE);
++ if (!cq->mq.peer) {
++ err = -ENOMEM;
++ goto bail3;
++ }
++
++ vq_repbuf_free(c2dev, reply);
++ vq_req_free(c2dev, vq_req);
++
++ spin_lock_init(&cq->lock);
++ atomic_set(&cq->refcount, 1);
++ init_waitqueue_head(&cq->wait);
++
++ /*
++ * Use the MQ index allocated by the adapter to
++ * store the CQ in the qptr_array
++ */
++ cq->cqn = cq->mq.index;
++ c2dev->qptr_array[cq->cqn] = cq;
++
++ return 0;
++
++ bail3:
++ vq_repbuf_free(c2dev, reply);
++ bail2:
++ vq_req_free(c2dev, vq_req);
++ bail1:
++ c2_free_cq_buf(c2dev, &cq->mq);
++ bail0:
++ c2_free_mqsp(cq->mq.shared);
++
++ return err;
++}
++
++void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq)
++{
++ int err;
++ struct c2_vq_req *vq_req;
++ struct c2wr_cq_destroy_req wr;
++ struct c2wr_cq_destroy_rep *reply;
++
++ might_sleep();
++
++ /* Clear CQ from the qptr array */
++ spin_lock_irq(&c2dev->lock);
++ c2dev->qptr_array[cq->mq.index] = NULL;
++ atomic_dec(&cq->refcount);
++ spin_unlock_irq(&c2dev->lock);
++
++ wait_event(cq->wait, !atomic_read(&cq->refcount));
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req) {
++ goto bail0;
++ }
++
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_CQ_DESTROY);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.cq_handle = cq->adapter_handle;
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail1;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail1;
++
++ reply = (struct c2wr_cq_destroy_rep *) (unsigned long) (vq_req->reply_msg);
++
++ vq_repbuf_free(c2dev, reply);
++ bail1:
++ vq_req_free(c2dev, vq_req);
++ bail0:
++ if (cq->is_kernel) {
++ c2_free_cq_buf(c2dev, &cq->mq);
++ }
++
++ return;
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_intr.c b/drivers/infiniband/hw/amso1100/c2_intr.c
+new file mode 100644
+index 0000000..0d0bc33
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_intr.c
+@@ -0,0 +1,209 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++#include "c2.h"
++#include <rdma/iw_cm.h>
++#include "c2_vq.h"
++
++static void handle_mq(struct c2_dev *c2dev, u32 index);
++static void handle_vq(struct c2_dev *c2dev, u32 mq_index);
++
++/*
++ * Handle RNIC interrupts
++ */
++void c2_rnic_interrupt(struct c2_dev *c2dev)
++{
++ unsigned int mq_index;
++
++ while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {
++ mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);
++ if (mq_index & 0x80000000) {
++ break;
++ }
++
++ c2dev->hints_read++;
++ handle_mq(c2dev, mq_index);
++ }
++
++}
++
++/*
++ * Top level MQ handler
++ */
++static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
++{
++ if (c2dev->qptr_array[mq_index] == NULL) {
++ pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
++ mq_index);
++ return;
++ }
++
++ switch (mq_index) {
++ case (0):
++ /*
++ * An index of 0 in the activity queue
++ * indicates the req vq now has messages
++ * available...
++ *
++ * Wake up any waiters waiting on req VQ
++ * message availability.
++ */
++ wake_up(&c2dev->req_vq_wo);
++ break;
++ case (1):
++ handle_vq(c2dev, mq_index);
++ break;
++ case (2):
++ /* We have to purge the VQ in case there are pending
++ * accept reply requests that would result in the
++ * generation of an ESTABLISHED event. If we don't
++ * generate these first, a CLOSE event could end up
++ * being delivered before the ESTABLISHED event.
++ */
++ handle_vq(c2dev, 1);
++
++ c2_ae_event(c2dev, mq_index);
++ break;
++ default:
++ /* There is no event synchronization between CQ events
++ * and AE or CM events. In fact, CQE could be
++ * delivered for all of the I/O up to and including the
++ * FLUSH for a peer disconenct prior to the ESTABLISHED
++ * event being delivered to the app. The reason for this
++ * is that CM events are delivered on a thread, while AE
++ * and CM events are delivered on interrupt context.
++ */
++ c2_cq_event(c2dev, mq_index);
++ break;
++ }
++
++ return;
++}
++
++/*
++ * Handles verbs WR replies.
++ */
++static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
++{
++ void *adapter_msg, *reply_msg;
++ struct c2wr_hdr *host_msg;
++ struct c2wr_hdr tmp;
++ struct c2_mq *reply_vq;
++ struct c2_vq_req *req;
++ struct iw_cm_event cm_event;
++ int err;
++
++ reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index];
++
++ /*
++ * get next msg from mq_index into adapter_msg.
++ * don't free it yet.
++ */
++ adapter_msg = c2_mq_consume(reply_vq);
++ if (adapter_msg == NULL) {
++ return;
++ }
++
++ host_msg = vq_repbuf_alloc(c2dev);
++
++ /*
++ * If we can't get a host buffer, then we'll still
++ * wakeup the waiter, we just won't give him the msg.
++ * It is assumed the waiter will deal with this...
++ */
++ if (!host_msg) {
++ pr_debug("handle_vq: no repbufs!\n");
++
++ /*
++ * just copy the WR header into a local variable.
++ * this allows us to still demux on the context
++ */
++ host_msg = &tmp;
++ memcpy(host_msg, adapter_msg, sizeof(tmp));
++ reply_msg = NULL;
++ } else {
++ memcpy(host_msg, adapter_msg, reply_vq->msg_size);
++ reply_msg = host_msg;
++ }
++
++ /*
++ * consume the msg from the MQ
++ */
++ c2_mq_free(reply_vq);
++
++ /*
++ * wakeup the waiter.
++ */
++ req = (struct c2_vq_req *) (unsigned long) host_msg->context;
++ if (req == NULL) {
++ /*
++ * We should never get here, as the adapter should
++ * never send us a reply that we're not expecting.
++ */
++ vq_repbuf_free(c2dev, host_msg);
++ pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");
++ return;
++ }
++
++ err = c2_errno(reply_msg);
++ if (!err) switch (req->event) {
++ case IW_CM_EVENT_ESTABLISHED:
++ c2_set_qp_state(req->qp,
++ C2_QP_STATE_RTS);
++ case IW_CM_EVENT_CLOSE:
++
++ /*
++ * Move the QP to RTS if this is
++ * the established event
++ */
++ cm_event.event = req->event;
++ cm_event.status = 0;
++ cm_event.local_addr = req->cm_id->local_addr;
++ cm_event.remote_addr = req->cm_id->remote_addr;
++ cm_event.private_data = NULL;
++ cm_event.private_data_len = 0;
++ req->cm_id->event_handler(req->cm_id, &cm_event);
++ break;
++ default:
++ break;
++ }
++
++ req->reply_msg = (u64) (unsigned long) (reply_msg);
++ atomic_set(&req->reply_ready, 1);
++ wake_up(&req->wait_object);
++
++ /*
++ * If the request was cancelled, then this put will
++ * free the vq_req memory...and reply_msg!!!
++ */
++ vq_req_put(c2dev, req);
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_mm.c b/drivers/infiniband/hw/amso1100/c2_mm.c
+new file mode 100644
+index 0000000..1e4f464
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_mm.c
+@@ -0,0 +1,375 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++#include "c2.h"
++#include "c2_vq.h"
++
++#define PBL_VIRT 1
++#define PBL_PHYS 2
++
++/*
++ * Send all the PBL messages to convey the remainder of the PBL
++ * Wait for the adapter's reply on the last one.
++ * This is indicated by setting the MEM_PBL_COMPLETE in the flags.
++ *
++ * NOTE: vq_req is _not_ freed by this function. The VQ Host
++ * Reply buffer _is_ freed by this function.
++ */
++static int
++send_pbl_messages(struct c2_dev *c2dev, u32 stag_index,
++ unsigned long va, u32 pbl_depth,
++ struct c2_vq_req *vq_req, int pbl_type)
++{
++ u32 pbe_count; /* amt that fits in a PBL msg */
++ u32 count; /* amt in this PBL MSG. */
++ struct c2wr_nsmr_pbl_req *wr; /* PBL WR ptr */
++ struct c2wr_nsmr_pbl_rep *reply; /* reply ptr */
++ int err, pbl_virt, pbl_index, i;
++
++ switch (pbl_type) {
++ case PBL_VIRT:
++ pbl_virt = 1;
++ break;
++ case PBL_PHYS:
++ pbl_virt = 0;
++ break;
++ default:
++ return -EINVAL;
++ break;
++ }
++
++ pbe_count = (c2dev->req_vq.msg_size -
++ sizeof(struct c2wr_nsmr_pbl_req)) / sizeof(u64);
++ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
++ if (!wr) {
++ return -ENOMEM;
++ }
++ c2_wr_set_id(wr, CCWR_NSMR_PBL);
++
++ /*
++ * Only the last PBL message will generate a reply from the verbs,
++ * so we set the context to 0 indicating there is no kernel verbs
++ * handler blocked awaiting this reply.
++ */
++ wr->hdr.context = 0;
++ wr->rnic_handle = c2dev->adapter_handle;
++ wr->stag_index = stag_index; /* already swapped */
++ wr->flags = 0;
++ pbl_index = 0;
++ while (pbl_depth) {
++ count = min(pbe_count, pbl_depth);
++ wr->addrs_length = cpu_to_be32(count);
++
++ /*
++ * If this is the last message, then reference the
++ * vq request struct cuz we're gonna wait for a reply.
++ * also make this PBL msg as the last one.
++ */
++ if (count == pbl_depth) {
++ /*
++ * reference the request struct. dereferenced in the
++ * int handler.
++ */
++ vq_req_get(c2dev, vq_req);
++ wr->flags = cpu_to_be32(MEM_PBL_COMPLETE);
++
++ /*
++ * This is the last PBL message.
++ * Set the context to our VQ Request Object so we can
++ * wait for the reply.
++ */
++ wr->hdr.context = (unsigned long) vq_req;
++ }
++
++ /*
++ * If pbl_virt is set then va is a virtual address
++ * that describes a virtually contiguous memory
++ * allocation. The wr needs the start of each virtual page
++ * to be converted to the corresponding physical address
++ * of the page. If pbl_virt is not set then va is an array
++ * of physical addresses and there is no conversion to do.
++ * Just fill in the wr with what is in the array.
++ */
++ for (i = 0; i < count; i++) {
++ if (pbl_virt) {
++ va += PAGE_SIZE;
++ } else {
++ wr->paddrs[i] =
++ cpu_to_be64(((u64 *)va)[pbl_index + i]);
++ }
++ }
++
++ /*
++ * Send WR to adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) wr);
++ if (err) {
++ if (count <= pbe_count) {
++ vq_req_put(c2dev, vq_req);
++ }
++ goto bail0;
++ }
++ pbl_depth -= count;
++ pbl_index += count;
++ }
++
++ /*
++ * Now wait for the reply...
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail0;
++ }
++
++ /*
++ * Process reply
++ */
++ reply = (struct c2wr_nsmr_pbl_rep *) (unsigned long) vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ err = c2_errno(reply);
++
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ kfree(wr);
++ return err;
++}
++
++#define C2_PBL_MAX_DEPTH 131072
++int
++c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
++ int page_size, int pbl_depth, u32 length,
++ u32 offset, u64 *va, enum c2_acf acf,
++ struct c2_mr *mr)
++{
++ struct c2_vq_req *vq_req;
++ struct c2wr_nsmr_register_req *wr;
++ struct c2wr_nsmr_register_rep *reply;
++ u16 flags;
++ int i, pbe_count, count;
++ int err;
++
++ if (!va || !length || !addr_list || !pbl_depth)
++ return -EINTR;
++
++ /*
++ * Verify PBL depth is within rnic max
++ */
++ if (pbl_depth > C2_PBL_MAX_DEPTH) {
++ return -EINTR;
++ }
++
++ /*
++ * allocate verbs request object
++ */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
++ if (!wr) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ /*
++ * build the WR
++ */
++ c2_wr_set_id(wr, CCWR_NSMR_REGISTER);
++ wr->hdr.context = (unsigned long) vq_req;
++ wr->rnic_handle = c2dev->adapter_handle;
++
++ flags = (acf | MEM_VA_BASED | MEM_REMOTE);
++
++ /*
++ * compute how many pbes can fit in the message
++ */
++ pbe_count = (c2dev->req_vq.msg_size -
++ sizeof(struct c2wr_nsmr_register_req)) / sizeof(u64);
++
++ if (pbl_depth <= pbe_count) {
++ flags |= MEM_PBL_COMPLETE;
++ }
++ wr->flags = cpu_to_be16(flags);
++ wr->stag_key = 0; //stag_key;
++ wr->va = cpu_to_be64(*va);
++ wr->pd_id = mr->pd->pd_id;
++ wr->pbe_size = cpu_to_be32(page_size);
++ wr->length = cpu_to_be32(length);
++ wr->pbl_depth = cpu_to_be32(pbl_depth);
++ wr->fbo = cpu_to_be32(offset);
++ count = min(pbl_depth, pbe_count);
++ wr->addrs_length = cpu_to_be32(count);
++
++ /*
++ * fill out the PBL for this message
++ */
++ for (i = 0; i < count; i++) {
++ wr->paddrs[i] = cpu_to_be64(addr_list[i]);
++ }
++
++ /*
++ * regerence the request struct
++ */
++ vq_req_get(c2dev, vq_req);
++
++ /*
++ * send the WR to the adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail1;
++ }
++
++ /*
++ * wait for reply from adapter
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail1;
++ }
++
++ /*
++ * process reply
++ */
++ reply =
++ (struct c2wr_nsmr_register_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++ if ((err = c2_errno(reply))) {
++ goto bail2;
++ }
++ //*p_pb_entries = be32_to_cpu(reply->pbl_depth);
++ mr->ibmr.lkey = mr->ibmr.rkey = be32_to_cpu(reply->stag_index);
++ vq_repbuf_free(c2dev, reply);
++
++ /*
++ * if there are still more PBEs we need to send them to
++ * the adapter and wait for a reply on the final one.
++ * reuse vq_req for this purpose.
++ */
++ pbl_depth -= count;
++ if (pbl_depth) {
++
++ vq_req->reply_msg = (unsigned long) NULL;
++ atomic_set(&vq_req->reply_ready, 0);
++ err = send_pbl_messages(c2dev,
++ cpu_to_be32(mr->ibmr.lkey),
++ (unsigned long) &addr_list[i],
++ pbl_depth, vq_req, PBL_PHYS);
++ if (err) {
++ goto bail1;
++ }
++ }
++
++ vq_req_free(c2dev, vq_req);
++ kfree(wr);
++
++ return err;
++
++ bail2:
++ vq_repbuf_free(c2dev, reply);
++ bail1:
++ kfree(wr);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index)
++{
++ struct c2_vq_req *vq_req; /* verbs request object */
++ struct c2wr_stag_dealloc_req wr; /* work request */
++ struct c2wr_stag_dealloc_rep *reply; /* WR reply */
++ int err;
++
++
++ /*
++ * allocate verbs request object
++ */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req) {
++ return -ENOMEM;
++ }
++
++ /*
++ * Build the WR
++ */
++ c2_wr_set_id(&wr, CCWR_STAG_DEALLOC);
++ wr.hdr.context = (u64) (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.stag_index = cpu_to_be32(stag_index);
++
++ /*
++ * reference the request struct. dereferenced in the int handler.
++ */
++ vq_req_get(c2dev, vq_req);
++
++ /*
++ * Send WR to adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ /*
++ * Wait for reply from adapter
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail0;
++ }
++
++ /*
++ * Process reply
++ */
++ reply = (struct c2wr_stag_dealloc_rep *) (unsigned long) vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ err = c2_errno(reply);
++
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_mq.c b/drivers/infiniband/hw/amso1100/c2_mq.c
+new file mode 100644
+index 0000000..b88a755
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_mq.c
+@@ -0,0 +1,174 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++#include "c2.h"
++#include "c2_mq.h"
++
++void *c2_mq_alloc(struct c2_mq *q)
++{
++ BUG_ON(q->magic != C2_MQ_MAGIC);
++ BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
++
++ if (c2_mq_full(q)) {
++ return NULL;
++ } else {
++#ifdef DEBUG
++ struct c2wr_hdr *m =
++ (struct c2wr_hdr *) (q->msg_pool.host + q->priv * q->msg_size);
++#ifdef CCMSGMAGIC
++ BUG_ON(m->magic != be32_to_cpu(~CCWR_MAGIC));
++ m->magic = cpu_to_be32(CCWR_MAGIC);
++#endif
++ return m;
++#else
++ return q->msg_pool.host + q->priv * q->msg_size;
++#endif
++ }
++}
++
++void c2_mq_produce(struct c2_mq *q)
++{
++ BUG_ON(q->magic != C2_MQ_MAGIC);
++ BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
++
++ if (!c2_mq_full(q)) {
++ q->priv = (q->priv + 1) % q->q_size;
++ q->hint_count++;
++ /* Update peer's offset. */
++ __raw_writew(cpu_to_be16(q->priv), &q->peer->shared);
++ }
++}
++
++void *c2_mq_consume(struct c2_mq *q)
++{
++ BUG_ON(q->magic != C2_MQ_MAGIC);
++ BUG_ON(q->type != C2_MQ_HOST_TARGET);
++
++ if (c2_mq_empty(q)) {
++ return NULL;
++ } else {
++#ifdef DEBUG
++ struct c2wr_hdr *m = (struct c2wr_hdr *)
++ (q->msg_pool.host + q->priv * q->msg_size);
++#ifdef CCMSGMAGIC
++ BUG_ON(m->magic != be32_to_cpu(CCWR_MAGIC));
++#endif
++ return m;
++#else
++ return q->msg_pool.host + q->priv * q->msg_size;
++#endif
++ }
++}
++
++void c2_mq_free(struct c2_mq *q)
++{
++ BUG_ON(q->magic != C2_MQ_MAGIC);
++ BUG_ON(q->type != C2_MQ_HOST_TARGET);
++
++ if (!c2_mq_empty(q)) {
++
++#ifdef CCMSGMAGIC
++ {
++ struct c2wr_hdr __iomem *m = (struct c2wr_hdr __iomem *)
++ (q->msg_pool.adapter + q->priv * q->msg_size);
++ __raw_writel(cpu_to_be32(~CCWR_MAGIC), &m->magic);
++ }
++#endif
++ q->priv = (q->priv + 1) % q->q_size;
++ /* Update peer's offset. */
++ __raw_writew(cpu_to_be16(q->priv), &q->peer->shared);
++ }
++}
++
++
++void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count)
++{
++ BUG_ON(q->magic != C2_MQ_MAGIC);
++ BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
++
++ while (wqe_count--) {
++ BUG_ON(c2_mq_empty(q));
++ *q->shared = cpu_to_be16((be16_to_cpu(*q->shared)+1) % q->q_size);
++ }
++}
++
++#if 0
++u32 c2_mq_count(struct c2_mq *q)
++{
++ s32 count;
++
++ if (q->type == C2_MQ_HOST_TARGET)
++ count = be16_to_cpu(*q->shared) - q->priv;
++ else
++ count = q->priv - be16_to_cpu(*q->shared);
++
++ if (count < 0)
++ count += q->q_size;
++
++ return (u32) count;
++}
++#endif /* 0 */
++
++void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
++ u8 __iomem *pool_start, u16 __iomem *peer, u32 type)
++{
++ BUG_ON(!q->shared);
++
++ /* This code assumes the byte swapping has already been done! */
++ q->index = index;
++ q->q_size = q_size;
++ q->msg_size = msg_size;
++ q->msg_pool.adapter = pool_start;
++ q->peer = (struct c2_mq_shared __iomem *) peer;
++ q->magic = C2_MQ_MAGIC;
++ q->type = type;
++ q->priv = 0;
++ q->hint_count = 0;
++ return;
++}
++void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
++ u8 *pool_start, u16 __iomem *peer, u32 type)
++{
++ BUG_ON(!q->shared);
++
++ /* This code assumes the byte swapping has already been done! */
++ q->index = index;
++ q->q_size = q_size;
++ q->msg_size = msg_size;
++ q->msg_pool.host = pool_start;
++ q->peer = (struct c2_mq_shared __iomem *) peer;
++ q->magic = C2_MQ_MAGIC;
++ q->type = type;
++ q->priv = 0;
++ q->hint_count = 0;
++ return;
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_mq.h b/drivers/infiniband/hw/amso1100/c2_mq.h
+new file mode 100644
+index 0000000..9185bbb
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_mq.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 _C2_MQ_H_
++#define _C2_MQ_H_
++#include <linux/kernel.h>
++#include <linux/dma-mapping.h>
++#include "c2_wr.h"
++
++enum c2_shared_regs {
++
++ C2_SHARED_ARMED = 0x10,
++ C2_SHARED_NOTIFY = 0x18,
++ C2_SHARED_SHARED = 0x40,
++};
++
++struct c2_mq_shared {
++ u16 unused1;
++ u8 armed;
++ u8 notification_type;
++ u32 unused2;
++ u16 shared;
++ /* Pad to 64 bytes. */
++ u8 pad[64 - sizeof(u16) - 2 * sizeof(u8) - sizeof(u32) - sizeof(u16)];
++};
++
++enum c2_mq_type {
++ C2_MQ_HOST_TARGET = 1,
++ C2_MQ_ADAPTER_TARGET = 2,
++};
++
++/*
++ * c2_mq_t is for kernel-mode MQs like the VQs Cand the AEQ.
++ * c2_user_mq_t (which is the same format) is for user-mode MQs...
++ */
++#define C2_MQ_MAGIC 0x4d512020 /* 'MQ ' */
++struct c2_mq {
++ u32 magic;
++ union {
++ u8 *host;
++ u8 __iomem *adapter;
++ } msg_pool;
++ dma_addr_t host_dma;
++ DECLARE_PCI_UNMAP_ADDR(mapping);
++ u16 hint_count;
++ u16 priv;
++ struct c2_mq_shared __iomem *peer;
++ u16 *shared;
++ dma_addr_t shared_dma;
++ u32 q_size;
++ u32 msg_size;
++ u32 index;
++ enum c2_mq_type type;
++};
++
++static __inline__ int c2_mq_empty(struct c2_mq *q)
++{
++ return q->priv == be16_to_cpu(*q->shared);
++}
++
++static __inline__ int c2_mq_full(struct c2_mq *q)
++{
++ return q->priv == (be16_to_cpu(*q->shared) + q->q_size - 1) % q->q_size;
++}
++
++extern void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count);
++extern void *c2_mq_alloc(struct c2_mq *q);
++extern void c2_mq_produce(struct c2_mq *q);
++extern void *c2_mq_consume(struct c2_mq *q);
++extern void c2_mq_free(struct c2_mq *q);
++extern void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
++ u8 __iomem *pool_start, u16 __iomem *peer, u32 type);
++extern void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
++ u8 *pool_start, u16 __iomem *peer, u32 type);
++
++#endif /* _C2_MQ_H_ */
+diff --git a/drivers/infiniband/hw/amso1100/c2_pd.c b/drivers/infiniband/hw/amso1100/c2_pd.c
+new file mode 100644
+index 0000000..00c7099
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_pd.c
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (c) 2004 Topspin Communications. All rights reserved.
++ * Copyright (c) 2005 Cisco Systems. All rights reserved.
++ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++
++#include <linux/init.h>
++#include <linux/errno.h>
++
++#include "c2.h"
++#include "c2_provider.h"
++
++int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd)
++{
++ u32 obj;
++ int ret = 0;
++
++ spin_lock(&c2dev->pd_table.lock);
++ obj = find_next_zero_bit(c2dev->pd_table.table, c2dev->pd_table.max,
++ c2dev->pd_table.last);
++ if (obj >= c2dev->pd_table.max)
++ obj = find_first_zero_bit(c2dev->pd_table.table,
++ c2dev->pd_table.max);
++ if (obj < c2dev->pd_table.max) {
++ pd->pd_id = obj;
++ __set_bit(obj, c2dev->pd_table.table);
++ c2dev->pd_table.last = obj+1;
++ if (c2dev->pd_table.last >= c2dev->pd_table.max)
++ c2dev->pd_table.last = 0;
++ } else
++ ret = -ENOMEM;
++ spin_unlock(&c2dev->pd_table.lock);
++ return ret;
++}
++
++void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd)
++{
++ spin_lock(&c2dev->pd_table.lock);
++ __clear_bit(pd->pd_id, c2dev->pd_table.table);
++ spin_unlock(&c2dev->pd_table.lock);
++}
++
++int __devinit c2_init_pd_table(struct c2_dev *c2dev)
++{
++
++ c2dev->pd_table.last = 0;
++ c2dev->pd_table.max = c2dev->props.max_pd;
++ spin_lock_init(&c2dev->pd_table.lock);
++ c2dev->pd_table.table = kmalloc(BITS_TO_LONGS(c2dev->props.max_pd) *
++ sizeof(long), GFP_KERNEL);
++ if (!c2dev->pd_table.table)
++ return -ENOMEM;
++ bitmap_zero(c2dev->pd_table.table, c2dev->props.max_pd);
++ return 0;
++}
++
++void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev)
++{
++ kfree(c2dev->pd_table.table);
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
+new file mode 100644
+index 0000000..da98d9f
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_provider.c
+@@ -0,0 +1,874 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/pci.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/if_vlan.h>
++#include <linux/crc32.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/if_arp.h>
++#include <linux/vmalloc.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/byteorder.h>
++
++#include <rdma/ib_smi.h>
++#include <rdma/ib_user_verbs.h>
++#include "c2.h"
++#include "c2_provider.h"
++#include "c2_user.h"
++
++static int c2_query_device(struct ib_device *ibdev,
++ struct ib_device_attr *props)
++{
++ struct c2_dev *c2dev = to_c2dev(ibdev);
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ *props = c2dev->props;
++ return 0;
++}
++
++static int c2_query_port(struct ib_device *ibdev,
++ u8 port, struct ib_port_attr *props)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ props->max_mtu = IB_MTU_4096;
++ props->lid = 0;
++ props->lmc = 0;
++ props->sm_lid = 0;
++ props->sm_sl = 0;
++ props->state = IB_PORT_ACTIVE;
++ props->phys_state = 0;
++ props->port_cap_flags =
++ IB_PORT_CM_SUP |
++ IB_PORT_REINIT_SUP |
++ IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
++ props->gid_tbl_len = 1;
++ props->pkey_tbl_len = 1;
++ props->qkey_viol_cntr = 0;
++ props->active_width = 1;
++ props->active_speed = 1;
++
++ return 0;
++}
++
++static int c2_modify_port(struct ib_device *ibdev,
++ u8 port, int port_modify_mask,
++ struct ib_port_modify *props)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return 0;
++}
++
++static int c2_query_pkey(struct ib_device *ibdev,
++ u8 port, u16 index, u16 * pkey)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ *pkey = 0;
++ return 0;
++}
++
++static int c2_query_gid(struct ib_device *ibdev, u8 port,
++ int index, union ib_gid *gid)
++{
++ struct c2_dev *c2dev = to_c2dev(ibdev);
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
++ memcpy(&(gid->raw[0]), c2dev->pseudo_netdev->dev_addr, 6);
++
++ return 0;
++}
++
++/* Allocate the user context data structure. This keeps track
++ * of all objects associated with a particular user-mode client.
++ */
++static struct ib_ucontext *c2_alloc_ucontext(struct ib_device *ibdev,
++ struct ib_udata *udata)
++{
++ struct c2_ucontext *context;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ context = kmalloc(sizeof(*context), GFP_KERNEL);
++ if (!context)
++ return ERR_PTR(-ENOMEM);
++
++ return &context->ibucontext;
++}
++
++static int c2_dealloc_ucontext(struct ib_ucontext *context)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ kfree(context);
++ return 0;
++}
++
++static int c2_mmap_uar(struct ib_ucontext *context, struct vm_area_struct *vma)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return -ENOSYS;
++}
++
++static struct ib_pd *c2_alloc_pd(struct ib_device *ibdev,
++ struct ib_ucontext *context,
++ struct ib_udata *udata)
++{
++ struct c2_pd *pd;
++ int err;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ pd = kmalloc(sizeof(*pd), GFP_KERNEL);
++ if (!pd)
++ return ERR_PTR(-ENOMEM);
++
++ err = c2_pd_alloc(to_c2dev(ibdev), !context, pd);
++ if (err) {
++ kfree(pd);
++ return ERR_PTR(err);
++ }
++
++ if (context) {
++ if (ib_copy_to_udata(udata, &pd->pd_id, sizeof(__u32))) {
++ c2_pd_free(to_c2dev(ibdev), pd);
++ kfree(pd);
++ return ERR_PTR(-EFAULT);
++ }
++ }
++
++ return &pd->ibpd;
++}
++
++static int c2_dealloc_pd(struct ib_pd *pd)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ c2_pd_free(to_c2dev(pd->device), to_c2pd(pd));
++ kfree(pd);
++
++ return 0;
++}
++
++static struct ib_ah *c2_ah_create(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return ERR_PTR(-ENOSYS);
++}
++
++static int c2_ah_destroy(struct ib_ah *ah)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return -ENOSYS;
++}
++
++static void c2_add_ref(struct ib_qp *ibqp)
++{
++ struct c2_qp *qp;
++ BUG_ON(!ibqp);
++ qp = to_c2qp(ibqp);
++ atomic_inc(&qp->refcount);
++}
++
++static void c2_rem_ref(struct ib_qp *ibqp)
++{
++ struct c2_qp *qp;
++ BUG_ON(!ibqp);
++ qp = to_c2qp(ibqp);
++ if (atomic_dec_and_test(&qp->refcount))
++ wake_up(&qp->wait);
++}
++
++struct ib_qp *c2_get_qp(struct ib_device *device, int qpn)
++{
++ struct c2_dev* c2dev = to_c2dev(device);
++ struct c2_qp *qp;
++
++ qp = c2_find_qpn(c2dev, qpn);
++ pr_debug("%s Returning QP=%p for QPN=%d, device=%p, refcount=%d\n",
++ __FUNCTION__, qp, qpn, device,
++ (qp?atomic_read(&qp->refcount):0));
++
++ return (qp?&qp->ibqp:NULL);
++}
++
++static struct ib_qp *c2_create_qp(struct ib_pd *pd,
++ struct ib_qp_init_attr *init_attr,
++ struct ib_udata *udata)
++{
++ struct c2_qp *qp;
++ int err;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ switch (init_attr->qp_type) {
++ case IB_QPT_RC:
++ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
++ if (!qp) {
++ pr_debug("%s: Unable to allocate QP\n", __FUNCTION__);
++ return ERR_PTR(-ENOMEM);
++ }
++ spin_lock_init(&qp->lock);
++ if (pd->uobject) {
++ /* userspace specific */
++ }
++
++ err = c2_alloc_qp(to_c2dev(pd->device),
++ to_c2pd(pd), init_attr, qp);
++
++ if (err && pd->uobject) {
++ /* userspace specific */
++ }
++
++ break;
++ default:
++ pr_debug("%s: Invalid QP type: %d\n", __FUNCTION__,
++ init_attr->qp_type);
++ return ERR_PTR(-EINVAL);
++ break;
++ }
++
++ if (err) {
++ kfree(qp);
++ return ERR_PTR(err);
++ }
++
++ return &qp->ibqp;
++}
++
++static int c2_destroy_qp(struct ib_qp *ib_qp)
++{
++ struct c2_qp *qp = to_c2qp(ib_qp);
++
++ pr_debug("%s:%u qp=%p,qp->state=%d\n",
++ __FUNCTION__, __LINE__,ib_qp,qp->state);
++ c2_free_qp(to_c2dev(ib_qp->device), qp);
++ kfree(qp);
++ return 0;
++}
++
++static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries,
++ struct ib_ucontext *context,
++ struct ib_udata *udata)
++{
++ struct c2_cq *cq;
++ int err;
++
++ cq = kmalloc(sizeof(*cq), GFP_KERNEL);
++ if (!cq) {
++ pr_debug("%s: Unable to allocate CQ\n", __FUNCTION__);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ err = c2_init_cq(to_c2dev(ibdev), entries, NULL, cq);
++ if (err) {
++ pr_debug("%s: error initializing CQ\n", __FUNCTION__);
++ kfree(cq);
++ return ERR_PTR(err);
++ }
++
++ return &cq->ibcq;
++}
++
++static int c2_destroy_cq(struct ib_cq *ib_cq)
++{
++ struct c2_cq *cq = to_c2cq(ib_cq);
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ c2_free_cq(to_c2dev(ib_cq->device), cq);
++ kfree(cq);
++
++ return 0;
++}
++
++static inline u32 c2_convert_access(int acc)
++{
++ return (acc & IB_ACCESS_REMOTE_WRITE ? C2_ACF_REMOTE_WRITE : 0) |
++ (acc & IB_ACCESS_REMOTE_READ ? C2_ACF_REMOTE_READ : 0) |
++ (acc & IB_ACCESS_LOCAL_WRITE ? C2_ACF_LOCAL_WRITE : 0) |
++ C2_ACF_LOCAL_READ | C2_ACF_WINDOW_BIND;
++}
++
++static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
++ struct ib_phys_buf *buffer_list,
++ int num_phys_buf, int acc, u64 * iova_start)
++{
++ struct c2_mr *mr;
++ u64 *page_list;
++ u32 total_len;
++ int err, i, j, k, page_shift, pbl_depth;
++
++ pbl_depth = 0;
++ total_len = 0;
++
++ page_shift = PAGE_SHIFT;
++ /*
++ * If there is only 1 buffer we assume this could
++ * be a map of all phy mem...use a 32k page_shift.
++ */
++ if (num_phys_buf == 1)
++ page_shift += 3;
++
++ for (i = 0; i < num_phys_buf; i++) {
++
++ if (buffer_list[i].addr & ~PAGE_MASK) {
++ pr_debug("Unaligned Memory Buffer: 0x%x\n",
++ (unsigned int) buffer_list[i].addr);
++ return ERR_PTR(-EINVAL);
++ }
++
++ if (!buffer_list[i].size) {
++ pr_debug("Invalid Buffer Size\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ total_len += buffer_list[i].size;
++ pbl_depth += ALIGN(buffer_list[i].size,
++ (1 << page_shift)) >> page_shift;
++ }
++
++ page_list = vmalloc(sizeof(u64) * pbl_depth);
++ if (!page_list) {
++ pr_debug("couldn't vmalloc page_list of size %zd\n",
++ (sizeof(u64) * pbl_depth));
++ return ERR_PTR(-ENOMEM);
++ }
++
++ for (i = 0, j = 0; i < num_phys_buf; i++) {
++
++ int naddrs;
++
++ naddrs = ALIGN(buffer_list[i].size,
++ (1 << page_shift)) >> page_shift;
++ for (k = 0; k < naddrs; k++)
++ page_list[j++] = (buffer_list[i].addr +
++ (k << page_shift));
++ }
++
++ mr = kmalloc(sizeof(*mr), GFP_KERNEL);
++ if (!mr) {
++ vfree(page_list);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ mr->pd = to_c2pd(ib_pd);
++ pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
++ "*iova_start %llx, first pa %llx, last pa %llx\n",
++ __FUNCTION__, page_shift, pbl_depth, total_len,
++ (unsigned long long) *iova_start,
++ (unsigned long long) page_list[0],
++ (unsigned long long) page_list[pbl_depth-1]);
++ err = c2_nsmr_register_phys_kern(to_c2dev(ib_pd->device), page_list,
++ (1 << page_shift), pbl_depth,
++ total_len, 0, iova_start,
++ c2_convert_access(acc), mr);
++ vfree(page_list);
++ if (err) {
++ kfree(mr);
++ return ERR_PTR(err);
++ }
++
++ return &mr->ibmr;
++}
++
++static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
++{
++ struct ib_phys_buf bl;
++ u64 kva = 0;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ /* AMSO1100 limit */
++ bl.size = 0xffffffff;
++ bl.addr = 0;
++ return c2_reg_phys_mr(pd, &bl, 1, acc, &kva);
++}
++
++static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
++ int acc, struct ib_udata *udata)
++{
++ u64 *pages;
++ u64 kva = 0;
++ int shift, n, len;
++ int i, j, k;
++ int err = 0;
++ struct ib_umem_chunk *chunk;
++ struct c2_pd *c2pd = to_c2pd(pd);
++ struct c2_mr *c2mr;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ shift = ffs(region->page_size) - 1;
++
++ c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
++ if (!c2mr)
++ return ERR_PTR(-ENOMEM);
++ c2mr->pd = c2pd;
++
++ n = 0;
++ list_for_each_entry(chunk, ®ion->chunk_list, list)
++ n += chunk->nents;
++
++ pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
++ if (!pages) {
++ err = -ENOMEM;
++ goto err;
++ }
++
++ i = 0;
++ list_for_each_entry(chunk, ®ion->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);
++ }
++ }
++ }
++
++ kva = (u64)region->virt_base;
++ err = c2_nsmr_register_phys_kern(to_c2dev(pd->device),
++ pages,
++ region->page_size,
++ i,
++ region->length,
++ region->offset,
++ &kva,
++ c2_convert_access(acc),
++ c2mr);
++ kfree(pages);
++ if (err) {
++ kfree(c2mr);
++ return ERR_PTR(err);
++ }
++ return &c2mr->ibmr;
++
++err:
++ kfree(c2mr);
++ return ERR_PTR(err);
++}
++
++static int c2_dereg_mr(struct ib_mr *ib_mr)
++{
++ struct c2_mr *mr = to_c2mr(ib_mr);
++ int err;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
++ if (err)
++ pr_debug("c2_stag_dealloc failed: %d\n", err);
++ else
++ kfree(mr);
++
++ return err;
++}
++
++static ssize_t show_rev(struct class_device *cdev, char *buf)
++{
++ struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev);
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return sprintf(buf, "%x\n", dev->props.hw_ver);
++}
++
++static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
++{
++ struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev);
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return sprintf(buf, "%x.%x.%x\n",
++ (int) (dev->props.fw_ver >> 32),
++ (int) (dev->props.fw_ver >> 16) & 0xffff,
++ (int) (dev->props.fw_ver & 0xffff));
++}
++
++static ssize_t show_hca(struct class_device *cdev, char *buf)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return sprintf(buf, "AMSO1100\n");
++}
++
++static ssize_t show_board(struct class_device *cdev, char *buf)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return sprintf(buf, "%.*s\n", 32, "AMSO1100 Board ID");
++}
++
++static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
++static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
++static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
++static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
++
++static struct class_device_attribute *c2_class_attributes[] = {
++ &class_device_attr_hw_rev,
++ &class_device_attr_fw_ver,
++ &class_device_attr_hca_type,
++ &class_device_attr_board_id
++};
++
++static int c2_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
++ int attr_mask, struct ib_udata *udata)
++{
++ int err;
++
++ err =
++ c2_qp_modify(to_c2dev(ibqp->device), to_c2qp(ibqp), attr,
++ attr_mask);
++
++ return err;
++}
++
++static int c2_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return -ENOSYS;
++}
++
++static int c2_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return -ENOSYS;
++}
++
++static int c2_process_mad(struct ib_device *ibdev,
++ int mad_flags,
++ u8 port_num,
++ struct ib_wc *in_wc,
++ struct ib_grh *in_grh,
++ struct ib_mad *in_mad, struct ib_mad *out_mad)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return -ENOSYS;
++}
++
++static int c2_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ /* Request a connection */
++ return c2_llp_connect(cm_id, iw_param);
++}
++
++static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ /* Accept the new connection */
++ return c2_llp_accept(cm_id, iw_param);
++}
++
++static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
++{
++ int err;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ err = c2_llp_reject(cm_id, pdata, pdata_len);
++ return err;
++}
++
++static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
++{
++ int err;
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ err = c2_llp_service_create(cm_id, backlog);
++ pr_debug("%s:%u err=%d\n",
++ __FUNCTION__, __LINE__,
++ err);
++ return err;
++}
++
++static int c2_service_destroy(struct iw_cm_id *cm_id)
++{
++ int err;
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++
++ err = c2_llp_service_destroy(cm_id);
++
++ return err;
++}
++
++static int c2_pseudo_up(struct net_device *netdev)
++{
++ struct in_device *ind;
++ struct c2_dev *c2dev = netdev->priv;
++
++ ind = in_dev_get(netdev);
++ if (!ind)
++ return 0;
++
++ pr_debug("adding...\n");
++ for_ifa(ind) {
++#ifdef DEBUG
++ u8 *ip = (u8 *) & ifa->ifa_address;
++
++ pr_debug("%s: %d.%d.%d.%d\n",
++ ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
++#endif
++ c2_add_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
++ }
++ endfor_ifa(ind);
++ in_dev_put(ind);
++
++ return 0;
++}
++
++static int c2_pseudo_down(struct net_device *netdev)
++{
++ struct in_device *ind;
++ struct c2_dev *c2dev = netdev->priv;
++
++ ind = in_dev_get(netdev);
++ if (!ind)
++ return 0;
++
++ pr_debug("deleting...\n");
++ for_ifa(ind) {
++#ifdef DEBUG
++ u8 *ip = (u8 *) & ifa->ifa_address;
++
++ pr_debug("%s: %d.%d.%d.%d\n",
++ ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
++#endif
++ c2_del_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
++ }
++ endfor_ifa(ind);
++ in_dev_put(ind);
++
++ return 0;
++}
++
++static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
++{
++ kfree_skb(skb);
++ return NETDEV_TX_OK;
++}
++
++static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
++{
++ int ret = 0;
++
++ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
++ return -EINVAL;
++
++ netdev->mtu = new_mtu;
++
++ /* TODO: Tell rnic about new rmda interface mtu */
++ return ret;
++}
++
++static void setup(struct net_device *netdev)
++{
++ SET_MODULE_OWNER(netdev);
++ netdev->open = c2_pseudo_up;
++ netdev->stop = c2_pseudo_down;
++ netdev->hard_start_xmit = c2_pseudo_xmit_frame;
++ netdev->get_stats = NULL;
++ netdev->tx_timeout = NULL;
++ netdev->set_mac_address = NULL;
++ netdev->change_mtu = c2_pseudo_change_mtu;
++ netdev->watchdog_timeo = 0;
++ netdev->type = ARPHRD_ETHER;
++ netdev->mtu = 1500;
++ netdev->hard_header_len = ETH_HLEN;
++ netdev->addr_len = ETH_ALEN;
++ netdev->tx_queue_len = 0;
++ netdev->flags |= IFF_NOARP;
++ return;
++}
++
++static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev)
++{
++ char name[IFNAMSIZ];
++ struct net_device *netdev;
++
++ /* change ethxxx to iwxxx */
++ strcpy(name, "iw");
++ strcat(name, &c2dev->netdev->name[3]);
++ netdev = alloc_netdev(sizeof(*netdev), name, setup);
++ if (!netdev) {
++ printk(KERN_ERR PFX "%s - etherdev alloc failed",
++ __FUNCTION__);
++ return NULL;
++ }
++
++ netdev->priv = c2dev;
++
++ SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
++
++ memcpy_fromio(netdev->dev_addr, c2dev->kva + C2_REGS_RDMA_ENADDR, 6);
++
++ /* Print out the MAC address */
++ pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
++ netdev->name,
++ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
++ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
++
++#if 0
++ /* Disable network packets */
++ netif_stop_queue(netdev);
++#endif
++ return netdev;
++}
++
++int c2_register_device(struct c2_dev *dev)
++{
++ int ret;
++ int i;
++
++ /* Register pseudo network device */
++ dev->pseudo_netdev = c2_pseudo_netdev_init(dev);
++ if (dev->pseudo_netdev) {
++ ret = register_netdev(dev->pseudo_netdev);
++ if (ret) {
++ printk(KERN_ERR PFX
++ "Unable to register netdev, ret = %d\n", ret);
++ free_netdev(dev->pseudo_netdev);
++ return ret;
++ }
++ }
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX);
++ dev->ibdev.owner = THIS_MODULE;
++ dev->ibdev.uverbs_cmd_mask =
++ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
++ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
++ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
++ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
++ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
++ (1ull << IB_USER_VERBS_CMD_REG_MR) |
++ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
++ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
++ (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
++ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
++ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
++ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
++ (1ull << IB_USER_VERBS_CMD_POST_SEND) |
++ (1ull << IB_USER_VERBS_CMD_POST_RECV);
++
++ dev->ibdev.node_type = RDMA_NODE_RNIC;
++ memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
++ memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
++ dev->ibdev.phys_port_cnt = 1;
++ dev->ibdev.dma_device = &dev->pcidev->dev;
++ dev->ibdev.class_dev.dev = &dev->pcidev->dev;
++ dev->ibdev.query_device = c2_query_device;
++ dev->ibdev.query_port = c2_query_port;
++ dev->ibdev.modify_port = c2_modify_port;
++ dev->ibdev.query_pkey = c2_query_pkey;
++ dev->ibdev.query_gid = c2_query_gid;
++ dev->ibdev.alloc_ucontext = c2_alloc_ucontext;
++ dev->ibdev.dealloc_ucontext = c2_dealloc_ucontext;
++ dev->ibdev.mmap = c2_mmap_uar;
++ dev->ibdev.alloc_pd = c2_alloc_pd;
++ dev->ibdev.dealloc_pd = c2_dealloc_pd;
++ dev->ibdev.create_ah = c2_ah_create;
++ dev->ibdev.destroy_ah = c2_ah_destroy;
++ dev->ibdev.create_qp = c2_create_qp;
++ dev->ibdev.modify_qp = c2_modify_qp;
++ dev->ibdev.destroy_qp = c2_destroy_qp;
++ dev->ibdev.create_cq = c2_create_cq;
++ dev->ibdev.destroy_cq = c2_destroy_cq;
++ dev->ibdev.poll_cq = c2_poll_cq;
++ dev->ibdev.get_dma_mr = c2_get_dma_mr;
++ dev->ibdev.reg_phys_mr = c2_reg_phys_mr;
++ dev->ibdev.reg_user_mr = c2_reg_user_mr;
++ dev->ibdev.dereg_mr = c2_dereg_mr;
++
++ dev->ibdev.alloc_fmr = NULL;
++ dev->ibdev.unmap_fmr = NULL;
++ dev->ibdev.dealloc_fmr = NULL;
++ dev->ibdev.map_phys_fmr = NULL;
++
++ dev->ibdev.attach_mcast = c2_multicast_attach;
++ dev->ibdev.detach_mcast = c2_multicast_detach;
++ dev->ibdev.process_mad = c2_process_mad;
++
++ dev->ibdev.req_notify_cq = c2_arm_cq;
++ dev->ibdev.post_send = c2_post_send;
++ dev->ibdev.post_recv = c2_post_receive;
++
++ dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
++ dev->ibdev.iwcm->add_ref = c2_add_ref;
++ dev->ibdev.iwcm->rem_ref = c2_rem_ref;
++ dev->ibdev.iwcm->get_qp = c2_get_qp;
++ dev->ibdev.iwcm->connect = c2_connect;
++ dev->ibdev.iwcm->accept = c2_accept;
++ dev->ibdev.iwcm->reject = c2_reject;
++ dev->ibdev.iwcm->create_listen = c2_service_create;
++ dev->ibdev.iwcm->destroy_listen = c2_service_destroy;
++
++ ret = ib_register_device(&dev->ibdev);
++ if (ret)
++ return ret;
++
++ for (i = 0; i < ARRAY_SIZE(c2_class_attributes); ++i) {
++ ret = class_device_create_file(&dev->ibdev.class_dev,
++ c2_class_attributes[i]);
++ if (ret) {
++ unregister_netdev(dev->pseudo_netdev);
++ free_netdev(dev->pseudo_netdev);
++ ib_unregister_device(&dev->ibdev);
++ return ret;
++ }
++ }
++
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ return 0;
++}
++
++void c2_unregister_device(struct c2_dev *dev)
++{
++ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
++ unregister_netdev(dev->pseudo_netdev);
++ free_netdev(dev->pseudo_netdev);
++ ib_unregister_device(&dev->ibdev);
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_provider.h b/drivers/infiniband/hw/amso1100/c2_provider.h
+new file mode 100644
+index 0000000..fc90622
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_provider.h
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 C2_PROVIDER_H
++#define C2_PROVIDER_H
++#include <linux/inetdevice.h>
++
++#include <rdma/ib_verbs.h>
++#include <rdma/ib_pack.h>
++
++#include "c2_mq.h"
++#include <rdma/iw_cm.h>
++
++#define C2_MPT_FLAG_ATOMIC (1 << 14)
++#define C2_MPT_FLAG_REMOTE_WRITE (1 << 13)
++#define C2_MPT_FLAG_REMOTE_READ (1 << 12)
++#define C2_MPT_FLAG_LOCAL_WRITE (1 << 11)
++#define C2_MPT_FLAG_LOCAL_READ (1 << 10)
++
++struct c2_buf_list {
++ void *buf;
++ DECLARE_PCI_UNMAP_ADDR(mapping)
++};
++
++
++/* The user context keeps track of objects allocated for a
++ * particular user-mode client. */
++struct c2_ucontext {
++ struct ib_ucontext ibucontext;
++};
++
++struct c2_mtt;
++
++/* All objects associated with a PD are kept in the
++ * associated user context if present.
++ */
++struct c2_pd {
++ struct ib_pd ibpd;
++ u32 pd_id;
++};
++
++struct c2_mr {
++ struct ib_mr ibmr;
++ struct c2_pd *pd;
++};
++
++struct c2_av;
++
++enum c2_ah_type {
++ C2_AH_ON_HCA,
++ C2_AH_PCI_POOL,
++ C2_AH_KMALLOC
++};
++
++struct c2_ah {
++ struct ib_ah ibah;
++};
++
++struct c2_cq {
++ struct ib_cq ibcq;
++ spinlock_t lock;
++ atomic_t refcount;
++ int cqn;
++ int is_kernel;
++ wait_queue_head_t wait;
++
++ u32 adapter_handle;
++ struct c2_mq mq;
++};
++
++struct c2_wq {
++ spinlock_t lock;
++};
++struct iw_cm_id;
++struct c2_qp {
++ struct ib_qp ibqp;
++ struct iw_cm_id *cm_id;
++ spinlock_t lock;
++ atomic_t refcount;
++ wait_queue_head_t wait;
++ int qpn;
++
++ u32 adapter_handle;
++ u32 send_sgl_depth;
++ u32 recv_sgl_depth;
++ u32 rdma_write_sgl_depth;
++ u8 state;
++
++ struct c2_mq sq_mq;
++ struct c2_mq rq_mq;
++};
++
++struct c2_cr_query_attrs {
++ u32 local_addr;
++ u32 remote_addr;
++ u16 local_port;
++ u16 remote_port;
++};
++
++static inline struct c2_pd *to_c2pd(struct ib_pd *ibpd)
++{
++ return container_of(ibpd, struct c2_pd, ibpd);
++}
++
++static inline struct c2_ucontext *to_c2ucontext(struct ib_ucontext *ibucontext)
++{
++ return container_of(ibucontext, struct c2_ucontext, ibucontext);
++}
++
++static inline struct c2_mr *to_c2mr(struct ib_mr *ibmr)
++{
++ return container_of(ibmr, struct c2_mr, ibmr);
++}
++
++
++static inline struct c2_ah *to_c2ah(struct ib_ah *ibah)
++{
++ return container_of(ibah, struct c2_ah, ibah);
++}
++
++static inline struct c2_cq *to_c2cq(struct ib_cq *ibcq)
++{
++ return container_of(ibcq, struct c2_cq, ibcq);
++}
++
++static inline struct c2_qp *to_c2qp(struct ib_qp *ibqp)
++{
++ return container_of(ibqp, struct c2_qp, ibqp);
++}
++
++static inline int is_rnic_addr(struct net_device *netdev, u32 addr)
++{
++ struct in_device *ind;
++ int ret = 0;
++
++ ind = in_dev_get(netdev);
++ if (!ind)
++ return 0;
++
++ for_ifa(ind) {
++ if (ifa->ifa_address == addr) {
++ ret = 1;
++ break;
++ }
++ }
++ endfor_ifa(ind);
++ in_dev_put(ind);
++ return ret;
++}
++#endif /* C2_PROVIDER_H */
+diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
+new file mode 100644
+index 0000000..5bcf697
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_qp.c
+@@ -0,0 +1,983 @@
++/*
++ * Copyright (c) 2004 Topspin Communications. All rights reserved.
++ * Copyright (c) 2005 Cisco Systems. All rights reserved.
++ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
++ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ *
++ */
++
++#include <linux/delay.h>
++
++#include "c2.h"
++#include "c2_vq.h"
++#include "c2_status.h"
++
++#define C2_MAX_ORD_PER_QP 128
++#define C2_MAX_IRD_PER_QP 128
++
++#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
++#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
++#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
++
++#define NO_SUPPORT -1
++static const u8 c2_opcode[] = {
++ [IB_WR_SEND] = C2_WR_TYPE_SEND,
++ [IB_WR_SEND_WITH_IMM] = NO_SUPPORT,
++ [IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE,
++ [IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT,
++ [IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ,
++ [IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT,
++ [IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT,
++};
++
++static int to_c2_state(enum ib_qp_state ib_state)
++{
++ switch (ib_state) {
++ case IB_QPS_RESET:
++ return C2_QP_STATE_IDLE;
++ case IB_QPS_RTS:
++ return C2_QP_STATE_RTS;
++ case IB_QPS_SQD:
++ return C2_QP_STATE_CLOSING;
++ case IB_QPS_SQE:
++ return C2_QP_STATE_CLOSING;
++ case IB_QPS_ERR:
++ return C2_QP_STATE_ERROR;
++ default:
++ return -1;
++ }
++}
++
++static int to_ib_state(enum c2_qp_state c2_state)
++{
++ switch (c2_state) {
++ case C2_QP_STATE_IDLE:
++ return IB_QPS_RESET;
++ case C2_QP_STATE_CONNECTING:
++ return IB_QPS_RTR;
++ case C2_QP_STATE_RTS:
++ return IB_QPS_RTS;
++ case C2_QP_STATE_CLOSING:
++ return IB_QPS_SQD;
++ case C2_QP_STATE_ERROR:
++ return IB_QPS_ERR;
++ case C2_QP_STATE_TERMINATE:
++ return IB_QPS_SQE;
++ default:
++ return -1;
++ }
++}
++
++static const char *to_ib_state_str(int ib_state)
++{
++ static const char *state_str[] = {
++ "IB_QPS_RESET",
++ "IB_QPS_INIT",
++ "IB_QPS_RTR",
++ "IB_QPS_RTS",
++ "IB_QPS_SQD",
++ "IB_QPS_SQE",
++ "IB_QPS_ERR"
++ };
++ if (ib_state < IB_QPS_RESET ||
++ ib_state > IB_QPS_ERR)
++ return "<invalid IB QP state>";
++
++ ib_state -= IB_QPS_RESET;
++ return state_str[ib_state];
++}
++
++void c2_set_qp_state(struct c2_qp *qp, int c2_state)
++{
++ int new_state = to_ib_state(c2_state);
++
++ pr_debug("%s: qp[%p] state modify %s --> %s\n",
++ __FUNCTION__,
++ qp,
++ to_ib_state_str(qp->state),
++ to_ib_state_str(new_state));
++ qp->state = new_state;
++}
++
++#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
++
++int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
++ struct ib_qp_attr *attr, int attr_mask)
++{
++ struct c2wr_qp_modify_req wr;
++ struct c2wr_qp_modify_rep *reply;
++ struct c2_vq_req *vq_req;
++ unsigned long flags;
++ u8 next_state;
++ int err;
++
++ pr_debug("%s:%d qp=%p, %s --> %s\n",
++ __FUNCTION__, __LINE__,
++ qp,
++ to_ib_state_str(qp->state),
++ to_ib_state_str(attr->qp_state));
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ c2_wr_set_id(&wr, CCWR_QP_MODIFY);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.qp_handle = qp->adapter_handle;
++ wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++ wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++ wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++ wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++
++ if (attr_mask & IB_QP_STATE) {
++ /* Ensure the state is valid */
++ if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
++ return -EINVAL;
++
++ wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state));
++
++ if (attr->qp_state == IB_QPS_ERR) {
++ spin_lock_irqsave(&qp->lock, flags);
++ if (qp->cm_id && qp->state == IB_QPS_RTS) {
++ pr_debug("Generating CLOSE event for QP-->ERR, "
++ "qp=%p, cm_id=%p\n",qp,qp->cm_id);
++ /* Generate an CLOSE event */
++ vq_req->cm_id = qp->cm_id;
++ vq_req->event = IW_CM_EVENT_CLOSE;
++ }
++ spin_unlock_irqrestore(&qp->lock, flags);
++ }
++ next_state = attr->qp_state;
++
++ } else if (attr_mask & IB_QP_CUR_STATE) {
++
++ if (attr->cur_qp_state != IB_QPS_RTR &&
++ attr->cur_qp_state != IB_QPS_RTS &&
++ attr->cur_qp_state != IB_QPS_SQD &&
++ attr->cur_qp_state != IB_QPS_SQE)
++ return -EINVAL;
++ else
++ wr.next_qp_state =
++ cpu_to_be32(to_c2_state(attr->cur_qp_state));
++
++ next_state = attr->cur_qp_state;
++
++ } else {
++ err = 0;
++ goto bail0;
++ }
++
++ /* reference the request struct */
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail0;
++
++ reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ err = c2_errno(reply);
++ if (!err)
++ qp->state = next_state;
++#ifdef DEBUG
++ else
++ pr_debug("%s: c2_errno=%d\n", __FUNCTION__, err);
++#endif
++ /*
++ * If we're going to error and generating the event here, then
++ * we need to remove the reference because there will be no
++ * close event generated by the adapter
++ */
++ spin_lock_irqsave(&qp->lock, flags);
++ if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) {
++ qp->cm_id->rem_ref(qp->cm_id);
++ qp->cm_id = NULL;
++ }
++ spin_unlock_irqrestore(&qp->lock, flags);
++
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++
++ pr_debug("%s:%d qp=%p, cur_state=%s\n",
++ __FUNCTION__, __LINE__,
++ qp,
++ to_ib_state_str(qp->state));
++ return err;
++}
++
++int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
++ int ord, int ird)
++{
++ struct c2wr_qp_modify_req wr;
++ struct c2wr_qp_modify_rep *reply;
++ struct c2_vq_req *vq_req;
++ int err;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ c2_wr_set_id(&wr, CCWR_QP_MODIFY);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.qp_handle = qp->adapter_handle;
++ wr.ord = cpu_to_be32(ord);
++ wr.ird = cpu_to_be32(ird);
++ wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++ wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++ wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
++
++ /* reference the request struct */
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail0;
++
++ reply = (struct c2wr_qp_modify_rep *) (unsigned long)
++ vq_req->reply_msg;
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ err = c2_errno(reply);
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp)
++{
++ struct c2_vq_req *vq_req;
++ struct c2wr_qp_destroy_req wr;
++ struct c2wr_qp_destroy_rep *reply;
++ unsigned long flags;
++ int err;
++
++ /*
++ * Allocate a verb request message
++ */
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req) {
++ return -ENOMEM;
++ }
++
++ /*
++ * Initialize the WR
++ */
++ c2_wr_set_id(&wr, CCWR_QP_DESTROY);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.qp_handle = qp->adapter_handle;
++
++ /*
++ * reference the request struct. dereferenced in the int handler.
++ */
++ vq_req_get(c2dev, vq_req);
++
++ spin_lock_irqsave(&qp->lock, flags);
++ if (qp->cm_id && qp->state == IB_QPS_RTS) {
++ pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, "
++ "qp=%p, cm_id=%p\n",qp,qp->cm_id);
++ /* Generate an CLOSE event */
++ vq_req->qp = qp;
++ vq_req->cm_id = qp->cm_id;
++ vq_req->event = IW_CM_EVENT_CLOSE;
++ }
++ spin_unlock_irqrestore(&qp->lock, flags);
++
++ /*
++ * Send WR to adapter
++ */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ /*
++ * Wait for reply from adapter
++ */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail0;
++ }
++
++ /*
++ * Process reply
++ */
++ reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ spin_lock_irqsave(&qp->lock, flags);
++ if (qp->cm_id) {
++ qp->cm_id->rem_ref(qp->cm_id);
++ qp->cm_id = NULL;
++ }
++ spin_unlock_irqrestore(&qp->lock, flags);
++
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++static int c2_alloc_qpn(struct c2_dev *c2dev, struct c2_qp *qp)
++{
++ int ret;
++
++ do {
++ spin_lock_irq(&c2dev->qp_table.lock);
++ ret = idr_get_new_above(&c2dev->qp_table.idr, qp,
++ c2dev->qp_table.last++, &qp->qpn);
++ spin_unlock_irq(&c2dev->qp_table.lock);
++ } while ((ret == -EAGAIN) &&
++ idr_pre_get(&c2dev->qp_table.idr, GFP_KERNEL));
++ return ret;
++}
++
++static void c2_free_qpn(struct c2_dev *c2dev, int qpn)
++{
++ spin_lock_irq(&c2dev->qp_table.lock);
++ idr_remove(&c2dev->qp_table.idr, qpn);
++ spin_unlock_irq(&c2dev->qp_table.lock);
++}
++
++struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn)
++{
++ unsigned long flags;
++ struct c2_qp *qp;
++
++ spin_lock_irqsave(&c2dev->qp_table.lock, flags);
++ qp = idr_find(&c2dev->qp_table.idr, qpn);
++ spin_unlock_irqrestore(&c2dev->qp_table.lock, flags);
++ return qp;
++}
++
++int c2_alloc_qp(struct c2_dev *c2dev,
++ struct c2_pd *pd,
++ struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp)
++{
++ struct c2wr_qp_create_req wr;
++ struct c2wr_qp_create_rep *reply;
++ struct c2_vq_req *vq_req;
++ struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq);
++ struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq);
++ unsigned long peer_pa;
++ u32 q_size, msg_size, mmap_size;
++ void __iomem *mmap;
++ int err;
++
++ err = c2_alloc_qpn(c2dev, qp);
++ if (err)
++ return err;
++ qp->ibqp.qp_num = qp->qpn;
++ qp->ibqp.qp_type = IB_QPT_RC;
++
++ /* Allocate the SQ and RQ shared pointers */
++ qp->sq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &qp->sq_mq.shared_dma, GFP_KERNEL);
++ if (!qp->sq_mq.shared) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ qp->rq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &qp->rq_mq.shared_dma, GFP_KERNEL);
++ if (!qp->rq_mq.shared) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ /* Allocate the verbs request */
++ vq_req = vq_req_alloc(c2dev);
++ if (vq_req == NULL) {
++ err = -ENOMEM;
++ goto bail2;
++ }
++
++ /* Initialize the work request */
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_QP_CREATE);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++ wr.sq_cq_handle = send_cq->adapter_handle;
++ wr.rq_cq_handle = recv_cq->adapter_handle;
++ wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1);
++ wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1);
++ wr.srq_handle = 0;
++ wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND |
++ QP_ZERO_STAG | QP_RDMA_READ_RESPONSE);
++ wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
++ wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge);
++ wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
++ wr.shared_sq_ht = cpu_to_be64(qp->sq_mq.shared_dma);
++ wr.shared_rq_ht = cpu_to_be64(qp->rq_mq.shared_dma);
++ wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP);
++ wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP);
++ wr.pd_id = pd->pd_id;
++ wr.user_context = (unsigned long) qp;
++
++ vq_req_get(c2dev, vq_req);
++
++ /* Send the WR to the adapter */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail3;
++ }
++
++ /* Wait for the verb reply */
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail3;
++ }
++
++ /* Process the reply */
++ reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail3;
++ }
++
++ if ((err = c2_wr_get_result(reply)) != 0) {
++ goto bail4;
++ }
++
++ /* Fill in the kernel QP struct */
++ atomic_set(&qp->refcount, 1);
++ qp->adapter_handle = reply->qp_handle;
++ qp->state = IB_QPS_RESET;
++ qp->send_sgl_depth = qp_attrs->cap.max_send_sge;
++ qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;
++ qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;
++
++ /* Initialize the SQ MQ */
++ q_size = be32_to_cpu(reply->sq_depth);
++ msg_size = be32_to_cpu(reply->sq_msg_size);
++ peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start);
++ mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
++ mmap = ioremap_nocache(peer_pa, mmap_size);
++ if (!mmap) {
++ err = -ENOMEM;
++ goto bail5;
++ }
++
++ c2_mq_req_init(&qp->sq_mq,
++ be32_to_cpu(reply->sq_mq_index),
++ q_size,
++ msg_size,
++ mmap + sizeof(struct c2_mq_shared), /* pool start */
++ mmap, /* peer */
++ C2_MQ_ADAPTER_TARGET);
++
++ /* Initialize the RQ mq */
++ q_size = be32_to_cpu(reply->rq_depth);
++ msg_size = be32_to_cpu(reply->rq_msg_size);
++ peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start);
++ mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
++ mmap = ioremap_nocache(peer_pa, mmap_size);
++ if (!mmap) {
++ err = -ENOMEM;
++ goto bail6;
++ }
++
++ c2_mq_req_init(&qp->rq_mq,
++ be32_to_cpu(reply->rq_mq_index),
++ q_size,
++ msg_size,
++ mmap + sizeof(struct c2_mq_shared), /* pool start */
++ mmap, /* peer */
++ C2_MQ_ADAPTER_TARGET);
++
++ vq_repbuf_free(c2dev, reply);
++ vq_req_free(c2dev, vq_req);
++
++ return 0;
++
++ bail6:
++ iounmap(qp->sq_mq.peer);
++ bail5:
++ destroy_qp(c2dev, qp);
++ bail4:
++ vq_repbuf_free(c2dev, reply);
++ bail3:
++ vq_req_free(c2dev, vq_req);
++ bail2:
++ c2_free_mqsp(qp->rq_mq.shared);
++ bail1:
++ c2_free_mqsp(qp->sq_mq.shared);
++ bail0:
++ c2_free_qpn(c2dev, qp->qpn);
++ return err;
++}
++
++void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)
++{
++ struct c2_cq *send_cq;
++ struct c2_cq *recv_cq;
++
++ send_cq = to_c2cq(qp->ibqp.send_cq);
++ recv_cq = to_c2cq(qp->ibqp.recv_cq);
++
++ /*
++ * Lock CQs here, so that CQ polling code can do QP lookup
++ * without taking a lock.
++ */
++ spin_lock_irq(&send_cq->lock);
++ if (send_cq != recv_cq)
++ spin_lock(&recv_cq->lock);
++
++ c2_free_qpn(c2dev, qp->qpn);
++
++ if (send_cq != recv_cq)
++ spin_unlock(&recv_cq->lock);
++ spin_unlock_irq(&send_cq->lock);
++
++ /*
++ * Destory qp in the rnic...
++ */
++ destroy_qp(c2dev, qp);
++
++ /*
++ * Mark any unreaped CQEs as null and void.
++ */
++ c2_cq_clean(c2dev, qp, send_cq->cqn);
++ if (send_cq != recv_cq)
++ c2_cq_clean(c2dev, qp, recv_cq->cqn);
++ /*
++ * Unmap the MQs and return the shared pointers
++ * to the message pool.
++ */
++ iounmap(qp->sq_mq.peer);
++ iounmap(qp->rq_mq.peer);
++ c2_free_mqsp(qp->sq_mq.shared);
++ c2_free_mqsp(qp->rq_mq.shared);
++
++ atomic_dec(&qp->refcount);
++ wait_event(qp->wait, !atomic_read(&qp->refcount));
++}
++
++/*
++ * Function: move_sgl
++ *
++ * Description:
++ * Move an SGL from the user's work request struct into a CCIL Work Request
++ * message, swapping to WR byte order and ensure the total length doesn't
++ * overflow.
++ *
++ * IN:
++ * dst - ptr to CCIL Work Request message SGL memory.
++ * src - ptr to the consumers SGL memory.
++ *
++ * OUT: none
++ *
++ * Return:
++ * CCIL status codes.
++ */
++static int
++move_sgl(struct c2_data_addr * dst, struct ib_sge *src, int count, u32 * p_len,
++ u8 * actual_count)
++{
++ u32 tot = 0; /* running total */
++ u8 acount = 0; /* running total non-0 len sge's */
++
++ while (count > 0) {
++ /*
++ * If the addition of this SGE causes the
++ * total SGL length to exceed 2^32-1, then
++ * fail-n-bail.
++ *
++ * If the current total plus the next element length
++ * wraps, then it will go negative and be less than the
++ * current total...
++ */
++ if ((tot + src->length) < tot) {
++ return -EINVAL;
++ }
++ /*
++ * Bug: 1456 (as well as 1498 & 1643)
++ * Skip over any sge's supplied with len=0
++ */
++ if (src->length) {
++ tot += src->length;
++ dst->stag = cpu_to_be32(src->lkey);
++ dst->to = cpu_to_be64(src->addr);
++ dst->length = cpu_to_be32(src->length);
++ dst++;
++ acount++;
++ }
++ src++;
++ count--;
++ }
++
++ if (acount == 0) {
++ /*
++ * Bug: 1476 (as well as 1498, 1456 and 1643)
++ * Setup the SGL in the WR to make it easier for the RNIC.
++ * This way, the FW doesn't have to deal with special cases.
++ * Setting length=0 should be sufficient.
++ */
++ dst->stag = 0;
++ dst->to = 0;
++ dst->length = 0;
++ }
++
++ *p_len = tot;
++ *actual_count = acount;
++ return 0;
++}
++
++/*
++ * Function: c2_activity (private function)
++ *
++ * Description:
++ * Post an mq index to the host->adapter activity fifo.
++ *
++ * IN:
++ * c2dev - ptr to c2dev structure
++ * mq_index - mq index to post
++ * shared - value most recently written to shared
++ *
++ * OUT:
++ *
++ * Return:
++ * none
++ */
++static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared)
++{
++ /*
++ * First read the register to see if the FIFO is full, and if so,
++ * spin until it's not. This isn't perfect -- there is no
++ * synchronization among the clients of the register, but in
++ * practice it prevents multiple CPU from hammering the bus
++ * with PCI RETRY. Note that when this does happen, the card
++ * cannot get on the bus and the card and system hang in a
++ * deadlock -- thus the need for this code. [TOT]
++ */
++ while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000)
++ udelay(10);
++
++ __raw_writel(C2_HINT_MAKE(mq_index, shared),
++ c2dev->regs + PCI_BAR0_ADAPTER_HINT);
++}
++
++/*
++ * Function: qp_wr_post
++ *
++ * Description:
++ * This in-line function allocates a MQ msg, then moves the host-copy of
++ * the completed WR into msg. Then it posts the message.
++ *
++ * IN:
++ * q - ptr to user MQ.
++ * wr - ptr to host-copy of the WR.
++ * qp - ptr to user qp
++ * size - Number of bytes to post. Assumed to be divisible by 4.
++ *
++ * OUT: none
++ *
++ * Return:
++ * CCIL status codes.
++ */
++static int qp_wr_post(struct c2_mq *q, union c2wr * wr, struct c2_qp *qp, u32 size)
++{
++ union c2wr *msg;
++
++ msg = c2_mq_alloc(q);
++ if (msg == NULL) {
++ return -EINVAL;
++ }
++#ifdef CCMSGMAGIC
++ ((c2wr_hdr_t *) wr)->magic = cpu_to_be32(CCWR_MAGIC);
++#endif
++
++ /*
++ * Since all header fields in the WR are the same as the
++ * CQE, set the following so the adapter need not.
++ */
++ c2_wr_set_result(wr, CCERR_PENDING);
++
++ /*
++ * Copy the wr down to the adapter
++ */
++ memcpy((void *) msg, (void *) wr, size);
++
++ c2_mq_produce(q);
++ return 0;
++}
++
++
++int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
++ struct ib_send_wr **bad_wr)
++{
++ struct c2_dev *c2dev = to_c2dev(ibqp->device);
++ struct c2_qp *qp = to_c2qp(ibqp);
++ union c2wr wr;
++ unsigned long lock_flags;
++ int err = 0;
++
++ u32 flags;
++ u32 tot_len;
++ u8 actual_sge_count;
++ u32 msg_size;
++
++ if (qp->state > IB_QPS_RTS)
++ return -EINVAL;
++
++ while (ib_wr) {
++
++ flags = 0;
++ wr.sqwr.sq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
++ if (ib_wr->send_flags & IB_SEND_SIGNALED) {
++ flags |= SQ_SIGNALED;
++ }
++
++ switch (ib_wr->opcode) {
++ case IB_WR_SEND:
++ if (ib_wr->send_flags & IB_SEND_SOLICITED) {
++ c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE);
++ msg_size = sizeof(struct c2wr_send_req);
++ } else {
++ c2_wr_set_id(&wr, C2_WR_TYPE_SEND);
++ msg_size = sizeof(struct c2wr_send_req);
++ }
++
++ wr.sqwr.send.remote_stag = 0;
++ msg_size += sizeof(struct c2_data_addr) * ib_wr->num_sge;
++ if (ib_wr->num_sge > qp->send_sgl_depth) {
++ err = -EINVAL;
++ break;
++ }
++ if (ib_wr->send_flags & IB_SEND_FENCE) {
++ flags |= SQ_READ_FENCE;
++ }
++ err = move_sgl((struct c2_data_addr *) & (wr.sqwr.send.data),
++ ib_wr->sg_list,
++ ib_wr->num_sge,
++ &tot_len, &actual_sge_count);
++ wr.sqwr.send.sge_len = cpu_to_be32(tot_len);
++ c2_wr_set_sge_count(&wr, actual_sge_count);
++ break;
++ case IB_WR_RDMA_WRITE:
++ c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_WRITE);
++ msg_size = sizeof(struct c2wr_rdma_write_req) +
++ (sizeof(struct c2_data_addr) * ib_wr->num_sge);
++ if (ib_wr->num_sge > qp->rdma_write_sgl_depth) {
++ err = -EINVAL;
++ break;
++ }
++ if (ib_wr->send_flags & IB_SEND_FENCE) {
++ flags |= SQ_READ_FENCE;
++ }
++ wr.sqwr.rdma_write.remote_stag =
++ cpu_to_be32(ib_wr->wr.rdma.rkey);
++ wr.sqwr.rdma_write.remote_to =
++ cpu_to_be64(ib_wr->wr.rdma.remote_addr);
++ err = move_sgl((struct c2_data_addr *)
++ & (wr.sqwr.rdma_write.data),
++ ib_wr->sg_list,
++ ib_wr->num_sge,
++ &tot_len, &actual_sge_count);
++ wr.sqwr.rdma_write.sge_len = cpu_to_be32(tot_len);
++ c2_wr_set_sge_count(&wr, actual_sge_count);
++ break;
++ case IB_WR_RDMA_READ:
++ c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_READ);
++ msg_size = sizeof(struct c2wr_rdma_read_req);
++
++ /* IWarp only suppots 1 sge for RDMA reads */
++ if (ib_wr->num_sge > 1) {
++ err = -EINVAL;
++ break;
++ }
++
++ /*
++ * Move the local and remote stag/to/len into the WR.
++ */
++ wr.sqwr.rdma_read.local_stag =
++ cpu_to_be32(ib_wr->sg_list->lkey);
++ wr.sqwr.rdma_read.local_to =
++ cpu_to_be64(ib_wr->sg_list->addr);
++ wr.sqwr.rdma_read.remote_stag =
++ cpu_to_be32(ib_wr->wr.rdma.rkey);
++ wr.sqwr.rdma_read.remote_to =
++ cpu_to_be64(ib_wr->wr.rdma.remote_addr);
++ wr.sqwr.rdma_read.length =
++ cpu_to_be32(ib_wr->sg_list->length);
++ break;
++ default:
++ /* error */
++ msg_size = 0;
++ err = -EINVAL;
++ break;
++ }
++
++ /*
++ * If we had an error on the last wr build, then
++ * break out. Possible errors include bogus WR
++ * type, and a bogus SGL length...
++ */
++ if (err) {
++ break;
++ }
++
++ /*
++ * Store flags
++ */
++ c2_wr_set_flags(&wr, flags);
++
++ /*
++ * Post the puppy!
++ */
++ spin_lock_irqsave(&qp->lock, lock_flags);
++ err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size);
++ if (err) {
++ spin_unlock_irqrestore(&qp->lock, lock_flags);
++ break;
++ }
++
++ /*
++ * Enqueue mq index to activity FIFO.
++ */
++ c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count);
++ spin_unlock_irqrestore(&qp->lock, lock_flags);
++
++ ib_wr = ib_wr->next;
++ }
++
++ if (err)
++ *bad_wr = ib_wr;
++ return err;
++}
++
++int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
++ struct ib_recv_wr **bad_wr)
++{
++ struct c2_dev *c2dev = to_c2dev(ibqp->device);
++ struct c2_qp *qp = to_c2qp(ibqp);
++ union c2wr wr;
++ unsigned long lock_flags;
++ int err = 0;
++
++ if (qp->state > IB_QPS_RTS)
++ return -EINVAL;
++
++ /*
++ * Try and post each work request
++ */
++ while (ib_wr) {
++ u32 tot_len;
++ u8 actual_sge_count;
++
++ if (ib_wr->num_sge > qp->recv_sgl_depth) {
++ err = -EINVAL;
++ break;
++ }
++
++ /*
++ * Create local host-copy of the WR
++ */
++ wr.rqwr.rq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
++ c2_wr_set_id(&wr, CCWR_RECV);
++ c2_wr_set_flags(&wr, 0);
++
++ /* sge_count is limited to eight bits. */
++ BUG_ON(ib_wr->num_sge >= 256);
++ err = move_sgl((struct c2_data_addr *) & (wr.rqwr.data),
++ ib_wr->sg_list,
++ ib_wr->num_sge, &tot_len, &actual_sge_count);
++ c2_wr_set_sge_count(&wr, actual_sge_count);
++
++ /*
++ * If we had an error on the last wr build, then
++ * break out. Possible errors include bogus WR
++ * type, and a bogus SGL length...
++ */
++ if (err) {
++ break;
++ }
++
++ spin_lock_irqsave(&qp->lock, lock_flags);
++ err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size);
++ if (err) {
++ spin_unlock_irqrestore(&qp->lock, lock_flags);
++ break;
++ }
++
++ /*
++ * Enqueue mq index to activity FIFO
++ */
++ c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count);
++ spin_unlock_irqrestore(&qp->lock, lock_flags);
++
++ ib_wr = ib_wr->next;
++ }
++
++ if (err)
++ *bad_wr = ib_wr;
++ return err;
++}
++
++void __devinit c2_init_qp_table(struct c2_dev *c2dev)
++{
++ spin_lock_init(&c2dev->qp_table.lock);
++ idr_init(&c2dev->qp_table.idr);
++}
++
++void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev)
++{
++ idr_destroy(&c2dev->qp_table.idr);
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
+new file mode 100644
+index 0000000..21d9612
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
+@@ -0,0 +1,654 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ *
++ */
++
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/pci.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/if_vlan.h>
++#include <linux/crc32.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/mm.h>
++#include <linux/inet.h>
++#include <linux/vmalloc.h>
++
++#include <linux/route.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/byteorder.h>
++#include <rdma/ib_smi.h>
++#include "c2.h"
++#include "c2_vq.h"
++
++/* Device capabilities */
++#define C2_MIN_PAGESIZE 1024
++
++#define C2_MAX_MRS 32768
++#define C2_MAX_QPS 16000
++#define C2_MAX_WQE_SZ 256
++#define C2_MAX_QP_WR ((128*1024)/C2_MAX_WQE_SZ)
++#define C2_MAX_SGES 4
++#define C2_MAX_SGE_RD 1
++#define C2_MAX_CQS 32768
++#define C2_MAX_CQES 4096
++#define C2_MAX_PDS 16384
++
++/*
++ * Send the adapter INIT message to the amso1100
++ */
++static int c2_adapter_init(struct c2_dev *c2dev)
++{
++ struct c2wr_init_req wr;
++ int err;
++
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_INIT);
++ wr.hdr.context = 0;
++ wr.hint_count = cpu_to_be64(c2dev->hint_count_dma);
++ wr.q0_host_shared = cpu_to_be64(c2dev->req_vq.shared_dma);
++ wr.q1_host_shared = cpu_to_be64(c2dev->rep_vq.shared_dma);
++ wr.q1_host_msg_pool = cpu_to_be64(c2dev->rep_vq.host_dma);
++ wr.q2_host_shared = cpu_to_be64(c2dev->aeq.shared_dma);
++ wr.q2_host_msg_pool = cpu_to_be64(c2dev->aeq.host_dma);
++
++ /* Post the init message */
++ err = vq_send_wr(c2dev, (union c2wr *) & wr);
++
++ return err;
++}
++
++/*
++ * Send the adapter TERM message to the amso1100
++ */
++static void c2_adapter_term(struct c2_dev *c2dev)
++{
++ struct c2wr_init_req wr;
++
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_TERM);
++ wr.hdr.context = 0;
++
++ /* Post the init message */
++ vq_send_wr(c2dev, (union c2wr *) & wr);
++ c2dev->init = 0;
++
++ return;
++}
++
++/*
++ * Query the adapter
++ */
++static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props)
++{
++ struct c2_vq_req *vq_req;
++ struct c2wr_rnic_query_req wr;
++ struct c2wr_rnic_query_rep *reply;
++ int err;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ c2_wr_set_id(&wr, CCWR_RNIC_QUERY);
++ wr.hdr.context = (unsigned long) vq_req;
++ wr.rnic_handle = c2dev->adapter_handle;
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) &wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail1;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail1;
++
++ reply =
++ (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply)
++ err = -ENOMEM;
++ else
++ err = c2_errno(reply);
++ if (err)
++ goto bail2;
++
++ props->fw_ver =
++ ((u64)be32_to_cpu(reply->fw_ver_major) << 32) |
++ ((be32_to_cpu(reply->fw_ver_minor) && 0xFFFF) << 16) |
++ (be32_to_cpu(reply->fw_ver_patch) && 0xFFFF);
++ memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6);
++ props->max_mr_size = 0xFFFFFFFF;
++ props->page_size_cap = ~(C2_MIN_PAGESIZE-1);
++ props->vendor_id = be32_to_cpu(reply->vendor_id);
++ props->vendor_part_id = be32_to_cpu(reply->part_number);
++ props->hw_ver = be32_to_cpu(reply->hw_version);
++ props->max_qp = be32_to_cpu(reply->max_qps);
++ props->max_qp_wr = be32_to_cpu(reply->max_qp_depth);
++ props->device_cap_flags = c2dev->device_cap_flags;
++ props->max_sge = C2_MAX_SGES;
++ props->max_sge_rd = C2_MAX_SGE_RD;
++ props->max_cq = be32_to_cpu(reply->max_cqs);
++ props->max_cqe = be32_to_cpu(reply->max_cq_depth);
++ props->max_mr = be32_to_cpu(reply->max_mrs);
++ props->max_pd = be32_to_cpu(reply->max_pds);
++ props->max_qp_rd_atom = be32_to_cpu(reply->max_qp_ird);
++ props->max_ee_rd_atom = 0;
++ props->max_res_rd_atom = be32_to_cpu(reply->max_global_ird);
++ props->max_qp_init_rd_atom = be32_to_cpu(reply->max_qp_ord);
++ props->max_ee_init_rd_atom = 0;
++ props->atomic_cap = IB_ATOMIC_NONE;
++ props->max_ee = 0;
++ props->max_rdd = 0;
++ props->max_mw = be32_to_cpu(reply->max_mws);
++ props->max_raw_ipv6_qp = 0;
++ props->max_raw_ethy_qp = 0;
++ props->max_mcast_grp = 0;
++ props->max_mcast_qp_attach = 0;
++ props->max_total_mcast_qp_attach = 0;
++ props->max_ah = 0;
++ props->max_fmr = 0;
++ props->max_map_per_fmr = 0;
++ props->max_srq = 0;
++ props->max_srq_wr = 0;
++ props->max_srq_sge = 0;
++ props->max_pkeys = 0;
++ props->local_ca_ack_delay = 0;
++
++ bail2:
++ vq_repbuf_free(c2dev, reply);
++
++ bail1:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++/*
++ * Add an IP address to the RNIC interface
++ */
++int c2_add_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask)
++{
++ struct c2_vq_req *vq_req;
++ struct c2wr_rnic_setconfig_req *wr;
++ struct c2wr_rnic_setconfig_rep *reply;
++ struct c2_netaddr netaddr;
++ int err, len;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ len = sizeof(struct c2_netaddr);
++ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
++ if (!wr) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);
++ wr->hdr.context = (unsigned long) vq_req;
++ wr->rnic_handle = c2dev->adapter_handle;
++ wr->option = cpu_to_be32(C2_CFG_ADD_ADDR);
++
++ netaddr.ip_addr = inaddr;
++ netaddr.netmask = inmask;
++ netaddr.mtu = 0;
++
++ memcpy(wr->data, &netaddr, len);
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail1;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail1;
++
++ reply =
++ (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ err = c2_errno(reply);
++ vq_repbuf_free(c2dev, reply);
++
++ bail1:
++ kfree(wr);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++/*
++ * Delete an IP address from the RNIC interface
++ */
++int c2_del_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask)
++{
++ struct c2_vq_req *vq_req;
++ struct c2wr_rnic_setconfig_req *wr;
++ struct c2wr_rnic_setconfig_rep *reply;
++ struct c2_netaddr netaddr;
++ int err, len;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (!vq_req)
++ return -ENOMEM;
++
++ len = sizeof(struct c2_netaddr);
++ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
++ if (!wr) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);
++ wr->hdr.context = (unsigned long) vq_req;
++ wr->rnic_handle = c2dev->adapter_handle;
++ wr->option = cpu_to_be32(C2_CFG_DEL_ADDR);
++
++ netaddr.ip_addr = inaddr;
++ netaddr.netmask = inmask;
++ netaddr.mtu = 0;
++
++ memcpy(wr->data, &netaddr, len);
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, (union c2wr *) wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail1;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err)
++ goto bail1;
++
++ reply =
++ (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ err = c2_errno(reply);
++ vq_repbuf_free(c2dev, reply);
++
++ bail1:
++ kfree(wr);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++/*
++ * Open a single RNIC instance to use with all
++ * low level openib calls
++ */
++static int c2_rnic_open(struct c2_dev *c2dev)
++{
++ struct c2_vq_req *vq_req;
++ union c2wr wr;
++ struct c2wr_rnic_open_rep *reply;
++ int err;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (vq_req == NULL) {
++ return -ENOMEM;
++ }
++
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_RNIC_OPEN);
++ wr.rnic_open.req.hdr.context = (unsigned long) (vq_req);
++ wr.rnic_open.req.flags = cpu_to_be16(RNIC_PRIV_MODE);
++ wr.rnic_open.req.port_num = cpu_to_be16(0);
++ wr.rnic_open.req.user_context = (unsigned long) c2dev;
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, &wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail0;
++ }
++
++ reply = (struct c2wr_rnic_open_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ if ((err = c2_errno(reply)) != 0) {
++ goto bail1;
++ }
++
++ c2dev->adapter_handle = reply->rnic_handle;
++
++ bail1:
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++/*
++ * Close the RNIC instance
++ */
++static int c2_rnic_close(struct c2_dev *c2dev)
++{
++ struct c2_vq_req *vq_req;
++ union c2wr wr;
++ struct c2wr_rnic_close_rep *reply;
++ int err;
++
++ vq_req = vq_req_alloc(c2dev);
++ if (vq_req == NULL) {
++ return -ENOMEM;
++ }
++
++ memset(&wr, 0, sizeof(wr));
++ c2_wr_set_id(&wr, CCWR_RNIC_CLOSE);
++ wr.rnic_close.req.hdr.context = (unsigned long) vq_req;
++ wr.rnic_close.req.rnic_handle = c2dev->adapter_handle;
++
++ vq_req_get(c2dev, vq_req);
++
++ err = vq_send_wr(c2dev, &wr);
++ if (err) {
++ vq_req_put(c2dev, vq_req);
++ goto bail0;
++ }
++
++ err = vq_wait_for_reply(c2dev, vq_req);
++ if (err) {
++ goto bail0;
++ }
++
++ reply = (struct c2wr_rnic_close_rep *) (unsigned long) (vq_req->reply_msg);
++ if (!reply) {
++ err = -ENOMEM;
++ goto bail0;
++ }
++
++ if ((err = c2_errno(reply)) != 0) {
++ goto bail1;
++ }
++
++ c2dev->adapter_handle = 0;
++
++ bail1:
++ vq_repbuf_free(c2dev, reply);
++ bail0:
++ vq_req_free(c2dev, vq_req);
++ return err;
++}
++
++/*
++ * Called by c2_probe to initialize the RNIC. This principally
++ * involves initalizing the various limits and resouce pools that
++ * comprise the RNIC instance.
++ */
++int c2_rnic_init(struct c2_dev *c2dev)
++{
++ int err;
++ u32 qsize, msgsize;
++ void *q1_pages;
++ void *q2_pages;
++ void __iomem *mmio_regs;
++
++ /* Device capabilities */
++ c2dev->device_cap_flags =
++ (IB_DEVICE_RESIZE_MAX_WR |
++ IB_DEVICE_CURR_QP_STATE_MOD |
++ IB_DEVICE_SYS_IMAGE_GUID |
++ IB_DEVICE_ZERO_STAG |
++ IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW);
++
++ /* Allocate the qptr_array */
++ c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *));
++ if (!c2dev->qptr_array) {
++ return -ENOMEM;
++ }
++
++ /* Inialize the qptr_array */
++ memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *));
++ c2dev->qptr_array[0] = (void *) &c2dev->req_vq;
++ c2dev->qptr_array[1] = (void *) &c2dev->rep_vq;
++ c2dev->qptr_array[2] = (void *) &c2dev->aeq;
++
++ /* Initialize data structures */
++ init_waitqueue_head(&c2dev->req_vq_wo);
++ spin_lock_init(&c2dev->vqlock);
++ spin_lock_init(&c2dev->lock);
++
++ /* Allocate MQ shared pointer pool for kernel clients. User
++ * mode client pools are hung off the user context
++ */
++ err = c2_init_mqsp_pool(c2dev, GFP_KERNEL, &c2dev->kern_mqsp_pool);
++ if (err) {
++ goto bail0;
++ }
++
++ /* Allocate shared pointers for Q0, Q1, and Q2 from
++ * the shared pointer pool.
++ */
++
++ c2dev->hint_count = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &c2dev->hint_count_dma,
++ GFP_KERNEL);
++ c2dev->req_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &c2dev->req_vq.shared_dma,
++ GFP_KERNEL);
++ c2dev->rep_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &c2dev->rep_vq.shared_dma,
++ GFP_KERNEL);
++ c2dev->aeq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
++ &c2dev->aeq.shared_dma, GFP_KERNEL);
++ if (!c2dev->hint_count || !c2dev->req_vq.shared ||
++ !c2dev->rep_vq.shared || !c2dev->aeq.shared) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++
++ mmio_regs = c2dev->kva;
++ /* Initialize the Verbs Request Queue */
++ c2_mq_req_init(&c2dev->req_vq, 0,
++ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_QSIZE)),
++ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_MSGSIZE)),
++ mmio_regs +
++ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_POOLSTART)),
++ mmio_regs +
++ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_SHARED)),
++ C2_MQ_ADAPTER_TARGET);
++
++ /* Initialize the Verbs Reply Queue */
++ qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_QSIZE));
++ msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_MSGSIZE));
++ q1_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize,
++ &c2dev->rep_vq.host_dma, GFP_KERNEL);
++ if (!q1_pages) {
++ err = -ENOMEM;
++ goto bail1;
++ }
++ pci_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma);
++ pr_debug("%s rep_vq va %p dma %llx\n", __FUNCTION__, q1_pages,
++ (unsigned long long) c2dev->rep_vq.host_dma);
++ c2_mq_rep_init(&c2dev->rep_vq,
++ 1,
++ qsize,
++ msgsize,
++ q1_pages,
++ mmio_regs +
++ be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_SHARED)),
++ C2_MQ_HOST_TARGET);
++
++ /* Initialize the Asynchronus Event Queue */
++ qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_QSIZE));
++ msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_MSGSIZE));
++ q2_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize,
++ &c2dev->aeq.host_dma, GFP_KERNEL);
++ if (!q2_pages) {
++ err = -ENOMEM;
++ goto bail2;
++ }
++ pci_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma);
++ pr_debug("%s aeq va %p dma %llx\n", __FUNCTION__, q2_pages,
++ (unsigned long long) c2dev->aeq.host_dma);
++ c2_mq_rep_init(&c2dev->aeq,
++ 2,
++ qsize,
++ msgsize,
++ q2_pages,
++ mmio_regs +
++ be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_SHARED)),
++ C2_MQ_HOST_TARGET);
++
++ /* Initialize the verbs request allocator */
++ err = vq_init(c2dev);
++ if (err)
++ goto bail3;
++
++ /* Enable interrupts on the adapter */
++ writel(0, c2dev->regs + C2_IDIS);
++
++ /* create the WR init message */
++ err = c2_adapter_init(c2dev);
++ if (err)
++ goto bail4;
++ c2dev->init++;
++
++ /* open an adapter instance */
++ err = c2_rnic_open(c2dev);
++ if (err)
++ goto bail4;
++
++ /* Initialize cached the adapter limits */
++ if (c2_rnic_query(c2dev, &c2dev->props))
++ goto bail5;
++
++ /* Initialize the PD pool */
++ err = c2_init_pd_table(c2dev);
++ if (err)
++ goto bail5;
++
++ /* Initialize the QP pool */
++ c2_init_qp_table(c2dev);
++ return 0;
++
++ bail5:
++ c2_rnic_close(c2dev);
++ bail4:
++ vq_term(c2dev);
++ bail3:
++ dma_free_coherent(&c2dev->pcidev->dev,
++ c2dev->aeq.q_size * c2dev->aeq.msg_size,
++ q2_pages, pci_unmap_addr(&c2dev->aeq, mapping));
++ bail2:
++ dma_free_coherent(&c2dev->pcidev->dev,
++ c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,
++ q1_pages, pci_unmap_addr(&c2dev->rep_vq, mapping));
++ bail1:
++ c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);
++ bail0:
++ vfree(c2dev->qptr_array);
++
++ return err;
++}
++
++/*
++ * Called by c2_remove to cleanup the RNIC resources.
++ */
++void c2_rnic_term(struct c2_dev *c2dev)
++{
++
++ /* Close the open adapter instance */
++ c2_rnic_close(c2dev);
++
++ /* Send the TERM message to the adapter */
++ c2_adapter_term(c2dev);
++
++ /* Disable interrupts on the adapter */
++ writel(1, c2dev->regs + C2_IDIS);
++
++ /* Free the QP pool */
++ c2_cleanup_qp_table(c2dev);
++
++ /* Free the PD pool */
++ c2_cleanup_pd_table(c2dev);
++
++ /* Free the verbs request allocator */
++ vq_term(c2dev);
++
++ /* Free the asynchronus event queue */
++ dma_free_coherent(&c2dev->pcidev->dev,
++ c2dev->aeq.q_size * c2dev->aeq.msg_size,
++ c2dev->aeq.msg_pool.host,
++ pci_unmap_addr(&c2dev->aeq, mapping));
++
++ /* Free the verbs reply queue */
++ dma_free_coherent(&c2dev->pcidev->dev,
++ c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,
++ c2dev->rep_vq.msg_pool.host,
++ pci_unmap_addr(&c2dev->rep_vq, mapping));
++
++ /* Free the MQ shared pointer pool */
++ c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);
++
++ /* Free the qptr_array */
++ vfree(c2dev->qptr_array);
++
++ return;
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_status.h b/drivers/infiniband/hw/amso1100/c2_status.h
+new file mode 100644
+index 0000000..6ee4aa9
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_status.h
+@@ -0,0 +1,158 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 _C2_STATUS_H_
++#define _C2_STATUS_H_
++
++/*
++ * Verbs Status Codes
++ */
++enum c2_status {
++ C2_OK = 0, /* This must be zero */
++ CCERR_INSUFFICIENT_RESOURCES = 1,
++ CCERR_INVALID_MODIFIER = 2,
++ CCERR_INVALID_MODE = 3,
++ CCERR_IN_USE = 4,
++ CCERR_INVALID_RNIC = 5,
++ CCERR_INTERRUPTED_OPERATION = 6,
++ CCERR_INVALID_EH = 7,
++ CCERR_INVALID_CQ = 8,
++ CCERR_CQ_EMPTY = 9,
++ CCERR_NOT_IMPLEMENTED = 10,
++ CCERR_CQ_DEPTH_TOO_SMALL = 11,
++ CCERR_PD_IN_USE = 12,
++ CCERR_INVALID_PD = 13,
++ CCERR_INVALID_SRQ = 14,
++ CCERR_INVALID_ADDRESS = 15,
++ CCERR_INVALID_NETMASK = 16,
++ CCERR_INVALID_QP = 17,
++ CCERR_INVALID_QP_STATE = 18,
++ CCERR_TOO_MANY_WRS_POSTED = 19,
++ CCERR_INVALID_WR_TYPE = 20,
++ CCERR_INVALID_SGL_LENGTH = 21,
++ CCERR_INVALID_SQ_DEPTH = 22,
++ CCERR_INVALID_RQ_DEPTH = 23,
++ CCERR_INVALID_ORD = 24,
++ CCERR_INVALID_IRD = 25,
++ CCERR_QP_ATTR_CANNOT_CHANGE = 26,
++ CCERR_INVALID_STAG = 27,
++ CCERR_QP_IN_USE = 28,
++ CCERR_OUTSTANDING_WRS = 29,
++ CCERR_STAG_IN_USE = 30,
++ CCERR_INVALID_STAG_INDEX = 31,
++ CCERR_INVALID_SGL_FORMAT = 32,
++ CCERR_ADAPTER_TIMEOUT = 33,
++ CCERR_INVALID_CQ_DEPTH = 34,
++ CCERR_INVALID_PRIVATE_DATA_LENGTH = 35,
++ CCERR_INVALID_EP = 36,
++ CCERR_MR_IN_USE = CCERR_STAG_IN_USE,
++ CCERR_FLUSHED = 38,
++ CCERR_INVALID_WQE = 39,
++ CCERR_LOCAL_QP_CATASTROPHIC_ERROR = 40,
++ CCERR_REMOTE_TERMINATION_ERROR = 41,
++ CCERR_BASE_AND_BOUNDS_VIOLATION = 42,
++ CCERR_ACCESS_VIOLATION = 43,
++ CCERR_INVALID_PD_ID = 44,
++ CCERR_WRAP_ERROR = 45,
++ CCERR_INV_STAG_ACCESS_ERROR = 46,
++ CCERR_ZERO_RDMA_READ_RESOURCES = 47,
++ CCERR_QP_NOT_PRIVILEGED = 48,
++ CCERR_STAG_STATE_NOT_INVALID = 49,
++ CCERR_INVALID_PAGE_SIZE = 50,
++ CCERR_INVALID_BUFFER_SIZE = 51,
++ CCERR_INVALID_PBE = 52,
++ CCERR_INVALID_FBO = 53,
++ CCERR_INVALID_LENGTH = 54,
++ CCERR_INVALID_ACCESS_RIGHTS = 55,
++ CCERR_PBL_TOO_BIG = 56,
++ CCERR_INVALID_VA = 57,
++ CCERR_INVALID_REGION = 58,
++ CCERR_INVALID_WINDOW = 59,
++ CCERR_TOTAL_LENGTH_TOO_BIG = 60,
++ CCERR_INVALID_QP_ID = 61,
++ CCERR_ADDR_IN_USE = 62,
++ CCERR_ADDR_NOT_AVAIL = 63,
++ CCERR_NET_DOWN = 64,
++ CCERR_NET_UNREACHABLE = 65,
++ CCERR_CONN_ABORTED = 66,
++ CCERR_CONN_RESET = 67,
++ CCERR_NO_BUFS = 68,
++ CCERR_CONN_TIMEDOUT = 69,
++ CCERR_CONN_REFUSED = 70,
++ CCERR_HOST_UNREACHABLE = 71,
++ CCERR_INVALID_SEND_SGL_DEPTH = 72,
++ CCERR_INVALID_RECV_SGL_DEPTH = 73,
++ CCERR_INVALID_RDMA_WRITE_SGL_DEPTH = 74,
++ CCERR_INSUFFICIENT_PRIVILEGES = 75,
++ CCERR_STACK_ERROR = 76,
++ CCERR_INVALID_VERSION = 77,
++ CCERR_INVALID_MTU = 78,
++ CCERR_INVALID_IMAGE = 79,
++ CCERR_PENDING = 98, /* not an error; user internally by adapter */
++ CCERR_DEFER = 99, /* not an error; used internally by adapter */
++ CCERR_FAILED_WRITE = 100,
++ CCERR_FAILED_ERASE = 101,
++ CCERR_FAILED_VERIFICATION = 102,
++ CCERR_NOT_FOUND = 103,
++
++};
++
++/*
++ * CCAE_ACTIVE_CONNECT_RESULTS status result codes.
++ */
++enum c2_connect_status {
++ C2_CONN_STATUS_SUCCESS = C2_OK,
++ C2_CONN_STATUS_NO_MEM = CCERR_INSUFFICIENT_RESOURCES,
++ C2_CONN_STATUS_TIMEDOUT = CCERR_CONN_TIMEDOUT,
++ C2_CONN_STATUS_REFUSED = CCERR_CONN_REFUSED,
++ C2_CONN_STATUS_NETUNREACH = CCERR_NET_UNREACHABLE,
++ C2_CONN_STATUS_HOSTUNREACH = CCERR_HOST_UNREACHABLE,
++ C2_CONN_STATUS_INVALID_RNIC = CCERR_INVALID_RNIC,
++ C2_CONN_STATUS_INVALID_QP = CCERR_INVALID_QP,
++ C2_CONN_STATUS_INVALID_QP_STATE = CCERR_INVALID_QP_STATE,
++ C2_CONN_STATUS_REJECTED = CCERR_CONN_RESET,
++ C2_CONN_STATUS_ADDR_NOT_AVAIL = CCERR_ADDR_NOT_AVAIL,
++};
++
++/*
++ * Flash programming status codes.
++ */
++enum c2_flash_status {
++ C2_FLASH_STATUS_SUCCESS = 0x0000,
++ C2_FLASH_STATUS_VERIFY_ERR = 0x0002,
++ C2_FLASH_STATUS_IMAGE_ERR = 0x0004,
++ C2_FLASH_STATUS_ECLBS = 0x0400,
++ C2_FLASH_STATUS_PSLBS = 0x0800,
++ C2_FLASH_STATUS_VPENS = 0x1000,
++};
++
++#endif /* _C2_STATUS_H_ */
+diff --git a/drivers/infiniband/hw/amso1100/c2_user.h b/drivers/infiniband/hw/amso1100/c2_user.h
+new file mode 100644
+index 0000000..7e9e7ad
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_user.h
+@@ -0,0 +1,82 @@
++/*
++ * Copyright (c) 2005 Topspin Communications. All rights reserved.
++ * Copyright (c) 2005 Cisco Systems. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 C2_USER_H
++#define C2_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 c2_alloc_ucontext_resp {
++ __u32 qp_tab_size;
++ __u32 uarc_size;
++};
++
++struct c2_alloc_pd_resp {
++ __u32 pdn;
++ __u32 reserved;
++};
++
++struct c2_create_cq {
++ __u32 lkey;
++ __u32 pdn;
++ __u64 arm_db_page;
++ __u64 set_db_page;
++ __u32 arm_db_index;
++ __u32 set_db_index;
++};
++
++struct c2_create_cq_resp {
++ __u32 cqn;
++ __u32 reserved;
++};
++
++struct c2_create_qp {
++ __u32 lkey;
++ __u32 reserved;
++ __u64 sq_db_page;
++ __u64 rq_db_page;
++ __u32 sq_db_index;
++ __u32 rq_db_index;
++};
++
++#endif /* C2_USER_H */
+diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c
+new file mode 100644
+index 0000000..40caeb5
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_vq.c
+@@ -0,0 +1,260 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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.
++ */
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++#include "c2_vq.h"
++#include "c2_provider.h"
++
++/*
++ * Verbs Request Objects:
++ *
++ * VQ Request Objects are allocated by the kernel verbs handlers.
++ * They contain a wait object, a refcnt, an atomic bool indicating that the
++ * adapter has replied, and a copy of the verb reply work request.
++ * A pointer to the VQ Request Object is passed down in the context
++ * field of the work request message, and reflected back by the adapter
++ * in the verbs reply message. The function handle_vq() in the interrupt
++ * path will use this pointer to:
++ * 1) append a copy of the verbs reply message
++ * 2) mark that the reply is ready
++ * 3) wake up the kernel verbs handler blocked awaiting the reply.
++ *
++ *
++ * The kernel verbs handlers do a "get" to put a 2nd reference on the
++ * VQ Request object. If the kernel verbs handler exits before the adapter
++ * can respond, this extra reference will keep the VQ Request object around
++ * until the adapter's reply can be processed. The reason we need this is
++ * because a pointer to this object is stuffed into the context field of
++ * the verbs work request message, and reflected back in the reply message.
++ * It is used in the interrupt handler (handle_vq()) to wake up the appropriate
++ * kernel verb handler that is blocked awaiting the verb reply.
++ * So handle_vq() will do a "put" on the object when it's done accessing it.
++ * NOTE: If we guarantee that the kernel verb handler will never bail before
++ * getting the reply, then we don't need these refcnts.
++ *
++ *
++ * VQ Request objects are freed by the kernel verbs handlers only
++ * after the verb has been processed, or when the adapter fails and
++ * does not reply.
++ *
++ *
++ * Verbs Reply Buffers:
++ *
++ * VQ Reply bufs are local host memory copies of a
++ * outstanding Verb Request reply
++ * message. The are always allocated by the kernel verbs handlers, and _may_ be
++ * freed by either the kernel verbs handler -or- the interrupt handler. The
++ * kernel verbs handler _must_ free the repbuf, then free the vq request object
++ * in that order.
++ */
++
++int vq_init(struct c2_dev *c2dev)
++{
++ sprintf(c2dev->vq_cache_name, "c2-vq:dev%c",
++ (char) ('0' + c2dev->devnum));
++ c2dev->host_msg_cache =
++ kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (c2dev->host_msg_cache == NULL) {
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++void vq_term(struct c2_dev *c2dev)
++{
++ kmem_cache_destroy(c2dev->host_msg_cache);
++}
++
++/* vq_req_alloc - allocate a VQ Request Object and initialize it.
++ * The refcnt is set to 1.
++ */
++struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
++{
++ struct c2_vq_req *r;
++
++ r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
++ if (r) {
++ init_waitqueue_head(&r->wait_object);
++ r->reply_msg = (u64) NULL;
++ r->event = 0;
++ r->cm_id = NULL;
++ r->qp = NULL;
++ atomic_set(&r->refcnt, 1);
++ atomic_set(&r->reply_ready, 0);
++ }
++ return r;
++}
++
++
++/* vq_req_free - free the VQ Request Object. It is assumed the verbs handler
++ * has already free the VQ Reply Buffer if it existed.
++ */
++void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
++{
++ r->reply_msg = (u64) NULL;
++ if (atomic_dec_and_test(&r->refcnt)) {
++ kfree(r);
++ }
++}
++
++/* vq_req_get - reference a VQ Request Object. Done
++ * only in the kernel verbs handlers.
++ */
++void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
++{
++ atomic_inc(&r->refcnt);
++}
++
++
++/* vq_req_put - dereference and potentially free a VQ Request Object.
++ *
++ * This is only called by handle_vq() on the
++ * interrupt when it is done processing
++ * a verb reply message. If the associated
++ * kernel verbs handler has already bailed,
++ * then this put will actually free the VQ
++ * Request object _and_ the VQ Reply Buffer
++ * if it exists.
++ */
++void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
++{
++ if (atomic_dec_and_test(&r->refcnt)) {
++ if (r->reply_msg != (u64) NULL)
++ vq_repbuf_free(c2dev,
++ (void *) (unsigned long) r->reply_msg);
++ kfree(r);
++ }
++}
++
++
++/*
++ * vq_repbuf_alloc - allocate a VQ Reply Buffer.
++ */
++void *vq_repbuf_alloc(struct c2_dev *c2dev)
++{
++ return kmem_cache_alloc(c2dev->host_msg_cache, SLAB_ATOMIC);
++}
++
++/*
++ * vq_send_wr - post a verbs request message to the Verbs Request Queue.
++ * If a message is not available in the MQ, then block until one is available.
++ * NOTE: handle_mq() on the interrupt context will wake up threads blocked here.
++ * When the adapter drains the Verbs Request Queue,
++ * it inserts MQ index 0 in to the
++ * adapter->host activity fifo and interrupts the host.
++ */
++int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr)
++{
++ void *msg;
++ wait_queue_t __wait;
++
++ /*
++ * grab adapter vq lock
++ */
++ spin_lock(&c2dev->vqlock);
++
++ /*
++ * allocate msg
++ */
++ msg = c2_mq_alloc(&c2dev->req_vq);
++
++ /*
++ * If we cannot get a msg, then we'll wait
++ * When a messages are available, the int handler will wake_up()
++ * any waiters.
++ */
++ while (msg == NULL) {
++ pr_debug("%s:%d no available msg in VQ, waiting...\n",
++ __FUNCTION__, __LINE__);
++ init_waitqueue_entry(&__wait, current);
++ add_wait_queue(&c2dev->req_vq_wo, &__wait);
++ spin_unlock(&c2dev->vqlock);
++ for (;;) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (!c2_mq_full(&c2dev->req_vq)) {
++ break;
++ }
++ if (!signal_pending(current)) {
++ schedule_timeout(1 * HZ); /* 1 second... */
++ continue;
++ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&c2dev->req_vq_wo, &__wait);
++ return -EINTR;
++ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&c2dev->req_vq_wo, &__wait);
++ spin_lock(&c2dev->vqlock);
++ msg = c2_mq_alloc(&c2dev->req_vq);
++ }
++
++ /*
++ * copy wr into adapter msg
++ */
++ memcpy(msg, wr, c2dev->req_vq.msg_size);
++
++ /*
++ * post msg
++ */
++ c2_mq_produce(&c2dev->req_vq);
++
++ /*
++ * release adapter vq lock
++ */
++ spin_unlock(&c2dev->vqlock);
++ return 0;
++}
++
++
++/*
++ * vq_wait_for_reply - block until the adapter posts a Verb Reply Message.
++ */
++int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req)
++{
++ if (!wait_event_timeout(req->wait_object,
++ atomic_read(&req->reply_ready),
++ 60*HZ))
++ return -ETIMEDOUT;
++
++ return 0;
++}
++
++/*
++ * vq_repbuf_free - Free a Verbs Reply Buffer.
++ */
++void vq_repbuf_free(struct c2_dev *c2dev, void *reply)
++{
++ kmem_cache_free(c2dev->host_msg_cache, reply);
++}
+diff --git a/drivers/infiniband/hw/amso1100/c2_vq.h b/drivers/infiniband/hw/amso1100/c2_vq.h
+new file mode 100644
+index 0000000..3380562
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_vq.h
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 _C2_VQ_H_
++#define _C2_VQ_H_
++#include <linux/sched.h>
++#include "c2.h"
++#include "c2_wr.h"
++#include "c2_provider.h"
++
++struct c2_vq_req {
++ u64 reply_msg; /* ptr to reply msg */
++ wait_queue_head_t wait_object; /* wait object for vq reqs */
++ atomic_t reply_ready; /* set when reply is ready */
++ atomic_t refcnt; /* used to cancel WRs... */
++ int event;
++ struct iw_cm_id *cm_id;
++ struct c2_qp *qp;
++};
++
++extern int vq_init(struct c2_dev *c2dev);
++extern void vq_term(struct c2_dev *c2dev);
++
++extern struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev);
++extern void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req);
++extern void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req);
++extern void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req);
++extern int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr);
++
++extern void *vq_repbuf_alloc(struct c2_dev *c2dev);
++extern void vq_repbuf_free(struct c2_dev *c2dev, void *reply);
++
++extern int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req);
++#endif /* _C2_VQ_H_ */
+diff --git a/drivers/infiniband/hw/amso1100/c2_wr.h b/drivers/infiniband/hw/amso1100/c2_wr.h
+new file mode 100644
+index 0000000..3ec6c43
+--- /dev/null
++++ b/drivers/infiniband/hw/amso1100/c2_wr.h
+@@ -0,0 +1,1520 @@
++/*
++ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 _C2_WR_H_
++#define _C2_WR_H_
++
++#ifdef CCDEBUG
++#define CCWR_MAGIC 0xb07700b0
++#endif
++
++#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
++
++/* Maximum allowed size in bytes of private_data exchange
++ * on connect.
++ */
++#define C2_MAX_PRIVATE_DATA_SIZE 200
++
++/*
++ * These types are shared among the adapter, host, and CCIL consumer.
++ */
++enum c2_cq_notification_type {
++ C2_CQ_NOTIFICATION_TYPE_NONE = 1,
++ C2_CQ_NOTIFICATION_TYPE_NEXT,
++ C2_CQ_NOTIFICATION_TYPE_NEXT_SE
++};
++
++enum c2_setconfig_cmd {
++ C2_CFG_ADD_ADDR = 1,
++ C2_CFG_DEL_ADDR = 2,
++ C2_CFG_ADD_ROUTE = 3,
++ C2_CFG_DEL_ROUTE = 4
++};
++
++enum c2_getconfig_cmd {
++ C2_GETCONFIG_ROUTES = 1,
++ C2_GETCONFIG_ADDRS
++};
++
++/*
++ * CCIL Work Request Identifiers
++ */
++enum c2wr_ids {
++ CCWR_RNIC_OPEN = 1,
++ CCWR_RNIC_QUERY,
++ CCWR_RNIC_SETCONFIG,
++ CCWR_RNIC_GETCONFIG,
++ CCWR_RNIC_CLOSE,
++ CCWR_CQ_CREATE,
++ CCWR_CQ_QUERY,
++ CCWR_CQ_MODIFY,
++ CCWR_CQ_DESTROY,
++ CCWR_QP_CONNECT,
++ CCWR_PD_ALLOC,
++ CCWR_PD_DEALLOC,
++ CCWR_SRQ_CREATE,
++ CCWR_SRQ_QUERY,
++ CCWR_SRQ_MODIFY,
++ CCWR_SRQ_DESTROY,
++ CCWR_QP_CREATE,
++ CCWR_QP_QUERY,
++ CCWR_QP_MODIFY,
++ CCWR_QP_DESTROY,
++ CCWR_NSMR_STAG_ALLOC,
++ CCWR_NSMR_REGISTER,
++ CCWR_NSMR_PBL,
++ CCWR_STAG_DEALLOC,
++ CCWR_NSMR_REREGISTER,
++ CCWR_SMR_REGISTER,
++ CCWR_MR_QUERY,
++ CCWR_MW_ALLOC,
++ CCWR_MW_QUERY,
++ CCWR_EP_CREATE,
++ CCWR_EP_GETOPT,
++ CCWR_EP_SETOPT,
++ CCWR_EP_DESTROY,
++ CCWR_EP_BIND,
++ CCWR_EP_CONNECT,
++ CCWR_EP_LISTEN,
++ CCWR_EP_SHUTDOWN,
++ CCWR_EP_LISTEN_CREATE,
++ CCWR_EP_LISTEN_DESTROY,
++ CCWR_EP_QUERY,
++ CCWR_CR_ACCEPT,
++ CCWR_CR_REJECT,
++ CCWR_CONSOLE,
++ CCWR_TERM,
++ CCWR_FLASH_INIT,
++ CCWR_FLASH,
++ CCWR_BUF_ALLOC,
++ CCWR_BUF_FREE,
++ CCWR_FLASH_WRITE,
++ CCWR_INIT, /* WARNING: Don't move this ever again! */
++
++
++
++ /* Add new IDs here */
++
++
++
++ /*
++ * WARNING: CCWR_LAST must always be the last verbs id defined!
++ * All the preceding IDs are fixed, and must not change.
++ * You can add new IDs, but must not remove or reorder
++ * any IDs. If you do, YOU will ruin any hope of
++ * compatability between versions.
++ */
++ CCWR_LAST,
++
++ /*
++ * Start over at 1 so that arrays indexed by user wr id's
++ * begin at 1. This is OK since the verbs and user wr id's
++ * are always used on disjoint sets of queues.
++ */
++ /*
++ * The order of the CCWR_SEND_XX verbs must
++ * match the order of the RDMA_OPs
++ */
++ CCWR_SEND = 1,
++ CCWR_SEND_INV,
++ CCWR_SEND_SE,
++ CCWR_SEND_SE_INV,
++ CCWR_RDMA_WRITE,
++ CCWR_RDMA_READ,
++ CCWR_RDMA_READ_INV,
++ CCWR_MW_BIND,
++ CCWR_NSMR_FASTREG,
++ CCWR_STAG_INVALIDATE,
++ CCWR_RECV,
++ CCWR_NOP,
++ CCWR_UNIMPL,
++/* WARNING: This must always be the last user wr id defined! */
++};
++#define RDMA_SEND_OPCODE_FROM_WR_ID(x) (x+2)
++
++/*
++ * SQ/RQ Work Request Types
++ */
++enum c2_wr_type {
++ C2_WR_TYPE_SEND = CCWR_SEND,
++ C2_WR_TYPE_SEND_SE = CCWR_SEND_SE,
++ C2_WR_TYPE_SEND_INV = CCWR_SEND_INV,
++ C2_WR_TYPE_SEND_SE_INV = CCWR_SEND_SE_INV,
++ C2_WR_TYPE_RDMA_WRITE = CCWR_RDMA_WRITE,
++ C2_WR_TYPE_RDMA_READ = CCWR_RDMA_READ,
++ C2_WR_TYPE_RDMA_READ_INV_STAG = CCWR_RDMA_READ_INV,
++ C2_WR_TYPE_BIND_MW = CCWR_MW_BIND,
++ C2_WR_TYPE_FASTREG_NSMR = CCWR_NSMR_FASTREG,
++ C2_WR_TYPE_INV_STAG = CCWR_STAG_INVALIDATE,
++ C2_WR_TYPE_RECV = CCWR_RECV,
++ C2_WR_TYPE_NOP = CCWR_NOP,
++};
++
++struct c2_netaddr {
++ u32 ip_addr;
++ u32 netmask;
++ u32 mtu;
++};
++
++struct c2_route {
++ u32 ip_addr; /* 0 indicates the default route */
++ u32 netmask; /* netmask associated with dst */
++ u32 flags;
++ union {
++ u32 ipaddr; /* address of the nexthop interface */
++ u8 enaddr[6];
++ } nexthop;
++};
++
++/*
++ * A Scatter Gather Entry.
++ */
++struct c2_data_addr {
++ u32 stag;
++ u32 length;
++ u64 to;
++};
++
++/*
++ * MR and MW flags used by the consumer, RI, and RNIC.
++ */
++enum c2_mm_flags {
++ MEM_REMOTE = 0x0001, /* allow mw binds with remote access. */
++ MEM_VA_BASED = 0x0002, /* Not Zero-based */
++ MEM_PBL_COMPLETE = 0x0004, /* PBL array is complete in this msg */
++ MEM_LOCAL_READ = 0x0008, /* allow local reads */
++ MEM_LOCAL_WRITE = 0x0010, /* allow local writes */
++ MEM_REMOTE_READ = 0x0020, /* allow remote reads */
++ MEM_REMOTE_WRITE = 0x0040, /* allow remote writes */
++ MEM_WINDOW_BIND = 0x0080, /* binds allowed */
++ MEM_SHARED = 0x0100, /* set if MR is shared */
++ MEM_STAG_VALID = 0x0200 /* set if STAG is in valid state */
++};
++
++/*
++ * CCIL API ACF flags defined in terms of the low level mem flags.
++ * This minimizes translation needed in the user API
++ */
++enum c2_acf {
++ C2_ACF_LOCAL_READ = MEM_LOCAL_READ,
++ C2_ACF_LOCAL_WRITE = MEM_LOCAL_WRITE,
++ C2_ACF_REMOTE_READ = MEM_REMOTE_READ,
++ C2_ACF_REMOTE_WRITE = MEM_REMOTE_WRITE,
++ C2_ACF_WINDOW_BIND = MEM_WINDOW_BIND
++};
++
++/*
++ * Image types of objects written to flash
++ */
++#define C2_FLASH_IMG_BITFILE 1
++#define C2_FLASH_IMG_OPTION_ROM 2
++#define C2_FLASH_IMG_VPD 3
++
++/*
++ * to fix bug 1815 we define the max size allowable of the
++ * terminate message (per the IETF spec).Refer to the IETF
++ * protocal specification, section 12.1.6, page 64)
++ * The message is prefixed by 20 types of DDP info.
++ *
++ * Then the message has 6 bytes for the terminate control
++ * and DDP segment length info plus a DDP header (either
++ * 14 or 18 byts) plus 28 bytes for the RDMA header.
++ * Thus the max size in:
++ * 20 + (6 + 18 + 28) = 72
++ */
++#define C2_MAX_TERMINATE_MESSAGE_SIZE (72)
++
++/*
++ * Build String Length. It must be the same as C2_BUILD_STR_LEN in ccil_api.h
++ */
++#define WR_BUILD_STR_LEN 64
++
++/*
++ * WARNING: All of these structs need to align any 64bit types on
++ * 64 bit boundaries! 64bit types include u64 and u64.
++ */
++
++/*
++ * Clustercore Work Request Header. Be sensitive to field layout
++ * and alignment.
++ */
++struct c2wr_hdr {
++ /* wqe_count is part of the cqe. It is put here so the
++ * adapter can write to it while the wr is pending without
++ * clobbering part of the wr. This word need not be dma'd
++ * from the host to adapter by libccil, but we copy it anyway
++ * to make the memcpy to the adapter better aligned.
++ */
++ u32 wqe_count;
++
++ /* Put these fields next so that later 32- and 64-bit
++ * quantities are naturally aligned.
++ */
++ u8 id;
++ u8 result; /* adapter -> host */
++ u8 sge_count; /* host -> adapter */
++ u8 flags; /* host -> adapter */
++
++ u64 context;
++#ifdef CCMSGMAGIC
++ u32 magic;
++ u32 pad;
++#endif
++} __attribute__((packed));
++
++/*
++ *------------------------ RNIC ------------------------
++ */
++
++/*
++ * WR_RNIC_OPEN
++ */
++
++/*
++ * Flags for the RNIC WRs
++ */
++enum c2_rnic_flags {
++ RNIC_IRD_STATIC = 0x0001,
++ RNIC_ORD_STATIC = 0x0002,
++ RNIC_QP_STATIC = 0x0004,
++ RNIC_SRQ_SUPPORTED = 0x0008,
++ RNIC_PBL_BLOCK_MODE = 0x0010,
++ RNIC_SRQ_MODEL_ARRIVAL = 0x0020,
++ RNIC_CQ_OVF_DETECTED = 0x0040,
++ RNIC_PRIV_MODE = 0x0080
++};
++
++struct c2wr_rnic_open_req {
++ struct c2wr_hdr hdr;
++ u64 user_context;
++ u16 flags; /* See enum c2_rnic_flags */
++ u16 port_num;
++} __attribute__((packed));
++
++struct c2wr_rnic_open_rep {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++} __attribute__((packed));
++
++union c2wr_rnic_open {
++ struct c2wr_rnic_open_req req;
++ struct c2wr_rnic_open_rep rep;
++} __attribute__((packed));
++
++struct c2wr_rnic_query_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++} __attribute__((packed));
++
++/*
++ * WR_RNIC_QUERY
++ */
++struct c2wr_rnic_query_rep {
++ struct c2wr_hdr hdr;
++ u64 user_context;
++ u32 vendor_id;
++ u32 part_number;
++ u32 hw_version;
++ u32 fw_ver_major;
++ u32 fw_ver_minor;
++ u32 fw_ver_patch;
++ char fw_ver_build_str[WR_BUILD_STR_LEN];
++ u32 max_qps;
++ u32 max_qp_depth;
++ u32 max_srq_depth;
++ u32 max_send_sgl_depth;
++ u32 max_rdma_sgl_depth;
++ u32 max_cqs;
++ u32 max_cq_depth;
++ u32 max_cq_event_handlers;
++ u32 max_mrs;
++ u32 max_pbl_depth;
++ u32 max_pds;
++ u32 max_global_ird;
++ u32 max_global_ord;
++ u32 max_qp_ird;
++ u32 max_qp_ord;
++ u32 flags;
++ u32 max_mws;
++ u32 pbe_range_low;
++ u32 pbe_range_high;
++ u32 max_srqs;
++ u32 page_size;
++} __attribute__((packed));
++
++union c2wr_rnic_query {
++ struct c2wr_rnic_query_req req;
++ struct c2wr_rnic_query_rep rep;
++} __attribute__((packed));
++
++/*
++ * WR_RNIC_GETCONFIG
++ */
++
++struct c2wr_rnic_getconfig_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 option; /* see c2_getconfig_cmd_t */
++ u64 reply_buf;
++ u32 reply_buf_len;
++} __attribute__((packed)) ;
++
++struct c2wr_rnic_getconfig_rep {
++ struct c2wr_hdr hdr;
++ u32 option; /* see c2_getconfig_cmd_t */
++ u32 count_len; /* length of the number of addresses configured */
++} __attribute__((packed)) ;
++
++union c2wr_rnic_getconfig {
++ struct c2wr_rnic_getconfig_req req;
++ struct c2wr_rnic_getconfig_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ * WR_RNIC_SETCONFIG
++ */
++struct c2wr_rnic_setconfig_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 option; /* See c2_setconfig_cmd_t */
++ /* variable data and pad. See c2_netaddr and c2_route */
++ u8 data[0];
++} __attribute__((packed)) ;
++
++struct c2wr_rnic_setconfig_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_rnic_setconfig {
++ struct c2wr_rnic_setconfig_req req;
++ struct c2wr_rnic_setconfig_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ * WR_RNIC_CLOSE
++ */
++struct c2wr_rnic_close_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++} __attribute__((packed)) ;
++
++struct c2wr_rnic_close_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_rnic_close {
++ struct c2wr_rnic_close_req req;
++ struct c2wr_rnic_close_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ *------------------------ CQ ------------------------
++ */
++struct c2wr_cq_create_req {
++ struct c2wr_hdr hdr;
++ u64 shared_ht;
++ u64 user_context;
++ u64 msg_pool;
++ u32 rnic_handle;
++ u32 msg_size;
++ u32 depth;
++} __attribute__((packed)) ;
++
++struct c2wr_cq_create_rep {
++ struct c2wr_hdr hdr;
++ u32 mq_index;
++ u32 adapter_shared;
++ u32 cq_handle;
++} __attribute__((packed)) ;
++
++union c2wr_cq_create {
++ struct c2wr_cq_create_req req;
++ struct c2wr_cq_create_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_cq_modify_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 cq_handle;
++ u32 new_depth;
++ u64 new_msg_pool;
++} __attribute__((packed)) ;
++
++struct c2wr_cq_modify_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_cq_modify {
++ struct c2wr_cq_modify_req req;
++ struct c2wr_cq_modify_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_cq_destroy_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 cq_handle;
++} __attribute__((packed)) ;
++
++struct c2wr_cq_destroy_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_cq_destroy {
++ struct c2wr_cq_destroy_req req;
++ struct c2wr_cq_destroy_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ *------------------------ PD ------------------------
++ */
++struct c2wr_pd_alloc_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 pd_id;
++} __attribute__((packed)) ;
++
++struct c2wr_pd_alloc_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_pd_alloc {
++ struct c2wr_pd_alloc_req req;
++ struct c2wr_pd_alloc_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_pd_dealloc_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 pd_id;
++} __attribute__((packed)) ;
++
++struct c2wr_pd_dealloc_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_pd_dealloc {
++ struct c2wr_pd_dealloc_req req;
++ struct c2wr_pd_dealloc_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ *------------------------ SRQ ------------------------
++ */
++struct c2wr_srq_create_req {
++ struct c2wr_hdr hdr;
++ u64 shared_ht;
++ u64 user_context;
++ u32 rnic_handle;
++ u32 srq_depth;
++ u32 srq_limit;
++ u32 sgl_depth;
++ u32 pd_id;
++} __attribute__((packed)) ;
++
++struct c2wr_srq_create_rep {
++ struct c2wr_hdr hdr;
++ u32 srq_depth;
++ u32 sgl_depth;
++ u32 msg_size;
++ u32 mq_index;
++ u32 mq_start;
++ u32 srq_handle;
++} __attribute__((packed)) ;
++
++union c2wr_srq_create {
++ struct c2wr_srq_create_req req;
++ struct c2wr_srq_create_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_srq_destroy_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 srq_handle;
++} __attribute__((packed)) ;
++
++struct c2wr_srq_destroy_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_srq_destroy {
++ struct c2wr_srq_destroy_req req;
++ struct c2wr_srq_destroy_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ *------------------------ QP ------------------------
++ */
++enum c2wr_qp_flags {
++ QP_RDMA_READ = 0x00000001, /* RDMA read enabled? */
++ QP_RDMA_WRITE = 0x00000002, /* RDMA write enabled? */
++ QP_MW_BIND = 0x00000004, /* MWs enabled */
++ QP_ZERO_STAG = 0x00000008, /* enabled? */
++ QP_REMOTE_TERMINATION = 0x00000010, /* remote end terminated */
++ QP_RDMA_READ_RESPONSE = 0x00000020 /* Remote RDMA read */
++ /* enabled? */
++};
++
++struct c2wr_qp_create_req {
++ struct c2wr_hdr hdr;
++ u64 shared_sq_ht;
++ u64 shared_rq_ht;
++ u64 user_context;
++ u32 rnic_handle;
++ u32 sq_cq_handle;
++ u32 rq_cq_handle;
++ u32 sq_depth;
++ u32 rq_depth;
++ u32 srq_handle;
++ u32 srq_limit;
++ u32 flags; /* see enum c2wr_qp_flags */
++ u32 send_sgl_depth;
++ u32 recv_sgl_depth;
++ u32 rdma_write_sgl_depth;
++ u32 ord;
++ u32 ird;
++ u32 pd_id;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_create_rep {
++ struct c2wr_hdr hdr;
++ u32 sq_depth;
++ u32 rq_depth;
++ u32 send_sgl_depth;
++ u32 recv_sgl_depth;
++ u32 rdma_write_sgl_depth;
++ u32 ord;
++ u32 ird;
++ u32 sq_msg_size;
++ u32 sq_mq_index;
++ u32 sq_mq_start;
++ u32 rq_msg_size;
++ u32 rq_mq_index;
++ u32 rq_mq_start;
++ u32 qp_handle;
++} __attribute__((packed)) ;
++
++union c2wr_qp_create {
++ struct c2wr_qp_create_req req;
++ struct c2wr_qp_create_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_query_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 qp_handle;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_query_rep {
++ struct c2wr_hdr hdr;
++ u64 user_context;
++ u32 rnic_handle;
++ u32 sq_depth;
++ u32 rq_depth;
++ u32 send_sgl_depth;
++ u32 rdma_write_sgl_depth;
++ u32 recv_sgl_depth;
++ u32 ord;
++ u32 ird;
++ u16 qp_state;
++ u16 flags; /* see c2wr_qp_flags_t */
++ u32 qp_id;
++ u32 local_addr;
++ u32 remote_addr;
++ u16 local_port;
++ u16 remote_port;
++ u32 terminate_msg_length; /* 0 if not present */
++ u8 data[0];
++ /* Terminate Message in-line here. */
++} __attribute__((packed)) ;
++
++union c2wr_qp_query {
++ struct c2wr_qp_query_req req;
++ struct c2wr_qp_query_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_modify_req {
++ struct c2wr_hdr hdr;
++ u64 stream_msg;
++ u32 stream_msg_length;
++ u32 rnic_handle;
++ u32 qp_handle;
++ u32 next_qp_state;
++ u32 ord;
++ u32 ird;
++ u32 sq_depth;
++ u32 rq_depth;
++ u32 llp_ep_handle;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_modify_rep {
++ struct c2wr_hdr hdr;
++ u32 ord;
++ u32 ird;
++ u32 sq_depth;
++ u32 rq_depth;
++ u32 sq_msg_size;
++ u32 sq_mq_index;
++ u32 sq_mq_start;
++ u32 rq_msg_size;
++ u32 rq_mq_index;
++ u32 rq_mq_start;
++} __attribute__((packed)) ;
++
++union c2wr_qp_modify {
++ struct c2wr_qp_modify_req req;
++ struct c2wr_qp_modify_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_destroy_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 qp_handle;
++} __attribute__((packed)) ;
++
++struct c2wr_qp_destroy_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_qp_destroy {
++ struct c2wr_qp_destroy_req req;
++ struct c2wr_qp_destroy_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ * The CCWR_QP_CONNECT msg is posted on the verbs request queue. It can
++ * only be posted when a QP is in IDLE state. After the connect request is
++ * submitted to the LLP, the adapter moves the QP to CONNECT_PENDING state.
++ * No synchronous reply from adapter to this WR. The results of
++ * connection are passed back in an async event CCAE_ACTIVE_CONNECT_RESULTS
++ * See c2wr_ae_active_connect_results_t
++ */
++struct c2wr_qp_connect_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 qp_handle;
++ u32 remote_addr;
++ u16 remote_port;
++ u16 pad;
++ u32 private_data_length;
++ u8 private_data[0]; /* Private data in-line. */
++} __attribute__((packed)) ;
++
++struct c2wr_qp_connect {
++ struct c2wr_qp_connect_req req;
++ /* no synchronous reply. */
++} __attribute__((packed)) ;
++
++
++/*
++ *------------------------ MM ------------------------
++ */
++
++struct c2wr_nsmr_stag_alloc_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 pbl_depth;
++ u32 pd_id;
++ u32 flags;
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_stag_alloc_rep {
++ struct c2wr_hdr hdr;
++ u32 pbl_depth;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++union c2wr_nsmr_stag_alloc {
++ struct c2wr_nsmr_stag_alloc_req req;
++ struct c2wr_nsmr_stag_alloc_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_register_req {
++ struct c2wr_hdr hdr;
++ u64 va;
++ u32 rnic_handle;
++ u16 flags;
++ u8 stag_key;
++ u8 pad;
++ u32 pd_id;
++ u32 pbl_depth;
++ u32 pbe_size;
++ u32 fbo;
++ u32 length;
++ u32 addrs_length;
++ /* array of paddrs (must be aligned on a 64bit boundary) */
++ u64 paddrs[0];
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_register_rep {
++ struct c2wr_hdr hdr;
++ u32 pbl_depth;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++union c2wr_nsmr_register {
++ struct c2wr_nsmr_register_req req;
++ struct c2wr_nsmr_register_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_pbl_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 flags;
++ u32 stag_index;
++ u32 addrs_length;
++ /* array of paddrs (must be aligned on a 64bit boundary) */
++ u64 paddrs[0];
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_pbl_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_nsmr_pbl {
++ struct c2wr_nsmr_pbl_req req;
++ struct c2wr_nsmr_pbl_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_mr_query_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++struct c2wr_mr_query_rep {
++ struct c2wr_hdr hdr;
++ u8 stag_key;
++ u8 pad[3];
++ u32 pd_id;
++ u32 flags;
++ u32 pbl_depth;
++} __attribute__((packed)) ;
++
++union c2wr_mr_query {
++ struct c2wr_mr_query_req req;
++ struct c2wr_mr_query_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_mw_query_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++struct c2wr_mw_query_rep {
++ struct c2wr_hdr hdr;
++ u8 stag_key;
++ u8 pad[3];
++ u32 pd_id;
++ u32 flags;
++} __attribute__((packed)) ;
++
++union c2wr_mw_query {
++ struct c2wr_mw_query_req req;
++ struct c2wr_mw_query_rep rep;
++} __attribute__((packed)) ;
++
++
++struct c2wr_stag_dealloc_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++struct c2wr_stag_dealloc_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed)) ;
++
++union c2wr_stag_dealloc {
++ struct c2wr_stag_dealloc_req req;
++ struct c2wr_stag_dealloc_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_reregister_req {
++ struct c2wr_hdr hdr;
++ u64 va;
++ u32 rnic_handle;
++ u16 flags;
++ u8 stag_key;
++ u8 pad;
++ u32 stag_index;
++ u32 pd_id;
++ u32 pbl_depth;
++ u32 pbe_size;
++ u32 fbo;
++ u32 length;
++ u32 addrs_length;
++ u32 pad1;
++ /* array of paddrs (must be aligned on a 64bit boundary) */
++ u64 paddrs[0];
++} __attribute__((packed)) ;
++
++struct c2wr_nsmr_reregister_rep {
++ struct c2wr_hdr hdr;
++ u32 pbl_depth;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++union c2wr_nsmr_reregister {
++ struct c2wr_nsmr_reregister_req req;
++ struct c2wr_nsmr_reregister_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_smr_register_req {
++ struct c2wr_hdr hdr;
++ u64 va;
++ u32 rnic_handle;
++ u16 flags;
++ u8 stag_key;
++ u8 pad;
++ u32 stag_index;
++ u32 pd_id;
++} __attribute__((packed)) ;
++
++struct c2wr_smr_register_rep {
++ struct c2wr_hdr hdr;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++union c2wr_smr_register {
++ struct c2wr_smr_register_req req;
++ struct c2wr_smr_register_rep rep;
++} __attribute__((packed)) ;
++
++struct c2wr_mw_alloc_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 pd_id;
++} __attribute__((packed)) ;
++
++struct c2wr_mw_alloc_rep {
++ struct c2wr_hdr hdr;
++ u32 stag_index;
++} __attribute__((packed)) ;
++
++union c2wr_mw_alloc {
++ struct c2wr_mw_alloc_req req;
++ struct c2wr_mw_alloc_rep rep;
++} __attribute__((packed)) ;
++
++/*
++ *------------------------ WRs -----------------------
++ */
++
++struct c2wr_user_hdr {
++ struct c2wr_hdr hdr; /* Has status and WR Type */
++} __attribute__((packed)) ;
++
++enum c2_qp_state {
++ C2_QP_STATE_IDLE = 0x01,
++ C2_QP_STATE_CONNECTING = 0x02,
++ C2_QP_STATE_RTS = 0x04,
++ C2_QP_STATE_CLOSING = 0x08,
++ C2_QP_STATE_TERMINATE = 0x10,
++ C2_QP_STATE_ERROR = 0x20,
++};
++
++/* Completion queue entry. */
++struct c2wr_ce {
++ struct c2wr_hdr hdr; /* Has status and WR Type */
++ u64 qp_user_context; /* c2_user_qp_t * */
++ u32 qp_state; /* Current QP State */
++ u32 handle; /* QPID or EP Handle */
++ u32 bytes_rcvd; /* valid for RECV WCs */
++ u32 stag;
++} __attribute__((packed)) ;
++
++
++/*
++ * Flags used for all post-sq WRs. These must fit in the flags
++ * field of the struct c2wr_hdr (eight bits).
++ */
++enum {
++ SQ_SIGNALED = 0x01,
++ SQ_READ_FENCE = 0x02,
++ SQ_FENCE = 0x04,
++};
++
++/*
++ * Common fields for all post-sq WRs. Namely the standard header and a
++ * secondary header with fields common to all post-sq WRs.
++ */
++struct c2_sq_hdr {
++ struct c2wr_user_hdr user_hdr;
++} __attribute__((packed));
++
++/*
++ * Same as above but for post-rq WRs.
++ */
++struct c2_rq_hdr {
++ struct c2wr_user_hdr user_hdr;
++} __attribute__((packed));
++
++/*
++ * use the same struct for all sends.
++ */
++struct c2wr_send_req {
++ struct c2_sq_hdr sq_hdr;
++ u32 sge_len;
++ u32 remote_stag;
++ u8 data[0]; /* SGE array */
++} __attribute__((packed));
++
++union c2wr_send {
++ struct c2wr_send_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++struct c2wr_rdma_write_req {
++ struct c2_sq_hdr sq_hdr;
++ u64 remote_to;
++ u32 remote_stag;
++ u32 sge_len;
++ u8 data[0]; /* SGE array */
++} __attribute__((packed));
++
++union c2wr_rdma_write {
++ struct c2wr_rdma_write_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++struct c2wr_rdma_read_req {
++ struct c2_sq_hdr sq_hdr;
++ u64 local_to;
++ u64 remote_to;
++ u32 local_stag;
++ u32 remote_stag;
++ u32 length;
++} __attribute__((packed));
++
++union c2wr_rdma_read {
++ struct c2wr_rdma_read_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++struct c2wr_mw_bind_req {
++ struct c2_sq_hdr sq_hdr;
++ u64 va;
++ u8 stag_key;
++ u8 pad[3];
++ u32 mw_stag_index;
++ u32 mr_stag_index;
++ u32 length;
++ u32 flags;
++} __attribute__((packed));
++
++union c2wr_mw_bind {
++ struct c2wr_mw_bind_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++struct c2wr_nsmr_fastreg_req {
++ struct c2_sq_hdr sq_hdr;
++ u64 va;
++ u8 stag_key;
++ u8 pad[3];
++ u32 stag_index;
++ u32 pbe_size;
++ u32 fbo;
++ u32 length;
++ u32 addrs_length;
++ /* array of paddrs (must be aligned on a 64bit boundary) */
++ u64 paddrs[0];
++} __attribute__((packed));
++
++union c2wr_nsmr_fastreg {
++ struct c2wr_nsmr_fastreg_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++struct c2wr_stag_invalidate_req {
++ struct c2_sq_hdr sq_hdr;
++ u8 stag_key;
++ u8 pad[3];
++ u32 stag_index;
++} __attribute__((packed));
++
++union c2wr_stag_invalidate {
++ struct c2wr_stag_invalidate_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++union c2wr_sqwr {
++ struct c2_sq_hdr sq_hdr;
++ struct c2wr_send_req send;
++ struct c2wr_send_req send_se;
++ struct c2wr_send_req send_inv;
++ struct c2wr_send_req send_se_inv;
++ struct c2wr_rdma_write_req rdma_write;
++ struct c2wr_rdma_read_req rdma_read;
++ struct c2wr_mw_bind_req mw_bind;
++ struct c2wr_nsmr_fastreg_req nsmr_fastreg;
++ struct c2wr_stag_invalidate_req stag_inv;
++} __attribute__((packed));
++
++
++/*
++ * RQ WRs
++ */
++struct c2wr_rqwr {
++ struct c2_rq_hdr rq_hdr;
++ u8 data[0]; /* array of SGEs */
++} __attribute__((packed));
++
++union c2wr_recv {
++ struct c2wr_rqwr req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++/*
++ * All AEs start with this header. Most AEs only need to convey the
++ * information in the header. Some, like LLP connection events, need
++ * more info. The union typdef c2wr_ae_t has all the possible AEs.
++ *
++ * hdr.context is the user_context from the rnic_open WR. NULL If this
++ * is not affiliated with an rnic
++ *
++ * hdr.id is the AE identifier (eg; CCAE_REMOTE_SHUTDOWN,
++ * CCAE_LLP_CLOSE_COMPLETE)
++ *
++ * resource_type is one of: C2_RES_IND_QP, C2_RES_IND_CQ, C2_RES_IND_SRQ
++ *
++ * user_context is the context passed down when the host created the resource.
++ */
++struct c2wr_ae_hdr {
++ struct c2wr_hdr hdr;
++ u64 user_context; /* user context for this res. */
++ u32 resource_type; /* see enum c2_resource_indicator */
++ u32 resource; /* handle for resource */
++ u32 qp_state; /* current QP State */
++} __attribute__((packed));
++
++/*
++ * After submitting the CCAE_ACTIVE_CONNECT_RESULTS message on the AEQ,
++ * the adapter moves the QP into RTS state
++ */
++struct c2wr_ae_active_connect_results {
++ struct c2wr_ae_hdr ae_hdr;
++ u32 laddr;
++ u32 raddr;
++ u16 lport;
++ u16 rport;
++ u32 private_data_length;
++ u8 private_data[0]; /* data is in-line in the msg. */
++} __attribute__((packed));
++
++/*
++ * When connections are established by the stack (and the private data
++ * MPA frame is received), the adapter will generate an event to the host.
++ * The details of the connection, any private data, and the new connection
++ * request handle is passed up via the CCAE_CONNECTION_REQUEST msg on the
++ * AE queue:
++ */
++struct c2wr_ae_connection_request {
++ struct c2wr_ae_hdr ae_hdr;
++ u32 cr_handle; /* connreq handle (sock ptr) */
++ u32 laddr;
++ u32 raddr;
++ u16 lport;
++ u16 rport;
++ u32 private_data_length;
++ u8 private_data[0]; /* data is in-line in the msg. */
++} __attribute__((packed));
++
++union c2wr_ae {
++ struct c2wr_ae_hdr ae_generic;
++ struct c2wr_ae_active_connect_results ae_active_connect_results;
++ struct c2wr_ae_connection_request ae_connection_request;
++} __attribute__((packed));
++
++struct c2wr_init_req {
++ struct c2wr_hdr hdr;
++ u64 hint_count;
++ u64 q0_host_shared;
++ u64 q1_host_shared;
++ u64 q1_host_msg_pool;
++ u64 q2_host_shared;
++ u64 q2_host_msg_pool;
++} __attribute__((packed));
++
++struct c2wr_init_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed));
++
++union c2wr_init {
++ struct c2wr_init_req req;
++ struct c2wr_init_rep rep;
++} __attribute__((packed));
++
++/*
++ * For upgrading flash.
++ */
++
++struct c2wr_flash_init_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++} __attribute__((packed));
++
++struct c2wr_flash_init_rep {
++ struct c2wr_hdr hdr;
++ u32 adapter_flash_buf_offset;
++ u32 adapter_flash_len;
++} __attribute__((packed));
++
++union c2wr_flash_init {
++ struct c2wr_flash_init_req req;
++ struct c2wr_flash_init_rep rep;
++} __attribute__((packed));
++
++struct c2wr_flash_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 len;
++} __attribute__((packed));
++
++struct c2wr_flash_rep {
++ struct c2wr_hdr hdr;
++ u32 status;
++} __attribute__((packed));
++
++union c2wr_flash {
++ struct c2wr_flash_req req;
++ struct c2wr_flash_rep rep;
++} __attribute__((packed));
++
++struct c2wr_buf_alloc_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 size;
++} __attribute__((packed));
++
++struct c2wr_buf_alloc_rep {
++ struct c2wr_hdr hdr;
++ u32 offset; /* 0 if mem not available */
++ u32 size; /* 0 if mem not available */
++} __attribute__((packed));
++
++union c2wr_buf_alloc {
++ struct c2wr_buf_alloc_req req;
++ struct c2wr_buf_alloc_rep rep;
++} __attribute__((packed));
++
++struct c2wr_buf_free_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 offset; /* Must match value from alloc */
++ u32 size; /* Must match value from alloc */
++} __attribute__((packed));
++
++struct c2wr_buf_free_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed));
++
++union c2wr_buf_free {
++ struct c2wr_buf_free_req req;
++ struct c2wr_ce rep;
++} __attribute__((packed));
++
++struct c2wr_flash_write_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 offset;
++ u32 size;
++ u32 type;
++ u32 flags;
++} __attribute__((packed));
++
++struct c2wr_flash_write_rep {
++ struct c2wr_hdr hdr;
++ u32 status;
++} __attribute__((packed));
++
++union c2wr_flash_write {
++ struct c2wr_flash_write_req req;
++ struct c2wr_flash_write_rep rep;
++} __attribute__((packed));
++
++/*
++ * Messages for LLP connection setup.
++ */
++
++/*
++ * Listen Request. This allocates a listening endpoint to allow passive
++ * connection setup. Newly established LLP connections are passed up
++ * via an AE. See c2wr_ae_connection_request_t
++ */
++struct c2wr_ep_listen_create_req {
++ struct c2wr_hdr hdr;
++ u64 user_context; /* returned in AEs. */
++ u32 rnic_handle;
++ u32 local_addr; /* local addr, or 0 */
++ u16 local_port; /* 0 means "pick one" */
++ u16 pad;
++ u32 backlog; /* tradional tcp listen bl */
++} __attribute__((packed));
++
++struct c2wr_ep_listen_create_rep {
++ struct c2wr_hdr hdr;
++ u32 ep_handle; /* handle to new listening ep */
++ u16 local_port; /* resulting port... */
++ u16 pad;
++} __attribute__((packed));
++
++union c2wr_ep_listen_create {
++ struct c2wr_ep_listen_create_req req;
++ struct c2wr_ep_listen_create_rep rep;
++} __attribute__((packed));
++
++struct c2wr_ep_listen_destroy_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 ep_handle;
++} __attribute__((packed));
++
++struct c2wr_ep_listen_destroy_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed));
++
++union c2wr_ep_listen_destroy {
++ struct c2wr_ep_listen_destroy_req req;
++ struct c2wr_ep_listen_destroy_rep rep;
++} __attribute__((packed));
++
++struct c2wr_ep_query_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 ep_handle;
++} __attribute__((packed));
++
++struct c2wr_ep_query_rep {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 local_addr;
++ u32 remote_addr;
++ u16 local_port;
++ u16 remote_port;
++} __attribute__((packed));
++
++union c2wr_ep_query {
++ struct c2wr_ep_query_req req;
++ struct c2wr_ep_query_rep rep;
++} __attribute__((packed));
++
++
++/*
++ * The host passes this down to indicate acceptance of a pending iWARP
++ * connection. The cr_handle was obtained from the CONNECTION_REQUEST
++ * AE passed up by the adapter. See c2wr_ae_connection_request_t.
++ */
++struct c2wr_cr_accept_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 qp_handle; /* QP to bind to this LLP conn */
++ u32 ep_handle; /* LLP handle to accept */
++ u32 private_data_length;
++ u8 private_data[0]; /* data in-line in msg. */
++} __attribute__((packed));
++
++/*
++ * adapter sends reply when private data is successfully submitted to
++ * the LLP.
++ */
++struct c2wr_cr_accept_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed));
++
++union c2wr_cr_accept {
++ struct c2wr_cr_accept_req req;
++ struct c2wr_cr_accept_rep rep;
++} __attribute__((packed));
++
++/*
++ * The host sends this down if a given iWARP connection request was
++ * rejected by the consumer. The cr_handle was obtained from a
++ * previous c2wr_ae_connection_request_t AE sent by the adapter.
++ */
++struct c2wr_cr_reject_req {
++ struct c2wr_hdr hdr;
++ u32 rnic_handle;
++ u32 ep_handle; /* LLP handle to reject */
++} __attribute__((packed));
++
++/*
++ * Dunno if this is needed, but we'll add it for now. The adapter will
++ * send the reject_reply after the LLP endpoint has been destroyed.
++ */
++struct c2wr_cr_reject_rep {
++ struct c2wr_hdr hdr;
++} __attribute__((packed));
++
++union c2wr_cr_reject {
++ struct c2wr_cr_reject_req req;
++ struct c2wr_cr_reject_rep rep;
++} __attribute__((packed));
++
++/*
++ * console command. Used to implement a debug console over the verbs
++ * request and reply queues.
++ */
++
++/*
++ * Console request message. It contains:
++ * - message hdr with id = CCWR_CONSOLE
++ * - the physaddr/len of host memory to be used for the reply.
++ * - the command string. eg: "netstat -s" or "zoneinfo"
++ */
++struct c2wr_console_req {
++ struct c2wr_hdr hdr; /* id = CCWR_CONSOLE */
++ u64 reply_buf; /* pinned host buf for reply */
++ u32 reply_buf_len; /* length of reply buffer */
++ u8 command[0]; /* NUL terminated ascii string */
++ /* containing the command req */
++} __attribute__((packed));
++
++/*
++ * flags used in the console reply.
++ */
++enum c2_console_flags {
++ CONS_REPLY_TRUNCATED = 0x00000001 /* reply was truncated */
++} __attribute__((packed));
++
++/*
++ * Console reply message.
++ * hdr.result contains the c2_status_t error if the reply was _not_ generated,
++ * or C2_OK if the reply was generated.
++ */
++struct c2wr_console_rep {
++ struct c2wr_hdr hdr; /* id = CCWR_CONSOLE */
++ u32 flags;
++} __attribute__((packed));
++
++union c2wr_console {
++ struct c2wr_console_req req;
++ struct c2wr_console_rep rep;
++} __attribute__((packed));
++
++
++/*
++ * Giant union with all WRs. Makes life easier...
++ */
++union c2wr {
++ struct c2wr_hdr hdr;
++ struct c2wr_user_hdr user_hdr;
++ union c2wr_rnic_open rnic_open;
++ union c2wr_rnic_query rnic_query;
++ union c2wr_rnic_getconfig rnic_getconfig;
++ union c2wr_rnic_setconfig rnic_setconfig;
++ union c2wr_rnic_close rnic_close;
++ union c2wr_cq_create cq_create;
++ union c2wr_cq_modify cq_modify;
++ union c2wr_cq_destroy cq_destroy;
++ union c2wr_pd_alloc pd_alloc;
++ union c2wr_pd_dealloc pd_dealloc;
++ union c2wr_srq_create srq_create;
++ union c2wr_srq_destroy srq_destroy;
++ union c2wr_qp_create qp_create;
++ union c2wr_qp_query qp_query;
++ union c2wr_qp_modify qp_modify;
++ union c2wr_qp_destroy qp_destroy;
++ struct c2wr_qp_connect qp_connect;
++ union c2wr_nsmr_stag_alloc nsmr_stag_alloc;
++ union c2wr_nsmr_register nsmr_register;
++ union c2wr_nsmr_pbl nsmr_pbl;
++ union c2wr_mr_query mr_query;
++ union c2wr_mw_query mw_query;
++ union c2wr_stag_dealloc stag_dealloc;
++ union c2wr_sqwr sqwr;
++ struct c2wr_rqwr rqwr;
++ struct c2wr_ce ce;
++ union c2wr_ae ae;
++ union c2wr_init init;
++ union c2wr_ep_listen_create ep_listen_create;
++ union c2wr_ep_listen_destroy ep_listen_destroy;
++ union c2wr_cr_accept cr_accept;
++ union c2wr_cr_reject cr_reject;
++ union c2wr_console console;
++ union c2wr_flash_init flash_init;
++ union c2wr_flash flash;
++ union c2wr_buf_alloc buf_alloc;
++ union c2wr_buf_free buf_free;
++ union c2wr_flash_write flash_write;
++} __attribute__((packed));
++
++
++/*
++ * Accessors for the wr fields that are packed together tightly to
++ * reduce the wr message size. The wr arguments are void* so that
++ * either a struct c2wr*, a struct c2wr_hdr*, or a pointer to any of the types
++ * in the struct c2wr union can be passed in.
++ */
++static __inline__ u8 c2_wr_get_id(void *wr)
++{
++ return ((struct c2wr_hdr *) wr)->id;
++}
++static __inline__ void c2_wr_set_id(void *wr, u8 id)
++{
++ ((struct c2wr_hdr *) wr)->id = id;
++}
++static __inline__ u8 c2_wr_get_result(void *wr)
++{
++ return ((struct c2wr_hdr *) wr)->result;
++}
++static __inline__ void c2_wr_set_result(void *wr, u8 result)
++{
++ ((struct c2wr_hdr *) wr)->result = result;
++}
++static __inline__ u8 c2_wr_get_flags(void *wr)
++{
++ return ((struct c2wr_hdr *) wr)->flags;
++}
++static __inline__ void c2_wr_set_flags(void *wr, u8 flags)
++{
++ ((struct c2wr_hdr *) wr)->flags = flags;
++}
++static __inline__ u8 c2_wr_get_sge_count(void *wr)
++{
++ return ((struct c2wr_hdr *) wr)->sge_count;
++}
++static __inline__ void c2_wr_set_sge_count(void *wr, u8 sge_count)
++{
++ ((struct c2wr_hdr *) wr)->sge_count = sge_count;
++}
++static __inline__ u32 c2_wr_get_wqe_count(void *wr)
++{
++ return ((struct c2wr_hdr *) wr)->wqe_count;
++}
++static __inline__ void c2_wr_set_wqe_count(void *wr, u32 wqe_count)
++{
++ ((struct c2wr_hdr *) wr)->wqe_count = wqe_count;
++}
++
++#endif /* _C2_WR_H_ */
+diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig
+new file mode 100644
+index 0000000..922389b
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/Kconfig
+@@ -0,0 +1,16 @@
++config INFINIBAND_EHCA
++ tristate "eHCA support"
++ depends on IBMEBUS && INFINIBAND
++ ---help---
++ This driver supports the IBM pSeries eHCA InfiniBand adapter.
++
++ To compile the driver as a module, choose M here. The module
++ will be called ib_ehca.
++
++config INFINIBAND_EHCA_SCALING
++ bool "Scaling support (EXPERIMENTAL)"
++ depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL
++ ---help---
++ eHCA scaling support schedules the CQ callbacks to different CPUs.
++
++ To enable this feature choose Y here.
+diff --git a/drivers/infiniband/hw/ehca/Makefile b/drivers/infiniband/hw/ehca/Makefile
+new file mode 100644
+index 0000000..74d284e
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/Makefile
+@@ -0,0 +1,16 @@
++# Authors: Heiko J Schick <schickhj at de.ibm.com>
++# Christoph Raisch <raisch at de.ibm.com>
++# Joachim Fenkes <fenkes at de.ibm.com>
++#
++# Copyright (c) 2005 IBM Corporation
++#
++# All rights reserved.
++#
++# This source code is distributed under a dual license of GPL v2.0 and OpenIB BSD.
++
++obj-$(CONFIG_INFINIBAND_EHCA) += ib_ehca.o
++
++ib_ehca-objs = ehca_main.o ehca_hca.o ehca_mcast.o ehca_pd.o ehca_av.o ehca_eq.o \
++ ehca_cq.o ehca_qp.o ehca_sqp.o ehca_mrmw.o ehca_reqs.o ehca_irq.o \
++ ehca_uverbs.o ipz_pt_fn.o hcp_if.o hcp_phyp.o
++
+diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
+new file mode 100644
+index 0000000..3bac197
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_av.c
+@@ -0,0 +1,271 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * adress vector functions
++ *
++ * Authors: Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Khadija Souissi <souissik at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/current.h>
++
++#include "ehca_tools.h"
++#include "ehca_iverbs.h"
++#include "hcp_if.h"
++
++static struct kmem_cache *av_cache;
++
++struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
++{
++ int ret;
++ struct ehca_av *av;
++ struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
++ ib_device);
++
++ av = kmem_cache_alloc(av_cache, SLAB_KERNEL);
++ if (!av) {
++ ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p",
++ pd, ah_attr);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ av->av.sl = ah_attr->sl;
++ av->av.dlid = ah_attr->dlid;
++ av->av.slid_path_bits = ah_attr->src_path_bits;
++
++ if (ehca_static_rate < 0) {
++ int ah_mult = ib_rate_to_mult(ah_attr->static_rate);
++ int ehca_mult =
++ ib_rate_to_mult(shca->sport[ah_attr->port_num].rate );
++
++ if (ah_mult >= ehca_mult)
++ av->av.ipd = 0;
++ else
++ av->av.ipd = (ah_mult > 0) ?
++ ((ehca_mult - 1) / ah_mult) : 0;
++ } else
++ av->av.ipd = ehca_static_rate;
++
++ av->av.lnh = ah_attr->ah_flags;
++ av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
++ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK,
++ ah_attr->grh.traffic_class);
++ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
++ ah_attr->grh.flow_label);
++ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
++ ah_attr->grh.hop_limit);
++ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B);
++ /* set sgid in grh.word_1 */
++ if (ah_attr->ah_flags & IB_AH_GRH) {
++ int rc;
++ struct ib_port_attr port_attr;
++ union ib_gid gid;
++ memset(&port_attr, 0, sizeof(port_attr));
++ rc = ehca_query_port(pd->device, ah_attr->port_num,
++ &port_attr);
++ if (rc) { /* invalid port number */
++ ret = -EINVAL;
++ ehca_err(pd->device, "Invalid port number "
++ "ehca_query_port() returned %x "
++ "pd=%p ah_attr=%p", rc, pd, ah_attr);
++ goto create_ah_exit1;
++ }
++ memset(&gid, 0, sizeof(gid));
++ rc = ehca_query_gid(pd->device,
++ ah_attr->port_num,
++ ah_attr->grh.sgid_index, &gid);
++ if (rc) {
++ ret = -EINVAL;
++ ehca_err(pd->device, "Failed to retrieve sgid "
++ "ehca_query_gid() returned %x "
++ "pd=%p ah_attr=%p", rc, pd, ah_attr);
++ goto create_ah_exit1;
++ }
++ memcpy(&av->av.grh.word_1, &gid, sizeof(gid));
++ }
++ /* for the time being we use a hard coded PMTU of 2048 Bytes */
++ av->av.pmtu = 4;
++
++ /* dgid comes in grh.word_3 */
++ memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid,
++ sizeof(ah_attr->grh.dgid));
++
++ return &av->ib_ah;
++
++create_ah_exit1:
++ kmem_cache_free(av_cache, av);
++
++ return ERR_PTR(ret);
++}
++
++int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
++{
++ struct ehca_av *av;
++ struct ehca_ud_av new_ehca_av;
++ struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
++ u32 cur_pid = current->tgid;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ memset(&new_ehca_av, 0, sizeof(new_ehca_av));
++ new_ehca_av.sl = ah_attr->sl;
++ new_ehca_av.dlid = ah_attr->dlid;
++ new_ehca_av.slid_path_bits = ah_attr->src_path_bits;
++ new_ehca_av.ipd = ah_attr->static_rate;
++ new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK,
++ (ah_attr->ah_flags & IB_AH_GRH) > 0);
++ new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK,
++ ah_attr->grh.traffic_class);
++ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
++ ah_attr->grh.flow_label);
++ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
++ ah_attr->grh.hop_limit);
++ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b);
++
++ /* set sgid in grh.word_1 */
++ if (ah_attr->ah_flags & IB_AH_GRH) {
++ int rc;
++ struct ib_port_attr port_attr;
++ union ib_gid gid;
++ memset(&port_attr, 0, sizeof(port_attr));
++ rc = ehca_query_port(ah->device, ah_attr->port_num,
++ &port_attr);
++ if (rc) { /* invalid port number */
++ ehca_err(ah->device, "Invalid port number "
++ "ehca_query_port() returned %x "
++ "ah=%p ah_attr=%p port_num=%x",
++ rc, ah, ah_attr, ah_attr->port_num);
++ return -EINVAL;
++ }
++ memset(&gid, 0, sizeof(gid));
++ rc = ehca_query_gid(ah->device,
++ ah_attr->port_num,
++ ah_attr->grh.sgid_index, &gid);
++ if (rc) {
++ ehca_err(ah->device, "Failed to retrieve sgid "
++ "ehca_query_gid() returned %x "
++ "ah=%p ah_attr=%p port_num=%x "
++ "sgid_index=%x",
++ rc, ah, ah_attr, ah_attr->port_num,
++ ah_attr->grh.sgid_index);
++ return -EINVAL;
++ }
++ memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid));
++ }
++
++ new_ehca_av.pmtu = 4; /* see also comment in create_ah() */
++
++ memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid,
++ sizeof(ah_attr->grh.dgid));
++
++ av = container_of(ah, struct ehca_av, ib_ah);
++ av->av = new_ehca_av;
++
++ return 0;
++}
++
++int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
++{
++ struct ehca_av *av = container_of(ah, struct ehca_av, ib_ah);
++ struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
++ u32 cur_pid = current->tgid;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3,
++ sizeof(ah_attr->grh.dgid));
++ ah_attr->sl = av->av.sl;
++
++ ah_attr->dlid = av->av.dlid;
++
++ ah_attr->src_path_bits = av->av.slid_path_bits;
++ ah_attr->static_rate = av->av.ipd;
++ ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh);
++ ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK,
++ av->av.grh.word_0);
++ ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK,
++ av->av.grh.word_0);
++ ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK,
++ av->av.grh.word_0);
++
++ return 0;
++}
++
++int ehca_destroy_ah(struct ib_ah *ah)
++{
++ struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
++ u32 cur_pid = current->tgid;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah));
++
++ return 0;
++}
++
++int ehca_init_av_cache(void)
++{
++ av_cache = kmem_cache_create("ehca_cache_av",
++ sizeof(struct ehca_av), 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!av_cache)
++ return -ENOMEM;
++ return 0;
++}
++
++void ehca_cleanup_av_cache(void)
++{
++ if (av_cache)
++ kmem_cache_destroy(av_cache);
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
+new file mode 100644
+index 0000000..1c72203
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_classes.h
+@@ -0,0 +1,346 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Struct definition for eHCA internal structures
++ *
++ * Authors: Heiko J Schick <schickhj at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __EHCA_CLASSES_H__
++#define __EHCA_CLASSES_H__
++
++#include "ehca_classes.h"
++#include "ipz_pt_fn.h"
++
++struct ehca_module;
++struct ehca_qp;
++struct ehca_cq;
++struct ehca_eq;
++struct ehca_mr;
++struct ehca_mw;
++struct ehca_pd;
++struct ehca_av;
++
++#ifdef CONFIG_PPC64
++#include "ehca_classes_pSeries.h"
++#endif
++
++#include <rdma/ib_verbs.h>
++#include <rdma/ib_user_verbs.h>
++
++#include "ehca_irq.h"
++
++struct ehca_eq {
++ u32 length;
++ struct ipz_queue ipz_queue;
++ struct ipz_eq_handle ipz_eq_handle;
++ struct work_struct work;
++ struct h_galpas galpas;
++ int is_initialized;
++ struct ehca_pfeq pf;
++ spinlock_t spinlock;
++ struct tasklet_struct interrupt_task;
++ u32 ist;
++};
++
++struct ehca_sport {
++ struct ib_cq *ibcq_aqp1;
++ struct ib_qp *ibqp_aqp1;
++ enum ib_rate rate;
++ enum ib_port_state port_state;
++};
++
++struct ehca_shca {
++ struct ib_device ib_device;
++ struct ibmebus_dev *ibmebus_dev;
++ u8 num_ports;
++ int hw_level;
++ struct list_head shca_list;
++ struct ipz_adapter_handle ipz_hca_handle;
++ struct ehca_sport sport[2];
++ struct ehca_eq eq;
++ struct ehca_eq neq;
++ struct ehca_mr *maxmr;
++ struct ehca_pd *pd;
++ struct h_galpas galpas;
++};
++
++struct ehca_pd {
++ struct ib_pd ib_pd;
++ struct ipz_pd fw_pd;
++ u32 ownpid;
++};
++
++struct ehca_qp {
++ struct ib_qp ib_qp;
++ u32 qp_type;
++ struct ipz_queue ipz_squeue;
++ struct ipz_queue ipz_rqueue;
++ struct h_galpas galpas;
++ u32 qkey;
++ u32 real_qp_num;
++ u32 token;
++ spinlock_t spinlock_s;
++ spinlock_t spinlock_r;
++ u32 sq_max_inline_data_size;
++ struct ipz_qp_handle ipz_qp_handle;
++ struct ehca_pfqp pf;
++ struct ib_qp_init_attr init_attr;
++ u64 uspace_squeue;
++ u64 uspace_rqueue;
++ u64 uspace_fwh;
++ struct ehca_cq *send_cq;
++ struct ehca_cq *recv_cq;
++ unsigned int sqerr_purgeflag;
++ struct hlist_node list_entries;
++};
++
++/* must be power of 2 */
++#define QP_HASHTAB_LEN 8
++
++struct ehca_cq {
++ struct ib_cq ib_cq;
++ struct ipz_queue ipz_queue;
++ struct h_galpas galpas;
++ spinlock_t spinlock;
++ u32 cq_number;
++ u32 token;
++ u32 nr_of_entries;
++ struct ipz_cq_handle ipz_cq_handle;
++ struct ehca_pfcq pf;
++ spinlock_t cb_lock;
++ u64 uspace_queue;
++ u64 uspace_fwh;
++ struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
++ struct list_head entry;
++ u32 nr_callbacks;
++ spinlock_t task_lock;
++ u32 ownpid;
++};
++
++enum ehca_mr_flag {
++ EHCA_MR_FLAG_FMR = 0x80000000, /* FMR, created with ehca_alloc_fmr */
++ EHCA_MR_FLAG_MAXMR = 0x40000000, /* max-MR */
++};
++
++struct ehca_mr {
++ union {
++ struct ib_mr ib_mr; /* must always be first in ehca_mr */
++ struct ib_fmr ib_fmr; /* must always be first in ehca_mr */
++ } ib;
++ spinlock_t mrlock;
++
++ enum ehca_mr_flag flags;
++ u32 num_pages; /* number of MR pages */
++ u32 num_4k; /* number of 4k "page" portions to form MR */
++ int acl; /* ACL (stored here for usage in reregister) */
++ u64 *start; /* virtual start address (stored here for */
++ /* usage in reregister) */
++ u64 size; /* size (stored here for usage in reregister) */
++ u32 fmr_page_size; /* page size for FMR */
++ u32 fmr_max_pages; /* max pages for FMR */
++ u32 fmr_max_maps; /* max outstanding maps for FMR */
++ u32 fmr_map_cnt; /* map counter for FMR */
++ /* fw specific data */
++ struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */
++ struct h_galpas galpas;
++ /* data for userspace bridge */
++ u32 nr_of_pages;
++ void *pagearray;
++};
++
++struct ehca_mw {
++ struct ib_mw ib_mw; /* gen2 mw, must always be first in ehca_mw */
++ spinlock_t mwlock;
++
++ u8 never_bound; /* indication MW was never bound */
++ struct ipz_mrmw_handle ipz_mw_handle; /* MW handle for h-calls */
++ struct h_galpas galpas;
++};
++
++enum ehca_mr_pgi_type {
++ EHCA_MR_PGI_PHYS = 1, /* type of ehca_reg_phys_mr,
++ * ehca_rereg_phys_mr,
++ * ehca_reg_internal_maxmr */
++ EHCA_MR_PGI_USER = 2, /* type of ehca_reg_user_mr */
++ EHCA_MR_PGI_FMR = 3 /* type of ehca_map_phys_fmr */
++};
++
++struct ehca_mr_pginfo {
++ enum ehca_mr_pgi_type type;
++ u64 num_pages;
++ u64 page_cnt;
++ u64 num_4k; /* number of 4k "page" portions */
++ u64 page_4k_cnt; /* counter for 4k "page" portions */
++ u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */
++
++ /* type EHCA_MR_PGI_PHYS section */
++ int num_phys_buf;
++ struct ib_phys_buf *phys_buf_array;
++ u64 next_buf;
++
++ /* type EHCA_MR_PGI_USER section */
++ struct ib_umem *region;
++ struct ib_umem_chunk *next_chunk;
++ u64 next_nmap;
++
++ /* type EHCA_MR_PGI_FMR section */
++ u64 *page_list;
++ u64 next_listelem;
++ /* next_4k also used within EHCA_MR_PGI_FMR */
++};
++
++/* output parameters for MR/FMR hipz calls */
++struct ehca_mr_hipzout_parms {
++ struct ipz_mrmw_handle handle;
++ u32 lkey;
++ u32 rkey;
++ u64 len;
++ u64 vaddr;
++ u32 acl;
++};
++
++/* output parameters for MW hipz calls */
++struct ehca_mw_hipzout_parms {
++ struct ipz_mrmw_handle handle;
++ u32 rkey;
++};
++
++struct ehca_av {
++ struct ib_ah ib_ah;
++ struct ehca_ud_av av;
++};
++
++struct ehca_ucontext {
++ struct ib_ucontext ib_ucontext;
++};
++
++struct ehca_module *ehca_module_new(void);
++
++int ehca_module_delete(struct ehca_module *me);
++
++int ehca_eq_ctor(struct ehca_eq *eq);
++
++int ehca_eq_dtor(struct ehca_eq *eq);
++
++struct ehca_shca *ehca_shca_new(void);
++
++int ehca_shca_delete(struct ehca_shca *me);
++
++struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
++
++int ehca_init_pd_cache(void);
++void ehca_cleanup_pd_cache(void);
++int ehca_init_cq_cache(void);
++void ehca_cleanup_cq_cache(void);
++int ehca_init_qp_cache(void);
++void ehca_cleanup_qp_cache(void);
++int ehca_init_av_cache(void);
++void ehca_cleanup_av_cache(void);
++int ehca_init_mrmw_cache(void);
++void ehca_cleanup_mrmw_cache(void);
++
++extern spinlock_t ehca_qp_idr_lock;
++extern spinlock_t ehca_cq_idr_lock;
++extern struct idr ehca_qp_idr;
++extern struct idr ehca_cq_idr;
++
++extern int ehca_static_rate;
++extern int ehca_port_act_time;
++extern int ehca_use_hp_mr;
++
++struct ipzu_queue_resp {
++ u64 queue; /* points to first queue entry */
++ u32 qe_size; /* queue entry size */
++ u32 act_nr_of_sg;
++ u32 queue_length; /* queue length allocated in bytes */
++ u32 pagesize;
++ u32 toggle_state;
++ u32 dummy; /* padding for 8 byte alignment */
++};
++
++struct ehca_create_cq_resp {
++ u32 cq_number;
++ u32 token;
++ struct ipzu_queue_resp ipz_queue;
++ struct h_galpas galpas;
++};
++
++struct ehca_create_qp_resp {
++ u32 qp_num;
++ u32 token;
++ u32 qp_type;
++ u32 qkey;
++ /* qp_num assigned by ehca: sqp0/1 may have got different numbers */
++ u32 real_qp_num;
++ u32 dummy; /* padding for 8 byte alignment */
++ struct ipzu_queue_resp ipz_squeue;
++ struct ipzu_queue_resp ipz_rqueue;
++ struct h_galpas galpas;
++};
++
++struct ehca_alloc_cq_parms {
++ u32 nr_cqe;
++ u32 act_nr_of_entries;
++ u32 act_pages;
++ struct ipz_eq_handle eq_handle;
++};
++
++struct ehca_alloc_qp_parms {
++ int servicetype;
++ int sigtype;
++ int daqp_ctrl;
++ int max_send_sge;
++ int max_recv_sge;
++ int ud_av_l_key_ctl;
++
++ u16 act_nr_send_wqes;
++ u16 act_nr_recv_wqes;
++ u8 act_nr_recv_sges;
++ u8 act_nr_send_sges;
++
++ u32 nr_rq_pages;
++ u32 nr_sq_pages;
++
++ struct ipz_eq_handle ipz_eq_handle;
++ struct ipz_pd pd;
++};
++
++int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
++int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
++struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
++
++#endif
+diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
+new file mode 100644
+index 0000000..5665f21
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
+@@ -0,0 +1,236 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * pSeries interface definitions
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __EHCA_CLASSES_PSERIES_H__
++#define __EHCA_CLASSES_PSERIES_H__
++
++#include "hcp_phyp.h"
++#include "ipz_pt_fn.h"
++
++
++struct ehca_pfqp {
++ struct ipz_qpt sqpt;
++ struct ipz_qpt rqpt;
++};
++
++struct ehca_pfcq {
++ struct ipz_qpt qpt;
++ u32 cqnr;
++};
++
++struct ehca_pfeq {
++ struct ipz_qpt qpt;
++ struct h_galpa galpa;
++ u32 eqnr;
++};
++
++struct ipz_adapter_handle {
++ u64 handle;
++};
++
++struct ipz_cq_handle {
++ u64 handle;
++};
++
++struct ipz_eq_handle {
++ u64 handle;
++};
++
++struct ipz_qp_handle {
++ u64 handle;
++};
++struct ipz_mrmw_handle {
++ u64 handle;
++};
++
++struct ipz_pd {
++ u32 value;
++};
++
++struct hcp_modify_qp_control_block {
++ u32 qkey; /* 00 */
++ u32 rdd; /* reliable datagram domain */
++ u32 send_psn; /* 02 */
++ u32 receive_psn; /* 03 */
++ u32 prim_phys_port; /* 04 */
++ u32 alt_phys_port; /* 05 */
++ u32 prim_p_key_idx; /* 06 */
++ u32 alt_p_key_idx; /* 07 */
++ u32 rdma_atomic_ctrl; /* 08 */
++ u32 qp_state; /* 09 */
++ u32 reserved_10; /* 10 */
++ u32 rdma_nr_atomic_resp_res; /* 11 */
++ u32 path_migration_state; /* 12 */
++ u32 rdma_atomic_outst_dest_qp; /* 13 */
++ u32 dest_qp_nr; /* 14 */
++ u32 min_rnr_nak_timer_field; /* 15 */
++ u32 service_level; /* 16 */
++ u32 send_grh_flag; /* 17 */
++ u32 retry_count; /* 18 */
++ u32 timeout; /* 19 */
++ u32 path_mtu; /* 20 */
++ u32 max_static_rate; /* 21 */
++ u32 dlid; /* 22 */
++ u32 rnr_retry_count; /* 23 */
++ u32 source_path_bits; /* 24 */
++ u32 traffic_class; /* 25 */
++ u32 hop_limit; /* 26 */
++ u32 source_gid_idx; /* 27 */
++ u32 flow_label; /* 28 */
++ u32 reserved_29; /* 29 */
++ union { /* 30 */
++ u64 dw[2];
++ u8 byte[16];
++ } dest_gid;
++ u32 service_level_al; /* 34 */
++ u32 send_grh_flag_al; /* 35 */
++ u32 retry_count_al; /* 36 */
++ u32 timeout_al; /* 37 */
++ u32 max_static_rate_al; /* 38 */
++ u32 dlid_al; /* 39 */
++ u32 rnr_retry_count_al; /* 40 */
++ u32 source_path_bits_al; /* 41 */
++ u32 traffic_class_al; /* 42 */
++ u32 hop_limit_al; /* 43 */
++ u32 source_gid_idx_al; /* 44 */
++ u32 flow_label_al; /* 45 */
++ u32 reserved_46; /* 46 */
++ u32 reserved_47; /* 47 */
++ union { /* 48 */
++ u64 dw[2];
++ u8 byte[16];
++ } dest_gid_al;
++ u32 max_nr_outst_send_wr; /* 52 */
++ u32 max_nr_outst_recv_wr; /* 53 */
++ u32 disable_ete_credit_check; /* 54 */
++ u32 qp_number; /* 55 */
++ u64 send_queue_handle; /* 56 */
++ u64 recv_queue_handle; /* 58 */
++ u32 actual_nr_sges_in_sq_wqe; /* 60 */
++ u32 actual_nr_sges_in_rq_wqe; /* 61 */
++ u32 qp_enable; /* 62 */
++ u32 curr_srq_limit; /* 63 */
++ u64 qp_aff_asyn_ev_log_reg; /* 64 */
++ u64 shared_rq_hndl; /* 66 */
++ u64 trigg_doorbell_qp_hndl; /* 68 */
++ u32 reserved_70_127[58]; /* 70 */
++};
++
++#define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0)
++#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2)
++#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3)
++#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4)
++#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5)
++#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6)
++#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7)
++#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8)
++#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9)
++#define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11)
++#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12)
++#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13)
++#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14)
++#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15)
++#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16)
++#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17)
++#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18)
++#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19)
++#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20)
++#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21)
++#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22)
++#define MQPCB_DLID EHCA_BMASK_IBM(16,31)
++#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23)
++#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31)
++#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24)
++#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31)
++#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25)
++#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26)
++#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27)
++#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28)
++#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31)
++#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30)
++#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31)
++#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31)
++#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32)
++#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31)
++#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33)
++#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
++#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34)
++#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31)
++#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35)
++#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36)
++#define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31)
++#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37)
++#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
++#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38)
++#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31)
++#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39)
++#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40)
++#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41)
++#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31)
++#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42)
++#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31)
++#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44)
++#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45)
++#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
++#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46)
++#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
++#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47)
++#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31)
++#define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31)
++#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48)
++#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31)
++#define MQPCB_MASK_CURR_SQR_LIMIT EHCA_BMASK_IBM(49,49)
++#define MQPCB_CURR_SQR_LIMIT EHCA_BMASK_IBM(15,31)
++#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50)
++#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51)
++
++#endif /* __EHCA_CLASSES_PSERIES_H__ */
+diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
+new file mode 100644
+index 0000000..458fe19
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_cq.c
+@@ -0,0 +1,427 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Completion queue handling
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Khadija Souissi <souissi at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ *
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/current.h>
++
++#include "ehca_iverbs.h"
++#include "ehca_classes.h"
++#include "ehca_irq.h"
++#include "hcp_if.h"
++
++static struct kmem_cache *cq_cache;
++
++int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp)
++{
++ unsigned int qp_num = qp->real_qp_num;
++ unsigned int key = qp_num & (QP_HASHTAB_LEN-1);
++ unsigned long spl_flags;
++
++ spin_lock_irqsave(&cq->spinlock, spl_flags);
++ hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]);
++ spin_unlock_irqrestore(&cq->spinlock, spl_flags);
++
++ ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x",
++ cq->cq_number, qp_num);
++
++ return 0;
++}
++
++int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
++{
++ int ret = -EINVAL;
++ unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
++ struct hlist_node *iter;
++ struct ehca_qp *qp;
++ unsigned long spl_flags;
++
++ spin_lock_irqsave(&cq->spinlock, spl_flags);
++ hlist_for_each(iter, &cq->qp_hashtab[key]) {
++ qp = hlist_entry(iter, struct ehca_qp, list_entries);
++ if (qp->real_qp_num == real_qp_num) {
++ hlist_del(iter);
++ ehca_dbg(cq->ib_cq.device,
++ "removed qp from cq .cq_num=%x real_qp_num=%x",
++ cq->cq_number, real_qp_num);
++ ret = 0;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&cq->spinlock, spl_flags);
++ if (ret)
++ ehca_err(cq->ib_cq.device,
++ "qp not found cq_num=%x real_qp_num=%x",
++ cq->cq_number, real_qp_num);
++
++ return ret;
++}
++
++struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
++{
++ struct ehca_qp *ret = NULL;
++ unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
++ struct hlist_node *iter;
++ struct ehca_qp *qp;
++ hlist_for_each(iter, &cq->qp_hashtab[key]) {
++ qp = hlist_entry(iter, struct ehca_qp, list_entries);
++ if (qp->real_qp_num == real_qp_num) {
++ ret = qp;
++ break;
++ }
++ }
++ return ret;
++}
++
++struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
++ struct ib_ucontext *context,
++ struct ib_udata *udata)
++{
++ static const u32 additional_cqe = 20;
++ struct ib_cq *cq;
++ struct ehca_cq *my_cq;
++ struct ehca_shca *shca =
++ container_of(device, struct ehca_shca, ib_device);
++ struct ipz_adapter_handle adapter_handle;
++ struct ehca_alloc_cq_parms param; /* h_call's out parameters */
++ struct h_galpa gal;
++ void *vpage;
++ u32 counter;
++ u64 rpage, cqx_fec, h_ret;
++ int ipz_rc, ret, i;
++ unsigned long flags;
++
++ if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
++ return ERR_PTR(-EINVAL);
++
++ my_cq = kmem_cache_alloc(cq_cache, SLAB_KERNEL);
++ if (!my_cq) {
++ ehca_err(device, "Out of memory for ehca_cq struct device=%p",
++ device);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ memset(my_cq, 0, sizeof(struct ehca_cq));
++ memset(¶m, 0, sizeof(struct ehca_alloc_cq_parms));
++
++ spin_lock_init(&my_cq->spinlock);
++ spin_lock_init(&my_cq->cb_lock);
++ spin_lock_init(&my_cq->task_lock);
++ my_cq->ownpid = current->tgid;
++
++ cq = &my_cq->ib_cq;
++
++ adapter_handle = shca->ipz_hca_handle;
++ param.eq_handle = shca->eq.ipz_eq_handle;
++
++ do {
++ if (!idr_pre_get(&ehca_cq_idr, GFP_KERNEL)) {
++ cq = ERR_PTR(-ENOMEM);
++ ehca_err(device, "Can't reserve idr nr. device=%p",
++ device);
++ goto create_cq_exit1;
++ }
++
++ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
++ ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
++
++ } while (ret == -EAGAIN);
++
++ if (ret) {
++ cq = ERR_PTR(-ENOMEM);
++ ehca_err(device, "Can't allocate new idr entry. device=%p",
++ device);
++ goto create_cq_exit1;
++ }
++
++ /*
++ * CQs maximum depth is 4GB-64, but we need additional 20 as buffer
++ * for receiving errors CQEs.
++ */
++ param.nr_cqe = cqe + additional_cqe;
++ h_ret = hipz_h_alloc_resource_cq(adapter_handle, my_cq, ¶m);
++
++ if (h_ret != H_SUCCESS) {
++ ehca_err(device, "hipz_h_alloc_resource_cq() failed "
++ "h_ret=%lx device=%p", h_ret, device);
++ cq = ERR_PTR(ehca2ib_return_code(h_ret));
++ goto create_cq_exit2;
++ }
++
++ ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
++ EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
++ if (!ipz_rc) {
++ ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
++ ipz_rc, device);
++ cq = ERR_PTR(-EINVAL);
++ goto create_cq_exit3;
++ }
++
++ for (counter = 0; counter < param.act_pages; counter++) {
++ vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
++ if (!vpage) {
++ ehca_err(device, "ipz_qpageit_get_inc() "
++ "returns NULL device=%p", device);
++ cq = ERR_PTR(-EAGAIN);
++ goto create_cq_exit4;
++ }
++ rpage = virt_to_abs(vpage);
++
++ h_ret = hipz_h_register_rpage_cq(adapter_handle,
++ my_cq->ipz_cq_handle,
++ &my_cq->pf,
++ 0,
++ 0,
++ rpage,
++ 1,
++ my_cq->galpas.
++ kernel);
++
++ if (h_ret < H_SUCCESS) {
++ ehca_err(device, "hipz_h_register_rpage_cq() failed "
++ "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i "
++ "act_pages=%i", my_cq, my_cq->cq_number,
++ h_ret, counter, param.act_pages);
++ cq = ERR_PTR(-EINVAL);
++ goto create_cq_exit4;
++ }
++
++ if (counter == (param.act_pages - 1)) {
++ vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
++ if ((h_ret != H_SUCCESS) || vpage) {
++ ehca_err(device, "Registration of pages not "
++ "complete ehca_cq=%p cq_num=%x "
++ "h_ret=%lx", my_cq, my_cq->cq_number,
++ h_ret);
++ cq = ERR_PTR(-EAGAIN);
++ goto create_cq_exit4;
++ }
++ } else {
++ if (h_ret != H_PAGE_REGISTERED) {
++ ehca_err(device, "Registration of page failed "
++ "ehca_cq=%p cq_num=%x h_ret=%lx"
++ "counter=%i act_pages=%i",
++ my_cq, my_cq->cq_number,
++ h_ret, counter, param.act_pages);
++ cq = ERR_PTR(-ENOMEM);
++ goto create_cq_exit4;
++ }
++ }
++ }
++
++ ipz_qeit_reset(&my_cq->ipz_queue);
++
++ gal = my_cq->galpas.kernel;
++ cqx_fec = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_fec));
++ ehca_dbg(device, "ehca_cq=%p cq_num=%x CQX_FEC=%lx",
++ my_cq, my_cq->cq_number, cqx_fec);
++
++ my_cq->ib_cq.cqe = my_cq->nr_of_entries =
++ param.act_nr_of_entries - additional_cqe;
++ my_cq->cq_number = (my_cq->ipz_cq_handle.handle) & 0xffff;
++
++ for (i = 0; i < QP_HASHTAB_LEN; i++)
++ INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
++
++ if (context) {
++ struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
++ struct ehca_create_cq_resp resp;
++ struct vm_area_struct *vma;
++ memset(&resp, 0, sizeof(resp));
++ resp.cq_number = my_cq->cq_number;
++ resp.token = my_cq->token;
++ resp.ipz_queue.qe_size = ipz_queue->qe_size;
++ resp.ipz_queue.act_nr_of_sg = ipz_queue->act_nr_of_sg;
++ resp.ipz_queue.queue_length = ipz_queue->queue_length;
++ resp.ipz_queue.pagesize = ipz_queue->pagesize;
++ resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
++ ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
++ ipz_queue->queue_length,
++ (void**)&resp.ipz_queue.queue,
++ &vma);
++ if (ret) {
++ ehca_err(device, "Could not mmap queue pages");
++ cq = ERR_PTR(ret);
++ goto create_cq_exit4;
++ }
++ my_cq->uspace_queue = resp.ipz_queue.queue;
++ resp.galpas = my_cq->galpas;
++ ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
++ (void**)&resp.galpas.kernel.fw_handle,
++ &vma);
++ if (ret) {
++ ehca_err(device, "Could not mmap fw_handle");
++ cq = ERR_PTR(ret);
++ goto create_cq_exit5;
++ }
++ my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
++ if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
++ ehca_err(device, "Copy to udata failed.");
++ goto create_cq_exit6;
++ }
++ }
++
++ return cq;
++
++create_cq_exit6:
++ ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
++
++create_cq_exit5:
++ ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
++
++create_cq_exit4:
++ ipz_queue_dtor(&my_cq->ipz_queue);
++
++create_cq_exit3:
++ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
++ if (h_ret != H_SUCCESS)
++ ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
++ "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret);
++
++create_cq_exit2:
++ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
++ idr_remove(&ehca_cq_idr, my_cq->token);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
++
++create_cq_exit1:
++ kmem_cache_free(cq_cache, my_cq);
++
++ return cq;
++}
++
++int ehca_destroy_cq(struct ib_cq *cq)
++{
++ u64 h_ret;
++ int ret;
++ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
++ int cq_num = my_cq->cq_number;
++ struct ib_device *device = cq->device;
++ struct ehca_shca *shca = container_of(device, struct ehca_shca,
++ ib_device);
++ struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
++ u32 cur_pid = current->tgid;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
++ while (my_cq->nr_callbacks)
++ yield();
++
++ idr_remove(&ehca_cq_idr, my_cq->token);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
++
++ if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
++ ehca_err(device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_cq->ownpid);
++ return -EINVAL;
++ }
++
++ /* un-mmap if vma alloc */
++ if (my_cq->uspace_queue ) {
++ ret = ehca_munmap(my_cq->uspace_queue,
++ my_cq->ipz_queue.queue_length);
++ if (ret)
++ ehca_err(device, "Could not munmap queue ehca_cq=%p "
++ "cq_num=%x", my_cq, cq_num);
++ ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
++ if (ret)
++ ehca_err(device, "Could not munmap fwh ehca_cq=%p "
++ "cq_num=%x", my_cq, cq_num);
++ }
++
++ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
++ if (h_ret == H_R_STATE) {
++ /* cq in err: read err data and destroy it forcibly */
++ ehca_dbg(device, "ehca_cq=%p cq_num=%x ressource=%lx in err "
++ "state. Try to delete it forcibly.",
++ my_cq, cq_num, my_cq->ipz_cq_handle.handle);
++ ehca_error_data(shca, my_cq, my_cq->ipz_cq_handle.handle);
++ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
++ if (h_ret == H_SUCCESS)
++ ehca_dbg(device, "cq_num=%x deleted successfully.",
++ cq_num);
++ }
++ if (h_ret != H_SUCCESS) {
++ ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx "
++ "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
++ return ehca2ib_return_code(h_ret);
++ }
++ ipz_queue_dtor(&my_cq->ipz_queue);
++ kmem_cache_free(cq_cache, my_cq);
++
++ return 0;
++}
++
++int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
++{
++ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
++ u32 cur_pid = current->tgid;
++
++ if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
++ ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_cq->ownpid);
++ return -EINVAL;
++ }
++
++ /* TODO: proper resize needs to be done */
++ ehca_err(cq->device, "not implemented yet");
++
++ return -EFAULT;
++}
++
++int ehca_init_cq_cache(void)
++{
++ cq_cache = kmem_cache_create("ehca_cache_cq",
++ sizeof(struct ehca_cq), 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!cq_cache)
++ return -ENOMEM;
++ return 0;
++}
++
++void ehca_cleanup_cq_cache(void)
++{
++ if (cq_cache)
++ kmem_cache_destroy(cq_cache);
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
+new file mode 100644
+index 0000000..5281dec
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_eq.c
+@@ -0,0 +1,185 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Event queue handling
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Khadija Souissi <souissi at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ *
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "ehca_classes.h"
++#include "ehca_irq.h"
++#include "ehca_iverbs.h"
++#include "ehca_qes.h"
++#include "hcp_if.h"
++#include "ipz_pt_fn.h"
++
++int ehca_create_eq(struct ehca_shca *shca,
++ struct ehca_eq *eq,
++ const enum ehca_eq_type type, const u32 length)
++{
++ u64 ret;
++ u32 nr_pages;
++ u32 i;
++ void *vpage;
++ struct ib_device *ib_dev = &shca->ib_device;
++
++ spin_lock_init(&eq->spinlock);
++ eq->is_initialized = 0;
++
++ if (type != EHCA_EQ && type != EHCA_NEQ) {
++ ehca_err(ib_dev, "Invalid EQ type %x. eq=%p", type, eq);
++ return -EINVAL;
++ }
++ if (!length) {
++ ehca_err(ib_dev, "EQ length must not be zero. eq=%p", eq);
++ return -EINVAL;
++ }
++
++ ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
++ &eq->pf,
++ type,
++ length,
++ &eq->ipz_eq_handle,
++ &eq->length,
++ &nr_pages, &eq->ist);
++
++ if (ret != H_SUCCESS) {
++ ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq);
++ return -EINVAL;
++ }
++
++ ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
++ EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
++ if (!ret) {
++ ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
++ goto create_eq_exit1;
++ }
++
++ for (i = 0; i < nr_pages; i++) {
++ u64 rpage;
++
++ if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
++ ret = H_RESOURCE;
++ goto create_eq_exit2;
++ }
++
++ rpage = virt_to_abs(vpage);
++ ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
++ eq->ipz_eq_handle,
++ &eq->pf,
++ 0, 0, rpage, 1);
++
++ if (i == (nr_pages - 1)) {
++ /* last page */
++ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
++ if (ret != H_SUCCESS || vpage)
++ goto create_eq_exit2;
++ } else {
++ if (ret != H_PAGE_REGISTERED || !vpage)
++ goto create_eq_exit2;
++ }
++ }
++
++ ipz_qeit_reset(&eq->ipz_queue);
++
++ /* register interrupt handlers and initialize work queues */
++ if (type == EHCA_EQ) {
++ ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq,
++ SA_INTERRUPT, "ehca_eq",
++ (void *)shca);
++ if (ret < 0)
++ ehca_err(ib_dev, "Can't map interrupt handler.");
++
++ tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
++ } else if (type == EHCA_NEQ) {
++ ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq,
++ SA_INTERRUPT, "ehca_neq",
++ (void *)shca);
++ if (ret < 0)
++ ehca_err(ib_dev, "Can't map interrupt handler.");
++
++ tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
++ }
++
++ eq->is_initialized = 1;
++
++ return 0;
++
++create_eq_exit2:
++ ipz_queue_dtor(&eq->ipz_queue);
++
++create_eq_exit1:
++ hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
++
++ return -EINVAL;
++}
++
++void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq)
++{
++ unsigned long flags;
++ void *eqe;
++
++ spin_lock_irqsave(&eq->spinlock, flags);
++ eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue);
++ spin_unlock_irqrestore(&eq->spinlock, flags);
++
++ return eqe;
++}
++
++int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
++{
++ unsigned long flags;
++ u64 h_ret;
++
++ spin_lock_irqsave(&eq->spinlock, flags);
++ ibmebus_free_irq(NULL, eq->ist, (void *)shca);
++
++ h_ret = hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
++
++ spin_unlock_irqrestore(&eq->spinlock, flags);
++
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "Can't free EQ resources.");
++ return -EINVAL;
++ }
++ ipz_queue_dtor(&eq->ipz_queue);
++
++ return 0;
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
+new file mode 100644
+index 0000000..5eae6ac
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_hca.c
+@@ -0,0 +1,241 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * HCA query functions
++ *
++ * Authors: Heiko J Schick <schickhj at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "ehca_tools.h"
++#include "hcp_if.h"
++
++int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
++{
++ int ret = 0;
++ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
++ ib_device);
++ struct hipz_query_hca *rblock;
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
++ return -ENOMEM;
++ }
++
++ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "Can't query device properties");
++ ret = -EINVAL;
++ goto query_device1;
++ }
++
++ memset(props, 0, sizeof(struct ib_device_attr));
++ props->fw_ver = rblock->hw_ver;
++ props->max_mr_size = rblock->max_mr_size;
++ props->vendor_id = rblock->vendor_id >> 8;
++ props->vendor_part_id = rblock->vendor_part_id >> 16;
++ props->hw_ver = rblock->hw_ver;
++ props->max_qp = min_t(int, rblock->max_qp, INT_MAX);
++ props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX);
++ props->max_sge = min_t(int, rblock->max_sge, INT_MAX);
++ props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX);
++ props->max_cq = min_t(int, rblock->max_cq, INT_MAX);
++ props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX);
++ props->max_mr = min_t(int, rblock->max_mr, INT_MAX);
++ props->max_mw = min_t(int, rblock->max_mw, INT_MAX);
++ props->max_pd = min_t(int, rblock->max_pd, INT_MAX);
++ props->max_ah = min_t(int, rblock->max_ah, INT_MAX);
++ props->max_fmr = min_t(int, rblock->max_mr, INT_MAX);
++ props->max_srq = 0;
++ props->max_srq_wr = 0;
++ props->max_srq_sge = 0;
++ props->max_pkeys = 16;
++ props->local_ca_ack_delay
++ = rblock->local_ca_ack_delay;
++ props->max_raw_ipv6_qp
++ = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
++ props->max_raw_ethy_qp
++ = min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
++ props->max_mcast_grp
++ = min_t(int, rblock->max_mcast_grp, INT_MAX);
++ props->max_mcast_qp_attach
++ = min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
++ props->max_total_mcast_qp_attach
++ = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
++
++query_device1:
++ kfree(rblock);
++
++ return ret;
++}
++
++int ehca_query_port(struct ib_device *ibdev,
++ u8 port, struct ib_port_attr *props)
++{
++ int ret = 0;
++ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
++ ib_device);
++ struct hipz_query_port *rblock;
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
++ return -ENOMEM;
++ }
++
++ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "Can't query port properties");
++ ret = -EINVAL;
++ goto query_port1;
++ }
++
++ memset(props, 0, sizeof(struct ib_port_attr));
++ props->state = rblock->state;
++
++ switch (rblock->max_mtu) {
++ case 0x1:
++ props->active_mtu = props->max_mtu = IB_MTU_256;
++ break;
++ case 0x2:
++ props->active_mtu = props->max_mtu = IB_MTU_512;
++ break;
++ case 0x3:
++ props->active_mtu = props->max_mtu = IB_MTU_1024;
++ break;
++ case 0x4:
++ props->active_mtu = props->max_mtu = IB_MTU_2048;
++ break;
++ case 0x5:
++ props->active_mtu = props->max_mtu = IB_MTU_4096;
++ break;
++ default:
++ ehca_err(&shca->ib_device, "Unknown MTU size: %x.",
++ rblock->max_mtu);
++ break;
++ }
++
++ props->gid_tbl_len = rblock->gid_tbl_len;
++ props->max_msg_sz = rblock->max_msg_sz;
++ props->bad_pkey_cntr = rblock->bad_pkey_cntr;
++ props->qkey_viol_cntr = rblock->qkey_viol_cntr;
++ props->pkey_tbl_len = rblock->pkey_tbl_len;
++ props->lid = rblock->lid;
++ props->sm_lid = rblock->sm_lid;
++ props->lmc = rblock->lmc;
++ props->sm_sl = rblock->sm_sl;
++ props->subnet_timeout = rblock->subnet_timeout;
++ props->init_type_reply = rblock->init_type_reply;
++
++ props->active_width = IB_WIDTH_12X;
++ props->active_speed = 0x1;
++
++query_port1:
++ kfree(rblock);
++
++ return ret;
++}
++
++int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
++{
++ int ret = 0;
++ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
++ struct hipz_query_port *rblock;
++
++ if (index > 16) {
++ ehca_err(&shca->ib_device, "Invalid index: %x.", index);
++ return -EINVAL;
++ }
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
++ return -ENOMEM;
++ }
++
++ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "Can't query port properties");
++ ret = -EINVAL;
++ goto query_pkey1;
++ }
++
++ memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16));
++
++query_pkey1:
++ kfree(rblock);
++
++ return ret;
++}
++
++int ehca_query_gid(struct ib_device *ibdev, u8 port,
++ int index, union ib_gid *gid)
++{
++ int ret = 0;
++ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
++ ib_device);
++ struct hipz_query_port *rblock;
++
++ if (index > 255) {
++ ehca_err(&shca->ib_device, "Invalid index: %x.", index);
++ return -EINVAL;
++ }
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
++ return -ENOMEM;
++ }
++
++ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "Can't query port properties");
++ ret = -EINVAL;
++ goto query_gid1;
++ }
++
++ memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64));
++ memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64));
++
++query_gid1:
++ kfree(rblock);
++
++ return ret;
++}
++
++int ehca_modify_port(struct ib_device *ibdev,
++ u8 port, int port_modify_mask,
++ struct ib_port_modify *props)
++{
++ /* Not implemented yet */
++ return -EFAULT;
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
+new file mode 100644
+index 0000000..048cc44
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_irq.c
+@@ -0,0 +1,762 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Functions for EQs, NEQs and interrupts
++ *
++ * Authors: Heiko J Schick <schickhj at de.ibm.com>
++ * Khadija Souissi <souissi at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "ehca_classes.h"
++#include "ehca_irq.h"
++#include "ehca_iverbs.h"
++#include "ehca_tools.h"
++#include "hcp_if.h"
++#include "hipz_fns.h"
++
++#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
++#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31)
++#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7)
++#define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31)
++#define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31)
++#define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63)
++#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63)
++
++#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
++#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
++#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
++#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
++
++#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
++#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
++
++#ifdef CONFIG_INFINIBAND_EHCA_SCALING
++
++static void queue_comp_task(struct ehca_cq *__cq);
++
++static struct ehca_comp_pool* pool;
++static struct notifier_block comp_pool_callback_nb;
++
++#endif
++
++static inline void comp_event_callback(struct ehca_cq *cq)
++{
++ if (!cq->ib_cq.comp_handler)
++ return;
++
++ spin_lock(&cq->cb_lock);
++ cq->ib_cq.comp_handler(&cq->ib_cq, cq->ib_cq.cq_context);
++ spin_unlock(&cq->cb_lock);
++
++ return;
++}
++
++static void print_error_data(struct ehca_shca * shca, void* data,
++ u64* rblock, int length)
++{
++ u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
++ u64 resource = rblock[1];
++
++ switch (type) {
++ case 0x1: /* Queue Pair */
++ {
++ struct ehca_qp *qp = (struct ehca_qp*)data;
++
++ /* only print error data if AER is set */
++ if (rblock[6] == 0)
++ return;
++
++ ehca_err(&shca->ib_device,
++ "QP 0x%x (resource=%lx) has errors.",
++ qp->ib_qp.qp_num, resource);
++ break;
++ }
++ case 0x4: /* Completion Queue */
++ {
++ struct ehca_cq *cq = (struct ehca_cq*)data;
++
++ ehca_err(&shca->ib_device,
++ "CQ 0x%x (resource=%lx) has errors.",
++ cq->cq_number, resource);
++ break;
++ }
++ default:
++ ehca_err(&shca->ib_device,
++ "Unknown errror type: %lx on %s.",
++ type, shca->ib_device.name);
++ break;
++ }
++
++ ehca_err(&shca->ib_device, "Error data is available: %lx.", resource);
++ ehca_err(&shca->ib_device, "EHCA ----- error data begin "
++ "---------------------------------------------------");
++ ehca_dmp(rblock, length, "resource=%lx", resource);
++ ehca_err(&shca->ib_device, "EHCA ----- error data end "
++ "----------------------------------------------------");
++
++ return;
++}
++
++int ehca_error_data(struct ehca_shca *shca, void *data,
++ u64 resource)
++{
++
++ unsigned long ret;
++ u64 *rblock;
++ unsigned long block_count;
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_err(&shca->ib_device, "Cannot allocate rblock memory.");
++ ret = -ENOMEM;
++ goto error_data1;
++ }
++
++ ret = hipz_h_error_data(shca->ipz_hca_handle,
++ resource,
++ rblock,
++ &block_count);
++
++ if (ret == H_R_STATE) {
++ ehca_err(&shca->ib_device,
++ "No error data is available: %lx.", resource);
++ }
++ else if (ret == H_SUCCESS) {
++ int length;
++
++ length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]);
++
++ if (length > PAGE_SIZE)
++ length = PAGE_SIZE;
++
++ print_error_data(shca, data, rblock, length);
++ }
++ else {
++ ehca_err(&shca->ib_device,
++ "Error data could not be fetched: %lx", resource);
++ }
++
++ kfree(rblock);
++
++error_data1:
++ return ret;
++
++}
++
++static void qp_event_callback(struct ehca_shca *shca,
++ u64 eqe,
++ enum ib_event_type event_type)
++{
++ struct ib_event event;
++ struct ehca_qp *qp;
++ unsigned long flags;
++ u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
++
++ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
++ qp = idr_find(&ehca_qp_idr, token);
++ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
++
++
++ if (!qp)
++ return;
++
++ ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
++
++ if (!qp->ib_qp.event_handler)
++ return;
++
++ event.device = &shca->ib_device;
++ event.event = event_type;
++ event.element.qp = &qp->ib_qp;
++
++ qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
++
++ return;
++}
++
++static void cq_event_callback(struct ehca_shca *shca,
++ u64 eqe)
++{
++ struct ehca_cq *cq;
++ unsigned long flags;
++ u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe);
++
++ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
++ cq = idr_find(&ehca_cq_idr, token);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
++
++ if (!cq)
++ return;
++
++ ehca_error_data(shca, cq, cq->ipz_cq_handle.handle);
++
++ return;
++}
++
++static void parse_identifier(struct ehca_shca *shca, u64 eqe)
++{
++ u8 identifier = EHCA_BMASK_GET(EQE_EE_IDENTIFIER, eqe);
++
++ switch (identifier) {
++ case 0x02: /* path migrated */
++ qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG);
++ break;
++ case 0x03: /* communication established */
++ qp_event_callback(shca, eqe, IB_EVENT_COMM_EST);
++ break;
++ case 0x04: /* send queue drained */
++ qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED);
++ break;
++ case 0x05: /* QP error */
++ case 0x06: /* QP error */
++ qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL);
++ break;
++ case 0x07: /* CQ error */
++ case 0x08: /* CQ error */
++ cq_event_callback(shca, eqe);
++ break;
++ case 0x09: /* MRMWPTE error */
++ ehca_err(&shca->ib_device, "MRMWPTE error.");
++ break;
++ case 0x0A: /* port event */
++ ehca_err(&shca->ib_device, "Port event.");
++ break;
++ case 0x0B: /* MR access error */
++ ehca_err(&shca->ib_device, "MR access error.");
++ break;
++ case 0x0C: /* EQ error */
++ ehca_err(&shca->ib_device, "EQ error.");
++ break;
++ case 0x0D: /* P/Q_Key mismatch */
++ ehca_err(&shca->ib_device, "P/Q_Key mismatch.");
++ break;
++ case 0x10: /* sampling complete */
++ ehca_err(&shca->ib_device, "Sampling complete.");
++ break;
++ case 0x11: /* unaffiliated access error */
++ ehca_err(&shca->ib_device, "Unaffiliated access error.");
++ break;
++ case 0x12: /* path migrating error */
++ ehca_err(&shca->ib_device, "Path migration error.");
++ break;
++ case 0x13: /* interface trace stopped */
++ ehca_err(&shca->ib_device, "Interface trace stopped.");
++ break;
++ case 0x14: /* first error capture info available */
++ default:
++ ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
++ identifier, shca->ib_device.name);
++ break;
++ }
++
++ return;
++}
++
++static void parse_ec(struct ehca_shca *shca, u64 eqe)
++{
++ struct ib_event event;
++ u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
++ u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
++
++ switch (ec) {
++ case 0x30: /* port availability change */
++ if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
++ ehca_info(&shca->ib_device,
++ "port %x is active.", port);
++ event.device = &shca->ib_device;
++ event.event = IB_EVENT_PORT_ACTIVE;
++ event.element.port_num = port;
++ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
++ ib_dispatch_event(&event);
++ } else {
++ ehca_info(&shca->ib_device,
++ "port %x is inactive.", port);
++ event.device = &shca->ib_device;
++ event.event = IB_EVENT_PORT_ERR;
++ event.element.port_num = port;
++ shca->sport[port - 1].port_state = IB_PORT_DOWN;
++ ib_dispatch_event(&event);
++ }
++ break;
++ case 0x31:
++ /* port configuration change
++ * disruptive change is caused by
++ * LID, PKEY or SM change
++ */
++ ehca_warn(&shca->ib_device,
++ "disruptive port %x configuration change", port);
++
++ ehca_info(&shca->ib_device,
++ "port %x is inactive.", port);
++ event.device = &shca->ib_device;
++ event.event = IB_EVENT_PORT_ERR;
++ event.element.port_num = port;
++ shca->sport[port - 1].port_state = IB_PORT_DOWN;
++ ib_dispatch_event(&event);
++
++ ehca_info(&shca->ib_device,
++ "port %x is active.", port);
++ event.device = &shca->ib_device;
++ event.event = IB_EVENT_PORT_ACTIVE;
++ event.element.port_num = port;
++ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
++ ib_dispatch_event(&event);
++ break;
++ case 0x32: /* adapter malfunction */
++ ehca_err(&shca->ib_device, "Adapter malfunction.");
++ break;
++ case 0x33: /* trace stopped */
++ ehca_err(&shca->ib_device, "Traced stopped.");
++ break;
++ default:
++ ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
++ ec, shca->ib_device.name);
++ break;
++ }
++
++ return;
++}
++
++static inline void reset_eq_pending(struct ehca_cq *cq)
++{
++ u64 CQx_EP;
++ struct h_galpa gal = cq->galpas.kernel;
++
++ hipz_galpa_store_cq(gal, cqx_ep, 0x0);
++ CQx_EP = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_ep));
++
++ return;
++}
++
++irqreturn_t ehca_interrupt_neq(int irq, void *dev_id)
++{
++ struct ehca_shca *shca = (struct ehca_shca*)dev_id;
++
++ tasklet_hi_schedule(&shca->neq.interrupt_task);
++
++ return IRQ_HANDLED;
++}
++
++void ehca_tasklet_neq(unsigned long data)
++{
++ struct ehca_shca *shca = (struct ehca_shca*)data;
++ struct ehca_eqe *eqe;
++ u64 ret;
++
++ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
++
++ while (eqe) {
++ if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry))
++ parse_ec(shca, eqe->entry);
++
++ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
++ }
++
++ ret = hipz_h_reset_event(shca->ipz_hca_handle,
++ shca->neq.ipz_eq_handle, 0xFFFFFFFFFFFFFFFFL);
++
++ if (ret != H_SUCCESS)
++ ehca_err(&shca->ib_device, "Can't clear notification events.");
++
++ return;
++}
++
++irqreturn_t ehca_interrupt_eq(int irq, void *dev_id)
++{
++ struct ehca_shca *shca = (struct ehca_shca*)dev_id;
++
++ tasklet_hi_schedule(&shca->eq.interrupt_task);
++
++ return IRQ_HANDLED;
++}
++
++void ehca_tasklet_eq(unsigned long data)
++{
++ struct ehca_shca *shca = (struct ehca_shca*)data;
++ struct ehca_eqe *eqe;
++ int int_state;
++ int query_cnt = 0;
++
++ do {
++ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
++
++ if ((shca->hw_level >= 2) && eqe)
++ int_state = 1;
++ else
++ int_state = 0;
++
++ while ((int_state == 1) || eqe) {
++ while (eqe) {
++ u64 eqe_value = eqe->entry;
++
++ ehca_dbg(&shca->ib_device,
++ "eqe_value=%lx", eqe_value);
++
++ /* TODO: better structure */
++ if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT,
++ eqe_value)) {
++ unsigned long flags;
++ u32 token;
++ struct ehca_cq *cq;
++
++ ehca_dbg(&shca->ib_device,
++ "... completion event");
++ token =
++ EHCA_BMASK_GET(EQE_CQ_TOKEN,
++ eqe_value);
++ spin_lock_irqsave(&ehca_cq_idr_lock,
++ flags);
++ cq = idr_find(&ehca_cq_idr, token);
++
++ if (cq == NULL) {
++ spin_unlock(&ehca_cq_idr_lock);
++ break;
++ }
++
++ reset_eq_pending(cq);
++#ifdef CONFIG_INFINIBAND_EHCA_SCALING
++ queue_comp_task(cq);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock,
++ flags);
++#else
++ spin_unlock_irqrestore(&ehca_cq_idr_lock,
++ flags);
++ comp_event_callback(cq);
++#endif
++ } else {
++ ehca_dbg(&shca->ib_device,
++ "... non completion event");
++ parse_identifier(shca, eqe_value);
++ }
++ eqe =
++ (struct ehca_eqe *)ehca_poll_eq(shca,
++ &shca->eq);
++ }
++
++ if (shca->hw_level >= 2) {
++ int_state =
++ hipz_h_query_int_state(shca->ipz_hca_handle,
++ shca->eq.ist);
++ query_cnt++;
++ iosync();
++ if (query_cnt >= 100) {
++ query_cnt = 0;
++ int_state = 0;
++ }
++ }
++ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
++
++ }
++ } while (int_state != 0);
++
++ return;
++}
++
++#ifdef CONFIG_INFINIBAND_EHCA_SCALING
++
++static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
++{
++ unsigned long flags_last_cpu;
++
++ if (ehca_debug_level)
++ ehca_dmp(&cpu_online_map, sizeof(cpumask_t), "");
++
++ spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu);
++ pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map);
++ if (pool->last_cpu == NR_CPUS)
++ pool->last_cpu = first_cpu(cpu_online_map);
++ spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu);
++
++ return pool->last_cpu;
++}
++
++static void __queue_comp_task(struct ehca_cq *__cq,
++ struct ehca_cpu_comp_task *cct)
++{
++ unsigned long flags_cct;
++ unsigned long flags_cq;
++
++ spin_lock_irqsave(&cct->task_lock, flags_cct);
++ spin_lock_irqsave(&__cq->task_lock, flags_cq);
++
++ if (__cq->nr_callbacks == 0) {
++ __cq->nr_callbacks++;
++ list_add_tail(&__cq->entry, &cct->cq_list);
++ cct->cq_jobs++;
++ wake_up(&cct->wait_queue);
++ }
++ else
++ __cq->nr_callbacks++;
++
++ spin_unlock_irqrestore(&__cq->task_lock, flags_cq);
++ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
++}
++
++static void queue_comp_task(struct ehca_cq *__cq)
++{
++ int cpu;
++ int cpu_id;
++ struct ehca_cpu_comp_task *cct;
++
++ cpu = get_cpu();
++ cpu_id = find_next_online_cpu(pool);
++
++ BUG_ON(!cpu_online(cpu_id));
++
++ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
++
++ if (cct->cq_jobs > 0) {
++ cpu_id = find_next_online_cpu(pool);
++ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
++ }
++
++ __queue_comp_task(__cq, cct);
++
++ put_cpu();
++
++ return;
++}
++
++static void run_comp_task(struct ehca_cpu_comp_task* cct)
++{
++ struct ehca_cq *cq;
++ unsigned long flags_cct;
++ unsigned long flags_cq;
++
++ spin_lock_irqsave(&cct->task_lock, flags_cct);
++
++ while (!list_empty(&cct->cq_list)) {
++ cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
++ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
++ comp_event_callback(cq);
++ spin_lock_irqsave(&cct->task_lock, flags_cct);
++
++ spin_lock_irqsave(&cq->task_lock, flags_cq);
++ cq->nr_callbacks--;
++ if (cq->nr_callbacks == 0) {
++ list_del_init(cct->cq_list.next);
++ cct->cq_jobs--;
++ }
++ spin_unlock_irqrestore(&cq->task_lock, flags_cq);
++
++ }
++
++ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
++
++ return;
++}
++
++static int comp_task(void *__cct)
++{
++ struct ehca_cpu_comp_task* cct = __cct;
++ DECLARE_WAITQUEUE(wait, current);
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ while(!kthread_should_stop()) {
++ add_wait_queue(&cct->wait_queue, &wait);
++
++ if (list_empty(&cct->cq_list))
++ schedule();
++ else
++ __set_current_state(TASK_RUNNING);
++
++ remove_wait_queue(&cct->wait_queue, &wait);
++
++ if (!list_empty(&cct->cq_list))
++ run_comp_task(__cct);
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ }
++ __set_current_state(TASK_RUNNING);
++
++ return 0;
++}
++
++static struct task_struct *create_comp_task(struct ehca_comp_pool *pool,
++ int cpu)
++{
++ struct ehca_cpu_comp_task *cct;
++
++ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
++ spin_lock_init(&cct->task_lock);
++ INIT_LIST_HEAD(&cct->cq_list);
++ init_waitqueue_head(&cct->wait_queue);
++ cct->task = kthread_create(comp_task, cct, "ehca_comp/%d", cpu);
++
++ return cct->task;
++}
++
++static void destroy_comp_task(struct ehca_comp_pool *pool,
++ int cpu)
++{
++ struct ehca_cpu_comp_task *cct;
++ struct task_struct *task;
++ unsigned long flags_cct;
++
++ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
++
++ spin_lock_irqsave(&cct->task_lock, flags_cct);
++
++ task = cct->task;
++ cct->task = NULL;
++ cct->cq_jobs = 0;
++
++ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
++
++ if (task)
++ kthread_stop(task);
++
++ return;
++}
++
++static void take_over_work(struct ehca_comp_pool *pool,
++ int cpu)
++{
++ struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
++ LIST_HEAD(list);
++ struct ehca_cq *cq;
++ unsigned long flags_cct;
++
++ spin_lock_irqsave(&cct->task_lock, flags_cct);
++
++ list_splice_init(&cct->cq_list, &list);
++
++ while(!list_empty(&list)) {
++ cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
++
++ list_del(&cq->entry);
++ __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
++ smp_processor_id()));
++ }
++
++ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
++
++}
++
++static int comp_pool_callback(struct notifier_block *nfb,
++ unsigned long action,
++ void *hcpu)
++{
++ unsigned int cpu = (unsigned long)hcpu;
++ struct ehca_cpu_comp_task *cct;
++
++ switch (action) {
++ case CPU_UP_PREPARE:
++ ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
++ if(!create_comp_task(pool, cpu)) {
++ ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
++ return NOTIFY_BAD;
++ }
++ break;
++ case CPU_UP_CANCELED:
++ ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
++ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
++ kthread_bind(cct->task, any_online_cpu(cpu_online_map));
++ destroy_comp_task(pool, cpu);
++ break;
++ case CPU_ONLINE:
++ ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
++ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
++ kthread_bind(cct->task, cpu);
++ wake_up_process(cct->task);
++ break;
++ case CPU_DOWN_PREPARE:
++ ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
++ break;
++ case CPU_DOWN_FAILED:
++ ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
++ break;
++ case CPU_DEAD:
++ ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
++ destroy_comp_task(pool, cpu);
++ take_over_work(pool, cpu);
++ break;
++ }
++
++ return NOTIFY_OK;
++}
++
++#endif
++
++int ehca_create_comp_pool(void)
++{
++#ifdef CONFIG_INFINIBAND_EHCA_SCALING
++ int cpu;
++ struct task_struct *task;
++
++ pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL);
++ if (pool == NULL)
++ return -ENOMEM;
++
++ spin_lock_init(&pool->last_cpu_lock);
++ pool->last_cpu = any_online_cpu(cpu_online_map);
++
++ pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
++ if (pool->cpu_comp_tasks == NULL) {
++ kfree(pool);
++ return -EINVAL;
++ }
++
++ for_each_online_cpu(cpu) {
++ task = create_comp_task(pool, cpu);
++ if (task) {
++ kthread_bind(task, cpu);
++ wake_up_process(task);
++ }
++ }
++
++ comp_pool_callback_nb.notifier_call = comp_pool_callback;
++ comp_pool_callback_nb.priority =0;
++ register_cpu_notifier(&comp_pool_callback_nb);
++#endif
++
++ return 0;
++}
++
++void ehca_destroy_comp_pool(void)
++{
++#ifdef CONFIG_INFINIBAND_EHCA_SCALING
++ int i;
++
++ unregister_cpu_notifier(&comp_pool_callback_nb);
++
++ for (i = 0; i < NR_CPUS; i++) {
++ if (cpu_online(i))
++ destroy_comp_task(pool, i);
++ }
++#endif
++
++ return;
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h
+new file mode 100644
+index 0000000..be579cc
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_irq.h
+@@ -0,0 +1,77 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Function definitions and structs for EQs, NEQs and interrupts
++ *
++ * Authors: Heiko J Schick <schickhj at de.ibm.com>
++ * Khadija Souissi <souissi at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __EHCA_IRQ_H
++#define __EHCA_IRQ_H
++
++
++struct ehca_shca;
++
++#include <linux/interrupt.h>
++#include <linux/types.h>
++#include <asm/atomic.h>
++
++int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource);
++
++irqreturn_t ehca_interrupt_neq(int irq, void *dev_id);
++void ehca_tasklet_neq(unsigned long data);
++
++irqreturn_t ehca_interrupt_eq(int irq, void *dev_id);
++void ehca_tasklet_eq(unsigned long data);
++
++struct ehca_cpu_comp_task {
++ wait_queue_head_t wait_queue;
++ struct list_head cq_list;
++ struct task_struct *task;
++ spinlock_t task_lock;
++ int cq_jobs;
++};
++
++struct ehca_comp_pool {
++ struct ehca_cpu_comp_task *cpu_comp_tasks;
++ int last_cpu;
++ spinlock_t last_cpu_lock;
++};
++
++int ehca_create_comp_pool(void);
++void ehca_destroy_comp_pool(void);
++
++#endif
+diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
+new file mode 100644
+index 0000000..319c39d
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
+@@ -0,0 +1,182 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Function definitions for internal functions
++ *
++ * Authors: Heiko J Schick <schickhj at de.ibm.com>
++ * Dietmar Decker <ddecker at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __EHCA_IVERBS_H__
++#define __EHCA_IVERBS_H__
++
++#include "ehca_classes.h"
++
++int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
++
++int ehca_query_port(struct ib_device *ibdev, u8 port,
++ struct ib_port_attr *props);
++
++int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
++
++int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
++ union ib_gid *gid);
++
++int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask,
++ struct ib_port_modify *props);
++
++struct ib_pd *ehca_alloc_pd(struct ib_device *device,
++ struct ib_ucontext *context,
++ struct ib_udata *udata);
++
++int ehca_dealloc_pd(struct ib_pd *pd);
++
++struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
++
++int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
++
++int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
++
++int ehca_destroy_ah(struct ib_ah *ah);
++
++struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
++
++struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
++ struct ib_phys_buf *phys_buf_array,
++ int num_phys_buf,
++ int mr_access_flags, u64 *iova_start);
++
++struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
++ struct ib_umem *region,
++ int mr_access_flags, struct ib_udata *udata);
++
++int ehca_rereg_phys_mr(struct ib_mr *mr,
++ int mr_rereg_mask,
++ struct ib_pd *pd,
++ struct ib_phys_buf *phys_buf_array,
++ int num_phys_buf, int mr_access_flags, u64 *iova_start);
++
++int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr);
++
++int ehca_dereg_mr(struct ib_mr *mr);
++
++struct ib_mw *ehca_alloc_mw(struct ib_pd *pd);
++
++int ehca_bind_mw(struct ib_qp *qp, struct ib_mw *mw,
++ struct ib_mw_bind *mw_bind);
++
++int ehca_dealloc_mw(struct ib_mw *mw);
++
++struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
++ int mr_access_flags,
++ struct ib_fmr_attr *fmr_attr);
++
++int ehca_map_phys_fmr(struct ib_fmr *fmr,
++ u64 *page_list, int list_len, u64 iova);
++
++int ehca_unmap_fmr(struct list_head *fmr_list);
++
++int ehca_dealloc_fmr(struct ib_fmr *fmr);
++
++enum ehca_eq_type {
++ EHCA_EQ = 0, /* Event Queue */
++ EHCA_NEQ /* Notification Event Queue */
++};
++
++int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq,
++ enum ehca_eq_type type, const u32 length);
++
++int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
++
++void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
++
++
++struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
++ struct ib_ucontext *context,
++ struct ib_udata *udata);
++
++int ehca_destroy_cq(struct ib_cq *cq);
++
++int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata);
++
++int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
++
++int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
++
++int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify);
++
++struct ib_qp *ehca_create_qp(struct ib_pd *pd,
++ struct ib_qp_init_attr *init_attr,
++ struct ib_udata *udata);
++
++int ehca_destroy_qp(struct ib_qp *qp);
++
++int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
++ struct ib_udata *udata);
++
++int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
++ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
++
++int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
++ struct ib_send_wr **bad_send_wr);
++
++int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
++ struct ib_recv_wr **bad_recv_wr);
++
++u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp,
++ struct ib_qp_init_attr *qp_init_attr);
++
++int ehca_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
++
++int ehca_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
++
++struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
++ struct ib_udata *udata);
++
++int ehca_dealloc_ucontext(struct ib_ucontext *context);
++
++int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
++
++void ehca_poll_eqs(unsigned long data);
++
++int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
++ struct vm_area_struct **vma);
++
++int ehca_mmap_register(u64 physical,void **mapped,
++ struct vm_area_struct **vma);
++
++int ehca_munmap(unsigned long addr, size_t len);
++
++#endif
+diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
+new file mode 100644
+index 0000000..024d511
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_main.c
+@@ -0,0 +1,820 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * module start stop, hca detection
++ *
++ * Authors: Heiko J Schick <schickhj at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Joachim Fenkes <fenkes at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "ehca_classes.h"
++#include "ehca_iverbs.h"
++#include "ehca_mrmw.h"
++#include "ehca_tools.h"
++#include "hcp_if.h"
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Christoph Raisch <raisch at de.ibm.com>");
++MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
++MODULE_VERSION("SVNEHCA_0017");
++
++int ehca_open_aqp1 = 0;
++int ehca_debug_level = 0;
++int ehca_hw_level = 0;
++int ehca_nr_ports = 2;
++int ehca_use_hp_mr = 0;
++int ehca_port_act_time = 30;
++int ehca_poll_all_eqs = 1;
++int ehca_static_rate = -1;
++
++module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
++module_param_named(debug_level, ehca_debug_level, int, 0);
++module_param_named(hw_level, ehca_hw_level, int, 0);
++module_param_named(nr_ports, ehca_nr_ports, int, 0);
++module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
++module_param_named(port_act_time, ehca_port_act_time, int, 0);
++module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
++module_param_named(static_rate, ehca_static_rate, int, 0);
++
++MODULE_PARM_DESC(open_aqp1,
++ "AQP1 on startup (0: no (default), 1: yes)");
++MODULE_PARM_DESC(debug_level,
++ "debug level"
++ " (0: no debug traces (default), 1: with debug traces)");
++MODULE_PARM_DESC(hw_level,
++ "hardware level"
++ " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
++MODULE_PARM_DESC(nr_ports,
++ "number of connected ports (default: 2)");
++MODULE_PARM_DESC(use_hp_mr,
++ "high performance MRs (0: no (default), 1: yes)");
++MODULE_PARM_DESC(port_act_time,
++ "time to wait for port activation (default: 30 sec)");
++MODULE_PARM_DESC(poll_all_eqs,
++ "polls all event queues periodically"
++ " (0: no, 1: yes (default))");
++MODULE_PARM_DESC(static_rate,
++ "set permanent static rate (default: disabled)");
++
++spinlock_t ehca_qp_idr_lock;
++spinlock_t ehca_cq_idr_lock;
++DEFINE_IDR(ehca_qp_idr);
++DEFINE_IDR(ehca_cq_idr);
++
++static struct list_head shca_list; /* list of all registered ehcas */
++static spinlock_t shca_list_lock;
++
++static struct timer_list poll_eqs_timer;
++
++static int ehca_create_slab_caches(void)
++{
++ int ret;
++
++ ret = ehca_init_pd_cache();
++ if (ret) {
++ ehca_gen_err("Cannot create PD SLAB cache.");
++ return ret;
++ }
++
++ ret = ehca_init_cq_cache();
++ if (ret) {
++ ehca_gen_err("Cannot create CQ SLAB cache.");
++ goto create_slab_caches2;
++ }
++
++ ret = ehca_init_qp_cache();
++ if (ret) {
++ ehca_gen_err("Cannot create QP SLAB cache.");
++ goto create_slab_caches3;
++ }
++
++ ret = ehca_init_av_cache();
++ if (ret) {
++ ehca_gen_err("Cannot create AV SLAB cache.");
++ goto create_slab_caches4;
++ }
++
++ ret = ehca_init_mrmw_cache();
++ if (ret) {
++ ehca_gen_err("Cannot create MR&MW SLAB cache.");
++ goto create_slab_caches5;
++ }
++
++ return 0;
++
++create_slab_caches5:
++ ehca_cleanup_av_cache();
++
++create_slab_caches4:
++ ehca_cleanup_qp_cache();
++
++create_slab_caches3:
++ ehca_cleanup_cq_cache();
++
++create_slab_caches2:
++ ehca_cleanup_pd_cache();
++
++ return ret;
++}
++
++static void ehca_destroy_slab_caches(void)
++{
++ ehca_cleanup_mrmw_cache();
++ ehca_cleanup_av_cache();
++ ehca_cleanup_qp_cache();
++ ehca_cleanup_cq_cache();
++ ehca_cleanup_pd_cache();
++}
++
++#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
++#define EHCA_REVID EHCA_BMASK_IBM(40,63)
++
++int ehca_sense_attributes(struct ehca_shca *shca)
++{
++ int ret = 0;
++ u64 h_ret;
++ struct hipz_query_hca *rblock;
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_gen_err("Cannot allocate rblock memory.");
++ return -ENOMEM;
++ }
++
++ h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
++ if (h_ret != H_SUCCESS) {
++ ehca_gen_err("Cannot query device properties. h_ret=%lx",
++ h_ret);
++ ret = -EPERM;
++ goto num_ports1;
++ }
++
++ if (ehca_nr_ports == 1)
++ shca->num_ports = 1;
++ else
++ shca->num_ports = (u8)rblock->num_ports;
++
++ ehca_gen_dbg(" ... found %x ports", rblock->num_ports);
++
++ if (ehca_hw_level == 0) {
++ u32 hcaaver;
++ u32 revid;
++
++ hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver);
++ revid = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver);
++
++ ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
++
++ if ((hcaaver == 1) && (revid == 0))
++ shca->hw_level = 0;
++ else if ((hcaaver == 1) && (revid == 1))
++ shca->hw_level = 1;
++ else if ((hcaaver == 1) && (revid == 2))
++ shca->hw_level = 2;
++ }
++ ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
++
++ shca->sport[0].rate = IB_RATE_30_GBPS;
++ shca->sport[1].rate = IB_RATE_30_GBPS;
++
++num_ports1:
++ kfree(rblock);
++ return ret;
++}
++
++static int init_node_guid(struct ehca_shca *shca)
++{
++ int ret = 0;
++ struct hipz_query_hca *rblock;
++
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!rblock) {
++ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
++ return -ENOMEM;
++ }
++
++ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "Can't query device properties");
++ ret = -EINVAL;
++ goto init_node_guid1;
++ }
++
++ memcpy(&shca->ib_device.node_guid, &rblock->node_guid, sizeof(u64));
++
++init_node_guid1:
++ kfree(rblock);
++ return ret;
++}
++
++int ehca_init_device(struct ehca_shca *shca)
++{
++ int ret;
++
++ ret = init_node_guid(shca);
++ if (ret)
++ return ret;
++
++ strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
++ shca->ib_device.owner = THIS_MODULE;
++
++ shca->ib_device.uverbs_abi_ver = 5;
++ shca->ib_device.uverbs_cmd_mask =
++ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
++ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
++ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
++ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
++ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
++ (1ull << IB_USER_VERBS_CMD_REG_MR) |
++ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
++ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
++ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
++ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
++ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
++ (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
++ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
++
++ shca->ib_device.node_type = RDMA_NODE_IB_CA;
++ shca->ib_device.phys_port_cnt = shca->num_ports;
++ shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev;
++ shca->ib_device.query_device = ehca_query_device;
++ shca->ib_device.query_port = ehca_query_port;
++ shca->ib_device.query_gid = ehca_query_gid;
++ shca->ib_device.query_pkey = ehca_query_pkey;
++ /* shca->in_device.modify_device = ehca_modify_device */
++ shca->ib_device.modify_port = ehca_modify_port;
++ shca->ib_device.alloc_ucontext = ehca_alloc_ucontext;
++ shca->ib_device.dealloc_ucontext = ehca_dealloc_ucontext;
++ shca->ib_device.alloc_pd = ehca_alloc_pd;
++ shca->ib_device.dealloc_pd = ehca_dealloc_pd;
++ shca->ib_device.create_ah = ehca_create_ah;
++ /* shca->ib_device.modify_ah = ehca_modify_ah; */
++ shca->ib_device.query_ah = ehca_query_ah;
++ shca->ib_device.destroy_ah = ehca_destroy_ah;
++ shca->ib_device.create_qp = ehca_create_qp;
++ shca->ib_device.modify_qp = ehca_modify_qp;
++ shca->ib_device.query_qp = ehca_query_qp;
++ shca->ib_device.destroy_qp = ehca_destroy_qp;
++ shca->ib_device.post_send = ehca_post_send;
++ shca->ib_device.post_recv = ehca_post_recv;
++ shca->ib_device.create_cq = ehca_create_cq;
++ shca->ib_device.destroy_cq = ehca_destroy_cq;
++ shca->ib_device.resize_cq = ehca_resize_cq;
++ shca->ib_device.poll_cq = ehca_poll_cq;
++ /* shca->ib_device.peek_cq = ehca_peek_cq; */
++ shca->ib_device.req_notify_cq = ehca_req_notify_cq;
++ /* shca->ib_device.req_ncomp_notif = ehca_req_ncomp_notif; */
++ shca->ib_device.get_dma_mr = ehca_get_dma_mr;
++ shca->ib_device.reg_phys_mr = ehca_reg_phys_mr;
++ shca->ib_device.reg_user_mr = ehca_reg_user_mr;
++ shca->ib_device.query_mr = ehca_query_mr;
++ shca->ib_device.dereg_mr = ehca_dereg_mr;
++ shca->ib_device.rereg_phys_mr = ehca_rereg_phys_mr;
++ shca->ib_device.alloc_mw = ehca_alloc_mw;
++ shca->ib_device.bind_mw = ehca_bind_mw;
++ shca->ib_device.dealloc_mw = ehca_dealloc_mw;
++ shca->ib_device.alloc_fmr = ehca_alloc_fmr;
++ shca->ib_device.map_phys_fmr = ehca_map_phys_fmr;
++ shca->ib_device.unmap_fmr = ehca_unmap_fmr;
++ shca->ib_device.dealloc_fmr = ehca_dealloc_fmr;
++ shca->ib_device.attach_mcast = ehca_attach_mcast;
++ shca->ib_device.detach_mcast = ehca_detach_mcast;
++ /* shca->ib_device.process_mad = ehca_process_mad; */
++ shca->ib_device.mmap = ehca_mmap;
++
++ return ret;
++}
++
++static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
++{
++ struct ehca_sport *sport = &shca->sport[port - 1];
++ struct ib_cq *ibcq;
++ struct ib_qp *ibqp;
++ struct ib_qp_init_attr qp_init_attr;
++ int ret;
++
++ if (sport->ibcq_aqp1) {
++ ehca_err(&shca->ib_device, "AQP1 CQ is already created.");
++ return -EPERM;
++ }
++
++ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
++ if (IS_ERR(ibcq)) {
++ ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
++ return PTR_ERR(ibcq);
++ }
++ sport->ibcq_aqp1 = ibcq;
++
++ if (sport->ibqp_aqp1) {
++ ehca_err(&shca->ib_device, "AQP1 QP is already created.");
++ ret = -EPERM;
++ goto create_aqp1;
++ }
++
++ memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr));
++ qp_init_attr.send_cq = ibcq;
++ qp_init_attr.recv_cq = ibcq;
++ qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
++ qp_init_attr.cap.max_send_wr = 100;
++ qp_init_attr.cap.max_recv_wr = 100;
++ qp_init_attr.cap.max_send_sge = 2;
++ qp_init_attr.cap.max_recv_sge = 1;
++ qp_init_attr.qp_type = IB_QPT_GSI;
++ qp_init_attr.port_num = port;
++ qp_init_attr.qp_context = NULL;
++ qp_init_attr.event_handler = NULL;
++ qp_init_attr.srq = NULL;
++
++ ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr);
++ if (IS_ERR(ibqp)) {
++ ehca_err(&shca->ib_device, "Cannot create AQP1 QP.");
++ ret = PTR_ERR(ibqp);
++ goto create_aqp1;
++ }
++ sport->ibqp_aqp1 = ibqp;
++
++ return 0;
++
++create_aqp1:
++ ib_destroy_cq(sport->ibcq_aqp1);
++ return ret;
++}
++
++static int ehca_destroy_aqp1(struct ehca_sport *sport)
++{
++ int ret;
++
++ ret = ib_destroy_qp(sport->ibqp_aqp1);
++ if (ret) {
++ ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret);
++ return ret;
++ }
++
++ ret = ib_destroy_cq(sport->ibcq_aqp1);
++ if (ret)
++ ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret);
++
++ return ret;
++}
++
++static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n",
++ ehca_debug_level);
++}
++
++static ssize_t ehca_store_debug_level(struct device_driver *ddp,
++ const char *buf, size_t count)
++{
++ int value = (*buf) - '0';
++ if (value >= 0 && value <= 9)
++ ehca_debug_level = value;
++ return 1;
++}
++
++DRIVER_ATTR(debug_level, S_IRUSR | S_IWUSR,
++ ehca_show_debug_level, ehca_store_debug_level);
++
++void ehca_create_driver_sysfs(struct ibmebus_driver *drv)
++{
++ driver_create_file(&drv->driver, &driver_attr_debug_level);
++}
++
++void ehca_remove_driver_sysfs(struct ibmebus_driver *drv)
++{
++ driver_remove_file(&drv->driver, &driver_attr_debug_level);
++}
++
++#define EHCA_RESOURCE_ATTR(name) \
++static ssize_t ehca_show_##name(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct ehca_shca *shca; \
++ struct hipz_query_hca *rblock; \
++ int data; \
++ \
++ shca = dev->driver_data; \
++ \
++ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); \
++ if (!rblock) { \
++ dev_err(dev, "Can't allocate rblock memory."); \
++ return 0; \
++ } \
++ \
++ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \
++ dev_err(dev, "Can't query device properties"); \
++ kfree(rblock); \
++ return 0; \
++ } \
++ \
++ data = rblock->name; \
++ kfree(rblock); \
++ \
++ if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \
++ return snprintf(buf, 256, "1\n"); \
++ else \
++ return snprintf(buf, 256, "%d\n", data); \
++ \
++} \
++static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL);
++
++EHCA_RESOURCE_ATTR(num_ports);
++EHCA_RESOURCE_ATTR(hw_ver);
++EHCA_RESOURCE_ATTR(max_eq);
++EHCA_RESOURCE_ATTR(cur_eq);
++EHCA_RESOURCE_ATTR(max_cq);
++EHCA_RESOURCE_ATTR(cur_cq);
++EHCA_RESOURCE_ATTR(max_qp);
++EHCA_RESOURCE_ATTR(cur_qp);
++EHCA_RESOURCE_ATTR(max_mr);
++EHCA_RESOURCE_ATTR(cur_mr);
++EHCA_RESOURCE_ATTR(max_mw);
++EHCA_RESOURCE_ATTR(cur_mw);
++EHCA_RESOURCE_ATTR(max_pd);
++EHCA_RESOURCE_ATTR(max_ah);
++
++static ssize_t ehca_show_adapter_handle(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct ehca_shca *shca = dev->driver_data;
++
++ return sprintf(buf, "%lx\n", shca->ipz_hca_handle.handle);
++
++}
++static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
++
++
++void ehca_create_device_sysfs(struct ibmebus_dev *dev)
++{
++ device_create_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
++ device_create_file(&dev->ofdev.dev, &dev_attr_num_ports);
++ device_create_file(&dev->ofdev.dev, &dev_attr_hw_ver);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_eq);
++ device_create_file(&dev->ofdev.dev, &dev_attr_cur_eq);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_cq);
++ device_create_file(&dev->ofdev.dev, &dev_attr_cur_cq);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_qp);
++ device_create_file(&dev->ofdev.dev, &dev_attr_cur_qp);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_mr);
++ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mr);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_mw);
++ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mw);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_pd);
++ device_create_file(&dev->ofdev.dev, &dev_attr_max_ah);
++}
++
++void ehca_remove_device_sysfs(struct ibmebus_dev *dev)
++{
++ device_remove_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_num_ports);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_hw_ver);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_eq);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_eq);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_cq);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_cq);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_qp);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_qp);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mr);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mr);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mw);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mw);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_pd);
++ device_remove_file(&dev->ofdev.dev, &dev_attr_max_ah);
++}
++
++static int __devinit ehca_probe(struct ibmebus_dev *dev,
++ const struct of_device_id *id)
++{
++ struct ehca_shca *shca;
++ u64 *handle;
++ struct ib_pd *ibpd;
++ int ret;
++
++ handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
++ if (!handle) {
++ ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
++ dev->ofdev.node->full_name);
++ return -ENODEV;
++ }
++
++ if (!(*handle)) {
++ ehca_gen_err("Wrong eHCA handle for adapter: %s.",
++ dev->ofdev.node->full_name);
++ return -ENODEV;
++ }
++
++ shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca));
++ if (!shca) {
++ ehca_gen_err("Cannot allocate shca memory.");
++ return -ENOMEM;
++ }
++
++ shca->ibmebus_dev = dev;
++ shca->ipz_hca_handle.handle = *handle;
++ dev->ofdev.dev.driver_data = shca;
++
++ ret = ehca_sense_attributes(shca);
++ if (ret < 0) {
++ ehca_gen_err("Cannot sense eHCA attributes.");
++ goto probe1;
++ }
++
++ ret = ehca_init_device(shca);
++ if (ret) {
++ ehca_gen_err("Cannot init ehca device struct");
++ goto probe1;
++ }
++
++ /* create event queues */
++ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
++ if (ret) {
++ ehca_err(&shca->ib_device, "Cannot create EQ.");
++ goto probe1;
++ }
++
++ ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);
++ if (ret) {
++ ehca_err(&shca->ib_device, "Cannot create NEQ.");
++ goto probe3;
++ }
++
++ /* create internal protection domain */
++ ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
++ if (IS_ERR(ibpd)) {
++ ehca_err(&shca->ib_device, "Cannot create internal PD.");
++ ret = PTR_ERR(ibpd);
++ goto probe4;
++ }
++
++ shca->pd = container_of(ibpd, struct ehca_pd, ib_pd);
++ shca->pd->ib_pd.device = &shca->ib_device;
++
++ /* create internal max MR */
++ ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
++
++ if (ret) {
++ ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x",
++ ret);
++ goto probe5;
++ }
++
++ ret = ib_register_device(&shca->ib_device);
++ if (ret) {
++ ehca_err(&shca->ib_device,
++ "ib_register_device() failed ret=%x", ret);
++ goto probe6;
++ }
++
++ /* create AQP1 for port 1 */
++ if (ehca_open_aqp1 == 1) {
++ shca->sport[0].port_state = IB_PORT_DOWN;
++ ret = ehca_create_aqp1(shca, 1);
++ if (ret) {
++ ehca_err(&shca->ib_device,
++ "Cannot create AQP1 for port 1.");
++ goto probe7;
++ }
++ }
++
++ /* create AQP1 for port 2 */
++ if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) {
++ shca->sport[1].port_state = IB_PORT_DOWN;
++ ret = ehca_create_aqp1(shca, 2);
++ if (ret) {
++ ehca_err(&shca->ib_device,
++ "Cannot create AQP1 for port 2.");
++ goto probe8;
++ }
++ }
++
++ ehca_create_device_sysfs(dev);
++
++ spin_lock(&shca_list_lock);
++ list_add(&shca->shca_list, &shca_list);
++ spin_unlock(&shca_list_lock);
++
++ return 0;
++
++probe8:
++ ret = ehca_destroy_aqp1(&shca->sport[0]);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy AQP1 for port 1. ret=%x", ret);
++
++probe7:
++ ib_unregister_device(&shca->ib_device);
++
++probe6:
++ ret = ehca_dereg_internal_maxmr(shca);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy internal MR. ret=%x", ret);
++
++probe5:
++ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy internal PD. ret=%x", ret);
++
++probe4:
++ ret = ehca_destroy_eq(shca, &shca->neq);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy NEQ. ret=%x", ret);
++
++probe3:
++ ret = ehca_destroy_eq(shca, &shca->eq);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy EQ. ret=%x", ret);
++
++probe1:
++ ib_dealloc_device(&shca->ib_device);
++
++ return -EINVAL;
++}
++
++static int __devexit ehca_remove(struct ibmebus_dev *dev)
++{
++ struct ehca_shca *shca = dev->ofdev.dev.driver_data;
++ int ret;
++
++ ehca_remove_device_sysfs(dev);
++
++ if (ehca_open_aqp1 == 1) {
++ int i;
++ for (i = 0; i < shca->num_ports; i++) {
++ ret = ehca_destroy_aqp1(&shca->sport[i]);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy AQP1 for port %x "
++ "ret=%x", ret, i);
++ }
++ }
++
++ ib_unregister_device(&shca->ib_device);
++
++ ret = ehca_dereg_internal_maxmr(shca);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy internal MR. ret=%x", ret);
++
++ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
++ if (ret)
++ ehca_err(&shca->ib_device,
++ "Cannot destroy internal PD. ret=%x", ret);
++
++ ret = ehca_destroy_eq(shca, &shca->eq);
++ if (ret)
++ ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret);
++
++ ret = ehca_destroy_eq(shca, &shca->neq);
++ if (ret)
++ ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret);
++
++ ib_dealloc_device(&shca->ib_device);
++
++ spin_lock(&shca_list_lock);
++ list_del(&shca->shca_list);
++ spin_unlock(&shca_list_lock);
++
++ return ret;
++}
++
++static struct of_device_id ehca_device_table[] =
++{
++ {
++ .name = "lhca",
++ .compatible = "IBM,lhca",
++ },
++ {},
++};
++
++static struct ibmebus_driver ehca_driver = {
++ .name = "ehca",
++ .id_table = ehca_device_table,
++ .probe = ehca_probe,
++ .remove = ehca_remove,
++};
++
++void ehca_poll_eqs(unsigned long data)
++{
++ struct ehca_shca *shca;
++
++ spin_lock(&shca_list_lock);
++ list_for_each_entry(shca, &shca_list, shca_list) {
++ if (shca->eq.is_initialized)
++ ehca_tasklet_eq((unsigned long)(void*)shca);
++ }
++ mod_timer(&poll_eqs_timer, jiffies + HZ);
++ spin_unlock(&shca_list_lock);
++}
++
++int __init ehca_module_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "eHCA Infiniband Device Driver "
++ "(Rel.: SVNEHCA_0017)\n");
++ idr_init(&ehca_qp_idr);
++ idr_init(&ehca_cq_idr);
++ spin_lock_init(&ehca_qp_idr_lock);
++ spin_lock_init(&ehca_cq_idr_lock);
++
++ INIT_LIST_HEAD(&shca_list);
++ spin_lock_init(&shca_list_lock);
++
++ if ((ret = ehca_create_comp_pool())) {
++ ehca_gen_err("Cannot create comp pool.");
++ return ret;
++ }
++
++ if ((ret = ehca_create_slab_caches())) {
++ ehca_gen_err("Cannot create SLAB caches");
++ ret = -ENOMEM;
++ goto module_init1;
++ }
++
++ if ((ret = ibmebus_register_driver(&ehca_driver))) {
++ ehca_gen_err("Cannot register eHCA device driver");
++ ret = -EINVAL;
++ goto module_init2;
++ }
++
++ ehca_create_driver_sysfs(&ehca_driver);
++
++ if (ehca_poll_all_eqs != 1) {
++ ehca_gen_err("WARNING!!!");
++ ehca_gen_err("It is possible to lose interrupts.");
++ } else {
++ init_timer(&poll_eqs_timer);
++ poll_eqs_timer.function = ehca_poll_eqs;
++ poll_eqs_timer.expires = jiffies + HZ;
++ add_timer(&poll_eqs_timer);
++ }
++
++ return 0;
++
++module_init2:
++ ehca_destroy_slab_caches();
++
++module_init1:
++ ehca_destroy_comp_pool();
++ return ret;
++};
++
++void __exit ehca_module_exit(void)
++{
++ if (ehca_poll_all_eqs == 1)
++ del_timer_sync(&poll_eqs_timer);
++
++ ehca_remove_driver_sysfs(&ehca_driver);
++ ibmebus_unregister_driver(&ehca_driver);
++
++ ehca_destroy_slab_caches();
++
++ ehca_destroy_comp_pool();
++
++ idr_destroy(&ehca_cq_idr);
++ idr_destroy(&ehca_qp_idr);
++};
++
++module_init(ehca_module_init);
++module_exit(ehca_module_exit);
+diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
+new file mode 100644
+index 0000000..32a8706
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
+@@ -0,0 +1,131 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * mcast functions
++ *
++ * Authors: Khadija Souissi <souissik at de.ibm.com>
++ * Waleri Fomin <fomin at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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/module.h>
++#include <linux/err.h>
++#include "ehca_classes.h"
++#include "ehca_tools.h"
++#include "ehca_qes.h"
++#include "ehca_iverbs.h"
++#include "hcp_if.h"
++
++#define MAX_MC_LID 0xFFFE
++#define MIN_MC_LID 0xC000 /* Multicast limits */
++#define EHCA_VALID_MULTICAST_GID(gid) ((gid)[0] == 0xFF)
++#define EHCA_VALID_MULTICAST_LID(lid) \
++ (((lid) >= MIN_MC_LID) && ((lid) <= MAX_MC_LID))
++
++int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
++{
++ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
++ struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
++ ib_device);
++ union ib_gid my_gid;
++ u64 subnet_prefix, interface_id, h_ret;
++
++ if (ibqp->qp_type != IB_QPT_UD) {
++ ehca_err(ibqp->device, "invalid qp_type=%x", ibqp->qp_type);
++ return -EINVAL;
++ }
++
++ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
++ ehca_err(ibqp->device, "invalid mulitcast gid");
++ return -EINVAL;
++ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
++ ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid);
++ return -EINVAL;
++ }
++
++ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
++
++ subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
++ interface_id = be64_to_cpu(my_gid.global.interface_id);
++ h_ret = hipz_h_attach_mcqp(shca->ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ my_qp->galpas.kernel,
++ lid, subnet_prefix, interface_id);
++ if (h_ret != H_SUCCESS)
++ ehca_err(ibqp->device,
++ "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
++ "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
++
++ return ehca2ib_return_code(h_ret);
++}
++
++int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
++{
++ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
++ struct ehca_shca *shca = container_of(ibqp->pd->device,
++ struct ehca_shca, ib_device);
++ union ib_gid my_gid;
++ u64 subnet_prefix, interface_id, h_ret;
++
++ if (ibqp->qp_type != IB_QPT_UD) {
++ ehca_err(ibqp->device, "invalid qp_type %x", ibqp->qp_type);
++ return -EINVAL;
++ }
++
++ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
++ ehca_err(ibqp->device, "invalid mulitcast gid");
++ return -EINVAL;
++ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
++ ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid);
++ return -EINVAL;
++ }
++
++ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
++
++ subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
++ interface_id = be64_to_cpu(my_gid.global.interface_id);
++ h_ret = hipz_h_detach_mcqp(shca->ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ my_qp->galpas.kernel,
++ lid, subnet_prefix, interface_id);
++ if (h_ret != H_SUCCESS)
++ ehca_err(ibqp->device,
++ "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
++ "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
++
++ return ehca2ib_return_code(h_ret);
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
+new file mode 100644
+index 0000000..5ca6544
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
+@@ -0,0 +1,2261 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * MR/MW functions
++ *
++ * Authors: Dietmar Decker <ddecker at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/current.h>
++
++#include "ehca_iverbs.h"
++#include "ehca_mrmw.h"
++#include "hcp_if.h"
++#include "hipz_hw.h"
++
++static struct kmem_cache *mr_cache;
++static struct kmem_cache *mw_cache;
++
++static struct ehca_mr *ehca_mr_new(void)
++{
++ struct ehca_mr *me;
++
++ me = kmem_cache_alloc(mr_cache, SLAB_KERNEL);
++ if (me) {
++ memset(me, 0, sizeof(struct ehca_mr));
++ spin_lock_init(&me->mrlock);
++ } else
++ ehca_gen_err("alloc failed");
++
++ return me;
++}
++
++static void ehca_mr_delete(struct ehca_mr *me)
++{
++ kmem_cache_free(mr_cache, me);
++}
++
++static struct ehca_mw *ehca_mw_new(void)
++{
++ struct ehca_mw *me;
++
++ me = kmem_cache_alloc(mw_cache, SLAB_KERNEL);
++ if (me) {
++ memset(me, 0, sizeof(struct ehca_mw));
++ spin_lock_init(&me->mwlock);
++ } else
++ ehca_gen_err("alloc failed");
++
++ return me;
++}
++
++static void ehca_mw_delete(struct ehca_mw *me)
++{
++ kmem_cache_free(mw_cache, me);
++}
++
++/*----------------------------------------------------------------------*/
++
++struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
++{
++ struct ib_mr *ib_mr;
++ int ret;
++ struct ehca_mr *e_maxmr;
++ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
++ struct ehca_shca *shca =
++ container_of(pd->device, struct ehca_shca, ib_device);
++
++ if (shca->maxmr) {
++ e_maxmr = ehca_mr_new();
++ if (!e_maxmr) {
++ ehca_err(&shca->ib_device, "out of memory");
++ ib_mr = ERR_PTR(-ENOMEM);
++ goto get_dma_mr_exit0;
++ }
++
++ ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
++ mr_access_flags, e_pd,
++ &e_maxmr->ib.ib_mr.lkey,
++ &e_maxmr->ib.ib_mr.rkey);
++ if (ret) {
++ ib_mr = ERR_PTR(ret);
++ goto get_dma_mr_exit0;
++ }
++ ib_mr = &e_maxmr->ib.ib_mr;
++ } else {
++ ehca_err(&shca->ib_device, "no internal max-MR exist!");
++ ib_mr = ERR_PTR(-EINVAL);
++ goto get_dma_mr_exit0;
++ }
++
++get_dma_mr_exit0:
++ if (IS_ERR(ib_mr))
++ ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ",
++ PTR_ERR(ib_mr), pd, mr_access_flags);
++ return ib_mr;
++} /* end ehca_get_dma_mr() */
++
++/*----------------------------------------------------------------------*/
++
++struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
++ struct ib_phys_buf *phys_buf_array,
++ int num_phys_buf,
++ int mr_access_flags,
++ u64 *iova_start)
++{
++ struct ib_mr *ib_mr;
++ int ret;
++ struct ehca_mr *e_mr;
++ struct ehca_shca *shca =
++ container_of(pd->device, struct ehca_shca, ib_device);
++ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
++
++ u64 size;
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++ u32 num_pages_mr;
++ u32 num_pages_4k; /* 4k portion "pages" */
++
++ if ((num_phys_buf <= 0) || !phys_buf_array) {
++ ehca_err(pd->device, "bad input values: num_phys_buf=%x "
++ "phys_buf_array=%p", num_phys_buf, phys_buf_array);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_phys_mr_exit0;
++ }
++ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
++ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
++ /*
++ * Remote Write Access requires Local Write Access
++ * Remote Atomic Access requires Local Write Access
++ */
++ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
++ mr_access_flags);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_phys_mr_exit0;
++ }
++
++ /* check physical buffer list and calculate size */
++ ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array, num_phys_buf,
++ iova_start, &size);
++ if (ret) {
++ ib_mr = ERR_PTR(ret);
++ goto reg_phys_mr_exit0;
++ }
++ if ((size == 0) ||
++ (((u64)iova_start + size) < (u64)iova_start)) {
++ ehca_err(pd->device, "bad input values: size=%lx iova_start=%p",
++ size, iova_start);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_phys_mr_exit0;
++ }
++
++ e_mr = ehca_mr_new();
++ if (!e_mr) {
++ ehca_err(pd->device, "out of memory");
++ ib_mr = ERR_PTR(-ENOMEM);
++ goto reg_phys_mr_exit0;
++ }
++
++ /* determine number of MR pages */
++ num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
++ PAGE_SIZE - 1) / PAGE_SIZE);
++ num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
++ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
++
++ /* register MR on HCA */
++ if (ehca_mr_is_maxmr(size, iova_start)) {
++ e_mr->flags |= EHCA_MR_FLAG_MAXMR;
++ ret = ehca_reg_maxmr(shca, e_mr, iova_start, mr_access_flags,
++ e_pd, &e_mr->ib.ib_mr.lkey,
++ &e_mr->ib.ib_mr.rkey);
++ if (ret) {
++ ib_mr = ERR_PTR(ret);
++ goto reg_phys_mr_exit1;
++ }
++ } else {
++ pginfo.type = EHCA_MR_PGI_PHYS;
++ pginfo.num_pages = num_pages_mr;
++ pginfo.num_4k = num_pages_4k;
++ pginfo.num_phys_buf = num_phys_buf;
++ pginfo.phys_buf_array = phys_buf_array;
++ pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
++ EHCA_PAGESIZE);
++
++ ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
++ e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
++ &e_mr->ib.ib_mr.rkey);
++ if (ret) {
++ ib_mr = ERR_PTR(ret);
++ goto reg_phys_mr_exit1;
++ }
++ }
++
++ /* successful registration of all pages */
++ return &e_mr->ib.ib_mr;
++
++reg_phys_mr_exit1:
++ ehca_mr_delete(e_mr);
++reg_phys_mr_exit0:
++ if (IS_ERR(ib_mr))
++ ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p "
++ "num_phys_buf=%x mr_access_flags=%x iova_start=%p",
++ PTR_ERR(ib_mr), pd, phys_buf_array,
++ num_phys_buf, mr_access_flags, iova_start);
++ return ib_mr;
++} /* end ehca_reg_phys_mr() */
++
++/*----------------------------------------------------------------------*/
++
++struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
++ struct ib_umem *region,
++ int mr_access_flags,
++ struct ib_udata *udata)
++{
++ struct ib_mr *ib_mr;
++ struct ehca_mr *e_mr;
++ struct ehca_shca *shca =
++ container_of(pd->device, struct ehca_shca, ib_device);
++ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++ int ret;
++ u32 num_pages_mr;
++ u32 num_pages_4k; /* 4k portion "pages" */
++
++ if (!pd) {
++ ehca_gen_err("bad pd=%p", pd);
++ return ERR_PTR(-EFAULT);
++ }
++ if (!region) {
++ ehca_err(pd->device, "bad input values: region=%p", region);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_user_mr_exit0;
++ }
++ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
++ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
++ /*
++ * Remote Write Access requires Local Write Access
++ * Remote Atomic Access requires Local Write Access
++ */
++ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
++ mr_access_flags);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_user_mr_exit0;
++ }
++ if (region->page_size != PAGE_SIZE) {
++ ehca_err(pd->device, "page size not supported, "
++ "region->page_size=%x", region->page_size);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_user_mr_exit0;
++ }
++
++ if ((region->length == 0) ||
++ ((region->virt_base + region->length) < region->virt_base)) {
++ ehca_err(pd->device, "bad input values: length=%lx "
++ "virt_base=%lx", region->length, region->virt_base);
++ ib_mr = ERR_PTR(-EINVAL);
++ goto reg_user_mr_exit0;
++ }
++
++ e_mr = ehca_mr_new();
++ if (!e_mr) {
++ ehca_err(pd->device, "out of memory");
++ ib_mr = ERR_PTR(-ENOMEM);
++ goto reg_user_mr_exit0;
++ }
++
++ /* determine number of MR pages */
++ num_pages_mr = (((region->virt_base % PAGE_SIZE) + region->length +
++ PAGE_SIZE - 1) / PAGE_SIZE);
++ num_pages_4k = (((region->virt_base % EHCA_PAGESIZE) + region->length +
++ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
++
++ /* register MR on HCA */
++ pginfo.type = EHCA_MR_PGI_USER;
++ pginfo.num_pages = num_pages_mr;
++ pginfo.num_4k = num_pages_4k;
++ pginfo.region = region;
++ pginfo.next_4k = region->offset / EHCA_PAGESIZE;
++ pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
++ (®ion->chunk_list),
++ list);
++
++ ret = ehca_reg_mr(shca, e_mr, (u64*)region->virt_base,
++ region->length, mr_access_flags, e_pd, &pginfo,
++ &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
++ if (ret) {
++ ib_mr = ERR_PTR(ret);
++ goto reg_user_mr_exit1;
++ }
++
++ /* successful registration of all pages */
++ return &e_mr->ib.ib_mr;
++
++reg_user_mr_exit1:
++ ehca_mr_delete(e_mr);
++reg_user_mr_exit0:
++ if (IS_ERR(ib_mr))
++ ehca_err(pd->device, "rc=%lx pd=%p region=%p mr_access_flags=%x"
++ " udata=%p",
++ PTR_ERR(ib_mr), pd, region, mr_access_flags, udata);
++ return ib_mr;
++} /* end ehca_reg_user_mr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_rereg_phys_mr(struct ib_mr *mr,
++ int mr_rereg_mask,
++ struct ib_pd *pd,
++ struct ib_phys_buf *phys_buf_array,
++ int num_phys_buf,
++ int mr_access_flags,
++ u64 *iova_start)
++{
++ int ret;
++
++ struct ehca_shca *shca =
++ container_of(mr->device, struct ehca_shca, ib_device);
++ struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
++ struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
++ u64 new_size;
++ u64 *new_start;
++ u32 new_acl;
++ struct ehca_pd *new_pd;
++ u32 tmp_lkey, tmp_rkey;
++ unsigned long sl_flags;
++ u32 num_pages_mr = 0;
++ u32 num_pages_4k = 0; /* 4k portion "pages" */
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++ u32 cur_pid = current->tgid;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ (my_pd->ownpid != cur_pid)) {
++ ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++
++ if (!(mr_rereg_mask & IB_MR_REREG_TRANS)) {
++ /* TODO not supported, because PHYP rereg hCall needs pages */
++ ehca_err(mr->device, "rereg without IB_MR_REREG_TRANS not "
++ "supported yet, mr_rereg_mask=%x", mr_rereg_mask);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++
++ if (mr_rereg_mask & IB_MR_REREG_PD) {
++ if (!pd) {
++ ehca_err(mr->device, "rereg with bad pd, pd=%p "
++ "mr_rereg_mask=%x", pd, mr_rereg_mask);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++ }
++
++ if ((mr_rereg_mask &
++ ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) ||
++ (mr_rereg_mask == 0)) {
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++
++ /* check other parameters */
++ if (e_mr == shca->maxmr) {
++ /* should be impossible, however reject to be sure */
++ ehca_err(mr->device, "rereg internal max-MR impossible, mr=%p "
++ "shca->maxmr=%p mr->lkey=%x",
++ mr, shca->maxmr, mr->lkey);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++ if (mr_rereg_mask & IB_MR_REREG_TRANS) { /* transl., i.e. addr/size */
++ if (e_mr->flags & EHCA_MR_FLAG_FMR) {
++ ehca_err(mr->device, "not supported for FMR, mr=%p "
++ "flags=%x", mr, e_mr->flags);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++ if (!phys_buf_array || num_phys_buf <= 0) {
++ ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
++ " phys_buf_array=%p num_phys_buf=%x",
++ mr_rereg_mask, phys_buf_array, num_phys_buf);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++ }
++ if ((mr_rereg_mask & IB_MR_REREG_ACCESS) && /* change ACL */
++ (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
++ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)))) {
++ /*
++ * Remote Write Access requires Local Write Access
++ * Remote Atomic Access requires Local Write Access
++ */
++ ehca_err(mr->device, "bad input values: mr_rereg_mask=%x "
++ "mr_access_flags=%x", mr_rereg_mask, mr_access_flags);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit0;
++ }
++
++ /* set requested values dependent on rereg request */
++ spin_lock_irqsave(&e_mr->mrlock, sl_flags);
++ new_start = e_mr->start; /* new == old address */
++ new_size = e_mr->size; /* new == old length */
++ new_acl = e_mr->acl; /* new == old access control */
++ new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
++
++ if (mr_rereg_mask & IB_MR_REREG_TRANS) {
++ new_start = iova_start; /* change address */
++ /* check physical buffer list and calculate size */
++ ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array,
++ num_phys_buf, iova_start,
++ &new_size);
++ if (ret)
++ goto rereg_phys_mr_exit1;
++ if ((new_size == 0) ||
++ (((u64)iova_start + new_size) < (u64)iova_start)) {
++ ehca_err(mr->device, "bad input values: new_size=%lx "
++ "iova_start=%p", new_size, iova_start);
++ ret = -EINVAL;
++ goto rereg_phys_mr_exit1;
++ }
++ num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
++ PAGE_SIZE - 1) / PAGE_SIZE);
++ num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
++ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
++ pginfo.type = EHCA_MR_PGI_PHYS;
++ pginfo.num_pages = num_pages_mr;
++ pginfo.num_4k = num_pages_4k;
++ pginfo.num_phys_buf = num_phys_buf;
++ pginfo.phys_buf_array = phys_buf_array;
++ pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
++ EHCA_PAGESIZE);
++ }
++ if (mr_rereg_mask & IB_MR_REREG_ACCESS)
++ new_acl = mr_access_flags;
++ if (mr_rereg_mask & IB_MR_REREG_PD)
++ new_pd = container_of(pd, struct ehca_pd, ib_pd);
++
++ ret = ehca_rereg_mr(shca, e_mr, new_start, new_size, new_acl,
++ new_pd, &pginfo, &tmp_lkey, &tmp_rkey);
++ if (ret)
++ goto rereg_phys_mr_exit1;
++
++ /* successful reregistration */
++ if (mr_rereg_mask & IB_MR_REREG_PD)
++ mr->pd = pd;
++ mr->lkey = tmp_lkey;
++ mr->rkey = tmp_rkey;
++
++rereg_phys_mr_exit1:
++ spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
++rereg_phys_mr_exit0:
++ if (ret)
++ ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p "
++ "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x "
++ "iova_start=%p",
++ ret, mr, mr_rereg_mask, pd, phys_buf_array,
++ num_phys_buf, mr_access_flags, iova_start);
++ return ret;
++} /* end ehca_rereg_phys_mr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
++{
++ int ret = 0;
++ u64 h_ret;
++ struct ehca_shca *shca =
++ container_of(mr->device, struct ehca_shca, ib_device);
++ struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
++ struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
++ u32 cur_pid = current->tgid;
++ unsigned long sl_flags;
++ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ (my_pd->ownpid != cur_pid)) {
++ ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ ret = -EINVAL;
++ goto query_mr_exit0;
++ }
++
++ if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
++ ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p "
++ "e_mr->flags=%x", mr, e_mr, e_mr->flags);
++ ret = -EINVAL;
++ goto query_mr_exit0;
++ }
++
++ memset(mr_attr, 0, sizeof(struct ib_mr_attr));
++ spin_lock_irqsave(&e_mr->mrlock, sl_flags);
++
++ h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p "
++ "hca_hndl=%lx mr_hndl=%lx lkey=%x",
++ h_ret, mr, shca->ipz_hca_handle.handle,
++ e_mr->ipz_mr_handle.handle, mr->lkey);
++ ret = ehca_mrmw_map_hrc_query_mr(h_ret);
++ goto query_mr_exit1;
++ }
++ mr_attr->pd = mr->pd;
++ mr_attr->device_virt_addr = hipzout.vaddr;
++ mr_attr->size = hipzout.len;
++ mr_attr->lkey = hipzout.lkey;
++ mr_attr->rkey = hipzout.rkey;
++ ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
++
++query_mr_exit1:
++ spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
++query_mr_exit0:
++ if (ret)
++ ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p",
++ ret, mr, mr_attr);
++ return ret;
++} /* end ehca_query_mr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_dereg_mr(struct ib_mr *mr)
++{
++ int ret = 0;
++ u64 h_ret;
++ struct ehca_shca *shca =
++ container_of(mr->device, struct ehca_shca, ib_device);
++ struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
++ struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
++ u32 cur_pid = current->tgid;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ (my_pd->ownpid != cur_pid)) {
++ ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ ret = -EINVAL;
++ goto dereg_mr_exit0;
++ }
++
++ if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
++ ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p "
++ "e_mr->flags=%x", mr, e_mr, e_mr->flags);
++ ret = -EINVAL;
++ goto dereg_mr_exit0;
++ } else if (e_mr == shca->maxmr) {
++ /* should be impossible, however reject to be sure */
++ ehca_err(mr->device, "dereg internal max-MR impossible, mr=%p "
++ "shca->maxmr=%p mr->lkey=%x",
++ mr, shca->maxmr, mr->lkey);
++ ret = -EINVAL;
++ goto dereg_mr_exit0;
++ }
++
++ /* TODO: BUSY: MR still has bound window(s) */
++ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p "
++ "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
++ h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
++ e_mr->ipz_mr_handle.handle, mr->lkey);
++ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
++ goto dereg_mr_exit0;
++ }
++
++ /* successful deregistration */
++ ehca_mr_delete(e_mr);
++
++dereg_mr_exit0:
++ if (ret)
++ ehca_err(mr->device, "ret=%x mr=%p", ret, mr);
++ return ret;
++} /* end ehca_dereg_mr() */
++
++/*----------------------------------------------------------------------*/
++
++struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
++{
++ struct ib_mw *ib_mw;
++ u64 h_ret;
++ struct ehca_mw *e_mw;
++ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
++ struct ehca_shca *shca =
++ container_of(pd->device, struct ehca_shca, ib_device);
++ struct ehca_mw_hipzout_parms hipzout = {{0},0};
++
++ e_mw = ehca_mw_new();
++ if (!e_mw) {
++ ib_mw = ERR_PTR(-ENOMEM);
++ goto alloc_mw_exit0;
++ }
++
++ h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
++ e_pd->fw_pd, &hipzout);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
++ "shca=%p hca_hndl=%lx mw=%p",
++ h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
++ ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
++ goto alloc_mw_exit1;
++ }
++ /* successful MW allocation */
++ e_mw->ipz_mw_handle = hipzout.handle;
++ e_mw->ib_mw.rkey = hipzout.rkey;
++ return &e_mw->ib_mw;
++
++alloc_mw_exit1:
++ ehca_mw_delete(e_mw);
++alloc_mw_exit0:
++ if (IS_ERR(ib_mw))
++ ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd);
++ return ib_mw;
++} /* end ehca_alloc_mw() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_bind_mw(struct ib_qp *qp,
++ struct ib_mw *mw,
++ struct ib_mw_bind *mw_bind)
++{
++ /* TODO: not supported up to now */
++ ehca_gen_err("bind MW currently not supported by HCAD");
++
++ return -EPERM;
++} /* end ehca_bind_mw() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_dealloc_mw(struct ib_mw *mw)
++{
++ u64 h_ret;
++ struct ehca_shca *shca =
++ container_of(mw->device, struct ehca_shca, ib_device);
++ struct ehca_mw *e_mw = container_of(mw, struct ehca_mw, ib_mw);
++
++ h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p "
++ "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
++ h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
++ e_mw->ipz_mw_handle.handle);
++ return ehca_mrmw_map_hrc_free_mw(h_ret);
++ }
++ /* successful deallocation */
++ ehca_mw_delete(e_mw);
++ return 0;
++} /* end ehca_dealloc_mw() */
++
++/*----------------------------------------------------------------------*/
++
++struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
++ int mr_access_flags,
++ struct ib_fmr_attr *fmr_attr)
++{
++ struct ib_fmr *ib_fmr;
++ struct ehca_shca *shca =
++ container_of(pd->device, struct ehca_shca, ib_device);
++ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
++ struct ehca_mr *e_fmr;
++ int ret;
++ u32 tmp_lkey, tmp_rkey;
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++
++ /* check other parameters */
++ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
++ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
++ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
++ /*
++ * Remote Write Access requires Local Write Access
++ * Remote Atomic Access requires Local Write Access
++ */
++ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
++ mr_access_flags);
++ ib_fmr = ERR_PTR(-EINVAL);
++ goto alloc_fmr_exit0;
++ }
++ if (mr_access_flags & IB_ACCESS_MW_BIND) {
++ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
++ mr_access_flags);
++ ib_fmr = ERR_PTR(-EINVAL);
++ goto alloc_fmr_exit0;
++ }
++ if ((fmr_attr->max_pages == 0) || (fmr_attr->max_maps == 0)) {
++ ehca_err(pd->device, "bad input values: fmr_attr->max_pages=%x "
++ "fmr_attr->max_maps=%x fmr_attr->page_shift=%x",
++ fmr_attr->max_pages, fmr_attr->max_maps,
++ fmr_attr->page_shift);
++ ib_fmr = ERR_PTR(-EINVAL);
++ goto alloc_fmr_exit0;
++ }
++ if (((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) &&
++ ((1 << fmr_attr->page_shift) != PAGE_SIZE)) {
++ ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
++ fmr_attr->page_shift);
++ ib_fmr = ERR_PTR(-EINVAL);
++ goto alloc_fmr_exit0;
++ }
++
++ e_fmr = ehca_mr_new();
++ if (!e_fmr) {
++ ib_fmr = ERR_PTR(-ENOMEM);
++ goto alloc_fmr_exit0;
++ }
++ e_fmr->flags |= EHCA_MR_FLAG_FMR;
++
++ /* register MR on HCA */
++ ret = ehca_reg_mr(shca, e_fmr, NULL,
++ fmr_attr->max_pages * (1 << fmr_attr->page_shift),
++ mr_access_flags, e_pd, &pginfo,
++ &tmp_lkey, &tmp_rkey);
++ if (ret) {
++ ib_fmr = ERR_PTR(ret);
++ goto alloc_fmr_exit1;
++ }
++
++ /* successful */
++ e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
++ e_fmr->fmr_max_pages = fmr_attr->max_pages;
++ e_fmr->fmr_max_maps = fmr_attr->max_maps;
++ e_fmr->fmr_map_cnt = 0;
++ return &e_fmr->ib.ib_fmr;
++
++alloc_fmr_exit1:
++ ehca_mr_delete(e_fmr);
++alloc_fmr_exit0:
++ if (IS_ERR(ib_fmr))
++ ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x "
++ "fmr_attr=%p", PTR_ERR(ib_fmr), pd,
++ mr_access_flags, fmr_attr);
++ return ib_fmr;
++} /* end ehca_alloc_fmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_map_phys_fmr(struct ib_fmr *fmr,
++ u64 *page_list,
++ int list_len,
++ u64 iova)
++{
++ int ret;
++ struct ehca_shca *shca =
++ container_of(fmr->device, struct ehca_shca, ib_device);
++ struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
++ struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++ u32 tmp_lkey, tmp_rkey;
++
++ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
++ ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x",
++ e_fmr, e_fmr->flags);
++ ret = -EINVAL;
++ goto map_phys_fmr_exit0;
++ }
++ ret = ehca_fmr_check_page_list(e_fmr, page_list, list_len);
++ if (ret)
++ goto map_phys_fmr_exit0;
++ if (iova % e_fmr->fmr_page_size) {
++ /* only whole-numbered pages */
++ ehca_err(fmr->device, "bad iova, iova=%lx fmr_page_size=%x",
++ iova, e_fmr->fmr_page_size);
++ ret = -EINVAL;
++ goto map_phys_fmr_exit0;
++ }
++ if (e_fmr->fmr_map_cnt >= e_fmr->fmr_max_maps) {
++ /* HCAD does not limit the maps, however trace this anyway */
++ ehca_info(fmr->device, "map limit exceeded, fmr=%p "
++ "e_fmr->fmr_map_cnt=%x e_fmr->fmr_max_maps=%x",
++ fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
++ }
++
++ pginfo.type = EHCA_MR_PGI_FMR;
++ pginfo.num_pages = list_len;
++ pginfo.num_4k = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
++ pginfo.page_list = page_list;
++ pginfo.next_4k = ((iova & (e_fmr->fmr_page_size-1)) /
++ EHCA_PAGESIZE);
++
++ ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
++ list_len * e_fmr->fmr_page_size,
++ e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
++ if (ret)
++ goto map_phys_fmr_exit0;
++
++ /* successful reregistration */
++ e_fmr->fmr_map_cnt++;
++ e_fmr->ib.ib_fmr.lkey = tmp_lkey;
++ e_fmr->ib.ib_fmr.rkey = tmp_rkey;
++ return 0;
++
++map_phys_fmr_exit0:
++ if (ret)
++ ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
++ "iova=%lx",
++ ret, fmr, page_list, list_len, iova);
++ return ret;
++} /* end ehca_map_phys_fmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_unmap_fmr(struct list_head *fmr_list)
++{
++ int ret = 0;
++ struct ib_fmr *ib_fmr;
++ struct ehca_shca *shca = NULL;
++ struct ehca_shca *prev_shca;
++ struct ehca_mr *e_fmr;
++ u32 num_fmr = 0;
++ u32 unmap_fmr_cnt = 0;
++
++ /* check all FMR belong to same SHCA, and check internal flag */
++ list_for_each_entry(ib_fmr, fmr_list, list) {
++ prev_shca = shca;
++ if (!ib_fmr) {
++ ehca_gen_err("bad fmr=%p in list", ib_fmr);
++ ret = -EINVAL;
++ goto unmap_fmr_exit0;
++ }
++ shca = container_of(ib_fmr->device, struct ehca_shca,
++ ib_device);
++ e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
++ if ((shca != prev_shca) && prev_shca) {
++ ehca_err(&shca->ib_device, "SHCA mismatch, shca=%p "
++ "prev_shca=%p e_fmr=%p",
++ shca, prev_shca, e_fmr);
++ ret = -EINVAL;
++ goto unmap_fmr_exit0;
++ }
++ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
++ ehca_err(&shca->ib_device, "not a FMR, e_fmr=%p "
++ "e_fmr->flags=%x", e_fmr, e_fmr->flags);
++ ret = -EINVAL;
++ goto unmap_fmr_exit0;
++ }
++ num_fmr++;
++ }
++
++ /* loop over all FMRs to unmap */
++ list_for_each_entry(ib_fmr, fmr_list, list) {
++ unmap_fmr_cnt++;
++ e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
++ shca = container_of(ib_fmr->device, struct ehca_shca,
++ ib_device);
++ ret = ehca_unmap_one_fmr(shca, e_fmr);
++ if (ret) {
++ /* unmap failed, stop unmapping of rest of FMRs */
++ ehca_err(&shca->ib_device, "unmap of one FMR failed, "
++ "stop rest, e_fmr=%p num_fmr=%x "
++ "unmap_fmr_cnt=%x lkey=%x", e_fmr, num_fmr,
++ unmap_fmr_cnt, e_fmr->ib.ib_fmr.lkey);
++ goto unmap_fmr_exit0;
++ }
++ }
++
++unmap_fmr_exit0:
++ if (ret)
++ ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
++ ret, fmr_list, num_fmr, unmap_fmr_cnt);
++ return ret;
++} /* end ehca_unmap_fmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_dealloc_fmr(struct ib_fmr *fmr)
++{
++ int ret;
++ u64 h_ret;
++ struct ehca_shca *shca =
++ container_of(fmr->device, struct ehca_shca, ib_device);
++ struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
++
++ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
++ ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x",
++ e_fmr, e_fmr->flags);
++ ret = -EINVAL;
++ goto free_fmr_exit0;
++ }
++
++ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p "
++ "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
++ h_ret, e_fmr, shca->ipz_hca_handle.handle,
++ e_fmr->ipz_mr_handle.handle, fmr->lkey);
++ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
++ goto free_fmr_exit0;
++ }
++ /* successful deregistration */
++ ehca_mr_delete(e_fmr);
++ return 0;
++
++free_fmr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr);
++ return ret;
++} /* end ehca_dealloc_fmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_reg_mr(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ u64 *iova_start,
++ u64 size,
++ int acl,
++ struct ehca_pd *e_pd,
++ struct ehca_mr_pginfo *pginfo,
++ u32 *lkey, /*OUT*/
++ u32 *rkey) /*OUT*/
++{
++ int ret;
++ u64 h_ret;
++ u32 hipz_acl;
++ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
++
++ ehca_mrmw_map_acl(acl, &hipz_acl);
++ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
++ if (ehca_use_hp_mr == 1)
++ hipz_acl |= 0x00000001;
++
++ h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
++ (u64)iova_start, size, hipz_acl,
++ e_pd->fw_pd, &hipzout);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
++ "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
++ ret = ehca_mrmw_map_hrc_alloc(h_ret);
++ goto ehca_reg_mr_exit0;
++ }
++
++ e_mr->ipz_mr_handle = hipzout.handle;
++
++ ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
++ if (ret)
++ goto ehca_reg_mr_exit1;
++
++ /* successful registration */
++ e_mr->num_pages = pginfo->num_pages;
++ e_mr->num_4k = pginfo->num_4k;
++ e_mr->start = iova_start;
++ e_mr->size = size;
++ e_mr->acl = acl;
++ *lkey = hipzout.lkey;
++ *rkey = hipzout.rkey;
++ return 0;
++
++ehca_reg_mr_exit1:
++ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
++ "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
++ "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
++ h_ret, shca, e_mr, iova_start, size, acl, e_pd,
++ hipzout.lkey, pginfo, pginfo->num_pages,
++ pginfo->num_4k, ret);
++ ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
++ "not recoverable");
++ }
++ehca_reg_mr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
++ "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
++ "num_pages=%lx num_4k=%lx",
++ ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
++ pginfo->num_pages, pginfo->num_4k);
++ return ret;
++} /* end ehca_reg_mr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_reg_mr_rpages(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ struct ehca_mr_pginfo *pginfo)
++{
++ int ret = 0;
++ u64 h_ret;
++ u32 rnum;
++ u64 rpage;
++ u32 i;
++ u64 *kpage;
++
++ kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!kpage) {
++ ehca_err(&shca->ib_device, "kpage alloc failed");
++ ret = -ENOMEM;
++ goto ehca_reg_mr_rpages_exit0;
++ }
++
++ /* max 512 pages per shot */
++ for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
++
++ if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
++ rnum = pginfo->num_4k % 512; /* last shot */
++ if (rnum == 0)
++ rnum = 512; /* last shot is full */
++ } else
++ rnum = 512;
++
++ if (rnum > 1) {
++ ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
++ if (ret) {
++ ehca_err(&shca->ib_device, "ehca_set_pagebuf "
++ "bad rc, ret=%x rnum=%x kpage=%p",
++ ret, rnum, kpage);
++ ret = -EFAULT;
++ goto ehca_reg_mr_rpages_exit1;
++ }
++ rpage = virt_to_abs(kpage);
++ if (!rpage) {
++ ehca_err(&shca->ib_device, "kpage=%p i=%x",
++ kpage, i);
++ ret = -EFAULT;
++ goto ehca_reg_mr_rpages_exit1;
++ }
++ } else { /* rnum==1 */
++ ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
++ if (ret) {
++ ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
++ "bad rc, ret=%x i=%x", ret, i);
++ ret = -EFAULT;
++ goto ehca_reg_mr_rpages_exit1;
++ }
++ }
++
++ h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
++ 0, /* pagesize 4k */
++ 0, rpage, rnum);
++
++ if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
++ /*
++ * check for 'registration complete'==H_SUCCESS
++ * and for 'page registered'==H_PAGE_REGISTERED
++ */
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "last "
++ "hipz_reg_rpage_mr failed, h_ret=%lx "
++ "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx"
++ " lkey=%x", h_ret, e_mr, i,
++ shca->ipz_hca_handle.handle,
++ e_mr->ipz_mr_handle.handle,
++ e_mr->ib.ib_mr.lkey);
++ ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
++ break;
++ } else
++ ret = 0;
++ } else if (h_ret != H_PAGE_REGISTERED) {
++ ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
++ "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx "
++ "mr_hndl=%lx", h_ret, e_mr, i,
++ e_mr->ib.ib_mr.lkey,
++ shca->ipz_hca_handle.handle,
++ e_mr->ipz_mr_handle.handle);
++ ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
++ break;
++ } else
++ ret = 0;
++ } /* end for(i) */
++
++
++ehca_reg_mr_rpages_exit1:
++ kfree(kpage);
++ehca_reg_mr_rpages_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
++ "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
++ pginfo->num_pages, pginfo->num_4k);
++ return ret;
++} /* end ehca_reg_mr_rpages() */
++
++/*----------------------------------------------------------------------*/
++
++inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ u64 *iova_start,
++ u64 size,
++ u32 acl,
++ struct ehca_pd *e_pd,
++ struct ehca_mr_pginfo *pginfo,
++ u32 *lkey, /*OUT*/
++ u32 *rkey) /*OUT*/
++{
++ int ret;
++ u64 h_ret;
++ u32 hipz_acl;
++ u64 *kpage;
++ u64 rpage;
++ struct ehca_mr_pginfo pginfo_save;
++ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
++
++ ehca_mrmw_map_acl(acl, &hipz_acl);
++ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
++
++ kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (!kpage) {
++ ehca_err(&shca->ib_device, "kpage alloc failed");
++ ret = -ENOMEM;
++ goto ehca_rereg_mr_rereg1_exit0;
++ }
++
++ pginfo_save = *pginfo;
++ ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
++ if (ret) {
++ ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
++ "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
++ e_mr, pginfo, pginfo->type, pginfo->num_pages,
++ pginfo->num_4k,kpage);
++ goto ehca_rereg_mr_rereg1_exit1;
++ }
++ rpage = virt_to_abs(kpage);
++ if (!rpage) {
++ ehca_err(&shca->ib_device, "kpage=%p", kpage);
++ ret = -EFAULT;
++ goto ehca_rereg_mr_rereg1_exit1;
++ }
++ h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_mr,
++ (u64)iova_start, size, hipz_acl,
++ e_pd->fw_pd, rpage, &hipzout);
++ if (h_ret != H_SUCCESS) {
++ /*
++ * reregistration unsuccessful, try it again with the 3 hCalls,
++ * e.g. this is required in case H_MR_CONDITION
++ * (MW bound or MR is shared)
++ */
++ ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
++ "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
++ *pginfo = pginfo_save;
++ ret = -EAGAIN;
++ } else if ((u64*)hipzout.vaddr != iova_start) {
++ ehca_err(&shca->ib_device, "PHYP changed iova_start in "
++ "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
++ "mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
++ hipzout.vaddr, e_mr, e_mr->ipz_mr_handle.handle,
++ e_mr->ib.ib_mr.lkey, hipzout.lkey);
++ ret = -EFAULT;
++ } else {
++ /*
++ * successful reregistration
++ * note: start and start_out are identical for eServer HCAs
++ */
++ e_mr->num_pages = pginfo->num_pages;
++ e_mr->num_4k = pginfo->num_4k;
++ e_mr->start = iova_start;
++ e_mr->size = size;
++ e_mr->acl = acl;
++ *lkey = hipzout.lkey;
++ *rkey = hipzout.rkey;
++ }
++
++ehca_rereg_mr_rereg1_exit1:
++ kfree(kpage);
++ehca_rereg_mr_rereg1_exit0:
++ if ( ret && (ret != -EAGAIN) )
++ ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
++ "pginfo=%p num_pages=%lx num_4k=%lx",
++ ret, *lkey, *rkey, pginfo, pginfo->num_pages,
++ pginfo->num_4k);
++ return ret;
++} /* end ehca_rereg_mr_rereg1() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_rereg_mr(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ u64 *iova_start,
++ u64 size,
++ int acl,
++ struct ehca_pd *e_pd,
++ struct ehca_mr_pginfo *pginfo,
++ u32 *lkey,
++ u32 *rkey)
++{
++ int ret = 0;
++ u64 h_ret;
++ int rereg_1_hcall = 1; /* 1: use hipz_h_reregister_pmr directly */
++ int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
++
++ /* first determine reregistration hCall(s) */
++ if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
++ (pginfo->num_4k > e_mr->num_4k)) {
++ ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
++ "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
++ rereg_1_hcall = 0;
++ rereg_3_hcall = 1;
++ }
++
++ if (e_mr->flags & EHCA_MR_FLAG_MAXMR) { /* check for max-MR */
++ rereg_1_hcall = 0;
++ rereg_3_hcall = 1;
++ e_mr->flags &= ~EHCA_MR_FLAG_MAXMR;
++ ehca_err(&shca->ib_device, "Rereg MR for max-MR! e_mr=%p",
++ e_mr);
++ }
++
++ if (rereg_1_hcall) {
++ ret = ehca_rereg_mr_rereg1(shca, e_mr, iova_start, size,
++ acl, e_pd, pginfo, lkey, rkey);
++ if (ret) {
++ if (ret == -EAGAIN)
++ rereg_3_hcall = 1;
++ else
++ goto ehca_rereg_mr_exit0;
++ }
++ }
++
++ if (rereg_3_hcall) {
++ struct ehca_mr save_mr;
++
++ /* first deregister old MR */
++ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "hipz_free_mr failed, "
++ "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx "
++ "mr->lkey=%x",
++ h_ret, e_mr, shca->ipz_hca_handle.handle,
++ e_mr->ipz_mr_handle.handle,
++ e_mr->ib.ib_mr.lkey);
++ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
++ goto ehca_rereg_mr_exit0;
++ }
++ /* clean ehca_mr_t, without changing struct ib_mr and lock */
++ save_mr = *e_mr;
++ ehca_mr_deletenew(e_mr);
++
++ /* set some MR values */
++ e_mr->flags = save_mr.flags;
++ e_mr->fmr_page_size = save_mr.fmr_page_size;
++ e_mr->fmr_max_pages = save_mr.fmr_max_pages;
++ e_mr->fmr_max_maps = save_mr.fmr_max_maps;
++ e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
++
++ ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
++ e_pd, pginfo, lkey, rkey);
++ if (ret) {
++ u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
++ memcpy(&e_mr->flags, &(save_mr.flags),
++ sizeof(struct ehca_mr) - offset);
++ goto ehca_rereg_mr_exit0;
++ }
++ }
++
++ehca_rereg_mr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
++ "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
++ "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
++ "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
++ acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
++ rereg_1_hcall, rereg_3_hcall);
++ return ret;
++} /* end ehca_rereg_mr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_unmap_one_fmr(struct ehca_shca *shca,
++ struct ehca_mr *e_fmr)
++{
++ int ret = 0;
++ u64 h_ret;
++ int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
++ int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
++ struct ehca_pd *e_pd =
++ container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
++ struct ehca_mr save_fmr;
++ u32 tmp_lkey, tmp_rkey;
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
++
++ /* first check if reregistration hCall can be used for unmap */
++ if (e_fmr->fmr_max_pages > 512) {
++ rereg_1_hcall = 0;
++ rereg_3_hcall = 1;
++ }
++
++ if (rereg_1_hcall) {
++ /*
++ * note: after using rereg hcall with len=0,
++ * rereg hcall must be used again for registering pages
++ */
++ h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
++ 0, 0, e_pd->fw_pd, 0, &hipzout);
++ if (h_ret != H_SUCCESS) {
++ /*
++ * should not happen, because length checked above,
++ * FMRs are not shared and no MW bound to FMRs
++ */
++ ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
++ "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
++ "mr_hndl=%lx lkey=%x lkey_out=%x",
++ h_ret, e_fmr, shca->ipz_hca_handle.handle,
++ e_fmr->ipz_mr_handle.handle,
++ e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
++ rereg_3_hcall = 1;
++ } else {
++ /* successful reregistration */
++ e_fmr->start = NULL;
++ e_fmr->size = 0;
++ tmp_lkey = hipzout.lkey;
++ tmp_rkey = hipzout.rkey;
++ }
++ }
++
++ if (rereg_3_hcall) {
++ struct ehca_mr save_mr;
++
++ /* first free old FMR */
++ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "hipz_free_mr failed, "
++ "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
++ "lkey=%x",
++ h_ret, e_fmr, shca->ipz_hca_handle.handle,
++ e_fmr->ipz_mr_handle.handle,
++ e_fmr->ib.ib_fmr.lkey);
++ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
++ goto ehca_unmap_one_fmr_exit0;
++ }
++ /* clean ehca_mr_t, without changing lock */
++ save_fmr = *e_fmr;
++ ehca_mr_deletenew(e_fmr);
++
++ /* set some MR values */
++ e_fmr->flags = save_fmr.flags;
++ e_fmr->fmr_page_size = save_fmr.fmr_page_size;
++ e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
++ e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
++ e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
++ e_fmr->acl = save_fmr.acl;
++
++ pginfo.type = EHCA_MR_PGI_FMR;
++ pginfo.num_pages = 0;
++ pginfo.num_4k = 0;
++ ret = ehca_reg_mr(shca, e_fmr, NULL,
++ (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
++ e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
++ &tmp_rkey);
++ if (ret) {
++ u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
++ memcpy(&e_fmr->flags, &(save_mr.flags),
++ sizeof(struct ehca_mr) - offset);
++ goto ehca_unmap_one_fmr_exit0;
++ }
++ }
++
++ehca_unmap_one_fmr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
++ "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
++ ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
++ rereg_1_hcall, rereg_3_hcall);
++ return ret;
++} /* end ehca_unmap_one_fmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_reg_smr(struct ehca_shca *shca,
++ struct ehca_mr *e_origmr,
++ struct ehca_mr *e_newmr,
++ u64 *iova_start,
++ int acl,
++ struct ehca_pd *e_pd,
++ u32 *lkey, /*OUT*/
++ u32 *rkey) /*OUT*/
++{
++ int ret = 0;
++ u64 h_ret;
++ u32 hipz_acl;
++ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
++
++ ehca_mrmw_map_acl(acl, &hipz_acl);
++ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
++
++ h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
++ (u64)iova_start, hipz_acl, e_pd->fw_pd,
++ &hipzout);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
++ "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
++ "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
++ h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
++ shca->ipz_hca_handle.handle,
++ e_origmr->ipz_mr_handle.handle,
++ e_origmr->ib.ib_mr.lkey);
++ ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
++ goto ehca_reg_smr_exit0;
++ }
++ /* successful registration */
++ e_newmr->num_pages = e_origmr->num_pages;
++ e_newmr->num_4k = e_origmr->num_4k;
++ e_newmr->start = iova_start;
++ e_newmr->size = e_origmr->size;
++ e_newmr->acl = acl;
++ e_newmr->ipz_mr_handle = hipzout.handle;
++ *lkey = hipzout.lkey;
++ *rkey = hipzout.rkey;
++ return 0;
++
++ehca_reg_smr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p "
++ "e_newmr=%p iova_start=%p acl=%x e_pd=%p",
++ ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd);
++ return ret;
++} /* end ehca_reg_smr() */
++
++/*----------------------------------------------------------------------*/
++
++/* register internal max-MR to internal SHCA */
++int ehca_reg_internal_maxmr(
++ struct ehca_shca *shca,
++ struct ehca_pd *e_pd,
++ struct ehca_mr **e_maxmr) /*OUT*/
++{
++ int ret;
++ struct ehca_mr *e_mr;
++ u64 *iova_start;
++ u64 size_maxmr;
++ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
++ struct ib_phys_buf ib_pbuf;
++ u32 num_pages_mr;
++ u32 num_pages_4k; /* 4k portion "pages" */
++
++ e_mr = ehca_mr_new();
++ if (!e_mr) {
++ ehca_err(&shca->ib_device, "out of memory");
++ ret = -ENOMEM;
++ goto ehca_reg_internal_maxmr_exit0;
++ }
++ e_mr->flags |= EHCA_MR_FLAG_MAXMR;
++
++ /* register internal max-MR on HCA */
++ size_maxmr = (u64)high_memory - PAGE_OFFSET;
++ iova_start = (u64*)KERNELBASE;
++ ib_pbuf.addr = 0;
++ ib_pbuf.size = size_maxmr;
++ num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
++ PAGE_SIZE - 1) / PAGE_SIZE);
++ num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
++ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
++
++ pginfo.type = EHCA_MR_PGI_PHYS;
++ pginfo.num_pages = num_pages_mr;
++ pginfo.num_4k = num_pages_4k;
++ pginfo.num_phys_buf = 1;
++ pginfo.phys_buf_array = &ib_pbuf;
++
++ ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
++ &pginfo, &e_mr->ib.ib_mr.lkey,
++ &e_mr->ib.ib_mr.rkey);
++ if (ret) {
++ ehca_err(&shca->ib_device, "reg of internal max MR failed, "
++ "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
++ "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
++ num_pages_mr, num_pages_4k);
++ goto ehca_reg_internal_maxmr_exit1;
++ }
++
++ /* successful registration of all pages */
++ e_mr->ib.ib_mr.device = e_pd->ib_pd.device;
++ e_mr->ib.ib_mr.pd = &e_pd->ib_pd;
++ e_mr->ib.ib_mr.uobject = NULL;
++ atomic_inc(&(e_pd->ib_pd.usecnt));
++ atomic_set(&(e_mr->ib.ib_mr.usecnt), 0);
++ *e_maxmr = e_mr;
++ return 0;
++
++ehca_reg_internal_maxmr_exit1:
++ ehca_mr_delete(e_mr);
++ehca_reg_internal_maxmr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p",
++ ret, shca, e_pd, e_maxmr);
++ return ret;
++} /* end ehca_reg_internal_maxmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_reg_maxmr(struct ehca_shca *shca,
++ struct ehca_mr *e_newmr,
++ u64 *iova_start,
++ int acl,
++ struct ehca_pd *e_pd,
++ u32 *lkey,
++ u32 *rkey)
++{
++ u64 h_ret;
++ struct ehca_mr *e_origmr = shca->maxmr;
++ u32 hipz_acl;
++ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
++
++ ehca_mrmw_map_acl(acl, &hipz_acl);
++ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
++
++ h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
++ (u64)iova_start, hipz_acl, e_pd->fw_pd,
++ &hipzout);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
++ "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
++ h_ret, e_origmr, shca->ipz_hca_handle.handle,
++ e_origmr->ipz_mr_handle.handle,
++ e_origmr->ib.ib_mr.lkey);
++ return ehca_mrmw_map_hrc_reg_smr(h_ret);
++ }
++ /* successful registration */
++ e_newmr->num_pages = e_origmr->num_pages;
++ e_newmr->num_4k = e_origmr->num_4k;
++ e_newmr->start = iova_start;
++ e_newmr->size = e_origmr->size;
++ e_newmr->acl = acl;
++ e_newmr->ipz_mr_handle = hipzout.handle;
++ *lkey = hipzout.lkey;
++ *rkey = hipzout.rkey;
++ return 0;
++} /* end ehca_reg_maxmr() */
++
++/*----------------------------------------------------------------------*/
++
++int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
++{
++ int ret;
++ struct ehca_mr *e_maxmr;
++ struct ib_pd *ib_pd;
++
++ if (!shca->maxmr) {
++ ehca_err(&shca->ib_device, "bad call, shca=%p", shca);
++ ret = -EINVAL;
++ goto ehca_dereg_internal_maxmr_exit0;
++ }
++
++ e_maxmr = shca->maxmr;
++ ib_pd = e_maxmr->ib.ib_mr.pd;
++ shca->maxmr = NULL; /* remove internal max-MR indication from SHCA */
++
++ ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
++ if (ret) {
++ ehca_err(&shca->ib_device, "dereg internal max-MR failed, "
++ "ret=%x e_maxmr=%p shca=%p lkey=%x",
++ ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
++ shca->maxmr = e_maxmr;
++ goto ehca_dereg_internal_maxmr_exit0;
++ }
++
++ atomic_dec(&ib_pd->usecnt);
++
++ehca_dereg_internal_maxmr_exit0:
++ if (ret)
++ ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p",
++ ret, shca, shca->maxmr);
++ return ret;
++} /* end ehca_dereg_internal_maxmr() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * check physical buffer array of MR verbs for validness and
++ * calculates MR size
++ */
++int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
++ int num_phys_buf,
++ u64 *iova_start,
++ u64 *size)
++{
++ struct ib_phys_buf *pbuf = phys_buf_array;
++ u64 size_count = 0;
++ u32 i;
++
++ if (num_phys_buf == 0) {
++ ehca_gen_err("bad phys buf array len, num_phys_buf=0");
++ return -EINVAL;
++ }
++ /* check first buffer */
++ if (((u64)iova_start & ~PAGE_MASK) != (pbuf->addr & ~PAGE_MASK)) {
++ ehca_gen_err("iova_start/addr mismatch, iova_start=%p "
++ "pbuf->addr=%lx pbuf->size=%lx",
++ iova_start, pbuf->addr, pbuf->size);
++ return -EINVAL;
++ }
++ if (((pbuf->addr + pbuf->size) % PAGE_SIZE) &&
++ (num_phys_buf > 1)) {
++ ehca_gen_err("addr/size mismatch in 1st buf, pbuf->addr=%lx "
++ "pbuf->size=%lx", pbuf->addr, pbuf->size);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < num_phys_buf; i++) {
++ if ((i > 0) && (pbuf->addr % PAGE_SIZE)) {
++ ehca_gen_err("bad address, i=%x pbuf->addr=%lx "
++ "pbuf->size=%lx",
++ i, pbuf->addr, pbuf->size);
++ return -EINVAL;
++ }
++ if (((i > 0) && /* not 1st */
++ (i < (num_phys_buf - 1)) && /* not last */
++ (pbuf->size % PAGE_SIZE)) || (pbuf->size == 0)) {
++ ehca_gen_err("bad size, i=%x pbuf->size=%lx",
++ i, pbuf->size);
++ return -EINVAL;
++ }
++ size_count += pbuf->size;
++ pbuf++;
++ }
++
++ *size = size_count;
++ return 0;
++} /* end ehca_mr_chk_buf_and_calc_size() */
++
++/*----------------------------------------------------------------------*/
++
++/* check page list of map FMR verb for validness */
++int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
++ u64 *page_list,
++ int list_len)
++{
++ u32 i;
++ u64 *page;
++
++ if ((list_len == 0) || (list_len > e_fmr->fmr_max_pages)) {
++ ehca_gen_err("bad list_len, list_len=%x "
++ "e_fmr->fmr_max_pages=%x fmr=%p",
++ list_len, e_fmr->fmr_max_pages, e_fmr);
++ return -EINVAL;
++ }
++
++ /* each page must be aligned */
++ page = page_list;
++ for (i = 0; i < list_len; i++) {
++ if (*page % e_fmr->fmr_page_size) {
++ ehca_gen_err("bad page, i=%x *page=%lx page=%p fmr=%p "
++ "fmr_page_size=%x", i, *page, page, e_fmr,
++ e_fmr->fmr_page_size);
++ return -EINVAL;
++ }
++ page++;
++ }
++
++ return 0;
++} /* end ehca_fmr_check_page_list() */
++
++/*----------------------------------------------------------------------*/
++
++/* setup page buffer from page info */
++int ehca_set_pagebuf(struct ehca_mr *e_mr,
++ struct ehca_mr_pginfo *pginfo,
++ u32 number,
++ u64 *kpage)
++{
++ int ret = 0;
++ struct ib_umem_chunk *prev_chunk;
++ struct ib_umem_chunk *chunk;
++ struct ib_phys_buf *pbuf;
++ u64 *fmrlist;
++ u64 num4k, pgaddr, offs4k;
++ u32 i = 0;
++ u32 j = 0;
++
++ if (pginfo->type == EHCA_MR_PGI_PHYS) {
++ /* loop over desired phys_buf_array entries */
++ while (i < number) {
++ pbuf = pginfo->phys_buf_array + pginfo->next_buf;
++ num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
++ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
++ offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
++ while (pginfo->next_4k < offs4k + num4k) {
++ /* sanity check */
++ if ((pginfo->page_cnt >= pginfo->num_pages) ||
++ (pginfo->page_4k_cnt >= pginfo->num_4k)) {
++ ehca_gen_err("page_cnt >= num_pages, "
++ "page_cnt=%lx "
++ "num_pages=%lx "
++ "page_4k_cnt=%lx "
++ "num_4k=%lx i=%x",
++ pginfo->page_cnt,
++ pginfo->num_pages,
++ pginfo->page_4k_cnt,
++ pginfo->num_4k, i);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_exit0;
++ }
++ *kpage = phys_to_abs(
++ (pbuf->addr & EHCA_PAGEMASK)
++ + (pginfo->next_4k * EHCA_PAGESIZE));
++ if ( !(*kpage) && pbuf->addr ) {
++ ehca_gen_err("pbuf->addr=%lx "
++ "pbuf->size=%lx "
++ "next_4k=%lx", pbuf->addr,
++ pbuf->size,
++ pginfo->next_4k);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_exit0;
++ }
++ (pginfo->page_4k_cnt)++;
++ (pginfo->next_4k)++;
++ if (pginfo->next_4k %
++ (PAGE_SIZE / EHCA_PAGESIZE) == 0)
++ (pginfo->page_cnt)++;
++ kpage++;
++ i++;
++ if (i >= number) break;
++ }
++ if (pginfo->next_4k >= offs4k + num4k) {
++ (pginfo->next_buf)++;
++ pginfo->next_4k = 0;
++ }
++ }
++ } else if (pginfo->type == EHCA_MR_PGI_USER) {
++ /* loop over desired chunk entries */
++ chunk = pginfo->next_chunk;
++ prev_chunk = pginfo->next_chunk;
++ list_for_each_entry_continue(chunk,
++ (&(pginfo->region->chunk_list)),
++ list) {
++ for (i = pginfo->next_nmap; i < chunk->nmap; ) {
++ pgaddr = ( page_to_pfn(chunk->page_list[i].page)
++ << PAGE_SHIFT );
++ *kpage = phys_to_abs(pgaddr +
++ (pginfo->next_4k *
++ EHCA_PAGESIZE));
++ if ( !(*kpage) ) {
++ ehca_gen_err("pgaddr=%lx "
++ "chunk->page_list[i]=%lx "
++ "i=%x next_4k=%lx mr=%p",
++ pgaddr,
++ (u64)sg_dma_address(
++ &chunk->
++ page_list[i]),
++ i, pginfo->next_4k, e_mr);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_exit0;
++ }
++ (pginfo->page_4k_cnt)++;
++ (pginfo->next_4k)++;
++ kpage++;
++ if (pginfo->next_4k %
++ (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
++ (pginfo->page_cnt)++;
++ (pginfo->next_nmap)++;
++ pginfo->next_4k = 0;
++ i++;
++ }
++ j++;
++ if (j >= number) break;
++ }
++ if ((pginfo->next_nmap >= chunk->nmap) &&
++ (j >= number)) {
++ pginfo->next_nmap = 0;
++ prev_chunk = chunk;
++ break;
++ } else if (pginfo->next_nmap >= chunk->nmap) {
++ pginfo->next_nmap = 0;
++ prev_chunk = chunk;
++ } else if (j >= number)
++ break;
++ else
++ prev_chunk = chunk;
++ }
++ pginfo->next_chunk =
++ list_prepare_entry(prev_chunk,
++ (&(pginfo->region->chunk_list)),
++ list);
++ } else if (pginfo->type == EHCA_MR_PGI_FMR) {
++ /* loop over desired page_list entries */
++ fmrlist = pginfo->page_list + pginfo->next_listelem;
++ for (i = 0; i < number; i++) {
++ *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
++ pginfo->next_4k * EHCA_PAGESIZE);
++ if ( !(*kpage) ) {
++ ehca_gen_err("*fmrlist=%lx fmrlist=%p "
++ "next_listelem=%lx next_4k=%lx",
++ *fmrlist, fmrlist,
++ pginfo->next_listelem,
++ pginfo->next_4k);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_exit0;
++ }
++ (pginfo->page_4k_cnt)++;
++ (pginfo->next_4k)++;
++ kpage++;
++ if (pginfo->next_4k %
++ (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
++ (pginfo->page_cnt)++;
++ (pginfo->next_listelem)++;
++ fmrlist++;
++ pginfo->next_4k = 0;
++ }
++ }
++ } else {
++ ehca_gen_err("bad pginfo->type=%x", pginfo->type);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_exit0;
++ }
++
++ehca_set_pagebuf_exit0:
++ if (ret)
++ ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
++ "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
++ "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
++ "next_listelem=%lx region=%p next_chunk=%p "
++ "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
++ pginfo->num_pages, pginfo->num_4k,
++ pginfo->next_buf, pginfo->next_4k, number, kpage,
++ pginfo->page_cnt, pginfo->page_4k_cnt, i,
++ pginfo->next_listelem, pginfo->region,
++ pginfo->next_chunk, pginfo->next_nmap);
++ return ret;
++} /* end ehca_set_pagebuf() */
++
++/*----------------------------------------------------------------------*/
++
++/* setup 1 page from page info page buffer */
++int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
++ struct ehca_mr_pginfo *pginfo,
++ u64 *rpage)
++{
++ int ret = 0;
++ struct ib_phys_buf *tmp_pbuf;
++ u64 *fmrlist;
++ struct ib_umem_chunk *chunk;
++ struct ib_umem_chunk *prev_chunk;
++ u64 pgaddr, num4k, offs4k;
++
++ if (pginfo->type == EHCA_MR_PGI_PHYS) {
++ /* sanity check */
++ if ((pginfo->page_cnt >= pginfo->num_pages) ||
++ (pginfo->page_4k_cnt >= pginfo->num_4k)) {
++ ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
++ "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
++ pginfo->page_cnt, pginfo->num_pages,
++ pginfo->page_4k_cnt, pginfo->num_4k);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_1_exit0;
++ }
++ tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
++ num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
++ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
++ offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
++ *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
++ (pginfo->next_4k * EHCA_PAGESIZE));
++ if ( !(*rpage) && tmp_pbuf->addr ) {
++ ehca_gen_err("tmp_pbuf->addr=%lx"
++ " tmp_pbuf->size=%lx next_4k=%lx",
++ tmp_pbuf->addr, tmp_pbuf->size,
++ pginfo->next_4k);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_1_exit0;
++ }
++ (pginfo->page_4k_cnt)++;
++ (pginfo->next_4k)++;
++ if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
++ (pginfo->page_cnt)++;
++ if (pginfo->next_4k >= offs4k + num4k) {
++ (pginfo->next_buf)++;
++ pginfo->next_4k = 0;
++ }
++ } else if (pginfo->type == EHCA_MR_PGI_USER) {
++ chunk = pginfo->next_chunk;
++ prev_chunk = pginfo->next_chunk;
++ list_for_each_entry_continue(chunk,
++ (&(pginfo->region->chunk_list)),
++ list) {
++ pgaddr = ( page_to_pfn(chunk->page_list[
++ pginfo->next_nmap].page)
++ << PAGE_SHIFT);
++ *rpage = phys_to_abs(pgaddr +
++ (pginfo->next_4k * EHCA_PAGESIZE));
++ if ( !(*rpage) ) {
++ ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
++ " next_nmap=%lx next_4k=%lx mr=%p",
++ pgaddr, (u64)sg_dma_address(
++ &chunk->page_list[
++ pginfo->
++ next_nmap]),
++ pginfo->next_nmap, pginfo->next_4k,
++ e_mr);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_1_exit0;
++ }
++ (pginfo->page_4k_cnt)++;
++ (pginfo->next_4k)++;
++ if (pginfo->next_4k %
++ (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
++ (pginfo->page_cnt)++;
++ (pginfo->next_nmap)++;
++ pginfo->next_4k = 0;
++ }
++ if (pginfo->next_nmap >= chunk->nmap) {
++ pginfo->next_nmap = 0;
++ prev_chunk = chunk;
++ }
++ break;
++ }
++ pginfo->next_chunk =
++ list_prepare_entry(prev_chunk,
++ (&(pginfo->region->chunk_list)),
++ list);
++ } else if (pginfo->type == EHCA_MR_PGI_FMR) {
++ fmrlist = pginfo->page_list + pginfo->next_listelem;
++ *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
++ pginfo->next_4k * EHCA_PAGESIZE);
++ if ( !(*rpage) ) {
++ ehca_gen_err("*fmrlist=%lx fmrlist=%p "
++ "next_listelem=%lx next_4k=%lx",
++ *fmrlist, fmrlist, pginfo->next_listelem,
++ pginfo->next_4k);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_1_exit0;
++ }
++ (pginfo->page_4k_cnt)++;
++ (pginfo->next_4k)++;
++ if (pginfo->next_4k %
++ (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
++ (pginfo->page_cnt)++;
++ (pginfo->next_listelem)++;
++ pginfo->next_4k = 0;
++ }
++ } else {
++ ehca_gen_err("bad pginfo->type=%x", pginfo->type);
++ ret = -EFAULT;
++ goto ehca_set_pagebuf_1_exit0;
++ }
++
++ehca_set_pagebuf_1_exit0:
++ if (ret)
++ ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
++ "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
++ "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
++ "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
++ pginfo, pginfo->type, pginfo->num_pages,
++ pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
++ rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
++ pginfo->next_listelem, pginfo->region,
++ pginfo->next_chunk, pginfo->next_nmap);
++ return ret;
++} /* end ehca_set_pagebuf_1() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * check MR if it is a max-MR, i.e. uses whole memory
++ * in case it's a max-MR 1 is returned, else 0
++ */
++int ehca_mr_is_maxmr(u64 size,
++ u64 *iova_start)
++{
++ /* a MR is treated as max-MR only if it fits following: */
++ if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
++ (iova_start == (void*)KERNELBASE)) {
++ ehca_gen_dbg("this is a max-MR");
++ return 1;
++ } else
++ return 0;
++} /* end ehca_mr_is_maxmr() */
++
++/*----------------------------------------------------------------------*/
++
++/* map access control for MR/MW. This routine is used for MR and MW. */
++void ehca_mrmw_map_acl(int ib_acl,
++ u32 *hipz_acl)
++{
++ *hipz_acl = 0;
++ if (ib_acl & IB_ACCESS_REMOTE_READ)
++ *hipz_acl |= HIPZ_ACCESSCTRL_R_READ;
++ if (ib_acl & IB_ACCESS_REMOTE_WRITE)
++ *hipz_acl |= HIPZ_ACCESSCTRL_R_WRITE;
++ if (ib_acl & IB_ACCESS_REMOTE_ATOMIC)
++ *hipz_acl |= HIPZ_ACCESSCTRL_R_ATOMIC;
++ if (ib_acl & IB_ACCESS_LOCAL_WRITE)
++ *hipz_acl |= HIPZ_ACCESSCTRL_L_WRITE;
++ if (ib_acl & IB_ACCESS_MW_BIND)
++ *hipz_acl |= HIPZ_ACCESSCTRL_MW_BIND;
++} /* end ehca_mrmw_map_acl() */
++
++/*----------------------------------------------------------------------*/
++
++/* sets page size in hipz access control for MR/MW. */
++void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/
++{
++ return; /* HCA supports only 4k */
++} /* end ehca_mrmw_set_pgsize_hipz_acl() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * reverse map access control for MR/MW.
++ * This routine is used for MR and MW.
++ */
++void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
++ int *ib_acl) /*OUT*/
++{
++ *ib_acl = 0;
++ if (*hipz_acl & HIPZ_ACCESSCTRL_R_READ)
++ *ib_acl |= IB_ACCESS_REMOTE_READ;
++ if (*hipz_acl & HIPZ_ACCESSCTRL_R_WRITE)
++ *ib_acl |= IB_ACCESS_REMOTE_WRITE;
++ if (*hipz_acl & HIPZ_ACCESSCTRL_R_ATOMIC)
++ *ib_acl |= IB_ACCESS_REMOTE_ATOMIC;
++ if (*hipz_acl & HIPZ_ACCESSCTRL_L_WRITE)
++ *ib_acl |= IB_ACCESS_LOCAL_WRITE;
++ if (*hipz_acl & HIPZ_ACCESSCTRL_MW_BIND)
++ *ib_acl |= IB_ACCESS_MW_BIND;
++} /* end ehca_mrmw_reverse_map_acl() */
++
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * map HIPZ rc to IB retcodes for MR/MW allocations
++ * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
++ */
++int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_SUCCESS: /* successful completion */
++ return 0;
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RT_PARM: /* invalid resource type */
++ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
++ case H_MLENGTH_PARM: /* invalid memory length */
++ case H_MEM_ACCESS_PARM: /* invalid access controls */
++ case H_CONSTRAINED: /* resource constraint */
++ return -EINVAL;
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_alloc() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * map HIPZ rc to IB retcodes for MR register rpage
++ * Used for hipz_h_register_rpage_mr at registering last page
++ */
++int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_SUCCESS: /* registration complete */
++ return 0;
++ case H_PAGE_REGISTERED: /* page registered */
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RH_PARM: /* invalid resource handle */
++/* case H_QT_PARM: invalid queue type */
++ case H_PARAMETER: /*
++ * invalid logical address,
++ * or count zero or greater 512
++ */
++ case H_TABLE_FULL: /* page table full */
++ case H_HARDWARE: /* HCA not operational */
++ return -EINVAL;
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_rrpg_last() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * map HIPZ rc to IB retcodes for MR register rpage
++ * Used for hipz_h_register_rpage_mr at registering one page, but not last page
++ */
++int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_PAGE_REGISTERED: /* page registered */
++ return 0;
++ case H_SUCCESS: /* registration complete */
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RH_PARM: /* invalid resource handle */
++/* case H_QT_PARM: invalid queue type */
++ case H_PARAMETER: /*
++ * invalid logical address,
++ * or count zero or greater 512
++ */
++ case H_TABLE_FULL: /* page table full */
++ case H_HARDWARE: /* HCA not operational */
++ return -EINVAL;
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
++
++/*----------------------------------------------------------------------*/
++
++/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
++int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_SUCCESS: /* successful completion */
++ return 0;
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RH_PARM: /* invalid resource handle */
++ return -EINVAL;
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_query_mr() */
++
++/*----------------------------------------------------------------------*/
++/*----------------------------------------------------------------------*/
++
++/*
++ * map HIPZ rc to IB retcodes for freeing MR resource
++ * Used for hipz_h_free_resource_mr
++ */
++int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_SUCCESS: /* resource freed */
++ return 0;
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RH_PARM: /* invalid resource handle */
++ case H_R_STATE: /* invalid resource state */
++ case H_HARDWARE: /* HCA not operational */
++ return -EINVAL;
++ case H_RESOURCE: /* Resource in use */
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_free_mr() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * map HIPZ rc to IB retcodes for freeing MW resource
++ * Used for hipz_h_free_resource_mw
++ */
++int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_SUCCESS: /* resource freed */
++ return 0;
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RH_PARM: /* invalid resource handle */
++ case H_R_STATE: /* invalid resource state */
++ case H_HARDWARE: /* HCA not operational */
++ return -EINVAL;
++ case H_RESOURCE: /* Resource in use */
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_free_mw() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * map HIPZ rc to IB retcodes for SMR registrations
++ * Used for hipz_h_register_smr.
++ */
++int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
++{
++ switch (hipz_rc) {
++ case H_SUCCESS: /* successful completion */
++ return 0;
++ case H_ADAPTER_PARM: /* invalid adapter handle */
++ case H_RH_PARM: /* invalid resource handle */
++ case H_MEM_PARM: /* invalid MR virtual address */
++ case H_MEM_ACCESS_PARM: /* invalid access controls */
++ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
++ return -EINVAL;
++ case H_BUSY: /* long busy */
++ return -EBUSY;
++ default:
++ return -EINVAL;
++ }
++} /* end ehca_mrmw_map_hrc_reg_smr() */
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * MR destructor and constructor
++ * used in Reregister MR verb, sets all fields in ehca_mr_t to 0,
++ * except struct ib_mr and spinlock
++ */
++void ehca_mr_deletenew(struct ehca_mr *mr)
++{
++ mr->flags = 0;
++ mr->num_pages = 0;
++ mr->num_4k = 0;
++ mr->acl = 0;
++ mr->start = NULL;
++ mr->fmr_page_size = 0;
++ mr->fmr_max_pages = 0;
++ mr->fmr_max_maps = 0;
++ mr->fmr_map_cnt = 0;
++ memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
++ memset(&mr->galpas, 0, sizeof(mr->galpas));
++ mr->nr_of_pages = 0;
++ mr->pagearray = NULL;
++} /* end ehca_mr_deletenew() */
++
++int ehca_init_mrmw_cache(void)
++{
++ mr_cache = kmem_cache_create("ehca_cache_mr",
++ sizeof(struct ehca_mr), 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!mr_cache)
++ return -ENOMEM;
++ mw_cache = kmem_cache_create("ehca_cache_mw",
++ sizeof(struct ehca_mw), 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!mw_cache) {
++ kmem_cache_destroy(mr_cache);
++ mr_cache = NULL;
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++void ehca_cleanup_mrmw_cache(void)
++{
++ if (mr_cache)
++ kmem_cache_destroy(mr_cache);
++ if (mw_cache)
++ kmem_cache_destroy(mw_cache);
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h
+new file mode 100644
+index 0000000..d936e40
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h
+@@ -0,0 +1,140 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * MR/MW declarations and inline functions
++ *
++ * Authors: Dietmar Decker <ddecker at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef _EHCA_MRMW_H_
++#define _EHCA_MRMW_H_
++
++int ehca_reg_mr(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ u64 *iova_start,
++ u64 size,
++ int acl,
++ struct ehca_pd *e_pd,
++ struct ehca_mr_pginfo *pginfo,
++ u32 *lkey,
++ u32 *rkey);
++
++int ehca_reg_mr_rpages(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ struct ehca_mr_pginfo *pginfo);
++
++int ehca_rereg_mr(struct ehca_shca *shca,
++ struct ehca_mr *e_mr,
++ u64 *iova_start,
++ u64 size,
++ int mr_access_flags,
++ struct ehca_pd *e_pd,
++ struct ehca_mr_pginfo *pginfo,
++ u32 *lkey,
++ u32 *rkey);
++
++int ehca_unmap_one_fmr(struct ehca_shca *shca,
++ struct ehca_mr *e_fmr);
++
++int ehca_reg_smr(struct ehca_shca *shca,
++ struct ehca_mr *e_origmr,
++ struct ehca_mr *e_newmr,
++ u64 *iova_start,
++ int acl,
++ struct ehca_pd *e_pd,
++ u32 *lkey,
++ u32 *rkey);
++
++int ehca_reg_internal_maxmr(struct ehca_shca *shca,
++ struct ehca_pd *e_pd,
++ struct ehca_mr **maxmr);
++
++int ehca_reg_maxmr(struct ehca_shca *shca,
++ struct ehca_mr *e_newmr,
++ u64 *iova_start,
++ int acl,
++ struct ehca_pd *e_pd,
++ u32 *lkey,
++ u32 *rkey);
++
++int ehca_dereg_internal_maxmr(struct ehca_shca *shca);
++
++int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
++ int num_phys_buf,
++ u64 *iova_start,
++ u64 *size);
++
++int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
++ u64 *page_list,
++ int list_len);
++
++int ehca_set_pagebuf(struct ehca_mr *e_mr,
++ struct ehca_mr_pginfo *pginfo,
++ u32 number,
++ u64 *kpage);
++
++int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
++ struct ehca_mr_pginfo *pginfo,
++ u64 *rpage);
++
++int ehca_mr_is_maxmr(u64 size,
++ u64 *iova_start);
++
++void ehca_mrmw_map_acl(int ib_acl,
++ u32 *hipz_acl);
++
++void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
++
++void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
++ int *ib_acl);
++
++int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
++
++int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
++
++int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
++
++int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
++
++int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
++
++int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
++
++int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
++
++void ehca_mr_deletenew(struct ehca_mr *mr);
++
++#endif /*_EHCA_MRMW_H_*/
+diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
+new file mode 100644
+index 0000000..2c3cdc6
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_pd.c
+@@ -0,0 +1,114 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * PD functions
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/current.h>
++
++#include "ehca_tools.h"
++#include "ehca_iverbs.h"
++
++static struct kmem_cache *pd_cache;
++
++struct ib_pd *ehca_alloc_pd(struct ib_device *device,
++ struct ib_ucontext *context, struct ib_udata *udata)
++{
++ struct ehca_pd *pd;
++
++ pd = kmem_cache_alloc(pd_cache, SLAB_KERNEL);
++ if (!pd) {
++ ehca_err(device, "device=%p context=%p out of memory",
++ device, context);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ memset(pd, 0, sizeof(struct ehca_pd));
++ pd->ownpid = current->tgid;
++
++ /*
++ * Kernel PD: when device = -1, 0
++ * User PD: when context != -1
++ */
++ if (!context) {
++ /*
++ * Kernel PDs after init reuses always
++ * the one created in ehca_shca_reopen()
++ */
++ struct ehca_shca *shca = container_of(device, struct ehca_shca,
++ ib_device);
++ pd->fw_pd.value = shca->pd->fw_pd.value;
++ } else
++ pd->fw_pd.value = (u64)pd;
++
++ return &pd->ib_pd;
++}
++
++int ehca_dealloc_pd(struct ib_pd *pd)
++{
++ u32 cur_pid = current->tgid;
++ struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(pd->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ kmem_cache_free(pd_cache,
++ container_of(pd, struct ehca_pd, ib_pd));
++
++ return 0;
++}
++
++int ehca_init_pd_cache(void)
++{
++ pd_cache = kmem_cache_create("ehca_cache_pd",
++ sizeof(struct ehca_pd), 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!pd_cache)
++ return -ENOMEM;
++ return 0;
++}
++
++void ehca_cleanup_pd_cache(void)
++{
++ if (pd_cache)
++ kmem_cache_destroy(pd_cache);
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h
+new file mode 100644
+index 0000000..8707d29
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_qes.h
+@@ -0,0 +1,259 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Hardware request structures
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++
++#ifndef _EHCA_QES_H_
++#define _EHCA_QES_H_
++
++#include "ehca_tools.h"
++
++/* virtual scatter gather entry to specify remote adresses with length */
++struct ehca_vsgentry {
++ u64 vaddr;
++ u32 lkey;
++ u32 length;
++};
++
++#define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7)
++#define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3)
++#define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12)
++#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31)
++#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47)
++#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55)
++#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63)
++
++/*
++ * Unreliable Datagram Address Vector Format
++ * see IBTA Vol1 chapter 8.3 Global Routing Header
++ */
++struct ehca_ud_av {
++ u8 sl;
++ u8 lnh;
++ u16 dlid;
++ u8 reserved1;
++ u8 reserved2;
++ u8 reserved3;
++ u8 slid_path_bits;
++ u8 reserved4;
++ u8 ipd;
++ u8 reserved5;
++ u8 pmtu;
++ u32 reserved6;
++ u64 reserved7;
++ union {
++ struct {
++ u64 word_0; /* always set to 6 */
++ /*should be 0x1B for IB transport */
++ u64 word_1;
++ u64 word_2;
++ u64 word_3;
++ u64 word_4;
++ } grh;
++ struct {
++ u32 wd_0;
++ u32 wd_1;
++ /* DWord_1 --> SGID */
++
++ u32 sgid_wd3;
++ u32 sgid_wd2;
++
++ u32 sgid_wd1;
++ u32 sgid_wd0;
++ /* DWord_3 --> DGID */
++
++ u32 dgid_wd3;
++ u32 dgid_wd2;
++
++ u32 dgid_wd1;
++ u32 dgid_wd0;
++ } grh_l;
++ };
++};
++
++/* maximum number of sg entries allowed in a WQE */
++#define MAX_WQE_SG_ENTRIES 252
++
++#define WQE_OPTYPE_SEND 0x80
++#define WQE_OPTYPE_RDMAREAD 0x40
++#define WQE_OPTYPE_RDMAWRITE 0x20
++#define WQE_OPTYPE_CMPSWAP 0x10
++#define WQE_OPTYPE_FETCHADD 0x08
++#define WQE_OPTYPE_BIND 0x04
++
++#define WQE_WRFLAG_REQ_SIGNAL_COM 0x80
++#define WQE_WRFLAG_FENCE 0x40
++#define WQE_WRFLAG_IMM_DATA_PRESENT 0x20
++#define WQE_WRFLAG_SOLIC_EVENT 0x10
++
++#define WQEF_CACHE_HINT 0x80
++#define WQEF_CACHE_HINT_RD_WR 0x40
++#define WQEF_TIMED_WQE 0x20
++#define WQEF_PURGE 0x08
++#define WQEF_HIGH_NIBBLE 0xF0
++
++#define MW_BIND_ACCESSCTRL_R_WRITE 0x40
++#define MW_BIND_ACCESSCTRL_R_READ 0x20
++#define MW_BIND_ACCESSCTRL_R_ATOMIC 0x10
++
++struct ehca_wqe {
++ u64 work_request_id;
++ u8 optype;
++ u8 wr_flag;
++ u16 pkeyi;
++ u8 wqef;
++ u8 nr_of_data_seg;
++ u16 wqe_provided_slid;
++ u32 destination_qp_number;
++ u32 resync_psn_sqp;
++ u32 local_ee_context_qkey;
++ u32 immediate_data;
++ union {
++ struct {
++ u64 remote_virtual_adress;
++ u32 rkey;
++ u32 reserved;
++ u64 atomic_1st_op_dma_len;
++ u64 atomic_2nd_op;
++ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
++
++ } nud;
++ struct {
++ u64 ehca_ud_av_ptr;
++ u64 reserved1;
++ u64 reserved2;
++ u64 reserved3;
++ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
++ } ud_avp;
++ struct {
++ struct ehca_ud_av ud_av;
++ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES -
++ 2];
++ } ud_av;
++ struct {
++ u64 reserved0;
++ u64 reserved1;
++ u64 reserved2;
++ u64 reserved3;
++ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
++ } all_rcv;
++
++ struct {
++ u64 reserved;
++ u32 rkey;
++ u32 old_rkey;
++ u64 reserved1;
++ u64 reserved2;
++ u64 virtual_address;
++ u32 reserved3;
++ u32 length;
++ u32 reserved4;
++ u16 reserved5;
++ u8 reserved6;
++ u8 lr_ctl;
++ u32 lkey;
++ u32 reserved7;
++ u64 reserved8;
++ u64 reserved9;
++ u64 reserved10;
++ u64 reserved11;
++ } bind;
++ struct {
++ u64 reserved12;
++ u64 reserved13;
++ u32 size;
++ u32 start;
++ } inline_data;
++ } u;
++
++};
++
++#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
++#define WC_IMM_DATA EHCA_BMASK_IBM(1,1)
++#define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2)
++#define WC_SE_BIT EHCA_BMASK_IBM(3,3)
++#define WC_STATUS_ERROR_BIT 0x80000000
++#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
++#define WC_STATUS_PURGE_BIT 0x10
++
++struct ehca_cqe {
++ u64 work_request_id;
++ u8 optype;
++ u8 w_completion_flags;
++ u16 reserved1;
++ u32 nr_bytes_transferred;
++ u32 immediate_data;
++ u32 local_qp_number;
++ u8 freed_resource_count;
++ u8 service_level;
++ u16 wqe_count;
++ u32 qp_token;
++ u32 qkey_ee_token;
++ u32 remote_qp_number;
++ u16 dlid;
++ u16 rlid;
++ u16 reserved2;
++ u16 pkey_index;
++ u32 cqe_timestamp;
++ u32 wqe_timestamp;
++ u8 wqe_timestamp_valid;
++ u8 reserved3;
++ u8 reserved4;
++ u8 cqe_flags;
++ u32 status;
++};
++
++struct ehca_eqe {
++ u64 entry;
++};
++
++struct ehca_mrte {
++ u64 starting_va;
++ u64 length; /* length of memory region in bytes*/
++ u32 pd;
++ u8 key_instance;
++ u8 pagesize;
++ u8 mr_control;
++ u8 local_remote_access_ctrl;
++ u8 reserved[0x20 - 0x18];
++ u64 at_pointer[4];
++};
++#endif /*_EHCA_QES_H_*/
+diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
+new file mode 100644
+index 0000000..4394123
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_qp.c
+@@ -0,0 +1,1507 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * QP functions
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/current.h>
++
++#include "ehca_classes.h"
++#include "ehca_tools.h"
++#include "ehca_qes.h"
++#include "ehca_iverbs.h"
++#include "hcp_if.h"
++#include "hipz_fns.h"
++
++static struct kmem_cache *qp_cache;
++
++/*
++ * attributes not supported by query qp
++ */
++#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \
++ IB_QP_MAX_QP_RD_ATOMIC | \
++ IB_QP_ACCESS_FLAGS | \
++ IB_QP_EN_SQD_ASYNC_NOTIFY)
++
++/*
++ * ehca (internal) qp state values
++ */
++enum ehca_qp_state {
++ EHCA_QPS_RESET = 1,
++ EHCA_QPS_INIT = 2,
++ EHCA_QPS_RTR = 3,
++ EHCA_QPS_RTS = 5,
++ EHCA_QPS_SQD = 6,
++ EHCA_QPS_SQE = 8,
++ EHCA_QPS_ERR = 128
++};
++
++/*
++ * qp state transitions as defined by IB Arch Rel 1.1 page 431
++ */
++enum ib_qp_statetrans {
++ IB_QPST_ANY2RESET,
++ IB_QPST_ANY2ERR,
++ IB_QPST_RESET2INIT,
++ IB_QPST_INIT2RTR,
++ IB_QPST_INIT2INIT,
++ IB_QPST_RTR2RTS,
++ IB_QPST_RTS2SQD,
++ IB_QPST_RTS2RTS,
++ IB_QPST_SQD2RTS,
++ IB_QPST_SQE2RTS,
++ IB_QPST_SQD2SQD,
++ IB_QPST_MAX /* nr of transitions, this must be last!!! */
++};
++
++/*
++ * ib2ehca_qp_state maps IB to ehca qp_state
++ * returns ehca qp state corresponding to given ib qp state
++ */
++static inline enum ehca_qp_state ib2ehca_qp_state(enum ib_qp_state ib_qp_state)
++{
++ switch (ib_qp_state) {
++ case IB_QPS_RESET:
++ return EHCA_QPS_RESET;
++ case IB_QPS_INIT:
++ return EHCA_QPS_INIT;
++ case IB_QPS_RTR:
++ return EHCA_QPS_RTR;
++ case IB_QPS_RTS:
++ return EHCA_QPS_RTS;
++ case IB_QPS_SQD:
++ return EHCA_QPS_SQD;
++ case IB_QPS_SQE:
++ return EHCA_QPS_SQE;
++ case IB_QPS_ERR:
++ return EHCA_QPS_ERR;
++ default:
++ ehca_gen_err("invalid ib_qp_state=%x", ib_qp_state);
++ return -EINVAL;
++ }
++}
++
++/*
++ * ehca2ib_qp_state maps ehca to IB qp_state
++ * returns ib qp state corresponding to given ehca qp state
++ */
++static inline enum ib_qp_state ehca2ib_qp_state(enum ehca_qp_state
++ ehca_qp_state)
++{
++ switch (ehca_qp_state) {
++ case EHCA_QPS_RESET:
++ return IB_QPS_RESET;
++ case EHCA_QPS_INIT:
++ return IB_QPS_INIT;
++ case EHCA_QPS_RTR:
++ return IB_QPS_RTR;
++ case EHCA_QPS_RTS:
++ return IB_QPS_RTS;
++ case EHCA_QPS_SQD:
++ return IB_QPS_SQD;
++ case EHCA_QPS_SQE:
++ return IB_QPS_SQE;
++ case EHCA_QPS_ERR:
++ return IB_QPS_ERR;
++ default:
++ ehca_gen_err("invalid ehca_qp_state=%x", ehca_qp_state);
++ return -EINVAL;
++ }
++}
++
++/*
++ * ehca_qp_type used as index for req_attr and opt_attr of
++ * struct ehca_modqp_statetrans
++ */
++enum ehca_qp_type {
++ QPT_RC = 0,
++ QPT_UC = 1,
++ QPT_UD = 2,
++ QPT_SQP = 3,
++ QPT_MAX
++};
++
++/*
++ * ib2ehcaqptype maps Ib to ehca qp_type
++ * returns ehca qp type corresponding to ib qp type
++ */
++static inline enum ehca_qp_type ib2ehcaqptype(enum ib_qp_type ibqptype)
++{
++ switch (ibqptype) {
++ case IB_QPT_SMI:
++ case IB_QPT_GSI:
++ return QPT_SQP;
++ case IB_QPT_RC:
++ return QPT_RC;
++ case IB_QPT_UC:
++ return QPT_UC;
++ case IB_QPT_UD:
++ return QPT_UD;
++ default:
++ ehca_gen_err("Invalid ibqptype=%x", ibqptype);
++ return -EINVAL;
++ }
++}
++
++static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate,
++ int ib_tostate)
++{
++ int index = -EINVAL;
++ switch (ib_tostate) {
++ case IB_QPS_RESET:
++ index = IB_QPST_ANY2RESET;
++ break;
++ case IB_QPS_INIT:
++ switch (ib_fromstate) {
++ case IB_QPS_RESET:
++ index = IB_QPST_RESET2INIT;
++ break;
++ case IB_QPS_INIT:
++ index = IB_QPST_INIT2INIT;
++ break;
++ }
++ break;
++ case IB_QPS_RTR:
++ if (ib_fromstate == IB_QPS_INIT)
++ index = IB_QPST_INIT2RTR;
++ break;
++ case IB_QPS_RTS:
++ switch (ib_fromstate) {
++ case IB_QPS_RTR:
++ index = IB_QPST_RTR2RTS;
++ break;
++ case IB_QPS_RTS:
++ index = IB_QPST_RTS2RTS;
++ break;
++ case IB_QPS_SQD:
++ index = IB_QPST_SQD2RTS;
++ break;
++ case IB_QPS_SQE:
++ index = IB_QPST_SQE2RTS;
++ break;
++ }
++ break;
++ case IB_QPS_SQD:
++ if (ib_fromstate == IB_QPS_RTS)
++ index = IB_QPST_RTS2SQD;
++ break;
++ case IB_QPS_SQE:
++ break;
++ case IB_QPS_ERR:
++ index = IB_QPST_ANY2ERR;
++ break;
++ default:
++ break;
++ }
++ return index;
++}
++
++enum ehca_service_type {
++ ST_RC = 0,
++ ST_UC = 1,
++ ST_RD = 2,
++ ST_UD = 3
++};
++
++/*
++ * ibqptype2servicetype returns hcp service type corresponding to given
++ * ib qp type used by create_qp()
++ */
++static inline int ibqptype2servicetype(enum ib_qp_type ibqptype)
++{
++ switch (ibqptype) {
++ case IB_QPT_SMI:
++ case IB_QPT_GSI:
++ return ST_UD;
++ case IB_QPT_RC:
++ return ST_RC;
++ case IB_QPT_UC:
++ return ST_UC;
++ case IB_QPT_UD:
++ return ST_UD;
++ case IB_QPT_RAW_IPV6:
++ return -EINVAL;
++ case IB_QPT_RAW_ETY:
++ return -EINVAL;
++ default:
++ ehca_gen_err("Invalid ibqptype=%x", ibqptype);
++ return -EINVAL;
++ }
++}
++
++/*
++ * init_qp_queues initializes/constructs r/squeue and registers queue pages.
++ */
++static inline int init_qp_queues(struct ehca_shca *shca,
++ struct ehca_qp *my_qp,
++ int nr_sq_pages,
++ int nr_rq_pages,
++ int swqe_size,
++ int rwqe_size,
++ int nr_send_sges, int nr_receive_sges)
++{
++ int ret, cnt, ipz_rc;
++ void *vpage;
++ u64 rpage, h_ret;
++ struct ib_device *ib_dev = &shca->ib_device;
++ struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
++
++ ipz_rc = ipz_queue_ctor(&my_qp->ipz_squeue,
++ nr_sq_pages,
++ EHCA_PAGESIZE, swqe_size, nr_send_sges);
++ if (!ipz_rc) {
++ ehca_err(ib_dev,"Cannot allocate page for squeue. ipz_rc=%x",
++ ipz_rc);
++ return -EBUSY;
++ }
++
++ ipz_rc = ipz_queue_ctor(&my_qp->ipz_rqueue,
++ nr_rq_pages,
++ EHCA_PAGESIZE, rwqe_size, nr_receive_sges);
++ if (!ipz_rc) {
++ ehca_err(ib_dev, "Cannot allocate page for rqueue. ipz_rc=%x",
++ ipz_rc);
++ ret = -EBUSY;
++ goto init_qp_queues0;
++ }
++ /* register SQ pages */
++ for (cnt = 0; cnt < nr_sq_pages; cnt++) {
++ vpage = ipz_qpageit_get_inc(&my_qp->ipz_squeue);
++ if (!vpage) {
++ ehca_err(ib_dev, "SQ ipz_qpageit_get_inc() "
++ "failed p_vpage= %p", vpage);
++ ret = -EINVAL;
++ goto init_qp_queues1;
++ }
++ rpage = virt_to_abs(vpage);
++
++ h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ &my_qp->pf, 0, 0,
++ rpage, 1,
++ my_qp->galpas.kernel);
++ if (h_ret < H_SUCCESS) {
++ ehca_err(ib_dev, "SQ hipz_qp_register_rpage()"
++ " failed rc=%lx", h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto init_qp_queues1;
++ }
++ }
++
++ ipz_qeit_reset(&my_qp->ipz_squeue);
++
++ /* register RQ pages */
++ for (cnt = 0; cnt < nr_rq_pages; cnt++) {
++ vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
++ if (!vpage) {
++ ehca_err(ib_dev, "RQ ipz_qpageit_get_inc() "
++ "failed p_vpage = %p", vpage);
++ ret = -EINVAL;
++ goto init_qp_queues1;
++ }
++
++ rpage = virt_to_abs(vpage);
++
++ h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ &my_qp->pf, 0, 1,
++ rpage, 1,my_qp->galpas.kernel);
++ if (h_ret < H_SUCCESS) {
++ ehca_err(ib_dev, "RQ hipz_qp_register_rpage() failed "
++ "rc=%lx", h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto init_qp_queues1;
++ }
++ if (cnt == (nr_rq_pages - 1)) { /* last page! */
++ if (h_ret != H_SUCCESS) {
++ ehca_err(ib_dev, "RQ hipz_qp_register_rpage() "
++ "h_ret= %lx ", h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto init_qp_queues1;
++ }
++ vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
++ if (vpage) {
++ ehca_err(ib_dev, "ipz_qpageit_get_inc() "
++ "should not succeed vpage=%p", vpage);
++ ret = -EINVAL;
++ goto init_qp_queues1;
++ }
++ } else {
++ if (h_ret != H_PAGE_REGISTERED) {
++ ehca_err(ib_dev, "RQ hipz_qp_register_rpage() "
++ "h_ret= %lx ", h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto init_qp_queues1;
++ }
++ }
++ }
++
++ ipz_qeit_reset(&my_qp->ipz_rqueue);
++
++ return 0;
++
++init_qp_queues1:
++ ipz_queue_dtor(&my_qp->ipz_rqueue);
++init_qp_queues0:
++ ipz_queue_dtor(&my_qp->ipz_squeue);
++ return ret;
++}
++
++struct ib_qp *ehca_create_qp(struct ib_pd *pd,
++ struct ib_qp_init_attr *init_attr,
++ struct ib_udata *udata)
++{
++ static int da_rc_msg_size[]={ 128, 256, 512, 1024, 2048, 4096 };
++ static int da_ud_sq_msg_size[]={ 128, 384, 896, 1920, 3968 };
++ struct ehca_qp *my_qp;
++ struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
++ struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
++ ib_device);
++ struct ib_ucontext *context = NULL;
++ u64 h_ret;
++ int max_send_sge, max_recv_sge, ret;
++
++ /* h_call's out parameters */
++ struct ehca_alloc_qp_parms parms;
++ u32 swqe_size = 0, rwqe_size = 0;
++ u8 daqp_completion, isdaqp;
++ unsigned long flags;
++
++ if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR &&
++ init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
++ ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",
++ init_attr->sq_sig_type);
++ return ERR_PTR(-EINVAL);
++ }
++
++ /* save daqp completion bits */
++ daqp_completion = init_attr->qp_type & 0x60;
++ /* save daqp bit */
++ isdaqp = (init_attr->qp_type & 0x80) ? 1 : 0;
++ init_attr->qp_type = init_attr->qp_type & 0x1F;
++
++ if (init_attr->qp_type != IB_QPT_UD &&
++ init_attr->qp_type != IB_QPT_SMI &&
++ init_attr->qp_type != IB_QPT_GSI &&
++ init_attr->qp_type != IB_QPT_UC &&
++ init_attr->qp_type != IB_QPT_RC) {
++ ehca_err(pd->device, "wrong QP Type=%x", init_attr->qp_type);
++ return ERR_PTR(-EINVAL);
++ }
++ if ((init_attr->qp_type != IB_QPT_RC && init_attr->qp_type != IB_QPT_UD)
++ && isdaqp) {
++ ehca_err(pd->device, "unsupported LL QP Type=%x",
++ init_attr->qp_type);
++ return ERR_PTR(-EINVAL);
++ } else if (init_attr->qp_type == IB_QPT_RC && isdaqp &&
++ (init_attr->cap.max_send_wr > 255 ||
++ init_attr->cap.max_recv_wr > 255 )) {
++ ehca_err(pd->device, "Invalid Number of max_sq_wr =%x "
++ "or max_rq_wr=%x for QP Type=%x",
++ init_attr->cap.max_send_wr,
++ init_attr->cap.max_recv_wr,init_attr->qp_type);
++ return ERR_PTR(-EINVAL);
++ } else if (init_attr->qp_type == IB_QPT_UD && isdaqp &&
++ init_attr->cap.max_send_wr > 255) {
++ ehca_err(pd->device,
++ "Invalid Number of max_send_wr=%x for UD QP_TYPE=%x",
++ init_attr->cap.max_send_wr, init_attr->qp_type);
++ return ERR_PTR(-EINVAL);
++ }
++
++ if (pd->uobject && udata)
++ context = pd->uobject->context;
++
++ my_qp = kmem_cache_alloc(qp_cache, SLAB_KERNEL);
++ if (!my_qp) {
++ ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ memset(my_qp, 0, sizeof(struct ehca_qp));
++ memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms));
++ spin_lock_init(&my_qp->spinlock_s);
++ spin_lock_init(&my_qp->spinlock_r);
++
++ my_qp->recv_cq =
++ container_of(init_attr->recv_cq, struct ehca_cq, ib_cq);
++ my_qp->send_cq =
++ container_of(init_attr->send_cq, struct ehca_cq, ib_cq);
++
++ my_qp->init_attr = *init_attr;
++
++ do {
++ if (!idr_pre_get(&ehca_qp_idr, GFP_KERNEL)) {
++ ret = -ENOMEM;
++ ehca_err(pd->device, "Can't reserve idr resources.");
++ goto create_qp_exit0;
++ }
++
++ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
++ ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
++ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
++
++ } while (ret == -EAGAIN);
++
++ if (ret) {
++ ret = -ENOMEM;
++ ehca_err(pd->device, "Can't allocate new idr entry.");
++ goto create_qp_exit0;
++ }
++
++ parms.servicetype = ibqptype2servicetype(init_attr->qp_type);
++ if (parms.servicetype < 0) {
++ ret = -EINVAL;
++ ehca_err(pd->device, "Invalid qp_type=%x", init_attr->qp_type);
++ goto create_qp_exit0;
++ }
++
++ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
++ parms.sigtype = HCALL_SIGT_EVERY;
++ else
++ parms.sigtype = HCALL_SIGT_BY_WQE;
++
++ /* UD_AV CIRCUMVENTION */
++ max_send_sge = init_attr->cap.max_send_sge;
++ max_recv_sge = init_attr->cap.max_recv_sge;
++ if (IB_QPT_UD == init_attr->qp_type ||
++ IB_QPT_GSI == init_attr->qp_type ||
++ IB_QPT_SMI == init_attr->qp_type) {
++ max_send_sge += 2;
++ max_recv_sge += 2;
++ }
++
++ parms.ipz_eq_handle = shca->eq.ipz_eq_handle;
++ parms.daqp_ctrl = isdaqp | daqp_completion;
++ parms.pd = my_pd->fw_pd;
++ parms.max_recv_sge = max_recv_sge;
++ parms.max_send_sge = max_send_sge;
++
++ h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, my_qp, &parms);
++
++ if (h_ret != H_SUCCESS) {
++ ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx",
++ h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto create_qp_exit1;
++ }
++
++ switch (init_attr->qp_type) {
++ case IB_QPT_RC:
++ if (isdaqp == 0) {
++ swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
++ (parms.act_nr_send_sges)]);
++ rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
++ (parms.act_nr_recv_sges)]);
++ } else { /* for daqp we need to use msg size, not wqe size */
++ swqe_size = da_rc_msg_size[max_send_sge];
++ rwqe_size = da_rc_msg_size[max_recv_sge];
++ parms.act_nr_send_sges = 1;
++ parms.act_nr_recv_sges = 1;
++ }
++ break;
++ case IB_QPT_UC:
++ swqe_size = offsetof(struct ehca_wqe,
++ u.nud.sg_list[parms.act_nr_send_sges]);
++ rwqe_size = offsetof(struct ehca_wqe,
++ u.nud.sg_list[parms.act_nr_recv_sges]);
++ break;
++
++ case IB_QPT_UD:
++ case IB_QPT_GSI:
++ case IB_QPT_SMI:
++ /* UD circumvention */
++ parms.act_nr_recv_sges -= 2;
++ parms.act_nr_send_sges -= 2;
++ if (isdaqp) {
++ swqe_size = da_ud_sq_msg_size[max_send_sge];
++ rwqe_size = da_rc_msg_size[max_recv_sge];
++ parms.act_nr_send_sges = 1;
++ parms.act_nr_recv_sges = 1;
++ } else {
++ swqe_size = offsetof(struct ehca_wqe,
++ u.ud_av.sg_list[parms.act_nr_send_sges]);
++ rwqe_size = offsetof(struct ehca_wqe,
++ u.ud_av.sg_list[parms.act_nr_recv_sges]);
++ }
++
++ if (IB_QPT_GSI == init_attr->qp_type ||
++ IB_QPT_SMI == init_attr->qp_type) {
++ parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
++ parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
++ parms.act_nr_send_sges = init_attr->cap.max_send_sge;
++ parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
++ my_qp->real_qp_num =
++ (init_attr->qp_type == IB_QPT_SMI) ? 0 : 1;
++ }
++
++ break;
++
++ default:
++ break;
++ }
++
++ /* initializes r/squeue and registers queue pages */
++ ret = init_qp_queues(shca, my_qp,
++ parms.nr_sq_pages, parms.nr_rq_pages,
++ swqe_size, rwqe_size,
++ parms.act_nr_send_sges, parms.act_nr_recv_sges);
++ if (ret) {
++ ehca_err(pd->device,
++ "Couldn't initialize r/squeue and pages ret=%x", ret);
++ goto create_qp_exit2;
++ }
++
++ my_qp->ib_qp.pd = &my_pd->ib_pd;
++ my_qp->ib_qp.device = my_pd->ib_pd.device;
++
++ my_qp->ib_qp.recv_cq = init_attr->recv_cq;
++ my_qp->ib_qp.send_cq = init_attr->send_cq;
++
++ my_qp->ib_qp.qp_num = my_qp->real_qp_num;
++ my_qp->ib_qp.qp_type = init_attr->qp_type;
++
++ my_qp->qp_type = init_attr->qp_type;
++ my_qp->ib_qp.srq = init_attr->srq;
++
++ my_qp->ib_qp.qp_context = init_attr->qp_context;
++ my_qp->ib_qp.event_handler = init_attr->event_handler;
++
++ init_attr->cap.max_inline_data = 0; /* not supported yet */
++ init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
++ init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
++ init_attr->cap.max_send_sge = parms.act_nr_send_sges;
++ init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
++
++ /* NOTE: define_apq0() not supported yet */
++ if (init_attr->qp_type == IB_QPT_GSI) {
++ h_ret = ehca_define_sqp(shca, my_qp, init_attr);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx",
++ h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto create_qp_exit3;
++ }
++ }
++ if (init_attr->send_cq) {
++ struct ehca_cq *cq = container_of(init_attr->send_cq,
++ struct ehca_cq, ib_cq);
++ ret = ehca_cq_assign_qp(cq, my_qp);
++ if (ret) {
++ ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
++ ret);
++ goto create_qp_exit3;
++ }
++ my_qp->send_cq = cq;
++ }
++ /* copy queues, galpa data to user space */
++ if (context && udata) {
++ struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
++ struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
++ struct ehca_create_qp_resp resp;
++ struct vm_area_struct * vma;
++ memset(&resp, 0, sizeof(resp));
++
++ resp.qp_num = my_qp->real_qp_num;
++ resp.token = my_qp->token;
++ resp.qp_type = my_qp->qp_type;
++ resp.qkey = my_qp->qkey;
++ resp.real_qp_num = my_qp->real_qp_num;
++ /* rqueue properties */
++ resp.ipz_rqueue.qe_size = ipz_rqueue->qe_size;
++ resp.ipz_rqueue.act_nr_of_sg = ipz_rqueue->act_nr_of_sg;
++ resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
++ resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
++ resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
++ ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
++ ipz_rqueue->queue_length,
++ (void**)&resp.ipz_rqueue.queue,
++ &vma);
++ if (ret) {
++ ehca_err(pd->device, "Could not mmap rqueue pages");
++ goto create_qp_exit3;
++ }
++ my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
++ /* squeue properties */
++ resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
++ resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
++ resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
++ resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
++ resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
++ ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
++ ipz_squeue->queue_length,
++ (void**)&resp.ipz_squeue.queue,
++ &vma);
++ if (ret) {
++ ehca_err(pd->device, "Could not mmap squeue pages");
++ goto create_qp_exit4;
++ }
++ my_qp->uspace_squeue = resp.ipz_squeue.queue;
++ /* fw_handle */
++ resp.galpas = my_qp->galpas;
++ ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
++ (void**)&resp.galpas.kernel.fw_handle,
++ &vma);
++ if (ret) {
++ ehca_err(pd->device, "Could not mmap fw_handle");
++ goto create_qp_exit5;
++ }
++ my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
++
++ if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
++ ehca_err(pd->device, "Copy to udata failed");
++ ret = -EINVAL;
++ goto create_qp_exit6;
++ }
++ }
++
++ return &my_qp->ib_qp;
++
++create_qp_exit6:
++ ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
++
++create_qp_exit5:
++ ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
++
++create_qp_exit4:
++ ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
++
++create_qp_exit3:
++ ipz_queue_dtor(&my_qp->ipz_rqueue);
++ ipz_queue_dtor(&my_qp->ipz_squeue);
++
++create_qp_exit2:
++ hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
++
++create_qp_exit1:
++ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
++ idr_remove(&ehca_qp_idr, my_qp->token);
++ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
++
++create_qp_exit0:
++ kmem_cache_free(qp_cache, my_qp);
++ return ERR_PTR(ret);
++}
++
++/*
++ * prepare_sqe_rts called by internal_modify_qp() at trans sqe -> rts
++ * set purge bit of bad wqe and subsequent wqes to avoid reentering sqe
++ * returns total number of bad wqes in bad_wqe_cnt
++ */
++static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
++ int *bad_wqe_cnt)
++{
++ u64 h_ret;
++ struct ipz_queue *squeue;
++ void *bad_send_wqe_p, *bad_send_wqe_v;
++ void *squeue_start_p, *squeue_end_p;
++ void *squeue_start_v, *squeue_end_v;
++ struct ehca_wqe *wqe;
++ int qp_num = my_qp->ib_qp.qp_num;
++
++ /* get send wqe pointer */
++ h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
++ my_qp->ipz_qp_handle, &my_qp->pf,
++ &bad_send_wqe_p, NULL, 2);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
++ " ehca_qp=%p qp_num=%x h_ret=%lx",
++ my_qp, qp_num, h_ret);
++ return ehca2ib_return_code(h_ret);
++ }
++ bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
++ ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
++ qp_num, bad_send_wqe_p);
++ /* convert wqe pointer to vadr */
++ bad_send_wqe_v = abs_to_virt((u64)bad_send_wqe_p);
++ if (ehca_debug_level)
++ ehca_dmp(bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num);
++ squeue = &my_qp->ipz_squeue;
++ squeue_start_p = (void*)virt_to_abs(ipz_qeit_calc(squeue, 0L));
++ squeue_end_p = squeue_start_p+squeue->queue_length;
++ squeue_start_v = abs_to_virt((u64)squeue_start_p);
++ squeue_end_v = abs_to_virt((u64)squeue_end_p);
++ ehca_dbg(&shca->ib_device, "qp_num=%x squeue_start_v=%p squeue_end_v=%p",
++ qp_num, squeue_start_v, squeue_end_v);
++
++ /* loop sets wqe's purge bit */
++ wqe = (struct ehca_wqe*)bad_send_wqe_v;
++ *bad_wqe_cnt = 0;
++ while (wqe->optype != 0xff && wqe->wqef != 0xff) {
++ if (ehca_debug_level)
++ ehca_dmp(wqe, 32, "qp_num=%x wqe", qp_num);
++ wqe->nr_of_data_seg = 0; /* suppress data access */
++ wqe->wqef = WQEF_PURGE; /* WQE to be purged */
++ wqe = (struct ehca_wqe*)((u8*)wqe+squeue->qe_size);
++ *bad_wqe_cnt = (*bad_wqe_cnt)+1;
++ if ((void*)wqe >= squeue_end_v) {
++ wqe = squeue_start_v;
++ }
++ }
++ /*
++ * bad wqe will be reprocessed and ignored when pol_cq() is called,
++ * i.e. nr of wqes with flush error status is one less
++ */
++ ehca_dbg(&shca->ib_device, "qp_num=%x flusherr_wqe_cnt=%x",
++ qp_num, (*bad_wqe_cnt)-1);
++ wqe->wqef = 0;
++
++ return 0;
++}
++
++/*
++ * internal_modify_qp with circumvention to handle aqp0 properly
++ * smi_reset2init indicates if this is an internal reset-to-init-call for
++ * smi. This flag must always be zero if called from ehca_modify_qp()!
++ * This internal func was intorduced to avoid recursion of ehca_modify_qp()!
++ */
++static int internal_modify_qp(struct ib_qp *ibqp,
++ struct ib_qp_attr *attr,
++ int attr_mask, int smi_reset2init)
++{
++ enum ib_qp_state qp_cur_state, qp_new_state;
++ int cnt, qp_attr_idx, ret = 0;
++ enum ib_qp_statetrans statetrans;
++ struct hcp_modify_qp_control_block *mqpcb;
++ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
++ struct ehca_shca *shca =
++ container_of(ibqp->pd->device, struct ehca_shca, ib_device);
++ u64 update_mask;
++ u64 h_ret;
++ int bad_wqe_cnt = 0;
++ int squeue_locked = 0;
++ unsigned long spl_flags = 0;
++
++ /* do query_qp to obtain current attr values */
++ mqpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
++ if (mqpcb == NULL) {
++ ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
++ "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
++ return -ENOMEM;
++ }
++
++ h_ret = hipz_h_query_qp(shca->ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ &my_qp->pf,
++ mqpcb, my_qp->galpas.kernel);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(ibqp->device, "hipz_h_query_qp() failed "
++ "ehca_qp=%p qp_num=%x h_ret=%lx",
++ my_qp, ibqp->qp_num, h_ret);
++ ret = ehca2ib_return_code(h_ret);
++ goto modify_qp_exit1;
++ }
++
++ qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state);
++
++ if (qp_cur_state == -EINVAL) { /* invalid qp state */
++ ret = -EINVAL;
++ ehca_err(ibqp->device, "Invalid current ehca_qp_state=%x "
++ "ehca_qp=%p qp_num=%x",
++ mqpcb->qp_state, my_qp, ibqp->qp_num);
++ goto modify_qp_exit1;
++ }
++ /*
++ * circumvention to set aqp0 initial state to init
++ * as expected by IB spec
++ */
++ if (smi_reset2init == 0 &&
++ ibqp->qp_type == IB_QPT_SMI &&
++ qp_cur_state == IB_QPS_RESET &&
++ (attr_mask & IB_QP_STATE) &&
++ attr->qp_state == IB_QPS_INIT) { /* RESET -> INIT */
++ struct ib_qp_attr smiqp_attr = {
++ .qp_state = IB_QPS_INIT,
++ .port_num = my_qp->init_attr.port_num,
++ .pkey_index = 0,
++ .qkey = 0
++ };
++ int smiqp_attr_mask = IB_QP_STATE | IB_QP_PORT |
++ IB_QP_PKEY_INDEX | IB_QP_QKEY;
++ int smirc = internal_modify_qp(
++ ibqp, &smiqp_attr, smiqp_attr_mask, 1);
++ if (smirc) {
++ ehca_err(ibqp->device, "SMI RESET -> INIT failed. "
++ "ehca_modify_qp() rc=%x", smirc);
++ ret = H_PARAMETER;
++ goto modify_qp_exit1;
++ }
++ qp_cur_state = IB_QPS_INIT;
++ ehca_dbg(ibqp->device, "SMI RESET -> INIT succeeded");
++ }
++ /* is transmitted current state equal to "real" current state */
++ if ((attr_mask & IB_QP_CUR_STATE) &&
++ qp_cur_state != attr->cur_qp_state) {
++ ret = -EINVAL;
++ ehca_err(ibqp->device,
++ "Invalid IB_QP_CUR_STATE attr->curr_qp_state=%x <>"
++ " actual cur_qp_state=%x. ehca_qp=%p qp_num=%x",
++ attr->cur_qp_state, qp_cur_state, my_qp, ibqp->qp_num);
++ goto modify_qp_exit1;
++ }
++
++ ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
++ "new qp_state=%x attribute_mask=%x",
++ my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
++
++ qp_new_state = attr_mask & IB_QP_STATE ? attr->qp_state : qp_cur_state;
++ if (!smi_reset2init &&
++ !ib_modify_qp_is_ok(qp_cur_state, qp_new_state, ibqp->qp_type,
++ attr_mask)) {
++ ret = -EINVAL;
++ ehca_err(ibqp->device,
++ "Invalid qp transition new_state=%x cur_state=%x "
++ "ehca_qp=%p qp_num=%x attr_mask=%x", qp_new_state,
++ qp_cur_state, my_qp, ibqp->qp_num, attr_mask);
++ goto modify_qp_exit1;
++ }
++
++ if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
++ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
++ else {
++ ret = -EINVAL;
++ ehca_err(ibqp->device, "Invalid new qp state=%x "
++ "ehca_qp=%p qp_num=%x",
++ qp_new_state, my_qp, ibqp->qp_num);
++ goto modify_qp_exit1;
++ }
++
++ /* retrieve state transition struct to get req and opt attrs */
++ statetrans = get_modqp_statetrans(qp_cur_state, qp_new_state);
++ if (statetrans < 0) {
++ ret = -EINVAL;
++ ehca_err(ibqp->device, "<INVALID STATE CHANGE> qp_cur_state=%x "
++ "new_qp_state=%x State_xsition=%x ehca_qp=%p "
++ "qp_num=%x", qp_cur_state, qp_new_state,
++ statetrans, my_qp, ibqp->qp_num);
++ goto modify_qp_exit1;
++ }
++
++ qp_attr_idx = ib2ehcaqptype(ibqp->qp_type);
++
++ if (qp_attr_idx < 0) {
++ ret = qp_attr_idx;
++ ehca_err(ibqp->device,
++ "Invalid QP type=%x ehca_qp=%p qp_num=%x",
++ ibqp->qp_type, my_qp, ibqp->qp_num);
++ goto modify_qp_exit1;
++ }
++
++ ehca_dbg(ibqp->device,
++ "ehca_qp=%p qp_num=%x <VALID STATE CHANGE> qp_state_xsit=%x",
++ my_qp, ibqp->qp_num, statetrans);
++
++ /* sqe -> rts: set purge bit of bad wqe before actual trans */
++ if ((my_qp->qp_type == IB_QPT_UD ||
++ my_qp->qp_type == IB_QPT_GSI ||
++ my_qp->qp_type == IB_QPT_SMI) &&
++ statetrans == IB_QPST_SQE2RTS) {
++ /* mark next free wqe if kernel */
++ if (my_qp->uspace_squeue == 0) {
++ struct ehca_wqe *wqe;
++ /* lock send queue */
++ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
++ squeue_locked = 1;
++ /* mark next free wqe */
++ wqe = (struct ehca_wqe*)
++ ipz_qeit_get(&my_qp->ipz_squeue);
++ wqe->optype = wqe->wqef = 0xff;
++ ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
++ ibqp->qp_num, wqe);
++ }
++ ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
++ if (ret) {
++ ehca_err(ibqp->device, "prepare_sqe_rts() failed "
++ "ehca_qp=%p qp_num=%x ret=%x",
++ my_qp, ibqp->qp_num, ret);
++ goto modify_qp_exit2;
++ }
++ }
++
++ /*
++ * enable RDMA_Atomic_Control if reset->init und reliable con
++ * this is necessary since gen2 does not provide that flag,
++ * but pHyp requires it
++ */
++ if (statetrans == IB_QPST_RESET2INIT &&
++ (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_UC)) {
++ mqpcb->rdma_atomic_ctrl = 3;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RDMA_ATOMIC_CTRL, 1);
++ }
++ /* circ. pHyp requires #RDMA/Atomic Resp Res for UC INIT -> RTR */
++ if (statetrans == IB_QPST_INIT2RTR &&
++ (ibqp->qp_type == IB_QPT_UC) &&
++ !(attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)) {
++ mqpcb->rdma_nr_atomic_resp_res = 1; /* default to 1 */
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
++ }
++
++ if (attr_mask & IB_QP_PKEY_INDEX) {
++ mqpcb->prim_p_key_idx = attr->pkey_index;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
++ }
++ if (attr_mask & IB_QP_PORT) {
++ if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
++ ret = -EINVAL;
++ ehca_err(ibqp->device, "Invalid port=%x. "
++ "ehca_qp=%p qp_num=%x num_ports=%x",
++ attr->port_num, my_qp, ibqp->qp_num,
++ shca->num_ports);
++ goto modify_qp_exit2;
++ }
++ mqpcb->prim_phys_port = attr->port_num;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
++ }
++ if (attr_mask & IB_QP_QKEY) {
++ mqpcb->qkey = attr->qkey;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_QKEY, 1);
++ }
++ if (attr_mask & IB_QP_AV) {
++ int ah_mult = ib_rate_to_mult(attr->ah_attr.static_rate);
++ int ehca_mult = ib_rate_to_mult(shca->sport[my_qp->
++ init_attr.port_num].rate);
++
++ mqpcb->dlid = attr->ah_attr.dlid;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID, 1);
++ mqpcb->source_path_bits = attr->ah_attr.src_path_bits;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS, 1);
++ mqpcb->service_level = attr->ah_attr.sl;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL, 1);
++
++ if (ah_mult < ehca_mult)
++ mqpcb->max_static_rate = (ah_mult > 0) ?
++ ((ehca_mult - 1) / ah_mult) : 0;
++ else
++ mqpcb->max_static_rate = 0;
++
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE, 1);
++
++ /*
++ * only if GRH is TRUE we might consider SOURCE_GID_IDX
++ * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
++ */
++ if (attr->ah_attr.ah_flags == IB_AH_GRH) {
++ mqpcb->send_grh_flag = 1 << 31;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1);
++ mqpcb->source_gid_idx = attr->ah_attr.grh.sgid_index;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX, 1);
++
++ for (cnt = 0; cnt < 16; cnt++)
++ mqpcb->dest_gid.byte[cnt] =
++ attr->ah_attr.grh.dgid.raw[cnt];
++
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_GID, 1);
++ mqpcb->flow_label = attr->ah_attr.grh.flow_label;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL, 1);
++ mqpcb->hop_limit = attr->ah_attr.grh.hop_limit;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT, 1);
++ mqpcb->traffic_class = attr->ah_attr.grh.traffic_class;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS, 1);
++ }
++ }
++
++ if (attr_mask & IB_QP_PATH_MTU) {
++ mqpcb->path_mtu = attr->path_mtu;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
++ }
++ if (attr_mask & IB_QP_TIMEOUT) {
++ mqpcb->timeout = attr->timeout;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT, 1);
++ }
++ if (attr_mask & IB_QP_RETRY_CNT) {
++ mqpcb->retry_count = attr->retry_cnt;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT, 1);
++ }
++ if (attr_mask & IB_QP_RNR_RETRY) {
++ mqpcb->rnr_retry_count = attr->rnr_retry;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT, 1);
++ }
++ if (attr_mask & IB_QP_RQ_PSN) {
++ mqpcb->receive_psn = attr->rq_psn;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RECEIVE_PSN, 1);
++ }
++ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
++ mqpcb->rdma_nr_atomic_resp_res = attr->max_dest_rd_atomic < 3 ?
++ attr->max_dest_rd_atomic : 2;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
++ }
++ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
++ mqpcb->rdma_atomic_outst_dest_qp = attr->max_rd_atomic < 3 ?
++ attr->max_rd_atomic : 2;
++ update_mask |=
++ EHCA_BMASK_SET
++ (MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP, 1);
++ }
++ if (attr_mask & IB_QP_ALT_PATH) {
++ int ah_mult = ib_rate_to_mult(attr->alt_ah_attr.static_rate);
++ int ehca_mult = ib_rate_to_mult(
++ shca->sport[my_qp->init_attr.port_num].rate);
++
++ mqpcb->dlid_al = attr->alt_ah_attr.dlid;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1);
++ mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1);
++ mqpcb->service_level_al = attr->alt_ah_attr.sl;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1);
++
++ if (ah_mult < ehca_mult)
++ mqpcb->max_static_rate = (ah_mult > 0) ?
++ ((ehca_mult - 1) / ah_mult) : 0;
++ else
++ mqpcb->max_static_rate_al = 0;
++
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1);
++
++ /*
++ * only if GRH is TRUE we might consider SOURCE_GID_IDX
++ * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
++ */
++ if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
++ mqpcb->send_grh_flag_al = 1 << 31;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
++ mqpcb->source_gid_idx_al =
++ attr->alt_ah_attr.grh.sgid_index;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1);
++
++ for (cnt = 0; cnt < 16; cnt++)
++ mqpcb->dest_gid_al.byte[cnt] =
++ attr->alt_ah_attr.grh.dgid.raw[cnt];
++
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1);
++ mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1);
++ mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1);
++ mqpcb->traffic_class_al =
++ attr->alt_ah_attr.grh.traffic_class;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
++ }
++ }
++
++ if (attr_mask & IB_QP_MIN_RNR_TIMER) {
++ mqpcb->min_rnr_nak_timer_field = attr->min_rnr_timer;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD, 1);
++ }
++
++ if (attr_mask & IB_QP_SQ_PSN) {
++ mqpcb->send_psn = attr->sq_psn;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_PSN, 1);
++ }
++
++ if (attr_mask & IB_QP_DEST_QPN) {
++ mqpcb->dest_qp_nr = attr->dest_qp_num;
++ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_QP_NR, 1);
++ }
++
++ if (attr_mask & IB_QP_PATH_MIG_STATE) {
++ mqpcb->path_migration_state = attr->path_mig_state;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
++ }
++
++ if (attr_mask & IB_QP_CAP) {
++ mqpcb->max_nr_outst_send_wr = attr->cap.max_send_wr+1;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_SEND_WR, 1);
++ mqpcb->max_nr_outst_recv_wr = attr->cap.max_recv_wr+1;
++ update_mask |=
++ EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_RECV_WR, 1);
++ /* no support for max_send/recv_sge yet */
++ }
++
++ if (ehca_debug_level)
++ ehca_dmp(mqpcb, 4*70, "qp_num=%x", ibqp->qp_num);
++
++ h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ &my_qp->pf,
++ update_mask,
++ mqpcb, my_qp->galpas.kernel);
++
++ if (h_ret != H_SUCCESS) {
++ ret = ehca2ib_return_code(h_ret);
++ ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
++ "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
++ goto modify_qp_exit2;
++ }
++
++ if ((my_qp->qp_type == IB_QPT_UD ||
++ my_qp->qp_type == IB_QPT_GSI ||
++ my_qp->qp_type == IB_QPT_SMI) &&
++ statetrans == IB_QPST_SQE2RTS) {
++ /* doorbell to reprocessing wqes */
++ iosync(); /* serialize GAL register access */
++ hipz_update_sqa(my_qp, bad_wqe_cnt-1);
++ ehca_gen_dbg("doorbell for %x wqes", bad_wqe_cnt);
++ }
++
++ if (statetrans == IB_QPST_RESET2INIT ||
++ statetrans == IB_QPST_INIT2INIT) {
++ mqpcb->qp_enable = 1;
++ mqpcb->qp_state = EHCA_QPS_INIT;
++ update_mask = 0;
++ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1);
++
++ h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
++ my_qp->ipz_qp_handle,
++ &my_qp->pf,
++ update_mask,
++ mqpcb,
++ my_qp->galpas.kernel);
++
++ if (h_ret != H_SUCCESS) {
++ ret = ehca2ib_return_code(h_ret);
++ ehca_err(ibqp->device, "ENABLE in context of "
++ "RESET_2_INIT failed! Maybe you didn't get "
++ "a LID h_ret=%lx ehca_qp=%p qp_num=%x",
++ h_ret, my_qp, ibqp->qp_num);
++ goto modify_qp_exit2;
++ }
++ }
++
++ if (statetrans == IB_QPST_ANY2RESET) {
++ ipz_qeit_reset(&my_qp->ipz_rqueue);
++ ipz_qeit_reset(&my_qp->ipz_squeue);
++ }
++
++ if (attr_mask & IB_QP_QKEY)
++ my_qp->qkey = attr->qkey;
++
++modify_qp_exit2:
++ if (squeue_locked) { /* this means: sqe -> rts */
++ spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
++ my_qp->sqerr_purgeflag = 1;
++ }
++
++modify_qp_exit1:
++ kfree(mqpcb);
++
++ return ret;
++}
++
++int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
++ struct ib_udata *udata)
++{
++ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
++ struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
++ ib_pd);
++ u32 cur_pid = current->tgid;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(ibqp->pd->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ return internal_modify_qp(ibqp, attr, attr_mask, 0);
++}
++
++int ehca_query_qp(struct ib_qp *qp,
++ struct ib_qp_attr *qp_attr,
++ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
++{
++ struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
++ struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
++ ib_pd);
++ struct ehca_shca *shca = container_of(qp->device, struct ehca_shca,
++ ib_device);
++ struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
++ struct hcp_modify_qp_control_block *qpcb;
++ u32 cur_pid = current->tgid;
++ int cnt, ret = 0;
++ u64 h_ret;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(qp->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
++ ehca_err(qp->device,"Invalid attribute mask "
++ "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
++ my_qp, qp->qp_num, qp_attr_mask);
++ return -EINVAL;
++ }
++
++ qpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL );
++ if (!qpcb) {
++ ehca_err(qp->device,"Out of memory for qpcb "
++ "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
++ return -ENOMEM;
++ }
++
++ h_ret = hipz_h_query_qp(adapter_handle,
++ my_qp->ipz_qp_handle,
++ &my_qp->pf,
++ qpcb, my_qp->galpas.kernel);
++
++ if (h_ret != H_SUCCESS) {
++ ret = ehca2ib_return_code(h_ret);
++ ehca_err(qp->device,"hipz_h_query_qp() failed "
++ "ehca_qp=%p qp_num=%x h_ret=%lx",
++ my_qp, qp->qp_num, h_ret);
++ goto query_qp_exit1;
++ }
++
++ qp_attr->cur_qp_state = ehca2ib_qp_state(qpcb->qp_state);
++ qp_attr->qp_state = qp_attr->cur_qp_state;
++
++ if (qp_attr->cur_qp_state == -EINVAL) {
++ ret = -EINVAL;
++ ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
++ "ehca_qp=%p qp_num=%x",
++ qpcb->qp_state, my_qp, qp->qp_num);
++ goto query_qp_exit1;
++ }
++
++ if (qp_attr->qp_state == IB_QPS_SQD)
++ qp_attr->sq_draining = 1;
++
++ qp_attr->qkey = qpcb->qkey;
++ qp_attr->path_mtu = qpcb->path_mtu;
++ qp_attr->path_mig_state = qpcb->path_migration_state;
++ qp_attr->rq_psn = qpcb->receive_psn;
++ qp_attr->sq_psn = qpcb->send_psn;
++ qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
++ qp_attr->cap.max_send_wr = qpcb->max_nr_outst_send_wr-1;
++ qp_attr->cap.max_recv_wr = qpcb->max_nr_outst_recv_wr-1;
++ /* UD_AV CIRCUMVENTION */
++ if (my_qp->qp_type == IB_QPT_UD) {
++ qp_attr->cap.max_send_sge =
++ qpcb->actual_nr_sges_in_sq_wqe - 2;
++ qp_attr->cap.max_recv_sge =
++ qpcb->actual_nr_sges_in_rq_wqe - 2;
++ } else {
++ qp_attr->cap.max_send_sge =
++ qpcb->actual_nr_sges_in_sq_wqe;
++ qp_attr->cap.max_recv_sge =
++ qpcb->actual_nr_sges_in_rq_wqe;
++ }
++
++ qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size;
++ qp_attr->dest_qp_num = qpcb->dest_qp_nr;
++
++ qp_attr->pkey_index =
++ EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->prim_p_key_idx);
++
++ qp_attr->port_num =
++ EHCA_BMASK_GET(MQPCB_PRIM_PHYS_PORT, qpcb->prim_phys_port);
++
++ qp_attr->timeout = qpcb->timeout;
++ qp_attr->retry_cnt = qpcb->retry_count;
++ qp_attr->rnr_retry = qpcb->rnr_retry_count;
++
++ qp_attr->alt_pkey_index =
++ EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->alt_p_key_idx);
++
++ qp_attr->alt_port_num = qpcb->alt_phys_port;
++ qp_attr->alt_timeout = qpcb->timeout_al;
++
++ /* primary av */
++ qp_attr->ah_attr.sl = qpcb->service_level;
++
++ if (qpcb->send_grh_flag) {
++ qp_attr->ah_attr.ah_flags = IB_AH_GRH;
++ }
++
++ qp_attr->ah_attr.static_rate = qpcb->max_static_rate;
++ qp_attr->ah_attr.dlid = qpcb->dlid;
++ qp_attr->ah_attr.src_path_bits = qpcb->source_path_bits;
++ qp_attr->ah_attr.port_num = qp_attr->port_num;
++
++ /* primary GRH */
++ qp_attr->ah_attr.grh.traffic_class = qpcb->traffic_class;
++ qp_attr->ah_attr.grh.hop_limit = qpcb->hop_limit;
++ qp_attr->ah_attr.grh.sgid_index = qpcb->source_gid_idx;
++ qp_attr->ah_attr.grh.flow_label = qpcb->flow_label;
++
++ for (cnt = 0; cnt < 16; cnt++)
++ qp_attr->ah_attr.grh.dgid.raw[cnt] =
++ qpcb->dest_gid.byte[cnt];
++
++ /* alternate AV */
++ qp_attr->alt_ah_attr.sl = qpcb->service_level_al;
++ if (qpcb->send_grh_flag_al) {
++ qp_attr->alt_ah_attr.ah_flags = IB_AH_GRH;
++ }
++
++ qp_attr->alt_ah_attr.static_rate = qpcb->max_static_rate_al;
++ qp_attr->alt_ah_attr.dlid = qpcb->dlid_al;
++ qp_attr->alt_ah_attr.src_path_bits = qpcb->source_path_bits_al;
++
++ /* alternate GRH */
++ qp_attr->alt_ah_attr.grh.traffic_class = qpcb->traffic_class_al;
++ qp_attr->alt_ah_attr.grh.hop_limit = qpcb->hop_limit_al;
++ qp_attr->alt_ah_attr.grh.sgid_index = qpcb->source_gid_idx_al;
++ qp_attr->alt_ah_attr.grh.flow_label = qpcb->flow_label_al;
++
++ for (cnt = 0; cnt < 16; cnt++)
++ qp_attr->alt_ah_attr.grh.dgid.raw[cnt] =
++ qpcb->dest_gid_al.byte[cnt];
++
++ /* return init attributes given in ehca_create_qp */
++ if (qp_init_attr)
++ *qp_init_attr = my_qp->init_attr;
++
++ if (ehca_debug_level)
++ ehca_dmp(qpcb, 4*70, "qp_num=%x", qp->qp_num);
++
++query_qp_exit1:
++ kfree(qpcb);
++
++ return ret;
++}
++
++int ehca_destroy_qp(struct ib_qp *ibqp)
++{
++ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
++ struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
++ ib_device);
++ struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
++ ib_pd);
++ u32 cur_pid = current->tgid;
++ u32 qp_num = ibqp->qp_num;
++ int ret;
++ u64 h_ret;
++ u8 port_num;
++ enum ib_qp_type qp_type;
++ unsigned long flags;
++
++ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
++ my_pd->ownpid != cur_pid) {
++ ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
++ cur_pid, my_pd->ownpid);
++ return -EINVAL;
++ }
++
++ if (my_qp->send_cq) {
++ ret = ehca_cq_unassign_qp(my_qp->send_cq,
++ my_qp->real_qp_num);
++ if (ret) {
++ ehca_err(ibqp->device, "Couldn't unassign qp from "
++ "send_cq ret=%x qp_num=%x cq_num=%x", ret,
++ my_qp->ib_qp.qp_num, my_qp->send_cq->cq_number);
++ return ret;
++ }
++ }
++
++ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
++ idr_remove(&ehca_qp_idr, my_qp->token);
++ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
++
++ /* un-mmap if vma alloc */
++ if (my_qp->uspace_rqueue) {
++ ret = ehca_munmap(my_qp->uspace_rqueue,
++ my_qp->ipz_rqueue.queue_length);
++ if (ret)
++ ehca_err(ibqp->device, "Could not munmap rqueue "
++ "qp_num=%x", qp_num);
++ ret = ehca_munmap(my_qp->uspace_squeue,
++ my_qp->ipz_squeue.queue_length);
++ if (ret)
++ ehca_err(ibqp->device, "Could not munmap squeue "
++ "qp_num=%x", qp_num);
++ ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
++ if (ret)
++ ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
++ qp_num);
++ }
++
++ h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
++ if (h_ret != H_SUCCESS) {
++ ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
++ "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
++ return ehca2ib_return_code(h_ret);
++ }
++
++ port_num = my_qp->init_attr.port_num;
++ qp_type = my_qp->init_attr.qp_type;
++
++ /* no support for IB_QPT_SMI yet */
++ if (qp_type == IB_QPT_GSI) {
++ struct ib_event event;
++ ehca_info(ibqp->device, "device %s: port %x is inactive.",
++ shca->ib_device.name, port_num);
++ event.device = &shca->ib_device;
++ event.event = IB_EVENT_PORT_ERR;
++ event.element.port_num = port_num;
++ shca->sport[port_num - 1].port_state = IB_PORT_DOWN;
++ ib_dispatch_event(&event);
++ }
++
++ ipz_queue_dtor(&my_qp->ipz_rqueue);
++ ipz_queue_dtor(&my_qp->ipz_squeue);
++ kmem_cache_free(qp_cache, my_qp);
++ return 0;
++}
++
++int ehca_init_qp_cache(void)
++{
++ qp_cache = kmem_cache_create("ehca_cache_qp",
++ sizeof(struct ehca_qp), 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!qp_cache)
++ return -ENOMEM;
++ return 0;
++}
++
++void ehca_cleanup_qp_cache(void)
++{
++ if (qp_cache)
++ kmem_cache_destroy(qp_cache);
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
+new file mode 100644
+index 0000000..b46bda1
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
+@@ -0,0 +1,653 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * post_send/recv, poll_cq, req_notify
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm-powerpc/system.h>
++#include "ehca_classes.h"
++#include "ehca_tools.h"
++#include "ehca_qes.h"
++#include "ehca_iverbs.h"
++#include "hcp_if.h"
++#include "hipz_fns.h"
++
++static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
++ struct ehca_wqe *wqe_p,
++ struct ib_recv_wr *recv_wr)
++{
++ u8 cnt_ds;
++ if (unlikely((recv_wr->num_sge < 0) ||
++ (recv_wr->num_sge > ipz_rqueue->act_nr_of_sg))) {
++ ehca_gen_err("Invalid number of WQE SGE. "
++ "num_sqe=%x max_nr_of_sg=%x",
++ recv_wr->num_sge, ipz_rqueue->act_nr_of_sg);
++ return -EINVAL; /* invalid SG list length */
++ }
++
++ /* clear wqe header until sglist */
++ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
++
++ wqe_p->work_request_id = recv_wr->wr_id;
++ wqe_p->nr_of_data_seg = recv_wr->num_sge;
++
++ for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
++ wqe_p->u.all_rcv.sg_list[cnt_ds].vaddr =
++ recv_wr->sg_list[cnt_ds].addr;
++ wqe_p->u.all_rcv.sg_list[cnt_ds].lkey =
++ recv_wr->sg_list[cnt_ds].lkey;
++ wqe_p->u.all_rcv.sg_list[cnt_ds].length =
++ recv_wr->sg_list[cnt_ds].length;
++ }
++
++ if (ehca_debug_level) {
++ ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
++ ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
++ }
++
++ return 0;
++}
++
++#if defined(DEBUG_GSI_SEND_WR)
++
++/* need ib_mad struct */
++#include <rdma/ib_mad.h>
++
++static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
++{
++ int idx;
++ int j;
++ while (send_wr) {
++ struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
++ struct ib_sge *sge = send_wr->sg_list;
++ ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
++ "send_flags=%x opcode=%x",idx, send_wr->wr_id,
++ send_wr->num_sge, send_wr->send_flags,
++ send_wr->opcode);
++ if (mad_hdr) {
++ ehca_gen_dbg("send_wr#%x mad_hdr base_version=%x "
++ "mgmt_class=%x class_version=%x method=%x "
++ "status=%x class_specific=%x tid=%lx "
++ "attr_id=%x resv=%x attr_mod=%x",
++ idx, mad_hdr->base_version,
++ mad_hdr->mgmt_class,
++ mad_hdr->class_version, mad_hdr->method,
++ mad_hdr->status, mad_hdr->class_specific,
++ mad_hdr->tid, mad_hdr->attr_id,
++ mad_hdr->resv,
++ mad_hdr->attr_mod);
++ }
++ for (j = 0; j < send_wr->num_sge; j++) {
++ u8 *data = (u8 *) abs_to_virt(sge->addr);
++ ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
++ "lkey=%x",
++ idx, j, data, sge->length, sge->lkey);
++ /* assume length is n*16 */
++ ehca_dmp(data, sge->length, "send_wr#%x sge#%x",
++ idx, j);
++ sge++;
++ } /* eof for j */
++ idx++;
++ send_wr = send_wr->next;
++ } /* eof while send_wr */
++}
++
++#endif /* DEBUG_GSI_SEND_WR */
++
++static inline int ehca_write_swqe(struct ehca_qp *qp,
++ struct ehca_wqe *wqe_p,
++ const struct ib_send_wr *send_wr)
++{
++ u32 idx;
++ u64 dma_length;
++ struct ehca_av *my_av;
++ u32 remote_qkey = send_wr->wr.ud.remote_qkey;
++
++ if (unlikely((send_wr->num_sge < 0) ||
++ (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
++ ehca_gen_err("Invalid number of WQE SGE. "
++ "num_sqe=%x max_nr_of_sg=%x",
++ send_wr->num_sge, qp->ipz_squeue.act_nr_of_sg);
++ return -EINVAL; /* invalid SG list length */
++ }
++
++ /* clear wqe header until sglist */
++ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
++
++ wqe_p->work_request_id = send_wr->wr_id;
++
++ switch (send_wr->opcode) {
++ case IB_WR_SEND:
++ case IB_WR_SEND_WITH_IMM:
++ wqe_p->optype = WQE_OPTYPE_SEND;
++ break;
++ case IB_WR_RDMA_WRITE:
++ case IB_WR_RDMA_WRITE_WITH_IMM:
++ wqe_p->optype = WQE_OPTYPE_RDMAWRITE;
++ break;
++ case IB_WR_RDMA_READ:
++ wqe_p->optype = WQE_OPTYPE_RDMAREAD;
++ break;
++ default:
++ ehca_gen_err("Invalid opcode=%x", send_wr->opcode);
++ return -EINVAL; /* invalid opcode */
++ }
++
++ wqe_p->wqef = (send_wr->opcode) & WQEF_HIGH_NIBBLE;
++
++ wqe_p->wr_flag = 0;
++
++ if (send_wr->send_flags & IB_SEND_SIGNALED)
++ wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
++
++ if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
++ send_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
++ /* this might not work as long as HW does not support it */
++ wqe_p->immediate_data = be32_to_cpu(send_wr->imm_data);
++ wqe_p->wr_flag |= WQE_WRFLAG_IMM_DATA_PRESENT;
++ }
++
++ wqe_p->nr_of_data_seg = send_wr->num_sge;
++
++ switch (qp->qp_type) {
++ case IB_QPT_SMI:
++ case IB_QPT_GSI:
++ /* no break is intential here */
++ case IB_QPT_UD:
++ /* IB 1.2 spec C10-15 compliance */
++ if (send_wr->wr.ud.remote_qkey & 0x80000000)
++ remote_qkey = qp->qkey;
++
++ wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
++ wqe_p->local_ee_context_qkey = remote_qkey;
++ if (!send_wr->wr.ud.ah) {
++ ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
++ return -EINVAL;
++ }
++ my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah);
++ wqe_p->u.ud_av.ud_av = my_av->av;
++
++ /*
++ * omitted check of IB_SEND_INLINE
++ * since HW does not support it
++ */
++ for (idx = 0; idx < send_wr->num_sge; idx++) {
++ wqe_p->u.ud_av.sg_list[idx].vaddr =
++ send_wr->sg_list[idx].addr;
++ wqe_p->u.ud_av.sg_list[idx].lkey =
++ send_wr->sg_list[idx].lkey;
++ wqe_p->u.ud_av.sg_list[idx].length =
++ send_wr->sg_list[idx].length;
++ } /* eof for idx */
++ if (qp->qp_type == IB_QPT_SMI ||
++ qp->qp_type == IB_QPT_GSI)
++ wqe_p->u.ud_av.ud_av.pmtu = 1;
++ if (qp->qp_type == IB_QPT_GSI) {
++ wqe_p->pkeyi = send_wr->wr.ud.pkey_index;
++#ifdef DEBUG_GSI_SEND_WR
++ trace_send_wr_ud(send_wr);
++#endif /* DEBUG_GSI_SEND_WR */
++ }
++ break;
++
++ case IB_QPT_UC:
++ if (send_wr->send_flags & IB_SEND_FENCE)
++ wqe_p->wr_flag |= WQE_WRFLAG_FENCE;
++ /* no break is intentional here */
++ case IB_QPT_RC:
++ /* TODO: atomic not implemented */
++ wqe_p->u.nud.remote_virtual_adress =
++ send_wr->wr.rdma.remote_addr;
++ wqe_p->u.nud.rkey = send_wr->wr.rdma.rkey;
++
++ /*
++ * omitted checking of IB_SEND_INLINE
++ * since HW does not support it
++ */
++ dma_length = 0;
++ for (idx = 0; idx < send_wr->num_sge; idx++) {
++ wqe_p->u.nud.sg_list[idx].vaddr =
++ send_wr->sg_list[idx].addr;
++ wqe_p->u.nud.sg_list[idx].lkey =
++ send_wr->sg_list[idx].lkey;
++ wqe_p->u.nud.sg_list[idx].length =
++ send_wr->sg_list[idx].length;
++ dma_length += send_wr->sg_list[idx].length;
++ } /* eof idx */
++ wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
++
++ break;
++
++ default:
++ ehca_gen_err("Invalid qptype=%x", qp->qp_type);
++ return -EINVAL;
++ }
++
++ if (ehca_debug_level) {
++ ehca_gen_dbg("SEND WQE written into queue qp=%p ", qp);
++ ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "send wqe");
++ }
++ return 0;
++}
++
++/* map_ib_wc_status converts raw cqe_status to ib_wc_status */
++static inline void map_ib_wc_status(u32 cqe_status,
++ enum ib_wc_status *wc_status)
++{
++ if (unlikely(cqe_status & WC_STATUS_ERROR_BIT)) {
++ switch (cqe_status & 0x3F) {
++ case 0x01:
++ case 0x21:
++ *wc_status = IB_WC_LOC_LEN_ERR;
++ break;
++ case 0x02:
++ case 0x22:
++ *wc_status = IB_WC_LOC_QP_OP_ERR;
++ break;
++ case 0x03:
++ case 0x23:
++ *wc_status = IB_WC_LOC_EEC_OP_ERR;
++ break;
++ case 0x04:
++ case 0x24:
++ *wc_status = IB_WC_LOC_PROT_ERR;
++ break;
++ case 0x05:
++ case 0x25:
++ *wc_status = IB_WC_WR_FLUSH_ERR;
++ break;
++ case 0x06:
++ *wc_status = IB_WC_MW_BIND_ERR;
++ break;
++ case 0x07: /* remote error - look into bits 20:24 */
++ switch ((cqe_status
++ & WC_STATUS_REMOTE_ERROR_FLAGS) >> 11) {
++ case 0x0:
++ /*
++ * PSN Sequence Error!
++ * couldn't find a matching status!
++ */
++ *wc_status = IB_WC_GENERAL_ERR;
++ break;
++ case 0x1:
++ *wc_status = IB_WC_REM_INV_REQ_ERR;
++ break;
++ case 0x2:
++ *wc_status = IB_WC_REM_ACCESS_ERR;
++ break;
++ case 0x3:
++ *wc_status = IB_WC_REM_OP_ERR;
++ break;
++ case 0x4:
++ *wc_status = IB_WC_REM_INV_RD_REQ_ERR;
++ break;
++ }
++ break;
++ case 0x08:
++ *wc_status = IB_WC_RETRY_EXC_ERR;
++ break;
++ case 0x09:
++ *wc_status = IB_WC_RNR_RETRY_EXC_ERR;
++ break;
++ case 0x0A:
++ case 0x2D:
++ *wc_status = IB_WC_REM_ABORT_ERR;
++ break;
++ case 0x0B:
++ case 0x2E:
++ *wc_status = IB_WC_INV_EECN_ERR;
++ break;
++ case 0x0C:
++ case 0x2F:
++ *wc_status = IB_WC_INV_EEC_STATE_ERR;
++ break;
++ case 0x0D:
++ *wc_status = IB_WC_BAD_RESP_ERR;
++ break;
++ case 0x10:
++ /* WQE purged */
++ *wc_status = IB_WC_WR_FLUSH_ERR;
++ break;
++ default:
++ *wc_status = IB_WC_FATAL_ERR;
++
++ }
++ } else
++ *wc_status = IB_WC_SUCCESS;
++}
++
++int ehca_post_send(struct ib_qp *qp,
++ struct ib_send_wr *send_wr,
++ struct ib_send_wr **bad_send_wr)
++{
++ struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
++ struct ib_send_wr *cur_send_wr;
++ struct ehca_wqe *wqe_p;
++ int wqe_cnt = 0;
++ int ret = 0;
++ unsigned long spl_flags;
++
++ /* LOCK the QUEUE */
++ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
++
++ /* loop processes list of send reqs */
++ for (cur_send_wr = send_wr; cur_send_wr != NULL;
++ cur_send_wr = cur_send_wr->next) {
++ u64 start_offset = my_qp->ipz_squeue.current_q_offset;
++ /* get pointer next to free WQE */
++ wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
++ if (unlikely(!wqe_p)) {
++ /* too many posted work requests: queue overflow */
++ if (bad_send_wr)
++ *bad_send_wr = cur_send_wr;
++ if (wqe_cnt == 0) {
++ ret = -ENOMEM;
++ ehca_err(qp->device, "Too many posted WQEs "
++ "qp_num=%x", qp->qp_num);
++ }
++ goto post_send_exit0;
++ }
++ /* write a SEND WQE into the QUEUE */
++ ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
++ /*
++ * if something failed,
++ * reset the free entry pointer to the start value
++ */
++ if (unlikely(ret)) {
++ my_qp->ipz_squeue.current_q_offset = start_offset;
++ *bad_send_wr = cur_send_wr;
++ if (wqe_cnt == 0) {
++ ret = -EINVAL;
++ ehca_err(qp->device, "Could not write WQE "
++ "qp_num=%x", qp->qp_num);
++ }
++ goto post_send_exit0;
++ }
++ wqe_cnt++;
++ ehca_dbg(qp->device, "ehca_qp=%p qp_num=%x wqe_cnt=%d",
++ my_qp, qp->qp_num, wqe_cnt);
++ } /* eof for cur_send_wr */
++
++post_send_exit0:
++ /* UNLOCK the QUEUE */
++ spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
++ iosync(); /* serialize GAL register access */
++ hipz_update_sqa(my_qp, wqe_cnt);
++ return ret;
++}
++
++int ehca_post_recv(struct ib_qp *qp,
++ struct ib_recv_wr *recv_wr,
++ struct ib_recv_wr **bad_recv_wr)
++{
++ struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
++ struct ib_recv_wr *cur_recv_wr;
++ struct ehca_wqe *wqe_p;
++ int wqe_cnt = 0;
++ int ret = 0;
++ unsigned long spl_flags;
++
++ /* LOCK the QUEUE */
++ spin_lock_irqsave(&my_qp->spinlock_r, spl_flags);
++
++ /* loop processes list of send reqs */
++ for (cur_recv_wr = recv_wr; cur_recv_wr != NULL;
++ cur_recv_wr = cur_recv_wr->next) {
++ u64 start_offset = my_qp->ipz_rqueue.current_q_offset;
++ /* get pointer next to free WQE */
++ wqe_p = ipz_qeit_get_inc(&my_qp->ipz_rqueue);
++ if (unlikely(!wqe_p)) {
++ /* too many posted work requests: queue overflow */
++ if (bad_recv_wr)
++ *bad_recv_wr = cur_recv_wr;
++ if (wqe_cnt == 0) {
++ ret = -ENOMEM;
++ ehca_err(qp->device, "Too many posted WQEs "
++ "qp_num=%x", qp->qp_num);
++ }
++ goto post_recv_exit0;
++ }
++ /* write a RECV WQE into the QUEUE */
++ ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr);
++ /*
++ * if something failed,
++ * reset the free entry pointer to the start value
++ */
++ if (unlikely(ret)) {
++ my_qp->ipz_rqueue.current_q_offset = start_offset;
++ *bad_recv_wr = cur_recv_wr;
++ if (wqe_cnt == 0) {
++ ret = -EINVAL;
++ ehca_err(qp->device, "Could not write WQE "
++ "qp_num=%x", qp->qp_num);
++ }
++ goto post_recv_exit0;
++ }
++ wqe_cnt++;
++ ehca_gen_dbg("ehca_qp=%p qp_num=%x wqe_cnt=%d",
++ my_qp, qp->qp_num, wqe_cnt);
++ } /* eof for cur_recv_wr */
++
++post_recv_exit0:
++ spin_unlock_irqrestore(&my_qp->spinlock_r, spl_flags);
++ iosync(); /* serialize GAL register access */
++ hipz_update_rqa(my_qp, wqe_cnt);
++ return ret;
++}
++
++/*
++ * ib_wc_opcode table converts ehca wc opcode to ib
++ * Since we use zero to indicate invalid opcode, the actual ib opcode must
++ * be decremented!!!
++ */
++static const u8 ib_wc_opcode[255] = {
++ [0x01] = IB_WC_RECV+1,
++ [0x02] = IB_WC_RECV_RDMA_WITH_IMM+1,
++ [0x04] = IB_WC_BIND_MW+1,
++ [0x08] = IB_WC_FETCH_ADD+1,
++ [0x10] = IB_WC_COMP_SWAP+1,
++ [0x20] = IB_WC_RDMA_WRITE+1,
++ [0x40] = IB_WC_RDMA_READ+1,
++ [0x80] = IB_WC_SEND+1
++};
++
++/* internal function to poll one entry of cq */
++static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
++{
++ int ret = 0;
++ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
++ struct ehca_cqe *cqe;
++ int cqe_count = 0;
++
++poll_cq_one_read_cqe:
++ cqe = (struct ehca_cqe *)
++ ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
++ if (!cqe) {
++ ret = -EAGAIN;
++ ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p "
++ "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret);
++ goto poll_cq_one_exit0;
++ }
++
++ /* prevents loads being reordered across this point */
++ rmb();
++
++ cqe_count++;
++ if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
++ struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
++ int purgeflag;
++ unsigned long spl_flags;
++ if (!qp) {
++ ehca_err(cq->device, "cq_num=%x qp_num=%x "
++ "could not find qp -> ignore cqe",
++ my_cq->cq_number, cqe->local_qp_number);
++ ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x",
++ my_cq->cq_number, cqe->local_qp_number);
++ /* ignore this purged cqe */
++ goto poll_cq_one_read_cqe;
++ }
++ spin_lock_irqsave(&qp->spinlock_s, spl_flags);
++ purgeflag = qp->sqerr_purgeflag;
++ spin_unlock_irqrestore(&qp->spinlock_s, spl_flags);
++
++ if (purgeflag) {
++ ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
++ "src_qp=%x",
++ cqe->local_qp_number, cqe->remote_qp_number);
++ if (ehca_debug_level)
++ ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
++ cqe->local_qp_number,
++ cqe->remote_qp_number);
++ /*
++ * ignore this to avoid double cqes of bad wqe
++ * that caused sqe and turn off purge flag
++ */
++ qp->sqerr_purgeflag = 0;
++ goto poll_cq_one_read_cqe;
++ }
++ }
++
++ /* tracing cqe */
++ if (ehca_debug_level) {
++ ehca_dbg(cq->device,
++ "Received COMPLETION ehca_cq=%p cq_num=%x -----",
++ my_cq, my_cq->cq_number);
++ ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
++ my_cq, my_cq->cq_number);
++ ehca_dbg(cq->device,
++ "ehca_cq=%p cq_num=%x -------------------------",
++ my_cq, my_cq->cq_number);
++ }
++
++ /* we got a completion! */
++ wc->wr_id = cqe->work_request_id;
++
++ /* eval ib_wc_opcode */
++ wc->opcode = ib_wc_opcode[cqe->optype]-1;
++ if (unlikely(wc->opcode == -1)) {
++ ehca_err(cq->device, "Invalid cqe->OPType=%x cqe->status=%x "
++ "ehca_cq=%p cq_num=%x",
++ cqe->optype, cqe->status, my_cq, my_cq->cq_number);
++ /* dump cqe for other infos */
++ ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
++ my_cq, my_cq->cq_number);
++ /* update also queue adder to throw away this entry!!! */
++ goto poll_cq_one_exit0;
++ }
++ /* eval ib_wc_status */
++ if (unlikely(cqe->status & WC_STATUS_ERROR_BIT)) {
++ /* complete with errors */
++ map_ib_wc_status(cqe->status, &wc->status);
++ wc->vendor_err = wc->status;
++ } else
++ wc->status = IB_WC_SUCCESS;
++
++ wc->qp_num = cqe->local_qp_number;
++ wc->byte_len = cqe->nr_bytes_transferred;
++ wc->pkey_index = cqe->pkey_index;
++ wc->slid = cqe->rlid;
++ wc->dlid_path_bits = cqe->dlid;
++ wc->src_qp = cqe->remote_qp_number;
++ wc->wc_flags = cqe->w_completion_flags;
++ wc->imm_data = cpu_to_be32(cqe->immediate_data);
++ wc->sl = cqe->service_level;
++
++ if (wc->status != IB_WC_SUCCESS)
++ ehca_dbg(cq->device,
++ "ehca_cq=%p cq_num=%x WARNING unsuccessful cqe "
++ "OPType=%x status=%x qp_num=%x src_qp=%x wr_id=%lx "
++ "cqe=%p", my_cq, my_cq->cq_number, cqe->optype,
++ cqe->status, cqe->local_qp_number,
++ cqe->remote_qp_number, cqe->work_request_id, cqe);
++
++poll_cq_one_exit0:
++ if (cqe_count > 0)
++ hipz_update_feca(my_cq, cqe_count);
++
++ return ret;
++}
++
++int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
++{
++ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
++ int nr;
++ struct ib_wc *current_wc = wc;
++ int ret = 0;
++ unsigned long spl_flags;
++
++ if (num_entries < 1) {
++ ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
++ "cq_num=%x", num_entries, my_cq, my_cq->cq_number);
++ ret = -EINVAL;
++ goto poll_cq_exit0;
++ }
++
++ spin_lock_irqsave(&my_cq->spinlock, spl_flags);
++ for (nr = 0; nr < num_entries; nr++) {
++ ret = ehca_poll_cq_one(cq, current_wc);
++ if (ret)
++ break;
++ current_wc++;
++ } /* eof for nr */
++ spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
++ if (ret == -EAGAIN || !ret)
++ ret = nr;
++
++poll_cq_exit0:
++ return ret;
++}
++
++int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
++{
++ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
++
++ switch (cq_notify) {
++ case IB_CQ_SOLICITED:
++ hipz_set_cqx_n0(my_cq, 1);
++ break;
++ case IB_CQ_NEXT_COMP:
++ hipz_set_cqx_n1(my_cq, 1);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
+new file mode 100644
+index 0000000..9f16e9c
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
+@@ -0,0 +1,111 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * SQP functions
++ *
++ * Authors: Khadija Souissi <souissi at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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/module.h>
++#include <linux/err.h>
++#include "ehca_classes.h"
++#include "ehca_tools.h"
++#include "ehca_qes.h"
++#include "ehca_iverbs.h"
++#include "hcp_if.h"
++
++
++/**
++ * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue
++ * pair is created successfully, the corresponding port gets active.
++ *
++ * Define Special Queue pair 0 (SMI QP) is still not supported.
++ *
++ * @qp_init_attr: Queue pair init attributes with port and queue pair type
++ */
++
++u64 ehca_define_sqp(struct ehca_shca *shca,
++ struct ehca_qp *ehca_qp,
++ struct ib_qp_init_attr *qp_init_attr)
++{
++ u32 pma_qp_nr, bma_qp_nr;
++ u64 ret;
++ u8 port = qp_init_attr->port_num;
++ int counter;
++
++ shca->sport[port - 1].port_state = IB_PORT_DOWN;
++
++ switch (qp_init_attr->qp_type) {
++ case IB_QPT_SMI:
++ /* function not supported yet */
++ break;
++ case IB_QPT_GSI:
++ ret = hipz_h_define_aqp1(shca->ipz_hca_handle,
++ ehca_qp->ipz_qp_handle,
++ ehca_qp->galpas.kernel,
++ (u32) qp_init_attr->port_num,
++ &pma_qp_nr, &bma_qp_nr);
++
++ if (ret != H_SUCCESS) {
++ ehca_err(&shca->ib_device,
++ "Can't define AQP1 for port %x. rc=%lx",
++ port, ret);
++ return ret;
++ }
++ break;
++ default:
++ ehca_err(&shca->ib_device, "invalid qp_type=%x",
++ qp_init_attr->qp_type);
++ return H_PARAMETER;
++ }
++
++ for (counter = 0;
++ shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
++ counter < ehca_port_act_time;
++ counter++) {
++ ehca_dbg(&shca->ib_device, "... wait until port %x is active",
++ port);
++ msleep_interruptible(1000);
++ }
++
++ if (counter == ehca_port_act_time) {
++ ehca_err(&shca->ib_device, "Port %x is not active.", port);
++ return H_HARDWARE;
++ }
++
++ return H_SUCCESS;
++}
+diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
+new file mode 100644
+index 0000000..973c4b5
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_tools.h
+@@ -0,0 +1,173 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * auxiliary functions
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Khadija Souissi <souissik at de.ibm.com>
++ * Waleri Fomin <fomin at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++
++#ifndef EHCA_TOOLS_H
++#define EHCA_TOOLS_H
++
++#include <linux/kernel.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/idr.h>
++#include <linux/kthread.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/version.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
++#include <linux/device.h>
++
++#include <asm/abs_addr.h>
++#include <asm/ibmebus.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/hvcall.h>
++
++extern int ehca_debug_level;
++
++#define ehca_dbg(ib_dev, format, arg...) \
++ do { \
++ if (unlikely(ehca_debug_level)) \
++ dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \
++ "PU%04x EHCA_DBG:%s " format "\n", \
++ get_paca()->paca_index, __FUNCTION__, \
++ ## arg); \
++ } while (0)
++
++#define ehca_info(ib_dev, format, arg...) \
++ dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \
++ get_paca()->paca_index, __FUNCTION__, ## arg)
++
++#define ehca_warn(ib_dev, format, arg...) \
++ dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \
++ get_paca()->paca_index, __FUNCTION__, ## arg)
++
++#define ehca_err(ib_dev, format, arg...) \
++ dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \
++ get_paca()->paca_index, __FUNCTION__, ## arg)
++
++/* use this one only if no ib_dev available */
++#define ehca_gen_dbg(format, arg...) \
++ do { \
++ if (unlikely(ehca_debug_level)) \
++ printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
++ get_paca()->paca_index, __FUNCTION__, ## arg); \
++ } while (0)
++
++#define ehca_gen_warn(format, arg...) \
++ do { \
++ if (unlikely(ehca_debug_level)) \
++ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
++ get_paca()->paca_index, __FUNCTION__, ## arg); \
++ } while (0)
++
++#define ehca_gen_err(format, arg...) \
++ printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \
++ get_paca()->paca_index, __FUNCTION__, ## arg)
++
++/**
++ * ehca_dmp - printk a memory block, whose length is n*8 bytes.
++ * Each line has the following layout:
++ * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
++ */
++#define ehca_dmp(adr, len, format, args...) \
++ do { \
++ unsigned int x; \
++ unsigned int l = (unsigned int)(len); \
++ unsigned char *deb = (unsigned char*)(adr); \
++ for (x = 0; x < l; x += 16) { \
++ printk("EHCA_DMP:%s " format \
++ " adr=%p ofs=%04x %016lx %016lx\n", \
++ __FUNCTION__, ##args, deb, x, \
++ *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
++ deb += 16; \
++ } \
++ } while (0)
++
++/* define a bitmask, little endian version */
++#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
++
++/* define a bitmask, the ibm way... */
++#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
++
++/* internal function, don't use */
++#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
++
++/* internal function, don't use */
++#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
++
++/**
++ * EHCA_BMASK_SET - return value shifted and masked by mask
++ * variable|=EHCA_BMASK_SET(MY_MASK,0x4711) ORs the bits in variable
++ * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
++ * in variable
++ */
++#define EHCA_BMASK_SET(mask,value) \
++ ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
++
++/**
++ * EHCA_BMASK_GET - extract a parameter from value by mask
++ */
++#define EHCA_BMASK_GET(mask,value) \
++ (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
++
++
++/* Converts ehca to ib return code */
++static inline int ehca2ib_return_code(u64 ehca_rc)
++{
++ switch (ehca_rc) {
++ case H_SUCCESS:
++ return 0;
++ case H_BUSY:
++ return -EBUSY;
++ case H_NO_MEM:
++ return -ENOMEM;
++ default:
++ return -EINVAL;
++ }
++}
++
++
++#endif /* EHCA_TOOLS_H */
+diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
+new file mode 100644
+index 0000000..e08764e
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
+@@ -0,0 +1,392 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * userspace support verbs
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/current.h>
++
++#include "ehca_classes.h"
++#include "ehca_iverbs.h"
++#include "ehca_mrmw.h"
++#include "ehca_tools.h"
++#include "hcp_if.h"
++
++struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
++ struct ib_udata *udata)
++{
++ struct ehca_ucontext *my_context;
++
++ my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
++ if (!my_context) {
++ ehca_err(device, "Out of memory device=%p", device);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ return &my_context->ib_ucontext;
++}
++
++int ehca_dealloc_ucontext(struct ib_ucontext *context)
++{
++ kfree(container_of(context, struct ehca_ucontext, ib_ucontext));
++ return 0;
++}
++
++struct page *ehca_nopage(struct vm_area_struct *vma,
++ unsigned long address, int *type)
++{
++ struct page *mypage = NULL;
++ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
++ u32 idr_handle = fileoffset >> 32;
++ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
++ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
++ u32 cur_pid = current->tgid;
++ unsigned long flags;
++ struct ehca_cq *cq;
++ struct ehca_qp *qp;
++ struct ehca_pd *pd;
++ u64 offset;
++ void *vaddr;
++
++ switch (q_type) {
++ case 1: /* CQ */
++ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
++ cq = idr_find(&ehca_cq_idr, idr_handle);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
++
++ /* make sure this mmap really belongs to the authorized user */
++ if (!cq) {
++ ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
++ return NOPAGE_SIGBUS;
++ }
++
++ if (cq->ownpid != cur_pid) {
++ ehca_err(cq->ib_cq.device,
++ "Invalid caller pid=%x ownpid=%x",
++ cur_pid, cq->ownpid);
++ return NOPAGE_SIGBUS;
++ }
++
++ if (rsrc_type == 2) {
++ ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
++ offset = address - vma->vm_start;
++ vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
++ ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
++ offset, vaddr);
++ mypage = virt_to_page(vaddr);
++ }
++ break;
++
++ case 2: /* QP */
++ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
++ qp = idr_find(&ehca_qp_idr, idr_handle);
++ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
++
++ /* make sure this mmap really belongs to the authorized user */
++ if (!qp) {
++ ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
++ return NOPAGE_SIGBUS;
++ }
++
++ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
++ if (pd->ownpid != cur_pid) {
++ ehca_err(qp->ib_qp.device,
++ "Invalid caller pid=%x ownpid=%x",
++ cur_pid, pd->ownpid);
++ return NOPAGE_SIGBUS;
++ }
++
++ if (rsrc_type == 2) { /* rqueue */
++ ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
++ offset = address - vma->vm_start;
++ vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
++ ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
++ offset, vaddr);
++ mypage = virt_to_page(vaddr);
++ } else if (rsrc_type == 3) { /* squeue */
++ ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
++ offset = address - vma->vm_start;
++ vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
++ ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
++ offset, vaddr);
++ mypage = virt_to_page(vaddr);
++ }
++ break;
++
++ default:
++ ehca_gen_err("bad queue type %x", q_type);
++ return NOPAGE_SIGBUS;
++ }
++
++ if (!mypage) {
++ ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
++ return NOPAGE_SIGBUS;
++ }
++ get_page(mypage);
++
++ return mypage;
++}
++
++static struct vm_operations_struct ehcau_vm_ops = {
++ .nopage = ehca_nopage,
++};
++
++int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
++{
++ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
++ u32 idr_handle = fileoffset >> 32;
++ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
++ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
++ u32 cur_pid = current->tgid;
++ u32 ret;
++ u64 vsize, physical;
++ unsigned long flags;
++ struct ehca_cq *cq;
++ struct ehca_qp *qp;
++ struct ehca_pd *pd;
++
++ switch (q_type) {
++ case 1: /* CQ */
++ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
++ cq = idr_find(&ehca_cq_idr, idr_handle);
++ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
++
++ /* make sure this mmap really belongs to the authorized user */
++ if (!cq)
++ return -EINVAL;
++
++ if (cq->ownpid != cur_pid) {
++ ehca_err(cq->ib_cq.device,
++ "Invalid caller pid=%x ownpid=%x",
++ cur_pid, cq->ownpid);
++ return -ENOMEM;
++ }
++
++ if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
++ return -EINVAL;
++
++ switch (rsrc_type) {
++ case 1: /* galpa fw handle */
++ ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
++ vma->vm_flags |= VM_RESERVED;
++ vsize = vma->vm_end - vma->vm_start;
++ if (vsize != EHCA_PAGESIZE) {
++ ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
++ vma->vm_end - vma->vm_start);
++ return -EINVAL;
++ }
++
++ physical = cq->galpas.user.fw_handle;
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++ vma->vm_flags |= VM_IO | VM_RESERVED;
++
++ ehca_dbg(cq->ib_cq.device,
++ "vsize=%lx physical=%lx", vsize, physical);
++ ret = remap_pfn_range(vma, vma->vm_start,
++ physical >> PAGE_SHIFT, vsize,
++ vma->vm_page_prot);
++ if (ret) {
++ ehca_err(cq->ib_cq.device,
++ "remap_pfn_range() failed ret=%x",
++ ret);
++ return -ENOMEM;
++ }
++ break;
++
++ case 2: /* cq queue_addr */
++ ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_ops = &ehcau_vm_ops;
++ break;
++
++ default:
++ ehca_err(cq->ib_cq.device, "bad resource type %x",
++ rsrc_type);
++ return -EINVAL;
++ }
++ break;
++
++ case 2: /* QP */
++ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
++ qp = idr_find(&ehca_qp_idr, idr_handle);
++ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
++
++ /* make sure this mmap really belongs to the authorized user */
++ if (!qp)
++ return -EINVAL;
++
++ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
++ if (pd->ownpid != cur_pid) {
++ ehca_err(qp->ib_qp.device,
++ "Invalid caller pid=%x ownpid=%x",
++ cur_pid, pd->ownpid);
++ return -ENOMEM;
++ }
++
++ if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
++ return -EINVAL;
++
++ switch (rsrc_type) {
++ case 1: /* galpa fw handle */
++ ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
++ vma->vm_flags |= VM_RESERVED;
++ vsize = vma->vm_end - vma->vm_start;
++ if (vsize != EHCA_PAGESIZE) {
++ ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
++ vma->vm_end - vma->vm_start);
++ return -EINVAL;
++ }
++
++ physical = qp->galpas.user.fw_handle;
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++ vma->vm_flags |= VM_IO | VM_RESERVED;
++
++ ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
++ vsize, physical);
++ ret = remap_pfn_range(vma, vma->vm_start,
++ physical >> PAGE_SHIFT, vsize,
++ vma->vm_page_prot);
++ if (ret) {
++ ehca_err(qp->ib_qp.device,
++ "remap_pfn_range() failed ret=%x",
++ ret);
++ return -ENOMEM;
++ }
++ break;
++
++ case 2: /* qp rqueue_addr */
++ ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_ops = &ehcau_vm_ops;
++ break;
++
++ case 3: /* qp squeue_addr */
++ ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_ops = &ehcau_vm_ops;
++ break;
++
++ default:
++ ehca_err(qp->ib_qp.device, "bad resource type %x",
++ rsrc_type);
++ return -EINVAL;
++ }
++ break;
++
++ default:
++ ehca_gen_err("bad queue type %x", q_type);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
++ struct vm_area_struct **vma)
++{
++ down_write(¤t->mm->mmap_sem);
++ *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
++ MAP_SHARED | MAP_ANONYMOUS,
++ foffset);
++ up_write(¤t->mm->mmap_sem);
++ if (!(*mapped)) {
++ ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
++ foffset, length);
++ return -EINVAL;
++ }
++
++ *vma = find_vma(current->mm, (u64)*mapped);
++ if (!(*vma)) {
++ down_write(¤t->mm->mmap_sem);
++ do_munmap(current->mm, 0, length);
++ up_write(¤t->mm->mmap_sem);
++ ehca_gen_err("couldn't find vma queue=%p", *mapped);
++ return -EINVAL;
++ }
++ (*vma)->vm_flags |= VM_RESERVED;
++ (*vma)->vm_ops = &ehcau_vm_ops;
++
++ return 0;
++}
++
++int ehca_mmap_register(u64 physical, void **mapped,
++ struct vm_area_struct **vma)
++{
++ int ret;
++ unsigned long vsize;
++ /* ehca hw supports only 4k page */
++ ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
++ if (ret) {
++ ehca_gen_err("could'nt mmap physical=%lx", physical);
++ return ret;
++ }
++
++ (*vma)->vm_flags |= VM_RESERVED;
++ vsize = (*vma)->vm_end - (*vma)->vm_start;
++ if (vsize != EHCA_PAGESIZE) {
++ ehca_gen_err("invalid vsize=%lx",
++ (*vma)->vm_end - (*vma)->vm_start);
++ return -EINVAL;
++ }
++
++ (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
++ (*vma)->vm_flags |= VM_IO | VM_RESERVED;
++
++ ret = remap_pfn_range((*vma), (*vma)->vm_start,
++ physical >> PAGE_SHIFT, vsize,
++ (*vma)->vm_page_prot);
++ if (ret) {
++ ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
++ return -ENOMEM;
++ }
++
++ return 0;
++
++}
++
++int ehca_munmap(unsigned long addr, size_t len) {
++ int ret = 0;
++ struct mm_struct *mm = current->mm;
++ if (mm) {
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, addr, len);
++ up_write(&mm->mmap_sem);
++ }
++ return ret;
++}
+diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
+new file mode 100644
+index 0000000..3fb46e6
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hcp_if.c
+@@ -0,0 +1,874 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Firmware Infiniband Interface code for POWER
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Gerd Bayer <gerd.bayer at de.ibm.com>
++ * Waleri Fomin <fomin at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <asm/hvcall.h>
++#include "ehca_tools.h"
++#include "hcp_if.h"
++#include "hcp_phyp.h"
++#include "hipz_fns.h"
++#include "ipz_pt_fn.h"
++
++#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11)
++#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12)
++#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15)
++#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18)
++#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21)
++#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23)
++#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31)
++#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63)
++
++#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15)
++#define H_ALL_RES_QP_MAX_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31)
++#define H_ALL_RES_QP_MAX_SEND_SGE EHCA_BMASK_IBM(32, 39)
++#define H_ALL_RES_QP_MAX_RECV_SGE EHCA_BMASK_IBM(40, 47)
++
++#define H_ALL_RES_QP_ACT_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31)
++#define H_ALL_RES_QP_ACT_OUTST_RECV_WR EHCA_BMASK_IBM(48, 63)
++#define H_ALL_RES_QP_ACT_SEND_SGE EHCA_BMASK_IBM(8, 15)
++#define H_ALL_RES_QP_ACT_RECV_SGE EHCA_BMASK_IBM(24, 31)
++
++#define H_ALL_RES_QP_SQUEUE_SIZE_PAGES EHCA_BMASK_IBM(0, 31)
++#define H_ALL_RES_QP_RQUEUE_SIZE_PAGES EHCA_BMASK_IBM(32, 63)
++
++/* direct access qp controls */
++#define DAQP_CTRL_ENABLE 0x01
++#define DAQP_CTRL_SEND_COMP 0x20
++#define DAQP_CTRL_RECV_COMP 0x40
++
++static u32 get_longbusy_msecs(int longbusy_rc)
++{
++ switch (longbusy_rc) {
++ case H_LONG_BUSY_ORDER_1_MSEC:
++ return 1;
++ case H_LONG_BUSY_ORDER_10_MSEC:
++ return 10;
++ case H_LONG_BUSY_ORDER_100_MSEC:
++ return 100;
++ case H_LONG_BUSY_ORDER_1_SEC:
++ return 1000;
++ case H_LONG_BUSY_ORDER_10_SEC:
++ return 10000;
++ case H_LONG_BUSY_ORDER_100_SEC:
++ return 100000;
++ default:
++ return 1;
++ }
++}
++
++static long ehca_plpar_hcall_norets(unsigned long opcode,
++ unsigned long arg1,
++ unsigned long arg2,
++ unsigned long arg3,
++ unsigned long arg4,
++ unsigned long arg5,
++ unsigned long arg6,
++ unsigned long arg7)
++{
++ long ret;
++ int i, sleep_msecs;
++
++ ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
++ "arg5=%lx arg6=%lx arg7=%lx",
++ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
++
++ for (i = 0; i < 5; i++) {
++ ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
++ arg5, arg6, arg7);
++
++ if (H_IS_LONG_BUSY(ret)) {
++ sleep_msecs = get_longbusy_msecs(ret);
++ msleep_interruptible(sleep_msecs);
++ continue;
++ }
++
++ if (ret < H_SUCCESS)
++ ehca_gen_err("opcode=%lx ret=%lx"
++ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
++ " arg5=%lx arg6=%lx arg7=%lx ",
++ opcode, ret,
++ arg1, arg2, arg3, arg4, arg5,
++ arg6, arg7);
++
++ ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret);
++ return ret;
++
++ }
++
++ return H_BUSY;
++}
++
++static long ehca_plpar_hcall9(unsigned long opcode,
++ unsigned long *outs, /* array of 9 outputs */
++ unsigned long arg1,
++ unsigned long arg2,
++ unsigned long arg3,
++ unsigned long arg4,
++ unsigned long arg5,
++ unsigned long arg6,
++ unsigned long arg7,
++ unsigned long arg8,
++ unsigned long arg9)
++{
++ long ret;
++ int i, sleep_msecs;
++
++ ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
++ "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
++ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
++ arg8, arg9);
++
++ for (i = 0; i < 5; i++) {
++ ret = plpar_hcall9(opcode, outs,
++ arg1, arg2, arg3, arg4, arg5,
++ arg6, arg7, arg8, arg9);
++
++ if (H_IS_LONG_BUSY(ret)) {
++ sleep_msecs = get_longbusy_msecs(ret);
++ msleep_interruptible(sleep_msecs);
++ continue;
++ }
++
++ if (ret < H_SUCCESS)
++ ehca_gen_err("opcode=%lx ret=%lx"
++ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
++ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
++ " arg9=%lx"
++ " out1=%lx out2=%lx out3=%lx out4=%lx"
++ " out5=%lx out6=%lx out7=%lx out8=%lx"
++ " out9=%lx",
++ opcode, ret,
++ arg1, arg2, arg3, arg4, arg5,
++ arg6, arg7, arg8, arg9,
++ outs[0], outs[1], outs[2], outs[3],
++ outs[4], outs[5], outs[6], outs[7],
++ outs[8]);
++
++ ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
++ "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx "
++ "out9=%lx",
++ opcode, ret, outs[0], outs[1], outs[2], outs[3],
++ outs[4], outs[5], outs[6], outs[7], outs[8]);
++ return ret;
++
++ }
++
++ return H_BUSY;
++}
++u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_pfeq *pfeq,
++ const u32 neq_control,
++ const u32 number_of_entries,
++ struct ipz_eq_handle *eq_handle,
++ u32 *act_nr_of_entries,
++ u32 *act_pages,
++ u32 *eq_ist)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++ u64 allocate_controls;
++
++ /* resource type */
++ allocate_controls = 3ULL;
++
++ /* ISN is associated */
++ if (neq_control != 1)
++ allocate_controls = (1ULL << (63 - 7)) | allocate_controls;
++ else /* notification event queue */
++ allocate_controls = (1ULL << 63) | allocate_controls;
++
++ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
++ adapter_handle.handle, /* r4 */
++ allocate_controls, /* r5 */
++ number_of_entries, /* r6 */
++ 0, 0, 0, 0, 0, 0);
++ eq_handle->handle = outs[0];
++ *act_nr_of_entries = (u32)outs[3];
++ *act_pages = (u32)outs[4];
++ *eq_ist = (u32)outs[5];
++
++ if (ret == H_NOT_ENOUGH_RESOURCES)
++ ehca_gen_err("Not enough resource - ret=%lx ", ret);
++
++ return ret;
++}
++
++u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
++ struct ipz_eq_handle eq_handle,
++ const u64 event_mask)
++{
++ return ehca_plpar_hcall_norets(H_RESET_EVENTS,
++ adapter_handle.handle, /* r4 */
++ eq_handle.handle, /* r5 */
++ event_mask, /* r6 */
++ 0, 0, 0, 0);
++}
++
++u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_cq *cq,
++ struct ehca_alloc_cq_parms *param)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
++ adapter_handle.handle, /* r4 */
++ 2, /* r5 */
++ param->eq_handle.handle, /* r6 */
++ cq->token, /* r7 */
++ param->nr_cqe, /* r8 */
++ 0, 0, 0, 0);
++ cq->ipz_cq_handle.handle = outs[0];
++ param->act_nr_of_entries = (u32)outs[3];
++ param->act_pages = (u32)outs[4];
++
++ if (ret == H_SUCCESS)
++ hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
++
++ if (ret == H_NOT_ENOUGH_RESOURCES)
++ ehca_gen_err("Not enough resources. ret=%lx", ret);
++
++ return ret;
++}
++
++u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_qp *qp,
++ struct ehca_alloc_qp_parms *parms)
++{
++ u64 ret;
++ u64 allocate_controls;
++ u64 max_r10_reg;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++ u16 max_nr_receive_wqes = qp->init_attr.cap.max_recv_wr + 1;
++ u16 max_nr_send_wqes = qp->init_attr.cap.max_send_wr + 1;
++ int daqp_ctrl = parms->daqp_ctrl;
++
++ allocate_controls =
++ EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS,
++ (daqp_ctrl & DAQP_CTRL_ENABLE) ? 1 : 0)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
++ (daqp_ctrl & DAQP_CTRL_RECV_COMP) ? 1 : 0)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
++ (daqp_ctrl & DAQP_CTRL_SEND_COMP) ? 1 : 0)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL,
++ parms->ud_av_l_key_ctl)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1);
++
++ max_r10_reg =
++ EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
++ max_nr_send_wqes)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
++ max_nr_receive_wqes)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
++ parms->max_send_sge)
++ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
++ parms->max_recv_sge);
++
++ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
++ adapter_handle.handle, /* r4 */
++ allocate_controls, /* r5 */
++ qp->send_cq->ipz_cq_handle.handle,
++ qp->recv_cq->ipz_cq_handle.handle,
++ parms->ipz_eq_handle.handle,
++ ((u64)qp->token << 32) | parms->pd.value,
++ max_r10_reg, /* r10 */
++ parms->ud_av_l_key_ctl, /* r11 */
++ 0);
++ qp->ipz_qp_handle.handle = outs[0];
++ qp->real_qp_num = (u32)outs[1];
++ parms->act_nr_send_sges =
++ (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
++ parms->act_nr_recv_wqes =
++ (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
++ parms->act_nr_send_sges =
++ (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
++ parms->act_nr_recv_sges =
++ (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
++ parms->nr_sq_pages =
++ (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
++ parms->nr_rq_pages =
++ (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
++
++ if (ret == H_SUCCESS)
++ hcp_galpas_ctor(&qp->galpas, outs[6], outs[6]);
++
++ if (ret == H_NOT_ENOUGH_RESOURCES)
++ ehca_gen_err("Not enough resources. ret=%lx", ret);
++
++ return ret;
++}
++
++u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
++ const u8 port_id,
++ struct hipz_query_port *query_port_response_block)
++{
++ u64 ret;
++ u64 r_cb = virt_to_abs(query_port_response_block);
++
++ if (r_cb & (EHCA_PAGESIZE-1)) {
++ ehca_gen_err("response block not page aligned");
++ return H_PARAMETER;
++ }
++
++ ret = ehca_plpar_hcall_norets(H_QUERY_PORT,
++ adapter_handle.handle, /* r4 */
++ port_id, /* r5 */
++ r_cb, /* r6 */
++ 0, 0, 0, 0);
++
++ if (ehca_debug_level)
++ ehca_dmp(query_port_response_block, 64, "response_block");
++
++ return ret;
++}
++
++u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
++ struct hipz_query_hca *query_hca_rblock)
++{
++ u64 r_cb = virt_to_abs(query_hca_rblock);
++
++ if (r_cb & (EHCA_PAGESIZE-1)) {
++ ehca_gen_err("response_block=%p not page aligned",
++ query_hca_rblock);
++ return H_PARAMETER;
++ }
++
++ return ehca_plpar_hcall_norets(H_QUERY_HCA,
++ adapter_handle.handle, /* r4 */
++ r_cb, /* r5 */
++ 0, 0, 0, 0, 0);
++}
++
++u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 resource_handle,
++ const u64 logical_address_of_page,
++ u64 count)
++{
++ return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
++ adapter_handle.handle, /* r4 */
++ queue_type | pagesize << 8, /* r5 */
++ resource_handle, /* r6 */
++ logical_address_of_page, /* r7 */
++ count, /* r8 */
++ 0, 0);
++}
++
++u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_eq_handle eq_handle,
++ struct ehca_pfeq *pfeq,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count)
++{
++ if (count != 1) {
++ ehca_gen_err("Ppage counter=%lx", count);
++ return H_PARAMETER;
++ }
++ return hipz_h_register_rpage(adapter_handle,
++ pagesize,
++ queue_type,
++ eq_handle.handle,
++ logical_address_of_page, count);
++}
++
++u64 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle,
++ u32 ist)
++{
++ u64 ret;
++ ret = ehca_plpar_hcall_norets(H_QUERY_INT_STATE,
++ adapter_handle.handle, /* r4 */
++ ist, /* r5 */
++ 0, 0, 0, 0, 0);
++
++ if (ret != H_SUCCESS && ret != H_BUSY)
++ ehca_gen_err("Could not query interrupt state.");
++
++ return ret;
++}
++
++u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_cq_handle cq_handle,
++ struct ehca_pfcq *pfcq,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count,
++ const struct h_galpa gal)
++{
++ if (count != 1) {
++ ehca_gen_err("Page counter=%lx", count);
++ return H_PARAMETER;
++ }
++
++ return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
++ cq_handle.handle, logical_address_of_page,
++ count);
++}
++
++u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count,
++ const struct h_galpa galpa)
++{
++ if (count != 1) {
++ ehca_gen_err("Page counter=%lx", count);
++ return H_PARAMETER;
++ }
++
++ return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
++ qp_handle.handle,logical_address_of_page,
++ count);
++}
++
++u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ void **log_addr_next_sq_wqe2processed,
++ void **log_addr_next_rq_wqe2processed,
++ int dis_and_get_function_code)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
++ adapter_handle.handle, /* r4 */
++ dis_and_get_function_code, /* r5 */
++ qp_handle.handle, /* r6 */
++ 0, 0, 0, 0, 0, 0);
++ if (log_addr_next_sq_wqe2processed)
++ *log_addr_next_sq_wqe2processed = (void*)outs[0];
++ if (log_addr_next_rq_wqe2processed)
++ *log_addr_next_rq_wqe2processed = (void*)outs[1];
++
++ return ret;
++}
++
++u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ const u64 update_mask,
++ struct hcp_modify_qp_control_block *mqpcb,
++ struct h_galpa gal)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++ ret = ehca_plpar_hcall9(H_MODIFY_QP, outs,
++ adapter_handle.handle, /* r4 */
++ qp_handle.handle, /* r5 */
++ update_mask, /* r6 */
++ virt_to_abs(mqpcb), /* r7 */
++ 0, 0, 0, 0, 0);
++
++ if (ret == H_NOT_ENOUGH_RESOURCES)
++ ehca_gen_err("Insufficient resources ret=%lx", ret);
++
++ return ret;
++}
++
++u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ struct hcp_modify_qp_control_block *qqpcb,
++ struct h_galpa gal)
++{
++ return ehca_plpar_hcall_norets(H_QUERY_QP,
++ adapter_handle.handle, /* r4 */
++ qp_handle.handle, /* r5 */
++ virt_to_abs(qqpcb), /* r6 */
++ 0, 0, 0, 0);
++}
++
++u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_qp *qp)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = hcp_galpas_dtor(&qp->galpas);
++ if (ret) {
++ ehca_gen_err("Could not destruct qp->galpas");
++ return H_RESOURCE;
++ }
++ ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
++ adapter_handle.handle, /* r4 */
++ /* function code */
++ 1, /* r5 */
++ qp->ipz_qp_handle.handle, /* r6 */
++ 0, 0, 0, 0, 0, 0);
++ if (ret == H_HARDWARE)
++ ehca_gen_err("HCA not operational. ret=%lx", ret);
++
++ ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
++ adapter_handle.handle, /* r4 */
++ qp->ipz_qp_handle.handle, /* r5 */
++ 0, 0, 0, 0, 0);
++
++ if (ret == H_RESOURCE)
++ ehca_gen_err("Resource still in use. ret=%lx", ret);
++
++ return ret;
++}
++
++u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u32 port)
++{
++ return ehca_plpar_hcall_norets(H_DEFINE_AQP0,
++ adapter_handle.handle, /* r4 */
++ qp_handle.handle, /* r5 */
++ port, /* r6 */
++ 0, 0, 0, 0);
++}
++
++u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u32 port, u32 * pma_qp_nr,
++ u32 * bma_qp_nr)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_DEFINE_AQP1, outs,
++ adapter_handle.handle, /* r4 */
++ qp_handle.handle, /* r5 */
++ port, /* r6 */
++ 0, 0, 0, 0, 0, 0);
++ *pma_qp_nr = (u32)outs[0];
++ *bma_qp_nr = (u32)outs[1];
++
++ if (ret == H_ALIAS_EXIST)
++ ehca_gen_err("AQP1 already exists. ret=%lx", ret);
++
++ return ret;
++}
++
++u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u16 mcg_dlid,
++ u64 subnet_prefix, u64 interface_id)
++{
++ u64 ret;
++
++ ret = ehca_plpar_hcall_norets(H_ATTACH_MCQP,
++ adapter_handle.handle, /* r4 */
++ qp_handle.handle, /* r5 */
++ mcg_dlid, /* r6 */
++ interface_id, /* r7 */
++ subnet_prefix, /* r8 */
++ 0, 0);
++
++ if (ret == H_NOT_ENOUGH_RESOURCES)
++ ehca_gen_err("Not enough resources. ret=%lx", ret);
++
++ return ret;
++}
++
++u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u16 mcg_dlid,
++ u64 subnet_prefix, u64 interface_id)
++{
++ return ehca_plpar_hcall_norets(H_DETACH_MCQP,
++ adapter_handle.handle, /* r4 */
++ qp_handle.handle, /* r5 */
++ mcg_dlid, /* r6 */
++ interface_id, /* r7 */
++ subnet_prefix, /* r8 */
++ 0, 0);
++}
++
++u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_cq *cq,
++ u8 force_flag)
++{
++ u64 ret;
++
++ ret = hcp_galpas_dtor(&cq->galpas);
++ if (ret) {
++ ehca_gen_err("Could not destruct cp->galpas");
++ return H_RESOURCE;
++ }
++
++ ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
++ adapter_handle.handle, /* r4 */
++ cq->ipz_cq_handle.handle, /* r5 */
++ force_flag != 0 ? 1L : 0L, /* r6 */
++ 0, 0, 0, 0);
++
++ if (ret == H_RESOURCE)
++ ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret);
++
++ return ret;
++}
++
++u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_eq *eq)
++{
++ u64 ret;
++
++ ret = hcp_galpas_dtor(&eq->galpas);
++ if (ret) {
++ ehca_gen_err("Could not destruct eq->galpas");
++ return H_RESOURCE;
++ }
++
++ ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
++ adapter_handle.handle, /* r4 */
++ eq->ipz_eq_handle.handle, /* r5 */
++ 0, 0, 0, 0, 0);
++
++ if (ret == H_RESOURCE)
++ ehca_gen_err("Resource in use. ret=%lx ", ret);
++
++ return ret;
++}
++
++u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const u64 vaddr,
++ const u64 length,
++ const u32 access_ctrl,
++ const struct ipz_pd pd,
++ struct ehca_mr_hipzout_parms *outparms)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
++ adapter_handle.handle, /* r4 */
++ 5, /* r5 */
++ vaddr, /* r6 */
++ length, /* r7 */
++ (((u64)access_ctrl) << 32ULL), /* r8 */
++ pd.value, /* r9 */
++ 0, 0, 0);
++ outparms->handle.handle = outs[0];
++ outparms->lkey = (u32)outs[2];
++ outparms->rkey = (u32)outs[3];
++
++ return ret;
++}
++
++u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count)
++{
++ u64 ret;
++
++ if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
++ ehca_gen_err("logical_address_of_page not on a 4k boundary "
++ "adapter_handle=%lx mr=%p mr_handle=%lx "
++ "pagesize=%x queue_type=%x "
++ "logical_address_of_page=%lx count=%lx",
++ adapter_handle.handle, mr,
++ mr->ipz_mr_handle.handle, pagesize, queue_type,
++ logical_address_of_page, count);
++ ret = H_PARAMETER;
++ } else
++ ret = hipz_h_register_rpage(adapter_handle, pagesize,
++ queue_type,
++ mr->ipz_mr_handle.handle,
++ logical_address_of_page, count);
++ return ret;
++}
++
++u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ struct ehca_mr_hipzout_parms *outparms)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_QUERY_MR, outs,
++ adapter_handle.handle, /* r4 */
++ mr->ipz_mr_handle.handle, /* r5 */
++ 0, 0, 0, 0, 0, 0, 0);
++ outparms->len = outs[0];
++ outparms->vaddr = outs[1];
++ outparms->acl = outs[4] >> 32;
++ outparms->lkey = (u32)(outs[5] >> 32);
++ outparms->rkey = (u32)(outs[5] & (0xffffffff));
++
++ return ret;
++}
++
++u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr)
++{
++ return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
++ adapter_handle.handle, /* r4 */
++ mr->ipz_mr_handle.handle, /* r5 */
++ 0, 0, 0, 0, 0);
++}
++
++u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const u64 vaddr_in,
++ const u64 length,
++ const u32 access_ctrl,
++ const struct ipz_pd pd,
++ const u64 mr_addr_cb,
++ struct ehca_mr_hipzout_parms *outparms)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_REREGISTER_PMR, outs,
++ adapter_handle.handle, /* r4 */
++ mr->ipz_mr_handle.handle, /* r5 */
++ vaddr_in, /* r6 */
++ length, /* r7 */
++ /* r8 */
++ ((((u64)access_ctrl) << 32ULL) | pd.value),
++ mr_addr_cb, /* r9 */
++ 0, 0, 0);
++ outparms->vaddr = outs[1];
++ outparms->lkey = (u32)outs[2];
++ outparms->rkey = (u32)outs[3];
++
++ return ret;
++}
++
++u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const struct ehca_mr *orig_mr,
++ const u64 vaddr_in,
++ const u32 access_ctrl,
++ const struct ipz_pd pd,
++ struct ehca_mr_hipzout_parms *outparms)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_REGISTER_SMR, outs,
++ adapter_handle.handle, /* r4 */
++ orig_mr->ipz_mr_handle.handle, /* r5 */
++ vaddr_in, /* r6 */
++ (((u64)access_ctrl) << 32ULL), /* r7 */
++ pd.value, /* r8 */
++ 0, 0, 0, 0);
++ outparms->handle.handle = outs[0];
++ outparms->lkey = (u32)outs[2];
++ outparms->rkey = (u32)outs[3];
++
++ return ret;
++}
++
++u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mw *mw,
++ const struct ipz_pd pd,
++ struct ehca_mw_hipzout_parms *outparms)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
++ adapter_handle.handle, /* r4 */
++ 6, /* r5 */
++ pd.value, /* r6 */
++ 0, 0, 0, 0, 0, 0);
++ outparms->handle.handle = outs[0];
++ outparms->rkey = (u32)outs[3];
++
++ return ret;
++}
++
++u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mw *mw,
++ struct ehca_mw_hipzout_parms *outparms)
++{
++ u64 ret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ ret = ehca_plpar_hcall9(H_QUERY_MW, outs,
++ adapter_handle.handle, /* r4 */
++ mw->ipz_mw_handle.handle, /* r5 */
++ 0, 0, 0, 0, 0, 0, 0);
++ outparms->rkey = (u32)outs[3];
++
++ return ret;
++}
++
++u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mw *mw)
++{
++ return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
++ adapter_handle.handle, /* r4 */
++ mw->ipz_mw_handle.handle, /* r5 */
++ 0, 0, 0, 0, 0);
++}
++
++u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
++ const u64 ressource_handle,
++ void *rblock,
++ unsigned long *byte_count)
++{
++ u64 r_cb = virt_to_abs(rblock);
++
++ if (r_cb & (EHCA_PAGESIZE-1)) {
++ ehca_gen_err("rblock not page aligned.");
++ return H_PARAMETER;
++ }
++
++ return ehca_plpar_hcall_norets(H_ERROR_DATA,
++ adapter_handle.handle,
++ ressource_handle,
++ r_cb,
++ 0, 0, 0, 0);
++}
+diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h
+new file mode 100644
+index 0000000..587ebd4
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hcp_if.h
+@@ -0,0 +1,261 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Firmware Infiniband Interface code for POWER
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Gerd Bayer <gerd.bayer at de.ibm.com>
++ * Waleri Fomin <fomin at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __HCP_IF_H__
++#define __HCP_IF_H__
++
++#include "ehca_classes.h"
++#include "ehca_tools.h"
++#include "hipz_hw.h"
++
++/*
++ * hipz_h_alloc_resource_eq allocates EQ resources in HW and FW, initalize
++ * resources, create the empty EQPT (ring).
++ */
++u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_pfeq *pfeq,
++ const u32 neq_control,
++ const u32 number_of_entries,
++ struct ipz_eq_handle *eq_handle,
++ u32 * act_nr_of_entries,
++ u32 * act_pages,
++ u32 * eq_ist);
++
++u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
++ struct ipz_eq_handle eq_handle,
++ const u64 event_mask);
++/*
++ * hipz_h_allocate_resource_cq allocates CQ resources in HW and FW, initialize
++ * resources, create the empty CQPT (ring).
++ */
++u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_cq *cq,
++ struct ehca_alloc_cq_parms *param);
++
++
++/*
++ * hipz_h_alloc_resource_qp allocates QP resources in HW and FW,
++ * initialize resources, create empty QPPTs (2 rings).
++ */
++u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_qp *qp,
++ struct ehca_alloc_qp_parms *parms);
++
++u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
++ const u8 port_id,
++ struct hipz_query_port *query_port_response_block);
++
++u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
++ struct hipz_query_hca *query_hca_rblock);
++
++/*
++ * hipz_h_register_rpage internal function in hcp_if.h for all
++ * hcp_H_REGISTER_RPAGE calls.
++ */
++u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 resource_handle,
++ const u64 logical_address_of_page,
++ u64 count);
++
++u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_eq_handle eq_handle,
++ struct ehca_pfeq *pfeq,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count);
++
++u64 hipz_h_query_int_state(const struct ipz_adapter_handle
++ hcp_adapter_handle,
++ u32 ist);
++
++u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_cq_handle cq_handle,
++ struct ehca_pfcq *pfcq,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count,
++ const struct h_galpa gal);
++
++u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count,
++ const struct h_galpa galpa);
++
++u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ void **log_addr_next_sq_wqe_tb_processed,
++ void **log_addr_next_rq_wqe_tb_processed,
++ int dis_and_get_function_code);
++enum hcall_sigt {
++ HCALL_SIGT_NO_CQE = 0,
++ HCALL_SIGT_BY_WQE = 1,
++ HCALL_SIGT_EVERY = 2
++};
++
++u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ const u64 update_mask,
++ struct hcp_modify_qp_control_block *mqpcb,
++ struct h_galpa gal);
++
++u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct ehca_pfqp *pfqp,
++ struct hcp_modify_qp_control_block *qqpcb,
++ struct h_galpa gal);
++
++u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_qp *qp);
++
++u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u32 port);
++
++u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u32 port, u32 * pma_qp_nr,
++ u32 * bma_qp_nr);
++
++u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u16 mcg_dlid,
++ u64 subnet_prefix, u64 interface_id);
++
++u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
++ const struct ipz_qp_handle qp_handle,
++ struct h_galpa gal,
++ u16 mcg_dlid,
++ u64 subnet_prefix, u64 interface_id);
++
++u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_cq *cq,
++ u8 force_flag);
++
++u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
++ struct ehca_eq *eq);
++
++/*
++ * hipz_h_alloc_resource_mr allocates MR resources in HW and FW, initialize
++ * resources.
++ */
++u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const u64 vaddr,
++ const u64 length,
++ const u32 access_ctrl,
++ const struct ipz_pd pd,
++ struct ehca_mr_hipzout_parms *outparms);
++
++/* hipz_h_register_rpage_mr registers MR resource pages in HW and FW */
++u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 logical_address_of_page,
++ const u64 count);
++
++/* hipz_h_query_mr queries MR in HW and FW */
++u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ struct ehca_mr_hipzout_parms *outparms);
++
++/* hipz_h_free_resource_mr frees MR resources in HW and FW */
++u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr);
++
++/* hipz_h_reregister_pmr reregisters MR in HW and FW */
++u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const u64 vaddr_in,
++ const u64 length,
++ const u32 access_ctrl,
++ const struct ipz_pd pd,
++ const u64 mr_addr_cb,
++ struct ehca_mr_hipzout_parms *outparms);
++
++/* hipz_h_register_smr register shared MR in HW and FW */
++u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mr *mr,
++ const struct ehca_mr *orig_mr,
++ const u64 vaddr_in,
++ const u32 access_ctrl,
++ const struct ipz_pd pd,
++ struct ehca_mr_hipzout_parms *outparms);
++
++/*
++ * hipz_h_alloc_resource_mw allocates MW resources in HW and FW, initialize
++ * resources.
++ */
++u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mw *mw,
++ const struct ipz_pd pd,
++ struct ehca_mw_hipzout_parms *outparms);
++
++/* hipz_h_query_mw queries MW in HW and FW */
++u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mw *mw,
++ struct ehca_mw_hipzout_parms *outparms);
++
++/* hipz_h_free_resource_mw frees MW resources in HW and FW */
++u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
++ const struct ehca_mw *mw);
++
++u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
++ const u64 ressource_handle,
++ void *rblock,
++ unsigned long *byte_count);
++
++#endif /* __HCP_IF_H__ */
+diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c
+new file mode 100644
+index 0000000..0b1a477
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hcp_phyp.c
+@@ -0,0 +1,80 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * load store abstraction for ehca register access with tracing
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "ehca_classes.h"
++#include "hipz_hw.h"
++
++int hcall_map_page(u64 physaddr, u64 *mapaddr)
++{
++ *mapaddr = (u64)(ioremap(physaddr, EHCA_PAGESIZE));
++ return 0;
++}
++
++int hcall_unmap_page(u64 mapaddr)
++{
++ iounmap((volatile void __iomem*)mapaddr);
++ return 0;
++}
++
++int hcp_galpas_ctor(struct h_galpas *galpas,
++ u64 paddr_kernel, u64 paddr_user)
++{
++ int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
++ if (ret)
++ return ret;
++
++ galpas->user.fw_handle = paddr_user;
++
++ return 0;
++}
++
++int hcp_galpas_dtor(struct h_galpas *galpas)
++{
++ if (galpas->kernel.fw_handle) {
++ int ret = hcall_unmap_page(galpas->kernel.fw_handle);
++ if (ret)
++ return ret;
++ }
++
++ galpas->user.fw_handle = galpas->kernel.fw_handle = 0;
++
++ return 0;
++}
+diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.h b/drivers/infiniband/hw/ehca/hcp_phyp.h
+new file mode 100644
+index 0000000..5305c2a
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hcp_phyp.h
+@@ -0,0 +1,90 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * Firmware calls
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Waleri Fomin <fomin at de.ibm.com>
++ * Gerd Bayer <gerd.bayer at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __HCP_PHYP_H__
++#define __HCP_PHYP_H__
++
++
++/*
++ * eHCA page (mapped into memory)
++ * resource to access eHCA register pages in CPU address space
++*/
++struct h_galpa {
++ u64 fw_handle;
++ /* for pSeries this is a 64bit memory address where
++ I/O memory is mapped into CPU address space (kv) */
++};
++
++/*
++ * resource to access eHCA address space registers, all types
++ */
++struct h_galpas {
++ u32 pid; /*PID of userspace galpa checking */
++ struct h_galpa user; /* user space accessible resource,
++ set to 0 if unused */
++ struct h_galpa kernel; /* kernel space accessible resource,
++ set to 0 if unused */
++};
++
++static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset)
++{
++ u64 addr = galpa.fw_handle + offset;
++ return *(volatile u64 __force *)addr;
++}
++
++static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value)
++{
++ u64 addr = galpa.fw_handle + offset;
++ *(volatile u64 __force *)addr = value;
++}
++
++int hcp_galpas_ctor(struct h_galpas *galpas,
++ u64 paddr_kernel, u64 paddr_user);
++
++int hcp_galpas_dtor(struct h_galpas *galpas);
++
++int hcall_map_page(u64 physaddr, u64 * mapaddr);
++
++int hcall_unmap_page(u64 mapaddr);
++
++#endif
+diff --git a/drivers/infiniband/hw/ehca/hipz_fns.h b/drivers/infiniband/hw/ehca/hipz_fns.h
+new file mode 100644
+index 0000000..9dac93d
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hipz_fns.h
+@@ -0,0 +1,68 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * HW abstraction register functions
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __HIPZ_FNS_H__
++#define __HIPZ_FNS_H__
++
++#include "ehca_classes.h"
++#include "hipz_hw.h"
++
++#include "hipz_fns_core.h"
++
++#define hipz_galpa_store_eq(gal, offset, value) \
++ hipz_galpa_store(gal, EQTEMM_OFFSET(offset), value)
++
++#define hipz_galpa_load_eq(gal, offset) \
++ hipz_galpa_load(gal, EQTEMM_OFFSET(offset))
++
++#define hipz_galpa_store_qped(gal, offset, value) \
++ hipz_galpa_store(gal, QPEDMM_OFFSET(offset), value)
++
++#define hipz_galpa_load_qped(gal, offset) \
++ hipz_galpa_load(gal, QPEDMM_OFFSET(offset))
++
++#define hipz_galpa_store_mrmw(gal, offset, value) \
++ hipz_galpa_store(gal, MRMWMM_OFFSET(offset), value)
++
++#define hipz_galpa_load_mrmw(gal, offset) \
++ hipz_galpa_load(gal, MRMWMM_OFFSET(offset))
++
++#endif
+diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h
+new file mode 100644
+index 0000000..20898a1
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h
+@@ -0,0 +1,100 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * HW abstraction register functions
++ *
++ * Authors: Christoph Raisch <raisch at de.ibm.com>
++ * Heiko J Schick <schickhj at de.ibm.com>
++ * Hoang-Nam Nguyen <hnguyen at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __HIPZ_FNS_CORE_H__
++#define __HIPZ_FNS_CORE_H__
++
++#include "hcp_phyp.h"
++#include "hipz_hw.h"
++
++#define hipz_galpa_store_cq(gal, offset, value) \
++ hipz_galpa_store(gal, CQTEMM_OFFSET(offset), value)
++
++#define hipz_galpa_load_cq(gal, offset) \
++ hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
++
++#define hipz_galpa_store_qp(gal,offset, value) \
++ hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
++#define hipz_galpa_load_qp(gal, offset) \
++ hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
++
++static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
++{
++ /* ringing doorbell :-) */
++ hipz_galpa_store_qp(qp->galpas.kernel, qpx_sqa,
++ EHCA_BMASK_SET(QPX_SQADDER, nr_wqes));
++}
++
++static inline void hipz_update_rqa(struct ehca_qp *qp, u16 nr_wqes)
++{
++ /* ringing doorbell :-) */
++ hipz_galpa_store_qp(qp->galpas.kernel, qpx_rqa,
++ EHCA_BMASK_SET(QPX_RQADDER, nr_wqes));
++}
++
++static inline void hipz_update_feca(struct ehca_cq *cq, u32 nr_cqes)
++{
++ hipz_galpa_store_cq(cq->galpas.kernel, cqx_feca,
++ EHCA_BMASK_SET(CQX_FECADDER, nr_cqes));
++}
++
++static inline void hipz_set_cqx_n0(struct ehca_cq *cq, u32 value)
++{
++ u64 cqx_n0_reg;
++
++ hipz_galpa_store_cq(cq->galpas.kernel, cqx_n0,
++ EHCA_BMASK_SET(CQX_N0_GENERATE_SOLICITED_COMP_EVENT,
++ value));
++ cqx_n0_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n0);
++}
++
++static inline void hipz_set_cqx_n1(struct ehca_cq *cq, u32 value)
++{
++ u64 cqx_n1_reg;
++
++ hipz_galpa_store_cq(cq->galpas.kernel, cqx_n1,
++ EHCA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, value));
++ cqx_n1_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n1);
++}
++
++#endif /* __HIPZ_FNC_CORE_H__ */
+diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h
+new file mode 100644
+index 0000000..3fc92b0
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/hipz_hw.h
+@@ -0,0 +1,388 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * eHCA register definitions
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __HIPZ_HW_H__
++#define __HIPZ_HW_H__
++
++#include "ehca_tools.h"
++
++/* QP Table Entry Memory Map */
++struct hipz_qptemm {
++ u64 qpx_hcr;
++ u64 qpx_c;
++ u64 qpx_herr;
++ u64 qpx_aer;
++/* 0x20*/
++ u64 qpx_sqa;
++ u64 qpx_sqc;
++ u64 qpx_rqa;
++ u64 qpx_rqc;
++/* 0x40*/
++ u64 qpx_st;
++ u64 qpx_pmstate;
++ u64 qpx_pmfa;
++ u64 qpx_pkey;
++/* 0x60*/
++ u64 qpx_pkeya;
++ u64 qpx_pkeyb;
++ u64 qpx_pkeyc;
++ u64 qpx_pkeyd;
++/* 0x80*/
++ u64 qpx_qkey;
++ u64 qpx_dqp;
++ u64 qpx_dlidp;
++ u64 qpx_portp;
++/* 0xa0*/
++ u64 qpx_slidp;
++ u64 qpx_slidpp;
++ u64 qpx_dlida;
++ u64 qpx_porta;
++/* 0xc0*/
++ u64 qpx_slida;
++ u64 qpx_slidpa;
++ u64 qpx_slvl;
++ u64 qpx_ipd;
++/* 0xe0*/
++ u64 qpx_mtu;
++ u64 qpx_lato;
++ u64 qpx_rlimit;
++ u64 qpx_rnrlimit;
++/* 0x100*/
++ u64 qpx_t;
++ u64 qpx_sqhp;
++ u64 qpx_sqptp;
++ u64 qpx_nspsn;
++/* 0x120*/
++ u64 qpx_nspsnhwm;
++ u64 reserved1;
++ u64 qpx_sdsi;
++ u64 qpx_sdsbc;
++/* 0x140*/
++ u64 qpx_sqwsize;
++ u64 qpx_sqwts;
++ u64 qpx_lsn;
++ u64 qpx_nssn;
++/* 0x160 */
++ u64 qpx_mor;
++ u64 qpx_cor;
++ u64 qpx_sqsize;
++ u64 qpx_erc;
++/* 0x180*/
++ u64 qpx_rnrrc;
++ u64 qpx_ernrwt;
++ u64 qpx_rnrresp;
++ u64 qpx_lmsna;
++/* 0x1a0 */
++ u64 qpx_sqhpc;
++ u64 qpx_sqcptp;
++ u64 qpx_sigt;
++ u64 qpx_wqecnt;
++/* 0x1c0*/
++ u64 qpx_rqhp;
++ u64 qpx_rqptp;
++ u64 qpx_rqsize;
++ u64 qpx_nrr;
++/* 0x1e0*/
++ u64 qpx_rdmac;
++ u64 qpx_nrpsn;
++ u64 qpx_lapsn;
++ u64 qpx_lcr;
++/* 0x200*/
++ u64 qpx_rwc;
++ u64 qpx_rwva;
++ u64 qpx_rdsi;
++ u64 qpx_rdsbc;
++/* 0x220*/
++ u64 qpx_rqwsize;
++ u64 qpx_crmsn;
++ u64 qpx_rdd;
++ u64 qpx_larpsn;
++/* 0x240*/
++ u64 qpx_pd;
++ u64 qpx_scqn;
++ u64 qpx_rcqn;
++ u64 qpx_aeqn;
++/* 0x260*/
++ u64 qpx_aaelog;
++ u64 qpx_ram;
++ u64 qpx_rdmaqe0;
++ u64 qpx_rdmaqe1;
++/* 0x280*/
++ u64 qpx_rdmaqe2;
++ u64 qpx_rdmaqe3;
++ u64 qpx_nrpsnhwm;
++/* 0x298*/
++ u64 reserved[(0x400 - 0x298) / 8];
++/* 0x400 extended data */
++ u64 reserved_ext[(0x500 - 0x400) / 8];
++/* 0x500 */
++ u64 reserved2[(0x1000 - 0x500) / 8];
++/* 0x1000 */
++};
++
++#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
++#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
++
++#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
++
++/* MRMWPT Entry Memory Map */
++struct hipz_mrmwmm {
++ /* 0x00 */
++ u64 mrx_hcr;
++
++ u64 mrx_c;
++ u64 mrx_herr;
++ u64 mrx_aer;
++ /* 0x20 */
++ u64 mrx_pp;
++ u64 reserved1;
++ u64 reserved2;
++ u64 reserved3;
++ /* 0x40 */
++ u64 reserved4[(0x200 - 0x40) / 8];
++ /* 0x200 */
++ u64 mrx_ctl[64];
++
++};
++
++#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
++
++struct hipz_qpedmm {
++ /* 0x00 */
++ u64 reserved0[(0x400) / 8];
++ /* 0x400 */
++ u64 qpedx_phh;
++ u64 qpedx_ppsgp;
++ /* 0x410 */
++ u64 qpedx_ppsgu;
++ u64 qpedx_ppdgp;
++ /* 0x420 */
++ u64 qpedx_ppdgu;
++ u64 qpedx_aph;
++ /* 0x430 */
++ u64 qpedx_apsgp;
++ u64 qpedx_apsgu;
++ /* 0x440 */
++ u64 qpedx_apdgp;
++ u64 qpedx_apdgu;
++ /* 0x450 */
++ u64 qpedx_apav;
++ u64 qpedx_apsav;
++ /* 0x460 */
++ u64 qpedx_hcr;
++ u64 reserved1[4];
++ /* 0x488 */
++ u64 qpedx_rrl0;
++ /* 0x490 */
++ u64 qpedx_rrrkey0;
++ u64 qpedx_rrva0;
++ /* 0x4a0 */
++ u64 reserved2;
++ u64 qpedx_rrl1;
++ /* 0x4b0 */
++ u64 qpedx_rrrkey1;
++ u64 qpedx_rrva1;
++ /* 0x4c0 */
++ u64 reserved3;
++ u64 qpedx_rrl2;
++ /* 0x4d0 */
++ u64 qpedx_rrrkey2;
++ u64 qpedx_rrva2;
++ /* 0x4e0 */
++ u64 reserved4;
++ u64 qpedx_rrl3;
++ /* 0x4f0 */
++ u64 qpedx_rrrkey3;
++ u64 qpedx_rrva3;
++};
++
++#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
++
++/* CQ Table Entry Memory Map */
++struct hipz_cqtemm {
++ u64 cqx_hcr;
++ u64 cqx_c;
++ u64 cqx_herr;
++ u64 cqx_aer;
++/* 0x20 */
++ u64 cqx_ptp;
++ u64 cqx_tp;
++ u64 cqx_fec;
++ u64 cqx_feca;
++/* 0x40 */
++ u64 cqx_ep;
++ u64 cqx_eq;
++/* 0x50 */
++ u64 reserved1;
++ u64 cqx_n0;
++/* 0x60 */
++ u64 cqx_n1;
++ u64 reserved2[(0x1000 - 0x60) / 8];
++/* 0x1000 */
++};
++
++#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63)
++#define CQX_FECADDER EHCA_BMASK_IBM(32,63)
++#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
++#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
++
++#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
++
++/* EQ Table Entry Memory Map */
++struct hipz_eqtemm {
++ u64 eqx_hcr;
++ u64 eqx_c;
++
++ u64 eqx_herr;
++ u64 eqx_aer;
++/* 0x20 */
++ u64 eqx_ptp;
++ u64 eqx_tp;
++ u64 eqx_ssba;
++ u64 eqx_psba;
++
++/* 0x40 */
++ u64 eqx_cec;
++ u64 eqx_meql;
++ u64 eqx_xisbi;
++ u64 eqx_xisc;
++/* 0x60 */
++ u64 eqx_it;
++
++};
++
++#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
++
++/* access control defines for MR/MW */
++#define HIPZ_ACCESSCTRL_L_WRITE 0x00800000
++#define HIPZ_ACCESSCTRL_R_WRITE 0x00400000
++#define HIPZ_ACCESSCTRL_R_READ 0x00200000
++#define HIPZ_ACCESSCTRL_R_ATOMIC 0x00100000
++#define HIPZ_ACCESSCTRL_MW_BIND 0x00080000
++
++/* query hca response block */
++struct hipz_query_hca {
++ u32 cur_reliable_dg;
++ u32 cur_qp;
++ u32 cur_cq;
++ u32 cur_eq;
++ u32 cur_mr;
++ u32 cur_mw;
++ u32 cur_ee_context;
++ u32 cur_mcast_grp;
++ u32 cur_qp_attached_mcast_grp;
++ u32 reserved1;
++ u32 cur_ipv6_qp;
++ u32 cur_eth_qp;
++ u32 cur_hp_mr;
++ u32 reserved2[3];
++ u32 max_rd_domain;
++ u32 max_qp;
++ u32 max_cq;
++ u32 max_eq;
++ u32 max_mr;
++ u32 max_hp_mr;
++ u32 max_mw;
++ u32 max_mrwpte;
++ u32 max_special_mrwpte;
++ u32 max_rd_ee_context;
++ u32 max_mcast_grp;
++ u32 max_total_mcast_qp_attach;
++ u32 max_mcast_qp_attach;
++ u32 max_raw_ipv6_qp;
++ u32 max_raw_ethy_qp;
++ u32 internal_clock_frequency;
++ u32 max_pd;
++ u32 max_ah;
++ u32 max_cqe;
++ u32 max_wqes_wq;
++ u32 max_partitions;
++ u32 max_rr_ee_context;
++ u32 max_rr_qp;
++ u32 max_rr_hca;
++ u32 max_act_wqs_ee_context;
++ u32 max_act_wqs_qp;
++ u32 max_sge;
++ u32 max_sge_rd;
++ u32 memory_page_size_supported;
++ u64 max_mr_size;
++ u32 local_ca_ack_delay;
++ u32 num_ports;
++ u32 vendor_id;
++ u32 vendor_part_id;
++ u32 hw_ver;
++ u64 node_guid;
++ u64 hca_cap_indicators;
++ u32 data_counter_register_size;
++ u32 max_shared_rq;
++ u32 max_isns_eq;
++ u32 max_neq;
++} __attribute__ ((packed));
++
++/* query port response block */
++struct hipz_query_port {
++ u32 state;
++ u32 bad_pkey_cntr;
++ u32 lmc;
++ u32 lid;
++ u32 subnet_timeout;
++ u32 qkey_viol_cntr;
++ u32 sm_sl;
++ u32 sm_lid;
++ u32 capability_mask;
++ u32 init_type_reply;
++ u32 pkey_tbl_len;
++ u32 gid_tbl_len;
++ u64 gid_prefix;
++ u32 port_nr;
++ u16 pkey_entries[16];
++ u8 reserved1[32];
++ u32 trent_size;
++ u32 trbuf_size;
++ u64 max_msg_sz;
++ u32 max_mtu;
++ u32 vl_cap;
++ u8 reserved2[1900];
++ u64 guid_entries[255];
++} __attribute__ ((packed));
++
++#endif
+diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+new file mode 100644
+index 0000000..e028ff1
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+@@ -0,0 +1,149 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * internal queue handling
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "ehca_tools.h"
++#include "ipz_pt_fn.h"
++
++void *ipz_qpageit_get_inc(struct ipz_queue *queue)
++{
++ void *ret = ipz_qeit_get(queue);
++ queue->current_q_offset += queue->pagesize;
++ if (queue->current_q_offset > queue->queue_length) {
++ queue->current_q_offset -= queue->pagesize;
++ ret = NULL;
++ }
++ if (((u64)ret) % EHCA_PAGESIZE) {
++ ehca_gen_err("ERROR!! not at PAGE-Boundary");
++ return NULL;
++ }
++ return ret;
++}
++
++void *ipz_qeit_eq_get_inc(struct ipz_queue *queue)
++{
++ void *ret = ipz_qeit_get(queue);
++ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
++
++ queue->current_q_offset += queue->qe_size;
++ if (queue->current_q_offset > last_entry_in_q) {
++ queue->current_q_offset = 0;
++ queue->toggle_state = (~queue->toggle_state) & 1;
++ }
++
++ return ret;
++}
++
++int ipz_queue_ctor(struct ipz_queue *queue,
++ const u32 nr_of_pages,
++ const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
++{
++ int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
++ int f;
++
++ if (pagesize > PAGE_SIZE) {
++ ehca_gen_err("FATAL ERROR: pagesize=%x is greater "
++ "than kernel page size", pagesize);
++ return 0;
++ }
++ if (!pages_per_kpage) {
++ ehca_gen_err("FATAL ERROR: invalid kernel page size. "
++ "pages_per_kpage=%x", pages_per_kpage);
++ return 0;
++ }
++ queue->queue_length = nr_of_pages * pagesize;
++ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
++ if (!queue->queue_pages) {
++ ehca_gen_err("ERROR!! didn't get the memory");
++ return 0;
++ }
++ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
++ /*
++ * allocate pages for queue:
++ * outer loop allocates whole kernel pages (page aligned) and
++ * inner loop divides a kernel page into smaller hca queue pages
++ */
++ f = 0;
++ while (f < nr_of_pages) {
++ u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
++ int k;
++ if (!kpage)
++ goto ipz_queue_ctor_exit0; /*NOMEM*/
++ for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) {
++ (queue->queue_pages)[f] = (struct ipz_page *)kpage;
++ kpage += EHCA_PAGESIZE;
++ f++;
++ }
++ }
++
++ queue->current_q_offset = 0;
++ queue->qe_size = qe_size;
++ queue->act_nr_of_sg = nr_of_sg;
++ queue->pagesize = pagesize;
++ queue->toggle_state = 1;
++ return 1;
++
++ ipz_queue_ctor_exit0:
++ ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
++ queue, f, nr_of_pages);
++ for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
++ if (!(queue->queue_pages)[f])
++ break;
++ free_page((unsigned long)(queue->queue_pages)[f]);
++ }
++ return 0;
++}
++
++int ipz_queue_dtor(struct ipz_queue *queue)
++{
++ int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
++ int g;
++ int nr_pages;
++
++ if (!queue || !queue->queue_pages) {
++ ehca_gen_dbg("queue or queue_pages is NULL");
++ return 0;
++ }
++ nr_pages = queue->queue_length / queue->pagesize;
++ for (g = 0; g < nr_pages; g += pages_per_kpage)
++ free_page((unsigned long)(queue->queue_pages)[g]);
++ vfree(queue->queue_pages);
++
++ return 1;
++}
+diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+new file mode 100644
+index 0000000..2f13509
+--- /dev/null
++++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+@@ -0,0 +1,247 @@
++/*
++ * IBM eServer eHCA Infiniband device driver for Linux on POWER
++ *
++ * internal queue handling
++ *
++ * Authors: Waleri Fomin <fomin at de.ibm.com>
++ * Reinhard Ernst <rernst at de.ibm.com>
++ * Christoph Raisch <raisch at de.ibm.com>
++ *
++ * Copyright (c) 2005 IBM Corporation
++ *
++ * All rights reserved.
++ *
++ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
++ * BSD.
++ *
++ * OpenIB BSD License
++ *
++ * 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.
++ *
++ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
++ */
++
++#ifndef __IPZ_PT_FN_H__
++#define __IPZ_PT_FN_H__
++
++#define EHCA_PAGESHIFT 12
++#define EHCA_PAGESIZE 4096UL
++#define EHCA_PAGEMASK (~(EHCA_PAGESIZE-1))
++#define EHCA_PT_ENTRIES 512UL
++
++#include "ehca_tools.h"
++#include "ehca_qes.h"
++
++/* struct generic ehca page */
++struct ipz_page {
++ u8 entries[EHCA_PAGESIZE];
++};
++
++/* struct generic queue in linux kernel virtual memory (kv) */
++struct ipz_queue {
++ u64 current_q_offset; /* current queue entry */
++
++ struct ipz_page **queue_pages; /* array of pages belonging to queue */
++ u32 qe_size; /* queue entry size */
++ u32 act_nr_of_sg;
++ u32 queue_length; /* queue length allocated in bytes */
++ u32 pagesize;
++ u32 toggle_state; /* toggle flag - per page */
++ u32 dummy3; /* 64 bit alignment */
++};
++
++/*
++ * return current Queue Entry for a certain q_offset
++ * returns address (kv) of Queue Entry
++ */
++static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
++{
++ struct ipz_page *current_page;
++ if (q_offset >= queue->queue_length)
++ return NULL;
++ current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT];
++ return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)];
++}
++
++/*
++ * return current Queue Entry
++ * returns address (kv) of Queue Entry
++ */
++static inline void *ipz_qeit_get(struct ipz_queue *queue)
++{
++ return ipz_qeit_calc(queue, queue->current_q_offset);
++}
++
++/*
++ * return current Queue Page , increment Queue Page iterator from
++ * page to page in struct ipz_queue, last increment will return 0! and
++ * NOT wrap
++ * returns address (kv) of Queue Page
++ * warning don't use in parallel with ipz_QE_get_inc()
++ */
++void *ipz_qpageit_get_inc(struct ipz_queue *queue);
++
++/*
++ * return current Queue Entry, increment Queue Entry iterator by one
++ * step in struct ipz_queue, will wrap in ringbuffer
++ * returns address (kv) of Queue Entry BEFORE increment
++ * warning don't use in parallel with ipz_qpageit_get_inc()
++ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
++ */
++static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
++{
++ void *ret = ipz_qeit_get(queue);
++ queue->current_q_offset += queue->qe_size;
++ if (queue->current_q_offset >= queue->queue_length) {
++ queue->current_q_offset = 0;
++ /* toggle the valid flag */
++ queue->toggle_state = (~queue->toggle_state) & 1;
++ }
++
++ return ret;
++}
++
++/*
++ * return current Queue Entry, increment Queue Entry iterator by one
++ * step in struct ipz_queue, will wrap in ringbuffer
++ * returns address (kv) of Queue Entry BEFORE increment
++ * returns 0 and does not increment, if wrong valid state
++ * warning don't use in parallel with ipz_qpageit_get_inc()
++ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
++ */
++static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
++{
++ struct ehca_cqe *cqe = ipz_qeit_get(queue);
++ u32 cqe_flags = cqe->cqe_flags;
++
++ if ((cqe_flags >> 7) != (queue->toggle_state & 1))
++ return NULL;
++
++ ipz_qeit_get_inc(queue);
++ return cqe;
++}
++
++/*
++ * returns and resets Queue Entry iterator
++ * returns address (kv) of first Queue Entry
++ */
++static inline void *ipz_qeit_reset(struct ipz_queue *queue)
++{
++ queue->current_q_offset = 0;
++ return ipz_qeit_get(queue);
++}
++
++/* struct generic page table */
++struct ipz_pt {
++ u64 entries[EHCA_PT_ENTRIES];
++};
++
++/* struct page table for a queue, only to be used in pf */
++struct ipz_qpt {
++ /* queue page tables (kv), use u64 because we know the element length */
++ u64 *qpts;
++ u32 n_qpts;
++ u32 n_ptes; /* number of page table entries */
++ u64 *current_pte_addr;
++};
++
++/*
++ * constructor for a ipz_queue_t, placement new for ipz_queue_t,
++ * new for all dependent datastructors
++ * all QP Tables are the same
++ * flow:
++ * allocate+pin queue
++ * see ipz_qpt_ctor()
++ * returns true if ok, false if out of memory
++ */
++int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
++ const u32 pagesize, const u32 qe_size,
++ const u32 nr_of_sg);
++
++/*
++ * destructor for a ipz_queue_t
++ * -# free queue
++ * see ipz_queue_ctor()
++ * returns true if ok, false if queue was NULL-ptr of free failed
++ */
++int ipz_queue_dtor(struct ipz_queue *queue);
++
++/*
++ * constructor for a ipz_qpt_t,
++ * placement new for struct ipz_queue, new for all dependent datastructors
++ * all QP Tables are the same,
++ * flow:
++ * -# allocate+pin queue
++ * -# initialise ptcb
++ * -# allocate+pin PTs
++ * -# link PTs to a ring, according to HCA Arch, set bit62 id needed
++ * -# the ring must have room for exactly nr_of_PTEs
++ * see ipz_qpt_ctor()
++ */
++void ipz_qpt_ctor(struct ipz_qpt *qpt,
++ const u32 nr_of_qes,
++ const u32 pagesize,
++ const u32 qe_size,
++ const u8 lowbyte, const u8 toggle,
++ u32 * act_nr_of_QEs, u32 * act_nr_of_pages);
++
++/*
++ * return current Queue Entry, increment Queue Entry iterator by one
++ * step in struct ipz_queue, will wrap in ringbuffer
++ * returns address (kv) of Queue Entry BEFORE increment
++ * warning don't use in parallel with ipz_qpageit_get_inc()
++ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
++ * fix EQ page problems
++ */
++void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
++
++/*
++ * return current Event Queue Entry, increment Queue Entry iterator
++ * by one step in struct ipz_queue if valid, will wrap in ringbuffer
++ * returns address (kv) of Queue Entry BEFORE increment
++ * returns 0 and does not increment, if wrong valid state
++ * warning don't use in parallel with ipz_queue_QPageit_get_inc()
++ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
++ */
++static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
++{
++ void *ret = ipz_qeit_get(queue);
++ u32 qe = *(u8 *) ret;
++ if ((qe >> 7) != (queue->toggle_state & 1))
++ return NULL;
++ ipz_qeit_eq_get_inc(queue); /* this is a good one */
++ return ret;
++}
++
++/* returns address (GX) of first queue entry */
++static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)
++{
++ return be64_to_cpu(qpt->qpts[0]);
++}
++
++/* returns address (kv) of first page of queue page table */
++static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt)
++{
++ return qpt->qpts;
++}
++
++#endif /* __IPZ_PT_FN_H__ */
+diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/infiniband/hw/ipath/Kconfig
+index 1db9489..574a678 100644
+--- a/drivers/infiniband/hw/ipath/Kconfig
++++ b/drivers/infiniband/hw/ipath/Kconfig
+@@ -1,16 +1,9 @@
+-config IPATH_CORE
+- tristate "QLogic InfiniPath Driver"
+- depends on 64BIT && PCI_MSI && NET
+- ---help---
+- This is a low-level driver for QLogic InfiniPath host channel
+- adapters (HCAs) based on the HT-400 and PE-800 chips.
+-
+ config INFINIBAND_IPATH
+- tristate "QLogic InfiniPath Verbs Driver"
+- depends on IPATH_CORE && INFINIBAND
++ tristate "QLogic InfiniPath Driver"
++ depends on PCI_MSI && 64BIT && INFINIBAND
+ ---help---
+- This is a driver that provides InfiniBand verbs support for
+- QLogic InfiniPath host channel adapters (HCAs). This
+- allows these devices to be used with both kernel upper level
+- protocols such as IP-over-InfiniBand as well as with userspace
+- applications (in conjunction with InfiniBand userspace access).
++ This is a driver for QLogic InfiniPath host channel adapters,
++ including InfiniBand verbs support. This driver allows these
++ devices to be used with both kernel upper level protocols such
++ as IP-over-InfiniBand as well as with userspace applications
++ (in conjunction with InfiniBand userspace access).
+diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
+index b0bf728..5e29cb0 100644
+--- a/drivers/infiniband/hw/ipath/Makefile
++++ b/drivers/infiniband/hw/ipath/Makefile
+@@ -1,36 +1,35 @@
+ EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \
+ -DIPATH_KERN_TYPE=0
+
+-obj-$(CONFIG_IPATH_CORE) += ipath_core.o
+ obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
+
+-ipath_core-y := \
++ib_ipath-y := \
++ ipath_cq.o \
+ ipath_diag.o \
+ ipath_driver.o \
+ ipath_eeprom.o \
+ ipath_file_ops.o \
+ ipath_fs.o \
+- ipath_ht400.o \
++ ipath_iba6110.o \
++ ipath_iba6120.o \
+ ipath_init_chip.o \
+ ipath_intr.o \
+- ipath_layer.o \
+- ipath_pe800.o \
+- ipath_stats.o \
+- ipath_sysfs.o \
+- ipath_user_pages.o
+-
+-ipath_core-$(CONFIG_X86_64) += ipath_wc_x86_64.o
+-
+-ib_ipath-y := \
+- ipath_cq.o \
+ ipath_keys.o \
++ ipath_layer.o \
+ ipath_mad.o \
++ ipath_mmap.o \
+ ipath_mr.o \
+ ipath_qp.o \
+ ipath_rc.o \
+ ipath_ruc.o \
+ ipath_srq.o \
++ ipath_stats.o \
++ ipath_sysfs.o \
+ ipath_uc.o \
+ ipath_ud.o \
+- ipath_verbs.o \
+- ipath_verbs_mcast.o
++ ipath_user_pages.o \
++ ipath_verbs_mcast.o \
++ ipath_verbs.o
++
++ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o
++ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o
+diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
+index 062bd39..54139d3 100644
+--- a/drivers/infiniband/hw/ipath/ipath_common.h
++++ b/drivers/infiniband/hw/ipath/ipath_common.h
+@@ -106,9 +106,9 @@ struct infinipath_stats {
+ __u64 sps_ether_spkts;
+ /* number of "ethernet" packets received by driver */
+ __u64 sps_ether_rpkts;
+- /* number of SMA packets sent by driver */
++ /* number of SMA packets sent by driver. Obsolete. */
+ __u64 sps_sma_spkts;
+- /* number of SMA packets received by driver */
++ /* number of SMA packets received by driver. Obsolete. */
+ __u64 sps_sma_rpkts;
+ /* number of times all ports rcvhdrq was full and packet dropped */
+ __u64 sps_hdrqfull;
+@@ -138,11 +138,12 @@ struct infinipath_stats {
+ __u64 sps_pageunlocks;
+ /*
+ * Number of packets dropped in kernel other than errors (ether
+- * packets if ipath not configured, sma/mad, etc.)
++ * packets if ipath not configured, etc.)
+ */
+ __u64 sps_krdrops;
++ __u64 sps_txeparity; /* PIO buffer parity error, recovered */
+ /* pad for future growth */
+- __u64 __sps_pad[46];
++ __u64 __sps_pad[45];
+ };
+
+ /*
+@@ -153,8 +154,6 @@ struct infinipath_stats {
+ #define IPATH_STATUS_DISABLED 0x2 /* hardware disabled */
+ /* Device has been disabled via admin request */
+ #define IPATH_STATUS_ADMIN_DISABLED 0x4
+-#define IPATH_STATUS_OIB_SMA 0x8 /* ipath_mad kernel SMA running */
+-#define IPATH_STATUS_SMA 0x10 /* user SMA running */
+ /* Chip has been found and initted */
+ #define IPATH_STATUS_CHIP_PRESENT 0x20
+ /* IB link is at ACTIVE, usable for data traffic */
+@@ -187,6 +186,9 @@ typedef enum _ipath_ureg {
+ #define IPATH_RUNTIME_PCIE 0x2
+ #define IPATH_RUNTIME_FORCE_WC_ORDER 0x4
+ #define IPATH_RUNTIME_RCVHDR_COPY 0x8
++#define IPATH_RUNTIME_MASTER 0x10
++#define IPATH_RUNTIME_PBC_REWRITE 0x20
++#define IPATH_RUNTIME_LOOSE_DMA_ALIGN 0x40
+
+ /*
+ * This structure is returned by ipath_userinit() immediately after
+@@ -204,7 +206,8 @@ struct ipath_base_info {
+ /* version of software, for feature checking. */
+ __u32 spi_sw_version;
+ /* InfiniPath port assigned, goes into sent packets */
+- __u32 spi_port;
++ __u16 spi_port;
++ __u16 spi_subport;
+ /*
+ * IB MTU, packets IB data must be less than this.
+ * The MTU is in bytes, and will be a multiple of 4 bytes.
+@@ -220,7 +223,7 @@ struct ipath_base_info {
+ __u32 spi_tidcnt;
+ /* size of the TID Eager list in infinipath, in entries */
+ __u32 spi_tidegrcnt;
+- /* size of a single receive header queue entry. */
++ /* size of a single receive header queue entry in words. */
+ __u32 spi_rcvhdrent_size;
+ /*
+ * Count of receive header queue entries allocated.
+@@ -312,6 +315,12 @@ struct ipath_base_info {
+ __u32 spi_filler_for_align;
+ /* address of readonly memory copy of the rcvhdrq tail register. */
+ __u64 spi_rcvhdr_tailaddr;
++
++ /* shared memory pages for subports if IPATH_RUNTIME_MASTER is set */
++ __u64 spi_subport_uregbase;
++ __u64 spi_subport_rcvegrbuf;
++ __u64 spi_subport_rcvhdr_base;
++
+ } __attribute__ ((aligned(8)));
+
+
+@@ -330,12 +339,12 @@ struct ipath_base_info {
+
+ /*
+ * Minor version differences are always compatible
+- * a within a major version, however if if user software is larger
++ * a within a major version, however if user software is larger
+ * than driver software, some new features and/or structure fields
+ * may not be implemented; the user code must deal with this if it
+- * cares, or it must abort after initialization reports the difference
++ * cares, or it must abort after initialization reports the difference.
+ */
+-#define IPATH_USER_SWMINOR 2
++#define IPATH_USER_SWMINOR 3
+
+ #define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
+
+@@ -381,7 +390,16 @@ struct ipath_user_info {
+ */
+ __u32 spu_rcvhdrsize;
+
+- __u64 spu_unused; /* kept for compatible layout */
++ /*
++ * If two or more processes wish to share a port, each process
++ * must set the spu_subport_cnt and spu_subport_id to the same
++ * values. The only restriction on the spu_subport_id is that
++ * it be unique for a given node.
++ */
++ __u16 spu_subport_cnt;
++ __u16 spu_subport_id;
++
++ __u32 spu_unused; /* kept for compatible layout */
+
+ /*
+ * address of struct base_info to write to
+@@ -394,19 +412,25 @@ struct ipath_user_info {
+
+ #define IPATH_CMD_MIN 16
+
+-#define IPATH_CMD_USER_INIT 16 /* set up userspace */
++#define __IPATH_CMD_USER_INIT 16 /* old set up userspace (for old user code) */
+ #define IPATH_CMD_PORT_INFO 17 /* find out what resources we got */
+ #define IPATH_CMD_RECV_CTRL 18 /* control receipt of packets */
+ #define IPATH_CMD_TID_UPDATE 19 /* update expected TID entries */
+ #define IPATH_CMD_TID_FREE 20 /* free expected TID entries */
+ #define IPATH_CMD_SET_PART_KEY 21 /* add partition key */
++#define IPATH_CMD_SLAVE_INFO 22 /* return info on slave processes */
++#define IPATH_CMD_ASSIGN_PORT 23 /* allocate HCA and port */
++#define IPATH_CMD_USER_INIT 24 /* set up userspace */
+
+-#define IPATH_CMD_MAX 21
++#define IPATH_CMD_MAX 24
+
+ struct ipath_port_info {
+ __u32 num_active; /* number of active units */
+ __u32 unit; /* unit (chip) assigned to caller */
+- __u32 port; /* port on unit assigned to caller */
++ __u16 port; /* port on unit assigned to caller */
++ __u16 subport; /* subport on unit assigned to caller */
++ __u16 num_ports; /* number of ports available on unit */
++ __u16 num_subports; /* number of subport slaves opened on port */
+ };
+
+ struct ipath_tid_info {
+@@ -437,6 +461,8 @@ struct ipath_cmd {
+ __u32 recv_ctrl;
+ /* partition key to set */
+ __u16 part_key;
++ /* user address of __u32 bitmask of active slaves */
++ __u64 slave_mask_addr;
+ } cmd;
+ };
+
+@@ -465,12 +491,11 @@ struct __ipath_sendpkt {
+ struct ipath_iovec sps_iov[4];
+ };
+
+-/* Passed into SMA special file's ->read and ->write methods. */
+-struct ipath_sma_pkt
+-{
+- __u32 unit; /* unit on which to send packet */
+- __u64 data; /* address of payload in userspace */
+- __u32 len; /* length of payload */
++/* Passed into diag data special file's ->write method. */
++struct ipath_diag_pkt {
++ __u32 unit;
++ __u64 data;
++ __u32 len;
+ };
+
+ /*
+@@ -599,6 +624,10 @@ struct infinipath_counters {
+
+ /* K_PktFlags bits */
+ #define INFINIPATH_KPF_INTR 0x1
++#define INFINIPATH_KPF_SUBPORT_MASK 0x3
++#define INFINIPATH_KPF_SUBPORT_SHIFT 1
++
++#define INFINIPATH_MAX_SUBPORT 4
+
+ /* SendPIO per-buffer control */
+ #define INFINIPATH_SP_TEST 0x40
+@@ -613,7 +642,7 @@ struct ipath_header {
+ /*
+ * Version - 4 bits, Port - 4 bits, TID - 10 bits and Offset -
+ * 14 bits before ECO change ~28 Dec 03. After that, Vers 4,
+- * Port 3, TID 11, offset 14.
++ * Port 4, TID 11, offset 13.
+ */
+ __le32 ver_port_tid_offset;
+ __le16 chksum;
+diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
+index 3efee34..87462e0 100644
+--- a/drivers/infiniband/hw/ipath/ipath_cq.c
++++ b/drivers/infiniband/hw/ipath/ipath_cq.c
+@@ -42,20 +42,29 @@
+ * @entry: work completion entry to add
+ * @sig: true if @entry is a solicitated entry
+ *
+- * This may be called with one of the qp->s_lock or qp->r_rq.lock held.
++ * This may be called with qp->s_lock held.
+ */
+ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
+ {
++ struct ipath_cq_wc *wc;
+ unsigned long flags;
++ u32 head;
+ u32 next;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
+- if (cq->head == cq->ibcq.cqe)
++ /*
++ * Note that the head pointer might be writable by user processes.
++ * Take care to verify it is a sane value.
++ */
++ wc = cq->queue;
++ head = wc->head;
++ if (head >= (unsigned) cq->ibcq.cqe) {
++ head = cq->ibcq.cqe;
+ next = 0;
+- else
+- next = cq->head + 1;
+- if (unlikely(next == cq->tail)) {
++ } else
++ next = head + 1;
++ if (unlikely(next == wc->tail)) {
+ spin_unlock_irqrestore(&cq->lock, flags);
+ if (cq->ibcq.event_handler) {
+ struct ib_event ev;
+@@ -67,8 +76,8 @@ void ipath_cq_enter(struct ipath_cq *cq,
+ }
+ return;
+ }
+- cq->queue[cq->head] = *entry;
+- cq->head = next;
++ wc->queue[head] = *entry;
++ wc->head = next;
+
+ if (cq->notify == IB_CQ_NEXT_COMP ||
+ (cq->notify == IB_CQ_SOLICITED && solicited)) {
+@@ -101,20 +110,27 @@ void ipath_cq_enter(struct ipath_cq *cq,
+ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+ {
+ struct ipath_cq *cq = to_icq(ibcq);
++ struct ipath_cq_wc *wc;
+ unsigned long flags;
+ int npolled;
++ u32 tail;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
++ wc = cq->queue;
++ tail = wc->tail;
++ if (tail > (u32) cq->ibcq.cqe)
++ tail = (u32) cq->ibcq.cqe;
+ for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
+- if (cq->tail == cq->head)
++ if (tail == wc->head)
+ break;
+- *entry = cq->queue[cq->tail];
+- if (cq->tail == cq->ibcq.cqe)
+- cq->tail = 0;
++ *entry = wc->queue[tail];
++ if (tail >= cq->ibcq.cqe)
++ tail = 0;
+ else
+- cq->tail++;
++ tail++;
+ }
++ wc->tail = tail;
+
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+@@ -160,38 +176,79 @@ struct ib_cq *ipath_create_cq(struct ib_
+ {
+ struct ipath_ibdev *dev = to_idev(ibdev);
+ struct ipath_cq *cq;
+- struct ib_wc *wc;
++ struct ipath_cq_wc *wc;
+ struct ib_cq *ret;
+
+- if (entries > ib_ipath_max_cqes) {
++ if (entries < 1 || entries > ib_ipath_max_cqes) {
+ ret = ERR_PTR(-EINVAL);
+- goto bail;
++ goto done;
+ }
+
+- if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
++ /* Allocate the completion queue structure. */
++ cq = kmalloc(sizeof(*cq), GFP_KERNEL);
++ if (!cq) {
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto done;
+ }
+
+ /*
+- * Need to use vmalloc() if we want to support large #s of
+- * entries.
++ * Allocate the completion queue entries and head/tail pointers.
++ * This is allocated separately so that it can be resized and
++ * also mapped into user space.
++ * We need to use vmalloc() in order to support mmap and large
++ * numbers of entries.
+ */
+- cq = kmalloc(sizeof(*cq), GFP_KERNEL);
+- if (!cq) {
++ wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries);
++ if (!wc) {
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto bail_cq;
+ }
+
+ /*
+- * Need to use vmalloc() if we want to support large #s of entries.
++ * Return the address of the WC as the offset to mmap.
++ * See ipath_mmap() for details.
+ */
+- wc = vmalloc(sizeof(*wc) * (entries + 1));
+- if (!wc) {
+- kfree(cq);
++ if (udata && udata->outlen >= sizeof(__u64)) {
++ struct ipath_mmap_info *ip;
++ __u64 offset = (__u64) wc;
++ int err;
++
++ err = ib_copy_to_udata(udata, &offset, sizeof(offset));
++ if (err) {
++ ret = ERR_PTR(err);
++ goto bail_wc;
++ }
++
++ /* Allocate info for ipath_mmap(). */
++ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
++ if (!ip) {
++ ret = ERR_PTR(-ENOMEM);
++ goto bail_wc;
++ }
++ cq->ip = ip;
++ ip->context = context;
++ ip->obj = wc;
++ kref_init(&ip->ref);
++ ip->mmap_cnt = 0;
++ ip->size = PAGE_ALIGN(sizeof(*wc) +
++ sizeof(struct ib_wc) * entries);
++ spin_lock_irq(&dev->pending_lock);
++ ip->next = dev->pending_mmaps;
++ dev->pending_mmaps = ip;
++ spin_unlock_irq(&dev->pending_lock);
++ } else
++ cq->ip = NULL;
++
++ spin_lock(&dev->n_cqs_lock);
++ if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
++ spin_unlock(&dev->n_cqs_lock);
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto bail_wc;
+ }
++
++ dev->n_cqs_allocated++;
++ spin_unlock(&dev->n_cqs_lock);
++
+ /*
+ * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
+ * The number of entries should be >= the number requested or return
+@@ -202,15 +259,21 @@ struct ib_cq *ipath_create_cq(struct ib_
+ cq->triggered = 0;
+ spin_lock_init(&cq->lock);
+ tasklet_init(&cq->comptask, send_complete, (unsigned long)cq);
+- cq->head = 0;
+- cq->tail = 0;
++ wc->head = 0;
++ wc->tail = 0;
+ cq->queue = wc;
+
+ ret = &cq->ibcq;
+
+- dev->n_cqs_allocated++;
++ goto done;
+
+-bail:
++bail_wc:
++ vfree(wc);
++
++bail_cq:
++ kfree(cq);
++
++done:
+ return ret;
+ }
+
+@@ -228,8 +291,13 @@ int ipath_destroy_cq(struct ib_cq *ibcq)
+ struct ipath_cq *cq = to_icq(ibcq);
+
+ tasklet_kill(&cq->comptask);
++ spin_lock(&dev->n_cqs_lock);
+ dev->n_cqs_allocated--;
+- vfree(cq->queue);
++ spin_unlock(&dev->n_cqs_lock);
++ if (cq->ip)
++ kref_put(&cq->ip->ref, ipath_release_mmap_info);
++ else
++ vfree(cq->queue);
+ kfree(cq);
+
+ return 0;
+@@ -253,7 +321,7 @@ int ipath_req_notify_cq(struct ib_cq *ib
+ spin_lock_irqsave(&cq->lock, flags);
+ /*
+ * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow
+- * any other transitions.
++ * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
+ */
+ if (cq->notify != IB_CQ_NEXT_COMP)
+ cq->notify = notify;
+@@ -261,49 +329,96 @@ int ipath_req_notify_cq(struct ib_cq *ib
+ return 0;
+ }
+
++/**
++ * ipath_resize_cq - change the size of the CQ
++ * @ibcq: the completion queue
++ *
++ * Returns 0 for success.
++ */
+ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
+ {
+ struct ipath_cq *cq = to_icq(ibcq);
+- struct ib_wc *wc, *old_wc;
+- u32 n;
++ struct ipath_cq_wc *old_wc;
++ struct ipath_cq_wc *wc;
++ u32 head, tail, n;
+ int ret;
+
++ if (cqe < 1 || cqe > ib_ipath_max_cqes) {
++ ret = -EINVAL;
++ goto bail;
++ }
++
+ /*
+ * Need to use vmalloc() if we want to support large #s of entries.
+ */
+- wc = vmalloc(sizeof(*wc) * (cqe + 1));
++ wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe);
+ if (!wc) {
+ ret = -ENOMEM;
+ goto bail;
+ }
+
++ /*
++ * Return the address of the WC as the offset to mmap.
++ * See ipath_mmap() for details.
++ */
++ if (udata && udata->outlen >= sizeof(__u64)) {
++ __u64 offset = (__u64) wc;
++
++ ret = ib_copy_to_udata(udata, &offset, sizeof(offset));
++ if (ret)
++ goto bail;
++ }
++
+ spin_lock_irq(&cq->lock);
+- if (cq->head < cq->tail)
+- n = cq->ibcq.cqe + 1 + cq->head - cq->tail;
++ /*
++ * Make sure head and tail are sane since they
++ * might be user writable.
++ */
++ old_wc = cq->queue;
++ head = old_wc->head;
++ if (head > (u32) cq->ibcq.cqe)
++ head = (u32) cq->ibcq.cqe;
++ tail = old_wc->tail;
++ if (tail > (u32) cq->ibcq.cqe)
++ tail = (u32) cq->ibcq.cqe;
++ if (head < tail)
++ n = cq->ibcq.cqe + 1 + head - tail;
+ else
+- n = cq->head - cq->tail;
++ n = head - tail;
+ if (unlikely((u32)cqe < n)) {
+ spin_unlock_irq(&cq->lock);
+ vfree(wc);
+ ret = -EOVERFLOW;
+ goto bail;
+ }
+- for (n = 0; cq->tail != cq->head; n++) {
+- wc[n] = cq->queue[cq->tail];
+- if (cq->tail == cq->ibcq.cqe)
+- cq->tail = 0;
++ for (n = 0; tail != head; n++) {
++ wc->queue[n] = old_wc->queue[tail];
++ if (tail == (u32) cq->ibcq.cqe)
++ tail = 0;
+ else
+- cq->tail++;
++ tail++;
+ }
+ cq->ibcq.cqe = cqe;
+- cq->head = n;
+- cq->tail = 0;
+- old_wc = cq->queue;
++ wc->head = n;
++ wc->tail = 0;
+ cq->queue = wc;
+ spin_unlock_irq(&cq->lock);
+
+ vfree(old_wc);
+
++ if (cq->ip) {
++ struct ipath_ibdev *dev = to_idev(ibcq->device);
++ struct ipath_mmap_info *ip = cq->ip;
++
++ ip->obj = wc;
++ ip->size = PAGE_ALIGN(sizeof(*wc) +
++ sizeof(struct ib_wc) * cqe);
++ spin_lock_irq(&dev->pending_lock);
++ ip->next = dev->pending_mmaps;
++ dev->pending_mmaps = ip;
++ spin_unlock_irq(&dev->pending_lock);
++ }
++
+ ret = 0;
+
+ bail:
+diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
+index f415bed..df69f0d 100644
+--- a/drivers/infiniband/hw/ipath/ipath_debug.h
++++ b/drivers/infiniband/hw/ipath/ipath_debug.h
+@@ -60,7 +60,6 @@
+ #define __IPATH_USER_SEND 0x1000 /* use user mode send */
+ #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */
+ #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */
+-#define __IPATH_SMADBG 0x8000 /* sma packet debug */
+ #define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */
+ #define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */
+ #define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */
+@@ -84,7 +83,6 @@
+ /* print mmap/nopage stuff, not using VDBG any more */
+ #define __IPATH_MMDBG 0x0
+ #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */
+-#define __IPATH_SMADBG 0x0 /* process startup (init)/exit messages */
+ #define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */
+ #define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */
+ #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */
+diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
+index 147dd89..28c087b 100644
+--- a/drivers/infiniband/hw/ipath/ipath_diag.c
++++ b/drivers/infiniband/hw/ipath/ipath_diag.c
+@@ -41,11 +41,12 @@
+ * through the /sys/bus/pci resource mmap interface.
+ */
+
++#include <linux/io.h>
+ #include <linux/pci.h>
++#include <linux/vmalloc.h>
+ #include <asm/uaccess.h>
+
+ #include "ipath_kernel.h"
+-#include "ipath_layer.h"
+ #include "ipath_common.h"
+
+ int ipath_diag_inuse;
+@@ -66,19 +67,54 @@ static struct file_operations diag_file_
+ .release = ipath_diag_release
+ };
+
++static ssize_t ipath_diagpkt_write(struct file *fp,
++ const char __user *data,
++ size_t count, loff_t *off);
++
++static struct file_operations diagpkt_file_ops = {
++ .owner = THIS_MODULE,
++ .write = ipath_diagpkt_write,
++};
++
++static atomic_t diagpkt_count = ATOMIC_INIT(0);
++static struct cdev *diagpkt_cdev;
++static struct class_device *diagpkt_class_dev;
++
+ int ipath_diag_add(struct ipath_devdata *dd)
+ {
+ char name[16];
++ int ret = 0;
++
++ if (atomic_inc_return(&diagpkt_count) == 1) {
++ ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR,
++ "ipath_diagpkt", &diagpkt_file_ops,
++ &diagpkt_cdev, &diagpkt_class_dev);
++
++ if (ret) {
++ ipath_dev_err(dd, "Couldn't create ipath_diagpkt "
++ "device: %d", ret);
++ goto done;
++ }
++ }
+
+ snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
+
+- return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
+- &diag_file_ops, &dd->diag_cdev,
+- &dd->diag_class_dev);
++ ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
++ &diag_file_ops, &dd->diag_cdev,
++ &dd->diag_class_dev);
++ if (ret)
++ ipath_dev_err(dd, "Couldn't create %s device: %d",
++ name, ret);
++
++done:
++ return ret;
+ }
+
+ void ipath_diag_remove(struct ipath_devdata *dd)
+ {
++ if (atomic_dec_and_test(&diagpkt_count))
++ ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev);
++
+ ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev);
+ }
+
+@@ -274,6 +310,134 @@ bail:
+ return ret;
+ }
+
++/**
++ * ipath_diagpkt_write - write an IB packet
++ * @fp: the diag data device file pointer
++ * @data: ipath_diag_pkt structure saying where to get the packet
++ * @count: size of data to write
++ * @off: unused by this code
++ */
++static ssize_t ipath_diagpkt_write(struct file *fp,
++ const char __user *data,
++ size_t count, loff_t *off)
++{
++ u32 __iomem *piobuf;
++ u32 plen, clen, pbufn;
++ struct ipath_diag_pkt dp;
++ u32 *tmpbuf = NULL;
++ struct ipath_devdata *dd;
++ ssize_t ret = 0;
++ u64 val;
++
++ if (count < sizeof(dp)) {
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ if (copy_from_user(&dp, data, sizeof(dp))) {
++ ret = -EFAULT;
++ goto bail;
++ }
++
++ /* send count must be an exact number of dwords */
++ if (dp.len & 3) {
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ clen = dp.len >> 2;
++
++ dd = ipath_lookup(dp.unit);
++ if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
++ !dd->ipath_kregbase) {
++ ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
++ dp.unit);
++ ret = -ENODEV;
++ goto bail;
++ }
++
++ if (ipath_diag_inuse && !diag_set_link &&
++ !(dd->ipath_flags & IPATH_LINKACTIVE)) {
++ diag_set_link = 1;
++ ipath_cdbg(VERBOSE, "Trying to set to set link active for "
++ "diag pkt\n");
++ ipath_set_linkstate(dd, IPATH_IB_LINKARM);
++ ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
++ }
++
++ if (!(dd->ipath_flags & IPATH_INITTED)) {
++ /* no hardware, freeze, etc. */
++ ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
++ ret = -ENODEV;
++ goto bail;
++ }
++ val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
++ if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM &&
++ val != IPATH_IBSTATE_ACTIVE) {
++ ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
++ dd->ipath_unit, (unsigned long long) val);
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ /* need total length before first word written */
++ /* +1 word is for the qword padding */
++ plen = sizeof(u32) + dp.len;
++
++ if ((plen + 4) > dd->ipath_ibmaxlen) {
++ ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
++ plen - 4, dd->ipath_ibmaxlen);
++ ret = -EINVAL;
++ goto bail; /* before writing pbc */
++ }
++ tmpbuf = vmalloc(plen);
++ if (!tmpbuf) {
++ dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
++ "failing\n");
++ ret = -ENOMEM;
++ goto bail;
++ }
++
++ if (copy_from_user(tmpbuf,
++ (const void __user *) (unsigned long) dp.data,
++ dp.len)) {
++ ret = -EFAULT;
++ goto bail;
++ }
++
++ piobuf = ipath_getpiobuf(dd, &pbufn);
++ if (!piobuf) {
++ ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
++ dd->ipath_unit);
++ ret = -EBUSY;
++ goto bail;
++ }
++
++ plen >>= 2; /* in dwords */
++
++ if (ipath_debug & __IPATH_PKTDBG)
++ ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
++ dd->ipath_unit, plen - 1, pbufn);
++
++ /* we have to flush after the PBC for correctness on some cpus
++ * or WC buffer can be written out of order */
++ writeq(plen, piobuf);
++ ipath_flush_wc();
++ /* copy all by the trigger word, then flush, so it's written
++ * to chip before trigger word, then write trigger word, then
++ * flush again, so packet is sent. */
++ __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
++ ipath_flush_wc();
++ __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
++ ipath_flush_wc();
++
++ ret = sizeof(dp);
++
++bail:
++ vfree(tmpbuf);
++ return ret;
++}
++
+ static int ipath_diag_release(struct inode *in, struct file *fp)
+ {
+ mutex_lock(&ipath_mutex);
+diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
+index f98518d..b4ffaa7 100644
+--- a/drivers/infiniband/hw/ipath/ipath_driver.c
++++ b/drivers/infiniband/hw/ipath/ipath_driver.c
+@@ -39,7 +39,7 @@
+ #include <linux/vmalloc.h>
+
+ #include "ipath_kernel.h"
+-#include "ipath_layer.h"
++#include "ipath_verbs.h"
+ #include "ipath_common.h"
+
+ static void ipath_update_pio_bufs(struct ipath_devdata *);
+@@ -51,8 +51,6 @@ const char *ipath_get_unit_name(int unit
+ return iname;
+ }
+
+-EXPORT_SYMBOL_GPL(ipath_get_unit_name);
+-
+ #define DRIVER_LOAD_MSG "QLogic " IPATH_DRV_NAME " loaded: "
+ #define PFX IPATH_DRV_NAME ": "
+
+@@ -60,13 +58,13 @@ EXPORT_SYMBOL_GPL(ipath_get_unit_name);
+ * The size has to be longer than this string, so we can append
+ * board/chip information to it in the init code.
+ */
+-const char ipath_core_version[] = IPATH_IDSTR "\n";
++const char ib_ipath_version[] = IPATH_IDSTR "\n";
+
+ static struct idr unit_table;
+ DEFINE_SPINLOCK(ipath_devs_lock);
+ LIST_HEAD(ipath_dev_list);
+
+-wait_queue_head_t ipath_sma_state_wait;
++wait_queue_head_t ipath_state_wait;
+
+ unsigned ipath_debug = __IPATH_INFO;
+
+@@ -97,16 +95,6 @@ const char *ipath_ibcstatus_str[] = {
+ "RecovIdle",
+ };
+
+-/*
+- * These variables are initialized in the chip-specific files
+- * but are defined here.
+- */
+-u16 ipath_gpio_sda_num, ipath_gpio_scl_num;
+-u64 ipath_gpio_sda, ipath_gpio_scl;
+-u64 infinipath_i_bitsextant;
+-ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
+-u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
+-
+ static void __devexit ipath_remove_one(struct pci_dev *);
+ static int __devinit ipath_init_one(struct pci_dev *,
+ const struct pci_device_id *);
+@@ -403,10 +391,10 @@ static int __devinit ipath_init_one(stru
+ /* setup the chip-specific functions, as early as possible. */
+ switch (ent->device) {
+ case PCI_DEVICE_ID_INFINIPATH_HT:
+- ipath_init_ht400_funcs(dd);
++ ipath_init_iba6110_funcs(dd);
+ break;
+ case PCI_DEVICE_ID_INFINIPATH_PE800:
+- ipath_init_pe800_funcs(dd);
++ ipath_init_iba6120_funcs(dd);
+ break;
+ default:
+ ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
+@@ -440,7 +428,13 @@ static int __devinit ipath_init_one(stru
+ }
+ dd->ipath_pcirev = rev;
+
++#if defined(__powerpc__)
++ /* There isn't a generic way to specify writethrough mappings */
++ dd->ipath_kregbase = __ioremap(addr, len,
++ (_PAGE_NO_CACHE|_PAGE_WRITETHRU));
++#else
+ dd->ipath_kregbase = ioremap_nocache(addr, len);
++#endif
+
+ if (!dd->ipath_kregbase) {
+ ipath_dbg("Unable to map io addr %llx to kvirt, failing\n",
+@@ -503,7 +497,7 @@ static int __devinit ipath_init_one(stru
+ ipathfs_add_device(dd);
+ ipath_user_add(dd);
+ ipath_diag_add(dd);
+- ipath_layer_add(dd);
++ ipath_register_ib_device(dd);
+
+ goto bail;
+
+@@ -523,28 +517,146 @@ bail:
+ return ret;
+ }
+
++static void __devexit cleanup_device(struct ipath_devdata *dd)
++{
++ int port;
++
++ ipath_shutdown_device(dd);
++
++ if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
++ /* can't do anything more with chip; needs re-init */
++ *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
++ if (dd->ipath_kregbase) {
++ /*
++ * if we haven't already cleaned up before these are
++ * to ensure any register reads/writes "fail" until
++ * re-init
++ */
++ dd->ipath_kregbase = NULL;
++ dd->ipath_uregbase = 0;
++ dd->ipath_sregbase = 0;
++ dd->ipath_cregbase = 0;
++ dd->ipath_kregsize = 0;
++ }
++ ipath_disable_wc(dd);
++ }
++
++ if (dd->ipath_pioavailregs_dma) {
++ dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
++ (void *) dd->ipath_pioavailregs_dma,
++ dd->ipath_pioavailregs_phys);
++ dd->ipath_pioavailregs_dma = NULL;
++ }
++ if (dd->ipath_dummy_hdrq) {
++ dma_free_coherent(&dd->pcidev->dev,
++ dd->ipath_pd[0]->port_rcvhdrq_size,
++ dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
++ dd->ipath_dummy_hdrq = NULL;
++ }
++
++ if (dd->ipath_pageshadow) {
++ struct page **tmpp = dd->ipath_pageshadow;
++ dma_addr_t *tmpd = dd->ipath_physshadow;
++ int i, cnt = 0;
++
++ ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
++ "locked\n");
++ for (port = 0; port < dd->ipath_cfgports; port++) {
++ int port_tidbase = port * dd->ipath_rcvtidcnt;
++ int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
++ for (i = port_tidbase; i < maxtid; i++) {
++ if (!tmpp[i])
++ continue;
++ pci_unmap_page(dd->pcidev, tmpd[i],
++ PAGE_SIZE, PCI_DMA_FROMDEVICE);
++ ipath_release_user_pages(&tmpp[i], 1);
++ tmpp[i] = NULL;
++ cnt++;
++ }
++ }
++ if (cnt) {
++ ipath_stats.sps_pageunlocks += cnt;
++ ipath_cdbg(VERBOSE, "There were still %u expTID "
++ "entries locked\n", cnt);
++ }
++ if (ipath_stats.sps_pagelocks ||
++ ipath_stats.sps_pageunlocks)
++ ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
++ "unlocked via ipath_m{un}lock\n",
++ (unsigned long long)
++ ipath_stats.sps_pagelocks,
++ (unsigned long long)
++ ipath_stats.sps_pageunlocks);
++
++ ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
++ dd->ipath_pageshadow);
++ vfree(dd->ipath_pageshadow);
++ dd->ipath_pageshadow = NULL;
++ }
++
++ /*
++ * free any resources still in use (usually just kernel ports)
++ * at unload; we do for portcnt, not cfgports, because cfgports
++ * could have changed while we were loaded.
++ */
++ for (port = 0; port < dd->ipath_portcnt; port++) {
++ struct ipath_portdata *pd = dd->ipath_pd[port];
++ dd->ipath_pd[port] = NULL;
++ ipath_free_pddata(dd, pd);
++ }
++ kfree(dd->ipath_pd);
++ /*
++ * debuggability, in case some cleanup path tries to use it
++ * after this
++ */
++ dd->ipath_pd = NULL;
++}
++
+ static void __devexit ipath_remove_one(struct pci_dev *pdev)
+ {
+- struct ipath_devdata *dd;
++ struct ipath_devdata *dd = pci_get_drvdata(pdev);
+
+- ipath_cdbg(VERBOSE, "removing, pdev=%p\n", pdev);
+- if (!pdev)
+- return;
++ ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd);
++
++ if (dd->verbs_dev)
++ ipath_unregister_ib_device(dd->verbs_dev);
+
+- dd = pci_get_drvdata(pdev);
+- ipath_layer_remove(dd);
+ ipath_diag_remove(dd);
+ ipath_user_remove(dd);
+ ipathfs_remove_device(dd);
+ ipath_device_remove_group(&pdev->dev, dd);
++
+ ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, "
+ "unit %u\n", dd, (u32) dd->ipath_unit);
+- if (dd->ipath_kregbase) {
+- ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n",
+- dd->ipath_kregbase);
+- iounmap((volatile void __iomem *) dd->ipath_kregbase);
+- dd->ipath_kregbase = NULL;
+- }
++
++ cleanup_device(dd);
++
++ /*
++ * turn off rcv, send, and interrupts for all ports, all drivers
++ * should also hard reset the chip here?
++ * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
++ * for all versions of the driver, if they were allocated
++ */
++ if (pdev->irq) {
++ ipath_cdbg(VERBOSE,
++ "unit %u free_irq of irq %x\n",
++ dd->ipath_unit, pdev->irq);
++ free_irq(pdev->irq, dd);
++ } else
++ ipath_dbg("irq is 0, not doing free_irq "
++ "for unit %u\n", dd->ipath_unit);
++ /*
++ * we check for NULL here, because it's outside
++ * the kregbase check, and we need to call it
++ * after the free_irq. Thus it's possible that
++ * the function pointers were never initialized.
++ */
++ if (dd->ipath_f_cleanup)
++ /* clean up chip-specific stuff */
++ dd->ipath_f_cleanup(dd);
++
++ ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", dd->ipath_kregbase);
++ iounmap((volatile void __iomem *) dd->ipath_kregbase);
+ pci_release_regions(pdev);
+ ipath_cdbg(VERBOSE, "calling pci_disable_device\n");
+ pci_disable_device(pdev);
+@@ -607,21 +719,23 @@ void ipath_disarm_piobufs(struct ipath_d
+ *
+ * wait up to msecs milliseconds for IB link state change to occur for
+ * now, take the easy polling route. Currently used only by
+- * ipath_layer_set_linkstate. Returns 0 if state reached, otherwise
++ * ipath_set_linkstate. Returns 0 if state reached, otherwise
+ * -ETIMEDOUT state can have multiple states set, for any of several
+ * transitions.
+ */
+-int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
++static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state,
++ int msecs)
+ {
+- dd->ipath_sma_state_wanted = state;
+- wait_event_interruptible_timeout(ipath_sma_state_wait,
++ dd->ipath_state_wanted = state;
++ wait_event_interruptible_timeout(ipath_state_wait,
+ (dd->ipath_flags & state),
+ msecs_to_jiffies(msecs));
+- dd->ipath_sma_state_wanted = 0;
++ dd->ipath_state_wanted = 0;
+
+ if (!(dd->ipath_flags & state)) {
+ u64 val;
+- ipath_cdbg(SMA, "Didn't reach linkstate %s within %u ms\n",
++ ipath_cdbg(VERBOSE, "Didn't reach linkstate %s within %u"
++ " ms\n",
+ /* test INIT ahead of DOWN, both can be set */
+ (state & IPATH_LINKINIT) ? "INIT" :
+ ((state & IPATH_LINKDOWN) ? "DOWN" :
+@@ -754,8 +868,8 @@ static void get_rhf_errstring(u32 err, c
+ static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
+ int err)
+ {
+- return dd->ipath_port0_skbs ?
+- (void *)dd->ipath_port0_skbs[bufnum]->data : NULL;
++ return dd->ipath_port0_skbinfo ?
++ (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
+ }
+
+ /**
+@@ -777,88 +891,39 @@ struct sk_buff *ipath_alloc_skb(struct i
+ */
+
+ /*
+- * We need 4 extra bytes for unaligned transfer copying
++ * We need 2 extra bytes for ipath_ether data sent in the
++ * key header. In order to keep everything dword aligned,
++ * we'll reserve 4 bytes.
+ */
++ len = dd->ipath_ibmaxlen + 4;
++
+ if (dd->ipath_flags & IPATH_4BYTE_TID) {
+- /* we need a 4KB multiple alignment, and there is no way
++ /* We need a 2KB multiple alignment, and there is no way
+ * to do it except to allocate extra and then skb_reserve
+ * enough to bring it up to the right alignment.
+ */
+- len = dd->ipath_ibmaxlen + 4 + (1 << 11) - 1;
++ len += 2047;
+ }
+- else
+- len = dd->ipath_ibmaxlen + 4;
++
+ skb = __dev_alloc_skb(len, gfp_mask);
+ if (!skb) {
+ ipath_dev_err(dd, "Failed to allocate skbuff, length %u\n",
+ len);
+ goto bail;
+ }
++
++ skb_reserve(skb, 4);
++
+ if (dd->ipath_flags & IPATH_4BYTE_TID) {
+- u32 una = ((1 << 11) - 1) & (unsigned long)(skb->data + 4);
++ u32 una = (unsigned long)skb->data & 2047;
+ if (una)
+- skb_reserve(skb, 4 + (1 << 11) - una);
+- else
+- skb_reserve(skb, 4);
+- } else
+- skb_reserve(skb, 4);
++ skb_reserve(skb, 2048 - una);
++ }
+
+ bail:
+ return skb;
+ }
+
+-/**
+- * ipath_rcv_layer - receive a packet for the layered (ethernet) driver
+- * @dd: the infinipath device
+- * @etail: the sk_buff number
+- * @tlen: the total packet length
+- * @hdr: the ethernet header
+- *
+- * Separate routine for better overall optimization
+- */
+-static void ipath_rcv_layer(struct ipath_devdata *dd, u32 etail,
+- u32 tlen, struct ether_header *hdr)
+-{
+- u32 elen;
+- u8 pad, *bthbytes;
+- struct sk_buff *skb, *nskb;
+-
+- if (dd->ipath_port0_skbs &&
+- hdr->sub_opcode == IPATH_ITH4X_OPCODE_ENCAP) {
+- /*
+- * Allocate a new sk_buff to replace the one we give
+- * to the network stack.
+- */
+- nskb = ipath_alloc_skb(dd, GFP_ATOMIC);
+- if (!nskb) {
+- /* count OK packets that we drop */
+- ipath_stats.sps_krdrops++;
+- return;
+- }
+-
+- bthbytes = (u8 *) hdr->bth;
+- pad = (bthbytes[1] >> 4) & 3;
+- /* +CRC32 */
+- elen = tlen - (sizeof(*hdr) + pad + sizeof(u32));
+-
+- skb = dd->ipath_port0_skbs[etail];
+- dd->ipath_port0_skbs[etail] = nskb;
+- skb_put(skb, elen);
+-
+- dd->ipath_f_put_tid(dd, etail + (u64 __iomem *)
+- ((char __iomem *) dd->ipath_kregbase
+- + dd->ipath_rcvegrbase), 0,
+- virt_to_phys(nskb->data));
+-
+- __ipath_layer_rcv(dd, hdr, skb);
+-
+- /* another ether packet received */
+- ipath_stats.sps_ether_rpkts++;
+- }
+- else if (hdr->sub_opcode == IPATH_ITH4X_OPCODE_LID_ARP)
+- __ipath_layer_rcv_lid(dd, hdr);
+-}
+-
+ static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
+ u32 eflags,
+ u32 l,
+@@ -972,26 +1037,17 @@ reloop:
+ if (unlikely(eflags))
+ ipath_rcv_hdrerr(dd, eflags, l, etail, rc);
+ else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
+- int ret = __ipath_verbs_rcv(dd, rc + 1,
+- ebuf, tlen);
+- if (ret == -ENODEV)
+- ipath_cdbg(VERBOSE,
+- "received IB packet, "
+- "not SMA (QP=%x)\n", qp);
+- if (dd->ipath_lli_counter)
+- dd->ipath_lli_counter--;
+-
+- } else if (etype == RCVHQ_RCV_TYPE_EAGER) {
+- if (qp == IPATH_KD_QP &&
+- bthbytes[0] == ipath_layer_rcv_opcode &&
+- ebuf)
+- ipath_rcv_layer(dd, etail, tlen,
+- (struct ether_header *)hdr);
+- else
+- ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
+- "qp=%x), len %x; ignored\n",
+- etype, bthbytes[0], qp, tlen);
++ ipath_ib_rcv(dd->verbs_dev, rc + 1, ebuf, tlen);
++ if (dd->ipath_lli_counter)
++ dd->ipath_lli_counter--;
++ ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
++ "qp=%x), len %x; ignored\n",
++ etype, bthbytes[0], qp, tlen);
+ }
++ else if (etype == RCVHQ_RCV_TYPE_EAGER)
++ ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
++ "qp=%x), len %x; ignored\n",
++ etype, bthbytes[0], qp, tlen);
+ else if (etype == RCVHQ_RCV_TYPE_EXPECTED)
+ ipath_dbg("Bug: Expected TID, opcode %x; ignored\n",
+ be32_to_cpu(hdr->bth[0]) & 0xff);
+@@ -1024,7 +1080,8 @@ reloop:
+ */
+ if (l == hdrqtail || (i && !(i&0xf))) {
+ u64 lval;
+- if (l == hdrqtail) /* PE-800 interrupt only on last */
++ if (l == hdrqtail)
++ /* request IBA6120 interrupt only on last */
+ lval = dd->ipath_rhdrhead_intr_off | l;
+ else
+ lval = l;
+@@ -1038,7 +1095,7 @@ reloop:
+ }
+
+ if (!dd->ipath_rhdrhead_intr_off && !reloop) {
+- /* HT-400 workaround; we can have a race clearing chip
++ /* IBA6110 workaround; we can have a race clearing chip
+ * interrupt with another interrupt about to be delivered,
+ * and can clear it before it is delivered on the GPIO
+ * workaround. By doing the extra check here for the
+@@ -1211,7 +1268,7 @@ int ipath_setrcvhdrsize(struct ipath_dev
+ *
+ * do appropriate marking as busy, etc.
+ * returns buffer number if one found (>=0), negative number is error.
+- * Used by ipath_sma_send_pkt and ipath_layer_send
++ * Used by ipath_layer_send
+ */
+ u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 * pbufnum)
+ {
+@@ -1317,13 +1374,6 @@ rescan:
+ goto bail;
+ }
+
+- if (updated)
+- /*
+- * ran out of bufs, now some (at least this one we just
+- * got) are now available, so tell the layered driver.
+- */
+- __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE);
+-
+ /*
+ * set next starting place. Since it's just an optimization,
+ * it doesn't matter who wins on this, so no locking
+@@ -1387,6 +1437,9 @@ int ipath_create_rcvhdrq(struct ipath_de
+ "for port %u rcvhdrqtailaddr failed\n",
+ pd->port_port);
+ ret = -ENOMEM;
++ dma_free_coherent(&dd->pcidev->dev, amt,
++ pd->port_rcvhdrq, pd->port_rcvhdrq_phys);
++ pd->port_rcvhdrq = NULL;
+ goto bail;
+ }
+ pd->port_rcvhdrqtailaddr_phys = phys_hdrqtail;
+@@ -1408,12 +1461,13 @@ int ipath_create_rcvhdrq(struct ipath_de
+ ipath_cdbg(VERBOSE, "reuse port %d rcvhdrq @%p %llx phys; "
+ "hdrtailaddr@%p %llx physical\n",
+ pd->port_port, pd->port_rcvhdrq,
+- pd->port_rcvhdrq_phys, pd->port_rcvhdrtail_kvaddr,
+- (unsigned long long)pd->port_rcvhdrqtailaddr_phys);
++ (unsigned long long) pd->port_rcvhdrq_phys,
++ pd->port_rcvhdrtail_kvaddr, (unsigned long long)
++ pd->port_rcvhdrqtailaddr_phys);
+
+ /* clear for security and sanity on each use */
+ memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
+- memset((void *)pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
++ memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+
+ /*
+ * tell chip each time we init it, even if we are re-using previous
+@@ -1500,7 +1554,7 @@ int ipath_waitfor_mdio_cmdready(struct i
+ return ret;
+ }
+
+-void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
++static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
+ {
+ static const char *what[4] = {
+ [0] = "DOWN",
+@@ -1511,7 +1565,7 @@ void ipath_set_ib_lstate(struct ipath_de
+ int linkcmd = (which >> INFINIPATH_IBCC_LINKCMD_SHIFT) &
+ INFINIPATH_IBCC_LINKCMD_MASK;
+
+- ipath_cdbg(SMA, "Trying to move unit %u to %s, current ltstate "
++ ipath_cdbg(VERBOSE, "Trying to move unit %u to %s, current ltstate "
+ "is %s\n", dd->ipath_unit,
+ what[linkcmd],
+ ipath_ibcstatus_str[
+@@ -1520,7 +1574,7 @@ void ipath_set_ib_lstate(struct ipath_de
+ INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
+ INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]);
+ /* flush all queued sends when going to DOWN or INIT, to be sure that
+- * they don't block SMA and other MAD packets */
++ * they don't block MAD packets */
+ if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) {
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ INFINIPATH_S_ABORT);
+@@ -1534,6 +1588,180 @@ void ipath_set_ib_lstate(struct ipath_de
+ dd->ipath_ibcctrl | which);
+ }
+
++int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
++{
++ u32 lstate;
++ int ret;
++
++ switch (newstate) {
++ case IPATH_IB_LINKDOWN:
++ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL <<
++ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
++ /* don't wait */
++ ret = 0;
++ goto bail;
++
++ case IPATH_IB_LINKDOWN_SLEEP:
++ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP <<
++ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
++ /* don't wait */
++ ret = 0;
++ goto bail;
++
++ case IPATH_IB_LINKDOWN_DISABLE:
++ ipath_set_ib_lstate(dd,
++ INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
++ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
++ /* don't wait */
++ ret = 0;
++ goto bail;
++
++ case IPATH_IB_LINKINIT:
++ if (dd->ipath_flags & IPATH_LINKINIT) {
++ ret = 0;
++ goto bail;
++ }
++ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT <<
++ INFINIPATH_IBCC_LINKCMD_SHIFT);
++ lstate = IPATH_LINKINIT;
++ break;
++
++ case IPATH_IB_LINKARM:
++ if (dd->ipath_flags & IPATH_LINKARMED) {
++ ret = 0;
++ goto bail;
++ }
++ if (!(dd->ipath_flags &
++ (IPATH_LINKINIT | IPATH_LINKACTIVE))) {
++ ret = -EINVAL;
++ goto bail;
++ }
++ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED <<
++ INFINIPATH_IBCC_LINKCMD_SHIFT);
++ /*
++ * Since the port can transition to ACTIVE by receiving
++ * a non VL 15 packet, wait for either state.
++ */
++ lstate = IPATH_LINKARMED | IPATH_LINKACTIVE;
++ break;
++
++ case IPATH_IB_LINKACTIVE:
++ if (dd->ipath_flags & IPATH_LINKACTIVE) {
++ ret = 0;
++ goto bail;
++ }
++ if (!(dd->ipath_flags & IPATH_LINKARMED)) {
++ ret = -EINVAL;
++ goto bail;
++ }
++ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE <<
++ INFINIPATH_IBCC_LINKCMD_SHIFT);
++ lstate = IPATH_LINKACTIVE;
++ break;
++
++ default:
++ ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
++ ret = -EINVAL;
++ goto bail;
++ }
++ ret = ipath_wait_linkstate(dd, lstate, 2000);
++
++bail:
++ return ret;
++}
++
++/**
++ * ipath_set_mtu - set the MTU
++ * @dd: the infinipath device
++ * @arg: the new MTU
++ *
++ * we can handle "any" incoming size, the issue here is whether we
++ * need to restrict our outgoing size. For now, we don't do any
++ * sanity checking on this, and we don't deal with what happens to
++ * programs that are already running when the size changes.
++ * NOTE: changing the MTU will usually cause the IBC to go back to
++ * link initialize (IPATH_IBSTATE_INIT) state...
++ */
++int ipath_set_mtu(struct ipath_devdata *dd, u16 arg)
++{
++ u32 piosize;
++ int changed = 0;
++ int ret;
++
++ /*
++ * mtu is IB data payload max. It's the largest power of 2 less
++ * than piosize (or even larger, since it only really controls the
++ * largest we can receive; we can send the max of the mtu and
++ * piosize). We check that it's one of the valid IB sizes.
++ */
++ if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&
++ arg != 4096) {
++ ipath_dbg("Trying to set invalid mtu %u, failing\n", arg);
++ ret = -EINVAL;
++ goto bail;
++ }
++ if (dd->ipath_ibmtu == arg) {
++ ret = 0; /* same as current */
++ goto bail;
++ }
++
++ piosize = dd->ipath_ibmaxlen;
++ dd->ipath_ibmtu = arg;
++
++ if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) {
++ /* Only if it's not the initial value (or reset to it) */
++ if (piosize != dd->ipath_init_ibmaxlen) {
++ dd->ipath_ibmaxlen = piosize;
++ changed = 1;
++ }
++ } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) {
++ piosize = arg + IPATH_PIO_MAXIBHDR;
++ ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x "
++ "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize,
++ arg);
++ dd->ipath_ibmaxlen = piosize;
++ changed = 1;
++ }
++
++ if (changed) {
++ /*
++ * set the IBC maxpktlength to the size of our pio
++ * buffers in words
++ */
++ u64 ibc = dd->ipath_ibcctrl;
++ ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK <<
++ INFINIPATH_IBCC_MAXPKTLEN_SHIFT);
++
++ piosize = piosize - 2 * sizeof(u32); /* ignore pbc */
++ dd->ipath_ibmaxlen = piosize;
++ piosize /= sizeof(u32); /* in words */
++ /*
++ * for ICRC, which we only send in diag test pkt mode, and
++ * we don't need to worry about that for mtu
++ */
++ piosize += 1;
++
++ ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
++ dd->ipath_ibcctrl = ibc;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
++ dd->ipath_ibcctrl);
++ dd->ipath_f_tidtemplate(dd);
++ }
++
++ ret = 0;
++
++bail:
++ return ret;
++}
++
++int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc)
++{
++ dd->ipath_lid = arg;
++ dd->ipath_lmc = lmc;
++
++ return 0;
++}
++
+ /**
+ * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register
+ * @dd: the infinipath device
+@@ -1637,13 +1865,6 @@ void ipath_shutdown_device(struct ipath_
+ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
+ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+
+- /*
+- * we are shutting down, so tell the layered driver. We don't do
+- * this on just a link state change, much like ethernet, a cable
+- * unplug, etc. doesn't change driver state
+- */
+- ipath_layer_intr(dd, IPATH_LAYER_INT_IF_DOWN);
+-
+ /* disable IBC */
+ dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+@@ -1699,7 +1920,7 @@ void ipath_free_pddata(struct ipath_devd
+ pd->port_rcvhdrq = NULL;
+ if (pd->port_rcvhdrtail_kvaddr) {
+ dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+- (void *)pd->port_rcvhdrtail_kvaddr,
++ pd->port_rcvhdrtail_kvaddr,
+ pd->port_rcvhdrqtailaddr_phys);
+ pd->port_rcvhdrtail_kvaddr = NULL;
+ }
+@@ -1718,24 +1939,32 @@ void ipath_free_pddata(struct ipath_devd
+ dma_free_coherent(&dd->pcidev->dev, size,
+ base, pd->port_rcvegrbuf_phys[e]);
+ }
+- vfree(pd->port_rcvegrbuf);
++ kfree(pd->port_rcvegrbuf);
+ pd->port_rcvegrbuf = NULL;
+- vfree(pd->port_rcvegrbuf_phys);
++ kfree(pd->port_rcvegrbuf_phys);
+ pd->port_rcvegrbuf_phys = NULL;
+ pd->port_rcvegrbuf_chunks = 0;
+- } else if (pd->port_port == 0 && dd->ipath_port0_skbs) {
++ } else if (pd->port_port == 0 && dd->ipath_port0_skbinfo) {
+ unsigned e;
+- struct sk_buff **skbs = dd->ipath_port0_skbs;
++ struct ipath_skbinfo *skbinfo = dd->ipath_port0_skbinfo;
+
+- dd->ipath_port0_skbs = NULL;
+- ipath_cdbg(VERBOSE, "free closed port %d ipath_port0_skbs "
+- "@ %p\n", pd->port_port, skbs);
++ dd->ipath_port0_skbinfo = NULL;
++ ipath_cdbg(VERBOSE, "free closed port %d "
++ "ipath_port0_skbinfo @ %p\n", pd->port_port,
++ skbinfo);
+ for (e = 0; e < dd->ipath_rcvegrcnt; e++)
+- if (skbs[e])
+- dev_kfree_skb(skbs[e]);
+- vfree(skbs);
++ if (skbinfo[e].skb) {
++ pci_unmap_single(dd->pcidev, skbinfo[e].phys,
++ dd->ipath_ibmaxlen,
++ PCI_DMA_FROMDEVICE);
++ dev_kfree_skb(skbinfo[e].skb);
++ }
++ vfree(skbinfo);
+ }
+ kfree(pd->port_tid_pg_list);
++ vfree(pd->subport_uregbase);
++ vfree(pd->subport_rcvegrbuf);
++ vfree(pd->subport_rcvhdr_base);
+ kfree(pd);
+ }
+
+@@ -1743,7 +1972,7 @@ static int __init infinipath_init(void)
+ {
+ int ret;
+
+- ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ipath_core_version);
++ ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version);
+
+ /*
+ * These must be called before the driver is registered with
+@@ -1791,148 +2020,12 @@ bail:
+ return ret;
+ }
+
+-static void cleanup_device(struct ipath_devdata *dd)
+-{
+- int port;
+-
+- ipath_shutdown_device(dd);
+-
+- if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
+- /* can't do anything more with chip; needs re-init */
+- *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
+- if (dd->ipath_kregbase) {
+- /*
+- * if we haven't already cleaned up before these are
+- * to ensure any register reads/writes "fail" until
+- * re-init
+- */
+- dd->ipath_kregbase = NULL;
+- dd->ipath_uregbase = 0;
+- dd->ipath_sregbase = 0;
+- dd->ipath_cregbase = 0;
+- dd->ipath_kregsize = 0;
+- }
+- ipath_disable_wc(dd);
+- }
+-
+- if (dd->ipath_pioavailregs_dma) {
+- dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+- (void *) dd->ipath_pioavailregs_dma,
+- dd->ipath_pioavailregs_phys);
+- dd->ipath_pioavailregs_dma = NULL;
+- }
+- if (dd->ipath_dummy_hdrq) {
+- dma_free_coherent(&dd->pcidev->dev,
+- dd->ipath_pd[0]->port_rcvhdrq_size,
+- dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
+- dd->ipath_dummy_hdrq = NULL;
+- }
+-
+- if (dd->ipath_pageshadow) {
+- struct page **tmpp = dd->ipath_pageshadow;
+- int i, cnt = 0;
+-
+- ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
+- "locked\n");
+- for (port = 0; port < dd->ipath_cfgports; port++) {
+- int port_tidbase = port * dd->ipath_rcvtidcnt;
+- int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
+- for (i = port_tidbase; i < maxtid; i++) {
+- if (!tmpp[i])
+- continue;
+- ipath_release_user_pages(&tmpp[i], 1);
+- tmpp[i] = NULL;
+- cnt++;
+- }
+- }
+- if (cnt) {
+- ipath_stats.sps_pageunlocks += cnt;
+- ipath_cdbg(VERBOSE, "There were still %u expTID "
+- "entries locked\n", cnt);
+- }
+- if (ipath_stats.sps_pagelocks ||
+- ipath_stats.sps_pageunlocks)
+- ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
+- "unlocked via ipath_m{un}lock\n",
+- (unsigned long long)
+- ipath_stats.sps_pagelocks,
+- (unsigned long long)
+- ipath_stats.sps_pageunlocks);
+-
+- ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
+- dd->ipath_pageshadow);
+- vfree(dd->ipath_pageshadow);
+- dd->ipath_pageshadow = NULL;
+- }
+-
+- /*
+- * free any resources still in use (usually just kernel ports)
+- * at unload; we do for portcnt, not cfgports, because cfgports
+- * could have changed while we were loaded.
+- */
+- for (port = 0; port < dd->ipath_portcnt; port++) {
+- struct ipath_portdata *pd = dd->ipath_pd[port];
+- dd->ipath_pd[port] = NULL;
+- ipath_free_pddata(dd, pd);
+- }
+- kfree(dd->ipath_pd);
+- /*
+- * debuggability, in case some cleanup path tries to use it
+- * after this
+- */
+- dd->ipath_pd = NULL;
+-}
+-
+ static void __exit infinipath_cleanup(void)
+ {
+- struct ipath_devdata *dd, *tmp;
+- unsigned long flags;
+-
+ ipath_exit_ipathfs();
+
+ ipath_driver_remove_group(&ipath_driver.driver);
+
+- spin_lock_irqsave(&ipath_devs_lock, flags);
+-
+- /*
+- * turn off rcv, send, and interrupts for all ports, all drivers
+- * should also hard reset the chip here?
+- * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
+- * for all versions of the driver, if they were allocated
+- */
+- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
+- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+-
+- if (dd->ipath_kregbase)
+- cleanup_device(dd);
+-
+- if (dd->pcidev) {
+- if (dd->pcidev->irq) {
+- ipath_cdbg(VERBOSE,
+- "unit %u free_irq of irq %x\n",
+- dd->ipath_unit, dd->pcidev->irq);
+- free_irq(dd->pcidev->irq, dd);
+- } else
+- ipath_dbg("irq is 0, not doing free_irq "
+- "for unit %u\n", dd->ipath_unit);
+-
+- /*
+- * we check for NULL here, because it's outside
+- * the kregbase check, and we need to call it
+- * after the free_irq. Thus it's possible that
+- * the function pointers were never initialized.
+- */
+- if (dd->ipath_f_cleanup)
+- /* clean up chip-specific stuff */
+- dd->ipath_f_cleanup(dd);
+-
+- dd->pcidev = NULL;
+- }
+- spin_lock_irqsave(&ipath_devs_lock, flags);
+- }
+-
+- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+-
+ ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
+ pci_unregister_driver(&ipath_driver);
+
+@@ -1998,5 +2091,22 @@ bail:
+ return ret;
+ }
+
++int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
++{
++ u64 val;
++ if ( new_pol_inv > INFINIPATH_XGXS_RX_POL_MASK ) {
++ return -1;
++ }
++ if ( dd->ipath_rx_pol_inv != new_pol_inv ) {
++ dd->ipath_rx_pol_inv = new_pol_inv;
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
++ val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
++ INFINIPATH_XGXS_RX_POL_SHIFT);
++ val |= ((u64)dd->ipath_rx_pol_inv) <<
++ INFINIPATH_XGXS_RX_POL_SHIFT;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
++ }
++ return 0;
++}
+ module_init(infinipath_init);
+ module_exit(infinipath_cleanup);
+diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
+index 3313356..a4019a6 100644
+--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
++++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
+@@ -100,9 +100,9 @@ static int i2c_gpio_set(struct ipath_dev
+ gpioval = &dd->ipath_gpio_out;
+ read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
+ if (line == i2c_line_scl)
+- mask = ipath_gpio_scl;
++ mask = dd->ipath_gpio_scl;
+ else
+- mask = ipath_gpio_sda;
++ mask = dd->ipath_gpio_sda;
+
+ if (new_line_state == i2c_line_high)
+ /* tri-state the output rather than force high */
+@@ -119,12 +119,12 @@ static int i2c_gpio_set(struct ipath_dev
+ write_val = 0x0UL;
+
+ if (line == i2c_line_scl) {
+- write_val <<= ipath_gpio_scl_num;
+- *gpioval = *gpioval & ~(1UL << ipath_gpio_scl_num);
++ write_val <<= dd->ipath_gpio_scl_num;
++ *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_scl_num);
+ *gpioval |= write_val;
+ } else {
+- write_val <<= ipath_gpio_sda_num;
+- *gpioval = *gpioval & ~(1UL << ipath_gpio_sda_num);
++ write_val <<= dd->ipath_gpio_sda_num;
++ *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_sda_num);
+ *gpioval |= write_val;
+ }
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval);
+@@ -157,9 +157,9 @@ static int i2c_gpio_get(struct ipath_dev
+ read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
+ /* config line to be an input */
+ if (line == i2c_line_scl)
+- mask = ipath_gpio_scl;
++ mask = dd->ipath_gpio_scl;
+ else
+- mask = ipath_gpio_sda;
++ mask = dd->ipath_gpio_sda;
+ write_val = read_val & ~mask;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val);
+ read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
+@@ -187,6 +187,7 @@ bail:
+ static void i2c_wait_for_writes(struct ipath_devdata *dd)
+ {
+ (void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
++ rmb();
+ }
+
+ static void scl_out(struct ipath_devdata *dd, u8 bit)
+diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
+index bbaa70e..a9ddc69 100644
+--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
++++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
+@@ -39,9 +39,14 @@
+ #include <asm/pgtable.h>
+
+ #include "ipath_kernel.h"
+-#include "ipath_layer.h"
+ #include "ipath_common.h"
+
++/*
++ * mmap64 doesn't allow all 64 bits for 32-bit applications
++ * so only use the low 43 bits.
++ */
++#define MMAP64_MASK 0x7FFFFFFFFFFUL
++
+ static int ipath_open(struct inode *, struct file *);
+ static int ipath_close(struct inode *, struct file *);
+ static ssize_t ipath_write(struct file *, const char __user *, size_t,
+@@ -58,18 +63,35 @@ static struct file_operations ipath_file
+ .mmap = ipath_mmap
+ };
+
+-static int ipath_get_base_info(struct ipath_portdata *pd,
++static int ipath_get_base_info(struct file *fp,
+ void __user *ubase, size_t ubase_size)
+ {
++ struct ipath_portdata *pd = port_fp(fp);
+ int ret = 0;
+ struct ipath_base_info *kinfo = NULL;
+ struct ipath_devdata *dd = pd->port_dd;
++ unsigned subport_cnt;
++ int shared, master;
++ size_t sz;
++
++ subport_cnt = pd->port_subport_cnt;
++ if (!subport_cnt) {
++ shared = 0;
++ master = 0;
++ subport_cnt = 1;
++ } else {
++ shared = 1;
++ master = !subport_fp(fp);
++ }
+
+- if (ubase_size < sizeof(*kinfo)) {
++ sz = sizeof(*kinfo);
++ /* If port sharing is not requested, allow the old size structure */
++ if (!shared)
++ sz -= 3 * sizeof(u64);
++ if (ubase_size < sz) {
+ ipath_cdbg(PROC,
+- "Base size %lu, need %lu (version mismatch?)\n",
+- (unsigned long) ubase_size,
+- (unsigned long) sizeof(*kinfo));
++ "Base size %zu, need %zu (version mismatch?)\n",
++ ubase_size, sz);
+ ret = -EINVAL;
+ goto bail;
+ }
+@@ -96,7 +118,9 @@ static int ipath_get_base_info(struct ip
+ kinfo->spi_rcv_egrperchunk = pd->port_rcvegrbufs_perchunk;
+ kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen /
+ pd->port_rcvegrbuf_chunks;
+- kinfo->spi_tidcnt = dd->ipath_rcvtidcnt;
++ kinfo->spi_tidcnt = dd->ipath_rcvtidcnt / subport_cnt;
++ if (master)
++ kinfo->spi_tidcnt += dd->ipath_rcvtidcnt % subport_cnt;
+ /*
+ * for this use, may be ipath_cfgports summed over all chips that
+ * are are configured and present
+@@ -119,31 +143,75 @@ static int ipath_get_base_info(struct ip
+ * page_address() macro worked, but in 2.6.11, even that returns the
+ * full 64 bit address (upper bits all 1's). So far, using the
+ * physical addresses (or chip offsets, for chip mapping) works, but
+- * no doubt some future kernel release will chang that, and we'll be
+- * on to yet another method of dealing with this
++ * no doubt some future kernel release will change that, and we'll be
++ * on to yet another method of dealing with this.
+ */
+ kinfo->spi_rcvhdr_base = (u64) pd->port_rcvhdrq_phys;
+- kinfo->spi_rcvhdr_tailaddr = (u64)pd->port_rcvhdrqtailaddr_phys;
++ kinfo->spi_rcvhdr_tailaddr = (u64) pd->port_rcvhdrqtailaddr_phys;
+ kinfo->spi_rcv_egrbufs = (u64) pd->port_rcvegr_phys;
+ kinfo->spi_pioavailaddr = (u64) dd->ipath_pioavailregs_phys;
+ kinfo->spi_status = (u64) kinfo->spi_pioavailaddr +
+ (void *) dd->ipath_statusp -
+ (void *) dd->ipath_pioavailregs_dma;
+- kinfo->spi_piobufbase = (u64) pd->port_piobufs;
+- kinfo->__spi_uregbase =
+- dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
++ if (!shared) {
++ kinfo->spi_piocnt = dd->ipath_pbufsport;
++ kinfo->spi_piobufbase = (u64) pd->port_piobufs;
++ kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
++ dd->ipath_palign * pd->port_port;
++ } else if (master) {
++ kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
++ (dd->ipath_pbufsport % subport_cnt);
++ /* Master's PIO buffers are after all the slave's */
++ kinfo->spi_piobufbase = (u64) pd->port_piobufs +
++ dd->ipath_palign *
++ (dd->ipath_pbufsport - kinfo->spi_piocnt);
++ kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
++ dd->ipath_palign * pd->port_port;
++ } else {
++ unsigned slave = subport_fp(fp) - 1;
++
++ kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt;
++ kinfo->spi_piobufbase = (u64) pd->port_piobufs +
++ dd->ipath_palign * kinfo->spi_piocnt * slave;
++ kinfo->__spi_uregbase = ((u64) pd->subport_uregbase +
++ PAGE_SIZE * slave) & MMAP64_MASK;
+
+- kinfo->spi_pioindex = dd->ipath_pbufsport * (pd->port_port - 1);
+- kinfo->spi_piocnt = dd->ipath_pbufsport;
++ kinfo->spi_rcvhdr_base = ((u64) pd->subport_rcvhdr_base +
++ pd->port_rcvhdrq_size * slave) & MMAP64_MASK;
++ kinfo->spi_rcvhdr_tailaddr =
++ (u64) pd->port_rcvhdrqtailaddr_phys & MMAP64_MASK;
++ kinfo->spi_rcv_egrbufs = ((u64) pd->subport_rcvegrbuf +
++ dd->ipath_rcvegrcnt * dd->ipath_rcvegrbufsize * slave) &
++ MMAP64_MASK;
++ }
++
++ kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) /
++ dd->ipath_palign;
+ kinfo->spi_pioalign = dd->ipath_palign;
+
+ kinfo->spi_qpair = IPATH_KD_QP;
+ kinfo->spi_piosize = dd->ipath_ibmaxlen;
+ kinfo->spi_mtu = dd->ipath_ibmaxlen; /* maxlen, not ibmtu */
+ kinfo->spi_port = pd->port_port;
++ kinfo->spi_subport = subport_fp(fp);
+ kinfo->spi_sw_version = IPATH_KERN_SWVERSION;
+ kinfo->spi_hw_version = dd->ipath_revision;
+
++ if (master) {
++ kinfo->spi_runtime_flags |= IPATH_RUNTIME_MASTER;
++ kinfo->spi_subport_uregbase =
++ (u64) pd->subport_uregbase & MMAP64_MASK;
++ kinfo->spi_subport_rcvegrbuf =
++ (u64) pd->subport_rcvegrbuf & MMAP64_MASK;
++ kinfo->spi_subport_rcvhdr_base =
++ (u64) pd->subport_rcvhdr_base & MMAP64_MASK;
++ ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n",
++ kinfo->spi_port, kinfo->spi_runtime_flags,
++ (unsigned long long) kinfo->spi_subport_uregbase,
++ (unsigned long long) kinfo->spi_subport_rcvegrbuf,
++ (unsigned long long) kinfo->spi_subport_rcvhdr_base);
++ }
++
+ if (copy_to_user(ubase, kinfo, sizeof(*kinfo)))
+ ret = -EFAULT;
+
+@@ -155,6 +223,7 @@ bail:
+ /**
+ * ipath_tid_update - update a port TID
+ * @pd: the port
++ * @fp: the ipath device file
+ * @ti: the TID information
+ *
+ * The new implementation as of Oct 2004 is that the driver assigns
+@@ -177,11 +246,11 @@ bail:
+ * virtually contiguous pages, that should change to improve
+ * performance.
+ */
+-static int ipath_tid_update(struct ipath_portdata *pd,
++static int ipath_tid_update(struct ipath_portdata *pd, struct file *fp,
+ const struct ipath_tid_info *ti)
+ {
+ int ret = 0, ntids;
+- u32 tid, porttid, cnt, i, tidcnt;
++ u32 tid, porttid, cnt, i, tidcnt, tidoff;
+ u16 *tidlist;
+ struct ipath_devdata *dd = pd->port_dd;
+ u64 physaddr;
+@@ -189,6 +258,7 @@ static int ipath_tid_update(struct ipath
+ u64 __iomem *tidbase;
+ unsigned long tidmap[8];
+ struct page **pagep = NULL;
++ unsigned subport = subport_fp(fp);
+
+ if (!dd->ipath_pageshadow) {
+ ret = -ENOMEM;
+@@ -205,20 +275,34 @@ static int ipath_tid_update(struct ipath
+ ret = -EFAULT;
+ goto done;
+ }
+- tidcnt = dd->ipath_rcvtidcnt;
+- if (cnt >= tidcnt) {
++ porttid = pd->port_port * dd->ipath_rcvtidcnt;
++ if (!pd->port_subport_cnt) {
++ tidcnt = dd->ipath_rcvtidcnt;
++ tid = pd->port_tidcursor;
++ tidoff = 0;
++ } else if (!subport) {
++ tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
++ (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
++ tidoff = dd->ipath_rcvtidcnt - tidcnt;
++ porttid += tidoff;
++ tid = tidcursor_fp(fp);
++ } else {
++ tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
++ tidoff = tidcnt * (subport - 1);
++ porttid += tidoff;
++ tid = tidcursor_fp(fp);
++ }
++ if (cnt > tidcnt) {
+ /* make sure it all fits in port_tid_pg_list */
+ dev_info(&dd->pcidev->dev, "Process tried to allocate %u "
+ "TIDs, only trying max (%u)\n", cnt, tidcnt);
+ cnt = tidcnt;
+ }
+- pagep = (struct page **)pd->port_tid_pg_list;
+- tidlist = (u16 *) (&pagep[cnt]);
++ pagep = &((struct page **) pd->port_tid_pg_list)[tidoff];
++ tidlist = &((u16 *) &pagep[dd->ipath_rcvtidcnt])[tidoff];
+
+ memset(tidmap, 0, sizeof(tidmap));
+- tid = pd->port_tidcursor;
+ /* before decrement; chip actual # */
+- porttid = pd->port_port * tidcnt;
+ ntids = tidcnt;
+ tidbase = (u64 __iomem *) (((char __iomem *) dd->ipath_kregbase) +
+ dd->ipath_rcvtidbase +
+@@ -275,16 +359,19 @@ static int ipath_tid_update(struct ipath
+ ret = -ENOMEM;
+ break;
+ }
+- tidlist[i] = tid;
++ tidlist[i] = tid + tidoff;
+ ipath_cdbg(VERBOSE, "Updating idx %u to TID %u, "
+- "vaddr %lx\n", i, tid, vaddr);
++ "vaddr %lx\n", i, tid + tidoff, vaddr);
+ /* we "know" system pages and TID pages are same size */
+ dd->ipath_pageshadow[porttid + tid] = pagep[i];
++ dd->ipath_physshadow[porttid + tid] = ipath_map_page(
++ dd->pcidev, pagep[i], 0, PAGE_SIZE,
++ PCI_DMA_FROMDEVICE);
+ /*
+ * don't need atomic or it's overhead
+ */
+ __set_bit(tid, tidmap);
+- physaddr = page_to_phys(pagep[i]);
++ physaddr = dd->ipath_physshadow[porttid + tid];
+ ipath_stats.sps_pagelocks++;
+ ipath_cdbg(VERBOSE,
+ "TID %u, vaddr %lx, physaddr %llx pgp %p\n",
+@@ -318,6 +405,9 @@ static int ipath_tid_update(struct ipath
+ tid);
+ dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
+ dd->ipath_tidinvalid);
++ pci_unmap_page(dd->pcidev,
++ dd->ipath_physshadow[porttid + tid],
++ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ dd->ipath_pageshadow[porttid + tid] = NULL;
+ ipath_stats.sps_pageunlocks++;
+ }
+@@ -342,7 +432,10 @@ static int ipath_tid_update(struct ipath
+ }
+ if (tid == tidcnt)
+ tid = 0;
+- pd->port_tidcursor = tid;
++ if (!pd->port_subport_cnt)
++ pd->port_tidcursor = tid;
++ else
++ tidcursor_fp(fp) = tid;
+ }
+
+ done:
+@@ -355,6 +448,7 @@ done:
+ /**
+ * ipath_tid_free - free a port TID
+ * @pd: the port
++ * @subport: the subport
+ * @ti: the TID info
+ *
+ * right now we are unlocking one page at a time, but since
+@@ -368,7 +462,7 @@ done:
+ * they pass in to us.
+ */
+
+-static int ipath_tid_free(struct ipath_portdata *pd,
++static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
+ const struct ipath_tid_info *ti)
+ {
+ int ret = 0;
+@@ -389,11 +483,20 @@ static int ipath_tid_free(struct ipath_p
+ }
+
+ porttid = pd->port_port * dd->ipath_rcvtidcnt;
++ if (!pd->port_subport_cnt)
++ tidcnt = dd->ipath_rcvtidcnt;
++ else if (!subport) {
++ tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
++ (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
++ porttid += dd->ipath_rcvtidcnt - tidcnt;
++ } else {
++ tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
++ porttid += tidcnt * (subport - 1);
++ }
+ tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
+ dd->ipath_rcvtidbase +
+ porttid * sizeof(*tidbase));
+
+- tidcnt = dd->ipath_rcvtidcnt;
+ limit = sizeof(tidmap) * BITS_PER_BYTE;
+ if (limit > tidcnt)
+ /* just in case size changes in future */
+@@ -418,6 +521,9 @@ static int ipath_tid_free(struct ipath_p
+ pd->port_pid, tid);
+ dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
+ dd->ipath_tidinvalid);
++ pci_unmap_page(dd->pcidev,
++ dd->ipath_physshadow[porttid + tid],
++ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ ipath_release_user_pages(
+ &dd->ipath_pageshadow[porttid + tid], 1);
+ dd->ipath_pageshadow[porttid + tid] = NULL;
+@@ -582,20 +688,24 @@ bail:
+ /**
+ * ipath_manage_rcvq - manage a port's receive queue
+ * @pd: the port
++ * @subport: the subport
+ * @start_stop: action to carry out
+ *
+ * start_stop == 0 disables receive on the port, for use in queue
+ * overflow conditions. start_stop==1 re-enables, to be used to
+ * re-init the software copy of the head register
+ */
+-static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
++static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
++ int start_stop)
+ {
+ struct ipath_devdata *dd = pd->port_dd;
+ u64 tval;
+
+- ipath_cdbg(PROC, "%sabling rcv for unit %u port %u\n",
++ ipath_cdbg(PROC, "%sabling rcv for unit %u port %u:%u\n",
+ start_stop ? "en" : "dis", dd->ipath_unit,
+- pd->port_port);
++ pd->port_port, subport);
++ if (subport)
++ goto bail;
+ /* atomically clear receive enable port. */
+ if (start_stop) {
+ /*
+@@ -610,7 +720,7 @@ static int ipath_manage_rcvq(struct ipat
+ * updated and correct itself, even in the face of software
+ * bugs.
+ */
+- *pd->port_rcvhdrtail_kvaddr = 0;
++ *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
+ set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+ &dd->ipath_rcvctrl);
+ } else
+@@ -631,6 +741,7 @@ static int ipath_manage_rcvq(struct ipat
+ tval = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
+ }
+ /* always; new head should be equal to new tail; see above */
++bail:
+ return 0;
+ }
+
+@@ -688,6 +799,36 @@ static void ipath_clean_part_key(struct
+ }
+ }
+
++/*
++ * Initialize the port data with the receive buffer sizes
++ * so this can be done while the master port is locked.
++ * Otherwise, there is a race with a slave opening the port
++ * and seeing these fields uninitialized.
++ */
++static void init_user_egr_sizes(struct ipath_portdata *pd)
++{
++ struct ipath_devdata *dd = pd->port_dd;
++ unsigned egrperchunk, egrcnt, size;
++
++ /*
++ * to avoid wasting a lot of memory, we allocate 32KB chunks of
++ * physically contiguous memory, advance through it until used up
++ * and then allocate more. Of course, we need memory to store those
++ * extra pointers, now. Started out with 256KB, but under heavy
++ * memory pressure (creating large files and then copying them over
++ * NFS while doing lots of MPI jobs), we hit some allocation
++ * failures, even though we can sleep... (2.6.10) Still get
++ * failures at 64K. 32K is the lowest we can go without wasting
++ * additional memory.
++ */
++ size = 0x8000;
++ egrperchunk = size / dd->ipath_rcvegrbufsize;
++ egrcnt = dd->ipath_rcvegrcnt;
++ pd->port_rcvegrbuf_chunks = (egrcnt + egrperchunk - 1) / egrperchunk;
++ pd->port_rcvegrbufs_perchunk = egrperchunk;
++ pd->port_rcvegrbuf_size = size;
++}
++
+ /**
+ * ipath_create_user_egr - allocate eager TID buffers
+ * @pd: the port to allocate TID buffers for
+@@ -703,7 +844,7 @@ static void ipath_clean_part_key(struct
+ static int ipath_create_user_egr(struct ipath_portdata *pd)
+ {
+ struct ipath_devdata *dd = pd->port_dd;
+- unsigned e, egrcnt, alloced, egrperchunk, chunk, egrsize, egroff;
++ unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
+ size_t size;
+ int ret;
+ gfp_t gfp_flags;
+@@ -723,31 +864,18 @@ static int ipath_create_user_egr(struct
+ ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
+ "offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
+
+- /*
+- * to avoid wasting a lot of memory, we allocate 32KB chunks of
+- * physically contiguous memory, advance through it until used up
+- * and then allocate more. Of course, we need memory to store those
+- * extra pointers, now. Started out with 256KB, but under heavy
+- * memory pressure (creating large files and then copying them over
+- * NFS while doing lots of MPI jobs), we hit some allocation
+- * failures, even though we can sleep... (2.6.10) Still get
+- * failures at 64K. 32K is the lowest we can go without wasting
+- * additional memory.
+- */
+- size = 0x8000;
+- alloced = ALIGN(egrsize * egrcnt, size);
+- egrperchunk = size / egrsize;
+- chunk = (egrcnt + egrperchunk - 1) / egrperchunk;
+- pd->port_rcvegrbuf_chunks = chunk;
+- pd->port_rcvegrbufs_perchunk = egrperchunk;
+- pd->port_rcvegrbuf_size = size;
+- pd->port_rcvegrbuf = vmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]));
++ chunk = pd->port_rcvegrbuf_chunks;
++ egrperchunk = pd->port_rcvegrbufs_perchunk;
++ size = pd->port_rcvegrbuf_size;
++ pd->port_rcvegrbuf = kmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]),
++ GFP_KERNEL);
+ if (!pd->port_rcvegrbuf) {
+ ret = -ENOMEM;
+ goto bail;
+ }
+ pd->port_rcvegrbuf_phys =
+- vmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]));
++ kmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]),
++ GFP_KERNEL);
+ if (!pd->port_rcvegrbuf_phys) {
+ ret = -ENOMEM;
+ goto bail_rcvegrbuf;
+@@ -792,105 +920,23 @@ bail_rcvegrbuf_phys:
+ pd->port_rcvegrbuf_phys[e]);
+
+ }
+- vfree(pd->port_rcvegrbuf_phys);
++ kfree(pd->port_rcvegrbuf_phys);
+ pd->port_rcvegrbuf_phys = NULL;
+ bail_rcvegrbuf:
+- vfree(pd->port_rcvegrbuf);
++ kfree(pd->port_rcvegrbuf);
+ pd->port_rcvegrbuf = NULL;
+ bail:
+ return ret;
+ }
+
+-static int ipath_do_user_init(struct ipath_portdata *pd,
+- const struct ipath_user_info *uinfo)
+-{
+- int ret = 0;
+- struct ipath_devdata *dd = pd->port_dd;
+- u32 head32;
+-
+- /* for now, if major version is different, bail */
+- if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
+- dev_info(&dd->pcidev->dev,
+- "User major version %d not same as driver "
+- "major %d\n", uinfo->spu_userversion >> 16,
+- IPATH_USER_SWMAJOR);
+- ret = -ENODEV;
+- goto done;
+- }
+-
+- if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR)
+- ipath_dbg("User minor version %d not same as driver "
+- "minor %d\n", uinfo->spu_userversion & 0xffff,
+- IPATH_USER_SWMINOR);
+-
+- if (uinfo->spu_rcvhdrsize) {
+- ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
+- if (ret)
+- goto done;
+- }
+-
+- /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
+-
+- /* for right now, kernel piobufs are at end, so port 1 is at 0 */
+- pd->port_piobufs = dd->ipath_piobufbase +
+- dd->ipath_pbufsport * (pd->port_port -
+- 1) * dd->ipath_palign;
+- ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
+- pd->port_port, pd->port_piobufs);
+-
+- /*
+- * Now allocate the rcvhdr Q and eager TIDs; skip the TID
+- * array for time being. If pd->port_port > chip-supported,
+- * we need to do extra stuff here to handle by handling overflow
+- * through port 0, someday
+- */
+- ret = ipath_create_rcvhdrq(dd, pd);
+- if (!ret)
+- ret = ipath_create_user_egr(pd);
+- if (ret)
+- goto done;
+-
+- /*
+- * set the eager head register for this port to the current values
+- * of the tail pointers, since we don't know if they were
+- * updated on last use of the port.
+- */
+- head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
+- ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
+- dd->ipath_lastegrheads[pd->port_port] = -1;
+- dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
+- ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
+- pd->port_port, head32);
+- pd->port_tidcursor = 0; /* start at beginning after open */
+- /*
+- * now enable the port; the tail registers will be written to memory
+- * by the chip as soon as it sees the write to
+- * dd->ipath_kregs->kr_rcvctrl. The update only happens on
+- * transition from 0 to 1, so clear it first, then set it as part of
+- * enabling the port. This will (very briefly) affect any other
+- * open ports, but it shouldn't be long enough to be an issue.
+- * We explictly set the in-memory copy to 0 beforehand, so we don't
+- * have to wait to be sure the DMA update has happened.
+- */
+- *pd->port_rcvhdrtail_kvaddr = 0ULL;
+- set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+- &dd->ipath_rcvctrl);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+- dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+- dd->ipath_rcvctrl);
+-done:
+- return ret;
+-}
+-
+
+ /* common code for the mappings on dma_alloc_coherent mem */
+ static int ipath_mmap_mem(struct vm_area_struct *vma,
+- struct ipath_portdata *pd, unsigned len,
+- int write_ok, dma_addr_t addr, char *what)
++ struct ipath_portdata *pd, unsigned len, int write_ok,
++ void *kvaddr, char *what)
+ {
+ struct ipath_devdata *dd = pd->port_dd;
+- unsigned pfn = (unsigned long)addr >> PAGE_SHIFT;
++ unsigned long pfn;
+ int ret;
+
+ if ((vma->vm_end - vma->vm_start) > len) {
+@@ -913,17 +959,17 @@ static int ipath_mmap_mem(struct vm_area
+ vma->vm_flags &= ~VM_MAYWRITE;
+ }
+
++ pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
+ ret = remap_pfn_range(vma, vma->vm_start, pfn,
+ len, vma->vm_page_prot);
+ if (ret)
+- dev_info(&dd->pcidev->dev,
+- "%s port%u mmap of %lx, %x bytes r%c failed: %d\n",
+- what, pd->port_port, (unsigned long)addr, len,
+- write_ok?'w':'o', ret);
++ dev_info(&dd->pcidev->dev, "%s port%u mmap of %lx, %x "
++ "bytes r%c failed: %d\n", what, pd->port_port,
++ pfn, len, write_ok?'w':'o', ret);
+ else
+- ipath_cdbg(VERBOSE, "%s port%u mmaped %lx, %x bytes r%c\n",
+- what, pd->port_port, (unsigned long)addr, len,
+- write_ok?'w':'o');
++ ipath_cdbg(VERBOSE, "%s port%u mmaped %lx, %x bytes "
++ "r%c\n", what, pd->port_port, pfn, len,
++ write_ok?'w':'o');
+ bail:
+ return ret;
+ }
+@@ -958,7 +1004,8 @@ static int mmap_ureg(struct vm_area_stru
+
+ static int mmap_piobufs(struct vm_area_struct *vma,
+ struct ipath_devdata *dd,
+- struct ipath_portdata *pd)
++ struct ipath_portdata *pd,
++ unsigned piobufs, unsigned piocnt)
+ {
+ unsigned long phys;
+ int ret;
+@@ -969,31 +1016,32 @@ static int mmap_piobufs(struct vm_area_s
+ * process data, and catches users who might try to read the i/o
+ * space due to a bug.
+ */
+- if ((vma->vm_end - vma->vm_start) >
+- (dd->ipath_pbufsport * dd->ipath_palign)) {
++ if ((vma->vm_end - vma->vm_start) > (piocnt * dd->ipath_palign)) {
+ dev_info(&dd->pcidev->dev, "FAIL mmap piobufs: "
+ "reqlen %lx > PAGE\n",
+ vma->vm_end - vma->vm_start);
+- ret = -EFAULT;
++ ret = -EINVAL;
+ goto bail;
+ }
+
+- phys = dd->ipath_physaddr + pd->port_piobufs;
++ phys = dd->ipath_physaddr + piobufs;
+
+ /*
+ * Don't mark this as non-cached, or we don't get the
+ * write combining behavior we want on the PIO buffers!
+ */
+
+- if (vma->vm_flags & VM_READ) {
+- dev_info(&dd->pcidev->dev,
+- "Can't map piobufs as readable (flags=%lx)\n",
+- vma->vm_flags);
+- ret = -EPERM;
+- goto bail;
+- }
++#if defined(__powerpc__)
++ /* There isn't a generic way to specify writethrough mappings */
++ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
++ pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
++ pgprot_val(vma->vm_page_prot) &= ~_PAGE_GUARDED;
++#endif
+
+- /* don't allow them to later change to readable with mprotect */
++ /*
++ * don't allow them to later change to readable with mprotect (for when
++ * not initially mapped readable, as is normally the case)
++ */
+ vma->vm_flags &= ~VM_MAYREAD;
+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+
+@@ -1010,7 +1058,7 @@ static int mmap_rcvegrbufs(struct vm_are
+ struct ipath_devdata *dd = pd->port_dd;
+ unsigned long start, size;
+ size_t total_size, i;
+- dma_addr_t *phys;
++ unsigned long pfn;
+ int ret;
+
+ size = pd->port_rcvegrbuf_size;
+@@ -1020,7 +1068,7 @@ static int mmap_rcvegrbufs(struct vm_are
+ "reqlen %lx > actual %lx\n",
+ vma->vm_end - vma->vm_start,
+ (unsigned long) total_size);
+- ret = -EFAULT;
++ ret = -EINVAL;
+ goto bail;
+ }
+
+@@ -1034,11 +1082,11 @@ static int mmap_rcvegrbufs(struct vm_are
+ vma->vm_flags &= ~VM_MAYWRITE;
+
+ start = vma->vm_start;
+- phys = pd->port_rcvegrbuf_phys;
+
+ for (i = 0; i < pd->port_rcvegrbuf_chunks; i++, start += size) {
+- ret = remap_pfn_range(vma, start, phys[i] >> PAGE_SHIFT,
+- size, vma->vm_page_prot);
++ pfn = virt_to_phys(pd->port_rcvegrbuf[i]) >> PAGE_SHIFT;
++ ret = remap_pfn_range(vma, start, pfn, size,
++ vma->vm_page_prot);
+ if (ret < 0)
+ goto bail;
+ }
+@@ -1048,6 +1096,122 @@ bail:
+ return ret;
+ }
+
++/*
++ * ipath_file_vma_nopage - handle a VMA page fault.
++ */
++static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
++ unsigned long address, int *type)
++{
++ unsigned long offset = address - vma->vm_start;
++ struct page *page = NOPAGE_SIGBUS;
++ void *pageptr;
++
++ /*
++ * Convert the vmalloc address into a struct page.
++ */
++ pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
++ page = vmalloc_to_page(pageptr);
++ if (!page)
++ goto out;
++
++ /* Increment the reference count. */
++ get_page(page);
++ if (type)
++ *type = VM_FAULT_MINOR;
++out:
++ return page;
++}
++
++static struct vm_operations_struct ipath_file_vm_ops = {
++ .nopage = ipath_file_vma_nopage,
++};
++
++static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
++ struct ipath_portdata *pd, unsigned subport)
++{
++ unsigned long len;
++ struct ipath_devdata *dd;
++ void *addr;
++ size_t size;
++ int ret;
++
++ /* If the port is not shared, all addresses should be physical */
++ if (!pd->port_subport_cnt) {
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ dd = pd->port_dd;
++ size = pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size;
++
++ /*
++ * Master has all the slave uregbase, rcvhdrq, and
++ * rcvegrbufs mmapped.
++ */
++ if (subport == 0) {
++ unsigned num_slaves = pd->port_subport_cnt - 1;
++
++ if (pgaddr == ((u64) pd->subport_uregbase & MMAP64_MASK)) {
++ addr = pd->subport_uregbase;
++ size = PAGE_SIZE * num_slaves;
++ } else if (pgaddr == ((u64) pd->subport_rcvhdr_base &
++ MMAP64_MASK)) {
++ addr = pd->subport_rcvhdr_base;
++ size = pd->port_rcvhdrq_size * num_slaves;
++ } else if (pgaddr == ((u64) pd->subport_rcvegrbuf &
++ MMAP64_MASK)) {
++ addr = pd->subport_rcvegrbuf;
++ size *= num_slaves;
++ } else {
++ ret = -EINVAL;
++ goto bail;
++ }
++ } else if (pgaddr == (((u64) pd->subport_uregbase +
++ PAGE_SIZE * (subport - 1)) & MMAP64_MASK)) {
++ addr = pd->subport_uregbase + PAGE_SIZE * (subport - 1);
++ size = PAGE_SIZE;
++ } else if (pgaddr == (((u64) pd->subport_rcvhdr_base +
++ pd->port_rcvhdrq_size * (subport - 1)) &
++ MMAP64_MASK)) {
++ addr = pd->subport_rcvhdr_base +
++ pd->port_rcvhdrq_size * (subport - 1);
++ size = pd->port_rcvhdrq_size;
++ } else if (pgaddr == (((u64) pd->subport_rcvegrbuf +
++ size * (subport - 1)) & MMAP64_MASK)) {
++ addr = pd->subport_rcvegrbuf + size * (subport - 1);
++ /* rcvegrbufs are read-only on the slave */
++ if (vma->vm_flags & VM_WRITE) {
++ dev_info(&dd->pcidev->dev,
++ "Can't map eager buffers as "
++ "writable (flags=%lx)\n", vma->vm_flags);
++ ret = -EPERM;
++ goto bail;
++ }
++ /*
++ * Don't allow permission to later change to writeable
++ * with mprotect.
++ */
++ vma->vm_flags &= ~VM_MAYWRITE;
++ } else {
++ ret = -EINVAL;
++ goto bail;
++ }
++ len = vma->vm_end - vma->vm_start;
++ if (len > size) {
++ ipath_cdbg(MM, "FAIL: reqlen %lx > %zx\n", len, size);
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
++ vma->vm_ops = &ipath_file_vm_ops;
++ vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
++ ret = 0;
++
++bail:
++ return ret;
++}
++
+ /**
+ * ipath_mmap - mmap various structures into user space
+ * @fp: the file pointer
+@@ -1063,73 +1227,99 @@ static int ipath_mmap(struct file *fp, s
+ struct ipath_portdata *pd;
+ struct ipath_devdata *dd;
+ u64 pgaddr, ureg;
++ unsigned piobufs, piocnt;
+ int ret;
+
+ pd = port_fp(fp);
++ if (!pd) {
++ ret = -EINVAL;
++ goto bail;
++ }
+ dd = pd->port_dd;
+
+ /*
+ * This is the ipath_do_user_init() code, mapping the shared buffers
+ * into the user process. The address referred to by vm_pgoff is the
+- * virtual, not physical, address; we only do one mmap for each
+- * space mapped.
++ * file offset passed via mmap(). For shared ports, this is the
++ * kernel vmalloc() address of the pages to share with the master.
++ * For non-shared or master ports, this is a physical address.
++ * We only do one mmap for each space mapped.
+ */
+ pgaddr = vma->vm_pgoff << PAGE_SHIFT;
+
+ /*
+- * Must fit in 40 bits for our hardware; some checked elsewhere,
+- * but we'll be paranoid. Check for 0 is mostly in case one of the
+- * allocations failed, but user called mmap anyway. We want to catch
+- * that before it can match.
++ * Check for 0 in case one of the allocations failed, but user
++ * called mmap anyway.
+ */
+- if (!pgaddr || pgaddr >= (1ULL<<40)) {
+- ipath_dev_err(dd, "Bad phys addr %llx, start %lx, end %lx\n",
+- (unsigned long long)pgaddr, vma->vm_start, vma->vm_end);
+- return -EINVAL;
++ if (!pgaddr) {
++ ret = -EINVAL;
++ goto bail;
+ }
+
+- /* just the offset of the port user registers, not physical addr */
+- ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+-
+- ipath_cdbg(MM, "ushare: pgaddr %llx vm_start=%lx, vmlen %lx\n",
++ ipath_cdbg(MM, "pgaddr %llx vm_start=%lx len %lx port %u:%u:%u\n",
+ (unsigned long long) pgaddr, vma->vm_start,
+- vma->vm_end - vma->vm_start);
++ vma->vm_end - vma->vm_start, dd->ipath_unit,
++ pd->port_port, subport_fp(fp));
+
+- if (vma->vm_start & (PAGE_SIZE-1)) {
+- ipath_dev_err(dd,
+- "vm_start not aligned: %lx, end=%lx phys %lx\n",
+- vma->vm_start, vma->vm_end, (unsigned long)pgaddr);
+- ret = -EINVAL;
++ /*
++ * Physical addresses must fit in 40 bits for our hardware.
++ * Check for kernel virtual addresses first, anything else must
++ * match a HW or memory address.
++ */
++ if (pgaddr >= (1ULL<<40)) {
++ ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
++ goto bail;
++ }
++
++ if (!pd->port_subport_cnt) {
++ /* port is not shared */
++ ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
++ piocnt = dd->ipath_pbufsport;
++ piobufs = pd->port_piobufs;
++ } else if (!subport_fp(fp)) {
++ /* caller is the master */
++ ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
++ piocnt = (dd->ipath_pbufsport / pd->port_subport_cnt) +
++ (dd->ipath_pbufsport % pd->port_subport_cnt);
++ piobufs = pd->port_piobufs +
++ dd->ipath_palign * (dd->ipath_pbufsport - piocnt);
++ } else {
++ unsigned slave = subport_fp(fp) - 1;
++
++ /* caller is a slave */
++ ureg = 0;
++ piocnt = dd->ipath_pbufsport / pd->port_subport_cnt;
++ piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave;
+ }
+- else if (pgaddr == ureg)
++
++ if (pgaddr == ureg)
+ ret = mmap_ureg(vma, dd, ureg);
+- else if (pgaddr == pd->port_piobufs)
+- ret = mmap_piobufs(vma, dd, pd);
+- else if (pgaddr == (u64) pd->port_rcvegr_phys)
++ else if (pgaddr == piobufs)
++ ret = mmap_piobufs(vma, dd, pd, piobufs, piocnt);
++ else if (pgaddr == dd->ipath_pioavailregs_phys)
++ /* in-memory copy of pioavail registers */
++ ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
++ (void *) dd->ipath_pioavailregs_dma,
++ "pioavail registers");
++ else if (subport_fp(fp))
++ /* Subports don't mmap the physical receive buffers */
++ ret = -EINVAL;
++ else if (pgaddr == pd->port_rcvegr_phys)
+ ret = mmap_rcvegrbufs(vma, pd);
+- else if (pgaddr == (u64) pd->port_rcvhdrq_phys) {
++ else if (pgaddr == (u64) pd->port_rcvhdrq_phys)
+ /*
+- * The rcvhdrq itself; readonly except on HT-400 (so have
++ * The rcvhdrq itself; readonly except on HT (so have
+ * to allow writable mapping), multiple pages, contiguous
+ * from an i/o perspective.
+ */
+- unsigned total_size =
+- ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize
+- * sizeof(u32), PAGE_SIZE);
+- ret = ipath_mmap_mem(vma, pd, total_size, 1,
+- pd->port_rcvhdrq_phys,
++ ret = ipath_mmap_mem(vma, pd, pd->port_rcvhdrq_size, 1,
++ pd->port_rcvhdrq,
+ "rcvhdrq");
+- }
+- else if (pgaddr == (u64)pd->port_rcvhdrqtailaddr_phys)
++ else if (pgaddr == (u64) pd->port_rcvhdrqtailaddr_phys)
+ /* in-memory copy of rcvhdrq tail register */
+ ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
+- pd->port_rcvhdrqtailaddr_phys,
++ pd->port_rcvhdrtail_kvaddr,
+ "rcvhdrq tail");
+- else if (pgaddr == dd->ipath_pioavailregs_phys)
+- /* in-memory copy of pioavail registers */
+- ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
+- dd->ipath_pioavailregs_phys,
+- "pioavail registers");
+ else
+ ret = -EINVAL;
+
+@@ -1137,9 +1327,10 @@ static int ipath_mmap(struct file *fp, s
+
+ if (ret < 0)
+ dev_info(&dd->pcidev->dev,
+- "Failure %d on addr %lx, off %lx\n",
+- -ret, vma->vm_start, vma->vm_pgoff);
+-
++ "Failure %d on off %llx len %lx\n",
++ -ret, (unsigned long long)pgaddr,
++ vma->vm_end - vma->vm_start);
++bail:
+ return ret;
+ }
+
+@@ -1149,9 +1340,12 @@ static unsigned int ipath_poll(struct fi
+ struct ipath_portdata *pd;
+ u32 head, tail;
+ int bit;
++ unsigned pollflag = 0;
+ struct ipath_devdata *dd;
+
+ pd = port_fp(fp);
++ if (!pd)
++ goto bail;
+ dd = pd->port_dd;
+
+ bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT;
+@@ -1174,7 +1368,7 @@ static unsigned int ipath_poll(struct fi
+
+ if (tail == head) {
+ set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
+- if(dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
++ if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
+ (void)ipath_write_ureg(dd, ur_rcvhdrhead,
+ dd->ipath_rhdrhead_intr_off
+ | head, pd->port_port);
+@@ -1185,9 +1379,12 @@ static unsigned int ipath_poll(struct fi
+ clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
+ pd->port_rcvwait_to++;
+ }
++ else
++ pollflag = POLLIN | POLLRDNORM;
+ }
+ else {
+ /* it's already happened; don't do wait_event overhead */
++ pollflag = POLLIN | POLLRDNORM;
+ pd->port_rcvnowait++;
+ }
+
+@@ -1195,18 +1392,80 @@ static unsigned int ipath_poll(struct fi
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl);
+
+- return 0;
++bail:
++ return pollflag;
++}
++
++static int init_subports(struct ipath_devdata *dd,
++ struct ipath_portdata *pd,
++ const struct ipath_user_info *uinfo)
++{
++ int ret = 0;
++ unsigned num_slaves;
++ size_t size;
++
++ /* Old user binaries don't know about subports */
++ if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR)
++ goto bail;
++ /*
++ * If the user is requesting zero or one port,
++ * skip the subport allocation.
++ */
++ if (uinfo->spu_subport_cnt <= 1)
++ goto bail;
++ if (uinfo->spu_subport_cnt > 4) {
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ num_slaves = uinfo->spu_subport_cnt - 1;
++ pd->subport_uregbase = vmalloc(PAGE_SIZE * num_slaves);
++ if (!pd->subport_uregbase) {
++ ret = -ENOMEM;
++ goto bail;
++ }
++ /* Note: pd->port_rcvhdrq_size isn't initialized yet. */
++ size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
++ sizeof(u32), PAGE_SIZE) * num_slaves;
++ pd->subport_rcvhdr_base = vmalloc(size);
++ if (!pd->subport_rcvhdr_base) {
++ ret = -ENOMEM;
++ goto bail_ureg;
++ }
++
++ pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks *
++ pd->port_rcvegrbuf_size *
++ num_slaves);
++ if (!pd->subport_rcvegrbuf) {
++ ret = -ENOMEM;
++ goto bail_rhdr;
++ }
++
++ pd->port_subport_cnt = uinfo->spu_subport_cnt;
++ pd->port_subport_id = uinfo->spu_subport_id;
++ pd->active_slaves = 1;
++ goto bail;
++
++bail_rhdr:
++ vfree(pd->subport_rcvhdr_base);
++bail_ureg:
++ vfree(pd->subport_uregbase);
++ pd->subport_uregbase = NULL;
++bail:
++ return ret;
+ }
+
+ static int try_alloc_port(struct ipath_devdata *dd, int port,
+- struct file *fp)
++ struct file *fp,
++ const struct ipath_user_info *uinfo)
+ {
++ struct ipath_portdata *pd;
+ int ret;
+
+- if (!dd->ipath_pd[port]) {
+- void *p, *ptmp;
++ if (!(pd = dd->ipath_pd[port])) {
++ void *ptmp;
+
+- p = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
++ pd = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
+
+ /*
+ * Allocate memory for use in ipath_tid_update() just once
+@@ -1216,34 +1475,36 @@ static int try_alloc_port(struct ipath_d
+ ptmp = kmalloc(dd->ipath_rcvtidcnt * sizeof(u16) +
+ dd->ipath_rcvtidcnt * sizeof(struct page **),
+ GFP_KERNEL);
+- if (!p || !ptmp) {
++ if (!pd || !ptmp) {
+ ipath_dev_err(dd, "Unable to allocate portdata "
+ "memory, failing open\n");
+ ret = -ENOMEM;
+- kfree(p);
++ kfree(pd);
+ kfree(ptmp);
+ goto bail;
+ }
+- dd->ipath_pd[port] = p;
++ dd->ipath_pd[port] = pd;
+ dd->ipath_pd[port]->port_port = port;
+ dd->ipath_pd[port]->port_dd = dd;
+ dd->ipath_pd[port]->port_tid_pg_list = ptmp;
+ init_waitqueue_head(&dd->ipath_pd[port]->port_wait);
+ }
+- if (!dd->ipath_pd[port]->port_cnt) {
+- dd->ipath_pd[port]->port_cnt = 1;
+- fp->private_data = (void *) dd->ipath_pd[port];
++ if (!pd->port_cnt) {
++ pd->userversion = uinfo->spu_userversion;
++ init_user_egr_sizes(pd);
++ if ((ret = init_subports(dd, pd, uinfo)) != 0)
++ goto bail;
+ ipath_cdbg(PROC, "%s[%u] opened unit:port %u:%u\n",
+ current->comm, current->pid, dd->ipath_unit,
+ port);
+- dd->ipath_pd[port]->port_pid = current->pid;
+- strncpy(dd->ipath_pd[port]->port_comm, current->comm,
+- sizeof(dd->ipath_pd[port]->port_comm));
++ pd->port_cnt = 1;
++ port_fp(fp) = pd;
++ pd->port_pid = current->pid;
++ strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm));
+ ipath_stats.sps_ports++;
+ ret = 0;
+- goto bail;
+- }
+- ret = -EBUSY;
++ } else
++ ret = -EBUSY;
+
+ bail:
+ return ret;
+@@ -1259,7 +1520,8 @@ static inline int usable(struct ipath_de
+ | IPATH_LINKUNK));
+ }
+
+-static int find_free_port(int unit, struct file *fp)
++static int find_free_port(int unit, struct file *fp,
++ const struct ipath_user_info *uinfo)
+ {
+ struct ipath_devdata *dd = ipath_lookup(unit);
+ int ret, i;
+@@ -1274,8 +1536,8 @@ static int find_free_port(int unit, stru
+ goto bail;
+ }
+
+- for (i = 0; i < dd->ipath_cfgports; i++) {
+- ret = try_alloc_port(dd, i, fp);
++ for (i = 1; i < dd->ipath_cfgports; i++) {
++ ret = try_alloc_port(dd, i, fp, uinfo);
+ if (ret != -EBUSY)
+ goto bail;
+ }
+@@ -1285,26 +1547,27 @@ bail:
+ return ret;
+ }
+
+-static int find_best_unit(struct file *fp)
++static int find_best_unit(struct file *fp,
++ const struct ipath_user_info *uinfo)
+ {
+ int ret = 0, i, prefunit = -1, devmax;
+ int maxofallports, npresent, nup;
+ int ndev;
+
+- (void) ipath_count_units(&npresent, &nup, &maxofallports);
++ devmax = ipath_count_units(&npresent, &nup, &maxofallports);
+
+ /*
+ * This code is present to allow a knowledgeable person to
+ * specify the layout of processes to processors before opening
+ * this driver, and then we'll assign the process to the "closest"
+- * HT-400 to that processor (we assume reasonable connectivity,
++ * InfiniPath chip to that processor (we assume reasonable connectivity,
+ * for now). This code assumes that if affinity has been set
+ * before this point, that at most one cpu is set; for now this
+ * is reasonable. I check for both cpus_empty() and cpus_full(),
+ * in case some kernel variant sets none of the bits when no
+ * affinity is set. 2.6.11 and 12 kernels have all present
+ * cpus set. Some day we'll have to fix it up further to handle
+- * a cpu subset. This algorithm fails for two HT-400's connected
++ * a cpu subset. This algorithm fails for two HT chips connected
+ * in tunnel fashion. Eventually this needs real topology
+ * information. There may be some issues with dual core numbering
+ * as well. This needs more work prior to release.
+@@ -1338,8 +1601,6 @@ static int find_best_unit(struct file *f
+
+ if (prefunit != -1)
+ devmax = prefunit + 1;
+- else
+- devmax = ipath_count_units(NULL, NULL, NULL);
+ recheck:
+ for (i = 1; i < maxofallports; i++) {
+ for (ndev = prefunit != -1 ? prefunit : 0; ndev < devmax;
+@@ -1354,7 +1615,7 @@ recheck:
+ * next.
+ */
+ continue;
+- ret = try_alloc_port(dd, i, fp);
++ ret = try_alloc_port(dd, i, fp, uinfo);
+ if (!ret)
+ goto done;
+ }
+@@ -1390,22 +1651,183 @@ done:
+ return ret;
+ }
+
++static int find_shared_port(struct file *fp,
++ const struct ipath_user_info *uinfo)
++{
++ int devmax, ndev, i;
++ int ret = 0;
++
++ devmax = ipath_count_units(NULL, NULL, NULL);
++
++ for (ndev = 0; ndev < devmax; ndev++) {
++ struct ipath_devdata *dd = ipath_lookup(ndev);
++
++ if (!dd)
++ continue;
++ for (i = 1; i < dd->ipath_cfgports; i++) {
++ struct ipath_portdata *pd = dd->ipath_pd[i];
++
++ /* Skip ports which are not yet open */
++ if (!pd || !pd->port_cnt)
++ continue;
++ /* Skip port if it doesn't match the requested one */
++ if (pd->port_subport_id != uinfo->spu_subport_id)
++ continue;
++ /* Verify the sharing process matches the master */
++ if (pd->port_subport_cnt != uinfo->spu_subport_cnt ||
++ pd->userversion != uinfo->spu_userversion ||
++ pd->port_cnt >= pd->port_subport_cnt) {
++ ret = -EINVAL;
++ goto done;
++ }
++ port_fp(fp) = pd;
++ subport_fp(fp) = pd->port_cnt++;
++ tidcursor_fp(fp) = 0;
++ pd->active_slaves |= 1 << subport_fp(fp);
++ ipath_cdbg(PROC,
++ "%s[%u] %u sharing %s[%u] unit:port %u:%u\n",
++ current->comm, current->pid,
++ subport_fp(fp),
++ pd->port_comm, pd->port_pid,
++ dd->ipath_unit, pd->port_port);
++ ret = 1;
++ goto done;
++ }
++ }
++
++done:
++ return ret;
++}
++
+ static int ipath_open(struct inode *in, struct file *fp)
+ {
+- int ret, user_minor;
++ /* The real work is performed later in ipath_assign_port() */
++ fp->private_data = kzalloc(sizeof(struct ipath_filedata), GFP_KERNEL);
++ return fp->private_data ? 0 : -ENOMEM;
++}
++
++
++/* Get port early, so can set affinity prior to memory allocation */
++static int ipath_assign_port(struct file *fp,
++ const struct ipath_user_info *uinfo)
++{
++ int ret;
++ int i_minor;
++ unsigned swminor;
++
++ /* Check to be sure we haven't already initialized this file */
++ if (port_fp(fp)) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ /* for now, if major version is different, bail */
++ if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
++ ipath_dbg("User major version %d not same as driver "
++ "major %d\n", uinfo->spu_userversion >> 16,
++ IPATH_USER_SWMAJOR);
++ ret = -ENODEV;
++ goto done;
++ }
++
++ swminor = uinfo->spu_userversion & 0xffff;
++ if (swminor != IPATH_USER_SWMINOR)
++ ipath_dbg("User minor version %d not same as driver "
++ "minor %d\n", swminor, IPATH_USER_SWMINOR);
+
+ mutex_lock(&ipath_mutex);
+
+- user_minor = iminor(in) - IPATH_USER_MINOR_BASE;
++ if (swminor == IPATH_USER_SWMINOR && uinfo->spu_subport_cnt &&
++ (ret = find_shared_port(fp, uinfo))) {
++ mutex_unlock(&ipath_mutex);
++ if (ret > 0)
++ ret = 0;
++ goto done;
++ }
++
++ i_minor = iminor(fp->f_dentry->d_inode) - IPATH_USER_MINOR_BASE;
+ ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n",
+- (long)in->i_rdev, user_minor);
++ (long)fp->f_dentry->d_inode->i_rdev, i_minor);
+
+- if (user_minor)
+- ret = find_free_port(user_minor - 1, fp);
++ if (i_minor)
++ ret = find_free_port(i_minor - 1, fp, uinfo);
+ else
+- ret = find_best_unit(fp);
++ ret = find_best_unit(fp, uinfo);
+
+ mutex_unlock(&ipath_mutex);
++
++done:
++ return ret;
++}
++
++
++static int ipath_do_user_init(struct file *fp,
++ const struct ipath_user_info *uinfo)
++{
++ int ret;
++ struct ipath_portdata *pd;
++ struct ipath_devdata *dd;
++ u32 head32;
++
++ pd = port_fp(fp);
++ dd = pd->port_dd;
++
++ if (uinfo->spu_rcvhdrsize) {
++ ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
++ if (ret)
++ goto done;
++ }
++
++ /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
++
++ /* for right now, kernel piobufs are at end, so port 1 is at 0 */
++ pd->port_piobufs = dd->ipath_piobufbase +
++ dd->ipath_pbufsport * (pd->port_port - 1) * dd->ipath_palign;
++ ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
++ pd->port_port, pd->port_piobufs);
++
++ /*
++ * Now allocate the rcvhdr Q and eager TIDs; skip the TID
++ * array for time being. If pd->port_port > chip-supported,
++ * we need to do extra stuff here to handle by handling overflow
++ * through port 0, someday
++ */
++ ret = ipath_create_rcvhdrq(dd, pd);
++ if (!ret)
++ ret = ipath_create_user_egr(pd);
++ if (ret)
++ goto done;
++
++ /*
++ * set the eager head register for this port to the current values
++ * of the tail pointers, since we don't know if they were
++ * updated on last use of the port.
++ */
++ head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
++ ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
++ dd->ipath_lastegrheads[pd->port_port] = -1;
++ dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
++ ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
++ pd->port_port, head32);
++ pd->port_tidcursor = 0; /* start at beginning after open */
++ /*
++ * now enable the port; the tail registers will be written to memory
++ * by the chip as soon as it sees the write to
++ * dd->ipath_kregs->kr_rcvctrl. The update only happens on
++ * transition from 0 to 1, so clear it first, then set it as part of
++ * enabling the port. This will (very briefly) affect any other
++ * open ports, but it shouldn't be long enough to be an issue.
++ * We explictly set the in-memory copy to 0 beforehand, so we don't
++ * have to wait to be sure the DMA update has happened.
++ */
++ *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
++ set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
++ &dd->ipath_rcvctrl);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
++ dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
++ dd->ipath_rcvctrl);
++done:
+ return ret;
+ }
+
+@@ -1428,6 +1850,8 @@ static void unlock_expected_tids(struct
+ if (!dd->ipath_pageshadow[i])
+ continue;
+
++ pci_unmap_page(dd->pcidev, dd->ipath_physshadow[i],
++ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ ipath_release_user_pages_on_close(&dd->ipath_pageshadow[i],
+ 1);
+ dd->ipath_pageshadow[i] = NULL;
+@@ -1448,6 +1872,7 @@ static void unlock_expected_tids(struct
+ static int ipath_close(struct inode *in, struct file *fp)
+ {
+ int ret = 0;
++ struct ipath_filedata *fd;
+ struct ipath_portdata *pd;
+ struct ipath_devdata *dd;
+ unsigned port;
+@@ -1457,9 +1882,24 @@ static int ipath_close(struct inode *in,
+
+ mutex_lock(&ipath_mutex);
+
+- pd = port_fp(fp);
+- port = pd->port_port;
++ fd = (struct ipath_filedata *) fp->private_data;
+ fp->private_data = NULL;
++ pd = fd->pd;
++ if (!pd) {
++ mutex_unlock(&ipath_mutex);
++ goto bail;
++ }
++ if (--pd->port_cnt) {
++ /*
++ * XXX If the master closes the port before the slave(s),
++ * revoke the mmap for the eager receive queue so
++ * the slave(s) don't wait for receive data forever.
++ */
++ pd->active_slaves &= ~(1 << fd->subport);
++ mutex_unlock(&ipath_mutex);
++ goto bail;
++ }
++ port = pd->port_port;
+ dd = pd->port_dd;
+
+ if (pd->port_hdrqfull) {
+@@ -1498,8 +1938,6 @@ static int ipath_close(struct inode *in,
+
+ /* clean up the pkeys for this port user */
+ ipath_clean_part_key(pd, dd);
+-
+-
+ /*
+ * be paranoid, and never write 0's to these, just use an
+ * unused part of the port 0 tail page. Of course,
+@@ -1518,39 +1956,49 @@ static int ipath_close(struct inode *in,
+ i = dd->ipath_pbufsport * (port - 1);
+ ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
+
++ dd->ipath_f_clear_tids(dd, pd->port_port);
++
+ if (dd->ipath_pageshadow)
+ unlock_expected_tids(pd);
+ ipath_stats.sps_ports--;
+ ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
+ pd->port_comm, pd->port_pid,
+ dd->ipath_unit, port);
+-
+- dd->ipath_f_clear_tids(dd, pd->port_port);
+ }
+
+- pd->port_cnt = 0;
+ pd->port_pid = 0;
+-
+ dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
+ mutex_unlock(&ipath_mutex);
+ ipath_free_pddata(dd, pd); /* after releasing the mutex */
+
++bail:
++ kfree(fd);
+ return ret;
+ }
+
+-static int ipath_port_info(struct ipath_portdata *pd,
++static int ipath_port_info(struct ipath_portdata *pd, u16 subport,
+ struct ipath_port_info __user *uinfo)
+ {
+ struct ipath_port_info info;
+ int nup;
+ int ret;
++ size_t sz;
+
+ (void) ipath_count_units(NULL, &nup, NULL);
+ info.num_active = nup;
+ info.unit = pd->port_dd->ipath_unit;
+ info.port = pd->port_port;
++ info.subport = subport;
++ /* Don't return new fields if old library opened the port. */
++ if ((pd->userversion & 0xffff) == IPATH_USER_SWMINOR) {
++ /* Number of user ports available for this device. */
++ info.num_ports = pd->port_dd->ipath_cfgports - 1;
++ info.num_subports = pd->port_subport_cnt;
++ sz = sizeof(info);
++ } else
++ sz = sizeof(info) - 2 * sizeof(u16);
+
+- if (copy_to_user(uinfo, &info, sizeof(info))) {
++ if (copy_to_user(uinfo, &info, sz)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+@@ -1560,6 +2008,16 @@ bail:
+ return ret;
+ }
+
++static int ipath_get_slave_info(struct ipath_portdata *pd,
++ void __user *slave_mask_addr)
++{
++ int ret = 0;
++
++ if (copy_to_user(slave_mask_addr, &pd->active_slaves, sizeof(u32)))
++ ret = -EFAULT;
++ return ret;
++}
++
+ static ssize_t ipath_write(struct file *fp, const char __user *data,
+ size_t count, loff_t *off)
+ {
+@@ -1586,6 +2044,8 @@ static ssize_t ipath_write(struct file *
+ consumed = sizeof(cmd.type);
+
+ switch (cmd.type) {
++ case IPATH_CMD_ASSIGN_PORT:
++ case __IPATH_CMD_USER_INIT:
+ case IPATH_CMD_USER_INIT:
+ copy = sizeof(cmd.cmd.user_info);
+ dest = &cmd.cmd.user_info;
+@@ -1612,6 +2072,11 @@ static ssize_t ipath_write(struct file *
+ dest = &cmd.cmd.part_key;
+ src = &ucmd->cmd.part_key;
+ break;
++ case IPATH_CMD_SLAVE_INFO:
++ copy = sizeof(cmd.cmd.slave_mask_addr);
++ dest = &cmd.cmd.slave_mask_addr;
++ src = &ucmd->cmd.slave_mask_addr;
++ break;
+ default:
+ ret = -EINVAL;
+ goto bail;
+@@ -1629,34 +2094,55 @@ static ssize_t ipath_write(struct file *
+
+ consumed += copy;
+ pd = port_fp(fp);
++ if (!pd && cmd.type != __IPATH_CMD_USER_INIT &&
++ cmd.type != IPATH_CMD_ASSIGN_PORT) {
++ ret = -EINVAL;
++ goto bail;
++ }
+
+ switch (cmd.type) {
++ case IPATH_CMD_ASSIGN_PORT:
++ ret = ipath_assign_port(fp, &cmd.cmd.user_info);
++ if (ret)
++ goto bail;
++ break;
++ case __IPATH_CMD_USER_INIT:
++ /* backwards compatibility, get port first */
++ ret = ipath_assign_port(fp, &cmd.cmd.user_info);
++ if (ret)
++ goto bail;
++ /* and fall through to current version. */
+ case IPATH_CMD_USER_INIT:
+- ret = ipath_do_user_init(pd, &cmd.cmd.user_info);
+- if (ret < 0)
++ ret = ipath_do_user_init(fp, &cmd.cmd.user_info);
++ if (ret)
+ goto bail;
+ ret = ipath_get_base_info(
+- pd, (void __user *) (unsigned long)
++ fp, (void __user *) (unsigned long)
+ cmd.cmd.user_info.spu_base_info,
+ cmd.cmd.user_info.spu_base_info_size);
+ break;
+ case IPATH_CMD_RECV_CTRL:
+- ret = ipath_manage_rcvq(pd, cmd.cmd.recv_ctrl);
++ ret = ipath_manage_rcvq(pd, subport_fp(fp), cmd.cmd.recv_ctrl);
+ break;
+ case IPATH_CMD_PORT_INFO:
+- ret = ipath_port_info(pd,
++ ret = ipath_port_info(pd, subport_fp(fp),
+ (struct ipath_port_info __user *)
+ (unsigned long) cmd.cmd.port_info);
+ break;
+ case IPATH_CMD_TID_UPDATE:
+- ret = ipath_tid_update(pd, &cmd.cmd.tid_info);
++ ret = ipath_tid_update(pd, fp, &cmd.cmd.tid_info);
+ break;
+ case IPATH_CMD_TID_FREE:
+- ret = ipath_tid_free(pd, &cmd.cmd.tid_info);
++ ret = ipath_tid_free(pd, subport_fp(fp), &cmd.cmd.tid_info);
+ break;
+ case IPATH_CMD_SET_PART_KEY:
+ ret = ipath_set_part_key(pd, cmd.cmd.part_key);
+ break;
++ case IPATH_CMD_SLAVE_INFO:
++ ret = ipath_get_slave_info(pd,
++ (void __user *) (unsigned long)
++ cmd.cmd.slave_mask_addr);
++ break;
+ }
+
+ if (ret >= 0)
+@@ -1815,7 +2301,7 @@ int ipath_user_add(struct ipath_devdata
+ if (ret < 0) {
+ ipath_dev_err(dd, "Could not create wildcard "
+ "minor: error %d\n", -ret);
+- goto bail_sma;
++ goto bail_user;
+ }
+
+ atomic_set(&user_setup, 1);
+@@ -1831,7 +2317,7 @@ int ipath_user_add(struct ipath_devdata
+
+ goto bail;
+
+-bail_sma:
++bail_user:
+ user_cleanup();
+ bail:
+ return ret;
+@@ -1853,4 +2339,3 @@ void ipath_user_remove(struct ipath_devd
+ bail:
+ return;
+ }
+-
+diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
+index 0936d8e..d9ff283 100644
+--- a/drivers/infiniband/hw/ipath/ipath_fs.c
++++ b/drivers/infiniband/hw/ipath/ipath_fs.c
+@@ -61,14 +61,13 @@ static int ipathfs_mknod(struct inode *d
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+- inode->u.generic_ip = data;
++ inode->i_private = data;
+ if ((mode & S_IFMT) == S_IFDIR) {
+ inode->i_op = &simple_dir_inode_operations;
+- inode->i_nlink++;
+- dir->i_nlink++;
++ inc_nlink(inode);
++ inc_nlink(dir);
+ }
+
+ inode->i_fop = fops;
+@@ -119,7 +118,7 @@ static ssize_t atomic_counters_read(stru
+ u16 i;
+ struct ipath_devdata *dd;
+
+- dd = file->f_dentry->d_inode->u.generic_ip;
++ dd = file->f_dentry->d_inode->i_private;
+
+ for (i = 0; i < NUM_COUNTERS; i++)
+ counters[i] = ipath_snap_cntr(dd, i);
+@@ -139,7 +138,7 @@ static ssize_t atomic_node_info_read(str
+ struct ipath_devdata *dd;
+ u64 guid;
+
+- dd = file->f_dentry->d_inode->u.generic_ip;
++ dd = file->f_dentry->d_inode->i_private;
+
+ guid = be64_to_cpu(dd->ipath_guid);
+
+@@ -178,7 +177,7 @@ static ssize_t atomic_port_info_read(str
+ u32 tmp, tmp2;
+ struct ipath_devdata *dd;
+
+- dd = file->f_dentry->d_inode->u.generic_ip;
++ dd = file->f_dentry->d_inode->i_private;
+
+ /* so we only initialize non-zero fields. */
+ memset(portinfo, 0, sizeof portinfo);
+@@ -191,8 +190,8 @@ static ssize_t atomic_port_info_read(str
+ portinfo[4] = (dd->ipath_lid << 16);
+
+ /*
+- * Notimpl yet SMLID (should we store this in the driver, in case
+- * SMA dies?) CapabilityMask is 0, we don't support any of these
++ * Notimpl yet SMLID.
++ * CapabilityMask is 0, we don't support any of these
+ * DiagCode is 0; we don't store any diag info for now Notimpl yet
+ * M_KeyLeasePeriod (we don't support M_Key)
+ */
+@@ -325,7 +324,7 @@ static ssize_t flash_read(struct file *f
+ goto bail;
+ }
+
+- dd = file->f_dentry->d_inode->u.generic_ip;
++ dd = file->f_dentry->d_inode->i_private;
+ if (ipath_eeprom_read(dd, pos, tmp, count)) {
+ ipath_dev_err(dd, "failed to read from flash\n");
+ ret = -ENXIO;
+@@ -357,19 +356,16 @@ static ssize_t flash_write(struct file *
+
+ pos = *ppos;
+
+- if ( pos < 0) {
++ if (pos != 0) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+- if (pos >= sizeof(struct ipath_flash)) {
+- ret = 0;
++ if (count != sizeof(struct ipath_flash)) {
++ ret = -EINVAL;
+ goto bail;
+ }
+
+- if (count > sizeof(struct ipath_flash) - pos)
+- count = sizeof(struct ipath_flash) - pos;
+-
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (!tmp) {
+ ret = -ENOMEM;
+@@ -381,7 +377,7 @@ static ssize_t flash_write(struct file *
+ goto bail_tmp;
+ }
+
+- dd = file->f_dentry->d_inode->u.generic_ip;
++ dd = file->f_dentry->d_inode->i_private;
+ if (ipath_eeprom_write(dd, pos, tmp, count)) {
+ ret = -ENXIO;
+ ipath_dev_err(dd, "failed to write to flash\n");
+diff --git a/drivers/infiniband/hw/ipath/ipath_ht400.c b/drivers/infiniband/hw/ipath/ipath_ht400.c
+deleted file mode 100644
+index 3db015d..0000000
+--- a/drivers/infiniband/hw/ipath/ipath_ht400.c
++++ /dev/null
+@@ -1,1603 +0,0 @@
+-/*
+- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
+- * 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.
+- */
+-
+-/*
+- * This file contains all of the code that is specific to the InfiniPath
+- * HT-400 chip.
+- */
+-
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-
+-#include "ipath_kernel.h"
+-#include "ipath_registers.h"
+-
+-/*
+- * This lists the InfiniPath HT400 registers, in the actual chip layout.
+- * This structure should never be directly accessed.
+- *
+- * The names are in InterCap form because they're taken straight from
+- * the chip specification. Since they're only used in this file, they
+- * don't pollute the rest of the source.
+-*/
+-
+-struct _infinipath_do_not_use_kernel_regs {
+- unsigned long long Revision;
+- unsigned long long Control;
+- unsigned long long PageAlign;
+- unsigned long long PortCnt;
+- unsigned long long DebugPortSelect;
+- unsigned long long DebugPort;
+- unsigned long long SendRegBase;
+- unsigned long long UserRegBase;
+- unsigned long long CounterRegBase;
+- unsigned long long Scratch;
+- unsigned long long ReservedMisc1;
+- unsigned long long InterruptConfig;
+- unsigned long long IntBlocked;
+- unsigned long long IntMask;
+- unsigned long long IntStatus;
+- unsigned long long IntClear;
+- unsigned long long ErrorMask;
+- unsigned long long ErrorStatus;
+- unsigned long long ErrorClear;
+- unsigned long long HwErrMask;
+- unsigned long long HwErrStatus;
+- unsigned long long HwErrClear;
+- unsigned long long HwDiagCtrl;
+- unsigned long long MDIO;
+- unsigned long long IBCStatus;
+- unsigned long long IBCCtrl;
+- unsigned long long ExtStatus;
+- unsigned long long ExtCtrl;
+- unsigned long long GPIOOut;
+- unsigned long long GPIOMask;
+- unsigned long long GPIOStatus;
+- unsigned long long GPIOClear;
+- unsigned long long RcvCtrl;
+- unsigned long long RcvBTHQP;
+- unsigned long long RcvHdrSize;
+- unsigned long long RcvHdrCnt;
+- unsigned long long RcvHdrEntSize;
+- unsigned long long RcvTIDBase;
+- unsigned long long RcvTIDCnt;
+- unsigned long long RcvEgrBase;
+- unsigned long long RcvEgrCnt;
+- unsigned long long RcvBufBase;
+- unsigned long long RcvBufSize;
+- unsigned long long RxIntMemBase;
+- unsigned long long RxIntMemSize;
+- unsigned long long RcvPartitionKey;
+- unsigned long long ReservedRcv[10];
+- unsigned long long SendCtrl;
+- unsigned long long SendPIOBufBase;
+- unsigned long long SendPIOSize;
+- unsigned long long SendPIOBufCnt;
+- unsigned long long SendPIOAvailAddr;
+- unsigned long long TxIntMemBase;
+- unsigned long long TxIntMemSize;
+- unsigned long long ReservedSend[9];
+- unsigned long long SendBufferError;
+- unsigned long long SendBufferErrorCONT1;
+- unsigned long long SendBufferErrorCONT2;
+- unsigned long long SendBufferErrorCONT3;
+- unsigned long long ReservedSBE[4];
+- unsigned long long RcvHdrAddr0;
+- unsigned long long RcvHdrAddr1;
+- unsigned long long RcvHdrAddr2;
+- unsigned long long RcvHdrAddr3;
+- unsigned long long RcvHdrAddr4;
+- unsigned long long RcvHdrAddr5;
+- unsigned long long RcvHdrAddr6;
+- unsigned long long RcvHdrAddr7;
+- unsigned long long RcvHdrAddr8;
+- unsigned long long ReservedRHA[7];
+- unsigned long long RcvHdrTailAddr0;
+- unsigned long long RcvHdrTailAddr1;
+- unsigned long long RcvHdrTailAddr2;
+- unsigned long long RcvHdrTailAddr3;
+- unsigned long long RcvHdrTailAddr4;
+- unsigned long long RcvHdrTailAddr5;
+- unsigned long long RcvHdrTailAddr6;
+- unsigned long long RcvHdrTailAddr7;
+- unsigned long long RcvHdrTailAddr8;
+- unsigned long long ReservedRHTA[7];
+- unsigned long long Sync; /* Software only */
+- unsigned long long Dump; /* Software only */
+- unsigned long long SimVer; /* Software only */
+- unsigned long long ReservedSW[5];
+- unsigned long long SerdesConfig0;
+- unsigned long long SerdesConfig1;
+- unsigned long long SerdesStatus;
+- unsigned long long XGXSConfig;
+- unsigned long long ReservedSW2[4];
+-};
+-
+-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
+- _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+-#define IPATH_CREG_OFFSET(field) (offsetof( \
+- struct infinipath_counters, field) / sizeof(u64))
+-
+-static const struct ipath_kregs ipath_ht_kregs = {
+- .kr_control = IPATH_KREG_OFFSET(Control),
+- .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
+- .kr_debugport = IPATH_KREG_OFFSET(DebugPort),
+- .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
+- .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
+- .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
+- .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
+- .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
+- .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
+- .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
+- .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
+- .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
+- .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
+- .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
+- .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
+- .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
+- .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
+- .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
+- .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
+- .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
+- .kr_intclear = IPATH_KREG_OFFSET(IntClear),
+- .kr_interruptconfig = IPATH_KREG_OFFSET(InterruptConfig),
+- .kr_intmask = IPATH_KREG_OFFSET(IntMask),
+- .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
+- .kr_mdio = IPATH_KREG_OFFSET(MDIO),
+- .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
+- .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
+- .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
+- .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
+- .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
+- .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
+- .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
+- .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
+- .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
+- .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
+- .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
+- .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
+- .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
+- .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
+- .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
+- .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
+- .kr_revision = IPATH_KREG_OFFSET(Revision),
+- .kr_scratch = IPATH_KREG_OFFSET(Scratch),
+- .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
+- .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
+- .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
+- .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
+- .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
+- .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
+- .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
+- .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
+- .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
+- .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
+- .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
+- .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
+- .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
+- .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
+- /*
+- * These should not be used directly via ipath_read_kreg64(),
+- * use them with ipath_read_kreg64_port(),
+- */
+- .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
+- .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0)
+-};
+-
+-static const struct ipath_cregs ipath_ht_cregs = {
+- .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
+- .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
+- .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
+- .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
+- .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
+- .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
+- .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
+- .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
+- .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
+- .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
+- .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
+- .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
+- /* calc from Reg_CounterRegBase + offset */
+- .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
+- .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
+- .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
+- .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
+- .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
+- .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
+- .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
+- .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
+- .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
+- .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
+- .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
+- .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
+- .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
+- .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
+- .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
+- .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
+- .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
+- .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
+- .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
+- .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
+- .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
+-};
+-
+-/* kr_intstatus, kr_intclear, kr_intmask bits */
+-#define INFINIPATH_I_RCVURG_MASK 0x1FF
+-#define INFINIPATH_I_RCVAVAIL_MASK 0x1FF
+-
+-/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
+-#define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0
+-#define INFINIPATH_HWE_HTCMEMPARITYERR_MASK 0x3FFFFFULL
+-#define INFINIPATH_HWE_HTCLNKABYTE0CRCERR 0x0000000000800000ULL
+-#define INFINIPATH_HWE_HTCLNKABYTE1CRCERR 0x0000000001000000ULL
+-#define INFINIPATH_HWE_HTCLNKBBYTE0CRCERR 0x0000000002000000ULL
+-#define INFINIPATH_HWE_HTCLNKBBYTE1CRCERR 0x0000000004000000ULL
+-#define INFINIPATH_HWE_HTCMISCERR4 0x0000000008000000ULL
+-#define INFINIPATH_HWE_HTCMISCERR5 0x0000000010000000ULL
+-#define INFINIPATH_HWE_HTCMISCERR6 0x0000000020000000ULL
+-#define INFINIPATH_HWE_HTCMISCERR7 0x0000000040000000ULL
+-#define INFINIPATH_HWE_HTCBUSTREQPARITYERR 0x0000000080000000ULL
+-#define INFINIPATH_HWE_HTCBUSTRESPPARITYERR 0x0000000100000000ULL
+-#define INFINIPATH_HWE_HTCBUSIREQPARITYERR 0x0000000200000000ULL
+-#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL
+-#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL
+-#define INFINIPATH_HWE_HTBPLL_FBSLIP 0x0200000000000000ULL
+-#define INFINIPATH_HWE_HTBPLL_RFSLIP 0x0400000000000000ULL
+-#define INFINIPATH_HWE_HTAPLL_FBSLIP 0x0800000000000000ULL
+-#define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL
+-#define INFINIPATH_HWE_SERDESPLLFAILED 0x2000000000000000ULL
+-
+-/* kr_extstatus bits */
+-#define INFINIPATH_EXTS_FREQSEL 0x2
+-#define INFINIPATH_EXTS_SERDESSEL 0x4
+-#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000
+-#define INFINIPATH_EXTS_MEMBIST_CORRECT 0x0000000000008000
+-
+-/*
+- * masks and bits that are different in different chips, or present only
+- * in one
+- */
+-static const ipath_err_t infinipath_hwe_htcmemparityerr_mask =
+- INFINIPATH_HWE_HTCMEMPARITYERR_MASK;
+-static const ipath_err_t infinipath_hwe_htcmemparityerr_shift =
+- INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT;
+-
+-static const ipath_err_t infinipath_hwe_htclnkabyte0crcerr =
+- INFINIPATH_HWE_HTCLNKABYTE0CRCERR;
+-static const ipath_err_t infinipath_hwe_htclnkabyte1crcerr =
+- INFINIPATH_HWE_HTCLNKABYTE1CRCERR;
+-static const ipath_err_t infinipath_hwe_htclnkbbyte0crcerr =
+- INFINIPATH_HWE_HTCLNKBBYTE0CRCERR;
+-static const ipath_err_t infinipath_hwe_htclnkbbyte1crcerr =
+- INFINIPATH_HWE_HTCLNKBBYTE1CRCERR;
+-
+-#define _IPATH_GPIO_SDA_NUM 1
+-#define _IPATH_GPIO_SCL_NUM 0
+-
+-#define IPATH_GPIO_SDA \
+- (1ULL << (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+-#define IPATH_GPIO_SCL \
+- (1ULL << (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+-
+-/* keep the code below somewhat more readonable; not used elsewhere */
+-#define _IPATH_HTLINK0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
+- infinipath_hwe_htclnkabyte1crcerr)
+-#define _IPATH_HTLINK1_CRCBITS (infinipath_hwe_htclnkbbyte0crcerr | \
+- infinipath_hwe_htclnkbbyte1crcerr)
+-#define _IPATH_HTLANE0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
+- infinipath_hwe_htclnkbbyte0crcerr)
+-#define _IPATH_HTLANE1_CRCBITS (infinipath_hwe_htclnkabyte1crcerr | \
+- infinipath_hwe_htclnkbbyte1crcerr)
+-
+-static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
+- char *msg, size_t msgl)
+-{
+- char bitsmsg[64];
+- ipath_err_t crcbits = hwerrs &
+- (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS);
+- /* don't check if 8bit HT */
+- if (dd->ipath_flags & IPATH_8BIT_IN_HT0)
+- crcbits &= ~infinipath_hwe_htclnkabyte1crcerr;
+- /* don't check if 8bit HT */
+- if (dd->ipath_flags & IPATH_8BIT_IN_HT1)
+- crcbits &= ~infinipath_hwe_htclnkbbyte1crcerr;
+- /*
+- * we'll want to ignore link errors on link that is
+- * not in use, if any. For now, complain about both
+- */
+- if (crcbits) {
+- u16 ctrl0, ctrl1;
+- snprintf(bitsmsg, sizeof bitsmsg,
+- "[HT%s lane %s CRC (%llx); ignore till reload]",
+- !(crcbits & _IPATH_HTLINK1_CRCBITS) ?
+- "0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
+- ? "1 (B)" : "0+1 (A+B)"),
+- !(crcbits & _IPATH_HTLANE1_CRCBITS) ? "0"
+- : (!(crcbits & _IPATH_HTLANE0_CRCBITS) ? "1" :
+- "0+1"), (unsigned long long) crcbits);
+- strlcat(msg, bitsmsg, msgl);
+-
+- /*
+- * print extra info for debugging. slave/primary
+- * config word 4, 8 (link control 0, 1)
+- */
+-
+- if (pci_read_config_word(dd->pcidev,
+- dd->ipath_ht_slave_off + 0x4,
+- &ctrl0))
+- dev_info(&dd->pcidev->dev, "Couldn't read "
+- "linkctrl0 of slave/primary "
+- "config block\n");
+- else if (!(ctrl0 & 1 << 6))
+- /* not if EOC bit set */
+- ipath_dbg("HT linkctrl0 0x%x%s%s\n", ctrl0,
+- ((ctrl0 >> 8) & 7) ? " CRC" : "",
+- ((ctrl0 >> 4) & 1) ? "linkfail" :
+- "");
+- if (pci_read_config_word(dd->pcidev,
+- dd->ipath_ht_slave_off + 0x8,
+- &ctrl1))
+- dev_info(&dd->pcidev->dev, "Couldn't read "
+- "linkctrl1 of slave/primary "
+- "config block\n");
+- else if (!(ctrl1 & 1 << 6))
+- /* not if EOC bit set */
+- ipath_dbg("HT linkctrl1 0x%x%s%s\n", ctrl1,
+- ((ctrl1 >> 8) & 7) ? " CRC" : "",
+- ((ctrl1 >> 4) & 1) ? "linkfail" :
+- "");
+-
+- /* disable until driver reloaded */
+- dd->ipath_hwerrmask &= ~crcbits;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- ipath_dbg("HT crc errs: %s\n", msg);
+- } else
+- ipath_dbg("ignoring HT crc errors 0x%llx, "
+- "not in use\n", (unsigned long long)
+- (hwerrs & (_IPATH_HTLINK0_CRCBITS |
+- _IPATH_HTLINK1_CRCBITS)));
+-}
+-
+-/**
+- * ipath_ht_handle_hwerrors - display hardware errors
+- * @dd: the infinipath device
+- * @msg: the output buffer
+- * @msgl: the size of the output buffer
+- *
+- * Use same msg buffer as regular errors to avoid
+- * excessive stack use. Most hardware errors are catastrophic, but for
+- * right now, we'll print them and continue.
+- * We reuse the same message buffer as ipath_handle_errors() to avoid
+- * excessive stack usage.
+- */
+-static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
+- size_t msgl)
+-{
+- ipath_err_t hwerrs;
+- u32 bits, ctrl;
+- int isfatal = 0;
+- char bitsmsg[64];
+-
+- hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
+-
+- if (!hwerrs) {
+- ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
+- /*
+- * better than printing cofusing messages
+- * This seems to be related to clearing the crc error, or
+- * the pll error during init.
+- */
+- goto bail;
+- } else if (hwerrs == -1LL) {
+- ipath_dev_err(dd, "Read of hardware error status failed "
+- "(all bits set); ignoring\n");
+- goto bail;
+- }
+- ipath_stats.sps_hwerrs++;
+-
+- /* Always clear the error status register, except MEMBISTFAIL,
+- * regardless of whether we continue or stop using the chip.
+- * We want that set so we know it failed, even across driver reload.
+- * We'll still ignore it in the hwerrmask. We do this partly for
+- * diagnostics, but also for support */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
+- hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
+-
+- hwerrs &= dd->ipath_hwerrmask;
+-
+- /*
+- * make sure we get this much out, unless told to be quiet,
+- * or it's occurred within the last 5 seconds
+- */
+- if ((hwerrs & ~dd->ipath_lasthwerror) ||
+- (ipath_debug & __IPATH_VERBDBG))
+- dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
+- "(cleared)\n", (unsigned long long) hwerrs);
+- dd->ipath_lasthwerror |= hwerrs;
+-
+- if (hwerrs & ~infinipath_hwe_bitsextant)
+- ipath_dev_err(dd, "hwerror interrupt with unknown errors "
+- "%llx set\n", (unsigned long long)
+- (hwerrs & ~infinipath_hwe_bitsextant));
+-
+- ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
+- if (ctrl & INFINIPATH_C_FREEZEMODE) {
+- if (hwerrs) {
+- /*
+- * if any set that we aren't ignoring; only
+- * make the complaint once, in case it's stuck
+- * or recurring, and we get here multiple
+- * times.
+- */
+- if (dd->ipath_flags & IPATH_INITTED) {
+- ipath_dev_err(dd, "Fatal Error (freeze "
+- "mode), no longer usable\n");
+- isfatal = 1;
+- }
+- *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
+- /* mark as having had error */
+- *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
+- /*
+- * mark as not usable, at a minimum until driver
+- * is reloaded, probably until reboot, since no
+- * other reset is possible.
+- */
+- dd->ipath_flags &= ~IPATH_INITTED;
+- } else {
+- ipath_dbg("Clearing freezemode on ignored hardware "
+- "error\n");
+- ctrl &= ~INFINIPATH_C_FREEZEMODE;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+- ctrl);
+- }
+- }
+-
+- *msg = '\0';
+-
+- /*
+- * may someday want to decode into which bits are which
+- * functional area for parity errors, etc.
+- */
+- if (hwerrs & (infinipath_hwe_htcmemparityerr_mask
+- << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT)) {
+- bits = (u32) ((hwerrs >>
+- INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) &
+- INFINIPATH_HWE_HTCMEMPARITYERR_MASK);
+- snprintf(bitsmsg, sizeof bitsmsg, "[HTC Parity Errs %x] ",
+- bits);
+- strlcat(msg, bitsmsg, msgl);
+- }
+- if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
+- << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
+- bits = (u32) ((hwerrs >>
+- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
+- INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
+- snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
+- bits);
+- strlcat(msg, bitsmsg, msgl);
+- }
+- if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
+- << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
+- bits = (u32) ((hwerrs >>
+- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
+- INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
+- snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
+- bits);
+- strlcat(msg, bitsmsg, msgl);
+- }
+- if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
+- strlcat(msg, "[IB2IPATH Parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
+- strlcat(msg, "[IPATH2IB Parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR)
+- strlcat(msg, "[HTC Ireq Parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR)
+- strlcat(msg, "[HTC Treq Parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR)
+- strlcat(msg, "[HTC Tresp Parity]", msgl);
+-
+- if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
+- hwerr_crcbits(dd, hwerrs, msg, msgl);
+-
+- if (hwerrs & INFINIPATH_HWE_HTCMISCERR5)
+- strlcat(msg, "[HT core Misc5]", msgl);
+- if (hwerrs & INFINIPATH_HWE_HTCMISCERR6)
+- strlcat(msg, "[HT core Misc6]", msgl);
+- if (hwerrs & INFINIPATH_HWE_HTCMISCERR7)
+- strlcat(msg, "[HT core Misc7]", msgl);
+- if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
+- strlcat(msg, "[Memory BIST test failed, HT-400 unusable]",
+- msgl);
+- /* ignore from now on, so disable until driver reloaded */
+- dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- }
+-#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
+- INFINIPATH_HWE_COREPLL_RFSLIP | \
+- INFINIPATH_HWE_HTBPLL_FBSLIP | \
+- INFINIPATH_HWE_HTBPLL_RFSLIP | \
+- INFINIPATH_HWE_HTAPLL_FBSLIP | \
+- INFINIPATH_HWE_HTAPLL_RFSLIP)
+-
+- if (hwerrs & _IPATH_PLL_FAIL) {
+- snprintf(bitsmsg, sizeof bitsmsg,
+- "[PLL failed (%llx), HT-400 unusable]",
+- (unsigned long long) (hwerrs & _IPATH_PLL_FAIL));
+- strlcat(msg, bitsmsg, msgl);
+- /* ignore from now on, so disable until driver reloaded */
+- dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- }
+-
+- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
+- /*
+- * If it occurs, it is left masked since the eternal
+- * interface is unused
+- */
+- dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- }
+-
+- if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
+- strlcat(msg, "[Rx Dsync]", msgl);
+- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
+- strlcat(msg, "[SerDes PLL]", msgl);
+-
+- ipath_dev_err(dd, "%s hardware error\n", msg);
+- if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
+- /*
+- * for status file; if no trailing brace is copied,
+- * we'll know it was truncated.
+- */
+- snprintf(dd->ipath_freezemsg,
+- dd->ipath_freezelen, "{%s}", msg);
+-
+-bail:;
+-}
+-
+-/**
+- * ipath_ht_boardname - fill in the board name
+- * @dd: the infinipath device
+- * @name: the output buffer
+- * @namelen: the size of the output buffer
+- *
+- * fill in the board name, based on the board revision register
+- */
+-static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
+- size_t namelen)
+-{
+- char *n = NULL;
+- u8 boardrev = dd->ipath_boardrev;
+- int ret;
+-
+- switch (boardrev) {
+- case 4: /* Ponderosa is one of the bringup boards */
+- n = "Ponderosa";
+- break;
+- case 5:
+- /*
+- * HT-460 original production board; two production levels, with
+- * different serial number ranges. See ipath_ht_early_init() for
+- * case where we enable IPATH_GPIO_INTR for later serial # range.
+- */
+- n = "InfiniPath_HT-460";
+- break;
+- case 6:
+- n = "OEM_Board_3";
+- break;
+- case 7:
+- /* HT-460 small form factor production board */
+- n = "InfiniPath_HT-465";
+- break;
+- case 8:
+- n = "LS/X-1";
+- break;
+- case 9: /* Comstock bringup test board */
+- n = "Comstock";
+- break;
+- case 10:
+- n = "OEM_Board_2";
+- break;
+- case 11:
+- n = "InfiniPath_HT-470";
+- break;
+- case 12:
+- n = "OEM_Board_4";
+- break;
+- default: /* don't know, just print the number */
+- ipath_dev_err(dd, "Don't yet know about board "
+- "with ID %u\n", boardrev);
+- snprintf(name, namelen, "Unknown_InfiniPath_HT-4xx_%u",
+- boardrev);
+- break;
+- }
+- if (n)
+- snprintf(name, namelen, "%s", n);
+-
+- if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {
+- /*
+- * This version of the driver only supports the HT-400
+- * Rev 3.2
+- */
+- ipath_dev_err(dd,
+- "Unsupported HT-400 revision %u.%u!\n",
+- dd->ipath_majrev, dd->ipath_minrev);
+- ret = 1;
+- goto bail;
+- }
+- /*
+- * pkt/word counters are 32 bit, and therefore wrap fast enough
+- * that we snapshot them from a timer, and maintain 64 bit shadow
+- * copies
+- */
+- dd->ipath_flags |= IPATH_32BITCOUNTERS;
+- if (dd->ipath_htspeed != 800)
+- ipath_dev_err(dd,
+- "Incorrectly configured for HT @ %uMHz\n",
+- dd->ipath_htspeed);
+- if (dd->ipath_boardrev == 7 || dd->ipath_boardrev == 11 ||
+- dd->ipath_boardrev == 6)
+- dd->ipath_flags |= IPATH_GPIO_INTR;
+- else
+- dd->ipath_flags |= IPATH_POLL_RX_INTR;
+- if (dd->ipath_boardrev == 8) { /* LS/X-1 */
+- u64 val;
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
+- if (val & INFINIPATH_EXTS_SERDESSEL) {
+- /*
+- * hardware disabled
+- *
+- * This means that the chip is hardware disabled,
+- * and will not be able to bring up the link,
+- * in any case. We special case this and abort
+- * early, to avoid later messages. We also set
+- * the DISABLED status bit
+- */
+- ipath_dbg("Unit %u is hardware-disabled\n",
+- dd->ipath_unit);
+- *dd->ipath_statusp |= IPATH_STATUS_DISABLED;
+- /* this value is handled differently */
+- ret = 2;
+- goto bail;
+- }
+- }
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-static void ipath_check_htlink(struct ipath_devdata *dd)
+-{
+- u8 linkerr, link_off, i;
+-
+- for (i = 0; i < 2; i++) {
+- link_off = dd->ipath_ht_slave_off + i * 4 + 0xd;
+- if (pci_read_config_byte(dd->pcidev, link_off, &linkerr))
+- dev_info(&dd->pcidev->dev, "Couldn't read "
+- "linkerror%d of HT slave/primary block\n",
+- i);
+- else if (linkerr & 0xf0) {
+- ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, "
+- "clearing\n", linkerr >> 4, i);
+- /*
+- * writing the linkerr bits that are set should
+- * clear them
+- */
+- if (pci_write_config_byte(dd->pcidev, link_off,
+- linkerr))
+- ipath_dbg("Failed write to clear HT "
+- "linkerror%d\n", i);
+- if (pci_read_config_byte(dd->pcidev, link_off,
+- &linkerr))
+- dev_info(&dd->pcidev->dev,
+- "Couldn't reread linkerror%d of "
+- "HT slave/primary block\n", i);
+- else if (linkerr & 0xf0)
+- dev_info(&dd->pcidev->dev,
+- "HT linkerror%d bits 0x%x "
+- "couldn't be cleared\n",
+- i, linkerr >> 4);
+- }
+- }
+-}
+-
+-static int ipath_setup_ht_reset(struct ipath_devdata *dd)
+-{
+- ipath_dbg("No reset possible for HT-400\n");
+- return 0;
+-}
+-
+-#define HT_CAPABILITY_ID 0x08 /* HT capabilities not defined in kernel */
+-#define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */
+-#define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */
+-
+-/*
+- * Bits 13-15 of command==0 is slave/primary block. Clear any HT CRC
+- * errors. We only bother to do this at load time, because it's OK if
+- * it happened before we were loaded (first time after boot/reset),
+- * but any time after that, it's fatal anyway. Also need to not check
+- * for for upper byte errors if we are in 8 bit mode, so figure out
+- * our width. For now, at least, also complain if it's 8 bit.
+- */
+-static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev,
+- int pos, u8 cap_type)
+-{
+- u8 linkwidth = 0, linkerr, link_a_b_off, link_off;
+- u16 linkctrl = 0;
+- int i;
+-
+- dd->ipath_ht_slave_off = pos;
+- /* command word, master_host bit */
+- /* master host || slave */
+- if ((cap_type >> 2) & 1)
+- link_a_b_off = 4;
+- else
+- link_a_b_off = 0;
+- ipath_cdbg(VERBOSE, "HT%u (Link %c) connected to processor\n",
+- link_a_b_off ? 1 : 0,
+- link_a_b_off ? 'B' : 'A');
+-
+- link_a_b_off += pos;
+-
+- /*
+- * check both link control registers; clear both HT CRC sets if
+- * necessary.
+- */
+- for (i = 0; i < 2; i++) {
+- link_off = pos + i * 4 + 0x4;
+- if (pci_read_config_word(pdev, link_off, &linkctrl))
+- ipath_dev_err(dd, "Couldn't read HT link control%d "
+- "register\n", i);
+- else if (linkctrl & (0xf << 8)) {
+- ipath_cdbg(VERBOSE, "Clear linkctrl%d CRC Error "
+- "bits %x\n", i, linkctrl & (0xf << 8));
+- /*
+- * now write them back to clear the error.
+- */
+- pci_write_config_byte(pdev, link_off,
+- linkctrl & (0xf << 8));
+- }
+- }
+-
+- /*
+- * As with HT CRC bits, same for protocol errors that might occur
+- * during boot.
+- */
+- for (i = 0; i < 2; i++) {
+- link_off = pos + i * 4 + 0xd;
+- if (pci_read_config_byte(pdev, link_off, &linkerr))
+- dev_info(&pdev->dev, "Couldn't read linkerror%d "
+- "of HT slave/primary block\n", i);
+- else if (linkerr & 0xf0) {
+- ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, "
+- "clearing\n", linkerr >> 4, i);
+- /*
+- * writing the linkerr bits that are set will clear
+- * them
+- */
+- if (pci_write_config_byte
+- (pdev, link_off, linkerr))
+- ipath_dbg("Failed write to clear HT "
+- "linkerror%d\n", i);
+- if (pci_read_config_byte(pdev, link_off, &linkerr))
+- dev_info(&pdev->dev, "Couldn't reread "
+- "linkerror%d of HT slave/primary "
+- "block\n", i);
+- else if (linkerr & 0xf0)
+- dev_info(&pdev->dev, "HT linkerror%d bits "
+- "0x%x couldn't be cleared\n",
+- i, linkerr >> 4);
+- }
+- }
+-
+- /*
+- * this is just for our link to the host, not devices connected
+- * through tunnel.
+- */
+-
+- if (pci_read_config_byte(pdev, link_a_b_off + 7, &linkwidth))
+- ipath_dev_err(dd, "Couldn't read HT link width "
+- "config register\n");
+- else {
+- u32 width;
+- switch (linkwidth & 7) {
+- case 5:
+- width = 4;
+- break;
+- case 4:
+- width = 2;
+- break;
+- case 3:
+- width = 32;
+- break;
+- case 1:
+- width = 16;
+- break;
+- case 0:
+- default: /* if wrong, assume 8 bit */
+- width = 8;
+- break;
+- }
+-
+- dd->ipath_htwidth = width;
+-
+- if (linkwidth != 0x11) {
+- ipath_dev_err(dd, "Not configured for 16 bit HT "
+- "(%x)\n", linkwidth);
+- if (!(linkwidth & 0xf)) {
+- ipath_dbg("Will ignore HT lane1 errors\n");
+- dd->ipath_flags |= IPATH_8BIT_IN_HT0;
+- }
+- }
+- }
+-
+- /*
+- * this is just for our link to the host, not devices connected
+- * through tunnel.
+- */
+- if (pci_read_config_byte(pdev, link_a_b_off + 0xd, &linkwidth))
+- ipath_dev_err(dd, "Couldn't read HT link frequency "
+- "config register\n");
+- else {
+- u32 speed;
+- switch (linkwidth & 0xf) {
+- case 6:
+- speed = 1000;
+- break;
+- case 5:
+- speed = 800;
+- break;
+- case 4:
+- speed = 600;
+- break;
+- case 3:
+- speed = 500;
+- break;
+- case 2:
+- speed = 400;
+- break;
+- case 1:
+- speed = 300;
+- break;
+- default:
+- /*
+- * assume reserved and vendor-specific are 200...
+- */
+- case 0:
+- speed = 200;
+- break;
+- }
+- dd->ipath_htspeed = speed;
+- }
+-}
+-
+-static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,
+- int pos)
+-{
+- u32 int_handler_addr_lower;
+- u32 int_handler_addr_upper;
+- u64 ihandler;
+- u32 intvec;
+-
+- /* use indirection register to get the intr handler */
+- pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10);
+- pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower);
+- pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11);
+- pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper);
+-
+- ihandler = (u64) int_handler_addr_lower |
+- ((u64) int_handler_addr_upper << 32);
+-
+- /*
+- * kernels with CONFIG_PCI_MSI set the vector in the irq field of
+- * struct pci_device, so we use that to program the HT-400 internal
+- * interrupt register (not config space) with that value. The BIOS
+- * must still have done the basic MSI setup.
+- */
+- intvec = pdev->irq;
+- /*
+- * clear any vector bits there; normally not set but we'll overload
+- * this for some debug purposes (setting the HTC debug register
+- * value from software, rather than GPIOs), so it might be set on a
+- * driver reload.
+- */
+- ihandler &= ~0xff0000;
+- /* x86 vector goes in intrinfo[23:16] */
+- ihandler |= intvec << 16;
+- ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, "
+- "interruptconfig %llx\n", int_handler_addr_lower,
+- int_handler_addr_upper, intvec,
+- (unsigned long long) ihandler);
+-
+- /* can't program yet, so save for interrupt setup */
+- dd->ipath_intconfig = ihandler;
+- /* keep going, so we find link control stuff also */
+-
+- return ihandler != 0;
+-}
+-
+-/**
+- * ipath_setup_ht_config - setup the interruptconfig register
+- * @dd: the infinipath device
+- * @pdev: the PCI device
+- *
+- * setup the interruptconfig register from the HT config info.
+- * Also clear CRC errors in HT linkcontrol, if necessary.
+- * This is done only for the real hardware. It is done before
+- * chip address space is initted, so can't touch infinipath registers
+- */
+-static int ipath_setup_ht_config(struct ipath_devdata *dd,
+- struct pci_dev *pdev)
+-{
+- int pos, ret = 0;
+- int ihandler = 0;
+-
+- /*
+- * Read the capability info to find the interrupt info, and also
+- * handle clearing CRC errors in linkctrl register if necessary. We
+- * do this early, before we ever enable errors or hardware errors,
+- * mostly to avoid causing the chip to enter freeze mode.
+- */
+- pos = pci_find_capability(pdev, HT_CAPABILITY_ID);
+- if (!pos) {
+- ipath_dev_err(dd, "Couldn't find HyperTransport "
+- "capability; no interrupts\n");
+- ret = -ENODEV;
+- goto bail;
+- }
+- do {
+- u8 cap_type;
+-
+- /* the HT capability type byte is 3 bytes after the
+- * capability byte.
+- */
+- if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
+- dev_info(&pdev->dev, "Couldn't read config "
+- "command @ %d\n", pos);
+- continue;
+- }
+- if (!(cap_type & 0xE0))
+- slave_or_pri_blk(dd, pdev, pos, cap_type);
+- else if (cap_type == HT_INTR_DISC_CONFIG)
+- ihandler = set_int_handler(dd, pdev, pos);
+- } while ((pos = pci_find_next_capability(pdev, pos,
+- HT_CAPABILITY_ID)));
+-
+- if (!ihandler) {
+- ipath_dev_err(dd, "Couldn't find interrupt handler in "
+- "config space\n");
+- ret = -ENODEV;
+- }
+-
+-bail:
+- return ret;
+-}
+-
+-/**
+- * ipath_setup_ht_cleanup - clean up any per-chip chip-specific stuff
+- * @dd: the infinipath device
+- *
+- * Called during driver unload.
+- * This is currently a nop for the HT-400, not for all chips
+- */
+-static void ipath_setup_ht_cleanup(struct ipath_devdata *dd)
+-{
+-}
+-
+-/**
+- * ipath_setup_ht_setextled - set the state of the two external LEDs
+- * @dd: the infinipath device
+- * @lst: the L state
+- * @ltst: the LT state
+- *
+- * Set the state of the two external LEDs, to indicate physical and
+- * logical state of IB link. For this chip (at least with recommended
+- * board pinouts), LED1 is Green (physical state), and LED2 is Yellow
+- * (logical state)
+- *
+- * Note: We try to match the Mellanox HCA LED behavior as best
+- * we can. Green indicates physical link state is OK (something is
+- * plugged in, and we can train).
+- * Amber indicates the link is logically up (ACTIVE).
+- * Mellanox further blinks the amber LED to indicate data packet
+- * activity, but we have no hardware support for that, so it would
+- * require waking up every 10-20 msecs and checking the counters
+- * on the chip, and then turning the LED off if appropriate. That's
+- * visible overhead, so not something we will do.
+- *
+- */
+-static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
+- u64 lst, u64 ltst)
+-{
+- u64 extctl;
+-
+- /* the diags use the LED to indicate diag info, so we leave
+- * the external LED alone when the diags are running */
+- if (ipath_diag_inuse)
+- return;
+-
+- /*
+- * start by setting both LED control bits to off, then turn
+- * on the appropriate bit(s).
+- */
+- if (dd->ipath_boardrev == 8) { /* LS/X-1 uses different pins */
+- /*
+- * major difference is that INFINIPATH_EXTC_LEDGBLERR_OFF
+- * is inverted, because it is normally used to indicate
+- * a hardware fault at reset, if there were errors
+- */
+- extctl = (dd->ipath_extctrl & ~INFINIPATH_EXTC_LEDGBLOK_ON)
+- | INFINIPATH_EXTC_LEDGBLERR_OFF;
+- if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
+- extctl &= ~INFINIPATH_EXTC_LEDGBLERR_OFF;
+- if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
+- extctl |= INFINIPATH_EXTC_LEDGBLOK_ON;
+- }
+- else {
+- extctl = dd->ipath_extctrl &
+- ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
+- INFINIPATH_EXTC_LED2PRIPORT_ON);
+- if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
+- extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
+- if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
+- extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
+- }
+- dd->ipath_extctrl = extctl;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
+-}
+-
+-static void ipath_init_ht_variables(void)
+-{
+- ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+- ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+- ipath_gpio_sda = IPATH_GPIO_SDA;
+- ipath_gpio_scl = IPATH_GPIO_SCL;
+-
+- infinipath_i_bitsextant =
+- (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
+- (INFINIPATH_I_RCVAVAIL_MASK <<
+- INFINIPATH_I_RCVAVAIL_SHIFT) |
+- INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
+- INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
+-
+- infinipath_e_bitsextant =
+- INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
+- INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
+- INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
+- INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
+- INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
+- INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
+- INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
+- INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
+- INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
+- INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
+- INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
+- INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
+- INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
+- INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
+- INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
+- INFINIPATH_E_HARDWARE;
+-
+- infinipath_hwe_bitsextant =
+- (INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
+- INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
+- (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
+- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
+- (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
+- INFINIPATH_HWE_HTCLNKABYTE0CRCERR |
+- INFINIPATH_HWE_HTCLNKABYTE1CRCERR |
+- INFINIPATH_HWE_HTCLNKBBYTE0CRCERR |
+- INFINIPATH_HWE_HTCLNKBBYTE1CRCERR |
+- INFINIPATH_HWE_HTCMISCERR4 |
+- INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 |
+- INFINIPATH_HWE_HTCMISCERR7 |
+- INFINIPATH_HWE_HTCBUSTREQPARITYERR |
+- INFINIPATH_HWE_HTCBUSTRESPPARITYERR |
+- INFINIPATH_HWE_HTCBUSIREQPARITYERR |
+- INFINIPATH_HWE_RXDSYNCMEMPARITYERR |
+- INFINIPATH_HWE_MEMBISTFAILED |
+- INFINIPATH_HWE_COREPLL_FBSLIP |
+- INFINIPATH_HWE_COREPLL_RFSLIP |
+- INFINIPATH_HWE_HTBPLL_FBSLIP |
+- INFINIPATH_HWE_HTBPLL_RFSLIP |
+- INFINIPATH_HWE_HTAPLL_FBSLIP |
+- INFINIPATH_HWE_HTAPLL_RFSLIP |
+- INFINIPATH_HWE_SERDESPLLFAILED |
+- INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
+- INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
+-
+- infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+- infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+-}
+-
+-/**
+- * ipath_ht_init_hwerrors - enable hardware errors
+- * @dd: the infinipath device
+- *
+- * now that we have finished initializing everything that might reasonably
+- * cause a hardware error, and cleared those errors bits as they occur,
+- * we can enable hardware errors in the mask (potentially enabling
+- * freeze mode), and enable hardware errors as errors (along with
+- * everything else) in errormask
+- */
+-static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
+-{
+- ipath_err_t val;
+- u64 extsval;
+-
+- extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
+-
+- if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
+- ipath_dev_err(dd, "MemBIST did not complete!\n");
+-
+- ipath_check_htlink(dd);
+-
+- /* barring bugs, all hwerrors become interrupts, which can */
+- val = -1LL;
+- /* don't look at crc lane1 if 8 bit */
+- if (dd->ipath_flags & IPATH_8BIT_IN_HT0)
+- val &= ~infinipath_hwe_htclnkabyte1crcerr;
+- /* don't look at crc lane1 if 8 bit */
+- if (dd->ipath_flags & IPATH_8BIT_IN_HT1)
+- val &= ~infinipath_hwe_htclnkbbyte1crcerr;
+-
+- /*
+- * disable RXDSYNCMEMPARITY because external serdes is unused,
+- * and therefore the logic will never be used or initialized,
+- * and uninitialized state will normally result in this error
+- * being asserted. Similarly for the external serdess pll
+- * lock signal.
+- */
+- val &= ~(INFINIPATH_HWE_SERDESPLLFAILED |
+- INFINIPATH_HWE_RXDSYNCMEMPARITYERR);
+-
+- /*
+- * Disable MISCERR4 because of an inversion in the HT core
+- * logic checking for errors that cause this bit to be set.
+- * The errata can also cause the protocol error bit to be set
+- * in the HT config space linkerror register(s).
+- */
+- val &= ~INFINIPATH_HWE_HTCMISCERR4;
+-
+- /*
+- * PLL ignored because MDIO interface has a logic problem
+- * for reads, on Comstock and Ponderosa. BRINGUP
+- */
+- if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
+- val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
+- dd->ipath_hwerrmask = val;
+-}
+-
+-/**
+- * ipath_ht_bringup_serdes - bring up the serdes
+- * @dd: the infinipath device
+- */
+-static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
+-{
+- u64 val, config1;
+- int ret = 0, change = 0;
+-
+- ipath_dbg("Trying to bringup serdes\n");
+-
+- if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
+- INFINIPATH_HWE_SERDESPLLFAILED)
+- {
+- ipath_dbg("At start, serdes PLL failed bit set in "
+- "hwerrstatus, clearing and continuing\n");
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
+- INFINIPATH_HWE_SERDESPLLFAILED);
+- }
+-
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
+- config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
+-
+- ipath_cdbg(VERBOSE, "Initial serdes status is config0=%llx "
+- "config1=%llx, sstatus=%llx xgxs %llx\n",
+- (unsigned long long) val, (unsigned long long) config1,
+- (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
+- (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
+-
+- /* force reset on */
+- val |= INFINIPATH_SERDC0_RESET_PLL
+- /* | INFINIPATH_SERDC0_RESET_MASK */
+- ;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
+- udelay(15); /* need pll reset set at least for a bit */
+-
+- if (val & INFINIPATH_SERDC0_RESET_PLL) {
+- u64 val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL;
+- /* set lane resets, and tx idle, during pll reset */
+- val2 |= INFINIPATH_SERDC0_RESET_MASK |
+- INFINIPATH_SERDC0_TXIDLE;
+- ipath_cdbg(VERBOSE, "Clearing serdes PLL reset (writing "
+- "%llx)\n", (unsigned long long) val2);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,
+- val2);
+- /*
+- * be sure chip saw it
+- */
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+- /*
+- * need pll reset clear at least 11 usec before lane
+- * resets cleared; give it a few more
+- */
+- udelay(15);
+- val = val2; /* for check below */
+- }
+-
+- if (val & (INFINIPATH_SERDC0_RESET_PLL |
+- INFINIPATH_SERDC0_RESET_MASK |
+- INFINIPATH_SERDC0_TXIDLE)) {
+- val &= ~(INFINIPATH_SERDC0_RESET_PLL |
+- INFINIPATH_SERDC0_RESET_MASK |
+- INFINIPATH_SERDC0_TXIDLE);
+- /* clear them */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,
+- val);
+- }
+-
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+- if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
+- INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
+- val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
+- INFINIPATH_XGXS_MDIOADDR_SHIFT);
+- /*
+- * we use address 3
+- */
+- val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
+- change = 1;
+- }
+- if (val & INFINIPATH_XGXS_RESET) {
+- /* normally true after boot */
+- val &= ~INFINIPATH_XGXS_RESET;
+- change = 1;
+- }
+- if (change)
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+-
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
+-
+- /* clear current and de-emphasis bits */
+- config1 &= ~0x0ffffffff00ULL;
+- /* set current to 20ma */
+- config1 |= 0x00000000000ULL;
+- /* set de-emphasis to -5.68dB */
+- config1 |= 0x0cccc000000ULL;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1);
+-
+- ipath_cdbg(VERBOSE, "After setup: serdes status is config0=%llx "
+- "config1=%llx, sstatus=%llx xgxs %llx\n",
+- (unsigned long long) val, (unsigned long long) config1,
+- (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
+- (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
+-
+- if (!ipath_waitfor_mdio_cmdready(dd)) {
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
+- ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
+- IPATH_MDIO_CTRL_XGXS_REG_8,
+- 0));
+- if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
+- IPATH_MDIO_DATAVALID, &val))
+- ipath_dbg("Never got MDIO data for XGXS status "
+- "read\n");
+- else
+- ipath_cdbg(VERBOSE, "MDIO Read reg8, "
+- "'bank' 31 %x\n", (u32) val);
+- } else
+- ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
+-
+- return ret; /* for now, say we always succeeded */
+-}
+-
+-/**
+- * ipath_ht_quiet_serdes - set serdes to txidle
+- * @dd: the infinipath device
+- * driver is being unloaded
+- */
+-static void ipath_ht_quiet_serdes(struct ipath_devdata *dd)
+-{
+- u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
+-
+- val |= INFINIPATH_SERDC0_TXIDLE;
+- ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
+- (unsigned long long) val);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
+-}
+-
+-static int ipath_ht_intconfig(struct ipath_devdata *dd)
+-{
+- int ret;
+-
+- if (!dd->ipath_intconfig) {
+- ipath_dev_err(dd, "No interrupts enabled, couldn't setup "
+- "interrupt address\n");
+- ret = 1;
+- goto bail;
+- }
+-
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig,
+- dd->ipath_intconfig); /* interrupt address */
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-/**
+- * ipath_pe_put_tid - write a TID in chip
+- * @dd: the infinipath device
+- * @tidptr: pointer to the expected TID (in chip) to udpate
+- * @tidtype: 0 for eager, 1 for expected
+- * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
+- *
+- * This exists as a separate routine to allow for special locking etc.
+- * It's used for both the full cleanup on exit, as well as the normal
+- * setup and teardown.
+- */
+-static void ipath_ht_put_tid(struct ipath_devdata *dd,
+- u64 __iomem *tidptr, u32 type,
+- unsigned long pa)
+-{
+- if (pa != dd->ipath_tidinvalid) {
+- if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) {
+- dev_info(&dd->pcidev->dev,
+- "physaddr %lx has more than "
+- "40 bits, using only 40!!!\n", pa);
+- pa &= INFINIPATH_RT_ADDR_MASK;
+- }
+- if (type == 0)
+- pa |= dd->ipath_tidtemplate;
+- else {
+- /* in words (fixed, full page). */
+- u64 lenvalid = PAGE_SIZE >> 2;
+- lenvalid <<= INFINIPATH_RT_BUFSIZE_SHIFT;
+- pa |= lenvalid | INFINIPATH_RT_VALID;
+- }
+- }
+- if (dd->ipath_kregbase)
+- writeq(pa, tidptr);
+-}
+-
+-/**
+- * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager
+- * @dd: the infinipath device
+- * @port: the port
+- *
+- * Used from ipath_close(), and at chip initialization.
+- */
+-static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port)
+-{
+- u64 __iomem *tidbase;
+- int i;
+-
+- if (!dd->ipath_kregbase)
+- return;
+-
+- ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
+-
+- /*
+- * need to invalidate all of the expected TID entries for this
+- * port, so we don't have valid entries that might somehow get
+- * used (early in next use of this port, or through some bug)
+- */
+- tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
+- dd->ipath_rcvtidbase +
+- port * dd->ipath_rcvtidcnt *
+- sizeof(*tidbase));
+- for (i = 0; i < dd->ipath_rcvtidcnt; i++)
+- ipath_ht_put_tid(dd, &tidbase[i], 1, dd->ipath_tidinvalid);
+-
+- tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
+- dd->ipath_rcvegrbase +
+- port * dd->ipath_rcvegrcnt *
+- sizeof(*tidbase));
+-
+- for (i = 0; i < dd->ipath_rcvegrcnt; i++)
+- ipath_ht_put_tid(dd, &tidbase[i], 0, dd->ipath_tidinvalid);
+-}
+-
+-/**
+- * ipath_ht_tidtemplate - setup constants for TID updates
+- * @dd: the infinipath device
+- *
+- * We setup stuff that we use a lot, to avoid calculating each time
+- */
+-static void ipath_ht_tidtemplate(struct ipath_devdata *dd)
+-{
+- dd->ipath_tidtemplate = dd->ipath_ibmaxlen >> 2;
+- dd->ipath_tidtemplate <<= INFINIPATH_RT_BUFSIZE_SHIFT;
+- dd->ipath_tidtemplate |= INFINIPATH_RT_VALID;
+-
+- /*
+- * work around chip errata bug 7358, by marking invalid tids
+- * as having max length
+- */
+- dd->ipath_tidinvalid = (-1LL & INFINIPATH_RT_BUFSIZE_MASK) <<
+- INFINIPATH_RT_BUFSIZE_SHIFT;
+-}
+-
+-static int ipath_ht_early_init(struct ipath_devdata *dd)
+-{
+- u32 __iomem *piobuf;
+- u32 pioincr, val32, egrsize;
+- int i;
+-
+- /*
+- * one cache line; long IB headers will spill over into received
+- * buffer
+- */
+- dd->ipath_rcvhdrentsize = 16;
+- dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
+-
+- /*
+- * For HT-400, we allocate a somewhat overly large eager buffer,
+- * such that we can guarantee that we can receive the largest
+- * packet that we can send out. To truly support a 4KB MTU,
+- * we need to bump this to a large value. To date, other than
+- * testing, we have never encountered an HCA that can really
+- * send 4KB MTU packets, so we do not handle that (we'll get
+- * errors interrupts if we ever see one).
+- */
+- dd->ipath_rcvegrbufsize = dd->ipath_piosize2k;
+- egrsize = dd->ipath_rcvegrbufsize;
+-
+- /*
+- * the min() check here is currently a nop, but it may not
+- * always be, depending on just how we do ipath_rcvegrbufsize
+- */
+- dd->ipath_ibmaxlen = min(dd->ipath_piosize2k,
+- dd->ipath_rcvegrbufsize);
+- dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
+- ipath_ht_tidtemplate(dd);
+-
+- /*
+- * zero all the TID entries at startup. We do this for sanity,
+- * in case of a previous driver crash of some kind, and also
+- * because the chip powers up with these memories in an unknown
+- * state. Use portcnt, not cfgports, since this is for the
+- * full chip, not for current (possibly different) configuration
+- * value.
+- * Chip Errata bug 6447
+- */
+- for (val32 = 0; val32 < dd->ipath_portcnt; val32++)
+- ipath_ht_clear_tids(dd, val32);
+-
+- /*
+- * write the pbc of each buffer, to be sure it's initialized, then
+- * cancel all the buffers, and also abort any packets that might
+- * have been in flight for some reason (the latter is for driver
+- * unload/reload, but isn't a bad idea at first init). PIO send
+- * isn't enabled at this point, so there is no danger of sending
+- * these out on the wire.
+- * Chip Errata bug 6610
+- */
+- piobuf = (u32 __iomem *) (((char __iomem *)(dd->ipath_kregbase)) +
+- dd->ipath_piobufbase);
+- pioincr = dd->ipath_palign / sizeof(*piobuf);
+- for (i = 0; i < dd->ipath_piobcnt2k; i++) {
+- /*
+- * reasonable word count, just to init pbc
+- */
+- writel(16, piobuf);
+- piobuf += pioincr;
+- }
+- /*
+- * self-clearing
+- */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+- INFINIPATH_S_ABORT);
+-
+- ipath_get_eeprom_info(dd);
+- if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
+- dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
+- /*
+- * Later production HT-460 has same changes as HT-465, so
+- * can use GPIO interrupts. They have serial #'s starting
+- * with 128, rather than 112.
+- */
+- dd->ipath_flags |= IPATH_GPIO_INTR;
+- dd->ipath_flags &= ~IPATH_POLL_RX_INTR;
+- }
+- return 0;
+-}
+-
+-/**
+- * ipath_init_ht_get_base_info - set chip-specific flags for user code
+- * @dd: the infinipath device
+- * @kbase: ipath_base_info pointer
+- *
+- * We set the PCIE flag because the lower bandwidth on PCIe vs
+- * HyperTransport can affect some user packet algorithims.
+- */
+-static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
+-{
+- struct ipath_base_info *kinfo = kbase;
+-
+- kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |
+- IPATH_RUNTIME_RCVHDR_COPY;
+-
+- return 0;
+-}
+-
+-/**
+- * ipath_init_ht400_funcs - set up the chip-specific function pointers
+- * @dd: the infinipath device
+- *
+- * This is global, and is called directly at init to set up the
+- * chip-specific function pointers for later use.
+- */
+-void ipath_init_ht400_funcs(struct ipath_devdata *dd)
+-{
+- dd->ipath_f_intrsetup = ipath_ht_intconfig;
+- dd->ipath_f_bus = ipath_setup_ht_config;
+- dd->ipath_f_reset = ipath_setup_ht_reset;
+- dd->ipath_f_get_boardname = ipath_ht_boardname;
+- dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors;
+- dd->ipath_f_early_init = ipath_ht_early_init;
+- dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors;
+- dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes;
+- dd->ipath_f_bringup_serdes = ipath_ht_bringup_serdes;
+- dd->ipath_f_clear_tids = ipath_ht_clear_tids;
+- dd->ipath_f_put_tid = ipath_ht_put_tid;
+- dd->ipath_f_cleanup = ipath_setup_ht_cleanup;
+- dd->ipath_f_setextled = ipath_setup_ht_setextled;
+- dd->ipath_f_get_base_info = ipath_ht_get_base_info;
+-
+- /*
+- * initialize chip-specific variables
+- */
+- dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
+-
+- /*
+- * setup the register offsets, since they are different for each
+- * chip
+- */
+- dd->ipath_kregs = &ipath_ht_kregs;
+- dd->ipath_cregs = &ipath_ht_cregs;
+-
+- /*
+- * do very early init that is needed before ipath_f_bus is
+- * called
+- */
+- ipath_init_ht_variables();
+-}
+diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
+new file mode 100644
+index 0000000..9e4e8d4
+--- /dev/null
++++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
+@@ -0,0 +1,1619 @@
++/*
++ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
++ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
++ * 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.
++ */
++
++/*
++ * This file contains all of the code that is specific to the InfiniPath
++ * HT chip.
++ */
++
++#include <linux/pci.h>
++#include <linux/delay.h>
++
++#include "ipath_kernel.h"
++#include "ipath_registers.h"
++
++/*
++ * This lists the InfiniPath registers, in the actual chip layout.
++ * This structure should never be directly accessed.
++ *
++ * The names are in InterCap form because they're taken straight from
++ * the chip specification. Since they're only used in this file, they
++ * don't pollute the rest of the source.
++*/
++
++struct _infinipath_do_not_use_kernel_regs {
++ unsigned long long Revision;
++ unsigned long long Control;
++ unsigned long long PageAlign;
++ unsigned long long PortCnt;
++ unsigned long long DebugPortSelect;
++ unsigned long long DebugPort;
++ unsigned long long SendRegBase;
++ unsigned long long UserRegBase;
++ unsigned long long CounterRegBase;
++ unsigned long long Scratch;
++ unsigned long long ReservedMisc1;
++ unsigned long long InterruptConfig;
++ unsigned long long IntBlocked;
++ unsigned long long IntMask;
++ unsigned long long IntStatus;
++ unsigned long long IntClear;
++ unsigned long long ErrorMask;
++ unsigned long long ErrorStatus;
++ unsigned long long ErrorClear;
++ unsigned long long HwErrMask;
++ unsigned long long HwErrStatus;
++ unsigned long long HwErrClear;
++ unsigned long long HwDiagCtrl;
++ unsigned long long MDIO;
++ unsigned long long IBCStatus;
++ unsigned long long IBCCtrl;
++ unsigned long long ExtStatus;
++ unsigned long long ExtCtrl;
++ unsigned long long GPIOOut;
++ unsigned long long GPIOMask;
++ unsigned long long GPIOStatus;
++ unsigned long long GPIOClear;
++ unsigned long long RcvCtrl;
++ unsigned long long RcvBTHQP;
++ unsigned long long RcvHdrSize;
++ unsigned long long RcvHdrCnt;
++ unsigned long long RcvHdrEntSize;
++ unsigned long long RcvTIDBase;
++ unsigned long long RcvTIDCnt;
++ unsigned long long RcvEgrBase;
++ unsigned long long RcvEgrCnt;
++ unsigned long long RcvBufBase;
++ unsigned long long RcvBufSize;
++ unsigned long long RxIntMemBase;
++ unsigned long long RxIntMemSize;
++ unsigned long long RcvPartitionKey;
++ unsigned long long ReservedRcv[10];
++ unsigned long long SendCtrl;
++ unsigned long long SendPIOBufBase;
++ unsigned long long SendPIOSize;
++ unsigned long long SendPIOBufCnt;
++ unsigned long long SendPIOAvailAddr;
++ unsigned long long TxIntMemBase;
++ unsigned long long TxIntMemSize;
++ unsigned long long ReservedSend[9];
++ unsigned long long SendBufferError;
++ unsigned long long SendBufferErrorCONT1;
++ unsigned long long SendBufferErrorCONT2;
++ unsigned long long SendBufferErrorCONT3;
++ unsigned long long ReservedSBE[4];
++ unsigned long long RcvHdrAddr0;
++ unsigned long long RcvHdrAddr1;
++ unsigned long long RcvHdrAddr2;
++ unsigned long long RcvHdrAddr3;
++ unsigned long long RcvHdrAddr4;
++ unsigned long long RcvHdrAddr5;
++ unsigned long long RcvHdrAddr6;
++ unsigned long long RcvHdrAddr7;
++ unsigned long long RcvHdrAddr8;
++ unsigned long long ReservedRHA[7];
++ unsigned long long RcvHdrTailAddr0;
++ unsigned long long RcvHdrTailAddr1;
++ unsigned long long RcvHdrTailAddr2;
++ unsigned long long RcvHdrTailAddr3;
++ unsigned long long RcvHdrTailAddr4;
++ unsigned long long RcvHdrTailAddr5;
++ unsigned long long RcvHdrTailAddr6;
++ unsigned long long RcvHdrTailAddr7;
++ unsigned long long RcvHdrTailAddr8;
++ unsigned long long ReservedRHTA[7];
++ unsigned long long Sync; /* Software only */
++ unsigned long long Dump; /* Software only */
++ unsigned long long SimVer; /* Software only */
++ unsigned long long ReservedSW[5];
++ unsigned long long SerdesConfig0;
++ unsigned long long SerdesConfig1;
++ unsigned long long SerdesStatus;
++ unsigned long long XGXSConfig;
++ unsigned long long ReservedSW2[4];
++};
++
++#define IPATH_KREG_OFFSET(field) (offsetof(struct \
++ _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
++#define IPATH_CREG_OFFSET(field) (offsetof( \
++ struct infinipath_counters, field) / sizeof(u64))
++
++static const struct ipath_kregs ipath_ht_kregs = {
++ .kr_control = IPATH_KREG_OFFSET(Control),
++ .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
++ .kr_debugport = IPATH_KREG_OFFSET(DebugPort),
++ .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
++ .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
++ .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
++ .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
++ .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
++ .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
++ .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
++ .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
++ .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
++ .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
++ .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
++ .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
++ .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
++ .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
++ .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
++ .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
++ .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
++ .kr_intclear = IPATH_KREG_OFFSET(IntClear),
++ .kr_interruptconfig = IPATH_KREG_OFFSET(InterruptConfig),
++ .kr_intmask = IPATH_KREG_OFFSET(IntMask),
++ .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
++ .kr_mdio = IPATH_KREG_OFFSET(MDIO),
++ .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
++ .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
++ .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
++ .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
++ .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
++ .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
++ .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
++ .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
++ .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
++ .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
++ .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
++ .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
++ .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
++ .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
++ .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
++ .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
++ .kr_revision = IPATH_KREG_OFFSET(Revision),
++ .kr_scratch = IPATH_KREG_OFFSET(Scratch),
++ .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
++ .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
++ .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
++ .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
++ .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
++ .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
++ .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
++ .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
++ .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
++ .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
++ .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
++ .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
++ .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
++ .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
++ /*
++ * These should not be used directly via ipath_read_kreg64(),
++ * use them with ipath_read_kreg64_port(),
++ */
++ .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
++ .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0)
++};
++
++static const struct ipath_cregs ipath_ht_cregs = {
++ .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
++ .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
++ .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
++ .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
++ .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
++ .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
++ .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
++ .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
++ .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
++ .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
++ .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
++ .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
++ /* calc from Reg_CounterRegBase + offset */
++ .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
++ .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
++ .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
++ .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
++ .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
++ .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
++ .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
++ .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
++ .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
++ .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
++ .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
++ .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
++ .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
++ .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
++ .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
++ .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
++ .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
++ .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
++ .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
++ .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
++ .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
++};
++
++/* kr_intstatus, kr_intclear, kr_intmask bits */
++#define INFINIPATH_I_RCVURG_MASK ((1U<<9)-1)
++#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<9)-1)
++
++/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
++#define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0
++#define INFINIPATH_HWE_HTCMEMPARITYERR_MASK 0x3FFFFFULL
++#define INFINIPATH_HWE_HTCLNKABYTE0CRCERR 0x0000000000800000ULL
++#define INFINIPATH_HWE_HTCLNKABYTE1CRCERR 0x0000000001000000ULL
++#define INFINIPATH_HWE_HTCLNKBBYTE0CRCERR 0x0000000002000000ULL
++#define INFINIPATH_HWE_HTCLNKBBYTE1CRCERR 0x0000000004000000ULL
++#define INFINIPATH_HWE_HTCMISCERR4 0x0000000008000000ULL
++#define INFINIPATH_HWE_HTCMISCERR5 0x0000000010000000ULL
++#define INFINIPATH_HWE_HTCMISCERR6 0x0000000020000000ULL
++#define INFINIPATH_HWE_HTCMISCERR7 0x0000000040000000ULL
++#define INFINIPATH_HWE_HTCBUSTREQPARITYERR 0x0000000080000000ULL
++#define INFINIPATH_HWE_HTCBUSTRESPPARITYERR 0x0000000100000000ULL
++#define INFINIPATH_HWE_HTCBUSIREQPARITYERR 0x0000000200000000ULL
++#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL
++#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL
++#define INFINIPATH_HWE_HTBPLL_FBSLIP 0x0200000000000000ULL
++#define INFINIPATH_HWE_HTBPLL_RFSLIP 0x0400000000000000ULL
++#define INFINIPATH_HWE_HTAPLL_FBSLIP 0x0800000000000000ULL
++#define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL
++#define INFINIPATH_HWE_SERDESPLLFAILED 0x2000000000000000ULL
++
++/* kr_extstatus bits */
++#define INFINIPATH_EXTS_FREQSEL 0x2
++#define INFINIPATH_EXTS_SERDESSEL 0x4
++#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000
++#define INFINIPATH_EXTS_MEMBIST_CORRECT 0x0000000000008000
++
++/*
++ * masks and bits that are different in different chips, or present only
++ * in one
++ */
++static const ipath_err_t infinipath_hwe_htcmemparityerr_mask =
++ INFINIPATH_HWE_HTCMEMPARITYERR_MASK;
++static const ipath_err_t infinipath_hwe_htcmemparityerr_shift =
++ INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT;
++
++static const ipath_err_t infinipath_hwe_htclnkabyte0crcerr =
++ INFINIPATH_HWE_HTCLNKABYTE0CRCERR;
++static const ipath_err_t infinipath_hwe_htclnkabyte1crcerr =
++ INFINIPATH_HWE_HTCLNKABYTE1CRCERR;
++static const ipath_err_t infinipath_hwe_htclnkbbyte0crcerr =
++ INFINIPATH_HWE_HTCLNKBBYTE0CRCERR;
++static const ipath_err_t infinipath_hwe_htclnkbbyte1crcerr =
++ INFINIPATH_HWE_HTCLNKBBYTE1CRCERR;
++
++#define _IPATH_GPIO_SDA_NUM 1
++#define _IPATH_GPIO_SCL_NUM 0
++
++#define IPATH_GPIO_SDA \
++ (1ULL << (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
++#define IPATH_GPIO_SCL \
++ (1ULL << (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
++
++/* keep the code below somewhat more readonable; not used elsewhere */
++#define _IPATH_HTLINK0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
++ infinipath_hwe_htclnkabyte1crcerr)
++#define _IPATH_HTLINK1_CRCBITS (infinipath_hwe_htclnkbbyte0crcerr | \
++ infinipath_hwe_htclnkbbyte1crcerr)
++#define _IPATH_HTLANE0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
++ infinipath_hwe_htclnkbbyte0crcerr)
++#define _IPATH_HTLANE1_CRCBITS (infinipath_hwe_htclnkabyte1crcerr | \
++ infinipath_hwe_htclnkbbyte1crcerr)
++
++static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
++ char *msg, size_t msgl)
++{
++ char bitsmsg[64];
++ ipath_err_t crcbits = hwerrs &
++ (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS);
++ /* don't check if 8bit HT */
++ if (dd->ipath_flags & IPATH_8BIT_IN_HT0)
++ crcbits &= ~infinipath_hwe_htclnkabyte1crcerr;
++ /* don't check if 8bit HT */
++ if (dd->ipath_flags & IPATH_8BIT_IN_HT1)
++ crcbits &= ~infinipath_hwe_htclnkbbyte1crcerr;
++ /*
++ * we'll want to ignore link errors on link that is
++ * not in use, if any. For now, complain about both
++ */
++ if (crcbits) {
++ u16 ctrl0, ctrl1;
++ snprintf(bitsmsg, sizeof bitsmsg,
++ "[HT%s lane %s CRC (%llx); powercycle to completely clear]",
++ !(crcbits & _IPATH_HTLINK1_CRCBITS) ?
++ "0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
++ ? "1 (B)" : "0+1 (A+B)"),
++ !(crcbits & _IPATH_HTLANE1_CRCBITS) ? "0"
++ : (!(crcbits & _IPATH_HTLANE0_CRCBITS) ? "1" :
++ "0+1"), (unsigned long long) crcbits);
++ strlcat(msg, bitsmsg, msgl);
++
++ /*
++ * print extra info for debugging. slave/primary
++ * config word 4, 8 (link control 0, 1)
++ */
++
++ if (pci_read_config_word(dd->pcidev,
++ dd->ipath_ht_slave_off + 0x4,
++ &ctrl0))
++ dev_info(&dd->pcidev->dev, "Couldn't read "
++ "linkctrl0 of slave/primary "
++ "config block\n");
++ else if (!(ctrl0 & 1 << 6))
++ /* not if EOC bit set */
++ ipath_dbg("HT linkctrl0 0x%x%s%s\n", ctrl0,
++ ((ctrl0 >> 8) & 7) ? " CRC" : "",
++ ((ctrl0 >> 4) & 1) ? "linkfail" :
++ "");
++ if (pci_read_config_word(dd->pcidev,
++ dd->ipath_ht_slave_off + 0x8,
++ &ctrl1))
++ dev_info(&dd->pcidev->dev, "Couldn't read "
++ "linkctrl1 of slave/primary "
++ "config block\n");
++ else if (!(ctrl1 & 1 << 6))
++ /* not if EOC bit set */
++ ipath_dbg("HT linkctrl1 0x%x%s%s\n", ctrl1,
++ ((ctrl1 >> 8) & 7) ? " CRC" : "",
++ ((ctrl1 >> 4) & 1) ? "linkfail" :
++ "");
++
++ /* disable until driver reloaded */
++ dd->ipath_hwerrmask &= ~crcbits;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ ipath_dbg("HT crc errs: %s\n", msg);
++ } else
++ ipath_dbg("ignoring HT crc errors 0x%llx, "
++ "not in use\n", (unsigned long long)
++ (hwerrs & (_IPATH_HTLINK0_CRCBITS |
++ _IPATH_HTLINK1_CRCBITS)));
++}
++
++/* 6110 specific hardware errors... */
++static const struct ipath_hwerror_msgs ipath_6110_hwerror_msgs[] = {
++ INFINIPATH_HWE_MSG(HTCBUSIREQPARITYERR, "HTC Ireq Parity"),
++ INFINIPATH_HWE_MSG(HTCBUSTREQPARITYERR, "HTC Treq Parity"),
++ INFINIPATH_HWE_MSG(HTCBUSTRESPPARITYERR, "HTC Tresp Parity"),
++ INFINIPATH_HWE_MSG(HTCMISCERR5, "HT core Misc5"),
++ INFINIPATH_HWE_MSG(HTCMISCERR6, "HT core Misc6"),
++ INFINIPATH_HWE_MSG(HTCMISCERR7, "HT core Misc7"),
++ INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
++ INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
++};
++
++/**
++ * ipath_ht_handle_hwerrors - display hardware errors.
++ * @dd: the infinipath device
++ * @msg: the output buffer
++ * @msgl: the size of the output buffer
++ *
++ * Use same msg buffer as regular errors to avoid excessive stack
++ * use. Most hardware errors are catastrophic, but for right now,
++ * we'll print them and continue. We reuse the same message buffer as
++ * ipath_handle_errors() to avoid excessive stack usage.
++ */
++static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
++ size_t msgl)
++{
++ ipath_err_t hwerrs;
++ u32 bits, ctrl;
++ int isfatal = 0;
++ char bitsmsg[64];
++
++ hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
++
++ if (!hwerrs) {
++ ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
++ /*
++ * better than printing cofusing messages
++ * This seems to be related to clearing the crc error, or
++ * the pll error during init.
++ */
++ goto bail;
++ } else if (hwerrs == -1LL) {
++ ipath_dev_err(dd, "Read of hardware error status failed "
++ "(all bits set); ignoring\n");
++ goto bail;
++ }
++ ipath_stats.sps_hwerrs++;
++
++ /* Always clear the error status register, except MEMBISTFAIL,
++ * regardless of whether we continue or stop using the chip.
++ * We want that set so we know it failed, even across driver reload.
++ * We'll still ignore it in the hwerrmask. We do this partly for
++ * diagnostics, but also for support */
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
++ hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
++
++ hwerrs &= dd->ipath_hwerrmask;
++
++ /*
++ * make sure we get this much out, unless told to be quiet,
++ * or it's occurred within the last 5 seconds
++ */
++ if ((hwerrs & ~(dd->ipath_lasthwerror |
++ ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
++ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
++ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
++ (ipath_debug & __IPATH_VERBDBG))
++ dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
++ "(cleared)\n", (unsigned long long) hwerrs);
++ dd->ipath_lasthwerror |= hwerrs;
++
++ if (hwerrs & ~dd->ipath_hwe_bitsextant)
++ ipath_dev_err(dd, "hwerror interrupt with unknown errors "
++ "%llx set\n", (unsigned long long)
++ (hwerrs & ~dd->ipath_hwe_bitsextant));
++
++ ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
++ if (ctrl & INFINIPATH_C_FREEZEMODE) {
++ /*
++ * parity errors in send memory are recoverable,
++ * just cancel the send (if indicated in * sendbuffererror),
++ * count the occurrence, unfreeze (if no other handled
++ * hardware error bits are set), and continue. They can
++ * occur if a processor speculative read is done to the PIO
++ * buffer while we are sending a packet, for example.
++ */
++ if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
++ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
++ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
++ ipath_stats.sps_txeparity++;
++ ipath_dbg("Recovering from TXE parity error (%llu), "
++ "hwerrstatus=%llx\n",
++ (unsigned long long) ipath_stats.sps_txeparity,
++ (unsigned long long) hwerrs);
++ ipath_disarm_senderrbufs(dd);
++ hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
++ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
++ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
++ if (!hwerrs) { /* else leave in freeze mode */
++ ipath_write_kreg(dd,
++ dd->ipath_kregs->kr_control,
++ dd->ipath_control);
++ return;
++ }
++ }
++ if (hwerrs) {
++ /*
++ * if any set that we aren't ignoring; only
++ * make the complaint once, in case it's stuck
++ * or recurring, and we get here multiple
++ * times.
++ */
++ if (dd->ipath_flags & IPATH_INITTED) {
++ ipath_dev_err(dd, "Fatal Hardware Error (freeze "
++ "mode), no longer usable, SN %.16s\n",
++ dd->ipath_serial);
++ isfatal = 1;
++ }
++ *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
++ /* mark as having had error */
++ *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
++ /*
++ * mark as not usable, at a minimum until driver
++ * is reloaded, probably until reboot, since no
++ * other reset is possible.
++ */
++ dd->ipath_flags &= ~IPATH_INITTED;
++ } else {
++ ipath_dbg("Clearing freezemode on ignored hardware "
++ "error\n");
++ ctrl &= ~INFINIPATH_C_FREEZEMODE;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
++ ctrl);
++ }
++ }
++
++ *msg = '\0';
++
++ /*
++ * may someday want to decode into which bits are which
++ * functional area for parity errors, etc.
++ */
++ if (hwerrs & (infinipath_hwe_htcmemparityerr_mask
++ << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT)) {
++ bits = (u32) ((hwerrs >>
++ INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) &
++ INFINIPATH_HWE_HTCMEMPARITYERR_MASK);
++ snprintf(bitsmsg, sizeof bitsmsg, "[HTC Parity Errs %x] ",
++ bits);
++ strlcat(msg, bitsmsg, msgl);
++ }
++
++ ipath_format_hwerrors(hwerrs,
++ ipath_6110_hwerror_msgs,
++ sizeof(ipath_6110_hwerror_msgs) /
++ sizeof(ipath_6110_hwerror_msgs[0]),
++ msg, msgl);
++
++ if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
++ hwerr_crcbits(dd, hwerrs, msg, msgl);
++
++ if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
++ strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
++ msgl);
++ /* ignore from now on, so disable until driver reloaded */
++ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ }
++#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
++ INFINIPATH_HWE_COREPLL_RFSLIP | \
++ INFINIPATH_HWE_HTBPLL_FBSLIP | \
++ INFINIPATH_HWE_HTBPLL_RFSLIP | \
++ INFINIPATH_HWE_HTAPLL_FBSLIP | \
++ INFINIPATH_HWE_HTAPLL_RFSLIP)
++
++ if (hwerrs & _IPATH_PLL_FAIL) {
++ snprintf(bitsmsg, sizeof bitsmsg,
++ "[PLL failed (%llx), InfiniPath hardware unusable]",
++ (unsigned long long) (hwerrs & _IPATH_PLL_FAIL));
++ strlcat(msg, bitsmsg, msgl);
++ /* ignore from now on, so disable until driver reloaded */
++ dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ }
++
++ if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
++ /*
++ * If it occurs, it is left masked since the eternal
++ * interface is unused
++ */
++ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ }
++
++ ipath_dev_err(dd, "%s hardware error\n", msg);
++ if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
++ /*
++ * for status file; if no trailing brace is copied,
++ * we'll know it was truncated.
++ */
++ snprintf(dd->ipath_freezemsg,
++ dd->ipath_freezelen, "{%s}", msg);
++
++bail:;
++}
++
++/**
++ * ipath_ht_boardname - fill in the board name
++ * @dd: the infinipath device
++ * @name: the output buffer
++ * @namelen: the size of the output buffer
++ *
++ * fill in the board name, based on the board revision register
++ */
++static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
++ size_t namelen)
++{
++ char *n = NULL;
++ u8 boardrev = dd->ipath_boardrev;
++ int ret;
++
++ switch (boardrev) {
++ case 4: /* Ponderosa is one of the bringup boards */
++ n = "Ponderosa";
++ break;
++ case 5:
++ /*
++ * original production board; two production levels, with
++ * different serial number ranges. See ipath_ht_early_init() for
++ * case where we enable IPATH_GPIO_INTR for later serial # range.
++ */
++ n = "InfiniPath_QHT7040";
++ break;
++ case 6:
++ n = "OEM_Board_3";
++ break;
++ case 7:
++ /* small form factor production board */
++ n = "InfiniPath_QHT7140";
++ break;
++ case 8:
++ n = "LS/X-1";
++ break;
++ case 9: /* Comstock bringup test board */
++ n = "Comstock";
++ break;
++ case 10:
++ n = "OEM_Board_2";
++ break;
++ case 11:
++ n = "InfiniPath_HT-470"; /* obsoleted */
++ break;
++ case 12:
++ n = "OEM_Board_4";
++ break;
++ default: /* don't know, just print the number */
++ ipath_dev_err(dd, "Don't yet know about board "
++ "with ID %u\n", boardrev);
++ snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
++ boardrev);
++ break;
++ }
++ if (n)
++ snprintf(name, namelen, "%s", n);
++
++ if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {
++ /*
++ * This version of the driver only supports Rev 3.2 and 3.3
++ */
++ ipath_dev_err(dd,
++ "Unsupported InfiniPath hardware revision %u.%u!\n",
++ dd->ipath_majrev, dd->ipath_minrev);
++ ret = 1;
++ goto bail;
++ }
++ /*
++ * pkt/word counters are 32 bit, and therefore wrap fast enough
++ * that we snapshot them from a timer, and maintain 64 bit shadow
++ * copies
++ */
++ dd->ipath_flags |= IPATH_32BITCOUNTERS;
++ if (dd->ipath_htspeed != 800)
++ ipath_dev_err(dd,
++ "Incorrectly configured for HT @ %uMHz\n",
++ dd->ipath_htspeed);
++ if (dd->ipath_boardrev == 7 || dd->ipath_boardrev == 11 ||
++ dd->ipath_boardrev == 6)
++ dd->ipath_flags |= IPATH_GPIO_INTR;
++ else
++ dd->ipath_flags |= IPATH_POLL_RX_INTR;
++ if (dd->ipath_boardrev == 8) { /* LS/X-1 */
++ u64 val;
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
++ if (val & INFINIPATH_EXTS_SERDESSEL) {
++ /*
++ * hardware disabled
++ *
++ * This means that the chip is hardware disabled,
++ * and will not be able to bring up the link,
++ * in any case. We special case this and abort
++ * early, to avoid later messages. We also set
++ * the DISABLED status bit
++ */
++ ipath_dbg("Unit %u is hardware-disabled\n",
++ dd->ipath_unit);
++ *dd->ipath_statusp |= IPATH_STATUS_DISABLED;
++ /* this value is handled differently */
++ ret = 2;
++ goto bail;
++ }
++ }
++ ret = 0;
++
++bail:
++ return ret;
++}
++
++static void ipath_check_htlink(struct ipath_devdata *dd)
++{
++ u8 linkerr, link_off, i;
++
++ for (i = 0; i < 2; i++) {
++ link_off = dd->ipath_ht_slave_off + i * 4 + 0xd;
++ if (pci_read_config_byte(dd->pcidev, link_off, &linkerr))
++ dev_info(&dd->pcidev->dev, "Couldn't read "
++ "linkerror%d of HT slave/primary block\n",
++ i);
++ else if (linkerr & 0xf0) {
++ ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, "
++ "clearing\n", linkerr >> 4, i);
++ /*
++ * writing the linkerr bits that are set should
++ * clear them
++ */
++ if (pci_write_config_byte(dd->pcidev, link_off,
++ linkerr))
++ ipath_dbg("Failed write to clear HT "
++ "linkerror%d\n", i);
++ if (pci_read_config_byte(dd->pcidev, link_off,
++ &linkerr))
++ dev_info(&dd->pcidev->dev,
++ "Couldn't reread linkerror%d of "
++ "HT slave/primary block\n", i);
++ else if (linkerr & 0xf0)
++ dev_info(&dd->pcidev->dev,
++ "HT linkerror%d bits 0x%x "
++ "couldn't be cleared\n",
++ i, linkerr >> 4);
++ }
++ }
++}
++
++static int ipath_setup_ht_reset(struct ipath_devdata *dd)
++{
++ ipath_dbg("No reset possible for this InfiniPath hardware\n");
++ return 0;
++}
++
++#define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */
++#define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */
++
++/*
++ * Bits 13-15 of command==0 is slave/primary block. Clear any HT CRC
++ * errors. We only bother to do this at load time, because it's OK if
++ * it happened before we were loaded (first time after boot/reset),
++ * but any time after that, it's fatal anyway. Also need to not check
++ * for for upper byte errors if we are in 8 bit mode, so figure out
++ * our width. For now, at least, also complain if it's 8 bit.
++ */
++static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev,
++ int pos, u8 cap_type)
++{
++ u8 linkwidth = 0, linkerr, link_a_b_off, link_off;
++ u16 linkctrl = 0;
++ int i;
++
++ dd->ipath_ht_slave_off = pos;
++ /* command word, master_host bit */
++ /* master host || slave */
++ if ((cap_type >> 2) & 1)
++ link_a_b_off = 4;
++ else
++ link_a_b_off = 0;
++ ipath_cdbg(VERBOSE, "HT%u (Link %c) connected to processor\n",
++ link_a_b_off ? 1 : 0,
++ link_a_b_off ? 'B' : 'A');
++
++ link_a_b_off += pos;
++
++ /*
++ * check both link control registers; clear both HT CRC sets if
++ * necessary.
++ */
++ for (i = 0; i < 2; i++) {
++ link_off = pos + i * 4 + 0x4;
++ if (pci_read_config_word(pdev, link_off, &linkctrl))
++ ipath_dev_err(dd, "Couldn't read HT link control%d "
++ "register\n", i);
++ else if (linkctrl & (0xf << 8)) {
++ ipath_cdbg(VERBOSE, "Clear linkctrl%d CRC Error "
++ "bits %x\n", i, linkctrl & (0xf << 8));
++ /*
++ * now write them back to clear the error.
++ */
++ pci_write_config_byte(pdev, link_off,
++ linkctrl & (0xf << 8));
++ }
++ }
++
++ /*
++ * As with HT CRC bits, same for protocol errors that might occur
++ * during boot.
++ */
++ for (i = 0; i < 2; i++) {
++ link_off = pos + i * 4 + 0xd;
++ if (pci_read_config_byte(pdev, link_off, &linkerr))
++ dev_info(&pdev->dev, "Couldn't read linkerror%d "
++ "of HT slave/primary block\n", i);
++ else if (linkerr & 0xf0) {
++ ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, "
++ "clearing\n", linkerr >> 4, i);
++ /*
++ * writing the linkerr bits that are set will clear
++ * them
++ */
++ if (pci_write_config_byte
++ (pdev, link_off, linkerr))
++ ipath_dbg("Failed write to clear HT "
++ "linkerror%d\n", i);
++ if (pci_read_config_byte(pdev, link_off, &linkerr))
++ dev_info(&pdev->dev, "Couldn't reread "
++ "linkerror%d of HT slave/primary "
++ "block\n", i);
++ else if (linkerr & 0xf0)
++ dev_info(&pdev->dev, "HT linkerror%d bits "
++ "0x%x couldn't be cleared\n",
++ i, linkerr >> 4);
++ }
++ }
++
++ /*
++ * this is just for our link to the host, not devices connected
++ * through tunnel.
++ */
++
++ if (pci_read_config_byte(pdev, link_a_b_off + 7, &linkwidth))
++ ipath_dev_err(dd, "Couldn't read HT link width "
++ "config register\n");
++ else {
++ u32 width;
++ switch (linkwidth & 7) {
++ case 5:
++ width = 4;
++ break;
++ case 4:
++ width = 2;
++ break;
++ case 3:
++ width = 32;
++ break;
++ case 1:
++ width = 16;
++ break;
++ case 0:
++ default: /* if wrong, assume 8 bit */
++ width = 8;
++ break;
++ }
++
++ dd->ipath_htwidth = width;
++
++ if (linkwidth != 0x11) {
++ ipath_dev_err(dd, "Not configured for 16 bit HT "
++ "(%x)\n", linkwidth);
++ if (!(linkwidth & 0xf)) {
++ ipath_dbg("Will ignore HT lane1 errors\n");
++ dd->ipath_flags |= IPATH_8BIT_IN_HT0;
++ }
++ }
++ }
++
++ /*
++ * this is just for our link to the host, not devices connected
++ * through tunnel.
++ */
++ if (pci_read_config_byte(pdev, link_a_b_off + 0xd, &linkwidth))
++ ipath_dev_err(dd, "Couldn't read HT link frequency "
++ "config register\n");
++ else {
++ u32 speed;
++ switch (linkwidth & 0xf) {
++ case 6:
++ speed = 1000;
++ break;
++ case 5:
++ speed = 800;
++ break;
++ case 4:
++ speed = 600;
++ break;
++ case 3:
++ speed = 500;
++ break;
++ case 2:
++ speed = 400;
++ break;
++ case 1:
++ speed = 300;
++ break;
++ default:
++ /*
++ * assume reserved and vendor-specific are 200...
++ */
++ case 0:
++ speed = 200;
++ break;
++ }
++ dd->ipath_htspeed = speed;
++ }
++}
++
++static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,
++ int pos)
++{
++ u32 int_handler_addr_lower;
++ u32 int_handler_addr_upper;
++ u64 ihandler;
++ u32 intvec;
++
++ /* use indirection register to get the intr handler */
++ pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10);
++ pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower);
++ pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11);
++ pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper);
++
++ ihandler = (u64) int_handler_addr_lower |
++ ((u64) int_handler_addr_upper << 32);
++
++ /*
++ * kernels with CONFIG_PCI_MSI set the vector in the irq field of
++ * struct pci_device, so we use that to program the internal
++ * interrupt register (not config space) with that value. The BIOS
++ * must still have done the basic MSI setup.
++ */
++ intvec = pdev->irq;
++ /*
++ * clear any vector bits there; normally not set but we'll overload
++ * this for some debug purposes (setting the HTC debug register
++ * value from software, rather than GPIOs), so it might be set on a
++ * driver reload.
++ */
++ ihandler &= ~0xff0000;
++ /* x86 vector goes in intrinfo[23:16] */
++ ihandler |= intvec << 16;
++ ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, "
++ "interruptconfig %llx\n", int_handler_addr_lower,
++ int_handler_addr_upper, intvec,
++ (unsigned long long) ihandler);
++
++ /* can't program yet, so save for interrupt setup */
++ dd->ipath_intconfig = ihandler;
++ /* keep going, so we find link control stuff also */
++
++ return ihandler != 0;
++}
++
++/**
++ * ipath_setup_ht_config - setup the interruptconfig register
++ * @dd: the infinipath device
++ * @pdev: the PCI device
++ *
++ * setup the interruptconfig register from the HT config info.
++ * Also clear CRC errors in HT linkcontrol, if necessary.
++ * This is done only for the real hardware. It is done before
++ * chip address space is initted, so can't touch infinipath registers
++ */
++static int ipath_setup_ht_config(struct ipath_devdata *dd,
++ struct pci_dev *pdev)
++{
++ int pos, ret = 0;
++ int ihandler = 0;
++
++ /*
++ * Read the capability info to find the interrupt info, and also
++ * handle clearing CRC errors in linkctrl register if necessary. We
++ * do this early, before we ever enable errors or hardware errors,
++ * mostly to avoid causing the chip to enter freeze mode.
++ */
++ pos = pci_find_capability(pdev, PCI_CAP_ID_HT);
++ if (!pos) {
++ ipath_dev_err(dd, "Couldn't find HyperTransport "
++ "capability; no interrupts\n");
++ ret = -ENODEV;
++ goto bail;
++ }
++ do {
++ u8 cap_type;
++
++ /* the HT capability type byte is 3 bytes after the
++ * capability byte.
++ */
++ if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
++ dev_info(&pdev->dev, "Couldn't read config "
++ "command @ %d\n", pos);
++ continue;
++ }
++ if (!(cap_type & 0xE0))
++ slave_or_pri_blk(dd, pdev, pos, cap_type);
++ else if (cap_type == HT_INTR_DISC_CONFIG)
++ ihandler = set_int_handler(dd, pdev, pos);
++ } while ((pos = pci_find_next_capability(pdev, pos,
++ PCI_CAP_ID_HT)));
++
++ if (!ihandler) {
++ ipath_dev_err(dd, "Couldn't find interrupt handler in "
++ "config space\n");
++ ret = -ENODEV;
++ }
++
++bail:
++ return ret;
++}
++
++/**
++ * ipath_setup_ht_cleanup - clean up any per-chip chip-specific stuff
++ * @dd: the infinipath device
++ *
++ * Called during driver unload.
++ * This is currently a nop for the HT chip, not for all chips
++ */
++static void ipath_setup_ht_cleanup(struct ipath_devdata *dd)
++{
++}
++
++/**
++ * ipath_setup_ht_setextled - set the state of the two external LEDs
++ * @dd: the infinipath device
++ * @lst: the L state
++ * @ltst: the LT state
++ *
++ * Set the state of the two external LEDs, to indicate physical and
++ * logical state of IB link. For this chip (at least with recommended
++ * board pinouts), LED1 is Green (physical state), and LED2 is Yellow
++ * (logical state)
++ *
++ * Note: We try to match the Mellanox HCA LED behavior as best
++ * we can. Green indicates physical link state is OK (something is
++ * plugged in, and we can train).
++ * Amber indicates the link is logically up (ACTIVE).
++ * Mellanox further blinks the amber LED to indicate data packet
++ * activity, but we have no hardware support for that, so it would
++ * require waking up every 10-20 msecs and checking the counters
++ * on the chip, and then turning the LED off if appropriate. That's
++ * visible overhead, so not something we will do.
++ *
++ */
++static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
++ u64 lst, u64 ltst)
++{
++ u64 extctl;
++
++ /* the diags use the LED to indicate diag info, so we leave
++ * the external LED alone when the diags are running */
++ if (ipath_diag_inuse)
++ return;
++
++ /*
++ * start by setting both LED control bits to off, then turn
++ * on the appropriate bit(s).
++ */
++ if (dd->ipath_boardrev == 8) { /* LS/X-1 uses different pins */
++ /*
++ * major difference is that INFINIPATH_EXTC_LEDGBLERR_OFF
++ * is inverted, because it is normally used to indicate
++ * a hardware fault at reset, if there were errors
++ */
++ extctl = (dd->ipath_extctrl & ~INFINIPATH_EXTC_LEDGBLOK_ON)
++ | INFINIPATH_EXTC_LEDGBLERR_OFF;
++ if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
++ extctl &= ~INFINIPATH_EXTC_LEDGBLERR_OFF;
++ if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
++ extctl |= INFINIPATH_EXTC_LEDGBLOK_ON;
++ }
++ else {
++ extctl = dd->ipath_extctrl &
++ ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
++ INFINIPATH_EXTC_LED2PRIPORT_ON);
++ if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
++ extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
++ if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
++ extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
++ }
++ dd->ipath_extctrl = extctl;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
++}
++
++static void ipath_init_ht_variables(struct ipath_devdata *dd)
++{
++ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
++ dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
++ dd->ipath_gpio_sda = IPATH_GPIO_SDA;
++ dd->ipath_gpio_scl = IPATH_GPIO_SCL;
++
++ dd->ipath_i_bitsextant =
++ (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
++ (INFINIPATH_I_RCVAVAIL_MASK <<
++ INFINIPATH_I_RCVAVAIL_SHIFT) |
++ INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
++ INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
++
++ dd->ipath_e_bitsextant =
++ INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
++ INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
++ INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
++ INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
++ INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
++ INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
++ INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
++ INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
++ INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
++ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
++ INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
++ INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
++ INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
++ INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
++ INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
++ INFINIPATH_E_HARDWARE;
++
++ dd->ipath_hwe_bitsextant =
++ (INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
++ INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
++ (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
++ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
++ (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
++ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
++ INFINIPATH_HWE_HTCLNKABYTE0CRCERR |
++ INFINIPATH_HWE_HTCLNKABYTE1CRCERR |
++ INFINIPATH_HWE_HTCLNKBBYTE0CRCERR |
++ INFINIPATH_HWE_HTCLNKBBYTE1CRCERR |
++ INFINIPATH_HWE_HTCMISCERR4 |
++ INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 |
++ INFINIPATH_HWE_HTCMISCERR7 |
++ INFINIPATH_HWE_HTCBUSTREQPARITYERR |
++ INFINIPATH_HWE_HTCBUSTRESPPARITYERR |
++ INFINIPATH_HWE_HTCBUSIREQPARITYERR |
++ INFINIPATH_HWE_RXDSYNCMEMPARITYERR |
++ INFINIPATH_HWE_MEMBISTFAILED |
++ INFINIPATH_HWE_COREPLL_FBSLIP |
++ INFINIPATH_HWE_COREPLL_RFSLIP |
++ INFINIPATH_HWE_HTBPLL_FBSLIP |
++ INFINIPATH_HWE_HTBPLL_RFSLIP |
++ INFINIPATH_HWE_HTAPLL_FBSLIP |
++ INFINIPATH_HWE_HTAPLL_RFSLIP |
++ INFINIPATH_HWE_SERDESPLLFAILED |
++ INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
++ INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
++
++ dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
++ dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
++}
++
++/**
++ * ipath_ht_init_hwerrors - enable hardware errors
++ * @dd: the infinipath device
++ *
++ * now that we have finished initializing everything that might reasonably
++ * cause a hardware error, and cleared those errors bits as they occur,
++ * we can enable hardware errors in the mask (potentially enabling
++ * freeze mode), and enable hardware errors as errors (along with
++ * everything else) in errormask
++ */
++static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
++{
++ ipath_err_t val;
++ u64 extsval;
++
++ extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
++
++ if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
++ ipath_dev_err(dd, "MemBIST did not complete!\n");
++
++ ipath_check_htlink(dd);
++
++ /* barring bugs, all hwerrors become interrupts, which can */
++ val = -1LL;
++ /* don't look at crc lane1 if 8 bit */
++ if (dd->ipath_flags & IPATH_8BIT_IN_HT0)
++ val &= ~infinipath_hwe_htclnkabyte1crcerr;
++ /* don't look at crc lane1 if 8 bit */
++ if (dd->ipath_flags & IPATH_8BIT_IN_HT1)
++ val &= ~infinipath_hwe_htclnkbbyte1crcerr;
++
++ /*
++ * disable RXDSYNCMEMPARITY because external serdes is unused,
++ * and therefore the logic will never be used or initialized,
++ * and uninitialized state will normally result in this error
++ * being asserted. Similarly for the external serdess pll
++ * lock signal.
++ */
++ val &= ~(INFINIPATH_HWE_SERDESPLLFAILED |
++ INFINIPATH_HWE_RXDSYNCMEMPARITYERR);
++
++ /*
++ * Disable MISCERR4 because of an inversion in the HT core
++ * logic checking for errors that cause this bit to be set.
++ * The errata can also cause the protocol error bit to be set
++ * in the HT config space linkerror register(s).
++ */
++ val &= ~INFINIPATH_HWE_HTCMISCERR4;
++
++ /*
++ * PLL ignored because MDIO interface has a logic problem
++ * for reads, on Comstock and Ponderosa. BRINGUP
++ */
++ if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
++ val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
++ dd->ipath_hwerrmask = val;
++}
++
++/**
++ * ipath_ht_bringup_serdes - bring up the serdes
++ * @dd: the infinipath device
++ */
++static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
++{
++ u64 val, config1;
++ int ret = 0, change = 0;
++
++ ipath_dbg("Trying to bringup serdes\n");
++
++ if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
++ INFINIPATH_HWE_SERDESPLLFAILED)
++ {
++ ipath_dbg("At start, serdes PLL failed bit set in "
++ "hwerrstatus, clearing and continuing\n");
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
++ INFINIPATH_HWE_SERDESPLLFAILED);
++ }
++
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
++ config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
++
++ ipath_cdbg(VERBOSE, "Initial serdes status is config0=%llx "
++ "config1=%llx, sstatus=%llx xgxs %llx\n",
++ (unsigned long long) val, (unsigned long long) config1,
++ (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
++ (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
++
++ /* force reset on */
++ val |= INFINIPATH_SERDC0_RESET_PLL
++ /* | INFINIPATH_SERDC0_RESET_MASK */
++ ;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
++ udelay(15); /* need pll reset set at least for a bit */
++
++ if (val & INFINIPATH_SERDC0_RESET_PLL) {
++ u64 val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL;
++ /* set lane resets, and tx idle, during pll reset */
++ val2 |= INFINIPATH_SERDC0_RESET_MASK |
++ INFINIPATH_SERDC0_TXIDLE;
++ ipath_cdbg(VERBOSE, "Clearing serdes PLL reset (writing "
++ "%llx)\n", (unsigned long long) val2);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,
++ val2);
++ /*
++ * be sure chip saw it
++ */
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++ /*
++ * need pll reset clear at least 11 usec before lane
++ * resets cleared; give it a few more
++ */
++ udelay(15);
++ val = val2; /* for check below */
++ }
++
++ if (val & (INFINIPATH_SERDC0_RESET_PLL |
++ INFINIPATH_SERDC0_RESET_MASK |
++ INFINIPATH_SERDC0_TXIDLE)) {
++ val &= ~(INFINIPATH_SERDC0_RESET_PLL |
++ INFINIPATH_SERDC0_RESET_MASK |
++ INFINIPATH_SERDC0_TXIDLE);
++ /* clear them */
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,
++ val);
++ }
++
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
++ if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
++ INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
++ val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
++ INFINIPATH_XGXS_MDIOADDR_SHIFT);
++ /*
++ * we use address 3
++ */
++ val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
++ change = 1;
++ }
++ if (val & INFINIPATH_XGXS_RESET) {
++ /* normally true after boot */
++ val &= ~INFINIPATH_XGXS_RESET;
++ change = 1;
++ }
++ if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
++ INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
++ /* need to compensate for Tx inversion in partner */
++ val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
++ INFINIPATH_XGXS_RX_POL_SHIFT);
++ val |= dd->ipath_rx_pol_inv <<
++ INFINIPATH_XGXS_RX_POL_SHIFT;
++ change = 1;
++ }
++ if (change)
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
++
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
++
++ /* clear current and de-emphasis bits */
++ config1 &= ~0x0ffffffff00ULL;
++ /* set current to 20ma */
++ config1 |= 0x00000000000ULL;
++ /* set de-emphasis to -5.68dB */
++ config1 |= 0x0cccc000000ULL;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1);
++
++ ipath_cdbg(VERBOSE, "After setup: serdes status is config0=%llx "
++ "config1=%llx, sstatus=%llx xgxs %llx\n",
++ (unsigned long long) val, (unsigned long long) config1,
++ (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
++ (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
++
++ if (!ipath_waitfor_mdio_cmdready(dd)) {
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
++ ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
++ IPATH_MDIO_CTRL_XGXS_REG_8,
++ 0));
++ if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
++ IPATH_MDIO_DATAVALID, &val))
++ ipath_dbg("Never got MDIO data for XGXS status "
++ "read\n");
++ else
++ ipath_cdbg(VERBOSE, "MDIO Read reg8, "
++ "'bank' 31 %x\n", (u32) val);
++ } else
++ ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
++
++ return ret; /* for now, say we always succeeded */
++}
++
++/**
++ * ipath_ht_quiet_serdes - set serdes to txidle
++ * @dd: the infinipath device
++ * driver is being unloaded
++ */
++static void ipath_ht_quiet_serdes(struct ipath_devdata *dd)
++{
++ u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
++
++ val |= INFINIPATH_SERDC0_TXIDLE;
++ ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
++ (unsigned long long) val);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
++}
++
++static int ipath_ht_intconfig(struct ipath_devdata *dd)
++{
++ int ret;
++
++ if (!dd->ipath_intconfig) {
++ ipath_dev_err(dd, "No interrupts enabled, couldn't setup "
++ "interrupt address\n");
++ ret = 1;
++ goto bail;
++ }
++
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig,
++ dd->ipath_intconfig); /* interrupt address */
++ ret = 0;
++
++bail:
++ return ret;
++}
++
++/**
++ * ipath_pe_put_tid - write a TID in chip
++ * @dd: the infinipath device
++ * @tidptr: pointer to the expected TID (in chip) to udpate
++ * @tidtype: 0 for eager, 1 for expected
++ * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
++ *
++ * This exists as a separate routine to allow for special locking etc.
++ * It's used for both the full cleanup on exit, as well as the normal
++ * setup and teardown.
++ */
++static void ipath_ht_put_tid(struct ipath_devdata *dd,
++ u64 __iomem *tidptr, u32 type,
++ unsigned long pa)
++{
++ if (pa != dd->ipath_tidinvalid) {
++ if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) {
++ dev_info(&dd->pcidev->dev,
++ "physaddr %lx has more than "
++ "40 bits, using only 40!!!\n", pa);
++ pa &= INFINIPATH_RT_ADDR_MASK;
++ }
++ if (type == 0)
++ pa |= dd->ipath_tidtemplate;
++ else {
++ /* in words (fixed, full page). */
++ u64 lenvalid = PAGE_SIZE >> 2;
++ lenvalid <<= INFINIPATH_RT_BUFSIZE_SHIFT;
++ pa |= lenvalid | INFINIPATH_RT_VALID;
++ }
++ }
++ if (dd->ipath_kregbase)
++ writeq(pa, tidptr);
++}
++
++/**
++ * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager
++ * @dd: the infinipath device
++ * @port: the port
++ *
++ * Used from ipath_close(), and at chip initialization.
++ */
++static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port)
++{
++ u64 __iomem *tidbase;
++ int i;
++
++ if (!dd->ipath_kregbase)
++ return;
++
++ ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
++
++ /*
++ * need to invalidate all of the expected TID entries for this
++ * port, so we don't have valid entries that might somehow get
++ * used (early in next use of this port, or through some bug)
++ */
++ tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
++ dd->ipath_rcvtidbase +
++ port * dd->ipath_rcvtidcnt *
++ sizeof(*tidbase));
++ for (i = 0; i < dd->ipath_rcvtidcnt; i++)
++ ipath_ht_put_tid(dd, &tidbase[i], 1, dd->ipath_tidinvalid);
++
++ tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
++ dd->ipath_rcvegrbase +
++ port * dd->ipath_rcvegrcnt *
++ sizeof(*tidbase));
++
++ for (i = 0; i < dd->ipath_rcvegrcnt; i++)
++ ipath_ht_put_tid(dd, &tidbase[i], 0, dd->ipath_tidinvalid);
++}
++
++/**
++ * ipath_ht_tidtemplate - setup constants for TID updates
++ * @dd: the infinipath device
++ *
++ * We setup stuff that we use a lot, to avoid calculating each time
++ */
++static void ipath_ht_tidtemplate(struct ipath_devdata *dd)
++{
++ dd->ipath_tidtemplate = dd->ipath_ibmaxlen >> 2;
++ dd->ipath_tidtemplate <<= INFINIPATH_RT_BUFSIZE_SHIFT;
++ dd->ipath_tidtemplate |= INFINIPATH_RT_VALID;
++
++ /*
++ * work around chip errata bug 7358, by marking invalid tids
++ * as having max length
++ */
++ dd->ipath_tidinvalid = (-1LL & INFINIPATH_RT_BUFSIZE_MASK) <<
++ INFINIPATH_RT_BUFSIZE_SHIFT;
++}
++
++static int ipath_ht_early_init(struct ipath_devdata *dd)
++{
++ u32 __iomem *piobuf;
++ u32 pioincr, val32, egrsize;
++ int i;
++
++ /*
++ * one cache line; long IB headers will spill over into received
++ * buffer
++ */
++ dd->ipath_rcvhdrentsize = 16;
++ dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
++
++ /*
++ * For HT, we allocate a somewhat overly large eager buffer,
++ * such that we can guarantee that we can receive the largest
++ * packet that we can send out. To truly support a 4KB MTU,
++ * we need to bump this to a large value. To date, other than
++ * testing, we have never encountered an HCA that can really
++ * send 4KB MTU packets, so we do not handle that (we'll get
++ * errors interrupts if we ever see one).
++ */
++ dd->ipath_rcvegrbufsize = dd->ipath_piosize2k;
++ egrsize = dd->ipath_rcvegrbufsize;
++
++ /*
++ * the min() check here is currently a nop, but it may not
++ * always be, depending on just how we do ipath_rcvegrbufsize
++ */
++ dd->ipath_ibmaxlen = min(dd->ipath_piosize2k,
++ dd->ipath_rcvegrbufsize);
++ dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
++ ipath_ht_tidtemplate(dd);
++
++ /*
++ * zero all the TID entries at startup. We do this for sanity,
++ * in case of a previous driver crash of some kind, and also
++ * because the chip powers up with these memories in an unknown
++ * state. Use portcnt, not cfgports, since this is for the
++ * full chip, not for current (possibly different) configuration
++ * value.
++ * Chip Errata bug 6447
++ */
++ for (val32 = 0; val32 < dd->ipath_portcnt; val32++)
++ ipath_ht_clear_tids(dd, val32);
++
++ /*
++ * write the pbc of each buffer, to be sure it's initialized, then
++ * cancel all the buffers, and also abort any packets that might
++ * have been in flight for some reason (the latter is for driver
++ * unload/reload, but isn't a bad idea at first init). PIO send
++ * isn't enabled at this point, so there is no danger of sending
++ * these out on the wire.
++ * Chip Errata bug 6610
++ */
++ piobuf = (u32 __iomem *) (((char __iomem *)(dd->ipath_kregbase)) +
++ dd->ipath_piobufbase);
++ pioincr = dd->ipath_palign / sizeof(*piobuf);
++ for (i = 0; i < dd->ipath_piobcnt2k; i++) {
++ /*
++ * reasonable word count, just to init pbc
++ */
++ writel(16, piobuf);
++ piobuf += pioincr;
++ }
++ /*
++ * self-clearing
++ */
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
++ INFINIPATH_S_ABORT);
++
++ ipath_get_eeprom_info(dd);
++ if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
++ dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
++ /*
++ * Later production QHT7040 has same changes as QHT7140, so
++ * can use GPIO interrupts. They have serial #'s starting
++ * with 128, rather than 112.
++ */
++ dd->ipath_flags |= IPATH_GPIO_INTR;
++ dd->ipath_flags &= ~IPATH_POLL_RX_INTR;
++ }
++ return 0;
++}
++
++/**
++ * ipath_init_ht_get_base_info - set chip-specific flags for user code
++ * @dd: the infinipath device
++ * @kbase: ipath_base_info pointer
++ *
++ * We set the PCIE flag because the lower bandwidth on PCIe vs
++ * HyperTransport can affect some user packet algorithims.
++ */
++static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
++{
++ struct ipath_base_info *kinfo = kbase;
++
++ kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |
++ IPATH_RUNTIME_RCVHDR_COPY;
++
++ return 0;
++}
++
++/**
++ * ipath_init_iba6110_funcs - set up the chip-specific function pointers
++ * @dd: the infinipath device
++ *
++ * This is global, and is called directly at init to set up the
++ * chip-specific function pointers for later use.
++ */
++void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
++{
++ dd->ipath_f_intrsetup = ipath_ht_intconfig;
++ dd->ipath_f_bus = ipath_setup_ht_config;
++ dd->ipath_f_reset = ipath_setup_ht_reset;
++ dd->ipath_f_get_boardname = ipath_ht_boardname;
++ dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors;
++ dd->ipath_f_early_init = ipath_ht_early_init;
++ dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors;
++ dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes;
++ dd->ipath_f_bringup_serdes = ipath_ht_bringup_serdes;
++ dd->ipath_f_clear_tids = ipath_ht_clear_tids;
++ dd->ipath_f_put_tid = ipath_ht_put_tid;
++ dd->ipath_f_cleanup = ipath_setup_ht_cleanup;
++ dd->ipath_f_setextled = ipath_setup_ht_setextled;
++ dd->ipath_f_get_base_info = ipath_ht_get_base_info;
++
++ /*
++ * initialize chip-specific variables
++ */
++ dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
++
++ /*
++ * setup the register offsets, since they are different for each
++ * chip
++ */
++ dd->ipath_kregs = &ipath_ht_kregs;
++ dd->ipath_cregs = &ipath_ht_cregs;
++
++ /*
++ * do very early init that is needed before ipath_f_bus is
++ * called
++ */
++ ipath_init_ht_variables(dd);
++}
+diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
+new file mode 100644
+index 0000000..a72ab9d
+--- /dev/null
++++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
+@@ -0,0 +1,1365 @@
++/*
++ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
++ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
++ * 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.
++ */
++/*
++ * This file contains all of the code that is specific to the
++ * InfiniPath PCIe chip.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++
++
++#include "ipath_kernel.h"
++#include "ipath_registers.h"
++
++/*
++ * This file contains all the chip-specific register information and
++ * access functions for the QLogic InfiniPath PCI-Express chip.
++ *
++ * This lists the InfiniPath registers, in the actual chip layout.
++ * This structure should never be directly accessed.
++ */
++struct _infinipath_do_not_use_kernel_regs {
++ unsigned long long Revision;
++ unsigned long long Control;
++ unsigned long long PageAlign;
++ unsigned long long PortCnt;
++ unsigned long long DebugPortSelect;
++ unsigned long long Reserved0;
++ unsigned long long SendRegBase;
++ unsigned long long UserRegBase;
++ unsigned long long CounterRegBase;
++ unsigned long long Scratch;
++ unsigned long long Reserved1;
++ unsigned long long Reserved2;
++ unsigned long long IntBlocked;
++ unsigned long long IntMask;
++ unsigned long long IntStatus;
++ unsigned long long IntClear;
++ unsigned long long ErrorMask;
++ unsigned long long ErrorStatus;
++ unsigned long long ErrorClear;
++ unsigned long long HwErrMask;
++ unsigned long long HwErrStatus;
++ unsigned long long HwErrClear;
++ unsigned long long HwDiagCtrl;
++ unsigned long long MDIO;
++ unsigned long long IBCStatus;
++ unsigned long long IBCCtrl;
++ unsigned long long ExtStatus;
++ unsigned long long ExtCtrl;
++ unsigned long long GPIOOut;
++ unsigned long long GPIOMask;
++ unsigned long long GPIOStatus;
++ unsigned long long GPIOClear;
++ unsigned long long RcvCtrl;
++ unsigned long long RcvBTHQP;
++ unsigned long long RcvHdrSize;
++ unsigned long long RcvHdrCnt;
++ unsigned long long RcvHdrEntSize;
++ unsigned long long RcvTIDBase;
++ unsigned long long RcvTIDCnt;
++ unsigned long long RcvEgrBase;
++ unsigned long long RcvEgrCnt;
++ unsigned long long RcvBufBase;
++ unsigned long long RcvBufSize;
++ unsigned long long RxIntMemBase;
++ unsigned long long RxIntMemSize;
++ unsigned long long RcvPartitionKey;
++ unsigned long long Reserved3;
++ unsigned long long RcvPktLEDCnt;
++ unsigned long long Reserved4[8];
++ unsigned long long SendCtrl;
++ unsigned long long SendPIOBufBase;
++ unsigned long long SendPIOSize;
++ unsigned long long SendPIOBufCnt;
++ unsigned long long SendPIOAvailAddr;
++ unsigned long long TxIntMemBase;
++ unsigned long long TxIntMemSize;
++ unsigned long long Reserved5;
++ unsigned long long PCIeRBufTestReg0;
++ unsigned long long PCIeRBufTestReg1;
++ unsigned long long Reserved51[6];
++ unsigned long long SendBufferError;
++ unsigned long long SendBufferErrorCONT1;
++ unsigned long long Reserved6SBE[6];
++ unsigned long long RcvHdrAddr0;
++ unsigned long long RcvHdrAddr1;
++ unsigned long long RcvHdrAddr2;
++ unsigned long long RcvHdrAddr3;
++ unsigned long long RcvHdrAddr4;
++ unsigned long long Reserved7RHA[11];
++ unsigned long long RcvHdrTailAddr0;
++ unsigned long long RcvHdrTailAddr1;
++ unsigned long long RcvHdrTailAddr2;
++ unsigned long long RcvHdrTailAddr3;
++ unsigned long long RcvHdrTailAddr4;
++ unsigned long long Reserved8RHTA[11];
++ unsigned long long Reserved9SW[8];
++ unsigned long long SerdesConfig0;
++ unsigned long long SerdesConfig1;
++ unsigned long long SerdesStatus;
++ unsigned long long XGXSConfig;
++ unsigned long long IBPLLCfg;
++ unsigned long long Reserved10SW2[3];
++ unsigned long long PCIEQ0SerdesConfig0;
++ unsigned long long PCIEQ0SerdesConfig1;
++ unsigned long long PCIEQ0SerdesStatus;
++ unsigned long long Reserved11;
++ unsigned long long PCIEQ1SerdesConfig0;
++ unsigned long long PCIEQ1SerdesConfig1;
++ unsigned long long PCIEQ1SerdesStatus;
++ unsigned long long Reserved12;
++};
++
++#define IPATH_KREG_OFFSET(field) (offsetof(struct \
++ _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
++#define IPATH_CREG_OFFSET(field) (offsetof( \
++ struct infinipath_counters, field) / sizeof(u64))
++
++static const struct ipath_kregs ipath_pe_kregs = {
++ .kr_control = IPATH_KREG_OFFSET(Control),
++ .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
++ .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
++ .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
++ .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
++ .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
++ .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
++ .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
++ .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
++ .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
++ .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
++ .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
++ .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
++ .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
++ .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
++ .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
++ .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
++ .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
++ .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
++ .kr_intclear = IPATH_KREG_OFFSET(IntClear),
++ .kr_intmask = IPATH_KREG_OFFSET(IntMask),
++ .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
++ .kr_mdio = IPATH_KREG_OFFSET(MDIO),
++ .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
++ .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
++ .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
++ .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
++ .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
++ .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
++ .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
++ .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
++ .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
++ .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
++ .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
++ .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
++ .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
++ .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
++ .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
++ .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
++ .kr_revision = IPATH_KREG_OFFSET(Revision),
++ .kr_scratch = IPATH_KREG_OFFSET(Scratch),
++ .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
++ .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
++ .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
++ .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
++ .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
++ .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
++ .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
++ .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
++ .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
++ .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
++ .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
++ .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
++ .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
++ .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
++ .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg),
++
++ /*
++ * These should not be used directly via ipath_read_kreg64(),
++ * use them with ipath_read_kreg64_port()
++ */
++ .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
++ .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
++
++ /* The rcvpktled register controls one of the debug port signals, so
++ * a packet activity LED can be connected to it. */
++ .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt),
++ .kr_pcierbuftestreg0 = IPATH_KREG_OFFSET(PCIeRBufTestReg0),
++ .kr_pcierbuftestreg1 = IPATH_KREG_OFFSET(PCIeRBufTestReg1),
++ .kr_pcieq0serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig0),
++ .kr_pcieq0serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig1),
++ .kr_pcieq0serdesstatus = IPATH_KREG_OFFSET(PCIEQ0SerdesStatus),
++ .kr_pcieq1serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig0),
++ .kr_pcieq1serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig1),
++ .kr_pcieq1serdesstatus = IPATH_KREG_OFFSET(PCIEQ1SerdesStatus)
++};
++
++static const struct ipath_cregs ipath_pe_cregs = {
++ .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
++ .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
++ .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
++ .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
++ .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
++ .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
++ .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
++ .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
++ .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
++ .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
++ .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
++ .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
++ .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
++ .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
++ .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
++ .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
++ .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
++ .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
++ .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
++ .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
++ .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
++ .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
++ .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
++ .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
++ .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
++ .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
++ .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
++ .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
++ .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
++ .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
++ .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
++ .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
++ .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
++};
++
++/* kr_intstatus, kr_intclear, kr_intmask bits */
++#define INFINIPATH_I_RCVURG_MASK ((1U<<5)-1)
++#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<5)-1)
++
++/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
++#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x000000000000003fULL
++#define INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT 0
++#define INFINIPATH_HWE_PCIEPOISONEDTLP 0x0000000010000000ULL
++#define INFINIPATH_HWE_PCIECPLTIMEOUT 0x0000000020000000ULL
++#define INFINIPATH_HWE_PCIEBUSPARITYXTLH 0x0000000040000000ULL
++#define INFINIPATH_HWE_PCIEBUSPARITYXADM 0x0000000080000000ULL
++#define INFINIPATH_HWE_PCIEBUSPARITYRADM 0x0000000100000000ULL
++#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL
++#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL
++#define INFINIPATH_HWE_PCIE1PLLFAILED 0x0400000000000000ULL
++#define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL
++#define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL
++
++/* kr_extstatus bits */
++#define INFINIPATH_EXTS_FREQSEL 0x2
++#define INFINIPATH_EXTS_SERDESSEL 0x4
++#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000
++#define INFINIPATH_EXTS_MEMBIST_FOUND 0x0000000000008000
++
++#define _IPATH_GPIO_SDA_NUM 1
++#define _IPATH_GPIO_SCL_NUM 0
++
++#define IPATH_GPIO_SDA (1ULL << \
++ (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
++#define IPATH_GPIO_SCL (1ULL << \
++ (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
++
++/*
++ * Rev2 silicon allows suppressing check for ArmLaunch errors.
++ * this can speed up short packet sends on systems that do
++ * not guaranteee write-order.
++ */
++#define INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR (1ULL<<63)
++
++/* 6120 specific hardware errors... */
++static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
++ INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
++ INFINIPATH_HWE_MSG(PCIECPLTIMEOUT, "PCIe completion timeout"),
++ /*
++ * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
++ * parity or memory parity error failures, because most likely we
++ * won't be able to talk to the core of the chip. Nonetheless, we
++ * might see them, if they are in parts of the PCIe core that aren't
++ * essential.
++ */
++ INFINIPATH_HWE_MSG(PCIE1PLLFAILED, "PCIePLL1"),
++ INFINIPATH_HWE_MSG(PCIE0PLLFAILED, "PCIePLL0"),
++ INFINIPATH_HWE_MSG(PCIEBUSPARITYXTLH, "PCIe XTLH core parity"),
++ INFINIPATH_HWE_MSG(PCIEBUSPARITYXADM, "PCIe ADM TX core parity"),
++ INFINIPATH_HWE_MSG(PCIEBUSPARITYRADM, "PCIe ADM RX core parity"),
++ INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
++ INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
++};
++
++/**
++ * ipath_pe_handle_hwerrors - display hardware errors.
++ * @dd: the infinipath device
++ * @msg: the output buffer
++ * @msgl: the size of the output buffer
++ *
++ * Use same msg buffer as regular errors to avoid excessive stack
++ * use. Most hardware errors are catastrophic, but for right now,
++ * we'll print them and continue. We reuse the same message buffer as
++ * ipath_handle_errors() to avoid excessive stack usage.
++ */
++static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
++ size_t msgl)
++{
++ ipath_err_t hwerrs;
++ u32 bits, ctrl;
++ int isfatal = 0;
++ char bitsmsg[64];
++
++ hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
++ if (!hwerrs) {
++ /*
++ * better than printing cofusing messages
++ * This seems to be related to clearing the crc error, or
++ * the pll error during init.
++ */
++ ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
++ return;
++ } else if (hwerrs == ~0ULL) {
++ ipath_dev_err(dd, "Read of hardware error status failed "
++ "(all bits set); ignoring\n");
++ return;
++ }
++ ipath_stats.sps_hwerrs++;
++
++ /* Always clear the error status register, except MEMBISTFAIL,
++ * regardless of whether we continue or stop using the chip.
++ * We want that set so we know it failed, even across driver reload.
++ * We'll still ignore it in the hwerrmask. We do this partly for
++ * diagnostics, but also for support */
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
++ hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
++
++ hwerrs &= dd->ipath_hwerrmask;
++
++ /*
++ * make sure we get this much out, unless told to be quiet,
++ * or it's occurred within the last 5 seconds
++ */
++ if ((hwerrs & ~(dd->ipath_lasthwerror |
++ ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
++ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
++ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
++ (ipath_debug & __IPATH_VERBDBG))
++ dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
++ "(cleared)\n", (unsigned long long) hwerrs);
++ dd->ipath_lasthwerror |= hwerrs;
++
++ if (hwerrs & ~dd->ipath_hwe_bitsextant)
++ ipath_dev_err(dd, "hwerror interrupt with unknown errors "
++ "%llx set\n", (unsigned long long)
++ (hwerrs & ~dd->ipath_hwe_bitsextant));
++
++ ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
++ if (ctrl & INFINIPATH_C_FREEZEMODE) {
++ /*
++ * parity errors in send memory are recoverable,
++ * just cancel the send (if indicated in * sendbuffererror),
++ * count the occurrence, unfreeze (if no other handled
++ * hardware error bits are set), and continue. They can
++ * occur if a processor speculative read is done to the PIO
++ * buffer while we are sending a packet, for example.
++ */
++ if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
++ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
++ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
++ ipath_stats.sps_txeparity++;
++ ipath_dbg("Recovering from TXE parity error (%llu), "
++ "hwerrstatus=%llx\n",
++ (unsigned long long) ipath_stats.sps_txeparity,
++ (unsigned long long) hwerrs);
++ ipath_disarm_senderrbufs(dd);
++ hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
++ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
++ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
++ if (!hwerrs) { /* else leave in freeze mode */
++ ipath_write_kreg(dd,
++ dd->ipath_kregs->kr_control,
++ dd->ipath_control);
++ return;
++ }
++ }
++ if (hwerrs) {
++ /*
++ * if any set that we aren't ignoring only make the
++ * complaint once, in case it's stuck or recurring,
++ * and we get here multiple times
++ */
++ if (dd->ipath_flags & IPATH_INITTED) {
++ ipath_dev_err(dd, "Fatal Hardware Error (freeze "
++ "mode), no longer usable, SN %.16s\n",
++ dd->ipath_serial);
++ isfatal = 1;
++ }
++ /*
++ * Mark as having had an error for driver, and also
++ * for /sys and status word mapped to user programs.
++ * This marks unit as not usable, until reset
++ */
++ *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
++ *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
++ dd->ipath_flags &= ~IPATH_INITTED;
++ } else {
++ ipath_dbg("Clearing freezemode on ignored hardware "
++ "error\n");
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
++ dd->ipath_control);
++ }
++ }
++
++ *msg = '\0';
++
++ if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
++ strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
++ msgl);
++ /* ignore from now on, so disable until driver reloaded */
++ *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
++ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ }
++
++ ipath_format_hwerrors(hwerrs,
++ ipath_6120_hwerror_msgs,
++ sizeof(ipath_6120_hwerror_msgs)/
++ sizeof(ipath_6120_hwerror_msgs[0]),
++ msg, msgl);
++
++ if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
++ << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
++ bits = (u32) ((hwerrs >>
++ INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) &
++ INFINIPATH_HWE_PCIEMEMPARITYERR_MASK);
++ snprintf(bitsmsg, sizeof bitsmsg,
++ "[PCIe Mem Parity Errs %x] ", bits);
++ strlcat(msg, bitsmsg, msgl);
++ }
++
++#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
++ INFINIPATH_HWE_COREPLL_RFSLIP )
++
++ if (hwerrs & _IPATH_PLL_FAIL) {
++ snprintf(bitsmsg, sizeof bitsmsg,
++ "[PLL failed (%llx), InfiniPath hardware unusable]",
++ (unsigned long long) hwerrs & _IPATH_PLL_FAIL);
++ strlcat(msg, bitsmsg, msgl);
++ /* ignore from now on, so disable until driver reloaded */
++ dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ }
++
++ if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
++ /*
++ * If it occurs, it is left masked since the eternal
++ * interface is unused
++ */
++ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
++ dd->ipath_hwerrmask);
++ }
++
++ ipath_dev_err(dd, "%s hardware error\n", msg);
++ if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) {
++ /*
++ * for /sys status file ; if no trailing } is copied, we'll
++ * know it was truncated.
++ */
++ snprintf(dd->ipath_freezemsg, dd->ipath_freezelen,
++ "{%s}", msg);
++ }
++}
++
++/**
++ * ipath_pe_boardname - fill in the board name
++ * @dd: the infinipath device
++ * @name: the output buffer
++ * @namelen: the size of the output buffer
++ *
++ * info is based on the board revision register
++ */
++static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
++ size_t namelen)
++{
++ char *n = NULL;
++ u8 boardrev = dd->ipath_boardrev;
++ int ret;
++
++ switch (boardrev) {
++ case 0:
++ n = "InfiniPath_Emulation";
++ break;
++ case 1:
++ n = "InfiniPath_QLE7140-Bringup";
++ break;
++ case 2:
++ n = "InfiniPath_QLE7140";
++ break;
++ case 3:
++ n = "InfiniPath_QMI7140";
++ break;
++ case 4:
++ n = "InfiniPath_QEM7140";
++ break;
++ case 5:
++ n = "InfiniPath_QMH7140";
++ break;
++ case 6:
++ n = "InfiniPath_QLE7142";
++ break;
++ default:
++ ipath_dev_err(dd,
++ "Don't yet know about board with ID %u\n",
++ boardrev);
++ snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u",
++ boardrev);
++ break;
++ }
++ if (n)
++ snprintf(name, namelen, "%s", n);
++
++ if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) {
++ ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n",
++ dd->ipath_majrev, dd->ipath_minrev);
++ ret = 1;
++ } else
++ ret = 0;
++
++ return ret;
++}
++
++/**
++ * ipath_pe_init_hwerrors - enable hardware errors
++ * @dd: the infinipath device
++ *
++ * now that we have finished initializing everything that might reasonably
++ * cause a hardware error, and cleared those errors bits as they occur,
++ * we can enable hardware errors in the mask (potentially enabling
++ * freeze mode), and enable hardware errors as errors (along with
++ * everything else) in errormask
++ */
++static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
++{
++ ipath_err_t val;
++ u64 extsval;
++
++ extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
++
++ if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
++ ipath_dev_err(dd, "MemBIST did not complete!\n");
++
++ val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */
++
++ if (!dd->ipath_boardrev) // no PLL for Emulator
++ val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
++
++ if (dd->ipath_minrev < 2) {
++ /* workaround bug 9460 in internal interface bus parity
++ * checking. Fixed (HW bug 9490) in Rev2.
++ */
++ val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
++ }
++ dd->ipath_hwerrmask = val;
++}
++
++/**
++ * ipath_pe_bringup_serdes - bring up the serdes
++ * @dd: the infinipath device
++ */
++static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
++{
++ u64 val, tmp, config1, prev_val;
++ int ret = 0;
++
++ ipath_dbg("Trying to bringup serdes\n");
++
++ if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
++ INFINIPATH_HWE_SERDESPLLFAILED) {
++ ipath_dbg("At start, serdes PLL failed bit set "
++ "in hwerrstatus, clearing and continuing\n");
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
++ INFINIPATH_HWE_SERDESPLLFAILED);
++ }
++
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
++ config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
++
++ ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, "
++ "xgxsconfig %llx\n", (unsigned long long) val,
++ (unsigned long long) config1, (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
++
++ /*
++ * Force reset on, also set rxdetect enable. Must do before reading
++ * serdesstatus at least for simulation, or some of the bits in
++ * serdes status will come back as undefined and cause simulation
++ * failures
++ */
++ val |= INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RXDETECT_EN
++ | INFINIPATH_SERDC0_L1PWR_DN;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
++ /* be sure chip saw it */
++ tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++ udelay(5); /* need pll reset set at least for a bit */
++ /*
++ * after PLL is reset, set the per-lane Resets and TxIdle and
++ * clear the PLL reset and rxdetect (to get falling edge).
++ * Leave L1PWR bits set (permanently)
++ */
++ val &= ~(INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_RESET_PLL
++ | INFINIPATH_SERDC0_L1PWR_DN);
++ val |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE;
++ ipath_cdbg(VERBOSE, "Clearing pll reset and setting lane resets "
++ "and txidle (%llx)\n", (unsigned long long) val);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
++ /* be sure chip saw it */
++ tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++ /* need PLL reset clear for at least 11 usec before lane
++ * resets cleared; give it a few more to be sure */
++ udelay(15);
++ val &= ~(INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE);
++
++ ipath_cdbg(VERBOSE, "Clearing lane resets and txidle "
++ "(writing %llx)\n", (unsigned long long) val);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
++ /* be sure chip saw it */
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
++ prev_val = val;
++ if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
++ INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
++ val &=
++ ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
++ INFINIPATH_XGXS_MDIOADDR_SHIFT);
++ /* MDIO address 3 */
++ val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
++ }
++ if (val & INFINIPATH_XGXS_RESET) {
++ val &= ~INFINIPATH_XGXS_RESET;
++ }
++ if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
++ INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
++ /* need to compensate for Tx inversion in partner */
++ val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
++ INFINIPATH_XGXS_RX_POL_SHIFT);
++ val |= dd->ipath_rx_pol_inv <<
++ INFINIPATH_XGXS_RX_POL_SHIFT;
++ }
++ if (dd->ipath_minrev >= 2) {
++ /* Rev 2. can tolerate multiple writes to PBC, and
++ * allowing them can provide lower latency on some
++ * CPUs, but this feature is off by default, only
++ * turned on by setting D63 of XGXSconfig reg.
++ * May want to make this conditional more
++ * fine-grained in future. This is not exactly
++ * related to XGXS, but where the bit ended up.
++ */
++ val |= INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR;
++ }
++ if (val != prev_val)
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
++
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
++
++ /* clear current and de-emphasis bits */
++ config1 &= ~0x0ffffffff00ULL;
++ /* set current to 20ma */
++ config1 |= 0x00000000000ULL;
++ /* set de-emphasis to -5.68dB */
++ config1 |= 0x0cccc000000ULL;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1);
++
++ ipath_cdbg(VERBOSE, "done: SerDes status config0=%llx "
++ "config1=%llx, sstatus=%llx xgxs=%llx\n",
++ (unsigned long long) val, (unsigned long long) config1,
++ (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
++ (unsigned long long)
++ ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
++
++ if (!ipath_waitfor_mdio_cmdready(dd)) {
++ ipath_write_kreg(
++ dd, dd->ipath_kregs->kr_mdio,
++ ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
++ IPATH_MDIO_CTRL_XGXS_REG_8, 0));
++ if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
++ IPATH_MDIO_DATAVALID, &val))
++ ipath_dbg("Never got MDIO data for XGXS "
++ "status read\n");
++ else
++ ipath_cdbg(VERBOSE, "MDIO Read reg8, "
++ "'bank' 31 %x\n", (u32) val);
++ } else
++ ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
++
++ return ret;
++}
++
++/**
++ * ipath_pe_quiet_serdes - set serdes to txidle
++ * @dd: the infinipath device
++ * Called when driver is being unloaded
++ */
++static void ipath_pe_quiet_serdes(struct ipath_devdata *dd)
++{
++ u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
++
++ val |= INFINIPATH_SERDC0_TXIDLE;
++ ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
++ (unsigned long long) val);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
++}
++
++static int ipath_pe_intconfig(struct ipath_devdata *dd)
++{
++ u64 val;
++ u32 chiprev;
++
++ /*
++ * If the chip supports added error indication via GPIO pins,
++ * enable interrupts on those bits so the interrupt routine
++ * can count the events. Also set flag so interrupt routine
++ * can know they are expected.
++ */
++ chiprev = dd->ipath_revision >> INFINIPATH_R_CHIPREVMINOR_SHIFT;
++ if ((chiprev & INFINIPATH_R_CHIPREVMINOR_MASK) > 1) {
++ /* Rev2+ reports extra errors via internal GPIO pins */
++ dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
++ val |= IPATH_GPIO_ERRINTR_MASK;
++ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
++ }
++ return 0;
++}
++
++/**
++ * ipath_setup_pe_setextled - set the state of the two external LEDs
++ * @dd: the infinipath device
++ * @lst: the L state
++ * @ltst: the LT state
++
++ * These LEDs indicate the physical and logical state of IB link.
++ * For this chip (at least with recommended board pinouts), LED1
++ * is Yellow (logical state) and LED2 is Green (physical state),
++ *
++ * Note: We try to match the Mellanox HCA LED behavior as best
++ * we can. Green indicates physical link state is OK (something is
++ * plugged in, and we can train).
++ * Amber indicates the link is logically up (ACTIVE).
++ * Mellanox further blinks the amber LED to indicate data packet
++ * activity, but we have no hardware support for that, so it would
++ * require waking up every 10-20 msecs and checking the counters
++ * on the chip, and then turning the LED off if appropriate. That's
++ * visible overhead, so not something we will do.
++ *
++ */
++static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
++ u64 ltst)
++{
++ u64 extctl;
++
++ /* the diags use the LED to indicate diag info, so we leave
++ * the external LED alone when the diags are running */
++ if (ipath_diag_inuse)
++ return;
++
++ extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
++ INFINIPATH_EXTC_LED2PRIPORT_ON);
++
++ if (ltst & INFINIPATH_IBCS_LT_STATE_LINKUP)
++ extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
++ if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
++ extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
++ dd->ipath_extctrl = extctl;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
++}
++
++/**
++ * ipath_setup_pe_cleanup - clean up any per-chip chip-specific stuff
++ * @dd: the infinipath device
++ *
++ * This is called during driver unload.
++ * We do the pci_disable_msi here, not in generic code, because it
++ * isn't used for the HT chips. If we do end up needing pci_enable_msi
++ * at some point in the future for HT, we'll move the call back
++ * into the main init_one code.
++ */
++static void ipath_setup_pe_cleanup(struct ipath_devdata *dd)
++{
++ dd->ipath_msi_lo = 0; /* just in case unload fails */
++ pci_disable_msi(dd->pcidev);
++}
++
++/**
++ * ipath_setup_pe_config - setup PCIe config related stuff
++ * @dd: the infinipath device
++ * @pdev: the PCI device
++ *
++ * The pci_enable_msi() call will fail on systems with MSI quirks
++ * such as those with AMD8131, even if the device of interest is not
++ * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed
++ * late in 2.6.16).
++ * All that can be done is to edit the kernel source to remove the quirk
++ * check until that is fixed.
++ * We do not need to call enable_msi() for our HyperTransport chip,
++ * even though it uses MSI, and we want to avoid the quirk warning, so
++ * So we call enable_msi only for PCIe. If we do end up needing
++ * pci_enable_msi at some point in the future for HT, we'll move the
++ * call back into the main init_one code.
++ * We save the msi lo and hi values, so we can restore them after
++ * chip reset (the kernel PCI infrastructure doesn't yet handle that
++ * correctly).
++ */
++static int ipath_setup_pe_config(struct ipath_devdata *dd,
++ struct pci_dev *pdev)
++{
++ int pos, ret;
++
++ dd->ipath_msi_lo = 0; /* used as a flag during reset processing */
++ ret = pci_enable_msi(dd->pcidev);
++ if (ret)
++ ipath_dev_err(dd, "pci_enable_msi failed: %d, "
++ "interrupts may not work\n", ret);
++ /* continue even if it fails, we may still be OK... */
++
++ if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
++ u16 control;
++ pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
++ &dd->ipath_msi_lo);
++ pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
++ &dd->ipath_msi_hi);
++ pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
++ &control);
++ /* now save the data (vector) info */
++ pci_read_config_word(dd->pcidev,
++ pos + ((control & PCI_MSI_FLAGS_64BIT)
++ ? 12 : 8),
++ &dd->ipath_msi_data);
++ ipath_cdbg(VERBOSE, "Read msi data 0x%x from config offset "
++ "0x%x, control=0x%x\n", dd->ipath_msi_data,
++ pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
++ control);
++ /* we save the cachelinesize also, although it doesn't
++ * really matter */
++ pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
++ &dd->ipath_pci_cacheline);
++ } else
++ ipath_dev_err(dd, "Can't find MSI capability, "
++ "can't save MSI settings for reset\n");
++ if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP))) {
++ u16 linkstat;
++ pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA,
++ &linkstat);
++ linkstat >>= 4;
++ linkstat &= 0x1f;
++ if (linkstat != 8)
++ ipath_dev_err(dd, "PCIe width %u, "
++ "performance reduced\n", linkstat);
++ }
++ else
++ ipath_dev_err(dd, "Can't find PCI Express "
++ "capability!\n");
++ return 0;
++}
++
++static void ipath_init_pe_variables(struct ipath_devdata *dd)
++{
++ /*
++ * bits for selecting i2c direction and values,
++ * used for I2C serial flash
++ */
++ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
++ dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
++ dd->ipath_gpio_sda = IPATH_GPIO_SDA;
++ dd->ipath_gpio_scl = IPATH_GPIO_SCL;
++
++ /* variables for sanity checking interrupt and errors */
++ dd->ipath_hwe_bitsextant =
++ (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
++ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
++ (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
++ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
++ (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<
++ INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |
++ INFINIPATH_HWE_PCIE1PLLFAILED |
++ INFINIPATH_HWE_PCIE0PLLFAILED |
++ INFINIPATH_HWE_PCIEPOISONEDTLP |
++ INFINIPATH_HWE_PCIECPLTIMEOUT |
++ INFINIPATH_HWE_PCIEBUSPARITYXTLH |
++ INFINIPATH_HWE_PCIEBUSPARITYXADM |
++ INFINIPATH_HWE_PCIEBUSPARITYRADM |
++ INFINIPATH_HWE_MEMBISTFAILED |
++ INFINIPATH_HWE_COREPLL_FBSLIP |
++ INFINIPATH_HWE_COREPLL_RFSLIP |
++ INFINIPATH_HWE_SERDESPLLFAILED |
++ INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
++ INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
++ dd->ipath_i_bitsextant =
++ (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
++ (INFINIPATH_I_RCVAVAIL_MASK <<
++ INFINIPATH_I_RCVAVAIL_SHIFT) |
++ INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
++ INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
++ dd->ipath_e_bitsextant =
++ INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
++ INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
++ INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
++ INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
++ INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
++ INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
++ INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
++ INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
++ INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
++ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
++ INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
++ INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
++ INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
++ INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
++ INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
++ INFINIPATH_E_HARDWARE;
++
++ dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
++ dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
++}
++
++/* setup the MSI stuff again after a reset. I'd like to just call
++ * pci_enable_msi() and request_irq() again, but when I do that,
++ * the MSI enable bit doesn't get set in the command word, and
++ * we switch to to a different interrupt vector, which is confusing,
++ * so I instead just do it all inline. Perhaps somehow can tie this
++ * into the PCIe hotplug support at some point
++ * Note, because I'm doing it all here, I don't call pci_disable_msi()
++ * or free_irq() at the start of ipath_setup_pe_reset().
++ */
++static int ipath_reinit_msi(struct ipath_devdata *dd)
++{
++ int pos;
++ u16 control;
++ int ret;
++
++ if (!dd->ipath_msi_lo) {
++ dev_info(&dd->pcidev->dev, "Can't restore MSI config, "
++ "initial setup failed?\n");
++ ret = 0;
++ goto bail;
++ }
++
++ if (!(pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
++ ipath_dev_err(dd, "Can't find MSI capability, "
++ "can't restore MSI settings\n");
++ ret = 0;
++ goto bail;
++ }
++ ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
++ dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO);
++ pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
++ dd->ipath_msi_lo);
++ ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
++ dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI);
++ pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
++ dd->ipath_msi_hi);
++ pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control);
++ if (!(control & PCI_MSI_FLAGS_ENABLE)) {
++ ipath_cdbg(VERBOSE, "MSI control at off %x was %x, "
++ "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS,
++ control, control | PCI_MSI_FLAGS_ENABLE);
++ control |= PCI_MSI_FLAGS_ENABLE;
++ pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
++ control);
++ }
++ /* now rewrite the data (vector) info */
++ pci_write_config_word(dd->pcidev, pos +
++ ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
++ dd->ipath_msi_data);
++ /* we restore the cachelinesize also, although it doesn't really
++ * matter */
++ pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
++ dd->ipath_pci_cacheline);
++ /* and now set the pci master bit again */
++ pci_set_master(dd->pcidev);
++ ret = 1;
++
++bail:
++ return ret;
++}
++
++/* This routine sleeps, so it can only be called from user context, not
++ * from interrupt context. If we need interrupt context, we can split
++ * it into two routines.
++*/
++static int ipath_setup_pe_reset(struct ipath_devdata *dd)
++{
++ u64 val;
++ int i;
++ int ret;
++
++ /* Use ERROR so it shows up in logs, etc. */
++ ipath_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->ipath_unit);
++ /* keep chip from being accessed in a few places */
++ dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT);
++ val = dd->ipath_control | INFINIPATH_C_RESET;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val);
++ mb();
++
++ for (i = 1; i <= 5; i++) {
++ int r;
++ /* allow MBIST, etc. to complete; longer on each retry.
++ * We sometimes get machine checks from bus timeout if no
++ * response, so for now, make it *really* long.
++ */
++ msleep(1000 + (1 + i) * 2000);
++ if ((r =
++ pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
++ dd->ipath_pcibar0)))
++ ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n",
++ r);
++ if ((r =
++ pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
++ dd->ipath_pcibar1)))
++ ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n",
++ r);
++ /* now re-enable memory access */
++ if ((r = pci_enable_device(dd->pcidev)))
++ ipath_dev_err(dd, "pci_enable_device failed after "
++ "reset: %d\n", r);
++ /* whether it worked or not, mark as present, again */
++ dd->ipath_flags |= IPATH_PRESENT;
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);
++ if (val == dd->ipath_revision) {
++ ipath_cdbg(VERBOSE, "Got matching revision "
++ "register %llx on try %d\n",
++ (unsigned long long) val, i);
++ ret = ipath_reinit_msi(dd);
++ goto bail;
++ }
++ /* Probably getting -1 back */
++ ipath_dbg("Didn't get expected revision register, "
++ "got %llx, try %d\n", (unsigned long long) val,
++ i + 1);
++ }
++ ret = 0; /* failed */
++
++bail:
++ return ret;
++}
++
++/**
++ * ipath_pe_put_tid - write a TID in chip
++ * @dd: the infinipath device
++ * @tidptr: pointer to the expected TID (in chip) to udpate
++ * @tidtype: 0 for eager, 1 for expected
++ * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
++ *
++ * This exists as a separate routine to allow for special locking etc.
++ * It's used for both the full cleanup on exit, as well as the normal
++ * setup and teardown.
++ */
++static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
++ u32 type, unsigned long pa)
++{
++ u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
++ unsigned long flags = 0; /* keep gcc quiet */
++
++ if (pa != dd->ipath_tidinvalid) {
++ if (pa & ((1U << 11) - 1)) {
++ dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
++ "not 4KB aligned!\n", pa);
++ return;
++ }
++ pa >>= 11;
++ /* paranoia check */
++ if (pa & (7<<29))
++ ipath_dev_err(dd,
++ "BUG: Physical page address 0x%lx "
++ "has bits set in 31-29\n", pa);
++
++ if (type == 0)
++ pa |= dd->ipath_tidtemplate;
++ else /* for now, always full 4KB page */
++ pa |= 2 << 29;
++ }
++
++ /* workaround chip bug 9437 by writing each TID twice
++ * and holding a spinlock around the writes, so they don't
++ * intermix with other TID (eager or expected) writes
++ * Unfortunately, this call can be done from interrupt level
++ * for the port 0 eager TIDs, so we have to use irqsave
++ */
++ spin_lock_irqsave(&dd->ipath_tid_lock, flags);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);
++ if (dd->ipath_kregbase)
++ writel(pa, tidp32);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xdeadbeef);
++ mmiowb();
++ spin_unlock_irqrestore(&dd->ipath_tid_lock, flags);
++}
++/**
++ * ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher
++ * @dd: the infinipath device
++ * @tidptr: pointer to the expected TID (in chip) to udpate
++ * @tidtype: 0 for eager, 1 for expected
++ * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
++ *
++ * This exists as a separate routine to allow for selection of the
++ * appropriate "flavor". The static calls in cleanup just use the
++ * revision-agnostic form, as they are not performance critical.
++ */
++static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr,
++ u32 type, unsigned long pa)
++{
++ u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
++
++ if (pa != dd->ipath_tidinvalid) {
++ if (pa & ((1U << 11) - 1)) {
++ dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
++ "not 2KB aligned!\n", pa);
++ return;
++ }
++ pa >>= 11;
++ /* paranoia check */
++ if (pa & (7<<29))
++ ipath_dev_err(dd,
++ "BUG: Physical page address 0x%lx "
++ "has bits set in 31-29\n", pa);
++
++ if (type == 0)
++ pa |= dd->ipath_tidtemplate;
++ else /* for now, always full 4KB page */
++ pa |= 2 << 29;
++ }
++ if (dd->ipath_kregbase)
++ writel(pa, tidp32);
++ mmiowb();
++}
++
++
++/**
++ * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager
++ * @dd: the infinipath device
++ * @port: the port
++ *
++ * clear all TID entries for a port, expected and eager.
++ * Used from ipath_close(). On this chip, TIDs are only 32 bits,
++ * not 64, but they are still on 64 bit boundaries, so tidbase
++ * is declared as u64 * for the pointer math, even though we write 32 bits
++ */
++static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
++{
++ u64 __iomem *tidbase;
++ unsigned long tidinv;
++ int i;
++
++ if (!dd->ipath_kregbase)
++ return;
++
++ ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
++
++ tidinv = dd->ipath_tidinvalid;
++ tidbase = (u64 __iomem *)
++ ((char __iomem *)(dd->ipath_kregbase) +
++ dd->ipath_rcvtidbase +
++ port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
++
++ for (i = 0; i < dd->ipath_rcvtidcnt; i++)
++ ipath_pe_put_tid(dd, &tidbase[i], 0, tidinv);
++
++ tidbase = (u64 __iomem *)
++ ((char __iomem *)(dd->ipath_kregbase) +
++ dd->ipath_rcvegrbase +
++ port * dd->ipath_rcvegrcnt * sizeof(*tidbase));
++
++ for (i = 0; i < dd->ipath_rcvegrcnt; i++)
++ ipath_pe_put_tid(dd, &tidbase[i], 1, tidinv);
++}
++
++/**
++ * ipath_pe_tidtemplate - setup constants for TID updates
++ * @dd: the infinipath device
++ *
++ * We setup stuff that we use a lot, to avoid calculating each time
++ */
++static void ipath_pe_tidtemplate(struct ipath_devdata *dd)
++{
++ u32 egrsize = dd->ipath_rcvegrbufsize;
++
++ /* For now, we always allocate 4KB buffers (at init) so we can
++ * receive max size packets. We may want a module parameter to
++ * specify 2KB or 4KB and/or make be per port instead of per device
++ * for those who want to reduce memory footprint. Note that the
++ * ipath_rcvhdrentsize size must be large enough to hold the largest
++ * IB header (currently 96 bytes) that we expect to handle (plus of
++ * course the 2 dwords of RHF).
++ */
++ if (egrsize == 2048)
++ dd->ipath_tidtemplate = 1U << 29;
++ else if (egrsize == 4096)
++ dd->ipath_tidtemplate = 2U << 29;
++ else {
++ egrsize = 4096;
++ dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize "
++ "%u, using %u\n", dd->ipath_rcvegrbufsize,
++ egrsize);
++ dd->ipath_tidtemplate = 2U << 29;
++ }
++ dd->ipath_tidinvalid = 0;
++}
++
++static int ipath_pe_early_init(struct ipath_devdata *dd)
++{
++ dd->ipath_flags |= IPATH_4BYTE_TID;
++
++ /*
++ * For openfabrics, we need to be able to handle an IB header of
++ * 24 dwords. HT chip has arbitrary sized receive buffers, so we
++ * made them the same size as the PIO buffers. This chip does not
++ * handle arbitrary size buffers, so we need the header large enough
++ * to handle largest IB header, but still have room for a 2KB MTU
++ * standard IB packet.
++ */
++ dd->ipath_rcvhdrentsize = 24;
++ dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
++
++ /*
++ * To truly support a 4KB MTU (for usermode), we need to
++ * bump this to a larger value. For now, we use them for
++ * the kernel only.
++ */
++ dd->ipath_rcvegrbufsize = 2048;
++ /*
++ * the min() check here is currently a nop, but it may not always
++ * be, depending on just how we do ipath_rcvegrbufsize
++ */
++ dd->ipath_ibmaxlen = min(dd->ipath_piosize2k,
++ dd->ipath_rcvegrbufsize +
++ (dd->ipath_rcvhdrentsize << 2));
++ dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
++
++ /*
++ * We can request a receive interrupt for 1 or
++ * more packets from current offset. For now, we set this
++ * up for a single packet.
++ */
++ dd->ipath_rhdrhead_intr_off = 1ULL<<32;
++
++ ipath_get_eeprom_info(dd);
++
++ return 0;
++}
++
++int __attribute__((weak)) ipath_unordered_wc(void)
++{
++ return 0;
++}
++
++/**
++ * ipath_init_pe_get_base_info - set chip-specific flags for user code
++ * @pd: the infinipath port
++ * @kbase: ipath_base_info pointer
++ *
++ * We set the PCIE flag because the lower bandwidth on PCIe vs
++ * HyperTransport can affect some user packet algorithims.
++ */
++static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
++{
++ struct ipath_base_info *kinfo = kbase;
++ struct ipath_devdata *dd;
++
++ if (ipath_unordered_wc()) {
++ kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER;
++ ipath_cdbg(PROC, "Intel processor, forcing WC order\n");
++ }
++ else
++ ipath_cdbg(PROC, "Not Intel processor, WC ordered\n");
++
++ if (pd == NULL)
++ goto done;
++
++ dd = pd->port_dd;
++
++ if (dd != NULL && dd->ipath_minrev >= 2) {
++ ipath_cdbg(PROC, "IBA6120 Rev2, allow multiple PBC write\n");
++ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PBC_REWRITE;
++ ipath_cdbg(PROC, "IBA6120 Rev2, allow loose DMA alignment\n");
++ kinfo->spi_runtime_flags |= IPATH_RUNTIME_LOOSE_DMA_ALIGN;
++ }
++
++done:
++ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
++ return 0;
++}
++
++/**
++ * ipath_init_iba6120_funcs - set up the chip-specific function pointers
++ * @dd: the infinipath device
++ *
++ * This is global, and is called directly at init to set up the
++ * chip-specific function pointers for later use.
++ */
++void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
++{
++ dd->ipath_f_intrsetup = ipath_pe_intconfig;
++ dd->ipath_f_bus = ipath_setup_pe_config;
++ dd->ipath_f_reset = ipath_setup_pe_reset;
++ dd->ipath_f_get_boardname = ipath_pe_boardname;
++ dd->ipath_f_init_hwerrors = ipath_pe_init_hwerrors;
++ dd->ipath_f_early_init = ipath_pe_early_init;
++ dd->ipath_f_handle_hwerrors = ipath_pe_handle_hwerrors;
++ dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
++ dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
++ dd->ipath_f_clear_tids = ipath_pe_clear_tids;
++ if (dd->ipath_minrev >= 2)
++ dd->ipath_f_put_tid = ipath_pe_put_tid_2;
++ else
++ dd->ipath_f_put_tid = ipath_pe_put_tid;
++ dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
++ dd->ipath_f_setextled = ipath_setup_pe_setextled;
++ dd->ipath_f_get_base_info = ipath_pe_get_base_info;
++
++ /* initialize chip-specific variables */
++ dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
++
++ /*
++ * setup the register offsets, since they are different for each
++ * chip
++ */
++ dd->ipath_kregs = &ipath_pe_kregs;
++ dd->ipath_cregs = &ipath_pe_cregs;
++
++ ipath_init_pe_variables(dd);
++}
++
+diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
+index 414cdd1..d819cca 100644
+--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
++++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
+@@ -53,8 +53,8 @@ module_param_named(cfgports, ipath_cfgpo
+ MODULE_PARM_DESC(cfgports, "Set max number of ports to use");
+
+ /*
+- * Number of buffers reserved for driver (layered drivers and SMA
+- * send). Reserved at end of buffer list. Initialized based on
++ * Number of buffers reserved for driver (verbs and layered drivers.)
++ * Reserved at end of buffer list. Initialized based on
+ * number of PIO buffers if not set via module interface.
+ * The problem with this is that it's global, but we'll use different
+ * numbers for different chip types. So the default value is not
+@@ -80,7 +80,7 @@ MODULE_PARM_DESC(kpiobufs, "Set number o
+ *
+ * Allocate the eager TID buffers and program them into infinipath.
+ * We use the network layer alloc_skb() allocator to allocate the
+- * memory, and either use the buffers as is for things like SMA
++ * memory, and either use the buffers as is for things like verbs
+ * packets, or pass the buffers up to the ipath layered driver and
+ * thence the network layer, replacing them as we do so (see
+ * ipath_rcv_layer()).
+@@ -88,13 +88,13 @@ MODULE_PARM_DESC(kpiobufs, "Set number o
+ static int create_port0_egr(struct ipath_devdata *dd)
+ {
+ unsigned e, egrcnt;
+- struct sk_buff **skbs;
++ struct ipath_skbinfo *skbinfo;
+ int ret;
+
+ egrcnt = dd->ipath_rcvegrcnt;
+
+- skbs = vmalloc(sizeof(*dd->ipath_port0_skbs) * egrcnt);
+- if (skbs == NULL) {
++ skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
++ if (skbinfo == NULL) {
+ ipath_dev_err(dd, "allocation error for eager TID "
+ "skb array\n");
+ ret = -ENOMEM;
+@@ -109,13 +109,13 @@ static int create_port0_egr(struct ipath
+ * 4 bytes so that the data buffer stays word aligned.
+ * See ipath_kreceive() for more details.
+ */
+- skbs[e] = ipath_alloc_skb(dd, GFP_KERNEL);
+- if (!skbs[e]) {
++ skbinfo[e].skb = ipath_alloc_skb(dd, GFP_KERNEL);
++ if (!skbinfo[e].skb) {
+ ipath_dev_err(dd, "SKB allocation error for "
+ "eager TID %u\n", e);
+ while (e != 0)
+- dev_kfree_skb(skbs[--e]);
+- vfree(skbs);
++ dev_kfree_skb(skbinfo[--e].skb);
++ vfree(skbinfo);
+ ret = -ENOMEM;
+ goto bail;
+ }
+@@ -124,14 +124,17 @@ static int create_port0_egr(struct ipath
+ * After loop above, so we can test non-NULL to see if ready
+ * to use at receive, etc.
+ */
+- dd->ipath_port0_skbs = skbs;
++ dd->ipath_port0_skbinfo = skbinfo;
+
+ for (e = 0; e < egrcnt; e++) {
+- unsigned long phys =
+- virt_to_phys(dd->ipath_port0_skbs[e]->data);
++ dd->ipath_port0_skbinfo[e].phys =
++ ipath_map_single(dd->pcidev,
++ dd->ipath_port0_skbinfo[e].skb->data,
++ dd->ipath_ibmaxlen, PCI_DMA_FROMDEVICE);
+ dd->ipath_f_put_tid(dd, e + (u64 __iomem *)
+ ((char __iomem *) dd->ipath_kregbase +
+- dd->ipath_rcvegrbase), 0, phys);
++ dd->ipath_rcvegrbase), 0,
++ dd->ipath_port0_skbinfo[e].phys);
+ }
+
+ ret = 0;
+@@ -240,7 +243,11 @@ static int init_chip_first(struct ipath_
+ "only supports %u\n", ipath_cfgports,
+ dd->ipath_portcnt);
+ }
+- dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_cfgports,
++ /*
++ * Allocate full portcnt array, rather than just cfgports, because
++ * cleanup iterates across all possible ports.
++ */
++ dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_portcnt,
+ GFP_KERNEL);
+
+ if (!dd->ipath_pd) {
+@@ -428,16 +435,33 @@ done:
+ */
+ static void init_shadow_tids(struct ipath_devdata *dd)
+ {
+- dd->ipath_pageshadow = (struct page **)
+- vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
++ struct page **pages;
++ dma_addr_t *addrs;
++
++ pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ sizeof(struct page *));
+- if (!dd->ipath_pageshadow)
++ if (!pages) {
+ ipath_dev_err(dd, "failed to allocate shadow page * "
+ "array, no expected sends!\n");
+- else
+- memset(dd->ipath_pageshadow, 0,
+- dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+- sizeof(struct page *));
++ dd->ipath_pageshadow = NULL;
++ return;
++ }
++
++ addrs = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
++ sizeof(dma_addr_t));
++ if (!addrs) {
++ ipath_dev_err(dd, "failed to allocate shadow dma handle "
++ "array, no expected sends!\n");
++ vfree(dd->ipath_pageshadow);
++ dd->ipath_pageshadow = NULL;
++ return;
++ }
++
++ memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt *
++ sizeof(struct page *));
++
++ dd->ipath_pageshadow = pages;
++ dd->ipath_physshadow = addrs;
+ }
+
+ static void enable_chip(struct ipath_devdata *dd,
+@@ -446,9 +470,9 @@ static void enable_chip(struct ipath_dev
+ u32 val;
+ int i;
+
+- if (!reinit) {
+- init_waitqueue_head(&ipath_sma_state_wait);
+- }
++ if (!reinit)
++ init_waitqueue_head(&ipath_state_wait);
++
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl);
+
+@@ -687,7 +711,7 @@ int ipath_init_chip(struct ipath_devdata
+ dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2)
+ / (sizeof(u64) * BITS_PER_BYTE / 2);
+ if (ipath_kpiobufs == 0) {
+- /* not set by user, or set explictly to default */
++ /* not set by user (this is default) */
+ if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128)
+ kpiobufs = 32;
+ else
+@@ -946,6 +970,7 @@ static int ipath_set_kpiobufs(const char
+ dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - val;
+ }
+
++ ipath_kpiobufs = val;
+ ret = 0;
+ bail:
+ spin_unlock_irqrestore(&ipath_devs_lock, flags);
+diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
+index 280e732..d9079ee 100644
+--- a/drivers/infiniband/hw/ipath/ipath_intr.c
++++ b/drivers/infiniband/hw/ipath/ipath_intr.c
+@@ -34,9 +34,53 @@
+ #include <linux/pci.h>
+
+ #include "ipath_kernel.h"
+-#include "ipath_layer.h"
++#include "ipath_verbs.h"
+ #include "ipath_common.h"
+
++/*
++ * Called when we might have an error that is specific to a particular
++ * PIO buffer, and may need to cancel that buffer, so it can be re-used.
++ */
++void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
++{
++ u32 piobcnt;
++ unsigned long sbuf[4];
++ /*
++ * it's possible that sendbuffererror could have bits set; might
++ * have already done this as a result of hardware error handling
++ */
++ piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
++ /* read these before writing errorclear */
++ sbuf[0] = ipath_read_kreg64(
++ dd, dd->ipath_kregs->kr_sendbuffererror);
++ sbuf[1] = ipath_read_kreg64(
++ dd, dd->ipath_kregs->kr_sendbuffererror + 1);
++ if (piobcnt > 128) {
++ sbuf[2] = ipath_read_kreg64(
++ dd, dd->ipath_kregs->kr_sendbuffererror + 2);
++ sbuf[3] = ipath_read_kreg64(
++ dd, dd->ipath_kregs->kr_sendbuffererror + 3);
++ }
++
++ if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
++ int i;
++ if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG)) {
++ __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
++ "SendbufErrs %lx %lx", sbuf[0],
++ sbuf[1]);
++ if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
++ printk(" %lx %lx ", sbuf[2], sbuf[3]);
++ printk("\n");
++ }
++
++ for (i = 0; i < piobcnt; i++)
++ if (test_bit(i, sbuf))
++ ipath_disarm_piobufs(dd, i, 1);
++ dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */
++ }
++}
++
++
+ /* These are all rcv-related errors which we want to count for stats */
+ #define E_SUM_PKTERRS \
+ (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \
+@@ -68,53 +112,9 @@
+
+ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
+ {
+- unsigned long sbuf[4];
+ u64 ignore_this_time = 0;
+- u32 piobcnt;
+-
+- /* if possible that sendbuffererror could be valid */
+- piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
+- /* read these before writing errorclear */
+- sbuf[0] = ipath_read_kreg64(
+- dd, dd->ipath_kregs->kr_sendbuffererror);
+- sbuf[1] = ipath_read_kreg64(
+- dd, dd->ipath_kregs->kr_sendbuffererror + 1);
+- if (piobcnt > 128) {
+- sbuf[2] = ipath_read_kreg64(
+- dd, dd->ipath_kregs->kr_sendbuffererror + 2);
+- sbuf[3] = ipath_read_kreg64(
+- dd, dd->ipath_kregs->kr_sendbuffererror + 3);
+- }
+-
+- if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
+- int i;
+-
+- ipath_cdbg(PKT, "SendbufErrs %lx %lx ", sbuf[0], sbuf[1]);
+- if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
+- printk("%lx %lx ", sbuf[2], sbuf[3]);
+- for (i = 0; i < piobcnt; i++) {
+- if (test_bit(i, sbuf)) {
+- u32 __iomem *piobuf;
+- if (i < dd->ipath_piobcnt2k)
+- piobuf = (u32 __iomem *)
+- (dd->ipath_pio2kbase +
+- i * dd->ipath_palign);
+- else
+- piobuf = (u32 __iomem *)
+- (dd->ipath_pio4kbase +
+- (i - dd->ipath_piobcnt2k) *
+- dd->ipath_4kalign);
+-
+- ipath_cdbg(PKT,
+- "PIObuf[%u] @%p pbc is %x; ",
+- i, piobuf, readl(piobuf));
+
+- ipath_disarm_piobufs(dd, i, 1);
+- }
+- }
+- if (ipath_debug & __IPATH_PKTDBG)
+- printk("\n");
+- }
++ ipath_disarm_senderrbufs(dd);
+ if ((errs & E_SUM_LINK_PKTERRS) &&
+ !(dd->ipath_flags & IPATH_LINKACTIVE)) {
+ /*
+@@ -132,6 +132,82 @@ static u64 handle_e_sum_errs(struct ipat
+ return ignore_this_time;
+ }
+
++/* generic hw error messages... */
++#define INFINIPATH_HWE_TXEMEMPARITYERR_MSG(a) \
++ { \
++ .mask = ( INFINIPATH_HWE_TXEMEMPARITYERR_##a << \
++ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT ), \
++ .msg = "TXE " #a " Memory Parity" \
++ }
++#define INFINIPATH_HWE_RXEMEMPARITYERR_MSG(a) \
++ { \
++ .mask = ( INFINIPATH_HWE_RXEMEMPARITYERR_##a << \
++ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT ), \
++ .msg = "RXE " #a " Memory Parity" \
++ }
++
++static const struct ipath_hwerror_msgs ipath_generic_hwerror_msgs[] = {
++ INFINIPATH_HWE_MSG(IBCBUSFRSPCPARITYERR, "IPATH2IB Parity"),
++ INFINIPATH_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2IPATH Parity"),
++
++ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOBUF),
++ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOPBC),
++ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOLAUNCHFIFO),
++
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(RCVBUF),
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(LOOKUPQ),
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EAGERTID),
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EXPTID),
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(FLAGBUF),
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(DATAINFO),
++ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(HDRINFO),
++};
++
++/**
++ * ipath_format_hwmsg - format a single hwerror message
++ * @msg message buffer
++ * @msgl length of message buffer
++ * @hwmsg message to add to message buffer
++ */
++static void ipath_format_hwmsg(char *msg, size_t msgl, const char *hwmsg)
++{
++ strlcat(msg, "[", msgl);
++ strlcat(msg, hwmsg, msgl);
++ strlcat(msg, "]", msgl);
++}
++
++/**
++ * ipath_format_hwerrors - format hardware error messages for display
++ * @hwerrs hardware errors bit vector
++ * @hwerrmsgs hardware error descriptions
++ * @nhwerrmsgs number of hwerrmsgs
++ * @msg message buffer
++ * @msgl message buffer length
++ */
++void ipath_format_hwerrors(u64 hwerrs,
++ const struct ipath_hwerror_msgs *hwerrmsgs,
++ size_t nhwerrmsgs,
++ char *msg, size_t msgl)
++{
++ int i;
++ const int glen =
++ sizeof(ipath_generic_hwerror_msgs) /
++ sizeof(ipath_generic_hwerror_msgs[0]);
++
++ for (i=0; i<glen; i++) {
++ if (hwerrs & ipath_generic_hwerror_msgs[i].mask) {
++ ipath_format_hwmsg(msg, msgl,
++ ipath_generic_hwerror_msgs[i].msg);
++ }
++ }
++
++ for (i=0; i<nhwerrmsgs; i++) {
++ if (hwerrs & hwerrmsgs[i].mask) {
++ ipath_format_hwmsg(msg, msgl, hwerrmsgs[i].msg);
++ }
++ }
++}
++
+ /* return the strings for the most common link states */
+ static char *ib_linkstate(u32 linkstate)
+ {
+@@ -201,7 +277,7 @@ static void handle_e_ibstatuschanged(str
+ ib_linkstate(lstate));
+ }
+ else
+- ipath_cdbg(SMA, "Unit %u link state %s, last "
++ ipath_cdbg(VERBOSE, "Unit %u link state %s, last "
+ "was %s\n", dd->ipath_unit,
+ ib_linkstate(lstate),
+ ib_linkstate((unsigned)
+@@ -213,7 +289,7 @@ static void handle_e_ibstatuschanged(str
+ if (lstate == IPATH_IBSTATE_INIT ||
+ lstate == IPATH_IBSTATE_ARM ||
+ lstate == IPATH_IBSTATE_ACTIVE)
+- ipath_cdbg(SMA, "Unit %u link state down"
++ ipath_cdbg(VERBOSE, "Unit %u link state down"
+ " (state 0x%x), from %s\n",
+ dd->ipath_unit,
+ (u32)val & IPATH_IBSTATE_MASK,
+@@ -269,7 +345,7 @@ static void handle_e_ibstatuschanged(str
+ INFINIPATH_IBCS_LINKSTATE_MASK)
+ == INFINIPATH_IBCS_L_STATE_ACTIVE)
+ /* if from up to down be more vocal */
+- ipath_cdbg(SMA,
++ ipath_cdbg(VERBOSE,
+ "Unit %u link now down (%s)\n",
+ dd->ipath_unit,
+ ipath_ibcstatus_str[ltstate]);
+@@ -289,8 +365,6 @@ static void handle_e_ibstatuschanged(str
+ *dd->ipath_statusp |=
+ IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
+ dd->ipath_f_setextled(dd, lstate, ltstate);
+-
+- __ipath_layer_intr(dd, IPATH_LAYER_INT_IF_UP);
+ } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
+ /*
+ * set INIT and DOWN. Down is checked by most of the other
+@@ -406,10 +480,10 @@ static int handle_errors(struct ipath_de
+ dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg);
+ }
+
+- if (!noprint && (errs & ~infinipath_e_bitsextant))
++ if (!noprint && (errs & ~dd->ipath_e_bitsextant))
+ ipath_dev_err(dd, "error interrupt with unknown errors "
+ "%llx set\n", (unsigned long long)
+- (errs & ~infinipath_e_bitsextant));
++ (errs & ~dd->ipath_e_bitsextant));
+
+ if (errs & E_SUM_ERRS)
+ ignore_this_time = handle_e_sum_errs(dd, errs);
+@@ -480,6 +554,14 @@ static int handle_errors(struct ipath_de
+ ~(INFINIPATH_E_HARDWARE |
+ INFINIPATH_E_IBSTATUSCHANGED);
+ }
++
++ /* likely due to cancel, so suppress */
++ if ((errs & (INFINIPATH_E_SPKTLEN | INFINIPATH_E_SPIOARMLAUNCH)) &&
++ dd->ipath_lastcancel > jiffies) {
++ ipath_dbg("Suppressed armlaunch/spktlen after error send cancel\n");
++ errs &= ~(INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SPKTLEN);
++ }
++
+ if (!errs)
+ return 0;
+
+@@ -531,7 +613,7 @@ static int handle_errors(struct ipath_de
+ * don't report same point multiple times,
+ * except kernel
+ */
+- tl = (u32) * pd->port_rcvhdrtail_kvaddr;
++ tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
+ if (tl == dd->ipath_lastrcvhdrqtails[i])
+ continue;
+ hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
+@@ -598,11 +680,11 @@ static int handle_errors(struct ipath_de
+
+ if (!noprint && *msg)
+ ipath_dev_err(dd, "%s error\n", msg);
+- if (dd->ipath_sma_state_wanted & dd->ipath_flags) {
+- ipath_cdbg(VERBOSE, "sma wanted state %x, iflags now %x, "
+- "waking\n", dd->ipath_sma_state_wanted,
++ if (dd->ipath_state_wanted & dd->ipath_flags) {
++ ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, "
++ "waking\n", dd->ipath_state_wanted,
+ dd->ipath_flags);
+- wake_up_interruptible(&ipath_sma_state_wait);
++ wake_up_interruptible(&ipath_state_wait);
+ }
+
+ return chkerrpkts;
+@@ -708,11 +790,7 @@ static void handle_layer_pioavail(struct
+ {
+ int ret;
+
+- ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE);
+- if (ret > 0)
+- goto set;
+-
+- ret = __ipath_verbs_piobufavail(dd);
++ ret = ipath_ib_piobufavail(dd->verbs_dev);
+ if (ret > 0)
+ goto set;
+
+@@ -735,9 +813,9 @@ static void handle_urcv(struct ipath_dev
+ int rcvdint = 0;
+
+ portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
+- infinipath_i_rcvavail_mask)
++ dd->ipath_i_rcvavail_mask)
+ | ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
+- infinipath_i_rcvurg_mask);
++ dd->ipath_i_rcvurg_mask);
+ for (i = 1; i < dd->ipath_cfgports; i++) {
+ struct ipath_portdata *pd = dd->ipath_pd[i];
+ if (portr & (1 << i) && pd && pd->port_cnt &&
+@@ -761,7 +839,7 @@ static void handle_urcv(struct ipath_dev
+ }
+ }
+
+-irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
++irqreturn_t ipath_intr(int irq, void *data)
+ {
+ struct ipath_devdata *dd = data;
+ u32 istat, chk0rcv = 0;
+@@ -814,7 +892,7 @@ irqreturn_t ipath_intr(int irq, void *da
+ if (oldhead != curtail) {
+ if (dd->ipath_flags & IPATH_GPIO_INTR) {
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+- (u64) (1 << 2));
++ (u64) (1 << IPATH_GPIO_PORT0_BIT));
+ istat = port0rbits | INFINIPATH_I_GPIO;
+ }
+ else
+@@ -844,10 +922,10 @@ irqreturn_t ipath_intr(int irq, void *da
+ if (unexpected)
+ unexpected = 0;
+
+- if (unlikely(istat & ~infinipath_i_bitsextant))
++ if (unlikely(istat & ~dd->ipath_i_bitsextant))
+ ipath_dev_err(dd,
+ "interrupt with unknown interrupts %x set\n",
+- istat & (u32) ~ infinipath_i_bitsextant);
++ istat & (u32) ~ dd->ipath_i_bitsextant);
+ else
+ ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat);
+
+@@ -873,26 +951,80 @@ irqreturn_t ipath_intr(int irq, void *da
+
+ if (istat & INFINIPATH_I_GPIO) {
+ /*
+- * Packets are available in the port 0 rcv queue.
+- * Eventually this needs to be generalized to check
+- * IPATH_GPIO_INTR, and the specific GPIO bit, if
+- * GPIO interrupts are used for anything else.
++ * GPIO interrupts fall in two broad classes:
++ * GPIO_2 indicates (on some HT4xx boards) that a packet
++ * has arrived for Port 0. Checking for this
++ * is controlled by flag IPATH_GPIO_INTR.
++ * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
++ * that we need to count. Checking for this
++ * is controlled by flag IPATH_GPIO_ERRINTRS.
+ */
+- if (unlikely(!(dd->ipath_flags & IPATH_GPIO_INTR))) {
+- u32 gpiostatus;
+- gpiostatus = ipath_read_kreg32(
+- dd, dd->ipath_kregs->kr_gpio_status);
+- ipath_dbg("Unexpected GPIO interrupt bits %x\n",
+- gpiostatus);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+- gpiostatus);
++ u32 gpiostatus;
++ u32 to_clear = 0;
++
++ gpiostatus = ipath_read_kreg32(
++ dd, dd->ipath_kregs->kr_gpio_status);
++ /* First the error-counter case.
++ */
++ if ((gpiostatus & IPATH_GPIO_ERRINTR_MASK) &&
++ (dd->ipath_flags & IPATH_GPIO_ERRINTRS)) {
++ /* want to clear the bits we see asserted. */
++ to_clear |= (gpiostatus & IPATH_GPIO_ERRINTR_MASK);
++
++ /*
++ * Count appropriately, clear bits out of our copy,
++ * as they have been "handled".
++ */
++ if (gpiostatus & (1 << IPATH_GPIO_RXUVL_BIT)) {
++ ipath_dbg("FlowCtl on UnsupVL\n");
++ dd->ipath_rxfc_unsupvl_errs++;
++ }
++ if (gpiostatus & (1 << IPATH_GPIO_OVRUN_BIT)) {
++ ipath_dbg("Overrun Threshold exceeded\n");
++ dd->ipath_overrun_thresh_errs++;
++ }
++ if (gpiostatus & (1 << IPATH_GPIO_LLI_BIT)) {
++ ipath_dbg("Local Link Integrity error\n");
++ dd->ipath_lli_errs++;
++ }
++ gpiostatus &= ~IPATH_GPIO_ERRINTR_MASK;
+ }
+- else {
+- /* Clear GPIO status bit 2 */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+- (u64) (1 << 2));
++ /* Now the Port0 Receive case */
++ if ((gpiostatus & (1 << IPATH_GPIO_PORT0_BIT)) &&
++ (dd->ipath_flags & IPATH_GPIO_INTR)) {
++ /*
++ * GPIO status bit 2 is set, and we expected it.
++ * clear it and indicate in p0bits.
++ * This probably only happens if a Port0 pkt
++ * arrives at _just_ the wrong time, and we
++ * handle that by seting chk0rcv;
++ */
++ to_clear |= (1 << IPATH_GPIO_PORT0_BIT);
++ gpiostatus &= ~(1 << IPATH_GPIO_PORT0_BIT);
+ chk0rcv = 1;
+ }
++ if (unlikely(gpiostatus)) {
++ /*
++ * Some unexpected bits remain. If they could have
++ * caused the interrupt, complain and clear.
++ * MEA: this is almost certainly non-ideal.
++ * we should look into auto-disable of unexpected
++ * GPIO interrupts, possibly on a "three strikes"
++ * basis.
++ */
++ u32 mask;
++ mask = ipath_read_kreg32(
++ dd, dd->ipath_kregs->kr_gpio_mask);
++ if (mask & gpiostatus) {
++ ipath_dbg("Unexpected GPIO IRQ bits %x\n",
++ gpiostatus & mask);
++ to_clear |= (gpiostatus & mask);
++ }
++ }
++ if (to_clear) {
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
++ (u64) to_clear);
++ }
+ }
+ chk0rcv |= istat & port0rbits;
+
+@@ -917,9 +1049,9 @@ irqreturn_t ipath_intr(int irq, void *da
+ istat &= ~port0rbits;
+ }
+
+- if (istat & ((infinipath_i_rcvavail_mask <<
++ if (istat & ((dd->ipath_i_rcvavail_mask <<
+ INFINIPATH_I_RCVAVAIL_SHIFT)
+- | (infinipath_i_rcvurg_mask <<
++ | (dd->ipath_i_rcvurg_mask <<
+ INFINIPATH_I_RCVURG_SHIFT)))
+ handle_urcv(dd, istat);
+
+diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
+index e9f374f..06d5020 100644
+--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
++++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
+@@ -39,6 +39,8 @@
+ */
+
+ #include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/dma-mapping.h>
+ #include <asm/io.h>
+
+ #include "ipath_common.h"
+@@ -62,7 +64,7 @@ struct ipath_portdata {
+ /* rcvhdrq base, needs mmap before useful */
+ void *port_rcvhdrq;
+ /* kernel virtual address where hdrqtail is updated */
+- volatile __le64 *port_rcvhdrtail_kvaddr;
++ void *port_rcvhdrtail_kvaddr;
+ /*
+ * temp buffer for expected send setup, allocated at open, instead
+ * of each setup call
+@@ -79,8 +81,8 @@ struct ipath_portdata {
+ dma_addr_t port_rcvhdrq_phys;
+ dma_addr_t port_rcvhdrqtailaddr_phys;
+ /*
+- * number of opens on this instance (0 or 1; ignoring forks, dup,
+- * etc. for now)
++ * number of opens (including slave subports) on this instance
++ * (ignoring forks, dup, etc. for now)
+ */
+ int port_cnt;
+ /*
+@@ -89,6 +91,10 @@ struct ipath_portdata {
+ */
+ /* instead of calculating it */
+ unsigned port_port;
++ /* non-zero if port is being shared. */
++ u16 port_subport_cnt;
++ /* non-zero if port is being shared. */
++ u16 port_subport_id;
+ /* chip offset of PIO buffers for this port */
+ u32 port_piobufs;
+ /* how many alloc_pages() chunks in port_rcvegrbuf_pages */
+@@ -121,6 +127,16 @@ struct ipath_portdata {
+ u16 port_pkeys[4];
+ /* so file ops can get at unit */
+ struct ipath_devdata *port_dd;
++ /* A page of memory for rcvhdrhead, rcvegrhead, rcvegrtail * N */
++ void *subport_uregbase;
++ /* An array of pages for the eager receive buffers * N */
++ void *subport_rcvegrbuf;
++ /* An array of pages for the eager header queue entries * N */
++ void *subport_rcvhdr_base;
++ /* The version of the library which opened this port */
++ u32 userversion;
++ /* Bitmask of active slaves */
++ u32 active_slaves;
+ };
+
+ struct sk_buff;
+@@ -132,10 +148,9 @@ struct _ipath_layer {
+ void *l_arg;
+ };
+
+-/* Verbs layer interface */
+-struct _verbs_layer {
+- void *l_arg;
+- struct timer_list l_timer;
++struct ipath_skbinfo {
++ struct sk_buff *skb;
++ dma_addr_t phys;
+ };
+
+ struct ipath_devdata {
+@@ -160,7 +175,7 @@ struct ipath_devdata {
+ /* ipath_cfgports pointers */
+ struct ipath_portdata **ipath_pd;
+ /* sk_buffs used by port 0 eager receive queue */
+- struct sk_buff **ipath_port0_skbs;
++ struct ipath_skbinfo *ipath_port0_skbinfo;
+ /* kvirt address of 1st 2k pio buffer */
+ void __iomem *ipath_pio2kbase;
+ /* kvirt address of 1st 4k pio buffer */
+@@ -198,7 +213,8 @@ struct ipath_devdata {
+ void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64);
+ /* fill out chip-specific fields */
+ int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
+- struct _verbs_layer verbs_layer;
++ struct ipath_ibdev *verbs_dev;
++ struct timer_list verbs_timer;
+ /* total dwords sent (summed from counter) */
+ u64 ipath_sword;
+ /* total dwords rcvd (summed from counter) */
+@@ -241,7 +257,7 @@ struct ipath_devdata {
+ u64 ipath_tidtemplate;
+ /* value to write to free TIDs */
+ u64 ipath_tidinvalid;
+- /* PE-800 rcv interrupt setup */
++ /* IBA6120 rcv interrupt setup */
+ u64 ipath_rhdrhead_intr_off;
+
+ /* size of memory at ipath_kregbase */
+@@ -250,8 +266,8 @@ struct ipath_devdata {
+ u32 ipath_pioavregs;
+ /* IPATH_POLL, etc. */
+ u32 ipath_flags;
+- /* ipath_flags sma is waiting for */
+- u32 ipath_sma_state_wanted;
++ /* ipath_flags driver is waiting for */
++ u32 ipath_state_wanted;
+ /* last buffer for user use, first buf for kernel use is this
+ * index. */
+ u32 ipath_lastport_piobuf;
+@@ -311,10 +327,6 @@ struct ipath_devdata {
+ u32 ipath_pcibar0;
+ /* so we can rewrite it after a chip reset */
+ u32 ipath_pcibar1;
+- /* sequential tries for SMA send and no bufs */
+- u32 ipath_nosma_bufs;
+- /* duration (seconds) ipath_nosma_bufs set */
+- u32 ipath_nosma_secs;
+
+ /* HT/PCI Vendor ID (here for NodeInfo) */
+ u16 ipath_vendorid;
+@@ -324,12 +336,16 @@ struct ipath_devdata {
+ u8 ipath_ht_slave_off;
+ /* for write combining settings */
+ unsigned long ipath_wc_cookie;
++ unsigned long ipath_wc_base;
++ unsigned long ipath_wc_len;
+ /* ref count for each pkey */
+ atomic_t ipath_pkeyrefs[4];
+ /* shadow copy of all exptids physaddr; used only by funcsim */
+ u64 *ipath_tidsimshadow;
+ /* shadow copy of struct page *'s for exp tid pages */
+ struct page **ipath_pageshadow;
++ /* shadow copy of dma handles for exp tid pages */
++ dma_addr_t *ipath_physshadow;
+ /* lock to workaround chip bug 9437 */
+ spinlock_t ipath_tid_lock;
+
+@@ -411,6 +427,9 @@ struct ipath_devdata {
+ unsigned long ipath_rcvctrl;
+ /* shadow kr_sendctrl */
+ unsigned long ipath_sendctrl;
++ /* ports waiting for PIOavail intr */
++ unsigned long ipath_portpiowait;
++ unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
+
+ /* value we put in kr_rcvhdrcnt */
+ u32 ipath_rcvhdrcnt;
+@@ -474,8 +493,6 @@ struct ipath_devdata {
+ u32 ipath_htwidth;
+ /* HT speed (200,400,800,1000) from HT config */
+ u32 ipath_htspeed;
+- /* ports waiting for PIOavail intr */
+- unsigned long ipath_portpiowait;
+ /*
+ * number of sequential ibcstatus change for polling active/quiet
+ * (i.e., link not coming up).
+@@ -512,34 +529,64 @@ struct ipath_devdata {
+ u8 ipath_pci_cacheline;
+ /* LID mask control */
+ u8 ipath_lmc;
++ /* Rx Polarity inversion (compensate for ~tx on partner) */
++ u8 ipath_rx_pol_inv;
+
+ /* local link integrity counter */
+ u32 ipath_lli_counter;
+ /* local link integrity errors */
+ u32 ipath_lli_errors;
++ /*
++ * Above counts only cases where _successive_ LocalLinkIntegrity
++ * errors were seen in the receive headers of kern-packets.
++ * Below are the three (monotonically increasing) counters
++ * maintained via GPIO interrupts on iba6120-rev2.
++ */
++ u32 ipath_rxfc_unsupvl_errs;
++ u32 ipath_overrun_thresh_errs;
++ u32 ipath_lli_errs;
++
++ /*
++ * Not all devices managed by a driver instance are the same
++ * type, so these fields must be per-device.
++ */
++ u64 ipath_i_bitsextant;
++ ipath_err_t ipath_e_bitsextant;
++ ipath_err_t ipath_hwe_bitsextant;
++
++ /*
++ * Below should be computable from number of ports,
++ * since they are never modified.
++ */
++ u32 ipath_i_rcvavail_mask;
++ u32 ipath_i_rcvurg_mask;
++
++ /*
++ * Register bits for selecting i2c direction and values, used for
++ * I2C serial flash.
++ */
++ u16 ipath_gpio_sda_num;
++ u16 ipath_gpio_scl_num;
++ u64 ipath_gpio_sda;
++ u64 ipath_gpio_scl;
+ };
+
++/* Private data for file operations */
++struct ipath_filedata {
++ struct ipath_portdata *pd;
++ unsigned subport;
++ unsigned tidcursor;
++};
+ extern struct list_head ipath_dev_list;
+ extern spinlock_t ipath_devs_lock;
+ extern struct ipath_devdata *ipath_lookup(int unit);
+
+-extern u16 ipath_layer_rcv_opcode;
+-extern int __ipath_layer_intr(struct ipath_devdata *, u32);
+-extern int ipath_layer_intr(struct ipath_devdata *, u32);
+-extern int __ipath_layer_rcv(struct ipath_devdata *, void *,
+- struct sk_buff *);
+-extern int __ipath_layer_rcv_lid(struct ipath_devdata *, void *);
+-extern int __ipath_verbs_piobufavail(struct ipath_devdata *);
+-extern int __ipath_verbs_rcv(struct ipath_devdata *, void *, void *, u32);
+-
+-void ipath_layer_add(struct ipath_devdata *);
+-void ipath_layer_remove(struct ipath_devdata *);
+-
+ int ipath_init_chip(struct ipath_devdata *, int);
+ int ipath_enable_wc(struct ipath_devdata *dd);
+ void ipath_disable_wc(struct ipath_devdata *dd);
+ int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp);
+ void ipath_shutdown_device(struct ipath_devdata *);
++void ipath_disarm_senderrbufs(struct ipath_devdata *);
+
+ struct file_operations;
+ int ipath_cdev_init(int minor, char *name, struct file_operations *fops,
+@@ -549,9 +596,8 @@ void ipath_cdev_cleanup(struct cdev **cd
+
+ int ipath_diag_add(struct ipath_devdata *);
+ void ipath_diag_remove(struct ipath_devdata *);
+-void ipath_diag_bringup_link(struct ipath_devdata *);
+
+-extern wait_queue_head_t ipath_sma_state_wait;
++extern wait_queue_head_t ipath_state_wait;
+
+ int ipath_user_add(struct ipath_devdata *dd);
+ void ipath_user_remove(struct ipath_devdata *dd);
+@@ -560,7 +606,7 @@ struct sk_buff *ipath_alloc_skb(struct i
+
+ extern int ipath_diag_inuse;
+
+-irqreturn_t ipath_intr(int irq, void *devid, struct pt_regs *regs);
++irqreturn_t ipath_intr(int irq, void *devid);
+ void ipath_decode_err(char *buf, size_t blen, ipath_err_t err);
+ #if __IPATH_INFO || __IPATH_DBG
+ extern const char *ipath_ibcstatus_str[];
+@@ -582,15 +628,21 @@ void ipath_free_pddata(struct ipath_devd
+
+ int ipath_parse_ushort(const char *str, unsigned short *valp);
+
+-int ipath_wait_linkstate(struct ipath_devdata *, u32, int);
+-void ipath_set_ib_lstate(struct ipath_devdata *, int);
+ void ipath_kreceive(struct ipath_devdata *);
+ int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
+ int ipath_reset_device(int);
+ void ipath_get_faststats(unsigned long);
++int ipath_set_linkstate(struct ipath_devdata *, u8);
++int ipath_set_mtu(struct ipath_devdata *, u16);
++int ipath_set_lid(struct ipath_devdata *, u32, u8);
++int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
+
+ /* for use in system calls, where we want to know device type, etc. */
+-#define port_fp(fp) ((struct ipath_portdata *) (fp)->private_data)
++#define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
++#define subport_fp(fp) \
++ ((struct ipath_filedata *)(fp)->private_data)->subport
++#define tidcursor_fp(fp) \
++ ((struct ipath_filedata *)(fp)->private_data)->tidcursor
+
+ /*
+ * values for ipath_flags
+@@ -630,6 +682,15 @@ void ipath_get_faststats(unsigned long);
+ /* can miss port0 rx interrupts */
+ #define IPATH_POLL_RX_INTR 0x40000
+ #define IPATH_DISABLED 0x80000 /* administratively disabled */
++ /* Use GPIO interrupts for new counters */
++#define IPATH_GPIO_ERRINTRS 0x100000
++
++/* Bits in GPIO for the added interrupts */
++#define IPATH_GPIO_PORT0_BIT 2
++#define IPATH_GPIO_RXUVL_BIT 3
++#define IPATH_GPIO_OVRUN_BIT 4
++#define IPATH_GPIO_LLI_BIT 5
++#define IPATH_GPIO_ERRINTR_MASK 0x38
+
+ /* portdata flag bit offsets */
+ /* waiting for a packet to arrive */
+@@ -642,10 +703,8 @@ void ipath_free_data(struct ipath_portda
+ int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
+ int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
+ u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
+-/* init PE-800-specific func */
+-void ipath_init_pe800_funcs(struct ipath_devdata *);
+-/* init HT-400-specific func */
+-void ipath_init_ht400_funcs(struct ipath_devdata *);
++void ipath_init_iba6120_funcs(struct ipath_devdata *);
++void ipath_init_iba6110_funcs(struct ipath_devdata *);
+ void ipath_get_eeprom_info(struct ipath_devdata *);
+ u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
+
+@@ -801,7 +860,7 @@ static inline u32 ipath_read_creg32(cons
+
+ struct device_driver;
+
+-extern const char ipath_core_version[];
++extern const char ib_ipath_version[];
+
+ int ipath_driver_create_group(struct device_driver *);
+ void ipath_driver_remove_group(struct device_driver *);
+@@ -816,6 +875,13 @@ int ipathfs_add_device(struct ipath_devd
+ int ipathfs_remove_device(struct ipath_devdata *);
+
+ /*
++ * dma_addr wrappers - all 0's invalid for hw
++ */
++dma_addr_t ipath_map_page(struct pci_dev *, struct page *, unsigned long,
++ size_t, int);
++dma_addr_t ipath_map_single(struct pci_dev *, void *, size_t, int);
++
++/*
+ * Flush write combining store buffers (if present) and perform a write
+ * barrier.
+ */
+@@ -831,10 +897,10 @@ const char *ipath_get_unit_name(int unit
+
+ extern struct mutex ipath_mutex;
+
+-#define IPATH_DRV_NAME "ipath_core"
++#define IPATH_DRV_NAME "ib_ipath"
+ #define IPATH_MAJOR 233
+ #define IPATH_USER_MINOR_BASE 0
+-#define IPATH_SMA_MINOR 128
++#define IPATH_DIAGPKT_MINOR 127
+ #define IPATH_DIAG_MINOR_BASE 129
+ #define IPATH_NMINORS 255
+
+@@ -872,4 +938,20 @@ extern struct mutex ipath_mutex;
+
+ #endif /* _IPATH_DEBUGGING */
+
++/*
++ * this is used for formatting hw error messages...
++ */
++struct ipath_hwerror_msgs {
++ u64 mask;
++ const char *msg;
++};
++
++#define INFINIPATH_HWE_MSG(a, b) { .mask = INFINIPATH_HWE_##a, .msg = b }
++
++/* in ipath_intr.c... */
++void ipath_format_hwerrors(u64 hwerrs,
++ const struct ipath_hwerror_msgs *hwerrmsgs,
++ size_t nhwerrmsgs,
++ char *msg, size_t lmsg);
++
+ #endif /* _IPATH_KERNEL_H */
+diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
+index a5ca279..9a6cbd0 100644
+--- a/drivers/infiniband/hw/ipath/ipath_keys.c
++++ b/drivers/infiniband/hw/ipath/ipath_keys.c
+@@ -34,6 +34,7 @@
+ #include <asm/io.h>
+
+ #include "ipath_verbs.h"
++#include "ipath_kernel.h"
+
+ /**
+ * ipath_alloc_lkey - allocate an lkey
+@@ -60,7 +61,7 @@ int ipath_alloc_lkey(struct ipath_lkey_t
+ r = (r + 1) & (rkt->max - 1);
+ if (r == n) {
+ spin_unlock_irqrestore(&rkt->lock, flags);
+- _VERBS_INFO("LKEY table full\n");
++ ipath_dbg(KERN_INFO "LKEY table full\n");
+ ret = 0;
+ goto bail;
+ }
+@@ -117,9 +118,10 @@ void ipath_free_lkey(struct ipath_lkey_t
+ * Check the IB SGE for validity and initialize our internal version
+ * of it.
+ */
+-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
++int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
+ struct ib_sge *sge, int acc)
+ {
++ struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
+ struct ipath_mregion *mr;
+ unsigned n, m;
+ size_t off;
+@@ -139,7 +141,8 @@ int ipath_lkey_ok(struct ipath_lkey_tabl
+ goto bail;
+ }
+ mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
+- if (unlikely(mr == NULL || mr->lkey != sge->lkey)) {
++ if (unlikely(mr == NULL || mr->lkey != sge->lkey ||
++ qp->ibqp.pd != mr->pd)) {
+ ret = 0;
+ goto bail;
+ }
+@@ -187,9 +190,10 @@ bail:
+ *
+ * Return 1 if successful, otherwise 0.
+ */
+-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
++int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
+ u32 len, u64 vaddr, u32 rkey, int acc)
+ {
++ struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ struct ipath_lkey_table *rkt = &dev->lk_table;
+ struct ipath_sge *sge = &ss->sge;
+ struct ipath_mregion *mr;
+@@ -213,7 +217,8 @@ int ipath_rkey_ok(struct ipath_ibdev *de
+ }
+
+ mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
+- if (unlikely(mr == NULL || mr->lkey != rkey)) {
++ if (unlikely(mr == NULL || mr->lkey != rkey ||
++ qp->ibqp.pd != mr->pd)) {
+ ret = 0;
+ goto bail;
+ }
+diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
+index b28c6f8..e46aa4e 100644
+--- a/drivers/infiniband/hw/ipath/ipath_layer.c
++++ b/drivers/infiniband/hw/ipath/ipath_layer.c
+@@ -42,26 +42,20 @@
+
+ #include "ipath_kernel.h"
+ #include "ipath_layer.h"
++#include "ipath_verbs.h"
+ #include "ipath_common.h"
+
+ /* Acquire before ipath_devs_lock. */
+ static DEFINE_MUTEX(ipath_layer_mutex);
+
+-static int ipath_verbs_registered;
+-
+ u16 ipath_layer_rcv_opcode;
+
+ static int (*layer_intr)(void *, u32);
+ static int (*layer_rcv)(void *, void *, struct sk_buff *);
+ static int (*layer_rcv_lid)(void *, void *);
+-static int (*verbs_piobufavail)(void *);
+-static void (*verbs_rcv)(void *, void *, void *, u32);
+
+ static void *(*layer_add_one)(int, struct ipath_devdata *);
+ static void (*layer_remove_one)(void *);
+-static void *(*verbs_add_one)(int, struct ipath_devdata *);
+-static void (*verbs_remove_one)(void *);
+-static void (*verbs_timer_cb)(void *);
+
+ int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
+ {
+@@ -107,302 +101,16 @@ int __ipath_layer_rcv_lid(struct ipath_d
+ return ret;
+ }
+
+-int __ipath_verbs_piobufavail(struct ipath_devdata *dd)
+-{
+- int ret = -ENODEV;
+-
+- if (dd->verbs_layer.l_arg && verbs_piobufavail)
+- ret = verbs_piobufavail(dd->verbs_layer.l_arg);
+-
+- return ret;
+-}
+-
+-int __ipath_verbs_rcv(struct ipath_devdata *dd, void *rc, void *ebuf,
+- u32 tlen)
+-{
+- int ret = -ENODEV;
+-
+- if (dd->verbs_layer.l_arg && verbs_rcv) {
+- verbs_rcv(dd->verbs_layer.l_arg, rc, ebuf, tlen);
+- ret = 0;
+- }
+-
+- return ret;
+-}
+-
+-int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 newstate)
++void ipath_layer_lid_changed(struct ipath_devdata *dd)
+ {
+- u32 lstate;
+- int ret;
+-
+- switch (newstate) {
+- case IPATH_IB_LINKDOWN:
+- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL <<
+- INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+- /* don't wait */
+- ret = 0;
+- goto bail;
+-
+- case IPATH_IB_LINKDOWN_SLEEP:
+- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP <<
+- INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+- /* don't wait */
+- ret = 0;
+- goto bail;
+-
+- case IPATH_IB_LINKDOWN_DISABLE:
+- ipath_set_ib_lstate(dd,
+- INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
+- INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+- /* don't wait */
+- ret = 0;
+- goto bail;
+-
+- case IPATH_IB_LINKINIT:
+- if (dd->ipath_flags & IPATH_LINKINIT) {
+- ret = 0;
+- goto bail;
+- }
+- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT <<
+- INFINIPATH_IBCC_LINKCMD_SHIFT);
+- lstate = IPATH_LINKINIT;
+- break;
+-
+- case IPATH_IB_LINKARM:
+- if (dd->ipath_flags & IPATH_LINKARMED) {
+- ret = 0;
+- goto bail;
+- }
+- if (!(dd->ipath_flags &
+- (IPATH_LINKINIT | IPATH_LINKACTIVE))) {
+- ret = -EINVAL;
+- goto bail;
+- }
+- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED <<
+- INFINIPATH_IBCC_LINKCMD_SHIFT);
+- /*
+- * Since the port can transition to ACTIVE by receiving
+- * a non VL 15 packet, wait for either state.
+- */
+- lstate = IPATH_LINKARMED | IPATH_LINKACTIVE;
+- break;
+-
+- case IPATH_IB_LINKACTIVE:
+- if (dd->ipath_flags & IPATH_LINKACTIVE) {
+- ret = 0;
+- goto bail;
+- }
+- if (!(dd->ipath_flags & IPATH_LINKARMED)) {
+- ret = -EINVAL;
+- goto bail;
+- }
+- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE <<
+- INFINIPATH_IBCC_LINKCMD_SHIFT);
+- lstate = IPATH_LINKACTIVE;
+- break;
+-
+- default:
+- ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
+- ret = -EINVAL;
+- goto bail;
+- }
+- ret = ipath_wait_linkstate(dd, lstate, 2000);
+-
+-bail:
+- return ret;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_linkstate);
+-
+-/**
+- * ipath_layer_set_mtu - set the MTU
+- * @dd: the infinipath device
+- * @arg: the new MTU
+- *
+- * we can handle "any" incoming size, the issue here is whether we
+- * need to restrict our outgoing size. For now, we don't do any
+- * sanity checking on this, and we don't deal with what happens to
+- * programs that are already running when the size changes.
+- * NOTE: changing the MTU will usually cause the IBC to go back to
+- * link initialize (IPATH_IBSTATE_INIT) state...
+- */
+-int ipath_layer_set_mtu(struct ipath_devdata *dd, u16 arg)
+-{
+- u32 piosize;
+- int changed = 0;
+- int ret;
+-
+- /*
+- * mtu is IB data payload max. It's the largest power of 2 less
+- * than piosize (or even larger, since it only really controls the
+- * largest we can receive; we can send the max of the mtu and
+- * piosize). We check that it's one of the valid IB sizes.
+- */
+- if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&
+- arg != 4096) {
+- ipath_dbg("Trying to set invalid mtu %u, failing\n", arg);
+- ret = -EINVAL;
+- goto bail;
+- }
+- if (dd->ipath_ibmtu == arg) {
+- ret = 0; /* same as current */
+- goto bail;
+- }
+-
+- piosize = dd->ipath_ibmaxlen;
+- dd->ipath_ibmtu = arg;
+-
+- if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) {
+- /* Only if it's not the initial value (or reset to it) */
+- if (piosize != dd->ipath_init_ibmaxlen) {
+- dd->ipath_ibmaxlen = piosize;
+- changed = 1;
+- }
+- } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) {
+- piosize = arg + IPATH_PIO_MAXIBHDR;
+- ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x "
+- "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize,
+- arg);
+- dd->ipath_ibmaxlen = piosize;
+- changed = 1;
+- }
+-
+- if (changed) {
+- /*
+- * set the IBC maxpktlength to the size of our pio
+- * buffers in words
+- */
+- u64 ibc = dd->ipath_ibcctrl;
+- ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK <<
+- INFINIPATH_IBCC_MAXPKTLEN_SHIFT);
+-
+- piosize = piosize - 2 * sizeof(u32); /* ignore pbc */
+- dd->ipath_ibmaxlen = piosize;
+- piosize /= sizeof(u32); /* in words */
+- /*
+- * for ICRC, which we only send in diag test pkt mode, and
+- * we don't need to worry about that for mtu
+- */
+- piosize += 1;
+-
+- ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
+- dd->ipath_ibcctrl = ibc;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+- dd->ipath_ibcctrl);
+- dd->ipath_f_tidtemplate(dd);
+- }
+-
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_mtu);
+-
+-int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc)
+-{
+- dd->ipath_lid = arg;
+- dd->ipath_lmc = lmc;
+-
+ mutex_lock(&ipath_layer_mutex);
+
+ if (dd->ipath_layer.l_arg && layer_intr)
+ layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID);
+
+ mutex_unlock(&ipath_layer_mutex);
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_set_lid);
+-
+-int ipath_layer_set_guid(struct ipath_devdata *dd, __be64 guid)
+-{
+- /* XXX - need to inform anyone who cares this just happened. */
+- dd->ipath_guid = guid;
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_guid);
+-
+-__be64 ipath_layer_get_guid(struct ipath_devdata *dd)
+-{
+- return dd->ipath_guid;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_guid);
+-
+-u32 ipath_layer_get_nguid(struct ipath_devdata *dd)
+-{
+- return dd->ipath_nguid;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_nguid);
+-
+-u32 ipath_layer_get_majrev(struct ipath_devdata *dd)
+-{
+- return dd->ipath_majrev;
+ }
+
+-EXPORT_SYMBOL_GPL(ipath_layer_get_majrev);
+-
+-u32 ipath_layer_get_minrev(struct ipath_devdata *dd)
+-{
+- return dd->ipath_minrev;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_minrev);
+-
+-u32 ipath_layer_get_pcirev(struct ipath_devdata *dd)
+-{
+- return dd->ipath_pcirev;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_pcirev);
+-
+-u32 ipath_layer_get_flags(struct ipath_devdata *dd)
+-{
+- return dd->ipath_flags;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_flags);
+-
+-struct device *ipath_layer_get_device(struct ipath_devdata *dd)
+-{
+- return &dd->pcidev->dev;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_device);
+-
+-u16 ipath_layer_get_deviceid(struct ipath_devdata *dd)
+-{
+- return dd->ipath_deviceid;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_deviceid);
+-
+-u32 ipath_layer_get_vendorid(struct ipath_devdata *dd)
+-{
+- return dd->ipath_vendorid;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_vendorid);
+-
+-u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd)
+-{
+- return dd->ipath_lastibcstat;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_lastibcstat);
+-
+-u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd)
+-{
+- return dd->ipath_ibmtu;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_ibmtu);
+-
+ void ipath_layer_add(struct ipath_devdata *dd)
+ {
+ mutex_lock(&ipath_layer_mutex);
+@@ -411,10 +119,6 @@ void ipath_layer_add(struct ipath_devdat
+ dd->ipath_layer.l_arg =
+ layer_add_one(dd->ipath_unit, dd);
+
+- if (verbs_add_one)
+- dd->verbs_layer.l_arg =
+- verbs_add_one(dd->ipath_unit, dd);
+-
+ mutex_unlock(&ipath_layer_mutex);
+ }
+
+@@ -427,11 +131,6 @@ void ipath_layer_remove(struct ipath_dev
+ dd->ipath_layer.l_arg = NULL;
+ }
+
+- if (dd->verbs_layer.l_arg && verbs_remove_one) {
+- verbs_remove_one(dd->verbs_layer.l_arg);
+- dd->verbs_layer.l_arg = NULL;
+- }
+-
+ mutex_unlock(&ipath_layer_mutex);
+ }
+
+@@ -463,9 +162,6 @@ int ipath_layer_register(void *(*l_add)(
+ if (dd->ipath_layer.l_arg)
+ continue;
+
+- if (!(*dd->ipath_statusp & IPATH_STATUS_SMA))
+- *dd->ipath_statusp |= IPATH_STATUS_OIB_SMA;
+-
+ spin_unlock_irqrestore(&ipath_devs_lock, flags);
+ dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd);
+ spin_lock_irqsave(&ipath_devs_lock, flags);
+@@ -509,107 +205,6 @@ void ipath_layer_unregister(void)
+
+ EXPORT_SYMBOL_GPL(ipath_layer_unregister);
+
+-static void __ipath_verbs_timer(unsigned long arg)
+-{
+- struct ipath_devdata *dd = (struct ipath_devdata *) arg;
+-
+- /*
+- * If port 0 receive packet interrupts are not available, or
+- * can be missed, poll the receive queue
+- */
+- if (dd->ipath_flags & IPATH_POLL_RX_INTR)
+- ipath_kreceive(dd);
+-
+- /* Handle verbs layer timeouts. */
+- if (dd->verbs_layer.l_arg && verbs_timer_cb)
+- verbs_timer_cb(dd->verbs_layer.l_arg);
+-
+- mod_timer(&dd->verbs_layer.l_timer, jiffies + 1);
+-}
+-
+-/**
+- * ipath_verbs_register - verbs layer registration
+- * @l_piobufavail: callback for when PIO buffers become available
+- * @l_rcv: callback for receiving a packet
+- * @l_timer_cb: timer callback
+- * @ipath_devdata: device data structure is put here
+- */
+-int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *),
+- void (*l_remove)(void *arg),
+- int (*l_piobufavail) (void *arg),
+- void (*l_rcv) (void *arg, void *rhdr,
+- void *data, u32 tlen),
+- void (*l_timer_cb) (void *arg))
+-{
+- struct ipath_devdata *dd, *tmp;
+- unsigned long flags;
+-
+- mutex_lock(&ipath_layer_mutex);
+-
+- verbs_add_one = l_add;
+- verbs_remove_one = l_remove;
+- verbs_piobufavail = l_piobufavail;
+- verbs_rcv = l_rcv;
+- verbs_timer_cb = l_timer_cb;
+-
+- spin_lock_irqsave(&ipath_devs_lock, flags);
+-
+- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
+- if (!(dd->ipath_flags & IPATH_INITTED))
+- continue;
+-
+- if (dd->verbs_layer.l_arg)
+- continue;
+-
+- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+- dd->verbs_layer.l_arg = l_add(dd->ipath_unit, dd);
+- spin_lock_irqsave(&ipath_devs_lock, flags);
+- }
+-
+- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+- mutex_unlock(&ipath_layer_mutex);
+-
+- ipath_verbs_registered = 1;
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_verbs_register);
+-
+-void ipath_verbs_unregister(void)
+-{
+- struct ipath_devdata *dd, *tmp;
+- unsigned long flags;
+-
+- mutex_lock(&ipath_layer_mutex);
+- spin_lock_irqsave(&ipath_devs_lock, flags);
+-
+- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
+- *dd->ipath_statusp &= ~IPATH_STATUS_OIB_SMA;
+-
+- if (dd->verbs_layer.l_arg && verbs_remove_one) {
+- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+- verbs_remove_one(dd->verbs_layer.l_arg);
+- spin_lock_irqsave(&ipath_devs_lock, flags);
+- dd->verbs_layer.l_arg = NULL;
+- }
+- }
+-
+- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+-
+- verbs_add_one = NULL;
+- verbs_remove_one = NULL;
+- verbs_piobufavail = NULL;
+- verbs_rcv = NULL;
+- verbs_timer_cb = NULL;
+-
+- ipath_verbs_registered = 0;
+-
+- mutex_unlock(&ipath_layer_mutex);
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_verbs_unregister);
+-
+ int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
+ {
+ int ret;
+@@ -698,390 +293,6 @@ u16 ipath_layer_get_bcast(struct ipath_d
+
+ EXPORT_SYMBOL_GPL(ipath_layer_get_bcast);
+
+-u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd)
+-{
+- return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_cr_errpkey);
+-
+-static void update_sge(struct ipath_sge_state *ss, u32 length)
+-{
+- struct ipath_sge *sge = &ss->sge;
+-
+- sge->vaddr += length;
+- sge->length -= length;
+- sge->sge_length -= length;
+- if (sge->sge_length == 0) {
+- if (--ss->num_sge)
+- *sge = *ss->sg_list++;
+- } else if (sge->length == 0 && sge->mr != NULL) {
+- if (++sge->n >= IPATH_SEGSZ) {
+- if (++sge->m >= sge->mr->mapsz)
+- return;
+- sge->n = 0;
+- }
+- sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;
+- sge->length = sge->mr->map[sge->m]->segs[sge->n].length;
+- }
+-}
+-
+-#ifdef __LITTLE_ENDIAN
+-static inline u32 get_upper_bits(u32 data, u32 shift)
+-{
+- return data >> shift;
+-}
+-
+-static inline u32 set_upper_bits(u32 data, u32 shift)
+-{
+- return data << shift;
+-}
+-
+-static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
+-{
+- data <<= ((sizeof(u32) - n) * BITS_PER_BYTE);
+- data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
+- return data;
+-}
+-#else
+-static inline u32 get_upper_bits(u32 data, u32 shift)
+-{
+- return data << shift;
+-}
+-
+-static inline u32 set_upper_bits(u32 data, u32 shift)
+-{
+- return data >> shift;
+-}
+-
+-static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
+-{
+- data >>= ((sizeof(u32) - n) * BITS_PER_BYTE);
+- data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
+- return data;
+-}
+-#endif
+-
+-static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
+- u32 length)
+-{
+- u32 extra = 0;
+- u32 data = 0;
+- u32 last;
+-
+- while (1) {
+- u32 len = ss->sge.length;
+- u32 off;
+-
+- BUG_ON(len == 0);
+- if (len > length)
+- len = length;
+- if (len > ss->sge.sge_length)
+- len = ss->sge.sge_length;
+- /* If the source address is not aligned, try to align it. */
+- off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
+- if (off) {
+- u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr &
+- ~(sizeof(u32) - 1));
+- u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE);
+- u32 y;
+-
+- y = sizeof(u32) - off;
+- if (len > y)
+- len = y;
+- if (len + extra >= sizeof(u32)) {
+- data |= set_upper_bits(v, extra *
+- BITS_PER_BYTE);
+- len = sizeof(u32) - extra;
+- if (len == length) {
+- last = data;
+- break;
+- }
+- __raw_writel(data, piobuf);
+- piobuf++;
+- extra = 0;
+- data = 0;
+- } else {
+- /* Clear unused upper bytes */
+- data |= clear_upper_bytes(v, len, extra);
+- if (len == length) {
+- last = data;
+- break;
+- }
+- extra += len;
+- }
+- } else if (extra) {
+- /* Source address is aligned. */
+- u32 *addr = (u32 *) ss->sge.vaddr;
+- int shift = extra * BITS_PER_BYTE;
+- int ushift = 32 - shift;
+- u32 l = len;
+-
+- while (l >= sizeof(u32)) {
+- u32 v = *addr;
+-
+- data |= set_upper_bits(v, shift);
+- __raw_writel(data, piobuf);
+- data = get_upper_bits(v, ushift);
+- piobuf++;
+- addr++;
+- l -= sizeof(u32);
+- }
+- /*
+- * We still have 'extra' number of bytes leftover.
+- */
+- if (l) {
+- u32 v = *addr;
+-
+- if (l + extra >= sizeof(u32)) {
+- data |= set_upper_bits(v, shift);
+- len -= l + extra - sizeof(u32);
+- if (len == length) {
+- last = data;
+- break;
+- }
+- __raw_writel(data, piobuf);
+- piobuf++;
+- extra = 0;
+- data = 0;
+- } else {
+- /* Clear unused upper bytes */
+- data |= clear_upper_bytes(v, l,
+- extra);
+- if (len == length) {
+- last = data;
+- break;
+- }
+- extra += l;
+- }
+- } else if (len == length) {
+- last = data;
+- break;
+- }
+- } else if (len == length) {
+- u32 w;
+-
+- /*
+- * Need to round up for the last dword in the
+- * packet.
+- */
+- w = (len + 3) >> 2;
+- __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
+- piobuf += w - 1;
+- last = ((u32 *) ss->sge.vaddr)[w - 1];
+- break;
+- } else {
+- u32 w = len >> 2;
+-
+- __iowrite32_copy(piobuf, ss->sge.vaddr, w);
+- piobuf += w;
+-
+- extra = len & (sizeof(u32) - 1);
+- if (extra) {
+- u32 v = ((u32 *) ss->sge.vaddr)[w];
+-
+- /* Clear unused upper bytes */
+- data = clear_upper_bytes(v, extra, 0);
+- }
+- }
+- update_sge(ss, len);
+- length -= len;
+- }
+- /* Update address before sending packet. */
+- update_sge(ss, length);
+- /* must flush early everything before trigger word */
+- ipath_flush_wc();
+- __raw_writel(last, piobuf);
+- /* be sure trigger word is written */
+- ipath_flush_wc();
+-}
+-
+-/**
+- * ipath_verbs_send - send a packet from the verbs layer
+- * @dd: the infinipath device
+- * @hdrwords: the number of words in the header
+- * @hdr: the packet header
+- * @len: the length of the packet in bytes
+- * @ss: the SGE to send
+- *
+- * This is like ipath_sma_send_pkt() in that we need to be able to send
+- * packets after the chip is initialized (MADs) but also like
+- * ipath_layer_send_hdr() since its used by the verbs layer.
+- */
+-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
+- u32 *hdr, u32 len, struct ipath_sge_state *ss)
+-{
+- u32 __iomem *piobuf;
+- u32 plen;
+- int ret;
+-
+- /* +1 is for the qword padding of pbc */
+- plen = hdrwords + ((len + 3) >> 2) + 1;
+- if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
+- ipath_dbg("packet len 0x%x too long, failing\n", plen);
+- ret = -EINVAL;
+- goto bail;
+- }
+-
+- /* Get a PIO buffer to use. */
+- piobuf = ipath_getpiobuf(dd, NULL);
+- if (unlikely(piobuf == NULL)) {
+- ret = -EBUSY;
+- goto bail;
+- }
+-
+- /*
+- * Write len to control qword, no flags.
+- * We have to flush after the PBC for correctness on some cpus
+- * or WC buffer can be written out of order.
+- */
+- writeq(plen, piobuf);
+- ipath_flush_wc();
+- piobuf += 2;
+- if (len == 0) {
+- /*
+- * If there is just the header portion, must flush before
+- * writing last word of header for correctness, and after
+- * the last header word (trigger word).
+- */
+- __iowrite32_copy(piobuf, hdr, hdrwords - 1);
+- ipath_flush_wc();
+- __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
+- ipath_flush_wc();
+- ret = 0;
+- goto bail;
+- }
+-
+- __iowrite32_copy(piobuf, hdr, hdrwords);
+- piobuf += hdrwords;
+-
+- /* The common case is aligned and contained in one segment. */
+- if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
+- !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
+- u32 w;
+- u32 *addr = (u32 *) ss->sge.vaddr;
+-
+- /* Update address before sending packet. */
+- update_sge(ss, len);
+- /* Need to round up for the last dword in the packet. */
+- w = (len + 3) >> 2;
+- __iowrite32_copy(piobuf, addr, w - 1);
+- /* must flush early everything before trigger word */
+- ipath_flush_wc();
+- __raw_writel(addr[w - 1], piobuf + w - 1);
+- /* be sure trigger word is written */
+- ipath_flush_wc();
+- ret = 0;
+- goto bail;
+- }
+- copy_io(piobuf, ss, len);
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_verbs_send);
+-
+-int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
+- u64 *rwords, u64 *spkts, u64 *rpkts,
+- u64 *xmit_wait)
+-{
+- int ret;
+-
+- if (!(dd->ipath_flags & IPATH_INITTED)) {
+- /* no hardware, freeze, etc. */
+- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
+- ret = -EINVAL;
+- goto bail;
+- }
+- *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
+- *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+- *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
+- *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+- *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt);
+-
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_snapshot_counters);
+-
+-/**
+- * ipath_layer_get_counters - get various chip counters
+- * @dd: the infinipath device
+- * @cntrs: counters are placed here
+- *
+- * Return the counters needed by recv_pma_get_portcounters().
+- */
+-int ipath_layer_get_counters(struct ipath_devdata *dd,
+- struct ipath_layer_counters *cntrs)
+-{
+- int ret;
+-
+- if (!(dd->ipath_flags & IPATH_INITTED)) {
+- /* no hardware, freeze, etc. */
+- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
+- ret = -EINVAL;
+- goto bail;
+- }
+- cntrs->symbol_error_counter =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+- cntrs->link_error_recovery_counter =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+- /*
+- * The link downed counter counts when the other side downs the
+- * connection. We add in the number of times we downed the link
+- * due to local link integrity errors to compensate.
+- */
+- cntrs->link_downed_counter =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
+- cntrs->port_rcv_errors =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt);
+- cntrs->port_rcv_remphys_errors =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
+- cntrs->port_xmit_discards =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
+- cntrs->port_xmit_data =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
+- cntrs->port_rcv_data =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+- cntrs->port_xmit_packets =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
+- cntrs->port_rcv_packets =
+- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+- cntrs->local_link_integrity_errors = dd->ipath_lli_errors;
+- cntrs->excessive_buffer_overrun_errors = 0; /* XXX */
+-
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_counters);
+-
+-int ipath_layer_want_buffer(struct ipath_devdata *dd)
+-{
+- set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+- dd->ipath_sendctrl);
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_want_buffer);
+-
+ int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr)
+ {
+ int ret = 0;
+@@ -1153,389 +364,3 @@ int ipath_layer_set_piointbufavail_int(s
+ }
+
+ EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int);
+-
+-int ipath_layer_enable_timer(struct ipath_devdata *dd)
+-{
+- /*
+- * HT-400 has a design flaw where the chip and kernel idea
+- * of the tail register don't always agree, and therefore we won't
+- * get an interrupt on the next packet received.
+- * If the board supports per packet receive interrupts, use it.
+- * Otherwise, the timer function periodically checks for packets
+- * to cover this case.
+- * Either way, the timer is needed for verbs layer related
+- * processing.
+- */
+- if (dd->ipath_flags & IPATH_GPIO_INTR) {
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect,
+- 0x2074076542310ULL);
+- /* Enable GPIO bit 2 interrupt */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
+- (u64) (1 << 2));
+- }
+-
+- init_timer(&dd->verbs_layer.l_timer);
+- dd->verbs_layer.l_timer.function = __ipath_verbs_timer;
+- dd->verbs_layer.l_timer.data = (unsigned long)dd;
+- dd->verbs_layer.l_timer.expires = jiffies + 1;
+- add_timer(&dd->verbs_layer.l_timer);
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_enable_timer);
+-
+-int ipath_layer_disable_timer(struct ipath_devdata *dd)
+-{
+- /* Disable GPIO bit 2 interrupt */
+- if (dd->ipath_flags & IPATH_GPIO_INTR)
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0);
+-
+- del_timer_sync(&dd->verbs_layer.l_timer);
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_disable_timer);
+-
+-/**
+- * ipath_layer_set_verbs_flags - set the verbs layer flags
+- * @dd: the infinipath device
+- * @flags: the flags to set
+- */
+-int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags)
+-{
+- struct ipath_devdata *ss;
+- unsigned long lflags;
+-
+- spin_lock_irqsave(&ipath_devs_lock, lflags);
+-
+- list_for_each_entry(ss, &ipath_dev_list, ipath_list) {
+- if (!(ss->ipath_flags & IPATH_INITTED))
+- continue;
+- if ((flags & IPATH_VERBS_KERNEL_SMA) &&
+- !(*ss->ipath_statusp & IPATH_STATUS_SMA))
+- *ss->ipath_statusp |= IPATH_STATUS_OIB_SMA;
+- else
+- *ss->ipath_statusp &= ~IPATH_STATUS_OIB_SMA;
+- }
+-
+- spin_unlock_irqrestore(&ipath_devs_lock, lflags);
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_verbs_flags);
+-
+-/**
+- * ipath_layer_get_npkeys - return the size of the PKEY table for port 0
+- * @dd: the infinipath device
+- */
+-unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd)
+-{
+- return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys);
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_npkeys);
+-
+-/**
+- * ipath_layer_get_pkey - return the indexed PKEY from the port 0 PKEY table
+- * @dd: the infinipath device
+- * @index: the PKEY index
+- */
+-unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index)
+-{
+- unsigned ret;
+-
+- if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys))
+- ret = 0;
+- else
+- ret = dd->ipath_pd[0]->port_pkeys[index];
+-
+- return ret;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_pkey);
+-
+-/**
+- * ipath_layer_get_pkeys - return the PKEY table for port 0
+- * @dd: the infinipath device
+- * @pkeys: the pkey table is placed here
+- */
+-int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
+-{
+- struct ipath_portdata *pd = dd->ipath_pd[0];
+-
+- memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_pkeys);
+-
+-/**
+- * rm_pkey - decrecment the reference count for the given PKEY
+- * @dd: the infinipath device
+- * @key: the PKEY index
+- *
+- * Return true if this was the last reference and the hardware table entry
+- * needs to be changed.
+- */
+-static int rm_pkey(struct ipath_devdata *dd, u16 key)
+-{
+- int i;
+- int ret;
+-
+- for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
+- if (dd->ipath_pkeys[i] != key)
+- continue;
+- if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
+- dd->ipath_pkeys[i] = 0;
+- ret = 1;
+- goto bail;
+- }
+- break;
+- }
+-
+- ret = 0;
+-
+-bail:
+- return ret;
+-}
+-
+-/**
+- * add_pkey - add the given PKEY to the hardware table
+- * @dd: the infinipath device
+- * @key: the PKEY
+- *
+- * Return an error code if unable to add the entry, zero if no change,
+- * or 1 if the hardware PKEY register needs to be updated.
+- */
+-static int add_pkey(struct ipath_devdata *dd, u16 key)
+-{
+- int i;
+- u16 lkey = key & 0x7FFF;
+- int any = 0;
+- int ret;
+-
+- if (lkey == 0x7FFF) {
+- ret = 0;
+- goto bail;
+- }
+-
+- /* Look for an empty slot or a matching PKEY. */
+- for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
+- if (!dd->ipath_pkeys[i]) {
+- any++;
+- continue;
+- }
+- /* If it matches exactly, try to increment the ref count */
+- if (dd->ipath_pkeys[i] == key) {
+- if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
+- ret = 0;
+- goto bail;
+- }
+- /* Lost the race. Look for an empty slot below. */
+- atomic_dec(&dd->ipath_pkeyrefs[i]);
+- any++;
+- }
+- /*
+- * It makes no sense to have both the limited and unlimited
+- * PKEY set at the same time since the unlimited one will
+- * disable the limited one.
+- */
+- if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
+- ret = -EEXIST;
+- goto bail;
+- }
+- }
+- if (!any) {
+- ret = -EBUSY;
+- goto bail;
+- }
+- for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
+- if (!dd->ipath_pkeys[i] &&
+- atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
+- /* for ipathstats, etc. */
+- ipath_stats.sps_pkeys[i] = lkey;
+- dd->ipath_pkeys[i] = key;
+- ret = 1;
+- goto bail;
+- }
+- }
+- ret = -EBUSY;
+-
+-bail:
+- return ret;
+-}
+-
+-/**
+- * ipath_layer_set_pkeys - set the PKEY table for port 0
+- * @dd: the infinipath device
+- * @pkeys: the PKEY table
+- */
+-int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 * pkeys)
+-{
+- struct ipath_portdata *pd;
+- int i;
+- int changed = 0;
+-
+- pd = dd->ipath_pd[0];
+-
+- for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
+- u16 key = pkeys[i];
+- u16 okey = pd->port_pkeys[i];
+-
+- if (key == okey)
+- continue;
+- /*
+- * The value of this PKEY table entry is changing.
+- * Remove the old entry in the hardware's array of PKEYs.
+- */
+- if (okey & 0x7FFF)
+- changed |= rm_pkey(dd, okey);
+- if (key & 0x7FFF) {
+- int ret = add_pkey(dd, key);
+-
+- if (ret < 0)
+- key = 0;
+- else
+- changed |= ret;
+- }
+- pd->port_pkeys[i] = key;
+- }
+- if (changed) {
+- u64 pkey;
+-
+- pkey = (u64) dd->ipath_pkeys[0] |
+- ((u64) dd->ipath_pkeys[1] << 16) |
+- ((u64) dd->ipath_pkeys[2] << 32) |
+- ((u64) dd->ipath_pkeys[3] << 48);
+- ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
+- (unsigned long long) pkey);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
+- pkey);
+- }
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_pkeys);
+-
+-/**
+- * ipath_layer_get_linkdowndefaultstate - get the default linkdown state
+- * @dd: the infinipath device
+- *
+- * Returns zero if the default is POLL, 1 if the default is SLEEP.
+- */
+-int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd)
+-{
+- return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_linkdowndefaultstate);
+-
+-/**
+- * ipath_layer_set_linkdowndefaultstate - set the default linkdown state
+- * @dd: the infinipath device
+- * @sleep: the new state
+- *
+- * Note that this will only take effect when the link state changes.
+- */
+-int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd,
+- int sleep)
+-{
+- if (sleep)
+- dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
+- else
+- dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+- dd->ipath_ibcctrl);
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_linkdowndefaultstate);
+-
+-int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd)
+-{
+- return (dd->ipath_ibcctrl >>
+- INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
+- INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_phyerrthreshold);
+-
+-/**
+- * ipath_layer_set_phyerrthreshold - set the physical error threshold
+- * @dd: the infinipath device
+- * @n: the new threshold
+- *
+- * Note that this will only take effect when the link state changes.
+- */
+-int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
+-{
+- unsigned v;
+-
+- v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
+- INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
+- if (v != n) {
+- dd->ipath_ibcctrl &=
+- ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
+- INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
+- dd->ipath_ibcctrl |=
+- (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+- dd->ipath_ibcctrl);
+- }
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_phyerrthreshold);
+-
+-int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd)
+-{
+- return (dd->ipath_ibcctrl >>
+- INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
+- INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_get_overrunthreshold);
+-
+-/**
+- * ipath_layer_set_overrunthreshold - set the overrun threshold
+- * @dd: the infinipath device
+- * @n: the new threshold
+- *
+- * Note that this will only take effect when the link state changes.
+- */
+-int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
+-{
+- unsigned v;
+-
+- v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
+- INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
+- if (v != n) {
+- dd->ipath_ibcctrl &=
+- ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
+- INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
+- dd->ipath_ibcctrl |=
+- (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+- dd->ipath_ibcctrl);
+- }
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ipath_layer_set_overrunthreshold);
+-
+-int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name,
+- size_t namelen)
+-{
+- return dd->ipath_f_get_boardname(dd, name, namelen);
+-}
+-EXPORT_SYMBOL_GPL(ipath_layer_get_boardname);
+-
+-u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd)
+-{
+- return dd->ipath_rcvhdrentsize;
+-}
+-EXPORT_SYMBOL_GPL(ipath_layer_get_rcvhdrentsize);
+diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h
+index 7148509..3854a4e 100644
+--- a/drivers/infiniband/hw/ipath/ipath_layer.h
++++ b/drivers/infiniband/hw/ipath/ipath_layer.h
+@@ -40,73 +40,9 @@
+ */
+
+ struct sk_buff;
+-struct ipath_sge_state;
+ struct ipath_devdata;
+ struct ether_header;
+
+-struct ipath_layer_counters {
+- u64 symbol_error_counter;
+- u64 link_error_recovery_counter;
+- u64 link_downed_counter;
+- u64 port_rcv_errors;
+- u64 port_rcv_remphys_errors;
+- u64 port_xmit_discards;
+- u64 port_xmit_data;
+- u64 port_rcv_data;
+- u64 port_xmit_packets;
+- u64 port_rcv_packets;
+- u32 local_link_integrity_errors;
+- u32 excessive_buffer_overrun_errors;
+-};
+-
+-/*
+- * A segment is a linear region of low physical memory.
+- * XXX Maybe we should use phys addr here and kmap()/kunmap().
+- * Used by the verbs layer.
+- */
+-struct ipath_seg {
+- void *vaddr;
+- size_t length;
+-};
+-
+-/* The number of ipath_segs that fit in a page. */
+-#define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg))
+-
+-struct ipath_segarray {
+- struct ipath_seg segs[IPATH_SEGSZ];
+-};
+-
+-struct ipath_mregion {
+- u64 user_base; /* User's address for this region */
+- u64 iova; /* IB start address of this region */
+- size_t length;
+- u32 lkey;
+- u32 offset; /* offset (bytes) to start of region */
+- int access_flags;
+- u32 max_segs; /* number of ipath_segs in all the arrays */
+- u32 mapsz; /* size of the map array */
+- struct ipath_segarray *map[0]; /* the segments */
+-};
+-
+-/*
+- * These keep track of the copy progress within a memory region.
+- * Used by the verbs layer.
+- */
+-struct ipath_sge {
+- struct ipath_mregion *mr;
+- void *vaddr; /* current pointer into the segment */
+- u32 sge_length; /* length of the SGE */
+- u32 length; /* remaining length of the segment */
+- u16 m; /* current index: mr->map[m] */
+- u16 n; /* current index: mr->map[m]->segs[n] */
+-};
+-
+-struct ipath_sge_state {
+- struct ipath_sge *sg_list; /* next SGE to be used if any */
+- struct ipath_sge sge; /* progress state for the current SGE */
+- u8 num_sge;
+-};
+-
+ int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
+ void (*l_remove)(void *),
+ int (*l_intr)(void *, u32),
+@@ -114,62 +50,14 @@ int ipath_layer_register(void *(*l_add)(
+ struct sk_buff *),
+ u16 rcv_opcode,
+ int (*l_rcv_lid)(void *, void *));
+-int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *),
+- void (*l_remove)(void *arg),
+- int (*l_piobufavail)(void *arg),
+- void (*l_rcv)(void *arg, void *rhdr,
+- void *data, u32 tlen),
+- void (*l_timer_cb)(void *arg));
+ void ipath_layer_unregister(void);
+-void ipath_verbs_unregister(void);
+ int ipath_layer_open(struct ipath_devdata *, u32 * pktmax);
+ u16 ipath_layer_get_lid(struct ipath_devdata *dd);
+ int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *);
+ u16 ipath_layer_get_bcast(struct ipath_devdata *dd);
+-u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd);
+-int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 state);
+-int ipath_layer_set_mtu(struct ipath_devdata *, u16);
+-int ipath_set_lid(struct ipath_devdata *, u32, u8);
+ int ipath_layer_send_hdr(struct ipath_devdata *dd,
+ struct ether_header *hdr);
+-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
+- u32 * hdr, u32 len, struct ipath_sge_state *ss);
+ int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd);
+-int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name,
+- size_t namelen);
+-int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
+- u64 *rwords, u64 *spkts, u64 *rpkts,
+- u64 *xmit_wait);
+-int ipath_layer_get_counters(struct ipath_devdata *dd,
+- struct ipath_layer_counters *cntrs);
+-int ipath_layer_want_buffer(struct ipath_devdata *dd);
+-int ipath_layer_set_guid(struct ipath_devdata *, __be64 guid);
+-__be64 ipath_layer_get_guid(struct ipath_devdata *);
+-u32 ipath_layer_get_nguid(struct ipath_devdata *);
+-u32 ipath_layer_get_majrev(struct ipath_devdata *);
+-u32 ipath_layer_get_minrev(struct ipath_devdata *);
+-u32 ipath_layer_get_pcirev(struct ipath_devdata *);
+-u32 ipath_layer_get_flags(struct ipath_devdata *dd);
+-struct device *ipath_layer_get_device(struct ipath_devdata *dd);
+-u16 ipath_layer_get_deviceid(struct ipath_devdata *dd);
+-u32 ipath_layer_get_vendorid(struct ipath_devdata *);
+-u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd);
+-u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd);
+-int ipath_layer_enable_timer(struct ipath_devdata *dd);
+-int ipath_layer_disable_timer(struct ipath_devdata *dd);
+-int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags);
+-unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd);
+-unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index);
+-int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 *pkeys);
+-int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 *pkeys);
+-int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd);
+-int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd,
+- int sleep);
+-int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd);
+-int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n);
+-int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd);
+-int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n);
+-u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd);
+
+ /* ipath_ether interrupt values */
+ #define IPATH_LAYER_INT_IF_UP 0x2
+@@ -178,9 +66,6 @@ u32 ipath_layer_get_rcvhdrentsize(struct
+ #define IPATH_LAYER_INT_SEND_CONTINUE 0x10
+ #define IPATH_LAYER_INT_BCAST 0x40
+
+-/* _verbs_layer.l_flags */
+-#define IPATH_VERBS_KERNEL_SMA 0x1
+-
+ extern unsigned ipath_debug; /* debugging bit mask */
+
+ #endif /* _IPATH_LAYER_H */
+diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
+index d340234..25908b0 100644
+--- a/drivers/infiniband/hw/ipath/ipath_mad.c
++++ b/drivers/infiniband/hw/ipath/ipath_mad.c
+@@ -87,7 +87,8 @@ static int recv_subn_get_nodeinfo(struct
+ struct ipath_devdata *dd = to_idev(ibdev)->dd;
+ u32 vendor, majrev, minrev;
+
+- if (smp->attr_mod)
++ /* GUID 0 is illegal */
++ if (smp->attr_mod || (dd->ipath_guid == 0))
+ smp->status |= IB_SMP_INVALID_FIELD;
+
+ nip->base_version = 1;
+@@ -101,15 +102,15 @@ static int recv_subn_get_nodeinfo(struct
+ nip->num_ports = ibdev->phys_port_cnt;
+ /* This is already in network order */
+ nip->sys_guid = to_idev(ibdev)->sys_image_guid;
+- nip->node_guid = ipath_layer_get_guid(dd);
++ nip->node_guid = dd->ipath_guid;
+ nip->port_guid = nip->sys_guid;
+- nip->partition_cap = cpu_to_be16(ipath_layer_get_npkeys(dd));
+- nip->device_id = cpu_to_be16(ipath_layer_get_deviceid(dd));
+- majrev = ipath_layer_get_majrev(dd);
+- minrev = ipath_layer_get_minrev(dd);
++ nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd));
++ nip->device_id = cpu_to_be16(dd->ipath_deviceid);
++ majrev = dd->ipath_majrev;
++ minrev = dd->ipath_minrev;
+ nip->revision = cpu_to_be32((majrev << 16) | minrev);
+ nip->local_port_num = port;
+- vendor = ipath_layer_get_vendorid(dd);
++ vendor = dd->ipath_vendorid;
+ nip->vendor_id[0] = 0;
+ nip->vendor_id[1] = vendor >> 8;
+ nip->vendor_id[2] = vendor;
+@@ -131,15 +132,96 @@ static int recv_subn_get_guidinfo(struct
+ * We only support one GUID for now. If this changes, the
+ * portinfo.guid_cap field needs to be updated too.
+ */
+- if (startgx == 0)
+- /* The first is a copy of the read-only HW GUID. */
+- *p = ipath_layer_get_guid(to_idev(ibdev)->dd);
+- else
++ if (startgx == 0) {
++ __be64 g = to_idev(ibdev)->dd->ipath_guid;
++ if (g == 0)
++ /* GUID 0 is illegal */
++ smp->status |= IB_SMP_INVALID_FIELD;
++ else
++ /* The first is a copy of the read-only HW GUID. */
++ *p = g;
++ } else
+ smp->status |= IB_SMP_INVALID_FIELD;
+
+ return reply(smp);
+ }
+
++
++static int get_overrunthreshold(struct ipath_devdata *dd)
++{
++ return (dd->ipath_ibcctrl >>
++ INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
++ INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
++}
++
++/**
++ * set_overrunthreshold - set the overrun threshold
++ * @dd: the infinipath device
++ * @n: the new threshold
++ *
++ * Note that this will only take effect when the link state changes.
++ */
++static int set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
++{
++ unsigned v;
++
++ v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
++ INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
++ if (v != n) {
++ dd->ipath_ibcctrl &=
++ ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
++ INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
++ dd->ipath_ibcctrl |=
++ (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
++ dd->ipath_ibcctrl);
++ }
++ return 0;
++}
++
++static int get_phyerrthreshold(struct ipath_devdata *dd)
++{
++ return (dd->ipath_ibcctrl >>
++ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
++ INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
++}
++
++/**
++ * set_phyerrthreshold - set the physical error threshold
++ * @dd: the infinipath device
++ * @n: the new threshold
++ *
++ * Note that this will only take effect when the link state changes.
++ */
++static int set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
++{
++ unsigned v;
++
++ v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
++ INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
++ if (v != n) {
++ dd->ipath_ibcctrl &=
++ ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
++ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
++ dd->ipath_ibcctrl |=
++ (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
++ dd->ipath_ibcctrl);
++ }
++ return 0;
++}
++
++/**
++ * get_linkdowndefaultstate - get the default linkdown state
++ * @dd: the infinipath device
++ *
++ * Returns zero if the default is POLL, 1 if the default is SLEEP.
++ */
++static int get_linkdowndefaultstate(struct ipath_devdata *dd)
++{
++ return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
++}
++
+ static int recv_subn_get_portinfo(struct ib_smp *smp,
+ struct ib_device *ibdev, u8 port)
+ {
+@@ -166,7 +248,7 @@ static int recv_subn_get_portinfo(struct
+ (dev->mkeyprot_resv_lmc >> 6) == 0)
+ pip->mkey = dev->mkey;
+ pip->gid_prefix = dev->gid_prefix;
+- lid = ipath_layer_get_lid(dev->dd);
++ lid = dev->dd->ipath_lid;
+ pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE;
+ pip->sm_lid = cpu_to_be16(dev->sm_lid);
+ pip->cap_mask = cpu_to_be32(dev->port_cap_flags);
+@@ -177,14 +259,14 @@ static int recv_subn_get_portinfo(struct
+ pip->link_width_supported = 3; /* 1x or 4x */
+ pip->link_width_active = 2; /* 4x */
+ pip->linkspeed_portstate = 0x10; /* 2.5Gbps */
+- ibcstat = ipath_layer_get_lastibcstat(dev->dd);
++ ibcstat = dev->dd->ipath_lastibcstat;
+ pip->linkspeed_portstate |= ((ibcstat >> 4) & 0x3) + 1;
+ pip->portphysstate_linkdown =
+ (ipath_cvt_physportstate[ibcstat & 0xf] << 4) |
+- (ipath_layer_get_linkdowndefaultstate(dev->dd) ? 1 : 2);
++ (get_linkdowndefaultstate(dev->dd) ? 1 : 2);
+ pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc;
+ pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */
+- switch (ipath_layer_get_ibmtu(dev->dd)) {
++ switch (dev->dd->ipath_ibmtu) {
+ case 4096:
+ mtu = IB_MTU_4096;
+ break;
+@@ -217,7 +299,7 @@ static int recv_subn_get_portinfo(struct
+ pip->mkey_violations = cpu_to_be16(dev->mkey_violations);
+ /* P_KeyViolations are counted by hardware. */
+ pip->pkey_violations =
+- cpu_to_be16((ipath_layer_get_cr_errpkey(dev->dd) -
++ cpu_to_be16((ipath_get_cr_errpkey(dev->dd) -
+ dev->z_pkey_violations) & 0xFFFF);
+ pip->qkey_violations = cpu_to_be16(dev->qkey_violations);
+ /* Only the hardware GUID is supported for now */
+@@ -226,8 +308,8 @@ static int recv_subn_get_portinfo(struct
+ /* 32.768 usec. response time (guessing) */
+ pip->resv_resptimevalue = 3;
+ pip->localphyerrors_overrunerrors =
+- (ipath_layer_get_phyerrthreshold(dev->dd) << 4) |
+- ipath_layer_get_overrunthreshold(dev->dd);
++ (get_phyerrthreshold(dev->dd) << 4) |
++ get_overrunthreshold(dev->dd);
+ /* pip->max_credit_hint; */
+ /* pip->link_roundtrip_latency[3]; */
+
+@@ -237,6 +319,20 @@ bail:
+ return ret;
+ }
+
++/**
++ * get_pkeys - return the PKEY table for port 0
++ * @dd: the infinipath device
++ * @pkeys: the pkey table is placed here
++ */
++static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
++{
++ struct ipath_portdata *pd = dd->ipath_pd[0];
++
++ memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
++
++ return 0;
++}
++
+ static int recv_subn_get_pkeytable(struct ib_smp *smp,
+ struct ib_device *ibdev)
+ {
+@@ -249,9 +345,9 @@ static int recv_subn_get_pkeytable(struc
+ memset(smp->data, 0, sizeof(smp->data));
+ if (startpx == 0) {
+ struct ipath_ibdev *dev = to_idev(ibdev);
+- unsigned i, n = ipath_layer_get_npkeys(dev->dd);
++ unsigned i, n = ipath_get_npkeys(dev->dd);
+
+- ipath_layer_get_pkeys(dev->dd, p);
++ get_pkeys(dev->dd, p);
+
+ for (i = 0; i < n; i++)
+ q[i] = cpu_to_be16(p[i]);
+@@ -269,6 +365,24 @@ static int recv_subn_set_guidinfo(struct
+ }
+
+ /**
++ * set_linkdowndefaultstate - set the default linkdown state
++ * @dd: the infinipath device
++ * @sleep: the new state
++ *
++ * Note that this will only take effect when the link state changes.
++ */
++static int set_linkdowndefaultstate(struct ipath_devdata *dd, int sleep)
++{
++ if (sleep)
++ dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
++ else
++ dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
++ dd->ipath_ibcctrl);
++ return 0;
++}
++
++/**
+ * recv_subn_set_portinfo - set port information
+ * @smp: the incoming SM packet
+ * @ibdev: the infiniband device
+@@ -290,7 +404,7 @@ static int recv_subn_set_portinfo(struct
+ u8 state;
+ u16 lstate;
+ u32 mtu;
+- int ret;
++ int ret, ore;
+
+ if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt)
+ goto err;
+@@ -304,7 +418,7 @@ static int recv_subn_set_portinfo(struct
+ dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
+
+ lid = be16_to_cpu(pip->lid);
+- if (lid != ipath_layer_get_lid(dev->dd)) {
++ if (lid != dev->dd->ipath_lid) {
+ /* Must be a valid unicast LID address. */
+ if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
+ goto err;
+@@ -342,11 +456,11 @@ static int recv_subn_set_portinfo(struct
+ case 0: /* NOP */
+ break;
+ case 1: /* SLEEP */
+- if (ipath_layer_set_linkdowndefaultstate(dev->dd, 1))
++ if (set_linkdowndefaultstate(dev->dd, 1))
+ goto err;
+ break;
+ case 2: /* POLL */
+- if (ipath_layer_set_linkdowndefaultstate(dev->dd, 0))
++ if (set_linkdowndefaultstate(dev->dd, 0))
+ goto err;
+ break;
+ default:
+@@ -376,7 +490,7 @@ static int recv_subn_set_portinfo(struct
+ /* XXX We have already partially updated our state! */
+ goto err;
+ }
+- ipath_layer_set_mtu(dev->dd, mtu);
++ ipath_set_mtu(dev->dd, mtu);
+
+ dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
+
+@@ -392,20 +506,16 @@ static int recv_subn_set_portinfo(struct
+ * later.
+ */
+ if (pip->pkey_violations == 0)
+- dev->z_pkey_violations =
+- ipath_layer_get_cr_errpkey(dev->dd);
++ dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd);
+
+ if (pip->qkey_violations == 0)
+ dev->qkey_violations = 0;
+
+- if (ipath_layer_set_phyerrthreshold(
+- dev->dd,
+- (pip->localphyerrors_overrunerrors >> 4) & 0xF))
++ ore = pip->localphyerrors_overrunerrors;
++ if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF))
+ goto err;
+
+- if (ipath_layer_set_overrunthreshold(
+- dev->dd,
+- (pip->localphyerrors_overrunerrors & 0xF)))
++ if (set_overrunthreshold(dev->dd, (ore & 0xF)))
+ goto err;
+
+ dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
+@@ -423,7 +533,7 @@ static int recv_subn_set_portinfo(struct
+ * is down or is being set to down.
+ */
+ state = pip->linkspeed_portstate & 0xF;
+- flags = ipath_layer_get_flags(dev->dd);
++ flags = dev->dd->ipath_flags;
+ lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
+ if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
+ goto err;
+@@ -439,7 +549,7 @@ static int recv_subn_set_portinfo(struct
+ /* FALLTHROUGH */
+ case IB_PORT_DOWN:
+ if (lstate == 0)
+- if (ipath_layer_get_linkdowndefaultstate(dev->dd))
++ if (get_linkdowndefaultstate(dev->dd))
+ lstate = IPATH_IB_LINKDOWN_SLEEP;
+ else
+ lstate = IPATH_IB_LINKDOWN;
+@@ -451,7 +561,7 @@ static int recv_subn_set_portinfo(struct
+ lstate = IPATH_IB_LINKDOWN_DISABLE;
+ else
+ goto err;
+- ipath_layer_set_linkstate(dev->dd, lstate);
++ ipath_set_linkstate(dev->dd, lstate);
+ if (flags & IPATH_LINKACTIVE) {
+ event.event = IB_EVENT_PORT_ERR;
+ ib_dispatch_event(&event);
+@@ -460,7 +570,7 @@ static int recv_subn_set_portinfo(struct
+ case IB_PORT_ARMED:
+ if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
+ break;
+- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKARM);
++ ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM);
+ if (flags & IPATH_LINKACTIVE) {
+ event.event = IB_EVENT_PORT_ERR;
+ ib_dispatch_event(&event);
+@@ -469,7 +579,7 @@ static int recv_subn_set_portinfo(struct
+ case IB_PORT_ACTIVE:
+ if (!(flags & IPATH_LINKARMED))
+ break;
+- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
++ ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
+ event.event = IB_EVENT_PORT_ACTIVE;
+ ib_dispatch_event(&event);
+ break;
+@@ -493,6 +603,152 @@ done:
+ return ret;
+ }
+
++/**
++ * rm_pkey - decrecment the reference count for the given PKEY
++ * @dd: the infinipath device
++ * @key: the PKEY index
++ *
++ * Return true if this was the last reference and the hardware table entry
++ * needs to be changed.
++ */
++static int rm_pkey(struct ipath_devdata *dd, u16 key)
++{
++ int i;
++ int ret;
++
++ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
++ if (dd->ipath_pkeys[i] != key)
++ continue;
++ if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
++ dd->ipath_pkeys[i] = 0;
++ ret = 1;
++ goto bail;
++ }
++ break;
++ }
++
++ ret = 0;
++
++bail:
++ return ret;
++}
++
++/**
++ * add_pkey - add the given PKEY to the hardware table
++ * @dd: the infinipath device
++ * @key: the PKEY
++ *
++ * Return an error code if unable to add the entry, zero if no change,
++ * or 1 if the hardware PKEY register needs to be updated.
++ */
++static int add_pkey(struct ipath_devdata *dd, u16 key)
++{
++ int i;
++ u16 lkey = key & 0x7FFF;
++ int any = 0;
++ int ret;
++
++ if (lkey == 0x7FFF) {
++ ret = 0;
++ goto bail;
++ }
++
++ /* Look for an empty slot or a matching PKEY. */
++ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
++ if (!dd->ipath_pkeys[i]) {
++ any++;
++ continue;
++ }
++ /* If it matches exactly, try to increment the ref count */
++ if (dd->ipath_pkeys[i] == key) {
++ if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
++ ret = 0;
++ goto bail;
++ }
++ /* Lost the race. Look for an empty slot below. */
++ atomic_dec(&dd->ipath_pkeyrefs[i]);
++ any++;
++ }
++ /*
++ * It makes no sense to have both the limited and unlimited
++ * PKEY set at the same time since the unlimited one will
++ * disable the limited one.
++ */
++ if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
++ ret = -EEXIST;
++ goto bail;
++ }
++ }
++ if (!any) {
++ ret = -EBUSY;
++ goto bail;
++ }
++ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
++ if (!dd->ipath_pkeys[i] &&
++ atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
++ /* for ipathstats, etc. */
++ ipath_stats.sps_pkeys[i] = lkey;
++ dd->ipath_pkeys[i] = key;
++ ret = 1;
++ goto bail;
++ }
++ }
++ ret = -EBUSY;
++
++bail:
++ return ret;
++}
++
++/**
++ * set_pkeys - set the PKEY table for port 0
++ * @dd: the infinipath device
++ * @pkeys: the PKEY table
++ */
++static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys)
++{
++ struct ipath_portdata *pd;
++ int i;
++ int changed = 0;
++
++ pd = dd->ipath_pd[0];
++
++ for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
++ u16 key = pkeys[i];
++ u16 okey = pd->port_pkeys[i];
++
++ if (key == okey)
++ continue;
++ /*
++ * The value of this PKEY table entry is changing.
++ * Remove the old entry in the hardware's array of PKEYs.
++ */
++ if (okey & 0x7FFF)
++ changed |= rm_pkey(dd, okey);
++ if (key & 0x7FFF) {
++ int ret = add_pkey(dd, key);
++
++ if (ret < 0)
++ key = 0;
++ else
++ changed |= ret;
++ }
++ pd->port_pkeys[i] = key;
++ }
++ if (changed) {
++ u64 pkey;
++
++ pkey = (u64) dd->ipath_pkeys[0] |
++ ((u64) dd->ipath_pkeys[1] << 16) |
++ ((u64) dd->ipath_pkeys[2] << 32) |
++ ((u64) dd->ipath_pkeys[3] << 48);
++ ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
++ (unsigned long long) pkey);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
++ pkey);
++ }
++ return 0;
++}
++
+ static int recv_subn_set_pkeytable(struct ib_smp *smp,
+ struct ib_device *ibdev)
+ {
+@@ -500,13 +756,12 @@ static int recv_subn_set_pkeytable(struc
+ __be16 *p = (__be16 *) smp->data;
+ u16 *q = (u16 *) smp->data;
+ struct ipath_ibdev *dev = to_idev(ibdev);
+- unsigned i, n = ipath_layer_get_npkeys(dev->dd);
++ unsigned i, n = ipath_get_npkeys(dev->dd);
+
+ for (i = 0; i < n; i++)
+ q[i] = be16_to_cpu(p[i]);
+
+- if (startpx != 0 ||
+- ipath_layer_set_pkeys(dev->dd, q) != 0)
++ if (startpx != 0 || set_pkeys(dev->dd, q) != 0)
+ smp->status |= IB_SMP_INVALID_FIELD;
+
+ return recv_subn_get_pkeytable(smp, ibdev);
+@@ -844,10 +1099,10 @@ static int recv_pma_get_portcounters(str
+ struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
+ pmp->data;
+ struct ipath_ibdev *dev = to_idev(ibdev);
+- struct ipath_layer_counters cntrs;
++ struct ipath_verbs_counters cntrs;
+ u8 port_select = p->port_select;
+
+- ipath_layer_get_counters(dev->dd, &cntrs);
++ ipath_get_counters(dev->dd, &cntrs);
+
+ /* Adjust counters for any resets done. */
+ cntrs.symbol_error_counter -= dev->z_symbol_error_counter;
+@@ -944,8 +1199,8 @@ static int recv_pma_get_portcounters_ext
+ u64 swords, rwords, spkts, rpkts, xwait;
+ u8 port_select = p->port_select;
+
+- ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
+- &rpkts, &xwait);
++ ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
++ &rpkts, &xwait);
+
+ /* Adjust counters for any resets done. */
+ swords -= dev->z_port_xmit_data;
+@@ -978,13 +1233,13 @@ static int recv_pma_set_portcounters(str
+ struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
+ pmp->data;
+ struct ipath_ibdev *dev = to_idev(ibdev);
+- struct ipath_layer_counters cntrs;
++ struct ipath_verbs_counters cntrs;
+
+ /*
+ * Since the HW doesn't support clearing counters, we save the
+ * current count and subtract it from future responses.
+ */
+- ipath_layer_get_counters(dev->dd, &cntrs);
++ ipath_get_counters(dev->dd, &cntrs);
+
+ if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR)
+ dev->z_symbol_error_counter = cntrs.symbol_error_counter;
+@@ -1041,8 +1296,8 @@ static int recv_pma_set_portcounters_ext
+ struct ipath_ibdev *dev = to_idev(ibdev);
+ u64 swords, rwords, spkts, rpkts, xwait;
+
+- ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
+- &rpkts, &xwait);
++ ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
++ &rpkts, &xwait);
+
+ if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA)
+ dev->z_port_xmit_data = swords;
+diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
+new file mode 100644
+index 0000000..a82157d
+--- /dev/null
++++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
+@@ -0,0 +1,121 @@
++/*
++ * Copyright (c) 2006 QLogic, 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
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/vmalloc.h>
++#include <linux/mm.h>
++#include <linux/errno.h>
++#include <asm/pgtable.h>
++
++#include "ipath_verbs.h"
++
++/**
++ * ipath_release_mmap_info - free mmap info structure
++ * @ref: a pointer to the kref within struct ipath_mmap_info
++ */
++void ipath_release_mmap_info(struct kref *ref)
++{
++ struct ipath_mmap_info *ip =
++ container_of(ref, struct ipath_mmap_info, ref);
++
++ vfree(ip->obj);
++ kfree(ip);
++}
++
++/*
++ * open and close keep track of how many times the CQ is mapped,
++ * to avoid releasing it.
++ */
++static void ipath_vma_open(struct vm_area_struct *vma)
++{
++ struct ipath_mmap_info *ip = vma->vm_private_data;
++
++ kref_get(&ip->ref);
++ ip->mmap_cnt++;
++}
++
++static void ipath_vma_close(struct vm_area_struct *vma)
++{
++ struct ipath_mmap_info *ip = vma->vm_private_data;
++
++ ip->mmap_cnt--;
++ kref_put(&ip->ref, ipath_release_mmap_info);
++}
++
++static struct vm_operations_struct ipath_vm_ops = {
++ .open = ipath_vma_open,
++ .close = ipath_vma_close,
++};
++
++/**
++ * ipath_mmap - create a new mmap region
++ * @context: the IB user context of the process making the mmap() call
++ * @vma: the VMA to be initialized
++ * Return zero if the mmap is OK. Otherwise, return an errno.
++ */
++int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
++{
++ struct ipath_ibdev *dev = to_idev(context->device);
++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++ unsigned long size = vma->vm_end - vma->vm_start;
++ struct ipath_mmap_info *ip, **pp;
++ int ret = -EINVAL;
++
++ /*
++ * Search the device's list of objects waiting for a mmap call.
++ * Normally, this list is very short since a call to create a
++ * CQ, QP, or SRQ is soon followed by a call to mmap().
++ */
++ spin_lock_irq(&dev->pending_lock);
++ for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) {
++ /* Only the creator is allowed to mmap the object */
++ if (context != ip->context || (void *) offset != ip->obj)
++ continue;
++ /* Don't allow a mmap larger than the object. */
++ if (size > ip->size)
++ break;
++
++ *pp = ip->next;
++ spin_unlock_irq(&dev->pending_lock);
++
++ ret = remap_vmalloc_range(vma, ip->obj, 0);
++ if (ret)
++ goto done;
++ vma->vm_ops = &ipath_vm_ops;
++ vma->vm_private_data = ip;
++ ipath_vma_open(vma);
++ goto done;
++ }
++ spin_unlock_irq(&dev->pending_lock);
++done:
++ return ret;
++}
+diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
+index 4ac31a5..a0673c1 100644
+--- a/drivers/infiniband/hw/ipath/ipath_mr.c
++++ b/drivers/infiniband/hw/ipath/ipath_mr.c
+@@ -36,6 +36,18 @@
+
+ #include "ipath_verbs.h"
+
++/* Fast memory region */
++struct ipath_fmr {
++ struct ib_fmr ibfmr;
++ u8 page_shift;
++ struct ipath_mregion mr; /* must be last */
++};
++
++static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr)
++{
++ return container_of(ibfmr, struct ipath_fmr, ibfmr);
++}
++
+ /**
+ * ipath_get_dma_mr - get a DMA memory region
+ * @pd: protection domain for this memory region
+@@ -126,6 +138,7 @@ struct ib_mr *ipath_reg_phys_mr(struct i
+ goto bail;
+ }
+
++ mr->mr.pd = pd;
+ mr->mr.user_base = *iova_start;
+ mr->mr.iova = *iova_start;
+ mr->mr.length = 0;
+@@ -185,6 +198,7 @@ struct ib_mr *ipath_reg_user_mr(struct i
+ goto bail;
+ }
+
++ mr->mr.pd = pd;
+ mr->mr.user_base = region->user_base;
+ mr->mr.iova = region->virt_base;
+ mr->mr.length = region->length;
+@@ -277,6 +291,7 @@ struct ib_fmr *ipath_alloc_fmr(struct ib
+ * Resources are allocated but no valid mapping (RKEY can't be
+ * used).
+ */
++ fmr->mr.pd = pd;
+ fmr->mr.user_base = 0;
+ fmr->mr.iova = 0;
+ fmr->mr.length = 0;
+diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_pe800.c
+deleted file mode 100644
+index b83f66d..0000000
+--- a/drivers/infiniband/hw/ipath/ipath_pe800.c
++++ /dev/null
+@@ -1,1254 +0,0 @@
+-/*
+- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
+- * 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.
+- */
+-/*
+- * This file contains all of the code that is specific to the
+- * InfiniPath PE-800 chip.
+- */
+-
+-#include <linux/interrupt.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-
+-
+-#include "ipath_kernel.h"
+-#include "ipath_registers.h"
+-
+-/*
+- * This file contains all the chip-specific register information and
+- * access functions for the QLogic InfiniPath PE800, the PCI-Express chip.
+- *
+- * This lists the InfiniPath PE800 registers, in the actual chip layout.
+- * This structure should never be directly accessed.
+- */
+-struct _infinipath_do_not_use_kernel_regs {
+- unsigned long long Revision;
+- unsigned long long Control;
+- unsigned long long PageAlign;
+- unsigned long long PortCnt;
+- unsigned long long DebugPortSelect;
+- unsigned long long Reserved0;
+- unsigned long long SendRegBase;
+- unsigned long long UserRegBase;
+- unsigned long long CounterRegBase;
+- unsigned long long Scratch;
+- unsigned long long Reserved1;
+- unsigned long long Reserved2;
+- unsigned long long IntBlocked;
+- unsigned long long IntMask;
+- unsigned long long IntStatus;
+- unsigned long long IntClear;
+- unsigned long long ErrorMask;
+- unsigned long long ErrorStatus;
+- unsigned long long ErrorClear;
+- unsigned long long HwErrMask;
+- unsigned long long HwErrStatus;
+- unsigned long long HwErrClear;
+- unsigned long long HwDiagCtrl;
+- unsigned long long MDIO;
+- unsigned long long IBCStatus;
+- unsigned long long IBCCtrl;
+- unsigned long long ExtStatus;
+- unsigned long long ExtCtrl;
+- unsigned long long GPIOOut;
+- unsigned long long GPIOMask;
+- unsigned long long GPIOStatus;
+- unsigned long long GPIOClear;
+- unsigned long long RcvCtrl;
+- unsigned long long RcvBTHQP;
+- unsigned long long RcvHdrSize;
+- unsigned long long RcvHdrCnt;
+- unsigned long long RcvHdrEntSize;
+- unsigned long long RcvTIDBase;
+- unsigned long long RcvTIDCnt;
+- unsigned long long RcvEgrBase;
+- unsigned long long RcvEgrCnt;
+- unsigned long long RcvBufBase;
+- unsigned long long RcvBufSize;
+- unsigned long long RxIntMemBase;
+- unsigned long long RxIntMemSize;
+- unsigned long long RcvPartitionKey;
+- unsigned long long Reserved3;
+- unsigned long long RcvPktLEDCnt;
+- unsigned long long Reserved4[8];
+- unsigned long long SendCtrl;
+- unsigned long long SendPIOBufBase;
+- unsigned long long SendPIOSize;
+- unsigned long long SendPIOBufCnt;
+- unsigned long long SendPIOAvailAddr;
+- unsigned long long TxIntMemBase;
+- unsigned long long TxIntMemSize;
+- unsigned long long Reserved5;
+- unsigned long long PCIeRBufTestReg0;
+- unsigned long long PCIeRBufTestReg1;
+- unsigned long long Reserved51[6];
+- unsigned long long SendBufferError;
+- unsigned long long SendBufferErrorCONT1;
+- unsigned long long Reserved6SBE[6];
+- unsigned long long RcvHdrAddr0;
+- unsigned long long RcvHdrAddr1;
+- unsigned long long RcvHdrAddr2;
+- unsigned long long RcvHdrAddr3;
+- unsigned long long RcvHdrAddr4;
+- unsigned long long Reserved7RHA[11];
+- unsigned long long RcvHdrTailAddr0;
+- unsigned long long RcvHdrTailAddr1;
+- unsigned long long RcvHdrTailAddr2;
+- unsigned long long RcvHdrTailAddr3;
+- unsigned long long RcvHdrTailAddr4;
+- unsigned long long Reserved8RHTA[11];
+- unsigned long long Reserved9SW[8];
+- unsigned long long SerdesConfig0;
+- unsigned long long SerdesConfig1;
+- unsigned long long SerdesStatus;
+- unsigned long long XGXSConfig;
+- unsigned long long IBPLLCfg;
+- unsigned long long Reserved10SW2[3];
+- unsigned long long PCIEQ0SerdesConfig0;
+- unsigned long long PCIEQ0SerdesConfig1;
+- unsigned long long PCIEQ0SerdesStatus;
+- unsigned long long Reserved11;
+- unsigned long long PCIEQ1SerdesConfig0;
+- unsigned long long PCIEQ1SerdesConfig1;
+- unsigned long long PCIEQ1SerdesStatus;
+- unsigned long long Reserved12;
+-};
+-
+-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
+- _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+-#define IPATH_CREG_OFFSET(field) (offsetof( \
+- struct infinipath_counters, field) / sizeof(u64))
+-
+-static const struct ipath_kregs ipath_pe_kregs = {
+- .kr_control = IPATH_KREG_OFFSET(Control),
+- .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
+- .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
+- .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
+- .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
+- .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
+- .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
+- .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
+- .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
+- .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
+- .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
+- .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
+- .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
+- .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
+- .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
+- .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
+- .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
+- .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
+- .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
+- .kr_intclear = IPATH_KREG_OFFSET(IntClear),
+- .kr_intmask = IPATH_KREG_OFFSET(IntMask),
+- .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
+- .kr_mdio = IPATH_KREG_OFFSET(MDIO),
+- .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
+- .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
+- .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
+- .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
+- .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
+- .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
+- .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
+- .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
+- .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
+- .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
+- .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
+- .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
+- .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
+- .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
+- .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
+- .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
+- .kr_revision = IPATH_KREG_OFFSET(Revision),
+- .kr_scratch = IPATH_KREG_OFFSET(Scratch),
+- .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
+- .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
+- .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
+- .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
+- .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
+- .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
+- .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
+- .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
+- .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
+- .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
+- .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
+- .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
+- .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
+- .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
+- .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg),
+-
+- /*
+- * These should not be used directly via ipath_read_kreg64(),
+- * use them with ipath_read_kreg64_port()
+- */
+- .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
+- .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
+-
+- /* This group is pe-800-specific; and used only in this file */
+- /* The rcvpktled register controls one of the debug port signals, so
+- * a packet activity LED can be connected to it. */
+- .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt),
+- .kr_pcierbuftestreg0 = IPATH_KREG_OFFSET(PCIeRBufTestReg0),
+- .kr_pcierbuftestreg1 = IPATH_KREG_OFFSET(PCIeRBufTestReg1),
+- .kr_pcieq0serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig0),
+- .kr_pcieq0serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig1),
+- .kr_pcieq0serdesstatus = IPATH_KREG_OFFSET(PCIEQ0SerdesStatus),
+- .kr_pcieq1serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig0),
+- .kr_pcieq1serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig1),
+- .kr_pcieq1serdesstatus = IPATH_KREG_OFFSET(PCIEQ1SerdesStatus)
+-};
+-
+-static const struct ipath_cregs ipath_pe_cregs = {
+- .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
+- .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
+- .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
+- .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
+- .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
+- .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
+- .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
+- .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
+- .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
+- .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
+- .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
+- .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
+- .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
+- .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
+- .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
+- .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
+- .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
+- .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
+- .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
+- .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
+- .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
+- .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
+- .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
+- .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
+- .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
+- .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
+- .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
+- .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
+- .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
+- .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
+- .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
+- .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
+- .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
+-};
+-
+-/* kr_intstatus, kr_intclear, kr_intmask bits */
+-#define INFINIPATH_I_RCVURG_MASK 0x1F
+-#define INFINIPATH_I_RCVAVAIL_MASK 0x1F
+-
+-/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
+-#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x000000000000003fULL
+-#define INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT 0
+-#define INFINIPATH_HWE_PCIEPOISONEDTLP 0x0000000010000000ULL
+-#define INFINIPATH_HWE_PCIECPLTIMEOUT 0x0000000020000000ULL
+-#define INFINIPATH_HWE_PCIEBUSPARITYXTLH 0x0000000040000000ULL
+-#define INFINIPATH_HWE_PCIEBUSPARITYXADM 0x0000000080000000ULL
+-#define INFINIPATH_HWE_PCIEBUSPARITYRADM 0x0000000100000000ULL
+-#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL
+-#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL
+-#define INFINIPATH_HWE_PCIE1PLLFAILED 0x0400000000000000ULL
+-#define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL
+-#define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL
+-
+-/* kr_extstatus bits */
+-#define INFINIPATH_EXTS_FREQSEL 0x2
+-#define INFINIPATH_EXTS_SERDESSEL 0x4
+-#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000
+-#define INFINIPATH_EXTS_MEMBIST_FOUND 0x0000000000008000
+-
+-#define _IPATH_GPIO_SDA_NUM 1
+-#define _IPATH_GPIO_SCL_NUM 0
+-
+-#define IPATH_GPIO_SDA (1ULL << \
+- (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+-#define IPATH_GPIO_SCL (1ULL << \
+- (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+-
+-/**
+- * ipath_pe_handle_hwerrors - display hardware errors.
+- * @dd: the infinipath device
+- * @msg: the output buffer
+- * @msgl: the size of the output buffer
+- *
+- * Use same msg buffer as regular errors to avoid excessive stack
+- * use. Most hardware errors are catastrophic, but for right now,
+- * we'll print them and continue. We reuse the same message buffer as
+- * ipath_handle_errors() to avoid excessive stack usage.
+- */
+-static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
+- size_t msgl)
+-{
+- ipath_err_t hwerrs;
+- u32 bits, ctrl;
+- int isfatal = 0;
+- char bitsmsg[64];
+-
+- hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
+- if (!hwerrs) {
+- /*
+- * better than printing cofusing messages
+- * This seems to be related to clearing the crc error, or
+- * the pll error during init.
+- */
+- ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
+- return;
+- } else if (hwerrs == ~0ULL) {
+- ipath_dev_err(dd, "Read of hardware error status failed "
+- "(all bits set); ignoring\n");
+- return;
+- }
+- ipath_stats.sps_hwerrs++;
+-
+- /* Always clear the error status register, except MEMBISTFAIL,
+- * regardless of whether we continue or stop using the chip.
+- * We want that set so we know it failed, even across driver reload.
+- * We'll still ignore it in the hwerrmask. We do this partly for
+- * diagnostics, but also for support */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
+- hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
+-
+- hwerrs &= dd->ipath_hwerrmask;
+-
+- /*
+- * make sure we get this much out, unless told to be quiet,
+- * or it's occurred within the last 5 seconds
+- */
+- if ((hwerrs & ~dd->ipath_lasthwerror) ||
+- (ipath_debug & __IPATH_VERBDBG))
+- dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
+- "(cleared)\n", (unsigned long long) hwerrs);
+- dd->ipath_lasthwerror |= hwerrs;
+-
+- if (hwerrs & ~infinipath_hwe_bitsextant)
+- ipath_dev_err(dd, "hwerror interrupt with unknown errors "
+- "%llx set\n", (unsigned long long)
+- (hwerrs & ~infinipath_hwe_bitsextant));
+-
+- ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
+- if (ctrl & INFINIPATH_C_FREEZEMODE) {
+- if (hwerrs) {
+- /*
+- * if any set that we aren't ignoring only make the
+- * complaint once, in case it's stuck or recurring,
+- * and we get here multiple times
+- */
+- if (dd->ipath_flags & IPATH_INITTED) {
+- ipath_dev_err(dd, "Fatal Error (freeze "
+- "mode), no longer usable\n");
+- isfatal = 1;
+- }
+- /*
+- * Mark as having had an error for driver, and also
+- * for /sys and status word mapped to user programs.
+- * This marks unit as not usable, until reset
+- */
+- *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
+- *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
+- dd->ipath_flags &= ~IPATH_INITTED;
+- } else {
+- ipath_dbg("Clearing freezemode on ignored hardware "
+- "error\n");
+- ctrl &= ~INFINIPATH_C_FREEZEMODE;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+- ctrl);
+- }
+- }
+-
+- *msg = '\0';
+-
+- if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
+- strlcat(msg, "[Memory BIST test failed, PE-800 unusable]",
+- msgl);
+- /* ignore from now on, so disable until driver reloaded */
+- *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
+- dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- }
+- if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
+- << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
+- bits = (u32) ((hwerrs >>
+- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
+- INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
+- snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
+- bits);
+- strlcat(msg, bitsmsg, msgl);
+- }
+- if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
+- << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
+- bits = (u32) ((hwerrs >>
+- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
+- INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
+- snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
+- bits);
+- strlcat(msg, bitsmsg, msgl);
+- }
+- if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
+- << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
+- bits = (u32) ((hwerrs >>
+- INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) &
+- INFINIPATH_HWE_PCIEMEMPARITYERR_MASK);
+- snprintf(bitsmsg, sizeof bitsmsg,
+- "[PCIe Mem Parity Errs %x] ", bits);
+- strlcat(msg, bitsmsg, msgl);
+- }
+- if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
+- strlcat(msg, "[IB2IPATH Parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
+- strlcat(msg, "[IPATH2IB Parity]", msgl);
+-
+-#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
+- INFINIPATH_HWE_COREPLL_RFSLIP )
+-
+- if (hwerrs & _IPATH_PLL_FAIL) {
+- snprintf(bitsmsg, sizeof bitsmsg,
+- "[PLL failed (%llx), PE-800 unusable]",
+- (unsigned long long) hwerrs & _IPATH_PLL_FAIL);
+- strlcat(msg, bitsmsg, msgl);
+- /* ignore from now on, so disable until driver reloaded */
+- dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- }
+-
+- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
+- /*
+- * If it occurs, it is left masked since the eternal
+- * interface is unused
+- */
+- dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
+- dd->ipath_hwerrmask);
+- }
+-
+- if (hwerrs & INFINIPATH_HWE_PCIEPOISONEDTLP)
+- strlcat(msg, "[PCIe Poisoned TLP]", msgl);
+- if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT)
+- strlcat(msg, "[PCIe completion timeout]", msgl);
+-
+- /*
+- * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
+- * parity or memory parity error failures, because most likely we
+- * won't be able to talk to the core of the chip. Nonetheless, we
+- * might see them, if they are in parts of the PCIe core that aren't
+- * essential.
+- */
+- if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED)
+- strlcat(msg, "[PCIePLL1]", msgl);
+- if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED)
+- strlcat(msg, "[PCIePLL0]", msgl);
+- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH)
+- strlcat(msg, "[PCIe XTLH core parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM)
+- strlcat(msg, "[PCIe ADM TX core parity]", msgl);
+- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM)
+- strlcat(msg, "[PCIe ADM RX core parity]", msgl);
+-
+- if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
+- strlcat(msg, "[Rx Dsync]", msgl);
+- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
+- strlcat(msg, "[SerDes PLL]", msgl);
+-
+- ipath_dev_err(dd, "%s hardware error\n", msg);
+- if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) {
+- /*
+- * for /sys status file ; if no trailing } is copied, we'll
+- * know it was truncated.
+- */
+- snprintf(dd->ipath_freezemsg, dd->ipath_freezelen,
+- "{%s}", msg);
+- }
+-}
+-
+-/**
+- * ipath_pe_boardname - fill in the board name
+- * @dd: the infinipath device
+- * @name: the output buffer
+- * @namelen: the size of the output buffer
+- *
+- * info is based on the board revision register
+- */
+-static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
+- size_t namelen)
+-{
+- char *n = NULL;
+- u8 boardrev = dd->ipath_boardrev;
+- int ret;
+-
+- switch (boardrev) {
+- case 0:
+- n = "InfiniPath_Emulation";
+- break;
+- case 1:
+- n = "InfiniPath_PE-800-Bringup";
+- break;
+- case 2:
+- n = "InfiniPath_PE-880";
+- break;
+- case 3:
+- n = "InfiniPath_PE-850";
+- break;
+- case 4:
+- n = "InfiniPath_PE-860";
+- break;
+- default:
+- ipath_dev_err(dd,
+- "Don't yet know about board with ID %u\n",
+- boardrev);
+- snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u",
+- boardrev);
+- break;
+- }
+- if (n)
+- snprintf(name, namelen, "%s", n);
+-
+- if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) {
+- ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n",
+- dd->ipath_majrev, dd->ipath_minrev);
+- ret = 1;
+- } else
+- ret = 0;
+-
+- return ret;
+-}
+-
+-/**
+- * ipath_pe_init_hwerrors - enable hardware errors
+- * @dd: the infinipath device
+- *
+- * now that we have finished initializing everything that might reasonably
+- * cause a hardware error, and cleared those errors bits as they occur,
+- * we can enable hardware errors in the mask (potentially enabling
+- * freeze mode), and enable hardware errors as errors (along with
+- * everything else) in errormask
+- */
+-static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
+-{
+- ipath_err_t val;
+- u64 extsval;
+-
+- extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
+-
+- if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
+- ipath_dev_err(dd, "MemBIST did not complete!\n");
+-
+- val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */
+-
+- if (!dd->ipath_boardrev) // no PLL for Emulator
+- val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
+-
+- /* workaround bug 9460 in internal interface bus parity checking */
+- val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
+-
+- dd->ipath_hwerrmask = val;
+-}
+-
+-/**
+- * ipath_pe_bringup_serdes - bring up the serdes
+- * @dd: the infinipath device
+- */
+-static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
+-{
+- u64 val, tmp, config1;
+- int ret = 0, change = 0;
+-
+- ipath_dbg("Trying to bringup serdes\n");
+-
+- if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
+- INFINIPATH_HWE_SERDESPLLFAILED) {
+- ipath_dbg("At start, serdes PLL failed bit set "
+- "in hwerrstatus, clearing and continuing\n");
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
+- INFINIPATH_HWE_SERDESPLLFAILED);
+- }
+-
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
+- config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
+-
+- ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, "
+- "xgxsconfig %llx\n", (unsigned long long) val,
+- (unsigned long long) config1, (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
+-
+- /*
+- * Force reset on, also set rxdetect enable. Must do before reading
+- * serdesstatus at least for simulation, or some of the bits in
+- * serdes status will come back as undefined and cause simulation
+- * failures
+- */
+- val |= INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RXDETECT_EN
+- | INFINIPATH_SERDC0_L1PWR_DN;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
+- /* be sure chip saw it */
+- tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+- udelay(5); /* need pll reset set at least for a bit */
+- /*
+- * after PLL is reset, set the per-lane Resets and TxIdle and
+- * clear the PLL reset and rxdetect (to get falling edge).
+- * Leave L1PWR bits set (permanently)
+- */
+- val &= ~(INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_RESET_PLL
+- | INFINIPATH_SERDC0_L1PWR_DN);
+- val |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE;
+- ipath_cdbg(VERBOSE, "Clearing pll reset and setting lane resets "
+- "and txidle (%llx)\n", (unsigned long long) val);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
+- /* be sure chip saw it */
+- tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+- /* need PLL reset clear for at least 11 usec before lane
+- * resets cleared; give it a few more to be sure */
+- udelay(15);
+- val &= ~(INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE);
+-
+- ipath_cdbg(VERBOSE, "Clearing lane resets and txidle "
+- "(writing %llx)\n", (unsigned long long) val);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
+- /* be sure chip saw it */
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+-
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+- if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
+- INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
+- val &=
+- ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
+- INFINIPATH_XGXS_MDIOADDR_SHIFT);
+- /* MDIO address 3 */
+- val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
+- change = 1;
+- }
+- if (val & INFINIPATH_XGXS_RESET) {
+- val &= ~INFINIPATH_XGXS_RESET;
+- change = 1;
+- }
+- if (change)
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+-
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
+-
+- /* clear current and de-emphasis bits */
+- config1 &= ~0x0ffffffff00ULL;
+- /* set current to 20ma */
+- config1 |= 0x00000000000ULL;
+- /* set de-emphasis to -5.68dB */
+- config1 |= 0x0cccc000000ULL;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1);
+-
+- ipath_cdbg(VERBOSE, "done: SerDes status config0=%llx "
+- "config1=%llx, sstatus=%llx xgxs=%llx\n",
+- (unsigned long long) val, (unsigned long long) config1,
+- (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
+- (unsigned long long)
+- ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
+-
+- if (!ipath_waitfor_mdio_cmdready(dd)) {
+- ipath_write_kreg(
+- dd, dd->ipath_kregs->kr_mdio,
+- ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
+- IPATH_MDIO_CTRL_XGXS_REG_8, 0));
+- if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
+- IPATH_MDIO_DATAVALID, &val))
+- ipath_dbg("Never got MDIO data for XGXS "
+- "status read\n");
+- else
+- ipath_cdbg(VERBOSE, "MDIO Read reg8, "
+- "'bank' 31 %x\n", (u32) val);
+- } else
+- ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
+-
+- return ret;
+-}
+-
+-/**
+- * ipath_pe_quiet_serdes - set serdes to txidle
+- * @dd: the infinipath device
+- * Called when driver is being unloaded
+- */
+-static void ipath_pe_quiet_serdes(struct ipath_devdata *dd)
+-{
+- u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
+-
+- val |= INFINIPATH_SERDC0_TXIDLE;
+- ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
+- (unsigned long long) val);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
+-}
+-
+-/* this is not yet needed on the PE800, so just return 0. */
+-static int ipath_pe_intconfig(struct ipath_devdata *dd)
+-{
+- return 0;
+-}
+-
+-/**
+- * ipath_setup_pe_setextled - set the state of the two external LEDs
+- * @dd: the infinipath device
+- * @lst: the L state
+- * @ltst: the LT state
+-
+- * These LEDs indicate the physical and logical state of IB link.
+- * For this chip (at least with recommended board pinouts), LED1
+- * is Yellow (logical state) and LED2 is Green (physical state),
+- *
+- * Note: We try to match the Mellanox HCA LED behavior as best
+- * we can. Green indicates physical link state is OK (something is
+- * plugged in, and we can train).
+- * Amber indicates the link is logically up (ACTIVE).
+- * Mellanox further blinks the amber LED to indicate data packet
+- * activity, but we have no hardware support for that, so it would
+- * require waking up every 10-20 msecs and checking the counters
+- * on the chip, and then turning the LED off if appropriate. That's
+- * visible overhead, so not something we will do.
+- *
+- */
+-static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
+- u64 ltst)
+-{
+- u64 extctl;
+-
+- /* the diags use the LED to indicate diag info, so we leave
+- * the external LED alone when the diags are running */
+- if (ipath_diag_inuse)
+- return;
+-
+- extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
+- INFINIPATH_EXTC_LED2PRIPORT_ON);
+-
+- if (ltst & INFINIPATH_IBCS_LT_STATE_LINKUP)
+- extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
+- if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
+- extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
+- dd->ipath_extctrl = extctl;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
+-}
+-
+-/**
+- * ipath_setup_pe_cleanup - clean up any per-chip chip-specific stuff
+- * @dd: the infinipath device
+- *
+- * This is called during driver unload.
+- * We do the pci_disable_msi here, not in generic code, because it
+- * isn't used for the HT-400. If we do end up needing pci_enable_msi
+- * at some point in the future for HT-400, we'll move the call back
+- * into the main init_one code.
+- */
+-static void ipath_setup_pe_cleanup(struct ipath_devdata *dd)
+-{
+- dd->ipath_msi_lo = 0; /* just in case unload fails */
+- pci_disable_msi(dd->pcidev);
+-}
+-
+-/**
+- * ipath_setup_pe_config - setup PCIe config related stuff
+- * @dd: the infinipath device
+- * @pdev: the PCI device
+- *
+- * The pci_enable_msi() call will fail on systems with MSI quirks
+- * such as those with AMD8131, even if the device of interest is not
+- * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed
+- * late in 2.6.16).
+- * All that can be done is to edit the kernel source to remove the quirk
+- * check until that is fixed.
+- * We do not need to call enable_msi() for our HyperTransport chip (HT-400),
+- * even those it uses MSI, and we want to avoid the quirk warning, so
+- * So we call enable_msi only for the PE-800. If we do end up needing
+- * pci_enable_msi at some point in the future for HT-400, we'll move the
+- * call back into the main init_one code.
+- * We save the msi lo and hi values, so we can restore them after
+- * chip reset (the kernel PCI infrastructure doesn't yet handle that
+- * correctly).
+- */
+-static int ipath_setup_pe_config(struct ipath_devdata *dd,
+- struct pci_dev *pdev)
+-{
+- int pos, ret;
+-
+- dd->ipath_msi_lo = 0; /* used as a flag during reset processing */
+- ret = pci_enable_msi(dd->pcidev);
+- if (ret)
+- ipath_dev_err(dd, "pci_enable_msi failed: %d, "
+- "interrupts may not work\n", ret);
+- /* continue even if it fails, we may still be OK... */
+-
+- if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
+- u16 control;
+- pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
+- &dd->ipath_msi_lo);
+- pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
+- &dd->ipath_msi_hi);
+- pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
+- &control);
+- /* now save the data (vector) info */
+- pci_read_config_word(dd->pcidev,
+- pos + ((control & PCI_MSI_FLAGS_64BIT)
+- ? 12 : 8),
+- &dd->ipath_msi_data);
+- ipath_cdbg(VERBOSE, "Read msi data 0x%x from config offset "
+- "0x%x, control=0x%x\n", dd->ipath_msi_data,
+- pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
+- control);
+- /* we save the cachelinesize also, although it doesn't
+- * really matter */
+- pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
+- &dd->ipath_pci_cacheline);
+- } else
+- ipath_dev_err(dd, "Can't find MSI capability, "
+- "can't save MSI settings for reset\n");
+- if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP))) {
+- u16 linkstat;
+- pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA,
+- &linkstat);
+- linkstat >>= 4;
+- linkstat &= 0x1f;
+- if (linkstat != 8)
+- ipath_dev_err(dd, "PCIe width %u, "
+- "performance reduced\n", linkstat);
+- }
+- else
+- ipath_dev_err(dd, "Can't find PCI Express "
+- "capability!\n");
+- return 0;
+-}
+-
+-static void ipath_init_pe_variables(void)
+-{
+- /*
+- * bits for selecting i2c direction and values,
+- * used for I2C serial flash
+- */
+- ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+- ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+- ipath_gpio_sda = IPATH_GPIO_SDA;
+- ipath_gpio_scl = IPATH_GPIO_SCL;
+-
+- /* variables for sanity checking interrupt and errors */
+- infinipath_hwe_bitsextant =
+- (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
+- (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<
+- INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |
+- INFINIPATH_HWE_PCIE1PLLFAILED |
+- INFINIPATH_HWE_PCIE0PLLFAILED |
+- INFINIPATH_HWE_PCIEPOISONEDTLP |
+- INFINIPATH_HWE_PCIECPLTIMEOUT |
+- INFINIPATH_HWE_PCIEBUSPARITYXTLH |
+- INFINIPATH_HWE_PCIEBUSPARITYXADM |
+- INFINIPATH_HWE_PCIEBUSPARITYRADM |
+- INFINIPATH_HWE_MEMBISTFAILED |
+- INFINIPATH_HWE_COREPLL_FBSLIP |
+- INFINIPATH_HWE_COREPLL_RFSLIP |
+- INFINIPATH_HWE_SERDESPLLFAILED |
+- INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
+- INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
+- infinipath_i_bitsextant =
+- (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
+- (INFINIPATH_I_RCVAVAIL_MASK <<
+- INFINIPATH_I_RCVAVAIL_SHIFT) |
+- INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
+- INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
+- infinipath_e_bitsextant =
+- INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
+- INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
+- INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
+- INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
+- INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
+- INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
+- INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
+- INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
+- INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
+- INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
+- INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
+- INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
+- INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
+- INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
+- INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
+- INFINIPATH_E_HARDWARE;
+-
+- infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+- infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+-}
+-
+-/* setup the MSI stuff again after a reset. I'd like to just call
+- * pci_enable_msi() and request_irq() again, but when I do that,
+- * the MSI enable bit doesn't get set in the command word, and
+- * we switch to to a different interrupt vector, which is confusing,
+- * so I instead just do it all inline. Perhaps somehow can tie this
+- * into the PCIe hotplug support at some point
+- * Note, because I'm doing it all here, I don't call pci_disable_msi()
+- * or free_irq() at the start of ipath_setup_pe_reset().
+- */
+-static int ipath_reinit_msi(struct ipath_devdata *dd)
+-{
+- int pos;
+- u16 control;
+- int ret;
+-
+- if (!dd->ipath_msi_lo) {
+- dev_info(&dd->pcidev->dev, "Can't restore MSI config, "
+- "initial setup failed?\n");
+- ret = 0;
+- goto bail;
+- }
+-
+- if (!(pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
+- ipath_dev_err(dd, "Can't find MSI capability, "
+- "can't restore MSI settings\n");
+- ret = 0;
+- goto bail;
+- }
+- ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
+- dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO);
+- pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
+- dd->ipath_msi_lo);
+- ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
+- dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI);
+- pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
+- dd->ipath_msi_hi);
+- pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control);
+- if (!(control & PCI_MSI_FLAGS_ENABLE)) {
+- ipath_cdbg(VERBOSE, "MSI control at off %x was %x, "
+- "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS,
+- control, control | PCI_MSI_FLAGS_ENABLE);
+- control |= PCI_MSI_FLAGS_ENABLE;
+- pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
+- control);
+- }
+- /* now rewrite the data (vector) info */
+- pci_write_config_word(dd->pcidev, pos +
+- ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
+- dd->ipath_msi_data);
+- /* we restore the cachelinesize also, although it doesn't really
+- * matter */
+- pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
+- dd->ipath_pci_cacheline);
+- /* and now set the pci master bit again */
+- pci_set_master(dd->pcidev);
+- ret = 1;
+-
+-bail:
+- return ret;
+-}
+-
+-/* This routine sleeps, so it can only be called from user context, not
+- * from interrupt context. If we need interrupt context, we can split
+- * it into two routines.
+-*/
+-static int ipath_setup_pe_reset(struct ipath_devdata *dd)
+-{
+- u64 val;
+- int i;
+- int ret;
+-
+- /* Use ERROR so it shows up in logs, etc. */
+- ipath_dev_err(dd, "Resetting PE-800 unit %u\n",
+- dd->ipath_unit);
+- /* keep chip from being accessed in a few places */
+- dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT);
+- val = dd->ipath_control | INFINIPATH_C_RESET;
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val);
+- mb();
+-
+- for (i = 1; i <= 5; i++) {
+- int r;
+- /* allow MBIST, etc. to complete; longer on each retry.
+- * We sometimes get machine checks from bus timeout if no
+- * response, so for now, make it *really* long.
+- */
+- msleep(1000 + (1 + i) * 2000);
+- if ((r =
+- pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
+- dd->ipath_pcibar0)))
+- ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n",
+- r);
+- if ((r =
+- pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
+- dd->ipath_pcibar1)))
+- ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n",
+- r);
+- /* now re-enable memory access */
+- if ((r = pci_enable_device(dd->pcidev)))
+- ipath_dev_err(dd, "pci_enable_device failed after "
+- "reset: %d\n", r);
+- /* whether it worked or not, mark as present, again */
+- dd->ipath_flags |= IPATH_PRESENT;
+- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);
+- if (val == dd->ipath_revision) {
+- ipath_cdbg(VERBOSE, "Got matching revision "
+- "register %llx on try %d\n",
+- (unsigned long long) val, i);
+- ret = ipath_reinit_msi(dd);
+- goto bail;
+- }
+- /* Probably getting -1 back */
+- ipath_dbg("Didn't get expected revision register, "
+- "got %llx, try %d\n", (unsigned long long) val,
+- i + 1);
+- }
+- ret = 0; /* failed */
+-
+-bail:
+- return ret;
+-}
+-
+-/**
+- * ipath_pe_put_tid - write a TID in chip
+- * @dd: the infinipath device
+- * @tidptr: pointer to the expected TID (in chip) to udpate
+- * @tidtype: 0 for eager, 1 for expected
+- * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
+- *
+- * This exists as a separate routine to allow for special locking etc.
+- * It's used for both the full cleanup on exit, as well as the normal
+- * setup and teardown.
+- */
+-static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
+- u32 type, unsigned long pa)
+-{
+- u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
+- unsigned long flags = 0; /* keep gcc quiet */
+-
+- if (pa != dd->ipath_tidinvalid) {
+- if (pa & ((1U << 11) - 1)) {
+- dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
+- "not 4KB aligned!\n", pa);
+- return;
+- }
+- pa >>= 11;
+- /* paranoia check */
+- if (pa & (7<<29))
+- ipath_dev_err(dd,
+- "BUG: Physical page address 0x%lx "
+- "has bits set in 31-29\n", pa);
+-
+- if (type == 0)
+- pa |= dd->ipath_tidtemplate;
+- else /* for now, always full 4KB page */
+- pa |= 2 << 29;
+- }
+-
+- /* workaround chip bug 9437 by writing each TID twice
+- * and holding a spinlock around the writes, so they don't
+- * intermix with other TID (eager or expected) writes
+- * Unfortunately, this call can be done from interrupt level
+- * for the port 0 eager TIDs, so we have to use irqsave
+- */
+- spin_lock_irqsave(&dd->ipath_tid_lock, flags);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);
+- if (dd->ipath_kregbase)
+- writel(pa, tidp32);
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xdeadbeef);
+- mmiowb();
+- spin_unlock_irqrestore(&dd->ipath_tid_lock, flags);
+-}
+-
+-/**
+- * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager
+- * @dd: the infinipath device
+- * @port: the port
+- *
+- * clear all TID entries for a port, expected and eager.
+- * Used from ipath_close(). On PE800, TIDs are only 32 bits,
+- * not 64, but they are still on 64 bit boundaries, so tidbase
+- * is declared as u64 * for the pointer math, even though we write 32 bits
+- */
+-static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
+-{
+- u64 __iomem *tidbase;
+- unsigned long tidinv;
+- int i;
+-
+- if (!dd->ipath_kregbase)
+- return;
+-
+- ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
+-
+- tidinv = dd->ipath_tidinvalid;
+- tidbase = (u64 __iomem *)
+- ((char __iomem *)(dd->ipath_kregbase) +
+- dd->ipath_rcvtidbase +
+- port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
+-
+- for (i = 0; i < dd->ipath_rcvtidcnt; i++)
+- ipath_pe_put_tid(dd, &tidbase[i], 0, tidinv);
+-
+- tidbase = (u64 __iomem *)
+- ((char __iomem *)(dd->ipath_kregbase) +
+- dd->ipath_rcvegrbase +
+- port * dd->ipath_rcvegrcnt * sizeof(*tidbase));
+-
+- for (i = 0; i < dd->ipath_rcvegrcnt; i++)
+- ipath_pe_put_tid(dd, &tidbase[i], 1, tidinv);
+-}
+-
+-/**
+- * ipath_pe_tidtemplate - setup constants for TID updates
+- * @dd: the infinipath device
+- *
+- * We setup stuff that we use a lot, to avoid calculating each time
+- */
+-static void ipath_pe_tidtemplate(struct ipath_devdata *dd)
+-{
+- u32 egrsize = dd->ipath_rcvegrbufsize;
+-
+- /* For now, we always allocate 4KB buffers (at init) so we can
+- * receive max size packets. We may want a module parameter to
+- * specify 2KB or 4KB and/or make be per port instead of per device
+- * for those who want to reduce memory footprint. Note that the
+- * ipath_rcvhdrentsize size must be large enough to hold the largest
+- * IB header (currently 96 bytes) that we expect to handle (plus of
+- * course the 2 dwords of RHF).
+- */
+- if (egrsize == 2048)
+- dd->ipath_tidtemplate = 1U << 29;
+- else if (egrsize == 4096)
+- dd->ipath_tidtemplate = 2U << 29;
+- else {
+- egrsize = 4096;
+- dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize "
+- "%u, using %u\n", dd->ipath_rcvegrbufsize,
+- egrsize);
+- dd->ipath_tidtemplate = 2U << 29;
+- }
+- dd->ipath_tidinvalid = 0;
+-}
+-
+-static int ipath_pe_early_init(struct ipath_devdata *dd)
+-{
+- dd->ipath_flags |= IPATH_4BYTE_TID;
+-
+- /*
+- * For openib, we need to be able to handle an IB header of 96 bytes
+- * or 24 dwords. HT-400 has arbitrary sized receive buffers, so we
+- * made them the same size as the PIO buffers. The PE-800 does not
+- * handle arbitrary size buffers, so we need the header large enough
+- * to handle largest IB header, but still have room for a 2KB MTU
+- * standard IB packet.
+- */
+- dd->ipath_rcvhdrentsize = 24;
+- dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
+-
+- /* For HT-400, we allocate a somewhat overly large eager buffer,
+- * such that we can guarantee that we can receive the largest packet
+- * that we can send out. To truly support a 4KB MTU, we need to
+- * bump this to a larger value. We'll do this when I get around to
+- * testing 4KB sends on the PE-800, which I have not yet done.
+- */
+- dd->ipath_rcvegrbufsize = 2048;
+- /*
+- * the min() check here is currently a nop, but it may not always
+- * be, depending on just how we do ipath_rcvegrbufsize
+- */
+- dd->ipath_ibmaxlen = min(dd->ipath_piosize2k,
+- dd->ipath_rcvegrbufsize +
+- (dd->ipath_rcvhdrentsize << 2));
+- dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
+-
+- /*
+- * For PE-800, we can request a receive interrupt for 1 or
+- * more packets from current offset. For now, we set this
+- * up for a single packet, to match the HT-400 behavior.
+- */
+- dd->ipath_rhdrhead_intr_off = 1ULL<<32;
+-
+- ipath_get_eeprom_info(dd);
+-
+- return 0;
+-}
+-
+-int __attribute__((weak)) ipath_unordered_wc(void)
+-{
+- return 0;
+-}
+-
+-/**
+- * ipath_init_pe_get_base_info - set chip-specific flags for user code
+- * @dd: the infinipath device
+- * @kbase: ipath_base_info pointer
+- *
+- * We set the PCIE flag because the lower bandwidth on PCIe vs
+- * HyperTransport can affect some user packet algorithims.
+- */
+-static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
+-{
+- struct ipath_base_info *kinfo = kbase;
+-
+- if (ipath_unordered_wc()) {
+- kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER;
+- ipath_cdbg(PROC, "Intel processor, forcing WC order\n");
+- }
+- else
+- ipath_cdbg(PROC, "Not Intel processor, WC ordered\n");
+-
+- kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
+-
+- return 0;
+-}
+-
+-/**
+- * ipath_init_pe800_funcs - set up the chip-specific function pointers
+- * @dd: the infinipath device
+- *
+- * This is global, and is called directly at init to set up the
+- * chip-specific function pointers for later use.
+- */
+-void ipath_init_pe800_funcs(struct ipath_devdata *dd)
+-{
+- dd->ipath_f_intrsetup = ipath_pe_intconfig;
+- dd->ipath_f_bus = ipath_setup_pe_config;
+- dd->ipath_f_reset = ipath_setup_pe_reset;
+- dd->ipath_f_get_boardname = ipath_pe_boardname;
+- dd->ipath_f_init_hwerrors = ipath_pe_init_hwerrors;
+- dd->ipath_f_early_init = ipath_pe_early_init;
+- dd->ipath_f_handle_hwerrors = ipath_pe_handle_hwerrors;
+- dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
+- dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
+- dd->ipath_f_clear_tids = ipath_pe_clear_tids;
+- dd->ipath_f_put_tid = ipath_pe_put_tid;
+- dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
+- dd->ipath_f_setextled = ipath_setup_pe_setextled;
+- dd->ipath_f_get_base_info = ipath_pe_get_base_info;
+-
+- /* initialize chip-specific variables */
+- dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
+-
+- /*
+- * setup the register offsets, since they are different for each
+- * chip
+- */
+- dd->ipath_kregs = &ipath_pe_kregs;
+- dd->ipath_cregs = &ipath_pe_cregs;
+-
+- ipath_init_pe_variables();
+-}
+-
+diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
+index 83e557b..46c1c89 100644
+--- a/drivers/infiniband/hw/ipath/ipath_qp.c
++++ b/drivers/infiniband/hw/ipath/ipath_qp.c
+@@ -35,7 +35,7 @@
+ #include <linux/vmalloc.h>
+
+ #include "ipath_verbs.h"
+-#include "ipath_common.h"
++#include "ipath_kernel.h"
+
+ #define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE)
+ #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
+@@ -44,19 +44,6 @@
+ #define find_next_offset(map, off) find_next_zero_bit((map)->page, \
+ BITS_PER_PAGE, off)
+
+-#define TRANS_INVALID 0
+-#define TRANS_ANY2RST 1
+-#define TRANS_RST2INIT 2
+-#define TRANS_INIT2INIT 3
+-#define TRANS_INIT2RTR 4
+-#define TRANS_RTR2RTS 5
+-#define TRANS_RTS2RTS 6
+-#define TRANS_SQERR2RTS 7
+-#define TRANS_ANY2ERR 8
+-#define TRANS_RTS2SQD 9 /* XXX Wait for expected ACKs & signal event */
+-#define TRANS_SQD2SQD 10 /* error if not drained & parameter change */
+-#define TRANS_SQD2RTS 11 /* error if not drained */
+-
+ /*
+ * Convert the AETH credit code into the number of credits.
+ */
+@@ -287,7 +274,7 @@ void ipath_free_all_qps(struct ipath_qp_
+ free_qpn(qpt, qp->ibqp.qp_num);
+ if (!atomic_dec_and_test(&qp->refcount) ||
+ !ipath_destroy_qp(&qp->ibqp))
+- _VERBS_INFO("QP memory leak!\n");
++ ipath_dbg(KERN_INFO "QP memory leak!\n");
+ qp = nqp;
+ }
+ }
+@@ -348,6 +335,7 @@ static void ipath_reset_qp(struct ipath_
+ qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
+ qp->r_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
+ qp->r_nak_state = 0;
++ qp->r_wrid_valid = 0;
+ qp->s_rnr_timeout = 0;
+ qp->s_head = 0;
+ qp->s_tail = 0;
+@@ -355,26 +343,30 @@ static void ipath_reset_qp(struct ipath_
+ qp->s_last = 0;
+ qp->s_ssn = 1;
+ qp->s_lsn = 0;
+- qp->r_rq.head = 0;
+- qp->r_rq.tail = 0;
++ qp->s_wait_credit = 0;
++ if (qp->r_rq.wq) {
++ qp->r_rq.wq->head = 0;
++ qp->r_rq.wq->tail = 0;
++ }
+ qp->r_reuse_sge = 0;
+ }
+
+ /**
+ * ipath_error_qp - put a QP into an error state
+ * @qp: the QP to put into an error state
++ * @err: the receive completion error to signal if a RWQE is active
+ *
+ * Flushes both send and receive work queues.
+ * QP s_lock should be held and interrupts disabled.
+ */
+
+-void ipath_error_qp(struct ipath_qp *qp)
++void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
+ {
+ struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ struct ib_wc wc;
+
+- _VERBS_INFO("QP%d/%d in error state\n",
+- qp->ibqp.qp_num, qp->remote_qpn);
++ ipath_dbg(KERN_INFO "QP%d/%d in error state\n",
++ qp->ibqp.qp_num, qp->remote_qpn);
+
+ spin_lock(&dev->pending_lock);
+ /* XXX What if its already removed by the timeout code? */
+@@ -384,7 +376,6 @@ void ipath_error_qp(struct ipath_qp *qp)
+ list_del_init(&qp->piowait);
+ spin_unlock(&dev->pending_lock);
+
+- wc.status = IB_WC_WR_FLUSH_ERR;
+ wc.vendor_err = 0;
+ wc.byte_len = 0;
+ wc.imm_data = 0;
+@@ -396,6 +387,12 @@ void ipath_error_qp(struct ipath_qp *qp)
+ wc.sl = 0;
+ wc.dlid_path_bits = 0;
+ wc.port_num = 0;
++ if (qp->r_wrid_valid) {
++ qp->r_wrid_valid = 0;
++ wc.status = err;
++ ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
++ }
++ wc.status = IB_WC_WR_FLUSH_ERR;
+
+ while (qp->s_last != qp->s_head) {
+ struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
+@@ -410,15 +407,32 @@ void ipath_error_qp(struct ipath_qp *qp)
+ qp->s_hdrwords = 0;
+ qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
+
+- wc.opcode = IB_WC_RECV;
+- spin_lock(&qp->r_rq.lock);
+- while (qp->r_rq.tail != qp->r_rq.head) {
+- wc.wr_id = get_rwqe_ptr(&qp->r_rq, qp->r_rq.tail)->wr_id;
+- if (++qp->r_rq.tail >= qp->r_rq.size)
+- qp->r_rq.tail = 0;
+- ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
++ if (qp->r_rq.wq) {
++ struct ipath_rwq *wq;
++ u32 head;
++ u32 tail;
++
++ spin_lock(&qp->r_rq.lock);
++
++ /* sanity check pointers before trusting them */
++ wq = qp->r_rq.wq;
++ head = wq->head;
++ if (head >= qp->r_rq.size)
++ head = 0;
++ tail = wq->tail;
++ if (tail >= qp->r_rq.size)
++ tail = 0;
++ wc.opcode = IB_WC_RECV;
++ while (tail != head) {
++ wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id;
++ if (++tail >= qp->r_rq.size)
++ tail = 0;
++ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
++ }
++ wq->tail = tail;
++
++ spin_unlock(&qp->r_rq.lock);
+ }
+- spin_unlock(&qp->r_rq.lock);
+ }
+
+ /**
+@@ -426,11 +440,12 @@ void ipath_error_qp(struct ipath_qp *qp)
+ * @ibqp: the queue pair who's attributes we're modifying
+ * @attr: the new attributes
+ * @attr_mask: the mask of attributes to modify
++ * @udata: user data for ipathverbs.so
+ *
+ * Returns 0 on success, otherwise returns an errno.
+ */
+ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+- int attr_mask)
++ int attr_mask, struct ib_udata *udata)
+ {
+ struct ipath_ibdev *dev = to_idev(ibqp->device);
+ struct ipath_qp *qp = to_iqp(ibqp);
+@@ -448,26 +463,53 @@ int ipath_modify_qp(struct ib_qp *ibqp,
+ attr_mask))
+ goto inval;
+
+- if (attr_mask & IB_QP_AV)
++ if (attr_mask & IB_QP_AV) {
+ if (attr->ah_attr.dlid == 0 ||
+ attr->ah_attr.dlid >= IPATH_MULTICAST_LID_BASE)
+ goto inval;
+
++ if ((attr->ah_attr.ah_flags & IB_AH_GRH) &&
++ (attr->ah_attr.grh.sgid_index > 1))
++ goto inval;
++ }
++
+ if (attr_mask & IB_QP_PKEY_INDEX)
+- if (attr->pkey_index >= ipath_layer_get_npkeys(dev->dd))
++ if (attr->pkey_index >= ipath_get_npkeys(dev->dd))
+ goto inval;
+
+ if (attr_mask & IB_QP_MIN_RNR_TIMER)
+ if (attr->min_rnr_timer > 31)
+ goto inval;
+
++ if (attr_mask & IB_QP_PORT)
++ if (attr->port_num == 0 ||
++ attr->port_num > ibqp->device->phys_port_cnt)
++ goto inval;
++
++ if (attr_mask & IB_QP_PATH_MTU)
++ if (attr->path_mtu > IB_MTU_4096)
++ goto inval;
++
++ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
++ if (attr->max_dest_rd_atomic > 1)
++ goto inval;
++
++ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
++ if (attr->max_rd_atomic > 1)
++ goto inval;
++
++ if (attr_mask & IB_QP_PATH_MIG_STATE)
++ if (attr->path_mig_state != IB_MIG_MIGRATED &&
++ attr->path_mig_state != IB_MIG_REARM)
++ goto inval;
++
+ switch (new_state) {
+ case IB_QPS_RESET:
+ ipath_reset_qp(qp);
+ break;
+
+ case IB_QPS_ERR:
+- ipath_error_qp(qp);
++ ipath_error_qp(qp, IB_WC_GENERAL_ERR);
+ break;
+
+ default:
+@@ -482,7 +524,7 @@ int ipath_modify_qp(struct ib_qp *ibqp,
+ qp->remote_qpn = attr->dest_qp_num;
+
+ if (attr_mask & IB_QP_SQ_PSN) {
+- qp->s_next_psn = attr->sq_psn;
++ qp->s_psn = qp->s_next_psn = attr->sq_psn;
+ qp->s_last_psn = qp->s_next_psn - 1;
+ }
+
+@@ -511,6 +553,9 @@ int ipath_modify_qp(struct ib_qp *ibqp,
+ if (attr_mask & IB_QP_MIN_RNR_TIMER)
+ qp->r_min_rnr_timer = attr->min_rnr_timer;
+
++ if (attr_mask & IB_QP_TIMEOUT)
++ qp->timeout = attr->timeout;
++
+ if (attr_mask & IB_QP_QKEY)
+ qp->qkey = attr->qkey;
+
+@@ -543,7 +588,7 @@ int ipath_query_qp(struct ib_qp *ibqp, s
+ attr->dest_qp_num = qp->remote_qpn;
+ attr->qp_access_flags = qp->qp_access_flags;
+ attr->cap.max_send_wr = qp->s_size - 1;
+- attr->cap.max_recv_wr = qp->r_rq.size - 1;
++ attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1;
+ attr->cap.max_send_sge = qp->s_max_sge;
+ attr->cap.max_recv_sge = qp->r_rq.max_sge;
+ attr->cap.max_inline_data = 0;
+@@ -557,7 +602,7 @@ int ipath_query_qp(struct ib_qp *ibqp, s
+ attr->max_dest_rd_atomic = 1;
+ attr->min_rnr_timer = qp->r_min_rnr_timer;
+ attr->port_num = 1;
+- attr->timeout = 0;
++ attr->timeout = qp->timeout;
+ attr->retry_cnt = qp->s_retry_cnt;
+ attr->rnr_retry = qp->s_rnr_retry;
+ attr->alt_port_num = 0;
+@@ -569,9 +614,10 @@ int ipath_query_qp(struct ib_qp *ibqp, s
+ init_attr->recv_cq = qp->ibqp.recv_cq;
+ init_attr->srq = qp->ibqp.srq;
+ init_attr->cap = attr->cap;
+- init_attr->sq_sig_type =
+- (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR))
+- ? IB_SIGNAL_REQ_WR : 0;
++ if (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR))
++ init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
++ else
++ init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
+ init_attr->qp_type = qp->ibqp.qp_type;
+ init_attr->port_num = 1;
+ return 0;
+@@ -596,13 +642,23 @@ __be32 ipath_compute_aeth(struct ipath_q
+ } else {
+ u32 min, max, x;
+ u32 credits;
+-
++ struct ipath_rwq *wq = qp->r_rq.wq;
++ u32 head;
++ u32 tail;
++
++ /* sanity check pointers before trusting them */
++ head = wq->head;
++ if (head >= qp->r_rq.size)
++ head = 0;
++ tail = wq->tail;
++ if (tail >= qp->r_rq.size)
++ tail = 0;
+ /*
+ * Compute the number of credits available (RWQEs).
+ * XXX Not holding the r_rq.lock here so there is a small
+ * chance that the pair of reads are not atomic.
+ */
+- credits = qp->r_rq.head - qp->r_rq.tail;
++ credits = head - tail;
+ if ((int)credits < 0)
+ credits += qp->r_rq.size;
+ /*
+@@ -679,27 +735,37 @@ struct ib_qp *ipath_create_qp(struct ib_
+ case IB_QPT_UD:
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+- qp = kmalloc(sizeof(*qp), GFP_KERNEL);
++ sz = sizeof(*qp);
++ if (init_attr->srq) {
++ struct ipath_srq *srq = to_isrq(init_attr->srq);
++
++ sz += sizeof(*qp->r_sg_list) *
++ srq->rq.max_sge;
++ } else
++ sz += sizeof(*qp->r_sg_list) *
++ init_attr->cap.max_recv_sge;
++ qp = kmalloc(sz, GFP_KERNEL);
+ if (!qp) {
+- vfree(swq);
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto bail_swq;
+ }
+ if (init_attr->srq) {
++ sz = 0;
+ qp->r_rq.size = 0;
+ qp->r_rq.max_sge = 0;
+ qp->r_rq.wq = NULL;
++ init_attr->cap.max_recv_wr = 0;
++ init_attr->cap.max_recv_sge = 0;
+ } else {
+ qp->r_rq.size = init_attr->cap.max_recv_wr + 1;
+ qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
+- sz = (sizeof(struct ipath_sge) * qp->r_rq.max_sge) +
++ sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
+ sizeof(struct ipath_rwqe);
+- qp->r_rq.wq = vmalloc(qp->r_rq.size * sz);
++ qp->r_rq.wq = vmalloc_user(sizeof(struct ipath_rwq) +
++ qp->r_rq.size * sz);
+ if (!qp->r_rq.wq) {
+- kfree(qp);
+- vfree(swq);
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto bail_qp;
+ }
+ }
+
+@@ -719,24 +785,19 @@ struct ib_qp *ipath_create_qp(struct ib_
+ qp->s_wq = swq;
+ qp->s_size = init_attr->cap.max_send_wr + 1;
+ qp->s_max_sge = init_attr->cap.max_send_sge;
+- qp->s_flags = init_attr->sq_sig_type == IB_SIGNAL_REQ_WR ?
+- 1 << IPATH_S_SIGNAL_REQ_WR : 0;
++ if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
++ qp->s_flags = 1 << IPATH_S_SIGNAL_REQ_WR;
++ else
++ qp->s_flags = 0;
+ dev = to_idev(ibpd->device);
+ err = ipath_alloc_qpn(&dev->qp_table, qp,
+ init_attr->qp_type);
+ if (err) {
+- vfree(swq);
+- vfree(qp->r_rq.wq);
+- kfree(qp);
+ ret = ERR_PTR(err);
+- goto bail;
++ goto bail_rwq;
+ }
++ qp->ip = NULL;
+ ipath_reset_qp(qp);
+-
+- /* Tell the core driver that the kernel SMA is present. */
+- if (init_attr->qp_type == IB_QPT_SMI)
+- ipath_layer_set_verbs_flags(dev->dd,
+- IPATH_VERBS_KERNEL_SMA);
+ break;
+
+ default:
+@@ -747,8 +808,63 @@ struct ib_qp *ipath_create_qp(struct ib_
+
+ init_attr->cap.max_inline_data = 0;
+
++ /*
++ * Return the address of the RWQ as the offset to mmap.
++ * See ipath_mmap() for details.
++ */
++ if (udata && udata->outlen >= sizeof(__u64)) {
++ struct ipath_mmap_info *ip;
++ __u64 offset = (__u64) qp->r_rq.wq;
++ int err;
++
++ err = ib_copy_to_udata(udata, &offset, sizeof(offset));
++ if (err) {
++ ret = ERR_PTR(err);
++ goto bail_rwq;
++ }
++
++ if (qp->r_rq.wq) {
++ /* Allocate info for ipath_mmap(). */
++ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
++ if (!ip) {
++ ret = ERR_PTR(-ENOMEM);
++ goto bail_rwq;
++ }
++ qp->ip = ip;
++ ip->context = ibpd->uobject->context;
++ ip->obj = qp->r_rq.wq;
++ kref_init(&ip->ref);
++ ip->mmap_cnt = 0;
++ ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
++ qp->r_rq.size * sz);
++ spin_lock_irq(&dev->pending_lock);
++ ip->next = dev->pending_mmaps;
++ dev->pending_mmaps = ip;
++ spin_unlock_irq(&dev->pending_lock);
++ }
++ }
++
++ spin_lock(&dev->n_qps_lock);
++ if (dev->n_qps_allocated == ib_ipath_max_qps) {
++ spin_unlock(&dev->n_qps_lock);
++ ret = ERR_PTR(-ENOMEM);
++ goto bail_ip;
++ }
++
++ dev->n_qps_allocated++;
++ spin_unlock(&dev->n_qps_lock);
++
+ ret = &qp->ibqp;
++ goto bail;
+
++bail_ip:
++ kfree(qp->ip);
++bail_rwq:
++ vfree(qp->r_rq.wq);
++bail_qp:
++ kfree(qp);
++bail_swq:
++ vfree(swq);
+ bail:
+ return ret;
+ }
+@@ -768,15 +884,12 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
+ struct ipath_ibdev *dev = to_idev(ibqp->device);
+ unsigned long flags;
+
+- /* Tell the core driver that the kernel SMA is gone. */
+- if (qp->ibqp.qp_type == IB_QPT_SMI)
+- ipath_layer_set_verbs_flags(dev->dd, 0);
+-
+- spin_lock_irqsave(&qp->r_rq.lock, flags);
+- spin_lock(&qp->s_lock);
++ spin_lock_irqsave(&qp->s_lock, flags);
+ qp->state = IB_QPS_ERR;
+- spin_unlock(&qp->s_lock);
+- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
++ spin_unlock_irqrestore(&qp->s_lock, flags);
++ spin_lock(&dev->n_qps_lock);
++ dev->n_qps_allocated--;
++ spin_unlock(&dev->n_qps_lock);
+
+ /* Stop the sending tasklet. */
+ tasklet_kill(&qp->s_task);
+@@ -797,8 +910,11 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
+ if (atomic_read(&qp->refcount) != 0)
+ ipath_free_qp(&dev->qp_table, qp);
+
++ if (qp->ip)
++ kref_put(&qp->ip->ref, ipath_release_mmap_info);
++ else
++ vfree(qp->r_rq.wq);
+ vfree(qp->s_wq);
+- vfree(qp->r_rq.wq);
+ kfree(qp);
+ return 0;
+ }
+@@ -850,8 +966,8 @@ void ipath_sqerror_qp(struct ipath_qp *q
+ struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
+
+- _VERBS_INFO("Send queue error on QP%d/%d: err: %d\n",
+- qp->ibqp.qp_num, qp->remote_qpn, wc->status);
++ ipath_dbg(KERN_INFO "Send queue error on QP%d/%d: err: %d\n",
++ qp->ibqp.qp_num, qp->remote_qpn, wc->status);
+
+ spin_lock(&dev->pending_lock);
+ /* XXX What if its already removed by the timeout code? */
+diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
+index 774d161..ce60387 100644
+--- a/drivers/infiniband/hw/ipath/ipath_rc.c
++++ b/drivers/infiniband/hw/ipath/ipath_rc.c
+@@ -32,7 +32,7 @@
+ */
+
+ #include "ipath_verbs.h"
+-#include "ipath_common.h"
++#include "ipath_kernel.h"
+
+ /* cut down ridiculously long IB macro names */
+ #define OP(x) IB_OPCODE_RC_##x
+@@ -201,6 +201,18 @@ int ipath_make_rc_req(struct ipath_qp *q
+ qp->s_rnr_timeout)
+ goto done;
+
++ /* Limit the number of packets sent without an ACK. */
++ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
++ qp->s_wait_credit = 1;
++ dev->n_rc_stalls++;
++ spin_lock(&dev->pending_lock);
++ if (list_empty(&qp->timerwait))
++ list_add_tail(&qp->timerwait,
++ &dev->pending[dev->pending_index]);
++ spin_unlock(&dev->pending_lock);
++ goto done;
++ }
++
+ /* header size in 32-bit words LRH+BTH = (8+12)/4. */
+ hwords = 5;
+ bth0 = 0;
+@@ -221,7 +233,7 @@ int ipath_make_rc_req(struct ipath_qp *q
+ /* Check if send work queue is empty. */
+ if (qp->s_tail == qp->s_head)
+ goto done;
+- qp->s_psn = wqe->psn = qp->s_next_psn;
++ wqe->psn = qp->s_next_psn;
+ newreq = 1;
+ }
+ /*
+@@ -229,10 +241,7 @@ int ipath_make_rc_req(struct ipath_qp *q
+ * original work request since we may need to resend
+ * it.
+ */
+- qp->s_sge.sge = wqe->sg_list[0];
+- qp->s_sge.sg_list = wqe->sg_list + 1;
+- qp->s_sge.num_sge = wqe->wr.num_sge;
+- qp->s_len = len = wqe->length;
++ len = wqe->length;
+ ss = &qp->s_sge;
+ bth2 = 0;
+ switch (wqe->wr.opcode) {
+@@ -356,14 +365,23 @@ int ipath_make_rc_req(struct ipath_qp *q
+ default:
+ goto done;
+ }
++ qp->s_sge.sge = wqe->sg_list[0];
++ qp->s_sge.sg_list = wqe->sg_list + 1;
++ qp->s_sge.num_sge = wqe->wr.num_sge;
++ qp->s_len = wqe->length;
+ if (newreq) {
+ qp->s_tail++;
+ if (qp->s_tail >= qp->s_size)
+ qp->s_tail = 0;
+ }
+- bth2 |= qp->s_psn++ & IPATH_PSN_MASK;
+- if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+- qp->s_next_psn = qp->s_psn;
++ bth2 |= qp->s_psn & IPATH_PSN_MASK;
++ if (wqe->wr.opcode == IB_WR_RDMA_READ)
++ qp->s_psn = wqe->lpsn + 1;
++ else {
++ qp->s_psn++;
++ if ((int)(qp->s_psn - qp->s_next_psn) > 0)
++ qp->s_next_psn = qp->s_psn;
++ }
+ /*
+ * Put the QP on the pending list so lost ACKs will cause
+ * a retry. More than one request can be pending so the
+@@ -393,12 +411,6 @@ int ipath_make_rc_req(struct ipath_qp *q
+ ss = &qp->s_sge;
+ len = qp->s_len;
+ if (len > pmtu) {
+- /*
+- * Request an ACK every 1/2 MB to avoid retransmit
+- * timeouts.
+- */
+- if (((wqe->length - len) % (512 * 1024)) == 0)
+- bth2 |= 1 << 31;
+ len = pmtu;
+ break;
+ }
+@@ -435,12 +447,6 @@ int ipath_make_rc_req(struct ipath_qp *q
+ ss = &qp->s_sge;
+ len = qp->s_len;
+ if (len > pmtu) {
+- /*
+- * Request an ACK every 1/2 MB to avoid retransmit
+- * timeouts.
+- */
+- if (((wqe->length - len) % (512 * 1024)) == 0)
+- bth2 |= 1 << 31;
+ len = pmtu;
+ break;
+ }
+@@ -498,6 +504,8 @@ int ipath_make_rc_req(struct ipath_qp *q
+ */
+ goto done;
+ }
++ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0)
++ bth2 |= 1 << 31; /* Request ACK. */
+ qp->s_len -= len;
+ qp->s_hdrwords = hwords;
+ qp->s_cur_sge = ss;
+@@ -540,7 +548,7 @@ static void send_rc_ack(struct ipath_qp
+ lrh0 = IPATH_LRH_GRH;
+ }
+ /* read pkey_index w/o lock (its atomic) */
+- bth0 = ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
++ bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ if (qp->r_nak_state)
+ ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
+ (qp->r_nak_state <<
+@@ -557,7 +565,7 @@ static void send_rc_ack(struct ipath_qp
+ hdr.lrh[0] = cpu_to_be16(lrh0);
+ hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
+- hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd));
++ hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+ ohdr->bth[0] = cpu_to_be32(bth0);
+ ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+ ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
+@@ -688,13 +696,6 @@ void ipath_restart_rc(struct ipath_qp *q
+ struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
+ struct ipath_ibdev *dev;
+
+- /*
+- * If there are no requests pending, we are done.
+- */
+- if (ipath_cmp24(psn, qp->s_next_psn) >= 0 ||
+- qp->s_last == qp->s_tail)
+- goto done;
+-
+ if (qp->s_retry == 0) {
+ wc->wr_id = wqe->wr.wr_id;
+ wc->status = IB_WC_RETRY_EXC_ERR;
+@@ -729,14 +730,21 @@ void ipath_restart_rc(struct ipath_qp *q
+ dev->n_rc_resends += (int)qp->s_psn - (int)psn;
+
+ reset_psn(qp, psn);
+-
+-done:
+ tasklet_hi_schedule(&qp->s_task);
+
+ bail:
+ return;
+ }
+
++static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
++{
++ if (qp->s_wait_credit) {
++ qp->s_wait_credit = 0;
++ tasklet_hi_schedule(&qp->s_task);
++ }
++ qp->s_last_psn = psn;
++}
++
+ /**
+ * do_rc_ack - process an incoming RC ACK
+ * @qp: the QP the ACK came in on
+@@ -754,6 +762,7 @@ static int do_rc_ack(struct ipath_qp *qp
+ struct ib_wc wc;
+ struct ipath_swqe *wqe;
+ int ret = 0;
++ u32 ack_psn;
+
+ /*
+ * Remove the QP from the timeout queue (or RNR timeout queue).
+@@ -766,26 +775,26 @@ static int do_rc_ack(struct ipath_qp *qp
+ list_del_init(&qp->timerwait);
+ spin_unlock(&dev->pending_lock);
+
++ /* Nothing is pending to ACK/NAK. */
++ if (unlikely(qp->s_last == qp->s_tail))
++ goto bail;
++
+ /*
+ * Note that NAKs implicitly ACK outstanding SEND and RDMA write
+ * requests and implicitly NAK RDMA read and atomic requests issued
+ * before the NAK'ed request. The MSN won't include the NAK'ed
+ * request but will include an ACK'ed request(s).
+ */
++ ack_psn = psn;
++ if (aeth >> 29)
++ ack_psn--;
+ wqe = get_swqe_ptr(qp, qp->s_last);
+
+- /* Nothing is pending to ACK/NAK. */
+- if (qp->s_last == qp->s_tail)
+- goto bail;
+-
+ /*
+ * The MSN might be for a later WQE than the PSN indicates so
+ * only complete WQEs that the PSN finishes.
+ */
+- while (ipath_cmp24(psn, wqe->lpsn) >= 0) {
+- /* If we are ACKing a WQE, the MSN should be >= the SSN. */
+- if (ipath_cmp24(aeth, wqe->ssn) < 0)
+- break;
++ while (ipath_cmp24(ack_psn, wqe->lpsn) >= 0) {
+ /*
+ * If this request is a RDMA read or atomic, and the ACK is
+ * for a later operation, this ACK NAKs the RDMA read or
+@@ -796,7 +805,8 @@ static int do_rc_ack(struct ipath_qp *qp
+ * is sent but before the response is received.
+ */
+ if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
+- opcode != OP(RDMA_READ_RESPONSE_LAST)) ||
++ (opcode != OP(RDMA_READ_RESPONSE_LAST) ||
++ ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
+ ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+ wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
+ (opcode != OP(ATOMIC_ACKNOWLEDGE) ||
+@@ -805,7 +815,7 @@ static int do_rc_ack(struct ipath_qp *qp
+ * The last valid PSN seen is the previous
+ * request's.
+ */
+- qp->s_last_psn = wqe->psn - 1;
++ update_last_psn(qp, wqe->psn - 1);
+ /* Retry this request. */
+ ipath_restart_rc(qp, wqe->psn, &wc);
+ /*
+@@ -814,6 +824,10 @@ static int do_rc_ack(struct ipath_qp *qp
+ */
+ goto bail;
+ }
++ if (wqe->wr.opcode == IB_WR_RDMA_READ ||
++ wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
++ wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
++ tasklet_hi_schedule(&qp->s_task);
+ /* Post a send completion queue entry if requested. */
+ if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) ||
+ (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
+@@ -864,7 +878,7 @@ static int do_rc_ack(struct ipath_qp *qp
+ ipath_get_credit(qp, aeth);
+ qp->s_rnr_retry = qp->s_rnr_retry_cnt;
+ qp->s_retry = qp->s_retry_cnt;
+- qp->s_last_psn = psn;
++ update_last_psn(qp, psn);
+ ret = 1;
+ goto bail;
+
+@@ -883,7 +897,7 @@ static int do_rc_ack(struct ipath_qp *qp
+ goto bail;
+
+ /* The last valid PSN is the previous PSN. */
+- qp->s_last_psn = psn - 1;
++ update_last_psn(qp, psn - 1);
+
+ dev->n_rc_resends += (int)qp->s_psn - (int)psn;
+
+@@ -898,7 +912,7 @@ static int do_rc_ack(struct ipath_qp *qp
+ case 3: /* NAK */
+ /* The last valid PSN seen is the previous request's. */
+ if (qp->s_last != qp->s_tail)
+- qp->s_last_psn = wqe->psn - 1;
++ update_last_psn(qp, wqe->psn - 1);
+ switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
+ IPATH_AETH_CREDIT_MASK) {
+ case 0: /* PSN sequence error */
+@@ -1044,7 +1058,8 @@ static inline void ipath_rc_rcv_resp(str
+ /* no AETH, no ACK */
+ if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
+ dev->n_rdma_seq++;
+- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
++ if (qp->s_last != qp->s_tail)
++ ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ goto ack_done;
+ }
+ rdma_read:
+@@ -1071,7 +1086,7 @@ static inline void ipath_rc_rcv_resp(str
+ * since we don't want s_sge modified.
+ */
+ qp->s_len -= pmtu;
+- qp->s_last_psn = psn;
++ update_last_psn(qp, psn);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ ipath_copy_sge(&qp->s_sge, data, pmtu);
+ goto bail;
+@@ -1080,7 +1095,8 @@ static inline void ipath_rc_rcv_resp(str
+ /* ACKs READ req. */
+ if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
+ dev->n_rdma_seq++;
+- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
++ if (qp->s_last != qp->s_tail)
++ ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ goto ack_done;
+ }
+ /* FALLTHROUGH */
+@@ -1223,7 +1239,7 @@ static inline int ipath_rc_rcv_error(str
+ * Address range must be a subset of the original
+ * request and start on pmtu boundaries.
+ */
+- ok = ipath_rkey_ok(dev, &qp->s_rdma_sge,
++ ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
+ qp->s_rdma_len, vaddr, rkey,
+ IB_ACCESS_REMOTE_READ);
+ if (unlikely(!ok)) {
+@@ -1282,6 +1298,14 @@ done:
+ return 1;
+ }
+
++static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
++{
++ spin_lock_irq(&qp->s_lock);
++ qp->state = IB_QPS_ERR;
++ ipath_error_qp(qp, err);
++ spin_unlock_irq(&qp->s_lock);
++}
++
+ /**
+ * ipath_rc_rcv - process an incoming RC packet
+ * @dev: the device this packet came in on
+@@ -1309,6 +1333,10 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ struct ib_reth *reth;
+ int header_in_data;
+
++ /* Validate the SLID. See Ch. 9.6.1.5 */
++ if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
++ goto done;
++
+ /* Check for GRH */
+ if (!has_grh) {
+ ohdr = &hdr->u.oth;
+@@ -1323,8 +1351,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ * the eager header buffer size to 56 bytes so the last 4
+ * bytes of the BTH header (PSN) is in the data buffer.
+ */
+- header_in_data =
+- ipath_layer_get_rcvhdrentsize(dev->dd) == 16;
++ header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
+ if (header_in_data) {
+ psn = be32_to_cpu(((__be32 *) data)[0]);
+ data += sizeof(__be32);
+@@ -1371,8 +1398,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ */
+ if (qp->r_ack_state >= OP(COMPARE_SWAP))
+ goto send_ack;
+- /* XXX Flush WQEs */
+- qp->state = IB_QPS_ERR;
++ ipath_rc_error(qp, IB_WC_REM_INV_REQ_ERR);
+ qp->r_ack_state = OP(SEND_ONLY);
+ qp->r_nak_state = IB_NAK_INVALID_REQUEST;
+ qp->r_ack_psn = qp->r_psn;
+@@ -1478,9 +1504,9 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ goto nack_inv;
+ ipath_copy_sge(&qp->r_sge, data, tlen);
+ qp->r_msn++;
+- if (opcode == OP(RDMA_WRITE_LAST) ||
+- opcode == OP(RDMA_WRITE_ONLY))
++ if (!qp->r_wrid_valid)
+ break;
++ qp->r_wrid_valid = 0;
+ wc.wr_id = qp->r_wr_id;
+ wc.status = IB_WC_SUCCESS;
+ wc.opcode = IB_WC_RECV;
+@@ -1518,7 +1544,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ int ok;
+
+ /* Check rkey & NAK */
+- ok = ipath_rkey_ok(dev, &qp->r_sge,
++ ok = ipath_rkey_ok(qp, &qp->r_sge,
+ qp->r_len, vaddr, rkey,
+ IB_ACCESS_REMOTE_WRITE);
+ if (unlikely(!ok))
+@@ -1560,7 +1586,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ int ok;
+
+ /* Check rkey & NAK */
+- ok = ipath_rkey_ok(dev, &qp->s_rdma_sge,
++ ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
+ qp->s_rdma_len, vaddr, rkey,
+ IB_ACCESS_REMOTE_READ);
+ if (unlikely(!ok)) {
+@@ -1619,7 +1645,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de
+ goto nack_inv;
+ rkey = be32_to_cpu(ateth->rkey);
+ /* Check rkey & NAK */
+- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge,
++ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge,
+ sizeof(u64), vaddr, rkey,
+ IB_ACCESS_REMOTE_ATOMIC)))
+ goto nack_acc;
+@@ -1671,8 +1697,7 @@ nack_acc:
+ * is pending though.
+ */
+ if (qp->r_ack_state < OP(COMPARE_SWAP)) {
+- /* XXX Flush WQEs */
+- qp->state = IB_QPS_ERR;
++ ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
+ qp->r_ack_state = OP(RDMA_WRITE_ONLY);
+ qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
+ qp->r_ack_psn = qp->r_psn;
+diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
+index 89df8f5..dffc760 100644
+--- a/drivers/infiniband/hw/ipath/ipath_registers.h
++++ b/drivers/infiniband/hw/ipath/ipath_registers.h
+@@ -36,8 +36,7 @@
+
+ /*
+ * This file should only be included by kernel source, and by the diags. It
+- * defines the registers, and their contents, for the InfiniPath HT-400
+- * chip.
++ * defines the registers, and their contents, for InfiniPath chips.
+ */
+
+ /*
+@@ -135,10 +134,24 @@
+ #define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40
+ #define INFINIPATH_HWE_RXEMEMPARITYERR_MASK 0x7FULL
+ #define INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT 44
+-#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL
+-#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
+ #define INFINIPATH_HWE_IBCBUSTOSPCPARITYERR 0x4000000000000000ULL
+ #define INFINIPATH_HWE_IBCBUSFRSPCPARITYERR 0x8000000000000000ULL
++/* txe mem parity errors (shift by INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) */
++#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF 0x1ULL
++#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC 0x2ULL
++#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOLAUNCHFIFO 0x4ULL
++/* rxe mem parity errors (shift by INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) */
++#define INFINIPATH_HWE_RXEMEMPARITYERR_RCVBUF 0x01ULL
++#define INFINIPATH_HWE_RXEMEMPARITYERR_LOOKUPQ 0x02ULL
++#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x04ULL
++#define INFINIPATH_HWE_RXEMEMPARITYERR_EXPTID 0x08ULL
++#define INFINIPATH_HWE_RXEMEMPARITYERR_FLAGBUF 0x10ULL
++#define INFINIPATH_HWE_RXEMEMPARITYERR_DATAINFO 0x20ULL
++#define INFINIPATH_HWE_RXEMEMPARITYERR_HDRINFO 0x40ULL
++/* waldo specific -- find the rest in ipath_6110.c */
++#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL
++/* monty specific -- find the rest in ipath_6120.c */
++#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
+
+ /* kr_hwdiagctrl bits */
+ #define INFINIPATH_DC_FORCETXEMEMPARITYERR_MASK 0xFULL
+@@ -210,9 +223,9 @@
+
+ /* combination link status states that we use with some frequency */
+ #define IPATH_IBSTATE_MASK ((INFINIPATH_IBCS_LINKTRAININGSTATE_MASK \
+- << INFINIPATH_IBCS_LINKSTATE_SHIFT) | \
++ << INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | \
+ (INFINIPATH_IBCS_LINKSTATE_MASK \
+- <<INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT))
++ <<INFINIPATH_IBCS_LINKSTATE_SHIFT))
+ #define IPATH_IBSTATE_INIT ((INFINIPATH_IBCS_L_STATE_INIT \
+ << INFINIPATH_IBCS_LINKSTATE_SHIFT) | \
+ (INFINIPATH_IBCS_LT_STATE_LINKUP \
+@@ -283,10 +296,12 @@
+ #define INFINIPATH_XGXS_RESET 0x7ULL
+ #define INFINIPATH_XGXS_MDIOADDR_MASK 0xfULL
+ #define INFINIPATH_XGXS_MDIOADDR_SHIFT 4
++#define INFINIPATH_XGXS_RX_POL_SHIFT 19
++#define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
+
+ #define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL /* 40 bits valid */
+
+-/* TID entries (memory), HT400-only */
++/* TID entries (memory), HT-only */
+ #define INFINIPATH_RT_VALID 0x8000000000000000ULL
+ #define INFINIPATH_RT_ADDR_SHIFT 0
+ #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFF
+@@ -301,6 +316,17 @@
+
+ typedef u64 ipath_err_t;
+
++/* The following change with the type of device, so
++ * need to be part of the ipath_devdata struct, or
++ * we could have problems plugging in devices of
++ * different types (e.g. one HT, one PCIE)
++ * in one system, to be managed by one driver.
++ * On the other hand, this file is may also be included
++ * by other code, so leave the declarations here
++ * temporarily. Minor footprint issue if common-model
++ * linker used, none if C89+ linker used.
++ */
++
+ /* mask of defined bits for various registers */
+ extern u64 infinipath_i_bitsextant;
+ extern ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
+@@ -309,13 +335,6 @@ extern ipath_err_t infinipath_e_bitsexta
+ extern u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
+
+ /*
+- * register bits for selecting i2c direction and values, used for I2C serial
+- * flash
+- */
+-extern u16 ipath_gpio_sda_num, ipath_gpio_scl_num;
+-extern u64 ipath_gpio_sda, ipath_gpio_scl;
+-
+-/*
+ * These are the infinipath general register numbers (not offsets).
+ * The kernel registers are used directly, those beyond the kernel
+ * registers are calculated from one of the base registers. The use of
+diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
+index 772bc59..f753051 100644
+--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
++++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
+@@ -32,7 +32,7 @@
+ */
+
+ #include "ipath_verbs.h"
+-#include "ipath_common.h"
++#include "ipath_kernel.h"
+
+ /*
+ * Convert the AETH RNR timeout code into the number of milliseconds.
+@@ -106,6 +106,52 @@ void ipath_insert_rnr_queue(struct ipath
+ spin_unlock_irqrestore(&dev->pending_lock, flags);
+ }
+
++static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
++{
++ int user = to_ipd(qp->ibqp.pd)->user;
++ int i, j, ret;
++ struct ib_wc wc;
++
++ qp->r_len = 0;
++ for (i = j = 0; i < wqe->num_sge; i++) {
++ if (wqe->sg_list[i].length == 0)
++ continue;
++ /* Check LKEY */
++ if ((user && wqe->sg_list[i].lkey == 0) ||
++ !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
++ IB_ACCESS_LOCAL_WRITE))
++ goto bad_lkey;
++ qp->r_len += wqe->sg_list[i].length;
++ j++;
++ }
++ qp->r_sge.sge = qp->r_sg_list[0];
++ qp->r_sge.sg_list = qp->r_sg_list + 1;
++ qp->r_sge.num_sge = j;
++ ret = 1;
++ goto bail;
++
++bad_lkey:
++ wc.wr_id = wqe->wr_id;
++ wc.status = IB_WC_LOC_PROT_ERR;
++ wc.opcode = IB_WC_RECV;
++ wc.vendor_err = 0;
++ wc.byte_len = 0;
++ wc.imm_data = 0;
++ wc.qp_num = qp->ibqp.qp_num;
++ wc.src_qp = 0;
++ wc.wc_flags = 0;
++ wc.pkey_index = 0;
++ wc.slid = 0;
++ wc.sl = 0;
++ wc.dlid_path_bits = 0;
++ wc.port_num = 0;
++ /* Signal solicited completion event. */
++ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
++ ret = 0;
++bail:
++ return ret;
++}
++
+ /**
+ * ipath_get_rwqe - copy the next RWQE into the QP's RWQE
+ * @qp: the QP
+@@ -119,71 +165,72 @@ int ipath_get_rwqe(struct ipath_qp *qp,
+ {
+ unsigned long flags;
+ struct ipath_rq *rq;
++ struct ipath_rwq *wq;
+ struct ipath_srq *srq;
+ struct ipath_rwqe *wqe;
+- int ret = 1;
++ void (*handler)(struct ib_event *, void *);
++ u32 tail;
++ int ret;
+
+- if (!qp->ibqp.srq) {
++ if (qp->ibqp.srq) {
++ srq = to_isrq(qp->ibqp.srq);
++ handler = srq->ibsrq.event_handler;
++ rq = &srq->rq;
++ } else {
++ srq = NULL;
++ handler = NULL;
+ rq = &qp->r_rq;
+- spin_lock_irqsave(&rq->lock, flags);
+-
+- if (unlikely(rq->tail == rq->head)) {
+- ret = 0;
+- goto done;
+- }
+- wqe = get_rwqe_ptr(rq, rq->tail);
+- qp->r_wr_id = wqe->wr_id;
+- if (!wr_id_only) {
+- qp->r_sge.sge = wqe->sg_list[0];
+- qp->r_sge.sg_list = wqe->sg_list + 1;
+- qp->r_sge.num_sge = wqe->num_sge;
+- qp->r_len = wqe->length;
+- }
+- if (++rq->tail >= rq->size)
+- rq->tail = 0;
+- goto done;
+ }
+
+- srq = to_isrq(qp->ibqp.srq);
+- rq = &srq->rq;
+ spin_lock_irqsave(&rq->lock, flags);
+-
+- if (unlikely(rq->tail == rq->head)) {
+- ret = 0;
+- goto done;
+- }
+- wqe = get_rwqe_ptr(rq, rq->tail);
++ wq = rq->wq;
++ tail = wq->tail;
++ /* Validate tail before using it since it is user writable. */
++ if (tail >= rq->size)
++ tail = 0;
++ do {
++ if (unlikely(tail == wq->head)) {
++ spin_unlock_irqrestore(&rq->lock, flags);
++ ret = 0;
++ goto bail;
++ }
++ wqe = get_rwqe_ptr(rq, tail);
++ if (++tail >= rq->size)
++ tail = 0;
++ } while (!wr_id_only && !init_sge(qp, wqe));
+ qp->r_wr_id = wqe->wr_id;
+- if (!wr_id_only) {
+- qp->r_sge.sge = wqe->sg_list[0];
+- qp->r_sge.sg_list = wqe->sg_list + 1;
+- qp->r_sge.num_sge = wqe->num_sge;
+- qp->r_len = wqe->length;
+- }
+- if (++rq->tail >= rq->size)
+- rq->tail = 0;
+- if (srq->ibsrq.event_handler) {
+- struct ib_event ev;
++ wq->tail = tail;
++
++ ret = 1;
++ if (handler) {
+ u32 n;
+
+- if (rq->head < rq->tail)
+- n = rq->size + rq->head - rq->tail;
++ /*
++ * validate head pointer value and compute
++ * the number of remaining WQEs.
++ */
++ n = wq->head;
++ if (n >= rq->size)
++ n = 0;
++ if (n < tail)
++ n += rq->size - tail;
+ else
+- n = rq->head - rq->tail;
++ n -= tail;
+ if (n < srq->limit) {
++ struct ib_event ev;
++
+ srq->limit = 0;
+ spin_unlock_irqrestore(&rq->lock, flags);
+ ev.device = qp->ibqp.device;
+ ev.element.srq = qp->ibqp.srq;
+ ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
+- srq->ibsrq.event_handler(&ev,
+- srq->ibsrq.srq_context);
++ handler(&ev, srq->ibsrq.srq_context);
+ goto bail;
+ }
+ }
+-
+-done:
+ spin_unlock_irqrestore(&rq->lock, flags);
++ qp->r_wrid_valid = 1;
++
+ bail:
+ return ret;
+ }
+@@ -278,7 +325,7 @@ again:
+ case IB_WR_RDMA_WRITE:
+ if (wqe->length == 0)
+ break;
+- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, wqe->length,
++ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
+ wqe->wr.wr.rdma.remote_addr,
+ wqe->wr.wr.rdma.rkey,
+ IB_ACCESS_REMOTE_WRITE))) {
+@@ -302,7 +349,7 @@ again:
+ break;
+
+ case IB_WR_RDMA_READ:
+- if (unlikely(!ipath_rkey_ok(dev, &sqp->s_sge, wqe->length,
++ if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
+ wqe->wr.wr.rdma.remote_addr,
+ wqe->wr.wr.rdma.rkey,
+ IB_ACCESS_REMOTE_READ)))
+@@ -317,7 +364,7 @@ again:
+
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, sizeof(u64),
++ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
+ wqe->wr.wr.rdma.remote_addr,
+ wqe->wr.wr.rdma.rkey,
+ IB_ACCESS_REMOTE_ATOMIC)))
+@@ -422,6 +469,15 @@ done:
+ wake_up(&qp->wait);
+ }
+
++static int want_buffer(struct ipath_devdata *dd)
++{
++ set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
++ dd->ipath_sendctrl);
++
++ return 0;
++}
++
+ /**
+ * ipath_no_bufs_available - tell the layer driver we need buffers
+ * @qp: the QP that caused the problem
+@@ -438,7 +494,7 @@ void ipath_no_bufs_available(struct ipat
+ list_add_tail(&qp->piowait, &dev->piowait);
+ spin_unlock_irqrestore(&dev->pending_lock, flags);
+ /*
+- * Note that as soon as ipath_layer_want_buffer() is called and
++ * Note that as soon as want_buffer() is called and
+ * possibly before it returns, ipath_ib_piobufavail()
+ * could be called. If we are still in the tasklet function,
+ * tasklet_hi_schedule() will not call us until the next time
+@@ -448,7 +504,7 @@ void ipath_no_bufs_available(struct ipat
+ */
+ clear_bit(IPATH_S_BUSY, &qp->s_flags);
+ tasklet_unlock(&qp->s_task);
+- ipath_layer_want_buffer(dev->dd);
++ want_buffer(dev->dd);
+ dev->n_piowait++;
+ }
+
+@@ -518,8 +574,7 @@ int ipath_post_ruc_send(struct ipath_qp
+ }
+ if (wr->sg_list[i].length == 0)
+ continue;
+- if (!ipath_lkey_ok(&to_idev(qp->ibqp.device)->lk_table,
+- &wqe->sg_list[j], &wr->sg_list[i],
++ if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
+ acc)) {
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ ret = -EINVAL;
+@@ -563,7 +618,7 @@ u32 ipath_make_grh(struct ipath_ibdev *d
+ hdr->hop_limit = grh->hop_limit;
+ /* The SGID is 32-bit aligned. */
+ hdr->sgid.global.subnet_prefix = dev->gid_prefix;
+- hdr->sgid.global.interface_id = ipath_layer_get_guid(dev->dd);
++ hdr->sgid.global.interface_id = dev->dd->ipath_guid;
+ hdr->dgid = grh->dgid;
+
+ /* GRH header size in 32-bit words. */
+@@ -595,8 +650,7 @@ void ipath_do_ruc_send(unsigned long dat
+ if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags))
+ goto bail;
+
+- if (unlikely(qp->remote_ah_attr.dlid ==
+- ipath_layer_get_lid(dev->dd))) {
++ if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
+ ipath_ruc_loopback(qp);
+ goto clear;
+ }
+@@ -663,8 +717,8 @@ again:
+ qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
+ SIZE_OF_CRC);
+- qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd));
+- bth0 |= ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
++ qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
++ bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ bth0 |= extra_bytes << 20;
+ ohdr->bth[0] = cpu_to_be32(bth0);
+ ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
+index f760434..9403350 100644
+--- a/drivers/infiniband/hw/ipath/ipath_srq.c
++++ b/drivers/infiniband/hw/ipath/ipath_srq.c
+@@ -48,66 +48,39 @@ int ipath_post_srq_receive(struct ib_srq
+ struct ib_recv_wr **bad_wr)
+ {
+ struct ipath_srq *srq = to_isrq(ibsrq);
+- struct ipath_ibdev *dev = to_idev(ibsrq->device);
++ struct ipath_rwq *wq;
+ unsigned long flags;
+ int ret;
+
+ for (; wr; wr = wr->next) {
+ struct ipath_rwqe *wqe;
+ u32 next;
+- int i, j;
++ int i;
+
+- if (wr->num_sge > srq->rq.max_sge) {
++ if ((unsigned) wr->num_sge > srq->rq.max_sge) {
+ *bad_wr = wr;
+ ret = -ENOMEM;
+ goto bail;
+ }
+
+ spin_lock_irqsave(&srq->rq.lock, flags);
+- next = srq->rq.head + 1;
++ wq = srq->rq.wq;
++ next = wq->head + 1;
+ if (next >= srq->rq.size)
+ next = 0;
+- if (next == srq->rq.tail) {
++ if (next == wq->tail) {
+ spin_unlock_irqrestore(&srq->rq.lock, flags);
+ *bad_wr = wr;
+ ret = -ENOMEM;
+ goto bail;
+ }
+
+- wqe = get_rwqe_ptr(&srq->rq, srq->rq.head);
++ wqe = get_rwqe_ptr(&srq->rq, wq->head);
+ wqe->wr_id = wr->wr_id;
+- wqe->sg_list[0].mr = NULL;
+- wqe->sg_list[0].vaddr = NULL;
+- wqe->sg_list[0].length = 0;
+- wqe->sg_list[0].sge_length = 0;
+- wqe->length = 0;
+- for (i = 0, j = 0; i < wr->num_sge; i++) {
+- /* Check LKEY */
+- if (to_ipd(srq->ibsrq.pd)->user &&
+- wr->sg_list[i].lkey == 0) {
+- spin_unlock_irqrestore(&srq->rq.lock,
+- flags);
+- *bad_wr = wr;
+- ret = -EINVAL;
+- goto bail;
+- }
+- if (wr->sg_list[i].length == 0)
+- continue;
+- if (!ipath_lkey_ok(&dev->lk_table,
+- &wqe->sg_list[j],
+- &wr->sg_list[i],
+- IB_ACCESS_LOCAL_WRITE)) {
+- spin_unlock_irqrestore(&srq->rq.lock,
+- flags);
+- *bad_wr = wr;
+- ret = -EINVAL;
+- goto bail;
+- }
+- wqe->length += wr->sg_list[i].length;
+- j++;
+- }
+- wqe->num_sge = j;
+- srq->rq.head = next;
++ wqe->num_sge = wr->num_sge;
++ for (i = 0; i < wr->num_sge; i++)
++ wqe->sg_list[i] = wr->sg_list[i];
++ wq->head = next;
+ spin_unlock_irqrestore(&srq->rq.lock, flags);
+ }
+ ret = 0;
+@@ -131,55 +104,99 @@ struct ib_srq *ipath_create_srq(struct i
+ u32 sz;
+ struct ib_srq *ret;
+
+- if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
+- ret = ERR_PTR(-ENOMEM);
+- goto bail;
+- }
+-
+ if (srq_init_attr->attr.max_wr == 0) {
+ ret = ERR_PTR(-EINVAL);
+- goto bail;
++ goto done;
+ }
+
+ if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) ||
+ (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) {
+ ret = ERR_PTR(-EINVAL);
+- goto bail;
++ goto done;
+ }
+
+ srq = kmalloc(sizeof(*srq), GFP_KERNEL);
+ if (!srq) {
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto done;
+ }
+
+ /*
+ * Need to use vmalloc() if we want to support large #s of entries.
+ */
+ srq->rq.size = srq_init_attr->attr.max_wr + 1;
+- sz = sizeof(struct ipath_sge) * srq_init_attr->attr.max_sge +
++ srq->rq.max_sge = srq_init_attr->attr.max_sge;
++ sz = sizeof(struct ib_sge) * srq->rq.max_sge +
+ sizeof(struct ipath_rwqe);
+- srq->rq.wq = vmalloc(srq->rq.size * sz);
++ srq->rq.wq = vmalloc_user(sizeof(struct ipath_rwq) + srq->rq.size * sz);
+ if (!srq->rq.wq) {
+- kfree(srq);
+ ret = ERR_PTR(-ENOMEM);
+- goto bail;
++ goto bail_srq;
+ }
+
+ /*
++ * Return the address of the RWQ as the offset to mmap.
++ * See ipath_mmap() for details.
++ */
++ if (udata && udata->outlen >= sizeof(__u64)) {
++ struct ipath_mmap_info *ip;
++ __u64 offset = (__u64) srq->rq.wq;
++ int err;
++
++ err = ib_copy_to_udata(udata, &offset, sizeof(offset));
++ if (err) {
++ ret = ERR_PTR(err);
++ goto bail_wq;
++ }
++
++ /* Allocate info for ipath_mmap(). */
++ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
++ if (!ip) {
++ ret = ERR_PTR(-ENOMEM);
++ goto bail_wq;
++ }
++ srq->ip = ip;
++ ip->context = ibpd->uobject->context;
++ ip->obj = srq->rq.wq;
++ kref_init(&ip->ref);
++ ip->mmap_cnt = 0;
++ ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
++ srq->rq.size * sz);
++ spin_lock_irq(&dev->pending_lock);
++ ip->next = dev->pending_mmaps;
++ dev->pending_mmaps = ip;
++ spin_unlock_irq(&dev->pending_lock);
++ } else
++ srq->ip = NULL;
++
++ /*
+ * ib_create_srq() will initialize srq->ibsrq.
+ */
+ spin_lock_init(&srq->rq.lock);
+- srq->rq.head = 0;
+- srq->rq.tail = 0;
+- srq->rq.max_sge = srq_init_attr->attr.max_sge;
++ srq->rq.wq->head = 0;
++ srq->rq.wq->tail = 0;
+ srq->limit = srq_init_attr->attr.srq_limit;
+
++ spin_lock(&dev->n_srqs_lock);
++ if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
++ spin_unlock(&dev->n_srqs_lock);
++ ret = ERR_PTR(-ENOMEM);
++ goto bail_wq;
++ }
++
++ dev->n_srqs_allocated++;
++ spin_unlock(&dev->n_srqs_lock);
++
+ ret = &srq->ibsrq;
++ goto done;
+
+- dev->n_srqs_allocated++;
++bail_wq:
++ vfree(srq->rq.wq);
+
+-bail:
++bail_srq:
++ kfree(srq);
++
++done:
+ return ret;
+ }
+
+@@ -188,83 +205,130 @@ bail:
+ * @ibsrq: the SRQ to modify
+ * @attr: the new attributes of the SRQ
+ * @attr_mask: indicates which attributes to modify
++ * @udata: user data for ipathverbs.so
+ */
+ int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+- enum ib_srq_attr_mask attr_mask)
++ enum ib_srq_attr_mask attr_mask,
++ struct ib_udata *udata)
+ {
+ struct ipath_srq *srq = to_isrq(ibsrq);
+- unsigned long flags;
+- int ret;
++ int ret = 0;
+
+- if (attr_mask & IB_SRQ_MAX_WR)
+- if ((attr->max_wr > ib_ipath_max_srq_wrs) ||
+- (attr->max_sge > srq->rq.max_sge)) {
+- ret = -EINVAL;
+- goto bail;
+- }
++ if (attr_mask & IB_SRQ_MAX_WR) {
++ struct ipath_rwq *owq;
++ struct ipath_rwq *wq;
++ struct ipath_rwqe *p;
++ u32 sz, size, n, head, tail;
+
+- if (attr_mask & IB_SRQ_LIMIT)
+- if (attr->srq_limit >= srq->rq.size) {
++ /* Check that the requested sizes are below the limits. */
++ if ((attr->max_wr > ib_ipath_max_srq_wrs) ||
++ ((attr_mask & IB_SRQ_LIMIT) ?
++ attr->srq_limit : srq->limit) > attr->max_wr) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+- if (attr_mask & IB_SRQ_MAX_WR) {
+- struct ipath_rwqe *wq, *p;
+- u32 sz, size, n;
+-
+ sz = sizeof(struct ipath_rwqe) +
+- attr->max_sge * sizeof(struct ipath_sge);
++ srq->rq.max_sge * sizeof(struct ib_sge);
+ size = attr->max_wr + 1;
+- wq = vmalloc(size * sz);
++ wq = vmalloc_user(sizeof(struct ipath_rwq) + size * sz);
+ if (!wq) {
+ ret = -ENOMEM;
+ goto bail;
+ }
+
+- spin_lock_irqsave(&srq->rq.lock, flags);
+- if (srq->rq.head < srq->rq.tail)
+- n = srq->rq.size + srq->rq.head - srq->rq.tail;
++ /*
++ * Return the address of the RWQ as the offset to mmap.
++ * See ipath_mmap() for details.
++ */
++ if (udata && udata->inlen >= sizeof(__u64)) {
++ __u64 offset_addr;
++ __u64 offset = (__u64) wq;
++
++ ret = ib_copy_from_udata(&offset_addr, udata,
++ sizeof(offset_addr));
++ if (ret) {
++ vfree(wq);
++ goto bail;
++ }
++ udata->outbuf = (void __user *) offset_addr;
++ ret = ib_copy_to_udata(udata, &offset,
++ sizeof(offset));
++ if (ret) {
++ vfree(wq);
++ goto bail;
++ }
++ }
++
++ spin_lock_irq(&srq->rq.lock);
++ /*
++ * validate head pointer value and compute
++ * the number of remaining WQEs.
++ */
++ owq = srq->rq.wq;
++ head = owq->head;
++ if (head >= srq->rq.size)
++ head = 0;
++ tail = owq->tail;
++ if (tail >= srq->rq.size)
++ tail = 0;
++ n = head;
++ if (n < tail)
++ n += srq->rq.size - tail;
+ else
+- n = srq->rq.head - srq->rq.tail;
+- if (size <= n || size <= srq->limit) {
+- spin_unlock_irqrestore(&srq->rq.lock, flags);
++ n -= tail;
++ if (size <= n) {
++ spin_unlock_irq(&srq->rq.lock);
+ vfree(wq);
+ ret = -EINVAL;
+ goto bail;
+ }
+ n = 0;
+- p = wq;
+- while (srq->rq.tail != srq->rq.head) {
++ p = wq->wq;
++ while (tail != head) {
+ struct ipath_rwqe *wqe;
+ int i;
+
+- wqe = get_rwqe_ptr(&srq->rq, srq->rq.tail);
++ wqe = get_rwqe_ptr(&srq->rq, tail);
+ p->wr_id = wqe->wr_id;
+- p->length = wqe->length;
+ p->num_sge = wqe->num_sge;
+ for (i = 0; i < wqe->num_sge; i++)
+ p->sg_list[i] = wqe->sg_list[i];
+ n++;
+ p = (struct ipath_rwqe *)((char *) p + sz);
+- if (++srq->rq.tail >= srq->rq.size)
+- srq->rq.tail = 0;
++ if (++tail >= srq->rq.size)
++ tail = 0;
+ }
+- vfree(srq->rq.wq);
+ srq->rq.wq = wq;
+ srq->rq.size = size;
+- srq->rq.head = n;
+- srq->rq.tail = 0;
+- srq->rq.max_sge = attr->max_sge;
+- spin_unlock_irqrestore(&srq->rq.lock, flags);
+- }
+-
+- if (attr_mask & IB_SRQ_LIMIT) {
+- spin_lock_irqsave(&srq->rq.lock, flags);
+- srq->limit = attr->srq_limit;
+- spin_unlock_irqrestore(&srq->rq.lock, flags);
++ wq->head = n;
++ wq->tail = 0;
++ if (attr_mask & IB_SRQ_LIMIT)
++ srq->limit = attr->srq_limit;
++ spin_unlock_irq(&srq->rq.lock);
++
++ vfree(owq);
++
++ if (srq->ip) {
++ struct ipath_mmap_info *ip = srq->ip;
++ struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
++
++ ip->obj = wq;
++ ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
++ size * sz);
++ spin_lock_irq(&dev->pending_lock);
++ ip->next = dev->pending_mmaps;
++ dev->pending_mmaps = ip;
++ spin_unlock_irq(&dev->pending_lock);
++ }
++ } else if (attr_mask & IB_SRQ_LIMIT) {
++ spin_lock_irq(&srq->rq.lock);
++ if (attr->srq_limit >= srq->rq.size)
++ ret = -EINVAL;
++ else
++ srq->limit = attr->srq_limit;
++ spin_unlock_irq(&srq->rq.lock);
+ }
+- ret = 0;
+
+ bail:
+ return ret;
+@@ -289,8 +353,13 @@ int ipath_destroy_srq(struct ib_srq *ibs
+ struct ipath_srq *srq = to_isrq(ibsrq);
+ struct ipath_ibdev *dev = to_idev(ibsrq->device);
+
++ spin_lock(&dev->n_srqs_lock);
+ dev->n_srqs_allocated--;
+- vfree(srq->rq.wq);
++ spin_unlock(&dev->n_srqs_lock);
++ if (srq->ip)
++ kref_put(&srq->ip->ref, ipath_release_mmap_info);
++ else
++ vfree(srq->rq.wq);
+ kfree(srq);
+
+ return 0;
+diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
+index 70351b7..30a8259 100644
+--- a/drivers/infiniband/hw/ipath/ipath_stats.c
++++ b/drivers/infiniband/hw/ipath/ipath_stats.c
+@@ -271,33 +271,6 @@ void ipath_get_faststats(unsigned long o
+ }
+ }
+
+- if (dd->ipath_nosma_bufs) {
+- dd->ipath_nosma_secs += 5;
+- if (dd->ipath_nosma_secs >= 30) {
+- ipath_cdbg(SMA, "No SMA bufs avail %u seconds; "
+- "cancelling pending sends\n",
+- dd->ipath_nosma_secs);
+- /*
+- * issue an abort as well, in case we have a packet
+- * stuck in launch fifo. This could corrupt an
+- * outgoing user packet in the worst case,
+- * but this is a pretty catastrophic, anyway.
+- */
+- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+- INFINIPATH_S_ABORT);
+- ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
+- dd->ipath_piobcnt2k +
+- dd->ipath_piobcnt4k -
+- dd->ipath_lastport_piobuf);
+- /* start again, if necessary */
+- dd->ipath_nosma_secs = 0;
+- } else
+- ipath_cdbg(SMA, "No SMA bufs avail %u tries, "
+- "after %u seconds\n",
+- dd->ipath_nosma_bufs,
+- dd->ipath_nosma_secs);
+- }
+-
+ done:
+ mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5);
+ }
+diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
+index b98821d..182de34 100644
+--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
++++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
+@@ -35,7 +35,6 @@
+ #include <linux/pci.h>
+
+ #include "ipath_kernel.h"
+-#include "ipath_layer.h"
+ #include "ipath_common.h"
+
+ /**
+@@ -76,7 +75,7 @@ bail:
+ static ssize_t show_version(struct device_driver *dev, char *buf)
+ {
+ /* The string printed here is already newline-terminated. */
+- return scnprintf(buf, PAGE_SIZE, "%s", ipath_core_version);
++ return scnprintf(buf, PAGE_SIZE, "%s", ib_ipath_version);
+ }
+
+ static ssize_t show_num_units(struct device_driver *dev, char *buf)
+@@ -108,8 +107,8 @@ static const char *ipath_status_str[] =
+ "Initted",
+ "Disabled",
+ "Admin_Disabled",
+- "OIB_SMA",
+- "SMA",
++ "", /* This used to be the old "OIB_SMA" status. */
++ "", /* This used to be the old "SMA" status. */
+ "Present",
+ "IB_link_up",
+ "IB_configured",
+@@ -227,7 +226,6 @@ static ssize_t store_mlid(struct device
+ unit = dd->ipath_unit;
+
+ dd->ipath_mlid = mlid;
+- ipath_layer_intr(dd, IPATH_LAYER_INT_BCAST);
+
+ goto bail;
+ invalid:
+@@ -259,7 +257,7 @@ static ssize_t store_guid(struct device
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+ ssize_t ret;
+ unsigned short guid[8];
+- __be64 nguid;
++ __be64 new_guid;
+ u8 *ng;
+ int i;
+
+@@ -268,7 +266,7 @@ static ssize_t store_guid(struct device
+ &guid[4], &guid[5], &guid[6], &guid[7]) != 8)
+ goto invalid;
+
+- ng = (u8 *) &nguid;
++ ng = (u8 *) &new_guid;
+
+ for (i = 0; i < 8; i++) {
+ if (guid[i] > 0xff)
+@@ -276,7 +274,10 @@ static ssize_t store_guid(struct device
+ ng[i] = guid[i];
+ }
+
+- dd->ipath_guid = nguid;
++ if (new_guid == 0)
++ goto invalid;
++
++ dd->ipath_guid = new_guid;
+ dd->ipath_nguid = 1;
+
+ ret = strlen(buf);
+@@ -299,6 +300,16 @@ static ssize_t show_nguid(struct device
+ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid);
+ }
+
++static ssize_t show_nports(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct ipath_devdata *dd = dev_get_drvdata(dev);
++
++ /* Return the number of user ports available. */
++ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_cfgports - 1);
++}
++
+ static ssize_t show_serial(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+@@ -467,7 +478,7 @@ static ssize_t store_link_state(struct d
+ if (ret < 0)
+ goto invalid;
+
+- r = ipath_layer_set_linkstate(dd, state);
++ r = ipath_set_linkstate(dd, state);
+ if (r < 0) {
+ ret = r;
+ goto bail;
+@@ -502,7 +513,7 @@ static ssize_t store_mtu(struct device *
+ if (ret < 0)
+ goto invalid;
+
+- r = ipath_layer_set_mtu(dd, mtu);
++ r = ipath_set_mtu(dd, mtu);
+ if (r < 0)
+ ret = r;
+
+@@ -563,6 +574,33 @@ bail:
+ return ret;
+ }
+
++static ssize_t store_rx_pol_inv(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf,
++ size_t count)
++{
++ struct ipath_devdata *dd = dev_get_drvdata(dev);
++ int ret, r;
++ u16 val;
++
++ ret = ipath_parse_ushort(buf, &val);
++ if (ret < 0)
++ goto invalid;
++
++ r = ipath_set_rx_pol_inv(dd, val);
++ if (r < 0) {
++ ret = r;
++ goto bail;
++ }
++
++ goto bail;
++invalid:
++ ipath_dev_err(dd, "attempt to set invalid Rx Polarity invert\n");
++bail:
++ return ret;
++}
++
++
+ static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
+ static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
+
+@@ -583,12 +621,14 @@ static DEVICE_ATTR(mlid, S_IWUSR | S_IRU
+ static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu);
+ static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled);
+ static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL);
++static DEVICE_ATTR(nports, S_IRUGO, show_nports, NULL);
+ static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset);
+ static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
+ static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+ static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL);
+ static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
+ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
++static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
+
+ static struct attribute *dev_attributes[] = {
+ &dev_attr_guid.attr,
+@@ -597,12 +637,14 @@ static struct attribute *dev_attributes[
+ &dev_attr_mlid.attr,
+ &dev_attr_mtu.attr,
+ &dev_attr_nguid.attr,
++ &dev_attr_nports.attr,
+ &dev_attr_serial.attr,
+ &dev_attr_status.attr,
+ &dev_attr_status_str.attr,
+ &dev_attr_boardversion.attr,
+ &dev_attr_unit.attr,
+ &dev_attr_enabled.attr,
++ &dev_attr_rx_pol_inv.attr,
+ NULL
+ };
+
+diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
+index c33abea..e636cfd 100644
+--- a/drivers/infiniband/hw/ipath/ipath_uc.c
++++ b/drivers/infiniband/hw/ipath/ipath_uc.c
+@@ -32,7 +32,7 @@
+ */
+
+ #include "ipath_verbs.h"
+-#include "ipath_common.h"
++#include "ipath_kernel.h"
+
+ /* cut down ridiculously long IB macro names */
+ #define OP(x) IB_OPCODE_UC_##x
+@@ -246,6 +246,10 @@ void ipath_uc_rcv(struct ipath_ibdev *de
+ struct ib_reth *reth;
+ int header_in_data;
+
++ /* Validate the SLID. See Ch. 9.6.1.5 */
++ if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
++ goto done;
++
+ /* Check for GRH */
+ if (!has_grh) {
+ ohdr = &hdr->u.oth;
+@@ -261,8 +265,7 @@ void ipath_uc_rcv(struct ipath_ibdev *de
+ * size to 56 bytes so the last 4 bytes of
+ * the BTH header (PSN) is in the data buffer.
+ */
+- header_in_data =
+- ipath_layer_get_rcvhdrentsize(dev->dd) == 16;
++ header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
+ if (header_in_data) {
+ psn = be32_to_cpu(((__be32 *) data)[0]);
+ data += sizeof(__be32);
+@@ -441,7 +444,7 @@ void ipath_uc_rcv(struct ipath_ibdev *de
+ int ok;
+
+ /* Check rkey */
+- ok = ipath_rkey_ok(dev, &qp->r_sge, qp->r_len,
++ ok = ipath_rkey_ok(qp, &qp->r_sge, qp->r_len,
+ vaddr, rkey,
+ IB_ACCESS_REMOTE_WRITE);
+ if (unlikely(!ok)) {
+diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
+index 3466129..49f1102 100644
+--- a/drivers/infiniband/hw/ipath/ipath_ud.c
++++ b/drivers/infiniband/hw/ipath/ipath_ud.c
+@@ -34,7 +34,52 @@
+ #include <rdma/ib_smi.h>
+
+ #include "ipath_verbs.h"
+-#include "ipath_common.h"
++#include "ipath_kernel.h"
++
++static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
++ u32 *lengthp, struct ipath_sge_state *ss)
++{
++ int user = to_ipd(qp->ibqp.pd)->user;
++ int i, j, ret;
++ struct ib_wc wc;
++
++ *lengthp = 0;
++ for (i = j = 0; i < wqe->num_sge; i++) {
++ if (wqe->sg_list[i].length == 0)
++ continue;
++ /* Check LKEY */
++ if ((user && wqe->sg_list[i].lkey == 0) ||
++ !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
++ &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
++ goto bad_lkey;
++ *lengthp += wqe->sg_list[i].length;
++ j++;
++ }
++ ss->num_sge = j;
++ ret = 1;
++ goto bail;
++
++bad_lkey:
++ wc.wr_id = wqe->wr_id;
++ wc.status = IB_WC_LOC_PROT_ERR;
++ wc.opcode = IB_WC_RECV;
++ wc.vendor_err = 0;
++ wc.byte_len = 0;
++ wc.imm_data = 0;
++ wc.qp_num = qp->ibqp.qp_num;
++ wc.src_qp = 0;
++ wc.wc_flags = 0;
++ wc.pkey_index = 0;
++ wc.slid = 0;
++ wc.sl = 0;
++ wc.dlid_path_bits = 0;
++ wc.port_num = 0;
++ /* Signal solicited completion event. */
++ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
++ ret = 0;
++bail:
++ return ret;
++}
+
+ /**
+ * ipath_ud_loopback - handle send on loopback QPs
+@@ -46,6 +91,8 @@
+ *
+ * This is called from ipath_post_ud_send() to forward a WQE addressed
+ * to the same HCA.
++ * Note that the receive interrupt handler may be calling ipath_ud_rcv()
++ * while this is being called.
+ */
+ static void ipath_ud_loopback(struct ipath_qp *sqp,
+ struct ipath_sge_state *ss,
+@@ -60,7 +107,11 @@ static void ipath_ud_loopback(struct ipa
+ struct ipath_srq *srq;
+ struct ipath_sge_state rsge;
+ struct ipath_sge *sge;
++ struct ipath_rwq *wq;
+ struct ipath_rwqe *wqe;
++ void (*handler)(struct ib_event *, void *);
++ u32 tail;
++ u32 rlen;
+
+ qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);
+ if (!qp)
+@@ -94,6 +145,13 @@ static void ipath_ud_loopback(struct ipa
+ wc->imm_data = 0;
+ }
+
++ if (wr->num_sge > 1) {
++ rsge.sg_list = kmalloc((wr->num_sge - 1) *
++ sizeof(struct ipath_sge),
++ GFP_ATOMIC);
++ } else
++ rsge.sg_list = NULL;
++
+ /*
+ * Get the next work request entry to find where to put the data.
+ * Note that it is safe to drop the lock after changing rq->tail
+@@ -101,37 +159,52 @@ static void ipath_ud_loopback(struct ipa
+ */
+ if (qp->ibqp.srq) {
+ srq = to_isrq(qp->ibqp.srq);
++ handler = srq->ibsrq.event_handler;
+ rq = &srq->rq;
+ } else {
+ srq = NULL;
++ handler = NULL;
+ rq = &qp->r_rq;
+ }
++
+ spin_lock_irqsave(&rq->lock, flags);
+- if (rq->tail == rq->head) {
+- spin_unlock_irqrestore(&rq->lock, flags);
+- dev->n_pkt_drops++;
+- goto done;
++ wq = rq->wq;
++ tail = wq->tail;
++ while (1) {
++ if (unlikely(tail == wq->head)) {
++ spin_unlock_irqrestore(&rq->lock, flags);
++ dev->n_pkt_drops++;
++ goto bail_sge;
++ }
++ wqe = get_rwqe_ptr(rq, tail);
++ if (++tail >= rq->size)
++ tail = 0;
++ if (init_sge(qp, wqe, &rlen, &rsge))
++ break;
++ wq->tail = tail;
+ }
+ /* Silently drop packets which are too big. */
+- wqe = get_rwqe_ptr(rq, rq->tail);
+- if (wc->byte_len > wqe->length) {
++ if (wc->byte_len > rlen) {
+ spin_unlock_irqrestore(&rq->lock, flags);
+ dev->n_pkt_drops++;
+- goto done;
++ goto bail_sge;
+ }
++ wq->tail = tail;
+ wc->wr_id = wqe->wr_id;
+- rsge.sge = wqe->sg_list[0];
+- rsge.sg_list = wqe->sg_list + 1;
+- rsge.num_sge = wqe->num_sge;
+- if (++rq->tail >= rq->size)
+- rq->tail = 0;
+- if (srq && srq->ibsrq.event_handler) {
++ if (handler) {
+ u32 n;
+
+- if (rq->head < rq->tail)
+- n = rq->size + rq->head - rq->tail;
++ /*
++ * validate head pointer value and compute
++ * the number of remaining WQEs.
++ */
++ n = wq->head;
++ if (n >= rq->size)
++ n = 0;
++ if (n < tail)
++ n += rq->size - tail;
+ else
+- n = rq->head - rq->tail;
++ n -= tail;
+ if (n < srq->limit) {
+ struct ib_event ev;
+
+@@ -140,12 +213,12 @@ static void ipath_ud_loopback(struct ipa
+ ev.device = qp->ibqp.device;
+ ev.element.srq = qp->ibqp.srq;
+ ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
+- srq->ibsrq.event_handler(&ev,
+- srq->ibsrq.srq_context);
++ handler(&ev, srq->ibsrq.srq_context);
+ } else
+ spin_unlock_irqrestore(&rq->lock, flags);
+ } else
+ spin_unlock_irqrestore(&rq->lock, flags);
++
+ ah_attr = &to_iah(wr->wr.ud.ah)->attr;
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
+@@ -186,7 +259,7 @@ static void ipath_ud_loopback(struct ipa
+ wc->src_qp = sqp->ibqp.qp_num;
+ /* XXX do we know which pkey matched? Only needed for GSI. */
+ wc->pkey_index = 0;
+- wc->slid = ipath_layer_get_lid(dev->dd) |
++ wc->slid = dev->dd->ipath_lid |
+ (ah_attr->src_path_bits &
+ ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));
+ wc->sl = ah_attr->sl;
+@@ -196,6 +269,8 @@ static void ipath_ud_loopback(struct ipa
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
+ wr->send_flags & IB_SEND_SOLICITED);
+
++bail_sge:
++ kfree(rsge.sg_list);
+ done:
+ if (atomic_dec_and_test(&qp->refcount))
+ wake_up(&qp->wait);
+@@ -266,7 +341,7 @@ int ipath_post_ud_send(struct ipath_qp *
+
+ if (wr->sg_list[i].length == 0)
+ continue;
+- if (!ipath_lkey_ok(&dev->lk_table, ss.num_sge ?
++ if (!ipath_lkey_ok(qp, ss.num_sge ?
+ sg_list + ss.num_sge - 1 : &ss.sge,
+ &wr->sg_list[i], 0)) {
+ ret = -EINVAL;
+@@ -276,7 +351,7 @@ int ipath_post_ud_send(struct ipath_qp *
+ ss.num_sge++;
+ }
+ /* Check for invalid packet size. */
+- if (len > ipath_layer_get_ibmtu(dev->dd)) {
++ if (len > dev->dd->ipath_ibmtu) {
+ ret = -EINVAL;
+ goto bail;
+ }
+@@ -298,7 +373,7 @@ int ipath_post_ud_send(struct ipath_qp *
+ dev->n_unicast_xmit++;
+ lid = ah_attr->dlid &
+ ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+- if (unlikely(lid == ipath_layer_get_lid(dev->dd))) {
++ if (unlikely(lid == dev->dd->ipath_lid)) {
+ /*
+ * Pass in an uninitialized ib_wc to save stack
+ * space.
+@@ -327,7 +402,7 @@ int ipath_post_ud_send(struct ipath_qp *
+ qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
+ dev->gid_prefix;
+ qp->s_hdr.u.l.grh.sgid.global.interface_id =
+- ipath_layer_get_guid(dev->dd);
++ dev->dd->ipath_guid;
+ qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid;
+ /*
+ * Don't worry about sending to locally attached multicast
+@@ -357,7 +432,7 @@ int ipath_post_ud_send(struct ipath_qp *
+ qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
+ qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
+ qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
+- lid = ipath_layer_get_lid(dev->dd);
++ lid = dev->dd->ipath_lid;
+ if (lid) {
+ lid |= ah_attr->src_path_bits &
+ ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+@@ -368,7 +443,7 @@ int ipath_post_ud_send(struct ipath_qp *
+ bth0 |= 1 << 23;
+ bth0 |= extra_bytes << 20;
+ bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
+- ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
++ ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ ohdr->bth[0] = cpu_to_be32(bth0);
+ /*
+ * Use the multicast QP if the destination LID is a multicast LID.
+@@ -433,13 +508,9 @@ void ipath_ud_rcv(struct ipath_ibdev *de
+ int opcode;
+ u32 hdrsize;
+ u32 pad;
+- unsigned long flags;
+ struct ib_wc wc;
+ u32 qkey;
+ u32 src_qp;
+- struct ipath_rq *rq;
+- struct ipath_srq *srq;
+- struct ipath_rwqe *wqe;
+ u16 dlid;
+ int header_in_data;
+
+@@ -458,8 +529,7 @@ void ipath_ud_rcv(struct ipath_ibdev *de
+ * the eager header buffer size to 56 bytes so the last 12
+ * bytes of the IB header is in the data buffer.
+ */
+- header_in_data =
+- ipath_layer_get_rcvhdrentsize(dev->dd) == 16;
++ header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
+ if (header_in_data) {
+ qkey = be32_to_cpu(((__be32 *) data)[1]);
+ src_qp = be32_to_cpu(((__be32 *) data)[2]);
+@@ -547,19 +617,10 @@ void ipath_ud_rcv(struct ipath_ibdev *de
+
+ /*
+ * Get the next work request entry to find where to put the data.
+- * Note that it is safe to drop the lock after changing rq->tail
+- * since ipath_post_receive() won't fill the empty slot.
+ */
+- if (qp->ibqp.srq) {
+- srq = to_isrq(qp->ibqp.srq);
+- rq = &srq->rq;
+- } else {
+- srq = NULL;
+- rq = &qp->r_rq;
+- }
+- spin_lock_irqsave(&rq->lock, flags);
+- if (rq->tail == rq->head) {
+- spin_unlock_irqrestore(&rq->lock, flags);
++ if (qp->r_reuse_sge)
++ qp->r_reuse_sge = 0;
++ else if (!ipath_get_rwqe(qp, 0)) {
+ /*
+ * Count VL15 packets dropped due to no receive buffer.
+ * Otherwise, count them as buffer overruns since usually,
+@@ -573,39 +634,11 @@ void ipath_ud_rcv(struct ipath_ibdev *de
+ goto bail;
+ }
+ /* Silently drop packets which are too big. */
+- wqe = get_rwqe_ptr(rq, rq->tail);
+- if (wc.byte_len > wqe->length) {
+- spin_unlock_irqrestore(&rq->lock, flags);
++ if (wc.byte_len > qp->r_len) {
++ qp->r_reuse_sge = 1;
+ dev->n_pkt_drops++;
+ goto bail;
+ }
+- wc.wr_id = wqe->wr_id;
+- qp->r_sge.sge = wqe->sg_list[0];
+- qp->r_sge.sg_list = wqe->sg_list + 1;
+- qp->r_sge.num_sge = wqe->num_sge;
+- if (++rq->tail >= rq->size)
+- rq->tail = 0;
+- if (srq && srq->ibsrq.event_handler) {
+- u32 n;
+-
+- if (rq->head < rq->tail)
+- n = rq->size + rq->head - rq->tail;
+- else
+- n = rq->head - rq->tail;
+- if (n < srq->limit) {
+- struct ib_event ev;
+-
+- srq->limit = 0;
+- spin_unlock_irqrestore(&rq->lock, flags);
+- ev.device = qp->ibqp.device;
+- ev.element.srq = qp->ibqp.srq;
+- ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
+- srq->ibsrq.event_handler(&ev,
+- srq->ibsrq.srq_context);
+- } else
+- spin_unlock_irqrestore(&rq->lock, flags);
+- } else
+- spin_unlock_irqrestore(&rq->lock, flags);
+ if (has_grh) {
+ ipath_copy_sge(&qp->r_sge, &hdr->u.l.grh,
+ sizeof(struct ib_grh));
+@@ -614,6 +647,7 @@ void ipath_ud_rcv(struct ipath_ibdev *de
+ ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh));
+ ipath_copy_sge(&qp->r_sge, data,
+ wc.byte_len - sizeof(struct ib_grh));
++ wc.wr_id = qp->r_wr_id;
+ wc.status = IB_WC_SUCCESS;
+ wc.opcode = IB_WC_RECV;
+ wc.vendor_err = 0;
+diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
+index e32fca9..413754b 100644
+--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
++++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
+@@ -90,6 +90,62 @@ bail:
+ }
+
+ /**
++ * ipath_map_page - a safety wrapper around pci_map_page()
++ *
++ * A dma_addr of all 0's is interpreted by the chip as "disabled".
++ * Unfortunately, it can also be a valid dma_addr returned on some
++ * architectures.
++ *
++ * The powerpc iommu assigns dma_addrs in ascending order, so we don't
++ * have to bother with retries or mapping a dummy page to insure we
++ * don't just get the same mapping again.
++ *
++ * I'm sure we won't be so lucky with other iommu's, so FIXME.
++ */
++dma_addr_t ipath_map_page(struct pci_dev *hwdev, struct page *page,
++ unsigned long offset, size_t size, int direction)
++{
++ dma_addr_t phys;
++
++ phys = pci_map_page(hwdev, page, offset, size, direction);
++
++ if (phys == 0) {
++ pci_unmap_page(hwdev, phys, size, direction);
++ phys = pci_map_page(hwdev, page, offset, size, direction);
++ /*
++ * FIXME: If we get 0 again, we should keep this page,
++ * map another, then free the 0 page.
++ */
++ }
++
++ return phys;
++}
++
++/**
++ * ipath_map_single - a safety wrapper around pci_map_single()
++ *
++ * Same idea as ipath_map_page().
++ */
++dma_addr_t ipath_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
++ int direction)
++{
++ dma_addr_t phys;
++
++ phys = pci_map_single(hwdev, ptr, size, direction);
++
++ if (phys == 0) {
++ pci_unmap_single(hwdev, phys, size, direction);
++ phys = pci_map_single(hwdev, ptr, size, direction);
++ /*
++ * FIXME: If we get 0 again, we should keep this page,
++ * map another, then free the 0 page.
++ */
++ }
++
++ return phys;
++}
++
++/**
+ * ipath_get_user_pages - lock user pages into memory
+ * @start_page: the start page
+ * @num_pages: the number of pages
+diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
+index d70a9b6..a545610 100644
+--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
++++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
+@@ -33,15 +33,13 @@
+
+ #include <rdma/ib_mad.h>
+ #include <rdma/ib_user_verbs.h>
++#include <linux/io.h>
+ #include <linux/utsname.h>
+
+ #include "ipath_kernel.h"
+ #include "ipath_verbs.h"
+ #include "ipath_common.h"
+
+-/* Not static, because we don't want the compiler removing it */
+-const char ipath_verbs_version[] = "ipath_verbs " IPATH_IDSTR;
+-
+ static unsigned int ib_ipath_qp_table_size = 251;
+ module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO);
+ MODULE_PARM_DESC(qp_table_size, "QP table size");
+@@ -52,10 +50,6 @@ module_param_named(lkey_table_size, ib_i
+ MODULE_PARM_DESC(lkey_table_size,
+ "LKEY table size in bits (2^n, 1 <= n <= 23)");
+
+-unsigned int ib_ipath_debug; /* debug mask */
+-module_param_named(debug, ib_ipath_debug, uint, S_IWUSR | S_IRUGO);
+-MODULE_PARM_DESC(debug, "Verbs debug mask");
+-
+ static unsigned int ib_ipath_max_pds = 0xFFFF;
+ module_param_named(max_pds, ib_ipath_max_pds, uint, S_IWUSR | S_IRUGO);
+ MODULE_PARM_DESC(max_pds,
+@@ -79,6 +73,10 @@ module_param_named(max_qp_wrs, ib_ipath_
+ S_IWUSR | S_IRUGO);
+ MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support");
+
++unsigned int ib_ipath_max_qps = 16384;
++module_param_named(max_qps, ib_ipath_max_qps, uint, S_IWUSR | S_IRUGO);
++MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support");
++
+ unsigned int ib_ipath_max_sges = 0x60;
+ module_param_named(max_sges, ib_ipath_max_sges, uint, S_IWUSR | S_IRUGO);
+ MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support");
+@@ -109,9 +107,9 @@ module_param_named(max_srq_wrs, ib_ipath
+ uint, S_IWUSR | S_IRUGO);
+ MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support");
+
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("QLogic <support at pathscale.com>");
+-MODULE_DESCRIPTION("QLogic InfiniPath driver");
++static unsigned int ib_ipath_disable_sma;
++module_param_named(disable_sma, ib_ipath_disable_sma, uint, S_IWUSR | S_IRUGO);
++MODULE_PARM_DESC(ib_ipath_disable_sma, "Disable the SMA");
+
+ const int ib_ipath_state_ops[IB_QPS_ERR + 1] = {
+ [IB_QPS_RESET] = 0,
+@@ -125,6 +123,16 @@ const int ib_ipath_state_ops[IB_QPS_ERR
+ [IB_QPS_ERR] = 0,
+ };
+
++struct ipath_ucontext {
++ struct ib_ucontext ibucontext;
++};
++
++static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext
++ *ibucontext)
++{
++ return container_of(ibucontext, struct ipath_ucontext, ibucontext);
++}
++
+ /*
+ * Translate ib_wr_opcode into ib_wc_opcode.
+ */
+@@ -277,11 +285,12 @@ static int ipath_post_receive(struct ib_
+ struct ib_recv_wr **bad_wr)
+ {
+ struct ipath_qp *qp = to_iqp(ibqp);
++ struct ipath_rwq *wq = qp->r_rq.wq;
+ unsigned long flags;
+ int ret;
+
+ /* Check that state is OK to post receive. */
+- if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK)) {
++ if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK) || !wq) {
+ *bad_wr = wr;
+ ret = -EINVAL;
+ goto bail;
+@@ -290,59 +299,31 @@ static int ipath_post_receive(struct ib_
+ for (; wr; wr = wr->next) {
+ struct ipath_rwqe *wqe;
+ u32 next;
+- int i, j;
++ int i;
+
+- if (wr->num_sge > qp->r_rq.max_sge) {
++ if ((unsigned) wr->num_sge > qp->r_rq.max_sge) {
+ *bad_wr = wr;
+ ret = -ENOMEM;
+ goto bail;
+ }
+
+ spin_lock_irqsave(&qp->r_rq.lock, flags);
+- next = qp->r_rq.head + 1;
++ next = wq->head + 1;
+ if (next >= qp->r_rq.size)
+ next = 0;
+- if (next == qp->r_rq.tail) {
++ if (next == wq->tail) {
+ spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+ *bad_wr = wr;
+ ret = -ENOMEM;
+ goto bail;
+ }
+
+- wqe = get_rwqe_ptr(&qp->r_rq, qp->r_rq.head);
++ wqe = get_rwqe_ptr(&qp->r_rq, wq->head);
+ wqe->wr_id = wr->wr_id;
+- wqe->sg_list[0].mr = NULL;
+- wqe->sg_list[0].vaddr = NULL;
+- wqe->sg_list[0].length = 0;
+- wqe->sg_list[0].sge_length = 0;
+- wqe->length = 0;
+- for (i = 0, j = 0; i < wr->num_sge; i++) {
+- /* Check LKEY */
+- if (to_ipd(qp->ibqp.pd)->user &&
+- wr->sg_list[i].lkey == 0) {
+- spin_unlock_irqrestore(&qp->r_rq.lock,
+- flags);
+- *bad_wr = wr;
+- ret = -EINVAL;
+- goto bail;
+- }
+- if (wr->sg_list[i].length == 0)
+- continue;
+- if (!ipath_lkey_ok(
+- &to_idev(qp->ibqp.device)->lk_table,
+- &wqe->sg_list[j], &wr->sg_list[i],
+- IB_ACCESS_LOCAL_WRITE)) {
+- spin_unlock_irqrestore(&qp->r_rq.lock,
+- flags);
+- *bad_wr = wr;
+- ret = -EINVAL;
+- goto bail;
+- }
+- wqe->length += wr->sg_list[i].length;
+- j++;
+- }
+- wqe->num_sge = j;
+- qp->r_rq.head = next;
++ wqe->num_sge = wr->num_sge;
++ for (i = 0; i < wr->num_sge; i++)
++ wqe->sg_list[i] = wr->sg_list[i];
++ wq->head = next;
+ spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+ }
+ ret = 0;
+@@ -377,6 +358,9 @@ static void ipath_qp_rcv(struct ipath_ib
+ switch (qp->ibqp.qp_type) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
++ if (ib_ipath_disable_sma)
++ break;
++ /* FALLTHROUGH */
+ case IB_QPT_UD:
+ ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp);
+ break;
+@@ -395,7 +379,7 @@ static void ipath_qp_rcv(struct ipath_ib
+ }
+
+ /**
+- * ipath_ib_rcv - process and incoming packet
++ * ipath_ib_rcv - process an incoming packet
+ * @arg: the device pointer
+ * @rhdr: the header of the packet
+ * @data: the packet data
+@@ -404,9 +388,9 @@ static void ipath_qp_rcv(struct ipath_ib
+ * This is called from ipath_kreceive() to process an incoming packet at
+ * interrupt level. Tlen is the length of the header + data + CRC in bytes.
+ */
+-static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
++void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data,
++ u32 tlen)
+ {
+- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
+ struct ipath_ib_header *hdr = rhdr;
+ struct ipath_other_headers *ohdr;
+ struct ipath_qp *qp;
+@@ -427,7 +411,7 @@ static void ipath_ib_rcv(void *arg, void
+ lid = be16_to_cpu(hdr->lrh[1]);
+ if (lid < IPATH_MULTICAST_LID_BASE) {
+ lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+- if (unlikely(lid != ipath_layer_get_lid(dev->dd))) {
++ if (unlikely(lid != dev->dd->ipath_lid)) {
+ dev->rcv_errors++;
+ goto bail;
+ }
+@@ -495,9 +479,8 @@ bail:;
+ * This is called from ipath_do_rcv_timer() at interrupt level to check for
+ * QPs which need retransmits and to collect performance numbers.
+ */
+-static void ipath_ib_timer(void *arg)
++void ipath_ib_timer(struct ipath_ibdev *dev)
+ {
+- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
+ struct ipath_qp *resend = NULL;
+ struct list_head *last;
+ struct ipath_qp *qp;
+@@ -539,19 +522,19 @@ static void ipath_ib_timer(void *arg)
+ if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED &&
+ --dev->pma_sample_start == 0) {
+ dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
+- ipath_layer_snapshot_counters(dev->dd, &dev->ipath_sword,
+- &dev->ipath_rword,
+- &dev->ipath_spkts,
+- &dev->ipath_rpkts,
+- &dev->ipath_xmit_wait);
++ ipath_snapshot_counters(dev->dd, &dev->ipath_sword,
++ &dev->ipath_rword,
++ &dev->ipath_spkts,
++ &dev->ipath_rpkts,
++ &dev->ipath_xmit_wait);
+ }
+ if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) {
+ if (dev->pma_sample_interval == 0) {
+ u64 ta, tb, tc, td, te;
+
+ dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
+- ipath_layer_snapshot_counters(dev->dd, &ta, &tb,
+- &tc, &td, &te);
++ ipath_snapshot_counters(dev->dd, &ta, &tb,
++ &tc, &td, &te);
+
+ dev->ipath_sword = ta - dev->ipath_sword;
+ dev->ipath_rword = tb - dev->ipath_rword;
+@@ -581,6 +564,365 @@ static void ipath_ib_timer(void *arg)
+ }
+ }
+
++static void update_sge(struct ipath_sge_state *ss, u32 length)
++{
++ struct ipath_sge *sge = &ss->sge;
++
++ sge->vaddr += length;
++ sge->length -= length;
++ sge->sge_length -= length;
++ if (sge->sge_length == 0) {
++ if (--ss->num_sge)
++ *sge = *ss->sg_list++;
++ } else if (sge->length == 0 && sge->mr != NULL) {
++ if (++sge->n >= IPATH_SEGSZ) {
++ if (++sge->m >= sge->mr->mapsz)
++ return;
++ sge->n = 0;
++ }
++ sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;
++ sge->length = sge->mr->map[sge->m]->segs[sge->n].length;
++ }
++}
++
++#ifdef __LITTLE_ENDIAN
++static inline u32 get_upper_bits(u32 data, u32 shift)
++{
++ return data >> shift;
++}
++
++static inline u32 set_upper_bits(u32 data, u32 shift)
++{
++ return data << shift;
++}
++
++static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
++{
++ data <<= ((sizeof(u32) - n) * BITS_PER_BYTE);
++ data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
++ return data;
++}
++#else
++static inline u32 get_upper_bits(u32 data, u32 shift)
++{
++ return data << shift;
++}
++
++static inline u32 set_upper_bits(u32 data, u32 shift)
++{
++ return data >> shift;
++}
++
++static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
++{
++ data >>= ((sizeof(u32) - n) * BITS_PER_BYTE);
++ data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
++ return data;
++}
++#endif
++
++static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
++ u32 length)
++{
++ u32 extra = 0;
++ u32 data = 0;
++ u32 last;
++
++ while (1) {
++ u32 len = ss->sge.length;
++ u32 off;
++
++ BUG_ON(len == 0);
++ if (len > length)
++ len = length;
++ if (len > ss->sge.sge_length)
++ len = ss->sge.sge_length;
++ /* If the source address is not aligned, try to align it. */
++ off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
++ if (off) {
++ u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr &
++ ~(sizeof(u32) - 1));
++ u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE);
++ u32 y;
++
++ y = sizeof(u32) - off;
++ if (len > y)
++ len = y;
++ if (len + extra >= sizeof(u32)) {
++ data |= set_upper_bits(v, extra *
++ BITS_PER_BYTE);
++ len = sizeof(u32) - extra;
++ if (len == length) {
++ last = data;
++ break;
++ }
++ __raw_writel(data, piobuf);
++ piobuf++;
++ extra = 0;
++ data = 0;
++ } else {
++ /* Clear unused upper bytes */
++ data |= clear_upper_bytes(v, len, extra);
++ if (len == length) {
++ last = data;
++ break;
++ }
++ extra += len;
++ }
++ } else if (extra) {
++ /* Source address is aligned. */
++ u32 *addr = (u32 *) ss->sge.vaddr;
++ int shift = extra * BITS_PER_BYTE;
++ int ushift = 32 - shift;
++ u32 l = len;
++
++ while (l >= sizeof(u32)) {
++ u32 v = *addr;
++
++ data |= set_upper_bits(v, shift);
++ __raw_writel(data, piobuf);
++ data = get_upper_bits(v, ushift);
++ piobuf++;
++ addr++;
++ l -= sizeof(u32);
++ }
++ /*
++ * We still have 'extra' number of bytes leftover.
++ */
++ if (l) {
++ u32 v = *addr;
++
++ if (l + extra >= sizeof(u32)) {
++ data |= set_upper_bits(v, shift);
++ len -= l + extra - sizeof(u32);
++ if (len == length) {
++ last = data;
++ break;
++ }
++ __raw_writel(data, piobuf);
++ piobuf++;
++ extra = 0;
++ data = 0;
++ } else {
++ /* Clear unused upper bytes */
++ data |= clear_upper_bytes(v, l,
++ extra);
++ if (len == length) {
++ last = data;
++ break;
++ }
++ extra += l;
++ }
++ } else if (len == length) {
++ last = data;
++ break;
++ }
++ } else if (len == length) {
++ u32 w;
++
++ /*
++ * Need to round up for the last dword in the
++ * packet.
++ */
++ w = (len + 3) >> 2;
++ __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
++ piobuf += w - 1;
++ last = ((u32 *) ss->sge.vaddr)[w - 1];
++ break;
++ } else {
++ u32 w = len >> 2;
++
++ __iowrite32_copy(piobuf, ss->sge.vaddr, w);
++ piobuf += w;
++
++ extra = len & (sizeof(u32) - 1);
++ if (extra) {
++ u32 v = ((u32 *) ss->sge.vaddr)[w];
++
++ /* Clear unused upper bytes */
++ data = clear_upper_bytes(v, extra, 0);
++ }
++ }
++ update_sge(ss, len);
++ length -= len;
++ }
++ /* Update address before sending packet. */
++ update_sge(ss, length);
++ /* must flush early everything before trigger word */
++ ipath_flush_wc();
++ __raw_writel(last, piobuf);
++ /* be sure trigger word is written */
++ ipath_flush_wc();
++}
++
++/**
++ * ipath_verbs_send - send a packet
++ * @dd: the infinipath device
++ * @hdrwords: the number of words in the header
++ * @hdr: the packet header
++ * @len: the length of the packet in bytes
++ * @ss: the SGE to send
++ */
++int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
++ u32 *hdr, u32 len, struct ipath_sge_state *ss)
++{
++ u32 __iomem *piobuf;
++ u32 plen;
++ int ret;
++
++ /* +1 is for the qword padding of pbc */
++ plen = hdrwords + ((len + 3) >> 2) + 1;
++ if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
++ ipath_dbg("packet len 0x%x too long, failing\n", plen);
++ ret = -EINVAL;
++ goto bail;
++ }
++
++ /* Get a PIO buffer to use. */
++ piobuf = ipath_getpiobuf(dd, NULL);
++ if (unlikely(piobuf == NULL)) {
++ ret = -EBUSY;
++ goto bail;
++ }
++
++ /*
++ * Write len to control qword, no flags.
++ * We have to flush after the PBC for correctness on some cpus
++ * or WC buffer can be written out of order.
++ */
++ writeq(plen, piobuf);
++ ipath_flush_wc();
++ piobuf += 2;
++ if (len == 0) {
++ /*
++ * If there is just the header portion, must flush before
++ * writing last word of header for correctness, and after
++ * the last header word (trigger word).
++ */
++ __iowrite32_copy(piobuf, hdr, hdrwords - 1);
++ ipath_flush_wc();
++ __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
++ ipath_flush_wc();
++ ret = 0;
++ goto bail;
++ }
++
++ __iowrite32_copy(piobuf, hdr, hdrwords);
++ piobuf += hdrwords;
++
++ /* The common case is aligned and contained in one segment. */
++ if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
++ !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
++ u32 w;
++ u32 *addr = (u32 *) ss->sge.vaddr;
++
++ /* Update address before sending packet. */
++ update_sge(ss, len);
++ /* Need to round up for the last dword in the packet. */
++ w = (len + 3) >> 2;
++ __iowrite32_copy(piobuf, addr, w - 1);
++ /* must flush early everything before trigger word */
++ ipath_flush_wc();
++ __raw_writel(addr[w - 1], piobuf + w - 1);
++ /* be sure trigger word is written */
++ ipath_flush_wc();
++ ret = 0;
++ goto bail;
++ }
++ copy_io(piobuf, ss, len);
++ ret = 0;
++
++bail:
++ return ret;
++}
++
++int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
++ u64 *rwords, u64 *spkts, u64 *rpkts,
++ u64 *xmit_wait)
++{
++ int ret;
++
++ if (!(dd->ipath_flags & IPATH_INITTED)) {
++ /* no hardware, freeze, etc. */
++ ipath_dbg("unit %u not usable\n", dd->ipath_unit);
++ ret = -EINVAL;
++ goto bail;
++ }
++ *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
++ *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
++ *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
++ *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
++ *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt);
++
++ ret = 0;
++
++bail:
++ return ret;
++}
++
++/**
++ * ipath_get_counters - get various chip counters
++ * @dd: the infinipath device
++ * @cntrs: counters are placed here
++ *
++ * Return the counters needed by recv_pma_get_portcounters().
++ */
++int ipath_get_counters(struct ipath_devdata *dd,
++ struct ipath_verbs_counters *cntrs)
++{
++ int ret;
++
++ if (!(dd->ipath_flags & IPATH_INITTED)) {
++ /* no hardware, freeze, etc. */
++ ipath_dbg("unit %u not usable\n", dd->ipath_unit);
++ ret = -EINVAL;
++ goto bail;
++ }
++ cntrs->symbol_error_counter =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
++ cntrs->link_error_recovery_counter =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
++ /*
++ * The link downed counter counts when the other side downs the
++ * connection. We add in the number of times we downed the link
++ * due to local link integrity errors to compensate.
++ */
++ cntrs->link_downed_counter =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
++ cntrs->port_rcv_errors =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
++ dd->ipath_rxfc_unsupvl_errs;
++ cntrs->port_rcv_remphys_errors =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
++ cntrs->port_xmit_discards =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
++ cntrs->port_xmit_data =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
++ cntrs->port_rcv_data =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
++ cntrs->port_xmit_packets =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
++ cntrs->port_rcv_packets =
++ ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
++ cntrs->local_link_integrity_errors =
++ (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
++ dd->ipath_lli_errs : dd->ipath_lli_errors;
++ cntrs->excessive_buffer_overrun_errors = dd->ipath_overrun_thresh_errs;
++
++ ret = 0;
++
++bail:
++ return ret;
++}
++
+ /**
+ * ipath_ib_piobufavail - callback when a PIO buffer is available
+ * @arg: the device pointer
+@@ -591,9 +933,8 @@ static void ipath_ib_timer(void *arg)
+ * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and
+ * return zero).
+ */
+-static int ipath_ib_piobufavail(void *arg)
++int ipath_ib_piobufavail(struct ipath_ibdev *dev)
+ {
+- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
+ struct ipath_qp *qp;
+ unsigned long flags;
+
+@@ -624,14 +965,14 @@ static int ipath_query_device(struct ib_
+ IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
+ IB_DEVICE_SYS_IMAGE_GUID;
+ props->page_size_cap = PAGE_SIZE;
+- props->vendor_id = ipath_layer_get_vendorid(dev->dd);
+- props->vendor_part_id = ipath_layer_get_deviceid(dev->dd);
+- props->hw_ver = ipath_layer_get_pcirev(dev->dd);
++ props->vendor_id = dev->dd->ipath_vendorid;
++ props->vendor_part_id = dev->dd->ipath_deviceid;
++ props->hw_ver = dev->dd->ipath_pcirev;
+
+ props->sys_image_guid = dev->sys_image_guid;
+
+ props->max_mr_size = ~0ull;
+- props->max_qp = dev->qp_table.max;
++ props->max_qp = ib_ipath_max_qps;
+ props->max_qp_wr = ib_ipath_max_qp_wrs;
+ props->max_sge = ib_ipath_max_sges;
+ props->max_cq = ib_ipath_max_cqs;
+@@ -647,7 +988,7 @@ static int ipath_query_device(struct ib_
+ props->max_srq_sge = ib_ipath_max_srq_sges;
+ /* props->local_ca_ack_delay */
+ props->atomic_cap = IB_ATOMIC_HCA;
+- props->max_pkeys = ipath_layer_get_npkeys(dev->dd);
++ props->max_pkeys = ipath_get_npkeys(dev->dd);
+ props->max_mcast_grp = ib_ipath_max_mcast_grps;
+ props->max_mcast_qp_attach = ib_ipath_max_mcast_qp_attached;
+ props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
+@@ -672,12 +1013,17 @@ const u8 ipath_cvt_physportstate[16] = {
+ [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6,
+ };
+
++u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
++{
++ return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
++}
++
+ static int ipath_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+ {
+ struct ipath_ibdev *dev = to_idev(ibdev);
+ enum ib_mtu mtu;
+- u16 lid = ipath_layer_get_lid(dev->dd);
++ u16 lid = dev->dd->ipath_lid;
+ u64 ibcstat;
+
+ memset(props, 0, sizeof(*props));
+@@ -685,16 +1031,16 @@ static int ipath_query_port(struct ib_de
+ props->lmc = dev->mkeyprot_resv_lmc & 7;
+ props->sm_lid = dev->sm_lid;
+ props->sm_sl = dev->sm_sl;
+- ibcstat = ipath_layer_get_lastibcstat(dev->dd);
++ ibcstat = dev->dd->ipath_lastibcstat;
+ props->state = ((ibcstat >> 4) & 0x3) + 1;
+ /* See phys_state_show() */
+ props->phys_state = ipath_cvt_physportstate[
+- ipath_layer_get_lastibcstat(dev->dd) & 0xf];
++ dev->dd->ipath_lastibcstat & 0xf];
+ props->port_cap_flags = dev->port_cap_flags;
+ props->gid_tbl_len = 1;
+ props->max_msg_sz = 0x80000000;
+- props->pkey_tbl_len = ipath_layer_get_npkeys(dev->dd);
+- props->bad_pkey_cntr = ipath_layer_get_cr_errpkey(dev->dd) -
++ props->pkey_tbl_len = ipath_get_npkeys(dev->dd);
++ props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) -
+ dev->z_pkey_violations;
+ props->qkey_viol_cntr = dev->qkey_violations;
+ props->active_width = IB_WIDTH_4X;
+@@ -704,7 +1050,7 @@ static int ipath_query_port(struct ib_de
+ props->init_type_reply = 0;
+
+ props->max_mtu = IB_MTU_4096;
+- switch (ipath_layer_get_ibmtu(dev->dd)) {
++ switch (dev->dd->ipath_ibmtu) {
+ case 4096:
+ mtu = IB_MTU_4096;
+ break;
+@@ -763,7 +1109,7 @@ static int ipath_modify_port(struct ib_d
+ dev->port_cap_flags |= props->set_port_cap_mask;
+ dev->port_cap_flags &= ~props->clr_port_cap_mask;
+ if (port_modify_mask & IB_PORT_SHUTDOWN)
+- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN);
++ ipath_set_linkstate(dev->dd, IPATH_IB_LINKDOWN);
+ if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR)
+ dev->qkey_violations = 0;
+ return 0;
+@@ -780,7 +1126,7 @@ static int ipath_query_gid(struct ib_dev
+ goto bail;
+ }
+ gid->global.subnet_prefix = dev->gid_prefix;
+- gid->global.interface_id = ipath_layer_get_guid(dev->dd);
++ gid->global.interface_id = dev->dd->ipath_guid;
+
+ ret = 0;
+
+@@ -803,18 +1149,22 @@ static struct ib_pd *ipath_alloc_pd(stru
+ * we allow allocations of more than we report for this value.
+ */
+
+- if (dev->n_pds_allocated == ib_ipath_max_pds) {
++ pd = kmalloc(sizeof *pd, GFP_KERNEL);
++ if (!pd) {
+ ret = ERR_PTR(-ENOMEM);
+ goto bail;
+ }
+
+- pd = kmalloc(sizeof *pd, GFP_KERNEL);
+- if (!pd) {
++ spin_lock(&dev->n_pds_lock);
++ if (dev->n_pds_allocated == ib_ipath_max_pds) {
++ spin_unlock(&dev->n_pds_lock);
++ kfree(pd);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail;
+ }
+
+ dev->n_pds_allocated++;
++ spin_unlock(&dev->n_pds_lock);
+
+ /* ib_alloc_pd() will initialize pd->ibpd. */
+ pd->user = udata != NULL;
+@@ -830,7 +1180,9 @@ static int ipath_dealloc_pd(struct ib_pd
+ struct ipath_pd *pd = to_ipd(ibpd);
+ struct ipath_ibdev *dev = to_idev(ibpd->device);
+
++ spin_lock(&dev->n_pds_lock);
+ dev->n_pds_allocated--;
++ spin_unlock(&dev->n_pds_lock);
+
+ kfree(pd);
+
+@@ -850,11 +1202,7 @@ static struct ib_ah *ipath_create_ah(str
+ struct ipath_ah *ah;
+ struct ib_ah *ret;
+ struct ipath_ibdev *dev = to_idev(pd->device);
+-
+- if (dev->n_ahs_allocated == ib_ipath_max_ahs) {
+- ret = ERR_PTR(-ENOMEM);
+- goto bail;
+- }
++ unsigned long flags;
+
+ /* A multicast address requires a GRH (see ch. 8.4.1). */
+ if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
+@@ -881,7 +1229,16 @@ static struct ib_ah *ipath_create_ah(str
+ goto bail;
+ }
+
++ spin_lock_irqsave(&dev->n_ahs_lock, flags);
++ if (dev->n_ahs_allocated == ib_ipath_max_ahs) {
++ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
++ kfree(ah);
++ ret = ERR_PTR(-ENOMEM);
++ goto bail;
++ }
++
+ dev->n_ahs_allocated++;
++ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+
+ /* ib_create_ah() will initialize ah->ibah. */
+ ah->attr = *ah_attr;
+@@ -902,8 +1259,11 @@ static int ipath_destroy_ah(struct ib_ah
+ {
+ struct ipath_ibdev *dev = to_idev(ibah->device);
+ struct ipath_ah *ah = to_iah(ibah);
++ unsigned long flags;
+
++ spin_lock_irqsave(&dev->n_ahs_lock, flags);
+ dev->n_ahs_allocated--;
++ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+
+ kfree(ah);
+
+@@ -919,25 +1279,50 @@ static int ipath_query_ah(struct ib_ah *
+ return 0;
+ }
+
++/**
++ * ipath_get_npkeys - return the size of the PKEY table for port 0
++ * @dd: the infinipath device
++ */
++unsigned ipath_get_npkeys(struct ipath_devdata *dd)
++{
++ return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys);
++}
++
++/**
++ * ipath_get_pkey - return the indexed PKEY from the port 0 PKEY table
++ * @dd: the infinipath device
++ * @index: the PKEY index
++ */
++unsigned ipath_get_pkey(struct ipath_devdata *dd, unsigned index)
++{
++ unsigned ret;
++
++ if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys))
++ ret = 0;
++ else
++ ret = dd->ipath_pd[0]->port_pkeys[index];
++
++ return ret;
++}
++
+ static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey)
+ {
+ struct ipath_ibdev *dev = to_idev(ibdev);
+ int ret;
+
+- if (index >= ipath_layer_get_npkeys(dev->dd)) {
++ if (index >= ipath_get_npkeys(dev->dd)) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+- *pkey = ipath_layer_get_pkey(dev->dd, index);
++ *pkey = ipath_get_pkey(dev->dd, index);
+ ret = 0;
+
+ bail:
+ return ret;
+ }
+
+-
+ /**
+ * ipath_alloc_ucontext - allocate a ucontest
+ * @ibdev: the infiniband device
+@@ -970,26 +1355,102 @@ static int ipath_dealloc_ucontext(struct
+
+ static int ipath_verbs_register_sysfs(struct ib_device *dev);
+
++static void __verbs_timer(unsigned long arg)
++{
++ struct ipath_devdata *dd = (struct ipath_devdata *) arg;
++
++ /*
++ * If port 0 receive packet interrupts are not available, or
++ * can be missed, poll the receive queue
++ */
++ if (dd->ipath_flags & IPATH_POLL_RX_INTR)
++ ipath_kreceive(dd);
++
++ /* Handle verbs layer timeouts. */
++ ipath_ib_timer(dd->verbs_dev);
++
++ mod_timer(&dd->verbs_timer, jiffies + 1);
++}
++
++static int enable_timer(struct ipath_devdata *dd)
++{
++ /*
++ * Early chips had a design flaw where the chip and kernel idea
++ * of the tail register don't always agree, and therefore we won't
++ * get an interrupt on the next packet received.
++ * If the board supports per packet receive interrupts, use it.
++ * Otherwise, the timer function periodically checks for packets
++ * to cover this case.
++ * Either way, the timer is needed for verbs layer related
++ * processing.
++ */
++ if (dd->ipath_flags & IPATH_GPIO_INTR) {
++ u64 val;
++ ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect,
++ 0x2074076542310ULL);
++ /* Enable GPIO bit 2 interrupt */
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
++ val |= (u64) (1 << IPATH_GPIO_PORT0_BIT);
++ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
++ }
++
++ init_timer(&dd->verbs_timer);
++ dd->verbs_timer.function = __verbs_timer;
++ dd->verbs_timer.data = (unsigned long)dd;
++ dd->verbs_timer.expires = jiffies + 1;
++ add_timer(&dd->verbs_timer);
++
++ return 0;
++}
++
++static int disable_timer(struct ipath_devdata *dd)
++{
++ /* Disable GPIO bit 2 interrupt */
++ if (dd->ipath_flags & IPATH_GPIO_INTR) {
++ u64 val;
++ /* Disable GPIO bit 2 interrupt */
++ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
++ val &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
++ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
++ /*
++ * We might want to undo changes to debugportselect,
++ * but how?
++ */
++ }
++
++ del_timer_sync(&dd->verbs_timer);
++
++ return 0;
++}
++
+ /**
+ * ipath_register_ib_device - register our device with the infiniband core
+- * @unit: the device number to register
+ * @dd: the device data structure
+ * Return the allocated ipath_ibdev pointer or NULL on error.
+ */
+-static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
++int ipath_register_ib_device(struct ipath_devdata *dd)
+ {
+- struct ipath_layer_counters cntrs;
++ struct ipath_verbs_counters cntrs;
+ struct ipath_ibdev *idev;
+ struct ib_device *dev;
+ int ret;
+
+ idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev);
+- if (idev == NULL)
++ if (idev == NULL) {
++ ret = -ENOMEM;
+ goto bail;
++ }
+
+ dev = &idev->ibdev;
+
+ /* Only need to initialize non-zero fields. */
++ spin_lock_init(&idev->n_pds_lock);
++ spin_lock_init(&idev->n_ahs_lock);
++ spin_lock_init(&idev->n_cqs_lock);
++ spin_lock_init(&idev->n_qps_lock);
++ spin_lock_init(&idev->n_srqs_lock);
++ spin_lock_init(&idev->n_mcast_grps_lock);
++
+ spin_lock_init(&idev->qp_table.lock);
+ spin_lock_init(&idev->lk_table.lock);
+ idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE);
+@@ -1030,7 +1491,7 @@ static void *ipath_register_ib_device(in
+ idev->link_width_enabled = 3; /* 1x or 4x */
+
+ /* Snapshot current HW counters to "clear" them. */
+- ipath_layer_get_counters(dd, &cntrs);
++ ipath_get_counters(dd, &cntrs);
+ idev->z_symbol_error_counter = cntrs.symbol_error_counter;
+ idev->z_link_error_recovery_counter =
+ cntrs.link_error_recovery_counter;
+@@ -1054,14 +1515,14 @@ static void *ipath_register_ib_device(in
+ * device types in the system, we can't be sure this is unique.
+ */
+ if (!sys_image_guid)
+- sys_image_guid = ipath_layer_get_guid(dd);
++ sys_image_guid = dd->ipath_guid;
+ idev->sys_image_guid = sys_image_guid;
+- idev->ib_unit = unit;
++ idev->ib_unit = dd->ipath_unit;
+ idev->dd = dd;
+
+ strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX);
+ dev->owner = THIS_MODULE;
+- dev->node_guid = ipath_layer_get_guid(dd);
++ dev->node_guid = dd->ipath_guid;
+ dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION;
+ dev->uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+@@ -1093,9 +1554,9 @@ static void *ipath_register_ib_device(in
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
+- dev->node_type = IB_NODE_CA;
++ dev->node_type = RDMA_NODE_IB_CA;
+ dev->phys_port_cnt = 1;
+- dev->dma_device = ipath_layer_get_device(dd);
++ dev->dma_device = &dd->pcidev->dev;
+ dev->class_dev.dev = dev->dma_device;
+ dev->query_device = ipath_query_device;
+ dev->modify_device = ipath_modify_device;
+@@ -1137,9 +1598,10 @@ static void *ipath_register_ib_device(in
+ dev->attach_mcast = ipath_multicast_attach;
+ dev->detach_mcast = ipath_multicast_detach;
+ dev->process_mad = ipath_process_mad;
++ dev->mmap = ipath_mmap;
+
+ snprintf(dev->node_desc, sizeof(dev->node_desc),
+- IPATH_IDSTR " %s kernel_SMA", system_utsname.nodename);
++ IPATH_IDSTR " %s", init_utsname()->nodename);
+
+ ret = ib_register_device(dev);
+ if (ret)
+@@ -1148,7 +1610,7 @@ static void *ipath_register_ib_device(in
+ if (ipath_verbs_register_sysfs(dev))
+ goto err_class;
+
+- ipath_layer_enable_timer(dd);
++ enable_timer(dd);
+
+ goto bail;
+
+@@ -1160,37 +1622,32 @@ err_lk:
+ kfree(idev->qp_table.table);
+ err_qp:
+ ib_dealloc_device(dev);
+- _VERBS_ERROR("ib_ipath%d cannot register verbs (%d)!\n",
+- unit, -ret);
++ ipath_dev_err(dd, "cannot register verbs: %d!\n", -ret);
+ idev = NULL;
+
+ bail:
+- return idev;
++ dd->verbs_dev = idev;
++ return ret;
+ }
+
+-static void ipath_unregister_ib_device(void *arg)
++void ipath_unregister_ib_device(struct ipath_ibdev *dev)
+ {
+- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
+ struct ib_device *ibdev = &dev->ibdev;
+
+- ipath_layer_disable_timer(dev->dd);
++ disable_timer(dev->dd);
+
+ ib_unregister_device(ibdev);
+
+ if (!list_empty(&dev->pending[0]) ||
+ !list_empty(&dev->pending[1]) ||
+ !list_empty(&dev->pending[2]))
+- _VERBS_ERROR("ipath%d pending list not empty!\n",
+- dev->ib_unit);
++ ipath_dev_err(dev->dd, "pending list not empty!\n");
+ if (!list_empty(&dev->piowait))
+- _VERBS_ERROR("ipath%d piowait list not empty!\n",
+- dev->ib_unit);
++ ipath_dev_err(dev->dd, "piowait list not empty!\n");
+ if (!list_empty(&dev->rnrwait))
+- _VERBS_ERROR("ipath%d rnrwait list not empty!\n",
+- dev->ib_unit);
++ ipath_dev_err(dev->dd, "rnrwait list not empty!\n");
+ if (!ipath_mcast_tree_empty())
+- _VERBS_ERROR("ipath%d multicast table memory leak!\n",
+- dev->ib_unit);
++ ipath_dev_err(dev->dd, "multicast table memory leak!\n");
+ /*
+ * Note that ipath_unregister_ib_device() can be called before all
+ * the QPs are destroyed!
+@@ -1201,25 +1658,12 @@ static void ipath_unregister_ib_device(v
+ ib_dealloc_device(ibdev);
+ }
+
+-static int __init ipath_verbs_init(void)
+-{
+- return ipath_verbs_register(ipath_register_ib_device,
+- ipath_unregister_ib_device,
+- ipath_ib_piobufavail, ipath_ib_rcv,
+- ipath_ib_timer);
+-}
+-
+-static void __exit ipath_verbs_cleanup(void)
+-{
+- ipath_verbs_unregister();
+-}
+-
+ static ssize_t show_rev(struct class_device *cdev, char *buf)
+ {
+ struct ipath_ibdev *dev =
+ container_of(cdev, struct ipath_ibdev, ibdev.class_dev);
+
+- return sprintf(buf, "%x\n", ipath_layer_get_pcirev(dev->dd));
++ return sprintf(buf, "%x\n", dev->dd->ipath_pcirev);
+ }
+
+ static ssize_t show_hca(struct class_device *cdev, char *buf)
+@@ -1228,7 +1672,7 @@ static ssize_t show_hca(struct class_dev
+ container_of(cdev, struct ipath_ibdev, ibdev.class_dev);
+ int ret;
+
+- ret = ipath_layer_get_boardname(dev->dd, buf, 128);
++ ret = dev->dd->ipath_f_get_boardname(dev->dd, buf, 128);
+ if (ret < 0)
+ goto bail;
+ strcat(buf, "\n");
+@@ -1255,6 +1699,7 @@ static ssize_t show_stats(struct class_d
+ "RC OTH NAKs %d\n"
+ "RC timeouts %d\n"
+ "RC RDMA dup %d\n"
++ "RC stalls %d\n"
+ "piobuf wait %d\n"
+ "no piobuf %d\n"
+ "PKT drops %d\n"
+@@ -1262,7 +1707,7 @@ static ssize_t show_stats(struct class_d
+ dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks,
+ dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks,
+ dev->n_other_naks, dev->n_timeouts,
+- dev->n_rdma_dup_busy, dev->n_piowait,
++ dev->n_rdma_dup_busy, dev->n_rc_stalls, dev->n_piowait,
+ dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs);
+ for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) {
+ const struct ipath_opcode_stats *si = &dev->opstats[i];
+@@ -1305,6 +1750,3 @@ static int ipath_verbs_register_sysfs(st
+ bail:
+ return ret;
+ }
+-
+-module_init(ipath_verbs_init);
+-module_exit(ipath_verbs_cleanup);
+diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
+index 2df6847..8039f6e 100644
+--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
++++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
+@@ -38,10 +38,10 @@
+ #include <linux/spinlock.h>
+ #include <linux/kernel.h>
+ #include <linux/interrupt.h>
++#include <linux/kref.h>
+ #include <rdma/ib_pack.h>
+
+ #include "ipath_layer.h"
+-#include "verbs_debug.h"
+
+ #define QPN_MAX (1 << 24)
+ #define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE)
+@@ -50,7 +50,7 @@
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+-#define IPATH_UVERBS_ABI_VERSION 1
++#define IPATH_UVERBS_ABI_VERSION 2
+
+ /*
+ * Define an ib_cq_notify value that is not valid so we know when CQ
+@@ -152,19 +152,6 @@ struct ipath_mcast {
+ int n_attached;
+ };
+
+-/* Memory region */
+-struct ipath_mr {
+- struct ib_mr ibmr;
+- struct ipath_mregion mr; /* must be last */
+-};
+-
+-/* Fast memory region */
+-struct ipath_fmr {
+- struct ib_fmr ibfmr;
+- u8 page_shift;
+- struct ipath_mregion mr; /* must be last */
+-};
+-
+ /* Protection domain */
+ struct ipath_pd {
+ struct ib_pd ibpd;
+@@ -178,58 +165,90 @@ struct ipath_ah {
+ };
+
+ /*
+- * Quick description of our CQ/QP locking scheme:
+- *
+- * We have one global lock that protects dev->cq/qp_table. Each
+- * struct ipath_cq/qp also has its own lock. An individual qp lock
+- * may be taken inside of an individual cq lock. Both cqs attached to
+- * a qp may be locked, with the send cq locked first. No other
+- * nesting should be done.
+- *
+- * Each struct ipath_cq/qp also has an atomic_t ref count. The
+- * pointer from the cq/qp_table to the struct counts as one reference.
+- * This reference also is good for access through the consumer API, so
+- * modifying the CQ/QP etc doesn't need to take another reference.
+- * Access because of a completion being polled does need a reference.
+- *
+- * Finally, each struct ipath_cq/qp has a wait_queue_head_t for the
+- * destroy function to sleep on.
+- *
+- * This means that access from the consumer API requires nothing but
+- * taking the struct's lock.
+- *
+- * Access because of a completion event should go as follows:
+- * - lock cq/qp_table and look up struct
+- * - increment ref count in struct
+- * - drop cq/qp_table lock
+- * - lock struct, do your thing, and unlock struct
+- * - decrement ref count; if zero, wake up waiters
+- *
+- * To destroy a CQ/QP, we can do the following:
+- * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock
+- * - decrement ref count
+- * - wait_event until ref count is zero
+- *
+- * It is the consumer's responsibilty to make sure that no QP
+- * operations (WQE posting or state modification) are pending when the
+- * QP is destroyed. Also, the consumer must make sure that calls to
+- * qp_modify are serialized.
+- *
+- * Possible optimizations (wait for profile data to see if/where we
+- * have locks bouncing between CPUs):
+- * - split cq/qp table lock into n separate (cache-aligned) locks,
+- * indexed (say) by the page in the table
++ * This structure is used by ipath_mmap() to validate an offset
++ * when an mmap() request is made. The vm_area_struct then uses
++ * this as its vm_private_data.
+ */
++struct ipath_mmap_info {
++ struct ipath_mmap_info *next;
++ struct ib_ucontext *context;
++ void *obj;
++ struct kref ref;
++ unsigned size;
++ unsigned mmap_cnt;
++};
++
++/*
++ * This structure is used to contain the head pointer, tail pointer,
++ * and completion queue entries as a single memory allocation so
++ * it can be mmap'ed into user space.
++ */
++struct ipath_cq_wc {
++ u32 head; /* index of next entry to fill */
++ u32 tail; /* index of next ib_poll_cq() entry */
++ struct ib_wc queue[1]; /* this is actually size ibcq.cqe + 1 */
++};
+
++/*
++ * The completion queue structure.
++ */
+ struct ipath_cq {
+ struct ib_cq ibcq;
+ struct tasklet_struct comptask;
+ spinlock_t lock;
+ u8 notify;
+ u8 triggered;
+- u32 head; /* new records added to the head */
+- u32 tail; /* poll_cq() reads from here. */
+- struct ib_wc *queue; /* this is actually ibcq.cqe + 1 */
++ struct ipath_cq_wc *queue;
++ struct ipath_mmap_info *ip;
++};
++
++/*
++ * A segment is a linear region of low physical memory.
++ * XXX Maybe we should use phys addr here and kmap()/kunmap().
++ * Used by the verbs layer.
++ */
++struct ipath_seg {
++ void *vaddr;
++ size_t length;
++};
++
++/* The number of ipath_segs that fit in a page. */
++#define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg))
++
++struct ipath_segarray {
++ struct ipath_seg segs[IPATH_SEGSZ];
++};
++
++struct ipath_mregion {
++ struct ib_pd *pd; /* shares refcnt of ibmr.pd */
++ u64 user_base; /* User's address for this region */
++ u64 iova; /* IB start address of this region */
++ size_t length;
++ u32 lkey;
++ u32 offset; /* offset (bytes) to start of region */
++ int access_flags;
++ u32 max_segs; /* number of ipath_segs in all the arrays */
++ u32 mapsz; /* size of the map array */
++ struct ipath_segarray *map[0]; /* the segments */
++};
++
++/*
++ * These keep track of the copy progress within a memory region.
++ * Used by the verbs layer.
++ */
++struct ipath_sge {
++ struct ipath_mregion *mr;
++ void *vaddr; /* current pointer into the segment */
++ u32 sge_length; /* length of the SGE */
++ u32 length; /* remaining length of the segment */
++ u16 m; /* current index: mr->map[m] */
++ u16 n; /* current index: mr->map[m]->segs[n] */
++};
++
++/* Memory region */
++struct ipath_mr {
++ struct ib_mr ibmr;
++ struct ipath_mregion mr; /* must be last */
+ };
+
+ /*
+@@ -248,32 +267,50 @@ struct ipath_swqe {
+
+ /*
+ * Receive work request queue entry.
+- * The size of the sg_list is determined when the QP is created and stored
+- * in qp->r_max_sge.
++ * The size of the sg_list is determined when the QP (or SRQ) is created
++ * and stored in qp->r_rq.max_sge (or srq->rq.max_sge).
+ */
+ struct ipath_rwqe {
+ u64 wr_id;
+- u32 length; /* total length of data in sg_list */
+ u8 num_sge;
+- struct ipath_sge sg_list[0];
++ struct ib_sge sg_list[0];
+ };
+
+-struct ipath_rq {
+- spinlock_t lock;
++/*
++ * This structure is used to contain the head pointer, tail pointer,
++ * and receive work queue entries as a single memory allocation so
++ * it can be mmap'ed into user space.
++ * Note that the wq array elements are variable size so you can't
++ * just index into the array to get the N'th element;
++ * use get_rwqe_ptr() instead.
++ */
++struct ipath_rwq {
+ u32 head; /* new work requests posted to the head */
+ u32 tail; /* receives pull requests from here. */
++ struct ipath_rwqe wq[0];
++};
++
++struct ipath_rq {
++ struct ipath_rwq *wq;
++ spinlock_t lock;
+ u32 size; /* size of RWQE array */
+ u8 max_sge;
+- struct ipath_rwqe *wq; /* RWQE array */
+ };
+
+ struct ipath_srq {
+ struct ib_srq ibsrq;
+ struct ipath_rq rq;
++ struct ipath_mmap_info *ip;
+ /* send signal when number of RWQEs < limit */
+ u32 limit;
+ };
+
++struct ipath_sge_state {
++ struct ipath_sge *sg_list; /* next SGE to be used if any */
++ struct ipath_sge sge; /* progress state for the current SGE */
++ u8 num_sge;
++};
++
+ /*
+ * Variables prefixed with s_ are for the requester (sender).
+ * Variables prefixed with r_ are for the responder (receiver).
+@@ -293,6 +330,7 @@ struct ipath_qp {
+ atomic_t refcount;
+ wait_queue_head_t wait;
+ struct tasklet_struct s_task;
++ struct ipath_mmap_info *ip;
+ struct ipath_sge_state *s_cur_sge;
+ struct ipath_sge_state s_sge; /* current send request data */
+ /* current RDMA read send data */
+@@ -327,13 +365,16 @@ struct ipath_qp {
+ u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */
+ u8 r_reuse_sge; /* for UC receive errors */
+ u8 r_sge_inx; /* current index into sg_list */
++ u8 r_wrid_valid; /* r_wrid set but CQ entry not yet made */
+ u8 qp_access_flags;
+ u8 s_max_sge; /* size of s_wq->sg_list */
+ u8 s_retry_cnt; /* number of times to retry */
+ u8 s_rnr_retry_cnt;
+ u8 s_retry; /* requester retry counter */
+ u8 s_rnr_retry; /* requester RNR retry counter */
++ u8 s_wait_credit; /* limit number of unacked packets sent */
+ u8 s_pkey_index; /* PKEY index to use */
++ u8 timeout; /* Timeout for this QP */
+ enum ib_mtu path_mtu;
+ u32 remote_qpn;
+ u32 qkey; /* QKEY for this QP (for UD or RD) */
+@@ -345,7 +386,8 @@ struct ipath_qp {
+ u32 s_ssn; /* SSN of tail entry */
+ u32 s_lsn; /* limit sequence number (credit) */
+ struct ipath_swqe *s_wq; /* send work queue */
+- struct ipath_rq r_rq; /* receive work queue */
++ struct ipath_rq r_rq; /* receive work queue */
++ struct ipath_sge r_sg_list[0]; /* verified SGEs */
+ };
+
+ /*
+@@ -354,6 +396,8 @@ struct ipath_qp {
+ #define IPATH_S_BUSY 0
+ #define IPATH_S_SIGNAL_REQ_WR 1
+
++#define IPATH_PSN_CREDIT 2048
++
+ /*
+ * Since struct ipath_swqe is not a fixed size, we can't simply index into
+ * struct ipath_qp.s_wq. This function does the array index computation.
+@@ -369,15 +413,15 @@ static inline struct ipath_swqe *get_swq
+
+ /*
+ * Since struct ipath_rwqe is not a fixed size, we can't simply index into
+- * struct ipath_rq.wq. This function does the array index computation.
++ * struct ipath_rwq.wq. This function does the array index computation.
+ */
+ static inline struct ipath_rwqe *get_rwqe_ptr(struct ipath_rq *rq,
+ unsigned n)
+ {
+ return (struct ipath_rwqe *)
+- ((char *) rq->wq +
++ ((char *) rq->wq->wq +
+ (sizeof(struct ipath_rwqe) +
+- rq->max_sge * sizeof(struct ipath_sge)) * n);
++ rq->max_sge * sizeof(struct ib_sge)) * n);
+ }
+
+ /*
+@@ -417,6 +461,7 @@ struct ipath_ibdev {
+ struct ib_device ibdev;
+ struct list_head dev_list;
+ struct ipath_devdata *dd;
++ struct ipath_mmap_info *pending_mmaps;
+ int ib_unit; /* This is the device number */
+ u16 sm_lid; /* in host order */
+ u8 sm_sl;
+@@ -435,11 +480,20 @@ struct ipath_ibdev {
+ __be64 sys_image_guid; /* in network order */
+ __be64 gid_prefix; /* in network order */
+ __be64 mkey;
++
+ u32 n_pds_allocated; /* number of PDs allocated for device */
++ spinlock_t n_pds_lock;
+ u32 n_ahs_allocated; /* number of AHs allocated for device */
++ spinlock_t n_ahs_lock;
+ u32 n_cqs_allocated; /* number of CQs allocated for device */
++ spinlock_t n_cqs_lock;
++ u32 n_qps_allocated; /* number of QPs allocated for device */
++ spinlock_t n_qps_lock;
+ u32 n_srqs_allocated; /* number of SRQs allocated for device */
++ spinlock_t n_srqs_lock;
+ u32 n_mcast_grps_allocated; /* number of mcast groups allocated */
++ spinlock_t n_mcast_grps_lock;
++
+ u64 ipath_sword; /* total dwords sent (sample result) */
+ u64 ipath_rword; /* total dwords received (sample result) */
+ u64 ipath_spkts; /* total packets sent (sample result) */
+@@ -472,6 +526,7 @@ struct ipath_ibdev {
+ u32 n_rnr_naks;
+ u32 n_other_naks;
+ u32 n_timeouts;
++ u32 n_rc_stalls;
+ u32 n_pkt_drops;
+ u32 n_vl15_dropped;
+ u32 n_wqe_errs;
+@@ -494,8 +549,19 @@ struct ipath_ibdev {
+ struct ipath_opcode_stats opstats[128];
+ };
+
+-struct ipath_ucontext {
+- struct ib_ucontext ibucontext;
++struct ipath_verbs_counters {
++ u64 symbol_error_counter;
++ u64 link_error_recovery_counter;
++ u64 link_downed_counter;
++ u64 port_rcv_errors;
++ u64 port_rcv_remphys_errors;
++ u64 port_xmit_discards;
++ u64 port_xmit_data;
++ u64 port_rcv_data;
++ u64 port_xmit_packets;
++ u64 port_rcv_packets;
++ u32 local_link_integrity_errors;
++ u32 excessive_buffer_overrun_errors;
+ };
+
+ static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
+@@ -503,11 +569,6 @@ static inline struct ipath_mr *to_imr(st
+ return container_of(ibmr, struct ipath_mr, ibmr);
+ }
+
+-static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr)
+-{
+- return container_of(ibfmr, struct ipath_fmr, ibfmr);
+-}
+-
+ static inline struct ipath_pd *to_ipd(struct ib_pd *ibpd)
+ {
+ return container_of(ibpd, struct ipath_pd, ibpd);
+@@ -545,12 +606,6 @@ int ipath_process_mad(struct ib_device *
+ struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad);
+
+-static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext
+- *ibucontext)
+-{
+- return container_of(ibucontext, struct ipath_ucontext, ibucontext);
+-}
+-
+ /*
+ * Compare the lower 24 bits of the two values.
+ * Returns an integer <, ==, or > than zero.
+@@ -562,6 +617,13 @@ static inline int ipath_cmp24(u32 a, u32
+
+ struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid);
+
++int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
++ u64 *rwords, u64 *spkts, u64 *rpkts,
++ u64 *xmit_wait);
++
++int ipath_get_counters(struct ipath_devdata *dd,
++ struct ipath_verbs_counters *cntrs);
++
+ int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
+
+ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
+@@ -578,8 +640,10 @@ struct ib_qp *ipath_create_qp(struct ib_
+
+ int ipath_destroy_qp(struct ib_qp *ibqp);
+
++void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
++
+ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+- int attr_mask);
++ int attr_mask, struct ib_udata *udata);
+
+ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr);
+@@ -592,13 +656,10 @@ void ipath_sqerror_qp(struct ipath_qp *q
+
+ void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
+
+-void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
++int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
++ u32 *hdr, u32 len, struct ipath_sge_state *ss);
+
+-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
+- u32 len, u64 vaddr, u32 rkey, int acc);
+-
+-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
+- struct ib_sge *sge, int acc);
++void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
+
+ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
+
+@@ -624,10 +685,10 @@ int ipath_alloc_lkey(struct ipath_lkey_t
+
+ void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey);
+
+-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
++int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
+ struct ib_sge *sge, int acc);
+
+-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
++int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
+ u32 len, u64 vaddr, u32 rkey, int acc);
+
+ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+@@ -638,7 +699,8 @@ struct ib_srq *ipath_create_srq(struct i
+ struct ib_udata *udata);
+
+ int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+- enum ib_srq_attr_mask attr_mask);
++ enum ib_srq_attr_mask attr_mask,
++ struct ib_udata *udata);
+
+ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
+
+@@ -680,6 +742,10 @@ int ipath_unmap_fmr(struct list_head *fm
+
+ int ipath_dealloc_fmr(struct ib_fmr *ibfmr);
+
++void ipath_release_mmap_info(struct kref *ref);
++
++int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
++
+ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
+
+ void ipath_insert_rnr_queue(struct ipath_qp *qp);
+@@ -700,6 +766,22 @@ int ipath_make_rc_req(struct ipath_qp *q
+ int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
+ u32 pmtu, u32 *bth0p, u32 *bth2p);
+
++int ipath_register_ib_device(struct ipath_devdata *);
++
++void ipath_unregister_ib_device(struct ipath_ibdev *);
++
++void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
++
++int ipath_ib_piobufavail(struct ipath_ibdev *);
++
++void ipath_ib_timer(struct ipath_ibdev *);
++
++unsigned ipath_get_npkeys(struct ipath_devdata *);
++
++u32 ipath_get_cr_errpkey(struct ipath_devdata *);
++
++unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
++
+ extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
+
+ extern const u8 ipath_cvt_physportstate[];
+@@ -714,6 +796,8 @@ extern unsigned int ib_ipath_max_cqs;
+
+ extern unsigned int ib_ipath_max_qp_wrs;
+
++extern unsigned int ib_ipath_max_qps;
++
+ extern unsigned int ib_ipath_max_sges;
+
+ extern unsigned int ib_ipath_max_mcast_grps;
+diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
+index ee0e1d9..085e28b 100644
+--- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
++++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
+@@ -207,12 +207,17 @@ static int ipath_mcast_add(struct ipath_
+ goto bail;
+ }
+
++ spin_lock(&dev->n_mcast_grps_lock);
+ if (dev->n_mcast_grps_allocated == ib_ipath_max_mcast_grps) {
++ spin_unlock(&dev->n_mcast_grps_lock);
+ ret = ENOMEM;
+ goto bail;
+ }
+
+ dev->n_mcast_grps_allocated++;
++ spin_unlock(&dev->n_mcast_grps_lock);
++
++ mcast->n_attached++;
+
+ list_add_tail_rcu(&mqp->list, &mcast->qp_list);
+
+@@ -343,7 +348,9 @@ int ipath_multicast_detach(struct ib_qp
+ atomic_dec(&mcast->refcount);
+ wait_event(mcast->wait, !atomic_read(&mcast->refcount));
+ ipath_mcast_free(mcast);
++ spin_lock(&dev->n_mcast_grps_lock);
+ dev->n_mcast_grps_allocated--;
++ spin_unlock(&dev->n_mcast_grps_lock);
+ }
+
+ ret = 0;
+diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
+new file mode 100644
+index 0000000..0095bb7
+--- /dev/null
++++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (c) 2006 QLogic, 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
++ * 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.
++ */
++
++/*
++ * This file is conditionally built on PowerPC only. Otherwise weak symbol
++ * versions of the functions exported from here are used.
++ */
++
++#include "ipath_kernel.h"
++
++/**
++ * ipath_enable_wc - enable write combining for MMIO writes to the device
++ * @dd: infinipath device
++ *
++ * Nothing to do on PowerPC, so just return without error.
++ */
++int ipath_enable_wc(struct ipath_devdata *dd)
++{
++ return 0;
++}
++
++/**
++ * ipath_unordered_wc - indicate whether write combining is unordered
++ *
++ * Because our performance depends on our ability to do write
++ * combining mmio writes in the most efficient way, we need to
++ * know if we are on a processor that may reorder stores when
++ * write combining.
++ */
++int ipath_unordered_wc(void)
++{
++ return 1;
++}
+diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+index f8f9e2e..04696e6 100644
+--- a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
++++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+@@ -123,6 +123,8 @@ int ipath_enable_wc(struct ipath_devdata
+ ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, "
+ "cookie is %d\n", cookie);
+ dd->ipath_wc_cookie = cookie;
++ dd->ipath_wc_base = (unsigned long) pioaddr;
++ dd->ipath_wc_len = (unsigned long) piolen;
+ }
+ }
+
+@@ -136,9 +138,16 @@ int ipath_enable_wc(struct ipath_devdata
+ void ipath_disable_wc(struct ipath_devdata *dd)
+ {
+ if (dd->ipath_wc_cookie) {
++ int r;
+ ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n");
+- mtrr_del(dd->ipath_wc_cookie, 0, 0);
+- dd->ipath_wc_cookie = 0;
++ r = mtrr_del(dd->ipath_wc_cookie, dd->ipath_wc_base,
++ dd->ipath_wc_len);
++ if (r < 0)
++ dev_info(&dd->pcidev->dev,
++ "mtrr_del(%lx, %lx, %lx) failed: %d\n",
++ dd->ipath_wc_cookie, dd->ipath_wc_base,
++ dd->ipath_wc_len, r);
++ dd->ipath_wc_cookie = 0; /* even on failure */
+ }
+ }
+
+diff --git a/drivers/infiniband/hw/ipath/verbs_debug.h b/drivers/infiniband/hw/ipath/verbs_debug.h
+deleted file mode 100644
+index 6186676..0000000
+--- a/drivers/infiniband/hw/ipath/verbs_debug.h
++++ /dev/null
+@@ -1,108 +0,0 @@
+-/*
+- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
+- * 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 _VERBS_DEBUG_H
+-#define _VERBS_DEBUG_H
+-
+-/*
+- * This file contains tracing code for the ib_ipath kernel module.
+- */
+-#ifndef _VERBS_DEBUGGING /* tracing enabled or not */
+-#define _VERBS_DEBUGGING 1
+-#endif
+-
+-extern unsigned ib_ipath_debug;
+-
+-#define _VERBS_ERROR(fmt,...) \
+- do { \
+- printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \
+- } while(0)
+-
+-#define _VERBS_UNIT_ERROR(unit,fmt,...) \
+- do { \
+- printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \
+- } while(0)
+-
+-#if _VERBS_DEBUGGING
+-
+-/*
+- * Mask values for debugging. The scheme allows us to compile out any
+- * of the debug tracing stuff, and if compiled in, to enable or
+- * disable dynamically.
+- * This can be set at modprobe time also:
+- * modprobe ib_path ib_ipath_debug=3
+- */
+-
+-#define __VERBS_INFO 0x1 /* generic low verbosity stuff */
+-#define __VERBS_DBG 0x2 /* generic debug */
+-#define __VERBS_VDBG 0x4 /* verbose debug */
+-#define __VERBS_SMADBG 0x8000 /* sma packet debug */
+-
+-#define _VERBS_INFO(fmt,...) \
+- do { \
+- if (unlikely(ib_ipath_debug&__VERBS_INFO)) \
+- printk(KERN_INFO "%s: " fmt,"ib_ipath", \
+- ##__VA_ARGS__); \
+- } while(0)
+-
+-#define _VERBS_DBG(fmt,...) \
+- do { \
+- if (unlikely(ib_ipath_debug&__VERBS_DBG)) \
+- printk(KERN_DEBUG "%s: " fmt, __func__, \
+- ##__VA_ARGS__); \
+- } while(0)
+-
+-#define _VERBS_VDBG(fmt,...) \
+- do { \
+- if (unlikely(ib_ipath_debug&__VERBS_VDBG)) \
+- printk(KERN_DEBUG "%s: " fmt, __func__, \
+- ##__VA_ARGS__); \
+- } while(0)
+-
+-#define _VERBS_SMADBG(fmt,...) \
+- do { \
+- if (unlikely(ib_ipath_debug&__VERBS_SMADBG)) \
+- printk(KERN_DEBUG "%s: " fmt, __func__, \
+- ##__VA_ARGS__); \
+- } while(0)
+-
+-#else /* ! _VERBS_DEBUGGING */
+-
+-#define _VERBS_INFO(fmt,...)
+-#define _VERBS_DBG(fmt,...)
+-#define _VERBS_VDBG(fmt,...)
+-#define _VERBS_SMADBG(fmt,...)
+-
+-#endif /* _VERBS_DEBUGGING */
+-
+-#endif /* _VERBS_DEBUG_H */
+diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
+index e215041..6959945 100644
+--- a/drivers/infiniband/hw/mthca/mthca_av.c
++++ b/drivers/infiniband/hw/mthca/mthca_av.c
+@@ -90,7 +90,7 @@ static enum ib_rate tavor_rate_to_ib(u8
+ case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS;
+ case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS;
+ case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS;
+- default: return port_rate;
++ default: return mult_to_ib_rate(port_rate);
+ }
+ }
+
+diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
+index c3bec74..cd044ea 100644
+--- a/drivers/infiniband/hw/mthca/mthca_catas.c
++++ b/drivers/infiniband/hw/mthca/mthca_catas.c
+@@ -34,6 +34,7 @@
+
+ #include <linux/jiffies.h>
+ #include <linux/timer.h>
++#include <linux/workqueue.h>
+
+ #include "mthca_dev.h"
+
+@@ -48,9 +49,41 @@ enum {
+
+ static DEFINE_SPINLOCK(catas_lock);
+
++static LIST_HEAD(catas_list);
++static struct workqueue_struct *catas_wq;
++static struct work_struct catas_work;
++
++static int catas_reset_disable;
++module_param_named(catas_reset_disable, catas_reset_disable, int, 0644);
++MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero");
++
++static void catas_reset(void *work_ptr)
++{
++ struct mthca_dev *dev, *tmpdev;
++ LIST_HEAD(tlist);
++ int ret;
++
++ mutex_lock(&mthca_device_mutex);
++
++ spin_lock_irq(&catas_lock);
++ list_splice_init(&catas_list, &tlist);
++ spin_unlock_irq(&catas_lock);
++
++ list_for_each_entry_safe(dev, tmpdev, &tlist, catas_err.list) {
++ ret = __mthca_restart_one(dev->pdev);
++ if (ret)
++ mthca_err(dev, "Reset failed (%d)\n", ret);
++ else
++ mthca_dbg(dev, "Reset succeeded\n");
++ }
++
++ mutex_unlock(&mthca_device_mutex);
++}
++
+ static void handle_catas(struct mthca_dev *dev)
+ {
+ struct ib_event event;
++ unsigned long flags;
+ const char *type;
+ int i;
+
+@@ -82,6 +115,14 @@ static void handle_catas(struct mthca_de
+ for (i = 0; i < dev->catas_err.size; ++i)
+ mthca_err(dev, " buf[%02x]: %08x\n",
+ i, swab32(readl(dev->catas_err.map + i)));
++
++ if (catas_reset_disable)
++ return;
++
++ spin_lock_irqsave(&catas_lock, flags);
++ list_add(&dev->catas_err.list, &catas_list);
++ queue_work(catas_wq, &catas_work);
++ spin_unlock_irqrestore(&catas_lock, flags);
+ }
+
+ static void poll_catas(unsigned long dev_ptr)
+@@ -135,6 +176,7 @@ void mthca_start_catas_poll(struct mthca
+ dev->catas_err.timer.data = (unsigned long) dev;
+ dev->catas_err.timer.function = poll_catas;
+ dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL;
++ INIT_LIST_HEAD(&dev->catas_err.list);
+ add_timer(&dev->catas_err.timer);
+ }
+
+@@ -153,4 +195,24 @@ void mthca_stop_catas_poll(struct mthca_
+ dev->catas_err.addr),
+ dev->catas_err.size * 4);
+ }
++
++ spin_lock_irq(&catas_lock);
++ list_del(&dev->catas_err.list);
++ spin_unlock_irq(&catas_lock);
++}
++
++int __init mthca_catas_init(void)
++{
++ INIT_WORK(&catas_work, catas_reset, NULL);
++
++ catas_wq = create_singlethread_workqueue("mthca_catas");
++ if (!catas_wq)
++ return -ENOMEM;
++
++ return 0;
++}
++
++void mthca_catas_cleanup(void)
++{
++ destroy_workqueue(catas_wq);
+ }
+diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
+index deabc14..768df72 100644
+--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
++++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
+@@ -34,7 +34,7 @@
+ * $Id: mthca_cmd.c 1349 2004-12-16 21:09:43Z roland $
+ */
+
+-#include <linux/sched.h>
++#include <linux/completion.h>
+ #include <linux/pci.h>
+ #include <linux/errno.h>
+ #include <asm/io.h>
+@@ -1820,11 +1820,11 @@ int mthca_MAD_IFC(struct mthca_dev *dev,
+
+ #define MAD_IFC_BOX_SIZE 0x400
+ #define MAD_IFC_MY_QPN_OFFSET 0x100
+-#define MAD_IFC_RQPN_OFFSET 0x104
+-#define MAD_IFC_SL_OFFSET 0x108
+-#define MAD_IFC_G_PATH_OFFSET 0x109
+-#define MAD_IFC_RLID_OFFSET 0x10a
+-#define MAD_IFC_PKEY_OFFSET 0x10e
++#define MAD_IFC_RQPN_OFFSET 0x108
++#define MAD_IFC_SL_OFFSET 0x10c
++#define MAD_IFC_G_PATH_OFFSET 0x10d
++#define MAD_IFC_RLID_OFFSET 0x10e
++#define MAD_IFC_PKEY_OFFSET 0x112
+ #define MAD_IFC_GRH_OFFSET 0x140
+
+ inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+@@ -1862,7 +1862,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev,
+
+ val = in_wc->dlid_path_bits |
+ (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
+- MTHCA_PUT(inbox, val, MAD_IFC_GRH_OFFSET);
++ MTHCA_PUT(inbox, val, MAD_IFC_G_PATH_OFFSET);
+
+ MTHCA_PUT(inbox, in_wc->slid, MAD_IFC_RLID_OFFSET);
+ MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
+@@ -1870,7 +1870,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev,
+ if (in_grh)
+ memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
+
+- op_modifier |= 0x10;
++ op_modifier |= 0x4;
+
+ in_modifier |= in_wc->slid << 16;
+ }
+diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
+index 3e27a08..149b369 100644
+--- a/drivers/infiniband/hw/mthca/mthca_cq.c
++++ b/drivers/infiniband/hw/mthca/mthca_cq.c
+@@ -39,6 +39,8 @@
+ #include <linux/init.h>
+ #include <linux/hardirq.h>
+
++#include <asm/io.h>
++
+ #include <rdma/ib_pack.h>
+
+ #include "mthca_dev.h"
+@@ -210,6 +212,11 @@ static inline void update_cons_index(str
+ mthca_write64(doorbell,
+ dev->kar + MTHCA_CQ_DOORBELL,
+ MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
++ /*
++ * Make sure doorbells don't leak out of CQ spinlock
++ * and reach the HCA out of order:
++ */
++ mmiowb();
+ }
+ }
+
+@@ -544,11 +551,11 @@ static inline int mthca_poll_one(struct
+ wq = &(*cur_qp)->rq;
+ wqe = be32_to_cpu(cqe->wqe);
+ wqe_index = wqe >> wq->wqe_shift;
+- /*
+- * WQE addr == base - 1 might be reported in receive completion
+- * with error instead of (rq size - 1) by Sinai FW 1.0.800 and
+- * Arbel FW 5.1.400. This bug should be fixed in later FW revs.
+- */
++ /*
++ * WQE addr == base - 1 might be reported in receive completion
++ * with error instead of (rq size - 1) by Sinai FW 1.0.800 and
++ * Arbel FW 5.1.400. This bug should be fixed in later FW revs.
++ */
+ if (unlikely(wqe_index < 0))
+ wqe_index = wq->max - 1;
+ entry->wr_id = (*cur_qp)->wrid[wqe_index];
+diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
+index f8160b8..fe5cecf 100644
+--- a/drivers/infiniband/hw/mthca/mthca_dev.h
++++ b/drivers/infiniband/hw/mthca/mthca_dev.h
+@@ -45,6 +45,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/timer.h>
+ #include <linux/mutex.h>
++#include <linux/list.h>
+
+ #include <asm/semaphore.h>
+
+@@ -283,8 +284,11 @@ struct mthca_catas_err {
+ unsigned long stop;
+ u32 size;
+ struct timer_list timer;
++ struct list_head list;
+ };
+
++extern struct mutex mthca_device_mutex;
++
+ struct mthca_dev {
+ struct ib_device ib_dev;
+ struct pci_dev *pdev;
+@@ -450,6 +454,9 @@ void mthca_unregister_device(struct mthc
+
+ void mthca_start_catas_poll(struct mthca_dev *dev);
+ void mthca_stop_catas_poll(struct mthca_dev *dev);
++int __mthca_restart_one(struct pci_dev *pdev);
++int mthca_catas_init(void);
++void mthca_catas_cleanup(void);
+
+ int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar);
+ void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
+@@ -506,7 +513,7 @@ int mthca_alloc_srq(struct mthca_dev *de
+ struct ib_srq_attr *attr, struct mthca_srq *srq);
+ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
+ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+- enum ib_srq_attr_mask attr_mask);
++ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+ int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
+ int mthca_max_srq_sge(struct mthca_dev *dev);
+ void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
+@@ -521,7 +528,8 @@ void mthca_qp_event(struct mthca_dev *de
+ enum ib_event_type event_type);
+ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr);
+-int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
++int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
++ struct ib_udata *udata);
+ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr);
+ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
+index a29b1b6..e284e06 100644
+--- a/drivers/infiniband/hw/mthca/mthca_eq.c
++++ b/drivers/infiniband/hw/mthca/mthca_eq.c
+@@ -405,7 +405,7 @@ static int mthca_eq_int(struct mthca_dev
+ return eqes_found;
+ }
+
+-static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
++static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr)
+ {
+ struct mthca_dev *dev = dev_ptr;
+ u32 ecr;
+@@ -432,8 +432,7 @@ static irqreturn_t mthca_tavor_interrupt
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr,
+- struct pt_regs *regs)
++static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr)
+ {
+ struct mthca_eq *eq = eq_ptr;
+ struct mthca_dev *dev = eq->dev;
+@@ -446,7 +445,7 @@ static irqreturn_t mthca_tavor_msi_x_int
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
++static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr)
+ {
+ struct mthca_dev *dev = dev_ptr;
+ int work = 0;
+@@ -467,8 +466,7 @@ static irqreturn_t mthca_arbel_interrupt
+ return IRQ_RETVAL(work);
+ }
+
+-static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr,
+- struct pt_regs *regs)
++static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr)
+ {
+ struct mthca_eq *eq = eq_ptr;
+ struct mthca_dev *dev = eq->dev;
+diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
+index d9bc030..45e106f 100644
+--- a/drivers/infiniband/hw/mthca/mthca_mad.c
++++ b/drivers/infiniband/hw/mthca/mthca_mad.c
+@@ -119,7 +119,7 @@ static void smp_snoop(struct ib_device *
+
+ mthca_update_rate(to_mdev(ibdev), port_num);
+ update_sm_ah(to_mdev(ibdev), port_num,
+- be16_to_cpu(pinfo->lid),
++ be16_to_cpu(pinfo->sm_lid),
+ pinfo->neighbormtu_mastersmsl & 0xf);
+
+ event.device = ibdev;
+diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
+index 7b82c19..47ea021 100644
+--- a/drivers/infiniband/hw/mthca/mthca_main.c
++++ b/drivers/infiniband/hw/mthca/mthca_main.c
+@@ -80,6 +80,8 @@ static int tune_pci = 0;
+ module_param(tune_pci, int, 0444);
+ MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero");
+
++struct mutex mthca_device_mutex;
++
+ static const char mthca_version[] __devinitdata =
+ DRV_NAME ": Mellanox InfiniBand HCA driver v"
+ DRV_VERSION " (" DRV_RELDATE ")\n";
+@@ -978,28 +980,15 @@ static struct {
+ MTHCA_FLAG_SINAI_OPT }
+ };
+
+-static int __devinit mthca_init_one(struct pci_dev *pdev,
+- const struct pci_device_id *id)
++static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
+ {
+- static int mthca_version_printed = 0;
+ int ddr_hidden = 0;
+ int err;
+ struct mthca_dev *mdev;
+
+- if (!mthca_version_printed) {
+- printk(KERN_INFO "%s", mthca_version);
+- ++mthca_version_printed;
+- }
+-
+ printk(KERN_INFO PFX "Initializing %s\n",
+ pci_name(pdev));
+
+- if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) {
+- printk(KERN_ERR PFX "%s has invalid driver data %lx\n",
+- pci_name(pdev), id->driver_data);
+- return -ENODEV;
+- }
+-
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot enable PCI device, "
+@@ -1065,7 +1054,7 @@ static int __devinit mthca_init_one(stru
+
+ mdev->pdev = pdev;
+
+- mdev->mthca_flags = mthca_hca_table[id->driver_data].flags;
++ mdev->mthca_flags = mthca_hca_table[hca_type].flags;
+ if (ddr_hidden)
+ mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
+
+@@ -1099,13 +1088,13 @@ static int __devinit mthca_init_one(stru
+ if (err)
+ goto err_cmd;
+
+- if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
++ if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
+ mthca_warn(mdev, "HCA FW version %d.%d.%d is old (%d.%d.%d is current).\n",
+ (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
+ (int) (mdev->fw_ver & 0xffff),
+- (int) (mthca_hca_table[id->driver_data].latest_fw >> 32),
+- (int) (mthca_hca_table[id->driver_data].latest_fw >> 16) & 0xffff,
+- (int) (mthca_hca_table[id->driver_data].latest_fw & 0xffff));
++ (int) (mthca_hca_table[hca_type].latest_fw >> 32),
++ (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff,
++ (int) (mthca_hca_table[hca_type].latest_fw & 0xffff));
+ mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
+ }
+
+@@ -1122,6 +1111,7 @@ static int __devinit mthca_init_one(stru
+ goto err_unregister;
+
+ pci_set_drvdata(pdev, mdev);
++ mdev->hca_type = hca_type;
+
+ return 0;
+
+@@ -1166,7 +1156,7 @@ err_disable_pdev:
+ return err;
+ }
+
+-static void __devexit mthca_remove_one(struct pci_dev *pdev)
++static void __mthca_remove_one(struct pci_dev *pdev)
+ {
+ struct mthca_dev *mdev = pci_get_drvdata(pdev);
+ u8 status;
+@@ -1211,6 +1201,51 @@ static void __devexit mthca_remove_one(s
+ }
+ }
+
++int __mthca_restart_one(struct pci_dev *pdev)
++{
++ struct mthca_dev *mdev;
++
++ mdev = pci_get_drvdata(pdev);
++ if (!mdev)
++ return -ENODEV;
++ __mthca_remove_one(pdev);
++ return __mthca_init_one(pdev, mdev->hca_type);
++}
++
++static int __devinit mthca_init_one(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ static int mthca_version_printed = 0;
++ int ret;
++
++ mutex_lock(&mthca_device_mutex);
++
++ if (!mthca_version_printed) {
++ printk(KERN_INFO "%s", mthca_version);
++ ++mthca_version_printed;
++ }
++
++ if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) {
++ printk(KERN_ERR PFX "%s has invalid driver data %lx\n",
++ pci_name(pdev), id->driver_data);
++ mutex_unlock(&mthca_device_mutex);
++ return -ENODEV;
++ }
++
++ ret = __mthca_init_one(pdev, id->driver_data);
++
++ mutex_unlock(&mthca_device_mutex);
++
++ return ret;
++}
++
++static void __devexit mthca_remove_one(struct pci_dev *pdev)
++{
++ mutex_lock(&mthca_device_mutex);
++ __mthca_remove_one(pdev);
++ mutex_unlock(&mthca_device_mutex);
++}
++
+ static struct pci_device_id mthca_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR),
+ .driver_data = TAVOR },
+@@ -1248,13 +1283,24 @@ static int __init mthca_init(void)
+ {
+ int ret;
+
++ mutex_init(&mthca_device_mutex);
++ ret = mthca_catas_init();
++ if (ret)
++ return ret;
++
+ ret = pci_register_driver(&mthca_driver);
+- return ret < 0 ? ret : 0;
++ if (ret < 0) {
++ mthca_catas_cleanup();
++ return ret;
++ }
++
++ return 0;
+ }
+
+ static void __exit mthca_cleanup(void)
+ {
+ pci_unregister_driver(&mthca_driver);
++ mthca_catas_cleanup();
+ }
+
+ module_init(mthca_init);
+diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
+index 265b1d1..fc67f78 100644
+--- a/drivers/infiniband/hw/mthca/mthca_provider.c
++++ b/drivers/infiniband/hw/mthca/mthca_provider.c
+@@ -179,6 +179,8 @@ static int mthca_query_port(struct ib_de
+ props->max_mtu = out_mad->data[41] & 0xf;
+ props->active_mtu = out_mad->data[36] >> 4;
+ props->subnet_timeout = out_mad->data[51] & 0x1f;
++ props->max_vl_num = out_mad->data[37] >> 4;
++ props->init_type_reply = out_mad->data[41] >> 4;
+
+ out:
+ kfree(in_mad);
+@@ -1288,7 +1290,7 @@ int mthca_register_device(struct mthca_d
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
+ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
+- dev->ib_dev.node_type = IB_NODE_CA;
++ dev->ib_dev.node_type = RDMA_NODE_IB_CA;
+ dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
+ dev->ib_dev.dma_device = &dev->pdev->dev;
+ dev->ib_dev.class_dev.dev = &dev->pdev->dev;
+diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
+index 2e8f6f3..6a7822e 100644
+--- a/drivers/infiniband/hw/mthca/mthca_qp.c
++++ b/drivers/infiniband/hw/mthca/mthca_qp.c
+@@ -39,6 +39,8 @@
+ #include <linux/string.h>
+ #include <linux/slab.h>
+
++#include <asm/io.h>
++
+ #include <rdma/ib_verbs.h>
+ #include <rdma/ib_cache.h>
+ #include <rdma/ib_pack.h>
+@@ -408,7 +410,7 @@ static void to_ib_ah_attr(struct mthca_d
+ ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28;
+ ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f;
+ ib_ah_attr->static_rate = mthca_rate_to_ib(dev,
+- path->static_rate & 0x7,
++ path->static_rate & 0xf,
+ ib_ah_attr->port_num);
+ ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
+ if (ib_ah_attr->ah_flags) {
+@@ -472,10 +474,14 @@ int mthca_query_qp(struct ib_qp *ibqp, s
+ if (qp->transport == RC || qp->transport == UC) {
+ to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+ to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
++ qp_attr->alt_pkey_index =
++ be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
++ qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
+ }
+
+- qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
+- qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
++ qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
++ qp_attr->port_num =
++ (be32_to_cpu(context->pri_path.port_pkey) >> 24) & 0x3;
+
+ /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+ qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING;
+@@ -486,11 +492,9 @@ int mthca_query_qp(struct ib_qp *ibqp, s
+ 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+ qp_attr->min_rnr_timer =
+ (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+- qp_attr->port_num = qp_attr->ah_attr.port_num;
+ qp_attr->timeout = context->pri_path.ackto >> 3;
+ qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7;
+ qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5;
+- qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
+ qp_attr->alt_timeout = context->alt_path.ackto >> 3;
+ qp_init_attr->cap = qp_attr->cap;
+
+@@ -527,7 +531,8 @@ static int mthca_path_set(struct mthca_d
+ return 0;
+ }
+
+-int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
++int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
++ struct ib_udata *udata)
+ {
+ struct mthca_dev *dev = to_mdev(ibqp->device);
+ struct mthca_qp *qp = to_mqp(ibqp);
+@@ -842,11 +847,10 @@ int mthca_modify_qp(struct ib_qp *ibqp,
+ * entries and reinitialize the QP.
+ */
+ if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) {
+- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
++ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
+ qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
+ if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
+- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
+- qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
++ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, NULL);
+
+ mthca_wq_reset(&qp->sq);
+ qp->sq.last = get_send_wqe(qp, qp->sq.max - 1);
+@@ -1730,6 +1734,11 @@ out:
+ mthca_write64(doorbell,
+ dev->kar + MTHCA_SEND_DOORBELL,
+ MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
++ /*
++ * Make sure doorbells don't leak out of SQ spinlock
++ * and reach the HCA out of order:
++ */
++ mmiowb();
+ }
+
+ qp->sq.next_ind = ind;
+@@ -1849,6 +1858,12 @@ out:
+ qp->rq.next_ind = ind;
+ qp->rq.head += nreq;
+
++ /*
++ * Make sure doorbells don't leak out of RQ spinlock and reach
++ * the HCA out of order:
++ */
++ mmiowb();
++
+ spin_unlock_irqrestore(&qp->rq.lock, flags);
+ return err;
+ }
+@@ -2110,6 +2125,12 @@ out:
+ MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+ }
+
++ /*
++ * Make sure doorbells don't leak out of SQ spinlock and reach
++ * the HCA out of order:
++ */
++ mmiowb();
++
+ spin_unlock_irqrestore(&qp->sq.lock, flags);
+ return err;
+ }
+diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
+index b60a9d7..f5d7677 100644
+--- a/drivers/infiniband/hw/mthca/mthca_srq.c
++++ b/drivers/infiniband/hw/mthca/mthca_srq.c
+@@ -35,6 +35,8 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
+
++#include <asm/io.h>
++
+ #include "mthca_dev.h"
+ #include "mthca_cmd.h"
+ #include "mthca_memfree.h"
+@@ -201,6 +203,8 @@ int mthca_alloc_srq(struct mthca_dev *de
+
+ if (mthca_is_memfree(dev))
+ srq->max = roundup_pow_of_two(srq->max + 1);
++ else
++ srq->max = srq->max + 1;
+
+ ds = max(64UL,
+ roundup_pow_of_two(sizeof (struct mthca_next_seg) +
+@@ -277,7 +281,7 @@ int mthca_alloc_srq(struct mthca_dev *de
+ srq->first_free = 0;
+ srq->last_free = srq->max - 1;
+
+- attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
++ attr->max_wr = srq->max - 1;
+ attr->max_sge = srq->max_gs;
+
+ return 0;
+@@ -358,7 +362,7 @@ void mthca_free_srq(struct mthca_dev *de
+ }
+
+ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+- enum ib_srq_attr_mask attr_mask)
++ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+ {
+ struct mthca_dev *dev = to_mdev(ibsrq->device);
+ struct mthca_srq *srq = to_msrq(ibsrq);
+@@ -413,7 +417,7 @@ int mthca_query_srq(struct ib_srq *ibsrq
+ srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark);
+ }
+
+- srq_attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
++ srq_attr->max_wr = srq->max - 1;
+ srq_attr->max_sge = srq->max_gs;
+
+ out:
+@@ -593,6 +597,12 @@ int mthca_tavor_post_srq_recv(struct ib_
+ MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+ }
+
++ /*
++ * Make sure doorbells don't leak out of SRQ spinlock and
++ * reach the HCA out of order:
++ */
++ mmiowb();
++
+ spin_unlock_irqrestore(&srq->lock, flags);
+ return err;
+ }
+diff --git a/drivers/infiniband/hw/mthca/mthca_uar.c b/drivers/infiniband/hw/mthca/mthca_uar.c
+index 8e92198..8b72848 100644
+--- a/drivers/infiniband/hw/mthca/mthca_uar.c
++++ b/drivers/infiniband/hw/mthca/mthca_uar.c
+@@ -60,7 +60,7 @@ int mthca_init_uar_table(struct mthca_de
+ ret = mthca_alloc_init(&dev->uar_table.alloc,
+ dev->limits.num_uars,
+ dev->limits.num_uars - 1,
+- dev->limits.reserved_uars);
++ dev->limits.reserved_uars + 1);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
+index d74653d..c75322d 100644
+--- a/drivers/infiniband/ulp/ipoib/Kconfig
++++ b/drivers/infiniband/ulp/ipoib/Kconfig
+@@ -26,7 +26,7 @@ config INFINIBAND_IPOIB_DEBUG_DATA
+ bool "IP-over-InfiniBand data path debugging"
+ depends on INFINIBAND_IPOIB_DEBUG
+ ---help---
+- This option compiles debugging code into the the data path
++ This option compiles debugging code into the data path
+ of the IPoIB driver. The output can be turned on via the
+ data_debug_level module parameter; however, even with output
+ turned off, this debugging code will have some performance
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
+index 474aa21..0b8a79d 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib.h
++++ b/drivers/infiniband/ulp/ipoib/ipoib.h
+@@ -336,6 +336,8 @@ static inline void ipoib_unregister_debu
+ extern int ipoib_sendq_size;
+ extern int ipoib_recvq_size;
+
++extern struct ib_sa_client ipoib_sa_client;
++
+ #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+ extern int ipoib_debug_level;
+
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+index 5dde380..f1cb836 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+@@ -141,7 +141,7 @@ static int ipoib_mcg_open(struct inode *
+ return ret;
+
+ seq = file->private_data;
+- seq->private = inode->u.generic_ip;
++ seq->private = inode->i_private;
+
+ return 0;
+ }
+@@ -247,7 +247,7 @@ static int ipoib_path_open(struct inode
+ return ret;
+
+ seq = file->private_data;
+- seq->private = inode->u.generic_ip;
++ seq->private = inode->i_private;
+
+ return 0;
+ }
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+index 5033666..8bf5e9e 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+@@ -169,117 +169,129 @@ static int ipoib_ib_post_receives(struct
+ return 0;
+ }
+
+-static void ipoib_ib_handle_wc(struct net_device *dev,
+- struct ib_wc *wc)
++static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ {
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+- unsigned int wr_id = wc->wr_id;
++ unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
++ struct sk_buff *skb;
++ dma_addr_t addr;
+
+- ipoib_dbg_data(priv, "called: id %d, op %d, status: %d\n",
++ ipoib_dbg_data(priv, "recv completion: id %d, op %d, status: %d\n",
+ wr_id, wc->opcode, wc->status);
+
+- if (wr_id & IPOIB_OP_RECV) {
+- wr_id &= ~IPOIB_OP_RECV;
+-
+- if (wr_id < ipoib_recvq_size) {
+- struct sk_buff *skb = priv->rx_ring[wr_id].skb;
+- dma_addr_t addr = priv->rx_ring[wr_id].mapping;
+-
+- if (unlikely(wc->status != IB_WC_SUCCESS)) {
+- if (wc->status != IB_WC_WR_FLUSH_ERR)
+- ipoib_warn(priv, "failed recv event "
+- "(status=%d, wrid=%d vend_err %x)\n",
+- wc->status, wr_id, wc->vendor_err);
+- dma_unmap_single(priv->ca->dma_device, addr,
+- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+- dev_kfree_skb_any(skb);
+- priv->rx_ring[wr_id].skb = NULL;
+- return;
+- }
++ if (unlikely(wr_id >= ipoib_recvq_size)) {
++ ipoib_warn(priv, "recv completion event with wrid %d (> %d)\n",
++ wr_id, ipoib_recvq_size);
++ return;
++ }
+
+- /*
+- * If we can't allocate a new RX buffer, dump
+- * this packet and reuse the old buffer.
+- */
+- if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
+- ++priv->stats.rx_dropped;
+- goto repost;
+- }
++ skb = priv->rx_ring[wr_id].skb;
++ addr = priv->rx_ring[wr_id].mapping;
+
+- ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
+- wc->byte_len, wc->slid);
++ if (unlikely(wc->status != IB_WC_SUCCESS)) {
++ if (wc->status != IB_WC_WR_FLUSH_ERR)
++ ipoib_warn(priv, "failed recv event "
++ "(status=%d, wrid=%d vend_err %x)\n",
++ wc->status, wr_id, wc->vendor_err);
++ dma_unmap_single(priv->ca->dma_device, addr,
++ IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
++ dev_kfree_skb_any(skb);
++ priv->rx_ring[wr_id].skb = NULL;
++ return;
++ }
+
+- dma_unmap_single(priv->ca->dma_device, addr,
+- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
++ /*
++ * If we can't allocate a new RX buffer, dump
++ * this packet and reuse the old buffer.
++ */
++ if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
++ ++priv->stats.rx_dropped;
++ goto repost;
++ }
+
+- skb_put(skb, wc->byte_len);
+- skb_pull(skb, IB_GRH_BYTES);
++ ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
++ wc->byte_len, wc->slid);
+
+- if (wc->slid != priv->local_lid ||
+- wc->src_qp != priv->qp->qp_num) {
+- skb->protocol = ((struct ipoib_header *) skb->data)->proto;
+- skb->mac.raw = skb->data;
+- skb_pull(skb, IPOIB_ENCAP_LEN);
++ dma_unmap_single(priv->ca->dma_device, addr,
++ IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+
+- dev->last_rx = jiffies;
+- ++priv->stats.rx_packets;
+- priv->stats.rx_bytes += skb->len;
++ skb_put(skb, wc->byte_len);
++ skb_pull(skb, IB_GRH_BYTES);
+
+- skb->dev = dev;
+- /* XXX get correct PACKET_ type here */
+- skb->pkt_type = PACKET_HOST;
+- netif_rx_ni(skb);
+- } else {
+- ipoib_dbg_data(priv, "dropping loopback packet\n");
+- dev_kfree_skb_any(skb);
+- }
++ if (wc->slid != priv->local_lid ||
++ wc->src_qp != priv->qp->qp_num) {
++ skb->protocol = ((struct ipoib_header *) skb->data)->proto;
++ skb->mac.raw = skb->data;
++ skb_pull(skb, IPOIB_ENCAP_LEN);
+
+- repost:
+- if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
+- ipoib_warn(priv, "ipoib_ib_post_receive failed "
+- "for buf %d\n", wr_id);
+- } else
+- ipoib_warn(priv, "completion event with wrid %d\n",
+- wr_id);
++ dev->last_rx = jiffies;
++ ++priv->stats.rx_packets;
++ priv->stats.rx_bytes += skb->len;
+
++ skb->dev = dev;
++ /* XXX get correct PACKET_ type here */
++ skb->pkt_type = PACKET_HOST;
++ netif_rx_ni(skb);
+ } else {
+- struct ipoib_tx_buf *tx_req;
+- unsigned long flags;
++ ipoib_dbg_data(priv, "dropping loopback packet\n");
++ dev_kfree_skb_any(skb);
++ }
+
+- if (wr_id >= ipoib_sendq_size) {
+- ipoib_warn(priv, "completion event with wrid %d (> %d)\n",
+- wr_id, ipoib_sendq_size);
+- return;
+- }
++repost:
++ if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
++ ipoib_warn(priv, "ipoib_ib_post_receive failed "
++ "for buf %d\n", wr_id);
++}
++
++static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
++{
++ struct ipoib_dev_priv *priv = netdev_priv(dev);
++ unsigned int wr_id = wc->wr_id;
++ struct ipoib_tx_buf *tx_req;
++ unsigned long flags;
+
+- ipoib_dbg_data(priv, "send complete, wrid %d\n", wr_id);
++ ipoib_dbg_data(priv, "send completion: id %d, op %d, status: %d\n",
++ wr_id, wc->opcode, wc->status);
+
+- tx_req = &priv->tx_ring[wr_id];
++ if (unlikely(wr_id >= ipoib_sendq_size)) {
++ ipoib_warn(priv, "send completion event with wrid %d (> %d)\n",
++ wr_id, ipoib_sendq_size);
++ return;
++ }
+
+- dma_unmap_single(priv->ca->dma_device,
+- pci_unmap_addr(tx_req, mapping),
+- tx_req->skb->len,
+- DMA_TO_DEVICE);
++ tx_req = &priv->tx_ring[wr_id];
+
+- ++priv->stats.tx_packets;
+- priv->stats.tx_bytes += tx_req->skb->len;
++ dma_unmap_single(priv->ca->dma_device,
++ pci_unmap_addr(tx_req, mapping),
++ tx_req->skb->len,
++ DMA_TO_DEVICE);
+
+- dev_kfree_skb_any(tx_req->skb);
++ ++priv->stats.tx_packets;
++ priv->stats.tx_bytes += tx_req->skb->len;
+
+- spin_lock_irqsave(&priv->tx_lock, flags);
+- ++priv->tx_tail;
+- if (netif_queue_stopped(dev) &&
+- test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) &&
+- priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1)
+- netif_wake_queue(dev);
+- spin_unlock_irqrestore(&priv->tx_lock, flags);
++ dev_kfree_skb_any(tx_req->skb);
+
+- if (wc->status != IB_WC_SUCCESS &&
+- wc->status != IB_WC_WR_FLUSH_ERR)
+- ipoib_warn(priv, "failed send event "
+- "(status=%d, wrid=%d vend_err %x)\n",
+- wc->status, wr_id, wc->vendor_err);
+- }
++ spin_lock_irqsave(&priv->tx_lock, flags);
++ ++priv->tx_tail;
++ if (netif_queue_stopped(dev) &&
++ test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) &&
++ priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1)
++ netif_wake_queue(dev);
++ spin_unlock_irqrestore(&priv->tx_lock, flags);
++
++ if (wc->status != IB_WC_SUCCESS &&
++ wc->status != IB_WC_WR_FLUSH_ERR)
++ ipoib_warn(priv, "failed send event "
++ "(status=%d, wrid=%d vend_err %x)\n",
++ wc->status, wr_id, wc->vendor_err);
++}
++
++static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc)
++{
++ if (wc->wr_id & IPOIB_OP_RECV)
++ ipoib_ib_handle_rx_wc(dev, wc);
++ else
++ ipoib_ib_handle_tx_wc(dev, wc);
+ }
+
+ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
+@@ -320,7 +332,7 @@ void ipoib_send(struct net_device *dev,
+ struct ipoib_tx_buf *tx_req;
+ dma_addr_t addr;
+
+- if (skb->len > dev->mtu + INFINIBAND_ALEN) {
++ if (unlikely(skb->len > dev->mtu + INFINIBAND_ALEN)) {
+ ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
+ skb->len, dev->mtu + INFINIBAND_ALEN);
+ ++priv->stats.tx_dropped;
+@@ -343,6 +355,11 @@ void ipoib_send(struct net_device *dev,
+ tx_req->skb = skb;
+ addr = dma_map_single(priv->ca->dma_device, skb->data, skb->len,
+ DMA_TO_DEVICE);
++ if (unlikely(dma_mapping_error(addr))) {
++ ++priv->stats.tx_errors;
++ dev_kfree_skb_any(skb);
++ return;
++ }
+ pci_unmap_addr_set(tx_req, mapping, addr);
+
+ if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
+@@ -619,8 +636,10 @@ void ipoib_ib_dev_flush(void *_dev)
+ * The device could have been brought down between the start and when
+ * we get here, don't bring it back up if it's not configured up
+ */
+- if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
++ if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) {
+ ipoib_ib_dev_up(dev);
++ ipoib_mcast_restart_task(dev);
++ }
+
+ mutex_lock(&priv->vlan_mutex);
+
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+index cf71d2a..1eaf00e 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+@@ -40,7 +40,6 @@
+
+ #include <linux/init.h>
+ #include <linux/slab.h>
+-#include <linux/vmalloc.h>
+ #include <linux/kernel.h>
+
+ #include <linux/if_arp.h> /* For ARPHRD_xxx */
+@@ -82,6 +81,8 @@ static const u8 ipv4_bcast_addr[] = {
+
+ struct workqueue_struct *ipoib_workqueue;
+
++struct ib_sa_client ipoib_sa_client;
++
+ static void ipoib_add_one(struct ib_device *device);
+ static void ipoib_remove_one(struct ib_device *device);
+
+@@ -336,7 +337,8 @@ void ipoib_flush_paths(struct net_device
+ struct ipoib_path *path, *tp;
+ LIST_HEAD(remove_list);
+
+- spin_lock_irq(&priv->lock);
++ spin_lock_irq(&priv->tx_lock);
++ spin_lock(&priv->lock);
+
+ list_splice(&priv->path_list, &remove_list);
+ INIT_LIST_HEAD(&priv->path_list);
+@@ -347,12 +349,15 @@ void ipoib_flush_paths(struct net_device
+ list_for_each_entry_safe(path, tp, &remove_list, list) {
+ if (path->query)
+ ib_sa_cancel_query(path->query_id, path->query);
+- spin_unlock_irq(&priv->lock);
++ spin_unlock(&priv->lock);
++ spin_unlock_irq(&priv->tx_lock);
+ wait_for_completion(&path->done);
+ path_free(dev, path);
+- spin_lock_irq(&priv->lock);
++ spin_lock_irq(&priv->tx_lock);
++ spin_lock(&priv->lock);
+ }
+- spin_unlock_irq(&priv->lock);
++ spin_unlock(&priv->lock);
++ spin_unlock_irq(&priv->tx_lock);
+ }
+
+ static void path_rec_completion(int status,
+@@ -459,7 +464,7 @@ static int path_rec_start(struct net_dev
+ init_completion(&path->done);
+
+ path->query_id =
+- ib_sa_path_rec_get(priv->ca, priv->port,
++ ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port,
+ &path->pathrec,
+ IB_SA_PATH_REC_DGID |
+ IB_SA_PATH_REC_SGID |
+@@ -615,7 +620,7 @@ static int ipoib_start_xmit(struct sk_bu
+ struct ipoib_neigh *neigh;
+ unsigned long flags;
+
+- if (!spin_trylock_irqsave(&priv->tx_lock, flags))
++ if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
+ return NETDEV_TX_LOCKED;
+
+ /*
+@@ -628,7 +633,7 @@ static int ipoib_start_xmit(struct sk_bu
+ return NETDEV_TX_BUSY;
+ }
+
+- if (skb->dst && skb->dst->neighbour) {
++ if (likely(skb->dst && skb->dst->neighbour)) {
+ if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
+ ipoib_path_lookup(skb, dev);
+ goto out;
+@@ -1107,13 +1112,16 @@ static void ipoib_add_one(struct ib_devi
+ struct ipoib_dev_priv *priv;
+ int s, e, p;
+
++ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
++ return;
++
+ dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
+ if (!dev_list)
+ return;
+
+ INIT_LIST_HEAD(dev_list);
+
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ s = 0;
+ e = 0;
+ } else {
+@@ -1137,6 +1145,9 @@ static void ipoib_remove_one(struct ib_d
+ struct ipoib_dev_priv *priv, *tmp;
+ struct list_head *dev_list;
+
++ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
++ return;
++
+ dev_list = ib_get_client_data(device, &ipoib_client);
+
+ list_for_each_entry_safe(priv, tmp, dev_list, list) {
+@@ -1181,13 +1192,16 @@ static int __init ipoib_init_module(void
+ goto err_fs;
+ }
+
++ ib_sa_register_client(&ipoib_sa_client);
++
+ ret = ib_register_client(&ipoib_client);
+ if (ret)
+- goto err_wq;
++ goto err_sa;
+
+ return 0;
+
+-err_wq:
++err_sa:
++ ib_sa_unregister_client(&ipoib_sa_client);
+ destroy_workqueue(ipoib_workqueue);
+
+ err_fs:
+@@ -1199,6 +1213,7 @@ err_fs:
+ static void __exit ipoib_cleanup_module(void)
+ {
+ ib_unregister_client(&ipoib_client);
++ ib_sa_unregister_client(&ipoib_sa_client);
+ ipoib_unregister_debugfs();
+ destroy_workqueue(ipoib_workqueue);
+ }
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+index ec356ce..3faa182 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+@@ -361,7 +361,7 @@ static int ipoib_mcast_sendonly_join(str
+
+ init_completion(&mcast->done);
+
+- ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec,
++ ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec,
+ IB_SA_MCMEMBER_REC_MGID |
+ IB_SA_MCMEMBER_REC_PORT_GID |
+ IB_SA_MCMEMBER_REC_PKEY |
+@@ -472,22 +472,32 @@ static void ipoib_mcast_join(struct net_
+
+ if (create) {
+ comp_mask |=
+- IB_SA_MCMEMBER_REC_QKEY |
+- IB_SA_MCMEMBER_REC_SL |
+- IB_SA_MCMEMBER_REC_FLOW_LABEL |
+- IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
++ IB_SA_MCMEMBER_REC_QKEY |
++ IB_SA_MCMEMBER_REC_MTU_SELECTOR |
++ IB_SA_MCMEMBER_REC_MTU |
++ IB_SA_MCMEMBER_REC_TRAFFIC_CLASS |
++ IB_SA_MCMEMBER_REC_RATE_SELECTOR |
++ IB_SA_MCMEMBER_REC_RATE |
++ IB_SA_MCMEMBER_REC_SL |
++ IB_SA_MCMEMBER_REC_FLOW_LABEL |
++ IB_SA_MCMEMBER_REC_HOP_LIMIT;
+
+ rec.qkey = priv->broadcast->mcmember.qkey;
++ rec.mtu_selector = IB_SA_EQ;
++ rec.mtu = priv->broadcast->mcmember.mtu;
++ rec.traffic_class = priv->broadcast->mcmember.traffic_class;
++ rec.rate_selector = IB_SA_EQ;
++ rec.rate = priv->broadcast->mcmember.rate;
+ rec.sl = priv->broadcast->mcmember.sl;
+ rec.flow_label = priv->broadcast->mcmember.flow_label;
+- rec.traffic_class = priv->broadcast->mcmember.traffic_class;
++ rec.hop_limit = priv->broadcast->mcmember.hop_limit;
+ }
+
+ init_completion(&mcast->done);
+
+- ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, comp_mask,
+- mcast->backoff * 1000, GFP_ATOMIC,
+- ipoib_mcast_join_complete,
++ ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port,
++ &rec, comp_mask, mcast->backoff * 1000,
++ GFP_ATOMIC, ipoib_mcast_join_complete,
+ mcast, &mcast->query);
+
+ if (ret < 0) {
+@@ -528,7 +538,7 @@ void ipoib_mcast_join_task(void *dev_ptr
+ priv->local_rate = attr.active_speed *
+ ib_width_enum_to_int(attr.active_width);
+ } else
+- ipoib_warn(priv, "ib_query_port failed\n");
++ ipoib_warn(priv, "ib_query_port failed\n");
+ }
+
+ if (!priv->broadcast) {
+@@ -681,7 +691,7 @@ static int ipoib_mcast_leave(struct net_
+ * Just make one shot at leaving and don't wait for a reply;
+ * if we fail, too bad.
+ */
+- ret = ib_sa_mcmember_rec_delete(priv->ca, priv->port, &rec,
++ ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec,
+ IB_SA_MCMEMBER_REC_MGID |
+ IB_SA_MCMEMBER_REC_PORT_GID |
+ IB_SA_MCMEMBER_REC_PKEY |
+@@ -795,7 +805,7 @@ void ipoib_mcast_dev_flush(struct net_de
+ }
+
+ if (priv->broadcast) {
+- rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
++ rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
+ list_add_tail(&priv->broadcast->list, &remove_list);
+ priv->broadcast = NULL;
+ }
+diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
+index fead87d..aecbb90 100644
+--- a/drivers/infiniband/ulp/iser/Kconfig
++++ b/drivers/infiniband/ulp/iser/Kconfig
+@@ -1,11 +1,12 @@
+ config INFINIBAND_ISER
+- tristate "ISCSI RDMA Protocol"
+- depends on INFINIBAND && SCSI
++ tristate "iSCSI Extensions for RDMA (iSER)"
++ depends on INFINIBAND && SCSI && INET
+ select SCSI_ISCSI_ATTRS
+ ---help---
+- Support for the ISCSI RDMA Protocol over InfiniBand. This
+- allows you to access storage devices that speak ISER/ISCSI
+- over InfiniBand.
++ Support for the iSCSI Extensions for RDMA (iSER) Protocol
++ over InfiniBand. This allows you to access storage devices
++ that speak iSCSI over iSER over InfiniBand.
+
+- The ISER protocol is defined by IETF.
+- See <http://www.ietf.org/>.
++ The iSER protocol is defined by IETF.
++ See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
++ and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
+diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
+index 1437d7e..9b2041e 100644
+--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
++++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
+@@ -141,18 +141,11 @@ iscsi_iser_cmd_init(struct iscsi_cmd_tas
+
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ BUG_ON(ctask->total_length == 0);
+- /* bytes to be sent via RDMA operations */
+- iser_ctask->rdma_data_count = ctask->total_length -
+- ctask->imm_count -
+- ctask->unsol_count;
+
+- debug_scsi("cmd [itt %x total %d imm %d unsol_data %d "
+- "rdma_data %d]\n",
++ debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
+ ctask->itt, ctask->total_length, ctask->imm_count,
+- ctask->unsol_count, iser_ctask->rdma_data_count);
+- } else
+- /* bytes to be sent via RDMA operations */
+- iser_ctask->rdma_data_count = ctask->total_length;
++ ctask->unsol_count);
++ }
+
+ iser_ctask_rdma_init(iser_ctask);
+ }
+@@ -196,13 +189,10 @@ iscsi_iser_ctask_xmit_unsol_data(struct
+ {
+ struct iscsi_data hdr;
+ int error = 0;
+- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+
+ /* Send data-out PDUs while there's still unsolicited data to send */
+ while (ctask->unsol_count > 0) {
+- iscsi_prep_unsolicit_data_pdu(ctask, &hdr,
+- iser_ctask->rdma_data_count);
+-
++ iscsi_prep_unsolicit_data_pdu(ctask, &hdr);
+ debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
+ hdr.itt, ctask->data_count);
+
+@@ -327,6 +317,8 @@ iscsi_iser_conn_destroy(struct iscsi_cls
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+ iscsi_conn_teardown(cls_conn);
++ if (iser_conn->ib_conn)
++ iser_conn->ib_conn->iser_conn = NULL;
+ kfree(iser_conn);
+ }
+
+@@ -371,11 +363,11 @@ iscsi_iser_conn_start(struct iscsi_cls_c
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ int err;
+
+- err = iscsi_conn_start(cls_conn);
++ err = iser_conn_set_full_featured_mode(conn);
+ if (err)
+ return err;
+
+- return iser_conn_set_full_featured_mode(conn);
++ return iscsi_conn_start(cls_conn);
+ }
+
+ static struct iscsi_transport iscsi_iser_transport;
+@@ -555,6 +547,7 @@ static struct scsi_host_template iscsi_i
+ .queuecommand = iscsi_queuecommand,
+ .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
++ .max_sectors = 1024,
+ .cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
+ .eh_abort_handler = iscsi_eh_abort,
+ .eh_host_reset_handler = iscsi_eh_host_reset,
+diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
+index 3350ba6..9c53916 100644
+--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
++++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
+@@ -82,8 +82,12 @@
+ __func__ , ## arg); \
+ } while (0)
+
++#define SHIFT_4K 12
++#define SIZE_4K (1UL << SHIFT_4K)
++#define MASK_4K (~(SIZE_4K-1))
++
+ /* support upto 512KB in one RDMA */
+-#define ISCSI_ISER_SG_TABLESIZE (0x80000 >> PAGE_SHIFT)
++#define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K)
+ #define ISCSI_ISER_MAX_LUN 256
+ #define ISCSI_ISER_MAX_CMD_LEN 16
+
+@@ -171,6 +175,7 @@ struct iser_mem_reg {
+ u64 va;
+ u64 len;
+ void *mem_h;
++ int is_fmr;
+ };
+
+ struct iser_regd_buf {
+@@ -187,7 +192,7 @@ struct iser_regd_buf {
+
+ struct iser_dto {
+ struct iscsi_iser_cmd_task *ctask;
+- struct iscsi_iser_conn *conn;
++ struct iser_conn *ib_conn;
+ int notify_enable;
+
+ /* vector of registered buffers */
+@@ -257,7 +262,6 @@ struct iscsi_iser_conn {
+ struct iscsi_iser_cmd_task {
+ struct iser_desc desc;
+ struct iscsi_iser_conn *iser_conn;
+- int rdma_data_count;/* RDMA bytes */
+ enum iser_task_status status;
+ int command_sent; /* set if command sent */
+ int dir[ISER_DIRS_NUM]; /* set if dir use*/
+@@ -351,4 +355,11 @@ int iser_post_send(struct iser_desc *tx
+
+ int iser_conn_state_comp(struct iser_conn *ib_conn,
+ enum iser_ib_conn_state comp);
++
++int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
++ struct iser_data_buf *data,
++ enum iser_data_dir iser_dir,
++ enum dma_data_direction dma_dir);
++
++void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask);
+ #endif
+diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
+index ccf56f6..9b3d79c 100644
+--- a/drivers/infiniband/ulp/iser/iser_initiator.c
++++ b/drivers/infiniband/ulp/iser/iser_initiator.c
+@@ -66,42 +66,6 @@ static void iser_dto_add_regd_buff(struc
+ dto->regd_vector_len++;
+ }
+
+-static int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+- struct iser_data_buf *data,
+- enum iser_data_dir iser_dir,
+- enum dma_data_direction dma_dir)
+-{
+- struct device *dma_device;
+-
+- iser_ctask->dir[iser_dir] = 1;
+- dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+-
+- data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
+- if (data->dma_nents == 0) {
+- iser_err("dma_map_sg failed!!!\n");
+- return -EINVAL;
+- }
+- return 0;
+-}
+-
+-static void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+-{
+- struct device *dma_device;
+- struct iser_data_buf *data;
+-
+- dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+-
+- if (iser_ctask->dir[ISER_DIR_IN]) {
+- data = &iser_ctask->data[ISER_DIR_IN];
+- dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
+- }
+-
+- if (iser_ctask->dir[ISER_DIR_OUT]) {
+- data = &iser_ctask->data[ISER_DIR_OUT];
+- dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
+- }
+-}
+-
+ /* Register user buffer memory and initialize passive rdma
+ * dto descriptor. Total data size is stored in
+ * iser_ctask->data[ISER_DIR_IN].data_len
+@@ -249,7 +213,7 @@ static int iser_post_receive_control(str
+ }
+
+ recv_dto = &rx_desc->dto;
+- recv_dto->conn = iser_conn;
++ recv_dto->ib_conn = iser_conn->ib_conn;
+ recv_dto->regd_vector_len = 0;
+
+ regd_hdr = &rx_desc->hdr_regd_buf;
+@@ -296,7 +260,7 @@ static void iser_create_send_desc(struct
+ regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */
+ regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
+
+- send_dto->conn = iser_conn;
++ send_dto->ib_conn = iser_conn->ib_conn;
+ send_dto->notify_enable = 1;
+ send_dto->regd_vector_len = 0;
+
+@@ -588,7 +552,7 @@ void iser_rcv_completion(struct iser_des
+ unsigned long dto_xfer_len)
+ {
+ struct iser_dto *dto = &rx_desc->dto;
+- struct iscsi_iser_conn *conn = dto->conn;
++ struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
+ struct iscsi_session *session = conn->iscsi_conn->session;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_iser_cmd_task *iser_ctask;
+@@ -641,7 +605,8 @@ void iser_rcv_completion(struct iser_des
+ void iser_snd_completion(struct iser_desc *tx_desc)
+ {
+ struct iser_dto *dto = &tx_desc->dto;
+- struct iscsi_iser_conn *iser_conn = dto->conn;
++ struct iser_conn *ib_conn = dto->ib_conn;
++ struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
+ struct iscsi_conn *conn = iser_conn->iscsi_conn;
+ struct iscsi_mgmt_task *mtask;
+
+@@ -652,7 +617,7 @@ void iser_snd_completion(struct iser_des
+ if (tx_desc->type == ISCSI_TX_DATAOUT)
+ kmem_cache_free(ig.desc_cache, tx_desc);
+
+- atomic_dec(&iser_conn->ib_conn->post_send_buf_count);
++ atomic_dec(&ib_conn->post_send_buf_count);
+
+ write_lock(conn->recv_lock);
+ if (conn->suspend_tx) {
+@@ -698,14 +663,19 @@ void iser_ctask_rdma_init(struct iscsi_i
+ void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
+ {
+ int deferred;
++ int is_rdma_aligned = 1;
+
+ /* if we were reading, copy back to unaligned sglist,
+ * anyway dma_unmap and free the copy
+ */
+- if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL)
++ if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL) {
++ is_rdma_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN);
+- if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL)
++ }
++ if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
++ is_rdma_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT);
++ }
+
+ if (iser_ctask->dir[ISER_DIR_IN]) {
+ deferred = iser_regd_buff_release
+@@ -725,7 +695,9 @@ void iser_ctask_rdma_finalize(struct isc
+ }
+ }
+
+- iser_dma_unmap_task_data(iser_ctask);
++ /* if the data was unaligned, it was already unmapped and then copied */
++ if (is_rdma_aligned)
++ iser_dma_unmap_task_data(iser_ctask);
+ }
+
+ void iser_dto_buffs_release(struct iser_dto *dto)
+diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
+index 31950a5..0606744 100644
+--- a/drivers/infiniband/ulp/iser/iser_memory.c
++++ b/drivers/infiniband/ulp/iser/iser_memory.c
+@@ -42,6 +42,7 @@
+ #include "iscsi_iser.h"
+
+ #define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */
++
+ /**
+ * Decrements the reference count for the
+ * registered buffer & releases it
+@@ -55,7 +56,7 @@ int iser_regd_buff_release(struct iser_r
+ if ((atomic_read(®d_buf->ref_count) == 0) ||
+ atomic_dec_and_test(®d_buf->ref_count)) {
+ /* if we used the dma mr, unreg is just NOP */
+- if (regd_buf->reg.rkey != 0)
++ if (regd_buf->reg.is_fmr)
+ iser_unreg_mem(®d_buf->reg);
+
+ if (regd_buf->dma_addr) {
+@@ -90,9 +91,9 @@ void iser_reg_single(struct iser_device
+ BUG_ON(dma_mapping_error(dma_addr));
+
+ regd_buf->reg.lkey = device->mr->lkey;
+- regd_buf->reg.rkey = 0; /* indicate there's no need to unreg */
+ regd_buf->reg.len = regd_buf->data_size;
+ regd_buf->reg.va = dma_addr;
++ regd_buf->reg.is_fmr = 0;
+
+ regd_buf->dma_addr = dma_addr;
+ regd_buf->direction = direction;
+@@ -239,7 +240,7 @@ static int iser_sg_to_page_vec(struct is
+ int i;
+
+ /* compute the offset of first element */
+- page_vec->offset = (u64) sg[0].offset;
++ page_vec->offset = (u64) sg[0].offset & ~MASK_4K;
+
+ for (i = 0; i < data->dma_nents; i++) {
+ total_sz += sg_dma_len(&sg[i]);
+@@ -247,21 +248,30 @@ static int iser_sg_to_page_vec(struct is
+ first_addr = sg_dma_address(&sg[i]);
+ last_addr = first_addr + sg_dma_len(&sg[i]);
+
+- start_aligned = !(first_addr & ~PAGE_MASK);
+- end_aligned = !(last_addr & ~PAGE_MASK);
++ start_aligned = !(first_addr & ~MASK_4K);
++ end_aligned = !(last_addr & ~MASK_4K);
+
+ /* continue to collect page fragments till aligned or SG ends */
+ while (!end_aligned && (i + 1 < data->dma_nents)) {
+ i++;
+ total_sz += sg_dma_len(&sg[i]);
+ last_addr = sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]);
+- end_aligned = !(last_addr & ~PAGE_MASK);
++ end_aligned = !(last_addr & ~MASK_4K);
+ }
+
+- first_addr = first_addr & PAGE_MASK;
+-
+- for (page = first_addr; page < last_addr; page += PAGE_SIZE)
+- page_vec->pages[cur_page++] = page;
++ /* handle the 1st page in the 1st DMA element */
++ if (cur_page == 0) {
++ page = first_addr & MASK_4K;
++ page_vec->pages[cur_page] = page;
++ cur_page++;
++ page += SIZE_4K;
++ } else
++ page = first_addr;
++
++ for (; page < last_addr; page += SIZE_4K) {
++ page_vec->pages[cur_page] = page;
++ cur_page++;
++ }
+
+ }
+ page_vec->data_size = total_sz;
+@@ -269,8 +279,7 @@ static int iser_sg_to_page_vec(struct is
+ return cur_page;
+ }
+
+-#define MASK_4K ((1UL << 12) - 1) /* 0xFFF */
+-#define IS_4K_ALIGNED(addr) ((((unsigned long)addr) & MASK_4K) == 0)
++#define IS_4K_ALIGNED(addr) ((((unsigned long)addr) & ~MASK_4K) == 0)
+
+ /**
+ * iser_data_buf_aligned_len - Tries to determine the maximal correctly aligned
+@@ -320,9 +329,9 @@ static void iser_data_buf_dump(struct is
+ struct scatterlist *sg = (struct scatterlist *)data->buf;
+ int i;
+
+- for (i = 0; i < data->size; i++)
++ for (i = 0; i < data->dma_nents; i++)
+ iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
+- "off:%d sz:%d dma_len:%d\n",
++ "off:0x%x sz:0x%x dma_len:0x%x\n",
+ i, (unsigned long)sg_dma_address(&sg[i]),
+ sg[i].page, sg[i].offset,
+ sg[i].length,sg_dma_len(&sg[i]));
+@@ -352,7 +361,7 @@ static void iser_page_vec_build(struct i
+
+ page_vec->length = page_vec_len;
+
+- if (page_vec_len * PAGE_SIZE < page_vec->data_size) {
++ if (page_vec_len * SIZE_4K < page_vec->data_size) {
+ iser_err("page_vec too short to hold this SG\n");
+ iser_data_buf_dump(data);
+ iser_dump_page_vec(page_vec);
+@@ -360,6 +369,44 @@ static void iser_page_vec_build(struct i
+ }
+ }
+
++int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
++ struct iser_data_buf *data,
++ enum iser_data_dir iser_dir,
++ enum dma_data_direction dma_dir)
++{
++ struct device *dma_device;
++
++ iser_ctask->dir[iser_dir] = 1;
++ dma_device =
++ iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
++
++ data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
++ if (data->dma_nents == 0) {
++ iser_err("dma_map_sg failed!!!\n");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
++{
++ struct device *dma_device;
++ struct iser_data_buf *data;
++
++ dma_device =
++ iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
++
++ if (iser_ctask->dir[ISER_DIR_IN]) {
++ data = &iser_ctask->data[ISER_DIR_IN];
++ dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
++ }
++
++ if (iser_ctask->dir[ISER_DIR_OUT]) {
++ data = &iser_ctask->data[ISER_DIR_OUT];
++ dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
++ }
++}
++
+ /**
+ * iser_reg_rdma_mem - Registers memory intended for RDMA,
+ * obtaining rkey and va
+@@ -370,18 +417,25 @@ int iser_reg_rdma_mem(struct iscsi_iser_
+ enum iser_data_dir cmd_dir)
+ {
+ struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn;
++ struct iser_device *device = ib_conn->device;
+ struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
+ struct iser_regd_buf *regd_buf;
+ int aligned_len;
+ int err;
++ int i;
++ struct scatterlist *sg;
+
+ regd_buf = &iser_ctask->rdma_regd[cmd_dir];
+
+ aligned_len = iser_data_buf_aligned_len(mem);
+- if (aligned_len != mem->size) {
++ if (aligned_len != mem->dma_nents) {
+ iser_err("rdma alignment violation %d/%d aligned\n",
+ aligned_len, mem->size);
+ iser_data_buf_dump(mem);
++
++ /* unmap the command data before accessing it */
++ iser_dma_unmap_task_data(iser_ctask);
++
+ /* allocate copy buf, if we are writing, copy the */
+ /* unaligned scatterlist, dma map the copy */
+ if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
+@@ -389,10 +443,38 @@ int iser_reg_rdma_mem(struct iscsi_iser_
+ mem = &iser_ctask->data_copy[cmd_dir];
+ }
+
+- iser_page_vec_build(mem, ib_conn->page_vec);
+- err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, ®d_buf->reg);
+- if (err)
+- return err;
++ /* if there a single dma entry, FMR is not needed */
++ if (mem->dma_nents == 1) {
++ sg = (struct scatterlist *)mem->buf;
++
++ regd_buf->reg.lkey = device->mr->lkey;
++ regd_buf->reg.rkey = device->mr->rkey;
++ regd_buf->reg.len = sg_dma_len(&sg[0]);
++ regd_buf->reg.va = sg_dma_address(&sg[0]);
++ regd_buf->reg.is_fmr = 0;
++
++ iser_dbg("PHYSICAL Mem.register: lkey: 0x%08X rkey: 0x%08X "
++ "va: 0x%08lX sz: %ld]\n",
++ (unsigned int)regd_buf->reg.lkey,
++ (unsigned int)regd_buf->reg.rkey,
++ (unsigned long)regd_buf->reg.va,
++ (unsigned long)regd_buf->reg.len);
++ } else { /* use FMR for multiple dma entries */
++ iser_page_vec_build(mem, ib_conn->page_vec);
++ err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, ®d_buf->reg);
++ if (err) {
++ iser_data_buf_dump(mem);
++ iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
++ ntoh24(iser_ctask->desc.iscsi_header.dlength));
++ iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
++ ib_conn->page_vec->data_size, ib_conn->page_vec->length,
++ ib_conn->page_vec->offset);
++ for (i=0 ; i<ib_conn->page_vec->length ; i++)
++ iser_err("page_vec[%d] = 0x%llx\n", i,
++ (unsigned long long) ib_conn->page_vec->pages[i]);
++ return err;
++ }
++ }
+
+ /* take a reference on this regd buf such that it will not be released *
+ * (eg in send dto completion) before we get the scsi response */
+diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
+index 72febf1..18a0000 100644
+--- a/drivers/infiniband/ulp/iser/iser_verbs.c
++++ b/drivers/infiniband/ulp/iser/iser_verbs.c
+@@ -88,8 +88,9 @@ static int iser_create_device_ib_res(str
+ iser_cq_tasklet_fn,
+ (unsigned long)device);
+
+- device->mr = ib_get_dma_mr(device->pd,
+- IB_ACCESS_LOCAL_WRITE);
++ device->mr = ib_get_dma_mr(device->pd, IB_ACCESS_LOCAL_WRITE |
++ IB_ACCESS_REMOTE_WRITE |
++ IB_ACCESS_REMOTE_READ);
+ if (IS_ERR(device->mr))
+ goto dma_mr_err;
+
+@@ -150,7 +151,7 @@ static int iser_create_ib_conn_res(struc
+ }
+ ib_conn->page_vec->pages = (u64 *) (ib_conn->page_vec + 1);
+
+- params.page_shift = PAGE_SHIFT;
++ params.page_shift = SHIFT_4K;
+ /* when the first/last SG element are not start/end *
+ * page aligned, the map whould be of N+1 pages */
+ params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1;
+@@ -570,6 +571,8 @@ void iser_conn_release(struct iser_conn
+ /* on EVENT_ADDR_ERROR there's no device yet for this conn */
+ if (device != NULL)
+ iser_device_try_release(device);
++ if (ib_conn->iser_conn)
++ ib_conn->iser_conn->ib_conn = NULL;
+ kfree(ib_conn);
+ }
+
+@@ -604,8 +607,9 @@ int iser_reg_page_vec(struct iser_conn
+
+ mem_reg->lkey = mem->fmr->lkey;
+ mem_reg->rkey = mem->fmr->rkey;
+- mem_reg->len = page_vec->length * PAGE_SIZE;
++ mem_reg->len = page_vec->length * SIZE_4K;
+ mem_reg->va = io_addr;
++ mem_reg->is_fmr = 1;
+ mem_reg->mem_h = (void *)mem;
+
+ mem_reg->va += page_vec->offset;
+@@ -692,7 +696,7 @@ int iser_post_recv(struct iser_desc *rx_
+ struct iser_dto *recv_dto = &rx_desc->dto;
+
+ /* Retrieve conn */
+- ib_conn = recv_dto->conn->ib_conn;
++ ib_conn = recv_dto->ib_conn;
+
+ iser_dto_to_iov(recv_dto, iov, 2);
+
+@@ -725,7 +729,7 @@ int iser_post_send(struct iser_desc *tx_
+ struct iser_conn *ib_conn;
+ struct iser_dto *dto = &tx_desc->dto;
+
+- ib_conn = dto->conn->ib_conn;
++ ib_conn = dto->ib_conn;
+
+ iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN);
+
+@@ -772,7 +776,7 @@ static void iser_comp_error_worker(void
+ static void iser_handle_comp_error(struct iser_desc *desc)
+ {
+ struct iser_dto *dto = &desc->dto;
+- struct iser_conn *ib_conn = dto->conn->ib_conn;
++ struct iser_conn *ib_conn = dto->ib_conn;
+
+ iser_dto_buffs_release(dto);
+
+diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
+index fd8344c..4b09147 100644
+--- a/drivers/infiniband/ulp/srp/ib_srp.c
++++ b/drivers/infiniband/ulp/srp/ib_srp.c
+@@ -96,6 +96,8 @@ static struct ib_client srp_client = {
+ .remove = srp_remove_one
+ };
+
++static struct ib_sa_client srp_sa_client;
++
+ static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
+ {
+ return (struct srp_target_port *) host->hostdata;
+@@ -267,7 +269,8 @@ static int srp_lookup_path(struct srp_ta
+
+ init_completion(&target->done);
+
+- target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev->dev,
++ target->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
++ target->srp_host->dev->dev,
+ target->srp_host->port,
+ &target->path,
+ IB_SA_PATH_REC_DGID |
+@@ -330,7 +333,7 @@ static int srp_send_req(struct srp_targe
+ req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
+ SRP_BUF_FORMAT_INDIRECT);
+ /*
+- * In the published SRP specification (draft rev. 16a), the
++ * In the published SRP specification (draft rev. 16a), the
+ * port identifier format is 8 bytes of ID extension followed
+ * by 8 bytes of GUID. Older drafts put the two halves in the
+ * opposite order, so that the GUID comes first.
+@@ -340,29 +343,32 @@ static int srp_send_req(struct srp_targe
+ */
+ if (target->io_class == SRP_REV10_IB_IO_CLASS) {
+ memcpy(req->priv.initiator_port_id,
+- target->srp_host->initiator_port_id + 8, 8);
++ &target->path.sgid.global.interface_id, 8);
+ memcpy(req->priv.initiator_port_id + 8,
+- target->srp_host->initiator_port_id, 8);
++ &target->initiator_ext, 8);
+ memcpy(req->priv.target_port_id, &target->ioc_guid, 8);
+ memcpy(req->priv.target_port_id + 8, &target->id_ext, 8);
+ } else {
+ memcpy(req->priv.initiator_port_id,
+- target->srp_host->initiator_port_id, 16);
++ &target->initiator_ext, 8);
++ memcpy(req->priv.initiator_port_id + 8,
++ &target->path.sgid.global.interface_id, 8);
+ memcpy(req->priv.target_port_id, &target->id_ext, 8);
+ memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
+ }
+
+ /*
+ * Topspin/Cisco SRP targets will reject our login unless we
+- * zero out the first 8 bytes of our initiator port ID. The
+- * second 8 bytes must be our local node GUID, but we always
+- * use that anyway.
++ * zero out the first 8 bytes of our initiator port ID and set
++ * the second 8 bytes to the local node GUID.
+ */
+ if (topspin_workarounds && !memcmp(&target->ioc_guid, topspin_oui, 3)) {
+ printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
+ "activated for target GUID %016llx\n",
+ (unsigned long long) be64_to_cpu(target->ioc_guid));
+ memset(req->priv.initiator_port_id, 0, 8);
++ memcpy(req->priv.initiator_port_id + 8,
++ &target->srp_host->dev->dev->node_guid, 8);
+ }
+
+ status = ib_send_cm_req(target->cm_id, &req->param);
+@@ -1449,12 +1455,28 @@ static ssize_t show_zero_req_lim(struct
+ return sprintf(buf, "%d\n", target->zero_req_lim);
+ }
+
+-static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
+-static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
+-static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
+-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+-static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
+-static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
++static ssize_t show_local_ib_port(struct class_device *cdev, char *buf)
++{
++ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
++
++ return sprintf(buf, "%d\n", target->srp_host->port);
++}
++
++static ssize_t show_local_ib_device(struct class_device *cdev, char *buf)
++{
++ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
++
++ return sprintf(buf, "%s\n", target->srp_host->dev->dev->name);
++}
++
++static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
++static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
++static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
++static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
++static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
++static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
++static CLASS_DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
++static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
+
+ static struct class_device_attribute *srp_host_attrs[] = {
+ &class_device_attr_id_ext,
+@@ -1463,6 +1485,8 @@ static struct class_device_attribute *sr
+ &class_device_attr_pkey,
+ &class_device_attr_dgid,
+ &class_device_attr_zero_req_lim,
++ &class_device_attr_local_ib_port,
++ &class_device_attr_local_ib_device,
+ NULL
+ };
+
+@@ -1532,6 +1556,7 @@ enum {
+ SRP_OPT_MAX_SECT = 1 << 5,
+ SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
+ SRP_OPT_IO_CLASS = 1 << 7,
++ SRP_OPT_INITIATOR_EXT = 1 << 8,
+ SRP_OPT_ALL = (SRP_OPT_ID_EXT |
+ SRP_OPT_IOC_GUID |
+ SRP_OPT_DGID |
+@@ -1548,6 +1573,7 @@ static match_table_t srp_opt_tokens = {
+ { SRP_OPT_MAX_SECT, "max_sect=%d" },
+ { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" },
+ { SRP_OPT_IO_CLASS, "io_class=%x" },
++ { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" },
+ { SRP_OPT_ERR, NULL }
+ };
+
+@@ -1647,6 +1673,12 @@ static int srp_parse_options(const char
+ target->io_class = token;
+ break;
+
++ case SRP_OPT_INITIATOR_EXT:
++ p = match_strdup(args);
++ target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16));
++ kfree(p);
++ break;
++
+ default:
+ printk(KERN_WARNING PFX "unknown parameter or missing value "
+ "'%s' in target creation request\n", p);
+@@ -1687,7 +1719,6 @@ static ssize_t srp_create_target(struct
+ target_host->max_lun = SRP_MAX_LUN;
+
+ target = host_to_target(target_host);
+- memset(target, 0, sizeof *target);
+
+ target->io_class = SRP_REV16A_IB_IO_CLASS;
+ target->scsi_host = target_host;
+@@ -1794,9 +1825,6 @@ static struct srp_host *srp_add_port(str
+ host->dev = device;
+ host->port = port;
+
+- host->initiator_port_id[7] = port;
+- memcpy(host->initiator_port_id + 8, &device->dev->node_guid, 8);
+-
+ host->class_dev.class = &srp_class;
+ host->class_dev.dev = device->dev->dma_device;
+ snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d",
+@@ -1881,7 +1909,7 @@ static void srp_add_one(struct ib_device
+ if (IS_ERR(srp_dev->fmr_pool))
+ srp_dev->fmr_pool = NULL;
+
+- if (device->node_type == IB_NODE_SWITCH) {
++ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ s = 0;
+ e = 0;
+ } else {
+@@ -1980,9 +2008,12 @@ static int __init srp_init_module(void)
+ return ret;
+ }
+
++ ib_sa_register_client(&srp_sa_client);
++
+ ret = ib_register_client(&srp_client);
+ if (ret) {
+ printk(KERN_ERR PFX "couldn't register IB client\n");
++ ib_sa_unregister_client(&srp_sa_client);
+ class_unregister(&srp_class);
+ return ret;
+ }
+@@ -1993,6 +2024,7 @@ static int __init srp_init_module(void)
+ static void __exit srp_cleanup_module(void)
+ {
+ ib_unregister_client(&srp_client);
++ ib_sa_unregister_client(&srp_sa_client);
+ class_unregister(&srp_class);
+ }
+
+diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
+index 5b581fb..d4e35ef 100644
+--- a/drivers/infiniband/ulp/srp/ib_srp.h
++++ b/drivers/infiniband/ulp/srp/ib_srp.h
+@@ -91,7 +91,6 @@ struct srp_device {
+ };
+
+ struct srp_host {
+- u8 initiator_port_id[16];
+ struct srp_device *dev;
+ u8 port;
+ struct class_device class_dev;
+@@ -122,6 +121,7 @@ struct srp_target_port {
+ __be64 id_ext;
+ __be64 ioc_guid;
+ __be64 service_id;
++ __be64 initiator_ext;
+ u16 io_class;
+ struct srp_host *srp_host;
+ struct Scsi_Host *scsi_host;
+diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
+index 58223b5..9623231 100644
+--- a/drivers/input/Kconfig
++++ b/drivers/input/Kconfig
+@@ -24,6 +24,20 @@ config INPUT
+
+ if INPUT
+
++config INPUT_FF_MEMLESS
++ tristate "Support for memoryless force-feedback devices"
++ default n
++ ---help---
++ Say Y here if you have memoryless force-feedback input device
++ such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual
++ Power 2, or similar. You will also need to enable hardware-specific
++ driver.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called ff-memless.
++
+ comment "Userland interfaces"
+
+ config INPUT_MOUSEDEV
+diff --git a/drivers/input/Makefile b/drivers/input/Makefile
+index 1a6ff49..a005b1d 100644
+--- a/drivers/input/Makefile
++++ b/drivers/input/Makefile
+@@ -4,7 +4,11 @@
+
+ # Each configuration option enables a list of files.
+
+-obj-$(CONFIG_INPUT) += input.o
++obj-$(CONFIG_INPUT) += input-core.o
++input-core-objs := input.o ff-core.o
++
++obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
++
+ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
+ obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
+ obj-$(CONFIG_INPUT_EVDEV) += evdev.o
+diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
+index 07358fb..5a9653c 100644
+--- a/drivers/input/evbug.c
++++ b/drivers/input/evbug.c
+@@ -42,10 +42,12 @@ static char evbug_name[] = "evbug";
+
+ static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+ {
+- printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
++ printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
++ handle->dev->phys, type, code, value);
+ }
+
+-static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
++static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
++ const struct input_device_id *id)
+ {
+ struct input_handle *handle;
+
+@@ -72,7 +74,7 @@ static void evbug_disconnect(struct inpu
+ kfree(handle);
+ }
+
+-static struct input_device_id evbug_ids[] = {
++static const struct input_device_id evbug_ids[] = {
+ { .driver_info = 1 }, /* Matches all devices */
+ { }, /* Terminating zero entry */
+ };
+@@ -89,8 +91,7 @@ static struct input_handler evbug_handle
+
+ static int __init evbug_init(void)
+ {
+- input_register_handler(&evbug_handler);
+- return 0;
++ return input_register_handler(&evbug_handler);
+ }
+
+ static void __exit evbug_exit(void)
+diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
+index 4bf4818..6439f37 100644
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct f
+ struct evdev *evdev = list->evdev;
+ struct input_dev *dev = evdev->handle.dev;
+ struct input_absinfo abs;
++ struct ff_effect effect;
+ int __user *ip = (int __user *)p;
+ int i, t, u, v;
++ int error;
+
+ if (!evdev->exist)
+ return -ENODEV;
+@@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct f
+ return 0;
+
+ case EVIOCSFF:
+- if (dev->upload_effect) {
+- struct ff_effect effect;
+- int err;
+-
+- if (copy_from_user(&effect, p, sizeof(effect)))
+- return -EFAULT;
+- err = dev->upload_effect(dev, &effect);
+- if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+- return -EFAULT;
+- return err;
+- } else
+- return -ENOSYS;
++ if (copy_from_user(&effect, p, sizeof(effect)))
++ return -EFAULT;
+
+- case EVIOCRMFF:
+- if (!dev->erase_effect)
+- return -ENOSYS;
++ error = input_ff_upload(dev, &effect, file);
+
+- return dev->erase_effect(dev, (int)(unsigned long) p);
++ if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
++ return -EFAULT;
++
++ return error;
++
++ case EVIOCRMFF:
++ return input_ff_erase(dev, (int)(unsigned long) p, file);
+
+ case EVIOCGEFFECTS:
+- if (put_user(dev->ff_effects_max, ip))
++ i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
++ if (put_user(i, ip))
+ return -EFAULT;
+ return 0;
+
+@@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct fi
+ }
+ #endif
+
+-static struct file_operations evdev_fops = {
++static const struct file_operations evdev_fops = {
+ .owner = THIS_MODULE,
+ .read = evdev_read,
+ .write = evdev_write,
+@@ -619,7 +616,8 @@ static struct file_operations evdev_fops
+ .flush = evdev_flush
+ };
+
+-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
++static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
++ const struct input_device_id *id)
+ {
+ struct evdev *evdev;
+ struct class_device *cdev;
+@@ -669,6 +667,7 @@ static void evdev_disconnect(struct inpu
+ evdev->exist = 0;
+
+ if (evdev->open) {
++ input_flush_device(handle, NULL);
+ input_close_device(handle);
+ wake_up_interruptible(&evdev->wait);
+ list_for_each_entry(list, &evdev->list, node)
+@@ -677,7 +676,7 @@ static void evdev_disconnect(struct inpu
+ evdev_free(evdev);
+ }
+
+-static struct input_device_id evdev_ids[] = {
++static const struct input_device_id evdev_ids[] = {
+ { .driver_info = 1 }, /* Matches all devices */
+ { }, /* Terminating zero entry */
+ };
+@@ -696,8 +695,7 @@ static struct input_handler evdev_handle
+
+ static int __init evdev_init(void)
+ {
+- input_register_handler(&evdev_handler);
+- return 0;
++ return input_register_handler(&evdev_handler);
+ }
+
+ static void __exit evdev_exit(void)
+diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
+new file mode 100644
+index 0000000..35656ca
+--- /dev/null
++++ b/drivers/input/ff-core.c
+@@ -0,0 +1,367 @@
++/*
++ * Force feedback support for Linux input subsystem
++ *
++ * Copyright (c) 2006 Anssi Hannula <anssi.hannula at gmail.com>
++ * Copyright (c) 2006 Dmitry Torokhov <dtor at 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
++ */
++
++/* #define DEBUG */
++
++#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg)
++
++#include <linux/input.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++
++/*
++ * Check that the effect_id is a valid effect and whether the user
++ * is the owner
++ */
++static int check_effect_access(struct ff_device *ff, int effect_id,
++ struct file *file)
++{
++ if (effect_id < 0 || effect_id >= ff->max_effects ||
++ !ff->effect_owners[effect_id])
++ return -EINVAL;
++
++ if (file && ff->effect_owners[effect_id] != file)
++ return -EACCES;
++
++ return 0;
++}
++
++/*
++ * Checks whether 2 effects can be combined together
++ */
++static inline int check_effects_compatible(struct ff_effect *e1,
++ struct ff_effect *e2)
++{
++ return e1->type == e2->type &&
++ (e1->type != FF_PERIODIC ||
++ e1->u.periodic.waveform == e2->u.periodic.waveform);
++}
++
++/*
++ * Convert an effect into compatible one
++ */
++static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
++{
++ int magnitude;
++
++ switch (effect->type) {
++ case FF_RUMBLE:
++ if (!test_bit(FF_PERIODIC, ff->ffbit))
++ return -EINVAL;
++
++ /*
++ * calculate manginude of sine wave as average of rumble's
++ * 2/3 of strong magnitude and 1/3 of weak magnitude
++ */
++ magnitude = effect->u.rumble.strong_magnitude / 3 +
++ effect->u.rumble.weak_magnitude / 6;
++
++ effect->type = FF_PERIODIC;
++ effect->u.periodic.waveform = FF_SINE;
++ effect->u.periodic.period = 50;
++ effect->u.periodic.magnitude = max(magnitude, 0x7fff);
++ effect->u.periodic.offset = 0;
++ effect->u.periodic.phase = 0;
++ effect->u.periodic.envelope.attack_length = 0;
++ effect->u.periodic.envelope.attack_level = 0;
++ effect->u.periodic.envelope.fade_length = 0;
++ effect->u.periodic.envelope.fade_level = 0;
++
++ return 0;
++
++ default:
++ /* Let driver handle conversion */
++ return 0;
++ }
++}
++
++/**
++ * input_ff_upload() - upload effect into force-feedback device
++ * @dev: input device
++ * @effect: effect to be uploaded
++ * @file: owner of the effect
++ */
++int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
++ struct file *file)
++{
++ struct ff_device *ff = dev->ff;
++ struct ff_effect *old;
++ int ret = 0;
++ int id;
++
++ if (!test_bit(EV_FF, dev->evbit))
++ return -ENOSYS;
++
++ if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
++ !test_bit(effect->type, dev->ffbit)) {
++ debug("invalid or not supported effect type in upload");
++ return -EINVAL;
++ }
++
++ if (effect->type == FF_PERIODIC &&
++ (effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
++ effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
++ !test_bit(effect->u.periodic.waveform, dev->ffbit))) {
++ debug("invalid or not supported wave form in upload");
++ return -EINVAL;
++ }
++
++ if (!test_bit(effect->type, ff->ffbit)) {
++ ret = compat_effect(ff, effect);
++ if (ret)
++ return ret;
++ }
++
++ mutex_lock(&ff->mutex);
++
++ if (effect->id == -1) {
++ for (id = 0; id < ff->max_effects; id++)
++ if (!ff->effect_owners[id])
++ break;
++
++ if (id >= ff->max_effects) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ effect->id = id;
++ old = NULL;
++
++ } else {
++ id = effect->id;
++
++ ret = check_effect_access(ff, id, file);
++ if (ret)
++ goto out;
++
++ old = &ff->effects[id];
++
++ if (!check_effects_compatible(effect, old)) {
++ ret = -EINVAL;
++ goto out;
++ }
++ }
++
++ ret = ff->upload(dev, effect, old);
++ if (ret)
++ goto out;
++
++ ff->effects[id] = *effect;
++ ff->effect_owners[id] = file;
++
++ out:
++ mutex_unlock(&ff->mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(input_ff_upload);
++
++/*
++ * Erases the effect if the requester is also the effect owner. The mutex
++ * should already be locked before calling this function.
++ */
++static int erase_effect(struct input_dev *dev, int effect_id,
++ struct file *file)
++{
++ struct ff_device *ff = dev->ff;
++ int error;
++
++ error = check_effect_access(ff, effect_id, file);
++ if (error)
++ return error;
++
++ ff->playback(dev, effect_id, 0);
++
++ if (ff->erase) {
++ error = ff->erase(dev, effect_id);
++ if (error)
++ return error;
++ }
++
++ ff->effect_owners[effect_id] = NULL;
++
++ return 0;
++}
++
++/**
++ * input_ff_erase - erase an effect from device
++ * @dev: input device to erase effect from
++ * @effect_id: id of the ffect to be erased
++ * @file: purported owner of the request
++ *
++ * This function erases a force-feedback effect from specified device.
++ * The effect will only be erased if it was uploaded through the same
++ * file handle that is requesting erase.
++ */
++int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
++{
++ struct ff_device *ff = dev->ff;
++ int ret;
++
++ if (!test_bit(EV_FF, dev->evbit))
++ return -ENOSYS;
++
++ mutex_lock(&ff->mutex);
++ ret = erase_effect(dev, effect_id, file);
++ mutex_unlock(&ff->mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(input_ff_erase);
++
++/*
++ * flush_effects - erase all effects owned by a file handle
++ */
++static int flush_effects(struct input_dev *dev, struct file *file)
++{
++ struct ff_device *ff = dev->ff;
++ int i;
++
++ debug("flushing now");
++
++ mutex_lock(&ff->mutex);
++
++ for (i = 0; i < ff->max_effects; i++)
++ erase_effect(dev, i, file);
++
++ mutex_unlock(&ff->mutex);
++
++ return 0;
++}
++
++/**
++ * input_ff_event() - generic handler for force-feedback events
++ * @dev: input device to send the effect to
++ * @type: event type (anything but EV_FF is ignored)
++ * @code: event code
++ * @value: event value
++ */
++int input_ff_event(struct input_dev *dev, unsigned int type,
++ unsigned int code, int value)
++{
++ struct ff_device *ff = dev->ff;
++
++ if (type != EV_FF)
++ return 0;
++
++ mutex_lock(&ff->mutex);
++
++ switch (code) {
++ case FF_GAIN:
++ if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
++ break;
++
++ ff->set_gain(dev, value);
++ break;
++
++ case FF_AUTOCENTER:
++ if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff)
++ break;
++
++ ff->set_autocenter(dev, value);
++ break;
++
++ default:
++ ff->playback(dev, code, value);
++ break;
++ }
++
++ mutex_unlock(&ff->mutex);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(input_ff_event);
++
++/**
++ * input_ff_create() - create force-feedback device
++ * @dev: input device supporting force-feedback
++ * @max_effects: maximum number of effects supported by the device
++ *
++ * This function allocates all necessary memory for a force feedback
++ * portion of an input device and installs all default handlers.
++ * @dev->ffbit should be already set up before calling this function.
++ * Once ff device is created you need to setup its upload, erase,
++ * playback and other handlers before registering input device
++ */
++int input_ff_create(struct input_dev *dev, int max_effects)
++{
++ struct ff_device *ff;
++ int i;
++
++ if (!max_effects) {
++ printk(KERN_ERR
++ "ff-core: cannot allocate device without any effects\n");
++ return -EINVAL;
++ }
++
++ ff = kzalloc(sizeof(struct ff_device) +
++ max_effects * sizeof(struct file *), GFP_KERNEL);
++ if (!ff)
++ return -ENOMEM;
++
++ ff->effects = kcalloc(max_effects, sizeof(struct ff_effect),
++ GFP_KERNEL);
++ if (!ff->effects) {
++ kfree(ff);
++ return -ENOMEM;
++ }
++
++ ff->max_effects = max_effects;
++ mutex_init(&ff->mutex);
++
++ dev->ff = ff;
++ dev->flush = flush_effects;
++ dev->event = input_ff_event;
++ set_bit(EV_FF, dev->evbit);
++
++ /* Copy "true" bits into ff device bitmap */
++ for (i = 0; i <= FF_MAX; i++)
++ if (test_bit(i, dev->ffbit))
++ set_bit(i, ff->ffbit);
++
++ /* we can emulate RUMBLE with periodic effects */
++ if (test_bit(FF_PERIODIC, ff->ffbit))
++ set_bit(FF_RUMBLE, dev->ffbit);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(input_ff_create);
++
++/**
++ * input_ff_free() - frees force feedback portion of input device
++ * @dev: input device supporintg force feedback
++ *
++ * This function is only needed in error path as input core will
++ * automatically free force feedback structures when device is
++ * destroyed.
++ */
++void input_ff_destroy(struct input_dev *dev)
++{
++ clear_bit(EV_FF, dev->evbit);
++ if (dev->ff) {
++ if (dev->ff->destroy)
++ dev->ff->destroy(dev->ff);
++ kfree(dev->ff->private);
++ kfree(dev->ff);
++ dev->ff = NULL;
++ }
++}
++EXPORT_SYMBOL_GPL(input_ff_destroy);
+diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
+new file mode 100644
+index 0000000..cd8b729
+--- /dev/null
++++ b/drivers/input/ff-memless.c
+@@ -0,0 +1,515 @@
++/*
++ * Force feedback support for memoryless devices
++ *
++ * Copyright (c) 2006 Anssi Hannula <anssi.hannula at gmail.com>
++ * Copyright (c) 2006 Dmitry Torokhov <dtor at 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
++ */
++
++/* #define DEBUG */
++
++#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg)
++
++#include <linux/input.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++
++#include "fixp-arith.h"
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Anssi Hannula <anssi.hannula at gmail.com>");
++MODULE_DESCRIPTION("Force feedback support for memoryless devices");
++
++/* Number of effects handled with memoryless devices */
++#define FF_MEMLESS_EFFECTS 16
++
++/* Envelope update interval in ms */
++#define FF_ENVELOPE_INTERVAL 50
++
++#define FF_EFFECT_STARTED 0
++#define FF_EFFECT_PLAYING 1
++#define FF_EFFECT_ABORTING 2
++
++struct ml_effect_state {
++ struct ff_effect *effect;
++ unsigned long flags; /* effect state (STARTED, PLAYING, etc) */
++ int count; /* loop count of the effect */
++ unsigned long play_at; /* start time */
++ unsigned long stop_at; /* stop time */
++ unsigned long adj_at; /* last time the effect was sent */
++};
++
++struct ml_device {
++ void *private;
++ struct ml_effect_state states[FF_MEMLESS_EFFECTS];
++ int gain;
++ struct timer_list timer;
++ spinlock_t timer_lock;
++ struct input_dev *dev;
++
++ int (*play_effect)(struct input_dev *dev, void *data,
++ struct ff_effect *effect);
++};
++
++static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
++{
++ static const struct ff_envelope empty_envelope;
++
++ switch (effect->type) {
++ case FF_PERIODIC:
++ return &effect->u.periodic.envelope;
++ case FF_CONSTANT:
++ return &effect->u.constant.envelope;
++ default:
++ return &empty_envelope;
++ }
++}
++
++/*
++ * Check for the next time envelope requires an update on memoryless devices
++ */
++static unsigned long calculate_next_time(struct ml_effect_state *state)
++{
++ const struct ff_envelope *envelope = get_envelope(state->effect);
++ unsigned long attack_stop, fade_start, next_fade;
++
++ if (envelope->attack_length) {
++ attack_stop = state->play_at +
++ msecs_to_jiffies(envelope->attack_length);
++ if (time_before(state->adj_at, attack_stop))
++ return state->adj_at +
++ msecs_to_jiffies(FF_ENVELOPE_INTERVAL);
++ }
++
++ if (state->effect->replay.length) {
++ if (envelope->fade_length) {
++ /* check when fading should start */
++ fade_start = state->stop_at -
++ msecs_to_jiffies(envelope->fade_length);
++
++ if (time_before(state->adj_at, fade_start))
++ return fade_start;
++
++ /* already fading, advance to next checkpoint */
++ next_fade = state->adj_at +
++ msecs_to_jiffies(FF_ENVELOPE_INTERVAL);
++ if (time_before(next_fade, state->stop_at))
++ return next_fade;
++ }
++
++ return state->stop_at;
++ }
++
++ return state->play_at;
++}
++
++static void ml_schedule_timer(struct ml_device *ml)
++{
++ struct ml_effect_state *state;
++ unsigned long now = jiffies;
++ unsigned long earliest = 0;
++ unsigned long next_at;
++ int events = 0;
++ int i;
++
++ debug("calculating next timer");
++
++ for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
++
++ state = &ml->states[i];
++
++ if (!test_bit(FF_EFFECT_STARTED, &state->flags))
++ continue;
++
++ if (test_bit(FF_EFFECT_PLAYING, &state->flags))
++ next_at = calculate_next_time(state);
++ else
++ next_at = state->play_at;
++
++ if (time_before_eq(now, next_at) &&
++ (++events == 1 || time_before(next_at, earliest)))
++ earliest = next_at;
++ }
++
++ if (!events) {
++ debug("no actions");
++ del_timer(&ml->timer);
++ } else {
++ debug("timer set");
++ mod_timer(&ml->timer, earliest);
++ }
++}
++
++/*
++ * Apply an envelope to a value
++ */
++static int apply_envelope(struct ml_effect_state *state, int value,
++ struct ff_envelope *envelope)
++{
++ struct ff_effect *effect = state->effect;
++ unsigned long now = jiffies;
++ int time_from_level;
++ int time_of_envelope;
++ int envelope_level;
++ int difference;
++
++ if (envelope->attack_length &&
++ time_before(now,
++ state->play_at + msecs_to_jiffies(envelope->attack_length))) {
++ debug("value = 0x%x, attack_level = 0x%x", value,
++ envelope->attack_level);
++ time_from_level = jiffies_to_msecs(now - state->play_at);
++ time_of_envelope = envelope->attack_length;
++ envelope_level = min_t(__s16, envelope->attack_level, 0x7fff);
++
++ } else if (envelope->fade_length && effect->replay.length &&
++ time_after(now,
++ state->stop_at - msecs_to_jiffies(envelope->fade_length)) &&
++ time_before(now, state->stop_at)) {
++ time_from_level = jiffies_to_msecs(state->stop_at - now);
++ time_of_envelope = envelope->fade_length;
++ envelope_level = min_t(__s16, envelope->fade_level, 0x7fff);
++ } else
++ return value;
++
++ difference = abs(value) - envelope_level;
++
++ debug("difference = %d", difference);
++ debug("time_from_level = 0x%x", time_from_level);
++ debug("time_of_envelope = 0x%x", time_of_envelope);
++
++ difference = difference * time_from_level / time_of_envelope;
++
++ debug("difference = %d", difference);
++
++ return value < 0 ?
++ -(difference + envelope_level) : (difference + envelope_level);
++}
++
++/*
++ * Return the type the effect has to be converted into (memless devices)
++ */
++static int get_compatible_type(struct ff_device *ff, int effect_type)
++{
++
++ if (test_bit(effect_type, ff->ffbit))
++ return effect_type;
++
++ if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit))
++ return FF_RUMBLE;
++
++ printk(KERN_ERR
++ "ff-memless: invalid type in get_compatible_type()\n");
++
++ return 0;
++}
++
++/*
++ * Combine two effects and apply gain.
++ */
++static void ml_combine_effects(struct ff_effect *effect,
++ struct ml_effect_state *state,
++ int gain)
++{
++ struct ff_effect *new = state->effect;
++ unsigned int strong, weak, i;
++ int x, y;
++ fixp_t level;
++
++ switch (new->type) {
++ case FF_CONSTANT:
++ i = new->direction * 360 / 0xffff;
++ level = fixp_new16(apply_envelope(state,
++ new->u.constant.level,
++ &new->u.constant.envelope));
++ x = fixp_mult(fixp_sin(i), level) * gain / 0xffff;
++ y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff;
++ /*
++ * here we abuse ff_ramp to hold x and y of constant force
++ * If in future any driver wants something else than x and y
++ * in s8, this should be changed to something more generic
++ */
++ effect->u.ramp.start_level =
++ max(min(effect->u.ramp.start_level + x, 0x7f), -0x80);
++ effect->u.ramp.end_level =
++ max(min(effect->u.ramp.end_level + y, 0x7f), -0x80);
++ break;
++
++ case FF_RUMBLE:
++ strong = new->u.rumble.strong_magnitude * gain / 0xffff;
++ weak = new->u.rumble.weak_magnitude * gain / 0xffff;
++ effect->u.rumble.strong_magnitude =
++ min(strong + effect->u.rumble.strong_magnitude,
++ 0xffffU);
++ effect->u.rumble.weak_magnitude =
++ min(weak + effect->u.rumble.weak_magnitude, 0xffffU);
++ break;
++
++ case FF_PERIODIC:
++ i = apply_envelope(state, abs(new->u.periodic.magnitude),
++ &new->u.periodic.envelope);
++
++ /* here we also scale it 0x7fff => 0xffff */
++ i = i * gain / 0x7fff;
++
++ effect->u.rumble.strong_magnitude =
++ min(i + effect->u.rumble.strong_magnitude, 0xffffU);
++ effect->u.rumble.weak_magnitude =
++ min(i + effect->u.rumble.weak_magnitude, 0xffffU);
++ break;
++
++ default:
++ printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n");
++ break;
++ }
++
++}
++
++
++/*
++ * Because memoryless devices have only one effect per effect type active
++ * at one time we have to combine multiple effects into one
++ */
++static int ml_get_combo_effect(struct ml_device *ml,
++ unsigned long *effect_handled,
++ struct ff_effect *combo_effect)
++{
++ struct ff_effect *effect;
++ struct ml_effect_state *state;
++ int effect_type;
++ int i;
++
++ memset(combo_effect, 0, sizeof(struct ff_effect));
++
++ for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
++ if (__test_and_set_bit(i, effect_handled))
++ continue;
++
++ state = &ml->states[i];
++ effect = state->effect;
++
++ if (!test_bit(FF_EFFECT_STARTED, &state->flags))
++ continue;
++
++ if (time_before(jiffies, state->play_at))
++ continue;
++
++ /*
++ * here we have started effects that are either
++ * currently playing (and may need be aborted)
++ * or need to start playing.
++ */
++ effect_type = get_compatible_type(ml->dev->ff, effect->type);
++ if (combo_effect->type != effect_type) {
++ if (combo_effect->type != 0) {
++ __clear_bit(i, effect_handled);
++ continue;
++ }
++ combo_effect->type = effect_type;
++ }
++
++ if (__test_and_clear_bit(FF_EFFECT_ABORTING, &state->flags)) {
++ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
++ __clear_bit(FF_EFFECT_STARTED, &state->flags);
++ } else if (effect->replay.length &&
++ time_after_eq(jiffies, state->stop_at)) {
++
++ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
++
++ if (--state->count <= 0) {
++ __clear_bit(FF_EFFECT_STARTED, &state->flags);
++ } else {
++ state->play_at = jiffies +
++ msecs_to_jiffies(effect->replay.delay);
++ state->stop_at = state->play_at +
++ msecs_to_jiffies(effect->replay.length);
++ }
++ } else {
++ __set_bit(FF_EFFECT_PLAYING, &state->flags);
++ state->adj_at = jiffies;
++ ml_combine_effects(combo_effect, state, ml->gain);
++ }
++ }
++
++ return combo_effect->type != 0;
++}
++
++static void ml_play_effects(struct ml_device *ml)
++{
++ struct ff_effect effect;
++ DECLARE_BITMAP(handled_bm, FF_MEMLESS_EFFECTS);
++
++ memset(handled_bm, 0, sizeof(handled_bm));
++
++ while (ml_get_combo_effect(ml, handled_bm, &effect))
++ ml->play_effect(ml->dev, ml->private, &effect);
++
++ ml_schedule_timer(ml);
++}
++
++static void ml_effect_timer(unsigned long timer_data)
++{
++ struct input_dev *dev = (struct input_dev *)timer_data;
++ struct ml_device *ml = dev->ff->private;
++
++ debug("timer: updating effects");
++
++ spin_lock(&ml->timer_lock);
++ ml_play_effects(ml);
++ spin_unlock(&ml->timer_lock);
++}
++
++static void ml_ff_set_gain(struct input_dev *dev, u16 gain)
++{
++ struct ml_device *ml = dev->ff->private;
++ int i;
++
++ spin_lock_bh(&ml->timer_lock);
++
++ ml->gain = gain;
++
++ for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
++ __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags);
++
++ ml_play_effects(ml);
++
++ spin_unlock_bh(&ml->timer_lock);
++}
++
++static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
++{
++ struct ml_device *ml = dev->ff->private;
++ struct ml_effect_state *state = &ml->states[effect_id];
++
++ spin_lock_bh(&ml->timer_lock);
++
++ if (value > 0) {
++ debug("initiated play");
++
++ __set_bit(FF_EFFECT_STARTED, &state->flags);
++ state->count = value;
++ state->play_at = jiffies +
++ msecs_to_jiffies(state->effect->replay.delay);
++ state->stop_at = state->play_at +
++ msecs_to_jiffies(state->effect->replay.length);
++ state->adj_at = state->play_at;
++
++ ml_schedule_timer(ml);
++
++ } else {
++ debug("initiated stop");
++
++ if (test_bit(FF_EFFECT_PLAYING, &state->flags))
++ __set_bit(FF_EFFECT_ABORTING, &state->flags);
++ else
++ __clear_bit(FF_EFFECT_STARTED, &state->flags);
++
++ ml_play_effects(ml);
++ }
++
++ spin_unlock_bh(&ml->timer_lock);
++
++ return 0;
++}
++
++static int ml_ff_upload(struct input_dev *dev,
++ struct ff_effect *effect, struct ff_effect *old)
++{
++ struct ml_device *ml = dev->ff->private;
++ struct ml_effect_state *state = &ml->states[effect->id];
++
++ spin_lock_bh(&ml->timer_lock);
++
++ if (test_bit(FF_EFFECT_STARTED, &state->flags)) {
++ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
++ state->play_at = jiffies +
++ msecs_to_jiffies(state->effect->replay.delay);
++ state->stop_at = state->play_at +
++ msecs_to_jiffies(state->effect->replay.length);
++ state->adj_at = state->play_at;
++ ml_schedule_timer(ml);
++ }
++
++ spin_unlock_bh(&ml->timer_lock);
++
++ return 0;
++}
++
++static void ml_ff_destroy(struct ff_device *ff)
++{
++ struct ml_device *ml = ff->private;
++
++ kfree(ml->private);
++}
++
++/**
++ * input_ff_create_memless() - create memoryless FF device
++ * @dev: input device supporting force-feedback
++ * @data: driver-specific data to be passed into @play_effect
++ * @play_effect: driver-specific method for playing FF effect
++ */
++int input_ff_create_memless(struct input_dev *dev, void *data,
++ int (*play_effect)(struct input_dev *, void *, struct ff_effect *))
++{
++ struct ml_device *ml;
++ struct ff_device *ff;
++ int error;
++ int i;
++
++ ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL);
++ if (!ml)
++ return -ENOMEM;
++
++ ml->dev = dev;
++ ml->private = data;
++ ml->play_effect = play_effect;
++ ml->gain = 0xffff;
++ spin_lock_init(&ml->timer_lock);
++ setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
++
++ set_bit(FF_GAIN, dev->ffbit);
++
++ error = input_ff_create(dev, FF_MEMLESS_EFFECTS);
++ if (error) {
++ kfree(ml);
++ return error;
++ }
++
++ ff = dev->ff;
++ ff->private = ml;
++ ff->upload = ml_ff_upload;
++ ff->playback = ml_ff_playback;
++ ff->set_gain = ml_ff_set_gain;
++ ff->destroy = ml_ff_destroy;
++
++ /* we can emulate periodic effects with RUMBLE */
++ if (test_bit(FF_RUMBLE, ff->ffbit)) {
++ set_bit(FF_PERIODIC, dev->ffbit);
++ set_bit(FF_SINE, dev->ffbit);
++ set_bit(FF_TRIANGLE, dev->ffbit);
++ set_bit(FF_SQUARE, dev->ffbit);
++ }
++
++ for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
++ ml->states[i].effect = &ff->effects[i];
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(input_ff_create_memless);
+diff --git a/drivers/input/fixp-arith.h b/drivers/input/fixp-arith.h
+new file mode 100644
+index 0000000..ed3d2da
+--- /dev/null
++++ b/drivers/input/fixp-arith.h
+@@ -0,0 +1,87 @@
++#ifndef _FIXP_ARITH_H
++#define _FIXP_ARITH_H
++
++/*
++ * Simplistic fixed-point arithmetics.
++ * Hmm, I'm probably duplicating some code :(
++ *
++ * Copyright (c) 2002 Johann Deneux
++ */
++
++/*
++ * 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 by
++ * e-mail - mail your message to <deneux at ifrance.com>
++ */
++
++#include <linux/types.h>
++
++/* The type representing fixed-point values */
++typedef s16 fixp_t;
++
++#define FRAC_N 8
++#define FRAC_MASK ((1<<FRAC_N)-1)
++
++/* Not to be used directly. Use fixp_{cos,sin} */
++static const fixp_t cos_table[46] = {
++ 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8,
++ 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD,
++ 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1,
++ 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078,
++ 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035,
++ 0x002C, 0x0023, 0x001A, 0x0011, 0x0008, 0x0000
++};
++
++
++/* a: 123 -> 123.0 */
++static inline fixp_t fixp_new(s16 a)
++{
++ return a<<FRAC_N;
++}
++
++/* a: 0xFFFF -> -1.0
++ 0x8000 -> 1.0
++ 0x0000 -> 0.0
++*/
++static inline fixp_t fixp_new16(s16 a)
++{
++ return ((s32)a)>>(16-FRAC_N);
++}
++
++static inline fixp_t fixp_cos(unsigned int degrees)
++{
++ int quadrant = (degrees / 90) & 3;
++ unsigned int i = degrees % 90;
++
++ if (quadrant == 1 || quadrant == 3)
++ i = 90 - i;
++
++ i >>= 1;
++
++ return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i];
++}
++
++static inline fixp_t fixp_sin(unsigned int degrees)
++{
++ return -fixp_cos(degrees + 90);
++}
++
++static inline fixp_t fixp_mult(fixp_t a, fixp_t b)
++{
++ return ((s32)(a*b))>>FRAC_N;
++}
++
++#endif
+diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
+index 90de5af..1dec00e 100644
+--- a/drivers/input/gameport/fm801-gp.c
++++ b/drivers/input/gameport/fm801-gp.c
+@@ -82,17 +82,19 @@ static int __devinit fm801_gp_probe(stru
+ {
+ struct fm801_gp *gp;
+ struct gameport *port;
++ int error;
+
+ gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
+ port = gameport_allocate_port();
+ if (!gp || !port) {
+ printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
+- kfree(gp);
+- gameport_free_port(port);
+- return -ENOMEM;
++ error = -ENOMEM;
++ goto err_out_free;
+ }
+
+- pci_enable_device(pci);
++ error = pci_enable_device(pci);
++ if (error)
++ goto err_out_free;
+
+ port->open = fm801_gp_open;
+ #ifdef HAVE_COOKED
+@@ -108,9 +110,8 @@ static int __devinit fm801_gp_probe(stru
+ if (!gp->res_port) {
+ printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
+ port->io, port->io + 0x0f);
+- gameport_free_port(port);
+- kfree(gp);
+- return -EBUSY;
++ error = -EBUSY;
++ goto err_out_disable_dev;
+ }
+
+ pci_set_drvdata(pci, gp);
+@@ -119,6 +120,13 @@ static int __devinit fm801_gp_probe(stru
+ gameport_register_port(port);
+
+ return 0;
++
++ err_out_disable_dev:
++ pci_disable_device(pci);
++ err_out_free:
++ gameport_free_port(port);
++ kfree(gp);
++ return error;
+ }
+
+ static void __devexit fm801_gp_remove(struct pci_dev *pci)
+diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
+index 3f47ae5..a0af97e 100644
+--- a/drivers/input/gameport/gameport.c
++++ b/drivers/input/gameport/gameport.c
+@@ -191,6 +191,8 @@ static void gameport_run_poll_handler(un
+
+ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
+ {
++ int error;
++
+ down_write(&gameport_bus.subsys.rwsem);
+
+ gameport->dev.driver = &drv->driver;
+@@ -198,8 +200,20 @@ static void gameport_bind_driver(struct
+ gameport->dev.driver = NULL;
+ goto out;
+ }
+- device_bind_driver(&gameport->dev);
+-out:
++
++ error = device_bind_driver(&gameport->dev);
++ if (error) {
++ printk(KERN_WARNING
++ "gameport: device_bind_driver() failed "
++ "for %s (%s) and %s, error: %d\n",
++ gameport->phys, gameport->name,
++ drv->description, error);
++ drv->disconnect(gameport);
++ gameport->dev.driver = NULL;
++ goto out;
++ }
++
++ out:
+ up_write(&gameport_bus.subsys.rwsem);
+ }
+
+diff --git a/drivers/input/input.c b/drivers/input/input.c
+index 9cb4b9a..1c8c8a5 100644
+--- a/drivers/input/input.c
++++ b/drivers/input/input.c
+@@ -176,6 +176,10 @@ void input_event(struct input_dev *dev,
+ break;
+
+ case EV_FF:
++
++ if (value < 0)
++ return;
++
+ if (dev->event)
+ dev->event(dev, type, code, value);
+ break;
+@@ -309,7 +313,8 @@ static void input_link_handle(struct inp
+ if (i != NBITS(max)) \
+ continue;
+
+-static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
++static const struct input_device_id *input_match_device(const struct input_device_id *id,
++ struct input_dev *dev)
+ {
+ int i;
+
+@@ -762,7 +767,9 @@ static void input_dev_release(struct cla
+ {
+ struct input_dev *dev = to_input_dev(class_dev);
+
++ input_ff_destroy(dev);
+ kfree(dev);
++
+ module_put(THIS_MODULE);
+ }
+
+@@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(
+
+ dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
+ if (dev) {
+- dev->dynalloc = 1;
+ dev->cdev.class = &input_class;
+ class_device_initialize(&dev->cdev);
+ mutex_init(&dev->mutex);
+ INIT_LIST_HEAD(&dev->h_list);
+ INIT_LIST_HEAD(&dev->node);
++
++ __module_get(THIS_MODULE);
+ }
+
+ return dev;
+@@ -929,17 +937,10 @@ int input_register_device(struct input_d
+ static atomic_t input_no = ATOMIC_INIT(0);
+ struct input_handle *handle;
+ struct input_handler *handler;
+- struct input_device_id *id;
++ const struct input_device_id *id;
+ const char *path;
+ int error;
+
+- if (!dev->dynalloc) {
+- printk(KERN_WARNING "input: device %s is statically allocated, will not register\n"
+- "Please convert to input_allocate_device() or contact dtor_core at ameritech.net\n",
+- dev->name ? dev->name : "<Unknown>");
+- return -EINVAL;
+- }
+-
+ set_bit(EV_SYN, dev->evbit);
+
+ /*
+@@ -955,10 +956,8 @@ int input_register_device(struct input_d
+ dev->rep[REP_PERIOD] = 33;
+ }
+
+- INIT_LIST_HEAD(&dev->h_list);
+ list_add_tail(&dev->node, &input_dev_list);
+
+- dev->cdev.class = &input_class;
+ snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
+ "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
+
+@@ -978,8 +977,6 @@ int input_register_device(struct input_d
+ if (error)
+ goto fail3;
+
+- __module_get(THIS_MODULE);
+-
+ path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
+ printk(KERN_INFO "input: %s as %s\n",
+ dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
+@@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device);
+ void input_unregister_device(struct input_dev *dev)
+ {
+ struct list_head *node, *next;
++ int code;
+
+- if (!dev)
+- return;
++ for (code = 0; code <= KEY_MAX; code++)
++ if (test_bit(code, dev->key))
++ input_report_key(dev, code, 0);
++ input_sync(dev);
+
+ del_timer_sync(&dev->timer);
+
+@@ -1037,19 +1037,20 @@ void input_unregister_device(struct inpu
+ }
+ EXPORT_SYMBOL(input_unregister_device);
+
+-void input_register_handler(struct input_handler *handler)
++int input_register_handler(struct input_handler *handler)
+ {
+ struct input_dev *dev;
+ struct input_handle *handle;
+- struct input_device_id *id;
+-
+- if (!handler)
+- return;
++ const struct input_device_id *id;
+
+ INIT_LIST_HEAD(&handler->h_list);
+
+- if (handler->fops != NULL)
++ if (handler->fops != NULL) {
++ if (input_table[handler->minor >> 5])
++ return -EBUSY;
++
+ input_table[handler->minor >> 5] = handler;
++ }
+
+ list_add_tail(&handler->node, &input_handler_list);
+
+@@ -1063,6 +1064,7 @@ void input_register_handler(struct input
+ }
+
+ input_wakeup_procfs_readers();
++ return 0;
+ }
+ EXPORT_SYMBOL(input_register_handler);
+
+diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
+index d671575..9f3529a 100644
+--- a/drivers/input/joydev.c
++++ b/drivers/input/joydev.c
+@@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *in
+ }
+ }
+
+-static struct file_operations joydev_fops = {
++static const struct file_operations joydev_fops = {
+ .owner = THIS_MODULE,
+ .read = joydev_read,
+ .write = joydev_write,
+@@ -465,7 +465,8 @@ static struct file_operations joydev_fop
+ .fasync = joydev_fasync,
+ };
+
+-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
++static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
++ const struct input_device_id *id)
+ {
+ struct joydev *joydev;
+ struct class_device *cdev;
+@@ -562,7 +563,7 @@ static void joydev_disconnect(struct inp
+ joydev_free(joydev);
+ }
+
+-static struct input_device_id joydev_blacklist[] = {
++static const struct input_device_id joydev_blacklist[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT(EV_KEY) },
+@@ -571,7 +572,7 @@ static struct input_device_id joydev_bla
+ { } /* Terminating entry */
+ };
+
+-static struct input_device_id joydev_ids[] = {
++static const struct input_device_id joydev_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_ABS) },
+@@ -605,8 +606,7 @@ static struct input_handler joydev_handl
+
+ static int __init joydev_init(void)
+ {
+- input_register_handler(&joydev_handler);
+- return 0;
++ return input_register_handler(&joydev_handler);
+ }
+
+ static void __exit joydev_exit(void)
+diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
+index 67519ef..2712634 100644
+--- a/drivers/input/joystick/Kconfig
++++ b/drivers/input/joystick/Kconfig
+@@ -32,7 +32,7 @@ config JOYSTICK_ANALOG
+ module will be called analog.
+
+ config JOYSTICK_A3D
+- tristate "Assasin 3D and MadCatz Panther devices"
++ tristate "Assassin 3D and MadCatz Panther devices"
+ select GAMEPORT
+ help
+ Say Y here if you have an FPGaming or MadCatz controller using the
+diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
+index 7249d32..650acf3 100644
+--- a/drivers/input/joystick/amijoy.c
++++ b/drivers/input/joystick/amijoy.c
+@@ -57,7 +57,7 @@ static DEFINE_MUTEX(amijoy_mutex);
+ static struct input_dev *amijoy_dev[2];
+ static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
+
+-static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t amijoy_interrupt(int irq, void *dummy)
+ {
+ int i, data = 0, button = 0;
+
+@@ -69,8 +69,6 @@ static irqreturn_t amijoy_interrupt(int
+ case 1: data = ~amiga_custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
+ }
+
+- input_regs(amijoy_dev[i], fp);
+-
+ input_report_key(amijoy_dev[i], BTN_TRIGGER, button);
+
+ input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
+diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
+index 50c9076..8fb0c19 100644
+--- a/drivers/input/joystick/iforce/iforce-ff.c
++++ b/drivers/input/joystick/iforce/iforce-ff.c
+@@ -165,19 +165,19 @@ static int make_condition_modifier(struc
+ data[0] = LO(mod_chunk->start);
+ data[1] = HI(mod_chunk->start);
+
+- data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */
+- data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */
++ data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */
++ data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */
+
+- center = (500*center)>>15;
++ center = (500 * center) >> 15;
+ data[4] = LO(center);
+ data[5] = HI(center);
+
+- db = (1000*db)>>16;
++ db = (1000 * db) >> 16;
+ data[6] = LO(db);
+ data[7] = HI(db);
+
+- data[8] = (100*rsat)>>16;
+- data[9] = (100*lsat)>>16;
++ data[8] = (100 * rsat) >> 16;
++ data[9] = (100 * lsat) >> 16;
+
+ iforce_send_packet(iforce, FF_CMD_CONDITION, data);
+ iforce_dump_packet("condition", FF_CMD_CONDITION, data);
+@@ -188,6 +188,7 @@ static int make_condition_modifier(struc
+ static unsigned char find_button(struct iforce *iforce, signed short button)
+ {
+ int i;
++
+ for (i = 1; iforce->type->btn[i] >= 0; i++)
+ if (iforce->type->btn[i] == button)
+ return i + 1;
+@@ -198,19 +199,17 @@ static unsigned char find_button(struct
+ * Analyse the changes in an effect, and tell if we need to send an condition
+ * parameter packet
+ */
+-static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new)
++static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
+ {
+- int id = new->id;
+- struct ff_effect* old = &iforce->core_effects[id].effect;
+- int ret=0;
++ int ret = 0;
+ int i;
+
+ if (new->type != FF_SPRING && new->type != FF_FRICTION) {
+ printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
+- return FALSE;
++ return 0;
+ }
+
+- for(i=0; i<2; i++) {
++ for (i = 0; i < 2; i++) {
+ ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation
+ || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation
+ || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff
+@@ -225,35 +224,29 @@ static int need_condition_modifier(struc
+ * Analyse the changes in an effect, and tell if we need to send a magnitude
+ * parameter packet
+ */
+-static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect)
++static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
+ {
+- int id = effect->id;
+- struct ff_effect* old = &iforce->core_effects[id].effect;
+-
+ if (effect->type != FF_CONSTANT) {
+ printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+- return FALSE;
++ return 0;
+ }
+
+- return (old->u.constant.level != effect->u.constant.level);
++ return old->u.constant.level != effect->u.constant.level;
+ }
+
+ /*
+ * Analyse the changes in an effect, and tell if we need to send an envelope
+ * parameter packet
+ */
+-static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect)
++static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effect)
+ {
+- int id = effect->id;
+- struct ff_effect* old = &iforce->core_effects[id].effect;
+-
+ switch (effect->type) {
+ case FF_CONSTANT:
+ if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length
+ || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level
+ || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length
+ || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level)
+- return TRUE;
++ return 1;
+ break;
+
+ case FF_PERIODIC:
+@@ -261,30 +254,26 @@ static int need_envelope_modifier(struct
+ || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level
+ || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length
+ || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level)
+- return TRUE;
++ return 1;
+ break;
+
+ default:
+ printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+ }
+
+- return FALSE;
++ return 0;
+ }
+
+ /*
+ * Analyse the changes in an effect, and tell if we need to send a periodic
+ * parameter effect
+ */
+-static int need_period_modifier(struct iforce* iforce, struct ff_effect* new)
++static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
+ {
+- int id = new->id;
+- struct ff_effect* old = &iforce->core_effects[id].effect;
+-
+ if (new->type != FF_PERIODIC) {
+- printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n");
+- return FALSE;
++ printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n");
++ return 0;
+ }
+-
+ return (old->u.periodic.period != new->u.periodic.period
+ || old->u.periodic.magnitude != new->u.periodic.magnitude
+ || old->u.periodic.offset != new->u.periodic.offset
+@@ -295,19 +284,16 @@ static int need_period_modifier(struct i
+ * Analyse the changes in an effect, and tell if we need to send an effect
+ * packet
+ */
+-static int need_core(struct iforce* iforce, struct ff_effect* new)
++static int need_core(struct ff_effect *old, struct ff_effect *new)
+ {
+- int id = new->id;
+- struct ff_effect* old = &iforce->core_effects[id].effect;
+-
+ if (old->direction != new->direction
+ || old->trigger.button != new->trigger.button
+ || old->trigger.interval != new->trigger.interval
+ || old->replay.length != new->replay.length
+ || old->replay.delay != new->replay.delay)
+- return TRUE;
++ return 1;
+
+- return FALSE;
++ return 0;
+ }
+ /*
+ * Send the part common to all effects to the device
+@@ -360,7 +346,7 @@ static int make_core(struct iforce* ifor
+ * Upload a periodic effect to the device
+ * See also iforce_upload_constant.
+ */
+-int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update)
++int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old)
+ {
+ u8 wave_code;
+ int core_id = effect->id;
+@@ -371,23 +357,25 @@ int iforce_upload_periodic(struct iforce
+ int param2_err = 1;
+ int core_err = 0;
+
+- if (!is_update || need_period_modifier(iforce, effect)) {
++ if (!old || need_period_modifier(old, effect)) {
+ param1_err = make_period_modifier(iforce, mod1_chunk,
+- is_update,
++ old != NULL,
+ effect->u.periodic.magnitude, effect->u.periodic.offset,
+ effect->u.periodic.period, effect->u.periodic.phase);
+- if (param1_err) return param1_err;
++ if (param1_err)
++ return param1_err;
+ set_bit(FF_MOD1_IS_USED, core_effect->flags);
+ }
+
+- if (!is_update || need_envelope_modifier(iforce, effect)) {
++ if (!old || need_envelope_modifier(old, effect)) {
+ param2_err = make_envelope_modifier(iforce, mod2_chunk,
+- is_update,
++ old !=NULL,
+ effect->u.periodic.envelope.attack_length,
+ effect->u.periodic.envelope.attack_level,
+ effect->u.periodic.envelope.fade_length,
+ effect->u.periodic.envelope.fade_level);
+- if (param2_err) return param2_err;
++ if (param2_err)
++ return param2_err;
+ set_bit(FF_MOD2_IS_USED, core_effect->flags);
+ }
+
+@@ -400,7 +388,7 @@ int iforce_upload_periodic(struct iforce
+ default: wave_code = 0x20; break;
+ }
+
+- if (!is_update || need_core(iforce, effect)) {
++ if (!old || need_core(old, effect)) {
+ core_err = make_core(iforce, effect->id,
+ mod1_chunk->start,
+ mod2_chunk->start,
+@@ -429,7 +417,7 @@ int iforce_upload_periodic(struct iforce
+ * 0 Ok, effect created or updated
+ * 1 effect did not change since last upload, and no packet was therefore sent
+ */
+-int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update)
++int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old)
+ {
+ int core_id = effect->id;
+ struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+@@ -439,26 +427,28 @@ int iforce_upload_constant(struct iforce
+ int param2_err = 1;
+ int core_err = 0;
+
+- if (!is_update || need_magnitude_modifier(iforce, effect)) {
++ if (!old || need_magnitude_modifier(old, effect)) {
+ param1_err = make_magnitude_modifier(iforce, mod1_chunk,
+- is_update,
++ old != NULL,
+ effect->u.constant.level);
+- if (param1_err) return param1_err;
++ if (param1_err)
++ return param1_err;
+ set_bit(FF_MOD1_IS_USED, core_effect->flags);
+ }
+
+- if (!is_update || need_envelope_modifier(iforce, effect)) {
++ if (!old || need_envelope_modifier(old, effect)) {
+ param2_err = make_envelope_modifier(iforce, mod2_chunk,
+- is_update,
++ old != NULL,
+ effect->u.constant.envelope.attack_length,
+ effect->u.constant.envelope.attack_level,
+ effect->u.constant.envelope.fade_length,
+ effect->u.constant.envelope.fade_level);
+- if (param2_err) return param2_err;
++ if (param2_err)
++ return param2_err;
+ set_bit(FF_MOD2_IS_USED, core_effect->flags);
+ }
+
+- if (!is_update || need_core(iforce, effect)) {
++ if (!old || need_core(old, effect)) {
+ core_err = make_core(iforce, effect->id,
+ mod1_chunk->start,
+ mod2_chunk->start,
+@@ -483,7 +473,7 @@ int iforce_upload_constant(struct iforce
+ /*
+ * Upload an condition effect. Those are for example friction, inertia, springs...
+ */
+-int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update)
++int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old)
+ {
+ int core_id = effect->id;
+ struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+@@ -494,37 +484,39 @@ int iforce_upload_condition(struct iforc
+ int core_err = 0;
+
+ switch (effect->type) {
+- case FF_SPRING: type = 0x40; break;
+- case FF_DAMPER: type = 0x41; break;
++ case FF_SPRING: type = 0x40; break;
++ case FF_DAMPER: type = 0x41; break;
+ default: return -1;
+ }
+
+- if (!is_update || need_condition_modifier(iforce, effect)) {
++ if (!old || need_condition_modifier(old, effect)) {
+ param_err = make_condition_modifier(iforce, mod1_chunk,
+- is_update,
++ old != NULL,
+ effect->u.condition[0].right_saturation,
+ effect->u.condition[0].left_saturation,
+ effect->u.condition[0].right_coeff,
+ effect->u.condition[0].left_coeff,
+ effect->u.condition[0].deadband,
+ effect->u.condition[0].center);
+- if (param_err) return param_err;
++ if (param_err)
++ return param_err;
+ set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+ param_err = make_condition_modifier(iforce, mod2_chunk,
+- is_update,
++ old != NULL,
+ effect->u.condition[1].right_saturation,
+ effect->u.condition[1].left_saturation,
+ effect->u.condition[1].right_coeff,
+ effect->u.condition[1].left_coeff,
+ effect->u.condition[1].deadband,
+ effect->u.condition[1].center);
+- if (param_err) return param_err;
++ if (param_err)
++ return param_err;
+ set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+ }
+
+- if (!is_update || need_core(iforce, effect)) {
++ if (!old || need_core(old, effect)) {
+ core_err = make_core(iforce, effect->id,
+ mod1_chunk->start, mod2_chunk->start,
+ type, 0xc0,
+diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
+index b4914e7..24c684b 100644
+--- a/drivers/input/joystick/iforce/iforce-main.c
++++ b/drivers/input/joystick/iforce/iforce-main.c
+@@ -83,103 +83,57 @@ static struct iforce_device iforce_devic
+ { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
+ };
+
+-
+-
+-static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
++static int iforce_playback(struct input_dev *dev, int effect_id, int value)
+ {
+ struct iforce* iforce = dev->private;
+- unsigned char data[3];
+-
+- if (type != EV_FF)
+- return -1;
+-
+- switch (code) {
+-
+- case FF_GAIN:
+-
+- data[0] = value >> 9;
+- iforce_send_packet(iforce, FF_CMD_GAIN, data);
+-
+- return 0;
+-
+- case FF_AUTOCENTER:
++ struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
+
+- data[0] = 0x03;
+- data[1] = value >> 9;
+- iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
++ if (value > 0)
++ set_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);
++ else
++ clear_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);
+
+- data[0] = 0x04;
+- data[1] = 0x01;
+- iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
++ iforce_control_playback(iforce, effect_id, value);
++ return 0;
++}
+
+- return 0;
++static void iforce_set_gain(struct input_dev *dev, u16 gain)
++{
++ struct iforce* iforce = dev->private;
++ unsigned char data[3];
+
+- default: /* Play or stop an effect */
++ data[0] = gain >> 9;
++ iforce_send_packet(iforce, FF_CMD_GAIN, data);
++}
+
+- if (!CHECK_OWNERSHIP(code, iforce)) {
+- return -1;
+- }
+- if (value > 0) {
+- set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
+- }
+- else {
+- clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
+- }
++static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
++{
++ struct iforce* iforce = dev->private;
++ unsigned char data[3];
+
+- iforce_control_playback(iforce, code, value);
+- return 0;
+- }
++ data[0] = 0x03;
++ data[1] = magnitude >> 9;
++ iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+- return -1;
++ data[0] = 0x04;
++ data[1] = 0x01;
++ iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
+ }
+
+ /*
+ * Function called when an ioctl is performed on the event dev entry.
+ * It uploads an effect to the device
+ */
+-static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
++static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
+ {
+ struct iforce* iforce = dev->private;
+- int id;
++ struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];
+ int ret;
+- int is_update;
+-
+-/* Check this effect type is supported by this device */
+- if (!test_bit(effect->type, iforce->dev->ffbit))
+- return -EINVAL;
+-
+-/*
+- * If we want to create a new effect, get a free id
+- */
+- if (effect->id == -1) {
+-
+- for (id = 0; id < FF_EFFECTS_MAX; ++id)
+- if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags))
+- break;
+-
+- if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max)
+- return -ENOMEM;
+-
+- effect->id = id;
+- iforce->core_effects[id].owner = current->pid;
+- iforce->core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */
+-
+- is_update = FALSE;
+- }
+- else {
+- /* We want to update an effect */
+- if (!CHECK_OWNERSHIP(effect->id, iforce))
+- return -EACCES;
+-
+- /* Parameter type cannot be updated */
+- if (effect->type != iforce->core_effects[effect->id].effect.type)
+- return -EINVAL;
+
++ if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) {
+ /* Check the effect is not already being updated */
+- if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags))
++ if (test_bit(FF_CORE_UPDATE, core_effect->flags))
+ return -EAGAIN;
+-
+- is_update = TRUE;
+ }
+
+ /*
+@@ -188,28 +142,28 @@ static int iforce_upload_effect(struct i
+ switch (effect->type) {
+
+ case FF_PERIODIC:
+- ret = iforce_upload_periodic(iforce, effect, is_update);
++ ret = iforce_upload_periodic(iforce, effect, old);
+ break;
+
+ case FF_CONSTANT:
+- ret = iforce_upload_constant(iforce, effect, is_update);
++ ret = iforce_upload_constant(iforce, effect, old);
+ break;
+
+ case FF_SPRING:
+ case FF_DAMPER:
+- ret = iforce_upload_condition(iforce, effect, is_update);
++ ret = iforce_upload_condition(iforce, effect, old);
+ break;
+
+ default:
+ return -EINVAL;
+ }
++
+ if (ret == 0) {
+ /* A packet was sent, forbid new updates until we are notified
+ * that the packet was updated
+ */
+- set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags);
++ set_bit(FF_CORE_UPDATE, core_effect->flags);
+ }
+- iforce->core_effects[effect->id].effect = *effect;
+ return ret;
+ }
+
+@@ -219,20 +173,9 @@ static int iforce_upload_effect(struct i
+ */
+ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
+ {
+- struct iforce* iforce = dev->private;
++ struct iforce *iforce = dev->private;
++ struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
+ int err = 0;
+- struct iforce_core_effect* core_effect;
+-
+- if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
+- return -EINVAL;
+-
+- core_effect = &iforce->core_effects[effect_id];
+-
+- /* Check who is trying to erase this effect */
+- if (core_effect->owner != current->pid) {
+- printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner);
+- return -EACCES;
+- }
+
+ if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
+ err = release_resource(&core_effect->mod1_chunk);
+@@ -240,7 +183,7 @@ static int iforce_erase_effect(struct in
+ if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
+ err = release_resource(&core_effect->mod2_chunk);
+
+- /*TODO: remember to change that if more FF_MOD* bits are added */
++ /* TODO: remember to change that if more FF_MOD* bits are added */
+ core_effect->flags[0] = 0;
+
+ return err;
+@@ -260,52 +203,31 @@ static int iforce_open(struct input_dev
+ #endif
+ }
+
+- /* Enable force feedback */
+- iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
++ if (test_bit(EV_FF, dev->evbit)) {
++ /* Enable force feedback */
++ iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
++ }
+
+ return 0;
+ }
+
+-static int iforce_flush(struct input_dev *dev, struct file *file)
++static void iforce_release(struct input_dev *dev)
+ {
+ struct iforce *iforce = dev->private;
+ int i;
+
+- /* Erase all effects this process owns */
+- for (i=0; i<dev->ff_effects_max; ++i) {
+-
+- if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
+- current->pid == iforce->core_effects[i].owner) {
+-
+- /* Stop effect */
+- input_report_ff(dev, i, 0);
+-
+- /* Free ressources assigned to effect */
+- if (iforce_erase_effect(dev, i)) {
+- printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i);
++ if (test_bit(EV_FF, dev->evbit)) {
++ /* Check: no effects should be present in memory */
++ for (i = 0; i < dev->ff->max_effects; i++) {
++ if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
++ printk(KERN_WARNING "iforce_release: Device still owns effects\n");
++ break;
+ }
+ }
+
++ /* Disable force feedback playback */
++ iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
+ }
+- return 0;
+-}
+-
+-static void iforce_release(struct input_dev *dev)
+-{
+- struct iforce *iforce = dev->private;
+- int i;
+-
+- /* Check: no effect should be present in memory */
+- for (i=0; i<dev->ff_effects_max; ++i) {
+- if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags))
+- break;
+- }
+- if (i<dev->ff_effects_max) {
+- printk(KERN_WARNING "iforce_release: Device still owns effects\n");
+- }
+-
+- /* Disable force feedback playback */
+- iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
+
+ switch (iforce->bus) {
+ #ifdef CONFIG_JOYSTICK_IFORCE_USB
+@@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce
+ int iforce_init_device(struct iforce *iforce)
+ {
+ struct input_dev *input_dev;
++ struct ff_device *ff;
+ unsigned char c[] = "CEOV";
+- int i;
++ int i, error;
++ int ff_effects = 0;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+@@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *if
+ input_dev->name = "Unknown I-Force device";
+ input_dev->open = iforce_open;
+ input_dev->close = iforce_release;
+- input_dev->flush = iforce_flush;
+- input_dev->event = iforce_input_event;
+- input_dev->upload_effect = iforce_upload_effect;
+- input_dev->erase_effect = iforce_erase_effect;
+- input_dev->ff_effects_max = 10;
+
+ /*
+ * On-device memory allocation.
+@@ -430,15 +349,15 @@ int iforce_init_device(struct iforce *if
+ printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
+
+ if (!iforce_get_id_packet(iforce, "N"))
+- iforce->dev->ff_effects_max = iforce->edata[1];
++ ff_effects = iforce->edata[1];
+ else
+ printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
+
+ /* Check if the device can store more effects than the driver can really handle */
+- if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) {
+- printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n",
+- iforce->dev->ff_effects_max, FF_EFFECTS_MAX);
+- iforce->dev->ff_effects_max = FF_EFFECTS_MAX;
++ if (ff_effects > IFORCE_EFFECTS_MAX) {
++ printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
++ IFORCE_EFFECTS_MAX, ff_effects);
++ ff_effects = IFORCE_EFFECTS_MAX;
+ }
+
+ /*
+@@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *if
+ * Set input device bitfields and ranges.
+ */
+
+- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS);
++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF_STATUS);
+
+- for (i = 0; iforce->type->btn[i] >= 0; i++) {
+- signed short t = iforce->type->btn[i];
+- set_bit(t, input_dev->keybit);
+- }
++ for (i = 0; iforce->type->btn[i] >= 0; i++)
++ set_bit(iforce->type->btn[i], input_dev->keybit);
+ set_bit(BTN_DEAD, input_dev->keybit);
+
+ for (i = 0; iforce->type->abs[i] >= 0; i++) {
+@@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *if
+ }
+ }
+
+- for (i = 0; iforce->type->ff[i] >= 0; i++)
+- set_bit(iforce->type->ff[i], input_dev->ffbit);
++ if (ff_effects) {
+
++ for (i = 0; iforce->type->ff[i] >= 0; i++)
++ set_bit(iforce->type->ff[i], input_dev->ffbit);
++
++ error = input_ff_create(input_dev, ff_effects);
++ if (error) {
++ input_free_device(input_dev);
++ return error;
++ }
++
++ ff = input_dev->ff;
++ ff->upload = iforce_upload_effect;
++ ff->erase = iforce_erase_effect;
++ ff->set_gain = iforce_set_gain;
++ ff->set_autocenter = iforce_set_autocenter;
++ ff->playback = iforce_playback;
++ }
+ /*
+ * Register input device.
+ */
+diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
+index 76cb1f8..808f059 100644
+--- a/drivers/input/joystick/iforce/iforce-packets.c
++++ b/drivers/input/joystick/iforce/iforce-packets.c
+@@ -140,7 +140,10 @@ static int mark_core_as_ready(struct ifo
+ {
+ int i;
+
+- for (i = 0; i < iforce->dev->ff_effects_max; ++i) {
++ if (!iforce->dev->ff)
++ return 0;
++
++ for (i = 0; i < iforce->dev->ff->max_effects; ++i) {
+ if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
+ (iforce->core_effects[i].mod1_chunk.start == addr ||
+ iforce->core_effects[i].mod2_chunk.start == addr)) {
+@@ -152,7 +155,7 @@ static int mark_core_as_ready(struct ifo
+ return -1;
+ }
+
+-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs)
++void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+ {
+ struct input_dev *dev = iforce->dev;
+ int i;
+@@ -180,9 +183,6 @@ void iforce_process_packet(struct iforce
+
+ case 0x01: /* joystick position data */
+ case 0x03: /* wheel position data */
+-
+- input_regs(dev, regs);
+-
+ if (HI(cmd) == 1) {
+ input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
+ input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
+@@ -221,7 +221,6 @@ void iforce_process_packet(struct iforce
+ break;
+
+ case 0x02: /* status report */
+- input_regs(dev, regs);
+ input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+ input_sync(dev);
+
+@@ -229,19 +228,17 @@ void iforce_process_packet(struct iforce
+ i = data[1] & 0x7f;
+ if (data[1] & 0x80) {
+ if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+- /* Report play event */
+- input_report_ff_status(dev, i, FF_STATUS_PLAYING);
++ /* Report play event */
++ input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+ }
+- }
+- else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
++ } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+ /* Report stop event */
+ input_report_ff_status(dev, i, FF_STATUS_STOPPED);
+ }
+ if (LO(cmd) > 3) {
+ int j;
+- for (j=3; j<LO(cmd); j+=2) {
++ for (j = 3; j < LO(cmd); j += 2)
+ mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
+- }
+ }
+ break;
+ }
+diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
+index 64a78c5..ca08f45 100644
+--- a/drivers/input/joystick/iforce/iforce-serio.c
++++ b/drivers/input/joystick/iforce/iforce-serio.c
+@@ -81,7 +81,7 @@ static void iforce_serio_write_wakeup(st
+ }
+
+ static irqreturn_t iforce_serio_irq(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct iforce *iforce = serio_get_drvdata(serio);
+
+@@ -115,7 +115,7 @@ static irqreturn_t iforce_serio_irq(stru
+ }
+
+ if (iforce->idx == iforce->len) {
+- iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data, regs);
++ iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
+ iforce->pkt = 0;
+ iforce->id = 0;
+ iforce->len = 0;
+diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
+index fe79d15..105112f 100644
+--- a/drivers/input/joystick/iforce/iforce-usb.c
++++ b/drivers/input/joystick/iforce/iforce-usb.c
+@@ -74,7 +74,7 @@ void iforce_usb_xmit(struct iforce *ifor
+ spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+ }
+
+-static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs)
++static void iforce_usb_irq(struct urb *urb)
+ {
+ struct iforce *iforce = urb->context;
+ int status;
+@@ -96,7 +96,7 @@ static void iforce_usb_irq(struct urb *u
+ }
+
+ iforce_process_packet(iforce,
+- (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs);
++ (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+
+ exit:
+ status = usb_submit_urb (urb, GFP_ATOMIC);
+@@ -105,7 +105,7 @@ exit:
+ __FUNCTION__, status);
+ }
+
+-static void iforce_usb_out(struct urb *urb, struct pt_regs *regs)
++static void iforce_usb_out(struct urb *urb)
+ {
+ struct iforce *iforce = urb->context;
+
+@@ -119,7 +119,7 @@ static void iforce_usb_out(struct urb *u
+ wake_up(&iforce->wait);
+ }
+
+-static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
++static void iforce_usb_ctrl(struct urb *urb)
+ {
+ struct iforce *iforce = urb->context;
+ if (urb->status) return;
+diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
+index e9924d6..ffaeaef 100644
+--- a/drivers/input/joystick/iforce/iforce.h
++++ b/drivers/input/joystick/iforce/iforce.h
+@@ -51,10 +51,7 @@
+ #define IFORCE_232 1
+ #define IFORCE_USB 2
+
+-#define FALSE 0
+-#define TRUE 1
+-
+-#define FF_EFFECTS_MAX 32
++#define IFORCE_EFFECTS_MAX 32
+
+ /* Each force feedback effect is made of one core effect, which can be
+ * associated to at most to effect modifiers
+@@ -67,24 +64,11 @@
+ #define FF_CORE_UPDATE 5 /* Effect is being updated */
+ #define FF_MODCORE_MAX 5
+
+-#define CHECK_OWNERSHIP(i, iforce) \
+- ((i) < FF_EFFECTS_MAX && i >= 0 && \
+- test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \
+- (current->pid == 0 || \
+- (iforce)->core_effects[(i)].owner == current->pid))
+-
+ struct iforce_core_effect {
+ /* Information about where modifiers are stored in the device's memory */
+ struct resource mod1_chunk;
+ struct resource mod2_chunk;
+ unsigned long flags[NBITS(FF_MODCORE_MAX)];
+- pid_t owner;
+- /* Used to keep track of parameters of an effect. They are needed
+- * to know what parts of an effect changed in an update operation.
+- * We try to send only parameter packets if possible, as sending
+- * effect parameter requires the effect to be stoped and restarted
+- */
+- struct ff_effect effect;
+ };
+
+ #define FF_CMD_EFFECT 0x010e
+@@ -145,7 +129,7 @@ struct iforce {
+ /* Force Feedback */
+ wait_queue_head_t wait;
+ struct resource device_memory;
+- struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
++ struct iforce_core_effect core_effects[IFORCE_EFFECTS_MAX];
+ struct mutex mem_mutex;
+ };
+
+@@ -176,15 +160,15 @@ void iforce_delete_device(struct iforce
+
+ /* iforce-packets.c */
+ int iforce_control_playback(struct iforce*, u16 id, unsigned int);
+-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs);
++void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
+ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
+ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
+ int iforce_get_id_packet(struct iforce *iforce, char *packet);
+
+ /* iforce-ff.c */
+-int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update);
+-int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
+-int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update);
++int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *);
++int iforce_upload_constant(struct iforce *, struct ff_effect *, struct ff_effect *);
++int iforce_upload_condition(struct iforce *, struct ff_effect *, struct ff_effect *);
+
+ /* Public variables */
+ extern struct serio_driver iforce_serio_drv;
+diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
+index 168b106..e3d1944 100644
+--- a/drivers/input/joystick/magellan.c
++++ b/drivers/input/joystick/magellan.c
+@@ -82,7 +82,7 @@ static int magellan_crunch_nibbles(unsig
+ return 0;
+ }
+
+-static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs)
++static void magellan_process_packet(struct magellan* magellan)
+ {
+ struct input_dev *dev = magellan->dev;
+ unsigned char *data = magellan->data;
+@@ -90,8 +90,6 @@ static void magellan_process_packet(stru
+
+ if (!magellan->idx) return;
+
+- input_regs(dev, regs);
+-
+ switch (magellan->data[0]) {
+
+ case 'd': /* Axis data */
+@@ -115,12 +113,12 @@ static void magellan_process_packet(stru
+ }
+
+ static irqreturn_t magellan_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct magellan* magellan = serio_get_drvdata(serio);
+
+ if (data == '\r') {
+- magellan_process_packet(magellan, regs);
++ magellan_process_packet(magellan);
+ magellan->idx = 0;
+ } else {
+ if (magellan->idx < MAGELLAN_MAX_LENGTH)
+diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
+index 7a19ee0..2a9808c 100644
+--- a/drivers/input/joystick/spaceball.c
++++ b/drivers/input/joystick/spaceball.c
+@@ -82,7 +82,7 @@ struct spaceball {
+ * SpaceBall.
+ */
+
+-static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs)
++static void spaceball_process_packet(struct spaceball* spaceball)
+ {
+ struct input_dev *dev = spaceball->dev;
+ unsigned char *data = spaceball->data;
+@@ -90,8 +90,6 @@ static void spaceball_process_packet(str
+
+ if (spaceball->idx < 2) return;
+
+- input_regs(dev, regs);
+-
+ switch (spaceball->data[0]) {
+
+ case 'D': /* Ball data */
+@@ -151,13 +149,13 @@ static void spaceball_process_packet(str
+ */
+
+ static irqreturn_t spaceball_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct spaceball *spaceball = serio_get_drvdata(serio);
+
+ switch (data) {
+ case 0xd:
+- spaceball_process_packet(spaceball, regs);
++ spaceball_process_packet(spaceball);
+ spaceball->idx = 0;
+ spaceball->escape = 0;
+ break;
+diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
+index 3e2782e..c4db024 100644
+--- a/drivers/input/joystick/spaceorb.c
++++ b/drivers/input/joystick/spaceorb.c
+@@ -74,7 +74,7 @@ static unsigned char *spaceorb_errors[]
+ * SpaceOrb.
+ */
+
+-static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs)
++static void spaceorb_process_packet(struct spaceorb *spaceorb)
+ {
+ struct input_dev *dev = spaceorb->dev;
+ unsigned char *data = spaceorb->data;
+@@ -86,8 +86,6 @@ static void spaceorb_process_packet(stru
+ for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
+ if (c) return;
+
+- input_regs(dev, regs);
+-
+ switch (data[0]) {
+
+ case 'R': /* Reset packet */
+@@ -131,12 +129,12 @@ static void spaceorb_process_packet(stru
+ }
+
+ static irqreturn_t spaceorb_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct spaceorb* spaceorb = serio_get_drvdata(serio);
+
+ if (~data & 0x80) {
+- if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs);
++ if (spaceorb->idx) spaceorb_process_packet(spaceorb);
+ spaceorb->idx = 0;
+ }
+ if (spaceorb->idx < SPACEORB_MAX_LENGTH)
+diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
+index 011ec48..1ffb032 100644
+--- a/drivers/input/joystick/stinger.c
++++ b/drivers/input/joystick/stinger.c
+@@ -64,15 +64,13 @@ struct stinger {
+ * Stinger. It updates the data accordingly.
+ */
+
+-static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs)
++static void stinger_process_packet(struct stinger *stinger)
+ {
+ struct input_dev *dev = stinger->dev;
+ unsigned char *data = stinger->data;
+
+ if (!stinger->idx) return;
+
+- input_regs(dev, regs);
+-
+ input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5));
+ input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4));
+ input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3));
+@@ -99,7 +97,7 @@ static void stinger_process_packet(struc
+ */
+
+ static irqreturn_t stinger_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct stinger *stinger = serio_get_drvdata(serio);
+
+@@ -109,7 +107,7 @@ static irqreturn_t stinger_interrupt(str
+ stinger->data[stinger->idx++] = data;
+
+ if (stinger->idx == 4) {
+- stinger_process_packet(stinger, regs);
++ stinger_process_packet(stinger);
+ stinger->idx = 0;
+ }
+
+diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
+index 076f237..49085df 100644
+--- a/drivers/input/joystick/twidjoy.c
++++ b/drivers/input/joystick/twidjoy.c
+@@ -104,7 +104,7 @@ struct twidjoy {
+ * Twiddler. It updates the data accordingly.
+ */
+
+-static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs)
++static void twidjoy_process_packet(struct twidjoy *twidjoy)
+ {
+ struct input_dev *dev = twidjoy->dev;
+ unsigned char *data = twidjoy->data;
+@@ -113,8 +113,6 @@ static void twidjoy_process_packet(struc
+
+ button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f);
+
+- input_regs(dev, regs);
+-
+ for (bp = twidjoy_buttons; bp->bitmask; bp++) {
+ int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift;
+ int i;
+@@ -141,7 +139,7 @@ static void twidjoy_process_packet(struc
+ * packet processing routine.
+ */
+
+-static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
++static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+ {
+ struct twidjoy *twidjoy = serio_get_drvdata(serio);
+
+@@ -158,7 +156,7 @@ static irqreturn_t twidjoy_interrupt(str
+ twidjoy->data[twidjoy->idx++] = data;
+
+ if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
+- twidjoy_process_packet(twidjoy, regs);
++ twidjoy_process_packet(twidjoy);
+ twidjoy->idx = 0;
+ }
+
+diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
+index f9c1a03..35edea1 100644
+--- a/drivers/input/joystick/warrior.c
++++ b/drivers/input/joystick/warrior.c
+@@ -64,15 +64,13 @@ struct warrior {
+ * Warrior. It updates the data accordingly.
+ */
+
+-static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs)
++static void warrior_process_packet(struct warrior *warrior)
+ {
+ struct input_dev *dev = warrior->dev;
+ unsigned char *data = warrior->data;
+
+ if (!warrior->idx) return;
+
+- input_regs(dev, regs);
+-
+ switch ((data[0] >> 4) & 7) {
+ case 1: /* Button data */
+ input_report_key(dev, BTN_TRIGGER, data[3] & 1);
+@@ -101,12 +99,12 @@ static void warrior_process_packet(struc
+ */
+
+ static irqreturn_t warrior_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct warrior *warrior = serio_get_drvdata(serio);
+
+ if (data & 0x80) {
+- if (warrior->idx) warrior_process_packet(warrior, regs);
++ if (warrior->idx) warrior_process_packet(warrior);
+ warrior->idx = 0;
+ warrior->len = warrior_lengths[(data >> 4) & 7];
+ }
+@@ -115,7 +113,7 @@ static irqreturn_t warrior_interrupt(str
+ warrior->data[warrior->idx++] = data;
+
+ if (warrior->idx == warrior->len) {
+- if (warrior->idx) warrior_process_packet(warrior, regs);
++ if (warrior->idx) warrior_process_packet(warrior);
+ warrior->idx = 0;
+ warrior->len = 0;
+ }
+diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
+index a9dda56..81a333f 100644
+--- a/drivers/input/keyboard/Kconfig
++++ b/drivers/input/keyboard/Kconfig
+@@ -121,6 +121,17 @@ config KEYBOARD_NEWTON
+ To compile this driver as a module, choose M here: the
+ module will be called newtonkbd.
+
++config KEYBOARD_STOWAWAY
++ tristate "Stowaway keyboard"
++ select SERIO
++ help
++ Say Y here if you have a Stowaway keyboard on a serial port.
++ Stowaway compatible keyboards like Dicota Input-PDA keyboard
++ are also supported by this driver.
++
++ To compile this driver as a module, choose M here: the
++ module will be called stowaway.
++
+ config KEYBOARD_CORGI
+ tristate "Corgi keyboard"
+ depends on PXA_SHARPSL
+@@ -155,7 +166,7 @@ config KEYBOARD_AMIGA
+
+ config KEYBOARD_HIL_OLD
+ tristate "HP HIL keyboard support (simple driver)"
+- depends on GSC
++ depends on GSC || HP300
+ default y
+ help
+ The "Human Interface Loop" is a older, 8-channel USB-like
+@@ -166,13 +177,13 @@ config KEYBOARD_HIL_OLD
+ However, it has been thoroughly tested and is stable.
+
+ If you want full HIL support including support for multiple
+- keyboards, mices and tablets, you have to enable the
++ keyboards, mice, and tablets, you have to enable the
+ "HP System Device Controller i8042 Support" in the input/serio
+ submenu.
+
+ config KEYBOARD_HIL
+ tristate "HP HIL keyboard support"
+- depends on GSC
++ depends on GSC || HP300
+ default y
+ select HP_SDC
+ select HIL_MLC
+@@ -183,4 +194,13 @@ config KEYBOARD_HIL
+ This driver implements support for HIL-keyboards attached
+ to your machine, so normally you should say Y here.
+
++config KEYBOARD_OMAP
++ tristate "TI OMAP keypad support"
++ depends on (ARCH_OMAP1 || ARCH_OMAP2)
++ help
++ Say Y here if you want to use the OMAP keypad.
++
++ To compile this driver as a module, choose M here: the
++ module will be called omap-keypad.
++
+ endif
+diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
+index 2708167..4c79e7b 100644
+--- a/drivers/input/keyboard/Makefile
++++ b/drivers/input/keyboard/Makefile
+@@ -11,8 +11,10 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
+ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
+ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
+ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
++obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
+ obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
+ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
+ obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
+ obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
++obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+
+diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
+index f1f9db9..8abdbd0 100644
+--- a/drivers/input/keyboard/amikbd.c
++++ b/drivers/input/keyboard/amikbd.c
+@@ -158,7 +158,7 @@ static const char *amikbd_messages[8] =
+
+ static struct input_dev *amikbd_dev;
+
+-static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t amikbd_interrupt(int irq, void *dummy)
+ {
+ unsigned char scancode, down;
+
+@@ -171,8 +171,6 @@ static irqreturn_t amikbd_interrupt(int
+ scancode >>= 1;
+
+ if (scancode < 0x78) { /* scancodes < 0x78 are keys */
+- input_regs(amikbd_dev, fp);
+-
+ if (scancode == 98) { /* CapsLock is a toggle switch key on Amiga */
+ input_report_key(amikbd_dev, scancode, 1);
+ input_report_key(amikbd_dev, scancode, 0);
+diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
+index a86afd0..cbb9366 100644
+--- a/drivers/input/keyboard/atkbd.c
++++ b/drivers/input/keyboard/atkbd.c
+@@ -221,6 +221,7 @@ struct atkbd {
+ unsigned long xl_bit;
+ unsigned int last;
+ unsigned long time;
++ unsigned long err_count;
+
+ struct work_struct event_work;
+ struct mutex event_mutex;
+@@ -234,11 +235,13 @@ static ssize_t atkbd_attr_set_helper(str
+ #define ATKBD_DEFINE_ATTR(_name) \
+ static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
+ static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
+-static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \
++static ssize_t atkbd_do_show_##_name(struct device *d, \
++ struct device_attribute *attr, char *b) \
+ { \
+ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
+ } \
+-static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \
++static ssize_t atkbd_do_set_##_name(struct device *d, \
++ struct device_attribute *attr, const char *b, size_t s) \
+ { \
+ return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
+ } \
+@@ -251,6 +254,32 @@ ATKBD_DEFINE_ATTR(set);
+ ATKBD_DEFINE_ATTR(softrepeat);
+ ATKBD_DEFINE_ATTR(softraw);
+
++#define ATKBD_DEFINE_RO_ATTR(_name) \
++static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
++static ssize_t atkbd_do_show_##_name(struct device *d, \
++ struct device_attribute *attr, char *b) \
++{ \
++ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
++} \
++static struct device_attribute atkbd_attr_##_name = \
++ __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
++
++ATKBD_DEFINE_RO_ATTR(err_count);
++
++static struct attribute *atkbd_attributes[] = {
++ &atkbd_attr_extra.attr,
++ &atkbd_attr_scroll.attr,
++ &atkbd_attr_set.attr,
++ &atkbd_attr_softrepeat.attr,
++ &atkbd_attr_softraw.attr,
++ &atkbd_attr_err_count.attr,
++ NULL
++};
++
++static struct attribute_group atkbd_attribute_group = {
++ .attrs = atkbd_attributes,
++};
++
+ static const unsigned int xl_table[] = {
+ ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
+ ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
+@@ -318,7 +347,7 @@ static unsigned int atkbd_compat_scancod
+ */
+
+ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
+- unsigned int flags, struct pt_regs *regs)
++ unsigned int flags)
+ {
+ struct atkbd *atkbd = serio_get_drvdata(serio);
+ struct input_dev *dev = atkbd->dev;
+@@ -396,7 +425,10 @@ static irqreturn_t atkbd_interrupt(struc
+ add_release_event = 1;
+ break;
+ case ATKBD_RET_ERR:
++ atkbd->err_count++;
++#ifdef ATKBD_DEBUG
+ printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
++#endif
+ goto out;
+ }
+
+@@ -458,7 +490,6 @@ static irqreturn_t atkbd_interrupt(struc
+ atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
+ }
+
+- input_regs(dev, regs);
+ input_event(dev, EV_KEY, keycode, value);
+ input_sync(dev);
+
+@@ -469,7 +500,6 @@ static irqreturn_t atkbd_interrupt(struc
+ }
+
+ if (atkbd->scroll) {
+- input_regs(dev, regs);
+ if (click != -1)
+ input_report_key(dev, BTN_MIDDLE, click);
+ input_report_rel(dev, REL_WHEEL, scroll);
+@@ -652,9 +682,7 @@ static int atkbd_probe(struct atkbd *atk
+ return 0;
+ }
+
+- if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */
+- param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */
+- param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */
++ if (!ps2_is_keyboard_id(param[0]))
+ return -1;
+
+ atkbd->id = (param[0] << 8) | param[1];
+@@ -790,12 +818,7 @@ static void atkbd_disconnect(struct seri
+ synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */
+ flush_scheduled_work();
+
+- device_remove_file(&serio->dev, &atkbd_attr_extra);
+- device_remove_file(&serio->dev, &atkbd_attr_scroll);
+- device_remove_file(&serio->dev, &atkbd_attr_set);
+- device_remove_file(&serio->dev, &atkbd_attr_softrepeat);
+- device_remove_file(&serio->dev, &atkbd_attr_softraw);
+-
++ sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
+ input_unregister_device(atkbd->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+@@ -965,11 +988,7 @@ static int atkbd_connect(struct serio *s
+ atkbd_set_keycode_table(atkbd);
+ atkbd_set_device_attrs(atkbd);
+
+- device_create_file(&serio->dev, &atkbd_attr_extra);
+- device_create_file(&serio->dev, &atkbd_attr_scroll);
+- device_create_file(&serio->dev, &atkbd_attr_set);
+- device_create_file(&serio->dev, &atkbd_attr_softrepeat);
+- device_create_file(&serio->dev, &atkbd_attr_softraw);
++ sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
+
+ atkbd_enable(atkbd);
+
+@@ -1263,6 +1282,11 @@ static ssize_t atkbd_set_softraw(struct
+ return count;
+ }
+
++static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
++{
++ return sprintf(buf, "%lu\n", atkbd->err_count);
++}
++
+
+ static int __init atkbd_init(void)
+ {
+diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
+index 1e03153..befdd60 100644
+--- a/drivers/input/keyboard/corgikbd.c
++++ b/drivers/input/keyboard/corgikbd.c
+@@ -129,7 +129,7 @@ static inline void corgikbd_reset_col(in
+ */
+
+ /* Scan the hardware keyboard and push any changes up through the input layer */
+-static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
++static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data)
+ {
+ unsigned int row, col, rowd;
+ unsigned long flags;
+@@ -140,9 +140,6 @@ static void corgikbd_scankeyboard(struct
+
+ spin_lock_irqsave(&corgikbd_data->lock, flags);
+
+- if (regs)
+- input_regs(corgikbd_data->input, regs);
+-
+ num_pressed = 0;
+ for (col = 0; col < KB_COLS; col++) {
+ /*
+@@ -191,14 +188,14 @@ static void corgikbd_scankeyboard(struct
+ /*
+ * corgi keyboard interrupt handler.
+ */
+-static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t corgikbd_interrupt(int irq, void *dev_id)
+ {
+ struct corgikbd *corgikbd_data = dev_id;
+
+ if (!timer_pending(&corgikbd_data->timer)) {
+ /** wait chattering delay **/
+ udelay(20);
+- corgikbd_scankeyboard(corgikbd_data, regs);
++ corgikbd_scankeyboard(corgikbd_data);
+ }
+
+ return IRQ_HANDLED;
+@@ -210,7 +207,7 @@ static irqreturn_t corgikbd_interrupt(in
+ static void corgikbd_timer_callback(unsigned long data)
+ {
+ struct corgikbd *corgikbd_data = (struct corgikbd *) data;
+- corgikbd_scankeyboard(corgikbd_data, NULL);
++ corgikbd_scankeyboard(corgikbd_data);
+ }
+
+ /*
+diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
+index 2e4abdc..e774dd3 100644
+--- a/drivers/input/keyboard/hil_kbd.c
++++ b/drivers/input/keyboard/hil_kbd.c
+@@ -198,7 +198,7 @@ static void hil_kbd_process_err(struct h
+ }
+
+ static irqreturn_t hil_kbd_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct hil_kbd *kbd;
+ hil_packet packet;
+@@ -328,7 +328,7 @@ static int hil_kbd_connect(struct serio
+ kbd->dev->id.vendor = PCI_VENDOR_ID_HP;
+ kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
+ kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
+- kbd->dev->dev = &serio->dev;
++ kbd->dev->cdev.dev = &serio->dev;
+
+ for (i = 0; i < 128; i++) {
+ set_bit(hil_kbd_set1[i], kbd->dev->keybit);
+diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
+index d22c7c6..54bc569 100644
+--- a/drivers/input/keyboard/hilkbd.c
++++ b/drivers/input/keyboard/hilkbd.c
+@@ -150,7 +150,7 @@ static inline void handle_data(unsigned
+ /*
+ * Handle HIL interrupts.
+ */
+-static irqreturn_t hil_interrupt(int irq, void *handle, struct pt_regs *regs)
++static irqreturn_t hil_interrupt(int irq, void *handle)
+ {
+ unsigned char s, c;
+
+diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
+index 5174224..708d5a1 100644
+--- a/drivers/input/keyboard/lkkbd.c
++++ b/drivers/input/keyboard/lkkbd.c
+@@ -453,8 +453,7 @@ lkkbd_detection_done (struct lkkbd *lk)
+ * is received.
+ */
+ static irqreturn_t
+-lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
+- struct pt_regs *regs)
++lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
+ {
+ struct lkkbd *lk = serio_get_drvdata (serio);
+ int i;
+@@ -473,7 +472,6 @@ lkkbd_interrupt (struct serio *serio, un
+
+ switch (data) {
+ case LK_ALL_KEYS_UP:
+- input_regs (lk->dev, regs);
+ for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++)
+ if (lk->keycode[i] != KEY_RESERVED)
+ input_report_key (lk->dev, lk->keycode[i], 0);
+@@ -501,7 +499,6 @@ lkkbd_interrupt (struct serio *serio, un
+
+ default:
+ if (lk->keycode[data] != KEY_RESERVED) {
+- input_regs (lk->dev, regs);
+ if (!test_bit (lk->keycode[data], lk->dev->key))
+ input_report_key (lk->dev, lk->keycode[data], 1);
+ else
+diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
+index 83906f8..5788dbc 100644
+--- a/drivers/input/keyboard/locomokbd.c
++++ b/drivers/input/keyboard/locomokbd.c
+@@ -126,7 +126,7 @@ static inline void locomokbd_reset_col(u
+ */
+
+ /* 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)
+ {
+ unsigned int row, col, rowd, scancode;
+ unsigned long flags;
+@@ -135,8 +135,6 @@ static void locomokbd_scankeyboard(struc
+
+ spin_lock_irqsave(&locomokbd->lock, flags);
+
+- input_regs(locomokbd->input, regs);
+-
+ locomokbd_charge_all(membase);
+
+ num_pressed = 0;
+@@ -171,13 +169,13 @@ static void locomokbd_scankeyboard(struc
+ /*
+ * LoCoMo keyboard interrupt handler.
+ */
+-static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
+ {
+ struct locomokbd *locomokbd = dev_id;
+ /** wait chattering delay **/
+ udelay(100);
+
+- locomokbd_scankeyboard(locomokbd, regs);
++ locomokbd_scankeyboard(locomokbd);
+
+ return IRQ_HANDLED;
+ }
+@@ -188,7 +186,7 @@ static irqreturn_t locomokbd_interrupt(i
+ static void locomokbd_timer_callback(unsigned long data)
+ {
+ struct locomokbd *locomokbd = (struct locomokbd *) data;
+- locomokbd_scankeyboard(locomokbd, NULL);
++ locomokbd_scankeyboard(locomokbd);
+ }
+
+ static int locomokbd_probe(struct locomo_dev *dev)
+diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
+index 40a3f55..9282e4e 100644
+--- a/drivers/input/keyboard/newtonkbd.c
++++ b/drivers/input/keyboard/newtonkbd.c
+@@ -65,13 +65,12 @@ struct nkbd {
+ };
+
+ static irqreturn_t nkbd_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct nkbd *nkbd = serio_get_drvdata(serio);
+
+ /* invalid scan codes are probably the init sequence, so we ignore them */
+ if (nkbd->keycode[data & NKBD_KEY]) {
+- input_regs(nkbd->dev, regs);
+ input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
+ input_sync(nkbd->dev);
+ }
+diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
+new file mode 100644
+index 0000000..5680a6d
+--- /dev/null
++++ b/drivers/input/keyboard/omap-keypad.c
+@@ -0,0 +1,491 @@
++/*
++ * linux/drivers/input/keyboard/omap-keypad.c
++ *
++ * OMAP Keypad Driver
++ *
++ * Copyright (C) 2003 Nokia Corporation
++ * Written by Timo Teräs <ext-timo.teras at nokia.com>
++ *
++ * Added support for H2 & H3 Keypad
++ * Copyright (C) 2004 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This 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/init.h>
++#include <linux/interrupt.h>
++#include <linux/types.h>
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/mutex.h>
++#include <linux/errno.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/keypad.h>
++#include <asm/arch/menelaus.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/mach-types.h>
++#include <asm/arch/mux.h>
++
++#undef NEW_BOARD_LEARNING_MODE
++
++static void omap_kp_tasklet(unsigned long);
++static void omap_kp_timer(unsigned long);
++
++static unsigned char keypad_state[8];
++static DEFINE_MUTEX(kp_enable_mutex);
++static int kp_enable = 1;
++static int kp_cur_group = -1;
++
++struct omap_kp {
++ struct input_dev *input;
++ struct timer_list timer;
++ int irq;
++ unsigned int rows;
++ unsigned int cols;
++ unsigned long delay;
++ unsigned int debounce;
++};
++
++DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
++
++static int *keymap;
++static unsigned int *row_gpios;
++static unsigned int *col_gpios;
++
++#ifdef CONFIG_ARCH_OMAP2
++static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
++{
++ int col;
++ for (col = 0; col < omap_kp->cols; col++) {
++ if (value & (1 << col))
++ omap_set_gpio_dataout(col_gpios[col], 1);
++ else
++ omap_set_gpio_dataout(col_gpios[col], 0);
++ }
++}
++
++static u8 get_row_gpio_val(struct omap_kp *omap_kp)
++{
++ int row;
++ u8 value = 0;
++
++ for (row = 0; row < omap_kp->rows; row++) {
++ if (omap_get_gpio_datain(row_gpios[row]))
++ value |= (1 << row);
++ }
++ return value;
++}
++#else
++#define set_col_gpio_val(x, y) do {} while (0)
++#define get_row_gpio_val(x) 0
++#endif
++
++static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
++{
++ struct omap_kp *omap_kp = dev_id;
++
++ /* disable keyboard interrupt and schedule for handling */
++ if (cpu_is_omap24xx()) {
++ int i;
++ for (i = 0; i < omap_kp->rows; i++)
++ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
++ } else
++ /* disable keyboard interrupt and schedule for handling */
++ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
++
++ tasklet_schedule(&kp_tasklet);
++
++ return IRQ_HANDLED;
++}
++
++static void omap_kp_timer(unsigned long data)
++{
++ tasklet_schedule(&kp_tasklet);
++}
++
++static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
++{
++ int col = 0;
++
++ /* read the keypad status */
++ if (cpu_is_omap24xx()) {
++ int i;
++ for (i = 0; i < omap_kp->rows; i++)
++ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
++
++ /* read the keypad status */
++ for (col = 0; col < omap_kp->cols; col++) {
++ set_col_gpio_val(omap_kp, ~(1 << col));
++ state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f;
++ }
++ set_col_gpio_val(omap_kp, 0);
++
++ } else {
++ /* disable keyboard interrupt and schedule for handling */
++ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
++
++ /* read the keypad status */
++ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
++ for (col = 0; col < omap_kp->cols; col++) {
++ omap_writew(~(1 << col) & 0xff,
++ OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
++
++ udelay(omap_kp->delay);
++
++ state[col] = ~omap_readw(OMAP_MPUIO_BASE +
++ OMAP_MPUIO_KBR_LATCH) & 0xff;
++ }
++ omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
++ udelay(2);
++ }
++}
++
++static inline int omap_kp_find_key(int col, int row)
++{
++ int i, key;
++
++ key = KEY(col, row, 0);
++ for (i = 0; keymap[i] != 0; i++)
++ if ((keymap[i] & 0xff000000) == key)
++ return keymap[i] & 0x00ffffff;
++ return -1;
++}
++
++static void omap_kp_tasklet(unsigned long data)
++{
++ struct omap_kp *omap_kp_data = (struct omap_kp *) data;
++ unsigned char new_state[8], changed, key_down = 0;
++ int col, row;
++ int spurious = 0;
++
++ /* check for any changes */
++ omap_kp_scan_keypad(omap_kp_data, new_state);
++
++ /* check for changes and print those */
++ for (col = 0; col < omap_kp_data->cols; col++) {
++ changed = new_state[col] ^ keypad_state[col];
++ key_down |= new_state[col];
++ if (changed == 0)
++ continue;
++
++ for (row = 0; row < omap_kp_data->rows; row++) {
++ int key;
++ if (!(changed & (1 << row)))
++ continue;
++#ifdef NEW_BOARD_LEARNING_MODE
++ printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
++ row, (new_state[col] & (1 << row)) ?
++ "pressed" : "released");
++#else
++ key = omap_kp_find_key(col, row);
++ if (key < 0) {
++ printk(KERN_WARNING
++ "omap-keypad: Spurious key event %d-%d\n",
++ col, row);
++ /* We scan again after a couple of seconds */
++ spurious = 1;
++ continue;
++ }
++
++ if (!(kp_cur_group == (key & GROUP_MASK) ||
++ kp_cur_group == -1))
++ continue;
++
++ kp_cur_group = key & GROUP_MASK;
++ input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
++ new_state[col] & (1 << row));
++#endif
++ }
++ }
++ memcpy(keypad_state, new_state, sizeof(keypad_state));
++
++ if (key_down) {
++ int delay = HZ / 20;
++ /* some key is pressed - keep irq disabled and use timer
++ * to poll the keypad */
++ if (spurious)
++ delay = 2 * HZ;
++ mod_timer(&omap_kp_data->timer, jiffies + delay);
++ } else {
++ /* enable interrupts */
++ if (cpu_is_omap24xx()) {
++ int i;
++ for (i = 0; i < omap_kp_data->rows; i++)
++ enable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
++ } else {
++ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
++ kp_cur_group = -1;
++ }
++ }
++}
++
++static ssize_t omap_kp_enable_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%u\n", kp_enable);
++}
++
++static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int state;
++
++ if (sscanf(buf, "%u", &state) != 1)
++ return -EINVAL;
++
++ if ((state != 1) && (state != 0))
++ return -EINVAL;
++
++ mutex_lock(&kp_enable_mutex);
++ if (state != kp_enable) {
++ if (state)
++ enable_irq(INT_KEYBOARD);
++ else
++ disable_irq(INT_KEYBOARD);
++ kp_enable = state;
++ }
++ mutex_unlock(&kp_enable_mutex);
++
++ return strnlen(buf, count);
++}
++
++static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
++
++#ifdef CONFIG_PM
++static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
++{
++ /* Nothing yet */
++
++ return 0;
++}
++
++static int omap_kp_resume(struct platform_device *dev)
++{
++ /* Nothing yet */
++
++ return 0;
++}
++#else
++#define omap_kp_suspend NULL
++#define omap_kp_resume NULL
++#endif
++
++static int __init omap_kp_probe(struct platform_device *pdev)
++{
++ struct omap_kp *omap_kp;
++ struct input_dev *input_dev;
++ struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
++ int i, col_idx, row_idx, irq_idx, ret;
++
++ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
++ printk(KERN_ERR "No rows, cols or keymap from pdata\n");
++ return -EINVAL;
++ }
++
++ omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!omap_kp || !input_dev) {
++ kfree(omap_kp);
++ input_free_device(input_dev);
++ return -ENOMEM;
++ }
++
++ platform_set_drvdata(pdev, omap_kp);
++
++ omap_kp->input = input_dev;
++
++ /* Disable the interrupt for the MPUIO keyboard */
++ if (!cpu_is_omap24xx())
++ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
++
++ keymap = pdata->keymap;
++
++ if (pdata->rep)
++ set_bit(EV_REP, input_dev->evbit);
++
++ if (pdata->delay)
++ omap_kp->delay = pdata->delay;
++
++ if (pdata->row_gpios && pdata->col_gpios) {
++ row_gpios = pdata->row_gpios;
++ col_gpios = pdata->col_gpios;
++ }
++
++ omap_kp->rows = pdata->rows;
++ omap_kp->cols = pdata->cols;
++
++ if (cpu_is_omap24xx()) {
++ /* Cols: outputs */
++ for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
++ if (omap_request_gpio(col_gpios[col_idx]) < 0) {
++ printk(KERN_ERR "Failed to request"
++ "GPIO%d for keypad\n",
++ col_gpios[col_idx]);
++ goto err1;
++ }
++ omap_set_gpio_direction(col_gpios[col_idx], 0);
++ }
++ /* Rows: inputs */
++ for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
++ if (omap_request_gpio(row_gpios[row_idx]) < 0) {
++ printk(KERN_ERR "Failed to request"
++ "GPIO%d for keypad\n",
++ row_gpios[row_idx]);
++ goto err2;
++ }
++ omap_set_gpio_direction(row_gpios[row_idx], 1);
++ }
++ }
++
++ setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
++
++ /* get the irq and init timer*/
++ tasklet_enable(&kp_tasklet);
++ kp_tasklet.data = (unsigned long) omap_kp;
++
++ ret = device_create_file(&pdev->dev, &dev_attr_enable);
++ if (ret < 0)
++ goto err2;
++
++ /* setup input device */
++ set_bit(EV_KEY, input_dev->evbit);
++ for (i = 0; keymap[i] != 0; i++)
++ set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
++ input_dev->name = "omap-keypad";
++ input_dev->phys = "omap-keypad/input0";
++ input_dev->cdev.dev = &pdev->dev;
++ input_dev->private = omap_kp;
++
++ input_dev->id.bustype = BUS_HOST;
++ input_dev->id.vendor = 0x0001;
++ input_dev->id.product = 0x0001;
++ input_dev->id.version = 0x0100;
++
++ input_dev->keycode = keymap;
++ input_dev->keycodesize = sizeof(unsigned int);
++ input_dev->keycodemax = pdata->keymapsize;
++
++ ret = input_register_device(omap_kp->input);
++ if (ret < 0) {
++ printk(KERN_ERR "Unable to register omap-keypad input device\n");
++ goto err3;
++ }
++
++ if (pdata->dbounce)
++ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
++
++ /* scan current status and enable interrupt */
++ omap_kp_scan_keypad(omap_kp, keypad_state);
++ if (!cpu_is_omap24xx()) {
++ omap_kp->irq = platform_get_irq(pdev, 0);
++ if (omap_kp->irq >= 0) {
++ if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
++ "omap-keypad", omap_kp) < 0)
++ goto err4;
++ }
++ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
++ } else {
++ for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
++ if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
++ omap_kp_interrupt,
++ IRQF_TRIGGER_FALLING,
++ "omap-keypad", omap_kp) < 0)
++ goto err5;
++ }
++ }
++ return 0;
++err5:
++ for (i = irq_idx-1; i >=0; i--)
++ free_irq(row_gpios[i], 0);
++err4:
++ input_unregister_device(omap_kp->input);
++ input_dev = NULL;
++err3:
++ device_remove_file(&pdev->dev, &dev_attr_enable);
++err2:
++ for (i = row_idx-1; i >=0; i--)
++ omap_free_gpio(row_gpios[i]);
++err1:
++ for (i = col_idx-1; i >=0; i--)
++ omap_free_gpio(col_gpios[i]);
++
++ kfree(omap_kp);
++ input_free_device(input_dev);
++
++ return -EINVAL;
++}
++
++static int omap_kp_remove(struct platform_device *pdev)
++{
++ struct omap_kp *omap_kp = platform_get_drvdata(pdev);
++
++ /* disable keypad interrupt handling */
++ tasklet_disable(&kp_tasklet);
++ if (cpu_is_omap24xx()) {
++ int i;
++ for (i = 0; i < omap_kp->cols; i++)
++ omap_free_gpio(col_gpios[i]);
++ for (i = 0; i < omap_kp->rows; i++) {
++ omap_free_gpio(row_gpios[i]);
++ free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
++ }
++ } else {
++ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
++ free_irq(omap_kp->irq, 0);
++ }
++
++ del_timer_sync(&omap_kp->timer);
++ tasklet_kill(&kp_tasklet);
++
++ /* unregister everything */
++ input_unregister_device(omap_kp->input);
++
++ kfree(omap_kp);
++
++ return 0;
++}
++
++static struct platform_driver omap_kp_driver = {
++ .probe = omap_kp_probe,
++ .remove = omap_kp_remove,
++ .suspend = omap_kp_suspend,
++ .resume = omap_kp_resume,
++ .driver = {
++ .name = "omap-keypad",
++ },
++};
++
++static int __devinit omap_kp_init(void)
++{
++ printk(KERN_INFO "OMAP Keypad Driver\n");
++ return platform_driver_register(&omap_kp_driver);
++}
++
++static void __exit omap_kp_exit(void)
++{
++ platform_driver_unregister(&omap_kp_driver);
++}
++
++module_init(omap_kp_init);
++module_exit(omap_kp_exit);
++
++MODULE_AUTHOR("Timo Teräs");
++MODULE_DESCRIPTION("OMAP Keypad Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
+index e385710..28b2748 100644
+--- a/drivers/input/keyboard/spitzkbd.c
++++ b/drivers/input/keyboard/spitzkbd.c
+@@ -176,7 +176,7 @@ static inline int spitzkbd_get_row_statu
+ */
+
+ /* Scan the hardware keyboard and push any changes up through the input layer */
+-static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs)
++static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data)
+ {
+ unsigned int row, col, rowd;
+ unsigned long flags;
+@@ -187,8 +187,6 @@ static void spitzkbd_scankeyboard(struct
+
+ spin_lock_irqsave(&spitzkbd_data->lock, flags);
+
+- input_regs(spitzkbd_data->input, regs);
+-
+ num_pressed = 0;
+ for (col = 0; col < KB_COLS; col++) {
+ /*
+@@ -239,14 +237,14 @@ static void spitzkbd_scankeyboard(struct
+ /*
+ * spitz keyboard interrupt handler.
+ */
+-static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id)
+ {
+ struct spitzkbd *spitzkbd_data = dev_id;
+
+ if (!timer_pending(&spitzkbd_data->timer)) {
+ /** wait chattering delay **/
+ udelay(20);
+- spitzkbd_scankeyboard(spitzkbd_data, regs);
++ spitzkbd_scankeyboard(spitzkbd_data);
+ }
+
+ return IRQ_HANDLED;
+@@ -259,7 +257,7 @@ static void spitzkbd_timer_callback(unsi
+ {
+ struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
+
+- spitzkbd_scankeyboard(spitzkbd_data, NULL);
++ spitzkbd_scankeyboard(spitzkbd_data);
+ }
+
+ /*
+@@ -267,7 +265,7 @@ static void spitzkbd_timer_callback(unsi
+ * We debounce the switches and pass them to the input system.
+ */
+
+-static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id)
+ {
+ struct spitzkbd *spitzkbd_data = dev_id;
+
+diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
+new file mode 100644
+index 0000000..e60937d
+--- /dev/null
++++ b/drivers/input/keyboard/stowaway.c
+@@ -0,0 +1,186 @@
++/*
++ * Stowaway keyboard driver for Linux
++ */
++
++/*
++ * Copyright (c) 2006 Marek Vasut
++ *
++ * Based on Newton keyboard driver for Linux
++ * by Justin Cormack
++ */
++
++/*
++ * 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 <marek.vasut at gmail.com>, or by paper mail:
++ * Marek Vasut, Liskovecka 559, Frydek-Mistek, 738 01 Czech Republic
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/serio.h>
++
++#define DRIVER_DESC "Stowaway keyboard driver"
++
++MODULE_AUTHOR("Marek Vasut <marek.vasut at gmail.com>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++#define SKBD_KEY_MASK 0x7f
++#define SKBD_RELEASE 0x80
++
++static unsigned char skbd_keycode[128] = {
++ KEY_1, KEY_2, KEY_3, KEY_Z, KEY_4, KEY_5, KEY_6, KEY_7,
++ 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_GRAVE,
++ KEY_X, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_SPACE,
++ KEY_CAPSLOCK, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0,
++ 0, 0, 0, KEY_LEFTALT, 0, 0, 0, 0,
++ 0, 0, 0, 0, KEY_C, KEY_V, KEY_B, KEY_N,
++ KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_HOME, KEY_8, KEY_9, KEY_0, KEY_ESC,
++ KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_END, KEY_U, KEY_I, KEY_O, KEY_P,
++ KEY_APOSTROPHE, KEY_ENTER, KEY_PAGEUP,0, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON,
++ KEY_SLASH, KEY_UP, KEY_PAGEDOWN, 0,KEY_M, KEY_COMMA, KEY_DOT, KEY_INSERT,
++ KEY_DELETE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0,
++ KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7,
++ KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0
++};
++
++struct skbd {
++ unsigned char keycode[128];
++ struct input_dev *dev;
++ struct serio *serio;
++ char phys[32];
++};
++
++static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data,
++ unsigned int flags)
++{
++ struct skbd *skbd = serio_get_drvdata(serio);
++ struct input_dev *dev = skbd->dev;
++
++ if (skbd->keycode[data & SKBD_KEY_MASK]) {
++ input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK],
++ !(data & SKBD_RELEASE));
++ input_sync(dev);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int skbd_connect(struct serio *serio, struct serio_driver *drv)
++{
++ struct skbd *skbd;
++ struct input_dev *input_dev;
++ int err = -ENOMEM;
++ int i;
++
++ skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!skbd || !input_dev)
++ goto fail1;
++
++ skbd->serio = serio;
++ skbd->dev = input_dev;
++ snprintf(skbd->phys, sizeof(skbd->phys), "%s/input0", serio->phys);
++ memcpy(skbd->keycode, skbd_keycode, sizeof(skbd->keycode));
++
++ input_dev->name = "Stowaway Keyboard";
++ input_dev->phys = skbd->phys;
++ input_dev->id.bustype = BUS_RS232;
++ input_dev->id.vendor = SERIO_STOWAWAY;
++ input_dev->id.product = 0x0001;
++ input_dev->id.version = 0x0100;
++ input_dev->cdev.dev = &serio->dev;
++ input_dev->private = skbd;
++
++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
++ input_dev->keycode = skbd->keycode;
++ input_dev->keycodesize = sizeof(unsigned char);
++ input_dev->keycodemax = ARRAY_SIZE(skbd_keycode);
++ for (i = 0; i < ARRAY_SIZE(skbd_keycode); i++)
++ set_bit(skbd_keycode[i], input_dev->keybit);
++ clear_bit(0, input_dev->keybit);
++
++ serio_set_drvdata(serio, skbd);
++
++ err = serio_open(serio, drv);
++ if (err)
++ goto fail2;
++
++ err = input_register_device(skbd->dev);
++ if (err)
++ goto fail3;
++
++ return 0;
++
++ fail3: serio_close(serio);
++ fail2: serio_set_drvdata(serio, NULL);
++ fail1: input_free_device(input_dev);
++ kfree(skbd);
++ return err;
++}
++
++static void skbd_disconnect(struct serio *serio)
++{
++ struct skbd *skbd = serio_get_drvdata(serio);
++
++ serio_close(serio);
++ serio_set_drvdata(serio, NULL);
++ input_unregister_device(skbd->dev);
++ kfree(skbd);
++}
++
++static struct serio_device_id skbd_serio_ids[] = {
++ {
++ .type = SERIO_RS232,
++ .proto = SERIO_STOWAWAY,
++ .id = SERIO_ANY,
++ .extra = SERIO_ANY,
++ },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(serio, skbd_serio_ids);
++
++static struct serio_driver skbd_drv = {
++ .driver = {
++ .name = "stowaway",
++ },
++ .description = DRIVER_DESC,
++ .id_table = skbd_serio_ids,
++ .interrupt = skbd_interrupt,
++ .connect = skbd_connect,
++ .disconnect = skbd_disconnect,
++};
++
++static int __init skbd_init(void)
++{
++ serio_register_driver(&skbd_drv);
++ return 0;
++}
++
++static void __exit skbd_exit(void)
++{
++ serio_unregister_driver(&skbd_drv);
++}
++
++module_init(skbd_init);
++module_exit(skbd_exit);
+diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
+index 9dbd7b8..cac4781 100644
+--- a/drivers/input/keyboard/sunkbd.c
++++ b/drivers/input/keyboard/sunkbd.c
+@@ -94,7 +94,7 @@ struct sunkbd {
+ */
+
+ static irqreturn_t sunkbd_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct sunkbd* sunkbd = serio_get_drvdata(serio);
+
+@@ -129,7 +129,6 @@ static irqreturn_t sunkbd_interrupt(stru
+ break;
+
+ if (sunkbd->keycode[data & SUNKBD_KEY]) {
+- input_regs(sunkbd->dev, regs);
+ input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
+ input_sync(sunkbd->dev);
+ } else {
+diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
+index 0821d53..8c11dc9 100644
+--- a/drivers/input/keyboard/xtkbd.c
++++ b/drivers/input/keyboard/xtkbd.c
+@@ -64,7 +64,7 @@ struct xtkbd {
+ };
+
+ static irqreturn_t xtkbd_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct xtkbd *xtkbd = serio_get_drvdata(serio);
+
+@@ -75,7 +75,6 @@ static irqreturn_t xtkbd_interrupt(struc
+ default:
+
+ if (xtkbd->keycode[data & XTKBD_KEY]) {
+- input_regs(xtkbd->dev, regs);
+ input_report_key(xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
+ input_sync(xtkbd->dev);
+ } else {
+diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
+index a6dfc74..ba0e88c 100644
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -73,7 +73,7 @@ config INPUT_UINPUT
+
+ config HP_SDC_RTC
+ tristate "HP SDC Real Time Clock"
+- depends on GSC
++ depends on GSC || HP300
+ select HP_SDC
+ help
+ Say Y here if you want to support the built-in real time clock
+diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
+index 1be9639..ab4da79 100644
+--- a/drivers/input/misc/hp_sdc_rtc.c
++++ b/drivers/input/misc/hp_sdc_rtc.c
+@@ -60,7 +60,7 @@ static struct fasync_struct *hp_sdc_rtc_
+
+ static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
+
+-static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
++static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos);
+
+ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
+@@ -385,14 +385,14 @@ static int hp_sdc_rtc_set_i8042timer (st
+ return 0;
+ }
+
+-static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
++static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos) {
+ ssize_t retval;
+
+ if (count < sizeof(unsigned long))
+ return -EINVAL;
+
+- retval = put_user(68, (unsigned long *)buf);
++ retval = put_user(68, (unsigned long __user *)buf);
+ return retval;
+ }
+
+@@ -696,7 +696,7 @@ static int __init hp_sdc_rtc_init(void)
+ if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
+ return ret;
+ misc_register(&hp_sdc_rtc_dev);
+- create_proc_read_entry ("driver/rtc", 0, 0,
++ create_proc_read_entry ("driver/rtc", 0, NULL,
+ hp_sdc_rtc_read_proc, NULL);
+
+ printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "
+diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
+index 805b636..105c6fc 100644
+--- a/drivers/input/misc/ixp4xx-beeper.c
++++ b/drivers/input/misc/ixp4xx-beeper.c
+@@ -79,7 +79,7 @@ static int ixp4xx_spkr_event(struct inpu
+ return 0;
+ }
+
+-static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
+ {
+ /* clear interrupt */
+ *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
+diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
+index d723e9a..9516439 100644
+--- a/drivers/input/misc/uinput.c
++++ b/drivers/input/misc/uinput.c
+@@ -20,6 +20,9 @@
+ * Author: Aristeu Sergio Rozanski Filho <aris at cathedrallabs.org>
+ *
+ * Changes/Revisions:
++ * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula at gmail.com>)
++ * - updated ff support for the changes in kernel interface
++ * - added MODULE_VERSION
+ * 0.2 16/10/2004 (Micah Dowty <micah at navi.cx>)
+ * - added force feedback support
+ * - added UI_SET_PHYS
+@@ -107,18 +110,31 @@ static int uinput_request_submit(struct
+ return request->retval;
+ }
+
+-static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
++static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
++{
++ uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
++}
++
++static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
++{
++ uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
++}
++
++static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
++{
++ return uinput_dev_event(dev, EV_FF, effect_id, value);
++}
++
++static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
+ {
+ struct uinput_request request;
+ int retval;
+
+- if (!test_bit(EV_FF, dev->evbit))
+- return -ENOSYS;
+-
+ request.id = -1;
+ init_completion(&request.done);
+ request.code = UI_FF_UPLOAD;
+- request.u.effect = effect;
++ request.u.upload.effect = effect;
++ request.u.upload.old = old;
+
+ retval = uinput_request_reserve_slot(dev->private, &request);
+ if (!retval)
+@@ -168,6 +184,7 @@ static void uinput_destroy_device(struct
+
+ static int uinput_create_device(struct uinput_device *udev)
+ {
++ struct input_dev *dev = udev->dev;
+ int error;
+
+ if (udev->state != UIST_SETUP_COMPLETE) {
+@@ -175,15 +192,29 @@ static int uinput_create_device(struct u
+ return -EINVAL;
+ }
+
+- error = input_register_device(udev->dev);
+- if (error) {
+- uinput_destroy_device(udev);
+- return error;
++ if (udev->ff_effects_max) {
++ error = input_ff_create(dev, udev->ff_effects_max);
++ if (error)
++ goto fail1;
++
++ dev->ff->upload = uinput_dev_upload_effect;
++ dev->ff->erase = uinput_dev_erase_effect;
++ dev->ff->playback = uinput_dev_playback;
++ dev->ff->set_gain = uinput_dev_set_gain;
++ dev->ff->set_autocenter = uinput_dev_set_autocenter;
+ }
+
++ error = input_register_device(udev->dev);
++ if (error)
++ goto fail2;
++
+ udev->state = UIST_CREATED;
+
+ return 0;
++
++ fail2: input_ff_destroy(dev);
++ fail1: uinput_destroy_device(udev);
++ return error;
+ }
+
+ static int uinput_open(struct inode *inode, struct file *file)
+@@ -243,8 +274,6 @@ static int uinput_allocate_device(struct
+ return -ENOMEM;
+
+ udev->dev->event = uinput_dev_event;
+- udev->dev->upload_effect = uinput_dev_upload_effect;
+- udev->dev->erase_effect = uinput_dev_erase_effect;
+ udev->dev->private = udev;
+
+ return 0;
+@@ -278,6 +307,8 @@ static int uinput_setup_device(struct ui
+ goto exit;
+ }
+
++ udev->ff_effects_max = user_dev->ff_effects_max;
++
+ size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
+ if (!size) {
+ retval = -EINVAL;
+@@ -296,7 +327,6 @@ static int uinput_setup_device(struct ui
+ dev->id.vendor = user_dev->id.vendor;
+ dev->id.product = user_dev->id.product;
+ dev->id.version = user_dev->id.version;
+- dev->ff_effects_max = user_dev->ff_effects_max;
+
+ size = sizeof(int) * (ABS_MAX + 1);
+ memcpy(dev->absmax, user_dev->absmax, size);
+@@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *fi
+ break;
+ }
+ req = uinput_request_find(udev, ff_up.request_id);
+- if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
++ if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
+ retval = -EINVAL;
+ break;
+ }
+ ff_up.retval = 0;
+- memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect));
++ memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect));
++ if (req->u.upload.old)
++ memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect));
++ else
++ memset(&ff_up.old, 0, sizeof(struct ff_effect));
++
+ if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
+ retval = -EFAULT;
+ break;
+@@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *fi
+ break;
+ }
+ req = uinput_request_find(udev, ff_up.request_id);
+- if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
++ if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
+ retval = -EINVAL;
+ break;
+ }
+ req->retval = ff_up.retval;
+- memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
+ uinput_request_done(udev, req);
+ break;
+
+@@ -622,6 +656,7 @@ static void __exit uinput_exit(void)
+ MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
+ MODULE_DESCRIPTION("User level driver support for input subsystem");
+ MODULE_LICENSE("GPL");
++MODULE_VERSION("0.3");
+
+ module_init(uinput_init);
+ module_exit(uinput_exit);
+diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
+index de0f46d..7b9d1c1 100644
+--- a/drivers/input/misc/wistron_btns.c
++++ b/drivers/input/misc/wistron_btns.c
+@@ -17,7 +17,7 @@
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
+ */
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <linux/dmi.h>
+ #include <linux/init.h>
+ #include <linux/input.h>
+@@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi
+
+ keymap = dmi->driver_data;
+ for (key = keymap; key->type != KE_END; key++) {
+- if (key->type == KE_WIFI) {
++ if (key->type == KE_WIFI)
+ have_wifi = 1;
+- break;
+- } else if (key->type == KE_BLUETOOTH) {
++ else if (key->type == KE_BLUETOOTH)
+ have_bluetooth = 1;
+- break;
+- }
+ }
+ return 1;
+ }
+@@ -389,7 +386,16 @@ static struct dmi_system_id dmi_ids[] __
+ },
+ .driver_data = keymap_acer_travelmate_240
+ },
+- {
++ {
++ .callback = dmi_matched,
++ .ident = "Acer TravelMate 2424NWXCi",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
++ },
++ .driver_data = keymap_acer_travelmate_240
++ },
++ {
+ .callback = dmi_matched,
+ .ident = "AOpen 1559AS",
+ .matches = {
+diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
+index f15ccf7..35d998c 100644
+--- a/drivers/input/mouse/Kconfig
++++ b/drivers/input/mouse/Kconfig
+@@ -119,7 +119,7 @@ config MOUSE_VSXXXAA
+
+ config MOUSE_HIL
+ tristate "HIL pointers (mice etc)."
+- depends on GSC
++ depends on GSC || HP300
+ select HP_SDC
+ select HIL_MLC
+ help
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 070d753..4e71a66 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -36,7 +36,7 @@
+ #define ALPS_PASS 0x20
+ #define ALPS_FW_BK_2 0x40
+
+-static struct alps_model_info alps_model_data[] = {
++static const struct alps_model_info alps_model_data[] = {
+ { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
+ { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
+ { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
+@@ -76,7 +76,7 @@ static struct alps_model_info alps_model
+ * on a dualpoint, etc.
+ */
+
+-static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
++static void alps_process_packet(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+@@ -85,8 +85,6 @@ static void alps_process_packet(struct p
+ 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_RIGHT, packet[0] & 2);
+@@ -181,13 +179,13 @@ static void alps_process_packet(struct p
+ input_sync(dev);
+ }
+
+-static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+
+ if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
+ if (psmouse->pktcnt == 3) {
+- alps_process_packet(psmouse, regs);
++ alps_process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+ return PSMOUSE_GOOD_DATA;
+@@ -202,17 +200,17 @@ static psmouse_ret_t alps_process_byte(s
+ return PSMOUSE_BAD_DATA;
+
+ if (psmouse->pktcnt == 6) {
+- alps_process_packet(psmouse, regs);
++ alps_process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+
+ return PSMOUSE_GOOD_DATA;
+ }
+
+-static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
++static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
+ {
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+- unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
++ static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
+ unsigned char param[4];
+ int i;
+
+@@ -504,7 +502,7 @@ init_fail:
+ int alps_detect(struct psmouse *psmouse, int set_properties)
+ {
+ int version;
+- struct alps_model_info *model;
++ const struct alps_model_info *model;
+
+ if (!(model = alps_get_model(psmouse, &version)))
+ return -1;
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index e428f8d..69db732 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -25,7 +25,7 @@ struct alps_data {
+ struct input_dev *dev2; /* Relative device */
+ char name[32]; /* Name */
+ char phys[32]; /* Phys */
+- struct alps_model_info *i; /* Info */
++ const struct alps_model_info *i;/* Info */
+ int prev_fin; /* Finger bit from previous packet */
+ };
+
+diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
+index c8b2cc9..599a7b2 100644
+--- a/drivers/input/mouse/amimouse.c
++++ b/drivers/input/mouse/amimouse.c
+@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
+ static int amimouse_lastx, amimouse_lasty;
+ static struct input_dev *amimouse_dev;
+
+-static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t amimouse_interrupt(int irq, void *dummy)
+ {
+ unsigned short joy0dat, potgor;
+ int nx, ny, dx, dy;
+@@ -59,8 +59,6 @@ static irqreturn_t amimouse_interrupt(in
+
+ potgor = amiga_custom.potgor;
+
+- input_regs(amimouse_dev, fp);
+-
+ input_report_rel(amimouse_dev, REL_X, dx);
+ input_report_rel(amimouse_dev, REL_Y, dy);
+
+diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
+index 69f0217..4f2b503 100644
+--- a/drivers/input/mouse/hil_ptr.c
++++ b/drivers/input/mouse/hil_ptr.c
+@@ -190,7 +190,7 @@ static void hil_ptr_process_err(struct h
+ }
+
+ static irqreturn_t hil_ptr_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct hil_ptr *ptr;
+ hil_packet packet;
+@@ -375,7 +375,7 @@ static int hil_ptr_connect(struct serio
+ ptr->dev->id.vendor = PCI_VENDOR_ID_HP;
+ ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */
+ ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */
+- ptr->dev->dev = &serio->dev;
++ ptr->dev->cdev.dev = &serio->dev;
+
+ input_register_device(ptr->dev);
+ printk(KERN_INFO "input: %s (%s), ID: %d\n",
+diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
+index 50f1fed..e1252fa 100644
+--- a/drivers/input/mouse/inport.c
++++ b/drivers/input/mouse/inport.c
+@@ -88,15 +88,13 @@ __obsolete_setup("inport_irq=");
+
+ static struct input_dev *inport_dev;
+
+-static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t inport_interrupt(int irq, void *dev_id)
+ {
+ unsigned char buttons;
+
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+- input_regs(inport_dev, regs);
+-
+ outb(INPORT_REG_X, INPORT_CONTROL_PORT);
+ input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
+
+diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
+index c14395b..c57e885 100644
+--- a/drivers/input/mouse/lifebook.c
++++ b/drivers/input/mouse/lifebook.c
+@@ -62,7 +62,7 @@ static struct dmi_system_id lifebook_dmi
+ };
+
+
+-static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
+ {
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+@@ -70,8 +70,6 @@ static psmouse_ret_t lifebook_process_by
+ 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,
+@@ -115,13 +113,15 @@ static int lifebook_absolute_mode(struct
+
+ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+ {
+- unsigned char params[] = { 0, 1, 2, 2, 3 };
++ static const unsigned char params[] = { 0, 1, 2, 2, 3 };
++ unsigned char p;
+
+ if (resolution == 0 || resolution > 400)
+ resolution = 400;
+
+- ps2_command(&psmouse->ps2dev, ¶ms[resolution / 100], PSMOUSE_CMD_SETRES);
+- psmouse->resolution = 50 << params[resolution / 100];
++ p = params[resolution / 100];
++ ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
++ psmouse->resolution = 50 << p;
+ }
+
+ static void lifebook_disconnect(struct psmouse *psmouse)
+diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
+index 9c7ce38..8e9c2f3 100644
+--- a/drivers/input/mouse/logibm.c
++++ b/drivers/input/mouse/logibm.c
+@@ -79,7 +79,7 @@ __obsolete_setup("logibm_irq=");
+
+ static struct input_dev *logibm_dev;
+
+-static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t logibm_interrupt(int irq, void *dev_id)
+ {
+ char dx, dy;
+ unsigned char buttons;
+@@ -95,7 +95,6 @@ static irqreturn_t logibm_interrupt(int
+ dy |= (buttons & 0xf) << 4;
+ buttons = ~buttons >> 5;
+
+- input_regs(logibm_dev, regs);
+ input_report_rel(logibm_dev, REL_X, dx);
+ input_report_rel(logibm_dev, REL_Y, dy);
+ input_report_key(logibm_dev, BTN_RIGHT, buttons & 1);
+diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
+index 54b696c..8a4f862 100644
+--- a/drivers/input/mouse/logips2pp.c
++++ b/drivers/input/mouse/logips2pp.c
+@@ -30,16 +30,16 @@
+ #define PS2PP_NAV_BTN 0x20
+
+ struct ps2pp_info {
+- const int model;
+- unsigned const int kind;
+- unsigned const int features;
++ u8 model;
++ u8 kind;
++ u16 features;
+ };
+
+ /*
+ * Process a PS2++ or PS2T++ packet.
+ */
+
+-static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
+ {
+ struct input_dev *dev = psmouse->dev;
+ unsigned char *packet = psmouse->packet;
+@@ -51,8 +51,6 @@ static psmouse_ret_t ps2pp_process_byte(
+ * Full packet accumulated, process it
+ */
+
+- input_regs(dev, regs);
+-
+ if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
+
+ /* Logitech extended packet */
+@@ -199,9 +197,9 @@ static void ps2pp_disconnect(struct psmo
+ device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
+ }
+
+-static struct ps2pp_info *get_model_info(unsigned char model)
++static const struct ps2pp_info *get_model_info(unsigned char model)
+ {
+- static struct ps2pp_info ps2pp_list[] = {
++ static const struct ps2pp_info ps2pp_list[] = {
+ { 12, 0, PS2PP_SIDE_BTN},
+ { 13, 0, 0 },
+ { 15, PS2PP_KIND_MX, /* MX1000 */
+@@ -215,6 +213,7 @@ static struct ps2pp_info *get_model_info
+ { 51, 0, 0 },
+ { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
+ { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
++ { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
+ { 61, PS2PP_KIND_MX, /* MX700 */
+ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
+ PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
+@@ -244,12 +243,11 @@ static struct ps2pp_info *get_model_info
+ PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
+ { 114, PS2PP_KIND_MX, /* MX310 */
+ PS2PP_WHEEL | PS2PP_SIDE_BTN |
+- PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },
+- { }
++ PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
+ };
+ int i;
+
+- for (i = 0; ps2pp_list[i].model; i++)
++ for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
+ if (model == ps2pp_list[i].model)
+ return &ps2pp_list[i];
+
+@@ -261,7 +259,8 @@ static struct ps2pp_info *get_model_info
+ * Set up input device's properties based on the detected mouse model.
+ */
+
+-static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info,
++static void ps2pp_set_model_properties(struct psmouse *psmouse,
++ const struct ps2pp_info *model_info,
+ int using_ps2pp)
+ {
+ struct input_dev *input_dev = psmouse->dev;
+@@ -327,7 +326,7 @@ int ps2pp_init(struct psmouse *psmouse,
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+ unsigned char model, buttons;
+- struct ps2pp_info *model_info;
++ const struct ps2pp_info *model_info;
+ int use_ps2pp = 0;
+
+ param[0] = 0;
+@@ -349,7 +348,7 @@ int ps2pp_init(struct psmouse *psmouse,
+ /*
+ * Do Logitech PS2++ / PS2T++ magic init.
+ */
+- if (model == 97) { /* Touch Pad 3 */
++ if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
+
+ /* Unprotect RAM */
+ param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
+diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
+index d284ea7..8c075aa 100644
+--- a/drivers/input/mouse/pc110pad.c
++++ b/drivers/input/mouse/pc110pad.c
+@@ -57,7 +57,7 @@ static struct input_dev *pc110pad_dev;
+ static int pc110pad_data[3];
+ static int pc110pad_count;
+
+-static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t pc110pad_interrupt(int irq, void *ptr)
+ {
+ int value = inb_p(pc110pad_io);
+ int handshake = inb_p(pc110pad_io + 2);
+@@ -71,7 +71,6 @@ static irqreturn_t pc110pad_interrupt(in
+ if (pc110pad_count < 3)
+ return IRQ_HANDLED;
+
+- input_regs(pc110pad_dev, regs);
+ input_report_key(pc110pad_dev, BTN_TOUCH,
+ pc110pad_data[0] & 0x01);
+ input_report_abs(pc110pad_dev, ABS_X,
+@@ -91,9 +90,9 @@ static void pc110pad_close(struct input_
+
+ static int pc110pad_open(struct input_dev *dev)
+ {
+- pc110pad_interrupt(0, NULL, NULL);
+- pc110pad_interrupt(0, NULL, NULL);
+- pc110pad_interrupt(0, NULL, NULL);
++ pc110pad_interrupt(0, NULL);
++ pc110pad_interrupt(0, NULL);
++ pc110pad_interrupt(0, NULL);
+ outb(PC110PAD_ON, pc110pad_io + 2);
+ pc110pad_count = 0;
+
+diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
+index 343afa3..6f9b2c7 100644
+--- a/drivers/input/mouse/psmouse-base.c
++++ b/drivers/input/mouse/psmouse-base.c
+@@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmouse
+
+ struct psmouse_protocol {
+ enum psmouse_type type;
+- char *name;
+- char *alias;
++ const char *name;
++ const char *alias;
+ int maxproto;
+ int (*detect)(struct psmouse *, int);
+ int (*init)(struct psmouse *);
+@@ -124,7 +124,7 @@ struct psmouse_protocol {
+ * relevant events to the input module once full packet has arrived.
+ */
+
+-static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
+ {
+ struct input_dev *dev = psmouse->dev;
+ unsigned char *packet = psmouse->packet;
+@@ -136,8 +136,6 @@ static psmouse_ret_t psmouse_process_byt
+ * Full packet accumulated, process it
+ */
+
+- input_regs(dev, regs);
+-
+ /*
+ * Scroll wheel on IntelliMice, scroll buttons on NetMice
+ */
+@@ -231,9 +229,9 @@ static void psmouse_set_state(struct psm
+ * by calling corresponding protocol handler.
+ */
+
+-static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static int psmouse_handle_byte(struct psmouse *psmouse)
+ {
+- psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs);
++ psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
+
+ switch (rc) {
+ case PSMOUSE_BAD_DATA:
+@@ -271,7 +269,7 @@ static int psmouse_handle_byte(struct ps
+ */
+
+ static irqreturn_t psmouse_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct psmouse *psmouse = serio_get_drvdata(serio);
+
+@@ -327,7 +325,7 @@ static irqreturn_t psmouse_interrupt(str
+ * Not a new device, try processing first byte normally
+ */
+ psmouse->pktcnt = 1;
+- if (psmouse_handle_byte(psmouse, regs))
++ if (psmouse_handle_byte(psmouse))
+ goto out;
+
+ psmouse->packet[psmouse->pktcnt++] = data;
+@@ -346,7 +344,7 @@ static irqreturn_t psmouse_interrupt(str
+ }
+
+ psmouse->last = jiffies;
+- psmouse_handle_byte(psmouse, regs);
++ psmouse_handle_byte(psmouse);
+
+ out:
+ return IRQ_HANDLED;
+@@ -507,15 +505,17 @@ static int thinking_detect(struct psmous
+ {
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[2];
+- unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 };
++ static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
+ int i;
+
+ param[0] = 10;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ param[0] = 0;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+- for (i = 0; seq[i]; i++)
+- ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
++ for (i = 0; i < ARRAY_SIZE(seq); i++) {
++ param[0] = seq[i];
++ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
++ }
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
+
+ if (param[0] != 2)
+@@ -652,7 +652,7 @@ static int psmouse_extensions(struct psm
+ return PSMOUSE_PS2;
+ }
+
+-static struct psmouse_protocol psmouse_protocols[] = {
++static const struct psmouse_protocol psmouse_protocols[] = {
+ {
+ .type = PSMOUSE_PS2,
+ .name = "PS/2",
+@@ -726,7 +726,7 @@ static struct psmouse_protocol psmouse_p
+ },
+ };
+
+-static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
++static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+ {
+ int i;
+
+@@ -738,9 +738,9 @@ static struct psmouse_protocol *psmouse_
+ return &psmouse_protocols[0];
+ }
+
+-static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
++static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+ {
+- struct psmouse_protocol *p;
++ const struct psmouse_protocol *p;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
+@@ -795,13 +795,15 @@ static int psmouse_probe(struct psmouse
+
+ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+ {
+- unsigned char params[] = { 0, 1, 2, 2, 3 };
++ static const unsigned char params[] = { 0, 1, 2, 2, 3 };
++ unsigned char p;
+
+ if (resolution == 0 || resolution > 200)
+ resolution = 200;
+
+- ps2_command(&psmouse->ps2dev, ¶ms[resolution / 50], PSMOUSE_CMD_SETRES);
+- psmouse->resolution = 25 << params[resolution / 50];
++ p = params[resolution / 50];
++ ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
++ psmouse->resolution = 25 << p;
+ }
+
+ /*
+@@ -810,12 +812,14 @@ void psmouse_set_resolution(struct psmou
+
+ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
+ {
+- unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
++ static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
++ unsigned char r;
+ int i = 0;
+
+ while (rates[i] > rate) i++;
+- ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE);
+- psmouse->rate = rates[i];
++ r = rates[i];
++ ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
++ psmouse->rate = r;
+ }
+
+ /*
+@@ -934,7 +938,7 @@ static void psmouse_resync(void *p)
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+ for (i = 0; i < psmouse->pktsize; i++) {
+ psmouse->pktcnt++;
+- rc = psmouse->protocol_handler(psmouse, NULL);
++ rc = psmouse->protocol_handler(psmouse);
+ if (rc != PSMOUSE_GOOD_DATA)
+ break;
+ }
+@@ -1031,7 +1035,7 @@ static void psmouse_disconnect(struct se
+ mutex_unlock(&psmouse_mutex);
+ }
+
+-static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
++static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto)
+ {
+ struct input_dev *input_dev = psmouse->dev;
+
+@@ -1362,7 +1366,7 @@ static ssize_t psmouse_attr_set_protocol
+ struct serio *serio = psmouse->ps2dev.serio;
+ struct psmouse *parent = NULL;
+ struct input_dev *new_dev;
+- struct psmouse_protocol *proto;
++ const struct psmouse_protocol *proto;
+ int retry = 0;
+
+ if (!(proto = psmouse_protocol_by_name(buf, count)))
+@@ -1459,7 +1463,7 @@ static ssize_t psmouse_attr_set_resoluti
+
+ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
+ {
+- struct psmouse_protocol *proto;
++ const struct psmouse_protocol *proto;
+
+ if (!val)
+ return -EINVAL;
+diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
+index 4d9107f..1b74cae 100644
+--- a/drivers/input/mouse/psmouse.h
++++ b/drivers/input/mouse/psmouse.h
+@@ -62,7 +62,7 @@ struct psmouse {
+ unsigned int resync_time;
+ unsigned int smartscroll; /* Logitech only */
+
+- psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
++ psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
+ void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
+ void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
+
+diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
+index 872b30b..ea04685 100644
+--- a/drivers/input/mouse/rpcmouse.c
++++ b/drivers/input/mouse/rpcmouse.c
+@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
+ static short rpcmouse_lastx, rpcmouse_lasty;
+ static struct input_dev *rpcmouse_dev;
+
+-static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t rpcmouse_irq(int irq, void *dev_id)
+ {
+ struct input_dev *dev = dev_id;
+ short x, y, dx, dy, b;
+@@ -51,8 +51,6 @@ static irqreturn_t rpcmouse_irq(int irq,
+ rpcmouse_lastx = x;
+ rpcmouse_lasty = y;
+
+- input_regs(dev, regs);
+-
+ input_report_rel(dev, REL_X, dx);
+ input_report_rel(dev, REL_Y, -dy);
+
+diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
+index 0023501..2a272c5 100644
+--- a/drivers/input/mouse/sermouse.c
++++ b/drivers/input/mouse/sermouse.c
+@@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech at u
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_LICENSE("GPL");
+
+-static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
++static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
+ "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
+ "Logitech MZ++ Mouse"};
+
+@@ -61,13 +61,11 @@ struct sermouse {
+ * second, which is as good as a PS/2 or USB mouse.
+ */
+
+-static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
++static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
+ {
+ struct input_dev *dev = sermouse->dev;
+ signed char *buf = sermouse->buf;
+
+- input_regs(dev, regs);
+-
+ switch (sermouse->count) {
+
+ case 0:
+@@ -104,15 +102,13 @@ static void sermouse_process_msc(struct
+ * standard 3-byte packets and 1200 bps.
+ */
+
+-static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
++static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
+ {
+ struct input_dev *dev = sermouse->dev;
+ signed char *buf = sermouse->buf;
+
+ if (data & 0x40) sermouse->count = 0;
+
+- input_regs(dev, regs);
+-
+ switch (sermouse->count) {
+
+ case 0:
+@@ -206,7 +202,7 @@ static void sermouse_process_ms(struct s
+ */
+
+ static irqreturn_t sermouse_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct sermouse *sermouse = serio_get_drvdata(serio);
+
+@@ -214,9 +210,9 @@ static irqreturn_t sermouse_interrupt(st
+ sermouse->last = jiffies;
+
+ if (sermouse->type > SERIO_SUN)
+- sermouse_process_ms(sermouse, data, regs);
++ sermouse_process_ms(sermouse, data);
+ else
+- sermouse_process_msc(sermouse, data, regs);
++ sermouse_process_msc(sermouse, data);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
+index ad5d0a8..49ac696 100644
+--- a/drivers/input/mouse/synaptics.c
++++ b/drivers/input/mouse/synaptics.c
+@@ -216,13 +216,13 @@ static void synaptics_pass_pt_packet(str
+ struct psmouse *child = serio_get_drvdata(ptport);
+
+ if (child && child->state == PSMOUSE_ACTIVATED) {
+- serio_interrupt(ptport, packet[1], 0, NULL);
+- serio_interrupt(ptport, packet[4], 0, NULL);
+- serio_interrupt(ptport, packet[5], 0, NULL);
++ serio_interrupt(ptport, packet[1], 0);
++ serio_interrupt(ptport, packet[4], 0);
++ serio_interrupt(ptport, packet[5], 0);
+ if (child->pktsize == 4)
+- serio_interrupt(ptport, packet[2], 0, NULL);
++ serio_interrupt(ptport, packet[2], 0);
+ } else
+- serio_interrupt(ptport, packet[1], 0, NULL);
++ serio_interrupt(ptport, packet[1], 0);
+ }
+
+ static void synaptics_pt_activate(struct psmouse *psmouse)
+@@ -430,11 +430,11 @@ static void synaptics_process_packet(str
+
+ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
+ {
+- static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
+- static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
+- static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
+- static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
+- static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
++ static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
++ static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
++ static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
++ static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
++ static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+
+ if (idx < 0 || idx > 4)
+ return 0;
+@@ -469,13 +469,10 @@ static unsigned char synaptics_detect_pk
+ return SYN_NEWABS_STRICT;
+ }
+
+-static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
+ {
+- struct input_dev *dev = psmouse->dev;
+ struct synaptics_data *priv = psmouse->private;
+
+- input_regs(dev, regs);
+-
+ if (psmouse->pktcnt >= 6) { /* Full packet received */
+ if (unlikely(priv->pkt_type == SYN_NEWABS))
+ priv->pkt_type = synaptics_detect_pkt_type(psmouse);
+diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
+index 47edcfd..ffdb50e 100644
+--- a/drivers/input/mouse/vsxxxaa.c
++++ b/drivers/input/mouse/vsxxxaa.c
+@@ -211,7 +211,7 @@ vsxxxaa_smells_like_packet (struct vsxxx
+ }
+
+ static void
+-vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
++vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
+ {
+ struct input_dev *dev = mouse->dev;
+ unsigned char *buf = mouse->buf;
+@@ -258,7 +258,6 @@ vsxxxaa_handle_REL_packet (struct vsxxxa
+ /*
+ * Report what we've found so far...
+ */
+- input_regs (dev, regs);
+ input_report_key (dev, BTN_LEFT, left);
+ input_report_key (dev, BTN_MIDDLE, middle);
+ input_report_key (dev, BTN_RIGHT, right);
+@@ -269,7 +268,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxa
+ }
+
+ static void
+-vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
++vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
+ {
+ struct input_dev *dev = mouse->dev;
+ unsigned char *buf = mouse->buf;
+@@ -312,7 +311,6 @@ vsxxxaa_handle_ABS_packet (struct vsxxxa
+ /*
+ * Report what we've found so far...
+ */
+- input_regs (dev, regs);
+ input_report_key (dev, BTN_LEFT, left);
+ input_report_key (dev, BTN_MIDDLE, middle);
+ input_report_key (dev, BTN_RIGHT, right);
+@@ -323,7 +321,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxa
+ }
+
+ static void
+-vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
++vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
+ {
+ struct input_dev *dev = mouse->dev;
+ unsigned char *buf = mouse->buf;
+@@ -367,7 +365,6 @@ vsxxxaa_handle_POR_packet (struct vsxxxa
+
+ if (error <= 0x1f) {
+ /* No (serious) error. Report buttons */
+- input_regs (dev, regs);
+ input_report_key (dev, BTN_LEFT, left);
+ input_report_key (dev, BTN_MIDDLE, middle);
+ input_report_key (dev, BTN_RIGHT, right);
+@@ -395,7 +392,7 @@ vsxxxaa_handle_POR_packet (struct vsxxxa
+ }
+
+ static void
+-vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
++vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
+ {
+ unsigned char *buf = mouse->buf;
+ int stray_bytes;
+@@ -432,7 +429,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mo
+ continue;
+ }
+
+- vsxxxaa_handle_REL_packet (mouse, regs);
++ vsxxxaa_handle_REL_packet (mouse);
+ continue; /* More to parse? */
+ }
+
+@@ -446,7 +443,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mo
+ continue;
+ }
+
+- vsxxxaa_handle_ABS_packet (mouse, regs);
++ vsxxxaa_handle_ABS_packet (mouse);
+ continue; /* More to parse? */
+ }
+
+@@ -460,7 +457,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mo
+ continue;
+ }
+
+- vsxxxaa_handle_POR_packet (mouse, regs);
++ vsxxxaa_handle_POR_packet (mouse);
+ continue; /* More to parse? */
+ }
+
+@@ -469,13 +466,12 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mo
+ }
+
+ static irqreturn_t
+-vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
+- struct pt_regs *regs)
++vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
+ {
+ struct vsxxxaa *mouse = serio_get_drvdata (serio);
+
+ vsxxxaa_queue_byte (mouse, data);
+- vsxxxaa_parse_buffer (mouse, regs);
++ vsxxxaa_parse_buffer (mouse);
+
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
+index 1f851ac..a22a74a 100644
+--- a/drivers/input/mousedev.c
++++ b/drivers/input/mousedev.c
+@@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct
+ (list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
+ }
+
+-static struct file_operations mousedev_fops = {
++static const struct file_operations mousedev_fops = {
+ .owner = THIS_MODULE,
+ .read = mousedev_read,
+ .write = mousedev_write,
+@@ -624,7 +624,8 @@ static struct file_operations mousedev_f
+ .fasync = mousedev_fasync,
+ };
+
+-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
++static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
++ const struct input_device_id *id)
+ {
+ struct mousedev *mousedev;
+ struct class_device *cdev;
+@@ -688,7 +689,7 @@ static void mousedev_disconnect(struct i
+ }
+ }
+
+-static struct input_device_id mousedev_ids[] = {
++static const struct input_device_id mousedev_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+ .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
+@@ -737,7 +738,12 @@ static int psaux_registered;
+
+ static int __init mousedev_init(void)
+ {
+- input_register_handler(&mousedev_handler);
++ struct class_device *cdev;
++ int error;
++
++ error = input_register_handler(&mousedev_handler);
++ if (error)
++ return error;
+
+ memset(&mousedev_mix, 0, sizeof(struct mousedev));
+ INIT_LIST_HEAD(&mousedev_mix.list);
+@@ -746,12 +752,20 @@ static int __init mousedev_init(void)
+ mousedev_mix.exist = 1;
+ mousedev_mix.minor = MOUSEDEV_MIX;
+
+- class_device_create(&input_class, NULL,
++ cdev = class_device_create(&input_class, NULL,
+ MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice");
++ if (IS_ERR(cdev)) {
++ input_unregister_handler(&mousedev_handler);
++ return PTR_ERR(cdev);
++ }
+
+ #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+- if (!(psaux_registered = !misc_register(&psaux_mouse)))
+- printk(KERN_WARNING "mice: could not misc_register the device\n");
++ error = misc_register(&psaux_mouse);
++ if (error)
++ printk(KERN_WARNING "mice: could not register psaux device, "
++ "error: %d\n", error);
++ else
++ psaux_registered = 1;
+ #endif
+
+ printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
+diff --git a/drivers/input/power.c b/drivers/input/power.c
+index 51a519e..ee82464 100644
+--- a/drivers/input/power.c
++++ b/drivers/input/power.c
+@@ -98,7 +98,7 @@ static void power_event(struct input_han
+
+ static struct input_handle *power_connect(struct input_handler *handler,
+ struct input_dev *dev,
+- struct input_device_id *id)
++ const struct input_device_id *id)
+ {
+ struct input_handle *handle;
+
+@@ -120,7 +120,7 @@ static void power_disconnect(struct inpu
+ kfree(handle);
+ }
+
+-static struct input_device_id power_ids[] = {
++static const struct input_device_id power_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT(EV_KEY) },
+@@ -150,8 +150,7 @@ static struct input_handler power_handle
+
+ static int __init power_init(void)
+ {
+- input_register_handler(&power_handler);
+- return 0;
++ return input_register_handler(&power_handler);
+ }
+
+ static void __exit power_exit(void)
+diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
+index 98acf17..adef447 100644
+--- a/drivers/input/serio/Kconfig
++++ b/drivers/input/serio/Kconfig
+@@ -112,12 +112,12 @@ config SERIO_GSCPS2
+
+ config HP_SDC
+ tristate "HP System Device Controller i8042 Support"
+- depends on GSC && SERIO
++ depends on (GSC || HP300) && SERIO
+ default y
+ ---help---
+- This option enables supports for the the "System Device
++ This option enables support for the "System Device
+ Controller", an i8042 carrying microcode to manage a
+- few miscellanous devices on some Hewlett Packard systems.
++ few miscellaneous devices on some Hewlett Packard systems.
+ The SDC itself contains a 10ms resolution timer/clock capable
+ of delivering interrupts on a periodic and one-shot basis.
+ The SDC may also be connected to a battery-backed real-time
+diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
+index 3df5eed..5a7b49c 100644
+--- a/drivers/input/serio/ambakmi.c
++++ b/drivers/input/serio/ambakmi.c
+@@ -37,14 +37,14 @@ struct amba_kmi_port {
+ unsigned int open;
+ };
+
+-static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t amba_kmi_int(int irq, void *dev_id)
+ {
+ struct amba_kmi_port *kmi = dev_id;
+ unsigned int status = readb(KMIIR);
+ int handled = IRQ_NONE;
+
+ while (status & KMIIR_RXINTR) {
+- serio_interrupt(kmi->io, readb(KMIDATA), 0, regs);
++ serio_interrupt(kmi->io, readb(KMIDATA), 0);
+ status = readb(KMIIR);
+ handled = IRQ_HANDLED;
+ }
+diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
+index bc6e87a..0d35018 100644
+--- a/drivers/input/serio/ct82c710.c
++++ b/drivers/input/serio/ct82c710.c
+@@ -71,9 +71,9 @@ static struct resource ct82c710_iores;
+ * is waiting in the 82C710.
+ */
+
+-static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id)
+ {
+- return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs);
++ return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0);
+ }
+
+ /*
+diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
+index cde036a..74f14e0 100644
+--- a/drivers/input/serio/gscps2.c
++++ b/drivers/input/serio/gscps2.c
+@@ -82,7 +82,7 @@ MODULE_DEVICE_TABLE(parisc, gscps2_devic
+ #define GSC_ID_MOUSE 1
+
+
+-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
++static irqreturn_t gscps2_interrupt(int irq, void *dev);
+
+ #define BUFFER_SIZE 0x0f
+
+@@ -166,7 +166,7 @@ static inline int gscps2_writeb_output(s
+
+ /* make sure any received data is returned as fast as possible */
+ /* this is important e.g. when we set the LEDs on the keyboard */
+- gscps2_interrupt(0, NULL, NULL);
++ gscps2_interrupt(0, NULL);
+
+ return 1;
+ }
+@@ -226,7 +226,7 @@ static LIST_HEAD(ps2port_list);
+ * later.
+ */
+
+-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t gscps2_interrupt(int irq, void *dev)
+ {
+ struct gscps2port *ps2port;
+
+@@ -267,7 +267,7 @@ static irqreturn_t gscps2_interrupt(int
+ rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
+ ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 );
+
+- serio_interrupt(ps2port->port, data, rxflags, regs);
++ serio_interrupt(ps2port->port, data, rxflags);
+
+ } /* while() */
+
+@@ -306,7 +306,7 @@ static int gscps2_open(struct serio *por
+ /* enable it */
+ gscps2_enable(ps2port, ENABLE);
+
+- gscps2_interrupt(0, NULL, NULL);
++ gscps2_interrupt(0, NULL);
+
+ return 0;
+ }
+diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
+index bbbe15e..49e11e2 100644
+--- a/drivers/input/serio/hil_mlc.c
++++ b/drivers/input/serio/hil_mlc.c
+@@ -162,10 +162,10 @@ static void hil_mlc_send_polls(hil_mlc *
+ if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
+ if (drv == NULL || drv->interrupt == NULL) goto skip;
+
+- drv->interrupt(serio, 0, 0, NULL);
+- drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+- drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL);
+- drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL);
++ drv->interrupt(serio, 0, 0);
++ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
++ drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
++ drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
+ skip:
+ did = (p & HIL_PKT_ADDR_MASK) >> 8;
+ serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
+@@ -174,10 +174,10 @@ static void hil_mlc_send_polls(hil_mlc *
+ }
+ cnt++; i++;
+ if (drv == NULL || drv->interrupt == NULL) continue;
+- drv->interrupt(serio, (p >> 24), 0, NULL);
+- drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL);
+- drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL);
+- drv->interrupt(serio, p & 0xff, 0, NULL);
++ drv->interrupt(serio, (p >> 24), 0);
++ drv->interrupt(serio, (p >> 16) & 0xff, 0);
++ drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
++ drv->interrupt(serio, p & 0xff, 0);
+ }
+ }
+
+@@ -391,23 +391,23 @@ static int hilse_operate(hil_mlc *mlc, i
+ }
+
+ #define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \
+-{ HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc },
++{ HILSE_FUNC, { .func = funct }, funct_arg, zero_rc, neg_rc, pos_rc },
+ #define OUT(pack) \
+-{ HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
++{ HILSE_OUT, { .packet = pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
+ #define CTS \
+-{ HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
++{ HILSE_CTS, { .packet = 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
+ #define EXPECT(comp, to, got, got_wrong, timed_out) \
+-{ HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out },
++{ HILSE_EXPECT, { .packet = comp }, to, got, got_wrong, timed_out },
+ #define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \
+-{ HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out },
++{ HILSE_EXPECT_LAST, { .packet = comp }, to, got, got_wrong, timed_out },
+ #define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \
+-{ HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out },
++{ HILSE_EXPECT_DISC, { .packet = comp }, to, got, got_wrong, timed_out },
+ #define IN(to, got, got_error, timed_out) \
+-{ HILSE_IN, { packet: 0 }, to, got, got_error, timed_out },
++{ HILSE_IN, { .packet = 0 }, to, got, got_error, timed_out },
+ #define OUT_DISC(pack) \
+-{ HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 },
++{ HILSE_OUT_DISC, { .packet = pack }, 0, 0, 0, 0 },
+ #define OUT_LAST(pack) \
+-{ HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 },
++{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 },
+
+ struct hilse_node hil_mlc_se[HILSEN_END] = {
+
+@@ -780,16 +780,16 @@ static int hil_mlc_serio_write(struct se
+ while ((last != idx) && (*last == 0)) last--;
+
+ while (idx != last) {
+- drv->interrupt(serio, 0, 0, NULL);
+- drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+- drv->interrupt(serio, 0, 0, NULL);
+- drv->interrupt(serio, *idx, 0, NULL);
++ drv->interrupt(serio, 0, 0);
++ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
++ drv->interrupt(serio, 0, 0);
++ drv->interrupt(serio, *idx, 0);
+ idx++;
+ }
+- drv->interrupt(serio, 0, 0, NULL);
+- drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+- drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL);
+- drv->interrupt(serio, *idx, 0, NULL);
++ drv->interrupt(serio, 0, 0);
++ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
++ drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
++ drv->interrupt(serio, *idx, 0);
+
+ mlc->serio_oidx[map->didx] = 0;
+ mlc->serio_opacket[map->didx] = 0;
+diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
+index a10348b..9907ad3 100644
+--- a/drivers/input/serio/hp_sdc.c
++++ b/drivers/input/serio/hp_sdc.c
+@@ -202,7 +202,7 @@ static void hp_sdc_take (int irq, void *
+ }
+ }
+
+-static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) {
++static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
+ uint8_t status, data;
+
+ status = hp_sdc_status_in8();
+@@ -253,7 +253,7 @@ static irqreturn_t hp_sdc_isr(int irq, v
+ }
+
+
+-static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) {
++static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
+ int status;
+
+ status = hp_sdc_status_in8();
+@@ -310,7 +310,7 @@ static void hp_sdc_tasklet(unsigned long
+ * in tasklet/bh context.
+ */
+ if (curr->act.irqhook)
+- curr->act.irqhook(0, 0, 0, 0);
++ curr->act.irqhook(0, NULL, 0, 0);
+ }
+ curr->actidx = curr->idx;
+ curr->idx++;
+@@ -525,7 +525,7 @@ actdone:
+ up(curr->act.semaphore);
+ }
+ else if (act & HP_SDC_ACT_CALLBACK) {
+- curr->act.irqhook(0,0,0,0);
++ curr->act.irqhook(0,NULL,0,0);
+ }
+ if (curr->idx >= curr->endidx) { /* This transaction is over. */
+ if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
+index cc21914..3b4e13b 100644
+--- a/drivers/input/serio/i8042-io.h
++++ b/drivers/input/serio/i8042-io.h
+@@ -67,25 +67,22 @@ static inline int i8042_platform_init(vo
+ * On some platforms touching the i8042 data register region can do really
+ * bad things. Because of this the region is always reserved on such boxes.
+ */
+-#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC_MERGE)
+- if (!request_region(I8042_DATA_REG, 16, "i8042"))
+- return -EBUSY;
+-#endif
+-
+- i8042_reset = 1;
+-
+ #if defined(CONFIG_PPC_MERGE)
+ if (check_legacy_ioport(I8042_DATA_REG))
+- return -EBUSY;
++ return -ENODEV;
++#endif
++#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__)
+ if (!request_region(I8042_DATA_REG, 16, "i8042"))
+ return -EBUSY;
+ #endif
++
++ i8042_reset = 1;
+ return 0;
+ }
+
+ static inline void i8042_platform_exit(void)
+ {
+-#if !defined(__sh__) && !defined(__alpha__) && !defined(CONFIG_PPC64)
++#if !defined(__sh__) && !defined(__alpha__)
+ release_region(I8042_DATA_REG, 16);
+ #endif
+ }
+diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
+index f606e96..8738edd 100644
+--- a/drivers/input/serio/i8042-x86ia64io.h
++++ b/drivers/input/serio/i8042-x86ia64io.h
+@@ -160,6 +160,13 @@ static struct dmi_system_id __initdata i
+ },
+ },
+ {
++ .ident = "Toshiba Equium A110",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
++ },
++ },
++ {
+ .ident = "Alienware Sentia",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
+@@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
+ },
+ },
++ {
++ .ident = "Amoi M636/A737",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
++ },
++ },
+ { }
+ };
+
+diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
+index 06a3f25..7e3141f 100644
+--- a/drivers/input/serio/i8042.c
++++ b/drivers/input/serio/i8042.c
+@@ -90,47 +90,26 @@ static DEFINE_SPINLOCK(i8042_lock);
+ struct i8042_port {
+ struct serio *serio;
+ int irq;
+- unsigned char disable;
+- unsigned char irqen;
+ unsigned char exists;
+ signed char mux;
+- char name[8];
+ };
+
+ #define I8042_KBD_PORT_NO 0
+ #define I8042_AUX_PORT_NO 1
+ #define I8042_MUX_PORT_NO 2
+ #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2)
+-static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
+- {
+- .disable = I8042_CTR_KBDDIS,
+- .irqen = I8042_CTR_KBDINT,
+- .mux = -1,
+- .name = "KBD",
+- },
+- {
+- .disable = I8042_CTR_AUXDIS,
+- .irqen = I8042_CTR_AUXINT,
+- .mux = -1,
+- .name = "AUX",
+- }
+-};
++
++static struct i8042_port i8042_ports[I8042_NUM_PORTS];
+
+ static unsigned char i8042_initial_ctr;
+ static unsigned char i8042_ctr;
+-static unsigned char i8042_mux_open;
+ static unsigned char i8042_mux_present;
+-static struct timer_list i8042_timer;
++static unsigned char i8042_kbd_irq_registered;
++static unsigned char i8042_aux_irq_registered;
++static unsigned char i8042_suppress_kbd_ack;
+ static struct platform_device *i8042_platform_device;
+
+-
+-/*
+- * Shared IRQ's require a device pointer, but this driver doesn't support
+- * multiple devices
+- */
+-#define i8042_request_irq_cookie (&i8042_timer)
+-
+-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t i8042_interrupt(int irq, void *dev_id);
+
+ /*
+ * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
+@@ -141,6 +120,7 @@ static irqreturn_t i8042_interrupt(int i
+ static int i8042_wait_read(void)
+ {
+ int i = 0;
++
+ while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
+ udelay(50);
+ i++;
+@@ -151,6 +131,7 @@ static int i8042_wait_read(void)
+ static int i8042_wait_write(void)
+ {
+ int i = 0;
++
+ while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
+ udelay(50);
+ i++;
+@@ -192,48 +173,57 @@ static int i8042_flush(void)
+ * encoded in bits 8-11 of the command number.
+ */
+
+-static int i8042_command(unsigned char *param, int command)
++static int __i8042_command(unsigned char *param, int command)
+ {
+- unsigned long flags;
+- int i, retval, auxerr = 0;
++ int i, error;
+
+ if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
+ return -1;
+
+- spin_lock_irqsave(&i8042_lock, flags);
+-
+- if ((retval = i8042_wait_write()))
+- goto out;
++ error = i8042_wait_write();
++ if (error)
++ return error;
+
+ dbg("%02x -> i8042 (command)", command & 0xff);
+ i8042_write_command(command & 0xff);
+
+ for (i = 0; i < ((command >> 12) & 0xf); i++) {
+- if ((retval = i8042_wait_write()))
+- goto out;
++ error = i8042_wait_write();
++ if (error)
++ return error;
+ dbg("%02x -> i8042 (parameter)", param[i]);
+ i8042_write_data(param[i]);
+ }
+
+ for (i = 0; i < ((command >> 8) & 0xf); i++) {
+- if ((retval = i8042_wait_read()))
+- goto out;
++ error = i8042_wait_read();
++ if (error) {
++ dbg(" -- i8042 (timeout)");
++ return error;
++ }
+
+ if (command == I8042_CMD_AUX_LOOP &&
+ !(i8042_read_status() & I8042_STR_AUXDATA)) {
+- retval = auxerr = -1;
+- goto out;
++ dbg(" -- i8042 (auxerr)");
++ return -1;
+ }
+
+ param[i] = i8042_read_data();
+ dbg("%02x <- i8042 (return)", param[i]);
+ }
+
+- if (retval)
+- dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout");
++ return 0;
++}
+
+- out:
++static int i8042_command(unsigned char *param, int command)
++{
++ unsigned long flags;
++ int retval;
++
++ spin_lock_irqsave(&i8042_lock, flags);
++ retval = __i8042_command(param, command);
+ spin_unlock_irqrestore(&i8042_lock, flags);
++
+ return retval;
+ }
+
+@@ -248,7 +238,7 @@ static int i8042_kbd_write(struct serio
+
+ spin_lock_irqsave(&i8042_lock, flags);
+
+- if(!(retval = i8042_wait_write())) {
++ if (!(retval = i8042_wait_write())) {
+ dbg("%02x -> i8042 (kbd-data)", c);
+ i8042_write_data(c);
+ }
+@@ -282,105 +272,11 @@ static int i8042_aux_write(struct serio
+ * characters later.
+ */
+
+- i8042_interrupt(0, NULL, NULL);
++ i8042_interrupt(0, NULL);
+ return retval;
+ }
+
+ /*
+- * i8042_activate_port() enables port on a chip.
+- */
+-
+-static int i8042_activate_port(struct i8042_port *port)
+-{
+- if (!port->serio)
+- return -1;
+-
+- i8042_flush();
+-
+- /*
+- * Enable port again here because it is disabled if we are
+- * resuming (normally it is enabled already).
+- */
+- i8042_ctr &= ~port->disable;
+-
+- i8042_ctr |= port->irqen;
+-
+- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+- i8042_ctr &= ~port->irqen;
+- return -1;
+- }
+-
+- return 0;
+-}
+-
+-
+-/*
+- * i8042_open() is called when a port is open by the higher layer.
+- * It allocates the interrupt and calls i8042_enable_port.
+- */
+-
+-static int i8042_open(struct serio *serio)
+-{
+- struct i8042_port *port = serio->port_data;
+-
+- if (port->mux != -1)
+- if (i8042_mux_open++)
+- return 0;
+-
+- if (request_irq(port->irq, i8042_interrupt,
+- IRQF_SHARED, "i8042", i8042_request_irq_cookie)) {
+- printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name);
+- goto irq_fail;
+- }
+-
+- if (i8042_activate_port(port)) {
+- printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name);
+- goto activate_fail;
+- }
+-
+- i8042_interrupt(0, NULL, NULL);
+-
+- return 0;
+-
+- activate_fail:
+- free_irq(port->irq, i8042_request_irq_cookie);
+-
+- irq_fail:
+- serio_unregister_port_delayed(serio);
+-
+- return -1;
+-}
+-
+-/*
+- * i8042_close() frees the interrupt, so that it can possibly be used
+- * by another driver. We never know - if the user doesn't have a mouse,
+- * the BIOS could have used the AUX interrupt for PCI.
+- */
+-
+-static void i8042_close(struct serio *serio)
+-{
+- struct i8042_port *port = serio->port_data;
+-
+- if (port->mux != -1)
+- if (--i8042_mux_open)
+- return;
+-
+- i8042_ctr &= ~port->irqen;
+-
+- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+- printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name);
+-/*
+- * We still want to continue and free IRQ so if more data keeps coming in
+- * kernel will just ignore the irq.
+- */
+- }
+-
+- free_irq(port->irq, i8042_request_irq_cookie);
+-
+- i8042_flush();
+-}
+-
+-/*
+ * i8042_start() is called by serio core when port is about to finish
+ * registering. It will mark port as existing so i8042_interrupt can
+ * start sending data through it.
+@@ -414,16 +310,14 @@ static void i8042_stop(struct serio *ser
+ * to the upper layers.
+ */
+
+-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i8042_interrupt(int irq, void *dev_id)
+ {
+ struct i8042_port *port;
+ unsigned long flags;
+ unsigned char str, data;
+ unsigned int dfl;
+ unsigned int port_no;
+- int ret;
+-
+- mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
++ int ret = 1;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+ str = i8042_read_status();
+@@ -480,20 +374,78 @@ static irqreturn_t i8042_interrupt(int i
+
+ port = &i8042_ports[port_no];
+
+- dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
+- data, port->name, irq,
++ dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
++ data, port_no, irq,
+ dfl & SERIO_PARITY ? ", bad parity" : "",
+ dfl & SERIO_TIMEOUT ? ", timeout" : "");
+
++ if (unlikely(i8042_suppress_kbd_ack))
++ if (port_no == I8042_KBD_PORT_NO &&
++ (data == 0xfa || data == 0xfe)) {
++ i8042_suppress_kbd_ack = 0;
++ goto out;
++ }
++
+ if (likely(port->exists))
+- serio_interrupt(port->serio, data, dfl, regs);
++ serio_interrupt(port->serio, data, dfl);
+
+- ret = 1;
+ out:
+ return IRQ_RETVAL(ret);
+ }
+
+ /*
++ * i8042_enable_kbd_port enables keybaord port on chip
++ */
++
++static int i8042_enable_kbd_port(void)
++{
++ i8042_ctr &= ~I8042_CTR_KBDDIS;
++ i8042_ctr |= I8042_CTR_KBDINT;
++
++ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
++ printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++/*
++ * i8042_enable_aux_port enables AUX (mouse) port on chip
++ */
++
++static int i8042_enable_aux_port(void)
++{
++ i8042_ctr &= ~I8042_CTR_AUXDIS;
++ i8042_ctr |= I8042_CTR_AUXINT;
++
++ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
++ printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++/*
++ * i8042_enable_mux_ports enables 4 individual AUX ports after
++ * the controller has been switched into Multiplexed mode
++ */
++
++static int i8042_enable_mux_ports(void)
++{
++ unsigned char param;
++ int i;
++
++ for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
++ i8042_command(¶m, I8042_CMD_MUX_PFX + i);
++ i8042_command(¶m, I8042_CMD_AUX_ENABLE);
++ }
++
++ return i8042_enable_aux_port();
++}
++
++/*
+ * i8042_set_mux_mode checks whether the controller has an active
+ * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode.
+ */
+@@ -510,8 +462,7 @@ static int i8042_set_mux_mode(unsigned i
+
+ /*
+ * Internal loopback test - send three bytes, they should come back from the
+- * mouse interface, the last should be version. Note that we negate mouseport
+- * command responses for the i8042_check_aux() routine.
++ * mouse interface, the last should be version.
+ */
+
+ param = 0xf0;
+@@ -530,67 +481,67 @@ static int i8042_set_mux_mode(unsigned i
+ return 0;
+ }
+
+-
+ /*
+- * i8042_enable_mux_ports enables 4 individual AUX ports after
+- * the controller has been switched into Multiplexed mode
++ * i8042_check_mux() checks whether the controller supports the PS/2 Active
++ * Multiplexing specification by Synaptics, Phoenix, Insyde and
++ * LCS/Telegraphics.
+ */
+
+-static int i8042_enable_mux_ports(void)
++static int __devinit i8042_check_mux(void)
+ {
+- unsigned char param;
+- int i;
++ unsigned char mux_version;
++
++ if (i8042_set_mux_mode(1, &mux_version))
++ return -1;
++
+ /*
+- * Disable all muxed ports by disabling AUX.
++ * Workaround for interference with USB Legacy emulation
++ * that causes a v10.12 MUX to be found.
+ */
++ if (mux_version == 0xAC)
++ return -1;
++
++ printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
++ (mux_version >> 4) & 0xf, mux_version & 0xf);
+
++/*
++ * Disable all muxed ports by disabling AUX.
++ */
+ i8042_ctr |= I8042_CTR_AUXDIS;
+ i8042_ctr &= ~I8042_CTR_AUXINT;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
+- return -1;
++ return -EIO;
+ }
+
+-/*
+- * Enable all muxed ports.
+- */
+-
+- for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
+- i8042_command(¶m, I8042_CMD_MUX_PFX + i);
+- i8042_command(¶m, I8042_CMD_AUX_ENABLE);
+- }
++ i8042_mux_present = 1;
+
+ return 0;
+ }
+
+-
+ /*
+- * i8042_check_mux() checks whether the controller supports the PS/2 Active
+- * Multiplexing specification by Synaptics, Phoenix, Insyde and
+- * LCS/Telegraphics.
++ * The following is used to test AUX IRQ delivery.
+ */
++static struct completion i8042_aux_irq_delivered __devinitdata;
++static int i8042_irq_being_tested __devinitdata;
+
+-static int __devinit i8042_check_mux(void)
++static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
+ {
+- unsigned char mux_version;
+-
+- if (i8042_set_mux_mode(1, &mux_version))
+- return -1;
+-
+- /* Workaround for interference with USB Legacy emulation */
+- /* that causes a v10.12 MUX to be found. */
+- if (mux_version == 0xAC)
+- return -1;
+-
+- printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
+- (mux_version >> 4) & 0xf, mux_version & 0xf);
++ unsigned long flags;
++ unsigned char str, data;
+
+- if (i8042_enable_mux_ports())
+- return -1;
++ spin_lock_irqsave(&i8042_lock, flags);
++ str = i8042_read_status();
++ if (str & I8042_STR_OBF) {
++ data = i8042_read_data();
++ if (i8042_irq_being_tested &&
++ data == 0xa5 && (str & I8042_STR_AUXDATA))
++ complete(&i8042_aux_irq_delivered);
++ }
++ spin_unlock_irqrestore(&i8042_lock, flags);
+
+- i8042_mux_present = 1;
+- return 0;
++ return IRQ_HANDLED;
+ }
+
+
+@@ -601,18 +552,10 @@ static int __devinit i8042_check_mux(voi
+
+ static int __devinit i8042_check_aux(void)
+ {
++ int retval = -1;
++ int irq_registered = 0;
++ unsigned long flags;
+ unsigned char param;
+- static int i8042_check_aux_cookie;
+-
+-/*
+- * Check if AUX irq is available. If it isn't, then there is no point
+- * in trying to detect AUX presence.
+- */
+-
+- if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,
+- IRQF_SHARED, "i8042", &i8042_check_aux_cookie))
+- return -1;
+- free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);
+
+ /*
+ * Get rid of bytes in the queue.
+@@ -637,9 +580,9 @@ static int __devinit i8042_check_aux(voi
+ * AUX ports, we test for this only when the LOOP command failed.
+ */
+
+- if (i8042_command(¶m, I8042_CMD_AUX_TEST)
+- || (param && param != 0xfa && param != 0xff))
+- return -1;
++ if (i8042_command(¶m, I8042_CMD_AUX_TEST) ||
++ (param && param != 0xfa && param != 0xff))
++ return -1;
+ }
+
+ /*
+@@ -659,54 +602,80 @@ static int __devinit i8042_check_aux(voi
+ return -1;
+
+ /*
+- * Disable the interface.
++ * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
++ * used it for a PCI card or somethig else.
+ */
+
+- i8042_ctr |= I8042_CTR_AUXDIS;
+- i8042_ctr &= ~I8042_CTR_AUXINT;
++ if (i8042_noloop) {
++/*
++ * Without LOOP command we can't test AUX IRQ delivery. Assume the port
++ * is working and hope we are right.
++ */
++ retval = 0;
++ goto out;
++ }
+
+- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+- return -1;
++ if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
++ "i8042", i8042_platform_device))
++ goto out;
+
+- return 0;
+-}
++ irq_registered = 1;
+
++ if (i8042_enable_aux_port())
++ goto out;
++
++ spin_lock_irqsave(&i8042_lock, flags);
+
++ init_completion(&i8042_aux_irq_delivered);
++ i8042_irq_being_tested = 1;
++
++ param = 0xa5;
++ retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff);
++
++ spin_unlock_irqrestore(&i8042_lock, flags);
++
++ if (retval)
++ goto out;
++
++ if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
++ msecs_to_jiffies(250)) == 0) {
+ /*
+- * i8042_port_register() marks the device as existing,
+- * registers it, and reports to the user.
++ * AUX IRQ was never delivered so we need to flush the controller to
++ * get rid of the byte we put there; otherwise keyboard may not work.
+ */
++ i8042_flush();
++ retval = -1;
++ }
+
+-static int __devinit i8042_port_register(struct i8042_port *port)
+-{
+- i8042_ctr &= ~port->disable;
++ out:
+
+- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+- printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
+- kfree(port->serio);
+- port->serio = NULL;
+- i8042_ctr |= port->disable;
+- return -EIO;
+- }
++/*
++ * Disable the interface.
++ */
+
+- printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
+- port->name,
+- (unsigned long) I8042_DATA_REG,
+- (unsigned long) I8042_COMMAND_REG,
+- port->irq);
++ i8042_ctr |= I8042_CTR_AUXDIS;
++ i8042_ctr &= ~I8042_CTR_AUXINT;
+
+- serio_register_port(port->serio);
++ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
++ retval = -1;
+
+- return 0;
+-}
++ if (irq_registered)
++ free_irq(I8042_AUX_IRQ, i8042_platform_device);
+
++ return retval;
++}
+
+-static void i8042_timer_func(unsigned long data)
++static int i8042_controller_check(void)
+ {
+- i8042_interrupt(0, NULL, NULL);
++ if (i8042_flush() == I8042_BUFFER_SIZE) {
++ printk(KERN_ERR "i8042.c: No controller found.\n");
++ return -ENODEV;
++ }
++
++ return 0;
+ }
+
+-static int i8042_ctl_test(void)
++static int i8042_controller_selftest(void)
+ {
+ unsigned char param;
+
+@@ -715,13 +684,13 @@ static int i8042_ctl_test(void)
+
+ if (i8042_command(¶m, I8042_CMD_CTL_TEST)) {
+ printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+- return -1;
++ return -ENODEV;
+ }
+
+ if (param != I8042_RET_CTL_TEST) {
+ printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
+ param, I8042_RET_CTL_TEST);
+- return -1;
++ return -EIO;
+ }
+
+ return 0;
+@@ -738,25 +707,12 @@ static int i8042_controller_init(void)
+ unsigned long flags;
+
+ /*
+- * Test the i8042. We need to know if it thinks it's working correctly
+- * before doing anything else.
+- */
+-
+- if (i8042_flush() == I8042_BUFFER_SIZE) {
+- printk(KERN_ERR "i8042.c: No controller found.\n");
+- return -1;
+- }
+-
+- if (i8042_ctl_test())
+- return -1;
+-
+-/*
+ * Save the CTR for restoral on unload / reboot.
+ */
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
+ printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
+- return -1;
++ return -EIO;
+ }
+
+ i8042_initial_ctr = i8042_ctr;
+@@ -805,7 +761,7 @@ static int i8042_controller_init(void)
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
+- return -1;
++ return -EIO;
+ }
+
+ return 0;
+@@ -813,15 +769,12 @@ static int i8042_controller_init(void)
+
+
+ /*
+- * Reset the controller.
++ * Reset the controller and reset CRT to the original value set by BIOS.
+ */
++
+ static void i8042_controller_reset(void)
+ {
+-/*
+- * Reset the controller if requested.
+- */
+-
+- i8042_ctl_test();
++ i8042_flush();
+
+ /*
+ * Disable MUX mode if present.
+@@ -831,12 +784,16 @@ static void i8042_controller_reset(void)
+ i8042_set_mux_mode(0, NULL);
+
+ /*
+- * Restore the original control register setting.
++ * Reset the controller if requested.
+ */
+
+- i8042_ctr = i8042_initial_ctr;
++ i8042_controller_selftest();
+
+- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
++/*
++ * Restore the original control register setting.
++ */
++
++ if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
+ printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
+ }
+
+@@ -850,14 +807,12 @@ static void i8042_controller_cleanup(voi
+ {
+ int i;
+
+- i8042_flush();
+-
+ /*
+ * Reset anything that is connected to the ports.
+ */
+
+ for (i = 0; i < I8042_NUM_PORTS; i++)
+- if (i8042_ports[i].exists)
++ if (i8042_ports[i].serio)
+ serio_cleanup(i8042_ports[i].serio);
+
+ i8042_controller_reset();
+@@ -894,11 +849,13 @@ static long i8042_panic_blink(long count
+ led ^= 0x01 | 0x04;
+ while (i8042_read_status() & I8042_STR_IBF)
+ DELAY;
++ i8042_suppress_kbd_ack = 1;
+ i8042_write_data(0xed); /* set leds */
+ DELAY;
+ while (i8042_read_status() & I8042_STR_IBF)
+ DELAY;
+ DELAY;
++ i8042_suppress_kbd_ack = 1;
+ i8042_write_data(led);
+ DELAY;
+ last_blink = count;
+@@ -913,8 +870,7 @@ static long i8042_panic_blink(long count
+
+ static int i8042_suspend(struct platform_device *dev, pm_message_t state)
+ {
+- del_timer_sync(&i8042_timer);
+- i8042_controller_reset();
++ i8042_controller_cleanup();
+
+ return 0;
+ }
+@@ -926,33 +882,39 @@ static int i8042_suspend(struct platform
+
+ static int i8042_resume(struct platform_device *dev)
+ {
+- int i;
++ int error;
+
+- if (i8042_ctl_test())
+- return -1;
++ error = i8042_controller_check();
++ if (error)
++ return error;
+
+- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+- printk(KERN_ERR "i8042: Can't write CTR\n");
+- return -1;
+- }
+-
+- if (i8042_mux_present)
+- if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
+- printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
++ error = i8042_controller_selftest();
++ if (error)
++ return error;
+
+ /*
+- * Activate all ports.
++ * Restore pre-resume CTR value and disable all ports
+ */
+
+- for (i = 0; i < I8042_NUM_PORTS; i++)
+- i8042_activate_port(&i8042_ports[i]);
++ i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
++ i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
++ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
++ printk(KERN_ERR "i8042: Can't write CTR to resume\n");
++ return -EIO;
++ }
+
+-/*
+- * Restart timer (for polling "stuck" data)
+- */
+- mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
++ if (i8042_mux_present) {
++ if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
++ printk(KERN_WARNING
++ "i8042: failed to resume active multiplexor, "
++ "mouse won't work.\n");
++ } else if (i8042_ports[I8042_AUX_PORT_NO].serio)
++ i8042_enable_aux_port();
+
+- panic_blink = i8042_panic_blink;
++ if (i8042_ports[I8042_KBD_PORT_NO].serio)
++ i8042_enable_kbd_port();
++
++ i8042_interrupt(0, NULL);
+
+ return 0;
+ }
+@@ -978,24 +940,24 @@ static int __devinit i8042_create_kbd_po
+
+ serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL;
+ serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write;
+- serio->open = i8042_open;
+- serio->close = i8042_close;
+ serio->start = i8042_start;
+ serio->stop = i8042_stop;
+ serio->port_data = port;
+ serio->dev.parent = &i8042_platform_device->dev;
+- strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name));
++ strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
+ strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
+
+ port->serio = serio;
++ port->irq = I8042_KBD_IRQ;
+
+- return i8042_port_register(port);
++ return 0;
+ }
+
+-static int __devinit i8042_create_aux_port(void)
++static int __devinit i8042_create_aux_port(int idx)
+ {
+ struct serio *serio;
+- struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];
++ int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
++ struct i8042_port *port = &i8042_ports[port_no];
+
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!serio)
+@@ -1003,111 +965,191 @@ static int __devinit i8042_create_aux_po
+
+ serio->id.type = SERIO_8042;
+ serio->write = i8042_aux_write;
+- serio->open = i8042_open;
+- serio->close = i8042_close;
+ serio->start = i8042_start;
+ serio->stop = i8042_stop;
+ serio->port_data = port;
+ serio->dev.parent = &i8042_platform_device->dev;
+- strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));
+- strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
++ if (idx < 0) {
++ strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
++ strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
++ } else {
++ snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
++ snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
++ }
+
+ port->serio = serio;
++ port->mux = idx;
++ port->irq = I8042_AUX_IRQ;
+
+- return i8042_port_register(port);
++ return 0;
+ }
+
+-static int __devinit i8042_create_mux_port(int index)
++static void __devinit i8042_free_kbd_port(void)
+ {
+- struct serio *serio;
+- struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];
++ kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
++ i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
++}
+
+- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+- if (!serio)
+- return -ENOMEM;
++static void __devinit i8042_free_aux_ports(void)
++{
++ int i;
+
+- serio->id.type = SERIO_8042;
+- serio->write = i8042_aux_write;
+- serio->open = i8042_open;
+- serio->close = i8042_close;
+- serio->start = i8042_start;
+- serio->stop = i8042_stop;
+- serio->port_data = port;
+- serio->dev.parent = &i8042_platform_device->dev;
+- snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index);
+- snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1);
++ for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
++ kfree(i8042_ports[i].serio);
++ i8042_ports[i].serio = NULL;
++ }
++}
+
+- *port = i8042_ports[I8042_AUX_PORT_NO];
+- port->exists = 0;
+- snprintf(port->name, sizeof(port->name), "AUX%d", index);
+- port->mux = index;
+- port->serio = serio;
++static void __devinit i8042_register_ports(void)
++{
++ int i;
+
+- return i8042_port_register(port);
++ for (i = 0; i < I8042_NUM_PORTS; i++) {
++ if (i8042_ports[i].serio) {
++ printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
++ i8042_ports[i].serio->name,
++ (unsigned long) I8042_DATA_REG,
++ (unsigned long) I8042_COMMAND_REG,
++ i8042_ports[i].irq);
++ serio_register_port(i8042_ports[i].serio);
++ }
++ }
+ }
+
+-static int __devinit i8042_probe(struct platform_device *dev)
++static void __devinit i8042_unregister_ports(void)
+ {
+- int i, have_ports = 0;
+- int err;
++ int i;
++
++ for (i = 0; i < I8042_NUM_PORTS; i++) {
++ if (i8042_ports[i].serio) {
++ serio_unregister_port(i8042_ports[i].serio);
++ i8042_ports[i].serio = NULL;
++ }
++ }
++}
+
+- init_timer(&i8042_timer);
+- i8042_timer.function = i8042_timer_func;
++static void i8042_free_irqs(void)
++{
++ if (i8042_aux_irq_registered)
++ free_irq(I8042_AUX_IRQ, i8042_platform_device);
++ if (i8042_kbd_irq_registered)
++ free_irq(I8042_KBD_IRQ, i8042_platform_device);
++
++ i8042_aux_irq_registered = i8042_kbd_irq_registered = 0;
++}
++
++static int __devinit i8042_setup_aux(void)
++{
++ int (*aux_enable)(void);
++ int error;
++ int i;
+
+- if (i8042_controller_init())
++ if (i8042_check_aux())
+ return -ENODEV;
+
+- if (!i8042_noaux && !i8042_check_aux()) {
+- if (!i8042_nomux && !i8042_check_mux()) {
+- for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
+- err = i8042_create_mux_port(i);
+- if (err)
+- goto err_unregister_ports;
+- }
+- } else {
+- err = i8042_create_aux_port();
+- if (err)
+- goto err_unregister_ports;
++ if (i8042_nomux || i8042_check_mux()) {
++ error = i8042_create_aux_port(-1);
++ if (error)
++ goto err_free_ports;
++ aux_enable = i8042_enable_aux_port;
++ } else {
++ for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
++ error = i8042_create_aux_port(i);
++ if (error)
++ goto err_free_ports;
+ }
+- have_ports = 1;
++ aux_enable = i8042_enable_mux_ports;
+ }
+
+- if (!i8042_nokbd) {
+- err = i8042_create_kbd_port();
+- if (err)
+- goto err_unregister_ports;
+- have_ports = 1;
+- }
++ error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
++ "i8042", i8042_platform_device);
++ if (error)
++ goto err_free_ports;
+
+- if (!have_ports) {
+- err = -ENODEV;
+- goto err_controller_cleanup;
+- }
++ if (aux_enable())
++ goto err_free_irq;
+
+- mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
++ i8042_aux_irq_registered = 1;
+ return 0;
+
+- err_unregister_ports:
+- for (i = 0; i < I8042_NUM_PORTS; i++)
+- if (i8042_ports[i].serio)
+- serio_unregister_port(i8042_ports[i].serio);
+- err_controller_cleanup:
+- i8042_controller_cleanup();
++ err_free_irq:
++ free_irq(I8042_AUX_IRQ, i8042_platform_device);
++ err_free_ports:
++ i8042_free_aux_ports();
++ return error;
++}
+
+- return err;
++static int __devinit i8042_setup_kbd(void)
++{
++ int error;
++
++ error = i8042_create_kbd_port();
++ if (error)
++ return error;
++
++ error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
++ "i8042", i8042_platform_device);
++ if (error)
++ goto err_free_port;
++
++ error = i8042_enable_kbd_port();
++ if (error)
++ goto err_free_irq;
++
++ i8042_kbd_irq_registered = 1;
++ return 0;
++
++ err_free_irq:
++ free_irq(I8042_KBD_IRQ, i8042_platform_device);
++ err_free_port:
++ i8042_free_kbd_port();
++ return error;
+ }
+
+-static int __devexit i8042_remove(struct platform_device *dev)
++static int __devinit i8042_probe(struct platform_device *dev)
+ {
+- int i;
++ int error;
+
+- i8042_controller_cleanup();
++ error = i8042_controller_selftest();
++ if (error)
++ return error;
+
+- for (i = 0; i < I8042_NUM_PORTS; i++)
+- if (i8042_ports[i].exists)
+- serio_unregister_port(i8042_ports[i].serio);
++ error = i8042_controller_init();
++ if (error)
++ return error;
++
++ if (!i8042_noaux) {
++ error = i8042_setup_aux();
++ if (error && error != -ENODEV && error != -EBUSY)
++ goto out_fail;
++ }
++
++ if (!i8042_nokbd) {
++ error = i8042_setup_kbd();
++ if (error)
++ goto out_fail;
++ }
+
+- del_timer_sync(&i8042_timer);
++/*
++ * Ok, everything is ready, let's register all serio ports
++ */
++ i8042_register_ports();
++
++ return 0;
++
++ out_fail:
++ i8042_free_aux_ports(); /* in case KBD failed but AUX not */
++ i8042_free_irqs();
++ i8042_controller_reset();
++
++ return error;
++}
++
++static int __devexit i8042_remove(struct platform_device *dev)
++{
++ i8042_unregister_ports();
++ i8042_free_irqs();
++ i8042_controller_reset();
+
+ return 0;
+ }
+@@ -1134,8 +1176,9 @@ static int __init i8042_init(void)
+ if (err)
+ return err;
+
+- i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
+- i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
++ err = i8042_controller_check();
++ if (err)
++ goto err_platform_exit;
+
+ err = platform_driver_register(&i8042_driver);
+ if (err)
+@@ -1151,6 +1194,8 @@ static int __init i8042_init(void)
+ if (err)
+ goto err_free_device;
+
++ panic_blink = i8042_panic_blink;
++
+ return 0;
+
+ err_free_device:
+@@ -1167,7 +1212,6 @@ static void __exit i8042_exit(void)
+ {
+ platform_device_unregister(i8042_platform_device);
+ platform_driver_unregister(&i8042_driver);
+-
+ i8042_platform_exit();
+
+ panic_blink = NULL;
+diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
+index af526ab..b3eb7a7 100644
+--- a/drivers/input/serio/i8042.h
++++ b/drivers/input/serio/i8042.h
+@@ -37,15 +37,6 @@
+ #define I8042_CTL_TIMEOUT 10000
+
+ /*
+- * When the device isn't opened and it's interrupts aren't used, we poll it at
+- * regular intervals to see if any characters arrived. If yes, we can start
+- * probing for any mouse / keyboard connected. This is the period of the
+- * polling.
+- */
+-
+-#define I8042_POLL_PERIOD HZ/20
+-
+-/*
+ * Status register bits.
+ */
+
+diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
+index ed202f2..e5b1b60 100644
+--- a/drivers/input/serio/libps2.c
++++ b/drivers/input/serio/libps2.c
+@@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor at mai
+ MODULE_DESCRIPTION("PS/2 driver library");
+ 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);
+-EXPORT_SYMBOL(ps2_handle_response);
+-EXPORT_SYMBOL(ps2_cmd_aborted);
+-
+ /* Work structure to schedule execution of a command */
+ struct ps2work {
+ struct work_struct work;
+@@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev,
+
+ return -ps2dev->nak;
+ }
++EXPORT_SYMBOL(ps2_sendbyte);
+
+ /*
+ * ps2_drain() waits for device to transmit requested number of bytes
+@@ -96,15 +88,16 @@ void ps2_drain(struct ps2dev *ps2dev, in
+ msecs_to_jiffies(timeout));
+ mutex_unlock(&ps2dev->cmd_mutex);
+ }
++EXPORT_SYMBOL(ps2_drain);
+
+ /*
+ * 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)
++int ps2_is_keyboard_id(char id_byte)
+ {
+- static char keyboard_ids[] = {
++ const static char keyboard_ids[] = {
+ 0xab, /* Regular keyboards */
+ 0xac, /* NCD Sun keyboard */
+ 0x2b, /* Trust keyboard, translated */
+@@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(cha
+
+ return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+ }
++EXPORT_SYMBOL(ps2_is_keyboard_id);
+
+ /*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+@@ -139,6 +133,19 @@ static int ps2_adjust_timeout(struct ps2
+
+ case PS2_CMD_GETID:
+ /*
++ * Microsoft Natural Elite keyboard responds to
++ * the GET ID command as it were a mouse, with
++ * a single byte. Fail the command so atkbd will
++ * use alternative probe to detect it.
++ */
++ if (ps2dev->cmdbuf[1] == 0xaa) {
++ serio_pause_rx(ps2dev->serio);
++ ps2dev->flags = 0;
++ serio_continue_rx(ps2dev->serio);
++ timeout = 0;
++ }
++
++ /*
+ * If device behind the port is not a keyboard there
+ * won't be 2nd byte of ID response.
+ */
+@@ -182,7 +189,7 @@ int ps2_command(struct ps2dev *ps2dev, u
+ return -1;
+ }
+
+- mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING);
++ mutex_lock(&ps2dev->cmd_mutex);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
+@@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, u
+ mutex_unlock(&ps2dev->cmd_mutex);
+ return rc;
+ }
++EXPORT_SYMBOL(ps2_command);
+
+ /*
+ * ps2_execute_scheduled_command() sends a command, previously scheduled by
+@@ -279,6 +287,7 @@ int ps2_schedule_command(struct ps2dev *
+
+ return 0;
+ }
++EXPORT_SYMBOL(ps2_schedule_command);
+
+ /*
+ * ps2_init() initializes ps2dev structure
+@@ -287,9 +296,11 @@ int ps2_schedule_command(struct ps2dev *
+ void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
+ {
+ mutex_init(&ps2dev->cmd_mutex);
++ lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth);
+ init_waitqueue_head(&ps2dev->wait);
+ ps2dev->serio = serio;
+ }
++EXPORT_SYMBOL(ps2_init);
+
+ /*
+ * ps2_handle_ack() is supposed to be used in interrupt handler
+@@ -335,6 +346,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev
+
+ return 1;
+ }
++EXPORT_SYMBOL(ps2_handle_ack);
+
+ /*
+ * ps2_handle_response() is supposed to be used in interrupt handler
+@@ -360,6 +372,7 @@ int ps2_handle_response(struct ps2dev *p
+
+ return 1;
+ }
++EXPORT_SYMBOL(ps2_handle_response);
+
+ void ps2_cmd_aborted(struct ps2dev *ps2dev)
+ {
+@@ -371,4 +384,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2d
+
+ ps2dev->flags = 0;
+ }
+-
++EXPORT_SYMBOL(ps2_cmd_aborted);
+diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
+index f08a5d0..558200e 100644
+--- a/drivers/input/serio/maceps2.c
++++ b/drivers/input/serio/maceps2.c
+@@ -72,8 +72,7 @@ static int maceps2_write(struct serio *d
+ return -1;
+ }
+
+-static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t maceps2_interrupt(int irq, void *dev_id)
+ {
+ struct serio *dev = dev_id;
+ struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port;
+@@ -81,7 +80,7 @@ static irqreturn_t maceps2_interrupt(int
+
+ if (port->status & PS2_STATUS_RX_FULL) {
+ byte = port->rx;
+- serio_interrupt(dev, byte & 0xff, 0, regs);
++ serio_interrupt(dev, byte & 0xff, 0);
+ }
+
+ return IRQ_HANDLED;
+diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
+index a5c1fb3..688610e 100644
+--- a/drivers/input/serio/parkbd.c
++++ b/drivers/input/serio/parkbd.c
+@@ -102,7 +102,7 @@ static int parkbd_write(struct serio *po
+ return 0;
+ }
+
+-static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void parkbd_interrupt(int irq, void *dev_id)
+ {
+
+ if (parkbd_writing) {
+@@ -134,7 +134,7 @@ static void parkbd_interrupt(int irq, vo
+ parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
+
+ if (parkbd_counter == parkbd_mode + 10)
+- serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs);
++ serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
+ }
+
+ parkbd_last = jiffies;
+diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
+index fb727c6..ea5e3c6 100644
+--- a/drivers/input/serio/pcips2.c
++++ b/drivers/input/serio/pcips2.c
+@@ -58,7 +58,7 @@ static int pcips2_write(struct serio *io
+ return 0;
+ }
+
+-static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t pcips2_interrupt(int irq, void *devid)
+ {
+ struct pcips2_data *ps2if = devid;
+ unsigned char status, scancode;
+@@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int
+ if (hweight8(scancode) & 1)
+ flag ^= SERIO_PARITY;
+
+- serio_interrupt(ps2if->io, scancode, flag, regs);
++ serio_interrupt(ps2if->io, scancode, flag);
+ } while (1);
+ return IRQ_RETVAL(handled);
+ }
+diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
+index d3827c5..cb89aff 100644
+--- a/drivers/input/serio/q40kbd.c
++++ b/drivers/input/serio/q40kbd.c
+@@ -53,14 +53,14 @@ DEFINE_SPINLOCK(q40kbd_lock);
+ static struct serio *q40kbd_port;
+ static struct platform_device *q40kbd_device;
+
+-static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&q40kbd_lock, flags);
+
+ if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
+- serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs);
++ serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0);
+
+ master_outb(-1, KEYBOARD_UNLOCK_REG);
+
+diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
+index 513d37f..49f8431 100644
+--- a/drivers/input/serio/rpckbd.c
++++ b/drivers/input/serio/rpckbd.c
+@@ -56,7 +56,7 @@ static int rpckbd_write(struct serio *po
+ return 0;
+ }
+
+-static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t rpckbd_rx(int irq, void *dev_id)
+ {
+ struct serio *port = dev_id;
+ unsigned int byte;
+@@ -65,13 +65,13 @@ static irqreturn_t rpckbd_rx(int irq, vo
+ while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
+ byte = iomd_readb(IOMD_KARTRX);
+
+- serio_interrupt(port, byte, 0, regs);
++ serio_interrupt(port, byte, 0);
+ handled = IRQ_HANDLED;
+ }
+ return handled;
+ }
+
+-static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t rpckbd_tx(int irq, void *dev_id)
+ {
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
+index ebd9976..5595087 100644
+--- a/drivers/input/serio/sa1111ps2.c
++++ b/drivers/input/serio/sa1111ps2.c
+@@ -40,7 +40,7 @@ struct ps2if {
+ * at the most one, but we loop for safety. If there was a
+ * framing error, we have to manually clear the status.
+ */
+-static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ps2_rxint(int irq, void *dev_id)
+ {
+ struct ps2if *ps2if = dev_id;
+ unsigned int scancode, flag, status;
+@@ -58,7 +58,7 @@ static irqreturn_t ps2_rxint(int irq, vo
+ if (hweight8(scancode) & 1)
+ flag ^= SERIO_PARITY;
+
+- serio_interrupt(ps2if->io, scancode, flag, regs);
++ serio_interrupt(ps2if->io, scancode, flag);
+
+ status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+ }
+@@ -69,7 +69,7 @@ static irqreturn_t ps2_rxint(int irq, vo
+ /*
+ * Completion of ps2 write
+ */
+-static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ps2_txint(int irq, void *dev_id)
+ {
+ struct ps2if *ps2if = dev_id;
+ unsigned int status;
+diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
+index 3e76ad7..211943f 100644
+--- a/drivers/input/serio/serio.c
++++ b/drivers/input/serio/serio.c
+@@ -118,6 +118,8 @@ static int serio_match_port(const struct
+
+ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
+ {
++ int error;
++
+ down_write(&serio_bus.subsys.rwsem);
+
+ if (serio_match_port(drv->id_table, serio)) {
+@@ -126,9 +128,19 @@ static void serio_bind_driver(struct ser
+ serio->dev.driver = NULL;
+ goto out;
+ }
+- device_bind_driver(&serio->dev);
++ error = device_bind_driver(&serio->dev);
++ if (error) {
++ printk(KERN_WARNING
++ "serio: device_bind_driver() failed "
++ "for %s (%s) and %s, error: %d\n",
++ serio->phys, serio->name,
++ drv->description, error);
++ serio_disconnect_driver(serio);
++ serio->dev.driver = NULL;
++ goto out;
++ }
+ }
+-out:
++ out:
+ up_write(&serio_bus.subsys.rwsem);
+ }
+
+@@ -538,8 +550,12 @@ static void serio_init_port(struct serio
+ "serio%ld", (long)atomic_inc_return(&serio_no) - 1);
+ serio->dev.bus = &serio_bus;
+ serio->dev.release = serio_release_port;
+- if (serio->parent)
++ if (serio->parent) {
+ serio->dev.parent = &serio->parent->dev;
++ serio->depth = serio->parent->depth + 1;
++ } else
++ serio->depth = 0;
++ lockdep_set_subclass(&serio->lock, serio->depth);
+ }
+
+ /*
+@@ -911,7 +927,7 @@ void serio_close(struct serio *serio)
+ }
+
+ irqreturn_t serio_interrupt(struct serio *serio,
+- unsigned char data, unsigned int dfl, struct pt_regs *regs)
++ unsigned char data, unsigned int dfl)
+ {
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+@@ -919,7 +935,7 @@ irqreturn_t serio_interrupt(struct serio
+ spin_lock_irqsave(&serio->lock, flags);
+
+ if (likely(serio->drv)) {
+- ret = serio->drv->interrupt(serio, data, dfl, regs);
++ ret = serio->drv->interrupt(serio, data, dfl);
+ } else if (!dfl && serio->registered) {
+ serio_rescan(serio);
+ ret = IRQ_HANDLED;
+diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
+index 71a8eea..ba2a203 100644
+--- a/drivers/input/serio/serio_raw.c
++++ b/drivers/input/serio/serio_raw.c
+@@ -250,7 +250,7 @@ static struct file_operations serio_raw_
+ *********************************************************************/
+
+ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
+- unsigned int dfl, struct pt_regs *regs)
++ unsigned int dfl)
+ {
+ struct serio_raw *serio_raw = serio_get_drvdata(serio);
+ struct serio_raw_list *list;
+diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
+index 54a680c..e1a3a79 100644
+--- a/drivers/input/serio/serport.c
++++ b/drivers/input/serio/serport.c
+@@ -117,9 +117,6 @@ static void serport_ldisc_close(struct t
+ * serport_ldisc_receive() is called by the low level tty driver when characters
+ * are ready for us. We forward the characters, one by one to the 'interrupt'
+ * routine.
+- *
+- * FIXME: We should get pt_regs from the tty layer and forward them to
+- * serio_interrupt here.
+ */
+
+ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+@@ -134,7 +131,7 @@ static void serport_ldisc_receive(struct
+ goto out;
+
+ for (i = 0; i < count; i++)
+- serio_interrupt(serport->serio, cp[i], 0, NULL);
++ serio_interrupt(serport->serio, cp[i], 0);
+
+ out:
+ spin_unlock_irqrestore(&serport->lock, flags);
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index b1b14f8..9418bbe 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600
+ To compile this driver as a module, choose M here: the
+ module will be called hp680_ts_input.
+
++config TOUCHSCREEN_PENMOUNT
++ tristate "Penmount serial touchscreen"
++ select SERIO
++ help
++ Say Y here if you have a Penmount serial touchscreen connected to
++ your system.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called penmount.
++
++config TOUCHSCREEN_TOUCHRIGHT
++ tristate "Touchright serial touchscreen"
++ select SERIO
++ help
++ Say Y here if you have a Touchright serial touchscreen connected to
++ your system.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called touchright.
++
++config TOUCHSCREEN_TOUCHWIN
++ tristate "Touchwin serial touchscreen"
++ select SERIO
++ help
++ Say Y here if you have a Touchwin serial touchscreen connected to
++ your system.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called touchwin.
++
+ endif
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 5e5557c..1abb8f1 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
+ obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
+ obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
++obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
++obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
++obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
+diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
+index 66e411b..f56d6a0 100644
+--- a/drivers/input/touchscreen/ads7846.c
++++ b/drivers/input/touchscreen/ads7846.c
+@@ -487,7 +487,7 @@ static void ads7846_timer(unsigned long
+ spin_unlock_irq(&ts->lock);
+ }
+
+-static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
++static irqreturn_t ads7846_irq(int irq, void *handle)
+ {
+ struct ads7846 *ts = handle;
+ unsigned long flags;
+diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
+index 9b66271..66121f6 100644
+--- a/drivers/input/touchscreen/corgi_ts.c
++++ b/drivers/input/touchscreen/corgi_ts.c
+@@ -173,7 +173,7 @@ static int read_xydata(struct corgi_ts *
+ return 1;
+ }
+
+-static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
++static void new_data(struct corgi_ts *corgi_ts)
+ {
+ if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
+ return;
+@@ -181,7 +181,6 @@ static void new_data(struct corgi_ts *co
+ if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
+ return;
+
+- input_regs(corgi_ts->input, regs);
+ input_report_abs(corgi_ts->input, ABS_X, corgi_ts->tc.x);
+ input_report_abs(corgi_ts->input, ABS_Y, corgi_ts->tc.y);
+ input_report_abs(corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
+@@ -189,14 +188,14 @@ static void new_data(struct corgi_ts *co
+ input_sync(corgi_ts->input);
+ }
+
+-static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
++static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer)
+ {
+ if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) {
+ /* Disable Interrupt */
+ set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE);
+ if (read_xydata(corgi_ts)) {
+ corgi_ts->pendown = 1;
+- new_data(corgi_ts, regs);
++ new_data(corgi_ts);
+ }
+ mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
+ } else {
+@@ -208,7 +207,7 @@ static void ts_interrupt_main(struct cor
+
+ if (corgi_ts->pendown) {
+ corgi_ts->tc.pressure = 0;
+- new_data(corgi_ts, regs);
++ new_data(corgi_ts);
+ }
+
+ /* Enable Falling Edge */
+@@ -220,13 +219,13 @@ static void ts_interrupt_main(struct cor
+ static void corgi_ts_timer(unsigned long data)
+ {
+ struct corgi_ts *corgits_data = (struct corgi_ts *) data;
+- ts_interrupt_main(corgits_data, 1, NULL);
++ ts_interrupt_main(corgits_data, 1);
+ }
+
+-static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ts_interrupt(int irq, void *dev_id)
+ {
+ struct corgi_ts *corgits_data = dev_id;
+- ts_interrupt_main(corgits_data, 0, regs);
++ ts_interrupt_main(corgits_data, 0);
+ return IRQ_HANDLED;
+ }
+
+@@ -238,7 +237,7 @@ static int corgits_suspend(struct platfo
+ if (corgi_ts->pendown) {
+ del_timer_sync(&corgi_ts->timer);
+ corgi_ts->tc.pressure = 0;
+- new_data(corgi_ts, NULL);
++ new_data(corgi_ts);
+ corgi_ts->pendown = 0;
+ }
+ corgi_ts->power_mode = PWR_MODE_SUSPEND;
+diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
+index c86a2eb..913e1b7 100644
+--- a/drivers/input/touchscreen/elo.c
++++ b/drivers/input/touchscreen/elo.c
+@@ -23,6 +23,7 @@
+ #include <linux/input.h>
+ #include <linux/serio.h>
+ #include <linux/init.h>
++#include <linux/ctype.h>
+
+ #define DRIVER_DESC "Elo serial touchscreen driver"
+
+@@ -34,7 +35,19 @@ MODULE_LICENSE("GPL");
+ * Definitions & global arrays.
+ */
+
+-#define ELO_MAX_LENGTH 10
++#define ELO_MAX_LENGTH 10
++
++#define ELO10_PACKET_LEN 8
++#define ELO10_TOUCH 0x03
++#define ELO10_PRESSURE 0x80
++
++#define ELO10_LEAD_BYTE 'U'
++
++#define ELO10_ID_CMD 'i'
++
++#define ELO10_TOUCH_PACKET 'T'
++#define ELO10_ACK_PACKET 'A'
++#define ELI10_ID_PACKET 'I'
+
+ /*
+ * Per-touchscreen data.
+@@ -43,51 +56,66 @@ MODULE_LICENSE("GPL");
+ struct elo {
+ struct input_dev *dev;
+ struct serio *serio;
++ struct mutex cmd_mutex;
++ struct completion cmd_done;
+ int id;
+ int idx;
++ unsigned char expected_packet;
+ unsigned char csum;
+ unsigned char data[ELO_MAX_LENGTH];
++ unsigned char response[ELO10_PACKET_LEN];
+ char phys[32];
+ };
+
+-static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs)
++static void elo_process_data_10(struct elo *elo, unsigned char data)
+ {
+ struct input_dev *dev = elo->dev;
+
+- elo->csum += elo->data[elo->idx] = data;
+-
++ elo->data[elo->idx] = data;
+ switch (elo->idx++) {
+-
+ case 0:
+- if (data != 'U') {
++ elo->csum = 0xaa;
++ if (data != ELO10_LEAD_BYTE) {
++ pr_debug("elo: unsynchronized data: 0x%02x\n", data);
+ elo->idx = 0;
+- elo->csum = 0;
+- }
+- break;
+-
+- case 1:
+- if (data != 'T') {
+- elo->idx = 0;
+- elo->csum = 0;
+ }
+ break;
+
+ case 9:
+- if (elo->csum) {
+- input_regs(dev, regs);
++ elo->idx = 0;
++ if (data != elo->csum) {
++ pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
++ data, elo->csum);
++ break;
++ }
++ if (elo->data[1] != elo->expected_packet) {
++ if (elo->data[1] != ELO10_TOUCH_PACKET)
++ pr_debug("elo: unexpected packet: 0x%02x\n",
++ elo->data[1]);
++ break;
++ }
++ if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
+ input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+ input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+- input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]);
+- input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]);
++ if (elo->data[2] & ELO10_PRESSURE)
++ input_report_abs(dev, ABS_PRESSURE,
++ (elo->data[8] << 8) | elo->data[7]);
++ input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
+ input_sync(dev);
++ } else if (elo->data[1] == ELO10_ACK_PACKET) {
++ if (elo->data[2] == '0')
++ elo->expected_packet = ELO10_TOUCH_PACKET;
++ complete(&elo->cmd_done);
++ } else {
++ memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
++ elo->expected_packet = ELO10_ACK_PACKET;
+ }
+- elo->idx = 0;
+- elo->csum = 0;
+ break;
+ }
++ elo->csum += data;
+ }
+
+-static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs)
++static void elo_process_data_6(struct elo *elo, unsigned char data)
+ {
+ struct input_dev *dev = elo->dev;
+
+@@ -105,7 +133,6 @@ static void elo_process_data_6(struct el
+ break;
+ }
+
+- input_regs(dev, regs);
+ input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+ input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+
+@@ -135,7 +162,7 @@ static void elo_process_data_6(struct el
+ }
+ }
+
+-static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs)
++static void elo_process_data_3(struct elo *elo, unsigned char data)
+ {
+ struct input_dev *dev = elo->dev;
+
+@@ -148,7 +175,6 @@ static void elo_process_data_3(struct el
+ elo->idx = 0;
+ break;
+ case 2:
+- input_regs(dev, regs);
+ input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+ input_report_abs(dev, ABS_X, elo->data[1]);
+ input_report_abs(dev, ABS_Y, elo->data[2]);
+@@ -159,39 +185,103 @@ static void elo_process_data_3(struct el
+ }
+
+ static irqreturn_t elo_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+- struct elo* elo = serio_get_drvdata(serio);
++ struct elo *elo = serio_get_drvdata(serio);
+
+ switch(elo->id) {
+ case 0:
+- elo_process_data_10(elo, data, regs);
++ elo_process_data_10(elo, data);
+ break;
+
+ case 1:
+ case 2:
+- elo_process_data_6(elo, data, regs);
++ elo_process_data_6(elo, data);
+ break;
+
+ case 3:
+- elo_process_data_3(elo, data, regs);
++ elo_process_data_3(elo, data);
+ break;
+ }
+
+ return IRQ_HANDLED;
+ }
+
++static int elo_command_10(struct elo *elo, unsigned char *packet)
++{
++ int rc = -1;
++ int i;
++ unsigned char csum = 0xaa + ELO10_LEAD_BYTE;
++
++ mutex_lock(&elo->cmd_mutex);
++
++ serio_pause_rx(elo->serio);
++ elo->expected_packet = toupper(packet[0]);
++ init_completion(&elo->cmd_done);
++ serio_continue_rx(elo->serio);
++
++ if (serio_write(elo->serio, ELO10_LEAD_BYTE))
++ goto out;
++
++ for (i = 0; i < ELO10_PACKET_LEN; i++) {
++ csum += packet[i];
++ if (serio_write(elo->serio, packet[i]))
++ goto out;
++ }
++
++ if (serio_write(elo->serio, csum))
++ goto out;
++
++ wait_for_completion_timeout(&elo->cmd_done, HZ);
++
++ if (elo->expected_packet == ELO10_TOUCH_PACKET) {
++ /* We are back in reporting mode, the command was ACKed */
++ memcpy(packet, elo->response, ELO10_PACKET_LEN);
++ rc = 0;
++ }
++
++ out:
++ mutex_unlock(&elo->cmd_mutex);
++ return rc;
++}
++
++static int elo_setup_10(struct elo *elo)
++{
++ static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" };
++ struct input_dev *dev = elo->dev;
++ unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD };
++
++ if (elo_command_10(elo, packet))
++ return -1;
++
++ dev->id.version = (packet[5] << 8) | packet[4];
++
++ input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0);
++ input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0);
++ if (packet[3] & ELO10_PRESSURE)
++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
++
++ printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
++ "features: %x02x, controller: 0x%02x\n",
++ elo_types[(packet[1] -'0') & 0x03],
++ packet[5], packet[4], packet[3], packet[7]);
++
++ return 0;
++}
++
+ /*
+ * elo_disconnect() is the opposite of elo_connect()
+ */
+
+ static void elo_disconnect(struct serio *serio)
+ {
+- struct elo* elo = serio_get_drvdata(serio);
++ struct elo *elo = serio_get_drvdata(serio);
+
++ input_get_device(elo->dev);
+ input_unregister_device(elo->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
++ input_put_device(elo->dev);
+ kfree(elo);
+ }
+
+@@ -211,12 +301,15 @@ static int elo_connect(struct serio *ser
+ input_dev = input_allocate_device();
+ if (!elo || !input_dev) {
+ err = -ENOMEM;
+- goto fail;
++ goto fail1;
+ }
+
+ elo->serio = serio;
+ elo->id = serio->id.id;
+ elo->dev = input_dev;
++ elo->expected_packet = ELO10_TOUCH_PACKET;
++ mutex_init(&elo->cmd_mutex);
++ init_completion(&elo->cmd_done);
+ snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
+
+ input_dev->private = elo;
+@@ -231,12 +324,17 @@ static int elo_connect(struct serio *ser
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
++ serio_set_drvdata(serio, elo);
++ err = serio_open(serio, drv);
++ if (err)
++ goto fail2;
++
+ switch (elo->id) {
+
+ case 0: /* 10-byte protocol */
+- input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
+- input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
+- input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
++ if (elo_setup_10(elo))
++ goto fail3;
++
+ break;
+
+ case 1: /* 6-byte protocol */
+@@ -253,17 +351,15 @@ static int elo_connect(struct serio *ser
+ break;
+ }
+
+- serio_set_drvdata(serio, elo);
+-
+- err = serio_open(serio, drv);
++ err = input_register_device(elo->dev);
+ if (err)
+- goto fail;
++ goto fail3;
+
+- input_register_device(elo->dev);
+ return 0;
+
+- fail: serio_set_drvdata(serio, NULL);
+- input_free_device(input_dev);
++ fail3: serio_close(serio);
++ fail2: serio_set_drvdata(serio, NULL);
++ fail1: input_free_device(input_dev);
+ kfree(elo);
+ return err;
+ }
+diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
+index b769b21..817c219 100644
+--- a/drivers/input/touchscreen/gunze.c
++++ b/drivers/input/touchscreen/gunze.c
+@@ -60,7 +60,7 @@ struct gunze {
+ char phys[32];
+ };
+
+-static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
++static void gunze_process_packet(struct gunze* gunze)
+ {
+ struct input_dev *dev = gunze->dev;
+
+@@ -70,7 +70,6 @@ static void gunze_process_packet(struct
+ return;
+ }
+
+- input_regs(dev, regs);
+ input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
+ input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
+ input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
+@@ -78,12 +77,12 @@ static void gunze_process_packet(struct
+ }
+
+ static irqreturn_t gunze_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct gunze* gunze = serio_get_drvdata(serio);
+
+ if (data == '\r') {
+- gunze_process_packet(gunze, regs);
++ gunze_process_packet(gunze);
+ gunze->idx = 0;
+ } else {
+ if (gunze->idx < GUNZE_MAX_LENGTH)
+diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
+index e2b9100..d9e61ee 100644
+--- a/drivers/input/touchscreen/h3600_ts_input.c
++++ b/drivers/input/touchscreen/h3600_ts_input.c
+@@ -106,19 +106,18 @@ struct h3600_dev {
+ char phys[32];
+ };
+
+-static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t action_button_handler(int irq, void *dev_id)
+ {
+ int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+ struct input_dev *dev = (struct input_dev *) dev_id;
+
+- input_regs(dev, regs);
+ input_report_key(dev, KEY_ENTER, down);
+ input_sync(dev);
+
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t npower_button_handler(int irq, void *dev_id)
+ {
+ int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+ struct input_dev *dev = (struct input_dev *) dev_id;
+@@ -127,7 +126,6 @@ static irqreturn_t npower_button_handler
+ * This interrupt is only called when we release the key. So we have
+ * to fake a key press.
+ */
+- input_regs(dev, regs);
+ input_report_key(dev, KEY_SUSPEND, 1);
+ input_report_key(dev, KEY_SUSPEND, down);
+ input_sync(dev);
+@@ -165,14 +163,12 @@ unsigned int h3600_flite_power(struct in
+ * packets. Some packets coming from serial are not touchscreen related. In
+ * this case we send them off to be processed elsewhere.
+ */
+-static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
++static void h3600ts_process_packet(struct h3600_dev *ts)
+ {
+ 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
+@@ -301,7 +297,7 @@ static int state;
+ #define STATE_EOF 3 /* state where we decode checksum or EOF */
+
+ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
+- unsigned int flags, struct pt_regs *regs)
++ unsigned int flags)
+ {
+ struct h3600_dev *ts = serio_get_drvdata(serio);
+
+@@ -333,7 +329,7 @@ static irqreturn_t h3600ts_interrupt(str
+ case STATE_EOF:
+ state = STATE_SOF;
+ if (data == CHAR_EOF || data == ts->chksum)
+- h3600ts_process_packet(ts, regs);
++ h3600ts_process_packet(ts);
+ break;
+ default:
+ printk("Error3\n");
+diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
+index fa97e0f..58fca31 100644
+--- a/drivers/input/touchscreen/hp680_ts_input.c
++++ b/drivers/input/touchscreen/hp680_ts_input.c
+@@ -6,7 +6,7 @@
+ #include <asm/io.h>
+ #include <asm/delay.h>
+ #include <asm/adc.h>
+-#include <asm/hp6xx/hp6xx.h>
++#include <asm/hp6xx.h>
+
+ #define MODNAME "hp680_ts_input"
+
+@@ -15,7 +15,6 @@
+ #define HP680_TS_ABS_Y_MIN 80
+ #define HP680_TS_ABS_Y_MAX 910
+
+-#define SCPCR 0xa4000116
+ #define PHDR 0xa400012e
+ #define SCPDR 0xa4000136
+
+@@ -67,7 +66,7 @@ static void do_softint(void *data)
+ enable_irq(HP680_TS_IRQ);
+ }
+
+-static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
+ {
+ disable_irq_nosync(irq);
+ schedule_delayed_work(&work, HZ / 20);
+@@ -77,19 +76,6 @@ static irqreturn_t hp680_ts_interrupt(in
+
+ static int __init hp680_ts_init(void)
+ {
+- u8 scpdr;
+- u16 scpcr;
+-
+- scpdr = ctrl_inb(SCPDR);
+- scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
+- scpdr &= ~SCPDR_TS_SCAN_ENABLE;
+- ctrl_outb(scpdr, SCPDR);
+-
+- scpcr = ctrl_inw(SCPCR);
+- scpcr &= ~SCPCR_TS_MASK;
+- scpcr |= SCPCR_TS_ENABLE;
+- ctrl_outw(scpcr, SCPCR);
+-
+ hp680_ts_dev = input_allocate_device();
+ if (!hp680_ts_dev)
+ return -ENOMEM;
+diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
+index 3226830..4cbcaa6 100644
+--- a/drivers/input/touchscreen/mk712.c
++++ b/drivers/input/touchscreen/mk712.c
+@@ -80,7 +80,7 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touc
+ static struct input_dev *mk712_dev;
+ static DEFINE_SPINLOCK(mk712_lock);
+
+-static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mk712_interrupt(int irq, void *dev_id)
+ {
+ unsigned char status;
+ static int debounce = 1;
+@@ -88,7 +88,6 @@ static irqreturn_t mk712_interrupt(int i
+ static unsigned short last_y;
+
+ spin_lock(&mk712_lock);
+- input_regs(mk712_dev, regs);
+
+ status = inb(mk712_io + MK712_STATUS);
+
+diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
+index 8647a90..3b4c616 100644
+--- a/drivers/input/touchscreen/mtouch.c
++++ b/drivers/input/touchscreen/mtouch.c
+@@ -63,12 +63,11 @@ struct mtouch {
+ char phys[32];
+ };
+
+-static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs)
++static void mtouch_process_format_tablet(struct mtouch *mtouch)
+ {
+ struct input_dev *dev = mtouch->dev;
+
+ if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
+- input_regs(dev, regs);
+ input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
+ input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
+ input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
+@@ -78,7 +77,7 @@ static void mtouch_process_format_tablet
+ }
+ }
+
+-static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs)
++static void mtouch_process_response(struct mtouch *mtouch)
+ {
+ if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
+ /* FIXME - process response */
+@@ -90,16 +89,16 @@ static void mtouch_process_response(stru
+ }
+
+ static irqreturn_t mtouch_interrupt(struct serio *serio,
+- unsigned char data, unsigned int flags, struct pt_regs *regs)
++ unsigned char data, unsigned int flags)
+ {
+ struct mtouch* mtouch = serio_get_drvdata(serio);
+
+ mtouch->data[mtouch->idx] = data;
+
+ if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
+- mtouch_process_format_tablet(mtouch, regs);
++ mtouch_process_format_tablet(mtouch);
+ else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
+- mtouch_process_response(mtouch, regs);
++ mtouch_process_response(mtouch);
+ else
+ printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
+
+diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
+new file mode 100644
+index 0000000..6c7d0c2
+--- /dev/null
++++ b/drivers/input/touchscreen/penmount.c
+@@ -0,0 +1,184 @@
++/*
++ * Penmount serial touchscreen driver
++ *
++ * Copyright (c) 2006 Rick Koch <n1gp at hotmail.com>
++ *
++ * Based on ELO driver (drivers/input/touchscreen/elo.c)
++ * Copyright (c) 2004 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.
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/serio.h>
++#include <linux/init.h>
++
++#define DRIVER_DESC "Penmount serial touchscreen driver"
++
++MODULE_AUTHOR("Rick Koch <n1gp at hotmail.com>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++/*
++ * Definitions & global arrays.
++ */
++
++#define PM_MAX_LENGTH 5
++
++/*
++ * Per-touchscreen data.
++ */
++
++struct pm {
++ struct input_dev *dev;
++ struct serio *serio;
++ int idx;
++ unsigned char data[PM_MAX_LENGTH];
++ char phys[32];
++};
++
++static irqreturn_t pm_interrupt(struct serio *serio,
++ unsigned char data, unsigned int flags)
++{
++ struct pm *pm = serio_get_drvdata(serio);
++ struct input_dev *dev = pm->dev;
++
++ pm->data[pm->idx] = data;
++
++ if (pm->data[0] & 0x80) {
++ if (PM_MAX_LENGTH == ++pm->idx) {
++ input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]);
++ input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]);
++ input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
++ input_sync(dev);
++ pm->idx = 0;
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * pm_disconnect() is the opposite of pm_connect()
++ */
++
++static void pm_disconnect(struct serio *serio)
++{
++ struct pm *pm = serio_get_drvdata(serio);
++
++ input_get_device(pm->dev);
++ input_unregister_device(pm->dev);
++ serio_close(serio);
++ serio_set_drvdata(serio, NULL);
++ input_put_device(pm->dev);
++ kfree(pm);
++}
++
++/*
++ * pm_connect() is the routine that is called when someone adds a
++ * new serio device that supports Gunze protocol and registers it as
++ * an input device.
++ */
++
++static int pm_connect(struct serio *serio, struct serio_driver *drv)
++{
++ struct pm *pm;
++ struct input_dev *input_dev;
++ int err;
++
++ pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!pm || !input_dev) {
++ err = -ENOMEM;
++ goto fail1;
++ }
++
++ pm->serio = serio;
++ pm->dev = input_dev;
++ snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
++
++ input_dev->private = pm;
++ input_dev->name = "Penmount Serial TouchScreen";
++ input_dev->phys = pm->phys;
++ input_dev->id.bustype = BUS_RS232;
++ input_dev->id.vendor = SERIO_PENMOUNT;
++ input_dev->id.product = 0;
++ input_dev->id.version = 0x0100;
++ input_dev->cdev.dev = &serio->dev;
++
++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
++ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
++ input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0);
++ input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0);
++
++ serio_set_drvdata(serio, pm);
++
++ err = serio_open(serio, drv);
++ if (err)
++ goto fail2;
++
++ err = input_register_device(pm->dev);
++ if (err)
++ goto fail3;
++
++ return 0;
++
++ fail3: serio_close(serio);
++ fail2: serio_set_drvdata(serio, NULL);
++ fail1: input_free_device(input_dev);
++ kfree(pm);
++ return err;
++}
++
++/*
++ * The serio driver structure.
++ */
++
++static struct serio_device_id pm_serio_ids[] = {
++ {
++ .type = SERIO_RS232,
++ .proto = SERIO_PENMOUNT,
++ .id = SERIO_ANY,
++ .extra = SERIO_ANY,
++ },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(serio, pm_serio_ids);
++
++static struct serio_driver pm_drv = {
++ .driver = {
++ .name = "penmountlpc",
++ },
++ .description = DRIVER_DESC,
++ .id_table = pm_serio_ids,
++ .interrupt = pm_interrupt,
++ .connect = pm_connect,
++ .disconnect = pm_disconnect,
++};
++
++/*
++ * The functions for inserting/removing us as a module.
++ */
++
++static int __init pm_init(void)
++{
++ serio_register_driver(&pm_drv);
++ return 0;
++}
++
++static void __exit pm_exit(void)
++{
++ serio_unregister_driver(&pm_drv);
++}
++
++module_init(pm_init);
++module_exit(pm_exit);
+diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
+new file mode 100644
+index 0000000..c74f74e
+--- /dev/null
++++ b/drivers/input/touchscreen/touchright.c
+@@ -0,0 +1,195 @@
++/*
++ * Touchright serial touchscreen driver
++ *
++ * Copyright (c) 2006 Rick Koch <n1gp at hotmail.com>
++ *
++ * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
++ * Copyright (c) 2004 Vojtech Pavlik
++ * and Dan Streetman <ddstreet at ieee.org>
++ */
++
++/*
++ * 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/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/serio.h>
++#include <linux/init.h>
++
++#define DRIVER_DESC "Touchright serial touchscreen driver"
++
++MODULE_AUTHOR("Rick Koch <n1gp at hotmail.com>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++/*
++ * Definitions & global arrays.
++ */
++
++#define TR_FORMAT_TOUCH_BIT 0x01
++#define TR_FORMAT_STATUS_BYTE 0x40
++#define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT
++
++#define TR_LENGTH 5
++
++#define TR_MIN_XC 0
++#define TR_MAX_XC 0x1ff
++#define TR_MIN_YC 0
++#define TR_MAX_YC 0x1ff
++
++/*
++ * Per-touchscreen data.
++ */
++
++struct tr {
++ struct input_dev *dev;
++ struct serio *serio;
++ int idx;
++ unsigned char data[TR_LENGTH];
++ char phys[32];
++};
++
++static irqreturn_t tr_interrupt(struct serio *serio,
++ unsigned char data, unsigned int flags)
++{
++ struct tr *tr = serio_get_drvdata(serio);
++ struct input_dev *dev = tr->dev;
++
++ tr->data[tr->idx] = data;
++
++ if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) {
++ if (++tr->idx == TR_LENGTH) {
++ input_report_abs(dev, ABS_X,
++ (tr->data[1] << 5) | (tr->data[2] >> 1));
++ input_report_abs(dev, ABS_Y,
++ (tr->data[3] << 5) | (tr->data[4] >> 1));
++ input_report_key(dev, BTN_TOUCH,
++ tr->data[0] & TR_FORMAT_TOUCH_BIT);
++ input_sync(dev);
++ tr->idx = 0;
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * tr_disconnect() is the opposite of tr_connect()
++ */
++
++static void tr_disconnect(struct serio *serio)
++{
++ struct tr *tr = serio_get_drvdata(serio);
++
++ input_get_device(tr->dev);
++ input_unregister_device(tr->dev);
++ serio_close(serio);
++ serio_set_drvdata(serio, NULL);
++ input_put_device(tr->dev);
++ kfree(tr);
++}
++
++/*
++ * tr_connect() is the routine that is called when someone adds a
++ * new serio device that supports the Touchright protocol and registers it as
++ * an input device.
++ */
++
++static int tr_connect(struct serio *serio, struct serio_driver *drv)
++{
++ struct tr *tr;
++ struct input_dev *input_dev;
++ int err;
++
++ tr = kzalloc(sizeof(struct tr), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!tr || !input_dev) {
++ err = -ENOMEM;
++ goto fail1;
++ }
++
++ tr->serio = serio;
++ tr->dev = input_dev;
++ snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
++
++ input_dev->private = tr;
++ input_dev->name = "Touchright Serial TouchScreen";
++ input_dev->phys = tr->phys;
++ input_dev->id.bustype = BUS_RS232;
++ input_dev->id.vendor = SERIO_TOUCHRIGHT;
++ input_dev->id.product = 0;
++ input_dev->id.version = 0x0100;
++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
++ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
++ input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
++ input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0);
++
++ serio_set_drvdata(serio, tr);
++
++ err = serio_open(serio, drv);
++ if (err)
++ goto fail2;
++
++ err = input_register_device(tr->dev);
++ if (err)
++ goto fail3;
++
++ return 0;
++
++ fail3: serio_close(serio);
++ fail2: serio_set_drvdata(serio, NULL);
++ fail1: input_free_device(input_dev);
++ kfree(tr);
++ return err;
++}
++
++/*
++ * The serio driver structure.
++ */
++
++static struct serio_device_id tr_serio_ids[] = {
++ {
++ .type = SERIO_RS232,
++ .proto = SERIO_TOUCHRIGHT,
++ .id = SERIO_ANY,
++ .extra = SERIO_ANY,
++ },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(serio, tr_serio_ids);
++
++static struct serio_driver tr_drv = {
++ .driver = {
++ .name = "touchright",
++ },
++ .description = DRIVER_DESC,
++ .id_table = tr_serio_ids,
++ .interrupt = tr_interrupt,
++ .connect = tr_connect,
++ .disconnect = tr_disconnect,
++};
++
++/*
++ * The functions for inserting/removing us as a module.
++ */
++
++static int __init tr_init(void)
++{
++ serio_register_driver(&tr_drv);
++ return 0;
++}
++
++static void __exit tr_exit(void)
++{
++ serio_unregister_driver(&tr_drv);
++}
++
++module_init(tr_init);
++module_exit(tr_exit);
+diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
+new file mode 100644
+index 0000000..9911820
+--- /dev/null
++++ b/drivers/input/touchscreen/touchwin.c
+@@ -0,0 +1,202 @@
++/*
++ * Touchwindow serial touchscreen driver
++ *
++ * Copyright (c) 2006 Rick Koch <n1gp at hotmail.com>
++ *
++ * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
++ * Copyright (c) 2004 Vojtech Pavlik
++ * and Dan Streetman <ddstreet at ieee.org>
++ */
++
++/*
++ * 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.
++ */
++
++/*
++ * 2005/02/19 Rick Koch:
++ * The Touchwindow I used is made by Edmark Corp. and
++ * constantly outputs a stream of 0's unless it is touched.
++ * It then outputs 3 bytes: X, Y, and a copy of Y.
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/serio.h>
++#include <linux/init.h>
++
++#define DRIVER_DESC "Touchwindow serial touchscreen driver"
++
++MODULE_AUTHOR("Rick Koch <n1gp at hotmail.com>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++/*
++ * Definitions & global arrays.
++ */
++
++#define TW_LENGTH 3
++
++#define TW_MIN_XC 0
++#define TW_MAX_XC 0xff
++#define TW_MIN_YC 0
++#define TW_MAX_YC 0xff
++
++/*
++ * Per-touchscreen data.
++ */
++
++struct tw {
++ struct input_dev *dev;
++ struct serio *serio;
++ int idx;
++ int touched;
++ unsigned char data[TW_LENGTH];
++ char phys[32];
++};
++
++static irqreturn_t tw_interrupt(struct serio *serio,
++ unsigned char data, unsigned int flags)
++{
++ struct tw *tw = serio_get_drvdata(serio);
++ struct input_dev *dev = tw->dev;
++
++ if (data) { /* touch */
++ tw->touched = 1;
++ tw->data[tw->idx++] = data;
++ /* verify length and that the two Y's are the same */
++ if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
++ input_report_abs(dev, ABS_X, tw->data[0]);
++ input_report_abs(dev, ABS_Y, tw->data[1]);
++ input_report_key(dev, BTN_TOUCH, 1);
++ input_sync(dev);
++ tw->idx = 0;
++ }
++ } else if (tw->touched) { /* untouch */
++ input_report_key(dev, BTN_TOUCH, 0);
++ input_sync(dev);
++ tw->idx = 0;
++ tw->touched = 0;
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * tw_disconnect() is the opposite of tw_connect()
++ */
++
++static void tw_disconnect(struct serio *serio)
++{
++ struct tw *tw = serio_get_drvdata(serio);
++
++ input_get_device(tw->dev);
++ input_unregister_device(tw->dev);
++ serio_close(serio);
++ serio_set_drvdata(serio, NULL);
++ input_put_device(tw->dev);
++ kfree(tw);
++}
++
++/*
++ * tw_connect() is the routine that is called when someone adds a
++ * new serio device that supports the Touchwin protocol and registers it as
++ * an input device.
++ */
++
++static int tw_connect(struct serio *serio, struct serio_driver *drv)
++{
++ struct tw *tw;
++ struct input_dev *input_dev;
++ int err;
++
++ tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!tw || !input_dev) {
++ err = -ENOMEM;
++ goto fail1;
++ }
++
++ tw->serio = serio;
++ tw->dev = input_dev;
++ snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
++
++ input_dev->private = tw;
++ input_dev->name = "Touchwindow Serial TouchScreen";
++ input_dev->phys = tw->phys;
++ input_dev->id.bustype = BUS_RS232;
++ input_dev->id.vendor = SERIO_TOUCHWIN;
++ input_dev->id.product = 0;
++ input_dev->id.version = 0x0100;
++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
++ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
++ input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
++ input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0);
++
++ serio_set_drvdata(serio, tw);
++
++ err = serio_open(serio, drv);
++ if (err)
++ goto fail2;
++
++ err = input_register_device(tw->dev);
++ if (err)
++ goto fail3;
++
++ return 0;
++
++ fail3: serio_close(serio);
++ fail2: serio_set_drvdata(serio, NULL);
++ fail1: input_free_device(input_dev);
++ kfree(tw);
++ return err;
++}
++
++/*
++ * The serio driver structure.
++ */
++
++static struct serio_device_id tw_serio_ids[] = {
++ {
++ .type = SERIO_RS232,
++ .proto = SERIO_TOUCHWIN,
++ .id = SERIO_ANY,
++ .extra = SERIO_ANY,
++ },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(serio, tw_serio_ids);
++
++static struct serio_driver tw_drv = {
++ .driver = {
++ .name = "touchwin",
++ },
++ .description = DRIVER_DESC,
++ .id_table = tw_serio_ids,
++ .interrupt = tw_interrupt,
++ .connect = tw_connect,
++ .disconnect = tw_disconnect,
++};
++
++/*
++ * The functions for inserting/removing us as a module.
++ */
++
++static int __init tw_init(void)
++{
++ serio_register_driver(&tw_drv);
++ return 0;
++}
++
++static void __exit tw_exit(void)
++{
++ serio_unregister_driver(&tw_drv);
++}
++
++module_init(tw_init);
++module_exit(tw_exit);
+diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
+index 00e3929..a730c46 100644
+--- a/drivers/input/tsdev.c
++++ b/drivers/input/tsdev.c
+@@ -135,8 +135,6 @@ struct tsdev_list {
+ #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
+ #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
+
+-static struct input_handler tsdev_handler;
+-
+ static struct tsdev *tsdev_table[TSDEV_MINORS/2];
+
+ static int tsdev_fasync(int fd, struct file *file, int on)
+@@ -263,7 +261,7 @@ static int tsdev_ioctl(struct inode *ino
+ return retval;
+ }
+
+-static struct file_operations tsdev_fops = {
++static const struct file_operations tsdev_fops = {
+ .owner = THIS_MODULE,
+ .open = tsdev_open,
+ .release = tsdev_release,
+@@ -370,7 +368,7 @@ static void tsdev_event(struct input_han
+
+ static struct input_handle *tsdev_connect(struct input_handler *handler,
+ struct input_dev *dev,
+- struct input_device_id *id)
++ const struct input_device_id *id)
+ {
+ struct tsdev *tsdev;
+ struct class_device *cdev;
+@@ -443,7 +441,7 @@ static void tsdev_disconnect(struct inpu
+ tsdev_free(tsdev);
+ }
+
+-static struct input_device_id tsdev_ids[] = {
++static const struct input_device_id tsdev_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+ .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
+@@ -481,9 +479,7 @@ static struct input_handler tsdev_handle
+
+ static int __init tsdev_init(void)
+ {
+- input_register_handler(&tsdev_handler);
+- printk(KERN_INFO "ts: Compaq touchscreen protocol output\n");
+- return 0;
++ return input_register_handler(&tsdev_handler);
+ }
+
+ static void __exit tsdev_exit(void)
+diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
+index bc98d77..3cac237 100644
+--- a/drivers/isdn/act2000/act2000_isa.c
++++ b/drivers/isdn/act2000/act2000_isa.c
+@@ -16,8 +16,6 @@
+ #include "act2000_isa.h"
+ #include "capi.h"
+
+-static act2000_card *irq2card_map[16];
+-
+ /*
+ * Reset Controller, then try to read the Card's signature.
+ + Return:
+@@ -63,16 +61,11 @@ act2000_isa_detect(unsigned short portba
+ }
+
+ static irqreturn_t
+-act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++act2000_isa_interrupt(int irq, void *dev_id)
+ {
+- act2000_card *card = irq2card_map[irq];
++ act2000_card *card = dev_id;
+ u_char istatus;
+
+- if (!card) {
+- printk(KERN_WARNING
+- "act2000: Spurious interrupt!\n");
+- return IRQ_NONE;
+- }
+ istatus = (inb(ISA_PORT_ISR) & 0x07);
+ if (istatus & ISA_ISR_OUT) {
+ /* RX fifo has data */
+@@ -139,17 +132,15 @@ int
+ act2000_isa_config_irq(act2000_card * card, short irq)
+ {
+ if (card->flags & ACT2000_FLAGS_IVALID) {
+- free_irq(card->irq, NULL);
+- irq2card_map[card->irq] = NULL;
++ free_irq(card->irq, card);
+ }
+ card->flags &= ~ACT2000_FLAGS_IVALID;
+ outb(ISA_COR_IRQOFF, ISA_PORT_COR);
+ if (!irq)
+ return 0;
+
+- if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
++ if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
+ card->irq = irq;
+- irq2card_map[card->irq] = card;
+ card->flags |= ACT2000_FLAGS_IVALID;
+ printk(KERN_WARNING
+ "act2000: Could not request irq %d\n",irq);
+@@ -188,10 +179,9 @@ act2000_isa_release(act2000_card * card)
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+- if (card->flags & ACT2000_FLAGS_IVALID) {
+- free_irq(card->irq, NULL);
+- irq2card_map[card->irq] = NULL;
+- }
++ if (card->flags & ACT2000_FLAGS_IVALID)
++ free_irq(card->irq, card);
++
+ card->flags &= ~ACT2000_FLAGS_IVALID;
+ if (card->flags & ACT2000_FLAGS_PVALID)
+ release_region(card->port, ISA_REGION);
+diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
+index 669f763..11844bb 100644
+--- a/drivers/isdn/capi/capi.c
++++ b/drivers/isdn/capi/capi.c
+@@ -1298,7 +1298,7 @@ static int capinc_tty_read_proc(char *pa
+
+ static struct tty_driver *capinc_tty_driver;
+
+-static struct tty_operations capinc_ops = {
++static const struct tty_operations capinc_ops = {
+ .open = capinc_tty_open,
+ .close = capinc_tty_close,
+ .write = capinc_tty_write,
+diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
+index d10c8b8..b6f9476 100644
+--- a/drivers/isdn/capi/capidrv.c
++++ b/drivers/isdn/capi/capidrv.c
+@@ -1907,7 +1907,8 @@ static int if_readstat(u8 __user *buf, i
+ }
+
+ for (p=buf, count=0; count < len; p++, count++) {
+- put_user(*card->q931_read++, p);
++ if (put_user(*card->q931_read++, p))
++ return -EFAULT;
+ if (card->q931_read > card->q931_end)
+ card->q931_read = card->q931_buf;
+ }
+diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
+index 9ea6bd0..2dd1b57 100644
+--- a/drivers/isdn/capi/capifs.c
++++ b/drivers/isdn/capi/capifs.c
+@@ -104,7 +104,6 @@ capifs_fill_super(struct super_block *s,
+ inode->i_ino = 1;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+- inode->i_blksize = 1024;
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+ inode->i_op = &simple_dir_inode_operations;
+@@ -149,7 +148,6 @@ void capifs_new_ncci(unsigned int number
+ if (!inode)
+ return;
+ inode->i_ino = number+2;
+- inode->i_blksize = 1024;
+ inode->i_uid = config.setuid ? config.uid : current->fsuid;
+ inode->i_gid = config.setgid ? config.gid : current->fsgid;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
+index 3845def..0c93732 100644
+--- a/drivers/isdn/gigaset/bas-gigaset.c
++++ b/drivers/isdn/gigaset/bas-gigaset.c
+@@ -192,7 +192,7 @@ static char *get_usb_statmsg(int status)
+ return "bit stuffing error, timeout, or unknown USB error";
+ case -EILSEQ:
+ return "CRC mismatch, timeout, or unknown USB error";
+- case -ETIMEDOUT:
++ case -ETIME:
+ return "timed out";
+ case -EPIPE:
+ return "endpoint stalled";
+@@ -454,7 +454,7 @@ inline static int update_basstate(struct
+ * urb USB request block
+ * urb->context = inbuf structure for controller state
+ */
+-static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
++static void read_ctrl_callback(struct urb *urb)
+ {
+ struct inbuf_t *inbuf = urb->context;
+ struct cardstate *cs = inbuf->cs;
+@@ -596,7 +596,7 @@ static int atread_submit(struct cardstat
+ * urb USB request block
+ * urb->context = controller state structure
+ */
+-static void read_int_callback(struct urb *urb, struct pt_regs *regs)
++static void read_int_callback(struct urb *urb)
+ {
+ struct cardstate *cs = urb->context;
+ struct bas_cardstate *ucs = cs->hw.bas;
+@@ -762,7 +762,7 @@ resubmit:
+ * urb USB request block of completed request
+ * urb->context = bc_state structure
+ */
+-static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
++static void read_iso_callback(struct urb *urb)
+ {
+ struct bc_state *bcs;
+ struct bas_bc_state *ubc;
+@@ -827,7 +827,7 @@ static void read_iso_callback(struct urb
+ * urb USB request block of completed request
+ * urb->context = isow_urbctx_t structure
+ */
+-static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
++static void write_iso_callback(struct urb *urb)
+ {
+ struct isow_urbctx_t *ucx;
+ struct bas_bc_state *ubc;
+@@ -1415,7 +1415,7 @@ static void req_timeout(unsigned long da
+ * urb USB request block of completed request
+ * urb->context = hardware specific controller state structure
+ */
+-static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
++static void write_ctrl_callback(struct urb *urb)
+ {
+ struct bas_cardstate *ucs = urb->context;
+ int rc;
+@@ -1661,7 +1661,7 @@ static void complete_cb(struct cardstate
+ * urb USB request block of completed request
+ * urb->context = controller state structure
+ */
+-static void write_command_callback(struct urb *urb, struct pt_regs *regs)
++static void write_command_callback(struct urb *urb)
+ {
+ struct cardstate *cs = urb->context;
+ struct bas_cardstate *ucs = cs->hw.bas;
+diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
+index aca165d..5800bee 100644
+--- a/drivers/isdn/gigaset/common.c
++++ b/drivers/isdn/gigaset/common.c
+@@ -616,7 +616,7 @@ static struct bc_state *gigaset_initbcs(
+ } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+ skb_reserve(bcs->skb, HW_HDR_LEN);
+ else {
+- dev_warn(cs->dev, "could not allocate skb\n");
++ warn("could not allocate skb\n");
+ bcs->inputstate |= INS_skip_frame;
+ }
+
+diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
+index bd2e426..596f3ae 100644
+--- a/drivers/isdn/gigaset/interface.c
++++ b/drivers/isdn/gigaset/interface.c
+@@ -134,7 +134,7 @@ static int if_tiocmset(struct tty_struc
+ static int if_write(struct tty_struct *tty,
+ const unsigned char *buf, int count);
+
+-static struct tty_operations if_ops = {
++static const struct tty_operations if_ops = {
+ .open = if_open,
+ .close = if_close,
+ .ioctl = if_ioctl,
+diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c
+index 9ae3a7f..9ad840e 100644
+--- a/drivers/isdn/gigaset/proc.c
++++ b/drivers/isdn/gigaset/proc.c
+@@ -83,5 +83,6 @@ void gigaset_init_dev_sysfs(struct cards
+ return;
+
+ gig_dbg(DEBUG_INIT, "setting up sysfs");
+- class_device_create_file(cs->class, &class_device_attr_cidmode);
++ if (class_device_create_file(cs->class, &class_device_attr_cidmode))
++ dev_err(cs->dev, "could not create sysfs attribute\n");
+ }
+diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
+index 6e05d9d..4ffa9eb 100644
+--- a/drivers/isdn/gigaset/usb-gigaset.c
++++ b/drivers/isdn/gigaset/usb-gigaset.c
+@@ -362,7 +362,7 @@ static void gigaset_modem_fill(unsigned
+ *
+ * It is called if the data was received from the device.
+ */
+-static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
++static void gigaset_read_int_callback(struct urb *urb)
+ {
+ struct inbuf_t *inbuf = urb->context;
+ struct cardstate *cs = inbuf->cs;
+@@ -420,7 +420,7 @@ static void gigaset_read_int_callback(st
+
+
+ /* This callback routine is called when data was transmitted to the device. */
+-static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void gigaset_write_bulk_callback(struct urb *urb)
+ {
+ struct cardstate *cs = urb->context;
+ unsigned long flags;
+diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
+index 3b43172..d964f07 100644
+--- a/drivers/isdn/hardware/avm/avmcard.h
++++ b/drivers/isdn/hardware/avm/avmcard.h
+@@ -554,7 +554,7 @@ void b1_register_appl(struct capi_ctr *c
+ void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
+ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+ void b1_parse_version(avmctrl_info *card);
+-irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
++irqreturn_t b1_interrupt(int interrupt, void *devptr);
+
+ int b1ctl_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl);
+@@ -567,7 +567,7 @@ void avmcard_dma_free(avmcard_dmainfo *)
+ int b1pciv4_detect(avmcard *card);
+ int t1pci_detect(avmcard *card);
+ void b1dma_reset(avmcard *card);
+-irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
++irqreturn_t b1dma_interrupt(int interrupt, void *devptr);
+
+ int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
+ void b1dma_reset_ctr(struct capi_ctr *ctrl);
+diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
+index 0c7061d..da27292 100644
+--- a/drivers/isdn/hardware/avm/b1.c
++++ b/drivers/isdn/hardware/avm/b1.c
+@@ -485,7 +485,7 @@ void b1_parse_version(avmctrl_info *cinf
+
+ /* ------------------------------------------------------------- */
+
+-irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
++irqreturn_t b1_interrupt(int interrupt, void *devptr)
+ {
+ avmcard *card = devptr;
+ avmctrl_info *cinfo = &card->ctrlinfo[0];
+diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
+index a4beeb4..ddd47cd 100644
+--- a/drivers/isdn/hardware/avm/b1dma.c
++++ b/drivers/isdn/hardware/avm/b1dma.c
+@@ -628,7 +628,7 @@ static void b1dma_handle_interrupt(avmca
+ spin_unlock(&card->lock);
+ }
+
+-irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
++irqreturn_t b1dma_interrupt(int interrupt, void *devptr)
+ {
+ avmcard *card = devptr;
+
+diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
+index 6c3d5f5..2a3eb38 100644
+--- a/drivers/isdn/hardware/avm/c4.c
++++ b/drivers/isdn/hardware/avm/c4.c
+@@ -713,7 +713,7 @@ static irqreturn_t c4_handle_interrupt(a
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
++static irqreturn_t c4_interrupt(int interrupt, void *devptr)
+ {
+ avmcard *card = devptr;
+
+diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
+index 5a2f854..e47c60b 100644
+--- a/drivers/isdn/hardware/avm/t1isa.c
++++ b/drivers/isdn/hardware/avm/t1isa.c
+@@ -131,7 +131,7 @@ static int t1_detectandinit(unsigned int
+ return 0;
+ }
+
+-static irqreturn_t t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
++static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
+ {
+ avmcard *card = devptr;
+ avmctrl_info *cinfo = &card->ctrlinfo[0];
+diff --git a/drivers/isdn/hardware/eicon/Kconfig b/drivers/isdn/hardware/eicon/Kconfig
+index 51e66bc..01d4afd 100644
+--- a/drivers/isdn/hardware/eicon/Kconfig
++++ b/drivers/isdn/hardware/eicon/Kconfig
+@@ -47,7 +47,7 @@ config ISDN_DIVAS_MAINT
+ tristate "DIVA Maint driver support"
+ depends on ISDN_DIVAS && m
+ help
+- Enable Divas Maintainance driver.
++ Enable Divas Maintenance driver.
+
+ endmenu
+
+diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
+index 8ab8027..ffa2afa 100644
+--- a/drivers/isdn/hardware/eicon/diva.c
++++ b/drivers/isdn/hardware/eicon/diva.c
+@@ -71,8 +71,6 @@ DivaIdiReqFunc(29)
+ DivaIdiReqFunc(30)
+ DivaIdiReqFunc(31)
+
+-struct pt_regs;
+-
+ /*
+ ** LOCALS
+ */
+@@ -515,7 +513,7 @@ diva_xdi_read(void *adapter, void *os_ha
+ }
+
+
+-irqreturn_t diva_os_irq_wrapper(int irq, void *context, struct pt_regs *regs)
++irqreturn_t diva_os_irq_wrapper(int irq, void *context)
+ {
+ diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
+ diva_xdi_clear_interrupts_proc_t clear_int_proc;
+diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
+index b7dadba..dae2e83 100644
+--- a/drivers/isdn/hardware/eicon/divasmain.c
++++ b/drivers/isdn/hardware/eicon/divasmain.c
+@@ -58,8 +58,7 @@ static char *DRIVERLNAME = "divas";
+ static char *DEVNAME = "Divas";
+ char *DRIVERRELEASE_DIVAS = "2.0";
+
+-extern irqreturn_t diva_os_irq_wrapper(int irq, void *context,
+- struct pt_regs *regs);
++extern irqreturn_t diva_os_irq_wrapper(int irq, void *context);
+ extern int create_divas_proc(void);
+ extern void remove_divas_proc(void);
+ extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
+diff --git a/drivers/isdn/hardware/eicon/dsp_defs.h b/drivers/isdn/hardware/eicon/dsp_defs.h
+index b44950e..fec1e38 100644
+--- a/drivers/isdn/hardware/eicon/dsp_defs.h
++++ b/drivers/isdn/hardware/eicon/dsp_defs.h
+@@ -34,9 +34,6 @@
+ *
+ * I/O functions returns -1 on error, 0 on EOF
+ */
+-#define OS_SEEK_SET 0
+-#define OS_SEEK_CUR 1
+-#define OS_SEEK_END 2
+ struct _OsFileHandle_;
+ typedef long ( * OsFileIo) (struct _OsFileHandle_ *handle,
+ void *buffer,
+diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
+index 6dfc941..eb57a98 100644
+--- a/drivers/isdn/hisax/Kconfig
++++ b/drivers/isdn/hisax/Kconfig
+@@ -321,7 +321,7 @@ config HISAX_HFC_PCI
+ help
+ This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
+
+- For more informations see under
++ For more information see under
+ <file:Documentation/isdn/README.hfc-pci>.
+
+ config HISAX_W6692
+diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
+index 8ae08c4..bec5901 100644
+--- a/drivers/isdn/hisax/amd7930_fn.c
++++ b/drivers/isdn/hisax/amd7930_fn.c
+@@ -733,7 +733,7 @@ dbusy_timer_handler(struct IsdnCardState
+ wByteAMD(cs, 0x21, 0x82);
+ wByteAMD(cs, 0x21, 0x02);
+ spin_unlock_irqrestore(&cs->lock, flags);
+- cs->irq_func(cs->irq, cs, NULL);
++ cs->irq_func(cs->irq, cs);
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
+diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h
+index e039c3a..1f4d80c 100644
+--- a/drivers/isdn/hisax/amd7930_fn.h
++++ b/drivers/isdn/hisax/amd7930_fn.h
+@@ -1,4 +1,4 @@
+-/* 2001/10/02
++/* drivers/isdn/hisax/amd7930_fn.h
+ *
+ * gerdes_amd7930.h Header-file included by
+ * gerdes_amd7930.c
+diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
+index 93ff941..61e69e9 100644
+--- a/drivers/isdn/hisax/asuscom.c
++++ b/drivers/isdn/hisax/asuscom.c
+@@ -156,7 +156,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++asuscom_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+@@ -194,7 +194,7 @@ asuscom_interrupt(int intno, void *dev_i
+ }
+
+ static irqreturn_t
+-asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
++asuscom_interrupt_ipac(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char ista, val, icnt = 5;
+diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
+index 729e906..d9028e9 100644
+--- a/drivers/isdn/hisax/avm_a1.c
++++ b/drivers/isdn/hisax/avm_a1.c
+@@ -101,7 +101,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++avm_a1_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval;
+diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
+index 574e252..c87fa3f 100644
+--- a/drivers/isdn/hisax/avm_a1p.c
++++ b/drivers/isdn/hisax/avm_a1p.c
+@@ -140,7 +140,7 @@ WriteHSCXfifo(struct IsdnCardState *cs,
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++avm_a1p_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval;
+diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
+index 369afd3..b04a178 100644
+--- a/drivers/isdn/hisax/avm_pci.c
++++ b/drivers/isdn/hisax/avm_pci.c
+@@ -651,7 +651,7 @@ inithdlc(struct IsdnCardState *cs)
+ }
+
+ static irqreturn_t
+-avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++avm_pcipnp_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_long flags;
+diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
+index 87a6301..871310d 100644
+--- a/drivers/isdn/hisax/bkm_a4t.c
++++ b/drivers/isdn/hisax/bkm_a4t.c
+@@ -125,7 +125,7 @@ WriteJADE(struct IsdnCardState *cs, int
+ #include "jade_irq.c"
+
+ static irqreturn_t
+-bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++bkm_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val = 0;
+diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
+index dae090a..3403106 100644
+--- a/drivers/isdn/hisax/bkm_a8.c
++++ b/drivers/isdn/hisax/bkm_a8.c
+@@ -140,7 +140,7 @@ set_ipac_active(struct IsdnCardState *cs
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
++bkm_interrupt_ipac(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char ista, val, icnt = 5;
+diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
+index e103503..785b085 100644
+--- a/drivers/isdn/hisax/config.c
++++ b/drivers/isdn/hisax/config.c
+@@ -631,7 +631,8 @@ static int HiSax_readstatus(u_char __use
+ count = cs->status_end - cs->status_read + 1;
+ if (count >= len)
+ count = len;
+- copy_to_user(p, cs->status_read, count);
++ if (copy_to_user(p, cs->status_read, count))
++ return -EFAULT;
+ cs->status_read += count;
+ if (cs->status_read > cs->status_end)
+ cs->status_read = cs->status_buf;
+@@ -642,7 +643,8 @@ static int HiSax_readstatus(u_char __use
+ cnt = HISAX_STATUS_BUFSIZE;
+ else
+ cnt = count;
+- copy_to_user(p, cs->status_read, cnt);
++ if (copy_to_user(p, cs->status_read, cnt))
++ return -EFAULT;
+ p += cnt;
+ cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
+ count -= cnt;
+@@ -1721,11 +1723,11 @@ static void hisax_b_l1l2(struct hisax_if
+ hisax_b_sched_event(bcs, B_RCVBUFREADY);
+ break;
+ case PH_DATA | CONFIRM:
+- bcs->tx_cnt -= (int) arg;
++ bcs->tx_cnt -= (long)arg;
+ if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag)) {
+ u_long flags;
+ spin_lock_irqsave(&bcs->aclock, flags);
+- bcs->ackcnt += (int) arg;
++ bcs->ackcnt += (long)arg;
+ spin_unlock_irqrestore(&bcs->aclock, flags);
+ schedule_event(bcs, B_ACKPENDING);
+ }
+@@ -1789,7 +1791,7 @@ static void hisax_b_l2l1(struct PStack *
+
+ switch (pr) {
+ case PH_ACTIVATE | REQUEST:
+- B_L2L1(b_if, pr, (void *) st->l1.mode);
++ B_L2L1(b_if, pr, (void *)(unsigned long)st->l1.mode);
+ break;
+ case PH_DATA | REQUEST:
+ case PH_PULL | INDICATION:
+diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
+index e294fa3..3dacfff 100644
+--- a/drivers/isdn/hisax/diva.c
++++ b/drivers/isdn/hisax/diva.c
+@@ -289,7 +289,7 @@ MemWriteHSCX_IPACX(struct IsdnCardState
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++diva_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval;
+@@ -319,7 +319,7 @@ diva_interrupt(int intno, void *dev_id,
+ }
+
+ static irqreturn_t
+-diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs)
++diva_irq_ipac_isa(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char ista,val;
+@@ -630,7 +630,7 @@ Memhscx_int_main(struct IsdnCardState *c
+ }
+
+ static irqreturn_t
+-diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs)
++diva_irq_ipac_pci(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char ista,val;
+@@ -685,7 +685,7 @@ Start_IPACPCI:
+ }
+
+ static irqreturn_t
+-diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
++diva_irq_ipacx_pci(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+@@ -716,8 +716,10 @@ release_io_diva(struct IsdnCardState *cs
+
+ *cfg = 0; /* disable INT0/1 */
+ *cfg = 2; /* reset pending INT0 */
+- iounmap((void *)cs->hw.diva.cfg_reg);
+- iounmap((void *)cs->hw.diva.pci_cfg);
++ if (cs->hw.diva.cfg_reg)
++ iounmap((void *)cs->hw.diva.cfg_reg);
++ if (cs->hw.diva.pci_cfg)
++ iounmap((void *)cs->hw.diva.pci_cfg);
+ return;
+ } else if (cs->subtyp != DIVA_IPAC_ISA) {
+ del_timer(&cs->hw.diva.tl);
+@@ -734,6 +736,23 @@ release_io_diva(struct IsdnCardState *cs
+ }
+
+ static void
++iounmap_diva(struct IsdnCardState *cs)
++{
++ if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) {
++ if (cs->hw.diva.cfg_reg) {
++ iounmap((void *)cs->hw.diva.cfg_reg);
++ cs->hw.diva.cfg_reg = 0;
++ }
++ if (cs->hw.diva.pci_cfg) {
++ iounmap((void *)cs->hw.diva.pci_cfg);
++ cs->hw.diva.pci_cfg = 0;
++ }
++ }
++
++ return;
++}
++
++static void
+ reset_diva(struct IsdnCardState *cs)
+ {
+ if (cs->subtyp == DIVA_IPAC_ISA) {
+@@ -1069,11 +1088,13 @@ setup_diva(struct IsdnCard *card)
+
+ if (!cs->irq) {
+ printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
++ iounmap_diva(cs);
+ return(0);
+ }
+
+ if (!cs->hw.diva.cfg_reg) {
+ printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
++ iounmap_diva(cs);
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+@@ -1123,6 +1144,7 @@ ready:
+ CardType[card->typ],
+ cs->hw.diva.cfg_reg,
+ cs->hw.diva.cfg_reg + bytecnt);
++ iounmap_diva(cs);
+ return (0);
+ }
+ }
+diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
+index 3b3e318..fab3e4e 100644
+--- a/drivers/isdn/hisax/elsa.c
++++ b/drivers/isdn/hisax/elsa.c
+@@ -282,7 +282,7 @@ TimerRun(struct IsdnCardState *cs)
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++elsa_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_long flags;
+@@ -361,7 +361,7 @@ elsa_interrupt(int intno, void *dev_id,
+ }
+
+ static irqreturn_t
+-elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
++elsa_interrupt_ipac(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_long flags;
+diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
+index 76c7d29..b45de9d 100644
+--- a/drivers/isdn/hisax/enternow_pci.c
++++ b/drivers/isdn/hisax/enternow_pci.c
+@@ -240,7 +240,7 @@ enpci_card_msg(struct IsdnCardState *cs,
+ }
+
+ static irqreturn_t
+-enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++enpci_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ unsigned char s0val, s1val, ir;
+diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
+index fe29372..3efa719 100644
+--- a/drivers/isdn/hisax/gazel.c
++++ b/drivers/isdn/hisax/gazel.c
+@@ -243,7 +243,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++gazel_interrupt(int intno, void *dev_id)
+ {
+ #define MAXCOUNT 5
+ struct IsdnCardState *cs = dev_id;
+@@ -274,7 +274,7 @@ gazel_interrupt(int intno, void *dev_id,
+
+
+ static irqreturn_t
+-gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
++gazel_interrupt_ipac(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char ista, val;
+diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
+index 3a5ca8a..d852c9d 100644
+--- a/drivers/isdn/hisax/hfc4s8s_l1.c
++++ b/drivers/isdn/hisax/hfc4s8s_l1.c
+@@ -424,7 +424,7 @@ bch_l2l1(struct hisax_if *ifc, int pr, v
+ struct hfc4s8s_btype *bch = ifc->priv;
+ struct hfc4s8s_l1 *l1 = bch->l1p;
+ struct sk_buff *skb = (struct sk_buff *) arg;
+- int mode = (int) arg;
++ long mode = (long) arg;
+ u_long flags;
+
+ switch (pr) {
+@@ -914,7 +914,7 @@ tx_d_frame(struct hfc4s8s_l1 *l1p)
+ struct sk_buff *skb;
+ u_char f1, f2;
+ u_char *cp;
+- int cnt;
++ long cnt;
+
+ if (l1p->l1_state != 7)
+ return;
+@@ -980,7 +980,8 @@ tx_b_frame(struct hfc4s8s_btype *bch)
+ struct sk_buff *skb;
+ struct hfc4s8s_l1 *l1 = bch->l1p;
+ u_char *cp;
+- int cnt, max, hdlc_num, ack_len = 0;
++ int cnt, max, hdlc_num;
++ long ack_len = 0;
+
+ if (!l1->enabled || (bch->mode == L1_MODE_NULL))
+ return;
+@@ -1267,7 +1268,7 @@ hfc4s8s_bh(hfc4s8s_hw * hw)
+ /* interrupt handler */
+ /*********************/
+ static irqreturn_t
+-hfc4s8s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++hfc4s8s_interrupt(int intno, void *dev_id)
+ {
+ hfc4s8s_hw *hw = dev_id;
+ u_char b, ovr;
+diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
+index 1df60ca..93f60b5 100644
+--- a/drivers/isdn/hisax/hfc_pci.c
++++ b/drivers/isdn/hisax/hfc_pci.c
+@@ -931,7 +931,7 @@ receive_emsg(struct IsdnCardState *cs)
+ /* Interrupt handler */
+ /*********************/
+ static irqreturn_t
+-hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++hfcpci_interrupt(int intno, void *dev_id)
+ {
+ u_long flags;
+ struct IsdnCardState *cs = dev_id;
+diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
+index f27c160..954d153 100644
+--- a/drivers/isdn/hisax/hfc_sx.c
++++ b/drivers/isdn/hisax/hfc_sx.c
+@@ -691,7 +691,7 @@ receive_emsg(struct IsdnCardState *cs)
+ /* Interrupt handler */
+ /*********************/
+ static irqreturn_t
+-hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++hfcsx_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char exval;
+@@ -970,7 +970,7 @@ HFCSX_l1hw(struct PStack *st, int pr, vo
+ break;
+ case (HW_TESTLOOP | REQUEST):
+ spin_lock_irqsave(&cs->lock, flags);
+- switch ((int) arg) {
++ switch ((long) arg) {
+ case (1):
+ Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */
+ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */
+@@ -986,7 +986,7 @@ HFCSX_l1hw(struct PStack *st, int pr, vo
+ default:
+ spin_unlock_irqrestore(&cs->lock, flags);
+ if (cs->debug & L1_DEB_WARN)
+- debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
++ debugl1(cs, "hfcsx_l1hw loop invalid %4lx", arg);
+ return;
+ }
+ cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
+diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
+index b5e571a..7105b04 100644
+--- a/drivers/isdn/hisax/hfc_usb.c
++++ b/drivers/isdn/hisax/hfc_usb.c
+@@ -276,7 +276,7 @@ control_action_handler(hfcusb_data * hfc
+ /* control completion routine handling background control cmds */
+ /***************************************************************/
+ static void
+-ctrl_complete(struct urb *urb, struct pt_regs *regs)
++ctrl_complete(struct urb *urb)
+ {
+ hfcusb_data *hfc = (hfcusb_data *) urb->context;
+ ctrl_buft *buf;
+@@ -603,7 +603,7 @@ static int iso_packets[8] =
+ /* transmit completion routine for all ISO tx fifos */
+ /*****************************************************/
+ static void
+-tx_iso_complete(struct urb *urb, struct pt_regs *regs)
++tx_iso_complete(struct urb *urb)
+ {
+ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
+ usb_fifo *fifo = context_iso_urb->owner_fifo;
+@@ -696,7 +696,7 @@ tx_iso_complete(struct urb *urb, struct
+ fifo->delete_flg = TRUE;
+ fifo->hif->l1l2(fifo->hif,
+ PH_DATA | CONFIRM,
+- (void *) fifo->skbuff->
++ (void *) (unsigned long) fifo->skbuff->
+ truesize);
+ if (fifo->skbuff && fifo->delete_flg) {
+ dev_kfree_skb_any(fifo->skbuff);
+@@ -726,7 +726,7 @@ tx_iso_complete(struct urb *urb, struct
+ /* receive completion routine for all ISO tx fifos */
+ /*****************************************************/
+ static void
+-rx_iso_complete(struct urb *urb, struct pt_regs *regs)
++rx_iso_complete(struct urb *urb)
+ {
+ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
+ usb_fifo *fifo = context_iso_urb->owner_fifo;
+@@ -919,7 +919,7 @@ collect_rx_frame(usb_fifo * fifo, __u8 *
+ /* receive completion routine for all rx fifos */
+ /***********************************************/
+ static void
+-rx_complete(struct urb *urb, struct pt_regs *regs)
++rx_complete(struct urb *urb)
+ {
+ int len;
+ int status;
+@@ -1144,7 +1144,7 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_i
+ set_hfcmode(hfc,
+ (fifo->fifonum ==
+ HFCUSB_B1_TX) ? 0 : 1,
+- (int) arg);
++ (long) arg);
+ fifo->hif->l1l2(fifo->hif,
+ PH_ACTIVATE | INDICATION,
+ NULL);
+diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
+index ec52c1a..6349367 100644
+--- a/drivers/isdn/hisax/hfc_usb.h
++++ b/drivers/isdn/hisax/hfc_usb.h
+@@ -137,11 +137,11 @@ static struct hfcusb_symbolic_list urb_e
+ {-ENXIO, "URB already queued"},
+ {-EFBIG, "Too much ISO frames requested"},
+ {-ENOSR, "Buffer error (overrun)"},
+- {-EPIPE, "Specified endpoint is stalled (device not responding)"},
++ {-EPIPE, "Specified endpoint is stalled"},
+ {-EOVERFLOW, "Babble (bad cable?)"},
+ {-EPROTO, "Bit-stuff error (bad cable?)"},
+- {-EILSEQ, "CRC/Timeout"},
+- {-ETIMEDOUT, "NAK (device does not respond)"},
++ {-EILSEQ, "CRC or missing token"},
++ {-ETIME, "Device did not respond"},
+ {-ESHUTDOWN, "Device unplugged"},
+ {-1, NULL}
+ };
+diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
+index 4e7f472..57670dc 100644
+--- a/drivers/isdn/hisax/hfcscard.c
++++ b/drivers/isdn/hisax/hfcscard.c
+@@ -21,7 +21,7 @@ extern const char *CardType[];
+ static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
+
+ static irqreturn_t
+-hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++hfcs_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat;
+diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
+index 75920aa..159c589 100644
+--- a/drivers/isdn/hisax/hisax.h
++++ b/drivers/isdn/hisax/hisax.h
+@@ -941,7 +941,7 @@ struct IsdnCardState {
+ int (*cardmsg) (struct IsdnCardState *, int, void *);
+ void (*setstack_d) (struct PStack *, struct IsdnCardState *);
+ void (*DC_Close) (struct IsdnCardState *);
+- int (*irq_func) (int, void *, struct pt_regs *);
++ int (*irq_func) (int, void *);
+ int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
+ struct Channel channel[2+MAX_WAITING_CALLS];
+ struct BCState bcs[2+MAX_WAITING_CALLS];
+@@ -1316,7 +1316,18 @@ void dlogframe(struct IsdnCardState *cs,
+ void iecpy(u_char * dest, u_char * iestart, int ieoffset);
+ #endif /* __KERNEL__ */
+
+-#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
++/*
++ * Busywait delay for `jiffs' jiffies
++ */
++#define HZDELAY(jiffs) do { \
++ int tout = jiffs; \
++ \
++ while (tout--) { \
++ int loops = USEC_PER_SEC / HZ; \
++ while (loops--) \
++ udelay(1); \
++ } \
++ } while (0)
+
+ int ll_run(struct IsdnCardState *cs, int addfeatures);
+ int CallcNew(void);
+diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
+index 1d7cf3b..f6db55a 100644
+--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
++++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
+@@ -546,7 +546,7 @@ static inline void hdlc_xpr_irq(struct f
+ }
+ bcs->tx_cnt = 0;
+ bcs->tx_skb = NULL;
+- B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
++ B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long)skb->truesize);
+ dev_kfree_skb_irq(skb);
+ }
+
+@@ -635,7 +635,7 @@ static void fritz_b_l2l1(struct hisax_if
+ hdlc_fill_fifo(bcs);
+ break;
+ case PH_ACTIVATE | REQUEST:
+- mode = (int) arg;
++ mode = (long) arg;
+ DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
+ modehdlc(bcs, mode);
+ B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
+@@ -651,7 +651,7 @@ static void fritz_b_l2l1(struct hisax_if
+ // ----------------------------------------------------------------------
+
+ static irqreturn_t
+-fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
++fcpci2_irq(int intno, void *dev)
+ {
+ struct fritz_adapter *adapter = dev;
+ unsigned char val;
+@@ -671,7 +671,7 @@ fcpci2_irq(int intno, void *dev, struct
+ }
+
+ static irqreturn_t
+-fcpci_irq(int intno, void *dev, struct pt_regs *regs)
++fcpci_irq(int intno, void *dev)
+ {
+ struct fritz_adapter *adapter = dev;
+ unsigned char sval;
+@@ -998,18 +998,15 @@ static int __init hisax_fcpcipnp_init(vo
+
+ retval = pci_register_driver(&fcpci_driver);
+ if (retval)
+- goto out;
++ return retval;
+ #ifdef __ISAPNP__
+ retval = pnp_register_driver(&fcpnp_driver);
+- if (retval < 0)
+- goto out_unregister_pci;
++ if (retval < 0) {
++ pci_unregister_driver(&fcpci_driver);
++ return retval;
++ }
+ #endif
+ return 0;
+-
+- out_unregister_pci:
+- pci_unregister_driver(&fcpci_driver);
+- out:
+- return retval;
+ }
+
+ static void __exit hisax_fcpcipnp_exit(void)
+diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
+index 2cf7b66..da70692 100644
+--- a/drivers/isdn/hisax/icc.c
++++ b/drivers/isdn/hisax/icc.c
+@@ -608,7 +608,7 @@ dbusy_timer_handler(struct IsdnCardState
+ debugl1(cs, "D-Channel Busy no skb");
+ }
+ cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
+- cs->irq_func(cs->irq, cs, NULL);
++ cs->irq_func(cs->irq, cs);
+ }
+ }
+ }
+diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
+index 565b789..282f349 100644
+--- a/drivers/isdn/hisax/isac.c
++++ b/drivers/isdn/hisax/isac.c
+@@ -609,7 +609,7 @@ dbusy_timer_handler(struct IsdnCardState
+ debugl1(cs, "D-Channel Busy no skb");
+ }
+ cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
+- cs->irq_func(cs->irq, cs, NULL);
++ cs->irq_func(cs->irq, cs);
+ }
+ }
+ }
+diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
+index 715a1a8..55de069 100644
+--- a/drivers/isdn/hisax/isurf.c
++++ b/drivers/isdn/hisax/isurf.c
+@@ -83,7 +83,7 @@ WriteISAR(struct IsdnCardState *cs, int
+ }
+
+ static irqreturn_t
+-isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++isurf_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
+index 3971750..252d79d 100644
+--- a/drivers/isdn/hisax/ix1_micro.c
++++ b/drivers/isdn/hisax/ix1_micro.c
+@@ -125,7 +125,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++ix1micro_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
+index 8c82519..a81d175 100644
+--- a/drivers/isdn/hisax/mic.c
++++ b/drivers/isdn/hisax/mic.c
+@@ -120,7 +120,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++mic_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h
+index 1080508..4d89d3e 100644
+--- a/drivers/isdn/hisax/netjet.h
++++ b/drivers/isdn/hisax/netjet.h
+@@ -66,7 +66,7 @@ void read_tiger(struct IsdnCardState *cs
+ void write_tiger(struct IsdnCardState *cs);
+
+ void netjet_fill_dma(struct BCState *bcs);
+-void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
++void netjet_interrupt(int intno, void *dev_id);
+ void inittiger(struct IsdnCardState *cs);
+ void release_io_netjet(struct IsdnCardState *cs);
+
+diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
+index 489022b..e5918c6 100644
+--- a/drivers/isdn/hisax/niccy.c
++++ b/drivers/isdn/hisax/niccy.c
+@@ -13,7 +13,6 @@
+ *
+ */
+
+-
+ #include <linux/init.h>
+ #include "hisax.h"
+ #include "isac.h"
+@@ -45,33 +44,31 @@ static const char *niccy_revision = "$Re
+ #define PCI_IRQ_DISABLE 0xff0000
+ #define PCI_IRQ_ASSERT 0x800000
+
+-static inline u_char
+-readreg(unsigned int ale, unsigned int adr, u_char off)
++static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off)
+ {
+ register u_char ret;
+
+ byteout(ale, off);
+ ret = bytein(adr);
+- return (ret);
++ return ret;
+ }
+
+-static inline void
+-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
++static inline void readfifo(unsigned int ale, unsigned int adr, u_char off,
++ u_char *data, int size)
+ {
+ byteout(ale, off);
+ insb(adr, data, size);
+ }
+
+-
+-static inline void
+-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
++static inline void writereg(unsigned int ale, unsigned int adr, u_char off,
++ u_char data)
+ {
+ byteout(ale, off);
+ byteout(adr, data);
+ }
+
+-static inline void
+-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
++static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
++ u_char *data, int size)
+ {
+ byteout(ale, off);
+ outsb(adr, data, size);
+@@ -79,39 +76,34 @@ writefifo(unsigned int ale, unsigned int
+
+ /* Interface functions */
+
+-static u_char
+-ReadISAC(struct IsdnCardState *cs, u_char offset)
++static u_char ReadISAC(struct IsdnCardState *cs, u_char offset)
+ {
+- return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
++ return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
+ }
+
+-static void
+-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
++static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+ {
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
+ }
+
+-static void
+-ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
++static void ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+ {
+ readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
+ }
+
+-static void
+-WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
++static void WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+ {
+ writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
+ }
+
+-static u_char
+-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
++static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+ {
+- return (readreg(cs->hw.niccy.hscx_ale,
+- cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
++ return readreg(cs->hw.niccy.hscx_ale,
++ cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
+ }
+
+-static void
+-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
++static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
++ u_char value)
+ {
+ writereg(cs->hw.niccy.hscx_ale,
+ cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
+@@ -130,8 +122,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+
+ #include "hscx_irq.c"
+
+-static irqreturn_t
+-niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++static irqreturn_t niccy_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+@@ -141,21 +132,23 @@ niccy_interrupt(int intno, void *dev_id,
+ if (cs->subtyp == NICCY_PCI) {
+ int ival;
+ ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+- if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
++ if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return IRQ_NONE;
+ }
+ outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+ }
+- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+- Start_HSCX:
++ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
++ HSCX_ISTA + 0x40);
++Start_HSCX:
+ if (val)
+ hscx_int_main(cs, val);
+ val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+- Start_ISAC:
++Start_ISAC:
+ if (val)
+ isac_interrupt(cs, val);
+- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
++ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
++ HSCX_ISTA + 0x40);
+ if (val) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+@@ -168,21 +161,21 @@ niccy_interrupt(int intno, void *dev_id,
+ goto Start_ISAC;
+ }
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
+- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
++ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,
++ 0xFF);
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
+- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
++ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,0);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+-static void
+-release_io_niccy(struct IsdnCardState *cs)
++static void release_io_niccy(struct IsdnCardState *cs)
+ {
+ if (cs->subtyp == NICCY_PCI) {
+ int val;
+-
++
+ val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+ val &= PCI_IRQ_DISABLE;
+ outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+@@ -194,8 +187,7 @@ release_io_niccy(struct IsdnCardState *c
+ }
+ }
+
+-static void
+-niccy_reset(struct IsdnCardState *cs)
++static void niccy_reset(struct IsdnCardState *cs)
+ {
+ if (cs->subtyp == NICCY_PCI) {
+ int val;
+@@ -207,29 +199,28 @@ niccy_reset(struct IsdnCardState *cs)
+ inithscxisac(cs, 3);
+ }
+
+-static int
+-niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
++static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+ {
+ u_long flags;
+
+ switch (mt) {
+- case CARD_RESET:
+- spin_lock_irqsave(&cs->lock, flags);
+- niccy_reset(cs);
+- spin_unlock_irqrestore(&cs->lock, flags);
+- return(0);
+- case CARD_RELEASE:
+- release_io_niccy(cs);
+- return(0);
+- case CARD_INIT:
+- spin_lock_irqsave(&cs->lock, flags);
+- niccy_reset(cs);
+- spin_unlock_irqrestore(&cs->lock, flags);
+- return(0);
+- case CARD_TEST:
+- return(0);
++ case CARD_RESET:
++ spin_lock_irqsave(&cs->lock, flags);
++ niccy_reset(cs);
++ spin_unlock_irqrestore(&cs->lock, flags);
++ return 0;
++ case CARD_RELEASE:
++ release_io_niccy(cs);
++ return 0;
++ case CARD_INIT:
++ spin_lock_irqsave(&cs->lock, flags);
++ niccy_reset(cs);
++ spin_unlock_irqrestore(&cs->lock, flags);
++ return 0;
++ case CARD_TEST:
++ return 0;
+ }
+- return(0);
++ return 0;
+ }
+
+ static struct pci_dev *niccy_dev __devinitdata = NULL;
+@@ -237,8 +228,7 @@ static struct pci_dev *niccy_dev __devin
+ static struct pnp_card *pnp_c __devinitdata = NULL;
+ #endif
+
+-int __devinit
+-setup_niccy(struct IsdnCard *card)
++int __devinit setup_niccy(struct IsdnCard *card)
+ {
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+@@ -246,40 +236,44 @@ setup_niccy(struct IsdnCard *card)
+ strcpy(tmp, niccy_revision);
+ printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NICCY)
+- return (0);
++ return 0;
+ #ifdef __ISAPNP__
+ if (!card->para[1] && isapnp_present()) {
+ struct pnp_dev *pnp_d = NULL;
+ int err;
+
+- if ((pnp_c = pnp_find_card(
+- ISAPNP_VENDOR('S', 'D', 'A'),
+- ISAPNP_FUNCTION(0x0150), pnp_c))) {
+- if (!(pnp_d = pnp_find_dev(pnp_c,
+- ISAPNP_VENDOR('S', 'D', 'A'),
+- ISAPNP_FUNCTION(0x0150), pnp_d))) {
+- printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
+- return (0);
++ pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'),
++ ISAPNP_FUNCTION(0x0150), pnp_c);
++ if (pnp_c) {
++ pnp_d = pnp_find_dev(pnp_c,
++ ISAPNP_VENDOR('S', 'D', 'A'),
++ ISAPNP_FUNCTION(0x0150), pnp_d);
++ if (!pnp_d) {
++ printk(KERN_ERR "NiccyPnP: PnP error card "
++ "found, no device\n");
++ return 0;
+ }
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+- if (err<0) {
+- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+- __FUNCTION__, err);
+- return(0);
++ if (err < 0) {
++ printk(KERN_WARNING "%s: pnp_activate_dev "
++ "ret(%d)\n", __FUNCTION__, err);
++ return 0;
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[2] = pnp_port_start(pnp_d, 1);
+ card->para[0] = pnp_irq(pnp_d, 0);
+- if (!card->para[0] || !card->para[1] || !card->para[2]) {
+- printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
+- card->para[0], card->para[1], card->para[2]);
++ if (!card->para[0] || !card->para[1] ||
++ !card->para[2]) {
++ printk(KERN_ERR "NiccyPnP:some resources are "
++ "missing %ld/%lx/%lx\n",
++ card->para[0], card->para[1],
++ card->para[2]);
+ pnp_disable_dev(pnp_d);
+- return(0);
++ return 0;
+ }
+- } else {
++ } else
+ printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
+- }
+ }
+ #endif
+ if (card->para[1]) {
+@@ -291,50 +285,51 @@ setup_niccy(struct IsdnCard *card)
+ cs->subtyp = NICCY_PNP;
+ cs->irq = card->para[0];
+ if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
+- printk(KERN_WARNING
+- "HiSax: %s data port %x-%x already in use\n",
+- CardType[card->typ],
+- cs->hw.niccy.isac,
+- cs->hw.niccy.isac + 1);
+- return (0);
++ printk(KERN_WARNING "HiSax: %s data port %x-%x "
++ "already in use\n", CardType[card->typ],
++ cs->hw.niccy.isac, cs->hw.niccy.isac + 1);
++ return 0;
+ }
+ if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
+- printk(KERN_WARNING
+- "HiSax: %s address port %x-%x already in use\n",
+- CardType[card->typ],
++ printk(KERN_WARNING "HiSax: %s address port %x-%x "
++ "already in use\n", CardType[card->typ],
+ cs->hw.niccy.isac_ale,
+ cs->hw.niccy.isac_ale + 1);
+ release_region(cs->hw.niccy.isac, 2);
+- return (0);
++ return 0;
+ }
+ } else {
+ #ifdef CONFIG_PCI
+ u_int pci_ioaddr;
+ cs->subtyp = 0;
+ if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
+- PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
++ PCI_DEVICE_ID_SATSAGEM_NICCY,
++ niccy_dev))) {
+ if (pci_enable_device(niccy_dev))
+- return(0);
++ return 0;
+ /* get IRQ */
+ if (!niccy_dev->irq) {
+- printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
+- return(0);
++ printk(KERN_WARNING
++ "Niccy: No IRQ for PCI card found\n");
++ return 0;
+ }
+ cs->irq = niccy_dev->irq;
+ cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
+ if (!cs->hw.niccy.cfg_reg) {
+- printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
+- return(0);
++ printk(KERN_WARNING
++ "Niccy: No IO-Adr for PCI cfg found\n");
++ return 0;
+ }
+ pci_ioaddr = pci_resource_start(niccy_dev, 1);
+ if (!pci_ioaddr) {
+- printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
+- return(0);
++ printk(KERN_WARNING
++ "Niccy: No IO-Adr for PCI card found\n");
++ return 0;
+ }
+ cs->subtyp = NICCY_PCI;
+ } else {
+ printk(KERN_WARNING "Niccy: No PCI card found\n");
+- return(0);
++ return 0;
+ }
+ cs->irq_flags |= IRQF_SHARED;
+ cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
+@@ -343,29 +338,28 @@ setup_niccy(struct IsdnCard *card)
+ cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
+ if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
+ printk(KERN_WARNING
+- "HiSax: %s data port %x-%x already in use\n",
+- CardType[card->typ],
+- cs->hw.niccy.isac,
+- cs->hw.niccy.isac + 4);
+- return (0);
++ "HiSax: %s data port %x-%x already in use\n",
++ CardType[card->typ],
++ cs->hw.niccy.isac, cs->hw.niccy.isac + 4);
++ return 0;
+ }
+ if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
+ printk(KERN_WARNING
+ "HiSax: %s pci port %x-%x already in use\n",
+- CardType[card->typ],
+- cs->hw.niccy.cfg_reg,
+- cs->hw.niccy.cfg_reg + 0x40);
++ CardType[card->typ],
++ cs->hw.niccy.cfg_reg,
++ cs->hw.niccy.cfg_reg + 0x40);
+ release_region(cs->hw.niccy.isac, 4);
+- return (0);
++ return 0;
+ }
+ #else
+ printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
+- return (0);
+-#endif /* CONFIG_PCI */
++ return 0;
++#endif /* CONFIG_PCI */
+ }
+ printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
+- CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
++ CardType[cs->typ], (cs->subtyp == 1) ? "PnP" : "PCI",
+ cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
+ setup_isac(cs);
+ cs->readisac = &ReadISAC;
+@@ -379,10 +373,10 @@ setup_niccy(struct IsdnCard *card)
+ cs->irq_func = &niccy_interrupt;
+ ISACVersion(cs, "Niccy:");
+ if (HscxVersion(cs, "Niccy:")) {
+- printk(KERN_WARNING
+- "Niccy: wrong HSCX versions check IO address\n");
++ printk(KERN_WARNING "Niccy: wrong HSCX versions check IO "
++ "address\n");
+ release_io_niccy(cs);
+- return (0);
++ return 0;
+ }
+- return (1);
++ return 1;
+ }
+diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
+index 80025fd..c09ffb1 100644
+--- a/drivers/isdn/hisax/nj_s.c
++++ b/drivers/isdn/hisax/nj_s.c
+@@ -26,7 +26,7 @@ static void dummywr(struct IsdnCardState
+ }
+
+ static irqreturn_t
+-netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++netjet_s_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, s1val, s0val;
+diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
+index 3749716..8202cf3 100644
+--- a/drivers/isdn/hisax/nj_u.c
++++ b/drivers/isdn/hisax/nj_u.c
+@@ -26,7 +26,7 @@ static void dummywr(struct IsdnCardState
+ }
+
+ static irqreturn_t
+-netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++netjet_u_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval;
+diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
+index e76042d..150ef68 100644
+--- a/drivers/isdn/hisax/s0box.c
++++ b/drivers/isdn/hisax/s0box.c
+@@ -141,7 +141,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++s0box_interrupt(int intno, void *dev_id)
+ {
+ #define MAXCOUNT 5
+ struct IsdnCardState *cs = dev_id;
+diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
+index d943d36..c99b166 100644
+--- a/drivers/isdn/hisax/saphir.c
++++ b/drivers/isdn/hisax/saphir.c
+@@ -117,7 +117,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++saphir_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
+index 8d8e8a2..9522141 100644
+--- a/drivers/isdn/hisax/sedlbauer.c
++++ b/drivers/isdn/hisax/sedlbauer.c
+@@ -260,7 +260,7 @@ WriteISAR(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++sedlbauer_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+@@ -306,7 +306,7 @@ sedlbauer_interrupt(int intno, void *dev
+ }
+
+ static irqreturn_t
+-sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
++sedlbauer_interrupt_ipac(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char ista, val, icnt = 5;
+@@ -353,7 +353,7 @@ Start_IPAC:
+ }
+
+ static irqreturn_t
+-sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
++sedlbauer_interrupt_isar(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
+index a49b694..0220950 100644
+--- a/drivers/isdn/hisax/sportster.c
++++ b/drivers/isdn/hisax/sportster.c
+@@ -99,7 +99,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++sportster_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
+index 22fd5db..75d0f24 100644
+--- a/drivers/isdn/hisax/st5481_b.c
++++ b/drivers/isdn/hisax/st5481_b.c
+@@ -86,7 +86,7 @@ static void usb_b_out(struct st5481_bcs
+ if (!skb->len) {
+ // Frame sent
+ b_out->tx_skb = NULL;
+- B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
++ B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize);
+ dev_kfree_skb_any(skb);
+
+ /* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
+@@ -161,7 +161,7 @@ static void led_blink(struct st5481_adap
+ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
+ }
+
+-static void usb_b_out_complete(struct urb *urb, struct pt_regs *regs)
++static void usb_b_out_complete(struct urb *urb)
+ {
+ struct st5481_bcs *bcs = urb->context;
+ struct st5481_b_out *b_out = &bcs->b_out;
+@@ -350,7 +350,7 @@ void st5481_b_l2l1(struct hisax_if *ifc,
+ {
+ struct st5481_bcs *bcs = ifc->priv;
+ struct sk_buff *skb = arg;
+- int mode;
++ long mode;
+
+ DBG(4, "");
+
+@@ -360,8 +360,8 @@ void st5481_b_l2l1(struct hisax_if *ifc,
+ bcs->b_out.tx_skb = skb;
+ break;
+ case PH_ACTIVATE | REQUEST:
+- mode = (int) arg;
+- DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
++ mode = (long) arg;
++ DBG(4,"B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode);
+ st5481B_mode(bcs, mode);
+ B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
+ break;
+diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
+index 493dc94..1d8c261 100644
+--- a/drivers/isdn/hisax/st5481_d.c
++++ b/drivers/isdn/hisax/st5481_d.c
+@@ -370,11 +370,11 @@ static void fifo_reseted(void *context)
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
+ }
+
+-static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs)
++static void usb_d_out_complete(struct urb *urb)
+ {
+ struct st5481_adapter *adapter = urb->context;
+ struct st5481_d_out *d_out = &adapter->d_out;
+- int buf_nr;
++ long buf_nr;
+
+ DBG(2, "");
+
+@@ -546,7 +546,7 @@ static void dout_reseted(struct FsmInst
+ static void dout_complete(struct FsmInst *fsm, int event, void *arg)
+ {
+ struct st5481_adapter *adapter = fsm->userdata;
+- int buf_nr = (int) arg;
++ long buf_nr = (long) arg;
+
+ usb_d_out(adapter, buf_nr);
+ }
+diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
+index b096b64..ff15951 100644
+--- a/drivers/isdn/hisax/st5481_usb.c
++++ b/drivers/isdn/hisax/st5481_usb.c
+@@ -125,7 +125,7 @@ void st5481_ph_command(struct st5481_ada
+ * Call the user provided completion routine and try
+ * to send the next request.
+ */
+-static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs)
++static void usb_ctrl_complete(struct urb *urb)
+ {
+ struct st5481_adapter *adapter = urb->context;
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+@@ -179,7 +179,7 @@ static void usb_ctrl_complete(struct urb
+ * Decode the register values and schedule a private event.
+ * Called at interrupt.
+ */
+-static void usb_int_complete(struct urb *urb, struct pt_regs *regs)
++static void usb_int_complete(struct urb *urb)
+ {
+ u8 *data = urb->transfer_buffer;
+ u8 irqbyte;
+@@ -483,7 +483,7 @@ void st5481_release_isocpipes(struct urb
+ * called 50 times per second with 20 ISOC descriptors.
+ * Called at interrupt.
+ */
+-static void usb_in_complete(struct urb *urb, struct pt_regs *regs)
++static void usb_in_complete(struct urb *urb)
+ {
+ struct st5481_in *in = urb->context;
+ unsigned char *ptr;
+diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
+index e94dc6f..0909662 100644
+--- a/drivers/isdn/hisax/teleint.c
++++ b/drivers/isdn/hisax/teleint.c
+@@ -157,7 +157,7 @@ WriteHFC(struct IsdnCardState *cs, int d
+ }
+
+ static irqreturn_t
+-TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++TeleInt_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
+index f94af09..4858133 100644
+--- a/drivers/isdn/hisax/teles0.c
++++ b/drivers/isdn/hisax/teles0.c
+@@ -144,7 +144,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++teles0_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
+index 5cb7124..6a5e379 100644
+--- a/drivers/isdn/hisax/teles3.c
++++ b/drivers/isdn/hisax/teles3.c
+@@ -101,7 +101,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++teles3_interrupt(int intno, void *dev_id)
+ {
+ #define MAXCOUNT 5
+ struct IsdnCardState *cs = dev_id;
+diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
+index dca4468..d09f6d0 100644
+--- a/drivers/isdn/hisax/telespci.c
++++ b/drivers/isdn/hisax/telespci.c
+@@ -226,7 +226,7 @@ WriteHSCX(struct IsdnCardState *cs, int
+ #include "hscx_irq.c"
+
+ static irqreturn_t
+-telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++telespci_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char hval, ival;
+diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
+index 0595293..1655341 100644
+--- a/drivers/isdn/hisax/w6692.c
++++ b/drivers/isdn/hisax/w6692.c
+@@ -400,7 +400,7 @@ W6692B_interrupt(struct IsdnCardState *c
+ }
+
+ static irqreturn_t
+-W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++W6692_interrupt(int intno, void *dev_id)
+ {
+ struct IsdnCardState *cs = dev_id;
+ u_char val, exval, v1;
+@@ -715,7 +715,7 @@ dbusy_timer_handler(struct IsdnCardState
+ }
+ cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */
+ spin_unlock_irqrestore(&cs->lock, flags);
+- cs->irq_func(cs->irq, cs, NULL);
++ cs->irq_func(cs->irq, cs);
+ return;
+ }
+ }
+diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
+index 73afebd..82e42a8 100644
+--- a/drivers/isdn/hysdn/boardergo.c
++++ b/drivers/isdn/hysdn/boardergo.c
+@@ -33,7 +33,7 @@
+ /* The cards interrupt handler. Called from system */
+ /***************************************************/
+ static irqreturn_t
+-ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
++ergo_interrupt(int intno, void *dev_id)
+ {
+ hysdn_card *card = dev_id; /* parameter from irq */
+ tErgDpram *dpr;
+@@ -45,11 +45,10 @@ ergo_interrupt(int intno, void *dev_id,
+ if (!card->irq_enabled)
+ return IRQ_NONE; /* other device interrupting or irq switched off */
+
+- save_flags(flags);
+- cli(); /* no further irqs allowed */
++ spin_lock_irqsave(&card->hysdn_lock, flags); /* no further irqs allowed */
+
+ if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
+- restore_flags(flags); /* restore old state */
++ spin_unlock_irqrestore(&card->hysdn_lock, flags); /* restore old state */
+ return IRQ_NONE; /* no interrupt requested by E1 */
+ }
+ /* clear any pending ints on the board */
+@@ -61,7 +60,7 @@ ergo_interrupt(int intno, void *dev_id,
+ /* start kernel task immediately after leaving all interrupts */
+ if (!card->hw_lock)
+ schedule_work(&card->irq_queue);
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ return IRQ_HANDLED;
+ } /* ergo_interrupt */
+
+@@ -83,10 +82,9 @@ ergo_irq_bh(hysdn_card * card)
+
+ dpr = card->dpram; /* point to DPRAM */
+
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+ if (card->hw_lock) {
+- restore_flags(flags); /* hardware currently unavailable */
++ spin_unlock_irqrestore(&card->hysdn_lock, flags); /* hardware currently unavailable */
+ return;
+ }
+ card->hw_lock = 1; /* we now lock the hardware */
+@@ -120,7 +118,7 @@ ergo_irq_bh(hysdn_card * card)
+ card->hw_lock = 0; /* free hardware again */
+ } while (again); /* until nothing more to do */
+
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ } /* ergo_irq_bh */
+
+
+@@ -137,8 +135,7 @@ ergo_stopcard(hysdn_card * card)
+ #ifdef CONFIG_HYSDN_CAPI
+ hycapi_capi_stop(card);
+ #endif /* CONFIG_HYSDN_CAPI */
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+ val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
+ val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
+ byteout(card->iobase + PCI9050_INTR_REG, val);
+@@ -147,7 +144,7 @@ ergo_stopcard(hysdn_card * card)
+ card->state = CARD_STATE_UNUSED;
+ card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
+
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ } /* ergo_stopcard */
+
+ /**************************************************************************/
+@@ -162,12 +159,11 @@ ergo_set_errlog_state(hysdn_card * card,
+ card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
+ return;
+ }
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+
+ if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
+ ((card->err_log_state == ERRLOG_STATE_ON) && on)) {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ return; /* nothing to do */
+ }
+ if (on)
+@@ -175,7 +171,7 @@ ergo_set_errlog_state(hysdn_card * card,
+ else
+ card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
+
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ schedule_work(&card->irq_queue);
+ } /* ergo_set_errlog_state */
+
+@@ -356,8 +352,7 @@ ergo_waitpofready(struct HYSDN_CARD *car
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "ERGO: pof boot success");
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+
+ card->state = CARD_STATE_RUN; /* now card is running */
+ /* enable the cards interrupt */
+@@ -370,7 +365,7 @@ ergo_waitpofready(struct HYSDN_CARD *car
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ if ((hynet_enable & (1 << card->myid))
+ && (i = hysdn_net_create(card)))
+ {
+@@ -408,7 +403,7 @@ ergo_releasehardware(hysdn_card * card)
+ free_irq(card->irq, card); /* release interrupt */
+ release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
+ release_region(card->iobase + PCI9050_USER_IO, 1);
+- vfree(card->dpram);
++ iounmap(card->dpram);
+ card->dpram = NULL; /* release shared mem */
+ } /* ergo_releasehardware */
+
+@@ -448,6 +443,7 @@ ergo_inithardware(hysdn_card * card)
+ card->waitpofready = ergo_waitpofready;
+ card->set_errlog_state = ergo_set_errlog_state;
+ INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card);
++ card->hysdn_lock = SPIN_LOCK_UNLOCKED;
+
+ return (0);
+ } /* ergo_inithardware */
+diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
+index 461e831..729df40 100644
+--- a/drivers/isdn/hysdn/hysdn_defs.h
++++ b/drivers/isdn/hysdn/hysdn_defs.h
+@@ -188,6 +188,8 @@ typedef struct HYSDN_CARD {
+ /* init and deinit stopcard for booting, too */
+ void (*stopcard) (struct HYSDN_CARD *);
+ void (*releasehardware) (struct HYSDN_CARD *);
++
++ spinlock_t hysdn_lock;
+ #ifdef CONFIG_HYSDN_CAPI
+ struct hycapictrl_info {
+ char cardname[32];
+diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
+index c4301e8..fcd4992 100644
+--- a/drivers/isdn/hysdn/hysdn_proclog.c
++++ b/drivers/isdn/hysdn/hysdn_proclog.c
+@@ -116,8 +116,7 @@ put_log_buffer(hysdn_card * card, char *
+ strcpy(ib->log_start, cp); /* set output string */
+ ib->next = NULL;
+ ib->proc_ctrl = pd; /* point to own control structure */
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+ ib->usage_cnt = pd->if_used;
+ if (!pd->log_head)
+ pd->log_head = ib; /* new head */
+@@ -125,7 +124,7 @@ put_log_buffer(hysdn_card * card, char *
+ pd->log_tail->next = ib; /* follows existing messages */
+ pd->log_tail = ib; /* new tail */
+ i = pd->del_lock++; /* get lock state */
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+
+ /* delete old entrys */
+ if (!i)
+@@ -270,14 +269,13 @@ hysdn_log_open(struct inode *ino, struct
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+ /* read access -> log/debug read */
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+ pd->if_used++;
+ if (pd->log_head)
+ filep->private_data = &pd->log_tail->next;
+ else
+ filep->private_data = &pd->log_head;
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+ } else { /* simultaneous read/write access forbidden ! */
+ unlock_kernel();
+ return (-EPERM); /* no permission this time */
+@@ -301,7 +299,7 @@ hysdn_log_close(struct inode *ino, struc
+ hysdn_card *card;
+ int retval = 0;
+ unsigned long flags;
+-
++ spinlock_t hysdn_lock = SPIN_LOCK_UNLOCKED;
+
+ lock_kernel();
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+@@ -311,8 +309,7 @@ hysdn_log_close(struct inode *ino, struc
+ /* read access -> log/debug read, mark one further file as closed */
+
+ pd = NULL;
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&hysdn_lock, flags);
+ inf = *((struct log_data **) filep->private_data); /* get first log entry */
+ if (inf)
+ pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
+@@ -335,7 +332,7 @@ hysdn_log_close(struct inode *ino, struc
+ inf->usage_cnt--; /* decrement usage count for buffers */
+ inf = inf->next;
+ }
+- restore_flags(flags);
++ spin_unlock_irqrestore(&hysdn_lock, flags);
+
+ if (pd)
+ if (pd->if_used <= 0) /* delete buffers if last file closed */
+diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
+index 1c0d54a..1875877 100644
+--- a/drivers/isdn/hysdn/hysdn_sched.c
++++ b/drivers/isdn/hysdn/hysdn_sched.c
+@@ -155,22 +155,17 @@ hysdn_tx_cfgline(hysdn_card *card, unsig
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
+
+- save_flags(flags);
+- cli();
+ while (card->async_busy) {
+- sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg delayed");
+
+ msleep_interruptible(20); /* Timeout 20ms */
+- if (!--cnt) {
+- restore_flags(flags);
++ if (!--cnt)
+ return (-ERR_ASYNC_TIME); /* timed out */
+- }
+- cli();
+ } /* wait for buffer to become free */
+
++ spin_lock_irqsave(&card->hysdn_lock, flags);
+ strcpy(card->async_data, line);
+ card->async_len = strlen(line) + 1;
+ card->async_channel = chan;
+@@ -178,30 +173,23 @@ hysdn_tx_cfgline(hysdn_card *card, unsig
+
+ /* now queue the task */
+ schedule_work(&card->irq_queue);
+- sti();
++ spin_unlock_irqrestore(&card->hysdn_lock, flags);
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data queued");
+
+ cnt++; /* short delay */
+- cli();
+
+ while (card->async_busy) {
+- sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
+
+ msleep_interruptible(20); /* Timeout 20ms */
+- if (!--cnt) {
+- restore_flags(flags);
++ if (!--cnt)
+ return (-ERR_ASYNC_TIME); /* timed out */
+- }
+- cli();
+ } /* wait for buffer to become free again */
+
+- restore_flags(flags);
+-
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data send");
+
+diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
+index a4f7288..3ef567b 100644
+--- a/drivers/isdn/i4l/Kconfig
++++ b/drivers/isdn/i4l/Kconfig
+@@ -5,6 +5,7 @@
+ config ISDN_PPP
+ bool "Support synchronous PPP"
+ depends on INET
++ select SLHC
+ help
+ Over digital connections such as ISDN, there is no need to
+ synchronize sender and recipient's clocks with start and stop bits
+diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
+index c3d79ee..69aee26 100644
+--- a/drivers/isdn/i4l/isdn_common.c
++++ b/drivers/isdn/i4l/isdn_common.c
+@@ -1134,9 +1134,12 @@ isdn_read(struct file *file, char __user
+ if (dev->drv[drvidx]->interface->readstat) {
+ if (count > dev->drv[drvidx]->stavail)
+ count = dev->drv[drvidx]->stavail;
+- len = dev->drv[drvidx]->interface->
+- readstat(buf, count, drvidx,
+- isdn_minor2chan(minor));
++ len = dev->drv[drvidx]->interface->readstat(buf, count,
++ drvidx, isdn_minor2chan(minor));
++ if (len < 0) {
++ retval = len;
++ goto out;
++ }
+ } else {
+ len = 0;
+ }
+diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
+index 43da8ae..1f8d6ae 100644
+--- a/drivers/isdn/i4l/isdn_net.c
++++ b/drivers/isdn/i4l/isdn_net.c
+@@ -1614,8 +1614,8 @@ isdn_net_ciscohdlck_slarp_send_reply(isd
+ struct sk_buff *skb;
+ unsigned char *p;
+ struct in_device *in_dev = NULL;
+- u32 addr = 0; /* local ipv4 address */
+- u32 mask = 0; /* local netmask */
++ __be32 addr = 0; /* local ipv4 address */
++ __be32 mask = 0; /* local netmask */
+
+ if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+ /* take primary(first) address of interface */
+diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
+index 9ab66e8..2b91bb0 100644
+--- a/drivers/isdn/i4l/isdn_tty.c
++++ b/drivers/isdn/i4l/isdn_tty.c
+@@ -1860,7 +1860,7 @@ modem_write_profile(atemu * m)
+ send_sig(SIGIO, dev->profd, 1);
+ }
+
+-static struct tty_operations modem_ops = {
++static const struct tty_operations modem_ops = {
+ .open = isdn_tty_open,
+ .close = isdn_tty_close,
+ .write = isdn_tty_write,
+diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
+index 6649f8b..730bbd0 100644
+--- a/drivers/isdn/icn/icn.c
++++ b/drivers/isdn/icn/icn.c
+@@ -1010,7 +1010,8 @@ icn_readstatus(u_char __user *buf, int l
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (card->msg_buf_read == card->msg_buf_write)
+ return count;
+- put_user(*card->msg_buf_read++, p);
++ if (put_user(*card->msg_buf_read++, p))
++ return -EFAULT;
+ if (card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
+index fabbd46..c3ae2ed 100644
+--- a/drivers/isdn/isdnloop/isdnloop.c
++++ b/drivers/isdn/isdnloop/isdnloop.c
+@@ -100,12 +100,11 @@ isdnloop_pollbchan(unsigned long data)
+ isdnloop_bchan_send(card, 1);
+ if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
+ /* schedule b-channel polling again */
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ card->flags |= ISDNLOOP_FLAGS_RBTIMER;
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ } else
+ card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
+ }
+@@ -281,8 +280,7 @@ isdnloop_putmsg(isdnloop_card * card, un
+ {
+ ulong flags;
+
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+ if (card->msg_buf_write == card->msg_buf_read) {
+ if (++card->msg_buf_read > card->msg_buf_end)
+@@ -290,7 +288,7 @@ isdnloop_putmsg(isdnloop_card * card, un
+ }
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+
+ /*
+@@ -372,21 +370,19 @@ isdnloop_polldchan(unsigned long data)
+ if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
+ /* schedule b-channel polling */
+ card->flags |= ISDNLOOP_FLAGS_RBTIMER;
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ del_timer(&card->rb_timer);
+ card->rb_timer.function = isdnloop_pollbchan;
+ card->rb_timer.data = (unsigned long) card;
+ card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+ /* schedule again */
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
+ add_timer(&card->st_timer);
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+
+ /*
+@@ -416,8 +412,7 @@ isdnloop_sendbuf(int channel, struct sk_
+ return 0;
+ if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
+ return 0;
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ nskb = dev_alloc_skb(skb->len);
+ if (nskb) {
+ memcpy(skb_put(nskb, len), skb->data, len);
+@@ -426,7 +421,7 @@ isdnloop_sendbuf(int channel, struct sk_
+ } else
+ len = 0;
+ card->sndcount[channel] += len;
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+ return len;
+ }
+@@ -451,7 +446,8 @@ isdnloop_readstatus(u_char __user *buf,
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (card->msg_buf_read == card->msg_buf_write)
+ return count;
+- put_user(*card->msg_buf_read++, p);
++ if (put_user(*card->msg_buf_read++, p))
++ return -EFAULT;
+ if (card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+@@ -576,8 +572,7 @@ isdnloop_atimeout(isdnloop_card * card,
+ unsigned long flags;
+ char buf[60];
+
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ if (card->rcard) {
+ isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
+ card->rcard[ch]->rcard[card->rch[ch]] = NULL;
+@@ -587,7 +582,7 @@ isdnloop_atimeout(isdnloop_card * card,
+ /* No user responding */
+ sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
+ isdnloop_fake(card, buf, ch + 1);
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+
+ /*
+@@ -622,8 +617,7 @@ isdnloop_start_ctimer(isdnloop_card * ca
+ {
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ init_timer(&card->c_timer[ch]);
+ card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
+ if (ch)
+@@ -632,7 +626,7 @@ isdnloop_start_ctimer(isdnloop_card * ca
+ card->c_timer[ch].function = isdnloop_atimeout0;
+ card->c_timer[ch].data = (unsigned long) card;
+ add_timer(&card->c_timer[ch]);
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+
+ /*
+@@ -647,10 +641,9 @@ isdnloop_kill_ctimer(isdnloop_card * car
+ {
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ del_timer(&card->c_timer[ch]);
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+
+ static u_char si2bit[] =
+@@ -706,13 +699,12 @@ isdnloop_try_call(isdnloop_card * card,
+ }
+ }
+ if (num_match) {
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ /* channel idle? */
+ if (!(cc->rcard[ch])) {
+ /* Check SI */
+ if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return 3;
+ }
+ /* ch is idle, si and number matches */
+@@ -720,10 +712,10 @@ isdnloop_try_call(isdnloop_card * card,
+ cc->rch[ch] = lch;
+ card->rcard[lch] = cc;
+ card->rch[lch] = ch;
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return 0;
+ } else {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ /* num matches, but busy */
+ if (ch == 1)
+ return 1;
+@@ -1027,8 +1019,7 @@ isdnloop_stopcard(isdnloop_card * card)
+ unsigned long flags;
+ isdn_ctrl cmd;
+
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
+ card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
+ del_timer(&card->st_timer);
+@@ -1039,7 +1030,7 @@ isdnloop_stopcard(isdnloop_card * card)
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ }
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ }
+
+ /*
+@@ -1078,18 +1069,17 @@ isdnloop_start(isdnloop_card * card, isd
+ return -EBUSY;
+ if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
+ return -EFAULT;
+- save_flags(flags);
+- cli();
++ spin_lock_irqsave(&card->isdnloop_lock, flags);
+ switch (sdef.ptype) {
+ case ISDN_PTYPE_EURO:
+ if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
+ -1)) {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return -ENOMEM;
+ }
+ card->sil[0] = card->sil[1] = 4;
+ if (isdnloop_fake(card, "TEI OK", 0)) {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return -ENOMEM;
+ }
+ for (i = 0; i < 3; i++)
+@@ -1098,12 +1088,12 @@ isdnloop_start(isdnloop_card * card, isd
+ case ISDN_PTYPE_1TR6:
+ if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
+ -1)) {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return -ENOMEM;
+ }
+ card->sil[0] = card->sil[1] = 4;
+ if (isdnloop_fake(card, "TEI OK", 0)) {
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return -ENOMEM;
+ }
+ strcpy(card->s0num[0], sdef.num[0]);
+@@ -1111,7 +1101,7 @@ isdnloop_start(isdnloop_card * card, isd
+ card->s0num[2][0] = '\0';
+ break;
+ default:
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
+ sdef.ptype);
+ return -EINVAL;
+@@ -1122,7 +1112,7 @@ isdnloop_start(isdnloop_card * card, isd
+ card->st_timer.data = (unsigned long) card;
+ add_timer(&card->st_timer);
+ card->flags |= ISDNLOOP_FLAGS_RUNNING;
+- restore_flags(flags);
++ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
+ return 0;
+ }
+
+@@ -1472,6 +1462,7 @@ isdnloop_initcard(char *id)
+ skb_queue_head_init(&card->bqueue[i]);
+ }
+ skb_queue_head_init(&card->dqueue);
++ card->isdnloop_lock = SPIN_LOCK_UNLOCKED;
+ card->next = cards;
+ cards = card;
+ if (!register_isdn(&card->interface)) {
+diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
+index d699fe5..0d458a8 100644
+--- a/drivers/isdn/isdnloop/isdnloop.h
++++ b/drivers/isdn/isdnloop/isdnloop.h
+@@ -94,6 +94,7 @@ typedef struct isdnloop_card {
+ struct sk_buff_head
+ bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
+ struct sk_buff_head dqueue; /* D-Channel queue */
++ spinlock_t isdnloop_lock;
+ } isdnloop_card;
+
+ /*
+diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
+index 94f2148..6ead5e1 100644
+--- a/drivers/isdn/pcbit/drv.c
++++ b/drivers/isdn/pcbit/drv.c
+@@ -725,23 +725,27 @@ static int pcbit_stat(u_char __user *buf
+
+ if (stat_st < stat_end)
+ {
+- copy_to_user(buf, statbuf + stat_st, len);
++ if (copy_to_user(buf, statbuf + stat_st, len))
++ return -EFAULT;
+ stat_st += len;
+ }
+ else
+ {
+ if (len > STATBUF_LEN - stat_st)
+ {
+- copy_to_user(buf, statbuf + stat_st,
+- STATBUF_LEN - stat_st);
+- copy_to_user(buf, statbuf,
+- len - (STATBUF_LEN - stat_st));
++ if (copy_to_user(buf, statbuf + stat_st,
++ STATBUF_LEN - stat_st))
++ return -EFAULT;
++ if (copy_to_user(buf, statbuf,
++ len - (STATBUF_LEN - stat_st)))
++ return -EFAULT;
+
+ stat_st = len - (STATBUF_LEN - stat_st);
+ }
+ else
+ {
+- copy_to_user(buf, statbuf + stat_st, len);
++ if (copy_to_user(buf, statbuf + stat_st, len))
++ return -EFAULT;
+
+ stat_st += len;
+
+diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
+index ba76693..937fd21 100644
+--- a/drivers/isdn/pcbit/layer2.c
++++ b/drivers/isdn/pcbit/layer2.c
+@@ -311,6 +311,7 @@ pcbit_deliver(void *data)
+ dev->read_queue = frame->next;
+ spin_unlock_irqrestore(&dev->lock, flags);
+
++ msg = 0;
+ SET_MSG_CPU(msg, 0);
+ SET_MSG_PROC(msg, 0);
+ SET_MSG_CMD(msg, frame->skb->data[2]);
+@@ -512,7 +513,7 @@ pcbit_firmware_bug(struct pcbit_dev *dev
+ }
+
+ irqreturn_t
+-pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs)
++pcbit_irq_handler(int interrupt, void *devptr)
+ {
+ struct pcbit_dev *dev;
+ u_char info,
+diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h
+index 0d99da3..2ac295e 100644
+--- a/drivers/isdn/pcbit/layer2.h
++++ b/drivers/isdn/pcbit/layer2.h
+@@ -124,7 +124,7 @@ struct frame_buf {
+ extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum,
+ struct sk_buff *skb, unsigned short hdr_len);
+
+-extern irqreturn_t pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs);
++extern irqreturn_t pcbit_irq_handler(int interrupt, void *);
+
+ extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
+
+diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
+index b4b2433..04b8a58 100644
+--- a/drivers/isdn/sc/command.c
++++ b/drivers/isdn/sc/command.c
+@@ -103,9 +103,6 @@ int command(isdn_ctrl *cmd)
+ return -ENODEV;
+ }
+
+- pr_debug("%s: Received %s command from Link Layer\n",
+- sc_adapter[card]->devicename, commands[cmd->command]);
+-
+ /*
+ * Dispatch the command
+ */
+@@ -118,7 +115,7 @@ int command(isdn_ctrl *cmd)
+ memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
+ if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr,
+ sizeof(scs_ioctl))) {
+- pr_debug("%s: Failed to verify user space 0x%x\n",
++ pr_debug("%s: Failed to verify user space 0x%lx\n",
+ sc_adapter[card]->devicename, cmdptr);
+ return -EFAULT;
+ }
+@@ -195,7 +192,7 @@ static int dial(int card, unsigned long
+ strlen(Phone),
+ (unsigned int *) Phone);
+
+- pr_debug("%s: Dialing %s on channel %d\n",
++ pr_debug("%s: Dialing %s on channel %lu\n",
+ sc_adapter[card]->devicename, Phone, channel+1);
+
+ return status;
+@@ -217,7 +214,7 @@ static int answer(int card, unsigned lon
+ }
+
+ indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
+- pr_debug("%s: Answered incoming call on channel %s\n",
++ pr_debug("%s: Answered incoming call on channel %lu\n",
+ sc_adapter[card]->devicename, channel+1);
+ return 0;
+ }
+@@ -240,7 +237,7 @@ static int hangup(int card, unsigned lon
+ (unsigned char) channel+1,
+ 0,
+ NULL);
+- pr_debug("%s: Sent HANGUP message to channel %d\n",
++ pr_debug("%s: Sent HANGUP message to channel %lu\n",
+ sc_adapter[card]->devicename, channel+1);
+ return status;
+ }
+@@ -260,9 +257,6 @@ static int setl2(int card, unsigned long
+ protocol = arg >> 8;
+ channel = arg & 0xff;
+ sc_adapter[card]->channel[channel].l2_proto = protocol;
+- pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
+- sc_adapter[card]->devicename, channel+1,
+- l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol);
+
+ /*
+ * check that the adapter is also set to the correct protocol
+@@ -293,8 +287,6 @@ static int setl3(int card, unsigned long
+ }
+
+ sc_adapter[card]->channel[channel].l3_proto = protocol;
+- pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
+- sc_adapter[card]->devicename, channel+1, l3protos[protocol]);
+ return 0;
+ }
+
+@@ -311,7 +303,7 @@ static int acceptb(int card, unsigned lo
+ return -ENOBUFS;
+ }
+
+- pr_debug("%s: B-Channel connection accepted on channel %d\n",
++ pr_debug("%s: B-Channel connection accepted on channel %lu\n",
+ sc_adapter[card]->devicename, channel+1);
+ indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
+ return 0;
+@@ -326,7 +318,7 @@ static int clreaz(int card, unsigned lon
+
+ strcpy(sc_adapter[card]->channel[arg].eazlist, "");
+ sc_adapter[card]->channel[arg].eazclear = 1;
+- pr_debug("%s: EAZ List cleared for channel %d\n",
++ pr_debug("%s: EAZ List cleared for channel %lu\n",
+ sc_adapter[card]->devicename, arg+1);
+ return 0;
+ }
+@@ -340,7 +332,7 @@ static int seteaz(int card, unsigned lon
+
+ strcpy(sc_adapter[card]->channel[arg].eazlist, num);
+ sc_adapter[card]->channel[arg].eazclear = 0;
+- pr_debug("%s: EAZ list for channel %d set to: %s\n",
++ pr_debug("%s: EAZ list for channel %lu set to: %s\n",
+ sc_adapter[card]->devicename, arg+1,
+ sc_adapter[card]->channel[arg].eazlist);
+ return 0;
+diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c
+index 5b8c7c1..5736732 100644
+--- a/drivers/isdn/sc/event.c
++++ b/drivers/isdn/sc/event.c
+@@ -45,8 +45,10 @@ int indicate_status(int card, int event,
+ {
+ isdn_ctrl cmd;
+
++#ifdef DEBUG
+ pr_debug("%s: Indicating event %s on Channel %d\n",
+ sc_adapter[card]->devicename, events[event-256], Channel);
++#endif
+ if (Data != NULL){
+ pr_debug("%s: Event data: %s\n", sc_adapter[card]->devicename,
+ Data);
+diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
+index a627e68..06c9872 100644
+--- a/drivers/isdn/sc/init.c
++++ b/drivers/isdn/sc/init.c
+@@ -35,7 +35,7 @@ module_param_array(irq, int, NULL, 0);
+ module_param_array(ram, int, NULL, 0);
+ module_param(do_reset, bool, 0);
+
+-extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *);
++extern irqreturn_t interrupt_handler(int, void *);
+ extern int sndpkt(int, int, int, struct sk_buff *);
+ extern int command(isdn_ctrl *);
+ extern int indicate_status(int, int, ulong, char*);
+@@ -98,13 +98,14 @@ static int __init sc_init(void)
+ * Confirm the I/O Address with a test
+ */
+ if(io[b] == 0) {
+- pr_debug("I/O Address 0x%x is in use.\n");
++ pr_debug("I/O Address invalid.\n");
+ continue;
+ }
+
+ outb(0x18, io[b] + 0x400 * EXP_PAGE0);
+ if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
+- pr_debug("I/O Base 0x%x fails test\n");
++ pr_debug("I/O Base 0x%x fails test\n",
++ io[b] + 0x400 * EXP_PAGE0);
+ continue;
+ }
+ }
+@@ -158,8 +159,8 @@ static int __init sc_init(void)
+ outb(0xFF, io[b] + RESET_OFFSET);
+ msleep_interruptible(10000);
+ }
+- pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
+- ram[b] == 0 ? "will" : "won't");
++ pr_debug("RAM Base for board %d is 0x%lx, %s probe\n", b,
++ ram[b], ram[b] == 0 ? "will" : "won't");
+
+ if(ram[b]) {
+ /*
+@@ -168,7 +169,7 @@ static int __init sc_init(void)
+ * board model
+ */
+ if(request_region(ram[b], SRAM_PAGESIZE, "sc test")) {
+- pr_debug("request_region for RAM base 0x%x succeeded\n", ram[b]);
++ pr_debug("request_region for RAM base 0x%lx succeeded\n", ram[b]);
+ model = identify_board(ram[b], io[b]);
+ release_region(ram[b], SRAM_PAGESIZE);
+ }
+@@ -204,7 +205,7 @@ static int __init sc_init(void)
+ * Nope, there was no place in RAM for the
+ * board, or it couldn't be identified
+ */
+- pr_debug("Failed to find an adapter at 0x%x\n", ram[b]);
++ pr_debug("Failed to find an adapter at 0x%lx\n", ram[b]);
+ continue;
+ }
+
+@@ -451,7 +452,7 @@ static int identify_board(unsigned long
+ HWConfig_pl hwci;
+ int x;
+
+- pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n",
++ pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n",
+ rambase, iobase);
+
+ /*
+@@ -490,7 +491,7 @@ static int identify_board(unsigned long
+ outb(PRI_BASEPG_VAL, pgport);
+ msleep_interruptible(1000);
+ sig = readl(rambase + SIG_OFFSET);
+- pr_debug("Looking for a signature, got 0x%x\n", sig);
++ pr_debug("Looking for a signature, got 0x%lx\n", sig);
+ if(sig == SIGNATURE)
+ return PRI_BOARD;
+
+@@ -500,7 +501,7 @@ static int identify_board(unsigned long
+ outb(BRI_BASEPG_VAL, pgport);
+ msleep_interruptible(1000);
+ sig = readl(rambase + SIG_OFFSET);
+- pr_debug("Looking for a signature, got 0x%x\n", sig);
++ pr_debug("Looking for a signature, got 0x%lx\n", sig);
+ if(sig == SIGNATURE)
+ return BRI_BOARD;
+
+@@ -510,7 +511,7 @@ static int identify_board(unsigned long
+ * Try to spot a card
+ */
+ sig = readl(rambase + SIG_OFFSET);
+- pr_debug("Looking for a signature, got 0x%x\n", sig);
++ pr_debug("Looking for a signature, got 0x%lx\n", sig);
+ if(sig != SIGNATURE)
+ return -1;
+
+@@ -540,7 +541,7 @@ static int identify_board(unsigned long
+ memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN);
+ pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status);
+ memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl));
+- pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n"
++ pr_debug("Hardware Config: Interface: %s, RAM Size: %ld, Serial: %s\n"
+ " Part: %s, Rev: %s\n",
+ hwci.st_u_sense ? "S/T" : "U", hwci.ram_size,
+ hwci.serial_no, hwci.part_no, hwci.rev_no);
+diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
+index 8631d33..cd17de1 100644
+--- a/drivers/isdn/sc/interrupt.c
++++ b/drivers/isdn/sc/interrupt.c
+@@ -45,7 +45,7 @@ static int get_card_from_irq(int irq)
+ /*
+ *
+ */
+-irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs)
++irqreturn_t interrupt_handler(int interrupt, void *cardptr)
+ {
+
+ RspMessage rcvmsg;
+@@ -91,7 +91,7 @@ irqreturn_t interrupt_handler(int interr
+ */
+ if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
+ {
+- pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
++ pr_debug("%s: Received packet 0x%x bytes long at 0x%lx\n",
+ sc_adapter[card]->devicename,
+ rcvmsg.msg_data.response.msg_len,
+ rcvmsg.msg_data.response.buff_offset);
+diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
+index f50defc..1e04676 100644
+--- a/drivers/isdn/sc/packet.c
++++ b/drivers/isdn/sc/packet.c
+@@ -44,7 +44,7 @@ int sndpkt(int devId, int channel, struc
+ return -ENODEV;
+ }
+
+- pr_debug("%s: sndpkt: frst = 0x%x nxt = %d f = %d n = %d\n",
++ pr_debug("%s: sndpkt: frst = 0x%lx nxt = %d f = %d n = %d\n",
+ sc_adapter[card]->devicename,
+ sc_adapter[card]->channel[channel].first_sendbuf,
+ sc_adapter[card]->channel[channel].next_sendbuf,
+@@ -66,7 +66,7 @@ int sndpkt(int devId, int channel, struc
+ ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf *
+ BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf;
+ ReqLnkWrite.msg_len = data->len; /* sk_buff size */
+- pr_debug("%s: writing %d bytes to buffer offset 0x%x\n",
++ pr_debug("%s: writing %d bytes to buffer offset 0x%lx\n",
+ sc_adapter[card]->devicename,
+ ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
+ memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
+@@ -74,7 +74,7 @@ int sndpkt(int devId, int channel, struc
+ /*
+ * sendmessage
+ */
+- pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n",
++ pr_debug("%s: sndpkt size=%d, buf_offset=0x%lx buf_indx=%d\n",
+ sc_adapter[card]->devicename,
+ ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
+ sc_adapter[card]->channel[channel].next_sendbuf);
+@@ -124,7 +124,7 @@ void rcvpkt(int card, RspMessage *rcvmsg
+ return;
+ }
+ skb_put(skb, rcvmsg->msg_data.response.msg_len);
+- pr_debug("%s: getting data from offset: 0x%x\n",
++ pr_debug("%s: getting data from offset: 0x%lx\n",
+ sc_adapter[card]->devicename,
+ rcvmsg->msg_data.response.buff_offset);
+ memcpy_fromshmem(card,
+@@ -143,7 +143,7 @@ void rcvpkt(int card, RspMessage *rcvmsg
+ /* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
+ newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
+ newll.msg_len = BUFFER_SIZE;
+- pr_debug("%s: recycled buffer at offset 0x%x size %d\n",
++ pr_debug("%s: recycled buffer at offset 0x%lx size %d\n",
+ sc_adapter[card]->devicename,
+ newll.buff_offset, newll.msg_len);
+ sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
+@@ -186,7 +186,7 @@ int setup_buffers(int card, int c)
+ sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
+ sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
+ sc_adapter[card]->channel[c-1].next_sendbuf = 0;
+- pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
++ pr_debug("%s: send buffer setup complete: first=0x%lx n=%d f=%d, nxt=%d\n",
+ sc_adapter[card]->devicename,
+ sc_adapter[card]->channel[c-1].first_sendbuf,
+ sc_adapter[card]->channel[c-1].num_sendbufs,
+@@ -203,7 +203,7 @@ int setup_buffers(int card, int c)
+ ((sc_adapter[card]->channel[c-1].first_sendbuf +
+ (nBuffers / 2) * buffer_size) + (buffer_size * i));
+ RcvBuffOffset.msg_len = buffer_size;
+- pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n",
++ pr_debug("%s: adding RcvBuffer #%d offset=0x%lx sz=%d bufsz:%d\n",
+ sc_adapter[card]->devicename,
+ i + 1, RcvBuffOffset.buff_offset,
+ RcvBuffOffset.msg_len,buffer_size);
+diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
+index 2485482..6f58862 100644
+--- a/drivers/isdn/sc/shmem.c
++++ b/drivers/isdn/sc/shmem.c
+@@ -61,7 +61,7 @@ void memcpy_toshmem(int card, void *dest
+ spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
+ pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
+ ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+- pr_debug("%s: copying %d bytes from %#x to %#x\n",
++ pr_debug("%s: copying %d bytes from %#lx to %#lx\n",
+ sc_adapter[card]->devicename, n,
+ (unsigned long) src,
+ sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
+diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
+index aced19a..f43282b 100644
+--- a/drivers/isdn/sc/timer.c
++++ b/drivers/isdn/sc/timer.c
+@@ -76,7 +76,7 @@ void check_reset(unsigned long data)
+ if (sc_adapter[card]->StartOnReset)
+ startproc(card);
+ } else {
+- pr_debug("%s: No signature yet, waiting another %d jiffies.\n",
++ pr_debug("%s: No signature yet, waiting another %lu jiffies.\n",
+ sc_adapter[card]->devicename, CHECKRESET_TIME);
+ mod_timer(&sc_adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
+ spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
+diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
+index d424b44..3c17112 100644
+--- a/drivers/leds/led-class.c
++++ b/drivers/leds/led-class.c
+@@ -91,6 +91,8 @@ EXPORT_SYMBOL_GPL(led_classdev_resume);
+ */
+ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
+ {
++ int rc;
++
+ led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
+ parent, "%s", led_cdev->name);
+ if (unlikely(IS_ERR(led_cdev->class_dev)))
+@@ -99,8 +101,10 @@ int led_classdev_register(struct device
+ class_set_devdata(led_cdev->class_dev, led_cdev);
+
+ /* register the attributes */
+- class_device_create_file(led_cdev->class_dev,
+- &class_device_attr_brightness);
++ rc = class_device_create_file(led_cdev->class_dev,
++ &class_device_attr_brightness);
++ if (rc)
++ goto err_out;
+
+ /* add to the list of leds */
+ write_lock(&leds_list_lock);
+@@ -110,22 +114,34 @@ int led_classdev_register(struct device
+ #ifdef CONFIG_LEDS_TRIGGERS
+ rwlock_init(&led_cdev->trigger_lock);
+
+- led_trigger_set_default(led_cdev);
++ rc = class_device_create_file(led_cdev->class_dev,
++ &class_device_attr_trigger);
++ if (rc)
++ goto err_out_led_list;
+
+- class_device_create_file(led_cdev->class_dev,
+- &class_device_attr_trigger);
++ led_trigger_set_default(led_cdev);
+ #endif
+
+ printk(KERN_INFO "Registered led device: %s\n",
+ led_cdev->class_dev->class_id);
+
+ return 0;
++
++#ifdef CONFIG_LEDS_TRIGGERS
++err_out_led_list:
++ class_device_remove_file(led_cdev->class_dev,
++ &class_device_attr_brightness);
++ list_del(&led_cdev->node);
++#endif
++err_out:
++ class_device_unregister(led_cdev->class_dev);
++ return rc;
+ }
+ EXPORT_SYMBOL_GPL(led_classdev_register);
+
+ /**
+ * led_classdev_unregister - unregisters a object of led_properties class.
+- * @led_cdev: the led device to unreigister
++ * @led_cdev: the led device to unregister
+ *
+ * Unregisters a previously registered via led_classdev_register object.
+ */
+diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
+index 47f0ff1..454fb09 100644
+--- a/drivers/leds/led-triggers.c
++++ b/drivers/leds/led-triggers.c
+@@ -125,6 +125,7 @@ void led_trigger_set(struct led_classdev
+ write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
+ if (led_cdev->trigger->deactivate)
+ led_cdev->trigger->deactivate(led_cdev);
++ led_set_brightness(led_cdev, LED_OFF);
+ }
+ if (trigger) {
+ write_lock_irqsave(&trigger->leddev_list_lock, flags);
+diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
+index e9f0611..599878c 100644
+--- a/drivers/leds/leds-ams-delta.c
++++ b/drivers/leds/leds-ams-delta.c
+@@ -8,7 +8,6 @@
+ * published by the Free Software Foundation.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
+diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
+index 3b87951..6f2d449 100644
+--- a/drivers/leds/leds-locomo.c
++++ b/drivers/leds/leds-locomo.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/leds/locomo.c
++ * linux/drivers/leds/leds-locomo.c
+ *
+ * Copyright (C) 2005 John Lenz <lenz at cs.wisc.edu>
+ *
+diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
+index 713c4a8..45ba3d4 100644
+--- a/drivers/leds/leds-net48xx.c
++++ b/drivers/leds/leds-net48xx.c
+@@ -16,6 +16,7 @@
+ #include <linux/leds.h>
+ #include <linux/err.h>
+ #include <asm/io.h>
++#include <linux/nsc_gpio.h>
+ #include <linux/scx200_gpio.h>
+
+ #define DRVNAME "net48xx-led"
+@@ -26,10 +27,7 @@ static struct platform_device *pdev;
+ static void net48xx_error_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+ {
+- if (value)
+- scx200_gpio_set_high(NET48XX_ERROR_LED_GPIO);
+- else
+- scx200_gpio_set_low(NET48XX_ERROR_LED_GPIO);
++ scx200_gpio_ops.gpio_set(NET48XX_ERROR_LED_GPIO, value ? 1 : 0);
+ }
+
+ static struct led_classdev net48xx_error_led = {
+@@ -81,7 +79,8 @@ static int __init net48xx_led_init(void)
+ {
+ int ret;
+
+- if (!scx200_gpio_present()) {
++ /* small hack, but scx200_gpio doesn't set .dev if the probe fails */
++ if (!scx200_gpio_ops.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
+index 179c287..29a8818 100644
+--- a/drivers/leds/ledtrig-timer.c
++++ b/drivers/leds/ledtrig-timer.c
+@@ -123,6 +123,7 @@ static CLASS_DEVICE_ATTR(delay_off, 0644
+ static void timer_trig_activate(struct led_classdev *led_cdev)
+ {
+ struct timer_trig_data *timer_data;
++ int rc;
+
+ timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
+ if (!timer_data)
+@@ -134,10 +135,21 @@ static void timer_trig_activate(struct l
+ timer_data->timer.function = led_timer_function;
+ timer_data->timer.data = (unsigned long) led_cdev;
+
+- class_device_create_file(led_cdev->class_dev,
++ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_delay_on);
+- class_device_create_file(led_cdev->class_dev,
++ if (rc) goto err_out;
++ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_delay_off);
++ if (rc) goto err_out_delayon;
++
++ return;
++
++err_out_delayon:
++ class_device_remove_file(led_cdev->class_dev,
++ &class_device_attr_delay_on);
++err_out:
++ led_cdev->trigger_data = NULL;
++ kfree(timer_data);
+ }
+
+ static void timer_trig_deactivate(struct led_classdev *led_cdev)
+diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
+index d5d649f..7f8477d 100644
+--- a/drivers/macintosh/Kconfig
++++ b/drivers/macintosh/Kconfig
+@@ -186,7 +186,7 @@ config THERM_ADT746X
+ depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
+ help
+ This driver provides some thermostat and fan control for the
+- iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty
++ iBook G4, and the ATI based aluminium PowerBooks, allowing slightly
+ better fan behaviour by default, and some manual control.
+
+ config THERM_PM72
+diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
+index d56d400..17ef5d3 100644
+--- a/drivers/macintosh/adb-iop.c
++++ b/drivers/macintosh/adb-iop.c
+@@ -30,7 +30,7 @@
+
+ /*#define DEBUG_ADB_IOP*/
+
+-extern void iop_ism_irq(int, void *, struct pt_regs *);
++extern void iop_ism_irq(int, void *);
+
+ static struct adb_request *current_req;
+ static struct adb_request *last_req;
+@@ -78,7 +78,7 @@ static void adb_iop_end_req(struct adb_r
+ * This will be called when a packet has been successfully sent.
+ */
+
+-static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
++static void adb_iop_complete(struct iop_msg *msg)
+ {
+ struct adb_request *req;
+ uint flags;
+@@ -100,7 +100,7 @@ static void adb_iop_complete(struct iop_
+ * commands or autopoll packets) are received.
+ */
+
+-static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
++static void adb_iop_listen(struct iop_msg *msg)
+ {
+ struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
+ struct adb_request *req;
+@@ -143,7 +143,7 @@ static void adb_iop_listen(struct iop_ms
+ req->reply_len = amsg->count + 1;
+ memcpy(req->reply, &amsg->cmd, req->reply_len);
+ } else {
+- adb_input(&amsg->cmd, amsg->count + 1, regs,
++ adb_input(&amsg->cmd, amsg->count + 1,
+ amsg->flags & ADB_IOP_AUTOPOLL);
+ }
+ memcpy(msg->reply, msg->message, IOP_MSG_LEN);
+@@ -266,7 +266,7 @@ int adb_iop_autopoll(int devs)
+ void adb_iop_poll(void)
+ {
+ if (adb_iop_state == idle) adb_iop_start();
+- iop_ism_irq(0, (void *) ADB_IOP, NULL);
++ iop_ism_irq(0, (void *) ADB_IOP);
+ }
+
+ int adb_iop_reset_bus(void)
+diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
+index 360f93f..be0bd34 100644
+--- a/drivers/macintosh/adb.c
++++ b/drivers/macintosh/adb.c
+@@ -103,7 +103,7 @@ static void adbdev_init(void);
+ static int try_handler_change(int, int);
+
+ static struct adb_handler {
+- void (*handler)(unsigned char *, int, struct pt_regs *, int);
++ void (*handler)(unsigned char *, int, int);
+ int original_address;
+ int handler_id;
+ int busy;
+@@ -522,7 +522,7 @@ bail:
+ the handler_id id it doesn't match. */
+ int
+ adb_register(int default_id, int handler_id, struct adb_ids *ids,
+- void (*handler)(unsigned char *, int, struct pt_regs *, int))
++ void (*handler)(unsigned char *, int, int))
+ {
+ int i;
+
+@@ -570,13 +570,13 @@ adb_unregister(int index)
+ }
+
+ void
+-adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
++adb_input(unsigned char *buf, int nb, int autopoll)
+ {
+ int i, id;
+ static int dump_adb_input = 0;
+ unsigned long flags;
+
+- void (*handler)(unsigned char *, int, struct pt_regs *, int);
++ void (*handler)(unsigned char *, int, int);
+
+ /* We skip keystrokes and mouse moves when the sleep process
+ * has been started. We stop autopoll, but this is another security
+@@ -597,7 +597,7 @@ adb_input(unsigned char *buf, int nb, st
+ adb_handler[id].busy = 1;
+ write_unlock_irqrestore(&adb_handler_lock, flags);
+ if (handler != NULL) {
+- (*handler)(buf, nb, regs, autopoll);
++ (*handler)(buf, nb, autopoll);
+ wmb();
+ adb_handler[id].busy = 0;
+ }
+diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
+index c69d23b..5066e7a 100644
+--- a/drivers/macintosh/adbhid.c
++++ b/drivers/macintosh/adbhid.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/input/adbhid.c
++ * drivers/macintosh/adbhid.c
+ *
+ * ADB HID driver for Power Macintosh computers.
+ *
+@@ -45,8 +45,8 @@
+ #include <linux/pmu.h>
+
+ #include <asm/machdep.h>
+-#include <asm/backlight.h>
+ #ifdef CONFIG_PPC_PMAC
++#include <asm/backlight.h>
+ #include <asm/pmac_feature.h>
+ #endif
+
+@@ -222,7 +222,7 @@ static struct adbhid *adbhid[16];
+
+ static void adbhid_probe(void);
+
+-static void adbhid_input_keycode(int, int, int, struct pt_regs *);
++static void adbhid_input_keycode(int, int, int);
+
+ static void init_trackpad(int id);
+ static void init_trackball(int id);
+@@ -253,7 +253,7 @@ static struct adb_ids buttons_ids;
+ #define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */
+
+ static void
+-adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
++adbhid_keyboard_input(unsigned char *data, int nb, int apoll)
+ {
+ int id = (data[0] >> 4) & 0x0f;
+
+@@ -266,13 +266,13 @@ adbhid_keyboard_input(unsigned char *dat
+ /* first check this is from register 0 */
+ if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
+ return; /* ignore it */
+- adbhid_input_keycode(id, data[1], 0, regs);
++ adbhid_input_keycode(id, data[1], 0);
+ if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
+- adbhid_input_keycode(id, data[2], 0, regs);
++ adbhid_input_keycode(id, data[2], 0);
+ }
+
+ static void
+-adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
++adbhid_input_keycode(int id, int keycode, int repeat)
+ {
+ struct adbhid *ahid = adbhid[id];
+ int up_flag;
+@@ -282,7 +282,6 @@ adbhid_input_keycode(int id, int keycode
+
+ switch (keycode) {
+ case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
+- input_regs(ahid->input, regs);
+ input_report_key(ahid->input, KEY_CAPSLOCK, 1);
+ input_report_key(ahid->input, KEY_CAPSLOCK, 0);
+ input_sync(ahid->input);
+@@ -338,7 +337,6 @@ adbhid_input_keycode(int id, int keycode
+ }
+
+ if (adbhid[id]->keycode[keycode]) {
+- input_regs(adbhid[id]->input, regs);
+ input_report_key(adbhid[id]->input,
+ adbhid[id]->keycode[keycode], !up_flag);
+ input_sync(adbhid[id]->input);
+@@ -349,7 +347,7 @@ adbhid_input_keycode(int id, int keycode
+ }
+
+ static void
+-adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
++adbhid_mouse_input(unsigned char *data, int nb, int autopoll)
+ {
+ int id = (data[0] >> 4) & 0x0f;
+
+@@ -432,8 +430,6 @@ adbhid_mouse_input(unsigned char *data,
+ break;
+ }
+
+- input_regs(adbhid[id]->input, regs);
+-
+ input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1));
+ input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
+
+@@ -449,7 +445,7 @@ adbhid_mouse_input(unsigned char *data,
+ }
+
+ static void
+-adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
++adbhid_buttons_input(unsigned char *data, int nb, int autopoll)
+ {
+ int id = (data[0] >> 4) & 0x0f;
+
+@@ -458,8 +454,6 @@ adbhid_buttons_input(unsigned char *data
+ return;
+ }
+
+- input_regs(adbhid[id]->input, regs);
+-
+ switch (adbhid[id]->original_handler_id) {
+ default:
+ case 0x02: /* Adjustable keyboard button device */
+diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
+index 4b08852..797cef7 100644
+--- a/drivers/macintosh/macio-adb.c
++++ b/drivers/macintosh/macio-adb.c
+@@ -64,7 +64,7 @@ static DEFINE_SPINLOCK(macio_lock);
+
+ static int macio_probe(void);
+ static int macio_init(void);
+-static irqreturn_t macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs);
++static irqreturn_t macio_adb_interrupt(int irq, void *arg);
+ static int macio_send_request(struct adb_request *req, int sync);
+ static int macio_adb_autopoll(int devs);
+ static void macio_adb_poll(void);
+@@ -189,8 +189,7 @@ static int macio_send_request(struct adb
+ return 0;
+ }
+
+-static irqreturn_t macio_adb_interrupt(int irq, void *arg,
+- struct pt_regs *regs)
++static irqreturn_t macio_adb_interrupt(int irq, void *arg)
+ {
+ int i, n, err;
+ struct adb_request *req = NULL;
+@@ -260,7 +259,7 @@ static irqreturn_t macio_adb_interrupt(i
+ (*done)(req);
+ }
+ if (ibuf_len)
+- adb_input(ibuf, ibuf_len, regs, autopoll);
++ adb_input(ibuf, ibuf_len, autopoll);
+
+ return IRQ_RETVAL(handled);
+ }
+@@ -271,6 +270,6 @@ static void macio_adb_poll(void)
+
+ local_irq_save(flags);
+ if (in_8(&adb->intr.r) != 0)
+- macio_adb_interrupt(0, NULL, NULL);
++ macio_adb_interrupt(0, NULL);
+ local_irq_restore(flags);
+ }
+diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
+index 82657bc..d562160 100644
+--- a/drivers/macintosh/macio_asic.c
++++ b/drivers/macintosh/macio_asic.c
+@@ -139,7 +139,9 @@ static int macio_uevent(struct device *d
+ {
+ struct macio_dev * macio_dev;
+ struct of_device * of;
+- char *scratch, *compat, *compat2;
++ char *scratch;
++ const char *compat, *compat2;
++
+ int i = 0;
+ int length, cplen, cplen2, seen = 0;
+
+@@ -173,7 +175,7 @@ static int macio_uevent(struct device *d
+ * 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);
++ compat = get_property(of->node, "compatible", &cplen);
+ compat2 = compat;
+ cplen2= cplen;
+ while (compat && cplen > 0) {
+@@ -454,7 +456,7 @@ static struct macio_dev * macio_add_one_
+ struct resource *parent_res)
+ {
+ struct macio_dev *dev;
+- u32 *reg;
++ const u32 *reg;
+
+ if (np == NULL)
+ return NULL;
+@@ -489,7 +491,7 @@ static struct macio_dev * macio_add_one_
+ #endif
+ MAX_NODE_NAME_SIZE, np->name);
+ } else {
+- reg = (u32 *)get_property(np, "reg", NULL);
++ reg = get_property(np, "reg", NULL);
+ sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
+ chip->lbus.index,
+ reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
+diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
+index cae24a1..8566bdf 100644
+--- a/drivers/macintosh/macio_sysfs.c
++++ b/drivers/macintosh/macio_sysfs.c
+@@ -16,12 +16,12 @@ static ssize_t
+ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct of_device *of;
+- char *compat;
++ const char *compat;
+ int cplen;
+ int length = 0;
+
+ of = &to_macio_device (dev)->ofdev;
+- compat = (char *) get_property(of->node, "compatible", &cplen);
++ compat = get_property(of->node, "compatible", &cplen);
+ if (!compat) {
+ *buf = '\0';
+ return 0;
+@@ -42,12 +42,12 @@ static ssize_t modalias_show (struct dev
+ char *buf)
+ {
+ struct of_device *of;
+- char *compat;
++ const char *compat;
+ int cplen;
+ int length;
+
+ of = &to_macio_device (dev)->ofdev;
+- compat = (char *) get_property (of->node, "compatible", &cplen);
++ compat = get_property(of->node, "compatible", &cplen);
+ if (!compat) compat = "", cplen = 1;
+ length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type);
+ buf += length;
+diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
+index 00ef468..ade25b3 100644
+--- a/drivers/macintosh/smu.c
++++ b/drivers/macintosh/smu.c
+@@ -145,7 +145,7 @@ static void smu_start_cmd(void)
+ }
+
+
+-static irqreturn_t smu_db_intr(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t smu_db_intr(int irq, void *arg)
+ {
+ unsigned long flags;
+ struct smu_cmd *cmd;
+@@ -224,7 +224,7 @@ static irqreturn_t smu_db_intr(int irq,
+ }
+
+
+-static irqreturn_t smu_msg_intr(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t smu_msg_intr(int irq, void *arg)
+ {
+ /* I don't quite know what to do with this one, we seem to never
+ * receive it, so I suspect we have to arm it someway in the SMU
+@@ -309,7 +309,7 @@ void smu_poll(void)
+
+ gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell);
+ if ((gpio & 7) == 7)
+- smu_db_intr(smu->db_irq, smu, NULL);
++ smu_db_intr(smu->db_irq, smu);
+ }
+ EXPORT_SYMBOL(smu_poll);
+
+@@ -454,7 +454,7 @@ EXPORT_SYMBOL(smu_present);
+ int __init smu_init (void)
+ {
+ struct device_node *np;
+- u32 *data;
++ const u32 *data;
+
+ np = of_find_node_by_type(NULL, "smu");
+ if (np == NULL)
+@@ -490,7 +490,7 @@ int __init smu_init (void)
+ printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
+ goto fail;
+ }
+- data = (u32 *)get_property(smu->db_node, "reg", NULL);
++ data = get_property(smu->db_node, "reg", NULL);
+ if (data == NULL) {
+ of_node_put(smu->db_node);
+ smu->db_node = NULL;
+@@ -511,7 +511,7 @@ int __init smu_init (void)
+ smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
+ if (smu->msg_node == NULL)
+ break;
+- data = (u32 *)get_property(smu->msg_node, "reg", NULL);
++ data = get_property(smu->msg_node, "reg", NULL);
+ if (data == NULL) {
+ of_node_put(smu->msg_node);
+ smu->msg_node = NULL;
+@@ -870,7 +870,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cm
+
+ static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
+ {
+- DECLARE_COMPLETION(comp);
++ DECLARE_COMPLETION_ONSTACK(comp);
+ unsigned int chunk;
+ struct smu_cmd cmd;
+ int rc;
+@@ -917,7 +917,7 @@ static int smu_read_datablock(u8 *dest,
+
+ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
+ {
+- DECLARE_COMPLETION(comp);
++ DECLARE_COMPLETION_ONSTACK(comp);
+ struct smu_simple_cmd cmd;
+ unsigned int addr, len, tlen;
+ struct smu_sdbp_header *hdr;
+@@ -982,11 +982,11 @@ static struct smu_sdbp_header *smu_creat
+ /* Note: Only allowed to return error code in pointers (using ERR_PTR)
+ * when interruptible is 1
+ */
+-struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
+- int interruptible)
++const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
++ unsigned int *size, int interruptible)
+ {
+ char pname[32];
+- struct smu_sdbp_header *part;
++ const struct smu_sdbp_header *part;
+
+ if (!smu)
+ return NULL;
+@@ -1003,8 +1003,7 @@ struct smu_sdbp_header *__smu_get_sdb_pa
+ } else
+ mutex_lock(&smu_part_access);
+
+- part = (struct smu_sdbp_header *)get_property(smu->of_node,
+- pname, size);
++ part = get_property(smu->of_node, pname, size);
+ if (part == NULL) {
+ DPRINTK("trying to extract from SMU ...\n");
+ part = smu_create_sdb_partition(id);
+@@ -1015,7 +1014,7 @@ struct smu_sdbp_header *__smu_get_sdb_pa
+ return part;
+ }
+
+-struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
++const struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
+ {
+ return __smu_get_sdb_partition(id, size, 0);
+ }
+@@ -1094,7 +1093,7 @@ static ssize_t smu_write(struct file *fi
+ pp->mode = smu_file_events;
+ return 0;
+ } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
+- struct smu_sdbp_header *part;
++ const struct smu_sdbp_header *part;
+ part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
+ if (part == NULL)
+ return -EINVAL;
+diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
+index 7f86478..a0f30d0 100644
+--- a/drivers/macintosh/therm_adt746x.c
++++ b/drivers/macintosh/therm_adt746x.c
+@@ -47,7 +47,7 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
+
+ static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */
+ static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */
+-static char *sensor_location[3] = {NULL, NULL, NULL};
++static const char *sensor_location[3] = {NULL, NULL, NULL};
+
+ static int limit_adjust = 0;
+ static int fan_speed = -1;
+@@ -553,7 +553,7 @@ static int __init
+ thermostat_init(void)
+ {
+ struct device_node* np;
+- u32 *prop;
++ const u32 *prop;
+ int i = 0, offset = 0;
+
+ np = of_find_node_by_name(NULL, "fan");
+@@ -566,13 +566,13 @@ thermostat_init(void)
+ else
+ return -ENODEV;
+
+- prop = (u32 *)get_property(np, "hwsensor-params-version", NULL);
++ prop = get_property(np, "hwsensor-params-version", NULL);
+ printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
+ (*prop == 1)?"":"un");
+ if (*prop != 1)
+ return -ENODEV;
+
+- prop = (u32 *)get_property(np, "reg", NULL);
++ prop = get_property(np, "reg", NULL);
+ if (!prop)
+ return -ENODEV;
+
+diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
+index 20bf672..d00c0c3 100644
+--- a/drivers/macintosh/therm_pm72.c
++++ b/drivers/macintosh/therm_pm72.c
+@@ -660,7 +660,7 @@ static int read_eeprom(int cpu, struct m
+ {
+ struct device_node *np;
+ char nodename[64];
+- u8 *data;
++ const u8 *data;
+ int len;
+
+ /* prom.c routine for finding a node by path is a bit brain dead
+@@ -673,7 +673,7 @@ static int read_eeprom(int cpu, struct m
+ printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid node from device-tree\n");
+ return -ENODEV;
+ }
+- data = (u8 *)get_property(np, "cpuid", &len);
++ data = get_property(np, "cpuid", &len);
+ if (data == NULL) {
+ printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid property from device-tree\n");
+ of_node_put(np);
+@@ -1336,7 +1336,7 @@ static int init_backside_state(struct ba
+ */
+ u3 = of_find_node_by_path("/u3 at 0,f8000000");
+ if (u3 != NULL) {
+- u32 *vers = (u32 *)get_property(u3, "device-rev", NULL);
++ const u32 *vers = get_property(u3, "device-rev", NULL);
+ if (vers)
+ if (((*vers) & 0x3f) < 0x34)
+ u3h = 0;
+@@ -2111,8 +2111,8 @@ static void fcu_lookup_fans(struct devic
+
+ while ((np = of_get_next_child(fcu_node, np)) != NULL) {
+ int type = -1;
+- char *loc;
+- u32 *reg;
++ const char *loc;
++ const u32 *reg;
+
+ DBG(" control: %s, type: %s\n", np->name, np->type);
+
+@@ -2128,8 +2128,8 @@ static void fcu_lookup_fans(struct devic
+ continue;
+
+ /* Lookup for a matching location */
+- loc = (char *)get_property(np, "location", NULL);
+- reg = (u32 *)get_property(np, "reg", NULL);
++ loc = get_property(np, "location", NULL);
++ reg = get_property(np, "reg", NULL);
+ if (loc == NULL || reg == NULL)
+ continue;
+ DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
+diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
+index c7d1c29..738faab 100644
+--- a/drivers/macintosh/therm_windtunnel.c
++++ b/drivers/macintosh/therm_windtunnel.c
+@@ -484,14 +484,14 @@ struct apple_thermal_info {
+ static int __init
+ g4fan_init( void )
+ {
+- struct apple_thermal_info *info;
++ const struct apple_thermal_info *info;
+ struct device_node *np;
+
+ init_MUTEX( &x.lock );
+
+ if( !(np=of_find_node_by_name(NULL, "power-mgt")) )
+ return -ENODEV;
+- info = (struct apple_thermal_info*)get_property(np, "thermal-info", NULL);
++ info = get_property(np, "thermal-info", NULL);
+ of_node_put(np);
+
+ if( !info || !machine_is_compatible("PowerMac3,6") )
+diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
+index 69d5452..df66291 100644
+--- a/drivers/macintosh/via-cuda.c
++++ b/drivers/macintosh/via-cuda.c
+@@ -98,8 +98,8 @@ static int cuda_reset_adb_bus(void);
+
+ static int cuda_init_via(void);
+ static void cuda_start(void);
+-static irqreturn_t cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
+-static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
++static irqreturn_t cuda_interrupt(int irq, void *arg);
++static void cuda_input(unsigned char *buf, int nb);
+ void cuda_poll(void);
+ static int cuda_write(struct adb_request *req);
+
+@@ -123,7 +123,7 @@ int __init find_via_cuda(void)
+ {
+ struct adb_request req;
+ phys_addr_t taddr;
+- u32 *reg;
++ const u32 *reg;
+ int err;
+
+ if (vias != 0)
+@@ -132,7 +132,7 @@ int __init find_via_cuda(void)
+ if (vias == 0)
+ return 0;
+
+- reg = (u32 *)get_property(vias, "reg", NULL);
++ reg = get_property(vias, "reg", NULL);
+ if (reg == NULL) {
+ printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
+ goto fail;
+@@ -437,12 +437,12 @@ cuda_poll(void)
+ * disable_irq(), would that work on m68k ? --BenH
+ */
+ local_irq_save(flags);
+- cuda_interrupt(0, NULL, NULL);
++ cuda_interrupt(0, NULL);
+ local_irq_restore(flags);
+ }
+
+ static irqreturn_t
+-cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
++cuda_interrupt(int irq, void *arg)
+ {
+ int status;
+ struct adb_request *req = NULL;
+@@ -594,12 +594,12 @@ cuda_interrupt(int irq, void *arg, struc
+ (*done)(req);
+ }
+ if (ibuf_len)
+- cuda_input(ibuf, ibuf_len, regs);
++ cuda_input(ibuf, ibuf_len);
+ return IRQ_HANDLED;
+ }
+
+ static void
+-cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
++cuda_input(unsigned char *buf, int nb)
+ {
+ int i;
+
+@@ -615,7 +615,7 @@ cuda_input(unsigned char *buf, int nb, s
+ }
+ #endif /* CONFIG_XMON */
+ #ifdef CONFIG_ADB
+- adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
++ adb_input(buf+2, nb-2, buf[1] & 0x40);
+ #endif /* CONFIG_ADB */
+ break;
+
+diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
+index 2a2ffe0..5d88d5b 100644
+--- a/drivers/macintosh/via-macii.c
++++ b/drivers/macintosh/via-macii.c
+@@ -77,7 +77,7 @@ static volatile unsigned char *via;
+
+ static int macii_init_via(void);
+ static void macii_start(void);
+-static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs);
++static irqreturn_t macii_interrupt(int irq, void *arg);
+ static void macii_retransmit(int);
+ static void macii_queue_poll(void);
+
+@@ -295,7 +295,7 @@ static void macii_poll(void)
+ unsigned long flags;
+
+ local_irq_save(flags);
+- if (via[IFR] & SR_INT) macii_interrupt(0, NULL, NULL);
++ if (via[IFR] & SR_INT) macii_interrupt(0, NULL);
+ local_irq_restore(flags);
+ }
+
+@@ -410,7 +410,7 @@ static void macii_start(void)
+ * Note: As of 21/10/97, the MacII ADB part works including timeout detection
+ * and retransmit (Talk to the last active device).
+ */
+-static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t macii_interrupt(int irq, void *arg)
+ {
+ int x, adbdir;
+ unsigned long flags;
+@@ -602,8 +602,7 @@ static irqreturn_t macii_interrupt(int i
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+ } else {
+- adb_input(reply_buf, reply_ptr - reply_buf,
+- regs, 0);
++ adb_input(reply_buf, reply_ptr - reply_buf, 0);
+ }
+
+ /*
+diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c
+index 0129fcc..1f0aa5d 100644
+--- a/drivers/macintosh/via-maciisi.c
++++ b/drivers/macintosh/via-maciisi.c
+@@ -84,8 +84,8 @@ static int maciisi_init(void);
+ static int maciisi_send_request(struct adb_request* req, int sync);
+ static void maciisi_sync(struct adb_request *req);
+ static int maciisi_write(struct adb_request* req);
+-static irqreturn_t maciisi_interrupt(int irq, void* arg, struct pt_regs* regs);
+-static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs);
++static irqreturn_t maciisi_interrupt(int irq, void* arg);
++static void maciisi_input(unsigned char *buf, int nb);
+ static int maciisi_init_via(void);
+ static void maciisi_poll(void);
+ static int maciisi_start(void);
+@@ -421,7 +421,7 @@ maciisi_poll(void)
+
+ local_irq_save(flags);
+ if (via[IFR] & SR_INT) {
+- maciisi_interrupt(0, NULL, NULL);
++ maciisi_interrupt(0, NULL);
+ }
+ else /* avoid calling this function too quickly in a loop */
+ udelay(ADB_DELAY);
+@@ -433,7 +433,7 @@ maciisi_poll(void)
+ register is either full or empty. In practice, I have no idea what
+ it means :( */
+ static irqreturn_t
+-maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
++maciisi_interrupt(int irq, void* arg)
+ {
+ int status;
+ struct adb_request *req;
+@@ -612,7 +612,7 @@ maciisi_interrupt(int irq, void* arg, st
+ /* Obviously, we got it */
+ reading_reply = 0;
+ } else {
+- maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs);
++ maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf);
+ }
+ maciisi_state = idle;
+ status = via[B] & (TIP|TREQ);
+@@ -657,7 +657,7 @@ maciisi_interrupt(int irq, void* arg, st
+ }
+
+ static void
+-maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs)
++maciisi_input(unsigned char *buf, int nb)
+ {
+ #ifdef DEBUG_MACIISI_ADB
+ int i;
+@@ -665,7 +665,7 @@ maciisi_input(unsigned char *buf, int nb
+
+ switch (buf[0]) {
+ case ADB_PACKET:
+- adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
++ adb_input(buf+2, nb-2, buf[1] & 0x40);
+ break;
+ default:
+ #ifdef DEBUG_MACIISI_ADB
+diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
+index a82f313..6c29fe7 100644
+--- a/drivers/macintosh/via-pmu-backlight.c
++++ b/drivers/macintosh/via-pmu-backlight.c
+@@ -16,7 +16,7 @@
+ #define MAX_PMU_LEVEL 0xFF
+
+ static struct backlight_properties pmu_backlight_data;
+-static spinlock_t pmu_backlight_lock;
++static DEFINE_SPINLOCK(pmu_backlight_lock);
+ static int sleeping;
+ static u8 bl_curve[FB_BACKLIGHT_LEVELS];
+
+diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
+index 5189d54..179af10 100644
+--- a/drivers/macintosh/via-pmu-led.c
++++ b/drivers/macintosh/via-pmu-led.c
+@@ -120,7 +120,7 @@ static int __init via_pmu_led_init(void)
+ dt = of_find_node_by_path("/");
+ if (dt == NULL)
+ return -ENODEV;
+- model = (const char *)get_property(dt, "model", NULL);
++ model = get_property(dt, "model", NULL);
+ if (model == NULL)
+ return -ENODEV;
+ if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
+diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
+index 14610a6..e63ea1c 100644
+--- a/drivers/macintosh/via-pmu.c
++++ b/drivers/macintosh/via-pmu.c
+@@ -191,8 +191,8 @@ static int pmu_adb_reset_bus(void);
+
+ static int init_pmu(void);
+ static void pmu_start(void);
+-static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
+-static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
++static irqreturn_t via_pmu_interrupt(int irq, void *arg);
++static irqreturn_t gpio1_interrupt(int irq, void *arg);
+ static int proc_get_info(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+ static int proc_get_irqstats(char *page, char **start, off_t off,
+@@ -280,7 +280,7 @@ static char *pbook_type[] = {
+ int __init find_via_pmu(void)
+ {
+ u64 taddr;
+- u32 *reg;
++ const u32 *reg;
+
+ if (via != 0)
+ return 1;
+@@ -288,7 +288,7 @@ int __init find_via_pmu(void)
+ if (vias == NULL)
+ return 0;
+
+- reg = (u32 *)get_property(vias, "reg", NULL);
++ reg = get_property(vias, "reg", NULL);
+ if (reg == NULL) {
+ printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
+ goto fail;
+@@ -330,14 +330,16 @@ int __init find_via_pmu(void)
+
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (gpiop) {
+- reg = (u32 *)get_property(gpiop, "reg", NULL);
++ reg = get_property(gpiop, "reg", NULL);
+ if (reg)
+ gaddr = of_translate_address(gpiop, reg);
+ if (gaddr != OF_BAD_ADDR)
+ gpio_reg = ioremap(gaddr, 0x10);
+ }
+- if (gpio_reg == NULL)
++ if (gpio_reg == NULL) {
+ printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
++ goto fail_gpio;
++ }
+ } else
+ pmu_kind = PMU_UNKNOWN;
+
+@@ -365,6 +367,9 @@ int __init find_via_pmu(void)
+ return 1;
+ fail:
+ of_node_put(vias);
++ iounmap(gpio_reg);
++ gpio_reg = NULL;
++ fail_gpio:
+ vias = NULL;
+ return 0;
+ }
+@@ -479,9 +484,9 @@ static int __init via_pmu_dev_init(void)
+ pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
+ } else {
+ struct device_node* prim = find_devices("power-mgt");
+- u32 *prim_info = NULL;
++ const u32 *prim_info = NULL;
+ if (prim)
+- prim_info = (u32 *)get_property(prim, "prim-info", NULL);
++ prim_info = get_property(prim, "prim-info", NULL);
+ if (prim_info) {
+ /* Other stuffs here yet unknown */
+ pmu_battery_count = (prim_info[6] >> 16) & 0xff;
+@@ -550,7 +555,7 @@ init_pmu(void)
+ }
+ if (pmu_state == idle)
+ adb_int_pending = 1;
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+ udelay(10);
+ }
+
+@@ -1210,7 +1215,7 @@ pmu_poll(void)
+ return;
+ if (disable_poll)
+ return;
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+ }
+
+ void
+@@ -1223,7 +1228,7 @@ pmu_poll_adb(void)
+ /* Kicks ADB read when PMU is suspended */
+ adb_int_pending = 1;
+ do {
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+ } while (pmu_suspended && (adb_int_pending || pmu_state != idle
+ || req_awaiting_reply));
+ }
+@@ -1234,7 +1239,7 @@ pmu_wait_complete(struct adb_request *re
+ if (!via)
+ return;
+ while((pmu_state != idle && pmu_state != locked) || !req->complete)
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+ }
+
+ /* This function loops until the PMU is idle and prevents it from
+@@ -1263,7 +1268,7 @@ pmu_suspend(void)
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ if (req_awaiting_reply)
+ adb_int_pending = 1;
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+ spin_lock_irqsave(&pmu_lock, flags);
+ if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
+ #ifdef SUSPEND_USES_PMU
+@@ -1313,7 +1318,7 @@ pmu_resume(void)
+
+ /* Interrupt data could be the result data from an ADB cmd */
+ static void
+-pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
++pmu_handle_data(unsigned char *data, int len)
+ {
+ unsigned char ints, pirq;
+ int i = 0;
+@@ -1388,7 +1393,7 @@ next:
+ if (!(pmu_kind == PMU_OHARE_BASED && len == 4
+ && data[1] == 0x2c && data[3] == 0xff
+ && (data[2] & ~1) == 0xf4))
+- adb_input(data+1, len-1, regs, 1);
++ adb_input(data+1, len-1, 1);
+ #endif /* CONFIG_ADB */
+ }
+ }
+@@ -1426,7 +1431,7 @@ next:
+ }
+
+ static struct adb_request*
+-pmu_sr_intr(struct pt_regs *regs)
++pmu_sr_intr(void)
+ {
+ struct adb_request *req;
+ int bite = 0;
+@@ -1532,7 +1537,7 @@ pmu_sr_intr(struct pt_regs *regs)
+ }
+
+ static irqreturn_t
+-via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
++via_pmu_interrupt(int irq, void *arg)
+ {
+ unsigned long flags;
+ int intr;
+@@ -1562,7 +1567,7 @@ via_pmu_interrupt(int irq, void *arg, st
+ pmu_irq_stats[0]++;
+ }
+ if (intr & SR_INT) {
+- req = pmu_sr_intr(regs);
++ req = pmu_sr_intr();
+ if (req)
+ break;
+ }
+@@ -1608,7 +1613,7 @@ no_free_slot:
+
+ /* Deal with interrupt datas outside of the lock */
+ if (int_data >= 0) {
+- pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs);
++ pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]);
+ spin_lock_irqsave(&pmu_lock, flags);
+ ++disable_poll;
+ int_data_state[int_data] = int_data_empty;
+@@ -1633,7 +1638,7 @@ pmu_unlock(void)
+
+
+ static irqreturn_t
+-gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
++gpio1_interrupt(int irq, void *arg)
+ {
+ unsigned long flags;
+
+@@ -1646,7 +1651,7 @@ gpio1_interrupt(int irq, void *arg, stru
+ pmu_irq_stats[1]++;
+ adb_int_pending = 1;
+ spin_unlock_irqrestore(&pmu_lock, flags);
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+@@ -1827,7 +1832,7 @@ pbook_alloc_pci_save(void)
+ struct pci_dev *pd = NULL;
+
+ npci = 0;
+- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
++ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ ++npci;
+ }
+ if (npci == 0)
+@@ -1857,9 +1862,11 @@ pbook_pci_save(void)
+ if (ps == NULL)
+ return;
+
+- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+- if (npci-- == 0)
++ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
++ if (npci-- == 0) {
++ pci_dev_put(pd);
+ return;
++ }
+ #ifndef HACKED_PCI_SAVE
+ pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+ pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
+@@ -1887,11 +1894,13 @@ pbook_pci_restore(void)
+ int npci = pbook_npci_saves;
+ int j;
+
+- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
++ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ #ifdef HACKED_PCI_SAVE
+ int i;
+- if (npci-- == 0)
++ if (npci-- == 0) {
++ pci_dev_put(pd);
+ return;
++ }
+ ps++;
+ for (i=2;i<16;i++)
+ pci_write_config_dword(pd, i<<4, ps->config[i]);
+@@ -2107,7 +2116,7 @@ pmac_wakeup_devices(void)
+
+ /* Force a poll of ADB interrupts */
+ adb_int_pending = 1;
+- via_pmu_interrupt(0, NULL, NULL);
++ via_pmu_interrupt(0, NULL);
+
+ /* Restart jiffies & scheduling */
+ wakeup_decrementer();
+diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
+index 35b7032..d9986f3 100644
+--- a/drivers/macintosh/via-pmu68k.c
++++ b/drivers/macintosh/via-pmu68k.c
+@@ -107,7 +107,7 @@ BLOCKING_NOTIFIER_HEAD(sleep_notifier_li
+ static int pmu_probe(void);
+ static int pmu_init(void);
+ static void pmu_start(void);
+-static irqreturn_t pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
++static irqreturn_t pmu_interrupt(int irq, void *arg);
+ static int pmu_send_request(struct adb_request *req, int sync);
+ static int pmu_autopoll(int devs);
+ void pmu_poll(void);
+@@ -118,8 +118,7 @@ static void pmu_start(void);
+ static void send_byte(int x);
+ static void recv_byte(void);
+ static void pmu_done(struct adb_request *req);
+-static void pmu_handle_data(unsigned char *data, int len,
+- struct pt_regs *regs);
++static void pmu_handle_data(unsigned char *data, int len);
+ static void set_volume(int level);
+ static void pmu_enable_backlight(int on);
+ static void pmu_set_brightness(int level);
+@@ -222,7 +221,7 @@ pmu_init(void)
+ }
+ if (pmu_state == idle) {
+ adb_int_pending = 1;
+- pmu_interrupt(0, NULL, NULL);
++ pmu_interrupt(0, NULL);
+ }
+ pmu_poll();
+ udelay(10);
+@@ -563,17 +562,17 @@ pmu_poll(void)
+ local_irq_save(flags);
+ if (via1[IFR] & SR_INT) {
+ via1[IFR] = SR_INT;
+- pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL);
++ pmu_interrupt(IRQ_MAC_ADB_SR, NULL);
+ }
+ if (via1[IFR] & CB1_INT) {
+ via1[IFR] = CB1_INT;
+- pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL);
++ pmu_interrupt(IRQ_MAC_ADB_CL, NULL);
+ }
+ local_irq_restore(flags);
+ }
+
+ static irqreturn_t
+-pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++pmu_interrupt(int irq, void *dev_id)
+ {
+ struct adb_request *req;
+ int timeout, bite = 0; /* to prevent compiler warning */
+@@ -657,7 +656,7 @@ pmu_interrupt(int irq, void *dev_id, str
+ }
+
+ if (pmu_state == reading_intr) {
+- pmu_handle_data(interrupt_data, data_index, regs);
++ pmu_handle_data(interrupt_data, data_index);
+ } else {
+ req = current_req;
+ current_req = req->next;
+@@ -701,7 +700,7 @@ pmu_done(struct adb_request *req)
+
+ /* Interrupt data could be the result data from an ADB cmd */
+ static void
+-pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
++pmu_handle_data(unsigned char *data, int len)
+ {
+ static int show_pmu_ints = 1;
+
+@@ -726,7 +725,7 @@ pmu_handle_data(unsigned char *data, int
+ }
+ pmu_done(req);
+ } else {
+- adb_input(data+1, len-1, regs, 1);
++ adb_input(data+1, len-1, 1);
+ }
+ } else {
+ if (data[0] == 0x08 && len == 3) {
+@@ -843,7 +842,7 @@ pbook_pci_save(void)
+ struct pci_save *ps;
+
+ npci = 0;
+- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
++ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
+ ++npci;
+ n_pbook_pci_saves = npci;
+ if (npci == 0)
+@@ -854,7 +853,7 @@ pbook_pci_save(void)
+ return;
+
+ pd = NULL;
+- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
++ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+ pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
+ pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
+@@ -871,7 +870,7 @@ pbook_pci_restore(void)
+ struct pci_dev *pd = NULL;
+ int j;
+
+- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
++ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ if (ps->command == 0)
+ continue;
+ pci_read_config_word(pd, PCI_COMMAND, &cmd);
+diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
+index ef66bf2..fa4b13f 100644
+--- a/drivers/macintosh/windfarm_pm112.c
++++ b/drivers/macintosh/windfarm_pm112.c
+@@ -650,24 +650,26 @@ static struct notifier_block pm112_event
+ .notifier_call = pm112_wf_notify,
+ };
+
+-static int wf_pm112_probe(struct device *dev)
++static int wf_pm112_probe(struct platform_device *dev)
+ {
+ wf_register_client(&pm112_events);
+ return 0;
+ }
+
+-static int wf_pm112_remove(struct device *dev)
++static int __devexit wf_pm112_remove(struct platform_device *dev)
+ {
+ wf_unregister_client(&pm112_events);
+ /* should release all sensors and controls */
+ return 0;
+ }
+
+-static struct device_driver wf_pm112_driver = {
+- .name = "windfarm",
+- .bus = &platform_bus_type,
++static struct platform_driver wf_pm112_driver = {
+ .probe = wf_pm112_probe,
+- .remove = wf_pm112_remove,
++ .remove = __devexit_p(wf_pm112_remove),
++ .driver = {
++ .name = "windfarm",
++ .bus = &platform_bus_type,
++ },
+ };
+
+ static int __init wf_pm112_init(void)
+@@ -683,13 +685,13 @@ static int __init wf_pm112_init(void)
+ ++nr_cores;
+
+ printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n");
+- driver_register(&wf_pm112_driver);
++ platform_driver_register(&wf_pm112_driver);
+ return 0;
+ }
+
+ static void __exit wf_pm112_exit(void)
+ {
+- driver_unregister(&wf_pm112_driver);
++ platform_driver_unregister(&wf_pm112_driver);
+ }
+
+ module_init(wf_pm112_init);
+diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
+index f1df6ef..2a94485 100644
+--- a/drivers/macintosh/windfarm_pm81.c
++++ b/drivers/macintosh/windfarm_pm81.c
+@@ -131,8 +131,6 @@
+
+ static int wf_smu_mach_model; /* machine model id */
+
+-static struct device *wf_smu_dev;
+-
+ /* Controls & sensors */
+ static struct wf_sensor *sensor_cpu_power;
+ static struct wf_sensor *sensor_cpu_temp;
+@@ -396,7 +394,7 @@ static void wf_smu_sys_fans_tick(struct
+ static void wf_smu_create_cpu_fans(void)
+ {
+ struct wf_cpu_pid_param pid_param;
+- struct smu_sdbp_header *hdr;
++ const struct smu_sdbp_header *hdr;
+ struct smu_sdbp_cpupiddata *piddata;
+ struct smu_sdbp_fvt *fvt;
+ s32 tmax, tdelta, maxpow, powadj;
+@@ -702,7 +700,7 @@ static struct notifier_block wf_smu_even
+
+ static int wf_init_pm(void)
+ {
+- struct smu_sdbp_header *hdr;
++ const struct smu_sdbp_header *hdr;
+
+ hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
+ if (hdr != 0) {
+@@ -717,16 +715,14 @@ static int wf_init_pm(void)
+ return 0;
+ }
+
+-static int wf_smu_probe(struct device *ddev)
++static int wf_smu_probe(struct platform_device *ddev)
+ {
+- wf_smu_dev = ddev;
+-
+ wf_register_client(&wf_smu_events);
+
+ return 0;
+ }
+
+-static int wf_smu_remove(struct device *ddev)
++static int __devexit wf_smu_remove(struct platform_device *ddev)
+ {
+ wf_unregister_client(&wf_smu_events);
+
+@@ -766,16 +762,16 @@ static int wf_smu_remove(struct device *
+ if (wf_smu_cpu_fans)
+ kfree(wf_smu_cpu_fans);
+
+- wf_smu_dev = NULL;
+-
+ return 0;
+ }
+
+-static struct device_driver wf_smu_driver = {
+- .name = "windfarm",
+- .bus = &platform_bus_type,
++static struct platform_driver wf_smu_driver = {
+ .probe = wf_smu_probe,
+- .remove = wf_smu_remove,
++ .remove = __devexit_p(wf_smu_remove),
++ .driver = {
++ .name = "windfarm",
++ .bus = &platform_bus_type,
++ },
+ };
+
+
+@@ -794,7 +790,7 @@ static int __init wf_smu_init(void)
+ request_module("windfarm_lm75_sensor");
+
+ #endif /* MODULE */
+- driver_register(&wf_smu_driver);
++ platform_driver_register(&wf_smu_driver);
+ }
+
+ return rc;
+@@ -803,7 +799,7 @@ static int __init wf_smu_init(void)
+ static void __exit wf_smu_exit(void)
+ {
+
+- driver_unregister(&wf_smu_driver);
++ platform_driver_unregister(&wf_smu_driver);
+ }
+
+
+diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
+index 0d6372e..9961a67 100644
+--- a/drivers/macintosh/windfarm_pm91.c
++++ b/drivers/macintosh/windfarm_pm91.c
+@@ -63,8 +63,6 @@
+ */
+ #undef HACKED_OVERTEMP
+
+-static struct device *wf_smu_dev;
+-
+ /* Controls & sensors */
+ static struct wf_sensor *sensor_cpu_power;
+ static struct wf_sensor *sensor_cpu_temp;
+@@ -144,7 +142,7 @@ static struct wf_smu_slots_fans_state *w
+ static void wf_smu_create_cpu_fans(void)
+ {
+ struct wf_cpu_pid_param pid_param;
+- struct smu_sdbp_header *hdr;
++ const struct smu_sdbp_header *hdr;
+ struct smu_sdbp_cpupiddata *piddata;
+ struct smu_sdbp_fvt *fvt;
+ s32 tmax, tdelta, maxpow, powadj;
+@@ -641,16 +639,14 @@ static int wf_init_pm(void)
+ return 0;
+ }
+
+-static int wf_smu_probe(struct device *ddev)
++static int wf_smu_probe(struct platform_device *ddev)
+ {
+- wf_smu_dev = ddev;
+-
+ wf_register_client(&wf_smu_events);
+
+ return 0;
+ }
+
+-static int wf_smu_remove(struct device *ddev)
++static int __devexit wf_smu_remove(struct platform_device *ddev)
+ {
+ wf_unregister_client(&wf_smu_events);
+
+@@ -698,16 +694,16 @@ static int wf_smu_remove(struct device *
+ if (wf_smu_cpu_fans)
+ kfree(wf_smu_cpu_fans);
+
+- wf_smu_dev = NULL;
+-
+ return 0;
+ }
+
+-static struct device_driver wf_smu_driver = {
+- .name = "windfarm",
+- .bus = &platform_bus_type,
++static struct platform_driver wf_smu_driver = {
+ .probe = wf_smu_probe,
+- .remove = wf_smu_remove,
++ .remove = __devexit_p(wf_smu_remove),
++ .driver = {
++ .name = "windfarm",
++ .bus = &platform_bus_type,
++ },
+ };
+
+
+@@ -725,7 +721,7 @@ static int __init wf_smu_init(void)
+ request_module("windfarm_lm75_sensor");
+
+ #endif /* MODULE */
+- driver_register(&wf_smu_driver);
++ platform_driver_register(&wf_smu_driver);
+ }
+
+ return rc;
+@@ -734,7 +730,7 @@ static int __init wf_smu_init(void)
+ static void __exit wf_smu_exit(void)
+ {
+
+- driver_unregister(&wf_smu_driver);
++ platform_driver_unregister(&wf_smu_driver);
+ }
+
+
+diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
+index a9e88ed..31b750d 100644
+--- a/drivers/macintosh/windfarm_smu_controls.c
++++ b/drivers/macintosh/windfarm_smu_controls.c
+@@ -56,7 +56,7 @@ static int smu_set_fan(int pwm, u8 id, u
+ {
+ struct smu_cmd cmd;
+ u8 buffer[16];
+- DECLARE_COMPLETION(comp);
++ DECLARE_COMPLETION_ONSTACK(comp);
+ int rc;
+
+ /* Fill SMU command structure */
+@@ -159,14 +159,15 @@ static struct smu_fan_control *smu_fan_c
+ int pwm_fan)
+ {
+ struct smu_fan_control *fct;
+- s32 *v; u32 *reg;
+- char *l;
++ const s32 *v;
++ const u32 *reg;
++ const char *l;
+
+ fct = kmalloc(sizeof(struct smu_fan_control), GFP_KERNEL);
+ if (fct == NULL)
+ return NULL;
+ fct->ctrl.ops = &smu_fan_ops;
+- l = (char *)get_property(node, "location", NULL);
++ l = get_property(node, "location", NULL);
+ if (l == NULL)
+ goto fail;
+
+@@ -223,17 +224,17 @@ static struct smu_fan_control *smu_fan_c
+ goto fail;
+
+ /* Get min & max values*/
+- v = (s32 *)get_property(node, "min-value", NULL);
++ v = get_property(node, "min-value", NULL);
+ if (v == NULL)
+ goto fail;
+ fct->min = *v;
+- v = (s32 *)get_property(node, "max-value", NULL);
++ v = get_property(node, "max-value", NULL);
+ if (v == NULL)
+ goto fail;
+ fct->max = *v;
+
+ /* Get "reg" value */
+- reg = (u32 *)get_property(node, "reg", NULL);
++ reg = get_property(node, "reg", NULL);
+ if (reg == NULL)
+ goto fail;
+ fct->reg = *reg;
+diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
+index e295a07..83f79de 100644
+--- a/drivers/macintosh/windfarm_smu_sat.c
++++ b/drivers/macintosh/windfarm_smu_sat.c
+@@ -233,15 +233,15 @@ static void wf_sat_create(struct i2c_ada
+ {
+ struct wf_sat *sat;
+ struct wf_sat_sensor *sens;
+- u32 *reg;
+- char *loc, *type;
++ const u32 *reg;
++ const char *loc, *type;
+ u8 addr, chip, core;
+ struct device_node *child;
+ int shift, cpu, index;
+ char *name;
+ int vsens[2], isens[2];
+
+- reg = (u32 *) get_property(dev, "reg", NULL);
++ reg = get_property(dev, "reg", NULL);
+ if (reg == NULL)
+ return;
+ addr = *reg;
+@@ -268,7 +268,7 @@ static void wf_sat_create(struct i2c_ada
+ isens[0] = isens[1] = -1;
+ child = NULL;
+ while ((child = of_get_next_child(dev, child)) != NULL) {
+- reg = (u32 *) get_property(child, "reg", NULL);
++ reg = get_property(child, "reg", NULL);
+ type = get_property(child, "device_type", NULL);
+ loc = get_property(child, "location", NULL);
+ if (reg == NULL || loc == NULL)
+@@ -397,12 +397,7 @@ static int wf_sat_detach(struct i2c_clie
+
+ static int __init sat_sensors_init(void)
+ {
+- int err;
+-
+- err = i2c_add_driver(&wf_sat_driver);
+- if (err < 0)
+- return err;
+- return 0;
++ return i2c_add_driver(&wf_sat_driver);
+ }
+
+ static void __exit sat_sensors_exit(void)
+diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
+index bed25dc..01b4c50 100644
+--- a/drivers/macintosh/windfarm_smu_sensors.c
++++ b/drivers/macintosh/windfarm_smu_sensors.c
+@@ -67,7 +67,7 @@ static void smu_ads_release(struct wf_se
+ static int smu_read_adc(u8 id, s32 *value)
+ {
+ struct smu_simple_cmd cmd;
+- DECLARE_COMPLETION(comp);
++ DECLARE_COMPLETION_ONSTACK(comp);
+ int rc;
+
+ rc = smu_queue_simple(&cmd, SMU_CMD_READ_ADC, 1,
+@@ -198,14 +198,14 @@ static struct wf_sensor_ops smu_slotspow
+ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
+ {
+ struct smu_ad_sensor *ads;
+- char *c, *l;
+- u32 *v;
++ const char *c, *l;
++ const u32 *v;
+
+ ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
+ if (ads == NULL)
+ return NULL;
+- c = (char *)get_property(node, "device_type", NULL);
+- l = (char *)get_property(node, "location", NULL);
++ c = get_property(node, "device_type", NULL);
++ l = get_property(node, "location", NULL);
+ if (c == NULL || l == NULL)
+ goto fail;
+
+@@ -255,7 +255,7 @@ static struct smu_ad_sensor *smu_ads_cre
+ } else
+ goto fail;
+
+- v = (u32 *)get_property(node, "reg", NULL);
++ v = get_property(node, "reg", NULL);
+ if (v == NULL)
+ goto fail;
+ ads->reg = *v;
+@@ -382,7 +382,7 @@ smu_cpu_power_create(struct wf_sensor *v
+
+ static void smu_fetch_param_partitions(void)
+ {
+- struct smu_sdbp_header *hdr;
++ const struct smu_sdbp_header *hdr;
+
+ /* Get CPU voltage/current/power calibration data */
+ hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL);
+diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
+index 09baa43..da862e4 100644
+--- a/drivers/mca/mca-bus.c
++++ b/drivers/mca/mca-bus.c
+@@ -100,6 +100,7 @@ static DEVICE_ATTR(pos, S_IRUGO, mca_sho
+ int __init mca_register_device(int bus, struct mca_device *mca_dev)
+ {
+ struct mca_bus *mca_bus = mca_root_busses[bus];
++ int rc;
+
+ mca_dev->dev.parent = &mca_bus->dev;
+ mca_dev->dev.bus = &mca_bus_type;
+@@ -108,13 +109,23 @@ int __init mca_register_device(int bus,
+ mca_dev->dev.dma_mask = &mca_dev->dma_mask;
+ mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
+
+- if (device_register(&mca_dev->dev))
+- return 0;
++ rc = device_register(&mca_dev->dev);
++ if (rc)
++ goto err_out;
+
+- device_create_file(&mca_dev->dev, &dev_attr_id);
+- device_create_file(&mca_dev->dev, &dev_attr_pos);
++ rc = device_create_file(&mca_dev->dev, &dev_attr_id);
++ if (rc) goto err_out_devreg;
++ rc = device_create_file(&mca_dev->dev, &dev_attr_pos);
++ if (rc) goto err_out_id;
+
+ return 1;
++
++err_out_id:
++ device_remove_file(&mca_dev->dev, &dev_attr_id);
++err_out_devreg:
++ device_unregister(&mca_dev->dev);
++err_out:
++ return 0;
+ }
+
+ /* */
+@@ -130,13 +141,16 @@ struct mca_bus * __devinit mca_attach_bu
+ return NULL;
+ }
+
+- mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL);
++ mca_bus = kzalloc(sizeof(struct mca_bus), GFP_KERNEL);
+ if (!mca_bus)
+ return NULL;
+- memset(mca_bus, 0, sizeof(struct mca_bus));
++
+ sprintf(mca_bus->dev.bus_id,"mca%d",bus);
+ sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
+- device_register(&mca_bus->dev);
++ if (device_register(&mca_bus->dev)) {
++ kfree(mca_bus);
++ return NULL;
++ }
+
+ mca_root_busses[bus] = mca_bus;
+
+diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
+index bf869ed..c92c152 100644
+--- a/drivers/md/Kconfig
++++ b/drivers/md/Kconfig
+@@ -2,6 +2,8 @@
+ # Block device driver configuration
+ #
+
++if BLOCK
++
+ menu "Multi-device support (RAID and LVM)"
+
+ config MD
+@@ -136,16 +138,16 @@ config MD_RAID456
+ If unsure, say Y.
+
+ config MD_RAID5_RESHAPE
+- bool "Support adding drives to a raid-5 array (experimental)"
+- depends on MD_RAID456 && EXPERIMENTAL
++ bool "Support adding drives to a raid-5 array"
++ depends on MD_RAID456
++ default y
+ ---help---
+ A RAID-5 set can be expanded by adding extra drives. This
+ requires "restriping" the array which means (almost) every
+ block must be written to a different place.
+
+ This option allows such restriping to be done while the array
+- is online. However it is still EXPERIMENTAL code. It should
+- work, but please be sure that you have backups.
++ is online.
+
+ You will need mdadm version 2.4.1 or later to use this
+ feature safely. During the early stage of reshape there is
+@@ -162,6 +164,8 @@ config MD_RAID5_RESHAPE
+ There should be enough spares already present to make the new
+ array workable.
+
++ If unsure, say Y.
++
+ config MD_MULTIPATH
+ tristate "Multipath I/O support"
+ depends on BLK_DEV_MD
+@@ -199,6 +203,14 @@ config BLK_DEV_DM
+
+ If unsure, say N.
+
++config DM_DEBUG
++ boolean "Device mapper debugging support"
++ depends on BLK_DEV_DM && EXPERIMENTAL
++ ---help---
++ Enable this for messages that may help debug device-mapper problems.
++
++ If unsure, say N.
++
+ config DM_CRYPT
+ tristate "Crypt target support"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+@@ -251,3 +263,4 @@ config DM_MULTIPATH_EMC
+
+ endmenu
+
++endif
+diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
+index ecc5676..d6f6147 100644
+--- a/drivers/md/bitmap.c
++++ b/drivers/md/bitmap.c
+@@ -536,7 +536,7 @@ static int bitmap_read_sb(struct bitmap
+ printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) "
+ "-- forcing full recovery\n", bmname(bitmap), events,
+ (unsigned long long) bitmap->mddev->events);
+- sb->state |= BITMAP_STALE;
++ sb->state |= cpu_to_le32(BITMAP_STALE);
+ }
+ success:
+ /* assign fields using values from superblock */
+@@ -544,11 +544,11 @@ success:
+ bitmap->daemon_sleep = daemon_sleep;
+ bitmap->daemon_lastrun = jiffies;
+ bitmap->max_write_behind = write_behind;
+- bitmap->flags |= sb->state;
++ bitmap->flags |= le32_to_cpu(sb->state);
+ if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
+ bitmap->flags |= BITMAP_HOSTENDIAN;
+ bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
+- if (sb->state & BITMAP_STALE)
++ if (sb->state & cpu_to_le32(BITMAP_STALE))
+ bitmap->events_cleared = bitmap->mddev->events;
+ err = 0;
+ out:
+@@ -578,9 +578,9 @@ static void bitmap_mask_state(struct bit
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
+ switch (op) {
+- case MASK_SET: sb->state |= bits;
++ case MASK_SET: sb->state |= cpu_to_le32(bits);
+ break;
+- case MASK_UNSET: sb->state &= ~bits;
++ case MASK_UNSET: sb->state &= cpu_to_le32(~bits);
+ break;
+ default: BUG();
+ }
+@@ -613,6 +613,7 @@ static inline unsigned long file_page_of
+ static inline struct page *filemap_get_page(struct bitmap *bitmap,
+ unsigned long chunk)
+ {
++ if (file_page_index(chunk) >= bitmap->file_pages) return NULL;
+ return bitmap->filemap[file_page_index(chunk) - file_page_index(0)];
+ }
+
+@@ -739,6 +740,7 @@ static void bitmap_file_set_bit(struct b
+ }
+
+ page = filemap_get_page(bitmap, chunk);
++ if (!page) return;
+ bit = file_page_offset(chunk);
+
+ /* set the bit */
+@@ -1322,6 +1324,18 @@ static void bitmap_set_memory_bits(struc
+
+ }
+
++/* dirty the memory and file bits for bitmap chunks "s" to "e" */
++void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
++{
++ unsigned long chunk;
++
++ for (chunk = s; chunk <= e; chunk++) {
++ sector_t sec = chunk << CHUNK_BLOCK_SHIFT(bitmap);
++ bitmap_set_memory_bits(bitmap, sec, 1);
++ bitmap_file_set_bit(bitmap, sec);
++ }
++}
++
+ /*
+ * flush out any pending updates
+ */
+@@ -1399,7 +1413,7 @@ int bitmap_create(mddev_t *mddev)
+ int err;
+ sector_t start;
+
+- BUG_ON(sizeof(bitmap_super_t) != 256);
++ BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
+
+ if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */
+ return 0;
+@@ -1430,8 +1444,7 @@ int bitmap_create(mddev_t *mddev)
+ if (err)
+ goto error;
+
+- bitmap->chunkshift = find_first_bit(&bitmap->chunksize,
+- sizeof(bitmap->chunksize));
++ bitmap->chunkshift = ffz(~bitmap->chunksize);
+
+ /* now that chunksize and chunkshift are set, we can use these macros */
+ chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) /
+diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
+index 6022ed1..08a40f4 100644
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -1,10 +1,12 @@
+ /*
+ * Copyright (C) 2003 Christophe Saout <christophe at saout.de>
+ * Copyright (C) 2004 Clemens Fruhwirth <clemens at endorphin.org>
++ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+@@ -14,6 +16,7 @@
+ #include <linux/slab.h>
+ #include <linux/crypto.h>
+ #include <linux/workqueue.h>
++#include <linux/backing-dev.h>
+ #include <asm/atomic.h>
+ #include <linux/scatterlist.h>
+ #include <asm/page.h>
+@@ -21,17 +24,19 @@
+ #include "dm.h"
+
+ #define DM_MSG_PREFIX "crypt"
++#define MESG_STR(x) x, sizeof(x)
+
+ /*
+ * per bio private data
+ */
+ struct crypt_io {
+ struct dm_target *target;
+- struct bio *bio;
++ struct bio *base_bio;
+ struct bio *first_clone;
+ struct work_struct work;
+ atomic_t pending;
+ int error;
++ int post_process;
+ };
+
+ /*
+@@ -62,6 +67,7 @@ struct crypt_iv_operations {
+ * Crypt: maps a linear range of a block device
+ * and encrypts / decrypts at the same time.
+ */
++enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
+ struct crypt_config {
+ struct dm_dev *dev;
+ sector_t start;
+@@ -72,22 +78,26 @@ struct crypt_config {
+ */
+ mempool_t *io_pool;
+ mempool_t *page_pool;
++ struct bio_set *bs;
+
+ /*
+ * crypto related data
+ */
+ struct crypt_iv_operations *iv_gen_ops;
+ char *iv_mode;
+- void *iv_gen_private;
++ struct crypto_cipher *iv_gen_private;
+ sector_t iv_offset;
+ unsigned int iv_size;
+
+- struct crypto_tfm *tfm;
++ char cipher[CRYPTO_MAX_ALG_NAME];
++ char chainmode[CRYPTO_MAX_ALG_NAME];
++ struct crypto_blkcipher *tfm;
++ unsigned long flags;
+ unsigned int key_size;
+ u8 key[0];
+ };
+
+-#define MIN_IOS 256
++#define MIN_IOS 16
+ #define MIN_POOL_PAGES 32
+ #define MIN_BIO_PAGES 8
+
+@@ -96,12 +106,12 @@ static kmem_cache_t *_crypt_io_pool;
+ /*
+ * Different IV generation algorithms:
+ *
+- * plain: the initial vector is the 32-bit low-endian version of the sector
++ * plain: the initial vector is the 32-bit little-endian version of the sector
+ * number, padded with zeros if neccessary.
+ *
+- * ess_iv: "encrypted sector|salt initial vector", the sector number is
+- * encrypted with the bulk cipher using a salt as key. The salt
+- * should be derived from the bulk cipher's key via hashing.
++ * essiv: "encrypted sector|salt initial vector", the sector number is
++ * encrypted with the bulk cipher using a salt as key. The salt
++ * should be derived from the bulk cipher's key via hashing.
+ *
+ * plumb: unimplemented, see:
+ * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
+@@ -118,11 +128,13 @@ static int crypt_iv_plain_gen(struct cry
+ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts)
+ {
+- struct crypto_tfm *essiv_tfm;
+- struct crypto_tfm *hash_tfm;
++ struct crypto_cipher *essiv_tfm;
++ struct crypto_hash *hash_tfm;
++ struct hash_desc desc;
+ struct scatterlist sg;
+ unsigned int saltsize;
+ u8 *salt;
++ int err;
+
+ if (opts == NULL) {
+ ti->error = "Digest algorithm missing for ESSIV mode";
+@@ -130,76 +142,70 @@ static int crypt_iv_essiv_ctr(struct cry
+ }
+
+ /* Hash the cipher key with the given hash algorithm */
+- hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
+- if (hash_tfm == NULL) {
++ hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(hash_tfm)) {
+ ti->error = "Error initializing ESSIV hash";
+- return -EINVAL;
+- }
+-
+- if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) {
+- ti->error = "Expected digest algorithm for ESSIV hash";
+- crypto_free_tfm(hash_tfm);
+- return -EINVAL;
++ return PTR_ERR(hash_tfm);
+ }
+
+- saltsize = crypto_tfm_alg_digestsize(hash_tfm);
++ saltsize = crypto_hash_digestsize(hash_tfm);
+ salt = kmalloc(saltsize, GFP_KERNEL);
+ if (salt == NULL) {
+ ti->error = "Error kmallocing salt storage in ESSIV";
+- crypto_free_tfm(hash_tfm);
++ crypto_free_hash(hash_tfm);
+ return -ENOMEM;
+ }
+
+ sg_set_buf(&sg, cc->key, cc->key_size);
+- crypto_digest_digest(hash_tfm, &sg, 1, salt);
+- crypto_free_tfm(hash_tfm);
++ desc.tfm = hash_tfm;
++ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++ err = crypto_hash_digest(&desc, &sg, cc->key_size, salt);
++ crypto_free_hash(hash_tfm);
++
++ if (err) {
++ ti->error = "Error calculating hash in ESSIV";
++ return err;
++ }
+
+ /* Setup the essiv_tfm with the given salt */
+- essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
+- CRYPTO_TFM_MODE_ECB |
+- CRYPTO_TFM_REQ_MAY_SLEEP);
+- if (essiv_tfm == NULL) {
++ essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(essiv_tfm)) {
+ ti->error = "Error allocating crypto tfm for ESSIV";
+ kfree(salt);
+- return -EINVAL;
++ return PTR_ERR(essiv_tfm);
+ }
+- if (crypto_tfm_alg_blocksize(essiv_tfm)
+- != crypto_tfm_alg_ivsize(cc->tfm)) {
++ if (crypto_cipher_blocksize(essiv_tfm) !=
++ crypto_blkcipher_ivsize(cc->tfm)) {
+ ti->error = "Block size of ESSIV cipher does "
+ "not match IV size of block cipher";
+- crypto_free_tfm(essiv_tfm);
++ crypto_free_cipher(essiv_tfm);
+ kfree(salt);
+ return -EINVAL;
+ }
+- if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) {
++ err = crypto_cipher_setkey(essiv_tfm, salt, saltsize);
++ if (err) {
+ ti->error = "Failed to set key for ESSIV cipher";
+- crypto_free_tfm(essiv_tfm);
++ crypto_free_cipher(essiv_tfm);
+ kfree(salt);
+- return -EINVAL;
++ return err;
+ }
+ kfree(salt);
+
+- cc->iv_gen_private = (void *)essiv_tfm;
++ cc->iv_gen_private = essiv_tfm;
+ return 0;
+ }
+
+ static void crypt_iv_essiv_dtr(struct crypt_config *cc)
+ {
+- crypto_free_tfm((struct crypto_tfm *)cc->iv_gen_private);
++ crypto_free_cipher(cc->iv_gen_private);
+ cc->iv_gen_private = NULL;
+ }
+
+ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+ {
+- struct scatterlist sg;
+-
+ memset(iv, 0, cc->iv_size);
+ *(u64 *)iv = cpu_to_le64(sector);
+-
+- sg_set_buf(&sg, iv, cc->iv_size);
+- crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private,
+- &sg, &sg, cc->iv_size);
+-
++ crypto_cipher_encrypt_one(cc->iv_gen_private, iv, iv);
+ return 0;
+ }
+
+@@ -220,6 +226,11 @@ crypt_convert_scatterlist(struct crypt_c
+ int write, sector_t sector)
+ {
+ u8 iv[cc->iv_size];
++ struct blkcipher_desc desc = {
++ .tfm = cc->tfm,
++ .info = iv,
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
++ };
+ int r;
+
+ if (cc->iv_gen_ops) {
+@@ -228,14 +239,14 @@ crypt_convert_scatterlist(struct crypt_c
+ return r;
+
+ if (write)
+- r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length, iv);
++ r = crypto_blkcipher_encrypt_iv(&desc, out, in, length);
+ else
+- r = crypto_cipher_decrypt_iv(cc->tfm, out, in, length, iv);
++ r = crypto_blkcipher_decrypt_iv(&desc, out, in, length);
+ } else {
+ if (write)
+- r = crypto_cipher_encrypt(cc->tfm, out, in, length);
++ r = crypto_blkcipher_encrypt(&desc, out, in, length);
+ else
+- r = crypto_cipher_decrypt(cc->tfm, out, in, length);
++ r = crypto_blkcipher_decrypt(&desc, out, in, length);
+ }
+
+ return r;
+@@ -302,6 +313,14 @@ static int crypt_convert(struct crypt_co
+ return r;
+ }
+
++ static void dm_crypt_bio_destructor(struct bio *bio)
++ {
++ struct crypt_io *io = bio->bi_private;
++ struct crypt_config *cc = io->target->private;
++
++ bio_free(bio, cc->bs);
++ }
++
+ /*
+ * Generate a new unfragmented bio with the given size
+ * This should never violate the device limitations
+@@ -311,34 +330,33 @@ static struct bio *
+ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
+ struct bio *base_bio, unsigned int *bio_vec_idx)
+ {
+- struct bio *bio;
++ struct bio *clone;
+ unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+ unsigned int i;
+
+- /*
+- * Use __GFP_NOMEMALLOC to tell the VM to act less aggressively and
+- * to fail earlier. This is not necessary but increases throughput.
+- * FIXME: Is this really intelligent?
+- */
+- if (base_bio)
+- bio = bio_clone(base_bio, GFP_NOIO|__GFP_NOMEMALLOC);
+- else
+- bio = bio_alloc(GFP_NOIO|__GFP_NOMEMALLOC, nr_iovecs);
+- if (!bio)
++ if (base_bio) {
++ clone = bio_alloc_bioset(GFP_NOIO, base_bio->bi_max_vecs, cc->bs);
++ __bio_clone(clone, base_bio);
++ } else
++ clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
++
++ if (!clone)
+ return NULL;
+
++ clone->bi_destructor = dm_crypt_bio_destructor;
++
+ /* if the last bio was not complete, continue where that one ended */
+- bio->bi_idx = *bio_vec_idx;
+- bio->bi_vcnt = *bio_vec_idx;
+- bio->bi_size = 0;
+- bio->bi_flags &= ~(1 << BIO_SEG_VALID);
++ clone->bi_idx = *bio_vec_idx;
++ clone->bi_vcnt = *bio_vec_idx;
++ clone->bi_size = 0;
++ clone->bi_flags &= ~(1 << BIO_SEG_VALID);
+
+- /* bio->bi_idx pages have already been allocated */
+- size -= bio->bi_idx * PAGE_SIZE;
++ /* clone->bi_idx pages have already been allocated */
++ size -= clone->bi_idx * PAGE_SIZE;
+
+- for(i = bio->bi_idx; i < nr_iovecs; i++) {
+- struct bio_vec *bv = bio_iovec_idx(bio, i);
++ for (i = clone->bi_idx; i < nr_iovecs; i++) {
++ struct bio_vec *bv = bio_iovec_idx(clone, i);
+
+ bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
+ if (!bv->bv_page)
+@@ -349,7 +367,7 @@ crypt_alloc_buffer(struct crypt_config *
+ * return a partially allocated bio, the caller will then try
+ * to allocate additional bios while submitting this partial bio
+ */
+- if ((i - bio->bi_idx) == (MIN_BIO_PAGES - 1))
++ if ((i - clone->bi_idx) == (MIN_BIO_PAGES - 1))
+ gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+
+ bv->bv_offset = 0;
+@@ -358,13 +376,13 @@ crypt_alloc_buffer(struct crypt_config *
+ else
+ bv->bv_len = size;
+
+- bio->bi_size += bv->bv_len;
+- bio->bi_vcnt++;
++ clone->bi_size += bv->bv_len;
++ clone->bi_vcnt++;
+ size -= bv->bv_len;
+ }
+
+- if (!bio->bi_size) {
+- bio_put(bio);
++ if (!clone->bi_size) {
++ bio_put(clone);
+ return NULL;
+ }
+
+@@ -372,13 +390,13 @@ crypt_alloc_buffer(struct crypt_config *
+ * Remember the last bio_vec allocated to be able
+ * to correctly continue after the splitting.
+ */
+- *bio_vec_idx = bio->bi_vcnt;
++ *bio_vec_idx = clone->bi_vcnt;
+
+- return bio;
++ return clone;
+ }
+
+ static void crypt_free_buffer_pages(struct crypt_config *cc,
+- struct bio *bio, unsigned int bytes)
++ struct bio *clone, unsigned int bytes)
+ {
+ unsigned int i, start, end;
+ struct bio_vec *bv;
+@@ -392,19 +410,19 @@ static void crypt_free_buffer_pages(stru
+ * A fix to the bi_idx issue in the kernel is in the works, so
+ * we will hopefully be able to revert to the cleaner solution soon.
+ */
+- i = bio->bi_vcnt - 1;
+- bv = bio_iovec_idx(bio, i);
+- end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - bio->bi_size;
++ i = clone->bi_vcnt - 1;
++ bv = bio_iovec_idx(clone, i);
++ end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size;
+ start = end - bytes;
+
+ start >>= PAGE_SHIFT;
+- if (!bio->bi_size)
+- end = bio->bi_vcnt;
++ if (!clone->bi_size)
++ end = clone->bi_vcnt;
+ else
+ end >>= PAGE_SHIFT;
+
+- for(i = start; i < end; i++) {
+- bv = bio_iovec_idx(bio, i);
++ for (i = start; i < end; i++) {
++ bv = bio_iovec_idx(clone, i);
+ BUG_ON(!bv->bv_page);
+ mempool_free(bv->bv_page, cc->page_pool);
+ bv->bv_page = NULL;
+@@ -428,7 +446,7 @@ static void dec_pending(struct crypt_io
+ if (io->first_clone)
+ bio_put(io->first_clone);
+
+- bio_endio(io->bio, io->bio->bi_size, io->error);
++ bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
+
+ mempool_free(io, cc->io_pool);
+ }
+@@ -437,29 +455,179 @@ static void dec_pending(struct crypt_io
+ * kcryptd:
+ *
+ * Needed because it would be very unwise to do decryption in an
+- * interrupt context, so bios returning from read requests get
+- * queued here.
++ * interrupt context.
+ */
+ static struct workqueue_struct *_kcryptd_workqueue;
++static void kcryptd_do_work(void *data);
+
+-static void kcryptd_do_work(void *data)
++static void kcryptd_queue_io(struct crypt_io *io)
+ {
+- struct crypt_io *io = (struct crypt_io *) data;
+- struct crypt_config *cc = (struct crypt_config *) io->target->private;
++ INIT_WORK(&io->work, kcryptd_do_work, io);
++ queue_work(_kcryptd_workqueue, &io->work);
++}
++
++static int crypt_endio(struct bio *clone, unsigned int done, int error)
++{
++ struct crypt_io *io = clone->bi_private;
++ struct crypt_config *cc = io->target->private;
++ unsigned read_io = bio_data_dir(clone) == READ;
++
++ /*
++ * free the processed pages, even if
++ * it's only a partially completed write
++ */
++ if (!read_io)
++ crypt_free_buffer_pages(cc, clone, done);
++
++ /* keep going - not finished yet */
++ if (unlikely(clone->bi_size))
++ return 1;
++
++ if (!read_io)
++ goto out;
++
++ if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) {
++ error = -EIO;
++ goto out;
++ }
++
++ bio_put(clone);
++ io->post_process = 1;
++ kcryptd_queue_io(io);
++ return 0;
++
++out:
++ bio_put(clone);
++ dec_pending(io, error);
++ return error;
++}
++
++static void clone_init(struct crypt_io *io, struct bio *clone)
++{
++ struct crypt_config *cc = io->target->private;
++
++ clone->bi_private = io;
++ clone->bi_end_io = crypt_endio;
++ clone->bi_bdev = cc->dev->bdev;
++ clone->bi_rw = io->base_bio->bi_rw;
++}
++
++static void process_read(struct crypt_io *io)
++{
++ struct crypt_config *cc = io->target->private;
++ struct bio *base_bio = io->base_bio;
++ struct bio *clone;
++ sector_t sector = base_bio->bi_sector - io->target->begin;
++
++ atomic_inc(&io->pending);
++
++ /*
++ * The block layer might modify the bvec array, so always
++ * copy the required bvecs because we need the original
++ * one in order to decrypt the whole bio data *afterwards*.
++ */
++ clone = bio_alloc_bioset(GFP_NOIO, bio_segments(base_bio), cc->bs);
++ if (unlikely(!clone)) {
++ dec_pending(io, -ENOMEM);
++ return;
++ }
++
++ clone_init(io, clone);
++ clone->bi_destructor = dm_crypt_bio_destructor;
++ clone->bi_idx = 0;
++ clone->bi_vcnt = bio_segments(base_bio);
++ clone->bi_size = base_bio->bi_size;
++ clone->bi_sector = cc->start + sector;
++ memcpy(clone->bi_io_vec, bio_iovec(base_bio),
++ sizeof(struct bio_vec) * clone->bi_vcnt);
++
++ generic_make_request(clone);
++}
++
++static void process_write(struct crypt_io *io)
++{
++ struct crypt_config *cc = io->target->private;
++ struct bio *base_bio = io->base_bio;
++ struct bio *clone;
+ struct convert_context ctx;
+- int r;
++ unsigned remaining = base_bio->bi_size;
++ sector_t sector = base_bio->bi_sector - io->target->begin;
++ unsigned bvec_idx = 0;
++
++ atomic_inc(&io->pending);
++
++ crypt_convert_init(cc, &ctx, NULL, base_bio, sector, 1);
++
++ /*
++ * The allocated buffers can be smaller than the whole bio,
++ * so repeat the whole process until all the data can be handled.
++ */
++ while (remaining) {
++ clone = crypt_alloc_buffer(cc, base_bio->bi_size,
++ io->first_clone, &bvec_idx);
++ if (unlikely(!clone)) {
++ dec_pending(io, -ENOMEM);
++ return;
++ }
++
++ ctx.bio_out = clone;
++
++ if (unlikely(crypt_convert(cc, &ctx) < 0)) {
++ crypt_free_buffer_pages(cc, clone, clone->bi_size);
++ bio_put(clone);
++ dec_pending(io, -EIO);
++ return;
++ }
++
++ clone_init(io, clone);
++ clone->bi_sector = cc->start + sector;
+
+- crypt_convert_init(cc, &ctx, io->bio, io->bio,
+- io->bio->bi_sector - io->target->begin, 0);
+- r = crypt_convert(cc, &ctx);
++ if (!io->first_clone) {
++ /*
++ * hold a reference to the first clone, because it
++ * holds the bio_vec array and that can't be freed
++ * before all other clones are released
++ */
++ bio_get(clone);
++ io->first_clone = clone;
++ }
+
+- dec_pending(io, r);
++ remaining -= clone->bi_size;
++ sector += bio_sectors(clone);
++
++ /* prevent bio_put of first_clone */
++ if (remaining)
++ atomic_inc(&io->pending);
++
++ generic_make_request(clone);
++
++ /* out of memory -> run queues */
++ if (remaining)
++ congestion_wait(bio_data_dir(clone), HZ/100);
++ }
+ }
+
+-static void kcryptd_queue_io(struct crypt_io *io)
++static void process_read_endio(struct crypt_io *io)
+ {
+- INIT_WORK(&io->work, kcryptd_do_work, io);
+- queue_work(_kcryptd_workqueue, &io->work);
++ struct crypt_config *cc = io->target->private;
++ struct convert_context ctx;
++
++ crypt_convert_init(cc, &ctx, io->base_bio, io->base_bio,
++ io->base_bio->bi_sector - io->target->begin, 0);
++
++ dec_pending(io, crypt_convert(cc, &ctx));
++}
++
++static void kcryptd_do_work(void *data)
++{
++ struct crypt_io *io = data;
++
++ if (io->post_process)
++ process_read_endio(io);
++ else if (bio_data_dir(io->base_bio) == READ)
++ process_read(io);
++ else
++ process_write(io);
+ }
+
+ /*
+@@ -473,7 +641,7 @@ static int crypt_decode_key(u8 *key, cha
+
+ buffer[2] = '\0';
+
+- for(i = 0; i < size; i++) {
++ for (i = 0; i < size; i++) {
+ buffer[0] = *hex++;
+ buffer[1] = *hex++;
+
+@@ -496,13 +664,38 @@ static void crypt_encode_key(char *hex,
+ {
+ unsigned int i;
+
+- for(i = 0; i < size; i++) {
++ for (i = 0; i < size; i++) {
+ sprintf(hex, "%02x", *key);
+ hex += 2;
+ key++;
+ }
+ }
+
++static int crypt_set_key(struct crypt_config *cc, char *key)
++{
++ unsigned key_size = strlen(key) >> 1;
++
++ if (cc->key_size && cc->key_size != key_size)
++ return -EINVAL;
++
++ cc->key_size = key_size; /* initial settings */
++
++ if ((!key_size && strcmp(key, "-")) ||
++ (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
++ return -EINVAL;
++
++ set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
++
++ return 0;
++}
++
++static int crypt_wipe_key(struct crypt_config *cc)
++{
++ clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
++ memset(&cc->key, 0, cc->key_size * sizeof(u8));
++ return 0;
++}
++
+ /*
+ * Construct an encryption mapping:
+ * <cipher> <key> <iv_offset> <dev_path> <start>
+@@ -510,13 +703,12 @@ static void crypt_encode_key(char *hex,
+ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ {
+ struct crypt_config *cc;
+- struct crypto_tfm *tfm;
++ struct crypto_blkcipher *tfm;
+ char *tmp;
+ char *cipher;
+ char *chainmode;
+ char *ivmode;
+ char *ivopts;
+- unsigned int crypto_flags;
+ unsigned int key_size;
+ unsigned long long tmpll;
+
+@@ -536,16 +728,14 @@ static int crypt_ctr(struct dm_target *t
+
+ key_size = strlen(argv[1]) >> 1;
+
+- cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
++ cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+ if (cc == NULL) {
+ ti->error =
+ "Cannot allocate transparent encryption context";
+ return -ENOMEM;
+ }
+
+- cc->key_size = key_size;
+- if ((!key_size && strcmp(argv[1], "-") != 0) ||
+- (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
++ if (crypt_set_key(cc, argv[1])) {
+ ti->error = "Error decoding key";
+ goto bad1;
+ }
+@@ -556,31 +746,25 @@ static int crypt_ctr(struct dm_target *t
+ ivmode = "plain";
+ }
+
+- /* Choose crypto_flags according to chainmode */
+- if (strcmp(chainmode, "cbc") == 0)
+- crypto_flags = CRYPTO_TFM_MODE_CBC;
+- else if (strcmp(chainmode, "ecb") == 0)
+- crypto_flags = CRYPTO_TFM_MODE_ECB;
+- else {
+- ti->error = "Unknown chaining mode";
++ if (strcmp(chainmode, "ecb") && !ivmode) {
++ ti->error = "This chaining mode requires an IV mechanism";
+ goto bad1;
+ }
+
+- if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) {
+- ti->error = "This chaining mode requires an IV mechanism";
++ if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", chainmode,
++ cipher) >= CRYPTO_MAX_ALG_NAME) {
++ ti->error = "Chain mode + cipher name is too long";
+ goto bad1;
+ }
+
+- tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
+- if (!tfm) {
++ tfm = crypto_alloc_blkcipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
+ ti->error = "Error allocating crypto tfm";
+ goto bad1;
+ }
+- if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) {
+- ti->error = "Expected cipher algorithm";
+- goto bad2;
+- }
+
++ strcpy(cc->cipher, cipher);
++ strcpy(cc->chainmode, chainmode);
+ cc->tfm = tfm;
+
+ /*
+@@ -603,12 +787,12 @@ static int crypt_ctr(struct dm_target *t
+ cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0)
+ goto bad2;
+
+- if (tfm->crt_cipher.cit_decrypt_iv && tfm->crt_cipher.cit_encrypt_iv)
++ cc->iv_size = crypto_blkcipher_ivsize(tfm);
++ if (cc->iv_size)
+ /* at least a 64 bit sector number should fit in our buffer */
+- cc->iv_size = max(crypto_tfm_alg_ivsize(tfm),
++ cc->iv_size = max(cc->iv_size,
+ (unsigned int)(sizeof(u64) / sizeof(u8)));
+ else {
+- cc->iv_size = 0;
+ if (cc->iv_gen_ops) {
+ DMWARN("Selected cipher does not support IVs");
+ if (cc->iv_gen_ops->dtr)
+@@ -629,7 +813,13 @@ static int crypt_ctr(struct dm_target *t
+ goto bad4;
+ }
+
+- if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
++ cc->bs = bioset_create(MIN_IOS, MIN_IOS, 4);
++ if (!cc->bs) {
++ ti->error = "Cannot allocate crypt bioset";
++ goto bad_bs;
++ }
++
++ if (crypto_blkcipher_setkey(tfm, cc->key, key_size) < 0) {
+ ti->error = "Error setting key";
+ goto bad5;
+ }
+@@ -668,6 +858,8 @@ static int crypt_ctr(struct dm_target *t
+ return 0;
+
+ bad5:
++ bioset_free(cc->bs);
++bad_bs:
+ mempool_destroy(cc->page_pool);
+ bad4:
+ mempool_destroy(cc->io_pool);
+@@ -675,7 +867,7 @@ bad3:
+ if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
+ cc->iv_gen_ops->dtr(cc);
+ bad2:
+- crypto_free_tfm(tfm);
++ crypto_free_blkcipher(tfm);
+ bad1:
+ /* Must zero key material before freeing */
+ memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
+@@ -687,13 +879,14 @@ static void crypt_dtr(struct dm_target *
+ {
+ struct crypt_config *cc = (struct crypt_config *) ti->private;
+
++ bioset_free(cc->bs);
+ mempool_destroy(cc->page_pool);
+ mempool_destroy(cc->io_pool);
+
+ kfree(cc->iv_mode);
+ if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
+ cc->iv_gen_ops->dtr(cc);
+- crypto_free_tfm(cc->tfm);
++ crypto_free_blkcipher(cc->tfm);
+ dm_put_device(ti, cc->dev);
+
+ /* Must zero key material before freeing */
+@@ -701,155 +894,27 @@ static void crypt_dtr(struct dm_target *
+ kfree(cc);
+ }
+
+-static int crypt_endio(struct bio *bio, unsigned int done, int error)
+-{
+- struct crypt_io *io = (struct crypt_io *) bio->bi_private;
+- struct crypt_config *cc = (struct crypt_config *) io->target->private;
+-
+- if (bio_data_dir(bio) == WRITE) {
+- /*
+- * free the processed pages, even if
+- * it's only a partially completed write
+- */
+- crypt_free_buffer_pages(cc, bio, done);
+- }
+-
+- if (bio->bi_size)
+- return 1;
+-
+- bio_put(bio);
+-
+- /*
+- * successful reads are decrypted by the worker thread
+- */
+- if ((bio_data_dir(bio) == READ)
+- && bio_flagged(bio, BIO_UPTODATE)) {
+- kcryptd_queue_io(io);
+- return 0;
+- }
+-
+- dec_pending(io, error);
+- return error;
+-}
+-
+-static inline struct bio *
+-crypt_clone(struct crypt_config *cc, struct crypt_io *io, struct bio *bio,
+- sector_t sector, unsigned int *bvec_idx,
+- struct convert_context *ctx)
+-{
+- struct bio *clone;
+-
+- if (bio_data_dir(bio) == WRITE) {
+- clone = crypt_alloc_buffer(cc, bio->bi_size,
+- io->first_clone, bvec_idx);
+- if (clone) {
+- ctx->bio_out = clone;
+- if (crypt_convert(cc, ctx) < 0) {
+- crypt_free_buffer_pages(cc, clone,
+- clone->bi_size);
+- bio_put(clone);
+- return NULL;
+- }
+- }
+- } else {
+- /*
+- * The block layer might modify the bvec array, so always
+- * copy the required bvecs because we need the original
+- * one in order to decrypt the whole bio data *afterwards*.
+- */
+- clone = bio_alloc(GFP_NOIO, bio_segments(bio));
+- if (clone) {
+- clone->bi_idx = 0;
+- clone->bi_vcnt = bio_segments(bio);
+- clone->bi_size = bio->bi_size;
+- memcpy(clone->bi_io_vec, bio_iovec(bio),
+- sizeof(struct bio_vec) * clone->bi_vcnt);
+- }
+- }
+-
+- if (!clone)
+- return NULL;
+-
+- clone->bi_private = io;
+- clone->bi_end_io = crypt_endio;
+- clone->bi_bdev = cc->dev->bdev;
+- clone->bi_sector = cc->start + sector;
+- clone->bi_rw = bio->bi_rw;
+-
+- return clone;
+-}
+-
+ static int crypt_map(struct dm_target *ti, struct bio *bio,
+ union map_info *map_context)
+ {
+- struct crypt_config *cc = (struct crypt_config *) ti->private;
+- struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
+- struct convert_context ctx;
+- struct bio *clone;
+- unsigned int remaining = bio->bi_size;
+- sector_t sector = bio->bi_sector - ti->begin;
+- unsigned int bvec_idx = 0;
++ struct crypt_config *cc = ti->private;
++ struct crypt_io *io;
+
++ io = mempool_alloc(cc->io_pool, GFP_NOIO);
+ io->target = ti;
+- io->bio = bio;
++ io->base_bio = bio;
+ io->first_clone = NULL;
+- io->error = 0;
+- atomic_set(&io->pending, 1); /* hold a reference */
+-
+- if (bio_data_dir(bio) == WRITE)
+- crypt_convert_init(cc, &ctx, NULL, bio, sector, 1);
++ io->error = io->post_process = 0;
++ atomic_set(&io->pending, 0);
++ kcryptd_queue_io(io);
+
+- /*
+- * The allocated buffers can be smaller than the whole bio,
+- * so repeat the whole process until all the data can be handled.
+- */
+- while (remaining) {
+- clone = crypt_clone(cc, io, bio, sector, &bvec_idx, &ctx);
+- if (!clone)
+- goto cleanup;
+-
+- if (!io->first_clone) {
+- /*
+- * hold a reference to the first clone, because it
+- * holds the bio_vec array and that can't be freed
+- * before all other clones are released
+- */
+- bio_get(clone);
+- io->first_clone = clone;
+- }
+- atomic_inc(&io->pending);
+-
+- remaining -= clone->bi_size;
+- sector += bio_sectors(clone);
+-
+- generic_make_request(clone);
+-
+- /* out of memory -> run queues */
+- if (remaining)
+- blk_congestion_wait(bio_data_dir(clone), HZ/100);
+- }
+-
+- /* drop reference, clones could have returned before we reach this */
+- dec_pending(io, 0);
+ return 0;
+-
+-cleanup:
+- if (io->first_clone) {
+- dec_pending(io, -ENOMEM);
+- return 0;
+- }
+-
+- /* if no bio has been dispatched yet, we can directly return the error */
+- mempool_free(io, cc->io_pool);
+- return -ENOMEM;
+ }
+
+ static int crypt_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned int maxlen)
+ {
+ struct crypt_config *cc = (struct crypt_config *) ti->private;
+- const char *cipher;
+- const char *chainmode = NULL;
+ unsigned int sz = 0;
+
+ switch (type) {
+@@ -858,23 +923,11 @@ static int crypt_status(struct dm_target
+ break;
+
+ case STATUSTYPE_TABLE:
+- cipher = crypto_tfm_alg_name(cc->tfm);
+-
+- switch(cc->tfm->crt_cipher.cit_mode) {
+- case CRYPTO_TFM_MODE_CBC:
+- chainmode = "cbc";
+- break;
+- case CRYPTO_TFM_MODE_ECB:
+- chainmode = "ecb";
+- break;
+- default:
+- BUG();
+- }
+-
+ if (cc->iv_mode)
+- DMEMIT("%s-%s-%s ", cipher, chainmode, cc->iv_mode);
++ DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode,
++ cc->iv_mode);
+ else
+- DMEMIT("%s-%s ", cipher, chainmode);
++ DMEMIT("%s-%s ", cc->cipher, cc->chainmode);
+
+ if (cc->key_size > 0) {
+ if ((maxlen - sz) < ((cc->key_size << 1) + 1))
+@@ -895,14 +948,71 @@ static int crypt_status(struct dm_target
+ return 0;
+ }
+
++static void crypt_postsuspend(struct dm_target *ti)
++{
++ struct crypt_config *cc = ti->private;
++
++ set_bit(DM_CRYPT_SUSPENDED, &cc->flags);
++}
++
++static int crypt_preresume(struct dm_target *ti)
++{
++ struct crypt_config *cc = ti->private;
++
++ if (!test_bit(DM_CRYPT_KEY_VALID, &cc->flags)) {
++ DMERR("aborting resume - crypt key is not set.");
++ return -EAGAIN;
++ }
++
++ return 0;
++}
++
++static void crypt_resume(struct dm_target *ti)
++{
++ struct crypt_config *cc = ti->private;
++
++ clear_bit(DM_CRYPT_SUSPENDED, &cc->flags);
++}
++
++/* Message interface
++ * key set <key>
++ * key wipe
++ */
++static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
++{
++ struct crypt_config *cc = ti->private;
++
++ if (argc < 2)
++ goto error;
++
++ if (!strnicmp(argv[0], MESG_STR("key"))) {
++ if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) {
++ DMWARN("not suspended during key manipulation.");
++ return -EINVAL;
++ }
++ if (argc == 3 && !strnicmp(argv[1], MESG_STR("set")))
++ return crypt_set_key(cc, argv[2]);
++ if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe")))
++ return crypt_wipe_key(cc);
++ }
++
++error:
++ DMWARN("unrecognised message received.");
++ return -EINVAL;
++}
++
+ static struct target_type crypt_target = {
+ .name = "crypt",
+- .version= {1, 1, 0},
++ .version= {1, 3, 0},
+ .module = THIS_MODULE,
+ .ctr = crypt_ctr,
+ .dtr = crypt_dtr,
+ .map = crypt_map,
+ .status = crypt_status,
++ .postsuspend = crypt_postsuspend,
++ .preresume = crypt_preresume,
++ .resume = crypt_resume,
++ .message = crypt_message,
+ };
+
+ static int __init dm_crypt_init(void)
+diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
+index 2a374cc..2b2d45d 100644
+--- a/drivers/md/dm-emc.c
++++ b/drivers/md/dm-emc.c
+@@ -126,7 +126,8 @@ static struct request *get_failover_req(
+ memset(&rq->cmd, 0, BLK_MAX_CDB);
+
+ rq->timeout = EMC_FAILOVER_TIMEOUT;
+- rq->flags |= (REQ_BLOCK_PC | REQ_FAILFAST | REQ_NOMERGE);
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
++ rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
+
+ return rq;
+ }
+diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
+index d12379b..99cdffa 100644
+--- a/drivers/md/dm-exception-store.c
++++ b/drivers/md/dm-exception-store.c
+@@ -17,6 +17,7 @@
+ #include <linux/slab.h>
+
+ #define DM_MSG_PREFIX "snapshots"
++#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */
+
+ /*-----------------------------------------------------------------
+ * Persistent snapshots, by persistent we mean that the snapshot
+@@ -150,6 +151,7 @@ static int alloc_area(struct pstore *ps)
+ static void free_area(struct pstore *ps)
+ {
+ vfree(ps->area);
++ ps->area = NULL;
+ }
+
+ /*
+@@ -198,48 +200,79 @@ static int read_header(struct pstore *ps
+ int r;
+ struct disk_header *dh;
+ chunk_t chunk_size;
++ int chunk_size_supplied = 1;
+
+- r = chunk_io(ps, 0, READ);
++ /*
++ * Use default chunk size (or hardsect_size, if larger) if none supplied
++ */
++ if (!ps->snap->chunk_size) {
++ ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
++ bdev_hardsect_size(ps->snap->cow->bdev) >> 9);
++ ps->snap->chunk_mask = ps->snap->chunk_size - 1;
++ ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1;
++ chunk_size_supplied = 0;
++ }
++
++ r = dm_io_get(sectors_to_pages(ps->snap->chunk_size));
+ if (r)
+ return r;
+
++ r = alloc_area(ps);
++ if (r)
++ goto bad1;
++
++ r = chunk_io(ps, 0, READ);
++ if (r)
++ goto bad2;
++
+ dh = (struct disk_header *) ps->area;
+
+ if (le32_to_cpu(dh->magic) == 0) {
+ *new_snapshot = 1;
++ return 0;
++ }
+
+- } else if (le32_to_cpu(dh->magic) == SNAP_MAGIC) {
+- *new_snapshot = 0;
+- ps->valid = le32_to_cpu(dh->valid);
+- ps->version = le32_to_cpu(dh->version);
+- chunk_size = le32_to_cpu(dh->chunk_size);
+- if (ps->snap->chunk_size != chunk_size) {
+- DMWARN("chunk size %llu in device metadata overrides "
+- "table chunk size of %llu.",
+- (unsigned long long)chunk_size,
+- (unsigned long long)ps->snap->chunk_size);
+-
+- /* We had a bogus chunk_size. Fix stuff up. */
+- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+- free_area(ps);
+-
+- ps->snap->chunk_size = chunk_size;
+- ps->snap->chunk_mask = chunk_size - 1;
+- ps->snap->chunk_shift = ffs(chunk_size) - 1;
+-
+- r = alloc_area(ps);
+- if (r)
+- return r;
+-
+- r = dm_io_get(sectors_to_pages(chunk_size));
+- if (r)
+- return r;
+- }
+- } else {
+- DMWARN("Invalid/corrupt snapshot");
++ if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
++ DMWARN("Invalid or corrupt snapshot");
+ r = -ENXIO;
++ goto bad2;
+ }
+
++ *new_snapshot = 0;
++ ps->valid = le32_to_cpu(dh->valid);
++ ps->version = le32_to_cpu(dh->version);
++ chunk_size = le32_to_cpu(dh->chunk_size);
++
++ if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size)
++ return 0;
++
++ DMWARN("chunk size %llu in device metadata overrides "
++ "table chunk size of %llu.",
++ (unsigned long long)chunk_size,
++ (unsigned long long)ps->snap->chunk_size);
++
++ /* We had a bogus chunk_size. Fix stuff up. */
++ dm_io_put(sectors_to_pages(ps->snap->chunk_size));
++ free_area(ps);
++
++ ps->snap->chunk_size = chunk_size;
++ ps->snap->chunk_mask = chunk_size - 1;
++ ps->snap->chunk_shift = ffs(chunk_size) - 1;
++
++ r = dm_io_get(sectors_to_pages(chunk_size));
++ if (r)
++ return r;
++
++ r = alloc_area(ps);
++ if (r)
++ goto bad1;
++
++ return 0;
++
++bad2:
++ free_area(ps);
++bad1:
++ dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+ return r;
+ }
+
+@@ -263,42 +296,29 @@ static int write_header(struct pstore *p
+ */
+ static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
+ {
+- if (index >= ps->exceptions_per_area)
+- return NULL;
++ BUG_ON(index >= ps->exceptions_per_area);
+
+ return ((struct disk_exception *) ps->area) + index;
+ }
+
+-static int read_exception(struct pstore *ps,
+- uint32_t index, struct disk_exception *result)
++static void read_exception(struct pstore *ps,
++ uint32_t index, struct disk_exception *result)
+ {
+- struct disk_exception *e;
+-
+- e = get_exception(ps, index);
+- if (!e)
+- return -EINVAL;
++ struct disk_exception *e = get_exception(ps, index);
+
+ /* copy it */
+ result->old_chunk = le64_to_cpu(e->old_chunk);
+ result->new_chunk = le64_to_cpu(e->new_chunk);
+-
+- return 0;
+ }
+
+-static int write_exception(struct pstore *ps,
+- uint32_t index, struct disk_exception *de)
++static void write_exception(struct pstore *ps,
++ uint32_t index, struct disk_exception *de)
+ {
+- struct disk_exception *e;
+-
+- e = get_exception(ps, index);
+- if (!e)
+- return -EINVAL;
++ struct disk_exception *e = get_exception(ps, index);
+
+ /* copy it */
+ e->old_chunk = cpu_to_le64(de->old_chunk);
+ e->new_chunk = cpu_to_le64(de->new_chunk);
+-
+- return 0;
+ }
+
+ /*
+@@ -316,10 +336,7 @@ static int insert_exceptions(struct psto
+ *full = 1;
+
+ for (i = 0; i < ps->exceptions_per_area; i++) {
+- r = read_exception(ps, i, &de);
+-
+- if (r)
+- return r;
++ read_exception(ps, i, &de);
+
+ /*
+ * If the new_chunk is pointing at the start of
+@@ -519,6 +536,16 @@ static void persistent_commit(struct exc
+ if (r)
+ ps->valid = 0;
+
++ /*
++ * Have we completely filled the current area ?
++ */
++ if (ps->current_committed == ps->exceptions_per_area) {
++ ps->current_committed = 0;
++ r = zero_area(ps, ps->current_area + 1);
++ if (r)
++ ps->valid = 0;
++ }
++
+ for (i = 0; i < ps->callback_count; i++) {
+ cb = ps->callbacks + i;
+ cb->callback(cb->context, r == 0 ? 1 : 0);
+@@ -526,16 +553,6 @@ static void persistent_commit(struct exc
+
+ ps->callback_count = 0;
+ }
+-
+- /*
+- * Have we completely filled the current area ?
+- */
+- if (ps->current_committed == ps->exceptions_per_area) {
+- ps->current_committed = 0;
+- r = zero_area(ps, ps->current_area + 1);
+- if (r)
+- ps->valid = 0;
+- }
+ }
+
+ static void persistent_drop(struct exception_store *store)
+@@ -547,32 +564,22 @@ static void persistent_drop(struct excep
+ DMWARN("write header failed");
+ }
+
+-int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
++int dm_create_persistent(struct exception_store *store)
+ {
+- int r;
+ struct pstore *ps;
+
+- r = dm_io_get(sectors_to_pages(chunk_size));
+- if (r)
+- return r;
+-
+ /* allocate the pstore */
+ ps = kmalloc(sizeof(*ps), GFP_KERNEL);
+- if (!ps) {
+- r = -ENOMEM;
+- goto bad;
+- }
++ if (!ps)
++ return -ENOMEM;
+
+ ps->snap = store->snap;
+ ps->valid = 1;
+ ps->version = SNAPSHOT_DISK_VERSION;
++ ps->area = NULL;
+ ps->next_free = 2; /* skipping the header and first area */
+ ps->current_committed = 0;
+
+- r = alloc_area(ps);
+- if (r)
+- goto bad;
+-
+ ps->callback_count = 0;
+ atomic_set(&ps->pending_count, 0);
+ ps->callbacks = NULL;
+@@ -586,13 +593,6 @@ int dm_create_persistent(struct exceptio
+ store->context = ps;
+
+ return 0;
+-
+- bad:
+- dm_io_put(sectors_to_pages(chunk_size));
+- if (ps && ps->area)
+- free_area(ps);
+- kfree(ps);
+- return r;
+ }
+
+ /*-----------------------------------------------------------------
+@@ -642,18 +642,16 @@ static void transient_fraction_full(stru
+ *denominator = get_dev_size(store->snap->cow->bdev);
+ }
+
+-int dm_create_transient(struct exception_store *store,
+- struct dm_snapshot *s, int blocksize)
++int dm_create_transient(struct exception_store *store)
+ {
+ struct transient_c *tc;
+
+- memset(store, 0, sizeof(*store));
+ store->destroy = transient_destroy;
+ store->read_metadata = transient_read_metadata;
+ store->prepare_exception = transient_prepare;
+ store->commit_exception = transient_commit;
++ store->drop_snapshot = NULL;
+ store->fraction_full = transient_fraction_full;
+- store->snap = s;
+
+ tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
+ if (!tc)
+diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
+index 47b3c62..0023490 100644
+--- a/drivers/md/dm-linear.c
++++ b/drivers/md/dm-linear.c
+@@ -98,14 +98,31 @@ static int linear_status(struct dm_targe
+ return 0;
+ }
+
++static int linear_ioctl(struct dm_target *ti, struct inode *inode,
++ struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct linear_c *lc = (struct linear_c *) ti->private;
++ struct block_device *bdev = lc->dev->bdev;
++ struct file fake_file = {};
++ struct dentry fake_dentry = {};
++
++ fake_file.f_mode = lc->dev->mode;
++ fake_file.f_dentry = &fake_dentry;
++ fake_dentry.d_inode = bdev->bd_inode;
++
++ return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg);
++}
++
+ static struct target_type linear_target = {
+ .name = "linear",
+- .version= {1, 0, 1},
++ .version= {1, 0, 2},
+ .module = THIS_MODULE,
+ .ctr = linear_ctr,
+ .dtr = linear_dtr,
+ .map = linear_map,
+ .status = linear_status,
++ .ioctl = linear_ioctl,
+ };
+
+ int __init dm_linear_init(void)
+diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
+index 93f701e..d754e0b 100644
+--- a/drivers/md/dm-mpath.c
++++ b/drivers/md/dm-mpath.c
+@@ -114,12 +114,10 @@ static void trigger_event(void *data);
+
+ static struct pgpath *alloc_pgpath(void)
+ {
+- struct pgpath *pgpath = kmalloc(sizeof(*pgpath), GFP_KERNEL);
++ struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);
+
+- if (pgpath) {
+- memset(pgpath, 0, sizeof(*pgpath));
++ if (pgpath)
+ pgpath->path.is_active = 1;
+- }
+
+ return pgpath;
+ }
+@@ -133,12 +131,10 @@ static struct priority_group *alloc_prio
+ {
+ struct priority_group *pg;
+
+- pg = kmalloc(sizeof(*pg), GFP_KERNEL);
+- if (!pg)
+- return NULL;
++ pg = kzalloc(sizeof(*pg), GFP_KERNEL);
+
+- memset(pg, 0, sizeof(*pg));
+- INIT_LIST_HEAD(&pg->pgpaths);
++ if (pg)
++ INIT_LIST_HEAD(&pg->pgpaths);
+
+ return pg;
+ }
+@@ -168,13 +164,12 @@ static void free_priority_group(struct p
+ kfree(pg);
+ }
+
+-static struct multipath *alloc_multipath(void)
++static struct multipath *alloc_multipath(struct dm_target *ti)
+ {
+ struct multipath *m;
+
+- m = kmalloc(sizeof(*m), GFP_KERNEL);
++ m = kzalloc(sizeof(*m), GFP_KERNEL);
+ if (m) {
+- memset(m, 0, sizeof(*m));
+ INIT_LIST_HEAD(&m->priority_groups);
+ spin_lock_init(&m->lock);
+ m->queue_io = 1;
+@@ -185,6 +180,8 @@ static struct multipath *alloc_multipath
+ kfree(m);
+ return NULL;
+ }
++ m->ti = ti;
++ ti->private = m;
+ }
+
+ return m;
+@@ -557,8 +554,7 @@ static struct pgpath *parse_path(struct
+ }
+
+ static struct priority_group *parse_priority_group(struct arg_set *as,
+- struct multipath *m,
+- struct dm_target *ti)
++ struct multipath *m)
+ {
+ static struct param _params[] = {
+ {1, 1024, "invalid number of paths"},
+@@ -568,6 +564,7 @@ static struct priority_group *parse_prio
+ int r;
+ unsigned i, nr_selector_args, nr_params;
+ struct priority_group *pg;
++ struct dm_target *ti = m->ti;
+
+ if (as->argc < 2) {
+ as->argc = 0;
+@@ -624,12 +621,12 @@ static struct priority_group *parse_prio
+ return NULL;
+ }
+
+-static int parse_hw_handler(struct arg_set *as, struct multipath *m,
+- struct dm_target *ti)
++static int parse_hw_handler(struct arg_set *as, struct multipath *m)
+ {
+ int r;
+ struct hw_handler_type *hwht;
+ unsigned hw_argc;
++ struct dm_target *ti = m->ti;
+
+ static struct param _params[] = {
+ {0, 1024, "invalid number of hardware handler args"},
+@@ -661,11 +658,11 @@ static int parse_hw_handler(struct arg_s
+ return 0;
+ }
+
+-static int parse_features(struct arg_set *as, struct multipath *m,
+- struct dm_target *ti)
++static int parse_features(struct arg_set *as, struct multipath *m)
+ {
+ int r;
+ unsigned argc;
++ struct dm_target *ti = m->ti;
+
+ static struct param _params[] = {
+ {0, 1, "invalid number of feature args"},
+@@ -704,19 +701,17 @@ static int multipath_ctr(struct dm_targe
+ as.argc = argc;
+ as.argv = argv;
+
+- m = alloc_multipath();
++ m = alloc_multipath(ti);
+ if (!m) {
+ ti->error = "can't allocate multipath";
+ return -EINVAL;
+ }
+
+- m->ti = ti;
+-
+- r = parse_features(&as, m, ti);
++ r = parse_features(&as, m);
+ if (r)
+ goto bad;
+
+- r = parse_hw_handler(&as, m, ti);
++ r = parse_hw_handler(&as, m);
+ if (r)
+ goto bad;
+
+@@ -732,7 +727,7 @@ static int multipath_ctr(struct dm_targe
+ while (as.argc) {
+ struct priority_group *pg;
+
+- pg = parse_priority_group(&as, m, ti);
++ pg = parse_priority_group(&as, m);
+ if (!pg) {
+ r = -EINVAL;
+ goto bad;
+@@ -752,8 +747,6 @@ static int multipath_ctr(struct dm_targe
+ goto bad;
+ }
+
+- ti->private = m;
+-
+ return 0;
+
+ bad:
+@@ -1266,12 +1259,47 @@ error:
+ return -EINVAL;
+ }
+
++static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
++ struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct multipath *m = (struct multipath *) ti->private;
++ struct block_device *bdev = NULL;
++ unsigned long flags;
++ struct file fake_file = {};
++ struct dentry fake_dentry = {};
++ int r = 0;
++
++ fake_file.f_dentry = &fake_dentry;
++
++ spin_lock_irqsave(&m->lock, flags);
++
++ if (!m->current_pgpath)
++ __choose_pgpath(m);
++
++ if (m->current_pgpath) {
++ bdev = m->current_pgpath->path.dev->bdev;
++ fake_dentry.d_inode = bdev->bd_inode;
++ fake_file.f_mode = m->current_pgpath->path.dev->mode;
++ }
++
++ if (m->queue_io)
++ r = -EAGAIN;
++ else if (!bdev)
++ r = -EIO;
++
++ spin_unlock_irqrestore(&m->lock, flags);
++
++ return r ? : blkdev_driver_ioctl(bdev->bd_inode, &fake_file,
++ bdev->bd_disk, cmd, arg);
++}
++
+ /*-----------------------------------------------------------------
+ * Module setup
+ *---------------------------------------------------------------*/
+ static struct target_type multipath_target = {
+ .name = "multipath",
+- .version = {1, 0, 4},
++ .version = {1, 0, 5},
+ .module = THIS_MODULE,
+ .ctr = multipath_ctr,
+ .dtr = multipath_dtr,
+@@ -1281,6 +1309,7 @@ static struct target_type multipath_targ
+ .resume = multipath_resume,
+ .status = multipath_status,
+ .message = multipath_message,
++ .ioctl = multipath_ioctl,
+ };
+
+ static int __init dm_multipath_init(void)
+diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
+index c54de98..659224c 100644
+--- a/drivers/md/dm-raid1.c
++++ b/drivers/md/dm-raid1.c
+@@ -1213,9 +1213,9 @@ static int mirror_status(struct dm_targe
+ break;
+
+ case STATUSTYPE_TABLE:
+- DMEMIT("%d ", ms->nr_mirrors);
++ DMEMIT("%d", ms->nr_mirrors);
+ for (m = 0; m < ms->nr_mirrors; m++)
+- DMEMIT("%s %llu ", ms->mirror[m].dev->name,
++ DMEMIT(" %s %llu", ms->mirror[m].dev->name,
+ (unsigned long long)ms->mirror[m].offset);
+ }
+
+diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
+index 1d0fafd..5281e00 100644
+--- a/drivers/md/dm-snap.c
++++ b/drivers/md/dm-snap.c
+@@ -39,6 +39,9 @@
+ */
+ #define SNAPSHOT_PAGES 256
+
++struct workqueue_struct *ksnapd;
++static void flush_queued_bios(void *data);
++
+ struct pending_exception {
+ struct exception e;
+
+@@ -56,7 +59,7 @@ struct pending_exception {
+
+ /*
+ * The primary pending_exception is the one that holds
+- * the sibling_count and the list of origin_bios for a
++ * the ref_count and the list of origin_bios for a
+ * group of pending_exceptions. It is always last to get freed.
+ * These fields get set up when writing to the origin.
+ */
+@@ -69,7 +72,7 @@ struct pending_exception {
+ * the sibling concerned and not pe->primary_pe->snap->lock unless
+ * they are the same.
+ */
+- atomic_t sibling_count;
++ atomic_t ref_count;
+
+ /* Pointer back to snapshot context */
+ struct dm_snapshot *snap;
+@@ -387,15 +390,46 @@ static inline ulong round_up(ulong n, ul
+ return (n + size) & ~size;
+ }
+
+-static void read_snapshot_metadata(struct dm_snapshot *s)
++static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg,
++ char **error)
+ {
+- if (s->store.read_metadata(&s->store)) {
+- down_write(&s->lock);
+- s->valid = 0;
+- up_write(&s->lock);
++ unsigned long chunk_size;
++ char *value;
++
++ chunk_size = simple_strtoul(chunk_size_arg, &value, 10);
++ if (*chunk_size_arg == '\0' || *value != '\0') {
++ *error = "Invalid chunk size";
++ return -EINVAL;
++ }
++
++ if (!chunk_size) {
++ s->chunk_size = s->chunk_mask = s->chunk_shift = 0;
++ return 0;
++ }
++
++ /*
++ * Chunk size must be multiple of page size. Silently
++ * round up if it's not.
++ */
++ chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
++
++ /* Check chunk_size is a power of 2 */
++ if (chunk_size & (chunk_size - 1)) {
++ *error = "Chunk size is not a power of 2";
++ return -EINVAL;
++ }
+
+- dm_table_event(s->table);
++ /* Validate the chunk size against the device block size */
++ if (chunk_size % (bdev_hardsect_size(s->cow->bdev) >> 9)) {
++ *error = "Chunk size is not a multiple of device blocksize";
++ return -EINVAL;
+ }
++
++ s->chunk_size = chunk_size;
++ s->chunk_mask = chunk_size - 1;
++ s->chunk_shift = ffs(chunk_size) - 1;
++
++ return 0;
+ }
+
+ /*
+@@ -404,15 +438,12 @@ static void read_snapshot_metadata(struc
+ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ {
+ struct dm_snapshot *s;
+- unsigned long chunk_size;
+ int r = -EINVAL;
+ char persistent;
+ char *origin_path;
+ char *cow_path;
+- char *value;
+- int blocksize;
+
+- if (argc < 4) {
++ if (argc != 4) {
+ ti->error = "requires exactly 4 arguments";
+ r = -EINVAL;
+ goto bad1;
+@@ -428,13 +459,6 @@ static int snapshot_ctr(struct dm_target
+ goto bad1;
+ }
+
+- chunk_size = simple_strtoul(argv[3], &value, 10);
+- if (chunk_size == 0 || value == NULL) {
+- ti->error = "Invalid chunk size";
+- r = -EINVAL;
+- goto bad1;
+- }
+-
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL) {
+ ti->error = "Cannot allocate snapshot context private "
+@@ -457,36 +481,17 @@ static int snapshot_ctr(struct dm_target
+ goto bad2;
+ }
+
+- /*
+- * Chunk size must be multiple of page size. Silently
+- * round up if it's not.
+- */
+- chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
+-
+- /* Validate the chunk size against the device block size */
+- blocksize = s->cow->bdev->bd_disk->queue->hardsect_size;
+- if (chunk_size % (blocksize >> 9)) {
+- ti->error = "Chunk size is not a multiple of device blocksize";
+- r = -EINVAL;
+- goto bad3;
+- }
+-
+- /* Check chunk_size is a power of 2 */
+- if (chunk_size & (chunk_size - 1)) {
+- ti->error = "Chunk size is not a power of 2";
+- r = -EINVAL;
++ r = set_chunk_size(s, argv[3], &ti->error);
++ if (r)
+ goto bad3;
+- }
+
+- s->chunk_size = chunk_size;
+- s->chunk_mask = chunk_size - 1;
+ s->type = persistent;
+- s->chunk_shift = ffs(chunk_size) - 1;
+
+ s->valid = 1;
+ s->active = 0;
+ s->last_percent = 0;
+ init_rwsem(&s->lock);
++ spin_lock_init(&s->pe_lock);
+ s->table = ti->table;
+
+ /* Allocate hash table for COW data */
+@@ -496,16 +501,12 @@ static int snapshot_ctr(struct dm_target
+ goto bad3;
+ }
+
+- /*
+- * Check the persistent flag - done here because we need the iobuf
+- * to check the LV header
+- */
+ s->store.snap = s;
+
+ if (persistent == 'P')
+- r = dm_create_persistent(&s->store, chunk_size);
++ r = dm_create_persistent(&s->store);
+ else
+- r = dm_create_transient(&s->store, s, blocksize);
++ r = dm_create_transient(&s->store);
+
+ if (r) {
+ ti->error = "Couldn't create exception store";
+@@ -520,7 +521,14 @@ static int snapshot_ctr(struct dm_target
+ }
+
+ /* Metadata must only be loaded into one table at once */
+- read_snapshot_metadata(s);
++ r = s->store.read_metadata(&s->store);
++ if (r) {
++ ti->error = "Failed to read snapshot metadata";
++ goto bad6;
++ }
++
++ bio_list_init(&s->queued_bios);
++ INIT_WORK(&s->queued_bios_work, flush_queued_bios, s);
+
+ /* Add snapshot to the list of snapshots for this origin */
+ /* Exceptions aren't triggered till snapshot_resume() is called */
+@@ -560,6 +568,8 @@ static void snapshot_dtr(struct dm_targe
+ {
+ struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+
++ flush_workqueue(ksnapd);
++
+ /* Prevent further origin writes from using this snapshot. */
+ /* After this returns there can be no new kcopyd jobs. */
+ unregister_snapshot(s);
+@@ -593,6 +603,19 @@ static void flush_bios(struct bio *bio)
+ }
+ }
+
++static void flush_queued_bios(void *data)
++{
++ struct dm_snapshot *s = (struct dm_snapshot *) data;
++ struct bio *queued_bios;
++ unsigned long flags;
++
++ spin_lock_irqsave(&s->pe_lock, flags);
++ queued_bios = bio_list_get(&s->queued_bios);
++ spin_unlock_irqrestore(&s->pe_lock, flags);
++
++ flush_bios(queued_bios);
++}
++
+ /*
+ * Error a list of buffers.
+ */
+@@ -608,28 +631,7 @@ static void error_bios(struct bio *bio)
+ }
+ }
+
+-static inline void error_snapshot_bios(struct pending_exception *pe)
+-{
+- error_bios(bio_list_get(&pe->snapshot_bios));
+-}
+-
+-static struct bio *__flush_bios(struct pending_exception *pe)
+-{
+- /*
+- * If this pe is involved in a write to the origin and
+- * it is the last sibling to complete then release
+- * the bios for the original write to the origin.
+- */
+-
+- if (pe->primary_pe &&
+- atomic_dec_and_test(&pe->primary_pe->sibling_count))
+- return bio_list_get(&pe->primary_pe->origin_bios);
+-
+- return NULL;
+-}
+-
+-static void __invalidate_snapshot(struct dm_snapshot *s,
+- struct pending_exception *pe, int err)
++static void __invalidate_snapshot(struct dm_snapshot *s, int err)
+ {
+ if (!s->valid)
+ return;
+@@ -639,9 +641,6 @@ static void __invalidate_snapshot(struct
+ else if (err == -ENOMEM)
+ DMERR("Invalidating snapshot: Unable to allocate exception.");
+
+- if (pe)
+- remove_exception(&pe->e);
+-
+ if (s->store.drop_snapshot)
+ s->store.drop_snapshot(&s->store);
+
+@@ -650,78 +649,95 @@ static void __invalidate_snapshot(struct
+ dm_table_event(s->table);
+ }
+
++static void get_pending_exception(struct pending_exception *pe)
++{
++ atomic_inc(&pe->ref_count);
++}
++
++static struct bio *put_pending_exception(struct pending_exception *pe)
++{
++ struct pending_exception *primary_pe;
++ struct bio *origin_bios = NULL;
++
++ primary_pe = pe->primary_pe;
++
++ /*
++ * If this pe is involved in a write to the origin and
++ * it is the last sibling to complete then release
++ * the bios for the original write to the origin.
++ */
++ if (primary_pe &&
++ atomic_dec_and_test(&primary_pe->ref_count))
++ origin_bios = bio_list_get(&primary_pe->origin_bios);
++
++ /*
++ * Free the pe if it's not linked to an origin write or if
++ * it's not itself a primary pe.
++ */
++ if (!primary_pe || primary_pe != pe)
++ free_pending_exception(pe);
++
++ /*
++ * Free the primary pe if nothing references it.
++ */
++ if (primary_pe && !atomic_read(&primary_pe->ref_count))
++ free_pending_exception(primary_pe);
++
++ return origin_bios;
++}
++
+ static void pending_complete(struct pending_exception *pe, int success)
+ {
+ struct exception *e;
+- struct pending_exception *primary_pe;
+ struct dm_snapshot *s = pe->snap;
+- struct bio *flush = NULL;
++ struct bio *origin_bios = NULL;
++ struct bio *snapshot_bios = NULL;
++ int error = 0;
+
+ if (!success) {
+ /* Read/write error - snapshot is unusable */
+ down_write(&s->lock);
+- __invalidate_snapshot(s, pe, -EIO);
+- flush = __flush_bios(pe);
+- up_write(&s->lock);
+-
+- error_snapshot_bios(pe);
++ __invalidate_snapshot(s, -EIO);
++ error = 1;
+ goto out;
+ }
+
+ e = alloc_exception();
+ if (!e) {
+ down_write(&s->lock);
+- __invalidate_snapshot(s, pe, -ENOMEM);
+- flush = __flush_bios(pe);
+- up_write(&s->lock);
+-
+- error_snapshot_bios(pe);
++ __invalidate_snapshot(s, -ENOMEM);
++ error = 1;
+ goto out;
+ }
+ *e = pe->e;
+
+- /*
+- * Add a proper exception, and remove the
+- * in-flight exception from the list.
+- */
+ down_write(&s->lock);
+ if (!s->valid) {
+- flush = __flush_bios(pe);
+- up_write(&s->lock);
+-
+ free_exception(e);
+-
+- error_snapshot_bios(pe);
++ error = 1;
+ goto out;
+ }
+
++ /*
++ * Add a proper exception, and remove the
++ * in-flight exception from the list.
++ */
+ insert_exception(&s->complete, e);
++
++ out:
+ remove_exception(&pe->e);
+- flush = __flush_bios(pe);
++ snapshot_bios = bio_list_get(&pe->snapshot_bios);
++ origin_bios = put_pending_exception(pe);
+
+ up_write(&s->lock);
+
+ /* Submit any pending write bios */
+- flush_bios(bio_list_get(&pe->snapshot_bios));
+-
+- out:
+- primary_pe = pe->primary_pe;
+-
+- /*
+- * Free the pe if it's not linked to an origin write or if
+- * it's not itself a primary pe.
+- */
+- if (!primary_pe || primary_pe != pe)
+- free_pending_exception(pe);
+-
+- /*
+- * Free the primary pe if nothing references it.
+- */
+- if (primary_pe && !atomic_read(&primary_pe->sibling_count))
+- free_pending_exception(primary_pe);
++ if (error)
++ error_bios(snapshot_bios);
++ else
++ flush_bios(snapshot_bios);
+
+- if (flush)
+- flush_bios(flush);
++ flush_bios(origin_bios);
+ }
+
+ static void commit_callback(void *context, int success)
+@@ -822,7 +838,7 @@ __find_pending_exception(struct dm_snaps
+ bio_list_init(&pe->origin_bios);
+ bio_list_init(&pe->snapshot_bios);
+ pe->primary_pe = NULL;
+- atomic_set(&pe->sibling_count, 1);
++ atomic_set(&pe->ref_count, 0);
+ pe->snap = s;
+ pe->started = 0;
+
+@@ -831,6 +847,7 @@ __find_pending_exception(struct dm_snaps
+ return NULL;
+ }
+
++ get_pending_exception(pe);
+ insert_exception(&s->pending, &pe->e);
+
+ out:
+@@ -850,7 +867,6 @@ static int snapshot_map(struct dm_target
+ {
+ struct exception *e;
+ struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+- int copy_needed = 0;
+ int r = 1;
+ chunk_t chunk;
+ struct pending_exception *pe = NULL;
+@@ -865,32 +881,31 @@ static int snapshot_map(struct dm_target
+ if (unlikely(bio_barrier(bio)))
+ return -EOPNOTSUPP;
+
++ /* FIXME: should only take write lock if we need
++ * to copy an exception */
++ down_write(&s->lock);
++
++ if (!s->valid) {
++ r = -EIO;
++ goto out_unlock;
++ }
++
++ /* If the block is already remapped - use that, else remap it */
++ e = lookup_exception(&s->complete, chunk);
++ if (e) {
++ remap_exception(s, e, bio);
++ goto out_unlock;
++ }
++
+ /*
+ * Write to snapshot - higher level takes care of RW/RO
+ * flags so we should only get this if we are
+ * writeable.
+ */
+ if (bio_rw(bio) == WRITE) {
+-
+- /* FIXME: should only take write lock if we need
+- * to copy an exception */
+- down_write(&s->lock);
+-
+- if (!s->valid) {
+- r = -EIO;
+- goto out_unlock;
+- }
+-
+- /* If the block is already remapped - use that, else remap it */
+- e = lookup_exception(&s->complete, chunk);
+- if (e) {
+- remap_exception(s, e, bio);
+- goto out_unlock;
+- }
+-
+ pe = __find_pending_exception(s, bio);
+ if (!pe) {
+- __invalidate_snapshot(s, pe, -ENOMEM);
++ __invalidate_snapshot(s, -ENOMEM);
+ r = -EIO;
+ goto out_unlock;
+ }
+@@ -898,45 +913,27 @@ static int snapshot_map(struct dm_target
+ remap_exception(s, &pe->e, bio);
+ bio_list_add(&pe->snapshot_bios, bio);
+
++ r = 0;
++
+ if (!pe->started) {
+ /* this is protected by snap->lock */
+ pe->started = 1;
+- copy_needed = 1;
+- }
+-
+- r = 0;
+-
+- out_unlock:
+- up_write(&s->lock);
+-
+- if (copy_needed)
++ up_write(&s->lock);
+ start_copy(pe);
+- } else {
++ goto out;
++ }
++ } else
+ /*
+ * FIXME: this read path scares me because we
+ * always use the origin when we have a pending
+ * exception. However I can't think of a
+ * situation where this is wrong - ejt.
+ */
++ bio->bi_bdev = s->origin->bdev;
+
+- /* Do reads */
+- down_read(&s->lock);
+-
+- if (!s->valid) {
+- up_read(&s->lock);
+- return -EIO;
+- }
+-
+- /* See if it it has been remapped */
+- e = lookup_exception(&s->complete, chunk);
+- if (e)
+- remap_exception(s, e, bio);
+- else
+- bio->bi_bdev = s->origin->bdev;
+-
+- up_read(&s->lock);
+- }
+-
++ out_unlock:
++ up_write(&s->lock);
++ out:
+ return r;
+ }
+
+@@ -1025,7 +1022,7 @@ static int __origin_write(struct list_he
+ * is already remapped in this snapshot
+ * and trigger an exception if not.
+ *
+- * sibling_count is initialised to 1 so pending_complete()
++ * ref_count is initialised to 1 so pending_complete()
+ * won't destroy the primary_pe while we're inside this loop.
+ */
+ e = lookup_exception(&snap->complete, chunk);
+@@ -1034,7 +1031,7 @@ static int __origin_write(struct list_he
+
+ pe = __find_pending_exception(snap, bio);
+ if (!pe) {
+- __invalidate_snapshot(snap, pe, ENOMEM);
++ __invalidate_snapshot(snap, -ENOMEM);
+ goto next_snapshot;
+ }
+
+@@ -1056,8 +1053,8 @@ static int __origin_write(struct list_he
+ }
+
+ if (!pe->primary_pe) {
+- atomic_inc(&primary_pe->sibling_count);
+ pe->primary_pe = primary_pe;
++ get_pending_exception(primary_pe);
+ }
+
+ if (!pe->started) {
+@@ -1070,20 +1067,20 @@ static int __origin_write(struct list_he
+ }
+
+ if (!primary_pe)
+- goto out;
++ return r;
+
+ /*
+ * If this is the first time we're processing this chunk and
+- * sibling_count is now 1 it means all the pending exceptions
++ * ref_count is now 1 it means all the pending exceptions
+ * got completed while we were in the loop above, so it falls to
+ * us here to remove the primary_pe and submit any origin_bios.
+ */
+
+- if (first && atomic_dec_and_test(&primary_pe->sibling_count)) {
++ if (first && atomic_dec_and_test(&primary_pe->ref_count)) {
+ flush_bios(bio_list_get(&primary_pe->origin_bios));
+ free_pending_exception(primary_pe);
+ /* If we got here, pe_queue is necessarily empty. */
+- goto out;
++ return r;
+ }
+
+ /*
+@@ -1092,7 +1089,6 @@ static int __origin_write(struct list_he
+ list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
+ start_copy(pe);
+
+- out:
+ return r;
+ }
+
+@@ -1205,7 +1201,7 @@ static int origin_status(struct dm_targe
+
+ static struct target_type origin_target = {
+ .name = "snapshot-origin",
+- .version = {1, 4, 0},
++ .version = {1, 5, 0},
+ .module = THIS_MODULE,
+ .ctr = origin_ctr,
+ .dtr = origin_dtr,
+@@ -1216,7 +1212,7 @@ static struct target_type origin_target
+
+ static struct target_type snapshot_target = {
+ .name = "snapshot",
+- .version = {1, 4, 0},
++ .version = {1, 5, 0},
+ .module = THIS_MODULE,
+ .ctr = snapshot_ctr,
+ .dtr = snapshot_dtr,
+@@ -1275,8 +1271,17 @@ static int __init dm_snapshot_init(void)
+ goto bad5;
+ }
+
++ ksnapd = create_singlethread_workqueue("ksnapd");
++ if (!ksnapd) {
++ DMERR("Failed to create ksnapd workqueue.");
++ r = -ENOMEM;
++ goto bad6;
++ }
++
+ return 0;
+
++ bad6:
++ mempool_destroy(pending_pool);
+ bad5:
+ kmem_cache_destroy(pending_cache);
+ bad4:
+@@ -1294,6 +1299,8 @@ static void __exit dm_snapshot_exit(void
+ {
+ int r;
+
++ destroy_workqueue(ksnapd);
++
+ r = dm_unregister_target(&snapshot_target);
+ if (r)
+ DMERR("snapshot unregister failed %d", r);
+diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
+index fdec1e2..15fa2ae 100644
+--- a/drivers/md/dm-snap.h
++++ b/drivers/md/dm-snap.h
+@@ -10,7 +10,9 @@
+ #define DM_SNAPSHOT_H
+
+ #include "dm.h"
++#include "dm-bio-list.h"
+ #include <linux/blkdev.h>
++#include <linux/workqueue.h>
+
+ struct exception_table {
+ uint32_t hash_mask;
+@@ -112,10 +114,20 @@ struct dm_snapshot {
+ struct exception_table pending;
+ struct exception_table complete;
+
++ /*
++ * pe_lock protects all pending_exception operations and access
++ * as well as the snapshot_bios list.
++ */
++ spinlock_t pe_lock;
++
+ /* The on disk metadata handler */
+ struct exception_store store;
+
+ struct kcopyd_client *kcopyd_client;
++
++ /* Queue of snapshot writes for ksnapd to flush */
++ struct bio_list queued_bios;
++ struct work_struct queued_bios_work;
+ };
+
+ /*
+@@ -128,10 +140,9 @@ int dm_add_exception(struct dm_snapshot
+ * Constructor and destructor for the default persistent
+ * store.
+ */
+-int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
++int dm_create_persistent(struct exception_store *store);
+
+-int dm_create_transient(struct exception_store *store,
+- struct dm_snapshot *s, int blocksize);
++int dm_create_transient(struct exception_store *store);
+
+ /*
+ * Return the number of sectors in the device.
+diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
+index 75fe949..05befa9 100644
+--- a/drivers/md/dm-table.c
++++ b/drivers/md/dm-table.c
+@@ -522,56 +522,61 @@ static int __table_get_device(struct dm_
+ return 0;
+ }
+
+-
+-int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
+- sector_t len, int mode, struct dm_dev **result)
++void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
+ {
+- int r = __table_get_device(ti->table, ti, path,
+- start, len, mode, result);
+- if (!r) {
+- request_queue_t *q = bdev_get_queue((*result)->bdev);
+- struct io_restrictions *rs = &ti->limits;
+-
+- /*
+- * Combine the device limits low.
+- *
+- * FIXME: if we move an io_restriction struct
+- * into q this would just be a call to
+- * combine_restrictions_low()
+- */
++ request_queue_t *q = bdev_get_queue(bdev);
++ struct io_restrictions *rs = &ti->limits;
++
++ /*
++ * Combine the device limits low.
++ *
++ * FIXME: if we move an io_restriction struct
++ * into q this would just be a call to
++ * combine_restrictions_low()
++ */
++ rs->max_sectors =
++ min_not_zero(rs->max_sectors, q->max_sectors);
++
++ /* FIXME: Device-Mapper on top of RAID-0 breaks because DM
++ * currently doesn't honor MD's merge_bvec_fn routine.
++ * In this case, we'll force DM to use PAGE_SIZE or
++ * smaller I/O, just to be safe. A better fix is in the
++ * works, but add this for the time being so it will at
++ * least operate correctly.
++ */
++ if (q->merge_bvec_fn)
+ rs->max_sectors =
+- min_not_zero(rs->max_sectors, q->max_sectors);
++ min_not_zero(rs->max_sectors,
++ (unsigned int) (PAGE_SIZE >> 9));
+
+- /* FIXME: Device-Mapper on top of RAID-0 breaks because DM
+- * currently doesn't honor MD's merge_bvec_fn routine.
+- * In this case, we'll force DM to use PAGE_SIZE or
+- * smaller I/O, just to be safe. A better fix is in the
+- * works, but add this for the time being so it will at
+- * least operate correctly.
+- */
+- if (q->merge_bvec_fn)
+- rs->max_sectors =
+- min_not_zero(rs->max_sectors,
+- (unsigned int) (PAGE_SIZE >> 9));
++ rs->max_phys_segments =
++ min_not_zero(rs->max_phys_segments,
++ q->max_phys_segments);
+
+- rs->max_phys_segments =
+- min_not_zero(rs->max_phys_segments,
+- q->max_phys_segments);
++ rs->max_hw_segments =
++ min_not_zero(rs->max_hw_segments, q->max_hw_segments);
+
+- rs->max_hw_segments =
+- min_not_zero(rs->max_hw_segments, q->max_hw_segments);
++ rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size);
+
+- rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size);
++ rs->max_segment_size =
++ min_not_zero(rs->max_segment_size, q->max_segment_size);
+
+- rs->max_segment_size =
+- min_not_zero(rs->max_segment_size, q->max_segment_size);
++ rs->seg_boundary_mask =
++ min_not_zero(rs->seg_boundary_mask,
++ q->seg_boundary_mask);
+
+- rs->seg_boundary_mask =
+- min_not_zero(rs->seg_boundary_mask,
+- q->seg_boundary_mask);
++ rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
++}
++EXPORT_SYMBOL_GPL(dm_set_device_limits);
+
+- rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+- }
++int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
++ sector_t len, int mode, struct dm_dev **result)
++{
++ int r = __table_get_device(ti->table, ti, path,
++ start, len, mode, result);
++
++ if (!r)
++ dm_set_device_limits(ti, (*result)->bdev);
+
+ return r;
+ }
+@@ -939,9 +944,20 @@ void dm_table_postsuspend_targets(struct
+ return suspend_targets(t, 1);
+ }
+
+-void dm_table_resume_targets(struct dm_table *t)
++int dm_table_resume_targets(struct dm_table *t)
+ {
+- int i;
++ int i, r = 0;
++
++ for (i = 0; i < t->num_targets; i++) {
++ struct dm_target *ti = t->targets + i;
++
++ if (!ti->type->preresume)
++ continue;
++
++ r = ti->type->preresume(ti);
++ if (r)
++ return r;
++ }
+
+ for (i = 0; i < t->num_targets; i++) {
+ struct dm_target *ti = t->targets + i;
+@@ -949,6 +965,8 @@ void dm_table_resume_targets(struct dm_t
+ if (ti->type->resume)
+ ti->type->resume(ti);
+ }
++
++ return 0;
+ }
+
+ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
+@@ -983,6 +1001,11 @@ int dm_table_flush_all(struct dm_table *
+ {
+ struct list_head *d, *devices = dm_table_get_devices(t);
+ int ret = 0;
++ unsigned i;
++
++ for (i = 0; i < t->num_targets; i++)
++ if (t->targets[i].type->flush)
++ t->targets[i].type->flush(&t->targets[i]);
+
+ for (d = devices->next; d != devices; d = d->next) {
+ struct dm_dev *dd = list_entry(d, struct dm_dev, list);
+diff --git a/drivers/md/dm.c b/drivers/md/dm.c
+index c99bf9f..b5764a8 100644
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -20,6 +20,7 @@
+ #include <linux/idr.h>
+ #include <linux/hdreg.h>
+ #include <linux/blktrace_api.h>
++#include <linux/smp_lock.h>
+
+ #define DM_MSG_PREFIX "core"
+
+@@ -101,6 +102,8 @@ struct mapped_device {
+ mempool_t *io_pool;
+ mempool_t *tio_pool;
+
++ struct bio_set *bs;
++
+ /*
+ * Event handling.
+ */
+@@ -121,16 +124,10 @@ struct mapped_device {
+ static kmem_cache_t *_io_cache;
+ static kmem_cache_t *_tio_cache;
+
+-static struct bio_set *dm_set;
+-
+ static int __init local_init(void)
+ {
+ int r;
+
+- dm_set = bioset_create(16, 16, 4);
+- if (!dm_set)
+- return -ENOMEM;
+-
+ /* allocate a slab for the dm_ios */
+ _io_cache = kmem_cache_create("dm_io",
+ sizeof(struct dm_io), 0, 0, NULL, NULL);
+@@ -164,8 +161,6 @@ static void local_exit(void)
+ kmem_cache_destroy(_tio_cache);
+ kmem_cache_destroy(_io_cache);
+
+- bioset_free(dm_set);
+-
+ if (unregister_blkdev(_major, _name) < 0)
+ DMERR("unregister_blkdev failed");
+
+@@ -288,6 +283,45 @@ static int dm_blk_getgeo(struct block_de
+ return dm_get_geometry(md, geo);
+ }
+
++static int dm_blk_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct mapped_device *md;
++ struct dm_table *map;
++ struct dm_target *tgt;
++ int r = -ENOTTY;
++
++ /* We don't really need this lock, but we do need 'inode'. */
++ unlock_kernel();
++
++ md = inode->i_bdev->bd_disk->private_data;
++
++ map = dm_get_table(md);
++
++ if (!map || !dm_table_get_size(map))
++ goto out;
++
++ /* We only support devices that have a single target */
++ if (dm_table_get_num_targets(map) != 1)
++ goto out;
++
++ tgt = dm_table_get_target(map, 0);
++
++ if (dm_suspended(md)) {
++ r = -EAGAIN;
++ goto out;
++ }
++
++ if (tgt->type->ioctl)
++ r = tgt->type->ioctl(tgt, inode, file, cmd, arg);
++
++out:
++ dm_table_put(map);
++
++ lock_kernel();
++ return r;
++}
++
+ static inline struct dm_io *alloc_io(struct mapped_device *md)
+ {
+ return mempool_alloc(md->io_pool, GFP_NOIO);
+@@ -435,7 +469,7 @@ static int clone_endio(struct bio *bio,
+ {
+ int r = 0;
+ struct target_io *tio = bio->bi_private;
+- struct dm_io *io = tio->io;
++ struct mapped_device *md = tio->io->md;
+ dm_endio_fn endio = tio->ti->type->end_io;
+
+ if (bio->bi_size)
+@@ -454,9 +488,15 @@ static int clone_endio(struct bio *bio,
+ return 1;
+ }
+
+- free_tio(io->md, tio);
+- dec_pending(io, error);
++ dec_pending(tio->io, error);
++
++ /*
++ * Store md for cleanup instead of tio which is about to get freed.
++ */
++ bio->bi_private = md->bs;
++
+ bio_put(bio);
++ free_tio(md, tio);
+ return r;
+ }
+
+@@ -485,6 +525,7 @@ static void __map_bio(struct dm_target *
+ {
+ int r;
+ sector_t sector;
++ struct mapped_device *md;
+
+ /*
+ * Sanity checks.
+@@ -514,10 +555,14 @@ static void __map_bio(struct dm_target *
+
+ else if (r < 0) {
+ /* error the io and bail out */
+- struct dm_io *io = tio->io;
+- free_tio(tio->io->md, tio);
+- dec_pending(io, r);
++ md = tio->io->md;
++ dec_pending(tio->io, r);
++ /*
++ * Store bio_set for cleanup.
++ */
++ clone->bi_private = md->bs;
+ bio_put(clone);
++ free_tio(md, tio);
+ }
+ }
+
+@@ -533,7 +578,9 @@ struct clone_info {
+
+ static void dm_bio_destructor(struct bio *bio)
+ {
+- bio_free(bio, dm_set);
++ struct bio_set *bs = bio->bi_private;
++
++ bio_free(bio, bs);
+ }
+
+ /*
+@@ -541,12 +588,12 @@ static void dm_bio_destructor(struct bio
+ */
+ static struct bio *split_bvec(struct bio *bio, sector_t sector,
+ unsigned short idx, unsigned int offset,
+- unsigned int len)
++ unsigned int len, struct bio_set *bs)
+ {
+ struct bio *clone;
+ struct bio_vec *bv = bio->bi_io_vec + idx;
+
+- clone = bio_alloc_bioset(GFP_NOIO, 1, dm_set);
++ clone = bio_alloc_bioset(GFP_NOIO, 1, bs);
+ clone->bi_destructor = dm_bio_destructor;
+ *clone->bi_io_vec = *bv;
+
+@@ -566,11 +613,13 @@ static struct bio *split_bvec(struct bio
+ */
+ static struct bio *clone_bio(struct bio *bio, sector_t sector,
+ unsigned short idx, unsigned short bv_count,
+- unsigned int len)
++ unsigned int len, struct bio_set *bs)
+ {
+ struct bio *clone;
+
+- clone = bio_clone(bio, GFP_NOIO);
++ clone = bio_alloc_bioset(GFP_NOIO, bio->bi_max_vecs, bs);
++ __bio_clone(clone, bio);
++ clone->bi_destructor = dm_bio_destructor;
+ clone->bi_sector = sector;
+ clone->bi_idx = idx;
+ clone->bi_vcnt = idx + bv_count;
+@@ -601,7 +650,8 @@ static void __clone_and_map(struct clone
+ * the remaining io with a single clone.
+ */
+ clone = clone_bio(bio, ci->sector, ci->idx,
+- bio->bi_vcnt - ci->idx, ci->sector_count);
++ bio->bi_vcnt - ci->idx, ci->sector_count,
++ ci->md->bs);
+ __map_bio(ti, clone, tio);
+ ci->sector_count = 0;
+
+@@ -624,7 +674,8 @@ static void __clone_and_map(struct clone
+ len += bv_len;
+ }
+
+- clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len);
++ clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len,
++ ci->md->bs);
+ __map_bio(ti, clone, tio);
+
+ ci->sector += len;
+@@ -653,7 +704,8 @@ static void __clone_and_map(struct clone
+ len = min(remaining, max);
+
+ clone = split_bvec(bio, ci->sector, ci->idx,
+- bv->bv_offset + offset, len);
++ bv->bv_offset + offset, len,
++ ci->md->bs);
+
+ __map_bio(ti, clone, tio);
+
+@@ -903,7 +955,7 @@ static struct mapped_device *alloc_dev(i
+
+ md->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!md->queue)
+- goto bad1;
++ goto bad1_free_minor;
+
+ md->queue->queuedata = md;
+ md->queue->backing_dev_info.congested_fn = dm_any_congested;
+@@ -921,6 +973,10 @@ static struct mapped_device *alloc_dev(i
+ if (!md->tio_pool)
+ goto bad3;
+
++ md->bs = bioset_create(16, 16, 4);
++ if (!md->bs)
++ goto bad_no_bioset;
++
+ md->disk = alloc_disk(1);
+ if (!md->disk)
+ goto bad4;
+@@ -948,11 +1004,14 @@ static struct mapped_device *alloc_dev(i
+ return md;
+
+ bad4:
++ bioset_free(md->bs);
++ bad_no_bioset:
+ mempool_destroy(md->tio_pool);
+ bad3:
+ mempool_destroy(md->io_pool);
+ bad2:
+ blk_cleanup_queue(md->queue);
++ bad1_free_minor:
+ free_minor(minor);
+ bad1:
+ module_put(THIS_MODULE);
+@@ -971,6 +1030,7 @@ static void free_dev(struct mapped_devic
+ }
+ mempool_destroy(md->tio_pool);
+ mempool_destroy(md->io_pool);
++ bioset_free(md->bs);
+ del_gendisk(md->disk);
+ free_minor(minor);
+
+@@ -1319,7 +1379,9 @@ int dm_resume(struct mapped_device *md)
+ if (!map || !dm_table_get_size(map))
+ goto out;
+
+- dm_table_resume_targets(map);
++ r = dm_table_resume_targets(map);
++ if (r)
++ goto out;
+
+ down_write(&md->io_lock);
+ clear_bit(DMF_BLOCK_IO, &md->flags);
+@@ -1337,6 +1399,8 @@ int dm_resume(struct mapped_device *md)
+
+ dm_table_unplug_all(map);
+
++ kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
++
+ r = 0;
+
+ out:
+@@ -1377,6 +1441,7 @@ int dm_suspended(struct mapped_device *m
+ static struct block_device_operations dm_blk_dops = {
+ .open = dm_blk_open,
+ .release = dm_blk_close,
++ .ioctl = dm_blk_ioctl,
+ .getgeo = dm_blk_getgeo,
+ .owner = THIS_MODULE
+ };
+diff --git a/drivers/md/dm.h b/drivers/md/dm.h
+index 3c03c0e..a48ec5e 100644
+--- a/drivers/md/dm.h
++++ b/drivers/md/dm.h
+@@ -21,6 +21,11 @@
+ #define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+ #define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+ #define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
++#ifdef CONFIG_DM_DEBUG
++# define DMDEBUG(f, arg...) printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
++#else
++# define DMDEBUG(f, arg...) do {} while (0)
++#endif
+
+ #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
+ 0 : scnprintf(result + sz, maxlen - sz, x))
+@@ -52,7 +57,7 @@ void dm_table_set_restrictions(struct dm
+ struct list_head *dm_table_get_devices(struct dm_table *t);
+ void dm_table_presuspend_targets(struct dm_table *t);
+ void dm_table_postsuspend_targets(struct dm_table *t);
+-void dm_table_resume_targets(struct dm_table *t);
++int dm_table_resume_targets(struct dm_table *t);
+ int dm_table_any_congested(struct dm_table *t, int bdi_bits);
+ void dm_table_unplug_all(struct dm_table *t);
+ int dm_table_flush_all(struct dm_table *t);
+diff --git a/drivers/md/linear.c b/drivers/md/linear.c
+index b99c19c..c625ddb 100644
+--- a/drivers/md/linear.c
++++ b/drivers/md/linear.c
+@@ -111,6 +111,19 @@ static int linear_issue_flush(request_qu
+ return ret;
+ }
+
++static int linear_congested(void *data, int bits)
++{
++ mddev_t *mddev = data;
++ linear_conf_t *conf = mddev_to_conf(mddev);
++ int i, ret = 0;
++
++ for (i = 0; i < mddev->raid_disks && !ret ; i++) {
++ request_queue_t *q = bdev_get_queue(conf->disks[i].rdev->bdev);
++ ret |= bdi_congested(&q->backing_dev_info, bits);
++ }
++ return ret;
++}
++
+ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
+ {
+ linear_conf_t *conf;
+@@ -269,6 +282,8 @@ static int linear_run (mddev_t *mddev)
+ blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
+ mddev->queue->unplug_fn = linear_unplug;
+ mddev->queue->issue_flush_fn = linear_issue_flush;
++ mddev->queue->backing_dev_info.congested_fn = linear_congested;
++ mddev->queue->backing_dev_info.congested_data = mddev;
+ return 0;
+ }
+
+diff --git a/drivers/md/md.c b/drivers/md/md.c
+index 8dbab2e..d111356 100644
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -389,8 +389,12 @@ static int super_written(struct bio *bio
+ if (bio->bi_size)
+ return 1;
+
+- if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
++ if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
++ printk("md: super_written gets error=%d, uptodate=%d\n",
++ error, test_bit(BIO_UPTODATE, &bio->bi_flags));
++ WARN_ON(test_bit(BIO_UPTODATE, &bio->bi_flags));
+ md_error(mddev, rdev);
++ }
+
+ if (atomic_dec_and_test(&mddev->pending_writes))
+ wake_up(&mddev->sb_wait);
+@@ -970,12 +974,13 @@ static void super_90_sync(mddev_t *mddev
+ * version 1 superblock
+ */
+
+-static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
++static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb)
+ {
+- unsigned int disk_csum, csum;
++ __le32 disk_csum;
++ u32 csum;
+ unsigned long long newcsum;
+ int size = 256 + le32_to_cpu(sb->max_dev)*2;
+- unsigned int *isuper = (unsigned int*)sb;
++ __le32 *isuper = (__le32*)sb;
+ int i;
+
+ disk_csum = sb->sb_csum;
+@@ -985,7 +990,7 @@ static unsigned int calc_sb_1_csum(struc
+ newcsum += le32_to_cpu(*isuper++);
+
+ if (size == 2)
+- newcsum += le16_to_cpu(*(unsigned short*) isuper);
++ newcsum += le16_to_cpu(*(__le16*) isuper);
+
+ csum = (newcsum & 0xffffffff) + (newcsum >> 32);
+ sb->sb_csum = disk_csum;
+@@ -1102,7 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev
+ if (le32_to_cpu(sb->chunksize))
+ rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1);
+
+- if (le32_to_cpu(sb->size) > rdev->size*2)
++ if (le64_to_cpu(sb->size) > rdev->size*2)
+ return -EINVAL;
+ return ret;
+ }
+@@ -1224,7 +1229,7 @@ static void super_1_sync(mddev_t *mddev,
+ else
+ sb->resync_offset = cpu_to_le64(0);
+
+- sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors);
++ sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors));
+
+ sb->raid_disks = cpu_to_le32(mddev->raid_disks);
+ sb->size = cpu_to_le64(mddev->size<<1);
+@@ -1587,7 +1592,7 @@ static void sync_sbs(mddev_t * mddev, in
+ }
+ }
+
+-void md_update_sb(mddev_t * mddev)
++static void md_update_sb(mddev_t * mddev, int force_change)
+ {
+ int err;
+ struct list_head *tmp;
+@@ -1598,7 +1603,18 @@ void md_update_sb(mddev_t * mddev)
+ repeat:
+ spin_lock_irq(&mddev->write_lock);
+
+- if (mddev->degraded && mddev->sb_dirty == 3)
++ set_bit(MD_CHANGE_PENDING, &mddev->flags);
++ if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
++ force_change = 1;
++ if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags))
++ /* just a clean<-> dirty transition, possibly leave spares alone,
++ * though if events isn't the right even/odd, we will have to do
++ * spares after all
++ */
++ nospares = 1;
++ if (force_change)
++ nospares = 0;
++ if (mddev->degraded)
+ /* If the array is degraded, then skipping spares is both
+ * dangerous and fairly pointless.
+ * Dangerous because a device that was removed from the array
+@@ -1608,20 +1624,14 @@ repeat:
+ * then a recovery will happen and soon that array won't
+ * be degraded any more and the spare can go back to sleep then.
+ */
+- mddev->sb_dirty = 1;
++ nospares = 0;
+
+ sync_req = mddev->in_sync;
+ mddev->utime = get_seconds();
+- if (mddev->sb_dirty == 3)
+- /* just a clean<-> dirty transition, possibly leave spares alone,
+- * though if events isn't the right even/odd, we will have to do
+- * spares after all
+- */
+- nospares = 1;
+
+ /* If this is just a dirty<->clean transition, and the array is clean
+ * and 'events' is odd, we can roll back to the previous clean state */
+- if (mddev->sb_dirty == 3
++ if (nospares
+ && (mddev->in_sync && mddev->recovery_cp == MaxSector)
+ && (mddev->events & 1))
+ mddev->events--;
+@@ -1652,7 +1662,6 @@ repeat:
+ MD_BUG();
+ mddev->events --;
+ }
+- mddev->sb_dirty = 2;
+ sync_sbs(mddev, nospares);
+
+ /*
+@@ -1660,7 +1669,7 @@ repeat:
+ * nonpersistent superblocks
+ */
+ if (!mddev->persistent) {
+- mddev->sb_dirty = 0;
++ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+ spin_unlock_irq(&mddev->write_lock);
+ wake_up(&mddev->sb_wait);
+ return;
+@@ -1697,20 +1706,20 @@ repeat:
+ break;
+ }
+ md_super_wait(mddev);
+- /* if there was a failure, sb_dirty was set to 1, and we re-write super */
++ /* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */
+
+ spin_lock_irq(&mddev->write_lock);
+- if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
++ if (mddev->in_sync != sync_req ||
++ test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
+ /* have to write it out again */
+ spin_unlock_irq(&mddev->write_lock);
+ goto repeat;
+ }
+- mddev->sb_dirty = 0;
++ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+ spin_unlock_irq(&mddev->write_lock);
+ wake_up(&mddev->sb_wait);
+
+ }
+-EXPORT_SYMBOL_GPL(md_update_sb);
+
+ /* words written to sysfs files may, or my not, be \n terminated.
+ * We want to accept with case. For this we use cmd_match.
+@@ -1783,7 +1792,7 @@ state_store(mdk_rdev_t *rdev, const char
+ else {
+ mddev_t *mddev = rdev->mddev;
+ kick_rdev_from_array(rdev);
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+ md_new_event(mddev);
+ err = 0;
+ }
+@@ -1994,6 +2003,7 @@ static mdk_rdev_t *md_import_device(dev_
+ kobject_init(&rdev->kobj);
+
+ rdev->desc_nr = -1;
++ rdev->saved_raid_disk = -1;
+ rdev->flags = 0;
+ rdev->data_offset = 0;
+ rdev->sb_events = 0;
+@@ -2426,7 +2436,7 @@ array_state_store(mddev_t *mddev, const
+ spin_lock_irq(&mddev->write_lock);
+ if (atomic_read(&mddev->writes_pending) == 0) {
+ mddev->in_sync = 1;
+- mddev->sb_dirty = 1;
++ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ spin_unlock_irq(&mddev->write_lock);
+ } else {
+@@ -2438,7 +2448,7 @@ array_state_store(mddev_t *mddev, const
+ case active:
+ if (mddev->pers) {
+ restart_array(mddev);
+- mddev->sb_dirty = 0;
++ clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ wake_up(&mddev->sb_wait);
+ err = 0;
+ } else {
+@@ -2520,6 +2530,36 @@ static struct md_sysfs_entry md_new_devi
+ __ATTR(new_dev, S_IWUSR, null_show, new_dev_store);
+
+ static ssize_t
++bitmap_store(mddev_t *mddev, const char *buf, size_t len)
++{
++ char *end;
++ unsigned long chunk, end_chunk;
++
++ if (!mddev->bitmap)
++ goto out;
++ /* buf should be <chunk> <chunk> ... or <chunk>-<chunk> ... (range) */
++ while (*buf) {
++ chunk = end_chunk = simple_strtoul(buf, &end, 0);
++ if (buf == end) break;
++ if (*end == '-') { /* range */
++ buf = end + 1;
++ end_chunk = simple_strtoul(buf, &end, 0);
++ if (buf == end) break;
++ }
++ if (*end && !isspace(*end)) break;
++ bitmap_dirty_bits(mddev->bitmap, chunk, end_chunk);
++ buf = end;
++ while (isspace(*buf)) buf++;
++ }
++ bitmap_unplug(mddev->bitmap); /* flush the bits to disk */
++out:
++ return len;
++}
++
++static struct md_sysfs_entry md_bitmap =
++__ATTR(bitmap_set_bits, S_IWUSR, null_show, bitmap_store);
++
++static ssize_t
+ size_show(mddev_t *mddev, char *page)
+ {
+ return sprintf(page, "%llu\n", (unsigned long long)mddev->size);
+@@ -2543,7 +2583,7 @@ size_store(mddev_t *mddev, const char *b
+
+ if (mddev->pers) {
+ err = update_size(mddev, size);
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+ } else {
+ if (mddev->size == 0 ||
+ mddev->size > size)
+@@ -2839,6 +2879,7 @@ static struct attribute *md_redundancy_a
+ &md_sync_completed.attr,
+ &md_suspend_lo.attr,
+ &md_suspend_hi.attr,
++ &md_bitmap.attr,
+ NULL,
+ };
+ static struct attribute_group md_redundancy_group = {
+@@ -3111,8 +3152,8 @@ static int do_md_run(mddev_t * mddev)
+
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+
+- if (mddev->sb_dirty)
+- md_update_sb(mddev);
++ if (mddev->flags)
++ md_update_sb(mddev, 0);
+
+ set_capacity(disk, mddev->array_size<<1);
+
+@@ -3159,6 +3200,7 @@ static int do_md_run(mddev_t * mddev)
+
+ mddev->changed = 1;
+ md_new_event(mddev);
++ kobject_uevent(&mddev->gendisk->kobj, KOBJ_ONLINE);
+ return 0;
+ }
+
+@@ -3272,13 +3314,14 @@ static int do_md_stop(mddev_t * mddev, i
+
+ module_put(mddev->pers->owner);
+ mddev->pers = NULL;
++ kobject_uevent(&mddev->gendisk->kobj, KOBJ_OFFLINE);
+ if (mddev->ro)
+ mddev->ro = 0;
+ }
+- if (!mddev->in_sync || mddev->sb_dirty) {
++ if (!mddev->in_sync || mddev->flags) {
+ /* mark array as shutdown cleanly */
+ mddev->in_sync = 1;
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+ }
+ if (mode == 1)
+ set_disk_ro(disk, 1);
+@@ -3374,6 +3417,7 @@ static void autorun_devices(int part)
+
+ printk(KERN_INFO "md: autorun ...\n");
+ while (!list_empty(&pending_raid_disks)) {
++ int unit;
+ dev_t dev;
+ LIST_HEAD(candidates);
+ rdev0 = list_entry(pending_raid_disks.next,
+@@ -3393,16 +3437,19 @@ static void autorun_devices(int part)
+ * mostly sane superblocks. It's time to allocate the
+ * mddev.
+ */
+- if (rdev0->preferred_minor < 0 || rdev0->preferred_minor >= MAX_MD_DEVS) {
++ if (part) {
++ dev = MKDEV(mdp_major,
++ rdev0->preferred_minor << MdpMinorShift);
++ unit = MINOR(dev) >> MdpMinorShift;
++ } else {
++ dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
++ unit = MINOR(dev);
++ }
++ if (rdev0->preferred_minor != unit) {
+ printk(KERN_INFO "md: unit number in %s is bad: %d\n",
+ bdevname(rdev0->bdev, b), rdev0->preferred_minor);
+ break;
+ }
+- if (part)
+- dev = MKDEV(mdp_major,
+- rdev0->preferred_minor << MdpMinorShift);
+- else
+- dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+
+ md_probe(dev, NULL, NULL);
+ mddev = mddev_find(dev);
+@@ -3440,67 +3487,6 @@ static void autorun_devices(int part)
+ printk(KERN_INFO "md: ... autorun DONE.\n");
+ }
+
+-/*
+- * import RAID devices based on one partition
+- * if possible, the array gets run as well.
+- */
+-
+-static int autostart_array(dev_t startdev)
+-{
+- char b[BDEVNAME_SIZE];
+- int err = -EINVAL, i;
+- mdp_super_t *sb = NULL;
+- mdk_rdev_t *start_rdev = NULL, *rdev;
+-
+- start_rdev = md_import_device(startdev, 0, 0);
+- if (IS_ERR(start_rdev))
+- return err;
+-
+-
+- /* NOTE: this can only work for 0.90.0 superblocks */
+- sb = (mdp_super_t*)page_address(start_rdev->sb_page);
+- if (sb->major_version != 0 ||
+- sb->minor_version != 90 ) {
+- printk(KERN_WARNING "md: can only autostart 0.90.0 arrays\n");
+- export_rdev(start_rdev);
+- return err;
+- }
+-
+- if (test_bit(Faulty, &start_rdev->flags)) {
+- printk(KERN_WARNING
+- "md: can not autostart based on faulty %s!\n",
+- bdevname(start_rdev->bdev,b));
+- export_rdev(start_rdev);
+- return err;
+- }
+- list_add(&start_rdev->same_set, &pending_raid_disks);
+-
+- for (i = 0; i < MD_SB_DISKS; i++) {
+- mdp_disk_t *desc = sb->disks + i;
+- dev_t dev = MKDEV(desc->major, desc->minor);
+-
+- if (!dev)
+- continue;
+- if (dev == startdev)
+- continue;
+- if (MAJOR(dev) != desc->major || MINOR(dev) != desc->minor)
+- continue;
+- rdev = md_import_device(dev, 0, 0);
+- if (IS_ERR(rdev))
+- continue;
+-
+- list_add(&rdev->same_set, &pending_raid_disks);
+- }
+-
+- /*
+- * possibly return codes
+- */
+- autorun_devices(0);
+- return 0;
+-
+-}
+-
+-
+ static int get_version(void __user * arg)
+ {
+ mdu_version_t ver;
+@@ -3808,7 +3794,7 @@ static int hot_remove_disk(mddev_t * mdd
+ goto busy;
+
+ kick_rdev_from_array(rdev);
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+ md_new_event(mddev);
+
+ return 0;
+@@ -3867,6 +3853,7 @@ static int hot_add_disk(mddev_t * mddev,
+ }
+ clear_bit(In_sync, &rdev->flags);
+ rdev->desc_nr = -1;
++ rdev->saved_raid_disk = -1;
+ err = bind_rdev_to_array(rdev, mddev);
+ if (err)
+ goto abort_export;
+@@ -3885,7 +3872,7 @@ static int hot_add_disk(mddev_t * mddev,
+
+ rdev->raid_disk = -1;
+
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+
+ /*
+ * Kick recovery, maybe this spare has to be added to the
+@@ -4016,7 +4003,8 @@ static int set_array_info(mddev_t * mdde
+
+ mddev->max_disks = MD_SB_DISKS;
+
+- mddev->sb_dirty = 1;
++ mddev->flags = 0;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+
+ mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
+ mddev->bitmap_offset = 0;
+@@ -4059,11 +4047,8 @@ static int update_size(mddev_t *mddev, u
+ return -EBUSY;
+ ITERATE_RDEV(mddev,rdev,tmp) {
+ sector_t avail;
+- if (rdev->sb_offset > rdev->data_offset)
+- avail = (rdev->sb_offset*2) - rdev->data_offset;
+- else
+- avail = get_capacity(rdev->bdev->bd_disk)
+- - rdev->data_offset;
++ avail = rdev->size * 2;
++
+ if (fit && (size == 0 || size > avail/2))
+ size = avail/2;
+ if (avail < ((sector_t)size << 1))
+@@ -4185,7 +4170,7 @@ static int update_array_info(mddev_t *md
+ mddev->bitmap_offset = 0;
+ }
+ }
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+ return rv;
+ }
+
+@@ -4259,27 +4244,6 @@ static int md_ioctl(struct inode *inode,
+ goto abort;
+ }
+
+-
+- if (cmd == START_ARRAY) {
+- /* START_ARRAY doesn't need to lock the array as autostart_array
+- * does the locking, and it could even be a different array
+- */
+- static int cnt = 3;
+- if (cnt > 0 ) {
+- printk(KERN_WARNING
+- "md: %s(pid %d) used deprecated START_ARRAY ioctl. "
+- "This will not be supported beyond July 2006\n",
+- current->comm, current->pid);
+- cnt--;
+- }
+- err = autostart_array(new_decode_dev(arg));
+- if (err) {
+- printk(KERN_WARNING "md: autostart failed!\n");
+- goto abort;
+- }
+- goto done;
+- }
+-
+ err = mddev_lock(mddev);
+ if (err) {
+ printk(KERN_INFO
+@@ -4476,8 +4440,7 @@ static int md_release(struct inode *inod
+ {
+ mddev_t *mddev = inode->i_bdev->bd_disk->private_data;
+
+- if (!mddev)
+- BUG();
++ BUG_ON(!mddev);
+ mddev_put(mddev);
+
+ return 0;
+@@ -4687,9 +4650,11 @@ static void status_resync(struct seq_fil
+ seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)",
+ (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)?
+ "reshape" :
+- (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
+- "resync" : "recovery")),
+- per_milli/10, per_milli % 10,
++ (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)?
++ "check" :
++ (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
++ "resync" : "recovery"))),
++ per_milli/10, per_milli % 10,
+ (unsigned long long) resync,
+ (unsigned long long) max_blocks);
+
+@@ -4948,6 +4913,7 @@ static unsigned int mdstat_poll(struct f
+ }
+
+ static struct file_operations md_seq_fops = {
++ .owner = THIS_MODULE,
+ .open = md_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -5042,12 +5008,12 @@ void md_write_start(mddev_t *mddev, stru
+ spin_lock_irq(&mddev->write_lock);
+ if (mddev->in_sync) {
+ mddev->in_sync = 0;
+- mddev->sb_dirty = 3;
++ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ }
+ spin_unlock_irq(&mddev->write_lock);
+ }
+- wait_event(mddev->sb_wait, mddev->sb_dirty==0);
++ wait_event(mddev->sb_wait, mddev->flags==0);
+ }
+
+ void md_write_end(mddev_t *mddev)
+@@ -5078,6 +5044,7 @@ void md_do_sync(mddev_t *mddev)
+ int skipped = 0;
+ struct list_head *rtmp;
+ mdk_rdev_t *rdev;
++ char *desc;
+
+ /* just incase thread restarts... */
+ if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
+@@ -5085,6 +5052,18 @@ void md_do_sync(mddev_t *mddev)
+ if (mddev->ro) /* never try to sync a read-only array */
+ return;
+
++ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
++ if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
++ desc = "data-check";
++ else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
++ desc = "requested-resync";
++ else
++ desc = "resync";
++ } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
++ desc = "reshape";
++ else
++ desc = "recovery";
++
+ /* we overload curr_resync somewhat here.
+ * 0 == not engaged in resync at all
+ * 2 == checking that there is no conflict with another sync
+@@ -5128,10 +5107,10 @@ void md_do_sync(mddev_t *mddev)
+ prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
+ if (!kthread_should_stop() &&
+ mddev2->curr_resync >= mddev->curr_resync) {
+- printk(KERN_INFO "md: delaying resync of %s"
+- " until %s has finished resync (they"
++ printk(KERN_INFO "md: delaying %s of %s"
++ " until %s has finished (they"
+ " share one or more physical units)\n",
+- mdname(mddev), mdname(mddev2));
++ desc, mdname(mddev), mdname(mddev2));
+ mddev_put(mddev2);
+ schedule();
+ finish_wait(&resync_wait, &wq);
+@@ -5167,12 +5146,12 @@ void md_do_sync(mddev_t *mddev)
+ j = rdev->recovery_offset;
+ }
+
+- printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
+- printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
+- " %d KB/sec/disc.\n", speed_min(mddev));
++ printk(KERN_INFO "md: %s of RAID array %s\n", desc, mdname(mddev));
++ printk(KERN_INFO "md: minimum _guaranteed_ speed:"
++ " %d KB/sec/disk.\n", speed_min(mddev));
+ printk(KERN_INFO "md: using maximum available idle IO bandwidth "
+- "(but not more than %d KB/sec) for reconstruction.\n",
+- speed_max(mddev));
++ "(but not more than %d KB/sec) for %s.\n",
++ speed_max(mddev), desc);
+
+ is_mddev_idle(mddev); /* this also initializes IO event counters */
+
+@@ -5198,8 +5177,8 @@ void md_do_sync(mddev_t *mddev)
+
+ if (j>2) {
+ printk(KERN_INFO
+- "md: resuming recovery of %s from checkpoint.\n",
+- mdname(mddev));
++ "md: resuming %s of %s from checkpoint.\n",
++ desc, mdname(mddev));
+ mddev->curr_resync = j;
+ }
+
+@@ -5282,7 +5261,7 @@ void md_do_sync(mddev_t *mddev)
+ }
+ }
+ }
+- printk(KERN_INFO "md: %s: sync done.\n",mdname(mddev));
++ printk(KERN_INFO "md: %s: %s done.\n",mdname(mddev), desc);
+ /*
+ * this also signals 'finished resyncing' to md_stop
+ */
+@@ -5302,8 +5281,8 @@ void md_do_sync(mddev_t *mddev)
+ if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+ if (mddev->curr_resync >= mddev->recovery_cp) {
+ printk(KERN_INFO
+- "md: checkpointing recovery of %s.\n",
+- mdname(mddev));
++ "md: checkpointing %s of %s.\n",
++ desc, mdname(mddev));
+ mddev->recovery_cp = mddev->curr_resync;
+ }
+ } else
+@@ -5317,7 +5296,6 @@ void md_do_sync(mddev_t *mddev)
+ !test_bit(In_sync, &rdev->flags) &&
+ rdev->recovery_offset < mddev->curr_resync)
+ rdev->recovery_offset = mddev->curr_resync;
+- mddev->sb_dirty = 1;
+ }
+ }
+
+@@ -5374,7 +5352,7 @@ void md_check_recovery(mddev_t *mddev)
+ }
+
+ if ( ! (
+- mddev->sb_dirty ||
++ mddev->flags ||
+ test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
+ (mddev->safemode == 1) ||
+@@ -5390,14 +5368,14 @@ void md_check_recovery(mddev_t *mddev)
+ if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
+ !mddev->in_sync && mddev->recovery_cp == MaxSector) {
+ mddev->in_sync = 1;
+- mddev->sb_dirty = 3;
++ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
+ spin_unlock_irq(&mddev->write_lock);
+
+- if (mddev->sb_dirty)
+- md_update_sb(mddev);
++ if (mddev->flags)
++ md_update_sb(mddev, 0);
+
+
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
+@@ -5416,7 +5394,7 @@ void md_check_recovery(mddev_t *mddev)
+ /* activate any spares */
+ mddev->pers->spare_active(mddev);
+ }
+- md_update_sb(mddev);
++ md_update_sb(mddev, 1);
+
+ /* if array is no-longer degraded, then any saved_raid_disk
+ * information must be scrapped
+@@ -5556,22 +5534,15 @@ static void md_geninit(void)
+
+ static int __init md_init(void)
+ {
+- printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d,"
+- " MD_SB_DISKS=%d\n",
+- MD_MAJOR_VERSION, MD_MINOR_VERSION,
+- MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
+- printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR_HI,
+- BITMAP_MINOR);
+-
+ if (register_blkdev(MAJOR_NR, "md"))
+ return -1;
+ if ((mdp_major=register_blkdev(0, "mdp"))<=0) {
+ unregister_blkdev(MAJOR_NR, "md");
+ return -1;
+ }
+- blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE,
+- md_probe, NULL, NULL);
+- blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<<MdpMinorShift, THIS_MODULE,
++ blk_register_region(MKDEV(MAJOR_NR, 0), 1UL<<MINORBITS, THIS_MODULE,
++ md_probe, NULL, NULL);
++ blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,
+ md_probe, NULL, NULL);
+
+ register_reboot_notifier(&md_notifier);
+@@ -5630,8 +5601,8 @@ static __exit void md_exit(void)
+ mddev_t *mddev;
+ struct list_head *tmp;
+
+- blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS);
+- blk_unregister_region(MKDEV(mdp_major,0), MAX_MD_DEVS << MdpMinorShift);
++ blk_unregister_region(MKDEV(MAJOR_NR,0), 1U << MINORBITS);
++ blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);
+
+ unregister_blkdev(MAJOR_NR,"md");
+ unregister_blkdev(mdp_major, "mdp");
+diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
+index 1cc9de4..14da37f 100644
+--- a/drivers/md/multipath.c
++++ b/drivers/md/multipath.c
+@@ -228,6 +228,28 @@ static int multipath_issue_flush(request
+ rcu_read_unlock();
+ return ret;
+ }
++static int multipath_congested(void *data, int bits)
++{
++ mddev_t *mddev = data;
++ multipath_conf_t *conf = mddev_to_conf(mddev);
++ int i, ret = 0;
++
++ rcu_read_lock();
++ for (i = 0; i < mddev->raid_disks ; i++) {
++ mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
++ if (rdev && !test_bit(Faulty, &rdev->flags)) {
++ request_queue_t *q = bdev_get_queue(rdev->bdev);
++
++ ret |= bdi_congested(&q->backing_dev_info, bits);
++ /* Just like multipath_map, we just check the
++ * first available device
++ */
++ break;
++ }
++ }
++ rcu_read_unlock();
++ return ret;
++}
+
+ /*
+ * Careful, this can execute in IRQ contexts as well!
+@@ -253,8 +275,9 @@ static void multipath_error (mddev_t *md
+ char b[BDEVNAME_SIZE];
+ clear_bit(In_sync, &rdev->flags);
+ set_bit(Faulty, &rdev->flags);
+- mddev->sb_dirty = 1;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ conf->working_disks--;
++ mddev->degraded++;
+ printk(KERN_ALERT "multipath: IO failure on %s,"
+ " disabling IO path. \n Operation continuing"
+ " on %d IO paths.\n",
+@@ -314,6 +337,7 @@ static int multipath_add_disk(mddev_t *m
+ blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+
+ conf->working_disks++;
++ mddev->degraded--;
+ rdev->raid_disk = path;
+ set_bit(In_sync, &rdev->flags);
+ rcu_assign_pointer(p->rdev, rdev);
+@@ -470,7 +494,6 @@ static int multipath_run (mddev_t *mddev
+ }
+
+ conf->raid_disks = mddev->raid_disks;
+- mddev->sb_dirty = 1;
+ conf->mddev = mddev;
+ spin_lock_init(&conf->device_lock);
+ INIT_LIST_HEAD(&conf->retry_list);
+@@ -480,7 +503,7 @@ static int multipath_run (mddev_t *mddev
+ mdname(mddev));
+ goto out_free_conf;
+ }
+- mddev->degraded = conf->raid_disks = conf->working_disks;
++ mddev->degraded = conf->raid_disks - conf->working_disks;
+
+ conf->pool = mempool_create_kzalloc_pool(NR_RESERVED_BUFS,
+ sizeof(struct multipath_bh));
+@@ -510,6 +533,8 @@ static int multipath_run (mddev_t *mddev
+
+ mddev->queue->unplug_fn = multipath_unplug;
+ mddev->queue->issue_flush_fn = multipath_issue_flush;
++ mddev->queue->backing_dev_info.congested_fn = multipath_congested;
++ mddev->queue->backing_dev_info.congested_data = mddev;
+
+ return 0;
+
+diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
+index cb8c631..dfe3214 100644
+--- a/drivers/md/raid0.c
++++ b/drivers/md/raid0.c
+@@ -60,6 +60,21 @@ static int raid0_issue_flush(request_que
+ return ret;
+ }
+
++static int raid0_congested(void *data, int bits)
++{
++ mddev_t *mddev = data;
++ raid0_conf_t *conf = mddev_to_conf(mddev);
++ mdk_rdev_t **devlist = conf->strip_zone[0].dev;
++ int i, ret = 0;
++
++ for (i = 0; i < mddev->raid_disks && !ret ; i++) {
++ request_queue_t *q = bdev_get_queue(devlist[i]->bdev);
++
++ ret |= bdi_congested(&q->backing_dev_info, bits);
++ }
++ return ret;
++}
++
+
+ static int create_strip_zones (mddev_t *mddev)
+ {
+@@ -236,6 +251,8 @@ static int create_strip_zones (mddev_t *
+ mddev->queue->unplug_fn = raid0_unplug;
+
+ mddev->queue->issue_flush_fn = raid0_issue_flush;
++ mddev->queue->backing_dev_info.congested_fn = raid0_congested;
++ mddev->queue->backing_dev_info.congested_data = mddev;
+
+ printk("raid0: done.\n");
+ return 0;
+diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
+index 3b4d69c..656fae9 100644
+--- a/drivers/md/raid1.c
++++ b/drivers/md/raid1.c
+@@ -271,7 +271,7 @@ static int raid1_end_read_request(struct
+ */
+ update_head_pos(mirror, r1_bio);
+
+- if (uptodate || conf->working_disks <= 1) {
++ if (uptodate || (conf->raid_disks - conf->mddev->degraded) <= 1) {
+ /*
+ * Set R1BIO_Uptodate in our master bio, so that
+ * we will return a good error code for to the higher
+@@ -601,6 +601,32 @@ static int raid1_issue_flush(request_que
+ return ret;
+ }
+
++static int raid1_congested(void *data, int bits)
++{
++ mddev_t *mddev = data;
++ conf_t *conf = mddev_to_conf(mddev);
++ int i, ret = 0;
++
++ rcu_read_lock();
++ for (i = 0; i < mddev->raid_disks; i++) {
++ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
++ if (rdev && !test_bit(Faulty, &rdev->flags)) {
++ request_queue_t *q = bdev_get_queue(rdev->bdev);
++
++ /* Note the '|| 1' - when read_balance prefers
++ * non-congested targets, it can be removed
++ */
++ if ((bits & (1<<BDI_write_congested)) || 1)
++ ret |= bdi_congested(&q->backing_dev_info, bits);
++ else
++ ret &= bdi_congested(&q->backing_dev_info, bits);
++ }
++ }
++ rcu_read_unlock();
++ return ret;
++}
++
++
+ /* Barriers....
+ * Sometimes we need to suspend IO while we do something else,
+ * either some resync/recovery, or reconfigure the array.
+@@ -929,7 +955,7 @@ static void status(struct seq_file *seq,
+ int i;
+
+ seq_printf(seq, " [%d/%d] [", conf->raid_disks,
+- conf->working_disks);
++ conf->raid_disks - mddev->degraded);
+ rcu_read_lock();
+ for (i = 0; i < conf->raid_disks; i++) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+@@ -953,26 +979,27 @@ static void error(mddev_t *mddev, mdk_rd
+ * else mark the drive as failed
+ */
+ if (test_bit(In_sync, &rdev->flags)
+- && conf->working_disks == 1)
++ && (conf->raid_disks - mddev->degraded) == 1)
+ /*
+ * Don't fail the drive, act as though we were just a
+ * normal single drive
+ */
+ return;
+- if (test_bit(In_sync, &rdev->flags)) {
++ if (test_and_clear_bit(In_sync, &rdev->flags)) {
++ unsigned long flags;
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded++;
+- conf->working_disks--;
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ /*
+ * if recovery is running, make sure it aborts.
+ */
+ set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ }
+- clear_bit(In_sync, &rdev->flags);
+ set_bit(Faulty, &rdev->flags);
+- mddev->sb_dirty = 1;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
+ " Operation continuing on %d devices\n",
+- bdevname(rdev->bdev,b), conf->working_disks);
++ bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
+ }
+
+ static void print_conf(conf_t *conf)
+@@ -984,7 +1011,7 @@ static void print_conf(conf_t *conf)
+ printk("(!conf)\n");
+ return;
+ }
+- printk(" --- wd:%d rd:%d\n", conf->working_disks,
++ printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
+ conf->raid_disks);
+
+ rcu_read_lock();
+@@ -1023,10 +1050,11 @@ static int raid1_spare_active(mddev_t *m
+ mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+ if (rdev
+ && !test_bit(Faulty, &rdev->flags)
+- && !test_bit(In_sync, &rdev->flags)) {
+- conf->working_disks++;
++ && !test_and_set_bit(In_sync, &rdev->flags)) {
++ unsigned long flags;
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded--;
+- set_bit(In_sync, &rdev->flags);
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ }
+ }
+
+@@ -1368,6 +1396,95 @@ static void sync_request_write(mddev_t *
+ * 3. Performs writes following reads for array syncronising.
+ */
+
++static void fix_read_error(conf_t *conf, int read_disk,
++ sector_t sect, int sectors)
++{
++ mddev_t *mddev = conf->mddev;
++ while(sectors) {
++ int s = sectors;
++ int d = read_disk;
++ int success = 0;
++ int start;
++ mdk_rdev_t *rdev;
++
++ if (s > (PAGE_SIZE>>9))
++ s = PAGE_SIZE >> 9;
++
++ do {
++ /* Note: no rcu protection needed here
++ * as this is synchronous in the raid1d thread
++ * which is the thread that might remove
++ * a device. If raid1d ever becomes multi-threaded....
++ */
++ rdev = conf->mirrors[d].rdev;
++ if (rdev &&
++ test_bit(In_sync, &rdev->flags) &&
++ sync_page_io(rdev->bdev,
++ sect + rdev->data_offset,
++ s<<9,
++ conf->tmppage, READ))
++ success = 1;
++ else {
++ d++;
++ if (d == conf->raid_disks)
++ d = 0;
++ }
++ } while (!success && d != read_disk);
++
++ if (!success) {
++ /* Cannot read from anywhere -- bye bye array */
++ md_error(mddev, conf->mirrors[read_disk].rdev);
++ break;
++ }
++ /* write it back and re-read */
++ start = d;
++ while (d != read_disk) {
++ if (d==0)
++ d = conf->raid_disks;
++ d--;
++ rdev = conf->mirrors[d].rdev;
++ if (rdev &&
++ test_bit(In_sync, &rdev->flags)) {
++ if (sync_page_io(rdev->bdev,
++ sect + rdev->data_offset,
++ s<<9, conf->tmppage, WRITE)
++ == 0)
++ /* Well, this device is dead */
++ md_error(mddev, rdev);
++ }
++ }
++ d = start;
++ while (d != read_disk) {
++ char b[BDEVNAME_SIZE];
++ if (d==0)
++ d = conf->raid_disks;
++ d--;
++ rdev = conf->mirrors[d].rdev;
++ if (rdev &&
++ test_bit(In_sync, &rdev->flags)) {
++ if (sync_page_io(rdev->bdev,
++ sect + rdev->data_offset,
++ s<<9, conf->tmppage, READ)
++ == 0)
++ /* Well, this device is dead */
++ md_error(mddev, rdev);
++ else {
++ atomic_add(s, &rdev->corrected_errors);
++ printk(KERN_INFO
++ "raid1:%s: read error corrected "
++ "(%d sectors at %llu on %s)\n",
++ mdname(mddev), s,
++ (unsigned long long)(sect +
++ rdev->data_offset),
++ bdevname(rdev->bdev, b));
++ }
++ }
++ }
++ sectors -= s;
++ sect += s;
++ }
++}
++
+ static void raid1d(mddev_t *mddev)
+ {
+ r1bio_t *r1_bio;
+@@ -1460,86 +1577,14 @@ static void raid1d(mddev_t *mddev)
+ * This is all done synchronously while the array is
+ * frozen
+ */
+- sector_t sect = r1_bio->sector;
+- int sectors = r1_bio->sectors;
+- freeze_array(conf);
+- if (mddev->ro == 0) while(sectors) {
+- int s = sectors;
+- int d = r1_bio->read_disk;
+- int success = 0;
+-
+- if (s > (PAGE_SIZE>>9))
+- s = PAGE_SIZE >> 9;
+-
+- do {
+- /* Note: no rcu protection needed here
+- * as this is synchronous in the raid1d thread
+- * which is the thread that might remove
+- * a device. If raid1d ever becomes multi-threaded....
+- */
+- rdev = conf->mirrors[d].rdev;
+- if (rdev &&
+- test_bit(In_sync, &rdev->flags) &&
+- sync_page_io(rdev->bdev,
+- sect + rdev->data_offset,
+- s<<9,
+- conf->tmppage, READ))
+- success = 1;
+- else {
+- d++;
+- if (d == conf->raid_disks)
+- d = 0;
+- }
+- } while (!success && d != r1_bio->read_disk);
+-
+- if (success) {
+- /* write it back and re-read */
+- int start = d;
+- while (d != r1_bio->read_disk) {
+- if (d==0)
+- d = conf->raid_disks;
+- d--;
+- rdev = conf->mirrors[d].rdev;
+- if (rdev &&
+- test_bit(In_sync, &rdev->flags)) {
+- if (sync_page_io(rdev->bdev,
+- sect + rdev->data_offset,
+- s<<9, conf->tmppage, WRITE) == 0)
+- /* Well, this device is dead */
+- md_error(mddev, rdev);
+- }
+- }
+- d = start;
+- while (d != r1_bio->read_disk) {
+- if (d==0)
+- d = conf->raid_disks;
+- d--;
+- rdev = conf->mirrors[d].rdev;
+- if (rdev &&
+- test_bit(In_sync, &rdev->flags)) {
+- if (sync_page_io(rdev->bdev,
+- sect + rdev->data_offset,
+- s<<9, conf->tmppage, READ) == 0)
+- /* Well, this device is dead */
+- md_error(mddev, rdev);
+- else {
+- atomic_add(s, &rdev->corrected_errors);
+- printk(KERN_INFO "raid1:%s: read error corrected (%d sectors at %llu on %s)\n",
+- mdname(mddev), s, (unsigned long long)(sect + rdev->data_offset), bdevname(rdev->bdev, b));
+- }
+- }
+- }
+- } else {
+- /* Cannot read from anywhere -- bye bye array */
+- md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
+- break;
+- }
+- sectors -= s;
+- sect += s;
++ if (mddev->ro == 0) {
++ freeze_array(conf);
++ fix_read_error(conf, r1_bio->read_disk,
++ r1_bio->sector,
++ r1_bio->sectors);
++ unfreeze_array(conf);
+ }
+
+- unfreeze_array(conf);
+-
+ bio = r1_bio->bios[r1_bio->read_disk];
+ if ((disk=read_balance(conf, r1_bio)) == -1) {
+ printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
+@@ -1884,15 +1929,11 @@ static int run(mddev_t *mddev)
+ blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+
+ disk->head_position = 0;
+- if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
+- conf->working_disks++;
+ }
+ conf->raid_disks = mddev->raid_disks;
+ conf->mddev = mddev;
+ spin_lock_init(&conf->device_lock);
+ INIT_LIST_HEAD(&conf->retry_list);
+- if (conf->working_disks == 1)
+- mddev->recovery_cp = MaxSector;
+
+ spin_lock_init(&conf->resync_lock);
+ init_waitqueue_head(&conf->wait_barrier);
+@@ -1900,11 +1941,6 @@ static int run(mddev_t *mddev)
+ bio_list_init(&conf->pending_bio_list);
+ bio_list_init(&conf->flushing_bio_list);
+
+- if (!conf->working_disks) {
+- printk(KERN_ERR "raid1: no operational mirrors for %s\n",
+- mdname(mddev));
+- goto out_free_conf;
+- }
+
+ mddev->degraded = 0;
+ for (i = 0; i < conf->raid_disks; i++) {
+@@ -1917,6 +1953,13 @@ static int run(mddev_t *mddev)
+ mddev->degraded++;
+ }
+ }
++ if (mddev->degraded == conf->raid_disks) {
++ printk(KERN_ERR "raid1: no operational mirrors for %s\n",
++ mdname(mddev));
++ goto out_free_conf;
++ }
++ if (conf->raid_disks - mddev->degraded == 1)
++ mddev->recovery_cp = MaxSector;
+
+ /*
+ * find the first working one and use it as a starting point
+@@ -1948,6 +1991,8 @@ static int run(mddev_t *mddev)
+
+ mddev->queue->unplug_fn = raid1_unplug;
+ mddev->queue->issue_flush_fn = raid1_issue_flush;
++ mddev->queue->backing_dev_info.congested_fn = raid1_congested;
++ mddev->queue->backing_dev_info.congested_data = mddev;
+
+ return 0;
+
+@@ -2035,7 +2080,7 @@ static int raid1_reshape(mddev_t *mddev)
+ mirror_info_t *newmirrors;
+ conf_t *conf = mddev_to_conf(mddev);
+ int cnt, raid_disks;
+-
++ unsigned long flags;
+ int d, d2;
+
+ /* Cannot change chunk_size, layout, or level */
+@@ -2094,7 +2139,9 @@ static int raid1_reshape(mddev_t *mddev)
+ kfree(conf->poolinfo);
+ conf->poolinfo = newpoolinfo;
+
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded += (raid_disks - conf->raid_disks);
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ conf->raid_disks = mddev->raid_disks = raid_disks;
+ mddev->delta_disks = 0;
+
+diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
+index 016ddb8..7492d60 100644
+--- a/drivers/md/raid10.c
++++ b/drivers/md/raid10.c
+@@ -648,6 +648,26 @@ static int raid10_issue_flush(request_qu
+ return ret;
+ }
+
++static int raid10_congested(void *data, int bits)
++{
++ mddev_t *mddev = data;
++ conf_t *conf = mddev_to_conf(mddev);
++ int i, ret = 0;
++
++ rcu_read_lock();
++ for (i = 0; i < mddev->raid_disks && ret == 0; i++) {
++ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
++ if (rdev && !test_bit(Faulty, &rdev->flags)) {
++ request_queue_t *q = bdev_get_queue(rdev->bdev);
++
++ ret |= bdi_congested(&q->backing_dev_info, bits);
++ }
++ }
++ rcu_read_unlock();
++ return ret;
++}
++
++
+ /* Barriers....
+ * Sometimes we need to suspend IO while we do something else,
+ * either some resync/recovery, or reconfigure the array.
+@@ -921,7 +941,7 @@ static void status(struct seq_file *seq,
+ seq_printf(seq, " %d far-copies", conf->far_copies);
+ }
+ seq_printf(seq, " [%d/%d] [", conf->raid_disks,
+- conf->working_disks);
++ conf->raid_disks - mddev->degraded);
+ for (i = 0; i < conf->raid_disks; i++)
+ seq_printf(seq, "%s",
+ conf->mirrors[i].rdev &&
+@@ -941,7 +961,7 @@ static void error(mddev_t *mddev, mdk_rd
+ * else mark the drive as failed
+ */
+ if (test_bit(In_sync, &rdev->flags)
+- && conf->working_disks == 1)
++ && conf->raid_disks-mddev->degraded == 1)
+ /*
+ * Don't fail the drive, just return an IO error.
+ * The test should really be more sophisticated than
+@@ -950,20 +970,21 @@ static void error(mddev_t *mddev, mdk_rd
+ * really dead" tests...
+ */
+ return;
+- if (test_bit(In_sync, &rdev->flags)) {
++ if (test_and_clear_bit(In_sync, &rdev->flags)) {
++ unsigned long flags;
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded++;
+- conf->working_disks--;
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ /*
+ * if recovery is running, make sure it aborts.
+ */
+ set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ }
+- clear_bit(In_sync, &rdev->flags);
+ set_bit(Faulty, &rdev->flags);
+- mddev->sb_dirty = 1;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
+ " Operation continuing on %d devices\n",
+- bdevname(rdev->bdev,b), conf->working_disks);
++ bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
+ }
+
+ static void print_conf(conf_t *conf)
+@@ -976,7 +997,7 @@ static void print_conf(conf_t *conf)
+ printk("(!conf)\n");
+ return;
+ }
+- printk(" --- wd:%d rd:%d\n", conf->working_disks,
++ printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
+ conf->raid_disks);
+
+ for (i = 0; i < conf->raid_disks; i++) {
+@@ -1034,10 +1055,11 @@ static int raid10_spare_active(mddev_t *
+ tmp = conf->mirrors + i;
+ if (tmp->rdev
+ && !test_bit(Faulty, &tmp->rdev->flags)
+- && !test_bit(In_sync, &tmp->rdev->flags)) {
+- conf->working_disks++;
++ && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
++ unsigned long flags;
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded--;
+- set_bit(In_sync, &tmp->rdev->flags);
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ }
+ }
+
+@@ -1350,9 +1372,119 @@ static void recovery_request_write(mddev
+ *
+ * 1. Retries failed read operations on working mirrors.
+ * 2. Updates the raid superblock when problems encounter.
+- * 3. Performs writes following reads for array syncronising.
++ * 3. Performs writes following reads for array synchronising.
+ */
+
++static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
++{
++ int sect = 0; /* Offset from r10_bio->sector */
++ int sectors = r10_bio->sectors;
++ mdk_rdev_t*rdev;
++ while(sectors) {
++ int s = sectors;
++ int sl = r10_bio->read_slot;
++ int success = 0;
++ int start;
++
++ if (s > (PAGE_SIZE>>9))
++ s = PAGE_SIZE >> 9;
++
++ rcu_read_lock();
++ do {
++ int d = r10_bio->devs[sl].devnum;
++ rdev = rcu_dereference(conf->mirrors[d].rdev);
++ if (rdev &&
++ test_bit(In_sync, &rdev->flags)) {
++ atomic_inc(&rdev->nr_pending);
++ rcu_read_unlock();
++ success = sync_page_io(rdev->bdev,
++ r10_bio->devs[sl].addr +
++ sect + rdev->data_offset,
++ s<<9,
++ conf->tmppage, READ);
++ rdev_dec_pending(rdev, mddev);
++ rcu_read_lock();
++ if (success)
++ break;
++ }
++ sl++;
++ if (sl == conf->copies)
++ sl = 0;
++ } while (!success && sl != r10_bio->read_slot);
++ rcu_read_unlock();
++
++ if (!success) {
++ /* Cannot read from anywhere -- bye bye array */
++ int dn = r10_bio->devs[r10_bio->read_slot].devnum;
++ md_error(mddev, conf->mirrors[dn].rdev);
++ break;
++ }
++
++ start = sl;
++ /* write it back and re-read */
++ rcu_read_lock();
++ while (sl != r10_bio->read_slot) {
++ int d;
++ if (sl==0)
++ sl = conf->copies;
++ sl--;
++ d = r10_bio->devs[sl].devnum;
++ rdev = rcu_dereference(conf->mirrors[d].rdev);
++ if (rdev &&
++ test_bit(In_sync, &rdev->flags)) {
++ atomic_inc(&rdev->nr_pending);
++ rcu_read_unlock();
++ atomic_add(s, &rdev->corrected_errors);
++ if (sync_page_io(rdev->bdev,
++ r10_bio->devs[sl].addr +
++ sect + rdev->data_offset,
++ s<<9, conf->tmppage, WRITE)
++ == 0)
++ /* Well, this device is dead */
++ md_error(mddev, rdev);
++ rdev_dec_pending(rdev, mddev);
++ rcu_read_lock();
++ }
++ }
++ sl = start;
++ while (sl != r10_bio->read_slot) {
++ int d;
++ if (sl==0)
++ sl = conf->copies;
++ sl--;
++ d = r10_bio->devs[sl].devnum;
++ rdev = rcu_dereference(conf->mirrors[d].rdev);
++ if (rdev &&
++ test_bit(In_sync, &rdev->flags)) {
++ char b[BDEVNAME_SIZE];
++ atomic_inc(&rdev->nr_pending);
++ rcu_read_unlock();
++ if (sync_page_io(rdev->bdev,
++ r10_bio->devs[sl].addr +
++ sect + rdev->data_offset,
++ s<<9, conf->tmppage, READ) == 0)
++ /* Well, this device is dead */
++ md_error(mddev, rdev);
++ else
++ printk(KERN_INFO
++ "raid10:%s: read error corrected"
++ " (%d sectors at %llu on %s)\n",
++ mdname(mddev), s,
++ (unsigned long long)(sect+
++ rdev->data_offset),
++ bdevname(rdev->bdev, b));
++
++ rdev_dec_pending(rdev, mddev);
++ rcu_read_lock();
++ }
++ }
++ rcu_read_unlock();
++
++ sectors -= s;
++ sect += s;
++ }
++}
++
+ static void raid10d(mddev_t *mddev)
+ {
+ r10bio_t *r10_bio;
+@@ -1413,105 +1545,12 @@ static void raid10d(mddev_t *mddev)
+ * This is all done synchronously while the array is
+ * frozen.
+ */
+- int sect = 0; /* Offset from r10_bio->sector */
+- int sectors = r10_bio->sectors;
+- freeze_array(conf);
+- if (mddev->ro == 0) while(sectors) {
+- int s = sectors;
+- int sl = r10_bio->read_slot;
+- int success = 0;
+-
+- if (s > (PAGE_SIZE>>9))
+- s = PAGE_SIZE >> 9;
+-
+- rcu_read_lock();
+- do {
+- int d = r10_bio->devs[sl].devnum;
+- rdev = rcu_dereference(conf->mirrors[d].rdev);
+- if (rdev &&
+- test_bit(In_sync, &rdev->flags)) {
+- atomic_inc(&rdev->nr_pending);
+- rcu_read_unlock();
+- success = sync_page_io(rdev->bdev,
+- r10_bio->devs[sl].addr +
+- sect + rdev->data_offset,
+- s<<9,
+- conf->tmppage, READ);
+- rdev_dec_pending(rdev, mddev);
+- rcu_read_lock();
+- if (success)
+- break;
+- }
+- sl++;
+- if (sl == conf->copies)
+- sl = 0;
+- } while (!success && sl != r10_bio->read_slot);
+- rcu_read_unlock();
+-
+- if (success) {
+- int start = sl;
+- /* write it back and re-read */
+- rcu_read_lock();
+- while (sl != r10_bio->read_slot) {
+- int d;
+- if (sl==0)
+- sl = conf->copies;
+- sl--;
+- d = r10_bio->devs[sl].devnum;
+- rdev = rcu_dereference(conf->mirrors[d].rdev);
+- if (rdev &&
+- test_bit(In_sync, &rdev->flags)) {
+- atomic_inc(&rdev->nr_pending);
+- rcu_read_unlock();
+- atomic_add(s, &rdev->corrected_errors);
+- if (sync_page_io(rdev->bdev,
+- r10_bio->devs[sl].addr +
+- sect + rdev->data_offset,
+- s<<9, conf->tmppage, WRITE) == 0)
+- /* Well, this device is dead */
+- md_error(mddev, rdev);
+- rdev_dec_pending(rdev, mddev);
+- rcu_read_lock();
+- }
+- }
+- sl = start;
+- while (sl != r10_bio->read_slot) {
+- int d;
+- if (sl==0)
+- sl = conf->copies;
+- sl--;
+- d = r10_bio->devs[sl].devnum;
+- rdev = rcu_dereference(conf->mirrors[d].rdev);
+- if (rdev &&
+- test_bit(In_sync, &rdev->flags)) {
+- atomic_inc(&rdev->nr_pending);
+- rcu_read_unlock();
+- if (sync_page_io(rdev->bdev,
+- r10_bio->devs[sl].addr +
+- sect + rdev->data_offset,
+- s<<9, conf->tmppage, READ) == 0)
+- /* Well, this device is dead */
+- md_error(mddev, rdev);
+- else
+- printk(KERN_INFO "raid10:%s: read error corrected (%d sectors at %llu on %s)\n",
+- mdname(mddev), s, (unsigned long long)(sect+rdev->data_offset), bdevname(rdev->bdev, b));
+-
+- rdev_dec_pending(rdev, mddev);
+- rcu_read_lock();
+- }
+- }
+- rcu_read_unlock();
+- } else {
+- /* Cannot read from anywhere -- bye bye array */
+- md_error(mddev, conf->mirrors[r10_bio->devs[r10_bio->read_slot].devnum].rdev);
+- break;
+- }
+- sectors -= s;
+- sect += s;
++ if (mddev->ro == 0) {
++ freeze_array(conf);
++ fix_read_error(conf, mddev, r10_bio);
++ unfreeze_array(conf);
+ }
+
+- unfreeze_array(conf);
+-
+ bio = r10_bio->devs[r10_bio->read_slot].bio;
+ r10_bio->devs[r10_bio->read_slot].bio =
+ mddev->ro ? IO_BLOCKED : NULL;
+@@ -2018,8 +2057,6 @@ static int run(mddev_t *mddev)
+ mddev->queue->max_sectors = (PAGE_SIZE>>9);
+
+ disk->head_position = 0;
+- if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
+- conf->working_disks++;
+ }
+ conf->raid_disks = mddev->raid_disks;
+ conf->mddev = mddev;
+@@ -2042,7 +2079,7 @@ static int run(mddev_t *mddev)
+ disk = conf->mirrors + i;
+
+ if (!disk->rdev ||
+- !test_bit(In_sync, &rdev->flags)) {
++ !test_bit(In_sync, &disk->rdev->flags)) {
+ disk->head_position = 0;
+ mddev->degraded++;
+ }
+@@ -2077,6 +2114,8 @@ static int run(mddev_t *mddev)
+
+ mddev->queue->unplug_fn = raid10_unplug;
+ mddev->queue->issue_flush_fn = raid10_issue_flush;
++ mddev->queue->backing_dev_info.congested_fn = raid10_congested;
++ mddev->queue->backing_dev_info.congested_data = mddev;
+
+ /* Calculate max read-ahead size.
+ * We need to readahead at least twice a whole stripe....
+diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
+index 4500660..e14f457 100644
+--- a/drivers/md/raid5.c
++++ b/drivers/md/raid5.c
+@@ -636,7 +636,6 @@ static int raid5_end_write_request (stru
+ struct stripe_head *sh = bi->bi_private;
+ raid5_conf_t *conf = sh->raid_conf;
+ int disks = sh->disks, i;
+- unsigned long flags;
+ int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+
+ if (bi->bi_size)
+@@ -654,7 +653,6 @@ static int raid5_end_write_request (stru
+ return 0;
+ }
+
+- spin_lock_irqsave(&conf->device_lock, flags);
+ if (!uptodate)
+ md_error(conf->mddev, conf->disks[i].rdev);
+
+@@ -662,8 +660,7 @@ static int raid5_end_write_request (stru
+
+ clear_bit(R5_LOCKED, &sh->dev[i].flags);
+ set_bit(STRIPE_HANDLE, &sh->state);
+- __release_stripe(conf, sh);
+- spin_unlock_irqrestore(&conf->device_lock, flags);
++ release_stripe(sh);
+ return 0;
+ }
+
+@@ -696,12 +693,12 @@ static void error(mddev_t *mddev, mdk_rd
+ PRINTK("raid5: error called\n");
+
+ if (!test_bit(Faulty, &rdev->flags)) {
+- mddev->sb_dirty = 1;
+- if (test_bit(In_sync, &rdev->flags)) {
+- conf->working_disks--;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
++ if (test_and_clear_bit(In_sync, &rdev->flags)) {
++ unsigned long flags;
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded++;
+- conf->failed_disks++;
+- clear_bit(In_sync, &rdev->flags);
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ /*
+ * if recovery was running, make sure it aborts.
+ */
+@@ -711,7 +708,7 @@ static void error(mddev_t *mddev, mdk_rd
+ printk (KERN_ALERT
+ "raid5: Disk failure on %s, disabling device."
+ " Operation continuing on %d devices\n",
+- bdevname(rdev->bdev,b), conf->working_disks);
++ bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
+ }
+ }
+
+@@ -1108,7 +1105,7 @@ static void compute_parity6(struct strip
+ if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+ wake_up(&conf->wait_for_overlap);
+
+- if (sh->dev[i].written) BUG();
++ BUG_ON(sh->dev[i].written);
+ sh->dev[i].written = chosen;
+ }
+ break;
+@@ -1353,10 +1350,9 @@ static int page_is_zero(struct page *p)
+ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
+ {
+ int sectors_per_chunk = conf->chunk_size >> 9;
+- sector_t x = stripe;
+ int pd_idx, dd_idx;
+- int chunk_offset = sector_div(x, sectors_per_chunk);
+- stripe = x;
++ int chunk_offset = sector_div(stripe, sectors_per_chunk);
++
+ raid5_compute_sector(stripe*(disks-1)*sectors_per_chunk
+ + chunk_offset, disks, disks-1, &dd_idx, &pd_idx, conf);
+ return pd_idx;
+@@ -2597,6 +2593,24 @@ static int raid5_issue_flush(request_que
+ return ret;
+ }
+
++static int raid5_congested(void *data, int bits)
++{
++ mddev_t *mddev = data;
++ raid5_conf_t *conf = mddev_to_conf(mddev);
++
++ /* No difference between reads and writes. Just check
++ * how busy the stripe_cache is
++ */
++ if (conf->inactive_blocked)
++ return 1;
++ if (conf->quiesce)
++ return 1;
++ if (list_empty_careful(&conf->inactive_list))
++ return 1;
++
++ return 0;
++}
++
+ static int make_request(request_queue_t *q, struct bio * bi)
+ {
+ mddev_t *mddev = q->queuedata;
+@@ -2781,9 +2795,9 @@ static sector_t reshape_request(mddev_t
+ wait_event(conf->wait_for_overlap,
+ atomic_read(&conf->reshape_stripes)==0);
+ mddev->reshape_position = conf->expand_progress;
+- mddev->sb_dirty = 1;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+- wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
++ wait_event(mddev->sb_wait, mddev->flags == 0 ||
+ kthread_should_stop());
+ spin_lock_irq(&conf->device_lock);
+ conf->expand_lo = mddev->reshape_position;
+@@ -3074,6 +3088,7 @@ static int run(mddev_t *mddev)
+ mdk_rdev_t *rdev;
+ struct disk_info *disk;
+ struct list_head *tmp;
++ int working_disks = 0;
+
+ if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) {
+ printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n",
+@@ -3176,14 +3191,14 @@ static int run(mddev_t *mddev)
+ printk(KERN_INFO "raid5: device %s operational as raid"
+ " disk %d\n", bdevname(rdev->bdev,b),
+ raid_disk);
+- conf->working_disks++;
++ working_disks++;
+ }
+ }
+
+ /*
+ * 0 for a fully functional array, 1 or 2 for a degraded array.
+ */
+- mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks;
++ mddev->degraded = conf->raid_disks - working_disks;
+ conf->mddev = mddev;
+ conf->chunk_size = mddev->chunk_size;
+ conf->level = mddev->level;
+@@ -3218,7 +3233,7 @@ static int run(mddev_t *mddev)
+ if (mddev->degraded > conf->max_degraded) {
+ printk(KERN_ERR "raid5: not enough operational devices for %s"
+ " (%d/%d failed)\n",
+- mdname(mddev), conf->failed_disks, conf->raid_disks);
++ mdname(mddev), mddev->degraded, conf->raid_disks);
+ goto abort;
+ }
+
+@@ -3299,6 +3314,9 @@ static int run(mddev_t *mddev)
+
+ mddev->queue->unplug_fn = raid5_unplug_device;
+ mddev->queue->issue_flush_fn = raid5_issue_flush;
++ mddev->queue->backing_dev_info.congested_fn = raid5_congested;
++ mddev->queue->backing_dev_info.congested_data = mddev;
++
+ mddev->array_size = mddev->size * (conf->previous_raid_disks -
+ conf->max_degraded);
+
+@@ -3375,7 +3393,7 @@ static void status (struct seq_file *seq
+ int i;
+
+ seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
+- seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks);
++ seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded);
+ for (i = 0; i < conf->raid_disks; i++)
+ seq_printf (seq, "%s",
+ conf->disks[i].rdev &&
+@@ -3397,8 +3415,8 @@ static void print_raid5_conf (raid5_conf
+ printk("(conf==NULL)\n");
+ return;
+ }
+- printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks,
+- conf->working_disks, conf->failed_disks);
++ printk(" --- rd:%d wd:%d\n", conf->raid_disks,
++ conf->raid_disks - conf->mddev->degraded);
+
+ for (i = 0; i < conf->raid_disks; i++) {
+ char b[BDEVNAME_SIZE];
+@@ -3420,11 +3438,11 @@ static int raid5_spare_active(mddev_t *m
+ tmp = conf->disks + i;
+ if (tmp->rdev
+ && !test_bit(Faulty, &tmp->rdev->flags)
+- && !test_bit(In_sync, &tmp->rdev->flags)) {
++ && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
++ unsigned long flags;
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded--;
+- conf->failed_disks--;
+- conf->working_disks++;
+- set_bit(In_sync, &tmp->rdev->flags);
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ }
+ }
+ print_raid5_conf(conf);
+@@ -3560,6 +3578,7 @@ static int raid5_start_reshape(mddev_t *
+ struct list_head *rtmp;
+ int spares = 0;
+ int added_devices = 0;
++ unsigned long flags;
+
+ if (mddev->degraded ||
+ test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+@@ -3593,7 +3612,6 @@ static int raid5_start_reshape(mddev_t *
+ if (raid5_add_disk(mddev, rdev)) {
+ char nm[20];
+ set_bit(In_sync, &rdev->flags);
+- conf->working_disks++;
+ added_devices++;
+ rdev->recovery_offset = 0;
+ sprintf(nm, "rd%d", rdev->raid_disk);
+@@ -3602,10 +3620,12 @@ static int raid5_start_reshape(mddev_t *
+ break;
+ }
+
++ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices;
++ spin_unlock_irqrestore(&conf->device_lock, flags);
+ mddev->raid_disks = conf->raid_disks;
+ mddev->reshape_position = 0;
+- mddev->sb_dirty = 1;
++ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index ed4aa4e..9f7e1fe 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -54,6 +54,7 @@ config VIDEO_V4L1_COMPAT
+
+ config VIDEO_V4L2
+ bool
++ depends on VIDEO_DEV
+ default y
+
+ source "drivers/media/video/Kconfig"
+diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
+index 1a04db4..f33e5d9 100644
+--- a/drivers/media/common/Kconfig
++++ b/drivers/media/common/Kconfig
+@@ -4,7 +4,6 @@ config VIDEO_SAA7146
+
+ config VIDEO_SAA7146_VV
+ tristate
+- select VIDEO_V4L2
+ select VIDEO_BUF
+ select VIDEO_VIDEOBUF
+ select VIDEO_SAA7146
+diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
+index ca98d94..db75344 100644
+--- a/drivers/media/common/ir-keymaps.c
++++ b/drivers/media/common/ir-keymaps.c
+@@ -32,6 +32,37 @@ IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_
+
+ EXPORT_SYMBOL_GPL(ir_codes_empty);
+
++/* Michal Majchrowicz <mmajchrowicz at gmail.com> */
++IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE] = {
++ /* numeric */
++ [ 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,
++
++ [ 0x5c ] = KEY_POWER, /* power */
++ [ 0x20 ] = KEY_F, /* full screen */
++ [ 0x0f ] = KEY_BACKSPACE, /* recall */
++ [ 0x1b ] = KEY_ENTER, /* mute */
++ [ 0x41 ] = KEY_RECORD, /* record */
++ [ 0x43 ] = KEY_STOP, /* stop */
++ [ 0x16 ] = KEY_S,
++ [ 0x1a ] = KEY_Q, /* off */
++ [ 0x2e ] = KEY_RED,
++ [ 0x1f ] = KEY_DOWN, /* channel - */
++ [ 0x1c ] = KEY_UP, /* channel + */
++ [ 0x10 ] = KEY_LEFT, /* volume - */
++ [ 0x1e ] = KEY_RIGHT, /* volume + */
++ [ 0x14 ] = KEY_F1,
++};
++
++EXPORT_SYMBOL_GPL(ir_codes_proteus_2309);
+ /* Matt Jesson <dvb at jesson.eclipse.co.uk */
+ IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
+ [ 0x28 ] = KEY_0, //'0' / 'enter'
+@@ -1473,3 +1504,51 @@ IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTA
+ };
+
+ EXPORT_SYMBOL_GPL(ir_codes_npgtech);
++
++/* Norwood Micro (non-Pro) TV Tuner
++ By Peter Naulls <peter at chocky.org>
++ Key comments are the functions given in the manual */
++IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
++ /* Keys 0 to 9 */
++ [ 0x20 ] = KEY_0,
++ [ 0x21 ] = KEY_1,
++ [ 0x22 ] = KEY_2,
++ [ 0x23 ] = KEY_3,
++ [ 0x24 ] = KEY_4,
++ [ 0x25 ] = KEY_5,
++ [ 0x26 ] = KEY_6,
++ [ 0x27 ] = KEY_7,
++ [ 0x28 ] = KEY_8,
++ [ 0x29 ] = KEY_9,
++
++ [ 0x78 ] = KEY_TUNER, /* Video Source */
++ [ 0x2c ] = KEY_EXIT, /* Open/Close software */
++ [ 0x2a ] = KEY_SELECT, /* 2 Digit Select */
++ [ 0x69 ] = KEY_AGAIN, /* Recall */
++
++ [ 0x32 ] = KEY_BRIGHTNESSUP, /* Brightness increase */
++ [ 0x33 ] = KEY_BRIGHTNESSDOWN, /* Brightness decrease */
++ [ 0x6b ] = KEY_KPPLUS, /* (not named >>>>>) */
++ [ 0x6c ] = KEY_KPMINUS, /* (not named <<<<<) */
++
++ [ 0x2d ] = KEY_MUTE, /* Mute */
++ [ 0x30 ] = KEY_VOLUMEUP, /* Volume up */
++ [ 0x31 ] = KEY_VOLUMEDOWN, /* Volume down */
++ [ 0x60 ] = KEY_CHANNELUP, /* Channel up */
++ [ 0x61 ] = KEY_CHANNELDOWN, /* Channel down */
++
++ [ 0x3f ] = KEY_RECORD, /* Record */
++ [ 0x37 ] = KEY_PLAY, /* Play */
++ [ 0x36 ] = KEY_PAUSE, /* Pause */
++ [ 0x2b ] = KEY_STOP, /* Stop */
++ [ 0x67 ] = KEY_FASTFORWARD, /* Foward */
++ [ 0x66 ] = KEY_REWIND, /* Rewind */
++ [ 0x3e ] = KEY_SEARCH, /* Auto Scan */
++ [ 0x2e ] = KEY_CAMERA, /* Capture Video */
++ [ 0x6d ] = KEY_MENU, /* Show/Hide Control */
++ [ 0x2f ] = KEY_ZOOM, /* Full Screen */
++ [ 0x34 ] = KEY_RADIO, /* FM */
++ [ 0x65 ] = KEY_POWER, /* Computer power */
++};
++
++EXPORT_SYMBOL_GPL(ir_codes_norwood);
+diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
+index b88451e..86cbdbc 100644
+--- a/drivers/media/common/saa7146_core.c
++++ b/drivers/media/common/saa7146_core.c
+@@ -230,7 +230,7 @@ int saa7146_pgtable_build_single(struct
+
+ /********************************************************************************/
+ /* interrupt handler */
+-static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t interrupt_hw(int irq, void *dev_id)
+ {
+ struct saa7146_dev *dev = dev_id;
+ u32 isr = 0;
+diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
+index 0027acc..d867a6a 100644
+--- a/drivers/media/common/saa7146_fops.c
++++ b/drivers/media/common/saa7146_fops.c
+@@ -455,7 +455,6 @@ static void vv_callback(struct saa7146_d
+
+ static struct video_device device_template =
+ {
+- .hardware = VID_HARDWARE_SAA7146,
+ .fops = &video_fops,
+ .minor = -1,
+ };
+diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
+index d9953f7..5297a36 100644
+--- a/drivers/media/common/saa7146_i2c.c
++++ b/drivers/media/common/saa7146_i2c.c
+@@ -217,11 +217,9 @@ static int saa7146_i2c_writeout(struct s
+ }
+ /* wait until we get a transfer done or error */
+ timeout = jiffies + HZ/100 + 1; /* 10ms */
++ /* first read usually delivers bogus results... */
++ saa7146_i2c_status(dev);
+ while(1) {
+- /**
+- * first read usually delivers bogus results...
+- */
+- saa7146_i2c_status(dev);
+ status = saa7146_i2c_status(dev);
+ if ((status & 0x3) != 1)
+ break;
+@@ -232,10 +230,10 @@ static int saa7146_i2c_writeout(struct s
+ DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n"));
+ return -EIO;
+ }
+- if ((++trial < 20) && short_delay)
++ if (++trial < 50 && short_delay)
+ udelay(10);
+ else
+- msleep(1);
++ msleep(1);
+ }
+ }
+
+diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
+index 49a06fc..a0dcd59 100644
+--- a/drivers/media/dvb/b2c2/Kconfig
++++ b/drivers/media/dvb/b2c2/Kconfig
+@@ -2,13 +2,13 @@ config DVB_B2C2_FLEXCOP
+ tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
+ depends on DVB_CORE && I2C
+ select DVB_PLL
+- select DVB_STV0299
+- select DVB_MT352
+- select DVB_MT312
+- select DVB_NXT200X
+- select DVB_STV0297
+- select DVB_BCM3510
+- select DVB_LGDT330X
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
++ select DVB_MT312 if !DVB_FE_CUSTOMISE
++ select DVB_NXT200X if !DVB_FE_CUSTOMISE
++ select DVB_STV0297 if !DVB_FE_CUSTOMISE
++ select DVB_BCM3510 if !DVB_FE_CUSTOMISE
++ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ help
+ Support for the digital TV receiver chip made by B2C2 Inc. included in
+ Technisats PCI cards and USB boxes.
+diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+index 3be87c7..b8ba878 100644
+--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
++++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+@@ -505,7 +505,7 @@ int flexcop_frontend_init(struct flexcop
+ struct dvb_frontend_ops *ops;
+
+ /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
+- if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
++ if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
+@@ -519,36 +519,36 @@ int flexcop_frontend_init(struct flexcop
+ info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
+ } else
+ /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
+- if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
++ if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
+ fc->dev_type = FC_AIR_DVB;
+ fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
+ info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
+ } else
+ /* try the air atsc 2nd generation (nxt2002) */
+- if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
++ if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
+ fc->dev_type = FC_AIR_ATSC2;
+- dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
++ dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+ info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
+ } else
+ /* try the air atsc 3nd generation (lgdt3303) */
+- if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
++ if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
+ fc->dev_type = FC_AIR_ATSC3;
+ fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_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) {
++ if ((fc->fe = dvb_attach(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)) != NULL) {
++ if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
+ fc->dev_type = FC_CABLE;
+ fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+ info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
+ } else
+ /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
+- if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
++ if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
+@@ -571,9 +571,7 @@ int flexcop_frontend_init(struct flexcop
+ } else {
+ if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
+ err("frontend registration failed!");
+- ops = &fc->fe->ops;
+- if (ops->release != NULL)
+- ops->release(fc->fe);
++ dvb_frontend_detach(fc->fe);
+ fc->fe = NULL;
+ return -EINVAL;
+ }
+@@ -584,8 +582,10 @@ int flexcop_frontend_init(struct flexcop
+
+ void flexcop_frontend_exit(struct flexcop_device *fc)
+ {
+- if (fc->init_state & FC_STATE_FE_INIT)
++ if (fc->init_state & FC_STATE_FE_INIT) {
+ dvb_unregister_frontend(fc->fe);
++ dvb_frontend_detach(fc->fe);
++ }
+
+ fc->init_state &= ~FC_STATE_FE_INIT;
+ }
+diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
+index eb2e643..0689324 100644
+--- a/drivers/media/dvb/b2c2/flexcop-pci.c
++++ b/drivers/media/dvb/b2c2/flexcop-pci.c
+@@ -122,7 +122,7 @@ static void flexcop_pci_irq_check_work(v
+ /* 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_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
+ {
+ struct flexcop_pci *fc_pci = dev_id;
+ struct flexcop_device *fc = fc_pci->fc_dev;
+diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
+index 515954f..2853ea1 100644
+--- a/drivers/media/dvb/b2c2/flexcop-usb.c
++++ b/drivers/media/dvb/b2c2/flexcop-usb.c
+@@ -328,7 +328,7 @@ static void flexcop_usb_process_frame(st
+ fc_usb->tmp_buffer_length = l;
+ }
+
+-static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
++static void flexcop_usb_urb_complete(struct urb *urb)
+ {
+ struct flexcop_usb *fc_usb = urb->context;
+ int i;
+diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
+index 7d0ee1a..ae2ff5d 100644
+--- a/drivers/media/dvb/bt8xx/Kconfig
++++ b/drivers/media/dvb/bt8xx/Kconfig
+@@ -2,13 +2,13 @@ config DVB_BT8XX
+ tristate "BT8xx based PCI cards"
+ depends on DVB_CORE && PCI && I2C && VIDEO_BT848
+ select DVB_PLL
+- select DVB_MT352
+- select DVB_SP887X
+- select DVB_NXT6000
+- select DVB_CX24110
+- select DVB_OR51211
+- select DVB_LGDT330X
+- select DVB_ZL10353
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
++ select DVB_SP887X if !DVB_FE_CUSTOMISE
++ select DVB_NXT6000 if !DVB_FE_CUSTOMISE
++ select DVB_CX24110 if !DVB_FE_CUSTOMISE
++ select DVB_OR51211 if !DVB_FE_CUSTOMISE
++ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
++ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ Support for PCI cards based on the Bt8xx PCI bridge. Examples are
+diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
+index 755822e..329a51c 100644
+--- a/drivers/media/dvb/bt8xx/bt878.c
++++ b/drivers/media/dvb/bt8xx/bt878.c
+@@ -266,7 +266,7 @@ EXPORT_SYMBOL(bt878_stop);
+ /* Interrupt service routine */
+ /*****************************/
+
+-static irqreturn_t bt878_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bt878_irq(int irq, void *dev_id)
+ {
+ u32 stat, astat, mask;
+ int count;
+diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
+index 06ac899..9f72b70 100644
+--- a/drivers/media/dvb/bt8xx/dst.c
++++ b/drivers/media/dvb/bt8xx/dst.c
+@@ -1715,6 +1715,15 @@ static int dst_get_frontend(struct dvb_f
+ static void dst_release(struct dvb_frontend *fe)
+ {
+ struct dst_state *state = fe->demodulator_priv;
++ if (state->dst_ca) {
++ dvb_unregister_device(state->dst_ca);
++#ifdef CONFIG_DVB_CORE_ATTACH
++ symbol_put(dst_ca_attach);
++#endif
++ }
++#ifdef CONFIG_DVB_CORE_ATTACH
++ symbol_put(dst_attach);
++#endif
+ kfree(state);
+ }
+
+diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
+index fa923b9..240ad08 100644
+--- a/drivers/media/dvb/bt8xx/dst_ca.c
++++ b/drivers/media/dvb/bt8xx/dst_ca.c
+@@ -699,12 +699,17 @@ static struct dvb_device dvbdev_ca = {
+ .fops = &dst_ca_fops
+ };
+
+-int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
++struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
+ {
+ struct dvb_device *dvbdev;
++
+ dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
+- dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA);
+- return 0;
++ if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
++ dst->dst_ca = dvbdev;
++ return dst->dst_ca;
++ }
++
++ return NULL;
+ }
+
+ EXPORT_SYMBOL(dst_ca_attach);
+diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
+index 0677b04..3bf084f 100644
+--- a/drivers/media/dvb/bt8xx/dst_common.h
++++ b/drivers/media/dvb/bt8xx/dst_common.h
+@@ -140,6 +140,7 @@ struct dst_state {
+ char *tuner_name;
+ struct mutex dst_mutex;
+ u8 fw_name[8];
++ struct dvb_device *dst_ca;
+ };
+
+ struct tuner_types {
+@@ -178,7 +179,7 @@ int write_dst(struct dst_state *state, u
+ int read_dst(struct dst_state *state, u8 * ret, u8 len);
+ u8 dst_check_sum(u8 * buf, u32 len);
+ struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
+-int dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
++struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
+ int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
+
+ int dst_command(struct dst_state* state, u8 * data, u8 len);
+diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+index b715b97..14e69a7 100644
+--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
++++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+@@ -67,7 +67,7 @@ static void dvb_bt8xx_task(unsigned long
+
+ static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+ {
+- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
++ struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
+ struct dvb_bt8xx_card *card = dvbdmx->priv;
+ int rc;
+
+@@ -595,15 +595,14 @@ static void lgdt330x_reset(struct dvb_bt
+
+ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
+ {
+- int ret;
+ struct dst_state* state = NULL;
+
+ switch(type) {
+ case BTTV_BOARD_DVICO_DVBT_LITE:
+- card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
++ card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
+
+ if (card->fe == NULL)
+- card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
++ card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
+ card->i2c_adapter);
+
+ if (card->fe != NULL) {
+@@ -615,7 +614,7 @@ static void frontend_init(struct dvb_bt8
+
+ case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+ lgdt330x_reset(card);
+- card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
++ card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
+ dprintk ("dvb_bt8xx: lgdt330x detected\n");
+@@ -630,7 +629,7 @@ static void frontend_init(struct dvb_bt8
+
+ /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
+ digitv_alps_tded4_reset(card);
+- card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
++ card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
+ dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
+@@ -639,7 +638,7 @@ static void frontend_init(struct dvb_bt8
+
+ /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
+ digitv_alps_tded4_reset(card);
+- card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
++ card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
+
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
+@@ -648,14 +647,14 @@ static void frontend_init(struct dvb_bt8
+ break;
+
+ case BTTV_BOARD_AVDVBT_761:
+- card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter);
++ card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+ }
+ break;
+
+ case BTTV_BOARD_AVDVBT_771:
+- card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
++ card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+@@ -666,26 +665,29 @@ static void frontend_init(struct dvb_bt8
+ case BTTV_BOARD_TWINHAN_DST:
+ /* DST is not a frontend driver !!! */
+ state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL);
++ if (!state) {
++ printk("dvb_bt8xx: No memory\n");
++ break;
++ }
+ /* Setup the Card */
+ state->config = &dst_config;
+ state->i2c = card->i2c_adapter;
+ state->bt = card->bt;
+-
++ state->dst_ca = NULL;
+ /* DST is not a frontend, attaching the ASIC */
+- if ((dst_attach(state, &card->dvb_adapter)) == NULL) {
++ if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
+ printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__);
+ break;
+ }
+- card->fe = &state->frontend;
+-
+ /* Attach other DST peripherals if any */
+ /* Conditional Access device */
++ card->fe = &state->frontend;
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+- ret = dst_ca_attach(state, &card->dvb_adapter);
++ dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
+ break;
+
+ case BTTV_BOARD_PINNACLESAT:
+- card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
++ card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+ card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+@@ -694,7 +696,7 @@ static void frontend_init(struct dvb_bt8
+ break;
+
+ case BTTV_BOARD_PC_HDTV:
+- card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
++ card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+ break;
+ }
+
+@@ -707,8 +709,7 @@ static void frontend_init(struct dvb_bt8
+ else
+ if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
+ printk("dvb-bt8xx: Frontend registration failed!\n");
+- if (card->fe->ops.release)
+- card->fe->ops.release(card->fe);
++ dvb_frontend_detach(card->fe);
+ card->fe = NULL;
+ }
+ }
+@@ -925,8 +926,10 @@ static void dvb_bt8xx_remove(struct bttv
+ card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
+ dvb_dmxdev_release(&card->dmxdev);
+ dvb_dmx_release(&card->demux);
+- if (card->fe)
++ if (card->fe) {
+ dvb_unregister_frontend(card->fe);
++ dvb_frontend_detach(card->fe);
++ }
+ dvb_unregister_adapter(&card->dvb_adapter);
+
+ kfree(card);
+diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
+index b5cdd57..3d778c5 100644
+--- a/drivers/media/dvb/cinergyT2/Kconfig
++++ b/drivers/media/dvb/cinergyT2/Kconfig
+@@ -56,7 +56,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL
+ measurements.
+
+ Please keep in mind that these updates cause traffic on the tuner
+- control bus and thus may or may not affect receiption sensitivity.
++ control bus and thus may or may not affect reception sensitivity.
+
+ The default value should be a safe choice for common applications.
+
+diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
+index 001c71b..ff7d4f5 100644
+--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
++++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
+@@ -238,7 +238,7 @@ static void cinergyt2_sleep (struct cine
+ cinergyt2->sleeping = sleep;
+ }
+
+-static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs);
++static void cinergyt2_stream_irq (struct urb *urb);
+
+ static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
+ {
+@@ -258,7 +258,7 @@ static int cinergyt2_submit_stream_urb (
+ return err;
+ }
+
+-static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs)
++static void cinergyt2_stream_irq (struct urb *urb)
+ {
+ struct cinergyt2 *cinergyt2 = urb->context;
+
+@@ -981,7 +981,7 @@ static int cinergyt2_suspend (struct usb
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+ return -ERESTARTSYS;
+
+- if (state.event > PM_EVENT_ON) {
++ if (1) {
+ struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
+
+ cinergyt2_suspend_rc(cinergyt2);
+diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
+index 12ee912..1990eda 100644
+--- a/drivers/media/dvb/dvb-core/Kconfig
++++ b/drivers/media/dvb/dvb-core/Kconfig
+@@ -9,3 +9,16 @@ config DVB_CORE
+ in-kernel drivers will select this automatically if needed.
+ If unsure say N.
+
++config DVB_CORE_ATTACH
++ bool "Load and attach frontend modules as needed"
++ depends on DVB_CORE
++ depends on MODULES
++ help
++ Remove the static dependency of DVB card drivers on all
++ frontend modules for all possible card variants. Instead,
++ allow the card drivers to only load the frontend modules
++ they require. This saves several KBytes of memory.
++
++ Note: You will need module-init-tools v3.2 or later for this feature.
++
++ If unsure say Y.
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
+index 57b34cd..53304e6 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
+@@ -1014,6 +1014,13 @@ static int dvb_frontend_open(struct inod
+ if ((ret = dvb_generic_open (inode, file)) < 0)
+ return ret;
+
++ if (fe->ops.ts_bus_ctrl) {
++ if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) {
++ dvb_generic_release (inode, file);
++ return ret;
++ }
++ }
++
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+
+ /* normal tune mode when opened R/W */
+@@ -1043,6 +1050,9 @@ static int dvb_frontend_release(struct i
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+ fepriv->release_jiffies = jiffies;
+
++ if (fe->ops.ts_bus_ctrl)
++ fe->ops.ts_bus_ctrl (fe, 0);
++
+ return dvb_generic_release (inode, file);
+ }
+
+@@ -1105,18 +1115,42 @@ int dvb_unregister_frontend(struct dvb_f
+ mutex_lock(&frontend_mutex);
+ dvb_unregister_device (fepriv->dvbdev);
+ dvb_frontend_stop (fe);
+- if (fe->ops.tuner_ops.release) {
+- fe->ops.tuner_ops.release(fe);
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 0);
+- }
+- if (fe->ops.release)
+- fe->ops.release(fe);
+- else
+- printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
++
+ /* fe is invalid now */
+ kfree(fepriv);
+ mutex_unlock(&frontend_mutex);
+ return 0;
+ }
+ EXPORT_SYMBOL(dvb_unregister_frontend);
++
++#ifdef CONFIG_DVB_CORE_ATTACH
++void dvb_frontend_detach(struct dvb_frontend* fe)
++{
++ void *ptr;
++
++ if (fe->ops.release_sec) {
++ fe->ops.release_sec(fe);
++ symbol_put_addr(fe->ops.release_sec);
++ }
++ if (fe->ops.tuner_ops.release) {
++ fe->ops.tuner_ops.release(fe);
++ symbol_put_addr(fe->ops.tuner_ops.release);
++ }
++ ptr = (void*)fe->ops.release;
++ if (ptr) {
++ fe->ops.release(fe);
++ symbol_put_addr(ptr);
++ }
++}
++#else
++void dvb_frontend_detach(struct dvb_frontend* fe)
++{
++ if (fe->ops.release_sec)
++ fe->ops.release_sec(fe);
++ if (fe->ops.tuner_ops.release)
++ fe->ops.tuner_ops.release(fe);
++ if (fe->ops.release)
++ fe->ops.release(fe);
++}
++#endif
++EXPORT_SYMBOL(dvb_frontend_detach);
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
+index 2887e2b..f233d78 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
+@@ -92,10 +92,13 @@ struct dvb_frontend_ops {
+ struct dvb_frontend_info info;
+
+ void (*release)(struct dvb_frontend* fe);
++ void (*release_sec)(struct dvb_frontend* fe);
+
+ int (*init)(struct dvb_frontend* fe);
+ int (*sleep)(struct dvb_frontend* fe);
+
++ int (*write)(struct dvb_frontend* fe, u8* buf, int len);
++
+ /* if this is set, it overrides the default swzigzag */
+ int (*tune)(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params,
+@@ -126,6 +129,7 @@ struct dvb_frontend_ops {
+ int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+ int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+ int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
++ int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
+
+ struct dvb_tuner_ops tuner_ops;
+ };
+@@ -147,7 +151,7 @@ struct dvb_frontend {
+ void* demodulator_priv;
+ void* tuner_priv;
+ void* frontend_priv;
+- void* misc_priv;
++ void* sec_priv;
+ };
+
+ extern int dvb_register_frontend(struct dvb_adapter* dvb,
+@@ -155,6 +159,8 @@ extern int dvb_register_frontend(struct
+
+ extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+
++extern void dvb_frontend_detach(struct dvb_frontend* fe);
++
+ extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
+
+ extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+index c972fe0..9878183 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+@@ -26,7 +26,6 @@
+
+
+
+-#define __KERNEL_SYSCALLS__
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
+index 7a7f75f..620e788 100644
+--- a/drivers/media/dvb/dvb-core/dvbdev.h
++++ b/drivers/media/dvb/dvb-core/dvbdev.h
+@@ -102,4 +102,26 @@ extern int dvb_usercopy(struct inode *in
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg));
+
++/** generic DVB attach function. */
++#ifdef CONFIG_DVB_CORE_ATTACH
++#define dvb_attach(FUNCTION, ARGS...) ({ \
++ void *__r = NULL; \
++ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
++ if (__a) { \
++ __r = (void *) __a(ARGS); \
++ if (__r == NULL) \
++ symbol_put(FUNCTION); \
++ } else { \
++ printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
++ } \
++ __r; \
++})
++
++#else
++#define dvb_attach(FUNCTION, ARGS...) ({ \
++ FUNCTION(ARGS); \
++})
++
++#endif
++
+ #endif /* #ifndef _DVBDEV_H_ */
+diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
+index 75824b7..a263b3f 100644
+--- a/drivers/media/dvb/dvb-usb/Kconfig
++++ b/drivers/media/dvb/dvb-usb/Kconfig
+@@ -26,6 +26,7 @@ config DVB_USB_A800
+ tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
++ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
+
+@@ -33,24 +34,13 @@ 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
++ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ 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:
+- Artec T1 USB1.1 boxes
+- Avermedia AverTV DVBT USB1.1
+- Compro Videomate DVB-U2000 - DVB-T USB
+- DiBcom USB1.1 reference devices (non-public)
+- Grandtec DVB-T USB
+- Hama DVB-T USB1.1-Box
+- KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+- TwinhanDTV Magic Box (VP7041e)
+- TwinhanDTV USB-Ter (VP7041)
+- Ultima Electronic/Artec T1 USB TVBOX
+-
+- The VP7041 seems to be identical to "CTS Portable" (Chinese
+- Television System).
++ For an up-to-date list of devices supported by this driver, have a look
++ on the Linux-DVB Wiki at www.linuxtv.org.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+@@ -65,13 +55,30 @@ 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
++ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ help
+- Support for 2.0 DVB-T receivers based on reference designs made by
++ Support for USB2.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:
+- Artec T1 USB2.0 boxes
+- DiBcom USB2.0 reference devices (non-public)
++ For an up-to-date list of devices supported by this driver, have a look
++ on the Linux-DVB Wiki at www.linuxtv.org.
++
++ Say Y if you own such a device and want to use it. You should build it as
++ a module.
++
++config DVB_USB_DIB0700
++ tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
++ depends on DVB_USB
++ select DVB_DIB3000MC
++ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
++ help
++ Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
++ USB bridge is also present in devices having the DiB7700 DVB-T-USB
++ silicon. This chip can be found in devices offered by Hauppauge,
++ Avermedia and other big and small companies.
++
++ For an up-to-date list of devices supported by this driver, have a look
++ on the Linux-DVB Wiki at www.linuxtv.org.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+@@ -80,16 +87,17 @@ config DVB_USB_UMT_010
+ tristate "HanfTek UMT-010 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_DIB3000MC
++ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+
+ config DVB_USB_CXUSB
+ tristate "Conexant USB2.0 hybrid reference design support"
+ depends on DVB_USB
+- select DVB_CX22702
+- select DVB_LGDT330X
+- select DVB_MT352
+- select DVB_ZL10353
++ select DVB_CX22702 if !DVB_FE_CUSTOMISE
++ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
++ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Conexant USB2.0 hybrid reference design.
+ Currently, only DVB and ATSC modes are supported, analog mode
+@@ -101,8 +109,8 @@ config DVB_USB_CXUSB
+ config DVB_USB_DIGITV
+ tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
+ depends on DVB_USB
+- select DVB_NXT6000
+- select DVB_MT352
++ select DVB_NXT6000 if !DVB_FE_CUSTOMISE
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
+
+@@ -145,6 +153,7 @@ config DVB_USB_NOVA_T_USB2
+ tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_DIB3000MC
++ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+
+diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
+index 9643f56..e239107 100644
+--- a/drivers/media/dvb/dvb-usb/Makefile
++++ b/drivers/media/dvb/dvb-usb/Makefile
+@@ -1,4 +1,4 @@
+-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
++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 usb-urb.o
+ obj-$(CONFIG_DVB_USB) += dvb-usb.o
+
+ dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
+@@ -36,4 +36,7 @@ obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-
+ dvb-usb-cxusb-objs = cxusb.o
+ obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+
++dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
++obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.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
+index ce44aa6..2ed3eb6 100644
+--- a/drivers/media/dvb/dvb-usb/a800.c
++++ b/drivers/media/dvb/dvb-usb/a800.c
+@@ -26,6 +26,14 @@ static int a800_power_ctrl(struct dvb_us
+ return 0;
+ }
+
++/* assure to put cold to 0 for iManufacturer == 1 */
++static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
++ struct dvb_usb_device_description **desc, int *cold)
++{
++ *cold = udev->descriptor.iManufacturer != 1;
++ return 0;
++}
++
+ static struct dvb_usb_rc_key a800_rc_keys[] = {
+ { 0x02, 0x01, KEY_PROG1 }, /* SOURCE */
+ { 0x02, 0x00, KEY_POWER }, /* POWER */
+@@ -81,7 +89,7 @@ static int a800_rc_query(struct dvb_usb_
+ }
+
+ /* USB Driver stuff */
+-static struct dvb_usb_properties a800_properties;
++static struct dvb_usb_device_properties a800_properties;
+
+ static int a800_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -97,34 +105,27 @@ static struct usb_device_id a800_table [
+ };
+ 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,
++static struct dvb_usb_device_properties a800_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+-
+ .firmware = "dvb-usb-avertv-a800-02.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
+-
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
++ .pid_filter_count = 32,
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+@@ -134,6 +135,21 @@ static struct dvb_usb_properties a800_pr
+ }
+ },
+
++ .size_of_priv = sizeof(struct dibusb_state),
++ },
++ },
++
++ .power_ctrl = a800_power_ctrl,
++ .identify_state = a800_identify_state,
++
++ .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,
+ .num_device_descs = 1,
+ .devices = {
+ { "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
+index ae23bdd..43f3906 100644
+--- a/drivers/media/dvb/dvb-usb/cxusb.c
++++ b/drivers/media/dvb/dvb-usb/cxusb.c
+@@ -161,13 +161,13 @@ static int cxusb_bluebird_power_ctrl(str
+ return 0;
+ }
+
+-static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
++static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+ u8 buf[2] = { 0x03, 0x00 };
+ if (onoff)
+- cxusb_ctrl_msg(d,CMD_STREAMING_ON, buf, 2, NULL, 0);
++ cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0);
+ else
+- cxusb_ctrl_msg(d,CMD_STREAMING_OFF, NULL, 0, NULL, 0);
++ cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+
+ return 0;
+ }
+@@ -327,8 +327,8 @@ static int cxusb_mt352_demod_init(struct
+ static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+ {
+- struct dvb_usb_device *d = fe->dvb->priv;
+- return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
++ return lg_h06xf_pll_set(fe, &adap->dev->i2c_adap, fep);
+ }
+
+ static struct cx22702_config cxusb_cx22702_config = {
+@@ -349,6 +349,7 @@ static struct mt352_config cxusb_dee1601
+
+ static struct zl10353_config cxusb_zl10353_dee1601_config = {
+ .demod_address = 0x0f,
++ .parallel_ts = 1,
+ };
+
+ static struct mt352_config cxusb_mt352_config = {
+@@ -358,98 +359,99 @@ static struct mt352_config cxusb_mt352_c
+ };
+
+ /* Callbacks for DVB USB */
+-static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
++static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+ u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+- d->pll_addr = 0x61;
+- memcpy(d->pll_init, bpll, 4);
+- d->pll_desc = &dvb_pll_fmd1216me;
++ adap->pll_addr = 0x61;
++ memcpy(adap->pll_init, bpll, 4);
++ adap->pll_desc = &dvb_pll_fmd1216me;
+
+- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
++ adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
++ adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
+ return 0;
+ }
+
+-static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
++static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+- d->pll_addr = 0x61;
+- d->pll_desc = &dvb_pll_thomson_dtt7579;
+- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
++ adap->pll_addr = 0x61;
++ adap->pll_desc = &dvb_pll_thomson_dtt7579;
++ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+ }
+
+-static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d)
++static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+- d->pll_addr = 0x61;
+- d->pll_desc = &dvb_pll_lg_z201;
+- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
++ adap->pll_addr = 0x61;
++ adap->pll_desc = &dvb_pll_lg_z201;
++ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+ }
+
+-static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d)
++static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+- d->pll_addr = 0x60;
+- d->pll_desc = &dvb_pll_thomson_dtt7579;
+- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
++ adap->pll_addr = 0x60;
++ adap->pll_desc = &dvb_pll_thomson_dtt7579;
++ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+ }
+
+-static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
++static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+- d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
++ adap->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
+ return 0;
+ }
+
+-static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
++static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+ u8 b;
+- if (usb_set_interface(d->udev,0,6) < 0)
++ if (usb_set_interface(adap->dev->udev, 0, 6) < 0)
+ err("set interface failed");
+
+- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1);
++ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
+
+- if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
++ if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+ }
+
+-static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_device *d)
++static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- if (usb_set_interface(d->udev,0,7) < 0)
++ if (usb_set_interface(adap->dev->udev, 0, 7) < 0)
+ err("set interface failed");
+
+- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
++ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+- if ((d->fe = lgdt330x_attach(&cxusb_lgdt3303_config, &d->i2c_adap)) != NULL)
++ if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+ }
+
+-static int cxusb_mt352_frontend_attach(struct dvb_usb_device *d)
+-{ /* used in both lgz201 and th7579 */
+- if (usb_set_interface(d->udev,0,0) < 0)
++static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
++{
++ /* used in both lgz201 and th7579 */
++ if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
+ err("set interface failed");
+
+- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
++ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+- if ((d->fe = mt352_attach(&cxusb_mt352_config, &d->i2c_adap)) != NULL)
++ if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+ }
+
+-static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
++static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- if (usb_set_interface(d->udev,0,0) < 0)
++ if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
+ err("set interface failed");
+
+- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
++ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+- if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+- ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
++ if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap)) != NULL) ||
++ ((adap->fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap)) != NULL))
+ return 0;
+
+ return -EIO;
+@@ -479,11 +481,11 @@ static int bluebird_patch_dvico_firmware
+ }
+
+ /* DVB USB Driver stuff */
+-static struct dvb_usb_properties cxusb_medion_properties;
+-static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
+-static struct dvb_usb_properties cxusb_bluebird_dee1601_properties;
+-static struct dvb_usb_properties cxusb_bluebird_lgz201_properties;
+-static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties;
++static struct dvb_usb_device_properties cxusb_medion_properties;
++static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
++static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
++static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
++static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
+
+ static int cxusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -503,36 +505,36 @@ static struct usb_device_id cxusb_table
+ { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
+- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
++ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
++ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
+- { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD) },
+- { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM) },
++ { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
++ { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
++ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
++ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
+ {} /* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE (usb, cxusb_table);
+
+-static struct dvb_usb_properties cxusb_medion_properties = {
++static struct dvb_usb_device_properties cxusb_medion_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .streaming_ctrl = cxusb_streaming_ctrl,
+- .power_ctrl = cxusb_power_ctrl,
+ .frontend_attach = cxusb_cx22702_frontend_attach,
+ .tuner_attach = cxusb_fmd1216me_tuner_attach,
+-
+- .i2c_algo = &cxusb_i2c_algo,
+-
+- .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+@@ -542,6 +544,14 @@ static struct dvb_usb_properties cxusb_m
+ }
+ },
+
++ },
++ },
++ .power_ctrl = cxusb_power_ctrl,
++
++ .i2c_algo = &cxusb_i2c_algo,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
++
+ .num_device_descs = 1,
+ .devices = {
+ { "Medion MD95700 (MDUSBTV-HYBRID)",
+@@ -551,7 +561,7 @@ static struct dvb_usb_properties cxusb_m
+ }
+ };
+
+-static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
++static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+@@ -562,22 +572,16 @@ static struct dvb_usb_properties cxusb_b
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .streaming_ctrl = cxusb_streaming_ctrl,
+- .power_ctrl = cxusb_bluebird_power_ctrl,
+ .frontend_attach = cxusb_lgdt3303_frontend_attach,
+ .tuner_attach = cxusb_lgdt3303_tuner_attach,
+
+- .i2c_algo = &cxusb_i2c_algo,
+-
+- .rc_interval = 100,
+- .rc_key_map = dvico_portable_rc_keys,
+- .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
+- .rc_query = cxusb_rc_query,
+-
+- .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+@@ -586,6 +590,19 @@ static struct dvb_usb_properties cxusb_b
+ }
+ }
+ },
++ },
++ },
++
++ .power_ctrl = cxusb_bluebird_power_ctrl,
++
++ .i2c_algo = &cxusb_i2c_algo,
++
++ .rc_interval = 100,
++ .rc_key_map = dvico_portable_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
++ .rc_query = cxusb_rc_query,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+@@ -596,7 +613,7 @@ static struct dvb_usb_properties cxusb_b
+ }
+ };
+
+-static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
++static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+@@ -607,22 +624,15 @@ static struct dvb_usb_properties cxusb_b
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .streaming_ctrl = cxusb_streaming_ctrl,
+- .power_ctrl = cxusb_bluebird_power_ctrl,
+ .frontend_attach = cxusb_dee1601_frontend_attach,
+ .tuner_attach = cxusb_dee1601_tuner_attach,
+-
+- .i2c_algo = &cxusb_i2c_algo,
+-
+- .rc_interval = 150,
+- .rc_key_map = dvico_mce_rc_keys,
+- .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
+- .rc_query = cxusb_rc_query,
+-
+- .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+@@ -631,8 +641,21 @@ static struct dvb_usb_properties cxusb_b
+ }
+ }
+ },
++ },
++ },
++
++ .power_ctrl = cxusb_bluebird_power_ctrl,
+
+- .num_device_descs = 2,
++ .i2c_algo = &cxusb_i2c_algo,
++
++ .rc_interval = 150,
++ .rc_key_map = dvico_mce_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
++ .rc_query = cxusb_rc_query,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
++
++ .num_device_descs = 3,
+ .devices = {
+ { "DViCO FusionHDTV DVB-T Dual USB",
+ { &cxusb_table[3], NULL },
+@@ -642,10 +665,14 @@ static struct dvb_usb_properties cxusb_b
+ { &cxusb_table[9], NULL },
+ { &cxusb_table[10], NULL },
+ },
++ { "DViCO FusionHDTV DVB-T Dual Digital 2",
++ { &cxusb_table[11], NULL },
++ { &cxusb_table[12], NULL },
++ },
+ }
+ };
+
+-static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = {
++static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+@@ -656,22 +683,16 @@ static struct dvb_usb_properties cxusb_b
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
++ .num_adapters = 2,
++ .adapter = {
++ {
+ .streaming_ctrl = cxusb_streaming_ctrl,
+- .power_ctrl = cxusb_bluebird_power_ctrl,
+ .frontend_attach = cxusb_mt352_frontend_attach,
+ .tuner_attach = cxusb_lgz201_tuner_attach,
+
+- .i2c_algo = &cxusb_i2c_algo,
+-
+- .rc_interval = 100,
+- .rc_key_map = dvico_portable_rc_keys,
+- .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
+- .rc_query = cxusb_rc_query,
+-
+- .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+@@ -680,7 +701,18 @@ static struct dvb_usb_properties cxusb_b
+ }
+ }
+ },
++ },
++ },
++ .power_ctrl = cxusb_bluebird_power_ctrl,
++
++ .i2c_algo = &cxusb_i2c_algo,
+
++ .rc_interval = 100,
++ .rc_key_map = dvico_portable_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
++ .rc_query = cxusb_rc_query,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
+ .num_device_descs = 1,
+ .devices = {
+ { "DViCO FusionHDTV DVB-T USB (LGZ201)",
+@@ -690,7 +722,7 @@ static struct dvb_usb_properties cxusb_b
+ }
+ };
+
+-static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = {
++static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+@@ -701,22 +733,16 @@ static struct dvb_usb_properties cxusb_b
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .streaming_ctrl = cxusb_streaming_ctrl,
+- .power_ctrl = cxusb_bluebird_power_ctrl,
+ .frontend_attach = cxusb_mt352_frontend_attach,
+ .tuner_attach = cxusb_dtt7579_tuner_attach,
+
+- .i2c_algo = &cxusb_i2c_algo,
+-
+- .rc_interval = 100,
+- .rc_key_map = dvico_portable_rc_keys,
+- .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
+- .rc_query = cxusb_rc_query,
+-
+- .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+@@ -725,6 +751,18 @@ static struct dvb_usb_properties cxusb_b
+ }
+ }
+ },
++ },
++ },
++ .power_ctrl = cxusb_bluebird_power_ctrl,
++
++ .i2c_algo = &cxusb_i2c_algo,
++
++ .rc_interval = 100,
++ .rc_key_map = dvico_portable_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
++ .rc_query = cxusb_rc_query,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
+new file mode 100644
+index 0000000..ac84347
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/dib0700.h
+@@ -0,0 +1,49 @@
++/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
++ *
++ * 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.
++ *
++ * Copyright (C) 2005-6 DiBcom, SA
++ */
++#ifndef _DIB0700_H_
++#define _DIB0700_H_
++
++#define DVB_USB_LOG_PREFIX "dib0700"
++#include "dvb-usb.h"
++
++#include "dib07x0.h"
++
++extern int dvb_usb_dib0700_debug;
++#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args)
++#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args)
++#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
++#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args)
++
++#define REQUEST_I2C_READ 0x2
++#define REQUEST_I2C_WRITE 0x3
++#define REQUEST_POLL_RC 0x4
++#define REQUEST_JUMPRAM 0x8
++#define REQUEST_SET_GPIO 0xC
++#define REQUEST_ENABLE_VIDEO 0xF
++ // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
++ // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
++ // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
++
++struct dib0700_state {
++ u8 channel_state;
++ u16 mt2060_if1[2];
++};
++
++extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
++extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
++extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
++extern struct i2c_algorithm dib0700_i2c_algo;
++extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
++ struct dvb_usb_device_description **desc, int *cold);
++
++extern int dib0700_device_count;
++extern struct dvb_usb_device_properties dib0700_devices[];
++extern struct usb_device_id dib0700_usb_id_table[];
++
++#endif
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
+new file mode 100644
+index 0000000..dca6c69
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -0,0 +1,279 @@
++/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
++ *
++ * 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.
++ *
++ * Copyright (C) 2005-6 DiBcom, SA
++ */
++#include "dib0700.h"
++
++/* debug */
++int dvb_usb_dib0700_debug;
++module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
++MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
++
++/* expecting rx buffer: request data[0] data[1] ... data[2] */
++static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
++{
++ int status;
++
++ deb_data(">>> ");
++ debug_dump(tx,txlen,deb_data);
++
++ status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
++ tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
++ USB_CTRL_GET_TIMEOUT);
++
++ if (status != txlen)
++ deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
++
++ return status < 0 ? status : 0;
++}
++
++/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
++static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
++{
++ u16 index, value;
++ int status;
++
++ if (txlen < 2) {
++ err("tx buffer length is smaller than 2. Makes no sense.");
++ return -EINVAL;
++ }
++ if (txlen > 4) {
++ err("tx buffer length is larger than 4. Not supported.");
++ return -EINVAL;
++ }
++
++ deb_data(">>> ");
++ debug_dump(tx,txlen,deb_data);
++
++ value = ((txlen - 2) << 8) | tx[1];
++ index = 0;
++ if (txlen > 2)
++ index |= (tx[2] << 8);
++ if (txlen > 3)
++ index |= tx[3];
++
++ /* think about swapping here */
++ value = le16_to_cpu(value);
++ index = le16_to_cpu(index);
++
++ status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
++ USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
++ USB_CTRL_GET_TIMEOUT);
++
++ if (status < 0)
++ deb_info("ep 0 read error (status = %d)\n",status);
++
++ deb_data("<<< ");
++ debug_dump(rx,rxlen,deb_data);
++
++ return status; /* length in case of success */
++}
++
++int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
++{
++ u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
++ return dib0700_ctrl_wr(d,buf,3);
++}
++
++/*
++ * I2C master xfer function
++ */
++static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
++{
++ struct dvb_usb_device *d = i2c_get_adapdata(adap);
++ int i,len;
++ u8 buf[255];
++
++ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
++ return -EAGAIN;
++
++ for (i = 0; i < num; i++) {
++ /* fill in the address */
++ buf[1] = (msg[i].addr << 1);
++ /* fill the buffer */
++ memcpy(&buf[2], msg[i].buf, msg[i].len);
++
++ /* write/read request */
++ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
++ buf[0] = REQUEST_I2C_READ;
++ buf[1] |= 1;
++
++ /* special thing in the current firmware: when length is zero the read-failed */
++ if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
++ deb_info("I2C read failed on address %x\n", msg[i].addr);
++ break;
++ }
++
++ msg[i+1].len = len;
++
++ i++;
++ } else {
++ buf[0] = REQUEST_I2C_WRITE;
++ if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0)
++ break;
++ }
++ }
++
++ mutex_unlock(&d->i2c_mutex);
++ return i;
++}
++
++static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
++{
++ return I2C_FUNC_I2C;
++}
++
++struct i2c_algorithm dib0700_i2c_algo = {
++ .master_xfer = dib0700_i2c_xfer,
++ .functionality = dib0700_i2c_func,
++};
++
++int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
++ struct dvb_usb_device_description **desc, int *cold)
++{
++ u8 buf[3] = { REQUEST_SET_GPIO, 4, (GPIO_IN << 7) | (0 << 6) }; // GPIO4 is save - used for I2C
++ *cold = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
++ buf[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, buf, 3, USB_CTRL_GET_TIMEOUT) != 3;
++
++ deb_info("cold: %d\n", *cold);
++ return 0;
++}
++
++static int dib0700_jumpram(struct usb_device *udev, u32 address)
++{
++ int ret, actlen;
++ u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
++ (address >> 24) & 0xff,
++ (address >> 16) & 0xff,
++ (address >> 8) & 0xff,
++ address & 0xff };
++
++ if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
++ deb_fw("jumpram to 0x%x failed\n",address);
++ return ret;
++ }
++ if (actlen != 8) {
++ deb_fw("jumpram to 0x%x failed\n",address);
++ return -EIO;
++ }
++ return 0;
++}
++
++int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
++{
++ struct hexline hx;
++ int pos = 0, ret, act_len;
++
++ u8 buf[260];
++
++ while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
++ deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
++
++ buf[0] = hx.len;
++ buf[1] = (hx.addr >> 8) & 0xff;
++ buf[2] = hx.addr & 0xff;
++ buf[3] = hx.type;
++ memcpy(&buf[4],hx.data,hx.len);
++ buf[4+hx.len] = hx.chk;
++
++ ret = usb_bulk_msg(udev,
++ usb_sndbulkpipe(udev, 0x01),
++ buf,
++ hx.len + 5,
++ &act_len,
++ 1000);
++
++ if (ret < 0) {
++ err("firmware download failed at %d with %d",pos,ret);
++ return ret;
++ }
++ }
++
++ if (ret == 0) {
++ /* start the firmware */
++ if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
++ info("firmware started successfully.");
++ msleep(100);
++ }
++ } else
++ ret = -EIO;
++
++ return ret;
++}
++
++int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
++{
++ struct dib0700_state *st = adap->dev->priv;
++ u8 b[4];
++
++ b[0] = REQUEST_ENABLE_VIDEO;
++ b[1] = 0x00;
++ b[2] = (0x01 << 4); /* Master mode */
++ b[3] = 0x00;
++
++ deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
++
++ if (onoff)
++ st->channel_state |= 1 << adap->id;
++ else
++ st->channel_state &= ~(1 << adap->id);
++
++ b[2] |= st->channel_state;
++
++ if (st->channel_state) /* if at least one channel is active */
++ b[1] = (0x01 << 4) | 0x00;
++
++ deb_info("data for streaming: %x %x\n",b[1],b[2]);
++
++ return dib0700_ctrl_wr(adap->dev, b, 4);
++}
++
++static int dib0700_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ int i;
++
++ for (i = 0; i < dib0700_device_count; i++)
++ if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
++ return 0;
++
++ return -ENODEV;
++}
++
++static struct usb_driver dib0700_driver = {
++ .name = "dvb_usb_dib0700",
++ .probe = dib0700_probe,
++ .disconnect = dvb_usb_device_exit,
++ .id_table = dib0700_usb_id_table,
++};
++
++/* module stuff */
++static int __init dib0700_module_init(void)
++{
++ int result;
++ info("loaded with support for %d different device-types", dib0700_device_count);
++ if ((result = usb_register(&dib0700_driver))) {
++ err("usb_register failed. Error number %d",result);
++ return result;
++ }
++
++ return 0;
++}
++
++static void __exit dib0700_module_exit(void)
++{
++ /* deregister this driver from the USB subsystem */
++ usb_deregister(&dib0700_driver);
++}
++
++module_init (dib0700_module_init);
++module_exit (dib0700_module_exit);
++
++MODULE_AUTHOR("Patrick Boettcher <pboettcher at dibcom.fr>");
++MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
++MODULE_VERSION("1.0");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
+new file mode 100644
+index 0000000..e473bfe
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
+@@ -0,0 +1,212 @@
++/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
++ *
++ * 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.
++ *
++ * Copyright (C) 2005-6 DiBcom, SA
++ */
++#include "dib0700.h"
++
++#include "dib3000mc.h"
++#include "mt2060.h"
++
++static int force_lna_activation;
++module_param(force_lna_activation, int, 0644);
++MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
++ "if applicable for the device (default: 0=automatic/off).");
++
++/* Hauppauge Nova-T 500
++ * has a LNA on GPIO0 which is enabled by setting 1 */
++static struct mt2060_config bristol_mt2060_config[2] = {
++ {
++ .i2c_address = 0x60,
++ .clock_out = 3,
++ }, {
++ .i2c_address = 0x61,
++ }
++};
++
++static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
++ .band_caps = BAND_VHF | BAND_UHF,
++ .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
++
++ .agc1_max = 42598,
++ .agc1_min = 17694,
++ .agc2_max = 45875,
++ .agc2_min = 0,
++
++ .agc1_pt1 = 0,
++ .agc1_pt2 = 59,
++
++ .agc1_slope1 = 0,
++ .agc1_slope2 = 69,
++
++ .agc2_pt1 = 0,
++ .agc2_pt2 = 59,
++
++ .agc2_slope1 = 111,
++ .agc2_slope2 = 28,
++};
++
++static struct dib3000mc_config bristol_dib3000mc_config[2] = {
++ { .agc = &bristol_dib3000p_mt2060_agc_config,
++ .max_time = 0x196,
++ .ln_adc_level = 0x1cc7,
++ .output_mpeg2_in_188_bytes = 1,
++ },
++ { .agc = &bristol_dib3000p_mt2060_agc_config,
++ .max_time = 0x196,
++ .ln_adc_level = 0x1cc7,
++ .output_mpeg2_in_188_bytes = 1,
++ }
++};
++
++static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
++{
++ struct dib0700_state *st = adap->dev->priv;
++ if (adap->id == 0) {
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
++
++ if (force_lna_activation)
++ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
++ else
++ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
++
++ if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
++ return -ENODEV;
++ }
++ }
++ st->mt2060_if1[adap->id] = 1220;
++ return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
++ (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
++}
++
++static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
++{
++ struct dib0700_state *st = adap->dev->priv;
++ struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
++ return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
++ st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
++}
++
++/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
++/*
++static struct mt2060_config stk7000p_mt2060_config = {
++ 0x60
++};
++*/
++
++static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
++{
++ /* unless there is no real power management in DVB - we leave the device on GPIO6 */
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
++
++// adap->fe = dib7000m_attach(&adap->dev->i2c_adap, &stk7700p_dib7000m_config, 18);
++ return 0;
++}
++
++static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
++{
++// tun_i2c = dib7000m_get_tuner_i2c_master(adap->fe, 1);
++// return mt2060_attach(adap->fe, tun_i2c, &stk3000p_mt2060_config, if1);
++ return 0;
++}
++
++struct usb_device_id dib0700_usb_id_table[] = {
++ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
++ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
++ { } /* Terminating entry */
++};
++MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
++
++#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \
++ .usb_ctrl = DEVICE_SPECIFIC, \
++ .firmware = "dvb-usb-dib0700-01.fw", \
++ .download_firmware = dib0700_download_firmware, \
++ .no_reconnect = 1, \
++ .size_of_priv = sizeof(struct dib0700_state), \
++ .i2c_algo = &dib0700_i2c_algo, \
++ .identify_state = dib0700_identify_state
++
++#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \
++ .streaming_ctrl = dib0700_streaming_ctrl, \
++ .stream = { \
++ .type = USB_BULK, \
++ .count = 4, \
++ .endpoint = ep, \
++ .u = { \
++ .bulk = { \
++ .buffersize = 39480, \
++ } \
++ } \
++ }
++
++struct dvb_usb_device_properties dib0700_devices[] = {
++ {
++ DIB0700_DEFAULT_DEVICE_PROPERTIES,
++
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .frontend_attach = stk7700p_frontend_attach,
++ .tuner_attach = stk7700p_tuner_attach,
++
++ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
++ },
++ },
++
++ .num_device_descs = 3,
++ .devices = {
++ { "DiBcom STK7700P reference design",
++ { &dib0700_usb_id_table[0], NULL },
++ { NULL },
++ },
++ { "Hauppauge Nova-T Stick",
++ { &dib0700_usb_id_table[3], NULL },
++ { NULL },
++ },
++ { "AVerMedia AVerTV DVB-T Volar",
++ { &dib0700_usb_id_table[4], NULL },
++ { NULL },
++ },
++ }
++ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
++
++ .num_adapters = 2,
++ .adapter = {
++ {
++ .frontend_attach = bristol_frontend_attach,
++ .tuner_attach = bristol_tuner_attach,
++
++ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
++ }, {
++ .frontend_attach = bristol_frontend_attach,
++ .tuner_attach = bristol_tuner_attach,
++
++ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
++ }
++ },
++
++ .num_device_descs = 1,
++ .devices = {
++ { "Hauppauge Nova-T 500 Dual DVB-T",
++ { &dib0700_usb_id_table[1], &dib0700_usb_id_table[2], NULL },
++ { NULL },
++ },
++ }
++ }
++};
++
++int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
+diff --git a/drivers/media/dvb/dvb-usb/dib07x0.h b/drivers/media/dvb/dvb-usb/dib07x0.h
+new file mode 100644
+index 0000000..7e62c10
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/dib07x0.h
+@@ -0,0 +1,21 @@
++#ifndef _DIB07X0_H_
++#define _DIB07X0_H_
++
++enum dib07x0_gpios {
++ GPIO0 = 0,
++ GPIO1 = 2,
++ GPIO2 = 3,
++ GPIO3 = 4,
++ GPIO4 = 5,
++ GPIO5 = 6,
++ GPIO6 = 8,
++ GPIO7 = 10,
++ GPIO8 = 11,
++ GPIO9 = 14,
++ GPIO10 = 15,
++};
++
++#define GPIO_IN 0
++#define GPIO_OUT 1
++
++#endif
+diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
+index abd75b4..5143e42 100644
+--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
++++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
+@@ -18,12 +18,12 @@ 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)
++int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+- if (d->priv != NULL) {
+- struct dibusb_state *st = d->priv;
++ if (adap->priv != NULL) {
++ struct dibusb_state *st = adap->priv;
+ if (st->ops.fifo_ctrl != NULL)
+- if (st->ops.fifo_ctrl(d->fe,onoff)) {
++ if (st->ops.fifo_ctrl(adap->fe,onoff)) {
+ err("error while controlling the fifo of the demod.");
+ return -ENODEV;
+ }
+@@ -32,23 +32,23 @@ int dibusb_streaming_ctrl(struct dvb_usb
+ }
+ EXPORT_SYMBOL(dibusb_streaming_ctrl);
+
+-int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
++int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
+ {
+- if (d->priv != NULL) {
+- struct dibusb_state *st = d->priv;
++ if (adap->priv != NULL) {
++ struct dibusb_state *st = adap->priv;
+ if (st->ops.pid_ctrl != NULL)
+- st->ops.pid_ctrl(d->fe,index,pid,onoff);
++ st->ops.pid_ctrl(adap->fe,index,pid,onoff);
+ }
+ return 0;
+ }
+ EXPORT_SYMBOL(dibusb_pid_filter);
+
+-int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff)
++int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+- if (d->priv != NULL) {
+- struct dibusb_state *st = d->priv;
++ if (adap->priv != NULL) {
++ struct dibusb_state *st = adap->priv;
+ if (st->ops.pid_parse != NULL)
+- if (st->ops.pid_parse(d->fe,onoff) < 0)
++ if (st->ops.pid_parse(adap->fe,onoff) < 0)
+ err("could not handle pid_parser");
+ }
+ return 0;
+@@ -68,24 +68,24 @@ int dibusb_power_ctrl(struct dvb_usb_dev
+ }
+ EXPORT_SYMBOL(dibusb_power_ctrl);
+
+-int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff)
++int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+ u8 b[3] = { 0 };
+ int ret;
+
+- if ((ret = dibusb_streaming_ctrl(d,onoff)) < 0)
++ if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
+ return ret;
+
+ if (onoff) {
+ b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
+ b[1] = 0x00;
+- if ((ret = dvb_usb_generic_write(d,b,2)) < 0)
++ if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
+ return ret;
+ }
+
+ b[0] = DIBUSB_REQ_SET_IOCTL;
+ b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
+- return dvb_usb_generic_write(d,b,3);
++ return dvb_usb_generic_write(adap->dev,b,3);
+ }
+ EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
+
+@@ -131,9 +131,6 @@ static int dibusb_i2c_xfer(struct i2c_ad
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 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)) {
+@@ -168,31 +165,143 @@ int dibusb_read_eeprom_byte(struct dvb_u
+ }
+ EXPORT_SYMBOL(dibusb_read_eeprom_byte);
+
+-int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
++/* 3000MC/P stuff */
++// Config Adjacent channels Perf -cal22
++static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
++ .band_caps = BAND_VHF | BAND_UHF,
++ .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
++
++ .agc1_max = 48497,
++ .agc1_min = 23593,
++ .agc2_max = 46531,
++ .agc2_min = 24904,
++
++ .agc1_pt1 = 0x65,
++ .agc1_pt2 = 0x69,
++
++ .agc1_slope1 = 0x51,
++ .agc1_slope2 = 0x27,
++
++ .agc2_pt1 = 0,
++ .agc2_pt2 = 0x33,
++
++ .agc2_slope1 = 0x35,
++ .agc2_slope2 = 0x37,
++};
++
++static struct dib3000mc_config stk3000p_dib3000p_config = {
++ &dib3000p_mt2060_agc_config,
++
++ .max_time = 0x196,
++ .ln_adc_level = 0x1cc7,
++
++ .output_mpeg2_in_188_bytes = 1,
++
++ .agc_command1 = 1,
++ .agc_command2 = 1,
++};
++
++static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
++ .band_caps = BAND_VHF | BAND_UHF,
++ .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
++
++ .agc1_max = 56361,
++ .agc1_min = 22282,
++ .agc2_max = 47841,
++ .agc2_min = 36045,
++
++ .agc1_pt1 = 0x3b,
++ .agc1_pt2 = 0x6b,
++
++ .agc1_slope1 = 0x55,
++ .agc1_slope2 = 0x1d,
++
++ .agc2_pt1 = 0,
++ .agc2_pt2 = 0x0a,
++
++ .agc2_slope1 = 0x95,
++ .agc2_slope2 = 0x1e,
++};
++
++static struct dib3000mc_config mod3000p_dib3000p_config = {
++ &dib3000p_panasonic_agc_config,
++
++ .max_time = 0x51,
++ .ln_adc_level = 0x1cc7,
++
++ .output_mpeg2_in_188_bytes = 1,
++
++ .agc_command1 = 1,
++ .agc_command2 = 1,
++};
++
++int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- struct dib3000_config demod_cfg;
+- struct dibusb_state *st = d->priv;
+-
+- 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->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+- d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+- return 0;
++ if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL ||
++ (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) {
++ if (adap->priv != NULL) {
++ struct dibusb_state *st = adap->priv;
++ st->ops.pid_parse = dib3000mc_pid_parse;
++ st->ops.pid_ctrl = dib3000mc_pid_control;
+ }
+-
++ 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;
++static struct mt2060_config stk3000p_mt2060_config = {
++ 0x60
++};
+
+- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
++int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
++{
++ struct dibusb_state *st = adap->priv;
++ u8 a,b;
++ u16 if1 = 1220;
++ struct i2c_adapter *tun_i2c;
++
++ // First IF calibration for Liteon Sticks
++ if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON &&
++ adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
++
++ dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
++ dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
++
++ if (a == 0x00)
++ if1 += b;
++ else if (a == 0x80)
++ if1 -= b;
++ else
++ warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
++
++ } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM &&
++ adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
++ u8 desc;
++ dibusb_read_eeprom_byte(adap->dev, 7, &desc);
++ if (desc == 2) {
++ a = 127;
++ do {
++ dibusb_read_eeprom_byte(adap->dev, a, &desc);
++ a--;
++ } while (a > 7 && (desc == 0xff || desc == 0x00));
++ if (desc & 0x80)
++ if1 -= (0xff - desc);
++ else
++ if1 += desc;
++ }
++ }
+
++ tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
++ if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
++ /* not found - use panasonic pll parameters */
++ if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
++ return -ENOMEM;
++ } else {
++ st->mt2060_present = 1;
++ /* set the correct parameters for the dib3000p */
++ dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config);
++ }
+ return 0;
+ }
+ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
+@@ -267,6 +376,67 @@ struct dvb_usb_rc_key dibusb_rc_keys[] =
+ { 0x86, 0x1e, KEY_DOWN },
+ { 0x86, 0x1f, KEY_LEFT },
+ { 0x86, 0x1b, KEY_RIGHT },
++
++ /* Key codes for the DiBcom MOD3000 remote. */
++ { 0x80, 0x00, KEY_MUTE },
++ { 0x80, 0x01, KEY_TEXT },
++ { 0x80, 0x02, KEY_HOME },
++ { 0x80, 0x03, KEY_POWER },
++
++ { 0x80, 0x04, KEY_RED },
++ { 0x80, 0x05, KEY_GREEN },
++ { 0x80, 0x06, KEY_YELLOW },
++ { 0x80, 0x07, KEY_BLUE },
++
++ { 0x80, 0x08, KEY_DVD },
++ { 0x80, 0x09, KEY_AUDIO },
++ { 0x80, 0x0a, KEY_MEDIA }, /* Pictures */
++ { 0x80, 0x0b, KEY_VIDEO },
++
++ { 0x80, 0x0c, KEY_BACK },
++ { 0x80, 0x0d, KEY_UP },
++ { 0x80, 0x0e, KEY_RADIO },
++ { 0x80, 0x0f, KEY_EPG },
++
++ { 0x80, 0x10, KEY_LEFT },
++ { 0x80, 0x11, KEY_OK },
++ { 0x80, 0x12, KEY_RIGHT },
++ { 0x80, 0x13, KEY_UNKNOWN }, /* SAP */
++
++ { 0x80, 0x14, KEY_TV },
++ { 0x80, 0x15, KEY_DOWN },
++ { 0x80, 0x16, KEY_MENU }, /* DVD Menu */
++ { 0x80, 0x17, KEY_LAST },
++
++ { 0x80, 0x18, KEY_RECORD },
++ { 0x80, 0x19, KEY_STOP },
++ { 0x80, 0x1a, KEY_PAUSE },
++ { 0x80, 0x1b, KEY_PLAY },
++
++ { 0x80, 0x1c, KEY_PREVIOUS },
++ { 0x80, 0x1d, KEY_REWIND },
++ { 0x80, 0x1e, KEY_FASTFORWARD },
++ { 0x80, 0x1f, KEY_NEXT},
++
++ { 0x80, 0x40, KEY_1 },
++ { 0x80, 0x41, KEY_2 },
++ { 0x80, 0x42, KEY_3 },
++ { 0x80, 0x43, KEY_CHANNELUP },
++
++ { 0x80, 0x44, KEY_4 },
++ { 0x80, 0x45, KEY_5 },
++ { 0x80, 0x46, KEY_6 },
++ { 0x80, 0x47, KEY_CHANNELDOWN },
++
++ { 0x80, 0x48, KEY_7 },
++ { 0x80, 0x49, KEY_8 },
++ { 0x80, 0x4a, KEY_9 },
++ { 0x80, 0x4b, KEY_VOLUMEUP },
++
++ { 0x80, 0x4c, KEY_CLEAR },
++ { 0x80, 0x4d, KEY_0 },
++ { 0x80, 0x4e, KEY_ENTER },
++ { 0x80, 0x4f, KEY_VOLUMEDOWN },
+ };
+ EXPORT_SYMBOL(dibusb_rc_keys);
+
+diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
+index f4c45f3..4fe363e 100644
+--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
++++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
+@@ -14,35 +14,35 @@
+ */
+ #include "dibusb.h"
+
+-static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
++static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+ struct dib3000_config demod_cfg;
+- struct dibusb_state *st = d->priv;
++ struct dibusb_state *st = adap->priv;
+
+ demod_cfg.demod_address = 0x8;
+
+- if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
++ if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+ return -ENODEV;
+- }
+
+- d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
++ adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
++ adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
++
++ adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+
+ return 0;
+ }
+
+-static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d)
++static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+- d->pll_addr = 0x61;
+- d->pll_desc = &dvb_pll_tua6010xs;
++ adap->pll_addr = 0x61;
++ adap->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)
++static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
+ {
+ u8 b[2] = { 0,0 }, b2[1];
+ int ret = 0;
+@@ -54,36 +54,36 @@ static int dibusb_tuner_probe_and_attach
+ /* 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 (adap->tuner_pass_ctrl)
++ adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+
+- if (i2c_transfer (&d->i2c_adap, msg, 2) != 2) {
++ if (i2c_transfer(&adap->dev->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 (adap->tuner_pass_ctrl)
++ adap->tuner_pass_ctrl(adap->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);
++ dibusb_thomson_tuner_attach(adap);
+ } 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;
++ adap->pll_addr = 0x60;
++ memcpy(adap->pll_init,bpll,4);
++ adap->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 struct dvb_usb_properties artec_t1_usb2_properties;
++static struct dvb_usb_device_properties dibusb1_1_properties;
++static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
++static struct dvb_usb_device_properties dibusb2_0b_properties;
++static struct dvb_usb_device_properties artec_t1_usb2_properties;
+
+ static int dibusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -150,34 +150,28 @@ static struct usb_device_id dibusb_dib30
+ };
+ 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,
++static struct dvb_usb_device_properties dibusb1_1_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_AN2135,
+
+ .firmware = "dvb-usb-dibusb-5.0.0.11.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
++ .pid_filter_count = 16,
+
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -186,6 +180,20 @@ static struct dvb_usb_properties dibusb1
+ }
+ }
+ },
++ .size_of_priv = sizeof(struct dibusb_state),
++ }
++ },
++
++ .power_ctrl = dibusb_power_ctrl,
++
++ .rc_interval = DEFAULT_RC_INTERVAL,
++ .rc_key_map = dibusb_rc_keys,
++ .rc_key_map_size = 111, /* 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,
+
+ .num_device_descs = 9,
+ .devices = {
+@@ -228,34 +236,27 @@ static struct dvb_usb_properties dibusb1
+ }
+ };
+
+-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,
+-
++static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = CYPRESS_AN2235,
+
+ .firmware = "dvb-usb-dibusb-an2235-01.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
++ .pid_filter_count = 16,
+
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -264,6 +265,19 @@ static struct dvb_usb_properties dibusb1
+ }
+ }
+ },
++ .size_of_priv = sizeof(struct dibusb_state),
++ },
++ },
++ .power_ctrl = dibusb_power_ctrl,
++
++ .rc_interval = DEFAULT_RC_INTERVAL,
++ .rc_key_map = dibusb_rc_keys,
++ .rc_key_map_size = 111, /* 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,
+
+ #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
+ .num_device_descs = 2,
+@@ -272,8 +286,8 @@ static struct dvb_usb_properties dibusb1
+ #endif
+ .devices = {
+ { "Artec T1 USB1.1 TVBOX with AN2235",
+- { &dibusb_dib3000mb_table[20], NULL },
+ { &dibusb_dib3000mb_table[21], NULL },
++ { &dibusb_dib3000mb_table[22], NULL },
+ },
+ #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
+ { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
+@@ -285,34 +299,27 @@ static struct dvb_usb_properties dibusb1
+ }
+ };
+
+-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 = 16,
++static struct dvb_usb_device_properties dibusb2_0b_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .firmware = "dvb-usb-adstech-usb2-02.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
++ .pid_filter_count = 16,
+
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+@@ -321,6 +328,19 @@ static struct dvb_usb_properties dibusb2
+ }
+ }
+ },
++ .size_of_priv = sizeof(struct dibusb_state),
++ }
++ },
++ .power_ctrl = dibusb2_0_power_ctrl,
++
++ .rc_interval = DEFAULT_RC_INTERVAL,
++ .rc_key_map = dibusb_rc_keys,
++ .rc_key_map_size = 111, /* 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,
+
+ .num_device_descs = 2,
+ .devices = {
+@@ -336,34 +356,27 @@ static struct dvb_usb_properties dibusb2
+ }
+ };
+
+-static struct dvb_usb_properties artec_t1_usb2_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,
++static struct dvb_usb_device_properties artec_t1_usb2_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
++ .pid_filter_count = 16,
+
+ .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_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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+@@ -372,6 +385,19 @@ static struct dvb_usb_properties artec_t
+ }
+ }
+ },
++ .size_of_priv = sizeof(struct dibusb_state),
++ }
++ },
++ .power_ctrl = dibusb2_0_power_ctrl,
++
++ .rc_interval = DEFAULT_RC_INTERVAL,
++ .rc_key_map = dibusb_rc_keys,
++ .rc_key_map_size = 111, /* 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,
+
+ .num_device_descs = 1,
+ .devices = {
+diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
+index 55802fb..a0fd37e 100644
+--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
++++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
+@@ -15,7 +15,7 @@
+ #include "dibusb.h"
+
+ /* USB Driver stuff */
+-static struct dvb_usb_properties dibusb_mc_properties;
++static struct dvb_usb_device_properties dibusb_mc_properties;
+
+ static int dibusb_mc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -28,37 +28,41 @@ static struct usb_device_id dibusb_dib30
+ /* 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) },
++/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
++/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) },
++/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) },
++/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) },
++/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) },
++/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) },
++/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) },
++/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) },
++/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) },
++/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) },
++/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) },
+ { } /* 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,
++static struct dvb_usb_device_properties dibusb_mc_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
+-
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
++ .pid_filter_count = 32,
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+@@ -67,17 +71,52 @@ static struct dvb_usb_properties dibusb_
+ }
+ }
+ },
++ .size_of_priv = sizeof(struct dibusb_state),
++ }
++ },
++ .power_ctrl = dibusb2_0_power_ctrl,
+
+- .num_device_descs = 2,
++ .rc_interval = DEFAULT_RC_INTERVAL,
++ .rc_key_map = dibusb_rc_keys,
++ .rc_key_map_size = 111, /* FIXME */
++ .rc_query = dibusb_rc_query,
++
++ .i2c_algo = &dibusb_i2c_algo,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
++
++ .num_device_descs = 7,
+ .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)",
++ { "Artec T1 USB2.0 TVBOX (please check the warm ID)",
+ { &dibusb_dib3000mc_table[2], NULL },
+- { NULL },
++ { &dibusb_dib3000mc_table[3], NULL },
++ },
++ { "LITE-ON USB2.0 DVB-T Tuner",
++ /* Also rebranded as Intuix S800, Toshiba */
++ { &dibusb_dib3000mc_table[4], NULL },
++ { &dibusb_dib3000mc_table[5], NULL },
++ },
++ { "MSI Digivox Mini SL",
++ { &dibusb_dib3000mc_table[6], NULL },
++ { &dibusb_dib3000mc_table[7], NULL },
++ },
++ { "GRAND - USB2.0 DVB-T adapter",
++ { &dibusb_dib3000mc_table[8], NULL },
++ { &dibusb_dib3000mc_table[9], NULL },
++ },
++ { "Artec T14 - USB2.0 DVB-T",
++ { &dibusb_dib3000mc_table[10], NULL },
++ { &dibusb_dib3000mc_table[11], NULL },
++ },
++ { "Leadtek - USB2.0 Winfast DTV dongle",
++ { &dibusb_dib3000mc_table[12], NULL },
++ { &dibusb_dib3000mc_table[13], NULL },
+ },
++ { NULL },
+ }
+ };
+
+diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
+index 2d99d05..b607810 100644
+--- a/drivers/media/dvb/dvb-usb/dibusb.h
++++ b/drivers/media/dvb/dvb-usb/dibusb.h
+@@ -17,6 +17,8 @@
+ #include "dvb-usb.h"
+
+ #include "dib3000.h"
++#include "dib3000mc.h"
++#include "mt2060.h"
+
+ /*
+ * protocol of all dibusb related devices
+@@ -96,7 +98,10 @@
+
+ struct dibusb_state {
+ struct dib_fe_xfer_ops ops;
++ int mt2060_present;
++};
+
++struct dibusb_device_state {
+ /* for RC5 remote control */
+ int old_toggle;
+ int last_repeat_count;
+@@ -104,14 +109,15 @@ struct dibusb_state {
+
+ 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_dib3000mc_frontend_attach(struct dvb_usb_adapter *);
++extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *);
++
++extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int);
++extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int);
++extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int);
++extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int);
+
+-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
+diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
+index c14d9ef..8fb3437 100644
+--- a/drivers/media/dvb/dvb-usb/digitv.c
++++ b/drivers/media/dvb/dvb-usb/digitv.c
+@@ -83,7 +83,7 @@ static struct i2c_algorithm digitv_i2c_a
+
+ /* Callbacks for DVB USB */
+ static int digitv_identify_state (struct usb_device *udev, struct
+- dvb_usb_properties *props, struct dvb_usb_device_description **desc,
++ dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
+ int *cold)
+ {
+ *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+@@ -116,59 +116,129 @@ static struct mt352_config digitv_mt352_
+
+ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+ {
+- struct dvb_usb_device *d = fe->dvb->priv;
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ u8 b[5];
+ dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+- return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
++ return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
+ }
+
+ static struct nxt6000_config digitv_nxt6000_config = {
+ .clock_inversion = 1,
+ };
+
+-static int digitv_frontend_attach(struct dvb_usb_device *d)
++static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
++ if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
++ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+ }
+- if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+- d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
++ if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
++ adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ return 0;
+ }
+ return -EIO;
+ }
+
+-static int digitv_tuner_attach(struct dvb_usb_device *d)
++static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+- d->pll_addr = 0x60;
+- d->pll_desc = &dvb_pll_tded4;
++ adap->pll_addr = 0x60;
++ adap->pll_desc = &dvb_pll_tded4;
+ return 0;
+ }
+
+ static struct dvb_usb_rc_key digitv_rc_keys[] = {
+- { 0x00, 0x16, KEY_POWER }, /* dummy key */
++ { 0x5f, 0x55, KEY_0 },
++ { 0x6f, 0x55, KEY_1 },
++ { 0x9f, 0x55, KEY_2 },
++ { 0xaf, 0x55, KEY_3 },
++ { 0x5f, 0x56, KEY_4 },
++ { 0x6f, 0x56, KEY_5 },
++ { 0x9f, 0x56, KEY_6 },
++ { 0xaf, 0x56, KEY_7 },
++ { 0x5f, 0x59, KEY_8 },
++ { 0x6f, 0x59, KEY_9 },
++ { 0x9f, 0x59, KEY_TV },
++ { 0xaf, 0x59, KEY_AUX },
++ { 0x5f, 0x5a, KEY_DVD },
++ { 0x6f, 0x5a, KEY_POWER },
++ { 0x9f, 0x5a, KEY_MHP }, /* labelled 'Picture' */
++ { 0xaf, 0x5a, KEY_AUDIO },
++ { 0x5f, 0x65, KEY_INFO },
++ { 0x6f, 0x65, KEY_F13 }, /* 16:9 */
++ { 0x9f, 0x65, KEY_F14 }, /* 14:9 */
++ { 0xaf, 0x65, KEY_EPG },
++ { 0x5f, 0x66, KEY_EXIT },
++ { 0x6f, 0x66, KEY_MENU },
++ { 0x9f, 0x66, KEY_UP },
++ { 0xaf, 0x66, KEY_DOWN },
++ { 0x5f, 0x69, KEY_LEFT },
++ { 0x6f, 0x69, KEY_RIGHT },
++ { 0x9f, 0x69, KEY_ENTER },
++ { 0xaf, 0x69, KEY_CHANNELUP },
++ { 0x5f, 0x6a, KEY_CHANNELDOWN },
++ { 0x6f, 0x6a, KEY_VOLUMEUP },
++ { 0x9f, 0x6a, KEY_VOLUMEDOWN },
++ { 0xaf, 0x6a, KEY_RED },
++ { 0x5f, 0x95, KEY_GREEN },
++ { 0x6f, 0x95, KEY_YELLOW },
++ { 0x9f, 0x95, KEY_BLUE },
++ { 0xaf, 0x95, KEY_SUBTITLE },
++ { 0x5f, 0x96, KEY_F15 }, /* AD */
++ { 0x6f, 0x96, KEY_TEXT },
++ { 0x9f, 0x96, KEY_MUTE },
++ { 0xaf, 0x96, KEY_REWIND },
++ { 0x5f, 0x99, KEY_STOP },
++ { 0x6f, 0x99, KEY_PLAY },
++ { 0x9f, 0x99, KEY_FASTFORWARD },
++ { 0xaf, 0x99, KEY_F16 }, /* chapter */
++ { 0x5f, 0x9a, KEY_PAUSE },
++ { 0x6f, 0x9a, KEY_PLAY },
++ { 0x9f, 0x9a, KEY_RECORD },
++ { 0xaf, 0x9a, KEY_F17 }, /* picture in picture */
++ { 0x5f, 0xa5, KEY_KPPLUS }, /* zoom in */
++ { 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
++ { 0x9f, 0xa5, KEY_F18 }, /* capture */
++ { 0xaf, 0xa5, KEY_F19 }, /* web */
++ { 0x5f, 0xa6, KEY_EMAIL },
++ { 0x6f, 0xa6, KEY_PHONE },
++ { 0x9f, 0xa6, KEY_PC },
+ };
+
+-/* TODO is it really the NEC protocol ? */
+ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+ {
++ int i;
+ u8 key[5];
++ u8 b[4] = { 0 };
++
++ *event = 0;
++ *state = REMOTE_NO_KEY_PRESSED;
+
+ digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
+- /* TODO state, maybe it is VV ? */
++
++ /* Tell the device we've read the remote. Not sure how necessary
++ this is, but the Nebula SDK does it. */
++ digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
++
++ /* if something is inside the buffer, simulate key press */
+ if (key[1] != 0)
+- key[0] = 0x01; /* if something is inside the buffer, simulate key press */
++ {
++ for (i = 0; i < d->props.rc_key_map_size; i++) {
++ if (d->props.rc_key_map[i].custom == key[1] &&
++ d->props.rc_key_map[i].data == key[2]) {
++ *event = d->props.rc_key_map[i].event;
++ *state = REMOTE_KEY_PRESSED;
++ return 0;
++ }
++ }
++ }
+
+- /* 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 struct dvb_usb_device_properties digitv_properties;
+
+ static int digitv_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -195,30 +265,21 @@ static struct usb_device_id digitv_table
+ };
+ MODULE_DEVICE_TABLE (usb, digitv_table);
+
+-static struct dvb_usb_properties digitv_properties = {
++static struct dvb_usb_device_properties digitv_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-digitv-02.fw",
+
+- .size_of_priv = 0,
+-
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -227,6 +288,18 @@ static struct dvb_usb_properties digitv_
+ }
+ }
+ },
++ }
++ },
++ .identify_state = digitv_identify_state,
++
++ .rc_interval = 1000,
++ .rc_key_map = digitv_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(digitv_rc_keys),
++ .rc_query = digitv_rc_query,
++
++ .i2c_algo = &digitv_i2c_algo,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
+index 70afcfd..fa43a41 100644
+--- a/drivers/media/dvb/dvb-usb/dtt200u.c
++++ b/drivers/media/dvb/dvb-usb/dtt200u.c
+@@ -28,19 +28,19 @@ static int dtt200u_power_ctrl(struct dvb
+ return 0;
+ }
+
+-static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
++static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+ u8 b_streaming[2] = { SET_STREAMING, onoff };
+ u8 b_rst_pid = RESET_PID_FILTER;
+
+- dvb_usb_generic_write(d,b_streaming,2);
++ dvb_usb_generic_write(adap->dev, b_streaming, 2);
+
+ if (onoff == 0)
+- dvb_usb_generic_write(d,&b_rst_pid,1);
++ dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
+ return 0;
+ }
+
+-static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
++static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
+ {
+ u8 b_pid[4];
+ pid = onoff ? pid : 0;
+@@ -50,7 +50,7 @@ static int dtt200u_pid_filter(struct dvb
+ b_pid[2] = pid & 0xff;
+ b_pid[3] = (pid >> 8) & 0x1f;
+
+- return dvb_usb_generic_write(d,b_pid,4);
++ return dvb_usb_generic_write(adap->dev, b_pid, 4);
+ }
+
+ /* remote control */
+@@ -86,21 +86,23 @@ static int dtt200u_rc_query(struct dvb_u
+ return 0;
+ }
+
+-static int dtt200u_frontend_attach(struct dvb_usb_device *d)
++static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- d->fe = dtt200u_fe_attach(d);
++ adap->fe = dtt200u_fe_attach(adap->dev);
+ return 0;
+ }
+
+-static struct dvb_usb_properties dtt200u_properties;
+-static struct dvb_usb_properties wt220u_properties;
+-static struct dvb_usb_properties wt220u_zl0353_properties;
++static struct dvb_usb_device_properties dtt200u_properties;
++static struct dvb_usb_device_properties wt220u_fc_properties;
++static struct dvb_usb_device_properties wt220u_properties;
++static struct dvb_usb_device_properties wt220u_zl0353_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,NULL) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
++ dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
+ return 0;
+
+@@ -114,32 +116,29 @@ static struct usb_device_id dtt200u_usb_
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) },
++ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) },
++ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) },
++ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) },
+ { 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,
+-
++static struct dvb_usb_device_properties dtt200u_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-dtt200u-01.fw",
+
+- .power_ctrl = dtt200u_power_ctrl,
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
++ .pid_filter_count = 15,
++
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -148,6 +147,16 @@ static struct dvb_usb_properties dtt200u
+ }
+ }
+ },
++ }
++ },
++ .power_ctrl = dtt200u_power_ctrl,
++
++ .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,
+
+ .num_device_descs = 1,
+ .devices = {
+@@ -159,28 +168,22 @@ static struct dvb_usb_properties dtt200u
+ }
+ };
+
+-static struct dvb_usb_properties wt220u_properties = {
+- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+- .pid_filter_count = 15,
+-
++static struct dvb_usb_device_properties wt220u_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-wt220u-02.fw",
+
+- .power_ctrl = dtt200u_power_ctrl,
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
++ .pid_filter_count = 15,
++
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -189,28 +192,54 @@ static struct dvb_usb_properties wt220u_
+ }
+ }
+ },
++ }
++ },
++ .power_ctrl = dtt200u_power_ctrl,
++
++ .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,
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
+- .cold_ids = { &dtt200u_usb_table[2], NULL },
++ .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
+ .warm_ids = { &dtt200u_usb_table[3], NULL },
+ },
+ { NULL },
+ }
+ };
+
+-static struct dvb_usb_properties wt220u_zl0353_properties = {
+- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+- .pid_filter_count = 15,
+-
++static struct dvb_usb_device_properties wt220u_fc_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+- .firmware = "dvb-usb-wt220u-zl0353-01.fw",
++ .firmware = "dvb-usb-wt220u-fc03.fw",
++
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
++ .pid_filter_count = 15,
+
+- .power_ctrl = dtt200u_power_ctrl,
+ .streaming_ctrl = dtt200u_streaming_ctrl,
+ .pid_filter = dtt200u_pid_filter,
+ .frontend_attach = dtt200u_frontend_attach,
++ /* parameter for the MPEG2-data transfer */
++ .stream = {
++ .type = USB_BULK,
++ .count = 7,
++ .endpoint = 0x06,
++ .u = {
++ .bulk = {
++ .buffersize = 4096,
++ }
++ }
++ },
++ }
++ },
++ .power_ctrl = dtt200u_power_ctrl,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+@@ -219,9 +248,32 @@ static struct dvb_usb_properties wt220u_
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
++ .num_device_descs = 1,
++ .devices = {
++ { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
++ .cold_ids = { &dtt200u_usb_table[6], NULL },
++ .warm_ids = { &dtt200u_usb_table[7], NULL },
++ },
++ { NULL },
++ }
++};
++
++static struct dvb_usb_device_properties wt220u_zl0353_properties = {
++ .usb_ctrl = CYPRESS_FX2,
++ .firmware = "dvb-usb-wt220u-zl0353-01.fw",
++
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
++ .pid_filter_count = 15,
++
++ .streaming_ctrl = dtt200u_streaming_ctrl,
++ .pid_filter = dtt200u_pid_filter,
++ .frontend_attach = dtt200u_frontend_attach,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -230,6 +282,16 @@ static struct dvb_usb_properties wt220u_
+ }
+ }
+ },
++ }
++ },
++ .power_ctrl = dtt200u_power_ctrl,
++
++ .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,
+
+ .num_device_descs = 1,
+ .devices = {
+@@ -271,6 +333,6 @@ module_init(dtt200u_usb_module_init);
+ module_exit(dtt200u_usb_module_exit);
+
+ MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher at desy.de>");
+-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices");
++MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
+ MODULE_VERSION("1.0");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+index a3460bf..35ab68f 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+@@ -14,31 +14,36 @@
+ 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)
++#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args)
++#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args)
++#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args)
++#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args)
++#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args)
++#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args)
++#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args)
++#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args)
++#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
+
+ /* commonly used methods */
+-extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
++extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
+
+-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_device_power_ctrl(struct dvb_usb_device *d, int onoff);
++
++extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
++extern int usb_urb_exit(struct usb_data_stream *stream);
++extern int usb_urb_submit(struct usb_data_stream *stream);
++extern int usb_urb_kill(struct usb_data_stream *stream);
++
++extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
++extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
+
+ 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_adapter_dvb_init(struct dvb_usb_adapter *adap);
++extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
++extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
++extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
+
+ extern int dvb_usb_remote_init(struct dvb_usb_device *);
+ extern int dvb_usb_remote_exit(struct dvb_usb_device *);
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+index ec63170..4561a67 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+@@ -1,6 +1,6 @@
+ /* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+@@ -8,55 +8,55 @@
+ */
+ #include "dvb-usb-common.h"
+
++/* does the complete input transfer handling */
+ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+ {
+- struct dvb_usb_device *d = dvbdmxfeed->demux->priv;
++ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+ int newfeedcount,ret;
+
+- if (d == NULL)
++ if (adap == NULL)
+ return -ENODEV;
+
+- newfeedcount = d->feedcount + (onoff ? 1 : -1);
++ newfeedcount = adap->feedcount + (onoff ? 1 : -1);
+
+- /*
+- * stop feed before setting a new pid if there will be no pid anymore
+- */
++ /* stop feed before setting a new pid if there will be no pid anymore */
+ if (newfeedcount == 0) {
+ deb_ts("stop feeding\n");
+- dvb_usb_urb_kill(d);
++ usb_urb_kill(&adap->stream);
+
+- if (d->props.streaming_ctrl != NULL)
+- if ((ret = d->props.streaming_ctrl(d,0)))
++ if (adap->props.streaming_ctrl != NULL)
++ if ((ret = adap->props.streaming_ctrl(adap,0)))
+ err("error while stopping stream.");
+-
+ }
+
+- d->feedcount = newfeedcount;
++ adap->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);
++ deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ?
++ "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ?
++ "on" : "off");
++ if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
++ adap->pid_filtering &&
++ adap->props.pid_filter != NULL)
++ adap->props.pid_filter(adap, 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) {
++ if (adap->feedcount == onoff && adap->feedcount > 0) {
+ deb_ts("submitting all URBs\n");
+- dvb_usb_urb_submit(d);
++ usb_urb_submit(&adap->stream);
+
+ 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)
++ if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
++ adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
++ adap->props.pid_filter_ctrl != NULL)
++ if (adap->props.pid_filter_ctrl(adap,adap->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)) {
++ if (adap->props.streaming_ctrl != NULL)
++ if (adap->props.streaming_ctrl(adap,1)) {
+ err("error while enabling fifo.");
+ return -ENODEV;
+ }
+@@ -77,134 +77,130 @@ static int dvb_usb_stop_feed(struct dvb_
+ return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+ }
+
+-int dvb_usb_dvb_init(struct dvb_usb_device *d)
++int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap)
+ {
+ int ret;
+
+- if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
+- d->owner, &d->udev->dev)) < 0) {
++ if ((ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
++ adap->dev->owner, &adap->dev->udev->dev)) < 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]);
++ adap->dvb_adap.priv = adap;
++
++ if (adap->dev->props.read_mac_address) {
++ if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
++ info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0],
++ adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2],
++ adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4],
++ adap->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;
++ adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
++ adap->demux.priv = adap;
+
+- 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) {
++ adap->demux.feednum = adap->demux.filternum = adap->max_feed_count;
++ adap->demux.start_feed = dvb_usb_start_feed;
++ adap->demux.stop_feed = dvb_usb_stop_feed;
++ adap->demux.write_to_decoder = NULL;
++ if ((ret = dvb_dmx_init(&adap->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) {
++ adap->dmxdev.filternum = adap->demux.filternum;
++ adap->dmxdev.demux = &adap->demux.dmx;
++ adap->dmxdev.capabilities = 0;
++ if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->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);
++ dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+
+- d->state |= DVB_USB_STATE_DVB;
++ adap->state |= DVB_USB_ADAP_STATE_DVB;
+ return 0;
+
+ err_dmx_dev:
+- dvb_dmx_release(&d->demux);
++ dvb_dmx_release(&adap->demux);
+ err_dmx:
+- dvb_unregister_adapter(&d->dvb_adap);
++ dvb_unregister_adapter(&adap->dvb_adap);
+ err:
+ return ret;
+ }
+
+-int dvb_usb_dvb_exit(struct dvb_usb_device *d)
++int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+ {
+- if (d->state & DVB_USB_STATE_DVB) {
++ if (adap->state & DVB_USB_ADAP_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;
++ dvb_net_release(&adap->dvb_net);
++ adap->demux.dmx.close(&adap->demux.dmx);
++ dvb_dmxdev_release(&adap->dmxdev);
++ dvb_dmx_release(&adap->demux);
++ dvb_unregister_adapter(&adap->dvb_adap);
++ adap->state &= ~DVB_USB_ADAP_STATE_DVB;
+ }
+ return 0;
+ }
+
+ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+ {
+- struct dvb_usb_device *d = fe->dvb->priv;
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+- if (d->props.power_ctrl)
+- d->props.power_ctrl(d,1);
++ dvb_usb_device_power_ctrl(adap->dev, 1);
+
+- if (d->fe_init)
+- d->fe_init(fe);
++ if (adap->fe_init)
++ adap->fe_init(fe);
+
+ return 0;
+ }
+
+ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+ {
+- struct dvb_usb_device *d = fe->dvb->priv;
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+- if (d->fe_sleep)
+- d->fe_sleep(fe);
++ if (adap->fe_sleep)
++ adap->fe_sleep(fe);
+
+- if (d->props.power_ctrl)
+- d->props.power_ctrl(d,0);
+-
+- return 0;
++ return dvb_usb_device_power_ctrl(adap->dev, 0);
+ }
+
+-int dvb_usb_fe_init(struct dvb_usb_device* d)
++int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
+ {
+- if (d->props.frontend_attach == NULL) {
+- err("strange '%s' doesn't want to attach a frontend.",d->desc->name);
++ if (adap->props.frontend_attach == NULL) {
++ err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id);
+ 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 (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) {
++ adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup;
++ adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep;
+
+- if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
++ if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
+ err("Frontend registration failed.");
+- if (d->fe->ops.release)
+- d->fe->ops.release(d->fe);
+- d->fe = NULL;
++ dvb_frontend_detach(adap->fe);
++ adap->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);
++ /* only attach the tuner if the demod is there */
++ if (adap->props.tuner_attach != NULL)
++ adap->props.tuner_attach(adap);
++ } else
++ err("no frontend was attached by '%s'",adap->dev->desc->name);
+
+ return 0;
+ }
+
+-int dvb_usb_fe_exit(struct dvb_usb_device *d)
++int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+ {
+- if (d->fe != NULL)
+- dvb_unregister_frontend(d->fe);
++ if (adap->fe != NULL) {
++ dvb_unregister_frontend(adap->fe);
++ dvb_frontend_detach(adap->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
+index 9222b0a..e1112e3 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+@@ -1,6 +1,6 @@
+ /* dvb-usb-firmware.c is part of the DVB USB library.
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at 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.
+@@ -24,9 +24,6 @@ static struct usb_cypress_controller cyp
+ { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
+ };
+
+-static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
+- int *pos);
+-
+ /*
+ * load a firmware packet to the device
+ */
+@@ -78,7 +75,7 @@ int usb_cypress_load_firmware(struct usb
+ }
+ EXPORT_SYMBOL(usb_cypress_load_firmware);
+
+-int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
++int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
+ {
+ int ret;
+ const struct firmware *fw = NULL;
+@@ -115,7 +112,7 @@ int dvb_usb_download_firmware(struct usb
+ return ret;
+ }
+
+-static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
++int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
+ int *pos)
+ {
+ u8 *b = (u8 *) &fw->data[*pos];
+@@ -146,3 +143,4 @@ static int dvb_usb_get_hexline(const str
+
+ return *pos;
+ }
++EXPORT_SYMBOL(dvb_usb_get_hexline);
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+index 6b611a7..55ba020 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+@@ -1,6 +1,6 @@
+ /* dvb-usb-i2c.c is part of the DVB USB library.
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for (de-)initializing an I2C adapter.
+@@ -48,48 +48,48 @@ int dvb_usb_i2c_exit(struct dvb_usb_devi
+
+ int dvb_usb_tuner_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 };
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
++ struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
+ int ret = 0;
+
+ /* if pll_desc is not used */
+- if (d->pll_desc == NULL)
++ if (adap->pll_desc == NULL)
+ return 0;
+
+- if (d->tuner_pass_ctrl)
+- d->tuner_pass_ctrl(fe,1,d->pll_addr);
++ if (adap->tuner_pass_ctrl)
++ adap->tuner_pass_ctrl(fe, 1, adap->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]);
++ deb_pll("pll init: %x\n",adap->pll_addr);
++ deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
++ adap->pll_init[2], adap->pll_init[3]);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+- if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
++ if (i2c_transfer (&adap->dev->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);
++ if (adap->tuner_pass_ctrl)
++ adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
+ return ret;
+ }
+ EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
+
+ int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
+ {
+- struct dvb_usb_device *d = fe->dvb->priv;
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+ if (buf_len != 5)
+ return -EINVAL;
+- if (d->pll_desc == NULL)
++ if (adap->pll_desc == NULL)
+ return 0;
+
+- deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
++ deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
+
+- b[0] = d->pll_addr;
+- dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
++ b[0] = adap->pll_addr;
++ dvb_pll_configure(adap->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]);
+
+@@ -99,26 +99,27 @@ EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
+
+ int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+ {
+- struct dvb_usb_device *d = fe->dvb->priv;
++ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ int ret = 0;
+ u8 b[5];
+- struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
++ struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
+
+ dvb_usb_tuner_calc_regs(fe,fep,b,5);
+
+- if (d->tuner_pass_ctrl)
+- d->tuner_pass_ctrl(fe,1,d->pll_addr);
++ if (adap->tuner_pass_ctrl)
++ adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+- if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
++
++ if (i2c_transfer(&adap->dev->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);
++ if (adap->tuner_pass_ctrl)
++ adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
+
+ return ret;
+ }
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+index 9569891..4d6b069 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+@@ -10,51 +10,52 @@
+ #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_KWORLD 0xeb2a
+-#define USB_VID_KYE 0x0458
+-#define USB_VID_MEDION 0x1660
+-#define USB_VID_PINNACLE 0x2304
+-#define USB_VID_VISIONPLUS 0x13d3
+-#define USB_VID_TWINHAN 0x1822
+-#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+-#define USB_VID_GENPIX 0x09c0
++#define USB_VID_ADSTECH 0x06e1
++#define USB_VID_ANCHOR 0x0547
++#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_GENPIX 0x09c0
++#define USB_VID_GRANDTEC 0x5032
++#define USB_VID_HANFTEK 0x15f4
++#define USB_VID_HAUPPAUGE 0x2040
++#define USB_VID_HYPER_PALTEK 0x1025
++#define USB_VID_KWORLD 0xeb2a
++#define USB_VID_KYE 0x0458
++#define USB_VID_LEADTEK 0x0413
++#define USB_VID_LITEON 0x04ca
++#define USB_VID_MEDION 0x1660
++#define USB_VID_PINNACLE 0x2304
++#define USB_VID_VISIONPLUS 0x13d3
++#define USB_VID_TWINHAN 0x1822
++#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
++#define USB_VID_WIDEVIEW 0x14aa
+
+ /* 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_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_HOOK_DEFAULT 0x0064
+-#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
++#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
+ #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_STK7700 0x1e14
+-#define USB_PID_DIBCOM_STK7700_REENUM 0x1e15
+-#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_DIBCOM_STK7700P 0x1e14
++#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
+@@ -69,25 +70,34 @@
+ #define USB_PID_DNTV_TINYUSB2_WARM 0x3224
+ #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_WARM 0x810a
+-#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_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_WARM 0x810a
++#define USB_PID_ARTEC_T14_COLD 0x810b
++#define USB_PID_ARTEC_T14_WARM 0x810c
++#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_WT220U_ZAP250_COLD 0x0220
++#define USB_PID_WT220U_COLD 0x0222
++#define USB_PID_WT220U_WARM 0x0221
++#define USB_PID_WT220U_FC_COLD 0x0225
++#define USB_PID_WT220U_FC_WARM 0x0226
+ #define USB_PID_WT220U_ZL0353_COLD 0x022a
+ #define USB_PID_WT220U_ZL0353_WARM 0x022b
+-#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
+-#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
++#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
++#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
++#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941
++#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
++#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
++#define USB_PID_AVERMEDIA_VOLAR 0x1234
+ #define USB_PID_NEBULA_DIGITV 0x0201
+ #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
+ #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
+@@ -96,15 +106,26 @@
+ #define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01
+ #define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10
+ #define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11
+-#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD 0xdb50
+-#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM 0xdb51
+-#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD 0xdb54
+-#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM 0xdb55
++#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD 0xdb50
++#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51
++#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58
++#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59
++#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
++#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55
+ #define USB_PID_MEDION_MD95700 0x0932
+ #define USB_PID_KYE_DVB_T_COLD 0x701e
+ #define USB_PID_KYE_DVB_T_WARM 0x701f
+-#define USB_PID_PCTV_200E 0x020e
+-#define USB_PID_PCTV_400E 0x020f
+-#define USB_PID_GENPIX_8PSK_COLD 0x0200
+-#define USB_PID_GENPIX_8PSK_WARM 0x0201
++#define USB_PID_PCTV_200E 0x020e
++#define USB_PID_PCTV_400E 0x020f
++#define USB_PID_LITEON_DVB_T_COLD 0xf000
++#define USB_PID_LITEON_DVB_T_WARM 0xf001
++#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
++#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361
++#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6
++#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7
++#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
++#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
++#define USB_PID_GENPIX_8PSK_COLD 0x0200
++#define USB_PID_GENPIX_8PSK_WARM 0x0201
++
+ #endif
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+index a1705ec..ffdde83 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+@@ -3,7 +3,7 @@
+ *
+ * dvb-usb-init.c
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at 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
+@@ -16,21 +16,105 @@
+ /* 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);
++MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (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).");
+
++static int dvb_usb_force_pid_filter_usage;
++module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
++MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
++
++static int dvb_usb_adapter_init(struct dvb_usb_device *d)
++{
++ struct dvb_usb_adapter *adap;
++ int ret,n;
++
++ for (n = 0; n < d->props.num_adapters; n++) {
++ adap = &d->adapter[n];
++ adap->dev = d;
++ adap->id = n;
++
++ memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
++
++/* speed - when running at FULL speed we need a HW PID filter */
++ if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_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 && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
++ (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
++ info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
++ adap->pid_filtering = 1;
++ adap->max_feed_count = adap->props.pid_filter_count;
++ } else {
++ info("will pass the complete MPEG2 transport stream to the software demuxer.");
++ adap->pid_filtering = 0;
++ adap->max_feed_count = 255;
++ }
++
++ if (!adap->pid_filtering &&
++ dvb_usb_force_pid_filter_usage &&
++ adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) {
++ info("pid filter enabled by module option.");
++ adap->pid_filtering = 1;
++ adap->max_feed_count = adap->props.pid_filter_count;
++ }
++
++ if (adap->props.size_of_priv > 0) {
++ adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
++ if (adap->priv == NULL) {
++ err("no memory for priv for adapter %d.",n);
++ return -ENOMEM;
++ }
++ }
++
++ if ((ret = dvb_usb_adapter_stream_init(adap)) ||
++ (ret = dvb_usb_adapter_dvb_init(adap)) ||
++ (ret = dvb_usb_adapter_frontend_init(adap))) {
++ return ret;
++ }
++
++ d->num_adapters_initialized++;
++ d->state |= DVB_USB_STATE_DVB;
++ }
++
++ /*
++ * 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));
++ }
++
++ return 0;
++}
++
++static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
++{
++ int n;
++ for (n = 0; n < d->num_adapters_initialized; n++) {
++ dvb_usb_adapter_frontend_exit(&d->adapter[n]);
++ dvb_usb_adapter_dvb_exit(&d->adapter[n]);
++ dvb_usb_adapter_stream_exit(&d->adapter[n]);
++ kfree(d->adapter[n].priv);
++ }
++ d->num_adapters_initialized = 0;
++ d->state &= ~DVB_USB_STATE_DVB;
++ return 0;
++}
++
++
+ /* general initialization functions */
+ static 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_adapter_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);
+@@ -47,32 +131,19 @@ static int dvb_usb_init(struct dvb_usb_d
+
+ d->state = DVB_USB_STATE_INIT;
+
+-/* check the capabilities 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.size_of_priv > 0) {
++ d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
++ if (d->priv == NULL) {
++ err("no memory for priv in 'struct dvb_usb_device'");
++ return -ENOMEM;
++ }
+ }
+
+- if (d->props.power_ctrl)
+- d->props.power_ctrl(d,1);
++/* check the capabilities and set appropriate variables */
++ dvb_usb_device_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))) {
++ if ((ret = dvb_usb_i2c_init(d)) ||
++ (ret = dvb_usb_adapter_init(d))) {
+ dvb_usb_exit(d);
+ return ret;
+ }
+@@ -80,14 +151,13 @@ static int dvb_usb_init(struct dvb_usb_d
+ if ((ret = dvb_usb_remote_init(d)))
+ err("could not initialize remote control.");
+
+- if (d->props.power_ctrl)
+- d->props.power_ctrl(d,0);
++ dvb_usb_device_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)
++static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
+ {
+ int i,j;
+ struct dvb_usb_device_description *desc = NULL;
+@@ -125,11 +195,25 @@ static struct dvb_usb_device_description
+ return desc;
+ }
+
++int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
++{
++ if (onoff)
++ d->powered++;
++ else
++ d->powered--;
++
++ if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
++ deb_info("power control: %d\n", onoff);
++ if (d->props.power_ctrl)
++ return d->props.power_ctrl(d, onoff);
++ }
++ return 0;
++}
++
+ /*
+ * USB
+ */
+-
+-int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
++int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_device_properties
+ *props, struct module *owner,struct dvb_usb_device **du)
+ {
+ struct usb_device *udev = interface_to_usbdev(intf);
+@@ -149,7 +233,7 @@ int dvb_usb_device_init(struct usb_inter
+ if (cold) {
+ info("found a '%s' in cold state, will try to load a firmware",desc->name);
+ ret = dvb_usb_download_firmware(udev,props);
+- if (!props->no_reconnect)
++ if (!props->no_reconnect || ret != 0)
+ return ret;
+ }
+
+@@ -161,19 +245,10 @@ int dvb_usb_device_init(struct usb_inter
+ }
+
+ d->udev = udev;
+- memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
++ memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
+ d->desc = desc;
+ d->owner = owner;
+
+- if (d->props.size_of_priv > 0) {
+- d->priv = kzalloc(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;
+- }
+- }
+-
+ usb_set_intfdata(intf, d);
+
+ if (du != NULL)
+@@ -204,7 +279,7 @@ void dvb_usb_device_exit(struct usb_inte
+ }
+ EXPORT_SYMBOL(dvb_usb_device_exit);
+
+-MODULE_VERSION("0.3");
++MODULE_VERSION("1.0");
+ MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher at 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
+index e5c6d98..0a3a0b6 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+@@ -1,11 +1,12 @@
+ /* dvb-usb-remote.c is part of the DVB USB library.
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at 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"
++#include <linux/usb/input.h>
+
+ /* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+@@ -96,7 +97,7 @@ int dvb_usb_remote_init(struct dvb_usb_d
+ return 0;
+
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+- strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys));
++ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+ d->rc_input_dev = input_allocate_device();
+ if (!d->rc_input_dev)
+@@ -107,6 +108,8 @@ int dvb_usb_remote_init(struct dvb_usb_d
+ d->rc_input_dev->keycodemax = KEY_MAX;
+ d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver";
+ d->rc_input_dev->phys = d->rc_phys;
++ usb_to_input_id(d->udev, &d->rc_input_dev->id);
++ d->rc_input_dev->cdev.dev = &d->udev->dev;
+
+ /* set the bits for the keys */
+ deb_rc("key map size: %d\n", d->props.rc_key_map_size);
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+index 9002f35..5cef12a 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+@@ -1,9 +1,9 @@
+ /* dvb-usb-urb.c is part of the DVB USB library.
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+- * This file contains functions for initializing and handling the
++ * This file keeps functions for initializing and handling the
+ * USB and URB stuff.
+ */
+ #include "dvb-usb-common.h"
+@@ -64,261 +64,32 @@ int dvb_usb_generic_write(struct dvb_usb
+ }
+ 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 = kcalloc(num, sizeof(u8 *), GFP_ATOMIC)) == NULL)
+- return -ENOMEM;
+-
+- if ((d->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) {
+- kfree(d->buf_list);
+- return -ENOMEM;
+- }
+-
+- 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: %llu)\n",
+- d->buf_num, d->buf_list[d->buf_num],
+- (unsigned long long)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)
++static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
+ {
+- 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;
++ struct dvb_usb_adapter *adap = stream->user_priv;
++ if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
++ dvb_dmx_swfilter(&adap->demux, buffer, length);
+ }
+
+-static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d)
++static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
+ {
+- 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;
+-
++ struct dvb_usb_adapter *adap = stream->user_priv;
++ if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
++ dvb_dmx_swfilter_204(&adap->demux, buffer, length);
+ }
+
+-int dvb_usb_urb_init(struct dvb_usb_device *d)
++int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
+ {
+- /*
+- * 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 = kzalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL);
+- if (d->urb_list == NULL)
+- return -ENOMEM;
+- 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;
+- }
++ adap->stream.udev = adap->dev->udev;
++ if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
++ adap->stream.complete = dvb_usb_data_complete_204;
++ else
++ adap->stream.complete = dvb_usb_data_complete;
++ adap->stream.user_priv = adap;
++ return usb_urb_init(&adap->stream, &adap->props.stream);
+ }
+
+-int dvb_usb_urb_exit(struct dvb_usb_device *d)
++int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
+ {
+- 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;
++ return usb_urb_exit(&adap->stream);
+ }
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
+index 97f8ea9..376c45a 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
++++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
+@@ -1,9 +1,11 @@
+ /* dvb-usb.h is part of the DVB USB library.
+ *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * the headerfile, all dvb-usb-drivers have to include.
++ *
++ * TODO: clean-up the structures for unused fields and update the comments
+ */
+ #ifndef __DVB_USB_H__
+ #define __DVB_USB_H__
+@@ -84,36 +86,84 @@ struct dvb_usb_rc_key {
+ };
+
+ struct dvb_usb_device;
++struct dvb_usb_adapter;
++struct usb_data_stream;
++
++/**
++ * Properties of USB streaming - TODO this structure should be somewhere else
++ * describes the kind of USB transfer used for data-streaming.
++ * (BULK or ISOC)
++ */
++struct usb_data_stream_properties {
++#define USB_BULK 1
++#define 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;
++};
+
+ /**
+- * struct dvb_usb_properties - properties of a dvb-usb-device
++ * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
++ * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
+ * @caps: capabilities of the DVB USB device.
+ * @pid_filter_count: number of PID filter position in the optional hardware
+ * PID-filter.
+- *
++ * @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.
++ * @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).
++ * @stream: configuration of the USB streaming
++ */
++struct dvb_usb_adapter_properties {
++#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
++#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
++#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
++#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
++ int caps;
++ int pid_filter_count;
++
++ int (*streaming_ctrl) (struct dvb_usb_adapter *, int);
++ int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
++ int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
++
++ int (*frontend_attach) (struct dvb_usb_adapter *);
++ int (*tuner_attach) (struct dvb_usb_adapter *);
++
++ struct usb_data_stream_properties stream;
++
++ int size_of_priv;
++};
++
++/**
++ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
+ * download.
+ * @firmware: name of the firmware file.
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ * DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+- so do the warm initialization right after it
+-
++ * so do the warm initialization right after it
++ *
+ * @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.
+ *
+@@ -130,50 +180,40 @@ struct dvb_usb_device;
+ * 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.
+- * (BULK or ISOC)
+- *
+ * @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 MAX_NO_OF_ADAPTER_PER_DEVICE 2
++struct dvb_usb_device_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
++#define DVB_USB_IS_AN_I2C_ADAPTER 0x01
+ int caps;
+- int pid_filter_count;
+
+ #define DEVICE_SPECIFIC 0
+ #define CYPRESS_AN2135 1
+ #define CYPRESS_AN2235 2
+ #define CYPRESS_FX2 3
+- int usb_ctrl;
++ int usb_ctrl;
++ int (*download_firmware) (struct usb_device *, const struct firmware *);
+ const char firmware[FIRMWARE_NAME_MAX];
+- int (*download_firmware) (struct usb_device *, const struct firmware *);
+- int no_reconnect;
++ int no_reconnect;
+
+ 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 num_adapters;
++ struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
++ int (*power_ctrl) (struct dvb_usb_device *, 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 *,
++ int (*identify_state) (struct usb_device *, struct dvb_usb_device_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;
++ 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;
+@@ -182,40 +222,12 @@ struct dvb_usb_properties {
+
+ 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.
+- *
++ * struct usb_data_stream - generic object of an USB stream
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+@@ -223,18 +235,40 @@ struct dvb_usb_properties {
+ *
+ * @urbs_initialized: number of URBs initialized.
+ * @urbs_submitted: number of URBs submitted.
++ */
++#define MAX_NO_URBS_FOR_DATA_STREAM 10
++struct usb_data_stream {
++ struct usb_device *udev;
++ struct usb_data_stream_properties props;
++
++#define USB_STATE_INIT 0x00
++#define USB_STATE_URB_BUF 0x01
++ int state;
++
++ void (*complete) (struct usb_data_stream *, u8 *, size_t);
++
++ struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
++ int buf_num;
++ unsigned long buf_size;
++ u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
++ dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
++
++ int urbs_initialized;
++ int urbs_submitted;
++
++ void *user_priv;
++};
++
++/**
++ * struct dvb_usb_adapter - a DVB adapter on a USB device
++ * @id: index of this adapter (starting with 0).
+ *
+ * @feedcount: number of reqested feeds (used for streaming-activation)
+ * @pid_filtering: is hardware pid_filtering used or not.
+ *
+- * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+- * @i2c_mutex: 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.
+@@ -244,8 +278,62 @@ struct dvb_usb_properties {
+ * @dvb_frontend: device's frontend.
+ * @max_feed_count: how many feeds can be handled simultaneously by this
+ * device
++ *
++ * @fe_init: rerouted frontend-init (wakeup) function.
+ * @fe_sleep: rerouted frontend-sleep function.
+- * @fe_init: rerouted frontend-init (wakeup) function.
++ *
++ * @stream: the usb data stream.
++ */
++struct dvb_usb_adapter {
++ struct dvb_usb_device *dev;
++ struct dvb_usb_adapter_properties props;
++
++#define DVB_USB_ADAP_STATE_INIT 0x000
++#define DVB_USB_ADAP_STATE_DVB 0x001
++ int state;
++
++ u8 id;
++
++ int feedcount;
++ int pid_filtering;
++
++ /* 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_init) (struct dvb_frontend *);
++ int (*fe_sleep) (struct dvb_frontend *);
++
++ struct usb_data_stream stream;
++
++ void *priv;
++};
++
++/**
++ * 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.
++ *
++ * @powered: indicated whether the device is power or not.
++ * Powered is in/decremented for each call to modify the state.
++ * @udev: pointer to the device's struct usb_device.
++ *
++ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
++ * @i2c_mutex: semaphore for i2c-transfers
++ *
++ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
++ *
+ * @rc_input_dev: input device for the remote control.
+ * @rc_query_work: struct work_struct frequent rc queries
+ * @last_event: last triggered event
+@@ -255,32 +343,18 @@ struct dvb_usb_properties {
+ * in size_of_priv of dvb_usb_properties).
+ */
+ struct dvb_usb_device {
+- struct dvb_usb_properties props;
++ struct dvb_usb_device_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;
++#define DVB_USB_STATE_INIT 0x000
++#define DVB_USB_STATE_I2C 0x001
++#define DVB_USB_STATE_DVB 0x002
++#define DVB_USB_STATE_REMOTE 0x004
++ int state;
+
+- int feedcount;
+- int pid_filtering;
++ int powered;
+
+ /* locking */
+ struct mutex usb_mutex;
+@@ -289,22 +363,8 @@ struct dvb_usb_device {
+ struct mutex i2c_mutex;
+ 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 *);
++ int num_adapters_initialized;
++ struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+ /* remote control */
+ struct input_dev *rc_input_dev;
+@@ -318,7 +378,7 @@ struct dvb_usb_device {
+ void *priv;
+ };
+
+-extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *, struct dvb_usb_device **);
++extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_device_properties *, struct module *, struct dvb_usb_device **);
+ extern void dvb_usb_device_exit(struct usb_interface *);
+
+ /* the generic read/write method for device control */
+@@ -342,5 +402,7 @@ struct hexline {
+ u8 chk;
+ };
+ extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
++extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
++
+
+ #endif
+diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
+index 9a98f3f..7375eb2 100644
+--- a/drivers/media/dvb/dvb-usb/gp8psk.c
++++ b/drivers/media/dvb/dvb-usb/gp8psk.c
+@@ -161,19 +161,18 @@ static int gp8psk_power_ctrl(struct dvb_
+ }
+
+
+-static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
++static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+- return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
++ return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
+ }
+
+-static int gp8psk_frontend_attach(struct dvb_usb_device *d)
++static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- d->fe = gp8psk_fe_attach(d);
+-
++ adap->fe = gp8psk_fe_attach(adap->dev);
+ return 0;
+ }
+
+-static struct dvb_usb_properties gp8psk_properties;
++static struct dvb_usb_device_properties gp8psk_properties;
+
+ static int gp8psk_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -188,20 +187,18 @@ static struct usb_device_id gp8psk_usb_t
+ };
+ MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+-static struct dvb_usb_properties gp8psk_properties = {
+- .caps = 0,
+-
++static struct dvb_usb_device_properties gp8psk_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-gp8psk-01.fw",
+
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .streaming_ctrl = gp8psk_streaming_ctrl,
+- .power_ctrl = gp8psk_power_ctrl,
+ .frontend_attach = gp8psk_frontend_attach,
+-
+- .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x82,
+ .u = {
+@@ -210,6 +207,11 @@ static struct dvb_usb_properties gp8psk_
+ }
+ }
+ },
++ }
++ },
++ .power_ctrl = gp8psk_power_ctrl,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+@@ -217,7 +219,7 @@ static struct dvb_usb_properties gp8psk_
+ .cold_ids = { &gp8psk_usb_table[0], NULL },
+ .warm_ids = { &gp8psk_usb_table[1], NULL },
+ },
+- { 0 },
++ { NULL },
+ }
+ };
+
+diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+index 412039d..a58874c 100644
+--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
++++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+@@ -75,7 +75,7 @@ static int nova_t_rc_query(struct dvb_us
+ u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
+ u16 raw;
+ int i;
+- struct dibusb_state *st = d->priv;
++ struct dibusb_device_state *st = d->priv;
+
+ dvb_usb_generic_rw(d,cmd,2,key,5,0);
+
+@@ -135,7 +135,7 @@ static int nova_t_read_mac_address (stru
+ }
+
+ /* USB Driver stuff */
+-static struct dvb_usb_properties nova_t_properties;
++static struct dvb_usb_device_properties nova_t_properties;
+
+ static int nova_t_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -151,34 +151,27 @@ static struct usb_device_id nova_t_table
+ };
+ 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,
++static struct dvb_usb_device_properties nova_t_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+- .firmware = "dvb-usb-nova-t-usb2-01.fw",
++ .firmware = "dvb-usb-nova-t-usb2-02.fw",
+
+- .size_of_priv = sizeof(struct dibusb_state),
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
++ .pid_filter_count = 32,
+
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+@@ -188,6 +181,23 @@ static struct dvb_usb_properties nova_t_
+ }
+ },
+
++ .size_of_priv = sizeof(struct dibusb_state),
++ }
++ },
++ .size_of_priv = sizeof(struct dibusb_device_state),
++
++ .power_ctrl = dibusb2_0_power_ctrl,
++ .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,
++
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge WinTV-NOVA-T usb2",
+diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
+index 97d74da..f9941ea 100644
+--- a/drivers/media/dvb/dvb-usb/umt-010.c
++++ b/drivers/media/dvb/dvb-usb/umt-010.c
+@@ -50,7 +50,7 @@ static int umt_mt352_demod_init(struct d
+ return 0;
+ }
+
+-static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
++static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+ struct mt352_config umt_config;
+
+@@ -58,21 +58,21 @@ static int umt_mt352_frontend_attach(str
+ umt_config.demod_init = umt_mt352_demod_init;
+ umt_config.demod_address = 0xf;
+
+- d->fe = mt352_attach(&umt_config, &d->i2c_adap);
++ adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
+
+ return 0;
+ }
+
+-static int umt_tuner_attach (struct dvb_usb_device *d)
++static int umt_tuner_attach (struct dvb_usb_adapter *adap)
+ {
+- d->pll_addr = 0x61;
+- d->pll_desc = &dvb_pll_tua6034;
+- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
++ adap->pll_addr = 0x61;
++ adap->pll_desc = &dvb_pll_tua6034;
++ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+ }
+
+ /* USB Driver stuff */
+-static struct dvb_usb_properties umt_properties;
++static struct dvb_usb_device_properties umt_properties;
+
+ static int umt_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -90,25 +90,22 @@ static struct usb_device_id umt_table []
+ };
+ MODULE_DEVICE_TABLE (usb, umt_table);
+
+-static struct dvb_usb_properties umt_properties = {
++static struct dvb_usb_device_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),
+-
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 20,
+ .endpoint = 0x06,
+ .u = {
+@@ -118,6 +115,15 @@ static struct dvb_usb_properties umt_pro
+ }
+ },
+
++ .size_of_priv = sizeof(struct dibusb_state),
++ }
++ },
++ .power_ctrl = dibusb_power_ctrl,
++
++ .i2c_algo = &dibusb_i2c_algo,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
++
+ .num_device_descs = 1,
+ .devices = {
+ { "Hanftek UMT-010 DVB-T USB2.0",
+diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c
+new file mode 100644
+index 0000000..78035ee
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/usb-urb.c
+@@ -0,0 +1,243 @@
++/* usb-urb.c is part of the DVB USB library.
++ *
++ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher at desy.de)
++ * see dvb-usb-init.c for copyright information.
++ *
++ * This file keeps functions for initializing and handling the
++ * BULK and ISOC USB data transfers in a generic way.
++ * Can be used for DVB-only and also, that's the plan, for
++ * Hybrid USB devices (analog and DVB).
++ */
++#include "dvb-usb-common.h"
++
++/* URB stuff for streaming */
++static void usb_urb_complete(struct urb *urb)
++{
++ struct usb_data_stream *stream = urb->context;
++ int ptype = usb_pipetype(urb->pipe);
++ int i;
++ u8 *b;
++
++ deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
++ ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
++ 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.\n", urb->status);
++ break;
++ }
++
++ b = (u8 *) urb->transfer_buffer;
++ switch (ptype) {
++ case PIPE_ISOCHRONOUS:
++ 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)
++ stream->complete(stream, 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_uxfer);
++ break;
++ case PIPE_BULK:
++ if (urb->actual_length > 0)
++ stream->complete(stream, b, urb->actual_length);
++ break;
++ default:
++ err("unkown endpoint type in completition handler.");
++ return;
++ }
++ usb_submit_urb(urb,GFP_ATOMIC);
++}
++
++int usb_urb_kill(struct usb_data_stream *stream)
++{
++ int i;
++ for (i = 0; i < stream->urbs_submitted; i++) {
++ deb_ts("killing URB no. %d.\n",i);
++
++ /* stop the URB */
++ usb_kill_urb(stream->urb_list[i]);
++ }
++ stream->urbs_submitted = 0;
++ return 0;
++}
++
++int usb_urb_submit(struct usb_data_stream *stream)
++{
++ int i,ret;
++ for (i = 0; i < stream->urbs_initialized; i++) {
++ deb_ts("submitting URB no. %d\n",i);
++ if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
++ err("could not submit URB no. %d - get them all back",i);
++ usb_urb_kill(stream);
++ return ret;
++ }
++ stream->urbs_submitted++;
++ }
++ return 0;
++}
++
++static int usb_free_stream_buffers(struct usb_data_stream *stream)
++{
++ if (stream->state & USB_STATE_URB_BUF) {
++ while (stream->buf_num) {
++ stream->buf_num--;
++ deb_mem("freeing buffer %d\n",stream->buf_num);
++ usb_buffer_free(stream->udev, stream->buf_size,
++ stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]);
++ }
++ }
++
++ stream->state &= ~USB_STATE_URB_BUF;
++
++ return 0;
++}
++
++static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
++{
++ stream->buf_num = 0;
++ stream->buf_size = size;
++
++ deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
++
++ for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
++ deb_mem("allocating buffer %d\n",stream->buf_num);
++ if (( stream->buf_list[stream->buf_num] =
++ usb_buffer_alloc(stream->udev, size, SLAB_ATOMIC,
++ &stream->dma_addr[stream->buf_num]) ) == NULL) {
++ deb_mem("not enough memory for urb-buffer allocation.\n");
++ usb_free_stream_buffers(stream);
++ return -ENOMEM;
++ }
++ deb_mem("buffer %d: %p (dma: %Lu)\n",
++ stream->buf_num,
++stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
++ memset(stream->buf_list[stream->buf_num],0,size);
++ stream->state |= USB_STATE_URB_BUF;
++ }
++ deb_mem("allocation successful\n");
++
++ return 0;
++}
++
++static int usb_bulk_urb_init(struct usb_data_stream *stream)
++{
++ int i;
++
++ if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
++ stream->props.u.bulk.buffersize)) < 0)
++ return i;
++
++ /* allocate the URBs */
++ for (i = 0; i < stream->props.count; i++) {
++ if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
++ return -ENOMEM;
++
++ usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
++ usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
++ stream->buf_list[i],
++ stream->props.u.bulk.buffersize,
++ usb_urb_complete, stream);
++
++ stream->urb_list[i]->transfer_flags = 0;
++ stream->urbs_initialized++;
++ }
++ return 0;
++}
++
++static int usb_isoc_urb_init(struct usb_data_stream *stream)
++{
++ int i,j;
++
++ if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
++ stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
++ return i;
++
++ /* allocate the URBs */
++ for (i = 0; i < stream->props.count; i++) {
++ struct urb *urb;
++ int frame_offset = 0;
++ if ((stream->urb_list[i] =
++ usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
++ return -ENOMEM;
++
++ urb = stream->urb_list[i];
++
++ urb->dev = stream->udev;
++ urb->context = stream;
++ urb->complete = usb_urb_complete;
++ urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
++ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
++ urb->interval = stream->props.u.isoc.interval;
++ urb->number_of_packets = stream->props.u.isoc.framesperurb;
++ urb->transfer_buffer_length = stream->buf_size;
++ urb->transfer_buffer = stream->buf_list[i];
++ urb->transfer_dma = stream->dma_addr[i];
++
++ for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
++ urb->iso_frame_desc[j].offset = frame_offset;
++ urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
++ frame_offset += stream->props.u.isoc.framesize;
++ }
++
++ stream->urbs_initialized++;
++ }
++ return 0;
++}
++
++int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
++{
++ if (stream == NULL || props == NULL)
++ return -EINVAL;
++
++ memcpy(&stream->props, props, sizeof(*props));
++
++ usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
++
++ if (stream->complete == NULL) {
++ err("there is no data callback - this doesn't make sense.");
++ return -EINVAL;
++ }
++
++ switch (stream->props.type) {
++ case USB_BULK:
++ return usb_bulk_urb_init(stream);
++ case USB_ISOC:
++ return usb_isoc_urb_init(stream);
++ default:
++ err("unkown URB-type for data transfer.");
++ return -EINVAL;
++ }
++}
++
++int usb_urb_exit(struct usb_data_stream *stream)
++{
++ int i;
++
++ usb_urb_kill(stream);
++
++ for (i = 0; i < stream->urbs_initialized; i++) {
++ if (stream->urb_list[i] != NULL) {
++ deb_mem("freeing URB no. %d.\n",i);
++ /* free the URBs */
++ usb_free_urb(stream->urb_list[i]);
++ }
++ }
++ stream->urbs_initialized = 0;
++
++ usb_free_stream_buffers(stream);
++ return 0;
++}
+diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
+index d4da494..3ecb2e0 100644
+--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
++++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
+@@ -24,6 +24,8 @@ struct vp702x_fe_state {
+ struct dvb_frontend fe;
+ struct dvb_usb_device *d;
+
++ struct dvb_frontend_ops ops;
++
+ fe_sec_voltage_t voltage;
+ fe_sec_tone_mode_t tone_mode;
+
+@@ -72,9 +74,6 @@ static int vp702x_fe_read_status(struct
+ else
+ *status = 0;
+
+- deb_fe("real state: %x\n",*status);
+- *status = 0x1f;
+-
+ if (*status & FE_HAS_LOCK)
+ st->status_check_interval = 1000;
+ else
+@@ -171,8 +170,6 @@ static int vp702x_fe_set_frontend(struct
+ st->status_check_interval = 250;
+ st->next_status_check = jiffies;
+
+- vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
+- msleep(30);
+ vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+
+ if (ibuf[2] == 0 && ibuf[3] == 0)
+@@ -183,6 +180,20 @@ static int vp702x_fe_set_frontend(struct
+ return 0;
+ }
+
++static int vp702x_fe_init(struct dvb_frontend *fe)
++{
++ struct vp702x_fe_state *st = fe->demodulator_priv;
++ deb_fe("%s\n",__FUNCTION__);
++ vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
++ return 0;
++}
++
++static int vp702x_fe_sleep(struct dvb_frontend *fe)
++{
++ deb_fe("%s\n",__FUNCTION__);
++ return 0;
++}
++
+ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+ {
+@@ -193,8 +204,8 @@ static int vp702x_fe_get_frontend(struct
+ static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+ {
+- struct vp702x_fe_state *st = fe->demodulator_priv;
+- u8 cmd[8],ibuf[10];
++ //struct vp702x_fe_state *st = fe->demodulator_priv;
++ u8 cmd[8];//,ibuf[10];
+ memset(cmd,0,8);
+
+ deb_fe("%s\n",__FUNCTION__);
+@@ -207,12 +218,12 @@ static int vp702x_fe_send_diseqc_msg (st
+ memcpy(&cmd[3], m->msg, m->msg_len);
+ cmd[7] = vp702x_chksum(cmd,0,7);
+
+- vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
++// vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+
+- if (ibuf[2] == 0 && ibuf[3] == 0)
+- deb_fe("diseqc cmd failed.\n");
+- else
+- deb_fe("diseqc cmd succeeded.\n");
++// if (ibuf[2] == 0 && ibuf[3] == 0)
++// deb_fe("diseqc cmd failed.\n");
++// else
++// deb_fe("diseqc cmd succeeded.\n");
+
+ return 0;
+ }
+@@ -318,8 +329,8 @@ static struct dvb_frontend_ops vp702x_fe
+ },
+ .release = vp702x_fe_release,
+
+- .init = NULL,
+- .sleep = NULL,
++ .init = vp702x_fe_init,
++ .sleep = vp702x_fe_sleep,
+
+ .set_frontend = vp702x_fe_set_frontend,
+ .get_frontend = vp702x_fe_get_frontend,
+diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
+index b2f098a..02bd61a 100644
+--- a/drivers/media/dvb/dvb-usb/vp702x.c
++++ b/drivers/media/dvb/dvb-usb/vp702x.c
+@@ -22,50 +22,54 @@ module_param_named(debug,dvb_usb_vp702x_
+ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+ struct vp702x_state {
+- u8 pid_table[17]; /* [16] controls the pid_table state */
++ int pid_filter_count;
++ int pid_filter_can_bypass;
++ u8 pid_filter_state;
++};
++
++struct vp702x_device_state {
++ u8 power_state;
+ };
+
+ /* check for mutex FIXME */
+ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+ {
+- int ret = 0,try = 0;
++ int ret = -1;
+
+- while (ret >= 0 && ret != blen && try < 3) {
+ ret = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value,index,b,blen,
+ 2000);
+- deb_info("reading number %d (ret: %d)\n",try,ret);
+- try++;
+- }
+
+- if (ret < 0 || ret != blen) {
+- warn("usb in operation failed.");
++ if (ret < 0) {
++ warn("usb in operation failed. (%d)", ret);
+ ret = -EIO;
+ } else
+ ret = 0;
+
+- deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
++
++ deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ return ret;
+ }
+
+-static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
++int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+ {
+- deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
++ int ret;
++ deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+- if (usb_control_msg(d->udev,
++ if ((ret = usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value,index,b,blen,
+- 2000) != blen) {
+- warn("usb out operation failed.");
++ 2000)) != blen) {
++ warn("usb out operation failed. (%d)",ret);
+ return -EIO;
+ } else
+ return 0;
+@@ -78,12 +82,10 @@ int vp702x_usb_inout_op(struct dvb_usb_d
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+- if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
+- goto unlock;
++ ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
+ msleep(msec);
+ ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
+
+-unlock:
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+@@ -108,29 +110,65 @@ static int vp702x_usb_inout_cmd(struct d
+ return ret;
+ }
+
+-static int vp702x_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
++static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
++{
++ u8 buf[16] = { 0 };
++ return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
++}
++
++static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
++{
++ u8 buf[16] = { 0 };
++ return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
++}
++
++static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
+ {
+- struct vp702x_state *st = d->priv;
+- u8 buf[9];
+-
+- if (onoff) {
+- st->pid_table[16] |= 1 << index;
+- st->pid_table[index*2] = (pid >> 8) & 0xff;
+- st->pid_table[index*2+1] = pid & 0xff;
+- } else {
+- st->pid_table[16] &= ~(1 << index);
+- st->pid_table[index*2] = st->pid_table[index*2+1] = 0;
++ struct vp702x_state *st = adap->priv;
++ u8 buf[16] = { 0 };
++
++ if (onoff)
++ st->pid_filter_state |= (1 << id);
++ else {
++ st->pid_filter_state &= ~(1 << id);
++ pid = 0xffff;
+ }
+
+- return vp702x_usb_inout_cmd(d,SET_PID_FILTER,st->pid_table,17,buf,9,10);
++ id = 0x10 + id*2;
++
++ vp702x_set_pld_state(adap, st->pid_filter_state);
++ vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
++ vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
++ return 0;
+ }
+
+-static int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
++
++static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
+ {
+- vp702x_usb_in_op(d,RESET_TUNER,0,0,NULL,0);
++ struct vp702x_state *st = adap->priv;
++ int i;
++ u8 b[10] = { 0 };
++
++ st->pid_filter_count = 8;
++ st->pid_filter_can_bypass = 1;
++ st->pid_filter_state = 0x00;
++
++ vp702x_set_pld_mode(adap, 1); // bypass
++
++ for (i = 0; i < st->pid_filter_count; i++)
++ vp702x_set_pid(adap, 0xffff, i, 1);
+
+- vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0);
+- return vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0);
++ vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
++ vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
++ vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
++
++ //vp702x_set_pld_mode(d, 0); // filter
++ return 0;
++}
++
++static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
++{
++ return 0;
+ }
+
+ /* keys for the enclosed remote control */
+@@ -166,74 +204,83 @@ static int vp702x_rc_query(struct dvb_us
+ return 0;
+ }
+
++int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
++{
++ struct vp702x_device_state *st = d->priv;
++
++ if (st->power_state == 0 && onoff)
++ vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
++ else if (st->power_state == 1 && onoff == 0)
++ vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
++
++ st->power_state = onoff;
++
++ return 0;
++}
++
+ static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
+ {
+- u8 macb[9];
+- if (vp702x_usb_inout_cmd(d, GET_MAC_ADDRESS, NULL, 0, macb, 9, 10))
+- return -EIO;
+- memcpy(mac,&macb[3],6);
++ u8 i;
++ for (i = 6; i < 12; i++)
++ vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
+ return 0;
+ }
+
+-static int vp702x_frontend_attach(struct dvb_usb_device *d)
++static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+- u8 buf[9] = { 0 };
++ u8 buf[10] = { 0 };
++
++ vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
+
+- if (vp702x_usb_inout_cmd(d, GET_SYSTEM_STRING, NULL, 0, buf, 9, 10))
++ if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
+ return -EIO;
+
+- buf[8] = '\0';
++ buf[9] = '\0';
+ info("system string: %s",&buf[1]);
+
+- d->fe = vp702x_fe_attach(d);
++ vp702x_init_pid_filter(adap);
++
++ adap->fe = vp702x_fe_attach(adap->dev);
++ vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
++
+ return 0;
+ }
+
+-static struct dvb_usb_properties vp702x_properties;
++static struct dvb_usb_device_properties vp702x_properties;
+
+ static int vp702x_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+- struct usb_device *udev = interface_to_usbdev(intf);
+-
+- usb_clear_halt(udev,usb_sndctrlpipe(udev,0));
+- usb_clear_halt(udev,usb_rcvctrlpipe(udev,0));
+-
+ return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL);
+ }
+
+ static struct usb_device_id vp702x_usb_table [] = {
+ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
+- { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_WARM) },
+- { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
+- { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
++// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
++// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
+ { 0 },
+ };
+ MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
+
+-static struct dvb_usb_properties vp702x_properties = {
+- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+- .pid_filter_count = 8, /* !!! */
+-
++static struct dvb_usb_device_properties vp702x_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+- .firmware = "dvb-usb-vp702x-01.fw",
++ .firmware = "dvb-usb-vp702x-02.fw",
++ .no_reconnect = 1,
+
+- .pid_filter = vp702x_pid_filter,
+- .power_ctrl = vp702x_power_ctrl,
+- .frontend_attach = vp702x_frontend_attach,
+- .read_mac_address = vp702x_read_mac_addr,
++ .size_of_priv = sizeof(struct vp702x_device_state),
+
+- .rc_key_map = vp702x_rc_keys,
+- .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
+- .rc_interval = 400,
+- .rc_query = vp702x_rc_query,
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
+
+- .size_of_priv = sizeof(struct vp702x_state),
++ .streaming_ctrl = vp702x_streaming_ctrl,
++ .frontend_attach = vp702x_frontend_attach,
+
+ /* parameter for the MPEG2-data transfer */
+- .urb = {
+- .type = DVB_USB_BULK,
+- .count = 7,
++ .stream = {
++ .type = USB_BULK,
++ .count = 10,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+@@ -241,24 +288,33 @@ static struct dvb_usb_properties vp702x_
+ }
+ }
+ },
++ .size_of_priv = sizeof(struct vp702x_state),
++ }
++ },
++ .read_mac_address = vp702x_read_mac_addr,
++
++ .rc_key_map = vp702x_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
++ .rc_interval = 400,
++ .rc_query = vp702x_rc_query,
+
+- .num_device_descs = 2,
++ .num_device_descs = 1,
+ .devices = {
+ { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
+ .cold_ids = { &vp702x_usb_table[0], NULL },
+- .warm_ids = { &vp702x_usb_table[1], NULL },
++ .warm_ids = { NULL },
+ },
+- { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
++/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
+ .cold_ids = { &vp702x_usb_table[2], NULL },
+ .warm_ids = { &vp702x_usb_table[3], NULL },
+ },
+- { 0 },
++*/ { NULL },
+ }
+ };
+
+ /* usb specific object needed to register this driver with the usb subsystem */
+ static struct usb_driver vp702x_usb_driver = {
+- .name = "dvb-usb-vp702x",
++ .name = "dvb_usb_vp702x",
+ .probe = vp702x_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = vp702x_usb_table,
+@@ -287,5 +343,5 @@ module_exit(vp702x_usb_module_exit);
+
+ MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher at desy.de>");
+ MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
+-MODULE_VERSION("1.0-alpha");
++MODULE_VERSION("1.0");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
+index c2f97f9..25a9dee 100644
+--- a/drivers/media/dvb/dvb-usb/vp702x.h
++++ b/drivers/media/dvb/dvb-usb/vp702x.h
+@@ -102,5 +102,7 @@ extern struct dvb_frontend * vp702x_fe_a
+
+ extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
+ extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
++extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
++extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
+
+ #endif
+diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
+index 8ea3834..b4cf002 100644
+--- a/drivers/media/dvb/dvb-usb/vp7045.c
++++ b/drivers/media/dvb/dvb-usb/vp7045.c
+@@ -169,31 +169,31 @@ static int vp7045_read_mac_addr(struct d
+ return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
+ }
+
+-static int vp7045_frontend_attach(struct dvb_usb_device *d)
++static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+ u8 buf[255] = { 0 };
+
+- vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0);
++ vp7045_usb_op(adap->dev,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);
++ vp7045_usb_op(adap->dev,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);
++ vp7045_usb_op(adap->dev,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);
++ adap->fe = vp7045_fe_attach(adap->dev);
+
+ return 0;
+ }
+
+-static struct dvb_usb_properties vp7045_properties;
++static struct dvb_usb_device_properties vp7045_properties;
+
+ static int vp7045_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -210,24 +210,17 @@ static struct usb_device_id vp7045_usb_t
+ };
+ MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
+
+-static struct dvb_usb_properties vp7045_properties = {
+- .caps = 0,
+-
++static struct dvb_usb_device_properties vp7045_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-vp7045-01.fw",
+
+- .power_ctrl = vp7045_power_ctrl,
++ .num_adapters = 1,
++ .adapter = {
++ {
+ .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,
++ .stream = {
++ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+@@ -236,6 +229,15 @@ static struct dvb_usb_properties vp7045_
+ }
+ }
+ },
++ }
++ },
++ .power_ctrl = vp7045_power_ctrl,
++ .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,
+
+ .num_device_descs = 2,
+ .devices = {
+diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
+index db97855..aebb8d6 100644
+--- a/drivers/media/dvb/frontends/Kconfig
++++ b/drivers/media/dvb/frontends/Kconfig
+@@ -1,48 +1,73 @@
+ menu "Customise DVB Frontends"
+ depends on DVB_CORE
+
++config DVB_FE_CUSTOMISE
++ bool "Customise the frontend modules to build"
++ default N
++ help
++ This allows the user to deselect frontend drivers unnecessary
++ for their hardware from the build. Use this option with care
++ as deselecting frontends which are in fact necessary will result
++ in DVB devices which cannot be tuned due to lack of driver support.
++
++ If unsure say N.
++
+ comment "DVB-S (satellite) frontends"
+ depends on DVB_CORE
+
+ config DVB_STV0299
+ tristate "ST STV0299 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+ config DVB_CX24110
+ tristate "Conexant CX24110 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+ config DVB_CX24123
+ tristate "Conexant CX24123 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+ config DVB_TDA8083
+ tristate "Philips TDA8083 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+ config DVB_MT312
+ tristate "Zarlink VP310/MT312 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+ config DVB_VES1X93
+ tristate "VLSI VES1893 or VES1993 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ 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 && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-S tuner module. Say Y when you want to support this frontend.
++
++config DVB_TDA10086
++ tristate "Philips TDA10086 based"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+@@ -52,6 +77,7 @@ comment "DVB-T (terrestrial) frontends"
+ config DVB_SP8870
+ tristate "Spase sp8870 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+@@ -64,6 +90,7 @@ config DVB_SP8870
+ config DVB_SP887X
+ tristate "Spase sp887x based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+@@ -76,24 +103,28 @@ config DVB_SP887X
+ config DVB_CX22700
+ tristate "Conexant CX22700 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ config DVB_CX22702
+ tristate "Conexant cx22702 demodulator (OFDM)"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ config DVB_L64781
+ tristate "LSI L64781"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ config DVB_TDA1004X
+ tristate "Philips TDA10045H/TDA10046H based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+@@ -107,24 +138,28 @@ config DVB_TDA1004X
+ config DVB_NXT6000
+ tristate "NxtWave Communications NXT6000 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ config DVB_MT352
+ tristate "Zarlink MT352 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ config DVB_ZL10353
+ tristate "Zarlink ZL10353 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ config DVB_DIB3000MB
+ tristate "DiBcom 3000M-B"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+@@ -132,6 +167,7 @@ config DVB_DIB3000MB
+ config DVB_DIB3000MC
+ tristate "DiBcom 3000P/M-C"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+@@ -142,18 +178,21 @@ comment "DVB-C (cable) frontends"
+ config DVB_VES1820
+ tristate "VLSI VES1820 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+ config DVB_TDA10021
+ tristate "Philips TDA10021 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+ config DVB_STV0297
+ tristate "ST STV0297 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+@@ -163,6 +202,7 @@ comment "ATSC (North American/Korean Ter
+ config DVB_NXT200X
+ tristate "NxtWave Communications NXT2002/NXT2004 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+@@ -177,6 +217,7 @@ config DVB_NXT200X
+ config DVB_OR51211
+ tristate "Oren OR51211 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+@@ -189,6 +230,7 @@ config DVB_OR51211
+ config DVB_OR51132
+ tristate "Oren OR51132 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+@@ -204,6 +246,7 @@ config DVB_OR51132
+ config DVB_BCM3510
+ tristate "Broadcom BCM3510"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
+@@ -212,28 +255,54 @@ config DVB_BCM3510
+ config DVB_LGDT330X
+ tristate "LG Electronics LGDT3302/LGDT3303 based"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+-
+-comment "Miscellaneous devices"
++comment "Tuners/PLL support"
+ depends on DVB_CORE
+
+ config DVB_PLL
+ tristate
+ depends on DVB_CORE && I2C
+
++config DVB_TDA826X
++ tristate "Philips TDA826X silicon tuner"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
++
++config DVB_TUNER_MT2060
++ tristate "Microtune MT2060 silicon IF tuner"
++ depends on I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A driver for the silicon IF tuner MT2060 from Microtune.
++
++comment "Miscellaneous devices"
++ depends on DVB_CORE
++
+ config DVB_LNBP21
+ tristate "LNBP21 SEC controller"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ An SEC control chip.
+
+ config DVB_ISL6421
+ tristate "ISL6421 SEC controller"
+ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
+ help
+ An SEC control chip.
+
++config DVB_TUA6100
++ tristate "TUA6100 PLL"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVBS PLL chip.
++
+ endmenu
+diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
+index 0e4880b..dce9cf0 100644
+--- a/drivers/media/dvb/frontends/Makefile
++++ b/drivers/media/dvb/frontends/Makefile
+@@ -11,8 +11,8 @@ obj-$(CONFIG_DVB_CX22700) += cx22700.o
+ obj-$(CONFIG_DVB_CX24110) += cx24110.o
+ obj-$(CONFIG_DVB_TDA8083) += tda8083.o
+ obj-$(CONFIG_DVB_L64781) += l64781.o
+-obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o
+-obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o
++obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
++obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
+ obj-$(CONFIG_DVB_MT312) += mt312.o
+ obj-$(CONFIG_DVB_VES1820) += ves1820.o
+ obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
+@@ -33,3 +33,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+ obj-$(CONFIG_DVB_CX24123) += cx24123.o
+ obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
++obj-$(CONFIG_DVB_TDA10086) += tda10086.o
++obj-$(CONFIG_DVB_TDA826X) += tda826x.o
++obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
++obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
+index 80f5d09..7e4f95e 100644
+--- a/drivers/media/dvb/frontends/bcm3510.h
++++ b/drivers/media/dvb/frontends/bcm3510.h
+@@ -34,7 +34,16 @@ struct bcm3510_config
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+ };
+
++#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_BCM3510
+
+ #endif
+diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
+index dcd8979..7ac3369 100644
+--- a/drivers/media/dvb/frontends/cx22700.h
++++ b/drivers/media/dvb/frontends/cx22700.h
+@@ -31,7 +31,16 @@ struct cx22700_config
+ u8 demod_address;
+ };
+
++#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_CX22700
+
+ #endif // CX22700_H
+diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
+index 4106d46..335219e 100644
+--- a/drivers/media/dvb/frontends/cx22702.c
++++ b/drivers/media/dvb/frontends/cx22702.c
+@@ -399,7 +399,9 @@ static int cx22702_read_signal_strength(
+ {
+ struct cx22702_state* state = fe->demodulator_priv;
+
+- *signal_strength = cx22702_readreg (state, 0x23);
++ u16 rs_ber = 0;
++ rs_ber = cx22702_readreg (state, 0x23);
++ *signal_strength = (rs_ber << 8) | rs_ber;
+
+ return 0;
+ }
+diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
+index 7f2f241..9cd64da 100644
+--- a/drivers/media/dvb/frontends/cx22702.h
++++ b/drivers/media/dvb/frontends/cx22702.h
+@@ -41,7 +41,16 @@ struct cx22702_config
+ u8 output_mode;
+ };
+
++#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_CX22702
+
+ #endif // CX22702_H
+diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
+index ce3c739..ae96395 100644
+--- a/drivers/media/dvb/frontends/cx24110.c
++++ b/drivers/media/dvb/frontends/cx24110.c
+@@ -1,4 +1,4 @@
+-/*
++ /*
+ cx24110 - Single Chip Satellite Channel Receiver driver module
+
+ Copyright (C) 2002 Peter Hettkamp <peter.hettkamp at htp-tel.de> based on
+@@ -311,16 +311,17 @@ static int cx24110_set_symbolrate (struc
+
+ }
+
+-int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
++static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
+ {
+ struct cx24110_state *state = fe->demodulator_priv;
+
++ if (len != 3)
++ return -EINVAL;
++
+ /* tuner data is 21 bits long, must be left-aligned in data */
+ /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
+ /* FIXME (low): add error handling, avoid infinite loops if HW fails... */
+
+- dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
+-
+ cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
+ cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
+
+@@ -329,19 +330,19 @@ int cx24110_pll_write (struct dvb_fronte
+ cx24110_writereg(state,0x72,0);
+
+ /* write the topmost 8 bits */
+- cx24110_writereg(state,0x72,(data>>24)&0xff);
++ cx24110_writereg(state,0x72,buf[0]);
+
+ /* wait for the send to be completed */
+ while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+ ;
+
+ /* send another 8 bytes */
+- cx24110_writereg(state,0x72,(data>>16)&0xff);
++ cx24110_writereg(state,0x72,buf[1]);
+ while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+ ;
+
+ /* and the topmost 5 bits of this byte */
+- cx24110_writereg(state,0x72,(data>>8)&0xff);
++ cx24110_writereg(state,0x72,buf[2]);
+ while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+ ;
+
+@@ -642,6 +643,7 @@ static struct dvb_frontend_ops cx24110_o
+ .release = cx24110_release,
+
+ .init = cx24110_initfe,
++ .write = _cx24110_pll_write,
+ .set_frontend = cx24110_set_frontend,
+ .get_frontend = cx24110_get_frontend,
+ .read_status = cx24110_read_status,
+@@ -664,4 +666,3 @@ MODULE_AUTHOR("Peter Hettkamp");
+ MODULE_LICENSE("GPL");
+
+ EXPORT_SYMBOL(cx24110_attach);
+-EXPORT_SYMBOL(cx24110_pll_write);
+diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
+index b354a64..0ca3af4 100644
+--- a/drivers/media/dvb/frontends/cx24110.h
++++ b/drivers/media/dvb/frontends/cx24110.h
+@@ -33,9 +33,24 @@ struct cx24110_config
+ u8 demod_address;
+ };
+
++static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) {
++ int r = 0;
++ u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)};
++ if (fe->ops.write)
++ r = fe->ops.write(fe, buf, 3);
++ return r;
++}
++
++#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+ struct i2c_adapter* i2c);
+-
+-extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data);
++#else
++static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_CX24110
+
+ #endif // CX24110_H
+diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
+index 274a87b..a356d28 100644
+--- a/drivers/media/dvb/frontends/cx24123.c
++++ b/drivers/media/dvb/frontends/cx24123.c
+@@ -45,9 +45,6 @@ struct cx24123_state
+
+ struct dvb_frontend frontend;
+
+- u32 lastber;
+- u16 snr;
+-
+ /* Some PLL specifics for tuning */
+ u32 VCAarg;
+ u32 VGAarg;
+@@ -194,7 +191,7 @@ static struct {
+ {0x06, 0x31}, /* MPEG (default) */
+ {0x0b, 0x00}, /* Freq search start point (default) */
+ {0x0c, 0x00}, /* Demodulator sample gain (default) */
+- {0x0d, 0x02}, /* Frequency search range = Fsymbol / 4 (default) */
++ {0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */
+ {0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */
+ {0x0f, 0xfe}, /* FEC search mask (all supported codes) */
+ {0x10, 0x01}, /* Default search inversion, no repeat (default) */
+@@ -223,8 +220,9 @@ static struct {
+ {0x44, 0x00}, /* Constellation (default) */
+ {0x45, 0x00}, /* Symbol count (default) */
+ {0x46, 0x0d}, /* Symbol rate estimator on (default) */
+- {0x56, 0x41}, /* Various (default) */
++ {0x56, 0xc1}, /* Error Counter = Viterbi BER */
+ {0x57, 0xff}, /* Error Counter Window (default) */
++ {0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */
+ {0x67, 0x83}, /* Non-DCII symbol clock */
+ };
+
+@@ -321,6 +319,12 @@ static int cx24123_set_fec(struct cx2412
+ if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+ fec = FEC_AUTO;
+
++ /* Set the soft decision threshold */
++ if(fec == FEC_1_2)
++ cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) | 0x01);
++ else
++ cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) & ~0x01);
++
+ switch (fec) {
+ case FEC_1_2:
+ dprintk("%s: set FEC to 1/2\n",__FUNCTION__);
+@@ -549,8 +553,8 @@ static int cx24123_pll_calculate(struct
+ ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
+ adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
+
+- if (adiv == 0)
+- ndiv++;
++ if (adiv == 0 && ndiv > 0)
++ ndiv--;
+
+ /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
+ state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
+@@ -657,6 +661,10 @@ static int cx24123_initfe(struct dvb_fro
+ for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+ cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+
++ /* Set the LNB polarity */
++ if(state->config->lnb_polarity)
++ cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
++
+ return 0;
+ }
+
+@@ -674,6 +682,9 @@ static int cx24123_set_voltage(struct dv
+ case SEC_VOLTAGE_18:
+ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x80);
++ case SEC_VOLTAGE_OFF:
++ /* already handled in cx88-dvb */
++ return 0;
+ default:
+ return -EINVAL;
+ };
+@@ -776,13 +787,15 @@ static int cx24123_read_status(struct dv
+ if (lock & 0x01)
+ *status |= FE_HAS_SIGNAL;
+ if (sync & 0x02)
+- *status |= FE_HAS_CARRIER;
++ *status |= FE_HAS_CARRIER; /* Phase locked */
+ if (sync & 0x04)
+ *status |= FE_HAS_VITERBI;
++
++ /* Reed-Solomon Status */
+ if (sync & 0x08)
+ *status |= FE_HAS_SYNC;
+ if (sync & 0x80)
+- *status |= FE_HAS_LOCK;
++ *status |= FE_HAS_LOCK; /*Full Sync */
+
+ return 0;
+ }
+@@ -795,29 +808,13 @@ static int cx24123_read_ber(struct dvb_f
+ {
+ struct cx24123_state *state = fe->demodulator_priv;
+
+- state->lastber =
+- ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
++ /* The true bit error rate is this value divided by
++ the window size (set as 256 * 255) */
++ *ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+ (cx24123_readreg(state, 0x1d) << 8 |
+- cx24123_readreg(state, 0x1e));
+-
+- /* Do the signal quality processing here, it's derived from the BER. */
+- /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
+- if (state->lastber < 5000)
+- state->snr = 655*100;
+- else if ( (state->lastber >= 5000) && (state->lastber < 55000) )
+- state->snr = 655*90;
+- else if ( (state->lastber >= 55000) && (state->lastber < 150000) )
+- state->snr = 655*80;
+- else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
+- state->snr = 655*70;
+- else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
+- state->snr = 655*65;
+- else
+- state->snr = 0;
+-
+- dprintk("%s: BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr);
++ cx24123_readreg(state, 0x1e));
+
+- *ber = state->lastber;
++ dprintk("%s: BER = %d\n",__FUNCTION__,*ber);
+
+ return 0;
+ }
+@@ -825,6 +822,7 @@ static int cx24123_read_ber(struct dvb_f
+ static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+ {
+ struct cx24123_state *state = fe->demodulator_priv;
++
+ *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+
+ dprintk("%s: Signal strength = %d\n",__FUNCTION__,*signal_strength);
+@@ -835,19 +833,13 @@ static int cx24123_read_signal_strength(
+ static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+ {
+ struct cx24123_state *state = fe->demodulator_priv;
+- *snr = state->snr;
+-
+- dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr);
+
+- return 0;
+-}
++ /* Inverted raw Es/N0 count, totally bogus but better than the
++ BER threshold. */
++ *snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
++ (u16)cx24123_readreg(state, 0x19));
+
+-static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+-{
+- struct cx24123_state *state = fe->demodulator_priv;
+- *ucblocks = state->lastber;
+-
+- dprintk("%s: ucblocks (ber) = %d\n",__FUNCTION__,*ucblocks);
++ dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr);
+
+ return 0;
+ }
+@@ -922,6 +914,29 @@ static int cx24123_set_tone(struct dvb_f
+ return 0;
+ }
+
++static int cx24123_tune(struct dvb_frontend* fe,
++ struct dvb_frontend_parameters* params,
++ unsigned int mode_flags,
++ int *delay,
++ fe_status_t *status)
++{
++ int retval = 0;
++
++ if (params != NULL)
++ retval = cx24123_set_frontend(fe, params);
++
++ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
++ cx24123_read_status(fe, status);
++ *delay = HZ/10;
++
++ return retval;
++}
++
++static int cx24123_get_algo(struct dvb_frontend *fe)
++{
++ return 1; //FE_ALGO_HW
++}
++
+ static void cx24123_release(struct dvb_frontend* fe)
+ {
+ struct cx24123_state* state = fe->demodulator_priv;
+@@ -949,8 +964,6 @@ struct dvb_frontend* cx24123_attach(cons
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+- state->lastber = 0;
+- state->snr = 0;
+ state->VCAarg = 0;
+ state->VGAarg = 0;
+ state->bandselectarg = 0;
+@@ -1003,11 +1016,12 @@ static struct dvb_frontend_ops cx24123_o
+ .read_ber = cx24123_read_ber,
+ .read_signal_strength = cx24123_read_signal_strength,
+ .read_snr = cx24123_read_snr,
+- .read_ucblocks = cx24123_read_ucblocks,
+ .diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+ .diseqc_send_burst = cx24123_diseqc_send_burst,
+ .set_tone = cx24123_set_tone,
+ .set_voltage = cx24123_set_voltage,
++ .tune = cx24123_tune,
++ .get_frontend_algo = cx24123_get_algo,
+ };
+
+ module_param(debug, int, 0644);
+diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
+index 9606f82..84f9e4f 100644
+--- a/drivers/media/dvb/frontends/cx24123.h
++++ b/drivers/media/dvb/frontends/cx24123.h
+@@ -30,9 +30,21 @@ struct cx24123_config
+
+ /* Need to set device param for start_dma */
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
++
++ /* 0 = LNB voltage normal, 1 = LNB voltage inverted */
++ int lnb_polarity;
+ };
+
++#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_CX24123
+
+ #endif /* CX24123_H */
+diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
+deleted file mode 100644
+index 1a4f1f7..0000000
+--- a/drivers/media/dvb/frontends/dib3000-common.c
++++ /dev/null
+@@ -1,83 +0,0 @@
+-#include "dib3000-common.h"
+-
+-#ifdef CONFIG_DVB_DIBCOM_DEBUG
+-static int debug;
+-module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
+-#endif
+-#define deb_info(args...) dprintk(0x01,args)
+-#define deb_i2c(args...) dprintk(0x02,args)
+-#define deb_srch(args...) dprintk(0x04,args)
+-
+-
+-int dib3000_read_reg(struct dib3000_state *state, u16 reg)
+-{
+- u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+- u8 rb[2];
+- struct i2c_msg msg[] = {
+- { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 },
+- { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+- };
+-
+- if (i2c_transfer(state->i2c, msg, 2) != 2)
+- deb_i2c("i2c read error\n");
+-
+- deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
+- (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
+-
+- return (rb[0] << 8) | rb[1];
+-}
+-
+-int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
+-{
+- u8 b[] = {
+- (reg >> 8) & 0xff, reg & 0xff,
+- (val >> 8) & 0xff, val & 0xff,
+- };
+- struct i2c_msg msg[] = {
+- { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
+- };
+- deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
+-
+- return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
+-}
+-
+-int dib3000_search_status(u16 irq,u16 lock)
+-{
+- if (irq & 0x02) {
+- if (lock & 0x01) {
+- deb_srch("auto search succeeded\n");
+- return 1; // auto search succeeded
+- } else {
+- deb_srch("auto search not successful\n");
+- return 0; // auto search failed
+- }
+- } else if (irq & 0x01) {
+- deb_srch("auto search failed\n");
+- return 0; // auto search failed
+- }
+- return -1; // try again
+-}
+-
+-/* for auto search */
+-u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
+- { /* fft */
+- { /* gua */
+- { 0, 1 }, /* 0 0 { 0,1 } */
+- { 3, 9 }, /* 0 1 { 0,1 } */
+- },
+- {
+- { 2, 5 }, /* 1 0 { 0,1 } */
+- { 6, 11 }, /* 1 1 { 0,1 } */
+- }
+- };
+-
+-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher at desy.de");
+-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
+-MODULE_LICENSE("GPL");
+-
+-EXPORT_SYMBOL(dib3000_seq);
+-
+-EXPORT_SYMBOL(dib3000_read_reg);
+-EXPORT_SYMBOL(dib3000_write_reg);
+-EXPORT_SYMBOL(dib3000_search_status);
+diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
+deleted file mode 100644
+index be1c0d3..0000000
+--- a/drivers/media/dvb/frontends/dib3000-common.h
++++ /dev/null
+@@ -1,135 +0,0 @@
+-/*
+- * .h-files for the common use of the frontend drivers made by DiBcom
+- * DiBcom 3000M-B/C, 3000P
+- *
+- * DiBcom (http://www.dibcom.fr/)
+- *
+- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
+- *
+- * based on GPL code from DibCom, which has
+- *
+- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol at 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.
+- *
+- * Acknowledgements
+- *
+- * Amaury Demol (ademol at dibcom.fr) from DiBcom for providing specs and driver
+- * sources, on which this driver (and the dvb-dibusb) are based.
+- *
+- * see Documentation/dvb/README.dibusb for more information
+- *
+- */
+-
+-#ifndef DIB3000_COMMON_H
+-#define DIB3000_COMMON_H
+-
+-#include "dvb_frontend.h"
+-#include "dib3000.h"
+-
+-/* info and err, taken from usb.h, if there is anything available like by default. */
+-#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg)
+-#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg)
+-#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
+-
+-/* frontend state */
+-struct dib3000_state {
+- struct i2c_adapter* i2c;
+-
+-/* configuration settings */
+- struct dib3000_config config;
+-
+- struct dvb_frontend frontend;
+- int timing_offset;
+- int timing_offset_comp_done;
+-
+- fe_bandwidth_t last_tuned_bw;
+- u32 last_tuned_freq;
+-};
+-
+-/* commonly used methods by the dib3000mb/mc/p frontend */
+-extern int dib3000_read_reg(struct dib3000_state *state, u16 reg);
+-extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val);
+-
+-extern int dib3000_search_status(u16 irq,u16 lock);
+-
+-/* handy shortcuts */
+-#define rd(reg) dib3000_read_reg(state,reg)
+-
+-#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
+- { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+-
+-#define wr_foreach(a,v) { int i; \
+- if (sizeof(a) != sizeof(v)) \
+- err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
+- for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+- wr(a[i],v[i]); \
+- }
+-
+-#define set_or(reg,val) wr(reg,rd(reg) | val)
+-
+-#define set_and(reg,val) wr(reg,rd(reg) & val)
+-
+-
+-/* debug */
+-
+-#ifdef CONFIG_DVB_DIBCOM_DEBUG
+-#define dprintk(level,args...) \
+- do { if ((debug & level)) { printk(args); } } while (0)
+-#else
+-#define dprintk(args...) do { } while (0)
+-#endif
+-
+-/* mask for enabling a specific pid for the pid_filter */
+-#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
+-
+-/* common values for tuning */
+-#define DIB3000_ALPHA_0 ( 0)
+-#define DIB3000_ALPHA_1 ( 1)
+-#define DIB3000_ALPHA_2 ( 2)
+-#define DIB3000_ALPHA_4 ( 4)
+-
+-#define DIB3000_CONSTELLATION_QPSK ( 0)
+-#define DIB3000_CONSTELLATION_16QAM ( 1)
+-#define DIB3000_CONSTELLATION_64QAM ( 2)
+-
+-#define DIB3000_GUARD_TIME_1_32 ( 0)
+-#define DIB3000_GUARD_TIME_1_16 ( 1)
+-#define DIB3000_GUARD_TIME_1_8 ( 2)
+-#define DIB3000_GUARD_TIME_1_4 ( 3)
+-
+-#define DIB3000_TRANSMISSION_MODE_2K ( 0)
+-#define DIB3000_TRANSMISSION_MODE_8K ( 1)
+-
+-#define DIB3000_SELECT_LP ( 0)
+-#define DIB3000_SELECT_HP ( 1)
+-
+-#define DIB3000_FEC_1_2 ( 1)
+-#define DIB3000_FEC_2_3 ( 2)
+-#define DIB3000_FEC_3_4 ( 3)
+-#define DIB3000_FEC_5_6 ( 5)
+-#define DIB3000_FEC_7_8 ( 7)
+-
+-#define DIB3000_HRCH_OFF ( 0)
+-#define DIB3000_HRCH_ON ( 1)
+-
+-#define DIB3000_DDS_INVERSION_OFF ( 0)
+-#define DIB3000_DDS_INVERSION_ON ( 1)
+-
+-#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8))
+-#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7)))
+-
+-/* for auto search */
+-extern u16 dib3000_seq[2][2][2];
+-
+-#define DIB3000_REG_MANUFACTOR_ID ( 1025)
+-#define DIB3000_I2C_ID_DIBCOM (0x01b3)
+-
+-#define DIB3000_REG_DEVICE_ID ( 1026)
+-#define DIB3000MB_DEVICE_ID (0x3000)
+-#define DIB3000MC_DEVICE_ID (0x3001)
+-#define DIB3000P_DEVICE_ID (0x3002)
+-
+-#endif // DIB3000_COMMON_H
+diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
+index ec92762..a6d3854 100644
+--- a/drivers/media/dvb/frontends/dib3000.h
++++ b/drivers/media/dvb/frontends/dib3000.h
+@@ -41,9 +41,16 @@ struct dib_fe_xfer_ops
+ int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
+ };
+
++#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+ struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
++#else
++static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
++ struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_DIB3000MB
+
+-extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
+- struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
+ #endif // DIB3000_H
+diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
+index 5302e11..adbabfd 100644
+--- a/drivers/media/dvb/frontends/dib3000mb.c
++++ b/drivers/media/dvb/frontends/dib3000mb.c
+@@ -29,9 +29,10 @@
+ #include <linux/string.h>
+ #include <linux/slab.h>
+
+-#include "dib3000-common.h"
+-#include "dib3000mb_priv.h"
++#include "dvb_frontend.h"
++
+ #include "dib3000.h"
++#include "dib3000mb_priv.h"
+
+ /* Version information */
+ #define DRIVER_VERSION "0.1"
+@@ -44,10 +45,81 @@ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
+ #endif
+ #define deb_info(args...) dprintk(0x01,args)
++#define deb_i2c(args...) dprintk(0x02,args)
++#define deb_srch(args...) dprintk(0x04,args)
++#define deb_info(args...) dprintk(0x01,args)
+ #define deb_xfer(args...) dprintk(0x02,args)
+ #define deb_setf(args...) dprintk(0x04,args)
+ #define deb_getf(args...) dprintk(0x08,args)
+
++#ifdef CONFIG_DVB_DIBCOM_DEBUG
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
++#endif
++
++static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
++{
++ u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
++ u8 rb[2];
++ struct i2c_msg msg[] = {
++ { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 },
++ { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
++ };
++
++ if (i2c_transfer(state->i2c, msg, 2) != 2)
++ deb_i2c("i2c read error\n");
++
++ deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
++ (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
++
++ return (rb[0] << 8) | rb[1];
++}
++
++static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
++{
++ u8 b[] = {
++ (reg >> 8) & 0xff, reg & 0xff,
++ (val >> 8) & 0xff, val & 0xff,
++ };
++ struct i2c_msg msg[] = {
++ { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
++ };
++ deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
++
++ return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
++}
++
++static int dib3000_search_status(u16 irq,u16 lock)
++{
++ if (irq & 0x02) {
++ if (lock & 0x01) {
++ deb_srch("auto search succeeded\n");
++ return 1; // auto search succeeded
++ } else {
++ deb_srch("auto search not successful\n");
++ return 0; // auto search failed
++ }
++ } else if (irq & 0x01) {
++ deb_srch("auto search failed\n");
++ return 0; // auto search failed
++ }
++ return -1; // try again
++}
++
++/* for auto search */
++static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
++ { /* fft */
++ { /* gua */
++ { 0, 1 }, /* 0 0 { 0,1 } */
++ { 3, 9 }, /* 0 1 { 0,1 } */
++ },
++ {
++ { 2, 5 }, /* 1 0 { 0,1 } */
++ { 6, 11 }, /* 1 1 { 0,1 } */
++ }
++ };
++
+ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep);
+
+diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
+index 999b190..1a12747 100644
+--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
++++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
+@@ -13,6 +13,99 @@
+ #ifndef __DIB3000MB_PRIV_H_INCLUDED__
+ #define __DIB3000MB_PRIV_H_INCLUDED__
+
++/* info and err, taken from usb.h, if there is anything available like by default. */
++#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg)
++#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
++
++/* handy shortcuts */
++#define rd(reg) dib3000_read_reg(state,reg)
++
++#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
++ { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
++
++#define wr_foreach(a,v) { int i; \
++ if (sizeof(a) != sizeof(v)) \
++ err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
++ for (i=0; i < sizeof(a)/sizeof(u16); i++) \
++ wr(a[i],v[i]); \
++ }
++
++#define set_or(reg,val) wr(reg,rd(reg) | val)
++
++#define set_and(reg,val) wr(reg,rd(reg) & val)
++
++/* debug */
++
++#ifdef CONFIG_DVB_DIBCOM_DEBUG
++#define dprintk(level,args...) \
++ do { if ((debug & level)) { printk(args); } } while (0)
++#else
++#define dprintk(args...) do { } while (0)
++#endif
++
++/* mask for enabling a specific pid for the pid_filter */
++#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
++
++/* common values for tuning */
++#define DIB3000_ALPHA_0 ( 0)
++#define DIB3000_ALPHA_1 ( 1)
++#define DIB3000_ALPHA_2 ( 2)
++#define DIB3000_ALPHA_4 ( 4)
++
++#define DIB3000_CONSTELLATION_QPSK ( 0)
++#define DIB3000_CONSTELLATION_16QAM ( 1)
++#define DIB3000_CONSTELLATION_64QAM ( 2)
++
++#define DIB3000_GUARD_TIME_1_32 ( 0)
++#define DIB3000_GUARD_TIME_1_16 ( 1)
++#define DIB3000_GUARD_TIME_1_8 ( 2)
++#define DIB3000_GUARD_TIME_1_4 ( 3)
++
++#define DIB3000_TRANSMISSION_MODE_2K ( 0)
++#define DIB3000_TRANSMISSION_MODE_8K ( 1)
++
++#define DIB3000_SELECT_LP ( 0)
++#define DIB3000_SELECT_HP ( 1)
++
++#define DIB3000_FEC_1_2 ( 1)
++#define DIB3000_FEC_2_3 ( 2)
++#define DIB3000_FEC_3_4 ( 3)
++#define DIB3000_FEC_5_6 ( 5)
++#define DIB3000_FEC_7_8 ( 7)
++
++#define DIB3000_HRCH_OFF ( 0)
++#define DIB3000_HRCH_ON ( 1)
++
++#define DIB3000_DDS_INVERSION_OFF ( 0)
++#define DIB3000_DDS_INVERSION_ON ( 1)
++
++#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8))
++#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7)))
++
++#define DIB3000_REG_MANUFACTOR_ID ( 1025)
++#define DIB3000_I2C_ID_DIBCOM (0x01b3)
++
++#define DIB3000_REG_DEVICE_ID ( 1026)
++#define DIB3000MB_DEVICE_ID (0x3000)
++#define DIB3000MC_DEVICE_ID (0x3001)
++#define DIB3000P_DEVICE_ID (0x3002)
++
++/* frontend state */
++struct dib3000_state {
++ struct i2c_adapter* i2c;
++
++/* configuration settings */
++ struct dib3000_config config;
++
++ struct dvb_frontend frontend;
++ int timing_offset;
++ int timing_offset_comp_done;
++
++ fe_bandwidth_t last_tuned_bw;
++ u32 last_tuned_freq;
++};
++
+ /* register addresses and some of their default values */
+
+ /* restart subsystems */
+diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
+index 9867347..3561a77 100644
+--- a/drivers/media/dvb/frontends/dib3000mc.c
++++ b/drivers/media/dvb/frontends/dib3000mc.c
+@@ -1,725 +1,727 @@
+ /*
+- * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C
+- * DiBcom (http://www.dibcom.fr/)
++ * Driver for DiBcom DiB3000MC/P-demodulator.
+ *
++ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher at desy.de)
+ *
+- * based on GPL code from DiBCom, which has
++ * This code is partially based on the previous dib3000mc.c .
+ *
+- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol at dibcom.fr)
+- *
+- * This program is free software; you can redistribute it and/or
++ * 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 at dibcom.fr) from DiBcom for providing specs and driver
+- * sources, on which this driver (and the dvb-dibusb) are based.
+- *
+- * see Documentation/dvb/README.dibusb for more information
+- *
+ */
++
+ #include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/init.h>
+-#include <linux/delay.h>
+-#include <linux/string.h>
+-#include <linux/slab.h>
+-
+-#include "dib3000-common.h"
+-#include "dib3000mc_priv.h"
+-#include "dib3000.h"
+-
+-/* Version information */
+-#define DRIVER_VERSION "0.1"
+-#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator"
+-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher at desy.de"
+-
+-#ifdef CONFIG_DVB_DIBCOM_DEBUG
++#include <linux/i2c.h>
++//#include <linux/init.h>
++//#include <linux/delay.h>
++//#include <linux/string.h>
++//#include <linux/slab.h>
++
++#include "dvb_frontend.h"
++
++#include "dib3000mc.h"
++
+ static int debug;
+ module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able)).");
+-#endif
+-#define deb_info(args...) dprintk(0x01,args)
+-#define deb_xfer(args...) dprintk(0x02,args)
+-#define deb_setf(args...) dprintk(0x04,args)
+-#define deb_getf(args...) dprintk(0x08,args)
+-#define deb_stat(args...) dprintk(0x10,args)
+-
+-static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
+- fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
++MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
++
++#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
++
++struct dib3000mc_state {
++ struct dvb_frontend demod;
++ struct dib3000mc_config *cfg;
++
++ u8 i2c_addr;
++ struct i2c_adapter *i2c_adap;
++
++ struct dibx000_i2c_master i2c_master;
++
++ u32 timf;
++
++ fe_bandwidth_t current_bandwidth;
++
++ u16 dev_id;
++};
++
++static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
+ {
+- switch (transmission_mode) {
+- case TRANSMISSION_MODE_2K:
+- wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]);
+- break;
+- case TRANSMISSION_MODE_8K:
+- wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]);
+- break;
+- default:
+- break;
+- }
++ u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
++ u8 rb[2];
++ struct i2c_msg msg[2] = {
++ { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
++ { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
++ };
+
+- switch (bandwidth) {
+-/* case BANDWIDTH_5_MHZ:
+- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]);
+- break; */
+- case BANDWIDTH_6_MHZ:
+- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]);
+- break;
+- case BANDWIDTH_7_MHZ:
+- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]);
+- break;
+- case BANDWIDTH_8_MHZ:
+- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]);
+- break;
+- default:
+- break;
+- }
++ if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
++ dprintk("i2c read error on %d\n",reg);
+
+- switch (mode) {
+- case 0: /* no impulse */ /* fall through */
+- wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]);
+- break;
+- case 1: /* new algo */
+- wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]);
+- set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */
+- break;
+- default: /* old algo */
+- wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]);
+- break;
+- }
+- return 0;
++ return (rb[0] << 8) | rb[1];
+ }
+
+-static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset,
+- fe_transmit_mode_t fft, fe_bandwidth_t bw)
++static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
+ {
+- u16 timf_msb,timf_lsb;
+- s32 tim_offset,tim_sgn;
+- u64 comp1,comp2,comp=0;
++ u8 b[4] = {
++ (reg >> 8) & 0xff, reg & 0xff,
++ (val >> 8) & 0xff, val & 0xff,
++ };
++ struct i2c_msg msg = {
++ .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
++ };
++ return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
++}
+
+- switch (bw) {
+- case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break;
+- case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break;
+- case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break;
+- default: err("unknown bandwidth (%d)",bw); break;
++
++static int dib3000mc_identify(struct dib3000mc_state *state)
++{
++ u16 value;
++ if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
++ dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
++ return -EREMOTEIO;
+ }
+- timf_msb = (comp >> 16) & 0xff;
+- timf_lsb = (comp & 0xffff);
+-
+- // Update the timing offset ;
+- if (upd_offset > 0) {
+- if (!state->timing_offset_comp_done) {
+- msleep(200);
+- state->timing_offset_comp_done = 1;
+- }
+- tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB);
+- if ((tim_offset & 0x2000) == 0x2000)
+- tim_offset |= 0xC000;
+- if (fft == TRANSMISSION_MODE_2K)
+- tim_offset <<= 2;
+- state->timing_offset += tim_offset;
++
++ value = dib3000mc_read_word(state, 1026);
++ if (value != 0x3001 && value != 0x3002) {
++ dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
++ return -EREMOTEIO;
+ }
++ state->dev_id = value;
++
++ dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
++
++ return 0;
++}
+
+- tim_offset = state->timing_offset;
+- if (tim_offset < 0) {
+- tim_sgn = 1;
+- tim_offset = -tim_offset;
++static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
++{
++ u32 timf;
++
++ if (state->timf == 0) {
++ timf = 1384402; // default value for 8MHz
++ if (update_offset)
++ msleep(200); // first time we do an update
+ } else
+- tim_sgn = 0;
++ timf = state->timf;
+
+- comp1 = (u32)tim_offset * (u32)timf_lsb ;
+- comp2 = (u32)tim_offset * (u32)timf_msb ;
+- comp = ((comp1 >> 16) + comp2) >> 7;
++ timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
+
+- if (tim_sgn == 0)
+- comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp;
+- else
+- comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ;
++ if (update_offset) {
++ s16 tim_offs = dib3000mc_read_word(state, 416);
++
++ if (tim_offs & 0x2000)
++ tim_offs -= 0x4000;
++
++ if (nfft == 0)
++ tim_offs *= 4;
++
++ timf += tim_offs;
++ state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
++ }
++
++ dprintk("timf: %d\n", timf);
+
+- timf_msb = (comp >> 16) & 0xff;
+- timf_lsb = comp & 0xffff;
++ dib3000mc_write_word(state, 23, timf >> 16);
++ dib3000mc_write_word(state, 24, timf & 0xffff);
+
+- wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb);
+- wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb);
+ return 0;
+ }
+
+-static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost)
++static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state)
+ {
+- if (boost) {
+- wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON);
++ u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb;
++ if (state->cfg->pwm3_inversion) {
++ reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
++ reg_52 |= (1 << 2);
+ } else {
+- wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF);
+- }
+- switch (bw) {
+- case BANDWIDTH_8_MHZ:
+- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+- break;
+- case BANDWIDTH_7_MHZ:
+- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz);
+- break;
+- case BANDWIDTH_6_MHZ:
+- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz);
+- break;
+-/* case BANDWIDTH_5_MHZ:
+- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz);
+- break;*/
+- case BANDWIDTH_AUTO:
+- return -EOPNOTSUPP;
+- default:
+- err("unknown bandwidth value (%d).",bw);
+- return -EINVAL;
+- }
+- if (boost) {
+- u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) +
+- rd(DIB3000MC_REG_BW_TIMOUT_LSB);
+- timeout *= 85; timeout >>= 7;
+- wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff);
+- wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff);
++ reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
++ reg_52 |= (1 << 8);
+ }
++ dib3000mc_write_word(state, 51, reg_51);
++ dib3000mc_write_word(state, 52, reg_52);
++
++ if (state->cfg->use_pwm3)
++ dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
++ else
++ dib3000mc_write_word(state, 245, 0);
++
++ dib3000mc_write_word(state, 1040, 0x3);
+ return 0;
+ }
+
+-static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con)
++static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
+ {
+- switch (con) {
+- case QAM_64:
+- wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]);
+- break;
+- case QAM_16:
+- wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
+- break;
+- case QPSK:
+- wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]);
+- break;
+- case QAM_AUTO:
++ int ret = 0;
++ u16 fifo_threshold = 1792;
++ u16 outreg = 0;
++ u16 outmode = 0;
++ u16 elecout = 1;
++ u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
++
++ dprintk("-I- Setting output mode for demod %p to %d\n",
++ &state->demod, mode);
++
++ switch (mode) {
++ case OUTMODE_HIGH_Z: // disable
++ elecout = 0;
++ break;
++ case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
++ outmode = 0;
++ break;
++ case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
++ outmode = 1;
++ break;
++ case OUTMODE_MPEG2_SERIAL: // STBs with serial input
++ outmode = 2;
++ break;
++ case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
++ elecout = 3;
++ /*ADDR @ 206 :
++ P_smo_error_discard [1;6:6] = 0
++ P_smo_rs_discard [1;5:5] = 0
++ P_smo_pid_parse [1;4:4] = 0
++ P_smo_fifo_flush [1;3:3] = 0
++ P_smo_mode [2;2:1] = 11
++ P_smo_ovf_prot [1;0:0] = 0
++ */
++ smo_reg |= 3 << 1;
++ fifo_threshold = 512;
++ outmode = 5;
++ break;
++ case OUTMODE_DIVERSITY:
++ outmode = 4;
++ elecout = 1;
+ break;
+ default:
+- warn("unkown constellation.");
++ dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
++ outmode = 0;
+ break;
+ }
+- return 0;
++
++ if ((state->cfg->output_mpeg2_in_188_bytes))
++ smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1
++
++ outreg = dib3000mc_read_word(state, 244) & 0x07FF;
++ outreg |= (outmode << 11);
++ ret |= dib3000mc_write_word(state, 244, outreg);
++ ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
++ ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
++ ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
++ return ret;
+ }
+
+-static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val)
++static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+ {
+- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+- fe_code_rate_t fe_cr = FEC_NONE;
+- u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0;
+- int seq;
+-
+- switch (ofdm->transmission_mode) {
+- case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
+- case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break;
+- case TRANSMISSION_MODE_AUTO: break;
+- default: return -EINVAL;
+- }
+- switch (ofdm->guard_interval) {
+- case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
+- case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
+- case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break;
+- case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break;
+- case GUARD_INTERVAL_AUTO: break;
+- default: return -EINVAL;
+- }
+- switch (ofdm->constellation) {
+- case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break;
+- case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
+- case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
+- case QAM_AUTO: break;
+- default: return -EINVAL;
+- }
+- switch (ofdm->hierarchy_information) {
+- case HIERARCHY_NONE: /* fall through */
+- case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break;
+- case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break;
+- case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break;
+- case HIERARCHY_AUTO: break;
+- default: return -EINVAL;
+- }
+- if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+- hrch = DIB3000_HRCH_OFF;
+- sel_hp = DIB3000_SELECT_HP;
+- fe_cr = ofdm->code_rate_HP;
+- } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
+- hrch = DIB3000_HRCH_ON;
+- sel_hp = DIB3000_SELECT_LP;
+- fe_cr = ofdm->code_rate_LP;
+- }
+- switch (fe_cr) {
+- case FEC_1_2: cr = DIB3000_FEC_1_2; break;
+- case FEC_2_3: cr = DIB3000_FEC_2_3; break;
+- case FEC_3_4: cr = DIB3000_FEC_3_4; break;
+- case FEC_5_6: cr = DIB3000_FEC_5_6; break;
+- case FEC_7_8: cr = DIB3000_FEC_7_8; break;
+- case FEC_NONE: break;
+- case FEC_AUTO: break;
+- default: return -EINVAL;
+- }
++ struct dib3000mc_state *state = demod->demodulator_priv;
++ u16 bw_cfg[6] = { 0 };
++ u16 imp_bw_cfg[3] = { 0 };
++ u16 reg;
+
+- wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft));
+- wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch));
++/* settings here are for 27.7MHz */
++ switch (bw) {
++ case BANDWIDTH_8_MHZ:
++ bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
++ imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
++ break;
+
+- switch (fep->inversion) {
+- case INVERSION_OFF:
+- wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
++ case BANDWIDTH_7_MHZ:
++ bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
++ imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
+ break;
+- case INVERSION_AUTO: /* fall through */
+- case INVERSION_ON:
+- wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
++
++ case BANDWIDTH_6_MHZ:
++ bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
++ imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
+ break;
+- default:
+- return -EINVAL;
++
++ case 255 /* BANDWIDTH_5_MHZ */:
++ bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
++ imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
++ break;
++
++ default: return -EINVAL;
+ }
+
+- seq = dib3000_seq
+- [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
+- [ofdm->guard_interval == GUARD_INTERVAL_AUTO]
+- [fep->inversion == INVERSION_AUTO];
+-
+- deb_setf("seq? %d\n", seq);
+- wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
+- *auto_val = ofdm->constellation == QAM_AUTO ||
+- ofdm->hierarchy_information == HIERARCHY_AUTO ||
+- ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
+- ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
+- fe_cr == FEC_AUTO ||
+- fep->inversion == INVERSION_AUTO;
++ for (reg = 6; reg < 12; reg++)
++ dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
++ dib3000mc_write_word(state, 12, 0x0000);
++ dib3000mc_write_word(state, 13, 0x03e8);
++ dib3000mc_write_word(state, 14, 0x0000);
++ dib3000mc_write_word(state, 15, 0x03f2);
++ dib3000mc_write_word(state, 16, 0x0001);
++ dib3000mc_write_word(state, 17, 0xb0d0);
++ // P_sec_len
++ dib3000mc_write_word(state, 18, 0x0393);
++ dib3000mc_write_word(state, 19, 0x8700);
++
++ for (reg = 55; reg < 58; reg++)
++ dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
++
++ // Timing configuration
++ dib3000mc_set_timing(state, 0, bw, 0);
++
+ return 0;
+ }
+
+-static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+- struct dvb_frontend_parameters *fep)
++static u16 impulse_noise_val[29] =
++
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+- fe_code_rate_t *cr;
+- u16 tps_val,cr_val;
+- int inv_test1,inv_test2;
+- u32 dds_val, threshold = 0x1000000;
+-
+- if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507))
+- return 0;
+-
+- dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
+- deb_getf("DDS_FREQ: %6x\n",dds_val);
+- if (dds_val < threshold)
+- inv_test1 = 0;
+- else if (dds_val == threshold)
+- inv_test1 = 1;
+- else
+- inv_test1 = 2;
+-
+- dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
+- deb_getf("DDS_SET_FREQ: %6x\n",dds_val);
+- if (dds_val < threshold)
+- inv_test2 = 0;
+- else if (dds_val == threshold)
+- inv_test2 = 1;
++ 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
++ 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
++ 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
++};
++
++static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
++{
++ u16 i;
++ for (i = 58; i < 87; i++)
++ dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
++
++ if (nfft == 1) {
++ dib3000mc_write_word(state, 58, 0x3b);
++ dib3000mc_write_word(state, 84, 0x00);
++ dib3000mc_write_word(state, 85, 0x8200);
++ }
++
++ dib3000mc_write_word(state, 34, 0x1294);
++ dib3000mc_write_word(state, 35, 0x1ff8);
++ if (mode == 1)
++ dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
++}
++
++static int dib3000mc_init(struct dvb_frontend *demod)
++{
++ struct dib3000mc_state *state = demod->demodulator_priv;
++ struct dibx000_agc_config *agc = state->cfg->agc;
++
++ // Restart Configuration
++ dib3000mc_write_word(state, 1027, 0x8000);
++ dib3000mc_write_word(state, 1027, 0x0000);
++
++ // power up the demod + mobility configuration
++ dib3000mc_write_word(state, 140, 0x0000);
++ dib3000mc_write_word(state, 1031, 0);
++
++ if (state->cfg->mobile_mode) {
++ dib3000mc_write_word(state, 139, 0x0000);
++ dib3000mc_write_word(state, 141, 0x0000);
++ dib3000mc_write_word(state, 175, 0x0002);
++ dib3000mc_write_word(state, 1032, 0x0000);
++ } else {
++ dib3000mc_write_word(state, 139, 0x0001);
++ dib3000mc_write_word(state, 141, 0x0000);
++ dib3000mc_write_word(state, 175, 0x0000);
++ dib3000mc_write_word(state, 1032, 0x012C);
++ }
++ dib3000mc_write_word(state, 1033, 0x0000);
++
++ // P_clk_cfg
++ dib3000mc_write_word(state, 1037, 0x3130);
++
++ // other configurations
++
++ // P_ctrl_sfreq
++ dib3000mc_write_word(state, 33, (5 << 0));
++ dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
++
++ // Phase noise control
++ // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
++ dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
++
++ if (state->cfg->phase_noise_mode == 0)
++ dib3000mc_write_word(state, 111, 0x00);
+ else
+- inv_test2 = 2;
++ dib3000mc_write_word(state, 111, 0x02);
++
++ // P_agc_global
++ dib3000mc_write_word(state, 50, 0x8000);
++
++ // agc setup misc
++ dib3000mc_setup_pwm_state(state);
++
++ // P_agc_counter_lock
++ dib3000mc_write_word(state, 53, 0x87);
++ // P_agc_counter_unlock
++ dib3000mc_write_word(state, 54, 0x87);
++
++ /* agc */
++ dib3000mc_write_word(state, 36, state->cfg->max_time);
++ dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0));
++ dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
++ dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
++
++ // set_agc_loop_Bw
++ dib3000mc_write_word(state, 40, 0x0179);
++ dib3000mc_write_word(state, 41, 0x03f0);
++
++ dib3000mc_write_word(state, 42, agc->agc1_max);
++ dib3000mc_write_word(state, 43, agc->agc1_min);
++ dib3000mc_write_word(state, 44, agc->agc2_max);
++ dib3000mc_write_word(state, 45, agc->agc2_min);
++ dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
++ dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
++ dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
++ dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
++
++// Begin: TimeOut registers
++ // P_pha3_thres
++ dib3000mc_write_word(state, 110, 3277);
++ // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
++ dib3000mc_write_word(state, 26, 0x6680);
++ // lock_mask0
++ dib3000mc_write_word(state, 1, 4);
++ // lock_mask1
++ dib3000mc_write_word(state, 2, 4);
++ // lock_mask2
++ dib3000mc_write_word(state, 3, 0x1000);
++ // P_search_maxtrial=1
++ dib3000mc_write_word(state, 5, 1);
++
++ dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
++
++ // div_lock_mask
++ dib3000mc_write_word(state, 4, 0x814);
++
++ dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
++ dib3000mc_write_word(state, 22, 0x463d);
++
++ // Spurious rm cfg
++ // P_cspu_regul, P_cspu_win_cut
++ dib3000mc_write_word(state, 120, 0x200f);
++ // P_adp_selec_monit
++ dib3000mc_write_word(state, 134, 0);
++
++ // Fec cfg
++ dib3000mc_write_word(state, 195, 0x10);
++
++ // diversity register: P_dvsy_sync_wait..
++ dib3000mc_write_word(state, 180, 0x2FF0);
++
++ // Impulse noise configuration
++ dib3000mc_set_impulse_noise(state, 0, 1);
++
++ // output mode set-up
++ dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
++
++ /* close the i2c-gate */
++ dib3000mc_write_word(state, 769, (1 << 7) );
+
+- fep->inversion =
+- ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
+- ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
+- INVERSION_ON : INVERSION_OFF;
++ return 0;
++}
+
+- deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
++static int dib3000mc_sleep(struct dvb_frontend *demod)
++{
++ struct dib3000mc_state *state = demod->demodulator_priv;
+
+- fep->frequency = state->last_tuned_freq;
+- fep->u.ofdm.bandwidth= state->last_tuned_bw;
++ dib3000mc_write_word(state, 1031, 0xFFFF);
++ dib3000mc_write_word(state, 1032, 0xFFFF);
++ dib3000mc_write_word(state, 1033, 0xFFF0);
+
+- tps_val = rd(DIB3000MC_REG_TUNING_PARM);
++ return 0;
++}
+
+- switch (DIB3000MC_TP_QAM(tps_val)) {
+- case DIB3000_CONSTELLATION_QPSK:
+- deb_getf("QPSK ");
+- ofdm->constellation = QPSK;
+- break;
+- case DIB3000_CONSTELLATION_16QAM:
+- deb_getf("QAM16 ");
+- ofdm->constellation = QAM_16;
++static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
++{
++ u16 cfg[4] = { 0 },reg;
++ switch (qam) {
++ case 0:
++ cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
+ break;
+- case DIB3000_CONSTELLATION_64QAM:
+- deb_getf("QAM64 ");
+- ofdm->constellation = QAM_64;
++ case 1:
++ cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
+ break;
+- default:
+- err("Unexpected constellation returned by TPS (%d)", tps_val);
++ case 2:
++ cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
+ break;
+ }
++ for (reg = 129; reg < 133; reg++)
++ dib3000mc_write_word(state, reg, cfg[reg - 129]);
++}
+
+- if (DIB3000MC_TP_HRCH(tps_val)) {
+- deb_getf("HRCH ON ");
+- cr = &ofdm->code_rate_LP;
+- ofdm->code_rate_HP = FEC_NONE;
+- switch (DIB3000MC_TP_ALPHA(tps_val)) {
+- case DIB3000_ALPHA_0:
+- deb_getf("HIERARCHY_NONE ");
+- ofdm->hierarchy_information = HIERARCHY_NONE;
+- break;
+- case DIB3000_ALPHA_1:
+- deb_getf("HIERARCHY_1 ");
+- ofdm->hierarchy_information = HIERARCHY_1;
+- break;
+- case DIB3000_ALPHA_2:
+- deb_getf("HIERARCHY_2 ");
+- ofdm->hierarchy_information = HIERARCHY_2;
+- break;
+- case DIB3000_ALPHA_4:
+- deb_getf("HIERARCHY_4 ");
+- ofdm->hierarchy_information = HIERARCHY_4;
+- break;
+- default:
+- err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
+- break;
+- }
+- cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val);
+- } else {
+- deb_getf("HRCH OFF ");
+- cr = &ofdm->code_rate_HP;
+- ofdm->code_rate_LP = FEC_NONE;
+- ofdm->hierarchy_information = HIERARCHY_NONE;
+- cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val);
+- }
++static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
++{
++ u16 tmp;
+
+- switch (cr_val) {
+- case DIB3000_FEC_1_2:
+- deb_getf("FEC_1_2 ");
+- *cr = FEC_1_2;
+- break;
+- case DIB3000_FEC_2_3:
+- deb_getf("FEC_2_3 ");
+- *cr = FEC_2_3;
+- break;
+- case DIB3000_FEC_3_4:
+- deb_getf("FEC_3_4 ");
+- *cr = FEC_3_4;
+- break;
+- case DIB3000_FEC_5_6:
+- deb_getf("FEC_5_6 ");
+- *cr = FEC_4_5;
+- break;
+- case DIB3000_FEC_7_8:
+- deb_getf("FEC_7_8 ");
+- *cr = FEC_7_8;
+- break;
+- default:
+- err("Unexpected FEC returned by TPS (%d)", tps_val);
+- break;
+- }
++ dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+
+- switch (DIB3000MC_TP_GUARD(tps_val)) {
+- case DIB3000_GUARD_TIME_1_32:
+- deb_getf("GUARD_INTERVAL_1_32 ");
+- ofdm->guard_interval = GUARD_INTERVAL_1_32;
+- break;
+- case DIB3000_GUARD_TIME_1_16:
+- deb_getf("GUARD_INTERVAL_1_16 ");
+- ofdm->guard_interval = GUARD_INTERVAL_1_16;
+- break;
+- case DIB3000_GUARD_TIME_1_8:
+- deb_getf("GUARD_INTERVAL_1_8 ");
+- ofdm->guard_interval = GUARD_INTERVAL_1_8;
+- break;
+- case DIB3000_GUARD_TIME_1_4:
+- deb_getf("GUARD_INTERVAL_1_4 ");
+- ofdm->guard_interval = GUARD_INTERVAL_1_4;
+- break;
+- default:
+- err("Unexpected Guard Time returned by TPS (%d)", tps_val);
+- break;
+- }
++// if (boost)
++// dib3000mc_write_word(state, 100, (11 << 6) + 6);
++// else
++ dib3000mc_write_word(state, 100, (16 << 6) + 9);
+
+- switch (DIB3000MC_TP_FFT(tps_val)) {
+- case DIB3000_TRANSMISSION_MODE_2K:
+- deb_getf("TRANSMISSION_MODE_2K ");
+- ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+- break;
+- case DIB3000_TRANSMISSION_MODE_8K:
+- deb_getf("TRANSMISSION_MODE_8K ");
+- ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+- break;
+- default:
+- err("unexpected transmission mode return by TPS (%d)", tps_val);
+- break;
+- }
+- deb_getf("\n");
++ dib3000mc_write_word(state, 1027, 0x0800);
++ dib3000mc_write_word(state, 1027, 0x0000);
+
+- return 0;
++ //Default cfg isi offset adp
++ dib3000mc_write_word(state, 26, 0x6680);
++ dib3000mc_write_word(state, 29, 0x1273);
++ dib3000mc_write_word(state, 33, 5);
++ dib3000mc_set_adp_cfg(state, 1);
++ dib3000mc_write_word(state, 133, 15564);
++
++ dib3000mc_write_word(state, 12 , 0x0);
++ dib3000mc_write_word(state, 13 , 0x3e8);
++ dib3000mc_write_word(state, 14 , 0x0);
++ dib3000mc_write_word(state, 15 , 0x3f2);
++
++ dib3000mc_write_word(state, 93,0);
++ dib3000mc_write_word(state, 94,0);
++ dib3000mc_write_word(state, 95,0);
++ dib3000mc_write_word(state, 96,0);
++ dib3000mc_write_word(state, 97,0);
++ dib3000mc_write_word(state, 98,0);
++
++ dib3000mc_set_impulse_noise(state, 0, chan->nfft);
++
++ tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
++ dib3000mc_write_word(state, 0, tmp);
++
++ dib3000mc_write_word(state, 5, seq);
++
++ tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
++ if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
++ tmp |= chan->vit_code_rate_hp << 1;
++ else
++ tmp |= chan->vit_code_rate_lp << 1;
++ dib3000mc_write_word(state, 181, tmp);
++
++ // diversity synchro delay
++ tmp = dib3000mc_read_word(state, 180) & 0x000f;
++ tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
++ dib3000mc_write_word(state, 180, tmp);
++
++ // restart demod
++ tmp = dib3000mc_read_word(state, 0);
++ dib3000mc_write_word(state, 0, tmp | (1 << 9));
++ dib3000mc_write_word(state, 0, tmp);
++
++ msleep(30);
++
++ dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+ }
+
+-static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+- struct dvb_frontend_parameters *fep, int tuner)
++static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+- int search_state,auto_val;
+- u16 val;
++ struct dib3000mc_state *state = demod->demodulator_priv;
++ u16 reg;
++// u32 val;
++ struct dibx000_ofdm_channel fchan;
+
+- if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+- fe->ops.tuner_ops.set_params(fe, fep);
+- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+-
+- state->last_tuned_freq = fep->frequency;
+- // if (!scanboost) {
+- dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
+- dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
+- state->last_tuned_bw = ofdm->bandwidth;
+-
+- wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
+- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
+- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
+-
+- /* Default cfg isi offset adp */
+- wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
+-
+- wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
+- dib3000mc_set_adp_cfg(state,ofdm->constellation);
+- wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
+-
+- wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
+- /* power smoothing */
+- if (ofdm->bandwidth != BANDWIDTH_8_MHZ) {
+- wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
+- } else {
+- wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
+- }
+- auto_val = 0;
+- dib3000mc_set_general_cfg(state,fep,&auto_val);
+- dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
+-
+- val = rd(DIB3000MC_REG_DEMOD_PARM);
+- wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
+- wr(DIB3000MC_REG_DEMOD_PARM,val);
+- // }
+- msleep(70);
+-
+- /* something has to be auto searched */
+- if (auto_val) {
+- int as_count=0;
+-
+- deb_setf("autosearch enabled.\n");
+-
+- val = rd(DIB3000MC_REG_DEMOD_PARM);
+- wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
+- wr(DIB3000MC_REG_DEMOD_PARM,val);
+-
+- while ((search_state = dib3000_search_status(
+- rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
+- msleep(10);
+-
+- deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
+-
+- if (search_state == 1) {
+- struct dvb_frontend_parameters feps;
+- if (dib3000mc_get_frontend(fe, &feps) == 0) {
+- deb_setf("reading tuning data from frontend succeeded.\n");
+- return dib3000mc_set_frontend(fe, &feps, 0);
+- }
+- }
+- } else {
+- dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth);
+- wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
+- dib3000mc_set_adp_cfg(state,ofdm->constellation);
+-
+- /* set_offset_cfg */
+- wr_foreach(dib3000mc_reg_offset,
+- dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
+- }
+- } else { /* second call, after autosearch (fka: set_WithKnownParams) */
+-// dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth);
++ INIT_OFDM_CHANNEL(&fchan);
++ fchan = *chan;
+
+- auto_val = 0;
+- dib3000mc_set_general_cfg(state,fep,&auto_val);
+- if (auto_val)
+- deb_info("auto_val is true, even though an auto search was already performed.\n");
+
+- dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
++ /* a channel for autosearch */
++ reg = 0;
++ if (chan->nfft == -1 && chan->guard == -1) reg = 7;
++ if (chan->nfft == -1 && chan->guard != -1) reg = 2;
++ if (chan->nfft != -1 && chan->guard == -1) reg = 3;
+
+- val = rd(DIB3000MC_REG_DEMOD_PARM);
+- wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
+- wr(DIB3000MC_REG_DEMOD_PARM,val);
++ fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
++ fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
++ fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+
+- msleep(30);
++ dib3000mc_set_channel_cfg(state, &fchan, reg);
++
++ reg = dib3000mc_read_word(state, 0);
++ dib3000mc_write_word(state, 0, reg | (1 << 8));
++ dib3000mc_read_word(state, 511);
++ dib3000mc_write_word(state, 0, reg);
+
+- wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
+- 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)
++static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
+ {
+- struct dib3000_state *state = fe->demodulator_priv;
+- deb_info("init start\n");
++ struct dib3000mc_state *state = demod->demodulator_priv;
++ u16 irq_pending = dib3000mc_read_word(state, 511);
+
+- state->timing_offset = 0;
+- state->timing_offset_comp_done = 0;
++ if (irq_pending & 0x1) // failed
++ return 1;
+
+- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
+- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
+- wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
+- wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
+- wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
+- wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
++ if (irq_pending & 0x2) // succeeded
++ return 2;
+
+- wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
+- wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
++ return 0; // still pending
++}
+
+- wr(33,5);
+- wr(36,81);
+- wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
++static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
++{
++ struct dib3000mc_state *state = demod->demodulator_priv;
+
+- wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
+- wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
++ // ** configure demod **
++ dib3000mc_set_channel_cfg(state, ch, 0);
+
+- /* mobile mode - portable reception */
+- wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
++ // activates isi
++ dib3000mc_write_word(state, 29, 0x1073);
+
+-/* TUNER_PANASONIC_ENV57H12D5: */
+- wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
+- wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
+- wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
++ dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
+
+- wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
+- wr(26,0x6680);
+- wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
+- wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
+- wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
+- wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
++ if (ch->nfft == 1) {
++ dib3000mc_write_word(state, 26, 38528);
++ dib3000mc_write_word(state, 33, 8);
++ } else {
++ dib3000mc_write_word(state, 26, 30336);
++ dib3000mc_write_word(state, 33, 6);
++ }
+
+- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+- wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
++ if (dib3000mc_read_word(state, 509) & 0x80)
++ dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+
+- wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
++ return 0;
++}
+
+- wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
+- wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
++struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
++{
++ struct dib3000mc_state *st = demod->demodulator_priv;
++ return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
++}
+
+- dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
+-// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
++EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
+
+- wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
+- wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
+- wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
++static int dib3000mc_get_frontend(struct dvb_frontend* fe,
++ struct dvb_frontend_parameters *fep)
++{
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ u16 tps = dib3000mc_read_word(state,458);
+
+- wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
++ fep->inversion = INVERSION_AUTO;
+
+- dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
++ fep->u.ofdm.bandwidth = state->current_bandwidth;
+
+-/* output mode control, just the MPEG2_SLAVE */
+-// set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
+- wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
+- wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
+- wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
+- wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
++ switch ((tps >> 8) & 0x1) {
++ case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
++ case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
++ }
+
+-/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
+- wr(DIB3000MC_REG_OUTMODE,
+- DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
+- rd(DIB3000MC_REG_OUTMODE)));
++ switch (tps & 0x3) {
++ case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
++ case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
++ case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
++ case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
++ }
+
+- wr(DIB3000MC_REG_SMO_MODE,
+- DIB3000MC_SMO_MODE_DEFAULT |
+- DIB3000MC_SMO_MODE_188);
++ switch ((tps >> 13) & 0x3) {
++ case 0: fep->u.ofdm.constellation = QPSK; break;
++ case 1: fep->u.ofdm.constellation = QAM_16; break;
++ case 2:
++ default: fep->u.ofdm.constellation = QAM_64; break;
++ }
+
+- wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
+- wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
+-*/
++ /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
++ /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
+
+-/* diversity */
+- wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
+- wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
++ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
++ switch ((tps >> 5) & 0x7) {
++ case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
++ case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
++ case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
++ case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
++ case 7:
++ default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+
+- set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
++ }
+
+- set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
++ switch ((tps >> 2) & 0x7) {
++ case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
++ case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
++ case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
++ case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
++ case 7:
++ default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
++ }
+
+- deb_info("init end\n");
+ return 0;
+ }
+-static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
++
++static int dib3000mc_set_frontend(struct dvb_frontend* fe,
++ struct dvb_frontend_parameters *fep)
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+- u16 lock = rd(DIB3000MC_REG_LOCKING);
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ struct dibx000_ofdm_channel ch;
++
++ INIT_OFDM_CHANNEL(&ch);
++ FEP2DIB(fep,&ch);
++
++ state->current_bandwidth = fep->u.ofdm.bandwidth;
++ dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
++
++ if (fe->ops.tuner_ops.set_params) {
++ fe->ops.tuner_ops.set_params(fe, fep);
++ msleep(100);
++ }
++
++ if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
++ fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
++ fep->u.ofdm.constellation == QAM_AUTO ||
++ fep->u.ofdm.code_rate_HP == FEC_AUTO) {
++ int i = 100, found;
++
++ dib3000mc_autosearch_start(fe, &ch);
++ do {
++ msleep(1);
++ found = dib3000mc_autosearch_is_irq(fe);
++ } while (found == 0 && i--);
++
++ dprintk("autosearch returns: %d\n",found);
++ if (found == 0 || found == 1)
++ return 0; // no channel found
++
++ dib3000mc_get_frontend(fe, fep);
++ FEP2DIB(fep,&ch);
++ }
++
++ /* make this a config parameter */
++ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
++
++ return dib3000mc_tune(fe, &ch);
++}
++
++static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
++{
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ u16 lock = dib3000mc_read_word(state, 509);
+
+ *stat = 0;
+- if (DIB3000MC_AGC_LOCK(lock))
++
++ if (lock & 0x8000)
+ *stat |= FE_HAS_SIGNAL;
+- if (DIB3000MC_CARRIER_LOCK(lock))
++ if (lock & 0x3000)
+ *stat |= FE_HAS_CARRIER;
+- if (DIB3000MC_TPS_LOCK(lock))
++ if (lock & 0x0100)
+ *stat |= FE_HAS_VITERBI;
+- if (DIB3000MC_MPEG_SYNC_LOCK(lock))
+- *stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
+-
+- deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040));
++ if (lock & 0x0010)
++ *stat |= FE_HAS_SYNC;
++ if (lock & 0x0008)
++ *stat |= FE_HAS_LOCK;
+
+ return 0;
+ }
+
+-static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
++static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+- *ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
+ return 0;
+ }
+
+-static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
++static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+-
+- *unc = rd(DIB3000MC_REG_PACKET_ERRORS);
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ *unc = dib3000mc_read_word(state, 508);
+ return 0;
+ }
+
+-/* see dib3000mb.c for calculation comments */
+-static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
++static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+- u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
+- *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
+-
+- deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ u16 val = dib3000mc_read_word(state, 392);
++ *strength = 65535 - val;
+ return 0;
+ }
+
+-/* see dib3000mb.c for calculation comments */
+ static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
+ {
+- struct dib3000_state* state = fe->demodulator_priv;
+- u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB),
+- val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB);
+- u16 sig,noise;
+-
+- sig = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
+- noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3);
+- if (noise == 0)
+- *snr = 0xffff;
+- else
+- *snr = (u16) sig/noise;
+-
+- deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
+- deb_stat("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
+- deb_stat("snr: %d\n",*snr);
+- return 0;
+-}
+-
+-static int dib3000mc_sleep(struct dvb_frontend* fe)
+-{
+- struct dib3000_state* state = fe->demodulator_priv;
+-
+- set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
+- wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
+- wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN);
+- wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN);
++ *snr = 0x0000;
+ return 0;
+ }
+
+@@ -729,185 +731,145 @@ static int dib3000mc_fe_get_tune_setting
+ return 0;
+ }
+
+-static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe)
++static void dib3000mc_release(struct dvb_frontend *fe)
+ {
+- return dib3000mc_fe_init(fe, 0);
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ dibx000_exit_i2c_master(&state->i2c_master);
++ kfree(state);
+ }
+
+-static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
++int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
+ {
+- return dib3000mc_set_frontend(fe, fep, 1);
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
++ return 0;
+ }
++EXPORT_SYMBOL(dib3000mc_pid_control);
+
+-static void dib3000mc_release(struct dvb_frontend* fe)
++int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
+ {
+- struct dib3000_state *state = fe->demodulator_priv;
+- kfree(state);
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
++ tmp |= (onoff << 4);
++ return dib3000mc_write_word(state, 206, tmp);
+ }
++EXPORT_SYMBOL(dib3000mc_pid_parse);
+
+-/* pid filter and transfer stuff */
+-static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
++void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
+ {
+- struct dib3000_state *state = fe->demodulator_priv;
+- pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
+- wr(index+DIB3000MC_REG_FIRST_PID,pid);
+- return 0;
++ struct dib3000mc_state *state = fe->demodulator_priv;
++ state->cfg = cfg;
+ }
++EXPORT_SYMBOL(dib3000mc_set_config);
+
+-static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
++int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[])
+ {
+- struct dib3000_state *state = fe->demodulator_priv;
+- u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
++ struct dib3000mc_state st = { .i2c_adap = i2c };
++ int k;
++ u8 new_addr;
++
++ static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
++
++ for (k = no_of_demods-1; k >= 0; k--) {
++ st.cfg = &cfg[k];
++
++ /* designated i2c address */
++ new_addr = DIB3000MC_I2C_ADDRESS[k];
++ st.i2c_addr = new_addr;
++ if (dib3000mc_identify(&st) != 0) {
++ st.i2c_addr = default_addr;
++ if (dib3000mc_identify(&st) != 0) {
++ dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
++ return -ENODEV;
++ }
++ }
+
+- deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
++ dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);
+
+- if (onoff) {
+- deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
+- wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
+- } else {
+- deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
+- wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
++ // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
++ dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);
++ st.i2c_addr = new_addr;
+ }
+- return 0;
+-}
+
+-static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
+-{
+- struct dib3000_state *state = fe->demodulator_priv;
+- u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
+-
+- deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
++ for (k = 0; k < no_of_demods; k++) {
++ st.cfg = &cfg[k];
++ st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];
+
+- if (onoff) {
+- wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
+- } else {
+- wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
+- }
+- return 0;
+-}
++ dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);
+
+-static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
+-{
+- struct dib3000_state *state = fe->demodulator_priv;
+- if (onoff) {
+- wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
+- } else {
+- wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
++ /* turn off data output */
++ dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);
+ }
+ return 0;
+ }
+-
+-static int dib3000mc_demod_init(struct dib3000_state *state)
+-{
+- u16 default_addr = 0x0a;
+- /* first init */
+- if (state->config.demod_address != default_addr) {
+- deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr);
+- wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
+- wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
+-
+- wr(DIB3000MC_REG_RST_I2C_ADDR,
+- DIB3000MC_DEMOD_ADDR(default_addr) |
+- DIB3000MC_DEMOD_ADDR_ON);
+-
+- state->config.demod_address = default_addr;
+-
+- wr(DIB3000MC_REG_RST_I2C_ADDR,
+- DIB3000MC_DEMOD_ADDR(default_addr));
+- } else
+- deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address);
+- return 0;
+-}
+-
++EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
+
+ static struct dvb_frontend_ops dib3000mc_ops;
+
+-struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
+- struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
++struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
+ {
+- struct dib3000_state* state = NULL;
+- u16 devid;
++ struct dvb_frontend *demod;
++ struct dib3000mc_state *st;
++ st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
++ if (st == NULL)
++ return NULL;
+
+- /* allocate memory for the internal state */
+- state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+- if (state == NULL)
+- goto error;
++ st->cfg = cfg;
++ st->i2c_adap = i2c_adap;
++ st->i2c_addr = i2c_addr;
+
+- /* setup the state */
+- state->i2c = i2c;
+- memcpy(&state->config,config,sizeof(struct dib3000_config));
++ demod = &st->demod;
++ demod->demodulator_priv = st;
++ memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
+
+- /* check for the correct demod */
+- if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
++ if (dib3000mc_identify(st) != 0)
+ goto error;
+
+- devid = rd(DIB3000_REG_DEVICE_ID);
+- if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
+- goto error;
++ dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
+
+- switch (devid) {
+- case DIB3000MC_DEVICE_ID:
+- info("Found a DiBcom 3000M-C, interesting...");
+- break;
+- case DIB3000P_DEVICE_ID:
+- info("Found a DiBcom 3000P.");
+- break;
+- }
+-
+- /* create dvb_frontend */
+- memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
+- state->frontend.demodulator_priv = state;
+-
+- /* set the xfer operations */
+- xfer_ops->pid_parse = dib3000mc_pid_parse;
+- xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
+- xfer_ops->pid_ctrl = dib3000mc_pid_control;
+- xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl;
++ dib3000mc_write_word(st, 1037, 0x3130);
+
+- dib3000mc_demod_init(state);
+-
+- return &state->frontend;
++ return demod;
+
+ error:
+- kfree(state);
++ kfree(st);
+ return NULL;
+ }
+ EXPORT_SYMBOL(dib3000mc_attach);
+
+ static struct dvb_frontend_ops dib3000mc_ops = {
+-
+ .info = {
+- .name = "DiBcom 3000P/M-C DVB-T",
+- .type = FE_OFDM,
+- .frequency_min = 44250000,
+- .frequency_max = 867250000,
+- .frequency_stepsize = 62500,
++ .name = "DiBcom 3000MC/P",
++ .type = FE_OFDM,
++ .frequency_min = 44250000,
++ .frequency_max = 867250000,
++ .frequency_stepsize = 62500,
+ .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,
++ 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 = dib3000mc_release,
++ .release = dib3000mc_release,
+
+- .init = dib3000mc_fe_init_nonmobile,
+- .sleep = dib3000mc_sleep,
++ .init = dib3000mc_init,
++ .sleep = dib3000mc_sleep,
+
+- .set_frontend = dib3000mc_set_frontend_and_tuner,
+- .get_frontend = dib3000mc_get_frontend,
+- .get_tune_settings = dib3000mc_fe_get_tune_settings,
++ .set_frontend = dib3000mc_set_frontend,
++ .get_tune_settings = dib3000mc_fe_get_tune_settings,
++ .get_frontend = dib3000mc_get_frontend,
+
+- .read_status = dib3000mc_read_status,
+- .read_ber = dib3000mc_read_ber,
++ .read_status = dib3000mc_read_status,
++ .read_ber = dib3000mc_read_ber,
+ .read_signal_strength = dib3000mc_read_signal_strength,
+- .read_snr = dib3000mc_read_snr,
+- .read_ucblocks = dib3000mc_read_unc_blocks,
++ .read_snr = dib3000mc_read_snr,
++ .read_ucblocks = dib3000mc_read_unc_blocks,
+ };
+
+-MODULE_AUTHOR(DRIVER_AUTHOR);
+-MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Patrick Boettcher <pboettcher at dibcom.fr>");
++MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h
+new file mode 100644
+index 0000000..72d4757
+--- /dev/null
++++ b/drivers/media/dvb/frontends/dib3000mc.h
+@@ -0,0 +1,61 @@
++/*
++ * Driver for DiBcom DiB3000MC/P-demodulator.
++ *
++ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
++ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de)
++ *
++ * This code is partially based on the previous dib3000mc.c .
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation, version 2.
++ */
++#ifndef DIB3000MC_H
++#define DIB3000MC_H
++
++#include "dibx000_common.h"
++
++struct dib3000mc_config {
++ struct dibx000_agc_config *agc;
++
++ u8 phase_noise_mode;
++ u8 impulse_noise_mode;
++
++ u8 pwm3_inversion;
++ u8 use_pwm3;
++ u16 pwm3_value;
++
++ u16 max_time;
++ u16 ln_adc_level;
++
++ u8 agc_command1 :1;
++ u8 agc_command2 :1;
++
++ u8 mobile_mode;
++
++ u8 output_mpeg2_in_188_bytes;
++};
++
++#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
++#define DEFAULT_DIB3000P_I2C_ADDRESS 24
++
++#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
++extern struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg);
++#else
++static inline struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_DIB3000MC
++
++extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]);
++
++extern struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating);
++
++extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
++extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
++
++extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *);
++
++#endif
+diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h
+deleted file mode 100644
+index 2930aac..0000000
+--- a/drivers/media/dvb/frontends/dib3000mc_priv.h
++++ /dev/null
+@@ -1,428 +0,0 @@
+-/*
+- * dib3000mc_priv.h
+- *
+- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher at 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 dib3000mc.c .
+- */
+-
+-#ifndef __DIB3000MC_PRIV_H__
+-#define __DIB3000MC_PRIV_H__
+-
+-/*
+- * Demodulator parameters
+- * reg: 0 1 1 1 11 11 111
+- * | | | | | |
+- * | | | | | +-- alpha (000=0, 001=1, 010=2, 100=4)
+- * | | | | +----- constellation (00=QPSK, 01=16QAM, 10=64QAM)
+- * | | | +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4)
+- * | | +----------- transmission mode (0=2k, 1=8k)
+- * | |
+- * | +-------------- restart autosearch for parameters
+- * +---------------- restart the demodulator
+- * reg: 181 1 111 1
+- * | | |
+- * | | +- FEC applies for HP or LP (0=LP, 1=HP)
+- * | +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8)
+- * +------- hierarchy on (0=no, 1=yes)
+- */
+-
+-/* demodulator tuning parameter and restart options */
+-#define DIB3000MC_REG_DEMOD_PARM ( 0)
+-#define DIB3000MC_DEMOD_PARM(a,c,g,t) ( \
+- (0x7 & a) | \
+- ((0x3 & c) << 3) | \
+- ((0x3 & g) << 5) | \
+- ((0x1 & t) << 7) )
+-#define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON (1 << 8)
+-#define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF (0 << 8)
+-#define DIB3000MC_DEMOD_RST_DEMOD_ON (1 << 9)
+-#define DIB3000MC_DEMOD_RST_DEMOD_OFF (0 << 9)
+-
+-/* register for hierarchy parameters */
+-#define DIB3000MC_REG_HRCH_PARM ( 181)
+-#define DIB3000MC_HRCH_PARM(s,f,h) ( \
+- (0x1 & s) | \
+- ((0x7 & f) << 1) | \
+- ((0x1 & h) << 4) )
+-
+-/* timeout ??? */
+-#define DIB3000MC_REG_UNK_1 ( 1)
+-#define DIB3000MC_UNK_1 ( 0x04)
+-
+-/* timeout ??? */
+-#define DIB3000MC_REG_UNK_2 ( 2)
+-#define DIB3000MC_UNK_2 ( 0x04)
+-
+-/* timeout ??? */
+-#define DIB3000MC_REG_UNK_3 ( 3)
+-#define DIB3000MC_UNK_3 (0x1000)
+-
+-#define DIB3000MC_REG_UNK_4 ( 4)
+-#define DIB3000MC_UNK_4 (0x0814)
+-
+-/* timeout ??? */
+-#define DIB3000MC_REG_SEQ_TPS ( 5)
+-#define DIB3000MC_SEQ_TPS_DEFAULT ( 1)
+-#define DIB3000MC_SEQ_TPS(s,t) ( \
+- ((s & 0x0f) << 4) | \
+- ((t & 0x01) << 8) )
+-#define DIB3000MC_IS_TPS(v) ((v << 8) & 0x1)
+-#define DIB3000MC_IS_AS(v) ((v >> 4) & 0xf)
+-
+-/* parameters for the bandwidth */
+-#define DIB3000MC_REG_BW_TIMOUT_MSB ( 6)
+-#define DIB3000MC_REG_BW_TIMOUT_LSB ( 7)
+-
+-static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 };
+-
+-/*static u16 dib3000mc_bandwidth_5mhz[] =
+- { 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/
+-
+-static u16 dib3000mc_bandwidth_6mhz[] =
+- { 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 };
+-
+-static u16 dib3000mc_bandwidth_7mhz[] =
+- { 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
+-
+-static u16 dib3000mc_bandwidth_8mhz[] =
+- { 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0d0 };
+-
+-static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
+-static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
+-
+-/* lock mask */
+-#define DIB3000MC_REG_LOCK_MASK ( 15)
+-#define DIB3000MC_ACTIVATE_LOCK_MASK (0x0800)
+-
+-/* reset the uncorrected packet count (??? do it 5 times) */
+-#define DIB3000MC_REG_RST_UNC ( 18)
+-#define DIB3000MC_RST_UNC_ON ( 1)
+-#define DIB3000MC_RST_UNC_OFF ( 0)
+-
+-#define DIB3000MC_REG_UNK_19 ( 19)
+-#define DIB3000MC_UNK_19 ( 0)
+-
+-/* DDS frequency value (IF position) and inversion bit */
+-#define DIB3000MC_REG_INVERSION ( 21)
+-#define DIB3000MC_REG_SET_DDS_FREQ_MSB ( 21)
+-#define DIB3000MC_DDS_FREQ_MSB_INV_OFF (0x0164)
+-#define DIB3000MC_DDS_FREQ_MSB_INV_ON (0x0364)
+-
+-#define DIB3000MC_REG_SET_DDS_FREQ_LSB ( 22)
+-#define DIB3000MC_DDS_FREQ_LSB (0x463d)
+-
+-/* timing frequencies setting */
+-#define DIB3000MC_REG_TIMING_FREQ_MSB ( 23)
+-#define DIB3000MC_REG_TIMING_FREQ_LSB ( 24)
+-#define DIB3000MC_CLOCK_REF (0x151fd1)
+-
+-//static u16 dib3000mc_reg_timing_freq[] = { 23,24 };
+-
+-//static u16 dib3000mc_timing_freq[][2] = {
+-// { 0x69, 0x9f18 }, /* 5 MHz */
+-// { 0x7e ,0xbee9 }, /* 6 MHz */
+-// { 0x93 ,0xdebb }, /* 7 MHz */
+-// { 0xa8 ,0xfe8c }, /* 8 MHz */
+-//};
+-
+-/* timeout ??? */
+-static u16 dib3000mc_reg_offset[] = { 26,33 };
+-
+-static u16 dib3000mc_offset[][2] = {
+- { 26240, 5 }, /* default */
+- { 30336, 6 }, /* 8K */
+- { 38528, 8 }, /* 2K */
+-};
+-
+-#define DIB3000MC_REG_ISI ( 29)
+-#define DIB3000MC_ISI_DEFAULT (0x1073)
+-#define DIB3000MC_ISI_ACTIVATE (0x0000)
+-#define DIB3000MC_ISI_INHIBIT (0x0200)
+-
+-/* impulse noise control */
+-static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
+-
+-static u16 dib3000mc_imp_noise_ctl[][2] = {
+- { 0x1294, 0x1ff8 }, /* mode 0 */
+- { 0x1294, 0x1ff8 }, /* mode 1 */
+- { 0x1294, 0x1ff8 }, /* mode 2 */
+- { 0x1294, 0x1ff8 }, /* mode 3 */
+- { 0x1294, 0x1ff8 }, /* mode 4 */
+-};
+-
+-/* AGC registers */
+-static u16 dib3000mc_reg_agc[] = {
+- 36,37,38,39,42,43,44,45,46,47,48,49
+-};
+-
+-static u16 dib3000mc_agc_tuner[][12] = {
+- { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666,
+- 0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019
+- }, /* TUNER_PANASONIC_ENV77H04D5, */
+-
+- { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a,
+- 0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e
+- }, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */
+-
+- { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff,
+- 0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040
+- }, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */
+-
+- { 0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29,
+- 0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537
+- }, /* TUNER_PROVIDER_X */
+- /* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */
+-};
+-
+-/* AGC loop bandwidth */
+-static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 };
+-static u16 dib3000mc_agc_bandwidth[] = { 0x119,0x330 };
+-
+-static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 };
+-static u16 dib3000mc_agc_bandwidth_general[] =
+- { 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
+-
+-#define DIB3000MC_REG_IMP_NOISE_55 ( 55)
+-#define DIB3000MC_IMP_NEW_ALGO(w) (w | (1<<10))
+-
+-/* Impulse noise params */
+-static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 };
+-static u16 dib3000mc_impluse_noise[][3] = {
+- { 0x489, 0x89, 0x72 }, /* 5 MHz */
+- { 0x4a5, 0xa5, 0x89 }, /* 6 MHz */
+- { 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */
+- { 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */
+-};
+-
+-static u16 dib3000mc_reg_fft[] = {
+- 58,59,60,61,62,63,64,65,66,67,68,69,
+- 70,71,72,73,74,75,76,77,78,79,80,81,
+- 82,83,84,85,86
+-};
+-
+-static u16 dib3000mc_fft_modes[][29] = {
+- { 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
+- 0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
+- 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
+- 0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+- 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0, 0xd
+- }, /* fft mode 0 */
+- { 0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
+- 0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
+- 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
+- 0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+- 0x3ffe, 0x5b3, 0x3feb, 0x0, 0x8200, 0xd
+- }, /* fft mode 1 */
+-};
+-
+-#define DIB3000MC_REG_UNK_88 ( 88)
+-#define DIB3000MC_UNK_88 (0x0410)
+-
+-static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 };
+-static u16 dib3000mc_bw[][6] = {
+- { 0,0,0,0,0,0 }, /* 5 MHz */
+- { 0,0,0,0,0,0 }, /* 6 MHz */
+- { 0,0,0,0,0,0 }, /* 7 MHz */
+- { 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */
+-};
+-
+-
+-/* phase noise control */
+-#define DIB3000MC_REG_UNK_99 ( 99)
+-#define DIB3000MC_UNK_99 (0x0220)
+-
+-#define DIB3000MC_REG_SCAN_BOOST ( 100)
+-#define DIB3000MC_SCAN_BOOST_ON ((11 << 6) + 6)
+-#define DIB3000MC_SCAN_BOOST_OFF ((16 << 6) + 9)
+-
+-/* timeout ??? */
+-#define DIB3000MC_REG_UNK_110 ( 110)
+-#define DIB3000MC_UNK_110 ( 3277)
+-
+-#define DIB3000MC_REG_UNK_111 ( 111)
+-#define DIB3000MC_UNK_111_PH_N_MODE_0 ( 0)
+-#define DIB3000MC_UNK_111_PH_N_MODE_1 (1 << 1)
+-
+-/* superious rm config */
+-#define DIB3000MC_REG_UNK_120 ( 120)
+-#define DIB3000MC_UNK_120 ( 8207)
+-
+-#define DIB3000MC_REG_UNK_133 ( 133)
+-#define DIB3000MC_UNK_133 ( 15564)
+-
+-#define DIB3000MC_REG_UNK_134 ( 134)
+-#define DIB3000MC_UNK_134 ( 0)
+-
+-/* adapter config for constellation */
+-static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 };
+-
+-static u16 dib3000mc_adp_cfg[][4] = {
+- { 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK */
+- { 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */
+- { 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */
+-};
+-
+-static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 };
+-
+-static u16 dib3000mc_mobile_mode[][5] = {
+- { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */
+- { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */
+- { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */
+- { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */
+-};
+-
+-#define DIB3000MC_REG_DIVERSITY1 ( 177)
+-#define DIB3000MC_DIVERSITY1_DEFAULT ( 1)
+-
+-#define DIB3000MC_REG_DIVERSITY2 ( 178)
+-#define DIB3000MC_DIVERSITY2_DEFAULT ( 1)
+-
+-#define DIB3000MC_REG_DIVERSITY3 ( 180)
+-#define DIB3000MC_DIVERSITY3_IN_OFF (0xfff0)
+-#define DIB3000MC_DIVERSITY3_IN_ON (0xfff6)
+-
+-#define DIB3000MC_REG_FEC_CFG ( 195)
+-#define DIB3000MC_FEC_CFG ( 0x10)
+-
+-/*
+- * reg 206, output mode
+- * 1111 1111
+- * |||| ||||
+- * |||| |||+- unk
+- * |||| ||+-- unk
+- * |||| |+--- unk (on by default)
+- * |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed))
+- * |||+------ pid_parse (1 = enabled, 0 = disabled)
+- * ||+------- outp_188 (1 = TS packet size 188, 0 = packet size 204)
+- * |+-------- unk
+- * +--------- unk
+- */
+-
+-#define DIB3000MC_REG_SMO_MODE ( 206)
+-#define DIB3000MC_SMO_MODE_DEFAULT (1 << 2)
+-#define DIB3000MC_SMO_MODE_FIFO_FLUSH (1 << 3)
+-#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH (0xfff7)
+-#define DIB3000MC_SMO_MODE_PID_PARSE (1 << 4)
+-#define DIB3000MC_SMO_MODE_NO_PID_PARSE (0xffef)
+-#define DIB3000MC_SMO_MODE_188 (1 << 5)
+-#define DIB3000MC_SMO_MODE_SLAVE (DIB3000MC_SMO_MODE_DEFAULT | \
+- DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
+-
+-#define DIB3000MC_REG_FIFO_THRESHOLD ( 207)
+-#define DIB3000MC_FIFO_THRESHOLD_DEFAULT ( 1792)
+-#define DIB3000MC_FIFO_THRESHOLD_SLAVE ( 512)
+-/*
+- * pidfilter
+- * it is not a hardware pidfilter but a filter which drops all pids
+- * except the ones set. When connected to USB1.1 bandwidth this is important.
+- * DiB3000P/M-C can filter up to 32 PIDs
+- */
+-#define DIB3000MC_REG_FIRST_PID ( 212)
+-#define DIB3000MC_NUM_PIDS ( 32)
+-
+-#define DIB3000MC_REG_OUTMODE ( 244)
+-#define DIB3000MC_OM_PARALLEL_GATED_CLK ( 0)
+-#define DIB3000MC_OM_PAR_CONT_CLK (1 << 11)
+-#define DIB3000MC_OM_SERIAL (2 << 11)
+-#define DIB3000MC_OM_DIVOUT_ON (4 << 11)
+-#define DIB3000MC_OM_SLAVE (DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK)
+-
+-#define DIB3000MC_REG_RF_POWER ( 392)
+-
+-#define DIB3000MC_REG_FFT_POSITION ( 407)
+-
+-#define DIB3000MC_REG_DDS_FREQ_MSB ( 414)
+-#define DIB3000MC_REG_DDS_FREQ_LSB ( 415)
+-
+-#define DIB3000MC_REG_TIMING_OFFS_MSB ( 416)
+-#define DIB3000MC_REG_TIMING_OFFS_LSB ( 417)
+-
+-#define DIB3000MC_REG_TUNING_PARM ( 458)
+-#define DIB3000MC_TP_QAM(v) ((v >> 13) & 0x03)
+-#define DIB3000MC_TP_HRCH(v) ((v >> 12) & 0x01)
+-#define DIB3000MC_TP_ALPHA(v) ((v >> 9) & 0x07)
+-#define DIB3000MC_TP_FFT(v) ((v >> 8) & 0x01)
+-#define DIB3000MC_TP_FEC_CR_HP(v) ((v >> 5) & 0x07)
+-#define DIB3000MC_TP_FEC_CR_LP(v) ((v >> 2) & 0x07)
+-#define DIB3000MC_TP_GUARD(v) (v & 0x03)
+-
+-#define DIB3000MC_REG_SIGNAL_NOISE_MSB ( 483)
+-#define DIB3000MC_REG_SIGNAL_NOISE_LSB ( 484)
+-
+-#define DIB3000MC_REG_MER ( 485)
+-
+-#define DIB3000MC_REG_BER_MSB ( 500)
+-#define DIB3000MC_REG_BER_LSB ( 501)
+-
+-#define DIB3000MC_REG_PACKET_ERRORS ( 503)
+-
+-#define DIB3000MC_REG_PACKET_ERROR_COUNT ( 506)
+-
+-#define DIB3000MC_REG_LOCK_507 ( 507)
+-#define DIB3000MC_LOCK_507 (0x0002) // ? name correct ?
+-
+-#define DIB3000MC_REG_LOCKING ( 509)
+-#define DIB3000MC_AGC_LOCK(v) (v & 0x8000)
+-#define DIB3000MC_CARRIER_LOCK(v) (v & 0x2000)
+-#define DIB3000MC_MPEG_SYNC_LOCK(v) (v & 0x0080)
+-#define DIB3000MC_MPEG_DATA_LOCK(v) (v & 0x0040)
+-#define DIB3000MC_TPS_LOCK(v) (v & 0x0004)
+-
+-#define DIB3000MC_REG_AS_IRQ ( 511)
+-#define DIB3000MC_AS_IRQ_SUCCESS (1 << 1)
+-#define DIB3000MC_AS_IRQ_FAIL ( 1)
+-
+-#define DIB3000MC_REG_TUNER ( 769)
+-
+-#define DIB3000MC_REG_RST_I2C_ADDR ( 1024)
+-#define DIB3000MC_DEMOD_ADDR_ON ( 1)
+-#define DIB3000MC_DEMOD_ADDR(a) ((a << 4) & 0x03F0)
+-
+-#define DIB3000MC_REG_RESTART ( 1027)
+-#define DIB3000MC_RESTART_OFF (0x0000)
+-#define DIB3000MC_RESTART_AGC (0x0800)
+-#define DIB3000MC_RESTART_CONFIG (0x8000)
+-
+-#define DIB3000MC_REG_RESTART_VIT ( 1028)
+-#define DIB3000MC_RESTART_VIT_OFF ( 0)
+-#define DIB3000MC_RESTART_VIT_ON ( 1)
+-
+-#define DIB3000MC_REG_CLK_CFG_1 ( 1031)
+-#define DIB3000MC_CLK_CFG_1_POWER_UP ( 0)
+-#define DIB3000MC_CLK_CFG_1_POWER_DOWN (0xffff)
+-
+-#define DIB3000MC_REG_CLK_CFG_2 ( 1032)
+-#define DIB3000MC_CLK_CFG_2_PUP_FIXED (0x012c)
+-#define DIB3000MC_CLK_CFG_2_PUP_PORT (0x0104)
+-#define DIB3000MC_CLK_CFG_2_PUP_MOBILE (0x0000)
+-#define DIB3000MC_CLK_CFG_2_POWER_DOWN (0xffff)
+-
+-#define DIB3000MC_REG_CLK_CFG_3 ( 1033)
+-#define DIB3000MC_CLK_CFG_3_POWER_UP ( 0)
+-#define DIB3000MC_CLK_CFG_3_POWER_DOWN (0xfff5)
+-
+-#define DIB3000MC_REG_CLK_CFG_7 ( 1037)
+-#define DIB3000MC_CLK_CFG_7_INIT ( 12592)
+-#define DIB3000MC_CLK_CFG_7_POWER_UP (~0x0003)
+-#define DIB3000MC_CLK_CFG_7_PWR_DOWN (0x0003)
+-#define DIB3000MC_CLK_CFG_7_DIV_IN_OFF (1 << 8)
+-
+-/* was commented out ??? */
+-#define DIB3000MC_REG_CLK_CFG_8 ( 1038)
+-#define DIB3000MC_CLK_CFG_8_POWER_UP (0x160c)
+-
+-#define DIB3000MC_REG_CLK_CFG_9 ( 1039)
+-#define DIB3000MC_CLK_CFG_9_POWER_UP ( 0)
+-
+-/* also clock ??? */
+-#define DIB3000MC_REG_ELEC_OUT ( 1040)
+-#define DIB3000MC_ELEC_OUT_HIGH_Z ( 0)
+-#define DIB3000MC_ELEC_OUT_DIV_OUT_ON ( 1)
+-#define DIB3000MC_ELEC_OUT_SLAVE ( 3)
+-
+-#endif
+diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
+new file mode 100644
+index 0000000..a18c8f4
+--- /dev/null
++++ b/drivers/media/dvb/frontends/dibx000_common.c
+@@ -0,0 +1,152 @@
++#include <linux/i2c.h>
++
++#include "dibx000_common.h"
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
++
++#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0)
++
++static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
++{
++ u8 b[4] = {
++ (reg >> 8) & 0xff, reg & 0xff,
++ (val >> 8) & 0xff, val & 0xff,
++ };
++ struct i2c_msg msg = {
++ .addr = mst->i2c_addr, .flags = 0, .buf = b, .len = 4
++ };
++ return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
++}
++
++
++static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf)
++{
++ if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
++ dprintk("selecting interface: %d\n",intf);
++ mst->selected_interface = intf;
++ return dibx000_write_word(mst, mst->base_reg + 4, intf);
++ }
++ return 0;
++}
++
++static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 addr, int onoff)
++{
++ u16 val;
++
++
++ if (onoff)
++ val = addr << 8; // bit 7 = use master or not, if 0, the gate is open
++ else
++ val = 1 << 7;
++
++ if (mst->device_rev > DIB7000)
++ val <<= 1;
++
++ tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
++ tx[1] = ( (mst->base_reg + 1) & 0xff);
++ tx[2] = val >> 8;
++ tx[3] = val & 0xff;
++
++ return 0;
++}
++
++static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
++{
++ return I2C_FUNC_I2C;
++}
++
++static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
++{
++ struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++ struct i2c_msg m[2 + num];
++ u8 tx_open[4], tx_close[4];
++
++ memset(m,0, sizeof(struct i2c_msg) * (2 + num));
++
++ dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
++
++ dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
++ m[0].addr = mst->i2c_addr;
++ m[0].buf = tx_open;
++ m[0].len = 4;
++
++ memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
++
++ dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
++ m[num+1].addr = mst->i2c_addr;
++ m[num+1].buf = tx_close;
++ m[num+1].len = 4;
++
++ return i2c_transfer(mst->i2c_adap, m, 2+num) == 2 + num ? num : -EIO;
++}
++
++static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
++ .master_xfer = dibx000_i2c_gated_tuner_xfer,
++ .functionality = dibx000_i2c_func,
++};
++
++struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating)
++{
++ struct i2c_adapter *i2c = NULL;
++
++ switch (intf) {
++ case DIBX000_I2C_INTERFACE_TUNER:
++ if (gating)
++ i2c = &mst->gated_tuner_i2c_adap;
++ break;
++ default:
++ printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
++ break;
++ }
++
++ return i2c;
++}
++EXPORT_SYMBOL(dibx000_get_i2c_adapter);
++
++static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst)
++{
++ strncpy(i2c_adap->name, name, I2C_NAME_SIZE);
++ i2c_adap->class = I2C_CLASS_TV_DIGITAL,
++ i2c_adap->algo = algo;
++ i2c_adap->algo_data = NULL;
++ i2c_set_adapdata(i2c_adap, mst);
++ if (i2c_add_adapter(i2c_adap) < 0)
++ return -ENODEV;
++ return 0;
++}
++
++int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr)
++{
++ u8 tx[4];
++ struct i2c_msg m = { .addr = i2c_addr >> 1, .buf = tx, .len = 4 };
++
++ mst->device_rev = device_rev;
++ mst->i2c_adap = i2c_adap;
++ mst->i2c_addr = i2c_addr >> 1;
++
++ if (device_rev == DIB7000P)
++ mst->base_reg = 1024;
++ else
++ mst->base_reg = 768;
++
++ if (i2c_adapter_init(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0)
++ printk(KERN_ERR "DiBX000: could not initialize the tuner i2c_adapter\n");
++
++ /* initialize the i2c-master by closing the gate */
++ dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
++
++ return i2c_transfer(i2c_adap, &m, 1) == 1;
++}
++EXPORT_SYMBOL(dibx000_init_i2c_master);
++
++void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
++{
++ i2c_del_adapter(&mst->gated_tuner_i2c_adap);
++}
++EXPORT_SYMBOL(dibx000_exit_i2c_master);
++
++MODULE_AUTHOR("Patrick Boettcher <pboettcher at dibcom.fr>");
++MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
+new file mode 100644
+index 0000000..bb0c65f
+--- /dev/null
++++ b/drivers/media/dvb/frontends/dibx000_common.h
+@@ -0,0 +1,166 @@
++#ifndef DIBX000_COMMON_H
++#define DIBX000_COMMON_H
++
++enum dibx000_i2c_interface {
++ DIBX000_I2C_INTERFACE_TUNER = 0,
++ DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
++ DIBX000_I2C_INTERFACE_GPIO_3_4 = 2
++};
++
++struct dibx000_i2c_master {
++#define DIB3000MC 1
++#define DIB7000 2
++#define DIB7000P 11
++#define DIB7000MC 12
++ u16 device_rev;
++
++ enum dibx000_i2c_interface selected_interface;
++
++// struct i2c_adapter tuner_i2c_adap;
++ struct i2c_adapter gated_tuner_i2c_adap;
++
++ struct i2c_adapter *i2c_adap;
++ u8 i2c_addr;
++
++ u16 base_reg;
++};
++
++extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr);
++extern struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating);
++extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
++
++#define BAND_LBAND 0x01
++#define BAND_UHF 0x02
++#define BAND_VHF 0x04
++
++struct dibx000_agc_config {
++ /* defines the capabilities of this AGC-setting - using the BAND_-defines*/
++ u8 band_caps;
++
++ u16 setup;
++
++ u16 inv_gain;
++ u16 time_stabiliz;
++
++ u8 alpha_level;
++ u16 thlock;
++
++ u8 wbd_inv;
++ u16 wbd_ref;
++ u8 wbd_sel;
++ u8 wbd_alpha;
++
++ u16 agc1_max;
++ u16 agc1_min;
++ u16 agc2_max;
++ u16 agc2_min;
++
++ u8 agc1_pt1;
++ u8 agc1_pt2;
++ u8 agc1_pt3;
++
++ u8 agc1_slope1;
++ u8 agc1_slope2;
++
++ u8 agc2_pt1;
++ u8 agc2_pt2;
++
++ u8 agc2_slope1;
++ u8 agc2_slope2;
++
++ u8 alpha_mant;
++ u8 alpha_exp;
++
++ u8 beta_mant;
++ u8 beta_exp;
++
++ u8 perform_agc_softsplit;
++
++ struct {
++ u16 min;
++ u16 max;
++ u16 min_thres;
++ u16 max_thres;
++ } split;
++};
++
++struct dibx000_bandwidth_config {
++ u32 internal;
++ u32 sampling;
++
++ u8 pll_prediv;
++ u8 pll_ratio;
++ u8 pll_range;
++ u8 pll_reset;
++ u8 pll_bypass;
++
++ u8 enable_refdiv;
++ u8 bypclk_div;
++ u8 IO_CLK_en_core;
++ u8 ADClkSrc;
++ u8 modulo;
++
++ u16 sad_cfg;
++
++ u32 ifreq;
++ u32 timf;
++};
++
++enum dibx000_adc_states {
++ DIBX000_SLOW_ADC_ON = 0,
++ DIBX000_SLOW_ADC_OFF,
++ DIBX000_ADC_ON,
++ DIBX000_ADC_OFF,
++ DIBX000_VBG_ENABLE,
++ DIBX000_VBG_DISABLE,
++};
++
++#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
++ (v) == BANDWIDTH_7_MHZ ? 7000 : \
++ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 )
++
++/* Chip output mode. */
++#define OUTMODE_HIGH_Z 0
++#define OUTMODE_MPEG2_PAR_GATED_CLK 1
++#define OUTMODE_MPEG2_PAR_CONT_CLK 2
++#define OUTMODE_MPEG2_SERIAL 7
++#define OUTMODE_DIVERSITY 4
++#define OUTMODE_MPEG2_FIFO 5
++
++/* I hope I can get rid of the following kludge in the near future */
++struct dibx000_ofdm_channel {
++ u8 Bw;
++ s16 nfft;
++ s16 guard;
++ s16 nqam;
++ s16 vit_hrch;
++ s16 vit_select_hp;
++ s16 vit_alpha;
++ s16 vit_code_rate_hp;
++ s16 vit_code_rate_lp;
++};
++
++#define FEP2DIB(fep,ch) \
++ (ch)->Bw = (fep)->u.ofdm.bandwidth; \
++ (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
++ (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
++ (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
++ (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
++ (ch)->vit_select_hp = 1; \
++ (ch)->vit_alpha = 1; \
++ (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
++ (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP;
++
++#define INIT_OFDM_CHANNEL(ch) do {\
++ (ch)->Bw = 0; \
++ (ch)->nfft = -1; \
++ (ch)->guard = -1; \
++ (ch)->nqam = -1; \
++ (ch)->vit_hrch = -1; \
++ (ch)->vit_select_hp = -1; \
++ (ch)->vit_alpha = -1; \
++ (ch)->vit_code_rate_hp = -1; \
++ (ch)->vit_code_rate_lp = -1; \
++} while (0)
++
++#endif
+diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
+index 2be33f2..b7e7108 100644
+--- a/drivers/media/dvb/frontends/dvb-pll.c
++++ b/drivers/media/dvb/frontends/dvb-pll.c
+@@ -493,6 +493,9 @@ static int dvb_pll_sleep(struct dvb_fron
+ int i;
+ int result;
+
++ if (priv->i2c == NULL)
++ return -EINVAL;
++
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (priv->pll_desc->entries[i].limit == 0)
+ break;
+@@ -611,7 +614,7 @@ static struct dvb_tuner_ops dvb_pll_tune
+ .get_bandwidth = dvb_pll_get_bandwidth,
+ };
+
+-int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
++struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+ {
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 };
+@@ -624,14 +627,14 @@ int dvb_pll_attach(struct dvb_frontend *
+
+ ret = i2c_transfer (i2c, &msg, 1);
+ if (ret != 1)
+- return -1;
++ return NULL;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+ if (priv == NULL)
+- return -ENOMEM;
++ return NULL;
+
+ priv->pll_i2c_address = pll_addr;
+ priv->i2c = i2c;
+@@ -643,7 +646,7 @@ int dvb_pll_attach(struct dvb_frontend *
+ fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+ fe->tuner_priv = priv;
+- return 0;
++ return fe;
+ }
+ EXPORT_SYMBOL(dvb_pll_attach);
+
+diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
+index 66361cd..ed5ac5a 100644
+--- a/drivers/media/dvb/frontends/dvb-pll.h
++++ b/drivers/media/dvb/frontends/dvb-pll.h
+@@ -57,8 +57,8 @@ extern int dvb_pll_configure(struct dvb_
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+- * @return 0 on success, nonzero on failure.
++ * @return Frontend pointer on success, NULL on failure
+ */
+-extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
++extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
+ #endif
+diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
+index 58c34db..ef31936 100644
+--- a/drivers/media/dvb/frontends/isl6421.c
++++ b/drivers/media/dvb/frontends/isl6421.c
+@@ -42,12 +42,11 @@ struct isl6421 {
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ u8 i2c_addr;
+- void (*release_chain)(struct dvb_frontend* fe);
+ };
+
+ static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+ {
+- struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
++ struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+@@ -75,7 +74,7 @@ static int isl6421_set_voltage(struct dv
+
+ static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+ {
+- struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
++ struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+@@ -93,31 +92,26 @@ static int isl6421_enable_high_lnb_volta
+
+ static void isl6421_release(struct dvb_frontend *fe)
+ {
+- struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+-
+ /* power off */
+ isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+- /* free data & call next release routine */
+- fe->ops.release = isl6421->release_chain;
+- kfree(fe->misc_priv);
+- fe->misc_priv = NULL;
+- if (fe->ops.release)
+- fe->ops.release(fe);
++ /* free */
++ kfree(fe->sec_priv);
++ fe->sec_priv = NULL;
+ }
+
+-int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
++struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+ {
+ struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+ if (!isl6421)
+- return -ENOMEM;
++ return NULL;
+
+ /* default configuration */
+ isl6421->config = ISL6421_ISEL1;
+ isl6421->i2c = i2c;
+ isl6421->i2c_addr = i2c_addr;
+- fe->misc_priv = isl6421;
++ fe->sec_priv = isl6421;
+
+ /* bits which should be forced to '1' */
+ isl6421->override_or = override_set;
+@@ -128,19 +122,17 @@ int isl6421_attach(struct dvb_frontend *
+ /* detect if it is present or not */
+ if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(isl6421);
+- fe->misc_priv = NULL;
+- return -EIO;
++ return NULL;
+ }
+
+ /* install release callback */
+- isl6421->release_chain = fe->ops.release;
+- fe->ops.release = isl6421_release;
++ fe->ops.release_sec = isl6421_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = isl6421_set_voltage;
+ fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+- return 0;
++ return fe;
+ }
+ EXPORT_SYMBOL(isl6421_attach);
+
+diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
+index 675f80a..ea7f78a 100644
+--- a/drivers/media/dvb/frontends/isl6421.h
++++ b/drivers/media/dvb/frontends/isl6421.h
+@@ -39,8 +39,17 @@
+ #define ISL6421_ISEL1 0x20
+ #define ISL6421_DCL 0x40
+
++#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE))
+ /* override_set and override_clear control which system register bits (above) to always set & clear */
+-extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
++extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear);
++#else
++static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
++ u8 override_set, u8 override_clear)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_ISL6421
+
+ #endif
+diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
+index 83b8bc2..cd15f76 100644
+--- a/drivers/media/dvb/frontends/l64781.h
++++ b/drivers/media/dvb/frontends/l64781.h
+@@ -31,8 +31,16 @@ struct l64781_config
+ u8 demod_address;
+ };
+
+-
++#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_L64781
+
+ #endif // L64781_H
+diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
+index bad903c..9950590 100644
+--- a/drivers/media/dvb/frontends/lgdt330x.h
++++ b/drivers/media/dvb/frontends/lgdt330x.h
+@@ -52,8 +52,17 @@ struct lgdt330x_config
+ int clock_polarity_flip;
+ };
+
++#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_LGDT330X
+
+ #endif /* LGDT330X_H */
+
+diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
+index e933edc..2d2f58c 100644
+--- a/drivers/media/dvb/frontends/lnbp21.c
++++ b/drivers/media/dvb/frontends/lnbp21.c
+@@ -40,12 +40,11 @@ struct lnbp21 {
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+- void (*release_chain)(struct dvb_frontend* fe);
+ };
+
+ static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+ {
+- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
++ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+@@ -73,7 +72,7 @@ static int lnbp21_set_voltage(struct dvb
+
+ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+ {
+- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
++ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+@@ -91,29 +90,24 @@ static int lnbp21_enable_high_lnb_voltag
+
+ static void lnbp21_release(struct dvb_frontend *fe)
+ {
+- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+-
+ /* LNBP power off */
+ lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+- /* free data & call next release routine */
+- fe->ops.release = lnbp21->release_chain;
+- kfree(fe->misc_priv);
+- fe->misc_priv = NULL;
+- if (fe->ops.release)
+- fe->ops.release(fe);
++ /* free data */
++ kfree(fe->sec_priv);
++ fe->sec_priv = NULL;
+ }
+
+-int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
++struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+ {
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+ if (!lnbp21)
+- return -ENOMEM;
++ return NULL;
+
+ /* default configuration */
+ lnbp21->config = LNBP21_ISEL;
+ lnbp21->i2c = i2c;
+- fe->misc_priv = lnbp21;
++ fe->sec_priv = lnbp21;
+
+ /* bits which should be forced to '1' */
+ lnbp21->override_or = override_set;
+@@ -124,19 +118,17 @@ int lnbp21_attach(struct dvb_frontend *f
+ /* detect if it is present or not */
+ if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(lnbp21);
+- fe->misc_priv = NULL;
+- return -EIO;
++ return NULL;
+ }
+
+ /* install release callback */
+- lnbp21->release_chain = fe->ops.release;
+- fe->ops.release = lnbp21_release;
++ fe->ops.release_sec = lnbp21_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = lnbp21_set_voltage;
+ fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+- return 0;
++ return fe;
+ }
+ EXPORT_SYMBOL(lnbp21_attach);
+
+diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
+index 047a4ab..68906ac 100644
+--- a/drivers/media/dvb/frontends/lnbp21.h
++++ b/drivers/media/dvb/frontends/lnbp21.h
+@@ -39,7 +39,15 @@
+
+ #include <linux/dvb/frontend.h>
+
++#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) && defined(MODULE))
+ /* override_set and override_clear control which system register bits (above) to always set & clear */
+-extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
++extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
++#else
++static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_LNBP21
+
+-#endif
++#endif // _LNBP21_H
+diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c
+new file mode 100644
+index 0000000..450fad8
+--- /dev/null
++++ b/drivers/media/dvb/frontends/mt2060.c
+@@ -0,0 +1,370 @@
++/*
++ * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
++ *
++ * Copyright (c) 2006 Olivier DANET <odanet at caramail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
++ */
++
++/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/delay.h>
++#include <linux/dvb/frontend.h>
++#include <linux/i2c.h>
++
++#include "dvb_frontend.h"
++
++#include "mt2060.h"
++#include "mt2060_priv.h"
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
++
++#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0)
++
++// Reads a single register
++static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
++{
++ struct i2c_msg msg[2] = {
++ { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 },
++ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
++ };
++
++ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
++ printk(KERN_WARNING "mt2060 I2C read failed\n");
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++// Writes a single register
++static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
++{
++ u8 buf[2] = { reg, val };
++ struct i2c_msg msg = {
++ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
++ };
++
++ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
++ printk(KERN_WARNING "mt2060 I2C write failed\n");
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++// Writes a set of consecutive registers
++static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
++{
++ struct i2c_msg msg = {
++ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
++ };
++ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
++ printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++// Initialisation sequences
++// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49
++static u8 mt2060_config1[] = {
++ REG_LO1C1,
++ 0x3F, 0x74, 0x00, 0x08, 0x93
++};
++
++// FMCG=2, GP2=0, GP1=0
++static u8 mt2060_config2[] = {
++ REG_MISC_CTRL,
++ 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42
++};
++
++// VGAG=3, V1CSE=1
++
++#ifdef MT2060_SPURCHECK
++/* The function below calculates the frequency offset between the output frequency if2
++ and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */
++static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2)
++{
++ int I,J;
++ int dia,diamin,diff;
++ diamin=1000000;
++ for (I = 1; I < 10; I++) {
++ J = ((2*I*lo1)/lo2+1)/2;
++ diff = I*(int)lo1-J*(int)lo2;
++ if (diff < 0) diff=-diff;
++ dia = (diff-(int)if2);
++ if (dia < 0) dia=-dia;
++ if (diamin > dia) diamin=dia;
++ }
++ return diamin;
++}
++
++#define BANDWIDTH 4000 // kHz
++
++/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */
++static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
++{
++ u32 Spur,Sp1,Sp2;
++ int I,J;
++ I=0;
++ J=1000;
++
++ Spur=mt2060_spurcalc(lo1,lo2,if2);
++ if (Spur < BANDWIDTH) {
++ /* Potential spurs detected */
++ dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)",
++ (int)lo1,(int)lo2);
++ I=1000;
++ Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2);
++ Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2);
++
++ if (Sp1 < Sp2) {
++ J=-J; I=-I; Spur=Sp2;
++ } else
++ Spur=Sp1;
++
++ while (Spur < BANDWIDTH) {
++ I += J;
++ Spur = mt2060_spurcalc(lo1+I,lo2+I,if2);
++ }
++ dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)",
++ (int)(lo1+I),(int)(lo2+I));
++ }
++ return I;
++}
++#endif
++
++#define IF2 36150 // IF2 frequency = 36.150 MHz
++#define FREF 16000 // Quartz oscillator 16 MHz
++
++static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
++{
++ struct mt2060_priv *priv;
++ int ret=0;
++ int i=0;
++ u32 freq;
++ u8 lnaband;
++ u32 f_lo1,f_lo2;
++ u32 div1,num1,div2,num2;
++ u8 b[8];
++ u32 if1;
++
++ priv = fe->tuner_priv;
++
++ if1 = priv->if1_freq;
++ b[0] = REG_LO1B1;
++ b[1] = 0xFF;
++
++ mt2060_writeregs(priv,b,2);
++
++ freq = params->frequency / 1000; // Hz -> kHz
++ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
++
++ f_lo1 = freq + if1 * 1000;
++ f_lo1 = (f_lo1 / 250) * 250;
++ f_lo2 = f_lo1 - freq - IF2;
++ // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise
++ f_lo2 = ((f_lo2 + 25) / 50) * 50;
++ priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000,
++
++#ifdef MT2060_SPURCHECK
++ // LO-related spurs detection and correction
++ num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2);
++ f_lo1 += num1;
++ f_lo2 += num1;
++#endif
++ //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 )
++ num1 = f_lo1 / (FREF / 64);
++ div1 = num1 / 64;
++ num1 &= 0x3f;
++
++ // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 )
++ num2 = f_lo2 * 64 / (FREF / 128);
++ div2 = num2 / 8192;
++ num2 &= 0x1fff;
++
++ if (freq <= 95000) lnaband = 0xB0; else
++ if (freq <= 180000) lnaband = 0xA0; else
++ if (freq <= 260000) lnaband = 0x90; else
++ if (freq <= 335000) lnaband = 0x80; else
++ if (freq <= 425000) lnaband = 0x70; else
++ if (freq <= 480000) lnaband = 0x60; else
++ if (freq <= 570000) lnaband = 0x50; else
++ if (freq <= 645000) lnaband = 0x40; else
++ if (freq <= 730000) lnaband = 0x30; else
++ if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10;
++
++ b[0] = REG_LO1C1;
++ b[1] = lnaband | ((num1 >>2) & 0x0F);
++ b[2] = div1;
++ b[3] = (num2 & 0x0F) | ((num1 & 3) << 4);
++ b[4] = num2 >> 4;
++ b[5] = ((num2 >>12) & 1) | (div2 << 1);
++
++ dprintk("IF1: %dMHz",(int)if1);
++ dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2);
++ dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2);
++ dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]);
++
++ mt2060_writeregs(priv,b,6);
++
++ //Waits for pll lock or timeout
++ i = 0;
++ do {
++ mt2060_readreg(priv,REG_LO_STATUS,b);
++ if ((b[0] & 0x88)==0x88)
++ break;
++ msleep(4);
++ i++;
++ } while (i<10);
++
++ return ret;
++}
++
++static void mt2060_calibrate(struct mt2060_priv *priv)
++{
++ u8 b = 0;
++ int i = 0;
++
++ if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1)))
++ return;
++ if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2)))
++ return;
++
++ /* initialize the clock output */
++ mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
++
++ do {
++ b |= (1 << 6); // FM1SS;
++ mt2060_writereg(priv, REG_LO2C1,b);
++ msleep(20);
++
++ if (i == 0) {
++ b |= (1 << 7); // FM1CA;
++ mt2060_writereg(priv, REG_LO2C1,b);
++ b &= ~(1 << 7); // FM1CA;
++ msleep(20);
++ }
++
++ b &= ~(1 << 6); // FM1SS
++ mt2060_writereg(priv, REG_LO2C1,b);
++
++ msleep(20);
++ i++;
++ } while (i < 9);
++
++ i = 0;
++ while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
++ msleep(20);
++
++ if (i < 10) {
++ mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
++ dprintk("calibration was successful: %d", (int)priv->fmfreq);
++ } else
++ dprintk("FMCAL timed out");
++}
++
++static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct mt2060_priv *priv = fe->tuner_priv;
++ *frequency = priv->frequency;
++ return 0;
++}
++
++static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
++{
++ struct mt2060_priv *priv = fe->tuner_priv;
++ *bandwidth = priv->bandwidth;
++ return 0;
++}
++
++static int mt2060_init(struct dvb_frontend *fe)
++{
++ struct mt2060_priv *priv = fe->tuner_priv;
++ return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
++}
++
++static int mt2060_sleep(struct dvb_frontend *fe)
++{
++ struct mt2060_priv *priv = fe->tuner_priv;
++ return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
++}
++
++static int mt2060_release(struct dvb_frontend *fe)
++{
++ kfree(fe->tuner_priv);
++ fe->tuner_priv = NULL;
++ return 0;
++}
++
++static const struct dvb_tuner_ops mt2060_tuner_ops = {
++ .info = {
++ .name = "Microtune MT2060",
++ .frequency_min = 48000000,
++ .frequency_max = 860000000,
++ .frequency_step = 50000,
++ },
++
++ .release = mt2060_release,
++
++ .init = mt2060_init,
++ .sleep = mt2060_sleep,
++
++ .set_params = mt2060_set_params,
++ .get_frequency = mt2060_get_frequency,
++ .get_bandwidth = mt2060_get_bandwidth
++};
++
++/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
++struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
++{
++ struct mt2060_priv *priv = NULL;
++ u8 id = 0;
++
++ priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL);
++ if (priv == NULL)
++ return NULL;
++
++ priv->cfg = cfg;
++ priv->i2c = i2c;
++ priv->if1_freq = if1;
++
++ if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
++ kfree(priv);
++ return NULL;
++ }
++
++ if (id != PART_REV) {
++ kfree(priv);
++ return NULL;
++ }
++ printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1);
++ memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops));
++
++ fe->tuner_priv = priv;
++
++ mt2060_calibrate(priv);
++
++ return fe;
++}
++EXPORT_SYMBOL(mt2060_attach);
++
++MODULE_AUTHOR("Olivier DANET");
++MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/dvb/frontends/mt2060.h
+new file mode 100644
+index 0000000..0a86eab
+--- /dev/null
++++ b/drivers/media/dvb/frontends/mt2060.h
+@@ -0,0 +1,43 @@
++/*
++ * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
++ *
++ * Copyright (c) 2006 Olivier DANET <odanet at caramail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
++ */
++
++#ifndef MT2060_H
++#define MT2060_H
++
++struct dvb_frontend;
++struct i2c_adapter;
++
++struct mt2060_config {
++ u8 i2c_address;
++ u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
++};
++
++#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE))
++extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
++#else
++static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TUNER_MT2060
++
++#endif
+diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/dvb/frontends/mt2060_priv.h
+new file mode 100644
+index 0000000..5eaccde
+--- /dev/null
++++ b/drivers/media/dvb/frontends/mt2060_priv.h
+@@ -0,0 +1,105 @@
++/*
++ * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
++ *
++ * Copyright (c) 2006 Olivier DANET <odanet at caramail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
++ */
++
++#ifndef MT2060_PRIV_H
++#define MT2060_PRIV_H
++
++// Uncomment the #define below to enable spurs checking. The results where quite unconvincing.
++// #define MT2060_SPURCHECK
++
++/* This driver is based on the information available in the datasheet of the
++ "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map :
++
++ I2C Address : 0x60
++
++ Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults )
++ --------------------------------------------------------------------------------
++ 00 | [ PART ] | [ REV ] | R = 0x63
++ 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F
++ 02 | [ DIV1 ] | RW = 0x74
++ 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00
++ 04 | NUM2(11:4) ] | RW = 0x08
++ 05 | [ DIV2 ] |NUM2(12)| RW = 0x93
++ 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R
++ 07 | [ FMF ] | R
++ 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R
++ 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20
++ 0A | ??
++ 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30
++ 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF
++ 0D | 1 | 0 | [ V1CS ] | RW = 0xB0
++ 0E | ??
++ 0F | ??
++ 10 | ??
++ 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42
++
++ PART : Part code : 6 for MT2060
++ REV : Revision code : 3 for current revision
++ LNABAND : Input frequency range : ( See code for details )
++ NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details )
++ FM1CA : Calibration Start Bit
++ FM1SS : Calibration Single Step bit
++ L1LK : LO1 Lock Detect
++ TAD1 : Tune Line ADC ( ? )
++ L2LK : LO2 Lock Detect
++ TAD2 : Tune Line ADC ( ? )
++ FMF : Estimated first IF Center frequency Offset ( ? )
++ FM1CAL : Calibration done bit
++ TEMP : On chip temperature sensor
++ FMCG : Mixer 1 Cap Gain ( ? )
++ GP01 / GP02 : Programmable digital outputs. Unconnected pins ?
++ V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? )
++ V1CS : LO1 Capacitor Selection Value ( ? )
++ LOTO : LO Timeout ( ? )
++ VGAG : Tuner Output gain
++*/
++
++#define I2C_ADDRESS 0x60
++
++#define REG_PART_REV 0
++#define REG_LO1C1 1
++#define REG_LO1C2 2
++#define REG_LO2C1 3
++#define REG_LO2C2 4
++#define REG_LO2C3 5
++#define REG_LO_STATUS 6
++#define REG_FM_FREQ 7
++#define REG_MISC_STAT 8
++#define REG_MISC_CTRL 9
++#define REG_RESERVED_A 0x0A
++#define REG_VGAG 0x0B
++#define REG_LO1B1 0x0C
++#define REG_LO1B2 0x0D
++#define REG_LOTO 0x11
++
++#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips
++
++struct mt2060_priv {
++ struct mt2060_config *cfg;
++ struct i2c_adapter *i2c;
++
++ u32 frequency;
++ u32 bandwidth;
++ u16 if1_freq;
++ u8 fmfreq;
++};
++
++#endif
+diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
+index 666a1bd..cf9a150 100644
+--- a/drivers/media/dvb/frontends/mt312.h
++++ b/drivers/media/dvb/frontends/mt312.h
+@@ -34,8 +34,16 @@ struct mt312_config
+ u8 demod_address;
+ };
+
++#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
+ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+ struct i2c_adapter* i2c);
+-
++#else
++static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_MT312
+
+ #endif // MT312_H
+diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
+index 5de7376..87e31ca 100644
+--- a/drivers/media/dvb/frontends/mt352.c
++++ b/drivers/media/dvb/frontends/mt352.c
+@@ -70,7 +70,7 @@ static int mt352_single_write(struct dvb
+ return 0;
+ }
+
+-int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
++static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+ {
+ int err,i;
+ for (i=0; i < ilen-1; i++)
+@@ -107,7 +107,7 @@ static int mt352_sleep(struct dvb_fronte
+ {
+ static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
+
+- mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
++ _mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
+ return 0;
+ }
+
+@@ -293,14 +293,14 @@ static int mt352_set_parameters(struct d
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+- mt352_write(fe, buf, 8);
+- mt352_write(fe, fsm_go, 2);
++ _mt352_write(fe, buf, 8);
++ _mt352_write(fe, fsm_go, 2);
+ } else {
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+ buf[8] <<= 1;
+- mt352_write(fe, buf, sizeof(buf));
+- mt352_write(fe, tuner_go, 2);
++ _mt352_write(fe, buf, sizeof(buf));
++ _mt352_write(fe, tuner_go, 2);
+ }
+ }
+
+@@ -522,7 +522,7 @@ static int mt352_init(struct dvb_fronten
+ (mt352_read_register(state, CONFIG) & 0x20) == 0) {
+
+ /* Do a "hard" reset */
+- mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
++ _mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
+ return state->config.demod_init(fe);
+ }
+
+@@ -585,6 +585,7 @@ static struct dvb_frontend_ops mt352_ops
+
+ .init = mt352_init,
+ .sleep = mt352_sleep,
++ .write = _mt352_write,
+
+ .set_frontend = mt352_set_parameters,
+ .get_frontend = mt352_get_parameters,
+@@ -605,4 +606,3 @@ MODULE_AUTHOR("Holger Waechtler, Daniel
+ MODULE_LICENSE("GPL");
+
+ EXPORT_SYMBOL(mt352_attach);
+-EXPORT_SYMBOL(mt352_write);
+diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
+index 9e7ff4b..e996408 100644
+--- a/drivers/media/dvb/frontends/mt352.h
++++ b/drivers/media/dvb/frontends/mt352.h
+@@ -51,9 +51,23 @@ struct mt352_config
+ int (*demod_init)(struct dvb_frontend* fe);
+ };
+
++#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_MT352
+
+-extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
++static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
++ int r = 0;
++ if (fe->ops.write)
++ r = fe->ops.write(fe, buf, len);
++ return r;
++}
+
+ #endif // MT352_H
+diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
+index 34d6173..28bc559 100644
+--- a/drivers/media/dvb/frontends/nxt200x.h
++++ b/drivers/media/dvb/frontends/nxt200x.h
+@@ -45,8 +45,17 @@ struct nxt200x_config
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+ };
+
++#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_NXT200X
+
+ #endif /* NXT200X_H */
+
+diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
+index 117031d..13d2251 100644
+--- a/drivers/media/dvb/frontends/nxt6000.h
++++ b/drivers/media/dvb/frontends/nxt6000.h
+@@ -33,7 +33,16 @@ struct nxt6000_config
+ u8 clock_inversion:1;
+ };
+
++#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_NXT6000
+
+ #endif // NXT6000_H
+diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
+index 8965888..add24f0 100644
+--- a/drivers/media/dvb/frontends/or51132.h
++++ b/drivers/media/dvb/frontends/or51132.h
+@@ -34,8 +34,17 @@ struct or51132_config
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+ };
+
++#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_OR51132
+
+ #endif // OR51132_H
+
+diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
+index 13a5a3a..8aad840 100644
+--- a/drivers/media/dvb/frontends/or51211.h
++++ b/drivers/media/dvb/frontends/or51211.h
+@@ -37,8 +37,17 @@ struct or51211_config
+ void (*sleep)(struct dvb_frontend * fe);
+ };
+
++#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_OR51211
+
+ #endif // OR51211_H
+
+diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
+index 4e39015..1555870 100644
+--- a/drivers/media/dvb/frontends/s5h1420.h
++++ b/drivers/media/dvb/frontends/s5h1420.h
+@@ -34,7 +34,16 @@ struct s5h1420_config
+ u8 invert:1;
+ };
+
++#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_S5H1420
+
+ #endif // S5H1420_H
+diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
+index 93afbb9..909cefe 100644
+--- a/drivers/media/dvb/frontends/sp8870.h
++++ b/drivers/media/dvb/frontends/sp8870.h
+@@ -35,7 +35,16 @@ struct sp8870_config
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+ };
+
++#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_SP8870
+
+ #endif // SP8870_H
+diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
+index c44b0eb..7ee78d7 100644
+--- a/drivers/media/dvb/frontends/sp887x.h
++++ b/drivers/media/dvb/frontends/sp887x.h
+@@ -17,7 +17,16 @@ struct sp887x_config
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+ };
+
++#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_SP887X
+
+ #endif // SP887X_H
+diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
+index 1da5384..69f4515 100644
+--- a/drivers/media/dvb/frontends/stv0297.h
++++ b/drivers/media/dvb/frontends/stv0297.h
+@@ -42,7 +42,16 @@ struct stv0297_config
+ u8 stop_during_read:1;
+ };
+
++#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_STV0297
+
+ #endif // STV0297_H
+diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
+index 96648a7..9348376 100644
+--- a/drivers/media/dvb/frontends/stv0299.c
++++ b/drivers/media/dvb/frontends/stv0299.c
+@@ -92,11 +92,14 @@ static int stv0299_writeregI (struct stv
+ return (ret != 1) ? -EREMOTEIO : 0;
+ }
+
+-int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
++int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+ {
+ struct stv0299_state* state = fe->demodulator_priv;
+
+- return stv0299_writeregI(state, reg, data);
++ if (len != 2)
++ return -EINVAL;
++
++ return stv0299_writeregI(state, buf[0], buf[1]);
+ }
+
+ static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
+@@ -694,6 +697,7 @@ static struct dvb_frontend_ops stv0299_o
+
+ .init = stv0299_init,
+ .sleep = stv0299_sleep,
++ .write = stv0299_write,
+ .i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
+
+ .set_frontend = stv0299_set_frontend,
+@@ -724,5 +728,4 @@ MODULE_AUTHOR("Ralph Metzler, Holger Wae
+ "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
+ MODULE_LICENSE("GPL");
+
+-EXPORT_SYMBOL(stv0299_writereg);
+ EXPORT_SYMBOL(stv0299_attach);
+diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
+index 1504828..33df949 100644
+--- a/drivers/media/dvb/frontends/stv0299.h
++++ b/drivers/media/dvb/frontends/stv0299.h
+@@ -89,9 +89,24 @@ struct stv0299_config
+ int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
+ };
+
+-extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+-
++#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_STV0299
++
++static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
++ int r = 0;
++ u8 buf[] = {reg, val};
++ if (fe->ops.write)
++ r = fe->ops.write(fe, buf, 2);
++ return r;
++}
+
+ #endif // STV0299_H
+diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
+index 9cbd164..dca8917 100644
+--- a/drivers/media/dvb/frontends/tda10021.c
++++ b/drivers/media/dvb/frontends/tda10021.c
+@@ -72,7 +72,7 @@ static u8 tda10021_inittab[0x40]=
+ 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
+ };
+
+-static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
++static int _tda10021_writereg (struct tda10021_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 };
+@@ -88,14 +88,6 @@ static int tda10021_writereg (struct tda
+ return (ret != 1) ? -EREMOTEIO : 0;
+ }
+
+-int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+-{
+- struct tda10021_state* state = fe->demodulator_priv;
+-
+- return tda10021_writereg(state, reg, data);
+-}
+-EXPORT_SYMBOL(tda10021_write_byte);
+-
+ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
+ {
+ u8 b0 [] = { reg };
+@@ -149,8 +141,8 @@ static int tda10021_setup_reg0 (struct t
+ else if (INVERSION_OFF == inversion)
+ DISABLE_INVERSION(reg0);
+
+- tda10021_writereg (state, 0x00, reg0 & 0xfe);
+- tda10021_writereg (state, 0x00, reg0 | 0x01);
++ _tda10021_writereg (state, 0x00, reg0 & 0xfe);
++ _tda10021_writereg (state, 0x00, reg0 | 0x01);
+
+ state->reg0 = reg0;
+ return 0;
+@@ -198,17 +190,27 @@ static int tda10021_set_symbolrate (stru
+
+ NDEC = (NDEC << 6) | tda10021_inittab[0x03];
+
+- tda10021_writereg (state, 0x03, NDEC);
+- tda10021_writereg (state, 0x0a, BDR&0xff);
+- tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
+- tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
++ _tda10021_writereg (state, 0x03, NDEC);
++ _tda10021_writereg (state, 0x0a, BDR&0xff);
++ _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
++ _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
+
+- tda10021_writereg (state, 0x0d, BDRI);
+- tda10021_writereg (state, 0x0e, SFIL);
++ _tda10021_writereg (state, 0x0d, BDRI);
++ _tda10021_writereg (state, 0x0e, SFIL);
+
+ return 0;
+ }
+
++int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
++{
++ struct tda10021_state* state = fe->demodulator_priv;
++
++ if (len != 2)
++ return -EINVAL;
++
++ return _tda10021_writereg(state, buf[0], buf[1]);
++}
++
+ static int tda10021_init (struct dvb_frontend *fe)
+ {
+ struct tda10021_state* state = fe->demodulator_priv;
+@@ -216,12 +218,12 @@ static int tda10021_init (struct dvb_fro
+
+ dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
+
+- //tda10021_writereg (fe, 0, 0);
++ //_tda10021_writereg (fe, 0, 0);
+
+ for (i=0; i<tda10021_inittab_size; i++)
+- tda10021_writereg (state, i, tda10021_inittab[i]);
++ _tda10021_writereg (state, i, tda10021_inittab[i]);
+
+- tda10021_writereg (state, 0x34, state->pwm);
++ _tda10021_writereg (state, 0x34, state->pwm);
+
+ //Comment by markus
+ //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
+@@ -230,7 +232,7 @@ static int tda10021_init (struct dvb_fro
+ //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
+
+ //Activate PLL
+- tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
++ _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
+ return 0;
+ }
+
+@@ -264,12 +266,12 @@ static int tda10021_set_parameters (stru
+ }
+
+ tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
+- tda10021_writereg (state, 0x34, state->pwm);
++ _tda10021_writereg (state, 0x34, state->pwm);
+
+- tda10021_writereg (state, 0x01, reg0x01[qam]);
+- tda10021_writereg (state, 0x05, reg0x05[qam]);
+- tda10021_writereg (state, 0x08, reg0x08[qam]);
+- tda10021_writereg (state, 0x09, reg0x09[qam]);
++ _tda10021_writereg (state, 0x01, reg0x01[qam]);
++ _tda10021_writereg (state, 0x05, reg0x05[qam]);
++ _tda10021_writereg (state, 0x08, reg0x08[qam]);
++ _tda10021_writereg (state, 0x09, reg0x09[qam]);
+
+ tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
+
+@@ -342,8 +344,8 @@ static int tda10021_read_ucblocks(struct
+ *ucblocks = 0xffffffff;
+
+ /* reset uncorrected block counter */
+- tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
+- tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
++ _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
++ _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
+
+ return 0;
+ }
+@@ -392,8 +394,8 @@ static int tda10021_sleep(struct dvb_fro
+ {
+ struct tda10021_state* state = fe->demodulator_priv;
+
+- tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
+- tda10021_writereg (state, 0x00, 0x80); /* standby */
++ _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
++ _tda10021_writereg (state, 0x00, 0x80); /* standby */
+
+ return 0;
+ }
+@@ -459,6 +461,7 @@ static struct dvb_frontend_ops tda10021_
+
+ .init = tda10021_init,
+ .sleep = tda10021_sleep,
++ .write = tda10021_write,
+ .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
+
+ .set_frontend = tda10021_set_parameters,
+diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
+index b1df425..e3da780 100644
+--- a/drivers/media/dvb/frontends/tda10021.h
++++ b/drivers/media/dvb/frontends/tda10021.h
+@@ -32,9 +32,24 @@ struct tda10021_config
+ u8 demod_address;
+ };
+
++#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+ struct i2c_adapter* i2c, u8 pwm);
+-
+-extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
++#else
++static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
++ struct i2c_adapter* i2c, u8 pwm)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TDA10021
++
++static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
++ int r = 0;
++ u8 buf[] = {reg, val};
++ if (fe->ops.write)
++ r = fe->ops.write(fe, buf, 2);
++ return r;
++}
+
+ #endif // TDA10021_H
+diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
+index 59a2ed6..11e0dca 100644
+--- a/drivers/media/dvb/frontends/tda1004x.c
++++ b/drivers/media/dvb/frontends/tda1004x.c
+@@ -579,11 +579,14 @@ static int tda1004x_decode_fec(int tdafe
+ return -1;
+ }
+
+-int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data)
++int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+ {
+ struct tda1004x_state* state = fe->demodulator_priv;
+
+- return tda1004x_write_byteI(state, reg, data);
++ if (len != 2)
++ return -EINVAL;
++
++ return tda1004x_write_byteI(state, buf[0], buf[1]);
+ }
+
+ static int tda10045_init(struct dvb_frontend* fe)
+@@ -1216,6 +1219,7 @@ static struct dvb_frontend_ops tda10045_
+
+ .init = tda10045_init,
+ .sleep = tda1004x_sleep,
++ .write = tda1004x_write,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
+
+ .set_frontend = tda1004x_set_fe,
+@@ -1274,6 +1278,7 @@ static struct dvb_frontend_ops tda10046_
+
+ .init = tda10046_init,
+ .sleep = tda1004x_sleep,
++ .write = tda1004x_write,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
+
+ .set_frontend = tda1004x_set_fe,
+@@ -1323,4 +1328,3 @@ MODULE_LICENSE("GPL");
+
+ EXPORT_SYMBOL(tda10045_attach);
+ EXPORT_SYMBOL(tda10046_attach);
+-EXPORT_SYMBOL(tda1004x_write_byte);
+diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
+index b877b23..605ad2d 100644
+--- a/drivers/media/dvb/frontends/tda1004x.h
++++ b/drivers/media/dvb/frontends/tda1004x.h
+@@ -71,12 +71,33 @@ struct tda1004x_config
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+ };
+
++#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c);
+
+ extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c);
+-
+-extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data);
++#else
++static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TDA1004X
++
++static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
++ int r = 0;
++ u8 buf[] = {reg, val};
++ if (fe->ops.write)
++ r = fe->ops.write(fe, buf, 2);
++ return r;
++}
+
+ #endif // TDA1004X_H
+diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
+new file mode 100644
+index 0000000..7456b0b
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda10086.c
+@@ -0,0 +1,740 @@
++ /*
++ Driver for Philips tda10086 DVBS Demodulator
++
++ (c) 2006 Andrew de Quincey
++
++ 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/jiffies.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++
++#include "dvb_frontend.h"
++#include "tda10086.h"
++
++#define SACLK 96000000
++
++struct tda10086_state {
++ struct i2c_adapter* i2c;
++ const struct tda10086_config* config;
++ struct dvb_frontend frontend;
++
++ /* private demod data */
++ u32 frequency;
++ u32 symbol_rate;
++};
++
++static int debug = 0;
++#define dprintk(args...) \
++ do { \
++ if (debug) printk(KERN_DEBUG "tda10086: " args); \
++ } while (0)
++
++static int tda10086_write_byte(struct tda10086_state *state, int reg, int data)
++{
++ int ret;
++ u8 b0[] = { reg, data };
++ struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 };
++
++ msg.addr = state->config->demod_address;
++ ret = i2c_transfer(state->i2c, &msg, 1);
++
++ if (ret != 1)
++ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
++ __FUNCTION__, reg, data, ret);
++
++ return (ret != 1) ? ret : 0;
++}
++
++static int tda10086_read_byte(struct tda10086_state *state, int reg)
++{
++ int ret;
++ u8 b0[] = { reg };
++ u8 b1[] = { 0 };
++ struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
++ { .flags = I2C_M_RD, .buf = b1, .len = 1 }};
++
++ msg[0].addr = state->config->demod_address;
++ msg[1].addr = state->config->demod_address;
++ ret = i2c_transfer(state->i2c, msg, 2);
++
++ if (ret != 2) {
++ dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
++ ret);
++ return ret;
++ }
++
++ return b1[0];
++}
++
++static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data)
++{
++ int val;
++
++ // read a byte and check
++ val = tda10086_read_byte(state, reg);
++ if (val < 0)
++ return val;
++
++ // mask if off
++ val = val & ~mask;
++ val |= data & 0xff;
++
++ // write it out again
++ return tda10086_write_byte(state, reg, val);
++}
++
++static int tda10086_init(struct dvb_frontend* fe)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ // reset
++ tda10086_write_byte(state, 0x00, 0x00);
++ msleep(10);
++
++ // misc setup
++ tda10086_write_byte(state, 0x01, 0x94);
++ tda10086_write_byte(state, 0x02, 0x35); // NOTE: TT drivers appear to disable CSWP
++ tda10086_write_byte(state, 0x03, 0x64);
++ tda10086_write_byte(state, 0x04, 0x43);
++ tda10086_write_byte(state, 0x0c, 0x0c);
++ tda10086_write_byte(state, 0x1b, 0xb0); // noise threshold
++ tda10086_write_byte(state, 0x20, 0x89); // misc
++ tda10086_write_byte(state, 0x30, 0x04); // acquisition period length
++ tda10086_write_byte(state, 0x32, 0x00); // irq off
++ tda10086_write_byte(state, 0x31, 0x56); // setup AFC
++
++ // setup PLL (assumes 16Mhz XIN)
++ tda10086_write_byte(state, 0x55, 0x2c); // misc PLL setup
++ tda10086_write_byte(state, 0x3a, 0x0b); // M=12
++ tda10086_write_byte(state, 0x3b, 0x01); // P=2
++ tda10086_write_mask(state, 0x55, 0x20, 0x00); // powerup PLL
++
++ // setup TS interface
++ tda10086_write_byte(state, 0x11, 0x81);
++ tda10086_write_byte(state, 0x12, 0x81);
++ tda10086_write_byte(state, 0x19, 0x40); // parallel mode A + MSBFIRST
++ tda10086_write_byte(state, 0x56, 0x80); // powerdown WPLL - unused in the mode we use
++ tda10086_write_byte(state, 0x57, 0x08); // bypass WPLL - unused in the mode we use
++ tda10086_write_byte(state, 0x10, 0x2a);
++
++ // setup ADC
++ tda10086_write_byte(state, 0x58, 0x61); // ADC setup
++ tda10086_write_mask(state, 0x58, 0x01, 0x00); // powerup ADC
++
++ // setup AGC
++ tda10086_write_byte(state, 0x05, 0x0B);
++ tda10086_write_byte(state, 0x37, 0x63);
++ tda10086_write_byte(state, 0x3f, 0x03); // NOTE: flydvb uses 0x0a and varies it
++ tda10086_write_byte(state, 0x40, 0x64);
++ tda10086_write_byte(state, 0x41, 0x4f);
++ tda10086_write_byte(state, 0x42, 0x43);
++
++ // setup viterbi
++ tda10086_write_byte(state, 0x1a, 0x11); // VBER 10^6, DVB, QPSK
++
++ // setup carrier recovery
++ tda10086_write_byte(state, 0x3d, 0x80);
++
++ // setup SEC
++ tda10086_write_byte(state, 0x36, 0x00); // all SEC off
++ tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); // } tone frequency
++ tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // }
++
++ return 0;
++}
++
++static void tda10086_diseqc_wait(struct tda10086_state *state)
++{
++ unsigned long timeout = jiffies + msecs_to_jiffies(200);
++ while (!(tda10086_read_byte(state, 0x50) & 0x01)) {
++ if(time_after(jiffies, timeout)) {
++ printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
++ break;
++ }
++ msleep(10);
++ }
++}
++
++static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ switch(tone) {
++ case SEC_TONE_OFF:
++ tda10086_write_byte(state, 0x36, 0x00);
++ break;
++
++ case SEC_TONE_ON:
++ tda10086_write_byte(state, 0x36, 0x01);
++ break;
++ }
++
++ return 0;
++}
++
++static int tda10086_send_master_cmd (struct dvb_frontend* fe,
++ struct dvb_diseqc_master_cmd* cmd)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++ int i;
++ u8 oldval;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ if (cmd->msg_len > 6)
++ return -EINVAL;
++ oldval = tda10086_read_byte(state, 0x36);
++
++ for(i=0; i< cmd->msg_len; i++) {
++ tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
++ }
++ tda10086_write_byte(state, 0x36, 0x08 | ((cmd->msg_len + 1) << 4));
++
++ tda10086_diseqc_wait(state);
++
++ tda10086_write_byte(state, 0x36, oldval);
++
++ return 0;
++}
++
++static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++ u8 oldval = tda10086_read_byte(state, 0x36);
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ switch(minicmd) {
++ case SEC_MINI_A:
++ tda10086_write_byte(state, 0x36, 0x04);
++ break;
++
++ case SEC_MINI_B:
++ tda10086_write_byte(state, 0x36, 0x06);
++ break;
++ }
++
++ tda10086_diseqc_wait(state);
++
++ tda10086_write_byte(state, 0x36, oldval);
++
++ return 0;
++}
++
++static int tda10086_set_inversion(struct tda10086_state *state,
++ struct dvb_frontend_parameters *fe_params)
++{
++ u8 invval = 0x80;
++
++ dprintk ("%s %i %i\n", __FUNCTION__, fe_params->inversion, state->config->invert);
++
++ switch(fe_params->inversion) {
++ case INVERSION_OFF:
++ if (state->config->invert)
++ invval = 0x40;
++ break;
++ case INVERSION_ON:
++ if (!state->config->invert)
++ invval = 0x40;
++ break;
++ case INVERSION_AUTO:
++ invval = 0x00;
++ break;
++ }
++ tda10086_write_mask(state, 0x0c, 0xc0, invval);
++
++ return 0;
++}
++
++static int tda10086_set_symbol_rate(struct tda10086_state *state,
++ struct dvb_frontend_parameters *fe_params)
++{
++ u8 dfn = 0;
++ u8 afs = 0;
++ u8 byp = 0;
++ u8 reg37 = 0x43;
++ u8 reg42 = 0x43;
++ u64 big;
++ u32 tmp;
++ u32 bdr;
++ u32 bdri;
++ u32 symbol_rate = fe_params->u.qpsk.symbol_rate;
++
++ dprintk ("%s %i\n", __FUNCTION__, symbol_rate);
++
++ // setup the decimation and anti-aliasing filters..
++ if (symbol_rate < (u32) (SACLK * 0.0137)) {
++ dfn=4;
++ afs=1;
++ } else if (symbol_rate < (u32) (SACLK * 0.0208)) {
++ dfn=4;
++ afs=0;
++ } else if (symbol_rate < (u32) (SACLK * 0.0270)) {
++ dfn=3;
++ afs=1;
++ } else if (symbol_rate < (u32) (SACLK * 0.0416)) {
++ dfn=3;
++ afs=0;
++ } else if (symbol_rate < (u32) (SACLK * 0.0550)) {
++ dfn=2;
++ afs=1;
++ } else if (symbol_rate < (u32) (SACLK * 0.0833)) {
++ dfn=2;
++ afs=0;
++ } else if (symbol_rate < (u32) (SACLK * 0.1100)) {
++ dfn=1;
++ afs=1;
++ } else if (symbol_rate < (u32) (SACLK * 0.1666)) {
++ dfn=1;
++ afs=0;
++ } else if (symbol_rate < (u32) (SACLK * 0.2200)) {
++ dfn=0;
++ afs=1;
++ } else if (symbol_rate < (u32) (SACLK * 0.3333)) {
++ dfn=0;
++ afs=0;
++ } else {
++ reg37 = 0x63;
++ reg42 = 0x4f;
++ byp=1;
++ }
++
++ // calculate BDR
++ big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn);
++ big += ((SACLK/1000ULL)-1ULL);
++ do_div(big, (SACLK/1000ULL));
++ bdr = big & 0xfffff;
++
++ // calculate BDRI
++ tmp = (1<<dfn)*(symbol_rate/1000);
++ bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp;
++
++ tda10086_write_byte(state, 0x21, (afs << 7) | dfn);
++ tda10086_write_mask(state, 0x20, 0x08, byp << 3);
++ tda10086_write_byte(state, 0x06, bdr);
++ tda10086_write_byte(state, 0x07, bdr >> 8);
++ tda10086_write_byte(state, 0x08, bdr >> 16);
++ tda10086_write_byte(state, 0x09, bdri);
++ tda10086_write_byte(state, 0x37, reg37);
++ tda10086_write_byte(state, 0x42, reg42);
++
++ return 0;
++}
++
++static int tda10086_set_fec(struct tda10086_state *state,
++ struct dvb_frontend_parameters *fe_params)
++{
++ u8 fecval;
++
++ dprintk ("%s %i\n", __FUNCTION__, fe_params->u.qpsk.fec_inner);
++
++ switch(fe_params->u.qpsk.fec_inner) {
++ case FEC_1_2:
++ fecval = 0x00;
++ break;
++ case FEC_2_3:
++ fecval = 0x01;
++ break;
++ case FEC_3_4:
++ fecval = 0x02;
++ break;
++ case FEC_4_5:
++ fecval = 0x03;
++ break;
++ case FEC_5_6:
++ fecval = 0x04;
++ break;
++ case FEC_6_7:
++ fecval = 0x05;
++ break;
++ case FEC_7_8:
++ fecval = 0x06;
++ break;
++ case FEC_8_9:
++ fecval = 0x07;
++ break;
++ case FEC_AUTO:
++ fecval = 0x08;
++ break;
++ default:
++ return -1;
++ }
++ tda10086_write_byte(state, 0x0d, fecval);
++
++ return 0;
++}
++
++static int tda10086_set_frontend(struct dvb_frontend* fe,
++ struct dvb_frontend_parameters *fe_params)
++{
++ struct tda10086_state *state = fe->demodulator_priv;
++ int ret;
++ u32 freq = 0;
++ int freqoff;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ // set params
++ if (fe->ops.tuner_ops.set_params) {
++ fe->ops.tuner_ops.set_params(fe, fe_params);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ if (fe->ops.tuner_ops.get_frequency)
++ fe->ops.tuner_ops.get_frequency(fe, &freq);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++ }
++
++ // calcluate the frequency offset (in *Hz* not kHz)
++ freqoff = fe_params->frequency - freq;
++ freqoff = ((1<<16) * freqoff) / (SACLK/1000);
++ tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f));
++ tda10086_write_byte(state, 0x3e, freqoff);
++
++ if ((ret = tda10086_set_inversion(state, fe_params)) < 0)
++ return ret;
++ if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0)
++ return ret;
++ if ((ret = tda10086_set_fec(state, fe_params)) < 0)
++ return ret;
++
++ // soft reset + disable TS output until lock
++ tda10086_write_mask(state, 0x10, 0x40, 0x40);
++ tda10086_write_mask(state, 0x00, 0x01, 0x00);
++
++ state->symbol_rate = fe_params->u.qpsk.symbol_rate;
++ state->frequency = fe_params->frequency;
++ return 0;
++}
++
++static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++ u8 val;
++ int tmp;
++ u64 tmp64;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ // calculate the updated frequency (note: we convert from Hz->kHz)
++ tmp64 = tda10086_read_byte(state, 0x52);
++ tmp64 |= (tda10086_read_byte(state, 0x51) << 8);
++ if (tmp64 & 0x8000)
++ tmp64 |= 0xffffffffffff0000ULL;
++ tmp64 = (tmp64 * (SACLK/1000ULL));
++ do_div(tmp64, (1ULL<<15) * (1ULL<<1));
++ fe_params->frequency = (int) state->frequency + (int) tmp64;
++
++ // the inversion
++ val = tda10086_read_byte(state, 0x0c);
++ if (val & 0x80) {
++ switch(val & 0x40) {
++ case 0x00:
++ fe_params->inversion = INVERSION_OFF;
++ if (state->config->invert)
++ fe_params->inversion = INVERSION_ON;
++ break;
++ default:
++ fe_params->inversion = INVERSION_ON;
++ if (state->config->invert)
++ fe_params->inversion = INVERSION_OFF;
++ break;
++ }
++ } else {
++ tda10086_read_byte(state, 0x0f);
++ switch(val & 0x02) {
++ case 0x00:
++ fe_params->inversion = INVERSION_OFF;
++ if (state->config->invert)
++ fe_params->inversion = INVERSION_ON;
++ break;
++ default:
++ fe_params->inversion = INVERSION_ON;
++ if (state->config->invert)
++ fe_params->inversion = INVERSION_OFF;
++ break;
++ }
++ }
++
++ // calculate the updated symbol rate
++ tmp = tda10086_read_byte(state, 0x1d);
++ if (tmp & 0x80)
++ tmp |= 0xffffff00;
++ tmp = (tmp * 480 * (1<<1)) / 128;
++ tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
++ fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp;
++
++ // the FEC
++ val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
++ switch(val) {
++ case 0x00:
++ fe_params->u.qpsk.fec_inner = FEC_1_2;
++ break;
++ case 0x01:
++ fe_params->u.qpsk.fec_inner = FEC_2_3;
++ break;
++ case 0x02:
++ fe_params->u.qpsk.fec_inner = FEC_3_4;
++ break;
++ case 0x03:
++ fe_params->u.qpsk.fec_inner = FEC_4_5;
++ break;
++ case 0x04:
++ fe_params->u.qpsk.fec_inner = FEC_5_6;
++ break;
++ case 0x05:
++ fe_params->u.qpsk.fec_inner = FEC_6_7;
++ break;
++ case 0x06:
++ fe_params->u.qpsk.fec_inner = FEC_7_8;
++ break;
++ case 0x07:
++ fe_params->u.qpsk.fec_inner = FEC_8_9;
++ break;
++ }
++
++ return 0;
++}
++
++static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++ u8 val;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ val = tda10086_read_byte(state, 0x0e);
++ *fe_status = 0;
++ if (val & 0x01)
++ *fe_status |= FE_HAS_SIGNAL;
++ if (val & 0x02)
++ *fe_status |= FE_HAS_CARRIER;
++ if (val & 0x04)
++ *fe_status |= FE_HAS_VITERBI;
++ if (val & 0x08)
++ *fe_status |= FE_HAS_SYNC;
++ if (val & 0x10)
++ *fe_status |= FE_HAS_LOCK;
++
++ return 0;
++}
++
++static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++ u8 _str;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ _str = tda10086_read_byte(state, 0x43);
++ *signal = (_str << 8) | _str;
++
++ return 0;
++}
++
++static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++ u8 _snr;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ _snr = tda10086_read_byte(state, 0x1c);
++ *snr = (_snr << 8) | _snr;
++
++ return 0;
++}
++
++static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ // read it
++ *ucblocks = tda10086_read_byte(state, 0x18) & 0x7f;
++
++ // reset counter
++ tda10086_write_byte(state, 0x18, 0x00);
++ tda10086_write_byte(state, 0x18, 0x80);
++
++ return 0;
++}
++
++static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ // read it
++ *ber = 0;
++ *ber |= tda10086_read_byte(state, 0x15);
++ *ber |= tda10086_read_byte(state, 0x16) << 8;
++ *ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16;
++
++ return 0;
++}
++
++static int tda10086_sleep(struct dvb_frontend* fe)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ tda10086_write_mask(state, 0x00, 0x08, 0x08);
++
++ return 0;
++}
++
++static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
++{
++ struct tda10086_state* state = fe->demodulator_priv;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ if (enable) {
++ tda10086_write_mask(state, 0x00, 0x10, 0x10);
++ } else {
++ tda10086_write_mask(state, 0x00, 0x10, 0x00);
++ }
++
++ return 0;
++}
++
++static int tda10086_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 void tda10086_release(struct dvb_frontend* fe)
++{
++ struct tda10086_state *state = fe->demodulator_priv;
++ tda10086_sleep(fe);
++ kfree(state);
++}
++
++static struct dvb_frontend_ops tda10086_ops = {
++
++ .info = {
++ .name = "Philips TDA10086 DVB-S",
++ .type = FE_QPSK,
++ .frequency_min = 950000,
++ .frequency_max = 2150000,
++ .frequency_stepsize = 125, /* kHz for QPSK frontends */
++ .symbol_rate_min = 1000000,
++ .symbol_rate_max = 45000000,
++ .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 = tda10086_release,
++
++ .init = tda10086_init,
++ .sleep = tda10086_sleep,
++ .i2c_gate_ctrl = tda10086_i2c_gate_ctrl,
++
++ .set_frontend = tda10086_set_frontend,
++ .get_frontend = tda10086_get_frontend,
++ .get_tune_settings = tda10086_get_tune_settings,
++
++ .read_status = tda10086_read_status,
++ .read_ber = tda10086_read_ber,
++ .read_signal_strength = tda10086_read_signal_strength,
++ .read_snr = tda10086_read_snr,
++ .read_ucblocks = tda10086_read_ucblocks,
++
++ .diseqc_send_master_cmd = tda10086_send_master_cmd,
++ .diseqc_send_burst = tda10086_send_burst,
++ .set_tone = tda10086_set_tone,
++};
++
++struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
++ struct i2c_adapter* i2c)
++{
++ struct tda10086_state *state;
++
++ dprintk ("%s\n", __FUNCTION__);
++
++ /* allocate memory for the internal state */
++ state = kmalloc(sizeof(struct tda10086_state), GFP_KERNEL);
++ if (!state)
++ return NULL;
++
++ /* setup the state */
++ state->config = config;
++ state->i2c = i2c;
++
++ /* check if the demod is there */
++ if (tda10086_read_byte(state, 0x1e) != 0xe1) {
++ kfree(state);
++ return NULL;
++ }
++
++ /* create dvb_frontend */
++ memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops));
++ state->frontend.demodulator_priv = state;
++ return &state->frontend;
++}
++
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
++
++MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator");
++MODULE_AUTHOR("Andrew de Quincey");
++MODULE_LICENSE("GPL");
++
++EXPORT_SYMBOL(tda10086_attach);
+diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h
+new file mode 100644
+index 0000000..ed584a8
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda10086.h
+@@ -0,0 +1,50 @@
++ /*
++ Driver for Philips tda10086 DVBS Frontend
++
++ (c) 2006 Andrew de Quincey
++
++ 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 TDA10086_H
++#define TDA10086_H
++
++#include <linux/dvb/frontend.h>
++#include <linux/firmware.h>
++
++struct tda10086_config
++{
++ /* the demodulator's i2c address */
++ u8 demod_address;
++
++ /* does the "inversion" need inverted? */
++ u8 invert;
++};
++
++#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
++extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
++ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TDA10086
++
++#endif // TDA10086_H
+diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
+index e7a48f6..2d33079 100644
+--- a/drivers/media/dvb/frontends/tda8083.h
++++ b/drivers/media/dvb/frontends/tda8083.h
+@@ -35,7 +35,16 @@ struct tda8083_config
+ u8 demod_address;
+ };
+
++#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TDA8083
+
+ #endif // TDA8083_H
+diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
+new file mode 100644
+index 0000000..eeab26b
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda826x.c
+@@ -0,0 +1,173 @@
++ /*
++ Driver for Philips tda8262/tda8263 DVBS Silicon tuners
++
++ (c) 2006 Andrew de Quincey
++
++ 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/module.h>
++#include <linux/dvb/frontend.h>
++#include <asm/types.h>
++
++#include "tda826x.h"
++
++static int debug = 0;
++#define dprintk(args...) \
++ do { \
++ if (debug) printk(KERN_DEBUG "tda826x: " args); \
++ } while (0)
++
++struct tda826x_priv {
++ /* i2c details */
++ int i2c_address;
++ struct i2c_adapter *i2c;
++ u8 has_loopthrough:1;
++ u32 frequency;
++};
++
++static int tda826x_release(struct dvb_frontend *fe)
++{
++ if (fe->tuner_priv)
++ kfree(fe->tuner_priv);
++ fe->tuner_priv = NULL;
++ return 0;
++}
++
++static int tda826x_sleep(struct dvb_frontend *fe)
++{
++ struct tda826x_priv *priv = fe->tuner_priv;
++ int ret;
++ u8 buf [] = { 0x00, 0x8d };
++ struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 };
++
++ dprintk("%s:\n", __FUNCTION__);
++
++ if (!priv->has_loopthrough)
++ buf[1] = 0xad;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
++ dprintk("%s: i2c error\n", __FUNCTION__);
++ }
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ return (ret == 1) ? 0 : ret;
++}
++
++static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
++{
++ struct tda826x_priv *priv = fe->tuner_priv;
++ int ret;
++ u32 div;
++ u8 buf [11];
++ struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 };
++
++ dprintk("%s:\n", __FUNCTION__);
++
++ div = (params->frequency + (1000-1)) / 1000;
++
++ buf[0] = 0x00; // subaddress
++ buf[1] = 0x09; // powerdown RSSI + the magic value 1
++ if (!priv->has_loopthrough)
++ buf[1] |= 0x20; // power down loopthrough if not needed
++ buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO
++ buf[3] = div >> 7;
++ buf[4] = div << 1;
++ buf[5] = 0xff; // basedband filter to max
++ buf[6] = 0xfe; // gains at max + no RF attenuation
++ buf[7] = 0x83; // charge pumps at high, tests off
++ buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports.
++ buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL
++ buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
++ dprintk("%s: i2c error\n", __FUNCTION__);
++ }
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ priv->frequency = div * 1000;
++
++ return (ret == 1) ? 0 : ret;
++}
++
++static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct tda826x_priv *priv = fe->tuner_priv;
++ *frequency = priv->frequency;
++ return 0;
++}
++
++static struct dvb_tuner_ops tda826x_tuner_ops = {
++ .info = {
++ .name = "Philips TDA826X",
++ .frequency_min = 950000,
++ .frequency_min = 2175000
++ },
++ .release = tda826x_release,
++ .sleep = tda826x_sleep,
++ .set_params = tda826x_set_params,
++ .get_frequency = tda826x_get_frequency,
++};
++
++struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough)
++{
++ struct tda826x_priv *priv = NULL;
++ u8 b1 [] = { 0, 0 };
++ struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 };
++ int ret;
++
++ dprintk("%s:\n", __FUNCTION__);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ ret = i2c_transfer (i2c, &msg, 1);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ if (ret != 1)
++ return NULL;
++ if (!(b1[1] & 0x80))
++ return NULL;
++
++ priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL);
++ if (priv == NULL)
++ return NULL;
++
++ priv->i2c_address = addr;
++ priv->i2c = i2c;
++ priv->has_loopthrough = has_loopthrough;
++
++ memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops));
++
++ fe->tuner_priv = priv;
++
++ return fe;
++}
++EXPORT_SYMBOL(tda826x_attach);
++
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
++
++MODULE_DESCRIPTION("DVB TDA826x driver");
++MODULE_AUTHOR("Andrew de Quincey");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h
+new file mode 100644
+index 0000000..ad99811
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda826x.h
+@@ -0,0 +1,53 @@
++ /*
++ Driver for Philips tda8262/tda8263 DVBS Silicon tuners
++
++ (c) 2006 Andrew de Quincey
++
++ 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 __DVB_TDA826X_H__
++#define __DVB_TDA826X_H__
++
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++
++/**
++ * Attach a tda826x tuner to the supplied frontend structure.
++ *
++ * @param fe Frontend to attach to.
++ * @param addr i2c address of the tuner.
++ * @param i2c i2c adapter to use.
++ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
++ * @return FE pointer on success, NULL on failure.
++ */
++#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE))
++extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
++ struct i2c_adapter *i2c,
++ int has_loopthrough);
++#else
++static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe,
++ int addr,
++ struct i2c_adapter *i2c,
++ int has_loopthrough)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TDA826X
++
++#endif // __DVB_TDA826X_H__
+diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
+new file mode 100644
+index 0000000..8855439
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tua6100.c
+@@ -0,0 +1,205 @@
++/**
++ * Driver for Infineon tua6100 pll.
++ *
++ * (c) 2006 Andrew de Quincey
++ *
++ * Based on code found in budget-av.c, which has the following:
++ * Compiled from various sources by Michael Hunold <michael at mihu.de>
++ *
++ * CI interface support (c) 2004 Olivier Gournet <ogournet at anevia.com> &
++ * Andrew de Quincey <adq_dvb at lidskialf.net>
++ *
++ * Copyright (C) 2002 Ralph Metzler <rjkm at metzlerbros.de>
++ *
++ * Copyright (C) 1999-2002 Ralph Metzler
++ * & Marcus Metzler for convergence integrated media GmbH
++ * 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/module.h>
++#include <linux/dvb/frontend.h>
++#include <asm/types.h>
++
++#include "tua6100.h"
++
++struct tua6100_priv {
++ /* i2c details */
++ int i2c_address;
++ struct i2c_adapter *i2c;
++ u32 frequency;
++};
++
++static int tua6100_release(struct dvb_frontend *fe)
++{
++ if (fe->tuner_priv)
++ kfree(fe->tuner_priv);
++ fe->tuner_priv = NULL;
++ return 0;
++}
++
++static int tua6100_sleep(struct dvb_frontend *fe)
++{
++ struct tua6100_priv *priv = fe->tuner_priv;
++ int ret;
++ u8 reg0[] = { 0x00, 0x00 };
++ struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
++ printk("%s: i2c error\n", __FUNCTION__);
++ }
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ return (ret == 1) ? 0 : ret;
++}
++
++static int tua6100_set_params(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *params)
++{
++ struct tua6100_priv *priv = fe->tuner_priv;
++ u32 div;
++ u32 prediv;
++ u8 reg0[] = { 0x00, 0x00 };
++ u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 };
++ u8 reg2[] = { 0x02, 0x00, 0x00 };
++ struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
++ struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
++ struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
++
++#define _R 4
++#define _P 32
++#define _ri 4000000
++
++ // setup register 0
++ if (params->frequency < 2000000) {
++ reg0[1] = 0x03;
++ } else {
++ reg0[1] = 0x07;
++ }
++
++ // setup register 1
++ if (params->frequency < 1630000) {
++ reg1[1] = 0x2c;
++ } else {
++ reg1[1] = 0x0c;
++ }
++ if (_P == 64)
++ reg1[1] |= 0x40;
++ if (params->frequency >= 1525000)
++ reg1[1] |= 0x80;
++
++ // register 2
++ reg2[1] = (_R >> 8) & 0x03;
++ reg2[2] = _R;
++ if (params->frequency < 1455000) {
++ reg2[1] |= 0x1c;
++ } else if (params->frequency < 1630000) {
++ reg2[1] |= 0x0c;
++ } else {
++ reg2[1] |= 0x1c;
++ }
++
++ // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz)
++ prediv = (params->frequency * _R) / (_ri / 1000);
++ div = prediv / _P;
++ reg1[1] |= (div >> 9) & 0x03;
++ reg1[2] = div >> 1;
++ reg1[3] = (div << 7);
++ priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
++
++ // Finally, calculate and store the value for A
++ reg1[3] |= (prediv - (div*_P)) & 0x7f;
++
++#undef _R
++#undef _P
++#undef _ri
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ if (i2c_transfer(priv->i2c, &msg0, 1) != 1)
++ return -EIO;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ if (i2c_transfer(priv->i2c, &msg2, 1) != 1)
++ return -EIO;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ if (i2c_transfer(priv->i2c, &msg1, 1) != 1)
++ return -EIO;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ return 0;
++}
++
++static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct tua6100_priv *priv = fe->tuner_priv;
++ *frequency = priv->frequency;
++ return 0;
++}
++
++static struct dvb_tuner_ops tua6100_tuner_ops = {
++ .info = {
++ .name = "Infineon TUA6100",
++ .frequency_min = 950000,
++ .frequency_max = 2150000,
++ .frequency_step = 1000,
++ },
++ .release = tua6100_release,
++ .sleep = tua6100_sleep,
++ .set_params = tua6100_set_params,
++ .get_frequency = tua6100_get_frequency,
++};
++
++struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
++{
++ struct tua6100_priv *priv = NULL;
++ u8 b1 [] = { 0x80 };
++ u8 b2 [] = { 0x00 };
++ struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 },
++ { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } };
++ int ret;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ ret = i2c_transfer (i2c, msg, 2);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ if (ret != 2)
++ return NULL;
++
++ priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL);
++ if (priv == NULL)
++ return NULL;
++
++ priv->i2c_address = addr;
++ priv->i2c = i2c;
++
++ memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops));
++ fe->tuner_priv = priv;
++ return fe;
++}
++EXPORT_SYMBOL(tua6100_attach);
++
++MODULE_DESCRIPTION("DVB tua6100 driver");
++MODULE_AUTHOR("Andrew de Quincey");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb/frontends/tua6100.h
+new file mode 100644
+index 0000000..03a665e
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tua6100.h
+@@ -0,0 +1,47 @@
++/**
++ * Driver for Infineon tua6100 PLL.
++ *
++ * (c) 2006 Andrew de Quincey
++ *
++ * Based on code found in budget-av.c, which has the following:
++ * Compiled from various sources by Michael Hunold <michael at mihu.de>
++ *
++ * CI interface support (c) 2004 Olivier Gournet <ogournet at anevia.com> &
++ * Andrew de Quincey <adq_dvb at lidskialf.net>
++ *
++ * Copyright (C) 2002 Ralph Metzler <rjkm at metzlerbros.de>
++ *
++ * Copyright (C) 1999-2002 Ralph Metzler
++ * & Marcus Metzler for convergence integrated media GmbH
++ * 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 __DVB_TUA6100_H__
++#define __DVB_TUA6100_H__
++
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++
++#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE))
++extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
++#else
++static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_TUA6100
++
++#endif
+diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
+index 520f095..e4a2a32 100644
+--- a/drivers/media/dvb/frontends/ves1820.h
++++ b/drivers/media/dvb/frontends/ves1820.h
+@@ -41,7 +41,16 @@ struct ves1820_config
+ u8 selagc:1;
+ };
+
++#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+ struct i2c_adapter* i2c, u8 pwm);
++#else
++static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
++ struct i2c_adapter* i2c, u8 pwm)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_VES1820
+
+ #endif // VES1820_H
+diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
+index ba88ae0..d507f89 100644
+--- a/drivers/media/dvb/frontends/ves1x93.h
++++ b/drivers/media/dvb/frontends/ves1x93.h
+@@ -40,7 +40,16 @@ struct ves1x93_config
+ u8 invert_pwm:1;
+ };
+
++#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_VES1X93
+
+ #endif // VES1X93_H
+diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
+index 2b95e8b..0e9b59a 100644
+--- a/drivers/media/dvb/frontends/zl10353.c
++++ b/drivers/media/dvb/frontends/zl10353.c
+@@ -140,6 +140,8 @@ static int zl10353_set_parameters(struct
+ zl10353_single_write(fe, 0x5E, 0x00);
+ zl10353_single_write(fe, 0x65, 0x5A);
+ zl10353_single_write(fe, 0x66, 0xE9);
++ zl10353_single_write(fe, 0x6C, 0xCD);
++ zl10353_single_write(fe, 0x6D, 0x7E);
+ zl10353_single_write(fe, 0x62, 0x0A);
+
+ // if there is no attached secondary tuner, we call set_params to program
+@@ -168,6 +170,7 @@ static int zl10353_set_parameters(struct
+ // even if there isn't a PLL attached to the secondary bus
+ zl10353_write(fe, pllbuf, sizeof(pllbuf));
+
++ zl10353_single_write(fe, 0x5F, 0x13);
+ zl10353_single_write(fe, 0x70, 0x01);
+ udelay(250);
+ zl10353_single_write(fe, 0xE4, 0x00);
+@@ -243,9 +246,12 @@ static int zl10353_init(struct dvb_front
+
+ if (debug_regs)
+ zl10353_dump_regs(fe);
++ if (state->config.parallel_ts)
++ zl10353_reset_attach[2] &= ~0x20;
+
+ /* Do a "hard" reset if not already done */
+- if (zl10353_read_register(state, 0x50) != 0x03) {
++ if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
++ zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
+ rc = zl10353_write(fe, zl10353_reset_attach,
+ sizeof(zl10353_reset_attach));
+ if (debug_regs)
+@@ -258,7 +264,6 @@ static int zl10353_init(struct dvb_front
+ static void zl10353_release(struct dvb_frontend *fe)
+ {
+ struct zl10353_state *state = fe->demodulator_priv;
+-
+ kfree(state);
+ }
+
+@@ -314,6 +319,7 @@ static struct dvb_frontend_ops zl10353_o
+
+ .init = zl10353_init,
+ .sleep = zl10353_sleep,
++ .write = zl10353_write,
+
+ .set_frontend = zl10353_set_parameters,
+ .get_tune_settings = zl10353_get_tune_settings,
+@@ -330,4 +336,3 @@ MODULE_AUTHOR("Chris Pascoe");
+ MODULE_LICENSE("GPL");
+
+ EXPORT_SYMBOL(zl10353_attach);
+-EXPORT_SYMBOL(zl10353_write);
+diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
+index 9770cb8..0bc0109 100644
+--- a/drivers/media/dvb/frontends/zl10353.h
++++ b/drivers/media/dvb/frontends/zl10353.h
+@@ -31,11 +31,21 @@ struct zl10353_config
+
+ /* set if no pll is connected to the secondary i2c bus */
+ int no_tuner;
++
++ /* set if parallel ts output is required */
++ int parallel_ts;
+ };
+
++#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
+ extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+ struct i2c_adapter *i2c);
+-
+-extern int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen);
++#else
++static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
++ struct i2c_adapter *i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++ return NULL;
++}
++#endif // CONFIG_DVB_ZL10353
+
+ #endif /* ZL10353_H */
+diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
+index 2310b2b..8e4ce10 100644
+--- a/drivers/media/dvb/pluto2/pluto2.c
++++ b/drivers/media/dvb/pluto2/pluto2.c
+@@ -306,7 +306,7 @@ static void pluto_dma_end(struct pluto *
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+ }
+
+-static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pluto_irq(int irq, void *dev_id)
+ {
+ struct pluto *pluto = dev_id;
+ u32 tscr;
+diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
+index 5fb0975..95531a6 100644
+--- a/drivers/media/dvb/ttpci/Kconfig
++++ b/drivers/media/dvb/ttpci/Kconfig
+@@ -1,17 +1,17 @@
+ config DVB_AV7110
+ tristate "AV7110 cards"
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+- select FW_LOADER
++ select FW_LOADER if !DVB_AV7110_FIRMWARE
+ select VIDEO_SAA7146_VV
+ select DVB_PLL
+- select DVB_VES1820
+- select DVB_VES1X93
+- select DVB_STV0299
+- select DVB_TDA8083
+- select DVB_SP8870
+- select DVB_STV0297
+- select DVB_L64781
+- select DVB_LNBP21
++ select DVB_VES1820 if !DVB_FE_CUSTOMISE
++ select DVB_VES1X93 if !DVB_FE_CUSTOMISE
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
++ select DVB_SP8870 if !DVB_FE_CUSTOMISE
++ select DVB_STV0297 if !DVB_FE_CUSTOMISE
++ select DVB_L64781 if !DVB_FE_CUSTOMISE
++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ help
+ Support for SAA7146 and AV7110 based DVB cards as produced
+ by Fujitsu-Siemens, Technotrend, Hauppauge and others.
+@@ -63,14 +63,16 @@ config DVB_BUDGET
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+ select VIDEO_SAA7146
+ select DVB_PLL
+- select DVB_STV0299
+- select DVB_VES1X93
+- select DVB_VES1820
+- select DVB_L64781
+- select DVB_TDA8083
+- select DVB_TDA10021
+- select DVB_S5H1420
+- select DVB_LNBP21
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_VES1X93 if !DVB_FE_CUSTOMISE
++ select DVB_VES1820 if !DVB_FE_CUSTOMISE
++ select DVB_L64781 if !DVB_FE_CUSTOMISE
++ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
++ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
++ select DVB_S5H1420 if !DVB_FE_CUSTOMISE
++ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
++ select DVB_TDA826X if !DVB_FE_CUSTOMISE
++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ help
+ Support for simple SAA7146 based DVB cards
+ (so called Budget- or Nova-PCI cards) without onboard
+@@ -86,10 +88,10 @@ config DVB_BUDGET_CI
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+ select VIDEO_SAA7146
+ select DVB_PLL
+- select DVB_STV0297
+- select DVB_STV0299
+- select DVB_TDA1004X
+- select DVB_LNBP21
++ select DVB_STV0297 if !DVB_FE_CUSTOMISE
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ help
+ Support for simple SAA7146 based DVB cards
+ (so called Budget- or Nova-PCI cards) without onboard
+@@ -108,9 +110,10 @@ config DVB_BUDGET_AV
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+ select VIDEO_SAA7146_VV
+ select DVB_PLL
+- select DVB_STV0299
+- select DVB_TDA1004X
+- select DVB_TDA10021
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
++ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
++ select DVB_TUA6100 if !DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ Support for simple SAA7146 based DVB cards
+@@ -127,9 +130,9 @@ config DVB_BUDGET_PATCH
+ depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
+ select DVB_AV7110
+ select DVB_PLL
+- select DVB_STV0299
+- select DVB_VES1X93
+- select DVB_TDA8083
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_VES1X93 if !DVB_FE_CUSTOMISE
++ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+ help
+ Support for Budget Patch (full TS) modification on
+ SAA7146+AV7110 based cards (DVB-S cards). This
+diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
+index 4506165..bba23bc 100644
+--- a/drivers/media/dvb/ttpci/av7110.c
++++ b/drivers/media/dvb/ttpci/av7110.c
+@@ -1383,8 +1383,10 @@ static void dvb_unregister(struct av7110
+ dvb_dmxdev_release(&av7110->dmxdev);
+ dvb_dmx_release(&av7110->demux);
+
+- if (av7110->fe != NULL)
++ if (av7110->fe != NULL) {
+ dvb_unregister_frontend(av7110->fe);
++ dvb_frontend_detach(av7110->fe);
++ }
+ dvb_unregister_device(av7110->osd_dev);
+ av7110_av_unregister(av7110);
+ av7110_ca_unregister(av7110);
+@@ -1699,9 +1701,13 @@ static int alps_tdlb7_tuner_set_params(s
+
+ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+ {
++#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &av7110->dev->pci->dev);
++#else
++ return -EINVAL;
++#endif
+ }
+
+ static struct sp8870_config alps_tdlb7_config = {
+@@ -2077,7 +2083,7 @@ static int frontend_init(struct av7110 *
+ if (av7110->dev->pci->subsystem_vendor == 0x110a) {
+ switch(av7110->dev->pci->subsystem_device) {
+ case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
+- av7110->fe = ves1820_attach(&philips_cd1516_config,
++ av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config,
+ &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+@@ -2092,7 +2098,7 @@ static int frontend_init(struct av7110 *
+ case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
+
+ // try the ALPS BSRV2 first of all
+- av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+@@ -2103,7 +2109,7 @@ static int frontend_init(struct av7110 *
+ }
+
+ // try the ALPS BSRU6 now
+- av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+@@ -2116,7 +2122,7 @@ static int frontend_init(struct av7110 *
+ }
+
+ // Try the grundig 29504-451
+- av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+@@ -2130,7 +2136,7 @@ static int frontend_init(struct av7110 *
+ switch(av7110->dev->pci->subsystem_device) {
+ case 0x0000:
+ /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
+- av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
++ av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap,
+ read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+@@ -2138,7 +2144,7 @@ static int frontend_init(struct av7110 *
+ break;
+ case 0x0003:
+ /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
+- av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
++ av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap,
+ read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+@@ -2148,17 +2154,24 @@ static int frontend_init(struct av7110 *
+ break;
+
+ case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
+-
+- // ALPS TDLB7
+- av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
++ // try ALPS TDLB7 first, then Grundig 29504-401
++ av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
++ break;
+ }
++ /* fall-thru */
++
++ case 0x0008: // Hauppauge/TT DVB-T
++ // Grundig 29504-401
++ av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap);
++ if (av7110->fe)
++ av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ break;
+
+ case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
+
+- av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
++ av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
+@@ -2166,7 +2179,7 @@ static int frontend_init(struct av7110 *
+
+ case 0x0004: // Galaxis DVB-S rev1.3
+ /* ALPS BSRV2 */
+- av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+@@ -2178,7 +2191,7 @@ static int frontend_init(struct av7110 *
+
+ case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
+ /* Grundig 29504-451 */
+- av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+@@ -2188,17 +2201,9 @@ static int frontend_init(struct av7110 *
+ }
+ break;
+
+- case 0x0008: // Hauppauge/TT DVB-T
+-
+- av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+- if (av7110->fe) {
+- av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+- }
+- break;
+-
+ case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
+
+- av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
+@@ -2214,12 +2219,12 @@ static int frontend_init(struct av7110 *
+
+ case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
+ /* ALPS BSBE1 */
+- av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
++ av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+- if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
++ if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) {
+ printk("dvb-ttpci: LNBP21 not found!\n");
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
+@@ -2255,8 +2260,7 @@ static int frontend_init(struct av7110 *
+ ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
+ if (ret < 0) {
+ printk("av7110: Frontend registration failed!\n");
+- if (av7110->fe->ops.release)
+- av7110->fe->ops.release(av7110->fe);
++ dvb_frontend_detach(av7110->fe);
+ av7110->fe = NULL;
+ }
+ }
+@@ -2823,7 +2827,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+
+ static struct saa7146_extension av7110_extension = {
+- .name = "dvb\0",
++ .name = "dvb",
+ .flags = SAA7146_I2C_SHORT_DELAY,
+
+ .module = THIS_MODULE,
+diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
+index 0f3a044..8c577cf 100644
+--- a/drivers/media/dvb/ttpci/av7110_av.c
++++ b/drivers/media/dvb/ttpci/av7110_av.c
+@@ -33,7 +33,6 @@
+ #include <linux/string.h>
+ #include <linux/sched.h>
+ #include <linux/delay.h>
+-#include <linux/byteorder/swabb.h>
+ #include <linux/smp_lock.h>
+ #include <linux/fs.h>
+
+diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
+index 6079e88..dd9aee3 100644
+--- a/drivers/media/dvb/ttpci/av7110_ca.c
++++ b/drivers/media/dvb/ttpci/av7110_ca.c
+@@ -35,7 +35,6 @@
+ #include <linux/fs.h>
+ #include <linux/timer.h>
+ #include <linux/poll.h>
+-#include <linux/byteorder/swabb.h>
+ #include <linux/smp_lock.h>
+
+ #include "av7110.h"
+diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
+index 75736f2..37de2e8 100644
+--- a/drivers/media/dvb/ttpci/av7110_hw.c
++++ b/drivers/media/dvb/ttpci/av7110_hw.c
+@@ -34,7 +34,6 @@
+ #include <linux/string.h>
+ #include <linux/sched.h>
+ #include <linux/delay.h>
+-#include <linux/byteorder/swabb.h>
+ #include <linux/smp_lock.h>
+ #include <linux/fs.h>
+
+diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
+index 6ffe53f..10cfe31 100644
+--- a/drivers/media/dvb/ttpci/av7110_v4l.c
++++ b/drivers/media/dvb/ttpci/av7110_v4l.c
+@@ -32,7 +32,6 @@
+ #include <linux/fs.h>
+ #include <linux/timer.h>
+ #include <linux/poll.h>
+-#include <linux/byteorder/swabb.h>
+ #include <linux/smp_lock.h>
+
+ #include "av7110.h"
+@@ -922,7 +921,7 @@ static struct saa7146_ext_vv av7110_vv_d
+ static struct saa7146_ext_vv av7110_vv_data_c = {
+ .inputs = 1,
+ .audios = 1,
+- .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
++ .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
+ .flags = SAA7146_USE_PORT_B_FOR_VBI,
+
+ .stds = &standard[0],
+diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
+index 2d21fec..2235ff8 100644
+--- a/drivers/media/dvb/ttpci/budget-av.c
++++ b/drivers/media/dvb/ttpci/budget-av.c
+@@ -37,6 +37,7 @@
+ #include "stv0299.h"
+ #include "tda10021.h"
+ #include "tda1004x.h"
++#include "tua6100.h"
+ #include "dvb-pll.h"
+ #include <media/saa7146_vv.h>
+ #include <linux/module.h>
+@@ -235,7 +236,7 @@ static int ciintf_slot_reset(struct dvb_
+
+ /* set tda10021 back to original clock configuration on reset */
+ if (budget_av->tda10021_poclkp) {
+- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
++ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
+ }
+
+@@ -257,7 +258,7 @@ static int ciintf_slot_shutdown(struct d
+
+ /* set tda10021 back to original clock configuration when cam removed */
+ if (budget_av->tda10021_poclkp) {
+- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
++ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
+ }
+ return 0;
+@@ -277,7 +278,7 @@ static int ciintf_slot_ts_enable(struct
+
+ /* tda10021 seems to need a different TS clock config when data is routed to the CAM */
+ if (budget_av->tda10021_poclkp) {
+- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
++ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ budget_av->tda10021_ts_enabled = 1;
+ }
+
+@@ -548,144 +549,6 @@ static int philips_su1278_ty_ci_tuner_se
+ return 0;
+ }
+
+-#define MIN2(a,b) ((a) < (b) ? (a) : (b))
+-#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
+-
+-static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
+- struct dvb_frontend_parameters *params)
+-{
+- u8 reg0 [2] = { 0x00, 0x00 };
+- u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
+- u8 reg2 [3] = { 0x02, 0x00, 0x00 };
+- int _fband;
+- int first_ZF;
+- int R, A, N, P, M;
+- struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
+- int freq = params->frequency;
+- struct budget *budget = (struct budget *) fe->dvb->priv;
+-
+- first_ZF = (freq) / 1000;
+-
+- if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
+- abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
+- _fband = 2;
+- else
+- _fband = 3;
+-
+- if (_fband == 2) {
+- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+- ((first_ZF >= 1430) && (first_ZF < 1950)))
+- reg0[1] = 0x07;
+- else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
+- ((first_ZF >= 1950) && (first_ZF < 2150)))
+- reg0[1] = 0x0B;
+- }
+-
+- if(_fband == 3) {
+- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+- ((first_ZF >= 1455) && (first_ZF < 1950)))
+- reg0[1] = 0x07;
+- else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
+- ((first_ZF >= 1950) && (first_ZF < 2150)))
+- reg0[1] = 0x0B;
+- else if ((first_ZF >= 1420) && (first_ZF < 1455))
+- reg0[1] = 0x0F;
+- }
+-
+- if (first_ZF > 1525)
+- reg1[1] |= 0x80;
+- else
+- reg1[1] &= 0x7F;
+-
+- if (_fband == 2) {
+- if (first_ZF > 1430) { /* 1430MHZ */
+- reg1[1] &= 0xCF; /* N2 */
+- reg2[1] &= 0xCF; /* R2 */
+- reg2[1] |= 0x10;
+- } else {
+- reg1[1] &= 0xCF; /* N2 */
+- reg1[1] |= 0x20;
+- reg2[1] &= 0xCF; /* R2 */
+- reg2[1] |= 0x10;
+- }
+- }
+-
+- if (_fband == 3) {
+- if ((first_ZF >= 1455) &&
+- (first_ZF < 1630)) {
+- reg1[1] &= 0xCF; /* N2 */
+- reg1[1] |= 0x20;
+- reg2[1] &= 0xCF; /* R2 */
+- } else {
+- if (first_ZF < 1455) {
+- reg1[1] &= 0xCF; /* N2 */
+- reg1[1] |= 0x20;
+- reg2[1] &= 0xCF; /* R2 */
+- reg2[1] |= 0x10;
+- } else {
+- if (first_ZF >= 1630) {
+- reg1[1] &= 0xCF; /* N2 */
+- reg2[1] &= 0xCF; /* R2 */
+- reg2[1] |= 0x10;
+- }
+- }
+- }
+- }
+-
+- /* set ports, enable P0 for symbol rates > 4Ms/s */
+- if (params->u.qpsk.symbol_rate >= 4000000)
+- reg1[1] |= 0x0c;
+- else
+- reg1[1] |= 0x04;
+-
+- reg2[1] |= 0x0c;
+-
+- R = 64;
+- A = 64;
+- P = 64; //32
+-
+- M = (freq * R) / 4; /* in Mhz */
+- N = (M - A * 1000) / (P * 1000);
+-
+- reg1[1] |= (N >> 9) & 0x03;
+- reg1[2] = (N >> 1) & 0xff;
+- reg1[3] = (N << 7) & 0x80;
+-
+- reg2[1] |= (R >> 8) & 0x03;
+- reg2[2] = R & 0xFF; /* R */
+-
+- reg1[3] |= A & 0x7f; /* A */
+-
+- if (P == 64)
+- reg1[1] |= 0x40; /* Prescaler 64/65 */
+-
+- reg0[1] |= 0x03;
+-
+- /* already enabled - do not reenable i2c repeater or TX fails */
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- msg.buf = reg0;
+- msg.len = sizeof(reg0);
+- if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+- return -EIO;
+-
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- msg.buf = reg1;
+- msg.len = sizeof(reg1);
+- if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+- return -EIO;
+-
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- msg.buf = reg2;
+- msg.len = sizeof(reg2);
+- if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+- return -EIO;
+-
+- return 0;
+-}
+-
+ static u8 typhoon_cinergy1200s_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+@@ -1068,9 +931,9 @@ static int tda10021_set_frontend(struct
+
+ result = budget_av->tda10021_set_frontend(fe, p);
+ if (budget_av->tda10021_ts_enabled) {
+- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
++ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ } else {
+- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
++ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ }
+
+ return result;
+@@ -1096,15 +959,16 @@ static void frontend_init(struct budget_
+ switch (saa->pci->subsystem_device) {
+
+ case SUBID_DVBS_KNC1:
++ case SUBID_DVBS_KNC1_PLUS:
+ case SUBID_DVBS_EASYWATCH_1:
+ if (saa->pci->subsystem_vendor == 0x1894) {
+- fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
++ fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config,
+ &budget_av->budget.i2c_adap);
+ if (fe) {
+- fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
++ dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap);
+ }
+ } else {
+- fe = stv0299_attach(&typhoon_config,
++ fe = dvb_attach(stv0299_attach, &typhoon_config,
+ &budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+@@ -1116,16 +980,15 @@ static void frontend_init(struct budget_
+ case SUBID_DVBS_TV_STAR_CI:
+ case SUBID_DVBS_CYNERGY1200N:
+ case SUBID_DVBS_EASYWATCH:
+- fe = stv0299_attach(&philips_sd1878_config,
++ fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
+ &budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ }
+ break;
+
+- case SUBID_DVBS_KNC1_PLUS:
+ case SUBID_DVBS_TYPHOON:
+- fe = stv0299_attach(&typhoon_config,
++ fe = dvb_attach(stv0299_attach, &typhoon_config,
+ &budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+@@ -1133,7 +996,7 @@ static void frontend_init(struct budget_
+ break;
+
+ case SUBID_DVBS_CINERGY1200:
+- fe = stv0299_attach(&cinergy_1200s_config,
++ fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
+ &budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+@@ -1141,19 +1004,10 @@ static void frontend_init(struct budget_
+ break;
+
+ case SUBID_DVBC_KNC1:
+- budget_av->reinitialise_demod = 1;
+- fe = tda10021_attach(&philips_cu1216_config,
+- &budget_av->budget.i2c_adap,
+- read_pwm(budget_av));
+- if (fe) {
+- fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+- }
+- break;
+-
+ case SUBID_DVBC_KNC1_PLUS:
+ case SUBID_DVBC_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
+- fe = tda10021_attach(&philips_cu1216_config,
++ fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
+ &budget_av->budget.i2c_adap,
+ read_pwm(budget_av));
+ if (fe) {
+@@ -1168,7 +1022,7 @@ static void frontend_init(struct budget_
+ case SUBID_DVBT_KNC1_PLUS:
+ case SUBID_DVBT_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
+- fe = tda10046_attach(&philips_tu1216_config,
++ fe = dvb_attach(tda10046_attach, &philips_tu1216_config,
+ &budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+@@ -1192,8 +1046,7 @@ static void frontend_init(struct budget_
+ if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
+ budget_av->budget.dvb_frontend)) {
+ printk(KERN_ERR "budget-av: Frontend registration failed!\n");
+- if (budget_av->budget.dvb_frontend->ops.release)
+- budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
++ dvb_frontend_detach(budget_av->budget.dvb_frontend);
+ budget_av->budget.dvb_frontend = NULL;
+ }
+ }
+@@ -1227,8 +1080,10 @@ static int budget_av_detach(struct saa71
+ if (budget_av->budget.ci_present)
+ ciintf_deinit(budget_av);
+
+- if (budget_av->budget.dvb_frontend != NULL)
++ if (budget_av->budget.dvb_frontend != NULL) {
+ dvb_unregister_frontend(budget_av->budget.dvb_frontend);
++ dvb_frontend_detach(budget_av->budget.dvb_frontend);
++ }
+ err = ttpci_budget_deinit(&budget_av->budget);
+
+ kfree(budget_av);
+@@ -1400,6 +1255,7 @@ static struct pci_device_id pci_tbl[] =
+ MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
+ MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
+ MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
++ MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),
+ MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
+ MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
+ MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
+index ffbbb3e..cd5ec48 100644
+--- a/drivers/media/dvb/ttpci/budget-ci.c
++++ b/drivers/media/dvb/ttpci/budget-ci.c
+@@ -46,7 +46,14 @@
+ #include "bsbe1.h"
+ #include "bsru6.h"
+
+-#define DEBIADDR_IR 0x1234
++/*
++ * Regarding DEBIADDR_IR:
++ * Some CI modules hang if random addresses are read.
++ * Using address 0x4000 for the IR read means that we
++ * use the same address as for CI version, which should
++ * be a safe default.
++ */
++#define DEBIADDR_IR 0x4000
+ #define DEBIADDR_CICONTROL 0x0000
+ #define DEBIADDR_CIVERSION 0x4000
+ #define DEBIADDR_IO 0x1000
+@@ -749,17 +756,17 @@ static int philips_tdm1316l_tuner_set_pa
+ // setup PLL filter and TDA9889
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+- tda1004x_write_byte(fe, 0x0C, 0x14);
++ tda1004x_writereg(fe, 0x0C, 0x14);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+- tda1004x_write_byte(fe, 0x0C, 0x80);
++ tda1004x_writereg(fe, 0x0C, 0x80);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+- tda1004x_write_byte(fe, 0x0C, 0x14);
++ tda1004x_writereg(fe, 0x0C, 0x14);
+ filter = 1;
+ break;
+
+@@ -988,7 +995,7 @@ static void frontend_init(struct budget_
+ switch (budget_ci->budget.dev->pci->subsystem_device) {
+ case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
+ budget_ci->budget.dvb_frontend =
+- stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
++ dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+@@ -998,7 +1005,7 @@ static void frontend_init(struct budget_
+
+ case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
+ budget_ci->budget.dvb_frontend =
+- stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
++ dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
+ break;
+@@ -1008,7 +1015,7 @@ static void frontend_init(struct budget_
+ case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
+ budget_ci->tuner_pll_address = 0x61;
+ budget_ci->budget.dvb_frontend =
+- stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
++ dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
+ break;
+@@ -1018,7 +1025,7 @@ static void frontend_init(struct budget_
+ 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);
++ dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
+@@ -1028,8 +1035,9 @@ static void frontend_init(struct budget_
+
+ case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
+ budget_ci->tuner_pll_address = 0x60;
++ philips_tdm1316l_config.invert = 1;
+ budget_ci->budget.dvb_frontend =
+- tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
++ dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
+@@ -1038,16 +1046,15 @@ static void frontend_init(struct budget_
+ break;
+
+ case 0x1017: // TT S-1500 PCI
+- budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
++ budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+ budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+- if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
++ if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
+ printk("%s: No LNBP21 found!\n", __FUNCTION__);
+- if (budget_ci->budget.dvb_frontend->ops.release)
+- budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
++ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
+@@ -1065,8 +1072,7 @@ static void frontend_init(struct budget_
+ if (dvb_register_frontend
+ (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+ printk("budget-ci: Frontend registration failed!\n");
+- if (budget_ci->budget.dvb_frontend->ops.release)
+- budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
++ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
+@@ -1114,8 +1120,10 @@ static int budget_ci_detach(struct saa71
+
+ if (budget_ci->budget.ci_present)
+ ciintf_deinit(budget_ci);
+- if (budget_ci->budget.dvb_frontend)
++ if (budget_ci->budget.dvb_frontend) {
+ dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
++ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
++ }
+ err = ttpci_budget_deinit(&budget_ci->budget);
+
+ tasklet_kill(&budget_ci->msp430_irq_tasklet);
+@@ -1153,7 +1161,7 @@ static struct pci_device_id pci_tbl[] =
+ MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+ static struct saa7146_extension budget_extension = {
+- .name = "budget_ci dvb\0",
++ .name = "budget_ci dvb",
+ .flags = SAA7146_I2C_SHORT_DELAY,
+
+ .module = THIS_MODULE,
+diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
+index 5722744..fc1267b 100644
+--- a/drivers/media/dvb/ttpci/budget-patch.c
++++ b/drivers/media/dvb/ttpci/budget-patch.c
+@@ -325,7 +325,7 @@ static void frontend_init(struct budget_
+ case 0x1013: // SATELCO Multimedia PCI
+
+ // try the ALPS BSRV2 first of all
+- budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+@@ -335,7 +335,7 @@ static void frontend_init(struct budget_
+ }
+
+ // try the ALPS BSRU6 now
+- budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+@@ -347,7 +347,7 @@ static void frontend_init(struct budget_
+ }
+
+ // Try the grundig 29504-451
+- budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+@@ -367,8 +367,7 @@ static void frontend_init(struct budget_
+ } else {
+ if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
+ printk("budget-av: Frontend registration failed!\n");
+- if (budget->dvb_frontend->ops.release)
+- budget->dvb_frontend->ops.release(budget->dvb_frontend);
++ dvb_frontend_detach(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ }
+ }
+@@ -627,8 +626,10 @@ static int budget_patch_detach (struct s
+ struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
+ int err;
+
+- if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
+-
++ if (budget->dvb_frontend) {
++ dvb_unregister_frontend(budget->dvb_frontend);
++ dvb_frontend_detach(budget->dvb_frontend);
++ }
+ err = ttpci_budget_deinit (budget);
+
+ kfree (budget);
+@@ -647,7 +648,7 @@ static void __exit budget_patch_exit(voi
+ }
+
+ static struct saa7146_extension budget_extension = {
+- .name = "budget_patch dvb\0",
++ .name = "budget_patch dvb",
+ .flags = 0,
+
+ .module = THIS_MODULE,
+diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
+index 863dffb..e58f039 100644
+--- a/drivers/media/dvb/ttpci/budget.c
++++ b/drivers/media/dvb/ttpci/budget.c
+@@ -41,6 +41,8 @@
+ #include "l64781.h"
+ #include "tda8083.h"
+ #include "s5h1420.h"
++#include "tda10086.h"
++#include "tda826x.h"
+ #include "lnbp21.h"
+ #include "bsru6.h"
+
+@@ -342,6 +344,11 @@ static struct s5h1420_config s5h1420_con
+ .invert = 1,
+ };
+
++static struct tda10086_config tda10086_config = {
++ .demod_address = 0x0e,
++ .invert = 0,
++};
++
+ static u8 read_pwm(struct budget* budget)
+ {
+ u8 b = 0xff;
+@@ -361,7 +368,7 @@ static void frontend_init(struct budget
+ case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+ case 0x1013:
+ // try the ALPS BSRV2 first of all
+- budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+@@ -371,7 +378,7 @@ static void frontend_init(struct budget
+ }
+
+ // try the ALPS BSRU6 now
+- budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+@@ -381,7 +388,7 @@ static void frontend_init(struct budget
+
+ case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+- budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
++ budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+@@ -390,7 +397,7 @@ static void frontend_init(struct budget
+
+ case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+- budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ break;
+@@ -398,7 +405,7 @@ static void frontend_init(struct budget
+ break;
+
+ case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
+- budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+@@ -408,7 +415,7 @@ static void frontend_init(struct budget
+ break;
+
+ case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
+- budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+@@ -417,10 +424,28 @@ static void frontend_init(struct budget
+ break;
+
+ case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
+- budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
++ budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+- if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
++ if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
++ printk("%s: No LNBP21 found!\n", __FUNCTION__);
++ goto error_out;
++ }
++ break;
++ }
++
++ case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
++ // gpio2 is connected to CLB - reset it + leave it high
++ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
++ msleep(1);
++ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
++ msleep(1);
++
++ budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
++ if (budget->dvb_frontend) {
++ if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
++ printk("%s: No tda826x found!\n", __FUNCTION__);
++ if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+ printk("%s: No LNBP21 found!\n", __FUNCTION__);
+ goto error_out;
+ }
+@@ -442,8 +467,7 @@ static void frontend_init(struct budget
+
+ error_out:
+ printk("budget: Frontend registration failed!\n");
+- if (budget->dvb_frontend->ops.release)
+- budget->dvb_frontend->ops.release(budget->dvb_frontend);
++ dvb_frontend_detach(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ return;
+ }
+@@ -481,7 +505,10 @@ static int budget_detach (struct saa7146
+ struct budget *budget = (struct budget*) dev->ext_priv;
+ int err;
+
+- if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
++ if (budget->dvb_frontend) {
++ dvb_unregister_frontend(budget->dvb_frontend);
++ dvb_frontend_detach(budget->dvb_frontend);
++ }
+
+ err = ttpci_budget_deinit (budget);
+
+@@ -497,6 +524,7 @@ MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-
+ MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
+ MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
+ MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
++MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
+ MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
+ MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
+
+@@ -506,6 +534,7 @@ static struct pci_device_id pci_tbl[] =
+ MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
+ MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
++ MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
+ MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
+ MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
+ {
+@@ -516,7 +545,7 @@ static struct pci_device_id pci_tbl[] =
+ MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+ static struct saa7146_extension budget_extension = {
+- .name = "budget dvb\0",
++ .name = "budget dvb",
+ .flags = SAA7146_I2C_SHORT_DELAY,
+
+ .module = THIS_MODULE,
+diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
+index 46a6a60..e78ea92 100644
+--- a/drivers/media/dvb/ttusb-budget/Kconfig
++++ b/drivers/media/dvb/ttusb-budget/Kconfig
+@@ -2,13 +2,13 @@ config DVB_TTUSB_BUDGET
+ tristate "Technotrend/Hauppauge Nova-USB devices"
+ depends on DVB_CORE && USB && I2C
+ select DVB_PLL
+- select DVB_CX22700
+- select DVB_TDA1004X
+- select DVB_VES1820
+- select DVB_TDA8083
+- select DVB_STV0299
+- select DVB_STV0297
+- select DVB_LNBP21
++ select DVB_CX22700 if !DVB_FE_CUSTOMISE
++ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
++ select DVB_VES1820 if !DVB_FE_CUSTOMISE
++ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
++ select DVB_STV0299 if !DVB_FE_CUSTOMISE
++ select DVB_STV0297 if !DVB_FE_CUSTOMISE
++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ help
+ Support for external USB adapters designed by Technotrend and
+ produced by Hauppauge, shipped under the brand name 'Nova-USB'.
+diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+index 04cef30..60820de 100644
+--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
++++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+@@ -732,7 +732,7 @@ static void ttusb_process_frame(struct t
+ }
+ }
+
+-static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs)
++static void ttusb_iso_irq(struct urb *urb)
+ {
+ struct ttusb *ttusb = urb->context;
+
+@@ -1107,17 +1107,17 @@ static int philips_tdm1316l_tuner_set_pa
+ // setup PLL filter
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+- tda1004x_write_byte(fe, 0x0C, 0);
++ tda1004x_writereg(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+- tda1004x_write_byte(fe, 0x0C, 0);
++ tda1004x_writereg(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+- tda1004x_write_byte(fe, 0x0C, 0xFF);
++ tda1004x_writereg(fe, 0x0C, 0xFF);
+ filter = 1;
+ break;
+
+@@ -1564,13 +1564,13 @@ static void frontend_init(struct ttusb*
+ switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
+ case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
+ // try the stv0299 based first
+- ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
++ ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
+
+ if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
+ alps_stv0299_config.inittab = alps_bsbe1_inittab;
+- lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
++ dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0);
+ } else { // ALPS BSRU6
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
+ }
+@@ -1578,7 +1578,7 @@ static void frontend_init(struct ttusb*
+ }
+
+ // Grundig 29504-491
+- ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
++ ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
+@@ -1587,13 +1587,13 @@ static void frontend_init(struct 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));
++ ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
+
+- ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
++ ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
+ break;
+@@ -1602,14 +1602,14 @@ static void frontend_init(struct ttusb*
+
+ 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);
++ ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
+ break;
+ }
+
+ // Philips td1316
+- ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
++ ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
+@@ -1625,8 +1625,7 @@ static void frontend_init(struct ttusb*
+ } else {
+ if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
+ printk("dvb-ttusb-budget: Frontend registration failed!\n");
+- if (ttusb->fe->ops.release)
+- ttusb->fe->ops.release(ttusb->fe);
++ dvb_frontend_detach(ttusb->fe);
+ ttusb->fe = NULL;
+ }
+ }
+@@ -1763,7 +1762,10 @@ static void ttusb_disconnect(struct usb_
+ dvb_net_release(&ttusb->dvbnet);
+ dvb_dmxdev_release(&ttusb->dmxdev);
+ dvb_dmx_release(&ttusb->dvb_demux);
+- if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
++ if (ttusb->fe != NULL) {
++ dvb_unregister_frontend(ttusb->fe);
++ dvb_frontend_detach(ttusb->fe);
++ }
+ i2c_del_adapter(&ttusb->i2c_adap);
+ dvb_unregister_adapter(&ttusb->adapter);
+
+diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+index 6c1cb77..a1c9fa9 100644
+--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
++++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+@@ -203,7 +203,7 @@ static u16 rc_keys[] = {
+ static void ttusb_dec_set_model(struct ttusb_dec *dec,
+ enum ttusb_dec_model model);
+
+-static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
++static void ttusb_dec_handle_irq( struct urb *urb)
+ {
+ struct ttusb_dec * dec = urb->context;
+ char *buffer = dec->irq_buffer;
+@@ -215,7 +215,7 @@ static void ttusb_dec_handle_irq( struct
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+- case -ETIMEDOUT:
++ case -ETIME:
+ /* this urb is dead, cleanup */
+ dprintk("%s:urb shutting down with status: %d\n",
+ __FUNCTION__, urb->status);
+@@ -755,7 +755,7 @@ static void ttusb_dec_process_urb_frame_
+ }
+ }
+
+-static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)
++static void ttusb_dec_process_urb(struct urb *urb)
+ {
+ struct ttusb_dec *dec = urb->context;
+
+@@ -1512,7 +1512,11 @@ static void ttusb_dec_exit_dvb(struct tt
+ dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
+ dvb_dmxdev_release(&dec->dmxdev);
+ dvb_dmx_release(&dec->demux);
+- if (dec->fe) dvb_unregister_frontend(dec->fe);
++ if (dec->fe) {
++ dvb_unregister_frontend(dec->fe);
++ if (dec->fe->ops.release)
++ dec->fe->ops.release(dec->fe);
++ }
+ dvb_unregister_adapter(&dec->adapter);
+ }
+
+diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
+index 220076b..6d96b17 100644
+--- a/drivers/media/radio/Kconfig
++++ b/drivers/media/radio/Kconfig
+@@ -7,7 +7,7 @@ menu "Radio Adapters"
+
+ config RADIO_CADET
+ tristate "ADS Cadet AM/FM Tuner"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these AM/FM radio cards, and then
+ fill in the port address below.
+@@ -25,7 +25,7 @@ config RADIO_CADET
+
+ config RADIO_RTRACK
+ tristate "AIMSlab RadioTrack (aka RadioReveal) support"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address below.
+@@ -59,7 +59,7 @@ config RADIO_RTRACK_PORT
+
+ config RADIO_RTRACK2
+ tristate "AIMSlab RadioTrack II support"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have this FM radio card, and then fill in the
+ port address below.
+@@ -82,7 +82,7 @@ config RADIO_RTRACK2_PORT
+
+ config RADIO_AZTECH
+ tristate "Aztech/Packard Bell Radio"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address below.
+@@ -106,7 +106,7 @@ config RADIO_AZTECH_PORT
+
+ config RADIO_GEMTEK
+ tristate "GemTek Radio Card support"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have this FM radio card, and then fill in the
+ port address below.
+@@ -131,7 +131,7 @@ config RADIO_GEMTEK_PORT
+
+ config RADIO_GEMTEK_PCI
+ tristate "GemTek PCI Radio Card support"
+- depends on VIDEO_V4L1 && PCI
++ depends on VIDEO_V4L2 && PCI
+ ---help---
+ Choose Y here if you have this PCI FM radio card.
+
+@@ -145,7 +145,7 @@ config RADIO_GEMTEK_PCI
+
+ config RADIO_MAXIRADIO
+ tristate "Guillemot MAXI Radio FM 2000 radio"
+- depends on VIDEO_V4L1 && PCI
++ depends on VIDEO_V4L2 && PCI
+ ---help---
+ Choose Y here if you have this radio card. This card may also be
+ found as Gemtek PCI FM.
+@@ -160,7 +160,7 @@ config RADIO_MAXIRADIO
+
+ config RADIO_MAESTRO
+ tristate "Maestro on board radio"
+- depends on VIDEO_V4L1
++ depends on VIDEO_V4L2 && PCI
+ ---help---
+ Say Y here to directly support the on-board radio tuner on the
+ Maestro 2 or 2E sound card.
+@@ -195,8 +195,7 @@ config RADIO_MIROPCM20_RDS
+ ---help---
+ Choose Y here if you want to see RDS/RBDS information like
+ RadioText, Programme Service name, Clock Time and date, Programme
+- TYpe and Traffic Announcement/Programme identification. You also
+- need to say Y to "miroSOUND PCM20 radio" and devfs!
++ Type and Traffic Announcement/Programme identification.
+
+ It's not possible to read the raw RDS packets from the device, so
+ the driver cant provide an V4L interface for this. But the
+@@ -208,7 +207,7 @@ config RADIO_MIROPCM20_RDS
+
+ config RADIO_SF16FMI
+ tristate "SF16FMI Radio"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards. If you
+ compile the driver into the kernel and your card is not PnP one, you
+@@ -225,7 +224,7 @@ config RADIO_SF16FMI
+
+ config RADIO_SF16FMR2
+ tristate "SF16FMR2 Radio"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards.
+
+@@ -239,7 +238,7 @@ config RADIO_SF16FMR2
+
+ config RADIO_TERRATEC
+ tristate "TerraTec ActiveRadio ISA Standalone"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have this FM radio card, and then fill in the
+ port address below. (TODO)
+@@ -268,7 +267,7 @@ config RADIO_TERRATEC_PORT
+
+ config RADIO_TRUST
+ tristate "Trust FM radio card"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ help
+ This is a driver for the Trust FM radio cards. Say Y if you have
+ such a card and want to use it under Linux.
+@@ -286,7 +285,7 @@ config RADIO_TRUST_PORT
+
+ config RADIO_TYPHOON
+ tristate "Typhoon Radio (a.k.a. EcoRadio)"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address and the frequency used for muting below.
+@@ -330,7 +329,7 @@ config RADIO_TYPHOON_MUTEFREQ
+
+ config RADIO_ZOLTRIX
+ tristate "Zoltrix Radio"
+- depends on ISA && VIDEO_V4L1
++ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address below.
+@@ -352,7 +351,7 @@ config RADIO_ZOLTRIX_PORT
+
+ config USB_DSBR
+ tristate "D-Link USB FM radio support (EXPERIMENTAL)"
+- depends on USB && VIDEO_V4L1 && EXPERIMENTAL
++ depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+ ---help---
+ Say Y here if you want to connect this type of radio to your
+ computer's USB port. Note that the audio is not digital, and
+diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
+index f7e33f9..db865a0 100644
+--- a/drivers/media/radio/dsbr100.c
++++ b/drivers/media/radio/dsbr100.c
+@@ -33,8 +33,14 @@
+
+ History:
+
++ Version 0.41-ac1:
++ Alan Cox: Some cleanups and fixes
++
++ Version 0.41:
++ Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
++
+ Version 0.40:
+- Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
++ Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+
+ Version 0.30:
+ Markus: Updates for 2.5.x kernel and more ISO compliant source
+@@ -65,13 +71,12 @@
+
+ */
+
+-
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/input.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+ #include <linux/usb.h>
+ #include <linux/smp_lock.h>
+@@ -79,7 +84,22 @@
+ /*
+ * Version Information
+ */
+-#define DRIVER_VERSION "v0.40"
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++
++#define DRIVER_VERSION "v0.41"
++#define RADIO_VERSION KERNEL_VERSION(0,4,1)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ }
++};
++
+ #define DRIVER_AUTHOR "Markus Demleitner <msdemlei at tucana.harvard.edu>"
+ #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
+
+@@ -111,7 +131,7 @@ static int radio_nr = -1;
+ module_param(radio_nr, int, 0);
+
+ /* Data for one (physical) device */
+-typedef struct {
++struct dsbr100_device {
+ struct usb_device *usbdev;
+ struct video_device *videodev;
+ unsigned char transfer_buffer[TB_LEN];
+@@ -119,7 +139,8 @@ typedef struct {
+ int stereo;
+ int users;
+ int removed;
+-} dsbr100_device;
++ int muted;
++};
+
+
+ /* File system interface */
+@@ -138,7 +159,6 @@ static struct video_device dsbr100_video
+ .owner = THIS_MODULE,
+ .name = "D-Link DSB-R 100",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_AZTECH,
+ .fops = &usb_dsbr100_fops,
+ .release = video_device_release,
+ };
+@@ -161,7 +181,7 @@ static struct usb_driver usb_dsbr100_dri
+ /* Low-level device interface begins here */
+
+ /* switch on radio */
+-static int dsbr100_start(dsbr100_device *radio)
++static int dsbr100_start(struct dsbr100_device *radio)
+ {
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+@@ -172,12 +192,13 @@ static int dsbr100_start(dsbr100_device
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+ return -1;
++ radio->muted=0;
+ return (radio->transfer_buffer)[0];
+ }
+
+
+ /* switch off radio */
+-static int dsbr100_stop(dsbr100_device *radio)
++static int dsbr100_stop(struct dsbr100_device *radio)
+ {
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+@@ -188,11 +209,12 @@ static int dsbr100_stop(dsbr100_device *
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+ return -1;
++ radio->muted=1;
+ return (radio->transfer_buffer)[0];
+ }
+
+ /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+-static int dsbr100_setfreq(dsbr100_device *radio, int freq)
++static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
+ {
+ freq = (freq/16*80)/1000+856;
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+@@ -217,7 +239,7 @@ static int dsbr100_setfreq(dsbr100_devic
+
+ /* return the device status. This is, in effect, just whether it
+ sees a stereo signal or not. Pity. */
+-static void dsbr100_getstat(dsbr100_device *radio)
++static void dsbr100_getstat(struct dsbr100_device *radio)
+ {
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+@@ -236,9 +258,9 @@ usb if it is */
+ static int usb_dsbr100_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+- dsbr100_device *radio;
++ struct dsbr100_device *radio;
+
+- if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
++ if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
+ return -ENOMEM;
+ if (!(radio->videodev = video_device_alloc())) {
+ kfree(radio);
+@@ -271,7 +293,7 @@ code I'd expect I better did that, but i
+ leak here it's tiny (~50 bytes per disconnect) */
+ static void usb_dsbr100_disconnect(struct usb_interface *intf)
+ {
+- dsbr100_device *radio = usb_get_intfdata(intf);
++ struct dsbr100_device *radio = usb_get_intfdata(intf);
+
+ usb_set_intfdata (intf, NULL);
+ if (radio) {
+@@ -291,89 +313,121 @@ static void usb_dsbr100_disconnect(struc
+ static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+ {
+- dsbr100_device *radio=video_get_drvdata(video_devdata(file));
++ struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+ if (!radio)
+ return -EIO;
+
+ switch(cmd) {
+- case VIDIOCGCAP: {
+- struct video_capability *v = arg;
+-
+- memset(v, 0, sizeof(*v));
+- v->type = VID_TYPE_TUNER;
+- v->channels = 1;
+- v->audios = 1;
+- strcpy(v->name, "D-Link R-100 USB FM Radio");
++ case VIDIOC_QUERYCAP:
++ {
++ struct v4l2_capability *v = arg;
++ memset(v,0,sizeof(*v));
++ strlcpy(v->driver, "dsbr100", sizeof (v->driver));
++ strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER: {
+- struct video_tuner *v = arg;
++ case VIDIOC_G_TUNER:
++ {
++ struct v4l2_tuner *v = arg;
+
+- dsbr100_getstat(radio);
+- if(v->tuner) /* Only 1 tuner */
++ if (v->index > 0)
+ return -EINVAL;
++
++ dsbr100_getstat(radio);
++
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
+ v->rangelow = FREQ_MIN*FREQ_MUL;
+ v->rangehigh = FREQ_MAX*FREQ_MUL;
+- v->flags = VIDEO_TUNER_LOW;
+- v->mode = VIDEO_MODE_AUTO;
+- v->signal = radio->stereo*0x7000;
+- /* Don't know how to get signal strength */
+- v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+- strcpy(v->name, "DSB R-100");
+- return 0;
+- }
+- case VIDIOCSTUNER: {
+- struct video_tuner *v = arg;
++ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ if(radio->stereo)
++ v->audmode = V4L2_TUNER_MODE_STEREO;
++ else
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal = 0xFFFF; /* We can't get the signal strength */
+
+- if(v->tuner!=0)
+- return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
+ return 0;
+ }
+- case VIDIOCGFREQ: {
+- int *freq = arg;
++ case VIDIOC_S_TUNER:
++ {
++ struct v4l2_tuner *v = arg;
+
+- if (radio->curfreq==-1)
++ if (v->index > 0)
+ return -EINVAL;
+- *freq = radio->curfreq;
++
+ return 0;
+ }
+- case VIDIOCSFREQ: {
+- int *freq = arg;
++ case VIDIOC_S_FREQUENCY:
++ {
++ struct v4l2_frequency *f = arg;
+
+- radio->curfreq = *freq;
++ radio->curfreq = f->frequency;
+ if (dsbr100_setfreq(radio, radio->curfreq)==-1)
+ warn("Set frequency failed");
+ return 0;
+ }
+- case VIDIOCGAUDIO: {
+- struct video_audio *v = arg;
+-
+- memset(v, 0, sizeof(*v));
+- v->flags |= VIDEO_AUDIO_MUTABLE;
+- v->mode = VIDEO_SOUND_STEREO;
+- v->volume = 1;
+- v->step = 1;
+- strcpy(v->name, "Radio");
++ case VIDIOC_G_FREQUENCY:
++ {
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = radio->curfreq;
++
+ return 0;
+ }
+- case VIDIOCSAUDIO: {
+- struct video_audio *v = arg;
+-
+- if (v->audio)
+- return -EINVAL;
+- if (v->flags&VIDEO_AUDIO_MUTE) {
+- if (dsbr100_stop(radio)==-1)
+- warn("Radio did not respond properly");
++ case VIDIOC_QUERYCTRL:
++ {
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return 0;
++ }
+ }
+- else
+- if (dsbr100_start(radio)==-1)
+- warn("Radio did not respond properly");
+- return 0;
++ return -EINVAL;
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=radio->muted;
++ return 0;
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ if (dsbr100_stop(radio)==-1)
++ warn("Radio did not respond properly");
++ } else {
++ if (dsbr100_start(radio)==-1)
++ warn("Radio did not respond properly");
++ }
++ return 0;
++ }
++ return -EINVAL;
+ }
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ usb_dsbr100_do_ioctl);
+ }
+ }
+
+@@ -385,9 +439,11 @@ static int usb_dsbr100_ioctl(struct inod
+
+ static int usb_dsbr100_open(struct inode *inode, struct file *file)
+ {
+- dsbr100_device *radio=video_get_drvdata(video_devdata(file));
++ struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+ radio->users = 1;
++ radio->muted = 1;
++
+ if (dsbr100_start(radio)<0) {
+ warn("Radio did not start up properly");
+ radio->users = 0;
+@@ -399,7 +455,7 @@ static int usb_dsbr100_open(struct inode
+
+ static int usb_dsbr100_close(struct inode *inode, struct file *file)
+ {
+- dsbr100_device *radio=video_get_drvdata(video_devdata(file));
++ struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+ if (!radio)
+ return -ENODEV;
+diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
+index df22a58..3368a89 100644
+--- a/drivers/media/radio/radio-aimslab.c
++++ b/drivers/media/radio/radio-aimslab.c
+@@ -1,5 +1,6 @@
+ /* radiotrack (radioreveal) driver for Linux radio support
+ * (c) 1997 M. Kirkwood
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ * Converted to new API by Alan Cox <Alan.Cox at linux.org>
+ * Various bugfixes and enhancements by Russell Kroll <rkroll at exploits.org>
+ *
+@@ -33,11 +34,13 @@
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_RTRACK_PORT */
+ #include <asm/semaphore.h> /* Lock for the I/O */
+
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
+ #ifndef CONFIG_RADIO_RTRACK_PORT
+ #define CONFIG_RADIO_RTRACK_PORT -1
+ #endif
+@@ -209,6 +212,25 @@ static int rt_getsigstr(struct rt_device
+ return 1; /* signal present */
+ }
+
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 0xff,
++ .step = 1,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+ static int rt_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+ {
+@@ -217,73 +239,114 @@ static int rt_do_ioctl(struct inode *ino
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
+- strcpy(v->name, "RadioTrack");
++ strlcpy(v->driver, "radio-aimslab", sizeof (v->driver));
++ strlcpy(v->card, "RadioTrack", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner) /* Only 1 tuner */
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
++
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
+ v->rangelow=(87*16000);
+ v->rangehigh=(108*16000);
+- v->flags=VIDEO_TUNER_LOW;
+- v->mode=VIDEO_MODE_AUTO;
+- strcpy(v->name, "FM");
++ v->rxsubchans =V4L2_TUNER_SUB_MONO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*rt_getsigstr(rt);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- *freq = rt->curfreq;
++ struct v4l2_frequency *f = arg;
++
++ rt->curfreq = f->frequency;
++ rt_setfreq(rt, rt->curfreq);
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_G_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- rt->curfreq = *freq;
+- rt_setfreq(rt, rt->curfreq);
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = rt->curfreq;
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+- memset(v,0, sizeof(*v));
+- v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+- v->volume=rt->curvol * 6554;
+- v->step=6554;
+- strcpy(v->name, "Radio");
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+- if(v->flags&VIDEO_AUDIO_MUTE)
+- rt_mute(rt);
+- else
+- rt_setvol(rt,v->volume/6554);
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=rt->muted;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value=rt->curvol * 6554;
++ return (0);
++ }
++ return -EINVAL;
+ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ rt_mute(rt);
++ } else {
++ rt_setvol(rt,rt->curvol);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ rt_setvol(rt,ctrl->value);
++ return (0);
++ }
++ return -EINVAL;
++ }
++
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ rt_do_ioctl);
+ }
+ }
+
+@@ -309,7 +372,7 @@ static struct video_device rtrack_radio=
+ .owner = THIS_MODULE,
+ .name = "RadioTrack radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_RTRACK,
++ .hardware = 0,
+ .fops = &rtrack_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
+index 95e6322..3ba5fa8 100644
+--- a/drivers/media/radio/radio-aztech.c
++++ b/drivers/media/radio/radio-aztech.c
+@@ -1,5 +1,6 @@
+ /* radio-aztech.c - Aztech radio card driver for Linux 2.2
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ * Adapted to support the Video for Linux API by
+ * Russell Kroll <rkroll at exploits.org>. Based on original tuner code by:
+ *
+@@ -30,9 +31,30 @@
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_AZTECH_PORT */
++
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 0xff,
++ .step = 1,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
+
+ /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
+
+@@ -166,81 +188,121 @@ static int az_do_ioctl(struct inode *ino
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
+- strcpy(v->name, "Aztech Radio");
++ strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
++ strlcpy(v->card, "Aztech Radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner) /* Only 1 tuner */
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
++
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
+ v->rangelow=(87*16000);
+ v->rangehigh=(108*16000);
+- v->flags=VIDEO_TUNER_LOW;
+- v->mode=VIDEO_MODE_AUTO;
+- v->signal=0xFFFF*az_getsigstr(az);
++ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability=V4L2_TUNER_CAP_LOW;
+ if(az_getstereo(az))
+- v->flags|=VIDEO_TUNER_STEREO_ON;
+- strcpy(v->name, "FM");
++ v->audmode = V4L2_TUNER_MODE_STEREO;
++ else
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=0xFFFF*az_getsigstr(az);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- *freq = az->curfreq;
++ struct v4l2_frequency *f = arg;
++
++ az->curfreq = f->frequency;
++ az_setfreq(az, az->curfreq);
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_G_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- az->curfreq = *freq;
+- az_setfreq(az, az->curfreq);
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = az->curfreq;
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+- memset(v,0, sizeof(*v));
+- v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+- if(az->stereo)
+- v->mode=VIDEO_SOUND_STEREO;
+- else
+- v->mode=VIDEO_SOUND_MONO;
+- v->volume=az->curvol;
+- v->step=16384;
+- strcpy(v->name, "Radio");
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+- az->curvol=v->volume;
+-
+- az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
+- if(v->flags&VIDEO_AUDIO_MUTE)
+- az_setvol(az,0);
+- else
+- az_setvol(az,az->curvol);
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (az->curvol==0)
++ ctrl->value=1;
++ else
++ ctrl->value=0;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value=az->curvol * 6554;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ az_setvol(az,0);
++ } else {
++ az_setvol(az,az->curvol);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ az_setvol(az,ctrl->value);
++ return (0);
++ }
++ return -EINVAL;
+ }
++
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ az_do_ioctl);
+ }
+ }
+
+@@ -266,7 +328,7 @@ static struct video_device aztech_radio=
+ .owner = THIS_MODULE,
+ .name = "Aztech radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_AZTECH,
++ .hardware = 0,
+ .fops = &aztech_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
+index 8641aec..69d4b79 100644
+--- a/drivers/media/radio/radio-cadet.c
++++ b/drivers/media/radio/radio-cadet.c
+@@ -25,20 +25,28 @@
+ *
+ * 2003-01-31 Alan Cox <alan at redhat.com>
+ * Cleaned up locking, delay code, general odds and ends
++ *
++ * 2006-07-30 Hans J. Koch <koch at hjk-az.de>
++ * Changed API to V4L2
+ */
+
++#include <linux/version.h>
+ #include <linux/module.h> /* Modules */
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* V4L2 API defs */
+ #include <media/v4l2-common.h>
+ #include <linux/param.h>
+ #include <linux/pnp.h>
+
+ #define RDS_BUFFER 256
++#define RDS_RX_FLAG 1
++#define MBS_RX_FLAG 2
++
++#define CADET_VERSION KERNEL_VERSION(0,3,3)
+
+ static int io=-1; /* default to isapnp activation */
+ static int radio_nr = -1;
+@@ -61,44 +69,24 @@ static int cadet_probe(void);
+ */
+ static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
+
+-static int cadet_getrds(void)
+-{
+- int rdsstat=0;
+-
+- spin_lock(&cadet_io_lock);
+- outb(3,io); /* Select Decoder Control/Status */
+- outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
+- spin_unlock(&cadet_io_lock);
+-
+- msleep(100);
+-
+- spin_lock(&cadet_io_lock);
+- outb(3,io); /* Select Decoder Control/Status */
+- if((inb(io+1)&0x80)!=0) {
+- rdsstat|=VIDEO_TUNER_RDS_ON;
+- }
+- if((inb(io+1)&0x10)!=0) {
+- rdsstat|=VIDEO_TUNER_MBS_ON;
+- }
+- spin_unlock(&cadet_io_lock);
+- return rdsstat;
+-}
+
+-static int cadet_getstereo(void)
++static int
++cadet_getstereo(void)
+ {
+- int ret = 0;
++ int ret = V4L2_TUNER_SUB_MONO;
+ if(curtuner != 0) /* Only FM has stereo capability! */
+- return 0;
++ return V4L2_TUNER_SUB_MONO;
+
+ spin_lock(&cadet_io_lock);
+ outb(7,io); /* Select tuner control */
+ if( (inb(io+1) & 0x40) == 0)
+- ret = 1;
++ ret = V4L2_TUNER_SUB_STEREO;
+ spin_unlock(&cadet_io_lock);
+ return ret;
+ }
+
+-static unsigned cadet_gettune(void)
++static unsigned
++cadet_gettune(void)
+ {
+ int curvol,i;
+ unsigned fifo=0;
+@@ -135,7 +123,8 @@ static unsigned cadet_gettune(void)
+ return fifo;
+ }
+
+-static unsigned cadet_getfreq(void)
++static unsigned
++cadet_getfreq(void)
+ {
+ int i;
+ unsigned freq=0,test,fifo=0;
+@@ -167,7 +156,8 @@ static unsigned cadet_getfreq(void)
+ return freq;
+ }
+
+-static void cadet_settune(unsigned fifo)
++static void
++cadet_settune(unsigned fifo)
+ {
+ int i;
+ unsigned test;
+@@ -195,7 +185,8 @@ static void cadet_settune(unsigned fifo)
+ spin_unlock(&cadet_io_lock);
+ }
+
+-static void cadet_setfreq(unsigned freq)
++static void
++cadet_setfreq(unsigned freq)
+ {
+ unsigned fifo;
+ int i,j,test;
+@@ -255,7 +246,8 @@ static void cadet_setfreq(unsigned freq)
+ }
+
+
+-static int cadet_getvol(void)
++static int
++cadet_getvol(void)
+ {
+ int ret = 0;
+
+@@ -270,7 +262,8 @@ static int cadet_getvol(void)
+ }
+
+
+-static void cadet_setvol(int vol)
++static void
++cadet_setvol(int vol)
+ {
+ spin_lock(&cadet_io_lock);
+ outb(7,io); /* Select tuner control */
+@@ -281,7 +274,8 @@ static void cadet_setvol(int vol)
+ spin_unlock(&cadet_io_lock);
+ }
+
+-static void cadet_handler(unsigned long data)
++static void
++cadet_handler(unsigned long data)
+ {
+ /*
+ * Service the RDS fifo
+@@ -322,8 +316,8 @@ static void cadet_handler(unsigned long
+
+
+
+-static ssize_t cadet_read(struct file *file, char __user *data,
+- size_t count, loff_t *ppos)
++static ssize_t
++cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+ {
+ int i=0;
+ unsigned char readbuf[RDS_BUFFER];
+@@ -359,128 +353,156 @@ static int cadet_do_ioctl(struct inode *
+ {
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
+- memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=2;
+- v->audios=1;
+- strcpy(v->name, "ADS Cadet");
++ struct v4l2_capability *cap = arg;
++ memset(cap,0,sizeof(*cap));
++ cap->capabilities =
++ V4L2_CAP_TUNER |
++ V4L2_CAP_READWRITE;
++ cap->version = CADET_VERSION;
++ strcpy(cap->driver, "ADS Cadet");
++ strcpy(cap->card, "ADS Cadet");
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if((v->tuner<0)||(v->tuner>1)) {
+- return -EINVAL;
+- }
+- switch(v->tuner) {
+- case 0:
+- strcpy(v->name,"FM");
+- v->rangelow=1400; /* 87.5 MHz */
+- v->rangehigh=1728; /* 108.0 MHz */
+- v->flags=0;
+- v->mode=0;
+- v->mode|=VIDEO_MODE_AUTO;
+- v->signal=sigstrength;
+- if(cadet_getstereo()==1) {
+- v->flags|=VIDEO_TUNER_STEREO_ON;
+- }
+- v->flags|=cadet_getrds();
+- break;
+- case 1:
+- strcpy(v->name,"AM");
+- v->rangelow=8320; /* 520 kHz */
+- v->rangehigh=26400; /* 1650 kHz */
+- v->flags=0;
+- v->flags|=VIDEO_TUNER_LOW;
+- v->mode=0;
+- v->mode|=VIDEO_MODE_AUTO;
+- v->signal=sigstrength;
+- break;
++ struct v4l2_tuner *t = arg;
++ memset(t,0,sizeof(*t));
++ t->type = V4L2_TUNER_RADIO;
++ switch (t->index)
++ {
++ case 0: strcpy(t->name, "FM");
++ t->capability = V4L2_TUNER_CAP_STEREO;
++ t->rangelow = 1400; /* 87.5 MHz */
++ t->rangehigh = 1728; /* 108.0 MHz */
++ t->rxsubchans=cadet_getstereo();
++ switch (t->rxsubchans){
++ case V4L2_TUNER_SUB_MONO:
++ t->audmode = V4L2_TUNER_MODE_MONO;
++ break;
++ case V4L2_TUNER_SUB_STEREO:
++ t->audmode = V4L2_TUNER_MODE_STEREO;
++ break;
++ default: ;
++ }
++ break;
++ case 1: strcpy(t->name, "AM");
++ t->capability = V4L2_TUNER_CAP_LOW;
++ t->rangelow = 8320; /* 520 kHz */
++ t->rangehigh = 26400; /* 1650 kHz */
++ t->rxsubchans = V4L2_TUNER_SUB_MONO;
++ t->audmode = V4L2_TUNER_MODE_MONO;
++ break;
++ default:
++ return -EINVAL;
+ }
++
++ t->signal = sigstrength; /* We might need to modify scaling of this */
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if((v->tuner<0)||(v->tuner>1)) {
++ struct v4l2_tuner *t = arg;
++ if((t->index != 0)&&(t->index != 1))
+ return -EINVAL;
+- }
+- curtuner=v->tuner;
++
++ curtuner = t->index;
+ return 0;
+ }
+- case VIDIOCGFREQ:
++ case VIDIOC_G_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- *freq = cadet_getfreq();
++ struct v4l2_frequency *f = arg;
++ memset(f,0,sizeof(*f));
++ f->tuner = curtuner;
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = cadet_getfreq();
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
++ struct v4l2_frequency *f = arg;
++ if (f->type != V4L2_TUNER_RADIO){
++ return -EINVAL;
++ }
++ if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728))) {
+ return -EINVAL;
+ }
+- if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
++ if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400))) {
+ return -EINVAL;
+ }
+- cadet_setfreq(*freq);
++ cadet_setfreq(f->frequency);
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *v = arg;
+- memset(v,0, sizeof(*v));
+- v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+- if(cadet_getstereo()==0) {
+- v->mode=VIDEO_SOUND_MONO;
+- } else {
+- v->mode=VIDEO_SOUND_STEREO;
++ struct v4l2_control *c = arg;
++ switch (c->id){
++ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
++ c->value = (cadet_getvol() == 0);
++ break;
++ case V4L2_CID_AUDIO_VOLUME:
++ c->value = cadet_getvol();
++ break;
++ default:
++ return -EINVAL;
+ }
+- v->volume=cadet_getvol();
+- v->step=0xffff;
+- strcpy(v->name, "Radio");
+ return 0;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_S_CTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+- cadet_setvol(v->volume);
+- if(v->flags&VIDEO_AUDIO_MUTE)
+- cadet_setvol(0);
+- else
+- cadet_setvol(0xffff);
++ struct v4l2_control *c = arg;
++ switch (c->id){
++ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
++ if (c->value) cadet_setvol(0);
++ else cadet_setvol(0xffff);
++ break;
++ case V4L2_CID_AUDIO_VOLUME:
++ cadet_setvol(c->value);
++ break;
++ default:
++ return -EINVAL;
++ }
+ return 0;
+ }
++
+ default:
+ return -ENOIOCTLCMD;
+ }
+ }
+
+-static int cadet_ioctl(struct inode *inode, struct file *file,
++static int
++cadet_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+ return video_usercopy(inode, file, cmd, arg, cadet_do_ioctl);
+ }
+
+-static int cadet_open(struct inode *inode, struct file *file)
++static int
++cadet_open(struct inode *inode, struct file *file)
+ {
+- if(users)
+- return -EBUSY;
+ users++;
+- init_waitqueue_head(&read_queue);
++ if (1 == users) init_waitqueue_head(&read_queue);
+ return 0;
+ }
+
+-static int cadet_release(struct inode *inode, struct file *file)
++static int
++cadet_release(struct inode *inode, struct file *file)
+ {
+- del_timer_sync(&readtimer);
+- rdsstat=0;
+ users--;
++ if (0 == users){
++ del_timer_sync(&readtimer);
++ rdsstat=0;
++ }
++ return 0;
++}
++
++static unsigned int
++cadet_poll(struct file *file, struct poll_table_struct *wait)
++{
++ poll_wait(file,&read_queue,wait);
++ if(rdsin != rdsout)
++ return POLLIN | POLLRDNORM;
+ return 0;
+ }
+
+@@ -491,6 +513,7 @@ static struct file_operations cadet_fops
+ .release = cadet_release,
+ .read = cadet_read,
+ .ioctl = cadet_ioctl,
++ .poll = cadet_poll,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .llseek = no_llseek,
+ };
+@@ -500,7 +523,6 @@ static struct video_device cadet_radio=
+ .owner = THIS_MODULE,
+ .name = "Cadet radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_CADET,
+ .fops = &cadet_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
+index 4c82956..eb14106 100644
+--- a/drivers/media/radio/radio-gemtek-pci.c
++++ b/drivers/media/radio/radio-gemtek-pci.c
+@@ -34,6 +34,8 @@
+ *
+ * TODO: multiple device support and portability were not tested
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
++ *
+ ***************************************************************************
+ */
+
+@@ -42,10 +44,32 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/pci.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+ #include <linux/errno.h>
+
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 65535,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+
+@@ -183,91 +207,117 @@ static int gemtek_pci_do_ioctl(struct in
+ struct gemtek_pci_card *card = dev->priv;
+
+ switch ( cmd ) {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *c = arg;
++ struct v4l2_capability *v = arg;
++ memset(v,0,sizeof(*v));
++ strlcpy(v->driver, "radio-gemtek-pci", sizeof (v->driver));
++ strlcpy(v->card, "GemTek PCI Radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
+
+- memset(c,0,sizeof(*c));
+- c->type = VID_TYPE_TUNER;
+- c->channels = 1;
+- c->audios = 1;
+- strcpy( c->name, "Gemtek PCI Radio" );
+ return 0;
+ }
+-
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *t = arg;
++ struct v4l2_tuner *v = arg;
+
+- if ( t->tuner )
++ if (v->index > 0)
+ return -EINVAL;
+
+- t->rangelow = GEMTEK_PCI_RANGE_LOW;
+- t->rangehigh = GEMTEK_PCI_RANGE_HIGH;
+- t->flags = VIDEO_TUNER_LOW;
+- t->mode = VIDEO_MODE_AUTO;
+- t->signal = 0xFFFF * gemtek_pci_getsignal( card );
+- strcpy( t->name, "FM" );
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow = GEMTEK_PCI_RANGE_LOW;
++ v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
++ v->rxsubchans =V4L2_TUNER_SUB_MONO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=0xFFFF*gemtek_pci_getsignal( card );
++
+ return 0;
+ }
+-
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *t = arg;
+- if ( t->tuner )
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- return 0;
+- }
+
+- case VIDIOCGFREQ:
+- {
+- unsigned long *freq = arg;
+- *freq = card->current_frequency;
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
++ struct v4l2_frequency *f = arg;
+
+- if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
+- (*freq > GEMTEK_PCI_RANGE_HIGH) )
++ if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
++ (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
+ return -EINVAL;
+
+- gemtek_pci_setfrequency( card, *freq );
+- card->current_frequency = *freq;
+- card->mute = FALSE;
+
++ gemtek_pci_setfrequency( card, f->frequency );
++ card->current_frequency = f->frequency;
++ card->mute = FALSE;
+ return 0;
+ }
+-
+- case VIDIOCGAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *a = arg;
+-
+- memset( a, 0, sizeof( *a ) );
+- a->flags |= VIDEO_AUDIO_MUTABLE;
+- a->volume = 1;
+- a->step = 65535;
+- strcpy( a->name, "Radio" );
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+-
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *a = arg;
+-
+- if ( a->audio )
+- return -EINVAL;
+-
+- if ( a->flags & VIDEO_AUDIO_MUTE )
+- gemtek_pci_mute( card );
+- else
+- gemtek_pci_unmute( card );
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=card->mute;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ if (card->mute)
++ ctrl->value=0;
++ else
++ ctrl->value=65535;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ gemtek_pci_mute(card);
++ } else {
++ gemtek_pci_unmute(card);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ if (ctrl->value) {
++ gemtek_pci_unmute(card);
++ } else {
++ gemtek_pci_mute(card);
++ }
++ return (0);
++ }
++ return -EINVAL;
+ }
+-
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ gemtek_pci_do_ioctl);
+ }
+ }
+
+@@ -309,7 +359,7 @@ static struct video_device vdev_template
+ .owner = THIS_MODULE,
+ .name = "Gemtek PCI Radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_GEMTEK,
++ .hardware = 0,
+ .fops = &gemtek_pci_fops,
+ };
+
+@@ -399,7 +449,7 @@ static int __init gemtek_pci_init_module
+
+ static void __exit gemtek_pci_cleanup_module( void )
+ {
+- return pci_unregister_driver( &gemtek_pci_driver );
++ pci_unregister_driver(&gemtek_pci_driver);
+ }
+
+ MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev at mail.ru>" );
+diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
+index 162f37d..730fe16 100644
+--- a/drivers/media/radio/radio-gemtek.c
++++ b/drivers/media/radio/radio-gemtek.c
+@@ -13,6 +13,7 @@
+ *
+ * TODO: Allow for more than one of these foolish entities :-)
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h> /* Modules */
+@@ -21,11 +22,32 @@
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
+ #include <linux/spinlock.h>
+
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 65535,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+ #ifndef CONFIG_RADIO_GEMTEK_PORT
+ #define CONFIG_RADIO_GEMTEK_PORT -1
+ #endif
+@@ -147,77 +169,122 @@ static int gemtek_do_ioctl(struct inode
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
+- strcpy(v->name, "GemTek");
++ strlcpy(v->driver, "radio-gemtek", sizeof (v->driver));
++ strlcpy(v->card, "GemTek", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner) /* Only 1 tuner */
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- v->rangelow=87*16000;
+- v->rangehigh=108*16000;
+- v->flags=VIDEO_TUNER_LOW;
+- v->mode=VIDEO_MODE_AUTO;
+- v->signal=0xFFFF*gemtek_getsigstr(rt);
++
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow=(87*16000);
++ v->rangehigh=(108*16000);
++ v->rxsubchans =V4L2_TUNER_SUB_MONO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=0xFFFF*gemtek_getsigstr(rt);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
+- return 0;
+- }
+- case VIDIOCGFREQ:
+- {
+- unsigned long *freq = arg;
+- *freq = rt->curfreq;
++
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- rt->curfreq = *freq;
++ struct v4l2_frequency *f = arg;
++
++ rt->curfreq = f->frequency;
+ /* needs to be called twice in order for getsigstr to work */
+ gemtek_setfreq(rt, rt->curfreq);
+ gemtek_setfreq(rt, rt->curfreq);
+ return 0;
+ }
+- case VIDIOCGAUDIO:
+- {
+- struct video_audio *v = arg;
+- memset(v,0, sizeof(*v));
+- v->flags|=VIDEO_AUDIO_MUTABLE;
+- v->volume=1;
+- v->step=65535;
+- strcpy(v->name, "Radio");
+- return 0;
+- }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
++ struct v4l2_frequency *f = arg;
+
+- if(v->flags&VIDEO_AUDIO_MUTE)
+- gemtek_mute(rt);
+- else
+- gemtek_unmute(rt);
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = rt->curfreq;
+
+ return 0;
+ }
++ case VIDIOC_QUERYCTRL:
++ {
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=rt->muted;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ if (rt->muted)
++ ctrl->value=0;
++ else
++ ctrl->value=65535;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ gemtek_mute(rt);
++ } else {
++ gemtek_unmute(rt);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ if (ctrl->value) {
++ gemtek_unmute(rt);
++ } else {
++ gemtek_mute(rt);
++ }
++ return (0);
++ }
++ return -EINVAL;
++ }
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ gemtek_do_ioctl);
+ }
+ }
+
+@@ -243,7 +310,7 @@ static struct video_device gemtek_radio=
+ .owner = THIS_MODULE,
+ .name = "GemTek radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_GEMTEK,
++ .hardware = 0,
+ .fops = &gemtek_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
+index fcfa6c9..e8ce5f7 100644
+--- a/drivers/media/radio/radio-maestro.c
++++ b/drivers/media/radio/radio-maestro.c
+@@ -14,6 +14,8 @@
+ * version 0.04
+ * + code improvements
+ * + VIDEO_TUNER_LOW is permanent
++ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h>
+@@ -25,10 +27,23 @@
+ #include <asm/uaccess.h>
+ #include <linux/mutex.h>
+ #include <linux/pci.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+
+-#define DRIVER_VERSION "0.05"
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,6)
++#define DRIVER_VERSION "0.06"
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ }
++};
+
+ #define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
+
+@@ -96,7 +111,7 @@ static struct file_operations maestro_fo
+ static struct video_device maestro_radio = {
+ .name = "Maestro radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_SF16MI,
++ .hardware = 0,
+ .fops = &maestro_fops,
+ };
+
+@@ -130,7 +145,7 @@ static u32 radio_bits_get(struct radio_d
+ rdata = inw(io);
+ if(!l)
+ dev->stereo = rdata & STR_MOST ?
+- 0 : VIDEO_TUNER_STEREO_ON;
++ 0 : 1;
+ else
+ if(rdata & STR_DATA)
+ data++;
+@@ -183,72 +198,120 @@ static inline int radio_function(struct
+ struct radio_device *card = video_get_drvdata(dev);
+
+ switch (cmd) {
+- case VIDIOCGCAP: {
+- struct video_capability *v = arg;
+- memset(v, 0, sizeof(*v));
+- strcpy(v->name, "Maestro radio");
+- v->type = VID_TYPE_TUNER;
+- v->channels = v->audios = 1;
+- return 0;
+- } case VIDIOCGTUNER: {
+- struct video_tuner *v = arg;
+- if (v->tuner)
+- return -EINVAL;
+- (void)radio_bits_get(card);
+- v->flags = VIDEO_TUNER_LOW | card->stereo;
+- v->signal = card->tuned;
+- strcpy(v->name, "FM");
+- v->rangelow = FREQ_LO;
+- v->rangehigh = FREQ_HI;
+- v->mode = VIDEO_MODE_AUTO;
+- return 0;
+- } case VIDIOCSTUNER: {
+- struct video_tuner *v = arg;
+- if (v->tuner != 0)
+- return -EINVAL;
+- return 0;
+- } case VIDIOCGFREQ: {
+- unsigned long *freq = arg;
+- *freq = BITS2FREQ(radio_bits_get(card));
+- return 0;
+- } case VIDIOCSFREQ: {
+- unsigned long *freq = arg;
+- if (*freq < FREQ_LO || *freq > FREQ_HI)
++ case VIDIOC_QUERYCAP:
++ {
++ struct v4l2_capability *v = arg;
++ memset(v,0,sizeof(*v));
++ strlcpy(v->driver, "radio-maestro", sizeof (v->driver));
++ strlcpy(v->card, "Maestro Radio", sizeof (v->card));
++ sprintf(v->bus_info,"PCI");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
++ return 0;
++ }
++ case VIDIOC_G_TUNER:
++ {
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
++ return -EINVAL;
++
++ (void)radio_bits_get(card);
++
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow = FREQ_LO;
++ v->rangehigh = FREQ_HI;
++ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ if(card->stereo)
++ v->audmode = V4L2_TUNER_MODE_STEREO;
++ else
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=card->tuned;
++
++ return 0;
++ }
++ case VIDIOC_S_TUNER:
++ {
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
++ return -EINVAL;
++
++ return 0;
++ }
++ case VIDIOC_S_FREQUENCY:
++ {
++ struct v4l2_frequency *f = arg;
++
++ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
++ return -EINVAL;
++ radio_bits_set(card, FREQ2BITS(f->frequency));
++
++ return 0;
++ }
++ case VIDIOC_G_FREQUENCY:
++ {
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = BITS2FREQ(radio_bits_get(card));
++
++ return 0;
++ }
++ case VIDIOC_QUERYCTRL:
++ {
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
+ return -EINVAL;
+- radio_bits_set(card, FREQ2BITS(*freq));
+- return 0;
+- } case VIDIOCGAUDIO: {
+- struct video_audio *v = arg;
+- memset(v, 0, sizeof(*v));
+- strcpy(v->name, "Radio");
+- v->flags = VIDEO_AUDIO_MUTABLE | card->muted;
+- v->mode = VIDEO_SOUND_STEREO;
+- return 0;
+- } case VIDIOCSAUDIO: {
+- struct video_audio *v = arg;
+- if (v->audio)
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=card->muted;
++ return (0);
++ }
+ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
+ {
+- register u16 io = card->io;
+- register u16 omask = inw(io + IO_MASK);
+- outw(~STR_WREN, io + IO_MASK);
+- outw((card->muted = v->flags & VIDEO_AUDIO_MUTE) ?
+- STR_WREN : 0, io);
+- udelay(4);
+- outw(omask, io + IO_MASK);
+- msleep(125);
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ {
++ register u16 io = card->io;
++ register u16 omask = inw(io + IO_MASK);
++ outw(~STR_WREN, io + IO_MASK);
++ outw((card->muted = ctrl->value ) ?
++ STR_WREN : 0, io);
++ udelay(4);
++ outw(omask, io + IO_MASK);
++ msleep(125);
++
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- } case VIDIOCGUNIT: {
+- struct video_unit *v = arg;
+- v->video = VIDEO_NO_UNIT;
+- v->vbi = VIDEO_NO_UNIT;
+- v->radio = dev->minor;
+- v->audio = 0;
+- v->teletext = VIDEO_NO_UNIT;
+- return 0;
+- } default:
+- return -ENOIOCTLCMD;
++ default:
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ radio_function);
+ }
+ }
+
+@@ -275,7 +338,7 @@ static u16 __devinit radio_power_on(stru
+ omask = inw(io + IO_MASK);
+ odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+ outw(odir & ~STR_WREN, io + IO_DIR);
+- dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE;
++ dev->muted = inw(io) & STR_WREN ? 0 : 1;
+ outw(odir, io + IO_DIR);
+ outw(~(STR_WREN | STR_CLK), io + IO_MASK);
+ outw(dev->muted ? 0 : STR_WREN, io);
+diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
+index f93d7af..c2eeae7 100644
+--- a/drivers/media/radio/radio-maxiradio.c
++++ b/drivers/media/radio/radio-maxiradio.c
+@@ -20,13 +20,14 @@
+ * 0.75b
+ * - better pci interface thanks to Francois Romieu <romieu at cogenit.fr>
+ *
+- * 0.75
++ * 0.75 Sun Feb 4 22:51:27 EET 2001
+ * - tiding up
+ * - removed support for multiple devices as it didn't work anyway
+ *
+ * BUGS:
+ * - card unmutes if you change frequency
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+
+@@ -40,11 +41,24 @@
+ #include <linux/mutex.h>
+
+ #include <linux/pci.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+
+-/* version 0.75 Sun Feb 4 22:51:27 EET 2001 */
+-#define DRIVER_VERSION "0.75"
++#define DRIVER_VERSION "0.76"
++
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,7,6)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ }
++};
+
+ #ifndef PCI_VENDOR_ID_GUILLEMOT
+ #define PCI_VENDOR_ID_GUILLEMOT 0x5046
+@@ -90,7 +104,6 @@ static struct video_device maxiradio_rad
+ .owner = THIS_MODULE,
+ .name = "Maxi Radio FM2000 radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_SF16MI,
+ .fops = &maxiradio_fops,
+ };
+
+@@ -176,89 +189,116 @@ static inline int radio_function(struct
+ struct radio_device *card=dev->priv;
+
+ switch(cmd) {
+- case VIDIOCGCAP: {
+- struct video_capability *v = arg;
+-
++ case VIDIOC_QUERYCAP:
++ {
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- strcpy(v->name, "Maxi Radio FM2000 radio");
+- v->type=VID_TYPE_TUNER;
+- v->channels=v->audios=1;
++ strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
++ strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER: {
+- struct video_tuner *v = arg;
++ case VIDIOC_G_TUNER:
++ {
++ struct v4l2_tuner *v = arg;
+
+- if(v->tuner)
++ if (v->index > 0)
+ return -EINVAL;
+
+- card->stereo = 0xffff * get_stereo(card->io);
+- card->tuned = 0xffff * get_tune(card->io);
+-
+- v->flags = VIDEO_TUNER_LOW | card->stereo;
+- v->signal = card->tuned;
+-
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+-
+- v->rangelow = FREQ_LO;
+- v->rangehigh = FREQ_HI;
+- v->mode = VIDEO_MODE_AUTO;
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow=FREQ_LO;
++ v->rangehigh=FREQ_HI;
++ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ if(get_stereo(card->io))
++ v->audmode = V4L2_TUNER_MODE_STEREO;
++ else
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=0xffff*get_tune(card->io);
+
+ return 0;
+ }
+- case VIDIOCSTUNER: {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ case VIDIOC_S_TUNER:
++ {
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- return 0;
+- }
+- case VIDIOCGFREQ: {
+- unsigned long *freq = arg;
+
+- *freq = card->freq;
+ return 0;
+ }
+- case VIDIOCSFREQ: {
+- unsigned long *freq = arg;
++ case VIDIOC_S_FREQUENCY:
++ {
++ struct v4l2_frequency *f = arg;
+
+- if (*freq < FREQ_LO || *freq > FREQ_HI)
++ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
+ return -EINVAL;
+- card->freq = *freq;
++
++ card->freq = f->frequency;
+ set_freq(card->io, FREQ2BITS(card->freq));
+ msleep(125);
+ return 0;
+ }
+- case VIDIOCGAUDIO: {
+- struct video_audio *v = arg;
+- memset(v,0,sizeof(*v));
+- strcpy(v->name, "Radio");
+- v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
+- v->mode=VIDEO_SOUND_STEREO;
+- return 0;
+- }
++ case VIDIOC_G_FREQUENCY:
++ {
++ struct v4l2_frequency *f = arg;
+
+- case VIDIOCSAUDIO: {
+- struct video_audio *v = arg;
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = card->freq;
+
+- if(v->audio)
+- return -EINVAL;
+- card->muted = v->flags & VIDEO_AUDIO_MUTE;
+- if(card->muted)
+- turn_power(card->io, 0);
+- else
+- set_freq(card->io, FREQ2BITS(card->freq));
+ return 0;
+ }
+- case VIDIOCGUNIT: {
+- struct video_unit *v = arg;
+-
+- v->video=VIDEO_NO_UNIT;
+- v->vbi=VIDEO_NO_UNIT;
+- v->radio=dev->minor;
+- v->audio=0;
+- v->teletext=VIDEO_NO_UNIT;
+- return 0;
++ case VIDIOC_QUERYCTRL:
++ {
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=card->muted;
++ return (0);
++ }
++ return -EINVAL;
+ }
+- default: return -ENOIOCTLCMD;
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ card->muted = ctrl->value;
++ if(card->muted)
++ turn_power(card->io, 0);
++ else
++ set_freq(card->io, FREQ2BITS(card->freq));
++ return 0;
++ }
++ return -EINVAL;
++ }
++
++ default:
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ radio_function);
++
+ }
+ }
+
+diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
+index 5b68ac4..b9e9848 100644
+--- a/drivers/media/radio/radio-rtrack2.c
++++ b/drivers/media/radio/radio-rtrack2.c
+@@ -6,6 +6,7 @@
+ *
+ * TODO: Allow for more than one of these foolish entities :-)
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h> /* Modules */
+@@ -14,11 +15,32 @@
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_RTRACK2_PORT */
+ #include <linux/spinlock.h>
+
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 65535,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+ #ifndef CONFIG_RADIO_RTRACK2_PORT
+ #define CONFIG_RADIO_RTRACK2_PORT -1
+ #endif
+@@ -115,75 +137,120 @@ static int rt_do_ioctl(struct inode *ino
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
+- strcpy(v->name, "RadioTrack II");
++ strlcpy(v->driver, "radio-rtrack2", sizeof (v->driver));
++ strlcpy(v->card, "RadioTrack II", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner) /* Only 1 tuner */
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- v->rangelow=88*16000;
+- v->rangehigh=108*16000;
+- v->flags=VIDEO_TUNER_LOW;
+- v->mode=VIDEO_MODE_AUTO;
+- v->signal=0xFFFF*rt_getsigstr(rt);
++
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow=(88*16000);
++ v->rangehigh=(108*16000);
++ v->rxsubchans =V4L2_TUNER_SUB_MONO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=0xFFFF*rt_getsigstr(rt);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- *freq = rt->curfreq;
++ struct v4l2_frequency *f = arg;
++
++ rt->curfreq = f->frequency;
++ rt_setfreq(rt, rt->curfreq);
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_G_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- rt->curfreq = *freq;
+- rt_setfreq(rt, rt->curfreq);
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = rt->curfreq;
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+- memset(v,0, sizeof(*v));
+- v->flags|=VIDEO_AUDIO_MUTABLE;
+- v->volume=1;
+- v->step=65535;
+- strcpy(v->name, "Radio");
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+-
+- if(v->flags&VIDEO_AUDIO_MUTE)
+- rt_mute(rt);
+- else
+- rt_unmute(rt);
+-
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=rt->muted;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ if (rt->muted)
++ ctrl->value=0;
++ else
++ ctrl->value=65535;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ rt_mute(rt);
++ } else {
++ rt_unmute(rt);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ if (ctrl->value) {
++ rt_unmute(rt);
++ } else {
++ rt_mute(rt);
++ }
++ return (0);
++ }
++ return -EINVAL;
+ }
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ rt_do_ioctl);
+ }
+ }
+
+@@ -209,7 +276,7 @@ static struct video_device rtrack2_radio
+ .owner = THIS_MODULE,
+ .name = "RadioTrack II radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_RTRACK2,
++ .hardware = 0,
+ .fops = &rtrack2_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
+index efee6e3..ecc854b 100644
+--- a/drivers/media/radio/radio-sf16fmi.c
++++ b/drivers/media/radio/radio-sf16fmi.c
+@@ -13,20 +13,35 @@
+ * No volume control - only mute/unmute - you have to use line volume
+ * control on SB-part of SF16FMI
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
++#include <linux/version.h>
+ #include <linux/kernel.h> /* __setup */
+ #include <linux/module.h> /* Modules */
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+ #include <linux/isapnp.h>
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/mutex.h>
+
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ }
++};
++
+ struct fmi_device
+ {
+ int port;
+@@ -123,93 +138,122 @@ static int fmi_do_ioctl(struct inode *in
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- strcpy(v->name, "SF16-FMx radio");
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
++ strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver));
++ strlcpy(v->card, "SF16-FMx radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
++ struct v4l2_tuner *v = arg;
+ int mult;
+
+- if(v->tuner) /* Only 1 tuner */
++ if (v->index > 0)
+ return -EINVAL;
++
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+- mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
++ v->type = V4L2_TUNER_RADIO;
++
++ mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
+ v->rangelow = RSF16_MINFREQ/mult;
+ v->rangehigh = RSF16_MAXFREQ/mult;
+- v->flags=fmi->flags;
+- v->mode=VIDEO_MODE_AUTO;
++ v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
++ v->capability=fmi->flags&V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_STEREO;
+ v->signal = fmi_getsigstr(fmi);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- fmi->flags = v->flags & VIDEO_TUNER_LOW;
+- /* Only 1 tuner so no setting needed ! */
+- return 0;
+- }
+- case VIDIOCGFREQ:
+- {
+- unsigned long *freq = arg;
+- *freq = fmi->curfreq;
+- if (!(fmi->flags & VIDEO_TUNER_LOW))
+- *freq /= 1000;
++
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- if (!(fmi->flags & VIDEO_TUNER_LOW))
+- *freq *= 1000;
+- if (*freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
++ struct v4l2_frequency *f = arg;
++
++ if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
++ f->frequency *= 1000;
++ if (f->frequency < RSF16_MINFREQ ||
++ f->frequency > RSF16_MAXFREQ )
+ return -EINVAL;
+ /*rounding in steps of 800 to match th freq
+ that will be used */
+- fmi->curfreq = (*freq/800)*800;
++ fmi->curfreq = (f->frequency/800)*800;
+ fmi_setfreq(fmi);
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_G_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- memset(v,0,sizeof(*v));
+- v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
+- strcpy(v->name, "Radio");
+- v->mode=VIDEO_SOUND_STEREO;
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = fmi->curfreq;
++ if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
++ f->frequency /= 1000;
++
+ return 0;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+- fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
+- fmi->curvol ?
+- fmi_unmute(fmi->port) : fmi_mute(fmi->port);
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- case VIDIOCGUNIT:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_unit *v = arg;
+- v->video=VIDEO_NO_UNIT;
+- v->vbi=VIDEO_NO_UNIT;
+- v->radio=dev->minor;
+- v->audio=0; /* How do we find out this??? */
+- v->teletext=VIDEO_NO_UNIT;
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=fmi->curvol;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ {
++ if (ctrl->value)
++ fmi_mute(fmi->port);
++ else
++ fmi_unmute(fmi->port);
++
++ fmi->curvol=ctrl->value;
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ fmi_do_ioctl);
+ }
+ }
+
+@@ -235,7 +279,7 @@ static struct video_device fmi_radio=
+ .owner = THIS_MODULE,
+ .name = "SF16FMx radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_SF16MI,
++ .hardware = 0,
+ .fops = &fmi_fops,
+ };
+
+@@ -294,7 +338,7 @@ static int __init fmi_init(void)
+ fmi_unit.port = io;
+ fmi_unit.curvol = 0;
+ fmi_unit.curfreq = 0;
+- fmi_unit.flags = VIDEO_TUNER_LOW;
++ fmi_unit.flags = V4L2_TUNER_CAP_LOW;
+ fmi_radio.priv = &fmi_unit;
+
+ mutex_init(&lock);
+diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
+index 3483b2c..4444dce 100644
+--- a/drivers/media/radio/radio-sf16fmr2.c
++++ b/drivers/media/radio/radio-sf16fmr2.c
+@@ -10,6 +10,8 @@
+ * For read stereo/mono you must wait 0.1 sec after set frequency and
+ * card unmuted so I set frequency on unmute
+ * Signal handling seem to work only on autoscanning (not implemented)
++ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h> /* Modules */
+@@ -18,12 +20,34 @@
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+ #include <linux/mutex.h>
+
+ static struct mutex lock;
+
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 1<<12,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+ #undef DEBUG
+ //#define DEBUG 1
+
+@@ -214,63 +238,65 @@ static int fmr2_do_ioctl(struct inode *i
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- strcpy(v->name, "SF16-FMR2 radio");
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
++ strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver));
++ strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
++ struct v4l2_tuner *v = arg;
+ int mult;
+
+- if(v->tuner) /* Only 1 tuner */
++ if (v->index > 0)
+ return -EINVAL;
++
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+- mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
++ v->type = V4L2_TUNER_RADIO;
++
++ mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
+ v->rangelow = RSF16_MINFREQ/mult;
+ v->rangehigh = RSF16_MAXFREQ/mult;
+- v->flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
+- if (fmr2->mute)
+- v->flags |= VIDEO_AUDIO_MUTE;
+- v->mode=VIDEO_MODE_AUTO;
++ v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
++ v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW;
++
++ v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
++ V4L2_TUNER_MODE_MONO;
+ mutex_lock(&lock);
+ v->signal = fmr2_getsigstr(fmr2);
+ mutex_unlock(&lock);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if (v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- fmr2->flags = v->flags & VIDEO_TUNER_LOW;
+- return 0;
+- }
+- case VIDIOCGFREQ:
+- {
+- unsigned long *freq = arg;
+- *freq = fmr2->curfreq;
+- if (!(fmr2->flags & VIDEO_TUNER_LOW))
+- *freq /= 1000;
++
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- if (!(fmr2->flags & VIDEO_TUNER_LOW))
+- *freq *= 1000;
+- if ( *freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
++ struct v4l2_frequency *f = arg;
++
++ if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
++ f->frequency *= 1000;
++ if (f->frequency < RSF16_MINFREQ ||
++ f->frequency > RSF16_MAXFREQ )
+ return -EINVAL;
+- /* rounding in steps of 200 to match th freq
+- * that will be used
+- */
+- fmr2->curfreq = (*freq/200)*200;
++ /*rounding in steps of 200 to match th freq
++ that will be used */
++ fmr2->curfreq = (f->frequency/200)*200;
+
+ /* set card freq (if not muted) */
+ if (fmr2->curvol && !fmr2->mute)
+@@ -279,40 +305,81 @@ static int fmr2_do_ioctl(struct inode *i
+ fmr2_setfreq(fmr2);
+ mutex_unlock(&lock);
+ }
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_G_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- memset(v,0,sizeof(*v));
+- /* !!! do not return VIDEO_AUDIO_MUTE */
+- v->flags = VIDEO_AUDIO_MUTABLE;
+- strcpy(v->name, "Radio");
+- /* get current stereo mode */
+- v->mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
+- /* volume supported ? */
+- if (fmr2->card_type == 11)
+- {
+- v->flags |= VIDEO_AUDIO_VOLUME;
+- v->step = 1 << 12;
+- v->volume = fmr2->curvol;
+- }
+- debug_print((KERN_DEBUG "Get flags %d vol %d\n", v->flags, v->volume));
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = fmr2->curfreq;
++ if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
++ f->frequency /= 1000;
++
+ return 0;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+- debug_print((KERN_DEBUG "Set flags %d vol %d\n", v->flags, v->volume));
+- /* set volume */
+- if (v->flags & VIDEO_AUDIO_VOLUME)
+- fmr2->curvol = v->volume; /* !!! set with precision */
+- if (fmr2->card_type != 11) fmr2->curvol = 65535;
+- fmr2->mute = 0;
+- if (v->flags & VIDEO_AUDIO_MUTE)
+- fmr2->mute = 1;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if ((fmr2->card_type != 11)
++ && V4L2_CID_AUDIO_VOLUME)
++ radio_qctrl[i].step=65535;
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=fmr2->mute;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value=fmr2->curvol;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ fmr2->mute=ctrl->value;
++ if (fmr2->card_type != 11) {
++ if (!fmr2->mute) {
++ fmr2->curvol = 65535;
++ } else {
++ fmr2->curvol = 0;
++ }
++ }
++ break;
++ case V4L2_CID_AUDIO_VOLUME:
++ fmr2->curvol = ctrl->value;
++ if (fmr2->card_type != 11) {
++ if (fmr2->curvol) {
++ fmr2->curvol = 65535;
++ fmr2->mute = 0;
++ } else {
++ fmr2->curvol = 0;
++ fmr2->mute = 1;
++ }
++ }
++ break;
++ default:
++ return -EINVAL;
++ }
+ #ifdef DEBUG
+ if (fmr2->curvol && !fmr2->mute)
+ printk(KERN_DEBUG "unmute\n");
+@@ -320,27 +387,18 @@ static int fmr2_do_ioctl(struct inode *i
+ printk(KERN_DEBUG "mute\n");
+ #endif
+ mutex_lock(&lock);
+- if (fmr2->curvol && !fmr2->mute)
+- {
++ if (fmr2->curvol && !fmr2->mute) {
+ fmr2_setvolume(fmr2);
+ fmr2_setfreq(fmr2);
+- }
+- else fmr2_mute(fmr2->port);
++ } else
++ fmr2_mute(fmr2->port);
+ mutex_unlock(&lock);
+- return 0;
+- }
+- case VIDIOCGUNIT:
+- {
+- struct video_unit *v = arg;
+- v->video=VIDEO_NO_UNIT;
+- v->vbi=VIDEO_NO_UNIT;
+- v->radio=dev->minor;
+- v->audio=0; /* How do we find out this??? */
+- v->teletext=VIDEO_NO_UNIT;
+- return 0;
++ return (0);
+ }
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ fmr2_do_ioctl);
++
+ }
+ }
+
+@@ -366,7 +424,7 @@ static struct video_device fmr2_radio=
+ .owner = THIS_MODULE,
+ .name = "SF16FMR2 radio",
+ . type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_SF16FMR2,
++ .hardware = 0,
+ .fops = &fmr2_fops,
+ };
+
+@@ -377,7 +435,7 @@ static int __init fmr2_init(void)
+ fmr2_unit.mute = 0;
+ fmr2_unit.curfreq = 0;
+ fmr2_unit.stereo = 1;
+- fmr2_unit.flags = VIDEO_TUNER_LOW;
++ fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
+ fmr2_unit.card_type = 0;
+ fmr2_radio.priv = &fmr2_unit;
+
+@@ -396,7 +454,6 @@ static int __init fmr2_init(void)
+ }
+
+ printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
+- debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
+ /* mute card - prevents noisy bootups */
+ mutex_lock(&lock);
+ fmr2_mute(io);
+diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
+index dfba4ae..f539491 100644
+--- a/drivers/media/radio/radio-terratec.c
++++ b/drivers/media/radio/radio-terratec.c
+@@ -21,6 +21,7 @@
+ * If you can help me out with that, please contact me!!
+ *
+ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h> /* Modules */
+@@ -29,11 +30,32 @@
+ #include <linux/delay.h> /* udelay */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_TERRATEC_PORT */
+ #include <linux/spinlock.h>
+
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 0xff,
++ .step = 1,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+ #ifndef CONFIG_RADIO_TERRATEC_PORT
+ #define CONFIG_RADIO_TERRATEC_PORT 0x590
+ #endif
+@@ -194,73 +216,117 @@ static int tt_do_ioctl(struct inode *ino
+
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
+- strcpy(v->name, "ActiveRadio");
++ strlcpy(v->driver, "radio-terratec", sizeof (v->driver));
++ strlcpy(v->card, "ActiveRadio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner) /* Only 1 tuner */
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
++
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
+ v->rangelow=(87*16000);
+ v->rangehigh=(108*16000);
+- v->flags=VIDEO_TUNER_LOW;
+- v->mode=VIDEO_MODE_AUTO;
+- strcpy(v->name, "FM");
++ v->rxsubchans =V4L2_TUNER_SUB_MONO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*tt_getsigstr(tt);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner!=0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- *freq = tt->curfreq;
++ struct v4l2_frequency *f = arg;
++
++ tt->curfreq = f->frequency;
++ tt_setfreq(tt, tt->curfreq);
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_G_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- tt->curfreq = *freq;
+- tt_setfreq(tt, tt->curfreq);
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = tt->curfreq;
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+- memset(v,0, sizeof(*v));
+- v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+- v->volume=tt->curvol * 6554;
+- v->step=6554;
+- strcpy(v->name, "Radio");
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *v = arg;
+- if(v->audio)
+- return -EINVAL;
+- if(v->flags&VIDEO_AUDIO_MUTE)
+- tt_mute(tt);
+- else
+- tt_setvol(tt,v->volume/6554);
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (tt->muted)
++ ctrl->value=1;
++ else
++ ctrl->value=0;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value=tt->curvol * 6554;
++ return (0);
++ }
++ return -EINVAL;
+ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ tt_mute(tt);
++ } else {
++ tt_setvol(tt,tt->curvol);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ tt_setvol(tt,ctrl->value);
++ return (0);
++ }
++ return -EINVAL;
++ }
++
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ tt_do_ioctl);
+ }
+ }
+
+@@ -286,7 +352,7 @@ static struct video_device terratec_radi
+ .owner = THIS_MODULE,
+ .name = "TerraTec ActiveRadio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_TERRATEC,
++ .hardware = 0,
+ .fops = &terratec_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
+index 8da4bad..bb03ad5 100644
+--- a/drivers/media/radio/radio-trust.c
++++ b/drivers/media/radio/radio-trust.c
+@@ -12,7 +12,7 @@
+ * Scott McGrath (smcgrath at twilight.vtc.vsc.edu)
+ * William McGrath (wmcgrath at twilight.vtc.vsc.edu)
+ *
+- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <stdarg.h>
+@@ -21,9 +21,46 @@
+ #include <linux/ioport.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
++
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 2048,
++ .default_value = 65535,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ },{
++ .id = V4L2_CID_AUDIO_BASS,
++ .name = "Bass",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 4370,
++ .default_value = 32768,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ },{
++ .id = V4L2_CID_AUDIO_TREBLE,
++ .name = "Treble",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 4370,
++ .default_value = 32768,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ },
++};
+
+ /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
+
+@@ -160,88 +197,125 @@ static int tr_do_ioctl(struct inode *ino
+ {
+ switch(cmd)
+ {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
+-
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type=VID_TYPE_TUNER;
+- v->channels=1;
+- v->audios=1;
+- strcpy(v->name, "Trust FM Radio");
++ strlcpy(v->driver, "radio-trust", sizeof (v->driver));
++ strlcpy(v->card, "Trust FM Radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
+
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
++ struct v4l2_tuner *v = arg;
+
+- if(v->tuner) /* Only 1 tuner */
++ if (v->index > 0)
+ return -EINVAL;
+
+- v->rangelow = 87500 * 16;
+- v->rangehigh = 108000 * 16;
+- v->flags = VIDEO_TUNER_LOW;
+- v->mode = VIDEO_MODE_AUTO;
++ memset(v,0,sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
+
+- v->signal = tr_getsigstr();
++ v->rangelow=(87.5*16000);
++ v->rangehigh=(108*16000);
++ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability=V4L2_TUNER_CAP_LOW;
+ if(tr_getstereo())
+- v->flags |= VIDEO_TUNER_STEREO_ON;
+-
+- strcpy(v->name, "FM");
++ v->audmode = V4L2_TUNER_MODE_STEREO;
++ else
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=tr_getsigstr();
+
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if(v->tuner != 0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
++ case VIDIOC_S_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- *freq = curfreq;
++ struct v4l2_frequency *f = arg;
++
++ curfreq = f->frequency;
++ tr_setfreq(curfreq);
+ return 0;
+ }
+- case VIDIOCSFREQ:
++ case VIDIOC_G_FREQUENCY:
+ {
+- unsigned long *freq = arg;
+- tr_setfreq(*freq);
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = curfreq;
++
+ return 0;
+ }
+- case VIDIOCGAUDIO:
++ case VIDIOC_QUERYCTRL:
+ {
+- struct video_audio *v = arg;
+-
+- memset(v,0, sizeof(*v));
+- v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
+- VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+- v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+- v->volume = curvol * 2048;
+- v->step = 2048;
+- v->bass = curbass * 4370;
+- v->treble = curtreble * 4370;
+-
+- strcpy(v->name, "Trust FM Radio");
+- return 0;
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_CTRL:
+ {
+- struct video_audio *v = arg;
+-
+- if(v->audio)
+- return -EINVAL;
+- tr_setvol(v->volume);
+- tr_setbass(v->bass);
+- tr_settreble(v->treble);
+- tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
+- tr_setmute(v->flags & VIDEO_AUDIO_MUTE);
+- return 0;
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=curmute;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value= curvol * 2048;
++ return (0);
++ case V4L2_CID_AUDIO_BASS:
++ ctrl->value= curbass * 4370;
++ return (0);
++ case V4L2_CID_AUDIO_TREBLE:
++ ctrl->value= curtreble * 4370;
++ return (0);
++ }
++ return -EINVAL;
+ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ tr_setmute(ctrl->value);
++ return 0;
++ case V4L2_CID_AUDIO_VOLUME:
++ tr_setvol(ctrl->value);
++ return 0;
++ case V4L2_CID_AUDIO_BASS:
++ tr_setbass(ctrl->value);
++ return 0;
++ case V4L2_CID_AUDIO_TREBLE:
++ tr_settreble(ctrl->value);
++ return (0);
++ }
++ return -EINVAL;
++ }
++
+ default:
+- return -ENOIOCTLCMD;
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ tr_do_ioctl);
+ }
+ }
+
+@@ -265,7 +339,7 @@ static struct video_device trust_radio=
+ .owner = THIS_MODULE,
+ .name = "Trust FM Radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_TRUST,
++ .hardware = 0,
+ .fops = &trust_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
+index edd0122..4a72b4d 100644
+--- a/drivers/media/radio/radio-typhoon.c
++++ b/drivers/media/radio/radio-typhoon.c
+@@ -27,6 +27,8 @@
+ * value where I do expect just noise and turn the speaker volume down.
+ * The frequency change is necessary since the card never seems to be
+ * completely silent.
++ *
++ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h> /* Modules */
+@@ -35,11 +37,32 @@
+ #include <linux/proc_fs.h> /* radio card status report */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_TYPHOON_* */
+
+-#define BANNER "Typhoon Radio Card driver v0.1\n"
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,1,1)
++#define BANNER "Typhoon Radio Card driver v0.1.1\n"
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 1<<14,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
++
+
+ #ifndef CONFIG_RADIO_TYPHOON_PORT
+ #define CONFIG_RADIO_TYPHOON_PORT -1
+@@ -171,76 +194,114 @@ static int typhoon_do_ioctl(struct inode
+ struct typhoon_device *typhoon = dev->priv;
+
+ switch (cmd) {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type = VID_TYPE_TUNER;
+- v->channels = 1;
+- v->audios = 1;
+- strcpy(v->name, "Typhoon Radio");
++ strlcpy(v->driver, "radio-typhoon", sizeof (v->driver));
++ strlcpy(v->card, "Typhoon Radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if (v->tuner) /* Only 1 tuner */
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- v->rangelow = 875 * 1600;
+- v->rangehigh = 1080 * 1600;
+- v->flags = VIDEO_TUNER_LOW;
+- v->mode = VIDEO_MODE_AUTO;
+- v->signal = 0xFFFF; /* We can't get the signal strength */
++
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow=(87.5*16000);
++ v->rangehigh=(108*16000);
++ v->rxsubchans =V4L2_TUNER_SUB_MONO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal = 0xFFFF; /* We can't get the signal strength */
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if (v->tuner != 0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
+- {
+- unsigned long *freq = arg;
+- *freq = typhoon->curfreq;
+- return 0;
+- }
+- case VIDIOCSFREQ:
+- {
+- unsigned long *freq = arg;
+- typhoon->curfreq = *freq;
+- typhoon_setfreq(typhoon, typhoon->curfreq);
+- return 0;
+- }
+- case VIDIOCGAUDIO:
++ case VIDIOC_S_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- memset(v, 0, sizeof(*v));
+- v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
+- v->mode |= VIDEO_SOUND_MONO;
+- v->volume = typhoon->curvol;
+- v->step = 1 << 14;
+- strcpy(v->name, "Typhoon Radio");
++ struct v4l2_frequency *f = arg;
++
++ typhoon->curfreq = f->frequency;
++ typhoon_setfreq(typhoon, typhoon->curfreq);
+ return 0;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- if (v->audio)
+- return -EINVAL;
+- if (v->flags & VIDEO_AUDIO_MUTE)
+- typhoon_mute(typhoon);
+- else
+- typhoon_unmute(typhoon);
+- if (v->flags & VIDEO_AUDIO_VOLUME)
+- typhoon_setvol(typhoon, v->volume);
++ struct v4l2_frequency *f = arg;
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = typhoon->curfreq;
++
+ return 0;
+ }
+- default:
+- return -ENOIOCTLCMD;
++ case VIDIOC_QUERYCTRL:
++ {
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=typhoon->muted;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value=typhoon->curvol;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ typhoon_mute(typhoon);
++ } else {
++ typhoon_unmute(typhoon);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ typhoon_setvol(typhoon, ctrl->value);
++ return (0);
++ }
++ return -EINVAL;
++ }
++
++ default:
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ typhoon_do_ioctl);
+ }
+ }
+
+@@ -271,7 +332,7 @@ static struct video_device typhoon_radio
+ .owner = THIS_MODULE,
+ .name = "Typhoon Radio",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_TYPHOON,
++ .hardware = 0,
+ .fops = &typhoon_fops,
+ };
+
+diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
+index 59b86a6..671fe1b 100644
+--- a/drivers/media/radio/radio-zoltrix.c
++++ b/drivers/media/radio/radio-zoltrix.c
+@@ -24,6 +24,9 @@
+ * - Added unmute function
+ * - Reworked ioctl functions
+ * 2002-07-15 - Fix Stereo typo
++ *
++ * 2006-07-24 - Converted to V4L2 API
++ * by Mauro Carvalho Chehab <mchehab at infradead.org>
+ */
+
+ #include <linux/module.h> /* Modules */
+@@ -32,9 +35,30 @@
+ #include <linux/delay.h> /* udelay, msleep */
+ #include <asm/io.h> /* outb, outb_p */
+ #include <asm/uaccess.h> /* copy to/from user */
+-#include <linux/videodev.h> /* kernel radio structs */
++#include <linux/videodev2.h> /* kernel radio structs */
+ #include <media/v4l2-common.h>
+-#include <linux/config.h> /* CONFIG_RADIO_ZOLTRIX_PORT */
++
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 65535,
++ .step = 4096,
++ .default_value = 0xff,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++};
+
+ #ifndef CONFIG_RADIO_ZOLTRIX_PORT
+ #define CONFIG_RADIO_ZOLTRIX_PORT -1
+@@ -213,78 +237,116 @@ static int zol_do_ioctl(struct inode *in
+ struct zol_device *zol = dev->priv;
+
+ switch (cmd) {
+- case VIDIOCGCAP:
++ case VIDIOC_QUERYCAP:
+ {
+- struct video_capability *v = arg;
+-
++ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+- v->type = VID_TYPE_TUNER;
+- v->channels = 1 + zol->stereo;
+- v->audios = 1;
+- strcpy(v->name, "Zoltrix Radio");
++ strlcpy(v->driver, "radio-zoltrix", sizeof (v->driver));
++ strlcpy(v->card, "Zoltrix Radio", sizeof (v->card));
++ sprintf(v->bus_info,"ISA");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++
+ return 0;
+ }
+- case VIDIOCGTUNER:
++ case VIDIOC_G_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if (v->tuner)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
++
++ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+- v->rangelow = (int) (88.0 * 16000);
+- v->rangehigh = (int) (108.0 * 16000);
+- v->flags = zol_is_stereo(zol)
+- ? VIDEO_TUNER_STEREO_ON : 0;
+- v->flags |= VIDEO_TUNER_LOW;
+- v->mode = VIDEO_MODE_AUTO;
+- v->signal = 0xFFFF * zol_getsigstr(zol);
++ v->type = V4L2_TUNER_RADIO;
++
++ v->rangelow=(88*16000);
++ v->rangehigh=(108*16000);
++ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability=V4L2_TUNER_CAP_LOW;
++ if(zol_is_stereo(zol))
++ v->audmode = V4L2_TUNER_MODE_STEREO;
++ else
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal=0xFFFF*zol_getsigstr(zol);
++
+ return 0;
+ }
+- case VIDIOCSTUNER:
++ case VIDIOC_S_TUNER:
+ {
+- struct video_tuner *v = arg;
+- if (v->tuner != 0)
++ struct v4l2_tuner *v = arg;
++
++ if (v->index > 0)
+ return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
++
+ return 0;
+ }
+- case VIDIOCGFREQ:
+- {
+- unsigned long *freq = arg;
+- *freq = zol->curfreq;
+- return 0;
+- }
+- case VIDIOCSFREQ:
+- {
+- unsigned long *freq = arg;
+- zol->curfreq = *freq;
+- zol_setfreq(zol, zol->curfreq);
+- return 0;
+- }
+- case VIDIOCGAUDIO:
++ case VIDIOC_S_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- memset(v, 0, sizeof(*v));
+- v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
+- v->mode |= zol_is_stereo(zol)
+- ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+- v->volume = zol->curvol * 4096;
+- v->step = 4096;
+- strcpy(v->name, "Zoltrix Radio");
++ struct v4l2_frequency *f = arg;
++
++ zol->curfreq = f->frequency;
++ zol_setfreq(zol, zol->curfreq);
+ return 0;
+ }
+- case VIDIOCSAUDIO:
++ case VIDIOC_G_FREQUENCY:
+ {
+- struct video_audio *v = arg;
+- if (v->audio)
+- return -EINVAL;
++ struct v4l2_frequency *f = arg;
+
+- if (v->flags & VIDEO_AUDIO_MUTE)
+- zol_mute(zol);
+- else {
+- zol_unmute(zol);
+- zol_setvol(zol, v->volume / 4096);
+- }
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = zol->curfreq;
+
++ return 0;
++ }
++ case VIDIOC_QUERYCTRL:
++ {
++ struct v4l2_queryctrl *qc = arg;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
++ return (0);
++ }
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_G_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value=zol->muted;
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value=zol->curvol * 4096;
++ return (0);
++ }
++ return -EINVAL;
++ }
++ case VIDIOC_S_CTRL:
++ {
++ struct v4l2_control *ctrl= arg;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value) {
++ zol_mute(zol);
++ } else {
++ zol_unmute(zol);
++ zol_setvol(zol,zol->curvol);
++ }
++ return (0);
++ case V4L2_CID_AUDIO_VOLUME:
++ zol_setvol(zol,ctrl->value/4096);
++ return (0);
++ }
++ zol->stereo = 1;
++ zol_setfreq(zol, zol->curfreq);
++#if 0
++/* FIXME: Implement stereo/mono switch on V4L2 */
+ if (v->mode & VIDEO_SOUND_STEREO) {
+ zol->stereo = 1;
+ zol_setfreq(zol, zol->curfreq);
+@@ -293,10 +355,13 @@ static int zol_do_ioctl(struct inode *in
+ zol->stereo = 0;
+ zol_setfreq(zol, zol->curfreq);
+ }
+- return 0;
++#endif
++ return -EINVAL;
+ }
+- default:
+- return -ENOIOCTLCMD;
++
++ default:
++ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
++ zol_do_ioctl);
+ }
+ }
+
+@@ -323,7 +388,7 @@ static struct video_device zoltrix_radio
+ .owner = THIS_MODULE,
+ .name = "Zoltrix Radio Plus",
+ .type = VID_TYPE_TUNER,
+- .hardware = VID_HARDWARE_ZOLTRIX,
++ .hardware = 0,
+ .fops = &zoltrix_fops,
+ };
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index 94d078b..fbe5b61 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -16,6 +16,322 @@ config VIDEO_ADV_DEBUG
+ V4L devices.
+ In doubt, say N.
+
++config VIDEO_HELPER_CHIPS_AUTO
++ bool "Autoselect pertinent encoders/decoders and other helper chips"
++ default y
++ ---help---
++ Most video cards may require additional modules to encode or
++ decode audio/video standards. This option will autoselect
++ all pertinent modules to each selected video module.
++
++ Unselect this only if you know exaclty what you are doing, since
++ it may break support on some boards.
++
++ In doubt, say Y.
++
++#
++# Encoder / Decoder module configuration
++#
++
++menu "Encoders/decoders and other helper chips"
++ depends on VIDEO_DEV && !VIDEO_HELPER_CHIPS_AUTO
++
++comment "Audio decoders"
++
++config VIDEO_TVAUDIO
++ tristate "Simple audio decoder chips"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for several audio decoder chips found on some bt8xx boards:
++ Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
++ tea6320, tea6420, tda8425, ta8874z.
++ Microchip: pic16c54 based design on ProVideo PV951 board.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tvaudio.
++
++config VIDEO_TDA7432
++ tristate "Philips TDA7432 audio processor"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for tda7432 audio decoder chip found on some bt8xx boards.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tda7432.
++
++config VIDEO_TDA9840
++ tristate "Philips TDA9840 audio processor"
++ depends on VIDEO_DEV && I2C
++ ---help---
++ Support for tda9840 audio decoder chip found on some Zoran boards.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tda9840.
++
++config VIDEO_TDA9875
++ tristate "Philips TDA9875 audio processor"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for tda9875 audio decoder chip found on some bt8xx boards.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tda9875.
++
++config VIDEO_TEA6415C
++ tristate "Philips TEA6415C audio processor"
++ depends on VIDEO_DEV && I2C
++ ---help---
++ Support for tea6415c audio decoder chip found on some bt8xx boards.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tea6415c.
++
++config VIDEO_TEA6420
++ tristate "Philips TEA6420 audio processor"
++ depends on VIDEO_DEV && I2C
++ ---help---
++ Support for tea6420 audio decoder chip found on some bt8xx boards.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tea6420.
++
++config VIDEO_MSP3400
++ tristate "Micronas MSP34xx audio decoders"
++ depends on VIDEO_V4L2 && I2C
++ ---help---
++ Support for the Micronas MSP34xx series of audio decoders.
++
++ To compile this driver as a module, choose M here: the
++ module will be called msp3400.
++
++config VIDEO_CS53L32A
++ tristate "Cirrus Logic CS53L32A audio ADC"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the Cirrus Logic CS53L32A low voltage
++ stereo A/D converter.
++
++ To compile this driver as a module, choose M here: the
++ module will be called cs53l32a.
++
++config VIDEO_TLV320AIC23B
++ tristate "Texas Instruments TLV320AIC23B audio codec"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the Texas Instruments TLV320AIC23B audio codec.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tlv320aic23b.
++
++config VIDEO_WM8775
++ tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the Wolfson Microelectronics WM8775 high
++ performance stereo A/D Converter with a 4 channel input mixer.
++
++ To compile this driver as a module, choose M here: the
++ module will be called wm8775.
++
++config VIDEO_WM8739
++ tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the Wolfson Microelectronics WM8739
++ stereo A/D Converter.
++
++ To compile this driver as a module, choose M here: the
++ module will be called wm8739.
++
++comment "Video decoders"
++
++config VIDEO_BT819
++ tristate "BT819A VideoStream decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for BT819A video decoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called bt819.
++
++config VIDEO_BT856
++ tristate "BT856 VideoStream decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for BT856 video decoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called bt856.
++
++config VIDEO_BT866
++ tristate "BT866 VideoStream decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for BT866 video decoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called bt866.
++
++config VIDEO_KS0127
++ tristate "KS0127 video decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for KS0127 video decoder.
++
++ This chip is used on AverMedia AVS6EYES Zoran-based MJPEG
++ cards.
++
++ To compile this driver as a module, choose M here: the
++ module will be called ks0127.
++
++config VIDEO_SAA7110
++ tristate "Philips SAA7110 video decoder"
++ depends on VIDEO_V4L1
++ ---help---
++ Support for the Philips SAA7110 video decoders.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7110.
++
++config VIDEO_SAA7111
++ tristate "Philips SAA7111 video decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for the Philips SAA711 video decoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7111.
++
++config VIDEO_SAA7114
++ tristate "Philips SAA7114 video decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for the Philips SAA7114 video decoder. This driver
++ is used only on Zoran driver and should be moved soon to
++ SAA711x module.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7114.
++
++config VIDEO_SAA711X
++ tristate "Philips SAA7113/4/5 video decoders"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the Philips SAA7113/4/5 video decoders.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7115.
++
++config VIDEO_SAA7191
++ tristate "Philips SAA7191 video decoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for the Philips SAA7191 video decoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7191.
++
++config VIDEO_TVP5150
++ tristate "Texas Instruments TVP5150 video decoder"
++ depends on VIDEO_V4L2 && I2C
++ ---help---
++ Support for the Texas Instruments TVP5150 video decoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tvp5150.
++
++config VIDEO_VPX3220
++ tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for VPX322x video decoders.
++
++ To compile this driver as a module, choose M here: the
++ module will be called vpx3220.
++
++comment "Video and audio decoders"
++
++source "drivers/media/video/cx25840/Kconfig"
++
++comment "MPEG video encoders"
++
++config VIDEO_CX2341X
++ tristate "Conexant CX2341x MPEG encoders"
++ depends on VIDEO_V4L2 && EXPERIMENTAL
++ ---help---
++ Support for the Conexant CX23416 MPEG encoders
++ and CX23415 MPEG encoder/decoders.
++
++ This module currently supports the encoding functions only.
++
++ To compile this driver as a module, choose M here: the
++ module will be called cx2341x.
++
++comment "Video encoders"
++
++config VIDEO_SAA7127
++ tristate "Philips SAA7127/9 digital video encoders"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the Philips SAA7127/9 digital video encoders.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7127.
++
++config VIDEO_SAA7185
++ tristate "Philips SAA7185 video encoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for the Philips SAA7185 video encoder.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa7185.
++
++config VIDEO_ADV7170
++ tristate "Analog Devices ADV7170 video encoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for the Analog Devices ADV7170 video encoder driver
++
++ To compile this driver as a module, choose M here: the
++ module will be called adv7170.
++
++config VIDEO_ADV7175
++ tristate "Analog Devices ADV7175 video encoder"
++ depends on VIDEO_V4L1 && I2C
++ ---help---
++ Support for the Analog Devices ADV7175 video encoder driver
++
++ To compile this driver as a module, choose M here: the
++ module will be called adv7175.
++
++comment "Video improvement chips"
++
++config VIDEO_UPD64031A
++ tristate "NEC Electronics uPD64031A Ghost Reduction"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the NEC Electronics uPD64031A Ghost Reduction
++ video chip. It is most often found in NTSC TV cards made for
++ Japan and is used to reduce the 'ghosting' effect that can
++ be present in analog TV broadcasts.
++
++ To compile this driver as a module, choose M here: the
++ module will be called upd64031a.
++
++config VIDEO_UPD64083
++ tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++ ---help---
++ Support for the NEC Electronics uPD64083 3-Dimensional Y/C
++ separation video chip. It is used to improve the quality of
++ the colors of a composite signal.
++
++ To compile this driver as a module, choose M here: the
++ module will be called upd64083.
++
++endmenu # encoder / decoder chips
++
+ config VIDEO_VIVI
+ tristate "Virtual Video Driver"
+ depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
+@@ -37,7 +353,7 @@ config VIDEO_SAA6588
+ help
+ Support for Radio Data System (RDS) decoder. This allows seeing
+ radio station identification transmitted using this standard.
+- Currentlly, it works only with bt8x8 chips.
++ Currently, it works only with bt8x8 chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa6588.
+@@ -135,7 +451,7 @@ source "drivers/media/video/cpia2/Kconfi
+
+ config VIDEO_SAA5246A
+ tristate "SAA5246A, SAA5281 Teletext processor"
+- depends on I2C && VIDEO_V4L1
++ depends on I2C && VIDEO_V4L2
+ help
+ Support for I2C bus based teletext using the SAA5246A or SAA5281
+ chip. Useful only if you live in Europe.
+@@ -145,7 +461,7 @@ config VIDEO_SAA5246A
+
+ config VIDEO_SAA5249
+ tristate "SAA5249 Teletext processor"
+- depends on VIDEO_DEV && I2C && VIDEO_V4L1
++ depends on VIDEO_DEV && I2C && VIDEO_V4L2
+ help
+ Support for I2C bus based teletext using the SAA5249 chip. At the
+ moment this is only useful on some European WinTV cards.
+@@ -162,8 +478,9 @@ config TUNER_3036
+
+ config VIDEO_VINO
+ tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
+- depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L1
++ depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
+ select I2C_ALGO_SGI
++ select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ Say Y here to build in support for the Vino video input system found
+ on SGI Indy machines.
+@@ -176,6 +493,9 @@ config VIDEO_STRADIS
+ driver for PCI. There is a product page at
+ <http://www.stradis.com/>.
+
++config VIDEO_ZORAN_ZR36060
++ tristate
++
+ config VIDEO_ZORAN
+ tristate "Zoran ZR36057/36067 Video For Linux"
+ depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && !PPC64
+@@ -192,12 +512,18 @@ config VIDEO_ZORAN
+ config VIDEO_ZORAN_BUZ
+ tristate "Iomega Buz support"
+ depends on VIDEO_ZORAN
++ select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_ZORAN_ZR36060
+ help
+ Support for the Iomega Buz MJPEG capture/playback card.
+
+ config VIDEO_ZORAN_DC10
+ tristate "Pinnacle/Miro DC10(+) support"
+ depends on VIDEO_ZORAN
++ select VIDEO_SAA7110
++ select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_ZORAN_ZR36060
+ help
+ Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+ card.
+@@ -205,6 +531,8 @@ config VIDEO_ZORAN_DC10
+ config VIDEO_ZORAN_DC30
+ tristate "Pinnacle/Miro DC30(+) support"
+ depends on VIDEO_ZORAN
++ select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+ card. This also supports really old DC10 cards based on the
+@@ -213,6 +541,9 @@ config VIDEO_ZORAN_DC30
+ config VIDEO_ZORAN_LML33
+ tristate "Linux Media Labs LML33 support"
+ depends on VIDEO_ZORAN
++ select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_ZORAN_ZR36060
+ help
+ Support for the Linux Media Labs LML33 MJPEG capture/playback
+ card.
+@@ -220,6 +551,9 @@ config VIDEO_ZORAN_LML33
+ config VIDEO_ZORAN_LML33R10
+ tristate "Linux Media Labs LML33R10 support"
+ depends on VIDEO_ZORAN
++ select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_ZORAN_ZR36060
+ help
+ support for the Linux Media Labs LML33R10 MJPEG capture/playback
+ card.
+@@ -227,6 +561,9 @@ config VIDEO_ZORAN_LML33R10
+ config VIDEO_ZORAN_AVS6EYES
+ tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+ depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
++ select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_ZORAN_ZR36060
+ help
+ Support for the AverMedia 6 Eyes video surveillance card.
+
+@@ -263,6 +600,10 @@ config VIDEO_MXB
+ depends on PCI && VIDEO_V4L1 && I2C
+ select VIDEO_SAA7146_VV
+ select VIDEO_TUNER
++ select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ This is a video4linux driver for the 'Multimedia eXtension Board'
+ TV card by Siemens-Nixdorf.
+@@ -274,7 +615,7 @@ config VIDEO_DPC
+ tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
+ depends on PCI && VIDEO_V4L1 && I2C
+ select VIDEO_SAA7146_VV
+- select VIDEO_V4L2
++ select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ This is a video4linux driver for the 'dpc7146 demonstration
+ board' by Philips-Semiconductors. It's the reference design
+@@ -287,9 +628,8 @@ config VIDEO_DPC
+
+ config VIDEO_HEXIUM_ORION
+ tristate "Hexium HV-PCI6 and Orion frame grabber"
+- depends on PCI && VIDEO_V4L1 && I2C
++ depends on PCI && VIDEO_V4L2 && I2C
+ select VIDEO_SAA7146_VV
+- select VIDEO_V4L2
+ ---help---
+ This is a video4linux driver for the Hexium HV-PCI6 and
+ Orion frame grabber cards by Hexium.
+@@ -299,9 +639,8 @@ config VIDEO_HEXIUM_ORION
+
+ config VIDEO_HEXIUM_GEMINI
+ tristate "Hexium Gemini frame grabber"
+- depends on PCI && VIDEO_V4L1 && I2C
++ depends on PCI && VIDEO_V4L2 && I2C
+ select VIDEO_SAA7146_VV
+- select VIDEO_V4L2
+ ---help---
+ This is a video4linux driver for the Hexium Gemini frame
+ grabber card by Hexium. Please note that the Gemini Dual
+@@ -320,123 +659,16 @@ config VIDEO_M32R_AR
+ camera module.
+
+ config VIDEO_M32R_AR_M64278
+- tristate "Use Colour AR module M64278(VGA)"
+- depends on VIDEO_M32R_AR && PLAT_M32700UT
+- ---help---
+- Say Y here to use the Renesas M64278E-800 camera module,
+- which supports VGA(640x480 pixcels) size of images.
+-
+-#
+-# Encoder / Decoder module configuration
+-#
+-
+-menu "Encoders and Decoders"
+- depends on VIDEO_DEV
+-
+-config VIDEO_MSP3400
+- tristate "Micronas MSP34xx audio decoders"
+- depends on VIDEO_DEV && I2C
+- ---help---
+- Support for the Micronas MSP34xx series of audio decoders.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called msp3400.
+-
+-config VIDEO_CS53L32A
+- tristate "Cirrus Logic CS53L32A audio ADC"
+- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+- ---help---
+- Support for the Cirrus Logic CS53L32A low voltage
+- stereo A/D converter.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called cs53l32a.
+-
+-config VIDEO_TLV320AIC23B
+- tristate "Texas Instruments TLV320AIC23B audio codec"
+- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+- ---help---
+- Support for the Texas Instruments TLV320AIC23B audio codec.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called tlv320aic23b.
+-
+-config VIDEO_WM8775
+- tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
+- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+- ---help---
+- Support for the Wolfson Microelectronics WM8775 high
+- performance stereo A/D Converter with a 4 channel input mixer.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called wm8775.
+-
+-config VIDEO_WM8739
+- tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
+- depends on VIDEO_DEV && I2C && EXPERIMENTAL
++ tristate "AR device with color module M64278(VGA)"
++ depends on PLAT_M32700UT
++ select VIDEO_M32R_AR
+ ---help---
+- Support for the Wolfson Microelectronics WM8739
+- stereo A/D Converter.
++ This is a video4linux driver for the Renesas AR (Artificial
++ Retina) with M64278E-800 camera module.
++ This module supports VGA(640x480 pixels) resolutions.
+
+ To compile this driver as a module, choose M here: the
+- module will be called wm8739.
+-
+-config VIDEO_CX2341X
+- tristate "Conexant CX2341x MPEG encoders"
+- depends on VIDEO_V4L2 && EXPERIMENTAL
+- ---help---
+- Support for the Conexant CX23416 MPEG encoders
+- and CX23415 MPEG encoder/decoders.
+-
+- This module currently supports the encoding functions only.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called cx2341x.
+-
+-source "drivers/media/video/cx25840/Kconfig"
+-
+-config VIDEO_SAA711X
+- tristate "Philips SAA7113/4/5 video decoders"
+- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+- ---help---
+- Support for the Philips SAA7113/4/5 video decoders.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called saa7115.
+-
+-config VIDEO_SAA7127
+- tristate "Philips SAA7127/9 digital video encoders"
+- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+- ---help---
+- Support for the Philips SAA7127/9 digital video encoders.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called saa7127.
+-
+-config VIDEO_UPD64031A
+- tristate "NEC Electronics uPD64031A Ghost Reduction"
+- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+- ---help---
+- Support for the NEC Electronics uPD64031A Ghost Reduction
+- video chip. It is most often found in NTSC TV cards made for
+- Japan and is used to reduce the 'ghosting' effect that can
+- be present in analog TV broadcasts.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called upd64031a.
+-
+-config VIDEO_UPD64083
+- tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
+- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+- ---help---
+- Support for the NEC Electronics uPD64083 3-Dimensional Y/C
+- separation video chip. It is used to improve the quality of
+- the colors of a composite signal.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called upd64083.
+-
+-endmenu # encoder / decoder chips
++ module will be called arv.
+
+ #
+ # USB Multimedia device configuration
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index e82e511..af57abc 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -17,7 +17,10 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
+ endif
+
+ obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+-obj-$(CONFIG_VIDEO_BT848) += tvaudio.o tda7432.o tda9875.o ir-kbd-i2c.o
++obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
++obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
++obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
++obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
+ obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
+
+ obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
+@@ -27,17 +30,32 @@ obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
+ obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+ obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+ obj-$(CONFIG_VIDEO_W9966) += w9966.o
+-obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o zr36060.o
+-obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o zr36060.o
+-obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
+- zr36016.o
+-obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
+-obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+-obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
++
++obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
++obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
++obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
++obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
++obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
++obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
++obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
++obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
++obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
++obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
++obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
++obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
++obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
++obj-$(CONFIG_VIDEO_BT819) += bt819.o
++obj-$(CONFIG_VIDEO_BT856) += bt856.o
++obj-$(CONFIG_VIDEO_BT866) += bt866.o
++obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
++
+ obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
++obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
++obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
++
+ obj-$(CONFIG_VIDEO_PMS) += pms.o
+ obj-$(CONFIG_VIDEO_PLANB) += planb.o
+-obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o
++obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
+ obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+ obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+@@ -46,7 +64,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
+ obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+ obj-$(CONFIG_VIDEO_CX88) += cx88/
+ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+-obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
++obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
+ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+@@ -55,10 +73,10 @@ obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+ obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+ obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
+ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+-obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o
++obj-$(CONFIG_VIDEO_MXB) += mxb.o
+ obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
+ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+-obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
++obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
+ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
+
+ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+@@ -70,8 +88,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom
+ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+
+ obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+-obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+-obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
+ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
+@@ -96,4 +112,3 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+ extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
+-
+diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
+index 5c5e682..4861799 100644
+--- a/drivers/media/video/arv.c
++++ b/drivers/media/video/arv.c
+@@ -549,7 +549,7 @@ static int ar_ioctl(struct inode *inode,
+ /*
+ * Interrupt handler
+ */
+-static void ar_interrupt(int irq, void *dev, struct pt_regs *regs)
++static void ar_interrupt(int irq, void *dev)
+ {
+ struct ar_device *ar = dev;
+ unsigned int line_count;
+diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
+index 05e42bb..772fd52 100644
+--- a/drivers/media/video/bt866.c
++++ b/drivers/media/video/bt866.c
+@@ -65,7 +65,7 @@ MODULE_LICENSE("GPL");
+ struct bt866 {
+ struct i2c_client *i2c;
+ int addr;
+- unsigned char reg[128];
++ unsigned char reg[256];
+
+ int norm;
+ int enable;
+diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
+index cdcf556..58eae88 100644
+--- a/drivers/media/video/bt8xx/Kconfig
++++ b/drivers/media/video/bt8xx/Kconfig
+@@ -8,7 +8,10 @@ config VIDEO_BT848
+ select VIDEO_IR
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+- select VIDEO_MSP3400
++ select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TDA9875 if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ Support for BT848 based frame grabber/overlay boards. This includes
+ the Miro, Hauppauge and STB boards. Please read the material in
+diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
+index de14818..a84903e 100644
+--- a/drivers/media/video/bt8xx/bttv-cards.c
++++ b/drivers/media/video/bt8xx/bttv-cards.c
+@@ -2000,7 +2000,7 @@ struct tvcard bttv_tvcards[] = {
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+- .muxsel = { 3, 0, 1, 2 },
++ .muxsel = { 3, 1 },
+ .pll = PLL_28,
+ .no_gpioirq = 1,
+ .has_dvb = 1,
+@@ -4991,7 +4991,7 @@ void __devinit bttv_check_chipset(void)
+ int pcipci_fail = 0;
+ struct pci_dev *dev = NULL;
+
+- if (pci_pci_problems & PCIPCI_FAIL)
++ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */
+ pcipci_fail = 1;
+ if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
+ triton1 = 1;
+diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
+index 20dff7c..6e1ddad 100644
+--- a/drivers/media/video/bt8xx/bttv-driver.c
++++ b/drivers/media/video/bt8xx/bttv-driver.c
+@@ -2431,6 +2431,14 @@ static int bttv_do_ioctl(struct inode *i
+ fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
+ if (fh->ovfmt)
+ fbuf->depth = fh->ovfmt->depth;
++ else {
++ if (fbuf->width)
++ fbuf->depth = ((fbuf->bytesperline<<3)
++ + (fbuf->width-1) )
++ /fbuf->width;
++ else
++ fbuf->depth = 0;
++ }
+ return 0;
+ }
+ case VIDIOCSFBUF:
+@@ -3745,7 +3753,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
+ spin_unlock(&btv->s_lock);
+ }
+
+-static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t bttv_irq(int irq, void *dev_id)
+ {
+ u32 stat,astat;
+ u32 dstat;
+@@ -4186,6 +4194,7 @@ static void __devexit bttv_remove(struct
+ return;
+ }
+
++#ifdef CONFIG_PM
+ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
+ {
+ struct bttv *btv = pci_get_drvdata(pci_dev);
+@@ -4266,6 +4275,7 @@ static int bttv_resume(struct pci_dev *p
+ spin_unlock_irqrestore(&btv->s_lock,flags);
+ return 0;
+ }
++#endif
+
+ static struct pci_device_id bttv_pci_tbl[] = {
+ {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+@@ -4286,8 +4296,10 @@ static struct pci_driver bttv_pci_driver
+ .id_table = bttv_pci_tbl,
+ .probe = bttv_probe,
+ .remove = __devexit_p(bttv_remove),
++#ifdef CONFIG_PM
+ .suspend = bttv_suspend,
+ .resume = bttv_resume,
++#endif
+ };
+
+ static int bttv_init_module(void)
+diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
+index 4b562b3..70de6c9 100644
+--- a/drivers/media/video/bt8xx/bttv-i2c.c
++++ b/drivers/media/video/bt8xx/bttv-i2c.c
+@@ -8,6 +8,9 @@
+ & Marcus Metzler (mocm at thp.uni-koeln.de)
+ (c) 1999-2003 Gerd Knorr <kraxel at bytesex.org>
+
++ (c) 2005 Mauro Carvalho Chehab <mchehab at infradead.org>
++ - Multituner support and i2c address binding
++
+ 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
+@@ -45,10 +48,18 @@ static int i2c_debug;
+ static int i2c_hw;
+ static int i2c_scan;
+ module_param(i2c_debug, int, 0644);
++MODULE_PARM_DESC(i2c_hw,"configure i2c debug level");
+ module_param(i2c_hw, int, 0444);
++MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, "
++ "instead of software bitbang");
+ module_param(i2c_scan, int, 0444);
+ MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
++static unsigned int i2c_udelay = 5;
++module_param(i2c_udelay, int, 0444);
++MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs "
++ "(should be 5 or higher). Lower value means higher bus speed.");
++
+ /* ----------------------------------------------------------------------- */
+ /* I2C functions - bitbanging adapter (software i2c) */
+
+@@ -100,7 +111,6 @@ static struct i2c_algo_bit_data bttv_i2c
+ .getsda = bttv_bit_getsda,
+ .getscl = bttv_bit_getscl,
+ .udelay = 16,
+- .mdelay = 10,
+ .timeout = 200,
+ };
+
+@@ -426,6 +436,11 @@ int __devinit init_bttv_i2c(struct bttv
+ sizeof(bttv_i2c_adap_hw_template));
+ } else {
+ /* bt848 */
++ /* Prevents usage of invalid delay values */
++ if (i2c_udelay<5)
++ i2c_udelay=5;
++ bttv_i2c_algo_bit_template.udelay=i2c_udelay;
++
+ memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
+ sizeof(bttv_i2c_adap_sw_template));
+ memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
+diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
+index b69ee11..d82a488 100644
+--- a/drivers/media/video/compat_ioctl32.c
++++ b/drivers/media/video/compat_ioctl32.c
+@@ -58,6 +58,7 @@ static int put_video_tuner32(struct vide
+ return 0;
+ }
+
++
+ struct video_buffer32 {
+ compat_caddr_t base;
+ compat_int_t height, width, depth, bytesperline;
+@@ -618,6 +619,7 @@ static int do_video_ioctl(struct file *f
+ struct video_buffer vb;
+ struct video_window vw;
+ struct video_code vc;
++ struct video_audio va;
+ #endif
+ struct v4l2_format v2f;
+ struct v4l2_buffer v2b;
+@@ -635,31 +637,31 @@ static int do_video_ioctl(struct file *f
+ /* First, convert the command. */
+ switch(cmd) {
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+- case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+- case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+- case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+- case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+- case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+- case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+- case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+- case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
++ case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
++ case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
++ case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
++ case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
++ case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
++ case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
++ case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
++ case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
+ #endif
+- case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+- case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+- case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+- case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+- case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+- case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+- case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+- case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+- case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+- case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
++ case VIDIOC_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
++ case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
++ case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
++ case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
++ case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
++ case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
++ case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
++ case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
++ case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
++ case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
+ case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
+ case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
+- case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
+- case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+- case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+- case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
++ case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
++ case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
++ case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
++ case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
+ };
+
+ switch(cmd) {
+@@ -676,6 +678,7 @@ static int do_video_ioctl(struct file *f
+ compatible_arg = 0;
+ break;
+
++
+ case VIDIOCSFREQ:
+ #endif
+ case VIDIOC_S_INPUT:
+@@ -683,7 +686,7 @@ static int do_video_ioctl(struct file *f
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ err = get_user(karg.vx, (u32 __user *)up);
+- compatible_arg = 0;
++ compatible_arg = 1;
+ break;
+
+ case VIDIOC_S_FBUF:
+@@ -739,6 +742,7 @@ static int do_video_ioctl(struct file *f
+ case VIDIOC_G_FBUF:
+ case VIDIOC_G_INPUT:
+ compatible_arg = 0;
++ break;
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+ case VIDIOCSMICROCODE:
+ err = microcode32(&karg.vc, up);
+@@ -755,7 +759,7 @@ static int do_video_ioctl(struct file *f
+ mm_segment_t old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+- err = native_ioctl(file, realcmd, (unsigned long)&karg);
++ err = native_ioctl(file, realcmd, (unsigned long) &karg);
+ set_fs(old_fs);
+ }
+ if(err == 0) {
+@@ -772,6 +776,7 @@ static int do_video_ioctl(struct file *f
+ case VIDIOCGFBUF:
+ err = put_video_buffer32(&karg.vb, up);
+ break;
++
+ #endif
+ case VIDIOC_G_FBUF:
+ err = put_v4l2_framebuffer32(&karg.v2fb, up);
+@@ -841,10 +846,14 @@ long v4l_compat_ioctl32(struct file *fil
+ case VIDIOCSFBUF32:
+ case VIDIOCGFREQ32:
+ case VIDIOCSFREQ32:
++ case VIDIOCGAUDIO:
++ case VIDIOCSAUDIO:
+ #endif
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_ENUM_FMT:
+ case VIDIOC_G_FMT32:
++ case VIDIOC_CROPCAP:
++ case VIDIOC_S_CROP:
+ case VIDIOC_S_FMT32:
+ case VIDIOC_REQBUFS:
+ case VIDIOC_QUERYBUF32:
+@@ -882,8 +891,6 @@ long v4l_compat_ioctl32(struct file *fil
+ case VIDIOCSPICT:
+ case VIDIOCCAPTURE:
+ case VIDIOCKEY:
+- case VIDIOCGAUDIO:
+- case VIDIOCSAUDIO:
+ case VIDIOCSYNC:
+ case VIDIOCMCAPTURE:
+ case VIDIOCGMBUF:
+diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
+index c5ecb2b..8d2dfc1 100644
+--- a/drivers/media/video/cpia2/cpia2.h
++++ b/drivers/media/video/cpia2/cpia2.h
+@@ -50,10 +50,6 @@
+ /***
+ * Image defines
+ ***/
+-#ifndef true
+-#define true 1
+-#define false 0
+-#endif
+
+ /* Misc constants */
+ #define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */
+diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
+index f4da029..28dc6a1 100644
+--- a/drivers/media/video/cpia2/cpia2_usb.c
++++ b/drivers/media/video/cpia2/cpia2_usb.c
+@@ -49,7 +49,7 @@ static int frame_sizes[] = {
+ #define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt]
+
+ static void process_frame(struct camera_data *cam);
+-static void cpia2_usb_complete(struct urb *urb, struct pt_regs *);
++static void cpia2_usb_complete(struct urb *urb);
+ static int cpia2_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id);
+ static void cpia2_usb_disconnect(struct usb_interface *intf);
+@@ -199,7 +199,7 @@ static void add_COM(struct camera_data *
+ *
+ * callback when incoming packet is received
+ *****************************************************************************/
+-static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs)
++static void cpia2_usb_complete(struct urb *urb)
+ {
+ int i;
+ unsigned char *cdata;
+diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
+index 2ee34a3..9da4726 100644
+--- a/drivers/media/video/cpia_usb.c
++++ b/drivers/media/video/cpia_usb.c
+@@ -109,7 +109,7 @@ static struct cpia_camera_ops cpia_usb_o
+ static LIST_HEAD(cam_list);
+ static spinlock_t cam_list_lock_usb;
+
+-static void cpia_usb_complete(struct urb *urb, struct pt_regs *regs)
++static void cpia_usb_complete(struct urb *urb)
+ {
+ int i;
+ char *cdata;
+diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
+index 65f00fc..657e0b9 100644
+--- a/drivers/media/video/cx2341x.c
++++ b/drivers/media/video/cx2341x.c
+@@ -691,7 +691,7 @@ void cx2341x_fill_defaults(struct cx2341
+ .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+- .video_temporal_filter = 0,
++ .video_temporal_filter = 8,
+ .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ .video_luma_median_filter_top = 255,
+ .video_luma_median_filter_bottom = 0,
+@@ -731,6 +731,7 @@ int cx2341x_update(void *priv, cx2341x_m
+ };
+
+ int err = 0;
++ u16 temporal = new->video_temporal_filter;
+
+ cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+@@ -741,6 +742,7 @@ int cx2341x_update(void *priv, cx2341x_m
+
+ if (old == NULL || old->width != new->width || old->height != new->height ||
+ old->video_encoding != new->video_encoding) {
++ int is_scaling;
+ u16 w = new->width;
+ u16 h = new->height;
+
+@@ -750,6 +752,20 @@ int cx2341x_update(void *priv, cx2341x_m
+ }
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+ if (err) return err;
++
++ /* Adjust temporal filter if necessary. The problem with the temporal
++ filter is that it works well with full resolution capturing, but
++ not when the capture window is scaled (the filter introduces
++ a ghosting effect). So if the capture window changed, and there is
++ no updated filter value, then the filter is set depending on whether
++ the new window is full resolution or not.
++
++ For full resolution a setting of 8 really improves the video
++ quality, especially if the original video quality is suboptimal. */
++ is_scaling = new->width != 720 || new->height != (new->is_50hz ? 576 : 480);
++ if (old && old->video_temporal_filter == temporal) {
++ temporal = is_scaling ? 0 : 8;
++ }
+ }
+
+ if (old == NULL || old->stream_type != new->stream_type) {
+@@ -815,9 +831,9 @@ int cx2341x_update(void *priv, cx2341x_m
+ }
+ if (old == NULL ||
+ old->video_spatial_filter != new->video_spatial_filter ||
+- old->video_temporal_filter != new->video_temporal_filter) {
++ old->video_temporal_filter != temporal) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+- new->video_spatial_filter, new->video_temporal_filter);
++ new->video_spatial_filter, temporal);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+@@ -855,6 +871,9 @@ void cx2341x_log_status(struct cx2341x_m
+ printk(KERN_INFO "%s: Stream: %s\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
++ printk(KERN_INFO "%s: VBI Format: %s\n",
++ prefix,
++ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
+
+ /* Video */
+ printk(KERN_INFO "%s: Video: %dx%d, %d fps\n",
+diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
+index 854264e..7cf29a0 100644
+--- a/drivers/media/video/cx25840/Kconfig
++++ b/drivers/media/video/cx25840/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_CX25840
+ tristate "Conexant CX2584x audio/video decoders"
+- depends on VIDEO_DEV && I2C && EXPERIMENTAL
++ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ Support for the Conexant CX2584x audio/video decoders.
+diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
+index 6cc8bf2..f85f208 100644
+--- a/drivers/media/video/cx25840/cx25840-vbi.c
++++ b/drivers/media/video/cx25840/cx25840-vbi.c
+@@ -111,6 +111,10 @@ void cx25840_vbi_setup(struct i2c_client
+ uv_lpf=0;
+ comb=0;
+ sc=0x0a425f;
++ } else if (std == V4L2_STD_PAL_Nc) {
++ uv_lpf=1;
++ comb=0x20;
++ sc=556453;
+ } else {
+ uv_lpf=1;
+ comb=0x20;
+@@ -231,6 +235,7 @@ int cx25840_vbi(struct i2c_client *clien
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ 0, 0, 0, 0
+ };
++ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+ int i;
+
+ fmt = arg;
+@@ -242,13 +247,25 @@ int cx25840_vbi(struct i2c_client *clien
+ if ((cx25840_read(client, 0x404) & 0x10) == 0)
+ break;
+
+- for (i = 7; i <= 23; i++) {
+- u8 v = cx25840_read(client, 0x424 + i - 7);
++ if (is_pal) {
++ for (i = 7; i <= 23; i++) {
++ u8 v = cx25840_read(client, 0x424 + i - 7);
+
+- svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+- svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+- svbi->service_set |=
+- svbi->service_lines[0][i] | svbi->service_lines[1][i];
++ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
++ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
++ svbi->service_set |=
++ svbi->service_lines[0][i] | svbi->service_lines[1][i];
++ }
++ }
++ else {
++ for (i = 10; i <= 21; i++) {
++ u8 v = cx25840_read(client, 0x424 + i - 10);
++
++ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
++ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
++ svbi->service_set |=
++ svbi->service_lines[0][i] | svbi->service_lines[1][i];
++ }
+ }
+ break;
+ }
+diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
+index 7a94e6a..0f9d969 100644
+--- a/drivers/media/video/cx88/Kconfig
++++ b/drivers/media/video/cx88/Kconfig
+@@ -1,7 +1,3 @@
+-config VIDEO_CX88_VP3054
+- tristate
+- depends on VIDEO_CX88_DVB && DVB_MT352
+-
+ config VIDEO_CX88
+ tristate "Conexant 2388x (bt878 successor) support"
+ depends on VIDEO_DEV && PCI && I2C
+@@ -52,6 +48,14 @@ config VIDEO_CX88_DVB
+ depends on VIDEO_CX88 && DVB_CORE
+ select VIDEO_BUF_DVB
+ select DVB_PLL
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
++ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
++ select DVB_OR51132 if !DVB_FE_CUSTOMISE
++ select DVB_CX22702 if !DVB_FE_CUSTOMISE
++ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
++ select DVB_NXT200X if !DVB_FE_CUSTOMISE
++ select DVB_CX24123 if !DVB_FE_CUSTOMISE
++ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ ---help---
+ This adds support for DVB/ATSC cards based on the
+ Conexant 2388x chip.
+@@ -59,101 +63,12 @@ config VIDEO_CX88_DVB
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-dvb.
+
+- You must also select one or more DVB/ATSC demodulators.
+- If you are unsure which you need, choose all of them.
+-
+-config VIDEO_CX88_DVB_ALL_FRONTENDS
+- bool "Build all supported frontends for cx2388x based TV cards"
+- default y
+- depends on VIDEO_CX88_DVB
+- select DVB_MT352
+- select VIDEO_CX88_VP3054
+- select DVB_ZL10353
+- select DVB_OR51132
+- select DVB_CX22702
+- select DVB_LGDT330X
+- select DVB_NXT200X
+- select DVB_CX24123
+- select DVB_ISL6421
+- ---help---
+- This builds cx88-dvb with all currently supported frontend
+- demodulators. If you wish to tweak your configuration, and
+- only include support for the hardware that you need, choose N here.
+-
+- If you are unsure, choose Y.
+-
+-config VIDEO_CX88_DVB_MT352
+- bool "Zarlink MT352 DVB-T Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_MT352
+- ---help---
+- This adds DVB-T support for cards based on the
+- Connexant 2388x chip and the MT352 demodulator.
+-
+-config VIDEO_CX88_DVB_VP3054
+- bool "VP-3054 Secondary I2C Bus Support"
+- default y
+- depends on VIDEO_CX88_DVB_MT352
+- select VIDEO_CX88_VP3054
++config VIDEO_CX88_VP3054
++ tristate "VP-3054 Secondary I2C Bus Support"
++ default m
++ depends on VIDEO_CX88_DVB && DVB_MT352
+ ---help---
+ This adds DVB-T support for cards based on the
+- Connexant 2388x chip and the MT352 demodulator,
++ Conexant 2388x chip and the MT352 demodulator,
+ which also require support for the VP-3054
+ Secondary I2C bus, such at DNTV Live! DVB-T Pro.
+-
+-config VIDEO_CX88_DVB_ZL10353
+- bool "Zarlink ZL10353 DVB-T Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_ZL10353
+- ---help---
+- This adds DVB-T support for cards based on the
+- Connexant 2388x chip and the ZL10353 demodulator,
+- successor to the Zarlink MT352.
+-
+-config VIDEO_CX88_DVB_OR51132
+- bool "OR51132 ATSC Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_OR51132
+- ---help---
+- This adds ATSC 8VSB and QAM64/256 support for cards based on the
+- Connexant 2388x chip and the OR51132 demodulator.
+-
+-config VIDEO_CX88_DVB_CX22702
+- bool "Conexant CX22702 DVB-T Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_CX22702
+- ---help---
+- This adds DVB-T support for cards based on the
+- Connexant 2388x chip and the CX22702 demodulator.
+-
+-config VIDEO_CX88_DVB_LGDT330X
+- bool "LG Electronics DT3302/DT3303 ATSC Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_LGDT330X
+- ---help---
+- This adds ATSC 8VSB and QAM64/256 support for cards based on the
+- Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
+-
+-config VIDEO_CX88_DVB_NXT200X
+- bool "NXT2002/NXT2004 ATSC Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_NXT200X
+- ---help---
+- This adds ATSC 8VSB and QAM64/256 support for cards based on the
+- Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
+-
+-config VIDEO_CX88_DVB_CX24123
+- bool "Conexant CX24123 DVB-S Support"
+- default y
+- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+- select DVB_CX24123
+- select DVB_ISL6421
+- ---help---
+- This adds DVB-S support for cards based on the
+- Connexant 2388x chip and the CX24123 demodulator.
+diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
+index 352b919..639c3b6 100644
+--- a/drivers/media/video/cx88/Makefile
++++ b/drivers/media/video/cx88/Makefile
+@@ -14,13 +14,6 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-
+ EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+ extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
+-extra-cflags-$(CONFIG_DVB_CX22702) += -DHAVE_CX22702=1
+-extra-cflags-$(CONFIG_DVB_OR51132) += -DHAVE_OR51132=1
+-extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1
+-extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
+-extra-cflags-$(CONFIG_DVB_ZL10353) += -DHAVE_ZL10353=1
+-extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1
+-extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1
+ extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
+
+ EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
+index f034066..e4355fd 100644
+--- a/drivers/media/video/cx88/cx88-alsa.c
++++ b/drivers/media/video/cx88/cx88-alsa.c
+@@ -262,7 +262,7 @@ static void cx8801_aud_irq(snd_cx88_card
+ /*
+ * BOARD Specific: Handles IRQ calls
+ */
+-static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cx8801_irq(int irq, void *dev_id)
+ {
+ snd_cx88_card_t *chip = dev_id;
+ struct cx88_core *core = chip->core;
+diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
+index b60177f..4673832 100644
+--- a/drivers/media/video/cx88/cx88-blackbird.c
++++ b/drivers/media/video/cx88/cx88-blackbird.c
+@@ -896,7 +896,7 @@ static int mpeg_do_ioctl(struct inode *i
+ snprintf(name, sizeof(name), "%s/2", core->name);
+ printk("%s/2: ============ START LOG STATUS ============\n",
+ core->name);
+- cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, 0);
++ cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+ cx2341x_log_status(&dev->params, name);
+ printk("%s/2: ============= END LOG STATUS =============\n",
+ core->name);
+@@ -1086,7 +1086,7 @@ static int __devinit blackbird_probe(str
+ return -EINVAL;
+
+ err = -ENODEV;
+- if (!cx88_boards[core->board].blackbird)
++ if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
+ goto fail_core;
+
+ err = -ENOMEM;
+@@ -1160,8 +1160,10 @@ static struct pci_driver blackbird_pci_d
+ .id_table = cx8802_pci_tbl,
+ .probe = blackbird_probe,
+ .remove = __devexit_p(blackbird_remove),
++#ifdef CONFIG_PM
+ .suspend = cx8802_suspend_common,
+ .resume = cx8802_resume_common,
++#endif
+ };
+
+ static int blackbird_init(void)
+diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
+index 14bd486..f764a57 100644
+--- a/drivers/media/video/cx88/cx88-cards.c
++++ b/drivers/media/video/cx88/cx88-cards.c
+@@ -294,7 +294,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x0000bd62,
+ },
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_IODATA_GVVCP3PCI] = {
+ .name = "IODATA GV-VCP3/PCI",
+@@ -358,7 +358,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x0000fde2,
+ },
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_MSI_TVANYWHERE] = {
+ .name = "MSI TV- at nywhere",
+@@ -401,7 +401,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
+ .name = "DViCO FusionHDTV DVB-T1",
+@@ -418,7 +418,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x000027df,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_KWORLD_LTV883] = {
+ .name = "KWorld LTV883RF",
+@@ -488,7 +488,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x0f00,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
+ .name = "Hauppauge Nova-T DVB-T",
+@@ -500,7 +500,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_CONEXANT_DVB_T1] = {
+ .name = "Conexant DVB-T reference design",
+@@ -512,7 +512,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_PROVIDEO_PV259] = {
+ .name = "Provideo PV259",
+@@ -524,7 +524,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ }},
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
+ .name = "DViCO FusionHDTV DVB-T Plus",
+@@ -541,7 +541,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x000027df,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DNTV_LIVE_DVB_T] = {
+ .name = "digitalnow DNTV Live! DVB-T",
+@@ -560,7 +560,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio0 = 0x00000700,
+ .gpio2 = 0x00000101,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_PCHDTV_HD3000] = {
+ .name = "pcHDTV HD3000 HDTV",
+@@ -599,7 +599,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio2 = 0x00000000,
+ .gpio3 = 0x00000000,
+ },
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_HAUPPAUGE_ROSLYN] = {
+ // entry added by Kaustubh D. Bhalerao <bhalerao.1 at osu.edu>
+@@ -633,7 +633,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio0 = 0xed96,
+ .gpio2 = 0x00ff,
+ },
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_DIGITALLOGIC_MEC] = {
+ .name = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
+@@ -659,7 +659,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x00009d00,
+ },
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_IODATA_GVBCTV7E] = {
+ .name = "IODATA GV/BCTV7E",
+@@ -727,7 +727,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x97e9,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+ .name = "ADS Tech Instant TV DVB-T PCI",
+@@ -746,7 +746,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
+ .name = "TerraTec Cinergy 1400 DVB-T",
+@@ -755,7 +755,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
+ .name = "DViCO FusionHDTV 5 Gold",
+@@ -777,7 +777,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x87f9,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
+ .name = "AverMedia UltraTV Media Center PCI 550",
+@@ -786,7 +786,7 @@ struct cx88_board cx88_boards[] = {
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 0,
+@@ -854,7 +854,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_WINFAST_DTV1000] = {
+ .name = "WinFast DTV1000-T",
+@@ -866,7 +866,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_AVERTV_303] = {
+ .name = "AVerTV 303 (M126)",
+@@ -914,7 +914,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
+ .name = "Hauppauge Nova-SE2 DVB-S",
+@@ -926,7 +926,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_KWORLD_DVBS_100] = {
+ .name = "KWorld DVB-S 100",
+@@ -944,7 +944,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_HAUPPAUGE_HVR1100] = {
+ .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
+@@ -964,7 +964,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ }},
+ /* fixme: Add radio support */
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
+ .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+@@ -981,7 +981,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 1,
+ }},
+ /* fixme: Add radio support */
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = {
+ .name = "digitalnow DNTV Live! DVB-T Pro",
+@@ -1008,7 +1008,7 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_RADIO,
+ .gpio0 = 0xf80808,
+ },
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_KWORLD_DVB_T_CX22702] = {
+ /* Kworld V-stream Xpert DVB-T with Thomson tuner */
+@@ -1030,7 +1030,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
+ .name = "DViCO FusionHDTV DVB-T Dual Digital",
+@@ -1041,13 +1041,13 @@ struct cx88_board cx88_boards[] = {
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+- .gpio0 = 0x000027df,
++ .gpio0 = 0x000067df,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+- .gpio0 = 0x000027df,
++ .gpio0 = 0x000067df,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
+ /* FIXME: Audio not working for s-video / composite inputs. */
+@@ -1075,7 +1075,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio0 = 0x3de6,
+ .gpio2 = 0x00ff,
+ },
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
+ .name = "DViCO FusionHDTV DVB-T Hybrid",
+@@ -1096,7 +1096,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x0000a75b,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_PCHDTV_HD5500] = {
+ .name = "pcHDTV HD5500 HDTV",
+@@ -1118,7 +1118,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 2,
+ .gpio0 = 0x87f9,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+ /* FIXME: tested TV input only, disabled composite,
+@@ -1134,7 +1134,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 0,
+ .gpio0 = 0x0000BDE6
+ }},
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+ /* FIXME: SVideo, Composite and FM inputs are untested */
+@@ -1150,7 +1150,7 @@ struct cx88_board cx88_boards[] = {
+ .vmux = 0,
+ .gpio0 = 0x5da6,
+ }},
+- .blackbird = 1,
++ .mpeg = CX88_MPEG_BLACKBIRD,
+ },
+ [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+ .name = "NPG Tech Real TV FM Top 10",
+@@ -1192,7 +1192,7 @@ struct cx88_board cx88_boards[] = {
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_GENIATECH_DVBS] = {
+ .name = "Geniatech DVB-S",
+@@ -1207,7 +1207,103 @@ struct cx88_board cx88_boards[] = {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ }},
+- .dvb = 1,
++ .mpeg = CX88_MPEG_DVB,
++ },
++ [CX88_BOARD_HAUPPAUGE_HVR3000] = {
++ /* FIXME: Add dvb & radio support */
++ .name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
++ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .tda9887_conf = TDA9887_PRESENT,
++ .input = {{
++ .type = CX88_VMUX_TELEVISION,
++ .vmux = 0,
++ .gpio0 = 0x84bf,
++ },{
++ .type = CX88_VMUX_COMPOSITE1,
++ .vmux = 1,
++ .gpio0 = 0x84bf,
++ },{
++ .type = CX88_VMUX_SVIDEO,
++ .vmux = 2,
++ .gpio0 = 0x84bf,
++ }},
++ .mpeg = CX88_MPEG_DVB,
++ },
++ [CX88_BOARD_NORWOOD_MICRO] = {
++ .name = "Norwood Micro TV Tuner",
++ .tuner_type = TUNER_TNF_5335MF,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .input = {{
++ .type = CX88_VMUX_TELEVISION,
++ .vmux = 0,
++ .gpio0 = 0x0709,
++ },{
++ .type = CX88_VMUX_COMPOSITE1,
++ .vmux = 1,
++ .gpio0 = 0x070b,
++ },{
++ .type = CX88_VMUX_SVIDEO,
++ .vmux = 2,
++ .gpio0 = 0x070b,
++ }},
++ },
++ [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
++ .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
++ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .input = {{
++ .type = CX88_VMUX_TELEVISION,
++ .vmux = 0,
++ .gpio0 = 0x003fffff,
++ .gpio1 = 0x00e00000,
++ .gpio2 = 0x003fffff,
++ .gpio3 = 0x02000000,
++ },{
++ .type = CX88_VMUX_COMPOSITE1,
++ .vmux = 1,
++ .gpio0 = 0x003fffff,
++ .gpio1 = 0x00e00000,
++ .gpio2 = 0x003fffff,
++ .gpio3 = 0x02000000,
++ },{
++ .type = CX88_VMUX_SVIDEO,
++ .vmux = 2,
++ .gpio0 = 0x003fffff,
++ .gpio1 = 0x00e00000,
++ .gpio2 = 0x003fffff,
++ .gpio3 = 0x02000000,
++ }},
++ },
++ [CX88_BOARD_HAUPPAUGE_HVR1300] = {
++ .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
++ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .tda9887_conf = TDA9887_PRESENT,
++ .audio_chip = AUDIO_CHIP_WM8775,
++ .input = {{
++ .type = CX88_VMUX_TELEVISION,
++ .vmux = 0,
++ .gpio0 = 0xe780,
++ },{
++ .type = CX88_VMUX_COMPOSITE1,
++ .vmux = 1,
++ .gpio0 = 0xe780,
++ },{
++ .type = CX88_VMUX_SVIDEO,
++ .vmux = 2,
++ .gpio0 = 0xe780,
++ }},
++ /* fixme: Add radio support */
++ .mpeg = CX88_MPEG_DVB,
+ },
+ };
+ const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
+@@ -1254,7 +1350,7 @@ struct cx88_subid cx88_subids[] = {
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ },{
+ .subvendor = 0x107d,
+- .subdevice = 0x663C,
++ .subdevice = 0x663c,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ },{
+ .subvendor = 0x1461,
+@@ -1458,6 +1554,55 @@ struct cx88_subid cx88_subids[] = {
+ .subvendor = 0x14f1,
+ .subdevice = 0x0084,
+ .card = CX88_BOARD_GENIATECH_DVBS,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x1404,
++ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
++ },{
++ .subvendor = 0x1461,
++ .subdevice = 0xc111, /* AverMedia M150-D */
++ /* This board is known to work with the ASUS PVR416 config */
++ .card = CX88_BOARD_ASUS_PVR_416,
++ },{
++ .subvendor = 0xc180,
++ .subdevice = 0xc980,
++ .card = CX88_BOARD_TE_DTV_250_OEM_SWANN,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x9600,
++ .card = CX88_BOARD_HAUPPAUGE_HVR1300,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x9601,
++ .card = CX88_BOARD_HAUPPAUGE_HVR1300,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x9602,
++ .card = CX88_BOARD_HAUPPAUGE_HVR1300,
++ },{
++ .subvendor = 0x107d,
++ .subdevice = 0x6632,
++ .card = CX88_BOARD_LEADTEK_PVR2000,
++ },{
++ .subvendor = 0x12ab,
++ .subdevice = 0x2300, /* Club3D Zap TV2100 */
++ .card = CX88_BOARD_KWORLD_DVB_T_CX22702,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x9000,
++ .card = CX88_BOARD_HAUPPAUGE_DVB_T1,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x1400,
++ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x1401,
++ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
++ },{
++ .subvendor = 0x0070,
++ .subdevice = 0x1402,
++ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
+ },
+ };
+ const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
+@@ -1501,6 +1646,15 @@ static void hauppauge_eeprom(struct cx88
+ /* Make sure we support the board model */
+ switch (tv.model)
+ {
++ case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */
++ case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */
++ case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */
++ case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */
++ case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */
++ case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */
++ case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */
++ case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */
++ case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
+ case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
+ case 34519: /* WinTV-PCI-FM */
+ case 90002: /* Nova-T-PCI (9002) */
+@@ -1512,6 +1666,11 @@ static void hauppauge_eeprom(struct cx88
+ case 92000: /* Nova-SE2 (OEM, No Video or IR) */
+ case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
+ case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
++ case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */
++ case 96019: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX/TX) */
++ case 96559: /* WinTV-HVR1300 (PAL Video, MPEG Video no IR) */
++ case 96569: /* WinTV-HVR1300 () */
++ case 96659: /* WinTV-HVR1300 () */
+ case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
+ /* known */
+ break;
+@@ -1638,6 +1797,22 @@ void cx88_card_list(struct cx88_core *co
+ core->name, i, cx88_boards[i].name);
+ }
+
++void cx88_card_setup_pre_i2c(struct cx88_core *core)
++{
++ switch (core->board) {
++ case CX88_BOARD_HAUPPAUGE_HVR1300:
++ /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
++ /* We leave here with the 702 on the bus */
++ cx_write(MO_GP0_IO, 0x0000e780);
++ udelay(1000);
++ cx_clear(MO_GP0_IO, 0x00000080);
++ udelay(50);
++ cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
++ udelay(1000);
++ break;
++ }
++}
++
+ void cx88_card_setup(struct cx88_core *core)
+ {
+ static u8 eeprom[256];
+@@ -1666,6 +1841,8 @@ void cx88_card_setup(struct cx88_core *c
+ case CX88_BOARD_HAUPPAUGE_DVB_T1:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1100LP:
++ case CX88_BOARD_HAUPPAUGE_HVR3000:
++ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ if (0 == core->i2c_rc)
+ hauppauge_eeprom(core,eeprom);
+ break;
+@@ -1673,9 +1850,15 @@ void cx88_card_setup(struct cx88_core *c
+ cx_write(MO_GP0_IO, 0x000007f8);
+ cx_write(MO_GP1_IO, 0x00000001);
+ break;
++ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
++ /* GPIO0:6 is hooked to FX2 reset pin */
++ cx_set(MO_GP0_IO, 0x00004040);
++ cx_clear(MO_GP0_IO, 0x00000040);
++ msleep(1000);
++ cx_set(MO_GP0_IO, 0x00004040);
++ /* FALLTHROUGH */
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+ /* GPIO0:0 is hooked to mt352 reset pin */
+ cx_set(MO_GP0_IO, 0x00000101);
+diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
+index 973d3f3..4b655f2 100644
+--- a/drivers/media/video/cx88/cx88-core.c
++++ b/drivers/media/video/cx88/cx88-core.c
+@@ -105,7 +105,7 @@ static u32* cx88_risc_field(u32 *rp, str
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ offset+=bpl;
+ } else {
+- /* scanline needs to be splitted */
++ /* scanline needs to be split */
+ todo = bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ (sg_dma_len(sg)-offset));
+@@ -658,13 +658,6 @@ static unsigned int inline norm_fsc8(str
+ return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
+ }
+
+-static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
+-{
+- return (norm->id & V4L2_STD_625_50)
+- ? HLNotchFilter135PAL
+- : HLNotchFilter135NTSC;
+-}
+-
+ static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+ {
+ /* Should always be Line Draw Time / (4*FSC) */
+@@ -792,6 +785,11 @@ int cx88_start_audio_dma(struct cx88_cor
+ {
+ /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
+ int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
++
++ /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
++ if (cx_read(MO_AUD_DMACNTRL) & 0x10)
++ return 0;
++
+ /* setup fifo + format */
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
+@@ -801,11 +799,16 @@ int cx88_start_audio_dma(struct cx88_cor
+
+ /* start dma */
+ cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
++
+ return 0;
+ }
+
+ int cx88_stop_audio_dma(struct cx88_core *core)
+ {
++ /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
++ if (cx_read(MO_AUD_DMACNTRL) & 0x10)
++ return 0;
++
+ /* stop dma */
+ cx_write(MO_AUD_DMACNTRL, 0x0000);
+
+@@ -927,7 +930,7 @@ int cx88_set_tvnorm(struct cx88_core *co
+ // htotal
+ tmp64 = norm_htotal(norm) * (u64)vdec_clock;
+ do_div(tmp64, fsc8);
+- htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
++ htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
+ dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
+ htotal, cx_read(MO_HTOTAL), (u32)tmp64);
+ cx_write(MO_HTOTAL, htotal);
+@@ -1123,6 +1126,7 @@ struct cx88_core* cx88_core_get(struct p
+
+ /* init hardware */
+ cx88_reset(core);
++ cx88_card_setup_pre_i2c(core);
+ cx88_i2c_init(core,pci);
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
+ cx88_card_setup(core);
+diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
+index afde378..0ef13e7 100644
+--- a/drivers/media/video/cx88/cx88-dvb.c
++++ b/drivers/media/video/cx88/cx88-dvb.c
+@@ -33,32 +33,18 @@
+ #include "dvb-pll.h"
+ #include <media/v4l2-common.h>
+
+-#ifdef HAVE_MT352
+-# include "mt352.h"
+-# include "mt352_priv.h"
+-# ifdef HAVE_VP3054_I2C
+-# include "cx88-vp3054-i2c.h"
+-# endif
+-#endif
+-#ifdef HAVE_ZL10353
+-# include "zl10353.h"
+-#endif
+-#ifdef HAVE_CX22702
+-# include "cx22702.h"
+-#endif
+-#ifdef HAVE_OR51132
+-# include "or51132.h"
+-#endif
+-#ifdef HAVE_LGDT330X
+-# include "lgdt330x.h"
+-# include "lg_h06xf.h"
+-#endif
+-#ifdef HAVE_NXT200X
+-# include "nxt200x.h"
+-#endif
+-#ifdef HAVE_CX24123
+-# include "cx24123.h"
++#include "mt352.h"
++#include "mt352_priv.h"
++#ifdef HAVE_VP3054_I2C
++# include "cx88-vp3054-i2c.h"
+ #endif
++#include "zl10353.h"
++#include "cx22702.h"
++#include "or51132.h"
++#include "lgdt330x.h"
++#include "lg_h06xf.h"
++#include "nxt200x.h"
++#include "cx24123.h"
+ #include "isl6421.h"
+
+ MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
+@@ -114,8 +100,6 @@ static struct videobuf_queue_ops dvb_qop
+ };
+
+ /* ------------------------------------------------------------------ */
+-
+-#ifdef HAVE_MT352
+ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
+ {
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
+@@ -181,7 +165,7 @@ static int dntv_live_dvbt_demod_init(str
+ }
+
+ static struct mt352_config dvico_fusionhdtv = {
+- .demod_address = 0x0F,
++ .demod_address = 0x0f,
+ .demod_init = dvico_fusionhdtv_demod_init,
+ };
+
+@@ -191,7 +175,7 @@ static struct mt352_config dntv_live_dvb
+ };
+
+ static struct mt352_config dvico_fusionhdtv_dual = {
+- .demod_address = 0x0F,
++ .demod_address = 0x0f,
+ .demod_init = dvico_dual_demod_init,
+ };
+
+@@ -266,8 +250,8 @@ static int dntv_live_dvbt_pro_tuner_set_
+ if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+
+ printk(KERN_WARNING "cx88-dvb: %s error "
+- "(addr %02x <- %02x, err = %i)\n",
+- __FUNCTION__, dev->core->pll_addr, buf[0], err);
++ "(addr %02x <- %02x, err = %i)\n",
++ __FUNCTION__, dev->core->pll_addr, buf[0], err);
+ if (err < 0)
+ return err;
+ else
+@@ -283,9 +267,7 @@ static struct mt352_config dntv_live_dvb
+ .demod_init = dntv_live_dvbt_pro_demod_init,
+ };
+ #endif
+-#endif
+
+-#ifdef HAVE_ZL10353
+ static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+ {
+@@ -304,8 +286,8 @@ static int dvico_hybrid_tuner_set_params
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "cx88-dvb: %s error "
+- "(addr %02x <- %02x, err = %i)\n",
+- __FUNCTION__, pllbuf[0], pllbuf[1], err);
++ "(addr %02x <- %02x, err = %i)\n",
++ __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ if (err < 0)
+ return err;
+ else
+@@ -316,16 +298,14 @@ static int dvico_hybrid_tuner_set_params
+ }
+
+ static struct zl10353_config dvico_fusionhdtv_hybrid = {
+- .demod_address = 0x0F,
++ .demod_address = 0x0f,
+ .no_tuner = 1,
+ };
+
+ static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+- .demod_address = 0x0F,
++ .demod_address = 0x0f,
+ };
+-#endif
+
+-#ifdef HAVE_CX22702
+ static struct cx22702_config connexant_refboard_config = {
+ .demod_address = 0x43,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+@@ -335,13 +315,22 @@ static struct cx22702_config hauppauge_n
+ .demod_address = 0x43,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+ };
++
+ static struct cx22702_config hauppauge_hvr1100_config = {
+ .demod_address = 0x63,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+ };
+-#endif
+
+-#ifdef HAVE_OR51132
++static struct cx22702_config hauppauge_hvr1300_config = {
++ .demod_address = 0x63,
++ .output_mode = CX22702_SERIAL_OUTPUT,
++};
++
++static struct cx22702_config hauppauge_hvr3000_config = {
++ .demod_address = 0x63,
++ .output_mode = CX22702_SERIAL_OUTPUT,
++};
++
+ static int or51132_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+ {
+@@ -351,12 +340,10 @@ static int or51132_set_ts_param(struct d
+ }
+
+ static struct or51132_config pchdtv_hd3000 = {
+- .demod_address = 0x15,
+- .set_ts_params = or51132_set_ts_param,
++ .demod_address = 0x15,
++ .set_ts_params = or51132_set_ts_param,
+ };
+-#endif
+
+-#ifdef HAVE_LGDT330X
+ static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
+ {
+@@ -373,14 +360,14 @@ static int lgdt3302_tuner_set_params(str
+
+ dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
+ dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+- __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
++ __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "cx88-dvb: %s error "
+- "(addr %02x <- %02x, err = %i)\n",
+- __FUNCTION__, buf[0], buf[1], err);
++ "(addr %02x <- %02x, err = %i)\n",
++ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+@@ -425,28 +412,26 @@ static int lgdt330x_set_ts_param(struct
+ }
+
+ static struct lgdt330x_config fusionhdtv_3_gold = {
+- .demod_address = 0x0e,
+- .demod_chip = LGDT3302,
+- .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
+- .set_ts_params = lgdt330x_set_ts_param,
++ .demod_address = 0x0e,
++ .demod_chip = LGDT3302,
++ .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
++ .set_ts_params = lgdt330x_set_ts_param,
+ };
+
+ static struct lgdt330x_config fusionhdtv_5_gold = {
+- .demod_address = 0x0e,
+- .demod_chip = LGDT3303,
+- .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+- .set_ts_params = lgdt330x_set_ts_param,
++ .demod_address = 0x0e,
++ .demod_chip = LGDT3303,
++ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
++ .set_ts_params = lgdt330x_set_ts_param,
+ };
+
+ static struct lgdt330x_config pchdtv_hd5500 = {
+- .demod_address = 0x59,
+- .demod_chip = LGDT3303,
+- .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+- .set_ts_params = lgdt330x_set_ts_param,
++ .demod_address = 0x59,
++ .demod_chip = LGDT3303,
++ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
++ .set_ts_params = lgdt330x_set_ts_param,
+ };
+-#endif
+
+-#ifdef HAVE_NXT200X
+ static int nxt200x_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+ {
+@@ -465,28 +450,27 @@ static int nxt200x_set_pll_input(u8* buf
+ }
+
+ static struct nxt200x_config ati_hdtvwonder = {
+- .demod_address = 0x0a,
+- .set_pll_input = nxt200x_set_pll_input,
+- .set_ts_params = nxt200x_set_ts_param,
++ .demod_address = 0x0a,
++ .set_pll_input = nxt200x_set_pll_input,
++ .set_ts_params = nxt200x_set_ts_param,
+ };
+-#endif
+
+-#ifdef HAVE_CX24123
+ static int cx24123_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+ {
+ struct cx8802_dev *dev= fe->dvb->priv;
+- dev->ts_gen_cntrl = 0x2;
++ dev->ts_gen_cntrl = 0x02;
+ return 0;
+ }
+
+-static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
++static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
++ fe_sec_voltage_t voltage)
+ {
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ if (voltage == SEC_VOLTAGE_OFF) {
+- cx_write(MO_GP0_IO, 0x000006fB);
++ cx_write(MO_GP0_IO, 0x000006fb);
+ } else {
+ cx_write(MO_GP0_IO, 0x000006f9);
+ }
+@@ -496,7 +480,8 @@ static int kworld_dvbs_100_set_voltage(s
+ return 0;
+ }
+
+-static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage)
+ {
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+@@ -512,20 +497,20 @@ static int geniatech_dvbs_set_voltage(st
+ }
+
+ static struct cx24123_config geniatech_dvbs_config = {
+- .demod_address = 0x55,
+- .set_ts_params = cx24123_set_ts_param,
++ .demod_address = 0x55,
++ .set_ts_params = cx24123_set_ts_param,
+ };
+
+ static struct cx24123_config hauppauge_novas_config = {
+- .demod_address = 0x55,
+- .set_ts_params = cx24123_set_ts_param,
++ .demod_address = 0x55,
++ .set_ts_params = cx24123_set_ts_param,
+ };
+
+ static struct cx24123_config kworld_dvbs_100_config = {
+- .demod_address = 0x15,
+- .set_ts_params = cx24123_set_ts_param,
++ .demod_address = 0x15,
++ .set_ts_params = cx24123_set_ts_param,
++ .lnb_polarity = 1,
+ };
+-#endif
+
+ static int dvb_register(struct cx8802_dev *dev)
+ {
+@@ -535,114 +520,124 @@ static int dvb_register(struct cx8802_de
+
+ /* init frontend */
+ switch (dev->core->board) {
+-#ifdef HAVE_CX22702
+ case CX88_BOARD_HAUPPAUGE_DVB_T1:
+- dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(cx22702_attach,
++ &hauppauge_novat_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt759x);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ &dev->core->i2c_adap,
++ &dvb_pll_thomson_dtt759x);
+ }
+ break;
+ case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+ case CX88_BOARD_CONEXANT_DVB_T1:
+ case CX88_BOARD_KWORLD_DVB_T_CX22702:
+ case CX88_BOARD_WINFAST_DTV1000:
+- dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(cx22702_attach,
++ &connexant_refboard_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x60,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt7579);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
++ &dev->core->i2c_adap,
++ &dvb_pll_thomson_dtt7579);
+ }
+ break;
+ case CX88_BOARD_WINFAST_DTV2000H:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+- dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(cx22702_attach,
++ &hauppauge_hvr1100_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_fmd1216me);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ &dev->core->i2c_adap,
++ &dvb_pll_fmd1216me);
++ }
++ break;
++ case CX88_BOARD_HAUPPAUGE_HVR1300:
++ dev->dvb.frontend = dvb_attach(cx22702_attach,
++ &hauppauge_hvr1300_config,
++ &dev->core->i2c_adap);
++ if (dev->dvb.frontend != NULL) {
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ &dev->core->i2c_adap,
++ &dvb_pll_fmd1216me);
++ }
++ break;
++ case CX88_BOARD_HAUPPAUGE_HVR3000:
++ dev->dvb.frontend = dvb_attach(cx22702_attach,
++ &hauppauge_hvr3000_config,
++ &dev->core->i2c_adap);
++ if (dev->dvb.frontend != NULL) {
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ &dev->core->i2c_adap,
++ &dvb_pll_fmd1216me);
+ }
+ break;
+-#endif
+-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+-#ifdef HAVE_MT352
+- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(mt352_attach,
++ &dvico_fusionhdtv,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x60,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt7579);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
++ NULL, &dvb_pll_thomson_dtt7579);
+ break;
+ }
+-#endif
+-#ifdef HAVE_ZL10353
+ /* ZL10353 replaces MT352 on later cards */
+- dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(zl10353_attach,
++ &dvico_fusionhdtv_plus_v1_1,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x60,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt7579);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
++ NULL, &dvb_pll_thomson_dtt7579);
+ }
+-#endif
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+-#ifdef HAVE_MT352
+ /* The tin box says DEE1601, but it seems to be DTT7579
+ * compatible, with a slightly different MT352 AGC gain. */
+- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(mt352_attach,
++ &dvico_fusionhdtv_dual,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt7579);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_thomson_dtt7579);
+ break;
+ }
+-#endif
+-#ifdef HAVE_ZL10353
+ /* ZL10353 replaces MT352 on later cards */
+- dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(zl10353_attach,
++ &dvico_fusionhdtv_plus_v1_1,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt7579);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_thomson_dtt7579);
+ }
+-#endif
+ break;
+-#endif /* HAVE_MT352 || HAVE_ZL10353 */
+-#ifdef HAVE_MT352
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(mt352_attach,
++ &dvico_fusionhdtv,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_lg_z201);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_lg_z201);
+ }
+ break;
+ case CX88_BOARD_KWORLD_DVB_T:
+ case CX88_BOARD_DNTV_LIVE_DVB_T:
+ case CX88_BOARD_ADSTECH_DVB_T_PCI:
+- dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(mt352_attach,
++ &dntv_live_dvbt_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_unknown_1);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_unknown_1);
+ }
+ break;
+ case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+ #ifdef HAVE_VP3054_I2C
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_fmd1216me;
+- dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
++ dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
+ &((struct vp3054_i2c_state *)dev->card_priv)->adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+@@ -651,30 +646,26 @@ static int dvb_register(struct cx8802_de
+ printk("%s: built without vp3054 support\n", dev->core->name);
+ #endif
+ break;
+-#endif
+-#ifdef HAVE_ZL10353
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_thomson_fe6600;
+- dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(zl10353_attach,
++ &dvico_fusionhdtv_hybrid,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+ }
+ break;
+-#endif
+-#ifdef HAVE_OR51132
+ case CX88_BOARD_PCHDTV_HD3000:
+- dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(or51132_attach,
++ &pchdtv_hd3000,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_thomson_dtt761x);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ &dev->core->i2c_adap,
++ &dvb_pll_thomson_dtt761x);
+ }
+ break;
+-#endif
+-#ifdef HAVE_LGDT330X
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+ dev->ts_gen_cntrl = 0x08;
+ {
+@@ -690,8 +681,9 @@ static int dvb_register(struct cx8802_de
+ fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_microtune_4042;
+- dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
++ &fusionhdtv_3_gold,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
+@@ -709,8 +701,9 @@ static int dvb_register(struct cx8802_de
+ mdelay(200);
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
+- dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
++ &fusionhdtv_3_gold,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
+@@ -726,8 +719,9 @@ static int dvb_register(struct cx8802_de
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+- dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
++ &fusionhdtv_5_gold,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
+@@ -743,52 +737,51 @@ static int dvb_register(struct cx8802_de
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+- dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
++ &pchdtv_hd5500,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
+ }
+ break;
+-#endif
+-#ifdef HAVE_NXT200X
+ case CX88_BOARD_ATI_HDTVWONDER:
+- dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(nxt200x_attach,
++ &ati_hdtvwonder,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61,
+- &dev->core->i2c_adap,
+- &dvb_pll_tuv1236d);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_tuv1236d);
+ }
+ break;
+-#endif
+-#ifdef HAVE_CX24123
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+- dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(cx24123_attach,
++ &hauppauge_novas_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+- isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
+- 0x08, 0x00, 0x00);
++ dvb_attach(isl6421_attach, dev->dvb.frontend,
++ &dev->core->i2c_adap, 0x08, 0x00, 0x00);
+ }
+ break;
+ case CX88_BOARD_KWORLD_DVBS_100:
+- dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(cx24123_attach,
++ &kworld_dvbs_100_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+ }
+ break;
+ case CX88_BOARD_GENIATECH_DVBS:
+- dev->dvb.frontend = cx24123_attach(&geniatech_dvbs_config,
+- &dev->core->i2c_adap);
++ dev->dvb.frontend = dvb_attach(cx24123_attach,
++ &geniatech_dvbs_config,
++ &dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+ }
+ break;
+-#endif
+ default:
+ printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+ dev->core->name);
+@@ -826,7 +819,7 @@ static int __devinit dvb_probe(struct pc
+ return -EINVAL;
+
+ err = -ENODEV;
+- if (!cx88_boards[core->board].dvb)
++ if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
+ goto fail_core;
+
+ err = -ENOMEM;
+@@ -908,8 +901,10 @@ static struct pci_driver dvb_pci_driver
+ .id_table = cx8802_pci_tbl,
+ .probe = dvb_probe,
+ .remove = __devexit_p(dvb_remove),
++#ifdef CONFIG_PM
+ .suspend = cx8802_suspend_common,
+ .resume = cx8802_resume_common,
++#endif
+ };
+
+ static int dvb_init(void)
+diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
+index 7066380..88af23a 100644
+--- a/drivers/media/video/cx88/cx88-i2c.c
++++ b/drivers/media/video/cx88/cx88-i2c.c
+@@ -7,6 +7,9 @@
+ (c) 2002 Yurij Sysoev <yurij at naturesoft.net>
+ (c) 1999-2003 Gerd Knorr <kraxel at bytesex.org>
+
++ (c) 2005 Mauro Carvalho Chehab <mchehab at infradead.org>
++ - Multituner support and i2c address binding
++
+ 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
+@@ -40,6 +43,11 @@ static unsigned int i2c_scan = 0;
+ module_param(i2c_scan, int, 0444);
+ MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
++static unsigned int i2c_udelay = 5;
++module_param(i2c_udelay, int, 0644);
++MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs "
++ "(should be 5 or higher). Lower value means higher bus speed.");
++
+ #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
+
+@@ -137,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_c
+ if (0 != core->i2c_rc)
+ return;
+
+- if (core->dvbdev) {
++ if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+
+@@ -155,7 +163,6 @@ static struct i2c_algo_bit_data cx8800_i
+ .getsda = cx8800_bit_getsda,
+ .getscl = cx8800_bit_getscl,
+ .udelay = 16,
+- .mdelay = 10,
+ .timeout = 200,
+ };
+
+@@ -199,6 +206,11 @@ static void do_i2c_scan(char *name, stru
+ /* init + register i2c algo-bit adapter */
+ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
+ {
++ /* Prevents usage of invalid delay values */
++ if (i2c_udelay<5)
++ i2c_udelay=5;
++ cx8800_i2c_algo_template.udelay=i2c_udelay;
++
+ memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
+ sizeof(core->i2c_adap));
+ memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
+@@ -208,7 +220,7 @@ int cx88_i2c_init(struct cx88_core *core
+
+ if (core->tuner_type != TUNER_ABSENT)
+ core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
+- if (cx88_boards[core->board].dvb)
++ if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB)
+ core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
+
+ core->i2c_adap.dev.parent = &pci->dev;
+diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
+index c255646..ee48995 100644
+--- a/drivers/media/video/cx88/cx88-input.c
++++ b/drivers/media/video/cx88/cx88-input.c
+@@ -107,7 +107,15 @@ static void cx88_ir_handle_key(struct cx
+ (gpio & ir->mask_keydown) ? " down" : "",
+ (gpio & ir->mask_keyup) ? " up" : "");
+
+- if (ir->mask_keydown) {
++ if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) {
++ u32 gpio_key = cx_read(MO_GP0_IO);
++
++ data = (data << 4) | ((gpio_key & 0xf0) >> 4);
++
++ ir_input_keydown(ir->input, &ir->ir, data, data);
++ ir_input_nokey(ir->input, &ir->ir);
++
++ } else if (ir->mask_keydown) {
+ /* bit set on keydown */
+ if (gpio & ir->mask_keydown) {
+ ir_input_keydown(ir->input, &ir->ir, data, data);
+@@ -187,6 +195,8 @@ int cx88_ir_init(struct cx88_core *core,
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
++ case CX88_BOARD_HAUPPAUGE_HVR1300:
++ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ ir_codes = ir_codes_hauppauge_new;
+ ir_type = IR_TYPE_RC5;
+ ir->sampling = 1;
+@@ -248,6 +258,13 @@ int cx88_ir_init(struct cx88_core *core,
+ ir_type = IR_TYPE_PD;
+ ir->sampling = 0xff00; /* address */
+ break;
++ case CX88_BOARD_NORWOOD_MICRO:
++ ir_codes = ir_codes_norwood;
++ ir->gpio_addr = MO_GP1_IO;
++ ir->mask_keycode = 0x0e;
++ ir->mask_keyup = 0x80;
++ ir->polling = 50; /* ms */
++ break;
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+ ir_codes = ir_codes_npgtech;
+ ir->gpio_addr = MO_GP0_IO;
+@@ -402,6 +419,8 @@ void cx88_ir_irq(struct cx88_core *core)
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
++ case CX88_BOARD_HAUPPAUGE_HVR1300:
++ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
+ ir_dprintk("biphase decoded: %x\n", ircode);
+ if ((ircode & 0xfffff000) != 0x3000)
+diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
+index 138a4f6..6b23a4e 100644
+--- a/drivers/media/video/cx88/cx88-mpeg.c
++++ b/drivers/media/video/cx88/cx88-mpeg.c
+@@ -65,8 +65,17 @@ static int cx8802_start_dma(struct cx880
+
+ /* FIXME: this needs a review.
+ * also: move to cx88-blackbird + cx88-dvb source files? */
++ if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) {
++ /* Report a warning until the mini driver patch is applied,
++ * else the following conditions will set the dma registers incorrectly.
++ * This will be removed in the next major patch and changes to the conditions
++ * will be made.
++ */
++ printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__);
++ return -EINVAL;
++ }
+
+- if (cx88_boards[core->board].dvb) {
++ if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) {
+ /* negedge driven & software reset */
+ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
+ udelay(100);
+@@ -92,7 +101,7 @@ static int cx8802_start_dma(struct cx880
+ udelay(100);
+ }
+
+- if (cx88_boards[core->board].blackbird) {
++ if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
+
+ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
+@@ -367,7 +376,7 @@ static void cx8802_mpeg_irq(struct cx880
+
+ #define MAX_IRQ_LOOP 10
+
+-static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cx8802_irq(int irq, void *dev_id)
+ {
+ struct cx8802_dev *dev = dev_id;
+ struct cx88_core *core = dev->core;
+diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
+index 5785c34..58ba9f7 100644
+--- a/drivers/media/video/cx88/cx88-tvaudio.c
++++ b/drivers/media/video/cx88/cx88-tvaudio.c
+@@ -52,7 +52,6 @@
+ #include <linux/init.h>
+ #include <linux/smp_lock.h>
+ #include <linux/delay.h>
+-#include <linux/config.h>
+ #include <linux/kthread.h>
+
+ #include "cx88.h"
+@@ -138,16 +137,12 @@ static void set_audio_finish(struct cx88
+ {
+ u32 volume;
+
+-#ifndef CONFIG_VIDEO_CX88_ALSA
+ /* restart dma; This avoids buzz in NICAM and is good in others */
+ cx88_stop_audio_dma(core);
+-#endif
+ cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
+-#ifndef CONFIG_VIDEO_CX88_ALSA
+ cx88_start_audio_dma(core);
+-#endif
+
+- if (cx88_boards[core->board].blackbird) {
++ if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ /* sets sound input from external adc */
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_ROSLYN:
+@@ -169,7 +164,7 @@ static void set_audio_finish(struct cx88
+ cx_write(AUD_I2SCNTL, 0);
+ /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
+ }
+- if ((always_analog) || (!cx88_boards[core->board].blackbird)) {
++ if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) {
+ ctl |= EN_DAC_ENABLE;
+ cx_write(AUD_CTL, ctl);
+ }
+diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
+index 94c92ba..90e298d 100644
+--- a/drivers/media/video/cx88/cx88-video.c
++++ b/drivers/media/video/cx88/cx88-video.c
+@@ -497,6 +497,7 @@ static int start_video_dma(struct cx8800
+ return 0;
+ }
+
++#ifdef CONFIG_PM
+ static int stop_video_dma(struct cx8800_dev *dev)
+ {
+ struct cx88_core *core = dev->core;
+@@ -512,6 +513,7 @@ static int stop_video_dma(struct cx8800_
+ cx_clear(MO_VID_INTMSK, 0x0f0011);
+ return 0;
+ }
++#endif
+
+ static int restart_video_queue(struct cx8800_dev *dev,
+ struct cx88_dmaqueue *q)
+@@ -1742,7 +1744,7 @@ static void cx8800_vid_irq(struct cx8800
+ }
+ }
+
+-static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cx8800_irq(int irq, void *dev_id)
+ {
+ struct cx8800_dev *dev = dev_id;
+ struct cx88_core *core = dev->core;
+@@ -1926,6 +1928,9 @@ static int __devinit cx8800_initdev(stru
+ if (TUNER_ABSENT != core->tuner_type)
+ request_module("tuner");
+
++ if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775)
++ request_module("wm8775");
++
+ /* register v4l devices */
+ dev->video_dev = cx88_vdev_init(core,dev->pci,
+ &cx8800_video_template,"video");
+@@ -2017,6 +2022,7 @@ static void __devexit cx8800_finidev(str
+ kfree(dev);
+ }
+
++#ifdef CONFIG_PM
+ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
+ {
+ struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+@@ -2092,6 +2098,7 @@ static int cx8800_resume(struct pci_dev
+
+ return 0;
+ }
++#endif
+
+ /* ----------------------------------------------------------- */
+
+@@ -2112,9 +2119,10 @@ static struct pci_driver cx8800_pci_driv
+ .id_table = cx8800_pci_tbl,
+ .probe = cx8800_initdev,
+ .remove = __devexit_p(cx8800_finidev),
+-
++#ifdef CONFIG_PM
+ .suspend = cx8800_suspend,
+ .resume = cx8800_resume,
++#endif
+ };
+
+ static int cx8800_init(void)
+diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
+index 751a754..2b4f197 100644
+--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
++++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
+@@ -100,7 +100,6 @@ static struct i2c_algo_bit_data vp3054_i
+ .getsda = vp3054_bit_getsda,
+ .getscl = vp3054_bit_getscl,
+ .udelay = 16,
+- .mdelay = 10,
+ .timeout = 200,
+ };
+
+diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
+index e781095..3bc91aa 100644
+--- a/drivers/media/video/cx88/cx88.h
++++ b/drivers/media/video/cx88/cx88.h
+@@ -30,6 +30,7 @@
+ #include <media/tveeprom.h>
+ #include <media/video-buf.h>
+ #include <media/cx2341x.h>
++#include <media/audiochip.h>
+ #include <media/video-buf-dvb.h>
+
+ #include "btcx-risc.h"
+@@ -39,12 +40,6 @@
+ #include <linux/mutex.h>
+ #define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
+
+-#ifndef TRUE
+-# define TRUE (1==1)
+-#endif
+-#ifndef FALSE
+-# define FALSE (1==0)
+-#endif
+ #define UNSET (-1U)
+
+ #define CX88_MAXBOARDS 8
+@@ -73,6 +68,12 @@ enum cx88_deemph_type {
+ FM_DEEMPH_75
+ };
+
++enum cx88_board_type {
++ CX88_BOARD_NONE = 0,
++ CX88_MPEG_DVB,
++ CX88_MPEG_BLACKBIRD
++};
++
+ /* ----------------------------------------------------------- */
+ /* tv norms */
+
+@@ -197,6 +198,10 @@ extern struct sram_channel cx88_sram_cha
+ #define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
+ #define CX88_BOARD_WINFAST_DTV2000H 51
+ #define CX88_BOARD_GENIATECH_DVBS 52
++#define CX88_BOARD_HAUPPAUGE_HVR3000 53
++#define CX88_BOARD_NORWOOD_MICRO 54
++#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
++#define CX88_BOARD_HAUPPAUGE_HVR1300 56
+
+ enum cx88_itype {
+ CX88_VMUX_COMPOSITE1 = 1,
+@@ -226,8 +231,8 @@ struct cx88_board {
+ int tda9887_conf;
+ struct cx88_input input[MAX_CX88_INPUT];
+ struct cx88_input radio;
+- unsigned int blackbird:1;
+- unsigned int dvb:1;
++ enum cx88_board_type mpeg;
++ enum audiochip audio_chip;
+ };
+
+ struct cx88_subid {
+@@ -545,6 +550,7 @@ extern const unsigned int cx88_idcount;
+
+ extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
+ extern void cx88_card_setup(struct cx88_core *core);
++extern void cx88_card_setup_pre_i2c(struct cx88_core *core);
+
+ /* ----------------------------------------------------------- */
+ /* cx88-tvaudio.c */
+diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
+index b9ba95f..b1012e9 100644
+--- a/drivers/media/video/dabusb.c
++++ b/drivers/media/video/dabusb.c
+@@ -166,7 +166,7 @@ static int dabusb_free_buffers (pdabusb_
+ return 0;
+ }
+ /*-------------------------------------------------------------------*/
+-static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)
++static void dabusb_iso_complete (struct urb *purb)
+ {
+ pbuff_t b = purb->context;
+ pdabusb_t s = b->s;
+diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
+index dfb15bf..9285a58 100644
+--- a/drivers/media/video/em28xx/Kconfig
++++ b/drivers/media/video/em28xx/Kconfig
+@@ -5,7 +5,8 @@ config VIDEO_EM28XX
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+- select VIDEO_SAA711X
++ select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ This is a video4linux driver for Empia 28xx based TV cards.
+
+diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
+index 4350cc7..255a47d 100644
+--- a/drivers/media/video/em28xx/em28xx-core.c
++++ b/drivers/media/video/em28xx/em28xx-core.c
+@@ -382,7 +382,7 @@ int em28xx_resolution_set(struct em28xx
+ /******************* isoc transfer handling ****************************/
+
+ #ifdef ENABLE_DEBUG_ISOC_FRAMES
+-static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
++static void em28xx_isoc_dump(struct urb *urb)
+ {
+ int len = 0;
+ int ntrans = 0;
+@@ -534,7 +534,7 @@ static inline void em28xx_isoc_video_cop
+ * em28xx_isoIrq()
+ * handles the incoming isoc urbs and fills the frames from our inqueue
+ */
+-static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
++static void em28xx_isocIrq(struct urb *urb)
+ {
+ struct em28xx *dev = urb->context;
+ int i, status;
+@@ -545,7 +545,7 @@ static void em28xx_isocIrq(struct urb *u
+ return;
+ #ifdef ENABLE_DEBUG_ISOC_FRAMES
+ if (isoc_debug>1)
+- em28xx_isoc_dump(urb, regs);
++ em28xx_isoc_dump(urb);
+ #endif
+
+ if (urb->status == -ENOENT)
+diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
+index 8992b6e..f786ab1 100644
+--- a/drivers/media/video/et61x251/et61x251_core.c
++++ b/drivers/media/video/et61x251/et61x251_core.c
+@@ -398,7 +398,7 @@ int et61x251_i2c_write(struct et61x251_d
+
+ /*****************************************************************************/
+
+-static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
++static void et61x251_urb_complete(struct urb *urb)
+ {
+ struct et61x251_device* cam = urb->context;
+ struct et61x251_frame_t** f;
+@@ -973,16 +973,32 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUG
+ et61x251_show_i2c_val, et61x251_store_i2c_val);
+
+
+-static void et61x251_create_sysfs(struct et61x251_device* cam)
++static int et61x251_create_sysfs(struct et61x251_device* cam)
+ {
+ struct video_device *v4ldev = cam->v4ldev;
++ int rc;
+
+- video_device_create_file(v4ldev, &class_device_attr_reg);
+- video_device_create_file(v4ldev, &class_device_attr_val);
++ rc = video_device_create_file(v4ldev, &class_device_attr_reg);
++ if (rc) goto err;
++ rc = video_device_create_file(v4ldev, &class_device_attr_val);
++ if (rc) goto err_reg;
+ if (cam->sensor.sysfs_ops) {
+- video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+- video_device_create_file(v4ldev, &class_device_attr_i2c_val);
++ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
++ if (rc) goto err_val;
++ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
++ if (rc) goto err_i2c_reg;
+ }
++
++ return 0;
++
++err_i2c_reg:
++ video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
++err_val:
++ video_device_remove_file(v4ldev, &class_device_attr_val);
++err_reg:
++ video_device_remove_file(v4ldev, &class_device_attr_reg);
++err:
++ return rc;
+ }
+ #endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+@@ -2534,7 +2550,9 @@ et61x251_usb_probe(struct usb_interface*
+ dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+- et61x251_create_sysfs(cam);
++ err = et61x251_create_sysfs(cam);
++ if (err)
++ goto fail2;
+ DBG(2, "Optional device control through 'sysfs' interface ready");
+ #endif
+
+@@ -2544,6 +2562,13 @@ et61x251_usb_probe(struct usb_interface*
+
+ return 0;
+
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++fail2:
++ video_nr[dev_nr] = -1;
++ dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
++ mutex_unlock(&cam->dev_mutex);
++ video_unregister_device(cam->v4ldev);
++#endif
+ fail:
+ if (cam) {
+ kfree(cam->control_buffer);
+diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
+index fba30a4..1457b16 100644
+--- a/drivers/media/video/ir-kbd-i2c.c
++++ b/drivers/media/video/ir-kbd-i2c.c
+@@ -64,23 +64,32 @@ MODULE_PARM_DESC(hauppauge, "Specify Hau
+ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ {
+ unsigned char buf[3];
+- int start, toggle, dev, code;
++ int start, range, toggle, dev, code;
+
+ /* poll IR chip */
+ if (3 != i2c_master_recv(&ir->c,buf,3))
+ return -EIO;
+
+ /* split rc5 data block ... */
+- start = (buf[0] >> 6) & 3;
++ start = (buf[0] >> 7) & 1;
++ range = (buf[0] >> 6) & 1;
+ toggle = (buf[0] >> 5) & 1;
+ dev = buf[0] & 0x1f;
+ code = (buf[1] >> 2) & 0x3f;
+
+- if (3 != start)
++ /* rc5 has two start bits
++ * the first bit must be one
++ * the second bit defines the command range (1 = 0-63, 0 = 64 - 127)
++ */
++ if (!start)
+ /* no key pressed */
+ return 0;
+- dprintk(1,"ir hauppauge (rc5): s%d t%d dev=%d code=%d\n",
+- start, toggle, dev, code);
++
++ if (!range)
++ code += 64;
++
++ dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
++ start, range, toggle, dev, code);
+
+ /* return key */
+ *ir_key = code;
+diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
+index 3bf7ac4..c1a377f 100644
+--- a/drivers/media/video/ks0127.c
++++ b/drivers/media/video/ks0127.c
+@@ -832,8 +832,7 @@ static int ks0127_detach(struct i2c_clie
+ static int __devinit ks0127_init_module(void)
+ {
+ init_reg_defaults();
+- i2c_add_driver(&i2c_driver_ks0127);
+- return 0;
++ return i2c_add_driver(&i2c_driver_ks0127);
+ }
+
+ static void __devexit ks0127_cleanup_module(void)
+diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
+index e278753..b083338 100644
+--- a/drivers/media/video/meye.c
++++ b/drivers/media/video/meye.c
+@@ -786,7 +786,7 @@ static void mchip_cont_compression_start
+ /* Interrupt handling */
+ /****************************************************************************/
+
+-static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t meye_irq(int irq, void *dev_id)
+ {
+ u32 v;
+ int reqnr;
+diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
+index 56246b8..cf43df3 100644
+--- a/drivers/media/video/msp3400-driver.c
++++ b/drivers/media/video/msp3400-driver.c
+@@ -904,6 +904,8 @@ static int msp_attach(struct i2c_adapter
+ state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+ /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+ state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
++ /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
++ state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
+
+ state->opmode = opmode;
+ if (state->opmode == OPMODE_AUTO) {
+diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
+index 545e4ac..7531efa 100644
+--- a/drivers/media/video/msp3400-driver.h
++++ b/drivers/media/video/msp3400-driver.h
+@@ -64,6 +64,7 @@ struct msp_state {
+ u8 has_sound_processing;
+ u8 has_virtual_dolby_surround;
+ u8 has_dolby_pro_logic;
++ u8 force_btsc;
+
+ int radio;
+ int opmode;
+diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
+index ed02ff8..4c7f85b 100644
+--- a/drivers/media/video/msp3400-kthreads.c
++++ b/drivers/media/video/msp3400-kthreads.c
+@@ -960,9 +960,10 @@ int msp34xxg_thread(void *data)
+
+ /* setup the chip*/
+ msp34xxg_reset(client);
+- state->std = state->radio ? 0x40 : msp_standard;
+- /* start autodetect */
++ state->std = state->radio ? 0x40 :
++ (state->force_btsc && msp_standard == 1) ? 32 : msp_standard;
+ msp_write_dem(client, 0x20, state->std);
++ /* start autodetect */
+ if (state->std != 1)
+ goto unmute;
+
+diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
+index 1b07a61..b4db2cb 100644
+--- a/drivers/media/video/ov511.c
++++ b/drivers/media/video/ov511.c
+@@ -301,10 +301,11 @@ static struct symbolic_list senlist[] =
+ static struct symbolic_list urb_errlist[] = {
+ { -ENOSR, "Buffer error (overrun)" },
+ { -EPIPE, "Stalled (device not responding)" },
+- { -EOVERFLOW, "Babble (bad cable?)" },
++ { -EOVERFLOW, "Babble (device sends too much data)" },
+ { -EPROTO, "Bit-stuff error (bad cable?)" },
+- { -EILSEQ, "CRC/Timeout" },
+- { -ETIMEDOUT, "NAK (device does not respond)" },
++ { -EILSEQ, "CRC/Timeout (bad cable?)" },
++ { -ETIME, "Device does not respond to token" },
++ { -ETIMEDOUT, "Device does not respond to command" },
+ { -1, NULL }
+ };
+
+@@ -3502,7 +3503,7 @@ check_middle:
+ }
+
+ static void
+-ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs)
++ov51x_isoc_irq(struct urb *urb)
+ {
+ int i;
+ struct usb_ov511 *ov;
+@@ -5647,17 +5648,49 @@ static ssize_t show_exposure(struct clas
+ }
+ static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
+
+-static void ov_create_sysfs(struct video_device *vdev)
++static int ov_create_sysfs(struct video_device *vdev)
+ {
+- video_device_create_file(vdev, &class_device_attr_custom_id);
+- video_device_create_file(vdev, &class_device_attr_model);
+- video_device_create_file(vdev, &class_device_attr_bridge);
+- video_device_create_file(vdev, &class_device_attr_sensor);
+- video_device_create_file(vdev, &class_device_attr_brightness);
+- video_device_create_file(vdev, &class_device_attr_saturation);
+- video_device_create_file(vdev, &class_device_attr_contrast);
+- video_device_create_file(vdev, &class_device_attr_hue);
+- video_device_create_file(vdev, &class_device_attr_exposure);
++ int rc;
++
++ rc = video_device_create_file(vdev, &class_device_attr_custom_id);
++ if (rc) goto err;
++ rc = video_device_create_file(vdev, &class_device_attr_model);
++ if (rc) goto err_id;
++ rc = video_device_create_file(vdev, &class_device_attr_bridge);
++ if (rc) goto err_model;
++ rc = video_device_create_file(vdev, &class_device_attr_sensor);
++ if (rc) goto err_bridge;
++ rc = video_device_create_file(vdev, &class_device_attr_brightness);
++ if (rc) goto err_sensor;
++ rc = video_device_create_file(vdev, &class_device_attr_saturation);
++ if (rc) goto err_bright;
++ rc = video_device_create_file(vdev, &class_device_attr_contrast);
++ if (rc) goto err_sat;
++ rc = video_device_create_file(vdev, &class_device_attr_hue);
++ if (rc) goto err_contrast;
++ rc = video_device_create_file(vdev, &class_device_attr_exposure);
++ if (rc) goto err_hue;
++
++ return 0;
++
++err_hue:
++ video_device_remove_file(vdev, &class_device_attr_hue);
++err_contrast:
++ video_device_remove_file(vdev, &class_device_attr_contrast);
++err_sat:
++ video_device_remove_file(vdev, &class_device_attr_saturation);
++err_bright:
++ video_device_remove_file(vdev, &class_device_attr_brightness);
++err_sensor:
++ video_device_remove_file(vdev, &class_device_attr_sensor);
++err_bridge:
++ video_device_remove_file(vdev, &class_device_attr_bridge);
++err_model:
++ video_device_remove_file(vdev, &class_device_attr_model);
++err_id:
++ video_device_remove_file(vdev, &class_device_attr_custom_id);
++err:
++ return rc;
+ }
+
+ /****************************************************************************
+@@ -5816,7 +5849,11 @@ ov51x_probe(struct usb_interface *intf,
+ ov->vdev->minor);
+
+ usb_set_intfdata(intf, ov);
+- ov_create_sysfs(ov->vdev);
++ if (ov_create_sysfs(ov->vdev)) {
++ err("ov_create_sysfs failed");
++ goto error;
++ }
++
+ return 0;
+
+ error:
+diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
+index 3484e36..368d6e2 100644
+--- a/drivers/media/video/planb.c
++++ b/drivers/media/video/planb.c
+@@ -91,7 +91,7 @@ static void planb_close(struct video_dev
+ static int planb_ioctl(struct video_device *, unsigned int, void *);
+ static int planb_init_done(struct video_device *);
+ static int planb_mmap(struct video_device *, const char *, unsigned long);
+-static void planb_irq(int, void *, struct pt_regs *);
++static void planb_irq(int, void *);
+ static void release_planb(void);
+ int init_planbs(struct video_init *);
+
+@@ -1316,7 +1316,7 @@ cmd_tab_data_end:
+ return c1;
+ }
+
+-static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
++static void planb_irq(int irq, void *dev_id)
+ {
+ unsigned int stat, astat;
+ struct planb *pb = (struct planb *)dev_id;
+diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
+index 7e727fe..5645c93 100644
+--- a/drivers/media/video/pvrusb2/Kconfig
++++ b/drivers/media/video/pvrusb2/Kconfig
+@@ -5,8 +5,6 @@ config VIDEO_PVRUSB2
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+- select VIDEO_SAA711X
+- select VIDEO_MSP3400
+ ---help---
+ This is a video4linux driver for Conexant 23416 based
+ usb2 personal video recorder devices.
+@@ -14,6 +12,20 @@ config VIDEO_PVRUSB2
+ To compile this driver as a module, choose M here: the
+ module will be called pvrusb2
+
++config VIDEO_PVRUSB2_29XXX
++ bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
++ depends on VIDEO_PVRUSB2 && EXPERIMENTAL
++ select VIDEO_SAA711X
++ select VIDEO_MSP3400
++ ---help---
++ This option enables support for WinTV-PVR USB2 devices whose
++ model number is of the form "29xxx" (leading prefix of "29"
++ followed by 3 digits).
++ To see if you may need this option, examine the white
++ sticker on the underside of your device.
++
++ If you are in doubt, say Y.
++
+ config VIDEO_PVRUSB2_24XXX
+ bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+ depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+@@ -25,14 +37,9 @@ config VIDEO_PVRUSB2_24XXX
+ form "24xxx" (leading prefix of "24" followed by 3 digits).
+ To see if you may need this option, examine the white
+ sticker on the underside of your device. Enabling this
+- option will not harm support for older devices, however it
+- is a separate option because of the experimental nature of
+- this new feature.
+-
+- If you are in doubt, say N.
++ option will not harm support for older devices.
+
+- Note: This feature is _very_ experimental. You have been
+- warned.
++ If you are in doubt, say Y.
+
+ config VIDEO_PVRUSB2_SYSFS
+ bool "pvrusb2 sysfs support (EXPERIMENTAL)"
+@@ -60,3 +67,5 @@ config VIDEO_PVRUSB2_DEBUGIFC
+ You do not need to select this option unless you plan
+ on debugging the driver or performing a manual firmware
+ extraction.
++
++ If you are in doubt, say N.
+diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
+index 02e4142..69b3e43 100644
+--- a/drivers/media/video/pvrusb2/Makefile
++++ b/drivers/media/video/pvrusb2/Makefile
+@@ -1,10 +1,6 @@
+ obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+ obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+
+-obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
+- pvrusb2-cx2584x-v4l.o \
+- pvrusb2-wm8775.o
+-
+ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+ pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
+ pvrusb2-encoder.o pvrusb2-video-v4l.o \
+@@ -12,7 +8,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrus
+ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+ pvrusb2-ctrl.o pvrusb2-std.o \
+ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+- $(obj-pvrusb2-24xxx-y) \
++ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+
+ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+index fb6198f..c77de85 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+@@ -43,12 +43,17 @@ int pvr2_ctrl_set_mask_value(struct pvr2
+ if (cptr->info->type == pvr2_ctl_bitmask) {
+ mask &= cptr->info->def.type_bitmask.valid_bits;
+ } else if (cptr->info->type == pvr2_ctl_int) {
+- if (val < cptr->info->def.type_int.min_value) {
+- break;
++ int lim;
++ lim = cptr->info->def.type_int.min_value;
++ if (cptr->info->get_min_value) {
++ cptr->info->get_min_value(cptr,&lim);
+ }
+- if (val > cptr->info->def.type_int.max_value) {
+- break;
++ if (val < lim) break;
++ lim = cptr->info->def.type_int.max_value;
++ if (cptr->info->get_max_value) {
++ cptr->info->get_max_value(cptr,&lim);
+ }
++ if (val > lim) break;
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ if (val >= cptr->info->def.type_enum.count) {
+ break;
+@@ -91,7 +96,9 @@ int pvr2_ctrl_get_max(struct pvr2_ctrl *
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+- if (cptr->info->type == pvr2_ctl_int) {
++ if (cptr->info->get_max_value) {
++ cptr->info->get_max_value(cptr,&ret);
++ } else if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.max_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+@@ -105,7 +112,9 @@ int pvr2_ctrl_get_min(struct pvr2_ctrl *
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+- if (cptr->info->type == pvr2_ctl_int) {
++ if (cptr->info->get_min_value) {
++ cptr->info->get_min_value(cptr,&ret);
++ } else if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.min_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+index 18a7073..c94f97b 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+@@ -317,7 +317,7 @@ int pvr2_encoder_configure(struct pvr2_h
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "Failed to configure cx32416");
++ "Failed to configure cx23416");
+ return ret;
+ }
+
+@@ -337,7 +337,7 @@ int pvr2_encoder_configure(struct pvr2_h
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "Failed to initialize cx32416 video input");
++ "Failed to initialize cx23416 video input");
+ return ret;
+ }
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+index 0d6dc33..34b08fb 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+@@ -33,7 +33,6 @@
+
+ */
+
+-#include <linux/config.h>
+ #include <linux/videodev2.h>
+ #include <linux/i2c.h>
+ #include <linux/mutex.h>
+@@ -41,32 +40,6 @@
+ #include "pvrusb2-io.h"
+ #include <media/cx2341x.h>
+
+-/* Legal values for the SRATE state variable */
+-#define PVR2_CVAL_SRATE_48 0
+-#define PVR2_CVAL_SRATE_44_1 1
+-
+-/* Legal values for the AUDIOBITRATE state variable */
+-#define PVR2_CVAL_AUDIOBITRATE_384 0
+-#define PVR2_CVAL_AUDIOBITRATE_320 1
+-#define PVR2_CVAL_AUDIOBITRATE_256 2
+-#define PVR2_CVAL_AUDIOBITRATE_224 3
+-#define PVR2_CVAL_AUDIOBITRATE_192 4
+-#define PVR2_CVAL_AUDIOBITRATE_160 5
+-#define PVR2_CVAL_AUDIOBITRATE_128 6
+-#define PVR2_CVAL_AUDIOBITRATE_112 7
+-#define PVR2_CVAL_AUDIOBITRATE_96 8
+-#define PVR2_CVAL_AUDIOBITRATE_80 9
+-#define PVR2_CVAL_AUDIOBITRATE_64 10
+-#define PVR2_CVAL_AUDIOBITRATE_56 11
+-#define PVR2_CVAL_AUDIOBITRATE_48 12
+-#define PVR2_CVAL_AUDIOBITRATE_32 13
+-#define PVR2_CVAL_AUDIOBITRATE_VBR 14
+-
+-/* Legal values for the AUDIOEMPHASIS state variable */
+-#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
+-#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
+-#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
+-
+ /* Legal values for PVR2_CID_HSM */
+ #define PVR2_CVAL_HSM_FAIL 0
+ #define PVR2_CVAL_HSM_FULL 1
+@@ -107,6 +80,8 @@ struct pvr2_ctl_info {
+
+ /* Control's implementation */
+ pvr2_ctlf_get_value get_value; /* Get its value */
++ pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
++ pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
+ pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
+ pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
+@@ -193,9 +168,7 @@ struct pvr2_decoder_ctrl {
+
+ /* Known major hardware variants, keyed from device ID */
+ #define PVR2_HDW_TYPE_29XXX 0
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ #define PVR2_HDW_TYPE_24XXX 1
+-#endif
+
+ typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
+ #define PVR2_I2C_FUNC_CNT 128
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+index be1e5cc..f920e0c 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+@@ -24,6 +24,7 @@
+ #include <linux/slab.h>
+ #include <linux/firmware.h>
+ #include <linux/videodev2.h>
++#include <media/v4l2-common.h>
+ #include <asm/semaphore.h>
+ #include "pvrusb2.h"
+ #include "pvrusb2-std.h"
+@@ -38,9 +39,7 @@
+
+ struct usb_device_id pvr2_device_table[] = {
+ [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
+-#endif
+ { }
+ };
+
+@@ -48,9 +47,7 @@ MODULE_DEVICE_TABLE(usb, pvr2_device_tab
+
+ static const char *pvr2_device_names[] = {
+ [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
+-#endif
+ };
+
+ struct pvr2_string_table {
+@@ -58,14 +55,12 @@ struct pvr2_string_table {
+ unsigned int cnt;
+ };
+
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ // Names of other client modules to request for 24xxx model hardware
+ static const char *pvr2_client_24xxx[] = {
+ "cx25840",
+ "tuner",
+ "wm8775",
+ };
+-#endif
+
+ // Names of other client modules to request for 29xxx model hardware
+ static const char *pvr2_client_29xxx[] = {
+@@ -79,12 +74,10 @@ static struct pvr2_string_table pvr2_cli
+ pvr2_client_29xxx,
+ sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ },
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = {
+ pvr2_client_24xxx,
+ sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ },
+-#endif
+ };
+
+ static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
+@@ -221,14 +214,15 @@ static const struct pvr2_mpeg_ids mpeg_i
+ };
+ #define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+
++
+ static const char *control_values_srate[] = {
+- [PVR2_CVAL_SRATE_48] = "48KHz",
+- [PVR2_CVAL_SRATE_44_1] = "44.1KHz",
++ [V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100] = "44.1 kHz",
++ [V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000] = "48 kHz",
++ [V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000] = "32 kHz",
+ };
+
+
+
+-
+ static const char *control_values_input[] = {
+ [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
+ [PVR2_CVAL_INPUT_RADIO] = "radio",
+@@ -362,6 +356,50 @@ static int ctrl_freq_set(struct pvr2_ctr
+ return 0;
+ }
+
++static int ctrl_hres_max_get(struct pvr2_ctrl *cptr,int *vp)
++{
++ /* If we're dealing with a 24xxx device, force the horizontal
++ maximum to be 720 no matter what, since we can't get the device
++ to work properly with any other value. Otherwise just return
++ the normal value. */
++ *vp = cptr->info->def.type_int.max_value;
++ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
++ return 0;
++}
++
++static int ctrl_hres_min_get(struct pvr2_ctrl *cptr,int *vp)
++{
++ /* If we're dealing with a 24xxx device, force the horizontal
++ minimum to be 720 no matter what, since we can't get the device
++ to work properly with any other value. Otherwise just return
++ the normal value. */
++ *vp = cptr->info->def.type_int.min_value;
++ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
++ return 0;
++}
++
++static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
++{
++ /* Actual maximum depends on the video standard in effect. */
++ if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {
++ *vp = 480;
++ } else {
++ *vp = 576;
++ }
++ return 0;
++}
++
++static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
++{
++ /* Actual minimum depends on device type. */
++ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
++ *vp = 75;
++ } else {
++ *vp = 17;
++ }
++ return 0;
++}
++
+ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+ {
+ return cptr->hdw->enc_stale != 0;
+@@ -719,19 +757,27 @@ static const struct pvr2_ctl_info contro
+ .internal_id = PVR2_CID_HRES,
+ .default_value = 720,
+ DEFREF(res_hor),
+- DEFINT(320,720),
++ DEFINT(19,720),
++ /* Hook in check for clamp on horizontal resolution in
++ order to avoid unsolved problem involving cx25840. */
++ .get_max_value = ctrl_hres_max_get,
++ .get_min_value = ctrl_hres_min_get,
+ },{
+ .desc = "Vertical capture resolution",
+ .name = "resolution_ver",
+ .internal_id = PVR2_CID_VRES,
+ .default_value = 480,
+ DEFREF(res_ver),
+- DEFINT(200,625),
++ DEFINT(17,576),
++ /* Hook in check for video standard and adjust maximum
++ depending on the standard. */
++ .get_max_value = ctrl_vres_max_get,
++ .get_min_value = ctrl_vres_min_get,
+ },{
+ .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+- .desc = "Sample rate",
++ .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
++ .desc = "Audio Sampling Frequency",
+ .name = "srate",
+- .default_value = PVR2_CVAL_SRATE_48,
+ DEFREF(srate),
+ DEFENUM(control_values_srate),
+ },{
+@@ -935,22 +981,18 @@ static int pvr2_upload_firmware1(struct
+ static const char *fw_files_29xxx[] = {
+ "v4l-pvrusb2-29xxx-01.fw",
+ };
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ static const char *fw_files_24xxx[] = {
+ "v4l-pvrusb2-24xxx-01.fw",
+ };
+-#endif
+ static const struct pvr2_string_table fw_file_defs[] = {
+ [PVR2_HDW_TYPE_29XXX] = {
+ fw_files_29xxx,
+ sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+ },
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = {
+ fw_files_24xxx,
+ sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ },
+-#endif
+ };
+ hdw->fw1_state = FW1_STATE_FAILED; // default result
+
+@@ -2237,11 +2279,14 @@ static int pvr2_hdw_commit_ctl_internal(
+ }
+
+ if (hdw->std_dirty ||
++ hdw->enc_stale ||
++ hdw->srate_dirty ||
++ hdw->res_ver_dirty ||
++ hdw->res_hor_dirty ||
+ 0) {
+ /* If any of this changes, then the encoder needs to be
+ reconfigured, and we need to reset the stream. */
+ stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+- stale_subsys_mask |= hdw->subsys_stream_mask;
+ }
+
+ if (hdw->srate_dirty) {
+@@ -2507,7 +2552,7 @@ void pvr2_hdw_v4l_store_minor_number(str
+ }
+
+
+-static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
++static void pvr2_ctl_write_complete(struct urb *urb)
+ {
+ struct pvr2_hdw *hdw = urb->context;
+ hdw->ctl_write_pend_flag = 0;
+@@ -2516,7 +2561,7 @@ static void pvr2_ctl_write_complete(stru
+ }
+
+
+-static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs)
++static void pvr2_ctl_read_complete(struct urb *urb)
+ {
+ struct pvr2_hdw *hdw = urb->context;
+ hdw->ctl_read_pend_flag = 0;
+@@ -3087,6 +3132,42 @@ static int pvr2_hdw_get_eeprom_addr(stru
+ }
+
+
++int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
++ u32 chip_id,unsigned long reg_id,
++ int setFl,u32 *val_ptr)
++{
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ struct list_head *item;
++ struct pvr2_i2c_client *cp;
++ struct v4l2_register req;
++ int stat = 0;
++ int okFl = 0;
++
++ req.i2c_id = chip_id;
++ req.reg = reg_id;
++ if (setFl) req.val = *val_ptr;
++ mutex_lock(&hdw->i2c_list_lock); do {
++ list_for_each(item,&hdw->i2c_clients) {
++ cp = list_entry(item,struct pvr2_i2c_client,list);
++ if (cp->client->driver->id != chip_id) continue;
++ stat = pvr2_i2c_client_cmd(
++ cp,(setFl ? VIDIOC_INT_S_REGISTER :
++ VIDIOC_INT_G_REGISTER),&req);
++ if (!setFl) *val_ptr = req.val;
++ okFl = !0;
++ break;
++ }
++ } while (0); mutex_unlock(&hdw->i2c_list_lock);
++ if (okFl) {
++ return stat;
++ }
++ return -EINVAL;
++#else
++ return -ENOSYS;
++#endif
++}
++
++
+ /*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+index fd931b5..29979bb 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+@@ -211,6 +211,14 @@ int pvr2_hdw_v4l_get_minor_number(struct
+ /* Store the v4l minor device number */
+ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+
++/* Direct read/write access to chip's registers:
++ chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
++ reg_id - register number to access
++ setFl - true to set the register, false to read it
++ val_ptr - storage location for source / result. */
++int pvr2_hdw_register_access(struct pvr2_hdw *,
++ u32 chip_id,unsigned long reg_id,
++ int setFl,u32 *val_ptr);
+
+ /* The following entry points are all lower level things you normally don't
+ want to worry about. */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+index fbe6039..0512166 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+@@ -19,6 +19,7 @@
+ *
+ */
+
++#include <linux/kernel.h>
+ #include "pvrusb2-i2c-core.h"
+ #include "pvrusb2-hdw-internal.h"
+ #include "pvrusb2-debug.h"
+@@ -26,10 +27,8 @@
+ #include "pvrusb2-audio.h"
+ #include "pvrusb2-tuner.h"
+ #include "pvrusb2-video-v4l.h"
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ #include "pvrusb2-cx2584x-v4l.h"
+ #include "pvrusb2-wm8775.h"
+-#endif
+
+ #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+@@ -71,7 +70,6 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw
+ return;
+ }
+ }
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ if (id == I2C_DRIVERID_CX25840) {
+ if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
+ return;
+@@ -82,7 +80,6 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw
+ return;
+ }
+ }
+-#endif
+ if (id == I2C_DRIVERID_SAA711X) {
+ if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
+ return;
+@@ -93,7 +90,8 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw
+
+ const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
+ {
+- if (idx >= sizeof(ops)/sizeof(ops[0])) return 0;
++ if (idx >= ARRAY_SIZE(ops))
++ return NULL;
+ return ops[idx];
+ }
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+index 8a9933d..05ea17a 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+@@ -31,7 +31,7 @@ static void set_standard(struct pvr2_hdw
+ v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
+ pvr2_trace(PVR2_TRACE_CHIPS,
+- "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
++ "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
+
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ }
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+index 7fca479..3b9012f 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+@@ -185,8 +185,6 @@ static int pvr2_i2c_basic_op(struct pvr2
+ }
+ }
+
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+-
+ /* This is a special entry point that is entered if an I2C operation is
+ attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
+ part doesn't work, but we know it is really there. So let's look for
+@@ -289,8 +287,6 @@ static int i2c_hack_cx25840(struct pvr2_
+ return -EIO;
+ }
+
+-#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
+-
+ /* This is a very, very limited I2C adapter implementation. We can only
+ support what we actually know will work on the device... */
+ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
+@@ -897,14 +893,12 @@ void pvr2_i2c_core_init(struct pvr2_hdw
+ hdw->i2c_func[idx] = pvr2_i2c_basic_op;
+ }
+
+-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ // If however we're dealing with new hardware, insert some hacks in
+ // the I2C transfer stack to let things work better.
+ if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+ hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+ hdw->i2c_func[0x44] = i2c_hack_cx25840;
+ }
+-#endif
+
+ // Configure the adapter and set up everything else related to it.
+ memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
+index 1e39376..70aa63e 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
+@@ -429,7 +429,7 @@ static void pvr2_stream_done(struct pvr2
+ } while (0); mutex_unlock(&sp->mutex);
+ }
+
+-static void buffer_complete(struct urb *urb, struct pt_regs *regs)
++static void buffer_complete(struct urb *urb)
+ {
+ struct pvr2_buffer *bp = urb->context;
+ struct pvr2_stream *sp;
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
+index 8f1a5af..e976c48 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
+@@ -20,7 +20,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+index d1dda5c..c294f46 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+@@ -19,7 +19,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
+ #include <asm/semaphore.h>
+@@ -40,8 +39,6 @@ struct pvr2_sysfs {
+ #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+ struct pvr2_sysfs_ctl_item *item_first;
+ struct pvr2_sysfs_ctl_item *item_last;
+- struct sysfs_ops kops;
+- struct kobj_type ktype;
+ struct class_device_attribute attr_v4l_minor_number;
+ struct class_device_attribute attr_unit_number;
+ int v4l_minor_number_created_ok;
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+index 0caf70b..bb40e90 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+@@ -29,27 +29,17 @@
+ #include "pvrusb2-v4l2.h"
+ #include "pvrusb2-ioread.h"
+ #include <linux/videodev2.h>
++#include <media/v4l2-dev.h>
+ #include <media/v4l2-common.h>
+
+ struct pvr2_v4l2_dev;
+ struct pvr2_v4l2_fh;
+ struct pvr2_v4l2;
+
+-/* V4L no longer provide the ability to set / get a private context pointer
+- (i.e. video_get_drvdata / video_set_drvdata), which means we have to
+- concoct our own context locating mechanism. Supposedly this is intended
+- to simplify driver implementation. It's not clear to me how that can
+- possibly be true. Our solution here is to maintain a lookup table of
+- our context instances, indexed by the minor device number of the V4L
+- device. See pvr2_v4l2_open() for some implications of this approach. */
+-static struct pvr2_v4l2_dev *devices[256];
+-static DEFINE_MUTEX(device_lock);
+-
+ struct pvr2_v4l2_dev {
++ struct video_device devbase; /* MUST be first! */
+ struct pvr2_v4l2 *v4lp;
+- struct video_device *vdev;
+ struct pvr2_context_stream *stream;
+- int ctxt_idx;
+ enum pvr2_config config;
+ };
+
+@@ -74,7 +64,7 @@ struct pvr2_v4l2 {
+ struct v4l2_prio_state prio;
+
+ /* streams */
+- struct pvr2_v4l2_dev video_dev;
++ struct pvr2_v4l2_dev *vdev;
+ };
+
+ static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+@@ -459,18 +449,26 @@ static int pvr2_v4l2_do_ioctl(struct ino
+ ret = 0;
+ switch(vf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
++ int lmin,lmax;
++ struct pvr2_ctrl *hcp,*vcp;
+ int h = vf->fmt.pix.height;
+ int w = vf->fmt.pix.width;
+-
+- if (h < 200) {
+- h = 200;
+- } else if (h > 625) {
+- h = 625;
++ hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
++ vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
++
++ lmin = pvr2_ctrl_get_min(hcp);
++ lmax = pvr2_ctrl_get_max(hcp);
++ if (w < lmin) {
++ w = lmin;
++ } else if (w > lmax) {
++ w = lmax;
+ }
+- if (w < 320) {
+- w = 320;
+- } else if (w > 720) {
+- w = 720;
++ lmin = pvr2_ctrl_get_min(vcp);
++ lmax = pvr2_ctrl_get_max(vcp);
++ if (h < lmin) {
++ h = lmin;
++ } else if (h > lmax) {
++ h = lmax;
+ }
+
+ memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+@@ -479,14 +477,8 @@ static int pvr2_v4l2_do_ioctl(struct ino
+ vf->fmt.pix.height = h;
+
+ if (cmd == VIDIOC_S_FMT) {
+- pvr2_ctrl_set_value(
+- pvr2_hdw_get_ctrl_by_id(hdw,
+- PVR2_CID_HRES),
+- vf->fmt.pix.width);
+- pvr2_ctrl_set_value(
+- pvr2_hdw_get_ctrl_by_id(hdw,
+- PVR2_CID_VRES),
+- vf->fmt.pix.height);
++ pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
++ pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
+ }
+ } break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+@@ -669,6 +661,20 @@ static int pvr2_v4l2_do_ioctl(struct ino
+ ret = 0;
+ break;
+ }
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ case VIDIOC_INT_G_REGISTER:
++ case VIDIOC_INT_S_REGISTER:
++ {
++ u32 val;
++ struct v4l2_register *req = (struct v4l2_register *)arg;
++ if (cmd == VIDIOC_INT_S_REGISTER) val = req->val;
++ ret = pvr2_hdw_register_access(
++ hdw,req->i2c_id,req->reg,
++ cmd == VIDIOC_INT_S_REGISTER,&val);
++ if (cmd == VIDIOC_INT_G_REGISTER) req->val = val;
++ break;
++ }
++#endif
+
+ default :
+ ret = v4l_compat_translate_ioctl(inode,file,cmd,
+@@ -702,21 +708,22 @@ static int pvr2_v4l2_do_ioctl(struct ino
+ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
+ {
+ printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
+- dip->vdev->minor,pvr2_config_get_name(dip->config));
+- if (dip->ctxt_idx >= 0) {
+- mutex_lock(&device_lock);
+- devices[dip->ctxt_idx] = NULL;
+- dip->ctxt_idx = -1;
+- mutex_unlock(&device_lock);
+- }
+- video_unregister_device(dip->vdev);
++ dip->devbase.minor,pvr2_config_get_name(dip->config));
++
++ /* Paranoia */
++ dip->v4lp = NULL;
++ dip->stream = NULL;
++
++ /* Actual deallocation happens later when all internal references
++ are gone. */
++ video_unregister_device(&dip->devbase);
+ }
+
+
+ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
+ {
+ pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
+- pvr2_v4l2_dev_destroy(&vp->video_dev);
++ pvr2_v4l2_dev_destroy(vp->vdev);
+
+ pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
+ pvr2_channel_done(&vp->channel);
+@@ -724,6 +731,14 @@ static void pvr2_v4l2_destroy_no_lock(st
+ }
+
+
++static void pvr2_video_device_release(struct video_device *vdev)
++{
++ struct pvr2_v4l2_dev *dev;
++ dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
++ kfree(dev);
++}
++
++
+ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
+ {
+ struct pvr2_v4l2 *vp;
+@@ -795,40 +810,12 @@ static int pvr2_v4l2_release(struct inod
+
+ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
+ {
+- struct pvr2_v4l2_dev *dip = NULL; /* Our own context pointer */
++ struct pvr2_v4l2_dev *dip; /* Our own context pointer */
+ struct pvr2_v4l2_fh *fhp;
+ struct pvr2_v4l2 *vp;
+ struct pvr2_hdw *hdw;
+
+- mutex_lock(&device_lock);
+- /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
+- atomic read of the device mapping array here, we still need the
+- mutex. The problem is that there is a tiny race possible when
+- we register the device. We can't update the device mapping
+- array until after the device has been registered, owing to the
+- fact that we can't know the minor device number until after the
+- registration succeeds. And if another thread tries to open the
+- device in the window of time after registration but before the
+- map is updated, then it will get back an erroneous null pointer
+- and the open will result in a spurious failure. The only way to
+- prevent that is to (a) be inside the mutex here before we access
+- the array, and (b) cover the entire registration process later
+- on with this same mutex. Thus if we get inside the mutex here,
+- then we can be assured that the registration process actually
+- completed correctly. This is an unhappy complication from the
+- use of global data in a driver that lives in a preemptible
+- environment. It sure would be nice if the video device itself
+- had a means for storing and retrieving a local context pointer.
+- Oh wait. It did. But now it's gone. Silly me. */
+- {
+- unsigned int midx = iminor(file->f_dentry->d_inode);
+- if (midx < sizeof(devices)/sizeof(devices[0])) {
+- dip = devices[midx];
+- }
+- }
+- mutex_unlock(&device_lock);
+-
+- if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
++ dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
+
+ vp = dip->v4lp;
+ hdw = vp->channel.hdw;
+@@ -1058,38 +1045,24 @@ static void pvr2_v4l2_dev_init(struct pv
+ return;
+ }
+
+- dip->vdev = video_device_alloc();
+- if (!dip->vdev) {
+- err("Alloc of pvrusb2 v4l video device failed");
+- return;
+- }
+-
+- memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
+- dip->vdev->release = video_device_release;
+- mutex_lock(&device_lock);
++ memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
++ dip->devbase.release = pvr2_video_device_release;
+
+ mindevnum = -1;
+ unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+ if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ mindevnum = video_nr[unit_number];
+ }
+- if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) &&
+- (video_register_device(dip->vdev, v4l_type, -1) < 0)) {
++ if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
++ (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
+ err("Failed to register pvrusb2 v4l video device");
+ } else {
+ printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
+- dip->vdev->minor,pvr2_config_get_name(dip->config));
+- }
+-
+- if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
+- (devices[dip->vdev->minor] == NULL)) {
+- dip->ctxt_idx = dip->vdev->minor;
+- devices[dip->ctxt_idx] = dip;
++ dip->devbase.minor,pvr2_config_get_name(dip->config));
+ }
+- mutex_unlock(&device_lock);
+
+ pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+- dip->vdev->minor);
++ dip->devbase.minor);
+ }
+
+
+@@ -1100,15 +1073,19 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struc
+ vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ if (!vp) return vp;
+ memset(vp,0,sizeof(*vp));
+- vp->video_dev.ctxt_idx = -1;
++ vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
++ if (!vp->vdev) {
++ kfree(vp);
++ return NULL;
++ }
++ memset(vp->vdev,0,sizeof(*vp->vdev));
+ pvr2_channel_init(&vp->channel,mnp);
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
+
+ vp->channel.check_func = pvr2_v4l2_internal_check;
+
+ /* register streams */
+- pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg);
+-
++ pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
+
+ return vp;
+ }
+diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
+index 11f751a..f5e8484 100644
+--- a/drivers/media/video/pwc/philips.txt
++++ b/drivers/media/video/pwc/philips.txt
+@@ -175,8 +175,8 @@ dev_hint
+ - If a device node is already occupied, registration will fail and
+ the webcam is not available.
+ - You can have up to 64 video devices; be sure to make enough device
+- nodes in /dev if you want to spread the numbers (this does not apply
+- to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
++ nodes in /dev if you want to spread the numbers.
++ After /dev/video9 comes /dev/video10 (not /dev/videoA).
+ - If a camera does not match any dev_hint, it will simply get assigned
+ the first available device node, just as it used to be.
+
+diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
+index d470394..46c1148 100644
+--- a/drivers/media/video/pwc/pwc-if.c
++++ b/drivers/media/video/pwc/pwc-if.c
+@@ -682,7 +682,7 @@ static int pwc_rcv_short_packet(struct p
+ /* This gets called for the Isochronous pipe (video). This is done in
+ * interrupt time, so it has to be fast, not crash, and not stall. Neat.
+ */
+-static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
++static void pwc_isoc_handler(struct urb *urb)
+ {
+ struct pwc_device *pdev;
+ int i, fst, flen;
+@@ -711,7 +711,7 @@ static void pwc_isoc_handler(struct urb
+ case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
+ case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
+ case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
+- case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
++ case -ETIME: errmsg = "Device does not respond"; break;
+ }
+ PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+ /* Give up after a number of contiguous errors on the USB bus.
+@@ -1024,12 +1024,25 @@ static ssize_t show_snapshot_button_stat
+ static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+ NULL);
+
+-static void pwc_create_sysfs_files(struct video_device *vdev)
++static int pwc_create_sysfs_files(struct video_device *vdev)
+ {
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+- if (pdev->features & FEATURE_MOTOR_PANTILT)
+- video_device_create_file(vdev, &class_device_attr_pan_tilt);
+- video_device_create_file(vdev, &class_device_attr_button);
++ int rc;
++
++ rc = video_device_create_file(vdev, &class_device_attr_button);
++ if (rc)
++ goto err;
++ if (pdev->features & FEATURE_MOTOR_PANTILT) {
++ rc = video_device_create_file(vdev,&class_device_attr_pan_tilt);
++ if (rc) goto err_button;
++ }
++
++ return 0;
++
++err_button:
++ video_device_remove_file(vdev, &class_device_attr_button);
++err:
++ return rc;
+ }
+
+ static void pwc_remove_sysfs_files(struct video_device *vdev)
+@@ -1408,7 +1421,7 @@ static int usb_pwc_probe(struct usb_inte
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct pwc_device *pdev = NULL;
+ int vendor_id, product_id, type_id;
+- int i, hint;
++ int i, hint, rc;
+ int features = 0;
+ int video_nr = -1; /* default: use next available device */
+ char serial_number[30], *name;
+@@ -1709,9 +1722,8 @@ static int usb_pwc_probe(struct usb_inte
+ i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+ if (i < 0) {
+ PWC_ERROR("Failed to register as video device (%d).\n", i);
+- video_device_release(pdev->vdev); /* Drip... drip... drip... */
+- kfree(pdev); /* Oops, no memory leaks please */
+- return -EIO;
++ rc = i;
++ goto err;
+ }
+ else {
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+@@ -1723,13 +1735,24 @@ static int usb_pwc_probe(struct usb_inte
+
+ PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
+ usb_set_intfdata (intf, pdev);
+- pwc_create_sysfs_files(pdev->vdev);
++ rc = pwc_create_sysfs_files(pdev->vdev);
++ if (rc)
++ goto err_unreg;
+
+ /* Set the leds off */
+ pwc_set_leds(pdev, 0, 0);
+ pwc_camera_power(pdev, 0);
+
+ return 0;
++
++err_unreg:
++ if (hint < MAX_DEV_HINTS)
++ device_hint[hint].pdev = NULL;
++ video_unregister_device(pdev->vdev);
++err:
++ video_device_release(pdev->vdev); /* Drip... drip... drip... */
++ kfree(pdev); /* Oops, no memory leaks please */
++ return rc;
+ }
+
+ /* The user janked out the cable... */
+diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
+index 59a1872..77bb940 100644
+--- a/drivers/media/video/saa5246a.c
++++ b/drivers/media/video/saa5246a.c
+@@ -830,7 +830,6 @@ static struct video_device saa_template
+ .owner = THIS_MODULE,
+ .name = IF_NAME,
+ .type = VID_TYPE_TELETEXT,
+- .hardware = VID_HARDWARE_SAA5249,
+ .fops = &saa_fops,
+ .release = video_device_release,
+ .minor = -1,
+diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
+index 19a8d65..bb3fb43 100644
+--- a/drivers/media/video/saa5249.c
++++ b/drivers/media/video/saa5249.c
+@@ -713,7 +713,6 @@ static struct video_device saa_template
+ .owner = THIS_MODULE,
+ .name = IF_NAME,
+ .type = VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */
+- .hardware = VID_HARDWARE_SAA5249,
+ .fops = &saa_fops,
+ };
+
+diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
+index b59c117..c5719f7 100644
+--- a/drivers/media/video/saa7115.c
++++ b/drivers/media/video/saa7115.c
+@@ -1,4 +1,6 @@
+-/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
++/* saa711x - Philips SAA711x video decoder driver
++ * This driver can work with saa7111, saa7111a, saa7113, saa7114,
++ * saa7115 and saa7118.
+ *
+ * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
+ * the saa7111 driver by Dave Perks.
+@@ -16,7 +18,9 @@
+ * (2/17/2003)
+ *
+ * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil at xs4all.nl>
+- * SAA7113 support by Mauro Carvalho Chehab <mchehab at infradead.org>
++ *
++ * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab at infradead.org>
++ * SAA7111, SAA7113 and SAA7118 support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -33,6 +37,7 @@
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++#include "saa711x_regs.h"
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -43,7 +48,9 @@
+ #include <media/saa7115.h>
+ #include <asm/div64.h>
+
+-MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
++#define VRES_60HZ (480+16)
++
++MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
+ MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
+ "Hans Verkuil, Mauro Carvalho Chehab");
+ MODULE_LICENSE("GPL");
+@@ -54,14 +61,14 @@ module_param(debug, bool, 0644);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+ static unsigned short normal_i2c[] = {
+- 0x4a >> 1, 0x48 >> 1, /* SAA7113 */
+- 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */
++ 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
++ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
+ I2C_CLIENT_END };
+
+
+ I2C_CLIENT_INSMOD;
+
+-struct saa7115_state {
++struct saa711x_state {
+ v4l2_std_id std;
+ int input;
+ int enable;
+@@ -70,6 +77,8 @@ struct saa7115_state {
+ int contrast;
+ int hue;
+ int sat;
++ int width;
++ int height;
+ enum v4l2_chip_ident ident;
+ u32 audclk_freq;
+ u32 crystal_freq;
+@@ -80,420 +89,508 @@ struct saa7115_state {
+
+ /* ----------------------------------------------------------------------- */
+
+-static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
++static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
+ {
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+-static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
++/* Sanity routine to check if a register is present */
++static int saa711x_has_reg(const int id, const u8 reg)
+ {
++ if (id == V4L2_IDENT_SAA7111)
++ return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
++ (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
++
++ /* common for saa7113/4/5/8 */
++ if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
++ reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
++ reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
++ reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
++ return 0;
++
++ switch (id) {
++ case V4L2_IDENT_SAA7113:
++ return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
++ reg != 0x5d && reg < 0x63;
++ case V4L2_IDENT_SAA7114:
++ return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
++ (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
++ reg != 0x81 && reg < 0xf0;
++ case V4L2_IDENT_SAA7115:
++ return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
++ case V4L2_IDENT_SAA7118:
++ return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
++ (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
++ (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
++ }
++ return 1;
++}
++
++static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
++{
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ unsigned char reg, data;
+
+ while (*regs != 0x00) {
+ reg = *(regs++);
+ data = *(regs++);
+- if (saa7115_write(client, reg, data) < 0)
+- return -1;
++
++ /* According with datasheets, reserved regs should be
++ filled with 0 - seems better not to touch on they */
++ if (saa711x_has_reg(state->ident,reg)) {
++ if (saa711x_write(client, reg, data) < 0)
++ return -1;
++ } else {
++ v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
++ }
+ }
+ return 0;
+ }
+
+-static inline int saa7115_read(struct i2c_client *client, u8 reg)
++static inline int saa711x_read(struct i2c_client *client, u8 reg)
+ {
+ return i2c_smbus_read_byte_data(client, reg);
+ }
+
+ /* ----------------------------------------------------------------------- */
+
++/* SAA7111 initialization table */
++static const unsigned char saa7111_init[] = {
++ R_01_INC_DELAY, 0x00, /* reserved */
++
++ /*front end */
++ R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
++ R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
++ * GAFIX=0, GAI1=256, GAI2=256 */
++ R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
++ R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
++
++ /* decoder */
++ R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
++ * pixels after end of last line */
++ R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
++ * work with NTSC, too */
++ R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
++ * VTRC=1, HPLL=0, VNOI=0 */
++ R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
++ * VBLB=0, UPTCV=0, APER=1 */
++ R_0A_LUMA_BRIGHT_CNTL, 0x80,
++ R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
++ R_0C_CHROMA_SAT_CNTL, 0x40,
++ R_0D_CHROMA_HUE_CNTL, 0x00,
++ R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
++ * FCTC=0, CHBW=1 */
++ R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
++ R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
++ R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
++ * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
++ R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
++ R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
++ R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
++ R_15_VGATE_START_FID_CHG, 0x00,
++ R_16_VGATE_STOP, 0x00,
++ R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
++
++ 0x00, 0x00
++};
++
++/* SAA7113 init codes */
++static const unsigned char saa7113_init[] = {
++ R_01_INC_DELAY, 0x08,
++ R_02_INPUT_CNTL_1, 0xc2,
++ R_03_INPUT_CNTL_2, 0x30,
++ R_04_INPUT_CNTL_3, 0x00,
++ R_05_INPUT_CNTL_4, 0x00,
++ R_06_H_SYNC_START, 0x89,
++ R_07_H_SYNC_STOP, 0x0d,
++ R_08_SYNC_CNTL, 0x88,
++ R_09_LUMA_CNTL, 0x01,
++ R_0A_LUMA_BRIGHT_CNTL, 0x80,
++ R_0B_LUMA_CONTRAST_CNTL, 0x47,
++ R_0C_CHROMA_SAT_CNTL, 0x40,
++ R_0D_CHROMA_HUE_CNTL, 0x00,
++ R_0E_CHROMA_CNTL_1, 0x01,
++ R_0F_CHROMA_GAIN_CNTL, 0x2a,
++ R_10_CHROMA_CNTL_2, 0x08,
++ R_11_MODE_DELAY_CNTL, 0x0c,
++ R_12_RT_SIGNAL_CNTL, 0x07,
++ R_13_RT_X_PORT_OUT_CNTL, 0x00,
++ R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
++ R_15_VGATE_START_FID_CHG, 0x00,
++ R_16_VGATE_STOP, 0x00,
++ R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
++
++ 0x00, 0x00
++};
++
+ /* If a value differs from the Hauppauge driver values, then the comment starts with
+ 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
+ Hauppauge driver sets. */
+
++/* SAA7114 and SAA7115 initialization table */
+ static const unsigned char saa7115_init_auto_input[] = {
+ /* Front-End Part */
+- 0x01, 0x48, /* white peak control disabled */
+- 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
+- 0x04, 0x90, /* analog gain set to 0 */
+- 0x05, 0x90, /* analog gain set to 0 */
++ R_01_INC_DELAY, 0x48, /* white peak control disabled */
++ R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
++ R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
++ R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
+ /* Decoder Part */
+- 0x06, 0xeb, /* horiz sync begin = -21 */
+- 0x07, 0xe0, /* horiz sync stop = -17 */
+- 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
+- 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
+- 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
+- 0x0d, 0x00, /* chrominance hue control */
+- 0x0f, 0x00, /* chrominance gain control: use automicatic mode */
+- 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */
+- 0x11, 0x00, /* delay control */
+- 0x12, 0x9d, /* RTS0 output control: VGATE */
+- 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
+- 0x14, 0x00, /* analog/ADC/auto compatibility control */
+- 0x18, 0x40, /* raw data gain 0x00 = nominal */
+- 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */
+- 0x1a, 0x77, /* color killer level control 0x77 = recommended */
+- 0x1b, 0x42, /* misc chroma control 0x42 = recommended */
+- 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
+- 0x1d, 0x01, /* combfilter control 0x01 = recommended */
++ R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
++ R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
++ R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
++ R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
++ R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
++ R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
++ R_0D_CHROMA_HUE_CNTL, 0x00,
++ R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
++ R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
++ R_11_MODE_DELAY_CNTL, 0x00,
++ R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
++ R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
++ R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
++ R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
++ R_19_RAW_DATA_OFF_CNTL, 0x80,
++ R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
++ R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
++ R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
++ R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
++
++
++ R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
+
+ /* Power Device Control */
+- 0x88, 0xd0, /* reset device */
+- 0x88, 0xf0, /* set device programmed, all in operational mode */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
+ 0x00, 0x00
+ };
+
++/* Used to reset saa7113, saa7114 and saa7115 */
+ static const unsigned char saa7115_cfg_reset_scaler[] = {
+- 0x87, 0x00, /* disable I-port output */
+- 0x88, 0xd0, /* reset scaler */
+- 0x88, 0xf0, /* activate scaler */
+- 0x87, 0x01, /* enable I-port output */
++ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
++ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
+ 0x00, 0x00
+ };
+
+ /* ============== SAA7715 VIDEO templates ============= */
+
+-static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
+- 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */
+- 0xcd, 0x02, /* hsize hi (output) */
++static const unsigned char saa7115_cfg_60hz_video[] = {
++ R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
+
+- /* Why not in 60hz-Land, too? */
+- 0xd0, 0x01, /* downscale = 1 */
+- 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+- 0xd9, 0x04,
+- 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+- 0xdd, 0x02, /* H-scaling incr chroma */
++ R_15_VGATE_START_FID_CHG, 0x03,
++ R_16_VGATE_STOP, 0x11,
++ R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
+
+- 0x00, 0x00
+-};
+-static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
+- 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
+- 0xcf, 0x00, /* vsize hi (output) */
++ R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
++ R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
+
+- /* Why not in 60hz-Land, too? */
+- 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+- 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
++ R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
+
+- 0xe0, 0x00, /* V-scaling incr luma low */
+- 0xe1, 0x04, /* " hi */
+- 0xe2, 0x00, /* V-scaling incr chroma low */
+- 0xe3, 0x04, /* " hi */
++ /* Task A */
++ R_90_A_TASK_HANDLING_CNTL, 0x80,
++ R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
++ R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
++ R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
+
+- 0x00, 0x00
+-};
++ /* hoffset low (input), 0x0002 is minimum */
++ R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
++ R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+-static const unsigned char saa7115_cfg_60hz_video[] = {
+- 0x80, 0x00, /* reset tasks */
+- 0x88, 0xd0, /* reset scaler */
++ /* hsize low (input), 0x02d0 = 720 */
++ R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
++ R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+- 0x15, 0x03, /* VGATE pulse start */
+- 0x16, 0x11, /* VGATE pulse stop */
+- 0x17, 0x9c, /* VGATE MSB and other values */
++ R_98_A_VERT_INPUT_WINDOW_START, 0x05,
++ R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+- 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
+- 0x0e, 0x07, /* lots of different stuff... video autodetection is on */
++ R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
++ R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
+
+- 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */
++ R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
++ R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
+
+- /* Task A */
+- 0x90, 0x80, /* Task Handling Control */
+- 0x91, 0x48, /* X-port formats/config */
+- 0x92, 0x40, /* Input Ref. signal Def. */
+- 0x93, 0x84, /* I-port config */
+- 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */
+- 0x95, 0x00, /* hoffset hi (input) */
+- 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+- 0x97, 0x02, /* hsize hi (input) */
+- 0x98, 0x05, /* voffset low (input) */
+- 0x99, 0x00, /* voffset hi (input) */
+- 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */
+- 0x9b, 0x00, /* vsize hi (input) */
+- 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
+- 0x9d, 0x05, /* hsize hi (output) */
+- 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */
+- 0x9f, 0x00, /* vsize hi (output) */
++ R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
++ R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
+
+ /* Task B */
+- 0xc0, 0x00, /* Task Handling Control */
+- 0xc1, 0x08, /* X-port formats/config */
+- 0xc2, 0x00, /* Input Ref. signal Def. */
+- 0xc3, 0x80, /* I-port config */
+- 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */
+- 0xc5, 0x00, /* hoffset hi (input) */
+- 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+- 0xc7, 0x02, /* hsize hi (input) */
+- 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */
+- 0xc9, 0x00, /* voffset hi (input) */
+- 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */
+- 0xcb, 0x00, /* vsize hi (input) */
+- 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
+- 0xcd, 0x02, /* hsize hi (output) */
+-
+- 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+- 0xf1, 0x05, /* low bit with 0xF0 */
+- 0xf5, 0xad, /* Set pulse generator register */
+- 0xf6, 0x01,
+-
+- 0x87, 0x00, /* Disable I-port output */
+- 0x88, 0xd0, /* reset scaler */
+- 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
+- 0x88, 0xf0, /* activate scaler */
+- 0x87, 0x01, /* Enable I-port output */
+- 0x00, 0x00
+-};
++ R_C0_B_TASK_HANDLING_CNTL, 0x00,
++ R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
++ R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
++ R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
+
+-static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
+- 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */
+- 0xcd, 0x02, /* hsize hi (output) */
++ /* 0x0002 is minimum */
++ R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
++ R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+- 0xd0, 0x01, /* down scale = 1 */
+- 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+- 0xd9, 0x04,
+- 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+- 0xdd, 0x02, /* H-scaling incr chroma */
++ /* 0x02d0 = 720 */
++ R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
++ R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+- 0x00, 0x00
+-};
+-static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
+- 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
+- 0xcf, 0x01, /* vsize hi (output) */
++ /* vwindow start 0x12 = 18 */
++ R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
++ R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
++
++ /* vwindow length 0xf8 = 248 */
++ R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
++ R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
+
+- 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+- 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
++ /* hwindow 0x02d0 = 720 */
++ R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
++ R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
+
+- 0xe0, 0x00, /* V-scaling incr luma low */
+- 0xe1, 0x04, /* " hi */
+- 0xe2, 0x00, /* V-scaling incr chroma low */
+- 0xe3, 0x04, /* " hi */
++ R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
++ R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
++ R_F5_PULSGEN_LINE_LENGTH, 0xad,
++ R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
+
+ 0x00, 0x00
+ };
+
+ static const unsigned char saa7115_cfg_50hz_video[] = {
+- 0x80, 0x00, /* reset tasks */
+- 0x88, 0xd0, /* reset scaler */
++ R_80_GLOBAL_CNTL_1, 0x00,
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
+
+- 0x15, 0x37, /* VGATE start */
+- 0x16, 0x16, /* VGATE stop */
+- 0x17, 0x99, /* VGATE MSB and other values */
++ R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
++ R_16_VGATE_STOP, 0x16,
++ R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
+
+- 0x08, 0x28, /* 0x28 = PAL */
+- 0x0e, 0x07, /* chrominance control 1 */
++ R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
++ R_0E_CHROMA_CNTL_1, 0x07,
+
+- 0x5a, 0x03, /* Vertical offset, standard 50hz value */
++ R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
+
+ /* Task A */
+- 0x90, 0x81, /* Task Handling Control */
+- 0x91, 0x48, /* X-port formats/config */
+- 0x92, 0x40, /* Input Ref. signal Def. */
+- 0x93, 0x84, /* I-port config */
++ R_90_A_TASK_HANDLING_CNTL, 0x81,
++ R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
++ R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
++ R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
++
+ /* This is weird: the datasheet says that you should use 2 as the minimum value, */
+ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+- 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */
+- 0x95, 0x00, /* hoffset hi (input) */
+- 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+- 0x97, 0x02, /* hsize hi (input) */
+- 0x98, 0x03, /* voffset low (input) */
+- 0x99, 0x00, /* voffset hi (input) */
+- 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */
+- 0x9b, 0x00, /* vsize hi (input) */
+- 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
+- 0x9d, 0x05, /* hsize hi (output) */
+- 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */
+- 0x9f, 0x00, /* vsize hi (output) */
++ /* hoffset low (input), 0x0002 is minimum */
++ R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
++ R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
++
++ /* hsize low (input), 0x02d0 = 720 */
++ R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
++ R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
++
++ R_98_A_VERT_INPUT_WINDOW_START, 0x03,
++ R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
++
++ /* vsize 0x12 = 18 */
++ R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
++ R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
++
++ /* hsize 0x05a0 = 1440 */
++ R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
++ R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
++ R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
++ R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
+
+ /* Task B */
+- 0xc0, 0x00, /* Task Handling Control */
+- 0xc1, 0x08, /* X-port formats/config */
+- 0xc2, 0x00, /* Input Ref. signal Def. */
+- 0xc3, 0x80, /* I-port config */
+- 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
+- 0xc5, 0x00, /* hoffset hi (input) */
+- 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+- 0xc7, 0x02, /* hsize hi (input) */
+- 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */
+- 0xc9, 0x00, /* voffset hi (input) */
+- 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */
+- 0xcb, 0x01, /* vsize hi (input) */
+- 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
+- 0xcd, 0x02, /* hsize hi (output) */
+- 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
+- 0xcf, 0x01, /* vsize hi (output) */
+-
+- 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+- 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */
+- 0xf5, 0xb0, /* Set pulse generator register */
+- 0xf6, 0x01,
+-
+- 0x87, 0x00, /* Disable I-port output */
+- 0x88, 0xd0, /* reset scaler (was 0xD0) */
+- 0x80, 0x20, /* Activate only task "B" */
+- 0x88, 0xf0, /* activate scaler */
+- 0x87, 0x01, /* Enable I-port output */
++ R_C0_B_TASK_HANDLING_CNTL, 0x00,
++ R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
++ R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
++ R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
++
++ /* This is weird: the datasheet says that you should use 2 as the minimum value, */
++ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
++ /* hoffset low (input), 0x0002 is minimum. See comment above. */
++ R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
++ R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
++
++ /* hsize 0x02d0 = 720 */
++ R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
++ R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
++
++ /* voffset 0x16 = 22 */
++ R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
++ R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
++
++ /* vsize 0x0120 = 288 */
++ R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
++ R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
++
++ /* hsize 0x02d0 = 720 */
++ R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
++ R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
++
++ R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
++ R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
++ R_F5_PULSGEN_LINE_LENGTH, 0xb0,
++ R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
++
+ 0x00, 0x00
+ };
+
+ /* ============== SAA7715 VIDEO templates (end) ======= */
+
+ static const unsigned char saa7115_cfg_vbi_on[] = {
+- 0x80, 0x00, /* reset tasks */
+- 0x88, 0xd0, /* reset scaler */
+- 0x80, 0x30, /* Activate both tasks */
+- 0x88, 0xf0, /* activate scaler */
+- 0x87, 0x01, /* Enable I-port output */
++ R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
++ R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
++ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
++
+ 0x00, 0x00
+ };
+
+ static const unsigned char saa7115_cfg_vbi_off[] = {
+- 0x80, 0x00, /* reset tasks */
+- 0x88, 0xd0, /* reset scaler */
+- 0x80, 0x20, /* Activate only task "B" */
+- 0x88, 0xf0, /* activate scaler */
+- 0x87, 0x01, /* Enable I-port output */
+- 0x00, 0x00
+-};
++ R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
++ R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
++ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
+
+-static const unsigned char saa7113_init_auto_input[] = {
+- 0x01, 0x08, /* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+- 0x02, 0xc2, /* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+- 0x03, 0x30, /* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+- 0x04, 0x00, /* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+- 0x05, 0x00, /* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+- 0x06, 0x89, /* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+- 0x07, 0x0d, /* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+- 0x08, 0x88, /* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+- 0x09, 0x01, /* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+- 0x0a, 0x80, /* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+- 0x0b, 0x47, /* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+- 0x0c, 0x40, /* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+- 0x0d, 0x00, /* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+- 0x0e, 0x01, /* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+- 0x0f, 0x2a, /* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+- 0x10, 0x08, /* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+- 0x11, 0x0c, /* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+- 0x12, 0x07, /* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+- 0x13, 0x00, /* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+- 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+- 0x15, 0x00, /* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+- 0x16, 0x00, /* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+- 0x17, 0x00, /* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+ 0x00, 0x00
+ };
+
++
+ static const unsigned char saa7115_init_misc[] = {
+- 0x81, 0x01, /* reg 0x15,0x16 define blanking window */
+- 0x82, 0x00,
+- 0x83, 0x01, /* I port settings */
+- 0x84, 0x20,
+- 0x85, 0x21,
+- 0x86, 0xc5,
+- 0x87, 0x01,
++ R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
++ R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
++ R_84_I_PORT_SIGNAL_DEF, 0x20,
++ R_85_I_PORT_SIGNAL_POLAR, 0x21,
++ R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
++ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
+
+ /* Task A */
+- 0xa0, 0x01, /* down scale = 1 */
+- 0xa1, 0x00, /* prescale accumulation length = 1 */
+- 0xa2, 0x00, /* dc gain and fir prefilter control */
+- 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */
+- 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */
+- 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */
+- 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */
+- 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+- 0xaa, 0x00, /* H-phase offset Luma = 0 */
+- 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+- 0xad, 0x01, /* H-scaling incr chroma */
+- 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
+-
+- 0xb0, 0x00, /* V-scaling incr luma low */
+- 0xb1, 0x04, /* " hi */
+- 0xb2, 0x00, /* V-scaling incr chroma low */
+- 0xb3, 0x04, /* " hi */
+- 0xb4, 0x01, /* V-scaling mode control */
+- 0xb8, 0x00, /* V-phase offset chroma 00 */
+- 0xb9, 0x00, /* V-phase offset chroma 01 */
+- 0xba, 0x00, /* V-phase offset chroma 10 */
+- 0xbb, 0x00, /* V-phase offset chroma 11 */
+- 0xbc, 0x00, /* V-phase offset luma 00 */
+- 0xbd, 0x00, /* V-phase offset luma 01 */
+- 0xbe, 0x00, /* V-phase offset luma 10 */
+- 0xbf, 0x00, /* V-phase offset luma 11 */
++ R_A0_A_HORIZ_PRESCALING, 0x01,
++ R_A1_A_ACCUMULATION_LENGTH, 0x00,
++ R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
++
++ /* Configure controls at nominal value*/
++ R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
++ R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
++ R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
++
++ /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
++ R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
++ R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
++
++ R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
++
++ /* must be horiz lum scaling / 2 */
++ R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
++ R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
++
++ /* must be offset luma / 2 */
++ R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
++
++ R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
++ R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
++
++ R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
++ R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
++
++ R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
++
++ R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
++ R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
++ R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
++ R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
++
++ R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
++ R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
++ R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
++ R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
+
+ /* Task B */
+- 0xd0, 0x01, /* down scale = 1 */
+- 0xd1, 0x00, /* prescale accumulation length = 1 */
+- 0xd2, 0x00, /* dc gain and fir prefilter control */
+- 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */
+- 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+- 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+- 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+- 0xd9, 0x04,
+- 0xda, 0x00, /* H-phase offset Luma = 0 */
+- 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+- 0xdd, 0x02, /* H-scaling incr chroma */
+- 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
+-
+- 0xe0, 0x00, /* V-scaling incr luma low */
+- 0xe1, 0x04, /* " hi */
+- 0xe2, 0x00, /* V-scaling incr chroma low */
+- 0xe3, 0x04, /* " hi */
+- 0xe4, 0x01, /* V-scaling mode control */
+- 0xe8, 0x00, /* V-phase offset chroma 00 */
+- 0xe9, 0x00, /* V-phase offset chroma 01 */
+- 0xea, 0x00, /* V-phase offset chroma 10 */
+- 0xeb, 0x00, /* V-phase offset chroma 11 */
+- 0xec, 0x00, /* V-phase offset luma 00 */
+- 0xed, 0x00, /* V-phase offset luma 01 */
+- 0xee, 0x00, /* V-phase offset luma 10 */
+- 0xef, 0x00, /* V-phase offset luma 11 */
+-
+- 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
+- 0xf3, 0x46,
+- 0xf4, 0x00,
+- 0xf7, 0x4b, /* not the recommended settings! */
+- 0xf8, 0x00,
+- 0xf9, 0x4b,
+- 0xfa, 0x00,
+- 0xfb, 0x4b,
+- 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */
++ R_D0_B_HORIZ_PRESCALING, 0x01,
++ R_D1_B_ACCUMULATION_LENGTH, 0x00,
++ R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
++
++ /* Configure controls at nominal value*/
++ R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
++ R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
++ R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
++
++ /* hor lum scaling 0x0400 = 1 */
++ R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
++ R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
++
++ R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
++
++ /* must be hor lum scaling / 2 */
++ R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
++ R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
++
++ /* must be offset luma / 2 */
++ R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
++
++ R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
++ R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
++
++ R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
++ R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
++
++ R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
++
++ R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
++ R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
++ R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
++ R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
++
++ R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
++ R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
++ R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
++ R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
++
++ R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
++ R_F3_PLL_INCREMENT, 0x46,
++ R_F4_PLL2_STATUS, 0x00,
++ R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
++ R_F8_PULSE_B_POS, 0x00,
++ R_F9_PULSE_B_POS_MSB, 0x4b,
++ R_FA_PULSE_C_POS, 0x00,
++ R_FB_PULSE_C_POS_MSB, 0x4b,
++
++ /* PLL2 lock detection settings: 71 lines 50% phase error */
++ R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
+
+ /* Turn off VBI */
+- 0x40, 0x20, /* No framing code errors allowed. */
+- 0x41, 0xff,
+- 0x42, 0xff,
+- 0x43, 0xff,
+- 0x44, 0xff,
+- 0x45, 0xff,
+- 0x46, 0xff,
+- 0x47, 0xff,
+- 0x48, 0xff,
+- 0x49, 0xff,
+- 0x4a, 0xff,
+- 0x4b, 0xff,
+- 0x4c, 0xff,
+- 0x4d, 0xff,
+- 0x4e, 0xff,
+- 0x4f, 0xff,
+- 0x50, 0xff,
+- 0x51, 0xff,
+- 0x52, 0xff,
+- 0x53, 0xff,
+- 0x54, 0xff,
+- 0x55, 0xff,
+- 0x56, 0xff,
+- 0x57, 0xff,
+- 0x58, 0x40,
+- 0x59, 0x47,
+- 0x5b, 0x83,
+- 0x5d, 0xbd,
+- 0x5e, 0x35,
+-
+- 0x02, 0x84, /* input tuner -> input 4, amplifier active */
+- 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
+-
+- 0x80, 0x20, /* enable task B */
+- 0x88, 0xd0,
+- 0x88, 0xf0,
++ R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
++ R_41_LCR_BASE, 0xff,
++ R_41_LCR_BASE+1, 0xff,
++ R_41_LCR_BASE+2, 0xff,
++ R_41_LCR_BASE+3, 0xff,
++ R_41_LCR_BASE+4, 0xff,
++ R_41_LCR_BASE+5, 0xff,
++ R_41_LCR_BASE+6, 0xff,
++ R_41_LCR_BASE+7, 0xff,
++ R_41_LCR_BASE+8, 0xff,
++ R_41_LCR_BASE+9, 0xff,
++ R_41_LCR_BASE+10, 0xff,
++ R_41_LCR_BASE+11, 0xff,
++ R_41_LCR_BASE+12, 0xff,
++ R_41_LCR_BASE+13, 0xff,
++ R_41_LCR_BASE+14, 0xff,
++ R_41_LCR_BASE+15, 0xff,
++ R_41_LCR_BASE+16, 0xff,
++ R_41_LCR_BASE+17, 0xff,
++ R_41_LCR_BASE+18, 0xff,
++ R_41_LCR_BASE+19, 0xff,
++ R_41_LCR_BASE+20, 0xff,
++ R_41_LCR_BASE+21, 0xff,
++ R_41_LCR_BASE+22, 0xff,
++ R_58_PROGRAM_FRAMING_CODE, 0x40,
++ R_59_H_OFF_FOR_SLICER, 0x47,
++ R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
++ R_5D_DID, 0xbd,
++ R_5E_SDID, 0x35,
++
++ R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
++
++ R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
++ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
+ 0x00, 0x00
+ };
+
+-static int saa7115_odd_parity(u8 c)
++static int saa711x_odd_parity(u8 c)
+ {
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+@@ -502,7 +599,7 @@ static int saa7115_odd_parity(u8 c)
+ return c & 1;
+ }
+
+-static int saa7115_decode_vps(u8 * dst, u8 * p)
++static int saa711x_decode_vps(u8 * dst, u8 * p)
+ {
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+@@ -549,7 +646,7 @@ static int saa7115_decode_vps(u8 * dst,
+ return err & 0xf0;
+ }
+
+-static int saa7115_decode_wss(u8 * p)
++static int saa711x_decode_wss(u8 * p)
+ {
+ static const int wss_bits[8] = {
+ 0, 0, 0, 1, 0, 1, 1, 1
+@@ -576,26 +673,25 @@ static int saa7115_decode_wss(u8 * p)
+ return wss;
+ }
+
+-
+-static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
++static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ u32 acpf;
+ u32 acni;
+ u32 hz;
+ u64 f;
+ u8 acc = 0; /* reg 0x3a, audio clock control */
+
++ /* Checks for chips that don't have audio clock (saa7111, saa7113) */
++ if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
++ return 0;
++
+ v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
+
+ /* sanity check */
+ if (freq < 32000 || freq > 48000)
+ return -EINVAL;
+
+- /* The saa7113 has no audio clock */
+- if (state->ident == V4L2_IDENT_SAA7113)
+- return 0;
+-
+ /* hz is the refresh rate times 100 */
+ hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
+ /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
+@@ -617,22 +713,26 @@ static int saa7115_set_audio_clock_freq(
+ if (state->apll)
+ acc |= 0x08;
+
+- saa7115_write(client, 0x38, 0x03);
+- saa7115_write(client, 0x39, 0x10);
+- saa7115_write(client, 0x3a, acc);
+- saa7115_write(client, 0x30, acpf & 0xff);
+- saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
+- saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
+- saa7115_write(client, 0x34, acni & 0xff);
+- saa7115_write(client, 0x35, (acni >> 8) & 0xff);
+- saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
++ saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
++ saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
++ saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
++
++ saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
++ saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
++ (acpf >> 8) & 0xff);
++ saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
++ (acpf >> 16) & 0x03);
++
++ saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
++ saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
++ saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
+ state->audclk_freq = freq;
+ return 0;
+ }
+
+-static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
++static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+@@ -642,7 +742,7 @@ static int saa7115_set_v4lctrl(struct i2
+ }
+
+ state->bright = ctrl->value;
+- saa7115_write(client, 0x0a, state->bright);
++ saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
+ break;
+
+ case V4L2_CID_CONTRAST:
+@@ -652,7 +752,7 @@ static int saa7115_set_v4lctrl(struct i2
+ }
+
+ state->contrast = ctrl->value;
+- saa7115_write(client, 0x0b, state->contrast);
++ saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
+ break;
+
+ case V4L2_CID_SATURATION:
+@@ -662,7 +762,7 @@ static int saa7115_set_v4lctrl(struct i2
+ }
+
+ state->sat = ctrl->value;
+- saa7115_write(client, 0x0c, state->sat);
++ saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
+ break;
+
+ case V4L2_CID_HUE:
+@@ -672,7 +772,7 @@ static int saa7115_set_v4lctrl(struct i2
+ }
+
+ state->hue = ctrl->value;
+- saa7115_write(client, 0x0d, state->hue);
++ saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
+ break;
+
+ default:
+@@ -682,9 +782,9 @@ static int saa7115_set_v4lctrl(struct i2
+ return 0;
+ }
+
+-static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
++static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+@@ -706,10 +806,115 @@ static int saa7115_get_v4lctrl(struct i2
+ return 0;
+ }
+
+-static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
++static int saa711x_set_size(struct i2c_client *client, int width, int height)
++{
++ struct saa711x_state *state = i2c_get_clientdata(client);
++ int HPSC, HFSC;
++ int VSCY;
++ int res;
++ int is_50hz = state->std & V4L2_STD_625_50;
++ int Vsrc = is_50hz ? 576 : 480;
++
++ v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
++
++ /* FIXME need better bounds checking here */
++ if ((width < 1) || (width > 1440))
++ return -EINVAL;
++ if ((height < 1) || (height > Vsrc))
++ return -EINVAL;
++
++ if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
++ /* Decoder only supports 720 columns and 480 or 576 lines */
++ if (width != 720)
++ return -EINVAL;
++ if (height != Vsrc)
++ return -EINVAL;
++ }
++
++ state->width = width;
++ state->height = height;
++
++ if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
++ return 0;
++
++ /* probably have a valid size, let's set it */
++ /* Set output width/height */
++ /* width */
++
++ saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
++ (u8) (width & 0xff));
++ saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
++ (u8) ((width >> 8) & 0xff));
++
++ /* Vertical Scaling uses height/2 */
++ res=height/2;
++
++ /* On 60Hz, it is using a higher Vertical Output Size */
++ if (!is_50hz)
++ res+=(VRES_60HZ-480)>>1;
++
++ /* height */
++ saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
++ (u8) (res & 0xff));
++ saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
++ (u8) ((res >> 8) & 0xff));
++
++ /* Scaling settings */
++ /* Hprescaler is floor(inres/outres) */
++ HPSC = (int)(720 / width);
++ /* 0 is not allowed (div. by zero) */
++ HPSC = HPSC ? HPSC : 1;
++ HFSC = (int)((1024 * 720) / (HPSC * width));
++ /* FIXME hardcodes to "Task B"
++ * write H prescaler integer */
++ saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
++ (u8) (HPSC & 0x3f));
++
++ v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
++ /* write H fine-scaling (luminance) */
++ saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
++ (u8) (HFSC & 0xff));
++ saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
++ (u8) ((HFSC >> 8) & 0xff));
++ /* write H fine-scaling (chrominance)
++ * must be lum/2, so i'll just bitshift :) */
++ saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
++ (u8) ((HFSC >> 1) & 0xff));
++ saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
++ (u8) ((HFSC >> 9) & 0xff));
++
++ VSCY = (int)((1024 * Vsrc) / height);
++ v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
++
++ /* Correct Contrast and Luminance */
++ saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
++ (u8) (64 * 1024 / VSCY));
++ saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
++ (u8) (64 * 1024 / VSCY));
++
++ /* write V fine-scaling (luminance) */
++ saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
++ (u8) (VSCY & 0xff));
++ saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
++ (u8) ((VSCY >> 8) & 0xff));
++ /* write V fine-scaling (chrominance) */
++ saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
++ (u8) (VSCY & 0xff));
++ saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
++ (u8) ((VSCY >> 8) & 0xff));
++
++ saa711x_writeregs(client, saa7115_cfg_reset_scaler);
++
++ /* Activates task "B" */
++ saa711x_write(client, R_80_GLOBAL_CNTL_1,
++ saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20);
++
++ return 0;
++}
++
++static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
+- int taskb = saa7115_read(client, 0x80) & 0x10;
++ struct saa711x_state *state = i2c_get_clientdata(client);
+
+ /* Prevent unnecessary standard changes. During a standard
+ change the I-Port is temporarily disabled. Any devices
+@@ -721,17 +926,21 @@ static void saa7115_set_v4lstd(struct i2
+ if (std == state->std)
+ return;
+
++ state->std = std;
++
+ // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
+ if (std & V4L2_STD_525_60) {
+ v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
+- saa7115_writeregs(client, saa7115_cfg_60hz_video);
++ saa711x_writeregs(client, saa7115_cfg_60hz_video);
++ saa711x_set_size(client,720,480);
+ } else {
+ v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
+- saa7115_writeregs(client, saa7115_cfg_50hz_video);
++ saa711x_writeregs(client, saa7115_cfg_50hz_video);
++ saa711x_set_size(client,720,576);
+ }
+
+ /* Register 0E - Bits D6-D4 on NO-AUTO mode
+- (SAA7113 doesn't have auto mode)
++ (SAA7111 and SAA7113 doesn't have auto mode)
+ 50 Hz / 625 lines 60 Hz / 525 lines
+ 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
+ 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
+@@ -739,8 +948,9 @@ static void saa7115_set_v4lstd(struct i2
+ 011 NTSC N (3.58MHz) PAL M (3.58MHz)
+ 100 reserved NTSC-Japan (3.58MHz)
+ */
+- if (state->ident == V4L2_IDENT_SAA7113) {
+- u8 reg = saa7115_read(client, 0x0e) & 0x8f;
++ if (state->ident == V4L2_IDENT_SAA7111 ||
++ state->ident == V4L2_IDENT_SAA7113) {
++ u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
+
+ if (std == V4L2_STD_PAL_M) {
+ reg |= 0x30;
+@@ -750,32 +960,33 @@ static void saa7115_set_v4lstd(struct i2
+ reg |= 0x10;
+ } else if (std == V4L2_STD_NTSC_M_JP) {
+ reg |= 0x40;
++ } else if (std == V4L2_STD_SECAM) {
++ reg |= 0x50;
+ }
+- saa7115_write(client, 0x0e, reg);
+- }
+-
++ saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
++ } else {
++ /* restart task B if needed */
++ int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
+
+- state->std = std;
++ if (taskb && state->ident == V4L2_IDENT_SAA7114) {
++ saa711x_writeregs(client, saa7115_cfg_vbi_on);
++ }
+
+- /* restart task B if needed */
+- if (taskb && state->ident != V4L2_IDENT_SAA7115) {
+- saa7115_writeregs(client, saa7115_cfg_vbi_on);
++ /* switch audio mode too! */
++ saa711x_set_audio_clock_freq(client, state->audclk_freq);
+ }
+-
+- /* switch audio mode too! */
+- saa7115_set_audio_clock_freq(client, state->audclk_freq);
+ }
+
+-static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
++static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+
+ return state->std;
+ }
+
+-static void saa7115_log_status(struct i2c_client *client)
++static void saa711x_log_status(struct i2c_client *client)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ int reg1e, reg1f;
+ int signalOk;
+ int vcr;
+@@ -783,7 +994,7 @@ static void saa7115_log_status(struct i2
+ v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
+ if (state->ident != V4L2_IDENT_SAA7115) {
+ /* status for the saa7114 */
+- reg1f = saa7115_read(client, 0x1f);
++ reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
+ signalOk = (reg1f & 0xc1) == 0x81;
+ v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
+ v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
+@@ -791,8 +1002,8 @@ static void saa7115_log_status(struct i2
+ }
+
+ /* status for the saa7115 */
+- reg1e = saa7115_read(client, 0x1e);
+- reg1f = saa7115_read(client, 0x1f);
++ reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
++ reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
+
+ signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+ vcr = !(reg1f & 0x10);
+@@ -819,19 +1030,27 @@ static void saa7115_log_status(struct i2
+ v4l_info(client, "Detected format: BW/No color\n");
+ break;
+ }
++ v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
+ }
+
+ /* setup the sliced VBI lcr registers according to the sliced VBI format */
+-static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
++static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ int is_50hz = (state->std & V4L2_STD_625_50);
+ u8 lcr[24];
+ int i, x;
+
+- /* saa7113/7114 doesn't yet support VBI */
++#if 1
++ /* saa7113/7114/7118 VBI support are experimental */
++ if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
++ return;
++
++#else
++ /* SAA7113 and SAA7118 also should support VBI - Need testing */
+ if (state->ident != V4L2_IDENT_SAA7115)
+ return;
++#endif
+
+ for (i = 0; i <= 23; i++)
+ lcr[i] = 0xff;
+@@ -888,14 +1107,16 @@ static void saa7115_set_lcr(struct i2c_c
+
+ /* write the lcr registers */
+ for (i = 2; i <= 23; i++) {
+- saa7115_write(client, i - 2 + 0x41, lcr[i]);
++ saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
+ }
+
+ /* enable/disable raw VBI capturing */
+- saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
++ saa711x_writeregs(client, fmt->service_set == 0 ?
++ saa7115_cfg_vbi_on :
++ saa7115_cfg_vbi_off);
+ }
+
+-static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
++static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+ {
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+@@ -911,10 +1132,10 @@ static int saa7115_get_v4lfmt(struct i2c
+ return -EINVAL;
+ memset(sliced, 0, sizeof(*sliced));
+ /* done if using raw VBI */
+- if (saa7115_read(client, 0x80) & 0x10)
++ if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
+ return 0;
+ for (i = 2; i <= 23; i++) {
+- u8 v = saa7115_read(client, i - 2 + 0x41);
++ u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
+
+ sliced->service_lines[0][i] = lcr2vbi[v >> 4];
+ sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
+@@ -924,114 +1145,31 @@ static int saa7115_get_v4lfmt(struct i2c
+ return 0;
+ }
+
+-static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
++static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
+- struct v4l2_pix_format *pix;
+- int HPSC, HFSC;
+- int VSCY, Vsrc;
+- int is_50hz = state->std & V4L2_STD_625_50;
+-
+ if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+- saa7115_set_lcr(client, &fmt->fmt.sliced);
++ saa711x_set_lcr(client, &fmt->fmt.sliced);
+ return 0;
+ }
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+- pix = &(fmt->fmt.pix);
+-
+- v4l_dbg(1, debug, client, "decoder set size\n");
+-
+- /* FIXME need better bounds checking here */
+- if ((pix->width < 1) || (pix->width > 1440))
+- return -EINVAL;
+- if ((pix->height < 1) || (pix->height > 960))
+- return -EINVAL;
+-
+- /* probably have a valid size, let's set it */
+- /* Set output width/height */
+- /* width */
+- saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
+- saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
+- /* height */
+- saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
+- saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
+-
+- /* Scaling settings */
+- /* Hprescaler is floor(inres/outres) */
+- /* FIXME hardcoding input res */
+- if (pix->width != 720) {
+- HPSC = (int)(720 / pix->width);
+- /* 0 is not allowed (div. by zero) */
+- HPSC = HPSC ? HPSC : 1;
+- HFSC = (int)((1024 * 720) / (HPSC * pix->width));
+-
+- v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+- /* FIXME hardcodes to "Task B"
+- * write H prescaler integer */
+- saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
+-
+- /* write H fine-scaling (luminance) */
+- saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
+- saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
+- /* write H fine-scaling (chrominance)
+- * must be lum/2, so i'll just bitshift :) */
+- saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
+- saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
+- } else {
+- if (is_50hz) {
+- v4l_dbg(1, debug, client, "Setting full 50hz width\n");
+- saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
+- } else {
+- v4l_dbg(1, debug, client, "Setting full 60hz width\n");
+- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+- }
+- }
+-
+- Vsrc = is_50hz ? 576 : 480;
+-
+- if (pix->height != Vsrc) {
+- VSCY = (int)((1024 * Vsrc) / pix->height);
+- v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+-
+- /* Correct Contrast and Luminance */
+- saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
+- saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
+-
+- /* write V fine-scaling (luminance) */
+- saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
+- saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
+- /* write V fine-scaling (chrominance) */
+- saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
+- saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
+- } else {
+- if (is_50hz) {
+- v4l_dbg(1, debug, client, "Setting full 50Hz height\n");
+- saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
+- } else {
+- v4l_dbg(1, debug, client, "Setting full 60hz height\n");
+- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+- }
+- }
+-
+- saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+- return 0;
++ return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
+ }
+
+ /* Decode the sliced VBI data stream as created by the saa7115.
+ The format is described in the saa7115 datasheet in Tables 25 and 26
+ and in Figure 33.
+ The current implementation uses SAV/EAV codes and not the ancillary data
+- headers. The vbi->p pointer points to the SDID byte right after the SAV
++ headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
+ code. */
+-static void saa7115_decode_vbi_line(struct i2c_client *client,
++static void saa711x_decode_vbi_line(struct i2c_client *client,
+ struct v4l2_decode_vbi_line *vbi)
+ {
+ static const char vbi_no_data_pattern[] = {
+ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
+ };
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ u8 *p = vbi->p;
+ u32 wss;
+ int id1, id2; /* the ID1 and ID2 bytes from the internal header */
+@@ -1066,12 +1204,12 @@ static void saa7115_decode_vbi_line(stru
+ vbi->type = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+- if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
++ if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
+ return;
+ vbi->type = V4L2_SLICED_CAPTION_525;
+ break;
+ case 5:
+- wss = saa7115_decode_wss(p);
++ wss = saa711x_decode_wss(p);
+ if (wss == -1)
+ return;
+ p[0] = wss & 0xff;
+@@ -1079,7 +1217,7 @@ static void saa7115_decode_vbi_line(stru
+ vbi->type = V4L2_SLICED_WSS_625;
+ break;
+ case 7:
+- if (saa7115_decode_vps(p, p) != 0)
++ if (saa711x_decode_vps(p, p) != 0)
+ return;
+ vbi->type = V4L2_SLICED_VPS;
+ break;
+@@ -1090,21 +1228,21 @@ static void saa7115_decode_vbi_line(stru
+
+ /* ============ SAA7115 AUDIO settings (end) ============= */
+
+-static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ int *iarg = arg;
+
+ /* ioctls to allow direct access to the saa7115 registers for testing */
+ switch (cmd) {
+ case VIDIOC_S_FMT:
+- return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
++ return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
+
+ case VIDIOC_G_FMT:
+- return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
++ return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+- return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
++ return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
+
+ case VIDIOC_G_TUNER:
+ {
+@@ -1113,7 +1251,7 @@ static int saa7115_command(struct i2c_cl
+
+ if (state->radio)
+ break;
+- status = saa7115_read(client, 0x1f);
++ status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
+
+ v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
+ vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+@@ -1121,14 +1259,14 @@ static int saa7115_command(struct i2c_cl
+ }
+
+ case VIDIOC_LOG_STATUS:
+- saa7115_log_status(client);
++ saa711x_log_status(client);
+ break;
+
+ case VIDIOC_G_CTRL:
+- return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
++ return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+- return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
++ return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL:
+ {
+@@ -1146,12 +1284,12 @@ static int saa7115_command(struct i2c_cl
+ }
+
+ case VIDIOC_G_STD:
+- *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
++ *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
+ break;
+
+ case VIDIOC_S_STD:
+ state->radio = 0;
+- saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
++ saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
+ break;
+
+ case AUDC_SET_RADIO:
+@@ -1187,13 +1325,13 @@ static int saa7115_command(struct i2c_cl
+ state->input = route->input;
+
+ /* select mode */
+- saa7115_write(client, 0x02,
+- (saa7115_read(client, 0x02) & 0xf0) |
++ saa711x_write(client, R_02_INPUT_CNTL_1,
++ (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
+ state->input);
+
+ /* bypass chrominance trap for S-Video modes */
+- saa7115_write(client, 0x09,
+- (saa7115_read(client, 0x09) & 0x7f) |
++ saa711x_write(client, R_09_LUMA_CNTL,
++ (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
+ (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+ break;
+ }
+@@ -1205,7 +1343,9 @@ static int saa7115_command(struct i2c_cl
+
+ if (state->enable != (cmd == VIDIOC_STREAMON)) {
+ state->enable = (cmd == VIDIOC_STREAMON);
+- saa7115_write(client, 0x87, state->enable);
++ saa711x_write(client,
++ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
++ state->enable);
+ }
+ break;
+
+@@ -1220,17 +1360,17 @@ static int saa7115_command(struct i2c_cl
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+- saa7115_set_audio_clock_freq(client, state->audclk_freq);
++ saa711x_set_audio_clock_freq(client, state->audclk_freq);
+ break;
+ }
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+- saa7115_decode_vbi_line(client, arg);
++ saa711x_decode_vbi_line(client, arg);
+ break;
+
+ case VIDIOC_INT_RESET:
+ v4l_dbg(1, debug, client, "decoder RESET\n");
+- saa7115_writeregs(client, saa7115_cfg_reset_scaler);
++ saa711x_writeregs(client, saa7115_cfg_reset_scaler);
+ break;
+
+ case VIDIOC_INT_G_VBI_DATA:
+@@ -1239,25 +1379,25 @@ static int saa7115_command(struct i2c_cl
+
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+- if (saa7115_read(client, 0x6b) & 0xc0)
++ if (saa711x_read(client, 0x6b) & 0xc0)
+ return -EIO;
+- data->data[0] = saa7115_read(client, 0x6c);
+- data->data[1] = saa7115_read(client, 0x6d);
++ data->data[0] = saa711x_read(client, 0x6c);
++ data->data[1] = saa711x_read(client, 0x6d);
+ return 0;
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0) {
+ /* CC */
+- if (saa7115_read(client, 0x66) & 0xc0)
++ if (saa711x_read(client, 0x66) & 0xc0)
+ return -EIO;
+- data->data[0] = saa7115_read(client, 0x67);
+- data->data[1] = saa7115_read(client, 0x68);
++ data->data[0] = saa711x_read(client, 0x67);
++ data->data[1] = saa711x_read(client, 0x68);
+ return 0;
+ }
+ /* XDS */
+- if (saa7115_read(client, 0x66) & 0x30)
++ if (saa711x_read(client, 0x66) & 0x30)
+ return -EIO;
+- data->data[0] = saa7115_read(client, 0x69);
+- data->data[1] = saa7115_read(client, 0x6a);
++ data->data[0] = saa711x_read(client, 0x69);
++ data->data[1] = saa711x_read(client, 0x6a);
+ return 0;
+ default:
+ return -EINVAL;
+@@ -1272,7 +1412,7 @@ static int saa7115_command(struct i2c_cl
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+ return -EINVAL;
+- reg->val = saa7115_read(client, reg->reg & 0xff);
++ reg->val = saa711x_read(client, reg->reg & 0xff);
+ break;
+ }
+
+@@ -1284,7 +1424,7 @@ static int saa7115_command(struct i2c_cl
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+- saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
++ saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
+ break;
+ }
+ #endif
+@@ -1302,12 +1442,14 @@ static int saa7115_command(struct i2c_cl
+
+ /* ----------------------------------------------------------------------- */
+
+-static struct i2c_driver i2c_driver_saa7115;
++static struct i2c_driver i2c_driver_saa711x;
+
+-static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
++static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
+ {
+ struct i2c_client *client;
+- struct saa7115_state *state;
++ struct saa711x_state *state;
++ int i;
++ char name[17];
+ u8 chip_id;
+
+ /* Check if the adapter supports the needed features */
+@@ -1319,28 +1461,31 @@ static int saa7115_attach(struct i2c_ada
+ return -ENOMEM;
+ client->addr = address;
+ client->adapter = adapter;
+- client->driver = &i2c_driver_saa7115;
++ client->driver = &i2c_driver_saa711x;
+ snprintf(client->name, sizeof(client->name) - 1, "saa7115");
+
+ v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
+
+- saa7115_write(client, 0, 5);
+- chip_id = saa7115_read(client, 0) & 0x0f;
+- if (chip_id < 3 && chip_id > 5) {
+- v4l_dbg(1, debug, client, "saa7115 not found\n");
+- kfree(client);
+- return 0;
++ for (i=0;i<0x0f;i++) {
++ saa711x_write(client, 0, i);
++ name[i] = (saa711x_read(client, 0) &0x0f) +'0';
++ if (name[i]>'9')
++ name[i]+='a'-'9'-1;
+ }
++ name[i]='\0';
++
++ saa711x_write(client, 0, 5);
++ chip_id = saa711x_read(client, 0) & 0x0f;
++
+ snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
+- v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
++ v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
+
+- state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
++ state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
+ i2c_set_clientdata(client, state);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+- state->std = V4L2_STD_NTSC;
+ state->input = -1;
+ state->enable = 1;
+ state->radio = 0;
+@@ -1349,15 +1494,25 @@ static int saa7115_attach(struct i2c_ada
+ state->hue = 0;
+ state->sat = 64;
+ switch (chip_id) {
++ case 1:
++ state->ident = V4L2_IDENT_SAA7111;
++ break;
+ case 3:
+ state->ident = V4L2_IDENT_SAA7113;
+ break;
+ case 4:
+ state->ident = V4L2_IDENT_SAA7114;
+ break;
+- default:
++ case 5:
+ state->ident = V4L2_IDENT_SAA7115;
+ break;
++ case 8:
++ state->ident = V4L2_IDENT_SAA7118;
++ break;
++ default:
++ state->ident = V4L2_IDENT_SAA7111;
++ v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
++
+ }
+
+ state->audclk_freq = 48000;
+@@ -1365,38 +1520,39 @@ static int saa7115_attach(struct i2c_ada
+ v4l_dbg(1, debug, client, "writing init values\n");
+
+ /* init to 60hz/48khz */
+- if (state->ident == V4L2_IDENT_SAA7113) {
+- state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
+- saa7115_writeregs(client, saa7113_init_auto_input);
+- } else {
++ state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
++ switch (state->ident) {
++ case V4L2_IDENT_SAA7111:
++ saa711x_writeregs(client, saa7111_init);
++ break;
++ case V4L2_IDENT_SAA7113:
++ saa711x_writeregs(client, saa7113_init);
++ break;
++ default:
+ state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
+- saa7115_writeregs(client, saa7115_init_auto_input);
++ saa711x_writeregs(client, saa7115_init_auto_input);
+ }
+- saa7115_writeregs(client, saa7115_init_misc);
+- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+- saa7115_writeregs(client, saa7115_cfg_60hz_video);
+- saa7115_set_audio_clock_freq(client, state->audclk_freq);
+- saa7115_writeregs(client, saa7115_cfg_reset_scaler);
++ saa711x_writeregs(client, saa7115_init_misc);
++ saa711x_set_v4lstd(client, V4L2_STD_NTSC);
+
+ i2c_attach_client(client);
+
+ v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
+- saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
++ saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
+
+ return 0;
+ }
+
+-static int saa7115_probe(struct i2c_adapter *adapter)
++static int saa711x_probe(struct i2c_adapter *adapter)
+ {
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+- return i2c_probe(adapter, &addr_data, &saa7115_attach);
++ return i2c_probe(adapter, &addr_data, &saa711x_attach);
+ return 0;
+ }
+
+-static int saa7115_detach(struct i2c_client *client)
++static int saa711x_detach(struct i2c_client *client)
+ {
+- struct saa7115_state *state = i2c_get_clientdata(client);
++ struct saa711x_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+@@ -1412,26 +1568,26 @@ static int saa7115_detach(struct i2c_cli
+ /* ----------------------------------------------------------------------- */
+
+ /* i2c implementation */
+-static struct i2c_driver i2c_driver_saa7115 = {
++static struct i2c_driver i2c_driver_saa711x = {
+ .driver = {
+ .name = "saa7115",
+ },
+ .id = I2C_DRIVERID_SAA711X,
+- .attach_adapter = saa7115_probe,
+- .detach_client = saa7115_detach,
+- .command = saa7115_command,
++ .attach_adapter = saa711x_probe,
++ .detach_client = saa711x_detach,
++ .command = saa711x_command,
+ };
+
+
+-static int __init saa7115_init_module(void)
++static int __init saa711x_init_module(void)
+ {
+- return i2c_add_driver(&i2c_driver_saa7115);
++ return i2c_add_driver(&i2c_driver_saa711x);
+ }
+
+-static void __exit saa7115_cleanup_module(void)
++static void __exit saa711x_cleanup_module(void)
+ {
+- i2c_del_driver(&i2c_driver_saa7115);
++ i2c_del_driver(&i2c_driver_saa711x);
+ }
+
+-module_init(saa7115_init_module);
+-module_exit(saa7115_cleanup_module);
++module_init(saa711x_init_module);
++module_exit(saa711x_cleanup_module);
+diff --git a/drivers/media/video/saa711x_regs.h b/drivers/media/video/saa711x_regs.h
+new file mode 100644
+index 0000000..4e5f2eb
+--- /dev/null
++++ b/drivers/media/video/saa711x_regs.h
+@@ -0,0 +1,549 @@
++/* saa711x - Philips SAA711x video decoder register specifications
++ *
++ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.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 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.
++ */
++
++#define R_00_CHIP_VERSION 0x00
++/* Video Decoder */
++ /* Video Decoder - Frontend part */
++#define R_01_INC_DELAY 0x01
++#define R_02_INPUT_CNTL_1 0x02
++#define R_03_INPUT_CNTL_2 0x03
++#define R_04_INPUT_CNTL_3 0x04
++#define R_05_INPUT_CNTL_4 0x05
++ /* Video Decoder - Decoder part */
++#define R_06_H_SYNC_START 0x06
++#define R_07_H_SYNC_STOP 0x07
++#define R_08_SYNC_CNTL 0x08
++#define R_09_LUMA_CNTL 0x09
++#define R_0A_LUMA_BRIGHT_CNTL 0x0a
++#define R_0B_LUMA_CONTRAST_CNTL 0x0b
++#define R_0C_CHROMA_SAT_CNTL 0x0c
++#define R_0D_CHROMA_HUE_CNTL 0x0d
++#define R_0E_CHROMA_CNTL_1 0x0e
++#define R_0F_CHROMA_GAIN_CNTL 0x0f
++#define R_10_CHROMA_CNTL_2 0x10
++#define R_11_MODE_DELAY_CNTL 0x11
++#define R_12_RT_SIGNAL_CNTL 0x12
++#define R_13_RT_X_PORT_OUT_CNTL 0x13
++#define R_14_ANAL_ADC_COMPAT_CNTL 0x14
++#define R_15_VGATE_START_FID_CHG 0x15
++#define R_16_VGATE_STOP 0x16
++#define R_17_MISC_VGATE_CONF_AND_MSB 0x17
++#define R_18_RAW_DATA_GAIN_CNTL 0x18
++#define R_19_RAW_DATA_OFF_CNTL 0x19
++#define R_1A_COLOR_KILL_LVL_CNTL 0x1a
++#define R_1B_MISC_TVVCRDET 0x1b
++#define R_1C_ENHAN_COMB_CTRL1 0x1c
++#define R_1D_ENHAN_COMB_CTRL2 0x1d
++#define R_1E_STATUS_BYTE_1_VD_DEC 0x1e
++#define R_1F_STATUS_BYTE_2_VD_DEC 0x1f
++
++/* Component processing and interrupt masking part */
++#define R_23_INPUT_CNTL_5 0x23
++#define R_24_INPUT_CNTL_6 0x24
++#define R_25_INPUT_CNTL_7 0x25
++#define R_29_COMP_DELAY 0x29
++#define R_2A_COMP_BRIGHT_CNTL 0x2a
++#define R_2B_COMP_CONTRAST_CNTL 0x2b
++#define R_2C_COMP_SAT_CNTL 0x2c
++#define R_2D_INTERRUPT_MASK_1 0x2d
++#define R_2E_INTERRUPT_MASK_2 0x2e
++#define R_2F_INTERRUPT_MASK_3 0x2f
++
++/* Audio clock generator part */
++#define R_30_AUD_MAST_CLK_CYCLES_PER_FIELD 0x30
++#define R_34_AUD_MAST_CLK_NOMINAL_INC 0x34
++#define R_38_CLK_RATIO_AMXCLK_TO_ASCLK 0x38
++#define R_39_CLK_RATIO_ASCLK_TO_ALRCLK 0x39
++#define R_3A_AUD_CLK_GEN_BASIC_SETUP 0x3a
++
++/* General purpose VBI data slicer part */
++#define R_40_SLICER_CNTL_1 0x40
++#define R_41_LCR_BASE 0x41
++#define R_58_PROGRAM_FRAMING_CODE 0x58
++#define R_59_H_OFF_FOR_SLICER 0x59
++#define R_5A_V_OFF_FOR_SLICER 0x5a
++#define R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF 0x5b
++#define R_5D_DID 0x5d
++#define R_5E_SDID 0x5e
++#define R_60_SLICER_STATUS_BYTE_0 0x60
++#define R_61_SLICER_STATUS_BYTE_1 0x61
++#define R_62_SLICER_STATUS_BYTE_2 0x62
++
++/* X port, I port and the scaler part */
++ /* Task independent global settings */
++#define R_80_GLOBAL_CNTL_1 0x80
++#define R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F 0x81
++#define R_83_X_PORT_I_O_ENA_AND_OUT_CLK 0x83
++#define R_84_I_PORT_SIGNAL_DEF 0x84
++#define R_85_I_PORT_SIGNAL_POLAR 0x85
++#define R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT 0x86
++#define R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED 0x87
++#define R_88_POWER_SAVE_ADC_PORT_CNTL 0x88
++#define R_8F_STATUS_INFO_SCALER 0x8f
++ /* Task A definition */
++ /* Basic settings and acquisition window definition */
++#define R_90_A_TASK_HANDLING_CNTL 0x90
++#define R_91_A_X_PORT_FORMATS_AND_CONF 0x91
++#define R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL 0x92
++#define R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF 0x93
++#define R_94_A_HORIZ_INPUT_WINDOW_START 0x94
++#define R_95_A_HORIZ_INPUT_WINDOW_START_MSB 0x95
++#define R_96_A_HORIZ_INPUT_WINDOW_LENGTH 0x96
++#define R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB 0x97
++#define R_98_A_VERT_INPUT_WINDOW_START 0x98
++#define R_99_A_VERT_INPUT_WINDOW_START_MSB 0x99
++#define R_9A_A_VERT_INPUT_WINDOW_LENGTH 0x9a
++#define R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB 0x9b
++#define R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH 0x9c
++#define R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB 0x9d
++#define R_9E_A_VERT_OUTPUT_WINDOW_LENGTH 0x9e
++#define R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB 0x9f
++ /* FIR filtering and prescaling */
++#define R_A0_A_HORIZ_PRESCALING 0xa0
++#define R_A1_A_ACCUMULATION_LENGTH 0xa1
++#define R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER 0xa2
++#define R_A4_A_LUMA_BRIGHTNESS_CNTL 0xa4
++#define R_A5_A_LUMA_CONTRAST_CNTL 0xa5
++#define R_A6_A_CHROMA_SATURATION_CNTL 0xa6
++ /* Horizontal phase scaling */
++#define R_A8_A_HORIZ_LUMA_SCALING_INC 0xa8
++#define R_A9_A_HORIZ_LUMA_SCALING_INC_MSB 0xa9
++#define R_AA_A_HORIZ_LUMA_PHASE_OFF 0xaa
++#define R_AC_A_HORIZ_CHROMA_SCALING_INC 0xac
++#define R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB 0xad
++#define R_AE_A_HORIZ_CHROMA_PHASE_OFF 0xae
++#define R_AF_A_HORIZ_CHROMA_PHASE_OFF_MSB 0xaf
++ /* Vertical scaling */
++#define R_B0_A_VERT_LUMA_SCALING_INC 0xb0
++#define R_B1_A_VERT_LUMA_SCALING_INC_MSB 0xb1
++#define R_B2_A_VERT_CHROMA_SCALING_INC 0xb2
++#define R_B3_A_VERT_CHROMA_SCALING_INC_MSB 0xb3
++#define R_B4_A_VERT_SCALING_MODE_CNTL 0xb4
++#define R_B8_A_VERT_CHROMA_PHASE_OFF_00 0xb8
++#define R_B9_A_VERT_CHROMA_PHASE_OFF_01 0xb9
++#define R_BA_A_VERT_CHROMA_PHASE_OFF_10 0xba
++#define R_BB_A_VERT_CHROMA_PHASE_OFF_11 0xbb
++#define R_BC_A_VERT_LUMA_PHASE_OFF_00 0xbc
++#define R_BD_A_VERT_LUMA_PHASE_OFF_01 0xbd
++#define R_BE_A_VERT_LUMA_PHASE_OFF_10 0xbe
++#define R_BF_A_VERT_LUMA_PHASE_OFF_11 0xbf
++ /* Task B definition */
++ /* Basic settings and acquisition window definition */
++#define R_C0_B_TASK_HANDLING_CNTL 0xc0
++#define R_C1_B_X_PORT_FORMATS_AND_CONF 0xc1
++#define R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION 0xc2
++#define R_C3_B_I_PORT_FORMATS_AND_CONF 0xc3
++#define R_C4_B_HORIZ_INPUT_WINDOW_START 0xc4
++#define R_C5_B_HORIZ_INPUT_WINDOW_START_MSB 0xc5
++#define R_C6_B_HORIZ_INPUT_WINDOW_LENGTH 0xc6
++#define R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB 0xc7
++#define R_C8_B_VERT_INPUT_WINDOW_START 0xc8
++#define R_C9_B_VERT_INPUT_WINDOW_START_MSB 0xc9
++#define R_CA_B_VERT_INPUT_WINDOW_LENGTH 0xca
++#define R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB 0xcb
++#define R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH 0xcc
++#define R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB 0xcd
++#define R_CE_B_VERT_OUTPUT_WINDOW_LENGTH 0xce
++#define R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB 0xcf
++ /* FIR filtering and prescaling */
++#define R_D0_B_HORIZ_PRESCALING 0xd0
++#define R_D1_B_ACCUMULATION_LENGTH 0xd1
++#define R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER 0xd2
++#define R_D4_B_LUMA_BRIGHTNESS_CNTL 0xd4
++#define R_D5_B_LUMA_CONTRAST_CNTL 0xd5
++#define R_D6_B_CHROMA_SATURATION_CNTL 0xd6
++ /* Horizontal phase scaling */
++#define R_D8_B_HORIZ_LUMA_SCALING_INC 0xd8
++#define R_D9_B_HORIZ_LUMA_SCALING_INC_MSB 0xd9
++#define R_DA_B_HORIZ_LUMA_PHASE_OFF 0xda
++#define R_DC_B_HORIZ_CHROMA_SCALING 0xdc
++#define R_DD_B_HORIZ_CHROMA_SCALING_MSB 0xdd
++#define R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA 0xde
++ /* Vertical scaling */
++#define R_E0_B_VERT_LUMA_SCALING_INC 0xe0
++#define R_E1_B_VERT_LUMA_SCALING_INC_MSB 0xe1
++#define R_E2_B_VERT_CHROMA_SCALING_INC 0xe2
++#define R_E3_B_VERT_CHROMA_SCALING_INC_MSB 0xe3
++#define R_E4_B_VERT_SCALING_MODE_CNTL 0xe4
++#define R_E8_B_VERT_CHROMA_PHASE_OFF_00 0xe8
++#define R_E9_B_VERT_CHROMA_PHASE_OFF_01 0xe9
++#define R_EA_B_VERT_CHROMA_PHASE_OFF_10 0xea
++#define R_EB_B_VERT_CHROMA_PHASE_OFF_11 0xeb
++#define R_EC_B_VERT_LUMA_PHASE_OFF_00 0xec
++#define R_ED_B_VERT_LUMA_PHASE_OFF_01 0xed
++#define R_EE_B_VERT_LUMA_PHASE_OFF_10 0xee
++#define R_EF_B_VERT_LUMA_PHASE_OFF_11 0xef
++
++/* second PLL (PLL2) and Pulsegenerator Programming */
++#define R_F0_LFCO_PER_LINE 0xf0
++#define R_F1_P_I_PARAM_SELECT 0xf1
++#define R_F2_NOMINAL_PLL2_DTO 0xf2
++#define R_F3_PLL_INCREMENT 0xf3
++#define R_F4_PLL2_STATUS 0xf4
++#define R_F5_PULSGEN_LINE_LENGTH 0xf5
++#define R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG 0xf6
++#define R_F7_PULSE_A_POS_MSB 0xf7
++#define R_F8_PULSE_B_POS 0xf8
++#define R_F9_PULSE_B_POS_MSB 0xf9
++#define R_FA_PULSE_C_POS 0xfa
++#define R_FB_PULSE_C_POS_MSB 0xfb
++#define R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES 0xff
++
++#if 0
++/* Those structs will be used in the future for debug purposes */
++struct saa711x_reg_descr {
++ u8 reg;
++ int count;
++ char *name;
++};
++
++struct saa711x_reg_descr saa711x_regs[] = {
++ /* REG COUNT NAME */
++ {R_00_CHIP_VERSION,1,
++ "Chip version"},
++
++ /* Video Decoder: R_01_INC_DELAY to R_1F_STATUS_BYTE_2_VD_DEC */
++
++ /* Video Decoder - Frontend part: R_01_INC_DELAY to R_05_INPUT_CNTL_4 */
++ {R_01_INC_DELAY,1,
++ "Increment delay"},
++ {R_02_INPUT_CNTL_1,1,
++ "Analog input control 1"},
++ {R_03_INPUT_CNTL_2,1,
++ "Analog input control 2"},
++ {R_04_INPUT_CNTL_3,1,
++ "Analog input control 3"},
++ {R_05_INPUT_CNTL_4,1,
++ "Analog input control 4"},
++
++ /* Video Decoder - Decoder part: R_06_H_SYNC_START to R_1F_STATUS_BYTE_2_VD_DEC */
++ {R_06_H_SYNC_START,1,
++ "Horizontal sync start"},
++ {R_07_H_SYNC_STOP,1,
++ "Horizontal sync stop"},
++ {R_08_SYNC_CNTL,1,
++ "Sync control"},
++ {R_09_LUMA_CNTL,1,
++ "Luminance control"},
++ {R_0A_LUMA_BRIGHT_CNTL,1,
++ "Luminance brightness control"},
++ {R_0B_LUMA_CONTRAST_CNTL,1,
++ "Luminance contrast control"},
++ {R_0C_CHROMA_SAT_CNTL,1,
++ "Chrominance saturation control"},
++ {R_0D_CHROMA_HUE_CNTL,1,
++ "Chrominance hue control"},
++ {R_0E_CHROMA_CNTL_1,1,
++ "Chrominance control 1"},
++ {R_0F_CHROMA_GAIN_CNTL,1,
++ "Chrominance gain control"},
++ {R_10_CHROMA_CNTL_2,1,
++ "Chrominance control 2"},
++ {R_11_MODE_DELAY_CNTL,1,
++ "Mode/delay control"},
++ {R_12_RT_SIGNAL_CNTL,1,
++ "RT signal control"},
++ {R_13_RT_X_PORT_OUT_CNTL,1,
++ "RT/X port output control"},
++ {R_14_ANAL_ADC_COMPAT_CNTL,1,
++ "Analog/ADC/compatibility control"},
++ {R_15_VGATE_START_FID_CHG, 1,
++ "VGATE start FID change"},
++ {R_16_VGATE_STOP,1,
++ "VGATE stop"},
++ {R_17_MISC_VGATE_CONF_AND_MSB, 1,
++ "Miscellaneous VGATE configuration and MSBs"},
++ {R_18_RAW_DATA_GAIN_CNTL,1,
++ "Raw data gain control",},
++ {R_19_RAW_DATA_OFF_CNTL,1,
++ "Raw data offset control",},
++ {R_1A_COLOR_KILL_LVL_CNTL,1,
++ "Color Killer Level Control"},
++ { R_1B_MISC_TVVCRDET, 1,
++ "MISC /TVVCRDET"},
++ { R_1C_ENHAN_COMB_CTRL1, 1,
++ "Enhanced comb ctrl1"},
++ { R_1D_ENHAN_COMB_CTRL2, 1,
++ "Enhanced comb ctrl1"},
++ {R_1E_STATUS_BYTE_1_VD_DEC,1,
++ "Status byte 1 video decoder"},
++ {R_1F_STATUS_BYTE_2_VD_DEC,1,
++ "Status byte 2 video decoder"},
++
++ /* Component processing and interrupt masking part: 0x20h to R_2F_INTERRUPT_MASK_3 */
++ /* 0x20 to 0x22 - Reserved */
++ {R_23_INPUT_CNTL_5,1,
++ "Analog input control 5"},
++ {R_24_INPUT_CNTL_6,1,
++ "Analog input control 6"},
++ {R_25_INPUT_CNTL_7,1,
++ "Analog input control 7"},
++ /* 0x26 to 0x28 - Reserved */
++ {R_29_COMP_DELAY,1,
++ "Component delay"},
++ {R_2A_COMP_BRIGHT_CNTL,1,
++ "Component brightness control"},
++ {R_2B_COMP_CONTRAST_CNTL,1,
++ "Component contrast control"},
++ {R_2C_COMP_SAT_CNTL,1,
++ "Component saturation control"},
++ {R_2D_INTERRUPT_MASK_1,1,
++ "Interrupt mask 1"},
++ {R_2E_INTERRUPT_MASK_2,1,
++ "Interrupt mask 2"},
++ {R_2F_INTERRUPT_MASK_3,1,
++ "Interrupt mask 3"},
++
++ /* Audio clock generator part: R_30_AUD_MAST_CLK_CYCLES_PER_FIELD to 0x3f */
++ {R_30_AUD_MAST_CLK_CYCLES_PER_FIELD,3,
++ "Audio master clock cycles per field"},
++ /* 0x33 - Reserved */
++ {R_34_AUD_MAST_CLK_NOMINAL_INC,3,
++ "Audio master clock nominal increment"},
++ /* 0x37 - Reserved */
++ {R_38_CLK_RATIO_AMXCLK_TO_ASCLK,1,
++ "Clock ratio AMXCLK to ASCLK"},
++ {R_39_CLK_RATIO_ASCLK_TO_ALRCLK,1,
++ "Clock ratio ASCLK to ALRCLK"},
++ {R_3A_AUD_CLK_GEN_BASIC_SETUP,1,
++ "Audio clock generator basic setup"},
++ /* 0x3b-0x3f - Reserved */
++
++ /* General purpose VBI data slicer part: R_40_SLICER_CNTL_1 to 0x7f */
++ {R_40_SLICER_CNTL_1,1,
++ "Slicer control 1"},
++ {R_41_LCR,23,
++ "R_41_LCR"},
++ {R_58_PROGRAM_FRAMING_CODE,1,
++ "Programmable framing code"},
++ {R_59_H_OFF_FOR_SLICER,1,
++ "Horizontal offset for slicer"},
++ {R_5A_V_OFF_FOR_SLICER,1,
++ "Vertical offset for slicer"},
++ {R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF,1,
++ "Field offset and MSBs for horizontal and vertical offset"},
++ {R_5D_DID,1,
++ "Header and data identification (R_5D_DID)"},
++ {R_5E_SDID,1,
++ "Sliced data identification (R_5E_SDID) code"},
++ {R_60_SLICER_STATUS_BYTE_0,1,
++ "Slicer status byte 0"},
++ {R_61_SLICER_STATUS_BYTE_1,1,
++ "Slicer status byte 1"},
++ {R_62_SLICER_STATUS_BYTE_2,1,
++ "Slicer status byte 2"},
++ /* 0x63-0x7f - Reserved */
++
++ /* X port, I port and the scaler part: R_80_GLOBAL_CNTL_1 to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
++ /* Task independent global settings: R_80_GLOBAL_CNTL_1 to R_8F_STATUS_INFO_SCALER */
++ {R_80_GLOBAL_CNTL_1,1,
++ "Global control 1"},
++ {R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F,1,
++ "Vertical sync and Field ID source selection, retimed V and F signals"},
++ /* 0x82 - Reserved */
++ {R_83_X_PORT_I_O_ENA_AND_OUT_CLK,1,
++ "X port I/O enable and output clock"},
++ {R_84_I_PORT_SIGNAL_DEF,1,
++ "I port signal definitions"},
++ {R_85_I_PORT_SIGNAL_POLAR,1,
++ "I port signal polarities"},
++ {R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT,1,
++ "I port FIFO flag control and arbitration"},
++ {R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 1,
++ "I port I/O enable output clock and gated"},
++ {R_88_POWER_SAVE_ADC_PORT_CNTL,1,
++ "Power save/ADC port control"},
++ /* 089-0x8e - Reserved */
++ {R_8F_STATUS_INFO_SCALER,1,
++ "Status information scaler part"},
++
++ /* Task A definition: R_90_A_TASK_HANDLING_CNTL to R_BF_A_VERT_LUMA_PHASE_OFF_11 */
++ /* Task A: Basic settings and acquisition window definition */
++ {R_90_A_TASK_HANDLING_CNTL,1,
++ "Task A: Task handling control"},
++ {R_91_A_X_PORT_FORMATS_AND_CONF,1,
++ "Task A: X port formats and configuration"},
++ {R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL,1,
++ "Task A: X port input reference signal definition"},
++ {R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF,1,
++ "Task A: I port output formats and configuration"},
++ {R_94_A_HORIZ_INPUT_WINDOW_START,2,
++ "Task A: Horizontal input window start"},
++ {R_96_A_HORIZ_INPUT_WINDOW_LENGTH,2,
++ "Task A: Horizontal input window length"},
++ {R_98_A_VERT_INPUT_WINDOW_START,2,
++ "Task A: Vertical input window start"},
++ {R_9A_A_VERT_INPUT_WINDOW_LENGTH,2,
++ "Task A: Vertical input window length"},
++ {R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH,2,
++ "Task A: Horizontal output window length"},
++ {R_9E_A_VERT_OUTPUT_WINDOW_LENGTH,2,
++ "Task A: Vertical output window length"},
++
++ /* Task A: FIR filtering and prescaling */
++ {R_A0_A_HORIZ_PRESCALING,1,
++ "Task A: Horizontal prescaling"},
++ {R_A1_A_ACCUMULATION_LENGTH,1,
++ "Task A: Accumulation length"},
++ {R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
++ "Task A: Prescaler DC gain and FIR prefilter"},
++ /* 0xa3 - Reserved */
++ {R_A4_A_LUMA_BRIGHTNESS_CNTL,1,
++ "Task A: Luminance brightness control"},
++ {R_A5_A_LUMA_CONTRAST_CNTL,1,
++ "Task A: Luminance contrast control"},
++ {R_A6_A_CHROMA_SATURATION_CNTL,1,
++ "Task A: Chrominance saturation control"},
++ /* 0xa7 - Reserved */
++
++ /* Task A: Horizontal phase scaling */
++ {R_A8_A_HORIZ_LUMA_SCALING_INC,2,
++ "Task A: Horizontal luminance scaling increment"},
++ {R_AA_A_HORIZ_LUMA_PHASE_OFF,1,
++ "Task A: Horizontal luminance phase offset"},
++ /* 0xab - Reserved */
++ {R_AC_A_HORIZ_CHROMA_SCALING_INC,2,
++ "Task A: Horizontal chrominance scaling increment"},
++ {R_AE_A_HORIZ_CHROMA_PHASE_OFF,1,
++ "Task A: Horizontal chrominance phase offset"},
++ /* 0xaf - Reserved */
++
++ /* Task A: Vertical scaling */
++ {R_B0_A_VERT_LUMA_SCALING_INC,2,
++ "Task A: Vertical luminance scaling increment"},
++ {R_B2_A_VERT_CHROMA_SCALING_INC,2,
++ "Task A: Vertical chrominance scaling increment"},
++ {R_B4_A_VERT_SCALING_MODE_CNTL,1,
++ "Task A: Vertical scaling mode control"},
++ /* 0xb5-0xb7 - Reserved */
++ {R_B8_A_VERT_CHROMA_PHASE_OFF_00,1,
++ "Task A: Vertical chrominance phase offset '00'"},
++ {R_B9_A_VERT_CHROMA_PHASE_OFF_01,1,
++ "Task A: Vertical chrominance phase offset '01'"},
++ {R_BA_A_VERT_CHROMA_PHASE_OFF_10,1,
++ "Task A: Vertical chrominance phase offset '10'"},
++ {R_BB_A_VERT_CHROMA_PHASE_OFF_11,1,
++ "Task A: Vertical chrominance phase offset '11'"},
++ {R_BC_A_VERT_LUMA_PHASE_OFF_00,1,
++ "Task A: Vertical luminance phase offset '00'"},
++ {R_BD_A_VERT_LUMA_PHASE_OFF_01,1,
++ "Task A: Vertical luminance phase offset '01'"},
++ {R_BE_A_VERT_LUMA_PHASE_OFF_10,1,
++ "Task A: Vertical luminance phase offset '10'"},
++ {R_BF_A_VERT_LUMA_PHASE_OFF_11,1,
++ "Task A: Vertical luminance phase offset '11'"},
++
++ /* Task B definition: R_C0_B_TASK_HANDLING_CNTL to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
++ /* Task B: Basic settings and acquisition window definition */
++ {R_C0_B_TASK_HANDLING_CNTL,1,
++ "Task B: Task handling control"},
++ {R_C1_B_X_PORT_FORMATS_AND_CONF,1,
++ "Task B: X port formats and configuration"},
++ {R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION,1,
++ "Task B: Input reference signal definition"},
++ {R_C3_B_I_PORT_FORMATS_AND_CONF,1,
++ "Task B: I port formats and configuration"},
++ {R_C4_B_HORIZ_INPUT_WINDOW_START,2,
++ "Task B: Horizontal input window start"},
++ {R_C6_B_HORIZ_INPUT_WINDOW_LENGTH,2,
++ "Task B: Horizontal input window length"},
++ {R_C8_B_VERT_INPUT_WINDOW_START,2,
++ "Task B: Vertical input window start"},
++ {R_CA_B_VERT_INPUT_WINDOW_LENGTH,2,
++ "Task B: Vertical input window length"},
++ {R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,2,
++ "Task B: Horizontal output window length"},
++ {R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,2,
++ "Task B: Vertical output window length"},
++
++ /* Task B: FIR filtering and prescaling */
++ {R_D0_B_HORIZ_PRESCALING,1,
++ "Task B: Horizontal prescaling"},
++ {R_D1_B_ACCUMULATION_LENGTH,1,
++ "Task B: Accumulation length"},
++ {R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
++ "Task B: Prescaler DC gain and FIR prefilter"},
++ /* 0xd3 - Reserved */
++ {R_D4_B_LUMA_BRIGHTNESS_CNTL,1,
++ "Task B: Luminance brightness control"},
++ {R_D5_B_LUMA_CONTRAST_CNTL,1,
++ "Task B: Luminance contrast control"},
++ {R_D6_B_CHROMA_SATURATION_CNTL,1,
++ "Task B: Chrominance saturation control"},
++ /* 0xd7 - Reserved */
++
++ /* Task B: Horizontal phase scaling */
++ {R_D8_B_HORIZ_LUMA_SCALING_INC,2,
++ "Task B: Horizontal luminance scaling increment"},
++ {R_DA_B_HORIZ_LUMA_PHASE_OFF,1,
++ "Task B: Horizontal luminance phase offset"},
++ /* 0xdb - Reserved */
++ {R_DC_B_HORIZ_CHROMA_SCALING,2,
++ "Task B: Horizontal chrominance scaling"},
++ {R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA,1,
++ "Task B: Horizontal Phase Offset Chroma"},
++ /* 0xdf - Reserved */
++
++ /* Task B: Vertical scaling */
++ {R_E0_B_VERT_LUMA_SCALING_INC,2,
++ "Task B: Vertical luminance scaling increment"},
++ {R_E2_B_VERT_CHROMA_SCALING_INC,2,
++ "Task B: Vertical chrominance scaling increment"},
++ {R_E4_B_VERT_SCALING_MODE_CNTL,1,
++ "Task B: Vertical scaling mode control"},
++ /* 0xe5-0xe7 - Reserved */
++ {R_E8_B_VERT_CHROMA_PHASE_OFF_00,1,
++ "Task B: Vertical chrominance phase offset '00'"},
++ {R_E9_B_VERT_CHROMA_PHASE_OFF_01,1,
++ "Task B: Vertical chrominance phase offset '01'"},
++ {R_EA_B_VERT_CHROMA_PHASE_OFF_10,1,
++ "Task B: Vertical chrominance phase offset '10'"},
++ {R_EB_B_VERT_CHROMA_PHASE_OFF_11,1,
++ "Task B: Vertical chrominance phase offset '11'"},
++ {R_EC_B_VERT_LUMA_PHASE_OFF_00,1,
++ "Task B: Vertical luminance phase offset '00'"},
++ {R_ED_B_VERT_LUMA_PHASE_OFF_01,1,
++ "Task B: Vertical luminance phase offset '01'"},
++ {R_EE_B_VERT_LUMA_PHASE_OFF_10,1,
++ "Task B: Vertical luminance phase offset '10'"},
++ {R_EF_B_VERT_LUMA_PHASE_OFF_11,1,
++ "Task B: Vertical luminance phase offset '11'"},
++
++ /* second PLL (PLL2) and Pulsegenerator Programming */
++ { R_F0_LFCO_PER_LINE, 1,
++ "LFCO's per line"},
++ { R_F1_P_I_PARAM_SELECT,1,
++ "P-/I- Param. Select., PLL Mode, PLL H-Src., LFCO's per line"},
++ { R_F2_NOMINAL_PLL2_DTO,1,
++ "Nominal PLL2 DTO"},
++ {R_F3_PLL_INCREMENT,1,
++ "PLL2 Increment"},
++ {R_F4_PLL2_STATUS,1,
++ "PLL2 Status"},
++ {R_F5_PULSGEN_LINE_LENGTH,1,
++ "Pulsgen. line length"},
++ {R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG,1,
++ "Pulse A Position, Pulsgen Resync., Pulsgen. H-Src., Pulsgen. line length"},
++ {R_F7_PULSE_A_POS_MSB,1,
++ "Pulse A Position"},
++ {R_F8_PULSE_B_POS,2,
++ "Pulse B Position"},
++ {R_FA_PULSE_C_POS,2,
++ "Pulse C Position"},
++ /* 0xfc to 0xfe - Reserved */
++ {R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES,1,
++ "S_PLL max. phase, error threshold, PLL2 no. of lines, threshold"},
++};
++#endif
+diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
+index f554316..59da79c 100644
+--- a/drivers/media/video/saa7134/Kconfig
++++ b/drivers/media/video/saa7134/Kconfig
+@@ -41,53 +41,15 @@ config VIDEO_SAA7134_DVB
+ select VIDEO_BUF_DVB
+ select FW_LOADER
+ select DVB_PLL
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
++ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
++ select DVB_NXT200X if !DVB_FE_CUSTOMISE
++ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
++ select DVB_TDA826X if !DVB_FE_CUSTOMISE
++ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ ---help---
+ This adds support for DVB cards based on the
+ Philips saa7134 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-dvb.
+-
+- You must also select one or more DVB demodulators.
+- If you are unsure which you need, choose all of them.
+-
+-config VIDEO_SAA7134_DVB_ALL_FRONTENDS
+- bool "Build all supported frontends for saa7134 based TV cards"
+- default y
+- depends on VIDEO_SAA7134_DVB
+- select DVB_MT352
+- select DVB_TDA1004X
+- select DVB_NXT200X
+- ---help---
+- This builds saa7134-dvb with all currently supported frontend
+- demodulators. If you wish to tweak your configuration, and
+- only include support for the hardware that you need, choose N here.
+-
+- If you are unsure, choose Y.
+-
+-config VIDEO_SAA7134_DVB_MT352
+- bool "Zarlink MT352 DVB-T Support"
+- default y
+- depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+- select DVB_MT352
+- ---help---
+- This adds DVB-T support for cards based on the
+- Philips saa7134 chip and the MT352 demodulator.
+-
+-config VIDEO_SAA7134_DVB_TDA1004X
+- bool "Phillips TDA10045H/TDA10046H DVB-T Support"
+- default y
+- depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+- select DVB_TDA1004X
+- ---help---
+- This adds DVB-T support for cards based on the
+- Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
+-
+-config VIDEO_SAA7134_DVB_NXT200X
+- bool "NXT2002/NXT2004 ATSC Support"
+- default y
+- depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+- select DVB_NXT200X
+- ---help---
+- This adds ATSC 8VSB and QAM64/256 support for cards based on the
+- Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
+diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
+index be7b9ee..89a1565 100644
+--- a/drivers/media/video/saa7134/Makefile
++++ b/drivers/media/video/saa7134/Makefile
+@@ -16,8 +16,5 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-
+ EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+ extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
+-extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
+-extra-cflags-$(CONFIG_DVB_TDA1004X) += -DHAVE_TDA1004X=1
+-extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1
+
+ EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
+index d73cff1..4abf5c0 100644
+--- a/drivers/media/video/saa7134/saa7134-alsa.c
++++ b/drivers/media/video/saa7134/saa7134-alsa.c
+@@ -212,7 +212,7 @@ static void saa7134_irq_alsa_done(struct
+ *
+ */
+
+-static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id)
+ {
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+@@ -590,6 +590,11 @@ static int snd_card_saa7134_hw_free(stru
+
+ static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
+ {
++ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
++ struct saa7134_dev *dev = saa7134->dev;
++
++ dev->ctl_mute = 1;
++ saa7134_tvaudio_setmute(dev);
+ return 0;
+ }
+
+@@ -631,6 +636,9 @@ static int snd_card_saa7134_capture_open
+ runtime->private_free = snd_card_saa7134_runtime_free;
+ runtime->hw = snd_card_saa7134_capture;
+
++ dev->ctl_mute = 0;
++ saa7134_tvaudio_setmute(dev);
++
+ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+ return err;
+
+diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
+index 927413a..c9d8e3b 100644
+--- a/drivers/media/video/saa7134/saa7134-cards.c
++++ b/drivers/media/video/saa7134/saa7134-cards.c
+@@ -1911,7 +1911,7 @@ struct saa7134_board saa7134_boards[] =
+ },
+ },
+ [SAA7134_BOARD_FLYDVBT_DUO_CARDBUS] = {
+- .name = "LifeView/Typhoon FlyDVB-T Duo Cardbus",
++ .name = "LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+@@ -2891,6 +2891,137 @@ struct saa7134_board saa7134_boards[] =
+ .gpio = 0x8000,
+ },
+ },
++ [SAA7134_BOARD_MEDION_MD8800_QUADRO] = {
++ .name = "Medion Md8800 Quadro",
++ .audio_clock = 0x00187de7,
++ .tuner_type = TUNER_PHILIPS_TDA8290,
++ .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,
++ .vmux = 0,
++ .amux = LINE2,
++ },{
++ .name = name_svideo,
++ .vmux = 8,
++ .amux = LINE2,
++ }},
++ },
++ [SAA7134_BOARD_FLYDVBS_LR300] = {
++ /* LifeView FlyDVB-s */
++ /* Igor M. Liplianin <liplianin at tut.by> */
++ .name = "LifeView FlyDVB-S /Acorp TV134DS",
++ .audio_clock = 0x00200000,
++ .tuner_type = TUNER_ABSENT,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .mpeg = SAA7134_MPEG_DVB,
++ .inputs = {{
++ .name = name_comp1, /* Composite input */
++ .vmux = 3,
++ .amux = LINE1,
++ },{
++ .name = name_svideo, /* S-Video signal on S-Video input */
++ .vmux = 8,
++ .amux = LINE1,
++ }},
++ },
++ [SAA7134_BOARD_PROTEUS_2309] = {
++ .name = "Proteus Pro 2309",
++ .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 = LINE2,
++ .tv = 1,
++ },{
++ .name = name_comp1,
++ .vmux = 0,
++ .amux = LINE2,
++ },{
++ .name = name_comp2,
++ .vmux = 3,
++ .amux = LINE2,
++ },{
++ .name = name_svideo,
++ .vmux = 8,
++ .amux = LINE2,
++ }},
++ .mute = {
++ .name = name_mute,
++ .amux = LINE1,
++ },
++ },
++ [SAA7134_BOARD_AVERMEDIA_A16AR] = {
++ /* Petr Baudis <pasky at ucw.cz> */
++ .name = "AVerMedia TV Hybrid A16AR",
++ .audio_clock = 0x187de7,
++ .tuner_type = TUNER_PHILIPS_TDA8290, /* untested */
++ .radio_type = TUNER_TEA5767, /* untested */
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .tda9887_conf = TDA9887_PRESENT,
++ .mpeg = SAA7134_MPEG_DVB,
++ .inputs = {{
++ .name = name_tv,
++ .vmux = 1,
++ .amux = TV,
++ .tv = 1,
++ },{
++ .name = name_comp1,
++ .vmux = 3,
++ .amux = LINE2,
++ },{
++ .name = name_svideo,
++ .vmux = 8,
++ .amux = LINE1,
++ }},
++ .radio = {
++ .name = name_radio,
++ .amux = LINE1,
++ },
++ },
++ [SAA7134_BOARD_ASUS_EUROPA2_HYBRID] = {
++ .name = "Asus Europa2 OEM",
++ .audio_clock = 0x00187de7,
++ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .tda9887_conf = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE,
++ .mpeg = SAA7134_MPEG_DVB,
++ .inputs = {{
++ .name = name_tv,
++ .vmux = 3,
++ .amux = TV,
++ .tv = 1,
++ },{
++ .name = name_comp1,
++ .vmux = 4,
++ .amux = LINE2,
++ },{
++ .name = name_svideo,
++ .vmux = 8,
++ .amux = LINE2,
++ }},
++ .radio = {
++ .name = name_radio,
++ .amux = LINE1,
++ },
++ },
+ };
+
+ const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
+@@ -3375,7 +3506,7 @@ struct pci_device_id saa7134_pci_tbl[] =
+ .driver_data = SAA7134_BOARD_FLYDVB_TRIO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+- .device = PCI_DEVICE_ID_PHILIPS_SAA7134, /* SAA 7131E */
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x2c05,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_777,
+@@ -3422,6 +3553,18 @@ struct pci_device_id saa7134_pci_tbl[] =
+ .subdevice = 0x0005,
+ .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2,
+ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
++ .subvendor = 0x5168,
++ .subdevice = 0x0300,
++ .driver_data = SAA7134_BOARD_FLYDVBS_LR300,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
++ .subvendor = 0x4e42,
++ .subdevice = 0x0300,/* LR300 */
++ .driver_data = SAA7134_BOARD_FLYDVBS_LR300,
++ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1489,
+@@ -3446,6 +3589,48 @@ struct pci_device_id saa7134_pci_tbl[] =
+ .subdevice = 0x3502, /* whats the difference to 0x3306 ?*/
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x16be,
++ .subdevice = 0x0007,
++ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x16be,
++ .subdevice = 0x0008,
++ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x1461,
++ .subdevice = 0x2c05,
++ .driver_data = SAA7134_BOARD_AVERMEDIA_777,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x1489,
++ .subdevice = 0x0502, /* Cardbus version */
++ .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
++ .subvendor = 0x0919, /* Philips Proteus PRO 2309 */
++ .subdevice = 0x2003,
++ .driver_data = SAA7134_BOARD_PROTEUS_2309,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
++ .subvendor = 0x1461,
++ .subdevice = 0x2c00,
++ .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
++ .subvendor = 0x1043,
++ .subdevice = 0x4860,
++ .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID,
++ },{
+ /* --- boards without eeprom + subsystem ID --- */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+@@ -3548,6 +3733,12 @@ int saa7134_board_init1(struct saa7134_d
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_FLYDVBTDUO:
++ case SAA7134_BOARD_PROTEUS_2309:
++ dev->has_remote = SAA7134_REMOTE_GPIO;
++ break;
++ case SAA7134_BOARD_FLYDVBS_LR300:
++ saa_writeb(SAA7134_GPIO_GPMODE3, 0x80);
++ saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x40);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_MD5044:
+@@ -3581,6 +3772,7 @@ int saa7134_board_init1(struct saa7134_d
+ saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+ saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
+ break;
++ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff);
+@@ -3713,6 +3905,7 @@ int saa7134_board_init2(struct saa7134_d
+ break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
++ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ /* The Philips EUROPA based hybrid boards have the tuner connected through
+ * the channel decoder. We have to make it transparent to find it
+ */
+@@ -3732,6 +3925,7 @@ int saa7134_board_init2(struct saa7134_d
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
++ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+ /* this is a hybrid board, initialize to analog mode
+ * and configure firmware eeprom address
+ */
+diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
+index be3a81f..5c9e63d 100644
+--- a/drivers/media/video/saa7134/saa7134-core.c
++++ b/drivers/media/video/saa7134/saa7134-core.c
+@@ -495,7 +495,7 @@ static void print_irqstatus(struct saa71
+ printk("\n");
+ }
+
+-static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t saa7134_irq(int irq, void *dev_id)
+ {
+ struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+ unsigned long report,status;
+@@ -843,7 +843,7 @@ static int __devinit saa7134_initdev(str
+ latency = 0x0A;
+ }
+ #endif
+- if (pci_pci_problems & PCIPCI_FAIL) {
++ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) {
+ printk(KERN_INFO "%s: quirk: this driver and your "
+ "chipset may not work together"
+ " in overlay mode.\n",dev->name);
+diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
+index 279828b..6b61d9b 100644
+--- a/drivers/media/video/saa7134/saa7134-dvb.c
++++ b/drivers/media/video/saa7134/saa7134-dvb.c
+@@ -34,17 +34,14 @@
+ #include <media/v4l2-common.h>
+ #include "dvb-pll.h"
+
+-#ifdef HAVE_MT352
+-# include "mt352.h"
+-# include "mt352_priv.h" /* FIXME */
+-#endif
+-#ifdef HAVE_TDA1004X
+-# include "tda1004x.h"
+-#endif
+-#ifdef HAVE_NXT200X
+-# include "nxt200x.h"
+-#endif
+-
++#include "mt352.h"
++#include "mt352_priv.h" /* FIXME */
++#include "tda1004x.h"
++#include "nxt200x.h"
++
++#include "tda10086.h"
++#include "tda826x.h"
++#include "isl6421.h"
+ MODULE_AUTHOR("Gerd Knorr <kraxel at bytesex.org> [SuSE Labs]");
+ MODULE_LICENSE("GPL");
+
+@@ -54,8 +51,6 @@ module_param(antenna_pwr, int, 0444);
+ MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+
+ /* ------------------------------------------------------------------ */
+-
+-#ifdef HAVE_MT352
+ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
+ {
+ u32 ok;
+@@ -185,12 +180,8 @@ static struct mt352_config avermedia_777
+ .demod_address = 0xf,
+ .demod_init = mt352_aver777_init,
+ };
+-#endif
+
+ /* ------------------------------------------------------------------ */
+-
+-#ifdef HAVE_TDA1004X
+-
+ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+ {
+ struct saa7134_dev *dev = fe->dvb->priv;
+@@ -883,6 +874,34 @@ static struct tda1004x_config philips_ti
+
+ /* ------------------------------------------------------------------ */
+
++static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe)
++{
++ struct saa7134_dev *dev = fe->dvb->priv;
++ static u8 data[] = { 0x3c, 0x33, 0x6a};
++ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
++
++ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
++ return -EIO;
++ /* make sure the DVB-T antenna input is set */
++ saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000);
++ return 0;
++}
++
++static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe)
++{
++ struct saa7134_dev *dev = fe->dvb->priv;
++ static u8 data[] = { 0x3c, 0x33, 0x68};
++ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
++
++ i2c_transfer(&dev->i2c_adap, &msg, 1);
++ philips_tda827xa_tuner_sleep( 0x61, fe);
++ /* reset antenna inputs for analog usage */
++ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000);
++ return 0;
++}
++
++/* ------------------------------------------------------------------ */
++
+ static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+ {
+ int ret;
+@@ -969,11 +988,58 @@ static struct tda1004x_config tevion_dvb
+ .request_firmware = NULL,
+ };
+
+-#endif
++/* ------------------------------------------------------------------ */
++
++static int md8800_dvbt_analog_mode(struct dvb_frontend *fe)
++{
++ struct saa7134_dev *dev = fe->dvb->priv;
++ static u8 data[] = { 0x3c, 0x33, 0x68};
++ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
++
++ i2c_transfer(&dev->i2c_adap, &msg, 1);
++ philips_tda827xa_tuner_sleep( 0x61, fe);
++ return 0;
++}
++
++static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
++{
++ int ret;
++ struct saa7134_dev *dev = fe->dvb->priv;
++ static u8 tda8290_close[] = { 0x21, 0xc0};
++ static u8 tda8290_open[] = { 0x21, 0x80};
++ struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
++ /* close tda8290 i2c bridge */
++ tda8290_msg.buf = tda8290_close;
++ ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
++ if (ret != 1)
++ return -EIO;
++ msleep(20);
++ ret = philips_tda827xa_pll_set(0x60, fe, params);
++ if (ret != 0)
++ return ret;
++ /* open tda8290 i2c bridge */
++ tda8290_msg.buf = tda8290_open;
++ i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
++ return ret;
++}
++
++static struct tda1004x_config md8800_dvbt_config = {
++ .demod_address = 0x08,
++ .invert = 1,
++ .invert_oclk = 0,
++ .xtal_freq = TDA10046_XTAL_16M,
++ .agc_config = TDA10046_AGC_TDA827X,
++ .if_freq = TDA10046_FREQ_045,
++ .request_firmware = NULL,
++};
++
++static struct tda10086_config flydvbs = {
++ .demod_address = 0x0e,
++ .invert = 0,
++};
+
+ /* ------------------------------------------------------------------ */
+
+-#ifdef HAVE_NXT200X
+ static struct nxt200x_config avertvhda180 = {
+ .demod_address = 0x0a,
+ };
+@@ -991,7 +1057,6 @@ static struct nxt200x_config kworldatsc1
+ .demod_address = 0x0a,
+ .set_pll_input = nxt200x_set_pll_input,
+ };
+-#endif
+
+ /* ------------------------------------------------------------------ */
+
+@@ -1009,29 +1074,27 @@ static int dvb_init(struct saa7134_dev *
+ dev);
+
+ switch (dev->board) {
+-#ifdef HAVE_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);
++ dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ }
+ break;
+-
+ case SAA7134_BOARD_AVERMEDIA_777:
++ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ printk("%s: avertv 777 dvb setup\n",dev->name);
+- dev->dvb.frontend = mt352_attach(&avermedia_777,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ }
+ break;
+-#endif
+-#ifdef HAVE_TDA1004X
+ case SAA7134_BOARD_MD7134:
+- dev->dvb.frontend = tda10046_attach(&medion_cardbus,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &medion_cardbus,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+@@ -1039,16 +1102,18 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TOUGH:
+- dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &philips_tu1216_60_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBTDUO:
+- dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &tda827x_lifeview_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+@@ -1056,8 +1121,9 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
+- dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &tda827x_lifeview_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+@@ -1065,8 +1131,9 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+- dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &philips_europa_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+@@ -1076,25 +1143,30 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+- dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &philips_europa_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
++ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
++ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+- dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &philips_tu1216_61_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+- dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &philips_tiger_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+@@ -1102,17 +1174,19 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+- dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &philips_tiger_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+- dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+- dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
++ dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init;
++ dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBT_LR301:
+- dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &tda827x_lifeview_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+@@ -1120,16 +1194,18 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+- dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &lifeview_trio_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+- dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &ads_tech_duo_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+@@ -1137,37 +1213,75 @@ static int dvb_init(struct saa7134_dev *
+ }
+ break;
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
+- dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &tevion_dvbt220rf_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+- dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
+- &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(tda10046_attach,
++ &ads_tech_duo_config,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
+ break;
+-#endif
+-#ifdef HAVE_NXT200X
++ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
++ dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config,
++ &dev->i2c_adap);
++ if (dev->dvb.frontend) {
++ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
++ dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode;
++ dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
++ }
++ break;
+ case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+- dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_tdhu2);
+ }
+ break;
+ case SAA7134_BOARD_KWORLD_ATSC110:
+- dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
++ dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
++ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+- dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
++ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
++ NULL, &dvb_pll_tuv1236d);
+ }
+ break;
+-#endif
++ case SAA7134_BOARD_FLYDVBS_LR300:
++ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
++ &dev->i2c_adap);
++ if (dev->dvb.frontend) {
++ if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
++ &dev->i2c_adap, 0) == NULL) {
++ printk("%s: No tda826x found!\n", __FUNCTION__);
++ }
++ if (dvb_attach(isl6421_attach, dev->dvb.frontend,
++ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
++ printk("%s: No ISL6421 found!\n", __FUNCTION__);
++ }
++ }
++ break;
++ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
++ dev->dvb.frontend = tda10046_attach(&medion_cardbus,
++ &dev->i2c_adap);
++ if (dev->dvb.frontend) {
++ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
++ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
++ dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
++ dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
++ dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
++ }
++ break;
++
+ default:
+ printk("%s: Huh? unknown DVB card?\n",dev->name);
+ break;
+diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
+index 7c59549..ff59911 100644
+--- a/drivers/media/video/saa7134/saa7134-input.c
++++ b/drivers/media/video/saa7134/saa7134-input.c
+@@ -185,6 +185,7 @@ int saa7134_input_init1(struct saa7134_d
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
++ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ ir_codes = ir_codes_avermedia;
+ mask_keycode = 0x0007C8;
+ mask_keydown = 0x000010;
+@@ -228,6 +229,12 @@ int saa7134_input_init1(struct saa7134_d
+ mask_keyup = 0x400000;
+ polling = 50; // ms
+ break;
++ case SAA7134_BOARD_PROTEUS_2309:
++ ir_codes = ir_codes_proteus_2309;
++ mask_keycode = 0x00007F;
++ mask_keyup = 0x000080;
++ polling = 50; // ms
++ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ ir_codes = ir_codes_videomate_tv_pvr;
+diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
+index 2e3ba5f..bfcb860 100644
+--- a/drivers/media/video/saa7134/saa7134-oss.c
++++ b/drivers/media/video/saa7134/saa7134-oss.c
+@@ -814,7 +814,7 @@ struct file_operations saa7134_mixer_fop
+
+ /* ------------------------------------------------------------------ */
+
+-static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t saa7134_oss_irq(int irq, void *dev_id)
+ {
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
+index 0db53d1..dd759d6 100644
+--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
++++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
+@@ -72,12 +72,12 @@ static struct mainscan {
+ int carr;
+ } mainscan[] = {
+ {
+- .name = "M",
+- .std = V4L2_STD_NTSC | V4L2_STD_PAL_M,
++ .name = "MN",
++ .std = V4L2_STD_MN,
+ .carr = 4500,
+ },{
+- .name = "BG",
+- .std = V4L2_STD_PAL_BG,
++ .name = "BGH",
++ .std = V4L2_STD_B | V4L2_STD_GH,
+ .carr = 5500,
+ },{
+ .name = "I",
+@@ -85,7 +85,7 @@ static struct mainscan {
+ .carr = 6000,
+ },{
+ .name = "DKL",
+- .std = V4L2_STD_PAL_DK | V4L2_STD_SECAM,
++ .std = V4L2_STD_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC,
+ .carr = 6500,
+ }
+ };
+@@ -93,76 +93,70 @@ static struct mainscan {
+ static struct saa7134_tvaudio tvaudio[] = {
+ {
+ .name = "PAL-B/G FM-stereo",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_BG,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ .carr1 = 5500,
+ .carr2 = 5742,
+ },{
+ .name = "PAL-D/K1 FM-stereo",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 6258,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ },{
+ .name = "PAL-D/K2 FM-stereo",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 6742,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ },{
+ .name = "PAL-D/K3 FM-stereo",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 5742,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ },{
+ .name = "PAL-B/G NICAM",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_BG,
+ .carr1 = 5500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "PAL-I NICAM",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_I,
+ .carr1 = 6000,
+ .carr2 = 6552,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "PAL-D/K NICAM",
+- .std = V4L2_STD_PAL,
++ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "SECAM-L NICAM",
+- .std = V4L2_STD_SECAM,
++ .std = V4L2_STD_SECAM_L,
+ .carr1 = 6500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_AM,
+ },{
+- .name = "SECAM-L MONO",
+- .std = V4L2_STD_SECAM,
++ .name = "SECAM-D/K NICAM",
++ .std = V4L2_STD_SECAM_DK,
+ .carr1 = 6500,
+- .carr2 = -1,
+- .mode = TVAUDIO_AM_MONO,
++ .carr2 = 5850,
++ .mode = TVAUDIO_NICAM_FM,
+ },{
+- .name = "SECAM-D/K",
+- .std = V4L2_STD_SECAM,
+- .carr1 = 6500,
+- .carr2 = -1,
+- .mode = TVAUDIO_FM_MONO,
++ .name = "NTSC-A2 FM-stereo",
++ .std = V4L2_STD_NTSC,
++ .carr1 = 4500,
++ .carr2 = 4724,
++ .mode = TVAUDIO_FM_K_STEREO,
+ },{
+ .name = "NTSC-M",
+ .std = V4L2_STD_NTSC,
+ .carr1 = 4500,
+ .carr2 = -1,
+ .mode = TVAUDIO_FM_MONO,
+- },{
+- .name = "NTSC-A2 FM-stereo",
+- .std = V4L2_STD_NTSC,
+- .carr1 = 4500,
+- .carr2 = 4724,
+- .mode = TVAUDIO_FM_K_STEREO,
+ }
+ };
+ #define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio))
+@@ -340,12 +334,6 @@ static void tvaudio_setmode(struct saa71
+ saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1);
+ saa_writeb(SAA7134_NICAM_CONFIG, 0x00);
+ break;
+- case TVAUDIO_AM_MONO:
+- saa_writeb(SAA7134_DEMODULATOR, 0x12);
+- saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00);
+- saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44);
+- saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0);
+- break;
+ case TVAUDIO_FM_SAT_STEREO:
+ /* not implemented (yet) */
+ break;
+@@ -390,7 +378,6 @@ static int tvaudio_checkcarrier(struct s
+ }
+ printk("\n");
+ }
+-
+ if (dev->tvnorm->id & scan->std) {
+ tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
+ saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+@@ -426,7 +413,6 @@ static int tvaudio_getstereo(struct saa7
+
+ switch (audio->mode) {
+ case TVAUDIO_FM_MONO:
+- case TVAUDIO_AM_MONO:
+ return V4L2_TUNER_SUB_MONO;
+ case TVAUDIO_FM_K_STEREO:
+ case TVAUDIO_FM_BG_STEREO:
+@@ -495,7 +481,6 @@ static int tvaudio_setstereo(struct saa7
+
+ switch (audio->mode) {
+ case TVAUDIO_FM_MONO:
+- case TVAUDIO_AM_MONO:
+ /* nothing to do ... */
+ break;
+ case TVAUDIO_FM_K_STEREO:
+@@ -556,6 +541,7 @@ static int tvaudio_thread(void *data)
+
+ if (1 == nscan) {
+ /* only one candidate -- skip scan ;) */
++ dprintk("only one main carrier candidate - skipping scan\n");
+ max1 = 12345;
+ carrier = default_carrier;
+ } else {
+@@ -603,7 +589,6 @@ static int tvaudio_thread(void *data)
+ dev->automute = 0;
+ saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
+ saa7134_tvaudio_setmute(dev);
+-
+ /* find the exact tv audio norm */
+ for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
+ if (dev->tvnorm->id != UNSET &&
+@@ -611,7 +596,7 @@ static int tvaudio_thread(void *data)
+ continue;
+ if (tvaudio[i].carr1 != carrier)
+ continue;
+-
++ /* Note: at least the primary carrier is right here */
+ if (UNSET == audio)
+ audio = i;
+ tvaudio_setmode(dev,&tvaudio[i],"trying");
+@@ -626,6 +611,7 @@ static int tvaudio_thread(void *data)
+ if (UNSET == audio)
+ continue;
+ tvaudio_setmode(dev,&tvaudio[audio],"using");
++
+ tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);
+ dev->tvaudio = &tvaudio[audio];
+
+@@ -750,7 +736,6 @@ static int mute_input_7133(struct saa713
+ int mask;
+ struct saa7134_input *in;
+
+- /* Hac 0506 route OSS sound simultanously */
+ xbarin = 0x03;
+ switch (dev->input->amux) {
+ case TV:
+@@ -834,18 +819,16 @@ static int tvaudio_thread_ddep(void *dat
+ } else {
+ /* (let chip) scan for sound carrier */
+ norms = 0;
+- if (dev->tvnorm->id & V4L2_STD_PAL) {
+- dprintk("PAL scan\n");
+- norms |= 0x2c; /* B/G + D/K + I */
+- }
+- if (dev->tvnorm->id & V4L2_STD_NTSC) {
+- dprintk("NTSC scan\n");
+- norms |= 0x40; /* M */
+- }
+- if (dev->tvnorm->id & V4L2_STD_SECAM) {
+- dprintk("SECAM scan\n");
+- norms |= 0x18; /* L + D/K */
+- }
++ if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH))
++ norms |= 0x04;
++ if (dev->tvnorm->id & V4L2_STD_PAL_I)
++ norms |= 0x20;
++ if (dev->tvnorm->id & V4L2_STD_DK)
++ norms |= 0x08;
++ if (dev->tvnorm->id & V4L2_STD_MN)
++ norms |= 0x40;
++ if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))
++ norms |= 0x10;
+ if (0 == norms)
+ norms = 0x7c; /* all */
+ dprintk("scanning:%s%s%s%s%s\n",
+@@ -1034,7 +1017,11 @@ int saa7134_tvaudio_fini(struct saa7134_
+
+ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
+ {
+- if (dev->thread.pid >= 0) {
++ if (dev->input->amux != TV) {
++ dprintk("sound IF not in use, skipping scan\n");
++ dev->automute = 0;
++ saa7134_tvaudio_setmute(dev);
++ } else if (dev->thread.pid >= 0) {
+ dev->thread.mode = UNSET;
+ dev->thread.scan2++;
+ wake_up_interruptible(&dev->thread.wq);
+@@ -1046,6 +1033,7 @@ int saa7134_tvaudio_do_scan(struct saa71
+ }
+
+ EXPORT_SYMBOL(saa_dsp_writel);
++EXPORT_SYMBOL(saa7134_tvaudio_setmute);
+
+ /* ----------------------------------------------------------- */
+ /*
+diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
+index 2c171af..830617e 100644
+--- a/drivers/media/video/saa7134/saa7134-video.c
++++ b/drivers/media/video/saa7134/saa7134-video.c
+@@ -43,12 +43,16 @@ static unsigned int gbuffers = 8;
+ static unsigned int noninterlaced = 1;
+ static unsigned int gbufsize = 720*576*4;
+ static unsigned int gbufsize_max = 720*576*4;
++static char secam[] = "--";
+ module_param(video_debug, int, 0644);
+ MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+ module_param(gbuffers, int, 0444);
+ MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
+ module_param(noninterlaced, int, 0644);
+ MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
++module_param_string(secam, secam, sizeof(secam), 0644);
++MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
++
+
+ #define dprintk(fmt, arg...) if (video_debug) \
+ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
+@@ -279,7 +283,43 @@ static struct saa7134_tvnorm tvnorms[] =
+ .id = V4L2_STD_SECAM,
+ NORM_625_50,
+
+- .sync_control = 0x18, /* old: 0x58, */
++ .sync_control = 0x18,
++ .luma_control = 0x1b,
++ .chroma_ctrl1 = 0xd1,
++ .chroma_gain = 0x80,
++ .chroma_ctrl2 = 0x00,
++ .vgate_misc = 0x1c,
++
++ },{
++ .name = "SECAM-DK",
++ .id = V4L2_STD_SECAM_DK,
++ NORM_625_50,
++
++ .sync_control = 0x18,
++ .luma_control = 0x1b,
++ .chroma_ctrl1 = 0xd1,
++ .chroma_gain = 0x80,
++ .chroma_ctrl2 = 0x00,
++ .vgate_misc = 0x1c,
++
++ },{
++ .name = "SECAM-L",
++ .id = V4L2_STD_SECAM_L,
++ NORM_625_50,
++
++ .sync_control = 0x18,
++ .luma_control = 0x1b,
++ .chroma_ctrl1 = 0xd1,
++ .chroma_gain = 0x80,
++ .chroma_ctrl2 = 0x00,
++ .vgate_misc = 0x1c,
++
++ },{
++ .name = "SECAM-Lc",
++ .id = V4L2_STD_SECAM_LC,
++ NORM_625_50,
++
++ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+@@ -1769,6 +1809,7 @@ static int video_do_ioctl(struct inode *
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
++ v4l2_std_id fixup;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (*id == tvnorms[i].id)
+@@ -1779,7 +1820,22 @@ static int video_do_ioctl(struct inode *
+ break;
+ if (i == TVNORMS)
+ return -EINVAL;
+-
++ if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
++ if (secam[0] == 'L' || secam[0] == 'l') {
++ if (secam[1] == 'C' || secam[1] == 'c')
++ fixup = V4L2_STD_SECAM_LC;
++ else
++ fixup = V4L2_STD_SECAM_L;
++ } else {
++ if (secam[0] == 'D' || secam[0] == 'd')
++ fixup = V4L2_STD_SECAM_DK;
++ else
++ fixup = V4L2_STD_SECAM;
++ }
++ for (i = 0; i < TVNORMS; i++)
++ if (fixup == tvnorms[i].id)
++ break;
++ }
+ mutex_lock(&dev->lock);
+ if (res_check(fh, RESOURCE_OVERLAY)) {
+ spin_lock_irqsave(&dev->slock,flags);
+@@ -2192,7 +2248,11 @@ static int radio_do_ioctl(struct inode *
+ t->type = V4L2_TUNER_RADIO;
+
+ saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+-
++ if (dev->input->amux == TV) {
++ t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
++ t->rxsubchans = (saa_readb(0x529) & 0x08) ?
++ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
++ }
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
+index c04ce61..7cf96b4 100644
+--- a/drivers/media/video/saa7134/saa7134.h
++++ b/drivers/media/video/saa7134/saa7134.h
+@@ -61,7 +61,6 @@ enum saa7134_tvaudio_mode {
+ TVAUDIO_FM_K_STEREO = 4,
+ TVAUDIO_NICAM_AM = 5,
+ TVAUDIO_NICAM_FM = 6,
+- TVAUDIO_AM_MONO = 7
+ };
+
+ enum saa7134_audio_in {
+@@ -223,6 +222,11 @@ struct saa7134_format {
+ #define SAA7134_BOARD_MD7134_BRIDGE_2 93
+ #define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+ #define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
++#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
++#define SAA7134_BOARD_FLYDVBS_LR300 97
++#define SAA7134_BOARD_PROTEUS_2309 98
++#define SAA7134_BOARD_AVERMEDIA_A16AR 99
++#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
+
+ #define SAA7134_MAXBOARDS 8
+ #define SAA7134_INPUT_MAX 8
+diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
+index 67987ba..7aeec57 100644
+--- a/drivers/media/video/se401.c
++++ b/drivers/media/video/se401.c
+@@ -282,7 +282,7 @@ static void se401_auto_resetlevel(struct
+ }
+
+ /* irq handler for snapshot button */
+-static void se401_button_irq(struct urb *urb, struct pt_regs *regs)
++static void se401_button_irq(struct urb *urb)
+ {
+ struct usb_se401 *se401 = urb->context;
+ int status;
+@@ -318,7 +318,7 @@ exit:
+ __FUNCTION__, status);
+ }
+
+-static void se401_video_irq(struct urb *urb, struct pt_regs *regs)
++static void se401_video_irq(struct urb *urb)
+ {
+ struct usb_se401 *se401 = urb->context;
+ int length = urb->actual_length;
+diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
+index 48d138a..a4702d3 100644
+--- a/drivers/media/video/sn9c102/sn9c102_core.c
++++ b/drivers/media/video/sn9c102/sn9c102_core.c
+@@ -518,7 +518,7 @@ sn9c102_find_eof_header(struct sn9c102_d
+ }
+
+
+-static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
++static void sn9c102_urb_complete(struct urb *urb)
+ {
+ struct sn9c102_device* cam = urb->context;
+ struct sn9c102_frame_t** f;
+@@ -1240,23 +1240,53 @@ static CLASS_DEVICE_ATTR(frame_header, S
+ sn9c102_show_frame_header, NULL);
+
+
+-static void sn9c102_create_sysfs(struct sn9c102_device* cam)
++static int sn9c102_create_sysfs(struct sn9c102_device* cam)
+ {
+ struct video_device *v4ldev = cam->v4ldev;
++ int rc;
++
++ rc = video_device_create_file(v4ldev, &class_device_attr_reg);
++ if (rc) goto err;
++ rc = video_device_create_file(v4ldev, &class_device_attr_val);
++ if (rc) goto err_reg;
++ rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
++ if (rc) goto err_val;
+
+- video_device_create_file(v4ldev, &class_device_attr_reg);
+- video_device_create_file(v4ldev, &class_device_attr_val);
+- video_device_create_file(v4ldev, &class_device_attr_frame_header);
+- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+- video_device_create_file(v4ldev, &class_device_attr_green);
+- else if (cam->bridge == BRIDGE_SN9C103) {
+- video_device_create_file(v4ldev, &class_device_attr_blue);
+- video_device_create_file(v4ldev, &class_device_attr_red);
+- }
+ if (cam->sensor.sysfs_ops) {
+- video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+- video_device_create_file(v4ldev, &class_device_attr_i2c_val);
++ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
++ if (rc) goto err_frhead;
++ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
++ if (rc) goto err_i2c_reg;
++ }
++
++ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
++ rc = video_device_create_file(v4ldev, &class_device_attr_green);
++ if (rc) goto err_i2c_val;
++ } else if (cam->bridge == BRIDGE_SN9C103) {
++ rc = video_device_create_file(v4ldev, &class_device_attr_blue);
++ if (rc) goto err_i2c_val;
++ rc = video_device_create_file(v4ldev, &class_device_attr_red);
++ if (rc) goto err_blue;
+ }
++
++ return 0;
++
++err_blue:
++ video_device_remove_file(v4ldev, &class_device_attr_blue);
++err_i2c_val:
++ if (cam->sensor.sysfs_ops)
++ video_device_remove_file(v4ldev, &class_device_attr_i2c_val);
++err_i2c_reg:
++ if (cam->sensor.sysfs_ops)
++ video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
++err_frhead:
++ video_device_remove_file(v4ldev, &class_device_attr_frame_header);
++err_val:
++ video_device_remove_file(v4ldev, &class_device_attr_val);
++err_reg:
++ video_device_remove_file(v4ldev, &class_device_attr_reg);
++err:
++ return rc;
+ }
+ #endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+@@ -2809,10 +2839,7 @@ sn9c102_usb_probe(struct usb_interface*
+ DBG(1, "V4L2 device registration failed");
+ if (err == -ENFILE && video_nr[dev_nr] == -1)
+ DBG(1, "Free /dev/videoX node not found");
+- video_nr[dev_nr] = -1;
+- dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+- mutex_unlock(&cam->dev_mutex);
+- goto fail;
++ goto fail2;
+ }
+
+ DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+@@ -2823,7 +2850,9 @@ sn9c102_usb_probe(struct usb_interface*
+ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+- sn9c102_create_sysfs(cam);
++ err = sn9c102_create_sysfs(cam);
++ if (err)
++ goto fail3;
+ DBG(2, "Optional device control through 'sysfs' interface ready");
+ #endif
+
+@@ -2833,6 +2862,14 @@ sn9c102_usb_probe(struct usb_interface*
+
+ return 0;
+
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++fail3:
++ video_unregister_device(cam->v4ldev);
++#endif
++fail2:
++ video_nr[dev_nr] = -1;
++ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
++ mutex_unlock(&cam->dev_mutex);
+ fail:
+ if (cam) {
+ kfree(cam->control_buffer);
+diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
+index 5686547..525d812 100644
+--- a/drivers/media/video/stradis.c
++++ b/drivers/media/video/stradis.c
+@@ -406,7 +406,7 @@ static void send_osd_data(struct saa7146
+ }
+ }
+
+-static irqreturn_t saa7146_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t saa7146_irq(int irq, void *dev_id)
+ {
+ struct saa7146 *saa = dev_id;
+ u32 stat, astat;
+diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
+index 2ba2991..6d1ef1e 100644
+--- a/drivers/media/video/stv680.c
++++ b/drivers/media/video/stv680.c
+@@ -516,16 +516,45 @@ stv680_file(frames_read, framecount, "%d
+ stv680_file(packets_dropped, dropped, "%d\n");
+ stv680_file(decoding_errors, error, "%d\n");
+
+-static void stv680_create_sysfs_files(struct video_device *vdev)
++static int stv680_create_sysfs_files(struct video_device *vdev)
+ {
+- video_device_create_file(vdev, &class_device_attr_model);
+- video_device_create_file(vdev, &class_device_attr_in_use);
+- video_device_create_file(vdev, &class_device_attr_streaming);
+- video_device_create_file(vdev, &class_device_attr_palette);
+- video_device_create_file(vdev, &class_device_attr_frames_total);
+- video_device_create_file(vdev, &class_device_attr_frames_read);
+- video_device_create_file(vdev, &class_device_attr_packets_dropped);
+- video_device_create_file(vdev, &class_device_attr_decoding_errors);
++ int rc;
++
++ rc = video_device_create_file(vdev, &class_device_attr_model);
++ if (rc) goto err;
++ rc = video_device_create_file(vdev, &class_device_attr_in_use);
++ if (rc) goto err_model;
++ rc = video_device_create_file(vdev, &class_device_attr_streaming);
++ if (rc) goto err_inuse;
++ rc = video_device_create_file(vdev, &class_device_attr_palette);
++ if (rc) goto err_stream;
++ rc = video_device_create_file(vdev, &class_device_attr_frames_total);
++ if (rc) goto err_pal;
++ rc = video_device_create_file(vdev, &class_device_attr_frames_read);
++ if (rc) goto err_framtot;
++ rc = video_device_create_file(vdev, &class_device_attr_packets_dropped);
++ if (rc) goto err_framread;
++ rc = video_device_create_file(vdev, &class_device_attr_decoding_errors);
++ if (rc) goto err_dropped;
++
++ return 0;
++
++err_dropped:
++ video_device_remove_file(vdev, &class_device_attr_packets_dropped);
++err_framread:
++ video_device_remove_file(vdev, &class_device_attr_frames_read);
++err_framtot:
++ video_device_remove_file(vdev, &class_device_attr_frames_total);
++err_pal:
++ video_device_remove_file(vdev, &class_device_attr_palette);
++err_stream:
++ video_device_remove_file(vdev, &class_device_attr_streaming);
++err_inuse:
++ video_device_remove_file(vdev, &class_device_attr_in_use);
++err_model:
++ video_device_remove_file(vdev, &class_device_attr_model);
++err:
++ return rc;
+ }
+
+ static void stv680_remove_sysfs_files(struct video_device *vdev)
+@@ -582,7 +611,7 @@ static int stv680_set_pict (struct usb_s
+ return 0;
+ }
+
+-static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
++static void stv680_video_irq (struct urb *urb)
+ {
+ struct usb_stv *stv680 = urb->context;
+ int length = urb->actual_length;
+@@ -1418,9 +1447,13 @@ static int stv680_probe (struct usb_inte
+ PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
+
+ usb_set_intfdata (intf, stv680);
+- stv680_create_sysfs_files(stv680->vdev);
++ retval = stv680_create_sysfs_files(stv680->vdev);
++ if (retval)
++ goto error_unreg;
+ return 0;
+
++error_unreg:
++ video_unregister_device(stv680->vdev);
+ error_vdev:
+ video_device_release(stv680->vdev);
+ error:
+diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
+index 8dab481..87ffb0e 100644
+--- a/drivers/media/video/tda9887.c
++++ b/drivers/media/video/tda9887.c
+@@ -480,6 +480,8 @@ static int tda9887_set_config(struct tun
+ }
+ if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+ buf[1] &= ~cQSS;
++ if (t->tda9887_config & TDA9887_GATING_18)
++ buf[3] &= ~cGating_36;
+ return 0;
+ }
+
+diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
+index abe37cf..63db4e9 100644
+--- a/drivers/media/video/tuner-simple.c
++++ b/drivers/media/video/tuner-simple.c
+@@ -10,7 +10,7 @@
+ #include <media/v4l2-common.h>
+
+ static int offset = 0;
+-module_param(offset, int, 0666);
++module_param(offset, int, 0664);
+ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
+
+ /* ---------------------------------------------------------------------- */
+@@ -331,6 +331,8 @@ static void default_set_tv_freq(struct i
+ else if (params->default_top_high)
+ config |= TDA9887_TOP(params->default_top_high);
+ }
++ if (params->default_pll_gating_18)
++ config |= TDA9887_GATING_18;
+ i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ }
+ tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+@@ -439,8 +441,6 @@ static void default_set_radio_freq(struc
+ buffer[3] = 0xa4;
+ break;
+ }
+- buffer[0] = (div>>8) & 0x7f;
+- buffer[1] = div & 0xff;
+ if (params->cb_first_if_lower_freq && div < t->last_div) {
+ buffer[0] = buffer[2];
+ buffer[1] = buffer[3];
+diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
+index 8b54259..7816823 100644
+--- a/drivers/media/video/tuner-types.c
++++ b/drivers/media/video/tuner-types.c
+@@ -650,6 +650,7 @@ static struct tuner_params tuner_microtu
+ .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_invert_for_secam_lc = 1,
++ .default_pll_gating_18 = 1,
+ },
+ };
+
+@@ -1045,7 +1046,6 @@ static struct tuner_params tuner_samsung
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
+- .has_tda9887 = 1,
+ },
+ };
+
+diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
+index 936e3f7..fcaef4b 100644
+--- a/drivers/media/video/tvaudio.c
++++ b/drivers/media/video/tvaudio.c
+@@ -28,6 +28,7 @@
+ #include <linux/i2c-algo-bit.h>
+ #include <linux/init.h>
+ #include <linux/smp_lock.h>
++#include <linux/kthread.h>
+
+ #include <media/tvaudio.h>
+ #include <media/v4l2-common.h>
+@@ -124,11 +125,8 @@ struct CHIPSTATE {
+ int input;
+
+ /* thread */
+- pid_t tpid;
+- struct completion texit;
+- wait_queue_head_t wq;
++ struct task_struct *thread;
+ struct timer_list wt;
+- int done;
+ int watch_stereo;
+ int audmode;
+ };
+@@ -264,28 +262,23 @@ static int chip_cmd(struct CHIPSTATE *ch
+ static void chip_thread_wake(unsigned long data)
+ {
+ struct CHIPSTATE *chip = (struct CHIPSTATE*)data;
+- wake_up_interruptible(&chip->wq);
++ wake_up_process(chip->thread);
+ }
+
+ static int chip_thread(void *data)
+ {
+- DECLARE_WAITQUEUE(wait, current);
+ struct CHIPSTATE *chip = data;
+ struct CHIPDESC *desc = chiplist + chip->type;
+
+- daemonize("%s", chip->c.name);
+- allow_signal(SIGTERM);
+ v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
+
+ for (;;) {
+- add_wait_queue(&chip->wq, &wait);
+- if (!chip->done) {
+- set_current_state(TASK_INTERRUPTIBLE);
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (!kthread_should_stop())
+ schedule();
+- }
+- remove_wait_queue(&chip->wq, &wait);
++ set_current_state(TASK_RUNNING);
+ try_to_freeze();
+- if (chip->done || signal_pending(current))
++ if (kthread_should_stop())
+ break;
+ v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
+
+@@ -301,7 +294,6 @@ static int chip_thread(void *data)
+ }
+
+ v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
+- complete_and_exit(&chip->texit, 0);
+ return 0;
+ }
+
+@@ -1536,19 +1528,18 @@ static int chip_attach(struct i2c_adapte
+ chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+ }
+
+- chip->tpid = -1;
++ chip->thread = NULL;
+ if (desc->checkmode) {
+ /* start async thread */
+ init_timer(&chip->wt);
+ chip->wt.function = chip_thread_wake;
+ chip->wt.data = (unsigned long)chip;
+- init_waitqueue_head(&chip->wq);
+- init_completion(&chip->texit);
+- chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
+- if (chip->tpid < 0)
+- v4l_warn(&chip->c, "%s: kernel_thread() failed\n",
++ chip->thread = kthread_run(chip_thread, chip, chip->c.name);
++ if (IS_ERR(chip->thread)) {
++ v4l_warn(&chip->c, "%s: failed to create kthread\n",
+ chip->c.name);
+- wake_up_interruptible(&chip->wq);
++ chip->thread = NULL;
++ }
+ }
+ return 0;
+ }
+@@ -1569,11 +1560,10 @@ static int chip_detach(struct i2c_client
+ struct CHIPSTATE *chip = i2c_get_clientdata(client);
+
+ del_timer_sync(&chip->wt);
+- if (chip->tpid >= 0) {
++ if (chip->thread) {
+ /* shutdown async thread */
+- chip->done = 1;
+- wake_up_interruptible(&chip->wq);
+- wait_for_completion(&chip->texit);
++ kthread_stop(chip->thread);
++ chip->thread = NULL;
+ }
+
+ i2c_detach_client(&chip->c);
+diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
+index d95529e..e6baaee 100644
+--- a/drivers/media/video/tveeprom.c
++++ b/drivers/media/video/tveeprom.c
+@@ -222,8 +222,8 @@ hauppauge_tuner[] =
+ { TUNER_TCL_2002MB, "TCL M2523_3DB_E"},
+ { TUNER_ABSENT, "Philips 8275A"},
+ { TUNER_ABSENT, "Microtune MT2060"},
+- { TUNER_ABSENT, "Philips FM1236 MK5"},
+- { TUNER_ABSENT, "Philips FM1216ME MK5"},
++ { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
++ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
+ { TUNER_ABSENT, "TCL M2523_3DI_E"},
+ { TUNER_ABSENT, "Samsung THPD5222FG30A"},
+ /* 120-129 */
+@@ -605,6 +605,8 @@ void tveeprom_hauppauge_analog(struct i2
+ tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
+ t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
+ }
++ }
++ for (i = j = 0; i < 8; i++) {
+ if (t_format2 & (1 << i)) {
+ tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
+ t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
+diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
+index b167ffa..bc0a4fc 100644
+--- a/drivers/media/video/tvp5150.c
++++ b/drivers/media/video/tvp5150.c
+@@ -294,7 +294,7 @@ static inline void tvp5150_selmux(struct
+ if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+ input = 8;
+
+- switch (input) {
++ switch (decoder->route.input) {
+ case TVP5150_COMPOSITE1:
+ input |= 2;
+ /* fall through */
+@@ -308,6 +308,11 @@ static inline void tvp5150_selmux(struct
+ break;
+ }
+
++ tvp5150_dbg( 1, "Selecting video route: route input=%i, output=%i "
++ "=> tvp5150 input=%i, opmode=%i\n",
++ decoder->route.input,decoder->route.output,
++ input, opmode );
++
+ tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
+ tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+ };
+diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
+index 6f31ecc..abe2146 100644
+--- a/drivers/media/video/usbvideo/konicawc.c
++++ b/drivers/media/video/usbvideo/konicawc.c
+@@ -222,6 +222,7 @@ static void konicawc_adjust_picture(stru
+ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
+ {
+ struct input_dev *input_dev;
++ int error;
+
+ usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+ strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+@@ -242,7 +243,13 @@ static void konicawc_register_input(stru
+
+ input_dev->private = cam;
+
+- input_register_device(cam->input);
++ error = input_register_device(cam->input);
++ if (error) {
++ warn("Failed to register camera's input device, err: %d\n",
++ error);
++ input_free_device(cam->input);
++ cam->input = NULL;
++ }
+ }
+
+ static void konicawc_unregister_input(struct konicawc *cam)
+@@ -380,7 +387,7 @@ static void resubmit_urb(struct uvd *uvd
+ }
+
+
+-static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
++static void konicawc_isoc_irq(struct urb *urb)
+ {
+ struct uvd *uvd = urb->context;
+ struct konicawc *cam = (struct konicawc *)uvd->user_data;
+diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
+index 56e01b6..9a26b94 100644
+--- a/drivers/media/video/usbvideo/quickcam_messenger.c
++++ b/drivers/media/video/usbvideo/quickcam_messenger.c
+@@ -125,7 +125,7 @@ static void qcm_report_buttonstat(struct
+ }
+ }
+
+-static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
++static void qcm_int_irq(struct urb *urb)
+ {
+ int ret;
+ struct uvd *uvd = urb->context;
+@@ -606,7 +606,7 @@ static void resubmit_urb(struct uvd *uvd
+ err("usb_submit_urb error (%d)", ret);
+ }
+
+-static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
++static void qcm_isoc_irq(struct urb *urb)
+ {
+ int len;
+ struct uvd *uvd = urb->context;
+diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
+index 13b37c8..d8b8802 100644
+--- a/drivers/media/video/usbvideo/usbvideo.c
++++ b/drivers/media/video/usbvideo/usbvideo.c
+@@ -1680,7 +1680,7 @@ static int usbvideo_CompressIsochronous(
+ return totlen;
+ }
+
+-static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs)
++static void usbvideo_IsocIrq(struct urb *urb)
+ {
+ int i, ret, len;
+ struct uvd *uvd = urb->context;
+diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
+index 90d48e8..08f9559 100644
+--- a/drivers/media/video/usbvideo/vicam.c
++++ b/drivers/media/video/usbvideo/vicam.c
+@@ -7,6 +7,7 @@
+ * Monroe Williams (monroe at pobox.com)
+ *
+ * Supports 3COM HomeConnect PC Digital WebCam
++ * Supports Compro PS39U WebCam
+ *
+ * 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
+@@ -60,6 +61,8 @@
+ /* Define these values to match your device */
+ #define USB_VICAM_VENDOR_ID 0x04c1
+ #define USB_VICAM_PRODUCT_ID 0x009d
++#define USB_COMPRO_VENDOR_ID 0x0602
++#define USB_COMPRO_PRODUCT_ID 0x1001
+
+ #define VICAM_BYTES_PER_PIXEL 3
+ #define VICAM_MAX_READ_SIZE (512*242+128)
+@@ -1254,6 +1257,7 @@ static struct video_device vicam_templat
+ /* table of devices that work with this driver */
+ static struct usb_device_id vicam_table[] = {
+ {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
++ {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
+ {} /* Terminating entry */
+ };
+
+diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
+index d7c3fcb..1d899e2 100644
+--- a/drivers/media/video/v4l1-compat.c
++++ b/drivers/media/video/v4l1-compat.c
+@@ -349,6 +349,8 @@ v4l_compat_translate_ioctl(struct inode
+ {
+ struct video_buffer *buffer = arg;
+
++ memset(buffer, 0, sizeof(*buffer));
++
+ err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
+ if (err < 0) {
+ dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n",err);
+@@ -361,7 +363,7 @@ v4l_compat_translate_ioctl(struct inode
+ switch (fbuf2.fmt.pixelformat) {
+ case V4L2_PIX_FMT_RGB332:
+ buffer->depth = 8;
+- break;
++ break;
+ case V4L2_PIX_FMT_RGB555:
+ buffer->depth = 15;
+ break;
+@@ -377,9 +379,13 @@ v4l_compat_translate_ioctl(struct inode
+ default:
+ buffer->depth = 0;
+ }
+- if (0 != fbuf2.fmt.bytesperline)
++ if (fbuf2.fmt.bytesperline) {
+ buffer->bytesperline = fbuf2.fmt.bytesperline;
+- else {
++ if (!buffer->depth && buffer->width)
++ buffer->depth = ((fbuf2.fmt.bytesperline<<3)
++ + (buffer->width-1) )
++ /buffer->width;
++ } else {
+ buffer->bytesperline =
+ (buffer->width * buffer->depth + 7) & 7;
+ buffer->bytesperline >>= 3;
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index 8d972ff..78d28b0 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -938,6 +938,7 @@ void v4l_printk_ioctl_arg(char *s,unsign
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ case VIDIOC_INT_I2S_CLOCK_FREQ:
+ case VIDIOC_INT_S_STANDBY:
++ case VIDIOC_INT_RESET:
+ {
+ u32 *p=arg;
+
+diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
+index 7ee8a53..f53edf1 100644
+--- a/drivers/media/video/video-buf-dvb.c
++++ b/drivers/media/video/video-buf-dvb.c
+@@ -223,6 +223,7 @@ fail_dmxdev:
+ fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+ fail_frontend:
++ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+ fail_adapter:
+ return result;
+@@ -236,6 +237,7 @@ void videobuf_dvb_unregister(struct vide
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
++ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+ }
+
+diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
+index acc5ea9..f429f49 100644
+--- a/drivers/media/video/video-buf.c
++++ b/drivers/media/video/video-buf.c
+@@ -365,7 +365,12 @@ videobuf_iolock(struct videobuf_queue* q
+ if (NULL == fbuf)
+ return -EINVAL;
+ /* FIXME: need sanity checks for vb->boff */
+- bus = (dma_addr_t)fbuf->base + vb->boff;
++ /*
++ * Using a double cast to avoid compiler warnings when
++ * building for PAE. Compiler doesn't like direct casting
++ * of a 32 bit ptr to 64 bit integer.
++ */
++ bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE,
+ bus, pages);
+diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
+index 88bf2af..d424a41 100644
+--- a/drivers/media/video/videodev.c
++++ b/drivers/media/video/videodev.c
+@@ -17,10 +17,11 @@
+ */
+
+ #define dbgarg(cmd, fmt, arg...) \
+- if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
++ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
+ printk (KERN_DEBUG "%s: ", vfd->name); \
+ v4l_printk_ioctl(cmd); \
+- printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
++ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
++ }
+
+ #define dbgarg2(fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+@@ -739,13 +740,13 @@ static int __video_do_ioctl(struct inode
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *p=arg;
+- if (!vfd->vidioc_qbuf)
++ if (!vfd->vidioc_dqbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+- ret=vfd->vidioc_qbuf(file, fh, p);
++ ret=vfd->vidioc_dqbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+@@ -836,7 +837,7 @@ static int __video_do_ioctl(struct inode
+ break;
+ }
+
+- if (index<=0 || index >= vfd->tvnormsize) {
++ if (index<0 || index >= vfd->tvnormsize) {
+ ret=-EINVAL;
+ break;
+ }
+@@ -1283,9 +1284,36 @@ static int __video_do_ioctl(struct inode
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+- if (!vfd->vidioc_g_parm)
+- break;
+- ret=vfd->vidioc_g_parm(file, fh, p);
++ if (vfd->vidioc_g_parm) {
++ ret=vfd->vidioc_g_parm(file, fh, p);
++ } else {
++ struct v4l2_standard s;
++ int i;
++
++ if (!vfd->tvnormsize) {
++ printk (KERN_WARNING "%s: no TV norms defined!\n",
++ vfd->name);
++ break;
++ }
++
++ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ for (i = 0; i < vfd->tvnormsize; i++)
++ if (vfd->tvnorms[i].id == vfd->current_norm)
++ break;
++ if (i >= vfd->tvnormsize)
++ return -EINVAL;
++
++ v4l2_video_std_construct(&s, vfd->current_norm,
++ vfd->tvnorms[i].name);
++
++ memset(p,0,sizeof(*p));
++
++ p->parm.capture.timeperframe = s.frameperiod;
++ ret=0;
++ }
++
+ dbgarg (cmd, "type=%d\n", p->type);
+ break;
+ }
+diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
+index 268e69f..6b6dff4 100644
+--- a/drivers/media/video/vino.c
++++ b/drivers/media/video/vino.c
+@@ -2325,7 +2325,7 @@ static void vino_capture_tasklet(unsigne
+ }
+ }
+
+-static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t vino_interrupt(int irq, void *dev_id)
+ {
+ u32 ctrl, intr;
+ unsigned int fc_a, fc_b;
+@@ -4404,7 +4404,6 @@ static struct video_device v4l_device_te
+ .name = "NOT SET",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+- .hardware = VID_HARDWARE_VINO,
+ .fops = &vino_fops,
+ .minor = -1,
+ };
+diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
+index 841884a..3c8dc72 100644
+--- a/drivers/media/video/vivi.c
++++ b/drivers/media/video/vivi.c
+@@ -272,7 +272,7 @@ static void gen_line(struct sg_to_addr t
+
+ /* Get first addr pointed to pixel position */
+ oldpg=get_addr_pos(pos,pages,to_addr);
+- pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT);
++ pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
+ basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
+
+ /* We will just duplicate the second pixel at the packet */
+@@ -287,7 +287,7 @@ static void gen_line(struct sg_to_addr t
+ for (color=0;color<4;color++) {
+ pgpos=get_addr_pos(pos,pages,to_addr);
+ if (pgpos!=oldpg) {
+- pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT);
++ pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
+ kunmap_atomic(basep, KM_BOUNCE_READ);
+ basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
+ oldpg=pgpos;
+@@ -339,8 +339,8 @@ static void gen_line(struct sg_to_addr t
+ for (color=0;color<4;color++) {
+ pgpos=get_addr_pos(pos,pages,to_addr);
+ if (pgpos!=oldpg) {
+- pg=pfn_to_page(to_addr[pgpos].
+- sg->dma_address
++ pg=pfn_to_page(sg_dma_address(
++ to_addr[pgpos].sg)
+ >> PAGE_SHIFT);
+ kunmap_atomic(basep,
+ KM_BOUNCE_READ);
+@@ -386,7 +386,7 @@ static void vivi_fillbuff(struct vivi_de
+ struct timeval ts;
+
+ /* Test if DMA mapping is ready */
+- if (!vb->dma.sglist[0].dma_address)
++ if (!sg_dma_address(&vb->dma.sglist[0]))
+ return;
+
+ prep_to_addr(to_addr,vb);
+@@ -783,7 +783,7 @@ static int vivi_map_sg(void *dev, struct
+ for (i = 0; i < nents; i++ ) {
+ BUG_ON(!sg[i].page);
+
+- sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
++ sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
+ }
+
+ return nents;
+@@ -992,7 +992,8 @@ static int vidiocgmbuf (struct file *fil
+ struct vivi_fh *fh=priv;
+ struct videobuf_queue *q=&fh->vb_vidq;
+ struct v4l2_requestbuffers req;
+- unsigned int i, ret;
++ unsigned int i;
++ int ret;
+
+ req.type = q->type;
+ req.count = 8;
+@@ -1359,6 +1360,8 @@ static int __init vivi_init(void)
+ dev->vidq.timeout.data = (unsigned long)dev;
+ init_timer(&dev->vidq.timeout);
+
++ vivi.current_norm = tvnorms[0].id;
++
+ ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
+ printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
+ return ret;
+diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
+index 1eca7e6..8ef31ed 100644
+--- a/drivers/media/video/vpx3220.c
++++ b/drivers/media/video/vpx3220.c
+@@ -744,6 +744,6 @@ vpx3220_cleanup (void)
+ module_init(vpx3220_init);
+ module_exit(vpx3220_cleanup);
+
+-MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video encoder driver");
++MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
+ MODULE_AUTHOR("Laurent Pinchart");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
+index 20f211b..ddce2fb 100644
+--- a/drivers/media/video/w9968cf.c
++++ b/drivers/media/video/w9968cf.c
+@@ -417,7 +417,7 @@ static int w9968cf_write_fsb(struct w996
+ static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
+ static int w9968cf_read_sb(struct w9968cf_device*);
+ static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
+-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
++static void w9968cf_urb_complete(struct urb *urb);
+
+ /* Low-level I2C (SMBus) I/O */
+ static int w9968cf_smbus_start(struct w9968cf_device*);
+@@ -586,15 +586,14 @@ static struct w9968cf_symbolic_list urb_
+ { -EFBIG, "Too much ISO frames requested" },
+ { -ENOSR, "Buffer error (overrun)" },
+ { -EPIPE, "Specified endpoint is stalled (device not responding)"},
+- { -EOVERFLOW, "Babble (bad cable?)" },
++ { -EOVERFLOW, "Babble (too much data)" },
+ { -EPROTO, "Bit-stuff error (bad cable?)" },
+ { -EILSEQ, "CRC/Timeout" },
+- { -ETIMEDOUT, "NAK (device does not respond)" },
++ { -ETIME, "Device does not respond to token" },
++ { -ETIMEDOUT, "Device does not respond to command" },
+ { -1, NULL }
+ };
+
+-
+-
+ /****************************************************************************
+ * Memory management functions *
+ ****************************************************************************/
+@@ -782,7 +781,7 @@ static int w9968cf_allocate_memory(struc
+ If there are no requested frames in the FIFO list, packets are collected into
+ a temporary buffer.
+ --------------------------------------------------------------------------*/
+-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
++static void w9968cf_urb_complete(struct urb *urb)
+ {
+ struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
+ struct w9968cf_frame_t** f;
+diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
+index 1b2be2d..5b55634 100644
+--- a/drivers/media/video/zc0301/zc0301_core.c
++++ b/drivers/media/video/zc0301/zc0301_core.c
+@@ -303,7 +303,7 @@ int zc0301_i2c_write(struct zc0301_devic
+
+ /*****************************************************************************/
+
+-static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
++static void zc0301_urb_complete(struct urb *urb)
+ {
+ struct zc0301_device* cam = urb->context;
+ struct zc0301_frame_t** f;
+diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
+index f2249ed..653822c 100644
+--- a/drivers/media/video/zoran_card.c
++++ b/drivers/media/video/zoran_card.c
+@@ -820,7 +820,6 @@ static struct i2c_algo_bit_data zoran_i2
+ .getsda = zoran_i2c_getsda,
+ .getscl = zoran_i2c_getscl,
+ .udelay = 10,
+- .mdelay = 0,
+ .timeout = 100,
+ };
+
+@@ -1279,9 +1278,7 @@ find_zr36057 (void)
+
+ zoran_num = 0;
+ while (zoran_num < BUZ_MAX &&
+- (dev =
+- pci_find_device(PCI_VENDOR_ID_ZORAN,
+- PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
++ (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
+ card_num = card[zoran_num];
+ zr = &zoran[zoran_num];
+ memset(zr, 0, sizeof(struct zoran)); // Just in case if previous cycle failed
+@@ -1542,7 +1539,8 @@ find_zr36057 (void)
+ goto zr_detach_vfe;
+ }
+ }
+-
++ /* Success so keep the pci_dev referenced */
++ pci_dev_get(zr->pci_dev);
+ zoran_num++;
+ continue;
+
+@@ -1564,6 +1562,9 @@ find_zr36057 (void)
+ iounmap(zr->zr36057_mem);
+ continue;
+ }
++ if (dev) /* Clean up ref count on early exit */
++ pci_dev_put(dev);
++
+ if (zoran_num == 0) {
+ dprintk(1, KERN_INFO "No known MJPEG cards found.\n");
+ }
+@@ -1621,10 +1622,10 @@ init_dc10_cards (void)
+ dprintk(5, KERN_DEBUG "Jotti is een held!\n");
+
+ /* some mainboards might not do PCI-PCI data transfer well */
+- if (pci_pci_problems & PCIPCI_FAIL) {
++ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
+ dprintk(1,
+ KERN_WARNING
+- "%s: chipset may not support reliable PCI-PCI DMA\n",
++ "%s: chipset does not support reliable PCI-PCI DMA\n",
+ ZORAN_NAME);
+ }
+
+@@ -1632,7 +1633,7 @@ init_dc10_cards (void)
+ for (i = 0; i < zoran_num; i++) {
+ struct zoran *zr = &zoran[i];
+
+- if (pci_pci_problems & PCIPCI_NATOMA && zr->revision <= 1) {
++ if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
+ zr->jpg_buffers.need_contiguous = 1;
+ dprintk(1,
+ KERN_INFO
+diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
+index 3cbac2e..168e431 100644
+--- a/drivers/media/video/zoran_device.c
++++ b/drivers/media/video/zoran_device.c
+@@ -1408,15 +1408,14 @@ error_handler (struct zoran *zr,
+
+ irqreturn_t
+ zoran_irq (int irq,
+- void *dev_id,
+- struct pt_regs *regs)
++ void *dev_id)
+ {
+ u32 stat, astat;
+ int count;
+ struct zoran *zr;
+ unsigned long flags;
+
+- zr = (struct zoran *) dev_id;
++ zr = dev_id;
+ count = 0;
+
+ if (zr->testing) {
+diff --git a/drivers/media/video/zoran_device.h b/drivers/media/video/zoran_device.h
+index f19705c..37fa86a 100644
+--- a/drivers/media/video/zoran_device.h
++++ b/drivers/media/video/zoran_device.h
+@@ -64,9 +64,7 @@ extern int wait_grab_pending(struct zora
+ /* interrupts */
+ extern void print_interrupts(struct zoran *zr);
+ extern void clear_interrupt_counters(struct zoran *zr);
+-extern irqreturn_t zoran_irq(int irq,
+- void *dev_id,
+- struct pt_regs *regs);
++extern irqreturn_t zoran_irq(int irq, void *dev_id);
+
+ /* JPEG codec access */
+ extern void jpeg_start(struct zoran *zr);
+diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
+index 5f90db2..862a984 100644
+--- a/drivers/media/video/zoran_driver.c
++++ b/drivers/media/video/zoran_driver.c
+@@ -1512,6 +1512,13 @@ setup_fbuffer (struct file
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
++ /* Don't allow frame buffer overlay if PCI or AGP is buggy, or on
++ ALi Magik (that needs very low latency while the card needs a
++ higher value always) */
++
++ if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK))
++ return -ENXIO;
++
+ /* we need a bytesperline value, even if not given */
+ if (!bytesperline)
+ bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
+diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
+index 5043738..0cbf564 100644
+--- a/drivers/media/video/zr36120.c
++++ b/drivers/media/video/zr36120.c
+@@ -335,13 +335,13 @@ DEBUG(printk(CARD_DEBUG "turning off\n",
+ }
+
+ static
+-void zoran_irq(int irq, void *dev_id, struct pt_regs * regs)
++void zoran_irq(int irq, void *dev_id)
+ {
+ u32 stat,estat;
+ int count = 0;
+ struct zoran *ztv = dev_id;
+
+- UNUSED(irq); UNUSED(regs);
++ UNUSED(irq);
+ for (;;) {
+ /* get/clear interrupt status bits */
+ stat=zrread(ZORAN_ISR);
+@@ -987,6 +987,8 @@ int zoran_ioctl(struct video_device* dev
+ VID_TYPE_SCALES;
+ if (ztv->have_tuner)
+ c.type |= VID_TYPE_TUNER;
++ if (pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
++ c.type &= ~VID_TYPE_OVERLAY;
+ if (ztv->have_decoder) {
+ c.channels = ztv->card->video_inputs;
+ c.audios = ztv->card->audio_inputs;
+@@ -1284,6 +1286,8 @@ int zoran_ioctl(struct video_device* dev
+ struct video_buffer v;
+ if(!capable(CAP_SYS_ADMIN))
+ return -EPERM;
++ if (pcipci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
++ return -ENXIO;
+ if (copy_from_user(&v, arg,sizeof(v)))
+ return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
+@@ -1836,16 +1840,16 @@ int __init find_zoran(void)
+ struct zoran *ztv;
+ struct pci_dev *dev = NULL;
+ unsigned char revision;
+- int zoran_num=0;
++ int zoran_num = 0;
+
+- while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
++ while ((dev = pci_get_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
+ {
+ /* Ok, a ZR36120/ZR36125 found! */
+ ztv = &zorans[zoran_num];
+ ztv->dev = dev;
+
+ if (pci_enable_device(dev))
+- return -EIO;
++ continue;
+
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
+ printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
+@@ -1863,17 +1867,18 @@ int __init find_zoran(void)
+ {
+ iounmap(ztv->zoran_mem);
+ printk(KERN_ERR "zoran: Bad irq number or handler\n");
+- return -EINVAL;
++ continue;
+ }
+ if (result==-EBUSY)
+ printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq);
+ if (result < 0) {
+ iounmap(ztv->zoran_mem);
+- return result;
++ continue;
+ }
+ /* Enable bus-mastering */
+ pci_set_master(dev);
+-
++ /* Keep a reference */
++ pci_dev_get(dev);
+ zoran_num++;
+ }
+ if(zoran_num)
+@@ -2030,13 +2035,16 @@ void release_zoran(int max)
+ /* free it */
+ free_irq(ztv->dev->irq,ztv);
+
+- /* unregister i2c_bus */
++ /* unregister i2c_bus */
+ i2c_unregister_bus((&ztv->i2c));
+
+ /* unmap and free memory */
+ if (ztv->zoran_mem)
+ iounmap(ztv->zoran_mem);
+
++ /* Drop PCI device */
++ pci_dev_put(ztv->dev);
++
+ video_unregister_device(&ztv->video_dev);
+ video_unregister_device(&ztv->vbi_dev);
+ }
+@@ -2053,13 +2061,12 @@ int __init zr36120_init(void)
+
+ handle_chipset();
+ zoran_cards = find_zoran();
+- if (zoran_cards<0)
+- /* no cards found, no need for a driver */
++ if (zoran_cards <= 0)
+ return -EIO;
+
+ /* initialize Zorans */
+ for (card=0; card<zoran_cards; card++) {
+- if (init_zoran(card)<0) {
++ if (init_zoran(card) < 0) {
+ /* only release the zorans we have registered */
+ release_zoran(card);
+ return -EIO;
+diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
+index 048b5b8..bb2bf5a 100644
+--- a/drivers/message/fusion/linux_compat.h
++++ b/drivers/message/fusion/linux_compat.h
+@@ -6,13 +6,4 @@
+ #include <linux/version.h>
+ #include <scsi/scsi_device.h>
+
+-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6))
+-static int inline scsi_device_online(struct scsi_device *sdev)
+-{
+- return sdev->online;
+-}
+-#endif
+-
+-
+-/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ #endif /* _LINUX_COMPAT_H */
+diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
+index 29d0635..e5c7271 100644
+--- a/drivers/message/fusion/mptbase.c
++++ b/drivers/message/fusion/mptbase.c
+@@ -122,7 +122,7 @@ static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq
+ /*
+ * Forward protos...
+ */
+-static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
++static irqreturn_t mpt_interrupt(int irq, void *bus_id);
+ static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+ static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
+ u32 *req, int replyBytes, u16 *u16reply, int maxwait,
+@@ -351,7 +351,6 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+ * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
+ * @irq: irq number (not used)
+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+- * @r: pt_regs pointer (not used)
+ *
+ * This routine is registered via the request_irq() kernel API call,
+ * and handles all interrupts generated from a specific MPT adapter
+@@ -365,7 +364,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+ * the protocol-specific details of the MPT request completion.
+ */
+ static irqreturn_t
+-mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
++mpt_interrupt(int irq, void *bus_id)
+ {
+ MPT_ADAPTER *ioc = bus_id;
+ u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
+diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
+index c537d71..a4afad4 100644
+--- a/drivers/message/fusion/mptbase.h
++++ b/drivers/message/fusion/mptbase.h
+@@ -75,8 +75,8 @@
+ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
+ #endif
+
+-#define MPT_LINUX_VERSION_COMMON "3.04.01"
+-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.01"
++#define MPT_LINUX_VERSION_COMMON "3.04.02"
++#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.02"
+ #define WHAT_MAGIC_STRING "@" "(" "#" ")"
+
+ #define show_mptmod_ver(s,ver) \
+diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
+index 85696f3..1dd4917 100644
+--- a/drivers/message/fusion/mptfc.c
++++ b/drivers/message/fusion/mptfc.c
+@@ -96,6 +96,10 @@ static int mptfc_qcmd(struct scsi_cmnd *
+ static void mptfc_target_destroy(struct scsi_target *starget);
+ static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
+ static void __devexit mptfc_remove(struct pci_dev *pdev);
++static int mptfc_abort(struct scsi_cmnd *SCpnt);
++static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);
++static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);
++static int mptfc_host_reset(struct scsi_cmnd *SCpnt);
+
+ static struct scsi_host_template mptfc_driver_template = {
+ .module = THIS_MODULE,
+@@ -110,10 +114,10 @@ static struct scsi_host_template mptfc_d
+ .target_destroy = mptfc_target_destroy,
+ .slave_destroy = mptscsih_slave_destroy,
+ .change_queue_depth = mptscsih_change_queue_depth,
+- .eh_abort_handler = mptscsih_abort,
+- .eh_device_reset_handler = mptscsih_dev_reset,
+- .eh_bus_reset_handler = mptscsih_bus_reset,
+- .eh_host_reset_handler = mptscsih_host_reset,
++ .eh_abort_handler = mptfc_abort,
++ .eh_device_reset_handler = mptfc_dev_reset,
++ .eh_bus_reset_handler = mptfc_bus_reset,
++ .eh_host_reset_handler = mptfc_host_reset,
+ .bios_param = mptscsih_bios_param,
+ .can_queue = MPT_FC_CAN_QUEUE,
+ .this_id = -1,
+@@ -162,9 +166,86 @@ static struct fc_function_template mptfc
+ .show_starget_port_id = 1,
+ .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+-
++ .show_host_supported_speeds = 1,
++ .show_host_maxframe_size = 1,
++ .show_host_speed = 1,
++ .show_host_fabric_name = 1,
++ .show_host_port_type = 1,
++ .show_host_port_state = 1,
++ .show_host_symbolic_name = 1,
+ };
+
++static int
++mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
++ int (*func)(struct scsi_cmnd *SCpnt),
++ const char *caller)
++{
++ struct scsi_device *sdev = SCpnt->device;
++ struct Scsi_Host *shost = sdev->host;
++ struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
++ unsigned long flags;
++ int ready;
++
++ spin_lock_irqsave(shost->host_lock, flags);
++ while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
++ spin_unlock_irqrestore(shost->host_lock, flags);
++ dfcprintk ((MYIOC_s_INFO_FMT
++ "mptfc_block_error_handler.%d: %d:%d, port status is "
++ "DID_IMM_RETRY, deferring %s recovery.\n",
++ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
++ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
++ SCpnt->device->id,SCpnt->device->lun,caller));
++ msleep(1000);
++ spin_lock_irqsave(shost->host_lock, flags);
++ }
++ spin_unlock_irqrestore(shost->host_lock, flags);
++
++ if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
++ dfcprintk ((MYIOC_s_INFO_FMT
++ "%s.%d: %d:%d, failing recovery, "
++ "port state %d, vdev %p.\n", caller,
++ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
++ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
++ SCpnt->device->id,SCpnt->device->lun,ready,
++ SCpnt->device->hostdata));
++ return FAILED;
++ }
++ dfcprintk ((MYIOC_s_INFO_FMT
++ "%s.%d: %d:%d, executing recovery.\n", caller,
++ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
++ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
++ SCpnt->device->id,SCpnt->device->lun));
++ return (*func)(SCpnt);
++}
++
++static int
++mptfc_abort(struct scsi_cmnd *SCpnt)
++{
++ return
++ mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
++}
++
++static int
++mptfc_dev_reset(struct scsi_cmnd *SCpnt)
++{
++ return
++ mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
++}
++
++static int
++mptfc_bus_reset(struct scsi_cmnd *SCpnt)
++{
++ return
++ mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
++}
++
++static int
++mptfc_host_reset(struct scsi_cmnd *SCpnt)
++{
++ return
++ mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
++}
++
+ static void
+ mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+ {
+@@ -556,6 +637,12 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void
+ return 0;
+ }
+
++ if (!SCpnt->device->hostdata) { /* vdev */
++ SCpnt->result = DID_NO_CONNECT << 16;
++ done(SCpnt);
++ return 0;
++ }
++
+ /* dd_data is null until finished adding target */
+ ri = *((struct mptfc_rport_info **)rport->dd_data);
+ if (unlikely(!ri)) {
+@@ -839,33 +926,95 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE
+ static void
+ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
+ {
+- unsigned class = 0, cos = 0;
++ unsigned class = 0;
++ unsigned cos = 0;
++ unsigned speed;
++ unsigned port_type;
++ unsigned port_state;
++ FCPortPage0_t *pp0;
++ struct Scsi_Host *sh;
++ char *sn;
+
+ /* don't know what to do as only one scsi (fc) host was allocated */
+ if (portnum != 0)
+ return;
+
+- class = ioc->fc_port_page0[portnum].SupportedServiceClass;
++ pp0 = &ioc->fc_port_page0[portnum];
++ sh = ioc->sh;
++
++ sn = fc_host_symbolic_name(sh);
++ snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
++ ioc->prod_name,
++ MPT_FW_REV_MAGIC_ID_STRING,
++ ioc->facts.FWVersion.Word);
++
++ fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
++
++ fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
++
++ fc_host_node_name(sh) =
++ (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
++
++ fc_host_port_name(sh) =
++ (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
++
++ fc_host_port_id(sh) = pp0->PortIdentifier;
++
++ class = pp0->SupportedServiceClass;
+ if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
+ cos |= FC_COS_CLASS1;
+ if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
+ cos |= FC_COS_CLASS2;
+ if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
+ cos |= FC_COS_CLASS3;
++ fc_host_supported_classes(sh) = cos;
++
++ if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
++ speed = FC_PORTSPEED_1GBIT;
++ else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
++ speed = FC_PORTSPEED_2GBIT;
++ else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
++ speed = FC_PORTSPEED_4GBIT;
++ else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
++ speed = FC_PORTSPEED_10GBIT;
++ else
++ speed = FC_PORTSPEED_UNKNOWN;
++ fc_host_speed(sh) = speed;
++
++ speed = 0;
++ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
++ speed |= FC_PORTSPEED_1GBIT;
++ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
++ speed |= FC_PORTSPEED_2GBIT;
++ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
++ speed |= FC_PORTSPEED_4GBIT;
++ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
++ speed |= FC_PORTSPEED_10GBIT;
++ fc_host_supported_speeds(sh) = speed;
++
++ port_state = FC_PORTSTATE_UNKNOWN;
++ if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
++ port_state = FC_PORTSTATE_ONLINE;
++ else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
++ port_state = FC_PORTSTATE_LINKDOWN;
++ fc_host_port_state(sh) = port_state;
++
++ port_type = FC_PORTTYPE_UNKNOWN;
++ if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
++ port_type = FC_PORTTYPE_PTP;
++ else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
++ port_type = FC_PORTTYPE_LPORT;
++ else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
++ port_type = FC_PORTTYPE_NLPORT;
++ else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
++ port_type = FC_PORTTYPE_NPORT;
++ fc_host_port_type(sh) = port_type;
++
++ fc_host_fabric_name(sh) =
++ (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
++ (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
++ (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
+
+- fc_host_node_name(ioc->sh) =
+- (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
+- | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
+-
+- fc_host_port_name(ioc->sh) =
+- (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
+- | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
+-
+- fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
+-
+- fc_host_supported_classes(ioc->sh) = cos;
+-
+- fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
+ }
+
+ static void
+diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
+index f66f220..b752a47 100644
+--- a/drivers/message/fusion/mptsas.c
++++ b/drivers/message/fusion/mptsas.c
+@@ -852,6 +852,10 @@ static int mptsas_get_linkerrors(struct
+ dma_addr_t dma_handle;
+ int error;
+
++ /* FIXME: only have link errors on local phys */
++ if (!scsi_is_sas_phy_local(phy))
++ return -EINVAL;
++
+ hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 1 /* page number 1*/;
+@@ -924,6 +928,10 @@ static int mptsas_phy_reset(struct sas_p
+ unsigned long timeleft;
+ int error = -ERESTARTSYS;
+
++ /* FIXME: fusion doesn't allow non-local phy reset */
++ if (!scsi_is_sas_phy_local(phy))
++ return -EINVAL;
++
+ /* not implemented for expanders */
+ if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
+ return -ENXIO;
+@@ -1570,9 +1578,6 @@ static int mptsas_probe_one_phy(struct d
+
+ if (!phy_info->phy) {
+
+- if (local)
+- phy->local_attached = 1;
+-
+ error = sas_phy_add(phy);
+ if (error) {
+ sas_phy_free(phy);
+@@ -1642,14 +1647,18 @@ static int mptsas_probe_one_phy(struct d
+
+ for (i = 0; i < port_info->num_phys; i++)
+ if (port_info->phy_info[i].identify.sas_address ==
+- identify.sas_address)
++ identify.sas_address) {
++ sas_port_mark_backlink(port);
+ goto out;
++ }
+
+ } else if (scsi_is_sas_rphy(parent)) {
+ struct sas_rphy *parent_rphy = dev_to_rphy(parent);
+ if (identify.sas_address ==
+- parent_rphy->identify.sas_address)
++ parent_rphy->identify.sas_address) {
++ sas_port_mark_backlink(port);
+ goto out;
++ }
+ }
+
+ switch (identify.device_type) {
+diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
+index fef6771..6443392 100644
+--- a/drivers/message/i2o/Kconfig
++++ b/drivers/message/i2o/Kconfig
+@@ -88,7 +88,7 @@ config I2O_BUS
+
+ config I2O_BLOCK
+ tristate "I2O Block OSM"
+- depends on I2O
++ depends on I2O && BLOCK
+ ---help---
+ Include support for the I2O Block OSM. The Block OSM presents disk
+ and other structured block devices to the operating system. If you
+diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c
+index ac06f10..d96c687 100644
+--- a/drivers/message/i2o/bus-osm.c
++++ b/drivers/message/i2o/bus-osm.c
+@@ -80,18 +80,26 @@ static DEVICE_ATTR(scan, S_IWUSR, NULL,
+ * @dev: device to verify if it is a I2O Bus Adapter device
+ *
+ * Because we want all Bus Adapters always return 0.
++ * Except when we fail. Then we are sad.
+ *
+- * Returns 0.
++ * Returns 0, except when we fail to excel.
+ */
+ static int i2o_bus_probe(struct device *dev)
+ {
+ struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
++ int rc;
+
+- device_create_file(dev, &dev_attr_scan);
++ rc = device_create_file(dev, &dev_attr_scan);
++ if (rc)
++ goto err_out;
+
+ osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+ return 0;
++
++err_out:
++ put_device(dev);
++ return rc;
+ };
+
+ /**
+diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
+index 7bd4d85..a235064 100644
+--- a/drivers/message/i2o/exec-osm.c
++++ b/drivers/message/i2o/exec-osm.c
+@@ -124,10 +124,10 @@ static void i2o_exec_wait_free(struct i2
+ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
+ unsigned long timeout, struct i2o_dma *dma)
+ {
+- DECLARE_WAIT_QUEUE_HEAD(wq);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+ struct i2o_exec_wait *wait;
+ static u32 tcntxt = 0x80000000;
+- long flags;
++ unsigned long flags;
+ int rc = 0;
+
+ wait = i2o_exec_wait_alloc();
+@@ -325,13 +325,24 @@ static DEVICE_ATTR(product_id, S_IRUGO,
+ static int i2o_exec_probe(struct device *dev)
+ {
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
++ int rc;
+
+- i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
++ rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
++ if (rc) goto err_out;
+
+- device_create_file(dev, &dev_attr_vendor_id);
+- device_create_file(dev, &dev_attr_product_id);
++ rc = device_create_file(dev, &dev_attr_vendor_id);
++ if (rc) goto err_evtreg;
++ rc = device_create_file(dev, &dev_attr_product_id);
++ if (rc) goto err_vid;
+
+ return 0;
++
++err_vid:
++ device_remove_file(dev, &dev_attr_vendor_id);
++err_evtreg:
++ i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
++err_out:
++ return rc;
+ };
+
+ /**
+diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
+index 1ddc2fb..eaba81b 100644
+--- a/drivers/message/i2o/i2o_block.c
++++ b/drivers/message/i2o/i2o_block.c
+@@ -390,9 +390,9 @@ static int i2o_block_prep_req_fn(struct
+ }
+
+ /* request is already processed by us, so return */
+- if (req->flags & REQ_SPECIAL) {
++ if (blk_special_request(req)) {
+ osm_debug("REQ_SPECIAL already set!\n");
+- req->flags |= REQ_DONTPREP;
++ req->cmd_flags |= REQ_DONTPREP;
+ return BLKPREP_OK;
+ }
+
+@@ -411,7 +411,8 @@ static int i2o_block_prep_req_fn(struct
+ ireq = req->special;
+
+ /* do not come back here */
+- req->flags |= REQ_DONTPREP | REQ_SPECIAL;
++ req->cmd_type = REQ_TYPE_SPECIAL;
++ req->cmd_flags |= REQ_DONTPREP;
+
+ return BLKPREP_OK;
+ };
+diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
+index 1b58444..62f1ac0 100644
+--- a/drivers/message/i2o/pci.c
++++ b/drivers/message/i2o/pci.c
+@@ -224,12 +224,11 @@ static int __devinit i2o_pci_alloc(struc
+ * i2o_pci_interrupt - Interrupt handler for I2O controller
+ * @irq: interrupt line
+ * @dev_id: pointer to the I2O controller
+- * @r: pointer to registers
+ *
+ * Handle an interrupt from a PCI based I2O controller. This turns out
+ * to be rather simple. We keep the controller pointer in the cookie.
+ */
+-static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
++static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id)
+ {
+ struct i2o_controller *c = dev_id;
+ u32 m;
+@@ -372,12 +371,13 @@ static int __devinit i2o_pci_probe(struc
+ * Expose the ship behind i960 for initialization, or it will
+ * failed
+ */
+- i960 =
+- pci_find_slot(c->pdev->bus->number,
++ i960 = pci_get_slot(c->pdev->bus,
+ PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
+
+- if (i960)
++ if (i960) {
+ pci_write_config_word(i960, 0x42, 0);
++ pci_dev_put(i960);
++ }
+
+ c->promise = 1;
+ c->limit_sectors = 1;
+diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
+index 2bf3272..149810a 100644
+--- a/drivers/mfd/ucb1x00-core.c
++++ b/drivers/mfd/ucb1x00-core.c
+@@ -203,7 +203,7 @@ void ucb1x00_adc_disable(struct ucb1x00
+ * SIBCLK to talk to the chip. We leave the clock running until
+ * we have finished processing all interrupts from the chip.
+ */
+-static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
+ {
+ struct ucb1x00 *ucb = devid;
+ struct ucb1x00_irq *irq;
+diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
+index 0277681..82938ad 100644
+--- a/drivers/mfd/ucb1x00-ts.c
++++ b/drivers/mfd/ucb1x00-ts.c
+@@ -58,6 +58,7 @@ static int adcsync;
+ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
+ {
+ struct input_dev *idev = ts->idev;
++
+ input_report_abs(idev, ABS_X, x);
+ input_report_abs(idev, ABS_Y, y);
+ input_report_abs(idev, ABS_PRESSURE, pressure);
+@@ -67,6 +68,7 @@ static inline void ucb1x00_ts_evt_add(st
+ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
+ {
+ struct input_dev *idev = ts->idev;
++
+ input_report_abs(idev, ABS_PRESSURE, 0);
+ input_sync(idev);
+ }
+@@ -189,6 +191,7 @@ static inline unsigned int ucb1x00_ts_re
+ static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
+ {
+ unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
++
+ if (machine_is_collie())
+ return (!(val & (UCB_TS_CR_TSPX_LOW)));
+ else
+@@ -291,6 +294,7 @@ static int ucb1x00_thread(void *_ts)
+ static void ucb1x00_ts_irq(int idx, void *id)
+ {
+ struct ucb1x00_ts *ts = id;
++
+ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+ wake_up(&ts->irq_wait);
+ }
+@@ -372,36 +376,43 @@ static int ucb1x00_ts_resume(struct ucb1
+ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
+ {
+ struct ucb1x00_ts *ts;
++ struct input_dev *idev;
++ int err;
+
+ ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
+- if (!ts)
+- return -ENOMEM;
+-
+- ts->idev = input_allocate_device();
+- if (!ts->idev) {
+- kfree(ts);
+- return -ENOMEM;
++ idev = input_allocate_device();
++ if (!ts || !idev) {
++ err = -ENOMEM;
++ goto fail;
+ }
+
+ ts->ucb = dev->ucb;
++ ts->idev = idev;
+ ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
+
+- ts->idev->private = ts;
+- ts->idev->name = "Touchscreen panel";
+- ts->idev->id.product = ts->ucb->id;
+- ts->idev->open = ucb1x00_ts_open;
+- ts->idev->close = ucb1x00_ts_close;
++ idev->private = ts;
++ idev->name = "Touchscreen panel";
++ idev->id.product = ts->ucb->id;
++ idev->open = ucb1x00_ts_open;
++ idev->close = ucb1x00_ts_close;
+
+- __set_bit(EV_ABS, ts->idev->evbit);
+- __set_bit(ABS_X, ts->idev->absbit);
+- __set_bit(ABS_Y, ts->idev->absbit);
+- __set_bit(ABS_PRESSURE, ts->idev->absbit);
++ __set_bit(EV_ABS, idev->evbit);
++ __set_bit(ABS_X, idev->absbit);
++ __set_bit(ABS_Y, idev->absbit);
++ __set_bit(ABS_PRESSURE, idev->absbit);
+
+- input_register_device(ts->idev);
++ err = input_register_device(idev);
++ if (err)
++ goto fail;
+
+ dev->priv = ts;
+
+ return 0;
++
++ fail:
++ input_free_device(idev);
++ kfree(ts);
++ return err;
+ }
+
+ static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 7fc692a..00db31c 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -18,7 +18,7 @@ config IBM_ASM
+ service processor board as a regular serial port. To make use of
+ this feature serial driver support (CONFIG_SERIAL_8250) must be
+ enabled.
+-
++
+ WARNING: This software may not be supported or function
+ correctly on your IBM server. Please consult the IBM ServerProven
+ website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for
+@@ -28,5 +28,64 @@ config IBM_ASM
+
+ If unsure, say N.
+
+-endmenu
++config SGI_IOC4
++ tristate "SGI IOC4 Base IO support"
++ depends on PCI
++ ---help---
++ This option enables basic support for the IOC4 chip on certain
++ SGI IO controller cards (IO9, IO10, and PCI-RT). This option
++ does not enable any specific functions on such a card, but provides
++ necessary infrastructure for other drivers to utilize.
++
++ If you have an SGI Altix with an IOC4-based card say Y.
++ Otherwise say N.
++
++config TIFM_CORE
++ tristate "TI Flash Media interface support (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ help
++ If you want support for Texas Instruments(R) Flash Media adapters
++ you should select this option and then also choose an appropriate
++ host adapter, such as 'TI Flash Media PCI74xx/PCI76xx host adapter
++ support', if you have a TI PCI74xx compatible card reader, for
++ example.
++ You will also have to select some flash card format drivers. MMC/SD
++ cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD
++ Interface support (MMC_TIFM_SD)'.
++
++ To compile this driver as a module, choose M here: the module will
++ be called tifm_core.
++
++config TIFM_7XX1
++ tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
++ depends on PCI && TIFM_CORE && EXPERIMENTAL
++ default TIFM_CORE
++ help
++ This option enables support for Texas Instruments(R) PCI74xx and
++ PCI76xx families of Flash Media adapters, found in many laptops.
++ To make actual use of the device, you will have to select some
++ flash card format drivers, as outlined in the TIFM_CORE Help.
+
++ To compile this driver as a module, choose M here: the module will
++ be called tifm_7xx1.
++
++config MSI_LAPTOP
++ tristate "MSI Laptop Extras"
++ depends on X86
++ depends on ACPI_EC
++ depends on BACKLIGHT_CLASS_DEVICE
++ ---help---
++ This is a driver for laptops built by MSI (MICRO-STAR
++ INTERNATIONAL):
++
++ MSI MegaBook S270 (MS-1013)
++ Cytron/TCM/Medion/Tchibo MD96100/SAM2000
++
++ It adds support for Bluetooth, WLAN and LCD brightness control.
++
++ More information about this driver is available at
++ <http://0pointer.de/lennart/tchibo.html>.
++
++ If you have an MSI S270 laptop, say Y or M here.
++
++endmenu
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 19c2b85..c9e98ab 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -3,5 +3,10 @@
+ #
+ obj- := misc.o # Dummy rule to force built-in.o to be made
+
+-obj-$(CONFIG_IBM_ASM) += ibmasm/
++obj-$(CONFIG_IBM_ASM) += ibmasm/
+ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
++obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
++obj-$(CONFIG_LKDTM) += lkdtm.o
++obj-$(CONFIG_TIFM_CORE) += tifm_core.o
++obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
++obj-$(CONFIG_SGI_IOC4) += ioc4.o
+diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
+index 634d538..48d5abe 100644
+--- a/drivers/misc/ibmasm/ibmasm.h
++++ b/drivers/misc/ibmasm/ibmasm.h
+@@ -196,10 +196,10 @@ extern int ibmasm_send_os_state(struct s
+
+ /* low level message processing */
+ extern int ibmasm_send_i2o_message(struct service_processor *sp);
+-extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs);
++extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id);
+
+ /* remote console */
+-extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp, struct pt_regs *regs);
++extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
+ extern int ibmasm_init_remote_input_dev(struct service_processor *sp);
+ extern void ibmasm_free_remote_input_dev(struct service_processor *sp);
+
+diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
+index 4a35caf..b99dc50 100644
+--- a/drivers/misc/ibmasm/ibmasmfs.c
++++ b/drivers/misc/ibmasm/ibmasmfs.c
+@@ -147,7 +147,6 @@ static struct inode *ibmasmfs_make_inode
+ if (ret) {
+ ret->i_mode = mode;
+ ret->i_uid = ret->i_gid = 0;
+- ret->i_blksize = PAGE_CACHE_SIZE;
+ ret->i_blocks = 0;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ }
+@@ -175,7 +174,7 @@ static struct dentry *ibmasmfs_create_fi
+ }
+
+ inode->i_fop = fops;
+- inode->u.generic_ip = data;
++ inode->i_private = data;
+
+ d_add(dentry, inode);
+ return dentry;
+@@ -244,7 +243,7 @@ static int command_file_open(struct inod
+ {
+ struct ibmasmfs_command_data *command_data;
+
+- if (!inode->u.generic_ip)
++ if (!inode->i_private)
+ return -ENODEV;
+
+ command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
+@@ -252,7 +251,7 @@ static int command_file_open(struct inod
+ return -ENOMEM;
+
+ command_data->command = NULL;
+- command_data->sp = inode->u.generic_ip;
++ command_data->sp = inode->i_private;
+ file->private_data = command_data;
+ return 0;
+ }
+@@ -351,10 +350,10 @@ static int event_file_open(struct inode
+ struct ibmasmfs_event_data *event_data;
+ struct service_processor *sp;
+
+- if (!inode->u.generic_ip)
++ if (!inode->i_private)
+ return -ENODEV;
+
+- sp = inode->u.generic_ip;
++ sp = inode->i_private;
+
+ event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
+ if (!event_data)
+@@ -439,14 +438,14 @@ static int r_heartbeat_file_open(struct
+ {
+ struct ibmasmfs_heartbeat_data *rhbeat;
+
+- if (!inode->u.generic_ip)
++ if (!inode->i_private)
+ return -ENODEV;
+
+ rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
+ if (!rhbeat)
+ return -ENOMEM;
+
+- rhbeat->sp = (struct service_processor *)inode->u.generic_ip;
++ rhbeat->sp = inode->i_private;
+ rhbeat->active = 0;
+ ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
+ file->private_data = rhbeat;
+@@ -508,7 +507,7 @@ static ssize_t r_heartbeat_file_write(st
+
+ static int remote_settings_file_open(struct inode *inode, struct file *file)
+ {
+- file->private_data = inode->u.generic_ip;
++ file->private_data = inode->i_private;
+ return 0;
+ }
+
+diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c
+index 47949a2..a3c589b 100644
+--- a/drivers/misc/ibmasm/lowlevel.c
++++ b/drivers/misc/ibmasm/lowlevel.c
+@@ -54,7 +54,7 @@ int ibmasm_send_i2o_message(struct servi
+ return 0;
+ }
+
+-irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs)
++irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id)
+ {
+ u32 mfa;
+ struct service_processor *sp = (struct service_processor *)dev_id;
+@@ -67,7 +67,7 @@ irqreturn_t ibmasm_interrupt_handler(int
+ dbg("respond to interrupt at %s\n", get_timestamp(tsbuf));
+
+ if (mouse_interrupt_pending(sp)) {
+- ibmasm_handle_mouse_interrupt(sp, regs);
++ ibmasm_handle_mouse_interrupt(sp);
+ clear_mouse_interrupt(sp);
+ }
+
+diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c
+index 0f9e3aa..a40fda6 100644
+--- a/drivers/misc/ibmasm/remote.c
++++ b/drivers/misc/ibmasm/remote.c
+@@ -158,12 +158,10 @@ static void print_input(struct remote_in
+ }
+ }
+
+-static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs,
+- struct remote_input *input)
++static void send_mouse_event(struct input_dev *dev, struct remote_input *input)
+ {
+ unsigned char buttons = input->mouse_buttons;
+
+- input_regs(dev, regs);
+ input_report_abs(dev, ABS_X, input->data.mouse.x);
+ input_report_abs(dev, ABS_Y, input->data.mouse.y);
+ input_report_key(dev, BTN_LEFT, buttons & REMOTE_BUTTON_LEFT);
+@@ -172,7 +170,7 @@ static void send_mouse_event(struct inpu
+ input_sync(dev);
+ }
+
+-static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs,
++static void send_keyboard_event(struct input_dev *dev,
+ struct remote_input *input)
+ {
+ unsigned int key;
+@@ -182,13 +180,11 @@ static void send_keyboard_event(struct i
+ key = xlate_high[code & 0xff];
+ else
+ key = xlate[code];
+- input_regs(dev, regs);
+ input_report_key(dev, key, (input->data.keyboard.key_down) ? 1 : 0);
+ input_sync(dev);
+ }
+
+-void ibmasm_handle_mouse_interrupt(struct service_processor *sp,
+- struct pt_regs *regs)
++void ibmasm_handle_mouse_interrupt(struct service_processor *sp)
+ {
+ unsigned long reader;
+ unsigned long writer;
+@@ -203,9 +199,9 @@ void ibmasm_handle_mouse_interrupt(struc
+
+ print_input(&input);
+ if (input.type == INPUT_TYPE_MOUSE) {
+- send_mouse_event(sp->remote.mouse_dev, regs, &input);
++ send_mouse_event(sp->remote.mouse_dev, &input);
+ } else if (input.type == INPUT_TYPE_KEYBOARD) {
+- send_keyboard_event(sp->remote.keybd_dev, regs, &input);
++ send_keyboard_event(sp->remote.keybd_dev, &input);
+ } else
+ break;
+
+diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
+new file mode 100644
+index 0000000..b995a15
+--- /dev/null
++++ b/drivers/misc/ioc4.c
+@@ -0,0 +1,474 @@
++/*
++ * 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-2006 Silicon Graphics, Inc. All Rights Reserved.
++ */
++
++/* This file contains the master driver module for use by SGI IOC4 subdrivers.
++ *
++ * It allocates any resources shared between multiple subdevices, and
++ * provides accessor functions (where needed) and the like for those
++ * resources. It also provides a mechanism for the subdevice modules
++ * to support loading and unloading.
++ *
++ * Non-shared resources (e.g. external interrupt A_INT_OUT register page
++ * alias, serial port and UART registers) are handled by the subdevice
++ * modules themselves.
++ *
++ * This is all necessary because IOC4 is not implemented as a multi-function
++ * PCI device, but an amalgamation of disparate registers for several
++ * types of device (ATA, serial, external interrupts). The normal
++ * resource management in the kernel doesn't have quite the right interfaces
++ * to handle this situation (e.g. multiple modules can't claim the same
++ * PCI ID), thus this IOC4 master module.
++ */
++
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/ioc4.h>
++#include <linux/ktime.h>
++#include <linux/mutex.h>
++#include <linux/time.h>
++#include <asm/io.h>
++
++/***************
++ * Definitions *
++ ***************/
++
++/* Tweakable values */
++
++/* PCI bus speed detection/calibration */
++#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
++#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */
++#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */
++#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */
++#define IOC4_CALIBRATE_HIGH_MHZ 75 /* Upper bound on bus speed sanity */
++#define IOC4_CALIBRATE_DEFAULT_MHZ 66 /* Assumed if sanity check fails */
++
++/************************
++ * Submodule management *
++ ************************/
++
++static DEFINE_MUTEX(ioc4_mutex);
++
++static LIST_HEAD(ioc4_devices);
++static LIST_HEAD(ioc4_submodules);
++
++/* Register an IOC4 submodule */
++int
++ioc4_register_submodule(struct ioc4_submodule *is)
++{
++ struct ioc4_driver_data *idd;
++
++ mutex_lock(&ioc4_mutex);
++ list_add(&is->is_list, &ioc4_submodules);
++
++ /* Initialize submodule for each IOC4 */
++ if (!is->is_probe)
++ goto out;
++
++ list_for_each_entry(idd, &ioc4_devices, idd_list) {
++ if (is->is_probe(idd)) {
++ printk(KERN_WARNING
++ "%s: IOC4 submodule %s probe failed "
++ "for pci_dev %s",
++ __FUNCTION__, module_name(is->is_owner),
++ pci_name(idd->idd_pdev));
++ }
++ }
++ out:
++ mutex_unlock(&ioc4_mutex);
++ return 0;
++}
++
++/* Unregister an IOC4 submodule */
++void
++ioc4_unregister_submodule(struct ioc4_submodule *is)
++{
++ struct ioc4_driver_data *idd;
++
++ mutex_lock(&ioc4_mutex);
++ list_del(&is->is_list);
++
++ /* Remove submodule for each IOC4 */
++ if (!is->is_remove)
++ goto out;
++
++ list_for_each_entry(idd, &ioc4_devices, idd_list) {
++ if (is->is_remove(idd)) {
++ printk(KERN_WARNING
++ "%s: IOC4 submodule %s remove failed "
++ "for pci_dev %s.\n",
++ __FUNCTION__, module_name(is->is_owner),
++ pci_name(idd->idd_pdev));
++ }
++ }
++ out:
++ mutex_unlock(&ioc4_mutex);
++}
++
++/*********************
++ * Device management *
++ *********************/
++
++#define IOC4_CALIBRATE_LOW_LIMIT \
++ (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
++#define IOC4_CALIBRATE_HIGH_LIMIT \
++ (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
++#define IOC4_CALIBRATE_DEFAULT \
++ (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
++
++#define IOC4_CALIBRATE_END \
++ (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
++
++#define IOC4_INT_OUT_MODE_TOGGLE 0x7 /* Toggle INT_OUT every COUNT+1 ticks */
++
++/* Determines external interrupt output clock period of the PCI bus an
++ * IOC4 is attached to. This value can be used to determine the PCI
++ * bus speed.
++ *
++ * IOC4 has a design feature that various internal timers are derived from
++ * the PCI bus clock. This causes IOC4 device drivers to need to take the
++ * bus speed into account when setting various register values (e.g. INT_OUT
++ * register COUNT field, UART divisors, etc). Since this information is
++ * needed by several subdrivers, it is determined by the main IOC4 driver,
++ * even though the following code utilizes external interrupt registers
++ * to perform the speed calculation.
++ */
++static void
++ioc4_clock_calibrate(struct ioc4_driver_data *idd)
++{
++ union ioc4_int_out int_out;
++ union ioc4_gpcr gpcr;
++ unsigned int state, last_state = 1;
++ struct timespec start_ts, end_ts;
++ uint64_t start, end, period;
++ unsigned int count = 0;
++
++ /* Enable output */
++ gpcr.raw = 0;
++ gpcr.fields.dir = IOC4_GPCR_DIR_0;
++ gpcr.fields.int_out_en = 1;
++ writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
++
++ /* Reset to power-on state */
++ writel(0, &idd->idd_misc_regs->int_out.raw);
++ mmiowb();
++
++ /* Set up square wave */
++ int_out.raw = 0;
++ int_out.fields.count = IOC4_CALIBRATE_COUNT;
++ int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
++ int_out.fields.diag = 0;
++ writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
++ mmiowb();
++
++ /* Check square wave period averaged over some number of cycles */
++ do {
++ int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
++ state = int_out.fields.int_out;
++ if (!last_state && state) {
++ count++;
++ if (count == IOC4_CALIBRATE_END) {
++ ktime_get_ts(&end_ts);
++ break;
++ } else if (count == IOC4_CALIBRATE_DISCARD)
++ ktime_get_ts(&start_ts);
++ }
++ last_state = state;
++ } while (1);
++
++ /* Calculation rearranged to preserve intermediate precision.
++ * Logically:
++ * 1. "end - start" gives us the measurement period over all
++ * the square wave cycles.
++ * 2. Divide by number of square wave cycles to get the period
++ * of a square wave cycle.
++ * 3. Divide by 2*(int_out.fields.count+1), which is the formula
++ * by which the IOC4 generates the square wave, to get the
++ * period of an IOC4 INT_OUT count.
++ */
++ end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec;
++ start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec;
++ period = (end - start) /
++ (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1));
++
++ /* Bounds check the result. */
++ if (period > IOC4_CALIBRATE_LOW_LIMIT ||
++ period < IOC4_CALIBRATE_HIGH_LIMIT) {
++ printk(KERN_INFO
++ "IOC4 %s: Clock calibration failed. Assuming"
++ "PCI clock is %d ns.\n",
++ pci_name(idd->idd_pdev),
++ IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
++ period = IOC4_CALIBRATE_DEFAULT;
++ } else {
++ u64 ns = period;
++
++ do_div(ns, IOC4_EXTINT_COUNT_DIVISOR);
++ printk(KERN_DEBUG
++ "IOC4 %s: PCI clock is %llu ns.\n",
++ pci_name(idd->idd_pdev), (unsigned long long)ns);
++ }
++
++ /* Remember results. We store the extint clock period rather
++ * than the PCI clock period so that greater precision is
++ * retained. Divide by IOC4_EXTINT_COUNT_DIVISOR to get
++ * PCI clock period.
++ */
++ idd->count_period = period;
++}
++
++/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT.
++ * Each brings out different combinations of IOC4 signals, thus.
++ * the IOC4 subdrivers need to know to which we're attached.
++ *
++ * We look for the presence of a SCSI (IO9) or SATA (IO10) controller
++ * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
++ * If neither is present, it's a PCI-RT.
++ */
++static unsigned int
++ioc4_variant(struct ioc4_driver_data *idd)
++{
++ struct pci_dev *pdev = NULL;
++ int found = 0;
++
++ /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */
++ do {
++ pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC,
++ PCI_DEVICE_ID_QLOGIC_ISP12160, pdev);
++ if (pdev &&
++ idd->idd_pdev->bus->number == pdev->bus->number &&
++ 3 == PCI_SLOT(pdev->devfn))
++ found = 1;
++ pci_dev_put(pdev);
++ } while (pdev && !found);
++ if (NULL != pdev)
++ return IOC4_VARIANT_IO9;
++
++ /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
++ pdev = NULL;
++ do {
++ pdev = pci_get_device(PCI_VENDOR_ID_VITESSE,
++ PCI_DEVICE_ID_VITESSE_VSC7174, pdev);
++ if (pdev &&
++ idd->idd_pdev->bus->number == pdev->bus->number &&
++ 3 == PCI_SLOT(pdev->devfn))
++ found = 1;
++ pci_dev_put(pdev);
++ } while (pdev && !found);
++ if (NULL != pdev)
++ return IOC4_VARIANT_IO10;
++
++ /* PCI-RT: No SCSI/SATA controller will be present */
++ return IOC4_VARIANT_PCI_RT;
++}
++
++/* Adds a new instance of an IOC4 card */
++static int
++ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
++{
++ struct ioc4_driver_data *idd;
++ struct ioc4_submodule *is;
++ uint32_t pcmd;
++ int ret;
++
++ /* Enable IOC4 and take ownership of it */
++ if ((ret = pci_enable_device(pdev))) {
++ printk(KERN_WARNING
++ "%s: Failed to enable IOC4 device for pci_dev %s.\n",
++ __FUNCTION__, pci_name(pdev));
++ goto out;
++ }
++ pci_set_master(pdev);
++
++ /* Set up per-IOC4 data */
++ idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
++ if (!idd) {
++ printk(KERN_WARNING
++ "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
++ __FUNCTION__, pci_name(pdev));
++ ret = -ENODEV;
++ goto out_idd;
++ }
++ idd->idd_pdev = pdev;
++ idd->idd_pci_id = pci_id;
++
++ /* Map IOC4 misc registers. These are shared between subdevices
++ * so the main IOC4 module manages them.
++ */
++ idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
++ if (!idd->idd_bar0) {
++ printk(KERN_WARNING
++ "%s: Unable to find IOC4 misc resource "
++ "for pci_dev %s.\n",
++ __FUNCTION__, pci_name(idd->idd_pdev));
++ ret = -ENODEV;
++ goto out_pci;
++ }
++ if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
++ "ioc4_misc")) {
++ printk(KERN_WARNING
++ "%s: Unable to request IOC4 misc region "
++ "for pci_dev %s.\n",
++ __FUNCTION__, pci_name(idd->idd_pdev));
++ ret = -ENODEV;
++ goto out_pci;
++ }
++ idd->idd_misc_regs = ioremap(idd->idd_bar0,
++ sizeof(struct ioc4_misc_regs));
++ if (!idd->idd_misc_regs) {
++ printk(KERN_WARNING
++ "%s: Unable to remap IOC4 misc region "
++ "for pci_dev %s.\n",
++ __FUNCTION__, pci_name(idd->idd_pdev));
++ ret = -ENODEV;
++ goto out_misc_region;
++ }
++
++ /* Failsafe portion of per-IOC4 initialization */
++
++ /* Detect card variant */
++ idd->idd_variant = ioc4_variant(idd);
++ printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev),
++ idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" :
++ idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" :
++ idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown");
++
++ /* Initialize IOC4 */
++ pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
++ pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
++ pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
++
++ /* Determine PCI clock */
++ ioc4_clock_calibrate(idd);
++
++ /* Disable/clear all interrupts. Need to do this here lest
++ * one submodule request the shared IOC4 IRQ, but interrupt
++ * is generated by a different subdevice.
++ */
++ /* Disable */
++ writel(~0, &idd->idd_misc_regs->other_iec.raw);
++ writel(~0, &idd->idd_misc_regs->sio_iec);
++ /* Clear (i.e. acknowledge) */
++ writel(~0, &idd->idd_misc_regs->other_ir.raw);
++ writel(~0, &idd->idd_misc_regs->sio_ir);
++
++ /* Track PCI-device specific data */
++ idd->idd_serial_data = NULL;
++ pci_set_drvdata(idd->idd_pdev, idd);
++
++ mutex_lock(&ioc4_mutex);
++ list_add_tail(&idd->idd_list, &ioc4_devices);
++
++ /* Add this IOC4 to all submodules */
++ list_for_each_entry(is, &ioc4_submodules, is_list) {
++ if (is->is_probe && is->is_probe(idd)) {
++ printk(KERN_WARNING
++ "%s: IOC4 submodule 0x%s probe failed "
++ "for pci_dev %s.\n",
++ __FUNCTION__, module_name(is->is_owner),
++ pci_name(idd->idd_pdev));
++ }
++ }
++ mutex_unlock(&ioc4_mutex);
++
++ return 0;
++
++out_misc_region:
++ release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
++out_pci:
++ kfree(idd);
++out_idd:
++ pci_disable_device(pdev);
++out:
++ return ret;
++}
++
++/* Removes a particular instance of an IOC4 card. */
++static void
++ioc4_remove(struct pci_dev *pdev)
++{
++ struct ioc4_submodule *is;
++ struct ioc4_driver_data *idd;
++
++ idd = pci_get_drvdata(pdev);
++
++ /* Remove this IOC4 from all submodules */
++ mutex_lock(&ioc4_mutex);
++ list_for_each_entry(is, &ioc4_submodules, is_list) {
++ if (is->is_remove && is->is_remove(idd)) {
++ printk(KERN_WARNING
++ "%s: IOC4 submodule 0x%s remove failed "
++ "for pci_dev %s.\n",
++ __FUNCTION__, module_name(is->is_owner),
++ pci_name(idd->idd_pdev));
++ }
++ }
++ mutex_unlock(&ioc4_mutex);
++
++ /* Release resources */
++ iounmap(idd->idd_misc_regs);
++ if (!idd->idd_bar0) {
++ printk(KERN_WARNING
++ "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
++ "Device removal may be incomplete.\n",
++ __FUNCTION__, pci_name(idd->idd_pdev));
++ }
++ release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
++
++ /* Disable IOC4 and relinquish */
++ pci_disable_device(pdev);
++
++ /* Remove and free driver data */
++ mutex_lock(&ioc4_mutex);
++ list_del(&idd->idd_list);
++ mutex_unlock(&ioc4_mutex);
++ kfree(idd);
++}
++
++static struct pci_device_id ioc4_id_table[] = {
++ {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
++ PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
++ {0}
++};
++
++static struct pci_driver ioc4_driver = {
++ .name = "IOC4",
++ .id_table = ioc4_id_table,
++ .probe = ioc4_probe,
++ .remove = ioc4_remove,
++};
++
++MODULE_DEVICE_TABLE(pci, ioc4_id_table);
++
++/*********************
++ * Module management *
++ *********************/
++
++/* Module load */
++static int __devinit
++ioc4_init(void)
++{
++ return pci_register_driver(&ioc4_driver);
++}
++
++/* Module unload */
++static void __devexit
++ioc4_exit(void)
++{
++ pci_unregister_driver(&ioc4_driver);
++}
++
++module_init(ioc4_init);
++module_exit(ioc4_exit);
++
++MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan at sgi.com>");
++MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
++MODULE_LICENSE("GPL");
++
++EXPORT_SYMBOL(ioc4_register_submodule);
++EXPORT_SYMBOL(ioc4_unregister_submodule);
+diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
+new file mode 100644
+index 0000000..db9d7df
+--- /dev/null
++++ b/drivers/misc/lkdtm.c
+@@ -0,0 +1,343 @@
++/*
++ * Kprobe module for testing crash dumps
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) IBM Corporation, 2006
++ *
++ * Author: Ankita Garg <ankita at in.ibm.com>
++ *
++ * This module induces system failures at predefined crashpoints to
++ * evaluate the reliability of crash dumps obtained using different dumping
++ * solutions.
++ *
++ * It is adapted from the Linux Kernel Dump Test Tool by
++ * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net>
++ *
++ * Usage : insmod lkdtm.ko [recur_count={>0}] cpoint_name=<> cpoint_type=<>
++ * [cpoint_count={>0}]
++ *
++ * recur_count : Recursion level for the stack overflow test. Default is 10.
++ *
++ * cpoint_name : Crash point where the kernel is to be crashed. It can be
++ * one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
++ * FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD,
++ * IDE_CORE_CP
++ *
++ * cpoint_type : Indicates the action to be taken on hitting the crash point.
++ * It can be one of PANIC, BUG, EXCEPTION, LOOP, OVERFLOW
++ *
++ * cpoint_count : Indicates the number of times the crash point is to be hit
++ * to trigger an action. The default is 10.
++ */
++
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/buffer_head.h>
++#include <linux/kprobes.h>
++#include <linux/list.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/hrtimer.h>
++#include <scsi/scsi_cmnd.h>
++
++#ifdef CONFIG_IDE
++#include <linux/ide.h>
++#endif
++
++#define NUM_CPOINTS 8
++#define NUM_CPOINT_TYPES 5
++#define DEFAULT_COUNT 10
++#define REC_NUM_DEFAULT 10
++
++enum cname {
++ INVALID,
++ INT_HARDWARE_ENTRY,
++ INT_HW_IRQ_EN,
++ INT_TASKLET_ENTRY,
++ FS_DEVRW,
++ MEM_SWAPOUT,
++ TIMERADD,
++ SCSI_DISPATCH_CMD,
++ IDE_CORE_CP
++};
++
++enum ctype {
++ NONE,
++ PANIC,
++ BUG,
++ EXCEPTION,
++ LOOP,
++ OVERFLOW
++};
++
++static char* cp_name[] = {
++ "INT_HARDWARE_ENTRY",
++ "INT_HW_IRQ_EN",
++ "INT_TASKLET_ENTRY",
++ "FS_DEVRW",
++ "MEM_SWAPOUT",
++ "TIMERADD",
++ "SCSI_DISPATCH_CMD",
++ "IDE_CORE_CP"
++};
++
++static char* cp_type[] = {
++ "PANIC",
++ "BUG",
++ "EXCEPTION",
++ "LOOP",
++ "OVERFLOW"
++};
++
++static struct jprobe lkdtm;
++
++static int lkdtm_parse_commandline(void);
++static void lkdtm_handler(void);
++
++static char* cpoint_name = INVALID;
++static char* cpoint_type = NONE;
++static int cpoint_count = DEFAULT_COUNT;
++static int recur_count = REC_NUM_DEFAULT;
++
++static enum cname cpoint = INVALID;
++static enum ctype cptype = NONE;
++static int count = DEFAULT_COUNT;
++
++module_param(recur_count, int, 0644);
++MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
++ "default is 10");
++module_param(cpoint_name, charp, 0644);
++MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
++module_param(cpoint_type, charp, 0644);
++MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
++ "hitting the crash point");
++module_param(cpoint_count, int, 0644);
++MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
++ "crash point is to be hit to trigger action");
++
++unsigned int jp_do_irq(unsigned int irq)
++{
++ lkdtm_handler();
++ jprobe_return();
++ return 0;
++}
++
++irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action)
++{
++ lkdtm_handler();
++ jprobe_return();
++ return 0;
++}
++
++void jp_tasklet_action(struct softirq_action *a)
++{
++ lkdtm_handler();
++ jprobe_return();
++}
++
++void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
++{
++ lkdtm_handler();
++ jprobe_return();
++}
++
++struct scan_control;
++
++unsigned long jp_shrink_inactive_list(unsigned long max_scan,
++ struct zone *zone, struct scan_control *sc)
++{
++ lkdtm_handler();
++ jprobe_return();
++ return 0;
++}
++
++int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
++ const enum hrtimer_mode mode)
++{
++ lkdtm_handler();
++ jprobe_return();
++ return 0;
++}
++
++int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
++{
++ lkdtm_handler();
++ jprobe_return();
++ return 0;
++}
++
++#ifdef CONFIG_IDE
++int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
++ struct block_device *bdev, unsigned int cmd,
++ unsigned long arg)
++{
++ lkdtm_handler();
++ jprobe_return();
++ return 0;
++}
++#endif
++
++static int lkdtm_parse_commandline(void)
++{
++ int i;
++
++ if (cpoint_name == INVALID || cpoint_type == NONE ||
++ cpoint_count < 1 || recur_count < 1)
++ return -EINVAL;
++
++ for (i = 0; i < NUM_CPOINTS; ++i) {
++ if (!strcmp(cpoint_name, cp_name[i])) {
++ cpoint = i + 1;
++ break;
++ }
++ }
++
++ for (i = 0; i < NUM_CPOINT_TYPES; ++i) {
++ if (!strcmp(cpoint_type, cp_type[i])) {
++ cptype = i + 1;
++ break;
++ }
++ }
++
++ if (cpoint == INVALID || cptype == NONE)
++ return -EINVAL;
++
++ count = cpoint_count;
++
++ return 0;
++}
++
++static int recursive_loop(int a)
++{
++ char buf[1024];
++
++ memset(buf,0xFF,1024);
++ recur_count--;
++ if (!recur_count)
++ return 0;
++ else
++ return recursive_loop(a);
++}
++
++void lkdtm_handler(void)
++{
++ printk(KERN_INFO "lkdtm : Crash point %s of type %s hit\n",
++ cpoint_name, cpoint_type);
++ --count;
++
++ if (count == 0) {
++ switch (cptype) {
++ case NONE:
++ break;
++ case PANIC:
++ printk(KERN_INFO "lkdtm : PANIC\n");
++ panic("dumptest");
++ break;
++ case BUG:
++ printk(KERN_INFO "lkdtm : BUG\n");
++ BUG();
++ break;
++ case EXCEPTION:
++ printk(KERN_INFO "lkdtm : EXCEPTION\n");
++ *((int *) 0) = 0;
++ break;
++ case LOOP:
++ printk(KERN_INFO "lkdtm : LOOP\n");
++ for (;;);
++ break;
++ case OVERFLOW:
++ printk(KERN_INFO "lkdtm : OVERFLOW\n");
++ (void) recursive_loop(0);
++ break;
++ default:
++ break;
++ }
++ count = cpoint_count;
++ }
++}
++
++int lkdtm_module_init(void)
++{
++ int ret;
++
++ if (lkdtm_parse_commandline() == -EINVAL) {
++ printk(KERN_INFO "lkdtm : Invalid command\n");
++ return -EINVAL;
++ }
++
++ switch (cpoint) {
++ case INT_HARDWARE_ENTRY:
++ lkdtm.kp.symbol_name = "__do_IRQ";
++ lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
++ break;
++ case INT_HW_IRQ_EN:
++ lkdtm.kp.symbol_name = "handle_IRQ_event";
++ lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
++ break;
++ case INT_TASKLET_ENTRY:
++ lkdtm.kp.symbol_name = "tasklet_action";
++ lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
++ break;
++ case FS_DEVRW:
++ lkdtm.kp.symbol_name = "ll_rw_block";
++ lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
++ break;
++ case MEM_SWAPOUT:
++ lkdtm.kp.symbol_name = "shrink_inactive_list";
++ lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
++ break;
++ case TIMERADD:
++ lkdtm.kp.symbol_name = "hrtimer_start";
++ lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
++ break;
++ case SCSI_DISPATCH_CMD:
++ lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
++ lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
++ break;
++ case IDE_CORE_CP:
++#ifdef CONFIG_IDE
++ lkdtm.kp.symbol_name = "generic_ide_ioctl";
++ lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
++#else
++ printk(KERN_INFO "lkdtm : Crash point not available\n");
++#endif
++ break;
++ default:
++ printk(KERN_INFO "lkdtm : Invalid Crash Point\n");
++ break;
++ }
++
++ if ((ret = register_jprobe(&lkdtm)) < 0) {
++ printk(KERN_INFO "lkdtm : Couldn't register jprobe\n");
++ return ret;
++ }
++
++ printk(KERN_INFO "lkdtm : Crash point %s of type %s registered\n",
++ cpoint_name, cpoint_type);
++ return 0;
++}
++
++void lkdtm_module_exit(void)
++{
++ unregister_jprobe(&lkdtm);
++ printk(KERN_INFO "lkdtm : Crash point unregistered\n");
++}
++
++module_init(lkdtm_module_init);
++module_exit(lkdtm_module_exit);
++
++MODULE_LICENSE("GPL");
+diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
+new file mode 100644
+index 0000000..fdb7153
+--- /dev/null
++++ b/drivers/misc/msi-laptop.c
+@@ -0,0 +1,395 @@
++/*-*-linux-c-*-*/
++
++/*
++ Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) 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., 51 Franklin Street, Fifth Floor, Boston, MA
++ 02110-1301, USA.
++ */
++
++/*
++ * msi-laptop.c - MSI S270 laptop support. This laptop is sold under
++ * various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
++ *
++ * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
++ *
++ * lcd_level - Screen brightness: contains a single integer in the
++ * range 0..8. (rw)
++ *
++ * auto_brightness - Enable automatic brightness control: contains
++ * either 0 or 1. If set to 1 the hardware adjusts the screen
++ * brightness automatically when the power cord is
++ * plugged/unplugged. (rw)
++ *
++ * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
++ *
++ * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
++ * Please note that this file is constantly 0 if no Bluetooth
++ * hardware is available. (ro)
++ *
++ * In addition to these platform device attributes the driver
++ * registers itself in the Linux backlight control subsystem and is
++ * available to userspace under /sys/class/backlight/msi-laptop-bl/.
++ *
++ * This driver might work on other laptops produced by MSI. If you
++ * want to try it you can pass force=1 as argument to the module which
++ * will force it to load even when the DMI data doesn't identify the
++ * laptop as MSI S270. YMMV.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/acpi.h>
++#include <linux/dmi.h>
++#include <linux/backlight.h>
++#include <linux/platform_device.h>
++#include <linux/autoconf.h>
++
++#define MSI_DRIVER_VERSION "0.5"
++
++#define MSI_LCD_LEVEL_MAX 9
++
++#define MSI_EC_COMMAND_WIRELESS 0x10
++#define MSI_EC_COMMAND_LCD_LEVEL 0x11
++
++static int force;
++module_param(force, bool, 0);
++MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
++
++static int auto_brightness;
++module_param(auto_brightness, int, 0);
++MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
++
++/* Hardware access */
++
++static int set_lcd_level(int level)
++{
++ u8 buf[2];
++
++ if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
++ return -EINVAL;
++
++ buf[0] = 0x80;
++ buf[1] = (u8) (level*31);
++
++ return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
++}
++
++static int get_lcd_level(void)
++{
++ u8 wdata = 0, rdata;
++ int result;
++
++ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
++ if (result < 0)
++ return result;
++
++ return (int) rdata / 31;
++}
++
++static int get_auto_brightness(void)
++{
++ u8 wdata = 4, rdata;
++ int result;
++
++ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
++ if (result < 0)
++ return result;
++
++ return !!(rdata & 8);
++}
++
++static int set_auto_brightness(int enable)
++{
++ u8 wdata[2], rdata;
++ int result;
++
++ wdata[0] = 4;
++
++ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1);
++ if (result < 0)
++ return result;
++
++ wdata[0] = 0x84;
++ wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
++
++ return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0);
++}
++
++static int get_wireless_state(int *wlan, int *bluetooth)
++{
++ u8 wdata = 0, rdata;
++ int result;
++
++ result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
++ if (result < 0)
++ return -1;
++
++ if (wlan)
++ *wlan = !!(rdata & 8);
++
++ if (bluetooth)
++ *bluetooth = !!(rdata & 128);
++
++ return 0;
++}
++
++/* Backlight device stuff */
++
++static int bl_get_brightness(struct backlight_device *b)
++{
++ return get_lcd_level();
++}
++
++
++static int bl_update_status(struct backlight_device *b)
++{
++ return set_lcd_level(b->props->brightness);
++}
++
++static struct backlight_properties msibl_props = {
++ .owner = THIS_MODULE,
++ .get_brightness = bl_get_brightness,
++ .update_status = bl_update_status,
++ .max_brightness = MSI_LCD_LEVEL_MAX-1,
++};
++
++static struct backlight_device *msibl_device;
++
++/* Platform device */
++
++static ssize_t show_wlan(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++
++ int ret, enabled;
++
++ ret = get_wireless_state(&enabled, NULL);
++ if (ret < 0)
++ return ret;
++
++ return sprintf(buf, "%i\n", enabled);
++}
++
++static ssize_t show_bluetooth(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++
++ int ret, enabled;
++
++ ret = get_wireless_state(NULL, &enabled);
++ if (ret < 0)
++ return ret;
++
++ return sprintf(buf, "%i\n", enabled);
++}
++
++static ssize_t show_lcd_level(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++
++ int ret;
++
++ ret = get_lcd_level();
++ if (ret < 0)
++ return ret;
++
++ return sprintf(buf, "%i\n", ret);
++}
++
++static ssize_t store_lcd_level(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++
++ int level, ret;
++
++ if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
++ return -EINVAL;
++
++ ret = set_lcd_level(level);
++ if (ret < 0)
++ return ret;
++
++ return count;
++}
++
++static ssize_t show_auto_brightness(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++
++ int ret;
++
++ ret = get_auto_brightness();
++ if (ret < 0)
++ return ret;
++
++ return sprintf(buf, "%i\n", ret);
++}
++
++static ssize_t store_auto_brightness(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++
++ int enable, ret;
++
++ if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
++ return -EINVAL;
++
++ ret = set_auto_brightness(enable);
++ if (ret < 0)
++ return ret;
++
++ return count;
++}
++
++static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
++static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
++static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
++static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
++
++static struct attribute *msipf_attributes[] = {
++ &dev_attr_lcd_level.attr,
++ &dev_attr_auto_brightness.attr,
++ &dev_attr_bluetooth.attr,
++ &dev_attr_wlan.attr,
++ NULL
++};
++
++static struct attribute_group msipf_attribute_group = {
++ .attrs = msipf_attributes
++};
++
++static struct platform_driver msipf_driver = {
++ .driver = {
++ .name = "msi-laptop-pf",
++ .owner = THIS_MODULE,
++ }
++};
++
++static struct platform_device *msipf_device;
++
++/* Initialization */
++
++static struct dmi_system_id __initdata msi_dmi_table[] = {
++ {
++ .ident = "MSI S270",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
++ }
++ },
++ {
++ .ident = "Medion MD96100",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
++ }
++ },
++ { }
++};
++
++
++static int __init msi_init(void)
++{
++ int ret;
++
++ if (acpi_disabled)
++ return -ENODEV;
++
++ if (!force && !dmi_check_system(msi_dmi_table))
++ return -ENODEV;
++
++ if (auto_brightness < 0 || auto_brightness > 2)
++ return -EINVAL;
++
++ /* Register backlight stuff */
++
++ msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
++ if (IS_ERR(msibl_device))
++ return PTR_ERR(msibl_device);
++
++ ret = platform_driver_register(&msipf_driver);
++ if (ret)
++ goto fail_backlight;
++
++ /* Register platform stuff */
++
++ msipf_device = platform_device_alloc("msi-laptop-pf", -1);
++ if (!msipf_device) {
++ ret = -ENOMEM;
++ goto fail_platform_driver;
++ }
++
++ ret = platform_device_add(msipf_device);
++ if (ret)
++ goto fail_platform_device1;
++
++ ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
++ if (ret)
++ goto fail_platform_device2;
++
++ /* Disable automatic brightness control by default because
++ * this module was probably loaded to do brightness control in
++ * software. */
++
++ if (auto_brightness != 2)
++ set_auto_brightness(auto_brightness);
++
++ printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
++
++ return 0;
++
++fail_platform_device2:
++
++ platform_device_del(msipf_device);
++
++fail_platform_device1:
++
++ platform_device_put(msipf_device);
++
++fail_platform_driver:
++
++ platform_driver_unregister(&msipf_driver);
++
++fail_backlight:
++
++ backlight_device_unregister(msibl_device);
++
++ return ret;
++}
++
++static void __exit msi_cleanup(void)
++{
++
++ sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
++ platform_device_unregister(msipf_device);
++ platform_driver_unregister(&msipf_driver);
++ backlight_device_unregister(msibl_device);
++
++ /* Enable automatic brightness control again */
++ if (auto_brightness != 2)
++ set_auto_brightness(1);
++
++ printk(KERN_INFO "msi-laptop: driver unloaded.\n");
++}
++
++module_init(msi_init);
++module_exit(msi_cleanup);
++
++MODULE_AUTHOR("Lennart Poettering");
++MODULE_DESCRIPTION("MSI Laptop Support");
++MODULE_VERSION(MSI_DRIVER_VERSION);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
+new file mode 100644
+index 0000000..1ba8754
+--- /dev/null
++++ b/drivers/misc/tifm_7xx1.c
+@@ -0,0 +1,438 @@
++/*
++ * tifm_7xx1.c - TI FlashMedia driver
++ *
++ * Copyright (C) 2006 Alex Dubov <oakad at yahoo.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/tifm.h>
++#include <linux/dma-mapping.h>
++
++#define DRIVER_NAME "tifm_7xx1"
++#define DRIVER_VERSION "0.6"
++
++static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
++{
++ int cnt;
++ unsigned long flags;
++
++ spin_lock_irqsave(&fm->lock, flags);
++ if (!fm->inhibit_new_cards) {
++ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
++ if (fm->sockets[cnt] == sock) {
++ fm->remove_mask |= (1 << cnt);
++ queue_work(fm->wq, &fm->media_remover);
++ break;
++ }
++ }
++ }
++ spin_unlock_irqrestore(&fm->lock, flags);
++}
++
++static void tifm_7xx1_remove_media(void *adapter)
++{
++ struct tifm_adapter *fm = adapter;
++ unsigned long flags;
++ int cnt;
++ struct tifm_dev *sock;
++
++ if (!class_device_get(&fm->cdev))
++ return;
++ spin_lock_irqsave(&fm->lock, flags);
++ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
++ if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
++ printk(KERN_INFO DRIVER_NAME
++ ": demand removing card from socket %d\n", cnt);
++ sock = fm->sockets[cnt];
++ fm->sockets[cnt] = NULL;
++ fm->remove_mask &= ~(1 << cnt);
++
++ writel(0x0e00, sock->addr + SOCK_CONTROL);
++
++ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
++ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
++ fm->addr + FM_SET_INTERRUPT_ENABLE);
++
++ spin_unlock_irqrestore(&fm->lock, flags);
++ device_unregister(&sock->dev);
++ spin_lock_irqsave(&fm->lock, flags);
++ }
++ }
++ spin_unlock_irqrestore(&fm->lock, flags);
++ class_device_put(&fm->cdev);
++}
++
++static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
++{
++ struct tifm_adapter *fm = dev_id;
++ unsigned int irq_status;
++ unsigned int sock_irq_status, cnt;
++
++ spin_lock(&fm->lock);
++ irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
++ if (irq_status == 0 || irq_status == (~0)) {
++ spin_unlock(&fm->lock);
++ return IRQ_NONE;
++ }
++
++ if (irq_status & TIFM_IRQ_ENABLE) {
++ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++
++ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
++ sock_irq_status = (irq_status >> cnt) &
++ (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
++
++ if (fm->sockets[cnt]) {
++ if (sock_irq_status &&
++ fm->sockets[cnt]->signal_irq)
++ sock_irq_status = fm->sockets[cnt]->
++ signal_irq(fm->sockets[cnt],
++ sock_irq_status);
++
++ if (irq_status & (1 << cnt))
++ fm->remove_mask |= 1 << cnt;
++ } else {
++ if (irq_status & (1 << cnt))
++ fm->insert_mask |= 1 << cnt;
++ }
++ }
++ }
++ writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
++
++ if (!fm->inhibit_new_cards) {
++ if (!fm->remove_mask && !fm->insert_mask) {
++ writel(TIFM_IRQ_ENABLE,
++ fm->addr + FM_SET_INTERRUPT_ENABLE);
++ } else {
++ queue_work(fm->wq, &fm->media_remover);
++ queue_work(fm->wq, &fm->media_inserter);
++ }
++ }
++
++ spin_unlock(&fm->lock);
++ return IRQ_HANDLED;
++}
++
++static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
++{
++ unsigned int s_state;
++ int cnt;
++
++ writel(0x0e00, sock_addr + SOCK_CONTROL);
++
++ for (cnt = 0; cnt < 100; cnt++) {
++ if (!(TIFM_SOCK_STATE_POWERED &
++ readl(sock_addr + SOCK_PRESENT_STATE)))
++ break;
++ msleep(10);
++ }
++
++ s_state = readl(sock_addr + SOCK_PRESENT_STATE);
++ if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
++ return FM_NULL;
++
++ if (is_x2) {
++ writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
++ } else {
++ // SmartMedia cards need extra 40 msec
++ if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
++ msleep(40);
++ writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
++ sock_addr + SOCK_CONTROL);
++ msleep(10);
++ writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
++ sock_addr + SOCK_CONTROL);
++ }
++
++ for (cnt = 0; cnt < 100; cnt++) {
++ if ((TIFM_SOCK_STATE_POWERED &
++ readl(sock_addr + SOCK_PRESENT_STATE)))
++ break;
++ msleep(10);
++ }
++
++ if (!is_x2)
++ writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
++ sock_addr + SOCK_CONTROL);
++
++ return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
++}
++
++inline static char __iomem *
++tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
++{
++ return base_addr + ((sock_num + 1) << 10);
++}
++
++static void tifm_7xx1_insert_media(void *adapter)
++{
++ struct tifm_adapter *fm = adapter;
++ unsigned long flags;
++ tifm_media_id media_id;
++ char *card_name = "xx";
++ int cnt, ok_to_register;
++ unsigned int insert_mask;
++ struct tifm_dev *new_sock = NULL;
++
++ if (!class_device_get(&fm->cdev))
++ return;
++ spin_lock_irqsave(&fm->lock, flags);
++ insert_mask = fm->insert_mask;
++ fm->insert_mask = 0;
++ if (fm->inhibit_new_cards) {
++ spin_unlock_irqrestore(&fm->lock, flags);
++ class_device_put(&fm->cdev);
++ return;
++ }
++ spin_unlock_irqrestore(&fm->lock, flags);
++
++ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
++ if (!(insert_mask & (1 << cnt)))
++ continue;
++
++ media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
++ fm->max_sockets == 2);
++ if (media_id) {
++ ok_to_register = 0;
++ new_sock = tifm_alloc_device(fm, cnt);
++ if (new_sock) {
++ new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
++ cnt);
++ new_sock->media_id = media_id;
++ switch (media_id) {
++ case 1:
++ card_name = "xd";
++ break;
++ case 2:
++ card_name = "ms";
++ break;
++ case 3:
++ card_name = "sd";
++ break;
++ default:
++ break;
++ }
++ snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
++ "tifm_%s%u:%u", card_name, fm->id, cnt);
++ printk(KERN_INFO DRIVER_NAME
++ ": %s card detected in socket %d\n",
++ card_name, cnt);
++ spin_lock_irqsave(&fm->lock, flags);
++ if (!fm->sockets[cnt]) {
++ fm->sockets[cnt] = new_sock;
++ ok_to_register = 1;
++ }
++ spin_unlock_irqrestore(&fm->lock, flags);
++ if (!ok_to_register ||
++ device_register(&new_sock->dev)) {
++ spin_lock_irqsave(&fm->lock, flags);
++ fm->sockets[cnt] = NULL;
++ spin_unlock_irqrestore(&fm->lock,
++ flags);
++ tifm_free_device(&new_sock->dev);
++ }
++ }
++ }
++ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
++ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
++ fm->addr + FM_SET_INTERRUPT_ENABLE);
++ }
++
++ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
++ class_device_put(&fm->cdev);
++}
++
++static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
++{
++ struct tifm_adapter *fm = pci_get_drvdata(dev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&fm->lock, flags);
++ fm->inhibit_new_cards = 1;
++ fm->remove_mask = 0xf;
++ fm->insert_mask = 0;
++ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ spin_unlock_irqrestore(&fm->lock, flags);
++ flush_workqueue(fm->wq);
++
++ tifm_7xx1_remove_media(fm);
++
++ pci_set_power_state(dev, PCI_D3hot);
++ pci_disable_device(dev);
++ pci_save_state(dev);
++ return 0;
++}
++
++static int tifm_7xx1_resume(struct pci_dev *dev)
++{
++ struct tifm_adapter *fm = pci_get_drvdata(dev);
++ unsigned long flags;
++
++ pci_restore_state(dev);
++ pci_enable_device(dev);
++ pci_set_power_state(dev, PCI_D0);
++ pci_set_master(dev);
++
++ spin_lock_irqsave(&fm->lock, flags);
++ fm->inhibit_new_cards = 0;
++ writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
++ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
++ fm->addr + FM_SET_INTERRUPT_ENABLE);
++ fm->insert_mask = 0xf;
++ spin_unlock_irqrestore(&fm->lock, flags);
++ return 0;
++}
++
++static int tifm_7xx1_probe(struct pci_dev *dev,
++ const struct pci_device_id *dev_id)
++{
++ struct tifm_adapter *fm;
++ int pci_dev_busy = 0;
++ int rc;
++
++ rc = pci_set_dma_mask(dev, DMA_32BIT_MASK);
++ if (rc)
++ return rc;
++
++ rc = pci_enable_device(dev);
++ if (rc)
++ return rc;
++
++ pci_set_master(dev);
++
++ rc = pci_request_regions(dev, DRIVER_NAME);
++ if (rc) {
++ pci_dev_busy = 1;
++ goto err_out;
++ }
++
++ pci_intx(dev, 1);
++
++ fm = tifm_alloc_adapter();
++ if (!fm) {
++ rc = -ENOMEM;
++ goto err_out_int;
++ }
++
++ fm->dev = &dev->dev;
++ fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
++ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
++ GFP_KERNEL);
++ if (!fm->sockets)
++ goto err_out_free;
++
++ INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm);
++ INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm);
++ fm->eject = tifm_7xx1_eject;
++ pci_set_drvdata(dev, fm);
++
++ fm->addr = ioremap(pci_resource_start(dev, 0),
++ pci_resource_len(dev, 0));
++ if (!fm->addr)
++ goto err_out_free;
++
++ rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
++ if (rc)
++ goto err_out_unmap;
++
++ rc = tifm_add_adapter(fm);
++ if (rc)
++ goto err_out_irq;
++
++ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
++ fm->addr + FM_SET_INTERRUPT_ENABLE);
++
++ fm->insert_mask = 0xf;
++
++ return 0;
++
++err_out_irq:
++ free_irq(dev->irq, fm);
++err_out_unmap:
++ iounmap(fm->addr);
++err_out_free:
++ pci_set_drvdata(dev, NULL);
++ tifm_free_adapter(fm);
++err_out_int:
++ pci_intx(dev, 0);
++ pci_release_regions(dev);
++err_out:
++ if (!pci_dev_busy)
++ pci_disable_device(dev);
++ return rc;
++}
++
++static void tifm_7xx1_remove(struct pci_dev *dev)
++{
++ struct tifm_adapter *fm = pci_get_drvdata(dev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&fm->lock, flags);
++ fm->inhibit_new_cards = 1;
++ fm->remove_mask = 0xf;
++ fm->insert_mask = 0;
++ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ spin_unlock_irqrestore(&fm->lock, flags);
++
++ flush_workqueue(fm->wq);
++
++ tifm_7xx1_remove_media(fm);
++
++ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
++ free_irq(dev->irq, fm);
++
++ tifm_remove_adapter(fm);
++
++ pci_set_drvdata(dev, NULL);
++
++ iounmap(fm->addr);
++ pci_intx(dev, 0);
++ pci_release_regions(dev);
++
++ pci_disable_device(dev);
++ tifm_free_adapter(fm);
++}
++
++static struct pci_device_id tifm_7xx1_pci_tbl [] = {
++ { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++ 0 }, /* xx21 - the one I have */
++ { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++ 0 }, /* xx12 - should be also supported */
++ { }
++};
++
++static struct pci_driver tifm_7xx1_driver = {
++ .name = DRIVER_NAME,
++ .id_table = tifm_7xx1_pci_tbl,
++ .probe = tifm_7xx1_probe,
++ .remove = tifm_7xx1_remove,
++ .suspend = tifm_7xx1_suspend,
++ .resume = tifm_7xx1_resume,
++};
++
++static int __init tifm_7xx1_init(void)
++{
++ return pci_register_driver(&tifm_7xx1_driver);
++}
++
++static void __exit tifm_7xx1_exit(void)
++{
++ pci_unregister_driver(&tifm_7xx1_driver);
++}
++
++MODULE_AUTHOR("Alex Dubov");
++MODULE_DESCRIPTION("TI FlashMedia host driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
++MODULE_VERSION(DRIVER_VERSION);
++
++module_init(tifm_7xx1_init);
++module_exit(tifm_7xx1_exit);
+diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
+new file mode 100644
+index 0000000..ee32613
+--- /dev/null
++++ b/drivers/misc/tifm_core.c
+@@ -0,0 +1,272 @@
++/*
++ * tifm_core.c - TI FlashMedia driver
++ *
++ * Copyright (C) 2006 Alex Dubov <oakad at yahoo.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/tifm.h>
++#include <linux/init.h>
++#include <linux/idr.h>
++
++#define DRIVER_NAME "tifm_core"
++#define DRIVER_VERSION "0.6"
++
++static DEFINE_IDR(tifm_adapter_idr);
++static DEFINE_SPINLOCK(tifm_adapter_lock);
++
++static tifm_media_id *tifm_device_match(tifm_media_id *ids,
++ struct tifm_dev *dev)
++{
++ while (*ids) {
++ if (dev->media_id == *ids)
++ return ids;
++ ids++;
++ }
++ return NULL;
++}
++
++static int tifm_match(struct device *dev, struct device_driver *drv)
++{
++ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
++ struct tifm_driver *fm_drv;
++
++ fm_drv = container_of(drv, struct tifm_driver, driver);
++ if (!fm_drv->id_table)
++ return -EINVAL;
++ if (tifm_device_match(fm_drv->id_table, fm_dev))
++ return 1;
++ return -ENODEV;
++}
++
++static int tifm_uevent(struct device *dev, char **envp, int num_envp,
++ char *buffer, int buffer_size)
++{
++ struct tifm_dev *fm_dev;
++ int i = 0;
++ int length = 0;
++ const char *card_type_name[] = {"INV", "SM", "MS", "SD"};
++
++ if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
++ return -ENODEV;
++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id]))
++ return -ENOMEM;
++
++ return 0;
++}
++
++static struct bus_type tifm_bus_type = {
++ .name = "tifm",
++ .match = tifm_match,
++ .uevent = tifm_uevent,
++};
++
++static void tifm_free(struct class_device *cdev)
++{
++ struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
++
++ kfree(fm->sockets);
++ if (fm->wq)
++ destroy_workqueue(fm->wq);
++ kfree(fm);
++}
++
++static struct class tifm_adapter_class = {
++ .name = "tifm_adapter",
++ .release = tifm_free
++};
++
++struct tifm_adapter *tifm_alloc_adapter(void)
++{
++ struct tifm_adapter *fm;
++
++ fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
++ if (fm) {
++ fm->cdev.class = &tifm_adapter_class;
++ spin_lock_init(&fm->lock);
++ class_device_initialize(&fm->cdev);
++ }
++ return fm;
++}
++EXPORT_SYMBOL(tifm_alloc_adapter);
++
++void tifm_free_adapter(struct tifm_adapter *fm)
++{
++ class_device_put(&fm->cdev);
++}
++EXPORT_SYMBOL(tifm_free_adapter);
++
++int tifm_add_adapter(struct tifm_adapter *fm)
++{
++ int rc;
++
++ if (!idr_pre_get(&tifm_adapter_idr, GFP_KERNEL))
++ return -ENOMEM;
++
++ spin_lock(&tifm_adapter_lock);
++ rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
++ spin_unlock(&tifm_adapter_lock);
++ if (!rc) {
++ snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
++ strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
++
++ fm->wq = create_singlethread_workqueue(fm->wq_name);
++ if (fm->wq)
++ return class_device_add(&fm->cdev);
++
++ spin_lock(&tifm_adapter_lock);
++ idr_remove(&tifm_adapter_idr, fm->id);
++ spin_unlock(&tifm_adapter_lock);
++ rc = -ENOMEM;
++ }
++ return rc;
++}
++EXPORT_SYMBOL(tifm_add_adapter);
++
++void tifm_remove_adapter(struct tifm_adapter *fm)
++{
++ class_device_del(&fm->cdev);
++
++ spin_lock(&tifm_adapter_lock);
++ idr_remove(&tifm_adapter_idr, fm->id);
++ spin_unlock(&tifm_adapter_lock);
++}
++EXPORT_SYMBOL(tifm_remove_adapter);
++
++void tifm_free_device(struct device *dev)
++{
++ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
++ if (fm_dev->wq)
++ destroy_workqueue(fm_dev->wq);
++ kfree(fm_dev);
++}
++EXPORT_SYMBOL(tifm_free_device);
++
++struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
++{
++ struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
++
++ if (dev) {
++ spin_lock_init(&dev->lock);
++ snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
++ dev->wq = create_singlethread_workqueue(dev->wq_name);
++ if (!dev->wq) {
++ kfree(dev);
++ return NULL;
++ }
++ dev->dev.parent = fm->dev;
++ dev->dev.bus = &tifm_bus_type;
++ dev->dev.release = tifm_free_device;
++ }
++ return dev;
++}
++EXPORT_SYMBOL(tifm_alloc_device);
++
++void tifm_eject(struct tifm_dev *sock)
++{
++ struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
++ fm->eject(fm, sock);
++}
++EXPORT_SYMBOL(tifm_eject);
++
++int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
++ int direction)
++{
++ return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
++}
++EXPORT_SYMBOL(tifm_map_sg);
++
++void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
++ int direction)
++{
++ pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
++}
++EXPORT_SYMBOL(tifm_unmap_sg);
++
++static int tifm_device_probe(struct device *dev)
++{
++ struct tifm_driver *drv;
++ struct tifm_dev *fm_dev;
++ int rc = 0;
++ const tifm_media_id *id;
++
++ drv = container_of(dev->driver, struct tifm_driver, driver);
++ fm_dev = container_of(dev, struct tifm_dev, dev);
++ get_device(dev);
++ if (!fm_dev->drv && drv->probe && drv->id_table) {
++ rc = -ENODEV;
++ id = tifm_device_match(drv->id_table, fm_dev);
++ if (id)
++ rc = drv->probe(fm_dev);
++ if (rc >= 0) {
++ rc = 0;
++ fm_dev->drv = drv;
++ }
++ }
++ if (rc)
++ put_device(dev);
++ return rc;
++}
++
++static int tifm_device_remove(struct device *dev)
++{
++ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
++ struct tifm_driver *drv = fm_dev->drv;
++
++ if (drv) {
++ if (drv->remove) drv->remove(fm_dev);
++ fm_dev->drv = 0;
++ }
++
++ put_device(dev);
++ return 0;
++}
++
++int tifm_register_driver(struct tifm_driver *drv)
++{
++ drv->driver.bus = &tifm_bus_type;
++ drv->driver.probe = tifm_device_probe;
++ drv->driver.remove = tifm_device_remove;
++
++ return driver_register(&drv->driver);
++}
++EXPORT_SYMBOL(tifm_register_driver);
++
++void tifm_unregister_driver(struct tifm_driver *drv)
++{
++ driver_unregister(&drv->driver);
++}
++EXPORT_SYMBOL(tifm_unregister_driver);
++
++static int __init tifm_init(void)
++{
++ int rc = bus_register(&tifm_bus_type);
++
++ if (!rc) {
++ rc = class_register(&tifm_adapter_class);
++ if (rc)
++ bus_unregister(&tifm_bus_type);
++ }
++
++ return rc;
++}
++
++static void __exit tifm_exit(void)
++{
++ class_unregister(&tifm_adapter_class);
++ bus_unregister(&tifm_bus_type);
++}
++
++subsys_initcall(tifm_init);
++module_exit(tifm_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Alex Dubov");
++MODULE_DESCRIPTION("TI FlashMedia core driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRIVER_VERSION);
+diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
+index 45bcf09..ea41852 100644
+--- a/drivers/mmc/Kconfig
++++ b/drivers/mmc/Kconfig
+@@ -21,7 +21,7 @@ config MMC_DEBUG
+
+ config MMC_BLOCK
+ tristate "MMC block device driver"
+- depends on MMC
++ depends on MMC && BLOCK
+ default y
+ help
+ Say Y here to enable the MMC block device driver support.
+@@ -109,4 +109,20 @@ config MMC_IMX
+
+ If unsure, say N.
+
++config MMC_TIFM_SD
++ tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
++ depends on MMC && EXPERIMENTAL
++ select TIFM_CORE
++ help
++ Say Y here if you want to be able to access MMC/SD cards with
++ the Texas Instruments(R) Flash Media card reader, found in many
++ laptops.
++ This option 'selects' (turns on, enables) 'TIFM_CORE', but you
++ probably also need appropriate card reader host adapter, such as
++ 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
++ (TIFM_7XX1)'.
++
++ To compile this driver as a module, choose M here: the
++ module will be called tifm_sd.
++
+ endmenu
+diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
+index d2957e3..acfd4de 100644
+--- a/drivers/mmc/Makefile
++++ b/drivers/mmc/Makefile
+@@ -23,8 +23,10 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
+ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+ obj-$(CONFIG_MMC_OMAP) += omap.o
+ obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
++obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
+
+-mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
++mmc_core-y := mmc.o mmc_sysfs.o
++mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
+
+ ifeq ($(CONFIG_MMC_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
+index 6b7638b..494b23f 100644
+--- a/drivers/mmc/at91_mci.c
++++ b/drivers/mmc/at91_mci.c
+@@ -661,7 +661,7 @@ static void at91_mci_set_ios(struct mmc_
+ /*
+ * Handle an interrupt
+ */
+-static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t at91_mci_irq(int irq, void *devid)
+ {
+ struct at91mci_host *host = devid;
+ int completed = 0;
+@@ -754,7 +754,7 @@ static irqreturn_t at91_mci_irq(int irq,
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs)
++static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
+ {
+ struct at91mci_host *host = _host;
+ int present = !at91_get_gpio_value(irq);
+@@ -822,6 +822,7 @@ static int at91_mci_probe(struct platfor
+ mmc->f_min = 375000;
+ mmc->f_max = 25000000;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++ mmc->caps = MMC_CAP_BYTEBLOCK;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+@@ -850,7 +851,7 @@ static int at91_mci_probe(struct platfor
+ /*
+ * Allocate the MCI interrupt
+ */
+- ret = request_irq(AT91_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
++ ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
+ if (ret) {
+ printk(KERN_ERR "Failed to request MCI interrupt\n");
+ clk_disable(mci_clk);
+@@ -906,7 +907,7 @@ static int at91_mci_remove(struct platfo
+
+ mmc_remove_host(mmc);
+ at91_mci_disable();
+- free_irq(AT91_ID_MCI, host);
++ free_irq(AT91RM9200_ID_MCI, host);
+ mmc_free_host(mmc);
+
+ clk_disable(mci_clk); /* Disable the peripheral clock */
+diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
+index fb60616..53ffcbb 100644
+--- a/drivers/mmc/au1xmmc.c
++++ b/drivers/mmc/au1xmmc.c
+@@ -731,7 +731,7 @@ static void au1xmmc_set_ios(struct mmc_h
+ }
+ }
+
+-static void au1xmmc_dma_callback(int irq, void *dev_id, struct pt_regs *regs)
++static void au1xmmc_dma_callback(int irq, void *dev_id)
+ {
+ struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
+
+@@ -750,7 +750,7 @@ static void au1xmmc_dma_callback(int irq
+ #define STATUS_DATA_IN (SD_STATUS_NE)
+ #define STATUS_DATA_OUT (SD_STATUS_TH)
+
+-static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
+ {
+
+ u32 status;
+diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
+index fb6565b..659d4a8 100644
+--- a/drivers/mmc/imxmmc.c
++++ b/drivers/mmc/imxmmc.c
+@@ -635,7 +635,7 @@ static int imxmci_cpu_driven_data(struct
+ return trans_done;
+ }
+
+-static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
++static void imxmci_dma_irq(int dma, void *devid)
+ {
+ struct imxmci_host *host = devid;
+ uint32_t stat = MMC_STATUS;
+@@ -646,7 +646,7 @@ static void imxmci_dma_irq(int dma, void
+ tasklet_schedule(&host->tasklet);
+ }
+
+-static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t imxmci_irq(int irq, void *devid)
+ {
+ struct imxmci_host *host = devid;
+ uint32_t stat = MMC_STATUS;
+@@ -956,7 +956,7 @@ static int imxmci_probe(struct platform_
+ mmc->f_min = 150000;
+ mmc->f_max = CLK_RATE/2;
+ mmc->ocr_avail = MMC_VDD_32_33;
+- mmc->caps |= MMC_CAP_4_BIT_DATA;
++ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
+
+ /* MMC core transfer sizes tunable parameters */
+ mmc->max_hw_segs = 64;
+diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
+index 74eaaee..ee8863c 100644
+--- a/drivers/mmc/mmc.c
++++ b/drivers/mmc/mmc.c
+@@ -996,7 +996,6 @@ static void mmc_read_scrs(struct mmc_hos
+
+ mmc_set_data_timeout(&data, card, 0);
+
+- data.blksz_bits = 3;
+ data.blksz = 1 << 3;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+@@ -1167,9 +1166,9 @@ static void mmc_setup(struct mmc_host *h
+ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
+ {
+ if (delay)
+- schedule_delayed_work(&host->detect, delay);
++ mmc_schedule_delayed_work(&host->detect, delay);
+ else
+- schedule_work(&host->detect);
++ mmc_schedule_work(&host->detect);
+ }
+
+ EXPORT_SYMBOL(mmc_detect_change);
+@@ -1312,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host);
+ */
+ void mmc_free_host(struct mmc_host *host)
+ {
+- flush_scheduled_work();
++ mmc_flush_scheduled_work();
+ mmc_free_host_sysfs(host);
+ }
+
+diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
+index 97bae00..cd5e0ab 100644
+--- a/drivers/mmc/mmc.h
++++ b/drivers/mmc/mmc.h
+@@ -18,4 +18,8 @@ struct mmc_host *mmc_alloc_host_sysfs(in
+ int mmc_add_host_sysfs(struct mmc_host *host);
+ void mmc_remove_host_sysfs(struct mmc_host *host);
+ void mmc_free_host_sysfs(struct mmc_host *host);
++
++int mmc_schedule_work(struct work_struct *work);
++int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay);
++void mmc_flush_scheduled_work(void);
+ #endif
+diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
+index a0e0dad..f9027c8 100644
+--- a/drivers/mmc/mmc_block.c
++++ b/drivers/mmc/mmc_block.c
+@@ -28,10 +28,12 @@
+ #include <linux/kdev_t.h>
+ #include <linux/blkdev.h>
+ #include <linux/mutex.h>
++#include <linux/scatterlist.h>
+
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+ #include <linux/mmc/protocol.h>
++#include <linux/mmc/host.h>
+
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -153,18 +155,84 @@ static int mmc_blk_prep_rq(struct mmc_qu
+ return stat;
+ }
+
++static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
++{
++ int err;
++ u32 blocks;
++
++ struct mmc_request mrq;
++ struct mmc_command cmd;
++ struct mmc_data data;
++ unsigned int timeout_us;
++
++ struct scatterlist sg;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_APP_CMD;
++ cmd.arg = card->rca << 16;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
++
++ err = mmc_wait_for_cmd(card->host, &cmd, 0);
++ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
++ return (u32)-1;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
++ cmd.arg = 0;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
++
++ memset(&data, 0, sizeof(struct mmc_data));
++
++ data.timeout_ns = card->csd.tacc_ns * 100;
++ data.timeout_clks = card->csd.tacc_clks * 100;
++
++ timeout_us = data.timeout_ns / 1000;
++ timeout_us += data.timeout_clks * 1000 /
++ (card->host->ios.clock / 1000);
++
++ if (timeout_us > 100000) {
++ data.timeout_ns = 100000000;
++ data.timeout_clks = 0;
++ }
++
++ data.blksz = 4;
++ data.blocks = 1;
++ data.flags = MMC_DATA_READ;
++ data.sg = &sg;
++ data.sg_len = 1;
++
++ memset(&mrq, 0, sizeof(struct mmc_request));
++
++ mrq.cmd = &cmd;
++ mrq.data = &data;
++
++ sg_init_one(&sg, &blocks, 4);
++
++ mmc_wait_for_req(card->host, &mrq);
++
++ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
++ return (u32)-1;
++
++ blocks = ntohl(blocks);
++
++ return blocks;
++}
++
+ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ {
+ struct mmc_blk_data *md = mq->data;
+ struct mmc_card *card = md->queue.card;
++ struct mmc_blk_request brq;
+ int ret;
+
+ if (mmc_card_claim_host(card))
+ goto cmd_err;
+
+ do {
+- struct mmc_blk_request brq;
+ struct mmc_command cmd;
++ u32 readcmd, writecmd;
+
+ memset(&brq, 0, sizeof(struct mmc_blk_request));
+ brq.mrq.cmd = &brq.cmd;
+@@ -172,7 +240,6 @@ static int mmc_blk_issue_rq(struct mmc_q
+
+ brq.cmd.arg = req->sector << 9;
+ brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+- brq.data.blksz_bits = md->block_bits;
+ brq.data.blksz = 1 << md->block_bits;
+ brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+ brq.stop.opcode = MMC_STOP_TRANSMISSION;
+@@ -181,20 +248,34 @@ static int mmc_blk_issue_rq(struct mmc_q
+
+ mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
+
+- if (rq_data_dir(req) == READ) {
+- brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
+- brq.data.flags |= MMC_DATA_READ;
+- } else {
+- brq.cmd.opcode = MMC_WRITE_BLOCK;
+- brq.data.flags |= MMC_DATA_WRITE;
++ /*
++ * If the host doesn't support multiple block writes, force
++ * block writes to single block. SD cards are excepted from
++ * this rule as they support querying the number of
++ * successfully written sectors.
++ */
++ if (rq_data_dir(req) != READ &&
++ !(card->host->caps & MMC_CAP_MULTIWRITE) &&
++ !mmc_card_sd(card))
+ brq.data.blocks = 1;
+- }
+
+ if (brq.data.blocks > 1) {
+ brq.data.flags |= MMC_DATA_MULTI;
+ brq.mrq.stop = &brq.stop;
++ readcmd = MMC_READ_MULTIPLE_BLOCK;
++ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+ } else {
+ brq.mrq.stop = NULL;
++ readcmd = MMC_READ_SINGLE_BLOCK;
++ writecmd = MMC_WRITE_BLOCK;
++ }
++
++ if (rq_data_dir(req) == READ) {
++ brq.cmd.opcode = readcmd;
++ brq.data.flags |= MMC_DATA_READ;
++ } else {
++ brq.cmd.opcode = writecmd;
++ brq.data.flags |= MMC_DATA_WRITE;
+ }
+
+ brq.data.sg = mq->sg;
+@@ -219,27 +300,29 @@ static int mmc_blk_issue_rq(struct mmc_q
+ goto cmd_err;
+ }
+
+- do {
+- int err;
+-
+- cmd.opcode = MMC_SEND_STATUS;
+- cmd.arg = card->rca << 16;
+- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+- err = mmc_wait_for_cmd(card->host, &cmd, 5);
+- if (err) {
+- printk(KERN_ERR "%s: error %d requesting status\n",
+- req->rq_disk->disk_name, err);
+- goto cmd_err;
+- }
+- } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
++ if (rq_data_dir(req) != READ) {
++ do {
++ int err;
++
++ cmd.opcode = MMC_SEND_STATUS;
++ cmd.arg = card->rca << 16;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
++ err = mmc_wait_for_cmd(card->host, &cmd, 5);
++ if (err) {
++ printk(KERN_ERR "%s: error %d requesting status\n",
++ req->rq_disk->disk_name, err);
++ goto cmd_err;
++ }
++ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+ #if 0
+- if (cmd.resp[0] & ~0x00000900)
+- printk(KERN_ERR "%s: status = %08x\n",
+- req->rq_disk->disk_name, cmd.resp[0]);
+- if (mmc_decode_status(cmd.resp))
+- goto cmd_err;
++ if (cmd.resp[0] & ~0x00000900)
++ printk(KERN_ERR "%s: status = %08x\n",
++ req->rq_disk->disk_name, cmd.resp[0]);
++ if (mmc_decode_status(cmd.resp))
++ goto cmd_err;
+ #endif
++ }
+
+ /*
+ * A block was successfully transferred.
+@@ -262,19 +345,46 @@ static int mmc_blk_issue_rq(struct mmc_q
+ return 1;
+
+ cmd_err:
++ ret = 1;
++
++ /*
++ * If this is an SD card and we're writing, we can first
++ * mark the known good sectors as ok.
++ *
++ * If the card is not SD, we can still ok written sectors
++ * if the controller can do proper error reporting.
++ *
++ * For reads we just fail the entire chunk as that should
++ * be safe in all cases.
++ */
++ if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
++ u32 blocks;
++ unsigned int bytes;
++
++ blocks = mmc_sd_num_wr_blocks(card);
++ if (blocks != (u32)-1) {
++ if (card->csd.write_partial)
++ bytes = blocks << md->block_bits;
++ else
++ bytes = blocks << 9;
++ spin_lock_irq(&md->lock);
++ ret = end_that_request_chunk(req, 1, bytes);
++ spin_unlock_irq(&md->lock);
++ }
++ } else if (rq_data_dir(req) != READ &&
++ (card->host->caps & MMC_CAP_MULTIWRITE)) {
++ spin_lock_irq(&md->lock);
++ ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
++ spin_unlock_irq(&md->lock);
++ }
++
+ mmc_card_release_host(card);
+
+- /*
+- * This is a little draconian, but until we get proper
+- * error handling sorted out here, its the best we can
+- * do - especially as some hosts have no idea how much
+- * data was transferred before the error occurred.
+- */
+ spin_lock_irq(&md->lock);
+- do {
++ while (ret) {
+ ret = end_that_request_chunk(req, 0,
+ req->current_nr_sectors << 9);
+- } while (ret);
++ }
+
+ add_disk_randomness(req->rq_disk);
+ blkdev_dequeue_request(req);
+diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
+index 74f8cde..4ccdd82 100644
+--- a/drivers/mmc/mmc_queue.c
++++ b/drivers/mmc/mmc_queue.c
+@@ -28,7 +28,7 @@ static int mmc_prep_request(struct reque
+ struct mmc_queue *mq = q->queuedata;
+ int ret = BLKPREP_KILL;
+
+- if (req->flags & REQ_SPECIAL) {
++ if (blk_special_request(req)) {
+ /*
+ * Special commands already have the command
+ * blocks already setup in req->special.
+@@ -36,7 +36,7 @@ static int mmc_prep_request(struct reque
+ BUG_ON(!req->special);
+
+ ret = BLKPREP_OK;
+- } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
++ } else if (blk_fs_request(req) || blk_pc_request(req)) {
+ /*
+ * Block I/O requests need translating according
+ * to the protocol.
+@@ -50,7 +50,7 @@ static int mmc_prep_request(struct reque
+ }
+
+ if (ret == BLKPREP_OK)
+- req->flags |= REQ_DONTPREP;
++ req->cmd_flags |= REQ_DONTPREP;
+
+ return ret;
+ }
+diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
+index a2a35fd..10cc973 100644
+--- a/drivers/mmc/mmc_sysfs.c
++++ b/drivers/mmc/mmc_sysfs.c
+@@ -13,6 +13,7 @@
+ #include <linux/init.h>
+ #include <linux/device.h>
+ #include <linux/idr.h>
++#include <linux/workqueue.h>
+
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+@@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host
+ class_device_put(&host->class_dev);
+ }
+
++static struct workqueue_struct *workqueue;
++
++/*
++ * Internal function. Schedule work in the MMC work queue.
++ */
++int mmc_schedule_work(struct work_struct *work)
++{
++ return queue_work(workqueue, work);
++}
++
++/*
++ * Internal function. Schedule delayed work in the MMC work queue.
++ */
++int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay)
++{
++ return queue_delayed_work(workqueue, work, delay);
++}
++
++/*
++ * Internal function. Flush all scheduled work from the MMC work queue.
++ */
++void mmc_flush_scheduled_work(void)
++{
++ flush_workqueue(workqueue);
++}
+
+ static int __init mmc_init(void)
+ {
+- int ret = bus_register(&mmc_bus_type);
++ int ret;
++
++ workqueue = create_singlethread_workqueue("kmmcd");
++ if (!workqueue)
++ return -ENOMEM;
++
++ ret = bus_register(&mmc_bus_type);
+ if (ret == 0) {
+ ret = class_register(&mmc_host_class);
+ if (ret)
+@@ -333,6 +365,7 @@ static void __exit mmc_exit(void)
+ {
+ class_unregister(&mmc_host_class);
+ bus_unregister(&mmc_bus_type);
++ destroy_workqueue(workqueue);
+ }
+
+ module_init(mmc_init);
+diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
+index 1886562..828503c 100644
+--- a/drivers/mmc/mmci.c
++++ b/drivers/mmc/mmci.c
+@@ -69,12 +69,13 @@ static void mmci_start_data(struct mmci_
+ unsigned int datactrl, timeout, irqmask;
+ unsigned long long clks;
+ void __iomem *base;
++ int blksz_bits;
+
+ DBG(host, "blksz %04x blks %04x flags %08x\n",
+- 1 << data->blksz_bits, data->blocks, data->flags);
++ data->blksz, data->blocks, data->flags);
+
+ host->data = data;
+- host->size = data->blocks << data->blksz_bits;
++ host->size = data->blksz;
+ host->data_xfered = 0;
+
+ mmci_init_sg(host, data);
+@@ -88,7 +89,10 @@ static void mmci_start_data(struct mmci_
+ writel(timeout, base + MMCIDATATIMER);
+ writel(host->size, base + MMCIDATALENGTH);
+
+- datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
++ blksz_bits = ffs(data->blksz) - 1;
++ BUG_ON(1 << blksz_bits != data->blksz);
++
++ datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
+ if (data->flags & MMC_DATA_READ) {
+ datactrl |= MCI_DPSM_DIRECTION;
+ irqmask = MCI_RXFIFOHALFFULLMASK;
+@@ -145,7 +149,7 @@ mmci_data_irq(struct mmci_host *host, st
+ unsigned int status)
+ {
+ if (status & MCI_DATABLOCKEND) {
+- host->data_xfered += 1 << data->blksz_bits;
++ host->data_xfered += data->blksz;
+ }
+ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+ if (status & MCI_DATACRCFAIL)
+@@ -257,7 +261,7 @@ static int mmci_pio_write(struct mmci_ho
+ /*
+ * PIO data transfer IRQ handler.
+ */
+-static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
+ {
+ struct mmci_host *host = dev_id;
+ void __iomem *base = host->base;
+@@ -343,7 +347,7 @@ static irqreturn_t mmci_pio_irq(int irq,
+ /*
+ * Handle completion of command and data transfers.
+ */
+-static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mmci_irq(int irq, void *dev_id)
+ {
+ struct mmci_host *host = dev_id;
+ u32 status;
+@@ -505,6 +509,7 @@ static int mmci_probe(struct amba_device
+ mmc->f_min = (host->mclk + 511) / 512;
+ mmc->f_max = min(host->mclk, fmax);
+ mmc->ocr_avail = plat->ocr_mask;
++ mmc->caps = MMC_CAP_MULTIWRITE;
+
+ /*
+ * We can do SGIO
+diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
+index ddf06b3..762fa28 100644
+--- a/drivers/mmc/omap.c
++++ b/drivers/mmc/omap.c
+@@ -377,7 +377,7 @@ static inline void mmc_omap_report_irq(u
+ }
+ }
+
+-static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
+ {
+ struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
+ u16 status;
+@@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq,
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
+ {
+ struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
+
+@@ -1034,13 +1034,14 @@ static int __init mmc_omap_probe(struct
+ host->irq = pdev->resource[1].start;
+ host->base = (void __iomem*)IO_ADDRESS(r->start);
+
+- if (minfo->wire4)
+- mmc->caps |= MMC_CAP_4_BIT_DATA;
+-
+ mmc->ops = &mmc_omap_ops;
+ mmc->f_min = 400000;
+ mmc->f_max = 24000000;
+ mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
++ mmc->caps = MMC_CAP_BYTEBLOCK;
++
++ if (minfo->wire4)
++ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ /* Use scatterlist DMA to reduce per-transfer costs.
+ * NOTE max_seg_size assumption that small blocks aren't
+diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
+index ef35090..a526698 100644
+--- a/drivers/mmc/pxamci.c
++++ b/drivers/mmc/pxamci.c
+@@ -299,7 +299,7 @@ static int pxamci_data_done(struct pxamc
+ return 1;
+ }
+
+-static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t pxamci_irq(int irq, void *devid)
+ {
+ struct pxamci_host *host = devid;
+ unsigned int ireg;
+@@ -399,13 +399,13 @@ static struct mmc_host_ops pxamci_ops =
+ .set_ios = pxamci_set_ios,
+ };
+
+-static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
++static void pxamci_dma_irq(int dma, void *devid)
+ {
+ printk(KERN_ERR "DMA%d: IRQ???\n", dma);
+ DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+ }
+
+-static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t pxamci_detect_irq(int irq, void *devid)
+ {
+ struct pxamci_host *host = mmc_priv(devid);
+
+diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
+index 4e21b3b..9a7d39b 100644
+--- a/drivers/mmc/sdhci.c
++++ b/drivers/mmc/sdhci.c
+@@ -4,8 +4,9 @@
+ * Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
++ * 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/delay.h>
+@@ -34,6 +35,8 @@ static unsigned int debug_quirks = 0;
+
+ #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
+ #define SDHCI_QUIRK_FORCE_DMA (1<<1)
++/* Controller doesn't like some resets when there is no card inserted. */
++#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
+
+ static const struct pci_device_id pci_ids[] __devinitdata = {
+ {
+@@ -50,7 +53,8 @@ static const struct pci_device_id pci_id
+ .device = PCI_DEVICE_ID_RICOH_R5C822,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+- .driver_data = SDHCI_QUIRK_FORCE_DMA,
++ .driver_data = SDHCI_QUIRK_FORCE_DMA |
++ SDHCI_QUIRK_NO_CARD_NO_RESET,
+ },
+
+ {
+@@ -124,6 +128,12 @@ static void sdhci_reset(struct sdhci_hos
+ {
+ unsigned long timeout;
+
++ if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
++ if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
++ SDHCI_CARD_PRESENT))
++ return;
++ }
++
+ writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
+
+ if (mask & SDHCI_RESET_ALL)
+@@ -716,6 +726,7 @@ static void sdhci_request(struct mmc_hos
+ } else
+ sdhci_send_command(host, mrq->cmd);
+
++ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+@@ -752,6 +763,7 @@ static void sdhci_set_ios(struct mmc_hos
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+
++ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+@@ -859,6 +871,7 @@ static void sdhci_tasklet_finish(unsigne
+
+ sdhci_deactivate_led(host);
+
++ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ mmc_request_done(host->mmc, mrq);
+@@ -892,6 +905,7 @@ static void sdhci_timeout_timer(unsigned
+ }
+ }
+
++ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+@@ -971,7 +985,7 @@ static void sdhci_data_irq(struct sdhci_
+ }
+ }
+
+-static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sdhci_irq(int irq, void *dev_id)
+ {
+ irqreturn_t result;
+ struct sdhci_host* host = dev_id;
+@@ -1029,6 +1043,7 @@ static irqreturn_t sdhci_irq(int irq, vo
+
+ result = IRQ_HANDLED;
+
++ mmiowb();
+ out:
+ spin_unlock(&host->lock);
+
+@@ -1094,6 +1109,7 @@ static int sdhci_resume (struct pci_dev
+ if (chip->hosts[i]->flags & SDHCI_USE_DMA)
+ pci_set_master(pdev);
+ sdhci_init(chip->hosts[i]);
++ mmiowb();
+ ret = mmc_resume_host(chip->hosts[i]->mmc);
+ if (ret)
+ return ret;
+@@ -1167,6 +1183,9 @@ static int __devinit sdhci_probe_slot(st
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+
++ host->chip = chip;
++ chip->hosts[slot] = host;
++
+ host->bar = first_bar + slot;
+
+ host->addr = pci_resource_start(pdev, host->bar);
+@@ -1262,7 +1281,7 @@ static int __devinit sdhci_probe_slot(st
+ mmc->ops = &sdhci_ops;
+ mmc->f_min = host->max_clk / 256;
+ mmc->f_max = host->max_clk;
+- mmc->caps = MMC_CAP_4_BIT_DATA;
++ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+ mmc->ocr_avail = 0;
+ if (caps & SDHCI_CAN_VDD_330)
+@@ -1310,7 +1329,7 @@ static int __devinit sdhci_probe_slot(st
+ tasklet_init(&host->finish_tasklet,
+ sdhci_tasklet_finish, (unsigned long)host);
+
+- setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
++ setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+
+ ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
+ host->slot_descr, host);
+@@ -1323,8 +1342,7 @@ static int __devinit sdhci_probe_slot(st
+ sdhci_dumpregs(host);
+ #endif
+
+- host->chip = chip;
+- chip->hosts[slot] = host;
++ mmiowb();
+
+ mmc_add_host(mmc);
+
+diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
+index f245334..72a6793 100644
+--- a/drivers/mmc/sdhci.h
++++ b/drivers/mmc/sdhci.h
+@@ -4,8 +4,9 @@
+ * Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
++ * 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.
+ */
+
+ /*
+diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
+new file mode 100644
+index 0000000..0fdc55b
+--- /dev/null
++++ b/drivers/mmc/tifm_sd.c
+@@ -0,0 +1,934 @@
++/*
++ * tifm_sd.c - TI FlashMedia driver
++ *
++ * Copyright (C) 2006 Alex Dubov <oakad at yahoo.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/tifm.h>
++#include <linux/mmc/protocol.h>
++#include <linux/mmc/host.h>
++#include <linux/highmem.h>
++#include <asm/io.h>
++
++#define DRIVER_NAME "tifm_sd"
++#define DRIVER_VERSION "0.6"
++
++static int no_dma = 0;
++static int fixed_timeout = 0;
++module_param(no_dma, bool, 0644);
++module_param(fixed_timeout, bool, 0644);
++
++/* Constants here are mostly from OMAP5912 datasheet */
++#define TIFM_MMCSD_RESET 0x0002
++#define TIFM_MMCSD_CLKMASK 0x03ff
++#define TIFM_MMCSD_POWER 0x0800
++#define TIFM_MMCSD_4BBUS 0x8000
++#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
++#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
++#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
++#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
++#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
++#define TIFM_MMCSD_READ 0x8000
++
++#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */
++#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */
++#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
++#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
++#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
++#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
++#define TIFM_MMCSD_DTO 0x0020 /* data time-out */
++#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
++#define TIFM_MMCSD_CTO 0x0080 /* command time-out */
++#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
++#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
++#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
++#define TIFM_MMCSD_CERR 0x4000 /* card status error */
++
++#define TIFM_MMCSD_FIFO_SIZE 0x0020
++
++#define TIFM_MMCSD_RSP_R0 0x0000
++#define TIFM_MMCSD_RSP_R1 0x0100
++#define TIFM_MMCSD_RSP_R2 0x0200
++#define TIFM_MMCSD_RSP_R3 0x0300
++#define TIFM_MMCSD_RSP_R4 0x0400
++#define TIFM_MMCSD_RSP_R5 0x0500
++#define TIFM_MMCSD_RSP_R6 0x0600
++
++#define TIFM_MMCSD_RSP_BUSY 0x0800
++
++#define TIFM_MMCSD_CMD_BC 0x0000
++#define TIFM_MMCSD_CMD_BCR 0x1000
++#define TIFM_MMCSD_CMD_AC 0x2000
++#define TIFM_MMCSD_CMD_ADTC 0x3000
++
++typedef enum {
++ IDLE = 0,
++ CMD, /* main command ended */
++ BRS, /* block transfer finished */
++ SCMD, /* stop command ended */
++ CARD, /* card left busy state */
++ FIFO, /* FIFO operation completed (uncertain) */
++ READY
++} card_state_t;
++
++enum {
++ FIFO_RDY = 0x0001, /* hardware dependent value */
++ HOST_REG = 0x0002,
++ EJECT = 0x0004,
++ EJECT_DONE = 0x0008,
++ CARD_BUSY = 0x0010,
++ OPENDRAIN = 0x0040, /* hardware dependent value */
++ CARD_EVENT = 0x0100, /* hardware dependent value */
++ CARD_RO = 0x0200, /* hardware dependent value */
++ FIFO_EVENT = 0x10000 }; /* hardware dependent value */
++
++struct tifm_sd {
++ struct tifm_dev *dev;
++
++ unsigned int flags;
++ card_state_t state;
++ unsigned int clk_freq;
++ unsigned int clk_div;
++ unsigned long timeout_jiffies; // software timeout - 2 sec
++
++ struct mmc_request *req;
++ struct work_struct cmd_handler;
++ struct work_struct abort_handler;
++ wait_queue_head_t can_eject;
++
++ size_t written_blocks;
++ char *buffer;
++ size_t buffer_size;
++ size_t buffer_pos;
++
++};
++
++static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
++ unsigned int host_status)
++{
++ struct mmc_command *cmd = host->req->cmd;
++ unsigned int t_val = 0, cnt = 0;
++
++ if (host_status & TIFM_MMCSD_BRS) {
++ /* in non-dma rx mode BRS fires when fifo is still not empty */
++ if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
++ while (host->buffer_size > host->buffer_pos) {
++ t_val = readl(sock->addr + SOCK_MMCSD_DATA);
++ host->buffer[host->buffer_pos++] = t_val & 0xff;
++ host->buffer[host->buffer_pos++] =
++ (t_val >> 8) & 0xff;
++ }
++ }
++ return 1;
++ } else if (host->buffer) {
++ if ((cmd->data->flags & MMC_DATA_READ) &&
++ (host_status & TIFM_MMCSD_AF)) {
++ for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
++ t_val = readl(sock->addr + SOCK_MMCSD_DATA);
++ if (host->buffer_size > host->buffer_pos) {
++ host->buffer[host->buffer_pos++] =
++ t_val & 0xff;
++ host->buffer[host->buffer_pos++] =
++ (t_val >> 8) & 0xff;
++ }
++ }
++ } else if ((cmd->data->flags & MMC_DATA_WRITE)
++ && (host_status & TIFM_MMCSD_AE)) {
++ for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
++ if (host->buffer_size > host->buffer_pos) {
++ t_val = host->buffer[host->buffer_pos++] & 0x00ff;
++ t_val |= ((host->buffer[host->buffer_pos++]) << 8)
++ & 0xff00;
++ writel(t_val,
++ sock->addr + SOCK_MMCSD_DATA);
++ }
++ }
++ }
++ }
++ return 0;
++}
++
++static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
++{
++ unsigned int rc = 0;
++
++ switch (mmc_resp_type(cmd)) {
++ case MMC_RSP_NONE:
++ rc |= TIFM_MMCSD_RSP_R0;
++ break;
++ case MMC_RSP_R1B:
++ rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
++ case MMC_RSP_R1:
++ rc |= TIFM_MMCSD_RSP_R1;
++ break;
++ case MMC_RSP_R2:
++ rc |= TIFM_MMCSD_RSP_R2;
++ break;
++ case MMC_RSP_R3:
++ rc |= TIFM_MMCSD_RSP_R3;
++ break;
++ case MMC_RSP_R6:
++ rc |= TIFM_MMCSD_RSP_R6;
++ break;
++ default:
++ BUG();
++ }
++
++ switch (mmc_cmd_type(cmd)) {
++ case MMC_CMD_BC:
++ rc |= TIFM_MMCSD_CMD_BC;
++ break;
++ case MMC_CMD_BCR:
++ rc |= TIFM_MMCSD_CMD_BCR;
++ break;
++ case MMC_CMD_AC:
++ rc |= TIFM_MMCSD_CMD_AC;
++ break;
++ case MMC_CMD_ADTC:
++ rc |= TIFM_MMCSD_CMD_ADTC;
++ break;
++ default:
++ BUG();
++ }
++ return rc;
++}
++
++static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
++{
++ struct tifm_dev *sock = host->dev;
++ unsigned int cmd_mask = tifm_sd_op_flags(cmd) |
++ (host->flags & OPENDRAIN);
++
++ if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
++ cmd_mask |= TIFM_MMCSD_READ;
++
++ dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
++ cmd->opcode, cmd->arg, cmd_mask);
++
++ writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
++ writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
++ writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
++}
++
++static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
++{
++ cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
++ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
++ cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
++ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
++ cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
++ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
++ cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
++ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
++}
++
++static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
++ unsigned int host_status)
++{
++ struct mmc_command *cmd = host->req->cmd;
++
++change_state:
++ switch (host->state) {
++ case IDLE:
++ return;
++ case CMD:
++ if (host_status & TIFM_MMCSD_EOC) {
++ tifm_sd_fetch_resp(cmd, sock);
++ if (cmd->data) {
++ host->state = BRS;
++ } else
++ host->state = READY;
++ goto change_state;
++ }
++ break;
++ case BRS:
++ if (tifm_sd_transfer_data(sock, host, host_status)) {
++ if (!host->req->stop) {
++ if (cmd->data->flags & MMC_DATA_WRITE) {
++ host->state = CARD;
++ } else {
++ host->state =
++ host->buffer ? READY : FIFO;
++ }
++ goto change_state;
++ }
++ tifm_sd_exec(host, host->req->stop);
++ host->state = SCMD;
++ }
++ break;
++ case SCMD:
++ if (host_status & TIFM_MMCSD_EOC) {
++ tifm_sd_fetch_resp(host->req->stop, sock);
++ if (cmd->error) {
++ host->state = READY;
++ } else if (cmd->data->flags & MMC_DATA_WRITE) {
++ host->state = CARD;
++ } else {
++ host->state = host->buffer ? READY : FIFO;
++ }
++ goto change_state;
++ }
++ break;
++ case CARD:
++ if (!(host->flags & CARD_BUSY)
++ && (host->written_blocks == cmd->data->blocks)) {
++ host->state = host->buffer ? READY : FIFO;
++ goto change_state;
++ }
++ break;
++ case FIFO:
++ if (host->flags & FIFO_RDY) {
++ host->state = READY;
++ host->flags &= ~FIFO_RDY;
++ goto change_state;
++ }
++ break;
++ case READY:
++ queue_work(sock->wq, &host->cmd_handler);
++ return;
++ }
++
++ queue_delayed_work(sock->wq, &host->abort_handler,
++ host->timeout_jiffies);
++}
++
++/* Called from interrupt handler */
++static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
++ unsigned int sock_irq_status)
++{
++ struct tifm_sd *host;
++ unsigned int host_status = 0, fifo_status = 0;
++ int error_code = 0;
++
++ spin_lock(&sock->lock);
++ host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
++ cancel_delayed_work(&host->abort_handler);
++
++ if (sock_irq_status & FIFO_EVENT) {
++ fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
++ writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
++
++ host->flags |= fifo_status & FIFO_RDY;
++ }
++
++ if (sock_irq_status & CARD_EVENT) {
++ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
++ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
++
++ if (!(host->flags & HOST_REG))
++ queue_work(sock->wq, &host->cmd_handler);
++ if (!host->req)
++ goto done;
++
++ if (host_status & TIFM_MMCSD_ERRMASK) {
++ if (host_status & TIFM_MMCSD_CERR)
++ error_code = MMC_ERR_FAILED;
++ else if (host_status &
++ (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
++ error_code = MMC_ERR_TIMEOUT;
++ else if (host_status &
++ (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
++ error_code = MMC_ERR_BADCRC;
++
++ writel(TIFM_FIFO_INT_SETALL,
++ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
++ writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
++
++ if (host->req->stop) {
++ if (host->state == SCMD) {
++ host->req->stop->error = error_code;
++ } else if(host->state == BRS) {
++ host->req->cmd->error = error_code;
++ tifm_sd_exec(host, host->req->stop);
++ queue_delayed_work(sock->wq,
++ &host->abort_handler,
++ host->timeout_jiffies);
++ host->state = SCMD;
++ goto done;
++ } else {
++ host->req->cmd->error = error_code;
++ }
++ } else {
++ host->req->cmd->error = error_code;
++ }
++ host->state = READY;
++ }
++
++ if (host_status & TIFM_MMCSD_CB)
++ host->flags |= CARD_BUSY;
++ if ((host_status & TIFM_MMCSD_EOFB) &&
++ (host->flags & CARD_BUSY)) {
++ host->written_blocks++;
++ host->flags &= ~CARD_BUSY;
++ }
++ }
++
++ if (host->req)
++ tifm_sd_process_cmd(sock, host, host_status);
++done:
++ dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
++ host_status, fifo_status);
++ spin_unlock(&sock->lock);
++ return sock_irq_status;
++}
++
++static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
++{
++ struct tifm_dev *sock = card->dev;
++ unsigned int dest_cnt;
++
++ /* DMA style IO */
++
++ writel(TIFM_FIFO_INT_SETALL,
++ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
++ writel(long_log2(cmd->data->blksz) - 2,
++ sock->addr + SOCK_FIFO_PAGE_SIZE);
++ writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
++ writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
++
++ dest_cnt = (cmd->data->blocks) << 8;
++
++ writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS);
++
++ writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
++ writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
++
++ if (cmd->data->flags & MMC_DATA_WRITE) {
++ writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
++ writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
++ sock->addr + SOCK_DMA_CONTROL);
++ } else {
++ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
++ writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
++ }
++}
++
++static void tifm_sd_set_data_timeout(struct tifm_sd *host,
++ struct mmc_data *data)
++{
++ struct tifm_dev *sock = host->dev;
++ unsigned int data_timeout = data->timeout_clks;
++
++ if (fixed_timeout)
++ return;
++
++ data_timeout += data->timeout_ns /
++ ((1000000000 / host->clk_freq) * host->clk_div);
++ data_timeout *= 10; // call it fudge factor for now
++
++ if (data_timeout < 0xffff) {
++ writel((~TIFM_MMCSD_DPE) &
++ readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
++ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
++ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
++ } else {
++ writel(TIFM_MMCSD_DPE |
++ readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
++ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
++ data_timeout = (data_timeout >> 10) + 1;
++ if(data_timeout > 0xffff)
++ data_timeout = 0; /* set to unlimited */
++ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
++ }
++}
++
++static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct tifm_sd *host = mmc_priv(mmc);
++ struct tifm_dev *sock = host->dev;
++ unsigned long flags;
++ int sg_count = 0;
++ struct mmc_data *r_data = mrq->cmd->data;
++
++ spin_lock_irqsave(&sock->lock, flags);
++ if (host->flags & EJECT) {
++ spin_unlock_irqrestore(&sock->lock, flags);
++ goto err_out;
++ }
++
++ if (host->req) {
++ printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
++ spin_unlock_irqrestore(&sock->lock, flags);
++ goto err_out;
++ }
++
++ if (r_data) {
++ tifm_sd_set_data_timeout(host, r_data);
++
++ sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len,
++ mrq->cmd->flags & MMC_DATA_WRITE
++ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
++ if (sg_count != 1) {
++ printk(KERN_ERR DRIVER_NAME
++ ": scatterlist map failed\n");
++ spin_unlock_irqrestore(&sock->lock, flags);
++ goto err_out;
++ }
++
++ host->written_blocks = 0;
++ host->flags &= ~CARD_BUSY;
++ tifm_sd_prepare_data(host, mrq->cmd);
++ }
++
++ host->req = mrq;
++ host->state = CMD;
++ queue_delayed_work(sock->wq, &host->abort_handler,
++ host->timeout_jiffies);
++ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++ tifm_sd_exec(host, mrq->cmd);
++ spin_unlock_irqrestore(&sock->lock, flags);
++ return;
++
++err_out:
++ if (sg_count > 0)
++ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
++ (r_data->flags & MMC_DATA_WRITE)
++ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
++
++ mrq->cmd->error = MMC_ERR_TIMEOUT;
++ mmc_request_done(mmc, mrq);
++}
++
++static void tifm_sd_end_cmd(void *data)
++{
++ struct tifm_sd *host = data;
++ struct tifm_dev *sock = host->dev;
++ struct mmc_host *mmc = tifm_get_drvdata(sock);
++ struct mmc_request *mrq;
++ struct mmc_data *r_data = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sock->lock, flags);
++
++ mrq = host->req;
++ host->req = NULL;
++ host->state = IDLE;
++
++ if (!mrq) {
++ printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
++ spin_unlock_irqrestore(&sock->lock, flags);
++ return;
++ }
++
++ r_data = mrq->cmd->data;
++ if (r_data) {
++ if (r_data->flags & MMC_DATA_WRITE) {
++ r_data->bytes_xfered = host->written_blocks *
++ r_data->blksz;
++ } else {
++ r_data->bytes_xfered = r_data->blocks -
++ readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
++ r_data->bytes_xfered *= r_data->blksz;
++ r_data->bytes_xfered += r_data->blksz -
++ readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
++ }
++ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
++ (r_data->flags & MMC_DATA_WRITE)
++ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
++ }
++
++ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++
++ spin_unlock_irqrestore(&sock->lock, flags);
++ mmc_request_done(mmc, mrq);
++}
++
++static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct tifm_sd *host = mmc_priv(mmc);
++ struct tifm_dev *sock = host->dev;
++ unsigned long flags;
++ struct mmc_data *r_data = mrq->cmd->data;
++ char *t_buffer = NULL;
++
++ if (r_data) {
++ t_buffer = kmap(r_data->sg->page);
++ if (!t_buffer) {
++ printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
++ goto err_out;
++ }
++ }
++
++ spin_lock_irqsave(&sock->lock, flags);
++ if (host->flags & EJECT) {
++ spin_unlock_irqrestore(&sock->lock, flags);
++ goto err_out;
++ }
++
++ if (host->req) {
++ printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
++ spin_unlock_irqrestore(&sock->lock, flags);
++ goto err_out;
++ }
++
++ if (r_data) {
++ tifm_sd_set_data_timeout(host, r_data);
++
++ host->buffer = t_buffer + r_data->sg->offset;
++ host->buffer_size = mrq->cmd->data->blocks *
++ mrq->cmd->data->blksz;
++
++ writel(TIFM_MMCSD_BUFINT |
++ readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
++ sock->addr + SOCK_MMCSD_INT_ENABLE);
++ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
++ (TIFM_MMCSD_FIFO_SIZE - 1),
++ sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
++
++ host->written_blocks = 0;
++ host->flags &= ~CARD_BUSY;
++ host->buffer_pos = 0;
++ writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
++ writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
++ }
++
++ host->req = mrq;
++ host->state = CMD;
++ queue_delayed_work(sock->wq, &host->abort_handler,
++ host->timeout_jiffies);
++ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++ tifm_sd_exec(host, mrq->cmd);
++ spin_unlock_irqrestore(&sock->lock, flags);
++ return;
++
++err_out:
++ if (t_buffer)
++ kunmap(r_data->sg->page);
++
++ mrq->cmd->error = MMC_ERR_TIMEOUT;
++ mmc_request_done(mmc, mrq);
++}
++
++static void tifm_sd_end_cmd_nodma(void *data)
++{
++ struct tifm_sd *host = (struct tifm_sd*)data;
++ struct tifm_dev *sock = host->dev;
++ struct mmc_host *mmc = tifm_get_drvdata(sock);
++ struct mmc_request *mrq;
++ struct mmc_data *r_data = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sock->lock, flags);
++
++ mrq = host->req;
++ host->req = NULL;
++ host->state = IDLE;
++
++ if (!mrq) {
++ printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
++ spin_unlock_irqrestore(&sock->lock, flags);
++ return;
++ }
++
++ r_data = mrq->cmd->data;
++ if (r_data) {
++ writel((~TIFM_MMCSD_BUFINT) &
++ readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
++ sock->addr + SOCK_MMCSD_INT_ENABLE);
++
++ if (r_data->flags & MMC_DATA_WRITE) {
++ r_data->bytes_xfered = host->written_blocks *
++ r_data->blksz;
++ } else {
++ r_data->bytes_xfered = r_data->blocks -
++ readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
++ r_data->bytes_xfered *= r_data->blksz;
++ r_data->bytes_xfered += r_data->blksz -
++ readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
++ }
++ host->buffer = NULL;
++ host->buffer_pos = 0;
++ host->buffer_size = 0;
++ }
++
++ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++
++ spin_unlock_irqrestore(&sock->lock, flags);
++
++ if (r_data)
++ kunmap(r_data->sg->page);
++
++ mmc_request_done(mmc, mrq);
++}
++
++static void tifm_sd_abort(void *data)
++{
++ printk(KERN_ERR DRIVER_NAME
++ ": card failed to respond for a long period of time");
++ tifm_eject(((struct tifm_sd*)data)->dev);
++}
++
++static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ struct tifm_sd *host = mmc_priv(mmc);
++ struct tifm_dev *sock = host->dev;
++ unsigned int clk_div1, clk_div2;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sock->lock, flags);
++
++ dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width,
++ ios->power_mode);
++ if (ios->bus_width == MMC_BUS_WIDTH_4) {
++ writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
++ sock->addr + SOCK_MMCSD_CONFIG);
++ } else {
++ writel((~TIFM_MMCSD_4BBUS) &
++ readl(sock->addr + SOCK_MMCSD_CONFIG),
++ sock->addr + SOCK_MMCSD_CONFIG);
++ }
++
++ if (ios->clock) {
++ clk_div1 = 20000000 / ios->clock;
++ if (!clk_div1)
++ clk_div1 = 1;
++
++ clk_div2 = 24000000 / ios->clock;
++ if (!clk_div2)
++ clk_div2 = 1;
++
++ if ((20000000 / clk_div1) > ios->clock)
++ clk_div1++;
++ if ((24000000 / clk_div2) > ios->clock)
++ clk_div2++;
++ if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
++ host->clk_freq = 20000000;
++ host->clk_div = clk_div1;
++ writel((~TIFM_CTRL_FAST_CLK) &
++ readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++ } else {
++ host->clk_freq = 24000000;
++ host->clk_div = clk_div2;
++ writel(TIFM_CTRL_FAST_CLK |
++ readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++ }
++ } else {
++ host->clk_div = 0;
++ }
++ host->clk_div &= TIFM_MMCSD_CLKMASK;
++ writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
++ readl(sock->addr + SOCK_MMCSD_CONFIG)),
++ sock->addr + SOCK_MMCSD_CONFIG);
++
++ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
++ host->flags |= OPENDRAIN;
++ else
++ host->flags &= ~OPENDRAIN;
++
++ /* chip_select : maybe later */
++ //vdd
++ //power is set before probe / after remove
++ //I believe, power_off when already marked for eject is sufficient to
++ // allow removal.
++ if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
++ host->flags |= EJECT_DONE;
++ wake_up_all(&host->can_eject);
++ }
++
++ spin_unlock_irqrestore(&sock->lock, flags);
++}
++
++static int tifm_sd_ro(struct mmc_host *mmc)
++{
++ int rc;
++ struct tifm_sd *host = mmc_priv(mmc);
++ struct tifm_dev *sock = host->dev;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sock->lock, flags);
++
++ host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE));
++ rc = (host->flags & CARD_RO) ? 1 : 0;
++
++ spin_unlock_irqrestore(&sock->lock, flags);
++ return rc;
++}
++
++static struct mmc_host_ops tifm_sd_ops = {
++ .request = tifm_sd_request,
++ .set_ios = tifm_sd_ios,
++ .get_ro = tifm_sd_ro
++};
++
++static void tifm_sd_register_host(void *data)
++{
++ struct tifm_sd *host = (struct tifm_sd*)data;
++ struct tifm_dev *sock = host->dev;
++ struct mmc_host *mmc = tifm_get_drvdata(sock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&sock->lock, flags);
++ host->flags |= HOST_REG;
++ PREPARE_WORK(&host->cmd_handler,
++ no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
++ data);
++ spin_unlock_irqrestore(&sock->lock, flags);
++ dev_dbg(&sock->dev, "adding host\n");
++ mmc_add_host(mmc);
++}
++
++static int tifm_sd_probe(struct tifm_dev *sock)
++{
++ struct mmc_host *mmc;
++ struct tifm_sd *host;
++ int rc = -EIO;
++
++ if (!(TIFM_SOCK_STATE_OCCUPIED &
++ readl(sock->addr + SOCK_PRESENT_STATE))) {
++ printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
++ return rc;
++ }
++
++ mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
++ if (!mmc)
++ return -ENOMEM;
++
++ host = mmc_priv(mmc);
++ host->dev = sock;
++ host->clk_div = 61;
++ init_waitqueue_head(&host->can_eject);
++ INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host);
++ INIT_WORK(&host->abort_handler, tifm_sd_abort, host);
++
++ tifm_set_drvdata(sock, mmc);
++ sock->signal_irq = tifm_sd_signal_irq;
++
++ host->clk_freq = 20000000;
++ host->timeout_jiffies = msecs_to_jiffies(1000);
++
++ tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
++ mmc->ops = &tifm_sd_ops;
++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++ mmc->caps = MMC_CAP_4_BIT_DATA;
++ mmc->f_min = 20000000 / 60;
++ mmc->f_max = 24000000;
++ mmc->max_hw_segs = 1;
++ mmc->max_phys_segs = 1;
++ mmc->max_sectors = 127;
++ mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
++
++ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
++ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
++ writel(host->clk_div | TIFM_MMCSD_POWER,
++ sock->addr + SOCK_MMCSD_CONFIG);
++
++ for (rc = 0; rc < 50; rc++) {
++ /* Wait for reset ack */
++ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
++ rc = 0;
++ break;
++ }
++ msleep(10);
++ }
++
++ if (rc) {
++ printk(KERN_ERR DRIVER_NAME
++ ": card not ready - probe failed\n");
++ mmc_free_host(mmc);
++ return -ENODEV;
++ }
++
++ writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
++ writel(host->clk_div | TIFM_MMCSD_POWER,
++ sock->addr + SOCK_MMCSD_CONFIG);
++ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
++ writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
++ sock->addr + SOCK_MMCSD_INT_ENABLE);
++
++ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
++ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
++ writel(host->clk_div | TIFM_MMCSD_POWER,
++ sock->addr + SOCK_MMCSD_CONFIG);
++
++ queue_delayed_work(sock->wq, &host->abort_handler,
++ host->timeout_jiffies);
++
++ return 0;
++}
++
++static int tifm_sd_host_is_down(struct tifm_dev *sock)
++{
++ struct mmc_host *mmc = tifm_get_drvdata(sock);
++ struct tifm_sd *host = mmc_priv(mmc);
++ unsigned long flags;
++ int rc = 0;
++
++ spin_lock_irqsave(&sock->lock, flags);
++ rc = (host->flags & EJECT_DONE);
++ spin_unlock_irqrestore(&sock->lock, flags);
++ return rc;
++}
++
++static void tifm_sd_remove(struct tifm_dev *sock)
++{
++ struct mmc_host *mmc = tifm_get_drvdata(sock);
++ struct tifm_sd *host = mmc_priv(mmc);
++ unsigned long flags;
++
++ spin_lock_irqsave(&sock->lock, flags);
++ host->flags |= EJECT;
++ if (host->req)
++ queue_work(sock->wq, &host->cmd_handler);
++ spin_unlock_irqrestore(&sock->lock, flags);
++ wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
++ host->timeout_jiffies);
++
++ if (host->flags & HOST_REG)
++ mmc_remove_host(mmc);
++
++ /* The meaning of the bit majority in this constant is unknown. */
++ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
++ sock->addr + SOCK_CONTROL);
++ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
++ writel(TIFM_FIFO_INT_SETALL,
++ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
++ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
++
++ tifm_set_drvdata(sock, NULL);
++ mmc_free_host(mmc);
++}
++
++static tifm_media_id tifm_sd_id_tbl[] = {
++ FM_SD, 0
++};
++
++static struct tifm_driver tifm_sd_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE
++ },
++ .id_table = tifm_sd_id_tbl,
++ .probe = tifm_sd_probe,
++ .remove = tifm_sd_remove
++};
++
++static int __init tifm_sd_init(void)
++{
++ return tifm_register_driver(&tifm_sd_driver);
++}
++
++static void __exit tifm_sd_exit(void)
++{
++ tifm_unregister_driver(&tifm_sd_driver);
++}
++
++MODULE_AUTHOR("Alex Dubov");
++MODULE_DESCRIPTION("TI FlashMedia SD driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
++MODULE_VERSION(DRIVER_VERSION);
++
++module_init(tifm_sd_init);
++module_exit(tifm_sd_exit);
+diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
+index c351c6d..ced309b 100644
+--- a/drivers/mmc/wbsd.c
++++ b/drivers/mmc/wbsd.c
+@@ -4,8 +4,9 @@
+ * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
++ * 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.
+ *
+ *
+ * Warning!
+@@ -1255,7 +1256,7 @@ end:
+ * Interrupt handling
+ */
+
+-static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wbsd_irq(int irq, void *dev_id)
+ {
+ struct wbsd_host *host = dev_id;
+ int isr;
+@@ -1323,7 +1324,7 @@ static int __devinit wbsd_alloc_mmc(stru
+ mmc->f_min = 375000;
+ mmc->f_max = 24000000;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+- mmc->caps = MMC_CAP_4_BIT_DATA;
++ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+ spin_lock_init(&host->lock);
+
+diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
+index 249baa7..6072993 100644
+--- a/drivers/mmc/wbsd.h
++++ b/drivers/mmc/wbsd.h
+@@ -4,8 +4,9 @@
+ * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
++ * 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.
+ */
+
+ #define LOCK_CODE 0xAA
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 1344ad7..a304b34 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -101,7 +101,7 @@ config MTD_REDBOOT_PARTS_READONLY
+
+ config MTD_CMDLINE_PARTS
+ bool "Command line partition table parsing"
+- depends on MTD_PARTITIONS = "y"
++ depends on MTD_PARTITIONS = "y" && MTD = "y"
+ ---help---
+ Allow generic configuration of the MTD partition tables via the kernel
+ command line. Multiple flash resources are supported for hardware where
+@@ -166,7 +166,7 @@ config MTD_CHAR
+
+ config MTD_BLOCK
+ tristate "Caching block device access to MTD devices"
+- depends on MTD
++ depends on MTD && BLOCK
+ ---help---
+ Although most flash chips have an erase size too large to be useful
+ as block devices, it is possible to use MTD devices which are based
+@@ -188,7 +188,7 @@ config MTD_BLOCK
+
+ config MTD_BLOCK_RO
+ tristate "Readonly block device access to MTD devices"
+- depends on MTD_BLOCK!=y && MTD
++ depends on MTD_BLOCK!=y && MTD && BLOCK
+ help
+ This allows you to mount read-only file systems (such as cramfs)
+ from an MTD device, without the overhead (and danger) of the caching
+@@ -199,7 +199,7 @@ config MTD_BLOCK_RO
+
+ config FTL
+ tristate "FTL (Flash Translation Layer) support"
+- depends on MTD
++ depends on MTD && BLOCK
+ ---help---
+ This provides support for the original Flash Translation Layer which
+ is part of the PCMCIA specification. It uses a kind of pseudo-
+@@ -215,7 +215,7 @@ config FTL
+
+ config NFTL
+ tristate "NFTL (NAND Flash Translation Layer) support"
+- depends on MTD
++ depends on MTD && BLOCK
+ ---help---
+ This provides support for the NAND Flash Translation Layer which is
+ used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
+@@ -238,7 +238,7 @@ config NFTL_RW
+
+ config INFTL
+ tristate "INFTL (Inverse NAND Flash Translation Layer) support"
+- depends on MTD
++ depends on MTD && BLOCK
+ ---help---
+ This provides support for the Inverse NAND Flash Translation
+ Layer which is used on M-Systems' newer DiskOnChip devices. It
+@@ -255,7 +255,7 @@ config INFTL
+
+ config RFD_FTL
+ tristate "Resident Flash Disk (Flash Translation Layer) support"
+- depends on MTD
++ depends on MTD && BLOCK
+ ---help---
+ This provides support for the flash translation layer known
+ as the Resident Flash Disk (RFD), as used by the Embedded BIOS
+@@ -263,6 +263,14 @@ config RFD_FTL
+
+ http://www.gensw.com/pages/prod/bios/rfd.htm
+
++config SSFDC
++ tristate "NAND SSFDC (SmartMedia) read only translation layer"
++ depends on MTD
++ default n
++ help
++ This enables read only access to SmartMedia formatted NAND
++ flash. You can mount it with FAT file system.
++
+ source "drivers/mtd/chips/Kconfig"
+
+ source "drivers/mtd/maps/Kconfig"
+diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+index fc93744..1e36b9a 100644
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.
+ obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
+ obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
+ obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o
++obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o
+
+ nftl-objs := nftlcore.o nftlmount.o
+ inftl-objs := inftlcore.o inftlmount.o
+diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
+index 6d8f30d..72e6d73 100644
+--- a/drivers/mtd/chips/Kconfig
++++ b/drivers/mtd/chips/Kconfig
+@@ -270,7 +270,7 @@ config MTD_JEDEC
+ tristate "JEDEC device support"
+ depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
+ help
+- Enable older older JEDEC flash interface devices for self
++ Enable older JEDEC flash interface devices for self
+ programming flash. It is commonly used in older AMD chips. It is
+ only called JEDEC because the JEDEC association
+ <http://www.jedec.org/> distributes the identification codes for the
+diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
+index a482e89..702ae4c 100644
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -212,6 +212,7 @@ static void fixup_use_atmel_lock(struct
+ {
+ mtd->lock = cfi_atmel_lock;
+ mtd->unlock = cfi_atmel_unlock;
++ mtd->flags |= MTD_STUPID_LOCK;
+ }
+
+ static struct cfi_fixup cfi_fixup_table[] = {
+diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
+index 16c02b5..440f685 100644
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -136,7 +136,7 @@ config MTDRAM_ABS_POS
+
+ config MTD_BLOCK2MTD
+ tristate "MTD using block device"
+- depends on MTD
++ depends on MTD && BLOCK
+ help
+ This driver allows a block device to appear as an MTD. It would
+ generally be used in the following cases:
+diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
+index 2c01497..354e165 100644
+--- a/drivers/mtd/devices/pmc551.c
++++ b/drivers/mtd/devices/pmc551.c
+@@ -4,82 +4,82 @@
+ * PMC551 PCI Mezzanine Ram Device
+ *
+ * Author:
+- * Mark Ferrell <mferrell at mvista.com>
+- * Copyright 1999,2000 Nortel Networks
++ * Mark Ferrell <mferrell at mvista.com>
++ * Copyright 1999,2000 Nortel Networks
+ *
+ * License:
+- * As part of this driver was derived from the slram.c driver it
+- * falls under the same license, which is GNU General Public
+- * License v2
++ * As part of this driver was derived from the slram.c driver it
++ * falls under the same license, which is GNU General Public
++ * License v2
+ *
+ * Description:
+- * This driver is intended to support the PMC551 PCI Ram device
+- * from Ramix Inc. The PMC551 is a PMC Mezzanine module for
+- * cPCI embedded systems. The device contains a single SROM
+- * that initially programs the V370PDC chipset onboard the
+- * device, and various banks of DRAM/SDRAM onboard. This driver
+- * implements this PCI Ram device as an MTD (Memory Technology
+- * Device) so that it can be used to hold a file system, or for
+- * added swap space in embedded systems. Since the memory on
+- * this board isn't as fast as main memory we do not try to hook
+- * it into main memory as that would simply reduce performance
+- * on the system. Using it as a block device allows us to use
+- * it as high speed swap or for a high speed disk device of some
+- * sort. Which becomes very useful on diskless systems in the
+- * embedded market I might add.
++ * This driver is intended to support the PMC551 PCI Ram device
++ * from Ramix Inc. The PMC551 is a PMC Mezzanine module for
++ * cPCI embedded systems. The device contains a single SROM
++ * that initially programs the V370PDC chipset onboard the
++ * device, and various banks of DRAM/SDRAM onboard. This driver
++ * implements this PCI Ram device as an MTD (Memory Technology
++ * Device) so that it can be used to hold a file system, or for
++ * added swap space in embedded systems. Since the memory on
++ * this board isn't as fast as main memory we do not try to hook
++ * it into main memory as that would simply reduce performance
++ * on the system. Using it as a block device allows us to use
++ * it as high speed swap or for a high speed disk device of some
++ * sort. Which becomes very useful on diskless systems in the
++ * embedded market I might add.
+ *
+ * Notes:
+- * Due to what I assume is more buggy SROM, the 64M PMC551 I
+- * have available claims that all 4 of it's DRAM banks have 64M
+- * of ram configured (making a grand total of 256M onboard).
+- * This is slightly annoying since the BAR0 size reflects the
+- * aperture size, not the dram size, and the V370PDC supplies no
+- * other method for memory size discovery. This problem is
+- * mostly only relevant when compiled as a module, as the
+- * unloading of the module with an aperture size smaller then
+- * the ram will cause the driver to detect the onboard memory
+- * size to be equal to the aperture size when the module is
+- * reloaded. Soooo, to help, the module supports an msize
+- * option to allow the specification of the onboard memory, and
+- * an asize option, to allow the specification of the aperture
+- * size. The aperture must be equal to or less then the memory
+- * size, the driver will correct this if you screw it up. This
+- * problem is not relevant for compiled in drivers as compiled
+- * in drivers only init once.
++ * Due to what I assume is more buggy SROM, the 64M PMC551 I
++ * have available claims that all 4 of it's DRAM banks have 64M
++ * of ram configured (making a grand total of 256M onboard).
++ * This is slightly annoying since the BAR0 size reflects the
++ * aperture size, not the dram size, and the V370PDC supplies no
++ * other method for memory size discovery. This problem is
++ * mostly only relevant when compiled as a module, as the
++ * unloading of the module with an aperture size smaller then
++ * the ram will cause the driver to detect the onboard memory
++ * size to be equal to the aperture size when the module is
++ * reloaded. Soooo, to help, the module supports an msize
++ * option to allow the specification of the onboard memory, and
++ * an asize option, to allow the specification of the aperture
++ * size. The aperture must be equal to or less then the memory
++ * size, the driver will correct this if you screw it up. This
++ * problem is not relevant for compiled in drivers as compiled
++ * in drivers only init once.
+ *
+ * Credits:
+- * Saeed Karamooz <saeed at ramix.com> of Ramix INC. for the
+- * initial example code of how to initialize this device and for
+- * help with questions I had concerning operation of the device.
++ * Saeed Karamooz <saeed at ramix.com> of Ramix INC. for the
++ * initial example code of how to initialize this device and for
++ * help with questions I had concerning operation of the device.
+ *
+- * Most of the MTD code for this driver was originally written
+- * for the slram.o module in the MTD drivers package which
+- * allows the mapping of system memory into an MTD device.
+- * Since the PMC551 memory module is accessed in the same
+- * fashion as system memory, the slram.c code became a very nice
+- * fit to the needs of this driver. All we added was PCI
+- * detection/initialization to the driver and automatically figure
+- * out the size via the PCI detection.o, later changes by Corey
+- * Minyard set up the card to utilize a 1M sliding apature.
++ * Most of the MTD code for this driver was originally written
++ * for the slram.o module in the MTD drivers package which
++ * allows the mapping of system memory into an MTD device.
++ * Since the PMC551 memory module is accessed in the same
++ * fashion as system memory, the slram.c code became a very nice
++ * fit to the needs of this driver. All we added was PCI
++ * detection/initialization to the driver and automatically figure
++ * out the size via the PCI detection.o, later changes by Corey
++ * Minyard set up the card to utilize a 1M sliding apature.
+ *
+- * Corey Minyard <minyard at nortelnetworks.com>
+- * * Modified driver to utilize a sliding aperture instead of
+- * mapping all memory into kernel space which turned out to
+- * be very wasteful.
+- * * Located a bug in the SROM's initialization sequence that
+- * made the memory unusable, added a fix to code to touch up
+- * the DRAM some.
++ * Corey Minyard <minyard at nortelnetworks.com>
++ * * Modified driver to utilize a sliding aperture instead of
++ * mapping all memory into kernel space which turned out to
++ * be very wasteful.
++ * * Located a bug in the SROM's initialization sequence that
++ * made the memory unusable, added a fix to code to touch up
++ * the DRAM some.
+ *
+ * Bugs/FIXME's:
+- * * MUST fix the init function to not spin on a register
+- * waiting for it to set .. this does not safely handle busted
+- * devices that never reset the register correctly which will
+- * cause the system to hang w/ a reboot being the only chance at
+- * recover. [sort of fixed, could be better]
+- * * Add I2C handling of the SROM so we can read the SROM's information
+- * about the aperture size. This should always accurately reflect the
+- * onboard memory size.
+- * * Comb the init routine. It's still a bit cludgy on a few things.
++ * * MUST fix the init function to not spin on a register
++ * waiting for it to set .. this does not safely handle busted
++ * devices that never reset the register correctly which will
++ * cause the system to hang w/ a reboot being the only chance at
++ * recover. [sort of fixed, could be better]
++ * * Add I2C handling of the SROM so we can read the SROM's information
++ * about the aperture size. This should always accurately reflect the
++ * onboard memory size.
++ * * Comb the init routine. It's still a bit cludgy on a few things.
+ */
+
+ #include <linux/kernel.h>
+@@ -105,74 +105,77 @@
+
+ static struct mtd_info *pmc551list;
+
+-static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
++static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
+ {
+- struct mypriv *priv = mtd->priv;
+- u32 soff_hi, soff_lo; /* start address offset hi/lo */
+- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
+- unsigned long end;
++ struct mypriv *priv = mtd->priv;
++ u32 soff_hi, soff_lo; /* start address offset hi/lo */
++ u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
++ unsigned long end;
+ u_char *ptr;
+ size_t retlen;
+
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
++ printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr,
++ (long)instr->len);
+ #endif
+
+- end = instr->addr + instr->len - 1;
++ end = instr->addr + instr->len - 1;
+
+- /* Is it past the end? */
+- if ( end > mtd->size ) {
++ /* Is it past the end? */
++ if (end > mtd->size) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n", (long)end, (long)mtd->size);
++ printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n",
++ (long)end, (long)mtd->size);
+ #endif
+- return -EINVAL;
+- }
+-
+- eoff_hi = end & ~(priv->asize - 1);
+- soff_hi = instr->addr & ~(priv->asize - 1);
+- eoff_lo = end & (priv->asize - 1);
+- soff_lo = instr->addr & (priv->asize - 1);
+-
+- pmc551_point (mtd, instr->addr, instr->len, &retlen, &ptr);
+-
+- if ( soff_hi == eoff_hi || mtd->size == priv->asize) {
+- /* The whole thing fits within one access, so just one shot
+- will do it. */
+- memset(ptr, 0xff, instr->len);
+- } else {
+- /* We have to do multiple writes to get all the data
+- written. */
+- while (soff_hi != eoff_hi) {
++ return -EINVAL;
++ }
++
++ eoff_hi = end & ~(priv->asize - 1);
++ soff_hi = instr->addr & ~(priv->asize - 1);
++ eoff_lo = end & (priv->asize - 1);
++ soff_lo = instr->addr & (priv->asize - 1);
++
++ pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
++
++ if (soff_hi == eoff_hi || mtd->size == priv->asize) {
++ /* The whole thing fits within one access, so just one shot
++ will do it. */
++ memset(ptr, 0xff, instr->len);
++ } else {
++ /* We have to do multiple writes to get all the data
++ written. */
++ while (soff_hi != eoff_hi) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk( KERN_DEBUG "pmc551_erase() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
++ printk(KERN_DEBUG "pmc551_erase() soff_hi: %ld, "
++ "eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
+ #endif
+- memset(ptr, 0xff, priv->asize);
+- if (soff_hi + priv->asize >= mtd->size) {
+- goto out;
+- }
+- soff_hi += priv->asize;
+- pmc551_point (mtd,(priv->base_map0|soff_hi),
+- priv->asize, &retlen, &ptr);
+- }
+- memset (ptr, 0xff, eoff_lo);
+- }
+-
+-out:
++ memset(ptr, 0xff, priv->asize);
++ if (soff_hi + priv->asize >= mtd->size) {
++ goto out;
++ }
++ soff_hi += priv->asize;
++ pmc551_point(mtd, (priv->base_map0 | soff_hi),
++ priv->asize, &retlen, &ptr);
++ }
++ memset(ptr, 0xff, eoff_lo);
++ }
++
++ out:
+ instr->state = MTD_ERASE_DONE;
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+ printk(KERN_DEBUG "pmc551_erase() done\n");
+ #endif
+
+- mtd_erase_callback(instr);
+- return 0;
++ mtd_erase_callback(instr);
++ return 0;
+ }
+
+-
+-static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
++static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
++ size_t * retlen, u_char ** mtdbuf)
+ {
+- struct mypriv *priv = mtd->priv;
+- u32 soff_hi;
+- u32 soff_lo;
++ struct mypriv *priv = mtd->priv;
++ u32 soff_hi;
++ u32 soff_lo;
+
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+ printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
+@@ -180,18 +183,19 @@ static int pmc551_point (struct mtd_info
+
+ if (from + len > mtd->size) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n", (long)from+len, (long)mtd->size);
++ printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n",
++ (long)from + len, (long)mtd->size);
+ #endif
+ return -EINVAL;
+ }
+
+- soff_hi = from & ~(priv->asize - 1);
+- soff_lo = from & (priv->asize - 1);
++ soff_hi = from & ~(priv->asize - 1);
++ soff_lo = from & (priv->asize - 1);
+
+ /* Cheap hack optimization */
+- if( priv->curr_map0 != from ) {
+- pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
+- (priv->base_map0 | soff_hi) );
++ if (priv->curr_map0 != from) {
++ pci_write_config_dword(priv->dev, PMC551_PCI_MEM_MAP0,
++ (priv->base_map0 | soff_hi));
+ priv->curr_map0 = soff_hi;
+ }
+
+@@ -200,137 +204,144 @@ static int pmc551_point (struct mtd_info
+ return 0;
+ }
+
+-
+-static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
++static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
++ size_t len)
+ {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+ printk(KERN_DEBUG "pmc551_unpoint()\n");
+ #endif
+ }
+
+-
+-static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
++ size_t * retlen, u_char * buf)
+ {
+- struct mypriv *priv = mtd->priv;
+- u32 soff_hi, soff_lo; /* start address offset hi/lo */
+- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
+- unsigned long end;
++ struct mypriv *priv = mtd->priv;
++ u32 soff_hi, soff_lo; /* start address offset hi/lo */
++ u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
++ unsigned long end;
+ u_char *ptr;
+- u_char *copyto = buf;
++ u_char *copyto = buf;
+
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n", (long)from, (long)len, (long)priv->asize);
++ printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n",
++ (long)from, (long)len, (long)priv->asize);
+ #endif
+
+- end = from + len - 1;
++ end = from + len - 1;
+
+- /* Is it past the end? */
+- if (end > mtd->size) {
++ /* Is it past the end? */
++ if (end > mtd->size) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n", (long) end, (long)mtd->size);
++ printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n",
++ (long)end, (long)mtd->size);
+ #endif
+- return -EINVAL;
+- }
+-
+- soff_hi = from & ~(priv->asize - 1);
+- eoff_hi = end & ~(priv->asize - 1);
+- soff_lo = from & (priv->asize - 1);
+- eoff_lo = end & (priv->asize - 1);
+-
+- pmc551_point (mtd, from, len, retlen, &ptr);
+-
+- if (soff_hi == eoff_hi) {
+- /* The whole thing fits within one access, so just one shot
+- will do it. */
+- memcpy(copyto, ptr, len);
+- copyto += len;
+- } else {
+- /* We have to do multiple writes to get all the data
+- written. */
+- while (soff_hi != eoff_hi) {
++ return -EINVAL;
++ }
++
++ soff_hi = from & ~(priv->asize - 1);
++ eoff_hi = end & ~(priv->asize - 1);
++ soff_lo = from & (priv->asize - 1);
++ eoff_lo = end & (priv->asize - 1);
++
++ pmc551_point(mtd, from, len, retlen, &ptr);
++
++ if (soff_hi == eoff_hi) {
++ /* The whole thing fits within one access, so just one shot
++ will do it. */
++ memcpy(copyto, ptr, len);
++ copyto += len;
++ } else {
++ /* We have to do multiple writes to get all the data
++ written. */
++ while (soff_hi != eoff_hi) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk( KERN_DEBUG "pmc551_read() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
++ printk(KERN_DEBUG "pmc551_read() soff_hi: %ld, "
++ "eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
+ #endif
+- memcpy(copyto, ptr, priv->asize);
+- copyto += priv->asize;
+- if (soff_hi + priv->asize >= mtd->size) {
+- goto out;
+- }
+- soff_hi += priv->asize;
+- pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
+- }
+- memcpy(copyto, ptr, eoff_lo);
+- copyto += eoff_lo;
+- }
+-
+-out:
++ memcpy(copyto, ptr, priv->asize);
++ copyto += priv->asize;
++ if (soff_hi + priv->asize >= mtd->size) {
++ goto out;
++ }
++ soff_hi += priv->asize;
++ pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
++ }
++ memcpy(copyto, ptr, eoff_lo);
++ copyto += eoff_lo;
++ }
++
++ out:
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+ printk(KERN_DEBUG "pmc551_read() done\n");
+ #endif
+- *retlen = copyto - buf;
+- return 0;
++ *retlen = copyto - buf;
++ return 0;
+ }
+
+-static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
++static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
++ size_t * retlen, const u_char * buf)
+ {
+- struct mypriv *priv = mtd->priv;
+- u32 soff_hi, soff_lo; /* start address offset hi/lo */
+- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
+- unsigned long end;
++ struct mypriv *priv = mtd->priv;
++ u32 soff_hi, soff_lo; /* start address offset hi/lo */
++ u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
++ unsigned long end;
+ u_char *ptr;
+- const u_char *copyfrom = buf;
+-
++ const u_char *copyfrom = buf;
+
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n", (long)to, (long)len, (long)priv->asize);
++ printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n",
++ (long)to, (long)len, (long)priv->asize);
+ #endif
+
+- end = to + len - 1;
+- /* Is it past the end? or did the u32 wrap? */
+- if (end > mtd->size ) {
++ end = to + len - 1;
++ /* Is it past the end? or did the u32 wrap? */
++ if (end > mtd->size) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, size: %ld, to: %ld)\n", (long) end, (long)mtd->size, (long)to);
++ printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, "
++ "size: %ld, to: %ld)\n", (long)end, (long)mtd->size,
++ (long)to);
+ #endif
+- return -EINVAL;
+- }
+-
+- soff_hi = to & ~(priv->asize - 1);
+- eoff_hi = end & ~(priv->asize - 1);
+- soff_lo = to & (priv->asize - 1);
+- eoff_lo = end & (priv->asize - 1);
+-
+- pmc551_point (mtd, to, len, retlen, &ptr);
+-
+- if (soff_hi == eoff_hi) {
+- /* The whole thing fits within one access, so just one shot
+- will do it. */
+- memcpy(ptr, copyfrom, len);
+- copyfrom += len;
+- } else {
+- /* We have to do multiple writes to get all the data
+- written. */
+- while (soff_hi != eoff_hi) {
++ return -EINVAL;
++ }
++
++ soff_hi = to & ~(priv->asize - 1);
++ eoff_hi = end & ~(priv->asize - 1);
++ soff_lo = to & (priv->asize - 1);
++ eoff_lo = end & (priv->asize - 1);
++
++ pmc551_point(mtd, to, len, retlen, &ptr);
++
++ if (soff_hi == eoff_hi) {
++ /* The whole thing fits within one access, so just one shot
++ will do it. */
++ memcpy(ptr, copyfrom, len);
++ copyfrom += len;
++ } else {
++ /* We have to do multiple writes to get all the data
++ written. */
++ while (soff_hi != eoff_hi) {
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk( KERN_DEBUG "pmc551_write() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
++ printk(KERN_DEBUG "pmc551_write() soff_hi: %ld, "
++ "eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
+ #endif
+- memcpy(ptr, copyfrom, priv->asize);
+- copyfrom += priv->asize;
+- if (soff_hi >= mtd->size) {
+- goto out;
+- }
+- soff_hi += priv->asize;
+- pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
+- }
+- memcpy(ptr, copyfrom, eoff_lo);
+- copyfrom += eoff_lo;
+- }
+-
+-out:
++ memcpy(ptr, copyfrom, priv->asize);
++ copyfrom += priv->asize;
++ if (soff_hi >= mtd->size) {
++ goto out;
++ }
++ soff_hi += priv->asize;
++ pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
++ }
++ memcpy(ptr, copyfrom, eoff_lo);
++ copyfrom += eoff_lo;
++ }
++
++ out:
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+ printk(KERN_DEBUG "pmc551_write() done\n");
+ #endif
+- *retlen = copyfrom - buf;
+- return 0;
++ *retlen = copyfrom - buf;
++ return 0;
+ }
+
+ /*
+@@ -345,58 +356,58 @@ out:
+ * mechanism
+ * returns the size of the memory region found.
+ */
+-static u32 fixup_pmc551 (struct pci_dev *dev)
++static u32 fixup_pmc551(struct pci_dev *dev)
+ {
+ #ifdef CONFIG_MTD_PMC551_BUGFIX
+- u32 dram_data;
++ u32 dram_data;
+ #endif
+- u32 size, dcmd, cfg, dtmp;
+- u16 cmd, tmp, i;
++ u32 size, dcmd, cfg, dtmp;
++ u16 cmd, tmp, i;
+ u8 bcmd, counter;
+
+- /* Sanity Check */
+- if(!dev) {
+- return -ENODEV;
+- }
++ /* Sanity Check */
++ if (!dev) {
++ return -ENODEV;
++ }
+
+ /*
+ * Attempt to reset the card
+ * FIXME: Stop Spinning registers
+ */
+- counter=0;
++ counter = 0;
+ /* unlock registers */
+- pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
++ pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5);
+ /* read in old data */
+- pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
++ pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
+ /* bang the reset line up and down for a few */
+- for(i=0;i<10;i++) {
+- counter=0;
++ for (i = 0; i < 10; i++) {
++ counter = 0;
+ bcmd &= ~0x80;
+- while(counter++ < 100) {
++ while (counter++ < 100) {
+ pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
+ }
+- counter=0;
++ counter = 0;
+ bcmd |= 0x80;
+- while(counter++ < 100) {
++ while (counter++ < 100) {
+ pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
+ }
+ }
+- bcmd |= (0x40|0x20);
++ bcmd |= (0x40 | 0x20);
+ pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
+
+- /*
++ /*
+ * Take care and turn off the memory on the device while we
+ * tweak the configurations
+ */
+- pci_read_config_word(dev, PCI_COMMAND, &cmd);
+- tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
+- pci_write_config_word(dev, PCI_COMMAND, tmp);
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
++ pci_write_config_word(dev, PCI_COMMAND, tmp);
+
+ /*
+ * Disable existing aperture before probing memory size
+ */
+ pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
+- dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
++ dtmp = (dcmd | PMC551_PCI_MEM_MAP_ENABLE | PMC551_PCI_MEM_MAP_REG_EN);
+ pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
+ /*
+ * Grab old BAR0 config so that we can figure out memory size
+@@ -407,220 +418,230 @@ static u32 fixup_pmc551 (struct pci_dev
+ * then write all 1's to the memory space, read back the result into
+ * "size", and then write back all the old config.
+ */
+- pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
++ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &cfg);
+ #ifndef CONFIG_MTD_PMC551_BUGFIX
+- pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
+- pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
+- size = (size&PCI_BASE_ADDRESS_MEM_MASK);
+- size &= ~(size-1);
+- pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ~0);
++ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &size);
++ size = (size & PCI_BASE_ADDRESS_MEM_MASK);
++ size &= ~(size - 1);
++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, cfg);
+ #else
+- /*
+- * Get the size of the memory by reading all the DRAM size values
+- * and adding them up.
+- *
+- * KLUDGE ALERT: the boards we are using have invalid column and
+- * row mux values. We fix them here, but this will break other
+- * memory configurations.
+- */
+- pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
+- size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
+- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+- pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
+-
+- pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
+- size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+- pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
+-
+- pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
+- size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+- pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
+-
+- pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
+- size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+- pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
+-
+- /*
+- * Oops .. something went wrong
+- */
+- if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
+- return -ENODEV;
+- }
+-#endif /* CONFIG_MTD_PMC551_BUGFIX */
+-
+- if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+- return -ENODEV;
++ /*
++ * Get the size of the memory by reading all the DRAM size values
++ * and adding them up.
++ *
++ * KLUDGE ALERT: the boards we are using have invalid column and
++ * row mux values. We fix them here, but this will break other
++ * memory configurations.
++ */
++ pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
++ size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
++ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
++ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
++ pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
++
++ pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
++ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
++ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
++ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
++ pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
++
++ pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
++ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
++ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
++ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
++ pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
++
++ pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
++ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
++ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
++ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
++ pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
++
++ /*
++ * Oops .. something went wrong
++ */
++ if ((size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
++ return -ENODEV;
++ }
++#endif /* CONFIG_MTD_PMC551_BUGFIX */
++
++ if ((cfg & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
++ return -ENODEV;
+ }
+
+- /*
+- * Precharge Dram
+- */
+- pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
+- pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
+-
+- /*
+- * Wait until command has gone through
+- * FIXME: register spinning issue
+- */
+- do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
+- if(counter++ > 100)break;
+- } while ( (PCI_COMMAND_IO) & cmd );
+-
+- /*
++ /*
++ * Precharge Dram
++ */
++ pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0400);
++ pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x00bf);
++
++ /*
++ * Wait until command has gone through
++ * FIXME: register spinning issue
++ */
++ do {
++ pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
++ if (counter++ > 100)
++ break;
++ } while ((PCI_COMMAND_IO) & cmd);
++
++ /*
+ * Turn on auto refresh
+ * The loop is taken directly from Ramix's example code. I assume that
+ * this must be held high for some duration of time, but I can find no
+ * documentation refrencing the reasons why.
+- */
+- for ( i = 1; i<=8 ; i++) {
+- pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
+-
+- /*
+- * Make certain command has gone through
+- * FIXME: register spinning issue
+- */
+- counter=0;
+- do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
+- if(counter++ > 100)break;
+- } while ( (PCI_COMMAND_IO) & cmd );
+- }
+-
+- pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
+- pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
+-
+- /*
+- * Wait until command completes
+- * FIXME: register spinning issue
+- */
+- counter=0;
+- do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
+- if(counter++ > 100)break;
+- } while ( (PCI_COMMAND_IO) & cmd );
+-
+- pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
+- dcmd |= 0x02000000;
+- pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
+-
+- /*
+- * Check to make certain fast back-to-back, if not
+- * then set it so
+- */
+- pci_read_config_word( dev, PCI_STATUS, &cmd);
+- if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
+- cmd |= PCI_COMMAND_FAST_BACK;
+- pci_write_config_word( dev, PCI_STATUS, cmd);
+- }
+-
+- /*
+- * Check to make certain the DEVSEL is set correctly, this device
+- * has a tendancy to assert DEVSEL and TRDY when a write is performed
+- * to the memory when memory is read-only
+- */
+- if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
+- cmd &= ~PCI_STATUS_DEVSEL_MASK;
+- pci_write_config_word( dev, PCI_STATUS, cmd );
+- }
+- /*
+- * Set to be prefetchable and put everything back based on old cfg.
++ */
++ for (i = 1; i <= 8; i++) {
++ pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0df);
++
++ /*
++ * Make certain command has gone through
++ * FIXME: register spinning issue
++ */
++ counter = 0;
++ do {
++ pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
++ if (counter++ > 100)
++ break;
++ } while ((PCI_COMMAND_IO) & cmd);
++ }
++
++ pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0020);
++ pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0ff);
++
++ /*
++ * Wait until command completes
++ * FIXME: register spinning issue
++ */
++ counter = 0;
++ do {
++ pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
++ if (counter++ > 100)
++ break;
++ } while ((PCI_COMMAND_IO) & cmd);
++
++ pci_read_config_dword(dev, PMC551_DRAM_CFG, &dcmd);
++ dcmd |= 0x02000000;
++ pci_write_config_dword(dev, PMC551_DRAM_CFG, dcmd);
++
++ /*
++ * Check to make certain fast back-to-back, if not
++ * then set it so
++ */
++ pci_read_config_word(dev, PCI_STATUS, &cmd);
++ if ((cmd & PCI_COMMAND_FAST_BACK) == 0) {
++ cmd |= PCI_COMMAND_FAST_BACK;
++ pci_write_config_word(dev, PCI_STATUS, cmd);
++ }
++
++ /*
++ * Check to make certain the DEVSEL is set correctly, this device
++ * has a tendancy to assert DEVSEL and TRDY when a write is performed
++ * to the memory when memory is read-only
++ */
++ if ((cmd & PCI_STATUS_DEVSEL_MASK) != 0x0) {
++ cmd &= ~PCI_STATUS_DEVSEL_MASK;
++ pci_write_config_word(dev, PCI_STATUS, cmd);
++ }
++ /*
++ * Set to be prefetchable and put everything back based on old cfg.
+ * it's possible that the reset of the V370PDC nuked the original
+ * setup
+- */
++ */
++ /*
++ cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
++ pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
++ */
++
+ /*
+- cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+- pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
+- */
+-
+- /*
+- * Turn PCI memory and I/O bus access back on
+- */
+- pci_write_config_word( dev, PCI_COMMAND,
+- PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
++ * Turn PCI memory and I/O bus access back on
++ */
++ pci_write_config_word(dev, PCI_COMMAND,
++ PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- /*
+- * Some screen fun
+- */
+- printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%llx\n",
+- (size<1024)?size:(size<1048576)?size>>10:size>>20,
+- (size<1024)?'B':(size<1048576)?'K':'M',
+- size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
+- (unsigned long long)((dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK));
+-
+- /*
+- * Check to see the state of the memory
+- */
+- pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
+- printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
+- "pmc551: DRAM_BLK0 Size: %d at %d\n"
+- "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
+- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+- (((0x1<<0)&dcmd) == 0)?"Off":"On",
+- PMC551_DRAM_BLK_GET_SIZE(dcmd),
+- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+-
+- pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
+- printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
+- "pmc551: DRAM_BLK1 Size: %d at %d\n"
+- "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
+- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+- (((0x1<<0)&dcmd) == 0)?"Off":"On",
+- PMC551_DRAM_BLK_GET_SIZE(dcmd),
+- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+-
+- pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
+- printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
+- "pmc551: DRAM_BLK2 Size: %d at %d\n"
+- "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
+- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+- (((0x1<<0)&dcmd) == 0)?"Off":"On",
+- PMC551_DRAM_BLK_GET_SIZE(dcmd),
+- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+-
+- pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
+- printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
+- "pmc551: DRAM_BLK3 Size: %d at %d\n"
+- "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
+- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
+- (((0x1<<0)&dcmd) == 0)?"Off":"On",
+- PMC551_DRAM_BLK_GET_SIZE(dcmd),
+- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
+-
+- pci_read_config_word( dev, PCI_COMMAND, &cmd );
+- printk( KERN_DEBUG "pmc551: Memory Access %s\n",
+- (((0x1<<1)&cmd) == 0)?"off":"on" );
+- printk( KERN_DEBUG "pmc551: I/O Access %s\n",
+- (((0x1<<0)&cmd) == 0)?"off":"on" );
+-
+- pci_read_config_word( dev, PCI_STATUS, &cmd );
+- printk( KERN_DEBUG "pmc551: Devsel %s\n",
+- ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
+- ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
+- ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
+-
+- printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
+- ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
+-
+- pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
+- printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
+- "pmc551: System Control Register is %slocked to PCI access\n"
+- "pmc551: System Control Register is %slocked to EEPROM access\n",
+- (bcmd&0x1)?"software":"hardware",
+- (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
++ /*
++ * Some screen fun
++ */
++ printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at "
++ "0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
++ size >> 10 : size >> 20,
++ (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size,
++ ((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
++ (unsigned long long)pci_resource_start(dev, 0));
++
++ /*
++ * Check to see the state of the memory
++ */
++ pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dcmd);
++ printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
++ "pmc551: DRAM_BLK0 Size: %d at %d\n"
++ "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
++ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
++ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
++ PMC551_DRAM_BLK_GET_SIZE(dcmd),
++ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
++ ((dcmd >> 9) & 0xF));
++
++ pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dcmd);
++ printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
++ "pmc551: DRAM_BLK1 Size: %d at %d\n"
++ "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
++ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
++ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
++ PMC551_DRAM_BLK_GET_SIZE(dcmd),
++ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
++ ((dcmd >> 9) & 0xF));
++
++ pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dcmd);
++ printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
++ "pmc551: DRAM_BLK2 Size: %d at %d\n"
++ "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
++ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
++ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
++ PMC551_DRAM_BLK_GET_SIZE(dcmd),
++ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
++ ((dcmd >> 9) & 0xF));
++
++ pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dcmd);
++ printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
++ "pmc551: DRAM_BLK3 Size: %d at %d\n"
++ "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
++ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
++ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
++ PMC551_DRAM_BLK_GET_SIZE(dcmd),
++ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
++ ((dcmd >> 9) & 0xF));
++
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ printk(KERN_DEBUG "pmc551: Memory Access %s\n",
++ (((0x1 << 1) & cmd) == 0) ? "off" : "on");
++ printk(KERN_DEBUG "pmc551: I/O Access %s\n",
++ (((0x1 << 0) & cmd) == 0) ? "off" : "on");
++
++ pci_read_config_word(dev, PCI_STATUS, &cmd);
++ printk(KERN_DEBUG "pmc551: Devsel %s\n",
++ ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x000) ? "Fast" :
++ ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x200) ? "Medium" :
++ ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x400) ? "Slow" : "Invalid");
++
++ printk(KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
++ ((PCI_COMMAND_FAST_BACK & cmd) == 0) ? "Not " : "");
++
++ pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
++ printk(KERN_DEBUG "pmc551: EEPROM is under %s control\n"
++ "pmc551: System Control Register is %slocked to PCI access\n"
++ "pmc551: System Control Register is %slocked to EEPROM access\n",
++ (bcmd & 0x1) ? "software" : "hardware",
++ (bcmd & 0x20) ? "" : "un", (bcmd & 0x40) ? "" : "un");
+ #endif
+- return size;
++ return size;
+ }
+
+ /*
+ * Kernel version specific module stuffages
+ */
+
+-
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Mark Ferrell <mferrell at mvista.com>");
+ MODULE_DESCRIPTION(PMC551_VERSION);
+@@ -628,11 +649,11 @@ MODULE_DESCRIPTION(PMC551_VERSION);
+ /*
+ * Stuff these outside the ifdef so as to not bust compiled in driver support
+ */
+-static int msize=0;
++static int msize = 0;
+ #if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
+-static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
++static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE
+ #else
+-static int asize=0;
++static int asize = 0;
+ #endif
+
+ module_param(msize, int, 0);
+@@ -645,164 +666,174 @@ MODULE_PARM_DESC(asize, "aperture size,
+ */
+ static int __init init_pmc551(void)
+ {
+- struct pci_dev *PCI_Device = NULL;
+- struct mypriv *priv;
+- int count, found=0;
+- struct mtd_info *mtd;
+- u32 length = 0;
+-
+- if(msize) {
+- msize = (1 << (ffs(msize) - 1))<<20;
+- if (msize > (1<<30)) {
+- printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n", msize);
++ struct pci_dev *PCI_Device = NULL;
++ struct mypriv *priv;
++ int count, found = 0;
++ struct mtd_info *mtd;
++ u32 length = 0;
++
++ if (msize) {
++ msize = (1 << (ffs(msize) - 1)) << 20;
++ if (msize > (1 << 30)) {
++ printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n",
++ msize);
+ return -EINVAL;
+ }
+ }
+
+- if(asize) {
+- asize = (1 << (ffs(asize) - 1))<<20;
+- if (asize > (1<<30) ) {
+- printk(KERN_NOTICE "pmc551: Invalid aperture size [%d]\n", asize);
++ if (asize) {
++ asize = (1 << (ffs(asize) - 1)) << 20;
++ if (asize > (1 << 30)) {
++ printk(KERN_NOTICE "pmc551: Invalid aperture size "
++ "[%d]\n", asize);
+ return -EINVAL;
+ }
+ }
+
+- printk(KERN_INFO PMC551_VERSION);
+-
+- /*
+- * PCU-bus chipset probe.
+- */
+- for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
+-
+- if ((PCI_Device = pci_find_device(PCI_VENDOR_ID_V3_SEMI,
+- PCI_DEVICE_ID_V3_SEMI_V370PDC,
+- PCI_Device ) ) == NULL) {
+- break;
+- }
+-
+- printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
+- (unsigned long long)PCI_Device->resource[0].start);
+-
+- /*
+- * The PMC551 device acts VERY weird if you don't init it
+- * first. i.e. it will not correctly report devsel. If for
+- * some reason the sdram is in a wrote-protected state the
+- * device will DEVSEL when it is written to causing problems
+- * with the oldproc.c driver in
+- * some kernels (2.2.*)
+- */
+- if((length = fixup_pmc551(PCI_Device)) <= 0) {
+- printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
+- break;
+- }
++ printk(KERN_INFO PMC551_VERSION);
++
++ /*
++ * PCU-bus chipset probe.
++ */
++ for (count = 0; count < MAX_MTD_DEVICES; count++) {
++
++ if ((PCI_Device = pci_get_device(PCI_VENDOR_ID_V3_SEMI,
++ PCI_DEVICE_ID_V3_SEMI_V370PDC,
++ PCI_Device)) == NULL) {
++ break;
++ }
++
++ printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
++ (unsigned long long)pci_resource_start(PCI_Device, 0));
++
++ /*
++ * The PMC551 device acts VERY weird if you don't init it
++ * first. i.e. it will not correctly report devsel. If for
++ * some reason the sdram is in a wrote-protected state the
++ * device will DEVSEL when it is written to causing problems
++ * with the oldproc.c driver in
++ * some kernels (2.2.*)
++ */
++ if ((length = fixup_pmc551(PCI_Device)) <= 0) {
++ printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
++ break;
++ }
+
+ /*
+ * This is needed until the driver is capable of reading the
+ * onboard I2C SROM to discover the "real" memory size.
+ */
+- if(msize) {
++ if (msize) {
+ length = msize;
+- printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
++ printk(KERN_NOTICE "pmc551: Using specified memory "
++ "size 0x%x\n", length);
+ } else {
+ msize = length;
+ }
+
+- mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+- if (!mtd) {
+- printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
+- break;
+- }
+-
+- memset(mtd, 0, sizeof(struct mtd_info));
+-
+- priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
+- if (!priv) {
+- printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
+- kfree(mtd);
+- break;
+- }
+- memset(priv, 0, sizeof(*priv));
+- mtd->priv = priv;
+- priv->dev = PCI_Device;
+-
+- if(asize > length) {
+- printk(KERN_NOTICE "pmc551: reducing aperture size to fit %dM\n",length>>20);
++ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
++ if (!mtd) {
++ printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
++ "device.\n");
++ break;
++ }
++
++ priv = kzalloc(sizeof(struct mypriv), GFP_KERNEL);
++ if (!priv) {
++ printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
++ "device.\n");
++ kfree(mtd);
++ break;
++ }
++ mtd->priv = priv;
++ priv->dev = PCI_Device;
++
++ if (asize > length) {
++ printk(KERN_NOTICE "pmc551: reducing aperture size to "
++ "fit %dM\n", length >> 20);
+ priv->asize = asize = length;
+ } else if (asize == 0 || asize == length) {
+- printk(KERN_NOTICE "pmc551: Using existing aperture size %dM\n", length>>20);
++ printk(KERN_NOTICE "pmc551: Using existing aperture "
++ "size %dM\n", length >> 20);
+ priv->asize = asize = length;
+ } else {
+- printk(KERN_NOTICE "pmc551: Using specified aperture size %dM\n", asize>>20);
++ printk(KERN_NOTICE "pmc551: Using specified aperture "
++ "size %dM\n", asize >> 20);
+ priv->asize = asize;
+ }
+- priv->start = ioremap(((PCI_Device->resource[0].start)
+- & PCI_BASE_ADDRESS_MEM_MASK),
+- priv->asize);
++ priv->start = pci_iomap(PCI_Device, 0, priv->asize);
+
+ if (!priv->start) {
+ printk(KERN_NOTICE "pmc551: Unable to map IO space\n");
+- kfree(mtd->priv);
+- kfree(mtd);
++ kfree(mtd->priv);
++ kfree(mtd);
+ break;
+ }
+-
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk( KERN_DEBUG "pmc551: setting aperture to %d\n",
+- ffs(priv->asize>>20)-1);
++ printk(KERN_DEBUG "pmc551: setting aperture to %d\n",
++ ffs(priv->asize >> 20) - 1);
+ #endif
+
+- priv->base_map0 = ( PMC551_PCI_MEM_MAP_REG_EN
+- | PMC551_PCI_MEM_MAP_ENABLE
+- | (ffs(priv->asize>>20)-1)<<4 );
+- priv->curr_map0 = priv->base_map0;
+- pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
+- priv->curr_map0 );
++ priv->base_map0 = (PMC551_PCI_MEM_MAP_REG_EN
++ | PMC551_PCI_MEM_MAP_ENABLE
++ | (ffs(priv->asize >> 20) - 1) << 4);
++ priv->curr_map0 = priv->base_map0;
++ pci_write_config_dword(priv->dev, PMC551_PCI_MEM_MAP0,
++ priv->curr_map0);
+
+ #ifdef CONFIG_MTD_PMC551_DEBUG
+- printk( KERN_DEBUG "pmc551: aperture set to %d\n",
+- (priv->base_map0 & 0xF0)>>4 );
++ printk(KERN_DEBUG "pmc551: aperture set to %d\n",
++ (priv->base_map0 & 0xF0) >> 4);
+ #endif
+
+- mtd->size = msize;
+- mtd->flags = MTD_CAP_RAM;
+- mtd->erase = pmc551_erase;
+- mtd->read = pmc551_read;
+- mtd->write = pmc551_write;
+- mtd->point = pmc551_point;
+- mtd->unpoint = pmc551_unpoint;
+- mtd->type = MTD_RAM;
+- mtd->name = "PMC551 RAM board";
+- mtd->erasesize = 0x10000;
+- mtd->writesize = 1;
+- mtd->owner = THIS_MODULE;
+-
+- if (add_mtd_device(mtd)) {
+- printk(KERN_NOTICE "pmc551: Failed to register new device\n");
+- iounmap(priv->start);
+- kfree(mtd->priv);
+- kfree(mtd);
+- break;
+- }
+- printk(KERN_NOTICE "Registered pmc551 memory device.\n");
+- printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+- priv->asize>>20,
+- priv->start,
+- priv->start + priv->asize);
+- printk(KERN_NOTICE "Total memory is %d%c\n",
+- (length<1024)?length:
+- (length<1048576)?length>>10:length>>20,
+- (length<1024)?'B':(length<1048576)?'K':'M');
++ mtd->size = msize;
++ mtd->flags = MTD_CAP_RAM;
++ mtd->erase = pmc551_erase;
++ mtd->read = pmc551_read;
++ mtd->write = pmc551_write;
++ mtd->point = pmc551_point;
++ mtd->unpoint = pmc551_unpoint;
++ mtd->type = MTD_RAM;
++ mtd->name = "PMC551 RAM board";
++ mtd->erasesize = 0x10000;
++ mtd->writesize = 1;
++ mtd->owner = THIS_MODULE;
++
++ if (add_mtd_device(mtd)) {
++ printk(KERN_NOTICE "pmc551: Failed to register new "
++ "device\n");
++ pci_iounmap(PCI_Device, priv->start);
++ kfree(mtd->priv);
++ kfree(mtd);
++ break;
++ }
++
++ /* Keep a reference as the add_mtd_device worked */
++ pci_dev_get(PCI_Device);
++
++ printk(KERN_NOTICE "Registered pmc551 memory device.\n");
++ printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
++ priv->asize >> 20,
++ priv->start, priv->start + priv->asize);
++ printk(KERN_NOTICE "Total memory is %d%c\n",
++ (length < 1024) ? length :
++ (length < 1048576) ? length >> 10 : length >> 20,
++ (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M');
+ priv->nextpmc551 = pmc551list;
+ pmc551list = mtd;
+ found++;
+- }
++ }
++
++ /* Exited early, reference left over */
++ if (PCI_Device)
++ pci_dev_put(PCI_Device);
+
+- if( !pmc551list ) {
+- printk(KERN_NOTICE "pmc551: not detected\n");
+- return -ENODEV;
+- } else {
++ if (!pmc551list) {
++ printk(KERN_NOTICE "pmc551: not detected\n");
++ return -ENODEV;
++ } else {
+ printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
+- return 0;
++ return 0;
+ }
+ }
+
+@@ -811,23 +842,24 @@ static int __init init_pmc551(void)
+ */
+ static void __exit cleanup_pmc551(void)
+ {
+- int found=0;
+- struct mtd_info *mtd;
++ int found = 0;
++ struct mtd_info *mtd;
+ struct mypriv *priv;
+
+- while((mtd=pmc551list)) {
++ while ((mtd = pmc551list)) {
+ priv = mtd->priv;
+ pmc551list = priv->nextpmc551;
+
+- if(priv->start) {
+- printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n",
+- priv->asize>>20, priv->start);
+- iounmap (priv->start);
++ if (priv->start) {
++ printk(KERN_DEBUG "pmc551: unmapping %dM starting at "
++ "0x%p\n", priv->asize >> 20, priv->start);
++ pci_iounmap(priv->dev, priv->start);
+ }
++ pci_dev_put(priv->dev);
+
+- kfree (mtd->priv);
+- del_mtd_device (mtd);
+- kfree (mtd);
++ kfree(mtd->priv);
++ del_mtd_device(mtd);
++ kfree(mtd);
+ found++;
+ }
+
+diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
+index 64d1b6a..24747bd 100644
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -447,14 +447,6 @@ config MTD_DC21285
+ 21285 bridge used with Intel's StrongARM processors. More info at
+ <http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
+
+-config MTD_IQ80310
+- tristate "CFI Flash device mapped on the XScale IQ80310 board"
+- depends on MTD_CFI && ARCH_IQ80310
+- help
+- This enables access routines for the flash chips on the Intel XScale
+- IQ80310 evaluation board. If you have one of these boards and would
+- like to use the flash chips on it, say 'Y'.
+-
+ config MTD_IXP4XX
+ tristate "CFI Flash device mapped on Intel IXP4xx based systems"
+ depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
+diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
+index ab71f17..191c192 100644
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_fla
+ 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_IQ80310) += iq80310.o
+ obj-$(CONFIG_MTD_L440GX) += l440gx.o
+ obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
+ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
+diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
+index 447955b..797caff 100644
+--- a/drivers/mtd/maps/amd76xrom.c
++++ b/drivers/mtd/maps/amd76xrom.c
+@@ -57,6 +57,7 @@ static void amd76xrom_cleanup(struct amd
+ /* Disable writes through the rom window */
+ pci_read_config_byte(window->pdev, 0x40, &byte);
+ pci_write_config_byte(window->pdev, 0x40, byte & ~1);
++ pci_dev_put(window->pdev);
+ }
+
+ /* Free all of the mtd devices */
+@@ -91,7 +92,7 @@ static int __devinit amd76xrom_init_one
+ struct amd76xrom_map_info *map = NULL;
+ unsigned long map_top;
+
+- /* Remember the pci dev I find the window in */
++ /* Remember the pci dev I find the window in - already have a ref */
+ window->pdev = pdev;
+
+ /* Assume the rom window is properly setup, and find it's size */
+@@ -302,7 +303,7 @@ static int __init init_amd76xrom(void)
+ struct pci_device_id *id;
+ pdev = NULL;
+ for(id = amd76xrom_pci_tbl; id->vendor; id++) {
+- pdev = pci_find_device(id->vendor, id->device, NULL);
++ pdev = pci_get_device(id->vendor, id->device, NULL);
+ if (pdev) {
+ break;
+ }
+diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
+index d95ae58..2cc9024 100644
+--- a/drivers/mtd/maps/arctic-mtd.c
++++ b/drivers/mtd/maps/arctic-mtd.c
+@@ -96,6 +96,8 @@ static struct mtd_partition arctic_parti
+ static int __init
+ init_arctic_mtd(void)
+ {
++ int err;
++
+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
+
+ arctic_mtd_map.virt = ioremap(PADDR, SIZE);
+@@ -109,12 +111,20 @@ init_arctic_mtd(void)
+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
+ arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
+
+- if (!arctic_mtd)
++ if (!arctic_mtd) {
++ iounmap(arctic_mtd_map.virt);
+ return -ENXIO;
++ }
+
+ arctic_mtd->owner = THIS_MODULE;
+
+- return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
++ err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
++ if (err) {
++ printk("%s: add_mtd_partitions failed\n", NAME);
++ iounmap(arctic_mtd_map.virt);
++ }
++
++ return err;
+ }
+
+ static void __exit
+diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
+index 51f962d..e074bb6 100644
+--- a/drivers/mtd/maps/bast-flash.c
++++ b/drivers/mtd/maps/bast-flash.c
+@@ -1,4 +1,4 @@
+-/* linux/drivers/mtd/maps/bast_flash.c
++/* linux/drivers/mtd/maps/bast-flash.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
+index 5df7361..d76d598 100644
+--- a/drivers/mtd/maps/beech-mtd.c
++++ b/drivers/mtd/maps/beech-mtd.c
+@@ -72,6 +72,8 @@ static struct mtd_partition beech_partit
+ static int __init
+ init_beech_mtd(void)
+ {
++ int err;
++
+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
+
+ beech_mtd_map.virt = ioremap(PADDR, SIZE);
+@@ -86,12 +88,20 @@ init_beech_mtd(void)
+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
+ beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
+
+- if (!beech_mtd)
++ if (!beech_mtd) {
++ iounmap(beech_mtd_map.virt);
+ return -ENXIO;
++ }
+
+ beech_mtd->owner = THIS_MODULE;
+
+- return add_mtd_partitions(beech_mtd, beech_partitions, 2);
++ err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
++ if (err) {
++ printk("%s: add_mtd_partitions failed\n", NAME);
++ iounmap(beech_mtd_map.virt);
++ }
++
++ return err;
+ }
+
+ static void __exit
+diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c
+index aa56def..df2c38e 100644
+--- a/drivers/mtd/maps/cstm_mips_ixx.c
++++ b/drivers/mtd/maps/cstm_mips_ixx.c
+@@ -171,7 +171,14 @@ int __init init_cstm_mips_ixx(void)
+ cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
+ cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
+ if (!cstm_mips_ixx_map[i].virt) {
++ int j = 0;
+ printk(KERN_WARNING "Failed to ioremap\n");
++ for (j = 0; j < i; j++) {
++ if (cstm_mips_ixx_map[j].virt) {
++ iounmap(cstm_mips_ixx_map[j].virt);
++ cstm_mips_ixx_map[j].virt = NULL;
++ }
++ }
+ return -EIO;
+ }
+ cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
+@@ -204,8 +211,15 @@ int __init init_cstm_mips_ixx(void)
+ cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
+ add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
+ }
+- else
+- return -ENXIO;
++ else {
++ for (i = 0; i < PHYSMAP_NUMBER; i++) {
++ if (cstm_mips_ixx_map[i].virt) {
++ iounmap(cstm_mips_ixx_map[i].virt);
++ cstm_mips_ixx_map[i].virt = NULL;
++ }
++ }
++ return -ENXIO;
++ }
+ }
+ return 0;
+ }
+diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c
+index a43c499..e0558b0 100644
+--- a/drivers/mtd/maps/dmv182.c
++++ b/drivers/mtd/maps/dmv182.c
+@@ -1,6 +1,6 @@
+
+ /*
+- * drivers/mtd/maps/svme182.c
++ * drivers/mtd/maps/dmv182.c
+ *
+ * Flash map driver for the Dy4 SVME182 board
+ *
+diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
+index 641e1dd..1488bb9 100644
+--- a/drivers/mtd/maps/ebony.c
++++ b/drivers/mtd/maps/ebony.c
+@@ -108,6 +108,7 @@ int __init init_ebony(void)
+ ARRAY_SIZE(ebony_small_partitions));
+ } else {
+ printk("map probe failed for flash\n");
++ iounmap(ebony_small_map.virt);
+ return -ENXIO;
+ }
+
+@@ -117,6 +118,7 @@ int __init init_ebony(void)
+
+ if (!ebony_large_map.virt) {
+ printk("Failed to ioremap flash\n");
++ iounmap(ebony_small_map.virt);
+ return -EIO;
+ }
+
+@@ -129,6 +131,8 @@ int __init init_ebony(void)
+ ARRAY_SIZE(ebony_large_partitions));
+ } else {
+ printk("map probe failed for flash\n");
++ iounmap(ebony_small_map.virt);
++ iounmap(ebony_large_map.virt);
+ return -ENXIO;
+ }
+
+diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
+index c6bf4e1..7c50c27 100644
+--- a/drivers/mtd/maps/fortunet.c
++++ b/drivers/mtd/maps/fortunet.c
+@@ -218,8 +218,11 @@ int __init init_fortunet(void)
+ map_regions[ix].map_info.size);
+ if(!map_regions[ix].map_info.virt)
+ {
++ int j = 0;
+ printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
+ map_regions[ix].map_info.name);
++ for (j = 0 ; j < ix; j++)
++ iounmap(map_regions[j].map_info.virt);
+ return -ENXIO;
+ }
+ simple_map_init(&map_regions[ix].map_info);
+diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
+index db4b570..2bb3e63 100644
+--- a/drivers/mtd/maps/ichxrom.c
++++ b/drivers/mtd/maps/ichxrom.c
+@@ -61,6 +61,7 @@ static void ichxrom_cleanup(struct ichxr
+ /* Disable writes through the rom window */
+ pci_read_config_word(window->pdev, BIOS_CNTL, &word);
+ pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
++ pci_dev_put(window->pdev);
+
+ /* Free all of the mtd devices */
+ list_for_each_entry_safe(map, scratch, &window->maps, list) {
+@@ -355,7 +356,7 @@ static int __init init_ichxrom(void)
+
+ pdev = NULL;
+ for (id = ichxrom_pci_tbl; id->vendor; id++) {
+- pdev = pci_find_device(id->vendor, id->device, NULL);
++ pdev = pci_get_device(id->vendor, id->device, NULL);
+ if (pdev) {
+ break;
+ }
+diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c
+deleted file mode 100644
+index 62d9e87..0000000
+--- a/drivers/mtd/maps/iq80310.c
++++ /dev/null
+@@ -1,118 +0,0 @@
+-/*
+- * $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
+- *
+- * Mapping for the Intel XScale IQ80310 evaluation board
+- *
+- * 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/slab.h>
+-#include <asm/io.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/map.h>
+-#include <linux/mtd/partitions.h>
+-
+-
+-#define WINDOW_ADDR 0
+-#define WINDOW_SIZE 8*1024*1024
+-#define BUSWIDTH 1
+-
+-static struct mtd_info *mymtd;
+-
+-static struct map_info iq80310_map = {
+- .name = "IQ80310 flash",
+- .size = WINDOW_SIZE,
+- .bankwidth = BUSWIDTH,
+- .phys = WINDOW_ADDR
+-};
+-
+-static struct mtd_partition iq80310_partitions[4] = {
+- {
+- .name = "Firmware",
+- .size = 0x00080000,
+- .offset = 0,
+- .mask_flags = MTD_WRITEABLE /* force read-only */
+- },{
+- .name = "Kernel",
+- .size = 0x000a0000,
+- .offset = 0x00080000,
+- },{
+- .name = "Filesystem",
+- .size = 0x00600000,
+- .offset = 0x00120000
+- },{
+- .name = "RedBoot",
+- .size = 0x000e0000,
+- .offset = 0x00720000,
+- .mask_flags = MTD_WRITEABLE
+- }
+-};
+-
+-static struct mtd_info *mymtd;
+-static struct mtd_partition *parsed_parts;
+-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+-
+-static int __init init_iq80310(void)
+-{
+- struct mtd_partition *parts;
+- int nb_parts = 0;
+- int parsed_nr_parts = 0;
+- int ret;
+-
+- iq80310_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
+- if (!iq80310_map.virt) {
+- printk("Failed to ioremap\n");
+- return -EIO;
+- }
+- simple_map_init(&iq80310_map);
+-
+- mymtd = do_map_probe("cfi_probe", &iq80310_map);
+- if (!mymtd) {
+- iounmap((void *)iq80310_map.virt);
+- return -ENXIO;
+- }
+- mymtd->owner = THIS_MODULE;
+-
+- ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
+-
+- if (ret > 0)
+- parsed_nr_parts = ret;
+-
+- if (parsed_nr_parts > 0) {
+- parts = parsed_parts;
+- nb_parts = parsed_nr_parts;
+- } else {
+- parts = iq80310_partitions;
+- nb_parts = ARRAY_SIZE(iq80310_partitions);
+- }
+- add_mtd_partitions(mymtd, parts, nb_parts);
+- return 0;
+-}
+-
+-static void __exit cleanup_iq80310(void)
+-{
+- if (mymtd) {
+- del_mtd_partitions(mymtd);
+- map_destroy(mymtd);
+- kfree(parsed_parts);
+- }
+- if (iq80310_map.virt)
+- iounmap((void *)iq80310_map.virt);
+-}
+-
+-module_init(init_iq80310);
+-module_exit(cleanup_iq80310);
+-
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Nicolas Pitre <nico at cam.org>");
+-MODULE_DESCRIPTION("MTD map driver for Intel XScale IQ80310 evaluation board");
+diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c
+index 986c586..7a828e3 100644
+--- a/drivers/mtd/maps/ixp4xx.c
++++ b/drivers/mtd/maps/ixp4xx.c
+@@ -253,7 +253,7 @@ static int ixp4xx_flash_probe(struct pla
+ /* Use the fast version */
+ info->map.write = ixp4xx_write16,
+
+- err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
++ err = parse_mtd_partitions(info->mtd, probes, &info->partitions, dev->resource->start);
+ if (err > 0) {
+ err = add_mtd_partitions(info->mtd, info->partitions, err);
+ if(err)
+diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c
+index 6b784ef..67620ad 100644
+--- a/drivers/mtd/maps/l440gx.c
++++ b/drivers/mtd/maps/l440gx.c
+@@ -61,14 +61,17 @@ static int __init init_l440gx(void)
+ struct resource *pm_iobase;
+ __u16 word;
+
+- dev = pci_find_device(PCI_VENDOR_ID_INTEL,
++ dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
+
+- pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
++ pm_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+
++ pci_dev_put(dev);
++
+ if (!dev || !pm_dev) {
+ printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n");
++ pci_dev_put(pm_dev);
+ return -ENODEV;
+ }
+
+@@ -76,6 +79,7 @@ static int __init init_l440gx(void)
+
+ if (!l440gx_map.virt) {
+ printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
++ pci_dev_put(pm_dev);
+ return -ENOMEM;
+ }
+ simple_map_init(&l440gx_map);
+@@ -99,8 +103,12 @@ static int __init init_l440gx(void)
+ pm_iobase->start += iobase & ~1;
+ pm_iobase->end += iobase & ~1;
+
++ pci_dev_put(pm_dev);
++
+ /* Allocate the resource region */
+ if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
++ pci_dev_put(dev);
++ pci_dev_put(pm_dev);
+ printk(KERN_WARNING "Could not allocate pm iobase resource\n");
+ iounmap(l440gx_map.virt);
+ return -ENXIO;
+diff --git a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c
+index 1c13d2d..e343763 100644
+--- a/drivers/mtd/maps/lasat.c
++++ b/drivers/mtd/maps/lasat.c
+@@ -79,6 +79,7 @@ static int __init init_lasat(void)
+ return 0;
+ }
+
++ iounmap(lasat_map.virt);
+ return -ENXIO;
+ }
+
+@@ -89,6 +90,7 @@ static void __exit cleanup_lasat(void)
+ map_destroy(lasat_mtd);
+ }
+ if (lasat_map.virt) {
++ iounmap(lasat_map.virt);
+ lasat_map.virt = 0;
+ }
+ }
+diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
+index 0994b5b..f9e8e5b 100644
+--- a/drivers/mtd/maps/nettel.c
++++ b/drivers/mtd/maps/nettel.c
+@@ -277,6 +277,7 @@ int __init nettel_init(void)
+ nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
+ if (!nettel_amd_map.virt) {
+ printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
++ iounmap(nettel_mmcrp);
+ return(-EIO);
+ }
+ simple_map_init(&nettel_amd_map);
+@@ -337,7 +338,8 @@ int __init nettel_init(void)
+ nettel_amd_map.virt = NULL;
+ #else
+ /* Only AMD flash supported */
+- return(-ENXIO);
++ rc = -ENXIO;
++ goto out_unmap2;
+ #endif
+ }
+
+@@ -361,14 +363,15 @@ int __init nettel_init(void)
+ nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
+ if (!nettel_intel_map.virt) {
+ printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
+- return(-EIO);
++ rc = -EIO;
++ goto out_unmap2;
+ }
+ simple_map_init(&nettel_intel_map);
+
+ intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+ if (!intel_mtd) {
+- iounmap(nettel_intel_map.virt);
+- return(-ENXIO);
++ rc = -ENXIO;
++ goto out_unmap1;
+ }
+
+ /* Set PAR to the detected size */
+@@ -394,13 +397,14 @@ int __init nettel_init(void)
+ nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
+ if (!nettel_intel_map.virt) {
+ printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
+- return(-EIO);
++ rc = -EIO;
++ goto out_unmap2;
+ }
+
+ intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+ if (! intel_mtd) {
+- iounmap((void *) nettel_intel_map.virt);
+- return(-ENXIO);
++ rc = -ENXIO;
++ goto out_unmap1;
+ }
+
+ intel1size = intel_mtd->size - intel0size;
+@@ -456,6 +460,18 @@ int __init nettel_init(void)
+ #endif
+
+ return(rc);
++
++#ifdef CONFIG_MTD_CFI_INTELEXT
++out_unmap1:
++ iounmap(nettel_intel_map.virt);
++#endif
++
++out_unmap2:
++ iounmap(nettel_mmcrp);
++ iounmap(nettel_amd_map.virt);
++
++ return(rc);
++
+ }
+
+ /****************************************************************************/
+@@ -469,6 +485,10 @@ void __exit nettel_cleanup(void)
+ del_mtd_partitions(amd_mtd);
+ map_destroy(amd_mtd);
+ }
++ if (nettel_mmcrp) {
++ iounmap(nettel_mmcrp);
++ nettel_mmcrp = NULL;
++ }
+ if (nettel_amd_map.virt) {
+ iounmap(nettel_amd_map.virt);
+ nettel_amd_map.virt = NULL;
+diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
+index 2f07602..5522eac 100644
+--- a/drivers/mtd/maps/ocotea.c
++++ b/drivers/mtd/maps/ocotea.c
+@@ -97,6 +97,7 @@ int __init init_ocotea(void)
+ ARRAY_SIZE(ocotea_small_partitions));
+ } else {
+ printk("map probe failed for flash\n");
++ iounmap(ocotea_small_map.virt);
+ return -ENXIO;
+ }
+
+@@ -106,6 +107,7 @@ int __init init_ocotea(void)
+
+ if (!ocotea_large_map.virt) {
+ printk("Failed to ioremap flash\n");
++ iounmap(ocotea_small_map.virt);
+ return -EIO;
+ }
+
+@@ -118,6 +120,8 @@ int __init init_ocotea(void)
+ ARRAY_SIZE(ocotea_large_partitions));
+ } else {
+ printk("map probe failed for flash\n");
++ iounmap(ocotea_small_map.virt);
++ iounmap(ocotea_large_map.virt);
+ return -ENXIO;
+ }
+
+diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
+index c861134..995347b 100644
+--- a/drivers/mtd/maps/pcmciamtd.c
++++ b/drivers/mtd/maps/pcmciamtd.c
+@@ -602,6 +602,10 @@ static int pcmciamtd_config(struct pcmci
+ ret = pcmcia_request_configuration(link, &link->conf);
+ if(ret != CS_SUCCESS) {
+ cs_error(link, RequestConfiguration, ret);
++ if (dev->win_base) {
++ iounmap(dev->win_base);
++ dev->win_base = NULL;
++ }
+ return -ENODEV;
+ }
+
+diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
+index 7799a25..d171776 100644
+--- a/drivers/mtd/maps/physmap.c
++++ b/drivers/mtd/maps/physmap.c
+@@ -62,7 +62,7 @@ static int physmap_flash_remove(struct p
+ }
+
+ if (info->map.virt != NULL)
+- iounmap((void *)info->map.virt);
++ iounmap(info->map.virt);
+
+ if (info->res != NULL) {
+ release_resource(info->res);
+@@ -158,9 +158,42 @@ err_out:
+ return err;
+ }
+
++#ifdef CONFIG_PM
++static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state)
++{
++ struct physmap_flash_info *info = platform_get_drvdata(dev);
++ int ret = 0;
++
++ if (info)
++ ret = info->mtd->suspend(info->mtd);
++
++ return ret;
++}
++
++static int physmap_flash_resume(struct platform_device *dev)
++{
++ struct physmap_flash_info *info = platform_get_drvdata(dev);
++ if (info)
++ info->mtd->resume(info->mtd);
++ return 0;
++}
++
++static void physmap_flash_shutdown(struct platform_device *dev)
++{
++ struct physmap_flash_info *info = platform_get_drvdata(dev);
++ if (info && info->mtd->suspend(info->mtd) == 0)
++ info->mtd->resume(info->mtd);
++}
++#endif
++
+ static struct platform_driver physmap_flash_driver = {
+ .probe = physmap_flash_probe,
+ .remove = physmap_flash_remove,
++#ifdef CONFIG_PM
++ .suspend = physmap_flash_suspend,
++ .resume = physmap_flash_resume,
++ .shutdown = physmap_flash_shutdown,
++#endif
+ .driver = {
+ .name = "physmap-flash",
+ },
+diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
+index ec8fdae..4d858b3 100644
+--- a/drivers/mtd/maps/redwood.c
++++ b/drivers/mtd/maps/redwood.c
+@@ -126,6 +126,8 @@ static struct mtd_info *redwood_mtd;
+
+ int __init init_redwood_flash(void)
+ {
++ int err;
++
+ printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
+ WINDOW_SIZE, WINDOW_ADDR);
+
+@@ -141,11 +143,18 @@ int __init init_redwood_flash(void)
+
+ if (redwood_mtd) {
+ redwood_mtd->owner = THIS_MODULE;
+- return add_mtd_partitions(redwood_mtd,
++ err = add_mtd_partitions(redwood_mtd,
+ redwood_flash_partitions,
+ NUM_REDWOOD_FLASH_PARTITIONS);
++ if (err) {
++ printk("init_redwood_flash: add_mtd_partitions failed\n");
++ iounmap(redwood_flash_map.virt);
++ }
++ return err;
++
+ }
+
++ iounmap(redwood_flash_map.virt);
+ return -ENXIO;
+ }
+
+diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
+index 7d0fcf8..b8c1331 100644
+--- a/drivers/mtd/maps/sbc8240.c
++++ b/drivers/mtd/maps/sbc8240.c
+@@ -156,7 +156,7 @@ int __init init_sbc8240_mtd (void)
+ };
+
+ int devicesfound = 0;
+- int i;
++ int i,j;
+
+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
+ printk (KERN_NOTICE MSG_PREFIX
+@@ -166,6 +166,10 @@ int __init init_sbc8240_mtd (void)
+ (unsigned long) ioremap (pt[i].addr, pt[i].size);
+ if (!sbc8240_map[i].map_priv_1) {
+ printk (MSG_PREFIX "failed to ioremap\n");
++ for (j = 0; j < i; j++) {
++ iounmap((void *) sbc8240_map[j].map_priv_1);
++ sbc8240_map[j].map_priv_1 = 0;
++ }
+ return -EIO;
+ }
+ simple_map_init(&sbc8240_mtd[i]);
+@@ -175,6 +179,11 @@ int __init init_sbc8240_mtd (void)
+ if (sbc8240_mtd[i]) {
+ sbc8240_mtd[i]->module = THIS_MODULE;
+ devicesfound++;
++ } else {
++ if (sbc8240_map[i].map_priv_1) {
++ iounmap((void *) sbc8240_map[i].map_priv_1);
++ sbc8240_map[i].map_priv_1 = 0;
++ }
+ }
+ }
+
+diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
+index 7391fd5..5e2bce2 100644
+--- a/drivers/mtd/maps/scx200_docflash.c
++++ b/drivers/mtd/maps/scx200_docflash.c
+@@ -87,19 +87,23 @@ static int __init init_scx200_docflash(v
+
+ printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
+
+- if ((bridge = pci_find_device(PCI_VENDOR_ID_NS,
++ if ((bridge = pci_get_device(PCI_VENDOR_ID_NS,
+ PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+ NULL)) == NULL)
+ return -ENODEV;
+
+ /* check that we have found the configuration block */
+- if (!scx200_cb_present())
++ if (!scx200_cb_present()) {
++ pci_dev_put(bridge);
+ return -ENODEV;
++ }
+
+ if (probe) {
+ /* Try to use the present flash mapping if any */
+ pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
+ pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
++ pci_dev_put(bridge);
++
+ pmr = inl(scx200_cb_base + SCx200_PMR);
+
+ if (base == 0
+@@ -127,6 +131,7 @@ static int __init init_scx200_docflash(v
+ return -ENOMEM;
+ }
+ } else {
++ pci_dev_put(bridge);
+ for (u = size; u > 1; u >>= 1)
+ ;
+ if (u != 1) {
+diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c
+index ec80eec..ca93212 100644
+--- a/drivers/mtd/maps/walnut.c
++++ b/drivers/mtd/maps/walnut.c
+@@ -68,6 +68,7 @@ int __init init_walnut(void)
+
+ if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
+ printk("The on-board flash is disabled (U79 sw 5)!");
++ iounmap(fpga_status_adr);
+ return -EIO;
+ }
+ if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
+@@ -81,6 +82,7 @@ int __init init_walnut(void)
+
+ if (!walnut_map.virt) {
+ printk("Failed to ioremap flash.\n");
++ iounmap(fpga_status_adr);
+ return -EIO;
+ }
+
+@@ -93,9 +95,11 @@ int __init init_walnut(void)
+ ARRAY_SIZE(walnut_partitions));
+ } else {
+ printk("map probe failed for flash\n");
++ iounmap(fpga_status_adr);
+ return -ENXIO;
+ }
+
++ iounmap(fpga_status_adr);
+ return 0;
+ }
+
+diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
+index 458d3c8..178b53b 100644
+--- a/drivers/mtd/mtd_blkdevs.c
++++ b/drivers/mtd/mtd_blkdevs.c
+@@ -46,7 +46,7 @@ static int do_blktrans_request(struct mt
+ nsect = req->current_nr_sectors;
+ buf = req->buffer;
+
+- if (!(req->flags & REQ_CMD))
++ if (!blk_fs_request(req))
+ return 0;
+
+ if (block + nsect > get_capacity(req->rq_disk))
+@@ -69,7 +69,7 @@ static int do_blktrans_request(struct mt
+ return 1;
+
+ default:
+- printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req));
++ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));
+ return 0;
+ }
+ }
+diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
+index 168d3ba..c4d26de 100644
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -57,6 +57,16 @@ int add_mtd_device(struct mtd_info *mtd)
+ mtd->index = i;
+ mtd->usecount = 0;
+
++ /* Some chips always power up locked. Unlock them now */
++ if ((mtd->flags & MTD_WRITEABLE)
++ && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
++ if (mtd->unlock(mtd, 0, mtd->size))
++ printk(KERN_WARNING
++ "%s: unlock failed, "
++ "writes may not work\n",
++ mtd->name);
++ }
++
+ DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
+ /* No need to get a refcount on the module containing
+ the notifier, since we hold the mtd_table_mutex */
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index c99302e..1831340 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -21,7 +21,7 @@ config MTD_NAND_VERIFY_WRITE
+ NAND flash device internally checks only bits transitioning
+ from 1 to 0. There is a rare possibility that even though the
+ device thinks the write was successful, a bit could have been
+- flipped accidentaly due to device wear or something else.
++ flipped accidentally due to device wear or something else.
+
+ config MTD_NAND_ECC_SMC
+ bool "NAND ECC Smart Media byte order"
+diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
+index 3122833..09e421a 100644
+--- a/drivers/mtd/nand/au1550nd.c
++++ b/drivers/mtd/nand/au1550nd.c
+@@ -21,18 +21,7 @@
+ #include <linux/version.h>
+ #include <asm/io.h>
+
+-/* fixme: this is ugly */
+-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
+ #include <asm/mach-au1x00/au1xxx.h>
+-#else
+-#include <asm/au1000.h>
+-#ifdef CONFIG_MIPS_PB1550
+-#include <asm/pb1550.h>
+-#endif
+-#ifdef CONFIG_MIPS_DB1550
+-#include <asm/db1x00.h>
+-#endif
+-#endif
+
+ /*
+ * MTD structure for NAND controller
+diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
+index e0a1d38..94924d5 100644
+--- a/drivers/mtd/nand/cs553x_nand.c
++++ b/drivers/mtd/nand/cs553x_nand.c
+@@ -249,7 +249,7 @@ static int __init cs553x_init_one(int cs
+ goto out;
+
+ out_ior:
+- iounmap((void *)this->IO_ADDR_R);
++ iounmap(this->IO_ADDR_R);
+ out_mtd:
+ kfree(new_mtd);
+ out:
+diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
+index 516c0e5..1daf823 100644
+--- a/drivers/mtd/nand/edb7312.c
++++ b/drivers/mtd/nand/edb7312.c
+@@ -198,6 +198,9 @@ static void __exit ep7312_cleanup(void)
+ /* Release resources, unregister device */
+ nand_release(ap7312_mtd);
+
++ /* Release io resource */
++ iounmap(this->IO_ADDR_R);
++
+ /* Free the MTD device structure */
+ kfree(ep7312_mtd);
+ }
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 975b2ef..41bfcae 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -415,7 +415,7 @@ static int nand_block_checkbad(struct mt
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+-static void nand_wait_ready(struct mtd_info *mtd)
++void nand_wait_ready(struct mtd_info *mtd)
+ {
+ struct nand_chip *chip = mtd->priv;
+ unsigned long timeo = jiffies + 2;
+@@ -429,6 +429,7 @@ static void nand_wait_ready(struct mtd_i
+ } while (time_before(jiffies, timeo));
+ led_trigger_event(nand_led_trigger, LED_OFF);
+ }
++EXPORT_SYMBOL_GPL(nand_wait_ready);
+
+ /**
+ * nand_command - [DEFAULT] Send command to NAND device
+@@ -766,8 +767,8 @@ static int nand_read_page_swecc(struct m
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+- uint8_t *ecc_calc = chip->buffers.ecccalc;
+- uint8_t *ecc_code = chip->buffers.ecccode;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ uint8_t *ecc_code = chip->buffers->ecccode;
+ int *eccpos = chip->ecc.layout->eccpos;
+
+ nand_read_page_raw(mtd, chip, buf);
+@@ -808,8 +809,8 @@ static int nand_read_page_hwecc(struct m
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+- uint8_t *ecc_calc = chip->buffers.ecccalc;
+- uint8_t *ecc_code = chip->buffers.ecccode;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ uint8_t *ecc_code = chip->buffers->ecccode;
+ int *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+@@ -970,7 +971,7 @@ static int nand_do_read_ops(struct mtd_i
+ page = realpage & chip->pagemask;
+
+ col = (int)(from & (mtd->writesize - 1));
+- chip->oob_poi = chip->buffers.oobrbuf;
++ chip->oob_poi = chip->buffers->oobrbuf;
+
+ buf = ops->datbuf;
+ oob = ops->oobbuf;
+@@ -981,7 +982,7 @@ static int nand_do_read_ops(struct mtd_i
+
+ /* Is the current page in the buffer ? */
+ if (realpage != chip->pagebuf || oob) {
+- bufpoi = aligned ? buf : chip->buffers.databuf;
++ bufpoi = aligned ? buf : chip->buffers->databuf;
+
+ if (likely(sndcmd)) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+@@ -989,14 +990,17 @@ static int nand_do_read_ops(struct mtd_i
+ }
+
+ /* Now read the page into the buffer */
+- ret = chip->ecc.read_page(mtd, chip, bufpoi);
++ if (unlikely(ops->mode == MTD_OOB_RAW))
++ ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
++ else
++ ret = chip->ecc.read_page(mtd, chip, bufpoi);
+ if (ret < 0)
+ break;
+
+ /* Transfer not aligned data */
+ if (!aligned) {
+ chip->pagebuf = realpage;
+- memcpy(buf, chip->buffers.databuf + col, bytes);
++ memcpy(buf, chip->buffers->databuf + col, bytes);
+ }
+
+ buf += bytes;
+@@ -1023,7 +1027,7 @@ static int nand_do_read_ops(struct mtd_i
+ nand_wait_ready(mtd);
+ }
+ } else {
+- memcpy(buf, chip->buffers.databuf + col, bytes);
++ memcpy(buf, chip->buffers->databuf + col, bytes);
+ buf += bytes;
+ }
+
+@@ -1266,7 +1270,7 @@ static int nand_do_read_oob(struct mtd_i
+ realpage = (int)(from >> chip->page_shift);
+ page = realpage & chip->pagemask;
+
+- chip->oob_poi = chip->buffers.oobrbuf;
++ chip->oob_poi = chip->buffers->oobrbuf;
+
+ while(1) {
+ sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
+@@ -1322,8 +1326,6 @@ static int nand_do_read_oob(struct mtd_i
+ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+ {
+- int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
+- uint8_t *buf) = NULL;
+ struct nand_chip *chip = mtd->priv;
+ int ret = -ENOTSUPP;
+
+@@ -1341,12 +1343,7 @@ static int nand_read_oob(struct mtd_info
+ switch(ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+- break;
+-
+ case MTD_OOB_RAW:
+- /* Replace the read_page algorithm temporary */
+- read_page = chip->ecc.read_page;
+- chip->ecc.read_page = nand_read_page_raw;
+ break;
+
+ default:
+@@ -1358,8 +1355,6 @@ static int nand_read_oob(struct mtd_info
+ else
+ ret = nand_do_read_ops(mtd, from, ops);
+
+- if (unlikely(ops->mode == MTD_OOB_RAW))
+- chip->ecc.read_page = read_page;
+ out:
+ nand_release_device(mtd);
+ return ret;
+@@ -1391,7 +1386,7 @@ static void nand_write_page_swecc(struct
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+- uint8_t *ecc_calc = chip->buffers.ecccalc;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+ int *eccpos = chip->ecc.layout->eccpos;
+
+@@ -1417,7 +1412,7 @@ static void nand_write_page_hwecc(struct
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+- uint8_t *ecc_calc = chip->buffers.ecccalc;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+ int *eccpos = chip->ecc.layout->eccpos;
+
+@@ -1478,21 +1473,25 @@ static void nand_write_page_syndrome(str
+ }
+
+ /**
+- * nand_write_page - [INTERNAL] write one page
++ * nand_write_page - [REPLACEABLE] write one page
+ * @mtd: MTD device structure
+ * @chip: NAND chip descriptor
+ * @buf: the data to write
+ * @page: page number to write
+ * @cached: cached programming
++ * @raw: use _raw version of write_page
+ */
+ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+- const uint8_t *buf, int page, int cached)
++ const uint8_t *buf, int page, int cached, int raw)
+ {
+ int status;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+- chip->ecc.write_page(mtd, chip, buf);
++ if (unlikely(raw))
++ chip->ecc.write_page_raw(mtd, chip, buf);
++ else
++ chip->ecc.write_page(mtd, chip, buf);
+
+ /*
+ * Cached progamming disabled for now, Not sure if its worth the
+@@ -1627,7 +1626,7 @@ static int nand_do_write_ops(struct mtd_
+ (chip->pagebuf << chip->page_shift) < (to + ops->len))
+ chip->pagebuf = -1;
+
+- chip->oob_poi = chip->buffers.oobwbuf;
++ chip->oob_poi = chip->buffers->oobwbuf;
+
+ while(1) {
+ int cached = writelen > bytes && page != blockmask;
+@@ -1635,7 +1634,8 @@ static int nand_do_write_ops(struct mtd_
+ if (unlikely(oob))
+ oob = nand_fill_oob(chip, oob, ops);
+
+- ret = nand_write_page(mtd, chip, buf, page, cached);
++ ret = chip->write_page(mtd, chip, buf, page, cached,
++ (ops->mode == MTD_OOB_RAW));
+ if (ret)
+ break;
+
+@@ -1745,7 +1745,7 @@ static int nand_do_write_oob(struct mtd_
+ if (page == chip->pagebuf)
+ chip->pagebuf = -1;
+
+- chip->oob_poi = chip->buffers.oobwbuf;
++ chip->oob_poi = chip->buffers->oobwbuf;
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+ nand_fill_oob(chip, ops->oobbuf, ops);
+ status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+@@ -1768,8 +1768,6 @@ static int nand_do_write_oob(struct mtd_
+ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+ {
+- void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+- const uint8_t *buf) = NULL;
+ struct nand_chip *chip = mtd->priv;
+ int ret = -ENOTSUPP;
+
+@@ -1787,12 +1785,7 @@ static int nand_write_oob(struct mtd_inf
+ switch(ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+- break;
+-
+ case MTD_OOB_RAW:
+- /* Replace the write_page algorithm temporary */
+- write_page = chip->ecc.write_page;
+- chip->ecc.write_page = nand_write_page_raw;
+ break;
+
+ default:
+@@ -1804,8 +1797,6 @@ static int nand_write_oob(struct mtd_inf
+ else
+ ret = nand_do_write_ops(mtd, to, ops);
+
+- if (unlikely(ops->mode == MTD_OOB_RAW))
+- chip->ecc.write_page = write_page;
+ out:
+ nand_release_device(mtd);
+ return ret;
+@@ -2288,40 +2279,22 @@ static struct nand_flash_dev *nand_get_f
+ return type;
+ }
+
+-/* module_text_address() isn't exported, and it's mostly a pointless
+- test if this is a module _anyway_ -- they'd have to try _really_ hard
+- to call us from in-kernel code if the core NAND support is modular. */
+-#ifdef MODULE
+-#define caller_is_module() (1)
+-#else
+-#define caller_is_module() \
+- module_text_address((unsigned long)__builtin_return_address(0))
+-#endif
+-
+ /**
+- * nand_scan - [NAND Interface] Scan for the NAND device
+- * @mtd: MTD device structure
+- * @maxchips: Number of chips to scan for
++ * nand_scan_ident - [NAND Interface] Scan for the NAND device
++ * @mtd: MTD device structure
++ * @maxchips: Number of chips to scan for
+ *
+- * This fills out all the uninitialized function pointers
+- * with the defaults.
+- * The flash ID is read and the mtd/chip structures are
+- * filled with the appropriate values.
+- * The mtd->owner field must be set to the module of the caller
++ * This is the first phase of the normal nand_scan() function. It
++ * reads the flash ID and sets up MTD fields accordingly.
+ *
++ * The mtd->owner field must be set to the module of the caller.
+ */
+-int nand_scan(struct mtd_info *mtd, int maxchips)
++int nand_scan_ident(struct mtd_info *mtd, int maxchips)
+ {
+ int i, busw, nand_maf_id;
+ struct nand_chip *chip = mtd->priv;
+ struct nand_flash_dev *type;
+
+- /* Many callers got this wrong, so check for it for a while... */
+- if (!mtd->owner && caller_is_module()) {
+- printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
+- BUG();
+- }
+-
+ /* Get buswidth to select the correct functions */
+ busw = chip->options & NAND_BUSWIDTH_16;
+ /* Set the default functions */
+@@ -2353,8 +2326,31 @@ int nand_scan(struct mtd_info *mtd, int
+ chip->numchips = i;
+ mtd->size = i * chip->chipsize;
+
++ return 0;
++}
++
++
++/**
++ * nand_scan_tail - [NAND Interface] Scan for the NAND device
++ * @mtd: MTD device structure
++ * @maxchips: Number of chips to scan for
++ *
++ * This is the second phase of the normal nand_scan() function. It
++ * fills out all the uninitialized function pointers with the defaults
++ * and scans for a bad block table if appropriate.
++ */
++int nand_scan_tail(struct mtd_info *mtd)
++{
++ int i;
++ struct nand_chip *chip = mtd->priv;
++
++ if (!(chip->options & NAND_OWN_BUFFERS))
++ chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
++ if (!chip->buffers)
++ return -ENOMEM;
++
+ /* Preset the internal oob write buffer */
+- memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize);
++ memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize);
+
+ /*
+ * If no default placement scheme is given, select an appropriate one
+@@ -2377,10 +2373,18 @@ int nand_scan(struct mtd_info *mtd, int
+ }
+ }
+
++ if (!chip->write_page)
++ chip->write_page = nand_write_page;
++
+ /*
+ * check ECC mode, default to software if 3byte/512byte hardware ECC is
+ * selected and we have 256 byte pagesize fallback to software ECC
+ */
++ if (!chip->ecc.read_page_raw)
++ chip->ecc.read_page_raw = nand_read_page_raw;
++ if (!chip->ecc.write_page_raw)
++ chip->ecc.write_page_raw = nand_write_page_raw;
++
+ switch (chip->ecc.mode) {
+ case NAND_ECC_HW:
+ /* Use standard hwecc read page function ? */
+@@ -2438,6 +2442,7 @@ int nand_scan(struct mtd_info *mtd, int
+ chip->ecc.size = mtd->writesize;
+ chip->ecc.bytes = 0;
+ break;
++
+ default:
+ printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
+ chip->ecc.mode);
+@@ -2503,6 +2508,44 @@ int nand_scan(struct mtd_info *mtd, int
+ return chip->scan_bbt(mtd);
+ }
+
++/* module_text_address() isn't exported, and it's mostly a pointless
++ test if this is a module _anyway_ -- they'd have to try _really_ hard
++ to call us from in-kernel code if the core NAND support is modular. */
++#ifdef MODULE
++#define caller_is_module() (1)
++#else
++#define caller_is_module() \
++ module_text_address((unsigned long)__builtin_return_address(0))
++#endif
++
++/**
++ * nand_scan - [NAND Interface] Scan for the NAND device
++ * @mtd: MTD device structure
++ * @maxchips: Number of chips to scan for
++ *
++ * This fills out all the uninitialized function pointers
++ * with the defaults.
++ * The flash ID is read and the mtd/chip structures are
++ * filled with the appropriate values.
++ * The mtd->owner field must be set to the module of the caller
++ *
++ */
++int nand_scan(struct mtd_info *mtd, int maxchips)
++{
++ int ret;
++
++ /* Many callers got this wrong, so check for it for a while... */
++ if (!mtd->owner && caller_is_module()) {
++ printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
++ BUG();
++ }
++
++ ret = nand_scan_ident(mtd, maxchips);
++ if (!ret)
++ ret = nand_scan_tail(mtd);
++ return ret;
++}
++
+ /**
+ * nand_release - [NAND Interface] Free resources held by the NAND device
+ * @mtd: MTD device structure
+@@ -2520,9 +2563,13 @@ void nand_release(struct mtd_info *mtd)
+
+ /* Free bad block table memory */
+ kfree(chip->bbt);
++ if (!(chip->options & NAND_OWN_BUFFERS))
++ kfree(chip->buffers);
+ }
+
+ EXPORT_SYMBOL_GPL(nand_scan);
++EXPORT_SYMBOL_GPL(nand_scan_ident);
++EXPORT_SYMBOL_GPL(nand_scan_tail);
+ EXPORT_SYMBOL_GPL(nand_release);
+
+ static int __init nand_base_init(void)
+diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
+index a612c4e..9402653 100644
+--- a/drivers/mtd/nand/nand_bbt.c
++++ b/drivers/mtd/nand/nand_bbt.c
+@@ -759,7 +759,7 @@ static inline int nand_memory_bbt(struct
+ struct nand_chip *this = mtd->priv;
+
+ bd->options &= ~NAND_BBT_SCANEMPTY;
+- return create_bbt(mtd, this->buffers.databuf, bd, -1);
++ return create_bbt(mtd, this->buffers->databuf, bd, -1);
+ }
+
+ /**
+diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
+index e5bd88f..039c759 100644
+--- a/drivers/mtd/nand/ndfc.c
++++ b/drivers/mtd/nand/ndfc.c
+@@ -168,7 +168,7 @@ static void ndfc_chip_init(struct ndfc_n
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+- chip->ecclayout = mtd->pl_chip->ecclayout;
++ chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
+ mtd->mtd.priv = chip;
+ mtd->mtd.owner = THIS_MODULE;
+ }
+diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c
+index 22fa65c..eb7d4d4 100644
+--- a/drivers/mtd/nand/ppchameleonevb.c
++++ b/drivers/mtd/nand/ppchameleonevb.c
+@@ -276,6 +276,7 @@ static int __init ppchameleonevb_init(vo
+ /* Scan to find existence of the device (it could not be mounted) */
+ if (nand_scan(ppchameleon_mtd, 1)) {
+ iounmap((void *)ppchameleon_fio_base);
++ ppchameleon_fio_base = NULL;
+ kfree(ppchameleon_mtd);
+ goto nand_evb_init;
+ }
+@@ -314,6 +315,8 @@ static int __init ppchameleonevb_init(vo
+ ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+ if (!ppchameleonevb_mtd) {
+ printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
++ if (ppchameleon_fio_base)
++ iounmap(ppchameleon_fio_base);
+ return -ENOMEM;
+ }
+
+@@ -322,6 +325,8 @@ static int __init ppchameleonevb_init(vo
+ if (!ppchameleonevb_fio_base) {
+ printk("ioremap PPChameleonEVB NAND flash failed\n");
+ kfree(ppchameleonevb_mtd);
++ if (ppchameleon_fio_base)
++ iounmap(ppchameleon_fio_base);
+ return -EIO;
+ }
+
+@@ -378,6 +383,8 @@ static int __init ppchameleonevb_init(vo
+ if (nand_scan(ppchameleonevb_mtd, 1)) {
+ iounmap((void *)ppchameleonevb_fio_base);
+ kfree(ppchameleonevb_mtd);
++ if (ppchameleon_fio_base)
++ iounmap(ppchameleon_fio_base);
+ return -ENXIO;
+ }
+ #ifdef CONFIG_MTD_PARTITIONS
+diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
+index dd5cea8..b5a5f8d 100644
+--- a/drivers/mtd/nftlcore.c
++++ b/drivers/mtd/nftlcore.c
+@@ -175,6 +175,8 @@ int nftl_write_oob(struct mtd_info *mtd,
+ return res;
+ }
+
++#ifdef CONFIG_NFTL_RW
++
+ /*
+ * Write data and oob to flash
+ */
+@@ -196,8 +198,6 @@ static int nftl_write(struct mtd_info *m
+ return res;
+ }
+
+-#ifdef CONFIG_NFTL_RW
+-
+ /* Actual NFTL access routines */
+ /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
+ * when the give Virtual Unit Chain
+diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
+index 5930a03..373bddc 100644
+--- a/drivers/mtd/onenand/Kconfig
++++ b/drivers/mtd/onenand/Kconfig
+@@ -21,7 +21,7 @@ config MTD_ONENAND_VERIFY_WRITE
+ OneNAND flash device internally checks only bits transitioning
+ from 1 to 0. There is a rare possibility that even though the
+ device thinks the write was successful, a bit could have been
+- flipped accidentaly due to device wear or something else.
++ flipped accidentally due to device wear or something else.
+
+ config MTD_ONENAND_GENERIC
+ tristate "OneNAND Flash device via platform device driver"
+@@ -43,10 +43,4 @@ config MTD_ONENAND_OTP
+
+ OTP block is fully-guaranteed to be a valid block.
+
+-config MTD_ONENAND_SYNC_READ
+- bool "OneNAND Sync. Burst Read Support"
+- depends on ARCH_OMAP
+- help
+- This enables support for Sync. Burst Read.
+-
+ endmenu
+diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
+index 84ec40d..8ed68b2 100644
+--- a/drivers/mtd/onenand/onenand_base.c
++++ b/drivers/mtd/onenand/onenand_base.c
+@@ -1,7 +1,7 @@
+ /*
+ * linux/drivers/mtd/onenand/onenand_base.c
+ *
+- * Copyright (C) 2005 Samsung Electronics
++ * Copyright (C) 2005-2006 Samsung Electronics
+ * Kyungmin Park <kyungmin.park at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+@@ -199,6 +199,7 @@ static int onenand_command(struct mtd_in
+ case ONENAND_CMD_UNLOCK:
+ case ONENAND_CMD_LOCK:
+ case ONENAND_CMD_LOCK_TIGHT:
++ case ONENAND_CMD_UNLOCK_ALL:
+ block = -1;
+ page = -1;
+ break;
+@@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_inf
+ end = len >> this->erase_shift;
+
+ /* Continuous lock scheme */
+- if (this->options & ONENAND_CONT_LOCK) {
++ if (this->options & ONENAND_HAS_CONT_LOCK) {
+ /* Set start block address */
+ this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
+ /* Set end block address */
+- this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
++ this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
+ /* Write unlock command */
+ this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
+
+@@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_inf
+ }
+
+ /* Block lock scheme */
+- for (block = start; block < end; block++) {
++ for (block = start; block < start + end; block++) {
+ /* Set block address */
+ value = onenand_block_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
+@@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_inf
+ return 0;
+ }
+
++/**
++ * onenand_check_lock_status - [OneNAND Interface] Check lock status
++ * @param this onenand chip data structure
++ *
++ * Check lock status
++ */
++static void onenand_check_lock_status(struct onenand_chip *this)
++{
++ unsigned int value, block, status;
++ unsigned int end;
++
++ end = this->chipsize >> this->erase_shift;
++ for (block = 0; block < end; block++) {
++ /* Set block address */
++ value = onenand_block_address(this, block);
++ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
++ /* Select DataRAM for DDP */
++ value = onenand_bufferram_address(this, block);
++ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
++ /* Set start block address */
++ this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
++
++ /* Check lock status */
++ status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
++ if (!(status & ONENAND_WP_US))
++ printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
++ }
++}
++
++/**
++ * onenand_unlock_all - [OneNAND Interface] unlock all blocks
++ * @param mtd MTD device structure
++ *
++ * Unlock all blocks
++ */
++static int onenand_unlock_all(struct mtd_info *mtd)
++{
++ struct onenand_chip *this = mtd->priv;
++
++ if (this->options & ONENAND_HAS_UNLOCK_ALL) {
++ /* Write unlock command */
++ this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
++
++ /* There's no return value */
++ this->wait(mtd, FL_UNLOCKING);
++
++ /* Sanity check */
++ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
++ & ONENAND_CTRL_ONGO)
++ continue;
++
++ /* Workaround for all block unlock in DDP */
++ if (this->device_id & ONENAND_DEVICE_IS_DDP) {
++ loff_t ofs;
++ size_t len;
++
++ /* 1st block on another chip */
++ ofs = this->chipsize >> 1;
++ len = 1 << this->erase_shift;
++
++ onenand_unlock(mtd, ofs, len);
++ }
++
++ onenand_check_lock_status(this);
++
++ return 0;
++ }
++
++ mtd->unlock(mtd, 0x0, this->chipsize);
++
++ return 0;
++}
++
+ #ifdef CONFIG_MTD_ONENAND_OTP
+
+ /* Interal OTP operation */
+@@ -1564,12 +1638,43 @@ static int onenand_lock_user_prot_reg(st
+ #endif /* CONFIG_MTD_ONENAND_OTP */
+
+ /**
++ * onenand_lock_scheme - Check and set OneNAND lock scheme
++ * @param mtd MTD data structure
++ *
++ * Check and set OneNAND lock scheme
++ */
++static void onenand_lock_scheme(struct mtd_info *mtd)
++{
++ struct onenand_chip *this = mtd->priv;
++ unsigned int density, process;
++
++ /* Lock scheme depends on density and process */
++ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
++ process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
++
++ /* Lock scheme */
++ if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
++ /* A-Die has all block unlock */
++ if (process) {
++ printk(KERN_DEBUG "Chip support all block unlock\n");
++ this->options |= ONENAND_HAS_UNLOCK_ALL;
++ }
++ } else {
++ /* Some OneNAND has continues lock scheme */
++ if (!process) {
++ printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
++ this->options |= ONENAND_HAS_CONT_LOCK;
++ }
++ }
++}
++
++/**
+ * onenand_print_device_info - Print device ID
+ * @param device device ID
+ *
+ * Print device ID
+ */
+-static void onenand_print_device_info(int device)
++static void onenand_print_device_info(int device, int version)
+ {
+ int vcc, demuxed, ddp, density;
+
+@@ -1583,6 +1688,7 @@ static void onenand_print_device_info(in
+ (16 << density),
+ vcc ? "2.65/3.3" : "1.8",
+ device);
++ printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
+ }
+
+ static const struct onenand_manufacturers onenand_manuf_ids[] = {
+@@ -1625,9 +1731,14 @@ static int onenand_check_maf(int manuf)
+ static int onenand_probe(struct mtd_info *mtd)
+ {
+ struct onenand_chip *this = mtd->priv;
+- int bram_maf_id, bram_dev_id, maf_id, dev_id;
+- int version_id;
++ int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
+ int density;
++ int syscfg;
++
++ /* Save system configuration 1 */
++ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
++ /* Clear Sync. Burst Read mode to read BootRAM */
++ this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1);
+
+ /* Send the command for reading device ID from BootRAM */
+ this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
+@@ -1636,24 +1747,31 @@ static int onenand_probe(struct mtd_info
+ bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
+ bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
+
++ /* Reset OneNAND to read default register values */
++ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
++ /* Wait reset */
++ this->wait(mtd, FL_RESETING);
++
++ /* Restore system configuration 1 */
++ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
++
+ /* Check manufacturer ID */
+ if (onenand_check_maf(bram_maf_id))
+ return -ENXIO;
+
+- /* Reset OneNAND to read default register values */
+- this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
+-
+ /* Read manufacturer and device IDs from Register */
+ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
+ dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
++ ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID);
+
+ /* Check OneNAND device */
+ if (maf_id != bram_maf_id || dev_id != bram_dev_id)
+ return -ENXIO;
+
+ /* Flash device information */
+- onenand_print_device_info(dev_id);
++ onenand_print_device_info(dev_id, ver_id);
+ this->device_id = dev_id;
++ this->version_id = ver_id;
+
+ density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ this->chipsize = (16 << density) << 20;
+@@ -1676,16 +1794,8 @@ static int onenand_probe(struct mtd_info
+
+ mtd->size = this->chipsize;
+
+- /* Version ID */
+- version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
+- printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);
+-
+- /* Lock scheme */
+- if (density <= ONENAND_DEVICE_DENSITY_512Mb &&
+- !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {
+- printk(KERN_INFO "Lock scheme is Continues Lock\n");
+- this->options |= ONENAND_CONT_LOCK;
+- }
++ /* Check OneNAND lock scheme */
++ onenand_lock_scheme(mtd);
+
+ return 0;
+ }
+@@ -1821,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, i
+ mtd->owner = THIS_MODULE;
+
+ /* Unlock whole block */
+- mtd->unlock(mtd, 0x0, this->chipsize);
++ onenand_unlock_all(mtd);
+
+ return this->scan_bbt(mtd);
+ }
+diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
+new file mode 100644
+index 0000000..79d3bb6
+--- /dev/null
++++ b/drivers/mtd/ssfdc.c
+@@ -0,0 +1,474 @@
++/*
++ * Linux driver for SSFDC Flash Translation Layer (Read only)
++ * (c) 2005 Eptar srl
++ * Author: Claudio Lanconelli <lanconelli.claudio at eptar.com>
++ *
++ * Based on NTFL and MTDBLOCK_RO drivers
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/hdreg.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/blktrans.h>
++
++struct ssfdcr_record {
++ struct mtd_blktrans_dev mbd;
++ int usecount;
++ unsigned char heads;
++ unsigned char sectors;
++ unsigned short cylinders;
++ int cis_block; /* block n. containing CIS/IDI */
++ int erase_size; /* phys_block_size */
++ unsigned short *logic_block_map; /* all zones (max 8192 phys blocks on
++ the 128MiB) */
++ int map_len; /* n. phys_blocks on the card */
++};
++
++#define SSFDCR_MAJOR 257
++#define SSFDCR_PARTN_BITS 3
++
++#define SECTOR_SIZE 512
++#define SECTOR_SHIFT 9
++#define OOB_SIZE 16
++
++#define MAX_LOGIC_BLK_PER_ZONE 1000
++#define MAX_PHYS_BLK_PER_ZONE 1024
++
++#define KiB(x) ( (x) * 1024L )
++#define MiB(x) ( KiB(x) * 1024L )
++
++/** CHS Table
++ 1MiB 2MiB 4MiB 8MiB 16MiB 32MiB 64MiB 128MiB
++NCylinder 125 125 250 250 500 500 500 500
++NHead 4 4 4 4 4 8 8 16
++NSector 4 8 8 16 16 16 32 32
++SumSector 2,000 4,000 8,000 16,000 32,000 64,000 128,000 256,000
++SectorSize 512 512 512 512 512 512 512 512
++**/
++
++typedef struct {
++ unsigned long size;
++ unsigned short cyl;
++ unsigned char head;
++ unsigned char sec;
++} chs_entry_t;
++
++/* Must be ordered by size */
++static const chs_entry_t chs_table[] = {
++ { MiB( 1), 125, 4, 4 },
++ { MiB( 2), 125, 4, 8 },
++ { MiB( 4), 250, 4, 8 },
++ { MiB( 8), 250, 4, 16 },
++ { MiB( 16), 500, 4, 16 },
++ { MiB( 32), 500, 8, 16 },
++ { MiB( 64), 500, 8, 32 },
++ { MiB(128), 500, 16, 32 },
++ { 0 },
++};
++
++static int get_chs(unsigned long size, unsigned short *cyl, unsigned char *head,
++ unsigned char *sec)
++{
++ int k;
++ int found = 0;
++
++ k = 0;
++ while (chs_table[k].size > 0 && size > chs_table[k].size)
++ k++;
++
++ if (chs_table[k].size > 0) {
++ if (cyl)
++ *cyl = chs_table[k].cyl;
++ if (head)
++ *head = chs_table[k].head;
++ if (sec)
++ *sec = chs_table[k].sec;
++ found = 1;
++ }
++
++ return found;
++}
++
++/* These bytes are the signature for the CIS/IDI sector */
++static const uint8_t cis_numbers[] = {
++ 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
++};
++
++/* Read and check for a valid CIS sector */
++static int get_valid_cis_sector(struct mtd_info *mtd)
++{
++ int ret, k, cis_sector;
++ size_t retlen;
++ loff_t offset;
++ uint8_t *sect_buf;
++
++ cis_sector = -1;
++
++ sect_buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
++ if (!sect_buf)
++ goto out;
++
++ /*
++ * Look for CIS/IDI sector on the first GOOD block (give up after 4 bad
++ * blocks). If the first good block doesn't contain CIS number the flash
++ * is not SSFDC formatted
++ */
++ for (k = 0, offset = 0; k < 4; k++, offset += mtd->erasesize) {
++ if (!mtd->block_isbad(mtd, offset)) {
++ ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen,
++ sect_buf);
++
++ /* CIS pattern match on the sector buffer */
++ if (ret < 0 || retlen != SECTOR_SIZE) {
++ printk(KERN_WARNING
++ "SSFDC_RO:can't read CIS/IDI sector\n");
++ } else if (!memcmp(sect_buf, cis_numbers,
++ sizeof(cis_numbers))) {
++ /* Found */
++ cis_sector = (int)(offset >> SECTOR_SHIFT);
++ } else {
++ DEBUG(MTD_DEBUG_LEVEL1,
++ "SSFDC_RO: CIS/IDI sector not found"
++ " on %s (mtd%d)\n", mtd->name,
++ mtd->index);
++ }
++ break;
++ }
++ }
++
++ kfree(sect_buf);
++ out:
++ return cis_sector;
++}
++
++/* Read physical sector (wrapper to MTD_READ) */
++static int read_physical_sector(struct mtd_info *mtd, uint8_t *sect_buf,
++ int sect_no)
++{
++ int ret;
++ size_t retlen;
++ loff_t offset = (loff_t)sect_no << SECTOR_SHIFT;
++
++ ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen, sect_buf);
++ if (ret < 0 || retlen != SECTOR_SIZE)
++ return -1;
++
++ return 0;
++}
++
++/* Read redundancy area (wrapper to MTD_READ_OOB */
++static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)
++{
++ struct mtd_oob_ops ops;
++ int ret;
++
++ ops.mode = MTD_OOB_RAW;
++ ops.ooboffs = 0;
++ ops.ooblen = mtd->oobsize;
++ ops.len = OOB_SIZE;
++ ops.oobbuf = buf;
++ ops.datbuf = NULL;
++
++ ret = mtd->read_oob(mtd, offs, &ops);
++ if (ret < 0 || ops.retlen != OOB_SIZE)
++ return -1;
++
++ return 0;
++}
++
++/* Parity calculator on a word of n bit size */
++static int get_parity(int number, int size)
++{
++ int k;
++ int parity;
++
++ parity = 1;
++ for (k = 0; k < size; k++) {
++ parity += (number >> k);
++ parity &= 1;
++ }
++ return parity;
++}
++
++/* Read and validate the logical block address field stored in the OOB */
++static int get_logical_address(uint8_t *oob_buf)
++{
++ int block_address, parity;
++ int offset[2] = {6, 11}; /* offset of the 2 address fields within OOB */
++ int j;
++ int ok = 0;
++
++ /*
++ * Look for the first valid logical address
++ * Valid address has fixed pattern on most significant bits and
++ * parity check
++ */
++ for (j = 0; j < ARRAY_SIZE(offset); j++) {
++ block_address = ((int)oob_buf[offset[j]] << 8) |
++ oob_buf[offset[j]+1];
++
++ /* Check for the signature bits in the address field (MSBits) */
++ if ((block_address & ~0x7FF) == 0x1000) {
++ parity = block_address & 0x01;
++ block_address &= 0x7FF;
++ block_address >>= 1;
++
++ if (get_parity(block_address, 10) != parity) {
++ DEBUG(MTD_DEBUG_LEVEL0,
++ "SSFDC_RO: logical address field%d"
++ "parity error(0x%04X)\n", j+1,
++ block_address);
++ } else {
++ ok = 1;
++ break;
++ }
++ }
++ }
++
++ if (!ok)
++ block_address = -2;
++
++ DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n",
++ block_address);
++
++ return block_address;
++}
++
++/* Build the logic block map */
++static int build_logical_block_map(struct ssfdcr_record *ssfdc)
++{
++ unsigned long offset;
++ uint8_t oob_buf[OOB_SIZE];
++ int ret, block_address, phys_block;
++ struct mtd_info *mtd = ssfdc->mbd.mtd;
++
++ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n",
++ ssfdc->map_len,
++ (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024);
++
++ /* Scan every physical block, skip CIS block */
++ for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len;
++ phys_block++) {
++ offset = (unsigned long)phys_block * ssfdc->erase_size;
++ if (mtd->block_isbad(mtd, offset))
++ continue; /* skip bad blocks */
++
++ ret = read_raw_oob(mtd, offset, oob_buf);
++ if (ret < 0) {
++ DEBUG(MTD_DEBUG_LEVEL0,
++ "SSFDC_RO: mtd read_oob() failed at %lu\n",
++ offset);
++ return -1;
++ }
++ block_address = get_logical_address(oob_buf);
++
++ /* Skip invalid addresses */
++ if (block_address >= 0 &&
++ block_address < MAX_LOGIC_BLK_PER_ZONE) {
++ int zone_index;
++
++ zone_index = phys_block / MAX_PHYS_BLK_PER_ZONE;
++ block_address += zone_index * MAX_LOGIC_BLK_PER_ZONE;
++ ssfdc->logic_block_map[block_address] =
++ (unsigned short)phys_block;
++
++ DEBUG(MTD_DEBUG_LEVEL2,
++ "SSFDC_RO: build_block_map() phys_block=%d,"
++ "logic_block_addr=%d, zone=%d\n",
++ phys_block, block_address, zone_index);
++ }
++ }
++ return 0;
++}
++
++static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
++{
++ struct ssfdcr_record *ssfdc;
++ int cis_sector;
++
++ /* Check for small page NAND flash */
++ if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE)
++ return;
++
++ /* Check for SSDFC format by reading CIS/IDI sector */
++ cis_sector = get_valid_cis_sector(mtd);
++ if (cis_sector == -1)
++ return;
++
++ ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL);
++ if (!ssfdc) {
++ printk(KERN_WARNING
++ "SSFDC_RO: out of memory for data structures\n");
++ return;
++ }
++
++ ssfdc->mbd.mtd = mtd;
++ ssfdc->mbd.devnum = -1;
++ ssfdc->mbd.blksize = SECTOR_SIZE;
++ ssfdc->mbd.tr = tr;
++ ssfdc->mbd.readonly = 1;
++
++ ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
++ ssfdc->erase_size = mtd->erasesize;
++ ssfdc->map_len = mtd->size / mtd->erasesize;
++
++ DEBUG(MTD_DEBUG_LEVEL1,
++ "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
++ ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
++ (ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) /
++ MAX_PHYS_BLK_PER_ZONE);
++
++ /* Set geometry */
++ ssfdc->heads = 16;
++ ssfdc->sectors = 32;
++ get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
++ ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) /
++ ((long)ssfdc->sectors * (long)ssfdc->heads));
++
++ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
++ ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,
++ (long)ssfdc->cylinders * (long)ssfdc->heads *
++ (long)ssfdc->sectors);
++
++ ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders *
++ (long)ssfdc->sectors;
++
++ /* Allocate logical block map */
++ ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) *
++ ssfdc->map_len, GFP_KERNEL);
++ if (!ssfdc->logic_block_map) {
++ printk(KERN_WARNING
++ "SSFDC_RO: out of memory for data structures\n");
++ goto out_err;
++ }
++ memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) *
++ ssfdc->map_len);
++
++ /* Build logical block map */
++ if (build_logical_block_map(ssfdc) < 0)
++ goto out_err;
++
++ /* Register device + partitions */
++ if (add_mtd_blktrans_dev(&ssfdc->mbd))
++ goto out_err;
++
++ printk(KERN_INFO "SSFDC_RO: Found ssfdc%c on mtd%d (%s)\n",
++ ssfdc->mbd.devnum + 'a', mtd->index, mtd->name);
++ return;
++
++out_err:
++ kfree(ssfdc->logic_block_map);
++ kfree(ssfdc);
++}
++
++static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)
++{
++ struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
++
++ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);
++
++ del_mtd_blktrans_dev(dev);
++ kfree(ssfdc->logic_block_map);
++ kfree(ssfdc);
++}
++
++static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
++ unsigned long logic_sect_no, char *buf)
++{
++ struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
++ int sectors_per_block, offset, block_address;
++
++ sectors_per_block = ssfdc->erase_size >> SECTOR_SHIFT;
++ offset = (int)(logic_sect_no % sectors_per_block);
++ block_address = (int)(logic_sect_no / sectors_per_block);
++
++ DEBUG(MTD_DEBUG_LEVEL3,
++ "SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"
++ " block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
++ block_address);
++
++ if (block_address >= ssfdc->map_len)
++ BUG();
++
++ block_address = ssfdc->logic_block_map[block_address];
++
++ DEBUG(MTD_DEBUG_LEVEL3,
++ "SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",
++ block_address);
++
++ if (block_address < 0xffff) {
++ unsigned long sect_no;
++
++ sect_no = (unsigned long)block_address * sectors_per_block +
++ offset;
++
++ DEBUG(MTD_DEBUG_LEVEL3,
++ "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",
++ sect_no);
++
++ if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0)
++ return -EIO;
++ } else {
++ memset(buf, 0xff, SECTOR_SIZE);
++ }
++
++ return 0;
++}
++
++static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
++{
++ struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
++
++ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",
++ ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);
++
++ geo->heads = ssfdc->heads;
++ geo->sectors = ssfdc->sectors;
++ geo->cylinders = ssfdc->cylinders;
++
++ return 0;
++}
++
++/****************************************************************************
++ *
++ * Module stuff
++ *
++ ****************************************************************************/
++
++static struct mtd_blktrans_ops ssfdcr_tr = {
++ .name = "ssfdc",
++ .major = SSFDCR_MAJOR,
++ .part_bits = SSFDCR_PARTN_BITS,
++ .getgeo = ssfdcr_getgeo,
++ .readsect = ssfdcr_readsect,
++ .add_mtd = ssfdcr_add_mtd,
++ .remove_dev = ssfdcr_remove_dev,
++ .owner = THIS_MODULE,
++};
++
++static int __init init_ssfdcr(void)
++{
++ printk(KERN_INFO "SSFDC read-only Flash Translation layer\n");
++
++ return register_mtd_blktrans(&ssfdcr_tr);
++}
++
++static void __exit cleanup_ssfdcr(void)
++{
++ deregister_mtd_blktrans(&ssfdcr_tr);
++}
++
++module_init(init_ssfdcr);
++module_exit(cleanup_ssfdcr);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio at eptar.com>");
++MODULE_DESCRIPTION("Flash Translation Layer for read-only SSFDC SmartMedia card");
+diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
+index 07136ec..11d170a 100644
+--- a/drivers/net/3c501.c
++++ b/drivers/net/3c501.c
+@@ -30,17 +30,17 @@
+ with a TX-TX optimisation to see if we can touch 180-200K/second as seems
+ theoretically maximum.
+ 19950402 Alan Cox <Alan.Cox at linux.org>
+-
+- Cleaned up for 2.3.x because we broke SMP now.
++
++ Cleaned up for 2.3.x because we broke SMP now.
+ 20000208 Alan Cox <alan at redhat.com>
+
+ Check up pass for 2.5. Nothing significant changed
+ 20021009 Alan Cox <alan at redhat.com>
+
+- Fixed zero fill corner case
++ Fixed zero fill corner case
+ 20030104 Alan Cox <alan at redhat.com>
+-
+-
++
++
+ For the avoidance of doubt the "preferred form" of this code is one which
+ is in an open non patent encumbered format. Where cryptographic key signing
+ forms part of the process of creating an executable the information
+@@ -58,7 +58,7 @@
+ * Some documentation is available from 3Com. Due to the boards age
+ * standard responses when you ask for this will range from 'be serious'
+ * to 'give it to a museum'. The documentation is incomplete and mostly
+- * of historical interest anyway.
++ * of historical interest anyway.
+ *
+ * The basic system is a single buffer which can be used to receive or
+ * transmit a packet. A third command mode exists when you are setting
+@@ -80,7 +80,7 @@
+ * out with those too).
+ *
+ * DOC: Problems
+- *
++ *
+ * There are a wide variety of undocumented error returns from the card
+ * and you basically have to kick the board and pray if they turn up. Most
+ * only occur under extreme load or if you do something the board doesn't
+@@ -120,7 +120,6 @@ static const char version[] =
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/errno.h>
+-#include <linux/config.h> /* for CONFIG_IP_MULTICAST */
+ #include <linux/spinlock.h>
+ #include <linux/ethtool.h>
+ #include <linux/delay.h>
+@@ -146,7 +145,7 @@ static int mem_start;
+
+ /**
+ * el1_probe: - probe for a 3c501
+- * @dev: The device structure passed in to probe.
++ * @dev: The device structure passed in to probe.
+ *
+ * This can be called from two places. The network layer will probe using
+ * a device structure passed in with the probe information completed. For a
+@@ -156,7 +155,7 @@ static int mem_start;
+ * Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to
+ * probe and failing to find anything.
+ */
+-
++
+ struct net_device * __init el1_probe(int unit)
+ {
+ struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+@@ -201,7 +200,7 @@ out:
+ }
+
+ /**
+- * el1_probe1:
++ * el1_probe1:
+ * @dev: The device structure to use
+ * @ioaddr: An I/O address to probe at.
+ *
+@@ -308,7 +307,7 @@ static int __init el1_probe1(struct net_
+ memset(dev->priv, 0, sizeof(struct net_local));
+ lp = netdev_priv(dev);
+ spin_lock_init(&lp->lock);
+-
++
+ /*
+ * The EL1-specific entries in the device structure.
+ */
+@@ -329,7 +328,7 @@ static int __init el1_probe1(struct net_
+ * @dev: device that is being opened
+ *
+ * When an ifconfig is issued which changes the device flags to include
+- * IFF_UP this function is called. It is only called when the change
++ * IFF_UP this function is called. It is only called when the change
+ * occurs, not when the interface remains up. #el1_close will be called
+ * when it goes down.
+ *
+@@ -368,12 +367,12 @@ static int el_open(struct net_device *de
+ * violence and prayer
+ *
+ */
+-
++
+ static void el_timeout(struct net_device *dev)
+ {
+ struct net_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+-
++
+ if (el_debug)
+ printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
+ dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
+@@ -386,7 +385,7 @@ static void el_timeout(struct net_device
+ netif_wake_queue(dev);
+ }
+
+-
++
+ /**
+ * el_start_xmit:
+ * @skb: The packet that is queued to be sent
+@@ -422,7 +421,7 @@ static int el_start_xmit(struct sk_buff
+ */
+
+ spin_lock_irqsave(&lp->lock, flags);
+-
++
+ /*
+ * Avoid timer-based retransmission conflicts.
+ */
+@@ -435,10 +434,10 @@ static int el_start_xmit(struct sk_buff
+ int pad = 0;
+ int gp_start;
+ unsigned char *buf = skb->data;
+-
++
+ if (len < ETH_ZLEN)
+ pad = ETH_ZLEN - len;
+-
++
+ gp_start = 0x800 - ( len + pad );
+
+ lp->tx_pkt_start = gp_start;
+@@ -464,7 +463,7 @@ static int el_start_xmit(struct sk_buff
+ */
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+-
++
+ outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */
+ outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */
+ outsb(DATAPORT,buf,len); /* load buffer (usual thing each byte increments the pointer) */
+@@ -473,7 +472,7 @@ static int el_start_xmit(struct sk_buff
+ outb(0, DATAPORT);
+ }
+ outw(gp_start, GP_LOW); /* the board reuses the same register */
+-
++
+ if(lp->loading != 2)
+ {
+ outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */
+@@ -497,9 +496,8 @@ static int el_start_xmit(struct sk_buff
+ * el_interrupt:
+ * @irq: Interrupt number
+ * @dev_id: The 3c501 that burped
+- * @regs: Register data (surplus to our requirements)
+ *
+- * Handle the ether interface interrupts. The 3c501 needs a lot more
++ * Handle the ether interface interrupts. The 3c501 needs a lot more
+ * hand holding than most cards. In particular we get a transmit interrupt
+ * with a collision error because the board firmware isnt capable of rewinding
+ * its own transmit buffer pointers. It can however count to 16 for us.
+@@ -516,7 +514,7 @@ static int el_start_xmit(struct sk_buff
+ * TCP window.
+ */
+
+-static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t el_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+@@ -527,7 +525,7 @@ static irqreturn_t el_interrupt(int irq,
+ lp = netdev_priv(dev);
+
+ spin_lock(&lp->lock);
+-
++
+ /*
+ * What happened ?
+ */
+@@ -795,7 +793,7 @@ static void el_reset(struct net_device
+ * of the rest will be cleaned up by #el1_open. Always returns 0 indicating
+ * a success.
+ */
+-
++
+ static int el1_close(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+@@ -804,7 +802,7 @@ static int el1_close(struct net_device *
+ printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr);
+
+ netif_stop_queue(dev);
+-
++
+ /*
+ * Free and disable the IRQ.
+ */
+@@ -825,7 +823,7 @@ static int el1_close(struct net_device *
+ *
+ * Returns the statistics for the card from the card private data
+ */
+-
++
+ static struct net_device_stats *el1_get_stats(struct net_device *dev)
+ {
+ struct net_local *lp = netdev_priv(dev);
+@@ -836,7 +834,7 @@ static struct net_device_stats *el1_get_
+ * set_multicast_list:
+ * @dev: The device to adjust
+ *
+- * Set or clear the multicast filter for this adaptor to use the best-effort
++ * Set or clear the multicast filter for this adaptor to use the best-effort
+ * filtering supported. The 3c501 supports only three modes of filtering.
+ * It always receives broadcasts and packets for itself. You can choose to
+ * optionally receive all packets, or all multicast packets on top of this.
+@@ -882,7 +880,7 @@ static void netdev_set_msglevel(struct n
+ debug = level;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+@@ -908,7 +906,7 @@ MODULE_PARM_DESC(irq, "EtherLink IRQ num
+ * Returns 0 for success or -EIO if a card is not found. Returning an error
+ * here also causes the module to be unloaded
+ */
+-
++
+ int __init init_module(void)
+ {
+ dev_3c501 = el1_probe(-1);
+@@ -919,11 +917,11 @@ int __init init_module(void)
+
+ /**
+ * cleanup_module:
+- *
++ *
+ * The module is being unloaded. We unhook our network device from the system
+ * and then free up the resources we took when the card was found.
+ */
+-
++
+ void cleanup_module(void)
+ {
+ struct net_device *dev = dev_3c501;
+diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
+index adb0588..c56a2c6 100644
+--- a/drivers/net/3c501.h
++++ b/drivers/net/3c501.h
+@@ -7,13 +7,13 @@ static int el1_probe1(struct net_device
+ static int el_open(struct net_device *dev);
+ static void el_timeout(struct net_device *dev);
+ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t el_interrupt(int irq, void *dev_id);
+ static void el_receive(struct net_device *dev);
+ static void el_reset(struct net_device *dev);
+ static int el1_close(struct net_device *dev);
+ static struct net_device_stats *el1_get_stats(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+ #define EL1_IO_EXTENT 16
+
+@@ -37,7 +37,7 @@ struct net_local
+ spinlock_t lock; /* Serializing lock */
+ };
+
+-
++
+ #define RX_STATUS (ioaddr + 0x06)
+ #define RX_CMD RX_STATUS
+ #define TX_STATUS (ioaddr + 0x07)
+diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
+index cb5ef75..a34b220 100644
+--- a/drivers/net/3c503.c
++++ b/drivers/net/3c503.c
+@@ -79,9 +79,9 @@ static void el2_block_input(struct net_d
+ int ring_offset);
+ static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
++
+
+-
+ /* This routine probes for a memory-mapped 3c503 board by looking for
+ the "location register" at the end of the jumpered boot PROM space.
+ This works even if a PROM isn't there.
+@@ -96,7 +96,7 @@ static int __init do_el2_probe(struct ne
+ int irq = dev->irq;
+
+ SET_MODULE_OWNER(dev);
+-
++
+ if (base_addr > 0x1ff) /* Check a single specified location. */
+ return el2_probe1(dev, base_addr);
+ else if (base_addr != 0) /* Don't probe at all. */
+@@ -127,7 +127,7 @@ static int __init do_el2_probe(struct ne
+
+ /* Try all of the locations that aren't obviously empty. This touches
+ a lot of locations, and is much riskier than the code above. */
+-static int __init
++static int __init
+ el2_pio_probe(struct net_device *dev)
+ {
+ int i;
+@@ -173,7 +173,7 @@ out:
+ /* Probe for the Etherlink II card at I/O port base IOADDR,
+ returning non-zero on success. If found, set the station
+ address and memory parameters in DEVICE. */
+-static int __init
++static int __init
+ el2_probe1(struct net_device *dev, int ioaddr)
+ {
+ int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
+@@ -367,7 +367,7 @@ out:
+ release_region(ioaddr, EL2_IO_EXTENT);
+ return retval;
+ }
+-
++
+ static int
+ el2_open(struct net_device *dev)
+ {
+@@ -385,7 +385,7 @@ el2_open(struct net_device *dev)
+ outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
+ outb_p(0x00, E33G_IDCFR);
+ if (*irqp == probe_irq_off(cookie) /* It's a good IRQ line! */
+- && ((retval = request_irq(dev->irq = *irqp,
++ && ((retval = request_irq(dev->irq = *irqp,
+ ei_interrupt, 0, dev->name, dev)) == 0))
+ break;
+ }
+@@ -666,7 +666,7 @@ static void netdev_get_drvinfo(struct ne
+ sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+diff --git a/drivers/net/3c503.h b/drivers/net/3c503.h
+index b9f8a46..e2367b8 100644
+--- a/drivers/net/3c503.h
++++ b/drivers/net/3c503.h
+@@ -14,7 +14,7 @@
+
+ /* Shared memory management parameters. NB: The 8 bit cards have only
+ one bank (MB1) which serves both Tx and Rx packet space. The 16bit
+- cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
++ cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
+ You choose which bank appears in the sh. mem window with EGACFR_MBSn */
+
+ #define EL2_MB0_START_PG (0x00) /* EL2/16 Tx packets go in bank 0 */
+@@ -82,7 +82,7 @@
+ 0 1 0 0x4000 -- bank 2, not used
+ 0 1 1 0x6000 -- bank 3, not used
+
+-There was going to be a 32k card that used bank 2 and 3, but it
++There was going to be a 32k card that used bank 2 and 3, but it
+ never got produced.
+
+ */
+diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
+index 19c0b85..458cb9c 100644
+--- a/drivers/net/3c505.c
++++ b/drivers/net/3c505.c
+@@ -315,11 +315,11 @@ static inline void check_3c505_dma(struc
+ spin_lock_irqsave(&adapter->lock, flags);
+ adapter->dmaing = 0;
+ adapter->busy = 0;
+-
++
+ f=claim_dma_lock();
+ disable_dma(dev->dma);
+ release_dma_lock(f);
+-
++
+ if (adapter->rx_active)
+ adapter->rx_active--;
+ outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
+@@ -649,7 +649,7 @@ static void receive_packet(struct net_de
+ *
+ ******************************************************/
+
+-static irqreturn_t elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
++static irqreturn_t elp_interrupt(int irq, void *dev_id)
+ {
+ int len;
+ int dlen;
+@@ -660,7 +660,7 @@ static irqreturn_t elp_interrupt(int irq
+
+ dev = dev_id;
+ adapter = (elp_device *) dev->priv;
+-
++
+ spin_lock(&adapter->lock);
+
+ do {
+@@ -712,7 +712,7 @@ static irqreturn_t elp_interrupt(int irq
+ timeout = jiffies + 3*HZ/100;
+ while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
+ if (receive_pcb(dev, &adapter->irx_pcb)) {
+- switch (adapter->irx_pcb.command)
++ switch (adapter->irx_pcb.command)
+ {
+ case 0:
+ break;
+@@ -889,7 +889,7 @@ static int elp_open(struct net_device *d
+ adapter->send_pcb_semaphore = 0;
+ adapter->rx_backlog.in = 0;
+ adapter->rx_backlog.out = 0;
+-
++
+ spin_lock_init(&adapter->lock);
+
+ /*
+@@ -1003,7 +1003,7 @@ static int send_packet(struct net_device
+ }
+
+ adapter->stats.tx_bytes += nlen;
+-
++
+ /*
+ * send the adapter a transmit packet command. Ignore segment and offset
+ * and make sure the length is even
+@@ -1044,7 +1044,7 @@ static int send_packet(struct net_device
+ outb_control(adapter->hcr_val | DMAE | TCEN, dev);
+ enable_dma(dev->dma);
+ release_dma_lock(flags);
+-
++
+ if (elp_debug >= 3)
+ printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);
+
+@@ -1054,7 +1054,7 @@ static int send_packet(struct net_device
+ /*
+ * The upper layer thinks we timed out
+ */
+-
++
+ static void elp_timeout(struct net_device *dev)
+ {
+ elp_device *adapter = dev->priv;
+@@ -1080,7 +1080,7 @@ static int elp_start_xmit(struct sk_buff
+ {
+ unsigned long flags;
+ elp_device *adapter = dev->priv;
+-
++
+ spin_lock_irqsave(&adapter->lock, flags);
+ check_3c505_dma(dev);
+
+@@ -1088,7 +1088,7 @@ static int elp_start_xmit(struct sk_buff
+ printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len);
+
+ netif_stop_queue(dev);
+-
++
+ /*
+ * send the packet at skb->data for skb->len
+ */
+@@ -1169,7 +1169,7 @@ static void netdev_set_msglevel(struct n
+ debug = level;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+@@ -1235,7 +1235,7 @@ static void elp_set_mc_list(struct net_d
+ printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+-
++
+ if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ /* send a "load multicast list" command to the board, max 10 addrs/cmd */
+ /* if num_addrs==0 the list will be cleared */
+diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
+index 77dfeed..1910cb1 100644
+--- a/drivers/net/3c505.h
++++ b/drivers/net/3c505.h
+@@ -72,7 +72,7 @@
+ /*****************************************************************
+ *
+ * timeout value
+- * this is a rough value used for loops to stop them from
++ * this is a rough value used for loops to stop them from
+ * locking up the whole machine in the case of failure or
+ * error conditions
+ *
+diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
+index 6039049..aa43563 100644
+--- a/drivers/net/3c507.c
++++ b/drivers/net/3c507.c
+@@ -286,7 +286,7 @@ static unsigned short init_words[] = {
+ static int el16_probe1(struct net_device *dev, int ioaddr);
+ static int el16_open(struct net_device *dev);
+ static int el16_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t el16_interrupt(int irq, void *dev_id);
+ static void el16_rx(struct net_device *dev);
+ static int el16_close(struct net_device *dev);
+ static struct net_device_stats *el16_get_stats(struct net_device *dev);
+@@ -294,14 +294,14 @@ static void el16_tx_timeout (struct net_
+
+ static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
+ static void init_82586_mem(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static void init_rx_bufs(struct net_device *);
+
+ static int io = 0x300;
+ static int irq;
+ static int mem_start;
+
+-
++
+ /* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+@@ -379,7 +379,7 @@ static int __init el16_probe1(struct net
+ if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
+ return -ENODEV;
+
+- if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
++ if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
+ (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
+ retval = -ENODEV;
+ goto out;
+@@ -543,7 +543,7 @@ static int el16_send_packet (struct sk_b
+
+ /* The typical workload of the driver:
+ Handle the network interface interrupts. */
+-static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t el16_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+@@ -575,7 +575,7 @@ static irqreturn_t el16_interrupt(int ir
+ while (lp->tx_pkts_in_ring) {
+ unsigned short tx_status = readw(shmem+lp->tx_reap);
+ if (!(tx_status & 0x8000)) {
+- if (net_debug > 5)
++ if (net_debug > 5)
+ printk("Tx command incomplete (%#x).\n", lp->tx_reap);
+ break;
+ }
+@@ -825,7 +825,7 @@ static void hardware_send_packet(struct
+ }
+
+ /* Grimly block further packets if there has been insufficient reaping. */
+- if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
++ if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
+ netif_wake_queue(dev);
+ }
+
+@@ -919,7 +919,7 @@ static void netdev_set_msglevel(struct n
+ debug = level;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+@@ -953,7 +953,7 @@ cleanup_module(void)
+ #endif /* MODULE */
+ MODULE_LICENSE("GPL");
+
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c"
+diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
+index cbdae54..f791bf0 100644
+--- a/drivers/net/3c509.c
++++ b/drivers/net/3c509.c
+@@ -28,7 +28,7 @@
+ FIXES:
+ Alan Cox: Removed the 'Unexpected interrupt' bug.
+ Michael Meskes: Upgraded to Donald Becker's version 1.07.
+- Alan Cox: Increased the eeprom delay. Regardless of
++ Alan Cox: Increased the eeprom delay. Regardless of
+ what the docs say some people definitely
+ get problems with lower (but in card spec)
+ delays
+@@ -162,7 +162,7 @@ enum RxFilter {
+ #define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
+ #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
+ #define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */
+-#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */
++#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */
+
+ /*
+ * Must be a power of two (we use a binary and in the
+@@ -191,7 +191,7 @@ static ushort id_read_eeprom(int index);
+ static ushort read_eeprom(int ioaddr, int index);
+ static int el3_open(struct net_device *dev);
+ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t el3_interrupt(int irq, void *dev_id);
+ static void update_stats(struct net_device *dev);
+ static struct net_device_stats *el3_get_stats(struct net_device *dev);
+ static int el3_rx(struct net_device *dev);
+@@ -200,7 +200,7 @@ static void set_multicast_list(struct ne
+ static void el3_tx_timeout (struct net_device *dev);
+ static void el3_down(struct net_device *dev);
+ static void el3_up(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+ #ifdef EL3_SUSPEND
+ static int el3_suspend(struct device *, pm_message_t);
+ static int el3_resume(struct device *);
+@@ -225,6 +225,7 @@ static struct eisa_device_id el3_eisa_id
+ { "TCM5095" },
+ { "" }
+ };
++MODULE_DEVICE_TABLE(eisa, el3_eisa_ids);
+
+ static int el3_eisa_probe (struct device *device);
+
+@@ -350,7 +351,7 @@ static int __init el3_common_init(struct
+ {
+ const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
+ printk("%s: 3c5x9 found at %#3.3lx, %s port, address ",
+- dev->name, dev->base_addr,
++ dev->name, dev->base_addr,
+ if_names[(dev->if_port & 0x03)]);
+ }
+
+@@ -528,7 +529,7 @@ no_pnp:
+ SET_MODULE_OWNER(dev);
+
+ netdev_boot_setup_check(dev);
+-
++
+ /* Set passed-in IRQ or I/O Addr. */
+ if (dev->irq > 1 && dev->irq < 16)
+ irq = dev->irq;
+@@ -630,7 +631,7 @@ static int __init el3_mca_probe(struct d
+ if_port = pos4 & 0x03;
+
+ irq = mca_device_transform_irq(mdev, irq);
+- ioaddr = mca_device_transform_ioport(mdev, ioaddr);
++ ioaddr = mca_device_transform_ioport(mdev, ioaddr);
+ if (el3_debug > 2) {
+ printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
+ }
+@@ -667,7 +668,7 @@ static int __init el3_mca_probe(struct d
+ el3_cards++;
+ return 0;
+ }
+-
++
+ #endif /* CONFIG_MCA */
+
+ #ifdef CONFIG_EISA
+@@ -684,7 +685,7 @@ static int __init el3_eisa_probe (struct
+ /* Yeepee, The driver framework is calling us ! */
+ edev = to_eisa_device (device);
+ ioaddr = edev->base_addr;
+-
++
+ if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509"))
+ return -EBUSY;
+
+@@ -751,7 +752,7 @@ static int __devexit el3_device_remove (
+ static ushort read_eeprom(int ioaddr, int index)
+ {
+ outw(EEPROM_READ + index, ioaddr + 10);
+- /* Pause for at least 162 us. for the read to take place.
++ /* Pause for at least 162 us. for the read to take place.
+ Some chips seem to require much longer */
+ mdelay(2);
+ return inw(ioaddr + 12);
+@@ -769,7 +770,7 @@ static ushort __init id_read_eeprom(int
+ /* Pause for at least 162 us. for the read to take place. */
+ /* Some chips seem to require much longer */
+ mdelay(4);
+-
++
+ for (bit = 15; bit >= 0; bit--)
+ word = (word << 1) + (inb(id_port) & 0x01);
+
+@@ -838,7 +839,7 @@ el3_start_xmit(struct sk_buff *skb, stru
+ netif_stop_queue (dev);
+
+ lp->stats.tx_bytes += skb->len;
+-
++
+ if (el3_debug > 4) {
+ printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
+ dev->name, skb->len, inw(ioaddr + EL3_STATUS));
+@@ -879,11 +880,7 @@ el3_start_xmit(struct sk_buff *skb, stru
+ outw(skb->len, ioaddr + TX_FIFO);
+ outw(0x00, ioaddr + TX_FIFO);
+ /* ... and the packet rounded to a doubleword. */
+-#ifdef __powerpc__
+- outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+-#else
+ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+-#endif
+
+ dev->trans_start = jiffies;
+ if (inw(ioaddr + TX_FREE) > 1536)
+@@ -913,18 +910,13 @@ el3_start_xmit(struct sk_buff *skb, stru
+
+ /* The EL3 interrupt handler. */
+ static irqreturn_t
+-el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++el3_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *)dev_id;
++ struct net_device *dev = dev_id;
+ struct el3_private *lp;
+ int ioaddr, status;
+ int i = max_interrupt_work;
+
+- if (dev == NULL) {
+- printk ("el3_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
+ lp = netdev_priv(dev);
+ spin_lock(&lp->lock);
+
+@@ -1009,7 +1001,7 @@ el3_interrupt(int irq, void *dev_id, str
+ static void el3_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- el3_interrupt(dev->irq, dev, NULL);
++ el3_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1024,7 +1016,7 @@ el3_get_stats(struct net_device *dev)
+ * This is fast enough not to bother with disable IRQ
+ * stuff.
+ */
+-
++
+ spin_lock_irqsave(&lp->lock, flags);
+ update_stats(dev);
+ spin_unlock_irqrestore(&lp->lock, flags);
+@@ -1103,13 +1095,8 @@ el3_rx(struct net_device *dev)
+ skb_reserve(skb, 2); /* Align IP on 16 byte */
+
+ /* 'skb->data' points to the start of sk_buff data area. */
+-#ifdef __powerpc__
+- insl_ns(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
+- (pkt_len + 3) >> 2);
+-#else
+ insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
+ (pkt_len + 3) >> 2);
+-#endif
+
+ outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+ skb->protocol = eth_type_trans(skb,dev);
+@@ -1168,7 +1155,7 @@ el3_close(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+ struct el3_private *lp = netdev_priv(dev);
+-
++
+ if (el3_debug > 2)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+@@ -1187,7 +1174,7 @@ el3_close(struct net_device *dev)
+ return 0;
+ }
+
+-static int
++static int
+ el3_link_ok(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+@@ -1204,9 +1191,9 @@ el3_netdev_get_ecmd(struct net_device *d
+ {
+ u16 tmp;
+ int ioaddr = dev->base_addr;
+-
++
+ EL3WINDOW(0);
+- /* obtain current transceiver via WN4_MEDIA? */
++ /* obtain current transceiver via WN4_MEDIA? */
+ tmp = inw(ioaddr + WN0_ADDR_CONF);
+ ecmd->transceiver = XCVR_INTERNAL;
+ switch (tmp >> 14) {
+@@ -1349,7 +1336,7 @@ static void el3_set_msglevel(struct net_
+ el3_debug = v;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = el3_get_drvinfo,
+ .get_settings = el3_get_settings,
+ .set_settings = el3_set_settings,
+@@ -1391,7 +1378,7 @@ el3_up(struct net_device *dev)
+ {
+ int i, sw_info, net_diag;
+ int ioaddr = dev->base_addr;
+-
++
+ /* Activating the board required and does no harm otherwise */
+ outw(0x0001, ioaddr + 4);
+
+@@ -1411,7 +1398,7 @@ el3_up(struct net_device *dev)
+ /* Combine secondary sw_info word (the adapter level) and primary
+ sw_info word (duplex setting plus other useless bits) */
+ EL3WINDOW(0);
+- sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |
++ sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |
+ (read_eeprom(ioaddr, 0x0d) & 0xBff0);
+
+ EL3WINDOW(4);
+@@ -1483,7 +1470,7 @@ el3_suspend(struct device *pdev, pm_mess
+ struct net_device *dev;
+ struct el3_private *lp;
+ int ioaddr;
+-
++
+ dev = pdev->driver_data;
+ lp = netdev_priv(dev);
+ ioaddr = dev->base_addr;
+@@ -1507,7 +1494,7 @@ el3_resume(struct device *pdev)
+ struct net_device *dev;
+ struct el3_private *lp;
+ int ioaddr;
+-
++
+ dev = pdev->driver_data;
+ lp = netdev_priv(dev);
+ ioaddr = dev->base_addr;
+@@ -1519,7 +1506,7 @@ el3_resume(struct device *pdev)
+
+ if (netif_running(dev))
+ netif_device_attach(dev);
+-
++
+ spin_unlock_irqrestore(&lp->lock, flags);
+ return 0;
+ }
+diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
+index aedfddf..c307ce6 100644
+--- a/drivers/net/3c515.c
++++ b/drivers/net/3c515.c
+@@ -12,12 +12,12 @@
+ Annapolis MD 21403
+
+
+- 2000/2/2- Added support for kernel-level ISAPnP
++ 2000/2/2- Added support for kernel-level ISAPnP
+ by Stephen Frost <sfrost at snowman.net> and Alessandro Zummo
+ Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
+-
++
+ 2001/11/17 - Added ethtool support (jgarzik)
+-
++
+ 2002/10/28 - Locking updates for 2.5 (alan at redhat.com)
+
+ */
+@@ -187,9 +187,9 @@ enum corkscrew_cmd {
+ TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
+ RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
+ UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2,
+- DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
+- TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
+- AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
++ DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
++ TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
++ AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
+ SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11,
+ SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11,
+ StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11,
+@@ -338,15 +338,15 @@ static struct media_table {
+ mask:8, /* The transceiver-present bit in Wn3_Config. */
+ next:8; /* The media type to try next. */
+ short wait; /* Time before we check media status. */
+-} media_tbl[] = {
+- { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
+- { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
+- { "undefined", 0, 0x80, XCVR_10baseT, 10000},
+- { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
+- { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
+- { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
+- { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
+- { "undefined", 0, 0x01, XCVR_10baseT, 10000},
++} media_tbl[] = {
++ { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
++ { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
++ { "undefined", 0, 0x80, XCVR_10baseT, 10000},
++ { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
++ { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
++ { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
++ { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
++ { "undefined", 0, 0x01, XCVR_10baseT, 10000},
+ { "Default", 0, 0xFF, XCVR_10baseT, 10000},
+ };
+
+@@ -373,16 +373,15 @@ static int corkscrew_start_xmit(struct s
+ static int corkscrew_rx(struct net_device *dev);
+ static void corkscrew_timeout(struct net_device *dev);
+ static int boomerang_rx(struct net_device *dev);
+-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t corkscrew_interrupt(int irq, void *dev_id);
+ static int corkscrew_close(struct net_device *dev);
+ static void update_stats(int addr, struct net_device *dev);
+ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
+-
++static const struct ethtool_ops netdev_ethtool_ops;
+
+-/*
++
++/*
+ Unfortunately maximizing the shared code between the integrated and
+ module version of the driver results in a complicated set of initialization
+ procedures.
+@@ -612,7 +611,7 @@ static int corkscrew_setup(struct net_de
+ printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
+
+ spin_lock_init(&vp->lock);
+-
++
+ /* Read the station address from the EEPROM. */
+ EL3WINDOW(0);
+ for (i = 0; i < 0x18; i++) {
+@@ -691,7 +690,7 @@ static int corkscrew_setup(struct net_de
+
+ return register_netdev(dev);
+ }
+-
++
+
+ static int corkscrew_open(struct net_device *dev)
+ {
+@@ -715,7 +714,7 @@ static int corkscrew_open(struct net_dev
+ } else if (vp->autoselect) {
+ /* Find first available media type, starting with 100baseTx. */
+ dev->if_port = 4;
+- while (!(vp->available_media & media_tbl[dev->if_port].mask))
++ while (!(vp->available_media & media_tbl[dev->if_port].mask))
+ dev->if_port = media_tbl[dev->if_port].next;
+
+ if (corkscrew_debug > 1)
+@@ -871,7 +870,7 @@ static void corkscrew_timer(unsigned lon
+ dev->name, media_tbl[dev->if_port].name);
+
+ spin_lock_irqsave(&vp->lock, flags);
+-
++
+ {
+ int old_window = inw(ioaddr + EL3_CMD) >> 13;
+ int media_status;
+@@ -911,7 +910,7 @@ static void corkscrew_timer(unsigned lon
+ media_tbl[dev->if_port].next;
+ }
+ while (!(vp->available_media & media_tbl[dev->if_port].mask));
+-
++
+ if (dev->if_port == 8) { /* Go back to default. */
+ dev->if_port = vp->default_media;
+ if (corkscrew_debug > 1)
+@@ -940,7 +939,7 @@ static void corkscrew_timer(unsigned lon
+ }
+ EL3WINDOW(old_window);
+ }
+-
++
+ spin_unlock_irqrestore(&vp->lock, flags);
+ if (corkscrew_debug > 1)
+ printk("%s: Media selection timer finished, %s.\n",
+@@ -1026,7 +1025,7 @@ static int corkscrew_start_xmit(struct s
+ outw(DownStall, ioaddr + EL3_CMD);
+ /* Wait for the stall to complete. */
+ for (i = 20; i >= 0; i--)
+- if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
++ if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
+ break;
+ if (prev_entry)
+ prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
+@@ -1102,7 +1101,7 @@ static int corkscrew_start_xmit(struct s
+ int j;
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (j = 20; j >= 0; j--)
+- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
++ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ }
+ outw(TxEnable, ioaddr + EL3_CMD);
+@@ -1116,8 +1115,7 @@ static int corkscrew_start_xmit(struct s
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+
+-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
+ {
+ /* Use the now-standard shared IRQ implementation. */
+ struct net_device *dev = dev_id;
+@@ -1130,7 +1128,7 @@ static irqreturn_t corkscrew_interrupt(i
+ latency = inb(ioaddr + Timer);
+
+ spin_lock(&lp->lock);
+-
++
+ status = inw(ioaddr + EL3_STATUS);
+
+ if (corkscrew_debug > 4)
+@@ -1249,7 +1247,7 @@ static irqreturn_t corkscrew_interrupt(i
+ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+
+ } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+-
++
+ spin_unlock(&lp->lock);
+
+ if (corkscrew_debug > 4)
+@@ -1308,7 +1306,7 @@ static int corkscrew_rx(struct net_devic
+ vp->stats.rx_bytes += pkt_len;
+ /* Wait a limited time to go to next packet. */
+ for (i = 200; i >= 0; i--)
+- if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
++ if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ continue;
+ } else if (corkscrew_debug)
+@@ -1561,13 +1559,13 @@ static void netdev_set_msglevel(struct n
+ corkscrew_debug = level;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+ };
+
+-
++
+ #ifdef MODULE
+ void cleanup_module(void)
+ {
+@@ -1584,7 +1582,7 @@ void cleanup_module(void)
+ }
+ }
+ #endif /* MODULE */
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"
+diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
+index 5dfd97f..9184946 100644
+--- a/drivers/net/3c523.c
++++ b/drivers/net/3c523.c
+@@ -83,7 +83,7 @@
+ Stuart Adamson <stuart.adamson at compsoc.net>
+ Nov 2001
+ added support for ethtool (jgarzik)
+-
++
+ $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
+ */
+
+@@ -180,7 +180,7 @@ sizeof(nop_cmd) = 8;
+ dev->name,__LINE__); \
+ elmc_id_reset586(); } } }
+
+-static irqreturn_t elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr);
++static irqreturn_t elmc_interrupt(int irq, void *dev_id);
+ static int elmc_open(struct net_device *dev);
+ static int elmc_close(struct net_device *dev);
+ static int elmc_send_packet(struct sk_buff *, struct net_device *);
+@@ -189,7 +189,7 @@ static void elmc_timeout(struct net_devi
+ #ifdef ELMC_MULTICAST
+ static void set_multicast_list(struct net_device *dev);
+ #endif
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+ /* helper-functions */
+ static int init586(struct net_device *dev);
+@@ -434,14 +434,14 @@ static int __init do_elmc_probe(struct n
+
+ dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
+ dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
+-
++
+ /*
+ If we're trying to match a specified irq or IO address,
+ we'll reject a match unless it's what we're looking for.
+ Also reject it if the card is already in use.
+ */
+
+- if ((irq && irq != dev->irq) ||
++ if ((irq && irq != dev->irq) ||
+ (base_addr && base_addr != dev->base_addr)) {
+ slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+ continue;
+@@ -540,7 +540,7 @@ static int __init do_elmc_probe(struct n
+
+ /* dump all the assorted information */
+ printk(KERN_INFO "%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
+- dev->irq, dev->if_port ? "ex" : "in",
++ dev->irq, dev->if_port ? "ex" : "in",
+ dev->mem_start, dev->mem_end - 1);
+
+ /* The hardware address for the 3c523 is stored in the first six
+@@ -564,7 +564,7 @@ static int __init do_elmc_probe(struct n
+ dev->set_multicast_list = NULL;
+ #endif
+ dev->ethtool_ops = &netdev_ethtool_ops;
+-
++
+ /* note that we haven't actually requested the IRQ from the kernel.
+ That gets done in elmc_open(). I'm not sure that's such a good idea,
+ but it works, so I'll go with it. */
+@@ -583,7 +583,7 @@ err_out:
+ release_region(dev->base_addr, ELMC_IO_EXTENT);
+ return retval;
+ }
+-
++
+ static void cleanup_card(struct net_device *dev)
+ {
+ mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL);
+@@ -900,16 +900,13 @@ static void *alloc_rfa(struct net_device
+ */
+
+ static irqreturn_t
+-elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
++elmc_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ unsigned short stat;
+ struct priv *p;
+
+- if (dev == NULL) {
+- printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2));
+- return IRQ_NONE;
+- } else if (!netif_running(dev)) {
++ if (!netif_running(dev)) {
+ /* The 3c523 has this habit of generating interrupts during the
+ reset. I'm not sure if the ni52 has this same problem, but it's
+ really annoying if we haven't finished initializing it. I was
+@@ -926,7 +923,7 @@ elmc_interrupt(int irq, void *dev_id, st
+
+ p = (struct priv *) dev->priv;
+
+- while ((stat = p->scb->status & STAT_MASK))
++ while ((stat = p->scb->status & STAT_MASK))
+ {
+ p->scb->cmd = stat;
+ elmc_attn586(); /* ack inter. */
+@@ -1102,7 +1099,7 @@ static void startrecv586(struct net_devi
+ /******************************************************
+ * timeout
+ */
+-
++
+ static void elmc_timeout(struct net_device *dev)
+ {
+ struct priv *p = (struct priv *) dev->priv;
+@@ -1129,7 +1126,7 @@ static void elmc_timeout(struct net_devi
+ elmc_open(dev);
+ }
+ }
+-
++
+ /******************************************************
+ * send frame
+ */
+@@ -1146,7 +1143,7 @@ static int elmc_send_packet(struct sk_bu
+ netif_stop_queue(dev);
+
+ len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+-
++
+ if (len != skb->len)
+ memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+ memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);
+@@ -1177,7 +1174,7 @@ static int elmc_send_packet(struct sk_bu
+ #else
+ next_nop = (p->nop_point + 1) & 0x1;
+ p->xmit_buffs[0]->size = TBD_LAST | len;
+-
++
+ p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+ = make16((p->nop_cmds[next_nop]));
+ p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+@@ -1259,7 +1256,7 @@ static void netdev_get_drvinfo(struct ne
+ sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+@@ -1281,7 +1278,7 @@ int __init init_module(void)
+ {
+ int this_dev,found = 0;
+
+- /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
++ /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
+ for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
+ struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+ if (!dev)
+diff --git a/drivers/net/3c523.h b/drivers/net/3c523.h
+index 7292f88..6956441 100644
+--- a/drivers/net/3c523.h
++++ b/drivers/net/3c523.h
+@@ -130,7 +130,7 @@ struct rfd_struct
+ /*
+ * Receive Buffer Descriptor (RBD)
+ */
+-struct rbd_struct
++struct rbd_struct
+ {
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+@@ -182,7 +182,7 @@ struct nop_cmd_struct
+ /*
+ * IA Setup command
+ */
+-struct iasetup_cmd_struct
++struct iasetup_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+@@ -191,7 +191,7 @@ struct iasetup_cmd_struct
+ };
+
+ /*
+- * Configure command
++ * Configure command
+ */
+ struct configure_cmd_struct
+ {
+@@ -213,9 +213,9 @@ struct configure_cmd_struct
+ };
+
+ /*
+- * Multicast Setup command
++ * Multicast Setup command
+ */
+-struct mcsetup_cmd_struct
++struct mcsetup_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+@@ -225,9 +225,9 @@ struct mcsetup_cmd_struct
+ };
+
+ /*
+- * transmit command
++ * transmit command
+ */
+-struct transmit_cmd_struct
++struct transmit_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
+index 03c0f71..f4aca53 100644
+--- a/drivers/net/3c527.c
++++ b/drivers/net/3c527.c
+@@ -1,7 +1,7 @@
+ /* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
+ *
+ * (c) Copyright 1998 Red Hat Software Inc
+- * Written by Alan Cox.
++ * Written by Alan Cox.
+ * Further debugging by Carl Drougge.
+ * Initial SMP support by Felipe W Damasio <felipewd at terra.com.br>
+ * Heavily modified by Richard Procter <rnp at paradise.net.nz>
+@@ -30,12 +30,12 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELD
+ * The diagram (Figure 1-1) and the POS summary disagree with the
+ * "Interrupt Level" section in the manual.
+ *
+- * The manual contradicts itself when describing the minimum number
+- * buffers in the 'configure lists' command.
+- * My card accepts a buffer config of 4/4.
++ * The manual contradicts itself when describing the minimum number
++ * buffers in the 'configure lists' command.
++ * My card accepts a buffer config of 4/4.
+ *
+ * Setting the SAV BP bit does not save bad packets, but
+- * only enables RX on-card stats collection.
++ * only enables RX on-card stats collection.
+ *
+ * The documentation in places seems to miss things. In actual fact
+ * I've always eventually found everything is documented, it just
+@@ -64,16 +64,16 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELD
+ * received frames exceeding a configurable length are passed
+ * directly to the higher networking layers without incuring a copy,
+ * in what amounts to a time/space trade-off.
+- *
++ *
+ * The card also keeps a large amount of statistical information
+ * on-board. In a perfect world, these could be used safely at no
+ * cost. However, lacking information to the contrary, processing
+ * them without races would involve so much extra complexity as to
+ * make it unworthwhile to do so. In the end, a hybrid SW/HW
+- * implementation was made necessary --- see mc32_update_stats().
++ * implementation was made necessary --- see mc32_update_stats().
+ *
+ * DOC: Notes
+- *
++ *
+ * It should be possible to use two or more cards, but at this stage
+ * only by loading two copies of the same module.
+ *
+@@ -132,28 +132,28 @@ static unsigned int mc32_debug = NET_DEB
+ /* The number of low I/O ports used by the ethercard. */
+ #define MC32_IO_EXTENT 8
+
+-/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
++/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
+ #define TX_RING_LEN 32 /* Typically the card supports 37 */
+ #define RX_RING_LEN 8 /* " " " */
+
+-/* Copy break point, see above for details.
+- * Setting to > 1512 effectively disables this feature. */
++/* Copy break point, see above for details.
++ * Setting to > 1512 effectively disables this feature. */
+ #define RX_COPYBREAK 200 /* Value from 3c59x.c */
+
+ /* Issue the 82586 workaround command - this is for "busy lans", but
+- * basically means for all lans now days - has a performance (latency)
+- * cost, but best set. */
++ * basically means for all lans now days - has a performance (latency)
++ * cost, but best set. */
+ static const int WORKAROUND_82586=1;
+
+ /* Pointers to buffers and their on-card records */
+-struct mc32_ring_desc
++struct mc32_ring_desc
+ {
+- volatile struct skb_header *p;
+- struct sk_buff *skb;
++ volatile struct skb_header *p;
++ struct sk_buff *skb;
+ };
+
+ /* Information that needs to be kept for each board. */
+-struct mc32_local
++struct mc32_local
+ {
+ int slot;
+
+@@ -165,7 +165,7 @@ struct mc32_local
+ volatile struct mc32_stats *stats; /* Start of on-card statistics */
+ u16 tx_chain; /* Transmit list start offset */
+ u16 rx_chain; /* Receive list start offset */
+- u16 tx_len; /* Transmit list count */
++ u16 tx_len; /* Transmit list count */
+ u16 rx_len; /* Receive list count */
+
+ u16 xceiver_desired_state; /* HALTED or RUNNING */
+@@ -180,7 +180,7 @@ struct mc32_local
+ atomic_t tx_ring_head; /* index to tx en-queue end */
+ u16 tx_ring_tail; /* index to tx de-queue end */
+
+- u16 rx_ring_tail; /* index to rx de-queue end */
++ u16 rx_ring_tail; /* index to rx de-queue end */
+
+ struct semaphore cmd_mutex; /* Serialises issuing of execute commands */
+ struct completion execution_cmd; /* Card has completed an execute command */
+@@ -204,7 +204,7 @@ static const struct mca_adapters_t mc32_
+ };
+
+
+-/* Macros for ring index manipulations */
++/* Macros for ring index manipulations */
+ static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+ static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
+
+@@ -217,12 +217,12 @@ static int mc32_command(struct net_
+ static int mc32_open(struct net_device *dev);
+ static void mc32_timeout(struct net_device *dev);
+ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t mc32_interrupt(int irq, void *dev_id);
+ static int mc32_close(struct net_device *dev);
+ static struct net_device_stats *mc32_get_stats(struct net_device *dev);
+ static void mc32_set_multicast_list(struct net_device *dev);
+ static void mc32_reset_multicast_list(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+ static void cleanup_card(struct net_device *dev)
+ {
+@@ -259,21 +259,21 @@ struct net_device *__init mc32_probe(int
+
+ SET_MODULE_OWNER(dev);
+
+- /* Do not check any supplied i/o locations.
++ /* Do not check any supplied i/o locations.
+ POS registers usually don't fail :) */
+
+- /* MCA cards have POS registers.
+- Autodetecting MCA cards is extremely simple.
++ /* MCA cards have POS registers.
++ Autodetecting MCA cards is extremely simple.
+ Just search for the card. */
+
+ for(i = 0; (mc32_adapters[i].name != NULL); i++) {
+- current_mca_slot =
++ current_mca_slot =
+ mca_find_unused_adapter(mc32_adapters[i].id, 0);
+
+ if(current_mca_slot != MCA_NOTFOUND) {
+ if(!mc32_probe1(dev, current_mca_slot))
+ {
+- mca_set_adapter_name(current_mca_slot,
++ mca_set_adapter_name(current_mca_slot,
+ mc32_adapters[i].name);
+ mca_mark_as_used(current_mca_slot);
+ err = register_netdev(dev);
+@@ -284,7 +284,7 @@ struct net_device *__init mc32_probe(int
+ }
+ return dev;
+ }
+-
++
+ }
+ }
+ free_netdev(dev);
+@@ -298,7 +298,7 @@ struct net_device *__init mc32_probe(int
+ *
+ * Decode the slot data and configure the card structures. Having done this we
+ * can reset the card and configure it. The card does a full self test cycle
+- * in firmware so we have to wait for it to return and post us either a
++ * in firmware so we have to wait for it to return and post us either a
+ * failure case or some addresses we use to find the board internals.
+ */
+
+@@ -347,7 +347,7 @@ static int __init mc32_probe1(struct net
+ printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot);
+
+ POS = mca_read_stored_pos(slot, 2);
+-
++
+ if(!(POS&1))
+ {
+ printk(" disabled.\n");
+@@ -357,7 +357,7 @@ static int __init mc32_probe1(struct net
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = mca_io_bases[(POS>>1)&7];
+ dev->mem_start = mca_mem_bases[(POS>>4)&7];
+-
++
+ POS = mca_read_stored_pos(slot, 4);
+ if(!(POS&1))
+ {
+@@ -366,21 +366,21 @@ static int __init mc32_probe1(struct net
+ }
+
+ POS = mca_read_stored_pos(slot, 5);
+-
++
+ i=(POS>>4)&3;
+ if(i==3)
+ {
+ printk("invalid memory window.\n");
+ return -ENODEV;
+ }
+-
++
+ i*=16384;
+ i+=16384;
+-
++
+ dev->mem_end=dev->mem_start + i;
+-
++
+ dev->irq = ((POS>>2)&3)+9;
+-
++
+ if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
+ {
+ printk("io 0x%3lX, which is busy.\n", dev->base_addr);
+@@ -389,23 +389,23 @@ static int __init mc32_probe1(struct net
+
+ printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
+ dev->base_addr, dev->irq, dev->mem_start, i/1024);
+-
+-
++
++
+ /* We ought to set the cache line size here.. */
+-
+-
++
++
+ /*
+ * Go PROM browsing
+ */
+-
++
+ printk("%s: Address ", dev->name);
+-
++
+ /* Retrieve and print the ethernet address. */
+ for (i = 0; i < 6; i++)
+ {
+ mca_write_pos(slot, 6, i+12);
+ mca_write_pos(slot, 7, 0);
+-
++
+ printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3));
+ }
+
+@@ -413,12 +413,12 @@ static int __init mc32_probe1(struct net
+ mca_write_pos(slot, 7, 0);
+
+ POS = mca_read_stored_pos(slot, 4);
+-
++
+ if(POS&2)
+ printk(" : BNC port selected.\n");
+- else
++ else
+ printk(" : AUI port selected.\n");
+-
++
+ POS=inb(dev->base_addr+HOST_CTRL);
+ POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
+ POS&=~HOST_CTRL_INTE;
+@@ -428,9 +428,9 @@ static int __init mc32_probe1(struct net
+ /* Reset off */
+ POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
+ outb(POS, dev->base_addr+HOST_CTRL);
+-
++
+ udelay(300);
+-
++
+ /*
+ * Grab the IRQ
+ */
+@@ -448,14 +448,14 @@ static int __init mc32_probe1(struct net
+ i=0;
+
+ base = inb(dev->base_addr);
+-
++
+ while(base == 0xFF)
+ {
+ i++;
+ if(i == 1000)
+ {
+ printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name);
+- err = -ENODEV;
++ err = -ENODEV;
+ goto err_exit_irq;
+ }
+ udelay(1000);
+@@ -470,15 +470,15 @@ static int __init mc32_probe1(struct net
+ base<0x0A?" test failure":"");
+ else
+ printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);
+- err = -ENODEV;
++ err = -ENODEV;
+ goto err_exit_irq;
+ }
+-
++
+ base=0;
+ for(i=0;i<4;i++)
+ {
+ int n=0;
+-
++
+ while(!(inb(dev->base_addr+2)&(1<<5)))
+ {
+ n++;
+@@ -493,31 +493,31 @@ static int __init mc32_probe1(struct net
+
+ base|=(inb(dev->base_addr)<<(8*i));
+ }
+-
++
+ lp->exec_box=isa_bus_to_virt(dev->mem_start+base);
+-
+- base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
+-
++
++ base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
++
+ lp->base = dev->mem_start+base;
+-
+- lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
++
++ lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
+ lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]);
+-
++
+ lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]);
+
+ /*
+ * Descriptor chains (card relative)
+ */
+-
++
+ lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
+ lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
+- lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
++ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
+ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
+
+ init_MUTEX_LOCKED(&lp->cmd_mutex);
+ init_completion(&lp->execution_cmd);
+ init_completion(&lp->xceiver_cmd);
+-
++
+ printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
+ dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
+
+@@ -543,12 +543,12 @@ err_exit_ports:
+ /**
+ * mc32_ready_poll - wait until we can feed it a command
+ * @dev: The device to wait for
+- *
++ *
+ * Wait until the card becomes ready to accept a command via the
+ * command register. This tells us nothing about the completion
+ * status of any pending commands and takes very little time at all.
+ */
+-
++
+ static inline void mc32_ready_poll(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+@@ -608,22 +608,22 @@ static int mc32_command_nowait(struct ne
+ *
+ * Sends exec commands in a user context. This permits us to wait around
+ * for the replies and also to wait for the command buffer to complete
+- * from a previous command before we execute our command. After our
++ * from a previous command before we execute our command. After our
+ * command completes we will attempt any pending multicast reload
+ * we blocked off by hogging the exec buffer.
+ *
+- * You feed the card a command, you wait, it interrupts you get a
++ * You feed the card a command, you wait, it interrupts you get a
+ * reply. All well and good. The complication arises because you use
+ * commands for filter list changes which come in at bh level from things
+ * like IPV6 group stuff.
+ */
+-
++
+ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ int ret = 0;
+-
++
+ down(&lp->cmd_mutex);
+
+ /*
+@@ -640,7 +640,7 @@ static int mc32_command(struct net_devic
+ outb(1<<6, ioaddr+HOST_CMD);
+
+ wait_for_completion(&lp->execution_cmd);
+-
++
+ if(lp->exec_box->mbox&(1<<13))
+ ret = -1;
+
+@@ -664,8 +664,8 @@ static int mc32_command(struct net_devic
+ * @dev: The 3c527 card to issue the command to
+ *
+ * This may be called from the interrupt state, where it is used
+- * to restart the rx ring if the card runs out of rx buffers.
+- *
++ * to restart the rx ring if the card runs out of rx buffers.
++ *
+ * We must first check if it's ok to (re)start the transceiver. See
+ * mc32_close for details.
+ */
+@@ -675,21 +675,21 @@ static void mc32_start_transceiver(struc
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+- /* Ignore RX overflow on device closure */
++ /* Ignore RX overflow on device closure */
+ if (lp->xceiver_desired_state==HALTED)
+- return;
++ return;
+
+ /* Give the card the offset to the post-EOL-bit RX descriptor */
+- mc32_ready_poll(dev);
++ mc32_ready_poll(dev);
+ lp->rx_box->mbox=0;
+- lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
+- outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
++ lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
++ outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
+
+- mc32_ready_poll(dev);
++ mc32_ready_poll(dev);
+ lp->tx_box->mbox=0;
+- outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
+-
+- /* We are not interrupted on start completion */
++ outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
++
++ /* We are not interrupted on start completion */
+ }
+
+
+@@ -703,21 +703,21 @@ static void mc32_start_transceiver(struc
+ *
+ * We then sleep until the card has notified us that both rx and
+ * tx have been suspended.
+- */
++ */
+
+-static void mc32_halt_transceiver(struct net_device *dev)
++static void mc32_halt_transceiver(struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+- mc32_ready_poll(dev);
++ mc32_ready_poll(dev);
+ lp->rx_box->mbox=0;
+- outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
++ outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
+ wait_for_completion(&lp->xceiver_cmd);
+
+- mc32_ready_poll(dev);
++ mc32_ready_poll(dev);
+ lp->tx_box->mbox=0;
+- outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
++ outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
+ wait_for_completion(&lp->xceiver_cmd);
+ }
+
+@@ -741,14 +741,14 @@ static void mc32_halt_transceiver(struct
+ * We then set the end-of-list bit for the last entry so that the
+ * card will know when it has run out of buffers.
+ */
+-
++
+ static int mc32_load_rx_ring(struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+ int i;
+ u16 rx_base;
+ volatile struct skb_header *p;
+-
++
+ rx_base=lp->rx_chain;
+
+ for(i=0; i<RX_RING_LEN; i++) {
+@@ -761,14 +761,14 @@ static int mc32_load_rx_ring(struct net_
+ skb_reserve(lp->rx_ring[i].skb, 18);
+
+ p=isa_bus_to_virt(lp->base+rx_base);
+-
++
+ p->control=0;
+ p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);
+ p->status=0;
+ p->length=1532;
+-
+- lp->rx_ring[i].p=p;
+- rx_base=p->next;
++
++ lp->rx_ring[i].p=p;
++ rx_base=p->next;
+ }
+
+ lp->rx_ring[i-1].p->control |= CONTROL_EOL;
+@@ -776,14 +776,14 @@ static int mc32_load_rx_ring(struct net_
+ lp->rx_ring_tail=0;
+
+ return 0;
+-}
++}
+
+
+ /**
+ * mc32_flush_rx_ring - free the ring of receive buffers
+ * @lp: Local data of 3c527 to flush the rx ring of
+ *
+- * Free the buffer for each ring slot. This may be called
++ * Free the buffer for each ring slot. This may be called
+ * before mc32_load_rx_ring(), eg. on error in mc32_open().
+ * Requires rx skb pointers to point to a valid skb, or NULL.
+ */
+@@ -791,16 +791,16 @@ static int mc32_load_rx_ring(struct net_
+ static void mc32_flush_rx_ring(struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+- int i;
++ int i;
+
+- for(i=0; i < RX_RING_LEN; i++)
+- {
++ for(i=0; i < RX_RING_LEN; i++)
++ {
+ if (lp->rx_ring[i].skb) {
+ dev_kfree_skb(lp->rx_ring[i].skb);
+ lp->rx_ring[i].skb = NULL;
+ }
+- lp->rx_ring[i].p=NULL;
+- }
++ lp->rx_ring[i].p=NULL;
++ }
+ }
+
+
+@@ -808,31 +808,31 @@ static void mc32_flush_rx_ring(struct ne
+ * mc32_load_tx_ring - load transmit ring
+ * @dev: The 3c527 card to issue the command to
+ *
+- * This sets up the host transmit data-structures.
++ * This sets up the host transmit data-structures.
+ *
+ * First, we obtain from the card it's current postion in the tx
+ * ring, so that we will know where to begin transmitting
+ * packets.
+- *
++ *
+ * Then, we read the 'next' pointers from the on-card tx ring into
+ * our tx_ring array to reduce slow shared-mem reads. Finally, we
+ * intitalise the tx house keeping variables.
+- *
+- */
++ *
++ */
+
+ static void mc32_load_tx_ring(struct net_device *dev)
+-{
++{
+ struct mc32_local *lp = netdev_priv(dev);
+ volatile struct skb_header *p;
+- int i;
++ int i;
+ u16 tx_base;
+
+- tx_base=lp->tx_box->data[0];
++ tx_base=lp->tx_box->data[0];
+
+ for(i=0 ; i<TX_RING_LEN ; i++)
+ {
+ p=isa_bus_to_virt(lp->base+tx_base);
+- lp->tx_ring[i].p=p;
++ lp->tx_ring[i].p=p;
+ lp->tx_ring[i].skb=NULL;
+
+ tx_base=p->next;
+@@ -841,10 +841,10 @@ static void mc32_load_tx_ring(struct net
+ /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */
+ /* see mc32_tx_ring */
+
+- atomic_set(&lp->tx_count, TX_RING_LEN-1);
+- atomic_set(&lp->tx_ring_head, 0);
+- lp->tx_ring_tail=0;
+-}
++ atomic_set(&lp->tx_count, TX_RING_LEN-1);
++ atomic_set(&lp->tx_ring_head, 0);
++ lp->tx_ring_tail=0;
++}
+
+
+ /**
+@@ -871,11 +871,11 @@ static void mc32_flush_tx_ring(struct ne
+ }
+ }
+
+- atomic_set(&lp->tx_count, 0);
+- atomic_set(&lp->tx_ring_head, 0);
++ atomic_set(&lp->tx_count, 0);
++ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
+ }
+-
++
+
+ /**
+ * mc32_open - handle 'up' of card
+@@ -909,7 +909,7 @@ static int mc32_open(struct net_device *
+ regs=inb(ioaddr+HOST_CTRL);
+ regs|=HOST_CTRL_INTE;
+ outb(regs, ioaddr+HOST_CTRL);
+-
++
+ /*
+ * Allow ourselves to issue commands
+ */
+@@ -924,52 +924,52 @@ static int mc32_open(struct net_device *
+ mc32_command(dev, 4, &one, 2);
+
+ /*
+- * Poke it to make sure it's really dead.
++ * Poke it to make sure it's really dead.
+ */
+
+- mc32_halt_transceiver(dev);
+- mc32_flush_tx_ring(dev);
++ mc32_halt_transceiver(dev);
++ mc32_flush_tx_ring(dev);
+
+- /*
+- * Ask card to set up on-card descriptors to our spec
+- */
++ /*
++ * Ask card to set up on-card descriptors to our spec
++ */
+
+- if(mc32_command(dev, 8, descnumbuffs, 4)) {
++ if(mc32_command(dev, 8, descnumbuffs, 4)) {
+ printk("%s: %s rejected our buffer configuration!\n",
+ dev->name, cardname);
+- mc32_close(dev);
+- return -ENOBUFS;
++ mc32_close(dev);
++ return -ENOBUFS;
+ }
+-
+- /* Report new configuration */
+- mc32_command(dev, 6, NULL, 0);
++
++ /* Report new configuration */
++ mc32_command(dev, 6, NULL, 0);
+
+ lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
+ lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
+- lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
++ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
+ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
+-
++
+ /* Set Network Address */
+ mc32_command(dev, 1, dev->dev_addr, 6);
+-
++
+ /* Set the filters */
+ mc32_set_multicast_list(dev);
+-
+- if (WORKAROUND_82586) {
++
++ if (WORKAROUND_82586) {
+ u16 zero_word=0;
+ mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
+ }
+
+ mc32_load_tx_ring(dev);
+-
+- if(mc32_load_rx_ring(dev))
++
++ if(mc32_load_rx_ring(dev))
+ {
+ mc32_close(dev);
+ return -ENOBUFS;
+ }
+
+ lp->xceiver_desired_state = RUNNING;
+-
++
+ /* And finally, set the ball rolling... */
+ mc32_start_transceiver(dev);
+
+@@ -1015,14 +1015,14 @@ static void mc32_timeout(struct net_devi
+ * after we've established a valid packet on the tx ring (and
+ * before we let the card "see" it, to prevent it racing with the
+ * irq handler).
+- *
++ *
+ */
+
+ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+ u32 head = atomic_read(&lp->tx_ring_head);
+-
++
+ volatile struct skb_header *p, *np;
+
+ netif_stop_queue(dev);
+@@ -1036,31 +1036,31 @@ static int mc32_send_packet(struct sk_bu
+ return 0;
+ }
+
+- atomic_dec(&lp->tx_count);
++ atomic_dec(&lp->tx_count);
+
+ /* P is the last sending/sent buffer as a pointer */
+ p=lp->tx_ring[head].p;
+-
++
+ head = next_tx(head);
+
+ /* NP is the buffer we will be loading */
+- np=lp->tx_ring[head].p;
+-
++ np=lp->tx_ring[head].p;
++
+ /* We will need this to flush the buffer out */
+ lp->tx_ring[head].skb=skb;
+
+- np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
++ np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ np->data = isa_virt_to_bus(skb->data);
+ np->status = 0;
+- np->control = CONTROL_EOP | CONTROL_EOL;
++ np->control = CONTROL_EOP | CONTROL_EOL;
+ wmb();
+-
++
+ /*
+ * The new frame has been setup; we can now
+ * let the interrupt handler and card "see" it
+ */
+
+- atomic_set(&lp->tx_ring_head, head);
++ atomic_set(&lp->tx_ring_head, head);
+ p->control &= ~CONTROL_EOL;
+
+ netif_wake_queue(dev);
+@@ -1072,13 +1072,13 @@ static int mc32_send_packet(struct sk_bu
+ * mc32_update_stats - pull off the on board statistics
+ * @dev: 3c527 to service
+ *
+- *
++ *
+ * Query and reset the on-card stats. There's the small possibility
+ * of a race here, which would result in an underestimation of
+ * actual errors. As such, we'd prefer to keep all our stats
+ * collection in software. As a rule, we do. However it can't be
+ * used for rx errors and collisions as, by default, the card discards
+- * bad rx packets.
++ * bad rx packets.
+ *
+ * Setting the SAV BP in the rx filter command supposedly
+ * stops this behaviour. However, testing shows that it only seems to
+@@ -1090,30 +1090,30 @@ static int mc32_send_packet(struct sk_bu
+ static void mc32_update_stats(struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+- volatile struct mc32_stats *st = lp->stats;
++ volatile struct mc32_stats *st = lp->stats;
+
+- u32 rx_errors=0;
+-
+- rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors;
++ u32 rx_errors=0;
++
++ rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors;
+ st->rx_crc_errors=0;
+- rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors;
+- st->rx_overrun_errors=0;
+- rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
++ rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors;
++ st->rx_overrun_errors=0;
++ rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
+ st->rx_alignment_errors=0;
+- rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors;
++ rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors;
+ st->rx_tooshort_errors=0;
+ rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
+- st->rx_outofresource_errors=0;
+- lp->net_stats.rx_errors=rx_errors;
+-
++ st->rx_outofresource_errors=0;
++ lp->net_stats.rx_errors=rx_errors;
++
+ /* Number of packets which saw one collision */
+ lp->net_stats.collisions+=st->dataC[10];
+- st->dataC[10]=0;
++ st->dataC[10]=0;
+
+- /* Number of packets which saw 2--15 collisions */
+- lp->net_stats.collisions+=st->dataC[11];
+- st->dataC[11]=0;
+-}
++ /* Number of packets which saw 2--15 collisions */
++ lp->net_stats.collisions+=st->dataC[11];
++ st->dataC[11]=0;
++}
+
+
+ /**
+@@ -1130,7 +1130,7 @@ static void mc32_update_stats(struct net
+ * For each completed packet, we will either copy it and pass it up
+ * the stack or, if the packet is near MTU sized, we allocate
+ * another buffer and flip the old one up the stack.
+- *
++ *
+ * We must succeed in keeping a buffer on the ring. If necessary we
+ * will toss a received packet rather than lose a ring entry. Once
+ * the first uncompleted descriptor is found, we move the
+@@ -1147,72 +1147,72 @@ static void mc32_rx_ring(struct net_devi
+ int x=0;
+
+ rx_old_tail = rx_ring_tail = lp->rx_ring_tail;
+-
++
+ do
+- {
+- p=lp->rx_ring[rx_ring_tail].p;
++ {
++ p=lp->rx_ring[rx_ring_tail].p;
+
+- if(!(p->status & (1<<7))) { /* Not COMPLETED */
++ if(!(p->status & (1<<7))) { /* Not COMPLETED */
+ break;
+- }
++ }
+ if(p->status & (1<<6)) /* COMPLETED_OK */
+- {
++ {
+
+ u16 length=p->length;
+- struct sk_buff *skb;
+- struct sk_buff *newskb;
++ struct sk_buff *skb;
++ struct sk_buff *newskb;
+
+ /* Try to save time by avoiding a copy on big frames */
+
+- if ((length > RX_COPYBREAK)
+- && ((newskb=dev_alloc_skb(1532)) != NULL))
+- {
++ if ((length > RX_COPYBREAK)
++ && ((newskb=dev_alloc_skb(1532)) != NULL))
++ {
+ skb=lp->rx_ring[rx_ring_tail].skb;
+ skb_put(skb, length);
+-
+- skb_reserve(newskb,18);
+- lp->rx_ring[rx_ring_tail].skb=newskb;
+- p->data=isa_virt_to_bus(newskb->data);
+- }
+- else
++
++ skb_reserve(newskb,18);
++ lp->rx_ring[rx_ring_tail].skb=newskb;
++ p->data=isa_virt_to_bus(newskb->data);
++ }
++ else
+ {
+- skb=dev_alloc_skb(length+2);
++ skb=dev_alloc_skb(length+2);
+
+ if(skb==NULL) {
+- lp->net_stats.rx_dropped++;
+- goto dropped;
++ lp->net_stats.rx_dropped++;
++ goto dropped;
+ }
+
+ skb_reserve(skb,2);
+ memcpy(skb_put(skb, length),
+ lp->rx_ring[rx_ring_tail].skb->data, length);
+ }
+-
+- skb->protocol=eth_type_trans(skb,dev);
+- skb->dev=dev;
++
++ skb->protocol=eth_type_trans(skb,dev);
++ skb->dev=dev;
+ dev->last_rx = jiffies;
+- lp->net_stats.rx_packets++;
+- lp->net_stats.rx_bytes += length;
++ lp->net_stats.rx_packets++;
++ lp->net_stats.rx_bytes += length;
+ netif_rx(skb);
+ }
+
+ dropped:
+- p->length = 1532;
++ p->length = 1532;
+ p->status = 0;
+-
+- rx_ring_tail=next_rx(rx_ring_tail);
++
++ rx_ring_tail=next_rx(rx_ring_tail);
+ }
+- while(x++<48);
++ while(x++<48);
+
+- /* If there was actually a frame to be processed, place the EOL bit */
+- /* at the descriptor prior to the one to be filled next */
++ /* If there was actually a frame to be processed, place the EOL bit */
++ /* at the descriptor prior to the one to be filled next */
+
+- if (rx_ring_tail != rx_old_tail)
+- {
+- lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
+- lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
++ if (rx_ring_tail != rx_old_tail)
++ {
++ lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
++ lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
+
+- lp->rx_ring_tail=rx_ring_tail;
++ lp->rx_ring_tail=rx_ring_tail;
+ }
+ }
+
+@@ -1228,10 +1228,10 @@ static void mc32_rx_ring(struct net_devi
+ * any errors. This continues until the transmit ring is emptied
+ * or we reach a descriptor that hasn't yet been processed by the
+ * card.
+- *
++ *
+ */
+
+-static void mc32_tx_ring(struct net_device *dev)
++static void mc32_tx_ring(struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+ volatile struct skb_header *np;
+@@ -1243,28 +1243,28 @@ static void mc32_tx_ring(struct net_devi
+ * condition with 'queue full'
+ */
+
+- while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
+- {
+- u16 t;
++ while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
++ {
++ u16 t;
+
+- t=next_tx(lp->tx_ring_tail);
+- np=lp->tx_ring[t].p;
++ t=next_tx(lp->tx_ring_tail);
++ np=lp->tx_ring[t].p;
+
+- if(!(np->status & (1<<7)))
++ if(!(np->status & (1<<7)))
+ {
+- /* Not COMPLETED */
+- break;
+- }
++ /* Not COMPLETED */
++ break;
++ }
+ lp->net_stats.tx_packets++;
+ if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
+ {
+- lp->net_stats.tx_errors++;
++ lp->net_stats.tx_errors++;
+
+ switch(np->status&0x0F)
+ {
+ case 1:
+ lp->net_stats.tx_aborted_errors++;
+- break; /* Max collisions */
++ break; /* Max collisions */
+ case 2:
+ lp->net_stats.tx_fifo_errors++;
+ break;
+@@ -1273,10 +1273,10 @@ static void mc32_tx_ring(struct net_devi
+ break;
+ case 4:
+ lp->net_stats.tx_window_errors++;
+- break; /* CTS Lost */
++ break; /* CTS Lost */
+ case 5:
+ lp->net_stats.tx_aborted_errors++;
+- break; /* Transmit timeout */
++ break; /* Transmit timeout */
+ }
+ }
+ /* Packets are sent in order - this is
+@@ -1288,10 +1288,10 @@ static void mc32_tx_ring(struct net_devi
+ atomic_inc(&lp->tx_count);
+ netif_wake_queue(dev);
+
+- lp->tx_ring_tail=t;
++ lp->tx_ring_tail=t;
+ }
+
+-}
++}
+
+
+ /**
+@@ -1316,19 +1316,14 @@ static void mc32_tx_ring(struct net_devi
+ *
+ */
+
+-static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t mc32_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct mc32_local *lp;
+ int ioaddr, status, boguscount = 0;
+ int rx_event = 0;
+- int tx_event = 0;
+-
+- if (dev == NULL) {
+- printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
+- return IRQ_NONE;
+- }
+-
++ int tx_event = 0;
++
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+
+@@ -1338,19 +1333,19 @@ static irqreturn_t mc32_interrupt(int ir
+ {
+ status=inb(ioaddr+HOST_CMD);
+
+-#ifdef DEBUG_IRQ
++#ifdef DEBUG_IRQ
+ printk("Status TX%d RX%d EX%d OV%d BC%d\n",
+ (status&7), (status>>3)&7, (status>>6)&1,
+ (status>>7)&1, boguscount);
+ #endif
+-
++
+ switch(status&7)
+ {
+ case 0:
+ break;
+ case 6: /* TX fail */
+ case 2: /* TX ok */
+- tx_event = 1;
++ tx_event = 1;
+ break;
+ case 3: /* Halt */
+ case 4: /* Abort */
+@@ -1365,7 +1360,7 @@ static irqreturn_t mc32_interrupt(int ir
+ case 0:
+ break;
+ case 2: /* RX */
+- rx_event=1;
++ rx_event=1;
+ break;
+ case 3: /* Halt */
+ case 4: /* Abort */
+@@ -1375,12 +1370,12 @@ static irqreturn_t mc32_interrupt(int ir
+ /* Out of RX buffers stat */
+ /* Must restart rx */
+ lp->net_stats.rx_dropped++;
+- mc32_rx_ring(dev);
+- mc32_start_transceiver(dev);
++ mc32_rx_ring(dev);
++ mc32_start_transceiver(dev);
+ break;
+ default:
+- printk("%s: strange rx ack %d\n",
+- dev->name, status&7);
++ printk("%s: strange rx ack %d\n",
++ dev->name, status&7);
+ }
+ status>>=3;
+ if(status&1)
+@@ -1389,10 +1384,10 @@ static irqreturn_t mc32_interrupt(int ir
+ * No thread is waiting: we need to tidy
+ * up ourself.
+ */
+-
++
+ if (lp->cmd_nonblocking) {
+ up(&lp->cmd_mutex);
+- if (lp->mc_reload_wait)
++ if (lp->mc_reload_wait)
+ mc32_reset_multicast_list(dev);
+ }
+ else complete(&lp->execution_cmd);
+@@ -1401,22 +1396,22 @@ static irqreturn_t mc32_interrupt(int ir
+ {
+ /*
+ * We get interrupted once per
+- * counter that is about to overflow.
++ * counter that is about to overflow.
+ */
+
+- mc32_update_stats(dev);
++ mc32_update_stats(dev);
+ }
+ }
+
+
+ /*
+- * Process the transmit and receive rings
++ * Process the transmit and receive rings
+ */
+
+- if(tx_event)
++ if(tx_event)
+ mc32_tx_ring(dev);
+-
+- if(rx_event)
++
++ if(rx_event)
+ mc32_rx_ring(dev);
+
+ return IRQ_HANDLED;
+@@ -1435,7 +1430,7 @@ static irqreturn_t mc32_interrupt(int ir
+ * driver. Otherwise, it is possible that the card may run out
+ * of receive buffers and restart the transceiver while we're
+ * trying to close it.
+- *
++ *
+ * We abort any receive and transmits going on and then wait until
+ * any pending exec commands have completed in other code threads.
+ * In theory we can't get here while that is true, in practice I am
+@@ -1452,7 +1447,7 @@ static int mc32_close(struct net_device
+
+ u8 regs;
+ u16 one=1;
+-
++
+ lp->xceiver_desired_state = HALTED;
+ netif_stop_queue(dev);
+
+@@ -1464,22 +1459,22 @@ static int mc32_close(struct net_device
+
+ /* Shut down the transceiver */
+
+- mc32_halt_transceiver(dev);
+-
++ mc32_halt_transceiver(dev);
++
+ /* Ensure we issue no more commands beyond this point */
+
+ down(&lp->cmd_mutex);
+-
+- /* Ok the card is now stopping */
+-
++
++ /* Ok the card is now stopping */
++
+ regs=inb(ioaddr+HOST_CTRL);
+ regs&=~HOST_CTRL_INTE;
+ outb(regs, ioaddr+HOST_CTRL);
+
+ mc32_flush_rx_ring(dev);
+ mc32_flush_tx_ring(dev);
+-
+- mc32_update_stats(dev);
++
++ mc32_update_stats(dev);
+
+ return 0;
+ }
+@@ -1490,15 +1485,15 @@ static int mc32_close(struct net_device
+ * @dev: The 3c527 card to handle
+ *
+ * We've collected all the stats we can in software already. Now
+- * it's time to update those kept on-card and return the lot.
+- *
++ * it's time to update those kept on-card and return the lot.
++ *
+ */
+
+ static struct net_device_stats *mc32_get_stats(struct net_device *dev)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+-
+- mc32_update_stats(dev);
++
++ mc32_update_stats(dev);
+ return &lp->net_stats;
+ }
+
+@@ -1506,7 +1501,7 @@ static struct net_device_stats *mc32_get
+ /**
+ * do_mc32_set_multicast_list - attempt to update multicasts
+ * @dev: 3c527 device to load the list on
+- * @retry: indicates this is not the first call.
++ * @retry: indicates this is not the first call.
+ *
+ *
+ * Actually set or clear the multicast filter for this adaptor. The
+@@ -1514,22 +1509,22 @@ static struct net_device_stats *mc32_get
+ * state as it may take multiple calls to get the command sequence
+ * completed. We just keep trying to schedule the loads until we
+ * manage to process them all.
+- *
++ *
+ * num_addrs == -1 Promiscuous mode, receive all packets
+- *
++ *
+ * num_addrs == 0 Normal mode, clear multicast list
+- *
+- * num_addrs > 0 Multicast mode, receive normal and MC packets,
+- * and do best-effort filtering.
+ *
+- * See mc32_update_stats() regards setting the SAV BP bit.
++ * num_addrs > 0 Multicast mode, receive normal and MC packets,
++ * and do best-effort filtering.
++ *
++ * See mc32_update_stats() regards setting the SAV BP bit.
+ *
+ */
+
+ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
+ {
+ struct mc32_local *lp = netdev_priv(dev);
+- u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
++ u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
+
+ if (dev->flags&IFF_PROMISC)
+ /* Enable promiscuous mode */
+@@ -1544,9 +1539,9 @@ static void do_mc32_set_multicast_list(s
+ unsigned char block[62];
+ unsigned char *bp;
+ struct dev_mc_list *dmc=dev->mc_list;
+-
++
+ int i;
+-
++
+ if(retry==0)
+ lp->mc_list_valid = 0;
+ if(!lp->mc_list_valid)
+@@ -1554,7 +1549,7 @@ static void do_mc32_set_multicast_list(s
+ block[1]=0;
+ block[0]=dev->mc_count;
+ bp=block+2;
+-
++
+ for(i=0;i<dev->mc_count;i++)
+ {
+ memcpy(bp, dmc->dmi_addr, 6);
+@@ -1569,12 +1564,12 @@ static void do_mc32_set_multicast_list(s
+ lp->mc_list_valid=1;
+ }
+ }
+-
+- if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
++
++ if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+ {
+ lp->mc_reload_wait = 1;
+- }
+- else {
++ }
++ else {
+ lp->mc_reload_wait = 0;
+ }
+ }
+@@ -1627,7 +1622,7 @@ static void netdev_set_msglevel(struct n
+ mc32_debug = level;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h
+index 53b5b07..75e28fe 100644
+--- a/drivers/net/3c527.h
++++ b/drivers/net/3c527.h
+@@ -5,7 +5,7 @@
+ /*
+ * Registers
+ */
+-
++
+ #define HOST_CMD 0
+ #define HOST_CMD_START_RX (1<<3)
+ #define HOST_CMD_SUSPND_RX (3<<3)
+@@ -63,7 +63,7 @@ struct mc32_stats
+ u32 tx_underrun_errors;
+ u32 tx_cts_errors;
+ u32 tx_timeout_errors;
+-
++
+ /* various cruft */
+ u32 dataA[6];
+ u16 dataB[5];
+diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
+index 80e8ca0..80bdcf8 100644
+--- a/drivers/net/3c59x.c
++++ b/drivers/net/3c59x.c
+@@ -717,8 +717,8 @@ static int vortex_start_xmit(struct sk_b
+ static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int vortex_rx(struct net_device *dev);
+ static int boomerang_rx(struct net_device *dev);
+-static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t vortex_interrupt(int irq, void *dev_id);
++static irqreturn_t boomerang_interrupt(int irq, void *dev_id);
+ static int vortex_close(struct net_device *dev);
+ static void dump_tx_ring(struct net_device *dev);
+ static void update_stats(void __iomem *ioaddr, struct net_device *dev);
+@@ -729,7 +729,7 @@ static int vortex_ioctl(struct net_devic
+ #endif
+ static void vortex_tx_timeout(struct net_device *dev);
+ static void acpi_set_WOL(struct net_device *dev);
+-static struct ethtool_ops vortex_ethtool_ops;
++static const struct ethtool_ops vortex_ethtool_ops;
+ static void set_8021q_mode(struct net_device *dev, int enable);
+
+ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
+@@ -794,9 +794,9 @@ static void poll_vortex(struct net_devic
+ unsigned long flags;
+ local_save_flags(flags);
+ local_irq_disable();
+- (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL);
++ (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
+ local_irq_restore(flags);
+-}
++}
+ #endif
+
+ #ifdef CONFIG_PM
+@@ -851,6 +851,7 @@ static struct eisa_device_id vortex_eisa
+ { "TCM5970", CH_3C597 },
+ { "" }
+ };
++MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
+
+ static int vortex_eisa_probe(struct device *device);
+ static int vortex_eisa_remove(struct device *device);
+@@ -904,7 +905,7 @@ static int vortex_eisa_remove(struct dev
+
+ vp = netdev_priv(dev);
+ ioaddr = vp->ioaddr;
+-
++
+ unregister_netdev(dev);
+ iowrite16(TotalReset|0x14, ioaddr + EL3_CMD);
+ release_region(dev->base_addr, VORTEX_TOTAL_SIZE);
+@@ -935,7 +936,7 @@ static int __init vortex_eisa_init(void)
+ eisa_found = 1;
+ }
+ #endif
+-
++
+ /* Special code to work-around the Compaq PCI BIOS32 problem. */
+ if (compaq_ioaddr) {
+ vortex_probe1(NULL, ioport_map(compaq_ioaddr, VORTEX_TOTAL_SIZE),
+@@ -953,7 +954,7 @@ static int __devinit vortex_init_one(str
+ struct vortex_chip_info *vci;
+ void __iomem *ioaddr;
+
+- /* wake up and enable device */
++ /* wake up and enable device */
+ rc = pci_enable_device(pdev);
+ if (rc < 0)
+ goto out;
+@@ -1089,7 +1090,7 @@ static int __devinit vortex_probe1(struc
+ if (request_region(dev->base_addr, vci->io_size, print_name) != NULL)
+ vp->must_free_region = 1;
+
+- /* enable bus-mastering if necessary */
++ /* enable bus-mastering if necessary */
+ if (vci->flags & PCI_USES_MASTER)
+ pci_set_master(pdev);
+
+@@ -1131,7 +1132,7 @@ static int __devinit vortex_probe1(struc
+ vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
+
+ /* if we are a PCI driver, we store info in pdev->driver_data
+- * instead of a module list */
++ * instead of a module list */
+ if (pdev)
+ pci_set_drvdata(pdev, dev);
+ if (edev)
+@@ -1393,7 +1394,7 @@ static int __devinit vortex_probe1(struc
+ dev->tx_timeout = vortex_tx_timeout;
+ dev->watchdog_timeo = (watchdog * HZ) / 1000;
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+- dev->poll_controller = poll_vortex;
++ dev->poll_controller = poll_vortex;
+ #endif
+ if (pdev) {
+ vp->pm_state_valid = 1;
+@@ -1848,9 +1849,9 @@ static void vortex_tx_timeout(struct net
+ unsigned long flags;
+ local_irq_save(flags);
+ if (vp->full_bus_master_tx)
+- boomerang_interrupt(dev->irq, dev, NULL);
++ boomerang_interrupt(dev->irq, dev);
+ else
+- vortex_interrupt(dev->irq, dev, NULL);
++ vortex_interrupt(dev->irq, dev);
+ local_irq_restore(flags);
+ }
+ }
+@@ -1875,11 +1876,11 @@ static void vortex_tx_timeout(struct net
+ vp->stats.tx_dropped++;
+ netif_wake_queue(dev);
+ }
+-
++
+ /* Issue Tx Enable */
+ iowrite16(TxEnable, ioaddr + EL3_CMD);
+ dev->trans_start = jiffies;
+-
++
+ /* Switch to register set 7 for normal use. */
+ EL3WINDOW(7);
+ }
+@@ -2077,7 +2078,7 @@ boomerang_start_xmit(struct sk_buff *skb
+
+ vp->tx_ring[entry].next = 0;
+ #if DO_ZEROCOPY
+- if (skb->ip_summed != CHECKSUM_HW)
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
+ else
+ vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum);
+@@ -2148,7 +2149,7 @@ boomerang_start_xmit(struct sk_buff *skb
+ */
+
+ static irqreturn_t
+-vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++vortex_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct vortex_private *vp = netdev_priv(dev);
+@@ -2253,7 +2254,7 @@ handler_exit:
+ */
+
+ static irqreturn_t
+-boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++boomerang_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct vortex_private *vp = netdev_priv(dev);
+@@ -2316,10 +2317,10 @@ boomerang_interrupt(int irq, void *dev_i
+ if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0)
+ break; /* It still hasn't been processed. */
+ #endif
+-
++
+ if (vp->tx_skbuff[entry]) {
+ struct sk_buff *skb = vp->tx_skbuff[entry];
+-#if DO_ZEROCOPY
++#if DO_ZEROCOPY
+ int i;
+ for (i=0; i<=skb_shinfo(skb)->nr_frags; i++)
+ pci_unmap_single(VORTEX_PCI(vp),
+@@ -2633,7 +2634,7 @@ vortex_close(struct net_device *dev)
+ "not using them!\n", dev->name);
+ }
+ #endif
+-
++
+ free_irq(dev->irq, dev);
+
+ if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+@@ -2675,7 +2676,7 @@ dump_tx_ring(struct net_device *dev)
+ if (vortex_debug > 0) {
+ struct vortex_private *vp = netdev_priv(dev);
+ void __iomem *ioaddr = vp->ioaddr;
+-
++
+ if (vp->full_bus_master_tx) {
+ int i;
+ int stalled = ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */
+@@ -2873,7 +2874,7 @@ static void vortex_get_drvinfo(struct ne
+ }
+ }
+
+-static struct ethtool_ops vortex_ethtool_ops = {
++static const struct ethtool_ops vortex_ethtool_ops = {
+ .get_drvinfo = vortex_get_drvinfo,
+ .get_strings = vortex_get_strings,
+ .get_msglevel = vortex_get_msglevel,
+@@ -2928,7 +2929,7 @@ static void set_rx_mode(struct net_devic
+ int new_mode;
+
+ if (dev->flags & IFF_PROMISC) {
+- if (vortex_debug > 0)
++ if (vortex_debug > 3)
+ printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
+ new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
+ } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
+@@ -3169,7 +3170,7 @@ static int __init vortex_init(void)
+ {
+ int pci_rc, eisa_rc;
+
+- pci_rc = pci_module_init(&vortex_driver);
++ pci_rc = pci_register_driver(&vortex_driver);
+ eisa_rc = vortex_eisa_init();
+
+ if (pci_rc == 0)
+@@ -3190,7 +3191,7 @@ static void __exit vortex_eisa_cleanup(v
+ /* Take care of the EISA devices */
+ eisa_driver_unregister(&vortex_eisa_driver);
+ #endif
+-
++
+ if (compaq_net_device) {
+ vp = compaq_net_device->priv;
+ ioaddr = ioport_map(compaq_net_device->base_addr,
+diff --git a/drivers/net/7990.c b/drivers/net/7990.c
+index 86633c5..7733697 100644
+--- a/drivers/net/7990.c
++++ b/drivers/net/7990.c
+@@ -1,7 +1,7 @@
+-/*
+- * 7990.c -- LANCE ethernet IC generic routines.
++/*
++ * 7990.c -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+- * drivers that are common because they all use the AMD 7990 LANCE
++ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell at chiark.greenend.org.uk>
+@@ -9,7 +9,7 @@
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ * NB: this was made easy by the fact that Jes Sorensen had cleaned up
+- * most of a2025 and sunlance with the aim of merging them, so the
++ * most of a2025 and sunlance with the aim of merging them, so the
+ * common code was pretty obvious.
+ */
+ #include <linux/crc32.h>
+@@ -109,10 +109,10 @@ do { \
+ ib->btx_ring[t].length,\
+ ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
+ }\
+-} while (0)
++} while (0)
+ #else
+ #define PRINT_RINGS()
+-#endif
++#endif
+
+ /* Load the CSR registers. The LANCE has to be STOPped when we do this! */
+ static void load_csrs (struct lance_private *lp)
+@@ -157,7 +157,7 @@ static void lance_init_ring (struct net_
+ * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
+ * However, the datasheet says that the BSWAP bit doesn't affect
+ * the init block, so surely it should be low byte first for
+- * everybody? Um.]
++ * everybody? Um.]
+ * We could define the ib->physaddr as three 16bit values and
+ * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
+ */
+@@ -171,11 +171,11 @@ static void lance_init_ring (struct net_
+ #else
+ for (i=0; i<6; i++)
+ ib->phys_addr[i] = dev->dev_addr[i];
+-#endif
++#endif
+
+ if (DEBUG_IRING)
+ printk ("TX rings:\n");
+-
++
+ lp->tx_full = 0;
+ /* Setup the Tx ring entries */
+ for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
+@@ -185,7 +185,7 @@ static void lance_init_ring (struct net_
+ ib->btx_ring [i].tmd1_bits = 0;
+ ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */
+ ib->btx_ring [i].misc = 0;
+- if (DEBUG_IRING)
++ if (DEBUG_IRING)
+ printk ("%d: 0x%8.8x\n", i, leptr);
+ }
+
+@@ -206,14 +206,14 @@ static void lance_init_ring (struct net_
+ }
+
+ /* Setup the initialization block */
+-
++
+ /* Setup rx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->brx_ring);
+ ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
+ ib->rx_ptr = leptr;
+ if (DEBUG_IRING)
+ printk ("RX ptr: %8.8x\n", leptr);
+-
++
+ /* Setup tx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->btx_ring);
+ ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
+@@ -256,7 +256,7 @@ static int lance_reset (struct net_devic
+ {
+ struct lance_private *lp = netdev_priv(dev);
+ int status;
+-
++
+ /* Stop the lance */
+ WRITERAP(lp, LE_CSR0);
+ WRITERDP(lp, LE_C0_STOP);
+@@ -297,7 +297,7 @@ static int lance_rx (struct net_device *
+ #endif
+ #ifdef CONFIG_HP300
+ blinken_leds(0x40, 0);
+-#endif
++#endif
+ WRITERDP(lp, LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */
+ for (rd = &ib->brx_ring [lp->rx_new]; /* For each Rx ring we own... */
+ !((bits = rd->rmd1_bits) & LE_R1_OWN);
+@@ -330,7 +330,7 @@ static int lance_rx (struct net_device *
+ lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+ return 0;
+ }
+-
++
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align */
+ skb_put (skb, len); /* make room */
+@@ -374,10 +374,10 @@ static int lance_tx (struct net_device *
+ /* If we hit a packet not owned by us, stop */
+ if (td->tmd1_bits & LE_T1_OWN)
+ break;
+-
++
+ if (td->tmd1_bits & LE_T1_ERR) {
+ status = td->misc;
+-
++
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+@@ -429,7 +429,7 @@ static int lance_tx (struct net_device *
+
+ lp->stats.tx_packets++;
+ }
+-
++
+ j = (j + 1) & lp->tx_ring_mod_mask;
+ }
+ lp->tx_old = j;
+@@ -438,7 +438,7 @@ static int lance_tx (struct net_device *
+ }
+
+ static irqreturn_t
+-lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
++lance_interrupt (int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct lance_private *lp = netdev_priv(dev);
+@@ -450,7 +450,7 @@ lance_interrupt (int irq, void *dev_id,
+ csr0 = READRDP(lp);
+
+ PRINT_RINGS();
+-
++
+ if (!(csr0 & LE_C0_INTR)) { /* Check if any interrupt has */
+ spin_unlock (&lp->devlock);
+ return IRQ_NONE; /* been generated by the Lance. */
+@@ -476,7 +476,7 @@ lance_interrupt (int irq, void *dev_id,
+ if (csr0 & LE_C0_MISS)
+ lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & LE_C0_MERR) {
+- printk("%s: Bus master arbitration failure, status %4.4x.\n",
++ printk("%s: Bus master arbitration failure, status %4.4x.\n",
+ dev->name, csr0);
+ /* Restart the chip. */
+ WRITERDP(lp, LE_C0_STRT);
+@@ -486,7 +486,7 @@ lance_interrupt (int irq, void *dev_id,
+ lp->tx_full = 0;
+ netif_wake_queue (dev);
+ }
+-
++
+ WRITERAP(lp, LE_CSR0);
+ WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+
+@@ -498,7 +498,7 @@ int lance_open (struct net_device *dev)
+ {
+ struct lance_private *lp = netdev_priv(dev);
+ int res;
+-
++
+ /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
+ if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+ return -EAGAIN;
+@@ -513,7 +513,7 @@ int lance_open (struct net_device *dev)
+ int lance_close (struct net_device *dev)
+ {
+ struct lance_private *lp = netdev_priv(dev);
+-
++
+ netif_stop_queue (dev);
+
+ /* Stop the LANCE */
+@@ -553,7 +553,7 @@ int lance_start_xmit (struct sk_buff *sk
+ /* dump the packet */
+ {
+ int i;
+-
++
+ for (i = 0; i < 64; i++) {
+ if ((i % 16) == 0)
+ printk ("\n");
+@@ -565,11 +565,11 @@ int lance_start_xmit (struct sk_buff *sk
+ entry = lp->tx_new & lp->tx_ring_mod_mask;
+ ib->btx_ring [entry].length = (-len) | 0xf000;
+ ib->btx_ring [entry].misc = 0;
+-
++
+ if (skb->len < ETH_ZLEN)
+ memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
+ memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+-
++
+ /* Now, give the packet to the lance */
+ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+ lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+@@ -579,7 +579,7 @@ int lance_start_xmit (struct sk_buff *sk
+ WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+-
++
+ spin_lock_irqsave (&lp->devlock, flags);
+ if (TX_BUFFS_AVAIL)
+ netif_start_queue (dev);
+@@ -607,9 +607,9 @@ static void lance_load_multicast (struct
+ char *addrs;
+ int i;
+ u32 crc;
+-
++
+ /* set all multicast bits */
+- if (dev->flags & IFF_ALLMULTI){
++ if (dev->flags & IFF_ALLMULTI){
+ ib->filter [0] = 0xffffffff;
+ ib->filter [1] = 0xffffffff;
+ return;
+@@ -626,7 +626,7 @@ static void lance_load_multicast (struct
+ /* multicast address? */
+ if (!(*addrs & 1))
+ continue;
+-
++
+ crc = ether_crc_le(6, addrs);
+ crc = crc >> 26;
+ mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+@@ -674,7 +674,7 @@ void lance_poll(struct net_device *dev)
+ WRITERAP(lp, LE_CSR0);
+ WRITERDP(lp, LE_C0_STRT);
+ spin_unlock (&lp->devlock);
+- lance_interrupt(dev->irq, dev, NULL);
++ lance_interrupt(dev->irq, dev);
+ }
+ #endif
+
+diff --git a/drivers/net/7990.h b/drivers/net/7990.h
+index 31ae509..b1212b5 100644
+--- a/drivers/net/7990.h
++++ b/drivers/net/7990.h
+@@ -1,9 +1,9 @@
+-/*
++/*
+ * 7990.h -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+- *
++ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell at chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+@@ -55,7 +55,7 @@ struct lance_rx_desc {
+ */
+ volatile unsigned short mblength; /* Actual number of bytes received */
+ };
+-
++
+ /* Ditto for TMD: */
+ struct lance_tx_desc {
+ volatile unsigned short tmd0; /* low address of packet */
+@@ -80,8 +80,8 @@ struct lance_init_block {
+ volatile unsigned short rx_len; /* receive len and high addr */
+ volatile unsigned short tx_ptr; /* transmit descriptor addr */
+ volatile unsigned short tx_len; /* transmit len and high addr */
+-
+- /* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
++
++ /* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
+ * This will be true if this whole struct is 8-byte aligned.
+ */
+ volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
+@@ -104,21 +104,21 @@ struct lance_private
+ unsigned long base;
+ volatile struct lance_init_block *init_block; /* CPU address of RAM */
+ volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
+-
++
+ int rx_new, tx_new;
+ int rx_old, tx_old;
+-
++
+ int lance_log_rx_bufs, lance_log_tx_bufs;
+ int rx_ring_mod_mask, tx_ring_mod_mask;
+-
++
+ struct net_device_stats stats;
+ int tpe; /* TPE is selected */
+ int auto_select; /* cable-selection is by carrier */
+ unsigned short busmaster_regval;
+
+ unsigned int irq; /* IRQ to register */
+-
+- /* This is because the HP LANCE is disgusting and you have to check
++
++ /* This is because the HP LANCE is disgusting and you have to check
+ * a DIO-specific register every time you read/write the LANCE regs :-<
+ * [could we get away with making these some sort of macro?]
+ */
+@@ -148,7 +148,7 @@ struct lance_private
+ #define LE_C0_RINT 0x0400 /* Receive Interrupt */
+ #define LE_C0_TINT 0x0200 /* Transmit Interrupt */
+ #define LE_C0_IDON 0x0100 /* Initialization Done */
+-#define LE_C0_INTR 0x0080 /* Interrupt Flag
++#define LE_C0_INTR 0x0080 /* Interrupt Flag
+ = BABL | MISS | MERR | RINT | TINT | IDON */
+ #define LE_C0_INEA 0x0040 /* Interrupt Enable */
+ #define LE_C0_RXON 0x0020 /* Receive On */
+@@ -185,7 +185,7 @@ struct lance_private
+ #define LE_MO_PSEL1 0x0100 /* port selection bit1 */
+ #define LE_MO_PSEL0 0x0080 /* port selection bit0 */
+ /* and this one is from the C-LANCE data sheet... */
+-#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
++#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
+ (C-LANCE, not original LANCE) */
+ #define LE_MO_INTL 0x0040 /* Internal Loopback */
+ #define LE_MO_DRTY 0x0020 /* Disable Retry */
+diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
+index 1428bb7..458dd9f 100644
+--- a/drivers/net/8139cp.c
++++ b/drivers/net/8139cp.c
+@@ -48,7 +48,7 @@
+ */
+
+ #define DRV_NAME "8139cp"
+-#define DRV_VERSION "1.2"
++#define DRV_VERSION "1.3"
+ #define DRV_RELDATE "Mar 22, 2004"
+
+
+@@ -314,12 +314,6 @@ struct cp_desc {
+ u64 addr;
+ };
+
+-struct ring_info {
+- struct sk_buff *skb;
+- dma_addr_t mapping;
+- u32 len;
+-};
+-
+ struct cp_dma_stats {
+ u64 tx_ok;
+ u64 rx_ok;
+@@ -353,23 +347,23 @@ struct cp_private {
+ struct net_device_stats net_stats;
+ struct cp_extra_stats cp_stats;
+
+- unsigned rx_tail ____cacheline_aligned;
++ unsigned rx_head ____cacheline_aligned;
++ unsigned rx_tail;
+ struct cp_desc *rx_ring;
+- struct ring_info rx_skb[CP_RX_RING_SIZE];
+- unsigned rx_buf_sz;
++ struct sk_buff *rx_skb[CP_RX_RING_SIZE];
+
+ unsigned tx_head ____cacheline_aligned;
+ unsigned tx_tail;
+-
+ struct cp_desc *tx_ring;
+- struct ring_info tx_skb[CP_TX_RING_SIZE];
+- dma_addr_t ring_dma;
++ struct sk_buff *tx_skb[CP_TX_RING_SIZE];
++
++ unsigned rx_buf_sz;
++ unsigned wol_enabled : 1; /* Is Wake-on-LAN enabled? */
+
+ #if CP_VLAN_TAG_USED
+ struct vlan_group *vlgrp;
+ #endif
+-
+- unsigned int wol_enabled : 1; /* Is Wake-on-LAN enabled? */
++ dma_addr_t ring_dma;
+
+ struct mii_if_info mii_if;
+ };
+@@ -407,10 +401,8 @@ static int cp_set_eeprom(struct net_devi
+ struct ethtool_eeprom *eeprom, u8 *data);
+
+ static struct pci_device_id cp_pci_tbl[] = {
+- { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+- { PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), },
++ { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), },
+ { },
+ };
+ MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
+@@ -542,7 +534,7 @@ rx_status_loop:
+ struct cp_desc *desc;
+ unsigned buflen;
+
+- skb = cp->rx_skb[rx_tail].skb;
++ skb = cp->rx_skb[rx_tail];
+ BUG_ON(!skb);
+
+ desc = &cp->rx_ring[rx_tail];
+@@ -551,7 +543,7 @@ rx_status_loop:
+ break;
+
+ len = (status & 0x1fff) - 4;
+- mapping = cp->rx_skb[rx_tail].mapping;
++ mapping = le64_to_cpu(desc->addr);
+
+ if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {
+ /* we don't support incoming fragmented frames.
+@@ -572,7 +564,7 @@ rx_status_loop:
+
+ if (netif_msg_rx_status(cp))
+ printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
+- cp->dev->name, rx_tail, status, len);
++ dev->name, rx_tail, status, len);
+
+ buflen = cp->rx_buf_sz + RX_OFFSET;
+ new_skb = dev_alloc_skb (buflen);
+@@ -582,7 +574,7 @@ rx_status_loop:
+ }
+
+ skb_reserve(new_skb, RX_OFFSET);
+- new_skb->dev = cp->dev;
++ new_skb->dev = dev;
+
+ pci_unmap_single(cp->pdev, mapping,
+ buflen, PCI_DMA_FROMDEVICE);
+@@ -595,11 +587,9 @@ rx_status_loop:
+
+ skb_put(skb, len);
+
+- mapping =
+- cp->rx_skb[rx_tail].mapping =
+- pci_map_single(cp->pdev, new_skb->data,
+- buflen, PCI_DMA_FROMDEVICE);
+- cp->rx_skb[rx_tail].skb = new_skb;
++ mapping = pci_map_single(cp->pdev, new_skb->data, buflen,
++ PCI_DMA_FROMDEVICE);
++ cp->rx_skb[rx_tail] = new_skb;
+
+ cp_rx_skb(cp, skb, desc);
+ rx++;
+@@ -641,8 +631,7 @@ rx_next:
+ return 1; /* not done */
+ }
+
+-static irqreturn_t
+-cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t cp_interrupt (int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct cp_private *cp;
+@@ -706,7 +695,7 @@ cp_interrupt (int irq, void *dev_instanc
+ static void cp_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- cp_interrupt(dev->irq, dev, NULL);
++ cp_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -717,19 +706,21 @@ static void cp_tx (struct cp_private *cp
+ unsigned tx_tail = cp->tx_tail;
+
+ while (tx_tail != tx_head) {
++ struct cp_desc *txd = cp->tx_ring + tx_tail;
+ struct sk_buff *skb;
+ u32 status;
+
+ rmb();
+- status = le32_to_cpu(cp->tx_ring[tx_tail].opts1);
++ status = le32_to_cpu(txd->opts1);
+ if (status & DescOwn)
+ break;
+
+- skb = cp->tx_skb[tx_tail].skb;
++ skb = cp->tx_skb[tx_tail];
+ BUG_ON(!skb);
+
+- pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
+- cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE);
++ pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr),
++ le32_to_cpu(txd->opts1) & 0xffff,
++ PCI_DMA_TODEVICE);
+
+ if (status & LastFrag) {
+ if (status & (TxError | TxFIFOUnder)) {
+@@ -756,7 +747,7 @@ static void cp_tx (struct cp_private *cp
+ dev_kfree_skb_irq(skb);
+ }
+
+- cp->tx_skb[tx_tail].skb = NULL;
++ cp->tx_skb[tx_tail] = NULL;
+
+ tx_tail = NEXT_TX(tx_tail);
+ }
+@@ -813,7 +804,7 @@ static int cp_start_xmit (struct sk_buff
+
+ if (mss)
+ flags |= LargeSend | ((mss & MSSMask) << MSSShift);
+- else if (skb->ip_summed == CHECKSUM_HW) {
++ else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ const struct iphdr *ip = skb->nh.iph;
+ if (ip->protocol == IPPROTO_TCP)
+ flags |= IPCS | TCPCS;
+@@ -826,9 +817,7 @@ static int cp_start_xmit (struct sk_buff
+ txd->opts1 = cpu_to_le32(flags);
+ wmb();
+
+- cp->tx_skb[entry].skb = skb;
+- cp->tx_skb[entry].mapping = mapping;
+- cp->tx_skb[entry].len = len;
++ cp->tx_skb[entry] = skb;
+ entry = NEXT_TX(entry);
+ } else {
+ struct cp_desc *txd;
+@@ -844,9 +833,7 @@ static int cp_start_xmit (struct sk_buff
+ first_len = skb_headlen(skb);
+ first_mapping = pci_map_single(cp->pdev, skb->data,
+ first_len, PCI_DMA_TODEVICE);
+- cp->tx_skb[entry].skb = skb;
+- cp->tx_skb[entry].mapping = first_mapping;
+- cp->tx_skb[entry].len = first_len;
++ cp->tx_skb[entry] = skb;
+ entry = NEXT_TX(entry);
+
+ for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+@@ -867,7 +854,7 @@ static int cp_start_xmit (struct sk_buff
+ if (mss)
+ ctrl |= LargeSend |
+ ((mss & MSSMask) << MSSShift);
+- else if (skb->ip_summed == CHECKSUM_HW) {
++ else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (ip->protocol == IPPROTO_TCP)
+ ctrl |= IPCS | TCPCS;
+ else if (ip->protocol == IPPROTO_UDP)
+@@ -887,9 +874,7 @@ static int cp_start_xmit (struct sk_buff
+ txd->opts1 = cpu_to_le32(ctrl);
+ wmb();
+
+- cp->tx_skb[entry].skb = skb;
+- cp->tx_skb[entry].mapping = mapping;
+- cp->tx_skb[entry].len = len;
++ cp->tx_skb[entry] = skb;
+ entry = NEXT_TX(entry);
+ }
+
+@@ -898,7 +883,7 @@ static int cp_start_xmit (struct sk_buff
+ txd->addr = cpu_to_le64(first_mapping);
+ wmb();
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (ip->protocol == IPPROTO_TCP)
+ txd->opts1 = cpu_to_le32(first_eor | first_len |
+ FirstFrag | DescOwn |
+@@ -942,8 +927,6 @@ static void __cp_set_rx_mode (struct net
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+@@ -1091,6 +1074,7 @@ static int cp_refill_rx (struct cp_priva
+
+ for (i = 0; i < CP_RX_RING_SIZE; i++) {
+ struct sk_buff *skb;
++ dma_addr_t mapping;
+
+ skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET);
+ if (!skb)
+@@ -1099,12 +1083,12 @@ static int cp_refill_rx (struct cp_priva
+ skb->dev = cp->dev;
+ skb_reserve(skb, RX_OFFSET);
+
+- cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
+- skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+- cp->rx_skb[i].skb = skb;
++ mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz,
++ PCI_DMA_FROMDEVICE);
++ cp->rx_skb[i] = skb;
+
+ cp->rx_ring[i].opts2 = 0;
+- cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
++ cp->rx_ring[i].addr = cpu_to_le64(mapping);
+ if (i == (CP_RX_RING_SIZE - 1))
+ cp->rx_ring[i].opts1 =
+ cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
+@@ -1152,23 +1136,27 @@ static int cp_alloc_rings (struct cp_pri
+
+ static void cp_clean_rings (struct cp_private *cp)
+ {
++ struct cp_desc *desc;
+ unsigned i;
+
+ for (i = 0; i < CP_RX_RING_SIZE; i++) {
+- if (cp->rx_skb[i].skb) {
+- pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping,
++ if (cp->rx_skb[i]) {
++ desc = cp->rx_ring + i;
++ pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+ cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+- dev_kfree_skb(cp->rx_skb[i].skb);
++ dev_kfree_skb(cp->rx_skb[i]);
+ }
+ }
+
+ for (i = 0; i < CP_TX_RING_SIZE; i++) {
+- if (cp->tx_skb[i].skb) {
+- struct sk_buff *skb = cp->tx_skb[i].skb;
+-
+- pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping,
+- cp->tx_skb[i].len, PCI_DMA_TODEVICE);
+- if (le32_to_cpu(cp->tx_ring[i].opts1) & LastFrag)
++ if (cp->tx_skb[i]) {
++ struct sk_buff *skb = cp->tx_skb[i];
++
++ desc = cp->tx_ring + i;
++ pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
++ le32_to_cpu(desc->opts1) & 0xffff,
++ PCI_DMA_TODEVICE);
++ if (le32_to_cpu(desc->opts1) & LastFrag)
+ dev_kfree_skb(skb);
+ cp->net_stats.tx_dropped++;
+ }
+@@ -1177,8 +1165,8 @@ static void cp_clean_rings (struct cp_pr
+ memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+ memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+
+- memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE);
+- memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);
++ memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
++ memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
+ }
+
+ static void cp_free_rings (struct cp_private *cp)
+@@ -1557,7 +1545,7 @@ static void cp_get_ethtool_stats (struct
+ pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
+ }
+
+-static struct ethtool_ops cp_ethtool_ops = {
++static const struct ethtool_ops cp_ethtool_ops = {
+ .get_drvinfo = cp_get_drvinfo,
+ .get_regs_len = cp_get_regs_len,
+ .get_stats_count = cp_get_stats_count,
+@@ -2010,7 +1998,6 @@ static void cp_remove_one (struct pci_de
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct cp_private *cp = netdev_priv(dev);
+
+- BUG_ON(!dev);
+ unregister_netdev(dev);
+ iounmap(cp->regs);
+ if (cp->wol_enabled)
+@@ -2025,14 +2012,12 @@ static void cp_remove_one (struct pci_de
+ #ifdef CONFIG_PM
+ static int cp_suspend (struct pci_dev *pdev, pm_message_t state)
+ {
+- struct net_device *dev;
+- struct cp_private *cp;
++ struct net_device *dev = pci_get_drvdata(pdev);
++ struct cp_private *cp = netdev_priv(dev);
+ unsigned long flags;
+
+- dev = pci_get_drvdata (pdev);
+- cp = netdev_priv(dev);
+-
+- if (!dev || !netif_running (dev)) return 0;
++ if (!netif_running(dev))
++ return 0;
+
+ netif_device_detach (dev);
+ netif_stop_queue (dev);
+@@ -2098,7 +2083,7 @@ static int __init cp_init (void)
+ #ifdef MODULE
+ printk("%s", version);
+ #endif
+- return pci_module_init (&cp_driver);
++ return pci_register_driver(&cp_driver);
+ }
+
+ static void __exit cp_exit (void)
+diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
+index e4f4eaf..d02ed51 100644
+--- a/drivers/net/8139too.c
++++ b/drivers/net/8139too.c
+@@ -90,7 +90,7 @@
+ */
+
+ #define DRV_NAME "8139too"
+-#define DRV_VERSION "0.9.27"
++#define DRV_VERSION "0.9.28"
+
+
+ #include <linux/module.h>
+@@ -629,8 +629,7 @@ static int rtl8139_poll(struct net_devic
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ static void rtl8139_poll_controller(struct net_device *dev);
+ #endif
+-static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
+- struct pt_regs *regs);
++static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
+ static int rtl8139_close (struct net_device *dev);
+ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+@@ -639,7 +638,7 @@ static void __set_rx_mode (struct net_de
+ static void rtl8139_hw_start (struct net_device *dev);
+ static void rtl8139_thread (void *_data);
+ static void rtl8139_tx_timeout_task(void *_data);
+-static struct ethtool_ops rtl8139_ethtool_ops;
++static const struct ethtool_ops rtl8139_ethtool_ops;
+
+ /* write MMIO register, with flush */
+ /* Flush avoids rtl8139 bug w/ posted MMIO writes */
+@@ -2146,8 +2145,7 @@ static int rtl8139_poll(struct net_devic
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct rtl8139_private *tp = netdev_priv(dev);
+@@ -2219,7 +2217,7 @@ static irqreturn_t rtl8139_interrupt (in
+ static void rtl8139_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- rtl8139_interrupt(dev->irq, dev, NULL);
++ rtl8139_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -2446,7 +2444,7 @@ static void rtl8139_get_strings(struct n
+ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+ }
+
+-static struct ethtool_ops rtl8139_ethtool_ops = {
++static const struct ethtool_ops rtl8139_ethtool_ops = {
+ .get_drvinfo = rtl8139_get_drvinfo,
+ .get_settings = rtl8139_get_settings,
+ .set_settings = rtl8139_set_settings,
+@@ -2512,9 +2510,6 @@ static void __set_rx_mode (struct net_de
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+- /* Unconditionally log net taps. */
+- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+@@ -2629,7 +2624,7 @@ static int __init rtl8139_init_module (v
+ printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+ #endif
+
+- return pci_module_init (&rtl8139_pci_driver);
++ return pci_register_driver(&rtl8139_pci_driver);
+ }
+
+
+diff --git a/drivers/net/82596.c b/drivers/net/82596.c
+index 257d3bc..8236f26 100644
+--- a/drivers/net/82596.c
++++ b/drivers/net/82596.c
+@@ -357,7 +357,7 @@ static char init_setup[] =
+
+ static int i596_open(struct net_device *dev);
+ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t i596_interrupt(int irq, void *dev_id);
+ static int i596_close(struct net_device *dev);
+ static struct net_device_stats *i596_get_stats(struct net_device *dev);
+ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+@@ -444,7 +444,7 @@ static inline int wait_cmd(struct net_de
+ static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str)
+ {
+ volatile struct i596_cmd *c = cmd;
+-
++
+ while (--delcnt && c->command)
+ udelay(10);
+ if (!delcnt) {
+@@ -455,7 +455,7 @@ static inline int wait_cfg(struct net_de
+ return 0;
+ }
+
+-
++
+ static void i596_display_data(struct net_device *dev)
+ {
+ struct i596_private *lp = dev->priv;
+@@ -501,7 +501,7 @@ static void i596_display_data(struct net
+
+
+ #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+-static irqreturn_t i596_error(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i596_error(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ #ifdef ENABLE_MVME16x_NET
+@@ -787,7 +787,7 @@ static inline int i596_rx(struct net_dev
+ }
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG " rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+-
++
+ if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+ /* a good frame */
+ int pkt_len = rbd->count & 0x3fff;
+@@ -1208,7 +1208,7 @@ struct net_device * __init i82596_probe(
+ Some other boards trip the checksum.. but then appear as
+ ether address 0. Trap these - AC */
+
+- if ((checksum % 0x100) ||
++ if ((checksum % 0x100) ||
+ (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
+ err = -ENODEV;
+ goto out1;
+@@ -1283,7 +1283,7 @@ out:
+ return ERR_PTR(err);
+ }
+
+-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i596_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct i596_private *lp;
+@@ -1294,7 +1294,7 @@ static irqreturn_t i596_interrupt(int ir
+ #ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
+- i596_error(irq, dev_id, regs);
++ i596_error(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+ }
+@@ -1545,7 +1545,7 @@ static void set_multicast_list(struct ne
+ printk(KERN_ERR "%s: Only %d multicast addresses supported",
+ dev->name, cnt);
+ }
+-
++
+ if (dev->mc_count > 0) {
+ struct dev_mc_list *dmi;
+ unsigned char *cp;
+@@ -1609,7 +1609,7 @@ void __exit cleanup_module(void)
+ }
+
+ #endif /* MODULE */
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c"
+diff --git a/drivers/net/8390.c b/drivers/net/8390.c
+index d2935ae..3d1c599 100644
+--- a/drivers/net/8390.c
++++ b/drivers/net/8390.c
+@@ -1,7 +1,7 @@
+ /* 8390.c: A general NS8390 ethernet driver core for linux. */
+ /*
+ Written 1992-94 by Donald Becker.
+-
++
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+
+@@ -13,7 +13,7 @@
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+-
++
+ This is the chip-specific code for many 8390-based ethernet adaptors.
+ This is not a complete driver, it must be combined with board-specific
+ code such as ne.c, wd.c, 3c503.c, etc.
+@@ -27,7 +27,7 @@
+ Changelog:
+
+ Paul Gortmaker : remove set_bit lock, other cleanups.
+- Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
++ Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
+ ei_block_input() for eth_io_copy_and_sum().
+ Paul Gortmaker : exchange static int ei_pingpong for a #define,
+ also add better Tx error handling.
+@@ -94,9 +94,9 @@ static const char version[] =
+ Read the 4 byte, page aligned 8390 header. *If* there is a
+ subsequent read, it will be of the rest of the packet.
+ void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+- Read COUNT bytes from the packet buffer into the skb data area. Start
++ Read COUNT bytes from the packet buffer into the skb data area. Start
+ reading from RING_OFFSET, the address as the 8390 sees it. This will always
+- follow the read of the 8390 header.
++ follow the read of the 8390 header.
+ */
+ #define ei_reset_8390 (ei_local->reset_8390)
+ #define ei_block_output (ei_local->block_output)
+@@ -128,7 +128,7 @@ static void do_set_multicast_list(struct
+ * a page register that controls bank and packet buffer access. We guard
+ * this with ei_local->page_lock. Nobody should assume or set the page other
+ * than zero when the lock is not held. Lock holders must restore page 0
+- * before unlocking. Even pure readers must take the lock to protect in
++ * before unlocking. Even pure readers must take the lock to protect in
+ * page 0.
+ *
+ * To make life difficult the chip can also be very slow. We therefore can't
+@@ -141,14 +141,14 @@ static void do_set_multicast_list(struct
+ * a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ * enter lock, take the queued irq. So we waddle instead of flying.
+ *
+- * Finally by special arrangement for the purpose of being generally
++ * Finally by special arrangement for the purpose of being generally
+ * annoying the transmit function is called bh atomic. That places
+ * restrictions on the user context callers as disable_irq won't save
+ * them.
+ */
+-
+
+-
++
++
+ /**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+@@ -168,12 +168,12 @@ int ei_open(struct net_device *dev)
+ dev->tx_timeout = ei_tx_timeout;
+ if (dev->watchdog_timeo <= 0)
+ dev->watchdog_timeo = TX_TIMEOUT;
+-
++
+ /*
+ * Grab the page lock so we own the register set, then call
+ * the init function.
+ */
+-
++
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ NS8390_init(dev, 1);
+ /* Set the flag before we drop the lock, That way the IRQ arrives
+@@ -198,7 +198,7 @@ int ei_close(struct net_device *dev)
+ /*
+ * Hold the page lock during close
+ */
+-
++
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ NS8390_init(dev, 0);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+@@ -241,26 +241,26 @@ void ei_tx_timeout(struct net_device *de
+ dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+ (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+
+- if (!isr && !ei_local->stat.tx_packets)
++ if (!isr && !ei_local->stat.tx_packets)
+ {
+ /* The 8390 probably hasn't gotten on the cable yet. */
+ ei_local->interface_num ^= 1; /* Try a different xcvr. */
+ }
+
+ /* Ugly but a reset can be slow, yet must be protected */
+-
++
+ disable_irq_nosync_lockdep(dev->irq);
+ spin_lock(&ei_local->page_lock);
+-
++
+ /* Try to restart the card. Perhaps the user has fixed something. */
+ ei_reset_8390(dev);
+ NS8390_init(dev, 1);
+-
++
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep(dev->irq);
+ netif_wake_queue(dev);
+ }
+-
++
+ /**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+@@ -268,7 +268,7 @@ void ei_tx_timeout(struct net_device *de
+ *
+ * Sends a packet to an 8390 network device.
+ */
+-
++
+ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ long e8390_base = dev->base_addr;
+@@ -285,24 +285,24 @@ static int ei_start_xmit(struct sk_buff
+ data = buf;
+ }
+
+- /* Mask interrupts from the ethercard.
++ /* Mask interrupts from the ethercard.
+ SMP: We have to grab the lock here otherwise the IRQ handler
+ on another CPU can flip window and race the IRQ mask set. We end
+ up trashing the mcast filter not disabling irqs if we don't lock */
+-
++
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ outb_p(0x00, e8390_base + EN0_IMR);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+-
+-
++
++
+ /*
+ * Slow phase with lock held.
+ */
+-
+- disable_irq_nosync(dev->irq);
+-
++
++ disable_irq_nosync_lockdep_irqsave(dev->irq, &flags);
++
+ spin_lock(&ei_local->page_lock);
+-
++
+ ei_local->irqlock = 1;
+
+ /*
+@@ -313,7 +313,7 @@ static int ei_start_xmit(struct sk_buff
+ * card, leaving a substantial gap between each transmitted packet.
+ */
+
+- if (ei_local->tx1 == 0)
++ if (ei_local->tx1 == 0)
+ {
+ output_page = ei_local->tx_start_page;
+ ei_local->tx1 = send_length;
+@@ -321,7 +321,7 @@ static int ei_start_xmit(struct sk_buff
+ printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+ }
+- else if (ei_local->tx2 == 0)
++ else if (ei_local->tx2 == 0)
+ {
+ output_page = ei_local->tx_start_page + TX_PAGES/2;
+ ei_local->tx2 = send_length;
+@@ -338,7 +338,7 @@ static int ei_start_xmit(struct sk_buff
+ netif_stop_queue(dev);
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ spin_unlock(&ei_local->page_lock);
+- enable_irq(dev->irq);
++ enable_irq_lockdep_irqrestore(dev->irq, &flags);
+ ei_local->stat.tx_errors++;
+ return 1;
+ }
+@@ -348,20 +348,20 @@ static int ei_start_xmit(struct sk_buff
+ * isn't already sending. If it is busy, the interrupt handler will
+ * trigger the send later, upon receiving a Tx done interrupt.
+ */
+-
++
+ ei_block_output(dev, send_length, data, output_page);
+-
+- if (! ei_local->txing)
++
++ if (! ei_local->txing)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, output_page);
+ dev->trans_start = jiffies;
+- if (output_page == ei_local->tx_start_page)
++ if (output_page == ei_local->tx_start_page)
+ {
+ ei_local->tx1 = -1;
+ ei_local->lasttx = -1;
+ }
+- else
++ else
+ {
+ ei_local->tx2 = -1;
+ ei_local->lasttx = -2;
+@@ -377,21 +377,20 @@ static int ei_start_xmit(struct sk_buff
+ /* Turn 8390 interrupts back on. */
+ ei_local->irqlock = 0;
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+-
++
+ spin_unlock(&ei_local->page_lock);
+- enable_irq(dev->irq);
++ enable_irq_lockdep_irqrestore(dev->irq, &flags);
+
+ dev_kfree_skb (skb);
+ ei_local->stat.tx_bytes += send_length;
+-
++
+ return 0;
+ }
+-
++
+ /**
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+- * @regs: unused
+ *
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+@@ -400,29 +399,23 @@ static int ei_start_xmit(struct sk_buff
+ * needed.
+ */
+
+-irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++irqreturn_t ei_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ long e8390_base;
+ int interrupts, nr_serviced = 0;
+ struct ei_device *ei_local;
+-
+- if (dev == NULL)
+- {
+- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
++
+ e8390_base = dev->base_addr;
+- ei_local = (struct ei_device *) netdev_priv(dev);
++ ei_local = netdev_priv(dev);
+
+ /*
+ * Protect the irq test too.
+ */
+-
++
+ spin_lock(&ei_local->page_lock);
+
+- if (ei_local->irqlock)
++ if (ei_local->irqlock)
+ {
+ #if 1 /* This might just be an interrupt for a PCI device sharing this line */
+ /* The "irqlock" check is only for testing. */
+@@ -435,16 +428,16 @@ irqreturn_t ei_interrupt(int irq, void *
+ spin_unlock(&ei_local->page_lock);
+ return IRQ_NONE;
+ }
+-
++
+ /* Change to page 0 and read the intr status reg. */
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+ if (ei_debug > 3)
+ printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
+ inb_p(e8390_base + EN0_ISR));
+-
++
+ /* !!Assumption!! -- we stay in page 0. Don't break this. */
+ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
+- && ++nr_serviced < MAX_SERVICE)
++ && ++nr_serviced < MAX_SERVICE)
+ {
+ if (!netif_running(dev)) {
+ printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+@@ -453,9 +446,9 @@ irqreturn_t ei_interrupt(int irq, void *
+ interrupts = 0;
+ break;
+ }
+- if (interrupts & ENISR_OVER)
++ if (interrupts & ENISR_OVER)
+ ei_rx_overrun(dev);
+- else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
++ else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
+ {
+ /* Got a good (?) packet. */
+ ei_receive(dev);
+@@ -466,27 +459,27 @@ irqreturn_t ei_interrupt(int irq, void *
+ else if (interrupts & ENISR_TX_ERR)
+ ei_tx_err(dev);
+
+- if (interrupts & ENISR_COUNTERS)
++ if (interrupts & ENISR_COUNTERS)
+ {
+ ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
+ ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1);
+ ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
+ outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
+ }
+-
++
+ /* Ignore any RDC interrupts that make it back to here. */
+- if (interrupts & ENISR_RDC)
++ if (interrupts & ENISR_RDC)
+ {
+ outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+ }
+
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ }
+-
+- if (interrupts && ei_debug)
++
++ if (interrupts && ei_debug)
+ {
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+- if (nr_serviced >= MAX_SERVICE)
++ if (nr_serviced >= MAX_SERVICE)
+ {
+ /* 0xFF is valid for a card removal */
+ if(interrupts!=0xFF)
+@@ -505,9 +498,9 @@ irqreturn_t ei_interrupt(int irq, void *
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ void ei_poll(struct net_device *dev)
+ {
+- disable_irq(dev->irq);
+- ei_interrupt(dev->irq, dev, NULL);
+- enable_irq(dev->irq);
++ disable_irq_lockdep(dev->irq);
++ ei_interrupt(dev->irq, dev);
++ enable_irq_lockdep(dev->irq);
+ }
+ #endif
+
+@@ -551,7 +544,7 @@ static void ei_tx_err(struct net_device
+
+ if (tx_was_aborted)
+ ei_tx_intr(dev);
+- else
++ else
+ {
+ ei_local->stat.tx_errors++;
+ if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
+@@ -573,7 +566,7 @@ static void ei_tx_intr(struct net_device
+ long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int status = inb(e8390_base + EN0_TSR);
+-
++
+ outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+
+ /*
+@@ -582,13 +575,13 @@ static void ei_tx_intr(struct net_device
+ */
+ ei_local->txqueue--;
+
+- if (ei_local->tx1 < 0)
++ if (ei_local->tx1 < 0)
+ {
+ if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+ printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx1);
+ ei_local->tx1 = 0;
+- if (ei_local->tx2 > 0)
++ if (ei_local->tx2 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+@@ -596,15 +589,15 @@ static void ei_tx_intr(struct net_device
+ ei_local->tx2 = -1,
+ ei_local->lasttx = 2;
+ }
+- else ei_local->lasttx = 20, ei_local->txing = 0;
++ else ei_local->lasttx = 20, ei_local->txing = 0;
+ }
+- else if (ei_local->tx2 < 0)
++ else if (ei_local->tx2 < 0)
+ {
+ if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
+ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx2);
+ ei_local->tx2 = 0;
+- if (ei_local->tx1 > 0)
++ if (ei_local->tx1 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+@@ -623,17 +616,17 @@ static void ei_tx_intr(struct net_device
+ ei_local->stat.collisions++;
+ if (status & ENTSR_PTX)
+ ei_local->stat.tx_packets++;
+- else
++ else
+ {
+ ei_local->stat.tx_errors++;
+- if (status & ENTSR_ABT)
++ if (status & ENTSR_ABT)
+ {
+ ei_local->stat.tx_aborted_errors++;
+ ei_local->stat.collisions += 16;
+ }
+- if (status & ENTSR_CRS)
++ if (status & ENTSR_CRS)
+ ei_local->stat.tx_carrier_errors++;
+- if (status & ENTSR_FU)
++ if (status & ENTSR_FU)
+ ei_local->stat.tx_fifo_errors++;
+ if (status & ENTSR_CDH)
+ ei_local->stat.tx_heartbeat_errors++;
+@@ -647,7 +640,7 @@ static void ei_tx_intr(struct net_device
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+- * We have a good packet(s), get it/them out of the buffers.
++ * We have a good packet(s), get it/them out of the buffers.
+ * Called with lock held.
+ */
+
+@@ -660,42 +653,42 @@ static void ei_receive(struct net_device
+ int rx_pkt_count = 0;
+ struct e8390_pkt_hdr rx_frame;
+ int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+-
+- while (++rx_pkt_count < 10)
++
++ while (++rx_pkt_count < 10)
+ {
+ int pkt_len, pkt_stat;
+-
++
+ /* Get the rx page (incoming packet pointer). */
+ outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
+ rxing_page = inb_p(e8390_base + EN1_CURPAG);
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+-
++
+ /* Remove one frame from the ring. Boundary is always a page behind. */
+ this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
+ if (this_frame >= ei_local->stop_page)
+ this_frame = ei_local->rx_start_page;
+-
++
+ /* Someday we'll omit the previous, iff we never get this message.
+- (There is at least one clone claimed to have a problem.)
+-
++ (There is at least one clone claimed to have a problem.)
++
+ Keep quiet if it looks like a card removal. One problem here
+ is that some clones crash in roughly the same way.
+ */
+ if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
+ printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
+ dev->name, this_frame, ei_local->current_page);
+-
++
+ if (this_frame == rxing_page) /* Read all the frames? */
+ break; /* Done for now */
+-
++
+ current_offset = this_frame << 8;
+ ei_get_8390_hdr(dev, &rx_frame, this_frame);
+-
++
+ pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
+ pkt_stat = rx_frame.status;
+-
++
+ next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+-
++
+ /* Check for bogosity warned by 3c503 book: the status byte is never
+ written. This happened a lot during testing! This code should be
+ cleaned up someday. */
+@@ -709,7 +702,7 @@ static void ei_receive(struct net_device
+ continue;
+ }
+
+- if (pkt_len < 60 || pkt_len > 1518)
++ if (pkt_len < 60 || pkt_len > 1518)
+ {
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+@@ -718,12 +711,12 @@ static void ei_receive(struct net_device
+ ei_local->stat.rx_errors++;
+ ei_local->stat.rx_length_errors++;
+ }
+- else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
++ else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
+ {
+ struct sk_buff *skb;
+-
++
+ skb = dev_alloc_skb(pkt_len+2);
+- if (skb == NULL)
++ if (skb == NULL)
+ {
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
+@@ -745,8 +738,8 @@ static void ei_receive(struct net_device
+ if (pkt_stat & ENRSR_PHY)
+ ei_local->stat.multicast++;
+ }
+- }
+- else
++ }
++ else
+ {
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+@@ -758,7 +751,7 @@ static void ei_receive(struct net_device
+ ei_local->stat.rx_fifo_errors++;
+ }
+ next_frame = rx_frame.next;
+-
++
+ /* This _should_ never happen: it's here for avoiding bad clones. */
+ if (next_frame >= ei_local->stop_page) {
+ printk("%s: next frame inconsistency, %#2x\n", dev->name,
+@@ -785,7 +778,7 @@ static void ei_receive(struct net_device
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network." Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+- * computer will hate you - it takes 10ms or so.
++ * computer will hate you - it takes 10ms or so.
+ */
+
+ static void ei_rx_overrun(struct net_device *dev)
+@@ -793,19 +786,19 @@ static void ei_rx_overrun(struct net_dev
+ long e8390_base = dev->base_addr;
+ unsigned char was_txing, must_resend = 0;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+-
++
+ /*
+ * Record whether a Tx was in progress and then issue the
+ * stop command.
+ */
+ was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+-
++
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+ ei_local->stat.rx_over_errors++;
+-
+- /*
++
++ /*
+ * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+ * Early datasheets said to poll the reset bit, but now they say that
+ * it "is not a reliable indicator and subsequently should be ignored."
+@@ -826,7 +819,7 @@ static void ei_rx_overrun(struct net_dev
+ */
+
+ if (was_txing)
+- {
++ {
+ unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+ if (!tx_completed)
+ must_resend = 1;
+@@ -848,7 +841,7 @@ static void ei_rx_overrun(struct net_dev
+ /*
+ * Leave loopback mode, and resend any packet that got stopped.
+ */
+- outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
++ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+ if (must_resend)
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+ }
+@@ -856,13 +849,13 @@ static void ei_rx_overrun(struct net_dev
+ /*
+ * Collect the stats. This is called unlocked and from several contexts.
+ */
+-
++
+ static struct net_device_stats *get_stats(struct net_device *dev)
+ {
+ long ioaddr = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned long flags;
+-
++
+ /* If the card is stopped, just return the present stats. */
+ if (!netif_running(dev))
+ return &ei_local->stat;
+@@ -873,7 +866,7 @@ static struct net_device_stats *get_stat
+ ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
+ ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+-
++
+ return &ei_local->stat;
+ }
+
+@@ -881,21 +874,21 @@ static struct net_device_stats *get_stat
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+-
++
+ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+ {
+ struct dev_mc_list *dmi;
+
+- for (dmi=dev->mc_list; dmi; dmi=dmi->next)
++ for (dmi=dev->mc_list; dmi; dmi=dmi->next)
+ {
+ u32 crc;
+- if (dmi->dmi_addrlen != ETH_ALEN)
++ if (dmi->dmi_addrlen != ETH_ALEN)
+ {
+ printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
+ continue;
+ }
+ crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+- /*
++ /*
+ * The 8390 uses the 6 most significant bits of the
+ * CRC to index the multicast table.
+ */
+@@ -908,16 +901,16 @@ static inline void make_mc_bits(u8 *bits
+ * @dev: net device for which multicast filter is adjusted
+ *
+ * Set or clear the multicast filter for this adaptor. May be called
+- * from a BH in 2.1.x. Must be called with lock held.
++ * from a BH in 2.1.x. Must be called with lock held.
+ */
+-
++
+ static void do_set_multicast_list(struct net_device *dev)
+ {
+ long e8390_base = dev->base_addr;
+ int i;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+- if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
++ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
+ {
+ memset(ei_local->mcfilter, 0, 8);
+ if (dev->mc_list)
+@@ -926,23 +919,23 @@ static void do_set_multicast_list(struct
+ else
+ memset(ei_local->mcfilter, 0xFF, 8); /* mcast set to accept-all */
+
+- /*
++ /*
+ * DP8390 manuals don't specify any magic sequence for altering
+ * the multicast regs on an already running card. To be safe, we
+ * ensure multicast mode is off prior to loading up the new hash
+ * table. If this proves to be not enough, we can always resort
+ * to stopping the NIC, loading the table and then restarting.
+ *
+- * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
++ * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
+ * Elite16) appear to be write-only. The NS 8390 data sheet lists
+ * them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
+ * Ultra32 EISA) appears to have this bug fixed.
+ */
+-
++
+ if (netif_running(dev))
+ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+- for(i = 0; i < 8; i++)
++ for(i = 0; i < 8; i++)
+ {
+ outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+ #ifndef BUG_83C690
+@@ -965,16 +958,16 @@ static void do_set_multicast_list(struct
+ * be parallel to just about everything else. Its also fairly quick and
+ * not called too often. Must protect against both bh and irq users
+ */
+-
++
+ static void set_multicast_list(struct net_device *dev)
+ {
+ unsigned long flags;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+-
++
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ do_set_multicast_list(dev);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+-}
++}
+
+ /**
+ * ethdev_setup - init rest of 8390 device struct
+@@ -989,7 +982,7 @@ static void ethdev_setup(struct net_devi
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ if (ei_debug > 1)
+ printk(version);
+-
++
+ dev->hard_start_xmit = &ei_start_xmit;
+ dev->get_stats = get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+@@ -1011,7 +1004,7 @@ struct net_device *__alloc_ei_netdev(int
+ ethdev_setup);
+ }
+
+-
++
+
+
+ /* This page of functions should be 8390 generic */
+@@ -1033,9 +1026,9 @@ void NS8390_init(struct net_device *dev,
+ int endcfg = ei_local->word16
+ ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
+ : 0x48;
+-
++
+ if(sizeof(struct e8390_pkt_hdr)!=4)
+- panic("8390.c: header struct mispacked\n");
++ panic("8390.c: header struct mispacked\n");
+ /* Follow National Semi's recommendations for initing the DP83902. */
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+ outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
+@@ -1055,11 +1048,11 @@ void NS8390_init(struct net_device *dev,
+ /* Clear the pending interrupts and mask. */
+ outb_p(0xFF, e8390_base + EN0_ISR);
+ outb_p(0x00, e8390_base + EN0_IMR);
+-
++
+ /* Copy the station address into the DS8390 registers. */
+
+ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+- for(i = 0; i < 6; i++)
++ for(i = 0; i < 6; i++)
+ {
+ outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+ if (ei_debug > 1 && inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+@@ -1073,7 +1066,7 @@ void NS8390_init(struct net_device *dev,
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_local->txing = 0;
+
+- if (startp)
++ if (startp)
+ {
+ outb_p(0xff, e8390_base + EN0_ISR);
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+@@ -1085,18 +1078,18 @@ void NS8390_init(struct net_device *dev,
+ }
+ }
+
+-/* Trigger a transmit start, assuming the length is valid.
++/* Trigger a transmit start, assuming the length is valid.
+ Always called with the page lock held */
+-
++
+ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+ int start_page)
+ {
+ long e8390_base = dev->base_addr;
+ struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
+-
++
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
+-
+- if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
++
++ if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
+ {
+ printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+ dev->name);
+diff --git a/drivers/net/8390.h b/drivers/net/8390.h
+index a9a58f5..f44f122 100644
+--- a/drivers/net/8390.h
++++ b/drivers/net/8390.h
+@@ -35,7 +35,7 @@ extern void ei_poll(struct net_device *d
+ extern void NS8390_init(struct net_device *dev, int startp);
+ extern int ei_open(struct net_device *dev);
+ extern int ei_close(struct net_device *dev);
+-extern irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t ei_interrupt(int irq, void *dev_id);
+ extern struct net_device *__alloc_ei_netdev(int size);
+ static inline struct net_device *alloc_ei_netdev(void)
+ {
+@@ -106,7 +106,7 @@ struct ei_device {
+ * Only generate indirect loads given a machine that needs them.
+ * - removed AMIGA_PCMCIA from this list, handled as ISA io now
+ */
+-
++
+ #if defined(CONFIG_MAC) || \
+ defined(CONFIG_ZORRO8390) || defined(CONFIG_ZORRO8390_MODULE) || \
+ defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index a2bd811..9cb3ca5 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -24,6 +24,9 @@ config NETDEVICES
+
+ If unsure, say Y.
+
++# All the following symbols are dependent on NETDEVICES - do not repeat
++# that for each of the symbols.
++if NETDEVICES
+
+ config IFB
+ tristate "Intermediate Functional Block support"
+@@ -438,12 +441,6 @@ config MIPS_JAZZ_SONIC
+ This is the driver for the onboard card of MIPS Magnum 4000,
+ Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+
+-config MIPS_GT96100ETH
+- bool "MIPS GT96100 Ethernet support"
+- depends on NET_ETHERNET && MIPS_GT96100
+- help
+- Say Y here to support the Ethernet subsystem on your GT96100 card.
+-
+ config MIPS_AU1X00_ENET
+ bool "MIPS AU1000 Ethernet support"
+ depends on NET_ETHERNET && SOC_AU1X00
+@@ -489,7 +486,7 @@ config SGI_IOC3_ETH_HW_TX_CSUM
+
+ config MIPS_SIM_NET
+ tristate "MIPS simulator Network device (EXPERIMENTAL)"
+- depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL
++ depends on MIPS_SIM && EXPERIMENTAL
+ help
+ The MIPSNET device is a simple Ethernet network device which is
+ emulated by the MIPS Simulator.
+@@ -1300,6 +1297,23 @@ config PCNET32
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called pcnet32.
+
++config PCNET32_NAPI
++ bool "Use RX polling (NAPI) (EXPERIMENTAL)"
++ depends on PCNET32 && EXPERIMENTAL
++ help
++ NAPI is a new driver API designed to reduce CPU and interrupt load
++ when the driver is receiving lots of packets from the card. It is
++ still somewhat experimental and thus not yet enabled by default.
++
++ If your estimated Rx load is 10kpps or more, or if the card will be
++ deployed on potentially unfriendly networks (e.g. in a firewall),
++ then say Y here.
++
++ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
++ information.
++
++ If in doubt, say N.
++
+ config AMD8111_ETH
+ tristate "AMD 8111 (new PCI lance) support"
+ depends on NET_PCI && PCI
+@@ -1411,6 +1425,22 @@ config FORCEDETH
+ <file:Documentation/networking/net-modules.txt>. The module will be
+ called forcedeth.
+
++config FORCEDETH_NAPI
++ bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
++ depends on FORCEDETH && EXPERIMENTAL
++ help
++ NAPI is a new driver API designed to reduce CPU and interrupt load
++ when the driver is receiving lots of packets from the card. It is
++ still somewhat experimental and thus not yet enabled by default.
++
++ If your estimated Rx load is 10kpps or more, or if the card will be
++ deployed on potentially unfriendly networks (e.g. in a firewall),
++ then say Y here.
++
++ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
++ information.
++
++ If in doubt, say N.
+
+ config CS89x0
+ tristate "CS89x0 support"
+@@ -2082,16 +2112,16 @@ config SKGE
+
+ config SKY2
+ tristate "SysKonnect Yukon2 support (EXPERIMENTAL)"
+- depends on PCI && EXPERIMENTAL
++ depends on PCI
+ select CRC32
+ ---help---
+- This driver supports Gigabit Ethernet adapters based on the the
++ This driver supports Gigabit Ethernet adapters based on the
+ Marvell Yukon 2 chipset:
+ Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
+ 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
+
+- This driver does not support the original Yukon chipset: a seperate
+- driver, skge, is provided for Yukon-based adapters.
++ There is companion driver for the older Marvell Yukon and
++ Genesis based adapters: skge.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sky2. This is recommended.
+@@ -2258,11 +2288,11 @@ config UGETH_TX_ON_DEMOND
+
+ config UGETH_HAS_GIGA
+ bool
+- depends on UCC_GETH && MPC836x
++ depends on UCC_GETH && PPC_MPC836x
+
+ config MV643XX_ETH
+ tristate "MV-643XX Ethernet support"
+- depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM
++ depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
+ select MII
+ help
+ This driver supports the gigabit Ethernet on the Marvell MV643XX
+@@ -2290,6 +2320,15 @@ config MV643XX_ETH_2
+ This enables support for Port 2 of the Marvell MV643XX Gigabit
+ Ethernet.
+
++config QLA3XXX
++ tristate "QLogic QLA3XXX Network Driver Support"
++ depends on PCI
++ help
++ This driver supports QLogic ISP3XXX gigabit Ethernet cards.
++
++ To compile this driver as a module, choose M here: the module
++ will be called qla3xxx.
++
+ endmenu
+
+ #
+@@ -2318,6 +2357,15 @@ config CHELSIO_T1
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb.
+
++config EHEA
++ tristate "eHEA Ethernet support"
++ depends on IBMEBUS
++ ---help---
++ This driver supports the IBM pSeries eHEA ethernet adapter.
++
++ To compile the driver as a module, choose M here. The module
++ will be called ehea.
++
+ config IXGB
+ tristate "Intel(R) PRO/10GbE support"
+ depends on PCI
+@@ -2419,7 +2467,7 @@ config ISERIES_VETH
+
+ config RIONET
+ tristate "RapidIO Ethernet over messaging driver support"
+- depends on NETDEVICES && RAPIDIO
++ depends on RAPIDIO
+
+ config RIONET_TX_SIZE
+ int "Number of outbound queue entries"
+@@ -2550,6 +2598,7 @@ config PLIP
+
+ config PPP
+ tristate "PPP (point-to-point protocol) support"
++ select SLHC
+ ---help---
+ PPP (Point to Point Protocol) is a newer and better SLIP. It serves
+ the same purpose: sending Internet traffic over telephone (and other
+@@ -2668,6 +2717,7 @@ config PPP_MPPE
+ select CRYPTO
+ select CRYPTO_SHA1
+ select CRYPTO_ARC4
++ select CRYPTO_ECB
+ ---help---
+ Support for the MPPE Encryption protocol, as employed by the
+ Microsoft Point-to-Point Tunneling Protocol.
+@@ -2730,6 +2780,7 @@ config SLIP
+ config SLIP_COMPRESSED
+ bool "CSLIP compressed headers"
+ depends on SLIP
++ select SLHC
+ ---help---
+ This protocol is faster than SLIP because it uses compression on the
+ TCP/IP headers (not on the data itself), but it has to be supported
+@@ -2742,6 +2793,12 @@ config SLIP_COMPRESSED
+ <http://www.tldp.org/docs.html#howto>, explains how to configure
+ CSLIP. This won't enlarge your kernel.
+
++config SLHC
++ tristate
++ help
++ This option enables Van Jacobsen serial line header compression
++ routines.
++
+ config SLIP_SMART
+ bool "Keepalive and linefill"
+ depends on SLIP
+@@ -2799,6 +2856,8 @@ config NETCONSOLE
+ If you want to log kernel messages over the network, enable this.
+ See <file:Documentation/networking/netconsole.txt> for details.
+
++endif #NETDEVICES
++
+ config NETPOLL
+ def_bool NETCONSOLE
+
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index 8427bf9..f270bc4 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -2,14 +2,11 @@
+ # Makefile for the Linux network (ethercard) device drivers.
+ #
+
+-ifeq ($(CONFIG_ISDN_PPP),y)
+- obj-$(CONFIG_ISDN) += slhc.o
+-endif
+-
+ obj-$(CONFIG_E1000) += e1000/
+ obj-$(CONFIG_IBM_EMAC) += ibm_emac/
+ obj-$(CONFIG_IXGB) += ixgb/
+ obj-$(CONFIG_CHELSIO_T1) += chelsio/
++obj-$(CONFIG_EHEA) += ehea/
+ obj-$(CONFIG_BONDING) += bonding/
+ obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+
+@@ -113,8 +110,9 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
+ obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
+
+ obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
++obj-$(CONFIG_QLA3XXX) += qla3xxx.o
+
+-obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
++obj-$(CONFIG_PPP) += ppp_generic.o
+ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
+ obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+ obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
+@@ -123,9 +121,7 @@ obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
+ obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+
+ obj-$(CONFIG_SLIP) += slip.o
+-ifeq ($(CONFIG_SLIP_COMPRESSED),y)
+- obj-$(CONFIG_SLIP) += slhc.o
+-endif
++obj-$(CONFIG_SLHC) += slhc.o
+
+ obj-$(CONFIG_DUMMY) += dummy.o
+ obj-$(CONFIG_IFB) += ifb.o
+@@ -174,7 +170,6 @@ obj-$(CONFIG_HPLANCE) += hplance.o 7990.
+ obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
+ obj-$(CONFIG_EQUALIZER) += eql.o
+ obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
+-obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
+ obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
+ obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
+ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
+diff --git a/drivers/net/Space.c b/drivers/net/Space.c
+index a8c245a..a67f5ef 100644
+--- a/drivers/net/Space.c
++++ b/drivers/net/Space.c
+@@ -18,7 +18,7 @@
+ * - struct init cleanup, enable multiple ISA autoprobes.
+ * Arnaldo Carvalho de Melo <acme at conectiva.com.br> - 09/1999
+ * - fix sbni: s/device/net_device/
+- * Paul Gortmaker (06/98):
++ * Paul Gortmaker (06/98):
+ * - sort probes in a sane way, make sure all (safe) probes
+ * get run once & failed autoprobes don't autoprobe again.
+ *
+@@ -91,7 +91,7 @@ extern struct net_device *mac89x0_probe(
+ extern struct net_device *mc32_probe(int unit);
+ extern struct net_device *cops_probe(int unit);
+ extern struct net_device *ltpc_probe(void);
+-
++
+ /* Detachable devices ("pocket adaptors") */
+ extern struct net_device *de620_probe(int unit);
+
+@@ -129,10 +129,10 @@ static int __init probe_list2(int unit,
+ */
+
+ static struct devprobe2 eisa_probes[] __initdata = {
+-#ifdef CONFIG_ULTRA32
+- {ultra32_probe, 0},
++#ifdef CONFIG_ULTRA32
++ {ultra32_probe, 0},
+ #endif
+-#ifdef CONFIG_AC3200
++#ifdef CONFIG_AC3200
+ {ac3200_probe, 0},
+ #endif
+ #ifdef CONFIG_ES3210
+@@ -165,16 +165,16 @@ static struct devprobe2 mca_probes[] __i
+ * look for EISA/PCI/MCA cards in addition to ISA cards).
+ */
+ static struct devprobe2 isa_probes[] __initdata = {
+-#ifdef CONFIG_HP100 /* ISA, EISA & PCI */
++#if defined(CONFIG_HP100) && defined(CONFIG_ISA) /* ISA, EISA */
+ {hp100_probe, 0},
+-#endif
++#endif
+ #ifdef CONFIG_3C515
+ {tc515_probe, 0},
+ #endif
+-#ifdef CONFIG_ULTRA
++#ifdef CONFIG_ULTRA
+ {ultra_probe, 0},
+ #endif
+-#ifdef CONFIG_WD80x3
++#ifdef CONFIG_WD80x3
+ {wd_probe, 0},
+ #endif
+ #ifdef CONFIG_EL2 /* 3c503 */
+@@ -199,7 +199,7 @@ static struct devprobe2 isa_probes[] __i
+ #ifdef CONFIG_SMC9194
+ {smc_init, 0},
+ #endif
+-#ifdef CONFIG_SEEQ8005
++#ifdef CONFIG_SEEQ8005
+ {seeq8005_probe, 0},
+ #endif
+ #ifdef CONFIG_CS89x0
+@@ -295,7 +295,7 @@ static struct devprobe2 m68k_probes[] __
+ * Unified ethernet device probe, segmented per architecture and
+ * per bus interface. This drives the legacy devices only for now.
+ */
+-
++
+ static void __init ethif_probe2(int unit)
+ {
+ unsigned long base_addr = netdev_boot_base("eth", unit);
+@@ -349,7 +349,7 @@ static void __init trif_probe2(int unit)
+ }
+ #endif
+
+-
++
+ /*
+ * The loopback device is global so it can be directly referenced
+ * by the network code. Also, it must be first on device list.
+@@ -365,7 +365,7 @@ static int __init net_olddevs_init(void)
+ printk(KERN_ERR "Network loopback device setup failed\n");
+ }
+
+-
++
+ #ifdef CONFIG_SBNI
+ for (num = 0; num < 8; ++num)
+ sbni_probe(num);
+diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
+index f4ea626..d76548e 100644
+--- a/drivers/net/a2065.c
++++ b/drivers/net/a2065.c
+@@ -93,7 +93,7 @@ struct lance_init_block {
+ unsigned short rx_len; /* receive len and high addr */
+ unsigned short tx_ptr; /* transmit descriptor addr */
+ unsigned short tx_len; /* transmit len and high addr */
+-
++
+ /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
+ struct lance_rx_desc brx_ring[RX_RING_SIZE];
+ struct lance_tx_desc btx_ring[TX_RING_SIZE];
+@@ -115,7 +115,7 @@ struct lance_private {
+
+ int rx_new, tx_new;
+ int rx_old, tx_old;
+-
++
+ int lance_log_rx_bufs, lance_log_tx_bufs;
+ int rx_ring_mod_mask, tx_ring_mod_mask;
+
+@@ -190,7 +190,7 @@ static void lance_init_ring (struct net_
+
+ if (ZERO)
+ printk(KERN_DEBUG "TX rings:\n");
+-
++
+ /* Setup the Tx ring entries */
+ for (i = 0; i <= (1<<lp->lance_log_tx_bufs); i++) {
+ leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
+@@ -219,14 +219,14 @@ static void lance_init_ring (struct net_
+ }
+
+ /* Setup the initialization block */
+-
++
+ /* Setup rx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->brx_ring);
+ ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
+ ib->rx_ptr = leptr;
+ if (ZERO)
+ printk(KERN_DEBUG "RX ptr: %8.8x\n", leptr);
+-
++
+ /* Setup tx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->btx_ring);
+ ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
+@@ -286,7 +286,7 @@ static int lance_rx (struct net_device *
+ }
+ printk ("]\n");
+ #endif
+-
++
+ ll->rdp = LE_C0_RINT|LE_C0_INEA;
+ for (rd = &ib->brx_ring [lp->rx_new];
+ !((bits = rd->rmd1_bits) & LE_R1_OWN);
+@@ -319,7 +319,7 @@ static int lance_rx (struct net_device *
+ lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+ return 0;
+ }
+-
++
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align */
+ skb_put (skb, len); /* make room */
+@@ -361,10 +361,10 @@ static int lance_tx (struct net_device *
+ /* If we hit a packet not owned by us, stop */
+ if (td->tmd1_bits & LE_T1_OWN)
+ break;
+-
++
+ if (td->tmd1_bits & LE_T1_ERR) {
+ status = td->misc;
+-
++
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+@@ -417,7 +417,7 @@ static int lance_tx (struct net_device *
+
+ lp->stats.tx_packets++;
+ }
+-
++
+ j = (j + 1) & lp->tx_ring_mod_mask;
+ }
+ lp->tx_old = j;
+@@ -425,8 +425,7 @@ static int lance_tx (struct net_device *
+ return 0;
+ }
+
+-static irqreturn_t
+-lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t lance_interrupt (int irq, void *dev_id)
+ {
+ struct net_device *dev;
+ struct lance_private *lp;
+@@ -452,7 +451,7 @@ lance_interrupt (int irq, void *dev_id,
+ /* Clear the error condition */
+ ll->rdp = LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA;
+ }
+-
++
+ if (csr0 & LE_C0_RINT)
+ lance_rx (dev);
+
+@@ -528,7 +527,7 @@ static inline int lance_reset (struct ne
+ struct lance_private *lp = netdev_priv(dev);
+ volatile struct lance_regs *ll = lp->ll;
+ int status;
+-
++
+ /* Stop the lance */
+ ll->rap = LE_CSR0;
+ ll->rdp = LE_C0_STOP;
+@@ -569,7 +568,7 @@ static int lance_start_xmit (struct sk_b
+
+ skblen = skb->len;
+ len = skblen;
+-
++
+ if (len < ETH_ZLEN) {
+ len = ETH_ZLEN;
+ if (skb_padto(skb, ETH_ZLEN))
+@@ -587,7 +586,7 @@ static int lance_start_xmit (struct sk_b
+ /* dump the packet */
+ {
+ int i;
+-
++
+ for (i = 0; i < 64; i++) {
+ if ((i % 16) == 0)
+ printk("\n" KERN_DEBUG);
+@@ -599,13 +598,13 @@ static int lance_start_xmit (struct sk_b
+ entry = lp->tx_new & lp->tx_ring_mod_mask;
+ ib->btx_ring [entry].length = (-len) | 0xf000;
+ ib->btx_ring [entry].misc = 0;
+-
++
+ memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+
+ /* Clear the slack of the packet, do I need this? */
+ if (len != skblen)
+ memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
+-
++
+ /* Now, give the packet to the lance */
+ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+ lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+@@ -619,7 +618,7 @@ static int lance_start_xmit (struct sk_b
+ ll->rdp = LE_C0_INEA | LE_C0_TDMD;
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+-
++
+ local_irq_restore(flags);
+
+ return status;
+@@ -642,9 +641,9 @@ static void lance_load_multicast (struct
+ char *addrs;
+ int i;
+ u32 crc;
+-
++
+ /* set all multicast bits */
+- if (dev->flags & IFF_ALLMULTI){
++ if (dev->flags & IFF_ALLMULTI){
+ ib->filter [0] = 0xffffffff;
+ ib->filter [1] = 0xffffffff;
+ return;
+@@ -661,7 +660,7 @@ static void lance_load_multicast (struct
+ /* multicast address? */
+ if (!(*addrs & 1))
+ continue;
+-
++
+ crc = ether_crc_le(6, addrs);
+ crc = crc >> 26;
+ mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+diff --git a/drivers/net/a2065.h b/drivers/net/a2065.h
+index 184ad57..5117759 100644
+--- a/drivers/net/a2065.h
++++ b/drivers/net/a2065.h
+@@ -109,7 +109,7 @@ struct lance_rx_desc {
+ */
+ unsigned short mblength; /* Aactual number of bytes received */
+ };
+-
++
+ struct lance_tx_desc {
+ unsigned short tmd0; /* low address of packet */
+ unsigned char tmd1_bits; /* descriptor bits */
+@@ -117,7 +117,7 @@ struct lance_tx_desc {
+ short length; /* Length is 2s complement (negative)! */
+ unsigned short misc;
+ };
+-
++
+
+ /*
+ * Receive Flags
+diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
+index 0fbbcb7..0dca8bb 100644
+--- a/drivers/net/ac3200.c
++++ b/drivers/net/ac3200.c
+@@ -45,7 +45,7 @@ static const char version[] =
+ #define AC_NIC_BASE 0x00
+ #define AC_SA_PROM 0x16 /* The station address PROM. */
+ #define AC_ADDR0 0x00 /* Prefix station address values. */
+-#define AC_ADDR1 0x40
++#define AC_ADDR1 0x40
+ #define AC_ADDR2 0x90
+ #define AC_ID_PORT 0xC80
+ #define AC_EISA_ID 0x0110d305
+@@ -89,7 +89,7 @@ static void ac_get_8390_hdr(struct net_d
+ int ring_page);
+
+ static int ac_close_card(struct net_device *dev);
+-
++
+
+ /* Probe for the AC3200.
+
+@@ -217,7 +217,7 @@ static int __init ac_probe1(int ioaddr,
+ dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
+ dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
+
+- printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
++ printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
+ dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
+
+ /*
+diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
+index 1c01e9b..33c6645 100644
+--- a/drivers/net/acenic.c
++++ b/drivers/net/acenic.c
+@@ -99,7 +99,7 @@
+ #endif
+
+ #ifndef PCI_VENDOR_ID_ALTEON
+-#define PCI_VENDOR_ID_ALTEON 0x12ae
++#define PCI_VENDOR_ID_ALTEON 0x12ae
+ #endif
+ #ifndef PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE
+ #define PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE 0x0001
+@@ -163,11 +163,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl)
+ #define SET_NETDEV_DEV(net, pdev) do{} while(0)
+ #endif
+
+-#if LINUX_VERSION_CODE >= 0x2051c
+ #define ace_sync_irq(irq) synchronize_irq(irq)
+-#else
+-#define ace_sync_irq(irq) synchronize_irq()
+-#endif
+
+ #ifndef offset_in_page
+ #define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK)
+@@ -443,7 +439,7 @@ MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C
+ MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
+
+
+-static char version[] __devinitdata =
++static char version[] __devinitdata =
+ "acenic.c: v0.92 08/05/2002 Jes Sorensen, linux-acenic at SunSITE.dk\n"
+ " http://home.cern.ch/~jes/gige/acenic.html\n";
+
+@@ -451,7 +447,7 @@ static int ace_get_settings(struct net_d
+ static int ace_set_settings(struct net_device *, struct ethtool_cmd *);
+ static void ace_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+
+-static struct ethtool_ops ace_ethtool_ops = {
++static const struct ethtool_ops ace_ethtool_ops = {
+ .get_settings = ace_get_settings,
+ .set_settings = ace_set_settings,
+ .get_drvinfo = ace_get_drvinfo,
+@@ -516,7 +512,7 @@ static int __devinit acenic_probe_one(st
+
+ pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
+
+- /* OpenFirmware on Mac's does not set this - DOH.. */
++ /* OpenFirmware on Mac's does not set this - DOH.. */
+ if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
+ printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
+ "access - was not enabled by BIOS/Firmware\n",
+@@ -636,7 +632,7 @@ static void __devexit acenic_remove_one(
+ writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl);
+ if (ap->version >= 2)
+ writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl);
+-
++
+ /*
+ * This clears any pending interrupts
+ */
+@@ -725,7 +721,7 @@ static struct pci_driver acenic_pci_driv
+
+ static int __init acenic_init(void)
+ {
+- return pci_module_init(&acenic_pci_driver);
++ return pci_register_driver(&acenic_pci_driver);
+ }
+
+ static void __exit acenic_exit(void)
+@@ -1059,7 +1055,7 @@ static int __devinit ace_init(struct net
+ printk(KERN_INFO " PCI bus width: %i bits, speed: %iMHz, "
+ "latency: %i clks\n",
+ (pci_state & PCI_32BIT) ? 32 : 64,
+- (pci_state & PCI_66MHZ) ? 66 : 33,
++ (pci_state & PCI_66MHZ) ? 66 : 33,
+ ap->pci_latency);
+
+ /*
+@@ -1161,7 +1157,7 @@ static int __devinit ace_init(struct net
+ pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command);
+ }
+ #endif
+-
++
+ /*
+ * Configure DMA attributes.
+ */
+@@ -1284,7 +1280,7 @@ static int __devinit ace_init(struct net
+ (RX_STD_RING_ENTRIES +
+ RX_JUMBO_RING_ENTRIES))));
+ info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
+- info->rx_mini_ctrl.flags =
++ info->rx_mini_ctrl.flags =
+ RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG;
+
+ for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
+@@ -1318,7 +1314,7 @@ static int __devinit ace_init(struct net
+
+ if (ACE_IS_TIGON_I(ap)) {
+ ap->tx_ring = (struct tx_desc *) regs->Window;
+- for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
++ for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
+ * sizeof(struct tx_desc)) / sizeof(u32); i++)
+ writel(0, (void __iomem *)ap->tx_ring + i * 4);
+
+@@ -1670,7 +1666,7 @@ static void ace_load_std_rx_ring(struct
+ {
+ struct ace_regs __iomem *regs = ap->regs;
+ short i, idx;
+-
++
+
+ prefetchw(&ap->cur_rx_bufs);
+
+@@ -1966,7 +1962,7 @@ static void ace_rx_int(struct net_device
+
+ prefetchw(&ap->cur_rx_bufs);
+ prefetchw(&ap->cur_mini_bufs);
+-
++
+ while (idx != rxretprd) {
+ struct ring_info *rip;
+ struct sk_buff *skb;
+@@ -1977,7 +1973,7 @@ static void ace_rx_int(struct net_device
+
+
+ /* make sure the rx descriptor isn't read before rxretprd */
+- if (idx == rxretcsm)
++ if (idx == rxretcsm)
+ rmb();
+
+ retdesc = &ap->rx_return_ring[idx];
+@@ -2009,7 +2005,7 @@ static void ace_rx_int(struct net_device
+ rip = &ap->skb->rx_mini_skbuff[skbidx];
+ mapsize = ACE_MINI_BUFSIZE;
+ rxdesc = &ap->rx_mini_ring[skbidx];
+- mini_count++;
++ mini_count++;
+ break;
+ default:
+ printk(KERN_INFO "%s: unknown frame type (0x%02x) "
+@@ -2040,7 +2036,7 @@ static void ace_rx_int(struct net_device
+ */
+ if (bd_flags & BD_FLG_TCP_UDP_SUM) {
+ skb->csum = htons(csum);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+@@ -2148,7 +2144,7 @@ static inline void ace_tx_int(struct net
+ }
+
+
+-static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++static irqreturn_t ace_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct ace_private *ap = netdev_priv(dev);
+@@ -2377,7 +2373,7 @@ static int ace_close(struct net_device *
+ */
+ netif_stop_queue(dev);
+
+-
++
+ if (ap->promisc) {
+ cmd.evt = C_SET_PROMISC_MODE;
+ cmd.code = C_C_PROMISC_DISABLE;
+@@ -2412,7 +2408,7 @@ static int ace_close(struct net_device *
+
+ if (mapping) {
+ if (ACE_IS_TIGON_I(ap)) {
+- struct tx_desc __iomem *tx
++ struct tx_desc __iomem *tx
+ = (struct tx_desc __iomem *) &ap->tx_ring[i];
+ writel(0, &tx->addr.addrhi);
+ writel(0, &tx->addr.addrlo);
+@@ -2511,7 +2507,7 @@ restart:
+
+ mapping = ace_map_tx_skb(ap, skb, skb, idx);
+ flagsize = (skb->len << 16) | (BD_FLG_END);
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ flagsize |= BD_FLG_TCP_UDP_SUM;
+ #if ACENIC_DO_VLAN
+ if (vlan_tx_tag_present(skb)) {
+@@ -2534,7 +2530,7 @@ restart:
+
+ mapping = ace_map_tx_skb(ap, skb, NULL, idx);
+ flagsize = (skb_headlen(skb) << 16);
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ flagsize |= BD_FLG_TCP_UDP_SUM;
+ #if ACENIC_DO_VLAN
+ if (vlan_tx_tag_present(skb)) {
+@@ -2560,7 +2556,7 @@ restart:
+ PCI_DMA_TODEVICE);
+
+ flagsize = (frag->size << 16);
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ flagsize |= BD_FLG_TCP_UDP_SUM;
+ idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
+
+@@ -2625,7 +2621,7 @@ overflow:
+ cpu_relax();
+ goto restart;
+ }
+-
++
+ /* The ring is stuck full. */
+ printk(KERN_WARNING "%s: Transmit ring stuck full\n", dev->name);
+ return NETDEV_TX_BUSY;
+@@ -2784,18 +2780,18 @@ static int ace_set_settings(struct net_d
+ return 0;
+ }
+
+-static void ace_get_drvinfo(struct net_device *dev,
++static void ace_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+ {
+ struct ace_private *ap = netdev_priv(dev);
+
+ strlcpy(info->driver, "acenic", sizeof(info->driver));
+- snprintf(info->version, sizeof(info->version), "%i.%i.%i",
++ snprintf(info->version, sizeof(info->version), "%i.%i.%i",
+ tigonFwReleaseMajor, tigonFwReleaseMinor,
+ tigonFwReleaseFix);
+
+ if (ap->pdev)
+- strlcpy(info->bus_info, pci_name(ap->pdev),
++ strlcpy(info->bus_info, pci_name(ap->pdev),
+ sizeof(info->bus_info));
+
+ }
+@@ -2912,7 +2908,7 @@ static void __devinit ace_copy(struct ac
+ while (size > 0) {
+ tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
+ min_t(u32, size, ACE_WINDOW_SIZE));
+- tdest = (void __iomem *) ®s->Window +
++ tdest = (void __iomem *) ®s->Window +
+ (dest & (ACE_WINDOW_SIZE - 1));
+ writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase);
+ /*
+@@ -2943,7 +2939,7 @@ static void __devinit ace_clear(struct a
+ while (size > 0) {
+ tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
+ min_t(u32, size, ACE_WINDOW_SIZE));
+- tdest = (void __iomem *) ®s->Window +
++ tdest = (void __iomem *) ®s->Window +
+ (dest & (ACE_WINDOW_SIZE - 1));
+ writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase);
+
+@@ -3060,7 +3056,7 @@ static void __devinit eeprom_prep(struct
+
+ for (i = 0; i < 8; i++, magic <<= 1) {
+ udelay(ACE_SHORT_DELAY);
+- if (magic & 0x80)
++ if (magic & 0x80)
+ local |= EEPROM_DATA_OUT;
+ else
+ local &= ~EEPROM_DATA_OUT;
+diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
+index 62ec8ce..8ca8534 100644
+--- a/drivers/net/acenic.h
++++ b/drivers/net/acenic.h
+@@ -173,7 +173,7 @@ typedef struct {
+ /*
+ * Host control register bits.
+ */
+-
++
+ #define IN_INT 0x01
+ #define CLR_INT 0x02
+ #define HW_RESET 0x08
+@@ -449,7 +449,7 @@ struct cmd {
+
+ struct tx_desc{
+ aceaddr addr;
+- u32 flagsize;
++ u32 flagsize;
+ #if 0
+ /*
+ * This is in PCI shared mem and must be accessed with readl/writel
+@@ -754,7 +754,7 @@ static inline void ace_unmask_irq(struct
+ {
+ struct ace_private *ap = netdev_priv(dev);
+ struct ace_regs __iomem *regs = ap->regs;
+-
++
+ if (ACE_IS_TIGON_I(ap))
+ writel(0, ®s->MaskInt);
+ else
+@@ -769,7 +769,7 @@ static int ace_init(struct net_device *d
+ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
+ static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
+ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
+-static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ace_interrupt(int irq, void *dev_id);
+ static int ace_load_firmware(struct net_device *dev);
+ static int ace_open(struct net_device *dev);
+ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev);
+diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h
+index ec146f6..fd41f78 100644
+--- a/drivers/net/acenic_firmware.h
++++ b/drivers/net/acenic_firmware.h
+@@ -23,4577 +23,4577 @@
+ #else
+ /* Generated by genfw.c */
+ static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
+-0x10000003,
+-0x0, 0xd, 0xd, 0x3c1d0001,
+-0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000,
+-0xc00100c, 0x0, 0xd, 0x27bdffd8,
+-0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
+-0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
+-0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
+-0x0, 0x3c040001, 0x248451a4, 0x24050001,
+-0x2e03021, 0x3821, 0x3c100001, 0x26107e50,
+-0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
+-0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
+-0x24050003, 0x3c040001, 0x248451b0, 0x2003021,
+-0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
+-0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
+-0x370821, 0xa02083b0, 0x3c010001, 0x370821,
+-0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3,
+-0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8,
+-0x418c0, 0x24840001, 0x771021, 0xac40727c,
+-0x771021, 0xac407280, 0x2e31021, 0xa445727c,
+-0x2c820020, 0x1440fff7, 0x418c0, 0x2021,
+-0x3405c000, 0x418c0, 0x24840001, 0x771021,
+-0xac40737c, 0x771021, 0xac407380, 0x2e31021,
+-0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0,
+-0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040,
+-0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
+-0x8f420218, 0x30420002, 0x10400009, 0x0,
+-0x8f420220, 0x3c030002, 0x34630004, 0x431025,
+-0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004,
+-0x8f420220, 0x3c030002, 0x34630006, 0x431025,
+-0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc,
+-0x8f420218, 0x30420010, 0x1040000a, 0x0,
+-0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220,
+-0x3c03000a, 0x34630004, 0x431025, 0x800108a,
+-0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006,
+-0x431025, 0xaee204c0, 0x8f42021c, 0x34420006,
+-0xaee204c8, 0x8f420218, 0x30420200, 0x10400003,
+-0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248,
+-0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
+-0x8f820054, 0x8001099, 0x24630064, 0x8f820054,
+-0x621023, 0x2c420065, 0x1440fffc, 0x0,
+-0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010,
+-0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030,
+-0xaee20028, 0x24020490, 0xaee20018, 0xaf840090,
+-0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a,
+-0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025,
+-0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
+-0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
+-0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
+-0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
+-0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014,
+-0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
+-0x26e40030, 0xc002488, 0x24050400, 0x27440080,
+-0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
+-0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060,
+-0x8f420260, 0x27450200, 0x24060008, 0xaee20068,
+-0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a,
+-0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
+-0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
+-0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
+-0x641821, 0x90635c20, 0x2e41021, 0x24840001,
+-0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
+-0x8f820040, 0x2e41821, 0x24840001, 0x21702,
+-0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
+-0x96e2046a, 0x30420003, 0x14400009, 0x0,
+-0x96e2047a, 0x30420003, 0x50400131, 0x3c030800,
+-0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700,
+-0x96e2047a, 0x30420003, 0x10400026, 0x3c020700,
+-0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700,
+-0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00,
+-0xaee204c0, 0x8f420218, 0x30420100, 0x10400005,
+-0x0, 0x3c020001, 0x2442e168, 0x800111d,
+-0x21100, 0x3c020001, 0x2442d35c, 0x21100,
+-0x21182, 0x3c030800, 0x431025, 0x3c010001,
+-0xac221238, 0x3c020001, 0x2442f680, 0x21100,
+-0x21182, 0x3c030800, 0x431025, 0x3c010001,
+-0xac221278, 0x8ee20000, 0x34424000, 0x8001238,
+-0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608,
+-0x8f430228, 0x24420001, 0x304900ff, 0x512300e2,
+-0xafa00010, 0x8ee20608, 0x210c0, 0x571021,
+-0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610,
+-0x8f870120, 0x27623800, 0x24e80020, 0x102102b,
+-0x50400001, 0x27683000, 0x8f820128, 0x11020004,
+-0x0, 0x8f820124, 0x15020007, 0x1021,
+-0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
+-0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0,
+-0x801821, 0x8ee40430, 0x8ee50434, 0xa32821,
+-0xa3302b, 0x822021, 0x862021, 0xace40000,
+-0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e,
+-0x2402000d, 0xace20018, 0xace9001c, 0x318c0,
+-0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4,
+-0xace20010, 0xaf880120, 0x92e24e20, 0x14400037,
+-0x24060001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+-0x0, 0x800118a, 0x0, 0x14a00005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+-0xac800000, 0x80011a0, 0x0, 0x8ee24e30,
+-0x24030040, 0x24420001, 0x50430003, 0x1021,
+-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x24020007,
+-0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
+-0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010,
+-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0xc002403, 0x34a5f000, 0x8001223, 0x0,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
+-0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400037, 0x24060001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c830000, 0x24020012, 0x1462001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+-0x80011f1, 0x0, 0x14a00005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x8001207, 0x0, 0x8ee24e30, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020012, 0xac820000,
+-0x24020001, 0xac820004, 0x14c0001b, 0x0,
+-0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014,
+-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+-0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
+-0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc,
+-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
+-0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
+-0x248451e8, 0x3405f001, 0x24420001, 0xaee20160,
+-0x8ee20160, 0x3021, 0x3821, 0xafa00010,
+-0xc002403, 0xafa00014, 0x8001238, 0x0,
+-0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
+-0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
+-0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
+-0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
+-0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec,
+-0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
+-0x2442a390, 0x451024, 0x21082, 0xaee304c8,
+-0x3c030800, 0x431025, 0x3c010001, 0xac221220,
+-0x3c020001, 0x2442add4, 0x451024, 0x21082,
+-0x431025, 0x3c010001, 0xac221280, 0x96e6045a,
+-0x3821, 0x24050011, 0xafa00010, 0xc002403,
+-0xafa00014, 0x8001268, 0x0, 0x3c020001,
+-0x2442a9d4, 0x21100, 0x21182, 0x3c030800,
+-0x431025, 0x3c010001, 0xac221280, 0x96e2046a,
+-0x30420010, 0x14400009, 0x0, 0x96e2047a,
+-0x30420010, 0x10400112, 0x0, 0x96e2046a,
+-0x30420010, 0x10400005, 0x3c020700, 0x96e2047a,
+-0x30420010, 0x14400102, 0x3c020700, 0x34423000,
+-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+-0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
+-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+-0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
+-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+-0x8f820128, 0x11020004, 0x0, 0x8f820124,
+-0x15020007, 0x1021, 0x8ee201a4, 0x3021,
+-0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4,
+-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xace40000, 0xace50004, 0x8ee30608,
+-0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
+-0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
+-0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
+-0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10a20005, 0x0, 0x80012d4,
+-0x0, 0x14a00005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x80012ea,
+-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x24020007, 0xac820000, 0x24020001,
+-0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
+-0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
+-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
+-0x800136d, 0x0, 0x8f830120, 0x27623800,
+-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+-0x14c20007, 0x0, 0x8ee201a4, 0x3021,
+-0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4,
+-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+-0x24020011, 0xac620018, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10a20005, 0x0, 0x800133b, 0x0,
+-0x14a00005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400013, 0xac800000, 0x8001351, 0x0,
+-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020012, 0xac820000, 0x24020001, 0xac820004,
+-0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
+-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+-0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
+-0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
+-0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
+-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
+-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+-0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002,
+-0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
+-0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+-0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200,
+-0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
+-0xc004500, 0x0, 0xc002318, 0x0,
+-0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
+-0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8,
+-0x34a5c358, 0x27623800, 0xaee27258, 0x27623800,
+-0xaee27260, 0x27623800, 0xaee27264, 0x3661021,
+-0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0,
+-0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c,
+-0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c,
+-0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c,
+-0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268,
+-0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8,
+-0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100,
+-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+-0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
+-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+-0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
+-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+-0x8f820128, 0x11020004, 0x0, 0x8f820124,
+-0x15020007, 0x1021, 0x8ee201a4, 0x3021,
+-0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4,
+-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xace40000, 0xace50004, 0x8ee30608,
+-0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
+-0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
+-0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
+-0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10a20005, 0x0, 0x800140c,
+-0x0, 0x14a00005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x8001422,
+-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x24020007, 0xac820000, 0x24020001,
+-0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
+-0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
+-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
+-0x80014a5, 0x0, 0x8f830120, 0x27623800,
+-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+-0x14c20007, 0x0, 0x8ee201a4, 0x3021,
+-0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4,
+-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+-0x24020011, 0xac620018, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10a20005, 0x0, 0x8001473, 0x0,
+-0x14a00005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400013, 0xac800000, 0x8001489, 0x0,
+-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020012, 0xac820000, 0x24020001, 0xac820004,
+-0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
+-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+-0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
+-0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
+-0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
+-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
+-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+-0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
+-0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd,
+-0x0, 0x8f820040, 0x30420001, 0x14400008,
+-0x0, 0x8f430104, 0x24020001, 0x10620004,
+-0x0, 0x8f420264, 0x10400006, 0x0,
+-0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5,
+-0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044,
+-0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178,
+-0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c,
+-0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021,
+-0xaee2726c, 0xc004064, 0x0, 0xc004440,
+-0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008,
+-0x27bd0028, 0x3e00008, 0x0, 0x3e00008,
+-0x0, 0x0, 0x0, 0x2402002c,
+-0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278,
+-0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88,
+-0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
+-0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
+-0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
+-0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067,
+-0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
+-0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
+-0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
+-0x431025, 0xaee20000, 0x8f420218, 0x30420100,
+-0x104000c6, 0x0, 0x8f8200b0, 0x30420004,
+-0x104000c2, 0x0, 0x3c030001, 0x771821,
+-0x8c6383d0, 0x8f820104, 0x146200b4, 0x0,
+-0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4,
+-0x146200ae, 0x0, 0x8f8200b0, 0x3c030080,
+-0x431024, 0x1040000d, 0x0, 0x8f82011c,
+-0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
+-0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
+-0x431024, 0x80015cc, 0xaf82011c, 0x3c030001,
+-0x771821, 0x8c6383d0, 0x8f820104, 0x14620082,
+-0x0, 0x3c030001, 0x771821, 0x8c6383d4,
+-0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
+-0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
+-0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0,
+-0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
+-0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
+-0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20006, 0x0, 0x8ee201a4,
+-0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4,
+-0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008,
+-0x24020400, 0xa462000e, 0x2402000f, 0xac620018,
+-0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4,
+-0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
+-0x0, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+-0x0, 0x800158a, 0x0, 0x14a00005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+-0xac800000, 0x80015a0, 0x0, 0x8ee24e30,
+-0x24030040, 0x24420001, 0x50430003, 0x1021,
+-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x24020007,
+-0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
+-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
+-0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
+-0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c,
+-0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
+-0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
+-0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284,
+-0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
+-0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
+-0x34a50900, 0x80015cc, 0x0, 0x8f820104,
+-0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4,
+-0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274,
+-0x92e304f4, 0x24420067, 0x14600006, 0xaee27274,
+-0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b,
+-0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004,
+-0x0, 0x92e204f4, 0x50400074, 0xa2e004f4,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+-0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
+-0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
+-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c830000, 0x24020012, 0x1462001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+-0x8001621, 0x0, 0x14a00005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x8001637, 0x0, 0x8ee24e30, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020012, 0xac820000,
+-0x24020001, 0xac820004, 0x5600000b, 0x24100001,
+-0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014,
+-0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
+-0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
+-0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4,
+-0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c,
+-0x1040006d, 0x0, 0x8f830120, 0x27623800,
+-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+-0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4,
+-0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
+-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+-0x24020011, 0xac620018, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10a20005, 0x0, 0x8001697, 0x0,
+-0x14a00005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400013, 0xac800000, 0x80016ad, 0x0,
+-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020012, 0xac820000, 0x24020001, 0xac820004,
+-0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
+-0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c,
+-0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
+-0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
+-0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
+-0x0, 0xaee04e24, 0x8f820040, 0x30420001,
+-0x14400008, 0x0, 0x8f430104, 0x24020001,
+-0x10620004, 0x0, 0x8f420264, 0x10400006,
+-0x0, 0x8ee2017c, 0x24420001, 0xaee2017c,
+-0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004,
+-0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178,
+-0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278,
+-0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238,
+-0x104002aa, 0x0, 0x3c020001, 0x571021,
+-0x904283e0, 0x144002a5, 0x0, 0x8f420080,
+-0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084,
+-0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088,
+-0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090,
+-0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098,
+-0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0,
+-0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8,
+-0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0,
+-0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8,
+-0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c,
+-0xaee0003c, 0x41080, 0x571021, 0x8ee3003c,
+-0x8c420244, 0x24840001, 0x621821, 0x2c82000f,
+-0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc,
+-0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x8021, 0x24420001, 0xaee201a4, 0x8001775,
+-0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030,
+-0xac620008, 0x24020400, 0xa462000e, 0x2402000f,
+-0xac620018, 0xac60001c, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
+-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10a20005, 0x0, 0x800175f, 0x0,
+-0x14a00005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400013, 0xac800000, 0x8001775, 0x0,
+-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020007, 0xac820000, 0x24020001, 0xac820004,
+-0x12000212, 0x3c020400, 0xafa20018, 0x3c020001,
+-0x571021, 0x904283b0, 0x1040010b, 0x0,
+-0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
+-0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
+-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+-0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
+-0x1221023, 0x2c420033, 0x1040006a, 0x5821,
+-0x24180008, 0x240f000d, 0x240d0007, 0x240c0040,
+-0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
+-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+-0x11020004, 0x0, 0x8f820124, 0x15020007,
+-0x1021, 0x8ee201a4, 0x8021, 0x24420001,
+-0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608,
+-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+-0xa32821, 0xa3302b, 0x822021, 0x862021,
+-0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e,
+-0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
+-0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
+-0xaf880120, 0x92e24e20, 0x14400033, 0x24100001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x80017e0,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400010, 0xac800000, 0x80017f3,
+-0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001,
+-0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
+-0x0, 0x316300ff, 0x24020001, 0x14620077,
+-0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054,
+-0x24690032, 0x1221023, 0x2c420033, 0x10400061,
+-0x5821, 0x240d0008, 0x240c0011, 0x24080012,
+-0x24070040, 0x240a0001, 0x8f830120, 0x27623800,
+-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+-0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4,
+-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+-0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400033, 0x24100001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x1448001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x10470007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x800184c,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400010, 0xac800000, 0x800185f,
+-0x0, 0x8ee24e30, 0x24420001, 0x50470003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0xac880000, 0xac8a0004, 0x56000006, 0x240b0001,
+-0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
+-0x0, 0x316300ff, 0x24020001, 0x14620003,
+-0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
+-0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
+-0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
+-0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120,
+-0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
+-0x800197c, 0x0, 0x3c040001, 0x248452bc,
+-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
+-0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
+-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120,
+-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+-0x27683000, 0x8f820128, 0x11020004, 0x0,
+-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+-0x8021, 0x24420001, 0xaee201a4, 0x80018f7,
+-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0xace40000, 0xace50004,
+-0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d,
+-0xace20018, 0xace9001c, 0x318c0, 0x2463060c,
+-0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010,
+-0xaf880120, 0x92e24e20, 0x14400037, 0x24100001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c830000, 0x24020007, 0x1462001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+-0x80018e1, 0x0, 0x14a00005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x80018f7, 0x0, 0x8ee24e30, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+-0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
+-0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014,
+-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+-0x34a5f000, 0x800197c, 0x0, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x8021, 0x24420001, 0xaee201a4, 0x800195e,
+-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+-0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008,
+-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10a20005, 0x0, 0x8001948,
+-0x0, 0x14a00005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x800195e,
+-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x24020012, 0xac820000, 0x24020001,
+-0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
+-0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608,
+-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
+-0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
+-0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014,
+-0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
+-0xc002403, 0x0, 0x8ee201ac, 0x8021,
+-0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
+-0x24020001, 0x3c010001, 0x370821, 0xa02083b0,
+-0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
+-0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
+-0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
+-0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84,
+-0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
+-0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
+-0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
+-0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228,
+-0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010,
+-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
+-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+-0x1040006a, 0x5821, 0x24180008, 0x240f000d,
+-0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
+-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+-0x27683000, 0x8f820128, 0x11020004, 0x0,
+-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+-0x8021, 0x24420001, 0xaee201a4, 0x8001a15,
+-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0xace40000, 0xace50004,
+-0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
+-0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
+-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+-0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+-0x0, 0x8001a02, 0x0, 0x14600005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+-0xac800000, 0x8001a15, 0x0, 0x8ee24e30,
+-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
+-0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
+-0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
+-0x24020001, 0x54620078, 0xafa00010, 0xaeea0608,
+-0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
+-0x2c420033, 0x10400061, 0x5821, 0x240d0008,
+-0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+-0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+-0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+-0x0, 0x8001a6e, 0x0, 0x14600005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+-0xac800000, 0x8001a81, 0x0, 0x8ee24e30,
+-0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
+-0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
+-0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
+-0x24020001, 0x10620022, 0x0, 0x3c040001,
+-0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
+-0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
+-0x8001aad, 0x0, 0x3c040001, 0x248452b0,
+-0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
+-0xc002403, 0x34a5f010, 0x8001aad, 0x0,
+-0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608,
+-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
+-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+-0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
+-0x8ee204d4, 0x30420001, 0x10400055, 0x0,
+-0x8f420218, 0x30420080, 0x10400029, 0x0,
+-0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c,
+-0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000,
+-0x2407ffff, 0x2021, 0x461024, 0x1444000d,
+-0x671824, 0x1465000b, 0x0, 0x8ee27b80,
+-0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021,
+-0x461024, 0x14440003, 0x671824, 0x1065000b,
+-0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0,
+-0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044,
+-0x38420020, 0x8001b38, 0xaf820044, 0x8f820044,
+-0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044,
+-0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044,
+-0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4,
+-0x24060000, 0x2407ffff, 0x2021, 0x461024,
+-0x1444000d, 0x671824, 0x1465000b, 0x0,
+-0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4,
+-0x2021, 0x461024, 0x14440003, 0x671824,
+-0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+-0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80,
+-0x8f820044, 0x38420040, 0x8001b38, 0xaf820044,
+-0x8f820044, 0x34420040, 0x8001b38, 0xaf820044,
+-0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c,
+-0x24430001, 0x28420015, 0x14400028, 0xaee37b8c,
+-0x8f820044, 0x38420020, 0xaf820044, 0x8001b38,
+-0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011,
+-0x0, 0x8f420218, 0x30420080, 0x10400009,
+-0x0, 0x8f820044, 0x34420020, 0xaf820044,
+-0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36,
+-0xaf820044, 0x8f820044, 0x34420060, 0x8001b36,
+-0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
+-0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
+-0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
+-0xaee07b88, 0xc004603, 0x0, 0x8fbf0024,
+-0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
+-0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
+-0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
+-0x8f960064, 0x32c20004, 0x1040000c, 0x24020004,
+-0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060,
+-0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001,
+-0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
+-0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
+-0x0, 0x32c20002, 0x1440000c, 0x3c050003,
+-0x3c040001, 0x24845354, 0x34a50001, 0x2c03021,
+-0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+-0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
+-0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
+-0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
+-0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
+-0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360,
+-0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
+-0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
+-0x0, 0x80022ed, 0xaf960064, 0x93a20020,
+-0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
+-0x3c010001, 0x220821, 0x8c225418, 0x400008,
+-0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
+-0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
+-0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
+-0x8fa20020, 0x24030001, 0x3c010001, 0x370821,
+-0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060,
+-0x34420100, 0xaf820060, 0x8ee20144, 0x24420001,
+-0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020,
+-0x21200, 0x22502, 0x24020001, 0x10820005,
+-0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9,
+-0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074,
+-0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4,
+-0xaee40070, 0xaee40074, 0x621824, 0xaee304d4,
+-0x8f840054, 0x41442, 0x41c82, 0x431021,
+-0x41cc2, 0x431023, 0x41d02, 0x431021,
+-0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
+-0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020,
+-0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
+-0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
+-0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
+-0x920c0, 0x2e41021, 0x9442727c, 0x30424000,
+-0x1040000a, 0x971021, 0x97430212, 0xa443727e,
+-0x8f430214, 0x971021, 0xac437280, 0x2e41821,
+-0x34028000, 0x8001c79, 0xa462727c, 0x9443727e,
+-0x97420212, 0x14620006, 0x2e41021, 0x971021,
+-0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021,
+-0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff,
+-0x2021, 0x410c0, 0x2e21021, 0x9442737c,
+-0x30424000, 0x54400005, 0x803021, 0x24840001,
+-0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
+-0x618c0, 0x610c0, 0x571821, 0x8c63737c,
+-0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
+-0x24845378, 0xafa20014, 0x8f470214, 0x3c050003,
+-0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
+-0x97440212, 0x771021, 0xa444737e, 0x8f440214,
+-0x771021, 0x2e31821, 0xac447380, 0x34028000,
+-0xa462737c, 0x910c0, 0x2e21021, 0x8001c79,
+-0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e,
+-0x510c0, 0x9443737e, 0x97420212, 0x14620006,
+-0x510c0, 0x971021, 0x8c437380, 0x8f420214,
+-0x10620065, 0x510c0, 0x2e21021, 0x9445737c,
+-0x510c0, 0x2e21021, 0x9442737c, 0x30428000,
+-0x1040fff0, 0x971021, 0x520c0, 0x971021,
+-0x9443737e, 0x97420212, 0x14620006, 0x2406ffff,
+-0x971021, 0x8c437380, 0x8f420214, 0x10620053,
+-0x3c020800, 0x2021, 0x410c0, 0x2e21021,
+-0x9442737c, 0x30424000, 0x54400005, 0x803021,
+-0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
+-0x4c10023, 0x618c0, 0x910c0, 0x571821,
+-0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
+-0x3c040001, 0x24845384, 0xafa20014, 0x8f470214,
+-0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
+-0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
+-0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
+-0x571021, 0x8c4283b4, 0x24420001, 0x3c010001,
+-0x370821, 0xac2283b4, 0x3c030001, 0x771821,
+-0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c,
+-0x97440212, 0x771021, 0xa444737e, 0x8f440214,
+-0x771021, 0x2e31821, 0xac447380, 0x34028000,
+-0xa462737c, 0x510c0, 0x2e21021, 0xa446737c,
+-0x2021, 0x428c0, 0x2e51021, 0x9442777c,
+-0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa,
+-0x428c0, 0x92e204d8, 0x10400006, 0x24020001,
+-0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f,
+-0xaee304dc, 0x8f830228, 0x24020001, 0x1221004,
+-0x621825, 0xaf830228, 0x3c020800, 0x34421000,
+-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+-0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
+-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+-0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
+-0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
+-0x5821, 0x24100008, 0x240f000d, 0x240d0007,
+-0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
+-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+-0x8f820128, 0x11020004, 0x0, 0x8f820124,
+-0x15020007, 0x1021, 0x8ee201a4, 0x3821,
+-0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4,
+-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xace40000, 0xace50004, 0x8ee20608,
+-0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
+-0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
+-0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
+-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c820000, 0x144d001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+-0x8001cf5, 0x0, 0x14600005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+-0x8001d08, 0x0, 0x8ee24e30, 0x24420001,
+-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
+-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+-0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
+-0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
+-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+-0x10400061, 0x5821, 0x240e0008, 0x240d0011,
+-0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x3821, 0x24420001, 0xaee201a4, 0x8001d74,
+-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+-0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
+-0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
+-0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
+-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c820000, 0x144a001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x10480007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+-0x8001d61, 0x0, 0x14600005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+-0x8001d74, 0x0, 0x8ee24e30, 0x24420001,
+-0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
+-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+-0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
+-0x10620022, 0x0, 0x3c040001, 0x24845390,
+-0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
+-0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
+-0x0, 0x3c040001, 0x2484539c, 0xafa00014,
+-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+-0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
+-0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
+-0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
+-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
+-0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
+-0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
+-0x928c0, 0x2e51021, 0x9442727c, 0x30428000,
+-0x1040002f, 0x2e51021, 0x9442727c, 0x30424000,
+-0x1440001c, 0xb71021, 0x9443727e, 0x97420212,
+-0x14620018, 0xb71021, 0x8c437280, 0x8f420214,
+-0x54620016, 0xafa20010, 0x92e204d8, 0x10400007,
+-0x24020001, 0x8ee304dc, 0x1221004, 0x21027,
+-0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228,
+-0x1221004, 0x21027, 0x621824, 0xaf830228,
+-0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
+-0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
+-0x571021, 0x8c42727c, 0x3c040001, 0x248453b4,
+-0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
+-0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
+-0xb71021, 0x9443727e, 0x97420212, 0x14620019,
+-0x918c0, 0xb71021, 0x8c437280, 0x8f420214,
+-0x14620014, 0x918c0, 0x2e51021, 0x9447727c,
+-0x720c0, 0x971021, 0x9443737e, 0xb71021,
+-0xa443727e, 0x971021, 0x8c437380, 0xb71021,
+-0xac437280, 0x2e41021, 0x9443737c, 0x2e51021,
+-0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e,
+-0xa462737c, 0x2e31021, 0x9447727c, 0x3021,
+-0x720c0, 0x2e41021, 0x9442737c, 0x4021,
+-0x30428000, 0x14400025, 0xe02821, 0x605021,
+-0x340bc000, 0x971021, 0x9443737e, 0x97420212,
+-0x54620015, 0xe02821, 0x971021, 0x8c437380,
+-0x8f420214, 0x54620010, 0xe02821, 0x11000006,
+-0x2e41021, 0x9443737c, 0x510c0, 0x2e21021,
+-0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021,
+-0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c,
+-0x8001e28, 0x24060001, 0x510c0, 0x2e21021,
+-0x9447737c, 0x720c0, 0x2e41021, 0x9442737c,
+-0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff,
+-0x14400025, 0x2021, 0x720c0, 0x971021,
+-0x9443737e, 0x97420212, 0x1462000f, 0x910c0,
+-0x971021, 0x8c437380, 0x8f420214, 0x1462000a,
+-0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
+-0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
+-0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
+-0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010,
+-0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
+-0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
+-0x3c020800, 0x2021, 0x428c0, 0xb71021,
+-0x9443777e, 0x97420212, 0x5462002b, 0x24840001,
+-0xb71021, 0x8c437780, 0x8f420214, 0x54620026,
+-0x24840001, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4,
+-0x3c020001, 0x571021, 0x8c4283b4, 0x809021,
+-0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784,
+-0x2f02021, 0x2f12821, 0xc002490, 0x24060008,
+-0x26310008, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x26520001, 0x242102b, 0x1440fff5, 0x26100008,
+-0x3c040001, 0x972021, 0x8c8483b4, 0x24050008,
+-0x420c0, 0x2484777c, 0xc002488, 0x2e42021,
+-0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf,
+-0x428c0, 0x3c020800, 0x34422000, 0xafa20018,
+-0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
+-0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
+-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+-0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
+-0x1221023, 0x2c420033, 0x1040006a, 0x5821,
+-0x24100008, 0x240f000d, 0x240d0007, 0x240c0040,
+-0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
+-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+-0x11020004, 0x0, 0x8f820124, 0x15020007,
+-0x1021, 0x8ee201a4, 0x3821, 0x24420001,
+-0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608,
+-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+-0xa32821, 0xa3302b, 0x822021, 0x862021,
+-0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e,
+-0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
+-0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
+-0xaf880120, 0x92e24e20, 0x14400033, 0x24070001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x8001ee8,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400010, 0xac800000, 0x8001efb,
+-0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001,
+-0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
+-0x0, 0x316300ff, 0x24020001, 0x54620078,
+-0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054,
+-0x24690032, 0x1221023, 0x2c420033, 0x10400061,
+-0x5821, 0x240e0008, 0x240d0011, 0x240a0012,
+-0x24080040, 0x240c0001, 0x8f830120, 0x27623800,
+-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+-0x14c20007, 0x0, 0x8ee201a4, 0x3821,
+-0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4,
+-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+-0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400033, 0x24070001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x144a001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x10480007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x8001f54,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400010, 0xac800000, 0x8001f67,
+-0x0, 0x8ee24e30, 0x24420001, 0x50480003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
+-0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
+-0x0, 0x316300ff, 0x24020001, 0x10620022,
+-0x0, 0x3c040001, 0x24845390, 0xafa00010,
+-0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
+-0xc002403, 0x34a5f011, 0x8001f93, 0x0,
+-0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120,
+-0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
+-0x8001f93, 0x0, 0x3c040001, 0x248453a8,
+-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
+-0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
+-0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001,
+-0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020,
+-0x21200, 0x21d02, 0x24020001, 0x10620005,
+-0x24020002, 0x1062000d, 0x0, 0x8001fb7,
+-0xafa00010, 0x92e204d8, 0x14400006, 0x24020001,
+-0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
+-0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
+-0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
+-0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8,
+-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
+-0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
+-0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
+-0x22502, 0x24020001, 0x10820005, 0x24020002,
+-0x1082000f, 0x0, 0x8001fe3, 0xafa00010,
+-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+-0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
+-0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
+-0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
+-0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
+-0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4,
+-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
+-0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
+-0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
+-0x21d02, 0x24020001, 0x10620005, 0x24020002,
+-0x1062000e, 0x0, 0x8002011, 0xafa00010,
+-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+-0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
+-0x370821, 0x8002018, 0xa02283b3, 0x3c020001,
+-0x571021, 0x904283b2, 0x3c010001, 0x370821,
+-0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
+-0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
+-0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020,
+-0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
+-0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
+-0x27840208, 0x27450200, 0xc00249a, 0x24060008,
+-0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
+-0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
+-0x8ee20134, 0x8f460248, 0x2021, 0xc005108,
+-0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
+-0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
+-0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
+-0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070,
+-0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0,
+-0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070,
+-0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
+-0x27450200, 0x24060008, 0xaee20068, 0x24020006,
+-0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00,
+-0xaee2006c, 0x240203e8, 0x24040002, 0x24030001,
+-0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
+-0x30420008, 0x10400004, 0x0, 0xaee30108,
+-0x8002061, 0x2021, 0xaee40108, 0x2021,
+-0x3c030001, 0x641821, 0x90635c30, 0x2e41021,
+-0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
+-0x0, 0x8f820040, 0x2e41821, 0x24840001,
+-0x21702, 0x24420030, 0xa062009c, 0x2e41021,
+-0x80022e8, 0xa040009c, 0x24020001, 0x3c010001,
+-0x370821, 0xa02283e0, 0x240b0400, 0x24080014,
+-0x240a0040, 0x24090001, 0x8f830100, 0x27623000,
+-0x24660020, 0xc2102b, 0x50400001, 0x27662800,
+-0x8f820108, 0x10c20004, 0x0, 0x8f820104,
+-0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821,
+-0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8,
+-0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e,
+-0xac680018, 0xac60001c, 0xac640000, 0xac650004,
+-0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec,
+-0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001,
+-0x504a0003, 0x1021, 0x8ee24e28, 0x24420001,
+-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2,
+-0x0, 0x80022e8, 0x0, 0x3c020900,
+-0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244,
+-0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1,
+-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+-0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
+-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+-0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
+-0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
+-0x5821, 0x24100008, 0x240f000d, 0x240d0007,
+-0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
+-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+-0x8f820128, 0x11020004, 0x0, 0x8f820124,
+-0x15020007, 0x1021, 0x8ee201a4, 0x3821,
+-0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4,
+-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xace40000, 0xace50004, 0x8ee20608,
+-0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
+-0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
+-0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
+-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c820000, 0x144d001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+-0x8002119, 0x0, 0x14600005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+-0x800212c, 0x0, 0x8ee24e30, 0x24420001,
+-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
+-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+-0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
+-0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
+-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+-0x10400061, 0x5821, 0x240e0008, 0x240d0011,
+-0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x3821, 0x24420001, 0xaee201a4, 0x8002198,
+-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+-0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
+-0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
+-0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
+-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c820000, 0x144a001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x10480007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+-0x8002185, 0x0, 0x14600005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+-0x8002198, 0x0, 0x8ee24e30, 0x24420001,
+-0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
+-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+-0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
+-0x10620022, 0x0, 0x3c040001, 0x24845390,
+-0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
+-0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
+-0x0, 0x3c040001, 0x2484539c, 0xafa00014,
+-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+-0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
+-0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
+-0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
+-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
+-0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
+-0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168,
+-0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
+-0x27450200, 0x24060008, 0xc00249a, 0xaee20068,
+-0x8f820220, 0x30420008, 0x14400002, 0x24020001,
+-0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
+-0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
+-0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020,
+-0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
+-0x3c030700, 0x34631000, 0x431025, 0xafa20018,
+-0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
+-0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0,
+-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+-0xac440610, 0x8f870120, 0x27623800, 0x24e80020,
+-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+-0x11020004, 0x0, 0x8f820124, 0x15020007,
+-0x1021, 0x8ee201a4, 0x3821, 0x24420001,
+-0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608,
+-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+-0xa32821, 0xa3302b, 0x822021, 0x862021,
+-0xace40000, 0xace50004, 0x8ee30608, 0x24020008,
+-0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c,
+-0x318c0, 0x2463060c, 0x2e31021, 0xace20008,
+-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+-0x14400037, 0x24070001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
+-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10a20005, 0x0, 0x8002247, 0x0,
+-0x14a00005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400013, 0xac800000, 0x800225d, 0x0,
+-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020007, 0xac820000, 0x24020001, 0xac820004,
+-0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4,
+-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+-0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
+-0x0, 0x8f830120, 0x27623800, 0x24660020,
+-0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
+-0x10c20004, 0x0, 0x8f820124, 0x14c20007,
+-0x0, 0x8ee201a4, 0x3821, 0x24420001,
+-0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608,
+-0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c,
+-0xac620008, 0x24020008, 0xa462000e, 0x24020011,
+-0xac620018, 0xac640000, 0xac650004, 0x8ee204c4,
+-0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
+-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c830000, 0x24020012, 0x1462001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+-0x0, 0x80022ae, 0x0, 0x14a00005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+-0xac800000, 0x80022c4, 0x0, 0x8ee24e30,
+-0x24030040, 0x24420001, 0x50430003, 0x1021,
+-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x24020012,
+-0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
+-0x0, 0x3c040001, 0x248453fc, 0xafa00010,
+-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
+-0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
+-0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228,
+-0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
+-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
+-0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
+-0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c,
+-0x8f42010c, 0x14620009, 0x24020002, 0xaf820064,
+-0x8f820064, 0x14400005, 0x0, 0x8f43022c,
+-0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044,
+-0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034,
+-0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
+-0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014,
+-0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
+-0x24840001, 0x3021, 0x1071026, 0x30420001,
+-0x10400002, 0x81842, 0x6a1826, 0x604021,
+-0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
+-0x25290001, 0x125102b, 0x1440fff0, 0x0,
+-0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8,
+-0x27642800, 0xafbf0010, 0xc002488, 0x24051000,
+-0x24020021, 0xaf800100, 0xaf800104, 0xaf800108,
+-0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120,
+-0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134,
+-0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30,
+-0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040,
+-0x10400004, 0x0, 0x8f82011c, 0x34420004,
+-0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+-0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
+-0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
+-0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403,
+-0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
+-0x3c020400, 0x10620029, 0x43102b, 0x14400008,
+-0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
+-0x10620011, 0x0, 0x8002374, 0x0,
+-0x10620008, 0x3c024000, 0x1462001c, 0x0,
+-0x8ee20190, 0x24420001, 0xaee20190, 0x8002374,
+-0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c,
+-0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002,
+-0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
+-0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd,
+-0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001,
+-0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0,
+-0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
+-0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
+-0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
+-0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0,
+-0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
+-0x8021, 0x43102b, 0x14400008, 0x3c042000,
+-0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
+-0x0, 0x80023e0, 0x0, 0x10640003,
+-0x3c024000, 0x14620045, 0x0, 0x8f8200a0,
+-0x441024, 0x10400006, 0x0, 0x8ee20194,
+-0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194,
+-0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198,
+-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c,
+-0x30420200, 0x1040001b, 0x0, 0x8f8300a0,
+-0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001,
+-0x3c020001, 0x3442f000, 0x621024, 0x50400001,
+-0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0,
+-0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124,
+-0x8f820124, 0x27633000, 0x43102b, 0x10400005,
+-0x276237e0, 0xaf820124, 0x80023ca, 0x0,
+-0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024,
+-0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002,
+-0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
+-0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd,
+-0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001,
+-0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
+-0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
+-0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
+-0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012,
+-0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021,
+-0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
+-0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250,
+-0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
+-0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010,
+-0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94,
+-0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
+-0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004,
+-0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
+-0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
+-0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0,
+-0x62182b, 0x10600005, 0x0, 0x3c020001,
+-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+-0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
+-0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
+-0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
+-0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0,
+-0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
+-0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
+-0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
+-0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001,
+-0x8c425c40, 0xc09021, 0xe09821, 0x10800006,
+-0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
+-0x800244e, 0x0, 0x24a40008, 0xc002488,
+-0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001,
+-0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94,
+-0x45102b, 0x10400005, 0x0, 0x3c020001,
+-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+-0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001,
+-0x8c635d94, 0x8e020004, 0xac620004, 0xac710008,
+-0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94,
+-0x45102b, 0xac720010, 0xac730014, 0xac740018,
+-0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
+-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+-0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
+-0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
+-0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
+-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+-0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
+-0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd,
+-0x24840004, 0x3e00008, 0x0, 0x10c00007,
+-0x0, 0x8c820000, 0x24840004, 0x24c6fffc,
+-0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008,
+-0x0, 0x10c00007, 0x0, 0x8ca20000,
+-0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb,
+-0x24840004, 0x3e00008, 0x0, 0x3e00008,
+-0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4,
+-0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4,
+-0x8ee304fc, 0x21100, 0x626021, 0x95870008,
+-0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c,
+-0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b,
+-0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258,
+-0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003,
+-0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c,
+-0x8ee3726c, 0x441021, 0x62182b, 0x10600006,
+-0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8,
+-0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200,
+-0x1040014d, 0x4821, 0x96e2045a, 0x30420010,
+-0x10400149, 0x0, 0x8f840100, 0x27623000,
+-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+-0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001,
+-0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000,
+-0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e,
+-0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c,
+-0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec,
+-0x14400036, 0x24090001, 0x8ee24e28, 0x210c0,
+-0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f,
+-0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
+-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
+-0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
+-0x0, 0x8002516, 0x0, 0x14a00005,
+-0x0, 0x8f820108, 0x24420020, 0xaf820108,
+-0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
+-0xac800000, 0x800252c, 0x0, 0x8ee24e28,
+-0x24030040, 0x24420001, 0x50430003, 0x1021,
+-0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
+-0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
+-0xac820000, 0x24020001, 0xac820004, 0x1520000a,
+-0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
+-0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
+-0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
+-0x3641821, 0x24420010, 0x43102b, 0x14400073,
+-0x0, 0x8ee27264, 0x24480010, 0x3641021,
+-0x102102b, 0x14400002, 0x3c02ffff, 0x1024021,
+-0x8f850100, 0x27623000, 0x24a60020, 0xc2102b,
+-0x50400001, 0x27662800, 0x8f820108, 0x10c20004,
+-0x0, 0x8f820104, 0x14c20007, 0x2563000c,
+-0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
+-0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021,
+-0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e,
+-0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4,
+-0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025,
+-0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037,
+-0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e22021, 0x8c830000, 0x24020005, 0x1462001f,
+-0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
+-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
+-0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
+-0x0, 0x800258a, 0x0, 0x14a00005,
+-0x0, 0x8f820108, 0x24420020, 0xaf820108,
+-0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
+-0xac800000, 0x80025a0, 0x0, 0x8ee24e28,
+-0x24030040, 0x24420001, 0x50430003, 0x1021,
+-0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
+-0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
+-0xac820000, 0x24020001, 0xac820004, 0x1520000a,
+-0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
+-0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
+-0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
+-0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
+-0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
+-0x27662800, 0x8f820108, 0x10c20004, 0x0,
+-0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8,
+-0x4821, 0x24420001, 0xaee201a8, 0x800260d,
+-0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000,
+-0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e,
+-0x24020006, 0xaca20018, 0x24630010, 0xaca30008,
+-0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002,
+-0x431025, 0xaca20010, 0xaf860100, 0x92e204ec,
+-0x14400037, 0x24090001, 0x8ee24e28, 0x210c0,
+-0x24424e38, 0x2e22021, 0x8c830000, 0x24020005,
+-0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c,
+-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001,
+-0x10430007, 0x0, 0x8ee24e2c, 0x24420001,
+-0x10a20005, 0x0, 0x80025f7, 0x0,
+-0x14a00005, 0x0, 0x8f820108, 0x24420020,
+-0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011,
+-0x50400013, 0xac800000, 0x800260d, 0x0,
+-0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x24020005, 0xac820000, 0x24020001, 0xac820004,
+-0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
+-0x3c040001, 0x24845730, 0x3c050004, 0xafa20014,
+-0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
+-0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
+-0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
+-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+-0x14a20007, 0x24020006, 0x8ee201a8, 0x4821,
+-0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8,
+-0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e,
+-0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c,
+-0x8ee204c8, 0x3c030002, 0x431025, 0xac820010,
+-0xaf850100, 0x92e204ec, 0x14400037, 0x24090001,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x8c830000, 0x24020005, 0x1462001f, 0x0,
+-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+-0x8002661, 0x0, 0x14a00005, 0x0,
+-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x8002677, 0x0, 0x8ee24e28, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+-0x24020001, 0xac820004, 0x15200009, 0x3c050004,
+-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
+-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
+-0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
+-0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
+-0x431021, 0xac44000c, 0x8ee27258, 0xafa20018,
+-0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
+-0x10400004, 0x24620001, 0x2403fffe, 0x431024,
+-0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800,
+-0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007,
+-0x451024, 0x24630007, 0xaee27258, 0x8ee2726c,
+-0x8ee47258, 0x651824, 0x431023, 0xaee2726c,
+-0x3661021, 0x82202b, 0x14800004, 0x3c03ffff,
+-0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258,
+-0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800,
+-0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4,
+-0x14e20007, 0x0, 0x8ee201b4, 0x4821,
+-0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4,
+-0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
+-0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
+-0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
+-0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018,
+-0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
+-0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
+-0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
+-0x10620016, 0x28620003, 0x10400005, 0x24020001,
+-0x10620008, 0x0, 0x8002703, 0x0,
+-0x24020003, 0x10620017, 0x0, 0x8002703,
+-0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
+-0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
+-0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0,
+-0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
+-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703,
+-0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+-0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0,
+-0x8ee500e4, 0x401821, 0x1021, 0xa32821,
+-0xa3302b, 0x822021, 0x862021, 0xaee400e0,
+-0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff,
+-0x104001c1, 0x31a20200, 0x1040014d, 0x4821,
+-0x96e2045a, 0x30420010, 0x10400149, 0x0,
+-0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
+-0x50400001, 0x27652800, 0x8f820108, 0x10a20004,
+-0x0, 0x8f820104, 0x14a20006, 0x2402000c,
+-0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e,
+-0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264,
+-0x24060005, 0xa482000e, 0xac860018, 0xac830008,
+-0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010,
+-0xaf850100, 0x92e204ec, 0x14400036, 0x24090001,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x8c820000, 0x1446001f, 0x0, 0x8ee34e28,
+-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+-0x24420001, 0x10a20005, 0x0, 0x8002758,
+-0x0, 0x14a00005, 0x0, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x800276e,
+-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+-0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
+-0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
+-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
+-0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
+-0x43102b, 0x14400073, 0x0, 0x8ee27264,
+-0x24480010, 0x3641021, 0x102102b, 0x14400002,
+-0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000,
+-0x24a60020, 0xc2102b, 0x50400001, 0x27662800,
+-0x8f820108, 0x10c20004, 0x0, 0x8f820104,
+-0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821,
+-0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8,
+-0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004,
+-0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008,
+-0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8,
+-0x3c030002, 0x431025, 0xaca20010, 0xaf860100,
+-0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28,
+-0x210c0, 0x24424e38, 0x2e22021, 0x8c830000,
+-0x24020005, 0x1462001f, 0x0, 0x8ee34e28,
+-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+-0x24420001, 0x10a20005, 0x0, 0x80027cc,
+-0x0, 0x14a00005, 0x0, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x80027e2,
+-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+-0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
+-0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
+-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
+-0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
+-0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
+-0xc2102b, 0x50400001, 0x27662800, 0x8f820108,
+-0x10c20004, 0x0, 0x8f820104, 0x14c20007,
+-0x2563000c, 0x8ee201a8, 0x4821, 0x24420001,
+-0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c,
+-0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264,
+-0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018,
+-0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c,
+-0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010,
+-0xaf860100, 0x92e204ec, 0x14400037, 0x24090001,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x8c830000, 0x24020005, 0x1462001f, 0x0,
+-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+-0x8002839, 0x0, 0x14a00005, 0x0,
+-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x800284f, 0x0, 0x8ee24e28, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+-0x24020001, 0xac820004, 0x1520000a, 0x34028100,
+-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
+-0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
+-0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
+-0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
+-0x8f830100, 0x27623000, 0x24640020, 0x82102b,
+-0x50400001, 0x27642800, 0x8f820108, 0x10820004,
+-0x0, 0x8f820104, 0x14820007, 0x24050005,
+-0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
+-0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004,
+-0x8ee27264, 0xa467000e, 0xac650018, 0xac620008,
+-0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010,
+-0xaf840100, 0x92e204ec, 0x14400036, 0x24090001,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
+-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+-0x24420001, 0x10a20005, 0x0, 0x80028a0,
+-0x0, 0x14a00005, 0x0, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x80028b6,
+-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+-0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
+-0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4,
+-0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
+-0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
+-0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
+-0x34a53800, 0x441021, 0xaee2725c, 0x3651021,
+-0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264,
+-0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458,
+-0x24630001, 0x2442ffff, 0x621824, 0xaee304e4,
+-0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0,
+-0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
+-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0,
+-0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189,
+-0x0, 0x8ee204e8, 0x8ee304fc, 0x21100,
+-0x621821, 0x94670008, 0x92e204ed, 0x8c680000,
+-0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8,
+-0x34460400, 0x31420200, 0x1040001f, 0x0,
+-0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000,
+-0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264,
+-0x9464000e, 0x3c050001, 0x34a53800, 0x24420004,
+-0xaee27264, 0x8ee37264, 0x42400, 0x3651021,
+-0x3c010001, 0x370821, 0xac2483dc, 0x62182b,
+-0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff,
+-0x431021, 0xaee27264, 0x8ee27264, 0x8002917,
+-0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff,
+-0x44102a, 0x10400015, 0x0, 0x8f8200d8,
+-0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c,
+-0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001,
+-0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a,
+-0x10400006, 0x0, 0x8ee201b8, 0x24420001,
+-0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001,
+-0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc,
+-0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001,
+-0x571021, 0x8c4283d8, 0x1040002f, 0x5021,
+-0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
+-0x50400001, 0x27652800, 0x8f820108, 0x10a20032,
+-0x0, 0x8f820104, 0x10a2002f, 0x24020015,
+-0xac880000, 0xac890004, 0x8ee37264, 0xa487000e,
+-0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001,
+-0x771821, 0x8c6383dc, 0xac860010, 0x431025,
+-0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066,
+-0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e21821, 0x24020015, 0xac620000, 0x24020001,
+-0x80029bf, 0xac620004, 0x8f840100, 0x27623000,
+-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+-0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001,
+-0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000,
+-0xac890004, 0x8ee37264, 0xa487000e, 0xac820018,
+-0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c,
+-0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x8c830000, 0x24020005, 0x1462001f, 0x0,
+-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+-0x80029a9, 0x0, 0x14a00005, 0x0,
+-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x80029bf, 0x0, 0x8ee24e28, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+-0x24020001, 0xac820004, 0x1540000a, 0x24020001,
+-0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730,
+-0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
+-0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
+-0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
+-0x370821, 0xac2083d8, 0x3c010001, 0x370821,
+-0xac2083dc, 0x21100, 0x431021, 0xac44000c,
+-0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021,
+-0x24420007, 0x451024, 0x24630007, 0xaee27258,
+-0x8ee2726c, 0x8ee47258, 0x651824, 0x431023,
+-0xaee2726c, 0x3661021, 0x82202b, 0x14800004,
+-0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258,
+-0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073,
+-0x0, 0x8f830100, 0x27623000, 0x24640020,
+-0x82102b, 0x14400002, 0x5021, 0x27642800,
+-0x8f820108, 0x10820004, 0x0, 0x8f820104,
+-0x14820006, 0x24050005, 0x8ee201a8, 0x24420001,
+-0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000,
+-0xac690004, 0x8ee27264, 0xa467000e, 0xac650018,
+-0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c,
+-0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+-0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
+-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+-0x24420001, 0x10a20005, 0x0, 0x8002a30,
+-0x0, 0x14a00005, 0x0, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x8002a46,
+-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+-0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
+-0x24845748, 0x3c050004, 0xafa90010, 0xafa00014,
+-0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
+-0x8002a72, 0x0, 0x8ee27264, 0x451021,
+-0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
+-0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c,
+-0x3641021, 0x62182b, 0x14600004, 0x3c03ffff,
+-0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8,
+-0x96e20458, 0x24630001, 0x2442ffff, 0x621824,
+-0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005,
+-0x0, 0x8f820060, 0x2403fff7, 0x431024,
+-0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+-0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100,
+-0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040,
+-0x24630001, 0x50620003, 0x1021, 0x8ee24e2c,
+-0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c,
+-0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28,
+-0x8c870004, 0x14620007, 0xa03021, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2,
+-0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e2c, 0x24420001,
+-0x210c0, 0x24424e38, 0x2e22021, 0x8c820004,
+-0x8f830108, 0x21140, 0x621821, 0xaf830108,
+-0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
+-0x104000c1, 0x31080, 0x3c010001, 0x220821,
+-0x8c225770, 0x400008, 0x0, 0x8ee204f0,
+-0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
+-0x43102b, 0x144000be, 0x0, 0x8ee304e4,
+-0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x8021, 0x24420001, 0xaee201a4, 0x8002b12,
+-0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
+-0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
+-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10a20005, 0x0, 0x8002afc,
+-0x0, 0x14a00005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x8002b12,
+-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x24020012, 0xac820000, 0x24020001,
+-0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
+-0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
+-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+-0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
+-0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
+-0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0,
+-0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274,
+-0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184,
+-0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee20504,
+-0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018,
+-0x21080, 0x571021, 0x8c440508, 0x24020003,
+-0x1462000f, 0x0, 0x3c020001, 0x571021,
+-0x904283b1, 0x10400014, 0x0, 0x8ee201d0,
+-0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8,
+-0x641821, 0x306300ff, 0x8002b59, 0xaee35240,
+-0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc,
+-0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10,
+-0x441021, 0xaee201d8, 0x8ee20000, 0x34420040,
+-0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
+-0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
+-0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
+-0x3c040001, 0x24845760, 0xafa60014, 0xafa20010,
+-0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
+-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+-0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
+-0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048,
+-0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104,
+-0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
+-0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
+-0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
+-0x31080, 0x3c010001, 0x220821, 0x8c2257c0,
+-0x400008, 0x0, 0x9663000e, 0x8ee2725c,
+-0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
+-0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
+-0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c,
+-0x82202b, 0x148003b9, 0x0, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x8021, 0x24420001, 0xaee201a4, 0x8002bfe,
+-0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
+-0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
+-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x8002be8,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400013, 0xac800000, 0x8002bfe,
+-0x0, 0x8ee24e30, 0x240c0040, 0x24420001,
+-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
+-0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
+-0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
+-0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
+-0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
+-0x240c0001, 0x8002f19, 0x0, 0x966c001c,
+-0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024,
+-0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc,
+-0x151900, 0x621021, 0x8c52000c, 0x92e27b98,
+-0x641821, 0x9476000a, 0x14400003, 0x32c20002,
+-0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021,
+-0x96e2045a, 0x30420002, 0x10400047, 0x0,
+-0x8e63001c, 0x8ee204fc, 0x32100, 0x821021,
+-0x8c42000c, 0x37e1821, 0x24420022, 0x43102b,
+-0x1440000a, 0x24050014, 0x8ee204fc, 0x821021,
+-0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e,
+-0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc,
+-0x821021, 0x8c42000c, 0x9450000e, 0x94430010,
+-0x94440012, 0x94450014, 0x2038021, 0x2048021,
+-0x2058021, 0x94430016, 0x94440018, 0x9445001a,
+-0x2038021, 0x2048021, 0x2058021, 0x9443001c,
+-0x9444001e, 0x94420020, 0x2038021, 0x2048021,
+-0x2028021, 0x101c02, 0x3202ffff, 0x628021,
+-0x8e63001c, 0x8ee204fc, 0x102402, 0x32900,
+-0xa21021, 0x8c43000c, 0x3202ffff, 0x828021,
+-0x37e1021, 0x24630018, 0x62182b, 0x14600009,
+-0x0, 0x8ee204fc, 0xa21021, 0x8c43000c,
+-0x101027, 0x3c01ffff, 0x230821, 0x8002c6f,
+-0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c,
+-0x101027, 0xa4620018, 0x96e2045a, 0x8821,
+-0x30420008, 0x14400063, 0xa021, 0x8e63001c,
+-0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c,
+-0x37e1821, 0x24420022, 0x43102b, 0x14400035,
+-0x0, 0x8ee204fc, 0xc21021, 0x8c42000c,
+-0x24470010, 0x37e1021, 0xe2102b, 0x50400001,
+-0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021,
+-0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b,
+-0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc,
+-0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a,
+-0x37e1021, 0xe2102b, 0x14400002, 0x2838821,
+-0xeb3821, 0x94e20000, 0x24e70002, 0x2228821,
+-0x37e1021, 0xe2102b, 0x50400001, 0xeb3821,
+-0x94e20000, 0x24e70002, 0x2228821, 0x37e1021,
+-0xe2102b, 0x50400001, 0xeb3821, 0x94e20000,
+-0x24e70002, 0x2228821, 0x37e1021, 0xe2102b,
+-0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0,
+-0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c,
+-0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021,
+-0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec,
+-0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821,
+-0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821,
+-0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c,
+-0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020,
+-0x2238821, 0x2248821, 0x2228821, 0x111c02,
+-0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
+-0x628821, 0x32c20001, 0x104000b2, 0x0,
+-0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080,
+-0x10400008, 0x0, 0x92e27b98, 0x14400005,
+-0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c,
+-0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021,
+-0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b,
+-0x14400008, 0xe02021, 0x2405000e, 0xc002f75,
+-0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09,
+-0x2028021, 0x94e60000, 0x24e70002, 0x94e50000,
+-0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000,
+-0x24e70002, 0x94e40000, 0x24e70002, 0x2068021,
+-0x2058021, 0x2038021, 0x2028021, 0x94e20000,
+-0x94e30002, 0x2048021, 0x2028021, 0x2038021,
+-0x101c02, 0x3202ffff, 0x628021, 0x101c02,
+-0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004,
+-0x3205ffff, 0x96620016, 0x8002d17, 0x512021,
+-0x96620016, 0x542021, 0x41402, 0x3083ffff,
+-0x432021, 0x852023, 0x41402, 0x822021,
+-0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4,
+-0x24430017, 0x37e1021, 0x62102b, 0x50400001,
+-0x6b1821, 0x90630000, 0x24020011, 0x14620031,
+-0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028,
+-0x43102b, 0x14400018, 0x0, 0x8ee27b9c,
+-0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff,
+-0x220821, 0x94220028, 0x822021, 0x41c02,
+-0x3082ffff, 0x622021, 0x32c20100, 0x14400004,
+-0x41027, 0x92e27b98, 0x14400002, 0x41027,
+-0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821,
+-0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008,
+-0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021,
+-0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
+-0x14400004, 0x41027, 0x92e27b98, 0x14400002,
+-0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a,
+-0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4,
+-0x24420032, 0x43102b, 0x14400018, 0x0,
+-0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4,
+-0x3c01ffff, 0x220821, 0x94220032, 0x822021,
+-0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
+-0x14400004, 0x41027, 0x92e27b98, 0x14400002,
+-0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff,
+-0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c,
+-0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032,
+-0x822021, 0x41c02, 0x3082ffff, 0x622021,
+-0x32c20100, 0x14400004, 0x41027, 0x92e27b98,
+-0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4,
+-0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821,
+-0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b,
+-0x1440001b, 0x34038100, 0x26430004, 0x37e1021,
+-0x62102b, 0x14400003, 0x602021, 0x6b1821,
+-0x602021, 0x8c620000, 0x24630004, 0xae420000,
+-0x37e1021, 0x62102b, 0x50400001, 0x6b1821,
+-0x8c620000, 0xac820000, 0x34028100, 0xa4620000,
+-0x24630002, 0x37e1021, 0x62102b, 0x50400001,
+-0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000,
+-0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e,
+-0xa64c000a, 0xae420000, 0xae440004, 0x9662000e,
+-0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e,
+-0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018,
+-0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
+-0x10400004, 0x24620001, 0x2403fffe, 0x431024,
+-0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100,
+-0x8ee27ba8, 0x24430001, 0x210c0, 0x571021,
+-0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac,
+-0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072,
+-0x0, 0x8ee27ba8, 0x24430001, 0x210c0,
+-0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c,
+-0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063,
+-0x4821, 0x5021, 0x8f8200f0, 0x24480008,
+-0x27621800, 0x102102b, 0x50400001, 0x27681000,
+-0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4,
+-0x8021, 0x24420001, 0xaee201b4, 0x8002dfa,
+-0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021,
+-0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004,
+-0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088,
+-0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088,
+-0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c,
+-0x401821, 0x1021, 0xa32821, 0xa3382b,
+-0x822021, 0x872021, 0x8ee204fc, 0xc93021,
+-0x63100, 0xaee400e0, 0xaee500e4, 0xc23021,
+-0x94c2000a, 0x240c0002, 0x21142, 0x30430003,
+-0x106c0016, 0x28620003, 0x10400005, 0x240c0001,
+-0x106c0008, 0x0, 0x8002e3f, 0x0,
+-0x240c0003, 0x106c0017, 0x0, 0x8002e3f,
+-0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
+-0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
+-0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0,
+-0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
+-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f,
+-0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+-0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001,
+-0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98,
+-0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008,
+-0x27621800, 0xe2102b, 0x50400001, 0x27671000,
+-0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4,
+-0x8021, 0x24420001, 0xaee201b4, 0x8002e5d,
+-0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018,
+-0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0,
+-0x16000007, 0x0, 0x8ee20088, 0x24420001,
+-0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c,
+-0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002,
+-0x401821, 0x1021, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0x161142, 0x30430003,
+-0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003,
+-0x10400005, 0x240c0001, 0x106c0008, 0x0,
+-0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019,
+-0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8,
+-0x8ee300ec, 0x24630001, 0x2c640001, 0x441021,
+-0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec,
+-0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4,
+-0x24630001, 0x2c640001, 0x441021, 0xaee200f0,
+-0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0,
+-0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+-0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c,
+-0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff,
+-0x431024, 0x24840001, 0xaee204e4, 0xaee404f0,
+-0x8f42023c, 0x82202b, 0x148000b0, 0x0,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+-0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
+-0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
+-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c830000, 0x24020012, 0x1462001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+-0x8002ef1, 0x0, 0x14600005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x8002f07, 0x0, 0x8ee24e30, 0x240c0040,
+-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
+-0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
+-0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014,
+-0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
+-0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
+-0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
+-0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170,
+-0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274,
+-0xaee204f8, 0x8f42023c, 0x10400038, 0x0,
+-0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c,
+-0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001,
+-0x504c0003, 0x1021, 0x8ee20504, 0x24420001,
+-0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003,
+-0x21080, 0x571021, 0x146c000f, 0x8c440508,
+-0x3c020001, 0x571021, 0x904283b1, 0x10400014,
+-0x0, 0x8ee201d0, 0x8ee35240, 0x441021,
+-0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff,
+-0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10,
+-0x441021, 0xaee201cc, 0x8ee201d8, 0x641821,
+-0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8,
+-0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000,
+-0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0,
+-0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x8f820108,
+-0x27633000, 0x43102b, 0x14400002, 0x27622800,
+-0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e,
+-0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058,
+-0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048,
+-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068,
+-0x52843, 0x10a0000d, 0x3021, 0x3c030001,
+-0x34633800, 0x3c07ffff, 0x3631021, 0x82102b,
+-0x50400001, 0x872021, 0x94820000, 0x24840002,
+-0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02,
+-0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff,
+-0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88,
+-0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068,
+-0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058,
+-0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c,
+-0x8ee204d4, 0x8021, 0x30420001, 0x1440002a,
+-0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8,
+-0xe22023, 0x2c821000, 0x50400001, 0x24841000,
+-0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8,
+-0x3c02000a, 0x3442efff, 0x1032023, 0x44102b,
+-0x10400003, 0x3c02000a, 0x3442f000, 0x822021,
+-0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021,
+-0xa32821, 0xa3302b, 0x822021, 0x862021,
+-0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4,
+-0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021,
+-0x904283c0, 0x1040000b, 0x0, 0x3c140001,
+-0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821,
+-0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193,
+-0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007,
+-0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
+-0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
+-0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
+-0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0,
+-0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
+-0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
+-0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
+-0x2409821, 0x3c020080, 0x621024, 0x1040000a,
+-0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c,
+-0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc,
+-0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001,
+-0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080,
+-0x3c080020, 0x34078000, 0x24420001, 0xaee20080,
+-0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021,
+-0xc3102b, 0x14400007, 0x0, 0x106b0011,
+-0x0, 0x106a0015, 0x0, 0x8003049,
+-0x42042, 0x10650023, 0xa3102b, 0x14400005,
+-0x0, 0x10690019, 0x0, 0x8003049,
+-0x42042, 0x10680021, 0x0, 0x8003049,
+-0x42042, 0x8ee20034, 0x24420001, 0xaee20034,
+-0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec,
+-0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049,
+-0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0,
+-0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4,
+-0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049,
+-0x42042, 0x8ee20030, 0x24420001, 0xaee20030,
+-0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8,
+-0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042,
+-0x1087047c, 0x0, 0x800300e, 0x0,
+-0x3c020001, 0x571021, 0x904283b2, 0x14400084,
+-0x24020001, 0x3c030001, 0x771821, 0x906383b3,
+-0x1462007f, 0x3c020100, 0x8e430000, 0x621024,
+-0x1040006f, 0x2402ffff, 0x14620005, 0x24100001,
+-0x96430004, 0x3402ffff, 0x10620075, 0x0,
+-0x92e204d8, 0x14400072, 0x0, 0x3c020001,
+-0x571021, 0x8c4283b4, 0x28420005, 0x10400020,
+-0x3821, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x18400016, 0x2821, 0x96660000, 0x520c0,
+-0x971021, 0x9442777e, 0x14460009, 0x971021,
+-0x94437780, 0x96620002, 0x14620005, 0x971021,
+-0x94437782, 0x96620004, 0x50620008, 0x24070001,
+-0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001,
+-0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff,
+-0x10400440, 0x0, 0x80030d5, 0x0,
+-0x2402021, 0xc0022fe, 0x24050006, 0x3044001f,
+-0x428c0, 0x2e51021, 0x9442727c, 0x30424000,
+-0x14400434, 0xb71021, 0x9443727e, 0x96620000,
+-0x1462000b, 0x418c0, 0xb71021, 0x94437280,
+-0x96620002, 0x14620006, 0x418c0, 0xb71021,
+-0x94437282, 0x96620004, 0x10620035, 0x418c0,
+-0x2e31021, 0x9442727c, 0x30428000, 0x14400421,
+-0x2e31021, 0x944b727c, 0x96670000, 0xb28c0,
+-0xb71021, 0x9442737e, 0x80030b7, 0x3021,
+-0x420c0, 0x2e41021, 0x9443737c, 0x2e41021,
+-0x944b737c, 0x30638000, 0x14600010, 0xb28c0,
+-0xb71021, 0x9442737e, 0x1447fff5, 0x1602021,
+-0xb71021, 0x94437380, 0x96620002, 0x5462fff1,
+-0x420c0, 0xb71021, 0x94437382, 0x96620004,
+-0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff,
+-0x10400400, 0x0, 0x80030d5, 0x0,
+-0x97430202, 0x96420000, 0x146203fa, 0x0,
+-0x97430204, 0x96420002, 0x146203f6, 0x0,
+-0x97430206, 0x96420004, 0x146203f2, 0x0,
+-0x92420000, 0x3a030001, 0x30420001, 0x431024,
+-0x10400074, 0x2402ffff, 0x8e630000, 0x14620004,
+-0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002,
+-0x3c020001, 0x571021, 0x904283b2, 0x1440006a,
+-0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c,
+-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+-0x10400020, 0x3821, 0x3c020001, 0x571021,
+-0x8c4283b4, 0x18400016, 0x2821, 0x96660000,
+-0x520c0, 0x971021, 0x9442777e, 0x14460009,
+-0x971021, 0x94437780, 0x96620002, 0x14620005,
+-0x971021, 0x94437782, 0x96620004, 0x50620008,
+-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+-0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6,
+-0x0, 0x2402021, 0xc0022fe, 0x24050006,
+-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+-0x30424000, 0x144003af, 0xb71021, 0x9443727e,
+-0x96620000, 0x1462000b, 0x418c0, 0xb71021,
+-0x94437280, 0x96620002, 0x14620006, 0x418c0,
+-0xb71021, 0x94437282, 0x96620004, 0x10620027,
+-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+-0x1440039c, 0x2e31021, 0x944b727c, 0x96670000,
+-0xb28c0, 0xb71021, 0x9442737e, 0x800313c,
+-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+-0x2e41021, 0x944b737c, 0x30638000, 0x14600010,
+-0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5,
+-0x1602021, 0xb71021, 0x94437380, 0x96620002,
+-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+-0x96620004, 0x5462ffec, 0x420c0, 0x24060001,
+-0x30c200ff, 0x1040037b, 0x0, 0x800314f,
+-0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260,
+-0x54102b, 0x1040003a, 0x0, 0x8f8300e4,
+-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
+-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+-0xc002403, 0x34a5f003, 0x80034cc, 0x0,
+-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+-0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+-0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
+-0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
+-0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
+-0x96e20468, 0x54102b, 0x10400003, 0x0,
+-0x240f0001, 0xa3af0027, 0x12800301, 0x24160007,
+-0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c,
+-0x8f430280, 0x24420001, 0x304207ff, 0x106202d3,
+-0x0, 0x93a20027, 0x10400014, 0x0,
+-0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244,
+-0x8ee65244, 0x8ee35244, 0x21140, 0x24425248,
+-0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff,
+-0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0,
+-0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
+-0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18,
+-0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021,
+-0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010,
+-0x10400019, 0x0, 0x9642000c, 0x340f8100,
+-0x144f0015, 0x0, 0x3c020001, 0x571021,
+-0x904283c0, 0x14400010, 0x0, 0x9642000e,
+-0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000,
+-0x2694fffc, 0xae42000c, 0xae430008, 0xae440004,
+-0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037,
+-0x34420200, 0xa602000e, 0x8e020000, 0x8e030004,
+-0x3c040001, 0x34843800, 0x306a0007, 0x26a9823,
+-0x3641021, 0x262102b, 0x10400005, 0x28aa021,
+-0x2641023, 0x3621823, 0x3c020020, 0x439823,
+-0x26820007, 0x2404fff8, 0x9603000a, 0x446024,
+-0x6a1821, 0x6c102b, 0x10400002, 0x1803821,
+-0x603821, 0xae130018, 0x8f880120, 0x24e20007,
+-0x443824, 0x27623800, 0x25090020, 0x122102b,
+-0x50400001, 0x27693000, 0x8f820128, 0x11220004,
+-0x0, 0x8f820124, 0x15220007, 0x1401821,
+-0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
+-0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004,
+-0x1021, 0xad130008, 0xa507000e, 0xad160018,
+-0xad06001c, 0xa3302b, 0xa32823, 0x822023,
+-0x862023, 0xad040000, 0xad050004, 0x8ee204c0,
+-0xad020010, 0xaf890120, 0x92e24e20, 0x14400033,
+-0x24110001, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c820000, 0x1456001f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x10550007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+-0x8003239, 0x0, 0x14600005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+-0x800324c, 0x0, 0x8ee24e30, 0x24420001,
+-0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
+-0x3c050006, 0x8e020018, 0x3c040001, 0x24845890,
+-0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
+-0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
+-0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
+-0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004,
+-0xae440008, 0x96020016, 0x8003470, 0xa642000e,
+-0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e,
+-0x28a1023, 0xa602000a, 0x34620004, 0xa602000e,
+-0x8f880120, 0x27623800, 0x25090020, 0x122102b,
+-0x14400002, 0x306affff, 0x27693000, 0x8f820128,
+-0x11220004, 0x0, 0x8f820124, 0x15220007,
+-0x24040020, 0x8ee201a4, 0x8821, 0x24420001,
+-0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c,
+-0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004,
+-0xad100008, 0xad040018, 0x52940, 0xa01821,
+-0x1021, 0xe33821, 0xe3202b, 0xc23021,
+-0xc43021, 0xad060000, 0xad070004, 0x8ee2724c,
+-0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
+-0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
+-0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x0, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
+-0x10550007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10620005, 0x0, 0x80032b7, 0x0,
+-0x14600005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400010, 0xac800000, 0x80032ca, 0x0,
+-0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
+-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0xac960000,
+-0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
+-0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
+-0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
+-0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
+-0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
+-0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
+-0x24630001, 0x306307ff, 0x26e25244, 0x15a20006,
+-0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
+-0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
+-0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073,
+-0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
+-0x8f430240, 0x43102b, 0x14400176, 0xa021,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
+-0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
+-0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
+-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400033, 0x24110001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x144e001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x10550007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x800333c,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400010, 0xac800000, 0x800334f,
+-0x0, 0x8ee24e30, 0x24420001, 0x50550003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
+-0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014,
+-0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
+-0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
+-0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
+-0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120,
+-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+-0x27663000, 0x8f820128, 0x10c20004, 0x0,
+-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+-0x8821, 0x24420001, 0xaee201a4, 0x80033ba,
+-0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8,
+-0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008,
+-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+-0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
+-0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+-0x1062001b, 0x0, 0x8c820004, 0x24420001,
+-0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
+-0x10550007, 0x0, 0x8ee24e34, 0x24420001,
+-0x10620005, 0x0, 0x80033a7, 0x0,
+-0x14600005, 0x0, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+-0x50400010, 0xac800000, 0x80033ba, 0x0,
+-0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
+-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
+-0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
+-0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
+-0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
+-0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
+-0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
+-0xa021, 0x960c000a, 0x183102b, 0x54400001,
+-0x1801821, 0xa603000a, 0x8f880120, 0x27623800,
+-0x25090020, 0x122102b, 0x50400001, 0x27693000,
+-0x8f820128, 0x11220004, 0x0, 0x8f820124,
+-0x15220007, 0x24040020, 0x8ee201a4, 0x8821,
+-0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4,
+-0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e,
+-0x24040004, 0xad100008, 0xad040018, 0x52940,
+-0xa01821, 0x1021, 0xe33821, 0xe3202b,
+-0xc23021, 0xc43021, 0xad060000, 0xad070004,
+-0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010,
+-0xaf890120, 0x92e24e20, 0x14400033, 0x24110001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x1456001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x10550007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x800341c,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400010, 0xac800000, 0x800342f,
+-0x0, 0x8ee24e30, 0x24420001, 0x50550003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0xac960000, 0xac9e0004, 0x1620001d, 0x0,
+-0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
+-0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
+-0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
+-0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
+-0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
+-0xae430004, 0xae440008, 0x96020016, 0xa642000e,
+-0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e,
+-0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
+-0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821,
+-0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a,
+-0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821,
+-0x93202b, 0x10800003, 0x3c02fff5, 0x34421000,
+-0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001,
+-0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004,
+-0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
+-0xa3a00027, 0x1680fd29, 0x0, 0x12800024,
+-0x0, 0x3c010001, 0x370821, 0xac3483c4,
+-0x3c010001, 0x370821, 0xac3383c8, 0x3c010001,
+-0x370821, 0xac3283cc, 0x93a20037, 0x10400008,
+-0x0, 0x3c020001, 0x571021, 0x8c4283cc,
+-0x24420004, 0x3c010001, 0x370821, 0xac2283cc,
+-0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff,
+-0x14620006, 0x0, 0x8ee201c4, 0x24420001,
+-0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc,
+-0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc,
+-0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
+-0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0xaee400c0, 0xaee500c4,
+-0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003,
+-0x14400017, 0x24020003, 0x15e20015, 0x0,
+-0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
+-0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
+-0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
+-0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
+-0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc,
+-0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
+-0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
+-0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
+-0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070,
+-0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060,
+-0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050,
+-0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044,
+-0xa821, 0xafb00030, 0x8021, 0xafbf004c,
+-0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038,
+-0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001,
+-0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4,
+-0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
+-0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
+-0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
+-0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
+-0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
+-0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
+-0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001,
+-0x571021, 0x904283c0, 0x1040000b, 0x0,
+-0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001,
+-0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021,
+-0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
+-0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
+-0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
+-0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
+-0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014,
+-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
+-0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
+-0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
+-0x10400058, 0x2408821, 0x3c020080, 0x621024,
+-0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
+-0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
+-0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004,
+-0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
+-0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
+-0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
+-0x10660021, 0xc3102b, 0x14400007, 0x0,
+-0x106b0011, 0x0, 0x106a0015, 0x0,
+-0x8003592, 0x42042, 0x10650023, 0xa3102b,
+-0x14400005, 0x0, 0x10690019, 0x0,
+-0x8003592, 0x42042, 0x10680021, 0x0,
+-0x8003592, 0x42042, 0x8ee20034, 0x24420001,
+-0xaee20034, 0x8ee20034, 0x8003592, 0x42042,
+-0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
+-0x8003592, 0x42042, 0x8ee201f0, 0x24420001,
+-0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042,
+-0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
+-0x8003592, 0x42042, 0x8ee20030, 0x24420001,
+-0xaee20030, 0x8ee20030, 0x8003592, 0x42042,
+-0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
+-0x42042, 0x108702b7, 0x0, 0x8003557,
+-0x0, 0x3c020001, 0x571021, 0x904283b2,
+-0x14400084, 0x24020001, 0x3c030001, 0x771821,
+-0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
+-0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
+-0x24100001, 0x96430004, 0x3402ffff, 0x10620075,
+-0x0, 0x92e204d8, 0x14400072, 0x0,
+-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+-0x10400020, 0x3821, 0x3c020001, 0x571021,
+-0x8c4283b4, 0x18400016, 0x2821, 0x96260000,
+-0x520c0, 0x971021, 0x9442777e, 0x14460009,
+-0x971021, 0x94437780, 0x96220002, 0x14620005,
+-0x971021, 0x94437782, 0x96220004, 0x50620008,
+-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+-0x30e200ff, 0x1040027b, 0x0, 0x800361e,
+-0x0, 0x2402021, 0xc0022fe, 0x24050006,
+-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+-0x30424000, 0x1440026f, 0xb71021, 0x9443727e,
+-0x96220000, 0x1462000b, 0x418c0, 0xb71021,
+-0x94437280, 0x96220002, 0x14620006, 0x418c0,
+-0xb71021, 0x94437282, 0x96220004, 0x10620035,
+-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+-0x1440025c, 0x2e31021, 0x9448727c, 0x96270000,
+-0x828c0, 0xb71021, 0x9442737e, 0x8003600,
+-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+-0x2e41021, 0x9448737c, 0x30638000, 0x14600010,
+-0x828c0, 0xb71021, 0x9442737e, 0x1447fff5,
+-0x1002021, 0xb71021, 0x94437380, 0x96220002,
+-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+-0x96220004, 0x5462ffec, 0x420c0, 0x24060001,
+-0x30c200ff, 0x1040023b, 0x0, 0x800361e,
+-0x0, 0x97430202, 0x96420000, 0x14620235,
+-0x0, 0x97430204, 0x96420002, 0x14620231,
+-0x0, 0x97430206, 0x96420004, 0x1462022d,
+-0x0, 0x92420000, 0x3a030001, 0x30420001,
+-0x431024, 0x10400074, 0x2402ffff, 0x8e230000,
+-0x14620004, 0x3402ffff, 0x96230004, 0x1062006f,
+-0x24140002, 0x3c020001, 0x571021, 0x904283b2,
+-0x1440006a, 0x24140003, 0x92e204d8, 0x14400067,
+-0x0, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x28420005, 0x10400020, 0x3821, 0x3c020001,
+-0x571021, 0x8c4283b4, 0x18400016, 0x2821,
+-0x96260000, 0x520c0, 0x971021, 0x9442777e,
+-0x14460009, 0x971021, 0x94437780, 0x96220002,
+-0x14620005, 0x971021, 0x94437782, 0x96220004,
+-0x50620008, 0x24070001, 0x3c020001, 0x571021,
+-0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
+-0x520c0, 0x30e200ff, 0x14400044, 0x24140003,
+-0x800384a, 0x0, 0x2402021, 0xc0022fe,
+-0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
+-0x9442727c, 0x30424000, 0x144001ea, 0xb71021,
+-0x9443727e, 0x96220000, 0x1462000b, 0x418c0,
+-0xb71021, 0x94437280, 0x96220002, 0x14620006,
+-0x418c0, 0xb71021, 0x94437282, 0x96220004,
+-0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
+-0x30428000, 0x144001d7, 0x2e31021, 0x9448727c,
+-0x96270000, 0x828c0, 0xb71021, 0x9442737e,
+-0x8003685, 0x3021, 0x420c0, 0x2e41021,
+-0x9443737c, 0x2e41021, 0x9448737c, 0x30638000,
+-0x14600010, 0x828c0, 0xb71021, 0x9442737e,
+-0x1447fff5, 0x1002021, 0xb71021, 0x94437380,
+-0x96220002, 0x5462fff1, 0x420c0, 0xb71021,
+-0x94437382, 0x96220004, 0x5462ffec, 0x420c0,
+-0x24060001, 0x30c200ff, 0x104001b6, 0x0,
+-0x8003698, 0x24140003, 0x24140001, 0x8f420260,
+-0x53102b, 0x10400049, 0x0, 0x8f8300e4,
+-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
+-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+-0xc002403, 0x34a5f003, 0x8003850, 0x0,
+-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+-0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+-0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
+-0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
+-0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
+-0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884,
+-0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
+-0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
+-0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
+-0x53102b, 0x54400001, 0x3c158000, 0x12600131,
+-0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280,
+-0x24420001, 0x304207ff, 0x10620108, 0x0,
+-0x12a00014, 0x0, 0x8ee35240, 0x8ee25244,
+-0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244,
+-0x21140, 0x24425248, 0x2e28021, 0x24630001,
+-0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0,
+-0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0,
+-0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb,
+-0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18,
+-0x21140, 0x24420e20, 0x2e28021, 0x24630001,
+-0x306801ff, 0x96e2046a, 0x30420010, 0x10400017,
+-0x34028100, 0x9643000c, 0x14620014, 0x0,
+-0x3c020001, 0x571021, 0x904283c0, 0x1440000f,
+-0x0, 0x9642000e, 0xa6020016, 0x8e420008,
+-0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c,
+-0xae430008, 0xae440004, 0x9602000e, 0x26310004,
+-0x24160001, 0x34420200, 0xa602000e, 0x9603000a,
+-0x2605021, 0x73102b, 0x10400002, 0x2606821,
+-0x605021, 0x2d42003d, 0x1040002a, 0x3821,
+-0x9623000c, 0x24020800, 0x54620027, 0xae110018,
+-0x3c020001, 0x571021, 0x904283c0, 0x54400022,
+-0xae110018, 0x26220017, 0x182102b, 0x10400013,
+-0x0, 0x3c02fff5, 0x511021, 0x90421017,
+-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+-0x621825, 0x10600013, 0x26220010, 0x182102b,
+-0x1040000e, 0x0, 0x3c07fff5, 0xf13821,
+-0x94e71010, 0x800375e, 0x24e7000e, 0x92220017,
+-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+-0x621825, 0x50600004, 0xae110018, 0x96270010,
+-0x24e7000e, 0xae110018, 0x3c020001, 0x571021,
+-0x904283c0, 0x2102b, 0x14e00002, 0x24ec0,
+-0x1403821, 0x8f830120, 0x27623800, 0x24660020,
+-0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
+-0x10c20004, 0x0, 0x8f820124, 0x14c20007,
+-0x2402000b, 0x8ee201a4, 0x4821, 0x24420001,
+-0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000,
+-0x8e050004, 0xac620018, 0x1751025, 0x491025,
+-0xac710008, 0xa467000e, 0xac62001c, 0xac640000,
+-0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120,
+-0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020007, 0x14620020, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001c, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30,
+-0x24020040, 0x24630001, 0x10620007, 0x0,
+-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+-0x80037a9, 0x0, 0x14a00005, 0x0,
+-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+-0x80037bf, 0x0, 0x8ee24e30, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+-0x24020001, 0xac820004, 0x15200018, 0x3c050006,
+-0x8e020018, 0x3c040001, 0x24845890, 0xafa20010,
+-0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
+-0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
+-0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
+-0xa642000c, 0xae430000, 0xae440004, 0xae450008,
+-0x96020016, 0x80037f8, 0xa642000e, 0x154d000a,
+-0x0, 0x9602000e, 0xa613000a, 0x34420004,
+-0xa602000e, 0x3c010001, 0x370821, 0xa02083c0,
+-0x80037f6, 0x9821, 0x9604000a, 0x93102b,
+-0x10400002, 0x2601821, 0x801821, 0x24020001,
+-0xa603000a, 0x3c010001, 0x370821, 0xa02283c0,
+-0x9604000a, 0x2248821, 0x191102b, 0x10400003,
+-0x3c02fff5, 0x34421000, 0x2228821, 0x2649823,
+-0xa821, 0x1660fef4, 0xadc80000, 0x12600021,
+-0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4,
+-0x3c010001, 0x370821, 0xac3183c8, 0x3c010001,
+-0x370821, 0x10400008, 0xac3283cc, 0x3c020001,
+-0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
+-0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280,
+-0x24420001, 0x14620006, 0x0, 0x8ee201c4,
+-0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4,
+-0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850,
+-0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821,
+-0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821,
+-0xa3302b, 0x822021, 0x862021, 0x24020002,
+-0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003,
+-0x14400017, 0x24020003, 0x16820015, 0x0,
+-0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
+-0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
+-0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
+-0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
+-0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc,
+-0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
+-0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
+-0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
+-0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c,
+-0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c,
+-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+-0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021,
+-0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058,
+-0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
+-0x8ee204d4, 0x8821, 0x24150001, 0x30420001,
+-0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4,
+-0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
+-0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
+-0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
+-0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
+-0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
+-0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
+-0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001,
+-0x571021, 0x904283c0, 0x1040000b, 0x0,
+-0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001,
+-0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021,
+-0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
+-0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
+-0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
+-0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
+-0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014,
+-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
+-0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
+-0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
+-0x10400058, 0x2408021, 0x3c020080, 0x621024,
+-0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
+-0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
+-0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004,
+-0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
+-0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
+-0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
+-0x10660021, 0xc3102b, 0x14400007, 0x0,
+-0x106b0011, 0x0, 0x106a0015, 0x0,
+-0x8003916, 0x42042, 0x10650023, 0xa3102b,
+-0x14400005, 0x0, 0x10690019, 0x0,
+-0x8003916, 0x42042, 0x10680021, 0x0,
+-0x8003916, 0x42042, 0x8ee20034, 0x24420001,
+-0xaee20034, 0x8ee20034, 0x8003916, 0x42042,
+-0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
+-0x8003916, 0x42042, 0x8ee201f0, 0x24420001,
+-0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042,
+-0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
+-0x8003916, 0x42042, 0x8ee20030, 0x24420001,
+-0xaee20030, 0x8ee20030, 0x8003916, 0x42042,
+-0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
+-0x42042, 0x1087033e, 0x0, 0x80038db,
+-0x0, 0x3c020001, 0x571021, 0x904283b2,
+-0x14400084, 0x24020001, 0x3c030001, 0x771821,
+-0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
+-0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
+-0x24110001, 0x96430004, 0x3402ffff, 0x10620075,
+-0x0, 0x92e204d8, 0x14400072, 0x0,
+-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+-0x10400020, 0x3821, 0x3c020001, 0x571021,
+-0x8c4283b4, 0x18400016, 0x2821, 0x96060000,
+-0x520c0, 0x971021, 0x9442777e, 0x14460009,
+-0x971021, 0x94437780, 0x96020002, 0x14620005,
+-0x971021, 0x94437782, 0x96020004, 0x50620008,
+-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+-0x30e200ff, 0x10400302, 0x0, 0x80039a2,
+-0x0, 0x2402021, 0xc0022fe, 0x24050006,
+-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+-0x30424000, 0x144002f6, 0xb71021, 0x9443727e,
+-0x96020000, 0x1462000b, 0x418c0, 0xb71021,
+-0x94437280, 0x96020002, 0x14620006, 0x418c0,
+-0xb71021, 0x94437282, 0x96020004, 0x10620035,
+-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+-0x144002e3, 0x2e31021, 0x944d727c, 0x96070000,
+-0xd28c0, 0xb71021, 0x9442737e, 0x8003984,
+-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+-0x2e41021, 0x944d737c, 0x30638000, 0x14600010,
+-0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5,
+-0x1a02021, 0xb71021, 0x94437380, 0x96020002,
+-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+-0x96020004, 0x5462ffec, 0x420c0, 0x24060001,
+-0x30c200ff, 0x104002c2, 0x0, 0x80039a2,
+-0x0, 0x97430202, 0x96420000, 0x146202bc,
+-0x0, 0x97430204, 0x96420002, 0x146202b8,
+-0x0, 0x97430206, 0x96420004, 0x146202b4,
+-0x0, 0x92420000, 0x3a230001, 0x30420001,
+-0x431024, 0x10400074, 0x2402ffff, 0x8e030000,
+-0x14620004, 0x3402ffff, 0x96030004, 0x1062006f,
+-0x24150002, 0x3c020001, 0x571021, 0x904283b2,
+-0x1440006a, 0x24150003, 0x92e204d8, 0x14400067,
+-0x0, 0x3c020001, 0x571021, 0x8c4283b4,
+-0x28420005, 0x10400020, 0x3821, 0x3c020001,
+-0x571021, 0x8c4283b4, 0x18400016, 0x2821,
+-0x96060000, 0x520c0, 0x971021, 0x9442777e,
+-0x14460009, 0x971021, 0x94437780, 0x96020002,
+-0x14620005, 0x971021, 0x94437782, 0x96020004,
+-0x50620008, 0x24070001, 0x3c020001, 0x571021,
+-0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
+-0x520c0, 0x30e200ff, 0x14400044, 0x24150003,
+-0x8003c55, 0x0, 0x2402021, 0xc0022fe,
+-0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
+-0x9442727c, 0x30424000, 0x14400271, 0xb71021,
+-0x9443727e, 0x96020000, 0x1462000b, 0x418c0,
+-0xb71021, 0x94437280, 0x96020002, 0x14620006,
+-0x418c0, 0xb71021, 0x94437282, 0x96020004,
+-0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
+-0x30428000, 0x1440025e, 0x2e31021, 0x944d727c,
+-0x96070000, 0xd28c0, 0xb71021, 0x9442737e,
+-0x8003a09, 0x3021, 0x420c0, 0x2e41021,
+-0x9443737c, 0x2e41021, 0x944d737c, 0x30638000,
+-0x14600010, 0xd28c0, 0xb71021, 0x9442737e,
+-0x1447fff5, 0x1a02021, 0xb71021, 0x94437380,
+-0x96020002, 0x5462fff1, 0x420c0, 0xb71021,
+-0x94437382, 0x96020004, 0x5462ffec, 0x420c0,
+-0x24060001, 0x30c200ff, 0x1040023d, 0x0,
+-0x8003a1c, 0x24150003, 0x24150001, 0x8f420260,
+-0x53102b, 0x10400036, 0x0, 0x8f8300e4,
+-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+-0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0,
+-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+-0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
+-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+-0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+-0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
+-0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
+-0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
+-0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5,
+-0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280,
+-0x24420001, 0x304207ff, 0x1062019e, 0x0,
+-0x12c00012, 0x0, 0x8ee35240, 0x8ee25244,
+-0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024,
+-0x8ee35244, 0x21140, 0x24425248, 0x2e28821,
+-0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0,
+-0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
+-0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18,
+-0xb021, 0xafb80024, 0x8ee30e18, 0x21140,
+-0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff,
+-0x96e2046a, 0x30420010, 0x10400018, 0x34028100,
+-0x9643000c, 0x14620015, 0x0, 0x3c020001,
+-0x571021, 0x904283c0, 0x14400010, 0x0,
+-0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004,
+-0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008,
+-0xae440004, 0x9622000e, 0x26100004, 0x24180001,
+-0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000,
+-0x8e230004, 0x3c040001, 0x34843800, 0x2003021,
+-0x306a0007, 0x20a8023, 0x3641021, 0x202102b,
+-0x10400005, 0x26a9821, 0x2041023, 0x3621823,
+-0x3c020020, 0x438023, 0x26620007, 0x9623000a,
+-0x2418fff8, 0x58c824, 0x6a1821, 0x79102b,
+-0x10400002, 0x3206021, 0x606021, 0x1801821,
+-0x24620007, 0x2418fff8, 0x586024, 0x26c102b,
+-0x14400004, 0x1932823, 0x1832823, 0x8003ac3,
+-0xc31021, 0xd31021, 0x4a2023, 0x1c4102b,
+-0x54400001, 0x8f2021, 0x25420040, 0x4c102b,
+-0x14400035, 0x5821, 0x94c3000c, 0x24020800,
+-0x54620032, 0xae260018, 0x3c020001, 0x571021,
+-0x904283c0, 0x5440002d, 0xae260018, 0x24c20017,
+-0x1c2102b, 0x10400013, 0x0, 0x3c02fff5,
+-0x461021, 0x90421017, 0x38430006, 0x2c630001,
+-0x38420011, 0x2c420001, 0x621825, 0x10600014,
+-0x24c20010, 0x1c2102b, 0x1040000e, 0x0,
+-0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4,
+-0x2562000e, 0x90c20017, 0x38430006, 0x2c630001,
+-0x38420011, 0x2c420001, 0x621825, 0x10600005,
+-0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821,
+-0x1601821, 0x24620007, 0x2418fff8, 0x585824,
+-0xc31021, 0x4a2023, 0x1c4102b, 0x10400002,
+-0x1632823, 0x8f2021, 0xae260018, 0x3c020001,
+-0x571021, 0x904283c0, 0x2102b, 0x216c0,
+-0x15600002, 0xafa20044, 0x1805821, 0x30820001,
+-0x10400007, 0x4021, 0x90880000, 0x24840001,
+-0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021,
+-0x50a00012, 0x81c02, 0x2ca20002, 0x54400009,
+-0x24a5ffff, 0x94820000, 0x24840002, 0x1024021,
+-0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21,
+-0x8f2021, 0x90820000, 0x21200, 0x1024021,
+-0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff,
+-0x624021, 0x3108ffff, 0x1402821, 0x11400011,
+-0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff,
+-0x94820000, 0x24840002, 0x1024021, 0x1c4102b,
+-0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021,
+-0x90820000, 0x21200, 0x1024021, 0x14a0fff2,
+-0x2ca20002, 0x81c02, 0x3102ffff, 0x624021,
+-0x81c02, 0x3102ffff, 0x8f890120, 0x624021,
+-0x27623800, 0x25230020, 0x62102b, 0x14400002,
+-0x3108ffff, 0x27633000, 0x8f820128, 0x10620004,
+-0x0, 0x8f820124, 0x14620007, 0x1402821,
+-0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4,
+-0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004,
+-0x81400, 0x3448000b, 0xad300008, 0xa52b000e,
+-0xad280018, 0x8fb80044, 0x2021, 0x2961025,
+-0x581025, 0xad22001c, 0xe5102b, 0xe53823,
+-0xc43023, 0xc23023, 0xad260000, 0xad270004,
+-0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20,
+-0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002,
+-0x14400003, 0x24020011, 0x15020024, 0x0,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c830000, 0x24020012, 0x1462000f, 0x0,
+-0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0,
+-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+-0x8ee34e30, 0x24420001, 0x105e002a, 0x0,
+-0x8003ba8, 0x0, 0x8ee24e30, 0x24420001,
+-0x505e0003, 0x1021, 0x8ee24e30, 0x24420001,
+-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30,
+-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x105e0007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x8003bb4,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400012, 0xac800000, 0x8003bc9,
+-0x0, 0x8ee24e30, 0x24420001, 0x505e0003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020007, 0xac820000, 0x24020001, 0xac820004,
+-0x14e00019, 0x3c050006, 0x3c040001, 0x24845890,
+-0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
+-0x8e230004, 0x2203021, 0x1603821, 0xc002403,
+-0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
+-0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c,
+-0xae430000, 0xae440004, 0xae450008, 0x96220016,
+-0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823,
+-0x9622000e, 0xa623000a, 0x34420004, 0xa622000e,
+-0x3c010001, 0x370821, 0xa02083c0, 0x8003bff,
+-0x9821, 0x9624000a, 0x83102b, 0x54400001,
+-0x801821, 0x24020001, 0xa623000a, 0x3c010001,
+-0x370821, 0xa02283c0, 0x9622000a, 0x4a1821,
+-0x2038021, 0x1d0102b, 0x54400001, 0x20f8021,
+-0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e,
+-0xaf0d0000, 0x12600022, 0x0, 0x3c010001,
+-0x370821, 0xac3383c4, 0x3c010001, 0x370821,
+-0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc,
+-0x93a2002f, 0x10400008, 0x0, 0x3c020001,
+-0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
+-0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c,
+-0x14620006, 0x0, 0x8ee201c4, 0x24420001,
+-0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc,
+-0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc,
+-0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
+-0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0x24020002, 0xaee400c0,
+-0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017,
+-0x24020003, 0x16a20015, 0x0, 0x8ee200d0,
+-0x8ee300d4, 0x24630001, 0x2c640001, 0x441021,
+-0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55,
+-0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001,
+-0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc,
+-0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8,
+-0x8ee300cc, 0x24630001, 0x2c640001, 0x441021,
+-0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc,
+-0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008,
+-0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064,
+-0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054,
+-0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
+-0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14,
+-0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c,
+-0x8ee20e14, 0x622023, 0x4820001, 0x24840200,
+-0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004,
+-0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823,
+-0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff,
+-0x804821, 0x69102a, 0x54400001, 0x604821,
+-0x8f870100, 0x27623000, 0x24e80020, 0x102102b,
+-0x50400001, 0x27682800, 0x8f820108, 0x11020004,
+-0x0, 0x8f820104, 0x15020007, 0x1021,
+-0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8,
+-0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140,
+-0x801821, 0x8ee40460, 0x8ee50464, 0xa32821,
+-0xa3302b, 0x822021, 0x862021, 0xace40000,
+-0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e,
+-0x24020002, 0xace20018, 0x31940, 0x24630e20,
+-0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c,
+-0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec,
+-0x14400011, 0x24040001, 0x8ee24e28, 0x24030040,
+-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+-0x24424e38, 0x2e21821, 0x24020002, 0xac620000,
+-0x24020001, 0xac620004, 0x1480000e, 0x24030040,
+-0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
+-0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
+-0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd,
+-0x0, 0x8ee20500, 0x24420001, 0x50430003,
+-0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
+-0x8ee20500, 0x21080, 0x571021, 0xac490508,
+-0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14,
+-0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0,
+-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
+-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
+-0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074,
+-0x0, 0x8ee35238, 0x8ee2523c, 0x622023,
+-0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c,
+-0x43102b, 0x14400004, 0x24020100, 0x8ee3523c,
+-0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c,
+-0x431023, 0x2443ffff, 0x804821, 0x69102a,
+-0x54400001, 0x604821, 0x8f870100, 0x27623000,
+-0x24e80020, 0x102102b, 0x50400001, 0x27682800,
+-0x8f820108, 0x11020004, 0x0, 0x8f820104,
+-0x15020007, 0x1021, 0x8ee201a8, 0x2021,
+-0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8,
+-0x8ee4523c, 0x42140, 0x801821, 0x8ee40470,
+-0x8ee50474, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xace40000, 0xace50004, 0x8ee3523c,
+-0x91140, 0xa4e2000e, 0x24020003, 0xace20018,
+-0x31940, 0x24635248, 0x2e31021, 0xace20008,
+-0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010,
+-0xaf880100, 0x92e204ec, 0x14400011, 0x24040001,
+-0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
+-0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
+-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821,
+-0x24020003, 0xac620000, 0x24020001, 0xac620004,
+-0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
+-0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
+-0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403,
+-0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
+-0x24420001, 0x50430003, 0x1021, 0x8ee20500,
+-0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
+-0x571021, 0xac490508, 0x8ee2523c, 0x491021,
+-0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238,
+-0x14620005, 0x0, 0x8f820060, 0x2403feff,
+-0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124,
+-0x8f860128, 0x24020040, 0x24630001, 0x50620003,
+-0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34,
+-0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0,
+-0x24425038, 0x14830007, 0x2e22821, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8003d92,
+-0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001,
+-0x50430003, 0x1021, 0x8ee24e34, 0x24420001,
+-0x210c0, 0x24425038, 0x2e22821, 0x8ca20004,
+-0x8f830128, 0x21140, 0x621821, 0xaf830128,
+-0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
+-0x10400008, 0x31080, 0x3c010001, 0x220821,
+-0x8c2258f0, 0x400008, 0x0, 0x24020001,
+-0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
+-0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
+-0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
+-0x8f820124, 0x106202b0, 0x9821, 0x3c11001f,
+-0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012,
+-0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
+-0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
+-0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
+-0x220821, 0x8c225948, 0x400008, 0x0,
+-0x8f420218, 0x30420100, 0x10400007, 0x0,
+-0x95830016, 0x95820018, 0x621823, 0x31402,
+-0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
+-0x3044ffff, 0x436824, 0x3c030800, 0x431824,
+-0x11a00004, 0xad84001c, 0x41140, 0x8003dd8,
+-0x24425248, 0x41140, 0x24420e20, 0x2e25821,
+-0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e,
+-0x95840016, 0x8003ec0, 0x0, 0x8d690018,
+-0x4021, 0x952a0000, 0x25290002, 0x95270000,
+-0x25290002, 0x95260000, 0x25290002, 0x95250000,
+-0x25290002, 0x95240000, 0x25290002, 0x95230000,
+-0x25290002, 0x95220000, 0x25290002, 0x1475021,
+-0x1465021, 0x1455021, 0x1445021, 0x1435021,
+-0x1425021, 0xa1c02, 0x3142ffff, 0x625021,
+-0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a,
+-0x314effff, 0x30420002, 0x10400044, 0x5021,
+-0x25220014, 0x222102b, 0x10400014, 0x1201821,
+-0x2405000a, 0x2021, 0x223102b, 0x54400001,
+-0x721821, 0x94620000, 0x24630002, 0x24a5ffff,
+-0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff,
+-0x622021, 0x41402, 0x3083ffff, 0x431021,
+-0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000,
+-0x25290002, 0x95280000, 0x25290002, 0x95270000,
+-0x25290002, 0x95260000, 0x25290002, 0x95250000,
+-0x25290002, 0x95230000, 0x25290002, 0x95220000,
+-0x25290002, 0x95240000, 0x25290002, 0x1485021,
+-0x1475021, 0x1465021, 0x1455021, 0x1435021,
+-0x1425021, 0x95220000, 0x95230002, 0x1445021,
+-0x1425021, 0x1435021, 0xa1c02, 0x3142ffff,
+-0x625021, 0xa1c02, 0x3142ffff, 0x625021,
+-0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018,
+-0x9443000c, 0x24020800, 0x54620005, 0xa5680010,
+-0x9562000e, 0x34420002, 0xa562000e, 0xa5680010,
+-0x96e2046a, 0x2821, 0x30420008, 0x14400056,
+-0x3021, 0x8d630018, 0x24620024, 0x222102b,
+-0x10400034, 0x24690010, 0x229102b, 0x54400001,
+-0x1324821, 0x95250000, 0x24690014, 0x229102b,
+-0x10400002, 0x24a5ffec, 0x1324821, 0x95220000,
+-0x30420fff, 0x14400003, 0x25290002, 0x8003e60,
+-0x24130001, 0x9821, 0xa03021, 0x229102b,
+-0x54400001, 0x1324821, 0x91220001, 0x25290002,
+-0xa22821, 0x229102b, 0x54400001, 0x1324821,
+-0x25290002, 0x229102b, 0x54400001, 0x1324821,
+-0x95220000, 0x25290002, 0xa22821, 0x229102b,
+-0x54400001, 0x1324821, 0x95220000, 0x25290002,
+-0xa22821, 0x229102b, 0x54400001, 0x1324821,
+-0x95220000, 0x25290002, 0xa22821, 0x229102b,
+-0x54400001, 0x1324821, 0x95220000, 0x8003e99,
+-0xa22821, 0x94650010, 0x94620014, 0x24690016,
+-0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c,
+-0x24130001, 0x9821, 0xa03021, 0x91230001,
+-0x25290004, 0x95220000, 0x25290002, 0x95240000,
+-0x25290002, 0xa32821, 0xa22821, 0x95220000,
+-0x95230002, 0xa42821, 0xa22821, 0xa32821,
+-0x51c02, 0x30a2ffff, 0x622821, 0x51c02,
+-0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001,
+-0x1040001e, 0x2021, 0x95820016, 0x4e2023,
+-0x41402, 0x822021, 0x326200ff, 0x50400002,
+-0x862021, 0x852021, 0x41402, 0x822021,
+-0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018,
+-0x24430017, 0x223102b, 0x54400001, 0x721821,
+-0x90620000, 0x38430011, 0x2c630001, 0x38420006,
+-0x2c420001, 0x621825, 0x10600004, 0x0,
+-0x9562000e, 0x34420001, 0xa562000e, 0x9562000e,
+-0x240a0002, 0x30420004, 0x10400002, 0xa5640012,
+-0x240a0004, 0x8f880120, 0x27623800, 0x25090020,
+-0x122102b, 0x50400001, 0x27693000, 0x8f820128,
+-0x11220004, 0x0, 0x8f820124, 0x15220007,
+-0x24040020, 0x8ee201a4, 0x8021, 0x24420001,
+-0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c,
+-0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e,
+-0xad0a0018, 0x52940, 0xa01821, 0x1021,
+-0xe33821, 0xe3202b, 0xc23021, 0xc43021,
+-0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025,
+-0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
+-0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee,
+-0x2c630002, 0x39420011, 0x2c420001, 0x621825,
+-0x10600024, 0x0, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c820000, 0x1455000f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b,
+-0x0, 0x8003f2e, 0x0, 0x8ee24e30,
+-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020001, 0x8003f4e,
+-0xac950000, 0x8ee24e30, 0x210c0, 0x24425038,
+-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+-0x0, 0x8003f3a, 0x0, 0x14600005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400012,
+-0xac800000, 0x8003f4f, 0x0, 0x8ee24e30,
+-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+-0x24020001, 0xac820004, 0x1600000d, 0x0,
+-0x8f820120, 0x3c040001, 0x24845938, 0xafa00014,
+-0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
+-0xc002403, 0x34a50001, 0x8004057, 0x0,
+-0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
+-0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
+-0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
+-0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff,
+-0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240,
+-0x104000e5, 0x0, 0x8ee20e1c, 0x24420001,
+-0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c,
+-0x8f420240, 0x10400072, 0x0, 0x8ee20e1c,
+-0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b,
+-0x144000d5, 0x0, 0x8f830120, 0x27623800,
+-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+-0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4,
+-0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
+-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+-0x24020011, 0xac620018, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400034, 0x24100001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c820000, 0x1455001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+-0x0, 0x8003fc6, 0x0, 0x14600005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400011,
+-0xac800000, 0x8003fda, 0x0, 0x8ee24e30,
+-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x24020001, 0xac950000,
+-0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
+-0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
+-0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
+-0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
+-0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+-0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
+-0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
+-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+-0xaf860120, 0x92e24e20, 0x14400034, 0x24100001,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x8c820000, 0x1455001f, 0x0, 0x8ee34e30,
+-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+-0x24420001, 0x10540007, 0x0, 0x8ee24e34,
+-0x24420001, 0x10620005, 0x0, 0x8004030,
+-0x0, 0x14600005, 0x0, 0x8f820128,
+-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+-0x2c420011, 0x50400011, 0xac800000, 0x8004044,
+-0x0, 0x8ee24e30, 0x24420001, 0x50540003,
+-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+-0x24020001, 0xac950000, 0xac820004, 0x1600000b,
+-0x0, 0x8ee2724c, 0x3c040001, 0x248458a8,
+-0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
+-0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
+-0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
+-0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124,
+-0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c,
+-0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+-0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
+-0x27840208, 0x27450200, 0x24060008, 0xafbf0014,
+-0xc00249a, 0xafb00010, 0x2021, 0x24100001,
+-0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
+-0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
+-0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8,
+-0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0,
+-0x3c010001, 0xac235cc8, 0xc005108, 0x24050004,
+-0xc004822, 0x0, 0x8ee20000, 0x3c03feff,
+-0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
+-0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
+-0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
+-0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
+-0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
+-0x248459f0, 0xc002403, 0x3821, 0x8ee20280,
+-0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
+-0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
+-0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
+-0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214,
+-0x3821, 0x24420001, 0xaee20214, 0x8ee20214,
+-0x3c020300, 0x2021024, 0x10400027, 0x3c110400,
+-0xc00429b, 0x0, 0x3c020100, 0x2021024,
+-0x10400007, 0x0, 0x8ee20218, 0x24420001,
+-0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
+-0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
+-0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
+-0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008,
+-0x2003021, 0x431024, 0xaee20000, 0x8f820220,
+-0x3821, 0x3c030300, 0x481024, 0x431025,
+-0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
+-0x8004296, 0x0, 0x2111024, 0x1040001f,
+-0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
+-0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008,
+-0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
+-0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
+-0x3463ffff, 0x2002021, 0x431024, 0xc004e54,
+-0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
+-0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+-0x431024, 0x8004295, 0x511025, 0x2021024,
+-0x10400142, 0x0, 0x8ee2022c, 0x24420001,
+-0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff,
+-0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
+-0x8f830054, 0x8f820054, 0x800410e, 0x24630002,
+-0x8f820054, 0x621023, 0x2c420003, 0x1440fffc,
+-0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007,
+-0x10400012, 0x0, 0x8f8300e4, 0x2402fff8,
+-0xc21024, 0x1043000d, 0x0, 0x8f820054,
+-0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054,
+-0x821023, 0x2c420051, 0x10400004, 0x0,
+-0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220,
+-0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220,
+-0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8,
+-0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f,
+-0x3442ffff, 0x24680008, 0x48102b, 0x10400003,
+-0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8,
+-0x8f850120, 0x8f840124, 0x8004145, 0x6021,
+-0x27623800, 0x82102b, 0x50400001, 0x27643000,
+-0x10a40010, 0x318200ff, 0x8c820018, 0x38430007,
+-0x2c630001, 0x3842000b, 0x2c420001, 0x621825,
+-0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001,
+-0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008,
+-0x318200ff, 0x14400065, 0x0, 0x3c020001,
+-0x571021, 0x904283c0, 0x14400060, 0x0,
+-0x8f8400e4, 0xc41023, 0x218c3, 0x4620001,
+-0x24630200, 0x8f8900c4, 0x10600005, 0x24020001,
+-0x10620009, 0x0, 0x8004187, 0x0,
+-0x8ee20230, 0x1205821, 0x24420001, 0xaee20230,
+-0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a,
+-0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000,
+-0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001,
+-0x651821, 0x2c62233f, 0x14400040, 0x0,
+-0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8,
+-0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4,
+-0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a,
+-0x24420001, 0xaee20238, 0x8c840000, 0x3463f000,
+-0x8ee20238, 0x883823, 0x67102b, 0x54400001,
+-0xe33821, 0x3c020003, 0x34420d40, 0x47102b,
+-0x10400003, 0x0, 0x80041bc, 0x805821,
+-0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4,
+-0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003,
+-0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c,
+-0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b,
+-0x54400001, 0xe53821, 0x147102b, 0x54400007,
+-0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4,
+-0x8f8400e4, 0x1486ffef, 0x0, 0x14860005,
+-0x0, 0x1205821, 0xaf8600e4, 0x80041bc,
+-0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8,
+-0x3c03000a, 0x3463f000, 0x483823, 0x67102b,
+-0x54400001, 0xe33821, 0x3c020003, 0x34420d3f,
+-0x47102b, 0x54400007, 0x6021, 0x1683823,
+-0x67102b, 0x54400003, 0xe33821, 0x80041cf,
+-0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b,
+-0x14400016, 0x318200ff, 0x14400006, 0x0,
+-0x3c020001, 0x571021, 0x904283c0, 0x1040000f,
+-0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000,
+-0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c,
+-0x24020001, 0x641824, 0x3c010001, 0x370821,
+-0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8,
+-0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000,
+-0x623823, 0x87102b, 0x54400001, 0xe43821,
+-0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001,
+-0x431025, 0x10400008, 0x0, 0x8f820220,
+-0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000,
+-0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
+-0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
+-0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
+-0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0,
+-0x431024, 0x1040001d, 0x0, 0x10c4001b,
+-0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
+-0x24850008, 0x27622800, 0x50a20001, 0x27651800,
+-0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff,
+-0x431021, 0x4d1024, 0x24430010, 0x6b102b,
+-0x54400001, 0x6a1821, 0x12b102b, 0x54400001,
+-0x12a4821, 0x10690002, 0x10c1025, 0xac820004,
+-0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220,
+-0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002,
+-0xaf820220, 0x8f830054, 0x8f820054, 0x8004237,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff,
+-0x3463fffb, 0x431024, 0xaf820220, 0x6010055,
+-0x0, 0x8ee20228, 0x24420001, 0xaee20228,
+-0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+-0x431024, 0x34420004, 0xaf820220, 0x8f830054,
+-0x8f820054, 0x8004251, 0x24630002, 0x8f820054,
+-0x621023, 0x2c420003, 0x1440fffc, 0x0,
+-0x8f8600e0, 0x30c20007, 0x10400012, 0x0,
+-0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d,
+-0x0, 0x8f820054, 0x8f8300e0, 0x14c30009,
+-0x24440032, 0x8f820054, 0x821023, 0x2c420033,
+-0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9,
+-0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd,
+-0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007,
+-0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0,
+-0x240301f5, 0x8f8200e8, 0x673823, 0x718c0,
+-0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4,
+-0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021,
+-0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002,
+-0x441024, 0x431025, 0xaf820220, 0x8f830054,
+-0x8f820054, 0x800428d, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
+-0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+-0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8,
+-0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
+-0x24845a14, 0x3c050008, 0x24020001, 0x3c010001,
+-0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
+-0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8,
+-0x3c010001, 0xac225ccc, 0xc002403, 0x3821,
+-0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
+-0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
+-0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
+-0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4,
+-0x8f820044, 0x3c030600, 0x34632000, 0x34420020,
+-0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228,
+-0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010,
+-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
+-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+-0x1040006a, 0x5821, 0x24180008, 0x240f000d,
+-0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
+-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+-0x27683000, 0x8f820128, 0x11020004, 0x0,
+-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+-0x2821, 0x24420001, 0xaee201a4, 0x800433d,
+-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+-0x822021, 0x862021, 0xace40000, 0xace50004,
+-0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
+-0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
+-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+-0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+-0x0, 0x800432a, 0x0, 0x14600005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+-0xac800000, 0x800433d, 0x0, 0x8ee24e30,
+-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
+-0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
+-0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
+-0x24020001, 0x54620079, 0xafa00010, 0xaeea0608,
+-0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
+-0x2c420033, 0x10400061, 0x5821, 0x240d0008,
+-0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
+-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+-0x0, 0x8f820124, 0x14c20007, 0x0,
+-0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4,
+-0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+-0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
+-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+-0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
+-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+-0x0, 0x8c820004, 0x24420001, 0xac820004,
+-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
+-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+-0x0, 0x8004396, 0x0, 0x14600005,
+-0x0, 0x8f820128, 0x24420020, 0xaf820128,
+-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+-0xac800000, 0x80043a9, 0x0, 0x8ee24e30,
+-0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
+-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+-0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
+-0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
+-0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
+-0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
+-0x0, 0x3c040001, 0x24845a20, 0xafa00014,
+-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+-0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
+-0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124,
+-0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
+-0x0, 0x3c040001, 0x24845a38, 0xafa00014,
+-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+-0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
+-0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
+-0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
+-0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d,
+-0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008,
+-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
+-0x24020001, 0x3c010001, 0xac225cd8, 0xc002403,
+-0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
+-0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
+-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+-0x34420008, 0xaf820220, 0x2021, 0xc0052a2,
+-0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x3c120001,
+-0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001,
+-0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
+-0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
+-0x0, 0xd, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x80014d6,
+-0x0, 0x80014d8, 0x3c0a0001, 0x80014d8,
+-0x3c0a0002, 0x80014d8, 0x0, 0x80024a6,
+-0x0, 0x80014d8, 0x3c0a0003, 0x80014d8,
+-0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8,
+-0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66,
+-0x0, 0x80014d8, 0x3c0a0006, 0x80014d8,
+-0x3c0a0007, 0x80014d8, 0x0, 0x80014d8,
+-0x0, 0x80014d8, 0x0, 0x8002a75,
+-0x0, 0x80014d8, 0x3c0a000b, 0x80014d8,
+-0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a,
+-0x0, 0x8002339, 0x0, 0x80014d8,
+-0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4,
+-0x0, 0x80014d8, 0x3c0a000f, 0x80040a7,
+-0x0, 0x8004091, 0x0, 0x80014d8,
+-0x3c0a0010, 0x80014ee, 0x0, 0x80014d8,
+-0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8,
+-0x3c0a0013, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x3c030001,
+-0x34633800, 0x24050080, 0x2404001f, 0x2406ffff,
+-0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
+-0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4,
+-0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0,
+-0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8,
+-0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4,
+-0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0,
+-0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8,
+-0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004,
+-0x8f830040, 0x3c02f000, 0x621824, 0x3c025000,
+-0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
+-0x3c024000, 0x10620008, 0x24020800, 0x8004539,
+-0x0, 0x10620004, 0x24020800, 0x8004539,
+-0x0, 0x24020700, 0x3c010001, 0xac225cdc,
+-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+-0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001,
+-0xac205cc4, 0x8004545, 0x24630064, 0x8f820054,
+-0x621023, 0x2c420065, 0x1440fffc, 0x0,
+-0xc004d71, 0x0, 0x24040001, 0x2821,
+-0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018,
+-0x8f830054, 0x8f820054, 0x8004556, 0x24630064,
+-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+-0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
+-0x8f830054, 0x8f820054, 0x8004562, 0x24630064,
+-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+-0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
+-0x8f830054, 0x8f820054, 0x800456e, 0x24630064,
+-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+-0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c,
+-0x24050002, 0x8f830054, 0x8f820054, 0x800457b,
+-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+-0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
+-0x26105da2, 0xc00494c, 0x2003021, 0x97a60018,
+-0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0,
+-0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
+-0xc002403, 0xafa20010, 0x97a20018, 0x1040004c,
+-0x24036040, 0x96020000, 0x3042fff0, 0x1443000a,
+-0x24020020, 0x3c030001, 0x94635da0, 0x54620009,
+-0x24027830, 0x24020003, 0x3c010001, 0xac225cc4,
+-0x80045ac, 0x24020005, 0x3c030001, 0x94635da0,
+-0x24027830, 0x1462000f, 0x24030010, 0x3c020001,
+-0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003,
+-0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001,
+-0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6,
+-0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001,
+-0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4,
+-0x24020015, 0x1462000f, 0x0, 0x3c020001,
+-0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001,
+-0x3842f430, 0x2c420001, 0x621825, 0x10600005,
+-0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6,
+-0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810,
+-0x1462000b, 0x24020002, 0x3c020001, 0x94425da2,
+-0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
+-0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
+-0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
+-0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001,
+-0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4,
+-0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4,
+-0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001,
+-0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc,
+-0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2,
+-0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8,
+-0x491021, 0x3c010001, 0xac225dac, 0xafa30010,
+-0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020,
+-0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001,
+-0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014,
+-0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000,
+-0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc,
+-0x8004617, 0x34844240, 0x3c040004, 0x3c030001,
+-0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016,
+-0x0, 0x3c04003d, 0x800462f, 0x34840900,
+-0x3c020001, 0x8c427e38, 0x30428000, 0x10400005,
+-0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a,
+-0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc,
+-0x34844240, 0x24020005, 0x14620003, 0x0,
+-0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac,
+-0x8f830054, 0x441021, 0x431023, 0x44102b,
+-0x14400037, 0x0, 0x3c020001, 0x8c425cd0,
+-0x14400033, 0x0, 0x3c010001, 0x10c00025,
+-0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001,
+-0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc,
+-0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
+-0xa91024, 0x10400010, 0x0, 0x14a70008,
+-0x0, 0x8d020000, 0x441024, 0x1040000a,
+-0x0, 0x3c010001, 0x800465b, 0xac255ce0,
+-0x8d420000, 0x441024, 0x10400003, 0x0,
+-0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0,
+-0x6182b, 0x2c420001, 0x431024, 0x5440ffe5,
+-0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0,
+-0x3c010001, 0xac225dac, 0x1060002a, 0x24020001,
+-0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc,
+-0x3c020001, 0x8c425ce0, 0x10400022, 0x0,
+-0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001,
+-0x3c010001, 0xac205ccc, 0x3c010001, 0x370821,
+-0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001,
+-0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac,
+-0x24020008, 0x10620005, 0x24020001, 0xc004695,
+-0x0, 0x8004692, 0x0, 0x3c030001,
+-0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001,
+-0x8c637dd0, 0x10620003, 0x0, 0xc004e54,
+-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+-0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000,
+-0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0,
+-0x3442ffff, 0x621824, 0x14a40008, 0xaee30000,
+-0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001,
+-0x8c425cf4, 0x10620008, 0x0, 0x3c020001,
+-0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0,
+-0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8,
+-0x24020002, 0x10620169, 0x2c620003, 0x10400005,
+-0x24020001, 0x10620008, 0x0, 0x800481c,
+-0x0, 0x24020004, 0x106200b1, 0x24020001,
+-0x800481d, 0x0, 0x3c020001, 0x571021,
+-0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a,
+-0x31080, 0x3c010001, 0x220821, 0x8c225ac8,
+-0x400008, 0x0, 0x3c030001, 0x8c635dbc,
+-0x24020005, 0x14620014, 0x0, 0x3c020001,
+-0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822,
+-0x0, 0x24020002, 0x3c010001, 0x370821,
+-0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4,
+-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+-0x800481f, 0xac205c60, 0xc004822, 0x0,
+-0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60,
+-0x104000dd, 0x24020002, 0x3c010001, 0x370821,
+-0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4,
+-0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003,
+-0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf,
+-0x0, 0x3c030001, 0x8c635d00, 0x800478e,
+-0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001,
+-0x8cc67e3c, 0xc005108, 0x2021, 0x24020005,
+-0x3c010001, 0xac205cd4, 0x3c010001, 0x370821,
+-0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc,
+-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
+-0xafa00010, 0xc002403, 0xafa00014, 0x800481f,
+-0x0, 0x8f820220, 0x3c03f700, 0x431025,
+-0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004,
+-0x431024, 0x144000a9, 0x24020007, 0x8f830054,
+-0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
+-0x2c422710, 0x144000f8, 0x24020001, 0x800481d,
+-0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+-0x2021, 0xc005386, 0x2021, 0x3c030001,
+-0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008,
+-0x621024, 0x10400006, 0x0, 0x8f820214,
+-0x3c03ffff, 0x431024, 0x8004741, 0x3442251f,
+-0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
+-0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
+-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
+-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+-0x24020008, 0x3c010001, 0x370821, 0xac2283ac,
+-0x8f820220, 0x3c030004, 0x431024, 0x14400005,
+-0x0, 0x8f820220, 0x3c03f700, 0x431025,
+-0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005,
+-0x1462000a, 0x0, 0x3c020001, 0x94425da2,
+-0x24429fbc, 0x2c420004, 0x10400004, 0x24040018,
+-0x24050002, 0xc004d93, 0x24060020, 0xc0043dd,
+-0x0, 0x3c010001, 0x800481f, 0xac205d50,
+-0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
+-0x2c620008, 0x104000ac, 0x31080, 0x3c010001,
+-0x220821, 0x8c225ae8, 0x400008, 0x0,
+-0xc00429b, 0x0, 0x3c010001, 0xac205ccc,
+-0xaf800204, 0x3c010001, 0xc004822, 0xac207e20,
+-0x24020001, 0x3c010001, 0xac225ce4, 0x24020002,
+-0x3c010001, 0x370821, 0x800481f, 0xac2283ac,
+-0xc00489f, 0x0, 0x3c030001, 0x8c635ce4,
+-0x24020009, 0x14620090, 0x24020003, 0x3c010001,
+-0x370821, 0x800481f, 0xac2283ac, 0x3c020001,
+-0x8c427e38, 0x30424000, 0x10400005, 0x0,
+-0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff,
+-0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
+-0x8f830054, 0x80047b9, 0x24020004, 0x8f830054,
+-0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
+-0x2c422710, 0x14400074, 0x24020005, 0x3c010001,
+-0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
+-0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
+-0x3c010001, 0xac207e20, 0x8f830054, 0x24020006,
+-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+-0x800481f, 0xac235da4, 0x8f830054, 0x3c020001,
+-0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a,
+-0x14400059, 0x0, 0x24020007, 0x3c010001,
+-0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
+-0x3c04f700, 0x441025, 0xaf820220, 0x8f820220,
+-0x3c030300, 0x431024, 0x14400005, 0x1821,
+-0x8f820220, 0x24030001, 0x441025, 0xaf820220,
+-0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff,
+-0x3c040001, 0x8c845d98, 0x431024, 0x3442251f,
+-0xaf820214, 0x24020008, 0x3c010001, 0x370821,
+-0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74,
+-0x14400007, 0x24020001, 0x3c010001, 0xac227dd0,
+-0xc004e54, 0x8f840220, 0x800480c, 0x0,
+-0x8f820220, 0x3c030008, 0x431024, 0x14400017,
+-0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000,
+-0x2021, 0x3c030200, 0x431025, 0xc005386,
+-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
+-0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd,
+-0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+-0x2021, 0x800481f, 0x0, 0x3c020001,
+-0x8c425d74, 0x10400010, 0x0, 0x3c020001,
+-0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70,
+-0x14400009, 0x24020002, 0x3c010001, 0xac205d74,
+-0x3c010001, 0x800481f, 0xac225d70, 0x24020001,
+-0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
+-0x34420004, 0xaf820220, 0x8f820200, 0x3c060001,
+-0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002,
+-0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001,
+-0x10c20008, 0x0, 0x8004868, 0x0,
+-0x24020004, 0x10c20013, 0x24020001, 0x8004868,
+-0x0, 0x3c030001, 0x8c635cb8, 0x3c020001,
+-0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001,
+-0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022,
+-0x441025, 0x451025, 0x34420002, 0x8004867,
+-0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200,
+-0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74,
+-0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0,
+-0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0,
+-0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
+-0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001,
+-0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825,
+-0x431025, 0x451025, 0xaf820220, 0x3e00008,
+-0x0, 0x8f820220, 0x3c030001, 0x8c635cc8,
+-0x34420004, 0xaf820220, 0x24020001, 0x1062000f,
+-0x0, 0x8f830054, 0x8f820054, 0x24630002,
+-0x621023, 0x2c420003, 0x10400011, 0x0,
+-0x8f820054, 0x621023, 0x2c420003, 0x1040000c,
+-0x0, 0x8004879, 0x0, 0x8f830054,
+-0x8f820054, 0x8004885, 0x24630007, 0x8f820054,
+-0x621023, 0x2c420008, 0x1440fffc, 0x0,
+-0x8f8400e0, 0x30820007, 0x1040000d, 0x0,
+-0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032,
+-0x8f820054, 0xa21023, 0x2c420033, 0x10400004,
+-0x0, 0x8f8200e0, 0x1082fff9, 0x0,
+-0x8f820220, 0x2403fffd, 0x431024, 0xaf820220,
+-0x3e00008, 0x0, 0x3c030001, 0x8c635ce4,
+-0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff,
+-0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009,
+-0x1040009d, 0x31080, 0x3c010001, 0x220821,
+-0x8c225b08, 0x400008, 0x0, 0x8f820044,
+-0x34428080, 0xaf820044, 0x8f830054, 0x8004938,
+-0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8,
+-0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a,
+-0x24020003, 0x8004945, 0x0, 0x8f820044,
+-0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044,
+-0x8f830054, 0x8004938, 0x24020004, 0x8f830054,
+-0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023,
+-0x2c42000a, 0x14400078, 0x24020005, 0x8004945,
+-0x0, 0x8f820220, 0x3c03f700, 0x431025,
+-0xaf820220, 0x8f820220, 0x2403fffb, 0x431024,
+-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+-0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200,
+-0x2403fffd, 0x431024, 0xaf820200, 0x24040001,
+-0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054,
+-0x80048ec, 0x24630001, 0x8f820054, 0x621023,
+-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
+-0x42040, 0xa4102b, 0x1040fff2, 0x0,
+-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+-0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f,
+-0xaf820214, 0x8f820220, 0x2403fffb, 0x431024,
+-0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008,
+-0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00,
+-0x346300e2, 0x441025, 0xaf820220, 0xaf830200,
+-0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008,
+-0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000,
+-0x34630040, 0x3c020001, 0x24425c70, 0xac820000,
+-0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938,
+-0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8,
+-0x2463fff6, 0x431023, 0x2c42000a, 0x14400022,
+-0x24020007, 0x8004945, 0x0, 0x8f8200e0,
+-0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220,
+-0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7,
+-0x431024, 0xaf820220, 0x8f820044, 0x34428080,
+-0xaf820044, 0x8f830054, 0x24020008, 0x3c010001,
+-0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8,
+-0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0,
+-0x431023, 0x2c422710, 0x14400003, 0x24020009,
+-0x3c010001, 0xac225ce4, 0x3e00008, 0x0,
+-0x0, 0x0, 0x0, 0x27bdffd8,
+-0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
+-0xafb10014, 0xc08821, 0xafb00010, 0x8021,
+-0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d4b, 0x2021, 0xc004d4b, 0x24040001,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x24100010, 0x2501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d4b, 0x108042, 0x1600fffa,
+-0x2501024, 0x24100010, 0x2701024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x2701024, 0xc004d71, 0x34108000,
+-0xc004d71, 0x0, 0xc004d2b, 0x0,
+-0x50400005, 0x108042, 0x96220000, 0x501025,
+-0xa6220000, 0x108042, 0x1600fff7, 0x0,
+-0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c,
+-0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
+-0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
+-0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
+-0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0x24100010, 0x2301024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x2501024, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+-0x96620000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+-0x0, 0xc004d71, 0x0, 0x8fbf0020,
+-0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00,
+-0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020,
+-0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
+-0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349,
+-0x31080, 0x3c010001, 0x220821, 0x8c225b30,
+-0x400008, 0x0, 0xc004d71, 0x8021,
+-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b,
+-0x2021, 0x108042, 0x1600fffc, 0x0,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fff8, 0x0, 0xc004d71, 0x0,
+-0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010,
+-0x8021, 0xc004d4b, 0x24040001, 0x26100001,
+-0x2e020020, 0x1440fffb, 0x0, 0xc004d4b,
+-0x2021, 0xc004d4b, 0x24040001, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0x24100010,
+-0x32020001, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020001,
+-0x24100010, 0xc004d4b, 0x2021, 0x108042,
+-0x1600fffc, 0x0, 0xc004d71, 0x34108000,
+-0xc004d71, 0x0, 0xc004d2b, 0x0,
+-0x50400005, 0x108042, 0x96220000, 0x501025,
+-0xa6220000, 0x108042, 0x1600fff7, 0x0,
+-0xc004d71, 0x0, 0x97a20010, 0x30428000,
+-0x144002dc, 0x24020003, 0x8004d24, 0x0,
+-0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0xc004d4b, 0x2021, 0x108042, 0x1600fffc,
+-0x0, 0xc004d4b, 0x24040001, 0xc004d4b,
+-0x2021, 0x34108000, 0x96220000, 0x501024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fff8, 0x0, 0xc004d71,
+-0x0, 0x8f830054, 0x8004d16, 0x24020004,
+-0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c,
+-0x431023, 0x2c420064, 0x1440029e, 0x24020002,
+-0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003,
+-0x14400296, 0x24020011, 0x24020003, 0x10620005,
+-0x24020004, 0x10620291, 0x2402000f, 0x8004d24,
+-0x24020011, 0x8004d24, 0x24020005, 0x24020014,
+-0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020012, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+-0x96220000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+-0x0, 0xc004d71, 0x0, 0x8f830054,
+-0x8004d16, 0x24020006, 0x8f830054, 0x3c020001,
+-0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
+-0x14400250, 0x24020007, 0x8004d24, 0x0,
+-0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020013, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020013,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fff8, 0x0, 0xc004d71, 0x0,
+-0x8f830054, 0x8004d16, 0x24020008, 0x8f830054,
+-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x1440020f, 0x24020009, 0x8004d24,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004d71, 0x34108000, 0xc004d71, 0x0,
+-0xc004d2b, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004d71, 0x8021,
+-0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fff8, 0x0, 0xc004d71, 0x0,
+-0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054,
+-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020017, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
+-0xc004d71, 0x34108000, 0xc004d71, 0x0,
+-0xc004d2b, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004d71, 0x8021,
+-0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020017, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fff8, 0x0, 0xc004d71, 0x0,
+-0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054,
+-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x14400127, 0x24020012, 0x8004d24,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020014, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
+-0xc004d71, 0x34108000, 0xc004d71, 0x0,
+-0xc004d2b, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004d71, 0x8021,
+-0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020014, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fff8, 0x0, 0xc004d71, 0x0,
+-0x8f830054, 0x8004d16, 0x24020013, 0x8f830054,
+-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004d71, 0x34108000, 0xc004d71, 0x0,
+-0xc004d2b, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004d71, 0x8021,
+-0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
+-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fff8, 0x0, 0xc004d71, 0x0,
+-0x8f830054, 0x8004d16, 0x2402000e, 0x24020840,
+-0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x32020013, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+-0x96220000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+-0x0, 0xc004d71, 0x0, 0x8f830054,
+-0x24020010, 0x3c010001, 0xac225d00, 0x3c010001,
+-0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001,
+-0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
+-0x14400004, 0x0, 0x24020011, 0x3c010001,
+-0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+-0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
+-0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
+-0x8f840054, 0x8f820054, 0xa32824, 0x8004d37,
+-0x24840001, 0x8f820054, 0x821023, 0x2c420002,
+-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+-0x8f820054, 0x8004d45, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
+-0x3442ffff, 0x42480, 0x621824, 0x3c020002,
+-0x822025, 0x641825, 0xaf830044, 0x8f820044,
+-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+-0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001,
+-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+-0x0, 0x8f820044, 0x3c030001, 0x431025,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x3e00008, 0x0,
+-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
+-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+-0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+-0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
+-0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
+-0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
+-0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+-0x96420000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d4b, 0x108042, 0x12000075,
+-0x0, 0x8004dc9, 0x0, 0x3274ffff,
+-0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b,
+-0x2021, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x2901024, 0xc004d71,
+-0x34108000, 0xc004d71, 0x0, 0xc004d2b,
+-0x0, 0x50400005, 0x108042, 0x96220000,
+-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+-0x0, 0xc004d71, 0x0, 0x32a5ffff,
+-0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
+-0x8004e14, 0x521025, 0x14a20006, 0x3271ffff,
+-0x97a20010, 0x121827, 0x431024, 0xa7a20010,
+-0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d4b, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+-0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
+-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+-0x96420000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+-0x0, 0xc004d71, 0x0, 0x8fbf0030,
+-0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
+-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
+-0x0, 0x0, 0x0, 0x27bdffe8,
+-0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
+-0x24020008, 0x1462022c, 0x803021, 0x3c020001,
+-0x8c425d98, 0x14400033, 0x0, 0x8f850224,
+-0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
+-0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
+-0x38a20400, 0x2c420001, 0x621825, 0x14600007,
+-0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
+-0x621825, 0x10600005, 0x0, 0xc00429b,
+-0x0, 0x8004e8d, 0x2402000e, 0xc0043dd,
+-0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+-0x2021, 0x3c030001, 0x8c635cc8, 0x24020004,
+-0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4,
+-0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4,
+-0x431024, 0x3c010001, 0xac225cc4, 0x2402000e,
+-0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087,
+-0x0, 0x8f820220, 0x3c030400, 0x431024,
+-0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
+-0x8c427ddc, 0xa32024, 0x431024, 0x1482000c,
+-0x0, 0x3c020001, 0x8c427de0, 0x24420001,
+-0x3c010001, 0xac227de0, 0x2c420002, 0x14400008,
+-0x24020001, 0x3c010001, 0x8004ead, 0xac227e00,
+-0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00,
+-0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040,
+-0x10400004, 0x24020001, 0x3c010001, 0x8004eb8,
+-0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001,
+-0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10,
+-0x24020001, 0x3c010001, 0xac227e10, 0x3c010001,
+-0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001,
+-0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001,
+-0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003,
+-0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024,
+-0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
+-0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700,
+-0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
+-0x220821, 0x8c225b80, 0x400008, 0x0,
+-0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0,
+-0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04,
+-0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0,
+-0xc00486a, 0xaf800224, 0x24020002, 0x3c010001,
+-0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056,
+-0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
+-0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
+-0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
+-0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8,
+-0x24040001, 0x3c010001, 0xac247e0c, 0x24420001,
+-0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001,
+-0xac237df4, 0x14400006, 0x24020003, 0x3c010001,
+-0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8,
+-0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054,
+-0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
+-0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
+-0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026,
+-0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
+-0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c,
+-0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001,
+-0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10,
+-0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
+-0x431024, 0xaee20000, 0x8f820204, 0x30420030,
+-0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c,
+-0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001,
+-0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10,
+-0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c,
+-0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002,
+-0x14400131, 0x24020001, 0x3c010001, 0xac225d74,
+-0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083,
+-0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024,
+-0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122,
+-0x0, 0x3c020001, 0x8c427ddc, 0x1040011e,
+-0x0, 0x3c010001, 0xac227e08, 0x24020003,
+-0x3c010001, 0xac227de0, 0x8005024, 0x24020006,
+-0x3c010001, 0xac207de8, 0x8f820204, 0x34420040,
+-0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007,
+-0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001,
+-0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005,
+-0x0, 0x3c020001, 0x8c427ddc, 0x104000f9,
+-0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000,
+-0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
+-0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001,
+-0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024,
+-0x641824, 0x10430004, 0x24020001, 0x3c010001,
+-0x8005083, 0xac227dd0, 0x24020003, 0xaca20000,
+-0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001,
+-0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001,
+-0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28,
+-0x14400005, 0x24020001, 0x3c020001, 0x8c427e24,
+-0x10400006, 0x24020001, 0x3c010001, 0xac225ccc,
+-0x3c010001, 0x8005083, 0xac207df8, 0x3c020001,
+-0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001,
+-0x210c0, 0x30630008, 0x3c010001, 0xac227df0,
+-0x3c010001, 0xac237dec, 0x8f830054, 0x24020009,
+-0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083,
+-0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4,
+-0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
+-0x0, 0x3c020001, 0x8c427e00, 0x10400005,
+-0x0, 0x3c020001, 0x8c427ddc, 0x104000a9,
+-0x24020002, 0x3c030001, 0x24637de0, 0x8c620000,
+-0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
+-0x8c427e0c, 0x1040000e, 0x0, 0x3c020001,
+-0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080,
+-0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
+-0x1440000c, 0x24020003, 0x8005011, 0x2402000c,
+-0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005,
+-0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
+-0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
+-0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000,
+-0x3c030001, 0x8c637df0, 0x431025, 0xaf820204,
+-0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b,
+-0x3c010001, 0xac227dd0, 0x641825, 0x3c010001,
+-0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000,
+-0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
+-0x8c427e10, 0x10400005, 0x0, 0x2402000c,
+-0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001,
+-0x8c427e00, 0x1040006c, 0x0, 0x3c040001,
+-0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001,
+-0x8c637dec, 0x10620064, 0x24020003, 0x3c010001,
+-0xac247e08, 0xaca20000, 0x24020006, 0x3c010001,
+-0x8005083, 0xac227dd0, 0x8f820200, 0x34420002,
+-0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
+-0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054,
+-0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
+-0x2c422710, 0x1440003a, 0x0, 0x3c020001,
+-0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001,
+-0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0,
+-0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8,
+-0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8,
+-0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
+-0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001,
+-0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4,
+-0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
+-0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220,
+-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+-0x34420002, 0x8005083, 0xaf820220, 0x3c020001,
+-0x8c427e00, 0x10400005, 0x0, 0x3c020001,
+-0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001,
+-0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002,
+-0x3c020001, 0x8c427e00, 0x1040000f, 0x0,
+-0x3c020001, 0x8c427ddc, 0x1440000b, 0x0,
+-0x24020002, 0x3c010001, 0x8005083, 0xac227dd0,
+-0x3c020001, 0x8c427e00, 0x10400003, 0x0,
+-0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
+-0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
+-0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000,
+-0x10400005, 0x34422000, 0x3c010001, 0xac227e1c,
+-0x8005095, 0xac600000, 0x3c010001, 0xac247e1c,
+-0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
+-0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067,
+-0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
+-0x24020030, 0x30822000, 0x1040005d, 0x30838000,
+-0x31a02, 0x30820001, 0x21200, 0x3c040001,
+-0x8c845d9c, 0x621825, 0x331c2, 0x3c030001,
+-0x24635d78, 0x30828000, 0x21202, 0x30840001,
+-0x42200, 0x441025, 0x239c2, 0x61080,
+-0x431021, 0x471021, 0x90430000, 0x24020001,
+-0x10620025, 0x0, 0x10600007, 0x24020002,
+-0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
+-0x80050f9, 0x0, 0x8f820200, 0x2403feff,
+-0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
+-0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
+-0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c,
+-0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
+-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+-0x24020100, 0x3c010001, 0xac227e44, 0x3c010001,
+-0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff,
+-0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
+-0x431025, 0xaf820220, 0x3c010001, 0xac207e44,
+-0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200,
+-0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
+-0x431025, 0xaf820220, 0x24020100, 0x3c010001,
+-0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c,
+-0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010,
+-0xc002403, 0xafa00014, 0x8005104, 0x0,
+-0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018,
+-0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
+-0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+-0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0,
+-0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001,
+-0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+-0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
+-0x24020002, 0x12620083, 0x2e620003, 0x10400005,
+-0x24020001, 0x1262000a, 0x0, 0x800529b,
+-0x0, 0x24020004, 0x126200fa, 0x24020008,
+-0x126200f9, 0x3c02ffec, 0x800529b, 0x0,
+-0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004,
+-0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+-0x3c010001, 0x310821, 0xac307e3c, 0x3c024000,
+-0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
+-0x101382, 0x3042001c, 0x3c030001, 0x24635d08,
+-0x431021, 0x823821, 0x3c020020, 0x2021024,
+-0x10400006, 0x24020100, 0x3c010001, 0x310821,
+-0xac227e40, 0x8005150, 0x3c020080, 0x3c010001,
+-0x310821, 0xac207e40, 0x3c020080, 0x2021024,
+-0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+-0x230821, 0x800515c, 0xac227e48, 0x121140,
+-0x3c010001, 0x220821, 0xac207e48, 0x94e40000,
+-0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010,
+-0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
+-0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+-0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002,
+-0x24040001, 0x2821, 0xc00498e, 0x27a60018,
+-0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001,
+-0xac315cd4, 0x14530004, 0x32028000, 0xc00429b,
+-0x0, 0x32028000, 0x1040011f, 0x0,
+-0xc00429b, 0x0, 0x3c030001, 0x8c635dbc,
+-0x24020005, 0x10620118, 0x24020002, 0x3c010001,
+-0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8,
+-0x24040001, 0x24050004, 0x27b0001a, 0xc00498e,
+-0x2003021, 0x24040001, 0x2821, 0xc00498e,
+-0x2003021, 0x3c020001, 0x511021, 0x8c427e34,
+-0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff,
+-0x3c010001, 0xac335cd4, 0x431024, 0x3c010001,
+-0x310821, 0x109300fa, 0xac227e34, 0x800529b,
+-0x0, 0x3c022000, 0x2021024, 0x10400005,
+-0x24020001, 0x3c010001, 0xac225d98, 0x80051ad,
+-0x128940, 0x3c010001, 0xac205d98, 0x128940,
+-0x3c010001, 0x310821, 0xac307e38, 0x3c024000,
+-0x2021024, 0x14400016, 0x0, 0x3c020001,
+-0x8c425d98, 0x10400008, 0x24040004, 0x24050001,
+-0xc004d93, 0x24062000, 0x24020001, 0x3c010001,
+-0x370821, 0xac2283ac, 0x3c020001, 0x511021,
+-0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024,
+-0x3c010001, 0x310821, 0x8005299, 0xac227e30,
+-0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0,
+-0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
+-0x8c425d9c, 0x24030100, 0x3c010001, 0x310821,
+-0xac237e44, 0x3c030001, 0x3c010001, 0x310821,
+-0xac237e4c, 0x80051f0, 0x34420400, 0x2021024,
+-0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c,
+-0x3c010001, 0x310821, 0xac237e44, 0x80051f0,
+-0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
+-0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001,
+-0x310821, 0xac237e4c, 0x34420c00, 0x3c010001,
+-0xac225d9c, 0x8005218, 0x24040001, 0x3c020020,
+-0x2021024, 0x10400006, 0x24020100, 0x3c010001,
+-0x310821, 0xac227e44, 0x8005201, 0x3c020080,
+-0x3c010001, 0x310821, 0xac207e44, 0x3c020080,
+-0x2021024, 0x10400007, 0x121940, 0x3c020001,
+-0x3c010001, 0x230821, 0xac227e4c, 0x800520f,
+-0x24040001, 0x121140, 0x3c010001, 0x220821,
+-0xac207e4c, 0x24040001, 0x2821, 0x27b0001e,
+-0xc00494c, 0x2003021, 0x24040001, 0x2821,
+-0xc00494c, 0x2003021, 0x24040001, 0x24050001,
+-0x27b0001c, 0xc00494c, 0x2003021, 0x24040001,
+-0x24050001, 0xc00494c, 0x2003021, 0x8005299,
+-0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
+-0x3c020008, 0x2028025, 0x121140, 0x3c010001,
+-0x220821, 0xac307e38, 0x3c022000, 0x2021024,
+-0x10400009, 0x0, 0x3c020001, 0x8c425d74,
+-0x14400005, 0x24020001, 0x3c010001, 0xac225d98,
+-0x800523a, 0x3c024000, 0x3c010001, 0xac205d98,
+-0x3c024000, 0x2021024, 0x1440001e, 0x0,
+-0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0,
+-0x10400007, 0x24022020, 0x3c010001, 0xac225d9c,
+-0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
+-0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
+-0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff,
+-0x441024, 0x3c010001, 0x230821, 0xac227e30,
+-0x24020001, 0x10a20044, 0x0, 0x8005299,
+-0x0, 0x3c020001, 0x8c425d98, 0x1040001c,
+-0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0,
+-0x2031024, 0x14430005, 0x121140, 0x3402a000,
+-0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001,
+-0x621821, 0x8c637e38, 0x3c020020, 0x621024,
+-0x10400004, 0x24022001, 0x3c010001, 0x8005294,
+-0xac225d9c, 0x3c020080, 0x621024, 0x1040001f,
+-0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c,
+-0x3c020020, 0x2021024, 0x10400007, 0x121940,
+-0x24020100, 0x3c010001, 0x230821, 0xac227e44,
+-0x8005288, 0x3c020080, 0x121140, 0x3c010001,
+-0x220821, 0xac207e44, 0x3c020080, 0x2021024,
+-0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+-0x230821, 0x8005294, 0xac227e4c, 0x121140,
+-0x3c010001, 0x220821, 0xac207e4c, 0x3c030001,
+-0x8c635cc8, 0x24020001, 0x10620003, 0x0,
+-0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
+-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+-0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021,
+-0xafb1001c, 0x8821, 0x24020002, 0xafbf0024,
+-0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010,
+-0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a,
+-0x128140, 0x8005380, 0x2201021, 0x24020004,
+-0x10a2007d, 0x24020008, 0x10a2007c, 0x122940,
+-0x8005380, 0x2201021, 0x3c030001, 0x701821,
+-0x8c637e3c, 0x3c024000, 0x621024, 0x14400009,
+-0x24040001, 0x3c027fff, 0x3442ffff, 0x628824,
+-0x3c010001, 0x300821, 0xac317e34, 0x8005380,
+-0x2201021, 0x24050001, 0xc00494c, 0x27a60010,
+-0x24040001, 0x24050001, 0xc00494c, 0x27a60010,
+-0x97a20010, 0x30420004, 0x10400034, 0x3c114000,
+-0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006,
+-0x10400034, 0x31080, 0x3c010001, 0x220821,
+-0x8c225be0, 0x400008, 0x0, 0x24040001,
+-0x24050011, 0x27b00012, 0xc00494c, 0x2003021,
+-0x24040001, 0x24050011, 0xc00494c, 0x2003021,
+-0x97a50012, 0x30a24000, 0x10400002, 0x3c040010,
+-0x3c040008, 0x3c030001, 0x8005301, 0x30a28000,
+-0x24040001, 0x24050014, 0x27b00012, 0xc00494c,
+-0x2003021, 0x24040001, 0x24050014, 0xc00494c,
+-0x2003021, 0x97a50012, 0x30a21000, 0x10400002,
+-0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800,
+-0x54400001, 0x3c030002, 0x3c028000, 0x2221025,
+-0x641825, 0x800530e, 0x438825, 0x3c110001,
+-0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff,
+-0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d,
+-0x121140, 0x3c020001, 0x8c425d98, 0x10400002,
+-0x3c022000, 0x2228825, 0x121140, 0x3c010001,
+-0x220821, 0x8c227e40, 0x10400003, 0x3c020020,
+-0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff,
+-0x2228824, 0x121140, 0x3c010001, 0x220821,
+-0x8c227e48, 0x10400003, 0x3c020080, 0x800532d,
+-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
+-0x121140, 0x3c010001, 0x220821, 0xac317e34,
+-0x8005380, 0x2201021, 0x122940, 0x3c030001,
+-0x651821, 0x8c637e38, 0x3c024000, 0x621024,
+-0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
+-0x3c010001, 0x250821, 0xac317e30, 0x8005380,
+-0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033,
+-0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c,
+-0x34842000, 0x3c030001, 0x8c635d98, 0x2102b,
+-0x21023, 0x441024, 0x10600003, 0x518825,
+-0x3c022000, 0x2228825, 0x3c020001, 0x451021,
+-0x8c427e44, 0x10400003, 0x3c020020, 0x800535d,
+-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+-0x121140, 0x3c010001, 0x220821, 0x8c227e4c,
+-0x10400003, 0x3c020080, 0x8005368, 0x2228825,
+-0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
+-0x8c425d60, 0x10400002, 0x3c020800, 0x2228825,
+-0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400,
+-0x2228825, 0x3c020001, 0x8c425d68, 0x10400006,
+-0x3c020100, 0x800537b, 0x2228825, 0x3c027fff,
+-0x3442ffff, 0x628824, 0x121140, 0x3c010001,
+-0x220821, 0xac317e30, 0x2201021, 0x8fbf0024,
+-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+-0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021,
+-0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
+-0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8,
+-0x8f930220, 0x24020002, 0x10620063, 0x2c620003,
+-0x10400005, 0x24020001, 0x1062000a, 0x141940,
+-0x8005448, 0x0, 0x24020004, 0x1062005a,
+-0x24020008, 0x10620059, 0x149140, 0x8005448,
+-0x0, 0x3c040001, 0x832021, 0x8c847e3c,
+-0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000,
+-0x821024, 0x1040003e, 0x3c020008, 0x2221024,
+-0x10400020, 0x36100002, 0x3c020001, 0x431021,
+-0x8c427e40, 0x10400005, 0x36100020, 0x36100100,
+-0x3c020020, 0x80053bd, 0x2228825, 0x2402feff,
+-0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+-0x141140, 0x3c010001, 0x220821, 0x8c227e48,
+-0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
+-0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff,
+-0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc,
+-0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
+-0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
+-0x2228824, 0x3c010001, 0x230821, 0xac207e40,
+-0x3c010001, 0x230821, 0xac207e48, 0xc00486a,
+-0x0, 0xaf900200, 0xaf930220, 0x8f820220,
+-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+-0x34420002, 0xaf820220, 0x80053f3, 0x141140,
+-0x8f820200, 0x2403fffd, 0x431024, 0xc00486a,
+-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+-0x2228824, 0x141140, 0x3c010001, 0x220821,
+-0x8005448, 0xac317e34, 0x149140, 0x3c040001,
+-0x922021, 0x8c847e38, 0x3c110001, 0x2328821,
+-0x8e317e30, 0x3c024000, 0x821024, 0x14400011,
+-0x0, 0x3c020001, 0x8c425d98, 0x14400006,
+-0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a,
+-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+-0x2228824, 0x3c010001, 0x320821, 0x8005448,
+-0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005,
+-0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b,
+-0x3c020020, 0x821024, 0x10400007, 0x36100020,
+-0x24020100, 0x3c010001, 0x320821, 0xac227e44,
+-0x8005428, 0x36100100, 0x3c010001, 0x320821,
+-0xac207e44, 0x2402feff, 0x2028024, 0x3c020080,
+-0x821024, 0x10400007, 0x141940, 0x3c020001,
+-0x3c010001, 0x230821, 0xac227e4c, 0x8005439,
+-0x2629825, 0x141140, 0x3c010001, 0x220821,
+-0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824,
+-0xc00486a, 0x0, 0xaf900200, 0xaf930220,
+-0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
+-0x8f820220, 0x34420002, 0xaf820220, 0x141140,
+-0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024,
+-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
++0x10000003,
++0x0, 0xd, 0xd, 0x3c1d0001,
++0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000,
++0xc00100c, 0x0, 0xd, 0x27bdffd8,
++0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
++0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
++0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
++0x0, 0x3c040001, 0x248451a4, 0x24050001,
++0x2e03021, 0x3821, 0x3c100001, 0x26107e50,
++0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
++0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
++0x24050003, 0x3c040001, 0x248451b0, 0x2003021,
++0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
++0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
++0x370821, 0xa02083b0, 0x3c010001, 0x370821,
++0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3,
++0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8,
++0x418c0, 0x24840001, 0x771021, 0xac40727c,
++0x771021, 0xac407280, 0x2e31021, 0xa445727c,
++0x2c820020, 0x1440fff7, 0x418c0, 0x2021,
++0x3405c000, 0x418c0, 0x24840001, 0x771021,
++0xac40737c, 0x771021, 0xac407380, 0x2e31021,
++0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0,
++0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040,
++0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
++0x8f420218, 0x30420002, 0x10400009, 0x0,
++0x8f420220, 0x3c030002, 0x34630004, 0x431025,
++0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004,
++0x8f420220, 0x3c030002, 0x34630006, 0x431025,
++0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc,
++0x8f420218, 0x30420010, 0x1040000a, 0x0,
++0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220,
++0x3c03000a, 0x34630004, 0x431025, 0x800108a,
++0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006,
++0x431025, 0xaee204c0, 0x8f42021c, 0x34420006,
++0xaee204c8, 0x8f420218, 0x30420200, 0x10400003,
++0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248,
++0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
++0x8f820054, 0x8001099, 0x24630064, 0x8f820054,
++0x621023, 0x2c420065, 0x1440fffc, 0x0,
++0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010,
++0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030,
++0xaee20028, 0x24020490, 0xaee20018, 0xaf840090,
++0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a,
++0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025,
++0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
++0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
++0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
++0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
++0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014,
++0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
++0x26e40030, 0xc002488, 0x24050400, 0x27440080,
++0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
++0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060,
++0x8f420260, 0x27450200, 0x24060008, 0xaee20068,
++0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a,
++0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
++0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
++0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
++0x641821, 0x90635c20, 0x2e41021, 0x24840001,
++0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
++0x8f820040, 0x2e41821, 0x24840001, 0x21702,
++0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
++0x96e2046a, 0x30420003, 0x14400009, 0x0,
++0x96e2047a, 0x30420003, 0x50400131, 0x3c030800,
++0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700,
++0x96e2047a, 0x30420003, 0x10400026, 0x3c020700,
++0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700,
++0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00,
++0xaee204c0, 0x8f420218, 0x30420100, 0x10400005,
++0x0, 0x3c020001, 0x2442e168, 0x800111d,
++0x21100, 0x3c020001, 0x2442d35c, 0x21100,
++0x21182, 0x3c030800, 0x431025, 0x3c010001,
++0xac221238, 0x3c020001, 0x2442f680, 0x21100,
++0x21182, 0x3c030800, 0x431025, 0x3c010001,
++0xac221278, 0x8ee20000, 0x34424000, 0x8001238,
++0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608,
++0x8f430228, 0x24420001, 0x304900ff, 0x512300e2,
++0xafa00010, 0x8ee20608, 0x210c0, 0x571021,
++0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610,
++0x8f870120, 0x27623800, 0x24e80020, 0x102102b,
++0x50400001, 0x27683000, 0x8f820128, 0x11020004,
++0x0, 0x8f820124, 0x15020007, 0x1021,
++0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
++0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0,
++0x801821, 0x8ee40430, 0x8ee50434, 0xa32821,
++0xa3302b, 0x822021, 0x862021, 0xace40000,
++0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e,
++0x2402000d, 0xace20018, 0xace9001c, 0x318c0,
++0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4,
++0xace20010, 0xaf880120, 0x92e24e20, 0x14400037,
++0x24060001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x24030040, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
++0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
++0x0, 0x800118a, 0x0, 0x14a00005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
++0xac800000, 0x80011a0, 0x0, 0x8ee24e30,
++0x24030040, 0x24420001, 0x50430003, 0x1021,
++0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x24020007,
++0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
++0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010,
++0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
++0xc002403, 0x34a5f000, 0x8001223, 0x0,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
++0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c,
++0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
++0x24020008, 0xa462000e, 0x24020011, 0xac620018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400037, 0x24060001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c830000, 0x24020012, 0x1462001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee54e30, 0x24420001, 0x10430007, 0x0,
++0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
++0x80011f1, 0x0, 0x14a00005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x8001207, 0x0, 0x8ee24e30, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020012, 0xac820000,
++0x24020001, 0xac820004, 0x14c0001b, 0x0,
++0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014,
++0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
++0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
++0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc,
++0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
++0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
++0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
++0x248451e8, 0x3405f001, 0x24420001, 0xaee20160,
++0x8ee20160, 0x3021, 0x3821, 0xafa00010,
++0xc002403, 0xafa00014, 0x8001238, 0x0,
++0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
++0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
++0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
++0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
++0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec,
++0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
++0x2442a390, 0x451024, 0x21082, 0xaee304c8,
++0x3c030800, 0x431025, 0x3c010001, 0xac221220,
++0x3c020001, 0x2442add4, 0x451024, 0x21082,
++0x431025, 0x3c010001, 0xac221280, 0x96e6045a,
++0x3821, 0x24050011, 0xafa00010, 0xc002403,
++0xafa00014, 0x8001268, 0x0, 0x3c020001,
++0x2442a9d4, 0x21100, 0x21182, 0x3c030800,
++0x431025, 0x3c010001, 0xac221280, 0x96e2046a,
++0x30420010, 0x14400009, 0x0, 0x96e2047a,
++0x30420010, 0x10400112, 0x0, 0x96e2046a,
++0x30420010, 0x10400005, 0x3c020700, 0x96e2047a,
++0x30420010, 0x14400102, 0x3c020700, 0x34423000,
++0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
++0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
++0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
++0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
++0x24e80020, 0x102102b, 0x50400001, 0x27683000,
++0x8f820128, 0x11020004, 0x0, 0x8f820124,
++0x15020007, 0x1021, 0x8ee201a4, 0x3021,
++0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4,
++0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
++0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xace40000, 0xace50004, 0x8ee30608,
++0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
++0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
++0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
++0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
++0x24420001, 0x10430007, 0x0, 0x8ee24e34,
++0x24420001, 0x10a20005, 0x0, 0x80012d4,
++0x0, 0x14a00005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x80012ea,
++0x0, 0x8ee24e30, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x24020007, 0xac820000, 0x24020001,
++0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
++0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
++0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
++0x800136d, 0x0, 0x8f830120, 0x27623800,
++0x24660020, 0xc2102b, 0x50400001, 0x27663000,
++0x8f820128, 0x10c20004, 0x0, 0x8f820124,
++0x14c20007, 0x0, 0x8ee201a4, 0x3021,
++0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4,
++0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
++0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
++0x24020011, 0xac620018, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
++0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
++0x10430007, 0x0, 0x8ee24e34, 0x24420001,
++0x10a20005, 0x0, 0x800133b, 0x0,
++0x14a00005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400013, 0xac800000, 0x8001351, 0x0,
++0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020012, 0xac820000, 0x24020001, 0xac820004,
++0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
++0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
++0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
++0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
++0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
++0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
++0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
++0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002,
++0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
++0x3821, 0xafa00010, 0xc002403, 0xafa00014,
++0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200,
++0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
++0xc004500, 0x0, 0xc002318, 0x0,
++0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
++0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8,
++0x34a5c358, 0x27623800, 0xaee27258, 0x27623800,
++0xaee27260, 0x27623800, 0xaee27264, 0x3661021,
++0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0,
++0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c,
++0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c,
++0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c,
++0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268,
++0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8,
++0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100,
++0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
++0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
++0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
++0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
++0x24e80020, 0x102102b, 0x50400001, 0x27683000,
++0x8f820128, 0x11020004, 0x0, 0x8f820124,
++0x15020007, 0x1021, 0x8ee201a4, 0x3021,
++0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4,
++0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
++0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xace40000, 0xace50004, 0x8ee30608,
++0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
++0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
++0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
++0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
++0x24420001, 0x10430007, 0x0, 0x8ee24e34,
++0x24420001, 0x10a20005, 0x0, 0x800140c,
++0x0, 0x14a00005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x8001422,
++0x0, 0x8ee24e30, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x24020007, 0xac820000, 0x24020001,
++0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
++0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
++0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
++0x80014a5, 0x0, 0x8f830120, 0x27623800,
++0x24660020, 0xc2102b, 0x50400001, 0x27663000,
++0x8f820128, 0x10c20004, 0x0, 0x8f820124,
++0x14c20007, 0x0, 0x8ee201a4, 0x3021,
++0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4,
++0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
++0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
++0x24020011, 0xac620018, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
++0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
++0x10430007, 0x0, 0x8ee24e34, 0x24420001,
++0x10a20005, 0x0, 0x8001473, 0x0,
++0x14a00005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400013, 0xac800000, 0x8001489, 0x0,
++0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020012, 0xac820000, 0x24020001, 0xac820004,
++0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
++0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
++0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
++0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
++0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
++0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
++0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
++0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
++0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd,
++0x0, 0x8f820040, 0x30420001, 0x14400008,
++0x0, 0x8f430104, 0x24020001, 0x10620004,
++0x0, 0x8f420264, 0x10400006, 0x0,
++0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5,
++0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044,
++0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178,
++0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c,
++0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021,
++0xaee2726c, 0xc004064, 0x0, 0xc004440,
++0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008,
++0x27bd0028, 0x3e00008, 0x0, 0x3e00008,
++0x0, 0x0, 0x0, 0x2402002c,
++0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278,
++0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88,
++0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
++0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
++0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
++0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067,
++0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
++0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
++0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
++0x431025, 0xaee20000, 0x8f420218, 0x30420100,
++0x104000c6, 0x0, 0x8f8200b0, 0x30420004,
++0x104000c2, 0x0, 0x3c030001, 0x771821,
++0x8c6383d0, 0x8f820104, 0x146200b4, 0x0,
++0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4,
++0x146200ae, 0x0, 0x8f8200b0, 0x3c030080,
++0x431024, 0x1040000d, 0x0, 0x8f82011c,
++0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
++0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
++0x431024, 0x80015cc, 0xaf82011c, 0x3c030001,
++0x771821, 0x8c6383d0, 0x8f820104, 0x14620082,
++0x0, 0x3c030001, 0x771821, 0x8c6383d4,
++0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
++0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
++0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0,
++0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
++0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
++0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20006, 0x0, 0x8ee201a4,
++0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4,
++0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008,
++0x24020400, 0xa462000e, 0x2402000f, 0xac620018,
++0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4,
++0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
++0x0, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x24030040, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
++0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
++0x0, 0x800158a, 0x0, 0x14a00005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
++0xac800000, 0x80015a0, 0x0, 0x8ee24e30,
++0x24030040, 0x24420001, 0x50430003, 0x1021,
++0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x24020007,
++0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
++0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
++0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
++0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c,
++0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
++0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
++0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284,
++0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
++0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
++0x34a50900, 0x80015cc, 0x0, 0x8f820104,
++0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4,
++0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274,
++0x92e304f4, 0x24420067, 0x14600006, 0xaee27274,
++0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b,
++0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004,
++0x0, 0x92e204f4, 0x50400074, 0xa2e004f4,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
++0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
++0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
++0x24020008, 0xa462000e, 0x24020011, 0xac620018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c830000, 0x24020012, 0x1462001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee54e30, 0x24420001, 0x10430007, 0x0,
++0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
++0x8001621, 0x0, 0x14a00005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x8001637, 0x0, 0x8ee24e30, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020012, 0xac820000,
++0x24020001, 0xac820004, 0x5600000b, 0x24100001,
++0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014,
++0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
++0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
++0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
++0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4,
++0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c,
++0x1040006d, 0x0, 0x8f830120, 0x27623800,
++0x24660020, 0xc2102b, 0x50400001, 0x27663000,
++0x8f820128, 0x10c20004, 0x0, 0x8f820124,
++0x14c20007, 0x0, 0x8ee201a4, 0x8021,
++0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4,
++0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
++0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
++0x24020011, 0xac620018, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
++0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
++0x10430007, 0x0, 0x8ee24e34, 0x24420001,
++0x10a20005, 0x0, 0x8001697, 0x0,
++0x14a00005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400013, 0xac800000, 0x80016ad, 0x0,
++0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020012, 0xac820000, 0x24020001, 0xac820004,
++0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
++0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c,
++0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
++0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
++0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
++0x0, 0xaee04e24, 0x8f820040, 0x30420001,
++0x14400008, 0x0, 0x8f430104, 0x24020001,
++0x10620004, 0x0, 0x8f420264, 0x10400006,
++0x0, 0x8ee2017c, 0x24420001, 0xaee2017c,
++0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004,
++0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178,
++0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278,
++0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238,
++0x104002aa, 0x0, 0x3c020001, 0x571021,
++0x904283e0, 0x144002a5, 0x0, 0x8f420080,
++0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084,
++0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088,
++0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090,
++0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098,
++0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0,
++0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8,
++0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0,
++0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8,
++0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c,
++0xaee0003c, 0x41080, 0x571021, 0x8ee3003c,
++0x8c420244, 0x24840001, 0x621821, 0x2c82000f,
++0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc,
++0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x8021, 0x24420001, 0xaee201a4, 0x8001775,
++0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030,
++0xac620008, 0x24020400, 0xa462000e, 0x2402000f,
++0xac620018, 0xac60001c, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
++0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
++0x10430007, 0x0, 0x8ee24e34, 0x24420001,
++0x10a20005, 0x0, 0x800175f, 0x0,
++0x14a00005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400013, 0xac800000, 0x8001775, 0x0,
++0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020007, 0xac820000, 0x24020001, 0xac820004,
++0x12000212, 0x3c020400, 0xafa20018, 0x3c020001,
++0x571021, 0x904283b0, 0x1040010b, 0x0,
++0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
++0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
++0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
++0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
++0x1221023, 0x2c420033, 0x1040006a, 0x5821,
++0x24180008, 0x240f000d, 0x240d0007, 0x240c0040,
++0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
++0x102102b, 0x50400001, 0x27683000, 0x8f820128,
++0x11020004, 0x0, 0x8f820124, 0x15020007,
++0x1021, 0x8ee201a4, 0x8021, 0x24420001,
++0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608,
++0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
++0xa32821, 0xa3302b, 0x822021, 0x862021,
++0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e,
++0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
++0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
++0xaf880120, 0x92e24e20, 0x14400033, 0x24100001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x80017e0,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400010, 0xac800000, 0x80017f3,
++0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001,
++0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
++0x0, 0x316300ff, 0x24020001, 0x14620077,
++0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054,
++0x24690032, 0x1221023, 0x2c420033, 0x10400061,
++0x5821, 0x240d0008, 0x240c0011, 0x24080012,
++0x24070040, 0x240a0001, 0x8f830120, 0x27623800,
++0x24660020, 0xc2102b, 0x50400001, 0x27663000,
++0x8f820128, 0x10c20004, 0x0, 0x8f820124,
++0x14c20007, 0x0, 0x8ee201a4, 0x8021,
++0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4,
++0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
++0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400033, 0x24100001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x1448001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x10470007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x800184c,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400010, 0xac800000, 0x800185f,
++0x0, 0x8ee24e30, 0x24420001, 0x50470003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0xac880000, 0xac8a0004, 0x56000006, 0x240b0001,
++0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
++0x0, 0x316300ff, 0x24020001, 0x14620003,
++0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
++0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
++0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
++0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120,
++0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
++0x800197c, 0x0, 0x3c040001, 0x248452bc,
++0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
++0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
++0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
++0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
++0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120,
++0x27623800, 0x24e80020, 0x102102b, 0x50400001,
++0x27683000, 0x8f820128, 0x11020004, 0x0,
++0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
++0x8021, 0x24420001, 0xaee201a4, 0x80018f7,
++0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
++0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0xace40000, 0xace50004,
++0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d,
++0xace20018, 0xace9001c, 0x318c0, 0x2463060c,
++0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010,
++0xaf880120, 0x92e24e20, 0x14400037, 0x24100001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c830000, 0x24020007, 0x1462001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee54e30, 0x24420001, 0x10430007, 0x0,
++0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
++0x80018e1, 0x0, 0x14a00005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x80018f7, 0x0, 0x8ee24e30, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020007, 0xac820000,
++0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
++0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014,
++0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
++0x34a5f000, 0x800197c, 0x0, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x8021, 0x24420001, 0xaee201a4, 0x800195e,
++0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
++0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008,
++0xa462000e, 0x24020011, 0xac620018, 0xac640000,
++0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
++0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
++0x24420001, 0x10430007, 0x0, 0x8ee24e34,
++0x24420001, 0x10a20005, 0x0, 0x8001948,
++0x0, 0x14a00005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x800195e,
++0x0, 0x8ee24e30, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x24020012, 0xac820000, 0x24020001,
++0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
++0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608,
++0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
++0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
++0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014,
++0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
++0xc002403, 0x0, 0x8ee201ac, 0x8021,
++0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
++0x24020001, 0x3c010001, 0x370821, 0xa02083b0,
++0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
++0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
++0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
++0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84,
++0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
++0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
++0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
++0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228,
++0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010,
++0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
++0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
++0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
++0x1040006a, 0x5821, 0x24180008, 0x240f000d,
++0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
++0x27623800, 0x24e80020, 0x102102b, 0x50400001,
++0x27683000, 0x8f820128, 0x11020004, 0x0,
++0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
++0x8021, 0x24420001, 0xaee201a4, 0x8001a15,
++0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
++0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0xace40000, 0xace50004,
++0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
++0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
++0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
++0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
++0x0, 0x8ee24e34, 0x24420001, 0x10620005,
++0x0, 0x8001a02, 0x0, 0x14600005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
++0xac800000, 0x8001a15, 0x0, 0x8ee24e30,
++0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
++0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
++0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
++0x24020001, 0x54620078, 0xafa00010, 0xaeea0608,
++0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
++0x2c420033, 0x10400061, 0x5821, 0x240d0008,
++0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
++0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c,
++0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
++0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
++0x0, 0x8ee24e34, 0x24420001, 0x10620005,
++0x0, 0x8001a6e, 0x0, 0x14600005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
++0xac800000, 0x8001a81, 0x0, 0x8ee24e30,
++0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
++0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
++0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
++0x24020001, 0x10620022, 0x0, 0x3c040001,
++0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
++0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
++0x8001aad, 0x0, 0x3c040001, 0x248452b0,
++0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
++0xc002403, 0x34a5f010, 0x8001aad, 0x0,
++0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608,
++0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
++0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
++0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
++0x8ee204d4, 0x30420001, 0x10400055, 0x0,
++0x8f420218, 0x30420080, 0x10400029, 0x0,
++0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c,
++0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000,
++0x2407ffff, 0x2021, 0x461024, 0x1444000d,
++0x671824, 0x1465000b, 0x0, 0x8ee27b80,
++0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021,
++0x461024, 0x14440003, 0x671824, 0x1065000b,
++0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0,
++0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044,
++0x38420020, 0x8001b38, 0xaf820044, 0x8f820044,
++0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044,
++0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044,
++0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4,
++0x24060000, 0x2407ffff, 0x2021, 0x461024,
++0x1444000d, 0x671824, 0x1465000b, 0x0,
++0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4,
++0x2021, 0x461024, 0x14440003, 0x671824,
++0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4,
++0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80,
++0x8f820044, 0x38420040, 0x8001b38, 0xaf820044,
++0x8f820044, 0x34420040, 0x8001b38, 0xaf820044,
++0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c,
++0x24430001, 0x28420015, 0x14400028, 0xaee37b8c,
++0x8f820044, 0x38420020, 0xaf820044, 0x8001b38,
++0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011,
++0x0, 0x8f420218, 0x30420080, 0x10400009,
++0x0, 0x8f820044, 0x34420020, 0xaf820044,
++0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36,
++0xaf820044, 0x8f820044, 0x34420060, 0x8001b36,
++0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
++0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
++0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
++0xaee07b88, 0xc004603, 0x0, 0x8fbf0024,
++0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
++0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
++0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
++0x8f960064, 0x32c20004, 0x1040000c, 0x24020004,
++0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060,
++0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001,
++0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
++0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
++0x0, 0x32c20002, 0x1440000c, 0x3c050003,
++0x3c040001, 0x24845354, 0x34a50001, 0x2c03021,
++0x3821, 0xafa00010, 0xc002403, 0xafa00014,
++0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
++0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
++0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
++0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
++0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360,
++0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
++0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
++0x0, 0x80022ed, 0xaf960064, 0x93a20020,
++0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
++0x3c010001, 0x220821, 0x8c225418, 0x400008,
++0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
++0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
++0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
++0x8fa20020, 0x24030001, 0x3c010001, 0x370821,
++0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060,
++0x34420100, 0xaf820060, 0x8ee20144, 0x24420001,
++0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020,
++0x21200, 0x22502, 0x24020001, 0x10820005,
++0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9,
++0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074,
++0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4,
++0xaee40070, 0xaee40074, 0x621824, 0xaee304d4,
++0x8f840054, 0x41442, 0x41c82, 0x431021,
++0x41cc2, 0x431023, 0x41d02, 0x431021,
++0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
++0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020,
++0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
++0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
++0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
++0x920c0, 0x2e41021, 0x9442727c, 0x30424000,
++0x1040000a, 0x971021, 0x97430212, 0xa443727e,
++0x8f430214, 0x971021, 0xac437280, 0x2e41821,
++0x34028000, 0x8001c79, 0xa462727c, 0x9443727e,
++0x97420212, 0x14620006, 0x2e41021, 0x971021,
++0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021,
++0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff,
++0x2021, 0x410c0, 0x2e21021, 0x9442737c,
++0x30424000, 0x54400005, 0x803021, 0x24840001,
++0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
++0x618c0, 0x610c0, 0x571821, 0x8c63737c,
++0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
++0x24845378, 0xafa20014, 0x8f470214, 0x3c050003,
++0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
++0x97440212, 0x771021, 0xa444737e, 0x8f440214,
++0x771021, 0x2e31821, 0xac447380, 0x34028000,
++0xa462737c, 0x910c0, 0x2e21021, 0x8001c79,
++0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e,
++0x510c0, 0x9443737e, 0x97420212, 0x14620006,
++0x510c0, 0x971021, 0x8c437380, 0x8f420214,
++0x10620065, 0x510c0, 0x2e21021, 0x9445737c,
++0x510c0, 0x2e21021, 0x9442737c, 0x30428000,
++0x1040fff0, 0x971021, 0x520c0, 0x971021,
++0x9443737e, 0x97420212, 0x14620006, 0x2406ffff,
++0x971021, 0x8c437380, 0x8f420214, 0x10620053,
++0x3c020800, 0x2021, 0x410c0, 0x2e21021,
++0x9442737c, 0x30424000, 0x54400005, 0x803021,
++0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
++0x4c10023, 0x618c0, 0x910c0, 0x571821,
++0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
++0x3c040001, 0x24845384, 0xafa20014, 0x8f470214,
++0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
++0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
++0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
++0x571021, 0x8c4283b4, 0x24420001, 0x3c010001,
++0x370821, 0xac2283b4, 0x3c030001, 0x771821,
++0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c,
++0x97440212, 0x771021, 0xa444737e, 0x8f440214,
++0x771021, 0x2e31821, 0xac447380, 0x34028000,
++0xa462737c, 0x510c0, 0x2e21021, 0xa446737c,
++0x2021, 0x428c0, 0x2e51021, 0x9442777c,
++0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa,
++0x428c0, 0x92e204d8, 0x10400006, 0x24020001,
++0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f,
++0xaee304dc, 0x8f830228, 0x24020001, 0x1221004,
++0x621825, 0xaf830228, 0x3c020800, 0x34421000,
++0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
++0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
++0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
++0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
++0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
++0x5821, 0x24100008, 0x240f000d, 0x240d0007,
++0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
++0x24e80020, 0x102102b, 0x50400001, 0x27683000,
++0x8f820128, 0x11020004, 0x0, 0x8f820124,
++0x15020007, 0x1021, 0x8ee201a4, 0x3821,
++0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4,
++0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
++0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xace40000, 0xace50004, 0x8ee20608,
++0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
++0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
++0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
++0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c820000, 0x144d001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
++0x8ee24e34, 0x24420001, 0x10620005, 0x0,
++0x8001cf5, 0x0, 0x14600005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
++0x8001d08, 0x0, 0x8ee24e30, 0x24420001,
++0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
++0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
++0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
++0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
++0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
++0x10400061, 0x5821, 0x240e0008, 0x240d0011,
++0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x3821, 0x24420001, 0xaee201a4, 0x8001d74,
++0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
++0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
++0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
++0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
++0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c820000, 0x144a001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x10480007, 0x0,
++0x8ee24e34, 0x24420001, 0x10620005, 0x0,
++0x8001d61, 0x0, 0x14600005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
++0x8001d74, 0x0, 0x8ee24e30, 0x24420001,
++0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
++0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
++0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
++0x10620022, 0x0, 0x3c040001, 0x24845390,
++0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
++0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
++0x0, 0x3c040001, 0x2484539c, 0xafa00014,
++0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
++0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
++0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
++0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
++0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
++0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
++0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
++0x928c0, 0x2e51021, 0x9442727c, 0x30428000,
++0x1040002f, 0x2e51021, 0x9442727c, 0x30424000,
++0x1440001c, 0xb71021, 0x9443727e, 0x97420212,
++0x14620018, 0xb71021, 0x8c437280, 0x8f420214,
++0x54620016, 0xafa20010, 0x92e204d8, 0x10400007,
++0x24020001, 0x8ee304dc, 0x1221004, 0x21027,
++0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228,
++0x1221004, 0x21027, 0x621824, 0xaf830228,
++0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
++0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
++0x571021, 0x8c42727c, 0x3c040001, 0x248453b4,
++0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
++0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
++0xb71021, 0x9443727e, 0x97420212, 0x14620019,
++0x918c0, 0xb71021, 0x8c437280, 0x8f420214,
++0x14620014, 0x918c0, 0x2e51021, 0x9447727c,
++0x720c0, 0x971021, 0x9443737e, 0xb71021,
++0xa443727e, 0x971021, 0x8c437380, 0xb71021,
++0xac437280, 0x2e41021, 0x9443737c, 0x2e51021,
++0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e,
++0xa462737c, 0x2e31021, 0x9447727c, 0x3021,
++0x720c0, 0x2e41021, 0x9442737c, 0x4021,
++0x30428000, 0x14400025, 0xe02821, 0x605021,
++0x340bc000, 0x971021, 0x9443737e, 0x97420212,
++0x54620015, 0xe02821, 0x971021, 0x8c437380,
++0x8f420214, 0x54620010, 0xe02821, 0x11000006,
++0x2e41021, 0x9443737c, 0x510c0, 0x2e21021,
++0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021,
++0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c,
++0x8001e28, 0x24060001, 0x510c0, 0x2e21021,
++0x9447737c, 0x720c0, 0x2e41021, 0x9442737c,
++0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff,
++0x14400025, 0x2021, 0x720c0, 0x971021,
++0x9443737e, 0x97420212, 0x1462000f, 0x910c0,
++0x971021, 0x8c437380, 0x8f420214, 0x1462000a,
++0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
++0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
++0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
++0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010,
++0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
++0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
++0x3c020800, 0x2021, 0x428c0, 0xb71021,
++0x9443777e, 0x97420212, 0x5462002b, 0x24840001,
++0xb71021, 0x8c437780, 0x8f420214, 0x54620026,
++0x24840001, 0x3c020001, 0x571021, 0x8c4283b4,
++0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4,
++0x3c020001, 0x571021, 0x8c4283b4, 0x809021,
++0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784,
++0x2f02021, 0x2f12821, 0xc002490, 0x24060008,
++0x26310008, 0x3c020001, 0x571021, 0x8c4283b4,
++0x26520001, 0x242102b, 0x1440fff5, 0x26100008,
++0x3c040001, 0x972021, 0x8c8483b4, 0x24050008,
++0x420c0, 0x2484777c, 0xc002488, 0x2e42021,
++0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf,
++0x428c0, 0x3c020800, 0x34422000, 0xafa20018,
++0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
++0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
++0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
++0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
++0x1221023, 0x2c420033, 0x1040006a, 0x5821,
++0x24100008, 0x240f000d, 0x240d0007, 0x240c0040,
++0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
++0x102102b, 0x50400001, 0x27683000, 0x8f820128,
++0x11020004, 0x0, 0x8f820124, 0x15020007,
++0x1021, 0x8ee201a4, 0x3821, 0x24420001,
++0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608,
++0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
++0xa32821, 0xa3302b, 0x822021, 0x862021,
++0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e,
++0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
++0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
++0xaf880120, 0x92e24e20, 0x14400033, 0x24070001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x8001ee8,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400010, 0xac800000, 0x8001efb,
++0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001,
++0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
++0x0, 0x316300ff, 0x24020001, 0x54620078,
++0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054,
++0x24690032, 0x1221023, 0x2c420033, 0x10400061,
++0x5821, 0x240e0008, 0x240d0011, 0x240a0012,
++0x24080040, 0x240c0001, 0x8f830120, 0x27623800,
++0x24660020, 0xc2102b, 0x50400001, 0x27663000,
++0x8f820128, 0x10c20004, 0x0, 0x8f820124,
++0x14c20007, 0x0, 0x8ee201a4, 0x3821,
++0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4,
++0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
++0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400033, 0x24070001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x144a001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x10480007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x8001f54,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400010, 0xac800000, 0x8001f67,
++0x0, 0x8ee24e30, 0x24420001, 0x50480003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
++0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
++0x0, 0x316300ff, 0x24020001, 0x10620022,
++0x0, 0x3c040001, 0x24845390, 0xafa00010,
++0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
++0xc002403, 0x34a5f011, 0x8001f93, 0x0,
++0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120,
++0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
++0x8001f93, 0x0, 0x3c040001, 0x248453a8,
++0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
++0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
++0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
++0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001,
++0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020,
++0x21200, 0x21d02, 0x24020001, 0x10620005,
++0x24020002, 0x1062000d, 0x0, 0x8001fb7,
++0xafa00010, 0x92e204d8, 0x14400006, 0x24020001,
++0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
++0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
++0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
++0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8,
++0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
++0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
++0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
++0x22502, 0x24020001, 0x10820005, 0x24020002,
++0x1082000f, 0x0, 0x8001fe3, 0xafa00010,
++0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
++0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
++0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
++0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
++0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
++0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4,
++0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
++0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
++0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
++0x21d02, 0x24020001, 0x10620005, 0x24020002,
++0x1062000e, 0x0, 0x8002011, 0xafa00010,
++0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
++0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
++0x370821, 0x8002018, 0xa02283b3, 0x3c020001,
++0x571021, 0x904283b2, 0x3c010001, 0x370821,
++0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
++0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
++0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020,
++0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
++0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
++0x27840208, 0x27450200, 0xc00249a, 0x24060008,
++0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
++0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
++0x8ee20134, 0x8f460248, 0x2021, 0xc005108,
++0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
++0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
++0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
++0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070,
++0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0,
++0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070,
++0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
++0x27450200, 0x24060008, 0xaee20068, 0x24020006,
++0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00,
++0xaee2006c, 0x240203e8, 0x24040002, 0x24030001,
++0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
++0x30420008, 0x10400004, 0x0, 0xaee30108,
++0x8002061, 0x2021, 0xaee40108, 0x2021,
++0x3c030001, 0x641821, 0x90635c30, 0x2e41021,
++0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
++0x0, 0x8f820040, 0x2e41821, 0x24840001,
++0x21702, 0x24420030, 0xa062009c, 0x2e41021,
++0x80022e8, 0xa040009c, 0x24020001, 0x3c010001,
++0x370821, 0xa02283e0, 0x240b0400, 0x24080014,
++0x240a0040, 0x24090001, 0x8f830100, 0x27623000,
++0x24660020, 0xc2102b, 0x50400001, 0x27662800,
++0x8f820108, 0x10c20004, 0x0, 0x8f820104,
++0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821,
++0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8,
++0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e,
++0xac680018, 0xac60001c, 0xac640000, 0xac650004,
++0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec,
++0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001,
++0x504a0003, 0x1021, 0x8ee24e28, 0x24420001,
++0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2,
++0x0, 0x80022e8, 0x0, 0x3c020900,
++0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244,
++0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1,
++0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
++0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
++0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
++0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
++0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
++0x5821, 0x24100008, 0x240f000d, 0x240d0007,
++0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
++0x24e80020, 0x102102b, 0x50400001, 0x27683000,
++0x8f820128, 0x11020004, 0x0, 0x8f820124,
++0x15020007, 0x1021, 0x8ee201a4, 0x3821,
++0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4,
++0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
++0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xace40000, 0xace50004, 0x8ee20608,
++0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
++0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
++0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
++0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c820000, 0x144d001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
++0x8ee24e34, 0x24420001, 0x10620005, 0x0,
++0x8002119, 0x0, 0x14600005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
++0x800212c, 0x0, 0x8ee24e30, 0x24420001,
++0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
++0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
++0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
++0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
++0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
++0x10400061, 0x5821, 0x240e0008, 0x240d0011,
++0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x3821, 0x24420001, 0xaee201a4, 0x8002198,
++0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
++0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
++0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
++0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
++0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c820000, 0x144a001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x10480007, 0x0,
++0x8ee24e34, 0x24420001, 0x10620005, 0x0,
++0x8002185, 0x0, 0x14600005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
++0x8002198, 0x0, 0x8ee24e30, 0x24420001,
++0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
++0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
++0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
++0x10620022, 0x0, 0x3c040001, 0x24845390,
++0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
++0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
++0x0, 0x3c040001, 0x2484539c, 0xafa00014,
++0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
++0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
++0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
++0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
++0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
++0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
++0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168,
++0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
++0x27450200, 0x24060008, 0xc00249a, 0xaee20068,
++0x8f820220, 0x30420008, 0x14400002, 0x24020001,
++0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
++0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
++0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020,
++0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
++0x3c030700, 0x34631000, 0x431025, 0xafa20018,
++0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
++0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0,
++0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
++0xac440610, 0x8f870120, 0x27623800, 0x24e80020,
++0x102102b, 0x50400001, 0x27683000, 0x8f820128,
++0x11020004, 0x0, 0x8f820124, 0x15020007,
++0x1021, 0x8ee201a4, 0x3821, 0x24420001,
++0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608,
++0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
++0xa32821, 0xa3302b, 0x822021, 0x862021,
++0xace40000, 0xace50004, 0x8ee30608, 0x24020008,
++0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c,
++0x318c0, 0x2463060c, 0x2e31021, 0xace20008,
++0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
++0x14400037, 0x24070001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
++0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
++0x10430007, 0x0, 0x8ee24e34, 0x24420001,
++0x10a20005, 0x0, 0x8002247, 0x0,
++0x14a00005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400013, 0xac800000, 0x800225d, 0x0,
++0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020007, 0xac820000, 0x24020001, 0xac820004,
++0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4,
++0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
++0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
++0x0, 0x8f830120, 0x27623800, 0x24660020,
++0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
++0x10c20004, 0x0, 0x8f820124, 0x14c20007,
++0x0, 0x8ee201a4, 0x3821, 0x24420001,
++0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608,
++0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c,
++0xac620008, 0x24020008, 0xa462000e, 0x24020011,
++0xac620018, 0xac640000, 0xac650004, 0x8ee204c4,
++0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
++0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c830000, 0x24020012, 0x1462001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x24030040, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
++0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
++0x0, 0x80022ae, 0x0, 0x14a00005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
++0xac800000, 0x80022c4, 0x0, 0x8ee24e30,
++0x24030040, 0x24420001, 0x50430003, 0x1021,
++0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x24020012,
++0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
++0x0, 0x3c040001, 0x248453fc, 0xafa00010,
++0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
++0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
++0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
++0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228,
++0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
++0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
++0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
++0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c,
++0x8f42010c, 0x14620009, 0x24020002, 0xaf820064,
++0x8f820064, 0x14400005, 0x0, 0x8f43022c,
++0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044,
++0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034,
++0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
++0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014,
++0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
++0x24840001, 0x3021, 0x1071026, 0x30420001,
++0x10400002, 0x81842, 0x6a1826, 0x604021,
++0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
++0x25290001, 0x125102b, 0x1440fff0, 0x0,
++0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8,
++0x27642800, 0xafbf0010, 0xc002488, 0x24051000,
++0x24020021, 0xaf800100, 0xaf800104, 0xaf800108,
++0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120,
++0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134,
++0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30,
++0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040,
++0x10400004, 0x0, 0x8f82011c, 0x34420004,
++0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
++0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
++0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
++0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403,
++0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
++0x3c020400, 0x10620029, 0x43102b, 0x14400008,
++0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
++0x10620011, 0x0, 0x8002374, 0x0,
++0x10620008, 0x3c024000, 0x1462001c, 0x0,
++0x8ee20190, 0x24420001, 0xaee20190, 0x8002374,
++0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c,
++0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002,
++0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
++0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd,
++0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001,
++0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0,
++0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
++0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
++0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
++0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0,
++0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
++0x8021, 0x43102b, 0x14400008, 0x3c042000,
++0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
++0x0, 0x80023e0, 0x0, 0x10640003,
++0x3c024000, 0x14620045, 0x0, 0x8f8200a0,
++0x441024, 0x10400006, 0x0, 0x8ee20194,
++0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194,
++0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198,
++0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c,
++0x30420200, 0x1040001b, 0x0, 0x8f8300a0,
++0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001,
++0x3c020001, 0x3442f000, 0x621024, 0x50400001,
++0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0,
++0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124,
++0x8f820124, 0x27633000, 0x43102b, 0x10400005,
++0x276237e0, 0xaf820124, 0x80023ca, 0x0,
++0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024,
++0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002,
++0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
++0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd,
++0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001,
++0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
++0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
++0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
++0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012,
++0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021,
++0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
++0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250,
++0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
++0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010,
++0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94,
++0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
++0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004,
++0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
++0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
++0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0,
++0x62182b, 0x10600005, 0x0, 0x3c020001,
++0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
++0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
++0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
++0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
++0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0,
++0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
++0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
++0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
++0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001,
++0x8c425c40, 0xc09021, 0xe09821, 0x10800006,
++0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
++0x800244e, 0x0, 0x24a40008, 0xc002488,
++0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001,
++0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94,
++0x45102b, 0x10400005, 0x0, 0x3c020001,
++0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
++0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001,
++0x8c635d94, 0x8e020004, 0xac620004, 0xac710008,
++0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94,
++0x45102b, 0xac720010, 0xac730014, 0xac740018,
++0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
++0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
++0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
++0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
++0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
++0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
++0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
++0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd,
++0x24840004, 0x3e00008, 0x0, 0x10c00007,
++0x0, 0x8c820000, 0x24840004, 0x24c6fffc,
++0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008,
++0x0, 0x10c00007, 0x0, 0x8ca20000,
++0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb,
++0x24840004, 0x3e00008, 0x0, 0x3e00008,
++0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4,
++0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4,
++0x8ee304fc, 0x21100, 0x626021, 0x95870008,
++0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c,
++0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b,
++0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258,
++0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003,
++0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c,
++0x8ee3726c, 0x441021, 0x62182b, 0x10600006,
++0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8,
++0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200,
++0x1040014d, 0x4821, 0x96e2045a, 0x30420010,
++0x10400149, 0x0, 0x8f840100, 0x27623000,
++0x24850020, 0xa2102b, 0x50400001, 0x27652800,
++0x8f820108, 0x10a20004, 0x0, 0x8f820104,
++0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001,
++0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000,
++0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e,
++0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c,
++0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec,
++0x14400036, 0x24090001, 0x8ee24e28, 0x210c0,
++0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f,
++0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
++0x24030040, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
++0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
++0x0, 0x8002516, 0x0, 0x14a00005,
++0x0, 0x8f820108, 0x24420020, 0xaf820108,
++0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
++0xac800000, 0x800252c, 0x0, 0x8ee24e28,
++0x24030040, 0x24420001, 0x50430003, 0x1021,
++0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
++0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
++0xac820000, 0x24020001, 0xac820004, 0x1520000a,
++0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
++0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
++0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
++0x3641821, 0x24420010, 0x43102b, 0x14400073,
++0x0, 0x8ee27264, 0x24480010, 0x3641021,
++0x102102b, 0x14400002, 0x3c02ffff, 0x1024021,
++0x8f850100, 0x27623000, 0x24a60020, 0xc2102b,
++0x50400001, 0x27662800, 0x8f820108, 0x10c20004,
++0x0, 0x8f820104, 0x14c20007, 0x2563000c,
++0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
++0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021,
++0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e,
++0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4,
++0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025,
++0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037,
++0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e22021, 0x8c830000, 0x24020005, 0x1462001f,
++0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
++0x24030040, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
++0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
++0x0, 0x800258a, 0x0, 0x14a00005,
++0x0, 0x8f820108, 0x24420020, 0xaf820108,
++0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
++0xac800000, 0x80025a0, 0x0, 0x8ee24e28,
++0x24030040, 0x24420001, 0x50430003, 0x1021,
++0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
++0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
++0xac820000, 0x24020001, 0xac820004, 0x1520000a,
++0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
++0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
++0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
++0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
++0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
++0x27662800, 0x8f820108, 0x10c20004, 0x0,
++0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8,
++0x4821, 0x24420001, 0xaee201a8, 0x800260d,
++0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000,
++0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e,
++0x24020006, 0xaca20018, 0x24630010, 0xaca30008,
++0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002,
++0x431025, 0xaca20010, 0xaf860100, 0x92e204ec,
++0x14400037, 0x24090001, 0x8ee24e28, 0x210c0,
++0x24424e38, 0x2e22021, 0x8c830000, 0x24020005,
++0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c,
++0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001,
++0x10430007, 0x0, 0x8ee24e2c, 0x24420001,
++0x10a20005, 0x0, 0x80025f7, 0x0,
++0x14a00005, 0x0, 0x8f820108, 0x24420020,
++0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011,
++0x50400013, 0xac800000, 0x800260d, 0x0,
++0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x24020005, 0xac820000, 0x24020001, 0xac820004,
++0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
++0x3c040001, 0x24845730, 0x3c050004, 0xafa20014,
++0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
++0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
++0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
++0x24850020, 0xa2102b, 0x50400001, 0x27652800,
++0x8f820108, 0x10a20004, 0x0, 0x8f820104,
++0x14a20007, 0x24020006, 0x8ee201a8, 0x4821,
++0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8,
++0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e,
++0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c,
++0x8ee204c8, 0x3c030002, 0x431025, 0xac820010,
++0xaf850100, 0x92e204ec, 0x14400037, 0x24090001,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x8c830000, 0x24020005, 0x1462001f, 0x0,
++0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
++0x8ee54e28, 0x24420001, 0x10430007, 0x0,
++0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
++0x8002661, 0x0, 0x14a00005, 0x0,
++0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x8002677, 0x0, 0x8ee24e28, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
++0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
++0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
++0x24020001, 0xac820004, 0x15200009, 0x3c050004,
++0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
++0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
++0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
++0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
++0x431021, 0xac44000c, 0x8ee27258, 0xafa20018,
++0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
++0x10400004, 0x24620001, 0x2403fffe, 0x431024,
++0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800,
++0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007,
++0x451024, 0x24630007, 0xaee27258, 0x8ee2726c,
++0x8ee47258, 0x651824, 0x431023, 0xaee2726c,
++0x3661021, 0x82202b, 0x14800004, 0x3c03ffff,
++0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258,
++0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800,
++0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4,
++0x14e20007, 0x0, 0x8ee201b4, 0x4821,
++0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4,
++0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
++0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
++0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
++0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018,
++0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
++0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
++0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
++0x10620016, 0x28620003, 0x10400005, 0x24020001,
++0x10620008, 0x0, 0x8002703, 0x0,
++0x24020003, 0x10620017, 0x0, 0x8002703,
++0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
++0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
++0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0,
++0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
++0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703,
++0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
++0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
++0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0,
++0x8ee500e4, 0x401821, 0x1021, 0xa32821,
++0xa3302b, 0x822021, 0x862021, 0xaee400e0,
++0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff,
++0x104001c1, 0x31a20200, 0x1040014d, 0x4821,
++0x96e2045a, 0x30420010, 0x10400149, 0x0,
++0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
++0x50400001, 0x27652800, 0x8f820108, 0x10a20004,
++0x0, 0x8f820104, 0x14a20006, 0x2402000c,
++0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e,
++0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264,
++0x24060005, 0xa482000e, 0xac860018, 0xac830008,
++0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010,
++0xaf850100, 0x92e204ec, 0x14400036, 0x24090001,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x8c820000, 0x1446001f, 0x0, 0x8ee34e28,
++0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
++0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
++0x24420001, 0x10a20005, 0x0, 0x8002758,
++0x0, 0x14a00005, 0x0, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x800276e,
++0x0, 0x8ee24e28, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
++0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e22021, 0x24020005, 0xac820000, 0x24020001,
++0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
++0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
++0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
++0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
++0x43102b, 0x14400073, 0x0, 0x8ee27264,
++0x24480010, 0x3641021, 0x102102b, 0x14400002,
++0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000,
++0x24a60020, 0xc2102b, 0x50400001, 0x27662800,
++0x8f820108, 0x10c20004, 0x0, 0x8f820104,
++0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821,
++0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8,
++0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004,
++0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008,
++0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8,
++0x3c030002, 0x431025, 0xaca20010, 0xaf860100,
++0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28,
++0x210c0, 0x24424e38, 0x2e22021, 0x8c830000,
++0x24020005, 0x1462001f, 0x0, 0x8ee34e28,
++0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
++0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
++0x24420001, 0x10a20005, 0x0, 0x80027cc,
++0x0, 0x14a00005, 0x0, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x80027e2,
++0x0, 0x8ee24e28, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
++0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e22021, 0x24020005, 0xac820000, 0x24020001,
++0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
++0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
++0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
++0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
++0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
++0xc2102b, 0x50400001, 0x27662800, 0x8f820108,
++0x10c20004, 0x0, 0x8f820104, 0x14c20007,
++0x2563000c, 0x8ee201a8, 0x4821, 0x24420001,
++0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c,
++0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264,
++0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018,
++0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c,
++0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010,
++0xaf860100, 0x92e204ec, 0x14400037, 0x24090001,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x8c830000, 0x24020005, 0x1462001f, 0x0,
++0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
++0x8ee54e28, 0x24420001, 0x10430007, 0x0,
++0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
++0x8002839, 0x0, 0x14a00005, 0x0,
++0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x800284f, 0x0, 0x8ee24e28, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
++0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
++0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
++0x24020001, 0xac820004, 0x1520000a, 0x34028100,
++0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
++0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
++0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
++0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
++0x8f830100, 0x27623000, 0x24640020, 0x82102b,
++0x50400001, 0x27642800, 0x8f820108, 0x10820004,
++0x0, 0x8f820104, 0x14820007, 0x24050005,
++0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
++0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004,
++0x8ee27264, 0xa467000e, 0xac650018, 0xac620008,
++0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010,
++0xaf840100, 0x92e204ec, 0x14400036, 0x24090001,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
++0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
++0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
++0x24420001, 0x10a20005, 0x0, 0x80028a0,
++0x0, 0x14a00005, 0x0, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x80028b6,
++0x0, 0x8ee24e28, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
++0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e22021, 0x24020005, 0xac820000, 0x24020001,
++0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
++0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4,
++0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
++0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
++0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
++0x34a53800, 0x441021, 0xaee2725c, 0x3651021,
++0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264,
++0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458,
++0x24630001, 0x2442ffff, 0x621824, 0xaee304e4,
++0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0,
++0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
++0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0,
++0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189,
++0x0, 0x8ee204e8, 0x8ee304fc, 0x21100,
++0x621821, 0x94670008, 0x92e204ed, 0x8c680000,
++0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8,
++0x34460400, 0x31420200, 0x1040001f, 0x0,
++0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000,
++0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264,
++0x9464000e, 0x3c050001, 0x34a53800, 0x24420004,
++0xaee27264, 0x8ee37264, 0x42400, 0x3651021,
++0x3c010001, 0x370821, 0xac2483dc, 0x62182b,
++0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff,
++0x431021, 0xaee27264, 0x8ee27264, 0x8002917,
++0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff,
++0x44102a, 0x10400015, 0x0, 0x8f8200d8,
++0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c,
++0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001,
++0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a,
++0x10400006, 0x0, 0x8ee201b8, 0x24420001,
++0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001,
++0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc,
++0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001,
++0x571021, 0x8c4283d8, 0x1040002f, 0x5021,
++0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
++0x50400001, 0x27652800, 0x8f820108, 0x10a20032,
++0x0, 0x8f820104, 0x10a2002f, 0x24020015,
++0xac880000, 0xac890004, 0x8ee37264, 0xa487000e,
++0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001,
++0x771821, 0x8c6383dc, 0xac860010, 0x431025,
++0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066,
++0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
++0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e21821, 0x24020015, 0xac620000, 0x24020001,
++0x80029bf, 0xac620004, 0x8f840100, 0x27623000,
++0x24850020, 0xa2102b, 0x50400001, 0x27652800,
++0x8f820108, 0x10a20004, 0x0, 0x8f820104,
++0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001,
++0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000,
++0xac890004, 0x8ee37264, 0xa487000e, 0xac820018,
++0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c,
++0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x8c830000, 0x24020005, 0x1462001f, 0x0,
++0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
++0x8ee54e28, 0x24420001, 0x10430007, 0x0,
++0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
++0x80029a9, 0x0, 0x14a00005, 0x0,
++0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x80029bf, 0x0, 0x8ee24e28, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
++0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
++0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
++0x24020001, 0xac820004, 0x1540000a, 0x24020001,
++0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730,
++0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
++0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
++0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
++0x370821, 0xac2083d8, 0x3c010001, 0x370821,
++0xac2083dc, 0x21100, 0x431021, 0xac44000c,
++0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021,
++0x24420007, 0x451024, 0x24630007, 0xaee27258,
++0x8ee2726c, 0x8ee47258, 0x651824, 0x431023,
++0xaee2726c, 0x3661021, 0x82202b, 0x14800004,
++0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258,
++0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073,
++0x0, 0x8f830100, 0x27623000, 0x24640020,
++0x82102b, 0x14400002, 0x5021, 0x27642800,
++0x8f820108, 0x10820004, 0x0, 0x8f820104,
++0x14820006, 0x24050005, 0x8ee201a8, 0x24420001,
++0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000,
++0xac690004, 0x8ee27264, 0xa467000e, 0xac650018,
++0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c,
++0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
++0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
++0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
++0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
++0x24420001, 0x10a20005, 0x0, 0x8002a30,
++0x0, 0x14a00005, 0x0, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x8002a46,
++0x0, 0x8ee24e28, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
++0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
++0x2e22021, 0x24020005, 0xac820000, 0x24020001,
++0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
++0x24845748, 0x3c050004, 0xafa90010, 0xafa00014,
++0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
++0x8002a72, 0x0, 0x8ee27264, 0x451021,
++0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
++0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c,
++0x3641021, 0x62182b, 0x14600004, 0x3c03ffff,
++0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8,
++0x96e20458, 0x24630001, 0x2442ffff, 0x621824,
++0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005,
++0x0, 0x8f820060, 0x2403fff7, 0x431024,
++0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020,
++0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100,
++0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040,
++0x24630001, 0x50620003, 0x1021, 0x8ee24e2c,
++0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c,
++0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28,
++0x8c870004, 0x14620007, 0xa03021, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2,
++0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e2c, 0x24420001,
++0x210c0, 0x24424e38, 0x2e22021, 0x8c820004,
++0x8f830108, 0x21140, 0x621821, 0xaf830108,
++0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
++0x104000c1, 0x31080, 0x3c010001, 0x220821,
++0x8c225770, 0x400008, 0x0, 0x8ee204f0,
++0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
++0x43102b, 0x144000be, 0x0, 0x8ee304e4,
++0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x8021, 0x24420001, 0xaee201a4, 0x8002b12,
++0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
++0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
++0xa462000e, 0x24020011, 0xac620018, 0xac640000,
++0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
++0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
++0x24420001, 0x10430007, 0x0, 0x8ee24e34,
++0x24420001, 0x10a20005, 0x0, 0x8002afc,
++0x0, 0x14a00005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x8002b12,
++0x0, 0x8ee24e30, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x24020012, 0xac820000, 0x24020001,
++0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
++0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
++0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
++0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
++0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
++0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0,
++0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274,
++0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184,
++0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee20504,
++0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018,
++0x21080, 0x571021, 0x8c440508, 0x24020003,
++0x1462000f, 0x0, 0x3c020001, 0x571021,
++0x904283b1, 0x10400014, 0x0, 0x8ee201d0,
++0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8,
++0x641821, 0x306300ff, 0x8002b59, 0xaee35240,
++0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc,
++0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10,
++0x441021, 0xaee201d8, 0x8ee20000, 0x34420040,
++0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
++0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
++0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
++0x3c040001, 0x24845760, 0xafa60014, 0xafa20010,
++0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
++0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
++0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
++0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048,
++0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104,
++0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
++0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
++0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
++0x31080, 0x3c010001, 0x220821, 0x8c2257c0,
++0x400008, 0x0, 0x9663000e, 0x8ee2725c,
++0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
++0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
++0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c,
++0x82202b, 0x148003b9, 0x0, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x8021, 0x24420001, 0xaee201a4, 0x8002bfe,
++0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
++0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
++0xa462000e, 0x24020011, 0xac620018, 0xac640000,
++0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
++0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x8002be8,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400013, 0xac800000, 0x8002bfe,
++0x0, 0x8ee24e30, 0x240c0040, 0x24420001,
++0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
++0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
++0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
++0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
++0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
++0x240c0001, 0x8002f19, 0x0, 0x966c001c,
++0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024,
++0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc,
++0x151900, 0x621021, 0x8c52000c, 0x92e27b98,
++0x641821, 0x9476000a, 0x14400003, 0x32c20002,
++0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021,
++0x96e2045a, 0x30420002, 0x10400047, 0x0,
++0x8e63001c, 0x8ee204fc, 0x32100, 0x821021,
++0x8c42000c, 0x37e1821, 0x24420022, 0x43102b,
++0x1440000a, 0x24050014, 0x8ee204fc, 0x821021,
++0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e,
++0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc,
++0x821021, 0x8c42000c, 0x9450000e, 0x94430010,
++0x94440012, 0x94450014, 0x2038021, 0x2048021,
++0x2058021, 0x94430016, 0x94440018, 0x9445001a,
++0x2038021, 0x2048021, 0x2058021, 0x9443001c,
++0x9444001e, 0x94420020, 0x2038021, 0x2048021,
++0x2028021, 0x101c02, 0x3202ffff, 0x628021,
++0x8e63001c, 0x8ee204fc, 0x102402, 0x32900,
++0xa21021, 0x8c43000c, 0x3202ffff, 0x828021,
++0x37e1021, 0x24630018, 0x62182b, 0x14600009,
++0x0, 0x8ee204fc, 0xa21021, 0x8c43000c,
++0x101027, 0x3c01ffff, 0x230821, 0x8002c6f,
++0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c,
++0x101027, 0xa4620018, 0x96e2045a, 0x8821,
++0x30420008, 0x14400063, 0xa021, 0x8e63001c,
++0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c,
++0x37e1821, 0x24420022, 0x43102b, 0x14400035,
++0x0, 0x8ee204fc, 0xc21021, 0x8c42000c,
++0x24470010, 0x37e1021, 0xe2102b, 0x50400001,
++0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021,
++0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b,
++0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc,
++0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a,
++0x37e1021, 0xe2102b, 0x14400002, 0x2838821,
++0xeb3821, 0x94e20000, 0x24e70002, 0x2228821,
++0x37e1021, 0xe2102b, 0x50400001, 0xeb3821,
++0x94e20000, 0x24e70002, 0x2228821, 0x37e1021,
++0xe2102b, 0x50400001, 0xeb3821, 0x94e20000,
++0x24e70002, 0x2228821, 0x37e1021, 0xe2102b,
++0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0,
++0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c,
++0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021,
++0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec,
++0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821,
++0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821,
++0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c,
++0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020,
++0x2238821, 0x2248821, 0x2228821, 0x111c02,
++0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
++0x628821, 0x32c20001, 0x104000b2, 0x0,
++0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080,
++0x10400008, 0x0, 0x92e27b98, 0x14400005,
++0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c,
++0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021,
++0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b,
++0x14400008, 0xe02021, 0x2405000e, 0xc002f75,
++0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09,
++0x2028021, 0x94e60000, 0x24e70002, 0x94e50000,
++0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000,
++0x24e70002, 0x94e40000, 0x24e70002, 0x2068021,
++0x2058021, 0x2038021, 0x2028021, 0x94e20000,
++0x94e30002, 0x2048021, 0x2028021, 0x2038021,
++0x101c02, 0x3202ffff, 0x628021, 0x101c02,
++0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004,
++0x3205ffff, 0x96620016, 0x8002d17, 0x512021,
++0x96620016, 0x542021, 0x41402, 0x3083ffff,
++0x432021, 0x852023, 0x41402, 0x822021,
++0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4,
++0x24430017, 0x37e1021, 0x62102b, 0x50400001,
++0x6b1821, 0x90630000, 0x24020011, 0x14620031,
++0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028,
++0x43102b, 0x14400018, 0x0, 0x8ee27b9c,
++0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff,
++0x220821, 0x94220028, 0x822021, 0x41c02,
++0x3082ffff, 0x622021, 0x32c20100, 0x14400004,
++0x41027, 0x92e27b98, 0x14400002, 0x41027,
++0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821,
++0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008,
++0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021,
++0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
++0x14400004, 0x41027, 0x92e27b98, 0x14400002,
++0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a,
++0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4,
++0x24420032, 0x43102b, 0x14400018, 0x0,
++0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4,
++0x3c01ffff, 0x220821, 0x94220032, 0x822021,
++0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
++0x14400004, 0x41027, 0x92e27b98, 0x14400002,
++0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff,
++0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c,
++0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032,
++0x822021, 0x41c02, 0x3082ffff, 0x622021,
++0x32c20100, 0x14400004, 0x41027, 0x92e27b98,
++0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4,
++0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821,
++0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b,
++0x1440001b, 0x34038100, 0x26430004, 0x37e1021,
++0x62102b, 0x14400003, 0x602021, 0x6b1821,
++0x602021, 0x8c620000, 0x24630004, 0xae420000,
++0x37e1021, 0x62102b, 0x50400001, 0x6b1821,
++0x8c620000, 0xac820000, 0x34028100, 0xa4620000,
++0x24630002, 0x37e1021, 0x62102b, 0x50400001,
++0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000,
++0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e,
++0xa64c000a, 0xae420000, 0xae440004, 0x9662000e,
++0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e,
++0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018,
++0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
++0x10400004, 0x24620001, 0x2403fffe, 0x431024,
++0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100,
++0x8ee27ba8, 0x24430001, 0x210c0, 0x571021,
++0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac,
++0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072,
++0x0, 0x8ee27ba8, 0x24430001, 0x210c0,
++0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c,
++0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063,
++0x4821, 0x5021, 0x8f8200f0, 0x24480008,
++0x27621800, 0x102102b, 0x50400001, 0x27681000,
++0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4,
++0x8021, 0x24420001, 0xaee201b4, 0x8002dfa,
++0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021,
++0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004,
++0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088,
++0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088,
++0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c,
++0x401821, 0x1021, 0xa32821, 0xa3382b,
++0x822021, 0x872021, 0x8ee204fc, 0xc93021,
++0x63100, 0xaee400e0, 0xaee500e4, 0xc23021,
++0x94c2000a, 0x240c0002, 0x21142, 0x30430003,
++0x106c0016, 0x28620003, 0x10400005, 0x240c0001,
++0x106c0008, 0x0, 0x8002e3f, 0x0,
++0x240c0003, 0x106c0017, 0x0, 0x8002e3f,
++0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
++0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
++0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0,
++0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
++0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f,
++0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
++0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
++0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001,
++0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98,
++0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008,
++0x27621800, 0xe2102b, 0x50400001, 0x27671000,
++0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4,
++0x8021, 0x24420001, 0xaee201b4, 0x8002e5d,
++0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018,
++0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0,
++0x16000007, 0x0, 0x8ee20088, 0x24420001,
++0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c,
++0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002,
++0x401821, 0x1021, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0x161142, 0x30430003,
++0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003,
++0x10400005, 0x240c0001, 0x106c0008, 0x0,
++0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019,
++0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8,
++0x8ee300ec, 0x24630001, 0x2c640001, 0x441021,
++0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec,
++0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4,
++0x24630001, 0x2c640001, 0x441021, 0xaee200f0,
++0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0,
++0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001,
++0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
++0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c,
++0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff,
++0x431024, 0x24840001, 0xaee204e4, 0xaee404f0,
++0x8f42023c, 0x82202b, 0x148000b0, 0x0,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
++0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
++0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
++0x24020008, 0xa462000e, 0x24020011, 0xac620018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c830000, 0x24020012, 0x1462001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
++0x8ee24e34, 0x24420001, 0x10620005, 0x0,
++0x8002ef1, 0x0, 0x14600005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x8002f07, 0x0, 0x8ee24e30, 0x240c0040,
++0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
++0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
++0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014,
++0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
++0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
++0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
++0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170,
++0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274,
++0xaee204f8, 0x8f42023c, 0x10400038, 0x0,
++0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c,
++0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001,
++0x504c0003, 0x1021, 0x8ee20504, 0x24420001,
++0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003,
++0x21080, 0x571021, 0x146c000f, 0x8c440508,
++0x3c020001, 0x571021, 0x904283b1, 0x10400014,
++0x0, 0x8ee201d0, 0x8ee35240, 0x441021,
++0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff,
++0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10,
++0x441021, 0xaee201cc, 0x8ee201d8, 0x641821,
++0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8,
++0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000,
++0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0,
++0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x8f820108,
++0x27633000, 0x43102b, 0x14400002, 0x27622800,
++0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e,
++0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058,
++0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048,
++0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068,
++0x52843, 0x10a0000d, 0x3021, 0x3c030001,
++0x34633800, 0x3c07ffff, 0x3631021, 0x82102b,
++0x50400001, 0x872021, 0x94820000, 0x24840002,
++0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02,
++0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff,
++0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88,
++0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068,
++0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058,
++0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c,
++0x8ee204d4, 0x8021, 0x30420001, 0x1440002a,
++0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8,
++0xe22023, 0x2c821000, 0x50400001, 0x24841000,
++0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8,
++0x3c02000a, 0x3442efff, 0x1032023, 0x44102b,
++0x10400003, 0x3c02000a, 0x3442f000, 0x822021,
++0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021,
++0xa32821, 0xa3302b, 0x822021, 0x862021,
++0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4,
++0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021,
++0x904283c0, 0x1040000b, 0x0, 0x3c140001,
++0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821,
++0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193,
++0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007,
++0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
++0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
++0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
++0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0,
++0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
++0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
++0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
++0x2409821, 0x3c020080, 0x621024, 0x1040000a,
++0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c,
++0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc,
++0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001,
++0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080,
++0x3c080020, 0x34078000, 0x24420001, 0xaee20080,
++0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021,
++0xc3102b, 0x14400007, 0x0, 0x106b0011,
++0x0, 0x106a0015, 0x0, 0x8003049,
++0x42042, 0x10650023, 0xa3102b, 0x14400005,
++0x0, 0x10690019, 0x0, 0x8003049,
++0x42042, 0x10680021, 0x0, 0x8003049,
++0x42042, 0x8ee20034, 0x24420001, 0xaee20034,
++0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec,
++0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049,
++0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0,
++0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4,
++0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049,
++0x42042, 0x8ee20030, 0x24420001, 0xaee20030,
++0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8,
++0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042,
++0x1087047c, 0x0, 0x800300e, 0x0,
++0x3c020001, 0x571021, 0x904283b2, 0x14400084,
++0x24020001, 0x3c030001, 0x771821, 0x906383b3,
++0x1462007f, 0x3c020100, 0x8e430000, 0x621024,
++0x1040006f, 0x2402ffff, 0x14620005, 0x24100001,
++0x96430004, 0x3402ffff, 0x10620075, 0x0,
++0x92e204d8, 0x14400072, 0x0, 0x3c020001,
++0x571021, 0x8c4283b4, 0x28420005, 0x10400020,
++0x3821, 0x3c020001, 0x571021, 0x8c4283b4,
++0x18400016, 0x2821, 0x96660000, 0x520c0,
++0x971021, 0x9442777e, 0x14460009, 0x971021,
++0x94437780, 0x96620002, 0x14620005, 0x971021,
++0x94437782, 0x96620004, 0x50620008, 0x24070001,
++0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001,
++0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff,
++0x10400440, 0x0, 0x80030d5, 0x0,
++0x2402021, 0xc0022fe, 0x24050006, 0x3044001f,
++0x428c0, 0x2e51021, 0x9442727c, 0x30424000,
++0x14400434, 0xb71021, 0x9443727e, 0x96620000,
++0x1462000b, 0x418c0, 0xb71021, 0x94437280,
++0x96620002, 0x14620006, 0x418c0, 0xb71021,
++0x94437282, 0x96620004, 0x10620035, 0x418c0,
++0x2e31021, 0x9442727c, 0x30428000, 0x14400421,
++0x2e31021, 0x944b727c, 0x96670000, 0xb28c0,
++0xb71021, 0x9442737e, 0x80030b7, 0x3021,
++0x420c0, 0x2e41021, 0x9443737c, 0x2e41021,
++0x944b737c, 0x30638000, 0x14600010, 0xb28c0,
++0xb71021, 0x9442737e, 0x1447fff5, 0x1602021,
++0xb71021, 0x94437380, 0x96620002, 0x5462fff1,
++0x420c0, 0xb71021, 0x94437382, 0x96620004,
++0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff,
++0x10400400, 0x0, 0x80030d5, 0x0,
++0x97430202, 0x96420000, 0x146203fa, 0x0,
++0x97430204, 0x96420002, 0x146203f6, 0x0,
++0x97430206, 0x96420004, 0x146203f2, 0x0,
++0x92420000, 0x3a030001, 0x30420001, 0x431024,
++0x10400074, 0x2402ffff, 0x8e630000, 0x14620004,
++0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002,
++0x3c020001, 0x571021, 0x904283b2, 0x1440006a,
++0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c,
++0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
++0x10400020, 0x3821, 0x3c020001, 0x571021,
++0x8c4283b4, 0x18400016, 0x2821, 0x96660000,
++0x520c0, 0x971021, 0x9442777e, 0x14460009,
++0x971021, 0x94437780, 0x96620002, 0x14620005,
++0x971021, 0x94437782, 0x96620004, 0x50620008,
++0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
++0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
++0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6,
++0x0, 0x2402021, 0xc0022fe, 0x24050006,
++0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
++0x30424000, 0x144003af, 0xb71021, 0x9443727e,
++0x96620000, 0x1462000b, 0x418c0, 0xb71021,
++0x94437280, 0x96620002, 0x14620006, 0x418c0,
++0xb71021, 0x94437282, 0x96620004, 0x10620027,
++0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
++0x1440039c, 0x2e31021, 0x944b727c, 0x96670000,
++0xb28c0, 0xb71021, 0x9442737e, 0x800313c,
++0x3021, 0x420c0, 0x2e41021, 0x9443737c,
++0x2e41021, 0x944b737c, 0x30638000, 0x14600010,
++0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5,
++0x1602021, 0xb71021, 0x94437380, 0x96620002,
++0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
++0x96620004, 0x5462ffec, 0x420c0, 0x24060001,
++0x30c200ff, 0x1040037b, 0x0, 0x800314f,
++0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260,
++0x54102b, 0x1040003a, 0x0, 0x8f8300e4,
++0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
++0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
++0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
++0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
++0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
++0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
++0xc002403, 0x34a5f003, 0x80034cc, 0x0,
++0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
++0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
++0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
++0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
++0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
++0x96e20468, 0x54102b, 0x10400003, 0x0,
++0x240f0001, 0xa3af0027, 0x12800301, 0x24160007,
++0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c,
++0x8f430280, 0x24420001, 0x304207ff, 0x106202d3,
++0x0, 0x93a20027, 0x10400014, 0x0,
++0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244,
++0x8ee65244, 0x8ee35244, 0x21140, 0x24425248,
++0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff,
++0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0,
++0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
++0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18,
++0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021,
++0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010,
++0x10400019, 0x0, 0x9642000c, 0x340f8100,
++0x144f0015, 0x0, 0x3c020001, 0x571021,
++0x904283c0, 0x14400010, 0x0, 0x9642000e,
++0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000,
++0x2694fffc, 0xae42000c, 0xae430008, 0xae440004,
++0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037,
++0x34420200, 0xa602000e, 0x8e020000, 0x8e030004,
++0x3c040001, 0x34843800, 0x306a0007, 0x26a9823,
++0x3641021, 0x262102b, 0x10400005, 0x28aa021,
++0x2641023, 0x3621823, 0x3c020020, 0x439823,
++0x26820007, 0x2404fff8, 0x9603000a, 0x446024,
++0x6a1821, 0x6c102b, 0x10400002, 0x1803821,
++0x603821, 0xae130018, 0x8f880120, 0x24e20007,
++0x443824, 0x27623800, 0x25090020, 0x122102b,
++0x50400001, 0x27693000, 0x8f820128, 0x11220004,
++0x0, 0x8f820124, 0x15220007, 0x1401821,
++0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
++0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004,
++0x1021, 0xad130008, 0xa507000e, 0xad160018,
++0xad06001c, 0xa3302b, 0xa32823, 0x822023,
++0x862023, 0xad040000, 0xad050004, 0x8ee204c0,
++0xad020010, 0xaf890120, 0x92e24e20, 0x14400033,
++0x24110001, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c820000, 0x1456001f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x10550007, 0x0,
++0x8ee24e34, 0x24420001, 0x10620005, 0x0,
++0x8003239, 0x0, 0x14600005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
++0x800324c, 0x0, 0x8ee24e30, 0x24420001,
++0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
++0x3c050006, 0x8e020018, 0x3c040001, 0x24845890,
++0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
++0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
++0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
++0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004,
++0xae440008, 0x96020016, 0x8003470, 0xa642000e,
++0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e,
++0x28a1023, 0xa602000a, 0x34620004, 0xa602000e,
++0x8f880120, 0x27623800, 0x25090020, 0x122102b,
++0x14400002, 0x306affff, 0x27693000, 0x8f820128,
++0x11220004, 0x0, 0x8f820124, 0x15220007,
++0x24040020, 0x8ee201a4, 0x8821, 0x24420001,
++0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c,
++0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004,
++0xad100008, 0xad040018, 0x52940, 0xa01821,
++0x1021, 0xe33821, 0xe3202b, 0xc23021,
++0xc43021, 0xad060000, 0xad070004, 0x8ee2724c,
++0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
++0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
++0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x0, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
++0x10550007, 0x0, 0x8ee24e34, 0x24420001,
++0x10620005, 0x0, 0x80032b7, 0x0,
++0x14600005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400010, 0xac800000, 0x80032ca, 0x0,
++0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
++0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0xac960000,
++0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
++0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
++0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
++0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
++0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
++0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
++0x24630001, 0x306307ff, 0x26e25244, 0x15a20006,
++0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
++0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
++0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073,
++0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
++0x8f430240, 0x43102b, 0x14400176, 0xa021,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
++0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
++0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
++0x24020008, 0xa462000e, 0x24020011, 0xac620018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400033, 0x24110001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x144e001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x10550007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x800333c,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400010, 0xac800000, 0x800334f,
++0x0, 0x8ee24e30, 0x24420001, 0x50550003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
++0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014,
++0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
++0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
++0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
++0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120,
++0x27623800, 0x24660020, 0xc2102b, 0x50400001,
++0x27663000, 0x8f820128, 0x10c20004, 0x0,
++0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
++0x8821, 0x24420001, 0xaee201a4, 0x80033ba,
++0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8,
++0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008,
++0xa462000e, 0x24020011, 0xac620018, 0xac640000,
++0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
++0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
++0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34,
++0x1062001b, 0x0, 0x8c820004, 0x24420001,
++0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
++0x10550007, 0x0, 0x8ee24e34, 0x24420001,
++0x10620005, 0x0, 0x80033a7, 0x0,
++0x14600005, 0x0, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
++0x50400010, 0xac800000, 0x80033ba, 0x0,
++0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
++0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
++0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
++0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
++0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
++0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
++0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
++0xa021, 0x960c000a, 0x183102b, 0x54400001,
++0x1801821, 0xa603000a, 0x8f880120, 0x27623800,
++0x25090020, 0x122102b, 0x50400001, 0x27693000,
++0x8f820128, 0x11220004, 0x0, 0x8f820124,
++0x15220007, 0x24040020, 0x8ee201a4, 0x8821,
++0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4,
++0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e,
++0x24040004, 0xad100008, 0xad040018, 0x52940,
++0xa01821, 0x1021, 0xe33821, 0xe3202b,
++0xc23021, 0xc43021, 0xad060000, 0xad070004,
++0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010,
++0xaf890120, 0x92e24e20, 0x14400033, 0x24110001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x1456001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x10550007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x800341c,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400010, 0xac800000, 0x800342f,
++0x0, 0x8ee24e30, 0x24420001, 0x50550003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0xac960000, 0xac9e0004, 0x1620001d, 0x0,
++0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
++0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
++0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
++0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
++0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
++0xae430004, 0xae440008, 0x96020016, 0xa642000e,
++0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e,
++0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
++0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821,
++0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a,
++0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821,
++0x93202b, 0x10800003, 0x3c02fff5, 0x34421000,
++0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001,
++0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004,
++0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
++0xa3a00027, 0x1680fd29, 0x0, 0x12800024,
++0x0, 0x3c010001, 0x370821, 0xac3483c4,
++0x3c010001, 0x370821, 0xac3383c8, 0x3c010001,
++0x370821, 0xac3283cc, 0x93a20037, 0x10400008,
++0x0, 0x3c020001, 0x571021, 0x8c4283cc,
++0x24420004, 0x3c010001, 0x370821, 0xac2283cc,
++0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff,
++0x14620006, 0x0, 0x8ee201c4, 0x24420001,
++0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc,
++0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc,
++0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
++0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0xaee400c0, 0xaee500c4,
++0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003,
++0x14400017, 0x24020003, 0x15e20015, 0x0,
++0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
++0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
++0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
++0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
++0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc,
++0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
++0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
++0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
++0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070,
++0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060,
++0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050,
++0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044,
++0xa821, 0xafb00030, 0x8021, 0xafbf004c,
++0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038,
++0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001,
++0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4,
++0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
++0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
++0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
++0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
++0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
++0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
++0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001,
++0x571021, 0x904283c0, 0x1040000b, 0x0,
++0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001,
++0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021,
++0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
++0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
++0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
++0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
++0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014,
++0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
++0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
++0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
++0x10400058, 0x2408821, 0x3c020080, 0x621024,
++0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
++0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
++0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004,
++0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
++0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
++0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
++0x10660021, 0xc3102b, 0x14400007, 0x0,
++0x106b0011, 0x0, 0x106a0015, 0x0,
++0x8003592, 0x42042, 0x10650023, 0xa3102b,
++0x14400005, 0x0, 0x10690019, 0x0,
++0x8003592, 0x42042, 0x10680021, 0x0,
++0x8003592, 0x42042, 0x8ee20034, 0x24420001,
++0xaee20034, 0x8ee20034, 0x8003592, 0x42042,
++0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
++0x8003592, 0x42042, 0x8ee201f0, 0x24420001,
++0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042,
++0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
++0x8003592, 0x42042, 0x8ee20030, 0x24420001,
++0xaee20030, 0x8ee20030, 0x8003592, 0x42042,
++0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
++0x42042, 0x108702b7, 0x0, 0x8003557,
++0x0, 0x3c020001, 0x571021, 0x904283b2,
++0x14400084, 0x24020001, 0x3c030001, 0x771821,
++0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
++0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
++0x24100001, 0x96430004, 0x3402ffff, 0x10620075,
++0x0, 0x92e204d8, 0x14400072, 0x0,
++0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
++0x10400020, 0x3821, 0x3c020001, 0x571021,
++0x8c4283b4, 0x18400016, 0x2821, 0x96260000,
++0x520c0, 0x971021, 0x9442777e, 0x14460009,
++0x971021, 0x94437780, 0x96220002, 0x14620005,
++0x971021, 0x94437782, 0x96220004, 0x50620008,
++0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
++0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
++0x30e200ff, 0x1040027b, 0x0, 0x800361e,
++0x0, 0x2402021, 0xc0022fe, 0x24050006,
++0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
++0x30424000, 0x1440026f, 0xb71021, 0x9443727e,
++0x96220000, 0x1462000b, 0x418c0, 0xb71021,
++0x94437280, 0x96220002, 0x14620006, 0x418c0,
++0xb71021, 0x94437282, 0x96220004, 0x10620035,
++0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
++0x1440025c, 0x2e31021, 0x9448727c, 0x96270000,
++0x828c0, 0xb71021, 0x9442737e, 0x8003600,
++0x3021, 0x420c0, 0x2e41021, 0x9443737c,
++0x2e41021, 0x9448737c, 0x30638000, 0x14600010,
++0x828c0, 0xb71021, 0x9442737e, 0x1447fff5,
++0x1002021, 0xb71021, 0x94437380, 0x96220002,
++0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
++0x96220004, 0x5462ffec, 0x420c0, 0x24060001,
++0x30c200ff, 0x1040023b, 0x0, 0x800361e,
++0x0, 0x97430202, 0x96420000, 0x14620235,
++0x0, 0x97430204, 0x96420002, 0x14620231,
++0x0, 0x97430206, 0x96420004, 0x1462022d,
++0x0, 0x92420000, 0x3a030001, 0x30420001,
++0x431024, 0x10400074, 0x2402ffff, 0x8e230000,
++0x14620004, 0x3402ffff, 0x96230004, 0x1062006f,
++0x24140002, 0x3c020001, 0x571021, 0x904283b2,
++0x1440006a, 0x24140003, 0x92e204d8, 0x14400067,
++0x0, 0x3c020001, 0x571021, 0x8c4283b4,
++0x28420005, 0x10400020, 0x3821, 0x3c020001,
++0x571021, 0x8c4283b4, 0x18400016, 0x2821,
++0x96260000, 0x520c0, 0x971021, 0x9442777e,
++0x14460009, 0x971021, 0x94437780, 0x96220002,
++0x14620005, 0x971021, 0x94437782, 0x96220004,
++0x50620008, 0x24070001, 0x3c020001, 0x571021,
++0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
++0x520c0, 0x30e200ff, 0x14400044, 0x24140003,
++0x800384a, 0x0, 0x2402021, 0xc0022fe,
++0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
++0x9442727c, 0x30424000, 0x144001ea, 0xb71021,
++0x9443727e, 0x96220000, 0x1462000b, 0x418c0,
++0xb71021, 0x94437280, 0x96220002, 0x14620006,
++0x418c0, 0xb71021, 0x94437282, 0x96220004,
++0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
++0x30428000, 0x144001d7, 0x2e31021, 0x9448727c,
++0x96270000, 0x828c0, 0xb71021, 0x9442737e,
++0x8003685, 0x3021, 0x420c0, 0x2e41021,
++0x9443737c, 0x2e41021, 0x9448737c, 0x30638000,
++0x14600010, 0x828c0, 0xb71021, 0x9442737e,
++0x1447fff5, 0x1002021, 0xb71021, 0x94437380,
++0x96220002, 0x5462fff1, 0x420c0, 0xb71021,
++0x94437382, 0x96220004, 0x5462ffec, 0x420c0,
++0x24060001, 0x30c200ff, 0x104001b6, 0x0,
++0x8003698, 0x24140003, 0x24140001, 0x8f420260,
++0x53102b, 0x10400049, 0x0, 0x8f8300e4,
++0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
++0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
++0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
++0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
++0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
++0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
++0xc002403, 0x34a5f003, 0x8003850, 0x0,
++0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
++0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
++0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
++0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
++0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
++0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884,
++0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
++0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
++0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
++0x53102b, 0x54400001, 0x3c158000, 0x12600131,
++0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280,
++0x24420001, 0x304207ff, 0x10620108, 0x0,
++0x12a00014, 0x0, 0x8ee35240, 0x8ee25244,
++0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244,
++0x21140, 0x24425248, 0x2e28021, 0x24630001,
++0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0,
++0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0,
++0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb,
++0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18,
++0x21140, 0x24420e20, 0x2e28021, 0x24630001,
++0x306801ff, 0x96e2046a, 0x30420010, 0x10400017,
++0x34028100, 0x9643000c, 0x14620014, 0x0,
++0x3c020001, 0x571021, 0x904283c0, 0x1440000f,
++0x0, 0x9642000e, 0xa6020016, 0x8e420008,
++0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c,
++0xae430008, 0xae440004, 0x9602000e, 0x26310004,
++0x24160001, 0x34420200, 0xa602000e, 0x9603000a,
++0x2605021, 0x73102b, 0x10400002, 0x2606821,
++0x605021, 0x2d42003d, 0x1040002a, 0x3821,
++0x9623000c, 0x24020800, 0x54620027, 0xae110018,
++0x3c020001, 0x571021, 0x904283c0, 0x54400022,
++0xae110018, 0x26220017, 0x182102b, 0x10400013,
++0x0, 0x3c02fff5, 0x511021, 0x90421017,
++0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
++0x621825, 0x10600013, 0x26220010, 0x182102b,
++0x1040000e, 0x0, 0x3c07fff5, 0xf13821,
++0x94e71010, 0x800375e, 0x24e7000e, 0x92220017,
++0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
++0x621825, 0x50600004, 0xae110018, 0x96270010,
++0x24e7000e, 0xae110018, 0x3c020001, 0x571021,
++0x904283c0, 0x2102b, 0x14e00002, 0x24ec0,
++0x1403821, 0x8f830120, 0x27623800, 0x24660020,
++0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
++0x10c20004, 0x0, 0x8f820124, 0x14c20007,
++0x2402000b, 0x8ee201a4, 0x4821, 0x24420001,
++0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000,
++0x8e050004, 0xac620018, 0x1751025, 0x491025,
++0xac710008, 0xa467000e, 0xac62001c, 0xac640000,
++0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120,
++0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020007, 0x14620020, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001c, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30,
++0x24020040, 0x24630001, 0x10620007, 0x0,
++0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
++0x80037a9, 0x0, 0x14a00005, 0x0,
++0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
++0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
++0x80037bf, 0x0, 0x8ee24e30, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020007, 0xac820000,
++0x24020001, 0xac820004, 0x15200018, 0x3c050006,
++0x8e020018, 0x3c040001, 0x24845890, 0xafa20010,
++0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
++0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
++0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
++0xa642000c, 0xae430000, 0xae440004, 0xae450008,
++0x96020016, 0x80037f8, 0xa642000e, 0x154d000a,
++0x0, 0x9602000e, 0xa613000a, 0x34420004,
++0xa602000e, 0x3c010001, 0x370821, 0xa02083c0,
++0x80037f6, 0x9821, 0x9604000a, 0x93102b,
++0x10400002, 0x2601821, 0x801821, 0x24020001,
++0xa603000a, 0x3c010001, 0x370821, 0xa02283c0,
++0x9604000a, 0x2248821, 0x191102b, 0x10400003,
++0x3c02fff5, 0x34421000, 0x2228821, 0x2649823,
++0xa821, 0x1660fef4, 0xadc80000, 0x12600021,
++0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4,
++0x3c010001, 0x370821, 0xac3183c8, 0x3c010001,
++0x370821, 0x10400008, 0xac3283cc, 0x3c020001,
++0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
++0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280,
++0x24420001, 0x14620006, 0x0, 0x8ee201c4,
++0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4,
++0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850,
++0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821,
++0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821,
++0xa3302b, 0x822021, 0x862021, 0x24020002,
++0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003,
++0x14400017, 0x24020003, 0x16820015, 0x0,
++0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
++0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
++0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
++0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
++0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc,
++0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
++0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
++0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
++0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c,
++0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c,
++0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
++0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021,
++0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058,
++0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
++0x8ee204d4, 0x8821, 0x24150001, 0x30420001,
++0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4,
++0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
++0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
++0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
++0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
++0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
++0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
++0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001,
++0x571021, 0x904283c0, 0x1040000b, 0x0,
++0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001,
++0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021,
++0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
++0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
++0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
++0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
++0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014,
++0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
++0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
++0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
++0x10400058, 0x2408021, 0x3c020080, 0x621024,
++0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
++0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
++0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004,
++0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
++0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
++0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
++0x10660021, 0xc3102b, 0x14400007, 0x0,
++0x106b0011, 0x0, 0x106a0015, 0x0,
++0x8003916, 0x42042, 0x10650023, 0xa3102b,
++0x14400005, 0x0, 0x10690019, 0x0,
++0x8003916, 0x42042, 0x10680021, 0x0,
++0x8003916, 0x42042, 0x8ee20034, 0x24420001,
++0xaee20034, 0x8ee20034, 0x8003916, 0x42042,
++0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
++0x8003916, 0x42042, 0x8ee201f0, 0x24420001,
++0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042,
++0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
++0x8003916, 0x42042, 0x8ee20030, 0x24420001,
++0xaee20030, 0x8ee20030, 0x8003916, 0x42042,
++0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
++0x42042, 0x1087033e, 0x0, 0x80038db,
++0x0, 0x3c020001, 0x571021, 0x904283b2,
++0x14400084, 0x24020001, 0x3c030001, 0x771821,
++0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
++0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
++0x24110001, 0x96430004, 0x3402ffff, 0x10620075,
++0x0, 0x92e204d8, 0x14400072, 0x0,
++0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
++0x10400020, 0x3821, 0x3c020001, 0x571021,
++0x8c4283b4, 0x18400016, 0x2821, 0x96060000,
++0x520c0, 0x971021, 0x9442777e, 0x14460009,
++0x971021, 0x94437780, 0x96020002, 0x14620005,
++0x971021, 0x94437782, 0x96020004, 0x50620008,
++0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
++0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
++0x30e200ff, 0x10400302, 0x0, 0x80039a2,
++0x0, 0x2402021, 0xc0022fe, 0x24050006,
++0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
++0x30424000, 0x144002f6, 0xb71021, 0x9443727e,
++0x96020000, 0x1462000b, 0x418c0, 0xb71021,
++0x94437280, 0x96020002, 0x14620006, 0x418c0,
++0xb71021, 0x94437282, 0x96020004, 0x10620035,
++0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
++0x144002e3, 0x2e31021, 0x944d727c, 0x96070000,
++0xd28c0, 0xb71021, 0x9442737e, 0x8003984,
++0x3021, 0x420c0, 0x2e41021, 0x9443737c,
++0x2e41021, 0x944d737c, 0x30638000, 0x14600010,
++0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5,
++0x1a02021, 0xb71021, 0x94437380, 0x96020002,
++0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
++0x96020004, 0x5462ffec, 0x420c0, 0x24060001,
++0x30c200ff, 0x104002c2, 0x0, 0x80039a2,
++0x0, 0x97430202, 0x96420000, 0x146202bc,
++0x0, 0x97430204, 0x96420002, 0x146202b8,
++0x0, 0x97430206, 0x96420004, 0x146202b4,
++0x0, 0x92420000, 0x3a230001, 0x30420001,
++0x431024, 0x10400074, 0x2402ffff, 0x8e030000,
++0x14620004, 0x3402ffff, 0x96030004, 0x1062006f,
++0x24150002, 0x3c020001, 0x571021, 0x904283b2,
++0x1440006a, 0x24150003, 0x92e204d8, 0x14400067,
++0x0, 0x3c020001, 0x571021, 0x8c4283b4,
++0x28420005, 0x10400020, 0x3821, 0x3c020001,
++0x571021, 0x8c4283b4, 0x18400016, 0x2821,
++0x96060000, 0x520c0, 0x971021, 0x9442777e,
++0x14460009, 0x971021, 0x94437780, 0x96020002,
++0x14620005, 0x971021, 0x94437782, 0x96020004,
++0x50620008, 0x24070001, 0x3c020001, 0x571021,
++0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
++0x520c0, 0x30e200ff, 0x14400044, 0x24150003,
++0x8003c55, 0x0, 0x2402021, 0xc0022fe,
++0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
++0x9442727c, 0x30424000, 0x14400271, 0xb71021,
++0x9443727e, 0x96020000, 0x1462000b, 0x418c0,
++0xb71021, 0x94437280, 0x96020002, 0x14620006,
++0x418c0, 0xb71021, 0x94437282, 0x96020004,
++0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
++0x30428000, 0x1440025e, 0x2e31021, 0x944d727c,
++0x96070000, 0xd28c0, 0xb71021, 0x9442737e,
++0x8003a09, 0x3021, 0x420c0, 0x2e41021,
++0x9443737c, 0x2e41021, 0x944d737c, 0x30638000,
++0x14600010, 0xd28c0, 0xb71021, 0x9442737e,
++0x1447fff5, 0x1a02021, 0xb71021, 0x94437380,
++0x96020002, 0x5462fff1, 0x420c0, 0xb71021,
++0x94437382, 0x96020004, 0x5462ffec, 0x420c0,
++0x24060001, 0x30c200ff, 0x1040023d, 0x0,
++0x8003a1c, 0x24150003, 0x24150001, 0x8f420260,
++0x53102b, 0x10400036, 0x0, 0x8f8300e4,
++0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
++0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
++0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
++0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
++0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0,
++0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
++0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
++0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
++0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
++0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
++0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
++0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
++0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5,
++0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280,
++0x24420001, 0x304207ff, 0x1062019e, 0x0,
++0x12c00012, 0x0, 0x8ee35240, 0x8ee25244,
++0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024,
++0x8ee35244, 0x21140, 0x24425248, 0x2e28821,
++0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0,
++0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
++0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18,
++0xb021, 0xafb80024, 0x8ee30e18, 0x21140,
++0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff,
++0x96e2046a, 0x30420010, 0x10400018, 0x34028100,
++0x9643000c, 0x14620015, 0x0, 0x3c020001,
++0x571021, 0x904283c0, 0x14400010, 0x0,
++0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004,
++0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008,
++0xae440004, 0x9622000e, 0x26100004, 0x24180001,
++0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000,
++0x8e230004, 0x3c040001, 0x34843800, 0x2003021,
++0x306a0007, 0x20a8023, 0x3641021, 0x202102b,
++0x10400005, 0x26a9821, 0x2041023, 0x3621823,
++0x3c020020, 0x438023, 0x26620007, 0x9623000a,
++0x2418fff8, 0x58c824, 0x6a1821, 0x79102b,
++0x10400002, 0x3206021, 0x606021, 0x1801821,
++0x24620007, 0x2418fff8, 0x586024, 0x26c102b,
++0x14400004, 0x1932823, 0x1832823, 0x8003ac3,
++0xc31021, 0xd31021, 0x4a2023, 0x1c4102b,
++0x54400001, 0x8f2021, 0x25420040, 0x4c102b,
++0x14400035, 0x5821, 0x94c3000c, 0x24020800,
++0x54620032, 0xae260018, 0x3c020001, 0x571021,
++0x904283c0, 0x5440002d, 0xae260018, 0x24c20017,
++0x1c2102b, 0x10400013, 0x0, 0x3c02fff5,
++0x461021, 0x90421017, 0x38430006, 0x2c630001,
++0x38420011, 0x2c420001, 0x621825, 0x10600014,
++0x24c20010, 0x1c2102b, 0x1040000e, 0x0,
++0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4,
++0x2562000e, 0x90c20017, 0x38430006, 0x2c630001,
++0x38420011, 0x2c420001, 0x621825, 0x10600005,
++0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821,
++0x1601821, 0x24620007, 0x2418fff8, 0x585824,
++0xc31021, 0x4a2023, 0x1c4102b, 0x10400002,
++0x1632823, 0x8f2021, 0xae260018, 0x3c020001,
++0x571021, 0x904283c0, 0x2102b, 0x216c0,
++0x15600002, 0xafa20044, 0x1805821, 0x30820001,
++0x10400007, 0x4021, 0x90880000, 0x24840001,
++0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021,
++0x50a00012, 0x81c02, 0x2ca20002, 0x54400009,
++0x24a5ffff, 0x94820000, 0x24840002, 0x1024021,
++0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21,
++0x8f2021, 0x90820000, 0x21200, 0x1024021,
++0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff,
++0x624021, 0x3108ffff, 0x1402821, 0x11400011,
++0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff,
++0x94820000, 0x24840002, 0x1024021, 0x1c4102b,
++0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021,
++0x90820000, 0x21200, 0x1024021, 0x14a0fff2,
++0x2ca20002, 0x81c02, 0x3102ffff, 0x624021,
++0x81c02, 0x3102ffff, 0x8f890120, 0x624021,
++0x27623800, 0x25230020, 0x62102b, 0x14400002,
++0x3108ffff, 0x27633000, 0x8f820128, 0x10620004,
++0x0, 0x8f820124, 0x14620007, 0x1402821,
++0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4,
++0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004,
++0x81400, 0x3448000b, 0xad300008, 0xa52b000e,
++0xad280018, 0x8fb80044, 0x2021, 0x2961025,
++0x581025, 0xad22001c, 0xe5102b, 0xe53823,
++0xc43023, 0xc23023, 0xad260000, 0xad270004,
++0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20,
++0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002,
++0x14400003, 0x24020011, 0x15020024, 0x0,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c830000, 0x24020012, 0x1462000f, 0x0,
++0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0,
++0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
++0x8ee34e30, 0x24420001, 0x105e002a, 0x0,
++0x8003ba8, 0x0, 0x8ee24e30, 0x24420001,
++0x505e0003, 0x1021, 0x8ee24e30, 0x24420001,
++0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30,
++0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
++0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x105e0007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x8003bb4,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400012, 0xac800000, 0x8003bc9,
++0x0, 0x8ee24e30, 0x24420001, 0x505e0003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020007, 0xac820000, 0x24020001, 0xac820004,
++0x14e00019, 0x3c050006, 0x3c040001, 0x24845890,
++0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
++0x8e230004, 0x2203021, 0x1603821, 0xc002403,
++0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
++0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c,
++0xae430000, 0xae440004, 0xae450008, 0x96220016,
++0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823,
++0x9622000e, 0xa623000a, 0x34420004, 0xa622000e,
++0x3c010001, 0x370821, 0xa02083c0, 0x8003bff,
++0x9821, 0x9624000a, 0x83102b, 0x54400001,
++0x801821, 0x24020001, 0xa623000a, 0x3c010001,
++0x370821, 0xa02283c0, 0x9622000a, 0x4a1821,
++0x2038021, 0x1d0102b, 0x54400001, 0x20f8021,
++0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e,
++0xaf0d0000, 0x12600022, 0x0, 0x3c010001,
++0x370821, 0xac3383c4, 0x3c010001, 0x370821,
++0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc,
++0x93a2002f, 0x10400008, 0x0, 0x3c020001,
++0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
++0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c,
++0x14620006, 0x0, 0x8ee201c4, 0x24420001,
++0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc,
++0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc,
++0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
++0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0x24020002, 0xaee400c0,
++0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017,
++0x24020003, 0x16a20015, 0x0, 0x8ee200d0,
++0x8ee300d4, 0x24630001, 0x2c640001, 0x441021,
++0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55,
++0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001,
++0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc,
++0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8,
++0x8ee300cc, 0x24630001, 0x2c640001, 0x441021,
++0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc,
++0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008,
++0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064,
++0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054,
++0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
++0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14,
++0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c,
++0x8ee20e14, 0x622023, 0x4820001, 0x24840200,
++0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004,
++0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823,
++0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff,
++0x804821, 0x69102a, 0x54400001, 0x604821,
++0x8f870100, 0x27623000, 0x24e80020, 0x102102b,
++0x50400001, 0x27682800, 0x8f820108, 0x11020004,
++0x0, 0x8f820104, 0x15020007, 0x1021,
++0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8,
++0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140,
++0x801821, 0x8ee40460, 0x8ee50464, 0xa32821,
++0xa3302b, 0x822021, 0x862021, 0xace40000,
++0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e,
++0x24020002, 0xace20018, 0x31940, 0x24630e20,
++0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c,
++0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec,
++0x14400011, 0x24040001, 0x8ee24e28, 0x24030040,
++0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
++0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
++0x24424e38, 0x2e21821, 0x24020002, 0xac620000,
++0x24020001, 0xac620004, 0x1480000e, 0x24030040,
++0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
++0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
++0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd,
++0x0, 0x8ee20500, 0x24420001, 0x50430003,
++0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
++0x8ee20500, 0x21080, 0x571021, 0xac490508,
++0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14,
++0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0,
++0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
++0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
++0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074,
++0x0, 0x8ee35238, 0x8ee2523c, 0x622023,
++0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c,
++0x43102b, 0x14400004, 0x24020100, 0x8ee3523c,
++0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c,
++0x431023, 0x2443ffff, 0x804821, 0x69102a,
++0x54400001, 0x604821, 0x8f870100, 0x27623000,
++0x24e80020, 0x102102b, 0x50400001, 0x27682800,
++0x8f820108, 0x11020004, 0x0, 0x8f820104,
++0x15020007, 0x1021, 0x8ee201a8, 0x2021,
++0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8,
++0x8ee4523c, 0x42140, 0x801821, 0x8ee40470,
++0x8ee50474, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xace40000, 0xace50004, 0x8ee3523c,
++0x91140, 0xa4e2000e, 0x24020003, 0xace20018,
++0x31940, 0x24635248, 0x2e31021, 0xace20008,
++0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010,
++0xaf880100, 0x92e204ec, 0x14400011, 0x24040001,
++0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
++0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
++0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821,
++0x24020003, 0xac620000, 0x24020001, 0xac620004,
++0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
++0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
++0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403,
++0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
++0x24420001, 0x50430003, 0x1021, 0x8ee20500,
++0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
++0x571021, 0xac490508, 0x8ee2523c, 0x491021,
++0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238,
++0x14620005, 0x0, 0x8f820060, 0x2403feff,
++0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124,
++0x8f860128, 0x24020040, 0x24630001, 0x50620003,
++0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34,
++0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0,
++0x24425038, 0x14830007, 0x2e22821, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8003d92,
++0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001,
++0x50430003, 0x1021, 0x8ee24e34, 0x24420001,
++0x210c0, 0x24425038, 0x2e22821, 0x8ca20004,
++0x8f830128, 0x21140, 0x621821, 0xaf830128,
++0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
++0x10400008, 0x31080, 0x3c010001, 0x220821,
++0x8c2258f0, 0x400008, 0x0, 0x24020001,
++0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
++0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
++0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
++0x8f820124, 0x106202b0, 0x9821, 0x3c11001f,
++0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012,
++0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
++0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
++0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
++0x220821, 0x8c225948, 0x400008, 0x0,
++0x8f420218, 0x30420100, 0x10400007, 0x0,
++0x95830016, 0x95820018, 0x621823, 0x31402,
++0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
++0x3044ffff, 0x436824, 0x3c030800, 0x431824,
++0x11a00004, 0xad84001c, 0x41140, 0x8003dd8,
++0x24425248, 0x41140, 0x24420e20, 0x2e25821,
++0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e,
++0x95840016, 0x8003ec0, 0x0, 0x8d690018,
++0x4021, 0x952a0000, 0x25290002, 0x95270000,
++0x25290002, 0x95260000, 0x25290002, 0x95250000,
++0x25290002, 0x95240000, 0x25290002, 0x95230000,
++0x25290002, 0x95220000, 0x25290002, 0x1475021,
++0x1465021, 0x1455021, 0x1445021, 0x1435021,
++0x1425021, 0xa1c02, 0x3142ffff, 0x625021,
++0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a,
++0x314effff, 0x30420002, 0x10400044, 0x5021,
++0x25220014, 0x222102b, 0x10400014, 0x1201821,
++0x2405000a, 0x2021, 0x223102b, 0x54400001,
++0x721821, 0x94620000, 0x24630002, 0x24a5ffff,
++0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff,
++0x622021, 0x41402, 0x3083ffff, 0x431021,
++0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000,
++0x25290002, 0x95280000, 0x25290002, 0x95270000,
++0x25290002, 0x95260000, 0x25290002, 0x95250000,
++0x25290002, 0x95230000, 0x25290002, 0x95220000,
++0x25290002, 0x95240000, 0x25290002, 0x1485021,
++0x1475021, 0x1465021, 0x1455021, 0x1435021,
++0x1425021, 0x95220000, 0x95230002, 0x1445021,
++0x1425021, 0x1435021, 0xa1c02, 0x3142ffff,
++0x625021, 0xa1c02, 0x3142ffff, 0x625021,
++0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018,
++0x9443000c, 0x24020800, 0x54620005, 0xa5680010,
++0x9562000e, 0x34420002, 0xa562000e, 0xa5680010,
++0x96e2046a, 0x2821, 0x30420008, 0x14400056,
++0x3021, 0x8d630018, 0x24620024, 0x222102b,
++0x10400034, 0x24690010, 0x229102b, 0x54400001,
++0x1324821, 0x95250000, 0x24690014, 0x229102b,
++0x10400002, 0x24a5ffec, 0x1324821, 0x95220000,
++0x30420fff, 0x14400003, 0x25290002, 0x8003e60,
++0x24130001, 0x9821, 0xa03021, 0x229102b,
++0x54400001, 0x1324821, 0x91220001, 0x25290002,
++0xa22821, 0x229102b, 0x54400001, 0x1324821,
++0x25290002, 0x229102b, 0x54400001, 0x1324821,
++0x95220000, 0x25290002, 0xa22821, 0x229102b,
++0x54400001, 0x1324821, 0x95220000, 0x25290002,
++0xa22821, 0x229102b, 0x54400001, 0x1324821,
++0x95220000, 0x25290002, 0xa22821, 0x229102b,
++0x54400001, 0x1324821, 0x95220000, 0x8003e99,
++0xa22821, 0x94650010, 0x94620014, 0x24690016,
++0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c,
++0x24130001, 0x9821, 0xa03021, 0x91230001,
++0x25290004, 0x95220000, 0x25290002, 0x95240000,
++0x25290002, 0xa32821, 0xa22821, 0x95220000,
++0x95230002, 0xa42821, 0xa22821, 0xa32821,
++0x51c02, 0x30a2ffff, 0x622821, 0x51c02,
++0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001,
++0x1040001e, 0x2021, 0x95820016, 0x4e2023,
++0x41402, 0x822021, 0x326200ff, 0x50400002,
++0x862021, 0x852021, 0x41402, 0x822021,
++0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018,
++0x24430017, 0x223102b, 0x54400001, 0x721821,
++0x90620000, 0x38430011, 0x2c630001, 0x38420006,
++0x2c420001, 0x621825, 0x10600004, 0x0,
++0x9562000e, 0x34420001, 0xa562000e, 0x9562000e,
++0x240a0002, 0x30420004, 0x10400002, 0xa5640012,
++0x240a0004, 0x8f880120, 0x27623800, 0x25090020,
++0x122102b, 0x50400001, 0x27693000, 0x8f820128,
++0x11220004, 0x0, 0x8f820124, 0x15220007,
++0x24040020, 0x8ee201a4, 0x8021, 0x24420001,
++0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c,
++0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e,
++0xad0a0018, 0x52940, 0xa01821, 0x1021,
++0xe33821, 0xe3202b, 0xc23021, 0xc43021,
++0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025,
++0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
++0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee,
++0x2c630002, 0x39420011, 0x2c420001, 0x621825,
++0x10600024, 0x0, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c820000, 0x1455000f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b,
++0x0, 0x8003f2e, 0x0, 0x8ee24e30,
++0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020001, 0x8003f4e,
++0xac950000, 0x8ee24e30, 0x210c0, 0x24425038,
++0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
++0x0, 0x8ee24e34, 0x24420001, 0x10620005,
++0x0, 0x8003f3a, 0x0, 0x14600005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400012,
++0xac800000, 0x8003f4f, 0x0, 0x8ee24e30,
++0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020007, 0xac820000,
++0x24020001, 0xac820004, 0x1600000d, 0x0,
++0x8f820120, 0x3c040001, 0x24845938, 0xafa00014,
++0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
++0xc002403, 0x34a50001, 0x8004057, 0x0,
++0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
++0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
++0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
++0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff,
++0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240,
++0x104000e5, 0x0, 0x8ee20e1c, 0x24420001,
++0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c,
++0x8f420240, 0x10400072, 0x0, 0x8ee20e1c,
++0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b,
++0x144000d5, 0x0, 0x8f830120, 0x27623800,
++0x24660020, 0xc2102b, 0x50400001, 0x27663000,
++0x8f820128, 0x10c20004, 0x0, 0x8f820124,
++0x14c20007, 0x0, 0x8ee201a4, 0x8021,
++0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4,
++0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
++0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
++0x24020011, 0xac620018, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400034, 0x24100001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c820000, 0x1455001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
++0x0, 0x8ee24e34, 0x24420001, 0x10620005,
++0x0, 0x8003fc6, 0x0, 0x14600005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400011,
++0xac800000, 0x8003fda, 0x0, 0x8ee24e30,
++0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x24020001, 0xac950000,
++0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
++0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
++0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
++0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
++0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
++0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
++0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
++0x24020008, 0xa462000e, 0x24020011, 0xac620018,
++0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
++0xaf860120, 0x92e24e20, 0x14400034, 0x24100001,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x8c820000, 0x1455001f, 0x0, 0x8ee34e30,
++0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
++0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
++0x24420001, 0x10540007, 0x0, 0x8ee24e34,
++0x24420001, 0x10620005, 0x0, 0x8004030,
++0x0, 0x14600005, 0x0, 0x8f820128,
++0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
++0x2c420011, 0x50400011, 0xac800000, 0x8004044,
++0x0, 0x8ee24e30, 0x24420001, 0x50540003,
++0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
++0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
++0x24020001, 0xac950000, 0xac820004, 0x1600000b,
++0x0, 0x8ee2724c, 0x3c040001, 0x248458a8,
++0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
++0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
++0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
++0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124,
++0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c,
++0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
++0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
++0x27840208, 0x27450200, 0x24060008, 0xafbf0014,
++0xc00249a, 0xafb00010, 0x2021, 0x24100001,
++0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
++0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
++0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8,
++0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0,
++0x3c010001, 0xac235cc8, 0xc005108, 0x24050004,
++0xc004822, 0x0, 0x8ee20000, 0x3c03feff,
++0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
++0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
++0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
++0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
++0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
++0x248459f0, 0xc002403, 0x3821, 0x8ee20280,
++0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
++0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
++0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
++0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214,
++0x3821, 0x24420001, 0xaee20214, 0x8ee20214,
++0x3c020300, 0x2021024, 0x10400027, 0x3c110400,
++0xc00429b, 0x0, 0x3c020100, 0x2021024,
++0x10400007, 0x0, 0x8ee20218, 0x24420001,
++0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
++0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
++0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
++0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008,
++0x2003021, 0x431024, 0xaee20000, 0x8f820220,
++0x3821, 0x3c030300, 0x481024, 0x431025,
++0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
++0x8004296, 0x0, 0x2111024, 0x1040001f,
++0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
++0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008,
++0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
++0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
++0x3463ffff, 0x2002021, 0x431024, 0xc004e54,
++0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
++0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
++0x431024, 0x8004295, 0x511025, 0x2021024,
++0x10400142, 0x0, 0x8ee2022c, 0x24420001,
++0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff,
++0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
++0x8f830054, 0x8f820054, 0x800410e, 0x24630002,
++0x8f820054, 0x621023, 0x2c420003, 0x1440fffc,
++0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007,
++0x10400012, 0x0, 0x8f8300e4, 0x2402fff8,
++0xc21024, 0x1043000d, 0x0, 0x8f820054,
++0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054,
++0x821023, 0x2c420051, 0x10400004, 0x0,
++0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220,
++0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220,
++0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8,
++0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f,
++0x3442ffff, 0x24680008, 0x48102b, 0x10400003,
++0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8,
++0x8f850120, 0x8f840124, 0x8004145, 0x6021,
++0x27623800, 0x82102b, 0x50400001, 0x27643000,
++0x10a40010, 0x318200ff, 0x8c820018, 0x38430007,
++0x2c630001, 0x3842000b, 0x2c420001, 0x621825,
++0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001,
++0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008,
++0x318200ff, 0x14400065, 0x0, 0x3c020001,
++0x571021, 0x904283c0, 0x14400060, 0x0,
++0x8f8400e4, 0xc41023, 0x218c3, 0x4620001,
++0x24630200, 0x8f8900c4, 0x10600005, 0x24020001,
++0x10620009, 0x0, 0x8004187, 0x0,
++0x8ee20230, 0x1205821, 0x24420001, 0xaee20230,
++0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a,
++0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000,
++0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001,
++0x651821, 0x2c62233f, 0x14400040, 0x0,
++0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8,
++0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4,
++0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a,
++0x24420001, 0xaee20238, 0x8c840000, 0x3463f000,
++0x8ee20238, 0x883823, 0x67102b, 0x54400001,
++0xe33821, 0x3c020003, 0x34420d40, 0x47102b,
++0x10400003, 0x0, 0x80041bc, 0x805821,
++0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4,
++0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003,
++0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c,
++0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b,
++0x54400001, 0xe53821, 0x147102b, 0x54400007,
++0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4,
++0x8f8400e4, 0x1486ffef, 0x0, 0x14860005,
++0x0, 0x1205821, 0xaf8600e4, 0x80041bc,
++0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8,
++0x3c03000a, 0x3463f000, 0x483823, 0x67102b,
++0x54400001, 0xe33821, 0x3c020003, 0x34420d3f,
++0x47102b, 0x54400007, 0x6021, 0x1683823,
++0x67102b, 0x54400003, 0xe33821, 0x80041cf,
++0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b,
++0x14400016, 0x318200ff, 0x14400006, 0x0,
++0x3c020001, 0x571021, 0x904283c0, 0x1040000f,
++0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000,
++0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c,
++0x24020001, 0x641824, 0x3c010001, 0x370821,
++0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8,
++0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000,
++0x623823, 0x87102b, 0x54400001, 0xe43821,
++0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001,
++0x431025, 0x10400008, 0x0, 0x8f820220,
++0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000,
++0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
++0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
++0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
++0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0,
++0x431024, 0x1040001d, 0x0, 0x10c4001b,
++0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
++0x24850008, 0x27622800, 0x50a20001, 0x27651800,
++0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff,
++0x431021, 0x4d1024, 0x24430010, 0x6b102b,
++0x54400001, 0x6a1821, 0x12b102b, 0x54400001,
++0x12a4821, 0x10690002, 0x10c1025, 0xac820004,
++0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220,
++0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002,
++0xaf820220, 0x8f830054, 0x8f820054, 0x8004237,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff,
++0x3463fffb, 0x431024, 0xaf820220, 0x6010055,
++0x0, 0x8ee20228, 0x24420001, 0xaee20228,
++0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff,
++0x431024, 0x34420004, 0xaf820220, 0x8f830054,
++0x8f820054, 0x8004251, 0x24630002, 0x8f820054,
++0x621023, 0x2c420003, 0x1440fffc, 0x0,
++0x8f8600e0, 0x30c20007, 0x10400012, 0x0,
++0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d,
++0x0, 0x8f820054, 0x8f8300e0, 0x14c30009,
++0x24440032, 0x8f820054, 0x821023, 0x2c420033,
++0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9,
++0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd,
++0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007,
++0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0,
++0x240301f5, 0x8f8200e8, 0x673823, 0x718c0,
++0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4,
++0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021,
++0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002,
++0x441024, 0x431025, 0xaf820220, 0x8f830054,
++0x8f820054, 0x800428d, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
++0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
++0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8,
++0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
++0x24845a14, 0x3c050008, 0x24020001, 0x3c010001,
++0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
++0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8,
++0x3c010001, 0xac225ccc, 0xc002403, 0x3821,
++0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
++0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
++0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
++0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4,
++0x8f820044, 0x3c030600, 0x34632000, 0x34420020,
++0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228,
++0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010,
++0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
++0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
++0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
++0x1040006a, 0x5821, 0x24180008, 0x240f000d,
++0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
++0x27623800, 0x24e80020, 0x102102b, 0x50400001,
++0x27683000, 0x8f820128, 0x11020004, 0x0,
++0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
++0x2821, 0x24420001, 0xaee201a4, 0x800433d,
++0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
++0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
++0x822021, 0x862021, 0xace40000, 0xace50004,
++0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
++0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
++0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
++0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
++0x0, 0x8ee24e34, 0x24420001, 0x10620005,
++0x0, 0x800432a, 0x0, 0x14600005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
++0xac800000, 0x800433d, 0x0, 0x8ee24e30,
++0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
++0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
++0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
++0x24020001, 0x54620079, 0xafa00010, 0xaeea0608,
++0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
++0x2c420033, 0x10400061, 0x5821, 0x240d0008,
++0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
++0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
++0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
++0x0, 0x8f820124, 0x14c20007, 0x0,
++0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4,
++0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c,
++0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
++0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
++0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
++0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
++0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
++0x0, 0x8c820004, 0x24420001, 0xac820004,
++0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
++0x0, 0x8ee24e34, 0x24420001, 0x10620005,
++0x0, 0x8004396, 0x0, 0x14600005,
++0x0, 0x8f820128, 0x24420020, 0xaf820128,
++0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
++0xac800000, 0x80043a9, 0x0, 0x8ee24e30,
++0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
++0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
++0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
++0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
++0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
++0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
++0x0, 0x3c040001, 0x24845a20, 0xafa00014,
++0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
++0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
++0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124,
++0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
++0x0, 0x3c040001, 0x24845a38, 0xafa00014,
++0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
++0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
++0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
++0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
++0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d,
++0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008,
++0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
++0x24020001, 0x3c010001, 0xac225cd8, 0xc002403,
++0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
++0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
++0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
++0x34420008, 0xaf820220, 0x2021, 0xc0052a2,
++0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x3c120001,
++0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001,
++0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
++0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
++0x0, 0xd, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x80014d6,
++0x0, 0x80014d8, 0x3c0a0001, 0x80014d8,
++0x3c0a0002, 0x80014d8, 0x0, 0x80024a6,
++0x0, 0x80014d8, 0x3c0a0003, 0x80014d8,
++0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8,
++0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66,
++0x0, 0x80014d8, 0x3c0a0006, 0x80014d8,
++0x3c0a0007, 0x80014d8, 0x0, 0x80014d8,
++0x0, 0x80014d8, 0x0, 0x8002a75,
++0x0, 0x80014d8, 0x3c0a000b, 0x80014d8,
++0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a,
++0x0, 0x8002339, 0x0, 0x80014d8,
++0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4,
++0x0, 0x80014d8, 0x3c0a000f, 0x80040a7,
++0x0, 0x8004091, 0x0, 0x80014d8,
++0x3c0a0010, 0x80014ee, 0x0, 0x80014d8,
++0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8,
++0x3c0a0013, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x3c030001,
++0x34633800, 0x24050080, 0x2404001f, 0x2406ffff,
++0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
++0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4,
++0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0,
++0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8,
++0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4,
++0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0,
++0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8,
++0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004,
++0x8f830040, 0x3c02f000, 0x621824, 0x3c025000,
++0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
++0x3c024000, 0x10620008, 0x24020800, 0x8004539,
++0x0, 0x10620004, 0x24020800, 0x8004539,
++0x0, 0x24020700, 0x3c010001, 0xac225cdc,
++0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
++0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001,
++0xac205cc4, 0x8004545, 0x24630064, 0x8f820054,
++0x621023, 0x2c420065, 0x1440fffc, 0x0,
++0xc004d71, 0x0, 0x24040001, 0x2821,
++0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018,
++0x8f830054, 0x8f820054, 0x8004556, 0x24630064,
++0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
++0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
++0x8f830054, 0x8f820054, 0x8004562, 0x24630064,
++0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
++0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
++0x8f830054, 0x8f820054, 0x800456e, 0x24630064,
++0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
++0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c,
++0x24050002, 0x8f830054, 0x8f820054, 0x800457b,
++0x24630064, 0x8f820054, 0x621023, 0x2c420065,
++0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
++0x26105da2, 0xc00494c, 0x2003021, 0x97a60018,
++0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0,
++0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
++0xc002403, 0xafa20010, 0x97a20018, 0x1040004c,
++0x24036040, 0x96020000, 0x3042fff0, 0x1443000a,
++0x24020020, 0x3c030001, 0x94635da0, 0x54620009,
++0x24027830, 0x24020003, 0x3c010001, 0xac225cc4,
++0x80045ac, 0x24020005, 0x3c030001, 0x94635da0,
++0x24027830, 0x1462000f, 0x24030010, 0x3c020001,
++0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003,
++0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001,
++0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6,
++0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001,
++0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4,
++0x24020015, 0x1462000f, 0x0, 0x3c020001,
++0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001,
++0x3842f430, 0x2c420001, 0x621825, 0x10600005,
++0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6,
++0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810,
++0x1462000b, 0x24020002, 0x3c020001, 0x94425da2,
++0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
++0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
++0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
++0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001,
++0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4,
++0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4,
++0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001,
++0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc,
++0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2,
++0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8,
++0x491021, 0x3c010001, 0xac225dac, 0xafa30010,
++0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020,
++0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001,
++0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014,
++0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000,
++0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc,
++0x8004617, 0x34844240, 0x3c040004, 0x3c030001,
++0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016,
++0x0, 0x3c04003d, 0x800462f, 0x34840900,
++0x3c020001, 0x8c427e38, 0x30428000, 0x10400005,
++0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a,
++0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc,
++0x34844240, 0x24020005, 0x14620003, 0x0,
++0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac,
++0x8f830054, 0x441021, 0x431023, 0x44102b,
++0x14400037, 0x0, 0x3c020001, 0x8c425cd0,
++0x14400033, 0x0, 0x3c010001, 0x10c00025,
++0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001,
++0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc,
++0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
++0xa91024, 0x10400010, 0x0, 0x14a70008,
++0x0, 0x8d020000, 0x441024, 0x1040000a,
++0x0, 0x3c010001, 0x800465b, 0xac255ce0,
++0x8d420000, 0x441024, 0x10400003, 0x0,
++0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0,
++0x6182b, 0x2c420001, 0x431024, 0x5440ffe5,
++0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0,
++0x3c010001, 0xac225dac, 0x1060002a, 0x24020001,
++0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc,
++0x3c020001, 0x8c425ce0, 0x10400022, 0x0,
++0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001,
++0x3c010001, 0xac205ccc, 0x3c010001, 0x370821,
++0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001,
++0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac,
++0x24020008, 0x10620005, 0x24020001, 0xc004695,
++0x0, 0x8004692, 0x0, 0x3c030001,
++0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001,
++0x8c637dd0, 0x10620003, 0x0, 0xc004e54,
++0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
++0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000,
++0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0,
++0x3442ffff, 0x621824, 0x14a40008, 0xaee30000,
++0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001,
++0x8c425cf4, 0x10620008, 0x0, 0x3c020001,
++0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0,
++0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8,
++0x24020002, 0x10620169, 0x2c620003, 0x10400005,
++0x24020001, 0x10620008, 0x0, 0x800481c,
++0x0, 0x24020004, 0x106200b1, 0x24020001,
++0x800481d, 0x0, 0x3c020001, 0x571021,
++0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a,
++0x31080, 0x3c010001, 0x220821, 0x8c225ac8,
++0x400008, 0x0, 0x3c030001, 0x8c635dbc,
++0x24020005, 0x14620014, 0x0, 0x3c020001,
++0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822,
++0x0, 0x24020002, 0x3c010001, 0x370821,
++0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4,
++0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
++0x800481f, 0xac205c60, 0xc004822, 0x0,
++0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60,
++0x104000dd, 0x24020002, 0x3c010001, 0x370821,
++0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4,
++0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003,
++0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf,
++0x0, 0x3c030001, 0x8c635d00, 0x800478e,
++0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001,
++0x8cc67e3c, 0xc005108, 0x2021, 0x24020005,
++0x3c010001, 0xac205cd4, 0x3c010001, 0x370821,
++0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc,
++0x3c05000f, 0x34a50100, 0x3021, 0x3821,
++0xafa00010, 0xc002403, 0xafa00014, 0x800481f,
++0x0, 0x8f820220, 0x3c03f700, 0x431025,
++0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004,
++0x431024, 0x144000a9, 0x24020007, 0x8f830054,
++0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
++0x2c422710, 0x144000f8, 0x24020001, 0x800481d,
++0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
++0x2021, 0xc005386, 0x2021, 0x3c030001,
++0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008,
++0x621024, 0x10400006, 0x0, 0x8f820214,
++0x3c03ffff, 0x431024, 0x8004741, 0x3442251f,
++0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
++0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
++0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
++0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
++0x24020008, 0x3c010001, 0x370821, 0xac2283ac,
++0x8f820220, 0x3c030004, 0x431024, 0x14400005,
++0x0, 0x8f820220, 0x3c03f700, 0x431025,
++0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005,
++0x1462000a, 0x0, 0x3c020001, 0x94425da2,
++0x24429fbc, 0x2c420004, 0x10400004, 0x24040018,
++0x24050002, 0xc004d93, 0x24060020, 0xc0043dd,
++0x0, 0x3c010001, 0x800481f, 0xac205d50,
++0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
++0x2c620008, 0x104000ac, 0x31080, 0x3c010001,
++0x220821, 0x8c225ae8, 0x400008, 0x0,
++0xc00429b, 0x0, 0x3c010001, 0xac205ccc,
++0xaf800204, 0x3c010001, 0xc004822, 0xac207e20,
++0x24020001, 0x3c010001, 0xac225ce4, 0x24020002,
++0x3c010001, 0x370821, 0x800481f, 0xac2283ac,
++0xc00489f, 0x0, 0x3c030001, 0x8c635ce4,
++0x24020009, 0x14620090, 0x24020003, 0x3c010001,
++0x370821, 0x800481f, 0xac2283ac, 0x3c020001,
++0x8c427e38, 0x30424000, 0x10400005, 0x0,
++0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff,
++0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
++0x8f830054, 0x80047b9, 0x24020004, 0x8f830054,
++0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
++0x2c422710, 0x14400074, 0x24020005, 0x3c010001,
++0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
++0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
++0x3c010001, 0xac207e20, 0x8f830054, 0x24020006,
++0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
++0x800481f, 0xac235da4, 0x8f830054, 0x3c020001,
++0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a,
++0x14400059, 0x0, 0x24020007, 0x3c010001,
++0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
++0x3c04f700, 0x441025, 0xaf820220, 0x8f820220,
++0x3c030300, 0x431024, 0x14400005, 0x1821,
++0x8f820220, 0x24030001, 0x441025, 0xaf820220,
++0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff,
++0x3c040001, 0x8c845d98, 0x431024, 0x3442251f,
++0xaf820214, 0x24020008, 0x3c010001, 0x370821,
++0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74,
++0x14400007, 0x24020001, 0x3c010001, 0xac227dd0,
++0xc004e54, 0x8f840220, 0x800480c, 0x0,
++0x8f820220, 0x3c030008, 0x431024, 0x14400017,
++0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000,
++0x2021, 0x3c030200, 0x431025, 0xc005386,
++0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
++0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd,
++0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
++0x2021, 0x800481f, 0x0, 0x3c020001,
++0x8c425d74, 0x10400010, 0x0, 0x3c020001,
++0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70,
++0x14400009, 0x24020002, 0x3c010001, 0xac205d74,
++0x3c010001, 0x800481f, 0xac225d70, 0x24020001,
++0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
++0x34420004, 0xaf820220, 0x8f820200, 0x3c060001,
++0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002,
++0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001,
++0x10c20008, 0x0, 0x8004868, 0x0,
++0x24020004, 0x10c20013, 0x24020001, 0x8004868,
++0x0, 0x3c030001, 0x8c635cb8, 0x3c020001,
++0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001,
++0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022,
++0x441025, 0x451025, 0x34420002, 0x8004867,
++0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200,
++0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74,
++0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0,
++0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0,
++0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
++0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001,
++0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825,
++0x431025, 0x451025, 0xaf820220, 0x3e00008,
++0x0, 0x8f820220, 0x3c030001, 0x8c635cc8,
++0x34420004, 0xaf820220, 0x24020001, 0x1062000f,
++0x0, 0x8f830054, 0x8f820054, 0x24630002,
++0x621023, 0x2c420003, 0x10400011, 0x0,
++0x8f820054, 0x621023, 0x2c420003, 0x1040000c,
++0x0, 0x8004879, 0x0, 0x8f830054,
++0x8f820054, 0x8004885, 0x24630007, 0x8f820054,
++0x621023, 0x2c420008, 0x1440fffc, 0x0,
++0x8f8400e0, 0x30820007, 0x1040000d, 0x0,
++0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032,
++0x8f820054, 0xa21023, 0x2c420033, 0x10400004,
++0x0, 0x8f8200e0, 0x1082fff9, 0x0,
++0x8f820220, 0x2403fffd, 0x431024, 0xaf820220,
++0x3e00008, 0x0, 0x3c030001, 0x8c635ce4,
++0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff,
++0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009,
++0x1040009d, 0x31080, 0x3c010001, 0x220821,
++0x8c225b08, 0x400008, 0x0, 0x8f820044,
++0x34428080, 0xaf820044, 0x8f830054, 0x8004938,
++0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8,
++0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a,
++0x24020003, 0x8004945, 0x0, 0x8f820044,
++0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044,
++0x8f830054, 0x8004938, 0x24020004, 0x8f830054,
++0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023,
++0x2c42000a, 0x14400078, 0x24020005, 0x8004945,
++0x0, 0x8f820220, 0x3c03f700, 0x431025,
++0xaf820220, 0x8f820220, 0x2403fffb, 0x431024,
++0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
++0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200,
++0x2403fffd, 0x431024, 0xaf820200, 0x24040001,
++0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054,
++0x80048ec, 0x24630001, 0x8f820054, 0x621023,
++0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
++0x42040, 0xa4102b, 0x1040fff2, 0x0,
++0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
++0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f,
++0xaf820214, 0x8f820220, 0x2403fffb, 0x431024,
++0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008,
++0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00,
++0x346300e2, 0x441025, 0xaf820220, 0xaf830200,
++0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008,
++0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000,
++0x34630040, 0x3c020001, 0x24425c70, 0xac820000,
++0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938,
++0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8,
++0x2463fff6, 0x431023, 0x2c42000a, 0x14400022,
++0x24020007, 0x8004945, 0x0, 0x8f8200e0,
++0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220,
++0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7,
++0x431024, 0xaf820220, 0x8f820044, 0x34428080,
++0xaf820044, 0x8f830054, 0x24020008, 0x3c010001,
++0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8,
++0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0,
++0x431023, 0x2c422710, 0x14400003, 0x24020009,
++0x3c010001, 0xac225ce4, 0x3e00008, 0x0,
++0x0, 0x0, 0x0, 0x27bdffd8,
++0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
++0xafb10014, 0xc08821, 0xafb00010, 0x8021,
++0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d4b, 0x2021, 0xc004d4b, 0x24040001,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x24100010, 0x2501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d4b, 0x108042, 0x1600fffa,
++0x2501024, 0x24100010, 0x2701024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x2701024, 0xc004d71, 0x34108000,
++0xc004d71, 0x0, 0xc004d2b, 0x0,
++0x50400005, 0x108042, 0x96220000, 0x501025,
++0xa6220000, 0x108042, 0x1600fff7, 0x0,
++0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c,
++0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
++0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
++0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
++0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0x24100010, 0x2301024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x2501024, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0x34108000,
++0x96620000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
++0x0, 0xc004d71, 0x0, 0x8fbf0020,
++0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
++0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00,
++0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020,
++0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
++0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349,
++0x31080, 0x3c010001, 0x220821, 0x8c225b30,
++0x400008, 0x0, 0xc004d71, 0x8021,
++0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b,
++0x2021, 0x108042, 0x1600fffc, 0x0,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fff8, 0x0, 0xc004d71, 0x0,
++0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010,
++0x8021, 0xc004d4b, 0x24040001, 0x26100001,
++0x2e020020, 0x1440fffb, 0x0, 0xc004d4b,
++0x2021, 0xc004d4b, 0x24040001, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0x24100010,
++0x32020001, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020001,
++0x24100010, 0xc004d4b, 0x2021, 0x108042,
++0x1600fffc, 0x0, 0xc004d71, 0x34108000,
++0xc004d71, 0x0, 0xc004d2b, 0x0,
++0x50400005, 0x108042, 0x96220000, 0x501025,
++0xa6220000, 0x108042, 0x1600fff7, 0x0,
++0xc004d71, 0x0, 0x97a20010, 0x30428000,
++0x144002dc, 0x24020003, 0x8004d24, 0x0,
++0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0xc004d4b, 0x2021, 0x108042, 0x1600fffc,
++0x0, 0xc004d4b, 0x24040001, 0xc004d4b,
++0x2021, 0x34108000, 0x96220000, 0x501024,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fff8, 0x0, 0xc004d71,
++0x0, 0x8f830054, 0x8004d16, 0x24020004,
++0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c,
++0x431023, 0x2c420064, 0x1440029e, 0x24020002,
++0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003,
++0x14400296, 0x24020011, 0x24020003, 0x10620005,
++0x24020004, 0x10620291, 0x2402000f, 0x8004d24,
++0x24020011, 0x8004d24, 0x24020005, 0x24020014,
++0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020012, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0x34108000,
++0x96220000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
++0x0, 0xc004d71, 0x0, 0x8f830054,
++0x8004d16, 0x24020006, 0x8f830054, 0x3c020001,
++0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
++0x14400250, 0x24020007, 0x8004d24, 0x0,
++0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020013, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020013,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fff8, 0x0, 0xc004d71, 0x0,
++0x8f830054, 0x8004d16, 0x24020008, 0x8f830054,
++0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
++0x2c420064, 0x1440020f, 0x24020009, 0x8004d24,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
++0xc004d4b, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
++0xc004d71, 0x34108000, 0xc004d71, 0x0,
++0xc004d2b, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004d71, 0x8021,
++0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fff8, 0x0, 0xc004d71, 0x0,
++0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054,
++0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
++0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
++0xc004d4b, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020017, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
++0xc004d71, 0x34108000, 0xc004d71, 0x0,
++0xc004d2b, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004d71, 0x8021,
++0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020017, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fff8, 0x0, 0xc004d71, 0x0,
++0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054,
++0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
++0x2c420064, 0x14400127, 0x24020012, 0x8004d24,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
++0xc004d4b, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020014, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
++0xc004d71, 0x34108000, 0xc004d71, 0x0,
++0xc004d2b, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004d71, 0x8021,
++0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020014, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fff8, 0x0, 0xc004d71, 0x0,
++0x8f830054, 0x8004d16, 0x24020013, 0x8f830054,
++0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
++0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
++0xc004d4b, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
++0xc004d71, 0x34108000, 0xc004d71, 0x0,
++0xc004d2b, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004d71, 0x8021,
++0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
++0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
++0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fff8, 0x0, 0xc004d71, 0x0,
++0x8f830054, 0x8004d16, 0x2402000e, 0x24020840,
++0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x32020013, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0x34108000,
++0x96220000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
++0x0, 0xc004d71, 0x0, 0x8f830054,
++0x24020010, 0x3c010001, 0xac225d00, 0x3c010001,
++0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001,
++0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
++0x14400004, 0x0, 0x24020011, 0x3c010001,
++0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
++0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
++0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
++0x8f840054, 0x8f820054, 0xa32824, 0x8004d37,
++0x24840001, 0x8f820054, 0x821023, 0x2c420002,
++0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
++0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
++0x8f820054, 0x8004d45, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
++0x3442ffff, 0x42480, 0x621824, 0x3c020002,
++0x822025, 0x641825, 0xaf830044, 0x8f820044,
++0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
++0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001,
++0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
++0x0, 0x8f820044, 0x3c030001, 0x431025,
++0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x3e00008, 0x0,
++0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
++0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
++0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
++0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
++0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
++0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
++0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
++0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
++0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0x34108000,
++0x96420000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d4b, 0x108042, 0x12000075,
++0x0, 0x8004dc9, 0x0, 0x3274ffff,
++0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b,
++0x2021, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x2901024, 0xc004d71,
++0x34108000, 0xc004d71, 0x0, 0xc004d2b,
++0x0, 0x50400005, 0x108042, 0x96220000,
++0x501025, 0xa6220000, 0x108042, 0x1600fff7,
++0x0, 0xc004d71, 0x0, 0x32a5ffff,
++0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
++0x8004e14, 0x521025, 0x14a20006, 0x3271ffff,
++0x97a20010, 0x121827, 0x431024, 0xa7a20010,
++0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d4b, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
++0x10400002, 0x2021, 0x24040001, 0xc004d4b,
++0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
++0x24040001, 0xc004d4b, 0x2021, 0x34108000,
++0x96420000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
++0x0, 0xc004d71, 0x0, 0x8fbf0030,
++0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
++0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
++0x0, 0x0, 0x0, 0x27bdffe8,
++0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
++0x24020008, 0x1462022c, 0x803021, 0x3c020001,
++0x8c425d98, 0x14400033, 0x0, 0x8f850224,
++0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
++0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
++0x38a20400, 0x2c420001, 0x621825, 0x14600007,
++0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
++0x621825, 0x10600005, 0x0, 0xc00429b,
++0x0, 0x8004e8d, 0x2402000e, 0xc0043dd,
++0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
++0x2021, 0x3c030001, 0x8c635cc8, 0x24020004,
++0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4,
++0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4,
++0x431024, 0x3c010001, 0xac225cc4, 0x2402000e,
++0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087,
++0x0, 0x8f820220, 0x3c030400, 0x431024,
++0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
++0x8c427ddc, 0xa32024, 0x431024, 0x1482000c,
++0x0, 0x3c020001, 0x8c427de0, 0x24420001,
++0x3c010001, 0xac227de0, 0x2c420002, 0x14400008,
++0x24020001, 0x3c010001, 0x8004ead, 0xac227e00,
++0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00,
++0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040,
++0x10400004, 0x24020001, 0x3c010001, 0x8004eb8,
++0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001,
++0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10,
++0x24020001, 0x3c010001, 0xac227e10, 0x3c010001,
++0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001,
++0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001,
++0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003,
++0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024,
++0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
++0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700,
++0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
++0x220821, 0x8c225b80, 0x400008, 0x0,
++0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0,
++0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04,
++0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0,
++0xc00486a, 0xaf800224, 0x24020002, 0x3c010001,
++0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056,
++0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
++0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
++0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
++0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8,
++0x24040001, 0x3c010001, 0xac247e0c, 0x24420001,
++0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001,
++0xac237df4, 0x14400006, 0x24020003, 0x3c010001,
++0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8,
++0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054,
++0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
++0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
++0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026,
++0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
++0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c,
++0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001,
++0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10,
++0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
++0x431024, 0xaee20000, 0x8f820204, 0x30420030,
++0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c,
++0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001,
++0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10,
++0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c,
++0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002,
++0x14400131, 0x24020001, 0x3c010001, 0xac225d74,
++0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083,
++0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024,
++0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122,
++0x0, 0x3c020001, 0x8c427ddc, 0x1040011e,
++0x0, 0x3c010001, 0xac227e08, 0x24020003,
++0x3c010001, 0xac227de0, 0x8005024, 0x24020006,
++0x3c010001, 0xac207de8, 0x8f820204, 0x34420040,
++0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007,
++0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001,
++0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005,
++0x0, 0x3c020001, 0x8c427ddc, 0x104000f9,
++0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000,
++0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
++0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001,
++0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024,
++0x641824, 0x10430004, 0x24020001, 0x3c010001,
++0x8005083, 0xac227dd0, 0x24020003, 0xaca20000,
++0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001,
++0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001,
++0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28,
++0x14400005, 0x24020001, 0x3c020001, 0x8c427e24,
++0x10400006, 0x24020001, 0x3c010001, 0xac225ccc,
++0x3c010001, 0x8005083, 0xac207df8, 0x3c020001,
++0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001,
++0x210c0, 0x30630008, 0x3c010001, 0xac227df0,
++0x3c010001, 0xac237dec, 0x8f830054, 0x24020009,
++0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083,
++0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4,
++0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
++0x0, 0x3c020001, 0x8c427e00, 0x10400005,
++0x0, 0x3c020001, 0x8c427ddc, 0x104000a9,
++0x24020002, 0x3c030001, 0x24637de0, 0x8c620000,
++0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
++0x8c427e0c, 0x1040000e, 0x0, 0x3c020001,
++0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080,
++0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
++0x1440000c, 0x24020003, 0x8005011, 0x2402000c,
++0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005,
++0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
++0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
++0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000,
++0x3c030001, 0x8c637df0, 0x431025, 0xaf820204,
++0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b,
++0x3c010001, 0xac227dd0, 0x641825, 0x3c010001,
++0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000,
++0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
++0x8c427e10, 0x10400005, 0x0, 0x2402000c,
++0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001,
++0x8c427e00, 0x1040006c, 0x0, 0x3c040001,
++0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001,
++0x8c637dec, 0x10620064, 0x24020003, 0x3c010001,
++0xac247e08, 0xaca20000, 0x24020006, 0x3c010001,
++0x8005083, 0xac227dd0, 0x8f820200, 0x34420002,
++0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
++0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054,
++0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
++0x2c422710, 0x1440003a, 0x0, 0x3c020001,
++0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001,
++0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0,
++0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8,
++0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8,
++0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
++0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001,
++0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4,
++0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
++0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220,
++0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
++0x34420002, 0x8005083, 0xaf820220, 0x3c020001,
++0x8c427e00, 0x10400005, 0x0, 0x3c020001,
++0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001,
++0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002,
++0x3c020001, 0x8c427e00, 0x1040000f, 0x0,
++0x3c020001, 0x8c427ddc, 0x1440000b, 0x0,
++0x24020002, 0x3c010001, 0x8005083, 0xac227dd0,
++0x3c020001, 0x8c427e00, 0x10400003, 0x0,
++0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
++0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
++0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000,
++0x10400005, 0x34422000, 0x3c010001, 0xac227e1c,
++0x8005095, 0xac600000, 0x3c010001, 0xac247e1c,
++0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
++0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067,
++0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
++0x24020030, 0x30822000, 0x1040005d, 0x30838000,
++0x31a02, 0x30820001, 0x21200, 0x3c040001,
++0x8c845d9c, 0x621825, 0x331c2, 0x3c030001,
++0x24635d78, 0x30828000, 0x21202, 0x30840001,
++0x42200, 0x441025, 0x239c2, 0x61080,
++0x431021, 0x471021, 0x90430000, 0x24020001,
++0x10620025, 0x0, 0x10600007, 0x24020002,
++0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
++0x80050f9, 0x0, 0x8f820200, 0x2403feff,
++0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
++0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
++0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c,
++0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
++0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
++0x24020100, 0x3c010001, 0xac227e44, 0x3c010001,
++0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff,
++0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
++0x431025, 0xaf820220, 0x3c010001, 0xac207e44,
++0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200,
++0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
++0x431025, 0xaf820220, 0x24020100, 0x3c010001,
++0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c,
++0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010,
++0xc002403, 0xafa00014, 0x8005104, 0x0,
++0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018,
++0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
++0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
++0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0,
++0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001,
++0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
++0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
++0x24020002, 0x12620083, 0x2e620003, 0x10400005,
++0x24020001, 0x1262000a, 0x0, 0x800529b,
++0x0, 0x24020004, 0x126200fa, 0x24020008,
++0x126200f9, 0x3c02ffec, 0x800529b, 0x0,
++0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004,
++0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
++0x3c010001, 0x310821, 0xac307e3c, 0x3c024000,
++0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
++0x101382, 0x3042001c, 0x3c030001, 0x24635d08,
++0x431021, 0x823821, 0x3c020020, 0x2021024,
++0x10400006, 0x24020100, 0x3c010001, 0x310821,
++0xac227e40, 0x8005150, 0x3c020080, 0x3c010001,
++0x310821, 0xac207e40, 0x3c020080, 0x2021024,
++0x10400006, 0x121940, 0x3c020001, 0x3c010001,
++0x230821, 0x800515c, 0xac227e48, 0x121140,
++0x3c010001, 0x220821, 0xac207e48, 0x94e40000,
++0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010,
++0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
++0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
++0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002,
++0x24040001, 0x2821, 0xc00498e, 0x27a60018,
++0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001,
++0xac315cd4, 0x14530004, 0x32028000, 0xc00429b,
++0x0, 0x32028000, 0x1040011f, 0x0,
++0xc00429b, 0x0, 0x3c030001, 0x8c635dbc,
++0x24020005, 0x10620118, 0x24020002, 0x3c010001,
++0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8,
++0x24040001, 0x24050004, 0x27b0001a, 0xc00498e,
++0x2003021, 0x24040001, 0x2821, 0xc00498e,
++0x2003021, 0x3c020001, 0x511021, 0x8c427e34,
++0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff,
++0x3c010001, 0xac335cd4, 0x431024, 0x3c010001,
++0x310821, 0x109300fa, 0xac227e34, 0x800529b,
++0x0, 0x3c022000, 0x2021024, 0x10400005,
++0x24020001, 0x3c010001, 0xac225d98, 0x80051ad,
++0x128940, 0x3c010001, 0xac205d98, 0x128940,
++0x3c010001, 0x310821, 0xac307e38, 0x3c024000,
++0x2021024, 0x14400016, 0x0, 0x3c020001,
++0x8c425d98, 0x10400008, 0x24040004, 0x24050001,
++0xc004d93, 0x24062000, 0x24020001, 0x3c010001,
++0x370821, 0xac2283ac, 0x3c020001, 0x511021,
++0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024,
++0x3c010001, 0x310821, 0x8005299, 0xac227e30,
++0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0,
++0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
++0x8c425d9c, 0x24030100, 0x3c010001, 0x310821,
++0xac237e44, 0x3c030001, 0x3c010001, 0x310821,
++0xac237e4c, 0x80051f0, 0x34420400, 0x2021024,
++0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c,
++0x3c010001, 0x310821, 0xac237e44, 0x80051f0,
++0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
++0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001,
++0x310821, 0xac237e4c, 0x34420c00, 0x3c010001,
++0xac225d9c, 0x8005218, 0x24040001, 0x3c020020,
++0x2021024, 0x10400006, 0x24020100, 0x3c010001,
++0x310821, 0xac227e44, 0x8005201, 0x3c020080,
++0x3c010001, 0x310821, 0xac207e44, 0x3c020080,
++0x2021024, 0x10400007, 0x121940, 0x3c020001,
++0x3c010001, 0x230821, 0xac227e4c, 0x800520f,
++0x24040001, 0x121140, 0x3c010001, 0x220821,
++0xac207e4c, 0x24040001, 0x2821, 0x27b0001e,
++0xc00494c, 0x2003021, 0x24040001, 0x2821,
++0xc00494c, 0x2003021, 0x24040001, 0x24050001,
++0x27b0001c, 0xc00494c, 0x2003021, 0x24040001,
++0x24050001, 0xc00494c, 0x2003021, 0x8005299,
++0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
++0x3c020008, 0x2028025, 0x121140, 0x3c010001,
++0x220821, 0xac307e38, 0x3c022000, 0x2021024,
++0x10400009, 0x0, 0x3c020001, 0x8c425d74,
++0x14400005, 0x24020001, 0x3c010001, 0xac225d98,
++0x800523a, 0x3c024000, 0x3c010001, 0xac205d98,
++0x3c024000, 0x2021024, 0x1440001e, 0x0,
++0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0,
++0x10400007, 0x24022020, 0x3c010001, 0xac225d9c,
++0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
++0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
++0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff,
++0x441024, 0x3c010001, 0x230821, 0xac227e30,
++0x24020001, 0x10a20044, 0x0, 0x8005299,
++0x0, 0x3c020001, 0x8c425d98, 0x1040001c,
++0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0,
++0x2031024, 0x14430005, 0x121140, 0x3402a000,
++0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001,
++0x621821, 0x8c637e38, 0x3c020020, 0x621024,
++0x10400004, 0x24022001, 0x3c010001, 0x8005294,
++0xac225d9c, 0x3c020080, 0x621024, 0x1040001f,
++0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c,
++0x3c020020, 0x2021024, 0x10400007, 0x121940,
++0x24020100, 0x3c010001, 0x230821, 0xac227e44,
++0x8005288, 0x3c020080, 0x121140, 0x3c010001,
++0x220821, 0xac207e44, 0x3c020080, 0x2021024,
++0x10400006, 0x121940, 0x3c020001, 0x3c010001,
++0x230821, 0x8005294, 0xac227e4c, 0x121140,
++0x3c010001, 0x220821, 0xac207e4c, 0x3c030001,
++0x8c635cc8, 0x24020001, 0x10620003, 0x0,
++0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
++0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
++0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021,
++0xafb1001c, 0x8821, 0x24020002, 0xafbf0024,
++0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010,
++0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a,
++0x128140, 0x8005380, 0x2201021, 0x24020004,
++0x10a2007d, 0x24020008, 0x10a2007c, 0x122940,
++0x8005380, 0x2201021, 0x3c030001, 0x701821,
++0x8c637e3c, 0x3c024000, 0x621024, 0x14400009,
++0x24040001, 0x3c027fff, 0x3442ffff, 0x628824,
++0x3c010001, 0x300821, 0xac317e34, 0x8005380,
++0x2201021, 0x24050001, 0xc00494c, 0x27a60010,
++0x24040001, 0x24050001, 0xc00494c, 0x27a60010,
++0x97a20010, 0x30420004, 0x10400034, 0x3c114000,
++0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006,
++0x10400034, 0x31080, 0x3c010001, 0x220821,
++0x8c225be0, 0x400008, 0x0, 0x24040001,
++0x24050011, 0x27b00012, 0xc00494c, 0x2003021,
++0x24040001, 0x24050011, 0xc00494c, 0x2003021,
++0x97a50012, 0x30a24000, 0x10400002, 0x3c040010,
++0x3c040008, 0x3c030001, 0x8005301, 0x30a28000,
++0x24040001, 0x24050014, 0x27b00012, 0xc00494c,
++0x2003021, 0x24040001, 0x24050014, 0xc00494c,
++0x2003021, 0x97a50012, 0x30a21000, 0x10400002,
++0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800,
++0x54400001, 0x3c030002, 0x3c028000, 0x2221025,
++0x641825, 0x800530e, 0x438825, 0x3c110001,
++0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff,
++0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d,
++0x121140, 0x3c020001, 0x8c425d98, 0x10400002,
++0x3c022000, 0x2228825, 0x121140, 0x3c010001,
++0x220821, 0x8c227e40, 0x10400003, 0x3c020020,
++0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff,
++0x2228824, 0x121140, 0x3c010001, 0x220821,
++0x8c227e48, 0x10400003, 0x3c020080, 0x800532d,
++0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
++0x121140, 0x3c010001, 0x220821, 0xac317e34,
++0x8005380, 0x2201021, 0x122940, 0x3c030001,
++0x651821, 0x8c637e38, 0x3c024000, 0x621024,
++0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
++0x3c010001, 0x250821, 0xac317e30, 0x8005380,
++0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033,
++0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c,
++0x34842000, 0x3c030001, 0x8c635d98, 0x2102b,
++0x21023, 0x441024, 0x10600003, 0x518825,
++0x3c022000, 0x2228825, 0x3c020001, 0x451021,
++0x8c427e44, 0x10400003, 0x3c020020, 0x800535d,
++0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
++0x121140, 0x3c010001, 0x220821, 0x8c227e4c,
++0x10400003, 0x3c020080, 0x8005368, 0x2228825,
++0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
++0x8c425d60, 0x10400002, 0x3c020800, 0x2228825,
++0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400,
++0x2228825, 0x3c020001, 0x8c425d68, 0x10400006,
++0x3c020100, 0x800537b, 0x2228825, 0x3c027fff,
++0x3442ffff, 0x628824, 0x121140, 0x3c010001,
++0x220821, 0xac317e30, 0x2201021, 0x8fbf0024,
++0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
++0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021,
++0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
++0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8,
++0x8f930220, 0x24020002, 0x10620063, 0x2c620003,
++0x10400005, 0x24020001, 0x1062000a, 0x141940,
++0x8005448, 0x0, 0x24020004, 0x1062005a,
++0x24020008, 0x10620059, 0x149140, 0x8005448,
++0x0, 0x3c040001, 0x832021, 0x8c847e3c,
++0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000,
++0x821024, 0x1040003e, 0x3c020008, 0x2221024,
++0x10400020, 0x36100002, 0x3c020001, 0x431021,
++0x8c427e40, 0x10400005, 0x36100020, 0x36100100,
++0x3c020020, 0x80053bd, 0x2228825, 0x2402feff,
++0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
++0x141140, 0x3c010001, 0x220821, 0x8c227e48,
++0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
++0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff,
++0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc,
++0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
++0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
++0x2228824, 0x3c010001, 0x230821, 0xac207e40,
++0x3c010001, 0x230821, 0xac207e48, 0xc00486a,
++0x0, 0xaf900200, 0xaf930220, 0x8f820220,
++0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
++0x34420002, 0xaf820220, 0x80053f3, 0x141140,
++0x8f820200, 0x2403fffd, 0x431024, 0xc00486a,
++0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
++0x2228824, 0x141140, 0x3c010001, 0x220821,
++0x8005448, 0xac317e34, 0x149140, 0x3c040001,
++0x922021, 0x8c847e38, 0x3c110001, 0x2328821,
++0x8e317e30, 0x3c024000, 0x821024, 0x14400011,
++0x0, 0x3c020001, 0x8c425d98, 0x14400006,
++0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a,
++0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
++0x2228824, 0x3c010001, 0x320821, 0x8005448,
++0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005,
++0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b,
++0x3c020020, 0x821024, 0x10400007, 0x36100020,
++0x24020100, 0x3c010001, 0x320821, 0xac227e44,
++0x8005428, 0x36100100, 0x3c010001, 0x320821,
++0xac207e44, 0x2402feff, 0x2028024, 0x3c020080,
++0x821024, 0x10400007, 0x141940, 0x3c020001,
++0x3c010001, 0x230821, 0xac227e4c, 0x8005439,
++0x2629825, 0x141140, 0x3c010001, 0x220821,
++0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824,
++0xc00486a, 0x0, 0xaf900200, 0xaf930220,
++0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
++0x8f820220, 0x34420002, 0xaf820220, 0x141140,
++0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024,
++0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+ 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
+ static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
+-0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e,
+-0x322e3131, 0x20313939, 0x382f3034, 0x2f323720,
+-0x32323a31, 0x333a3432, 0x20736875, 0x616e6720,
+-0x45787020, 0x24000000, 0x7468655f, 0x4441574e,
+-0x0, 0x53544143, 0x4b5f3120, 0x0,
+-0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71,
+-0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
+-0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43,
+-0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375,
+-0x6d000000, 0x52656376, 0x566c616e, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32,
+-0x2e382031, 0x3939382f, 0x30372f33, 0x31203137,
+-0x3a35383a, 0x34352073, 0x6875616e, 0x67204578,
+-0x70202400, 0x542d446d, 0x61526431, 0x0,
+-0x542d446d, 0x61424200, 0x542d446d, 0x61320000,
+-0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51,
+-0x64527845, 0x0, 0x656e714d, 0x45765046,
+-0x61696c00, 0x656e714d, 0x45764661, 0x696c0000,
+-0x6661696c, 0x456e454d, 0x0, 0x3f456e71,
+-0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
+-0x6576526e, 0x6746756c, 0x6c000000, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31,
+-0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138,
+-0x2031373a, 0x31313a31, 0x38207368, 0x75616e67,
+-0x20457870, 0x20240000, 0x3f4d626f, 0x78457674,
+-0x0, 0x4e4f636f, 0x6d616e64, 0x0,
+-0x68737465, 0x5f455252, 0x0, 0x412d4572,
+-0x72427563, 0x0, 0x4552524f, 0x522d4164,
+-0x64000000, 0x656e714d, 0x45765046, 0x61696c00,
+-0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
+-0x456e454d, 0x0, 0x442d4572, 0x724c6173,
+-0x74000000, 0x442d4572, 0x72320000, 0x6d437374,
+-0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552,
+-0x52000000, 0x46696c74, 0x4d644552, 0x52000000,
+-0x636d645f, 0x45525200, 0x3f456e71, 0x45767400,
+-0x3f6e6f51, 0x64457650, 0x0, 0x6576526e,
+-0x6746756c, 0x6c000000, 0x0, 0x6ea0,
+-0x7fbc, 0x6e38, 0x8734, 0x82b0,
+-0x8780, 0x8780, 0x6f54, 0x7694,
+-0x7f0c, 0x80a8, 0x8074, 0x8780,
+-0x7e70, 0x80cc, 0x6e64, 0x81cc,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33,
+-0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
+-0x333a3431, 0x20736875, 0x616e6720, 0x45787020,
+-0x24000000, 0x646d6172, 0x6441544e, 0x0,
+-0x646d6177, 0x7241544e, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32,
+-0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
+-0x3a31333a, 0x35302073, 0x6875616e, 0x67204578,
+-0x70202400, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e,
+-0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
+-0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
+-0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
+-0x23312046, 0x72692041, 0x70722037, 0x2031373a,
+-0x35353a34, 0x38205044, 0x54203230, 0x30300000,
+-0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
+-0x2031373a, 0x35353a34, 0x38000000, 0x46575f43,
+-0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
+-0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
+-0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
+-0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
+-0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f,
+-0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a,
+-0x20676363, 0x20766572, 0x73696f6e, 0x20322e37,
+-0x2e320000, 0x0, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32,
+-0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
+-0x333a3434, 0x20736875, 0x616e6720, 0x45787020,
+-0x24000000, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e,
+-0x31312031, 0x3939382f, 0x31322f32, 0x32203137,
+-0x3a31373a, 0x35352073, 0x6875616e, 0x67204578,
+-0x70202400, 0x736e6464, 0x654e6f51, 0x20000000,
+-0x6e6f454e, 0x515f5458, 0x0, 0x736e6464,
+-0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845,
+-0x0, 0x756e6b72, 0x64747970, 0x65000000,
+-0x0, 0xaccc, 0xaccc, 0xad9c,
+-0xaab0, 0xaab0, 0xad9c, 0xad9c,
+-0xad9c, 0xad9c, 0xad9c, 0xad9c,
+-0xad9c, 0xad9c, 0xad9c, 0xad9c,
+-0xad9c, 0xad9c, 0xad9c, 0xad7c,
+-0x0, 0xbca8, 0xbca8, 0xbd70,
+-0xae4c, 0xb058, 0xbd70, 0xbd70,
+-0xbd70, 0xbd70, 0xbd70, 0xbd70,
+-0xbd70, 0xbd70, 0xbd70, 0xbd70,
+-0xbd70, 0xbd70, 0xbd70, 0xbd54,
+-0xb040, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e,
+-0x31392031, 0x3939382f, 0x30372f32, 0x34203231,
+-0x3a33303a, 0x30352073, 0x6875616e, 0x67204578,
+-0x70202400, 0x706b5278, 0x45525200, 0x66726d32,
+-0x4c617267, 0x65000000, 0x72784e6f, 0x52784264,
+-0x0, 0x72785144, 0x6d614446, 0x0,
+-0x72785144, 0x6d614246, 0x0, 0x3f6e6f51,
+-0x64527845, 0x0, 0x706b5278, 0x45525273,
+-0x0, 0x66726d32, 0x4c726753, 0x0,
+-0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146,
+-0x0, 0x3f724a42, 0x64446d46, 0x0,
+-0x0, 0xf678, 0xf678, 0xf678,
+-0xf678, 0xf678, 0xf678, 0xf678,
+-0xf678, 0xf678, 0xf678, 0xf678,
+-0xf678, 0xf678, 0xf678, 0xf678,
+-0xf670, 0xf670, 0xf670, 0x572d444d,
+-0x41456e46, 0x0, 0x0, 0xfdc0,
+-0x1015c, 0xfddc, 0x1015c, 0x1015c,
+-0x1015c, 0x1015c, 0x1015c, 0x1015c,
+-0xf704, 0x1015c, 0x1015c, 0x1015c,
+-0x1015c, 0x1015c, 0x10154, 0x10154,
+-0x10154, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31,
+-0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
+-0x31333a34, 0x32207368, 0x75616e67, 0x20457870,
+-0x20240000, 0x6d616374, 0x7841544e, 0x0,
+-0x4e745379, 0x6e264c6b, 0x0, 0x72656d61,
+-0x73737274, 0x0, 0x6c696e6b, 0x444f574e,
+-0x0, 0x656e714d, 0x45765046, 0x61696c00,
+-0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
+-0x456e454d, 0x0, 0x6c696e6b, 0x55500000,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+-0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32,
+-0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
+-0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
+-0x70202400, 0x50726f62, 0x65506879, 0x0,
+-0x6c6e6b41, 0x53535254, 0x0, 0x11b2c,
+-0x11bc4, 0x11bf8, 0x11c2c, 0x11c58,
+-0x11c6c, 0x11ca8, 0x1207c, 0x11de4,
+-0x11e24, 0x11e50, 0x11e90, 0x11ec0,
+-0x11efc, 0x11f30, 0x1207c, 0x122c0,
+-0x122d8, 0x12300, 0x12320, 0x12348,
+-0x12478, 0x124a0, 0x124f4, 0x1251c,
+-0x0, 0x1278c, 0x1285c, 0x12934,
+-0x12a04, 0x12a60, 0x12b3c, 0x12b64,
+-0x12c40, 0x12c68, 0x12e10, 0x12e38,
+-0x12fe0, 0x131d8, 0x1346c, 0x13380,
+-0x1346c, 0x13498, 0x13008, 0x131b0,
+-0x0, 0x13b84, 0x13bc8, 0x13c60,
+-0x13cac, 0x13d1c, 0x13db4, 0x13de8,
+-0x13e70, 0x13f08, 0x13fd8, 0x14018,
+-0x1409c, 0x140c0, 0x141f4, 0x646f4261,
+-0x73655067, 0x0, 0x0, 0x0,
+-0x0, 0x73746d61, 0x634c4e4b, 0x0,
+-0x0, 0x14c38, 0x14c38, 0x14b80,
+-0x14bc4, 0x14c38, 0x14c38, 0x0,
++0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e,
++0x322e3131, 0x20313939, 0x382f3034, 0x2f323720,
++0x32323a31, 0x333a3432, 0x20736875, 0x616e6720,
++0x45787020, 0x24000000, 0x7468655f, 0x4441574e,
++0x0, 0x53544143, 0x4b5f3120, 0x0,
++0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71,
++0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
++0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43,
++0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375,
++0x6d000000, 0x52656376, 0x566c616e, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32,
++0x2e382031, 0x3939382f, 0x30372f33, 0x31203137,
++0x3a35383a, 0x34352073, 0x6875616e, 0x67204578,
++0x70202400, 0x542d446d, 0x61526431, 0x0,
++0x542d446d, 0x61424200, 0x542d446d, 0x61320000,
++0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51,
++0x64527845, 0x0, 0x656e714d, 0x45765046,
++0x61696c00, 0x656e714d, 0x45764661, 0x696c0000,
++0x6661696c, 0x456e454d, 0x0, 0x3f456e71,
++0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
++0x6576526e, 0x6746756c, 0x6c000000, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31,
++0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138,
++0x2031373a, 0x31313a31, 0x38207368, 0x75616e67,
++0x20457870, 0x20240000, 0x3f4d626f, 0x78457674,
++0x0, 0x4e4f636f, 0x6d616e64, 0x0,
++0x68737465, 0x5f455252, 0x0, 0x412d4572,
++0x72427563, 0x0, 0x4552524f, 0x522d4164,
++0x64000000, 0x656e714d, 0x45765046, 0x61696c00,
++0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
++0x456e454d, 0x0, 0x442d4572, 0x724c6173,
++0x74000000, 0x442d4572, 0x72320000, 0x6d437374,
++0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552,
++0x52000000, 0x46696c74, 0x4d644552, 0x52000000,
++0x636d645f, 0x45525200, 0x3f456e71, 0x45767400,
++0x3f6e6f51, 0x64457650, 0x0, 0x6576526e,
++0x6746756c, 0x6c000000, 0x0, 0x6ea0,
++0x7fbc, 0x6e38, 0x8734, 0x82b0,
++0x8780, 0x8780, 0x6f54, 0x7694,
++0x7f0c, 0x80a8, 0x8074, 0x8780,
++0x7e70, 0x80cc, 0x6e64, 0x81cc,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33,
++0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
++0x333a3431, 0x20736875, 0x616e6720, 0x45787020,
++0x24000000, 0x646d6172, 0x6441544e, 0x0,
++0x646d6177, 0x7241544e, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32,
++0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
++0x3a31333a, 0x35302073, 0x6875616e, 0x67204578,
++0x70202400, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e,
++0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
++0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
++0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
++0x23312046, 0x72692041, 0x70722037, 0x2031373a,
++0x35353a34, 0x38205044, 0x54203230, 0x30300000,
++0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
++0x2031373a, 0x35353a34, 0x38000000, 0x46575f43,
++0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
++0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
++0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
++0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
++0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f,
++0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a,
++0x20676363, 0x20766572, 0x73696f6e, 0x20322e37,
++0x2e320000, 0x0, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32,
++0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
++0x333a3434, 0x20736875, 0x616e6720, 0x45787020,
++0x24000000, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e,
++0x31312031, 0x3939382f, 0x31322f32, 0x32203137,
++0x3a31373a, 0x35352073, 0x6875616e, 0x67204578,
++0x70202400, 0x736e6464, 0x654e6f51, 0x20000000,
++0x6e6f454e, 0x515f5458, 0x0, 0x736e6464,
++0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845,
++0x0, 0x756e6b72, 0x64747970, 0x65000000,
++0x0, 0xaccc, 0xaccc, 0xad9c,
++0xaab0, 0xaab0, 0xad9c, 0xad9c,
++0xad9c, 0xad9c, 0xad9c, 0xad9c,
++0xad9c, 0xad9c, 0xad9c, 0xad9c,
++0xad9c, 0xad9c, 0xad9c, 0xad7c,
++0x0, 0xbca8, 0xbca8, 0xbd70,
++0xae4c, 0xb058, 0xbd70, 0xbd70,
++0xbd70, 0xbd70, 0xbd70, 0xbd70,
++0xbd70, 0xbd70, 0xbd70, 0xbd70,
++0xbd70, 0xbd70, 0xbd70, 0xbd54,
++0xb040, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e,
++0x31392031, 0x3939382f, 0x30372f32, 0x34203231,
++0x3a33303a, 0x30352073, 0x6875616e, 0x67204578,
++0x70202400, 0x706b5278, 0x45525200, 0x66726d32,
++0x4c617267, 0x65000000, 0x72784e6f, 0x52784264,
++0x0, 0x72785144, 0x6d614446, 0x0,
++0x72785144, 0x6d614246, 0x0, 0x3f6e6f51,
++0x64527845, 0x0, 0x706b5278, 0x45525273,
++0x0, 0x66726d32, 0x4c726753, 0x0,
++0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146,
++0x0, 0x3f724a42, 0x64446d46, 0x0,
++0x0, 0xf678, 0xf678, 0xf678,
++0xf678, 0xf678, 0xf678, 0xf678,
++0xf678, 0xf678, 0xf678, 0xf678,
++0xf678, 0xf678, 0xf678, 0xf678,
++0xf670, 0xf670, 0xf670, 0x572d444d,
++0x41456e46, 0x0, 0x0, 0xfdc0,
++0x1015c, 0xfddc, 0x1015c, 0x1015c,
++0x1015c, 0x1015c, 0x1015c, 0x1015c,
++0xf704, 0x1015c, 0x1015c, 0x1015c,
++0x1015c, 0x1015c, 0x10154, 0x10154,
++0x10154, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31,
++0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
++0x31333a34, 0x32207368, 0x75616e67, 0x20457870,
++0x20240000, 0x6d616374, 0x7841544e, 0x0,
++0x4e745379, 0x6e264c6b, 0x0, 0x72656d61,
++0x73737274, 0x0, 0x6c696e6b, 0x444f574e,
++0x0, 0x656e714d, 0x45765046, 0x61696c00,
++0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
++0x456e454d, 0x0, 0x6c696e6b, 0x55500000,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
++0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32,
++0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
++0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
++0x70202400, 0x50726f62, 0x65506879, 0x0,
++0x6c6e6b41, 0x53535254, 0x0, 0x11b2c,
++0x11bc4, 0x11bf8, 0x11c2c, 0x11c58,
++0x11c6c, 0x11ca8, 0x1207c, 0x11de4,
++0x11e24, 0x11e50, 0x11e90, 0x11ec0,
++0x11efc, 0x11f30, 0x1207c, 0x122c0,
++0x122d8, 0x12300, 0x12320, 0x12348,
++0x12478, 0x124a0, 0x124f4, 0x1251c,
++0x0, 0x1278c, 0x1285c, 0x12934,
++0x12a04, 0x12a60, 0x12b3c, 0x12b64,
++0x12c40, 0x12c68, 0x12e10, 0x12e38,
++0x12fe0, 0x131d8, 0x1346c, 0x13380,
++0x1346c, 0x13498, 0x13008, 0x131b0,
++0x0, 0x13b84, 0x13bc8, 0x13c60,
++0x13cac, 0x13d1c, 0x13db4, 0x13de8,
++0x13e70, 0x13f08, 0x13fd8, 0x14018,
++0x1409c, 0x140c0, 0x141f4, 0x646f4261,
++0x73655067, 0x0, 0x0, 0x0,
++0x0, 0x73746d61, 0x634c4e4b, 0x0,
++0x0, 0x14c38, 0x14c38, 0x14b80,
++0x14bc4, 0x14c38, 0x14c38, 0x0,
+ 0x0, 0x0 };
+ static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
+-0x416c7465,
+-0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
+-0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
+-0x0, 0x0, 0x0, 0x135418,
+-0x13e7fc, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x60cf00,
+-0x60, 0xcf000000, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x3, 0x0,
+-0x1, 0x0, 0x0, 0x0,
+-0x1, 0x0, 0x1, 0x0,
+-0x0, 0x0, 0x0, 0x1,
+-0x1, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x1000000, 0x21000000,
+-0x12000140, 0x0, 0x0, 0x20000000,
+-0x120000a0, 0x0, 0x12000060, 0x12000180,
+-0x120001e0, 0x0, 0x0, 0x0,
+-0x1, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x2,
+-0x0, 0x0, 0x30001, 0x1,
++0x416c7465,
++0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
++0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
++0x0, 0x0, 0x0, 0x135418,
++0x13e7fc, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x60cf00,
++0x60, 0xcf000000, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x3, 0x0,
++0x1, 0x0, 0x0, 0x0,
++0x1, 0x0, 0x1, 0x0,
++0x0, 0x0, 0x0, 0x1,
++0x1, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x1000000, 0x21000000,
++0x12000140, 0x0, 0x0, 0x20000000,
++0x120000a0, 0x0, 0x12000060, 0x12000180,
++0x120001e0, 0x0, 0x0, 0x0,
++0x1, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x2,
++0x0, 0x0, 0x30001, 0x1,
+ 0x30201, 0x0, 0x0, 0x0 };
+ #endif
+ /* Generated by genfw.c */
+@@ -4612,4845 +4612,4845 @@ static u32 tigonFwData[(MAX_DATA_LEN/4)
+ #define tigon2FwBssAddr 0x00016f50
+ #define tigon2FwBssLen 0x20c0
+ static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
+-0x0,
+-0x10000003, 0x0, 0xd, 0xd,
+-0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000,
+-0x26104000, 0xc0010c0, 0x0, 0xd,
+-0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000,
+-0x26104000, 0xc0017e0, 0x0, 0xd,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x2000008,
+-0x0, 0x800172f, 0x3c0a0001, 0x800172f,
+-0x3c0a0002, 0x800172f, 0x0, 0x8002cac,
+-0x0, 0x8002c4f, 0x0, 0x800172f,
+-0x3c0a0004, 0x800328a, 0x0, 0x8001a52,
+-0x0, 0x800394d, 0x0, 0x80038f4,
+-0x0, 0x800172f, 0x3c0a0006, 0x80039bb,
+-0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f,
+-0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6,
+-0x0, 0x800172f, 0x3c0a000b, 0x800172f,
+-0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb,
+-0x0, 0x8002890, 0x0, 0x800172f,
+-0x3c0a000e, 0x800208c, 0x0, 0x8001964,
+-0x0, 0x8001a04, 0x0, 0x8003ca6,
+-0x0, 0x8003c94, 0x0, 0x800172f,
+-0x0, 0x800191a, 0x0, 0x800172f,
+-0x0, 0x800172f, 0x3c0a0013, 0x800172f,
+-0x3c0a0014, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x27bdffe0,
+-0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140,
+-0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20,
+-0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc,
+-0x401821, 0x3c020010, 0x3c010001, 0xac236e9c,
+-0x10620011, 0x43102b, 0x14400002, 0x3c020020,
+-0x3c020008, 0x1062000c, 0x24050100, 0x3c060001,
+-0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020,
+-0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001,
+-0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4,
+-0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe,
+-0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002,
+-0x24639010, 0x3c040001, 0x8c846cc4, 0x431023,
+-0x14800002, 0x458021, 0x2610fa38, 0x2402f000,
+-0x2028024, 0xc001785, 0x2002021, 0x2022823,
+-0x3c040020, 0x821823, 0x651823, 0x247bb000,
+-0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf,
+-0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf,
+-0x3463e000, 0x852023, 0x3c010001, 0xac246ea8,
+-0x822023, 0x3c010001, 0xac256e90, 0x52842,
+-0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001,
+-0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823,
+-0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac,
+-0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011,
+-0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
+-0xc001749, 0x0, 0x3c020001, 0x8c426cd0,
+-0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200,
+-0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004,
+-0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021,
+-0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38,
+-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
+-0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8,
+-0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4,
+-0x3c020001, 0x8c426cc8, 0x14400003, 0x0,
+-0x3c010001, 0xac206cd0, 0xc001151, 0x0,
+-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
+-0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8,
+-0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060,
+-0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c,
+-0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014,
+-0x8f860040, 0x3c040001, 0x24845c80, 0x24050200,
+-0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821,
+-0x8f830040, 0x3c02f000, 0x621824, 0x3c026000,
+-0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001,
+-0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014,
+-0x8f860040, 0x24050300, 0xc002b3b, 0x2003821,
+-0x8f820240, 0x3c030001, 0x431025, 0xaf820240,
+-0xaf800048, 0x8f820048, 0x14400005, 0x0,
+-0xaf800048, 0x8f820048, 0x10400004, 0x0,
+-0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c,
+-0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8,
+-0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001,
+-0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001,
+-0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001,
+-0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001,
+-0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001,
+-0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c,
+-0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138,
+-0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150,
+-0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140,
+-0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014,
+-0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014,
+-0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0,
+-0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014,
+-0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac,
+-0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c,
+-0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff,
+-0x1061824, 0xe81024, 0x43102b, 0x10400006,
+-0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010,
+-0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010,
+-0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004,
+-0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000,
+-0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c,
+-0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010,
+-0xc002b3b, 0xafa30014, 0xaf800054, 0xaf80011c,
+-0x8c020218, 0x30420002, 0x10400009, 0x0,
+-0x8c020220, 0x3c030002, 0x34630004, 0x431025,
+-0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004,
+-0x8c020220, 0x3c030002, 0x34630006, 0x431025,
+-0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014,
+-0x8c020218, 0x30420010, 0x1040000a, 0x0,
+-0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220,
+-0x3c03000a, 0x34630004, 0x431025, 0x10000009,
+-0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006,
+-0x431025, 0xaf420008, 0x8c02021c, 0x34420006,
+-0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0,
+-0x8f830054, 0x8f820054, 0xaf8000d0, 0xaf8000c0,
+-0x10000002, 0x24630064, 0x8f820054, 0x621023,
+-0x2c420065, 0x1440fffc, 0x0, 0x8c040208,
+-0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490,
+-0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008,
+-0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
+-0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c,
+-0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004,
+-0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00,
+-0x431024, 0x10400021, 0x0, 0x8f8200b4,
+-0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001,
+-0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c,
+-0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001,
+-0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014,
+-0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b,
+-0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+-0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+-0x3c030001, 0x431025, 0xaf820140, 0x96e20472,
+-0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482,
+-0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b,
+-0xafa20014, 0x96f00452, 0x32020001, 0x10400002,
+-0xb021, 0x24160001, 0x32020002, 0x54400001,
+-0x36d60002, 0x32020008, 0x54400001, 0x36d60004,
+-0x32020010, 0x54400001, 0x36d60008, 0x32020020,
+-0x54400001, 0x36d60010, 0x32020040, 0x54400001,
+-0x36d60020, 0x32020080, 0x54400001, 0x36d60040,
+-0x96e60482, 0x30c20200, 0x54400001, 0x36d64000,
+-0x96e30472, 0x30620200, 0x10400003, 0x30620100,
+-0x10000003, 0x36d62000, 0x54400001, 0x36d61000,
+-0x96f00462, 0x32c24000, 0x14400004, 0x3207009b,
+-0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000,
+-0x1440000d, 0x32020001, 0x3062009b, 0x10e20009,
+-0x240e0001, 0x3c040001, 0x24845d20, 0x24051300,
+-0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b,
+-0xafa00014, 0x32020001, 0x54400001, 0x36d60080,
+-0x32020002, 0x54400001, 0x36d60100, 0x32020008,
+-0x54400001, 0x36d60200, 0x32020010, 0x54400001,
+-0x36d60400, 0x32020080, 0x54400001, 0x36d60800,
+-0x8c020218, 0x30420200, 0x10400002, 0x3c020008,
+-0x2c2b025, 0x8c020218, 0x30420800, 0x10400002,
+-0x3c020080, 0x2c2b025, 0x8c020218, 0x30420400,
+-0x10400002, 0x3c020100, 0x2c2b025, 0x8c020218,
+-0x30420100, 0x10400002, 0x3c020200, 0x2c2b025,
+-0x8c020218, 0x30420080, 0x10400002, 0x3c020400,
+-0x2c2b025, 0x8c020218, 0x30422000, 0x10400002,
+-0x3c020010, 0x2c2b025, 0x8c020218, 0x30424000,
+-0x10400002, 0x3c020020, 0x2c2b025, 0x8c020218,
+-0x30421000, 0x10400002, 0x3c020040, 0x2c2b025,
+-0x8ee20498, 0x8ee3049c, 0xaf420160, 0xaf430164,
+-0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c,
+-0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174,
+-0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c,
+-0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184,
+-0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c,
+-0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194,
+-0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c,
+-0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4,
+-0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8,
+-0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c,
+-0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
+-0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a,
+-0x3484ca00, 0x3821, 0x24020006, 0x24030002,
+-0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200,
+-0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290,
+-0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8,
+-0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f,
+-0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001,
+-0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c,
+-0x24051400, 0x21702, 0x24420030, 0xa062022c,
+-0x3471021, 0xa040022c, 0x8c070218, 0x2c03021,
+-0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014,
+-0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80,
+-0x24060010, 0x27b10030, 0x2203821, 0x27b30034,
+-0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8,
+-0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00,
+-0x8fa20034, 0x246400ff, 0x852024, 0x831823,
+-0x431023, 0xafa20034, 0xafa40030, 0x3c040001,
+-0x24845d44, 0x3c050000, 0x24a54100, 0x24060108,
+-0x2203821, 0xc0017a3, 0xafb30010, 0x409021,
+-0x32c20003, 0x3c010001, 0xac326e80, 0x10400045,
+-0x2203821, 0x8f820050, 0x3c030010, 0x431024,
+-0x10400016, 0x0, 0x8c020218, 0x30420040,
+-0x1040000f, 0x24020001, 0x8f820050, 0x8c030218,
+-0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f,
+-0xafa20010, 0xafa30014, 0x8f870040, 0x24051500,
+-0xc002b3b, 0x2c03021, 0x10000004, 0x0,
+-0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
+-0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001,
+-0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030,
+-0x2603821, 0x27b10034, 0x34420a00, 0xaf420010,
+-0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70,
+-0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90,
+-0xc53023, 0x2603821, 0xaf420108, 0xc0017a3,
+-0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001,
+-0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023,
+-0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3,
+-0xafb10010, 0x3c040001, 0x24845da4, 0x10000024,
+-0x24051600, 0x3c040001, 0x24845dac, 0x3c050001,
+-0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023,
+-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc,
+-0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c,
+-0xc53023, 0x2203821, 0xaf420108, 0xc0017a3,
+-0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001,
+-0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023,
+-0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3,
+-0xafb30010, 0x3c040001, 0x24845de4, 0x24051650,
+-0x2c03021, 0x3821, 0x3c010001, 0xac226ef8,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020,
+-0x10400021, 0x27a70030, 0x3c040001, 0x24845df0,
+-0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8,
+-0xc53023, 0x24022000, 0xaf42001c, 0x27a20034,
+-0xc0017a3, 0xafa20010, 0x21900, 0x31982,
+-0x3c040800, 0x641825, 0xae430028, 0x24030010,
+-0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040,
+-0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010,
+-0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0,
+-0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c,
+-0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001,
+-0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10,
+-0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c,
+-0x24051700, 0xc002b3b, 0x3821, 0x3c020000,
+-0x24425cbc, 0x21100, 0x21182, 0x3c030800,
+-0x431025, 0xae420028, 0x24020008, 0xaf42003c,
+-0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001,
+-0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c,
+-0x24051800, 0x32c60020, 0xc002b3b, 0x0,
+-0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff,
+-0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800,
+-0x651824, 0x31882, 0x641825, 0x451024,
+-0x21082, 0x441025, 0xacc20080, 0x32c20180,
+-0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080,
+-0x431024, 0x1040000d, 0x0, 0x8f820050,
+-0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001,
+-0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040,
+-0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050,
+-0x3c030010, 0x431024, 0x10400016, 0x0,
+-0x8c020218, 0x30420040, 0x1040000f, 0x24020001,
+-0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001,
+-0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014,
+-0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021,
+-0x10000004, 0x0, 0x3c010001, 0x370821,
+-0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001,
+-0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023,
+-0x8f420008, 0x27b30030, 0x2603821, 0x27b10034,
+-0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010,
+-0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4,
+-0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821,
+-0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001,
+-0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001,
+-0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001,
+-0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001,
+-0x24845e7c, 0x10000027, 0x24052100, 0x3c040001,
+-0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001,
+-0x24c6a104, 0xc53023, 0x27b10030, 0x2203821,
+-0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001,
+-0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001,
+-0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c,
+-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4,
+-0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4,
+-0xc53023, 0x2203821, 0x3c010001, 0xac226f04,
+-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8,
+-0x24052150, 0x2c03021, 0x3821, 0x3c010001,
+-0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014,
+-0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff,
+-0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800,
+-0x711824, 0x31882, 0x6e1825, 0x511024,
+-0x21082, 0x4e1025, 0xae630038, 0xae620078,
+-0x8c020218, 0x30420040, 0x14400004, 0x24020001,
+-0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
+-0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001,
+-0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821,
+-0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001,
+-0xac226efc, 0x511024, 0x21082, 0x3c0e0800,
+-0x4e1025, 0xae620050, 0x32c22000, 0x10400006,
+-0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024,
+-0x1000000f, 0x21082, 0x3c040001, 0x24845ed8,
+-0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4,
+-0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001,
+-0xac226f14, 0x511024, 0x21082, 0x3c0e0800,
+-0x4e1025, 0xae620048, 0x32c24000, 0x10400005,
+-0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e,
+-0x21100, 0x3c040001, 0x24845ef0, 0x3c050001,
+-0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023,
+-0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001,
+-0xac226f08, 0x21100, 0x21182, 0x3c030800,
+-0x431025, 0xae420060, 0x3c040001, 0x24845f08,
+-0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650,
+-0xc53023, 0x27b10030, 0x2203821, 0x27b30034,
+-0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff,
+-0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468,
+-0x3c060000, 0x24c66588, 0xc53023, 0x2203821,
+-0x240f021, 0x3c010001, 0xac226edc, 0x4e1024,
+-0x21082, 0x3c150800, 0x551025, 0xafae0044,
+-0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001,
+-0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000,
+-0x24c66808, 0x8fae0044, 0xc53023, 0x2203821,
+-0x3c010001, 0xac226ed0, 0x4e1024, 0x21082,
+-0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010,
+-0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810,
+-0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023,
+-0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024,
+-0x21082, 0x551025, 0xafc200c0, 0xc0017a3,
+-0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001,
+-0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044,
+-0xc53023, 0x2203821, 0x3c010001, 0xac226ed4,
+-0x4e1024, 0x21082, 0x551025, 0xafc200c8,
+-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c,
+-0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20,
+-0xc53023, 0x2203821, 0xaf420110, 0xc0017a3,
+-0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001,
+-0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023,
+-0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010,
+-0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80,
+-0x3c060001, 0x24c65aac, 0xc53023, 0x2203821,
+-0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010,
+-0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298,
+-0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821,
+-0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044,
+-0x3c010001, 0xac226f18, 0x4e1024, 0x21082,
+-0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40,
+-0x0, 0xc0027a8, 0x0, 0xac000228,
+-0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038,
+-0x96e20460, 0xaf420080, 0x32c24000, 0x14400003,
+-0x0, 0x96e20480, 0xaf420084, 0x96e70490,
+-0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088,
+-0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000,
+-0x10400003, 0x24020400, 0x10e2000b, 0x0,
+-0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f,
+-0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
+-0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138,
+-0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098,
+-0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084,
+-0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200,
+-0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58,
+-0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0,
+-0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c,
+-0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff,
+-0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010,
+-0x3c010001, 0xac226eb8, 0x21100, 0x21182,
+-0x511025, 0xc0018fc, 0xae420000, 0x8f820240,
+-0x3c030001, 0x431025, 0xaf820240, 0x3c020000,
+-0x24424034, 0xaf820244, 0xaf800240, 0x8f820060,
+-0x511024, 0x14400005, 0x3c030800, 0x8f820060,
+-0x431024, 0x1040fffd, 0x0, 0xc003c4d,
+-0x8821, 0x3c020100, 0xafa20020, 0x8f530018,
+-0x240200ff, 0x56620001, 0x26710001, 0x8c020228,
+-0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
+-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+-0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010,
+-0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
+-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+-0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
+-0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
+-0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
+-0x24070008, 0xa32821, 0xa3482b, 0x822021,
+-0x100f809, 0x892021, 0x1440000b, 0x24070008,
+-0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+-0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020,
+-0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
+-0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
+-0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
+-0x40f809, 0x24c6001c, 0x14400010, 0x0,
+-0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
+-0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+-0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020,
+-0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4,
+-0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f,
+-0x10400069, 0x3c020700, 0x34423000, 0xafa20028,
+-0x8f530018, 0x240200ff, 0x12620002, 0x8821,
+-0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
+-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+-0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009,
+-0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f,
+-0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c,
+-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+-0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+-0xa3482b, 0x822021, 0x100f809, 0x892021,
+-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009,
+-0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200,
+-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
+-0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
+-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+-0x14400010, 0x0, 0x8f420340, 0x24420001,
+-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009,
+-0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b,
+-0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0,
+-0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010,
+-0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b,
+-0x3821, 0x10000004, 0x0, 0x8c020264,
+-0x10400005, 0x0, 0x8f8200a0, 0x30420004,
+-0x1440fffa, 0x0, 0x8f820044, 0x34420004,
+-0xaf820044, 0x8f420308, 0x24420001, 0xaf420308,
+-0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023,
+-0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
+-0x10400006, 0x24020001, 0x8f420090, 0x8f430144,
+-0x431021, 0xaf420090, 0x24020001, 0xaf42008c,
+-0x32c20008, 0x10400006, 0x0, 0x8f820214,
+-0x3c038100, 0x3042ffff, 0x431025, 0xaf820214,
+-0x3c030001, 0x8c636d94, 0x30620002, 0x10400009,
+-0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000,
+-0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012,
+-0xc53023, 0x10400009, 0x0, 0x3c040001,
+-0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000,
+-0x24c67678, 0x10000008, 0xc53023, 0x3c040001,
+-0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000,
+-0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034,
+-0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc,
+-0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100,
+-0x21182, 0x431025, 0xae420040, 0x8f8200a0,
+-0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c,
+-0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001,
+-0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001,
+-0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001,
+-0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b,
+-0x24052400, 0x8f820200, 0xafa20010, 0x8f820220,
+-0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001,
+-0x24846008, 0xc002b3b, 0x24052500, 0x8f830060,
+-0x74100b, 0x242000a, 0x200f821, 0x0,
+-0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
+-0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
+-0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001,
+-0x24846014, 0x24052600, 0x3021, 0x3821,
+-0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014,
+-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
+-0x0, 0x3e00008, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x3e00008, 0x0, 0x3e00008, 0x0,
+-0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef,
+-0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff,
+-0xafa40018, 0xa22823, 0xa32824, 0x8ca20000,
+-0x1044000a, 0x0, 0xafa50010, 0x8ca20000,
+-0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001,
+-0x2484601c, 0xc002b3b, 0x24052700, 0x8fbf0218,
+-0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
+-0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
+-0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
+-0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
+-0xaca30000, 0x10460005, 0xae040000, 0xa08021,
+-0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
+-0x24846028, 0x24052800, 0x2003021, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021,
+-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+-0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
+-0x2821, 0x24030020, 0xe31024, 0x10400002,
+-0x63042, 0xa62821, 0x31842, 0x1460fffb,
+-0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
+-0x45102b, 0x14400003, 0x3c020001, 0x10000008,
+-0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
+-0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
+-0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
+-0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
+-0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
+-0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
+-0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
+-0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
+-0xc002b3b, 0x2403021, 0x8e230000, 0x702021,
+-0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
+-0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
+-0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
+-0x8e220000, 0x501021, 0x1000000b, 0xae220000,
+-0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
+-0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
+-0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c,
+-0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+-0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
+-0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84,
+-0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc,
+-0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001,
+-0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0,
+-0xac201ffc, 0x431023, 0x441023, 0x245bb000,
+-0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
+-0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
+-0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0,
+-0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001,
+-0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d,
+-0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+-0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200,
+-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
+-0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
+-0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
+-0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014,
+-0xc001916, 0x0, 0x8f820240, 0x34420004,
+-0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
+-0x571021, 0x904240f4, 0x10400092, 0x2403fffc,
+-0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c,
+-0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
+-0x24846040, 0x70102b, 0x1440001a, 0x27b30018,
+-0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
+-0xafa30014, 0xc002b3b, 0x2203821, 0x8fa30018,
+-0x702021, 0x64102b, 0x10400007, 0x2403021,
+-0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
+-0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
+-0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
+-0xae620000, 0x2408821, 0x24053100, 0xafb00010,
+-0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
+-0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c,
+-0x3c040001, 0x2484605c, 0x24120020, 0x3c010001,
+-0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018,
+-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50,
+-0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
+-0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020,
+-0x65102b, 0x10400007, 0x0, 0x8c820000,
+-0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+-0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+-0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+-0x3c100001, 0x26106f50, 0x24053100, 0xafa70010,
+-0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+-0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001,
+-0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001,
+-0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018,
+-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70,
+-0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
+-0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020,
+-0x65102b, 0x10400007, 0x0, 0x8c820000,
+-0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+-0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+-0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+-0x3c100001, 0x26106f70, 0x24053100, 0xafa70010,
+-0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+-0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031,
+-0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001,
+-0x2652809c, 0x2121023, 0x438024, 0x8fa3001c,
+-0x3c040001, 0x24846084, 0x70102b, 0x1440001a,
+-0x27b30018, 0x8fb10018, 0x24053000, 0x2403021,
+-0xafb00010, 0xafa30014, 0xc002b3b, 0x2203821,
+-0x8fa30018, 0x702021, 0x64102b, 0x10400007,
+-0x2403021, 0x8cc20000, 0xac620000, 0x24630004,
+-0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c,
+-0x501023, 0xafa2001c, 0x8e620000, 0x501021,
+-0x1000000a, 0xae620000, 0x2408821, 0x24053100,
+-0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021,
+-0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001,
+-0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400,
+-0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c,
+-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+-0x27bd0038, 0x0, 0x0, 0x8f820040,
+-0x3c03f000, 0x431024, 0x3c036000, 0x14430006,
+-0x0, 0x8f820050, 0x2403ff80, 0x431024,
+-0x34420055, 0xaf820050, 0x8f820054, 0x244203e8,
+-0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004,
+-0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4,
+-0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008,
+-0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008,
+-0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054,
+-0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024,
+-0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024,
+-0x36940040, 0x3c020001, 0x8c426da8, 0x10400017,
+-0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016,
+-0x282a025, 0x3c020001, 0x8c426e44, 0x14400012,
+-0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003,
+-0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002,
+-0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf,
+-0x0, 0x10000004, 0x3c020200, 0xc004196,
+-0x0, 0x3c020200, 0x2c21024, 0x10400003,
+-0x0, 0xc001f4b, 0x0, 0x8f4200d8,
+-0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b,
+-0x14400003, 0x0, 0xaf4000d8, 0x36940080,
+-0x8c030238, 0x1060000c, 0x0, 0x8f4201b0,
+-0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006,
+-0x0, 0x934205c5, 0x14400003, 0x0,
+-0xc001da0, 0x0, 0x8fbf0010, 0x3e00008,
+-0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8,
+-0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059,
+-0x0, 0x3c020001, 0x571021, 0x904240f0,
+-0x10400026, 0x24070008, 0x8f440170, 0x8f450174,
+-0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010,
+-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
+-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
+-0x370821, 0xa02240f0, 0x8f820124, 0xafa20010,
+-0x8f820128, 0x3c040001, 0x24846128, 0xafa20014,
+-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
+-0x34a50900, 0x1000005c, 0x0, 0x8f420300,
+-0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c,
+-0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170,
+-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+-0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
+-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+-0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120,
+-0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036,
+-0x0, 0x8f420300, 0x8f43002c, 0x24420001,
+-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+-0xaf430038, 0x3c010001, 0x370821, 0xa02040f1,
+-0x3c010001, 0x370821, 0xa02040f0, 0x10000026,
+-0xaf400034, 0x934205c1, 0x1040001d, 0x0,
+-0xa34005c1, 0x8f820040, 0x30420001, 0x14400008,
+-0x2021, 0x8c030104, 0x24020001, 0x50620005,
+-0x24040001, 0x8c020264, 0x10400003, 0x801021,
+-0x24040001, 0x801021, 0x10400006, 0x0,
+-0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008,
+-0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
+-0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
+-0x3c010001, 0x370821, 0xa02040f0, 0x3c010001,
+-0x370821, 0xa02040f1, 0x8f420000, 0x10400007,
+-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+-0x0, 0x10000005, 0x0, 0xaf800048,
+-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+-0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060,
+-0x8f420000, 0x10400003, 0x0, 0x10000002,
+-0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008,
+-0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8,
+-0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029,
+-0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c,
+-0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
+-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+-0x14400011, 0x24020001, 0x3c010001, 0x370821,
+-0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
+-0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044,
+-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300,
+-0x1000000f, 0x0, 0x8f420304, 0x24420001,
+-0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
+-0x3c010001, 0x370821, 0xa02040f2, 0x10000004,
+-0xaf400078, 0x3c010001, 0x370821, 0xa02040f2,
+-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x3c03feff, 0x3463ffff,
+-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
+-0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8,
+-0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
+-0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5,
+-0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b,
+-0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002,
+-0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001,
+-0x8c636d98, 0x34420002, 0xaf420004, 0x24020001,
+-0x14620003, 0x3c020600, 0x10000002, 0x34423000,
+-0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034,
+-0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff,
+-0x11420002, 0x1821, 0x25430001, 0x8c020228,
+-0x609821, 0x1662000e, 0x3c050009, 0x8f42033c,
+-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+-0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014,
+-0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500,
+-0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020,
+-0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
+-0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
+-0x1040001b, 0xa821, 0xe09021, 0x265e04c0,
+-0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004,
+-0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021,
+-0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008,
+-0xa32821, 0xa3482b, 0x822021, 0x100f809,
+-0x892021, 0x54400006, 0x24150001, 0x8f820054,
+-0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0,
+-0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378,
+-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+-0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124,
+-0x3c040001, 0x24846118, 0xafa20014, 0x8d460000,
+-0x3c050009, 0x10000035, 0x34a50600, 0x8f420308,
+-0x24150001, 0x24420001, 0xaf420308, 0x8f420308,
+-0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054,
+-0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016,
+-0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c,
+-0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010,
+-0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c,
+-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
+-0x0, 0x8f820054, 0x2221023, 0x2c4203e9,
+-0x1440ffee, 0x0, 0x32a200ff, 0x14400011,
+-0x3c050009, 0x8f420378, 0x24420001, 0xaf420378,
+-0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034,
+-0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
+-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
+-0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec,
+-0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029,
+-0x36100040, 0x3c020400, 0x2c21024, 0x10400013,
+-0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4,
+-0x14640006, 0x36100040, 0x8f420270, 0x8f430274,
+-0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250,
+-0x8f430254, 0x8f440270, 0x8f450274, 0x10000012,
+-0x3a100020, 0x1000002b, 0x2028024, 0x8f420250,
+-0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024,
+-0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021,
+-0x36100040, 0x8f420250, 0x8f430254, 0x8f440270,
+-0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019,
+-0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011,
+-0x28420033, 0x8f420004, 0x30420001, 0x10400009,
+-0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf,
+-0x2028024, 0x1000000b, 0x36100040, 0x10000009,
+-0x36100060, 0x8f4200d4, 0x36100040, 0x24430001,
+-0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4,
+-0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024,
+-0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
+-0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
+-0x27bd0058, 0x3e00008, 0x0, 0x3c020001,
+-0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+-0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001,
+-0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004,
+-0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004,
+-0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004,
+-0x24020001, 0x14620003, 0x3c020600, 0x10000002,
+-0x34423000, 0x34421000, 0xafa20020, 0x1821,
+-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+-0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
+-0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021,
+-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+-0x24070008, 0xa32821, 0xa3482b, 0x822021,
+-0x100f809, 0x892021, 0x54400006, 0x24130001,
+-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+-0x0, 0x326200ff, 0x54400017, 0xaf520018,
+-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+-0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
+-0x8d460000, 0x10000035, 0x34a50600, 0x8f420308,
+-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+-0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054,
+-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016,
+-0x9821, 0x3c150020, 0x24110010, 0x8f42000c,
+-0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
+-0xafb20014, 0x551025, 0xafa20018, 0x8f42010c,
+-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
+-0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
+-0x1440ffee, 0x0, 0x326200ff, 0x14400011,
+-0x0, 0x8f420378, 0x24420001, 0xaf420378,
+-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24846120, 0x3c050009,
+-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
+-0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec,
+-0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018,
+-0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4,
+-0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270,
+-0x8f430274, 0x8f4401b8, 0x10640021, 0x0,
+-0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0,
+-0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4,
+-0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0,
+-0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001,
+-0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001,
+-0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001,
+-0x8f420004, 0x30420001, 0x10400008, 0x0,
+-0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1,
+-0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4,
+-0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5,
+-0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1,
+-0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1,
+-0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c,
+-0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001,
+-0x5462001f, 0x2021, 0x3c020001, 0x90426cf0,
+-0x1443001b, 0x24040005, 0x10000019, 0x24040006,
+-0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b,
+-0x24020001, 0x3c030001, 0x90636cf1, 0x54620010,
+-0x2021, 0x3c020001, 0x90426cf0, 0x1443000c,
+-0x24040003, 0x1000000a, 0x24040004, 0x3c030001,
+-0x90636cf1, 0x14620006, 0x2021, 0x3c020001,
+-0x90426cf0, 0x24040001, 0x50440001, 0x24040002,
+-0xc00565a, 0x0, 0x2402ff7f, 0x282a024,
+-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+-0x27bd0050, 0x3e00008, 0x0, 0x3c020001,
+-0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+-0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001,
+-0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8,
+-0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
+-0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
+-0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
+-0x10000002, 0x34423000, 0x34421000, 0xafa20020,
+-0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
+-0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
+-0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
+-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+-0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014,
+-0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
+-0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
+-0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
+-0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
+-0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
+-0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
+-0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
+-0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
+-0x822021, 0x100f809, 0x892021, 0x54400006,
+-0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
+-0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
+-0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
+-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24846118, 0x3c050009,
+-0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
+-0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
+-0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
+-0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
+-0x10400016, 0x9821, 0x3c150020, 0x24110010,
+-0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+-0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
+-0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
+-0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
+-0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
+-0x14400011, 0x0, 0x8f420378, 0x24420001,
+-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+-0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
+-0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
+-0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001,
+-0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
+-0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
+-0x0, 0x934205c0, 0x8f440250, 0x8f450254,
+-0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
+-0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
+-0x0, 0x8f420250, 0x8f430254, 0x934405c0,
+-0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
+-0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
+-0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
+-0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
+-0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
+-0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
+-0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
+-0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
+-0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
+-0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
+-0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
+-0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
+-0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
+-0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
+-0x10400007, 0x0, 0x934205c0, 0x34420040,
+-0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
+-0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
+-0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
+-0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
+-0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
+-0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
+-0x14620005, 0x0, 0x934405c0, 0x42102,
+-0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
+-0xc005640, 0x0, 0x2402ff7f, 0x282a024,
+-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+-0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
+-0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
+-0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
+-0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
+-0x8c820000, 0xac620000, 0x24630004, 0x65102b,
+-0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
+-0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
+-0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
+-0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
+-0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
+-0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
+-0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
+-0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
+-0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
+-0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
+-0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
+-0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
+-0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
+-0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
+-0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
+-0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
+-0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
+-0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+-0x24040001, 0x24050000, 0x651821, 0x65302b,
+-0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
+-0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
+-0x24090000, 0x401821, 0x1021, 0x882024,
+-0xa92824, 0x822025, 0xa32825, 0xaee400c0,
+-0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
+-0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
+-0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
+-0x65302b, 0x441021, 0x461021, 0xaee200d0,
+-0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
+-0x401821, 0x1021, 0x882024, 0xa92824,
+-0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
+-0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
+-0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
+-0x24040001, 0x24050000, 0x651821, 0x65302b,
+-0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
+-0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
+-0x1021, 0x882024, 0xa92824, 0x822025,
+-0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
+-0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
+-0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
+-0x40f809, 0x24070400, 0x104000f0, 0x3c020400,
+-0xafa20020, 0x934205c6, 0x10400089, 0x1821,
+-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+-0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
+-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+-0x24070008, 0xa32821, 0xa3482b, 0x822021,
+-0x100f809, 0x892021, 0x54400006, 0x24130001,
+-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+-0x0, 0x326200ff, 0x54400017, 0xaf520018,
+-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+-0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
+-0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+-0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
+-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
+-0x24846120, 0x3c050009, 0xafa20014, 0x8d460000,
+-0x34a50700, 0xc002b3b, 0x3c03821, 0x1021,
+-0x1440005b, 0x24020001, 0x10000065, 0x0,
+-0x8f510018, 0x240200ff, 0x12220002, 0x8021,
+-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
+-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+-0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009,
+-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+-0xa3482b, 0x822021, 0x100f809, 0x892021,
+-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009,
+-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
+-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
+-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+-0x54400011, 0x24020001, 0x8f420340, 0x24420001,
+-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24846104, 0x3c050009,
+-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
+-0x2203821, 0x1021, 0x1040000d, 0x24020001,
+-0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
+-0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
+-0xaee20150, 0x10000003, 0x8ee20150, 0x24020001,
+-0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+-0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020,
+-0x8f8200b0, 0x30420004, 0x10400068, 0x0,
+-0x8f430128, 0x8f820104, 0x14620005, 0x0,
+-0x8f430130, 0x8f8200b4, 0x10620006, 0x0,
+-0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b,
+-0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024,
+-0x1040000d, 0x0, 0x8f82011c, 0x34420002,
+-0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024,
+-0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024,
+-0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104,
+-0x14620005, 0x0, 0x8f430130, 0x8f8200b4,
+-0x10620010, 0x0, 0x8f820104, 0xaf420128,
+-0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010,
+-0x8f420130, 0x3c040001, 0x24846144, 0xafa20014,
+-0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031,
+-0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130,
+-0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c,
+-0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000,
+-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104,
+-0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008,
+-0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c,
+-0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c,
+-0x26e60028, 0x40f809, 0x24070400, 0x8f82011c,
+-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
+-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128,
+-0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c,
+-0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
+-0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0,
+-0x30420004, 0x10400069, 0x0, 0x8f43012c,
+-0x8f820124, 0x14620005, 0x0, 0x8f430134,
+-0x8f8200a4, 0x10620006, 0x0, 0x8f820124,
+-0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134,
+-0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d,
+-0x0, 0x8f82011c, 0x34420002, 0xaf82011c,
+-0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0,
+-0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b,
+-0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005,
+-0x0, 0x8f430134, 0x8f8200a4, 0x10620010,
+-0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
+-0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134,
+-0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c,
+-0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200,
+-0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001,
+-0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0,
+-0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c,
+-0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0,
+-0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124,
+-0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208,
+-0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001,
+-0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c,
+-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
+-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c,
+-0xafa20010, 0x8f420134, 0x3c040001, 0x24846180,
+-0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
+-0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020,
+-0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001,
+-0x3c060080, 0x3c050100, 0x8f820070, 0x481024,
+-0x1040fffd, 0x0, 0x8f820054, 0x24420005,
+-0xaf820078, 0x8c040234, 0x10800016, 0x1821,
+-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
+-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
+-0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
+-0x0, 0x3c030080, 0x3c010001, 0x370821,
+-0xac2040e8, 0x3c010001, 0x370821, 0x1000000b,
+-0xa02740f0, 0x3c020001, 0x571021, 0x904240f0,
+-0x54400006, 0x661825, 0x3c020001, 0x571021,
+-0x904240f1, 0x54400001, 0x661825, 0x8c040230,
+-0x10800013, 0x0, 0x3c020001, 0x571021,
+-0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
+-0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
+-0x44102b, 0x14400006, 0x0, 0x3c010001,
+-0x370821, 0xac2040ec, 0x10000006, 0x651825,
+-0x3c020001, 0x571021, 0x904240f2, 0x54400001,
+-0x651825, 0x1060ffbc, 0x0, 0x8f420000,
+-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+-0x1040fffd, 0x0, 0x10000005, 0x0,
+-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+-0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
+-0x10400003, 0x0, 0x1000ffa7, 0xaf80004c,
+-0x1000ffa5, 0xaf800048, 0x3e00008, 0x0,
+-0x0, 0x0, 0x0, 0x27bdffe0,
+-0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025,
+-0x24040004, 0x8c020114, 0xaf420020, 0xaf840064,
+-0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc,
+-0x8f820064, 0x30420004, 0x14400005, 0x0,
+-0x8c030114, 0x8f420020, 0x1462fff2, 0x0,
+-0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x431025, 0xaf820060,
+-0x8f420000, 0x10400073, 0x0, 0x1000006f,
+-0x0, 0x30c20008, 0x10400020, 0x24040008,
+-0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
+-0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
+-0x30420008, 0x14400005, 0x0, 0x8c03011c,
+-0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
+-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+-0x1040fffd, 0x0, 0x10000005, 0x0,
+-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+-0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
+-0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
+-0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
+-0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
+-0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
+-0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
+-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
+-0x30c20010, 0x10400029, 0x24040010, 0x8c020124,
+-0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
+-0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
+-0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
+-0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
+-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x34420100, 0xaf820060,
+-0x8f420000, 0x10400003, 0x0, 0x1000006c,
+-0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001,
+-0x10400004, 0x24020001, 0xaf820064, 0x10000064,
+-0x0, 0x30c20002, 0x1440000b, 0x3c050003,
+-0x3c040001, 0x24846244, 0x34a50500, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0,
+-0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c,
+-0x10a20048, 0x51080, 0x8c460300, 0x24a20001,
+-0x3045003f, 0x24020003, 0xac05022c, 0x61e02,
+-0x10620005, 0x24020010, 0x1062001d, 0x30c20fff,
+-0x10000039, 0x0, 0x8f4302a8, 0x8f440000,
+-0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8,
+-0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c,
+-0x1040fffd, 0x0, 0x10000005, 0x0,
+-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+-0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
+-0x1040001f, 0x0, 0x1000001b, 0x0,
+-0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
+-0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
+-0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c,
+-0x1040fffd, 0x0, 0x10000005, 0x0,
+-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+-0x8f820060, 0x34420100, 0xaf820060, 0x8f420000,
+-0x10400003, 0x0, 0x10000006, 0xaf80004c,
+-0x10000004, 0xaf800048, 0xc002196, 0xc02021,
+-0x402821, 0x8c02010c, 0x14a20002, 0x24020002,
+-0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
+-0x0, 0x8c02010c, 0x14a2ffac, 0x0,
+-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
+-0x0, 0x27bdffa0, 0xafb00040, 0x808021,
+-0x101602, 0x2442ffff, 0x304300ff, 0x2c620013,
+-0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
+-0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034,
+-0x31080, 0x3c010001, 0x220821, 0x8c226288,
+-0x400008, 0x0, 0x101302, 0x30440fff,
+-0x24020001, 0x10820005, 0x24020002, 0x1082000c,
+-0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004,
+-0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204,
+-0x3c040001, 0x8c846e80, 0x10000009, 0x34630001,
+-0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001,
+-0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28,
+-0x21100, 0x21182, 0xaf430004, 0x3c030800,
+-0x431025, 0xac820038, 0x8f840054, 0x41442,
+-0x41c82, 0x431021, 0x41cc2, 0x431023,
+-0x41d02, 0x431021, 0x41d42, 0x431023,
+-0x10000009, 0xaf420208, 0x3c040001, 0x24846250,
+-0x34a51000, 0x2003021, 0x3821, 0xafa00010,
+-0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001,
+-0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028,
+-0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
+-0xc002518, 0x2002021, 0x10000216, 0x0,
+-0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
+-0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
+-0x21080, 0x8c430300, 0x25420001, 0x3042003f,
+-0xafa20034, 0xac02022c, 0xafa50028, 0xc002518,
+-0xafa3002c, 0x10000203, 0x0, 0x27b00028,
+-0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
+-0xc002657, 0x2002021, 0x100001fa, 0x0,
+-0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
+-0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
+-0x21080, 0x8c430300, 0x25420001, 0x3042003f,
+-0xafa20034, 0xac02022c, 0xafa50028, 0xc002657,
+-0xafa3002c, 0x100001e7, 0x0, 0x101302,
+-0x30430fff, 0x24020001, 0x10620005, 0x24020002,
+-0x1062001e, 0x3c020002, 0x10000033, 0x3c050003,
+-0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025,
+-0x8f820228, 0x3c010001, 0x370821, 0xac2238d8,
+-0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc,
+-0x8f820230, 0x3c010001, 0x370821, 0xac2238e0,
+-0x8f820234, 0x3c010001, 0x370821, 0xac2238e4,
+-0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230,
+-0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024,
+-0x10400012, 0x3c02fffd, 0x3c020001, 0x571021,
+-0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021,
+-0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021,
+-0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021,
+-0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff,
+-0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c,
+-0x34a51100, 0x2003021, 0x3821, 0xafa00010,
+-0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001,
+-0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302,
+-0x30450fff, 0x24020001, 0x10a20005, 0x24020002,
+-0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003,
+-0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004,
+-0x2c4b025, 0x621824, 0x34630008, 0xaf830220,
+-0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb,
+-0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024,
+-0xaf820220, 0x10000009, 0xaf450298, 0x3c040001,
+-0x24846268, 0x34a51200, 0x2003021, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc,
+-0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc,
+-0x27840208, 0x24050200, 0xc002bbf, 0x24060008,
+-0x27440224, 0x24050200, 0xc002bbf, 0x24060008,
+-0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169,
+-0x8f4202c4, 0x101302, 0x30430fff, 0x24020001,
+-0x10620011, 0x28620002, 0x50400005, 0x24020002,
+-0x10600007, 0x0, 0x10000017, 0x0,
+-0x1062000f, 0x0, 0x10000013, 0x0,
+-0x8c060248, 0x2021, 0xc005104, 0x24050004,
+-0x10000007, 0x0, 0x8c060248, 0x2021,
+-0xc005104, 0x24050004, 0x10000010, 0x0,
+-0x8c06024c, 0x2021, 0xc005104, 0x24050001,
+-0x1000000a, 0x0, 0x3c040001, 0x24846274,
+-0x3c050003, 0x34a51300, 0x2003021, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0,
+-0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0,
+-0xc002426, 0x0, 0x10000136, 0x0,
+-0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8,
+-0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014,
+-0xafa20018, 0x8f420108, 0x26e60028, 0x40f809,
+-0x24070400, 0x1040fff5, 0x0, 0x10000125,
+-0x0, 0x3c03ffff, 0x34637fff, 0x8f420368,
+-0x8f440360, 0x2c3b024, 0x1821, 0xaf400058,
+-0xaf40005c, 0xaf400060, 0xaf400064, 0x441023,
+-0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020,
+-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+-0xafaa003c, 0x27c30001, 0x8c020228, 0x609021,
+-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+-0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010,
+-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+-0x24070008, 0xa32821, 0xa3482b, 0x822021,
+-0x100f809, 0x892021, 0x54400006, 0x24130001,
+-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+-0x0, 0x326200ff, 0x54400017, 0xaf520018,
+-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+-0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124,
+-0x3c040001, 0x24846218, 0x3c050009, 0xafa20014,
+-0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+-0x326200ff, 0x14400011, 0x0, 0x8f420378,
+-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+-0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001,
+-0x24846220, 0x3c050009, 0xafa20014, 0x8d460000,
+-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0,
+-0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8,
+-0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8,
+-0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
+-0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8,
+-0x8f820220, 0x30420008, 0x14400002, 0x24020001,
+-0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001,
+-0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff,
+-0x3442ffff, 0x2021824, 0x32c20180, 0x14400006,
+-0x3402fffb, 0x43102b, 0x14400003, 0x0,
+-0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280,
+-0x3c050003, 0x34a51500, 0x2003021, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700,
+-0x34421000, 0x101e02, 0x621825, 0xafa30020,
+-0x8f510018, 0x240200ff, 0x12220002, 0x8021,
+-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
+-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+-0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009,
+-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+-0xa3482b, 0x822021, 0x100f809, 0x892021,
+-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009,
+-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
+-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
+-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+-0x14400010, 0x0, 0x8f420340, 0x24420001,
+-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24846204, 0x3c050009,
+-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
+-0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0,
+-0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0,
+-0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054,
+-0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044,
+-0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8,
+-0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8,
+-0x354a8320, 0x90870000, 0x24840001, 0x3021,
+-0x1071026, 0x30420001, 0x10400002, 0x81842,
+-0x6a1826, 0x604021, 0x24c60001, 0x2cc20008,
+-0x1440fff7, 0x73842, 0x25290001, 0x125102b,
+-0x1440fff0, 0x0, 0x1001021, 0x3e00008,
+-0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+-0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200,
+-0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+-0x431024, 0x34420004, 0xaf820220, 0x8f820200,
+-0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004,
+-0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360,
+-0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c,
+-0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0,
+-0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8,
+-0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360,
+-0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368,
+-0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c,
+-0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
+-0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf,
+-0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc,
+-0x240203e8, 0x24040002, 0x24030001, 0xaf420294,
+-0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008,
+-0x10400004, 0x0, 0xaf430298, 0x10000003,
+-0x3021, 0xaf440298, 0x3021, 0x3c030001,
+-0x661821, 0x90636d00, 0x3461021, 0x24c60001,
+-0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821,
+-0x24c60001, 0x8f820040, 0x24040080, 0x24050080,
+-0x21702, 0x24420030, 0xa062022c, 0x3461021,
+-0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004,
+-0x14400006, 0x0, 0x8f820220, 0x3c0308ff,
+-0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c,
+-0x30e20004, 0x14400006, 0x0, 0x8f820200,
+-0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
+-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+-0x27bd0050, 0x0, 0x0, 0xaf400104,
+-0x24040001, 0x410c0, 0x2e21821, 0x24820001,
+-0x3c010001, 0x230821, 0xa42234d0, 0x402021,
+-0x2c820080, 0x1440fff8, 0x410c0, 0x24020001,
+-0x3c010001, 0x370821, 0xa42038d0, 0xaf420100,
+-0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234,
+-0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014,
+-0xafb00010, 0x8f420104, 0x28420005, 0x10400026,
+-0x808021, 0x3c020001, 0x8f430104, 0x344230d0,
+-0x2e22021, 0x318c0, 0x621821, 0x2e31821,
+-0x83102b, 0x10400015, 0x1021, 0x96070000,
+-0x24840006, 0x24660006, 0x9482fffc, 0x14470009,
+-0x2821, 0x9483fffe, 0x96020002, 0x14620006,
+-0xa01021, 0x94820000, 0x96030004, 0x431026,
+-0x2c450001, 0xa01021, 0x14400009, 0x24840008,
+-0x86102b, 0x1440fff0, 0x1021, 0x304200ff,
+-0x14400030, 0x24020001, 0x1000002e, 0x1021,
+-0x1000fffa, 0x24020001, 0x2002021, 0xc00240c,
+-0x24050006, 0x3042007f, 0x218c0, 0x2e31021,
+-0x3c010001, 0x220821, 0x942230d0, 0x1040fff2,
+-0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0,
+-0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000,
+-0x610c0, 0x572021, 0x882021, 0x94820000,
+-0x14470009, 0x2821, 0x94830002, 0x96020002,
+-0x14620006, 0xa01021, 0x94820004, 0x96030004,
+-0x431026, 0x2c450001, 0xa01021, 0x14400007,
+-0x610c0, 0x2e21021, 0x3c060001, 0xc23021,
+-0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2,
+-0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008,
+-0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0,
+-0x801021, 0xafb00030, 0x24500002, 0x2002021,
+-0x24050006, 0xafb10034, 0x408821, 0xafbf0048,
+-0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c,
+-0xafb20038, 0x3047007f, 0x710c0, 0x2e21021,
+-0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c,
+-0xa03021, 0x3c090001, 0x352934d2, 0x96280002,
+-0x510c0, 0x572021, 0x892021, 0x94820000,
+-0x14480009, 0x3021, 0x94830002, 0x96020002,
+-0x14620006, 0xc01021, 0x94820004, 0x96030004,
+-0x431026, 0x2c460001, 0xc01021, 0x14400007,
+-0x510c0, 0x2e21021, 0x3c050001, 0xa22821,
+-0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021,
+-0x10c00014, 0x610c0, 0x571821, 0x3c010001,
+-0x230821, 0x8c2334d0, 0x571021, 0xafa30010,
+-0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001,
+-0x24846394, 0xafa20014, 0x8e260000, 0x8e270004,
+-0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063,
+-0x3c020800, 0x8f450100, 0x10a00006, 0x510c0,
+-0x2e21021, 0x3c010001, 0x220821, 0x942234d0,
+-0xaf420100, 0xa03021, 0x14c00011, 0x628c0,
+-0x710c0, 0x2e21021, 0xafa70010, 0x3c010001,
+-0x220821, 0x942230d0, 0x3c040001, 0x248463a0,
+-0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004,
+-0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800,
+-0xb71821, 0x3c020001, 0x96040000, 0x344234d2,
+-0x621821, 0xa4640000, 0x8e020002, 0x720c0,
+-0xac620002, 0x2e41021, 0x3c030001, 0x621821,
+-0x946330d0, 0x2e51021, 0x3c010001, 0x220821,
+-0xa42334d0, 0x2e41021, 0x3c010001, 0x220821,
+-0xa42630d0, 0x8f420104, 0x24420001, 0x28420080,
+-0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001,
+-0x348430d2, 0x96030000, 0x210c0, 0x571021,
+-0x441021, 0xa4430000, 0x8e030002, 0xac430002,
+-0x8f420104, 0x24420001, 0xaf420104, 0x3c020002,
+-0x2c21024, 0x10400011, 0x72142, 0x3c030001,
+-0x346338d8, 0x24020003, 0x441023, 0x21080,
+-0x572021, 0x832021, 0x571021, 0x431021,
+-0x30e5001f, 0x8c430000, 0x24020001, 0xa21004,
+-0x621825, 0x1000000c, 0xac830000, 0x24020003,
+-0x441023, 0x21080, 0x5c2821, 0x5c1021,
+-0x30e4001f, 0x8c430228, 0x24020001, 0x821004,
+-0x621825, 0xaca30228, 0x3c020800, 0x34421000,
+-0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020,
+-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
+-0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
+-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+-0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009,
+-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
+-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
+-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
+-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
+-0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+-0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
+-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
+-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+-0xa3482b, 0x822021, 0x100f809, 0x892021,
+-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
+-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
+-0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+-0xafa20010, 0x8f820124, 0x3c040001, 0x24846368,
+-0x3c050009, 0xafa20014, 0x8d460000, 0x10000033,
+-0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+-0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
+-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+-0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
+-0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+-0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
+-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
+-0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
+-0x1440ffef, 0x0, 0x326200ff, 0x14400011,
+-0x0, 0x8f420378, 0x24420001, 0xaf420378,
+-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+-0x8f820124, 0x3c040001, 0x24846370, 0x3c050009,
+-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
+-0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4,
+-0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4,
+-0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+-0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021,
+-0xafb00040, 0x24500002, 0x2002021, 0x24050006,
+-0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054,
+-0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048,
+-0x3048007f, 0x810c0, 0x2e21021, 0x3c060001,
+-0xc23021, 0x94c630d0, 0x10c0001c, 0x3821,
+-0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0,
+-0x572021, 0x8a2021, 0x94820000, 0x14490009,
+-0x2821, 0x94830002, 0x96020002, 0x14620006,
+-0xa01021, 0x94820004, 0x96030004, 0x431026,
+-0x2c450001, 0xa01021, 0x14400008, 0x610c0,
+-0xc03821, 0x2e21021, 0x3c060001, 0xc23021,
+-0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011,
+-0xafa70028, 0x810c0, 0x2e21021, 0xafa80010,
+-0x3c010001, 0x220821, 0x942230d0, 0x3c040001,
+-0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004,
+-0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075,
+-0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021,
+-0x3c030001, 0x621821, 0x946334d0, 0x710c0,
+-0x2e21021, 0x3c010001, 0x220821, 0xa42334d0,
+-0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001,
+-0x621821, 0x946334d0, 0x810c0, 0x2e21021,
+-0x3c010001, 0x220821, 0xa42330d0, 0x3c040001,
+-0x348430d0, 0x8f430100, 0x610c0, 0x2e21021,
+-0x3c010001, 0x220821, 0xa42334d0, 0x8f420104,
+-0x2e43821, 0x2821, 0x18400029, 0xaf460100,
+-0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009,
+-0x2021, 0x94c3fffe, 0x96020002, 0x14620006,
+-0x801021, 0x94c20000, 0x96030004, 0x431026,
+-0x2c440001, 0x801021, 0x50400014, 0x24a50001,
+-0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b,
+-0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe,
+-0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff,
+-0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104,
+-0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104,
+-0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008,
+-0x810c0, 0x2e21021, 0x3c010001, 0x220821,
+-0x942230d0, 0x14400023, 0x3c020800, 0x3c020002,
+-0x2c21024, 0x10400012, 0x82142, 0x3c030001,
+-0x346338d8, 0x24020003, 0x441023, 0x21080,
+-0x572021, 0x832021, 0x571021, 0x431021,
+-0x3105001f, 0x24030001, 0x8c420000, 0xa31804,
+-0x31827, 0x431024, 0x1000000d, 0xac820000,
+-0x24020003, 0x441023, 0x21080, 0x5c2821,
+-0x5c1021, 0x3104001f, 0x24030001, 0x8c420228,
+-0x831804, 0x31827, 0x431024, 0xaca20228,
+-0x3c020800, 0x34422000, 0x1821, 0xafa20020,
+-0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002,
+-0xafab0034, 0x27c30001, 0x8c020228, 0x609021,
+-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+-0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010,
+-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+-0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c,
+-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+-0x24070008, 0xa32821, 0xa3482b, 0x822021,
+-0x100f809, 0x892021, 0x54400006, 0x24130001,
+-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+-0x0, 0x326200ff, 0x54400017, 0xaf520018,
+-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+-0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124,
+-0x3c040001, 0x24846368, 0x3c050009, 0xafa20014,
+-0x8d660000, 0x10000033, 0x34a50600, 0x8f420308,
+-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+-0x326200ff, 0x14400011, 0x0, 0x8f420378,
+-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+-0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001,
+-0x24846370, 0x3c050009, 0xafa20014, 0x8d660000,
+-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8,
+-0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4,
+-0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058,
+-0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
+-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
+-0x0, 0x0, 0x0, 0x27bdffe0,
+-0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000,
+-0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8,
+-0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100,
+-0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114,
+-0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128,
+-0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec,
+-0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4,
+-0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021,
+-0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c,
+-0x3c040001, 0x24846470, 0x3c050001, 0x34420001,
+-0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
+-0x34a50100, 0xc002b3b, 0x3821, 0x8c020218,
+-0x30420040, 0x10400014, 0x0, 0x8f82011c,
+-0x3c040001, 0x2484647c, 0x3c050001, 0x34420004,
+-0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
+-0x10000007, 0x34a50200, 0x3c040001, 0x24846484,
+-0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300,
+-0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014,
+-0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002,
+-0x24680020, 0x27684800, 0x8f820128, 0x11020004,
+-0x0, 0x8f820124, 0x15020007, 0x0,
+-0x8f430334, 0x1021, 0x24630001, 0xaf430334,
+-0x10000039, 0x8f430334, 0xac640000, 0xac650004,
+-0xac660008, 0xa467000e, 0xac690018, 0xac6a001c,
+-0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc,
+-0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000,
+-0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f,
+-0x10400018, 0x3c020001, 0x8c830004, 0x2c620010,
+-0x10400013, 0x3c020001, 0x24630001, 0xac830004,
+-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+-0x14440015, 0x24020001, 0x8f820128, 0x24420020,
+-0xaf820128, 0x8f820128, 0x1000000f, 0x24020001,
+-0x3c020001, 0x344230c8, 0x2e21021, 0x54820004,
+-0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021,
+-0x402021, 0x24020001, 0xaf4400f4, 0xac890000,
+-0xac820004, 0x24020001, 0x3e00008, 0x0,
+-0x3e00008, 0x0, 0x8fa90010, 0x8f83010c,
+-0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0,
+-0x14620002, 0x24680020, 0x27684000, 0x8f820108,
+-0x11020004, 0x0, 0x8f820104, 0x15020007,
+-0x0, 0x8f430338, 0x1021, 0x24630001,
+-0xaf430338, 0x10000035, 0x8f430338, 0xac640000,
+-0xac650004, 0xac660008, 0xa467000e, 0xac690018,
+-0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100,
+-0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019,
+-0x31220006, 0x10400018, 0x3c020001, 0x8c830004,
+-0x2c620010, 0x10400013, 0x3c020001, 0x24630001,
+-0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021,
+-0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
+-0x2e21021, 0x14440015, 0x24020001, 0x8f820108,
+-0x24420020, 0xaf820108, 0x8f820108, 0x1000000f,
+-0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021,
+-0x54820004, 0x24820008, 0x3c020001, 0x34422cc0,
+-0x2e21021, 0x402021, 0x24020001, 0xaf4400ec,
+-0xac890000, 0xac820004, 0x24020001, 0x3e00008,
+-0x0, 0x3e00008, 0x0, 0x27bdffd8,
+-0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024,
+-0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104,
+-0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100,
+-0x2403021, 0x2203821, 0xafa20010, 0xc002b3b,
+-0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c,
+-0x3c040001, 0x24846498, 0xafa20014, 0x8e060000,
+-0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510,
+-0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001,
+-0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014,
+-0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00,
+-0x2221024, 0x3c030800, 0x54430016, 0x3c030200,
+-0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200,
+-0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030,
+-0x3021, 0x3821, 0x36420002, 0xaf82011c,
+-0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024,
+-0x0, 0x2c31024, 0x1040000d, 0x2231024,
+-0x1040000b, 0x36420002, 0xaf82011c, 0x36220001,
+-0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330,
+-0x24420001, 0xaf420330, 0x10000015, 0x8f420330,
+-0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010,
+-0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0,
+-0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002,
+-0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+-0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+-0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
+-0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001,
+-0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020,
+-0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0,
+-0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021,
+-0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014,
+-0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001,
+-0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004,
+-0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018,
+-0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500,
+-0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001,
+-0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024,
+-0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac,
+-0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001,
+-0x2484650c, 0x3c050001, 0x34a5f030, 0x3021,
+-0x3821, 0x36420002, 0xaf82011c, 0x36220001,
+-0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010,
+-0xc002b3b, 0xafa00014, 0x10000024, 0x0,
+-0x2c31024, 0x1040000d, 0x2231024, 0x1040000b,
+-0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
+-0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001,
+-0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001,
+-0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014,
+-0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b,
+-0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+-0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+-0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
+-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+-0x27bd0028, 0x6021, 0x5021, 0x3021,
+-0x2821, 0x6821, 0x4821, 0x7821,
+-0x7021, 0x8f880124, 0x8f870104, 0x1580002e,
+-0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120,
+-0x10460029, 0x0, 0x3c040001, 0x8c846ee4,
+-0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004,
+-0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e,
+-0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014,
+-0x10000012, 0x24c60020, 0x10400017, 0x0,
+-0x3c040001, 0x8c846ee4, 0x8d020000, 0x8d030004,
+-0xac820000, 0xac830004, 0x8d020008, 0xac820008,
+-0x9502000e, 0xa482000e, 0x8d020010, 0x25060020,
+-0xac820010, 0x8d020014, 0x240c0001, 0xc01821,
+-0xac820014, 0x27624fe0, 0x43102b, 0x54400001,
+-0x27634800, 0x603021, 0x1540002f, 0x31620100,
+-0x11200014, 0x31628000, 0x8f820100, 0x1045002a,
+-0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000,
+-0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008,
+-0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010,
+-0x240a0001, 0xac820010, 0x8ca20014, 0x10000012,
+-0x24a50020, 0x10400018, 0x31620100, 0x3c040001,
+-0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000,
+-0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e,
+-0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010,
+-0x8ce20014, 0x240a0001, 0xa01821, 0xac820014,
+-0x276247e0, 0x43102b, 0x54400001, 0x27634000,
+-0x602821, 0x31620100, 0x5440001d, 0x31621000,
+-0x11a00009, 0x31a20800, 0x10400004, 0x25020020,
+-0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124,
+-0x8f880124, 0x6821, 0x11800011, 0x31621000,
+-0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004,
+-0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4,
+-0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021,
+-0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000,
+-0x1440ff82, 0x0, 0x1120000f, 0x31220800,
+-0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000,
+-0x3c020002, 0x1221024, 0x10400004, 0x24e20020,
+-0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104,
+-0x8f870104, 0x4821, 0x1140ff70, 0x0,
+-0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004,
+-0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4,
+-0x9482000e, 0xaf82009c, 0x8c820010, 0x5021,
+-0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014,
+-0x3e00008, 0x0, 0x6021, 0x5821,
+-0x3021, 0x2821, 0x6821, 0x5021,
+-0x7821, 0x7021, 0x8f880124, 0x8f870104,
+-0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014,
+-0x31220800, 0x8f820120, 0x10460029, 0x0,
+-0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004,
+-0xac820000, 0xac830004, 0x8cc20008, 0xac820008,
+-0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001,
+-0xac820010, 0x8cc20014, 0x10000012, 0x24c60020,
+-0x10400017, 0x0, 0x3c040001, 0x8c846ee4,
+-0x8d020000, 0x8d030004, 0xac820000, 0xac830004,
+-0x8d020008, 0xac820008, 0x9502000e, 0xa482000e,
+-0x8d020010, 0x25060020, 0xac820010, 0x8d020014,
+-0x240c0001, 0xc01821, 0xac820014, 0x27624fe0,
+-0x43102b, 0x54400001, 0x27634800, 0x603021,
+-0x1560002f, 0x31220100, 0x11400014, 0x31228000,
+-0x8f820100, 0x1045002a, 0x31220100, 0x3c040001,
+-0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000,
+-0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e,
+-0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010,
+-0x8ca20014, 0x10000012, 0x24a50020, 0x10400018,
+-0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000,
+-0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008,
+-0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010,
+-0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001,
+-0xa01821, 0xac820014, 0x276247e0, 0x43102b,
+-0x54400001, 0x27634000, 0x602821, 0x31220100,
+-0x5440001d, 0x31221000, 0x11a00009, 0x31a20800,
+-0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000,
+-0x25020020, 0xaf820124, 0x8f880124, 0x6821,
+-0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4,
+-0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084,
+-0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac,
+-0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010,
+-0x8c8f0014, 0x31221000, 0x14400022, 0x0,
+-0x1140000f, 0x31420800, 0x10400004, 0x3c020002,
+-0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024,
+-0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4,
+-0x24e20020, 0xaf820104, 0x8f870104, 0x5021,
+-0x11600010, 0x0, 0x3c040001, 0x8c846ee0,
+-0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
+-0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c,
+-0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010,
+-0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024,
+-0x1040ff5c, 0x0, 0x8f820054, 0x24420005,
+-0xaf820078, 0x8c040234, 0x10800016, 0x1821,
+-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
+-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
+-0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
+-0x24020001, 0x3c030080, 0x3c010001, 0x370821,
+-0xac2040e8, 0x3c010001, 0x370821, 0x1000000c,
+-0xa02240f0, 0x3c020001, 0x571021, 0x904240f0,
+-0x14400006, 0x3c020080, 0x3c020001, 0x571021,
+-0x904240f1, 0x10400002, 0x3c020080, 0x621825,
+-0x8c040230, 0x10800013, 0x0, 0x3c020001,
+-0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
+-0x370821, 0xac2240ec, 0x3c020001, 0x571021,
+-0x8c4240ec, 0x44102b, 0x14400006, 0x0,
+-0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
+-0x781825, 0x3c020001, 0x571021, 0x904240f2,
+-0x54400001, 0x781825, 0x1060ff1a, 0x0,
+-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x431025, 0xaf820060,
+-0x8f420000, 0x10400003, 0x0, 0x1000ff05,
+-0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008,
+-0x0, 0x0, 0x0, 0x3c020001,
+-0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012,
+-0xafb00010, 0x3c100001, 0x26106f90, 0x2002021,
+-0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001,
+-0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250,
+-0x24022000, 0xac100254, 0xac020258, 0x24020001,
+-0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010,
+-0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec,
+-0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
+-0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
+-0xad260010, 0xad270014, 0xad230018, 0xad28001c,
+-0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90,
+-0x122102b, 0x10400003, 0x0, 0x3c090001,
+-0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000,
+-0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec,
+-0xad220004, 0xac090250, 0x3e00008, 0x0,
+-0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec,
+-0x3c020001, 0x8c426d10, 0xafb10014, 0x808821,
+-0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
+-0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
+-0xae020000, 0x3c020001, 0x8c426d10, 0xc09821,
+-0xe0a821, 0x10800006, 0xae020004, 0x26050008,
+-0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0,
+-0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0,
+-0x3c030001, 0x24636f90, 0x203102b, 0x10400003,
+-0x0, 0x3c100001, 0x8e106ee8, 0x8e220000,
+-0xae020000, 0x8e220004, 0xae120008, 0xae020004,
+-0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
+-0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
+-0x203102b, 0x10400003, 0x0, 0x3c100001,
+-0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000,
+-0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec,
+-0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
+-0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+-0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
+-0x83102b, 0x10400006, 0x0, 0xac800000,
+-0x24840004, 0x83102b, 0x5440fffd, 0xac800000,
+-0x3e00008, 0x0, 0xa61821, 0xa3102b,
+-0x10400007, 0x0, 0x8c820000, 0xaca20000,
+-0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004,
+-0x3e00008, 0x0, 0x861821, 0x83102b,
+-0x10400007, 0x0, 0x8ca20000, 0xac820000,
+-0x24840004, 0x83102b, 0x1440fffb, 0x24a50004,
+-0x3e00008, 0x0, 0x63080, 0x861821,
+-0x83102b, 0x10400006, 0x0, 0xac850000,
+-0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
+-0x3e00008, 0x0, 0x0, 0x26e50028,
+-0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c,
+-0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204,
+-0x8f4c0200, 0x24640400, 0x64102b, 0x10400008,
+-0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004,
+-0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff,
+-0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c,
+-0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204,
+-0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200,
+-0x821024, 0x34420004, 0xc31824, 0x34630004,
+-0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084,
+-0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c,
+-0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094,
+-0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c,
+-0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4,
+-0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac,
+-0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4,
+-0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc,
+-0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0,
+-0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0,
+-0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4,
+-0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec,
+-0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c,
+-0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4,
+-0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8,
+-0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff,
+-0x3463fffb, 0x431024, 0xaf820220, 0x30c20004,
+-0x14400006, 0x0, 0x8f820200, 0x3c03c0ff,
+-0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc,
+-0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc,
+-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+-0xafb00020, 0x8f430024, 0x8f420020, 0x10620038,
+-0x0, 0x8f430020, 0x8f420024, 0x622023,
+-0x4810003, 0x0, 0x8f420040, 0x822021,
+-0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
+-0x0, 0x8f430040, 0x8f420024, 0x10000005,
+-0x621023, 0x8f420030, 0x8f430024, 0x431023,
+-0x2442ffff, 0x406021, 0x8c102a, 0x54400001,
+-0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024,
+-0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c,
+-0x24070001, 0xafa70010, 0x84100, 0x1001821,
+-0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014,
+-0x8f470014, 0x1021, 0x63100, 0xafa70018,
+-0xa32821, 0xa3382b, 0x822021, 0x872021,
+-0x8f420108, 0x1663021, 0x40f809, 0xc3900,
+-0x54400001, 0xaf500024, 0x8f430024, 0x8f420020,
+-0x14620018, 0x0, 0x8f420000, 0x10400007,
+-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+-0x0, 0x10000005, 0x0, 0xaf800048,
+-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+-0x2403ffef, 0x431024, 0xaf820060, 0x8f420000,
+-0x10400003, 0x0, 0x10000002, 0xaf80004c,
+-0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008,
+-0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0,
+-0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
+-0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
+-0x10000002, 0x0, 0x8f530020, 0x8f420030,
+-0x105300eb, 0x21100, 0x8f43001c, 0x628021,
+-0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
+-0x9611000a, 0x3246ffff, 0x46102a, 0x10400017,
+-0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+-0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf,
+-0x10400005, 0x0, 0x8f420090, 0x8f430144,
+-0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+-0x10400006, 0x0, 0x8f420348, 0x24420001,
+-0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc,
+-0x14400006, 0x0, 0x8f420344, 0x24420001,
+-0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2,
+-0x1040000b, 0x32c20008, 0x10400008, 0x32220200,
+-0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
+-0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac,
+-0x32220004, 0x1040007f, 0x32220800, 0x10400003,
+-0x3247ffff, 0x10000002, 0x24020020, 0x24020004,
+-0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
+-0x3c030002, 0x431025, 0xafa20018, 0x8f460098,
+-0x8f420108, 0x40f809, 0x0, 0x104000b7,
+-0x0, 0x8f42009c, 0x8f430094, 0x2421021,
+-0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008,
+-0x3c034000, 0x8f420094, 0x431025, 0xafa20020,
+-0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025,
+-0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024,
+-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
+-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
+-0x8f440270, 0x8f450274, 0x401821, 0x1021,
+-0xa32821, 0xa3302b, 0x822021, 0x862021,
+-0x32230060, 0x24020040, 0xaf440270, 0xaf450274,
+-0x10620017, 0x2c620041, 0x10400005, 0x24020020,
+-0x10620008, 0x24020001, 0x10000026, 0x0,
+-0x24020060, 0x10620019, 0x24020001, 0x10000021,
+-0x0, 0x8f420278, 0x8f43027c, 0x24630001,
+-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+-0x8f420278, 0x8f43027c, 0x10000016, 0x24020001,
+-0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
+-0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
+-0x8f430284, 0x1000000b, 0x24020001, 0x8f420288,
+-0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
+-0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c,
+-0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff,
+-0x2406fff8, 0x8f45013c, 0x441021, 0x24420007,
+-0x461024, 0x24840007, 0xaf420094, 0x8f420090,
+-0x8f430094, 0x862024, 0x441023, 0x65182b,
+-0x14600005, 0xaf420090, 0x8f420094, 0x8f430144,
+-0x431023, 0xaf420094, 0x8f420094, 0x10000023,
+-0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020,
+-0x14400002, 0x24020010, 0x24020002, 0xafa20010,
+-0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018,
+-0x8f460098, 0x8f420108, 0x40f809, 0x0,
+-0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090,
+-0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c,
+-0x8f440098, 0xa34005c2, 0x651823, 0xaf430090,
+-0x451021, 0x86202b, 0x14800005, 0xaf42009c,
+-0x8f420098, 0x8f430144, 0x431023, 0xaf420098,
+-0x32c20020, 0x10400005, 0x0, 0x8f420358,
+-0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030,
+-0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+-0xaf420030, 0x8f420030, 0x14530018, 0x0,
+-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x2403fff7, 0x431024,
+-0xaf820060, 0x8f420000, 0x10400003, 0x0,
+-0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038,
+-0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+-0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
+-0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
+-0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
+-0x10000002, 0x0, 0x8f520020, 0x8f420030,
+-0x105200b5, 0x21100, 0x8f43001c, 0x628021,
+-0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
+-0x9607000a, 0x3226ffff, 0x46102a, 0x10400017,
+-0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+-0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47,
+-0x10400005, 0x0, 0x8f420090, 0x8f430144,
+-0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+-0x10400006, 0x0, 0x8f420348, 0x24420001,
+-0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc,
+-0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8,
+-0x431024, 0x461023, 0x218c3, 0x58600001,
+-0x24630100, 0x8f42008c, 0x43102b, 0x14400006,
+-0x712c2, 0x8f420344, 0x24420001, 0xaf420344,
+-0x10000098, 0x8f420344, 0x934305c2, 0x1060000f,
+-0x30460001, 0x8f420010, 0x34480400, 0x32c20008,
+-0x10400008, 0x30e20200, 0x10400006, 0x3c034000,
+-0x9602000e, 0xaf4300ac, 0x21400, 0x10000004,
+-0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010,
+-0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac,
+-0x11200005, 0x30c200ff, 0x14400006, 0x24020040,
+-0x10000004, 0x24020008, 0x14400002, 0x24020020,
+-0x24020004, 0xafa20010, 0x8f430030, 0x11200004,
+-0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014,
+-0x3c020002, 0x1021025, 0xafa20018, 0x8f460098,
+-0x8f420108, 0x40f809, 0x0, 0x10400069,
+-0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001,
+-0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2,
+-0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021,
+-0x24420007, 0x461024, 0x24840007, 0xaf420094,
+-0x8f420090, 0x8f430094, 0x862024, 0x441023,
+-0x65182b, 0x14600005, 0xaf420090, 0x8f420094,
+-0x8f430144, 0x431023, 0xaf420094, 0x8f430094,
+-0x8f420140, 0x43102b, 0x10400009, 0x0,
+-0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138,
+-0x641823, 0x431023, 0xaf420090, 0xaf450094,
+-0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d,
+-0x30c200ff, 0x14400002, 0x24020010, 0x24020002,
+-0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014,
+-0x8f460098, 0x8f420108, 0x40f809, 0x0,
+-0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c,
+-0x451021, 0xaf420098, 0x8f420090, 0x8f430098,
+-0xa34005c2, 0x451023, 0x64182b, 0x14600005,
+-0xaf420090, 0x8f420098, 0x8f430144, 0x431023,
+-0xaf420098, 0x8f420030, 0x8f430040, 0x24420001,
+-0x2463ffff, 0x431024, 0xaf420030, 0x8f420030,
+-0x14520018, 0x0, 0x8f420000, 0x10400007,
+-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+-0x0, 0x10000005, 0x0, 0xaf800048,
+-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+-0x2403fff7, 0x431024, 0xaf820060, 0x8f420000,
+-0x10400003, 0x0, 0x10000002, 0xaf80004c,
+-0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024,
+-0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
+-0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0,
+-0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021,
+-0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
+-0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
+-0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001,
+-0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0,
+-0x34422ec0, 0x2e21021, 0x54620004, 0x24620008,
+-0x3c020001, 0x34422cc0, 0x2e21021, 0x401821,
+-0x8c620004, 0x21140, 0x821021, 0xaf820108,
+-0xac600000, 0x8c850018, 0x30a20036, 0x1040006c,
+-0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034,
+-0x24420001, 0x2463ffff, 0x431024, 0x862021,
+-0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034,
+-0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4,
+-0x0, 0x32c20010, 0x10400028, 0x24070008,
+-0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+-0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
+-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+-0x14400011, 0x24020001, 0x3c010001, 0x370821,
+-0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
+-0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c,
+-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100,
+-0x10000036, 0x0, 0x8f420300, 0x8f43002c,
+-0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
+-0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170,
+-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+-0x24020020, 0xafa20010, 0xafa30014, 0xafa80018,
+-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+-0x24020001, 0x3c010001, 0x370821, 0xa02240f0,
+-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+-0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120,
+-0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f,
+-0x0, 0x8f420300, 0x24420001, 0xaf420300,
+-0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038,
+-0x3c010001, 0x370821, 0xa02040f1, 0x3c010001,
+-0x370821, 0xa02040f0, 0xaf400034, 0x8f420314,
+-0x24420001, 0xaf420314, 0x10000059, 0x8f420314,
+-0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028,
+-0xa22023, 0x4810003, 0x0, 0x8f420040,
+-0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
+-0x441021, 0x10600007, 0xaf420358, 0xaf80004c,
+-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+-0x0, 0x8f820060, 0x34420008, 0xaf820060,
+-0x8f420000, 0x10400003, 0x0, 0x10000038,
+-0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f,
+-0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c,
+-0x8f420050, 0x622023, 0x4820001, 0x24840200,
+-0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368,
+-0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000,
+-0x8c83001c, 0x8f420070, 0x622023, 0x4820001,
+-0x24840400, 0x8f420364, 0x441021, 0xaf420364,
+-0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e,
+-0x3c020800, 0x8c83001c, 0x8f420060, 0x622023,
+-0x4820001, 0x24840100, 0x8f420360, 0x441021,
+-0xaf420360, 0x8f420368, 0xaf430060, 0x441021,
+-0xaf420368, 0x3c020800, 0x2c21024, 0x50400008,
+-0x36940040, 0x10000006, 0x0, 0x30a20100,
+-0x10400003, 0x0, 0xc002bd8, 0x0,
+-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
+-0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c,
+-0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c,
+-0xafb00038, 0x8f910108, 0x26220020, 0xaf820108,
+-0x8e320018, 0xa821, 0x32420024, 0x104001ba,
+-0xf021, 0x8e26001c, 0x8f43001c, 0x61100,
+-0x621821, 0x8c70000c, 0x9604000c, 0x962d0016,
+-0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001,
+-0x621825, 0x10600015, 0x2821, 0x32c20040,
+-0x10400015, 0x24020800, 0x96030014, 0x14620012,
+-0x3402aaaa, 0x9603000e, 0x14620007, 0x2021,
+-0x96030010, 0x24020300, 0x14620004, 0x801021,
+-0x96020012, 0x2c440001, 0x801021, 0x54400006,
+-0x24050016, 0x10000004, 0x0, 0x24020800,
+-0x50820001, 0x2405000e, 0x934205c3, 0x14400008,
+-0x5821, 0x240b0001, 0x32620180, 0xaf4500a8,
+-0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3,
+-0x10a00085, 0x2054021, 0x91020000, 0x3821,
+-0x3042000f, 0x25080, 0x32c20002, 0x10400012,
+-0x10a1821, 0x32620002, 0x10400010, 0x32c20001,
+-0x1002021, 0x94820000, 0x24840002, 0xe23821,
+-0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02,
+-0x623821, 0x71c02, 0x30e2ffff, 0x623821,
+-0x71027, 0xa502000a, 0x32c20001, 0x1040006a,
+-0x32620001, 0x10400068, 0x0, 0x8f4200a8,
+-0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8,
+-0x431021, 0x904c0009, 0x318900ff, 0x39230006,
+-0x3182b, 0x39220011, 0x2102b, 0x621824,
+-0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001,
+-0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600,
+-0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e,
+-0x0, 0x32c20004, 0x14400013, 0x2821,
+-0x316200ff, 0x14400004, 0x0, 0x95020002,
+-0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e,
+-0x95030010, 0xa22821, 0xa32821, 0x95030012,
+-0x91040009, 0x95020002, 0xa32821, 0xa42821,
+-0x4a1023, 0xa22821, 0x2002021, 0x94820000,
+-0x24840002, 0xe23821, 0x88102b, 0x1440fffb,
+-0x71c02, 0x30e2ffff, 0x623821, 0x71c02,
+-0x30e2ffff, 0x623821, 0x1a52821, 0x51c02,
+-0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
+-0x622821, 0xa72823, 0x51402, 0xa22821,
+-0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff,
+-0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8,
+-0x624021, 0x91020000, 0x3042000f, 0x25080,
+-0x318300ff, 0x24020006, 0x14620003, 0x10a1021,
+-0x10000002, 0x24440010, 0x24440006, 0x316200ff,
+-0x14400006, 0x0, 0x94820000, 0xa22821,
+-0x51c02, 0x30a2ffff, 0x622821, 0x934205c3,
+-0x10400003, 0x32620100, 0x50400003, 0xa4850000,
+-0x52827, 0xa4850000, 0x9622000e, 0x8f43009c,
+-0x621821, 0x32a200ff, 0x10400007, 0xaf43009c,
+-0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c,
+-0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c,
+-0xafa20024, 0x32620080, 0x10400010, 0x32620100,
+-0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
+-0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
+-0x220821, 0xac2338e8, 0x3c010001, 0x220821,
+-0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064,
+-0x0, 0x8f4200b4, 0x24430001, 0x210c0,
+-0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024,
+-0x3c010001, 0x220821, 0xac2338e8, 0x3c010001,
+-0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051,
+-0x3821, 0x3c090001, 0x352938e8, 0x3c08001f,
+-0x3508ffff, 0x240bffff, 0x340affff, 0x710c0,
+-0x571021, 0x491021, 0x8c430000, 0x8c440004,
+-0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028,
+-0x8fa4002c, 0xac430000, 0xac440004, 0x24420008,
+-0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c,
+-0x97a2002e, 0x8f440270, 0x8f450274, 0x401821,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaf440270, 0xaf450274, 0x8fa20028,
+-0x481024, 0x90430000, 0x30630001, 0x1460000b,
+-0x402021, 0x8f420278, 0x8f43027c, 0x24630001,
+-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+-0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000,
+-0x144b000e, 0x0, 0x94820004, 0x144a000b,
+-0x0, 0x8f420288, 0x8f43028c, 0x24630001,
+-0x2c640001, 0x441021, 0xaf420288, 0xaf43028c,
+-0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280,
+-0x8f430284, 0x24630001, 0x2c640001, 0x441021,
+-0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
+-0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8,
+-0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4,
+-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
+-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
+-0x8f46008c, 0x8f440270, 0x8f450274, 0x401821,
+-0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821,
+-0xa3302b, 0x822021, 0x862021, 0xaf440270,
+-0xaf450274, 0x92020000, 0x30420001, 0x1440000c,
+-0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001,
+-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+-0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020,
+-0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004,
+-0x1462000c, 0x0, 0x8f420288, 0x8f43028c,
+-0x24630001, 0x2c640001, 0x441021, 0xaf420288,
+-0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b,
+-0x32c20020, 0x8f420280, 0x8f430284, 0x24630001,
+-0x2c640001, 0x441021, 0xaf420280, 0xaf430284,
+-0x8f420280, 0x8f430284, 0x32c20020, 0x10400005,
+-0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358,
+-0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001,
+-0x2463ffff, 0x431024, 0xaf42002c, 0x32420060,
+-0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
+-0xaf420034, 0x8c03023c, 0x43102b, 0x14400102,
+-0x32c20010, 0x10400018, 0x24070008, 0x8f440170,
+-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+-0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047,
+-0x24020001, 0x8f420300, 0x8f43002c, 0x24420001,
+-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+-0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174,
+-0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
+-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+-0x40f809, 0x24c6001c, 0x10400057, 0x24020001,
+-0x10000065, 0x0, 0x32420012, 0x10400075,
+-0x32420001, 0x9622000e, 0x8f43009c, 0x621821,
+-0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358,
+-0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c,
+-0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+-0xaf42002c, 0x32420010, 0x14400008, 0x32c20010,
+-0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
+-0x43102b, 0x144000bc, 0x32c20010, 0x10400028,
+-0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
+-0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
+-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
+-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
+-0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
+-0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014,
+-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
+-0x34a51100, 0x10000036, 0x0, 0x8f420300,
+-0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
+-0x24020001, 0xa34205c1, 0x10000026, 0xaf430038,
+-0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+-0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
+-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+-0x14400011, 0x24020001, 0x3c010001, 0x370821,
+-0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
+-0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c,
+-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900,
+-0x1000000f, 0x0, 0x8f420300, 0x24420001,
+-0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1,
+-0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
+-0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
+-0x8f420314, 0x24420001, 0xaf420314, 0x10000062,
+-0x8f420314, 0x10400022, 0x32427000, 0x8e25001c,
+-0x8f420028, 0xa22023, 0x4810003, 0x0,
+-0x8f420040, 0x822021, 0x8f420358, 0x8f430000,
+-0xaf450028, 0x441021, 0x10600007, 0xaf420358,
+-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+-0x10000005, 0x0, 0xaf800048, 0x8f820048,
+-0x1040fffd, 0x0, 0x8f820060, 0x34420008,
+-0xaf820060, 0x8f420000, 0x10400003, 0x0,
+-0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048,
+-0x1040002f, 0x32421000, 0x1040000c, 0x32424000,
+-0x8e23001c, 0x8f420050, 0x622023, 0x4820001,
+-0x24840200, 0x8f42035c, 0x441021, 0xaf42035c,
+-0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c,
+-0x32c28000, 0x8e23001c, 0x8f420070, 0x622023,
+-0x4820001, 0x24840400, 0x8f420364, 0x441021,
+-0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070,
+-0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060,
+-0x622023, 0x4820001, 0x24840100, 0x8f420360,
+-0x441021, 0xaf420360, 0x8f420368, 0xaf430060,
+-0x441021, 0xaf420368, 0x3c020800, 0x2c21024,
+-0x50400011, 0x36940040, 0x1000000f, 0x0,
+-0x32420048, 0x10400007, 0x24150001, 0x8e22001c,
+-0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75,
+-0xae22001c, 0x32420100, 0x10400003, 0x0,
+-0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c,
+-0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c,
+-0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008,
+-0x0, 0x0, 0x0, 0x8f8300e4,
+-0x8f8200e0, 0x2404fff8, 0x441024, 0x621026,
+-0x2102b, 0x21023, 0x3e00008, 0x621024,
+-0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
+-0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4,
+-0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8,
+-0x14a20002, 0x24a20008, 0x27623000, 0x408021,
+-0x16030005, 0x30820004, 0x10400004, 0xc02021,
+-0x10000022, 0x1021, 0x8e040000, 0x8f42011c,
+-0x14a20003, 0x0, 0x8f420120, 0xaf420114,
+-0x8ca30000, 0x8f420148, 0x831823, 0x43102b,
+-0x10400003, 0x0, 0x8f420148, 0x621821,
+-0x94a20006, 0x24420050, 0x62102b, 0x1440000f,
+-0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000,
+-0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894,
+-0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
+-0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c,
+-0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
+-0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8,
+-0x2402fff8, 0x823824, 0xe32023, 0x2c821000,
+-0x50400001, 0x24841000, 0x420c2, 0x801821,
+-0x8f440258, 0x8f45025c, 0x1021, 0xa32821,
+-0xa3302b, 0x822021, 0x862021, 0xaf440258,
+-0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023,
+-0x82102b, 0x14400004, 0x801821, 0x8f420148,
+-0x822021, 0x801821, 0x8f440250, 0x8f450254,
+-0x1021, 0xa32821, 0xa3302b, 0x822021,
+-0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8,
+-0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0,
+-0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4,
+-0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
+-0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c,
+-0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086,
+-0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c,
+-0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129,
+-0xafaa007c, 0x8f420114, 0x40f809, 0x0,
+-0x403021, 0x10c0034f, 0x0, 0x8cc20000,
+-0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024,
+-0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c,
+-0x3c020006, 0x2c21024, 0xafab007c, 0x14400015,
+-0xafaa0064, 0x91420000, 0x30420001, 0x10400011,
+-0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff,
+-0x95430004, 0x1062000b, 0x0, 0xc0024bb,
+-0x8fa40064, 0x304200ff, 0x14400006, 0x0,
+-0x8f420118, 0x40f809, 0x0, 0x1000032d,
+-0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
+-0x431024, 0x3c03ffff, 0x431824, 0x14600003,
+-0xafa20024, 0x10000040, 0x1821, 0x3c020080,
+-0x621024, 0x10400007, 0x0, 0x8f42038c,
+-0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
+-0x24030001, 0x8f420210, 0x24420001, 0xaf420210,
+-0x8f420210, 0x3c020001, 0x621024, 0x10400006,
+-0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
+-0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
+-0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
+-0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
+-0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
+-0x8f420380, 0x3c020008, 0x621024, 0x10400006,
+-0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
+-0x8f420384, 0x3c020010, 0x621024, 0x10400006,
+-0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
+-0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
+-0x24030001, 0x8f420388, 0x24420001, 0xaf420388,
+-0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c,
+-0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8,
+-0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c,
+-0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010,
+-0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
+-0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
+-0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080,
+-0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c,
+-0x3c020080, 0x34420100, 0x1621024, 0x10400005,
+-0x0, 0x8f42020c, 0x24420001, 0xaf42020c,
+-0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400,
+-0x10400015, 0x34028100, 0x8faa0064, 0x9543000c,
+-0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e,
+-0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
+-0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c,
+-0xa7a20086, 0xad63000c, 0xad640008, 0xad650004,
+-0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024,
+-0x10400004, 0x0, 0x8faa006c, 0x254a0004,
+-0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074,
+-0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074,
+-0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc,
+-0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b,
+-0x10400056, 0x32c28000, 0x1040005e, 0x240a0003,
+-0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058,
+-0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024,
+-0x24420001, 0xaf420350, 0x1000024f, 0x8f420350,
+-0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
+-0x3c040001, 0x248468d0, 0x26620001, 0xafa20014,
+-0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
+-0xc002b3b, 0x34a52250, 0x1000023f, 0x0,
+-0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
+-0x3c040001, 0x248468d0, 0x24020002, 0xafa20014,
+-0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
+-0xc002b3b, 0x34a52450, 0x1000022f, 0x0,
+-0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8,
+-0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800,
+-0xc002b3b, 0x603021, 0x10000223, 0x0,
+-0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0,
+-0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120,
+-0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216,
+-0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124,
+-0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010,
+-0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b,
+-0x34a53200, 0x10000208, 0x0, 0x8f420084,
+-0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001,
+-0x2c21024, 0x10400004, 0x0, 0x240b0002,
+-0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020,
+-0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c,
+-0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002,
+-0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054,
+-0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001,
+-0x304201ff, 0xafa20054, 0x1e1140, 0x431021,
+-0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c,
+-0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010,
+-0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b,
+-0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024,
+-0x24630001, 0xaf430350, 0x100001d3, 0x8f420350,
+-0x156a001d, 0x0, 0x8f430074, 0x8f420070,
+-0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c,
+-0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140,
+-0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044,
+-0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007,
+-0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070,
+-0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c,
+-0x1000ffc3, 0x0, 0x8f430064, 0x8f420060,
+-0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c,
+-0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054,
+-0x24020004, 0x1562000e, 0x1e1140, 0x1e1180,
+-0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a,
+-0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024,
+-0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097,
+-0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044,
+-0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014,
+-0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007,
+-0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024,
+-0x1440ff34, 0x0, 0x8f420370, 0x240a0001,
+-0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90,
+-0x8f420370, 0x27a30036, 0x131040, 0x621821,
+-0x94620000, 0x441021, 0x10000020, 0xa4620000,
+-0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072,
+-0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4,
+-0x25420020, 0xafa20028, 0x25420008, 0xafa20030,
+-0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a,
+-0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a,
+-0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018,
+-0x24630002, 0x822023, 0x1880ffde, 0x26730001,
+-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
+-0x26650001, 0xa2102a, 0x1440002b, 0x24030001,
+-0x8f83012c, 0x10600023, 0x0, 0x8f820124,
+-0x431023, 0x22143, 0x58800001, 0x24840040,
+-0x8f820128, 0x431023, 0x21943, 0x58600001,
+-0x24630040, 0x64102a, 0x54400001, 0x602021,
+-0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011,
+-0x24030001, 0x10000015, 0x306200ff, 0x8fab0064,
+-0x96070018, 0xafab0010, 0x8e220008, 0x3c040001,
+-0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400,
+-0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b,
+-0x0, 0x8f420334, 0x1821, 0x24420001,
+-0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc,
+-0x3c020800, 0x12600021, 0x9021, 0x8fb100a4,
+-0x2208021, 0x8e220008, 0x96070018, 0x8fa60064,
+-0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010,
+-0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
+-0x40f809, 0x0, 0x1040ffd8, 0x3c050007,
+-0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821,
+-0x14b102b, 0x10400004, 0xafab0064, 0x8f420148,
+-0x1625823, 0xafab0064, 0x26100002, 0x26520001,
+-0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c,
+-0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002,
+-0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
+-0x10600013, 0x0, 0x8f820124, 0x431023,
+-0x22143, 0x58800001, 0x24840040, 0x8f820128,
+-0x431023, 0x21943, 0x58600001, 0x24630040,
+-0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+-0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
+-0x8f420334, 0x1821, 0x24420001, 0xaf420334,
+-0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800,
+-0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b,
+-0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
+-0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008,
+-0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809,
+-0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e,
+-0x97aa008e, 0x11400007, 0x609021, 0x934205c4,
+-0x14400004, 0x0, 0x97ab0086, 0x6a1825,
+-0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024,
+-0x10400003, 0xa1402, 0x34630400, 0xa6a20014,
+-0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004,
+-0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a,
+-0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000,
+-0xafa20010, 0x8f420044, 0x2a03021, 0x24070020,
+-0xafa20014, 0x8f42000c, 0x31940, 0x604821,
+-0xafa20018, 0x8f42010c, 0x4021, 0xa92821,
+-0xa9182b, 0x882021, 0x40f809, 0x832021,
+-0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c,
+-0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c,
+-0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002,
+-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
+-0x8f42035c, 0x156a0006, 0x0, 0x8f420364,
+-0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364,
+-0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360,
+-0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044,
+-0x8f440088, 0x8f430078, 0x24420001, 0x441024,
+-0x24630001, 0xaf420044, 0xaf430078, 0x8c020240,
+-0x62182b, 0x14600075, 0x24070008, 0x8f440168,
+-0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120,
+-0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
+-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+-0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2,
+-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+-0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120,
+-0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b,
+-0x0, 0x8f420304, 0x24420001, 0xaf420304,
+-0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
+-0x370821, 0xa02040f2, 0xaf400078, 0x8f420318,
+-0x24420001, 0xaf420318, 0x10000048, 0x8f420318,
+-0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
+-0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
+-0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
+-0x604821, 0xafa20018, 0x8f42010c, 0x4021,
+-0xa92821, 0xa9182b, 0x882021, 0x40f809,
+-0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4,
+-0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c,
+-0x8fab009c, 0x1505021, 0x16a102b, 0x10400004,
+-0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064,
+-0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c,
+-0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002,
+-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
+-0x8f42035c, 0x114b0006, 0x0, 0x8f420360,
+-0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360,
+-0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364,
+-0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044,
+-0x8f440088, 0x8f430078, 0x24420001, 0x441024,
+-0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c,
+-0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e,
+-0x0, 0x934205c4, 0x10400009, 0x0,
+-0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c,
+-0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc,
+-0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020,
+-0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004,
+-0x8c450008, 0xa44a000e, 0xac440000, 0xac450004,
+-0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c,
+-0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff,
+-0x2484fffc, 0x801821, 0x8f440250, 0x8f450254,
+-0x8f460118, 0x1021, 0xa32821, 0xa3382b,
+-0x822021, 0x872021, 0xaf440250, 0xc0f809,
+-0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
+-0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
+-0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
+-0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc,
+-0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac,
+-0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c,
+-0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e,
+-0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4,
+-0x10000130, 0xafab006c, 0x8f420114, 0x40f809,
+-0x0, 0x403021, 0x10c002a1, 0x0,
+-0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024,
+-0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc,
+-0xafa20064, 0x3c020006, 0x2c21024, 0x14400015,
+-0xafac006c, 0x93c20000, 0x30420001, 0x10400011,
+-0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff,
+-0x97c30004, 0x1062000b, 0x0, 0xc0024bb,
+-0x3c02021, 0x304200ff, 0x14400006, 0x0,
+-0x8f420118, 0x40f809, 0x0, 0x10000280,
+-0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
+-0x431024, 0x3c03ffff, 0x431824, 0x14600003,
+-0xafa20024, 0x10000040, 0x8021, 0x3c020080,
+-0x621024, 0x10400007, 0x0, 0x8f42038c,
+-0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
+-0x24100001, 0x8f420210, 0x24420001, 0xaf420210,
+-0x8f420210, 0x3c020001, 0x621024, 0x10400006,
+-0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
+-0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
+-0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
+-0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
+-0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
+-0x8f420380, 0x3c020008, 0x621024, 0x10400006,
+-0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
+-0x8f420384, 0x3c020010, 0x621024, 0x10400006,
+-0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
+-0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
+-0x24100001, 0x8f420388, 0x24420001, 0xaf420388,
+-0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064,
+-0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8,
+-0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c,
+-0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010,
+-0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
+-0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
+-0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010,
+-0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400,
+-0x8fab006c, 0x3c020080, 0x34420100, 0x1621024,
+-0x10400005, 0x0, 0x8f42020c, 0x24420001,
+-0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064,
+-0x32c20400, 0x10400012, 0x34028100, 0x97c3000c,
+-0x1462000f, 0x0, 0x240c0200, 0xa7ac0076,
+-0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064,
+-0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e,
+-0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004,
+-0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100,
+-0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001,
+-0x621825, 0x10600015, 0x2821, 0x32c20800,
+-0x10400015, 0x24020800, 0x97c30014, 0x14620012,
+-0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021,
+-0x97c30010, 0x24020300, 0x14620004, 0x801021,
+-0x97c20012, 0x2c440001, 0x801021, 0x54400006,
+-0x24050016, 0x10000004, 0x0, 0x24020800,
+-0x50820001, 0x2405000e, 0x10a00013, 0x3c52021,
+-0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b,
+-0x10400003, 0x0, 0x8f420148, 0x621823,
+-0x90620000, 0x38430006, 0x2c630001, 0x38420011,
+-0x2c420001, 0x621825, 0x10600004, 0x3c020100,
+-0x94820002, 0x453821, 0x3c020100, 0x2c21024,
+-0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008,
+-0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064,
+-0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014,
+-0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080,
+-0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000,
+-0x10400034, 0x240b0003, 0x32c21000, 0x10400031,
+-0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350,
+-0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350,
+-0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025,
+-0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001,
+-0x248468d0, 0x26620001, 0xafa20014, 0xafa30010,
+-0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b,
+-0x34a55300, 0x10000162, 0x0, 0x8ea20000,
+-0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010,
+-0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b,
+-0x603021, 0x10000156, 0x0, 0x8f420084,
+-0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001,
+-0x2c21024, 0x10400004, 0x0, 0x240c0002,
+-0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020,
+-0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021,
+-0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b,
+-0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c,
+-0x26220001, 0x304201ff, 0xafa20054, 0x111140,
+-0x431021, 0x1000006b, 0x2e2a821, 0x8f420044,
+-0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014,
+-0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
+-0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf,
+-0x282a024, 0x24630001, 0xaf430350, 0x10000124,
+-0x8f420350, 0x156c001d, 0x0, 0x8f430074,
+-0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074,
+-0xafab004c, 0x26220001, 0x304203ff, 0xafa20054,
+-0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821,
+-0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8,
+-0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074,
+-0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b,
+-0xafab005c, 0x1000ffc3, 0x0, 0x8f430064,
+-0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064,
+-0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff,
+-0xafa20054, 0x24020004, 0x1562000e, 0x111140,
+-0x111180, 0x24420cc0, 0x2e21021, 0xafa20044,
+-0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b,
+-0x10400024, 0x25950020, 0x240c0001, 0x10000021,
+-0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821,
+-0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4,
+-0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060,
+-0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008,
+-0x2c21024, 0x1440ff61, 0x0, 0x8f420370,
+-0x240c0001, 0xafac005c, 0x24420001, 0xaf420370,
+-0x1000ff90, 0x8f420370, 0x27a30036, 0x131040,
+-0x621821, 0x94620000, 0x441021, 0x1000001f,
+-0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084,
+-0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c,
+-0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
+-0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
+-0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
+-0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
+-0x24630002, 0x822023, 0x1880ffdf, 0x26730001,
+-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
+-0x262102a, 0x14400030, 0x24030001, 0x8f83012c,
+-0x10600028, 0x0, 0x8f820124, 0x431023,
+-0x22143, 0x58800001, 0x24840040, 0x8f820128,
+-0x431023, 0x21943, 0x58600001, 0x24630040,
+-0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+-0x8f4200fc, 0x262102a, 0x10400016, 0x24030001,
+-0x1000001a, 0x306200ff, 0x8fac008c, 0x101040,
+-0x4c1021, 0x94470018, 0x101080, 0x4c1021,
+-0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc,
+-0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500,
+-0x2003021, 0xc002b3b, 0xafa30014, 0x10000039,
+-0x0, 0x8f420334, 0x1821, 0x24420001,
+-0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06,
+-0x8021, 0x8f430008, 0x2402fbff, 0x1260002d,
+-0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c,
+-0x2669ffff, 0x2209021, 0x8e420008, 0x96270018,
+-0x8c440000, 0x8c450004, 0x56090004, 0x240b0001,
+-0x240c0002, 0x10000002, 0xafac0010, 0xafab0010,
+-0x16000004, 0xafa80014, 0x8f420008, 0x10000002,
+-0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021,
+-0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0,
+-0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2,
+-0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021,
+-0x5e102b, 0x10400003, 0x26310002, 0x8f420148,
+-0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda,
+-0x26520004, 0x8fb00064, 0x1000001a, 0x0,
+-0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001,
+-0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c,
+-0x240c0002, 0xafac0010, 0x934305c4, 0xb1700,
+-0x10600003, 0x2223025, 0x3c020800, 0xc23025,
+-0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c,
+-0x3c03021, 0x40f809, 0x2003821, 0x1040fecb,
+-0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e,
+-0x934205c4, 0x14400004, 0x0, 0x97ab007e,
+-0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff,
+-0x1821024, 0x10400003, 0xc1402, 0x34630400,
+-0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006,
+-0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e,
+-0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f,
+-0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064,
+-0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4,
+-0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c,
+-0xad8b0000, 0x8fac0064, 0x1580feba, 0x0,
+-0x8fab0064, 0x1160001b, 0x0, 0x934205c4,
+-0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0,
+-0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076,
+-0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c,
+-0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008,
+-0xa44c000e, 0xac440000, 0xac450004, 0xac460008,
+-0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010,
+-0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc,
+-0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
+-0x1021, 0xa32821, 0xa3382b, 0x822021,
+-0x872021, 0xaf440250, 0xc0f809, 0xaf450254,
+-0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4,
+-0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008,
+-0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8,
+-0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048,
+-0x10620034, 0x0, 0x8f430048, 0x8f42004c,
+-0x622023, 0x4820001, 0x24840200, 0x8f430054,
+-0x8f42004c, 0x43102b, 0x14400004, 0x24020200,
+-0x8f43004c, 0x10000005, 0x431023, 0x8f420054,
+-0x8f43004c, 0x431023, 0x2442ffff, 0x405021,
+-0x8a102a, 0x54400001, 0x805021, 0x8f49004c,
+-0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
+-0x24071000, 0xafa70010, 0x84140, 0x1001821,
+-0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014,
+-0x1021, 0x63140, 0xafa70018, 0xa32821,
+-0xa3382b, 0x822021, 0x872021, 0x3402ecc0,
+-0xc23021, 0x8f420108, 0x2e63021, 0x40f809,
+-0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c,
+-0x8f420048, 0x14620018, 0x0, 0x8f420000,
+-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+-0x1040fffd, 0x0, 0x10000005, 0x0,
+-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
+-0x8f420000, 0x10400003, 0x0, 0x10000002,
+-0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
+-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
+-0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c,
+-0x8f420058, 0x10620049, 0x0, 0x8f430058,
+-0x8f42005c, 0x622023, 0x4820001, 0x24840100,
+-0x8f430064, 0x8f42005c, 0x43102b, 0x14400004,
+-0x24020100, 0x8f43005c, 0x10000005, 0x431023,
+-0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff,
+-0x403821, 0x87102a, 0x54400001, 0x803821,
+-0x8f42005c, 0x471021, 0x305000ff, 0x32c21000,
+-0x10400015, 0x24082000, 0x8f49005c, 0x8f440190,
+-0x8f450194, 0x8f46005c, 0x73980, 0xafa80010,
+-0xafb00014, 0x8f480014, 0x94980, 0x1201821,
+-0x1021, 0xa32821, 0xa3482b, 0x822021,
+-0x892021, 0x63180, 0xafa80018, 0x8f420108,
+-0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190,
+-0x8f450194, 0x8f46005c, 0x73940, 0xafa80010,
+-0xafb00014, 0x8f480014, 0x94940, 0x1201821,
+-0x1021, 0xa32821, 0xa3482b, 0x822021,
+-0x892021, 0x63140, 0xafa80018, 0x8f420108,
+-0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001,
+-0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018,
+-0x0, 0x8f420000, 0x10400007, 0x0,
+-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+-0x10000005, 0x0, 0xaf800048, 0x8f820048,
+-0x1040fffd, 0x0, 0x8f820060, 0x2403feff,
+-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+-0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033,
+-0x0, 0x8f430068, 0x8f42006c, 0x622023,
+-0x4820001, 0x24840400, 0x8f430074, 0x8f42006c,
+-0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
+-0x10000005, 0x431023, 0x8f420074, 0x8f43006c,
+-0x431023, 0x2442ffff, 0x405021, 0x8a102a,
+-0x54400001, 0x805021, 0x8f49006c, 0x8f48006c,
+-0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000,
+-0xafa70010, 0x84140, 0x1001821, 0x12a4821,
+-0x313003ff, 0xafb00014, 0x8f470014, 0x1021,
+-0x63140, 0x24c66cc0, 0xafa70018, 0xa32821,
+-0xa3382b, 0x822021, 0x872021, 0x8f420108,
+-0x2e63021, 0x40f809, 0xa3940, 0x54400001,
+-0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018,
+-0x0, 0x8f420000, 0x10400007, 0x0,
+-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+-0x10000005, 0x0, 0xaf800048, 0x8f820048,
+-0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff,
+-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+-0x3e00008, 0x0, 0x8f4200fc, 0x3c030001,
+-0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc,
+-0x8f850128, 0x2e31021, 0x54820004, 0x24820008,
+-0x3c020001, 0x34422ec8, 0x2e21021, 0x401821,
+-0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004,
+-0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128,
+-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+-0x401821, 0x8c620004, 0x21140, 0xa21021,
+-0xaf820128, 0xac600000, 0x8ca30018, 0x30620070,
+-0x1040002d, 0x30620020, 0x10400004, 0x3c020010,
+-0x2c21024, 0x1040000d, 0x0, 0x30620040,
+-0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
+-0x0, 0x30620010, 0x1040001f, 0x3c020040,
+-0x2c21024, 0x1440001c, 0x0, 0x8f820040,
+-0x30420001, 0x14400008, 0x2021, 0x8c030104,
+-0x24020001, 0x50620005, 0x24040001, 0x8c020264,
+-0x10400003, 0x801021, 0x24040001, 0x801021,
+-0x10400006, 0x0, 0x8f42030c, 0x24420001,
+-0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044,
+-0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
+-0xaf420308, 0x8f420308, 0x3e00008, 0x0,
+-0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
+-0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
+-0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001,
+-0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128,
+-0x8d030018, 0x30620070, 0x1040002e, 0x30620020,
+-0x10400004, 0x3c020010, 0x2c21024, 0x1040000d,
+-0x0, 0x30620040, 0x10400004, 0x3c020020,
+-0x2c21024, 0x10400007, 0x0, 0x30620010,
+-0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6,
+-0x0, 0x8f820040, 0x30420001, 0x14400008,
+-0x2021, 0x8c030104, 0x24020001, 0x50620005,
+-0x24040001, 0x8c020264, 0x10400003, 0x801021,
+-0x24040001, 0x801021, 0x10400006, 0x0,
+-0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192,
+-0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
+-0x8f420308, 0x24420001, 0xaf420308, 0x1000018a,
+-0x8f420308, 0x30620002, 0x1040014b, 0x3c020800,
+-0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016,
+-0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001,
+-0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0,
+-0x431021, 0x10000010, 0x2e2a821, 0x24020002,
+-0x15420005, 0x24020003, 0x1e1140, 0x24426cc0,
+-0x10000009, 0x2e2a821, 0x15420005, 0x1e1180,
+-0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821,
+-0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc,
+-0x30420400, 0x10400003, 0xafaa002c, 0x100000e1,
+-0x8821, 0x10800004, 0x8821, 0x97b10026,
+-0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c,
+-0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870,
+-0x2c420001, 0x621825, 0x10600015, 0x2021,
+-0x32c20800, 0x10400015, 0x24020800, 0x96630014,
+-0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007,
+-0x2821, 0x96630010, 0x24020300, 0x14620004,
+-0xa01021, 0x96620012, 0x2c450001, 0xa01021,
+-0x54400006, 0x24040016, 0x10000004, 0x0,
+-0x24020800, 0x50a20001, 0x2404000e, 0x108000b9,
+-0x2649021, 0x92420000, 0x3042000f, 0x28080,
+-0x32c20100, 0x10400020, 0x2501821, 0x3c020020,
+-0x43102b, 0x1440000e, 0x2402021, 0x2821,
+-0x94820000, 0x24840002, 0xa22821, 0x83102b,
+-0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821,
+-0x51c02, 0x30a2ffff, 0x10000009, 0x622821,
+-0x8f470148, 0x8f420110, 0x102842, 0x3c060020,
+-0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040,
+-0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002,
+-0x10000002, 0xafaa002c, 0x2821, 0x32c20080,
+-0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f,
+-0x3442ffff, 0x43102b, 0x10400003, 0x0,
+-0x8f420148, 0x621823, 0x90660000, 0x30c200ff,
+-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+-0x621825, 0x1060007f, 0x24020800, 0x8821,
+-0x97a3003e, 0x1462000f, 0x2602021, 0x96710000,
+-0x96620002, 0x96630004, 0x96640006, 0x2228821,
+-0x2238821, 0x2248821, 0x96620008, 0x9663000a,
+-0x9664000c, 0x2228821, 0x2238821, 0x10000007,
+-0x2248821, 0x94820000, 0x24840002, 0x2228821,
+-0x92102b, 0x1440fffb, 0x0, 0x111c02,
+-0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
+-0x628821, 0x32c20200, 0x10400003, 0x26440006,
+-0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff,
+-0xa4102b, 0x10400003, 0x0, 0x8f420148,
+-0x822023, 0x94820000, 0x30421fff, 0x10400004,
+-0x2644000c, 0x96420002, 0x10000030, 0x508023,
+-0x96420002, 0x26430014, 0x508023, 0x3c020020,
+-0x43102b, 0x1440000a, 0xd08021, 0x9642000c,
+-0x2028021, 0x9642000e, 0x96430010, 0x96440012,
+-0x2028021, 0x2038021, 0x10000020, 0x2048021,
+-0xa4102b, 0x10400003, 0x0, 0x8f420148,
+-0x822023, 0x94820000, 0x24840002, 0x2028021,
+-0xa4102b, 0x10400003, 0x0, 0x8f420148,
+-0x822023, 0x94820000, 0x24840002, 0x2028021,
+-0xa4102b, 0x10400003, 0x0, 0x8f420148,
+-0x822023, 0x94820000, 0x24840002, 0x2028021,
+-0xa4102b, 0x10400003, 0x0, 0x8f420148,
+-0x822023, 0x94820000, 0x2028021, 0x3c020100,
+-0x2c21024, 0x1040000e, 0x0, 0x8faa002c,
+-0x31420004, 0x1040000a, 0x0, 0x9504000e,
+-0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff,
+-0x2228821, 0x111c02, 0x3222ffff, 0x628821,
+-0x8faa0024, 0x1518823, 0x111402, 0x2228821,
+-0x2308821, 0x111402, 0x2228821, 0x3231ffff,
+-0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001,
+-0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e,
+-0x8faa002c, 0x31420004, 0x10400002, 0x24091000,
+-0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4,
+-0xafa90010, 0x8f490044, 0x84140, 0x1001821,
+-0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020,
+-0xafa80018, 0x8f48010c, 0x1021, 0xa32821,
+-0xa3482b, 0x822021, 0x100f809, 0x892021,
+-0x1440000b, 0x0, 0x8f820128, 0x3c040001,
+-0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124,
+-0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920,
+-0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044,
+-0x8f430088, 0x24420001, 0x431024, 0xaf420044,
+-0x8faa0034, 0x8f440368, 0x24020001, 0x15420006,
+-0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
+-0x10000049, 0x8f42035c, 0x15420006, 0x0,
+-0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042,
+-0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
+-0x1000003d, 0x8f420360, 0x30621000, 0x10400005,
+-0x30628000, 0x8f420078, 0x24420001, 0x10000036,
+-0xaf420078, 0x10400034, 0x0, 0x8f420078,
+-0x24420001, 0xaf420078, 0x8c030240, 0x43102b,
+-0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c,
+-0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040,
+-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+-0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
+-0x3c010001, 0x370821, 0xa02240f2, 0x8f820124,
+-0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c,
+-0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009,
+-0xc002b3b, 0x34a51300, 0x1000000b, 0x0,
+-0x8f420304, 0x24420001, 0xaf420304, 0x8f420304,
+-0x8f420044, 0xaf42007c, 0x3c010001, 0x370821,
+-0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001,
+-0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c,
+-0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c,
+-0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008,
+-0x0, 0x0, 0x0, 0x8f42013c,
+-0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
+-0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
+-0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
+-0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
+-0xc002bbf, 0x24060008, 0x8c020204, 0xc004012,
+-0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002,
+-0x1040000e, 0x2021, 0x8c060248, 0x24020002,
+-0x3c010001, 0xac226d98, 0xc005104, 0x24050002,
+-0x2021, 0x8c060248, 0x24020001, 0x3c010001,
+-0xac226d98, 0x10000011, 0x24050001, 0x8c060248,
+-0x24020004, 0x3c010001, 0xac226d98, 0xc005104,
+-0x24050004, 0x3c020001, 0x8c426d94, 0x30420001,
+-0x10400008, 0x24020001, 0x3c010001, 0xac226d98,
+-0x2021, 0x24050001, 0x3c06601b, 0xc005104,
+-0x0, 0x3c040001, 0x248469d0, 0x8f420150,
+-0x8f430154, 0x3c050008, 0x8f460158, 0x21640,
+-0x31940, 0x34630403, 0x431025, 0x633c0,
+-0x461025, 0xaf82021c, 0xafa00010, 0xafa00014,
+-0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821,
+-0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8,
+-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
+-0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010,
+-0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc,
+-0xc002b3b, 0x3821, 0x8f420410, 0x24420001,
+-0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c,
+-0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4,
+-0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010,
+-0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8,
+-0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821,
+-0x3c044000, 0x2041024, 0x504000b4, 0x3c040100,
+-0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc,
+-0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823,
+-0x43102b, 0x10400003, 0x0, 0x8f420148,
+-0x621821, 0x10600005, 0x0, 0x8f42014c,
+-0x43102b, 0x1040000b, 0x0, 0x8f8200e0,
+-0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220,
+-0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce,
+-0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+-0x431024, 0x34420004, 0xaf820220, 0x8f8200e0,
+-0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8,
+-0x8f840120, 0x8f830124, 0x10000005, 0x2821,
+-0x14620002, 0x24620020, 0x27624800, 0x401821,
+-0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003,
+-0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001,
+-0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008,
+-0x30a200ff, 0x14400058, 0x0, 0x934205c4,
+-0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0,
+-0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023,
+-0x218c3, 0x4620001, 0x24630200, 0x10600005,
+-0x24020001, 0x10620009, 0x0, 0x1000001f,
+-0x0, 0x8f4203c0, 0xe03021, 0x24420001,
+-0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4,
+-0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
+-0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
+-0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
+-0x14400031, 0x0, 0x8f42020c, 0x24420001,
+-0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
+-0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8,
+-0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000,
+-0x8f420148, 0xa71823, 0x43102b, 0x10400003,
+-0x0, 0x8f420148, 0x621821, 0x8f42014c,
+-0x43102b, 0x5440000a, 0xa03021, 0x8f42020c,
+-0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008,
+-0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8,
+-0x1488000d, 0x27623000, 0x14820002, 0x2482fff8,
+-0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff,
+-0xc33021, 0x46102b, 0x10400003, 0x0,
+-0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4,
+-0x8f420148, 0xc31823, 0x43102b, 0x10400003,
+-0x0, 0x8f420148, 0x621821, 0x10600005,
+-0x0, 0x8f42014c, 0x43102b, 0x50400008,
+-0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb,
+-0x431024, 0x3c034000, 0x1000003f, 0x431025,
+-0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
+-0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024,
+-0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001,
+-0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff,
+-0x3463ffff, 0x431024, 0x441025, 0xc003daf,
+-0xaf820220, 0x10000029, 0x0, 0x2111024,
+-0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001,
+-0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019,
+-0x0, 0x2111024, 0x1040001c, 0x0,
+-0x8f830224, 0x24021402, 0x14620009, 0x3c050008,
+-0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014,
+-0x8f860224, 0x34a50500, 0xc002b3b, 0x3821,
+-0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0,
+-0x8f820220, 0x2002021, 0x34420002, 0xc004e9c,
+-0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+-0x431024, 0x511025, 0xaf820220, 0x8fbf0020,
+-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
+-0x3e00008, 0x0, 0x3c020001, 0x8c426da8,
+-0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
+-0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
+-0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008,
+-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
+-0x24020001, 0x3c010001, 0xac206da8, 0x3c010001,
+-0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff,
+-0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
+-0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
+-0x10400092, 0x284a024, 0x3c040600, 0x34842000,
+-0x8f420004, 0x2821, 0x2403fffd, 0x431024,
+-0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
+-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
+-0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
+-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+-0x8c020228, 0x3c040001, 0x24846998, 0x3c050009,
+-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
+-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
+-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
+-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
+-0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+-0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
+-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
+-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+-0xa3482b, 0x822021, 0x100f809, 0x892021,
+-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
+-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
+-0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+-0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4,
+-0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
+-0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+-0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
+-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+-0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
+-0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
+-0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
+-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+-0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
+-0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
+-0x326200ff, 0x14400011, 0x0, 0x8f420378,
+-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
+-0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000,
+-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec,
+-0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
+-0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
+-0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
+-0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d,
+-0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008,
+-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
+-0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b,
+-0x3821, 0x3c020004, 0x2c21024, 0x10400007,
+-0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+-0x431024, 0x34420008, 0xaf820220, 0x3c050001,
+-0x8ca56d98, 0x24020001, 0x14a20007, 0x2021,
+-0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c,
+-0x10000006, 0x3c020007, 0xc00529b, 0x2021,
+-0xac020268, 0x8c030268, 0x3c020007, 0x621824,
+-0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
+-0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
+-0x3c020098, 0x1000000b, 0x0, 0x14620009,
+-0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
+-0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
+-0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+-0x0, 0x0, 0x0, 0x86102b,
+-0x50400001, 0x872023, 0xc41023, 0x24843,
+-0x125102b, 0x1040001b, 0x91040, 0x824021,
+-0x88102b, 0x10400007, 0x1821, 0x94820000,
+-0x24840002, 0x621821, 0x88102b, 0x1440fffb,
+-0x0, 0x602021, 0xc73023, 0xa91023,
+-0x21040, 0xc22821, 0xc5102b, 0x10400007,
+-0x1821, 0x94c20000, 0x24c60002, 0x621821,
+-0xc5102b, 0x1440fffb, 0x0, 0x1000000d,
+-0x832021, 0x51040, 0x822821, 0x85102b,
+-0x10400007, 0x1821, 0x94820000, 0x24840002,
+-0x621821, 0x85102b, 0x1440fffb, 0x0,
+-0x602021, 0x41c02, 0x3082ffff, 0x622021,
+-0x41c02, 0x3082ffff, 0x622021, 0x3e00008,
+-0x3082ffff, 0x3e00008, 0x0, 0x802821,
+-0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff,
+-0x24a20004, 0x62102b, 0x54400007, 0x65102b,
+-0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002,
+-0x1000002a, 0x441021, 0x10400003, 0x0,
+-0x8f420148, 0xa22823, 0x90a40000, 0x24a50001,
+-0x65102b, 0x10400003, 0x0, 0x8f420148,
+-0xa22823, 0x90a20000, 0x24a50001, 0x21200,
+-0x822021, 0x65102b, 0x10400003, 0x0,
+-0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
+-0x822021, 0x65102b, 0x10400003, 0x0,
+-0x8f420148, 0xa22823, 0x90a20000, 0x1000002d,
+-0x21200, 0x3463ffff, 0x24a20004, 0x62102b,
+-0x5440000a, 0x65102b, 0x90a20000, 0x90a40002,
+-0x90a30001, 0x90a50003, 0x441021, 0x21200,
+-0x651821, 0x10000020, 0x432021, 0x10400003,
+-0x0, 0x8f420148, 0xa22823, 0x90a20000,
+-0x24a50001, 0x22200, 0x65102b, 0x10400003,
+-0x0, 0x8f420148, 0xa22823, 0x90a20000,
+-0x24a50001, 0x822021, 0x65102b, 0x10400003,
+-0x0, 0x8f420148, 0xa22823, 0x90a20000,
+-0x24a50001, 0x21200, 0x822021, 0x65102b,
+-0x10400003, 0x0, 0x8f420148, 0xa22823,
+-0x90a20000, 0x822021, 0x41c02, 0x3082ffff,
+-0x622021, 0x41c02, 0x3082ffff, 0x622021,
+-0x3e00008, 0x3082ffff, 0x0, 0x8f820220,
+-0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8,
+-0x30424000, 0x10400054, 0x24040001, 0x8f820200,
+-0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
+-0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
+-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x8f820224, 0x1444004d, 0x42040, 0xc4102b,
+-0x1040fff1, 0x0, 0x8f820200, 0x451025,
+-0xaf820200, 0x8f820220, 0x34428000, 0xaf820220,
+-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+-0x0, 0x8f820220, 0x3c030004, 0x431024,
+-0x1440000f, 0x0, 0x8f820220, 0x3c03ffff,
+-0x34637fff, 0x431024, 0xaf820220, 0x8f830054,
+-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x8f820220, 0x3c030004, 0x431024, 0x1440000d,
+-0x0, 0x8f820220, 0x34428000, 0xaf820220,
+-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+-0x0, 0x8f820220, 0x3c030004, 0x431024,
+-0x1040001b, 0x1021, 0x8f830220, 0x24020001,
+-0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700,
+-0x441025, 0xaf820220, 0x8f820220, 0x2403fffd,
+-0x431024, 0xaf820220, 0x8f820220, 0x3c030300,
+-0x431024, 0x14400003, 0x0, 0x10000008,
+-0x1021, 0x8f820220, 0x34420002, 0xaf820220,
+-0x8f830220, 0x24020001, 0x641825, 0xaf830220,
+-0x3e00008, 0x0, 0x2021, 0x3c050100,
+-0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
+-0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4,
+-0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0,
+-0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8,
+-0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4,
+-0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0,
+-0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8,
+-0x418c0, 0x24840001, 0x3631021, 0xac453004,
+-0x3631021, 0xac403000, 0x28820200, 0x1440fff9,
+-0x418c0, 0x2021, 0x418c0, 0x24840001,
+-0x3631021, 0xac402804, 0x3631021, 0xac402800,
+-0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c,
+-0x24030080, 0x24040100, 0xac600000, 0x24630004,
+-0x64102b, 0x5440fffd, 0xac600000, 0x8f830040,
+-0x3c02f000, 0x621824, 0x3c025000, 0x1062000c,
+-0x43102b, 0x14400006, 0x3c026000, 0x3c024000,
+-0x10620008, 0x24020800, 0x10000008, 0x0,
+-0x10620004, 0x24020800, 0x10000004, 0x0,
+-0x24020700, 0x3c010001, 0xac226dac, 0x3e00008,
+-0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0,
+-0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020,
+-0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e,
+-0x0, 0x3c010001, 0xac206dbc, 0x8f830054,
+-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
+-0x621023, 0x2c420065, 0x1440fffc, 0x0,
+-0xc004db9, 0x0, 0x24040001, 0x2821,
+-0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018,
+-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+-0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c,
+-0x24050002, 0x8f830054, 0x8f820054, 0x10000002,
+-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+-0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
+-0x26106f26, 0xc00457c, 0x2003021, 0x97a60018,
+-0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0,
+-0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
+-0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d,
+-0x24036040, 0x96020000, 0x3042fff0, 0x1443000c,
+-0x24020020, 0x3c030001, 0x94636f24, 0x1462000b,
+-0x24027830, 0x24020003, 0x3c010001, 0xac226d94,
+-0x24020005, 0x3c010001, 0x1000003f, 0xac226f34,
+-0x3c030001, 0x94636f24, 0x24027830, 0x1462000c,
+-0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0,
+-0x14430007, 0x24020003, 0x3c010001, 0xac226d94,
+-0x24020006, 0x3c010001, 0x1000002f, 0xac226f34,
+-0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24,
+-0x34420001, 0x3c010001, 0xac226d94, 0x24020015,
+-0x1462000b, 0x0, 0x3c020001, 0x94426f26,
+-0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430,
+-0x2c420001, 0x621825, 0x1460001b, 0x24020003,
+-0x3c030001, 0x94636f24, 0x24027810, 0x14620016,
+-0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0,
+-0x14400011, 0x24020002, 0x1000000f, 0x24020004,
+-0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001,
+-0xac226d94, 0x1000005e, 0x24020004, 0x3c020001,
+-0x8c426d94, 0x34420004, 0x3c010001, 0x100000af,
+-0xac226d94, 0x24020001, 0x3c010001, 0xac226f40,
+-0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2,
+-0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054,
+-0x8f820054, 0x24030008, 0x3c010001, 0xac236d98,
+-0x10000002, 0x248401f4, 0x8f820054, 0x821023,
+-0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
+-0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
+-0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
+-0x1440fffc, 0x8021, 0x24120001, 0x24110009,
+-0xc004482, 0x0, 0x3c010001, 0xac326db4,
+-0xc004547, 0x0, 0x3c020001, 0x8c426db4,
+-0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
+-0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
+-0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
+-0x0, 0x8f820220, 0x24040001, 0x34420002,
+-0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
+-0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
+-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x8f820224, 0x14440005, 0x34028000, 0x42040,
+-0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0,
+-0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
+-0x3c010001, 0xac226d98, 0x8021, 0x24120009,
+-0x3c11ffff, 0x36313f7f, 0xc004482, 0x0,
+-0x24020001, 0x3c010001, 0xac226db4, 0xc004547,
+-0x0, 0x3c020001, 0x8c426db4, 0x1452fffb,
+-0x0, 0x8f820044, 0x511024, 0x34425080,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+-0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
+-0x1440fffc, 0x0, 0x8f820044, 0x511024,
+-0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
+-0x10000002, 0x2463000a, 0x8f820054, 0x621023,
+-0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
+-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
+-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
+-0x621023, 0x2c420065, 0x1440fffc, 0x0,
+-0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
+-0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
+-0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
+-0x10000002, 0x24630001, 0x8f820054, 0x621023,
+-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
+-0x14440005, 0x34028000, 0x42040, 0xa4102b,
+-0x1040fff0, 0x34028000, 0x1082ff50, 0x26100001,
+-0x2e020064, 0x1440ffb0, 0x0, 0x3c020001,
+-0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0,
+-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+-0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001,
+-0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001,
+-0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001,
+-0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001,
+-0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001,
+-0xac206d98, 0x491021, 0x3c010001, 0xac226f30,
+-0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c,
+-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+-0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98,
+-0x24060004, 0x24020001, 0x14a20014, 0xafbf0010,
+-0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005,
+-0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005,
+-0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40,
+-0x348493e0, 0x24020005, 0x14620016, 0x0,
+-0x3c04003d, 0x10000013, 0x34840900, 0x3c020002,
+-0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e,
+-0x3c030001, 0x8c636f40, 0x10000005, 0x34848480,
+-0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240,
+-0x24020005, 0x14620003, 0x0, 0x3c04007a,
+-0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054,
+-0x441021, 0x431023, 0x44102b, 0x1440004c,
+-0x0, 0x3c020001, 0x8c426da0, 0x14400048,
+-0x0, 0x3c010001, 0x10c00025, 0xac206db0,
+-0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000,
+-0x3c080002, 0x25088ffc, 0x250afffc, 0x52842,
+-0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024,
+-0x10400010, 0x0, 0x14a70008, 0x0,
+-0x8d020000, 0x441024, 0x1040000a, 0x0,
+-0x3c010001, 0x10000007, 0xac256db0, 0x8d420000,
+-0x441024, 0x10400003, 0x0, 0x3c010001,
+-0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b,
+-0x2c420001, 0x431024, 0x5440ffe5, 0x52842,
+-0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001,
+-0xac226f30, 0x1060003b, 0x24020005, 0x3c030001,
+-0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012,
+-0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000,
+-0x34635000, 0x431024, 0x14400006, 0x24020001,
+-0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98,
+-0x24020001, 0x3c010001, 0xac226e24, 0x3c010001,
+-0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c,
+-0x3c020001, 0x8c426db0, 0x1040001e, 0x0,
+-0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001,
+-0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001,
+-0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8,
+-0x24020008, 0x10620005, 0x24020001, 0xc004239,
+-0x0, 0x1000000b, 0x0, 0x3c030001,
+-0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002,
+-0x8c638f90, 0x10620003, 0x0, 0xc004e9c,
+-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+-0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98,
+-0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024,
+-0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001,
+-0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8,
+-0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4,
+-0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c,
+-0x2c620003, 0x10400005, 0x24020001, 0x1062000a,
+-0x0, 0x10000226, 0x0, 0x24020004,
+-0x106200b6, 0x24020008, 0x1062010a, 0x24020001,
+-0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff,
+-0x2c620008, 0x1040021c, 0x31080, 0x3c010001,
+-0x220821, 0x8c226af8, 0x400008, 0x0,
+-0x3c030001, 0x8c636f40, 0x24020005, 0x14620010,
+-0x0, 0x3c020001, 0x8c426da4, 0x10400008,
+-0x24020003, 0xc004482, 0x0, 0x24020002,
+-0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4,
+-0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30,
+-0xc004482, 0x0, 0x3c020001, 0x8c426da4,
+-0x3c010001, 0xac206d30, 0x1440017a, 0x24020002,
+-0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40,
+-0x24020005, 0x14620003, 0x24020001, 0x3c010001,
+-0xac226dd0, 0xc0045ff, 0x0, 0x3c030001,
+-0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001,
+-0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104,
+-0x2021, 0x24020005, 0x3c010001, 0xac206da4,
+-0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec,
+-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
+-0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6,
+-0x0, 0x8f820220, 0x3c030004, 0x431024,
+-0x14400175, 0x24020007, 0x8f830054, 0x3c020001,
+-0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710,
+-0x14400003, 0x24020001, 0x3c010001, 0xac226d9c,
+-0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2,
+-0x0, 0x8f820220, 0x30428000, 0x1040017d,
+-0x0, 0x10000175, 0x0, 0x3c050001,
+-0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b,
+-0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0,
+-0x24020001, 0x3c020008, 0x621024, 0x10400006,
+-0x0, 0x8f820214, 0x3c03ffff, 0x431024,
+-0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff,
+-0x431024, 0x3442241f, 0xaf820214, 0x8f820220,
+-0x3c030200, 0x34420002, 0xaf820220, 0x24020008,
+-0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004,
+-0x431024, 0x14400016, 0x0, 0x3c020002,
+-0x8c428ffc, 0x30425000, 0x1040000d, 0x0,
+-0x8f820220, 0x30428000, 0x10400006, 0x0,
+-0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003,
+-0x431024, 0x8f820220, 0x34428000, 0xaf820220,
+-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+-0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a,
+-0x0, 0x3c020001, 0x94426f26, 0x24429fbc,
+-0x2c420004, 0x10400004, 0x24040018, 0x24050002,
+-0xc004ddb, 0x24060020, 0xc003e6d, 0x0,
+-0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8,
+-0x2443ffff, 0x2c620008, 0x1040016b, 0x31080,
+-0x3c010001, 0x220821, 0x8c226b18, 0x400008,
+-0x0, 0xc004547, 0x0, 0x3c030001,
+-0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002,
+-0x8c428ff8, 0x30424000, 0x10400004, 0x0,
+-0x8f820044, 0x10000006, 0x3442f080, 0x8f820044,
+-0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080,
+-0xaf820044, 0x8f830054, 0x100000ea, 0x24020004,
+-0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
+-0x431023, 0x2c422710, 0x14400147, 0x24020005,
+-0x100000d8, 0x0, 0x8f820220, 0x3c03f700,
+-0x431025, 0xaf820220, 0xaf800204, 0x3c010002,
+-0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001,
+-0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a,
+-0x14400135, 0x24020007, 0x100000d7, 0x0,
+-0xc003f50, 0x0, 0x1040012d, 0x24020001,
+-0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c,
+-0x431024, 0x3442251f, 0xaf820214, 0x24020008,
+-0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44,
+-0x10400064, 0x24020001, 0x8f820220, 0x3c030008,
+-0x431024, 0x1040006a, 0x3c020200, 0x10000078,
+-0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007,
+-0x10400115, 0x31080, 0x3c010001, 0x220821,
+-0x8c226b38, 0x400008, 0x0, 0xc003daf,
+-0x0, 0x3c010001, 0xac206d9c, 0xaf800204,
+-0x3c010002, 0xc004482, 0xac208fe0, 0x24020001,
+-0x3c010001, 0xac226db4, 0x24020002, 0x10000102,
+-0xaee204b8, 0xc004547, 0x0, 0x3c030001,
+-0x8c636db4, 0x10000084, 0x24020009, 0x3c020002,
+-0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8,
+-0x10000002, 0x344201f6, 0x344201fe, 0xaf820238,
+-0x8f830054, 0x1000008b, 0x24020004, 0x8f830054,
+-0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023,
+-0x2c422710, 0x144000e8, 0x24020005, 0x10000079,
+-0x0, 0x8f820220, 0x3c03f700, 0x431025,
+-0xaf820220, 0xaf800204, 0x3c010002, 0x10000077,
+-0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28,
+-0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6,
+-0x24020007, 0x10000078, 0x0, 0xc003f50,
+-0x0, 0x104000ce, 0x24020001, 0x8f820214,
+-0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024,
+-0x3442251f, 0xaf820214, 0x24020008, 0x1080000f,
+-0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b,
+-0x0, 0x8f820220, 0x34420002, 0xaf820220,
+-0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c,
+-0x8f840220, 0x10000016, 0x0, 0x8f820220,
+-0x3c030008, 0x431024, 0x14400011, 0x3c020200,
+-0x282a025, 0x2402000e, 0x3c010002, 0xac228f90,
+-0xc00551b, 0x2021, 0x8f820220, 0x34420002,
+-0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98,
+-0xc00529b, 0x2021, 0x100000a3, 0x0,
+-0x3c020001, 0x8c426e44, 0x1040009f, 0x0,
+-0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001,
+-0xac226e40, 0x14400098, 0x24020002, 0x3c010001,
+-0xac206e44, 0x3c010001, 0x10000093, 0xac226e40,
+-0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e,
+-0x31080, 0x3c010001, 0x220821, 0x8c226b58,
+-0x400008, 0x0, 0x3c020001, 0x8c426da4,
+-0x10400018, 0x24020005, 0xc004482, 0x0,
+-0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e,
+-0xac206da4, 0xc004963, 0x0, 0x3c030001,
+-0x8c636dd4, 0x24020006, 0x14620077, 0x24020003,
+-0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98,
+-0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021,
+-0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220,
+-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
+-0x24020006, 0xaee204b8, 0x3c010001, 0x10000062,
+-0xac236f28, 0x8f820220, 0x3c030004, 0x431024,
+-0x10400003, 0x24020007, 0x1000005b, 0xaee204b8,
+-0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
+-0x431023, 0x2c422710, 0x14400003, 0x24020001,
+-0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8,
+-0x30425000, 0x1040004c, 0x0, 0x8f820220,
+-0x30428000, 0x10400007, 0x0, 0x8f820220,
+-0x3c03ffff, 0x34637fff, 0x431024, 0x10000042,
+-0xaf820220, 0x8f820220, 0x34428000, 0x1000003e,
+-0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b,
+-0x2021, 0xc00551b, 0x2021, 0x3c020002,
+-0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214,
+-0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
+-0x24020008, 0xaee204b8, 0x8f820220, 0x34420002,
+-0xaf820220, 0x8f820220, 0x3c030004, 0x431024,
+-0x14400016, 0x0, 0x3c020002, 0x8c428ff8,
+-0x30425000, 0x1040000d, 0x0, 0x8f820220,
+-0x30428000, 0x10400006, 0x0, 0x8f820220,
+-0x3c03ffff, 0x34637fff, 0x10000003, 0x431024,
+-0x8f820220, 0x34428000, 0xaf820220, 0x8f820220,
+-0x3c03f700, 0x431025, 0xaf820220, 0x3c020001,
+-0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004,
+-0x24040018, 0x24050002, 0xc004ddb, 0x24060020,
+-0xc003e6d, 0x0, 0x10000003, 0x0,
+-0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008,
+-0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
+-0x34420004, 0xaf820220, 0x8f820200, 0x3c050001,
+-0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002,
+-0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001,
+-0x10a2000a, 0x0, 0x100000b1, 0x0,
+-0x24020004, 0x10a20072, 0x24020008, 0x10a20085,
+-0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050,
+-0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40,
+-0x621824, 0x3c020700, 0x621825, 0x24020e00,
+-0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200,
+-0xaf850220, 0x14800006, 0xaf820238, 0x8f820044,
+-0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044,
+-0x3c030001, 0x8c636f40, 0x24020005, 0x14620004,
+-0x0, 0x8f820044, 0x34425000, 0xaf820044,
+-0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40,
+-0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c,
+-0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001,
+-0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000,
+-0x621825, 0x641825, 0x1000000a, 0x34620002,
+-0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac,
+-0x3c040001, 0x8c846d8c, 0x431025, 0x441025,
+-0x34420002, 0xaf820220, 0x1000002f, 0x24020001,
+-0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff,
+-0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824,
+-0x3c020d00, 0x621825, 0x24020001, 0xaf830050,
+-0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00,
+-0x3c020001, 0x8c426d80, 0x10000004, 0x34630070,
+-0x3c020001, 0x8c426d80, 0x34630072, 0x431025,
+-0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700,
+-0x621825, 0x3c020001, 0x8c426d90, 0x3c040001,
+-0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025,
+-0x441025, 0xaf820220, 0x24020005, 0x14a20006,
+-0x24020001, 0x8f820044, 0x2403afff, 0x431024,
+-0xaf820044, 0x24020001, 0x1000003d, 0xaf820238,
+-0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001,
+-0x8c846f1c, 0x621824, 0x3c020a00, 0x621825,
+-0x24020001, 0xaf830050, 0xaf820200, 0x1080001e,
+-0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a,
+-0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a,
+-0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c,
+-0x3442ffff, 0x621824, 0x1080000f, 0xaf830050,
+-0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00,
+-0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001,
+-0xaf820200, 0xaf820220, 0x641825, 0xaf830200,
+-0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80,
+-0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
+-0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84,
+-0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac,
+-0x651825, 0x431025, 0x441025, 0xaf820220,
+-0x3e00008, 0x0, 0x3c030001, 0x8c636db4,
+-0x3c020001, 0x8c426db8, 0x10620003, 0x24020002,
+-0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003,
+-0x10400025, 0x24020001, 0x14620023, 0x24020004,
+-0x3c030001, 0x8c636d98, 0x10620006, 0x24020008,
+-0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009,
+-0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044,
+-0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080,
+-0xaf820044, 0x8f830054, 0x24020002, 0x3c010001,
+-0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c,
+-0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0,
+-0x431023, 0x2c422710, 0x14400003, 0x24020009,
+-0x3c010001, 0xac226db4, 0x3e00008, 0x0,
+-0x0, 0x0, 0x0, 0x27bdffd8,
+-0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
+-0xafb10014, 0xc08821, 0xafb00010, 0x8021,
+-0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x24100010, 0x2501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x2501024, 0x24100010, 0x2701024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x2701024, 0xc004db9, 0x34108000,
+-0xc004db9, 0x0, 0xc004d58, 0x0,
+-0x50400005, 0x108042, 0x96220000, 0x501025,
+-0xa6220000, 0x108042, 0x1600fff7, 0x0,
+-0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c,
+-0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
+-0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
+-0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
+-0xafb00010, 0x8021, 0xafbf0020, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0x24100010, 0x2301024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x2501024, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x34108000,
+-0x96620000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+-0x0, 0xc004db9, 0x0, 0x8fbf0020,
+-0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+-0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0,
+-0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020,
+-0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001,
+-0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005,
+-0x14620005, 0x2483ffff, 0xc004963, 0x0,
+-0x1000034c, 0x0, 0x2c620013, 0x10400349,
+-0x31080, 0x3c010001, 0x220821, 0x8c226b80,
+-0x400008, 0x0, 0xc004db9, 0x8021,
+-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
+-0x2021, 0x108042, 0x1600fffc, 0x0,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010,
+-0x8021, 0xc004d78, 0x24040001, 0x26100001,
+-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x24100010,
+-0x32020001, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
+-0x24100010, 0xc004d78, 0x2021, 0x108042,
+-0x1600fffc, 0x0, 0xc004db9, 0x34108000,
+-0xc004db9, 0x0, 0xc004d58, 0x0,
+-0x50400005, 0x108042, 0x96220000, 0x501025,
+-0xa6220000, 0x108042, 0x1600fff7, 0x0,
+-0xc004db9, 0x0, 0x97a20010, 0x30428000,
+-0x144002dc, 0x24020003, 0x100002d8, 0x0,
+-0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0xc004d78, 0x2021, 0x108042, 0x1600fffc,
+-0x0, 0xc004d78, 0x24040001, 0xc004d78,
+-0x2021, 0x34108000, 0x96220000, 0x501024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fff8, 0x0, 0xc004db9,
+-0x0, 0x8f830054, 0x10000296, 0x24020004,
+-0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c,
+-0x431023, 0x2c420064, 0x1440029e, 0x24020002,
+-0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003,
+-0x14400296, 0x24020011, 0x24020003, 0x10620005,
+-0x24020004, 0x10620291, 0x2402000f, 0x1000028f,
+-0x24020011, 0x1000028d, 0x24020005, 0x24020014,
+-0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020012, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x34108000,
+-0x96220000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+-0x0, 0xc004db9, 0x0, 0x8f830054,
+-0x10000248, 0x24020006, 0x8f830054, 0x3c020001,
+-0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
+-0x14400250, 0x24020007, 0x1000024c, 0x0,
+-0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020013, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020013,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x8f830054, 0x10000207, 0x24020008, 0x8f830054,
+-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x1440020f, 0x24020009, 0x1000020b,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x8021,
+-0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x8f830054, 0x10000193, 0x2402000a, 0x8f830054,
+-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x1440019b, 0x2402000b, 0x10000197,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020017, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x8021,
+-0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020017, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054,
+-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x14400127, 0x24020012, 0x10000123,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020014, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x8021,
+-0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020014, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x8f830054, 0x100000ab, 0x24020013, 0x8f830054,
+-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+-0x2c420064, 0x144000b3, 0x2402000d, 0x100000af,
+-0x0, 0x27b10010, 0xa7a00010, 0x8021,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x8021,
+-0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x96220000, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x8f830054, 0x10000037, 0x2402000e, 0x24020840,
+-0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020013, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x34108000,
+-0x96220000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+-0x0, 0xc004db9, 0x0, 0x8f830054,
+-0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001,
+-0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001,
+-0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
+-0x14400004, 0x0, 0x24020011, 0x3c010001,
+-0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98,
+-0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030,
+-0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002,
+-0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc,
+-0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c,
+-0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c,
+-0x2463ffff, 0x2c620006, 0x10400377, 0x31080,
+-0x3c010001, 0x220821, 0x8c226bd8, 0x400008,
+-0x0, 0x2021, 0x2821, 0xc004ddb,
+-0x34068000, 0x24040010, 0x24050002, 0x24060002,
+-0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002,
+-0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018,
+-0xa7a00018, 0x8021, 0xc004d78, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x24100010, 0x32020001, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x32020001, 0x24100010, 0xc004d78, 0x2021,
+-0x108042, 0x1600fffc, 0x0, 0xc004db9,
+-0x34108000, 0xc004db9, 0x0, 0xc004d58,
+-0x0, 0x50400005, 0x108042, 0x96220000,
+-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+-0x0, 0xc004db9, 0x0, 0x97a20018,
+-0x30428000, 0x14400004, 0x24020003, 0x3c010001,
+-0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a,
+-0xac226dd4, 0x24040010, 0x24050002, 0x24060002,
+-0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001,
+-0x8c636e20, 0x24020001, 0x146201e1, 0x8021,
+-0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x24100010, 0x32020001, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x32020001, 0x24100010, 0x32020018, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
+-0xc004db9, 0x0, 0xc004d58, 0x0,
+-0x50400005, 0x108042, 0x96220000, 0x501025,
+-0xa6220000, 0x108042, 0x1600fff7, 0x0,
+-0xc004db9, 0x8021, 0x27b10018, 0xa7a00018,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0x24100010, 0x32020001,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+-0x32020018, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x96220000, 0x501025, 0xa6220000, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x8021,
+-0x24040018, 0x2821, 0xc004ddb, 0x24060404,
+-0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001,
+-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x24100010,
+-0x32020001, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
+-0x24100010, 0x32020018, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x32020018, 0xc004db9, 0x34108000, 0xc004db9,
+-0x0, 0xc004d58, 0x0, 0x50400005,
+-0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
+-0x108042, 0x1600fff7, 0x0, 0xc004db9,
+-0x8021, 0xa7a0001a, 0xc004d78, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x24100010, 0x32020001, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x32020001, 0x24100010, 0x32020018, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
+-0xc004db9, 0x0, 0xc004d58, 0x0,
+-0x50400005, 0x108042, 0x97a2001a, 0x501025,
+-0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
+-0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
+-0x2021, 0x24100010, 0xc004d78, 0x2021,
+-0x108042, 0x1600fffc, 0x0, 0x24100010,
+-0x3202001e, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x3202001e,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x97a2001c, 0x501025, 0xa7a2001c, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x8021,
+-0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001,
+-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x24100010,
+-0xc004d78, 0x2021, 0x108042, 0x1600fffc,
+-0x0, 0x24100010, 0x3202001e, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000,
+-0xc004db9, 0x0, 0xc004d58, 0x0,
+-0x50400005, 0x108042, 0x97a2001c, 0x501025,
+-0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
+-0xc004db9, 0x8021, 0x24020002, 0xa7a2001e,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0x24100010, 0xc004d78,
+-0x2021, 0x108042, 0x1600fffc, 0x0,
+-0x24100010, 0x3202001e, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x3202001e, 0xc004d78, 0x24040001, 0xc004d78,
+-0x2021, 0x34108000, 0x97a2001e, 0x501024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fff8, 0x0, 0xc004db9,
+-0x8021, 0xa7a00020, 0xc004d78, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x24100010, 0xc004d78, 0x2021, 0x108042,
+-0x1600fffc, 0x0, 0x24100010, 0x3202001e,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x3202001e, 0xc004db9,
+-0x34108000, 0xc004db9, 0x0, 0xc004d58,
+-0x0, 0x50400005, 0x108042, 0x97a20020,
+-0x501025, 0xa7a20020, 0x108042, 0x1600fff7,
+-0x0, 0xc004db9, 0x8021, 0xa7a00020,
+-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+-0x1440fffb, 0x0, 0xc004d78, 0x2021,
+-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0x24100010, 0xc004d78,
+-0x2021, 0x108042, 0x1600fffc, 0x0,
+-0x24100010, 0x3202001e, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+-0x3202001e, 0xc004db9, 0x34108000, 0xc004db9,
+-0x0, 0xc004d58, 0x0, 0x50400005,
+-0x108042, 0x97a20020, 0x501025, 0xa7a20020,
+-0x108042, 0x1600fff7, 0x0, 0xc004db9,
+-0x8021, 0xa7a00022, 0xc004d78, 0x24040001,
+-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+-0x24100010, 0xc004d78, 0x2021, 0x108042,
+-0x1600fffc, 0x0, 0x24100010, 0xc004d78,
+-0x2021, 0x108042, 0x1600fffc, 0x0,
+-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+-0x34108000, 0x97a20022, 0x501024, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fff8, 0x0, 0xc004db9, 0x0,
+-0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
+-0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d,
+-0x0, 0x3c020001, 0x94426f26, 0x3c010001,
+-0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c,
+-0x24040009, 0x24050001, 0xc004ddb, 0x24060400,
+-0x24040018, 0x24050001, 0xc004ddb, 0x24060020,
+-0x24040018, 0x24050001, 0xc004ddb, 0x24062000,
+-0x3c024000, 0x2421024, 0x10400123, 0x3c022000,
+-0x2421024, 0x10400004, 0x0, 0x3c010001,
+-0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c,
+-0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9,
+-0x0, 0x3c020001, 0x8c426f1c, 0x10400067,
+-0x3c020004, 0x2421024, 0x10400011, 0xa7a00018,
+-0x3c020008, 0x2421024, 0x10400002, 0x24020200,
+-0xa7a20018, 0x3c020010, 0x2421024, 0x10400004,
+-0x0, 0x97a20018, 0x34420100, 0xa7a20018,
+-0x97a60018, 0x24040009, 0x10000004, 0x2821,
+-0x24040009, 0x2821, 0x3021, 0xc004ddb,
+-0x0, 0x24020001, 0xa7a2001a, 0x3c020008,
+-0x2421024, 0x1040000c, 0x3c020002, 0x2421024,
+-0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001,
+-0x2421024, 0x10400005, 0x3c020010, 0x97a2001a,
+-0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024,
+-0x1040000e, 0x3c020002, 0x2421024, 0x10400005,
+-0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a,
+-0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0,
+-0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0,
+-0x2431024, 0x54430004, 0x3c020020, 0x97a2001a,
+-0x1000000c, 0x34420400, 0x2421024, 0x50400004,
+-0x3c020080, 0x97a2001a, 0x10000006, 0x34420800,
+-0x2421024, 0x10400004, 0x0, 0x97a2001a,
+-0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004,
+-0xc004ddb, 0x2821, 0x3c020004, 0x2421024,
+-0x10400004, 0xa7a0001c, 0x32425000, 0x14400004,
+-0x0, 0x32424000, 0x10400005, 0x2021,
+-0xc004cf9, 0x2402021, 0x10000096, 0x0,
+-0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb,
+-0xa7a6001c, 0x1000008f, 0x0, 0x2421024,
+-0x10400004, 0xa7a00018, 0x32425000, 0x14400004,
+-0x0, 0x32424000, 0x10400005, 0x3c020010,
+-0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a,
+-0x2421024, 0x10400004, 0x0, 0x97a20018,
+-0x10000004, 0xa7a20018, 0x97a20018, 0x34420100,
+-0xa7a20018, 0x3c020001, 0x2421024, 0x10400004,
+-0x0, 0x97a20018, 0x10000004, 0xa7a20018,
+-0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018,
+-0x2021, 0xc004ddb, 0x2821, 0xa7a0001a,
+-0x8021, 0xc004d78, 0x24040001, 0x26100001,
+-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x24100010,
+-0x32020001, 0x10400002, 0x2021, 0x24040001,
+-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
+-0x24100010, 0xc004d78, 0x2021, 0x108042,
+-0x1600fffc, 0x0, 0xc004db9, 0x34108000,
+-0xc004db9, 0x0, 0xc004d58, 0x0,
+-0x50400005, 0x108042, 0x97a2001a, 0x501025,
+-0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
+-0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
+-0x2021, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
+-0x2021, 0x108042, 0x1600fffc, 0x0,
+-0xc004db9, 0x34108000, 0xc004db9, 0x0,
+-0xc004d58, 0x0, 0x50400005, 0x108042,
+-0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
+-0x1600fff7, 0x0, 0xc004db9, 0x0,
+-0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a,
+-0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c,
+-0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b,
+-0xafa30014, 0x8f830054, 0x24020004, 0x3c010001,
+-0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38,
+-0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c,
+-0x431023, 0x2c420064, 0x1440000f, 0x0,
+-0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4,
+-0x3c03f700, 0x431025, 0x10000007, 0xaf820220,
+-0x24020006, 0x3c010001, 0xac226dd4, 0x24020011,
+-0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030,
+-0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038,
+-0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c,
+-0x8821, 0x32024000, 0x10400013, 0xafbf0020,
+-0x3c020010, 0x2021024, 0x2c420001, 0x21023,
+-0x30434100, 0x3c020001, 0x2021024, 0x14400006,
+-0x34714000, 0x3c020002, 0x2021024, 0x14400002,
+-0x34716000, 0x34714040, 0x2021, 0x2821,
+-0x10000036, 0x2203021, 0x32021000, 0x10400035,
+-0x2021, 0x2821, 0xc004ddb, 0x24060040,
+-0x24040018, 0x2821, 0xc004ddb, 0x24060c00,
+-0x24040017, 0x2821, 0xc004ddb, 0x24060400,
+-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+-0x24040017, 0x2821, 0xc004ddb, 0x24062500,
+-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+-0x24040017, 0x2821, 0xc004ddb, 0x24064600,
+-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+-0x24040017, 0x2821, 0xc004ddb, 0x24066700,
+-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+-0x2404001f, 0x2821, 0xc004ddb, 0x24060010,
+-0x24040009, 0x2821, 0xc004ddb, 0x24061500,
+-0x24040009, 0x2821, 0x24061d00, 0xc004ddb,
+-0x0, 0x3c040001, 0x24846bf0, 0x3c05000e,
+-0x34a50100, 0x2003021, 0x2203821, 0xafa00010,
+-0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c,
+-0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044,
+-0x8f820044, 0x3c030001, 0x431025, 0x3c030008,
+-0xaf820044, 0x8f840054, 0x8f820054, 0xa32824,
+-0x10000002, 0x24840001, 0x8f820054, 0x821023,
+-0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
+-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+-0x0, 0x3e00008, 0xa01021, 0x8f830044,
+-0x3c02fff0, 0x3442ffff, 0x42480, 0x621824,
+-0x3c020002, 0x822025, 0x641825, 0xaf830044,
+-0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x8f820044, 0x3c030001,
+-0x431025, 0xaf820044, 0x8f830054, 0x8f820054,
+-0x10000002, 0x24630001, 0x8f820054, 0x621023,
+-0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
+-0x0, 0x8f820044, 0x2403ff7f, 0x431024,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x8f820044, 0x34420080,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x3e00008, 0x0,
+-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
+-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
+-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+-0x621023, 0x2c420002, 0x1440fffc, 0x0,
+-0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+-0x809821, 0xafbe002c, 0xa0f021, 0xafb20020,
+-0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028,
+-0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
+-0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x34108000,
+-0x96420000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x12000075,
+-0x0, 0x1000fff6, 0x0, 0x3275ffff,
+-0x27b10010, 0xa7a00010, 0x8021, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
+-0x2021, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x2b01024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x2b01024, 0xc004db9,
+-0x34108000, 0xc004db9, 0x0, 0xc004d58,
+-0x0, 0x50400005, 0x108042, 0x96220000,
+-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+-0x0, 0xc004db9, 0x0, 0x33c5ffff,
+-0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
+-0x10000006, 0x521025, 0x14a20006, 0x3271ffff,
+-0x97a20010, 0x121827, 0x431024, 0xa7a20010,
+-0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
+-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+-0x0, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+-0x24040001, 0x24100010, 0x32020001, 0x10400002,
+-0x2021, 0x24040001, 0xc004d78, 0x108042,
+-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+-0x10400002, 0x2021, 0x24040001, 0xc004d78,
+-0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
+-0x24040001, 0xc004d78, 0x2021, 0x34108000,
+-0x96420000, 0x501024, 0x10400002, 0x2021,
+-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+-0x0, 0xc004db9, 0x0, 0x8fbf0030,
+-0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020,
+-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
+-0x0, 0x0, 0x0, 0x27bdffe8,
+-0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0,
+-0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
+-0x0, 0xc003daf, 0x8f840224, 0x100001d8,
+-0x0, 0x8f820220, 0x3c030008, 0x431024,
+-0x10400026, 0x24020001, 0x8f840224, 0x8f820220,
+-0x3c030400, 0x431024, 0x10400006, 0x0,
+-0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b,
+-0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000,
+-0x24420001, 0xac620000, 0x2c420002, 0x14400003,
+-0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002,
+-0x8c428fc0, 0x10400006, 0x30820040, 0x10400004,
+-0x24020001, 0x3c010002, 0x10000003, 0xac228fc4,
+-0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c,
+-0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002,
+-0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002,
+-0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002,
+-0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002,
+-0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002,
+-0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194,
+-0x31080, 0x3c010001, 0x220821, 0x8c226c00,
+-0x400008, 0x0, 0x24020002, 0x3c010002,
+-0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002,
+-0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002,
+-0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224,
+-0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0,
+-0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf,
+-0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd,
+-0x431024, 0xaf820200, 0x3c010002, 0xac208fe0,
+-0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001,
+-0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002,
+-0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4,
+-0x14400006, 0x24020003, 0x3c010001, 0xac246d9c,
+-0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002,
+-0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002,
+-0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
+-0x14400003, 0x24020004, 0x3c010002, 0xac228f90,
+-0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff,
+-0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001,
+-0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8,
+-0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002,
+-0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204,
+-0x3463ffff, 0x30420030, 0x1440012f, 0x283a024,
+-0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002,
+-0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0,
+-0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff,
+-0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001,
+-0xac226e3c, 0x2c420002, 0x14400125, 0x24020001,
+-0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c,
+-0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002,
+-0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024,
+-0x3c020002, 0x8c428f9c, 0x10400115, 0x0,
+-0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002,
+-0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002,
+-0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204,
+-0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002,
+-0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0,
+-0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
+-0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002,
+-0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
+-0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4,
+-0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c,
+-0x3c030002, 0x8c638fc8, 0x441024, 0x641824,
+-0x10430004, 0x24020001, 0x3c010002, 0x100000e4,
+-0xac228f90, 0x24020003, 0xaca20000, 0x24020008,
+-0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc,
+-0x1040000c, 0x24020001, 0x3c040002, 0xc005091,
+-0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005,
+-0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006,
+-0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002,
+-0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0,
+-0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0,
+-0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002,
+-0xac238fac, 0x8f830054, 0x24020009, 0x3c010002,
+-0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4,
+-0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0,
+-0x431023, 0x2c422710, 0x1440009f, 0x0,
+-0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
+-0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002,
+-0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21,
+-0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc,
+-0x1040000e, 0x0, 0x3c020002, 0x8c428f9c,
+-0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f,
+-0x2402000c, 0x8f820204, 0x30420080, 0x1440000c,
+-0x24020003, 0x10000029, 0x2402000c, 0x3c020002,
+-0x8c428f9c, 0x30420080, 0x14400005, 0x24020003,
+-0x8f820204, 0x30420080, 0x1040001f, 0x24020003,
+-0xac620000, 0x2402000a, 0x3c010002, 0xac228f90,
+-0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002,
+-0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000,
+-0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002,
+-0xac228f90, 0x641825, 0x3c010002, 0xac238fe0,
+-0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
+-0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0,
+-0x10400005, 0x0, 0x2402000c, 0x3c010002,
+-0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0,
+-0x10400063, 0x0, 0x3c040002, 0x8c848f9c,
+-0x10800055, 0x30820008, 0x3c030002, 0x8c638fac,
+-0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8,
+-0xaca20000, 0x24020006, 0x3c010002, 0x10000054,
+-0xac228f90, 0x8f820200, 0x34420002, 0xaf820200,
+-0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90,
+-0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002,
+-0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
+-0x14400031, 0x0, 0x3c020002, 0x8c428fd0,
+-0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4,
+-0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d,
+-0x0, 0x3c050001, 0x8ca56d98, 0xc00529b,
+-0x2021, 0x3c030001, 0x8c636d98, 0x24020004,
+-0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94,
+-0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94,
+-0x431024, 0x3c010001, 0xac226d94, 0x8f830224,
+-0x3c020200, 0x3c010002, 0xac238fec, 0x10000020,
+-0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005,
+-0x0, 0x3c020002, 0x8c428f9c, 0x1040000f,
+-0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21,
+-0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0,
+-0x1040000f, 0x0, 0x3c020002, 0x8c428f9c,
+-0x1440000b, 0x0, 0x24020002, 0x3c010002,
+-0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0,
+-0x10400003, 0x0, 0xc003daf, 0x0,
+-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+-0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002,
+-0x24638fe8, 0x8c620000, 0x10400005, 0x34422000,
+-0x3c010002, 0xac228fdc, 0x10000003, 0xac600000,
+-0x3c010002, 0xac248fdc, 0x3e00008, 0x0,
+-0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002,
+-0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e,
+-0x821024, 0x14400061, 0x24020030, 0x30822000,
+-0x1040005d, 0x30838000, 0x31a02, 0x30820001,
+-0x21200, 0x3c040001, 0x8c846f20, 0x621825,
+-0x331c2, 0x3c030001, 0x24636e48, 0x30828000,
+-0x21202, 0x30840001, 0x42200, 0x441025,
+-0x239c2, 0x61080, 0x431021, 0x471021,
+-0x90430000, 0x24020001, 0x10620025, 0x0,
+-0x10600007, 0x24020002, 0x10620013, 0x24020003,
+-0x1062002c, 0x3c05000f, 0x10000037, 0x0,
+-0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
+-0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
+-0xaf820220, 0x3c010002, 0xac209004, 0x3c010002,
+-0x10000034, 0xac20900c, 0x8f820200, 0x34420100,
+-0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
+-0x431024, 0xaf820220, 0x24020100, 0x3c010002,
+-0xac229004, 0x3c010002, 0x10000026, 0xac20900c,
+-0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
+-0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
+-0x3c010002, 0xac209004, 0x3c010002, 0x10000019,
+-0xac23900c, 0x8f820200, 0x34420100, 0xaf820200,
+-0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
+-0x24020100, 0x3c010002, 0xac229004, 0x3c010002,
+-0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001,
+-0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014,
+-0x10000004, 0x0, 0x24020030, 0x3c010002,
+-0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+-0x0, 0x0, 0x0, 0x27bdffc8,
+-0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+-0xafb00020, 0xc08021, 0x3c040001, 0x24846c50,
+-0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001,
+-0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+-0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010,
+-0x24020002, 0x12620083, 0x2e620003, 0x10400005,
+-0x24020001, 0x1262000a, 0x0, 0x10000173,
+-0x0, 0x24020004, 0x126200f8, 0x24020008,
+-0x126200f7, 0x3c02ffec, 0x1000016c, 0x0,
+-0x3c020001, 0x8c426d94, 0x30420002, 0x14400004,
+-0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+-0x3c010002, 0x310821, 0xac308ffc, 0x3c024000,
+-0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
+-0x101382, 0x3042001c, 0x3c030001, 0x24636dd8,
+-0x431021, 0x823821, 0x3c020020, 0x2021024,
+-0x10400006, 0x24020100, 0x3c010002, 0x310821,
+-0xac229000, 0x10000005, 0x3c020080, 0x3c010002,
+-0x310821, 0xac209000, 0x3c020080, 0x2021024,
+-0x10400006, 0x121940, 0x3c020001, 0x3c010002,
+-0x230821, 0x10000005, 0xac229008, 0x121140,
+-0x3c010002, 0x220821, 0xac209008, 0x94e40000,
+-0x3c030001, 0x8c636f40, 0x24020005, 0x10620010,
+-0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
+-0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+-0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002,
+-0x24040001, 0x2821, 0xc0045be, 0x27a60018,
+-0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001,
+-0xac316da4, 0x14530004, 0x32028000, 0xc003daf,
+-0x0, 0x32028000, 0x1040011c, 0x0,
+-0xc003daf, 0x0, 0x3c030001, 0x8c636f40,
+-0x24020005, 0x10620115, 0x24020002, 0x3c010001,
+-0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98,
+-0x24040001, 0x24050004, 0x27b0001a, 0xc0045be,
+-0x2003021, 0x24040001, 0x2821, 0xc0045be,
+-0x2003021, 0x3c020002, 0x511021, 0x8c428ff4,
+-0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff,
+-0x3c010001, 0xac336da4, 0x431024, 0x3c010002,
+-0x310821, 0x109300f7, 0xac228ff4, 0x100000f7,
+-0x0, 0x3c022000, 0x2021024, 0x10400005,
+-0x24020001, 0x3c010001, 0xac226f1c, 0x10000004,
+-0x128940, 0x3c010001, 0xac206f1c, 0x128940,
+-0x3c010002, 0x310821, 0xac308ff8, 0x3c024000,
+-0x2021024, 0x14400014, 0x0, 0x3c020001,
+-0x8c426f1c, 0x10400006, 0x24040004, 0x24050001,
+-0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8,
+-0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff,
+-0x3463ffff, 0x431024, 0x3c010002, 0x310821,
+-0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c,
+-0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
+-0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100,
+-0x3c010002, 0x310821, 0xac239004, 0x3c030001,
+-0x3c010002, 0x310821, 0xac23900c, 0x10000015,
+-0x34420400, 0x2021024, 0x10400008, 0x24030100,
+-0x3c020001, 0x8c426f20, 0x3c010002, 0x310821,
+-0xac239004, 0x1000000b, 0x34420800, 0x3c020080,
+-0x2021024, 0x1040002e, 0x3c030001, 0x3c020001,
+-0x8c426f20, 0x3c010002, 0x310821, 0xac23900c,
+-0x34420c00, 0x3c010001, 0xac226f20, 0x10000025,
+-0x24040001, 0x3c020020, 0x2021024, 0x10400006,
+-0x24020100, 0x3c010002, 0x310821, 0xac229004,
+-0x10000005, 0x3c020080, 0x3c010002, 0x310821,
+-0xac209004, 0x3c020080, 0x2021024, 0x10400007,
+-0x121940, 0x3c020001, 0x3c010002, 0x230821,
+-0xac22900c, 0x10000006, 0x24040001, 0x121140,
+-0x3c010002, 0x220821, 0xac20900c, 0x24040001,
+-0x2821, 0x27b0001e, 0xc00457c, 0x2003021,
+-0x24040001, 0x2821, 0xc00457c, 0x2003021,
+-0x24040001, 0x24050001, 0x27b0001c, 0xc00457c,
+-0x2003021, 0x24040001, 0x24050001, 0xc00457c,
+-0x2003021, 0x10000077, 0x0, 0x3c02ffec,
+-0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
+-0x121140, 0x3c010002, 0x220821, 0xac308ff8,
+-0x3c022000, 0x2021024, 0x10400009, 0x0,
+-0x3c020001, 0x8c426e44, 0x14400005, 0x24020001,
+-0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000,
+-0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024,
+-0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c,
+-0xaf820238, 0x3c010001, 0xac206db0, 0x10600005,
+-0x24022020, 0x3c010001, 0xac226f20, 0x24020001,
+-0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
+-0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98,
+-0x3484ffff, 0x441024, 0x3c010002, 0x230821,
+-0xac228ff0, 0x24020001, 0x10a20044, 0x0,
+-0x10000040, 0x0, 0x3c020001, 0x8c426f1c,
+-0x1040001c, 0x24022000, 0x3c010001, 0xac226f20,
+-0x3c0300a0, 0x2031024, 0x14430005, 0x121140,
+-0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20,
+-0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020,
+-0x621024, 0x10400004, 0x24022001, 0x3c010001,
+-0x10000023, 0xac226f20, 0x3c020080, 0x621024,
+-0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c,
+-0xac226f20, 0x3c020020, 0x2021024, 0x10400007,
+-0x121940, 0x24020100, 0x3c010002, 0x230821,
+-0xac229004, 0x10000006, 0x3c020080, 0x121140,
+-0x3c010002, 0x220821, 0xac209004, 0x3c020080,
+-0x2021024, 0x10400006, 0x121940, 0x3c020001,
+-0x3c010002, 0x230821, 0x10000005, 0xac22900c,
+-0x121140, 0x3c010002, 0x220821, 0xac20900c,
+-0x3c030001, 0x8c636d98, 0x24020001, 0x10620003,
+-0x0, 0xc003daf, 0x0, 0x8fbf0030,
+-0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+-0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c,
+-0x9821, 0xafb50040, 0xa821, 0xafb10034,
+-0x8821, 0x24020002, 0xafbf0048, 0xafbe0044,
+-0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a,
+-0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022,
+-0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005,
+-0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d,
+-0x2201021, 0x24020004, 0x10a2020a, 0x24020008,
+-0x10a20208, 0x2201021, 0x10000256, 0x0,
+-0x8fa8002c, 0x88140, 0x3c030002, 0x701821,
+-0x8c638ffc, 0x621024, 0x14400009, 0x24040001,
+-0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002,
+-0x300821, 0xac318ff4, 0x10000246, 0x2201021,
+-0x24050001, 0xc00457c, 0x27a60018, 0x24040001,
+-0x24050001, 0xc00457c, 0x27a60018, 0x97a20018,
+-0x30420004, 0x104000d9, 0x3c114000, 0x3c020001,
+-0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9,
+-0x31080, 0x3c010001, 0x220821, 0x8c226c68,
+-0x400008, 0x0, 0x24040001, 0x24050011,
+-0x27b0001a, 0xc00457c, 0x2003021, 0x24040001,
+-0x24050011, 0xc00457c, 0x2003021, 0x97a3001a,
+-0x30624000, 0x10400002, 0x3c150010, 0x3c150008,
+-0x30628000, 0x104000aa, 0x3c130001, 0x100000a8,
+-0x3c130002, 0x24040001, 0x24050014, 0x27b0001a,
+-0xc00457c, 0x2003021, 0x24040001, 0x24050014,
+-0xc00457c, 0x2003021, 0x97a3001a, 0x30621000,
+-0x10400002, 0x3c150010, 0x3c150008, 0x30620800,
+-0x10400097, 0x3c130001, 0x10000095, 0x3c130002,
+-0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
+-0x2003021, 0x24040001, 0x24050019, 0xc00457c,
+-0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
+-0x10620027, 0x28620401, 0x1040000e, 0x24020200,
+-0x1062001f, 0x28620201, 0x10400005, 0x24020100,
+-0x5062001e, 0x3c130001, 0x1000001e, 0x24040001,
+-0x24020300, 0x50620019, 0x3c130002, 0x10000019,
+-0x24040001, 0x24020600, 0x1062000d, 0x28620601,
+-0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
+-0x10000010, 0x24040001, 0x24020700, 0x1462000d,
+-0x24040001, 0x3c130004, 0x1000000a, 0x3c150008,
+-0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
+-0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
+-0x24040001, 0x24050018, 0x27b0001e, 0xc00457c,
+-0x2003021, 0x24040001, 0x24050018, 0xc00457c,
+-0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140,
+-0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022,
+-0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010,
+-0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b,
+-0xafa20014, 0x3c020004, 0x16620010, 0x3c020001,
+-0x8f840054, 0x24030001, 0x24020002, 0x3c010001,
+-0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001,
+-0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001,
+-0xac246f30, 0x1000004f, 0x2b38825, 0x16620039,
+-0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e,
+-0x24040018, 0x2021, 0x2821, 0xc004ddb,
+-0x34068000, 0x8f830054, 0x8f820054, 0x2b38825,
+-0x10000002, 0x24630032, 0x8f820054, 0x621023,
+-0x2c420033, 0x1440fffc, 0x0, 0x8f830054,
+-0x24020001, 0x3c010001, 0xac226e20, 0x3c010001,
+-0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001,
+-0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001,
+-0x1000002c, 0xac236f30, 0x2821, 0xc004ddb,
+-0x24060404, 0x2021, 0x2405001e, 0x27a60018,
+-0x24020002, 0xc0045be, 0xa7a20018, 0x2021,
+-0x2821, 0x27a60018, 0xc0045be, 0xa7a00018,
+-0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
+-0x3c028000, 0x2221025, 0x2b31825, 0x10000015,
+-0x438825, 0x2221025, 0x2751825, 0x438825,
+-0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98,
+-0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b,
+-0xafb10014, 0x10000007, 0x0, 0x3c110002,
+-0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff,
+-0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e,
+-0x0, 0x3c020001, 0x8c426f1c, 0x10400002,
+-0x3c022000, 0x2228825, 0x8fa8002c, 0x81140,
+-0x3c010002, 0x220821, 0x8c229000, 0x10400003,
+-0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf,
+-0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
+-0x3c010002, 0x220821, 0x8c229008, 0x10400003,
+-0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f,
+-0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
+-0x3c010002, 0x220821, 0xac318ff4, 0x10000135,
+-0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002,
+-0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024,
+-0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff,
+-0x628824, 0x3c010002, 0x3e0821, 0xac318ff0,
+-0x10000124, 0x2201021, 0x2821, 0xc00457c,
+-0x27a60018, 0x24040001, 0x2821, 0xc00457c,
+-0x27a60018, 0x24040001, 0x24050001, 0x27b20020,
+-0xc00457c, 0x2403021, 0x24040001, 0x24050001,
+-0xc00457c, 0x2403021, 0x24040001, 0x24050004,
+-0x27b1001e, 0xc00457c, 0x2203021, 0x24040001,
+-0x24050004, 0xc00457c, 0x2203021, 0x24040001,
+-0x24050005, 0x27b00022, 0xc00457c, 0x2003021,
+-0x24040001, 0x24050005, 0xc00457c, 0x2003021,
+-0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
+-0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
+-0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
+-0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
+-0x24040001, 0x24050018, 0xc00457c, 0x2203021,
+-0x24040001, 0x24050018, 0xc00457c, 0x2203021,
+-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+-0x97a20018, 0x30420004, 0x10400066, 0x3c114000,
+-0x3c030001, 0x8c636f34, 0x24020005, 0x14620067,
+-0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
+-0x2003021, 0x24040001, 0x24050019, 0xc00457c,
+-0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
+-0x10620027, 0x28620401, 0x1040000e, 0x24020200,
+-0x1062001f, 0x28620201, 0x10400005, 0x24020100,
+-0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004,
+-0x24020300, 0x50620019, 0x3c130002, 0x10000019,
+-0x3c020004, 0x24020600, 0x1062000d, 0x28620601,
+-0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
+-0x10000010, 0x3c020004, 0x24020700, 0x1462000d,
+-0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008,
+-0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
+-0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
+-0x3c020004, 0x12620017, 0x3c028000, 0x8f820054,
+-0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001,
+-0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001,
+-0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001,
+-0x16620022, 0x2758825, 0x2021, 0x2821,
+-0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b,
+-0xac306e20, 0x2221025, 0x2b31825, 0x438825,
+-0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001,
+-0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010,
+-0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001,
+-0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007,
+-0x0, 0x3c110002, 0x23e8821, 0x8e318ff0,
+-0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001,
+-0x8c426da8, 0x10400069, 0x0, 0x3c020001,
+-0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825,
+-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
+-0x8c229004, 0x10400003, 0x3c020020, 0x10000005,
+-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
+-0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f,
+-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b,
+-0x2228824, 0x8fa8002c, 0x82940, 0x3c030002,
+-0x651821, 0x8c638ff8, 0x3c024000, 0x621024,
+-0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
+-0x3c010002, 0x250821, 0xac318ff0, 0x10000041,
+-0x2201021, 0x3c020001, 0x8c426da8, 0x10400034,
+-0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c,
+-0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b,
+-0x21023, 0x441024, 0x10600003, 0x518825,
+-0x3c022000, 0x2228825, 0x3c020002, 0x451021,
+-0x8c429004, 0x10400003, 0x3c020020, 0x10000004,
+-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
+-0x8c22900c, 0x10400003, 0x3c020080, 0x10000004,
+-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
+-0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800,
+-0x2228825, 0x3c020001, 0x8c426e34, 0x10400002,
+-0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38,
+-0x10400006, 0x3c020100, 0x10000004, 0x2228825,
+-0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c,
+-0x81140, 0x3c010002, 0x220821, 0xac318ff0,
+-0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+-0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028,
+-0x809021, 0xafbf002c, 0xafb10024, 0xafb00020,
+-0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220,
+-0x24020002, 0x1202005c, 0x2e020003, 0x10400005,
+-0x24020001, 0x1202000a, 0x121940, 0x1000010c,
+-0x0, 0x24020004, 0x120200bf, 0x24020008,
+-0x120200be, 0x128940, 0x10000105, 0x0,
+-0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002,
+-0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024,
+-0x10400038, 0x3c020008, 0x2021024, 0x10400020,
+-0x34840002, 0x3c020002, 0x431021, 0x8c429000,
+-0x10400005, 0x34840020, 0x34840100, 0x3c020020,
+-0x10000006, 0x2028025, 0x2402feff, 0x822024,
+-0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140,
+-0x3c010002, 0x220821, 0x8c229008, 0x10400005,
+-0x3c020001, 0xc23025, 0x3c020080, 0x10000016,
+-0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024,
+-0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024,
+-0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff,
+-0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024,
+-0x3c010002, 0x230821, 0xac209000, 0x3c010002,
+-0x230821, 0xac209008, 0xaf840200, 0xaf860220,
+-0x8f820220, 0x34420002, 0xaf820220, 0x1000000a,
+-0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200,
+-0x2028024, 0x2402fffd, 0x621824, 0xc003daf,
+-0xaf830200, 0x121140, 0x3c010002, 0x220821,
+-0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c,
+-0x10400069, 0x24050004, 0x24040001, 0xc00457c,
+-0x27a60018, 0x24040001, 0x24050005, 0xc00457c,
+-0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001,
+-0x24846e48, 0x30630c00, 0x31a82, 0x30420c00,
+-0x21282, 0xa7a2001a, 0x21080, 0x441021,
+-0x431021, 0xa7a30018, 0x90480000, 0x24020001,
+-0x3103ffff, 0x10620029, 0x28620002, 0x10400005,
+-0x0, 0x10600009, 0x0, 0x1000003d,
+-0x0, 0x10700013, 0x24020003, 0x1062002c,
+-0x0, 0x10000037, 0x0, 0x8f820200,
+-0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
+-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+-0x3c010002, 0xac209004, 0x3c010002, 0x10000032,
+-0xac20900c, 0x8f820200, 0x34420100, 0xaf820200,
+-0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
+-0xaf820220, 0x24020100, 0x3c010002, 0xac229004,
+-0x3c010002, 0x10000024, 0xac20900c, 0x8f820200,
+-0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
+-0x3c030001, 0x431025, 0xaf820220, 0x3c010002,
+-0xac209004, 0x3c010002, 0x10000017, 0xac23900c,
+-0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
+-0x3c030001, 0x431025, 0xaf820220, 0x24020100,
+-0x3c010002, 0xac229004, 0x3c010002, 0x1000000a,
+-0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a,
+-0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010,
+-0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002,
+-0x1000004b, 0xaf820200, 0x128940, 0x3c050002,
+-0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021,
+-0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010,
+-0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
+-0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200,
+-0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024,
+-0x3c010002, 0x310821, 0x10000031, 0xac308ff0,
+-0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020,
+-0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020,
+-0xa21024, 0x10400007, 0x34840020, 0x24020100,
+-0x3c010002, 0x310821, 0xac229004, 0x10000006,
+-0x34840100, 0x3c010002, 0x310821, 0xac209004,
+-0x2402feff, 0x822024, 0x3c020080, 0xa21024,
+-0x10400007, 0x121940, 0x3c020001, 0x3c010002,
+-0x230821, 0xac22900c, 0x10000008, 0xc23025,
+-0x121140, 0x3c010002, 0x220821, 0xac20900c,
+-0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200,
+-0xaf860220, 0x8f820220, 0x34420002, 0xaf820220,
+-0x121140, 0x3c010002, 0x220821, 0xac308ff0,
+-0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+-0x3e00008, 0x27bd0030, 0x0, 0x1821,
+-0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007,
+-0x30420001, 0x10400004, 0x0, 0x8f820044,
+-0x10000003, 0x34420040, 0x8f820044, 0x461024,
+-0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
+-0x8f820044, 0x451024, 0xaf820044, 0x24630001,
+-0x28620008, 0x5440ffee, 0x641007, 0x3e00008,
+-0x0, 0x2c820008, 0x1040001b, 0x0,
+-0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001,
+-0x24426e60, 0x621821, 0x24640004, 0x90620000,
+-0x10400004, 0x0, 0x8f820044, 0x10000003,
+-0x34420040, 0x8f820044, 0x461024, 0xaf820044,
+-0x8f820044, 0x34420020, 0xaf820044, 0x8f820044,
+-0x451024, 0xaf820044, 0x24630001, 0x64102b,
+-0x1440ffee, 0x0, 0x3e00008, 0x0,
+-0x0, 0x0, 0x0, 0x8f8400c4,
+-0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824,
+-0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008,
+-0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004,
+-0x14400012, 0x805021, 0x8ce90000, 0x8f42013c,
+-0x1494823, 0x49182b, 0x94eb0006, 0x10600002,
+-0x25630050, 0x494821, 0x123182b, 0x50400003,
+-0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8,
+-0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008,
+-0x1021, 0x3e00008, 0x0, 0x8f8300e4,
+-0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8,
+-0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8,
+-0x3e00008, 0xaf8200e4, 0x3e00008, 0x0,
+-0x0, 0x0, 0x0, 0x8f880120,
+-0x27624fe0, 0x8f830128, 0x15020002, 0x25090020,
+-0x27694800, 0x11230012, 0x8fa20010, 0xad040000,
+-0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
+-0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
+-0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc,
+-0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc,
+-0x8f430324, 0x1021, 0x24630001, 0x3e00008,
+-0xaf430324, 0x3e00008, 0x0, 0x8f880100,
+-0x276247e0, 0x8f830108, 0x15020002, 0x25090020,
+-0x27694000, 0x1123000f, 0x8fa20010, 0xad040000,
+-0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
+-0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
+-0xad020010, 0xad030014, 0xaf890100, 0x3e00008,
+-0x24020001, 0x8f430328, 0x1021, 0x24630001,
+-0x3e00008, 0xaf430328, 0x3e00008, 0x0,
++0x0,
++0x10000003, 0x0, 0xd, 0xd,
++0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000,
++0x26104000, 0xc0010c0, 0x0, 0xd,
++0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000,
++0x26104000, 0xc0017e0, 0x0, 0xd,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x2000008,
++0x0, 0x800172f, 0x3c0a0001, 0x800172f,
++0x3c0a0002, 0x800172f, 0x0, 0x8002cac,
++0x0, 0x8002c4f, 0x0, 0x800172f,
++0x3c0a0004, 0x800328a, 0x0, 0x8001a52,
++0x0, 0x800394d, 0x0, 0x80038f4,
++0x0, 0x800172f, 0x3c0a0006, 0x80039bb,
++0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f,
++0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6,
++0x0, 0x800172f, 0x3c0a000b, 0x800172f,
++0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb,
++0x0, 0x8002890, 0x0, 0x800172f,
++0x3c0a000e, 0x800208c, 0x0, 0x8001964,
++0x0, 0x8001a04, 0x0, 0x8003ca6,
++0x0, 0x8003c94, 0x0, 0x800172f,
++0x0, 0x800191a, 0x0, 0x800172f,
++0x0, 0x800172f, 0x3c0a0013, 0x800172f,
++0x3c0a0014, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x27bdffe0,
++0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140,
++0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20,
++0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc,
++0x401821, 0x3c020010, 0x3c010001, 0xac236e9c,
++0x10620011, 0x43102b, 0x14400002, 0x3c020020,
++0x3c020008, 0x1062000c, 0x24050100, 0x3c060001,
++0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020,
++0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001,
++0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4,
++0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe,
++0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002,
++0x24639010, 0x3c040001, 0x8c846cc4, 0x431023,
++0x14800002, 0x458021, 0x2610fa38, 0x2402f000,
++0x2028024, 0xc001785, 0x2002021, 0x2022823,
++0x3c040020, 0x821823, 0x651823, 0x247bb000,
++0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf,
++0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf,
++0x3463e000, 0x852023, 0x3c010001, 0xac246ea8,
++0x822023, 0x3c010001, 0xac256e90, 0x52842,
++0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001,
++0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823,
++0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac,
++0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011,
++0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
++0xc001749, 0x0, 0x3c020001, 0x8c426cd0,
++0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200,
++0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004,
++0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021,
++0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38,
++0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
++0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8,
++0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4,
++0x3c020001, 0x8c426cc8, 0x14400003, 0x0,
++0x3c010001, 0xac206cd0, 0xc001151, 0x0,
++0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
++0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
++0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8,
++0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060,
++0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c,
++0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014,
++0x8f860040, 0x3c040001, 0x24845c80, 0x24050200,
++0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821,
++0x8f830040, 0x3c02f000, 0x621824, 0x3c026000,
++0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001,
++0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014,
++0x8f860040, 0x24050300, 0xc002b3b, 0x2003821,
++0x8f820240, 0x3c030001, 0x431025, 0xaf820240,
++0xaf800048, 0x8f820048, 0x14400005, 0x0,
++0xaf800048, 0x8f820048, 0x10400004, 0x0,
++0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c,
++0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8,
++0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001,
++0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001,
++0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001,
++0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001,
++0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001,
++0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c,
++0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138,
++0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150,
++0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140,
++0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014,
++0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014,
++0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0,
++0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014,
++0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac,
++0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c,
++0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff,
++0x1061824, 0xe81024, 0x43102b, 0x10400006,
++0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010,
++0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010,
++0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004,
++0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000,
++0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c,
++0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010,
++0xc002b3b, 0xafa30014, 0xaf800054, 0xaf80011c,
++0x8c020218, 0x30420002, 0x10400009, 0x0,
++0x8c020220, 0x3c030002, 0x34630004, 0x431025,
++0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004,
++0x8c020220, 0x3c030002, 0x34630006, 0x431025,
++0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014,
++0x8c020218, 0x30420010, 0x1040000a, 0x0,
++0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220,
++0x3c03000a, 0x34630004, 0x431025, 0x10000009,
++0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006,
++0x431025, 0xaf420008, 0x8c02021c, 0x34420006,
++0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0,
++0x8f830054, 0x8f820054, 0xaf8000d0, 0xaf8000c0,
++0x10000002, 0x24630064, 0x8f820054, 0x621023,
++0x2c420065, 0x1440fffc, 0x0, 0x8c040208,
++0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490,
++0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008,
++0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
++0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c,
++0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004,
++0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00,
++0x431024, 0x10400021, 0x0, 0x8f8200b4,
++0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001,
++0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c,
++0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001,
++0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014,
++0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b,
++0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
++0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
++0x3c030001, 0x431025, 0xaf820140, 0x96e20472,
++0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482,
++0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b,
++0xafa20014, 0x96f00452, 0x32020001, 0x10400002,
++0xb021, 0x24160001, 0x32020002, 0x54400001,
++0x36d60002, 0x32020008, 0x54400001, 0x36d60004,
++0x32020010, 0x54400001, 0x36d60008, 0x32020020,
++0x54400001, 0x36d60010, 0x32020040, 0x54400001,
++0x36d60020, 0x32020080, 0x54400001, 0x36d60040,
++0x96e60482, 0x30c20200, 0x54400001, 0x36d64000,
++0x96e30472, 0x30620200, 0x10400003, 0x30620100,
++0x10000003, 0x36d62000, 0x54400001, 0x36d61000,
++0x96f00462, 0x32c24000, 0x14400004, 0x3207009b,
++0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000,
++0x1440000d, 0x32020001, 0x3062009b, 0x10e20009,
++0x240e0001, 0x3c040001, 0x24845d20, 0x24051300,
++0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b,
++0xafa00014, 0x32020001, 0x54400001, 0x36d60080,
++0x32020002, 0x54400001, 0x36d60100, 0x32020008,
++0x54400001, 0x36d60200, 0x32020010, 0x54400001,
++0x36d60400, 0x32020080, 0x54400001, 0x36d60800,
++0x8c020218, 0x30420200, 0x10400002, 0x3c020008,
++0x2c2b025, 0x8c020218, 0x30420800, 0x10400002,
++0x3c020080, 0x2c2b025, 0x8c020218, 0x30420400,
++0x10400002, 0x3c020100, 0x2c2b025, 0x8c020218,
++0x30420100, 0x10400002, 0x3c020200, 0x2c2b025,
++0x8c020218, 0x30420080, 0x10400002, 0x3c020400,
++0x2c2b025, 0x8c020218, 0x30422000, 0x10400002,
++0x3c020010, 0x2c2b025, 0x8c020218, 0x30424000,
++0x10400002, 0x3c020020, 0x2c2b025, 0x8c020218,
++0x30421000, 0x10400002, 0x3c020040, 0x2c2b025,
++0x8ee20498, 0x8ee3049c, 0xaf420160, 0xaf430164,
++0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c,
++0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174,
++0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c,
++0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184,
++0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c,
++0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194,
++0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c,
++0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4,
++0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8,
++0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c,
++0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
++0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a,
++0x3484ca00, 0x3821, 0x24020006, 0x24030002,
++0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200,
++0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290,
++0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8,
++0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f,
++0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001,
++0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c,
++0x24051400, 0x21702, 0x24420030, 0xa062022c,
++0x3471021, 0xa040022c, 0x8c070218, 0x2c03021,
++0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014,
++0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80,
++0x24060010, 0x27b10030, 0x2203821, 0x27b30034,
++0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8,
++0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00,
++0x8fa20034, 0x246400ff, 0x852024, 0x831823,
++0x431023, 0xafa20034, 0xafa40030, 0x3c040001,
++0x24845d44, 0x3c050000, 0x24a54100, 0x24060108,
++0x2203821, 0xc0017a3, 0xafb30010, 0x409021,
++0x32c20003, 0x3c010001, 0xac326e80, 0x10400045,
++0x2203821, 0x8f820050, 0x3c030010, 0x431024,
++0x10400016, 0x0, 0x8c020218, 0x30420040,
++0x1040000f, 0x24020001, 0x8f820050, 0x8c030218,
++0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f,
++0xafa20010, 0xafa30014, 0x8f870040, 0x24051500,
++0xc002b3b, 0x2c03021, 0x10000004, 0x0,
++0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
++0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001,
++0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030,
++0x2603821, 0x27b10034, 0x34420a00, 0xaf420010,
++0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70,
++0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90,
++0xc53023, 0x2603821, 0xaf420108, 0xc0017a3,
++0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001,
++0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023,
++0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3,
++0xafb10010, 0x3c040001, 0x24845da4, 0x10000024,
++0x24051600, 0x3c040001, 0x24845dac, 0x3c050001,
++0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023,
++0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc,
++0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c,
++0xc53023, 0x2203821, 0xaf420108, 0xc0017a3,
++0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001,
++0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023,
++0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3,
++0xafb30010, 0x3c040001, 0x24845de4, 0x24051650,
++0x2c03021, 0x3821, 0x3c010001, 0xac226ef8,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020,
++0x10400021, 0x27a70030, 0x3c040001, 0x24845df0,
++0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8,
++0xc53023, 0x24022000, 0xaf42001c, 0x27a20034,
++0xc0017a3, 0xafa20010, 0x21900, 0x31982,
++0x3c040800, 0x641825, 0xae430028, 0x24030010,
++0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040,
++0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010,
++0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0,
++0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c,
++0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001,
++0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10,
++0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c,
++0x24051700, 0xc002b3b, 0x3821, 0x3c020000,
++0x24425cbc, 0x21100, 0x21182, 0x3c030800,
++0x431025, 0xae420028, 0x24020008, 0xaf42003c,
++0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001,
++0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c,
++0x24051800, 0x32c60020, 0xc002b3b, 0x0,
++0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff,
++0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800,
++0x651824, 0x31882, 0x641825, 0x451024,
++0x21082, 0x441025, 0xacc20080, 0x32c20180,
++0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080,
++0x431024, 0x1040000d, 0x0, 0x8f820050,
++0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001,
++0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040,
++0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050,
++0x3c030010, 0x431024, 0x10400016, 0x0,
++0x8c020218, 0x30420040, 0x1040000f, 0x24020001,
++0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001,
++0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014,
++0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021,
++0x10000004, 0x0, 0x3c010001, 0x370821,
++0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001,
++0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023,
++0x8f420008, 0x27b30030, 0x2603821, 0x27b10034,
++0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010,
++0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4,
++0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821,
++0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001,
++0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001,
++0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001,
++0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001,
++0x24845e7c, 0x10000027, 0x24052100, 0x3c040001,
++0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001,
++0x24c6a104, 0xc53023, 0x27b10030, 0x2203821,
++0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001,
++0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001,
++0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c,
++0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4,
++0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4,
++0xc53023, 0x2203821, 0x3c010001, 0xac226f04,
++0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8,
++0x24052150, 0x2c03021, 0x3821, 0x3c010001,
++0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014,
++0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff,
++0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800,
++0x711824, 0x31882, 0x6e1825, 0x511024,
++0x21082, 0x4e1025, 0xae630038, 0xae620078,
++0x8c020218, 0x30420040, 0x14400004, 0x24020001,
++0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
++0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001,
++0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821,
++0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001,
++0xac226efc, 0x511024, 0x21082, 0x3c0e0800,
++0x4e1025, 0xae620050, 0x32c22000, 0x10400006,
++0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024,
++0x1000000f, 0x21082, 0x3c040001, 0x24845ed8,
++0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4,
++0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001,
++0xac226f14, 0x511024, 0x21082, 0x3c0e0800,
++0x4e1025, 0xae620048, 0x32c24000, 0x10400005,
++0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e,
++0x21100, 0x3c040001, 0x24845ef0, 0x3c050001,
++0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023,
++0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001,
++0xac226f08, 0x21100, 0x21182, 0x3c030800,
++0x431025, 0xae420060, 0x3c040001, 0x24845f08,
++0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650,
++0xc53023, 0x27b10030, 0x2203821, 0x27b30034,
++0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff,
++0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468,
++0x3c060000, 0x24c66588, 0xc53023, 0x2203821,
++0x240f021, 0x3c010001, 0xac226edc, 0x4e1024,
++0x21082, 0x3c150800, 0x551025, 0xafae0044,
++0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001,
++0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000,
++0x24c66808, 0x8fae0044, 0xc53023, 0x2203821,
++0x3c010001, 0xac226ed0, 0x4e1024, 0x21082,
++0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010,
++0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810,
++0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023,
++0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024,
++0x21082, 0x551025, 0xafc200c0, 0xc0017a3,
++0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001,
++0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044,
++0xc53023, 0x2203821, 0x3c010001, 0xac226ed4,
++0x4e1024, 0x21082, 0x551025, 0xafc200c8,
++0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c,
++0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20,
++0xc53023, 0x2203821, 0xaf420110, 0xc0017a3,
++0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001,
++0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023,
++0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010,
++0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80,
++0x3c060001, 0x24c65aac, 0xc53023, 0x2203821,
++0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010,
++0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298,
++0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821,
++0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044,
++0x3c010001, 0xac226f18, 0x4e1024, 0x21082,
++0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40,
++0x0, 0xc0027a8, 0x0, 0xac000228,
++0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038,
++0x96e20460, 0xaf420080, 0x32c24000, 0x14400003,
++0x0, 0x96e20480, 0xaf420084, 0x96e70490,
++0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088,
++0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000,
++0x10400003, 0x24020400, 0x10e2000b, 0x0,
++0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f,
++0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
++0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138,
++0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098,
++0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084,
++0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200,
++0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58,
++0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0,
++0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c,
++0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff,
++0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010,
++0x3c010001, 0xac226eb8, 0x21100, 0x21182,
++0x511025, 0xc0018fc, 0xae420000, 0x8f820240,
++0x3c030001, 0x431025, 0xaf820240, 0x3c020000,
++0x24424034, 0xaf820244, 0xaf800240, 0x8f820060,
++0x511024, 0x14400005, 0x3c030800, 0x8f820060,
++0x431024, 0x1040fffd, 0x0, 0xc003c4d,
++0x8821, 0x3c020100, 0xafa20020, 0x8f530018,
++0x240200ff, 0x56620001, 0x26710001, 0x8c020228,
++0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
++0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
++0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010,
++0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
++0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
++0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
++0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
++0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
++0x24070008, 0xa32821, 0xa3482b, 0x822021,
++0x100f809, 0x892021, 0x1440000b, 0x24070008,
++0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
++0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020,
++0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
++0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
++0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
++0x40f809, 0x24c6001c, 0x14400010, 0x0,
++0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
++0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
++0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020,
++0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4,
++0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f,
++0x10400069, 0x3c020700, 0x34423000, 0xafa20028,
++0x8f530018, 0x240200ff, 0x12620002, 0x8821,
++0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
++0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
++0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009,
++0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f,
++0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c,
++0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
++0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
++0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
++0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
++0xa3482b, 0x822021, 0x100f809, 0x892021,
++0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009,
++0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200,
++0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
++0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
++0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
++0x14400010, 0x0, 0x8f420340, 0x24420001,
++0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009,
++0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b,
++0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0,
++0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010,
++0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b,
++0x3821, 0x10000004, 0x0, 0x8c020264,
++0x10400005, 0x0, 0x8f8200a0, 0x30420004,
++0x1440fffa, 0x0, 0x8f820044, 0x34420004,
++0xaf820044, 0x8f420308, 0x24420001, 0xaf420308,
++0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023,
++0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
++0x10400006, 0x24020001, 0x8f420090, 0x8f430144,
++0x431021, 0xaf420090, 0x24020001, 0xaf42008c,
++0x32c20008, 0x10400006, 0x0, 0x8f820214,
++0x3c038100, 0x3042ffff, 0x431025, 0xaf820214,
++0x3c030001, 0x8c636d94, 0x30620002, 0x10400009,
++0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000,
++0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012,
++0xc53023, 0x10400009, 0x0, 0x3c040001,
++0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000,
++0x24c67678, 0x10000008, 0xc53023, 0x3c040001,
++0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000,
++0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034,
++0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc,
++0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100,
++0x21182, 0x431025, 0xae420040, 0x8f8200a0,
++0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c,
++0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001,
++0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001,
++0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001,
++0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b,
++0x24052400, 0x8f820200, 0xafa20010, 0x8f820220,
++0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001,
++0x24846008, 0xc002b3b, 0x24052500, 0x8f830060,
++0x74100b, 0x242000a, 0x200f821, 0x0,
++0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
++0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
++0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001,
++0x24846014, 0x24052600, 0x3021, 0x3821,
++0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014,
++0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
++0x0, 0x3e00008, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x3e00008, 0x0, 0x3e00008, 0x0,
++0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef,
++0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff,
++0xafa40018, 0xa22823, 0xa32824, 0x8ca20000,
++0x1044000a, 0x0, 0xafa50010, 0x8ca20000,
++0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001,
++0x2484601c, 0xc002b3b, 0x24052700, 0x8fbf0218,
++0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
++0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
++0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
++0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
++0xaca30000, 0x10460005, 0xae040000, 0xa08021,
++0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
++0x24846028, 0x24052800, 0x2003021, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021,
++0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
++0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
++0x2821, 0x24030020, 0xe31024, 0x10400002,
++0x63042, 0xa62821, 0x31842, 0x1460fffb,
++0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
++0x45102b, 0x14400003, 0x3c020001, 0x10000008,
++0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
++0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
++0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
++0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
++0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
++0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
++0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
++0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
++0xc002b3b, 0x2403021, 0x8e230000, 0x702021,
++0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
++0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
++0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
++0x8e220000, 0x501021, 0x1000000b, 0xae220000,
++0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
++0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
++0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c,
++0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
++0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
++0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84,
++0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc,
++0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001,
++0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0,
++0xac201ffc, 0x431023, 0x441023, 0x245bb000,
++0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
++0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
++0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0,
++0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001,
++0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d,
++0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
++0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200,
++0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
++0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
++0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
++0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014,
++0xc001916, 0x0, 0x8f820240, 0x34420004,
++0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
++0x571021, 0x904240f4, 0x10400092, 0x2403fffc,
++0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c,
++0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
++0x24846040, 0x70102b, 0x1440001a, 0x27b30018,
++0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
++0xafa30014, 0xc002b3b, 0x2203821, 0x8fa30018,
++0x702021, 0x64102b, 0x10400007, 0x2403021,
++0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
++0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
++0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
++0xae620000, 0x2408821, 0x24053100, 0xafb00010,
++0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
++0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c,
++0x3c040001, 0x2484605c, 0x24120020, 0x3c010001,
++0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018,
++0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50,
++0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
++0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020,
++0x65102b, 0x10400007, 0x0, 0x8c820000,
++0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
++0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
++0x8e220000, 0x521021, 0x1000000b, 0xae220000,
++0x3c100001, 0x26106f50, 0x24053100, 0xafa70010,
++0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
++0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001,
++0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001,
++0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018,
++0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70,
++0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
++0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020,
++0x65102b, 0x10400007, 0x0, 0x8c820000,
++0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
++0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
++0x8e220000, 0x521021, 0x1000000b, 0xae220000,
++0x3c100001, 0x26106f70, 0x24053100, 0xafa70010,
++0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
++0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031,
++0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001,
++0x2652809c, 0x2121023, 0x438024, 0x8fa3001c,
++0x3c040001, 0x24846084, 0x70102b, 0x1440001a,
++0x27b30018, 0x8fb10018, 0x24053000, 0x2403021,
++0xafb00010, 0xafa30014, 0xc002b3b, 0x2203821,
++0x8fa30018, 0x702021, 0x64102b, 0x10400007,
++0x2403021, 0x8cc20000, 0xac620000, 0x24630004,
++0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c,
++0x501023, 0xafa2001c, 0x8e620000, 0x501021,
++0x1000000a, 0xae620000, 0x2408821, 0x24053100,
++0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021,
++0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001,
++0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400,
++0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c,
++0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
++0x27bd0038, 0x0, 0x0, 0x8f820040,
++0x3c03f000, 0x431024, 0x3c036000, 0x14430006,
++0x0, 0x8f820050, 0x2403ff80, 0x431024,
++0x34420055, 0xaf820050, 0x8f820054, 0x244203e8,
++0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004,
++0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4,
++0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008,
++0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008,
++0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054,
++0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024,
++0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024,
++0x36940040, 0x3c020001, 0x8c426da8, 0x10400017,
++0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016,
++0x282a025, 0x3c020001, 0x8c426e44, 0x14400012,
++0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003,
++0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002,
++0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf,
++0x0, 0x10000004, 0x3c020200, 0xc004196,
++0x0, 0x3c020200, 0x2c21024, 0x10400003,
++0x0, 0xc001f4b, 0x0, 0x8f4200d8,
++0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b,
++0x14400003, 0x0, 0xaf4000d8, 0x36940080,
++0x8c030238, 0x1060000c, 0x0, 0x8f4201b0,
++0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006,
++0x0, 0x934205c5, 0x14400003, 0x0,
++0xc001da0, 0x0, 0x8fbf0010, 0x3e00008,
++0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8,
++0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059,
++0x0, 0x3c020001, 0x571021, 0x904240f0,
++0x10400026, 0x24070008, 0x8f440170, 0x8f450174,
++0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010,
++0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
++0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
++0x370821, 0xa02240f0, 0x8f820124, 0xafa20010,
++0x8f820128, 0x3c040001, 0x24846128, 0xafa20014,
++0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
++0x34a50900, 0x1000005c, 0x0, 0x8f420300,
++0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c,
++0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170,
++0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
++0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
++0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
++0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
++0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
++0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120,
++0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036,
++0x0, 0x8f420300, 0x8f43002c, 0x24420001,
++0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
++0xaf430038, 0x3c010001, 0x370821, 0xa02040f1,
++0x3c010001, 0x370821, 0xa02040f0, 0x10000026,
++0xaf400034, 0x934205c1, 0x1040001d, 0x0,
++0xa34005c1, 0x8f820040, 0x30420001, 0x14400008,
++0x2021, 0x8c030104, 0x24020001, 0x50620005,
++0x24040001, 0x8c020264, 0x10400003, 0x801021,
++0x24040001, 0x801021, 0x10400006, 0x0,
++0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008,
++0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
++0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
++0x3c010001, 0x370821, 0xa02040f0, 0x3c010001,
++0x370821, 0xa02040f1, 0x8f420000, 0x10400007,
++0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
++0x0, 0x10000005, 0x0, 0xaf800048,
++0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
++0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060,
++0x8f420000, 0x10400003, 0x0, 0x10000002,
++0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008,
++0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8,
++0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029,
++0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c,
++0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
++0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
++0x14400011, 0x24020001, 0x3c010001, 0x370821,
++0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
++0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044,
++0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300,
++0x1000000f, 0x0, 0x8f420304, 0x24420001,
++0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
++0x3c010001, 0x370821, 0xa02040f2, 0x10000004,
++0xaf400078, 0x3c010001, 0x370821, 0xa02040f2,
++0x8f420000, 0x10400007, 0x0, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x3c03feff, 0x3463ffff,
++0x431024, 0xaf820060, 0x8f420000, 0x10400003,
++0x0, 0x10000002, 0xaf80004c, 0xaf800048,
++0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
++0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8,
++0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
++0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5,
++0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b,
++0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002,
++0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001,
++0x8c636d98, 0x34420002, 0xaf420004, 0x24020001,
++0x14620003, 0x3c020600, 0x10000002, 0x34423000,
++0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034,
++0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff,
++0x11420002, 0x1821, 0x25430001, 0x8c020228,
++0x609821, 0x1662000e, 0x3c050009, 0x8f42033c,
++0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
++0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014,
++0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500,
++0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020,
++0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
++0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
++0x1040001b, 0xa821, 0xe09021, 0x265e04c0,
++0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004,
++0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021,
++0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008,
++0xa32821, 0xa3482b, 0x822021, 0x100f809,
++0x892021, 0x54400006, 0x24150001, 0x8f820054,
++0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0,
++0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378,
++0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
++0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124,
++0x3c040001, 0x24846118, 0xafa20014, 0x8d460000,
++0x3c050009, 0x10000035, 0x34a50600, 0x8f420308,
++0x24150001, 0x24420001, 0xaf420308, 0x8f420308,
++0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054,
++0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016,
++0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c,
++0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010,
++0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c,
++0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
++0x0, 0x8f820054, 0x2221023, 0x2c4203e9,
++0x1440ffee, 0x0, 0x32a200ff, 0x14400011,
++0x3c050009, 0x8f420378, 0x24420001, 0xaf420378,
++0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034,
++0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
++0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
++0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec,
++0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029,
++0x36100040, 0x3c020400, 0x2c21024, 0x10400013,
++0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4,
++0x14640006, 0x36100040, 0x8f420270, 0x8f430274,
++0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250,
++0x8f430254, 0x8f440270, 0x8f450274, 0x10000012,
++0x3a100020, 0x1000002b, 0x2028024, 0x8f420250,
++0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024,
++0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021,
++0x36100040, 0x8f420250, 0x8f430254, 0x8f440270,
++0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019,
++0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011,
++0x28420033, 0x8f420004, 0x30420001, 0x10400009,
++0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf,
++0x2028024, 0x1000000b, 0x36100040, 0x10000009,
++0x36100060, 0x8f4200d4, 0x36100040, 0x24430001,
++0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4,
++0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024,
++0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
++0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
++0x27bd0058, 0x3e00008, 0x0, 0x3c020001,
++0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
++0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
++0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001,
++0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004,
++0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004,
++0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004,
++0x24020001, 0x14620003, 0x3c020600, 0x10000002,
++0x34423000, 0x34421000, 0xafa20020, 0x1821,
++0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
++0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
++0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
++0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
++0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
++0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021,
++0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
++0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
++0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
++0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
++0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
++0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
++0x24070008, 0xa32821, 0xa3482b, 0x822021,
++0x100f809, 0x892021, 0x54400006, 0x24130001,
++0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
++0x0, 0x326200ff, 0x54400017, 0xaf520018,
++0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
++0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
++0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
++0x8d460000, 0x10000035, 0x34a50600, 0x8f420308,
++0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
++0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054,
++0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016,
++0x9821, 0x3c150020, 0x24110010, 0x8f42000c,
++0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
++0xafb20014, 0x551025, 0xafa20018, 0x8f42010c,
++0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
++0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
++0x1440ffee, 0x0, 0x326200ff, 0x14400011,
++0x0, 0x8f420378, 0x24420001, 0xaf420378,
++0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24846120, 0x3c050009,
++0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
++0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec,
++0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018,
++0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4,
++0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270,
++0x8f430274, 0x8f4401b8, 0x10640021, 0x0,
++0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0,
++0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4,
++0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0,
++0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001,
++0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001,
++0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001,
++0x8f420004, 0x30420001, 0x10400008, 0x0,
++0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1,
++0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4,
++0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5,
++0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1,
++0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1,
++0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c,
++0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001,
++0x5462001f, 0x2021, 0x3c020001, 0x90426cf0,
++0x1443001b, 0x24040005, 0x10000019, 0x24040006,
++0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b,
++0x24020001, 0x3c030001, 0x90636cf1, 0x54620010,
++0x2021, 0x3c020001, 0x90426cf0, 0x1443000c,
++0x24040003, 0x1000000a, 0x24040004, 0x3c030001,
++0x90636cf1, 0x14620006, 0x2021, 0x3c020001,
++0x90426cf0, 0x24040001, 0x50440001, 0x24040002,
++0xc00565a, 0x0, 0x2402ff7f, 0x282a024,
++0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
++0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
++0x27bd0050, 0x3e00008, 0x0, 0x3c020001,
++0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
++0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
++0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001,
++0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8,
++0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
++0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
++0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
++0x10000002, 0x34423000, 0x34421000, 0xafa20020,
++0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
++0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
++0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
++0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
++0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014,
++0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
++0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
++0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
++0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
++0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
++0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
++0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
++0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
++0x822021, 0x100f809, 0x892021, 0x54400006,
++0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
++0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
++0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
++0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24846118, 0x3c050009,
++0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
++0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
++0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
++0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
++0x10400016, 0x9821, 0x3c150020, 0x24110010,
++0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
++0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
++0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
++0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
++0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
++0x14400011, 0x0, 0x8f420378, 0x24420001,
++0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
++0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
++0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
++0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001,
++0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
++0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
++0x0, 0x934205c0, 0x8f440250, 0x8f450254,
++0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
++0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
++0x0, 0x8f420250, 0x8f430254, 0x934405c0,
++0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
++0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
++0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
++0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
++0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
++0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
++0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
++0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
++0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
++0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
++0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
++0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
++0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
++0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
++0x10400007, 0x0, 0x934205c0, 0x34420040,
++0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
++0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
++0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
++0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
++0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
++0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
++0x14620005, 0x0, 0x934405c0, 0x42102,
++0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
++0xc005640, 0x0, 0x2402ff7f, 0x282a024,
++0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
++0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
++0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
++0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
++0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
++0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
++0x8c820000, 0xac620000, 0x24630004, 0x65102b,
++0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
++0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
++0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
++0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
++0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
++0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
++0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
++0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
++0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
++0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
++0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
++0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
++0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
++0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
++0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
++0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
++0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
++0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
++0x24040001, 0x24050000, 0x651821, 0x65302b,
++0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
++0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
++0x24090000, 0x401821, 0x1021, 0x882024,
++0xa92824, 0x822025, 0xa32825, 0xaee400c0,
++0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
++0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
++0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
++0x65302b, 0x441021, 0x461021, 0xaee200d0,
++0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
++0x401821, 0x1021, 0x882024, 0xa92824,
++0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
++0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
++0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
++0x24040001, 0x24050000, 0x651821, 0x65302b,
++0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
++0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
++0x1021, 0x882024, 0xa92824, 0x822025,
++0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
++0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
++0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
++0x40f809, 0x24070400, 0x104000f0, 0x3c020400,
++0xafa20020, 0x934205c6, 0x10400089, 0x1821,
++0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
++0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
++0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
++0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
++0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
++0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
++0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
++0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
++0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
++0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
++0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
++0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
++0x24070008, 0xa32821, 0xa3482b, 0x822021,
++0x100f809, 0x892021, 0x54400006, 0x24130001,
++0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
++0x0, 0x326200ff, 0x54400017, 0xaf520018,
++0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
++0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
++0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
++0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
++0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
++0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
++0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
++0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
++0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
++0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
++0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
++0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
++0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
++0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
++0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
++0x24846120, 0x3c050009, 0xafa20014, 0x8d460000,
++0x34a50700, 0xc002b3b, 0x3c03821, 0x1021,
++0x1440005b, 0x24020001, 0x10000065, 0x0,
++0x8f510018, 0x240200ff, 0x12220002, 0x8021,
++0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
++0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
++0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009,
++0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
++0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
++0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
++0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
++0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
++0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
++0xa3482b, 0x822021, 0x100f809, 0x892021,
++0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
++0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009,
++0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
++0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
++0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
++0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
++0x54400011, 0x24020001, 0x8f420340, 0x24420001,
++0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24846104, 0x3c050009,
++0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
++0x2203821, 0x1021, 0x1040000d, 0x24020001,
++0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
++0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
++0xaee20150, 0x10000003, 0x8ee20150, 0x24020001,
++0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
++0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
++0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020,
++0x8f8200b0, 0x30420004, 0x10400068, 0x0,
++0x8f430128, 0x8f820104, 0x14620005, 0x0,
++0x8f430130, 0x8f8200b4, 0x10620006, 0x0,
++0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b,
++0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024,
++0x1040000d, 0x0, 0x8f82011c, 0x34420002,
++0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024,
++0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024,
++0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104,
++0x14620005, 0x0, 0x8f430130, 0x8f8200b4,
++0x10620010, 0x0, 0x8f820104, 0xaf420128,
++0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010,
++0x8f420130, 0x3c040001, 0x24846144, 0xafa20014,
++0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031,
++0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130,
++0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c,
++0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000,
++0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104,
++0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008,
++0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c,
++0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c,
++0x26e60028, 0x40f809, 0x24070400, 0x8f82011c,
++0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
++0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128,
++0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c,
++0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
++0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0,
++0x30420004, 0x10400069, 0x0, 0x8f43012c,
++0x8f820124, 0x14620005, 0x0, 0x8f430134,
++0x8f8200a4, 0x10620006, 0x0, 0x8f820124,
++0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134,
++0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d,
++0x0, 0x8f82011c, 0x34420002, 0xaf82011c,
++0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0,
++0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b,
++0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005,
++0x0, 0x8f430134, 0x8f8200a4, 0x10620010,
++0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
++0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134,
++0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c,
++0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200,
++0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001,
++0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0,
++0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c,
++0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0,
++0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124,
++0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208,
++0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001,
++0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c,
++0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
++0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c,
++0xafa20010, 0x8f420134, 0x3c040001, 0x24846180,
++0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
++0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020,
++0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001,
++0x3c060080, 0x3c050100, 0x8f820070, 0x481024,
++0x1040fffd, 0x0, 0x8f820054, 0x24420005,
++0xaf820078, 0x8c040234, 0x10800016, 0x1821,
++0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
++0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
++0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
++0x0, 0x3c030080, 0x3c010001, 0x370821,
++0xac2040e8, 0x3c010001, 0x370821, 0x1000000b,
++0xa02740f0, 0x3c020001, 0x571021, 0x904240f0,
++0x54400006, 0x661825, 0x3c020001, 0x571021,
++0x904240f1, 0x54400001, 0x661825, 0x8c040230,
++0x10800013, 0x0, 0x3c020001, 0x571021,
++0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
++0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
++0x44102b, 0x14400006, 0x0, 0x3c010001,
++0x370821, 0xac2040ec, 0x10000006, 0x651825,
++0x3c020001, 0x571021, 0x904240f2, 0x54400001,
++0x651825, 0x1060ffbc, 0x0, 0x8f420000,
++0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
++0x1040fffd, 0x0, 0x10000005, 0x0,
++0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
++0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
++0x10400003, 0x0, 0x1000ffa7, 0xaf80004c,
++0x1000ffa5, 0xaf800048, 0x3e00008, 0x0,
++0x0, 0x0, 0x0, 0x27bdffe0,
++0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025,
++0x24040004, 0x8c020114, 0xaf420020, 0xaf840064,
++0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc,
++0x8f820064, 0x30420004, 0x14400005, 0x0,
++0x8c030114, 0x8f420020, 0x1462fff2, 0x0,
++0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x431025, 0xaf820060,
++0x8f420000, 0x10400073, 0x0, 0x1000006f,
++0x0, 0x30c20008, 0x10400020, 0x24040008,
++0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
++0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
++0x30420008, 0x14400005, 0x0, 0x8c03011c,
++0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
++0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
++0x1040fffd, 0x0, 0x10000005, 0x0,
++0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
++0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
++0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
++0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
++0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
++0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
++0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
++0x8f420000, 0x10400007, 0x0, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
++0x30c20010, 0x10400029, 0x24040010, 0x8c020124,
++0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
++0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
++0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
++0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
++0x8f420000, 0x10400007, 0x0, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x34420100, 0xaf820060,
++0x8f420000, 0x10400003, 0x0, 0x1000006c,
++0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001,
++0x10400004, 0x24020001, 0xaf820064, 0x10000064,
++0x0, 0x30c20002, 0x1440000b, 0x3c050003,
++0x3c040001, 0x24846244, 0x34a50500, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0,
++0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c,
++0x10a20048, 0x51080, 0x8c460300, 0x24a20001,
++0x3045003f, 0x24020003, 0xac05022c, 0x61e02,
++0x10620005, 0x24020010, 0x1062001d, 0x30c20fff,
++0x10000039, 0x0, 0x8f4302a8, 0x8f440000,
++0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8,
++0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c,
++0x1040fffd, 0x0, 0x10000005, 0x0,
++0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
++0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
++0x1040001f, 0x0, 0x1000001b, 0x0,
++0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
++0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
++0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c,
++0x1040fffd, 0x0, 0x10000005, 0x0,
++0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
++0x8f820060, 0x34420100, 0xaf820060, 0x8f420000,
++0x10400003, 0x0, 0x10000006, 0xaf80004c,
++0x10000004, 0xaf800048, 0xc002196, 0xc02021,
++0x402821, 0x8c02010c, 0x14a20002, 0x24020002,
++0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
++0x0, 0x8c02010c, 0x14a2ffac, 0x0,
++0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
++0x0, 0x27bdffa0, 0xafb00040, 0x808021,
++0x101602, 0x2442ffff, 0x304300ff, 0x2c620013,
++0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
++0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034,
++0x31080, 0x3c010001, 0x220821, 0x8c226288,
++0x400008, 0x0, 0x101302, 0x30440fff,
++0x24020001, 0x10820005, 0x24020002, 0x1082000c,
++0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004,
++0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204,
++0x3c040001, 0x8c846e80, 0x10000009, 0x34630001,
++0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001,
++0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28,
++0x21100, 0x21182, 0xaf430004, 0x3c030800,
++0x431025, 0xac820038, 0x8f840054, 0x41442,
++0x41c82, 0x431021, 0x41cc2, 0x431023,
++0x41d02, 0x431021, 0x41d42, 0x431023,
++0x10000009, 0xaf420208, 0x3c040001, 0x24846250,
++0x34a51000, 0x2003021, 0x3821, 0xafa00010,
++0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001,
++0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028,
++0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
++0xc002518, 0x2002021, 0x10000216, 0x0,
++0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
++0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
++0x21080, 0x8c430300, 0x25420001, 0x3042003f,
++0xafa20034, 0xac02022c, 0xafa50028, 0xc002518,
++0xafa3002c, 0x10000203, 0x0, 0x27b00028,
++0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
++0xc002657, 0x2002021, 0x100001fa, 0x0,
++0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
++0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
++0x21080, 0x8c430300, 0x25420001, 0x3042003f,
++0xafa20034, 0xac02022c, 0xafa50028, 0xc002657,
++0xafa3002c, 0x100001e7, 0x0, 0x101302,
++0x30430fff, 0x24020001, 0x10620005, 0x24020002,
++0x1062001e, 0x3c020002, 0x10000033, 0x3c050003,
++0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025,
++0x8f820228, 0x3c010001, 0x370821, 0xac2238d8,
++0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc,
++0x8f820230, 0x3c010001, 0x370821, 0xac2238e0,
++0x8f820234, 0x3c010001, 0x370821, 0xac2238e4,
++0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230,
++0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024,
++0x10400012, 0x3c02fffd, 0x3c020001, 0x571021,
++0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021,
++0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021,
++0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021,
++0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff,
++0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c,
++0x34a51100, 0x2003021, 0x3821, 0xafa00010,
++0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001,
++0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302,
++0x30450fff, 0x24020001, 0x10a20005, 0x24020002,
++0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003,
++0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004,
++0x2c4b025, 0x621824, 0x34630008, 0xaf830220,
++0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb,
++0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024,
++0xaf820220, 0x10000009, 0xaf450298, 0x3c040001,
++0x24846268, 0x34a51200, 0x2003021, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc,
++0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc,
++0x27840208, 0x24050200, 0xc002bbf, 0x24060008,
++0x27440224, 0x24050200, 0xc002bbf, 0x24060008,
++0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169,
++0x8f4202c4, 0x101302, 0x30430fff, 0x24020001,
++0x10620011, 0x28620002, 0x50400005, 0x24020002,
++0x10600007, 0x0, 0x10000017, 0x0,
++0x1062000f, 0x0, 0x10000013, 0x0,
++0x8c060248, 0x2021, 0xc005104, 0x24050004,
++0x10000007, 0x0, 0x8c060248, 0x2021,
++0xc005104, 0x24050004, 0x10000010, 0x0,
++0x8c06024c, 0x2021, 0xc005104, 0x24050001,
++0x1000000a, 0x0, 0x3c040001, 0x24846274,
++0x3c050003, 0x34a51300, 0x2003021, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0,
++0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0,
++0xc002426, 0x0, 0x10000136, 0x0,
++0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8,
++0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014,
++0xafa20018, 0x8f420108, 0x26e60028, 0x40f809,
++0x24070400, 0x1040fff5, 0x0, 0x10000125,
++0x0, 0x3c03ffff, 0x34637fff, 0x8f420368,
++0x8f440360, 0x2c3b024, 0x1821, 0xaf400058,
++0xaf40005c, 0xaf400060, 0xaf400064, 0x441023,
++0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020,
++0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
++0xafaa003c, 0x27c30001, 0x8c020228, 0x609021,
++0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
++0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
++0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010,
++0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
++0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
++0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
++0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
++0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
++0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
++0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
++0x24070008, 0xa32821, 0xa3482b, 0x822021,
++0x100f809, 0x892021, 0x54400006, 0x24130001,
++0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
++0x0, 0x326200ff, 0x54400017, 0xaf520018,
++0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
++0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124,
++0x3c040001, 0x24846218, 0x3c050009, 0xafa20014,
++0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
++0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
++0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
++0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
++0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
++0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
++0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
++0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
++0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
++0x326200ff, 0x14400011, 0x0, 0x8f420378,
++0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
++0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001,
++0x24846220, 0x3c050009, 0xafa20014, 0x8d460000,
++0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0,
++0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8,
++0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8,
++0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
++0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8,
++0x8f820220, 0x30420008, 0x14400002, 0x24020001,
++0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001,
++0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff,
++0x3442ffff, 0x2021824, 0x32c20180, 0x14400006,
++0x3402fffb, 0x43102b, 0x14400003, 0x0,
++0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280,
++0x3c050003, 0x34a51500, 0x2003021, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700,
++0x34421000, 0x101e02, 0x621825, 0xafa30020,
++0x8f510018, 0x240200ff, 0x12220002, 0x8021,
++0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
++0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
++0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009,
++0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
++0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
++0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
++0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
++0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
++0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
++0xa3482b, 0x822021, 0x100f809, 0x892021,
++0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
++0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009,
++0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
++0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
++0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
++0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
++0x14400010, 0x0, 0x8f420340, 0x24420001,
++0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24846204, 0x3c050009,
++0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
++0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0,
++0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0,
++0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054,
++0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044,
++0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8,
++0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8,
++0x354a8320, 0x90870000, 0x24840001, 0x3021,
++0x1071026, 0x30420001, 0x10400002, 0x81842,
++0x6a1826, 0x604021, 0x24c60001, 0x2cc20008,
++0x1440fff7, 0x73842, 0x25290001, 0x125102b,
++0x1440fff0, 0x0, 0x1001021, 0x3e00008,
++0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
++0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
++0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200,
++0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff,
++0x431024, 0x34420004, 0xaf820220, 0x8f820200,
++0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004,
++0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360,
++0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c,
++0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0,
++0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8,
++0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360,
++0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368,
++0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c,
++0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
++0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf,
++0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc,
++0x240203e8, 0x24040002, 0x24030001, 0xaf420294,
++0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008,
++0x10400004, 0x0, 0xaf430298, 0x10000003,
++0x3021, 0xaf440298, 0x3021, 0x3c030001,
++0x661821, 0x90636d00, 0x3461021, 0x24c60001,
++0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821,
++0x24c60001, 0x8f820040, 0x24040080, 0x24050080,
++0x21702, 0x24420030, 0xa062022c, 0x3461021,
++0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004,
++0x14400006, 0x0, 0x8f820220, 0x3c0308ff,
++0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c,
++0x30e20004, 0x14400006, 0x0, 0x8f820200,
++0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
++0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
++0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
++0x27bd0050, 0x0, 0x0, 0xaf400104,
++0x24040001, 0x410c0, 0x2e21821, 0x24820001,
++0x3c010001, 0x230821, 0xa42234d0, 0x402021,
++0x2c820080, 0x1440fff8, 0x410c0, 0x24020001,
++0x3c010001, 0x370821, 0xa42038d0, 0xaf420100,
++0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234,
++0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014,
++0xafb00010, 0x8f420104, 0x28420005, 0x10400026,
++0x808021, 0x3c020001, 0x8f430104, 0x344230d0,
++0x2e22021, 0x318c0, 0x621821, 0x2e31821,
++0x83102b, 0x10400015, 0x1021, 0x96070000,
++0x24840006, 0x24660006, 0x9482fffc, 0x14470009,
++0x2821, 0x9483fffe, 0x96020002, 0x14620006,
++0xa01021, 0x94820000, 0x96030004, 0x431026,
++0x2c450001, 0xa01021, 0x14400009, 0x24840008,
++0x86102b, 0x1440fff0, 0x1021, 0x304200ff,
++0x14400030, 0x24020001, 0x1000002e, 0x1021,
++0x1000fffa, 0x24020001, 0x2002021, 0xc00240c,
++0x24050006, 0x3042007f, 0x218c0, 0x2e31021,
++0x3c010001, 0x220821, 0x942230d0, 0x1040fff2,
++0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0,
++0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000,
++0x610c0, 0x572021, 0x882021, 0x94820000,
++0x14470009, 0x2821, 0x94830002, 0x96020002,
++0x14620006, 0xa01021, 0x94820004, 0x96030004,
++0x431026, 0x2c450001, 0xa01021, 0x14400007,
++0x610c0, 0x2e21021, 0x3c060001, 0xc23021,
++0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2,
++0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008,
++0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0,
++0x801021, 0xafb00030, 0x24500002, 0x2002021,
++0x24050006, 0xafb10034, 0x408821, 0xafbf0048,
++0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c,
++0xafb20038, 0x3047007f, 0x710c0, 0x2e21021,
++0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c,
++0xa03021, 0x3c090001, 0x352934d2, 0x96280002,
++0x510c0, 0x572021, 0x892021, 0x94820000,
++0x14480009, 0x3021, 0x94830002, 0x96020002,
++0x14620006, 0xc01021, 0x94820004, 0x96030004,
++0x431026, 0x2c460001, 0xc01021, 0x14400007,
++0x510c0, 0x2e21021, 0x3c050001, 0xa22821,
++0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021,
++0x10c00014, 0x610c0, 0x571821, 0x3c010001,
++0x230821, 0x8c2334d0, 0x571021, 0xafa30010,
++0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001,
++0x24846394, 0xafa20014, 0x8e260000, 0x8e270004,
++0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063,
++0x3c020800, 0x8f450100, 0x10a00006, 0x510c0,
++0x2e21021, 0x3c010001, 0x220821, 0x942234d0,
++0xaf420100, 0xa03021, 0x14c00011, 0x628c0,
++0x710c0, 0x2e21021, 0xafa70010, 0x3c010001,
++0x220821, 0x942230d0, 0x3c040001, 0x248463a0,
++0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004,
++0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800,
++0xb71821, 0x3c020001, 0x96040000, 0x344234d2,
++0x621821, 0xa4640000, 0x8e020002, 0x720c0,
++0xac620002, 0x2e41021, 0x3c030001, 0x621821,
++0x946330d0, 0x2e51021, 0x3c010001, 0x220821,
++0xa42334d0, 0x2e41021, 0x3c010001, 0x220821,
++0xa42630d0, 0x8f420104, 0x24420001, 0x28420080,
++0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001,
++0x348430d2, 0x96030000, 0x210c0, 0x571021,
++0x441021, 0xa4430000, 0x8e030002, 0xac430002,
++0x8f420104, 0x24420001, 0xaf420104, 0x3c020002,
++0x2c21024, 0x10400011, 0x72142, 0x3c030001,
++0x346338d8, 0x24020003, 0x441023, 0x21080,
++0x572021, 0x832021, 0x571021, 0x431021,
++0x30e5001f, 0x8c430000, 0x24020001, 0xa21004,
++0x621825, 0x1000000c, 0xac830000, 0x24020003,
++0x441023, 0x21080, 0x5c2821, 0x5c1021,
++0x30e4001f, 0x8c430228, 0x24020001, 0x821004,
++0x621825, 0xaca30228, 0x3c020800, 0x34421000,
++0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020,
++0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
++0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
++0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
++0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009,
++0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
++0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
++0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
++0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
++0x9821, 0xe08821, 0x263504c0, 0x8f440178,
++0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
++0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
++0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
++0xa3482b, 0x822021, 0x100f809, 0x892021,
++0x54400006, 0x24130001, 0x8f820054, 0x2021023,
++0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
++0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
++0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
++0xafa20010, 0x8f820124, 0x3c040001, 0x24846368,
++0x3c050009, 0xafa20014, 0x8d460000, 0x10000033,
++0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
++0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
++0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
++0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
++0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
++0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
++0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
++0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
++0x1440ffef, 0x0, 0x326200ff, 0x14400011,
++0x0, 0x8f420378, 0x24420001, 0xaf420378,
++0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
++0x8f820124, 0x3c040001, 0x24846370, 0x3c050009,
++0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
++0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4,
++0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4,
++0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
++0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
++0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021,
++0xafb00040, 0x24500002, 0x2002021, 0x24050006,
++0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054,
++0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048,
++0x3048007f, 0x810c0, 0x2e21021, 0x3c060001,
++0xc23021, 0x94c630d0, 0x10c0001c, 0x3821,
++0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0,
++0x572021, 0x8a2021, 0x94820000, 0x14490009,
++0x2821, 0x94830002, 0x96020002, 0x14620006,
++0xa01021, 0x94820004, 0x96030004, 0x431026,
++0x2c450001, 0xa01021, 0x14400008, 0x610c0,
++0xc03821, 0x2e21021, 0x3c060001, 0xc23021,
++0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011,
++0xafa70028, 0x810c0, 0x2e21021, 0xafa80010,
++0x3c010001, 0x220821, 0x942230d0, 0x3c040001,
++0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004,
++0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075,
++0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021,
++0x3c030001, 0x621821, 0x946334d0, 0x710c0,
++0x2e21021, 0x3c010001, 0x220821, 0xa42334d0,
++0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001,
++0x621821, 0x946334d0, 0x810c0, 0x2e21021,
++0x3c010001, 0x220821, 0xa42330d0, 0x3c040001,
++0x348430d0, 0x8f430100, 0x610c0, 0x2e21021,
++0x3c010001, 0x220821, 0xa42334d0, 0x8f420104,
++0x2e43821, 0x2821, 0x18400029, 0xaf460100,
++0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009,
++0x2021, 0x94c3fffe, 0x96020002, 0x14620006,
++0x801021, 0x94c20000, 0x96030004, 0x431026,
++0x2c440001, 0x801021, 0x50400014, 0x24a50001,
++0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b,
++0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe,
++0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff,
++0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104,
++0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104,
++0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008,
++0x810c0, 0x2e21021, 0x3c010001, 0x220821,
++0x942230d0, 0x14400023, 0x3c020800, 0x3c020002,
++0x2c21024, 0x10400012, 0x82142, 0x3c030001,
++0x346338d8, 0x24020003, 0x441023, 0x21080,
++0x572021, 0x832021, 0x571021, 0x431021,
++0x3105001f, 0x24030001, 0x8c420000, 0xa31804,
++0x31827, 0x431024, 0x1000000d, 0xac820000,
++0x24020003, 0x441023, 0x21080, 0x5c2821,
++0x5c1021, 0x3104001f, 0x24030001, 0x8c420228,
++0x831804, 0x31827, 0x431024, 0xaca20228,
++0x3c020800, 0x34422000, 0x1821, 0xafa20020,
++0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002,
++0xafab0034, 0x27c30001, 0x8c020228, 0x609021,
++0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
++0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
++0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010,
++0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
++0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
++0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
++0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
++0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
++0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c,
++0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
++0x24070008, 0xa32821, 0xa3482b, 0x822021,
++0x100f809, 0x892021, 0x54400006, 0x24130001,
++0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
++0x0, 0x326200ff, 0x54400017, 0xaf520018,
++0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
++0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124,
++0x3c040001, 0x24846368, 0x3c050009, 0xafa20014,
++0x8d660000, 0x10000033, 0x34a50600, 0x8f420308,
++0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
++0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
++0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
++0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
++0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
++0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
++0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
++0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
++0x326200ff, 0x14400011, 0x0, 0x8f420378,
++0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
++0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001,
++0x24846370, 0x3c050009, 0xafa20014, 0x8d660000,
++0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8,
++0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4,
++0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058,
++0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
++0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
++0x0, 0x0, 0x0, 0x27bdffe0,
++0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000,
++0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8,
++0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100,
++0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114,
++0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128,
++0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec,
++0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4,
++0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021,
++0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c,
++0x3c040001, 0x24846470, 0x3c050001, 0x34420001,
++0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
++0x34a50100, 0xc002b3b, 0x3821, 0x8c020218,
++0x30420040, 0x10400014, 0x0, 0x8f82011c,
++0x3c040001, 0x2484647c, 0x3c050001, 0x34420004,
++0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
++0x10000007, 0x34a50200, 0x3c040001, 0x24846484,
++0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300,
++0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014,
++0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002,
++0x24680020, 0x27684800, 0x8f820128, 0x11020004,
++0x0, 0x8f820124, 0x15020007, 0x0,
++0x8f430334, 0x1021, 0x24630001, 0xaf430334,
++0x10000039, 0x8f430334, 0xac640000, 0xac650004,
++0xac660008, 0xa467000e, 0xac690018, 0xac6a001c,
++0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc,
++0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000,
++0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f,
++0x10400018, 0x3c020001, 0x8c830004, 0x2c620010,
++0x10400013, 0x3c020001, 0x24630001, 0xac830004,
++0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
++0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
++0x14440015, 0x24020001, 0x8f820128, 0x24420020,
++0xaf820128, 0x8f820128, 0x1000000f, 0x24020001,
++0x3c020001, 0x344230c8, 0x2e21021, 0x54820004,
++0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021,
++0x402021, 0x24020001, 0xaf4400f4, 0xac890000,
++0xac820004, 0x24020001, 0x3e00008, 0x0,
++0x3e00008, 0x0, 0x8fa90010, 0x8f83010c,
++0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0,
++0x14620002, 0x24680020, 0x27684000, 0x8f820108,
++0x11020004, 0x0, 0x8f820104, 0x15020007,
++0x0, 0x8f430338, 0x1021, 0x24630001,
++0xaf430338, 0x10000035, 0x8f430338, 0xac640000,
++0xac650004, 0xac660008, 0xa467000e, 0xac690018,
++0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100,
++0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019,
++0x31220006, 0x10400018, 0x3c020001, 0x8c830004,
++0x2c620010, 0x10400013, 0x3c020001, 0x24630001,
++0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021,
++0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
++0x2e21021, 0x14440015, 0x24020001, 0x8f820108,
++0x24420020, 0xaf820108, 0x8f820108, 0x1000000f,
++0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021,
++0x54820004, 0x24820008, 0x3c020001, 0x34422cc0,
++0x2e21021, 0x402021, 0x24020001, 0xaf4400ec,
++0xac890000, 0xac820004, 0x24020001, 0x3e00008,
++0x0, 0x3e00008, 0x0, 0x27bdffd8,
++0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024,
++0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104,
++0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100,
++0x2403021, 0x2203821, 0xafa20010, 0xc002b3b,
++0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c,
++0x3c040001, 0x24846498, 0xafa20014, 0x8e060000,
++0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510,
++0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001,
++0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014,
++0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00,
++0x2221024, 0x3c030800, 0x54430016, 0x3c030200,
++0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200,
++0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030,
++0x3021, 0x3821, 0x36420002, 0xaf82011c,
++0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024,
++0x0, 0x2c31024, 0x1040000d, 0x2231024,
++0x1040000b, 0x36420002, 0xaf82011c, 0x36220001,
++0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330,
++0x24420001, 0xaf420330, 0x10000015, 0x8f420330,
++0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010,
++0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0,
++0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002,
++0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
++0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
++0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
++0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001,
++0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020,
++0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0,
++0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021,
++0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014,
++0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001,
++0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004,
++0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018,
++0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500,
++0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001,
++0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024,
++0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac,
++0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001,
++0x2484650c, 0x3c050001, 0x34a5f030, 0x3021,
++0x3821, 0x36420002, 0xaf82011c, 0x36220001,
++0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010,
++0xc002b3b, 0xafa00014, 0x10000024, 0x0,
++0x2c31024, 0x1040000d, 0x2231024, 0x1040000b,
++0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
++0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001,
++0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001,
++0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014,
++0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b,
++0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
++0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
++0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
++0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
++0x27bd0028, 0x6021, 0x5021, 0x3021,
++0x2821, 0x6821, 0x4821, 0x7821,
++0x7021, 0x8f880124, 0x8f870104, 0x1580002e,
++0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120,
++0x10460029, 0x0, 0x3c040001, 0x8c846ee4,
++0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004,
++0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e,
++0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014,
++0x10000012, 0x24c60020, 0x10400017, 0x0,
++0x3c040001, 0x8c846ee4, 0x8d020000, 0x8d030004,
++0xac820000, 0xac830004, 0x8d020008, 0xac820008,
++0x9502000e, 0xa482000e, 0x8d020010, 0x25060020,
++0xac820010, 0x8d020014, 0x240c0001, 0xc01821,
++0xac820014, 0x27624fe0, 0x43102b, 0x54400001,
++0x27634800, 0x603021, 0x1540002f, 0x31620100,
++0x11200014, 0x31628000, 0x8f820100, 0x1045002a,
++0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000,
++0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008,
++0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010,
++0x240a0001, 0xac820010, 0x8ca20014, 0x10000012,
++0x24a50020, 0x10400018, 0x31620100, 0x3c040001,
++0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000,
++0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e,
++0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010,
++0x8ce20014, 0x240a0001, 0xa01821, 0xac820014,
++0x276247e0, 0x43102b, 0x54400001, 0x27634000,
++0x602821, 0x31620100, 0x5440001d, 0x31621000,
++0x11a00009, 0x31a20800, 0x10400004, 0x25020020,
++0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124,
++0x8f880124, 0x6821, 0x11800011, 0x31621000,
++0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004,
++0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4,
++0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021,
++0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000,
++0x1440ff82, 0x0, 0x1120000f, 0x31220800,
++0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000,
++0x3c020002, 0x1221024, 0x10400004, 0x24e20020,
++0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104,
++0x8f870104, 0x4821, 0x1140ff70, 0x0,
++0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004,
++0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4,
++0x9482000e, 0xaf82009c, 0x8c820010, 0x5021,
++0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014,
++0x3e00008, 0x0, 0x6021, 0x5821,
++0x3021, 0x2821, 0x6821, 0x5021,
++0x7821, 0x7021, 0x8f880124, 0x8f870104,
++0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014,
++0x31220800, 0x8f820120, 0x10460029, 0x0,
++0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004,
++0xac820000, 0xac830004, 0x8cc20008, 0xac820008,
++0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001,
++0xac820010, 0x8cc20014, 0x10000012, 0x24c60020,
++0x10400017, 0x0, 0x3c040001, 0x8c846ee4,
++0x8d020000, 0x8d030004, 0xac820000, 0xac830004,
++0x8d020008, 0xac820008, 0x9502000e, 0xa482000e,
++0x8d020010, 0x25060020, 0xac820010, 0x8d020014,
++0x240c0001, 0xc01821, 0xac820014, 0x27624fe0,
++0x43102b, 0x54400001, 0x27634800, 0x603021,
++0x1560002f, 0x31220100, 0x11400014, 0x31228000,
++0x8f820100, 0x1045002a, 0x31220100, 0x3c040001,
++0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000,
++0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e,
++0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010,
++0x8ca20014, 0x10000012, 0x24a50020, 0x10400018,
++0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000,
++0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008,
++0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010,
++0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001,
++0xa01821, 0xac820014, 0x276247e0, 0x43102b,
++0x54400001, 0x27634000, 0x602821, 0x31220100,
++0x5440001d, 0x31221000, 0x11a00009, 0x31a20800,
++0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000,
++0x25020020, 0xaf820124, 0x8f880124, 0x6821,
++0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4,
++0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084,
++0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac,
++0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010,
++0x8c8f0014, 0x31221000, 0x14400022, 0x0,
++0x1140000f, 0x31420800, 0x10400004, 0x3c020002,
++0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024,
++0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4,
++0x24e20020, 0xaf820104, 0x8f870104, 0x5021,
++0x11600010, 0x0, 0x3c040001, 0x8c846ee0,
++0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
++0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c,
++0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010,
++0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024,
++0x1040ff5c, 0x0, 0x8f820054, 0x24420005,
++0xaf820078, 0x8c040234, 0x10800016, 0x1821,
++0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
++0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
++0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
++0x24020001, 0x3c030080, 0x3c010001, 0x370821,
++0xac2040e8, 0x3c010001, 0x370821, 0x1000000c,
++0xa02240f0, 0x3c020001, 0x571021, 0x904240f0,
++0x14400006, 0x3c020080, 0x3c020001, 0x571021,
++0x904240f1, 0x10400002, 0x3c020080, 0x621825,
++0x8c040230, 0x10800013, 0x0, 0x3c020001,
++0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
++0x370821, 0xac2240ec, 0x3c020001, 0x571021,
++0x8c4240ec, 0x44102b, 0x14400006, 0x0,
++0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
++0x781825, 0x3c020001, 0x571021, 0x904240f2,
++0x54400001, 0x781825, 0x1060ff1a, 0x0,
++0x8f420000, 0x10400007, 0x0, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x431025, 0xaf820060,
++0x8f420000, 0x10400003, 0x0, 0x1000ff05,
++0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008,
++0x0, 0x0, 0x0, 0x3c020001,
++0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012,
++0xafb00010, 0x3c100001, 0x26106f90, 0x2002021,
++0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001,
++0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250,
++0x24022000, 0xac100254, 0xac020258, 0x24020001,
++0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010,
++0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec,
++0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
++0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
++0xad260010, 0xad270014, 0xad230018, 0xad28001c,
++0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90,
++0x122102b, 0x10400003, 0x0, 0x3c090001,
++0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000,
++0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec,
++0xad220004, 0xac090250, 0x3e00008, 0x0,
++0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec,
++0x3c020001, 0x8c426d10, 0xafb10014, 0x808821,
++0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
++0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
++0xae020000, 0x3c020001, 0x8c426d10, 0xc09821,
++0xe0a821, 0x10800006, 0xae020004, 0x26050008,
++0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0,
++0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0,
++0x3c030001, 0x24636f90, 0x203102b, 0x10400003,
++0x0, 0x3c100001, 0x8e106ee8, 0x8e220000,
++0xae020000, 0x8e220004, 0xae120008, 0xae020004,
++0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
++0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
++0x203102b, 0x10400003, 0x0, 0x3c100001,
++0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000,
++0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec,
++0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
++0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
++0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
++0x83102b, 0x10400006, 0x0, 0xac800000,
++0x24840004, 0x83102b, 0x5440fffd, 0xac800000,
++0x3e00008, 0x0, 0xa61821, 0xa3102b,
++0x10400007, 0x0, 0x8c820000, 0xaca20000,
++0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004,
++0x3e00008, 0x0, 0x861821, 0x83102b,
++0x10400007, 0x0, 0x8ca20000, 0xac820000,
++0x24840004, 0x83102b, 0x1440fffb, 0x24a50004,
++0x3e00008, 0x0, 0x63080, 0x861821,
++0x83102b, 0x10400006, 0x0, 0xac850000,
++0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
++0x3e00008, 0x0, 0x0, 0x26e50028,
++0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c,
++0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204,
++0x8f4c0200, 0x24640400, 0x64102b, 0x10400008,
++0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004,
++0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff,
++0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c,
++0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204,
++0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200,
++0x821024, 0x34420004, 0xc31824, 0x34630004,
++0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084,
++0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c,
++0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094,
++0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c,
++0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4,
++0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac,
++0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4,
++0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc,
++0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0,
++0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0,
++0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4,
++0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec,
++0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c,
++0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4,
++0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8,
++0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff,
++0x3463fffb, 0x431024, 0xaf820220, 0x30c20004,
++0x14400006, 0x0, 0x8f820200, 0x3c03c0ff,
++0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc,
++0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc,
++0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
++0xafb00020, 0x8f430024, 0x8f420020, 0x10620038,
++0x0, 0x8f430020, 0x8f420024, 0x622023,
++0x4810003, 0x0, 0x8f420040, 0x822021,
++0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
++0x0, 0x8f430040, 0x8f420024, 0x10000005,
++0x621023, 0x8f420030, 0x8f430024, 0x431023,
++0x2442ffff, 0x406021, 0x8c102a, 0x54400001,
++0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024,
++0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c,
++0x24070001, 0xafa70010, 0x84100, 0x1001821,
++0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014,
++0x8f470014, 0x1021, 0x63100, 0xafa70018,
++0xa32821, 0xa3382b, 0x822021, 0x872021,
++0x8f420108, 0x1663021, 0x40f809, 0xc3900,
++0x54400001, 0xaf500024, 0x8f430024, 0x8f420020,
++0x14620018, 0x0, 0x8f420000, 0x10400007,
++0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
++0x0, 0x10000005, 0x0, 0xaf800048,
++0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
++0x2403ffef, 0x431024, 0xaf820060, 0x8f420000,
++0x10400003, 0x0, 0x10000002, 0xaf80004c,
++0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008,
++0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0,
++0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
++0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
++0x10000002, 0x0, 0x8f530020, 0x8f420030,
++0x105300eb, 0x21100, 0x8f43001c, 0x628021,
++0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
++0x9611000a, 0x3246ffff, 0x46102a, 0x10400017,
++0x0, 0x8f8200d8, 0x8f430098, 0x431023,
++0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf,
++0x10400005, 0x0, 0x8f420090, 0x8f430144,
++0x431021, 0xaf420090, 0x8f420090, 0x46102a,
++0x10400006, 0x0, 0x8f420348, 0x24420001,
++0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc,
++0x14400006, 0x0, 0x8f420344, 0x24420001,
++0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2,
++0x1040000b, 0x32c20008, 0x10400008, 0x32220200,
++0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
++0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac,
++0x32220004, 0x1040007f, 0x32220800, 0x10400003,
++0x3247ffff, 0x10000002, 0x24020020, 0x24020004,
++0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
++0x3c030002, 0x431025, 0xafa20018, 0x8f460098,
++0x8f420108, 0x40f809, 0x0, 0x104000b7,
++0x0, 0x8f42009c, 0x8f430094, 0x2421021,
++0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008,
++0x3c034000, 0x8f420094, 0x431025, 0xafa20020,
++0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025,
++0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024,
++0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
++0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
++0x8f440270, 0x8f450274, 0x401821, 0x1021,
++0xa32821, 0xa3302b, 0x822021, 0x862021,
++0x32230060, 0x24020040, 0xaf440270, 0xaf450274,
++0x10620017, 0x2c620041, 0x10400005, 0x24020020,
++0x10620008, 0x24020001, 0x10000026, 0x0,
++0x24020060, 0x10620019, 0x24020001, 0x10000021,
++0x0, 0x8f420278, 0x8f43027c, 0x24630001,
++0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
++0x8f420278, 0x8f43027c, 0x10000016, 0x24020001,
++0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
++0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
++0x8f430284, 0x1000000b, 0x24020001, 0x8f420288,
++0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
++0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c,
++0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff,
++0x2406fff8, 0x8f45013c, 0x441021, 0x24420007,
++0x461024, 0x24840007, 0xaf420094, 0x8f420090,
++0x8f430094, 0x862024, 0x441023, 0x65182b,
++0x14600005, 0xaf420090, 0x8f420094, 0x8f430144,
++0x431023, 0xaf420094, 0x8f420094, 0x10000023,
++0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020,
++0x14400002, 0x24020010, 0x24020002, 0xafa20010,
++0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018,
++0x8f460098, 0x8f420108, 0x40f809, 0x0,
++0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090,
++0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c,
++0x8f440098, 0xa34005c2, 0x651823, 0xaf430090,
++0x451021, 0x86202b, 0x14800005, 0xaf42009c,
++0x8f420098, 0x8f430144, 0x431023, 0xaf420098,
++0x32c20020, 0x10400005, 0x0, 0x8f420358,
++0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030,
++0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
++0xaf420030, 0x8f420030, 0x14530018, 0x0,
++0x8f420000, 0x10400007, 0x0, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x2403fff7, 0x431024,
++0xaf820060, 0x8f420000, 0x10400003, 0x0,
++0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038,
++0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
++0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
++0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
++0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
++0x10000002, 0x0, 0x8f520020, 0x8f420030,
++0x105200b5, 0x21100, 0x8f43001c, 0x628021,
++0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
++0x9607000a, 0x3226ffff, 0x46102a, 0x10400017,
++0x0, 0x8f8200d8, 0x8f430098, 0x431023,
++0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47,
++0x10400005, 0x0, 0x8f420090, 0x8f430144,
++0x431021, 0xaf420090, 0x8f420090, 0x46102a,
++0x10400006, 0x0, 0x8f420348, 0x24420001,
++0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc,
++0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8,
++0x431024, 0x461023, 0x218c3, 0x58600001,
++0x24630100, 0x8f42008c, 0x43102b, 0x14400006,
++0x712c2, 0x8f420344, 0x24420001, 0xaf420344,
++0x10000098, 0x8f420344, 0x934305c2, 0x1060000f,
++0x30460001, 0x8f420010, 0x34480400, 0x32c20008,
++0x10400008, 0x30e20200, 0x10400006, 0x3c034000,
++0x9602000e, 0xaf4300ac, 0x21400, 0x10000004,
++0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010,
++0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac,
++0x11200005, 0x30c200ff, 0x14400006, 0x24020040,
++0x10000004, 0x24020008, 0x14400002, 0x24020020,
++0x24020004, 0xafa20010, 0x8f430030, 0x11200004,
++0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014,
++0x3c020002, 0x1021025, 0xafa20018, 0x8f460098,
++0x8f420108, 0x40f809, 0x0, 0x10400069,
++0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001,
++0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2,
++0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021,
++0x24420007, 0x461024, 0x24840007, 0xaf420094,
++0x8f420090, 0x8f430094, 0x862024, 0x441023,
++0x65182b, 0x14600005, 0xaf420090, 0x8f420094,
++0x8f430144, 0x431023, 0xaf420094, 0x8f430094,
++0x8f420140, 0x43102b, 0x10400009, 0x0,
++0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138,
++0x641823, 0x431023, 0xaf420090, 0xaf450094,
++0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d,
++0x30c200ff, 0x14400002, 0x24020010, 0x24020002,
++0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014,
++0x8f460098, 0x8f420108, 0x40f809, 0x0,
++0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c,
++0x451021, 0xaf420098, 0x8f420090, 0x8f430098,
++0xa34005c2, 0x451023, 0x64182b, 0x14600005,
++0xaf420090, 0x8f420098, 0x8f430144, 0x431023,
++0xaf420098, 0x8f420030, 0x8f430040, 0x24420001,
++0x2463ffff, 0x431024, 0xaf420030, 0x8f420030,
++0x14520018, 0x0, 0x8f420000, 0x10400007,
++0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
++0x0, 0x10000005, 0x0, 0xaf800048,
++0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
++0x2403fff7, 0x431024, 0xaf820060, 0x8f420000,
++0x10400003, 0x0, 0x10000002, 0xaf80004c,
++0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024,
++0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
++0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0,
++0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021,
++0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
++0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
++0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001,
++0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0,
++0x34422ec0, 0x2e21021, 0x54620004, 0x24620008,
++0x3c020001, 0x34422cc0, 0x2e21021, 0x401821,
++0x8c620004, 0x21140, 0x821021, 0xaf820108,
++0xac600000, 0x8c850018, 0x30a20036, 0x1040006c,
++0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034,
++0x24420001, 0x2463ffff, 0x431024, 0x862021,
++0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034,
++0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4,
++0x0, 0x32c20010, 0x10400028, 0x24070008,
++0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
++0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
++0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
++0x14400011, 0x24020001, 0x3c010001, 0x370821,
++0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
++0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c,
++0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100,
++0x10000036, 0x0, 0x8f420300, 0x8f43002c,
++0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
++0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170,
++0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
++0x24020020, 0xafa20010, 0xafa30014, 0xafa80018,
++0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
++0x24020001, 0x3c010001, 0x370821, 0xa02240f0,
++0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
++0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120,
++0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f,
++0x0, 0x8f420300, 0x24420001, 0xaf420300,
++0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038,
++0x3c010001, 0x370821, 0xa02040f1, 0x3c010001,
++0x370821, 0xa02040f0, 0xaf400034, 0x8f420314,
++0x24420001, 0xaf420314, 0x10000059, 0x8f420314,
++0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028,
++0xa22023, 0x4810003, 0x0, 0x8f420040,
++0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
++0x441021, 0x10600007, 0xaf420358, 0xaf80004c,
++0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
++0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
++0x0, 0x8f820060, 0x34420008, 0xaf820060,
++0x8f420000, 0x10400003, 0x0, 0x10000038,
++0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f,
++0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c,
++0x8f420050, 0x622023, 0x4820001, 0x24840200,
++0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368,
++0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000,
++0x8c83001c, 0x8f420070, 0x622023, 0x4820001,
++0x24840400, 0x8f420364, 0x441021, 0xaf420364,
++0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e,
++0x3c020800, 0x8c83001c, 0x8f420060, 0x622023,
++0x4820001, 0x24840100, 0x8f420360, 0x441021,
++0xaf420360, 0x8f420368, 0xaf430060, 0x441021,
++0xaf420368, 0x3c020800, 0x2c21024, 0x50400008,
++0x36940040, 0x10000006, 0x0, 0x30a20100,
++0x10400003, 0x0, 0xc002bd8, 0x0,
++0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
++0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c,
++0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c,
++0xafb00038, 0x8f910108, 0x26220020, 0xaf820108,
++0x8e320018, 0xa821, 0x32420024, 0x104001ba,
++0xf021, 0x8e26001c, 0x8f43001c, 0x61100,
++0x621821, 0x8c70000c, 0x9604000c, 0x962d0016,
++0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001,
++0x621825, 0x10600015, 0x2821, 0x32c20040,
++0x10400015, 0x24020800, 0x96030014, 0x14620012,
++0x3402aaaa, 0x9603000e, 0x14620007, 0x2021,
++0x96030010, 0x24020300, 0x14620004, 0x801021,
++0x96020012, 0x2c440001, 0x801021, 0x54400006,
++0x24050016, 0x10000004, 0x0, 0x24020800,
++0x50820001, 0x2405000e, 0x934205c3, 0x14400008,
++0x5821, 0x240b0001, 0x32620180, 0xaf4500a8,
++0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3,
++0x10a00085, 0x2054021, 0x91020000, 0x3821,
++0x3042000f, 0x25080, 0x32c20002, 0x10400012,
++0x10a1821, 0x32620002, 0x10400010, 0x32c20001,
++0x1002021, 0x94820000, 0x24840002, 0xe23821,
++0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02,
++0x623821, 0x71c02, 0x30e2ffff, 0x623821,
++0x71027, 0xa502000a, 0x32c20001, 0x1040006a,
++0x32620001, 0x10400068, 0x0, 0x8f4200a8,
++0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8,
++0x431021, 0x904c0009, 0x318900ff, 0x39230006,
++0x3182b, 0x39220011, 0x2102b, 0x621824,
++0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001,
++0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600,
++0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e,
++0x0, 0x32c20004, 0x14400013, 0x2821,
++0x316200ff, 0x14400004, 0x0, 0x95020002,
++0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e,
++0x95030010, 0xa22821, 0xa32821, 0x95030012,
++0x91040009, 0x95020002, 0xa32821, 0xa42821,
++0x4a1023, 0xa22821, 0x2002021, 0x94820000,
++0x24840002, 0xe23821, 0x88102b, 0x1440fffb,
++0x71c02, 0x30e2ffff, 0x623821, 0x71c02,
++0x30e2ffff, 0x623821, 0x1a52821, 0x51c02,
++0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
++0x622821, 0xa72823, 0x51402, 0xa22821,
++0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff,
++0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8,
++0x624021, 0x91020000, 0x3042000f, 0x25080,
++0x318300ff, 0x24020006, 0x14620003, 0x10a1021,
++0x10000002, 0x24440010, 0x24440006, 0x316200ff,
++0x14400006, 0x0, 0x94820000, 0xa22821,
++0x51c02, 0x30a2ffff, 0x622821, 0x934205c3,
++0x10400003, 0x32620100, 0x50400003, 0xa4850000,
++0x52827, 0xa4850000, 0x9622000e, 0x8f43009c,
++0x621821, 0x32a200ff, 0x10400007, 0xaf43009c,
++0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c,
++0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c,
++0xafa20024, 0x32620080, 0x10400010, 0x32620100,
++0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
++0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
++0x220821, 0xac2338e8, 0x3c010001, 0x220821,
++0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064,
++0x0, 0x8f4200b4, 0x24430001, 0x210c0,
++0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024,
++0x3c010001, 0x220821, 0xac2338e8, 0x3c010001,
++0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051,
++0x3821, 0x3c090001, 0x352938e8, 0x3c08001f,
++0x3508ffff, 0x240bffff, 0x340affff, 0x710c0,
++0x571021, 0x491021, 0x8c430000, 0x8c440004,
++0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028,
++0x8fa4002c, 0xac430000, 0xac440004, 0x24420008,
++0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c,
++0x97a2002e, 0x8f440270, 0x8f450274, 0x401821,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaf440270, 0xaf450274, 0x8fa20028,
++0x481024, 0x90430000, 0x30630001, 0x1460000b,
++0x402021, 0x8f420278, 0x8f43027c, 0x24630001,
++0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
++0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000,
++0x144b000e, 0x0, 0x94820004, 0x144a000b,
++0x0, 0x8f420288, 0x8f43028c, 0x24630001,
++0x2c640001, 0x441021, 0xaf420288, 0xaf43028c,
++0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280,
++0x8f430284, 0x24630001, 0x2c640001, 0x441021,
++0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
++0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8,
++0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4,
++0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
++0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
++0x8f46008c, 0x8f440270, 0x8f450274, 0x401821,
++0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821,
++0xa3302b, 0x822021, 0x862021, 0xaf440270,
++0xaf450274, 0x92020000, 0x30420001, 0x1440000c,
++0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001,
++0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
++0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020,
++0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004,
++0x1462000c, 0x0, 0x8f420288, 0x8f43028c,
++0x24630001, 0x2c640001, 0x441021, 0xaf420288,
++0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b,
++0x32c20020, 0x8f420280, 0x8f430284, 0x24630001,
++0x2c640001, 0x441021, 0xaf420280, 0xaf430284,
++0x8f420280, 0x8f430284, 0x32c20020, 0x10400005,
++0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358,
++0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001,
++0x2463ffff, 0x431024, 0xaf42002c, 0x32420060,
++0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
++0xaf420034, 0x8c03023c, 0x43102b, 0x14400102,
++0x32c20010, 0x10400018, 0x24070008, 0x8f440170,
++0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
++0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
++0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047,
++0x24020001, 0x8f420300, 0x8f43002c, 0x24420001,
++0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
++0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174,
++0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
++0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
++0x40f809, 0x24c6001c, 0x10400057, 0x24020001,
++0x10000065, 0x0, 0x32420012, 0x10400075,
++0x32420001, 0x9622000e, 0x8f43009c, 0x621821,
++0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358,
++0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c,
++0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
++0xaf42002c, 0x32420010, 0x14400008, 0x32c20010,
++0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
++0x43102b, 0x144000bc, 0x32c20010, 0x10400028,
++0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
++0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
++0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
++0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
++0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
++0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014,
++0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
++0x34a51100, 0x10000036, 0x0, 0x8f420300,
++0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
++0x24020001, 0xa34205c1, 0x10000026, 0xaf430038,
++0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
++0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
++0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
++0x14400011, 0x24020001, 0x3c010001, 0x370821,
++0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
++0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c,
++0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900,
++0x1000000f, 0x0, 0x8f420300, 0x24420001,
++0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1,
++0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
++0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
++0x8f420314, 0x24420001, 0xaf420314, 0x10000062,
++0x8f420314, 0x10400022, 0x32427000, 0x8e25001c,
++0x8f420028, 0xa22023, 0x4810003, 0x0,
++0x8f420040, 0x822021, 0x8f420358, 0x8f430000,
++0xaf450028, 0x441021, 0x10600007, 0xaf420358,
++0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
++0x10000005, 0x0, 0xaf800048, 0x8f820048,
++0x1040fffd, 0x0, 0x8f820060, 0x34420008,
++0xaf820060, 0x8f420000, 0x10400003, 0x0,
++0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048,
++0x1040002f, 0x32421000, 0x1040000c, 0x32424000,
++0x8e23001c, 0x8f420050, 0x622023, 0x4820001,
++0x24840200, 0x8f42035c, 0x441021, 0xaf42035c,
++0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c,
++0x32c28000, 0x8e23001c, 0x8f420070, 0x622023,
++0x4820001, 0x24840400, 0x8f420364, 0x441021,
++0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070,
++0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060,
++0x622023, 0x4820001, 0x24840100, 0x8f420360,
++0x441021, 0xaf420360, 0x8f420368, 0xaf430060,
++0x441021, 0xaf420368, 0x3c020800, 0x2c21024,
++0x50400011, 0x36940040, 0x1000000f, 0x0,
++0x32420048, 0x10400007, 0x24150001, 0x8e22001c,
++0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75,
++0xae22001c, 0x32420100, 0x10400003, 0x0,
++0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c,
++0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c,
++0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008,
++0x0, 0x0, 0x0, 0x8f8300e4,
++0x8f8200e0, 0x2404fff8, 0x441024, 0x621026,
++0x2102b, 0x21023, 0x3e00008, 0x621024,
++0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
++0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4,
++0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8,
++0x14a20002, 0x24a20008, 0x27623000, 0x408021,
++0x16030005, 0x30820004, 0x10400004, 0xc02021,
++0x10000022, 0x1021, 0x8e040000, 0x8f42011c,
++0x14a20003, 0x0, 0x8f420120, 0xaf420114,
++0x8ca30000, 0x8f420148, 0x831823, 0x43102b,
++0x10400003, 0x0, 0x8f420148, 0x621821,
++0x94a20006, 0x24420050, 0x62102b, 0x1440000f,
++0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000,
++0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894,
++0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
++0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c,
++0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
++0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8,
++0x2402fff8, 0x823824, 0xe32023, 0x2c821000,
++0x50400001, 0x24841000, 0x420c2, 0x801821,
++0x8f440258, 0x8f45025c, 0x1021, 0xa32821,
++0xa3302b, 0x822021, 0x862021, 0xaf440258,
++0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023,
++0x82102b, 0x14400004, 0x801821, 0x8f420148,
++0x822021, 0x801821, 0x8f440250, 0x8f450254,
++0x1021, 0xa32821, 0xa3302b, 0x822021,
++0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8,
++0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0,
++0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4,
++0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
++0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c,
++0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086,
++0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c,
++0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129,
++0xafaa007c, 0x8f420114, 0x40f809, 0x0,
++0x403021, 0x10c0034f, 0x0, 0x8cc20000,
++0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024,
++0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c,
++0x3c020006, 0x2c21024, 0xafab007c, 0x14400015,
++0xafaa0064, 0x91420000, 0x30420001, 0x10400011,
++0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff,
++0x95430004, 0x1062000b, 0x0, 0xc0024bb,
++0x8fa40064, 0x304200ff, 0x14400006, 0x0,
++0x8f420118, 0x40f809, 0x0, 0x1000032d,
++0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
++0x431024, 0x3c03ffff, 0x431824, 0x14600003,
++0xafa20024, 0x10000040, 0x1821, 0x3c020080,
++0x621024, 0x10400007, 0x0, 0x8f42038c,
++0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
++0x24030001, 0x8f420210, 0x24420001, 0xaf420210,
++0x8f420210, 0x3c020001, 0x621024, 0x10400006,
++0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
++0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
++0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
++0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
++0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
++0x8f420380, 0x3c020008, 0x621024, 0x10400006,
++0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
++0x8f420384, 0x3c020010, 0x621024, 0x10400006,
++0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
++0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
++0x24030001, 0x8f420388, 0x24420001, 0xaf420388,
++0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c,
++0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8,
++0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c,
++0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010,
++0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
++0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
++0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080,
++0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c,
++0x3c020080, 0x34420100, 0x1621024, 0x10400005,
++0x0, 0x8f42020c, 0x24420001, 0xaf42020c,
++0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400,
++0x10400015, 0x34028100, 0x8faa0064, 0x9543000c,
++0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e,
++0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
++0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c,
++0xa7a20086, 0xad63000c, 0xad640008, 0xad650004,
++0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024,
++0x10400004, 0x0, 0x8faa006c, 0x254a0004,
++0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074,
++0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074,
++0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc,
++0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b,
++0x10400056, 0x32c28000, 0x1040005e, 0x240a0003,
++0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058,
++0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024,
++0x24420001, 0xaf420350, 0x1000024f, 0x8f420350,
++0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
++0x3c040001, 0x248468d0, 0x26620001, 0xafa20014,
++0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
++0xc002b3b, 0x34a52250, 0x1000023f, 0x0,
++0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
++0x3c040001, 0x248468d0, 0x24020002, 0xafa20014,
++0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
++0xc002b3b, 0x34a52450, 0x1000022f, 0x0,
++0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8,
++0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800,
++0xc002b3b, 0x603021, 0x10000223, 0x0,
++0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0,
++0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120,
++0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216,
++0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124,
++0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010,
++0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b,
++0x34a53200, 0x10000208, 0x0, 0x8f420084,
++0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001,
++0x2c21024, 0x10400004, 0x0, 0x240b0002,
++0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020,
++0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c,
++0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002,
++0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054,
++0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001,
++0x304201ff, 0xafa20054, 0x1e1140, 0x431021,
++0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c,
++0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010,
++0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b,
++0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024,
++0x24630001, 0xaf430350, 0x100001d3, 0x8f420350,
++0x156a001d, 0x0, 0x8f430074, 0x8f420070,
++0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c,
++0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140,
++0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044,
++0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007,
++0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070,
++0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c,
++0x1000ffc3, 0x0, 0x8f430064, 0x8f420060,
++0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c,
++0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054,
++0x24020004, 0x1562000e, 0x1e1140, 0x1e1180,
++0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a,
++0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024,
++0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097,
++0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044,
++0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014,
++0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007,
++0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024,
++0x1440ff34, 0x0, 0x8f420370, 0x240a0001,
++0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90,
++0x8f420370, 0x27a30036, 0x131040, 0x621821,
++0x94620000, 0x441021, 0x10000020, 0xa4620000,
++0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072,
++0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4,
++0x25420020, 0xafa20028, 0x25420008, 0xafa20030,
++0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a,
++0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a,
++0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018,
++0x24630002, 0x822023, 0x1880ffde, 0x26730001,
++0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
++0x26650001, 0xa2102a, 0x1440002b, 0x24030001,
++0x8f83012c, 0x10600023, 0x0, 0x8f820124,
++0x431023, 0x22143, 0x58800001, 0x24840040,
++0x8f820128, 0x431023, 0x21943, 0x58600001,
++0x24630040, 0x64102a, 0x54400001, 0x602021,
++0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011,
++0x24030001, 0x10000015, 0x306200ff, 0x8fab0064,
++0x96070018, 0xafab0010, 0x8e220008, 0x3c040001,
++0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400,
++0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b,
++0x0, 0x8f420334, 0x1821, 0x24420001,
++0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc,
++0x3c020800, 0x12600021, 0x9021, 0x8fb100a4,
++0x2208021, 0x8e220008, 0x96070018, 0x8fa60064,
++0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010,
++0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
++0x40f809, 0x0, 0x1040ffd8, 0x3c050007,
++0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821,
++0x14b102b, 0x10400004, 0xafab0064, 0x8f420148,
++0x1625823, 0xafab0064, 0x26100002, 0x26520001,
++0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c,
++0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002,
++0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
++0x10600013, 0x0, 0x8f820124, 0x431023,
++0x22143, 0x58800001, 0x24840040, 0x8f820128,
++0x431023, 0x21943, 0x58600001, 0x24630040,
++0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
++0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
++0x8f420334, 0x1821, 0x24420001, 0xaf420334,
++0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800,
++0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b,
++0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
++0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008,
++0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809,
++0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e,
++0x97aa008e, 0x11400007, 0x609021, 0x934205c4,
++0x14400004, 0x0, 0x97ab0086, 0x6a1825,
++0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024,
++0x10400003, 0xa1402, 0x34630400, 0xa6a20014,
++0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004,
++0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a,
++0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000,
++0xafa20010, 0x8f420044, 0x2a03021, 0x24070020,
++0xafa20014, 0x8f42000c, 0x31940, 0x604821,
++0xafa20018, 0x8f42010c, 0x4021, 0xa92821,
++0xa9182b, 0x882021, 0x40f809, 0x832021,
++0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c,
++0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c,
++0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002,
++0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
++0x8f42035c, 0x156a0006, 0x0, 0x8f420364,
++0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364,
++0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360,
++0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044,
++0x8f440088, 0x8f430078, 0x24420001, 0x441024,
++0x24630001, 0xaf420044, 0xaf430078, 0x8c020240,
++0x62182b, 0x14600075, 0x24070008, 0x8f440168,
++0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120,
++0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
++0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
++0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2,
++0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
++0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120,
++0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b,
++0x0, 0x8f420304, 0x24420001, 0xaf420304,
++0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
++0x370821, 0xa02040f2, 0xaf400078, 0x8f420318,
++0x24420001, 0xaf420318, 0x10000048, 0x8f420318,
++0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
++0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
++0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
++0x604821, 0xafa20018, 0x8f42010c, 0x4021,
++0xa92821, 0xa9182b, 0x882021, 0x40f809,
++0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4,
++0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c,
++0x8fab009c, 0x1505021, 0x16a102b, 0x10400004,
++0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064,
++0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c,
++0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002,
++0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
++0x8f42035c, 0x114b0006, 0x0, 0x8f420360,
++0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360,
++0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364,
++0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044,
++0x8f440088, 0x8f430078, 0x24420001, 0x441024,
++0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c,
++0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e,
++0x0, 0x934205c4, 0x10400009, 0x0,
++0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c,
++0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc,
++0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020,
++0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004,
++0x8c450008, 0xa44a000e, 0xac440000, 0xac450004,
++0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c,
++0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff,
++0x2484fffc, 0x801821, 0x8f440250, 0x8f450254,
++0x8f460118, 0x1021, 0xa32821, 0xa3382b,
++0x822021, 0x872021, 0xaf440250, 0xc0f809,
++0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
++0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
++0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
++0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc,
++0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac,
++0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c,
++0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e,
++0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4,
++0x10000130, 0xafab006c, 0x8f420114, 0x40f809,
++0x0, 0x403021, 0x10c002a1, 0x0,
++0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024,
++0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc,
++0xafa20064, 0x3c020006, 0x2c21024, 0x14400015,
++0xafac006c, 0x93c20000, 0x30420001, 0x10400011,
++0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff,
++0x97c30004, 0x1062000b, 0x0, 0xc0024bb,
++0x3c02021, 0x304200ff, 0x14400006, 0x0,
++0x8f420118, 0x40f809, 0x0, 0x10000280,
++0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
++0x431024, 0x3c03ffff, 0x431824, 0x14600003,
++0xafa20024, 0x10000040, 0x8021, 0x3c020080,
++0x621024, 0x10400007, 0x0, 0x8f42038c,
++0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
++0x24100001, 0x8f420210, 0x24420001, 0xaf420210,
++0x8f420210, 0x3c020001, 0x621024, 0x10400006,
++0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
++0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
++0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
++0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
++0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
++0x8f420380, 0x3c020008, 0x621024, 0x10400006,
++0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
++0x8f420384, 0x3c020010, 0x621024, 0x10400006,
++0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
++0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
++0x24100001, 0x8f420388, 0x24420001, 0xaf420388,
++0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064,
++0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8,
++0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c,
++0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010,
++0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
++0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
++0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010,
++0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400,
++0x8fab006c, 0x3c020080, 0x34420100, 0x1621024,
++0x10400005, 0x0, 0x8f42020c, 0x24420001,
++0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064,
++0x32c20400, 0x10400012, 0x34028100, 0x97c3000c,
++0x1462000f, 0x0, 0x240c0200, 0xa7ac0076,
++0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064,
++0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e,
++0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004,
++0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100,
++0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001,
++0x621825, 0x10600015, 0x2821, 0x32c20800,
++0x10400015, 0x24020800, 0x97c30014, 0x14620012,
++0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021,
++0x97c30010, 0x24020300, 0x14620004, 0x801021,
++0x97c20012, 0x2c440001, 0x801021, 0x54400006,
++0x24050016, 0x10000004, 0x0, 0x24020800,
++0x50820001, 0x2405000e, 0x10a00013, 0x3c52021,
++0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b,
++0x10400003, 0x0, 0x8f420148, 0x621823,
++0x90620000, 0x38430006, 0x2c630001, 0x38420011,
++0x2c420001, 0x621825, 0x10600004, 0x3c020100,
++0x94820002, 0x453821, 0x3c020100, 0x2c21024,
++0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008,
++0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064,
++0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014,
++0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080,
++0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000,
++0x10400034, 0x240b0003, 0x32c21000, 0x10400031,
++0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350,
++0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350,
++0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025,
++0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001,
++0x248468d0, 0x26620001, 0xafa20014, 0xafa30010,
++0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b,
++0x34a55300, 0x10000162, 0x0, 0x8ea20000,
++0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010,
++0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b,
++0x603021, 0x10000156, 0x0, 0x8f420084,
++0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001,
++0x2c21024, 0x10400004, 0x0, 0x240c0002,
++0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020,
++0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021,
++0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b,
++0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c,
++0x26220001, 0x304201ff, 0xafa20054, 0x111140,
++0x431021, 0x1000006b, 0x2e2a821, 0x8f420044,
++0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014,
++0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
++0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf,
++0x282a024, 0x24630001, 0xaf430350, 0x10000124,
++0x8f420350, 0x156c001d, 0x0, 0x8f430074,
++0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074,
++0xafab004c, 0x26220001, 0x304203ff, 0xafa20054,
++0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821,
++0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8,
++0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074,
++0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b,
++0xafab005c, 0x1000ffc3, 0x0, 0x8f430064,
++0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064,
++0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff,
++0xafa20054, 0x24020004, 0x1562000e, 0x111140,
++0x111180, 0x24420cc0, 0x2e21021, 0xafa20044,
++0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b,
++0x10400024, 0x25950020, 0x240c0001, 0x10000021,
++0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821,
++0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4,
++0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060,
++0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008,
++0x2c21024, 0x1440ff61, 0x0, 0x8f420370,
++0x240c0001, 0xafac005c, 0x24420001, 0xaf420370,
++0x1000ff90, 0x8f420370, 0x27a30036, 0x131040,
++0x621821, 0x94620000, 0x441021, 0x1000001f,
++0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084,
++0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c,
++0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
++0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
++0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
++0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
++0x24630002, 0x822023, 0x1880ffdf, 0x26730001,
++0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
++0x262102a, 0x14400030, 0x24030001, 0x8f83012c,
++0x10600028, 0x0, 0x8f820124, 0x431023,
++0x22143, 0x58800001, 0x24840040, 0x8f820128,
++0x431023, 0x21943, 0x58600001, 0x24630040,
++0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
++0x8f4200fc, 0x262102a, 0x10400016, 0x24030001,
++0x1000001a, 0x306200ff, 0x8fac008c, 0x101040,
++0x4c1021, 0x94470018, 0x101080, 0x4c1021,
++0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc,
++0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500,
++0x2003021, 0xc002b3b, 0xafa30014, 0x10000039,
++0x0, 0x8f420334, 0x1821, 0x24420001,
++0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06,
++0x8021, 0x8f430008, 0x2402fbff, 0x1260002d,
++0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c,
++0x2669ffff, 0x2209021, 0x8e420008, 0x96270018,
++0x8c440000, 0x8c450004, 0x56090004, 0x240b0001,
++0x240c0002, 0x10000002, 0xafac0010, 0xafab0010,
++0x16000004, 0xafa80014, 0x8f420008, 0x10000002,
++0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021,
++0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0,
++0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2,
++0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021,
++0x5e102b, 0x10400003, 0x26310002, 0x8f420148,
++0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda,
++0x26520004, 0x8fb00064, 0x1000001a, 0x0,
++0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001,
++0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c,
++0x240c0002, 0xafac0010, 0x934305c4, 0xb1700,
++0x10600003, 0x2223025, 0x3c020800, 0xc23025,
++0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c,
++0x3c03021, 0x40f809, 0x2003821, 0x1040fecb,
++0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e,
++0x934205c4, 0x14400004, 0x0, 0x97ab007e,
++0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff,
++0x1821024, 0x10400003, 0xc1402, 0x34630400,
++0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006,
++0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e,
++0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f,
++0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064,
++0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4,
++0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c,
++0xad8b0000, 0x8fac0064, 0x1580feba, 0x0,
++0x8fab0064, 0x1160001b, 0x0, 0x934205c4,
++0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0,
++0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076,
++0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c,
++0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008,
++0xa44c000e, 0xac440000, 0xac450004, 0xac460008,
++0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010,
++0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc,
++0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
++0x1021, 0xa32821, 0xa3382b, 0x822021,
++0x872021, 0xaf440250, 0xc0f809, 0xaf450254,
++0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4,
++0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008,
++0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8,
++0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048,
++0x10620034, 0x0, 0x8f430048, 0x8f42004c,
++0x622023, 0x4820001, 0x24840200, 0x8f430054,
++0x8f42004c, 0x43102b, 0x14400004, 0x24020200,
++0x8f43004c, 0x10000005, 0x431023, 0x8f420054,
++0x8f43004c, 0x431023, 0x2442ffff, 0x405021,
++0x8a102a, 0x54400001, 0x805021, 0x8f49004c,
++0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
++0x24071000, 0xafa70010, 0x84140, 0x1001821,
++0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014,
++0x1021, 0x63140, 0xafa70018, 0xa32821,
++0xa3382b, 0x822021, 0x872021, 0x3402ecc0,
++0xc23021, 0x8f420108, 0x2e63021, 0x40f809,
++0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c,
++0x8f420048, 0x14620018, 0x0, 0x8f420000,
++0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
++0x1040fffd, 0x0, 0x10000005, 0x0,
++0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
++0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
++0x8f420000, 0x10400003, 0x0, 0x10000002,
++0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
++0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
++0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c,
++0x8f420058, 0x10620049, 0x0, 0x8f430058,
++0x8f42005c, 0x622023, 0x4820001, 0x24840100,
++0x8f430064, 0x8f42005c, 0x43102b, 0x14400004,
++0x24020100, 0x8f43005c, 0x10000005, 0x431023,
++0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff,
++0x403821, 0x87102a, 0x54400001, 0x803821,
++0x8f42005c, 0x471021, 0x305000ff, 0x32c21000,
++0x10400015, 0x24082000, 0x8f49005c, 0x8f440190,
++0x8f450194, 0x8f46005c, 0x73980, 0xafa80010,
++0xafb00014, 0x8f480014, 0x94980, 0x1201821,
++0x1021, 0xa32821, 0xa3482b, 0x822021,
++0x892021, 0x63180, 0xafa80018, 0x8f420108,
++0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190,
++0x8f450194, 0x8f46005c, 0x73940, 0xafa80010,
++0xafb00014, 0x8f480014, 0x94940, 0x1201821,
++0x1021, 0xa32821, 0xa3482b, 0x822021,
++0x892021, 0x63140, 0xafa80018, 0x8f420108,
++0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001,
++0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018,
++0x0, 0x8f420000, 0x10400007, 0x0,
++0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
++0x10000005, 0x0, 0xaf800048, 0x8f820048,
++0x1040fffd, 0x0, 0x8f820060, 0x2403feff,
++0x431024, 0xaf820060, 0x8f420000, 0x10400003,
++0x0, 0x10000002, 0xaf80004c, 0xaf800048,
++0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
++0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
++0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033,
++0x0, 0x8f430068, 0x8f42006c, 0x622023,
++0x4820001, 0x24840400, 0x8f430074, 0x8f42006c,
++0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
++0x10000005, 0x431023, 0x8f420074, 0x8f43006c,
++0x431023, 0x2442ffff, 0x405021, 0x8a102a,
++0x54400001, 0x805021, 0x8f49006c, 0x8f48006c,
++0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000,
++0xafa70010, 0x84140, 0x1001821, 0x12a4821,
++0x313003ff, 0xafb00014, 0x8f470014, 0x1021,
++0x63140, 0x24c66cc0, 0xafa70018, 0xa32821,
++0xa3382b, 0x822021, 0x872021, 0x8f420108,
++0x2e63021, 0x40f809, 0xa3940, 0x54400001,
++0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018,
++0x0, 0x8f420000, 0x10400007, 0x0,
++0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
++0x10000005, 0x0, 0xaf800048, 0x8f820048,
++0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff,
++0x431024, 0xaf820060, 0x8f420000, 0x10400003,
++0x0, 0x10000002, 0xaf80004c, 0xaf800048,
++0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
++0x3e00008, 0x0, 0x8f4200fc, 0x3c030001,
++0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc,
++0x8f850128, 0x2e31021, 0x54820004, 0x24820008,
++0x3c020001, 0x34422ec8, 0x2e21021, 0x401821,
++0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004,
++0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128,
++0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
++0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
++0x401821, 0x8c620004, 0x21140, 0xa21021,
++0xaf820128, 0xac600000, 0x8ca30018, 0x30620070,
++0x1040002d, 0x30620020, 0x10400004, 0x3c020010,
++0x2c21024, 0x1040000d, 0x0, 0x30620040,
++0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
++0x0, 0x30620010, 0x1040001f, 0x3c020040,
++0x2c21024, 0x1440001c, 0x0, 0x8f820040,
++0x30420001, 0x14400008, 0x2021, 0x8c030104,
++0x24020001, 0x50620005, 0x24040001, 0x8c020264,
++0x10400003, 0x801021, 0x24040001, 0x801021,
++0x10400006, 0x0, 0x8f42030c, 0x24420001,
++0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044,
++0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
++0xaf420308, 0x8f420308, 0x3e00008, 0x0,
++0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
++0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
++0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001,
++0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128,
++0x8d030018, 0x30620070, 0x1040002e, 0x30620020,
++0x10400004, 0x3c020010, 0x2c21024, 0x1040000d,
++0x0, 0x30620040, 0x10400004, 0x3c020020,
++0x2c21024, 0x10400007, 0x0, 0x30620010,
++0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6,
++0x0, 0x8f820040, 0x30420001, 0x14400008,
++0x2021, 0x8c030104, 0x24020001, 0x50620005,
++0x24040001, 0x8c020264, 0x10400003, 0x801021,
++0x24040001, 0x801021, 0x10400006, 0x0,
++0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192,
++0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
++0x8f420308, 0x24420001, 0xaf420308, 0x1000018a,
++0x8f420308, 0x30620002, 0x1040014b, 0x3c020800,
++0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016,
++0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001,
++0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0,
++0x431021, 0x10000010, 0x2e2a821, 0x24020002,
++0x15420005, 0x24020003, 0x1e1140, 0x24426cc0,
++0x10000009, 0x2e2a821, 0x15420005, 0x1e1180,
++0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821,
++0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc,
++0x30420400, 0x10400003, 0xafaa002c, 0x100000e1,
++0x8821, 0x10800004, 0x8821, 0x97b10026,
++0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c,
++0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870,
++0x2c420001, 0x621825, 0x10600015, 0x2021,
++0x32c20800, 0x10400015, 0x24020800, 0x96630014,
++0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007,
++0x2821, 0x96630010, 0x24020300, 0x14620004,
++0xa01021, 0x96620012, 0x2c450001, 0xa01021,
++0x54400006, 0x24040016, 0x10000004, 0x0,
++0x24020800, 0x50a20001, 0x2404000e, 0x108000b9,
++0x2649021, 0x92420000, 0x3042000f, 0x28080,
++0x32c20100, 0x10400020, 0x2501821, 0x3c020020,
++0x43102b, 0x1440000e, 0x2402021, 0x2821,
++0x94820000, 0x24840002, 0xa22821, 0x83102b,
++0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821,
++0x51c02, 0x30a2ffff, 0x10000009, 0x622821,
++0x8f470148, 0x8f420110, 0x102842, 0x3c060020,
++0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040,
++0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002,
++0x10000002, 0xafaa002c, 0x2821, 0x32c20080,
++0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f,
++0x3442ffff, 0x43102b, 0x10400003, 0x0,
++0x8f420148, 0x621823, 0x90660000, 0x30c200ff,
++0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
++0x621825, 0x1060007f, 0x24020800, 0x8821,
++0x97a3003e, 0x1462000f, 0x2602021, 0x96710000,
++0x96620002, 0x96630004, 0x96640006, 0x2228821,
++0x2238821, 0x2248821, 0x96620008, 0x9663000a,
++0x9664000c, 0x2228821, 0x2238821, 0x10000007,
++0x2248821, 0x94820000, 0x24840002, 0x2228821,
++0x92102b, 0x1440fffb, 0x0, 0x111c02,
++0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
++0x628821, 0x32c20200, 0x10400003, 0x26440006,
++0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff,
++0xa4102b, 0x10400003, 0x0, 0x8f420148,
++0x822023, 0x94820000, 0x30421fff, 0x10400004,
++0x2644000c, 0x96420002, 0x10000030, 0x508023,
++0x96420002, 0x26430014, 0x508023, 0x3c020020,
++0x43102b, 0x1440000a, 0xd08021, 0x9642000c,
++0x2028021, 0x9642000e, 0x96430010, 0x96440012,
++0x2028021, 0x2038021, 0x10000020, 0x2048021,
++0xa4102b, 0x10400003, 0x0, 0x8f420148,
++0x822023, 0x94820000, 0x24840002, 0x2028021,
++0xa4102b, 0x10400003, 0x0, 0x8f420148,
++0x822023, 0x94820000, 0x24840002, 0x2028021,
++0xa4102b, 0x10400003, 0x0, 0x8f420148,
++0x822023, 0x94820000, 0x24840002, 0x2028021,
++0xa4102b, 0x10400003, 0x0, 0x8f420148,
++0x822023, 0x94820000, 0x2028021, 0x3c020100,
++0x2c21024, 0x1040000e, 0x0, 0x8faa002c,
++0x31420004, 0x1040000a, 0x0, 0x9504000e,
++0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff,
++0x2228821, 0x111c02, 0x3222ffff, 0x628821,
++0x8faa0024, 0x1518823, 0x111402, 0x2228821,
++0x2308821, 0x111402, 0x2228821, 0x3231ffff,
++0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001,
++0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e,
++0x8faa002c, 0x31420004, 0x10400002, 0x24091000,
++0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4,
++0xafa90010, 0x8f490044, 0x84140, 0x1001821,
++0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020,
++0xafa80018, 0x8f48010c, 0x1021, 0xa32821,
++0xa3482b, 0x822021, 0x100f809, 0x892021,
++0x1440000b, 0x0, 0x8f820128, 0x3c040001,
++0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124,
++0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920,
++0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044,
++0x8f430088, 0x24420001, 0x431024, 0xaf420044,
++0x8faa0034, 0x8f440368, 0x24020001, 0x15420006,
++0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
++0x10000049, 0x8f42035c, 0x15420006, 0x0,
++0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042,
++0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
++0x1000003d, 0x8f420360, 0x30621000, 0x10400005,
++0x30628000, 0x8f420078, 0x24420001, 0x10000036,
++0xaf420078, 0x10400034, 0x0, 0x8f420078,
++0x24420001, 0xaf420078, 0x8c030240, 0x43102b,
++0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c,
++0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040,
++0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
++0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
++0x3c010001, 0x370821, 0xa02240f2, 0x8f820124,
++0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c,
++0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009,
++0xc002b3b, 0x34a51300, 0x1000000b, 0x0,
++0x8f420304, 0x24420001, 0xaf420304, 0x8f420304,
++0x8f420044, 0xaf42007c, 0x3c010001, 0x370821,
++0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001,
++0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c,
++0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c,
++0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008,
++0x0, 0x0, 0x0, 0x8f42013c,
++0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
++0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
++0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
++0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
++0xc002bbf, 0x24060008, 0x8c020204, 0xc004012,
++0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002,
++0x1040000e, 0x2021, 0x8c060248, 0x24020002,
++0x3c010001, 0xac226d98, 0xc005104, 0x24050002,
++0x2021, 0x8c060248, 0x24020001, 0x3c010001,
++0xac226d98, 0x10000011, 0x24050001, 0x8c060248,
++0x24020004, 0x3c010001, 0xac226d98, 0xc005104,
++0x24050004, 0x3c020001, 0x8c426d94, 0x30420001,
++0x10400008, 0x24020001, 0x3c010001, 0xac226d98,
++0x2021, 0x24050001, 0x3c06601b, 0xc005104,
++0x0, 0x3c040001, 0x248469d0, 0x8f420150,
++0x8f430154, 0x3c050008, 0x8f460158, 0x21640,
++0x31940, 0x34630403, 0x431025, 0x633c0,
++0x461025, 0xaf82021c, 0xafa00010, 0xafa00014,
++0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821,
++0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8,
++0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
++0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010,
++0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc,
++0xc002b3b, 0x3821, 0x8f420410, 0x24420001,
++0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c,
++0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4,
++0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010,
++0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8,
++0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821,
++0x3c044000, 0x2041024, 0x504000b4, 0x3c040100,
++0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc,
++0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823,
++0x43102b, 0x10400003, 0x0, 0x8f420148,
++0x621821, 0x10600005, 0x0, 0x8f42014c,
++0x43102b, 0x1040000b, 0x0, 0x8f8200e0,
++0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220,
++0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce,
++0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff,
++0x431024, 0x34420004, 0xaf820220, 0x8f8200e0,
++0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8,
++0x8f840120, 0x8f830124, 0x10000005, 0x2821,
++0x14620002, 0x24620020, 0x27624800, 0x401821,
++0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003,
++0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001,
++0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008,
++0x30a200ff, 0x14400058, 0x0, 0x934205c4,
++0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0,
++0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023,
++0x218c3, 0x4620001, 0x24630200, 0x10600005,
++0x24020001, 0x10620009, 0x0, 0x1000001f,
++0x0, 0x8f4203c0, 0xe03021, 0x24420001,
++0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4,
++0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
++0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
++0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
++0x14400031, 0x0, 0x8f42020c, 0x24420001,
++0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
++0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8,
++0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000,
++0x8f420148, 0xa71823, 0x43102b, 0x10400003,
++0x0, 0x8f420148, 0x621821, 0x8f42014c,
++0x43102b, 0x5440000a, 0xa03021, 0x8f42020c,
++0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008,
++0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8,
++0x1488000d, 0x27623000, 0x14820002, 0x2482fff8,
++0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff,
++0xc33021, 0x46102b, 0x10400003, 0x0,
++0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4,
++0x8f420148, 0xc31823, 0x43102b, 0x10400003,
++0x0, 0x8f420148, 0x621821, 0x10600005,
++0x0, 0x8f42014c, 0x43102b, 0x50400008,
++0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb,
++0x431024, 0x3c034000, 0x1000003f, 0x431025,
++0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
++0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024,
++0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001,
++0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff,
++0x3463ffff, 0x431024, 0x441025, 0xc003daf,
++0xaf820220, 0x10000029, 0x0, 0x2111024,
++0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001,
++0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019,
++0x0, 0x2111024, 0x1040001c, 0x0,
++0x8f830224, 0x24021402, 0x14620009, 0x3c050008,
++0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014,
++0x8f860224, 0x34a50500, 0xc002b3b, 0x3821,
++0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0,
++0x8f820220, 0x2002021, 0x34420002, 0xc004e9c,
++0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
++0x431024, 0x511025, 0xaf820220, 0x8fbf0020,
++0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
++0x3e00008, 0x0, 0x3c020001, 0x8c426da8,
++0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
++0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
++0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008,
++0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
++0x24020001, 0x3c010001, 0xac206da8, 0x3c010001,
++0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff,
++0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
++0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
++0x10400092, 0x284a024, 0x3c040600, 0x34842000,
++0x8f420004, 0x2821, 0x2403fffd, 0x431024,
++0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
++0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
++0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
++0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
++0x8c020228, 0x3c040001, 0x24846998, 0x3c050009,
++0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
++0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
++0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
++0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
++0x9821, 0xe08821, 0x263504c0, 0x8f440178,
++0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
++0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
++0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
++0xa3482b, 0x822021, 0x100f809, 0x892021,
++0x54400006, 0x24130001, 0x8f820054, 0x2021023,
++0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
++0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
++0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
++0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4,
++0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
++0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
++0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
++0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
++0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
++0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
++0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
++0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
++0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
++0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
++0x326200ff, 0x14400011, 0x0, 0x8f420378,
++0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
++0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
++0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000,
++0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec,
++0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
++0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
++0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
++0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d,
++0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008,
++0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
++0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b,
++0x3821, 0x3c020004, 0x2c21024, 0x10400007,
++0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
++0x431024, 0x34420008, 0xaf820220, 0x3c050001,
++0x8ca56d98, 0x24020001, 0x14a20007, 0x2021,
++0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c,
++0x10000006, 0x3c020007, 0xc00529b, 0x2021,
++0xac020268, 0x8c030268, 0x3c020007, 0x621824,
++0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
++0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
++0x3c020098, 0x1000000b, 0x0, 0x14620009,
++0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
++0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
++0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
++0x0, 0x0, 0x0, 0x86102b,
++0x50400001, 0x872023, 0xc41023, 0x24843,
++0x125102b, 0x1040001b, 0x91040, 0x824021,
++0x88102b, 0x10400007, 0x1821, 0x94820000,
++0x24840002, 0x621821, 0x88102b, 0x1440fffb,
++0x0, 0x602021, 0xc73023, 0xa91023,
++0x21040, 0xc22821, 0xc5102b, 0x10400007,
++0x1821, 0x94c20000, 0x24c60002, 0x621821,
++0xc5102b, 0x1440fffb, 0x0, 0x1000000d,
++0x832021, 0x51040, 0x822821, 0x85102b,
++0x10400007, 0x1821, 0x94820000, 0x24840002,
++0x621821, 0x85102b, 0x1440fffb, 0x0,
++0x602021, 0x41c02, 0x3082ffff, 0x622021,
++0x41c02, 0x3082ffff, 0x622021, 0x3e00008,
++0x3082ffff, 0x3e00008, 0x0, 0x802821,
++0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff,
++0x24a20004, 0x62102b, 0x54400007, 0x65102b,
++0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002,
++0x1000002a, 0x441021, 0x10400003, 0x0,
++0x8f420148, 0xa22823, 0x90a40000, 0x24a50001,
++0x65102b, 0x10400003, 0x0, 0x8f420148,
++0xa22823, 0x90a20000, 0x24a50001, 0x21200,
++0x822021, 0x65102b, 0x10400003, 0x0,
++0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
++0x822021, 0x65102b, 0x10400003, 0x0,
++0x8f420148, 0xa22823, 0x90a20000, 0x1000002d,
++0x21200, 0x3463ffff, 0x24a20004, 0x62102b,
++0x5440000a, 0x65102b, 0x90a20000, 0x90a40002,
++0x90a30001, 0x90a50003, 0x441021, 0x21200,
++0x651821, 0x10000020, 0x432021, 0x10400003,
++0x0, 0x8f420148, 0xa22823, 0x90a20000,
++0x24a50001, 0x22200, 0x65102b, 0x10400003,
++0x0, 0x8f420148, 0xa22823, 0x90a20000,
++0x24a50001, 0x822021, 0x65102b, 0x10400003,
++0x0, 0x8f420148, 0xa22823, 0x90a20000,
++0x24a50001, 0x21200, 0x822021, 0x65102b,
++0x10400003, 0x0, 0x8f420148, 0xa22823,
++0x90a20000, 0x822021, 0x41c02, 0x3082ffff,
++0x622021, 0x41c02, 0x3082ffff, 0x622021,
++0x3e00008, 0x3082ffff, 0x0, 0x8f820220,
++0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8,
++0x30424000, 0x10400054, 0x24040001, 0x8f820200,
++0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
++0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
++0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x8f820224, 0x1444004d, 0x42040, 0xc4102b,
++0x1040fff1, 0x0, 0x8f820200, 0x451025,
++0xaf820200, 0x8f820220, 0x34428000, 0xaf820220,
++0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
++0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
++0x0, 0x8f820220, 0x3c030004, 0x431024,
++0x1440000f, 0x0, 0x8f820220, 0x3c03ffff,
++0x34637fff, 0x431024, 0xaf820220, 0x8f830054,
++0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x8f820220, 0x3c030004, 0x431024, 0x1440000d,
++0x0, 0x8f820220, 0x34428000, 0xaf820220,
++0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
++0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
++0x0, 0x8f820220, 0x3c030004, 0x431024,
++0x1040001b, 0x1021, 0x8f830220, 0x24020001,
++0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700,
++0x441025, 0xaf820220, 0x8f820220, 0x2403fffd,
++0x431024, 0xaf820220, 0x8f820220, 0x3c030300,
++0x431024, 0x14400003, 0x0, 0x10000008,
++0x1021, 0x8f820220, 0x34420002, 0xaf820220,
++0x8f830220, 0x24020001, 0x641825, 0xaf830220,
++0x3e00008, 0x0, 0x2021, 0x3c050100,
++0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
++0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4,
++0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0,
++0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8,
++0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4,
++0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0,
++0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8,
++0x418c0, 0x24840001, 0x3631021, 0xac453004,
++0x3631021, 0xac403000, 0x28820200, 0x1440fff9,
++0x418c0, 0x2021, 0x418c0, 0x24840001,
++0x3631021, 0xac402804, 0x3631021, 0xac402800,
++0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c,
++0x24030080, 0x24040100, 0xac600000, 0x24630004,
++0x64102b, 0x5440fffd, 0xac600000, 0x8f830040,
++0x3c02f000, 0x621824, 0x3c025000, 0x1062000c,
++0x43102b, 0x14400006, 0x3c026000, 0x3c024000,
++0x10620008, 0x24020800, 0x10000008, 0x0,
++0x10620004, 0x24020800, 0x10000004, 0x0,
++0x24020700, 0x3c010001, 0xac226dac, 0x3e00008,
++0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0,
++0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020,
++0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e,
++0x0, 0x3c010001, 0xac206dbc, 0x8f830054,
++0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
++0x621023, 0x2c420065, 0x1440fffc, 0x0,
++0xc004db9, 0x0, 0x24040001, 0x2821,
++0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018,
++0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
++0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
++0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
++0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
++0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
++0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
++0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
++0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
++0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c,
++0x24050002, 0x8f830054, 0x8f820054, 0x10000002,
++0x24630064, 0x8f820054, 0x621023, 0x2c420065,
++0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
++0x26106f26, 0xc00457c, 0x2003021, 0x97a60018,
++0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0,
++0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
++0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d,
++0x24036040, 0x96020000, 0x3042fff0, 0x1443000c,
++0x24020020, 0x3c030001, 0x94636f24, 0x1462000b,
++0x24027830, 0x24020003, 0x3c010001, 0xac226d94,
++0x24020005, 0x3c010001, 0x1000003f, 0xac226f34,
++0x3c030001, 0x94636f24, 0x24027830, 0x1462000c,
++0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0,
++0x14430007, 0x24020003, 0x3c010001, 0xac226d94,
++0x24020006, 0x3c010001, 0x1000002f, 0xac226f34,
++0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24,
++0x34420001, 0x3c010001, 0xac226d94, 0x24020015,
++0x1462000b, 0x0, 0x3c020001, 0x94426f26,
++0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430,
++0x2c420001, 0x621825, 0x1460001b, 0x24020003,
++0x3c030001, 0x94636f24, 0x24027810, 0x14620016,
++0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0,
++0x14400011, 0x24020002, 0x1000000f, 0x24020004,
++0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001,
++0xac226d94, 0x1000005e, 0x24020004, 0x3c020001,
++0x8c426d94, 0x34420004, 0x3c010001, 0x100000af,
++0xac226d94, 0x24020001, 0x3c010001, 0xac226f40,
++0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2,
++0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054,
++0x8f820054, 0x24030008, 0x3c010001, 0xac236d98,
++0x10000002, 0x248401f4, 0x8f820054, 0x821023,
++0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
++0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
++0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
++0x1440fffc, 0x8021, 0x24120001, 0x24110009,
++0xc004482, 0x0, 0x3c010001, 0xac326db4,
++0xc004547, 0x0, 0x3c020001, 0x8c426db4,
++0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
++0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
++0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
++0x0, 0x8f820220, 0x24040001, 0x34420002,
++0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
++0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
++0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x8f820224, 0x14440005, 0x34028000, 0x42040,
++0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0,
++0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
++0x3c010001, 0xac226d98, 0x8021, 0x24120009,
++0x3c11ffff, 0x36313f7f, 0xc004482, 0x0,
++0x24020001, 0x3c010001, 0xac226db4, 0xc004547,
++0x0, 0x3c020001, 0x8c426db4, 0x1452fffb,
++0x0, 0x8f820044, 0x511024, 0x34425080,
++0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
++0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
++0x1440fffc, 0x0, 0x8f820044, 0x511024,
++0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
++0x10000002, 0x2463000a, 0x8f820054, 0x621023,
++0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
++0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
++0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
++0x621023, 0x2c420065, 0x1440fffc, 0x0,
++0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
++0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
++0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
++0x10000002, 0x24630001, 0x8f820054, 0x621023,
++0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
++0x14440005, 0x34028000, 0x42040, 0xa4102b,
++0x1040fff0, 0x34028000, 0x1082ff50, 0x26100001,
++0x2e020064, 0x1440ffb0, 0x0, 0x3c020001,
++0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0,
++0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
++0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001,
++0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001,
++0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001,
++0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001,
++0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001,
++0xac206d98, 0x491021, 0x3c010001, 0xac226f30,
++0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c,
++0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
++0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98,
++0x24060004, 0x24020001, 0x14a20014, 0xafbf0010,
++0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005,
++0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005,
++0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40,
++0x348493e0, 0x24020005, 0x14620016, 0x0,
++0x3c04003d, 0x10000013, 0x34840900, 0x3c020002,
++0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e,
++0x3c030001, 0x8c636f40, 0x10000005, 0x34848480,
++0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240,
++0x24020005, 0x14620003, 0x0, 0x3c04007a,
++0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054,
++0x441021, 0x431023, 0x44102b, 0x1440004c,
++0x0, 0x3c020001, 0x8c426da0, 0x14400048,
++0x0, 0x3c010001, 0x10c00025, 0xac206db0,
++0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000,
++0x3c080002, 0x25088ffc, 0x250afffc, 0x52842,
++0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024,
++0x10400010, 0x0, 0x14a70008, 0x0,
++0x8d020000, 0x441024, 0x1040000a, 0x0,
++0x3c010001, 0x10000007, 0xac256db0, 0x8d420000,
++0x441024, 0x10400003, 0x0, 0x3c010001,
++0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b,
++0x2c420001, 0x431024, 0x5440ffe5, 0x52842,
++0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001,
++0xac226f30, 0x1060003b, 0x24020005, 0x3c030001,
++0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012,
++0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000,
++0x34635000, 0x431024, 0x14400006, 0x24020001,
++0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98,
++0x24020001, 0x3c010001, 0xac226e24, 0x3c010001,
++0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c,
++0x3c020001, 0x8c426db0, 0x1040001e, 0x0,
++0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001,
++0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001,
++0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8,
++0x24020008, 0x10620005, 0x24020001, 0xc004239,
++0x0, 0x1000000b, 0x0, 0x3c030001,
++0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002,
++0x8c638f90, 0x10620003, 0x0, 0xc004e9c,
++0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
++0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98,
++0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024,
++0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001,
++0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8,
++0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4,
++0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c,
++0x2c620003, 0x10400005, 0x24020001, 0x1062000a,
++0x0, 0x10000226, 0x0, 0x24020004,
++0x106200b6, 0x24020008, 0x1062010a, 0x24020001,
++0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff,
++0x2c620008, 0x1040021c, 0x31080, 0x3c010001,
++0x220821, 0x8c226af8, 0x400008, 0x0,
++0x3c030001, 0x8c636f40, 0x24020005, 0x14620010,
++0x0, 0x3c020001, 0x8c426da4, 0x10400008,
++0x24020003, 0xc004482, 0x0, 0x24020002,
++0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4,
++0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30,
++0xc004482, 0x0, 0x3c020001, 0x8c426da4,
++0x3c010001, 0xac206d30, 0x1440017a, 0x24020002,
++0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40,
++0x24020005, 0x14620003, 0x24020001, 0x3c010001,
++0xac226dd0, 0xc0045ff, 0x0, 0x3c030001,
++0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001,
++0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104,
++0x2021, 0x24020005, 0x3c010001, 0xac206da4,
++0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec,
++0x3c05000f, 0x34a50100, 0x3021, 0x3821,
++0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6,
++0x0, 0x8f820220, 0x3c030004, 0x431024,
++0x14400175, 0x24020007, 0x8f830054, 0x3c020001,
++0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710,
++0x14400003, 0x24020001, 0x3c010001, 0xac226d9c,
++0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2,
++0x0, 0x8f820220, 0x30428000, 0x1040017d,
++0x0, 0x10000175, 0x0, 0x3c050001,
++0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b,
++0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0,
++0x24020001, 0x3c020008, 0x621024, 0x10400006,
++0x0, 0x8f820214, 0x3c03ffff, 0x431024,
++0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff,
++0x431024, 0x3442241f, 0xaf820214, 0x8f820220,
++0x3c030200, 0x34420002, 0xaf820220, 0x24020008,
++0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004,
++0x431024, 0x14400016, 0x0, 0x3c020002,
++0x8c428ffc, 0x30425000, 0x1040000d, 0x0,
++0x8f820220, 0x30428000, 0x10400006, 0x0,
++0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003,
++0x431024, 0x8f820220, 0x34428000, 0xaf820220,
++0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
++0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a,
++0x0, 0x3c020001, 0x94426f26, 0x24429fbc,
++0x2c420004, 0x10400004, 0x24040018, 0x24050002,
++0xc004ddb, 0x24060020, 0xc003e6d, 0x0,
++0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8,
++0x2443ffff, 0x2c620008, 0x1040016b, 0x31080,
++0x3c010001, 0x220821, 0x8c226b18, 0x400008,
++0x0, 0xc004547, 0x0, 0x3c030001,
++0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002,
++0x8c428ff8, 0x30424000, 0x10400004, 0x0,
++0x8f820044, 0x10000006, 0x3442f080, 0x8f820044,
++0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080,
++0xaf820044, 0x8f830054, 0x100000ea, 0x24020004,
++0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
++0x431023, 0x2c422710, 0x14400147, 0x24020005,
++0x100000d8, 0x0, 0x8f820220, 0x3c03f700,
++0x431025, 0xaf820220, 0xaf800204, 0x3c010002,
++0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001,
++0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a,
++0x14400135, 0x24020007, 0x100000d7, 0x0,
++0xc003f50, 0x0, 0x1040012d, 0x24020001,
++0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c,
++0x431024, 0x3442251f, 0xaf820214, 0x24020008,
++0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44,
++0x10400064, 0x24020001, 0x8f820220, 0x3c030008,
++0x431024, 0x1040006a, 0x3c020200, 0x10000078,
++0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007,
++0x10400115, 0x31080, 0x3c010001, 0x220821,
++0x8c226b38, 0x400008, 0x0, 0xc003daf,
++0x0, 0x3c010001, 0xac206d9c, 0xaf800204,
++0x3c010002, 0xc004482, 0xac208fe0, 0x24020001,
++0x3c010001, 0xac226db4, 0x24020002, 0x10000102,
++0xaee204b8, 0xc004547, 0x0, 0x3c030001,
++0x8c636db4, 0x10000084, 0x24020009, 0x3c020002,
++0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8,
++0x10000002, 0x344201f6, 0x344201fe, 0xaf820238,
++0x8f830054, 0x1000008b, 0x24020004, 0x8f830054,
++0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023,
++0x2c422710, 0x144000e8, 0x24020005, 0x10000079,
++0x0, 0x8f820220, 0x3c03f700, 0x431025,
++0xaf820220, 0xaf800204, 0x3c010002, 0x10000077,
++0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28,
++0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6,
++0x24020007, 0x10000078, 0x0, 0xc003f50,
++0x0, 0x104000ce, 0x24020001, 0x8f820214,
++0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024,
++0x3442251f, 0xaf820214, 0x24020008, 0x1080000f,
++0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b,
++0x0, 0x8f820220, 0x34420002, 0xaf820220,
++0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c,
++0x8f840220, 0x10000016, 0x0, 0x8f820220,
++0x3c030008, 0x431024, 0x14400011, 0x3c020200,
++0x282a025, 0x2402000e, 0x3c010002, 0xac228f90,
++0xc00551b, 0x2021, 0x8f820220, 0x34420002,
++0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98,
++0xc00529b, 0x2021, 0x100000a3, 0x0,
++0x3c020001, 0x8c426e44, 0x1040009f, 0x0,
++0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001,
++0xac226e40, 0x14400098, 0x24020002, 0x3c010001,
++0xac206e44, 0x3c010001, 0x10000093, 0xac226e40,
++0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e,
++0x31080, 0x3c010001, 0x220821, 0x8c226b58,
++0x400008, 0x0, 0x3c020001, 0x8c426da4,
++0x10400018, 0x24020005, 0xc004482, 0x0,
++0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e,
++0xac206da4, 0xc004963, 0x0, 0x3c030001,
++0x8c636dd4, 0x24020006, 0x14620077, 0x24020003,
++0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98,
++0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021,
++0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220,
++0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
++0x24020006, 0xaee204b8, 0x3c010001, 0x10000062,
++0xac236f28, 0x8f820220, 0x3c030004, 0x431024,
++0x10400003, 0x24020007, 0x1000005b, 0xaee204b8,
++0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
++0x431023, 0x2c422710, 0x14400003, 0x24020001,
++0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8,
++0x30425000, 0x1040004c, 0x0, 0x8f820220,
++0x30428000, 0x10400007, 0x0, 0x8f820220,
++0x3c03ffff, 0x34637fff, 0x431024, 0x10000042,
++0xaf820220, 0x8f820220, 0x34428000, 0x1000003e,
++0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b,
++0x2021, 0xc00551b, 0x2021, 0x3c020002,
++0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214,
++0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
++0x24020008, 0xaee204b8, 0x8f820220, 0x34420002,
++0xaf820220, 0x8f820220, 0x3c030004, 0x431024,
++0x14400016, 0x0, 0x3c020002, 0x8c428ff8,
++0x30425000, 0x1040000d, 0x0, 0x8f820220,
++0x30428000, 0x10400006, 0x0, 0x8f820220,
++0x3c03ffff, 0x34637fff, 0x10000003, 0x431024,
++0x8f820220, 0x34428000, 0xaf820220, 0x8f820220,
++0x3c03f700, 0x431025, 0xaf820220, 0x3c020001,
++0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004,
++0x24040018, 0x24050002, 0xc004ddb, 0x24060020,
++0xc003e6d, 0x0, 0x10000003, 0x0,
++0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008,
++0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
++0x34420004, 0xaf820220, 0x8f820200, 0x3c050001,
++0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002,
++0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001,
++0x10a2000a, 0x0, 0x100000b1, 0x0,
++0x24020004, 0x10a20072, 0x24020008, 0x10a20085,
++0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050,
++0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40,
++0x621824, 0x3c020700, 0x621825, 0x24020e00,
++0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200,
++0xaf850220, 0x14800006, 0xaf820238, 0x8f820044,
++0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044,
++0x3c030001, 0x8c636f40, 0x24020005, 0x14620004,
++0x0, 0x8f820044, 0x34425000, 0xaf820044,
++0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40,
++0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c,
++0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001,
++0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000,
++0x621825, 0x641825, 0x1000000a, 0x34620002,
++0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac,
++0x3c040001, 0x8c846d8c, 0x431025, 0x441025,
++0x34420002, 0xaf820220, 0x1000002f, 0x24020001,
++0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff,
++0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824,
++0x3c020d00, 0x621825, 0x24020001, 0xaf830050,
++0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00,
++0x3c020001, 0x8c426d80, 0x10000004, 0x34630070,
++0x3c020001, 0x8c426d80, 0x34630072, 0x431025,
++0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700,
++0x621825, 0x3c020001, 0x8c426d90, 0x3c040001,
++0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025,
++0x441025, 0xaf820220, 0x24020005, 0x14a20006,
++0x24020001, 0x8f820044, 0x2403afff, 0x431024,
++0xaf820044, 0x24020001, 0x1000003d, 0xaf820238,
++0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001,
++0x8c846f1c, 0x621824, 0x3c020a00, 0x621825,
++0x24020001, 0xaf830050, 0xaf820200, 0x1080001e,
++0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a,
++0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a,
++0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c,
++0x3442ffff, 0x621824, 0x1080000f, 0xaf830050,
++0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00,
++0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001,
++0xaf820200, 0xaf820220, 0x641825, 0xaf830200,
++0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80,
++0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
++0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84,
++0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac,
++0x651825, 0x431025, 0x441025, 0xaf820220,
++0x3e00008, 0x0, 0x3c030001, 0x8c636db4,
++0x3c020001, 0x8c426db8, 0x10620003, 0x24020002,
++0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003,
++0x10400025, 0x24020001, 0x14620023, 0x24020004,
++0x3c030001, 0x8c636d98, 0x10620006, 0x24020008,
++0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009,
++0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044,
++0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080,
++0xaf820044, 0x8f830054, 0x24020002, 0x3c010001,
++0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c,
++0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0,
++0x431023, 0x2c422710, 0x14400003, 0x24020009,
++0x3c010001, 0xac226db4, 0x3e00008, 0x0,
++0x0, 0x0, 0x0, 0x27bdffd8,
++0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
++0xafb10014, 0xc08821, 0xafb00010, 0x8021,
++0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x24100010, 0x2501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x2501024, 0x24100010, 0x2701024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x2701024, 0xc004db9, 0x34108000,
++0xc004db9, 0x0, 0xc004d58, 0x0,
++0x50400005, 0x108042, 0x96220000, 0x501025,
++0xa6220000, 0x108042, 0x1600fff7, 0x0,
++0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c,
++0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
++0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
++0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
++0xafb00010, 0x8021, 0xafbf0020, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0x24100010, 0x2301024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x2501024, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x34108000,
++0x96620000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
++0x0, 0xc004db9, 0x0, 0x8fbf0020,
++0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
++0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0,
++0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020,
++0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001,
++0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005,
++0x14620005, 0x2483ffff, 0xc004963, 0x0,
++0x1000034c, 0x0, 0x2c620013, 0x10400349,
++0x31080, 0x3c010001, 0x220821, 0x8c226b80,
++0x400008, 0x0, 0xc004db9, 0x8021,
++0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
++0x2021, 0x108042, 0x1600fffc, 0x0,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010,
++0x8021, 0xc004d78, 0x24040001, 0x26100001,
++0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
++0x2021, 0xc004d78, 0x24040001, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x24100010,
++0x32020001, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
++0x24100010, 0xc004d78, 0x2021, 0x108042,
++0x1600fffc, 0x0, 0xc004db9, 0x34108000,
++0xc004db9, 0x0, 0xc004d58, 0x0,
++0x50400005, 0x108042, 0x96220000, 0x501025,
++0xa6220000, 0x108042, 0x1600fff7, 0x0,
++0xc004db9, 0x0, 0x97a20010, 0x30428000,
++0x144002dc, 0x24020003, 0x100002d8, 0x0,
++0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0xc004d78, 0x2021, 0x108042, 0x1600fffc,
++0x0, 0xc004d78, 0x24040001, 0xc004d78,
++0x2021, 0x34108000, 0x96220000, 0x501024,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fff8, 0x0, 0xc004db9,
++0x0, 0x8f830054, 0x10000296, 0x24020004,
++0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c,
++0x431023, 0x2c420064, 0x1440029e, 0x24020002,
++0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003,
++0x14400296, 0x24020011, 0x24020003, 0x10620005,
++0x24020004, 0x10620291, 0x2402000f, 0x1000028f,
++0x24020011, 0x1000028d, 0x24020005, 0x24020014,
++0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020012, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x34108000,
++0x96220000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
++0x0, 0xc004db9, 0x0, 0x8f830054,
++0x10000248, 0x24020006, 0x8f830054, 0x3c020001,
++0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
++0x14400250, 0x24020007, 0x1000024c, 0x0,
++0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020013, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020013,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x8f830054, 0x10000207, 0x24020008, 0x8f830054,
++0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
++0x2c420064, 0x1440020f, 0x24020009, 0x1000020b,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x8021,
++0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x8f830054, 0x10000193, 0x2402000a, 0x8f830054,
++0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
++0x2c420064, 0x1440019b, 0x2402000b, 0x10000197,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020017, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x8021,
++0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020017, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054,
++0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
++0x2c420064, 0x14400127, 0x24020012, 0x10000123,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020014, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x8021,
++0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020014, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x8f830054, 0x100000ab, 0x24020013, 0x8f830054,
++0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
++0x2c420064, 0x144000b3, 0x2402000d, 0x100000af,
++0x0, 0x27b10010, 0xa7a00010, 0x8021,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x8021,
++0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x96220000, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x8f830054, 0x10000037, 0x2402000e, 0x24020840,
++0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020013, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x34108000,
++0x96220000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
++0x0, 0xc004db9, 0x0, 0x8f830054,
++0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001,
++0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001,
++0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
++0x14400004, 0x0, 0x24020011, 0x3c010001,
++0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
++0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98,
++0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030,
++0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002,
++0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc,
++0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c,
++0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c,
++0x2463ffff, 0x2c620006, 0x10400377, 0x31080,
++0x3c010001, 0x220821, 0x8c226bd8, 0x400008,
++0x0, 0x2021, 0x2821, 0xc004ddb,
++0x34068000, 0x24040010, 0x24050002, 0x24060002,
++0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002,
++0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018,
++0xa7a00018, 0x8021, 0xc004d78, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x24100010, 0x32020001, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x32020001, 0x24100010, 0xc004d78, 0x2021,
++0x108042, 0x1600fffc, 0x0, 0xc004db9,
++0x34108000, 0xc004db9, 0x0, 0xc004d58,
++0x0, 0x50400005, 0x108042, 0x96220000,
++0x501025, 0xa6220000, 0x108042, 0x1600fff7,
++0x0, 0xc004db9, 0x0, 0x97a20018,
++0x30428000, 0x14400004, 0x24020003, 0x3c010001,
++0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a,
++0xac226dd4, 0x24040010, 0x24050002, 0x24060002,
++0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001,
++0x8c636e20, 0x24020001, 0x146201e1, 0x8021,
++0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x24100010, 0x32020001, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x32020001, 0x24100010, 0x32020018, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
++0xc004db9, 0x0, 0xc004d58, 0x0,
++0x50400005, 0x108042, 0x96220000, 0x501025,
++0xa6220000, 0x108042, 0x1600fff7, 0x0,
++0xc004db9, 0x8021, 0x27b10018, 0xa7a00018,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0x24100010, 0x32020001,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x32020001, 0x24100010,
++0x32020018, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x96220000, 0x501025, 0xa6220000, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x8021,
++0x24040018, 0x2821, 0xc004ddb, 0x24060404,
++0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001,
++0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
++0x2021, 0xc004d78, 0x24040001, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x24100010,
++0x32020001, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
++0x24100010, 0x32020018, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x32020018, 0xc004db9, 0x34108000, 0xc004db9,
++0x0, 0xc004d58, 0x0, 0x50400005,
++0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
++0x108042, 0x1600fff7, 0x0, 0xc004db9,
++0x8021, 0xa7a0001a, 0xc004d78, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x24100010, 0x32020001, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x32020001, 0x24100010, 0x32020018, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
++0xc004db9, 0x0, 0xc004d58, 0x0,
++0x50400005, 0x108042, 0x97a2001a, 0x501025,
++0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
++0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
++0x2021, 0x24100010, 0xc004d78, 0x2021,
++0x108042, 0x1600fffc, 0x0, 0x24100010,
++0x3202001e, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x3202001e,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x97a2001c, 0x501025, 0xa7a2001c, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x8021,
++0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001,
++0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
++0x2021, 0xc004d78, 0x24040001, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x24100010,
++0xc004d78, 0x2021, 0x108042, 0x1600fffc,
++0x0, 0x24100010, 0x3202001e, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000,
++0xc004db9, 0x0, 0xc004d58, 0x0,
++0x50400005, 0x108042, 0x97a2001c, 0x501025,
++0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
++0xc004db9, 0x8021, 0x24020002, 0xa7a2001e,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0x24100010, 0xc004d78,
++0x2021, 0x108042, 0x1600fffc, 0x0,
++0x24100010, 0x3202001e, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x3202001e, 0xc004d78, 0x24040001, 0xc004d78,
++0x2021, 0x34108000, 0x97a2001e, 0x501024,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fff8, 0x0, 0xc004db9,
++0x8021, 0xa7a00020, 0xc004d78, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x24100010, 0xc004d78, 0x2021, 0x108042,
++0x1600fffc, 0x0, 0x24100010, 0x3202001e,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x3202001e, 0xc004db9,
++0x34108000, 0xc004db9, 0x0, 0xc004d58,
++0x0, 0x50400005, 0x108042, 0x97a20020,
++0x501025, 0xa7a20020, 0x108042, 0x1600fff7,
++0x0, 0xc004db9, 0x8021, 0xa7a00020,
++0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
++0x1440fffb, 0x0, 0xc004d78, 0x2021,
++0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0x24100010, 0xc004d78,
++0x2021, 0x108042, 0x1600fffc, 0x0,
++0x24100010, 0x3202001e, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
++0x3202001e, 0xc004db9, 0x34108000, 0xc004db9,
++0x0, 0xc004d58, 0x0, 0x50400005,
++0x108042, 0x97a20020, 0x501025, 0xa7a20020,
++0x108042, 0x1600fff7, 0x0, 0xc004db9,
++0x8021, 0xa7a00022, 0xc004d78, 0x24040001,
++0x26100001, 0x2e020020, 0x1440fffb, 0x0,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0xc004d78, 0x2021, 0xc004d78, 0x24040001,
++0x24100010, 0xc004d78, 0x2021, 0x108042,
++0x1600fffc, 0x0, 0x24100010, 0xc004d78,
++0x2021, 0x108042, 0x1600fffc, 0x0,
++0xc004d78, 0x24040001, 0xc004d78, 0x2021,
++0x34108000, 0x97a20022, 0x501024, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fff8, 0x0, 0xc004db9, 0x0,
++0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
++0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d,
++0x0, 0x3c020001, 0x94426f26, 0x3c010001,
++0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c,
++0x24040009, 0x24050001, 0xc004ddb, 0x24060400,
++0x24040018, 0x24050001, 0xc004ddb, 0x24060020,
++0x24040018, 0x24050001, 0xc004ddb, 0x24062000,
++0x3c024000, 0x2421024, 0x10400123, 0x3c022000,
++0x2421024, 0x10400004, 0x0, 0x3c010001,
++0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c,
++0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9,
++0x0, 0x3c020001, 0x8c426f1c, 0x10400067,
++0x3c020004, 0x2421024, 0x10400011, 0xa7a00018,
++0x3c020008, 0x2421024, 0x10400002, 0x24020200,
++0xa7a20018, 0x3c020010, 0x2421024, 0x10400004,
++0x0, 0x97a20018, 0x34420100, 0xa7a20018,
++0x97a60018, 0x24040009, 0x10000004, 0x2821,
++0x24040009, 0x2821, 0x3021, 0xc004ddb,
++0x0, 0x24020001, 0xa7a2001a, 0x3c020008,
++0x2421024, 0x1040000c, 0x3c020002, 0x2421024,
++0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001,
++0x2421024, 0x10400005, 0x3c020010, 0x97a2001a,
++0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024,
++0x1040000e, 0x3c020002, 0x2421024, 0x10400005,
++0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a,
++0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0,
++0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0,
++0x2431024, 0x54430004, 0x3c020020, 0x97a2001a,
++0x1000000c, 0x34420400, 0x2421024, 0x50400004,
++0x3c020080, 0x97a2001a, 0x10000006, 0x34420800,
++0x2421024, 0x10400004, 0x0, 0x97a2001a,
++0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004,
++0xc004ddb, 0x2821, 0x3c020004, 0x2421024,
++0x10400004, 0xa7a0001c, 0x32425000, 0x14400004,
++0x0, 0x32424000, 0x10400005, 0x2021,
++0xc004cf9, 0x2402021, 0x10000096, 0x0,
++0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb,
++0xa7a6001c, 0x1000008f, 0x0, 0x2421024,
++0x10400004, 0xa7a00018, 0x32425000, 0x14400004,
++0x0, 0x32424000, 0x10400005, 0x3c020010,
++0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a,
++0x2421024, 0x10400004, 0x0, 0x97a20018,
++0x10000004, 0xa7a20018, 0x97a20018, 0x34420100,
++0xa7a20018, 0x3c020001, 0x2421024, 0x10400004,
++0x0, 0x97a20018, 0x10000004, 0xa7a20018,
++0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018,
++0x2021, 0xc004ddb, 0x2821, 0xa7a0001a,
++0x8021, 0xc004d78, 0x24040001, 0x26100001,
++0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
++0x2021, 0xc004d78, 0x24040001, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x24100010,
++0x32020001, 0x10400002, 0x2021, 0x24040001,
++0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
++0x24100010, 0xc004d78, 0x2021, 0x108042,
++0x1600fffc, 0x0, 0xc004db9, 0x34108000,
++0xc004db9, 0x0, 0xc004d58, 0x0,
++0x50400005, 0x108042, 0x97a2001a, 0x501025,
++0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
++0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
++0x2021, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
++0x2021, 0x108042, 0x1600fffc, 0x0,
++0xc004db9, 0x34108000, 0xc004db9, 0x0,
++0xc004d58, 0x0, 0x50400005, 0x108042,
++0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
++0x1600fff7, 0x0, 0xc004db9, 0x0,
++0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a,
++0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c,
++0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b,
++0xafa30014, 0x8f830054, 0x24020004, 0x3c010001,
++0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38,
++0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c,
++0x431023, 0x2c420064, 0x1440000f, 0x0,
++0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4,
++0x3c03f700, 0x431025, 0x10000007, 0xaf820220,
++0x24020006, 0x3c010001, 0xac226dd4, 0x24020011,
++0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030,
++0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038,
++0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c,
++0x8821, 0x32024000, 0x10400013, 0xafbf0020,
++0x3c020010, 0x2021024, 0x2c420001, 0x21023,
++0x30434100, 0x3c020001, 0x2021024, 0x14400006,
++0x34714000, 0x3c020002, 0x2021024, 0x14400002,
++0x34716000, 0x34714040, 0x2021, 0x2821,
++0x10000036, 0x2203021, 0x32021000, 0x10400035,
++0x2021, 0x2821, 0xc004ddb, 0x24060040,
++0x24040018, 0x2821, 0xc004ddb, 0x24060c00,
++0x24040017, 0x2821, 0xc004ddb, 0x24060400,
++0x24040016, 0x2821, 0xc004ddb, 0x24060006,
++0x24040017, 0x2821, 0xc004ddb, 0x24062500,
++0x24040016, 0x2821, 0xc004ddb, 0x24060006,
++0x24040017, 0x2821, 0xc004ddb, 0x24064600,
++0x24040016, 0x2821, 0xc004ddb, 0x24060006,
++0x24040017, 0x2821, 0xc004ddb, 0x24066700,
++0x24040016, 0x2821, 0xc004ddb, 0x24060006,
++0x2404001f, 0x2821, 0xc004ddb, 0x24060010,
++0x24040009, 0x2821, 0xc004ddb, 0x24061500,
++0x24040009, 0x2821, 0x24061d00, 0xc004ddb,
++0x0, 0x3c040001, 0x24846bf0, 0x3c05000e,
++0x34a50100, 0x2003021, 0x2203821, 0xafa00010,
++0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c,
++0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044,
++0x8f820044, 0x3c030001, 0x431025, 0x3c030008,
++0xaf820044, 0x8f840054, 0x8f820054, 0xa32824,
++0x10000002, 0x24840001, 0x8f820054, 0x821023,
++0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
++0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
++0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
++0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
++0x0, 0x3e00008, 0xa01021, 0x8f830044,
++0x3c02fff0, 0x3442ffff, 0x42480, 0x621824,
++0x3c020002, 0x822025, 0x641825, 0xaf830044,
++0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
++0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x8f820044, 0x3c030001,
++0x431025, 0xaf820044, 0x8f830054, 0x8f820054,
++0x10000002, 0x24630001, 0x8f820054, 0x621023,
++0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
++0x0, 0x8f820044, 0x2403ff7f, 0x431024,
++0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x8f820044, 0x34420080,
++0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x3e00008, 0x0,
++0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
++0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
++0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
++0x24630001, 0x8f820054, 0x621023, 0x2c420002,
++0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
++0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
++0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
++0x621023, 0x2c420002, 0x1440fffc, 0x0,
++0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
++0x809821, 0xafbe002c, 0xa0f021, 0xafb20020,
++0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028,
++0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
++0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x34108000,
++0x96420000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x12000075,
++0x0, 0x1000fff6, 0x0, 0x3275ffff,
++0x27b10010, 0xa7a00010, 0x8021, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
++0x2021, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x2b01024,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x2b01024, 0xc004db9,
++0x34108000, 0xc004db9, 0x0, 0xc004d58,
++0x0, 0x50400005, 0x108042, 0x96220000,
++0x501025, 0xa6220000, 0x108042, 0x1600fff7,
++0x0, 0xc004db9, 0x0, 0x33c5ffff,
++0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
++0x10000006, 0x521025, 0x14a20006, 0x3271ffff,
++0x97a20010, 0x121827, 0x431024, 0xa7a20010,
++0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
++0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
++0x0, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0xc004d78,
++0x24040001, 0x24100010, 0x32020001, 0x10400002,
++0x2021, 0x24040001, 0xc004d78, 0x108042,
++0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
++0x10400002, 0x2021, 0x24040001, 0xc004d78,
++0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
++0x24040001, 0xc004d78, 0x2021, 0x34108000,
++0x96420000, 0x501024, 0x10400002, 0x2021,
++0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
++0x0, 0xc004db9, 0x0, 0x8fbf0030,
++0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020,
++0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
++0x0, 0x0, 0x0, 0x27bdffe8,
++0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0,
++0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
++0x0, 0xc003daf, 0x8f840224, 0x100001d8,
++0x0, 0x8f820220, 0x3c030008, 0x431024,
++0x10400026, 0x24020001, 0x8f840224, 0x8f820220,
++0x3c030400, 0x431024, 0x10400006, 0x0,
++0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b,
++0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000,
++0x24420001, 0xac620000, 0x2c420002, 0x14400003,
++0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002,
++0x8c428fc0, 0x10400006, 0x30820040, 0x10400004,
++0x24020001, 0x3c010002, 0x10000003, 0xac228fc4,
++0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c,
++0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002,
++0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002,
++0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002,
++0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002,
++0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002,
++0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194,
++0x31080, 0x3c010001, 0x220821, 0x8c226c00,
++0x400008, 0x0, 0x24020002, 0x3c010002,
++0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002,
++0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002,
++0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224,
++0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0,
++0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf,
++0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd,
++0x431024, 0xaf820200, 0x3c010002, 0xac208fe0,
++0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001,
++0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002,
++0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4,
++0x14400006, 0x24020003, 0x3c010001, 0xac246d9c,
++0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002,
++0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002,
++0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
++0x14400003, 0x24020004, 0x3c010002, 0xac228f90,
++0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff,
++0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001,
++0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8,
++0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002,
++0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204,
++0x3463ffff, 0x30420030, 0x1440012f, 0x283a024,
++0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002,
++0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0,
++0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff,
++0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001,
++0xac226e3c, 0x2c420002, 0x14400125, 0x24020001,
++0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c,
++0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002,
++0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024,
++0x3c020002, 0x8c428f9c, 0x10400115, 0x0,
++0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002,
++0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002,
++0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204,
++0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002,
++0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0,
++0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
++0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002,
++0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
++0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4,
++0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c,
++0x3c030002, 0x8c638fc8, 0x441024, 0x641824,
++0x10430004, 0x24020001, 0x3c010002, 0x100000e4,
++0xac228f90, 0x24020003, 0xaca20000, 0x24020008,
++0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc,
++0x1040000c, 0x24020001, 0x3c040002, 0xc005091,
++0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005,
++0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006,
++0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002,
++0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0,
++0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0,
++0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002,
++0xac238fac, 0x8f830054, 0x24020009, 0x3c010002,
++0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4,
++0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0,
++0x431023, 0x2c422710, 0x1440009f, 0x0,
++0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
++0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002,
++0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21,
++0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc,
++0x1040000e, 0x0, 0x3c020002, 0x8c428f9c,
++0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f,
++0x2402000c, 0x8f820204, 0x30420080, 0x1440000c,
++0x24020003, 0x10000029, 0x2402000c, 0x3c020002,
++0x8c428f9c, 0x30420080, 0x14400005, 0x24020003,
++0x8f820204, 0x30420080, 0x1040001f, 0x24020003,
++0xac620000, 0x2402000a, 0x3c010002, 0xac228f90,
++0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002,
++0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000,
++0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002,
++0xac228f90, 0x641825, 0x3c010002, 0xac238fe0,
++0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
++0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0,
++0x10400005, 0x0, 0x2402000c, 0x3c010002,
++0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0,
++0x10400063, 0x0, 0x3c040002, 0x8c848f9c,
++0x10800055, 0x30820008, 0x3c030002, 0x8c638fac,
++0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8,
++0xaca20000, 0x24020006, 0x3c010002, 0x10000054,
++0xac228f90, 0x8f820200, 0x34420002, 0xaf820200,
++0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90,
++0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002,
++0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
++0x14400031, 0x0, 0x3c020002, 0x8c428fd0,
++0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4,
++0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d,
++0x0, 0x3c050001, 0x8ca56d98, 0xc00529b,
++0x2021, 0x3c030001, 0x8c636d98, 0x24020004,
++0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94,
++0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94,
++0x431024, 0x3c010001, 0xac226d94, 0x8f830224,
++0x3c020200, 0x3c010002, 0xac238fec, 0x10000020,
++0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005,
++0x0, 0x3c020002, 0x8c428f9c, 0x1040000f,
++0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21,
++0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0,
++0x1040000f, 0x0, 0x3c020002, 0x8c428f9c,
++0x1440000b, 0x0, 0x24020002, 0x3c010002,
++0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0,
++0x10400003, 0x0, 0xc003daf, 0x0,
++0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
++0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002,
++0x24638fe8, 0x8c620000, 0x10400005, 0x34422000,
++0x3c010002, 0xac228fdc, 0x10000003, 0xac600000,
++0x3c010002, 0xac248fdc, 0x3e00008, 0x0,
++0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002,
++0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e,
++0x821024, 0x14400061, 0x24020030, 0x30822000,
++0x1040005d, 0x30838000, 0x31a02, 0x30820001,
++0x21200, 0x3c040001, 0x8c846f20, 0x621825,
++0x331c2, 0x3c030001, 0x24636e48, 0x30828000,
++0x21202, 0x30840001, 0x42200, 0x441025,
++0x239c2, 0x61080, 0x431021, 0x471021,
++0x90430000, 0x24020001, 0x10620025, 0x0,
++0x10600007, 0x24020002, 0x10620013, 0x24020003,
++0x1062002c, 0x3c05000f, 0x10000037, 0x0,
++0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
++0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
++0xaf820220, 0x3c010002, 0xac209004, 0x3c010002,
++0x10000034, 0xac20900c, 0x8f820200, 0x34420100,
++0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
++0x431024, 0xaf820220, 0x24020100, 0x3c010002,
++0xac229004, 0x3c010002, 0x10000026, 0xac20900c,
++0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
++0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
++0x3c010002, 0xac209004, 0x3c010002, 0x10000019,
++0xac23900c, 0x8f820200, 0x34420100, 0xaf820200,
++0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
++0x24020100, 0x3c010002, 0xac229004, 0x3c010002,
++0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001,
++0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014,
++0x10000004, 0x0, 0x24020030, 0x3c010002,
++0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020,
++0x0, 0x0, 0x0, 0x27bdffc8,
++0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
++0xafb00020, 0xc08021, 0x3c040001, 0x24846c50,
++0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001,
++0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
++0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010,
++0x24020002, 0x12620083, 0x2e620003, 0x10400005,
++0x24020001, 0x1262000a, 0x0, 0x10000173,
++0x0, 0x24020004, 0x126200f8, 0x24020008,
++0x126200f7, 0x3c02ffec, 0x1000016c, 0x0,
++0x3c020001, 0x8c426d94, 0x30420002, 0x14400004,
++0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
++0x3c010002, 0x310821, 0xac308ffc, 0x3c024000,
++0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
++0x101382, 0x3042001c, 0x3c030001, 0x24636dd8,
++0x431021, 0x823821, 0x3c020020, 0x2021024,
++0x10400006, 0x24020100, 0x3c010002, 0x310821,
++0xac229000, 0x10000005, 0x3c020080, 0x3c010002,
++0x310821, 0xac209000, 0x3c020080, 0x2021024,
++0x10400006, 0x121940, 0x3c020001, 0x3c010002,
++0x230821, 0x10000005, 0xac229008, 0x121140,
++0x3c010002, 0x220821, 0xac209008, 0x94e40000,
++0x3c030001, 0x8c636f40, 0x24020005, 0x10620010,
++0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
++0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
++0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002,
++0x24040001, 0x2821, 0xc0045be, 0x27a60018,
++0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001,
++0xac316da4, 0x14530004, 0x32028000, 0xc003daf,
++0x0, 0x32028000, 0x1040011c, 0x0,
++0xc003daf, 0x0, 0x3c030001, 0x8c636f40,
++0x24020005, 0x10620115, 0x24020002, 0x3c010001,
++0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98,
++0x24040001, 0x24050004, 0x27b0001a, 0xc0045be,
++0x2003021, 0x24040001, 0x2821, 0xc0045be,
++0x2003021, 0x3c020002, 0x511021, 0x8c428ff4,
++0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff,
++0x3c010001, 0xac336da4, 0x431024, 0x3c010002,
++0x310821, 0x109300f7, 0xac228ff4, 0x100000f7,
++0x0, 0x3c022000, 0x2021024, 0x10400005,
++0x24020001, 0x3c010001, 0xac226f1c, 0x10000004,
++0x128940, 0x3c010001, 0xac206f1c, 0x128940,
++0x3c010002, 0x310821, 0xac308ff8, 0x3c024000,
++0x2021024, 0x14400014, 0x0, 0x3c020001,
++0x8c426f1c, 0x10400006, 0x24040004, 0x24050001,
++0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8,
++0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff,
++0x3463ffff, 0x431024, 0x3c010002, 0x310821,
++0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c,
++0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
++0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100,
++0x3c010002, 0x310821, 0xac239004, 0x3c030001,
++0x3c010002, 0x310821, 0xac23900c, 0x10000015,
++0x34420400, 0x2021024, 0x10400008, 0x24030100,
++0x3c020001, 0x8c426f20, 0x3c010002, 0x310821,
++0xac239004, 0x1000000b, 0x34420800, 0x3c020080,
++0x2021024, 0x1040002e, 0x3c030001, 0x3c020001,
++0x8c426f20, 0x3c010002, 0x310821, 0xac23900c,
++0x34420c00, 0x3c010001, 0xac226f20, 0x10000025,
++0x24040001, 0x3c020020, 0x2021024, 0x10400006,
++0x24020100, 0x3c010002, 0x310821, 0xac229004,
++0x10000005, 0x3c020080, 0x3c010002, 0x310821,
++0xac209004, 0x3c020080, 0x2021024, 0x10400007,
++0x121940, 0x3c020001, 0x3c010002, 0x230821,
++0xac22900c, 0x10000006, 0x24040001, 0x121140,
++0x3c010002, 0x220821, 0xac20900c, 0x24040001,
++0x2821, 0x27b0001e, 0xc00457c, 0x2003021,
++0x24040001, 0x2821, 0xc00457c, 0x2003021,
++0x24040001, 0x24050001, 0x27b0001c, 0xc00457c,
++0x2003021, 0x24040001, 0x24050001, 0xc00457c,
++0x2003021, 0x10000077, 0x0, 0x3c02ffec,
++0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
++0x121140, 0x3c010002, 0x220821, 0xac308ff8,
++0x3c022000, 0x2021024, 0x10400009, 0x0,
++0x3c020001, 0x8c426e44, 0x14400005, 0x24020001,
++0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000,
++0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024,
++0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c,
++0xaf820238, 0x3c010001, 0xac206db0, 0x10600005,
++0x24022020, 0x3c010001, 0xac226f20, 0x24020001,
++0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
++0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98,
++0x3484ffff, 0x441024, 0x3c010002, 0x230821,
++0xac228ff0, 0x24020001, 0x10a20044, 0x0,
++0x10000040, 0x0, 0x3c020001, 0x8c426f1c,
++0x1040001c, 0x24022000, 0x3c010001, 0xac226f20,
++0x3c0300a0, 0x2031024, 0x14430005, 0x121140,
++0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20,
++0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020,
++0x621024, 0x10400004, 0x24022001, 0x3c010001,
++0x10000023, 0xac226f20, 0x3c020080, 0x621024,
++0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c,
++0xac226f20, 0x3c020020, 0x2021024, 0x10400007,
++0x121940, 0x24020100, 0x3c010002, 0x230821,
++0xac229004, 0x10000006, 0x3c020080, 0x121140,
++0x3c010002, 0x220821, 0xac209004, 0x3c020080,
++0x2021024, 0x10400006, 0x121940, 0x3c020001,
++0x3c010002, 0x230821, 0x10000005, 0xac22900c,
++0x121140, 0x3c010002, 0x220821, 0xac20900c,
++0x3c030001, 0x8c636d98, 0x24020001, 0x10620003,
++0x0, 0xc003daf, 0x0, 0x8fbf0030,
++0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
++0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c,
++0x9821, 0xafb50040, 0xa821, 0xafb10034,
++0x8821, 0x24020002, 0xafbf0048, 0xafbe0044,
++0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a,
++0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022,
++0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005,
++0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d,
++0x2201021, 0x24020004, 0x10a2020a, 0x24020008,
++0x10a20208, 0x2201021, 0x10000256, 0x0,
++0x8fa8002c, 0x88140, 0x3c030002, 0x701821,
++0x8c638ffc, 0x621024, 0x14400009, 0x24040001,
++0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002,
++0x300821, 0xac318ff4, 0x10000246, 0x2201021,
++0x24050001, 0xc00457c, 0x27a60018, 0x24040001,
++0x24050001, 0xc00457c, 0x27a60018, 0x97a20018,
++0x30420004, 0x104000d9, 0x3c114000, 0x3c020001,
++0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9,
++0x31080, 0x3c010001, 0x220821, 0x8c226c68,
++0x400008, 0x0, 0x24040001, 0x24050011,
++0x27b0001a, 0xc00457c, 0x2003021, 0x24040001,
++0x24050011, 0xc00457c, 0x2003021, 0x97a3001a,
++0x30624000, 0x10400002, 0x3c150010, 0x3c150008,
++0x30628000, 0x104000aa, 0x3c130001, 0x100000a8,
++0x3c130002, 0x24040001, 0x24050014, 0x27b0001a,
++0xc00457c, 0x2003021, 0x24040001, 0x24050014,
++0xc00457c, 0x2003021, 0x97a3001a, 0x30621000,
++0x10400002, 0x3c150010, 0x3c150008, 0x30620800,
++0x10400097, 0x3c130001, 0x10000095, 0x3c130002,
++0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
++0x2003021, 0x24040001, 0x24050019, 0xc00457c,
++0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
++0x10620027, 0x28620401, 0x1040000e, 0x24020200,
++0x1062001f, 0x28620201, 0x10400005, 0x24020100,
++0x5062001e, 0x3c130001, 0x1000001e, 0x24040001,
++0x24020300, 0x50620019, 0x3c130002, 0x10000019,
++0x24040001, 0x24020600, 0x1062000d, 0x28620601,
++0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
++0x10000010, 0x24040001, 0x24020700, 0x1462000d,
++0x24040001, 0x3c130004, 0x1000000a, 0x3c150008,
++0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
++0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
++0x24040001, 0x24050018, 0x27b0001e, 0xc00457c,
++0x2003021, 0x24040001, 0x24050018, 0xc00457c,
++0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140,
++0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022,
++0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010,
++0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b,
++0xafa20014, 0x3c020004, 0x16620010, 0x3c020001,
++0x8f840054, 0x24030001, 0x24020002, 0x3c010001,
++0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001,
++0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001,
++0xac246f30, 0x1000004f, 0x2b38825, 0x16620039,
++0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e,
++0x24040018, 0x2021, 0x2821, 0xc004ddb,
++0x34068000, 0x8f830054, 0x8f820054, 0x2b38825,
++0x10000002, 0x24630032, 0x8f820054, 0x621023,
++0x2c420033, 0x1440fffc, 0x0, 0x8f830054,
++0x24020001, 0x3c010001, 0xac226e20, 0x3c010001,
++0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001,
++0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001,
++0x1000002c, 0xac236f30, 0x2821, 0xc004ddb,
++0x24060404, 0x2021, 0x2405001e, 0x27a60018,
++0x24020002, 0xc0045be, 0xa7a20018, 0x2021,
++0x2821, 0x27a60018, 0xc0045be, 0xa7a00018,
++0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
++0x3c028000, 0x2221025, 0x2b31825, 0x10000015,
++0x438825, 0x2221025, 0x2751825, 0x438825,
++0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98,
++0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b,
++0xafb10014, 0x10000007, 0x0, 0x3c110002,
++0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff,
++0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e,
++0x0, 0x3c020001, 0x8c426f1c, 0x10400002,
++0x3c022000, 0x2228825, 0x8fa8002c, 0x81140,
++0x3c010002, 0x220821, 0x8c229000, 0x10400003,
++0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf,
++0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
++0x3c010002, 0x220821, 0x8c229008, 0x10400003,
++0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f,
++0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
++0x3c010002, 0x220821, 0xac318ff4, 0x10000135,
++0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002,
++0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024,
++0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff,
++0x628824, 0x3c010002, 0x3e0821, 0xac318ff0,
++0x10000124, 0x2201021, 0x2821, 0xc00457c,
++0x27a60018, 0x24040001, 0x2821, 0xc00457c,
++0x27a60018, 0x24040001, 0x24050001, 0x27b20020,
++0xc00457c, 0x2403021, 0x24040001, 0x24050001,
++0xc00457c, 0x2403021, 0x24040001, 0x24050004,
++0x27b1001e, 0xc00457c, 0x2203021, 0x24040001,
++0x24050004, 0xc00457c, 0x2203021, 0x24040001,
++0x24050005, 0x27b00022, 0xc00457c, 0x2003021,
++0x24040001, 0x24050005, 0xc00457c, 0x2003021,
++0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
++0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
++0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
++0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
++0x24040001, 0x24050018, 0xc00457c, 0x2203021,
++0x24040001, 0x24050018, 0xc00457c, 0x2203021,
++0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
++0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
++0x97a20018, 0x30420004, 0x10400066, 0x3c114000,
++0x3c030001, 0x8c636f34, 0x24020005, 0x14620067,
++0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
++0x2003021, 0x24040001, 0x24050019, 0xc00457c,
++0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
++0x10620027, 0x28620401, 0x1040000e, 0x24020200,
++0x1062001f, 0x28620201, 0x10400005, 0x24020100,
++0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004,
++0x24020300, 0x50620019, 0x3c130002, 0x10000019,
++0x3c020004, 0x24020600, 0x1062000d, 0x28620601,
++0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
++0x10000010, 0x3c020004, 0x24020700, 0x1462000d,
++0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008,
++0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
++0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
++0x3c020004, 0x12620017, 0x3c028000, 0x8f820054,
++0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001,
++0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001,
++0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001,
++0x16620022, 0x2758825, 0x2021, 0x2821,
++0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b,
++0xac306e20, 0x2221025, 0x2b31825, 0x438825,
++0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001,
++0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010,
++0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001,
++0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007,
++0x0, 0x3c110002, 0x23e8821, 0x8e318ff0,
++0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001,
++0x8c426da8, 0x10400069, 0x0, 0x3c020001,
++0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825,
++0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
++0x8c229004, 0x10400003, 0x3c020020, 0x10000005,
++0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
++0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
++0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f,
++0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b,
++0x2228824, 0x8fa8002c, 0x82940, 0x3c030002,
++0x651821, 0x8c638ff8, 0x3c024000, 0x621024,
++0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
++0x3c010002, 0x250821, 0xac318ff0, 0x10000041,
++0x2201021, 0x3c020001, 0x8c426da8, 0x10400034,
++0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c,
++0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b,
++0x21023, 0x441024, 0x10600003, 0x518825,
++0x3c022000, 0x2228825, 0x3c020002, 0x451021,
++0x8c429004, 0x10400003, 0x3c020020, 0x10000004,
++0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
++0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
++0x8c22900c, 0x10400003, 0x3c020080, 0x10000004,
++0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
++0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800,
++0x2228825, 0x3c020001, 0x8c426e34, 0x10400002,
++0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38,
++0x10400006, 0x3c020100, 0x10000004, 0x2228825,
++0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c,
++0x81140, 0x3c010002, 0x220821, 0xac318ff0,
++0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
++0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
++0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028,
++0x809021, 0xafbf002c, 0xafb10024, 0xafb00020,
++0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220,
++0x24020002, 0x1202005c, 0x2e020003, 0x10400005,
++0x24020001, 0x1202000a, 0x121940, 0x1000010c,
++0x0, 0x24020004, 0x120200bf, 0x24020008,
++0x120200be, 0x128940, 0x10000105, 0x0,
++0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002,
++0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024,
++0x10400038, 0x3c020008, 0x2021024, 0x10400020,
++0x34840002, 0x3c020002, 0x431021, 0x8c429000,
++0x10400005, 0x34840020, 0x34840100, 0x3c020020,
++0x10000006, 0x2028025, 0x2402feff, 0x822024,
++0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140,
++0x3c010002, 0x220821, 0x8c229008, 0x10400005,
++0x3c020001, 0xc23025, 0x3c020080, 0x10000016,
++0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024,
++0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024,
++0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff,
++0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024,
++0x3c010002, 0x230821, 0xac209000, 0x3c010002,
++0x230821, 0xac209008, 0xaf840200, 0xaf860220,
++0x8f820220, 0x34420002, 0xaf820220, 0x1000000a,
++0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200,
++0x2028024, 0x2402fffd, 0x621824, 0xc003daf,
++0xaf830200, 0x121140, 0x3c010002, 0x220821,
++0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c,
++0x10400069, 0x24050004, 0x24040001, 0xc00457c,
++0x27a60018, 0x24040001, 0x24050005, 0xc00457c,
++0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001,
++0x24846e48, 0x30630c00, 0x31a82, 0x30420c00,
++0x21282, 0xa7a2001a, 0x21080, 0x441021,
++0x431021, 0xa7a30018, 0x90480000, 0x24020001,
++0x3103ffff, 0x10620029, 0x28620002, 0x10400005,
++0x0, 0x10600009, 0x0, 0x1000003d,
++0x0, 0x10700013, 0x24020003, 0x1062002c,
++0x0, 0x10000037, 0x0, 0x8f820200,
++0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
++0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
++0x3c010002, 0xac209004, 0x3c010002, 0x10000032,
++0xac20900c, 0x8f820200, 0x34420100, 0xaf820200,
++0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
++0xaf820220, 0x24020100, 0x3c010002, 0xac229004,
++0x3c010002, 0x10000024, 0xac20900c, 0x8f820200,
++0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
++0x3c030001, 0x431025, 0xaf820220, 0x3c010002,
++0xac209004, 0x3c010002, 0x10000017, 0xac23900c,
++0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
++0x3c030001, 0x431025, 0xaf820220, 0x24020100,
++0x3c010002, 0xac229004, 0x3c010002, 0x1000000a,
++0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a,
++0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010,
++0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002,
++0x1000004b, 0xaf820200, 0x128940, 0x3c050002,
++0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021,
++0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010,
++0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
++0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200,
++0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024,
++0x3c010002, 0x310821, 0x10000031, 0xac308ff0,
++0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020,
++0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020,
++0xa21024, 0x10400007, 0x34840020, 0x24020100,
++0x3c010002, 0x310821, 0xac229004, 0x10000006,
++0x34840100, 0x3c010002, 0x310821, 0xac209004,
++0x2402feff, 0x822024, 0x3c020080, 0xa21024,
++0x10400007, 0x121940, 0x3c020001, 0x3c010002,
++0x230821, 0xac22900c, 0x10000008, 0xc23025,
++0x121140, 0x3c010002, 0x220821, 0xac20900c,
++0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200,
++0xaf860220, 0x8f820220, 0x34420002, 0xaf820220,
++0x121140, 0x3c010002, 0x220821, 0xac308ff0,
++0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
++0x3e00008, 0x27bd0030, 0x0, 0x1821,
++0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007,
++0x30420001, 0x10400004, 0x0, 0x8f820044,
++0x10000003, 0x34420040, 0x8f820044, 0x461024,
++0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
++0x8f820044, 0x451024, 0xaf820044, 0x24630001,
++0x28620008, 0x5440ffee, 0x641007, 0x3e00008,
++0x0, 0x2c820008, 0x1040001b, 0x0,
++0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001,
++0x24426e60, 0x621821, 0x24640004, 0x90620000,
++0x10400004, 0x0, 0x8f820044, 0x10000003,
++0x34420040, 0x8f820044, 0x461024, 0xaf820044,
++0x8f820044, 0x34420020, 0xaf820044, 0x8f820044,
++0x451024, 0xaf820044, 0x24630001, 0x64102b,
++0x1440ffee, 0x0, 0x3e00008, 0x0,
++0x0, 0x0, 0x0, 0x8f8400c4,
++0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824,
++0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008,
++0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004,
++0x14400012, 0x805021, 0x8ce90000, 0x8f42013c,
++0x1494823, 0x49182b, 0x94eb0006, 0x10600002,
++0x25630050, 0x494821, 0x123182b, 0x50400003,
++0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8,
++0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008,
++0x1021, 0x3e00008, 0x0, 0x8f8300e4,
++0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8,
++0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8,
++0x3e00008, 0xaf8200e4, 0x3e00008, 0x0,
++0x0, 0x0, 0x0, 0x8f880120,
++0x27624fe0, 0x8f830128, 0x15020002, 0x25090020,
++0x27694800, 0x11230012, 0x8fa20010, 0xad040000,
++0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
++0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
++0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc,
++0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc,
++0x8f430324, 0x1021, 0x24630001, 0x3e00008,
++0xaf430324, 0x3e00008, 0x0, 0x8f880100,
++0x276247e0, 0x8f830108, 0x15020002, 0x25090020,
++0x27694000, 0x1123000f, 0x8fa20010, 0xad040000,
++0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
++0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
++0xad020010, 0xad030014, 0xaf890100, 0x3e00008,
++0x24020001, 0x8f430328, 0x1021, 0x24630001,
++0x3e00008, 0xaf430328, 0x3e00008, 0x0,
+ 0x0, 0x0, 0x0, 0x0 };
+ static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
+-0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31,
+-0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234,
+-0x2030303a, 0x31303a35, 0x35207368, 0x75616e67,
+-0x20457870, 0x20240000, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x6261644d, 0x656d537a,
+-0x0, 0x68775665, 0x72000000, 0x62616448,
+-0x77566572, 0x0, 0x2a2a4441, 0x574e5f41,
+-0x0, 0x74785278, 0x4266537a, 0x0,
+-0x62664174, 0x6e4d726b, 0x0, 0x7265645a,
+-0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600,
+-0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c,
+-0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e,
+-0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e,
+-0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677,
+-0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773,
+-0x0, 0x62616452, 0x78526362, 0x0,
+-0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469,
+-0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64,
+-0x6c657200, 0x63616e74, 0x31446d61, 0x0,
+-0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b,
+-0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461,
+-0x5f726561, 0x64795f63, 0x6b73756d, 0x0,
+-0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374,
+-0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00,
+-0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000,
+-0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561,
+-0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173,
+-0x73697374, 0x0, 0x74436b73, 0x6d4f6666,
+-0x0, 0x2b685f73, 0x656e645f, 0x62645f72,
+-0x65616479, 0x0, 0x68737453, 0x52696e67,
+-0x0, 0x62616453, 0x52696e67, 0x0,
+-0x6e696353, 0x52696e67, 0x0, 0x77446d61,
+-0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74,
+-0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0,
+-0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63,
+-0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77,
+-0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000,
+-0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74,
+-0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72,
+-0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77,
+-0x725f6173, 0x73697374, 0x0, 0x72436b73,
+-0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f,
+-0x62645f72, 0x65616479, 0x0, 0x2b685f72,
+-0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561,
+-0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69,
+-0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f,
+-0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572,
+-0x0, 0x2b685f64, 0x6f5f7570, 0x64617465,
+-0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64,
+-0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64,
+-0x0, 0x2b636b73, 0x756d3136, 0x0,
+-0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100,
+-0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0,
+-0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d,
+-0x61635f72, 0x785f6174, 0x746e0000, 0x62616452,
+-0x6574537a, 0x0, 0x72784264, 0x4266537a,
+-0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65,
+-0x72000000, 0x66774f70, 0x4661696c, 0x0,
+-0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000,
+-0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000,
+-0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000,
+-0x696e7453, 0x74617465, 0x0, 0x2a2a696e,
+-0x69744370, 0x0, 0x23736372, 0x65616d00,
+-0x69537461, 0x636b4572, 0x0, 0x70726f62,
+-0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42,
+-0x0, 0x2b73775f, 0x646d615f, 0x61737369,
+-0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000,
+-0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573,
+-0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264,
+-0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469,
+-0x6d657200, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e,
+-0x322e3335, 0x20313939, 0x392f3031, 0x2f323720,
+-0x31393a30, 0x393a3530, 0x20686179, 0x65732045,
+-0x78702024, 0x0, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x542d446d, 0x61526432,
+-0x0, 0x542d446d, 0x61526431, 0x0,
+-0x542d446d, 0x61526442, 0x0, 0x542d446d,
+-0x61577232, 0x0, 0x542d446d, 0x61577231,
+-0x0, 0x542d446d, 0x61577242, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e,
+-0x312e322e, 0x32382031, 0x3939392f, 0x30312f32,
+-0x30203139, 0x3a34393a, 0x34392073, 0x6875616e,
+-0x67204578, 0x70202400, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278,
+-0x0, 0x3f636d64, 0x48737453, 0x0,
+-0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
+-0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
+-0x0, 0x3f636d64, 0x45727200, 0x86ac,
+-0x8e5c, 0x8e5c, 0x8de4, 0x8b78,
+-0x8e30, 0x8e5c, 0x8790, 0x8800,
+-0x8990, 0x8a68, 0x8a34, 0x8e5c,
+-0x8870, 0x8b24, 0x8e5c, 0x8b34,
+-0x87b4, 0x8824, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e,
+-0x322e3820, 0x31393938, 0x2f31322f, 0x30382030,
+-0x323a3336, 0x3a333620, 0x73687561, 0x6e672045,
+-0x78702024, 0x0, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x6164644d, 0x63447570,
+-0x0, 0x6164644d, 0x6346756c, 0x0,
+-0x64656c4d, 0x634e6f45, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e,
+-0x32342031, 0x3939382f, 0x31322f32, 0x31203030,
+-0x3a33333a, 0x30392073, 0x6875616e, 0x67204578,
+-0x70202400, 0x65767452, 0x6e674600, 0x51657674,
+-0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
+-0x526e6746, 0x0, 0x4d516576, 0x74460000,
+-0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
+-0x0, 0x5173436f, 0x6e734600, 0x51725072,
+-0x6f644600, 0x7377446d, 0x614f6666, 0x0,
+-0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00,
+-0x2372446d, 0x6141544e, 0x0, 0x72446d61,
+-0x41544e30, 0x0, 0x72446d61, 0x41544e31,
+-0x0, 0x72446d61, 0x34476200, 0x2a50414e,
+-0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f,
+-0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63,
+-0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d,
+-0x6141544e, 0x0, 0x77446d61, 0x41544e30,
+-0x0, 0x77446d61, 0x41544e31, 0x0,
+-0x77446d61, 0x34476200, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e,
+-0x322e3520, 0x31393938, 0x2f30392f, 0x33302031,
+-0x383a3530, 0x3a323820, 0x73687561, 0x6e672045,
+-0x78702024, 0x0, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32,
+-0x2e313220, 0x31393939, 0x2f30312f, 0x32302031,
+-0x393a3439, 0x3a353120, 0x73687561, 0x6e672045,
+-0x78702024, 0x0, 0x46575f56, 0x45525349,
+-0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037,
+-0x2031373a, 0x35373a35, 0x32205044, 0x54203230,
+-0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54,
+-0x494d453a, 0x2031373a, 0x35373a35, 0x32000000,
+-0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064,
+-0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049,
+-0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465,
+-0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44,
+-0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f,
+-0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049,
+-0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e,
+-0x20322e37, 0x2e320000, 0x0, 0x12041100,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e,
+-0x35203139, 0x39382f30, 0x392f3330, 0x2031383a,
+-0x35303a30, 0x38207368, 0x75616e67, 0x20457870,
+-0x20240000, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32,
+-0x2e343420, 0x31393938, 0x2f31322f, 0x32312030,
+-0x303a3333, 0x3a313820, 0x73687561, 0x6e672045,
+-0x78702024, 0x0, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x69736e74, 0x54637055,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32,
+-0x2e353320, 0x31393939, 0x2f30312f, 0x31362030,
+-0x323a3535, 0x3a343320, 0x73687561, 0x6e672045,
+-0x78702024, 0x0, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x724d6163, 0x43686b30,
+-0x0, 0x72784672, 0x6d324c67, 0x0,
+-0x72784e6f, 0x53744264, 0x0, 0x72784e6f,
+-0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264,
+-0x0, 0x7278436b, 0x446d6146, 0x0,
+-0x72785144, 0x6d457846, 0x0, 0x72785144,
+-0x6d614600, 0x72785144, 0x4c426446, 0x0,
+-0x72785144, 0x6d426446, 0x0, 0x72784372,
+-0x63506164, 0x0, 0x72536d51, 0x446d6146,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e,
+-0x32322031, 0x3939382f, 0x31322f30, 0x38203032,
+-0x3a33363a, 0x33302073, 0x6875616e, 0x67204578,
+-0x70202400, 0x65767452, 0x6e674600, 0x51657674,
+-0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
+-0x526e6746, 0x0, 0x4d516576, 0x74460000,
+-0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
+-0x0, 0x5173436f, 0x6e734600, 0x51725072,
+-0x6f644600, 0x6d616354, 0x68726573, 0x0,
+-0x23744d61, 0x6341544e, 0x0, 0x23724d61,
+-0x6341544e, 0x0, 0x72656d41, 0x73737274,
+-0x0, 0x6c696e6b, 0x444f574e, 0x0,
+-0x6c696e6b, 0x55500000, 0x0, 0x0,
+-0x0, 0x24486561, 0x6465723a, 0x202f7072,
+-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+-0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e,
+-0x322e3920, 0x31393939, 0x2f30312f, 0x31342030,
+-0x303a3033, 0x3a343820, 0x73687561, 0x6e672045,
+-0x78702024, 0x0, 0x65767452, 0x6e674600,
+-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+-0x51725072, 0x6f644600, 0x0, 0x0,
+-0x0, 0x50726f62, 0x65506879, 0x0,
+-0x6c6e6b41, 0x53535254, 0x0, 0x109a4,
+-0x10a1c, 0x10a50, 0x10a7c, 0x11050,
+-0x10aa8, 0x10b10, 0x111fc, 0x10dc0,
+-0x10c68, 0x10c80, 0x10cc4, 0x10cec,
+-0x10d0c, 0x10d34, 0x111fc, 0x10dc0,
+-0x10df8, 0x10e10, 0x10e40, 0x10e68,
+-0x10e88, 0x10eb0, 0x0, 0x10fdc,
+-0x11008, 0x1102c, 0x111fc, 0x11050,
+-0x11078, 0x11108, 0x0, 0x0,
+-0x0, 0x1186c, 0x1193c, 0x11a14,
+-0x11ae4, 0x11b40, 0x11c1c, 0x11c44,
+-0x11d20, 0x11d48, 0x11ef0, 0x11f18,
+-0x120c0, 0x122b8, 0x1254c, 0x12460,
+-0x1254c, 0x12578, 0x120e8, 0x12290,
+-0x7273745f, 0x676d6969, 0x0, 0x12608,
+-0x12640, 0x12728, 0x13374, 0x133b4,
+-0x133cc, 0x7365746c, 0x6f6f7000, 0x0,
+-0x0, 0x13bbc, 0x13bfc, 0x13c8c,
+-0x13cd0, 0x13d34, 0x13dc0, 0x13df4,
+-0x13e7c, 0x13f14, 0x13fe4, 0x14024,
+-0x140a8, 0x140cc, 0x141dc, 0x646f4261,
+-0x73655067, 0x0, 0x0, 0x0,
+-0x0, 0x73746d61, 0x634c4e4b, 0x0,
+-0x6765746d, 0x636c6e6b, 0x0, 0x14ed8,
+-0x14ed8, 0x14b8c, 0x14bd8, 0x14c24,
+-0x14ed8, 0x7365746d, 0x61636163, 0x74000000,
++0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31,
++0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234,
++0x2030303a, 0x31303a35, 0x35207368, 0x75616e67,
++0x20457870, 0x20240000, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x6261644d, 0x656d537a,
++0x0, 0x68775665, 0x72000000, 0x62616448,
++0x77566572, 0x0, 0x2a2a4441, 0x574e5f41,
++0x0, 0x74785278, 0x4266537a, 0x0,
++0x62664174, 0x6e4d726b, 0x0, 0x7265645a,
++0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600,
++0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c,
++0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e,
++0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e,
++0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677,
++0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773,
++0x0, 0x62616452, 0x78526362, 0x0,
++0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469,
++0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64,
++0x6c657200, 0x63616e74, 0x31446d61, 0x0,
++0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b,
++0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461,
++0x5f726561, 0x64795f63, 0x6b73756d, 0x0,
++0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374,
++0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00,
++0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000,
++0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561,
++0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173,
++0x73697374, 0x0, 0x74436b73, 0x6d4f6666,
++0x0, 0x2b685f73, 0x656e645f, 0x62645f72,
++0x65616479, 0x0, 0x68737453, 0x52696e67,
++0x0, 0x62616453, 0x52696e67, 0x0,
++0x6e696353, 0x52696e67, 0x0, 0x77446d61,
++0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74,
++0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0,
++0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63,
++0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77,
++0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000,
++0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74,
++0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72,
++0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77,
++0x725f6173, 0x73697374, 0x0, 0x72436b73,
++0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f,
++0x62645f72, 0x65616479, 0x0, 0x2b685f72,
++0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561,
++0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69,
++0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f,
++0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572,
++0x0, 0x2b685f64, 0x6f5f7570, 0x64617465,
++0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64,
++0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64,
++0x0, 0x2b636b73, 0x756d3136, 0x0,
++0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100,
++0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0,
++0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d,
++0x61635f72, 0x785f6174, 0x746e0000, 0x62616452,
++0x6574537a, 0x0, 0x72784264, 0x4266537a,
++0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65,
++0x72000000, 0x66774f70, 0x4661696c, 0x0,
++0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000,
++0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000,
++0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000,
++0x696e7453, 0x74617465, 0x0, 0x2a2a696e,
++0x69744370, 0x0, 0x23736372, 0x65616d00,
++0x69537461, 0x636b4572, 0x0, 0x70726f62,
++0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42,
++0x0, 0x2b73775f, 0x646d615f, 0x61737369,
++0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000,
++0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573,
++0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264,
++0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469,
++0x6d657200, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e,
++0x322e3335, 0x20313939, 0x392f3031, 0x2f323720,
++0x31393a30, 0x393a3530, 0x20686179, 0x65732045,
++0x78702024, 0x0, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x542d446d, 0x61526432,
++0x0, 0x542d446d, 0x61526431, 0x0,
++0x542d446d, 0x61526442, 0x0, 0x542d446d,
++0x61577232, 0x0, 0x542d446d, 0x61577231,
++0x0, 0x542d446d, 0x61577242, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e,
++0x312e322e, 0x32382031, 0x3939392f, 0x30312f32,
++0x30203139, 0x3a34393a, 0x34392073, 0x6875616e,
++0x67204578, 0x70202400, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278,
++0x0, 0x3f636d64, 0x48737453, 0x0,
++0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
++0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
++0x0, 0x3f636d64, 0x45727200, 0x86ac,
++0x8e5c, 0x8e5c, 0x8de4, 0x8b78,
++0x8e30, 0x8e5c, 0x8790, 0x8800,
++0x8990, 0x8a68, 0x8a34, 0x8e5c,
++0x8870, 0x8b24, 0x8e5c, 0x8b34,
++0x87b4, 0x8824, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e,
++0x322e3820, 0x31393938, 0x2f31322f, 0x30382030,
++0x323a3336, 0x3a333620, 0x73687561, 0x6e672045,
++0x78702024, 0x0, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x6164644d, 0x63447570,
++0x0, 0x6164644d, 0x6346756c, 0x0,
++0x64656c4d, 0x634e6f45, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e,
++0x32342031, 0x3939382f, 0x31322f32, 0x31203030,
++0x3a33333a, 0x30392073, 0x6875616e, 0x67204578,
++0x70202400, 0x65767452, 0x6e674600, 0x51657674,
++0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
++0x526e6746, 0x0, 0x4d516576, 0x74460000,
++0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
++0x0, 0x5173436f, 0x6e734600, 0x51725072,
++0x6f644600, 0x7377446d, 0x614f6666, 0x0,
++0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00,
++0x2372446d, 0x6141544e, 0x0, 0x72446d61,
++0x41544e30, 0x0, 0x72446d61, 0x41544e31,
++0x0, 0x72446d61, 0x34476200, 0x2a50414e,
++0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f,
++0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63,
++0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d,
++0x6141544e, 0x0, 0x77446d61, 0x41544e30,
++0x0, 0x77446d61, 0x41544e31, 0x0,
++0x77446d61, 0x34476200, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e,
++0x322e3520, 0x31393938, 0x2f30392f, 0x33302031,
++0x383a3530, 0x3a323820, 0x73687561, 0x6e672045,
++0x78702024, 0x0, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32,
++0x2e313220, 0x31393939, 0x2f30312f, 0x32302031,
++0x393a3439, 0x3a353120, 0x73687561, 0x6e672045,
++0x78702024, 0x0, 0x46575f56, 0x45525349,
++0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037,
++0x2031373a, 0x35373a35, 0x32205044, 0x54203230,
++0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54,
++0x494d453a, 0x2031373a, 0x35373a35, 0x32000000,
++0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064,
++0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049,
++0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465,
++0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44,
++0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f,
++0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049,
++0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e,
++0x20322e37, 0x2e320000, 0x0, 0x12041100,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e,
++0x35203139, 0x39382f30, 0x392f3330, 0x2031383a,
++0x35303a30, 0x38207368, 0x75616e67, 0x20457870,
++0x20240000, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32,
++0x2e343420, 0x31393938, 0x2f31322f, 0x32312030,
++0x303a3333, 0x3a313820, 0x73687561, 0x6e672045,
++0x78702024, 0x0, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x69736e74, 0x54637055,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32,
++0x2e353320, 0x31393939, 0x2f30312f, 0x31362030,
++0x323a3535, 0x3a343320, 0x73687561, 0x6e672045,
++0x78702024, 0x0, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x724d6163, 0x43686b30,
++0x0, 0x72784672, 0x6d324c67, 0x0,
++0x72784e6f, 0x53744264, 0x0, 0x72784e6f,
++0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264,
++0x0, 0x7278436b, 0x446d6146, 0x0,
++0x72785144, 0x6d457846, 0x0, 0x72785144,
++0x6d614600, 0x72785144, 0x4c426446, 0x0,
++0x72785144, 0x6d426446, 0x0, 0x72784372,
++0x63506164, 0x0, 0x72536d51, 0x446d6146,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e,
++0x32322031, 0x3939382f, 0x31322f30, 0x38203032,
++0x3a33363a, 0x33302073, 0x6875616e, 0x67204578,
++0x70202400, 0x65767452, 0x6e674600, 0x51657674,
++0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
++0x526e6746, 0x0, 0x4d516576, 0x74460000,
++0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
++0x0, 0x5173436f, 0x6e734600, 0x51725072,
++0x6f644600, 0x6d616354, 0x68726573, 0x0,
++0x23744d61, 0x6341544e, 0x0, 0x23724d61,
++0x6341544e, 0x0, 0x72656d41, 0x73737274,
++0x0, 0x6c696e6b, 0x444f574e, 0x0,
++0x6c696e6b, 0x55500000, 0x0, 0x0,
++0x0, 0x24486561, 0x6465723a, 0x202f7072,
++0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
++0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
++0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e,
++0x322e3920, 0x31393939, 0x2f30312f, 0x31342030,
++0x303a3033, 0x3a343820, 0x73687561, 0x6e672045,
++0x78702024, 0x0, 0x65767452, 0x6e674600,
++0x51657674, 0x46000000, 0x51657674, 0x505f4600,
++0x4d657674, 0x526e6746, 0x0, 0x4d516576,
++0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
++0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
++0x51725072, 0x6f644600, 0x0, 0x0,
++0x0, 0x50726f62, 0x65506879, 0x0,
++0x6c6e6b41, 0x53535254, 0x0, 0x109a4,
++0x10a1c, 0x10a50, 0x10a7c, 0x11050,
++0x10aa8, 0x10b10, 0x111fc, 0x10dc0,
++0x10c68, 0x10c80, 0x10cc4, 0x10cec,
++0x10d0c, 0x10d34, 0x111fc, 0x10dc0,
++0x10df8, 0x10e10, 0x10e40, 0x10e68,
++0x10e88, 0x10eb0, 0x0, 0x10fdc,
++0x11008, 0x1102c, 0x111fc, 0x11050,
++0x11078, 0x11108, 0x0, 0x0,
++0x0, 0x1186c, 0x1193c, 0x11a14,
++0x11ae4, 0x11b40, 0x11c1c, 0x11c44,
++0x11d20, 0x11d48, 0x11ef0, 0x11f18,
++0x120c0, 0x122b8, 0x1254c, 0x12460,
++0x1254c, 0x12578, 0x120e8, 0x12290,
++0x7273745f, 0x676d6969, 0x0, 0x12608,
++0x12640, 0x12728, 0x13374, 0x133b4,
++0x133cc, 0x7365746c, 0x6f6f7000, 0x0,
++0x0, 0x13bbc, 0x13bfc, 0x13c8c,
++0x13cd0, 0x13d34, 0x13dc0, 0x13df4,
++0x13e7c, 0x13f14, 0x13fe4, 0x14024,
++0x140a8, 0x140cc, 0x141dc, 0x646f4261,
++0x73655067, 0x0, 0x0, 0x0,
++0x0, 0x73746d61, 0x634c4e4b, 0x0,
++0x6765746d, 0x636c6e6b, 0x0, 0x14ed8,
++0x14ed8, 0x14b8c, 0x14bd8, 0x14c24,
++0x14ed8, 0x7365746d, 0x61636163, 0x74000000,
+ 0x0, 0x0 };
+ static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
+-0x1,
+-0x1, 0x1, 0xc001fc, 0x3ffc,
+-0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
+-0x43205600, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x416c7465,
+-0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
+-0x0, 0x0, 0x0, 0x1ffffc,
+-0x1fff7c, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x60cf00,
+-0x60, 0xcf000000, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x3, 0x0,
+-0x1, 0x0, 0x0, 0x0,
+-0x1, 0x0, 0x1, 0x0,
+-0x0, 0x0, 0x0, 0x1,
+-0x1, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x1000000, 0x21000000,
+-0x12000140, 0x0, 0x0, 0x20000000,
+-0x120000a0, 0x0, 0x12000060, 0x12000180,
+-0x120001e0, 0x0, 0x0, 0x0,
+-0x1, 0x0, 0x0, 0x0,
+-0x0, 0x0, 0x0, 0x2,
+-0x0, 0x0, 0x30001, 0x1,
+-0x30201, 0x0, 0x0, 0x1010101,
+-0x1010100, 0x10100, 0x1010001, 0x10001,
++0x1,
++0x1, 0x1, 0xc001fc, 0x3ffc,
++0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
++0x43205600, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x416c7465,
++0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
++0x0, 0x0, 0x0, 0x1ffffc,
++0x1fff7c, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x60cf00,
++0x60, 0xcf000000, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x3, 0x0,
++0x1, 0x0, 0x0, 0x0,
++0x1, 0x0, 0x1, 0x0,
++0x0, 0x0, 0x0, 0x1,
++0x1, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x1000000, 0x21000000,
++0x12000140, 0x0, 0x0, 0x20000000,
++0x120000a0, 0x0, 0x12000060, 0x12000180,
++0x120001e0, 0x0, 0x0, 0x0,
++0x1, 0x0, 0x0, 0x0,
++0x0, 0x0, 0x0, 0x2,
++0x0, 0x0, 0x30001, 0x1,
++0x30201, 0x0, 0x0, 0x1010101,
++0x1010100, 0x10100, 0x1010001, 0x10001,
+ 0x1000101, 0x101, 0x0, 0x0 };
+diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
+index ed322a7..ef65e59 100644
+--- a/drivers/net/amd8111e.c
++++ b/drivers/net/amd8111e.c
+@@ -1,8 +1,8 @@
+
+-/* Advanced Micro Devices Inc. AMD8111E Linux Network Driver
+- * Copyright (C) 2004 Advanced Micro Devices
++/* Advanced Micro Devices Inc. AMD8111E Linux Network Driver
++ * Copyright (C) 2004 Advanced Micro Devices
++ *
+ *
+- *
+ * Copyright 2001,2002 Jeff Garzik <jgarzik at mandrakesoft.com> [ 8139cp.c,tg3.c ]
+ * Copyright (C) 2001, 2002 David S. Miller (davem at redhat.com)[ tg3.c]
+ * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
+@@ -12,7 +12,7 @@
+ * Carsten Langgaard, carstenl at mips.com [ pcnet32.c ]
+ * Copyright (C) 2000 MIPS Technologies, Inc. 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
+@@ -25,16 +25,16 @@
+ *
+ * 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
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+-
++
+ Module Name:
+
+ amd8111e.c
+
+ Abstract:
+-
+- AMD8111 based 10/100 Ethernet Controller Driver.
++
++ AMD8111 based 10/100 Ethernet Controller Driver.
+
+ Environment:
+
+@@ -58,13 +58,13 @@ Revision History:
+ 3.0.4 12/09/2003
+ 1. Added set_mac_address routine for bonding driver support.
+ 2. Tested the driver for bonding support
+- 3. Bug fix: Fixed mismach in actual receive buffer lenth and lenth
++ 3. Bug fix: Fixed mismach in actual receive buffer lenth and lenth
+ indicated to the h/w.
+- 4. Modified amd8111e_rx() routine to receive all the received packets
++ 4. Modified amd8111e_rx() routine to receive all the received packets
+ in the first interrupt.
+ 5. Bug fix: Corrected rx_errors reported in get_stats() function.
+ 3.0.5 03/22/2004
+- 1. Added NAPI support
++ 1. Added NAPI support
+
+ */
+
+@@ -84,7 +84,7 @@ Revision History:
+ #include <linux/ethtool.h>
+ #include <linux/mii.h>
+ #include <linux/if_vlan.h>
+-#include <linux/ctype.h>
++#include <linux/ctype.h>
+ #include <linux/crc32.h>
+ #include <linux/dma-mapping.h>
+
+@@ -101,9 +101,9 @@ Revision History:
+
+ #include "amd8111e.h"
+ #define MODULE_NAME "amd8111e"
+-#define MODULE_VERS "3.0.5"
++#define MODULE_VERS "3.0.6"
+ MODULE_AUTHOR("Advanced Micro Devices, Inc.");
+-MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3");
++MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.6");
+ MODULE_LICENSE("GPL");
+ MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl);
+ module_param_array(speed_duplex, int, NULL, 0);
+@@ -114,13 +114,13 @@ module_param_array(dynamic_ipg, bool, NU
+ MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");
+
+ static struct pci_device_id amd8111e_pci_tbl[] = {
+-
++
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { 0, }
+
+ };
+-/*
++/*
+ This function will read the PHY registers.
+ */
+ static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
+@@ -141,17 +141,17 @@ static int amd8111e_read_phy(struct amd8
+ } while (--repeat && (reg_val & PHY_CMD_ACTIVE));
+ if(reg_val & PHY_RD_ERR)
+ goto err_phy_read;
+-
++
+ *val = reg_val & 0xffff;
+ return 0;
+-err_phy_read:
++err_phy_read:
+ *val = 0;
+ return -EINVAL;
+-
++
+ }
+
+-/*
+-This function will write into PHY registers.
++/*
++This function will write into PHY registers.
+ */
+ static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
+ {
+@@ -170,19 +170,19 @@ static int amd8111e_write_phy(struct amd
+ reg_val = readl(mmio + PHY_ACCESS);
+ udelay(30); /* It takes 30 us to read/write the data */
+ } while (--repeat && (reg_val & PHY_CMD_ACTIVE));
+-
++
+ if(reg_val & PHY_RD_ERR)
+ goto err_phy_write;
+-
++
+ return 0;
+
+-err_phy_write:
++err_phy_write:
+ return -EINVAL;
+-
++
+ }
+-/*
++/*
+ This is the mii register read function provided to the mii interface.
+-*/
++*/
+ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num)
+ {
+ struct amd8111e_priv* lp = netdev_priv(dev);
+@@ -190,12 +190,12 @@ static int amd8111e_mdio_read(struct net
+
+ amd8111e_read_phy(lp,phy_id,reg_num,®_val);
+ return reg_val;
+-
++
+ }
+
+-/*
++/*
+ This is the mii register write function provided to the mii interface.
+-*/
++*/
+ static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val)
+ {
+ struct amd8111e_priv* lp = netdev_priv(dev);
+@@ -210,7 +210,7 @@ static void amd8111e_set_ext_phy(struct
+ {
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ u32 bmcr,advert,tmp;
+-
++
+ /* Determine mii register values to set the speed */
+ advert = amd8111e_mdio_read(dev, lp->ext_phy_addr, MII_ADVERTISE);
+ tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+@@ -227,7 +227,7 @@ static void amd8111e_set_ext_phy(struct
+ case SPEED10_FULL:
+ tmp |= ADVERTISE_10FULL;
+ break;
+- case SPEED100_HALF:
++ case SPEED100_HALF:
+ tmp |= ADVERTISE_100HALF;
+ break;
+ case SPEED100_FULL:
+@@ -244,8 +244,8 @@ static void amd8111e_set_ext_phy(struct
+
+ }
+
+-/*
+-This function will unmap skb->data space and will free
++/*
++This function will unmap skb->data space and will free
+ all transmit and receive skbuffs.
+ */
+ static int amd8111e_free_skbs(struct net_device *dev)
+@@ -274,7 +274,7 @@ static int amd8111e_free_skbs(struct net
+ lp->rx_dma_addr[i] = 0;
+ }
+ }
+-
++
+ return 0;
+ }
+
+@@ -285,7 +285,7 @@ static inline void amd8111e_set_rx_buff_
+ {
+ struct amd8111e_priv* lp = netdev_priv(dev);
+ unsigned int mtu = dev->mtu;
+-
++
+ if (mtu > ETH_DATA_LEN){
+ /* MTU + ethernet header + FCS
+ + optional VLAN tag + skb reserve space 2 */
+@@ -298,7 +298,7 @@ static inline void amd8111e_set_rx_buff_
+ }
+ }
+
+-/*
++/*
+ This function will free all the previously allocated buffers, determine new receive buffer length and will allocate new receive buffers. This function also allocates and initializes both the transmitter and receive hardware descriptors.
+ */
+ static int amd8111e_init_ring(struct net_device *dev)
+@@ -309,24 +309,24 @@ static int amd8111e_init_ring(struct net
+ lp->rx_idx = lp->tx_idx = 0;
+ lp->tx_complete_idx = 0;
+ lp->tx_ring_idx = 0;
+-
++
+
+ if(lp->opened)
+ /* Free previously allocated transmit and receive skbs */
+- amd8111e_free_skbs(dev);
++ amd8111e_free_skbs(dev);
+
+ else{
+ /* allocate the tx and rx descriptors */
+- if((lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
++ if((lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,
+ &lp->tx_ring_dma_addr)) == NULL)
+-
++
+ goto err_no_mem;
+-
+- if((lp->rx_ring = pci_alloc_consistent(lp->pci_dev,
++
++ if((lp->rx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,
+ &lp->rx_ring_dma_addr)) == NULL)
+-
++
+ goto err_free_tx_ring;
+
+ }
+@@ -346,7 +346,7 @@ static int amd8111e_init_ring(struct net
+ }
+ /* Initilaizing receive descriptors */
+ for (i = 0; i < NUM_RX_BUFFERS; i++) {
+- lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev,
++ lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev,
+ lp->rx_skbuff[i]->data,lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
+
+ lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
+@@ -365,15 +365,15 @@ static int amd8111e_init_ring(struct net
+ return 0;
+
+ err_free_rx_ring:
+-
+- pci_free_consistent(lp->pci_dev,
++
++ pci_free_consistent(lp->pci_dev,
+ sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,lp->rx_ring,
+ lp->rx_ring_dma_addr);
+
+ err_free_tx_ring:
+-
++
+ pci_free_consistent(lp->pci_dev,
+- sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,lp->tx_ring,
++ sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,lp->tx_ring,
+ lp->tx_ring_dma_addr);
+
+ err_no_mem:
+@@ -395,11 +395,11 @@ static int amd8111e_set_coalesce(struct
+ case RX_INTR_COAL :
+ timeout = coal_conf->rx_timeout;
+ event_count = coal_conf->rx_event_count;
+- if( timeout > MAX_TIMEOUT ||
+- event_count > MAX_EVENT_COUNT )
++ if( timeout > MAX_TIMEOUT ||
++ event_count > MAX_EVENT_COUNT )
+ return -EINVAL;
+
+- timeout = timeout * DELAY_TIMER_CONV;
++ timeout = timeout * DELAY_TIMER_CONV;
+ writel(VAL0|STINTEN, mmio+INTEN0);
+ writel((u32)DLY_INT_A_R0|( event_count<< 16 )|timeout,
+ mmio+DLY_INT_A);
+@@ -408,12 +408,12 @@ static int amd8111e_set_coalesce(struct
+ case TX_INTR_COAL :
+ timeout = coal_conf->tx_timeout;
+ event_count = coal_conf->tx_event_count;
+- if( timeout > MAX_TIMEOUT ||
+- event_count > MAX_EVENT_COUNT )
++ if( timeout > MAX_TIMEOUT ||
++ event_count > MAX_EVENT_COUNT )
+ return -EINVAL;
+
+-
+- timeout = timeout * DELAY_TIMER_CONV;
++
++ timeout = timeout * DELAY_TIMER_CONV;
+ writel(VAL0|STINTEN,mmio+INTEN0);
+ writel((u32)DLY_INT_B_T0|( event_count<< 16 )|timeout,
+ mmio+DLY_INT_B);
+@@ -425,7 +425,7 @@ static int amd8111e_set_coalesce(struct
+ writel(0, mmio +DLY_INT_B);
+ writel(0, mmio+DLY_INT_A);
+ break;
+- case ENABLE_COAL:
++ case ENABLE_COAL:
+ /* Start the timer */
+ writel((u32)SOFT_TIMER_FREQ, mmio+STVAL); /* 0.5 sec */
+ writel(VAL0|STINTEN, mmio+INTEN0);
+@@ -438,8 +438,8 @@ static int amd8111e_set_coalesce(struct
+
+ }
+
+-/*
+-This function initializes the device registers and starts the device.
++/*
++This function initializes the device registers and starts the device.
+ */
+ static int amd8111e_restart(struct net_device *dev)
+ {
+@@ -455,8 +455,8 @@ static int amd8111e_restart(struct net_d
+
+ /* enable the port manager and set auto negotiation always */
+ writel((u32) VAL1|EN_PMGR, mmio + CMD3 );
+- writel((u32)XPHYANE|XPHYRST , mmio + CTRL2);
+-
++ writel((u32)XPHYANE|XPHYRST , mmio + CTRL2);
++
+ amd8111e_set_ext_phy(dev);
+
+ /* set control registers */
+@@ -465,7 +465,7 @@ static int amd8111e_restart(struct net_d
+ writel( reg_val| XMTSP_128 | CACHE_ALIGN, mmio + CTRL1 );
+
+ /* enable interrupt */
+- writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN |
++ writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN |
+ APINT0EN | MIIPDTINTEN | MCCIINTEN | MCCINTEN | MREINTEN |
+ SPNDINTEN | MPINTEN | SINTEN | STINTEN, mmio + INTEN0);
+
+@@ -477,10 +477,10 @@ static int amd8111e_restart(struct net_d
+
+ writew((u32)NUM_TX_RING_DR, mmio + XMT_RING_LEN0);
+ writew((u16)NUM_RX_RING_DR, mmio + RCV_RING_LEN0);
+-
++
+ /* set default IPG to 96 */
+ writew((u32)DEFAULT_IPG,mmio+IPG);
+- writew((u32)(DEFAULT_IPG-IFS1_DELTA), mmio + IFS1);
++ writew((u32)(DEFAULT_IPG-IFS1_DELTA), mmio + IFS1);
+
+ if(lp->options & OPTION_JUMBO_ENABLE){
+ writel((u32)VAL2|JUMBO, mmio + CMD3);
+@@ -497,10 +497,10 @@ static int amd8111e_restart(struct net_d
+ writel((u32) VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3);
+ #endif
+ writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2 );
+-
++
+ /* Setting the MAC address to the device */
+ for(i = 0; i < ETH_ADDR_LEN; i++)
+- writeb( dev->dev_addr[i], mmio + PADR + i );
++ writeb( dev->dev_addr[i], mmio + PADR + i );
+
+ /* Enable interrupt coalesce */
+ if(lp->options & OPTION_INTR_COAL_ENABLE){
+@@ -508,18 +508,18 @@ static int amd8111e_restart(struct net_d
+ dev->name);
+ amd8111e_set_coalesce(dev,ENABLE_COAL);
+ }
+-
++
+ /* set RUN bit to start the chip */
+ writel(VAL2 | RDMD0, mmio + CMD0);
+ writel(VAL0 | INTREN | RUN, mmio + CMD0);
+-
++
+ /* To avoid PCI posting bug */
+ readl(mmio+CMD0);
+ return 0;
+ }
+-/*
+-This function clears necessary the device registers.
+-*/
++/*
++This function clears necessary the device registers.
++*/
+ static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
+ {
+ unsigned int reg_val;
+@@ -544,7 +544,7 @@ static void amd8111e_init_hw_default( st
+
+ /* Clear CMD0 */
+ writel(CMD0_CLEAR,mmio + CMD0);
+-
++
+ /* Clear CMD2 */
+ writel(CMD2_CLEAR, mmio +CMD2);
+
+@@ -594,7 +594,7 @@ static void amd8111e_init_hw_default( st
+
+ /* SRAM_SIZE register */
+ reg_val = readl(mmio + SRAM_SIZE);
+-
++
+ if(lp->options & OPTION_JUMBO_ENABLE)
+ writel( VAL2|JUMBO, mmio + CMD3);
+ #if AMD8111E_VLAN_TAG_USED
+@@ -608,56 +608,56 @@ static void amd8111e_init_hw_default( st
+
+ }
+
+-/*
+-This function disables the interrupt and clears all the pending
++/*
++This function disables the interrupt and clears all the pending
+ interrupts in INT0
+ */
+ static void amd8111e_disable_interrupt(struct amd8111e_priv* lp)
+-{
++{
+ u32 intr0;
+
+ /* Disable interrupt */
+ writel(INTREN, lp->mmio + CMD0);
+-
++
+ /* Clear INT0 */
+ intr0 = readl(lp->mmio + INT0);
+ writel(intr0, lp->mmio + INT0);
+-
++
+ /* To avoid PCI posting bug */
+ readl(lp->mmio + INT0);
+
+ }
+
+ /*
+-This function stops the chip.
++This function stops the chip.
+ */
+ static void amd8111e_stop_chip(struct amd8111e_priv* lp)
+ {
+ writel(RUN, lp->mmio + CMD0);
+-
++
+ /* To avoid PCI posting bug */
+ readl(lp->mmio + CMD0);
+ }
+
+-/*
++/*
+ This function frees the transmiter and receiver descriptor rings.
+ */
+ static void amd8111e_free_ring(struct amd8111e_priv* lp)
+-{
++{
+
+ /* Free transmit and receive skbs */
+ amd8111e_free_skbs(lp->amd8111e_net_dev);
+
+ /* Free transmit and receive descriptor rings */
+ if(lp->rx_ring){
+- pci_free_consistent(lp->pci_dev,
++ pci_free_consistent(lp->pci_dev,
+ sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,
+ lp->rx_ring, lp->rx_ring_dma_addr);
+ lp->rx_ring = NULL;
+ }
+-
++
+ if(lp->tx_ring){
+- pci_free_consistent(lp->pci_dev,
++ pci_free_consistent(lp->pci_dev,
+ sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,
+ lp->tx_ring, lp->tx_ring_dma_addr);
+
+@@ -665,10 +665,10 @@ static void amd8111e_free_ring(struct am
+ }
+
+ }
+-#if AMD8111E_VLAN_TAG_USED
+-/*
++#if AMD8111E_VLAN_TAG_USED
++/*
+ This is the receive indication function for packets with vlan tag.
+-*/
++*/
+ static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 vlan_tag)
+ {
+ #ifdef CONFIG_AMD8111E_NAPI
+@@ -680,7 +680,7 @@ static int amd8111e_vlan_rx(struct amd81
+ #endif
+
+ /*
+-This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb.
++This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb.
+ */
+ static int amd8111e_tx(struct net_device *dev)
+ {
+@@ -709,7 +709,7 @@ static int amd8111e_tx(struct net_device
+ lp->tx_complete_idx++;
+ /*COAL update tx coalescing parameters */
+ lp->coal_conf.tx_packets++;
+- lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
++ lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
+
+ if (netif_queue_stopped(dev) &&
+ lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
+@@ -734,13 +734,13 @@ static int amd8111e_rx_poll(struct net_d
+ int num_rx_pkt = 0;
+ /*int max_rx_pkt = NUM_RX_BUFFERS;*/
+ short pkt_len;
+-#if AMD8111E_VLAN_TAG_USED
++#if AMD8111E_VLAN_TAG_USED
+ short vtag;
+ #endif
+ int rx_pkt_limit = dev->quota;
+ unsigned long flags;
+-
+- do{
++
++ do{
+ /* process receive packets until we use the quota*/
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while(1) {
+@@ -748,11 +748,11 @@ static int amd8111e_rx_poll(struct net_d
+ if (status & OWN_BIT)
+ break;
+
+- /*
++ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf at perftech.com> to Russ Nelson: Even with
+- * full-sized * buffers it's possible for a
+- * jabber packet to use two buffers, with only
++ * full-sized * buffers it's possible for a
++ * jabber packet to use two buffers, with only
+ * the last correctly noting the error.
+ */
+
+@@ -769,9 +769,9 @@ static int amd8111e_rx_poll(struct net_d
+ }
+ pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
+
+-#if AMD8111E_VLAN_TAG_USED
++#if AMD8111E_VLAN_TAG_USED
+ vtag = status & TT_MASK;
+- /*MAC will strip vlan tag*/
++ /*MAC will strip vlan tag*/
+ if(lp->vlgrp != NULL && vtag !=0)
+ min_pkt_len =MIN_PKT_LEN - 4;
+ else
+@@ -786,13 +786,13 @@ static int amd8111e_rx_poll(struct net_d
+ if(--rx_pkt_limit < 0)
+ goto rx_not_empty;
+ if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
+- /* if allocation fail,
++ /* if allocation fail,
+ ignore that pkt and go to next one */
+ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+ lp->drv_rx_errors++;
+ goto err_next_pkt;
+ }
+-
++
+ skb_reserve(new_skb, 2);
+ skb = lp->rx_skbuff[rx_index];
+ pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
+@@ -805,10 +805,10 @@ static int amd8111e_rx_poll(struct net_d
+ new_skb->data,
+ lp->rx_buff_len-2,
+ PCI_DMA_FROMDEVICE);
+-
++
+ skb->protocol = eth_type_trans(skb, dev);
+
+-#if AMD8111E_VLAN_TAG_USED
++#if AMD8111E_VLAN_TAG_USED
+ if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
+ amd8111e_vlan_rx(lp, skb,
+ le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
+@@ -817,20 +817,20 @@ static int amd8111e_rx_poll(struct net_d
+ netif_receive_skb(skb);
+ /*COAL update rx coalescing parameters*/
+ lp->coal_conf.rx_packets++;
+- lp->coal_conf.rx_bytes += pkt_len;
++ lp->coal_conf.rx_bytes += pkt_len;
+ num_rx_pkt++;
+ dev->last_rx = jiffies;
+-
+- err_next_pkt:
++
++ err_next_pkt:
+ lp->rx_ring[rx_index].buff_phy_addr
+ = cpu_to_le32(lp->rx_dma_addr[rx_index]);
+- lp->rx_ring[rx_index].buff_count =
++ lp->rx_ring[rx_index].buff_count =
+ cpu_to_le16(lp->rx_buff_len-2);
+ wmb();
+ lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
+ rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
+ }
+- /* Check the interrupt status register for more packets in the
++ /* Check the interrupt status register for more packets in the
+ mean time. Process them since we have not used up our quota.*/
+
+ intr0 = readl(mmio + INT0);
+@@ -852,13 +852,13 @@ static int amd8111e_rx_poll(struct net_d
+
+ rx_not_empty:
+ /* Do not call a netif_rx_complete */
+- dev->quota -= num_rx_pkt;
++ dev->quota -= num_rx_pkt;
+ *budget -= num_rx_pkt;
+ return 1;
+ }
+
+ #else
+-/*
++/*
+ This function will check the ownership of receive buffers and descriptors. It will indicate to kernel up to half the number of maximum receive buffers in the descriptor ring, in a single receive interrupt. It will also replenish the descriptors with new skbs.
+ */
+ static int amd8111e_rx(struct net_device *dev)
+@@ -870,19 +870,19 @@ static int amd8111e_rx(struct net_device
+ int num_rx_pkt = 0;
+ int max_rx_pkt = NUM_RX_BUFFERS;
+ short pkt_len;
+-#if AMD8111E_VLAN_TAG_USED
++#if AMD8111E_VLAN_TAG_USED
+ short vtag;
+ #endif
+-
++
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while(++num_rx_pkt <= max_rx_pkt){
+ status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
+ if(status & OWN_BIT)
+ return 0;
+-
+- /* check if err summary bit is set */
++
++ /* check if err summary bit is set */
+ if(status & ERR_BIT){
+- /*
++ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf at perftech.com> to Russ Nelson: Even with full-sized
+ * buffers it's possible for a jabber packet to use two
+@@ -899,9 +899,9 @@ static int amd8111e_rx(struct net_device
+ }
+ pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
+
+-#if AMD8111E_VLAN_TAG_USED
++#if AMD8111E_VLAN_TAG_USED
+ vtag = status & TT_MASK;
+- /*MAC will strip vlan tag*/
++ /*MAC will strip vlan tag*/
+ if(lp->vlgrp != NULL && vtag !=0)
+ min_pkt_len =MIN_PKT_LEN - 4;
+ else
+@@ -914,13 +914,13 @@ static int amd8111e_rx(struct net_device
+ goto err_next_pkt;
+ }
+ if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
+- /* if allocation fail,
++ /* if allocation fail,
+ ignore that pkt and go to next one */
+ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+ lp->drv_rx_errors++;
+ goto err_next_pkt;
+ }
+-
++
+ skb_reserve(new_skb, 2);
+ skb = lp->rx_skbuff[rx_index];
+ pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
+@@ -931,27 +931,27 @@ static int amd8111e_rx(struct net_device
+ new_skb->dev = dev;
+ lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
+ new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);
+-
++
+ skb->protocol = eth_type_trans(skb, dev);
+
+-#if AMD8111E_VLAN_TAG_USED
++#if AMD8111E_VLAN_TAG_USED
+ if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
+ amd8111e_vlan_rx(lp, skb,
+ le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
+ } else
+ #endif
+-
++
+ netif_rx (skb);
+ /*COAL update rx coalescing parameters*/
+ lp->coal_conf.rx_packets++;
+- lp->coal_conf.rx_bytes += pkt_len;
++ lp->coal_conf.rx_bytes += pkt_len;
+
+ dev->last_rx = jiffies;
+-
++
+ err_next_pkt:
+ lp->rx_ring[rx_index].buff_phy_addr
+ = cpu_to_le32(lp->rx_dma_addr[rx_index]);
+- lp->rx_ring[rx_index].buff_count =
++ lp->rx_ring[rx_index].buff_count =
+ cpu_to_le16(lp->rx_buff_len-2);
+ wmb();
+ lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
+@@ -961,26 +961,26 @@ err_next_pkt:
+ return 0;
+ }
+ #endif /* CONFIG_AMD8111E_NAPI */
+-/*
++/*
+ This function will indicate the link status to the kernel.
+ */
+ static int amd8111e_link_change(struct net_device* dev)
+-{
++{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ int status0,speed;
+
+ /* read the link change */
+ status0 = readl(lp->mmio + STAT0);
+-
++
+ if(status0 & LINK_STATS){
+ if(status0 & AUTONEG_COMPLETE)
+ lp->link_config.autoneg = AUTONEG_ENABLE;
+- else
++ else
+ lp->link_config.autoneg = AUTONEG_DISABLE;
+
+ if(status0 & FULL_DPLX)
+ lp->link_config.duplex = DUPLEX_FULL;
+- else
++ else
+ lp->link_config.duplex = DUPLEX_HALF;
+ speed = (status0 & SPEED_MASK) >> 7;
+ if(speed == PHY_SPEED_10)
+@@ -989,22 +989,22 @@ static int amd8111e_link_change(struct n
+ lp->link_config.speed = SPEED_100;
+
+ printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n", dev->name,
+- (lp->link_config.speed == SPEED_100) ? "100": "10",
+- (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half");
++ (lp->link_config.speed == SPEED_100) ? "100": "10",
++ (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half");
+ netif_carrier_on(dev);
+ }
+- else{
++ else{
+ lp->link_config.speed = SPEED_INVALID;
+ lp->link_config.duplex = DUPLEX_INVALID;
+ lp->link_config.autoneg = AUTONEG_INVALID;
+ printk(KERN_INFO "%s: Link is Down.\n",dev->name);
+ netif_carrier_off(dev);
+ }
+-
++
+ return 0;
+ }
+ /*
+-This function reads the mib counters.
++This function reads the mib counters.
+ */
+ static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
+ {
+@@ -1025,7 +1025,7 @@ static int amd8111e_read_mib(void __iome
+
+ /*
+ This function reads the mib registers and returns the hardware statistics. It updates previous internal driver statistics with new values.
+-*/
++*/
+ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
+ {
+ struct amd8111e_priv *lp = netdev_priv(dev);
+@@ -1033,9 +1033,9 @@ static struct net_device_stats *amd8111e
+ unsigned long flags;
+ /* struct net_device_stats *prev_stats = &lp->prev_stats; */
+ struct net_device_stats* new_stats = &lp->stats;
+-
++
+ if(!lp->opened)
+- return &lp->stats;
++ return &lp->stats;
+ spin_lock_irqsave (&lp->lock, flags);
+
+ /* stats.rx_packets */
+@@ -1078,7 +1078,7 @@ static struct net_device_stats *amd8111e
+ new_stats->collisions = amd8111e_read_mib(mmio, xmt_collisions);
+
+ /* stats.rx_length_errors*/
+- new_stats->rx_length_errors =
++ new_stats->rx_length_errors =
+ amd8111e_read_mib(mmio, rcv_undersize_pkts)+
+ amd8111e_read_mib(mmio, rcv_oversize_pkts);
+
+@@ -1099,11 +1099,11 @@ static struct net_device_stats *amd8111e
+ new_stats->rx_missed_errors = amd8111e_read_mib(mmio, rcv_miss_pkts);
+
+ /* stats.tx_aborted_errors*/
+- new_stats->tx_aborted_errors =
++ new_stats->tx_aborted_errors =
+ amd8111e_read_mib(mmio, xmt_excessive_collision);
+
+ /* stats.tx_carrier_errors*/
+- new_stats->tx_carrier_errors =
++ new_stats->tx_carrier_errors =
+ amd8111e_read_mib(mmio, xmt_loss_carrier);
+
+ /* stats.tx_fifo_errors*/
+@@ -1115,12 +1115,12 @@ static struct net_device_stats *amd8111e
+
+ /* Reset the mibs for collecting new statistics */
+ /* writew(MIB_CLEAR, mmio + MIB_ADDR);*/
+-
++
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ return new_stats;
+ }
+-/* This function recalculate the interupt coalescing mode on every interrupt
++/* This function recalculate the interupt coalescing mode on every interrupt
+ according to the datarate and the packet rate.
+ */
+ static int amd8111e_calc_coalesce(struct net_device *dev)
+@@ -1136,19 +1136,19 @@ static int amd8111e_calc_coalesce(struct
+
+ tx_pkt_rate = coal_conf->tx_packets - coal_conf->tx_prev_packets;
+ coal_conf->tx_prev_packets = coal_conf->tx_packets;
+-
++
+ tx_data_rate = coal_conf->tx_bytes - coal_conf->tx_prev_bytes;
+ coal_conf->tx_prev_bytes = coal_conf->tx_bytes;
+-
++
+ rx_pkt_rate = coal_conf->rx_packets - coal_conf->rx_prev_packets;
+ coal_conf->rx_prev_packets = coal_conf->rx_packets;
+-
++
+ rx_data_rate = coal_conf->rx_bytes - coal_conf->rx_prev_bytes;
+ coal_conf->rx_prev_bytes = coal_conf->rx_bytes;
+-
++
+ if(rx_pkt_rate < 800){
+ if(coal_conf->rx_coal_type != NO_COALESCE){
+-
++
+ coal_conf->rx_timeout = 0x0;
+ coal_conf->rx_event_count = 0;
+ amd8111e_set_coalesce(dev,RX_INTR_COAL);
+@@ -1156,11 +1156,11 @@ static int amd8111e_calc_coalesce(struct
+ }
+ }
+ else{
+-
++
+ rx_pkt_size = rx_data_rate/rx_pkt_rate;
+ if (rx_pkt_size < 128){
+ if(coal_conf->rx_coal_type != NO_COALESCE){
+-
++
+ coal_conf->rx_timeout = 0;
+ coal_conf->rx_event_count = 0;
+ amd8111e_set_coalesce(dev,RX_INTR_COAL);
+@@ -1169,7 +1169,7 @@ static int amd8111e_calc_coalesce(struct
+
+ }
+ else if ( (rx_pkt_size >= 128) && (rx_pkt_size < 512) ){
+-
++
+ if(coal_conf->rx_coal_type != LOW_COALESCE){
+ coal_conf->rx_timeout = 1;
+ coal_conf->rx_event_count = 4;
+@@ -1178,14 +1178,14 @@ static int amd8111e_calc_coalesce(struct
+ }
+ }
+ else if ((rx_pkt_size >= 512) && (rx_pkt_size < 1024)){
+-
++
+ if(coal_conf->rx_coal_type != MEDIUM_COALESCE){
+ coal_conf->rx_timeout = 1;
+ coal_conf->rx_event_count = 4;
+ amd8111e_set_coalesce(dev,RX_INTR_COAL);
+ coal_conf->rx_coal_type = MEDIUM_COALESCE;
+- }
+-
++ }
++
+ }
+ else if(rx_pkt_size >= 1024){
+ if(coal_conf->rx_coal_type != HIGH_COALESCE){
+@@ -1193,13 +1193,13 @@ static int amd8111e_calc_coalesce(struct
+ coal_conf->rx_event_count = 3;
+ amd8111e_set_coalesce(dev,RX_INTR_COAL);
+ coal_conf->rx_coal_type = HIGH_COALESCE;
+- }
++ }
+ }
+ }
+ /* NOW FOR TX INTR COALESC */
+ if(tx_pkt_rate < 800){
+ if(coal_conf->tx_coal_type != NO_COALESCE){
+-
++
+ coal_conf->tx_timeout = 0x0;
+ coal_conf->tx_event_count = 0;
+ amd8111e_set_coalesce(dev,TX_INTR_COAL);
+@@ -1207,12 +1207,12 @@ static int amd8111e_calc_coalesce(struct
+ }
+ }
+ else{
+-
++
+ tx_pkt_size = tx_data_rate/tx_pkt_rate;
+ if (tx_pkt_size < 128){
+-
++
+ if(coal_conf->tx_coal_type != NO_COALESCE){
+-
++
+ coal_conf->tx_timeout = 0;
+ coal_conf->tx_event_count = 0;
+ amd8111e_set_coalesce(dev,TX_INTR_COAL);
+@@ -1221,7 +1221,7 @@ static int amd8111e_calc_coalesce(struct
+
+ }
+ else if ( (tx_pkt_size >= 128) && (tx_pkt_size < 512) ){
+-
++
+ if(coal_conf->tx_coal_type != LOW_COALESCE){
+ coal_conf->tx_timeout = 1;
+ coal_conf->tx_event_count = 2;
+@@ -1231,14 +1231,14 @@ static int amd8111e_calc_coalesce(struct
+ }
+ }
+ else if ((tx_pkt_size >= 512) && (tx_pkt_size < 1024)){
+-
++
+ if(coal_conf->tx_coal_type != MEDIUM_COALESCE){
+ coal_conf->tx_timeout = 2;
+ coal_conf->tx_event_count = 5;
+ amd8111e_set_coalesce(dev,TX_INTR_COAL);
+ coal_conf->tx_coal_type = MEDIUM_COALESCE;
+- }
+-
++ }
++
+ }
+ else if(tx_pkt_size >= 1024){
+ if (tx_pkt_size >= 1024){
+@@ -1247,7 +1247,7 @@ static int amd8111e_calc_coalesce(struct
+ coal_conf->tx_event_count = 8;
+ amd8111e_set_coalesce(dev,TX_INTR_COAL);
+ coal_conf->tx_coal_type = HIGH_COALESCE;
+- }
++ }
+ }
+ }
+ }
+@@ -1257,7 +1257,7 @@ static int amd8111e_calc_coalesce(struct
+ /*
+ This is device interrupt function. It handles transmit, receive,link change and hardware timer interrupts.
+ */
+-static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t amd8111e_interrupt(int irq, void *dev_id)
+ {
+
+ struct net_device * dev = (struct net_device *) dev_id;
+@@ -1284,7 +1284,7 @@ static irqreturn_t amd8111e_interrupt(in
+ handled = 0;
+ goto err_no_interrupt;
+ }
+-
++
+ /* Current driver processes 4 interrupts : RINT,TINT,LCINT,STINT */
+ writel(intr0, mmio + INT0);
+
+@@ -1313,7 +1313,7 @@ static irqreturn_t amd8111e_interrupt(in
+ /* Check if Transmit Interrupt has occurred. */
+ if(intr0 & TINT0)
+ amd8111e_tx(dev);
+-
++
+ /* Check if Link Change Interrupt has occurred. */
+ if (intr0 & LCINT)
+ amd8111e_link_change(dev);
+@@ -1324,21 +1324,21 @@ static irqreturn_t amd8111e_interrupt(in
+
+ err_no_interrupt:
+ writel( VAL0 | INTREN,mmio + CMD0);
+-
++
+ spin_unlock(&lp->lock);
+-
++
+ return IRQ_RETVAL(handled);
+ }
+
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ static void amd8111e_poll(struct net_device *dev)
+-{
++{
+ unsigned long flags;
+- local_save_flags(flags);
++ local_save_flags(flags);
+ local_irq_disable();
+- amd8111e_interrupt(0, dev, NULL);
+- local_irq_restore(flags);
+-}
++ amd8111e_interrupt(0, dev);
++ local_irq_restore(flags);
++}
+ #endif
+
+
+@@ -1349,35 +1349,35 @@ static int amd8111e_close(struct net_dev
+ {
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ netif_stop_queue(dev);
+-
++
+ spin_lock_irq(&lp->lock);
+-
++
+ amd8111e_disable_interrupt(lp);
+ amd8111e_stop_chip(lp);
+ amd8111e_free_ring(lp);
+-
++
+ netif_carrier_off(lp->amd8111e_net_dev);
+
+ /* Delete ipg timer */
+- if(lp->options & OPTION_DYN_IPG_ENABLE)
++ if(lp->options & OPTION_DYN_IPG_ENABLE)
+ del_timer_sync(&lp->ipg_data.ipg_timer);
+
+ spin_unlock_irq(&lp->lock);
+ free_irq(dev->irq, dev);
+-
++
+ /* Update the statistics before closing */
+ amd8111e_get_stats(dev);
+ lp->opened = 0;
+ return 0;
+ }
+-/* This function opens new interface.It requests irq for the device, initializes the device,buffers and descriptors, and starts the device.
++/* This function opens new interface.It requests irq for the device, initializes the device,buffers and descriptors, and starts the device.
+ */
+ static int amd8111e_open(struct net_device * dev )
+ {
+ struct amd8111e_priv *lp = netdev_priv(dev);
+
+ if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, IRQF_SHARED,
+- dev->name, dev))
++ dev->name, dev))
+ return -EAGAIN;
+
+ spin_lock_irq(&lp->lock);
+@@ -1391,7 +1391,7 @@ static int amd8111e_open(struct net_devi
+ return -ENOMEM;
+ }
+ /* Start ipg timer */
+- if(lp->options & OPTION_DYN_IPG_ENABLE){
++ if(lp->options & OPTION_DYN_IPG_ENABLE){
+ add_timer(&lp->ipg_data.ipg_timer);
+ printk(KERN_INFO "%s: Dynamic IPG Enabled.\n",dev->name);
+ }
+@@ -1402,21 +1402,21 @@ static int amd8111e_open(struct net_devi
+
+ netif_start_queue(dev);
+
+- return 0;
++ return 0;
+ }
+-/*
++/*
+ This function checks if there is any transmit descriptors available to queue more packet.
+ */
+ static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp )
+-{
++{
+ int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK;
+ if(lp->tx_skbuff[tx_index] != 0)
+ return -1;
+ else
+ return 0;
+-
++
+ }
+-/*
++/*
+ This function will queue the transmit packets to the descriptors and will trigger the send operation. It also initializes the transmit descriptors with buffer physical address, byte count, ownership to hardware etc.
+ */
+
+@@ -1437,9 +1437,9 @@ static int amd8111e_start_xmit(struct sk
+
+ #if AMD8111E_VLAN_TAG_USED
+ if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
+- lp->tx_ring[tx_index].tag_ctrl_cmd |=
+- cpu_to_le16(TCC_VLAN_INSERT);
+- lp->tx_ring[tx_index].tag_ctrl_info =
++ lp->tx_ring[tx_index].tag_ctrl_cmd |=
++ cpu_to_le16(TCC_VLAN_INSERT);
++ lp->tx_ring[tx_index].tag_ctrl_info =
+ cpu_to_le16(vlan_tx_tag_get(skb));
+
+ }
+@@ -1510,14 +1510,14 @@ static int amd8111e_ether_crc(int len, c
+ }
+ else
+ crc >>= 1;
+-
++
+ octet >>= 1;
+ }
+- }
+- return crc;
++ }
++ return crc;
+ }
+ /*
+-This function sets promiscuos mode, all-multi mode or the multicast address
++This function sets promiscuos mode, all-multi mode or the multicast address
+ list to the device.
+ */
+ static void amd8111e_set_multicast_list(struct net_device *dev)
+@@ -1527,7 +1527,6 @@ static void amd8111e_set_multicast_list(
+ u32 mc_filter[2] ;
+ int i,bit_num;
+ if(dev->flags & IFF_PROMISC){
+- printk(KERN_INFO "%s: Setting promiscuous mode.\n",dev->name);
+ writel( VAL2 | PROM, lp->mmio + CMD2);
+ return;
+ }
+@@ -1559,7 +1558,7 @@ static void amd8111e_set_multicast_list(
+ i++, mc_ptr = mc_ptr->next) {
+ bit_num = ( amd8111e_ether_crc(ETH_ALEN,mc_ptr->dmi_addr) >> 26 ) & 0x3f;
+ mc_filter[bit_num >> 5] |= 1 << (bit_num & 31);
+- }
++ }
+ amd8111e_writeq(*(u64*)mc_filter,lp->mmio+ LADRF);
+
+ /* To eliminate PCI posting bug */
+@@ -1635,18 +1634,18 @@ static int amd8111e_set_wol(struct net_d
+ return -EINVAL;
+ spin_lock_irq(&lp->lock);
+ if (wol_info->wolopts & WAKE_MAGIC)
+- lp->options |=
++ lp->options |=
+ (OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
+ else if(wol_info->wolopts & WAKE_PHY)
+- lp->options |=
++ lp->options |=
+ (OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
+ else
+- lp->options &= ~OPTION_WOL_ENABLE;
++ lp->options &= ~OPTION_WOL_ENABLE;
+ spin_unlock_irq(&lp->lock);
+ return 0;
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = amd8111e_get_drvinfo,
+ .get_regs_len = amd8111e_get_regs_len,
+ .get_regs = amd8111e_get_regs,
+@@ -1659,9 +1658,9 @@ static struct ethtool_ops ops = {
+ };
+
+ /*
+-This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application.
++This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application.
+ */
+-
++
+ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
+ {
+ struct mii_ioctl_data *data = if_mii(ifr);
+@@ -1677,7 +1676,7 @@ static int amd8111e_ioctl(struct net_dev
+ data->phy_id = lp->ext_phy_addr;
+
+ /* fallthru */
+- case SIOCGMIIREG:
++ case SIOCGMIIREG:
+
+ spin_lock_irq(&lp->lock);
+ err = amd8111e_read_phy(lp, data->phy_id,
+@@ -1712,16 +1711,16 @@ static int amd8111e_set_mac_address(stru
+ spin_lock_irq(&lp->lock);
+ /* Setting the MAC address to the device */
+ for(i = 0; i < ETH_ADDR_LEN; i++)
+- writeb( dev->dev_addr[i], lp->mmio + PADR + i );
+-
++ writeb( dev->dev_addr[i], lp->mmio + PADR + i );
++
+ spin_unlock_irq(&lp->lock);
+
+ return 0;
+ }
+
+-/*
++/*
+ This function changes the mtu of the device. It restarts the device to initialize the descriptor with new receive buffers.
+-*/
++*/
+ static int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
+ {
+ struct amd8111e_priv *lp = netdev_priv(dev);
+@@ -1732,7 +1731,7 @@ static int amd8111e_change_mtu(struct ne
+
+ if (!netif_running(dev)) {
+ /* new_mtu will be used
+- when device starts netxt time */
++ when device starts netxt time */
+ dev->mtu = new_mtu;
+ return 0;
+ }
+@@ -1759,7 +1758,7 @@ static void amd8111e_vlan_rx_register(st
+ lp->vlgrp = grp;
+ spin_unlock_irq(&lp->lock);
+ }
+-
++
+ static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+ {
+ struct amd8111e_priv *lp = netdev_priv(dev);
+@@ -1784,11 +1783,11 @@ static int amd8111e_enable_link_change(s
+
+ /* Adapter is already stoped/suspended/interrupt-disabled */
+ writel(VAL0|LCMODE_SW,lp->mmio + CMD7);
+-
++
+ /* To eliminate PCI posting bug */
+ readl(lp->mmio + CMD7);
+ return 0;
+-}
++}
+ /* This function is called when a packet transmission fails to complete within a resonable period, on the assumption that an interrupts have been failed or the interface is locked up. This function will reinitialize the hardware */
+
+ static void amd8111e_tx_timeout(struct net_device *dev)
+@@ -1805,10 +1804,10 @@ static void amd8111e_tx_timeout(struct n
+ netif_wake_queue(dev);
+ }
+ static int amd8111e_suspend(struct pci_dev *pci_dev, pm_message_t state)
+-{
++{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ struct amd8111e_priv *lp = netdev_priv(dev);
+-
++
+ if (!netif_running(dev))
+ return 0;
+
+@@ -1818,10 +1817,10 @@ static int amd8111e_suspend(struct pci_d
+ spin_unlock_irq(&lp->lock);
+
+ netif_device_detach(dev);
+-
++
+ /* stop chip */
+ spin_lock_irq(&lp->lock);
+- if(lp->options & OPTION_DYN_IPG_ENABLE)
++ if(lp->options & OPTION_DYN_IPG_ENABLE)
+ del_timer_sync(&lp->ipg_data.ipg_timer);
+ amd8111e_stop_chip(lp);
+ spin_unlock_irq(&lp->lock);
+@@ -1829,19 +1828,19 @@ static int amd8111e_suspend(struct pci_d
+ if(lp->options & OPTION_WOL_ENABLE){
+ /* enable wol */
+ if(lp->options & OPTION_WAKE_MAGIC_ENABLE)
+- amd8111e_enable_magicpkt(lp);
++ amd8111e_enable_magicpkt(lp);
+ if(lp->options & OPTION_WAKE_PHY_ENABLE)
+- amd8111e_enable_link_change(lp);
+-
++ amd8111e_enable_link_change(lp);
++
+ pci_enable_wake(pci_dev, PCI_D3hot, 1);
+ pci_enable_wake(pci_dev, PCI_D3cold, 1);
+
+ }
+- else{
++ else{
+ pci_enable_wake(pci_dev, PCI_D3hot, 0);
+ pci_enable_wake(pci_dev, PCI_D3cold, 0);
+ }
+-
++
+ pci_save_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D3hot);
+
+@@ -1851,7 +1850,7 @@ static int amd8111e_resume(struct pci_de
+ {
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ struct amd8111e_priv *lp = netdev_priv(dev);
+-
++
+ if (!netif_running(dev))
+ return 0;
+
+@@ -1866,8 +1865,8 @@ static int amd8111e_resume(struct pci_de
+ spin_lock_irq(&lp->lock);
+ amd8111e_restart(dev);
+ /* Restart ipg timer */
+- if(lp->options & OPTION_DYN_IPG_ENABLE)
+- mod_timer(&lp->ipg_data.ipg_timer,
++ if(lp->options & OPTION_DYN_IPG_ENABLE)
++ mod_timer(&lp->ipg_data.ipg_timer,
+ jiffies + IPG_CONVERGE_JIFFIES);
+ spin_unlock_irq(&lp->lock);
+
+@@ -1895,16 +1894,16 @@ static void amd8111e_config_ipg(struct n
+ unsigned int prev_col_cnt = ipg_data->col_cnt;
+ unsigned int total_col_cnt;
+ unsigned int tmp_ipg;
+-
++
+ if(lp->link_config.duplex == DUPLEX_FULL){
+ ipg_data->ipg = DEFAULT_IPG;
+ return;
+ }
+
+ if(ipg_data->ipg_state == SSTATE){
+-
++
+ if(ipg_data->timer_tick == IPG_STABLE_TIME){
+-
++
+ ipg_data->timer_tick = 0;
+ ipg_data->ipg = MIN_IPG - IPG_STEP;
+ ipg_data->current_ipg = MIN_IPG;
+@@ -1916,15 +1915,15 @@ static void amd8111e_config_ipg(struct n
+ }
+
+ if(ipg_data->ipg_state == CSTATE){
+-
++
+ /* Get the current collision count */
+
+- total_col_cnt = ipg_data->col_cnt =
++ total_col_cnt = ipg_data->col_cnt =
+ amd8111e_read_mib(mmio, xmt_collisions);
+
+- if ((total_col_cnt - prev_col_cnt) <
++ if ((total_col_cnt - prev_col_cnt) <
+ (ipg_data->diff_col_cnt)){
+-
++
+ ipg_data->diff_col_cnt =
+ total_col_cnt - prev_col_cnt ;
+
+@@ -1939,8 +1938,8 @@ static void amd8111e_config_ipg(struct n
+ tmp_ipg = ipg_data->ipg;
+ ipg_data->ipg_state = SSTATE;
+ }
+- writew((u32)tmp_ipg, mmio + IPG);
+- writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1);
++ writew((u32)tmp_ipg, mmio + IPG);
++ writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1);
+ }
+ mod_timer(&lp->ipg_data.ipg_timer, jiffies + IPG_CONVERGE_JIFFIES);
+ return;
+@@ -2011,7 +2010,7 @@ static int __devinit amd8111e_probe_one(
+ "exiting.\n");
+ goto err_free_reg;
+ }
+-
++
+ reg_addr = pci_resource_start(pdev, 0);
+ reg_len = pci_resource_len(pdev, 0);
+
+@@ -2029,8 +2028,8 @@ static int __devinit amd8111e_probe_one(
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
+ dev->vlan_rx_register =amd8111e_vlan_rx_register;
+ dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
+-#endif
+-
++#endif
++
+ lp = netdev_priv(dev);
+ lp->pci_dev = pdev;
+ lp->amd8111e_net_dev = dev;
+@@ -2045,17 +2044,17 @@ static int __devinit amd8111e_probe_one(
+ err = -ENOMEM;
+ goto err_free_dev;
+ }
+-
++
+ /* Initializing MAC address */
+ for(i = 0; i < ETH_ADDR_LEN; i++)
+ dev->dev_addr[i] =readb(lp->mmio + PADR + i);
+-
++
+ /* Setting user defined parametrs */
+ lp->ext_phy_option = speed_duplex[card_idx];
+ if(coalesce[card_idx])
+- lp->options |= OPTION_INTR_COAL_ENABLE;
++ lp->options |= OPTION_INTR_COAL_ENABLE;
+ if(dynamic_ipg[card_idx++])
+- lp->options |= OPTION_DYN_IPG_ENABLE;
++ lp->options |= OPTION_DYN_IPG_ENABLE;
+
+ /* Initialize driver entry points */
+ dev->open = amd8111e_open;
+@@ -2068,21 +2067,21 @@ static int __devinit amd8111e_probe_one(
+ dev->change_mtu = amd8111e_change_mtu;
+ SET_ETHTOOL_OPS(dev, &ops);
+ dev->irq =pdev->irq;
+- dev->tx_timeout = amd8111e_tx_timeout;
+- dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
++ dev->tx_timeout = amd8111e_tx_timeout;
++ dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
+ #ifdef CONFIG_AMD8111E_NAPI
+ dev->poll = amd8111e_rx_poll;
+ dev->weight = 32;
+ #endif
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+- dev->poll_controller = amd8111e_poll;
++ dev->poll_controller = amd8111e_poll;
+ #endif
+
+ #if AMD8111E_VLAN_TAG_USED
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->vlan_rx_register =amd8111e_vlan_rx_register;
+ dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
+-#endif
++#endif
+ /* Probe the external PHY */
+ amd8111e_probe_ext_phy(dev);
+
+@@ -2104,13 +2103,13 @@ static int __devinit amd8111e_probe_one(
+ }
+
+ pci_set_drvdata(pdev, dev);
+-
++
+ /* Initialize software ipg timer */
+- if(lp->options & OPTION_DYN_IPG_ENABLE){
++ if(lp->options & OPTION_DYN_IPG_ENABLE){
+ init_timer(&lp->ipg_data.ipg_timer);
+ lp->ipg_data.ipg_timer.data = (unsigned long) dev;
+ lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg;
+- lp->ipg_data.ipg_timer.expires = jiffies +
++ lp->ipg_data.ipg_timer.expires = jiffies +
+ IPG_CONVERGE_JIFFIES;
+ lp->ipg_data.ipg = DEFAULT_IPG;
+ lp->ipg_data.ipg_state = CSTATE;
+@@ -2123,7 +2122,7 @@ static int __devinit amd8111e_probe_one(
+ printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version);
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
+- printk( "\n");
++ printk( "\n");
+ if (lp->ext_phy_id)
+ printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
+ dev->name, lp->ext_phy_id, lp->ext_phy_addr);
+@@ -2158,7 +2157,7 @@ static struct pci_driver amd8111e_driver
+
+ static int __init amd8111e_init(void)
+ {
+- return pci_module_init(&amd8111e_driver);
++ return pci_register_driver(&amd8111e_driver);
+ }
+
+ static void __exit amd8111e_cleanup(void)
+diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
+index cfe3a42..7727d32 100644
+--- a/drivers/net/amd8111e.h
++++ b/drivers/net/amd8111e.h
+@@ -1,6 +1,6 @@
+ /*
+- * Advanced Micro Devices Inc. AMD8111E Linux Network Driver
+- * Copyright (C) 2003 Advanced Micro Devices
++ * Advanced Micro Devices Inc. AMD8111E Linux Network Driver
++ * Copyright (C) 2003 Advanced Micro Devices
+ *
+ * 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
+@@ -14,7 +14,7 @@
+ *
+ * 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
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+
+ Module Name:
+@@ -22,11 +22,11 @@ Module Name:
+ amd8111e.h
+
+ Abstract:
+-
+- AMD8111 based 10/100 Ethernet Controller driver definitions.
++
++ AMD8111 based 10/100 Ethernet Controller driver definitions.
+
+ Environment:
+-
++
+ Kernel Mode
+
+ Revision History:
+@@ -40,7 +40,7 @@ Revision History:
+
+ /* Command style register access
+
+-Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register.
++Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register.
+
+ eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
+
+@@ -122,8 +122,8 @@ typedef enum {
+ ASF_INIT_DONE = (1 << 1),
+ ASF_INIT_PRESENT = (1 << 0),
+
+-}STAT_ASF_BITS;
+-
++}STAT_ASF_BITS;
++
+ typedef enum {
+
+ MIB_CMD_ACTIVE = (1 << 15 ),
+@@ -135,7 +135,7 @@ typedef enum {
+
+
+ typedef enum {
+-
++
+ PMAT_DET = (1 << 12),
+ MP_DET = (1 << 11),
+ LC_DET = (1 << 10),
+@@ -157,7 +157,7 @@ typedef enum {
+ typedef enum {
+
+ INTR = (1 << 31),
+- PCSINT = (1 << 28),
++ PCSINT = (1 << 28),
+ LCINT = (1 << 27),
+ APINT5 = (1 << 26),
+ APINT4 = (1 << 25),
+@@ -221,7 +221,7 @@ typedef enum {
+
+ INTEN0_CLEAR = 0x1F7F7F1F, /* Command style register */
+
+-}INTEN0_BITS;
++}INTEN0_BITS;
+
+ typedef enum {
+ /* VAL2 */
+@@ -240,7 +240,7 @@ typedef enum {
+ INTREN = (1 << 1),
+ RUN = (1 << 0),
+
+- CMD0_CLEAR = 0x000F0F7F, /* Command style register */
++ CMD0_CLEAR = 0x000F0F7F, /* Command style register */
+
+ }CMD0_BITS;
+
+@@ -279,20 +279,20 @@ typedef enum {
+ ASF_INIT_DONE_ALIAS = (1 << 29),
+ /* VAL2 */
+ JUMBO = (1 << 21),
+- VSIZE = (1 << 20),
++ VSIZE = (1 << 20),
+ VLONLY = (1 << 19),
+- VL_TAG_DEL = (1 << 18),
++ VL_TAG_DEL = (1 << 18),
+ /* VAL1 */
+- EN_PMGR = (1 << 14),
++ EN_PMGR = (1 << 14),
+ INTLEVEL = (1 << 13),
+- FORCE_FULL_DUPLEX = (1 << 12),
+- FORCE_LINK_STATUS = (1 << 11),
+- APEP = (1 << 10),
+- MPPLBA = (1 << 9),
++ FORCE_FULL_DUPLEX = (1 << 12),
++ FORCE_LINK_STATUS = (1 << 11),
++ APEP = (1 << 10),
++ MPPLBA = (1 << 9),
+ /* VAL0 */
+- RESET_PHY_PULSE = (1 << 2),
+- RESET_PHY = (1 << 1),
+- PHY_RST_POL = (1 << 0),
++ RESET_PHY_PULSE = (1 << 2),
++ RESET_PHY = (1 << 1),
++ PHY_RST_POL = (1 << 0),
+
+ }CMD3_BITS;
+
+@@ -314,7 +314,7 @@ typedef enum {
+
+ RESET_PHY_WIDTH = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
+ XMTSP_MASK = (1 << 9) | (1 << 8), /* 9:8 */
+- XMTSP_128 = (1 << 9), /* 9 */
++ XMTSP_128 = (1 << 9), /* 9 */
+ XMTSP_64 = (1 << 8),
+ CACHE_ALIGN = (1 << 4),
+ BURST_LIMIT_MASK = (0xF << 0 ),
+@@ -445,7 +445,7 @@ typedef enum {
+ DLY_INT_B_T1 = (1 << 25),
+ DLY_INT_B_T0 = ( 1 << 24),
+ EVENT_COUNT_B = (0xF << 16) | (0x1 << 20),/* 20:16 */
+- MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)|
++ MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)|
+ (1 << 9) | (1 << 10), /* 10:0 */
+ }DLY_INT_B_BITS;
+
+@@ -569,20 +569,20 @@ typedef enum {
+ #define MAX_UNITS 8 /* Maximum number of devices possible */
+
+ #define NUM_TX_BUFFERS 32 /* Number of transmit buffers */
+-#define NUM_RX_BUFFERS 32 /* Number of receive buffers */
++#define NUM_RX_BUFFERS 32 /* Number of receive buffers */
+
+ #define TX_BUFF_MOD_MASK 31 /* (NUM_TX_BUFFERS -1) */
+ #define RX_BUFF_MOD_MASK 31 /* (NUM_RX_BUFFERS -1) */
+
+-#define NUM_TX_RING_DR 32
+-#define NUM_RX_RING_DR 32
++#define NUM_TX_RING_DR 32
++#define NUM_RX_RING_DR 32
+
+ #define TX_RING_DR_MOD_MASK 31 /* (NUM_TX_RING_DR -1) */
+ #define RX_RING_DR_MOD_MASK 31 /* (NUM_RX_RING_DR -1) */
+
+-#define MAX_FILTER_SIZE 64 /* Maximum multicast address */
+-#define AMD8111E_MIN_MTU 60
+-#define AMD8111E_MAX_MTU 9000
++#define MAX_FILTER_SIZE 64 /* Maximum multicast address */
++#define AMD8111E_MIN_MTU 60
++#define AMD8111E_MAX_MTU 9000
+
+ #define PKT_BUFF_SZ 1536
+ #define MIN_PKT_LEN 60
+@@ -591,7 +591,7 @@ typedef enum {
+ #define AMD8111E_TX_TIMEOUT (3 * HZ)/* 3 sec */
+ #define SOFT_TIMER_FREQ 0xBEBC /* 0.5 sec */
+ #define DELAY_TIMER_CONV 50 /* msec to 10 usec conversion.
+- Only 500 usec resolution */
++ Only 500 usec resolution */
+ #define OPTION_VLAN_ENABLE 0x0001
+ #define OPTION_JUMBO_ENABLE 0x0002
+ #define OPTION_MULTICAST_ENABLE 0x0004
+@@ -611,12 +611,12 @@ typedef enum {
+ #define MIN_IPG 96
+ #define MAX_IPG 255
+ #define IPG_STEP 16
+-#define CSTATE 1
+-#define SSTATE 2
++#define CSTATE 1
++#define SSTATE 2
+
+ /* Assume contoller gets data 10 times the maximum processing time */
+-#define REPEAT_CNT 10;
+-
++#define REPEAT_CNT 10;
++
+ /* amd8111e decriptor flag definitions */
+ typedef enum {
+
+@@ -649,7 +649,7 @@ typedef enum {
+ #define TCC_MASK 0x0003
+
+ /* driver ioctl parameters */
+-#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32)
++#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32)
+
+ /* crc generator constants */
+ #define CRC32 0xedb88320
+@@ -670,15 +670,15 @@ struct amd8111e_tx_dr{
+ u32 buff_phy_addr;
+
+ u32 reserved;
+-};
++};
+
+ struct amd8111e_rx_dr{
+-
++
+ u32 reserved;
+
+ u16 msg_count; /* Received message len */
+
+- u16 tag_ctrl_info;
++ u16 tag_ctrl_info;
+
+ u16 buff_count; /* Len of the buffer pointed by descriptor. */
+
+@@ -692,7 +692,7 @@ struct amd8111e_link_config{
+ #define SPEED_INVALID 0xffff
+ #define DUPLEX_INVALID 0xff
+ #define AUTONEG_INVALID 0xff
+-
++
+ unsigned long orig_phy_option;
+ u16 speed;
+ u8 duplex;
+@@ -709,7 +709,7 @@ enum coal_type{
+
+ };
+
+-enum coal_mode{
++enum coal_mode{
+ RX_INTR_COAL,
+ TX_INTR_COAL,
+ DISABLE_COAL,
+@@ -727,7 +727,7 @@ struct amd8111e_coalesce_conf{
+ unsigned long rx_bytes;
+ unsigned long rx_prev_bytes;
+ unsigned int rx_coal_type;
+-
++
+ unsigned int tx_timeout;
+ unsigned int tx_event_count;
+ unsigned long tx_packets;
+@@ -738,7 +738,7 @@ struct amd8111e_coalesce_conf{
+
+ };
+ struct ipg_info{
+-
++
+ unsigned int ipg_state;
+ unsigned int ipg;
+ unsigned int current_ipg;
+@@ -750,7 +750,7 @@ struct ipg_info{
+ };
+
+ struct amd8111e_priv{
+-
++
+ struct amd8111e_tx_dr* tx_ring;
+ struct amd8111e_rx_dr* rx_ring;
+ dma_addr_t tx_ring_dma_addr; /* tx descriptor ring base address */
+@@ -766,7 +766,7 @@ struct amd8111e_priv{
+ dma_addr_t rx_dma_addr[NUM_RX_BUFFERS];
+ /* Reg memory mapped address */
+ void __iomem *mmio;
+-
++
+ spinlock_t lock; /* Guard lock */
+ unsigned long rx_idx, tx_idx; /* The next free ring entry */
+ unsigned long tx_complete_idx;
+@@ -778,7 +778,7 @@ struct amd8111e_priv{
+ unsigned long ext_phy_option;
+ int ext_phy_addr;
+ u32 ext_phy_id;
+-
++
+ struct amd8111e_link_config link_config;
+ int pm_cap;
+
+@@ -787,22 +787,22 @@ struct amd8111e_priv{
+ struct mii_if_info mii_if;
+ #if AMD8111E_VLAN_TAG_USED
+ struct vlan_group *vlgrp;
+-#endif
++#endif
+ char opened;
+ struct net_device_stats stats;
+ unsigned int drv_rx_errors;
+ struct dev_mc_list* mc_list;
+ struct amd8111e_coalesce_conf coal_conf;
+
+- struct ipg_info ipg_data;
+-
++ struct ipg_info ipg_data;
++
+ };
+
+ /* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
+ BUG? */
+ #define amd8111e_writeq(_UlData,_memMap) \
+ writel(*(u32*)(&_UlData), _memMap); \
+- writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)
++ writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)
+
+ /* maps the external speed options to internal value */
+ typedef enum {
+diff --git a/drivers/net/apne.c b/drivers/net/apne.c
+index 9cc13a0..9164d8c 100644
+--- a/drivers/net/apne.c
++++ b/drivers/net/apne.c
+@@ -88,7 +88,7 @@ static void apne_block_input(struct net_
+ struct sk_buff *skb, int ring_offset);
+ static void apne_block_output(struct net_device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+-static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t apne_interrupt(int irq, void *dev_id);
+
+ static int init_pcmcia(void);
+
+@@ -132,9 +132,9 @@ struct net_device * __init apne_probe(in
+
+ if ( !(AMIGAHW_PRESENT(PCMCIA)) )
+ return ERR_PTR(-ENODEV);
+-
++
+ printk("Looking for PCMCIA ethernet card : ");
+-
++
+ /* check if a card is inserted */
+ if (!(PCMCIA_INSERTED)) {
+ printk("NO PCMCIA card inserted\n");
+@@ -205,7 +205,7 @@ static int __init apne_probe1(struct net
+ int neX000, ctron;
+ #endif
+ static unsigned version_printed;
+-
++
+ if (ei_debug && version_printed++ == 0)
+ printk(version);
+
+@@ -261,13 +261,13 @@ static int __init apne_probe1(struct net
+
+ /* At this point, wordlength *only* tells us if the SA_prom is doubled
+ up or not because some broken PCI cards don't respect the byte-wide
+- request in program_seq above, and hence don't have doubled up values.
++ request in program_seq above, and hence don't have doubled up values.
+ These broken cards would otherwise be detected as an ne1000. */
+
+ if (wordlength == 2)
+ for (i = 0; i < 16; i++)
+ SA_prom[i] = SA_prom[i+i];
+-
++
+ if (wordlength == 2) {
+ /* We must set the 8390 for word mode. */
+ outb(0x49, ioaddr + NE_EN0_DCFG);
+@@ -543,7 +543,7 @@ apne_block_output(struct net_device *dev
+ return;
+ }
+
+-static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t apne_interrupt(int irq, void *dev_id)
+ {
+ unsigned char pcmcia_intreq;
+
+@@ -559,7 +559,7 @@ static irqreturn_t apne_interrupt(int ir
+ if (ei_debug > 3)
+ printk("pcmcia intreq = %x\n", pcmcia_intreq);
+ pcmcia_disable_irq(); /* to get rid of the sti() within ei_interrupt */
+- ei_interrupt(irq, dev_id, regs);
++ ei_interrupt(irq, dev_id);
+ pcmcia_ack_int(pcmcia_get_intreq());
+ pcmcia_enable_irq();
+ return IRQ_HANDLED;
+diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
+index ae7f828..cc1a27e 100644
+--- a/drivers/net/appletalk/cops.c
++++ b/drivers/net/appletalk/cops.c
+@@ -188,7 +188,7 @@ static void cops_reset (struct net_devic
+ static void cops_load (struct net_device *dev);
+ static int cops_nodeid (struct net_device *dev, int nodeid);
+
+-static irqreturn_t cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t cops_interrupt (int irq, void *dev_id);
+ static void cops_poll (unsigned long ltdev);
+ static void cops_timeout(struct net_device *dev);
+ static void cops_rx (struct net_device *dev);
+@@ -721,7 +721,7 @@ static void cops_poll(unsigned long ltde
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+-static irqreturn_t cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t cops_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct cops_local *lp;
+diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
+index 7f7dd45..b98592a 100644
+--- a/drivers/net/appletalk/ipddp.c
++++ b/drivers/net/appletalk/ipddp.c
+@@ -145,9 +145,7 @@ static int ipddp_xmit(struct sk_buff *sk
+
+ /* Create the Extended DDP header */
+ ddp = (struct ddpehdr *)skb->data;
+- ddp->deh_len = skb->len;
+- ddp->deh_hops = 1;
+- ddp->deh_pad = 0;
++ ddp->deh_len_hops = htons(skb->len + (1<<10));
+ ddp->deh_sum = 0;
+
+ /*
+@@ -170,7 +168,6 @@ static int ipddp_xmit(struct sk_buff *sk
+ ddp->deh_sport = 72;
+
+ *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
+- *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
+
+ skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
+
+diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
+index d5666c3..2ea44ce 100644
+--- a/drivers/net/appletalk/ltpc.c
++++ b/drivers/net/appletalk/ltpc.c
+@@ -790,7 +790,7 @@ static int sendup_buffer (struct net_dev
+ /* the handler for the board interrupt */
+
+ static irqreturn_t
+-ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
++ltpc_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+
+diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
+index 5a95005..4e91dab 100644
+--- a/drivers/net/arcnet/arcnet.c
++++ b/drivers/net/arcnet/arcnet.c
+@@ -752,7 +752,7 @@ static void arcnet_timeout(struct net_de
+ * interrupts. Establish which device needs attention, and call the correct
+ * chipset interrupt handler.
+ */
+-irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t arcnet_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct arcnet_local *lp;
+diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
+index 979a33d..98d326b 100644
+--- a/drivers/net/arcnet/com20020-pci.c
++++ b/drivers/net/arcnet/com20020-pci.c
+@@ -161,6 +161,7 @@ static struct pci_device_id com20020pci_
+ { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
++ { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ {0,}
+ };
+@@ -177,7 +178,7 @@ static struct pci_driver com20020pci_dri
+ static int __init com20020pci_init(void)
+ {
+ BUGLVL(D_NORMAL) printk(VERSION);
+- return pci_module_init(&com20020pci_driver);
++ return pci_register_driver(&com20020pci_driver);
+ }
+
+ static void __exit com20020pci_cleanup(void)
+diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
+index cc721ad..9dfc09b 100644
+--- a/drivers/net/ariadne.c
++++ b/drivers/net/ariadne.c
+@@ -120,7 +120,7 @@ static int ariadne_start_xmit(struct sk_
+ static void ariadne_tx_timeout(struct net_device *dev);
+ static int ariadne_rx(struct net_device *dev);
+ static void ariadne_reset(struct net_device *dev);
+-static irqreturn_t ariadne_interrupt(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t ariadne_interrupt(int irq, void *data);
+ static int ariadne_close(struct net_device *dev);
+ static struct net_device_stats *ariadne_get_stats(struct net_device *dev);
+ #ifdef HAVE_MULTICAST
+@@ -416,7 +416,7 @@ static inline void ariadne_reset(struct
+ }
+
+
+-static irqreturn_t ariadne_interrupt(int irq, void *data, struct pt_regs *fp)
++static irqreturn_t ariadne_interrupt(int irq, void *data)
+ {
+ struct net_device *dev = (struct net_device *)data;
+ volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
+@@ -825,8 +825,6 @@ static void set_multicast_list(struct ne
+ ariadne_init_ring(dev);
+
+ if (dev->flags & IFF_PROMISC) {
+- /* Log any net taps. */
+- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ lance->RAP = CSR15; /* Mode Register */
+ lance->RDP = PROM; /* Set promiscuous mode */
+ } else {
+diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
+index 77fe20d..678e4f4 100644
+--- a/drivers/net/arm/Kconfig
++++ b/drivers/net/arm/Kconfig
+@@ -39,3 +39,10 @@ config ARM_AT91_ETHER
+ help
+ If you wish to compile a kernel for the AT91RM9200 and enable
+ ethernet support, then you should always answer Y to this.
++
++config EP93XX_ETH
++ tristate "EP93xx Ethernet support"
++ depends on NET_ETHERNET && ARM && ARCH_EP93XX
++ help
++ This is a driver for the ethernet hardware included in EP93xx CPUs.
++ Say Y if you are building a kernel for EP93xx based devices.
+diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
+index 42c95b7..a4c8682 100644
+--- a/drivers/net/arm/Makefile
++++ b/drivers/net/arm/Makefile
+@@ -8,3 +8,4 @@ obj-$(CONFIG_ARM_ETHERH) += etherh.o
+ obj-$(CONFIG_ARM_ETHER3) += ether3.o
+ obj-$(CONFIG_ARM_ETHER1) += ether1.o
+ obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
++obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
+diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
+index 09d5c3f..ddd12d4 100644
+--- a/drivers/net/arm/am79c961a.c
++++ b/drivers/net/arm/am79c961a.c
+@@ -38,7 +38,7 @@
+ #include "am79c961a.h"
+
+ static irqreturn_t
+-am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
++am79c961_interrupt (int irq, void *dev_id);
+
+ static unsigned int net_debug = NET_DEBUG;
+
+@@ -596,7 +596,7 @@ am79c961_tx(struct net_device *dev, stru
+ }
+
+ static irqreturn_t
+-am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++am79c961_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct dev_priv *priv = netdev_priv(dev);
+diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h
+index 6a49ac7..483009f 100644
+--- a/drivers/net/arm/am79c961a.h
++++ b/drivers/net/arm/am79c961a.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/net/am79c961.h
++ * linux/drivers/net/arm/am79c961a.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
+diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
+index 85493b7..b54b857 100644
+--- a/drivers/net/arm/at91_ether.c
++++ b/drivers/net/arm/at91_ether.c
+@@ -196,7 +196,7 @@ static void update_linkspeed(struct net_
+ /*
+ * Handle interrupts from the PHY
+ */
+-static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct at91_private *lp = (struct at91_private *) dev->priv;
+@@ -648,7 +648,7 @@ static void at91ether_get_drvinfo(struct
+ strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ }
+
+-static struct ethtool_ops at91ether_ethtool_ops = {
++static const struct ethtool_ops at91ether_ethtool_ops = {
+ .get_settings = at91ether_get_settings,
+ .set_settings = at91ether_set_settings,
+ .get_drvinfo = at91ether_get_drvinfo,
+@@ -888,7 +888,7 @@ static void at91ether_rx(struct net_devi
+ /*
+ * MAC interrupt handler
+ */
+-static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct at91_private *lp = (struct at91_private *) dev->priv;
+@@ -947,7 +947,7 @@ static int __init at91ether_setup(unsign
+ return -ENOMEM;
+
+ dev->base_addr = AT91_VA_BASE_EMAC;
+- dev->irq = AT91_ID_EMAC;
++ dev->irq = AT91RM9200_ID_EMAC;
+ SET_MODULE_OWNER(dev);
+
+ /* Install the interrupt handler */
+diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
+new file mode 100644
+index 0000000..8ebd68e
+--- /dev/null
++++ b/drivers/net/arm/ep93xx_eth.c
+@@ -0,0 +1,923 @@
++/*
++ * EP93xx ethernet network device driver
++ * Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.org>
++ * Dedicated to Marija Kulikova.
++ *
++ * 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/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/mii.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <asm/arch/ep93xx-regs.h>
++#include <asm/arch/platform.h>
++#include <asm/io.h>
++
++#define DRV_MODULE_NAME "ep93xx-eth"
++#define DRV_MODULE_VERSION "0.1"
++
++#define RX_QUEUE_ENTRIES 64
++#define TX_QUEUE_ENTRIES 8
++
++#define MAX_PKT_SIZE 2044
++#define PKT_BUF_SIZE 2048
++
++#define REG_RXCTL 0x0000
++#define REG_RXCTL_DEFAULT 0x00073800
++#define REG_TXCTL 0x0004
++#define REG_TXCTL_ENABLE 0x00000001
++#define REG_MIICMD 0x0010
++#define REG_MIICMD_READ 0x00008000
++#define REG_MIICMD_WRITE 0x00004000
++#define REG_MIIDATA 0x0014
++#define REG_MIISTS 0x0018
++#define REG_MIISTS_BUSY 0x00000001
++#define REG_SELFCTL 0x0020
++#define REG_SELFCTL_RESET 0x00000001
++#define REG_INTEN 0x0024
++#define REG_INTEN_TX 0x00000008
++#define REG_INTEN_RX 0x00000007
++#define REG_INTSTSP 0x0028
++#define REG_INTSTS_TX 0x00000008
++#define REG_INTSTS_RX 0x00000004
++#define REG_INTSTSC 0x002c
++#define REG_AFP 0x004c
++#define REG_INDAD0 0x0050
++#define REG_INDAD1 0x0051
++#define REG_INDAD2 0x0052
++#define REG_INDAD3 0x0053
++#define REG_INDAD4 0x0054
++#define REG_INDAD5 0x0055
++#define REG_GIINTMSK 0x0064
++#define REG_GIINTMSK_ENABLE 0x00008000
++#define REG_BMCTL 0x0080
++#define REG_BMCTL_ENABLE_TX 0x00000100
++#define REG_BMCTL_ENABLE_RX 0x00000001
++#define REG_BMSTS 0x0084
++#define REG_BMSTS_RX_ACTIVE 0x00000008
++#define REG_RXDQBADD 0x0090
++#define REG_RXDQBLEN 0x0094
++#define REG_RXDCURADD 0x0098
++#define REG_RXDENQ 0x009c
++#define REG_RXSTSQBADD 0x00a0
++#define REG_RXSTSQBLEN 0x00a4
++#define REG_RXSTSQCURADD 0x00a8
++#define REG_RXSTSENQ 0x00ac
++#define REG_TXDQBADD 0x00b0
++#define REG_TXDQBLEN 0x00b4
++#define REG_TXDQCURADD 0x00b8
++#define REG_TXDENQ 0x00bc
++#define REG_TXSTSQBADD 0x00c0
++#define REG_TXSTSQBLEN 0x00c4
++#define REG_TXSTSQCURADD 0x00c8
++#define REG_MAXFRMLEN 0x00e8
++
++struct ep93xx_rdesc
++{
++ u32 buf_addr;
++ u32 rdesc1;
++};
++
++#define RDESC1_NSOF 0x80000000
++#define RDESC1_BUFFER_INDEX 0x7fff0000
++#define RDESC1_BUFFER_LENGTH 0x0000ffff
++
++struct ep93xx_rstat
++{
++ u32 rstat0;
++ u32 rstat1;
++};
++
++#define RSTAT0_RFP 0x80000000
++#define RSTAT0_RWE 0x40000000
++#define RSTAT0_EOF 0x20000000
++#define RSTAT0_EOB 0x10000000
++#define RSTAT0_AM 0x00c00000
++#define RSTAT0_RX_ERR 0x00200000
++#define RSTAT0_OE 0x00100000
++#define RSTAT0_FE 0x00080000
++#define RSTAT0_RUNT 0x00040000
++#define RSTAT0_EDATA 0x00020000
++#define RSTAT0_CRCE 0x00010000
++#define RSTAT0_CRCI 0x00008000
++#define RSTAT0_HTI 0x00003f00
++#define RSTAT1_RFP 0x80000000
++#define RSTAT1_BUFFER_INDEX 0x7fff0000
++#define RSTAT1_FRAME_LENGTH 0x0000ffff
++
++struct ep93xx_tdesc
++{
++ u32 buf_addr;
++ u32 tdesc1;
++};
++
++#define TDESC1_EOF 0x80000000
++#define TDESC1_BUFFER_INDEX 0x7fff0000
++#define TDESC1_BUFFER_ABORT 0x00008000
++#define TDESC1_BUFFER_LENGTH 0x00000fff
++
++struct ep93xx_tstat
++{
++ u32 tstat0;
++};
++
++#define TSTAT0_TXFP 0x80000000
++#define TSTAT0_TXWE 0x40000000
++#define TSTAT0_FA 0x20000000
++#define TSTAT0_LCRS 0x10000000
++#define TSTAT0_OW 0x04000000
++#define TSTAT0_TXU 0x02000000
++#define TSTAT0_ECOLL 0x01000000
++#define TSTAT0_NCOLL 0x001f0000
++#define TSTAT0_BUFFER_INDEX 0x00007fff
++
++struct ep93xx_descs
++{
++ struct ep93xx_rdesc rdesc[RX_QUEUE_ENTRIES];
++ struct ep93xx_tdesc tdesc[TX_QUEUE_ENTRIES];
++ struct ep93xx_rstat rstat[RX_QUEUE_ENTRIES];
++ struct ep93xx_tstat tstat[TX_QUEUE_ENTRIES];
++};
++
++struct ep93xx_priv
++{
++ struct resource *res;
++ void *base_addr;
++ int irq;
++
++ struct ep93xx_descs *descs;
++ dma_addr_t descs_dma_addr;
++
++ void *rx_buf[RX_QUEUE_ENTRIES];
++ void *tx_buf[TX_QUEUE_ENTRIES];
++
++ spinlock_t rx_lock;
++ unsigned int rx_pointer;
++ unsigned int tx_clean_pointer;
++ unsigned int tx_pointer;
++ spinlock_t tx_pending_lock;
++ unsigned int tx_pending;
++
++ struct net_device_stats stats;
++
++ struct mii_if_info mii;
++ u8 mdc_divisor;
++};
++
++#define rdb(ep, off) __raw_readb((ep)->base_addr + (off))
++#define rdw(ep, off) __raw_readw((ep)->base_addr + (off))
++#define rdl(ep, off) __raw_readl((ep)->base_addr + (off))
++#define wrb(ep, off, val) __raw_writeb((val), (ep)->base_addr + (off))
++#define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off))
++#define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off))
++
++static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg);
++
++static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ return &(ep->stats);
++}
++
++static int ep93xx_rx(struct net_device *dev, int *budget)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int rx_done;
++ int processed;
++
++ rx_done = 0;
++ processed = 0;
++ while (*budget > 0) {
++ int entry;
++ struct ep93xx_rstat *rstat;
++ u32 rstat0;
++ u32 rstat1;
++ int length;
++ struct sk_buff *skb;
++
++ entry = ep->rx_pointer;
++ rstat = ep->descs->rstat + entry;
++
++ rstat0 = rstat->rstat0;
++ rstat1 = rstat->rstat1;
++ if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) {
++ rx_done = 1;
++ break;
++ }
++
++ rstat->rstat0 = 0;
++ rstat->rstat1 = 0;
++
++ if (!(rstat0 & RSTAT0_EOF))
++ printk(KERN_CRIT "ep93xx_rx: not end-of-frame "
++ " %.8x %.8x\n", rstat0, rstat1);
++ if (!(rstat0 & RSTAT0_EOB))
++ printk(KERN_CRIT "ep93xx_rx: not end-of-buffer "
++ " %.8x %.8x\n", rstat0, rstat1);
++ if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry)
++ printk(KERN_CRIT "ep93xx_rx: entry mismatch "
++ " %.8x %.8x\n", rstat0, rstat1);
++
++ if (!(rstat0 & RSTAT0_RWE)) {
++ ep->stats.rx_errors++;
++ if (rstat0 & RSTAT0_OE)
++ ep->stats.rx_fifo_errors++;
++ if (rstat0 & RSTAT0_FE)
++ ep->stats.rx_frame_errors++;
++ if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA))
++ ep->stats.rx_length_errors++;
++ if (rstat0 & RSTAT0_CRCE)
++ ep->stats.rx_crc_errors++;
++ goto err;
++ }
++
++ length = rstat1 & RSTAT1_FRAME_LENGTH;
++ if (length > MAX_PKT_SIZE) {
++ printk(KERN_NOTICE "ep93xx_rx: invalid length "
++ " %.8x %.8x\n", rstat0, rstat1);
++ goto err;
++ }
++
++ /* Strip FCS. */
++ if (rstat0 & RSTAT0_CRCI)
++ length -= 4;
++
++ skb = dev_alloc_skb(length + 2);
++ if (likely(skb != NULL)) {
++ skb->dev = dev;
++ skb_reserve(skb, 2);
++ dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr,
++ length, DMA_FROM_DEVICE);
++ eth_copy_and_sum(skb, ep->rx_buf[entry], length, 0);
++ skb_put(skb, length);
++ skb->protocol = eth_type_trans(skb, dev);
++
++ dev->last_rx = jiffies;
++
++ netif_receive_skb(skb);
++
++ ep->stats.rx_packets++;
++ ep->stats.rx_bytes += length;
++ } else {
++ ep->stats.rx_dropped++;
++ }
++
++err:
++ ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1);
++ processed++;
++ dev->quota--;
++ (*budget)--;
++ }
++
++ if (processed) {
++ wrw(ep, REG_RXDENQ, processed);
++ wrw(ep, REG_RXSTSENQ, processed);
++ }
++
++ return !rx_done;
++}
++
++static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
++{
++ struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer;
++ return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
++}
++
++static int ep93xx_poll(struct net_device *dev, int *budget)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++
++ /*
++ * @@@ Have to stop polling if device is downed while we
++ * are polling.
++ */
++
++poll_some_more:
++ if (ep93xx_rx(dev, budget))
++ return 1;
++
++ netif_rx_complete(dev);
++
++ spin_lock_irq(&ep->rx_lock);
++ wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
++ if (ep93xx_have_more_rx(ep)) {
++ wrl(ep, REG_INTEN, REG_INTEN_TX);
++ wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
++ spin_unlock_irq(&ep->rx_lock);
++
++ if (netif_rx_reschedule(dev, 0))
++ goto poll_some_more;
++
++ return 0;
++ }
++ spin_unlock_irq(&ep->rx_lock);
++
++ return 0;
++}
++
++static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int entry;
++
++ if (unlikely(skb->len > MAX_PKT_SIZE)) {
++ ep->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return NETDEV_TX_OK;
++ }
++
++ entry = ep->tx_pointer;
++ ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1);
++
++ ep->descs->tdesc[entry].tdesc1 =
++ TDESC1_EOF | (entry << 16) | (skb->len & 0xfff);
++ skb_copy_and_csum_dev(skb, ep->tx_buf[entry]);
++ dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr,
++ skb->len, DMA_TO_DEVICE);
++ dev_kfree_skb(skb);
++
++ dev->trans_start = jiffies;
++
++ spin_lock_irq(&ep->tx_pending_lock);
++ ep->tx_pending++;
++ if (ep->tx_pending == TX_QUEUE_ENTRIES)
++ netif_stop_queue(dev);
++ spin_unlock_irq(&ep->tx_pending_lock);
++
++ wrl(ep, REG_TXDENQ, 1);
++
++ return NETDEV_TX_OK;
++}
++
++static void ep93xx_tx_complete(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int wake;
++
++ wake = 0;
++
++ spin_lock(&ep->tx_pending_lock);
++ while (1) {
++ int entry;
++ struct ep93xx_tstat *tstat;
++ u32 tstat0;
++
++ entry = ep->tx_clean_pointer;
++ tstat = ep->descs->tstat + entry;
++
++ tstat0 = tstat->tstat0;
++ if (!(tstat0 & TSTAT0_TXFP))
++ break;
++
++ tstat->tstat0 = 0;
++
++ if (tstat0 & TSTAT0_FA)
++ printk(KERN_CRIT "ep93xx_tx_complete: frame aborted "
++ " %.8x\n", tstat0);
++ if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry)
++ printk(KERN_CRIT "ep93xx_tx_complete: entry mismatch "
++ " %.8x\n", tstat0);
++
++ if (tstat0 & TSTAT0_TXWE) {
++ int length = ep->descs->tdesc[entry].tdesc1 & 0xfff;
++
++ ep->stats.tx_packets++;
++ ep->stats.tx_bytes += length;
++ } else {
++ ep->stats.tx_errors++;
++ }
++
++ if (tstat0 & TSTAT0_OW)
++ ep->stats.tx_window_errors++;
++ if (tstat0 & TSTAT0_TXU)
++ ep->stats.tx_fifo_errors++;
++ ep->stats.collisions += (tstat0 >> 16) & 0x1f;
++
++ ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1);
++ if (ep->tx_pending == TX_QUEUE_ENTRIES)
++ wake = 1;
++ ep->tx_pending--;
++ }
++ spin_unlock(&ep->tx_pending_lock);
++
++ if (wake)
++ netif_wake_queue(dev);
++}
++
++static irqreturn_t ep93xx_irq(int irq, void *dev_id)
++{
++ struct net_device *dev = dev_id;
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ u32 status;
++
++ status = rdl(ep, REG_INTSTSC);
++ if (status == 0)
++ return IRQ_NONE;
++
++ if (status & REG_INTSTS_RX) {
++ spin_lock(&ep->rx_lock);
++ if (likely(__netif_rx_schedule_prep(dev))) {
++ wrl(ep, REG_INTEN, REG_INTEN_TX);
++ __netif_rx_schedule(dev);
++ }
++ spin_unlock(&ep->rx_lock);
++ }
++
++ if (status & REG_INTSTS_TX)
++ ep93xx_tx_complete(dev);
++
++ return IRQ_HANDLED;
++}
++
++static void ep93xx_free_buffers(struct ep93xx_priv *ep)
++{
++ int i;
++
++ for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
++ dma_addr_t d;
++
++ d = ep->descs->rdesc[i].buf_addr;
++ if (d)
++ dma_unmap_single(NULL, d, PAGE_SIZE, DMA_FROM_DEVICE);
++
++ if (ep->rx_buf[i] != NULL)
++ free_page((unsigned long)ep->rx_buf[i]);
++ }
++
++ for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) {
++ dma_addr_t d;
++
++ d = ep->descs->tdesc[i].buf_addr;
++ if (d)
++ dma_unmap_single(NULL, d, PAGE_SIZE, DMA_TO_DEVICE);
++
++ if (ep->tx_buf[i] != NULL)
++ free_page((unsigned long)ep->tx_buf[i]);
++ }
++
++ dma_free_coherent(NULL, sizeof(struct ep93xx_descs), ep->descs,
++ ep->descs_dma_addr);
++}
++
++/*
++ * The hardware enforces a sub-2K maximum packet size, so we put
++ * two buffers on every hardware page.
++ */
++static int ep93xx_alloc_buffers(struct ep93xx_priv *ep)
++{
++ int i;
++
++ ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs),
++ &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA);
++ if (ep->descs == NULL)
++ return 1;
++
++ for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
++ void *page;
++ dma_addr_t d;
++
++ page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
++ if (page == NULL)
++ goto err;
++
++ d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE);
++ if (dma_mapping_error(d)) {
++ free_page((unsigned long)page);
++ goto err;
++ }
++
++ ep->rx_buf[i] = page;
++ ep->descs->rdesc[i].buf_addr = d;
++ ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE;
++
++ ep->rx_buf[i + 1] = page + PKT_BUF_SIZE;
++ ep->descs->rdesc[i + 1].buf_addr = d + PKT_BUF_SIZE;
++ ep->descs->rdesc[i + 1].rdesc1 = ((i + 1) << 16) | PKT_BUF_SIZE;
++ }
++
++ for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) {
++ void *page;
++ dma_addr_t d;
++
++ page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
++ if (page == NULL)
++ goto err;
++
++ d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE);
++ if (dma_mapping_error(d)) {
++ free_page((unsigned long)page);
++ goto err;
++ }
++
++ ep->tx_buf[i] = page;
++ ep->descs->tdesc[i].buf_addr = d;
++
++ ep->tx_buf[i + 1] = page + PKT_BUF_SIZE;
++ ep->descs->tdesc[i + 1].buf_addr = d + PKT_BUF_SIZE;
++ }
++
++ return 0;
++
++err:
++ ep93xx_free_buffers(ep);
++ return 1;
++}
++
++static int ep93xx_start_hw(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ unsigned long addr;
++ int i;
++
++ wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET);
++ for (i = 0; i < 10; i++) {
++ if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0)
++ break;
++ msleep(1);
++ }
++
++ if (i == 10) {
++ printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
++ return 1;
++ }
++
++ wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9));
++
++ /* Does the PHY support preamble suppress? */
++ if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0)
++ wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8));
++
++ /* Receive descriptor ring. */
++ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc);
++ wrl(ep, REG_RXDQBADD, addr);
++ wrl(ep, REG_RXDCURADD, addr);
++ wrw(ep, REG_RXDQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc));
++
++ /* Receive status ring. */
++ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat);
++ wrl(ep, REG_RXSTSQBADD, addr);
++ wrl(ep, REG_RXSTSQCURADD, addr);
++ wrw(ep, REG_RXSTSQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat));
++
++ /* Transmit descriptor ring. */
++ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc);
++ wrl(ep, REG_TXDQBADD, addr);
++ wrl(ep, REG_TXDQCURADD, addr);
++ wrw(ep, REG_TXDQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc));
++
++ /* Transmit status ring. */
++ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat);
++ wrl(ep, REG_TXSTSQBADD, addr);
++ wrl(ep, REG_TXSTSQCURADD, addr);
++ wrw(ep, REG_TXSTSQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat));
++
++ wrl(ep, REG_BMCTL, REG_BMCTL_ENABLE_TX | REG_BMCTL_ENABLE_RX);
++ wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
++ wrl(ep, REG_GIINTMSK, 0);
++
++ for (i = 0; i < 10; i++) {
++ if ((rdl(ep, REG_BMSTS) & REG_BMSTS_RX_ACTIVE) != 0)
++ break;
++ msleep(1);
++ }
++
++ if (i == 10) {
++ printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n");
++ return 1;
++ }
++
++ wrl(ep, REG_RXDENQ, RX_QUEUE_ENTRIES);
++ wrl(ep, REG_RXSTSENQ, RX_QUEUE_ENTRIES);
++
++ wrb(ep, REG_INDAD0, dev->dev_addr[0]);
++ wrb(ep, REG_INDAD1, dev->dev_addr[1]);
++ wrb(ep, REG_INDAD2, dev->dev_addr[2]);
++ wrb(ep, REG_INDAD3, dev->dev_addr[3]);
++ wrb(ep, REG_INDAD4, dev->dev_addr[4]);
++ wrb(ep, REG_INDAD5, dev->dev_addr[5]);
++ wrl(ep, REG_AFP, 0);
++
++ wrl(ep, REG_MAXFRMLEN, (MAX_PKT_SIZE << 16) | MAX_PKT_SIZE);
++
++ wrl(ep, REG_RXCTL, REG_RXCTL_DEFAULT);
++ wrl(ep, REG_TXCTL, REG_TXCTL_ENABLE);
++
++ return 0;
++}
++
++static void ep93xx_stop_hw(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int i;
++
++ wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET);
++ for (i = 0; i < 10; i++) {
++ if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0)
++ break;
++ msleep(1);
++ }
++
++ if (i == 10)
++ printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
++}
++
++static int ep93xx_open(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int err;
++
++ if (ep93xx_alloc_buffers(ep))
++ return -ENOMEM;
++
++ if (is_zero_ether_addr(dev->dev_addr)) {
++ random_ether_addr(dev->dev_addr);
++ printk(KERN_INFO "%s: generated random MAC address "
++ "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name,
++ dev->dev_addr[0], dev->dev_addr[1],
++ dev->dev_addr[2], dev->dev_addr[3],
++ dev->dev_addr[4], dev->dev_addr[5]);
++ }
++
++ if (ep93xx_start_hw(dev)) {
++ ep93xx_free_buffers(ep);
++ return -EIO;
++ }
++
++ spin_lock_init(&ep->rx_lock);
++ ep->rx_pointer = 0;
++ ep->tx_clean_pointer = 0;
++ ep->tx_pointer = 0;
++ spin_lock_init(&ep->tx_pending_lock);
++ ep->tx_pending = 0;
++
++ err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev);
++ if (err) {
++ ep93xx_stop_hw(dev);
++ ep93xx_free_buffers(ep);
++ return err;
++ }
++
++ wrl(ep, REG_GIINTMSK, REG_GIINTMSK_ENABLE);
++
++ netif_start_queue(dev);
++
++ return 0;
++}
++
++static int ep93xx_close(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++
++ netif_stop_queue(dev);
++
++ wrl(ep, REG_GIINTMSK, 0);
++ free_irq(ep->irq, dev);
++ ep93xx_stop_hw(dev);
++ ep93xx_free_buffers(ep);
++
++ return 0;
++}
++
++static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ struct mii_ioctl_data *data = if_mii(ifr);
++
++ return generic_mii_ioctl(&ep->mii, data, cmd, NULL);
++}
++
++static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int data;
++ int i;
++
++ wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg);
++
++ for (i = 0; i < 10; i++) {
++ if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
++ break;
++ msleep(1);
++ }
++
++ if (i == 10) {
++ printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n");
++ data = 0xffff;
++ } else {
++ data = rdl(ep, REG_MIIDATA);
++ }
++
++ return data;
++}
++
++static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ int i;
++
++ wrl(ep, REG_MIIDATA, data);
++ wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg);
++
++ for (i = 0; i < 10; i++) {
++ if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
++ break;
++ msleep(1);
++ }
++
++ if (i == 10)
++ printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n");
++}
++
++static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
++{
++ strcpy(info->driver, DRV_MODULE_NAME);
++ strcpy(info->version, DRV_MODULE_VERSION);
++}
++
++static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ return mii_ethtool_gset(&ep->mii, cmd);
++}
++
++static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ return mii_ethtool_sset(&ep->mii, cmd);
++}
++
++static int ep93xx_nway_reset(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ return mii_nway_restart(&ep->mii);
++}
++
++static u32 ep93xx_get_link(struct net_device *dev)
++{
++ struct ep93xx_priv *ep = netdev_priv(dev);
++ return mii_link_ok(&ep->mii);
++}
++
++static struct ethtool_ops ep93xx_ethtool_ops = {
++ .get_drvinfo = ep93xx_get_drvinfo,
++ .get_settings = ep93xx_get_settings,
++ .set_settings = ep93xx_set_settings,
++ .nway_reset = ep93xx_nway_reset,
++ .get_link = ep93xx_get_link,
++};
++
++struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
++{
++ struct net_device *dev;
++ struct ep93xx_priv *ep;
++
++ dev = alloc_etherdev(sizeof(struct ep93xx_priv));
++ if (dev == NULL)
++ return NULL;
++ ep = netdev_priv(dev);
++
++ memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN);
++
++ dev->get_stats = ep93xx_get_stats;
++ dev->ethtool_ops = &ep93xx_ethtool_ops;
++ dev->poll = ep93xx_poll;
++ dev->hard_start_xmit = ep93xx_xmit;
++ dev->open = ep93xx_open;
++ dev->stop = ep93xx_close;
++ dev->do_ioctl = ep93xx_ioctl;
++
++ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
++ dev->weight = 64;
++
++ return dev;
++}
++
++
++static int ep93xx_eth_remove(struct platform_device *pdev)
++{
++ struct net_device *dev;
++ struct ep93xx_priv *ep;
++
++ dev = platform_get_drvdata(pdev);
++ if (dev == NULL)
++ return 0;
++ platform_set_drvdata(pdev, NULL);
++
++ ep = netdev_priv(dev);
++
++ /* @@@ Force down. */
++ unregister_netdev(dev);
++ ep93xx_free_buffers(ep);
++
++ if (ep->base_addr != NULL)
++ iounmap(ep->base_addr);
++
++ if (ep->res != NULL) {
++ release_resource(ep->res);
++ kfree(ep->res);
++ }
++
++ free_netdev(dev);
++
++ return 0;
++}
++
++static int ep93xx_eth_probe(struct platform_device *pdev)
++{
++ struct ep93xx_eth_data *data;
++ struct net_device *dev;
++ struct ep93xx_priv *ep;
++ int err;
++
++ data = pdev->dev.platform_data;
++ if (pdev == NULL)
++ return -ENODEV;
++
++ dev = ep93xx_dev_alloc(data);
++ if (dev == NULL) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++ ep = netdev_priv(dev);
++
++ platform_set_drvdata(pdev, dev);
++
++ ep->res = request_mem_region(pdev->resource[0].start,
++ pdev->resource[0].end - pdev->resource[0].start + 1,
++ pdev->dev.bus_id);
++ if (ep->res == NULL) {
++ dev_err(&pdev->dev, "Could not reserve memory region\n");
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ ep->base_addr = ioremap(pdev->resource[0].start,
++ pdev->resource[0].end - pdev->resource[0].start);
++ if (ep->base_addr == NULL) {
++ dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++ err = -EIO;
++ goto err_out;
++ }
++ ep->irq = pdev->resource[1].start;
++
++ ep->mii.phy_id = data->phy_id;
++ ep->mii.phy_id_mask = 0x1f;
++ ep->mii.reg_num_mask = 0x1f;
++ ep->mii.dev = dev;
++ ep->mii.mdio_read = ep93xx_mdio_read;
++ ep->mii.mdio_write = ep93xx_mdio_write;
++ ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */
++
++ err = register_netdev(dev);
++ if (err) {
++ dev_err(&pdev->dev, "Failed to register netdev\n");
++ goto err_out;
++ }
++
++ printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, "
++ "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name,
++ ep->irq, data->dev_addr[0], data->dev_addr[1],
++ data->dev_addr[2], data->dev_addr[3],
++ data->dev_addr[4], data->dev_addr[5]);
++
++ return 0;
++
++err_out:
++ ep93xx_eth_remove(pdev);
++ return err;
++}
++
++
++static struct platform_driver ep93xx_eth_driver = {
++ .probe = ep93xx_eth_probe,
++ .remove = ep93xx_eth_remove,
++ .driver = {
++ .name = "ep93xx-eth",
++ },
++};
++
++static int __init ep93xx_eth_init_module(void)
++{
++ printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n");
++ return platform_driver_register(&ep93xx_eth_driver);
++}
++
++static void __exit ep93xx_eth_cleanup_module(void)
++{
++ platform_driver_unregister(&ep93xx_eth_driver);
++}
++
++module_init(ep93xx_eth_init_module);
++module_exit(ep93xx_eth_cleanup_module);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
+index 312955d..f3478a3 100644
+--- a/drivers/net/arm/ether1.c
++++ b/drivers/net/arm/ether1.c
+@@ -68,7 +68,7 @@ static unsigned int net_debug = NET_DEBU
+
+ static int ether1_open(struct net_device *dev);
+ static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ether1_interrupt(int irq, void *dev_id);
+ static int ether1_close(struct net_device *dev);
+ static struct net_device_stats *ether1_getstats(struct net_device *dev);
+ static void ether1_setmulticastlist(struct net_device *dev);
+@@ -908,7 +908,7 @@ ether1_recv_done (struct net_device *dev
+ }
+
+ static irqreturn_t
+-ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
++ether1_interrupt (int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ int status;
+diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
+index 0810741..84686c8 100644
+--- a/drivers/net/arm/ether3.c
++++ b/drivers/net/arm/ether3.c
+@@ -81,7 +81,7 @@ static int ether3_rx(struct net_device *
+ static void ether3_tx(struct net_device *dev);
+ static int ether3_open (struct net_device *dev);
+ static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ether3_interrupt (int irq, void *dev_id);
+ static int ether3_close (struct net_device *dev);
+ static struct net_device_stats *ether3_getstats (struct net_device *dev);
+ static void ether3_setmulticastlist (struct net_device *dev);
+@@ -568,7 +568,7 @@ ether3_sendpacket(struct sk_buff *skb, s
+ }
+
+ static irqreturn_t
+-ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++ether3_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ unsigned int status, handled = IRQ_NONE;
+diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
+index d52deb8..4ae9897 100644
+--- a/drivers/net/arm/etherh.c
++++ b/drivers/net/arm/etherh.c
+@@ -626,7 +626,7 @@ static int etherh_set_settings(struct ne
+ return 0;
+ }
+
+-static struct ethtool_ops etherh_ethtool_ops = {
++static const struct ethtool_ops etherh_ethtool_ops = {
+ .get_settings = etherh_get_settings,
+ .set_settings = etherh_set_settings,
+ .get_drvinfo = etherh_get_drvinfo,
+diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
+index 4ca061c..8620a5b 100644
+--- a/drivers/net/at1700.c
++++ b/drivers/net/at1700.c
+@@ -18,7 +18,7 @@
+ straight-forward Fujitsu MB86965 implementations.
+
+ Modification for Fujitsu FMV-18X cards is done by Yutaka Tamiya
+- (tamy at flab.fujitsu.co.jp).
++ (tamy at flab.fujitsu.co.jp).
+
+ Sources:
+ The Fujitsu MB86965 datasheet.
+@@ -58,7 +58,7 @@
+ #include <asm/dma.h>
+
+ static char version[] __initdata =
+- "at1700.c:v1.15 4/7/98 Donald Becker (becker at cesdis.gsfc.nasa.gov)\n";
++ "at1700.c:v1.16 9/11/06 Donald Becker (becker at cesdis.gsfc.nasa.gov)\n";
+
+ #define DRV_NAME "at1700"
+
+@@ -161,14 +161,14 @@ static int at1700_probe1(struct net_devi
+ static int read_eeprom(long ioaddr, int location);
+ static int net_open(struct net_device *dev);
+ static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t net_interrupt(int irq, void *dev_id);
+ static void net_rx(struct net_device *dev);
+ static int net_close(struct net_device *dev);
+ static struct net_device_stats *net_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+ static void net_tx_timeout (struct net_device *dev);
+
+-
++
+ #ifdef CONFIG_MCA_LEGACY
+ struct at1720_mca_adapters_struct {
+ char* name;
+@@ -201,7 +201,7 @@ static void cleanup_card(struct net_devi
+ struct net_local *lp = netdev_priv(dev);
+ if (lp->mca_slot >= 0)
+ mca_mark_as_unused(lp->mca_slot);
+-#endif
++#endif
+ free_irq(dev->irq, NULL);
+ release_region(dev->base_addr, AT1700_IO_EXTENT);
+ }
+@@ -301,7 +301,7 @@ static int __init at1700_probe1(struct n
+ for (j = 0; at1720_mca_adapters[j].name != NULL; j ++) {
+ slot = 0;
+ while (slot != MCA_NOTFOUND) {
+-
++
+ slot = mca_find_unused_adapter( at1720_mca_adapters[j].id, slot );
+ if (slot == MCA_NOTFOUND) break;
+
+@@ -315,7 +315,7 @@ static int __init at1700_probe1(struct n
+ if (( pos3 & 0x07) == at1700_ioaddr_pattern[l_i])
+ break;
+ ioaddr = at1700_mca_probe_list[l_i];
+-
++
+ for (irq = 0; irq < 0x10; irq++)
+ if (((((pos4>>4) & 0x0f) | (pos3 & 0xf0)) & 0xff) == at1700_irq_pattern[irq])
+ break;
+@@ -328,7 +328,7 @@ static int __init at1700_probe1(struct n
+ }
+
+ dev->irq = irq;
+-
++
+ /* claim the slot */
+ mca_set_adapter_name( slot, at1720_mca_adapters[j].name );
+ mca_mark_as_used(slot);
+@@ -353,7 +353,7 @@ static int __init at1700_probe1(struct n
+ else {
+ goto err_out;
+ }
+-
++
+ #ifdef CONFIG_MCA_LEGACY
+ found:
+ #endif
+@@ -487,7 +487,7 @@ err_out:
+ return ret;
+ }
+
+-
++
+ /* EEPROM_Ctrl bits. */
+ #define EE_SHIFT_CLK 0x40 /* EEPROM shift clock, in reg. 16. */
+ #define EE_CS 0x20 /* EEPROM chip select, in reg. 16. */
+@@ -528,7 +528,7 @@ static int __init read_eeprom(long ioadd
+ return retval;
+ }
+
+-
++
+
+ static int net_open(struct net_device *dev)
+ {
+@@ -645,11 +645,10 @@ static int net_send_packet (struct sk_bu
+
+ return 0;
+ }
+-
++
+ /* The typical workload of the driver:
+ Handle the network interface interrupts. */
+-static irqreturn_t
+-net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t net_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+@@ -663,9 +662,9 @@ net_interrupt(int irq, void *dev_id, str
+
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+-
++
+ spin_lock (&lp->lock);
+-
++
+ status = inw(ioaddr + TX_STATUS);
+ outw(status, ioaddr + TX_STATUS);
+
+@@ -851,8 +850,6 @@ set_rx_mode(struct net_device *dev)
+ int i;
+
+ if (dev->flags & IFF_PROMISC) {
+- /* Unconditionally log net taps. */
+- printk("%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
+ } else if (dev->mc_count > MC_FILTERBREAK
+@@ -921,7 +918,7 @@ cleanup_module(void)
+ #endif /* MODULE */
+ MODULE_LICENSE("GPL");
+
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c"
+diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
+index 5e5f80b..4e3bf6a 100644
+--- a/drivers/net/atari_bionet.c
++++ b/drivers/net/atari_bionet.c
+@@ -220,7 +220,7 @@ gsend:
+ }
+
+ static irqreturn_t
+-bionet_intr(int irq, void *data, struct pt_regs *fp) {
++bionet_intr(int irq, void *data) {
+ return IRQ_HANDLED;
+ }
+
+@@ -460,7 +460,7 @@ bionet_send_packet(struct sk_buff *skb,
+ if (bionet_debug >1) {
+ u_char *data = nic_packet->buffer, *p;
+ int i;
+-
++
+ printk( "%s: TX pkt type 0x%4x from ", dev->name,
+ ((u_short *)data)[6]);
+
+@@ -551,7 +551,7 @@ bionet_poll_rx(struct net_device *dev) {
+ /* 'skb->data' points to the start of sk_buff data area.
+ */
+ memcpy(skb->data, nic_packet->buffer, pkt_len);
+- skb->protocol = eth_type_trans( skb, dev );
++ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ lp->stats.rx_packets++;
+@@ -565,17 +565,17 @@ bionet_poll_rx(struct net_device *dev) {
+ if (bionet_debug >1) {
+ u_char *data = nic_packet->buffer, *p;
+ int i;
+-
++
+ printk( "%s: RX pkt type 0x%4x from ", dev->name,
+ ((u_short *)data)[6]);
+-
+-
++
++
+ for( p = &data[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ printk(" to ");
+ for( p = data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+-
++
+ printk( "%s: ", dev->name );
+ printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x len %d\n",
+@@ -636,7 +636,7 @@ bionet_close(struct net_device *dev) {
+ /* Get the current statistics.
+ This may be called with the card open or closed.
+ */
+-static struct net_device_stats *net_get_stats(struct net_device *dev)
++static struct net_device_stats *net_get_stats(struct net_device *dev)
+ {
+ struct net_local *lp = netdev_priv(dev);
+ return &lp->stats;
+diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
+index d6039e6..3b54361 100644
+--- a/drivers/net/atari_pamsnet.c
++++ b/drivers/net/atari_pamsnet.c
+@@ -163,7 +163,7 @@ static int pamsnet_close(struct net_devi
+ static struct net_device_stats *net_get_stats(struct net_device *dev);
+ static void pamsnet_tick(unsigned long);
+
+-static irqreturn_t pamsnet_intr(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t pamsnet_intr(int irq, void *data);
+
+ static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0);
+
+@@ -494,7 +494,6 @@ static irqreturn_t
+ pamsnet_intr(irq, data, fp)
+ int irq;
+ void *data;
+- struct pt_regs *fp;
+ {
+ return IRQ_HANDLED;
+ }
+@@ -857,7 +856,7 @@ pamsnet_close(struct net_device *dev) {
+ /* Get the current statistics.
+ This may be called with the card open or closed.
+ */
+-static struct net_device_stats *net_get_stats(struct net_device *dev)
++static struct net_device_stats *net_get_stats(struct net_device *dev)
+ {
+ struct net_local *lp = netdev_priv(dev);
+ return &lp->stats;
+diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
+index 91783a8..d79489e 100644
+--- a/drivers/net/atarilance.c
++++ b/drivers/net/atarilance.c
+@@ -344,7 +344,7 @@ static unsigned long lance_probe1( struc
+ static int lance_open( struct net_device *dev );
+ static void lance_init_ring( struct net_device *dev );
+ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
++static irqreturn_t lance_interrupt( int irq, void *dev_id );
+ static int lance_rx( struct net_device *dev );
+ static int lance_close( struct net_device *dev );
+ static struct net_device_stats *lance_get_stats( struct net_device *dev );
+@@ -356,7 +356,7 @@ static void lance_tx_timeout (struct net
+
+
+
+-
++
+
+ static void *slow_memcpy( void *dst, const void *src, size_t len )
+
+@@ -549,7 +549,7 @@ static unsigned long __init lance_probe1
+ memaddr == (unsigned short *)0xffe00000) {
+ /* PAMs card and Riebl on ST use level 5 autovector */
+ if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
+- "PAM/Riebl-ST Ethernet", dev)) {
++ "PAM/Riebl-ST Ethernet", dev)) {
+ printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
+ return( 0 );
+ }
+@@ -639,7 +639,7 @@ static unsigned long __init lance_probe1
+ /* XXX MSch */
+ dev->tx_timeout = lance_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+-
++
+
+ #if 0
+ dev->start = 0;
+@@ -650,7 +650,7 @@ static unsigned long __init lance_probe1
+ return( 1 );
+ }
+
+-
++
+ static int lance_open( struct net_device *dev )
+
+ { struct lance_private *lp = (struct lance_private *)dev->priv;
+@@ -744,7 +744,7 @@ static void lance_tx_timeout (struct net
+ {
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ struct lance_ioreg *IO = lp->iobase;
+-
++
+ AREG = CSR0;
+ DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
+ dev->name, DREG ));
+@@ -772,7 +772,7 @@ static void lance_tx_timeout (struct net
+ -MEM->tx_head[i].length,
+ MEM->tx_head[i].misc ));
+ }
+-#endif
++#endif
+ /* XXX MSch: maybe purge/reinit ring here */
+ /* lance_restart, essentially */
+ lance_init_ring(dev);
+@@ -802,12 +802,12 @@ static int lance_start_xmit( struct sk_b
+ /* PAM-Card has a bug: Can only send packets with even number of bytes! */
+ else if (lp->cardtype == PAM_CARD && (len & 1))
+ ++len;
+-
++
+ if (len > skb->len) {
+ if (skb_padto(skb, len))
+ return 0;
+ }
+-
++
+ netif_stop_queue (dev);
+
+ /* Fill in a Tx ring entry */
+@@ -866,7 +866,7 @@ static int lance_start_xmit( struct sk_b
+
+ /* The LANCE interrupt handler. */
+
+-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t lance_interrupt( int irq, void *dev_id )
+ {
+ struct net_device *dev = dev_id;
+ struct lance_private *lp;
+@@ -1121,7 +1121,7 @@ static void set_multicast_list( struct n
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Log any net taps. */
+- DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
++ DPRINTK( 2, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+ REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
+ } else {
+ short multicast_table[4];
+@@ -1175,7 +1175,7 @@ static int lance_set_mac_address( struct
+ return( 0 );
+ }
+
+-
++
+ #ifdef MODULE
+ static struct net_device *atarilance_dev;
+
+@@ -1195,7 +1195,7 @@ void cleanup_module(void)
+ }
+
+ #endif /* MODULE */
+-
++
+
+ /*
+ * Local variables:
+diff --git a/drivers/net/atp.c b/drivers/net/atp.c
+index bfa674e..2d306fc 100644
+--- a/drivers/net/atp.c
++++ b/drivers/net/atp.c
+@@ -203,7 +203,7 @@ static void hardware_init(struct net_dev
+ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode);
+ static void trigger_send(long ioaddr, int length);
+ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t atp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t atp_interrupt(int irq, void *dev_id);
+ static void net_rx(struct net_device *dev);
+ static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode);
+ static int net_close(struct net_device *dev);
+@@ -221,7 +221,7 @@ static struct net_device *root_atp_dev;
+ If dev->base_addr == 1, always return failure.
+ If dev->base_addr == 2, allocate space for the device and return success
+ (detachable devices only).
+-
++
+ FIXME: we should use the parport layer for this
+ */
+ static int __init atp_init(void)
+@@ -596,20 +596,15 @@ static int atp_send_packet(struct sk_buf
+
+ /* The typical workload of the driver:
+ Handle the network interface interrupts. */
+-static irqreturn_t
+-atp_interrupt(int irq, void *dev_instance, struct pt_regs * regs)
++static irqreturn_t atp_interrupt(int irq, void *dev_instance)
+ {
+- struct net_device *dev = (struct net_device *)dev_instance;
++ struct net_device *dev = dev_instance;
+ struct net_local *lp;
+ long ioaddr;
+ static int num_tx_since_rx;
+ int boguscount = max_interrupt_work;
+ int handled = 0;
+
+- if (dev == NULL) {
+- printk(KERN_ERR "ATP_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+
+diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
+index 55f6e3f..7db3c8a 100644
+--- a/drivers/net/au1000_eth.c
++++ b/drivers/net/au1000_eth.c
+@@ -6,8 +6,8 @@
+ * Copyright 2002 TimeSys Corp.
+ * Added ethtool/mii-tool support,
+ * Copyright 2004 Matt Porter <mporter at kernel.crashing.org>
+- * Update: 2004 Bjoern Riemer, riemer at fokus.fraunhofer.de
+- * or riemer at riemer-nt.de: fixed the link beat detection with
++ * Update: 2004 Bjoern Riemer, riemer at fokus.fraunhofer.de
++ * or riemer at riemer-nt.de: fixed the link beat detection with
+ * ioctls (SIOCGMIIPHY)
+ * Copyright 2006 Herbert Valerio Riedel <hvr at gnu.org>
+ * converted to use linux-2.6.x's PHY framework
+@@ -32,7 +32,7 @@
+ *
+ * ########################################################################
+ *
+- *
++ *
+ */
+
+ #include <linux/module.h>
+@@ -72,7 +72,7 @@ static int au1000_debug = 3;
+ #endif
+
+ #define DRV_NAME "au1000_eth"
+-#define DRV_VERSION "1.5"
++#define DRV_VERSION "1.6"
+ #define DRV_AUTHOR "Pete Popov <ppopov at embeddedalley.com>"
+ #define DRV_DESC "Au1xxx on-chip Ethernet driver"
+
+@@ -89,7 +89,7 @@ static int au1000_open(struct net_device
+ static int au1000_close(struct net_device *);
+ static int au1000_tx(struct sk_buff *, struct net_device *);
+ static int au1000_rx(struct net_device *);
+-static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t au1000_interrupt(int, void *);
+ static void au1000_tx_timeout(struct net_device *);
+ static void set_rx_mode(struct net_device *);
+ static struct net_device_stats *au1000_get_stats(struct net_device *);
+@@ -102,18 +102,18 @@ static void enable_mac(struct net_device
+ // externs
+ extern int get_ethernet_addr(char *ethernet_addr);
+ extern void str2eaddr(unsigned char *ea, unsigned char *str);
+-extern char * __init prom_getcmdline(void);
++extern char * prom_getcmdline(void);
+
+ /*
+ * Theory of operation
+ *
+- * The Au1000 MACs use a simple rx and tx descriptor ring scheme.
+- * There are four receive and four transmit descriptors. These
+- * descriptors are not in memory; rather, they are just a set of
++ * The Au1000 MACs use a simple rx and tx descriptor ring scheme.
++ * There are four receive and four transmit descriptors. These
++ * descriptors are not in memory; rather, they are just a set of
+ * hardware registers.
+ *
+ * Since the Au1000 has a coherent data cache, the receive and
+- * transmit buffers are allocated from the KSEG0 segment. The
++ * transmit buffers are allocated from the KSEG0 segment. The
+ * hardware registers, however, are still mapped at KSEG1 to
+ * make sure there's no out-of-order writes, and that all writes
+ * complete immediately.
+@@ -123,7 +123,7 @@ extern char * __init prom_getcmdline(voi
+ * the mac address is, and the mac address is not passed on the
+ * command line.
+ */
+-static unsigned char au1000_mac_addr[6] __devinitdata = {
++static unsigned char au1000_mac_addr[6] __devinitdata = {
+ 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00
+ };
+
+@@ -207,13 +207,13 @@ static int mdio_read(struct net_device *
+ while (*mii_control_reg & MAC_MII_BUSY) {
+ mdelay(1);
+ if (--timedout == 0) {
+- printk(KERN_ERR "%s: read_MII busy timeout!!\n",
++ printk(KERN_ERR "%s: read_MII busy timeout!!\n",
+ dev->name);
+ return -1;
+ }
+ }
+
+- mii_control = MAC_SET_MII_SELECT_REG(reg) |
++ mii_control = MAC_SET_MII_SELECT_REG(reg) |
+ MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
+
+ *mii_control_reg = mii_control;
+@@ -222,7 +222,7 @@ static int mdio_read(struct net_device *
+ while (*mii_control_reg & MAC_MII_BUSY) {
+ mdelay(1);
+ if (--timedout == 0) {
+- printk(KERN_ERR "%s: mdio_read busy timeout!!\n",
++ printk(KERN_ERR "%s: mdio_read busy timeout!!\n",
+ dev->name);
+ return -1;
+ }
+@@ -241,13 +241,13 @@ static void mdio_write(struct net_device
+ while (*mii_control_reg & MAC_MII_BUSY) {
+ mdelay(1);
+ if (--timedout == 0) {
+- printk(KERN_ERR "%s: mdio_write busy timeout!!\n",
++ printk(KERN_ERR "%s: mdio_write busy timeout!!\n",
+ dev->name);
+ return;
+ }
+ }
+
+- mii_control = MAC_SET_MII_SELECT_REG(reg) |
++ mii_control = MAC_SET_MII_SELECT_REG(reg) |
+ MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
+
+ *mii_data_reg = value;
+@@ -394,7 +394,7 @@ static int mii_probe (struct net_device
+
+ /*
+ * Buffer allocation/deallocation routines. The buffer descriptor returned
+- * has the virtual and dma address of a buffer suitable for
++ * has the virtual and dma address of a buffer suitable for
+ * both, receive and transmit operations.
+ */
+ static db_dest_t *GetFreeDB(struct au1000_private *aup)
+@@ -500,22 +500,22 @@ static void reset_mac(struct net_device
+ spin_unlock_irqrestore(&aup->lock, flags);
+ }
+
+-/*
++/*
+ * Setup the receive and transmit "rings". These pointers are the addresses
+ * of the rx and tx MAC DMA registers so they are fixed by the hardware --
+ * these are not descriptors sitting in memory.
+ */
+-static void
++static void
+ setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
+ {
+ int i;
+
+ for (i = 0; i < NUM_RX_DMA; i++) {
+- aup->rx_dma_ring[i] =
++ aup->rx_dma_ring[i] =
+ (volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
+ }
+ for (i = 0; i < NUM_TX_DMA; i++) {
+- aup->tx_dma_ring[i] =
++ aup->tx_dma_ring[i] =
+ (volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
+ }
+ }
+@@ -608,7 +608,7 @@ au1000_get_drvinfo(struct net_device *de
+ info->regdump_len = 0;
+ }
+
+-static struct ethtool_ops au1000_ethtool_ops = {
++static const struct ethtool_ops au1000_ethtool_ops = {
+ .get_settings = au1000_get_settings,
+ .set_settings = au1000_set_settings,
+ .get_drvinfo = au1000_get_drvinfo,
+@@ -691,7 +691,7 @@ static struct net_device * au1000_probe(
+ /* Use the hard coded MAC addresses */
+ else {
+ str2eaddr(ethaddr, pmac + strlen("ethaddr="));
+- memcpy(au1000_mac_addr, ethaddr,
++ memcpy(au1000_mac_addr, ethaddr,
+ sizeof(au1000_mac_addr));
+ }
+ }
+@@ -780,8 +780,8 @@ static struct net_device * au1000_probe(
+ dev->tx_timeout = au1000_tx_timeout;
+ dev->watchdog_timeo = ETH_TX_TIMEOUT;
+
+- /*
+- * The boot code uses the ethernet controller, so reset it to start
++ /*
++ * The boot code uses the ethernet controller, so reset it to start
+ * fresh. au1000_init() expects that the device is in reset state.
+ */
+ reset_mac(dev);
+@@ -810,7 +810,7 @@ err_out:
+ return NULL;
+ }
+
+-/*
++/*
+ * Initialize the interface.
+ *
+ * When the device powers up, the clocks are disabled and the
+@@ -826,7 +826,7 @@ static int au1000_init(struct net_device
+ int i;
+ u32 control;
+
+- if (au1000_debug > 4)
++ if (au1000_debug > 4)
+ printk("%s: au1000_init\n", dev->name);
+
+ /* bring the device out of reset */
+@@ -1102,8 +1102,8 @@ static int au1000_tx(struct sk_buff *skb
+ int i;
+
+ if (au1000_debug > 5)
+- printk("%s: tx: aup %x len=%d, data=%p, head %d\n",
+- dev->name, (unsigned)aup, skb->len,
++ printk("%s: tx: aup %x len=%d, data=%p, head %d\n",
++ dev->name, (unsigned)aup, skb->len,
+ skb->data, aup->tx_head);
+
+ ptxd = aup->tx_dma_ring[aup->tx_head];
+@@ -1127,7 +1127,7 @@ static int au1000_tx(struct sk_buff *skb
+ pDB = aup->tx_db_inuse[aup->tx_head];
+ memcpy((void *)pDB->vaddr, skb->data, skb->len);
+ if (skb->len < ETH_ZLEN) {
+- for (i=skb->len; i<ETH_ZLEN; i++) {
++ for (i=skb->len; i<ETH_ZLEN; i++) {
+ ((char *)pDB->vaddr)[i] = 0;
+ }
+ ptxd->len = ETH_ZLEN;
+@@ -1166,7 +1166,7 @@ static inline void update_rx_stats(struc
+ if (status & RX_COLL)
+ ps->collisions++;
+ }
+- else
++ else
+ ps->rx_bytes += status & RX_FRAME_LEN_MASK;
+
+ }
+@@ -1215,13 +1215,13 @@ static int au1000_rx(struct net_device *
+ }
+ else {
+ if (au1000_debug > 4) {
+- if (status & RX_MISSED_FRAME)
++ if (status & RX_MISSED_FRAME)
+ printk("rx miss\n");
+- if (status & RX_WDOG_TIMER)
++ if (status & RX_WDOG_TIMER)
+ printk("rx wdog\n");
+- if (status & RX_RUNT)
++ if (status & RX_RUNT)
+ printk("rx runt\n");
+- if (status & RX_OVERLEN)
++ if (status & RX_OVERLEN)
+ printk("rx overlen\n");
+ if (status & RX_COLL)
+ printk("rx coll\n");
+@@ -1253,7 +1253,7 @@ static int au1000_rx(struct net_device *
+ /*
+ * Au1000 interrupt service routine.
+ */
+-static irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t au1000_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+
+@@ -1287,12 +1287,11 @@ static void set_rx_mode(struct net_devic
+ {
+ struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+- if (au1000_debug > 4)
++ if (au1000_debug > 4)
+ printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags);
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ aup->mac->control |= MAC_PROMISCUOUS;
+- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ } else if ((dev->flags & IFF_ALLMULTI) ||
+ dev->mc_count > MULTICAST_FILTER_LIMIT) {
+ aup->mac->control |= MAC_PASS_ALL_MULTI;
+@@ -1306,7 +1305,7 @@ static void set_rx_mode(struct net_devic
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+- set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,
++ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,
+ (long *)mc_filter);
+ }
+ aup->mac->multi_hash_high = mc_filter[1];
+diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
+index 41c2f84..52fe00d 100644
+--- a/drivers/net/au1000_eth.h
++++ b/drivers/net/au1000_eth.h
+@@ -23,7 +23,7 @@
+ *
+ * ########################################################################
+ *
+- *
++ *
+ */
+
+
+@@ -40,8 +40,8 @@
+
+ #define MULTICAST_FILTER_LIMIT 64
+
+-/*
+- * Data Buffer Descriptor. Data buffers must be aligned on 32 byte
++/*
++ * Data Buffer Descriptor. Data buffers must be aligned on 32 byte
+ * boundary for both, receive and transmit.
+ */
+ typedef struct db_dest {
+@@ -51,7 +51,7 @@ typedef struct db_dest {
+ } db_dest_t;
+
+ /*
+- * The transmit and receive descriptors are memory
++ * The transmit and receive descriptors are memory
+ * mapped registers.
+ */
+ typedef struct tx_dma {
+@@ -107,9 +107,9 @@ struct au1000_private {
+
+ struct phy_device *phy_dev;
+ struct mii_bus mii_bus;
+-
++
+ /* These variables are just for quick access to certain regs addresses. */
+- volatile mac_reg_t *mac; /* mac registers */
++ volatile mac_reg_t *mac; /* mac registers */
+ volatile u32 *enable; /* address of MAC Enable Register */
+
+ u32 vaddr; /* virtual address of rx/tx buffers */
+diff --git a/drivers/net/b44.c b/drivers/net/b44.c
+index bea0fc0..474a4e3 100644
+--- a/drivers/net/b44.c
++++ b/drivers/net/b44.c
+@@ -896,7 +896,7 @@ static int b44_poll(struct net_device *n
+ return (done ? 0 : 1);
+ }
+
+-static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t b44_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct b44 *bp = netdev_priv(dev);
+@@ -908,8 +908,9 @@ static irqreturn_t b44_interrupt(int irq
+ istat = br32(bp, B44_ISTAT);
+ imask = br32(bp, B44_IMASK);
+
+- /* ??? What the fuck is the purpose of the interrupt mask
+- * ??? register if we have to mask it out by hand anyways?
++ /* The interrupt mask register controls which interrupt bits
++ * will actually raise an interrupt to the CPU when set by hw/firmware,
++ * but doesn't mask off the bits.
+ */
+ istat &= imask;
+ if (istat) {
+@@ -1461,7 +1462,7 @@ out:
+ static void b44_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- b44_interrupt(dev->irq, dev, NULL);
++ b44_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1706,14 +1707,15 @@ static void __b44_set_rx_mode(struct net
+
+ __b44_set_mac_addr(bp);
+
+- if (dev->flags & IFF_ALLMULTI)
++ if ((dev->flags & IFF_ALLMULTI) ||
++ (dev->mc_count > B44_MCAST_TABLE_SIZE))
+ val |= RXCONFIG_ALLMULTI;
+ else
+ i = __b44_load_mcast(bp, dev);
+
+- for (; i < 64; i++) {
++ for (; i < 64; i++)
+ __b44_cam_write(bp, zero, i);
+- }
++
+ bw32(bp, B44_RXCONFIG, val);
+ val = br32(bp, B44_CAM_CTRL);
+ bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+@@ -2012,7 +2014,7 @@ static int b44_set_wol(struct net_device
+ return 0;
+ }
+
+-static struct ethtool_ops b44_ethtool_ops = {
++static const struct ethtool_ops b44_ethtool_ops = {
+ .get_drvinfo = b44_get_drvinfo,
+ .get_settings = b44_get_settings,
+ .set_settings = b44_set_settings,
+@@ -2055,7 +2057,7 @@ static int b44_read_eeprom(struct b44 *b
+ u16 *ptr = (u16 *) data;
+
+ for (i = 0; i < 128; i += 2)
+- ptr[i / 2] = readw(bp->regs + 4096 + i);
++ ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
+
+ return 0;
+ }
+@@ -2354,7 +2356,7 @@ static int __init b44_init(void)
+ dma_desc_align_mask = ~(dma_desc_align_size - 1);
+ dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
+
+- return pci_module_init(&b44_driver);
++ return pci_register_driver(&b44_driver);
+ }
+
+ static void __exit b44_cleanup(void)
+diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
+index 6fad83f..4528ce9 100644
+--- a/drivers/net/bmac.c
++++ b/drivers/net/bmac.c
+@@ -152,9 +152,9 @@ static void bmac_init_chip(struct net_de
+ static void bmac_init_registers(struct net_device *dev);
+ static void bmac_enable_and_reset_chip(struct net_device *dev);
+ static int bmac_set_address(struct net_device *dev, void *addr);
+-static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t bmac_misc_intr(int irq, void *dev_id);
++static irqreturn_t bmac_txdma_intr(int irq, void *dev_id);
++static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id);
+ static void bmac_set_timeout(struct net_device *dev);
+ static void bmac_tx_timeout(unsigned long data);
+ static int bmac_output(struct sk_buff *skb, struct net_device *dev);
+@@ -333,7 +333,7 @@ bmac_init_registers(struct net_device *d
+ udelay(10000);
+ }
+
+- bmwrite(dev, RSEED, (unsigned short)0x1968);
++ bmwrite(dev, RSEED, (unsigned short)0x1968);
+
+ regValue = bmread(dev, XIFC);
+ regValue |= TxOutputEnable;
+@@ -373,7 +373,7 @@ bmac_init_registers(struct net_device *d
+ bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+ bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+ bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+-
++
+ pWord16 = (unsigned short *)dev->dev_addr;
+ bmwrite(dev, MADD0, *pWord16++);
+ bmwrite(dev, MADD1, *pWord16++);
+@@ -411,11 +411,11 @@ bmac_start_chip(struct net_device *dev)
+ /* enable rx dma channel */
+ dbdma_continue(rd);
+
+- oldConfig = bmread(dev, TXCFG);
++ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
+ /* turn on rx plus any other bits already on (promiscuous possibly) */
+- oldConfig = bmread(dev, RXCFG);
++ oldConfig = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+ udelay(20000);
+ }
+@@ -456,12 +456,12 @@ static void bmac_init_chip(struct net_de
+ #ifdef CONFIG_PM
+ static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
+ {
+- struct net_device* dev = macio_get_drvdata(mdev);
++ struct net_device* dev = macio_get_drvdata(mdev);
+ struct bmac_data *bp = netdev_priv(dev);
+ unsigned long flags;
+ unsigned short config;
+ int i;
+-
++
+ netif_device_detach(dev);
+ /* prolly should wait for dma to finish & turn off the chip */
+ spin_lock_irqsave(&bp->lock, flags);
+@@ -477,7 +477,7 @@ static int bmac_suspend(struct macio_dev
+ if (bp->opened) {
+ volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+ volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+-
++
+ config = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+ config = bmread(dev, TXCFG);
+@@ -506,7 +506,7 @@ static int bmac_suspend(struct macio_dev
+
+ static int bmac_resume(struct macio_dev *mdev)
+ {
+- struct net_device* dev = macio_get_drvdata(mdev);
++ struct net_device* dev = macio_get_drvdata(mdev);
+ struct bmac_data *bp = netdev_priv(dev);
+
+ /* see if this is enough */
+@@ -688,7 +688,7 @@ static int bmac_transmit_packet(struct s
+
+ static int rxintcount;
+
+-static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct bmac_data *bp = netdev_priv(dev);
+@@ -765,7 +765,7 @@ static irqreturn_t bmac_rxdma_intr(int i
+
+ static int txintcount;
+
+-static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct bmac_data *bp = netdev_priv(dev);
+@@ -855,12 +855,12 @@ crc416(unsigned int curval, unsigned sho
+ else high_crc_set = 1;
+
+ cur = cur << 1;
+-
++
+ if ((next & 0x0001) == 0) low_data_set = 0;
+ else low_data_set = 1;
+
+ next = next >> 1;
+-
++
+ /* do the XOR */
+ if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY;
+ }
+@@ -869,7 +869,7 @@ crc416(unsigned int curval, unsigned sho
+
+ static unsigned int
+ bmac_crc(unsigned short *address)
+-{
++{
+ unsigned int newcrc;
+
+ XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
+@@ -887,7 +887,7 @@ bmac_crc(unsigned short *address)
+
+ static void
+ bmac_addhash(struct bmac_data *bp, unsigned char *addr)
+-{
++{
+ unsigned int crc;
+ unsigned short mask;
+
+@@ -902,7 +902,7 @@ bmac_addhash(struct bmac_data *bp, unsig
+
+ static void
+ bmac_removehash(struct bmac_data *bp, unsigned char *addr)
+-{
++{
+ unsigned int crc;
+ unsigned char mask;
+
+@@ -1054,13 +1054,13 @@ static void bmac_set_multicast(struct ne
+ bmwrite(dev, RXCFG, rx_cfg);
+ } else {
+ u16 hash_table[4];
+-
++
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg &= ~RxPromiscEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+
+ for(i = 0; i < 4; i++) hash_table[i] = 0;
+-
++
+ for(i = 0; i < dev->mc_count; i++) {
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+@@ -1082,7 +1082,7 @@ static void bmac_set_multicast(struct ne
+
+ static int miscintcount;
+
+-static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bmac_misc_intr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct bmac_data *bp = netdev_priv(dev);
+@@ -1091,7 +1091,7 @@ static irqreturn_t bmac_misc_intr(int ir
+ XXDEBUG(("bmac_misc_intr\n"));
+ }
+ /* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
+- /* bmac_txdma_intr_inner(irq, dev_id, regs); */
++ /* bmac_txdma_intr_inner(irq, dev_id); */
+ /* if (status & FrameReceived) bp->stats.rx_dropped++; */
+ if (status & RxErrorMask) bp->stats.rx_errors++;
+ if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
+@@ -1220,7 +1220,7 @@ bmac_get_station_address(struct net_devi
+ int i;
+ unsigned short data;
+
+- for (i = 0; i < 6; i++)
++ for (i = 0; i < 6; i++)
+ {
+ reset_and_select_srom(dev);
+ data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
+@@ -1244,7 +1244,7 @@ static void bmac_reset_and_enable(struct
+ bmac_start_chip(dev);
+ bmwrite(dev, INTDISABLE, EnableNormal);
+ bp->sleeping = 0;
+-
++
+ /*
+ * It seems that the bmac can't receive until it's transmitted
+ * a packet. So we give it a dummy packet to transmit.
+@@ -1264,7 +1264,8 @@ static int __devinit bmac_probe(struct m
+ {
+ int j, rev, ret;
+ struct bmac_data *bp;
+- unsigned char *addr;
++ const unsigned char *prop_addr;
++ unsigned char addr[6];
+ struct net_device *dev;
+ int is_bmac_plus = ((int)match->data) != 0;
+
+@@ -1272,21 +1273,23 @@ static int __devinit bmac_probe(struct m
+ printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
+ return -ENODEV;
+ }
+- addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
+- if (addr == NULL) {
+- addr = get_property(macio_get_of_node(mdev), "local-mac-address", NULL);
+- if (addr == NULL) {
++ prop_addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
++ if (prop_addr == NULL) {
++ prop_addr = get_property(macio_get_of_node(mdev),
++ "local-mac-address", NULL);
++ if (prop_addr == NULL) {
+ printk(KERN_ERR "BMAC: Can't get mac-address\n");
+ return -ENODEV;
+ }
+ }
++ memcpy(addr, prop_addr, sizeof(addr));
+
+ dev = alloc_etherdev(PRIV_BYTES);
+ if (!dev) {
+ printk(KERN_ERR "BMAC: alloc_etherdev failed, out of memory\n");
+ return -ENOMEM;
+ }
+-
++
+ bp = netdev_priv(dev);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
+@@ -1379,7 +1382,7 @@ static int __devinit bmac_probe(struct m
+ printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+ XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+ printk("\n");
+-
++
+ return 0;
+
+ err_out_irq2:
+@@ -1471,7 +1474,7 @@ bmac_start(struct net_device *dev)
+
+ if (bp->sleeping)
+ return;
+-
++
+ spin_lock_irqsave(&bp->lock, flags);
+ while (1) {
+ i = bp->tx_fill + 1;
+@@ -1559,9 +1562,9 @@ static void bmac_tx_timeout(unsigned lon
+ }
+
+ /* turn it back on */
+- oldConfig = bmread(dev, RXCFG);
++ oldConfig = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+- oldConfig = bmread(dev, TXCFG);
++ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
+ spin_unlock_irqrestore(&bp->lock, flags);
+@@ -1571,10 +1574,10 @@ static void bmac_tx_timeout(unsigned lon
+ static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
+ {
+ int i,*ip;
+-
++
+ for (i=0;i< count;i++) {
+ ip = (int*)(cp+i);
+-
++
+ printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
+ ld_le32(ip+0),
+ ld_le32(ip+1),
+@@ -1630,7 +1633,7 @@ static int __devexit bmac_remove(struct
+ unregister_netdev(dev);
+
+ free_irq(dev->irq, dev);
+- free_irq(bp->tx_dma_intr, dev);
++ free_irq(bp->tx_dma_intr, dev);
+ free_irq(bp->rx_dma_intr, dev);
+
+ iounmap((void __iomem *)dev->base_addr);
+@@ -1644,7 +1647,7 @@ static int __devexit bmac_remove(struct
+ return 0;
+ }
+
+-static struct of_device_id bmac_match[] =
++static struct of_device_id bmac_match[] =
+ {
+ {
+ .name = "bmac",
+@@ -1659,7 +1662,7 @@ static struct of_device_id bmac_match[]
+ };
+ MODULE_DEVICE_TABLE (of, bmac_match);
+
+-static struct macio_driver bmac_driver =
++static struct macio_driver bmac_driver =
+ {
+ .name = "bmac",
+ .match_table = bmac_match,
+diff --git a/drivers/net/bmac.h b/drivers/net/bmac.h
+index df3b93d..a1d19d8 100644
+--- a/drivers/net/bmac.h
++++ b/drivers/net/bmac.h
+@@ -14,7 +14,7 @@
+ * (HME) controller. See sunhme.h
+ */
+
+-
++
+ /* register offsets */
+
+ /* global status and control */
+diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
+index 652eb05..01b76d3 100644
+--- a/drivers/net/bnx2.c
++++ b/drivers/net/bnx2.c
+@@ -56,8 +56,8 @@
+
+ #define DRV_MODULE_NAME "bnx2"
+ #define PFX DRV_MODULE_NAME ": "
+-#define DRV_MODULE_VERSION "1.4.44"
+-#define DRV_MODULE_RELDATE "August 10, 2006"
++#define DRV_MODULE_VERSION "1.4.45"
++#define DRV_MODULE_RELDATE "September 29, 2006"
+
+ #define RUN_AT(x) (jiffies + (x))
+
+@@ -148,7 +148,7 @@ static struct flash_spec flash_table[] =
+ SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+ "Entry 0100"},
+ /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
+- {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
++ {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
+ 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
+ "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
+@@ -317,7 +317,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg,
+ BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
+ BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
+ REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
+-
++
+ for (i = 0; i < 50; i++) {
+ udelay(10);
+
+@@ -585,7 +585,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
+ u32 local_adv, remote_adv;
+
+ bp->flow_ctrl = 0;
+- if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
++ if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
+ (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
+
+ if (bp->duplex == DUPLEX_FULL) {
+@@ -1087,7 +1087,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
+
+ #define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
+-
++
+ #define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
+
+ static int
+@@ -1120,7 +1120,7 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
+ new_adv_reg |= ADVERTISE_100FULL;
+ if (bp->advertising & ADVERTISED_1000baseT_Full)
+ new_adv1000_reg |= ADVERTISE_1000FULL;
+-
++
+ new_adv_reg |= ADVERTISE_CSMA;
+
+ new_adv_reg |= bnx2_phy_get_pause_adv(bp);
+@@ -1157,7 +1157,7 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
+
+ bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_read_phy(bp, MII_BMSR, &bmsr);
+-
++
+ if (bmsr & BMSR_LSTATUS) {
+ /* Force link down */
+ bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+@@ -1547,7 +1547,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
+ }
+
+ static void
+-bnx2_set_mac_addr(struct bnx2 *bp)
++bnx2_set_mac_addr(struct bnx2 *bp)
+ {
+ u32 val;
+ u8 *mac_addr = bp->dev->dev_addr;
+@@ -1556,7 +1556,7 @@ bnx2_set_mac_addr(struct bnx2 *bp)
+
+ REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
+
+- val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
++ val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
+ (mac_addr[4] << 8) | mac_addr[5];
+
+ REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
+@@ -1638,7 +1638,7 @@ bnx2_tx_int(struct bnx2 *bp)
+
+ tx_buf = &bp->tx_buf_ring[sw_ring_cons];
+ skb = tx_buf->skb;
+-#ifdef BCM_TSO
++#ifdef BCM_TSO
+ /* partial BD completions possible with TSO packets */
+ if (skb_is_gso(skb)) {
+ u16 last_idx, last_ring_idx;
+@@ -1888,7 +1888,7 @@ next_rx:
+ * is that the MSI interrupt is always serviced.
+ */
+ static irqreturn_t
+-bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
++bnx2_msi(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct bnx2 *bp = netdev_priv(dev);
+@@ -1908,7 +1908,7 @@ bnx2_msi(int irq, void *dev_instance, st
+ }
+
+ static irqreturn_t
+-bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++bnx2_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct bnx2 *bp = netdev_priv(dev);
+@@ -1984,12 +1984,12 @@ bnx2_poll(struct net_device *dev, int *b
+
+ if (orig_budget > dev->quota)
+ orig_budget = dev->quota;
+-
++
+ work_done = bnx2_rx_int(bp, orig_budget);
+ *budget -= work_done;
+ dev->quota -= work_done;
+ }
+-
++
+ bp->last_status_idx = bp->status_blk->status_idx;
+ rmb();
+
+@@ -2322,7 +2322,7 @@ bnx2_init_cpus(struct bnx2 *bp)
+ cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
+ cpu_reg.spad_base = BNX2_RXP_SCRATCH;
+ cpu_reg.mips_view_base = 0x8000000;
+-
++
+ fw.ver_major = bnx2_RXP_b06FwReleaseMajor;
+ fw.ver_minor = bnx2_RXP_b06FwReleaseMinor;
+ fw.ver_fix = bnx2_RXP_b06FwReleaseFix;
+@@ -2374,7 +2374,7 @@ bnx2_init_cpus(struct bnx2 *bp)
+ cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
+ cpu_reg.spad_base = BNX2_TXP_SCRATCH;
+ cpu_reg.mips_view_base = 0x8000000;
+-
++
+ fw.ver_major = bnx2_TXP_b06FwReleaseMajor;
+ fw.ver_minor = bnx2_TXP_b06FwReleaseMinor;
+ fw.ver_fix = bnx2_TXP_b06FwReleaseFix;
+@@ -2426,7 +2426,7 @@ bnx2_init_cpus(struct bnx2 *bp)
+ cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
+ cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
+ cpu_reg.mips_view_base = 0x8000000;
+-
++
+ fw.ver_major = bnx2_TPAT_b06FwReleaseMajor;
+ fw.ver_minor = bnx2_TPAT_b06FwReleaseMinor;
+ fw.ver_fix = bnx2_TPAT_b06FwReleaseFix;
+@@ -2478,7 +2478,7 @@ bnx2_init_cpus(struct bnx2 *bp)
+ cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
+ cpu_reg.spad_base = BNX2_COM_SCRATCH;
+ cpu_reg.mips_view_base = 0x8000000;
+-
++
+ fw.ver_major = bnx2_COM_b06FwReleaseMajor;
+ fw.ver_minor = bnx2_COM_b06FwReleaseMinor;
+ fw.ver_fix = bnx2_COM_b06FwReleaseFix;
+@@ -2741,7 +2741,7 @@ bnx2_enable_nvram_access(struct bnx2 *bp
+
+ val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
+ /* Enable both bits, even on read. */
+- REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
++ REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
+ val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
+ }
+
+@@ -2752,7 +2752,7 @@ bnx2_disable_nvram_access(struct bnx2 *b
+
+ val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
+ /* Disable both bits, even after read. */
+- REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
++ REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
+ val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
+ BNX2_NVM_ACCESS_ENABLE_WR_EN));
+ }
+@@ -3143,7 +3143,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 of
+ /* Find the data_start addr */
+ data_start = (written == 0) ? offset32 : page_start;
+ /* Find the data_end addr */
+- data_end = (page_end > offset32 + len32) ?
++ data_end = (page_end > offset32 + len32) ?
+ (offset32 + len32) : page_end;
+
+ /* Request access to the flash interface. */
+@@ -3164,8 +3164,8 @@ bnx2_nvram_write(struct bnx2 *bp, u32 of
+ cmd_flags |= BNX2_NVM_COMMAND_LAST;
+ }
+ rc = bnx2_nvram_read_dword(bp,
+- page_start + j,
+- &flash_buffer[j],
++ page_start + j,
++ &flash_buffer[j],
+ cmd_flags);
+
+ if (rc)
+@@ -3192,7 +3192,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 of
+ if (bp->flash_info->buffered == 0) {
+ for (addr = page_start; addr < data_start;
+ addr += 4, i += 4) {
+-
++
+ rc = bnx2_nvram_write_dword(bp, addr,
+ &flash_buffer[i], cmd_flags);
+
+@@ -3226,7 +3226,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 of
+ if (bp->flash_info->buffered == 0) {
+ for (addr = data_end; addr < page_end;
+ addr += 4, i += 4) {
+-
++
+ if (addr == page_end-4) {
+ cmd_flags = BNX2_NVM_COMMAND_LAST;
+ }
+@@ -3351,9 +3351,9 @@ bnx2_init_chip(struct bnx2 *bp)
+ val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
+ BNX2_DMA_CONFIG_DATA_WORD_SWAP |
+ #ifdef __BIG_ENDIAN
+- BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
++ BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
+ #endif
+- BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
++ BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
+ DMA_READ_CHANS << 12 |
+ DMA_WRITE_CHANS << 16;
+
+@@ -3446,7 +3446,7 @@ bnx2_init_chip(struct bnx2 *bp)
+ REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
+ (u64) bp->stats_blk_mapping >> 32);
+
+- REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
++ REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
+ (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
+
+ REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
+@@ -3511,7 +3511,7 @@ bnx2_init_tx_ring(struct bnx2 *bp)
+ bp->tx_wake_thresh = bp->tx_ring_size / 2;
+
+ txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
+-
++
+ txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
+ txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
+
+@@ -3519,7 +3519,7 @@ bnx2_init_tx_ring(struct bnx2 *bp)
+ bp->tx_cons = 0;
+ bp->hw_tx_cons = 0;
+ bp->tx_prod_bseq = 0;
+-
++
+ val = BNX2_L2CTX_TYPE_TYPE_L2;
+ val |= BNX2_L2CTX_TYPE_SIZE_L2;
+ CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TYPE, val);
+@@ -3540,7 +3540,7 @@ bnx2_init_rx_ring(struct bnx2 *bp)
+ {
+ struct rx_bd *rxbd;
+ int i;
+- u16 prod, ring_prod;
++ u16 prod, ring_prod;
+ u32 val;
+
+ /* 8 for CRC and VLAN */
+@@ -3552,7 +3552,7 @@ bnx2_init_rx_ring(struct bnx2 *bp)
+ bp->rx_cons = 0;
+ bp->hw_rx_cons = 0;
+ bp->rx_prod_bseq = 0;
+-
++
+ for (i = 0; i < bp->rx_max_ring; i++) {
+ int j;
+
+@@ -3927,7 +3927,7 @@ bnx2_test_memory(struct bnx2 *bp)
+ return ret;
+ }
+ }
+-
++
+ return ret;
+ }
+
+@@ -4124,7 +4124,7 @@ bnx2_test_link(struct bnx2 *bp)
+ bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ spin_unlock_bh(&bp->phy_lock);
+-
++
+ if (bmsr & BMSR_LSTATUS) {
+ return 0;
+ }
+@@ -4291,7 +4291,7 @@ bnx2_open(struct net_device *dev)
+ bnx2_free_mem(bp);
+ return rc;
+ }
+-
++
+ mod_timer(&bp->timer, jiffies + bp->current_interval);
+
+ atomic_set(&bp->intr_sem, 0);
+@@ -4423,7 +4423,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
+ ring_prod = TX_RING_IDX(prod);
+
+ vlan_tag_flags = 0;
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
+ }
+
+@@ -4431,7 +4431,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
+ vlan_tag_flags |=
+ (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
+ }
+-#ifdef BCM_TSO
++#ifdef BCM_TSO
+ if ((mss = skb_shinfo(skb)->gso_size) &&
+ (skb->len > (bp->dev->mtu + ETH_HLEN))) {
+ u32 tcp_opt_len, ip_tcp_len;
+@@ -4470,7 +4470,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
+ }
+
+ mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+-
++
+ tx_buf = &bp->tx_buf_ring[ring_prod];
+ tx_buf->skb = skb;
+ pci_unmap_addr_set(tx_buf, mapping, mapping);
+@@ -4600,23 +4600,23 @@ bnx2_get_stats(struct net_device *dev)
+ net_stats->tx_bytes =
+ GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
+
+- net_stats->multicast =
++ net_stats->multicast =
+ GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
+
+- net_stats->collisions =
++ net_stats->collisions =
+ (unsigned long) stats_blk->stat_EtherStatsCollisions;
+
+- net_stats->rx_length_errors =
++ net_stats->rx_length_errors =
+ (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
+ stats_blk->stat_EtherStatsOverrsizePkts);
+
+- net_stats->rx_over_errors =
++ net_stats->rx_over_errors =
+ (unsigned long) stats_blk->stat_IfInMBUFDiscards;
+
+- net_stats->rx_frame_errors =
++ net_stats->rx_frame_errors =
+ (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
+
+- net_stats->rx_crc_errors =
++ net_stats->rx_crc_errors =
+ (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
+
+ net_stats->rx_errors = net_stats->rx_length_errors +
+@@ -4637,7 +4637,7 @@ bnx2_get_stats(struct net_device *dev)
+ }
+
+ net_stats->tx_errors =
+- (unsigned long)
++ (unsigned long)
+ stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
+ +
+ net_stats->tx_aborted_errors +
+@@ -4698,7 +4698,7 @@ bnx2_get_settings(struct net_device *dev
+
+ return 0;
+ }
+-
++
+ static int
+ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+@@ -4711,7 +4711,7 @@ bnx2_set_settings(struct net_device *dev
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ autoneg |= AUTONEG_SPEED;
+
+- cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
++ cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
+
+ /* allow advertising 1 speed */
+ if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
+@@ -4988,7 +4988,7 @@ bnx2_set_coalesce(struct net_device *dev
+ bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
+ if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
+
+- bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
++ bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
+ if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
+
+ bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
+@@ -5206,46 +5206,46 @@ static const unsigned long bnx2_stats_of
+ STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
+ STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
+ STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
+- STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
+- STATS_OFFSET32(stat_Dot3StatsFCSErrors),
+- STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
+- STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
+- STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
+- STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
+- STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
+- STATS_OFFSET32(stat_Dot3StatsLateCollisions),
+- STATS_OFFSET32(stat_EtherStatsCollisions),
+- STATS_OFFSET32(stat_EtherStatsFragments),
+- STATS_OFFSET32(stat_EtherStatsJabbers),
+- STATS_OFFSET32(stat_EtherStatsUndersizePkts),
+- STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
+- STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
+- STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
+- STATS_OFFSET32(stat_XonPauseFramesReceived),
+- STATS_OFFSET32(stat_XoffPauseFramesReceived),
+- STATS_OFFSET32(stat_OutXonSent),
+- STATS_OFFSET32(stat_OutXoffSent),
+- STATS_OFFSET32(stat_MacControlFramesReceived),
+- STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
+- STATS_OFFSET32(stat_IfInMBUFDiscards),
++ STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
++ STATS_OFFSET32(stat_Dot3StatsFCSErrors),
++ STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
++ STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
++ STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
++ STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
++ STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
++ STATS_OFFSET32(stat_Dot3StatsLateCollisions),
++ STATS_OFFSET32(stat_EtherStatsCollisions),
++ STATS_OFFSET32(stat_EtherStatsFragments),
++ STATS_OFFSET32(stat_EtherStatsJabbers),
++ STATS_OFFSET32(stat_EtherStatsUndersizePkts),
++ STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
++ STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
++ STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
++ STATS_OFFSET32(stat_XonPauseFramesReceived),
++ STATS_OFFSET32(stat_XoffPauseFramesReceived),
++ STATS_OFFSET32(stat_OutXonSent),
++ STATS_OFFSET32(stat_OutXoffSent),
++ STATS_OFFSET32(stat_MacControlFramesReceived),
++ STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
++ STATS_OFFSET32(stat_IfInMBUFDiscards),
+ STATS_OFFSET32(stat_FwRxDrop),
+ };
+
+ /* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
+ * skipped because of errata.
+- */
++ */
+ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
+ 8,0,8,8,8,8,8,8,8,8,
+ 4,0,4,4,4,4,4,4,4,4,
+@@ -5429,7 +5429,7 @@ bnx2_phys_id(struct net_device *dev, u32
+ return 0;
+ }
+
+-static struct ethtool_ops bnx2_ethtool_ops = {
++static const struct ethtool_ops bnx2_ethtool_ops = {
+ .get_settings = bnx2_get_settings,
+ .set_settings = bnx2_set_settings,
+ .get_drvinfo = bnx2_get_drvinfo,
+@@ -5554,7 +5554,7 @@ poll_bnx2(struct net_device *dev)
+ struct bnx2 *bp = netdev_priv(dev);
+
+ disable_irq(bp->pdev->irq);
+- bnx2_interrupt(bp->pdev->irq, dev, NULL);
++ bnx2_interrupt(bp->pdev->irq, dev);
+ enable_irq(bp->pdev->irq);
+ }
+ #endif
+@@ -5665,7 +5665,7 @@ bnx2_init_board(struct pci_dev *pdev, st
+ bp->flags |= PCIX_FLAG;
+
+ clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
+-
++
+ clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
+ switch (clkreg) {
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
+@@ -5762,7 +5762,7 @@ bnx2_init_board(struct pci_dev *pdev, st
+ bp->tx_quick_cons_trip = 20;
+ bp->tx_ticks_int = 80;
+ bp->tx_ticks = 80;
+-
++
+ bp->rx_quick_cons_trip_int = 6;
+ bp->rx_quick_cons_trip = 6;
+ bp->rx_ticks_int = 18;
+@@ -5805,6 +5805,34 @@ bnx2_init_board(struct pci_dev *pdev, st
+ bp->cmd_ticks_int = bp->cmd_ticks;
+ }
+
++ /* Disable MSI on 5706 if AMD 8132 bridge is found.
++ *
++ * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
++ * with byte enables disabled on the unused 32-bit word. This is legal
++ * but causes problems on the AMD 8132 which will eventually stop
++ * responding after a while.
++ *
++ * AMD believes this incompatibility is unique to the 5706, and
++ * prefers to locally disable MSI rather than globally disabling it
++ * using pci_msi_quirk.
++ */
++ if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
++ struct pci_dev *amd_8132 = NULL;
++
++ while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
++ PCI_DEVICE_ID_AMD_8132_BRIDGE,
++ amd_8132))) {
++ u8 rev;
++
++ pci_read_config_byte(amd_8132, PCI_REVISION_ID, &rev);
++ if (rev >= 0x10 && rev <= 0x13) {
++ disable_msi = 1;
++ pci_dev_put(amd_8132);
++ break;
++ }
++ }
++ }
++
+ bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
+ bp->req_line_speed = 0;
+ if (bp->phy_flags & PHY_SERDES_FLAG) {
+@@ -6016,7 +6044,7 @@ static struct pci_driver bnx2_pci_driver
+
+ static int __init bnx2_init(void)
+ {
+- return pci_module_init(&bnx2_pci_driver);
++ return pci_register_driver(&bnx2_pci_driver);
+ }
+
+ static void __exit bnx2_cleanup(void)
+diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
+index fe80476..ca31904 100644
+--- a/drivers/net/bnx2.h
++++ b/drivers/net/bnx2.h
+@@ -22,9 +22,9 @@
+ */
+ struct tx_bd {
+ u32 tx_bd_haddr_hi;
+- u32 tx_bd_haddr_lo;
+- u32 tx_bd_mss_nbytes;
+- u32 tx_bd_vlan_tag_flags;
++ u32 tx_bd_haddr_lo;
++ u32 tx_bd_mss_nbytes;
++ u32 tx_bd_vlan_tag_flags;
+ #define TX_BD_FLAGS_CONN_FAULT (1<<0)
+ #define TX_BD_FLAGS_TCP_UDP_CKSUM (1<<1)
+ #define TX_BD_FLAGS_IP_CKSUM (1<<2)
+@@ -3893,7 +3893,7 @@ struct bnx2 {
+ u16 tx_cons __attribute__((aligned(L1_CACHE_BYTES)));
+ u16 hw_tx_cons;
+
+-#ifdef BCM_VLAN
++#ifdef BCM_VLAN
+ struct vlan_group *vlgrp;
+ #endif
+
+@@ -3950,7 +3950,7 @@ struct bnx2 {
+ #define CHIP_REV_Ax 0x00000000
+ #define CHIP_REV_Bx 0x00001000
+ #define CHIP_REV_Cx 0x00002000
+-
++
+ #define CHIP_METAL(bp) (((bp)->chip_id) & 0x00000ff0)
+ #define CHIP_BONDING(bp) (((bp)->chip_id) & 0x0000000f)
+
+@@ -3969,7 +3969,7 @@ struct bnx2 {
+
+ u32 phy_addr;
+ u32 phy_id;
+-
++
+ u16 bus_speed_mhz;
+ u8 wol;
+
+@@ -4025,7 +4025,7 @@ struct bnx2 {
+
+ u32 advertising;
+
+- u8 req_flow_ctrl; /* flow ctrl advertisement */
++ u8 req_flow_ctrl; /* flow ctrl advertisement */
+ /* settings or forced */
+ /* settings */
+ u8 autoneg;
+@@ -4179,7 +4179,7 @@ struct fw_info {
+ #define BNX2_DRV_MSG_DATA_WAIT1 0x00020000
+ #define BNX2_DRV_MSG_DATA_WAIT2 0x00030000
+ #define BNX2_DRV_MSG_DATA_WAIT3 0x00040000
+-
++
+ #define BNX2_DRV_MSG_SEQ 0x0000ffff
+
+ #define BNX2_FW_MB 0x00000008
+@@ -4189,38 +4189,38 @@ struct fw_info {
+ #define BNX2_FW_MSG_STATUS_FAILURE 0x00ff0000
+
+ #define BNX2_LINK_STATUS 0x0000000c
+-#define BNX2_LINK_STATUS_INIT_VALUE 0xffffffff
+-#define BNX2_LINK_STATUS_LINK_UP 0x1
+-#define BNX2_LINK_STATUS_LINK_DOWN 0x0
++#define BNX2_LINK_STATUS_INIT_VALUE 0xffffffff
++#define BNX2_LINK_STATUS_LINK_UP 0x1
++#define BNX2_LINK_STATUS_LINK_DOWN 0x0
+ #define BNX2_LINK_STATUS_SPEED_MASK 0x1e
+-#define BNX2_LINK_STATUS_AN_INCOMPLETE (0<<1)
+-#define BNX2_LINK_STATUS_10HALF (1<<1)
+-#define BNX2_LINK_STATUS_10FULL (2<<1)
+-#define BNX2_LINK_STATUS_100HALF (3<<1)
+-#define BNX2_LINK_STATUS_100BASE_T4 (4<<1)
+-#define BNX2_LINK_STATUS_100FULL (5<<1)
+-#define BNX2_LINK_STATUS_1000HALF (6<<1)
+-#define BNX2_LINK_STATUS_1000FULL (7<<1)
+-#define BNX2_LINK_STATUS_2500HALF (8<<1)
+-#define BNX2_LINK_STATUS_2500FULL (9<<1)
+-#define BNX2_LINK_STATUS_AN_ENABLED (1<<5)
+-#define BNX2_LINK_STATUS_AN_COMPLETE (1<<6)
+-#define BNX2_LINK_STATUS_PARALLEL_DET (1<<7)
+-#define BNX2_LINK_STATUS_RESERVED (1<<8)
+-#define BNX2_LINK_STATUS_PARTNER_AD_1000FULL (1<<9)
+-#define BNX2_LINK_STATUS_PARTNER_AD_1000HALF (1<<10)
+-#define BNX2_LINK_STATUS_PARTNER_AD_100BT4 (1<<11)
+-#define BNX2_LINK_STATUS_PARTNER_AD_100FULL (1<<12)
+-#define BNX2_LINK_STATUS_PARTNER_AD_100HALF (1<<13)
+-#define BNX2_LINK_STATUS_PARTNER_AD_10FULL (1<<14)
+-#define BNX2_LINK_STATUS_PARTNER_AD_10HALF (1<<15)
+-#define BNX2_LINK_STATUS_TX_FC_ENABLED (1<<16)
+-#define BNX2_LINK_STATUS_RX_FC_ENABLED (1<<17)
+-#define BNX2_LINK_STATUS_PARTNER_SYM_PAUSE_CAP (1<<18)
+-#define BNX2_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP (1<<19)
+-#define BNX2_LINK_STATUS_SERDES_LINK (1<<20)
+-#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL (1<<21)
+-#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF (1<<22)
++#define BNX2_LINK_STATUS_AN_INCOMPLETE (0<<1)
++#define BNX2_LINK_STATUS_10HALF (1<<1)
++#define BNX2_LINK_STATUS_10FULL (2<<1)
++#define BNX2_LINK_STATUS_100HALF (3<<1)
++#define BNX2_LINK_STATUS_100BASE_T4 (4<<1)
++#define BNX2_LINK_STATUS_100FULL (5<<1)
++#define BNX2_LINK_STATUS_1000HALF (6<<1)
++#define BNX2_LINK_STATUS_1000FULL (7<<1)
++#define BNX2_LINK_STATUS_2500HALF (8<<1)
++#define BNX2_LINK_STATUS_2500FULL (9<<1)
++#define BNX2_LINK_STATUS_AN_ENABLED (1<<5)
++#define BNX2_LINK_STATUS_AN_COMPLETE (1<<6)
++#define BNX2_LINK_STATUS_PARALLEL_DET (1<<7)
++#define BNX2_LINK_STATUS_RESERVED (1<<8)
++#define BNX2_LINK_STATUS_PARTNER_AD_1000FULL (1<<9)
++#define BNX2_LINK_STATUS_PARTNER_AD_1000HALF (1<<10)
++#define BNX2_LINK_STATUS_PARTNER_AD_100BT4 (1<<11)
++#define BNX2_LINK_STATUS_PARTNER_AD_100FULL (1<<12)
++#define BNX2_LINK_STATUS_PARTNER_AD_100HALF (1<<13)
++#define BNX2_LINK_STATUS_PARTNER_AD_10FULL (1<<14)
++#define BNX2_LINK_STATUS_PARTNER_AD_10HALF (1<<15)
++#define BNX2_LINK_STATUS_TX_FC_ENABLED (1<<16)
++#define BNX2_LINK_STATUS_RX_FC_ENABLED (1<<17)
++#define BNX2_LINK_STATUS_PARTNER_SYM_PAUSE_CAP (1<<18)
++#define BNX2_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP (1<<19)
++#define BNX2_LINK_STATUS_SERDES_LINK (1<<20)
++#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL (1<<21)
++#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF (1<<22)
+
+ #define BNX2_DRV_PULSE_MB 0x00000010
+ #define BNX2_DRV_PULSE_SEQ_MASK 0x00007fff
+@@ -4400,7 +4400,7 @@ struct fw_info {
+ 0x00020000)
+ #define BNX2_BC_STATE_RESET_TYPE_VAUX (BNX2_BC_STATE_RESET_TYPE_SIG | \
+ 0x00030000)
+-#define BNX2_BC_STATE_RESET_TYPE_DRV_MASK DRV_MSG_CODE
++#define BNX2_BC_STATE_RESET_TYPE_DRV_MASK DRV_MSG_CODE
+ #define BNX2_BC_STATE_RESET_TYPE_DRV_RESET (BNX2_BC_STATE_RESET_TYPE_SIG | \
+ DRV_MSG_CODE_RESET)
+ #define BNX2_BC_STATE_RESET_TYPE_DRV_UNLOAD (BNX2_BC_STATE_RESET_TYPE_SIG | \
+@@ -4443,7 +4443,7 @@ struct fw_info {
+ #define BNX2_BC_STATE_ERR_DRV_DEAD (BNX2_BC_STATE_SIGN | 0x0500)
+ #define BNX2_BC_STATE_ERR_NO_RXP (BNX2_BC_STATE_SIGN | 0x0600)
+ #define BNX2_BC_STATE_ERR_TOO_MANY_RBUF (BNX2_BC_STATE_SIGN | 0x0700)
+-
++
+ #define BNX2_BC_STATE_DEBUG_CMD 0x1dc
+ #define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE 0x42440000
+ #define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE_MASK 0xffff0000
+diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
+index 6a40707..3fb354d 100644
+--- a/drivers/net/bonding/bond_3ad.c
++++ b/drivers/net/bonding/bond_3ad.c
+@@ -85,6 +85,7 @@
+ #define AD_LINK_SPEED_BITMASK_10MBPS 0x2
+ #define AD_LINK_SPEED_BITMASK_100MBPS 0x4
+ #define AD_LINK_SPEED_BITMASK_1000MBPS 0x8
++#define AD_LINK_SPEED_BITMASK_10000MBPS 0x10
+ //endalloun
+
+ // compare MAC addresses
+@@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port
+ static u8 __get_duplex(struct port *port);
+ static inline void __initialize_port_locks(struct port *port);
+ //conversions
+-static void __ntohs_lacpdu(struct lacpdu *lacpdu);
++static void __htons_lacpdu(struct lacpdu *lacpdu);
+ static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
+
+
+@@ -330,7 +331,8 @@ static inline void __release_rx_machine_
+ * 0,
+ * %AD_LINK_SPEED_BITMASK_10MBPS,
+ * %AD_LINK_SPEED_BITMASK_100MBPS,
+- * %AD_LINK_SPEED_BITMASK_1000MBPS
++ * %AD_LINK_SPEED_BITMASK_1000MBPS,
++ * %AD_LINK_SPEED_BITMASK_10000MBPS
+ */
+ static u16 __get_link_speed(struct port *port)
+ {
+@@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port
+ speed = AD_LINK_SPEED_BITMASK_1000MBPS;
+ break;
+
++ case SPEED_10000:
++ speed = AD_LINK_SPEED_BITMASK_10000MBPS;
++ break;
++
+ default:
+ speed = 0; // unknown speed value from ethtool. shouldn't happen
+ break;
+@@ -414,23 +420,23 @@ static inline void __initialize_port_loc
+
+ //conversions
+ /**
+- * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
++ * __htons_lacpdu - convert the contents of a LACPDU to network byte order
+ * @lacpdu: the speicifed lacpdu
+ *
+ * For each multi-byte field in the lacpdu, convert its content
+ */
+-static void __ntohs_lacpdu(struct lacpdu *lacpdu)
++static void __htons_lacpdu(struct lacpdu *lacpdu)
+ {
+ if (lacpdu) {
+- lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority);
+- lacpdu->actor_key = ntohs(lacpdu->actor_key);
+- lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority);
+- lacpdu->actor_port = ntohs(lacpdu->actor_port);
+- lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
+- lacpdu->partner_key = ntohs(lacpdu->partner_key);
+- lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority);
+- lacpdu->partner_port = ntohs(lacpdu->partner_port);
+- lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay);
++ lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
++ lacpdu->actor_key = htons(lacpdu->actor_key);
++ lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
++ lacpdu->actor_port = htons(lacpdu->actor_port);
++ lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
++ lacpdu->partner_key = htons(lacpdu->partner_key);
++ lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
++ lacpdu->partner_port = htons(lacpdu->partner_port);
++ lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
+ }
+ }
+
+@@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *
+ // validate lacpdu and port
+ if (lacpdu && port) {
+ // record the new parameter values for the partner operational
+- port->partner_oper_port_number = lacpdu->actor_port;
+- port->partner_oper_port_priority = lacpdu->actor_port_priority;
++ port->partner_oper_port_number = ntohs(lacpdu->actor_port);
++ port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority);
+ port->partner_oper_system = lacpdu->actor_system;
+- port->partner_oper_system_priority = lacpdu->actor_system_priority;
+- port->partner_oper_key = lacpdu->actor_key;
++ port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority);
++ port->partner_oper_key = ntohs(lacpdu->actor_key);
+ // zero partener's lase states
+ port->partner_oper_port_state = 0;
+ port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
+@@ -561,11 +567,11 @@ static void __update_selected(struct lac
+ // validate lacpdu and port
+ if (lacpdu && port) {
+ // check if any parameter is different
+- if ((lacpdu->actor_port != port->partner_oper_port_number) ||
+- (lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
++ if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) ||
++ (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) ||
+ MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
+- (lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
+- (lacpdu->actor_key != port->partner_oper_key) ||
++ (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) ||
++ (ntohs(lacpdu->actor_key) != port->partner_oper_key) ||
+ ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
+ ) {
+ // update the state machine Selected variable
+@@ -628,11 +634,11 @@ static void __choose_matched(struct lacp
+ // validate lacpdu and port
+ if (lacpdu && port) {
+ // check if all parameters are alike
+- if (((lacpdu->partner_port == port->actor_port_number) &&
+- (lacpdu->partner_port_priority == port->actor_port_priority) &&
++ if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
++ (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
+ !MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
+- (lacpdu->partner_system_priority == port->actor_system_priority) &&
+- (lacpdu->partner_key == port->actor_oper_port_key) &&
++ (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
++ (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
+ ((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
+ // or this is individual link(aggregation == FALSE)
+ ((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
+@@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *
+ // validate lacpdu and port
+ if (lacpdu && port) {
+ // check if any parameter is different
+- if ((lacpdu->partner_port != port->actor_port_number) ||
+- (lacpdu->partner_port_priority != port->actor_port_priority) ||
++ if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
++ (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
+ MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
+- (lacpdu->partner_system_priority != port->actor_system_priority) ||
+- (lacpdu->partner_key != port->actor_oper_port_key) ||
++ (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
++ (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
+ ((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
+ ((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
+ ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
+@@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct ag
+ case AD_LINK_SPEED_BITMASK_1000MBPS:
+ bandwidth = aggregator->num_of_ports * 1000;
+ break;
++ case AD_LINK_SPEED_BITMASK_10000MBPS:
++ bandwidth = aggregator->num_of_ports * 10000;
++ break;
+ default:
+ bandwidth=0; // to silent the compilor ....
+ }
+@@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_
+ */
+
+ /* Convert all non u8 parameters to Big Endian for transmit */
+- __ntohs_lacpdu(lacpdu);
++ __htons_lacpdu(lacpdu);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+@@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struc
+
+ switch (lacpdu->subtype) {
+ case AD_TYPE_LACPDU:
+- __ntohs_lacpdu(lacpdu);
+ dprintk("Received LACPDU on port %d\n", port->actor_port_number);
+ ad_rx_machine(lacpdu, port);
+ break;
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index e83bc82..3292316 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1433,7 +1433,7 @@ void bond_alb_monitor(struct bonding *bo
+ * write lock to protect from other code that also
+ * sets the promiscuity.
+ */
+- write_lock(&bond->curr_slave_lock);
++ write_lock_bh(&bond->curr_slave_lock);
+
+ if (bond_info->primary_is_promisc &&
+ (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
+@@ -1448,7 +1448,7 @@ void bond_alb_monitor(struct bonding *bo
+ bond_info->primary_is_promisc = 0;
+ }
+
+- write_unlock(&bond->curr_slave_lock);
++ write_unlock_bh(&bond->curr_slave_lock);
+
+ if (bond_info->rlb_rebalance) {
+ bond_info->rlb_rebalance = 0;
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 8b95123..c0bbdda 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -96,6 +96,7 @@ 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, };
++static char *arp_validate = NULL;
+ struct bond_params bonding_defaults;
+
+ module_param(max_bonds, int, 0);
+@@ -127,6 +128,8 @@ module_param(arp_interval, int, 0);
+ MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
+ module_param_array(arp_ip_target, charp, NULL, 0);
+ MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
++module_param(arp_validate, charp, 0);
++MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
+
+ /*----------------------------- Global variables ----------------------------*/
+
+@@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[]
+ { NULL, -1},
+ };
+
++struct bond_parm_tbl arp_validate_tbl[] = {
++{ "none", BOND_ARP_VALIDATE_NONE},
++{ "active", BOND_ARP_VALIDATE_ACTIVE},
++{ "backup", BOND_ARP_VALIDATE_BACKUP},
++{ "all", BOND_ARP_VALIDATE_ALL},
++{ NULL, -1},
++};
++
+ /*-------------------------- Forward declarations ---------------------------*/
+
+ static void bond_send_gratuitous_arp(struct bonding *bond);
+@@ -638,6 +649,7 @@ verify:
+ case SPEED_10:
+ case SPEED_100:
+ case SPEED_1000:
++ case SPEED_10000:
+ break;
+ default:
+ return -1;
+@@ -1210,10 +1222,14 @@ static int bond_compute_features(struct
+ unsigned long features = BOND_INTERSECT_FEATURES;
+ struct slave *slave;
+ struct net_device *bond_dev = bond->dev;
++ unsigned short max_hard_header_len = ETH_HLEN;
+ int i;
+
+- bond_for_each_slave(bond, slave, i)
++ bond_for_each_slave(bond, slave, i) {
+ features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
++ if (slave->dev->hard_header_len > max_hard_header_len)
++ max_hard_header_len = slave->dev->hard_header_len;
++ }
+
+ if ((features & NETIF_F_SG) &&
+ !(features & NETIF_F_ALL_CSUM))
+@@ -1231,6 +1247,7 @@ static int bond_compute_features(struct
+
+ features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
+ bond_dev->features = features;
++ bond_dev->hard_header_len = max_hard_header_len;
+
+ return 0;
+ }
+@@ -1365,6 +1382,7 @@ int bond_enslave(struct net_device *bond
+ }
+
+ new_slave->dev = slave_dev;
++ slave_dev->priv_flags |= IFF_BONDING;
+
+ if ((bond->params.mode == BOND_MODE_TLB) ||
+ (bond->params.mode == BOND_MODE_ALB)) {
+@@ -1417,6 +1435,8 @@ int bond_enslave(struct net_device *bond
+
+ bond_compute_features(bond);
+
++ new_slave->last_arp_rx = jiffies;
++
+ if (bond->params.miimon && !bond->params.use_carrier) {
+ link_reporting = bond_check_dev_link(bond, slave_dev, 1);
+
+@@ -1493,29 +1513,8 @@ int bond_enslave(struct net_device *bond
+
+ switch (bond->params.mode) {
+ case BOND_MODE_ACTIVEBACKUP:
+- /* if we're in active-backup mode, we need one and
+- * only one active interface. The backup interfaces
+- * will have their SLAVE_INACTIVE flag set because we
+- * need them to be drop all packets. Thus, since we
+- * guarantee that curr_active_slave always point to
+- * the last usable interface, we just have to verify
+- * this interface's flag.
+- */
+- if (((!bond->curr_active_slave) ||
+- (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
+- (new_slave->link != BOND_LINK_DOWN)) {
+- /* first slave or no active slave yet, and this link
+- is OK, so make this interface the active one */
+- bond_change_active_slave(bond, new_slave);
+- printk(KERN_INFO DRV_NAME
+- ": %s: first active interface up!\n",
+- bond->dev->name);
+- netif_carrier_on(bond->dev);
+-
+- } else {
+- dprintk("This is just a backup slave\n");
+- bond_set_slave_inactive_flags(new_slave);
+- }
++ bond_set_slave_inactive_flags(new_slave);
++ bond_select_active_slave(bond);
+ break;
+ case BOND_MODE_8023AD:
+ /* in 802.3ad mode, the internal mechanism
+@@ -1778,7 +1777,8 @@ int bond_release(struct net_device *bond
+ dev_set_mac_address(slave_dev, &addr);
+
+ slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
+- IFF_SLAVE_INACTIVE);
++ IFF_SLAVE_INACTIVE | IFF_BONDING |
++ IFF_SLAVE_NEEDARP);
+
+ kfree(slave);
+
+@@ -2252,7 +2252,7 @@ static u32 bond_glean_dev_ip(struct net_
+ {
+ struct in_device *idev;
+ struct in_ifaddr *ifa;
+- u32 addr = 0;
++ __be32 addr = 0;
+
+ if (!dev)
+ return 0;
+@@ -2291,6 +2291,25 @@ static int bond_has_ip(struct bonding *b
+ return 0;
+ }
+
++static int bond_has_this_ip(struct bonding *bond, u32 ip)
++{
++ struct vlan_entry *vlan, *vlan_next;
++
++ if (ip == 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 (ip == 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
+@@ -2429,6 +2448,93 @@ static void bond_send_gratuitous_arp(str
+ }
+ }
+
++static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
++{
++ int i;
++ u32 *targets = bond->params.arp_targets;
++
++ targets = bond->params.arp_targets;
++ for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
++ dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] "
++ "%u.%u.%u.%u bhti(tip) %d\n",
++ NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]),
++ bond_has_this_ip(bond, tip));
++ if (sip == targets[i]) {
++ if (bond_has_this_ip(bond, tip))
++ slave->last_arp_rx = jiffies;
++ return;
++ }
++ }
++}
++
++static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
++{
++ struct arphdr *arp;
++ struct slave *slave;
++ struct bonding *bond;
++ unsigned char *arp_ptr;
++ u32 sip, tip;
++
++ if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
++ goto out;
++
++ bond = dev->priv;
++ read_lock(&bond->lock);
++
++ dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
++ bond->dev->name, skb->dev ? skb->dev->name : "NULL",
++ orig_dev ? orig_dev->name : "NULL");
++
++ slave = bond_get_slave_by_dev(bond, orig_dev);
++ if (!slave || !slave_do_arp_validate(bond, slave))
++ goto out_unlock;
++
++ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
++ if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
++ (2 * dev->addr_len) +
++ (2 * sizeof(u32)))))
++ goto out_unlock;
++
++ arp = skb->nh.arph;
++ if (arp->ar_hln != dev->addr_len ||
++ skb->pkt_type == PACKET_OTHERHOST ||
++ skb->pkt_type == PACKET_LOOPBACK ||
++ arp->ar_hrd != htons(ARPHRD_ETHER) ||
++ arp->ar_pro != htons(ETH_P_IP) ||
++ arp->ar_pln != 4)
++ goto out_unlock;
++
++ arp_ptr = (unsigned char *)(arp + 1);
++ arp_ptr += dev->addr_len;
++ memcpy(&sip, arp_ptr, 4);
++ arp_ptr += 4 + dev->addr_len;
++ memcpy(&tip, arp_ptr, 4);
++
++ dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u"
++ " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name,
++ slave->state, bond->params.arp_validate,
++ slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip));
++
++ /*
++ * Backup slaves won't see the ARP reply, but do come through
++ * here for each ARP probe (so we swap the sip/tip to validate
++ * the probe). In a "redundant switch, common router" type of
++ * configuration, the ARP probe will (hopefully) travel from
++ * the active, through one switch, the router, then the other
++ * switch before reaching the backup.
++ */
++ if (slave->state == BOND_STATE_ACTIVE)
++ bond_validate_arp(bond, slave, sip, tip);
++ else
++ bond_validate_arp(bond, slave, tip, sip);
++
++out_unlock:
++ read_unlock(&bond->lock);
++out:
++ dev_kfree_skb(skb);
++ return NET_RX_SUCCESS;
++}
++
+ /*
+ * this function is called regularly to monitor each slave's link
+ * ensuring that traffic is being sent and received when arp monitoring
+@@ -2593,7 +2699,8 @@ void bond_activebackup_arp_mon(struct ne
+ */
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->link != BOND_LINK_UP) {
+- if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) {
++ if ((jiffies - slave_last_rx(bond, slave)) <=
++ delta_in_ticks) {
+
+ slave->link = BOND_LINK_UP;
+
+@@ -2638,7 +2745,7 @@ void bond_activebackup_arp_mon(struct ne
+
+ if ((slave != bond->curr_active_slave) &&
+ (!bond->current_arp_slave) &&
+- (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
++ (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) &&
+ bond_has_ip(bond))) {
+ /* a backup slave has gone down; three times
+ * the delta allows the current slave to be
+@@ -2685,7 +2792,7 @@ void bond_activebackup_arp_mon(struct ne
+ * 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)) &&
++ (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) &&
+ bond_has_ip(bond))) &&
+ ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
+
+@@ -2950,7 +3057,7 @@ static void bond_info_show_slave(struct
+ seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
+ seq_printf(seq, "MII Status: %s\n",
+ (slave->link == BOND_LINK_UP) ? "up" : "down");
+- seq_printf(seq, "Link Failure Count: %d\n",
++ seq_printf(seq, "Link Failure Count: %u\n",
+ slave->link_failure_count);
+
+ seq_printf(seq,
+@@ -3210,6 +3317,9 @@ static int bond_netdev_event(struct noti
+ (event_dev ? event_dev->name : "None"),
+ event);
+
++ if (!(event_dev->priv_flags & IFF_BONDING))
++ return NOTIFY_DONE;
++
+ if (event_dev->flags & IFF_MASTER) {
+ dprintk("IFF_MASTER\n");
+ return bond_master_netdev_event(event, event_dev);
+@@ -3305,6 +3415,21 @@ static void bond_unregister_lacpdu(struc
+ dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
+ }
+
++void bond_register_arp(struct bonding *bond)
++{
++ struct packet_type *pt = &bond->arp_mon_pt;
++
++ pt->type = htons(ETH_P_ARP);
++ pt->dev = NULL; /*bond->dev;XXX*/
++ pt->func = bond_arp_rcv;
++ dev_add_pack(pt);
++}
++
++void bond_unregister_arp(struct bonding *bond)
++{
++ dev_remove_pack(&bond->arp_mon_pt);
++}
++
+ /*---------------------------- Hashing Policies -----------------------------*/
+
+ /*
+@@ -3391,6 +3516,9 @@ static int bond_open(struct net_device *
+ } else {
+ arp_timer->function = (void *)&bond_loadbalance_arp_mon;
+ }
++ if (bond->params.arp_validate)
++ bond_register_arp(bond);
++
+ add_timer(arp_timer);
+ }
+
+@@ -3418,9 +3546,11 @@ static int bond_close(struct net_device
+ bond_unregister_lacpdu(bond);
+ }
+
++ if (bond->params.arp_validate)
++ bond_unregister_arp(bond);
++
+ write_lock_bh(&bond->lock);
+
+- bond_mc_list_destroy(bond);
+
+ /* signal timers not to re-arm */
+ bond->kill_timers = 1;
+@@ -3451,8 +3581,6 @@ static int bond_close(struct net_device
+ break;
+ }
+
+- /* Release the bonded slaves */
+- bond_release_all(bond_dev);
+
+ if ((bond->params.mode == BOND_MODE_TLB) ||
+ (bond->params.mode == BOND_MODE_ALB)) {
+@@ -4130,7 +4258,7 @@ static void bond_ethtool_get_drvinfo(str
+ snprintf(drvinfo->fw_version, 32, "%d", BOND_ABI_VERSION);
+ }
+
+-static struct ethtool_ops bond_ethtool_ops = {
++static const struct ethtool_ops bond_ethtool_ops = {
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_tso = ethtool_op_get_tso,
+ .get_ufo = ethtool_op_get_ufo,
+@@ -4179,6 +4307,7 @@ static int bond_init(struct net_device *
+ /* Initialize the device options */
+ bond_dev->tx_queue_len = 0;
+ bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
++ bond_dev->priv_flags |= IFF_BONDING;
+
+ /* At first, we block adding VLANs. That's the only way to
+ * prevent problems that occur when adding VLANs over an
+@@ -4237,6 +4366,9 @@ static void bond_free_all(void)
+ list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+ struct net_device *bond_dev = bond->dev;
+
++ bond_mc_list_destroy(bond);
++ /* Release the bonded slaves */
++ bond_release_all(bond_dev);
+ unregister_netdevice(bond_dev);
+ bond_deinit(bond_dev);
+ }
+@@ -4270,6 +4402,8 @@ int bond_parse_parm(char *mode_arg, stru
+
+ static int bond_check_params(struct bond_params *params)
+ {
++ int arp_validate_value;
++
+ /*
+ * Convert string parameters.
+ */
+@@ -4473,6 +4607,29 @@ static int bond_check_params(struct bond
+ arp_interval = 0;
+ }
+
++ if (arp_validate) {
++ if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
++ printk(KERN_ERR DRV_NAME
++ ": arp_validate only supported in active-backup mode\n");
++ return -EINVAL;
++ }
++ if (!arp_interval) {
++ printk(KERN_ERR DRV_NAME
++ ": arp_validate requires arp_interval\n");
++ return -EINVAL;
++ }
++
++ arp_validate_value = bond_parse_parm(arp_validate,
++ arp_validate_tbl);
++ if (arp_validate_value == -1) {
++ printk(KERN_ERR DRV_NAME
++ ": Error: invalid arp_validate \"%s\"\n",
++ arp_validate == NULL ? "NULL" : arp_validate);
++ return -EINVAL;
++ }
++ } else
++ arp_validate_value = 0;
++
+ if (miimon) {
+ printk(KERN_INFO DRV_NAME
+ ": MII link monitoring set to %d ms\n",
+@@ -4481,8 +4638,10 @@ static int bond_check_params(struct bond
+ int i;
+
+ printk(KERN_INFO DRV_NAME
+- ": ARP monitoring set to %d ms with %d target(s):",
+- arp_interval, arp_ip_count);
++ ": ARP monitoring set to %d ms, validate %s, with %d target(s):",
++ arp_interval,
++ arp_validate_tbl[arp_validate_value].modename,
++ arp_ip_count);
+
+ for (i = 0; i < arp_ip_count; i++)
+ printk (" %s", arp_ip_target[i]);
+@@ -4516,6 +4675,7 @@ static int bond_check_params(struct bond
+ params->xmit_policy = xmit_hashtype;
+ params->miimon = miimon;
+ params->arp_interval = arp_interval;
++ params->arp_validate = arp_validate_value;
+ params->updelay = updelay;
+ params->downdelay = downdelay;
+ params->use_carrier = use_carrier;
+diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
+index cfe4dc3..ced9ed8 100644
+--- a/drivers/net/bonding/bond_sysfs.c
++++ b/drivers/net/bonding/bond_sysfs.c
+@@ -51,6 +51,7 @@ extern struct bond_params bonding_defaul
+ extern struct bond_parm_tbl bond_mode_tbl[];
+ extern struct bond_parm_tbl bond_lacp_tbl[];
+ extern struct bond_parm_tbl xmit_hashtype_tbl[];
++extern struct bond_parm_tbl arp_validate_tbl[];
+
+ static int expected_refcount = -1;
+ static struct class *netdev_class;
+@@ -503,6 +504,53 @@ out:
+ static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
+
+ /*
++ * Show and set arp_validate.
++ */
++static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
++{
++ struct bonding *bond = to_bond(cd);
++
++ return sprintf(buf, "%s %d\n",
++ arp_validate_tbl[bond->params.arp_validate].modename,
++ bond->params.arp_validate) + 1;
++}
++
++static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
++{
++ int new_value;
++ struct bonding *bond = to_bond(cd);
++
++ new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
++ if (new_value < 0) {
++ printk(KERN_ERR DRV_NAME
++ ": %s: Ignoring invalid arp_validate value %s\n",
++ bond->dev->name, buf);
++ return -EINVAL;
++ }
++ if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
++ printk(KERN_ERR DRV_NAME
++ ": %s: arp_validate only supported in active-backup mode.\n",
++ bond->dev->name);
++ return -EINVAL;
++ }
++ printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n",
++ bond->dev->name, arp_validate_tbl[new_value].modename,
++ new_value);
++
++ if (!bond->params.arp_validate && new_value) {
++ bond_register_arp(bond);
++ } else if (bond->params.arp_validate && !new_value) {
++ bond_unregister_arp(bond);
++ }
++
++ bond->params.arp_validate = new_value;
++
++ return count;
++}
++
++static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
++
++/*
+ * Show and set the arp timer interval. There are two tricky bits
+ * here. First, if ARP monitoring is activated, then we must disable
+ * MII monitoring. Second, if the ARP timer isn't running, we must
+@@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(stru
+ "ARP monitoring. Disabling ARP monitoring...\n",
+ bond->dev->name);
+ bond->params.arp_interval = 0;
++ if (bond->params.arp_validate) {
++ bond_unregister_arp(bond);
++ bond->params.arp_validate =
++ BOND_ARP_VALIDATE_NONE;
++ }
+ /* Kill ARP timer, else it brings bond's link down */
+ if (bond->mii_timer.function) {
+ printk(KERN_INFO DRV_NAME
+@@ -1093,7 +1146,7 @@ static ssize_t bonding_store_active_slav
+ strlen(slave->dev->name)) == 0) {
+ old_active = bond->curr_active_slave;
+ new_active = slave;
+- if (new_active && (new_active == old_active)) {
++ if (new_active == old_active) {
+ /* do nothing */
+ printk(KERN_INFO DRV_NAME
+ ": %s: %s is already the current active slave.\n",
+@@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac,
+ static struct attribute *per_bond_attrs[] = {
+ &class_device_attr_slaves.attr,
+ &class_device_attr_mode.attr,
++ &class_device_attr_arp_validate.attr,
+ &class_device_attr_arp_interval.attr,
+ &class_device_attr_arp_ip_target.attr,
+ &class_device_attr_downdelay.attr,
+diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
+index 0bdfe2c..dc434fb 100644
+--- a/drivers/net/bonding/bonding.h
++++ b/drivers/net/bonding/bonding.h
+@@ -22,8 +22,8 @@
+ #include "bond_3ad.h"
+ #include "bond_alb.h"
+
+-#define DRV_VERSION "3.0.3"
+-#define DRV_RELDATE "March 23, 2006"
++#define DRV_VERSION "3.1.1"
++#define DRV_RELDATE "September 26, 2006"
+ #define DRV_NAME "bonding"
+ #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
+
+@@ -126,6 +126,7 @@ struct bond_params {
+ int xmit_policy;
+ int miimon;
+ int arp_interval;
++ int arp_validate;
+ int use_carrier;
+ int updelay;
+ int downdelay;
+@@ -149,8 +150,9 @@ struct slave {
+ struct net_device *dev; /* first - useful for panic debug */
+ struct slave *next;
+ struct slave *prev;
+- s16 delay;
++ int delay;
+ u32 jiffies;
++ u32 last_arp_rx;
+ s8 link; /* one of BOND_LINK_XXXX */
+ s8 state; /* one of BOND_STATE_XXXX */
+ u32 original_flags;
+@@ -198,6 +200,7 @@ struct bonding {
+ struct bond_params params;
+ struct list_head vlan_list;
+ struct vlan_group *vlgrp;
++ struct packet_type arp_mon_pt;
+ };
+
+ /**
+@@ -228,6 +231,25 @@ static inline struct bonding *bond_get_b
+ return (struct bonding *)slave->dev->master->priv;
+ }
+
++#define BOND_ARP_VALIDATE_NONE 0
++#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
++#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
++#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
++ BOND_ARP_VALIDATE_BACKUP)
++
++extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
++{
++ return bond->params.arp_validate & (1 << slave->state);
++}
++
++extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave)
++{
++ if (slave_do_arp_validate(bond, slave))
++ return slave->last_arp_rx;
++
++ return slave->dev->last_rx;
++}
++
+ static inline void bond_set_slave_inactive_flags(struct slave *slave)
+ {
+ struct bonding *bond = slave->dev->master->priv;
+@@ -235,12 +257,14 @@ static inline void bond_set_slave_inacti
+ bond->params.mode != BOND_MODE_ALB)
+ slave->state = BOND_STATE_BACKUP;
+ slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
++ if (slave_do_arp_validate(bond, slave))
++ slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
+ }
+
+ static inline void bond_set_slave_active_flags(struct slave *slave)
+ {
+ slave->state = BOND_STATE_ACTIVE;
+- slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
++ slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP);
+ }
+
+ static inline void bond_set_master_3ad_flags(struct bonding *bond)
+@@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, stru
+ const char *bond_mode_name(int mode);
+ void bond_select_active_slave(struct bonding *bond);
+ void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
++void bond_register_arp(struct bonding *);
++void bond_unregister_arp(struct bonding *);
+
+ #endif /* _LINUX_BONDING_H */
+
+diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
+index fb4098e..bae1de1 100644
+--- a/drivers/net/bsd_comp.c
++++ b/drivers/net/bsd_comp.c
+@@ -1,5 +1,5 @@
+ /*
+- * Update: The Berkeley copyright was changed, and the change
++ * Update: The Berkeley copyright was changed, and the change
+ * is retroactive to all "true" BSD software (ie everything
+ * from UCB as opposed to other peoples code that just carried
+ * the same license). The new copyright doesn't clash with the
+@@ -256,9 +256,9 @@ static int bsd_check (struct bsd_db *db)
+ db->in_count -= (db->in_count >> 2);
+ db->bytes_out -= (db->bytes_out >> 2);
+ }
+-
++
+ db->checkpoint = db->in_count + CHECK_GAP;
+-
++
+ if (db->max_ent >= db->maxmaxcode)
+ {
+ /* Reset the dictionary only if the ratio is worse,
+@@ -274,7 +274,7 @@ static int bsd_check (struct bsd_db *db)
+ {
+ new_ratio /= db->bytes_out;
+ }
+-
++
+ if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
+ {
+ bsd_clear (db);
+@@ -293,7 +293,7 @@ static int bsd_check (struct bsd_db *db)
+ static void bsd_comp_stats (void *state, struct compstat *stats)
+ {
+ struct bsd_db *db = (struct bsd_db *) state;
+-
++
+ stats->unc_bytes = db->uncomp_bytes;
+ stats->unc_packets = db->uncomp_count;
+ stats->comp_bytes = db->comp_bytes;
+@@ -325,7 +325,7 @@ static void bsd_reset (void *state)
+ static void bsd_free (void *state)
+ {
+ struct bsd_db *db = state;
+-
++
+ if (!db)
+ return;
+
+@@ -468,7 +468,7 @@ static int bsd_init (void *state, unsign
+ {
+ struct bsd_db *db = state;
+ int indx;
+-
++
+ if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3)
+ || (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+ || (BSD_NBITS(options[2]) != db->maxbits)
+@@ -500,9 +500,9 @@ static int bsd_init (void *state, unsign
+ if (debug)
+ #endif
+ db->debug = 1;
+-
++
+ bsd_reset(db);
+-
++
+ return 1;
+ }
+
+@@ -660,7 +660,7 @@ static int bsd_compress (void *state, un
+ fcode = BSD_KEY (ent, c);
+ hval = BSD_HASH (ent, c, hshift);
+ dictp = dict_ptr (db, hval);
+-
++
+ /* Validate and then check the entry. */
+ if (dictp->codem1 >= max_ent)
+ {
+@@ -672,7 +672,7 @@ static int bsd_compress (void *state, un
+ ent = dictp->codem1 + 1;
+ continue; /* found (prefix,suffix) */
+ }
+-
++
+ /* continue probing until a match or invalid entry */
+ disp = (hval == 0) ? 1 : hval;
+
+@@ -693,10 +693,10 @@ static int bsd_compress (void *state, un
+
+ ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
+ continue;
+-
++
+ nomatch:
+ OUTPUT(ent); /* output the prefix */
+-
++
+ /* code -> hashtable */
+ if (max_ent < db->maxmaxcode)
+ {
+@@ -710,7 +710,7 @@ nomatch:
+ db->n_bits = ++n_bits;
+ mxcode = MAXCODE (n_bits);
+ }
+-
++
+ /* Invalidate old hash table entry using
+ * this code, and then take it over.
+ */
+@@ -738,7 +738,7 @@ nomatch:
+ }
+ ent = c;
+ }
+-
++
+ OUTPUT(ent); /* output the last code */
+
+ db->bytes_out += olen - PPP_HDRLEN - BSD_OVHD;
+@@ -760,7 +760,7 @@ nomatch:
+ {
+ OUTPUT (CLEAR);
+ }
+-
++
+ /*
+ * Pad dribble bits of last code with ones.
+ * Do not emit a completely useless byte of ones.
+@@ -770,7 +770,7 @@ nomatch:
+ {
+ PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
+ }
+-
++
+ /*
+ * Increase code size if we would have without the packet
+ * boundary because the decompressor will do so.
+@@ -856,7 +856,7 @@ static int bsd_decompress (void *state,
+ bitno = 32; /* 1st valid bit in accm */
+ n_bits = db->n_bits;
+ tgtbitno = 32 - n_bits; /* bitno when we have a code */
+-
++
+ /*
+ * Save the address/control from the PPP header
+ * and then get the sequence number.
+@@ -869,7 +869,7 @@ static int bsd_decompress (void *state,
+
+ ibuf += (PPP_HDRLEN + 2);
+ ilen = isize - (PPP_HDRLEN + 2);
+-
++
+ /*
+ * Check the sequence number and give up if it differs from
+ * the value we're expecting.
+@@ -897,7 +897,7 @@ static int bsd_decompress (void *state,
+ *wptr++ = adrs;
+ *wptr++ = ctrl;
+ *wptr++ = 0;
+-
++
+ oldcode = CLEAR;
+ explen = 3;
+
+@@ -934,7 +934,7 @@ static int bsd_decompress (void *state,
+ /*
+ * The dictionary must only be cleared at the end of a packet.
+ */
+-
++
+ if (incode == CLEAR)
+ {
+ if (ilen > 0)
+@@ -945,7 +945,7 @@ static int bsd_decompress (void *state,
+ }
+ return DECOMP_FATALERROR; /* probably a bug */
+ }
+-
++
+ bsd_clear(db);
+ break;
+ }
+@@ -962,7 +962,7 @@ static int bsd_decompress (void *state,
+ }
+ return DECOMP_FATALERROR; /* probably a bug */
+ }
+-
++
+ /* Special case for KwKwK string. */
+ if (incode > max_ent)
+ {
+@@ -974,7 +974,7 @@ static int bsd_decompress (void *state,
+ finchar = incode;
+ extra = 0;
+ }
+-
++
+ codelen = *(lens_ptr (db, finchar));
+ explen += codelen + extra;
+ if (explen > osize)
+@@ -989,7 +989,7 @@ static int bsd_decompress (void *state,
+ }
+ return DECOMP_FATALERROR;
+ }
+-
++
+ /*
+ * Decode this code and install it in the decompressed buffer.
+ */
+@@ -999,7 +999,7 @@ static int bsd_decompress (void *state,
+ while (finchar > LAST)
+ {
+ struct bsd_dict *dictp2 = dict_ptr (db, finchar);
+-
++
+ dictp = dict_ptr (db, dictp2->cptr);
+ #ifdef DEBUG
+ if (--codelen <= 0 || dictp->codem1 != finchar-1)
+@@ -1029,7 +1029,7 @@ static int bsd_decompress (void *state,
+ finchar = dictp->f.hs.prefix;
+ }
+ *--p = finchar;
+-
++
+ #ifdef DEBUG
+ if (--codelen != 0)
+ {
+@@ -1037,12 +1037,12 @@ static int bsd_decompress (void *state,
+ db->unit, codelen, incode, max_ent);
+ }
+ #endif
+-
++
+ if (extra) /* the KwKwK case again */
+ {
+ *wptr++ = finchar;
+ }
+-
++
+ /*
+ * If not first code in a packet, and
+ * if not out of code space, then allocate a new code.
+@@ -1057,11 +1057,11 @@ static int bsd_decompress (void *state,
+ unsigned short *lens1, *lens2;
+ unsigned long fcode;
+ int hval, disp, indx;
+-
++
+ fcode = BSD_KEY(oldcode,finchar);
+ hval = BSD_HASH(oldcode,finchar,db->hshift);
+ dictp = dict_ptr (db, hval);
+-
++
+ /* look for a free hash table entry */
+ if (dictp->codem1 < max_ent)
+ {
+@@ -1077,7 +1077,7 @@ static int bsd_decompress (void *state,
+ }
+ while (dictp->codem1 < max_ent);
+ }
+-
++
+ /*
+ * Invalidate previous hash table entry
+ * assigned this code, and then take it over
+@@ -1101,7 +1101,7 @@ static int bsd_decompress (void *state,
+ lens1 = lens_ptr (db, max_ent);
+ lens2 = lens_ptr (db, oldcode);
+ *lens1 = *lens2 + 1;
+-
++
+ /* Expand code size if needed. */
+ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+ {
+@@ -1127,7 +1127,7 @@ static int bsd_decompress (void *state,
+ }
+ return explen;
+ }
+-
++
+ /*************************************************************
+ * Table of addresses for the BSD compression module
+ *************************************************************/
+diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
+index a31544c..521c5b7 100644
+--- a/drivers/net/cassini.c
++++ b/drivers/net/cassini.c
+@@ -43,7 +43,7 @@
+ * -- on page reclamation, the driver swaps the page with a spare page.
+ * if that page is still in use, it frees its reference to that page,
+ * and allocates a new page for use. otherwise, it just recycles the
+- * the page.
++ * the page.
+ *
+ * NOTE: cassini can parse the header. however, it's not worth it
+ * as long as the network stack requires a header copy.
+@@ -60,10 +60,10 @@
+ * interrupts, but the INT# assignment needs to be set up properly by
+ * the BIOS and conveyed to the driver. PCI BIOSes don't know how to do
+ * that. also, the two descriptor rings are designed to distinguish between
+- * encrypted and non-encrypted packets, but we use them for buffering
++ * encrypted and non-encrypted packets, but we use them for buffering
+ * instead.
+ *
+- * by default, the selective clear mask is set up to process rx packets.
++ * by default, the selective clear mask is set up to process rx packets.
+ */
+
+
+@@ -112,7 +112,7 @@
+ #endif
+
+ /* select which firmware to use */
+-#define USE_HP_WORKAROUND
++#define USE_HP_WORKAROUND
+ #define HP_WORKAROUND_DEFAULT /* select which firmware to use as default */
+ #define CAS_HP_ALT_FIRMWARE cas_prog_null /* alternate firmware */
+
+@@ -168,7 +168,7 @@
+ #define STOP_TRIES_PHY 1000
+ #define STOP_TRIES 5000
+
+-/* specify a minimum frame size to deal with some fifo issues
++/* specify a minimum frame size to deal with some fifo issues
+ * max mtu == 2 * page size - ethernet header - 64 - swivel =
+ * 2 * page_size - 0x50
+ */
+@@ -207,7 +207,7 @@ MODULE_PARM_DESC(link_mode, "default lin
+ * being confused and never showing a link status of "up."
+ */
+ #define DEFAULT_LINKDOWN_TIMEOUT 5
+-/*
++/*
+ * Value in seconds, for user input.
+ */
+ static int linkdown_timeout = DEFAULT_LINKDOWN_TIMEOUT;
+@@ -249,7 +249,7 @@ static inline void cas_lock_tx(struct ca
+ {
+ int i;
+
+- for (i = 0; i < N_TX_RINGS; i++)
++ for (i = 0; i < N_TX_RINGS; i++)
+ spin_lock(&cp->tx_lock[i]);
+ }
+
+@@ -278,8 +278,8 @@ static inline void cas_unlock_tx(struct
+ {
+ int i;
+
+- for (i = N_TX_RINGS; i > 0; i--)
+- spin_unlock(&cp->tx_lock[i - 1]);
++ for (i = N_TX_RINGS; i > 0; i--)
++ spin_unlock(&cp->tx_lock[i - 1]);
+ }
+
+ static inline void cas_unlock_all(struct cas *cp)
+@@ -316,7 +316,7 @@ static void cas_disable_irq(struct cas *
+ #ifdef USE_PCI_INTD
+ case 3:
+ #endif
+- writel(INTRN_MASK_CLEAR_ALL | INTRN_MASK_RX_EN,
++ writel(INTRN_MASK_CLEAR_ALL | INTRN_MASK_RX_EN,
+ cp->regs + REG_PLUS_INTRN_MASK(ring));
+ break;
+ #endif
+@@ -415,7 +415,7 @@ static inline void cas_entropy_reset(str
+ if ((cp->cas_flags & CAS_FLAG_ENTROPY_DEV) == 0)
+ return;
+
+- writel(BIM_LOCAL_DEV_PAD | BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_EXT,
++ writel(BIM_LOCAL_DEV_PAD | BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_EXT,
+ cp->regs + REG_BIM_LOCAL_DEV_EN);
+ writeb(ENTROPY_RESET_STC_MODE, cp->regs + REG_ENTROPY_RESET);
+ writeb(0x55, cp->regs + REG_ENTROPY_RAND_REG);
+@@ -426,7 +426,7 @@ static inline void cas_entropy_reset(str
+ #endif
+ }
+
+-/* access to the phy. the following assumes that we've initialized the MIF to
++/* access to the phy. the following assumes that we've initialized the MIF to
+ * be in frame rather than bit-bang mode
+ */
+ static u16 cas_phy_read(struct cas *cp, int reg)
+@@ -439,7 +439,7 @@ static u16 cas_phy_read(struct cas *cp,
+ cmd |= CAS_BASE(MIF_FRAME_REG_ADDR, reg);
+ cmd |= MIF_FRAME_TURN_AROUND_MSB;
+ writel(cmd, cp->regs + REG_MIF_FRAME);
+-
++
+ /* poll for completion */
+ while (limit-- > 0) {
+ udelay(10);
+@@ -461,7 +461,7 @@ static int cas_phy_write(struct cas *cp,
+ cmd |= MIF_FRAME_TURN_AROUND_MSB;
+ cmd |= val & MIF_FRAME_DATA_MASK;
+ writel(cmd, cp->regs + REG_MIF_FRAME);
+-
++
+ /* poll for completion */
+ while (limit-- > 0) {
+ udelay(10);
+@@ -474,7 +474,7 @@ static int cas_phy_write(struct cas *cp,
+
+ static void cas_phy_powerup(struct cas *cp)
+ {
+- u16 ctl = cas_phy_read(cp, MII_BMCR);
++ u16 ctl = cas_phy_read(cp, MII_BMCR);
+
+ if ((ctl & BMCR_PDOWN) == 0)
+ return;
+@@ -484,7 +484,7 @@ static void cas_phy_powerup(struct cas *
+
+ static void cas_phy_powerdown(struct cas *cp)
+ {
+- u16 ctl = cas_phy_read(cp, MII_BMCR);
++ u16 ctl = cas_phy_read(cp, MII_BMCR);
+
+ if (ctl & BMCR_PDOWN)
+ return;
+@@ -495,7 +495,7 @@ static void cas_phy_powerdown(struct cas
+ /* cp->lock held. note: the last put_page will free the buffer */
+ static int cas_page_free(struct cas *cp, cas_page_t *page)
+ {
+- pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
++ pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
+ PCI_DMA_FROMDEVICE);
+ cas_buffer_dec(page);
+ __free_pages(page->buffer, cp->page_order);
+@@ -507,7 +507,7 @@ static int cas_page_free(struct cas *cp,
+ #define RX_USED_ADD(x, y) ((x)->used += (y))
+ #define RX_USED_SET(x, y) ((x)->used = (y))
+ #else
+-#define RX_USED_ADD(x, y)
++#define RX_USED_ADD(x, y)
+ #define RX_USED_SET(x, y)
+ #endif
+
+@@ -602,7 +602,7 @@ static void cas_spare_recover(struct cas
+ list_splice(&cp->rx_inuse_list, &list);
+ INIT_LIST_HEAD(&cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+-
++
+ list_for_each_safe(elem, tmp, &list) {
+ cas_page_t *page = list_entry(elem, cas_page_t, list);
+
+@@ -627,7 +627,7 @@ static void cas_spare_recover(struct cas
+ list_splice(&list, &cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+ }
+-
++
+ spin_lock(&cp->rx_spare_lock);
+ needed = cp->rx_spares_needed;
+ spin_unlock(&cp->rx_spare_lock);
+@@ -639,7 +639,7 @@ static void cas_spare_recover(struct cas
+ i = 0;
+ while (i < needed) {
+ cas_page_t *spare = cas_page_alloc(cp, flags);
+- if (!spare)
++ if (!spare)
+ break;
+ list_add(&spare->list, &list);
+ i++;
+@@ -695,12 +695,12 @@ static cas_page_t *cas_page_dequeue(stru
+ static void cas_mif_poll(struct cas *cp, const int enable)
+ {
+ u32 cfg;
+-
+- cfg = readl(cp->regs + REG_MIF_CFG);
++
++ cfg = readl(cp->regs + REG_MIF_CFG);
+ cfg &= (MIF_CFG_MDIO_0 | MIF_CFG_MDIO_1);
+
+ if (cp->phy_type & CAS_PHY_MII_MDIO1)
+- cfg |= MIF_CFG_PHY_SELECT;
++ cfg |= MIF_CFG_PHY_SELECT;
+
+ /* poll and interrupt on link status change. */
+ if (enable) {
+@@ -708,8 +708,8 @@ static void cas_mif_poll(struct cas *cp,
+ cfg |= CAS_BASE(MIF_CFG_POLL_REG, MII_BMSR);
+ cfg |= CAS_BASE(MIF_CFG_POLL_PHY, cp->phy_addr);
+ }
+- writel((enable) ? ~(BMSR_LSTATUS | BMSR_ANEGCOMPLETE) : 0xFFFF,
+- cp->regs + REG_MIF_MASK);
++ writel((enable) ? ~(BMSR_LSTATUS | BMSR_ANEGCOMPLETE) : 0xFFFF,
++ cp->regs + REG_MIF_MASK);
+ writel(cfg, cp->regs + REG_MIF_CFG);
+ }
+
+@@ -759,7 +759,7 @@ start_aneg:
+ /*
+ * WTZ: If the old state was link_up, we turn off the carrier
+ * to replicate everything we do elsewhere on a link-down
+- * event when we were already in a link-up state..
++ * event when we were already in a link-up state..
+ */
+ if (oldstate == link_up)
+ netif_carrier_off(cp->dev);
+@@ -767,7 +767,7 @@ start_aneg:
+ /*
+ * WTZ: This branch will simply schedule a full reset after
+ * we explicitly changed link modes in an ioctl. See if this
+- * fixes the link-problems we were having for forced mode.
++ * fixes the link-problems we were having for forced mode.
+ */
+ atomic_inc(&cp->reset_task_pending);
+ atomic_inc(&cp->reset_task_pending_all);
+@@ -795,7 +795,7 @@ start_aneg:
+ } else {
+ cas_mif_poll(cp, 0);
+ ctl = cas_phy_read(cp, MII_BMCR);
+- ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
++ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
+ CAS_BMCR_SPEED1000 | BMCR_ANENABLE);
+ ctl |= cp->link_cntl;
+ if (ctl & BMCR_ANENABLE) {
+@@ -818,7 +818,7 @@ static int cas_reset_mii_phy(struct cas
+ {
+ int limit = STOP_TRIES_PHY;
+ u16 val;
+-
++
+ cas_phy_write(cp, MII_BMCR, BMCR_RESET);
+ udelay(100);
+ while (limit--) {
+@@ -901,17 +901,17 @@ static void cas_phy_init(struct cas *cp)
+ val = cas_phy_read(cp, BROADCOM_MII_REG4);
+ if (val & 0x0080) {
+ /* link workaround */
+- cas_phy_write(cp, BROADCOM_MII_REG4,
++ cas_phy_write(cp, BROADCOM_MII_REG4,
+ val & ~0x0080);
+ }
+-
++
+ } else if (cp->cas_flags & CAS_FLAG_SATURN) {
+- writel((cp->phy_type & CAS_PHY_MII_MDIO0) ?
+- SATURN_PCFG_FSI : 0x0,
++ writel((cp->phy_type & CAS_PHY_MII_MDIO0) ?
++ SATURN_PCFG_FSI : 0x0,
+ cp->regs + REG_SATURN_PCFG);
+
+ /* load firmware to address 10Mbps auto-negotiation
+- * issue. NOTE: this will need to be changed if the
++ * issue. NOTE: this will need to be changed if the
+ * default firmware gets fixed.
+ */
+ if (PHY_NS_DP83065 == cp->phy_id) {
+@@ -930,9 +930,9 @@ static void cas_phy_init(struct cas *cp)
+ cas_phy_read(cp, MII_ADVERTISE) |
+ (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL |
+- CAS_ADVERTISE_PAUSE |
++ CAS_ADVERTISE_PAUSE |
+ CAS_ADVERTISE_ASYM_PAUSE));
+-
++
+ if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
+ /* make sure that we don't advertise half
+ * duplex to avoid a chip issue
+@@ -963,7 +963,7 @@ static void cas_phy_init(struct cas *cp)
+ limit = STOP_TRIES;
+ while (limit-- > 0) {
+ udelay(10);
+- if ((readl(cp->regs + REG_PCS_MII_CTRL) &
++ if ((readl(cp->regs + REG_PCS_MII_CTRL) &
+ PCS_MII_RESET) == 0)
+ break;
+ }
+@@ -980,7 +980,7 @@ static void cas_phy_init(struct cas *cp)
+ /* Advertise all capabilities except half-duplex. */
+ val = readl(cp->regs + REG_PCS_MII_ADVERT);
+ val &= ~PCS_MII_ADVERT_HD;
+- val |= (PCS_MII_ADVERT_FD | PCS_MII_ADVERT_SYM_PAUSE |
++ val |= (PCS_MII_ADVERT_FD | PCS_MII_ADVERT_SYM_PAUSE |
+ PCS_MII_ADVERT_ASYM_PAUSE);
+ writel(val, cp->regs + REG_PCS_MII_ADVERT);
+
+@@ -1014,7 +1014,7 @@ static int cas_pcs_link_check(struct cas
+ PCS_MII_STATUS_REMOTE_FAULT)) ==
+ (PCS_MII_STATUS_AUTONEG_COMP | PCS_MII_STATUS_REMOTE_FAULT)) {
+ if (netif_msg_link(cp))
+- printk(KERN_INFO "%s: PCS RemoteFault\n",
++ printk(KERN_INFO "%s: PCS RemoteFault\n",
+ cp->dev->name);
+ }
+
+@@ -1033,7 +1033,7 @@ static int cas_pcs_link_check(struct cas
+ if (cp->opened) {
+ cp->lstate = link_up;
+ cp->link_transition = LINK_TRANSITION_LINK_UP;
+-
++
+ cas_set_link_modes(cp);
+ netif_carrier_on(cp->dev);
+ }
+@@ -1044,8 +1044,8 @@ static int cas_pcs_link_check(struct cas
+ cp->link_transition != LINK_TRANSITION_REQUESTED_RESET &&
+ !cp->link_transition_jiffies_valid) {
+ /*
+- * force a reset, as a workaround for the
+- * link-failure problem. May want to move this to a
++ * force a reset, as a workaround for the
++ * link-failure problem. May want to move this to a
+ * point a bit earlier in the sequence. If we had
+ * generated a reset a short time ago, we'll wait for
+ * the link timer to check the status until a
+@@ -1103,17 +1103,17 @@ static int cas_pcs_link_check(struct cas
+ return retval;
+ }
+
+-static int cas_pcs_interrupt(struct net_device *dev,
++static int cas_pcs_interrupt(struct net_device *dev,
+ struct cas *cp, u32 status)
+ {
+ u32 stat = readl(cp->regs + REG_PCS_INTR_STATUS);
+
+- if ((stat & PCS_INTR_STATUS_LINK_CHANGE) == 0)
++ if ((stat & PCS_INTR_STATUS_LINK_CHANGE) == 0)
+ return 0;
+ return cas_pcs_link_check(cp);
+ }
+
+-static int cas_txmac_interrupt(struct net_device *dev,
++static int cas_txmac_interrupt(struct net_device *dev,
+ struct cas *cp, u32 status)
+ {
+ u32 txmac_stat = readl(cp->regs + REG_MAC_TX_STATUS);
+@@ -1168,7 +1168,7 @@ static int cas_txmac_interrupt(struct ne
+ return 0;
+ }
+
+-static void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
++static void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
+ {
+ cas_hp_inst_t *inst;
+ u32 val;
+@@ -1203,12 +1203,12 @@ static void cas_load_firmware(struct cas
+
+ static void cas_init_rx_dma(struct cas *cp)
+ {
+- u64 desc_dma = cp->block_dvma;
++ u64 desc_dma = cp->block_dvma;
+ u32 val;
+ int i, size;
+
+ /* rx free descriptors */
+- val = CAS_BASE(RX_CFG_SWIVEL, RX_SWIVEL_OFF_VAL);
++ val = CAS_BASE(RX_CFG_SWIVEL, RX_SWIVEL_OFF_VAL);
+ val |= CAS_BASE(RX_CFG_DESC_RING, RX_DESC_RINGN_INDEX(0));
+ val |= CAS_BASE(RX_CFG_COMP_RING, RX_COMP_RINGN_INDEX(0));
+ if ((N_RX_DESC_RINGS > 1) &&
+@@ -1216,27 +1216,27 @@ static void cas_init_rx_dma(struct cas *
+ val |= CAS_BASE(RX_CFG_DESC_RING1, RX_DESC_RINGN_INDEX(1));
+ writel(val, cp->regs + REG_RX_CFG);
+
+- val = (unsigned long) cp->init_rxds[0] -
++ val = (unsigned long) cp->init_rxds[0] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs + REG_RX_DB_HI);
+ writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_DB_LOW);
+ writel(RX_DESC_RINGN_SIZE(0) - 4, cp->regs + REG_RX_KICK);
+
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+- /* rx desc 2 is for IPSEC packets. however,
++ /* rx desc 2 is for IPSEC packets. however,
+ * we don't it that for that purpose.
+ */
+- val = (unsigned long) cp->init_rxds[1] -
++ val = (unsigned long) cp->init_rxds[1] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs + REG_PLUS_RX_DB1_HI);
+- writel((desc_dma + val) & 0xffffffff, cp->regs +
++ writel((desc_dma + val) & 0xffffffff, cp->regs +
+ REG_PLUS_RX_DB1_LOW);
+- writel(RX_DESC_RINGN_SIZE(1) - 4, cp->regs +
++ writel(RX_DESC_RINGN_SIZE(1) - 4, cp->regs +
+ REG_PLUS_RX_KICK1);
+ }
+-
++
+ /* rx completion registers */
+- val = (unsigned long) cp->init_rxcs[0] -
++ val = (unsigned long) cp->init_rxcs[0] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs + REG_RX_CB_HI);
+ writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_CB_LOW);
+@@ -1244,11 +1244,11 @@ static void cas_init_rx_dma(struct cas *
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ /* rx comp 2-4 */
+ for (i = 1; i < MAX_RX_COMP_RINGS; i++) {
+- val = (unsigned long) cp->init_rxcs[i] -
++ val = (unsigned long) cp->init_rxcs[i] -
+ (unsigned long) cp->init_block;
+- writel((desc_dma + val) >> 32, cp->regs +
++ writel((desc_dma + val) >> 32, cp->regs +
+ REG_PLUS_RX_CBN_HI(i));
+- writel((desc_dma + val) & 0xffffffff, cp->regs +
++ writel((desc_dma + val) & 0xffffffff, cp->regs +
+ REG_PLUS_RX_CBN_LOW(i));
+ }
+ }
+@@ -1265,21 +1265,21 @@ static void cas_init_rx_dma(struct cas *
+
+ /* 2 is different from 3 and 4 */
+ if (N_RX_COMP_RINGS > 1)
+- writel(INTR_RX_DONE_ALT | INTR_RX_BUF_UNAVAIL_1,
++ writel(INTR_RX_DONE_ALT | INTR_RX_BUF_UNAVAIL_1,
+ cp->regs + REG_PLUS_ALIASN_CLEAR(1));
+
+- for (i = 2; i < N_RX_COMP_RINGS; i++)
+- writel(INTR_RX_DONE_ALT,
++ for (i = 2; i < N_RX_COMP_RINGS; i++)
++ writel(INTR_RX_DONE_ALT,
+ cp->regs + REG_PLUS_ALIASN_CLEAR(i));
+ }
+
+ /* set up pause thresholds */
+ val = CAS_BASE(RX_PAUSE_THRESH_OFF,
+ cp->rx_pause_off / RX_PAUSE_THRESH_QUANTUM);
+- val |= CAS_BASE(RX_PAUSE_THRESH_ON,
++ val |= CAS_BASE(RX_PAUSE_THRESH_ON,
+ cp->rx_pause_on / RX_PAUSE_THRESH_QUANTUM);
+ writel(val, cp->regs + REG_RX_PAUSE_THRESH);
+-
++
+ /* zero out dma reassembly buffers */
+ for (i = 0; i < 64; i++) {
+ writel(i, cp->regs + REG_RX_TABLE_ADDR);
+@@ -1318,7 +1318,7 @@ static void cas_init_rx_dma(struct cas *
+ * this should be tunable.
+ */
+ writel(0x0, cp->regs + REG_RX_RED);
+-
++
+ /* receive page sizes. default == 2K (0x800) */
+ val = 0;
+ if (cp->page_size == 0x1000)
+@@ -1327,7 +1327,7 @@ static void cas_init_rx_dma(struct cas *
+ val = 0x2;
+ else if (cp->page_size == 0x4000)
+ val = 0x3;
+-
++
+ /* round mtu + offset. constrain to page size. */
+ size = cp->dev->mtu + 64;
+ if (size > cp->page_size)
+@@ -1344,11 +1344,11 @@ static void cas_init_rx_dma(struct cas *
+
+ cp->mtu_stride = 1 << (i + 10);
+ val = CAS_BASE(RX_PAGE_SIZE, val);
+- val |= CAS_BASE(RX_PAGE_SIZE_MTU_STRIDE, i);
++ val |= CAS_BASE(RX_PAGE_SIZE_MTU_STRIDE, i);
+ val |= CAS_BASE(RX_PAGE_SIZE_MTU_COUNT, cp->page_size >> (i + 10));
+ val |= CAS_BASE(RX_PAGE_SIZE_MTU_OFF, 0x1);
+ writel(val, cp->regs + REG_RX_PAGE_SIZE);
+-
++
+ /* enable the header parser if desired */
+ if (CAS_HP_FIRMWARE == cas_prog_null)
+ return;
+@@ -1362,7 +1362,7 @@ static void cas_init_rx_dma(struct cas *
+ static inline void cas_rxc_init(struct cas_rx_comp *rxc)
+ {
+ memset(rxc, 0, sizeof(*rxc));
+- rxc->word4 = cpu_to_le64(RX_COMP4_ZERO);
++ rxc->word4 = cpu_to_le64(RX_COMP4_ZERO);
+ }
+
+ /* NOTE: we use the ENC RX DESC ring for spares. the rx_page[0,1]
+@@ -1385,9 +1385,9 @@ static inline cas_page_t *cas_page_spare
+ }
+ return new;
+ }
+-
++
+ /* this needs to be changed if we actually use the ENC RX DESC ring */
+-static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
++static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
+ const int index)
+ {
+ cas_page_t **page0 = cp->rx_pages[0];
+@@ -1400,7 +1400,7 @@ static cas_page_t *cas_page_swap(struct
+ page1[index] = page0[index];
+ page0[index] = new;
+ }
+- }
++ }
+ RX_USED_SET(page0[index], 0);
+ return page0[index];
+ }
+@@ -1424,11 +1424,11 @@ static void cas_clean_rxds(struct cas *c
+ for (i = 0; i < size; i++) {
+ cas_page_t *page = cas_page_swap(cp, 0, i);
+ rxd[i].buffer = cpu_to_le64(page->dma_addr);
+- rxd[i].index = cpu_to_le64(CAS_BASE(RX_INDEX_NUM, i) |
++ rxd[i].index = cpu_to_le64(CAS_BASE(RX_INDEX_NUM, i) |
+ CAS_BASE(RX_INDEX_RING, 0));
+ }
+
+- cp->rx_old[0] = RX_DESC_RINGN_SIZE(0) - 4;
++ cp->rx_old[0] = RX_DESC_RINGN_SIZE(0) - 4;
+ cp->rx_last[0] = 0;
+ cp->cas_flags &= ~CAS_FLAG_RXD_POST(0);
+ }
+@@ -1533,7 +1533,7 @@ static int cas_rxmac_interrupt(struct ne
+
+ /* these are all rollovers */
+ spin_lock(&cp->stat_lock[0]);
+- if (stat & MAC_RX_ALIGN_ERR)
++ if (stat & MAC_RX_ALIGN_ERR)
+ cp->net_stats[0].rx_frame_errors += 0x10000;
+
+ if (stat & MAC_RX_CRC_ERR)
+@@ -1579,12 +1579,12 @@ static int cas_mac_interrupt(struct net_
+ return 0;
+ }
+
+-
++
+ /* Must be invoked under cp->lock. */
+ static inline int cas_mdio_link_not_up(struct cas *cp)
+ {
+ u16 val;
+-
++
+ switch (cp->lstate) {
+ case link_force_ret:
+ if (netif_msg_link(cp))
+@@ -1595,7 +1595,7 @@ static inline int cas_mdio_link_not_up(s
+ cp->lstate = link_force_ok;
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+ break;
+-
++
+ case link_aneg:
+ val = cas_phy_read(cp, MII_BMCR);
+
+@@ -1604,7 +1604,7 @@ static inline int cas_mdio_link_not_up(s
+ */
+ val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+ val |= BMCR_FULLDPLX;
+- val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
++ val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
+ CAS_BMCR_SPEED1000 : BMCR_SPEED100;
+ cas_phy_write(cp, MII_BMCR, val);
+ cp->timer_ticks = 5;
+@@ -1646,11 +1646,11 @@ static int cas_mii_link_check(struct cas
+
+ if (bmsr & BMSR_LSTATUS) {
+ /* Ok, here we got a link. If we had it due to a forced
+- * fallback, and we were configured for autoneg, we
++ * fallback, and we were configured for autoneg, we
+ * retry a short autoneg pass. If you know your hub is
+ * broken, use ethtool ;)
+ */
+- if ((cp->lstate == link_force_try) &&
++ if ((cp->lstate == link_force_try) &&
+ (cp->link_cntl & BMCR_ANENABLE)) {
+ cp->lstate = link_force_ret;
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+@@ -1690,10 +1690,10 @@ static int cas_mii_link_check(struct cas
+ printk(KERN_INFO "%s: Link down\n",
+ cp->dev->name);
+ restart = 1;
+-
++
+ } else if (++cp->timer_ticks > 10)
+ cas_mdio_link_not_up(cp);
+-
++
+ return restart;
+ }
+
+@@ -1908,7 +1908,7 @@ static inline void cas_tx_ringN(struct c
+
+ skbs[entry] = NULL;
+ cp->tx_tiny_use[ring][entry].nbufs = 0;
+-
++
+ for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+ struct cas_tx_desc *txd = txds + entry;
+
+@@ -1923,7 +1923,7 @@ static inline void cas_tx_ringN(struct c
+ if (cp->tx_tiny_use[ring][entry].used) {
+ cp->tx_tiny_use[ring][entry].used = 0;
+ entry = TX_DESC_NEXT(ring, entry);
+- }
++ }
+ }
+
+ spin_lock(&cp->stat_lock[ring]);
+@@ -1964,14 +1964,14 @@ static void cas_tx(struct net_device *de
+ #else
+ limit = readl(cp->regs + REG_TX_COMPN(ring));
+ #endif
+- if (cp->tx_old[ring] != limit)
++ if (cp->tx_old[ring] != limit)
+ cas_tx_ringN(cp, ring, limit);
+ }
+ }
+
+
+-static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
+- int entry, const u64 *words,
++static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
++ int entry, const u64 *words,
+ struct sk_buff **skbref)
+ {
+ int dlen, hlen, len, i, alloclen;
+@@ -1979,19 +1979,19 @@ static int cas_rx_process_pkt(struct cas
+ struct cas_page *page;
+ struct sk_buff *skb;
+ void *addr, *crcaddr;
+- char *p;
++ char *p;
+
+ hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
+ dlen = CAS_VAL(RX_COMP1_DATA_SIZE, words[0]);
+ len = hlen + dlen;
+
+- if (RX_COPY_ALWAYS || (words[2] & RX_COMP3_SMALL_PKT))
++ if (RX_COPY_ALWAYS || (words[2] & RX_COMP3_SMALL_PKT))
+ alloclen = len;
+- else
++ else
+ alloclen = max(hlen, RX_COPY_MIN);
+
+ skb = dev_alloc_skb(alloclen + swivel + cp->crc_size);
+- if (skb == NULL)
++ if (skb == NULL)
+ return -1;
+
+ *skbref = skb;
+@@ -2003,7 +2003,7 @@ static int cas_rx_process_pkt(struct cas
+ if (hlen) { /* always copy header pages */
+ i = CAS_VAL(RX_COMP2_HDR_INDEX, words[1]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+- off = CAS_VAL(RX_COMP2_HDR_OFF, words[1]) * 0x100 +
++ off = CAS_VAL(RX_COMP2_HDR_OFF, words[1]) * 0x100 +
+ swivel;
+
+ i = hlen;
+@@ -2019,7 +2019,7 @@ static int cas_rx_process_pkt(struct cas
+ RX_USED_ADD(page, 0x100);
+ p += hlen;
+ swivel = 0;
+- }
++ }
+
+
+ if (alloclen < (hlen + dlen)) {
+@@ -2070,7 +2070,7 @@ static int cas_rx_process_pkt(struct cas
+ frag->page = page->buffer;
+ frag->page_offset = off;
+ frag->size = hlen - swivel;
+-
++
+ /* any more data? */
+ if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
+ hlen = dlen;
+@@ -2078,8 +2078,8 @@ static int cas_rx_process_pkt(struct cas
+
+ i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+- pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
+- hlen + cp->crc_size,
++ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
++ hlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+ pci_dma_sync_single_for_device(cp->pdev, page->dma_addr,
+ hlen + cp->crc_size,
+@@ -2087,7 +2087,7 @@ static int cas_rx_process_pkt(struct cas
+
+ skb_shinfo(skb)->nr_frags++;
+ skb->data_len += hlen;
+- skb->len += hlen;
++ skb->len += hlen;
+ frag++;
+
+ get_page(page->buffer);
+@@ -2134,14 +2134,14 @@ static int cas_rx_process_pkt(struct cas
+ RX_USED_ADD(page, cp->mtu_stride);
+ else
+ RX_USED_ADD(page, i);
+-
++
+ /* any more data? */
+ if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
+ p += hlen;
+ i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+- pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
+- dlen + cp->crc_size,
++ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
++ dlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+ addr = cas_page_map(page->buffer);
+ memcpy(p, addr, dlen + cp->crc_size);
+@@ -2149,7 +2149,7 @@ static int cas_rx_process_pkt(struct cas
+ dlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+ cas_page_unmap(addr);
+- RX_USED_ADD(page, dlen + cp->crc_size);
++ RX_USED_ADD(page, dlen + cp->crc_size);
+ }
+ end_copy_pkt:
+ if (cp->crc_size) {
+@@ -2167,14 +2167,14 @@ end_copy_pkt:
+ cas_page_unmap(addr);
+ }
+ skb->csum = ntohs(i ^ 0xffff);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->protocol = eth_type_trans(skb, cp->dev);
+ return len;
+ }
+
+
+ /* we can handle up to 64 rx flows at a time. we do the same thing
+- * as nonreassm except that we batch up the buffers.
++ * as nonreassm except that we batch up the buffers.
+ * NOTE: we currently just treat each flow as a bunch of packets that
+ * we pass up. a better way would be to coalesce the packets
+ * into a jumbo packet. to do that, we need to do the following:
+@@ -2184,7 +2184,7 @@ end_copy_pkt:
+ * data length and merge the checksums.
+ * 3) on flow release, fix up the header.
+ * 4) make sure the higher layer doesn't care.
+- * because packets get coalesced, we shouldn't run into fragment count
++ * because packets get coalesced, we shouldn't run into fragment count
+ * issues.
+ */
+ static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words,
+@@ -2192,8 +2192,8 @@ static inline void cas_rx_flow_pkt(struc
+ {
+ int flowid = CAS_VAL(RX_COMP3_FLOWID, words[2]) & (N_RX_FLOWS - 1);
+ struct sk_buff_head *flow = &cp->rx_flows[flowid];
+-
+- /* this is protected at a higher layer, so no need to
++
++ /* this is protected at a higher layer, so no need to
+ * do any additional locking here. stick the buffer
+ * at the end.
+ */
+@@ -2218,19 +2218,19 @@ static void cas_post_page(struct cas *cp
+ new = cas_page_swap(cp, ring, index);
+ cp->init_rxds[ring][entry].buffer = cpu_to_le64(new->dma_addr);
+ cp->init_rxds[ring][entry].index =
+- cpu_to_le64(CAS_BASE(RX_INDEX_NUM, index) |
++ cpu_to_le64(CAS_BASE(RX_INDEX_NUM, index) |
+ CAS_BASE(RX_INDEX_RING, ring));
+
+ entry = RX_DESC_ENTRY(ring, entry + 1);
+ cp->rx_old[ring] = entry;
+-
++
+ if (entry % 4)
+ return;
+
+ if (ring == 0)
+ writel(entry, cp->regs + REG_RX_KICK);
+ else if ((N_RX_DESC_RINGS > 1) &&
+- (cp->cas_flags & CAS_FLAG_REG_PLUS))
++ (cp->cas_flags & CAS_FLAG_REG_PLUS))
+ writel(entry, cp->regs + REG_PLUS_RX_KICK1);
+ }
+
+@@ -2249,7 +2249,7 @@ static int cas_post_rxds_ringN(struct ca
+ cp->dev->name, ring, entry);
+
+ cluster = -1;
+- count = entry & 0x3;
++ count = entry & 0x3;
+ last = RX_DESC_ENTRY(ring, num ? entry + num - 4: entry - 4);
+ released = 0;
+ while (entry != last) {
+@@ -2257,12 +2257,12 @@ static int cas_post_rxds_ringN(struct ca
+ if (cas_buffer_count(page[entry]) > 1) {
+ cas_page_t *new = cas_page_dequeue(cp);
+ if (!new) {
+- /* let the timer know that we need to
++ /* let the timer know that we need to
+ * do this again
+ */
+ cp->cas_flags |= CAS_FLAG_RXD_POST(ring);
+ if (!timer_pending(&cp->link_timer))
+- mod_timer(&cp->link_timer, jiffies +
++ mod_timer(&cp->link_timer, jiffies +
+ CAS_LINK_FAST_TIMEOUT);
+ cp->rx_old[ring] = entry;
+ cp->rx_last[ring] = num ? num - released : 0;
+@@ -2271,10 +2271,10 @@ static int cas_post_rxds_ringN(struct ca
+ spin_lock(&cp->rx_inuse_lock);
+ list_add(&page[entry]->list, &cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+- cp->init_rxds[ring][entry].buffer =
++ cp->init_rxds[ring][entry].buffer =
+ cpu_to_le64(new->dma_addr);
+ page[entry] = new;
+-
++
+ }
+
+ if (++count == 4) {
+@@ -2286,13 +2286,13 @@ static int cas_post_rxds_ringN(struct ca
+ }
+ cp->rx_old[ring] = entry;
+
+- if (cluster < 0)
++ if (cluster < 0)
+ return 0;
+
+ if (ring == 0)
+ writel(cluster, cp->regs + REG_RX_KICK);
+ else if ((N_RX_DESC_RINGS > 1) &&
+- (cp->cas_flags & CAS_FLAG_REG_PLUS))
++ (cp->cas_flags & CAS_FLAG_REG_PLUS))
+ writel(cluster, cp->regs + REG_PLUS_RX_KICK1);
+ return 0;
+ }
+@@ -2301,14 +2301,14 @@ static int cas_post_rxds_ringN(struct ca
+ /* process a completion ring. packets are set up in three basic ways:
+ * small packets: should be copied header + data in single buffer.
+ * large packets: header and data in a single buffer.
+- * split packets: header in a separate buffer from data.
++ * split packets: header in a separate buffer from data.
+ * data may be in multiple pages. data may be > 256
+- * bytes but in a single page.
++ * bytes but in a single page.
+ *
+ * NOTE: RX page posting is done in this routine as well. while there's
+ * the capability of using multiple RX completion rings, it isn't
+ * really worthwhile due to the fact that the page posting will
+- * force serialization on the single descriptor ring.
++ * force serialization on the single descriptor ring.
+ */
+ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
+ {
+@@ -2319,7 +2319,7 @@ static int cas_rx_ringN(struct cas *cp,
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: rx[%d] interrupt, done: %d/%d\n",
+ cp->dev->name, ring,
+- readl(cp->regs + REG_RX_COMP_HEAD),
++ readl(cp->regs + REG_RX_COMP_HEAD),
+ cp->rx_new[ring]);
+
+ entry = cp->rx_new[ring];
+@@ -2375,7 +2375,7 @@ static int cas_rx_ringN(struct cas *cp,
+ */
+ if (RX_DONT_BATCH || (type == 0x2)) {
+ /* non-reassm: these always get released */
+- cas_skb_release(skb);
++ cas_skb_release(skb);
+ } else {
+ cas_rx_flow_pkt(cp, words, skb);
+ }
+@@ -2396,7 +2396,7 @@ static int cas_rx_ringN(struct cas *cp,
+ i = CAS_VAL(RX_INDEX_NUM, i);
+ cas_post_page(cp, dring, i);
+ }
+-
++
+ if (words[0] & RX_COMP1_RELEASE_DATA) {
+ i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
+ dring = CAS_VAL(RX_INDEX_RING, i);
+@@ -2412,7 +2412,7 @@ static int cas_rx_ringN(struct cas *cp,
+ }
+
+ /* skip to the next entry */
+- entry = RX_COMP_ENTRY(ring, entry + 1 +
++ entry = RX_COMP_ENTRY(ring, entry + 1 +
+ CAS_VAL(RX_COMP1_SKIP, words[0]));
+ #ifdef USE_NAPI
+ if (budget && (npackets >= budget))
+@@ -2436,12 +2436,12 @@ static void cas_post_rxcs_ringN(struct n
+ int last, entry;
+
+ last = cp->rx_cur[ring];
+- entry = cp->rx_new[ring];
++ entry = cp->rx_new[ring];
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: rxc[%d] interrupt, done: %d/%d\n",
+ dev->name, ring, readl(cp->regs + REG_RX_COMP_HEAD),
+ entry);
+-
++
+ /* zero and re-mark descriptors */
+ while (last != entry) {
+ cas_rxc_init(rxc + last);
+@@ -2451,25 +2451,25 @@ static void cas_post_rxcs_ringN(struct n
+
+ if (ring == 0)
+ writel(last, cp->regs + REG_RX_COMP_TAIL);
+- else if (cp->cas_flags & CAS_FLAG_REG_PLUS)
++ else if (cp->cas_flags & CAS_FLAG_REG_PLUS)
+ writel(last, cp->regs + REG_PLUS_RX_COMPN_TAIL(ring));
+ }
+
+
+
+-/* cassini can use all four PCI interrupts for the completion ring.
++/* cassini can use all four PCI interrupts for the completion ring.
+ * rings 3 and 4 are identical
+ */
+ #if defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
+-static inline void cas_handle_irqN(struct net_device *dev,
++static inline void cas_handle_irqN(struct net_device *dev,
+ struct cas *cp, const u32 status,
+ const int ring)
+ {
+- if (status & (INTR_RX_COMP_FULL_ALT | INTR_RX_COMP_AF_ALT))
++ if (status & (INTR_RX_COMP_FULL_ALT | INTR_RX_COMP_AF_ALT))
+ cas_post_rxcs_ringN(dev, cp, ring);
+ }
+
+-static irqreturn_t cas_interruptN(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cas_interruptN(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct cas *cp = netdev_priv(dev);
+@@ -2505,7 +2505,7 @@ static irqreturn_t cas_interruptN(int ir
+ static inline void cas_handle_irq1(struct cas *cp, const u32 status)
+ {
+ if (status & INTR_RX_BUF_UNAVAIL_1) {
+- /* Frame arrived, no free RX buffers available.
++ /* Frame arrived, no free RX buffers available.
+ * NOTE: we can get this on a link transition. */
+ cas_post_rxds_ringN(cp, 1, 0);
+ spin_lock(&cp->stat_lock[1]);
+@@ -2513,8 +2513,8 @@ static inline void cas_handle_irq1(struc
+ spin_unlock(&cp->stat_lock[1]);
+ }
+
+- if (status & INTR_RX_BUF_AE_1)
+- cas_post_rxds_ringN(cp, 1, RX_DESC_RINGN_SIZE(1) -
++ if (status & INTR_RX_BUF_AE_1)
++ cas_post_rxds_ringN(cp, 1, RX_DESC_RINGN_SIZE(1) -
+ RX_AE_FREEN_VAL(1));
+
+ if (status & (INTR_RX_COMP_AF | INTR_RX_COMP_FULL))
+@@ -2522,7 +2522,7 @@ static inline void cas_handle_irq1(struc
+ }
+
+ /* ring 2 handles a few more events than 3 and 4 */
+-static irqreturn_t cas_interrupt1(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cas_interrupt1(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct cas *cp = netdev_priv(dev);
+@@ -2558,7 +2558,7 @@ static inline void cas_handle_irq(struct
+ cas_abnormal_irq(dev, cp, status);
+
+ if (status & INTR_RX_BUF_UNAVAIL) {
+- /* Frame arrived, no free RX buffers available.
++ /* Frame arrived, no free RX buffers available.
+ * NOTE: we can get this on a link transition.
+ */
+ cas_post_rxds_ringN(cp, 0, 0);
+@@ -2574,7 +2574,7 @@ static inline void cas_handle_irq(struct
+ cas_post_rxcs_ringN(dev, cp, 0);
+ }
+
+-static irqreturn_t cas_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cas_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct cas *cp = netdev_priv(dev);
+@@ -2625,7 +2625,7 @@ static int cas_poll(struct net_device *d
+ todo = min(*budget, dev->quota);
+
+ /* to make sure we're fair with the work we loop through each
+- * ring N_RX_COMP_RING times with a request of
++ * ring N_RX_COMP_RING times with a request of
+ * todo / N_RX_COMP_RINGS
+ */
+ enable_intr = 1;
+@@ -2689,7 +2689,7 @@ static void cas_netpoll(struct net_devic
+ struct cas *cp = netdev_priv(dev);
+
+ cas_disable_irq(cp, 0);
+- cas_interrupt(cp->pdev->irq, dev, NULL);
++ cas_interrupt(cp->pdev->irq, dev);
+ cas_enable_irq(cp, 0);
+
+ #ifdef USE_PCI_INTB
+@@ -2784,13 +2784,13 @@ static void cas_write_txd(struct cas *cp
+ txd->buffer = cpu_to_le64(mapping);
+ }
+
+-static inline void *tx_tiny_buf(struct cas *cp, const int ring,
++static inline void *tx_tiny_buf(struct cas *cp, const int ring,
+ const int entry)
+ {
+ return cp->tx_tiny_bufs[ring] + TX_TINY_BUF_LEN*entry;
+ }
+
+-static inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
++static inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
+ const int entry, const int tentry)
+ {
+ cp->tx_tiny_use[ring][tentry].nbufs++;
+@@ -2798,7 +2798,7 @@ static inline dma_addr_t tx_tiny_map(str
+ return cp->tx_tiny_dvma[ring] + TX_TINY_BUF_LEN*entry;
+ }
+
+-static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
++static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
+ struct sk_buff *skb)
+ {
+ struct net_device *dev = cp->dev;
+@@ -2811,7 +2811,7 @@ static inline int cas_xmit_tx_ringN(stru
+ spin_lock_irqsave(&cp->tx_lock[ring], flags);
+
+ /* This is a hard error, log it. */
+- if (TX_BUFFS_AVAIL(cp, ring) <=
++ if (TX_BUFFS_AVAIL(cp, ring) <=
+ CAS_TABORT(cp)*(skb_shinfo(skb)->nr_frags + 1)) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
+@@ -2821,13 +2821,13 @@ static inline int cas_xmit_tx_ringN(stru
+ }
+
+ ctrl = 0;
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u64 csum_start_off, csum_stuff_off;
+
+ csum_start_off = (u64) (skb->h.raw - skb->data);
+ csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data);
+
+- ctrl = TX_DESC_CSUM_EN |
++ ctrl = TX_DESC_CSUM_EN |
+ CAS_BASE(TX_DESC_CSUM_START, csum_start_off) |
+ CAS_BASE(TX_DESC_CSUM_STUFF, csum_stuff_off);
+ }
+@@ -2845,17 +2845,17 @@ static inline int cas_xmit_tx_ringN(stru
+ tabort = cas_calc_tabort(cp, (unsigned long) skb->data, len);
+ if (unlikely(tabort)) {
+ /* NOTE: len is always > tabort */
+- cas_write_txd(cp, ring, entry, mapping, len - tabort,
++ cas_write_txd(cp, ring, entry, mapping, len - tabort,
+ ctrl | TX_DESC_SOF, 0);
+ entry = TX_DESC_NEXT(ring, entry);
+
+- memcpy(tx_tiny_buf(cp, ring, entry), skb->data +
++ memcpy(tx_tiny_buf(cp, ring, entry), skb->data +
+ len - tabort, tabort);
+ mapping = tx_tiny_map(cp, ring, entry, tentry);
+ cas_write_txd(cp, ring, entry, mapping, tabort, ctrl,
+ (nr_frags == 0));
+ } else {
+- cas_write_txd(cp, ring, entry, mapping, len, ctrl |
++ cas_write_txd(cp, ring, entry, mapping, len, ctrl |
+ TX_DESC_SOF, (nr_frags == 0));
+ }
+ entry = TX_DESC_NEXT(ring, entry);
+@@ -2876,10 +2876,10 @@ static inline int cas_xmit_tx_ringN(stru
+ cas_write_txd(cp, ring, entry, mapping, len - tabort,
+ ctrl, 0);
+ entry = TX_DESC_NEXT(ring, entry);
+-
++
+ addr = cas_page_map(fragp->page);
+ memcpy(tx_tiny_buf(cp, ring, entry),
+- addr + fragp->page_offset + len - tabort,
++ addr + fragp->page_offset + len - tabort,
+ tabort);
+ cas_page_unmap(addr);
+ mapping = tx_tiny_map(cp, ring, entry, tentry);
+@@ -2898,12 +2898,12 @@ static inline int cas_xmit_tx_ringN(stru
+ if (netif_msg_tx_queued(cp))
+ printk(KERN_DEBUG "%s: tx[%d] queued, slot %d, skblen %d, "
+ "avail %d\n",
+- dev->name, ring, entry, skb->len,
++ dev->name, ring, entry, skb->len,
+ TX_BUFFS_AVAIL(cp, ring));
+ writel(entry, cp->regs + REG_TX_KICKN(ring));
+ spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
+ return 0;
+-}
++}
+
+ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -2912,7 +2912,7 @@ static int cas_start_xmit(struct sk_buff
+ /* this is only used as a load-balancing hint, so it doesn't
+ * need to be SMP safe
+ */
+- static int ring;
++ static int ring;
+
+ if (skb_padto(skb, cp->min_frame_size))
+ return 0;
+@@ -2943,14 +2943,14 @@ static void cas_init_tx_dma(struct cas *
+ /* enable completion writebacks, enable paced mode,
+ * disable read pipe, and disable pre-interrupt compwbs
+ */
+- val = TX_CFG_COMPWB_Q1 | TX_CFG_COMPWB_Q2 |
++ val = TX_CFG_COMPWB_Q1 | TX_CFG_COMPWB_Q2 |
+ TX_CFG_COMPWB_Q3 | TX_CFG_COMPWB_Q4 |
+- TX_CFG_DMA_RDPIPE_DIS | TX_CFG_PACED_MODE |
++ TX_CFG_DMA_RDPIPE_DIS | TX_CFG_PACED_MODE |
+ TX_CFG_INTR_COMPWB_DIS;
+
+ /* write out tx ring info and tx desc bases */
+ for (i = 0; i < MAX_TX_RINGS; i++) {
+- off = (unsigned long) cp->init_txds[i] -
++ off = (unsigned long) cp->init_txds[i] -
+ (unsigned long) cp->init_block;
+
+ val |= CAS_TX_RINGN_BASE(i);
+@@ -2991,7 +2991,7 @@ static u32 cas_setup_multicast(struct ca
+ {
+ u32 rxcfg = 0;
+ int i;
+-
++
+ if (cp->dev->flags & IFF_PROMISC) {
+ rxcfg |= MAC_RX_CFG_PROMISC_EN;
+
+@@ -3016,16 +3016,16 @@ static u32 cas_setup_multicast(struct ca
+ writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 2));
+ continue;
+ }
+- writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
++ writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
+ cp->regs + REG_MAC_ADDRN(i*3 + 0));
+- writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
++ writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
+ cp->regs + REG_MAC_ADDRN(i*3 + 1));
+- writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
++ writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
+ cp->regs + REG_MAC_ADDRN(i*3 + 2));
+ dmi = dmi->next;
+ }
+
+- /* use hw hash table for the next series of
++ /* use hw hash table for the next series of
+ * multicast addresses
+ */
+ memset(hash_table, 0, sizeof(hash_table));
+@@ -3036,7 +3036,7 @@ static u32 cas_setup_multicast(struct ca
+ dmi = dmi->next;
+ }
+ for (i=0; i < 16; i++)
+- writel(hash_table[i], cp->regs +
++ writel(hash_table[i], cp->regs +
+ REG_MAC_HASH_TABLEN(i));
+ rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
+ }
+@@ -3121,23 +3121,23 @@ static void cas_init_mac(struct cas *cp)
+ writel(0x00, cp->regs + REG_MAC_IPG0);
+ writel(0x08, cp->regs + REG_MAC_IPG1);
+ writel(0x04, cp->regs + REG_MAC_IPG2);
+-
++
+ /* change later for 802.3z */
+- writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
++ writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
+
+ /* min frame + FCS */
+ writel(ETH_ZLEN + 4, cp->regs + REG_MAC_FRAMESIZE_MIN);
+
+ /* Ethernet payload + header + FCS + optional VLAN tag. NOTE: we
+- * specify the maximum frame size to prevent RX tag errors on
++ * specify the maximum frame size to prevent RX tag errors on
+ * oversized frames.
+ */
+ writel(CAS_BASE(MAC_FRAMESIZE_MAX_BURST, 0x2000) |
+- CAS_BASE(MAC_FRAMESIZE_MAX_FRAME,
+- (CAS_MAX_MTU + ETH_HLEN + 4 + 4)),
++ CAS_BASE(MAC_FRAMESIZE_MAX_FRAME,
++ (CAS_MAX_MTU + ETH_HLEN + 4 + 4)),
+ cp->regs + REG_MAC_FRAMESIZE_MAX);
+
+- /* NOTE: crc_size is used as a surrogate for half-duplex.
++ /* NOTE: crc_size is used as a surrogate for half-duplex.
+ * workaround saturn half-duplex issue by increasing preamble
+ * size to 65 bytes.
+ */
+@@ -3180,7 +3180,7 @@ static void cas_init_mac(struct cas *cp)
+ * spin_lock_irqsave, but we are called only in cas_init_hw and
+ * cas_init_hw is protected by cas_lock_all, which calls
+ * spin_lock_irq (so it doesn't need to save the flags, and
+- * we should be OK for the writel, as that is the only
++ * we should be OK for the writel, as that is the only
+ * difference).
+ */
+ cp->mac_rx_cfg = rxcfg = cas_setup_multicast(cp);
+@@ -3229,7 +3229,7 @@ static int cas_vpd_match(const void __io
+ {
+ int len = strlen(str) + 1;
+ int i;
+-
++
+ for (i = 0; i < len; i++) {
+ if (readb(p + i) != str[i])
+ return 0;
+@@ -3246,7 +3246,7 @@ static int cas_vpd_match(const void __io
+ * number.
+ * 3) fiber cards don't have bridges, so their slot numbers don't
+ * mean anything.
+- * 4) we don't actually know we have a fiber card until after
++ * 4) we don't actually know we have a fiber card until after
+ * the mac addresses are parsed.
+ */
+ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
+@@ -3278,15 +3278,15 @@ static int cas_get_vpd_info(struct cas *
+ (readb(p + i + 1) == 0x43) &&
+ (readb(p + i + 2) == 0x49) &&
+ (readb(p + i + 3) == 0x52)) {
+- base = p + (readb(p + i + 8) |
++ base = p + (readb(p + i + 8) |
+ (readb(p + i + 9) << 8));
+ break;
+- }
++ }
+ }
+
+ if (!base || (readb(base) != 0x82))
+ goto use_random_mac_addr;
+-
++
+ i = (readb(base + 1) | (readb(base + 2) << 8)) + 3;
+ while (i < EXPANSION_ROM_SIZE) {
+ if (readb(base + i) != 0x90) /* no vpd found */
+@@ -3304,20 +3304,20 @@ static int cas_get_vpd_info(struct cas *
+ char type;
+
+ p += 3;
+-
++
+ /* look for the following things:
+ * -- correct length == 29
+- * 3 (type) + 2 (size) +
+- * 18 (strlen("local-mac-address") + 1) +
+- * 6 (mac addr)
++ * 3 (type) + 2 (size) +
++ * 18 (strlen("local-mac-address") + 1) +
++ * 6 (mac addr)
+ * -- VPD Instance 'I'
+ * -- VPD Type Bytes 'B'
+ * -- VPD data length == 6
+ * -- property string == local-mac-address
+- *
++ *
+ * -- correct length == 24
+- * 3 (type) + 2 (size) +
+- * 12 (strlen("entropy-dev") + 1) +
++ * 3 (type) + 2 (size) +
++ * 12 (strlen("entropy-dev") + 1) +
+ * 7 (strlen("vms110") + 1)
+ * -- VPD Instance 'I'
+ * -- VPD Type String 'B'
+@@ -3325,17 +3325,17 @@ static int cas_get_vpd_info(struct cas *
+ * -- property string == entropy-dev
+ *
+ * -- correct length == 18
+- * 3 (type) + 2 (size) +
+- * 9 (strlen("phy-type") + 1) +
++ * 3 (type) + 2 (size) +
++ * 9 (strlen("phy-type") + 1) +
+ * 4 (strlen("pcs") + 1)
+ * -- VPD Instance 'I'
+ * -- VPD Type String 'S'
+ * -- VPD data length == 4
+ * -- property string == phy-type
+- *
++ *
+ * -- correct length == 23
+- * 3 (type) + 2 (size) +
+- * 14 (strlen("phy-interface") + 1) +
++ * 3 (type) + 2 (size) +
++ * 14 (strlen("phy-interface") + 1) +
+ * 4 (strlen("pcs") + 1)
+ * -- VPD Instance 'I'
+ * -- VPD Type String 'S'
+@@ -3349,14 +3349,14 @@ static int cas_get_vpd_info(struct cas *
+ type = readb(p + 3);
+ if (type == 'B') {
+ if ((klen == 29) && readb(p + 4) == 6 &&
+- cas_vpd_match(p + 5,
++ cas_vpd_match(p + 5,
+ "local-mac-address")) {
+- if (mac_off++ > offset)
++ if (mac_off++ > offset)
+ goto next;
+
+ /* set mac address */
+- for (j = 0; j < 6; j++)
+- dev_addr[j] =
++ for (j = 0; j < 6; j++)
++ dev_addr[j] =
+ readb(p + 23 + j);
+ goto found_mac;
+ }
+@@ -3366,7 +3366,7 @@ static int cas_get_vpd_info(struct cas *
+ goto next;
+
+ #ifdef USE_ENTROPY_DEV
+- if ((klen == 24) &&
++ if ((klen == 24) &&
+ cas_vpd_match(p + 5, "entropy-dev") &&
+ cas_vpd_match(p + 17, "vms110")) {
+ cp->cas_flags |= CAS_FLAG_ENTROPY_DEV;
+@@ -3384,7 +3384,7 @@ static int cas_get_vpd_info(struct cas *
+ goto found_phy;
+ }
+ }
+-
++
+ if ((klen == 23) && readb(p + 4) == 4 &&
+ cas_vpd_match(p + 5, "phy-interface")) {
+ if (cas_vpd_match(p + 19, "pcs")) {
+@@ -3462,12 +3462,12 @@ static int cas_check_invariants(struct c
+ int i;
+
+ /* get page size for rx buffers. */
+- cp->page_order = 0;
++ cp->page_order = 0;
+ #ifdef USE_PAGE_ORDER
+ if (PAGE_SHIFT < CAS_JUMBO_PAGE_SHIFT) {
+ /* see if we can allocate larger pages */
+- struct page *page = alloc_pages(GFP_ATOMIC,
+- CAS_JUMBO_PAGE_SHIFT -
++ struct page *page = alloc_pages(GFP_ATOMIC,
++ CAS_JUMBO_PAGE_SHIFT -
+ PAGE_SHIFT);
+ if (page) {
+ __free_pages(page, CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT);
+@@ -3483,15 +3483,15 @@ static int cas_check_invariants(struct c
+ cp->tx_fifo_size = readl(cp->regs + REG_TX_FIFO_SIZE) * 64;
+ cp->rx_fifo_size = RX_FIFO_SIZE;
+
+- /* finish phy determination. MDIO1 takes precedence over MDIO0 if
++ /* finish phy determination. MDIO1 takes precedence over MDIO0 if
+ * they're both connected.
+ */
+- cp->phy_type = cas_get_vpd_info(cp, cp->dev->dev_addr,
++ cp->phy_type = cas_get_vpd_info(cp, cp->dev->dev_addr,
+ PCI_SLOT(pdev->devfn));
+ if (cp->phy_type & CAS_PHY_SERDES) {
+ cp->cas_flags |= CAS_FLAG_1000MB_CAP;
+ return 0; /* no more checking needed */
+- }
++ }
+
+ /* MII */
+ cfg = readl(cp->regs + REG_MIF_CFG);
+@@ -3525,7 +3525,7 @@ static int cas_check_invariants(struct c
+ done:
+ /* see if we can do gigabit */
+ cfg = cas_phy_read(cp, MII_BMSR);
+- if ((cfg & CAS_BMSR_1000_EXTEND) &&
++ if ((cfg & CAS_BMSR_1000_EXTEND) &&
+ cas_phy_read(cp, CAS_MII_1000_EXTEND))
+ cp->cas_flags |= CAS_FLAG_1000MB_CAP;
+ return 0;
+@@ -3537,7 +3537,7 @@ static inline void cas_start_dma(struct
+ int i;
+ u32 val;
+ int txfailed = 0;
+-
++
+ /* enable dma */
+ val = readl(cp->regs + REG_TX_CFG) | TX_CFG_DMA_EN;
+ writel(val, cp->regs + REG_TX_CFG);
+@@ -3563,8 +3563,8 @@ static inline void cas_start_dma(struct
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+ if ((val & MAC_RX_CFG_EN)) {
+ if (txfailed) {
+- printk(KERN_ERR
+- "%s: enabling mac failed [tx:%08x:%08x].\n",
++ printk(KERN_ERR
++ "%s: enabling mac failed [tx:%08x:%08x].\n",
+ cp->dev->name,
+ readl(cp->regs + REG_MIF_STATE_MACHINE),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
+@@ -3573,7 +3573,7 @@ static inline void cas_start_dma(struct
+ }
+ udelay(10);
+ }
+- printk(KERN_ERR "%s: enabling mac failed [%s:%08x:%08x].\n",
++ printk(KERN_ERR "%s: enabling mac failed [%s:%08x:%08x].\n",
+ cp->dev->name,
+ (txfailed? "tx,rx":"rx"),
+ readl(cp->regs + REG_MIF_STATE_MACHINE),
+@@ -3585,11 +3585,11 @@ enable_rx_done:
+ writel(0, cp->regs + REG_RX_COMP_TAIL);
+
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+- if (N_RX_DESC_RINGS > 1)
+- writel(RX_DESC_RINGN_SIZE(1) - 4,
++ if (N_RX_DESC_RINGS > 1)
++ writel(RX_DESC_RINGN_SIZE(1) - 4,
+ cp->regs + REG_PLUS_RX_KICK1);
+
+- for (i = 1; i < N_RX_COMP_RINGS; i++)
++ for (i = 1; i < N_RX_COMP_RINGS; i++)
+ writel(0, cp->regs + REG_PLUS_RX_COMPN_TAIL(i));
+ }
+ }
+@@ -3615,7 +3615,7 @@ static void cas_read_mii_link_mode(struc
+ *fd = 0;
+ *spd = 10;
+ *pause = 0;
+-
++
+ /* use GMII registers */
+ val = cas_phy_read(cp, MII_LPA);
+ if (val & CAS_LPA_PAUSE)
+@@ -3656,7 +3656,7 @@ static void cas_set_link_modes(struct ca
+ cas_mif_poll(cp, 0);
+ val = cas_phy_read(cp, MII_BMCR);
+ if (val & BMCR_ANENABLE) {
+- cas_read_mii_link_mode(cp, &full_duplex, &speed,
++ cas_read_mii_link_mode(cp, &full_duplex, &speed,
+ &pause);
+ } else {
+ if (val & BMCR_FULLDPLX)
+@@ -3689,7 +3689,7 @@ static void cas_set_link_modes(struct ca
+ if (!full_duplex)
+ val |= MAC_XIF_DISABLE_ECHO;
+ }
+- if (full_duplex)
++ if (full_duplex)
+ val |= MAC_XIF_FDPLX_LED;
+ if (speed == 1000)
+ val |= MAC_XIF_GMII_MODE;
+@@ -3709,17 +3709,17 @@ static void cas_set_link_modes(struct ca
+ /* val now set up for REG_MAC_TX_CFG */
+
+ /* If gigabit and half-duplex, enable carrier extension
+- * mode. increase slot time to 512 bytes as well.
++ * mode. increase slot time to 512 bytes as well.
+ * else, disable it and make sure slot time is 64 bytes.
+ * also activate checksum bug workaround
+ */
+ if ((speed == 1000) && !full_duplex) {
+- writel(val | MAC_TX_CFG_CARRIER_EXTEND,
++ writel(val | MAC_TX_CFG_CARRIER_EXTEND,
+ cp->regs + REG_MAC_TX_CFG);
+
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+ val &= ~MAC_RX_CFG_STRIP_FCS; /* checksum workaround */
+- writel(val | MAC_RX_CFG_CARRIER_EXTEND,
++ writel(val | MAC_RX_CFG_CARRIER_EXTEND,
+ cp->regs + REG_MAC_RX_CFG);
+
+ writel(0x200, cp->regs + REG_MAC_SLOT_TIME);
+@@ -3731,7 +3731,7 @@ static void cas_set_link_modes(struct ca
+ } else {
+ writel(val, cp->regs + REG_MAC_TX_CFG);
+
+- /* checksum bug workaround. don't strip FCS when in
++ /* checksum bug workaround. don't strip FCS when in
+ * half-duplex mode
+ */
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+@@ -3744,7 +3744,7 @@ static void cas_set_link_modes(struct ca
+ cp->crc_size = 4;
+ cp->min_frame_size = CAS_MIN_FRAME;
+ }
+- writel(val & ~MAC_RX_CFG_CARRIER_EXTEND,
++ writel(val & ~MAC_RX_CFG_CARRIER_EXTEND,
+ cp->regs + REG_MAC_RX_CFG);
+ writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
+ }
+@@ -3772,7 +3772,7 @@ static void cas_set_link_modes(struct ca
+ val |= MAC_CTRL_CFG_SEND_PAUSE_EN;
+ if (pause & 0x01) { /* symmetric pause */
+ val |= MAC_CTRL_CFG_RECV_PAUSE_EN;
+- }
++ }
+ }
+ writel(val, cp->regs + REG_MAC_CTRL_CFG);
+ cas_start_dma(cp);
+@@ -3804,7 +3804,7 @@ static void cas_init_hw(struct cas *cp,
+ */
+ static void cas_hard_reset(struct cas *cp)
+ {
+- writel(BIM_LOCAL_DEV_SOFT_0, cp->regs + REG_BIM_LOCAL_DEV_EN);
++ writel(BIM_LOCAL_DEV_SOFT_0, cp->regs + REG_BIM_LOCAL_DEV_EN);
+ udelay(20);
+ pci_restore_state(cp->pdev);
+ }
+@@ -3822,7 +3822,7 @@ static void cas_global_reset(struct cas
+ * need some special handling if the chip is set into a
+ * loopback mode.
+ */
+- writel((SW_RESET_TX | SW_RESET_RX | SW_RESET_BLOCK_PCS_SLINK),
++ writel((SW_RESET_TX | SW_RESET_RX | SW_RESET_BLOCK_PCS_SLINK),
+ cp->regs + REG_SW_RESET);
+ } else {
+ writel(SW_RESET_TX | SW_RESET_RX, cp->regs + REG_SW_RESET);
+@@ -3842,16 +3842,16 @@ static void cas_global_reset(struct cas
+
+ done:
+ /* enable various BIM interrupts */
+- writel(BIM_CFG_DPAR_INTR_ENABLE | BIM_CFG_RMA_INTR_ENABLE |
++ writel(BIM_CFG_DPAR_INTR_ENABLE | BIM_CFG_RMA_INTR_ENABLE |
+ BIM_CFG_RTA_INTR_ENABLE, cp->regs + REG_BIM_CFG);
+
+ /* clear out pci error status mask for handled errors.
+ * we don't deal with DMA counter overflows as they happen
+ * all the time.
+ */
+- writel(0xFFFFFFFFU & ~(PCI_ERR_BADACK | PCI_ERR_DTRTO |
+- PCI_ERR_OTHER | PCI_ERR_BIM_DMA_WRITE |
+- PCI_ERR_BIM_DMA_READ), cp->regs +
++ writel(0xFFFFFFFFU & ~(PCI_ERR_BADACK | PCI_ERR_DTRTO |
++ PCI_ERR_OTHER | PCI_ERR_BIM_DMA_WRITE |
++ PCI_ERR_BIM_DMA_READ), cp->regs +
+ REG_PCI_ERR_STATUS_MASK);
+
+ /* set up for MII by default to address mac rx reset timeout
+@@ -3912,7 +3912,7 @@ static void cas_shutdown(struct cas *cp)
+ #else
+ while (atomic_read(&cp->reset_task_pending))
+ schedule();
+-#endif
++#endif
+ /* Actually stop the chip */
+ cas_lock_all_save(cp, flags);
+ cas_reset(cp, 0);
+@@ -3942,7 +3942,7 @@ static int cas_change_mtu(struct net_dev
+ }
+ schedule_work(&cp->reset_task);
+ #else
+- atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
++ atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
+ CAS_RESET_ALL : CAS_RESET_MTU);
+ printk(KERN_ERR "reset called in cas_change_mtu\n");
+ schedule_work(&cp->reset_task);
+@@ -3976,7 +3976,7 @@ static void cas_clean_txd(struct cas *cp
+ * needs to be unmapped.
+ */
+ daddr = le64_to_cpu(txd[ent].buffer);
+- dlen = CAS_VAL(TX_DESC_BUFLEN,
++ dlen = CAS_VAL(TX_DESC_BUFLEN,
+ le64_to_cpu(txd[ent].control));
+ pci_unmap_page(cp->pdev, daddr, dlen,
+ PCI_DMA_TODEVICE);
+@@ -4047,7 +4047,7 @@ static inline int cas_alloc_rx_desc(stru
+
+ size = RX_DESC_RINGN_SIZE(ring);
+ for (i = 0; i < size; i++) {
+- if ((page[i] = cas_page_alloc(cp, GFP_KERNEL)) == NULL)
++ if ((page[i] = cas_page_alloc(cp, GFP_KERNEL)) == NULL)
+ return -1;
+ }
+ return 0;
+@@ -4114,7 +4114,7 @@ static void cas_reset_task(void *data)
+ * call to cas_init_hw will restart auto negotiation.
+ * Setting the second argument of cas_reset to
+ * !(pending == CAS_RESET_ALL) will set this argument
+- * to 1 (avoiding reinitializing the PHY for the normal
++ * to 1 (avoiding reinitializing the PHY for the normal
+ * PCS case) when auto negotiation is not restarted.
+ */
+ #if 1
+@@ -4151,9 +4151,9 @@ static void cas_link_timer(unsigned long
+
+ if (link_transition_timeout != 0 &&
+ cp->link_transition_jiffies_valid &&
+- ((jiffies - cp->link_transition_jiffies) >
++ ((jiffies - cp->link_transition_jiffies) >
+ (link_transition_timeout))) {
+- /* One-second counter so link-down workaround doesn't
++ /* One-second counter so link-down workaround doesn't
+ * cause resets to occur so fast as to fool the switch
+ * into thinking the link is down.
+ */
+@@ -4173,10 +4173,10 @@ static void cas_link_timer(unsigned long
+ #if 1
+ if (atomic_read(&cp->reset_task_pending_all) ||
+ atomic_read(&cp->reset_task_pending_spare) ||
+- atomic_read(&cp->reset_task_pending_mtu))
++ atomic_read(&cp->reset_task_pending_mtu))
+ goto done;
+ #else
+- if (atomic_read(&cp->reset_task_pending))
++ if (atomic_read(&cp->reset_task_pending))
+ goto done;
+ #endif
+
+@@ -4268,7 +4268,7 @@ done:
+ spin_unlock_irqrestore(&cp->lock, flags);
+ }
+
+-/* tiny buffers are used to avoid target abort issues with
++/* tiny buffers are used to avoid target abort issues with
+ * older cassini's
+ */
+ static void cas_tx_tiny_free(struct cas *cp)
+@@ -4280,7 +4280,7 @@ static void cas_tx_tiny_free(struct cas
+ if (!cp->tx_tiny_bufs[i])
+ continue;
+
+- pci_free_consistent(pdev, TX_TINY_BUF_BLOCK,
++ pci_free_consistent(pdev, TX_TINY_BUF_BLOCK,
+ cp->tx_tiny_bufs[i],
+ cp->tx_tiny_dvma[i]);
+ cp->tx_tiny_bufs[i] = NULL;
+@@ -4293,7 +4293,7 @@ static int cas_tx_tiny_alloc(struct cas
+ int i;
+
+ for (i = 0; i < N_TX_RINGS; i++) {
+- cp->tx_tiny_bufs[i] =
++ cp->tx_tiny_bufs[i] =
+ pci_alloc_consistent(pdev, TX_TINY_BUF_BLOCK,
+ &cp->tx_tiny_dvma[i]);
+ if (!cp->tx_tiny_bufs[i]) {
+@@ -4322,7 +4322,7 @@ static int cas_open(struct net_device *d
+ /* Reset the chip */
+ cas_lock_all_save(cp, flags);
+ /* We set the second arg to cas_reset to zero
+- * because cas_init_hw below will have its second
++ * because cas_init_hw below will have its second
+ * argument set to non-zero, which will force
+ * autonegotiation to start.
+ */
+@@ -4338,19 +4338,19 @@ static int cas_open(struct net_device *d
+ err = -ENOMEM;
+ if (cas_alloc_rxds(cp) < 0)
+ goto err_tx_tiny;
+-
++
+ /* allocate spares */
+ cas_spare_init(cp);
+ cas_spare_recover(cp, GFP_KERNEL);
+
+ /* We can now request the interrupt as we know it's masked
+ * on the controller. cassini+ has up to 4 interrupts
+- * that can be used, but you need to do explicit pci interrupt
++ * that can be used, but you need to do explicit pci interrupt
+ * mapping to expose them
+ */
+ if (request_irq(cp->pdev->irq, cas_interrupt,
+ IRQF_SHARED, dev->name, (void *) dev)) {
+- printk(KERN_ERR "%s: failed to request irq !\n",
++ printk(KERN_ERR "%s: failed to request irq !\n",
+ cp->dev->name);
+ err = -EAGAIN;
+ goto err_spare;
+@@ -4388,9 +4388,9 @@ static int cas_close(struct net_device *
+
+ /* Stop traffic, mark us closed */
+ cas_lock_all_save(cp, flags);
+- cp->opened = 0;
++ cp->opened = 0;
+ cas_reset(cp, 0);
+- cas_phy_init(cp);
++ cas_phy_init(cp);
+ cas_begin_auto_negotiation(cp, NULL);
+ cas_clean_rings(cp);
+ cas_unlock_all_restore(cp, flags);
+@@ -4483,7 +4483,7 @@ static struct net_device_stats *cas_get_
+ /* we collate all of the stats into net_stats[N_TX_RING] */
+ if (!cp->hw_running)
+ return stats + N_TX_RINGS;
+-
++
+ /* collect outstanding stats */
+ /* WTZ: the Cassini spec gives these as 16 bit counters but
+ * stored in 32-bit words. Added a mask of 0xffff to be safe,
+@@ -4493,11 +4493,11 @@ static struct net_device_stats *cas_get_
+ * that consistent.
+ */
+ spin_lock_irqsave(&cp->stat_lock[N_TX_RINGS], flags);
+- stats[N_TX_RINGS].rx_crc_errors +=
++ stats[N_TX_RINGS].rx_crc_errors +=
+ readl(cp->regs + REG_MAC_FCS_ERR) & 0xffff;
+- stats[N_TX_RINGS].rx_frame_errors +=
++ stats[N_TX_RINGS].rx_frame_errors +=
+ readl(cp->regs + REG_MAC_ALIGN_ERR) &0xffff;
+- stats[N_TX_RINGS].rx_length_errors +=
++ stats[N_TX_RINGS].rx_length_errors +=
+ readl(cp->regs + REG_MAC_LEN_ERR) & 0xffff;
+ #if 1
+ tmp = (readl(cp->regs + REG_MAC_COLL_EXCESS) & 0xffff) +
+@@ -4506,7 +4506,7 @@ static struct net_device_stats *cas_get_
+ stats[N_TX_RINGS].collisions +=
+ tmp + (readl(cp->regs + REG_MAC_COLL_NORMAL) & 0xffff);
+ #else
+- stats[N_TX_RINGS].tx_aborted_errors +=
++ stats[N_TX_RINGS].tx_aborted_errors +=
+ readl(cp->regs + REG_MAC_COLL_EXCESS);
+ stats[N_TX_RINGS].collisions += readl(cp->regs + REG_MAC_COLL_EXCESS) +
+ readl(cp->regs + REG_MAC_COLL_LATE);
+@@ -4525,7 +4525,7 @@ static struct net_device_stats *cas_get_
+
+ for (i = 0; i < N_TX_RINGS; i++) {
+ spin_lock(&cp->stat_lock[i]);
+- stats[N_TX_RINGS].rx_length_errors +=
++ stats[N_TX_RINGS].rx_length_errors +=
+ stats[i].rx_length_errors;
+ stats[N_TX_RINGS].rx_crc_errors += stats[i].rx_crc_errors;
+ stats[N_TX_RINGS].rx_packets += stats[i].rx_packets;
+@@ -4550,10 +4550,10 @@ static void cas_set_multicast(struct net
+ u32 rxcfg, rxcfg_new;
+ unsigned long flags;
+ int limit = STOP_TRIES;
+-
++
+ if (!cp->hw_running)
+ return;
+-
++
+ spin_lock_irqsave(&cp->lock, flags);
+ rxcfg = readl(cp->regs + REG_MAC_RX_CFG);
+
+@@ -4619,22 +4619,22 @@ static int cas_get_settings(struct net_d
+ XCVR_INTERNAL : XCVR_EXTERNAL;
+ cmd->phy_address = cp->phy_addr;
+ cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII |
+- ADVERTISED_10baseT_Half |
+- ADVERTISED_10baseT_Full |
+- ADVERTISED_100baseT_Half |
++ ADVERTISED_10baseT_Half |
++ ADVERTISED_10baseT_Full |
++ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full;
+
+ cmd->supported |=
+- (SUPPORTED_10baseT_Half |
++ (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+- SUPPORTED_100baseT_Half |
++ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_TP | SUPPORTED_MII);
+
+ if (cp->hw_running) {
+ cas_mif_poll(cp, 0);
+ bmcr = cas_phy_read(cp, MII_BMCR);
+- cas_read_mii_link_mode(cp, &full_duplex,
++ cas_read_mii_link_mode(cp, &full_duplex,
+ &speed, &pause);
+ cas_mif_poll(cp, 1);
+ }
+@@ -4647,9 +4647,9 @@ static int cas_get_settings(struct net_d
+ cmd->advertising |= ADVERTISED_FIBRE;
+
+ if (cp->hw_running) {
+- /* pcs uses the same bits as mii */
++ /* pcs uses the same bits as mii */
+ bmcr = readl(cp->regs + REG_PCS_MII_CTRL);
+- cas_read_pcs_link_mode(cp, &full_duplex,
++ cas_read_pcs_link_mode(cp, &full_duplex,
+ &speed, &pause);
+ }
+ }
+@@ -4667,8 +4667,8 @@ static int cas_get_settings(struct net_d
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->speed =
+ (bmcr & CAS_BMCR_SPEED1000) ?
+- SPEED_1000 :
+- ((bmcr & BMCR_SPEED100) ? SPEED_100:
++ SPEED_1000 :
++ ((bmcr & BMCR_SPEED100) ? SPEED_100:
+ SPEED_10);
+ cmd->duplex =
+ (bmcr & BMCR_FULLDPLX) ?
+@@ -4676,7 +4676,7 @@ static int cas_get_settings(struct net_d
+ }
+ if (linkstate != link_up) {
+ /* Force these to "unknown" if the link is not up and
+- * autonogotiation in enabled. We can set the link
++ * autonogotiation in enabled. We can set the link
+ * speed to 0, but not cmd->duplex,
+ * because its legal values are 0 and 1. Ethtool will
+ * print the value reported in parentheses after the
+@@ -4783,7 +4783,7 @@ static int cas_get_stats_count(struct ne
+
+ static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+ {
+- memcpy(data, ðtool_cassini_statnames,
++ memcpy(data, ðtool_cassini_statnames,
+ CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN);
+ }
+
+@@ -4812,7 +4812,7 @@ static void cas_get_ethtool_stats(struct
+ BUG_ON(i != CAS_NUM_STAT_KEYS);
+ }
+
+-static struct ethtool_ops cas_ethtool_ops = {
++static const struct ethtool_ops cas_ethtool_ops = {
+ .get_drvinfo = cas_get_drvinfo,
+ .get_settings = cas_get_settings,
+ .set_settings = cas_set_settings,
+@@ -4833,7 +4833,7 @@ static int cas_ioctl(struct net_device *
+ struct mii_ioctl_data *data = if_mii(ifr);
+ unsigned long flags;
+ int rc = -EOPNOTSUPP;
+-
++
+ /* Hold the PM mutex while doing ioctl's or we may collide
+ * with open/close and power management and oops.
+ */
+@@ -4933,11 +4933,11 @@ static int __devinit cas_init_one(struct
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ &orig_cacheline_size);
+ if (orig_cacheline_size < CAS_PREF_CACHELINE_SIZE) {
+- cas_cacheline_size =
+- (CAS_PREF_CACHELINE_SIZE < SMP_CACHE_BYTES) ?
++ cas_cacheline_size =
++ (CAS_PREF_CACHELINE_SIZE < SMP_CACHE_BYTES) ?
+ CAS_PREF_CACHELINE_SIZE : SMP_CACHE_BYTES;
+- if (pci_write_config_byte(pdev,
+- PCI_CACHE_LINE_SIZE,
++ if (pci_write_config_byte(pdev,
++ PCI_CACHE_LINE_SIZE,
+ cas_cacheline_size)) {
+ dev_err(&pdev->dev, "Could not set PCI cache "
+ "line size\n");
+@@ -4977,7 +4977,7 @@ static int __devinit cas_init_one(struct
+ cp->orig_cacheline_size = cas_cacheline_size ? orig_cacheline_size: 0;
+ #endif
+ cp->dev = dev;
+- cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
++ cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
+ cassini_debug;
+
+ cp->link_transition = LINK_TRANSITION_UNKNOWN;
+@@ -5041,13 +5041,13 @@ static int __devinit cas_init_one(struct
+ goto err_out_iounmap;
+ }
+
+- for (i = 0; i < N_TX_RINGS; i++)
++ for (i = 0; i < N_TX_RINGS; i++)
+ cp->init_txds[i] = cp->init_block->txds[i];
+
+- for (i = 0; i < N_RX_DESC_RINGS; i++)
++ for (i = 0; i < N_RX_DESC_RINGS; i++)
+ cp->init_rxds[i] = cp->init_block->rxds[i];
+
+- for (i = 0; i < N_RX_COMP_RINGS; i++)
++ for (i = 0; i < N_RX_COMP_RINGS; i++)
+ cp->init_rxcs[i] = cp->init_block->rxcs[i];
+
+ for (i = 0; i < N_RX_FLOWS; i++)
+@@ -5087,11 +5087,11 @@ static int __devinit cas_init_one(struct
+
+ i = readl(cp->regs + REG_BIM_CFG);
+ printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
+- "Ethernet[%d] ", dev->name,
+- (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
++ "Ethernet[%d] ", dev->name,
++ (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
+ (i & BIM_CFG_32BIT) ? "32" : "64",
+ (i & BIM_CFG_66MHZ) ? "66" : "33",
+- (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
++ (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i],
+@@ -5123,7 +5123,7 @@ err_out_free_res:
+
+ err_write_cacheline:
+ /* Try to restore it in case the error occured after we
+- * set it.
++ * set it.
+ */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, orig_cacheline_size);
+
+@@ -5157,7 +5157,7 @@ static void __devexit cas_remove_one(str
+ /* Restore the cache line size if we had modified
+ * it.
+ */
+- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
++ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ cp->orig_cacheline_size);
+ }
+ #endif
+@@ -5178,7 +5178,7 @@ static int cas_suspend(struct pci_dev *p
+ unsigned long flags;
+
+ mutex_lock(&cp->pm_mutex);
+-
++
+ /* If the driver is opened, we stop the DMA */
+ if (cp->opened) {
+ netif_device_detach(dev);
+@@ -5245,7 +5245,7 @@ static int __init cas_init(void)
+ else
+ link_transition_timeout = 0;
+
+- return pci_module_init(&cas_driver);
++ return pci_register_driver(&cas_driver);
+ }
+
+ static void __exit cas_cleanup(void)
+diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
+index ab55c7e..a970804 100644
+--- a/drivers/net/cassini.h
++++ b/drivers/net/cassini.h
+@@ -21,7 +21,7 @@
+ *
+ * vendor id: 0x108E (Sun Microsystems, Inc.)
+ * device id: 0xabba (Cassini)
+- * revision ids: 0x01 = Cassini
++ * revision ids: 0x01 = Cassini
+ * 0x02 = Cassini rev 2
+ * 0x10 = Cassini+
+ * 0x11 = Cassini+ 0.2u
+@@ -46,16 +46,16 @@
+ * appear in cassini+. REG_MINUS_ addresses only appear in cassini.
+ */
+ #define CAS_ID_REV2 0x02
+-#define CAS_ID_REVPLUS 0x10
+-#define CAS_ID_REVPLUS02u 0x11
++#define CAS_ID_REVPLUS 0x10
++#define CAS_ID_REVPLUS02u 0x11
+ #define CAS_ID_REVSATURNB2 0x30
+
+ /** global resources **/
+
+ /* this register sets the weights for the weighted round robin arbiter. e.g.,
+ * if rx weight == 1 and tx weight == 0, rx == 2x tx transfer credit
+- * for its next turn to access the pci bus.
+- * map: 0x0 = x1, 0x1 = x2, 0x2 = x4, 0x3 = x8
++ * for its next turn to access the pci bus.
++ * map: 0x0 = x1, 0x1 = x2, 0x2 = x4, 0x3 = x8
+ * DEFAULT: 0x0, SIZE: 5 bits
+ */
+ #define REG_CAWR 0x0004 /* core arbitration weight */
+@@ -66,8 +66,8 @@
+ #define CAWR_RR_DIS 0x10 /* [4] */
+
+ /* if enabled, BIM can send bursts across PCI bus > cacheline size. burst
+- * sizes determined by length of packet or descriptor transfer and the
+- * max length allowed by the target.
++ * sizes determined by length of packet or descriptor transfer and the
++ * max length allowed by the target.
+ * DEFAULT: 0x0, SIZE: 1 bit
+ */
+ #define REG_INF_BURST 0x0008 /* infinite burst enable reg */
+@@ -75,21 +75,21 @@
+
+ /* top level interrupts [0-9] are auto-cleared to 0 when the status
+ * register is read. second level interrupts [13 - 18] are cleared at
+- * the source. tx completion register 3 is replicated in [19 - 31]
++ * the source. tx completion register 3 is replicated in [19 - 31]
+ * DEFAULT: 0x00000000, SIZE: 29 bits
+ */
+ #define REG_INTR_STATUS 0x000C /* interrupt status register */
+-#define INTR_TX_INTME 0x00000001 /* frame w/ INT ME desc bit set
++#define INTR_TX_INTME 0x00000001 /* frame w/ INT ME desc bit set
+ xferred from host queue to
+ TX FIFO */
+ #define INTR_TX_ALL 0x00000002 /* all xmit frames xferred into
+ TX FIFO. i.e.,
+- TX Kick == TX complete. if
++ TX Kick == TX complete. if
+ PACED_MODE set, then TX FIFO
+ also empty */
+-#define INTR_TX_DONE 0x00000004 /* any frame xferred into tx
++#define INTR_TX_DONE 0x00000004 /* any frame xferred into tx
+ FIFO */
+-#define INTR_TX_TAG_ERROR 0x00000008 /* TX FIFO tag framing
++#define INTR_TX_TAG_ERROR 0x00000008 /* TX FIFO tag framing
+ corrupted. FATAL ERROR */
+ #define INTR_RX_DONE 0x00000010 /* at least 1 frame xferred
+ from RX FIFO to host mem.
+@@ -98,18 +98,18 @@
+ intr blanking. */
+ #define INTR_RX_BUF_UNAVAIL 0x00000020 /* no more receive buffers.
+ RX Kick == RX complete */
+-#define INTR_RX_TAG_ERROR 0x00000040 /* RX FIFO tag framing
++#define INTR_RX_TAG_ERROR 0x00000040 /* RX FIFO tag framing
+ corrupted. FATAL ERROR */
+ #define INTR_RX_COMP_FULL 0x00000080 /* no more room in completion
+ ring to post descriptors.
+ RX complete head incr to
+ almost reach RX complete
+ tail */
+-#define INTR_RX_BUF_AE 0x00000100 /* less than the
++#define INTR_RX_BUF_AE 0x00000100 /* less than the
+ programmable threshold #
+ of free descr avail for
+ hw use */
+-#define INTR_RX_COMP_AF 0x00000200 /* less than the
++#define INTR_RX_COMP_AF 0x00000200 /* less than the
+ programmable threshold #
+ of descr spaces for hw
+ use in completion descr
+@@ -119,17 +119,17 @@
+ from fifo during DMA or
+ header parser provides TCP
+ header and payload size >
+- MAC packet size.
++ MAC packet size.
+ FATAL ERROR */
+ #define INTR_SUMMARY 0x00001000 /* summary interrupt bit. this
+- bit will be set if an interrupt
++ bit will be set if an interrupt
+ generated on the pci bus. useful
+- when driver is polling for
++ when driver is polling for
+ interrupts */
+ #define INTR_PCS_STATUS 0x00002000 /* PCS interrupt status register */
+-#define INTR_TX_MAC_STATUS 0x00004000 /* TX MAC status register has at
++#define INTR_TX_MAC_STATUS 0x00004000 /* TX MAC status register has at
+ least 1 unmasked interrupt set */
+-#define INTR_RX_MAC_STATUS 0x00008000 /* RX MAC status register has at
++#define INTR_RX_MAC_STATUS 0x00008000 /* RX MAC status register has at
+ least 1 unmasked interrupt set */
+ #define INTR_MAC_CTRL_STATUS 0x00010000 /* MAC control status register has
+ at least 1 unmasked interrupt
+@@ -137,9 +137,9 @@
+ #define INTR_MIF_STATUS 0x00020000 /* MIF status register has at least
+ 1 unmasked interrupt set */
+ #define INTR_PCI_ERROR_STATUS 0x00040000 /* PCI error status register in the
+- BIF has at least 1 unmasked
++ BIF has at least 1 unmasked
+ interrupt set */
+-#define INTR_TX_COMP_3_MASK 0xFFF80000 /* mask for TX completion
++#define INTR_TX_COMP_3_MASK 0xFFF80000 /* mask for TX completion
+ 3 reg data */
+ #define INTR_TX_COMP_3_SHIFT 19
+ #define INTR_ERROR_MASK (INTR_MIF_STATUS | INTR_PCI_ERROR_STATUS | \
+@@ -149,7 +149,7 @@
+ INTR_MAC_CTRL_STATUS)
+
+ /* determines which status events will cause an interrupt. layout same
+- * as REG_INTR_STATUS.
++ * as REG_INTR_STATUS.
+ * DEFAULT: 0xFFFFFFFF, SIZE: 16 bits
+ */
+ #define REG_INTR_MASK 0x0010 /* Interrupt mask */
+@@ -158,18 +158,18 @@
+ * useful when driver is polling for interrupts. layout same as REG_INTR_MASK.
+ * DEFAULT: 0x00000000, SIZE: 12 bits
+ */
+-#define REG_ALIAS_CLEAR 0x0014 /* alias clear mask
++#define REG_ALIAS_CLEAR 0x0014 /* alias clear mask
+ (used w/ status alias) */
+ /* same as REG_INTR_STATUS except that only bits cleared are those selected by
+- * REG_ALIAS_CLEAR
++ * REG_ALIAS_CLEAR
+ * DEFAULT: 0x00000000, SIZE: 29 bits
+ */
+-#define REG_INTR_STATUS_ALIAS 0x001C /* interrupt status alias
++#define REG_INTR_STATUS_ALIAS 0x001C /* interrupt status alias
+ (selective clear) */
+
+ /* DEFAULT: 0x0, SIZE: 3 bits */
+ #define REG_PCI_ERR_STATUS 0x1000 /* PCI error status */
+-#define PCI_ERR_BADACK 0x01 /* reserved in Cassini+.
++#define PCI_ERR_BADACK 0x01 /* reserved in Cassini+.
+ set if no ACK64# during ABS64 cycle
+ in Cassini. */
+ #define PCI_ERR_DTRTO 0x02 /* delayed xaction timeout. set if
+@@ -179,16 +179,16 @@
+ unused in Cassini. */
+ #define PCI_ERR_BIM_DMA_READ 0x10 /* BIM received 0 count DMA read req.
+ unused in Cassini. */
+-#define PCI_ERR_BIM_DMA_TIMEOUT 0x20 /* BIM received 255 retries during
++#define PCI_ERR_BIM_DMA_TIMEOUT 0x20 /* BIM received 255 retries during
+ DMA. unused in cassini. */
+
+ /* mask for PCI status events that will set PCI_ERR_STATUS. if cleared, event
+- * causes an interrupt to be generated.
++ * causes an interrupt to be generated.
+ * DEFAULT: 0x7, SIZE: 3 bits
+ */
+ #define REG_PCI_ERR_STATUS_MASK 0x1004 /* PCI Error status mask */
+
+-/* used to configure PCI related parameters that are not in PCI config space.
++/* used to configure PCI related parameters that are not in PCI config space.
+ * DEFAULT: 0bxx000, SIZE: 5 bits
+ */
+ #define REG_BIM_CFG 0x1008 /* BIM Configuration */
+@@ -201,7 +201,7 @@
+ #define BIM_CFG_RMA_INTR_ENABLE 0x040 /* master abort intr enable */
+ #define BIM_CFG_RTA_INTR_ENABLE 0x080 /* target abort intr enable */
+ #define BIM_CFG_RESERVED2 0x100 /* reserved */
+-#define BIM_CFG_BIM_DISABLE 0x200 /* stop BIM DMA. use before global
++#define BIM_CFG_BIM_DISABLE 0x200 /* stop BIM DMA. use before global
+ reset. reserved in Cassini. */
+ #define BIM_CFG_BIM_STATUS 0x400 /* (ro) 1 = BIM DMA suspended.
+ reserved in Cassini. */
+@@ -212,7 +212,7 @@
+ #define REG_BIM_DIAG 0x100C /* BIM Diagnostic */
+ #define BIM_DIAG_MSTR_SM_MASK 0x3FFFFF00 /* PCI master controller state
+ machine bits [21:0] */
+-#define BIM_DIAG_BRST_SM_MASK 0x7F /* PCI burst controller state
++#define BIM_DIAG_BRST_SM_MASK 0x7F /* PCI burst controller state
+ machine bits [6:0] */
+
+ /* writing to SW_RESET_TX and SW_RESET_RX will issue a global
+@@ -224,14 +224,14 @@
+ #define SW_RESET_RX 0x00000002 /* reset RX DMA engine. poll until
+ cleared to 0. */
+ #define SW_RESET_RSTOUT 0x00000004 /* force RSTOUT# pin active (low).
+- resets PHY and anything else
++ resets PHY and anything else
+ connected to RSTOUT#. RSTOUT#
+ is also activated by local PCI
+- reset when hot-swap is being
++ reset when hot-swap is being
+ done. */
+-#define SW_RESET_BLOCK_PCS_SLINK 0x00000008 /* if a global reset is done with
+- this bit set, PCS and SLINK
+- modules won't be reset.
++#define SW_RESET_BLOCK_PCS_SLINK 0x00000008 /* if a global reset is done with
++ this bit set, PCS and SLINK
++ modules won't be reset.
+ i.e., link won't drop. */
+ #define SW_RESET_BREQ_SM_MASK 0x00007F00 /* breq state machine [6:0] */
+ #define SW_RESET_PCIARB_SM_MASK 0x00070000 /* pci arbitration state bits:
+@@ -252,7 +252,7 @@
+ 0b01: AD_ACK_RX
+ 0b10: AD_ACK_TX
+ 0b11: AD_IDL_TX */
+-#define SW_RESET_WRPCI_SM_MASK 0x06000000 /* write pci state bits
++#define SW_RESET_WRPCI_SM_MASK 0x06000000 /* write pci state bits
+ 0b00: WR_PCI_WAT
+ 0b01: WR_PCI_RDY
+ 0b11: WR_PCI_ACK */
+@@ -268,7 +268,7 @@
+ * value written has both lower and upper 32-bit halves rotated to the right
+ * one bit position. e.g., FFFFFFFF FFFFFFFF -> 7FFFFFFF 7FFFFFFF
+ */
+-#define REG_MINUS_BIM_DATAPATH_TEST 0x1018 /* Cassini: BIM datapath test
++#define REG_MINUS_BIM_DATAPATH_TEST 0x1018 /* Cassini: BIM datapath test
+ Cassini+: reserved */
+
+ /* output enables are provided for each device's chip select and for the rest
+@@ -276,12 +276,12 @@
+ * bits are connected to general purpus control/status bits.
+ * DEFAULT: 0x7
+ */
+-#define REG_BIM_LOCAL_DEV_EN 0x1020 /* BIM local device
++#define REG_BIM_LOCAL_DEV_EN 0x1020 /* BIM local device
+ output EN. default: 0x7 */
+ #define BIM_LOCAL_DEV_PAD 0x01 /* address bus, RW signal, and
+ OE signal output enable on the
+ local bus interface. these
+- are shared between both local
++ are shared between both local
+ bus devices. tristate when 0. */
+ #define BIM_LOCAL_DEV_PROM 0x02 /* PROM chip select */
+ #define BIM_LOCAL_DEV_EXT 0x04 /* secondary local bus device chip
+@@ -291,8 +291,8 @@
+ #define BIM_LOCAL_DEV_HW_RESET 0x20 /* internal hw reset. Cassini+ only. */
+
+ /* access 24 entry BIM read and write buffers. put address in REG_BIM_BUFFER_ADDR
+- * and read/write from/to it REG_BIM_BUFFER_DATA_LOW and _DATA_HI.
+- * _DATA_HI should be the last access of the sequence.
++ * and read/write from/to it REG_BIM_BUFFER_DATA_LOW and _DATA_HI.
++ * _DATA_HI should be the last access of the sequence.
+ * DEFAULT: undefined
+ */
+ #define REG_BIM_BUFFER_ADDR 0x1024 /* BIM buffer address. for
+@@ -304,10 +304,10 @@
+ #define REG_BIM_BUFFER_DATA_LOW 0x1028 /* BIM buffer data low */
+ #define REG_BIM_BUFFER_DATA_HI 0x102C /* BIM buffer data high */
+
+-/* set BIM_RAM_BIST_START to start built-in self test for BIM read buffer.
++/* set BIM_RAM_BIST_START to start built-in self test for BIM read buffer.
+ * bit auto-clears when done with status read from _SUMMARY and _PASS bits.
+ */
+-#define REG_BIM_RAM_BIST 0x102C /* BIM RAM (read buffer) BIST
++#define REG_BIM_RAM_BIST 0x102C /* BIM RAM (read buffer) BIST
+ control/status */
+ #define BIM_RAM_BIST_RD_START 0x01 /* start BIST for BIM read buffer */
+ #define BIM_RAM_BIST_WR_START 0x02 /* start BIST for BIM write buffer.
+@@ -321,7 +321,7 @@
+ #define BIM_RAM_BIST_RD_LOW_PASS 0x10 /* read low bank passes BIST */
+ #define BIM_RAM_BIST_RD_HI_PASS 0x20 /* read high bank passes BIST */
+ #define BIM_RAM_BIST_WR_LOW_PASS 0x40 /* write low bank passes BIST.
+- Cassini only. reserved in
++ Cassini only. reserved in
+ Cassini+. */
+ #define BIM_RAM_BIST_WR_HI_PASS 0x80 /* write high bank passes BIST.
+ Cassini only. reserved in
+@@ -333,7 +333,7 @@
+ #define REG_BIM_DIAG_MUX 0x1030 /* BIM diagnostic probe mux
+ select register */
+
+-/* enable probe monitoring mode and select data appearing on the P_A* bus. bit
++/* enable probe monitoring mode and select data appearing on the P_A* bus. bit
+ * values for _SEL_HI_MASK and _SEL_LOW_MASK:
+ * 0x0: internal probe[7:0] (pci arb state, wtc empty w, wtc full w, wtc empty w,
+ * wtc empty r, post pci)
+@@ -353,7 +353,7 @@
+ * 0xe: hp probe[7:0] 0xf: mac probe[7:0]
+ */
+ #define REG_PLUS_PROBE_MUX_SELECT 0x1034 /* Cassini+: PROBE MUX SELECT */
+-#define PROBE_MUX_EN 0x80000000 /* allow probe signals to be
++#define PROBE_MUX_EN 0x80000000 /* allow probe signals to be
+ driven on local bus P_A[15:0]
+ for debugging */
+ #define PROBE_MUX_SUB_MUX_MASK 0x0000FF00 /* select sub module probe signals:
+@@ -362,28 +362,28 @@
+ 0x30 = tx[1:0]
+ 0xC0 = hp[1:0] */
+ #define PROBE_MUX_SEL_HI_MASK 0x000000F0 /* select which module to appear
+- on P_A[15:8]. see above for
++ on P_A[15:8]. see above for
+ values. */
+ #define PROBE_MUX_SEL_LOW_MASK 0x0000000F /* select which module to appear
+- on P_A[7:0]. see above for
++ on P_A[7:0]. see above for
+ values. */
+
+-/* values mean the same thing as REG_INTR_MASK excep that it's for INTB.
++/* values mean the same thing as REG_INTR_MASK excep that it's for INTB.
+ DEFAULT: 0x1F */
+ #define REG_PLUS_INTR_MASK_1 0x1038 /* Cassini+: interrupt mask
+ register 2 for INTB */
+ #define REG_PLUS_INTRN_MASK(x) (REG_PLUS_INTR_MASK_1 + ((x) - 1)*16)
+-/* bits correspond to both _MASK and _STATUS registers. _ALT corresponds to
+- * all of the alternate (2-4) INTR registers while _1 corresponds to only
+- * _MASK_1 and _STATUS_1 registers.
++/* bits correspond to both _MASK and _STATUS registers. _ALT corresponds to
++ * all of the alternate (2-4) INTR registers while _1 corresponds to only
++ * _MASK_1 and _STATUS_1 registers.
+ * DEFAULT: 0x7 for MASK registers, 0x0 for ALIAS_CLEAR registers
+ */
+-#define INTR_RX_DONE_ALT 0x01
++#define INTR_RX_DONE_ALT 0x01
+ #define INTR_RX_COMP_FULL_ALT 0x02
+ #define INTR_RX_COMP_AF_ALT 0x04
+ #define INTR_RX_BUF_UNAVAIL_1 0x08
+ #define INTR_RX_BUF_AE_1 0x10 /* almost empty */
+-#define INTRN_MASK_RX_EN 0x80
++#define INTRN_MASK_RX_EN 0x80
+ #define INTRN_MASK_CLEAR_ALL (INTR_RX_DONE_ALT | \
+ INTR_RX_COMP_FULL_ALT | \
+ INTR_RX_COMP_AF_ALT | \
+@@ -399,7 +399,7 @@
+ register 2 for INTB */
+ #define REG_PLUS_ALIASN_CLEAR(x) (REG_PLUS_ALIAS_CLEAR_1 + ((x) - 1)*16)
+
+-#define REG_PLUS_INTR_STATUS_ALIAS_1 0x1044 /* Cassini+: interrupt status
++#define REG_PLUS_INTR_STATUS_ALIAS_1 0x1044 /* Cassini+: interrupt status
+ register alias 2 for INTB */
+ #define REG_PLUS_INTRN_STATUS_ALIAS(x) (REG_PLUS_INTR_STATUS_ALIAS_1 + ((x) - 1)*16)
+
+@@ -411,18 +411,18 @@
+ #define SATURN_PCFG_CLA 0x00000004 /* 1 = phy link100led */
+ #define SATURN_PCFG_LLA 0x00000008 /* 1 = phy link1000led */
+ #define SATURN_PCFG_RLA 0x00000010 /* 1 = phy duplexled */
+-#define SATURN_PCFG_PDS 0x00000020 /* phy debug mode.
++#define SATURN_PCFG_PDS 0x00000020 /* phy debug mode.
+ 0 = normal */
+-#define SATURN_PCFG_MTP 0x00000080 /* test point select */
+-#define SATURN_PCFG_GMO 0x00000100 /* GMII observe. 1 =
++#define SATURN_PCFG_MTP 0x00000080 /* test point select */
++#define SATURN_PCFG_GMO 0x00000100 /* GMII observe. 1 =
+ GMII on SERDES pins for
+ monitoring. */
+ #define SATURN_PCFG_FSI 0x00000200 /* 1 = freeze serdes/gmii. all
+ pins configed as outputs.
+ for power saving when using
+ internal phy. */
+-#define SATURN_PCFG_LAD 0x00000800 /* 0 = mac core led ctrl
+- polarity from strapping
++#define SATURN_PCFG_LAD 0x00000800 /* 0 = mac core led ctrl
++ polarity from strapping
+ value.
+ 1 = mac core led ctrl
+ polarity active low. */
+@@ -433,26 +433,26 @@
+ #define MAX_TX_RINGS (1 << MAX_TX_RINGS_SHIFT)
+ #define MAX_TX_RINGS_MASK (MAX_TX_RINGS - 1)
+
+-/* TX configuration.
+- * descr ring sizes size = 32 * (1 << n), n < 9. e.g., 0x8 = 8k. default: 0x8
++/* TX configuration.
++ * descr ring sizes size = 32 * (1 << n), n < 9. e.g., 0x8 = 8k. default: 0x8
+ * DEFAULT: 0x3F000001
+ */
+ #define REG_TX_CFG 0x2004 /* TX config */
+ #define TX_CFG_DMA_EN 0x00000001 /* enable TX DMA. if cleared, DMA
+ will stop after xfer of current
+ buffer has been completed. */
+-#define TX_CFG_FIFO_PIO_SEL 0x00000002 /* TX DMA FIFO can be
+- accessed w/ FIFO addr
+- and data registers.
+- TX DMA should be
++#define TX_CFG_FIFO_PIO_SEL 0x00000002 /* TX DMA FIFO can be
++ accessed w/ FIFO addr
++ and data registers.
++ TX DMA should be
+ disabled. */
+ #define TX_CFG_DESC_RING0_MASK 0x0000003C /* # desc entries in
+ ring 1. */
+ #define TX_CFG_DESC_RING0_SHIFT 2
+ #define TX_CFG_DESC_RINGN_MASK(a) (TX_CFG_DESC_RING0_MASK << (a)*4)
+ #define TX_CFG_DESC_RINGN_SHIFT(a) (TX_CFG_DESC_RING0_SHIFT + (a)*4)
+-#define TX_CFG_PACED_MODE 0x00100000 /* TX_ALL only set after
+- TX FIFO becomes empty.
++#define TX_CFG_PACED_MODE 0x00100000 /* TX_ALL only set after
++ TX FIFO becomes empty.
+ if 0, TX_ALL set
+ if descr queue empty. */
+ #define TX_CFG_DMA_RDPIPE_DIS 0x01000000 /* always set to 1 */
+@@ -470,26 +470,26 @@
+ through Q4 */
+ #define TX_CFG_INTR_COMPWB_DIS 0x20000000 /* disable pre-interrupt completion
+ writeback */
+-#define TX_CFG_CTX_SEL_MASK 0xC0000000 /* selects tx test port
++#define TX_CFG_CTX_SEL_MASK 0xC0000000 /* selects tx test port
+ connection
+- 0b00: tx mac req,
++ 0b00: tx mac req,
+ tx mac retry req,
+ tx ack and tx tag.
+- 0b01: txdma rd req,
++ 0b01: txdma rd req,
+ txdma rd ack,
+ txdma rd rdy,
+ txdma rd type0
+- 0b11: txdma wr req,
++ 0b11: txdma wr req,
+ txdma wr ack,
+ txdma wr rdy,
+ txdma wr xfr done. */
+ #define TX_CFG_CTX_SEL_SHIFT 30
+-
++
+ /* 11-bit counters that point to next location in FIFO to be loaded/retrieved.
+ * used for diagnostics only.
+ */
+ #define REG_TX_FIFO_WRITE_PTR 0x2014 /* TX FIFO write pointer */
+-#define REG_TX_FIFO_SHADOW_WRITE_PTR 0x2018 /* TX FIFO shadow write
++#define REG_TX_FIFO_SHADOW_WRITE_PTR 0x2018 /* TX FIFO shadow write
+ pointer. temp hold reg.
+ diagnostics only. */
+ #define REG_TX_FIFO_READ_PTR 0x201C /* TX FIFO read pointer */
+@@ -509,7 +509,7 @@
+ #define TX_SM_1_CACHE_MASK 0x03C00000 /* desc. prefetch cache controller
+ state machine */
+ #define TX_SM_1_CBQ_ARB_MASK 0xF8000000 /* CBQ arbiter state machine */
+-
++
+ #define REG_TX_SM_2 0x202C /* TX state machine reg #2 */
+ #define TX_SM_2_COMP_WB_MASK 0x07 /* completion writeback sm */
+ #define TX_SM_2_SUB_LOAD_MASK 0x38 /* sub load state machine */
+@@ -521,9 +521,9 @@
+ #define REG_TX_DATA_PTR_LOW 0x2030 /* TX data pointer low */
+ #define REG_TX_DATA_PTR_HI 0x2034 /* TX data pointer high */
+
+-/* 13 bit registers written by driver w/ descriptor value that follows
++/* 13 bit registers written by driver w/ descriptor value that follows
+ * last valid xmit descriptor. kick # and complete # values are used by
+- * the xmit dma engine to control tx descr fetching. if > 1 valid
++ * the xmit dma engine to control tx descr fetching. if > 1 valid
+ * tx descr is available within the cache line being read, cassini will
+ * internally cache up to 4 of them. 0 on reset. _KICK = rw, _COMP = ro.
+ */
+@@ -532,12 +532,12 @@
+ #define REG_TX_COMP0 0x2048 /* TX completion reg #1 */
+ #define REG_TX_COMPN(x) (REG_TX_COMP0 + (x)*4)
+
+-/* values of TX_COMPLETE_1-4 are written. each completion register
+- * is 2bytes in size and contiguous. 8B allocation w/ 8B alignment.
++/* values of TX_COMPLETE_1-4 are written. each completion register
++ * is 2bytes in size and contiguous. 8B allocation w/ 8B alignment.
+ * NOTE: completion reg values are only written back prior to TX_INTME and
+- * TX_ALL interrupts. at all other times, the most up-to-date index values
+- * should be obtained from the REG_TX_COMPLETE_# registers.
+- * here's the layout:
++ * TX_ALL interrupts. at all other times, the most up-to-date index values
++ * should be obtained from the REG_TX_COMPLETE_# registers.
++ * here's the layout:
+ * offset from base addr completion # byte
+ * 0 TX_COMPLETE_1_MSB
+ * 1 TX_COMPLETE_1_LSB
+@@ -558,7 +558,7 @@
+ #define TX_COMPWB_LSB_MASK 0x000000000000FF00ULL
+ #define TX_COMPWB_LSB_SHIFT 8
+ #define TX_COMPWB_NEXT(x) ((x) >> 16)
+-
++
+ /* 53 MSB used as base address. 11 LSB assumed to be 0. TX desc pointer must
+ * be 2KB-aligned. */
+ #define REG_TX_DB0_LOW 0x2060 /* TX descriptor base low #1 */
+@@ -594,11 +594,11 @@
+ #define REG_TX_FIFO_DATA_HI_T0 0x2114 /* TX FIFO data high t0 */
+ #define REG_TX_FIFO_SIZE 0x2118 /* (ro) TX FIFO size = 0x090 = 9KB */
+
+-/* 9-bit register controls BIST of TX FIFO. bit set indicates that the BIST
++/* 9-bit register controls BIST of TX FIFO. bit set indicates that the BIST
+ * passed for the specified memory
+ */
+ #define REG_TX_RAMBIST 0x211C /* TX RAMBIST control/status */
+-#define TX_RAMBIST_STATE 0x01C0 /* progress state of RAMBIST
++#define TX_RAMBIST_STATE 0x01C0 /* progress state of RAMBIST
+ controller state machine */
+ #define TX_RAMBIST_RAM33A_PASS 0x0020 /* RAM33A passed */
+ #define TX_RAMBIST_RAM32A_PASS 0x0010 /* RAM32A passed */
+@@ -612,33 +612,33 @@
+ #define MAX_RX_DESC_RINGS 2
+ #define MAX_RX_COMP_RINGS 4
+
+-/* receive DMA channel configuration. default: 0x80910
++/* receive DMA channel configuration. default: 0x80910
+ * free ring size = (1 << n)*32 -> [32 - 8k]
+- * completion ring size = (1 << n)*128 -> [128 - 32k], n < 9
++ * completion ring size = (1 << n)*128 -> [128 - 32k], n < 9
+ * DEFAULT: 0x80910
+ */
+ #define REG_RX_CFG 0x4000 /* RX config */
+ #define RX_CFG_DMA_EN 0x00000001 /* enable RX DMA. 0 stops
+ channel as soon as current
+ frame xfer has completed.
+- driver should disable MAC
+- for 200ms before disabling
++ driver should disable MAC
++ for 200ms before disabling
+ RX */
+-#define RX_CFG_DESC_RING_MASK 0x0000001E /* # desc entries in RX
+- free desc ring.
++#define RX_CFG_DESC_RING_MASK 0x0000001E /* # desc entries in RX
++ free desc ring.
+ def: 0x8 = 8k */
+ #define RX_CFG_DESC_RING_SHIFT 1
+ #define RX_CFG_COMP_RING_MASK 0x000001E0 /* # desc entries in RX complete
+ ring. def: 0x8 = 32k */
+ #define RX_CFG_COMP_RING_SHIFT 5
+-#define RX_CFG_BATCH_DIS 0x00000200 /* disable receive desc
++#define RX_CFG_BATCH_DIS 0x00000200 /* disable receive desc
+ batching. def: 0x0 =
+ enabled */
+-#define RX_CFG_SWIVEL_MASK 0x00001C00 /* byte offset of the 1st
+- data byte of the packet
++#define RX_CFG_SWIVEL_MASK 0x00001C00 /* byte offset of the 1st
++ data byte of the packet
+ w/in 8 byte boundares.
+- this swivels the data
+- DMA'ed to header
++ this swivels the data
++ DMA'ed to header
+ buffers, jumbo buffers
+ when header split is not
+ requested and MTU sized
+@@ -647,17 +647,17 @@
+
+ /* cassini+ only */
+ #define RX_CFG_DESC_RING1_MASK 0x000F0000 /* # of desc entries in
+- RX free desc ring 2.
++ RX free desc ring 2.
+ def: 0x8 = 8k */
+ #define RX_CFG_DESC_RING1_SHIFT 16
+
+
+-/* the page size register allows cassini chips to do the following with
++/* the page size register allows cassini chips to do the following with
+ * received data:
+ * [--------------------------------------------------------------] page
+ * [off][buf1][pad][off][buf2][pad][off][buf3][pad][off][buf4][pad]
+ * |--------------| = PAGE_SIZE_BUFFER_STRIDE
+- * page = PAGE_SIZE
++ * page = PAGE_SIZE
+ * offset = PAGE_SIZE_MTU_OFF
+ * for the above example, MTU_BUFFER_COUNT = 4.
+ * NOTE: as is apparent, you need to ensure that the following holds:
+@@ -667,20 +667,20 @@
+ #define REG_RX_PAGE_SIZE 0x4004 /* RX page size */
+ #define RX_PAGE_SIZE_MASK 0x00000003 /* size of pages pointed to
+ by receive descriptors.
+- if jumbo buffers are
+- supported the page size
++ if jumbo buffers are
++ supported the page size
+ should not be < 8k.
+ 0b00 = 2k, 0b01 = 4k
+ 0b10 = 8k, 0b11 = 16k
+ DEFAULT: 8k */
+ #define RX_PAGE_SIZE_SHIFT 0
+ #define RX_PAGE_SIZE_MTU_COUNT_MASK 0x00007800 /* # of MTU buffers the hw
+- packs into a page.
++ packs into a page.
+ DEFAULT: 4 */
+ #define RX_PAGE_SIZE_MTU_COUNT_SHIFT 11
+ #define RX_PAGE_SIZE_MTU_STRIDE_MASK 0x18000000 /* # of bytes that separate
+- each MTU buffer +
+- offset from each
++ each MTU buffer +
++ offset from each
+ other.
+ 0b00 = 1k, 0b01 = 2k
+ 0b10 = 4k, 0b11 = 8k
+@@ -688,24 +688,24 @@
+ #define RX_PAGE_SIZE_MTU_STRIDE_SHIFT 27
+ #define RX_PAGE_SIZE_MTU_OFF_MASK 0xC0000000 /* offset in each page that
+ hw writes the MTU buffer
+- into.
+- 0b00 = 0,
++ into.
++ 0b00 = 0,
+ 0b01 = 64 bytes
+ 0b10 = 96, 0b11 = 128
+ DEFAULT: 0x1 */
+ #define RX_PAGE_SIZE_MTU_OFF_SHIFT 30
+-
+-/* 11-bit counter points to next location in RX FIFO to be loaded/read.
++
++/* 11-bit counter points to next location in RX FIFO to be loaded/read.
+ * shadow write pointers enable retries in case of early receive aborts.
+ * DEFAULT: 0x0. generated on 64-bit boundaries.
+ */
+ #define REG_RX_FIFO_WRITE_PTR 0x4008 /* RX FIFO write pointer */
+ #define REG_RX_FIFO_READ_PTR 0x400C /* RX FIFO read pointer */
+-#define REG_RX_IPP_FIFO_SHADOW_WRITE_PTR 0x4010 /* RX IPP FIFO shadow write
++#define REG_RX_IPP_FIFO_SHADOW_WRITE_PTR 0x4010 /* RX IPP FIFO shadow write
+ pointer */
+ #define REG_RX_IPP_FIFO_SHADOW_READ_PTR 0x4014 /* RX IPP FIFO shadow read
+ pointer */
+-#define REG_RX_IPP_FIFO_READ_PTR 0x400C /* RX IPP FIFO read
++#define REG_RX_IPP_FIFO_READ_PTR 0x400C /* RX IPP FIFO read
+ pointer. (8-bit counter) */
+
+ /* current state of RX DMA state engines + other info
+@@ -738,7 +738,7 @@
+ 0x2 = wait xon
+ 0x3 = wait xon ack */
+ #define RX_DEBUG_DATA_STATE_MASK 0x000001E00 /* unload data state machine
+- states:
++ states:
+ 0x0 = idle data
+ 0x1 = header begin
+ 0x2 = xfer header
+@@ -747,7 +747,7 @@
+ 0x5 = xfer mtu
+ 0x6 = xfer mtu ld
+ 0x7 = jumbo begin
+- 0x8 = xfer jumbo
++ 0x8 = xfer jumbo
+ 0x9 = xfer jumbo ld
+ 0xa = reas begin
+ 0xb = xfer reas
+@@ -776,15 +776,15 @@
+ * XOFF PAUSE uses pause time value pre-programmed in the Send PAUSE MAC reg
+ * XON PAUSE uses a pause time of 0. granularity of threshold is 64bytes.
+ * PAUSE thresholds defined in terms of FIFO occupancy and may be translated
+- * into FIFO vacancy using RX_FIFO_SIZE. setting ON will trigger XON frames
++ * into FIFO vacancy using RX_FIFO_SIZE. setting ON will trigger XON frames
+ * when FIFO reaches 0. OFF threshold should not be > size of RX FIFO. max
+- * value is is 0x6F.
++ * value is is 0x6F.
+ * DEFAULT: 0x00078
+ */
+ #define REG_RX_PAUSE_THRESH 0x4020 /* RX pause thresholds */
+ #define RX_PAUSE_THRESH_QUANTUM 64
+ #define RX_PAUSE_THRESH_OFF_MASK 0x000001FF /* XOFF PAUSE emitted when
+- RX FIFO occupancy >
++ RX FIFO occupancy >
+ value*64B */
+ #define RX_PAUSE_THRESH_OFF_SHIFT 0
+ #define RX_PAUSE_THRESH_ON_MASK 0x001FF000 /* XON PAUSE emitted after
+@@ -797,9 +797,9 @@
+ #define RX_PAUSE_THRESH_ON_SHIFT 12
+
+ /* 13-bit register used to control RX desc fetching and intr generation. if 4+
+- * valid RX descriptors are available, Cassini will read 4 at a time.
++ * valid RX descriptors are available, Cassini will read 4 at a time.
+ * writing N means that all desc up to *but* excluding N are available. N must
+- * be a multiple of 4 (N % 4 = 0). first desc should be cache-line aligned.
++ * be a multiple of 4 (N % 4 = 0). first desc should be cache-line aligned.
+ * DEFAULT: 0 on reset
+ */
+ #define REG_RX_KICK 0x4024 /* RX kick reg */
+@@ -807,16 +807,16 @@
+ /* 8KB aligned 64-bit pointer to the base of the RX free/completion rings.
+ * lower 13 bits of the low register are hard-wired to 0.
+ */
+-#define REG_RX_DB_LOW 0x4028 /* RX descriptor ring
++#define REG_RX_DB_LOW 0x4028 /* RX descriptor ring
+ base low */
+ #define REG_RX_DB_HI 0x402C /* RX descriptor ring
+ base hi */
+ #define REG_RX_CB_LOW 0x4030 /* RX completion ring
+ base low */
+-#define REG_RX_CB_HI 0x4034 /* RX completion ring
++#define REG_RX_CB_HI 0x4034 /* RX completion ring
+ base hi */
+ /* 13-bit register indicate desc used by cassini for receive frames. used
+- * for diagnostic purposes.
++ * for diagnostic purposes.
+ * DEFAULT: 0 on reset
+ */
+ #define REG_RX_COMP 0x4038 /* (ro) RX completion */
+@@ -837,9 +837,9 @@
+ /* values used for receive interrupt blanking. loaded each time the ISR is read
+ * DEFAULT: 0x00000000
+ */
+-#define REG_RX_BLANK 0x4044 /* RX blanking register
++#define REG_RX_BLANK 0x4044 /* RX blanking register
+ for ISR read */
+-#define RX_BLANK_INTR_PKT_MASK 0x000001FF /* RX_DONE intr asserted if
++#define RX_BLANK_INTR_PKT_MASK 0x000001FF /* RX_DONE intr asserted if
+ this many sets of completion
+ writebacks (up to 2 packets)
+ occur since the last time
+@@ -849,33 +849,33 @@
+ #define RX_BLANK_INTR_TIME_MASK 0x3FFFF000 /* RX_DONE interrupt asserted
+ if that many clocks were
+ counted since last time the
+- ISR was read.
++ ISR was read.
+ each count is 512 core
+ clocks (125MHz). 0 = no
+ time blanking */
+ #define RX_BLANK_INTR_TIME_SHIFT 12
+
+-/* values used for interrupt generation based on threshold values of how
++/* values used for interrupt generation based on threshold values of how
+ * many free desc and completion entries are available for hw use.
+ * DEFAULT: 0x00000000
+ */
+-#define REG_RX_AE_THRESH 0x4048 /* RX almost empty
++#define REG_RX_AE_THRESH 0x4048 /* RX almost empty
+ thresholds */
+-#define RX_AE_THRESH_FREE_MASK 0x00001FFF /* RX_BUF_AE will be
++#define RX_AE_THRESH_FREE_MASK 0x00001FFF /* RX_BUF_AE will be
+ generated if # desc
+- avail for hw use <=
++ avail for hw use <=
+ # */
+ #define RX_AE_THRESH_FREE_SHIFT 0
+ #define RX_AE_THRESH_COMP_MASK 0x0FFFE000 /* RX_COMP_AE will be
+- generated if # of
++ generated if # of
+ completion entries
+- avail for hw use <=
++ avail for hw use <=
+ # */
+ #define RX_AE_THRESH_COMP_SHIFT 13
+
+-/* probabilities for random early drop (RED) thresholds on a FIFO threshold
+- * basis. probability should increase when the FIFO level increases. control
+- * packets are never dropped and not counted in stats. probability programmed
++/* probabilities for random early drop (RED) thresholds on a FIFO threshold
++ * basis. probability should increase when the FIFO level increases. control
++ * packets are never dropped and not counted in stats. probability programmed
+ * on a 12.5% granularity. e.g., 0x1 = 1/8 packets dropped.
+ * DEFAULT: 0x00000000
+ */
+@@ -885,8 +885,8 @@
+ #define RX_RED_8K_10K_FIFO_MASK 0x00FF0000 /* 8KB < FIFO thresh < 10KB */
+ #define RX_RED_10K_12K_FIFO_MASK 0xFF000000 /* 10KB < FIFO thresh < 12KB */
+
+-/* FIFO fullness levels for RX FIFO, RX control FIFO, and RX IPP FIFO.
+- * RX control FIFO = # of packets in RX FIFO.
++/* FIFO fullness levels for RX FIFO, RX control FIFO, and RX IPP FIFO.
++ * RX control FIFO = # of packets in RX FIFO.
+ * DEFAULT: 0x0
+ */
+ #define REG_RX_FIFO_FULLNESS 0x4050 /* (ro) RX FIFO fullness */
+@@ -895,12 +895,12 @@
+ #define RX_FIFO_FULLNESS_RX_PKT_MASK 0x000000FF /* # packets in RX FIFO */
+ #define REG_RX_IPP_PACKET_COUNT 0x4054 /* RX IPP packet counter */
+ #define REG_RX_WORK_DMA_PTR_LOW 0x4058 /* RX working DMA ptr low */
+-#define REG_RX_WORK_DMA_PTR_HI 0x405C /* RX working DMA ptr
++#define REG_RX_WORK_DMA_PTR_HI 0x405C /* RX working DMA ptr
+ high */
+
+ /* BIST testing ro RX FIFO, RX control FIFO, and RX IPP FIFO. only RX BIST
+ * START/COMPLETE is writeable. START will clear when the BIST has completed
+- * checking all 17 RAMS.
++ * checking all 17 RAMS.
+ * DEFAULT: 0bxxxx xxxxx xxxx xxxx xxxx x000 0000 0000 00x0
+ */
+ #define REG_RX_BIST 0x4060 /* (ro) RX BIST */
+@@ -923,41 +923,41 @@
+ #define RX_BIST_REAS_27_PASS 0x00080000 /* RX Reas 27 passed */
+ #define RX_BIST_STATE_MASK 0x00078000 /* BIST state machine */
+ #define RX_BIST_SUMMARY 0x00000002 /* when BIST complete,
+- summary pass bit
++ summary pass bit
+ contains AND of BIST
+ results of all 16
+ RAMS */
+-#define RX_BIST_START 0x00000001 /* write 1 to start
++#define RX_BIST_START 0x00000001 /* write 1 to start
+ BIST. self clears
+ on completion. */
+
+ /* next location in RX CTRL FIFO that will be loaded w/ data from RX IPP/read
+- * from to retrieve packet control info.
++ * from to retrieve packet control info.
+ * DEFAULT: 0
+ */
+-#define REG_RX_CTRL_FIFO_WRITE_PTR 0x4064 /* (ro) RX control FIFO
++#define REG_RX_CTRL_FIFO_WRITE_PTR 0x4064 /* (ro) RX control FIFO
+ write ptr */
+ #define REG_RX_CTRL_FIFO_READ_PTR 0x4068 /* (ro) RX control FIFO read
+ ptr */
+
+ /* receive interrupt blanking. loaded each time interrupt alias register is
+- * read.
++ * read.
+ * DEFAULT: 0x0
+ */
+ #define REG_RX_BLANK_ALIAS_READ 0x406C /* RX blanking register for
+ alias read */
+-#define RX_BAR_INTR_PACKET_MASK 0x000001FF /* assert RX_DONE if #
+- completion writebacks
+- > # since last ISR
+- read. 0 = no
+- blanking. up to 2
+- packets per
++#define RX_BAR_INTR_PACKET_MASK 0x000001FF /* assert RX_DONE if #
++ completion writebacks
++ > # since last ISR
++ read. 0 = no
++ blanking. up to 2
++ packets per
+ completion wb. */
+ #define RX_BAR_INTR_TIME_MASK 0x3FFFF000 /* assert RX_DONE if #
+ clocks > # since last
+ ISR read. each count
+ is 512 core clocks
+- (125MHz). 0 = no
++ (125MHz). 0 = no
+ blanking. */
+
+ /* diagnostic access to RX FIFO. 32 LSB accessed via DATA_LOW. 32 MSB accessed
+@@ -981,13 +981,13 @@
+ * should be last write access of the write sequence.
+ * DEFAULT: undefined
+ */
+-#define REG_RX_CTRL_FIFO_ADDR 0x4094 /* RX Control FIFO and
++#define REG_RX_CTRL_FIFO_ADDR 0x4094 /* RX Control FIFO and
+ Batching FIFO addr */
+-#define REG_RX_CTRL_FIFO_DATA_LOW 0x4098 /* RX Control FIFO data
++#define REG_RX_CTRL_FIFO_DATA_LOW 0x4098 /* RX Control FIFO data
+ low */
+-#define REG_RX_CTRL_FIFO_DATA_MID 0x409C /* RX Control FIFO data
++#define REG_RX_CTRL_FIFO_DATA_MID 0x409C /* RX Control FIFO data
+ mid */
+-#define REG_RX_CTRL_FIFO_DATA_HI 0x4100 /* RX Control FIFO data
++#define REG_RX_CTRL_FIFO_DATA_HI 0x4100 /* RX Control FIFO data
+ hi and flow id */
+ #define RX_CTRL_FIFO_DATA_HI_CTRL 0x0001 /* upper bit of ctrl word */
+ #define RX_CTRL_FIFO_DATA_HI_FLOW_MASK 0x007E /* flow id */
+@@ -1004,7 +1004,7 @@
+ T1 */
+
+ /* 64-bit pointer to receive data buffer in host memory used for headers and
+- * small packets. MSB in high register. loaded by DMA state machine and
++ * small packets. MSB in high register. loaded by DMA state machine and
+ * increments as DMA writes receive data. only 50 LSB are incremented. top
+ * 13 bits taken from RX descriptor.
+ * DEFAULT: undefined
+@@ -1013,17 +1013,17 @@
+ low */
+ #define REG_RX_HEADER_PAGE_PTR_HI 0x411C /* (ro) RX header page ptr
+ high */
+-#define REG_RX_MTU_PAGE_PTR_LOW 0x4120 /* (ro) RX MTU page pointer
++#define REG_RX_MTU_PAGE_PTR_LOW 0x4120 /* (ro) RX MTU page pointer
+ low */
+-#define REG_RX_MTU_PAGE_PTR_HI 0x4124 /* (ro) RX MTU page pointer
++#define REG_RX_MTU_PAGE_PTR_HI 0x4124 /* (ro) RX MTU page pointer
+ high */
+
+ /* PIO diagnostic access to RX reassembly DMA Table RAM. 6-bit register holds
+ * one of 64 79-bit locations in the RX Reassembly DMA table and the addr of
+- * one of the 64 byte locations in the Batching table. LOW holds 32 LSB.
++ * one of the 64 byte locations in the Batching table. LOW holds 32 LSB.
+ * MID holds the next 32 LSB. HIGH holds the 15 MSB. RX_DMA_EN must be set
+ * to 0 for PIO access. DATA_HIGH should be last write of write sequence.
+- * layout:
++ * layout:
+ * reassmbl ptr [78:15] | reassmbl index [14:1] | reassmbl entry valid [0]
+ * DEFAULT: undefined
+ */
+@@ -1033,7 +1033,7 @@
+
+ #define REG_RX_TABLE_DATA_LOW 0x412C /* RX reassembly DMA table
+ data low */
+-#define REG_RX_TABLE_DATA_MID 0x4130 /* RX reassembly DMA table
++#define REG_RX_TABLE_DATA_MID 0x4130 /* RX reassembly DMA table
+ data mid */
+ #define REG_RX_TABLE_DATA_HI 0x4134 /* RX reassembly DMA table
+ data high */
+@@ -1053,11 +1053,11 @@
+ #define REG_PLUS_RX_CBN_LOW(x) (REG_PLUS_RX_CB1_LOW + 8*((x) - 1))
+ #define REG_PLUS_RX_CBN_HI(x) (REG_PLUS_RX_CB1_HI + 8*((x) - 1))
+ #define REG_PLUS_RX_KICK1 0x4220 /* RX Kick 2 register */
+-#define REG_PLUS_RX_COMP1 0x4224 /* (ro) RX completion 2
++#define REG_PLUS_RX_COMP1 0x4224 /* (ro) RX completion 2
+ reg */
+-#define REG_PLUS_RX_COMP1_HEAD 0x4228 /* (ro) RX completion 2
++#define REG_PLUS_RX_COMP1_HEAD 0x4228 /* (ro) RX completion 2
+ head reg. 4 total. */
+-#define REG_PLUS_RX_COMP1_TAIL 0x422C /* RX completion 2
++#define REG_PLUS_RX_COMP1_TAIL 0x422C /* RX completion 2
+ tail reg. 4 total. */
+ #define REG_PLUS_RX_COMPN_HEAD(x) (REG_PLUS_RX_COMP1_HEAD + 8*((x) - 1))
+ #define REG_PLUS_RX_COMPN_TAIL(x) (REG_PLUS_RX_COMP1_TAIL + 8*((x) - 1))
+@@ -1068,13 +1068,13 @@
+
+ /** header parser registers **/
+
+-/* RX parser configuration register.
++/* RX parser configuration register.
+ * DEFAULT: 0x1651004
+ */
+-#define REG_HP_CFG 0x4140 /* header parser
++#define REG_HP_CFG 0x4140 /* header parser
+ configuration reg */
+ #define HP_CFG_PARSE_EN 0x00000001 /* enab header parsing */
+-#define HP_CFG_NUM_CPU_MASK 0x000000FC /* # processors
++#define HP_CFG_NUM_CPU_MASK 0x000000FC /* # processors
+ 0 = 64. 0x3f = 63 */
+ #define HP_CFG_NUM_CPU_SHIFT 2
+ #define HP_CFG_SYN_INC_MASK 0x00000100 /* SYN bit won't increment
+@@ -1088,7 +1088,7 @@
+ /* access to RX Instruction RAM. 5-bit register/counter holds addr
+ * of 39 bit entry to be read/written. 32 LSB in _DATA_LOW. 7 MSB in _DATA_HI.
+ * RX_DMA_EN must be 0 for RX instr PIO access. DATA_HI should be last access
+- * of sequence.
++ * of sequence.
+ * DEFAULT: undefined
+ */
+ #define REG_HP_INSTR_RAM_ADDR 0x4144 /* HP instruction RAM
+@@ -1104,7 +1104,7 @@
+ #define HP_INSTR_RAM_LOW_OUTEN_SHIFT 20
+ #define HP_INSTR_RAM_LOW_OUTARG_MASK 0xFFC00000
+ #define HP_INSTR_RAM_LOW_OUTARG_SHIFT 22
+-#define REG_HP_INSTR_RAM_DATA_MID 0x414C /* HP instruction RAM
++#define REG_HP_INSTR_RAM_DATA_MID 0x414C /* HP instruction RAM
+ data mid */
+ #define HP_INSTR_RAM_MID_OUTARG_MASK 0x00000003
+ #define HP_INSTR_RAM_MID_OUTARG_SHIFT 0
+@@ -1131,7 +1131,7 @@
+ * 11-bit register. Data fills the LSB portion of bus if less than 32 bits.
+ * DATA_RAM: write RAM_FDB_DATA with index to access DATA_RAM.
+ * RAM bytes = 4*(x - 1) + [3:0]. e.g., 0 -> [3:0], 31 -> [123:120]
+- * FLOWDB: write DATA_RAM_FDB register and then read/write FDB1-12 to access
++ * FLOWDB: write DATA_RAM_FDB register and then read/write FDB1-12 to access
+ * flow database.
+ * RX_DMA_EN must be 0 for RX parser RAM PIO access. RX Parser RAM data reg
+ * should be the last write access of the write sequence.
+@@ -1139,17 +1139,17 @@
+ */
+ #define REG_HP_DATA_RAM_FDB_ADDR 0x4154 /* HP data and FDB
+ RAM address */
+-#define HP_DATA_RAM_FDB_DATA_MASK 0x001F /* select 1 of 86 byte
+- locations in header
+- parser data ram to
++#define HP_DATA_RAM_FDB_DATA_MASK 0x001F /* select 1 of 86 byte
++ locations in header
++ parser data ram to
+ read/write */
+ #define HP_DATA_RAM_FDB_FDB_MASK 0x3F00 /* 1 of 64 353-bit locations
+ in the flow database */
+ #define REG_HP_DATA_RAM_DATA 0x4158 /* HP data RAM data */
+
+-/* HP flow database registers: 1 - 12, 0x415C - 0x4188, 4 8-bit bytes
++/* HP flow database registers: 1 - 12, 0x415C - 0x4188, 4 8-bit bytes
+ * FLOW_DB(1) = IP_SA[127:96], FLOW_DB(2) = IP_SA[95:64]
+- * FLOW_DB(3) = IP_SA[63:32], FLOW_DB(4) = IP_SA[31:0]
++ * FLOW_DB(3) = IP_SA[63:32], FLOW_DB(4) = IP_SA[31:0]
+ * FLOW_DB(5) = IP_DA[127:96], FLOW_DB(6) = IP_DA[95:64]
+ * FLOW_DB(7) = IP_DA[63:32], FLOW_DB(8) = IP_DA[31:0]
+ * FLOW_DB(9) = {TCP_SP[15:0],TCP_DP[15:0]}
+@@ -1159,7 +1159,7 @@
+ #define REG_HP_FLOW_DB0 0x415C /* HP flow database 1 reg */
+ #define REG_HP_FLOW_DBN(x) (REG_HP_FLOW_DB0 + (x)*4)
+
+-/* diagnostics for RX Header Parser block.
++/* diagnostics for RX Header Parser block.
+ * ASUN: the header parser state machine register is used for diagnostics
+ * purposes. however, the spec doesn't have any details on it.
+ */
+@@ -1167,7 +1167,7 @@
+ #define REG_HP_STATUS0 0x4190 /* (ro) HP status 1 */
+ #define HP_STATUS0_SAP_MASK 0xFFFF0000 /* SAP */
+ #define HP_STATUS0_L3_OFF_MASK 0x0000FE00 /* L3 offset */
+-#define HP_STATUS0_LB_CPUNUM_MASK 0x000001F8 /* load balancing CPU
++#define HP_STATUS0_LB_CPUNUM_MASK 0x000001F8 /* load balancing CPU
+ number */
+ #define HP_STATUS0_HRP_OPCODE_MASK 0x00000007 /* HRP opcode */
+
+@@ -1179,11 +1179,11 @@
+
+ #define REG_HP_STATUS2 0x4198 /* (ro) HP status 3 */
+ #define HP_STATUS2_ACCUR2_MASK 0xF0000000 /* accu R2[3:0] */
+-#define HP_STATUS2_CSUM_OFF_MASK 0x07F00000 /* checksum start
++#define HP_STATUS2_CSUM_OFF_MASK 0x07F00000 /* checksum start
+ start offset */
+ #define HP_STATUS2_ACCUR1_MASK 0x000FE000 /* accu R1 */
+ #define HP_STATUS2_FORCE_DROP 0x00001000 /* force drop */
+-#define HP_STATUS2_BWO_REASSM 0x00000800 /* batching w/o
++#define HP_STATUS2_BWO_REASSM 0x00000800 /* batching w/o
+ reassembly */
+ #define HP_STATUS2_JH_SPLIT_EN 0x00000400 /* jumbo header split
+ enable */
+@@ -1191,9 +1191,9 @@
+ check */
+ #define HP_STATUS2_DATA_MASK_ZERO 0x00000100 /* mask of data length
+ equal to zero */
+-#define HP_STATUS2_FORCE_TCP_CHECK 0x00000080 /* force tcp payload
++#define HP_STATUS2_FORCE_TCP_CHECK 0x00000080 /* force tcp payload
+ chk */
+-#define HP_STATUS2_MASK_TCP_THRESH 0x00000040 /* mask of payload
++#define HP_STATUS2_MASK_TCP_THRESH 0x00000040 /* mask of payload
+ threshold */
+ #define HP_STATUS2_NO_ASSIST 0x00000020 /* no assist */
+ #define HP_STATUS2_CTRL_PACKET_FLAG 0x00000010 /* control packet flag */
+@@ -1214,7 +1214,7 @@
+ #define HP_RAM_BIST_HP_INSTR2_PASS 0x10000000 /* HP instr ram 2 */
+ #define HP_RAM_BIST_FDBM_AGE0_PASS 0x08000000 /* FDBM aging RAM0 */
+ #define HP_RAM_BIST_FDBM_AGE1_PASS 0x04000000 /* FDBM aging RAM1 */
+-#define HP_RAM_BIST_FDBM_FLOWID00_PASS 0x02000000 /* FDBM flowid RAM0
++#define HP_RAM_BIST_FDBM_FLOWID00_PASS 0x02000000 /* FDBM flowid RAM0
+ bank 0 */
+ #define HP_RAM_BIST_FDBM_FLOWID10_PASS 0x01000000 /* FDBM flowid RAM1
+ bank 0 */
+@@ -1247,25 +1247,25 @@
+ /* execute a pause flow control frame transmission
+ DEFAULT: 0x0XXXX */
+ #define REG_MAC_SEND_PAUSE 0x6008 /* send pause command reg */
+-#define MAC_SEND_PAUSE_TIME_MASK 0x0000FFFF /* value of pause time
++#define MAC_SEND_PAUSE_TIME_MASK 0x0000FFFF /* value of pause time
+ to be sent on network
+- in units of slot
++ in units of slot
+ times */
+ #define MAC_SEND_PAUSE_SEND 0x00010000 /* send pause flow ctrl
+ frame on network */
+
+ /* bit set indicates that event occurred. auto-cleared when status register
+- * is read and have corresponding mask bits in mask register. events will
+- * trigger an interrupt if the corresponding mask bit is 0.
++ * is read and have corresponding mask bits in mask register. events will
++ * trigger an interrupt if the corresponding mask bit is 0.
+ * status register default: 0x00000000
+ * mask register default = 0xFFFFFFFF on reset
+ */
+ #define REG_MAC_TX_STATUS 0x6010 /* TX MAC status reg */
+-#define MAC_TX_FRAME_XMIT 0x0001 /* successful frame
++#define MAC_TX_FRAME_XMIT 0x0001 /* successful frame
+ transmision */
+-#define MAC_TX_UNDERRUN 0x0002 /* terminated frame
++#define MAC_TX_UNDERRUN 0x0002 /* terminated frame
+ transmission due to
+- data starvation in the
++ data starvation in the
+ xmit data path */
+ #define MAC_TX_MAX_PACKET_ERR 0x0004 /* frame exceeds max allowed
+ length passed to TX MAC
+@@ -1286,7 +1286,7 @@
+ #define REG_MAC_RX_STATUS 0x6014 /* RX MAC status reg */
+ #define MAC_RX_FRAME_RECV 0x0001 /* successful receipt of
+ a frame */
+-#define MAC_RX_OVERFLOW 0x0002 /* dropped frame due to
++#define MAC_RX_OVERFLOW 0x0002 /* dropped frame due to
+ RX FIFO overflow */
+ #define MAC_RX_FRAME_COUNT 0x0004 /* rollover of receive frame
+ counter */
+@@ -1294,27 +1294,27 @@
+ error counter */
+ #define MAC_RX_CRC_ERR 0x0010 /* rollover of crc error
+ counter */
+-#define MAC_RX_LEN_ERR 0x0020 /* rollover of length
++#define MAC_RX_LEN_ERR 0x0020 /* rollover of length
+ error counter */
+-#define MAC_RX_VIOL_ERR 0x0040 /* rollover of code
++#define MAC_RX_VIOL_ERR 0x0040 /* rollover of code
+ violation error */
+
+ /* DEFAULT: 0xXXXX0000 on reset */
+ #define REG_MAC_CTRL_STATUS 0x6018 /* MAC control status reg */
+-#define MAC_CTRL_PAUSE_RECEIVED 0x00000001 /* successful
+- reception of a
+- pause control
++#define MAC_CTRL_PAUSE_RECEIVED 0x00000001 /* successful
++ reception of a
++ pause control
+ frame */
+-#define MAC_CTRL_PAUSE_STATE 0x00000002 /* MAC has made a
+- transition from
+- "not paused" to
++#define MAC_CTRL_PAUSE_STATE 0x00000002 /* MAC has made a
++ transition from
++ "not paused" to
+ "paused" */
+-#define MAC_CTRL_NOPAUSE_STATE 0x00000004 /* MAC has made a
+- transition from
++#define MAC_CTRL_NOPAUSE_STATE 0x00000004 /* MAC has made a
++ transition from
+ "paused" to "not
+ paused" */
+ #define MAC_CTRL_PAUSE_TIME_MASK 0xFFFF0000 /* value of pause time
+- operand that was
++ operand that was
+ received in the last
+ pause flow control
+ frame */
+@@ -1326,13 +1326,13 @@
+ /* layout identical to CTRL MAC[2:0] */
+ #define REG_MAC_CTRL_MASK 0x6028 /* MAC control mask reg */
+
+-/* to ensure proper operation, CFG_EN must be cleared to 0 and a delay
++/* to ensure proper operation, CFG_EN must be cleared to 0 and a delay
+ * imposed before writes to other bits in the TX_MAC_CFG register or any of
+ * the MAC parameters is performed. delay dependent upon time required to
+ * transmit a maximum size frame (= MAC_FRAMESIZE_MAX*8/Mbps). e.g.,
+- * the delay for a 1518-byte frame on a 100Mbps network is 125us.
+- * alternatively, just poll TX_CFG_EN until it reads back as 0.
+- * NOTE: on half-duplex 1Gbps, TX_CFG_CARRIER_EXTEND and
++ * the delay for a 1518-byte frame on a 100Mbps network is 125us.
++ * alternatively, just poll TX_CFG_EN until it reads back as 0.
++ * NOTE: on half-duplex 1Gbps, TX_CFG_CARRIER_EXTEND and
+ * RX_CFG_CARRIER_EXTEND should be set and the SLOT_TIME register should
+ * be 0x200 (slot time of 512 bytes)
+ */
+@@ -1340,12 +1340,12 @@
+ #define MAC_TX_CFG_EN 0x0001 /* enable TX MAC. 0 will
+ force TXMAC state
+ machine to remain in
+- idle state or to
++ idle state or to
+ transition to idle state
+ on completion of an
+ ongoing packet. */
+ #define MAC_TX_CFG_IGNORE_CARRIER 0x0002 /* disable CSMA/CD deferral
+- process. set to 1 when
++ process. set to 1 when
+ full duplex and 0 when
+ half duplex */
+ #define MAC_TX_CFG_IGNORE_COLL 0x0004 /* disable CSMA/CD backoff
+@@ -1353,32 +1353,32 @@
+ full duplex and 0 when
+ half duplex */
+ #define MAC_TX_CFG_IPG_EN 0x0008 /* enable extension of the
+- Rx-to-TX IPG. after
+- receiving a frame, TX
+- MAC will reset its
+- deferral process to
++ Rx-to-TX IPG. after
++ receiving a frame, TX
++ MAC will reset its
++ deferral process to
+ carrier sense for the
+ amount of time = IPG0 +
+- IPG1 and commit to
++ IPG1 and commit to
+ transmission for time
+ specified in IPG2. when
+ 0 or when xmitting frames
+ back-to-pack (Tx-to-Tx
+- IPG), TX MAC ignores
++ IPG), TX MAC ignores
+ IPG0 and will only use
+ IPG1 for deferral time.
+ IPG2 still used. */
+ #define MAC_TX_CFG_NEVER_GIVE_UP_EN 0x0010 /* TX MAC will not easily
+- give up on frame
+- xmission. if backoff
++ give up on frame
++ xmission. if backoff
+ algorithm reaches the
+ ATTEMPT_LIMIT, it will
+ clear attempts counter
+ and continue trying to
+- send the frame as
+- specified by
++ send the frame as
++ specified by
+ GIVE_UP_LIM. when 0,
+- TX MAC will execute
++ TX MAC will execute
+ standard CSMA/CD prot. */
+ #define MAC_TX_CFG_NEVER_GIVE_UP_LIM 0x0020 /* when set, TX MAC will
+ continue to try to xmit
+@@ -1386,13 +1386,13 @@
+ 0, TX MAC will continue
+ to try xmitting until
+ successful or backoff
+- algorithm reaches
++ algorithm reaches
+ ATTEMPT_LIMIT*16 */
+ #define MAC_TX_CFG_NO_BACKOFF 0x0040 /* modify CSMA/CD to disable
+ backoff algorithm. TX
+ MAC will not back off
+ after a xmission attempt
+- that resulted in a
++ that resulted in a
+ collision. */
+ #define MAC_TX_CFG_SLOW_DOWN 0x0080 /* modify CSMA/CD so that
+ deferral process is reset
+@@ -1408,11 +1408,11 @@
+ packets. when clear, CRC
+ generation is dependent
+ upon NO_CRC bit in the
+- xmit control word from
++ xmit control word from
+ TX DMA */
+ #define MAC_TX_CFG_CARRIER_EXTEND 0x0200 /* enables xmit part of the
+- carrier extension
+- feature. this allows for
++ carrier extension
++ feature. this allows for
+ longer collision domains
+ by extending the carrier
+ and collision window
+@@ -1422,44 +1422,44 @@
+ for half-duplex at 1Gbps,
+ clear otherwise. */
+
+-/* when CRC is not stripped, reassembly packets will not contain the CRC.
++/* when CRC is not stripped, reassembly packets will not contain the CRC.
+ * these will be stripped by HRP because it reassembles layer 4 data, and the
+- * CRC is layer 2. however, non-reassembly packets will still contain the CRC
++ * CRC is layer 2. however, non-reassembly packets will still contain the CRC
+ * when passed to the host. to ensure proper operation, need to wait 3.2ms
+ * after clearing RX_CFG_EN before writing to any other RX MAC registers
+ * or other MAC parameters. alternatively, poll RX_CFG_EN until it clears
+- * to 0. similary, HASH_FILTER_EN and ADDR_FILTER_EN have the same
++ * to 0. similary, HASH_FILTER_EN and ADDR_FILTER_EN have the same
+ * restrictions as CFG_EN.
+ */
+ #define REG_MAC_RX_CFG 0x6034 /* RX MAC config reg */
+ #define MAC_RX_CFG_EN 0x0001 /* enable RX MAC */
+ #define MAC_RX_CFG_STRIP_PAD 0x0002 /* always program to 0.
+ feature not supported */
+-#define MAC_RX_CFG_STRIP_FCS 0x0004 /* RX MAC will strip the
+- last 4 bytes of a
++#define MAC_RX_CFG_STRIP_FCS 0x0004 /* RX MAC will strip the
++ last 4 bytes of a
+ received frame. */
+ #define MAC_RX_CFG_PROMISC_EN 0x0008 /* promiscuous mode */
+-#define MAC_RX_CFG_PROMISC_GROUP_EN 0x0010 /* accept all valid
++#define MAC_RX_CFG_PROMISC_GROUP_EN 0x0010 /* accept all valid
+ multicast frames (group
+ bit in DA field set) */
+ #define MAC_RX_CFG_HASH_FILTER_EN 0x0020 /* use hash table to filter
+ multicast addresses */
+-#define MAC_RX_CFG_ADDR_FILTER_EN 0x0040 /* cause RX MAC to use
+- address filtering regs
++#define MAC_RX_CFG_ADDR_FILTER_EN 0x0040 /* cause RX MAC to use
++ address filtering regs
+ to filter both unicast
+- and multicast
++ and multicast
+ addresses */
+ #define MAC_RX_CFG_DISABLE_DISCARD 0x0080 /* pass errored frames to
+ RX DMA by setting BAD
+ bit but not Abort bit
+- in the status. CRC,
++ in the status. CRC,
+ framing, and length errs
+- will not increment
++ will not increment
+ error counters. frames
+ which don't match dest
+ addr will be passed up
+ w/ BAD bit set. */
+-#define MAC_RX_CFG_CARRIER_EXTEND 0x0100 /* enable reception of
++#define MAC_RX_CFG_CARRIER_EXTEND 0x0100 /* enable reception of
+ packet bursts generated
+ by carrier extension
+ with packet bursting
+@@ -1468,18 +1468,18 @@
+
+ /* DEFAULT: 0x0 */
+ #define REG_MAC_CTRL_CFG 0x6038 /* MAC control config reg */
+-#define MAC_CTRL_CFG_SEND_PAUSE_EN 0x0001 /* respond to requests for
+- sending pause flow ctrl
++#define MAC_CTRL_CFG_SEND_PAUSE_EN 0x0001 /* respond to requests for
++ sending pause flow ctrl
+ frames */
+-#define MAC_CTRL_CFG_RECV_PAUSE_EN 0x0002 /* respond to received
++#define MAC_CTRL_CFG_RECV_PAUSE_EN 0x0002 /* respond to received
+ pause flow ctrl frames */
+ #define MAC_CTRL_CFG_PASS_CTRL 0x0004 /* pass valid MAC ctrl
+ packets to RX DMA */
+
+ /* to ensure proper operation, a global initialization sequence should be
+ * performed when a loopback config is entered or exited. if programmed after
+- * a hw or global sw reset, RX/TX MAC software reset and initialization
+- * should be done to ensure stable clocking.
++ * a hw or global sw reset, RX/TX MAC software reset and initialization
++ * should be done to ensure stable clocking.
+ * DEFAULT: 0x0
+ */
+ #define REG_MAC_XIF_CFG 0x603C /* XIF config reg */
+@@ -1489,26 +1489,26 @@
+ path to GMII recv data
+ path. phy mode register
+ clock selection must be
+- set to GMII mode and
++ set to GMII mode and
+ GMII_MODE should be set
+ to 1. in loopback mode,
+ REFCLK will drive the
+ entire mac core. 0 for
+ normal operation. */
+ #define MAC_XIF_DISABLE_ECHO 0x0004 /* disables receive data
+- path during packet
++ path during packet
+ xmission. clear to 0
+ in any full duplex mode,
+ in any loopback mode,
+ or in half-duplex SERDES
+ or SLINK modes. set when
+- in half-duplex when
++ in half-duplex when
+ using external phy. */
+ #define MAC_XIF_GMII_MODE 0x0008 /* MAC operates with GMII
+ clocks and datapath */
+ #define MAC_XIF_MII_BUFFER_OUTPUT_EN 0x0010 /* MII_BUF_EN pin. enable
+ external tristate buffer
+- on the MII receive
++ on the MII receive
+ bus. */
+ #define MAC_XIF_LINK_LED 0x0020 /* LINKLED# active (low) */
+ #define MAC_XIF_FDPLX_LED 0x0040 /* FDPLXLED# active (low) */
+@@ -1521,7 +1521,7 @@
+ recommended: 0x04 */
+ #define REG_MAC_SLOT_TIME 0x604C /* slot time reg
+ recommended: 0x40 */
+-#define REG_MAC_FRAMESIZE_MIN 0x6050 /* min frame size reg
++#define REG_MAC_FRAMESIZE_MIN 0x6050 /* min frame size reg
+ recommended: 0x40 */
+
+ /* FRAMESIZE_MAX holds both the max frame size as well as the max burst size.
+@@ -1536,39 +1536,39 @@
+ preamble bytes that the
+ TX MAC will xmit at the
+ beginning of each frame
+- value should be 2 or
+- greater. recommended
++ value should be 2 or
++ greater. recommended
+ value: 0x07 */
+-#define REG_MAC_JAM_SIZE 0x605C /* jam size reg. duration
++#define REG_MAC_JAM_SIZE 0x605C /* jam size reg. duration
+ of jam in units of media
+ byte time. recommended
+ value: 0x04 */
+ #define REG_MAC_ATTEMPT_LIMIT 0x6060 /* attempt limit reg. #
+ of attempts TX MAC will
+- make to xmit a frame
++ make to xmit a frame
+ before it resets its
+ attempts counter. after
+- the limit has been
++ the limit has been
+ reached, TX MAC may or
+ may not drop the frame
+ dependent upon value
+- in TX_MAC_CFG.
+- recommended
++ in TX_MAC_CFG.
++ recommended
+ value: 0x10 */
+ #define REG_MAC_CTRL_TYPE 0x6064 /* MAC control type reg.
+- type field of a MAC
++ type field of a MAC
+ ctrl frame. recommended
+ value: 0x8808 */
+
+ /* mac address registers: 0 - 44, 0x6080 - 0x6130, 4 8-bit bytes.
+- * register contains comparison
++ * register contains comparison
+ * 0 16 MSB of primary MAC addr [47:32] of DA field
+ * 1 16 middle bits "" [31:16] of DA field
+ * 2 16 LSB "" [15:0] of DA field
+ * 3*x 16MSB of alt MAC addr 1-15 [47:32] of DA field
+ * 4*x 16 middle bits "" [31:16]
+ * 5*x 16 LSB "" [15:0]
+- * 42 16 MSB of MAC CTRL addr [47:32] of DA.
++ * 42 16 MSB of MAC CTRL addr [47:32] of DA.
+ * 43 16 middle bits "" [31:16]
+ * 44 16 LSB "" [15:0]
+ * MAC CTRL addr must be the reserved multicast addr for MAC CTRL frames.
+@@ -1586,39 +1586,39 @@
+ #define REG_MAC_ADDRN(x) (REG_MAC_ADDR0 + (x)*4)
+ #define REG_MAC_ADDR_FILTER0 0x614C /* address filter 0 reg
+ [47:32] */
+-#define REG_MAC_ADDR_FILTER1 0x6150 /* address filter 1 reg
++#define REG_MAC_ADDR_FILTER1 0x6150 /* address filter 1 reg
+ [31:16] */
+-#define REG_MAC_ADDR_FILTER2 0x6154 /* address filter 2 reg
++#define REG_MAC_ADDR_FILTER2 0x6154 /* address filter 2 reg
+ [15:0] */
+ #define REG_MAC_ADDR_FILTER2_1_MASK 0x6158 /* address filter 2 and 1
+ mask reg. 8-bit reg
+ contains nibble mask for
+ reg 2 and 1. */
+-#define REG_MAC_ADDR_FILTER0_MASK 0x615C /* address filter 0 mask
++#define REG_MAC_ADDR_FILTER0_MASK 0x615C /* address filter 0 mask
+ reg */
+
+-/* hash table registers: 0 - 15, 0x6160 - 0x619C, 4 8-bit bytes
++/* hash table registers: 0 - 15, 0x6160 - 0x619C, 4 8-bit bytes
+ * 16-bit registers contain bits of the hash table.
+- * reg x -> [16*(15 - x) + 15 : 16*(15 - x)].
++ * reg x -> [16*(15 - x) + 15 : 16*(15 - x)].
+ * e.g., 15 -> [15:0], 0 -> [255:240]
+ */
+ #define REG_MAC_HASH_TABLE0 0x6160 /* hash table 0 reg */
+ #define REG_MAC_HASH_TABLEN(x) (REG_MAC_HASH_TABLE0 + (x)*4)
+
+-/* statistics registers. these registers generate an interrupt on
++/* statistics registers. these registers generate an interrupt on
+ * overflow. recommended initialization: 0x0000. most are 16-bits except
+ * for PEAK_ATTEMPTS register which is 8 bits.
+ */
+-#define REG_MAC_COLL_NORMAL 0x61A0 /* normal collision
++#define REG_MAC_COLL_NORMAL 0x61A0 /* normal collision
+ counter. */
+ #define REG_MAC_COLL_FIRST 0x61A4 /* first attempt
+- successful collision
++ successful collision
+ counter */
+-#define REG_MAC_COLL_EXCESS 0x61A8 /* excessive collision
++#define REG_MAC_COLL_EXCESS 0x61A8 /* excessive collision
+ counter */
+ #define REG_MAC_COLL_LATE 0x61AC /* late collision counter */
+-#define REG_MAC_TIMER_DEFER 0x61B0 /* defer timer. time base
+- is the media byte
++#define REG_MAC_TIMER_DEFER 0x61B0 /* defer timer. time base
++ is the media byte
+ clock/256 */
+ #define REG_MAC_ATTEMPTS_PEAK 0x61B4 /* peak attempts reg */
+ #define REG_MAC_RECV_FRAME 0x61B8 /* receive frame counter */
+@@ -1633,13 +1633,13 @@
+ 10-bit register used as a
+ seed for the random number
+ generator for the CSMA/CD
+- backoff algorithm. only
++ backoff algorithm. only
+ programmed after power-on
+- reset and should be a
+- random value which has a
+- high likelihood of being
+- unique for each MAC
+- attached to a network
++ reset and should be a
++ random value which has a
++ high likelihood of being
++ unique for each MAC
++ attached to a network
+ segment (e.g., 10 LSB of
+ MAC address) */
+
+@@ -1649,7 +1649,7 @@
+
+ /* 27-bit register has the current state for key state machines in the MAC */
+ #define REG_MAC_STATE_MACHINE 0x61D0 /* (ro) state machine reg */
+-#define MAC_SM_RLM_MASK 0x07800000
++#define MAC_SM_RLM_MASK 0x07800000
+ #define MAC_SM_RLM_SHIFT 23
+ #define MAC_SM_RX_FC_MASK 0x00700000
+ #define MAC_SM_RX_FC_SHIFT 20
+@@ -1666,26 +1666,26 @@
+ #define MAC_SM_TX_FIFO_EMPTY_MASK 0x00000007
+ #define MAC_SM_TX_FIFO_EMPTY_SHIFT 0
+
+-/** MIF registers. the MIF can be programmed in either bit-bang or
++/** MIF registers. the MIF can be programmed in either bit-bang or
+ * frame mode.
+ **/
+ #define REG_MIF_BIT_BANG_CLOCK 0x6200 /* MIF bit-bang clock.
+- 1 -> 0 will generate a
++ 1 -> 0 will generate a
+ rising edge. 0 -> 1 will
+ generate a falling edge. */
+ #define REG_MIF_BIT_BANG_DATA 0x6204 /* MIF bit-bang data. 1-bit
+ register generates data */
+-#define REG_MIF_BIT_BANG_OUTPUT_EN 0x6208 /* MIF bit-bang output
+- enable. enable when
++#define REG_MIF_BIT_BANG_OUTPUT_EN 0x6208 /* MIF bit-bang output
++ enable. enable when
+ xmitting data from MIF to
+ transceiver. */
+
+-/* 32-bit register serves as an instruction register when the MIF is
++/* 32-bit register serves as an instruction register when the MIF is
+ * programmed in frame mode. load this register w/ a valid instruction
+ * (as per IEEE 802.3u MII spec). poll this register to check for instruction
+ * execution completion. during a read operation, this register will also
+- * contain the 16-bit data returned by the tranceiver. unless specified
+- * otherwise, fields are considered "don't care" when polling for
++ * contain the 16-bit data returned by the tranceiver. unless specified
++ * otherwise, fields are considered "don't care" when polling for
+ * completion.
+ */
+ #define REG_MIF_FRAME 0x620C /* MIF frame/output reg */
+@@ -1693,14 +1693,14 @@
+ load w/ 01 when
+ issuing an instr */
+ #define MIF_FRAME_ST 0x40000000 /* STart of frame */
+-#define MIF_FRAME_OPCODE_MASK 0x30000000 /* opcode. 01 for a
+- write. 10 for a
++#define MIF_FRAME_OPCODE_MASK 0x30000000 /* opcode. 01 for a
++ write. 10 for a
+ read */
+ #define MIF_FRAME_OP_READ 0x20000000 /* read OPcode */
+ #define MIF_FRAME_OP_WRITE 0x10000000 /* write OPcode */
+ #define MIF_FRAME_PHY_ADDR_MASK 0x0F800000 /* phy address. when
+ issuing an instr,
+- this field should be
++ this field should be
+ loaded w/ the XCVR
+ addr */
+ #define MIF_FRAME_PHY_ADDR_SHIFT 23
+@@ -1724,12 +1724,12 @@
+ to be written in
+ transceiver reg for a
+ write. doesn't matter
+- in a read. when
+- polling for
++ in a read. when
++ polling for
+ completion, field is
+ "don't care" for write
+- and 16-bit data
+- returned by the
++ and 16-bit data
++ returned by the
+ transceiver for a
+ read (if valid bit
+ is set) */
+@@ -1748,16 +1748,16 @@
+ #define MIF_CFG_POLL_REG_SHIFT 3
+ #define MIF_CFG_MDIO_0 0x0100 /* (ro) dual purpose.
+ when MDIO_0 is idle,
+- 1 -> tranceiver is
++ 1 -> tranceiver is
+ connected to MDIO_0.
+ when MIF is communicating
+- w/ MDIO_0 in bit-bang
++ w/ MDIO_0 in bit-bang
+ mode, this bit indicates
+ the incoming bit stream
+ during a read op */
+ #define MIF_CFG_MDIO_1 0x0200 /* (ro) dual purpose.
+- when MDIO_1 is idle,
+- 1 -> transceiver is
++ when MDIO_1 is idle,
++ 1 -> transceiver is
+ connected to MDIO_1.
+ when MIF is communicating
+ w/ MDIO_1 in bit-bang
+@@ -1770,7 +1770,7 @@
+
+ /* 16-bit register used to determine which bits in the POLL_STATUS portion of
+ * the MIF_STATUS register will cause an interrupt. if a mask bit is 0,
+- * corresponding bit of the POLL_STATUS will generate a MIF interrupt when
++ * corresponding bit of the POLL_STATUS will generate a MIF interrupt when
+ * set. DEFAULT: 0xFFFF
+ */
+ #define REG_MIF_MASK 0x6214 /* MIF mask reg */
+@@ -1779,7 +1779,7 @@
+ #define REG_MIF_STATUS 0x6218 /* MIF status reg */
+ #define MIF_STATUS_POLL_DATA_MASK 0xFFFF0000 /* poll data contains
+ the "latest image"
+- update of the XCVR
++ update of the XCVR
+ reg being read */
+ #define MIF_STATUS_POLL_DATA_SHIFT 16
+ #define MIF_STATUS_POLL_STATUS_MASK 0x0000FFFF /* poll status indicates
+@@ -1792,19 +1792,19 @@
+
+ /* 7-bit register has current state for all state machines in the MIF */
+ #define REG_MIF_STATE_MACHINE 0x621C /* MIF state machine reg */
+-#define MIF_SM_CONTROL_MASK 0x07 /* control state machine
++#define MIF_SM_CONTROL_MASK 0x07 /* control state machine
+ state */
+ #define MIF_SM_EXECUTION_MASK 0x60 /* execution state machine
+ state */
+
+ /** PCS/Serialink. the following registers are equivalent to the standard
+- * MII management registers except that they're directly mapped in
++ * MII management registers except that they're directly mapped in
+ * Cassini's register space.
+ **/
+
+ /* the auto-negotiation enable bit should be programmed the same at
+ * the link partner as in the local device to enable auto-negotiation to
+- * complete. when that bit is reprogrammed, auto-neg/manual config is
++ * complete. when that bit is reprogrammed, auto-neg/manual config is
+ * restarted automatically.
+ * DEFAULT: 0x1040
+ */
+@@ -1815,10 +1815,10 @@
+ to MAC interface is
+ activated regardless
+ of activity */
+-#define PCS_MII_CTRL_DUPLEX 0x0100 /* forced 0x0. PCS
++#define PCS_MII_CTRL_DUPLEX 0x0100 /* forced 0x0. PCS
+ behaviour same for
+ half and full dplx */
+-#define PCS_MII_RESTART_AUTONEG 0x0200 /* self clearing.
++#define PCS_MII_RESTART_AUTONEG 0x0200 /* self clearing.
+ restart auto-
+ negotiation */
+ #define PCS_MII_ISOLATE 0x0400 /* read as 0. ignored
+@@ -1829,10 +1829,10 @@
+ through automatic
+ link config before it
+ can be used. when 0,
+- link can be used
++ link can be used
+ w/out any link config
+ phase */
+-#define PCS_MII_10_100_SEL 0x2000 /* read as 0. ignored on
++#define PCS_MII_10_100_SEL 0x2000 /* read as 0. ignored on
+ writes */
+ #define PCS_MII_RESET 0x8000 /* reset PCS. self-clears
+ when done */
+@@ -1841,7 +1841,7 @@
+ #define REG_PCS_MII_STATUS 0x9004 /* PCS MII status reg */
+ #define PCS_MII_STATUS_EXTEND_CAP 0x0001 /* reads 0 */
+ #define PCS_MII_STATUS_JABBER_DETECT 0x0002 /* reads 0 */
+-#define PCS_MII_STATUS_LINK_STATUS 0x0004 /* 1 -> link up.
++#define PCS_MII_STATUS_LINK_STATUS 0x0004 /* 1 -> link up.
+ 0 -> link down. 0 is
+ latched so that 0 is
+ kept until read. read
+@@ -1853,7 +1853,7 @@
+ from received link code
+ word. only valid after
+ auto-neg completed */
+-#define PCS_MII_STATUS_AUTONEG_COMP 0x0020 /* 1 -> auto-negotiation
++#define PCS_MII_STATUS_AUTONEG_COMP 0x0020 /* 1 -> auto-negotiation
+ completed
+ 0 -> auto-negotiation not
+ completed */
+@@ -1862,7 +1862,7 @@
+ a 1000 Base-X PHY. writes
+ to it are ignored */
+
+-/* used during auto-negotiation.
++/* used during auto-negotiation.
+ * DEFAULT: 0x00E0
+ */
+ #define REG_PCS_MII_ADVERT 0x9008 /* PCS MII advertisement
+@@ -1873,7 +1873,7 @@
+ 1000 Base-X */
+ #define PCS_MII_ADVERT_SYM_PAUSE 0x0080 /* advertise PAUSE
+ symmetric capability */
+-#define PCS_MII_ADVERT_ASYM_PAUSE 0x0100 /* advertises PAUSE
++#define PCS_MII_ADVERT_ASYM_PAUSE 0x0100 /* advertises PAUSE
+ asymmetric capability */
+ #define PCS_MII_ADVERT_RF_MASK 0x3000 /* remote fault. write bit13
+ to optionally indicate to
+@@ -1881,7 +1881,7 @@
+ going off-line. bit12 will
+ get set when signal
+ detect == FAIL and will
+- remain set until
++ remain set until
+ successful negotiation */
+ #define PCS_MII_ADVERT_ACK 0x4000 /* (ro) */
+ #define PCS_MII_ADVERT_NEXT_PAGE 0x8000 /* (ro) forced 0x0 */
+@@ -1905,7 +1905,7 @@
+ 0 when modifying
+ PCS_MII_ADVERT */
+ #define PCS_CFG_SD_OVERRIDE 0x02 /* sets signal detect to
+- OK. bit is
++ OK. bit is
+ non-resettable */
+ #define PCS_CFG_SD_ACTIVE_LOW 0x04 /* changes interpretation
+ of optical signal to make
+@@ -1914,23 +1914,23 @@
+ #define PCS_CFG_JITTER_STUDY_MASK 0x18 /* used to make jitter
+ measurements. a single
+ code group is xmitted
+- regularly.
++ regularly.
+ 0x0 = normal operation
+- 0x1 = high freq test
++ 0x1 = high freq test
+ pattern, D21.5
+ 0x2 = low freq test
+ pattern, K28.7
+ 0x3 = reserved */
+ #define PCS_CFG_10MS_TIMER_OVERRIDE 0x20 /* shortens 10-20ms auto-
+- negotiation timer to
++ negotiation timer to
+ a few cycles for test
+ purposes */
+
+ /* used for diagnostic purposes. bits 20-22 autoclear on read */
+-#define REG_PCS_STATE_MACHINE 0x9014 /* (ro) PCS state machine
++#define REG_PCS_STATE_MACHINE 0x9014 /* (ro) PCS state machine
+ and diagnostic reg */
+-#define PCS_SM_TX_STATE_MASK 0x0000000F /* 0 and 1 indicate
+- xmission of idle.
++#define PCS_SM_TX_STATE_MASK 0x0000000F /* 0 and 1 indicate
++ xmission of idle.
+ otherwise, xmission of
+ a packet */
+ #define PCS_SM_RX_STATE_MASK 0x000000F0 /* 0 indicates reception
+@@ -1943,39 +1943,39 @@
+ Config codes. cycling
+ through 0-1 indicates
+ reception of idles */
+-#define PCS_SM_LINK_STATE_MASK 0x0001E000
++#define PCS_SM_LINK_STATE_MASK 0x0001E000
+ #define SM_LINK_STATE_UP 0x00016000 /* link state is up */
+
+ #define PCS_SM_LOSS_LINK_C 0x00100000 /* loss of link due to
+- recept of Config
++ recept of Config
+ codes */
+ #define PCS_SM_LOSS_LINK_SYNC 0x00200000 /* loss of link due to
+ loss of sync */
+-#define PCS_SM_LOSS_SIGNAL_DETECT 0x00400000 /* signal detect goes
++#define PCS_SM_LOSS_SIGNAL_DETECT 0x00400000 /* signal detect goes
+ from OK to FAIL. bit29
+- will also be set if
++ will also be set if
+ this is set */
+ #define PCS_SM_NO_LINK_BREAKLINK 0x01000000 /* link not up due to
+ receipt of breaklink
+ C codes from partner.
+ C codes w/ 0 content
+ received triggering
+- start/restart of
+- autonegotiation.
++ start/restart of
++ autonegotiation.
+ should be sent for
+ no longer than 20ms */
+-#define PCS_SM_NO_LINK_SERDES 0x02000000 /* serdes being
++#define PCS_SM_NO_LINK_SERDES 0x02000000 /* serdes being
+ initialized. see serdes
+ state reg */
+ #define PCS_SM_NO_LINK_C 0x04000000 /* C codes not stable or
+ not received */
+-#define PCS_SM_NO_LINK_SYNC 0x08000000 /* word sync not
++#define PCS_SM_NO_LINK_SYNC 0x08000000 /* word sync not
+ achieved */
+-#define PCS_SM_NO_LINK_WAIT_C 0x10000000 /* waiting for C codes
++#define PCS_SM_NO_LINK_WAIT_C 0x10000000 /* waiting for C codes
+ w/ ack bit set */
+ #define PCS_SM_NO_LINK_NO_IDLE 0x20000000 /* link partner continues
+- to send C codes
+- instead of idle
++ to send C codes
++ instead of idle
+ symbols or pkt data */
+
+ /* this register indicates interrupt changes in specific PCS MII status bits.
+@@ -1991,21 +1991,21 @@
+ * DEFAULT: none
+ */
+ #define REG_PCS_DATAPATH_MODE 0x9050 /* datapath mode reg */
+-#define PCS_DATAPATH_MODE_MII 0x00 /* PCS is not used and
+- MII/GMII is selected.
++#define PCS_DATAPATH_MODE_MII 0x00 /* PCS is not used and
++ MII/GMII is selected.
+ selection between MII and
+- GMII is controlled by
++ GMII is controlled by
+ XIF_CFG */
+ #define PCS_DATAPATH_MODE_SERDES 0x02 /* PCS is used via the
+ 10-bit interface */
+
+ /* input to serdes chip or serialink block */
+ #define REG_PCS_SERDES_CTRL 0x9054 /* serdes control reg */
+-#define PCS_SERDES_CTRL_LOOPBACK 0x01 /* enable loopback on
++#define PCS_SERDES_CTRL_LOOPBACK 0x01 /* enable loopback on
+ serdes interface */
+ #define PCS_SERDES_CTRL_SYNCD_EN 0x02 /* enable sync carrier
+ detection. should be
+- 0x0 for normal
++ 0x0 for normal
+ operation */
+ #define PCS_SERDES_CTRL_LOCKREF 0x04 /* frequency-lock RBC[0:1]
+ to REFCLK when set.
+@@ -2014,28 +2014,28 @@
+ serial data */
+
+ /* multiplex test outputs into the PROM address (PA_3 through PA_0) pins.
+- * should be 0x0 for normal operations.
++ * should be 0x0 for normal operations.
+ * 0b000 normal operation, PROM address[3:0] selected
+- * 0b001 rxdma req, rxdma ack, rxdma ready, rxdma read
+- * 0b010 rxmac req, rx ack, rx tag, rx clk shared
+- * 0b011 txmac req, tx ack, tx tag, tx retry req
+- * 0b100 tx tp3, tx tp2, tx tp1, tx tp0
++ * 0b001 rxdma req, rxdma ack, rxdma ready, rxdma read
++ * 0b010 rxmac req, rx ack, rx tag, rx clk shared
++ * 0b011 txmac req, tx ack, tx tag, tx retry req
++ * 0b100 tx tp3, tx tp2, tx tp1, tx tp0
+ * 0b101 R period RX, R period TX, R period HP, R period BIM
+ * DEFAULT: 0x0
+ */
+ #define REG_PCS_SHARED_OUTPUT_SEL 0x9058 /* shared output select */
+ #define PCS_SOS_PROM_ADDR_MASK 0x0007
+
+-/* used for diagnostics. this register indicates progress of the SERDES
+- * boot up.
++/* used for diagnostics. this register indicates progress of the SERDES
++ * boot up.
+ * 0b00 undergoing reset
+ * 0b01 waiting 500us while lockrefn is asserted
+ * 0b10 waiting for comma detect
+- * 0b11 receive data is synchronized
++ * 0b11 receive data is synchronized
+ * DEFAULT: 0x0
+ */
+ #define REG_PCS_SERDES_STATE 0x905C /* (ro) serdes state */
+-#define PCS_SERDES_STATE_MASK 0x03
++#define PCS_SERDES_STATE_MASK 0x03
+
+ /* used for diagnostics. indicates number of packets transmitted or received.
+ * counters rollover w/out generating an interrupt.
+@@ -2044,18 +2044,18 @@
+ #define REG_PCS_PACKET_COUNT 0x9060 /* (ro) PCS packet counter */
+ #define PCS_PACKET_COUNT_TX 0x000007FF /* pkts xmitted by PCS */
+ #define PCS_PACKET_COUNT_RX 0x07FF0000 /* pkts recvd by PCS
+- whether they
++ whether they
+ encountered an error
+ or not */
+
+-/** LocalBus Devices. the following provides run-time access to the
++/** LocalBus Devices. the following provides run-time access to the
+ * Cassini's PROM
+ ***/
+ #define REG_EXPANSION_ROM_RUN_START 0x100000 /* expansion rom run time
+ access */
+ #define REG_EXPANSION_ROM_RUN_END 0x17FFFF
+
+-#define REG_SECOND_LOCALBUS_START 0x180000 /* secondary local bus
++#define REG_SECOND_LOCALBUS_START 0x180000 /* secondary local bus
+ device */
+ #define REG_SECOND_LOCALBUS_END 0x1FFFFF
+
+@@ -2103,7 +2103,7 @@
+ #define CAS_MII_1000_EXTEND 0x0F
+
+ #define CAS_BMSR_1000_EXTEND 0x0100 /* supports 1000Base-T extended status */
+-/*
++/*
+ * if autoneg is disabled, here's the table:
+ * BMCR_SPEED100 = 100Mbps
+ * BMCR_SPEED1000 = 1000Mbps
+@@ -2145,7 +2145,7 @@ typedef struct cas_hp_inst {
+ u8 outenab; /* output enable: 0 = not, 1 = if match
+ 2 = if !match, 3 = always */
+ u8 outshift; /* barrel shift right, 4 bits */
+- u16 outmask;
++ u16 outmask;
+ } cas_hp_inst_t;
+
+ /* comparison */
+@@ -2232,9 +2232,9 @@ typedef struct cas_hp_inst {
+
+ #ifdef USE_HP_IP46TCP4
+ static cas_hp_inst_t cas_prog_ip46tcp4tab[] = {
+- CAS_PROG_IP46TCP4_PREAMBLE,
+- { "TCP seq", /* DADDR should point to dest port */
+- 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
++ CAS_PROG_IP46TCP4_PREAMBLE,
++ { "TCP seq", /* DADDR should point to dest port */
++ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ S1_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
+@@ -2263,7 +2263,7 @@ static cas_hp_inst_t cas_prog_ip46tcp4ta
+ static cas_hp_inst_t cas_prog_ip46tcp4nohttptab[] = {
+ CAS_PROG_IP46TCP4_PREAMBLE,
+ { "TCP seq", /* DADDR should point to dest port */
+- 0xFFFF, 0x0080, OP_EQ, 0, S2_HTTP, 0, S1_TCPFG, LD_SEQ,
++ 0xFFFF, 0x0080, OP_EQ, 0, S2_HTTP, 0, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff} , /* Load TCP seq # */
+ { "TCP control flags", 0xFFFF, 0x8080, OP_EQ, 0, S2_HTTP, 0,
+ S1_TCPHL, ST_FLG, 0x145, 2, 0x0, 0x002f, }, /* Load TCP flags */
+@@ -2328,7 +2328,7 @@ static cas_hp_inst_t cas_prog_ip4fragtab
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S3_TCPFG, 4, S3_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+- { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHL, 0,
++ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHL, 0,
+ S3_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHc, 0, S3_TCPHc,
+ LD_R1, 0x205, 3, 0xB, 0xf000},
+@@ -2338,7 +2338,7 @@ static cas_hp_inst_t cas_prog_ip4fragtab
+ LD_FID, 0x103, 3, 0x0, 0xffff}, /* FID IP4 src+dst */
+ { "IP4 frag offset", 0x0000, 0x0000, OP_EQ, 0, S3_FOFF, 0, S3_FOFF,
+ LD_SEQ, 0x040, 1, 0xD, 0xfff8},
+- { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
++ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { NULL },
+ };
+@@ -2356,11 +2356,11 @@ static cas_hp_inst_t cas_prog_ip46tcp4ba
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 0, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+- { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
++ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ S1_TCPHL, ST_FLG, 0x000, 3, 0x0, 0x0000}, /* Load TCP flags */
+- { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0,
++ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0,
+ S1_TCPHc, LD_R1, 0x205, 3, 0xB, 0xf000},
+- { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
++ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ S1_PCKT, IM_CTL, 0x040, 3, 0x0, 0xffff}, /* set batch bit */
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+@@ -2381,7 +2381,7 @@ static cas_hp_inst_t cas_prog_ip46tcp4ba
+ static cas_hp_inst_t cas_prog_workaroundtab[] = {
+ { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
+ S1_PCKT, CL_REG, 0x3ff, 1, 0x0, 0x0000} ,
+- { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
++ { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
+ IM_CTL, 0x04a, 3, 0x0, 0xffff},
+ { "CFI?", 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+@@ -2395,7 +2395,7 @@ static cas_hp_inst_t cas_prog_workaroun
+ IM_SAP, 0x6AE, 3, 0x0, 0xffff},
+ { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
+ LD_SUM, 0x00a, 1, 0x0, 0x0000},
+- { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
++ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
+ LD_LEN, 0x03e, 1, 0x0, 0xffff},
+ { "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_CLNP,
+ LD_FID, 0x182, 3, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
+@@ -2408,7 +2408,7 @@ static cas_hp_inst_t cas_prog_workaroun
+ { "TCP64?", 0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_CLNP,
+ LD_LEN, 0x03f, 1, 0x0, 0xffff},
+ { "TCP seq", /* DADDR should point to dest port */
+- 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
++ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ S1_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
+@@ -2429,7 +2429,7 @@ static cas_hp_inst_t cas_prog_workaroun
+
+ #ifdef USE_HP_ENCRYPT
+ static cas_hp_inst_t cas_prog_encryptiontab[] = {
+- { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
++ { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
+ S1_PCKT, CL_REG, 0x3ff, 1, 0x0, 0x0000},
+ { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
+ IM_CTL, 0x00a, 3, 0x0, 0xffff},
+@@ -2439,19 +2439,19 @@ static cas_hp_inst_t cas_prog_encryptio
+ 00,
+ #endif
+ { "CFI?", /* FIND CFI and If FIND go to CleanUP1 (ignore and send to host) */
+- 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
++ 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+- { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
++ { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+- { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP,
++ { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLCc?", 0xff00, 0x0300, OP_EQ, 2, S1_IPV4, 0, S1_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+- { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
++ { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
+ LD_SAP, 0x100, 3, 0x0, 0xffff},
+- { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
++ { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
+ LD_SUM, 0x00a, 1, 0x0, 0x0000},
+- { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
++ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
+ LD_LEN, 0x03e, 1, 0x0, 0xffff},
+ { "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_ESP4,
+ LD_FID, 0x182, 1, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
+@@ -2459,9 +2459,9 @@ static cas_hp_inst_t cas_prog_encryptio
+ LD_SUM, 0x015, 1, 0x0, 0x0000},
+ { "IPV6 len", 0xf000, 0x6000, OP_EQ, 0, S1_IPV6c, 0, S1_CLNP,
+ IM_R1, 0x128, 1, 0x0, 0xffff},
+- { "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP,
++ { "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP,
+ LD_FID, 0x484, 1, 0x0, 0xffff}, /* FID IP6&TCP src+dst */
+- { "TCP64?",
++ { "TCP64?",
+ #if 0
+ //@@@0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_ESP6, LD_LEN, 0x03f, 1, 0x0, 0xffff,
+ #endif
+@@ -2472,10 +2472,10 @@ static cas_hp_inst_t cas_prog_encryptio
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0xFFFF, 0x8080, OP_EQ, 0, S2_HTTP, 0,
+ S1_TCPHL, ST_FLG, 0x145, 2, 0x0, 0x002f}, /* Load TCP flags */
+- { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
++ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
+ LD_R1, 0x205, 3, 0xB, 0xf000} ,
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+- S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
++ S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP2,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { "Cleanup 2", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+@@ -2483,7 +2483,7 @@ static cas_hp_inst_t cas_prog_encryptio
+ { "Drop packet", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x080, 3, 0x0, 0xffff},
+ { "No HTTP", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+- IM_CTL, 0x044, 3, 0x0, 0xffff},
++ IM_CTL, 0x044, 3, 0x0, 0xffff},
+ { "IPV4 ESP encrypted?", /* S1_ESP4 */
+ 0x00ff, 0x0032, OP_EQ, 0, S1_CLNP2, 0, S1_AH4, IM_CTL,
+ 0x021, 1, 0x0, 0xffff},
+@@ -4044,7 +4044,7 @@ cas_saturn_patch_t cas_saturn_patch[] =
+ * deal with that, i just allocate rings to create the desired
+ * alignment. here are the constraints:
+ * RX DESC and COMP rings must be 8KB aligned
+- * TX DESC must be 2KB aligned.
++ * TX DESC must be 2KB aligned.
+ * if you change the numbers, be cognizant of how the alignment will change
+ * in INIT_BLOCK as well.
+ */
+@@ -4095,20 +4095,20 @@ cas_saturn_patch_t cas_saturn_patch[] =
+ /* min is 2k, but we can't do jumbo frames unless it's at least 8k */
+ #define CAS_MIN_PAGE_SHIFT 11 /* 2048 */
+ #define CAS_JUMBO_PAGE_SHIFT 13 /* 8192 */
+-#define CAS_MAX_PAGE_SHIFT 14 /* 16384 */
++#define CAS_MAX_PAGE_SHIFT 14 /* 16384 */
+
+ #define TX_DESC_BUFLEN_MASK 0x0000000000003FFFULL /* buffer length in
+ bytes. 0 - 9256 */
+ #define TX_DESC_BUFLEN_SHIFT 0
+ #define TX_DESC_CSUM_START_MASK 0x00000000001F8000ULL /* checksum start. #
+- of bytes to be
++ of bytes to be
+ skipped before
+ csum calc begins.
+ value must be
+ even */
+ #define TX_DESC_CSUM_START_SHIFT 15
+ #define TX_DESC_CSUM_STUFF_MASK 0x000000001FE00000ULL /* checksum stuff.
+- byte offset w/in
++ byte offset w/in
+ the pkt for the
+ 1st csum byte.
+ must be > 8 */
+@@ -4137,7 +4137,7 @@ struct cas_rx_desc {
+
+ /* received packets are put on the completion ring. */
+ /* word 1 */
+-#define RX_COMP1_DATA_SIZE_MASK 0x0000000007FFE000ULL
++#define RX_COMP1_DATA_SIZE_MASK 0x0000000007FFE000ULL
+ #define RX_COMP1_DATA_SIZE_SHIFT 13
+ #define RX_COMP1_DATA_OFF_MASK 0x000001FFF8000000ULL
+ #define RX_COMP1_DATA_OFF_SHIFT 27
+@@ -4147,8 +4147,8 @@ struct cas_rx_desc {
+ #define RX_COMP1_SKIP_SHIFT 55
+ #define RX_COMP1_RELEASE_NEXT 0x0200000000000000ULL
+ #define RX_COMP1_SPLIT_PKT 0x0400000000000000ULL
+-#define RX_COMP1_RELEASE_FLOW 0x0800000000000000ULL
+-#define RX_COMP1_RELEASE_DATA 0x1000000000000000ULL
++#define RX_COMP1_RELEASE_FLOW 0x0800000000000000ULL
++#define RX_COMP1_RELEASE_DATA 0x1000000000000000ULL
+ #define RX_COMP1_RELEASE_HDR 0x2000000000000000ULL
+ #define RX_COMP1_TYPE_MASK 0xC000000000000000ULL
+ #define RX_COMP1_TYPE_SHIFT 62
+@@ -4201,7 +4201,7 @@ struct cas_rx_desc {
+
+ /* we encode the following: ring/index/release. only 14 bits
+ * are usable.
+- * NOTE: the encoding is dependent upon RX_DESC_RING_SIZE and
++ * NOTE: the encoding is dependent upon RX_DESC_RING_SIZE and
+ * MAX_RX_DESC_RINGS. */
+ #define RX_INDEX_NUM_MASK 0x0000000000000FFFULL
+ #define RX_INDEX_NUM_SHIFT 0
+@@ -4214,7 +4214,7 @@ struct cas_rx_comp {
+ u64 word2;
+ u64 word3;
+ u64 word4;
+-};
++};
+
+ enum link_state {
+ link_down = 0, /* No link, will retry */
+@@ -4235,9 +4235,9 @@ typedef struct cas_page {
+
+ /* some alignment constraints:
+ * TX DESC, RX DESC, and RX COMP must each be 8K aligned.
+- * TX COMPWB must be 8-byte aligned.
++ * TX COMPWB must be 8-byte aligned.
+ * to accomplish this, here's what we do:
+- *
++ *
+ * INIT_BLOCK_RX_COMP = 64k (already aligned)
+ * INIT_BLOCK_RX_DESC = 8k
+ * INIT_BLOCK_TX = 8k
+@@ -4250,9 +4250,9 @@ typedef struct cas_page {
+
+ struct cas_init_block {
+ struct cas_rx_comp rxcs[N_RX_COMP_RINGS][INIT_BLOCK_RX_COMP];
+- struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
++ struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
+ struct cas_tx_desc txds[N_TX_RINGS][INIT_BLOCK_TX];
+- u64 tx_compwb;
++ u64 tx_compwb;
+ };
+
+ /* tiny buffers to deal with target abort issue. we allocate a bit
+@@ -4278,7 +4278,7 @@ struct cas {
+ int tx_new[N_TX_RINGS], tx_old[N_TX_RINGS];
+ int rx_old[N_RX_DESC_RINGS];
+ int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS];
+- int rx_last[N_RX_DESC_RINGS];
++ int rx_last[N_RX_DESC_RINGS];
+
+ /* Set when chip is actually in operational state
+ * (ie. not power managed) */
+@@ -4337,7 +4337,7 @@ struct cas {
+ int min_frame_size; /* for tx fifo workaround */
+
+ /* page size allocation */
+- int page_size;
++ int page_size;
+ int page_order;
+ int mtu_stride;
+
+@@ -4362,7 +4362,7 @@ struct cas {
+ #ifdef CONFIG_CASSINI_QGE_DEBUG
+ atomic_t interrupt_seen; /* 1 if any interrupts are getting through */
+ #endif
+-
++
+ /* Link-down problem workaround */
+ #define LINK_TRANSITION_UNKNOWN 0
+ #define LINK_TRANSITION_ON_FAILURE 1
+@@ -4383,7 +4383,7 @@ struct cas {
+ int casreg_len; /* reg-space size for dumping */
+ u64 pause_entered;
+ u16 pause_last_time_recvd;
+-
++
+ dma_addr_t block_dvma, tx_tiny_dvma[N_TX_RINGS];
+ struct pci_dev *pdev;
+ struct net_device *dev;
+@@ -4394,7 +4394,7 @@ struct cas {
+ #define RX_COMP_ENTRY(r, x) ((x) & (RX_COMP_RINGN_SIZE(r) - 1))
+
+ #define TX_BUFF_COUNT(r, x, y) ((x) <= (y) ? ((y) - (x)) : \
+- (TX_DESC_RINGN_SIZE(r) - (x) + (y)))
++ (TX_DESC_RINGN_SIZE(r) - (x) + (y)))
+
+ #define TX_BUFFS_AVAIL(cp, i) ((cp)->tx_old[(i)] <= (cp)->tx_new[(i)] ? \
+ (cp)->tx_old[(i)] + (TX_DESC_RINGN_SIZE(i) - 1) - (cp)->tx_new[(i)] : \
+diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
+index 27925e4..5b357d9 100644
+--- a/drivers/net/chelsio/cpl5_cmd.h
++++ b/drivers/net/chelsio/cpl5_cmd.h
+@@ -108,7 +108,7 @@ struct cpl_tx_pkt_lso {
+ u8 iff:4;
+ #endif
+ u16 vlan;
+- u32 len;
++ __be32 len;
+
+ u32 rsvd2;
+ u8 rsvd3;
+@@ -119,7 +119,7 @@ struct cpl_tx_pkt_lso {
+ u8 ip_hdr_words:4;
+ u8 tcp_hdr_words:4;
+ #endif
+- u16 eth_type_mss;
++ __be16 eth_type_mss;
+ };
+
+ struct cpl_rx_pkt {
+@@ -138,7 +138,7 @@ struct cpl_rx_pkt {
+ u8 iff:4;
+ #endif
+ u16 csum;
+- u16 vlan;
++ __be16 vlan;
+ u16 len;
+ };
+
+diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
+index e678724..ad7ff96 100644
+--- a/drivers/net/chelsio/cxgb2.c
++++ b/drivers/net/chelsio/cxgb2.c
+@@ -779,7 +779,7 @@ static int get_eeprom(struct net_device
+ return 0;
+ }
+
+-static struct ethtool_ops t1_ethtool_ops = {
++static const struct ethtool_ops t1_ethtool_ops = {
+ .get_settings = get_settings,
+ .set_settings = set_settings,
+ .get_drvinfo = get_drvinfo,
+@@ -918,7 +918,7 @@ static void t1_netpoll(struct net_device
+ struct adapter *adapter = dev->priv;
+
+ local_irq_save(flags);
+- t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter, NULL);
++ t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter);
+ local_irq_restore(flags);
+ }
+ #endif
+@@ -1243,7 +1243,7 @@ static struct pci_driver driver = {
+
+ static int __init t1_init_module(void)
+ {
+- return pci_module_init(&driver);
++ return pci_register_driver(&driver);
+ }
+
+ static void __exit t1_cleanup_module(void)
+diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
+index 61b3754..9799c12 100644
+--- a/drivers/net/chelsio/sge.c
++++ b/drivers/net/chelsio/sge.c
+@@ -1217,7 +1217,7 @@ static inline int napi_is_scheduled(stru
+ /*
+ * NAPI version of the main interrupt handler.
+ */
+-static irqreturn_t t1_interrupt_napi(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t t1_interrupt_napi(int irq, void *data)
+ {
+ int handled;
+ struct adapter *adapter = data;
+@@ -1279,7 +1279,7 @@ static irqreturn_t t1_interrupt_napi(int
+ * 5. If we took an interrupt, but no valid respQ descriptors was found we
+ * let the slow_intr_handler run and do error handling.
+ */
+-static irqreturn_t t1_interrupt(int irq, void *cookie, struct pt_regs *regs)
++static irqreturn_t t1_interrupt(int irq, void *cookie)
+ {
+ int work_done;
+ struct respQ_e *e;
+@@ -1312,7 +1312,7 @@ static irqreturn_t t1_interrupt(int irq,
+ return IRQ_RETVAL(work_done != 0);
+ }
+
+-intr_handler_t t1_select_intr_handler(adapter_t *adapter)
++irq_handler_t t1_select_intr_handler(adapter_t *adapter)
+ {
+ return adapter->params.sge.polling ? t1_interrupt_napi : t1_interrupt;
+ }
+@@ -1470,9 +1470,9 @@ int t1_start_xmit(struct sk_buff *skb, s
+ }
+
+ if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
+- skb->ip_summed == CHECKSUM_HW &&
++ skb->ip_summed == CHECKSUM_PARTIAL &&
+ skb->nh.iph->protocol == IPPROTO_UDP)
+- if (unlikely(skb_checksum_help(skb, 0))) {
++ if (unlikely(skb_checksum_help(skb))) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+@@ -1495,11 +1495,11 @@ int t1_start_xmit(struct sk_buff *skb, s
+ cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl));
+ cpl->opcode = CPL_TX_PKT;
+ cpl->ip_csum_dis = 1; /* SW calculates IP csum */
+- cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_HW ? 0 : 1;
++ cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1;
+ /* the length field isn't used so don't bother setting it */
+
+- st->tx_cso += (skb->ip_summed == CHECKSUM_HW);
+- sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_HW);
++ st->tx_cso += (skb->ip_summed == CHECKSUM_PARTIAL);
++ sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_PARTIAL);
+ sge->stats.tx_reg_pkts++;
+ }
+ cpl->iff = dev->if_port;
+diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
+index 6d0d24a..91af47b 100644
+--- a/drivers/net/chelsio/sge.h
++++ b/drivers/net/chelsio/sge.h
+@@ -43,13 +43,6 @@
+ #include <linux/interrupt.h>
+ #include <asm/byteorder.h>
+
+-#ifndef IRQ_RETVAL
+-#define IRQ_RETVAL(x)
+-typedef void irqreturn_t;
+-#endif
+-
+-typedef irqreturn_t (*intr_handler_t)(int, void *, struct pt_regs *);
+-
+ struct sge_intr_counts {
+ unsigned int respQ_empty; /* # times respQ empty */
+ unsigned int respQ_overflow; /* # respQ overflow (fatal) */
+@@ -88,7 +81,7 @@ struct sge *t1_sge_create(struct adapter
+ int t1_sge_configure(struct sge *, struct sge_params *);
+ int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
+ void t1_sge_destroy(struct sge *);
+-intr_handler_t t1_select_intr_handler(adapter_t *adapter);
++irq_handler_t t1_select_intr_handler(adapter_t *adapter);
+ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ void t1_set_vlan_accel(struct adapter *adapter, int on_off);
+ void t1_sge_start(struct sge *);
+diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
+index 0eb1f87..966b563 100644
+--- a/drivers/net/cris/eth_v10.c
++++ b/drivers/net/cris/eth_v10.c
+@@ -403,8 +403,8 @@ static int etrax_ethernet_init(void);
+ static int e100_open(struct net_device *dev);
+ static int e100_set_mac_address(struct net_device *dev, void *addr);
+ static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id);
++static irqreturn_t e100nw_interrupt(int irq, void *dev_id);
+ static void e100_rx(struct net_device *dev);
+ static int e100_close(struct net_device *dev);
+ static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+@@ -434,7 +434,7 @@ static void e100_reset_transceiver(struc
+ static void e100_clear_network_leds(unsigned long dummy);
+ static void e100_set_network_leds(int active);
+
+-static struct ethtool_ops e100_ethtool_ops;
++static const struct ethtool_ops e100_ethtool_ops;
+
+ static void broadcom_check_speed(struct net_device* dev);
+ static void broadcom_check_duplex(struct net_device* dev);
+@@ -1197,7 +1197,7 @@ e100_send_packet(struct sk_buff *skb, st
+ */
+
+ static irqreturn_t
+-e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++e100rxtx_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct net_local *np = (struct net_local *)dev->priv;
+@@ -1264,7 +1264,7 @@ e100rxtx_interrupt(int irq, void *dev_id
+ }
+
+ static irqreturn_t
+-e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++e100nw_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct net_local *np = (struct net_local *)dev->priv;
+@@ -1552,7 +1552,7 @@ static int e100_nway_reset(struct net_de
+ return 0;
+ }
+
+-static struct ethtool_ops e100_ethtool_ops = {
++static const struct ethtool_ops e100_ethtool_ops = {
+ .get_settings = e100_get_settings,
+ .set_settings = e100_set_settings,
+ .get_drvinfo = e100_get_drvinfo,
+diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
+index 2dcca79..4ffc9b4 100644
+--- a/drivers/net/cs89x0.c
++++ b/drivers/net/cs89x0.c
+@@ -15,13 +15,13 @@
+ Changelog:
+
+ Mike Cruse : mcruse at cti-ltd.com
+- : Changes for Linux 2.0 compatibility.
++ : Changes for Linux 2.0 compatibility.
+ : Added dev_id parameter in net_interrupt(),
+ : request_irq() and free_irq(). Just NULL for now.
+
+ Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
+ : in net_open() and net_close() so kerneld would know
+- : that the module is in use and wouldn't eject the
++ : that the module is in use and wouldn't eject the
+ : driver prematurely.
+
+ Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
+@@ -31,7 +31,7 @@
+
+ Russ Nelson : Jul 13 1998. Added RxOnly DMA support.
+
+- Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility.
++ Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility.
+ : email: ethernet at crystal.cirrus.com
+
+ Alan Cox : Removed 1.2 support, added 2.1 extra counters.
+@@ -163,12 +163,12 @@ static char version[] __initdata =
+ /* First, a few definitions that the brave might change.
+ A zero-terminated list of I/O addresses to be probed. Some special flags..
+ Addr & 1 = Read back the address port, look for signature and reset
+- the page window before probing
+- Addr & 3 = Reset the page window and probe
++ the page window before probing
++ Addr & 3 = Reset the page window and probe
+ The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
+ but it is possible that a Cirrus board could be plugged into the ISA
+ slots. */
+-/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
++/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
+ them to system IRQ numbers. This mapping is card specific and is set to
+ the configuration of the Cirrus Eval board for this chip. */
+ #ifdef CONFIG_ARCH_CLPS7500
+@@ -249,7 +249,7 @@ struct net_local {
+ static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular);
+ static int net_open(struct net_device *dev);
+ static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t net_interrupt(int irq, void *dev_id);
+ static void set_multicast_list(struct net_device *dev);
+ static void net_timeout(struct net_device *dev);
+ static void net_rx(struct net_device *dev);
+@@ -299,7 +299,7 @@ static int __init media_fn(char *str)
+
+ __setup("cs89x0_media=", media_fn);
+
+-
++
+ /* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+@@ -495,7 +495,7 @@ get_eeprom_cksum(int off, int len, int *
+ static void net_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- net_interrupt(dev->irq, dev, NULL);
++ net_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -630,7 +630,7 @@ cs89x0_probe1(struct net_device *dev, in
+ dev->base_addr);
+
+ reset_chip(dev);
+-
++
+ /* Here we read the current configuration of the chip. If there
+ is no Extended EEPROM then the idea is to not disturb the chip
+ configuration, it should have been correctly setup by automatic
+@@ -654,7 +654,7 @@ cs89x0_probe1(struct net_device *dev, in
+ cnt = (*confd++ & 0x00ff) >> 1;
+ while (--cnt > 0) {
+ __u16 j = *confd++;
+-
++
+ switch (j & 0x0fff) {
+ case PP_IA:
+ for (i = 0; i < ETH_ALEN/2; i++) {
+@@ -670,7 +670,7 @@ cs89x0_probe1(struct net_device *dev, in
+ } else
+ #endif
+
+- if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
++ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
+ (EEPROM_OK|EEPROM_PRESENT)) {
+ /* Load the MAC. */
+ for (i=0; i < ETH_ALEN/2; i++) {
+@@ -679,17 +679,17 @@ cs89x0_probe1(struct net_device *dev, in
+ dev->dev_addr[i*2] = Addr & 0xFF;
+ dev->dev_addr[i*2+1] = Addr >> 8;
+ }
+-
+- /* Load the Adapter Configuration.
+- Note: Barring any more specific information from some
+- other source (ie EEPROM+Schematics), we would not know
+- how to operate a 10Base2 interface on the AUI port.
+- However, since we do read the status of HCB1 and use
+- settings that always result in calls to control_dc_dc(dev,0)
+- a BNC interface should work if the enable pin
+- (dc/dc converter) is on HCB1. It will be called AUI
++
++ /* Load the Adapter Configuration.
++ Note: Barring any more specific information from some
++ other source (ie EEPROM+Schematics), we would not know
++ how to operate a 10Base2 interface on the AUI port.
++ However, since we do read the status of HCB1 and use
++ settings that always result in calls to control_dc_dc(dev,0)
++ a BNC interface should work if the enable pin
++ (dc/dc converter) is on HCB1. It will be called AUI
+ however. */
+-
++
+ lp->adapter_cnf = 0;
+ i = readreg(dev, PP_LineCTL);
+ /* Preserve the setting of the HCB1 pin. */
+@@ -706,22 +706,22 @@ cs89x0_probe1(struct net_device *dev, in
+ lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI;
+ /* Check if the card is in Auto mode. */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
+- lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
++ lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
+ A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
+-
++
+ if (net_debug > 1)
+ printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
+ dev->name, i, lp->adapter_cnf);
+
+ /* IRQ. Other chips already probe, see below. */
+- if (lp->chip_type == CS8900)
++ if (lp->chip_type == CS8900)
+ lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
+-
++
+ printk( "[Cirrus EEPROM] ");
+ }
+
+ printk("\n");
+-
++
+ /* First check to see if an EEPROM is attached. */
+ #ifdef CONFIG_SH_HICOSH4 /* no EEPROM on HiCO, don't hazzle with it here */
+ if (1) {
+@@ -736,13 +736,13 @@ cs89x0_probe1(struct net_device *dev, in
+ /* Check if the chip was able to read its own configuration starting
+ at 0 in the EEPROM*/
+ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
+- (EEPROM_OK|EEPROM_PRESENT))
++ (EEPROM_OK|EEPROM_PRESENT))
+ printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
+-
++
+ } else {
+ /* This reads an extended EEPROM that is not documented
+ in the CS8900 datasheet. */
+-
++
+ /* get transmission control word but keep the autonegotiation bits */
+ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
+ /* Store adapter configuration */
+@@ -810,7 +810,7 @@ cs89x0_probe1(struct net_device *dev, in
+ printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
+ else
+ i = cs8900_irq_map[i];
+-
++
+ lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
+ } else {
+ int irq_map_buff[IRQ_MAP_LEN/2];
+@@ -875,7 +875,7 @@ out1:
+ return retval;
+ }
+
+-
++
+ /*********************************
+ * This page contains DMA routines
+ **********************************/
+@@ -1064,14 +1064,14 @@ void __init reset_chip(struct net_devic
+ ;
+ }
+
+-
++
+ static void
+ control_dc_dc(struct net_device *dev, int on_not_off)
+ {
+ struct net_local *lp = netdev_priv(dev);
+ unsigned int selfcontrol;
+ int timenow = jiffies;
+- /* control the DC to DC convertor in the SelfControl register.
++ /* control the DC to DC convertor in the SelfControl register.
+ Note: This is hooked up to a general purpose pin, might not
+ always be a DC to DC convertor. */
+
+@@ -1240,7 +1240,7 @@ detect_bnc(struct net_device *dev)
+ return DETECTED_NONE;
+ }
+
+-
++
+ static void
+ write_irq(struct net_device *dev, int chip_type, int irq)
+ {
+@@ -1544,7 +1544,7 @@ static int net_send_packet(struct sk_buf
+ * Gasp! It hasn't. But that shouldn't happen since
+ * we're waiting for TxOk, so return 1 and requeue this packet.
+ */
+-
++
+ spin_unlock_irq(&lp->lock);
+ if (net_debug) printk("cs89x0: Tx buffer not free!\n");
+ return 1;
+@@ -1569,11 +1569,11 @@ static int net_send_packet(struct sk_buf
+
+ return 0;
+ }
+-
++
+ /* The typical workload of the driver:
+ Handle the network interface interrupts. */
+-
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++
++static irqreturn_t net_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+@@ -1740,7 +1740,7 @@ net_close(struct net_device *dev)
+ #endif
+
+ netif_stop_queue(dev);
+-
++
+ writereg(dev, PP_RxCFG, 0);
+ writereg(dev, PP_TxCFG, 0);
+ writereg(dev, PP_BufCFG, 0);
+@@ -1791,7 +1791,7 @@ static void set_multicast_list(struct ne
+ /* The multicast-accept list is initialized to accept-all, and we
+ rely on higher-level filtering for now. */
+ lp->rx_mode = RX_MULTCAST_ACCEPT;
+- }
++ }
+ else
+ lp->rx_mode = 0;
+
+@@ -1833,8 +1833,8 @@ static int set_mac_address(struct net_de
+ static struct net_device *dev_cs89x0;
+
+ /*
+- * Support the 'debug' module parm even if we're compiled for non-debug to
+- * avoid breaking someone's startup scripts
++ * Support the 'debug' module parm even if we're compiled for non-debug to
++ * avoid breaking someone's startup scripts
+ */
+
+ static int io;
+@@ -1983,7 +1983,7 @@ cleanup_module(void)
+ free_netdev(dev_cs89x0);
+ }
+ #endif /* MODULE */
+-
++
+ /*
+ * Local variables:
+ * version-control: t
+diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
+index 968fe11..204ed37 100644
+--- a/drivers/net/cs89x0.h
++++ b/drivers/net/cs89x0.h
+@@ -427,8 +427,8 @@
+ #define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */
+
+ #define CS8900 0x0000
+-#define CS8920 0x4000
+-#define CS8920M 0x6000
++#define CS8920 0x4000
++#define CS8920M 0x6000
+ #define REVISON_BITS 0x1F00
+ #define EEVER_NUMBER 0x12
+ #define CHKSUM_LEN 0x14
+diff --git a/drivers/net/de600.c b/drivers/net/de600.c
+index 56a100f..690bb40 100644
+--- a/drivers/net/de600.c
++++ b/drivers/net/de600.c
+@@ -179,7 +179,7 @@ static inline void trigger_interrupt(str
+ * Copy a buffer to the adapter transmit page memory.
+ * Start sending.
+ */
+-
++
+ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ unsigned long flags;
+@@ -258,21 +258,15 @@ static int de600_start_xmit(struct sk_bu
+ * Handle the network interface interrupts.
+ */
+
+-static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t de600_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ u8 irq_status;
+ int retrig = 0;
+ int boguscount = 0;
+
+- /* This might just as well be deleted now, no crummy drivers present :-) */
+- if ((dev == NULL) || (DE600_IRQ != irq)) {
+- printk(KERN_ERR "%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
+- return IRQ_NONE;
+- }
+-
+ spin_lock(&de600_lock);
+-
++
+ select_nic();
+ irq_status = de600_read_status(dev);
+
+diff --git a/drivers/net/de600.h b/drivers/net/de600.h
+index e407301..1288e48 100644
+--- a/drivers/net/de600.h
++++ b/drivers/net/de600.h
+@@ -125,7 +125,7 @@ static struct net_device_stats *get_stat
+ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+ /* Dispatch from interrupts. */
+-static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t de600_interrupt(int irq, void *dev_id);
+ static int de600_tx_intr(struct net_device *dev, int irq_status);
+ static void de600_rx_intr(struct net_device *dev);
+
+diff --git a/drivers/net/de620.c b/drivers/net/de620.c
+index 22fc5b8..b6ad0cb 100644
+--- a/drivers/net/de620.c
++++ b/drivers/net/de620.c
+@@ -40,7 +40,7 @@
+ *****************************************************************************/
+ static const char version[] =
+ "de620.c: $Revision: 1.40 $, Bjorn Ekwall <bj0rn at blox.se>\n";
+-
++
+ /***********************************************************************
+ *
+ * "Tuning" section.
+@@ -115,7 +115,7 @@ static const char version[] =
+ #define COUNT_LOOPS
+ */
+ #endif
+-
++
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+@@ -221,7 +221,7 @@ static void de620_set_multicast_list(str
+ static int de620_start_xmit(struct sk_buff *, struct net_device *);
+
+ /* Dispatch from interrupts. */
+-static irqreturn_t de620_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t de620_interrupt(int, void *);
+ static int de620_rx_intr(struct net_device *);
+
+ /* Initialization */
+@@ -250,7 +250,7 @@ static struct nic {
+ byte Media;
+ byte SCR;
+ } nic_data;
+-
++
+ /**********************************************************
+ * *
+ * Convenience macros/functions for D-Link DE-620 adapter *
+@@ -432,7 +432,7 @@ de620_get_register(struct net_device *de
+
+ return value;
+ }
+-
++
+ /*********************************************************************
+ *
+ * Open/initialize the board.
+@@ -515,10 +515,10 @@ static void de620_set_multicast_list(str
+ }
+
+ /*******************************************************
+- *
++ *
+ * Handle timeouts on transmit
+ */
+-
++
+ static void de620_timeout(struct net_device *dev)
+ {
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
+@@ -540,9 +540,9 @@ static int de620_start_xmit(struct sk_bu
+ byte using_txbuf;
+
+ using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
+-
++
+ netif_stop_queue(dev);
+-
++
+
+ if ((len = skb->len) < RUNT)
+ len = RUNT;
+@@ -584,14 +584,14 @@ static int de620_start_xmit(struct sk_bu
+ dev_kfree_skb (skb);
+ return 0;
+ }
+-
++
+ /*****************************************************
+ *
+ * Handle the network interface interrupts.
+ *
+ */
+ static irqreturn_t
+-de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
++de620_interrupt(int irq_in, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ byte irq_status;
+@@ -599,7 +599,7 @@ de620_interrupt(int irq_in, void *dev_id
+ int again = 0;
+
+ spin_lock(&de620_lock);
+-
++
+ /* Read the status register (_not_ the status port) */
+ irq_status = de620_get_register(dev, R_STS);
+
+@@ -615,7 +615,7 @@ de620_interrupt(int irq_in, void *dev_id
+
+ if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
+ netif_wake_queue(dev);
+-
++
+ spin_unlock(&de620_lock);
+ return IRQ_HANDLED;
+ }
+@@ -720,7 +720,7 @@ static int de620_rx_intr(struct net_devi
+
+ return (next_rx_page != curr_page); /* That was slightly tricky... */
+ }
+-
++
+ /*********************************************
+ *
+ * Reset the adapter to a known state
+@@ -803,7 +803,7 @@ static int adapter_init(struct net_devic
+
+ return 0; /* all ok */
+ }
+-
++
+ /******************************************************************************
+ *
+ * Only start-up code below
+@@ -827,7 +827,7 @@ struct net_device * __init de620_probe(i
+ SET_MODULE_OWNER(dev);
+
+ spin_lock_init(&de620_lock);
+-
++
+ /*
+ * This is where the base_addr and irq gets set.
+ * Tunable at compile-time and insmod-time
+@@ -840,7 +840,7 @@ struct net_device * __init de620_probe(i
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+ }
+-
++
+ if (de620_debug)
+ printk(version);
+
+@@ -889,7 +889,7 @@ struct net_device * __init de620_probe(i
+ dev->tx_timeout = de620_timeout;
+ dev->watchdog_timeo = HZ*2;
+ dev->set_multicast_list = de620_set_multicast_list;
+-
++
+ /* base_addr and irq are already set, see above! */
+
+ /* dump eeprom */
+@@ -917,7 +917,7 @@ out1:
+ out:
+ return ERR_PTR(err);
+ }
+-
++
+ /**********************************
+ *
+ * Read info from on-board EEPROM
+@@ -1003,7 +1003,7 @@ static int __init read_eeprom(struct net
+
+ return 0; /* no errors */
+ }
+-
++
+ /******************************************************************************
+ *
+ * Loadable module skeleton
+@@ -1029,7 +1029,7 @@ void cleanup_module(void)
+ #endif /* MODULE */
+ MODULE_LICENSE("GPL");
+
+-
++
+ /*
+ * (add '-DMODULE' when compiling as loadable module)
+ *
+diff --git a/drivers/net/declance.c b/drivers/net/declance.c
+index 6ad5796..00e2a8a 100644
+--- a/drivers/net/declance.c
++++ b/drivers/net/declance.c
+@@ -1,4 +1,4 @@
+-/*
++/*
+ * Lance ethernet driver for the MIPS processor based
+ * DECstation family
+ *
+@@ -158,9 +158,9 @@ MODULE_LICENSE("GPL");
+
+ /* The DS2000/3000 have a linear 64 KB buffer.
+
+- * The PMAD-AA has 128 kb buffer on-board.
++ * The PMAD-AA has 128 kb buffer on-board.
+ *
+- * The IOASIC LANCE devices use a shared memory region. This region as seen
++ * The IOASIC LANCE devices use a shared memory region. This region as seen
+ * from the CPU is (max) 128 KB long and has to be on an 128 KB boundary.
+ * The LANCE sees this as a 64 KB long continuous memory region.
+ *
+@@ -694,19 +694,17 @@ out:
+ spin_unlock(&lp->lock);
+ }
+
+-static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+
+ printk("%s: DMA error\n", dev->name);
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t lance_interrupt(const int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t lance_interrupt(const int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct lance_private *lp = netdev_priv(dev);
+ volatile struct lance_regs *ll = lp->ll;
+ int csr0;
+@@ -882,7 +880,7 @@ static int lance_start_xmit(struct sk_bu
+ skblen = skb->len;
+
+ len = skblen;
+-
++
+ if (len < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
+diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
+index 91cc8cb..8f514cc 100644
+--- a/drivers/net/defxx.c
++++ b/drivers/net/defxx.c
+@@ -248,8 +248,7 @@ static int dfx_close(struct net_device
+ 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 irqreturn_t dfx_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t dfx_interrupt(int irq, void *dev_id);
+
+ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
+ static void dfx_ctl_set_multicast_list(struct net_device *dev);
+@@ -275,7 +274,7 @@ static void dfx_xmt_flush(DFX_board_t *
+
+ static struct net_device *root_dfx_eisa_dev;
+
+-
++
+ /*
+ * =======================
+ * = dfx_port_write_byte =
+@@ -283,13 +282,13 @@ static struct net_device *root_dfx_eisa_
+ * = dfx_port_write_long =
+ * = dfx_port_read_long =
+ * =======================
+- *
++ *
+ * Overview:
+ * Routines for reading and writing values from/to adapter
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ * offset - register offset from base I/O address
+@@ -301,7 +300,7 @@ static struct net_device *root_dfx_eisa_
+ * Functional Description:
+ * These routines perform the correct operation to read or write
+ * the adapter register.
+- *
++ *
+ * EISA port block base addresses are based on the slot number in which the
+ * controller is installed. For example, if the EISA controller is installed
+ * in slot 4, the port block base address is 0x4000. If the controller is
+@@ -377,18 +376,18 @@ static inline void dfx_port_read_long(
+ *data = inl(port);
+ }
+
+-
++
+ /*
+ * =============
+ * = dfx_init_one_pci_or_eisa =
+ * =============
+- *
++ *
+ * Overview:
+ * Initializes a supported FDDI EISA or PCI controller
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * pdev - pointer to pci device information (NULL for EISA)
+ * ioaddr - pointer to port (NULL for PCI)
+@@ -537,18 +536,18 @@ static int __init dfx_eisa_init(void)
+ }
+ return rc;
+ }
+-
++
+ /*
+ * ================
+ * = dfx_bus_init =
+ * ================
+- *
++ *
+ * Overview:
+ * Initializes EISA and PCI controller bus-specific logic.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+@@ -672,19 +671,19 @@ static void __devinit dfx_bus_init(struc
+ }
+ }
+
+-
++
+ /*
+ * ========================
+ * = dfx_bus_config_check =
+ * ========================
+- *
++ *
+ * Overview:
+ * Checks the configuration (burst size, full-duplex, etc.) If any parameters
+ * are illegal, then this routine will set new defaults.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -766,19 +765,19 @@ static void __devinit dfx_bus_config_che
+ }
+ }
+
+-
++
+ /*
+ * ===================
+ * = dfx_driver_init =
+ * ===================
+- *
++ *
+ * Overview:
+ * Initializes remaining adapter board structure information
+ * and makes sure adapter is in a safe state prior to dfx_open().
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ * print_name - printable device name
+@@ -984,18 +983,18 @@ static int __devinit dfx_driver_init(str
+ return(DFX_K_SUCCESS);
+ }
+
+-
++
+ /*
+ * =================
+ * = dfx_adap_init =
+ * =================
+- *
++ *
+ * Overview:
+ * Brings the adapter to the link avail/link unavailable state.
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ * get_buffers - non-zero if buffers to be allocated
+@@ -1188,18 +1187,18 @@ static int dfx_adap_init(DFX_board_t *bp
+ return(DFX_K_SUCCESS);
+ }
+
+-
++
+ /*
+ * ============
+ * = dfx_open =
+ * ============
+- *
++ *
+ * Overview:
+ * Opens the adapter
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+@@ -1225,7 +1224,7 @@ static int dfx_open(struct net_device *d
+ DFX_board_t *bp = dev->priv;
+
+ DBG_printk("In dfx_open...\n");
+-
++
+ /* Register IRQ - support shared interrupts by passing device ptr */
+
+ ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev);
+@@ -1276,18 +1275,18 @@ static int dfx_open(struct net_device *d
+ return(0);
+ }
+
+-
++
+ /*
+ * =============
+ * = dfx_close =
+ * =============
+- *
++ *
+ * Overview:
+ * Closes the device/module.
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+@@ -1360,26 +1359,26 @@ static int dfx_close(struct net_device *
+ /* Clear device structure flags */
+
+ netif_stop_queue(dev);
+-
++
+ /* Deregister (free) IRQ */
+
+ free_irq(dev->irq, dev);
+-
++
+ return(0);
+ }
+
+-
++
+ /*
+ * ======================
+ * = dfx_int_pr_halt_id =
+ * ======================
+- *
++ *
+ * Overview:
+ * Displays halt id's in string form.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -1452,18 +1451,18 @@ static void dfx_int_pr_halt_id(DFX_board
+ }
+ }
+
+-
++
+ /*
+ * ==========================
+ * = dfx_int_type_0_process =
+ * ==========================
+- *
++ *
+ * Overview:
+ * Processes Type 0 interrupts.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -1569,7 +1568,7 @@ static void dfx_int_type_0_process(DFX_b
+ /* Check for adapter state change */
+
+ if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE)
+- {
++ {
+ /* Get latest adapter state */
+
+ state = dfx_hw_adap_state_rd(bp); /* get adapter state */
+@@ -1604,18 +1603,18 @@ static void dfx_int_type_0_process(DFX_b
+ }
+ }
+
+-
++
+ /*
+ * ==================
+ * = dfx_int_common =
+ * ==================
+- *
++ *
+ * Overview:
+ * Interrupt service routine (ISR)
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -1678,7 +1677,7 @@ static void dfx_int_common(struct net_de
+ dfx_int_type_0_process(bp); /* process Type 0 interrupts */
+ }
+
+-
++
+ /*
+ * =================
+ * = dfx_interrupt =
+@@ -1693,7 +1692,6 @@ static void dfx_int_common(struct net_de
+ * Arguments:
+ * irq - interrupt vector
+ * dev_id - pointer to device information
+- * regs - pointer to registers structure
+ *
+ * Functional Description:
+ * This routine calls the interrupt processing routine for this adapter. It
+@@ -1716,7 +1714,7 @@ static void dfx_int_common(struct net_de
+ * Interrupts are disabled, then reenabled at the adapter.
+ */
+
+-static irqreturn_t dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dfx_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ DFX_board_t *bp; /* private board structure pointer */
+@@ -1780,18 +1778,18 @@ static irqreturn_t dfx_interrupt(int irq
+ return IRQ_HANDLED;
+ }
+
+-
++
+ /*
+ * =====================
+ * = dfx_ctl_get_stats =
+ * =====================
+- *
++ *
+ * Overview:
+ * Get statistics for FDDI adapter
+- *
++ *
+ * Returns:
+ * Pointer to FDDI statistics structure
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+@@ -1967,19 +1965,19 @@ static struct net_device_stats *dfx_ctl_
+ return((struct net_device_stats *) &bp->stats);
+ }
+
+-
++
+ /*
+ * ==============================
+ * = dfx_ctl_set_multicast_list =
+ * ==============================
+- *
++ *
+ * Overview:
+ * Enable/Disable LLC frame promiscuous mode reception
+ * on the adapter and/or update multicast address table.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+@@ -2088,19 +2086,19 @@ static void dfx_ctl_set_multicast_list(s
+ }
+ }
+
+-
++
+ /*
+ * ===========================
+ * = dfx_ctl_set_mac_address =
+ * ===========================
+- *
++ *
+ * Overview:
+ * Add node address override (unicast address) to adapter
+ * CAM and update dev_addr field in device table.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * dev - pointer to device information
+ * addr - pointer to sockaddr structure containing unicast address to add
+@@ -2178,7 +2176,7 @@ static int dfx_ctl_set_mac_address(struc
+ return(0); /* always return zero */
+ }
+
+-
++
+ /*
+ * ======================
+ * = dfx_ctl_update_cam =
+@@ -2263,7 +2261,7 @@ static int dfx_ctl_update_cam(DFX_board_
+ return(DFX_K_SUCCESS);
+ }
+
+-
++
+ /*
+ * ==========================
+ * = dfx_ctl_update_filters =
+@@ -2272,10 +2270,10 @@ static int dfx_ctl_update_cam(DFX_board_
+ * Overview:
+ * Procedure to update adapter filters with desired
+ * filter settings.
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -2329,18 +2327,18 @@ static int dfx_ctl_update_filters(DFX_bo
+ return(DFX_K_SUCCESS);
+ }
+
+-
++
+ /*
+ * ======================
+ * = dfx_hw_dma_cmd_req =
+ * ======================
+- *
++ *
+ * Overview:
+ * Sends PDQ DMA command to adapter firmware
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -2374,9 +2372,9 @@ static int dfx_hw_dma_cmd_req(DFX_board_
+ {
+ int status; /* adapter status */
+ int timeout_cnt; /* used in for loops */
+-
++
+ /* Make sure the adapter is in a state that we can issue the DMA command in */
+-
++
+ status = dfx_hw_adap_state_rd(bp);
+ if ((status == PI_STATE_K_RESET) ||
+ (status == PI_STATE_K_HALTED) ||
+@@ -2397,7 +2395,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_
+ dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword);
+
+ /* Put request buffer on the command request queue */
+-
++
+ bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP |
+ PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN));
+ bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys;
+@@ -2419,7 +2417,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_
+ break;
+ udelay(100); /* wait for 100 microseconds */
+ }
+- if (timeout_cnt == 0)
++ if (timeout_cnt == 0)
+ return(DFX_K_HW_TIMEOUT);
+
+ /* Bump (and wrap) the completion index and write out to register */
+@@ -2439,7 +2437,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_
+ break;
+ udelay(100); /* wait for 100 microseconds */
+ }
+- if (timeout_cnt == 0)
++ if (timeout_cnt == 0)
+ return(DFX_K_HW_TIMEOUT);
+
+ /* Bump (and wrap) the completion index and write out to register */
+@@ -2450,18 +2448,18 @@ static int dfx_hw_dma_cmd_req(DFX_board_
+ return(DFX_K_SUCCESS);
+ }
+
+-
++
+ /*
+ * ========================
+ * = dfx_hw_port_ctrl_req =
+ * ========================
+- *
++ *
+ * Overview:
+ * Sends PDQ port control command to adapter firmware
+- *
++ *
+ * Returns:
+ * Host data register value in host_data if ptr is not NULL
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ * command - port control command
+@@ -2497,7 +2495,7 @@ static int dfx_hw_port_ctrl_req(
+ int timeout_cnt; /* used in for loops */
+
+ /* Set Command Error bit in command longword */
+-
++
+ port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR);
+
+ /* Issue port command to the adapter */
+@@ -2520,12 +2518,12 @@ static int dfx_hw_port_ctrl_req(
+ break;
+ udelay(100); /* wait for 100 microseconds */
+ }
+- if (timeout_cnt == 0)
++ if (timeout_cnt == 0)
+ return(DFX_K_HW_TIMEOUT);
+
+ /*
+- * If the address of host_data is non-zero, assume caller has supplied a
+- * non NULL pointer, and return the contents of the HOST_DATA register in
++ * If the address of host_data is non-zero, assume caller has supplied a
++ * non NULL pointer, and return the contents of the HOST_DATA register in
+ * it.
+ */
+
+@@ -2534,18 +2532,18 @@ static int dfx_hw_port_ctrl_req(
+ return(DFX_K_SUCCESS);
+ }
+
+-
++
+ /*
+ * =====================
+ * = dfx_hw_adap_reset =
+ * =====================
+- *
++ *
+ * Overview:
+ * Resets adapter
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ * type - type of reset to perform
+@@ -2588,18 +2586,18 @@ static void dfx_hw_adap_reset(
+ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0);
+ }
+
+-
++
+ /*
+ * ========================
+ * = dfx_hw_adap_state_rd =
+ * ========================
+- *
++ *
+ * Overview:
+ * Returns current adapter state
+- *
++ *
+ * Returns:
+ * Adapter state per PDQ Port Specification
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -2624,18 +2622,18 @@ static int dfx_hw_adap_state_rd(DFX_boar
+ return((port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE);
+ }
+
+-
++
+ /*
+ * =====================
+ * = dfx_hw_dma_uninit =
+ * =====================
+- *
++ *
+ * Overview:
+ * Brings adapter to DMA_UNAVAILABLE state
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ * type - type of reset to perform
+@@ -2672,38 +2670,38 @@ static int dfx_hw_dma_uninit(DFX_board_t
+ break;
+ udelay(100); /* wait for 100 microseconds */
+ }
+- if (timeout_cnt == 0)
++ if (timeout_cnt == 0)
+ return(DFX_K_HW_TIMEOUT);
+ return(DFX_K_SUCCESS);
+ }
+-
++
+ /*
+ * Align an sk_buff to a boundary power of 2
+ *
+ */
+-
++
+ static void my_skb_align(struct sk_buff *skb, int n)
+ {
+ unsigned long x = (unsigned long)skb->data;
+ unsigned long v;
+-
++
+ v = ALIGN(x, n); /* Where we want to be */
+-
++
+ skb_reserve(skb, v - x);
+ }
+
+-
++
+ /*
+ * ================
+ * = dfx_rcv_init =
+ * ================
+- *
++ *
+ * Overview:
+ * Produces buffers to adapter LLC Host receive descriptor block
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ * get_buffers - non-zero if buffers to be allocated
+@@ -2764,7 +2762,7 @@ static int dfx_rcv_init(DFX_board_t *bp,
+ * align to 128 bytes for compatibility with
+ * the old EISA boards.
+ */
+-
++
+ my_skb_align(newskb, 128);
+ bp->descr_block_virt->rcv_data[i + j].long_1 =
+ (u32)pci_map_single(bp->pci_dev, newskb->data,
+@@ -2795,18 +2793,18 @@ static int dfx_rcv_init(DFX_board_t *bp,
+ return 0;
+ }
+
+-
++
+ /*
+ * =========================
+ * = dfx_rcv_queue_process =
+ * =========================
+- *
++ *
+ * Overview:
+ * Process received LLC frames.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -2880,7 +2878,7 @@ static void dfx_rcv_queue_process(
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ if (newskb){
+ rx_in_place = 1;
+-
++
+ my_skb_align(newskb, 128);
+ skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
+ pci_unmap_single(bp->pci_dev,
+@@ -2914,7 +2912,7 @@ static void dfx_rcv_queue_process(
+
+ memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ }
+-
++
+ skb_reserve(skb,3); /* adjust data field so that it points to FC byte */
+ skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */
+ skb->dev = bp->dev; /* pass up device pointer */
+@@ -2945,18 +2943,18 @@ static void dfx_rcv_queue_process(
+ }
+ }
+
+-
++
+ /*
+ * =====================
+ * = dfx_xmt_queue_pkt =
+ * =====================
+- *
++ *
+ * Overview:
+ * Queues packets for transmission
+- *
++ *
+ * Returns:
+ * Condition code
+- *
++ *
+ * Arguments:
+ * skb - pointer to sk_buff to queue for transmission
+ * dev - pointer to device information
+@@ -3020,7 +3018,7 @@ static int dfx_xmt_queue_pkt(
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+-
++
+ /*
+ * Verify that incoming transmit request is OK
+ *
+@@ -3032,7 +3030,7 @@ static int dfx_xmt_queue_pkt(
+
+ if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
+ {
+- printk("%s: Invalid packet length - %u bytes\n",
++ printk("%s: Invalid packet length - %u bytes\n",
+ dev->name, skb->len);
+ bp->xmt_length_errors++; /* bump error counter */
+ netif_wake_queue(dev);
+@@ -3065,7 +3063,7 @@ static int dfx_xmt_queue_pkt(
+ }
+
+ spin_lock_irqsave(&bp->lock, flags);
+-
++
+ /* Get the current producer and the next free xmt data descriptor */
+
+ prod = bp->rcv_xmt_reg.index.xmt_prod;
+@@ -3167,18 +3165,18 @@ static int dfx_xmt_queue_pkt(
+ return(0); /* packet queued to adapter */
+ }
+
+-
++
+ /*
+ * ================
+ * = dfx_xmt_done =
+ * ================
+- *
++ *
+ * Overview:
+ * Processes all frames that have been transmitted.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -3246,18 +3244,18 @@ static int dfx_xmt_done(DFX_board_t *bp)
+ return freed;
+ }
+
+-
++
+ /*
+ * =================
+ * = dfx_rcv_flush =
+ * =================
+- *
++ *
+ * Overview:
+ * Remove all skb's in the receive ring.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -3299,14 +3297,14 @@ static inline void dfx_rcv_flush( DFX_bo
+ * =================
+ * = dfx_xmt_flush =
+ * =================
+- *
++ *
+ * Overview:
+ * Processes all frames whether they've been transmitted
+ * or not.
+- *
++ *
+ * Returns:
+ * None
+- *
++ *
+ * Arguments:
+ * bp - pointer to board information
+ *
+@@ -3444,13 +3442,13 @@ static int __init dfx_init(void)
+ {
+ int rc_pci, rc_eisa;
+
+- rc_pci = pci_module_init(&dfx_driver);
++ rc_pci = pci_register_driver(&dfx_driver);
+ if (rc_pci >= 0) dfx_have_pci = 1;
+-
++
+ rc_eisa = dfx_eisa_init();
+ if (rc_eisa >= 0) dfx_have_eisa = 1;
+
+- return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
++ return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
+ }
+
+ static void __exit dfx_cleanup(void)
+@@ -3459,8 +3457,8 @@ static void __exit dfx_cleanup(void)
+ pci_unregister_driver(&dfx_driver);
+ if (dfx_have_eisa)
+ dfx_eisa_cleanup();
+-
+-}
++
++}
+
+ module_init(dfx_init);
+ module_exit(dfx_cleanup);
+@@ -3469,7 +3467,7 @@ MODULE_DESCRIPTION("DEC FDDIcontroller E
+ DRV_VERSION " " DRV_RELDATE);
+ MODULE_LICENSE("GPL");
+
+-
++
+ /*
+ * Local variables:
+ * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c"
+diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
+index a480b80..8b1e9a1 100644
+--- a/drivers/net/defxx.h
++++ b/drivers/net/defxx.h
+@@ -45,7 +45,7 @@ typedef struct /* 64-bit counter *
+ } PI_CNTR;
+
+ typedef struct /* LAN address */
+- {
++ {
+ PI_UINT32 lwrd_0;
+ PI_UINT32 lwrd_1;
+ } PI_LAN_ADDR;
+@@ -146,7 +146,7 @@ typedef struct /* Station ID addre
+ #define PI_STATE_K_LINK_UNAVAIL 5
+ #define PI_STATE_K_HALTED 6
+ #define PI_STATE_K_RING_MEMBER 7
+-#define PI_STATE_K_NUMBER 8
++#define PI_STATE_K_NUMBER 8
+
+ /* Define codes for command type */
+
+@@ -175,9 +175,9 @@ typedef struct /* Station ID addre
+ #define PI_ITEM_K_EOL 0x00 /* End-of-Item list */
+ #define PI_ITEM_K_T_REQ 0x01 /* DECnet T_REQ */
+ #define PI_ITEM_K_TVX 0x02 /* DECnet TVX */
+-#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */
++#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */
+ #define PI_ITEM_K_LEM_THRESHOLD 0x04 /* DECnet LEM Threshold */
+-#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */
++#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */
+ #define PI_ITEM_K_CNTR_INTERVAL 0x06 /* Chars_Set */
+ #define PI_ITEM_K_IND_GROUP_PROM 0x07 /* Filters_Set */
+ #define PI_ITEM_K_GROUP_PROM 0x08 /* Filters_Set */
+@@ -283,16 +283,16 @@ typedef struct
+
+ /* Start Response */
+
+-typedef struct
++typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_START_RSP;
+
+ /* Filters_Set Request */
+
+ #define PI_CMD_FILTERS_SET_K_ITEMS_MAX 63 /* Fits in a 512 byte buffer */
+
+-typedef struct
++typedef struct
+ {
+ PI_UINT32 cmd_type;
+ PI_ITEM_LIST item[PI_CMD_FILTERS_SET_K_ITEMS_MAX];
+@@ -302,21 +302,21 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_FILTERS_SET_RSP;
+
+ /* Filters_Get Request */
+
+ typedef struct
+ {
+- PI_UINT32 cmd_type;
++ PI_UINT32 cmd_type;
+ } PI_CMD_FILTERS_GET_REQ;
+
+ /* Filters_Get Response */
+
+-typedef struct
++typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ PI_UINT32 ind_group_prom;
+ PI_UINT32 group_prom;
+ PI_UINT32 broadcast_all;
+@@ -339,14 +339,14 @@ typedef struct
+ PI_UINT32 item_code;
+ PI_UINT32 value;
+ PI_UINT32 item_index;
+- } item[PI_CMD_CHARS_SET_K_ITEMS_MAX];
++ } item[PI_CMD_CHARS_SET_K_ITEMS_MAX];
+ } PI_CMD_CHARS_SET_REQ;
+
+ /* Chars_Set Response */
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_CHARS_SET_RSP;
+
+
+@@ -362,20 +362,20 @@ typedef struct
+ PI_UINT32 item_code;
+ PI_UINT32 value;
+ PI_UINT32 item_index;
+- } item[PI_CMD_SNMP_SET_K_ITEMS_MAX];
++ } item[PI_CMD_SNMP_SET_K_ITEMS_MAX];
+ } PI_CMD_SNMP_SET_REQ;
+
+ /* SNMP_Set Response */
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_SNMP_SET_RSP;
+
+
+ /* SMT_MIB_Set Request */
+
+-#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */
++#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */
+
+ typedef struct
+ {
+@@ -392,7 +392,7 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_SMT_MIB_SET_RSP;
+
+ /* SMT_MIB_Get Request */
+@@ -407,8 +407,8 @@ typedef struct
+ typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */
+ {
+ PI_RSP_HEADER header;
+-
+- /* SMT GROUP */
++
++ /* SMT GROUP */
+
+ PI_STATION_ID smt_station_id;
+ PI_UINT32 smt_op_version_id;
+@@ -485,7 +485,7 @@ typedef struct /* Refer to ANSI F
+ PI_UINT32 port_connection_capabilities[PI_PHY_K_MAX];
+ PI_UINT32 port_bs_flag[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_estimate[PI_PHY_K_MAX];
+- PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
++ PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_alarm[PI_PHY_K_MAX];
+ PI_UINT32 port_connect_state[PI_PHY_K_MAX];
+ PI_UINT32 port_pcm_state[PI_PHY_K_MAX];
+@@ -497,7 +497,7 @@ typedef struct /* Refer to ANSI F
+
+ PI_CNTR path_ring_latency;
+
+- } PI_CMD_SMT_MIB_GET_RSP;
++ } PI_CMD_SMT_MIB_GET_RSP;
+
+
+ /*
+@@ -506,7 +506,7 @@ typedef struct /* Refer to ANSI F
+ * certain host-sent SMT frames such as PMF Get and Set requests. The
+ * codes have been taken from the MIB summary section of ANSI SMT 7.3.
+ */
+-
++
+ #define PI_GRP_K_SMT_STATION_ID 0x100A
+ #define PI_ITEM_K_SMT_STATION_ID 0x100B
+ #define PI_ITEM_K_SMT_OP_VERS_ID 0x100D
+@@ -536,7 +536,7 @@ typedef struct /* Refer to ANSI F
+ #define PI_ITEM_K_SMT_REM_DISC_FLAG 0x102C
+ #define PI_ITEM_K_SMT_STATION_STATUS 0x102D
+ #define PI_ITEM_K_SMT_PEER_WRAP_FLAG 0x102E
+-
++
+ #define PI_GRP_K_SMT_MIB_OPERATION 0x1032
+ #define PI_ITEM_K_SMT_MSG_TIME_STAMP 0x1033
+ #define PI_ITEM_K_SMT_TRN_TIME_STAMP 0x1034
+@@ -643,9 +643,9 @@ typedef struct
+
+ /* Addr_Filter_Set Response */
+
+-typedef struct
++typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_ADDR_FILTER_SET_RSP;
+
+ /* Addr_Filter_Get Request */
+@@ -659,7 +659,7 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE];
+ } PI_CMD_ADDR_FILTER_GET_RSP;
+
+@@ -674,7 +674,7 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ PI_STATION_ID station_id; /* Station */
+ PI_UINT32 station_type;
+ PI_UINT32 smt_ver_id;
+@@ -728,66 +728,66 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+
+ /* SMT GROUP */
+
+- PI_STATION_ID smt_station_id;
++ PI_STATION_ID smt_station_id;
+ PI_UINT32 smt_op_version_id;
+ PI_UINT32 smt_hi_version_id;
+ PI_UINT32 smt_lo_version_id;
+- PI_UINT32 smt_mac_ct;
+- PI_UINT32 smt_non_master_ct;
+- PI_UINT32 smt_master_ct;
+- PI_UINT32 smt_paths_available;
+- PI_UINT32 smt_config_capabilities;
+- PI_UINT32 smt_config_policy;
+- PI_UINT32 smt_connection_policy;
+- PI_UINT32 smt_t_notify;
++ PI_UINT32 smt_mac_ct;
++ PI_UINT32 smt_non_master_ct;
++ PI_UINT32 smt_master_ct;
++ PI_UINT32 smt_paths_available;
++ PI_UINT32 smt_config_capabilities;
++ PI_UINT32 smt_config_policy;
++ PI_UINT32 smt_connection_policy;
++ PI_UINT32 smt_t_notify;
+ PI_UINT32 smt_status_reporting;
+- PI_UINT32 smt_ecm_state;
+- PI_UINT32 smt_cf_state;
+- PI_UINT32 smt_hold_state;
++ PI_UINT32 smt_ecm_state;
++ PI_UINT32 smt_cf_state;
++ PI_UINT32 smt_hold_state;
+ PI_UINT32 smt_remote_disconnect_flag;
+- PI_UINT32 smt_station_action;
++ PI_UINT32 smt_station_action;
+
+ /* MAC GROUP */
+
+- PI_UINT32 mac_frame_status_capabilities;
++ PI_UINT32 mac_frame_status_capabilities;
+ PI_UINT32 mac_t_max_greatest_lower_bound;
+ PI_UINT32 mac_tvx_greatest_lower_bound;
+ PI_UINT32 mac_paths_available;
+ PI_UINT32 mac_current_path;
+- PI_LAN_ADDR mac_upstream_nbr;
+- PI_LAN_ADDR mac_old_upstream_nbr;
+- PI_UINT32 mac_dup_addr_test;
++ PI_LAN_ADDR mac_upstream_nbr;
++ PI_LAN_ADDR mac_old_upstream_nbr;
++ PI_UINT32 mac_dup_addr_test;
+ PI_UINT32 mac_paths_requested;
+ PI_UINT32 mac_downstream_port_type;
+- PI_LAN_ADDR mac_smt_address;
+- PI_UINT32 mac_t_req;
++ PI_LAN_ADDR mac_smt_address;
++ PI_UINT32 mac_t_req;
+ PI_UINT32 mac_t_neg;
+- PI_UINT32 mac_t_max;
+- PI_UINT32 mac_tvx_value;
+- PI_UINT32 mac_t_min;
++ PI_UINT32 mac_t_max;
++ PI_UINT32 mac_tvx_value;
++ PI_UINT32 mac_t_min;
+ PI_UINT32 mac_current_frame_status;
+ /* mac_frame_cts */
+ /* mac_error_cts */
+ /* mac_lost_cts */
+- PI_UINT32 mac_frame_error_threshold;
+- PI_UINT32 mac_frame_error_ratio;
++ PI_UINT32 mac_frame_error_threshold;
++ PI_UINT32 mac_frame_error_ratio;
+ PI_UINT32 mac_rmt_state;
+ PI_UINT32 mac_da_flag;
+- PI_UINT32 mac_una_da_flag;
++ PI_UINT32 mac_una_da_flag;
+ PI_UINT32 mac_frame_condition;
+- PI_UINT32 mac_chip_set;
+- PI_UINT32 mac_action;
++ PI_UINT32 mac_chip_set;
++ PI_UINT32 mac_action;
+
+ /* PATH GROUP => Does not need to be implemented */
+
+ /* PORT GROUP */
+
+- PI_UINT32 port_pc_type[PI_PHY_K_MAX];
+- PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX];
++ PI_UINT32 port_pc_type[PI_PHY_K_MAX];
++ PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX];
+ PI_UINT32 port_connection_policies[PI_PHY_K_MAX];
+ PI_UINT32 port_remote_mac_indicated[PI_PHY_K_MAX];
+ PI_UINT32 port_ce_state[PI_PHY_K_MAX];
+@@ -798,17 +798,17 @@ typedef struct
+ PI_UINT32 port_tb_max[PI_PHY_K_MAX];
+ PI_UINT32 port_bs_flag[PI_PHY_K_MAX];
+ /* port_lct_fail_cts[PI_PHY_K_MAX]; */
+- PI_UINT32 port_ler_estimate[PI_PHY_K_MAX];
++ PI_UINT32 port_ler_estimate[PI_PHY_K_MAX];
+ /* port_lem_reject_cts[PI_PHY_K_MAX]; */
+ /* port_lem_cts[PI_PHY_K_MAX]; */
+- PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
+- PI_UINT32 port_ler_alarm[PI_PHY_K_MAX];
++ PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
++ PI_UINT32 port_ler_alarm[PI_PHY_K_MAX];
+ PI_UINT32 port_connect_state[PI_PHY_K_MAX];
+ PI_UINT32 port_pcm_state[PI_PHY_K_MAX];
+ PI_UINT32 port_pc_withhold[PI_PHY_K_MAX];
+- PI_UINT32 port_ler_condition[PI_PHY_K_MAX];
+- PI_UINT32 port_chip_set[PI_PHY_K_MAX];
+- PI_UINT32 port_action[PI_PHY_K_MAX];
++ PI_UINT32 port_ler_condition[PI_PHY_K_MAX];
++ PI_UINT32 port_chip_set[PI_PHY_K_MAX];
++ PI_UINT32 port_action[PI_PHY_K_MAX];
+
+ /* ATTACHMENT GROUP */
+
+@@ -833,7 +833,7 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+
+ /* SMT GROUP */
+
+@@ -841,7 +841,7 @@ typedef struct
+
+ /* MAC GROUP */
+
+- PI_UINT32 emac_link_state;
++ PI_UINT32 emac_link_state;
+ PI_UINT32 emac_ring_purger_state;
+ PI_UINT32 emac_ring_purger_enable;
+ PI_UINT32 emac_frame_strip_mode;
+@@ -915,9 +915,9 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
+- PI_CNTR time_since_reset;
+- PI_CNTR_BLK cntrs;
++ PI_RSP_HEADER header;
++ PI_CNTR time_since_reset;
++ PI_CNTR_BLK cntrs;
+ } PI_CMD_CNTRS_GET_RSP;
+
+ /* Counters_Set Request */
+@@ -925,14 +925,14 @@ typedef struct
+ typedef struct
+ {
+ PI_UINT32 cmd_type;
+- PI_CNTR_BLK cntrs;
++ PI_CNTR_BLK cntrs;
+ } PI_CMD_CNTRS_SET_REQ;
+
+ /* Counters_Set Response */
+
+-typedef struct
++typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_CNTRS_SET_RSP;
+
+ /* Error_Log_Clear Request */
+@@ -946,7 +946,7 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ } PI_CMD_ERROR_LOG_CLEAR_RSP;
+
+ /* Error_Log_Get Request */
+@@ -966,7 +966,7 @@ typedef struct
+
+ typedef struct
+ {
+- struct
++ struct
+ {
+ PI_UINT32 fru_imp_mask;
+ PI_UINT32 test_id;
+@@ -977,7 +977,7 @@ typedef struct
+
+ typedef struct
+ {
+- PI_RSP_HEADER header;
++ PI_RSP_HEADER header;
+ PI_UINT32 event_status;
+ PI_UINT32 caller_id;
+ PI_UINT32 timestamp_l;
+@@ -993,7 +993,7 @@ typedef struct
+ #define PI_LOG_EVENT_STATUS_K_VALID 0 /* Valid Event Status */
+ #define PI_LOG_EVENT_STATUS_K_INVALID 1 /* Invalid Event Status */
+ #define PI_LOG_CALLER_ID_K_NONE 0 /* No caller */
+-#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */
++#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */
+ #define PI_LOG_CALLER_ID_K_MFG 2 /* Mfg power-up selftest */
+ #define PI_LOG_CALLER_ID_K_ONLINE 3 /* On-line diagnostics */
+ #define PI_LOG_CALLER_ID_K_HW 4 /* Hardware */
+@@ -1026,7 +1026,7 @@ typedef union
+ PI_CMD_DEC_EXT_MIB_GET_REQ dec_mib_get;
+ PI_CMD_SMT_MIB_SET_REQ smt_mib_set;
+ PI_CMD_SMT_MIB_GET_REQ smt_mib_get;
+- char pad[PI_CMD_REQ_K_SIZE_MAX];
++ char pad[PI_CMD_REQ_K_SIZE_MAX];
+ } PI_DMA_CMD_REQ;
+
+ typedef union
+@@ -1048,7 +1048,7 @@ typedef union
+ PI_CMD_DEC_EXT_MIB_GET_RSP dec_mib_get;
+ PI_CMD_SMT_MIB_SET_RSP smt_mib_set;
+ PI_CMD_SMT_MIB_GET_RSP smt_mib_get;
+- char pad[PI_CMD_RSP_K_SIZE_MAX];
++ char pad[PI_CMD_RSP_K_SIZE_MAX];
+ } PI_DMA_CMD_RSP;
+
+ typedef union
+@@ -1094,7 +1094,7 @@ typedef struct
+ #define PI_DESCR_BLK_K_SMT_HOST 0x1000
+ #define PI_DESCR_BLK_K_UNSOL 0x1200
+ #define PI_DESCR_BLK_K_CMD_RSP 0x1280
+-#define PI_DESCR_BLK_K_CMD_REQ 0x1300
++#define PI_DESCR_BLK_K_CMD_REQ 0x1300
+
+ /* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host) */
+ /* Note a field has been added for later versions of the PDQ to allow for */
+@@ -1110,10 +1110,10 @@ typedef struct
+ } PI_RCV_DESCR;
+
+ #define PI_RCV_DESCR_M_SOP 0x80000000
+-#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000
+-#define PI_RCV_DESCR_M_MBZ 0x60000000
++#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000
++#define PI_RCV_DESCR_M_MBZ 0x60000000
+ #define PI_RCV_DESCR_M_SEG_LEN 0x1F800000
+-#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000
++#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000
+ #define PI_RCV_DESCR_M_SEG_CNT 0x000F0000
+ #define PI_RCV_DESCR_M_BUFF_HI 0x0000FFFF
+
+@@ -1121,7 +1121,7 @@ typedef struct
+ #define PI_RCV_DESCR_V_SEG_LEN_LO 29
+ #define PI_RCV_DESCR_V_MBZ 29
+ #define PI_RCV_DESCR_V_SEG_LEN 23
+-#define PI_RCV_DESCR_V_SEG_LEN_HI 20
++#define PI_RCV_DESCR_V_SEG_LEN_HI 20
+ #define PI_RCV_DESCR_V_SEG_CNT 16
+ #define PI_RCV_DESCR_V_BUFF_HI 0
+
+@@ -1135,7 +1135,7 @@ typedef struct
+
+ #define PI_XMT_DESCR_M_SOP 0x80000000
+ #define PI_XMT_DESCR_M_EOP 0x40000000
+-#define PI_XMT_DESCR_M_MBZ 0x20000000
++#define PI_XMT_DESCR_M_MBZ 0x20000000
+ #define PI_XMT_DESCR_M_SEG_LEN 0x1FFF0000
+ #define PI_XMT_DESCR_M_BUFF_HI 0x0000FFFF
+
+@@ -1195,7 +1195,7 @@ typedef struct
+ #define PI_PCTRL_M_CONS_BLOCK 0x0040
+ #define PI_PCTRL_M_UNINIT 0x0020
+ #define PI_PCTRL_M_RING_MEMBER 0x0010
+-#define PI_PCTRL_M_MLA 0x0008
++#define PI_PCTRL_M_MLA 0x0008
+ #define PI_PCTRL_M_FW_REV_READ 0x0004
+ #define PI_PCTRL_M_DEV_SPECIFIC 0x0002
+ #define PI_PCTRL_M_SUB_CMD 0x0001
+@@ -1230,12 +1230,12 @@ typedef struct
+
+ #define PI_PDATA_A_INIT_M_DESC_BLK_ADDR 0x0FFFFE000
+ #define PI_PDATA_A_INIT_M_RESERVED 0x000001FFC
+-#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002
++#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002
+ #define PI_PDATA_A_INIT_M_BSWAP_LITERAL 0x000000001
+
+ #define PI_PDATA_A_INIT_V_DESC_BLK_ADDR 13
+ #define PI_PDATA_A_INIT_V_RESERVED 3
+-#define PI_PDATA_A_INIT_V_BSWAP_DATA 1
++#define PI_PDATA_A_INIT_V_BSWAP_DATA 1
+ #define PI_PDATA_A_INIT_V_BSWAP_LITERAL 0
+
+ /* Port Reset Register */
+@@ -1281,11 +1281,11 @@ typedef struct
+ #define PI_HALT_ID_K_IMAGE_CRC_ERROR 7 /* Image is bad, update it */
+ #define PI_HALT_ID_K_BUS_EXCEPTION 8 /* 68K bus exception */
+
+-/* Host Interrupt Enable Register as seen by host */
++/* Host Interrupt Enable Register as seen by host */
+
+ #define PI_HOST_INT_M_XMT_DATA_ENB 0x80000000 /* Type 2 Enables */
+-#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000
+-#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */
++#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000
++#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */
+ #define PI_HOST_INT_M_UNSOL_ENB 0x20000000
+ #define PI_HOST_INT_M_CMD_RSP_ENB 0x08000000
+ #define PI_HOST_INT_M_CMD_REQ_ENB 0x04000000
+@@ -1301,8 +1301,8 @@ typedef struct
+ #define PI_HOST_INT_M_BUS_PAR_ERR 0x00000001
+
+ #define PI_HOST_INT_V_XMT_DATA_ENB 31 /* Type 2 Enables */
+-#define PI_HOST_INT_V_RCV_DATA_ENB 30
+-#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */
++#define PI_HOST_INT_V_RCV_DATA_ENB 30
++#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */
+ #define PI_HOST_INT_V_UNSOL_ENB 28
+ #define PI_HOST_INT_V_CMD_RSP_ENB 27
+ #define PI_HOST_INT_V_CMD_REQ_ENB 26
+@@ -1333,8 +1333,8 @@ typedef struct
+ #define PI_TYPE_0_STAT_M_PM_PAR_ERR 0x00000002
+ #define PI_TYPE_0_STAT_M_BUS_PAR_ERR 0x00000001
+
+-#define PI_TYPE_0_STAT_V_1MS 7
+-#define PI_TYPE_0_STAT_V_20MS 6
++#define PI_TYPE_0_STAT_V_1MS 7
++#define PI_TYPE_0_STAT_V_20MS 6
+ #define PI_TYPE_0_STAT_V_CSR_CMD_DONE 5
+ #define PI_TYPE_0_STAT_V_STATE_CHANGE 4
+ #define PI_TYPE_0_STAT_V_XMT_FLUSH 3
+@@ -1692,7 +1692,7 @@ typedef struct DFX_board_tag
+ {
+ /* Keep virtual and physical pointers to locked, physically contiguous memory */
+
+- char *kmalloced; /* pci_free_consistent this on unload */
++ char *kmalloced; /* pci_free_consistent this on unload */
+ dma_addr_t kmalloced_dma;
+ /* DMA handle for the above */
+ PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */
+@@ -1739,9 +1739,9 @@ typedef struct DFX_board_tag
+ /* Store pointers to transmit buffers for transmit completion code */
+
+ XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES];
+-
++
+ /* Transmit spinlocks */
+-
++
+ spinlock_t lock;
+
+ /* Store device, bus-specific, and parameter information for this adapter */
+diff --git a/drivers/net/depca.c b/drivers/net/depca.c
+index b1cbe99..f87f6e3 100644
+--- a/drivers/net/depca.c
++++ b/drivers/net/depca.c
+@@ -4,9 +4,9 @@
+
+
+ Copyright 1994 David C. Davies
+- and
++ and
+ United States Government
+- (as represented by the Director, National Security Agency).
++ (as represented by the Director, National Security Agency).
+
+ Copyright 1995 Digital Equipment Corporation.
+
+@@ -61,7 +61,7 @@
+ Digital Equipment Corporation, 1989
+ 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
+ Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
+-
++
+
+ Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
+ driver.
+@@ -135,20 +135,20 @@
+ [Alan Cox: Changed the code to allow command line irq/io assignments]
+ [Dave Davies: Changed the code to allow command line mem/name
+ assignments]
+- 6) run the net startup bits for your eth?? interface manually
+- (usually /etc/rc.inet[12] at boot time).
++ 6) run the net startup bits for your eth?? interface manually
++ (usually /etc/rc.inet[12] at boot time).
+ 7) enjoy!
+
+ Note that autoprobing is not allowed in loadable modules - the system is
+ already up and running and you're messing with interrupts.
+
+- To unload a module, turn off the associated interface
++ To unload a module, turn off the associated interface
+ 'ifconfig eth?? down' then 'rmmod depca'.
+
+ To assign a base memory address for the shared memory when running as a
+ loadable module, see 5 above. To include the adapter name (if you have
+ no PROM but know the card name) also see 5 above. Note that this last
+- option will not work with kernel built-in depca's.
++ option will not work with kernel built-in depca's.
+
+ The shared memory assignment for a loadable module makes sense to avoid
+ the 'memory autoprobe' picking the wrong shared memory (for the case of
+@@ -157,7 +157,7 @@
+ ************************************************************************
+ Support for MCA EtherWORKS cards added 11-3-98.
+ Verified to work with up to 2 DE212 cards in a system (although not
+- fully stress-tested).
++ fully stress-tested).
+
+ Currently known bugs/limitations:
+
+@@ -176,7 +176,7 @@
+ ----------------
+
+ Version Date Description
+-
++
+ 0.1 25-jan-94 Initial writing.
+ 0.2 27-jan-94 Added LANCE TX hardware buffer chaining.
+ 0.3 1-feb-94 Added multiple DEPCA support.
+@@ -190,7 +190,7 @@
+ 0.351 30-apr-94 Added EISA support. Added DE422 recognition.
+ 0.36 16-may-94 DE422 fix released.
+ 0.37 22-jul-94 Added MODULE support
+- 0.38 15-aug-94 Added DBR ROM switch in depca_close().
++ 0.38 15-aug-94 Added DBR ROM switch in depca_close().
+ Multi DEPCA bug fix.
+ 0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0.
+ 0.381 12-dec-94 Added DE101 recognition, fix multicast bug.
+@@ -198,17 +198,17 @@
+ 0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
+ <stromain at alf.dec.com>
+ 0.384 17-mar-95 Fix a ring full bug reported by <bkm at star.rl.ac.uk>
+- 0.385 3-apr-95 Fix a recognition bug reported by
++ 0.385 3-apr-95 Fix a recognition bug reported by
+ <ryan.niemi at lastfrontier.com>
+ 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
+ 0.40 25-May-95 Rewrite for portability & updated.
+ ALPHA support from <jestabro at amt.tay1.dec.com>
+ 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
+ suggestion by <heiko at colossus.escape.de>
+- 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
++ 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
+ modules.
+ Add 'adapter_name' for loadable modules when no PROM.
+- Both above from a suggestion by
++ Both above from a suggestion by
+ <pchen at woodruffs121.residence.gatech.edu>.
+ Add new multicasting code.
+ 0.421 22-Apr-96 Fix alloc_device() bug <jari at markkus2.fimr.fi>
+@@ -218,7 +218,7 @@
+ 0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
+ reported by <mmogilvi at elbert.uccs.edu>
+ 0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
+- by <tymm at computer.org>
++ by <tymm at computer.org>
+ 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm at computer.org>
+ 0.5 14-Nov-98 Re-spin for 2.1.x kernels.
+ 0.51 27-Jun-99 Correct received packet length for CRC from
+@@ -411,7 +411,7 @@ static struct platform_driver depca_isa_
+ .name = depca_string,
+ },
+ };
+-
++
+ /*
+ ** Miscellaneous info...
+ */
+@@ -421,14 +421,14 @@ static struct platform_driver depca_isa_
+ ** Memory Alignment. Each descriptor is 4 longwords long. To force a
+ ** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+ ** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
+-** and hence the RX descriptor ring's first entry.
++** and hence the RX descriptor ring's first entry.
+ */
+ #define DEPCA_ALIGN4 ((u_long)4 - 1) /* 1 longword align */
+ #define DEPCA_ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */
+ #define DEPCA_ALIGN DEPCA_ALIGN8 /* Keep the LANCE happy... */
+
+ /*
+-** The DEPCA Rx and Tx ring descriptors.
++** The DEPCA Rx and Tx ring descriptors.
+ */
+ struct depca_rx_desc {
+ volatile s32 base;
+@@ -518,7 +518,7 @@ struct depca_private {
+ */
+ static int depca_open(struct net_device *dev);
+ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t depca_interrupt(int irq, void *dev_id);
+ static int depca_close(struct net_device *dev);
+ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static void depca_tx_timeout(struct net_device *dev);
+@@ -591,7 +591,7 @@ static int __init depca_hw_init (struct
+ */
+
+ ioaddr = dev->base_addr;
+-
++
+ STOP_DEPCA;
+
+ nicsr = inb(DEPCA_NICSR);
+@@ -610,7 +610,7 @@ static int __init depca_hw_init (struct
+
+ printk ("%s: %s at 0x%04lx",
+ device->bus_id, depca_signature[lp->adapter], ioaddr);
+-
++
+ switch (lp->depca_bus) {
+ #ifdef CONFIG_MCA
+ case DEPCA_BUS_MCA:
+@@ -657,7 +657,7 @@ static int __init depca_hw_init (struct
+ if (lp->depca_bus != DEPCA_BUS_MCA)
+ mem_start += 0x8000;
+ }
+-
++
+ if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
+ > (netRAM << 10)) {
+ printk(",\n requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
+@@ -682,7 +682,7 @@ static int __init depca_hw_init (struct
+ printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
+ goto out_priv;
+ }
+-
++
+ status = -EIO;
+ lp->sh_mem = ioremap(mem_start, mem_len);
+ if (lp->sh_mem == NULL) {
+@@ -811,7 +811,7 @@ static int __init depca_hw_init (struct
+
+ device->driver_data = dev;
+ SET_NETDEV_DEV (dev, device);
+-
++
+ status = register_netdev(dev);
+ if (status == 0)
+ return 0;
+@@ -822,7 +822,7 @@ out1:
+ out_priv:
+ return status;
+ }
+-
++
+
+ static int depca_open(struct net_device *dev)
+ {
+@@ -924,8 +924,8 @@ static void depca_tx_timeout(struct net_
+ }
+
+
+-/*
+-** Writes a socket buffer to TX descriptor ring and starts transmission
++/*
++** Writes a socket buffer to TX descriptor ring and starts transmission
+ */
+ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -939,7 +939,7 @@ static int depca_start_xmit(struct sk_bu
+
+ if (skb_padto(skb, ETH_ZLEN))
+ goto out;
+-
++
+ netif_stop_queue(dev);
+
+ if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
+@@ -963,9 +963,9 @@ static int depca_start_xmit(struct sk_bu
+ }
+
+ /*
+-** The DEPCA interrupt handler.
++** The DEPCA interrupt handler.
+ */
+-static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t depca_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct depca_private *lp;
+@@ -1053,8 +1053,8 @@ static int depca_rx(struct net_device *d
+ memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
+ }
+
+- /*
+- ** Notify the upper protocol layers that there is another
++ /*
++ ** Notify the upper protocol layers that there is another
+ ** packet to handle
+ */
+ skb->protocol = eth_type_trans(skb, dev);
+@@ -1167,9 +1167,9 @@ static int depca_close(struct net_device
+ printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
+ }
+
+- /*
++ /*
+ ** We stop the DEPCA here -- it occasionally polls
+- ** memory if we don't.
++ ** memory if we don't.
+ */
+ outw(STOP, DEPCA_DATA);
+
+@@ -1320,12 +1320,12 @@ static void SetMulticastFilter(struct ne
+ static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
+ {
+ int status = 0;
+-
++
+ if (!request_region (ioaddr, DEPCA_TOTAL_SIZE, depca_string)) {
+ status = -EBUSY;
+ goto out;
+ }
+-
++
+ if (DevicePresent(ioaddr)) {
+ status = -ENODEV;
+ goto out_release;
+@@ -1337,7 +1337,7 @@ static int __init depca_common_init (u_l
+ }
+
+ return 0;
+-
++
+ out_release:
+ release_region (ioaddr, DEPCA_TOTAL_SIZE);
+ out:
+@@ -1359,16 +1359,16 @@ static int __init depca_mca_probe(struct
+ struct depca_private *lp;
+
+ /*
+- ** Search for the adapter. If an address has been given, search
++ ** Search for the adapter. If an address has been given, search
+ ** specifically for the card at that address. Otherwise find the
+ ** first card in the system.
+ */
+-
++
+ pos[0] = mca_device_read_stored_pos(mdev, 2);
+ pos[1] = mca_device_read_stored_pos(mdev, 3);
+
+ /*
+- ** IO of card is handled by bits 1 and 2 of pos0.
++ ** IO of card is handled by bits 1 and 2 of pos0.
+ **
+ ** bit2 bit1 IO
+ ** 0 0 0x2c00
+@@ -1381,12 +1381,12 @@ static int __init depca_mca_probe(struct
+
+ /*
+ ** Found the adapter we were looking for. Now start setting it up.
+- **
++ **
+ ** First work on decoding the IRQ. It's stored in the lower 4 bits
+ ** of pos1. Bits are as follows (from the ADF file):
+ **
+- ** Bits
+- ** 3 2 1 0 IRQ
++ ** Bits
++ ** 3 2 1 0 IRQ
+ ** --------------------
+ ** 0 0 1 0 5
+ ** 0 0 0 1 9
+@@ -1435,7 +1435,7 @@ static int __init depca_mca_probe(struct
+ strncpy(mdev->name, depca_mca_adapter_name[mdev->index],
+ sizeof(mdev->name));
+ mca_device_set_claim(mdev, 1);
+-
++
+ /*
+ ** Get everything allocated and initialized... (almost just
+ ** like the ISA and EISA probes)
+@@ -1452,10 +1452,10 @@ static int __init depca_mca_probe(struct
+ lp->depca_bus = DEPCA_BUS_MCA;
+ lp->adapter = depca_mca_adapter_type[mdev->index];
+ lp->mem_start = mem_start;
+-
++
+ if ((err = depca_hw_init(dev, device)))
+ goto out_free;
+-
++
+ return 0;
+
+ out_free:
+@@ -1479,7 +1479,7 @@ static void __init depca_platform_probe
+
+ for (i = 0; depca_io_ports[i].iobase; i++) {
+ depca_io_ports[i].device = NULL;
+-
++
+ /* if an address has been specified on the command
+ * line, use it (if valid) */
+ if (io && io != depca_io_ports[i].iobase)
+@@ -1503,7 +1503,7 @@ static void __init depca_platform_probe
+ * no hardware at this address. Unregister it, as the
+ * release fuction will take care of freeing the
+ * allocated structure */
+-
++
+ depca_io_ports[i].device = NULL;
+ pldev->dev.platform_data = NULL;
+ platform_device_unregister (pldev);
+@@ -1541,7 +1541,7 @@ static int __init depca_isa_probe (struc
+ goto out;
+
+ adapter = depca_shmem_probe (&mem_start);
+-
++
+ if (adapter == unknown) {
+ status = -ENODEV;
+ goto out_free;
+@@ -1554,10 +1554,10 @@ static int __init depca_isa_probe (struc
+ lp->depca_bus = DEPCA_BUS_ISA;
+ lp->adapter = adapter;
+ lp->mem_start = mem_start;
+-
++
+ if ((status = depca_hw_init(dev, &device->dev)))
+ goto out_free;
+-
++
+ return 0;
+
+ out_free:
+@@ -1591,7 +1591,7 @@ static int __init depca_eisa_probe (stru
+ * it's address with the ethernet prom)... As we don't parse
+ * the EISA configuration structures (yet... :-), just rely on
+ * the ISA probing to sort it out... */
+-
++
+ depca_shmem_probe (&mem_start);
+
+ dev->base_addr = ioaddr;
+@@ -1600,10 +1600,10 @@ static int __init depca_eisa_probe (stru
+ lp->depca_bus = DEPCA_BUS_EISA;
+ lp->adapter = edev->id.driver_data;
+ lp->mem_start = mem_start;
+-
++
+ if ((status = depca_hw_init(dev, device)))
+ goto out_free;
+-
++
+ return 0;
+
+ out_free:
+@@ -1650,7 +1650,7 @@ static int __init DepcaSignature(char *n
+ * used, at least on x86. Instead, reserve a memory region a
+ * board would certainly use. If it works, go ahead. If not,
+ * run like hell... */
+-
++
+ if (!request_mem_region (mem_addr, 16, depca_string))
+ return unknown;
+
+@@ -1699,7 +1699,7 @@ static int __init DepcaSignature(char *n
+ ** if the first address octet is a 0x08 - this minimises the chances of
+ ** messing around with some other hardware, but it assumes that this DEPCA
+ ** card initialized itself correctly.
+-**
++**
+ ** Search the Ethernet address ROM for the signature. Since the ROM address
+ ** counter can start at an arbitrary point, the search must include the entire
+ ** probe sequence length plus the (length_of_the_signature - 1).
+@@ -1804,7 +1804,7 @@ static int load_packet(struct net_device
+ entry = lp->tx_new; /* Ring around buffer number. */
+ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
+ if (!(readl(&lp->tx_ring[end].base) & T_OWN)) { /* Enough room? */
+- /*
++ /*
+ ** Caution: the write order is important here... don't set up the
+ ** ownership rights until all the other information is in place.
+ */
+@@ -2086,7 +2086,7 @@ static int __init depca_module_init (voi
+ #endif
+ err |= platform_driver_register (&depca_isa_driver);
+ depca_platform_probe ();
+-
++
+ return err;
+ }
+
+diff --git a/drivers/net/depca.h b/drivers/net/depca.h
+index 1178527..ee42648 100644
+--- a/drivers/net/depca.h
++++ b/drivers/net/depca.h
+@@ -20,17 +20,17 @@
+ #define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */
+
+ /*
+-** These are LANCE registers addressable through DEPCA_ADDR
++** These are LANCE registers addressable through DEPCA_ADDR
+ */
+ #define CSR0 0
+ #define CSR1 1
+ #define CSR2 2
+ #define CSR3 3
+
+-/*
+-** NETWORK INTERFACE CSR (NI_CSR) bit definitions
++/*
++** NETWORK INTERFACE CSR (NI_CSR) bit definitions
+ */
+-
++
+ #define TO 0x0100 /* Time Out for remote boot */
+ #define SHE 0x0080 /* SHadow memory Enable */
+ #define BS 0x0040 /* Bank Select */
+@@ -42,8 +42,8 @@
+ #define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */
+ #define LED 0x0001 /* LED control */
+
+-/*
+-** Control and Status Register 0 (CSR0) bit definitions
++/*
++** Control and Status Register 0 (CSR0) bit definitions
+ */
+
+ #define ERR 0x8000 /* Error summary */
+@@ -74,7 +74,7 @@
+ #define BCON 0x0001 /* Byte CONtrol */
+
+ /*
+-** Initialization Block Mode Register
++** Initialization Block Mode Register
+ */
+
+ #define PROM 0x8000 /* Promiscuous Mode */
+@@ -88,7 +88,7 @@
+ #define DRX 0x0001 /* Disable the Receiver */
+
+ /*
+-** Receive Message Descriptor 1 (RMD1) bit definitions.
++** Receive Message Descriptor 1 (RMD1) bit definitions.
+ */
+
+ #define R_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
+@@ -101,7 +101,7 @@
+ #define R_ENP 0x0100 /* End of Packet */
+
+ /*
+-** Transmit Message Descriptor 1 (TMD1) bit definitions.
++** Transmit Message Descriptor 1 (TMD1) bit definitions.
+ */
+
+ #define T_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
+@@ -125,10 +125,10 @@
+ #define TMD3_LCAR 0x0800 /* Loss of CARrier */
+ #define TMD3_RTRY 0x0400 /* ReTRY error */
+
+-/*
+-** EISA configuration Register (CNFG) bit definitions
++/*
++** EISA configuration Register (CNFG) bit definitions
+ */
+-
++
+ #define TIMEOUT 0x0100 /* 0:2.5 mins, 1: 30 secs */
+ #define REMOTE 0x0080 /* Remote Boot Enable -> 1 */
+ #define IRQ11 0x0040 /* Enable -> 1 */
+@@ -165,8 +165,8 @@ struct depca_ioctl {
+ unsigned char __user *data; /* Pointer to the data buffer */
+ };
+
+-/*
+-** Recognised commands for the driver
++/*
++** Recognised commands for the driver
+ */
+ #define DEPCA_GET_HWADDR 0x01 /* Get the hardware address */
+ #define DEPCA_SET_HWADDR 0x02 /* Get the hardware address */
+diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
+index fa4f094..a795202 100644
+--- a/drivers/net/dgrs.c
++++ b/drivers/net/dgrs.c
+@@ -110,7 +110,6 @@ static char version[] __initdata =
+ * DGRS include files
+ */
+ typedef unsigned char uchar;
+-typedef unsigned int bool;
+ #define vol volatile
+
+ #include "dgrs.h"
+@@ -874,7 +873,7 @@ static int dgrs_ioctl(struct net_device
+ privN->bcomm->bc_filter_port = ioc.port;
+ privN->bcomm->bc_filter_num = ioc.filter;
+ privN->bcomm->bc_filter_len = ioc.len;
+-
++
+ if (ioc.len)
+ {
+ if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
+@@ -896,10 +895,10 @@ static int dgrs_ioctl(struct net_device
+ * dev, priv will always refer to the 0th device in Multi-NIC mode.
+ */
+
+-static irqreturn_t dgrs_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dgrs_intr(int irq, void *dev_id)
+ {
+- struct net_device *dev0 = (struct net_device *) dev_id;
+- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
++ struct net_device *dev0 = dev_id;
++ DGRS_PRIV *priv0 = dev0->priv;
+ I596_CB *cbp;
+ int cmd;
+ int i;
+@@ -986,7 +985,7 @@ ack_intr:
+ /*
+ * Download the board firmware
+ */
+-static int __init
++static int __init
+ dgrs_download(struct net_device *dev0)
+ {
+ DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
+@@ -1150,7 +1149,7 @@ dgrs_download(struct net_device *dev0)
+ /*
+ * Probe (init) a board
+ */
+-static int __init
++static int __init
+ dgrs_probe1(struct net_device *dev)
+ {
+ DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
+@@ -1190,7 +1189,7 @@ dgrs_probe1(struct net_device *dev)
+ */
+ if (priv->plxreg)
+ OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
+-
++
+ rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev);
+ if (rc)
+ goto err_out;
+@@ -1228,7 +1227,7 @@ err_out:
+ return rc;
+ }
+
+-static int __init
++static int __init
+ dgrs_initclone(struct net_device *dev)
+ {
+ DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
+@@ -1243,7 +1242,7 @@ dgrs_initclone(struct net_device *dev)
+ return (0);
+ }
+
+-static struct net_device * __init
++static struct net_device * __init
+ dgrs_found_device(
+ int io,
+ ulong mem,
+@@ -1276,9 +1275,9 @@ dgrs_found_device(
+
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, pdev);
+-
++
+ ret = dgrs_probe1(dev);
+- if (ret)
++ if (ret)
+ goto err1;
+
+ ret = register_netdev(dev);
+@@ -1301,7 +1300,7 @@ dgrs_found_device(
+ /* Allocate new dev and priv structures */
+ devN = alloc_etherdev(sizeof(DGRS_PRIV));
+ ret = -ENOMEM;
+- if (!devN)
++ if (!devN)
+ goto fail;
+
+ /* Don't copy the network device structure! */
+@@ -1335,7 +1334,7 @@ dgrs_found_device(
+ }
+ return dev;
+
+- fail:
++ fail:
+ while (i >= 0) {
+ struct net_device *d = priv->devtbl[i--];
+ unregister_netdev(d);
+@@ -1480,7 +1479,7 @@ static int __init dgrs_eisa_probe (struc
+ return -EBUSY;
+ }
+
+- if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
++ if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
+ goto err_out;
+
+ mem = (inb(io+ES4H_AS_31_24) << 24)
+@@ -1504,11 +1503,11 @@ static int __init dgrs_eisa_probe (struc
+ static int __devexit dgrs_eisa_remove(struct device *gendev)
+ {
+ struct net_device *dev = gendev->driver_data;
+-
++
+ dgrs_remove(dev);
+
+ release_region(dev->base_addr, 256);
+-
++
+ free_netdev(dev);
+ return 0;
+ }
+diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h
+index c347cd1..6058d53 100644
+--- a/drivers/net/dgrs.h
++++ b/drivers/net/dgrs.h
+@@ -31,8 +31,8 @@ typedef struct dgrs_ioctl {
+ unsigned short filter; /* filter number for command, if needed */
+ } DGRS_IOCTL;
+
+-/*
+- * Commands for the driver
++/*
++ * Commands for the driver
+ */
+ #define DGRS_GETMEM 0x01 /* Get the dual port memory address */
+ #define DGRS_SETFILTER 0x02 /* Set a filter */
+diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h
+index a8e5bb5..f0e2121 100644
+--- a/drivers/net/dgrs_asstruct.h
++++ b/drivers/net/dgrs_asstruct.h
+@@ -19,7 +19,7 @@
+ # define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1
+ # define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2
+ # define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
+-# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
++# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
+
+ #else /* C */
+
+diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h
+index 6646608..5e9c252 100644
+--- a/drivers/net/dgrs_bcomm.h
++++ b/drivers/net/dgrs_bcomm.h
+@@ -27,7 +27,7 @@
+ * bc_nowait
+ * bc_hostarea_len
+ * bc_filter_len
+- *
++ *
+ */
+ BEGIN_STRUCT(bios_comm)
+ S4(ulong, bc_intflag) /* Count of all interrupts */
+diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h
+index 51596ce..7539b59 100644
+--- a/drivers/net/dgrs_ether.h
++++ b/drivers/net/dgrs_ether.h
+@@ -49,7 +49,7 @@ typedef struct
+ int buf_cnt; /* Total RBD's allocated */
+
+ /* Rx Statistics */
+- ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
++ ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
+ ulong cnt_rx_good; /* Total good packets rcvd */
+ ulong cnt_rx_bad; /* Total of all bad packets rcvd */
+ /* Subtotals can be gotten from SCB */
+@@ -94,7 +94,7 @@ typedef struct
+ * Filter 0: input filter
+ * Filter 1: output filter
+ */
+-
++
+ ulong *filter_space[NFILTERS];
+ FILTER_FUNC *filter_func[NFILTERS];
+ ulong filter_cnt[NFILTERS];
+diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h
+index c7a38c1..ac9217a 100644
+--- a/drivers/net/dgrs_i82596.h
++++ b/drivers/net/dgrs_i82596.h
+@@ -455,7 +455,7 @@ typedef volatile struct
+ /************************************************************************/
+ typedef volatile struct
+ {
+- ulong sysbus;
++ ulong sysbus;
+ ulong dummy;
+ I596_ISCP *iscpp;
+ } I596_SCP;
+diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
+index 402961e..9d446a0 100644
+--- a/drivers/net/dl2k.c
++++ b/drivers/net/dl2k.c
+@@ -17,7 +17,7 @@
+ #include <linux/dma-mapping.h>
+
+ static char version[] __devinitdata =
+- KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
++ KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
+ #define MAX_UNITS 8
+ static int mtu[MAX_UNITS];
+ static int vlan[MAX_UNITS];
+@@ -60,7 +60,7 @@ static void rio_timer (unsigned long dat
+ static void rio_tx_timeout (struct net_device *dev);
+ static void alloc_list (struct net_device *dev);
+ static int start_xmit (struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t rio_interrupt (int irq, void *dev_instance);
+ static void rio_free_tx (struct net_device *dev, int irq);
+ static void tx_error (struct net_device *dev, int tx_status);
+ static int receive_packet (struct net_device *dev);
+@@ -83,7 +83,7 @@ static int mii_read (struct net_device *
+ static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
+ u16 data);
+
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+
+ static int __devinit
+ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -144,9 +144,9 @@ rio_probe1 (struct pci_dev *pdev, const
+ if (media[card_idx] != NULL) {
+ np->an_enable = 0;
+ if (strcmp (media[card_idx], "auto") == 0 ||
+- strcmp (media[card_idx], "autosense") == 0 ||
++ strcmp (media[card_idx], "autosense") == 0 ||
+ strcmp (media[card_idx], "0") == 0 ) {
+- np->an_enable = 2;
++ np->an_enable = 2;
+ } else if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+ strcmp (media[card_idx], "4") == 0) {
+ np->speed = 100;
+@@ -232,7 +232,7 @@ rio_probe1 (struct pci_dev *pdev, const
+ err = find_miiphy (dev);
+ if (err)
+ goto err_out_unmap_rx;
+-
++
+ /* Fiber device? */
+ np->phy_media = (readw(ioaddr + ASICCtrl) & PhyMedia) ? 1 : 0;
+ np->link_status = 0;
+@@ -263,11 +263,11 @@ rio_probe1 (struct pci_dev *pdev, const
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], irq);
+ if (tx_coalesce > 1)
+- printk(KERN_INFO "tx_coalesce:\t%d packets\n",
++ printk(KERN_INFO "tx_coalesce:\t%d packets\n",
+ tx_coalesce);
+ if (np->coalesce)
+ printk(KERN_INFO "rx_coalesce:\t%d packets\n"
+- KERN_INFO "rx_timeout: \t%d ns\n",
++ KERN_INFO "rx_timeout: \t%d ns\n",
+ np->rx_coalesce, np->rx_timeout*640);
+ if (np->vlan)
+ printk(KERN_INFO "vlan(id):\t%d\n", np->vlan);
+@@ -339,7 +339,7 @@ parse_eeprom (struct net_device *dev)
+ }
+ #ifdef MEM_MAPPING
+ ioaddr = dev->base_addr;
+-#endif
++#endif
+ /* Check CRC */
+ crc = ~ether_crc_le (256 - 4, sromdata);
+ if (psrom->crc != crc) {
+@@ -400,16 +400,16 @@ rio_open (struct net_device *dev)
+ long ioaddr = dev->base_addr;
+ int i;
+ u16 macctrl;
+-
++
+ i = request_irq (dev->irq, &rio_interrupt, IRQF_SHARED, dev->name, dev);
+ if (i)
+ return i;
+-
++
+ /* Reset all logic functions */
+ writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+ ioaddr + ASICCtrl + 2);
+ mdelay(10);
+-
++
+ /* DebugCtrl bit 4, 5, 9 must set */
+ writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
+
+@@ -440,7 +440,7 @@ rio_open (struct net_device *dev)
+ /* VLAN supported */
+ if (np->vlan) {
+ /* priority field in RxDMAIntCtrl */
+- writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
++ writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
+ ioaddr + RxDMAIntCtrl);
+ /* VLANId */
+ writew (np->vlan, ioaddr + VLANId);
+@@ -459,9 +459,9 @@ rio_open (struct net_device *dev)
+ add_timer (&np->timer);
+
+ /* Start Tx/Rx */
+- writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
++ writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
+ ioaddr + MACCtrl);
+-
++
+ macctrl = 0;
+ macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+ macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+@@ -470,13 +470,13 @@ rio_open (struct net_device *dev)
+ writew(macctrl, ioaddr + MACCtrl);
+
+ netif_start_queue (dev);
+-
++
+ /* Enable default interrupts */
+ EnableInt ();
+ return 0;
+ }
+
+-static void
++static void
+ rio_timer (unsigned long data)
+ {
+ struct net_device *dev = (struct net_device *)data;
+@@ -521,7 +521,7 @@ rio_timer (unsigned long data)
+ np->timer.expires = jiffies + next_tick;
+ add_timer(&np->timer);
+ }
+-
++
+ static void
+ rio_tx_timeout (struct net_device *dev)
+ {
+@@ -611,7 +611,7 @@ start_xmit (struct sk_buff *skb, struct
+ txdesc = &np->tx_ring[entry];
+
+ #if 0
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ txdesc->status |=
+ cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
+ IPChecksumEnable);
+@@ -632,12 +632,12 @@ start_xmit (struct sk_buff *skb, struct
+ * Work around: Always use 1 descriptor in 10Mbps mode */
+ if (entry % np->tx_coalesce == 0 || np->speed == 10)
+ txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
+- WordAlignDisable |
++ WordAlignDisable |
+ TxDMAIndicate |
+ (1 << FragCountShift));
+ else
+ txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
+- WordAlignDisable |
++ WordAlignDisable |
+ (1 << FragCountShift));
+
+ /* TxDMAPollNow */
+@@ -658,14 +658,14 @@ start_xmit (struct sk_buff *skb, struct
+ dev->base_addr + TFDListPtr0);
+ writel (0, dev->base_addr + TFDListPtr1);
+ }
+-
++
+ /* NETDEV WATCHDOG timer */
+ dev->trans_start = jiffies;
+ return 0;
+ }
+
+ static irqreturn_t
+-rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
++rio_interrupt (int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct netdev_private *np;
+@@ -677,7 +677,7 @@ rio_interrupt (int irq, void *dev_instan
+ ioaddr = dev->base_addr;
+ np = netdev_priv(dev);
+ while (1) {
+- int_status = readw (ioaddr + IntStatus);
++ int_status = readw (ioaddr + IntStatus);
+ writew (int_status, ioaddr + IntStatus);
+ int_status &= DEFAULT_INTR;
+ if (int_status == 0 || --cnt < 0)
+@@ -693,7 +693,7 @@ rio_interrupt (int irq, void *dev_instan
+ if (tx_status & 0x01)
+ tx_error (dev, tx_status);
+ /* Free used tx skbuffs */
+- rio_free_tx (dev, 1);
++ rio_free_tx (dev, 1);
+ }
+
+ /* Handle uncommon events */
+@@ -706,19 +706,19 @@ rio_interrupt (int irq, void *dev_instan
+ return IRQ_RETVAL(handled);
+ }
+
+-static void
+-rio_free_tx (struct net_device *dev, int irq)
++static void
++rio_free_tx (struct net_device *dev, int irq)
+ {
+ struct netdev_private *np = netdev_priv(dev);
+ int entry = np->old_tx % TX_RING_SIZE;
+ int tx_use = 0;
+ unsigned long flag = 0;
+-
++
+ if (irq)
+ spin_lock(&np->tx_lock);
+ else
+ spin_lock_irqsave(&np->tx_lock, flag);
+-
++
+ /* Free used tx skbuffs */
+ while (entry != np->cur_tx) {
+ struct sk_buff *skb;
+@@ -744,11 +744,11 @@ rio_free_tx (struct net_device *dev, int
+ spin_unlock_irqrestore(&np->tx_lock, flag);
+ np->old_tx = entry;
+
+- /* If the ring is no longer full, clear tx_full and
++ /* If the ring is no longer full, clear tx_full and
+ call netif_wake_queue() */
+
+ if (netif_queue_stopped(dev) &&
+- ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
++ ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
+ < TX_QUEUE_LEN - 1 || np->speed == 10)) {
+ netif_wake_queue (dev);
+ }
+@@ -805,11 +805,11 @@ tx_error (struct net_device *dev, int tx
+ /* Let TxStartThresh stay default value */
+ }
+ /* Maximum Collisions */
+-#ifdef ETHER_STATS
+- if (tx_status & 0x08)
++#ifdef ETHER_STATS
++ if (tx_status & 0x08)
+ np->stats.collisions16++;
+ #else
+- if (tx_status & 0x08)
++ if (tx_status & 0x08)
+ np->stats.collisions++;
+ #endif
+ /* Restart the Tx */
+@@ -862,7 +862,7 @@ receive_packet (struct net_device *dev)
+ np->rx_skbuff[entry] = NULL;
+ } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+ pci_dma_sync_single_for_cpu(np->pdev,
+- desc->fraginfo &
++ desc->fraginfo &
+ DMA_48BIT_MASK,
+ np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+@@ -880,12 +880,12 @@ receive_packet (struct net_device *dev)
+ PCI_DMA_FROMDEVICE);
+ }
+ skb->protocol = eth_type_trans (skb, dev);
+-#if 0
++#if 0
+ /* Checksum done by hw, but csum value unavailable. */
+- if (np->pci_rev_id >= 0x0c &&
++ if (np->pci_rev_id >= 0x0c &&
+ !(frame_status & (TCPError | UDPError | IPError))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+- }
++ }
+ #endif
+ netif_rx (skb);
+ dev->last_rx = jiffies;
+@@ -945,14 +945,14 @@ rio_error (struct net_device *dev, int i
+ mii_get_media (dev);
+ if (np->speed == 1000)
+ np->tx_coalesce = tx_coalesce;
+- else
++ else
+ np->tx_coalesce = 1;
+ macctrl = 0;
+ macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+ macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+- macctrl |= (np->tx_flow) ?
++ macctrl |= (np->tx_flow) ?
+ TxFlowControlEnable : 0;
+- macctrl |= (np->rx_flow) ?
++ macctrl |= (np->rx_flow) ?
+ RxFlowControlEnable : 0;
+ writew(macctrl, ioaddr + MACCtrl);
+ np->link_status = 1;
+@@ -969,7 +969,7 @@ rio_error (struct net_device *dev, int i
+ get_stats (dev);
+ }
+
+- /* PCI Error, a catastronphic error related to the bus interface
++ /* PCI Error, a catastronphic error related to the bus interface
+ occurs, set GlobalReset and HostReset to reset. */
+ if (int_status & HostError) {
+ printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
+@@ -991,16 +991,16 @@ get_stats (struct net_device *dev)
+
+ /* All statistics registers need to be acknowledged,
+ else statistic overflow could cause problems */
+-
++
+ np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
+ np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
+ np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
+ np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
+
+ np->stats.multicast = readl (ioaddr + McstFramesRcvdOk);
+- np->stats.collisions += readl (ioaddr + SingleColFrames)
+- + readl (ioaddr + MultiColFrames);
+-
++ np->stats.collisions += readl (ioaddr + SingleColFrames)
++ + readl (ioaddr + MultiColFrames);
++
+ /* detailed tx errors */
+ stat_reg = readw (ioaddr + FramesAbortXSColls);
+ np->stats.tx_aborted_errors += stat_reg;
+@@ -1047,7 +1047,7 @@ clear_stats (struct net_device *dev)
+ long ioaddr = dev->base_addr;
+ #ifdef MEM_MAPPING
+ int i;
+-#endif
++#endif
+
+ /* All statistics registers need to be acknowledged,
+ else statistic overflow could cause problems */
+@@ -1060,7 +1060,7 @@ clear_stats (struct net_device *dev)
+ readl (ioaddr + SingleColFrames);
+ readl (ioaddr + MultiColFrames);
+ readl (ioaddr + LateCollisions);
+- /* detailed rx errors */
++ /* detailed rx errors */
+ readw (ioaddr + FrameTooLongErrors);
+ readw (ioaddr + InRangeLengthErrors);
+ readw (ioaddr + FramesCheckSeqErrors);
+@@ -1086,7 +1086,7 @@ clear_stats (struct net_device *dev)
+ #ifdef MEM_MAPPING
+ for (i = 0x100; i <= 0x150; i += 4)
+ readl (ioaddr + i);
+-#endif
++#endif
+ readw (ioaddr + TxJumboFrames);
+ readw (ioaddr + RxJumboFrames);
+ readw (ioaddr + TCPCheckSumErrors);
+@@ -1118,26 +1118,26 @@ set_multicast (struct net_device *dev)
+ u32 hash_table[2];
+ u16 rx_mode = 0;
+ struct netdev_private *np = netdev_priv(dev);
+-
++
+ hash_table[0] = hash_table[1] = 0;
+ /* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
+ hash_table[1] |= cpu_to_le32(0x02000000);
+ if (dev->flags & IFF_PROMISC) {
+ /* Receive all frames promiscuously. */
+ rx_mode = ReceiveAllFrames;
+- } else if ((dev->flags & IFF_ALLMULTI) ||
++ } else if ((dev->flags & IFF_ALLMULTI) ||
+ (dev->mc_count > multicast_filter_limit)) {
+ /* Receive broadcast and multicast frames */
+ rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
+ } else if (dev->mc_count > 0) {
+ int i;
+ struct dev_mc_list *mclist;
+- /* Receive broadcast frames and multicast frames filtering
++ /* Receive broadcast frames and multicast frames filtering
+ by Hashtable */
+ rx_mode =
+ ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
+- for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+- i++, mclist=mclist->next)
++ for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
++ i++, mclist=mclist->next)
+ {
+ int bit, index = 0;
+ int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+@@ -1167,7 +1167,7 @@ static void rio_get_drvinfo(struct net_d
+ strcpy(info->driver, "dl2k");
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(np->pdev));
+-}
++}
+
+ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+@@ -1177,10 +1177,10 @@ static int rio_get_settings(struct net_d
+ cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
+ cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE;
+ cmd->port = PORT_FIBRE;
+- cmd->transceiver = XCVR_INTERNAL;
++ cmd->transceiver = XCVR_INTERNAL;
+ } else {
+ /* copper device */
+- cmd->supported = SUPPORTED_10baseT_Half |
++ cmd->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_MII;
+@@ -1191,7 +1191,7 @@ static int rio_get_settings(struct net_d
+ cmd->port = PORT_MII;
+ cmd->transceiver = XCVR_INTERNAL;
+ }
+- if ( np->link_status ) {
++ if ( np->link_status ) {
+ cmd->speed = np->speed;
+ cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+@@ -1202,9 +1202,9 @@ static int rio_get_settings(struct net_d
+ cmd->autoneg = AUTONEG_ENABLE;
+ else
+ cmd->autoneg = AUTONEG_DISABLE;
+-
++
+ cmd->phy_address = np->phy_addr;
+- return 0;
++ return 0;
+ }
+
+ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -1217,22 +1217,22 @@ static int rio_set_settings(struct net_d
+ else {
+ np->an_enable = 1;
+ mii_set_media(dev);
+- return 0;
+- }
++ return 0;
++ }
+ } else {
+ np->an_enable = 0;
+ if (np->speed == 1000) {
+- cmd->speed = SPEED_100;
++ cmd->speed = SPEED_100;
+ cmd->duplex = DUPLEX_FULL;
+ printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
+ }
+ switch(cmd->speed + cmd->duplex) {
+-
++
+ case SPEED_10 + DUPLEX_HALF:
+ np->speed = 10;
+ np->full_duplex = 0;
+ break;
+-
++
+ case SPEED_10 + DUPLEX_FULL:
+ np->speed = 10;
+ np->full_duplex = 1;
+@@ -1248,7 +1248,7 @@ static int rio_set_settings(struct net_d
+ case SPEED_1000 + DUPLEX_HALF:/* not supported */
+ case SPEED_1000 + DUPLEX_FULL:/* not supported */
+ default:
+- return -EINVAL;
++ return -EINVAL;
+ }
+ mii_set_media(dev);
+ }
+@@ -1261,7 +1261,7 @@ static u32 rio_get_link(struct net_devic
+ return np->link_status;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = rio_get_drvinfo,
+ .get_settings = rio_get_settings,
+ .set_settings = rio_set_settings,
+@@ -1274,7 +1274,7 @@ rio_ioctl (struct net_device *dev, struc
+ int phy_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru;
+-
++
+ struct netdev_desc *desc;
+ int i;
+
+@@ -1282,7 +1282,7 @@ rio_ioctl (struct net_device *dev, struc
+ switch (cmd) {
+ case SIOCDEVPRIVATE:
+ break;
+-
++
+ case SIOCDEVPRIVATE + 1:
+ miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
+ break;
+@@ -1467,7 +1467,7 @@ mii_get_media (struct net_device *dev)
+ /* Auto-Negotiation not completed */
+ return -1;
+ }
+- negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
++ negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
+ mii_read (dev, phy_addr, MII_ANLPAR);
+ mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+ mssr.image = mii_read (dev, phy_addr, MII_MSSR);
+@@ -1519,9 +1519,9 @@ mii_get_media (struct net_device *dev)
+ printk ("Half duplex\n");
+ }
+ }
+- if (np->tx_flow)
++ if (np->tx_flow)
+ printk(KERN_INFO "Enable Tx Flow Control\n");
+- else
++ else
+ printk(KERN_INFO "Disable Tx Flow Control\n");
+ if (np->rx_flow)
+ printk(KERN_INFO "Enable Rx Flow Control\n");
+@@ -1561,7 +1561,7 @@ mii_set_media (struct net_device *dev)
+ pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+ pscr.bits.mdi_crossover_mode = 3; /* 11'b */
+ mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+-
++
+ /* Soft reset PHY */
+ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+ bmcr.image = 0;
+@@ -1639,7 +1639,7 @@ mii_get_media_pcs (struct net_device *de
+ /* Auto-Negotiation not completed */
+ return -1;
+ }
+- negotiate.image = mii_read (dev, phy_addr, PCS_ANAR) &
++ negotiate.image = mii_read (dev, phy_addr, PCS_ANAR) &
+ mii_read (dev, phy_addr, PCS_ANLPAR);
+ np->speed = 1000;
+ if (negotiate.bits.full_duplex) {
+@@ -1666,9 +1666,9 @@ mii_get_media_pcs (struct net_device *de
+ printk ("Half duplex\n");
+ }
+ }
+- if (np->tx_flow)
++ if (np->tx_flow)
+ printk(KERN_INFO "Enable Tx Flow Control\n");
+- else
++ else
+ printk(KERN_INFO "Disable Tx Flow Control\n");
+ if (np->rx_flow)
+ printk(KERN_INFO "Enable Rx Flow Control\n");
+@@ -1694,9 +1694,9 @@ mii_set_media_pcs (struct net_device *de
+ /* Advertise capabilities */
+ esr.image = mii_read (dev, phy_addr, PCS_ESR);
+ anar.image = mii_read (dev, phy_addr, MII_ANAR);
+- anar.bits.half_duplex =
++ anar.bits.half_duplex =
+ esr.bits.media_1000BT_HD | esr.bits.media_1000BX_HD;
+- anar.bits.full_duplex =
++ anar.bits.full_duplex =
+ esr.bits.media_1000BT_FD | esr.bits.media_1000BX_FD;
+ anar.bits.pause = 1;
+ anar.bits.asymmetric = 1;
+@@ -1754,14 +1754,14 @@ rio_close (struct net_device *dev)
+ synchronize_irq (dev->irq);
+ free_irq (dev->irq, dev);
+ del_timer_sync (&np->timer);
+-
++
+ /* Free all the skbuffs in the queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ np->rx_ring[i].status = 0;
+ np->rx_ring[i].fraginfo = 0;
+ skb = np->rx_skbuff[i];
+ if (skb) {
+- pci_unmap_single(np->pdev,
++ pci_unmap_single(np->pdev,
+ np->rx_ring[i].fraginfo & DMA_48BIT_MASK,
+ skb->len, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb (skb);
+@@ -1771,7 +1771,7 @@ rio_close (struct net_device *dev)
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ skb = np->tx_skbuff[i];
+ if (skb) {
+- pci_unmap_single(np->pdev,
++ pci_unmap_single(np->pdev,
+ np->tx_ring[i].fraginfo & DMA_48BIT_MASK,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb (skb);
+@@ -1815,7 +1815,7 @@ static struct pci_driver rio_driver = {
+ static int __init
+ rio_init (void)
+ {
+- return pci_module_init (&rio_driver);
++ return pci_register_driver(&rio_driver);
+ }
+
+ static void __exit
+@@ -1828,9 +1828,9 @@ module_init (rio_init);
+ module_exit (rio_exit);
+
+ /*
+-
+-Compile command:
+-
++
++Compile command:
++
+ gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
+
+ Read Documentation/networking/dl2k.txt for details.
+diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
+index 5344920..814c449 100644
+--- a/drivers/net/dl2k.h
++++ b/drivers/net/dl2k.h
+@@ -1,5 +1,5 @@
+ /* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+-/*
++/*
+ Copyright (c) 2001, 2002 by D-Link Corporation
+ Written by Edward Peng.<edward_peng at dlink.com.tw>
+ Created 03-May-2001, base on Linux' sundance.c.
+@@ -216,7 +216,7 @@ enum MACCtrl_bits {
+ enum ASICCtrl_LoWord_bits {
+ PhyMedia = 0x0080,
+ };
+-
++
+ enum ASICCtrl_HiWord_bits {
+ GlobalReset = 0x0001,
+ RxReset = 0x0002,
+@@ -596,7 +596,7 @@ typedef union t_PCS_ANLPAR {
+ } ANLPAR_PCS_t, *PANLPAR_PCS_t;
+
+ enum _pcs_anlpar {
+- PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
++ PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
+ PCS_ANLPAR_REMOTE_FAULT = PCS_ANAR_REMOTE_FAULT,
+ PCS_ANLPAR_ASYMMETRIC = PCS_ANAR_ASYMMETRIC,
+ PCS_ANLPAR_PAUSE = PCS_ANAR_PAUSE,
+diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
+index a860ebb..615d2b1 100644
+--- a/drivers/net/dm9000.c
++++ b/drivers/net/dm9000.c
+@@ -159,7 +159,7 @@ static void dm9000_init_dm9000(struct ne
+
+ static struct net_device_stats *dm9000_get_stats(struct net_device *);
+
+-static irqreturn_t dm9000_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t dm9000_interrupt(int, void *);
+
+ static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
+ static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg,
+@@ -346,7 +346,7 @@ static void dm9000_timeout(struct net_de
+ static void dm9000_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- dm9000_interrupt(dev->irq,dev,NULL);
++ dm9000_interrupt(dev->irq,dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -804,7 +804,7 @@ dm9000_tx_done(struct net_device *dev, b
+ }
+
+ static irqreturn_t
+-dm9000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++dm9000_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ board_info_t *db;
+diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
+index 2146cf7..60673bc 100644
+--- a/drivers/net/dummy.c
++++ b/drivers/net/dummy.c
+@@ -11,7 +11,7 @@
+ One solution is to set up a dummy link using PPP/SLIP/PLIP,
+ but this seems (to me) too much overhead for too little gain.
+ This driver provides a small alternative. Thus you can do
+-
++
+ [when not running slip]
+ ifconfig dummy slip.addr.ess.here up
+ [to go to slip]
+@@ -44,9 +44,9 @@ static int dummy_set_address(struct net_
+ {
+ struct sockaddr *sa = p;
+
+- if (!is_valid_ether_addr(sa->sa_data))
++ if (!is_valid_ether_addr(sa->sa_data))
+ return -EADDRNOTAVAIL;
+-
++
+ memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
+ return 0;
+ }
+@@ -111,7 +111,7 @@ static int __init dummy_init_one(int ind
+ free_netdev(dev_dummy);
+ dev_dummy = NULL;
+ } else {
+- dummies[index] = dev_dummy;
++ dummies[index] = dev_dummy;
+ }
+
+ return err;
+@@ -121,30 +121,30 @@ static void dummy_free_one(int index)
+ {
+ unregister_netdev(dummies[index]);
+ free_netdev(dummies[index]);
+-}
++}
+
+ static int __init dummy_init_module(void)
+-{
++{
+ int i, err = 0;
+- dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL);
++ dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL);
+ if (!dummies)
+- return -ENOMEM;
++ return -ENOMEM;
+ for (i = 0; i < numdummies && !err; i++)
+- err = dummy_init_one(i);
+- if (err) {
++ err = dummy_init_one(i);
++ if (err) {
+ i--;
+ while (--i >= 0)
+ dummy_free_one(i);
+ }
+ return err;
+-}
++}
+
+ static void __exit dummy_cleanup_module(void)
+ {
+ int i;
+- for (i = 0; i < numdummies; i++)
+- dummy_free_one(i);
+- kfree(dummies);
++ for (i = 0; i < numdummies; i++)
++ dummy_free_one(i);
++ kfree(dummies);
+ }
+
+ module_init(dummy_init_module);
+diff --git a/drivers/net/e100.c b/drivers/net/e100.c
+index ce850f1..19ab344 100644
+--- a/drivers/net/e100.c
++++ b/drivers/net/e100.c
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
++ Intel PRO/100 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+- under the terms of the GNU General Public License as published by the Free
+- Software Foundation; either version 2 of the License, or (at your option)
+- any later version.
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
+
+- This program is distributed in the hope that it will be useful, but WITHOUT
++ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -158,10 +158,10 @@
+
+
+ #define DRV_NAME "e100"
+-#define DRV_EXT "-NAPI"
+-#define DRV_VERSION "3.5.10-k2"DRV_EXT
++#define DRV_EXT "-NAPI"
++#define DRV_VERSION "3.5.17-k2"DRV_EXT
+ #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
+-#define DRV_COPYRIGHT "Copyright(c) 1999-2005 Intel Corporation"
++#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
+ #define PFX DRV_NAME ": "
+
+ #define E100_WATCHDOG_PERIOD (2 * HZ)
+@@ -1395,15 +1395,11 @@ 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))) {
+- /* 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);
++ (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);
+ }
+
+ return 0;
+@@ -1661,13 +1657,14 @@ static int e100_tx_clean(struct nic *nic
+
+ spin_lock(&nic->cb_lock);
+
+- DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n",
+- nic->cb_to_clean->status);
+-
+ /* Clean CBs marked complete */
+ for(cb = nic->cb_to_clean;
+ cb->status & cpu_to_le16(cb_complete);
+ cb = nic->cb_to_clean = cb->next) {
++ DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
++ (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
++ cb->status);
++
+ if(likely(cb->skb != NULL)) {
+ nic->net_stats.tx_packets++;
+ nic->net_stats.tx_bytes += cb->skb->len;
+@@ -1767,11 +1764,10 @@ static inline void e100_start_receiver(s
+ #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
+ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
+ {
+- if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
++ if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
+ return -ENOMEM;
+
+ /* Align, init, and map the RFD. */
+- rx->skb->dev = nic->netdev;
+ skb_reserve(rx->skb, NET_IP_ALIGN);
+ memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
+ rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
+@@ -1953,7 +1949,7 @@ static int e100_rx_alloc_list(struct nic
+ return 0;
+ }
+
+-static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t e100_intr(int irq, void *dev_id)
+ {
+ struct net_device *netdev = dev_id;
+ struct nic *nic = netdev_priv(netdev);
+@@ -2009,7 +2005,7 @@ static void e100_netpoll(struct net_devi
+ struct nic *nic = netdev_priv(netdev);
+
+ e100_disable_irq(nic);
+- e100_intr(nic->pdev->irq, netdev, NULL);
++ e100_intr(nic->pdev->irq, netdev);
+ e100_tx_clean(nic);
+ e100_enable_irq(nic);
+ }
+@@ -2043,7 +2039,6 @@ static int e100_change_mtu(struct net_de
+ return 0;
+ }
+
+-#ifdef CONFIG_PM
+ static int e100_asf(struct nic *nic)
+ {
+ /* ASF can be enabled from eeprom */
+@@ -2052,7 +2047,6 @@ static int e100_asf(struct nic *nic)
+ !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
+ ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
+ }
+-#endif
+
+ static int e100_up(struct nic *nic)
+ {
+@@ -2147,7 +2141,7 @@ static int e100_loopback_test(struct nic
+
+ e100_start_receiver(nic, NULL);
+
+- if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
++ if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
+ err = -ENOMEM;
+ goto err_loopback_none;
+ }
+@@ -2482,7 +2476,7 @@ static void e100_get_strings(struct net_
+ }
+ }
+
+-static struct ethtool_ops e100_ethtool_ops = {
++static const struct ethtool_ops e100_ethtool_ops = {
+ .get_settings = e100_get_settings,
+ .set_settings = e100_set_settings,
+ .get_drvinfo = e100_get_drvinfo,
+@@ -2577,7 +2571,7 @@ static int __devinit e100_probe(struct p
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = e100_netpoll;
+ #endif
+- strcpy(netdev->name, pci_name(pdev));
++ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+ nic = netdev_priv(netdev);
+ nic->netdev = netdev;
+@@ -2724,22 +2718,26 @@ static int e100_suspend(struct pci_dev *
+ {
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+- int retval;
+
+- if(netif_running(netdev))
+- e100_down(nic);
+- e100_hw_reset(nic);
+- netif_device_detach(netdev);
++#ifdef CONFIG_E100_NAPI
++ if (netif_running(netdev))
++ netif_poll_disable(nic->netdev);
++#endif
++ del_timer_sync(&nic->watchdog);
++ netif_carrier_off(nic->netdev);
+
+ pci_save_state(pdev);
+- retval = pci_enable_wake(pdev, pci_choose_state(pdev, state),
+- nic->flags & (wol_magic | e100_asf(nic)));
+- if (retval)
+- DPRINTK(PROBE,ERR, "Error enabling wake\n");
++
++ if ((nic->flags & wol_magic) | e100_asf(nic)) {
++ pci_enable_wake(pdev, PCI_D3hot, 1);
++ pci_enable_wake(pdev, PCI_D3cold, 1);
++ } else {
++ pci_enable_wake(pdev, PCI_D3hot, 0);
++ pci_enable_wake(pdev, PCI_D3cold, 0);
++ }
++
+ pci_disable_device(pdev);
+- retval = pci_set_power_state(pdev, pci_choose_state(pdev, state));
+- if (retval)
+- DPRINTK(PROBE,ERR, "Error %d setting power state\n", retval);
++ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+ }
+@@ -2748,39 +2746,43 @@ static int e100_resume(struct pci_dev *p
+ {
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+- int retval;
+
+- retval = pci_set_power_state(pdev, PCI_D0);
+- if (retval)
+- DPRINTK(PROBE,ERR, "Error waking adapter\n");
++ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ /* ack any pending wake events, disable PME */
+- retval = pci_enable_wake(pdev, 0, 0);
+- if (retval)
+- DPRINTK(PROBE,ERR, "Error clearing wake events\n");
++ pci_enable_wake(pdev, 0, 0);
+
+ netif_device_attach(netdev);
+- if(netif_running(netdev))
++ if (netif_running(netdev))
+ e100_up(nic);
+
+ return 0;
+ }
+-#endif
++#endif /* CONFIG_PM */
+
+
+ static void e100_shutdown(struct pci_dev *pdev)
+ {
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+- int retval;
+
+-#ifdef CONFIG_PM
+- retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+-#else
+- retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic));
++#ifdef CONFIG_E100_NAPI
++ if (netif_running(netdev))
++ netif_poll_disable(nic->netdev);
+ #endif
+- if (retval)
+- DPRINTK(PROBE,ERR, "Error enabling wake\n");
++ del_timer_sync(&nic->watchdog);
++ netif_carrier_off(nic->netdev);
++
++ if ((nic->flags & wol_magic) | e100_asf(nic)) {
++ pci_enable_wake(pdev, PCI_D3hot, 1);
++ pci_enable_wake(pdev, PCI_D3cold, 1);
++ } else {
++ pci_enable_wake(pdev, PCI_D3hot, 0);
++ pci_enable_wake(pdev, PCI_D3cold, 0);
++ }
++
++ pci_disable_device(pdev);
++ pci_set_power_state(pdev, PCI_D3hot);
+ }
+
+ /* ------------------ PCI Error Recovery infrastructure -------------- */
+@@ -2799,6 +2801,7 @@ static pci_ers_result_t e100_io_error_de
+ /* Detach; put netif into state similar to hotplug unplug. */
+ netif_poll_enable(netdev);
+ netif_device_detach(netdev);
++ pci_disable_device(pdev);
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+@@ -2864,6 +2867,7 @@ static struct pci_driver e100_driver = {
+ .probe = e100_probe,
+ .remove = __devexit_p(e100_remove),
+ #ifdef CONFIG_PM
++ /* Power Management hooks */
+ .suspend = e100_suspend,
+ .resume = e100_resume,
+ #endif
+@@ -2877,7 +2881,7 @@ static int __init e100_init_module(void)
+ printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+ printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
+ }
+- return pci_module_init(&e100_driver);
++ return pci_register_driver(&e100_driver);
+ }
+
+ static void __exit e100_cleanup_module(void)
+diff --git a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE
+deleted file mode 100644
+index 5f297e5..0000000
+--- a/drivers/net/e1000/LICENSE
++++ /dev/null
+@@ -1,339 +0,0 @@
+-
+-"This software program is licensed subject to the GNU General Public License
+-(GPL). Version 2, June 1991, available at
+-<http://www.fsf.org/copyleft/gpl.html>"
+-
+-GNU General Public License
+-
+-Version 2, June 1991
+-
+-Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+-
+-Everyone is permitted to copy and distribute verbatim copies of this license
+-document, but changing it is not allowed.
+-
+-Preamble
+-
+-The licenses for most software are designed to take away your freedom to
+-share and change it. By contrast, the GNU General Public License is intended
+-to guarantee your freedom to share and change free software--to make sure
+-the software is free for all its users. This General Public License applies
+-to most of the Free Software Foundation's software and to any other program
+-whose authors commit to using it. (Some other Free Software Foundation
+-software is covered by the GNU Library General Public License instead.) You
+-can apply it to your programs, too.
+-
+-When we speak of free software, we are referring to freedom, not price. Our
+-General Public Licenses are designed to make sure that you have the freedom
+-to distribute copies of free software (and charge for this service if you
+-wish), that you receive source code or can get it if you want it, that you
+-can change the software or use pieces of it in new free programs; and that
+-you know you can do these things.
+-
+-To protect your rights, we need to make restrictions that forbid anyone to
+-deny you these rights or to ask you to surrender the rights. These
+-restrictions translate to certain responsibilities for you if you distribute
+-copies of the software, or if you modify it.
+-
+-For example, if you distribute copies of such a program, whether gratis or
+-for a fee, you must give the recipients all the rights that you have. You
+-must make sure that they, too, receive or can get the source code. And you
+-must show them these terms so they know their rights.
+-
+-We protect your rights with two steps: (1) copyright the software, and (2)
+-offer you this license which gives you legal permission to copy, distribute
+-and/or modify the software.
+-
+-Also, for each author's protection and ours, we want to make certain that
+-everyone understands that there is no warranty for this free software. If
+-the software is modified by someone else and passed on, we want its
+-recipients to know that what they have is not the original, so that any
+-problems introduced by others will not reflect on the original authors'
+-reputations.
+-
+-Finally, any free program is threatened constantly by software patents. We
+-wish to avoid the danger that redistributors of a free program will
+-individually obtain patent licenses, in effect making the program
+-proprietary. To prevent this, we have made it clear that any patent must be
+-licensed for everyone's free use or not licensed at all.
+-
+-The precise terms and conditions for copying, distribution and modification
+-follow.
+-
+-TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+-
+-0. This License applies to any program or other work which contains a notice
+- placed by the copyright holder saying it may be distributed under the
+- terms of this General Public License. The "Program", below, refers to any
+- such program or work, and a "work based on the Program" means either the
+- Program or any derivative work under copyright law: that is to say, a
+- work containing the Program or a portion of it, either verbatim or with
+- modifications and/or translated into another language. (Hereinafter,
+- translation is included without limitation in the term "modification".)
+- Each licensee is addressed as "you".
+-
+- Activities other than copying, distribution and modification are not
+- covered by this License; they are outside its scope. The act of running
+- the Program is not restricted, and the output from the Program is covered
+- only if its contents constitute a work based on the Program (independent
+- of having been made by running the Program). Whether that is true depends
+- on what the Program does.
+-
+-1. You may copy and distribute verbatim copies of the Program's source code
+- as you receive it, in any medium, provided that you conspicuously and
+- appropriately publish on each copy an appropriate copyright notice and
+- disclaimer of warranty; keep intact all the notices that refer to this
+- License and to the absence of any warranty; and give any other recipients
+- of the Program a copy of this License along with the Program.
+-
+- You may charge a fee for the physical act of transferring a copy, and you
+- may at your option offer warranty protection in exchange for a fee.
+-
+-2. You may modify your copy or copies of the Program or any portion of it,
+- thus forming a work based on the Program, and copy and distribute such
+- modifications or work under the terms of Section 1 above, provided that
+- you also meet all of these conditions:
+-
+- * a) You must cause the modified files to carry prominent notices stating
+- that you changed the files and the date of any change.
+-
+- * b) You must cause any work that you distribute or publish, that in
+- whole or in part contains or is derived from the Program or any part
+- thereof, to be licensed as a whole at no charge to all third parties
+- under the terms of this License.
+-
+- * c) If the modified program normally reads commands interactively when
+- run, you must cause it, when started running for such interactive
+- use in the most ordinary way, to print or display an announcement
+- including an appropriate copyright notice and a notice that there is
+- no warranty (or else, saying that you provide a warranty) and that
+- users may redistribute the program under these conditions, and
+- telling the user how to view a copy of this License. (Exception: if
+- the Program itself is interactive but does not normally print such
+- an announcement, your work based on the Program is not required to
+- print an announcement.)
+-
+- These requirements apply to the modified work as a whole. If identifiable
+- sections of that work are not derived from the Program, and can be
+- reasonably considered independent and separate works in themselves, then
+- this License, and its terms, do not apply to those sections when you
+- distribute them as separate works. But when you distribute the same
+- sections as part of a whole which is a work based on the Program, the
+- distribution of the whole must be on the terms of this License, whose
+- permissions for other licensees extend to the entire whole, and thus to
+- each and every part regardless of who wrote it.
+-
+- Thus, it is not the intent of this section to claim rights or contest
+- your rights to work written entirely by you; rather, the intent is to
+- exercise the right to control the distribution of derivative or
+- collective works based on the Program.
+-
+- In addition, mere aggregation of another work not based on the Program
+- with the Program (or with a work based on the Program) on a volume of a
+- storage or distribution medium does not bring the other work under the
+- scope of this License.
+-
+-3. You may copy and distribute the Program (or a work based on it, under
+- Section 2) in object code or executable form under the terms of Sections
+- 1 and 2 above provided that you also do one of the following:
+-
+- * a) Accompany it with the complete corresponding machine-readable source
+- code, which must be distributed under the terms of Sections 1 and 2
+- above on a medium customarily used for software interchange; or,
+-
+- * b) Accompany it with a written offer, valid for at least three years,
+- to give any third party, for a charge no more than your cost of
+- physically performing source distribution, a complete machine-
+- readable copy of the corresponding source code, to be distributed
+- under the terms of Sections 1 and 2 above on a medium customarily
+- used for software interchange; or,
+-
+- * c) Accompany it with the information you received as to the offer to
+- distribute corresponding source code. (This alternative is allowed
+- only for noncommercial distribution and only if you received the
+- program in object code or executable form with such an offer, in
+- accord with Subsection b above.)
+-
+- The source code for a work means the preferred form of the work for
+- making modifications to it. For an executable work, complete source code
+- means all the source code for all modules it contains, plus any
+- associated interface definition files, plus the scripts used to control
+- compilation and installation of the executable. However, as a special
+- exception, the source code distributed need not include anything that is
+- normally distributed (in either source or binary form) with the major
+- components (compiler, kernel, and so on) of the operating system on which
+- the executable runs, unless that component itself accompanies the
+- executable.
+-
+- If distribution of executable or object code is made by offering access
+- to copy from a designated place, then offering equivalent access to copy
+- the source code from the same place counts as distribution of the source
+- code, even though third parties are not compelled to copy the source
+- along with the object code.
+-
+-4. You may not copy, modify, sublicense, or distribute the Program except as
+- expressly provided under this License. Any attempt otherwise to copy,
+- modify, sublicense or distribute the Program is void, and will
+- automatically terminate your rights under this License. However, parties
+- who have received copies, or rights, from you under this License will not
+- have their licenses terminated so long as such parties remain in full
+- compliance.
+-
+-5. You are not required to accept this License, since you have not signed
+- it. However, nothing else grants you permission to modify or distribute
+- the Program or its derivative works. These actions are prohibited by law
+- if you do not accept this License. Therefore, by modifying or
+- distributing the Program (or any work based on the Program), you
+- indicate your acceptance of this License to do so, and all its terms and
+- conditions for copying, distributing or modifying the Program or works
+- based on it.
+-
+-6. Each time you redistribute the Program (or any work based on the
+- Program), the recipient automatically receives a license from the
+- original licensor to copy, distribute or modify the Program subject to
+- these terms and conditions. You may not impose any further restrictions
+- on the recipients' exercise of the rights granted herein. You are not
+- responsible for enforcing compliance by third parties to this License.
+-
+-7. If, as a consequence of a court judgment or allegation of patent
+- infringement or for any other reason (not limited to patent issues),
+- conditions are imposed on you (whether by court order, agreement or
+- otherwise) that contradict the conditions of this License, they do not
+- excuse you from the conditions of this License. If you cannot distribute
+- so as to satisfy simultaneously your obligations under this License and
+- any other pertinent obligations, then as a consequence you may not
+- distribute the Program at all. For example, if a patent license would
+- not permit royalty-free redistribution of the Program by all those who
+- receive copies directly or indirectly through you, then the only way you
+- could satisfy both it and this License would be to refrain entirely from
+- distribution of the Program.
+-
+- If any portion of this section is held invalid or unenforceable under any
+- particular circumstance, the balance of the section is intended to apply
+- and the section as a whole is intended to apply in other circumstances.
+-
+- It is not the purpose of this section to induce you to infringe any
+- patents or other property right claims or to contest validity of any
+- such claims; this section has the sole purpose of protecting the
+- integrity of the free software distribution system, which is implemented
+- by public license practices. Many people have made generous contributions
+- to the wide range of software distributed through that system in
+- reliance on consistent application of that system; it is up to the
+- author/donor to decide if he or she is willing to distribute software
+- through any other system and a licensee cannot impose that choice.
+-
+- This section is intended to make thoroughly clear what is believed to be
+- a consequence of the rest of this License.
+-
+-8. If the distribution and/or use of the Program is restricted in certain
+- countries either by patents or by copyrighted interfaces, the original
+- copyright holder who places the Program under this License may add an
+- explicit geographical distribution limitation excluding those countries,
+- so that distribution is permitted only in or among countries not thus
+- excluded. In such case, this License incorporates the limitation as if
+- written in the body of this License.
+-
+-9. The Free Software Foundation may publish revised and/or new versions of
+- the General Public License from time to time. Such new versions will be
+- similar in spirit to the present version, but may differ in detail to
+- address new problems or concerns.
+-
+- Each version is given a distinguishing version number. If the Program
+- specifies a version number of this License which applies to it and "any
+- later version", you have the option of following the terms and
+- conditions either of that version or of any later version published by
+- the Free Software Foundation. If the Program does not specify a version
+- number of this License, you may choose any version ever published by the
+- Free Software Foundation.
+-
+-10. If you wish to incorporate parts of the Program into other free programs
+- whose distribution conditions are different, write to the author to ask
+- for permission. For software which is copyrighted by the Free Software
+- Foundation, write to the Free Software Foundation; we sometimes make
+- exceptions for this. Our decision will be guided by the two goals of
+- preserving the free status of all derivatives of our free software and
+- of promoting the sharing and reuse of software generally.
+-
+- NO WARRANTY
+-
+-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+- EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+- ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+- YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+- NECESSARY SERVICING, REPAIR OR CORRECTION.
+-
+-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+- DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+- DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
+- (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+- INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+- THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
+- OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+-
+-END OF TERMS AND CONDITIONS
+-
+-How to Apply These Terms to Your New Programs
+-
+-If you develop a new program, and you want it to be of the greatest
+-possible use to the public, the best way to achieve this is to make it free
+-software which everyone can redistribute and change under these terms.
+-
+-To do so, attach the following notices to the program. It is safest to
+-attach them to the start of each source file to most effectively convey the
+-exclusion of warranty; and each file should have at least the "copyright"
+-line and a pointer to where the full notice is found.
+-
+-one line to give the program's name and an idea of what it does.
+-Copyright (C) yyyy name of author
+-
+-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.
+-
+-Also add information on how to contact you by electronic and paper mail.
+-
+-If the program is interactive, make it output a short notice like this when
+-it starts in an interactive mode:
+-
+-Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
+-with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free
+-software, and you are welcome to redistribute it under certain conditions;
+-type 'show c' for details.
+-
+-The hypothetical commands 'show w' and 'show c' should show the appropriate
+-parts of the General Public License. Of course, the commands you use may be
+-called something other than 'show w' and 'show c'; they could even be
+-mouse-clicks or menu items--whatever suits your program.
+-
+-You should also get your employer (if you work as a programmer) or your
+-school, if any, to sign a "copyright disclaimer" for the program, if
+-necessary. Here is a sample; alter the names:
+-
+-Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+-'Gnomovision' (which makes passes at compilers) written by James Hacker.
+-
+-signature of Ty Coon, 1 April 1989
+-Ty Coon, President of Vice
+-
+-This General Public License does not permit incorporating your program into
+-proprietary programs. If your program is a subroutine library, you may
+-consider it more useful to permit linking proprietary applications with the
+-library. If this is what you want to do, use the GNU Library General Public
+-License instead of this License.
+diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
+index 5dea2b7..4a6ab15 100644
+--- a/drivers/net/e1000/Makefile
++++ b/drivers/net/e1000/Makefile
+@@ -1,25 +1,24 @@
+ ################################################################################
+ #
+-#
+-# Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++# Intel PRO/1000 Linux driver
++# Copyright(c) 1999 - 2006 Intel Corporation.
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms and conditions of the GNU General Public License,
++# version 2, as published by the Free Software Foundation.
++#
++# This program is distributed in the hope it will be useful, but WITHOUT
++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ # more details.
+-#
++#
+ # You should have received a copy of the GNU General Public License along with
+-# this program; if not, write to the Free Software Foundation, Inc., 59
+-# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-#
+-# The full GNU General Public License is included in this distribution in the
+-# file called LICENSE.
+-#
++# this program; if not, write to the Free Software Foundation, Inc.,
++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++#
++# The full GNU General Public License is included in this distribution in
++# the file called "COPYING".
++#
+ # Contact Information:
+ # Linux NICS <linux.nics at intel.com>
+ # e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
+index d304297..7ecce43 100644
+--- a/drivers/net/e1000/e1000.h
++++ b/drivers/net/e1000/e1000.h
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -242,12 +241,10 @@ struct e1000_adapter {
+ struct timer_list watchdog_timer;
+ struct timer_list phy_info_timer;
+ struct vlan_group *vlgrp;
+- uint16_t mng_vlan_id;
++ uint16_t mng_vlan_id;
+ uint32_t bd_number;
+ uint32_t rx_buffer_len;
+- uint32_t part_num;
+ uint32_t wol;
+- uint32_t ksp3_port_a;
+ uint32_t smartspeed;
+ uint32_t en_mng_pt;
+ uint16_t link_speed;
+@@ -342,33 +339,15 @@ struct e1000_adapter {
+ boolean_t tso_force;
+ #endif
+ boolean_t smart_power_down; /* phy smart power down */
++ boolean_t quad_port_a;
+ unsigned long flags;
++ uint32_t eeprom_wol;
+ };
+
+ enum e1000_state_t {
+- __E1000_DRIVER_TESTING,
++ __E1000_TESTING,
+ __E1000_RESETTING,
++ __E1000_DOWN
+ };
+
+-/* e1000_main.c */
+-extern char e1000_driver_name[];
+-extern char e1000_driver_version[];
+-int e1000_up(struct e1000_adapter *adapter);
+-void e1000_down(struct e1000_adapter *adapter);
+-void e1000_reset(struct e1000_adapter *adapter);
+-void e1000_reinit_locked(struct e1000_adapter *adapter);
+-int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+-void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
+-int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+-void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+-void e1000_update_stats(struct e1000_adapter *adapter);
+-int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
+-
+-/* e1000_ethtool.c */
+-void e1000_set_ethtool_ops(struct net_device *netdev);
+-
+-/* e1000_param.c */
+-void e1000_check_options(struct e1000_adapter *adapter);
+-
+-
+ #endif /* _E1000_H_ */
+diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
+index 88a82ba..c564adb 100644
+--- a/drivers/net/e1000/e1000_ethtool.c
++++ b/drivers/net/e1000/e1000_ethtool.c
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -33,6 +32,21 @@
+
+ #include <asm/uaccess.h>
+
++extern char e1000_driver_name[];
++extern char e1000_driver_version[];
++
++extern int e1000_up(struct e1000_adapter *adapter);
++extern void e1000_down(struct e1000_adapter *adapter);
++extern void e1000_reinit_locked(struct e1000_adapter *adapter);
++extern void e1000_reset(struct e1000_adapter *adapter);
++extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
++extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
++extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
++extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
++extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
++extern void e1000_update_stats(struct e1000_adapter *adapter);
++
++
+ struct e1000_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+@@ -42,26 +56,30 @@ struct e1000_stats {
+ #define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+ static const struct e1000_stats e1000_gstrings_stats[] = {
+- { "rx_packets", E1000_STAT(net_stats.rx_packets) },
+- { "tx_packets", E1000_STAT(net_stats.tx_packets) },
+- { "rx_bytes", E1000_STAT(net_stats.rx_bytes) },
+- { "tx_bytes", E1000_STAT(net_stats.tx_bytes) },
+- { "rx_errors", E1000_STAT(net_stats.rx_errors) },
+- { "tx_errors", E1000_STAT(net_stats.tx_errors) },
++ { "rx_packets", E1000_STAT(stats.gprc) },
++ { "tx_packets", E1000_STAT(stats.gptc) },
++ { "rx_bytes", E1000_STAT(stats.gorcl) },
++ { "tx_bytes", E1000_STAT(stats.gotcl) },
++ { "rx_broadcast", E1000_STAT(stats.bprc) },
++ { "tx_broadcast", E1000_STAT(stats.bptc) },
++ { "rx_multicast", E1000_STAT(stats.mprc) },
++ { "tx_multicast", E1000_STAT(stats.mptc) },
++ { "rx_errors", E1000_STAT(stats.rxerrc) },
++ { "tx_errors", E1000_STAT(stats.txerrc) },
+ { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+- { "multicast", E1000_STAT(net_stats.multicast) },
+- { "collisions", E1000_STAT(net_stats.collisions) },
+- { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
++ { "multicast", E1000_STAT(stats.mprc) },
++ { "collisions", E1000_STAT(stats.colc) },
++ { "rx_length_errors", E1000_STAT(stats.rlerrc) },
+ { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+- { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) },
++ { "rx_crc_errors", E1000_STAT(stats.crcerrs) },
+ { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
+- { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },
+- { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },
+- { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },
++ { "rx_missed_errors", E1000_STAT(stats.mpc) },
++ { "tx_aborted_errors", E1000_STAT(stats.ecol) },
++ { "tx_carrier_errors", E1000_STAT(stats.tncrs) },
+ { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+- { "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) },
++ { "tx_window_errors", E1000_STAT(stats.latecol) },
+ { "tx_abort_late_coll", E1000_STAT(stats.latecol) },
+ { "tx_deferred_ok", E1000_STAT(stats.dc) },
+ { "tx_single_coll_ok", E1000_STAT(stats.scc) },
+@@ -183,6 +201,9 @@ e1000_set_settings(struct net_device *ne
+ return -EINVAL;
+ }
+
++ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
++ msleep(1);
++
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ hw->autoneg = 1;
+ if (hw->media_type == e1000_media_type_fiber)
+@@ -190,25 +211,25 @@ e1000_set_settings(struct net_device *ne
+ 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;
++ hw->autoneg_advertised = ecmd->advertising |
++ ADVERTISED_TP |
++ ADVERTISED_Autoneg;
+ ecmd->advertising = hw->autoneg_advertised;
+ } else
+- if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
++ if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
++ clear_bit(__E1000_RESETTING, &adapter->flags);
+ return -EINVAL;
++ }
+
+ /* reset the link */
+
+- if (netif_running(adapter->netdev))
+- e1000_reinit_locked(adapter);
+- else
++ if (netif_running(adapter->netdev)) {
++ e1000_down(adapter);
++ e1000_up(adapter);
++ } else
+ e1000_reset(adapter);
+
++ clear_bit(__E1000_RESETTING, &adapter->flags);
+ return 0;
+ }
+
+@@ -222,11 +243,11 @@ e1000_get_pauseparam(struct net_device *
+ pause->autoneg =
+ (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+- if (hw->fc == e1000_fc_rx_pause)
++ if (hw->fc == E1000_FC_RX_PAUSE)
+ pause->rx_pause = 1;
+- else if (hw->fc == e1000_fc_tx_pause)
++ else if (hw->fc == E1000_FC_TX_PAUSE)
+ pause->tx_pause = 1;
+- else if (hw->fc == e1000_fc_full) {
++ else if (hw->fc == E1000_FC_FULL) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+@@ -238,30 +259,36 @@ e1000_set_pauseparam(struct net_device *
+ {
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
++ int retval = 0;
+
+ adapter->fc_autoneg = pause->autoneg;
+
++ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
++ msleep(1);
++
+ if (pause->rx_pause && pause->tx_pause)
+- hw->fc = e1000_fc_full;
++ hw->fc = E1000_FC_FULL;
+ else if (pause->rx_pause && !pause->tx_pause)
+- hw->fc = e1000_fc_rx_pause;
++ hw->fc = E1000_FC_RX_PAUSE;
+ else if (!pause->rx_pause && pause->tx_pause)
+- hw->fc = e1000_fc_tx_pause;
++ hw->fc = E1000_FC_TX_PAUSE;
+ else if (!pause->rx_pause && !pause->tx_pause)
+- hw->fc = e1000_fc_none;
++ hw->fc = E1000_FC_NONE;
+
+ hw->original_fc = hw->fc;
+
+ if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+- if (netif_running(adapter->netdev))
+- e1000_reinit_locked(adapter);
+- else
++ if (netif_running(adapter->netdev)) {
++ e1000_down(adapter);
++ e1000_up(adapter);
++ } else
+ e1000_reset(adapter);
+ } else
+- return ((hw->media_type == e1000_media_type_fiber) ?
+- e1000_setup_link(hw) : e1000_force_mac_fc(hw));
++ retval = ((hw->media_type == e1000_media_type_fiber) ?
++ e1000_setup_link(hw) : e1000_force_mac_fc(hw));
+
+- return 0;
++ clear_bit(__E1000_RESETTING, &adapter->flags);
++ return retval;
+ }
+
+ static uint32_t
+@@ -415,12 +442,12 @@ e1000_get_regs(struct net_device *netdev
+ regs_buff[23] = regs_buff[18]; /* mdix mode */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
+ } else {
+- e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
++ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ regs_buff[13] = (uint32_t)phy_data; /* cable length */
+ regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+- e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
++ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */
+ regs_buff[18] = regs_buff[13]; /* cable polarity */
+ regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+@@ -434,7 +461,8 @@ e1000_get_regs(struct net_device *netdev
+ regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */
+ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
+ if (hw->mac_type >= e1000_82540 &&
+- hw->media_type == e1000_media_type_copper) {
++ hw->mac_type < e1000_82571 &&
++ hw->media_type == e1000_media_type_copper) {
+ regs_buff[26] = E1000_READ_REG(hw, MANC);
+ }
+ }
+@@ -619,8 +647,8 @@ e1000_set_ringparam(struct net_device *n
+ {
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ e1000_mac_type mac_type = adapter->hw.mac_type;
+- struct e1000_tx_ring *txdr, *tx_old, *tx_new;
+- struct e1000_rx_ring *rxdr, *rx_old, *rx_new;
++ struct e1000_tx_ring *txdr, *tx_old;
++ struct e1000_rx_ring *rxdr, *rx_old;
+ int i, err, tx_ring_size, rx_ring_size;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+@@ -638,23 +666,17 @@ e1000_set_ringparam(struct net_device *n
+ tx_old = adapter->tx_ring;
+ rx_old = adapter->rx_ring;
+
+- adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL);
+- if (!adapter->tx_ring) {
+- err = -ENOMEM;
+- goto err_setup_rx;
+- }
+- memset(adapter->tx_ring, 0, tx_ring_size);
++ err = -ENOMEM;
++ txdr = kzalloc(tx_ring_size, GFP_KERNEL);
++ if (!txdr)
++ goto err_alloc_tx;
+
+- adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL);
+- if (!adapter->rx_ring) {
+- kfree(adapter->tx_ring);
+- err = -ENOMEM;
+- goto err_setup_rx;
+- }
+- memset(adapter->rx_ring, 0, rx_ring_size);
++ rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
++ if (!rxdr)
++ goto err_alloc_rx;
+
+- txdr = adapter->tx_ring;
+- rxdr = adapter->rx_ring;
++ adapter->tx_ring = txdr;
++ adapter->rx_ring = rxdr;
+
+ rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
+ rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
+@@ -681,28 +703,29 @@ e1000_set_ringparam(struct net_device *n
+ /* save the new, restore the old in order to free it,
+ * then restore the new back again */
+
+- rx_new = adapter->rx_ring;
+- tx_new = adapter->tx_ring;
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ e1000_free_all_rx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
+ kfree(tx_old);
+ kfree(rx_old);
+- adapter->rx_ring = rx_new;
+- adapter->tx_ring = tx_new;
++ adapter->rx_ring = rxdr;
++ adapter->tx_ring = txdr;
+ if ((err = e1000_up(adapter)))
+ goto err_setup;
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->flags);
+-
+ return 0;
+ err_setup_tx:
+ e1000_free_all_rx_resources(adapter);
+ err_setup_rx:
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
++ kfree(rxdr);
++err_alloc_rx:
++ kfree(txdr);
++err_alloc_tx:
+ e1000_up(adapter);
+ err_setup:
+ clear_bit(__E1000_RESETTING, &adapter->flags);
+@@ -861,8 +884,7 @@ e1000_eeprom_test(struct e1000_adapter *
+
+ static irqreturn_t
+ e1000_test_intr(int irq,
+- void *data,
+- struct pt_regs *regs)
++ void *data)
+ {
+ struct net_device *netdev = (struct net_device *) data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+@@ -881,21 +903,22 @@ e1000_intr_test(struct e1000_adapter *ad
+
+ *data = 0;
+
++ /* NOTE: we don't test MSI interrupts here, yet */
+ /* Hook up test interrupt handler just for this test */
+ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED,
+- netdev->name, netdev)) {
+- shared_int = FALSE;
+- } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+- netdev->name, netdev)){
++ netdev->name, netdev))
++ shared_int = FALSE;
++ else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
++ netdev->name, netdev)) {
+ *data = 1;
+ return -1;
+ }
+- DPRINTK(PROBE,INFO, "testing %s interrupt\n",
++ DPRINTK(HW, INFO, "testing %s interrupt\n",
+ (shared_int ? "shared" : "unshared"));
+
+ /* Disable all the interrupts */
+ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
+- msec_delay(10);
++ msleep(10);
+
+ /* Test each interrupt */
+ for (; i < 10; i++) {
+@@ -915,7 +938,7 @@ e1000_intr_test(struct e1000_adapter *ad
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+- msec_delay(10);
++ msleep(10);
+
+ if (adapter->test_icr & mask) {
+ *data = 3;
+@@ -932,7 +955,7 @@ e1000_intr_test(struct e1000_adapter *ad
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMS, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+- msec_delay(10);
++ msleep(10);
+
+ if (!(adapter->test_icr & mask)) {
+ *data = 4;
+@@ -949,7 +972,7 @@ e1000_intr_test(struct e1000_adapter *ad
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, ~mask & 0x00007FFF);
+ E1000_WRITE_REG(&adapter->hw, ICS, ~mask & 0x00007FFF);
+- msec_delay(10);
++ msleep(10);
+
+ if (adapter->test_icr) {
+ *data = 5;
+@@ -960,7 +983,7 @@ e1000_intr_test(struct e1000_adapter *ad
+
+ /* Disable all the interrupts */
+ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
+- msec_delay(10);
++ msleep(10);
+
+ /* Unhook test interrupt handler */
+ free_irq(irq, netdev);
+@@ -1256,11 +1279,10 @@ e1000_integrated_phy_loopback(struct e10
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140);
+ /* autoneg off */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140);
+- } else if (adapter->hw.phy_type == e1000_phy_gg82563) {
++ } else if (adapter->hw.phy_type == e1000_phy_gg82563)
+ e1000_write_phy_reg(&adapter->hw,
+ GG82563_PHY_KMRN_MODE_CTRL,
+ 0x1CC);
+- }
+
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+
+@@ -1288,9 +1310,9 @@ e1000_integrated_phy_loopback(struct e10
+ }
+
+ if (adapter->hw.media_type == e1000_media_type_copper &&
+- adapter->hw.phy_type == e1000_phy_m88) {
++ adapter->hw.phy_type == e1000_phy_m88)
+ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+- } else {
++ else {
+ /* Set the ILOS bit on the fiber Nic is half
+ * duplex link is detected. */
+ stat_reg = E1000_READ_REG(&adapter->hw, STATUS);
+@@ -1383,7 +1405,7 @@ e1000_setup_loopback_test(struct e1000_a
+ #define E1000_SERDES_LB_ON 0x410
+ e1000_set_phy_loopback(adapter);
+ E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON);
+- msec_delay(10);
++ msleep(10);
+ return 0;
+ break;
+ default:
+@@ -1416,7 +1438,7 @@ e1000_loopback_cleanup(struct e1000_adap
+ hw->media_type == e1000_media_type_internal_serdes) {
+ #define E1000_SERDES_LB_OFF 0x400
+ E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF);
+- msec_delay(10);
++ msleep(10);
+ break;
+ }
+ /* Fall Through */
+@@ -1426,11 +1448,10 @@ e1000_loopback_cleanup(struct e1000_adap
+ case e1000_82546_rev_3:
+ default:
+ hw->autoneg = TRUE;
+- if (hw->phy_type == e1000_phy_gg82563) {
++ if (hw->phy_type == e1000_phy_gg82563)
+ e1000_write_phy_reg(hw,
+ GG82563_PHY_KMRN_MODE_CTRL,
+ 0x180);
+- }
+ e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
+ if (phy_reg & MII_CR_LOOPBACK) {
+ phy_reg &= ~MII_CR_LOOPBACK;
+@@ -1497,7 +1518,7 @@ e1000_run_loopback_test(struct e1000_ada
+ if (unlikely(++k == txdr->count)) k = 0;
+ }
+ E1000_WRITE_REG(&adapter->hw, TDT, k);
+- msec_delay(200);
++ msleep(200);
+ time = jiffies; /* set the start time for the receive */
+ good_cnt = 0;
+ do { /* receive the sent packets */
+@@ -1568,14 +1589,14 @@ e1000_link_test(struct e1000_adapter *ad
+ e1000_check_for_link(&adapter->hw);
+ if (adapter->hw.serdes_link_down == FALSE)
+ return *data;
+- msec_delay(20);
++ msleep(20);
+ } while (i++ < 3750);
+
+ *data = 1;
+ } else {
+ e1000_check_for_link(&adapter->hw);
+ if (adapter->hw.autoneg) /* if auto_neg is set wait for it */
+- msec_delay(4000);
++ msleep(4000);
+
+ if (!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
+ *data = 1;
+@@ -1590,6 +1611,8 @@ e1000_diag_test_count(struct net_device
+ return E1000_TEST_LEN;
+ }
+
++extern void e1000_power_up_phy(struct e1000_adapter *);
++
+ static void
+ e1000_diag_test(struct net_device *netdev,
+ struct ethtool_test *eth_test, uint64_t *data)
+@@ -1597,7 +1620,7 @@ e1000_diag_test(struct net_device *netde
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ boolean_t if_running = netif_running(netdev);
+
+- set_bit(__E1000_DRIVER_TESTING, &adapter->flags);
++ set_bit(__E1000_TESTING, &adapter->flags);
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ /* Offline tests */
+
+@@ -1606,6 +1629,8 @@ e1000_diag_test(struct net_device *netde
+ uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex;
+ uint8_t autoneg = adapter->hw.autoneg;
+
++ DPRINTK(HW, INFO, "offline testing starting\n");
++
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result */
+ if (e1000_link_test(adapter, &data[4]))
+@@ -1629,6 +1654,8 @@ e1000_diag_test(struct net_device *netde
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
++ /* make sure the phy is powered up */
++ e1000_power_up_phy(adapter);
+ if (e1000_loopback_test(adapter, &data[3]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+@@ -1638,10 +1665,11 @@ e1000_diag_test(struct net_device *netde
+ adapter->hw.autoneg = autoneg;
+
+ e1000_reset(adapter);
+- clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
++ clear_bit(__E1000_TESTING, &adapter->flags);
+ if (if_running)
+ dev_open(netdev);
+ } else {
++ DPRINTK(HW, INFO, "online testing starting\n");
+ /* Online tests */
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+@@ -1652,18 +1680,17 @@ e1000_diag_test(struct net_device *netde
+ data[2] = 0;
+ data[3] = 0;
+
+- clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
++ clear_bit(__E1000_TESTING, &adapter->flags);
+ }
+ msleep_interruptible(4 * 1000);
+ }
+
+-static void
+-e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
++static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+ {
+- struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
++ int retval = 1; /* fail by default */
+
+- switch (adapter->hw.device_id) {
++ switch (hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+@@ -1672,52 +1699,87 @@ e1000_get_wol(struct net_device *netdev,
+ case E1000_DEV_ID_82545EM_FIBER:
+ case E1000_DEV_ID_82545EM_COPPER:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER:
++ case E1000_DEV_ID_82546GB_PCIE:
++ /* these don't support WoL at all */
+ wol->supported = 0;
+- wol->wolopts = 0;
+- return;
+-
+- case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+- /* device id 10B5 port-A supports wol */
+- if (!adapter->ksp3_port_a) {
+- wol->supported = 0;
+- return;
+- }
+- /* KSP3 does not suppport UCAST wake-ups for any interface */
+- wol->supported = WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+-
+- if (adapter->wol & E1000_WUFC_EX)
+- DPRINTK(DRV, ERR, "Interface does not support "
+- "directed (unicast) frame wake-up packets\n");
+- wol->wolopts = 0;
+- goto do_defaults;
+-
++ break;
+ case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546GB_FIBER:
+ case E1000_DEV_ID_82571EB_FIBER:
+- /* Wake events only supported on port A for dual fiber */
++ case E1000_DEV_ID_82571EB_SERDES:
++ case E1000_DEV_ID_82571EB_COPPER:
++ /* Wake events not supported on port B */
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) {
+ wol->supported = 0;
+- wol->wolopts = 0;
+- return;
++ break;
+ }
+- /* Fall Through */
+-
++ /* return success for non excluded adapter ports */
++ retval = 0;
++ break;
++ case E1000_DEV_ID_82571EB_QUAD_COPPER:
++ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
++ /* quad port adapters only support WoL on port A */
++ if (!adapter->quad_port_a) {
++ wol->supported = 0;
++ break;
++ }
++ /* return success for non excluded adapter ports */
++ retval = 0;
++ break;
+ default:
+- wol->supported = WAKE_UCAST | WAKE_MCAST |
+- WAKE_BCAST | WAKE_MAGIC;
+- wol->wolopts = 0;
++ /* dual port cards only support WoL on port A from now on
++ * unless it was enabled in the eeprom for port B
++ * so exclude FUNC_1 ports from having WoL enabled */
++ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1 &&
++ !adapter->eeprom_wol) {
++ wol->supported = 0;
++ break;
++ }
+
+-do_defaults:
+- if (adapter->wol & E1000_WUFC_EX)
+- wol->wolopts |= WAKE_UCAST;
+- if (adapter->wol & E1000_WUFC_MC)
+- wol->wolopts |= WAKE_MCAST;
+- if (adapter->wol & E1000_WUFC_BC)
+- wol->wolopts |= WAKE_BCAST;
+- if (adapter->wol & E1000_WUFC_MAG)
+- wol->wolopts |= WAKE_MAGIC;
++ retval = 0;
++ }
++
++ return retval;
++}
++
++static void
++e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
++{
++ struct e1000_adapter *adapter = netdev_priv(netdev);
++
++ wol->supported = WAKE_UCAST | WAKE_MCAST |
++ WAKE_BCAST | WAKE_MAGIC;
++ wol->wolopts = 0;
++
++ /* this function will set ->supported = 0 and return 1 if wol is not
++ * supported by this hardware */
++ if (e1000_wol_exclusion(adapter, wol))
+ return;
++
++ /* apply any specific unsupported masks here */
++ switch (adapter->hw.device_id) {
++ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
++ /* KSP3 does not suppport UCAST wake-ups */
++ wol->supported &= ~WAKE_UCAST;
++
++ if (adapter->wol & E1000_WUFC_EX)
++ DPRINTK(DRV, ERR, "Interface does not support "
++ "directed (unicast) frame wake-up packets\n");
++ break;
++ default:
++ break;
+ }
++
++ if (adapter->wol & E1000_WUFC_EX)
++ wol->wolopts |= WAKE_UCAST;
++ if (adapter->wol & E1000_WUFC_MC)
++ wol->wolopts |= WAKE_MCAST;
++ if (adapter->wol & E1000_WUFC_BC)
++ wol->wolopts |= WAKE_BCAST;
++ if (adapter->wol & E1000_WUFC_MAG)
++ wol->wolopts |= WAKE_MAGIC;
++
++ return;
+ }
+
+ static int
+@@ -1726,51 +1788,35 @@ e1000_set_wol(struct net_device *netdev,
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+- switch (adapter->hw.device_id) {
+- case E1000_DEV_ID_82542:
+- case E1000_DEV_ID_82543GC_FIBER:
+- case E1000_DEV_ID_82543GC_COPPER:
+- case E1000_DEV_ID_82544EI_FIBER:
+- case E1000_DEV_ID_82546EB_QUAD_COPPER:
+- case E1000_DEV_ID_82546GB_QUAD_COPPER:
+- case E1000_DEV_ID_82545EM_FIBER:
+- case E1000_DEV_ID_82545EM_COPPER:
++ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
++ return -EOPNOTSUPP;
++
++ if (e1000_wol_exclusion(adapter, wol))
+ return wol->wolopts ? -EOPNOTSUPP : 0;
+
++ switch (hw->device_id) {
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+- /* device id 10B5 port-A supports wol */
+- if (!adapter->ksp3_port_a)
+- return wol->wolopts ? -EOPNOTSUPP : 0;
+-
+ if (wol->wolopts & WAKE_UCAST) {
+ DPRINTK(DRV, ERR, "Interface does not support "
+ "directed (unicast) frame wake-up packets\n");
+ return -EOPNOTSUPP;
+ }
+-
+- case E1000_DEV_ID_82546EB_FIBER:
+- case E1000_DEV_ID_82546GB_FIBER:
+- case E1000_DEV_ID_82571EB_FIBER:
+- /* Wake events only supported on port A for dual fiber */
+- if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+- return wol->wolopts ? -EOPNOTSUPP : 0;
+- /* Fall Through */
+-
++ break;
+ default:
+- if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+- return -EOPNOTSUPP;
++ break;
++ }
+
+- adapter->wol = 0;
++ /* these settings will always override what we currently have */
++ adapter->wol = 0;
+
+- if (wol->wolopts & WAKE_UCAST)
+- adapter->wol |= E1000_WUFC_EX;
+- if (wol->wolopts & WAKE_MCAST)
+- adapter->wol |= E1000_WUFC_MC;
+- if (wol->wolopts & WAKE_BCAST)
+- adapter->wol |= E1000_WUFC_BC;
+- if (wol->wolopts & WAKE_MAGIC)
+- adapter->wol |= E1000_WUFC_MAG;
+- }
++ if (wol->wolopts & WAKE_UCAST)
++ adapter->wol |= E1000_WUFC_EX;
++ if (wol->wolopts & WAKE_MCAST)
++ adapter->wol |= E1000_WUFC_MC;
++ if (wol->wolopts & WAKE_BCAST)
++ adapter->wol |= E1000_WUFC_BC;
++ if (wol->wolopts & WAKE_MAGIC)
++ adapter->wol |= E1000_WUFC_MAG;
+
+ return 0;
+ }
+@@ -1887,7 +1933,7 @@ e1000_get_strings(struct net_device *net
+ }
+ }
+
+-static struct ethtool_ops e1000_ethtool_ops = {
++static const struct ethtool_ops e1000_ethtool_ops = {
+ .get_settings = e1000_get_settings,
+ .set_settings = e1000_set_settings,
+ .get_drvinfo = e1000_get_drvinfo,
+@@ -1895,8 +1941,8 @@ static struct ethtool_ops e1000_ethtool_
+ .get_regs = e1000_get_regs,
+ .get_wol = e1000_get_wol,
+ .set_wol = e1000_set_wol,
+- .get_msglevel = e1000_get_msglevel,
+- .set_msglevel = e1000_set_msglevel,
++ .get_msglevel = e1000_get_msglevel,
++ .set_msglevel = e1000_set_msglevel,
+ .nway_reset = e1000_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_eeprom_len = e1000_get_eeprom_len,
+@@ -1904,17 +1950,17 @@ static struct ethtool_ops e1000_ethtool_
+ .set_eeprom = e1000_set_eeprom,
+ .get_ringparam = e1000_get_ringparam,
+ .set_ringparam = e1000_set_ringparam,
+- .get_pauseparam = e1000_get_pauseparam,
+- .set_pauseparam = e1000_set_pauseparam,
+- .get_rx_csum = e1000_get_rx_csum,
+- .set_rx_csum = e1000_set_rx_csum,
+- .get_tx_csum = e1000_get_tx_csum,
+- .set_tx_csum = e1000_set_tx_csum,
+- .get_sg = ethtool_op_get_sg,
+- .set_sg = ethtool_op_set_sg,
++ .get_pauseparam = e1000_get_pauseparam,
++ .set_pauseparam = e1000_set_pauseparam,
++ .get_rx_csum = e1000_get_rx_csum,
++ .set_rx_csum = e1000_set_rx_csum,
++ .get_tx_csum = e1000_get_tx_csum,
++ .set_tx_csum = e1000_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = ethtool_op_set_sg,
+ #ifdef NETIF_F_TSO
+- .get_tso = ethtool_op_get_tso,
+- .set_tso = e1000_set_tso,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = e1000_set_tso,
+ #endif
+ .self_test_count = e1000_diag_test_count,
+ .self_test = e1000_diag_test,
+@@ -1922,7 +1968,7 @@ static struct ethtool_ops e1000_ethtool_
+ .phys_id = e1000_phys_id,
+ .get_stats_count = e1000_get_stats_count,
+ .get_ethtool_stats = e1000_get_ethtool_stats,
+- .get_perm_addr = ethtool_op_get_perm_addr,
++ .get_perm_addr = ethtool_op_get_perm_addr,
+ };
+
+ void e1000_set_ethtool_ops(struct net_device *netdev)
+diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
+index b3b9191..65077f3 100644
+--- a/drivers/net/e1000/e1000_hw.c
++++ b/drivers/net/e1000/e1000_hw.c
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -31,8 +30,66 @@
+ * Shared functions for accessing and configuring the MAC
+ */
+
++
+ #include "e1000_hw.h"
+
++static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
++static void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
++static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data);
++static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
++static int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
++static void e1000_release_software_semaphore(struct e1000_hw *hw);
++
++static uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
++static int32_t e1000_check_downshift(struct e1000_hw *hw);
++static int32_t e1000_check_polarity(struct e1000_hw *hw, e1000_rev_polarity *polarity);
++static void e1000_clear_hw_cntrs(struct e1000_hw *hw);
++static void e1000_clear_vfta(struct e1000_hw *hw);
++static int32_t e1000_commit_shadow_ram(struct e1000_hw *hw);
++static int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up);
++static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
++static int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
++static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t bank);
++static int32_t e1000_get_auto_rd_done(struct e1000_hw *hw);
++static int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length);
++static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw);
++static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw);
++static int32_t e1000_get_software_flag(struct e1000_hw *hw);
++static int32_t e1000_ich8_cycle_init(struct e1000_hw *hw);
++static int32_t e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout);
++static int32_t e1000_id_led_init(struct e1000_hw *hw);
++static int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size);
++static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
++static void e1000_init_rx_addrs(struct e1000_hw *hw);
++static void e1000_initialize_hardware_bits(struct e1000_hw *hw);
++static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw);
++static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
++static int32_t e1000_mng_enable_host_if(struct e1000_hw *hw);
++static int32_t e1000_mng_host_if_write(struct e1000_hw *hw, uint8_t *buffer, uint16_t length, uint16_t offset, uint8_t *sum);
++static int32_t e1000_mng_write_cmd_header(struct e1000_hw* hw, struct e1000_host_mng_command_header* hdr);
++static int32_t e1000_mng_write_commit(struct e1000_hw *hw);
++static int32_t e1000_phy_ife_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
++static int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
++static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
++static int32_t e1000_write_eeprom_eewr(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
++static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd);
++static int32_t e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
++static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
++static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t *data);
++static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte);
++static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte);
++static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data);
++static int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t *data);
++static int32_t e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t data);
++static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
++static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
++static void e1000_release_software_flag(struct e1000_hw *hw);
++static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active);
++static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active);
++static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop);
++static void e1000_set_pci_express_master_disable(struct e1000_hw *hw);
++static int32_t e1000_wait_autoneg(struct e1000_hw *hw);
++static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+ static int32_t e1000_set_phy_type(struct e1000_hw *hw);
+ static void e1000_phy_init_script(struct e1000_hw *hw);
+ static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+@@ -69,69 +126,10 @@ static int32_t e1000_polarity_reversal_w
+ static int32_t e1000_set_phy_mode(struct e1000_hw *hw);
+ static int32_t e1000_host_if_read_cookie(struct e1000_hw *hw, uint8_t *buffer);
+ static uint8_t e1000_calculate_mng_checksum(char *buffer, uint32_t length);
+-static uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
+-static int32_t e1000_check_downshift(struct e1000_hw *hw);
+-static int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity);
+-static void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+-static void e1000_clear_vfta(struct e1000_hw *hw);
+-static int32_t e1000_commit_shadow_ram(struct e1000_hw *hw);
+-static int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw,
+- boolean_t link_up);
+-static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+-static int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+-static int32_t e1000_get_auto_rd_done(struct e1000_hw *hw);
+-static int32_t e1000_get_cable_length(struct e1000_hw *hw,
+- uint16_t *min_length,
+- uint16_t *max_length);
+-static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw);
+-static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw);
+-static int32_t e1000_id_led_init(struct e1000_hw * hw);
+-static void e1000_init_rx_addrs(struct e1000_hw *hw);
+-static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw);
+-static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd);
+-static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+-static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset,
+- uint16_t words, uint16_t *data);
+-static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active);
+-static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active);
+-static int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+-
+-static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
+- uint32_t value);
+-
+-#define E1000_WRITE_REG_IO(a, reg, val) \
+- e1000_write_reg_io((a), E1000_##reg, val)
+ static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw,
+ uint16_t duplex);
+ static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
+
+-static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw,
+- uint32_t segment);
+-static int32_t e1000_get_software_flag(struct e1000_hw *hw);
+-static int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
+-static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
+-static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
+-static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+- uint16_t words, uint16_t *data);
+-static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index,
+- uint8_t* data);
+-static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index,
+- uint16_t *data);
+-static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr,
+- uint16_t *data);
+-static void e1000_release_software_flag(struct e1000_hw *hw);
+-static void e1000_release_software_semaphore(struct e1000_hw *hw);
+-static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw,
+- uint32_t no_snoop);
+-static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw,
+- uint32_t index, uint8_t byte);
+-static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+- uint16_t words, uint16_t *data);
+-static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
+- uint8_t data);
+-static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr,
+- uint16_t data);
+-
+ /* IGP cable length table */
+ static const
+ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
+@@ -155,21 +153,20 @@ uint16_t e1000_igp_2_cable_length_table[
+ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+ 104, 109, 114, 118, 121, 124};
+
+-
+ /******************************************************************************
+ * Set the phy type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+-int32_t
++static int32_t
+ e1000_set_phy_type(struct e1000_hw *hw)
+ {
+ DEBUGFUNC("e1000_set_phy_type");
+
+- if(hw->mac_type == e1000_undefined)
++ if (hw->mac_type == e1000_undefined)
+ return -E1000_ERR_PHY_TYPE;
+
+- switch(hw->phy_id) {
++ switch (hw->phy_id) {
+ case M88E1000_E_PHY_ID:
+ case M88E1000_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+@@ -177,10 +174,10 @@ e1000_set_phy_type(struct e1000_hw *hw)
+ hw->phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID:
+- if(hw->mac_type == e1000_82541 ||
+- hw->mac_type == e1000_82541_rev_2 ||
+- hw->mac_type == e1000_82547 ||
+- hw->mac_type == e1000_82547_rev_2) {
++ if (hw->mac_type == e1000_82541 ||
++ hw->mac_type == e1000_82541_rev_2 ||
++ hw->mac_type == e1000_82547 ||
++ hw->mac_type == e1000_82547_rev_2) {
+ hw->phy_type = e1000_phy_igp;
+ break;
+ }
+@@ -220,8 +217,8 @@ e1000_phy_init_script(struct e1000_hw *h
+
+ DEBUGFUNC("e1000_phy_init_script");
+
+- if(hw->phy_init_script) {
+- msec_delay(20);
++ if (hw->phy_init_script) {
++ msleep(20);
+
+ /* Save off the current value of register 0x2F5B to be restored at
+ * the end of this routine. */
+@@ -230,13 +227,13 @@ e1000_phy_init_script(struct e1000_hw *h
+ /* Disabled the PHY transmitter */
+ e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+- msec_delay(20);
++ msleep(20);
+
+ e1000_write_phy_reg(hw,0x0000,0x0140);
+
+- msec_delay(5);
++ msleep(5);
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82541:
+ case e1000_82547:
+ e1000_write_phy_reg(hw, 0x1F95, 0x0001);
+@@ -268,27 +265,27 @@ e1000_phy_init_script(struct e1000_hw *h
+
+ e1000_write_phy_reg(hw, 0x0000, 0x3300);
+
+- msec_delay(20);
++ msleep(20);
+
+ /* Now enable the transmitter */
+ e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+- if(hw->mac_type == e1000_82547) {
++ if (hw->mac_type == e1000_82547) {
+ uint16_t fused, fine, coarse;
+
+ /* Move to analog registers page */
+ e1000_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
+
+- if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
++ if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+ e1000_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused);
+
+ fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+ coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
+
+- if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
++ if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+ coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+- } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
++ } else if (coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
+
+ fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+@@ -387,6 +384,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
++ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ hw->mac_type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI_COPPER:
+@@ -418,7 +416,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
+ return -E1000_ERR_MAC_TYPE;
+ }
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ hw->swfwhw_semaphore_present = TRUE;
+ hw->asf_firmware_present = TRUE;
+@@ -456,7 +454,7 @@ e1000_set_media_type(struct e1000_hw *hw
+
+ DEBUGFUNC("e1000_set_media_type");
+
+- if(hw->mac_type != e1000_82543) {
++ if (hw->mac_type != e1000_82543) {
+ /* tbi_compatibility is only valid on 82543 */
+ hw->tbi_compatibility_en = FALSE;
+ }
+@@ -516,16 +514,16 @@ e1000_reset_hw(struct e1000_hw *hw)
+ DEBUGFUNC("e1000_reset_hw");
+
+ /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+- if(hw->mac_type == e1000_82542_rev2_0) {
++ if (hw->mac_type == e1000_82542_rev2_0) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ e1000_pci_clear_mwi(hw);
+ }
+
+- if(hw->bus_type == e1000_bus_type_pci_express) {
++ if (hw->bus_type == e1000_bus_type_pci_express) {
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+- if(e1000_disable_pciex_master(hw) != E1000_SUCCESS) {
++ if (e1000_disable_pciex_master(hw) != E1000_SUCCESS) {
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+ }
+ }
+@@ -548,19 +546,19 @@ e1000_reset_hw(struct e1000_hw *hw)
+ /* Delay to allow any outstanding PCI transactions to complete before
+ * resetting the device
+ */
+- msec_delay(10);
++ msleep(10);
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Must reset the PHY before resetting the MAC */
+- if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
++ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+- msec_delay(5);
++ msleep(5);
+ }
+
+ /* Must acquire the MDIO ownership before MAC reset.
+ * Ownership defaults to firmware after a reset. */
+- if(hw->mac_type == e1000_82573) {
++ if (hw->mac_type == e1000_82573) {
+ timeout = 10;
+
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+@@ -570,14 +568,14 @@ e1000_reset_hw(struct e1000_hw *hw)
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+
+- if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
++ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+ else
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+- msec_delay(2);
++ msleep(2);
+ timeout--;
+- } while(timeout);
++ } while (timeout);
+ }
+
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+@@ -595,7 +593,7 @@ e1000_reset_hw(struct e1000_hw *hw)
+ */
+ DEBUGOUT("Issuing a global reset to MAC\n");
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82544:
+ case e1000_82540:
+ case e1000_82545:
+@@ -623,7 +621,7 @@ e1000_reset_hw(struct e1000_hw *hw)
+
+ e1000_get_software_flag(hw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+- msec_delay(5);
++ msleep(5);
+ break;
+ default:
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+@@ -634,7 +632,7 @@ e1000_reset_hw(struct e1000_hw *hw)
+ * device. Later controllers reload the EEPROM automatically, so just wait
+ * for reload to complete.
+ */
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+@@ -646,14 +644,14 @@ e1000_reset_hw(struct e1000_hw *hw)
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ /* Wait for EEPROM reload */
+- msec_delay(2);
++ msleep(2);
+ break;
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+ /* Wait for EEPROM reload */
+- msec_delay(20);
++ msleep(20);
+ break;
+ case e1000_82573:
+ if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
+@@ -664,29 +662,22 @@ e1000_reset_hw(struct e1000_hw *hw)
+ E1000_WRITE_FLUSH(hw);
+ }
+ /* fall through */
+- case e1000_82571:
+- case e1000_82572:
+- case e1000_ich8lan:
+- case e1000_80003es2lan:
++ default:
++ /* Auto read done will delay 5ms or poll based on mac type */
+ ret_val = e1000_get_auto_rd_done(hw);
+- if(ret_val)
+- /* We don't want to continue accessing MAC registers. */
++ if (ret_val)
+ return ret_val;
+ break;
+- default:
+- /* Wait for EEPROM reload (it happens automatically) */
+- msec_delay(5);
+- break;
+ }
+
+ /* Disable HW ARPs on ASF enabled adapters */
+- if(hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) {
++ if (hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) {
+ manc = E1000_READ_REG(hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(hw, MANC, manc);
+ }
+
+- if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
++ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ e1000_phy_init_script(hw);
+
+ /* Configure activity LED after PHY reset */
+@@ -704,8 +695,8 @@ e1000_reset_hw(struct e1000_hw *hw)
+ icr = E1000_READ_REG(hw, ICR);
+
+ /* If MWI was previously enabled, reenable it. */
+- if(hw->mac_type == e1000_82542_rev2_0) {
+- if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
++ if (hw->mac_type == e1000_82542_rev2_0) {
++ if (hw->pci_cmd_word & PCI_COMMAND_INVALIDATE)
+ e1000_pci_set_mwi(hw);
+ }
+
+@@ -719,6 +710,123 @@ e1000_reset_hw(struct e1000_hw *hw)
+ }
+
+ /******************************************************************************
++ *
++ * Initialize a number of hardware-dependent bits
++ *
++ * hw: Struct containing variables accessed by shared code
++ *
++ * This function contains hardware limitation workarounds for PCI-E adapters
++ *
++ *****************************************************************************/
++static void
++e1000_initialize_hardware_bits(struct e1000_hw *hw)
++{
++ if ((hw->mac_type >= e1000_82571) && (!hw->initialize_hw_bits_disable)) {
++ /* Settings common to all PCI-express silicon */
++ uint32_t reg_ctrl, reg_ctrl_ext;
++ uint32_t reg_tarc0, reg_tarc1;
++ uint32_t reg_tctl;
++ uint32_t reg_txdctl, reg_txdctl1;
++
++ /* link autonegotiation/sync workarounds */
++ reg_tarc0 = E1000_READ_REG(hw, TARC0);
++ reg_tarc0 &= ~((1 << 30)|(1 << 29)|(1 << 28)|(1 << 27));
++
++ /* Enable not-done TX descriptor counting */
++ reg_txdctl = E1000_READ_REG(hw, TXDCTL);
++ reg_txdctl |= E1000_TXDCTL_COUNT_DESC;
++ E1000_WRITE_REG(hw, TXDCTL, reg_txdctl);
++ reg_txdctl1 = E1000_READ_REG(hw, TXDCTL1);
++ reg_txdctl1 |= E1000_TXDCTL_COUNT_DESC;
++ E1000_WRITE_REG(hw, TXDCTL1, reg_txdctl1);
++
++ switch (hw->mac_type) {
++ case e1000_82571:
++ case e1000_82572:
++ /* Clear PHY TX compatible mode bits */
++ reg_tarc1 = E1000_READ_REG(hw, TARC1);
++ reg_tarc1 &= ~((1 << 30)|(1 << 29));
++
++ /* link autonegotiation/sync workarounds */
++ reg_tarc0 |= ((1 << 26)|(1 << 25)|(1 << 24)|(1 << 23));
++
++ /* TX ring control fixes */
++ reg_tarc1 |= ((1 << 26)|(1 << 25)|(1 << 24));
++
++ /* Multiple read bit is reversed polarity */
++ reg_tctl = E1000_READ_REG(hw, TCTL);
++ if (reg_tctl & E1000_TCTL_MULR)
++ reg_tarc1 &= ~(1 << 28);
++ else
++ reg_tarc1 |= (1 << 28);
++
++ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
++ break;
++ case e1000_82573:
++ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
++ reg_ctrl_ext &= ~(1 << 23);
++ reg_ctrl_ext |= (1 << 22);
++
++ /* TX byte count fix */
++ reg_ctrl = E1000_READ_REG(hw, CTRL);
++ reg_ctrl &= ~(1 << 29);
++
++ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
++ E1000_WRITE_REG(hw, CTRL, reg_ctrl);
++ break;
++ case e1000_80003es2lan:
++ /* improve small packet performace for fiber/serdes */
++ if ((hw->media_type == e1000_media_type_fiber) ||
++ (hw->media_type == e1000_media_type_internal_serdes)) {
++ reg_tarc0 &= ~(1 << 20);
++ }
++
++ /* Multiple read bit is reversed polarity */
++ reg_tctl = E1000_READ_REG(hw, TCTL);
++ reg_tarc1 = E1000_READ_REG(hw, TARC1);
++ if (reg_tctl & E1000_TCTL_MULR)
++ reg_tarc1 &= ~(1 << 28);
++ else
++ reg_tarc1 |= (1 << 28);
++
++ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
++ break;
++ case e1000_ich8lan:
++ /* Reduce concurrent DMA requests to 3 from 4 */
++ if ((hw->revision_id < 3) ||
++ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
++ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))
++ reg_tarc0 |= ((1 << 29)|(1 << 28));
++
++ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
++ reg_ctrl_ext |= (1 << 22);
++ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
++
++ /* workaround TX hang with TSO=on */
++ reg_tarc0 |= ((1 << 27)|(1 << 26)|(1 << 24)|(1 << 23));
++
++ /* Multiple read bit is reversed polarity */
++ reg_tctl = E1000_READ_REG(hw, TCTL);
++ reg_tarc1 = E1000_READ_REG(hw, TARC1);
++ if (reg_tctl & E1000_TCTL_MULR)
++ reg_tarc1 &= ~(1 << 28);
++ else
++ reg_tarc1 |= (1 << 28);
++
++ /* workaround TX hang with TSO=on */
++ reg_tarc1 |= ((1 << 30)|(1 << 26)|(1 << 24));
++
++ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
++ break;
++ default:
++ break;
++ }
++
++ E1000_WRITE_REG(hw, TARC0, reg_tarc0);
++ }
++}
++
++/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+@@ -745,9 +853,19 @@ e1000_init_hw(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_init_hw");
+
++ /* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */
++ if ((hw->mac_type == e1000_ich8lan) &&
++ ((hw->revision_id < 3) ||
++ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
++ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))) {
++ reg_data = E1000_READ_REG(hw, STATUS);
++ reg_data &= ~0x80000000;
++ E1000_WRITE_REG(hw, STATUS, reg_data);
++ }
++
+ /* Initialize Identification LED */
+ ret_val = e1000_id_led_init(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Initializing Identification LED\n");
+ return ret_val;
+ }
+@@ -755,6 +873,9 @@ e1000_init_hw(struct e1000_hw *hw)
+ /* Set the media type and TBI compatibility */
+ e1000_set_media_type(hw);
+
++ /* Must be called after e1000_set_media_type because media_type is used */
++ e1000_initialize_hardware_bits(hw);
++
+ /* Disabling VLAN filtering. */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+@@ -765,12 +886,12 @@ e1000_init_hw(struct e1000_hw *hw)
+ }
+
+ /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+- if(hw->mac_type == e1000_82542_rev2_0) {
++ if (hw->mac_type == e1000_82542_rev2_0) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ e1000_pci_clear_mwi(hw);
+ E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+ E1000_WRITE_FLUSH(hw);
+- msec_delay(5);
++ msleep(5);
+ }
+
+ /* Setup the receive address. This involves initializing all of the Receive
+@@ -779,11 +900,11 @@ e1000_init_hw(struct e1000_hw *hw)
+ e1000_init_rx_addrs(hw);
+
+ /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+- if(hw->mac_type == e1000_82542_rev2_0) {
++ if (hw->mac_type == e1000_82542_rev2_0) {
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_FLUSH(hw);
+- msec_delay(1);
+- if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
++ msleep(1);
++ if (hw->pci_cmd_word & PCI_COMMAND_INVALIDATE)
+ e1000_pci_set_mwi(hw);
+ }
+
+@@ -792,7 +913,7 @@ e1000_init_hw(struct e1000_hw *hw)
+ mta_size = E1000_MC_TBL_SIZE;
+ if (hw->mac_type == e1000_ich8lan)
+ mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
+- for(i = 0; i < mta_size; i++) {
++ for (i = 0; i < mta_size; i++) {
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ /* use write flush to prevent Memory Write Block (MWB) from
+ * occuring when accessing our register space */
+@@ -804,18 +925,18 @@ e1000_init_hw(struct e1000_hw *hw)
+ * gives equal priority to transmits and receives. Valid only on
+ * 82542 and 82543 silicon.
+ */
+- if(hw->dma_fairness && hw->mac_type <= e1000_82543) {
++ if (hw->dma_fairness && hw->mac_type <= e1000_82543) {
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+ }
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82545_rev_3:
+ case e1000_82546_rev_3:
+ break;
+ default:
+ /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+- if(hw->bus_type == e1000_bus_type_pcix) {
++ if (hw->bus_type == e1000_bus_type_pcix) {
+ e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+ e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
+ &pcix_stat_hi_word);
+@@ -823,9 +944,9 @@ e1000_init_hw(struct e1000_hw *hw)
+ PCIX_COMMAND_MMRBC_SHIFT;
+ stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+ PCIX_STATUS_HI_MMRBC_SHIFT;
+- if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
++ if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+- if(cmd_mmrbc > stat_mmrbc) {
++ if (cmd_mmrbc > stat_mmrbc) {
+ pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+ pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+ e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
+@@ -837,26 +958,15 @@ e1000_init_hw(struct e1000_hw *hw)
+
+ /* More time needed for PHY to initialize */
+ if (hw->mac_type == e1000_ich8lan)
+- msec_delay(15);
++ msleep(15);
+
+ /* Call a subroutine to configure the link and setup flow control. */
+ ret_val = e1000_setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+- if(hw->mac_type > e1000_82544) {
++ if (hw->mac_type > e1000_82544) {
+ ctrl = E1000_READ_REG(hw, TXDCTL);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+- switch (hw->mac_type) {
+- default:
+- break;
+- case e1000_82571:
+- case e1000_82572:
+- case e1000_82573:
+- case e1000_ich8lan:
+- case e1000_80003es2lan:
+- ctrl |= E1000_TXDCTL_COUNT_DESC;
+- break;
+- }
+ E1000_WRITE_REG(hw, TXDCTL, ctrl);
+ }
+
+@@ -894,14 +1004,11 @@ e1000_init_hw(struct e1000_hw *hw)
+ case e1000_ich8lan:
+ ctrl = E1000_READ_REG(hw, TXDCTL1);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+- if(hw->mac_type >= e1000_82571)
+- ctrl |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+ break;
+ }
+
+
+-
+ if (hw->mac_type == e1000_82573) {
+ uint32_t gcr = E1000_READ_REG(hw, GCR);
+ gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+@@ -945,10 +1052,10 @@ e1000_adjust_serdes_amplitude(struct e10
+
+ DEBUGFUNC("e1000_adjust_serdes_amplitude");
+
+- if(hw->media_type != e1000_media_type_internal_serdes)
++ if (hw->media_type != e1000_media_type_internal_serdes)
+ return E1000_SUCCESS;
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82545_rev_3:
+ case e1000_82546_rev_3:
+ break;
+@@ -961,11 +1068,11 @@ e1000_adjust_serdes_amplitude(struct e10
+ return ret_val;
+ }
+
+- if(eeprom_data != EEPROM_RESERVED_WORD) {
++ if (eeprom_data != EEPROM_RESERVED_WORD) {
+ /* Adjust SERDES output amplitude only. */
+ eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+@@ -1005,11 +1112,11 @@ e1000_setup_link(struct e1000_hw *hw)
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+- if (hw->fc == e1000_fc_default) {
++ if (hw->fc == E1000_FC_DEFAULT) {
+ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ case e1000_82573:
+- hw->fc = e1000_fc_full;
++ hw->fc = E1000_FC_FULL;
+ break;
+ default:
+ ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
+@@ -1019,12 +1126,12 @@ e1000_setup_link(struct e1000_hw *hw)
+ return -E1000_ERR_EEPROM;
+ }
+ if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+- hw->fc = e1000_fc_none;
++ hw->fc = E1000_FC_NONE;
+ else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+ EEPROM_WORD0F_ASM_DIR)
+- hw->fc = e1000_fc_tx_pause;
++ hw->fc = E1000_FC_TX_PAUSE;
+ else
+- hw->fc = e1000_fc_full;
++ hw->fc = E1000_FC_FULL;
+ break;
+ }
+ }
+@@ -1033,11 +1140,11 @@ e1000_setup_link(struct e1000_hw *hw)
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+- if(hw->mac_type == e1000_82542_rev2_0)
+- hw->fc &= (~e1000_fc_tx_pause);
++ if (hw->mac_type == e1000_82542_rev2_0)
++ hw->fc &= (~E1000_FC_TX_PAUSE);
+
+- if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+- hw->fc &= (~e1000_fc_rx_pause);
++ if ((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
++ hw->fc &= (~E1000_FC_RX_PAUSE);
+
+ hw->original_fc = hw->fc;
+
+@@ -1051,12 +1158,12 @@ e1000_setup_link(struct e1000_hw *hw)
+ * or e1000_phy_setup() is called.
+ */
+ if (hw->mac_type == e1000_82543) {
+- ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
+- 1, &eeprom_data);
+- if (ret_val) {
+- DEBUGOUT("EEPROM Read Error\n");
+- return -E1000_ERR_EEPROM;
+- }
++ ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
++ 1, &eeprom_data);
++ if (ret_val) {
++ DEBUGOUT("EEPROM Read Error\n");
++ return -E1000_ERR_EEPROM;
++ }
+ ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+ SWDPIO__EXT_SHIFT);
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+@@ -1089,14 +1196,14 @@ e1000_setup_link(struct e1000_hw *hw)
+ * ability to transmit pause frames in not enabled, then these
+ * registers will be set to 0.
+ */
+- if(!(hw->fc & e1000_fc_tx_pause)) {
++ if (!(hw->fc & E1000_FC_TX_PAUSE)) {
+ E1000_WRITE_REG(hw, FCRTL, 0);
+ E1000_WRITE_REG(hw, FCRTH, 0);
+ } else {
+ /* We need to set up the Receive Threshold high and low water marks
+ * as well as (optionally) enabling the transmission of XON frames.
+ */
+- if(hw->fc_send_xon) {
++ if (hw->fc_send_xon) {
+ E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ } else {
+@@ -1136,18 +1243,18 @@ e1000_setup_fiber_serdes_link(struct e10
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572)
+ E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK);
+
+- /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
++ /* On adapters with a MAC newer than 82544, SWDP 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal. This applies to fiber media only.
+- * If we're on serdes media, adjust the output amplitude to value set in
+- * the EEPROM.
++ * If we're on serdes media, adjust the output amplitude to value
++ * set in the EEPROM.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+- if(hw->media_type == e1000_media_type_fiber)
++ if (hw->media_type == e1000_media_type_fiber)
+ signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
+
+ ret_val = e1000_adjust_serdes_amplitude(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Take the link out of reset */
+@@ -1155,7 +1262,7 @@ e1000_setup_fiber_serdes_link(struct e10
+
+ /* Adjust VCO speed to improve BER performance */
+ ret_val = e1000_set_vco_speed(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ e1000_config_collision_dist(hw);
+@@ -1176,11 +1283,11 @@ e1000_setup_fiber_serdes_link(struct e10
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (hw->fc) {
+- case e1000_fc_none:
++ case E1000_FC_NONE:
+ /* Flow control is completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+- case e1000_fc_rx_pause:
++ case E1000_FC_RX_PAUSE:
+ /* RX Flow control is enabled and TX Flow control is disabled by a
+ * software over-ride. Since there really isn't a way to advertise
+ * that we are capable of RX Pause ONLY, we will advertise that we
+@@ -1189,13 +1296,13 @@ e1000_setup_fiber_serdes_link(struct e10
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+- case e1000_fc_tx_pause:
++ case E1000_FC_TX_PAUSE:
+ /* TX Flow control is enabled, and RX Flow control is disabled, by a
+ * software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+- case e1000_fc_full:
++ case E1000_FC_FULL:
+ /* Flow control (both RX and TX) is enabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+@@ -1218,7 +1325,7 @@ e1000_setup_fiber_serdes_link(struct e10
+ E1000_WRITE_FLUSH(hw);
+
+ hw->txcw = txcw;
+- msec_delay(1);
++ msleep(1);
+
+ /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+ * indication in the Device Status Register. Time-out if a link isn't
+@@ -1226,15 +1333,15 @@ e1000_setup_fiber_serdes_link(struct e10
+ * less than 500 milliseconds even if the other end is doing it in SW).
+ * For internal serdes, we just assume a signal is present, then poll.
+ */
+- if(hw->media_type == e1000_media_type_internal_serdes ||
++ if (hw->media_type == e1000_media_type_internal_serdes ||
+ (E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+ DEBUGOUT("Looking for Link\n");
+- for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+- msec_delay(10);
++ for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
++ msleep(10);
+ status = E1000_READ_REG(hw, STATUS);
+- if(status & E1000_STATUS_LU) break;
++ if (status & E1000_STATUS_LU) break;
+ }
+- if(i == (LINK_UP_TIMEOUT / 10)) {
++ if (i == (LINK_UP_TIMEOUT / 10)) {
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ hw->autoneg_failed = 1;
+ /* AutoNeg failed to achieve a link, so we'll call
+@@ -1243,7 +1350,7 @@ e1000_setup_fiber_serdes_link(struct e10
+ * non-autonegotiating link partners.
+ */
+ ret_val = e1000_check_for_link(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error while checking for link\n");
+ return ret_val;
+ }
+@@ -1277,7 +1384,7 @@ e1000_copper_link_preconfig(struct e1000
+ * the PHY speed and duplex configuration is. In addition, we need to
+ * perform a hardware reset on the PHY to take it out of reset.
+ */
+- if(hw->mac_type > e1000_82543) {
++ if (hw->mac_type > e1000_82543) {
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+@@ -1285,13 +1392,13 @@ e1000_copper_link_preconfig(struct e1000
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ ret_val = e1000_phy_hw_reset(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+ /* Make sure we have a valid PHY */
+ ret_val = e1000_detect_gig_phy(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error, did not detect valid phy.\n");
+ return ret_val;
+ }
+@@ -1299,19 +1406,19 @@ e1000_copper_link_preconfig(struct e1000
+
+ /* Set PHY to class A mode (if necessary) */
+ ret_val = e1000_set_phy_mode(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if((hw->mac_type == e1000_82545_rev_3) ||
++ if ((hw->mac_type == e1000_82545_rev_3) ||
+ (hw->mac_type == e1000_82546_rev_3)) {
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ phy_data |= 0x00000008;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ }
+
+- if(hw->mac_type <= e1000_82543 ||
+- hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
+- hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2)
++ if (hw->mac_type <= e1000_82543 ||
++ hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
++ hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2)
+ hw->phy_reset_disable = FALSE;
+
+ return E1000_SUCCESS;
+@@ -1341,8 +1448,8 @@ e1000_copper_link_igp_setup(struct e1000
+ return ret_val;
+ }
+
+- /* Wait 10ms for MAC to configure PHY from eeprom settings */
+- msec_delay(15);
++ /* Wait 15ms for MAC to configure PHY from eeprom settings */
++ msleep(15);
+ if (hw->mac_type != e1000_ich8lan) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+@@ -1351,11 +1458,14 @@ e1000_copper_link_igp_setup(struct e1000
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+- /* disable lplu d3 during driver init */
+- ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+- if (ret_val) {
+- DEBUGOUT("Error Disabling LPLU D3\n");
+- return ret_val;
++ /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */
++ if (hw->phy_type == e1000_phy_igp) {
++ /* disable lplu d3 during driver init */
++ ret_val = e1000_set_d3_lplu_state(hw, FALSE);
++ if (ret_val) {
++ DEBUGOUT("Error Disabling LPLU D3\n");
++ return ret_val;
++ }
+ }
+
+ /* disable lplu d0 during driver init */
+@@ -1393,45 +1503,45 @@ e1000_copper_link_igp_setup(struct e1000
+ }
+ }
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* set auto-master slave resolution settings */
+- if(hw->autoneg) {
++ if (hw->autoneg) {
+ e1000_ms_type phy_ms_setting = hw->master_slave;
+
+- if(hw->ffe_config_state == e1000_ffe_config_active)
++ if (hw->ffe_config_state == e1000_ffe_config_active)
+ hw->ffe_config_state = e1000_ffe_config_enabled;
+
+- if(hw->dsp_config_state == e1000_dsp_config_activated)
++ if (hw->dsp_config_state == e1000_dsp_config_activated)
+ hw->dsp_config_state = e1000_dsp_config_enabled;
+
+ /* when autonegotiation advertisment is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default. */
+- if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
++ if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+- ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+- if(ret_val)
++ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
++ &phy_data);
++ if (ret_val)
+ return ret_val;
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+- ret_val = e1000_write_phy_reg(hw,
+- IGP01E1000_PHY_PORT_CONFIG,
+- phy_data);
+- if(ret_val)
++ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
++ phy_data);
++ if (ret_val)
+ return ret_val;
+ /* Set auto Master/Slave resolution process */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+@@ -1455,7 +1565,7 @@ e1000_copper_link_igp_setup(struct e1000
+ break;
+ }
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+@@ -1476,12 +1586,12 @@ e1000_copper_link_ggp_setup(struct e1000
+
+ DEBUGFUNC("e1000_copper_link_ggp_setup");
+
+- if(!hw->phy_reset_disable) {
++ if (!hw->phy_reset_disable) {
+
+ /* Enable CRS on TX for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+@@ -1490,7 +1600,7 @@ e1000_copper_link_ggp_setup(struct e1000
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Options:
+@@ -1501,7 +1611,7 @@ e1000_copper_link_ggp_setup(struct e1000
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+@@ -1526,11 +1636,11 @@ e1000_copper_link_ggp_setup(struct e1000
+ * 1 - Enabled
+ */
+ phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+- if(hw->disable_polarity_correction == 1)
++ if (hw->disable_polarity_correction == 1)
+ phy_data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* SW Reset the PHY so all changes take effect */
+@@ -1586,9 +1696,9 @@ e1000_copper_link_ggp_setup(struct e1000
+ return ret_val;
+
+ phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+-
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ phy_data);
++
+ if (ret_val)
+ return ret_val;
+ }
+@@ -1623,12 +1733,12 @@ e1000_copper_link_mgp_setup(struct e1000
+
+ DEBUGFUNC("e1000_copper_link_mgp_setup");
+
+- if(hw->phy_reset_disable)
++ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+@@ -1665,7 +1775,7 @@ e1000_copper_link_mgp_setup(struct e1000
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+- if(hw->disable_polarity_correction == 1)
++ if (hw->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+@@ -1705,7 +1815,7 @@ e1000_copper_link_mgp_setup(struct e1000
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+@@ -1735,7 +1845,7 @@ e1000_copper_link_autoneg(struct e1000_h
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+- if(hw->autoneg_advertised == 0)
++ if (hw->autoneg_advertised == 0)
+ hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /* IFE phy only supports 10/100 */
+@@ -1744,7 +1854,7 @@ e1000_copper_link_autoneg(struct e1000_h
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+@@ -1754,20 +1864,20 @@ e1000_copper_link_autoneg(struct e1000_h
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+- if(hw->wait_autoneg_complete) {
++ if (hw->wait_autoneg_complete) {
+ ret_val = e1000_wait_autoneg(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error while waiting for autoneg to complete\n");
+ return ret_val;
+ }
+@@ -1778,7 +1888,6 @@ e1000_copper_link_autoneg(struct e1000_h
+ return E1000_SUCCESS;
+ }
+
+-
+ /******************************************************************************
+ * Config the MAC and the PHY after link is up.
+ * 1) Set up the MAC to the current PHY speed/duplex
+@@ -1797,25 +1906,25 @@ e1000_copper_link_postconfig(struct e100
+ int32_t ret_val;
+ DEBUGFUNC("e1000_copper_link_postconfig");
+
+- if(hw->mac_type >= e1000_82544) {
++ if (hw->mac_type >= e1000_82544) {
+ e1000_config_collision_dist(hw);
+ } else {
+ ret_val = e1000_config_mac_to_phy(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+ ret_val = e1000_config_fc_after_link_up(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Configuring Flow Control\n");
+ return ret_val;
+ }
+
+ /* Config DSP to improve Giga link quality */
+- if(hw->phy_type == e1000_phy_igp) {
++ if (hw->phy_type == e1000_phy_igp) {
+ ret_val = e1000_config_dsp_after_link_change(hw, TRUE);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Configuring DSP after link up\n");
+ return ret_val;
+ }
+@@ -1861,7 +1970,7 @@ e1000_setup_copper_link(struct e1000_hw
+
+ /* Check if it is a valid PHY and set PHY mode if necessary. */
+ ret_val = e1000_copper_link_preconfig(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ switch (hw->mac_type) {
+@@ -1882,30 +1991,30 @@ e1000_setup_copper_link(struct e1000_hw
+ hw->phy_type == e1000_phy_igp_3 ||
+ hw->phy_type == e1000_phy_igp_2) {
+ ret_val = e1000_copper_link_igp_setup(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else if (hw->phy_type == e1000_phy_m88) {
+ ret_val = e1000_copper_link_mgp_setup(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ ret_val = e1000_copper_link_ggp_setup(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+- if(hw->autoneg) {
++ if (hw->autoneg) {
+ /* Setup autoneg and flow control advertisement
+ * and perform autonegotiation */
+ ret_val = e1000_copper_link_autoneg(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else {
+ /* PHY will be set to 10H, 10F, 100H,or 100F
+ * depending on value from forced_speed_duplex. */
+ DEBUGOUT("Forcing speed and duplex\n");
+ ret_val = e1000_phy_force_speed_duplex(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Forcing Speed and Duplex\n");
+ return ret_val;
+ }
+@@ -1914,18 +2023,18 @@ e1000_setup_copper_link(struct e1000_hw
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+- for(i = 0; i < 10; i++) {
++ for (i = 0; i < 10; i++) {
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(phy_data & MII_SR_LINK_STATUS) {
++ if (phy_data & MII_SR_LINK_STATUS) {
+ /* Config the MAC and PHY after link is up */
+ ret_val = e1000_copper_link_postconfig(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ DEBUGOUT("Valid link established!!!\n");
+@@ -2027,7 +2136,7 @@ e1000_phy_setup_autoneg(struct e1000_hw
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ if (hw->phy_type != e1000_phy_ife) {
+@@ -2055,36 +2164,36 @@ e1000_phy_setup_autoneg(struct e1000_hw
+ DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+- if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
++ if (hw->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+- if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
++ if (hw->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+- if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
++ if (hw->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+- if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
++ if (hw->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+- if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
++ if (hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+ }
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+- if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
++ if (hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ if (hw->phy_type == e1000_phy_ife) {
+@@ -2109,13 +2218,13 @@ e1000_phy_setup_autoneg(struct e1000_hw
+ * in the EEPROM is used.
+ */
+ switch (hw->fc) {
+- case e1000_fc_none: /* 0 */
++ case E1000_FC_NONE: /* 0 */
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+- case e1000_fc_rx_pause: /* 1 */
++ case E1000_FC_RX_PAUSE: /* 1 */
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+@@ -2127,14 +2236,14 @@ e1000_phy_setup_autoneg(struct e1000_hw
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+- case e1000_fc_tx_pause: /* 2 */
++ case E1000_FC_TX_PAUSE: /* 2 */
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+- case e1000_fc_full: /* 3 */
++ case E1000_FC_FULL: /* 3 */
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+@@ -2146,7 +2255,7 @@ e1000_phy_setup_autoneg(struct e1000_hw
+ }
+
+ ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+@@ -2178,7 +2287,7 @@ e1000_phy_force_speed_duplex(struct e100
+ DEBUGFUNC("e1000_phy_force_speed_duplex");
+
+ /* Turn off Flow control if we are forcing speed and duplex. */
+- hw->fc = e1000_fc_none;
++ hw->fc = E1000_FC_NONE;
+
+ DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+@@ -2194,7 +2303,7 @@ e1000_phy_force_speed_duplex(struct e100
+
+ /* Read the MII Control Register. */
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* We need to disable autoneg in order to force link and duplex. */
+@@ -2202,8 +2311,8 @@ e1000_phy_force_speed_duplex(struct e100
+ mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Are we forcing Full or Half Duplex? */
+- if(hw->forced_speed_duplex == e1000_100_full ||
+- hw->forced_speed_duplex == e1000_10_full) {
++ if (hw->forced_speed_duplex == e1000_100_full ||
++ hw->forced_speed_duplex == e1000_10_full) {
+ /* We want to force full duplex so we SET the full duplex bits in the
+ * Device and MII Control Registers.
+ */
+@@ -2220,7 +2329,7 @@ e1000_phy_force_speed_duplex(struct e100
+ }
+
+ /* Are we forcing 100Mbps??? */
+- if(hw->forced_speed_duplex == e1000_100_full ||
++ if (hw->forced_speed_duplex == e1000_100_full ||
+ hw->forced_speed_duplex == e1000_100_half) {
+ /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+ ctrl |= E1000_CTRL_SPD_100;
+@@ -2243,7 +2352,7 @@ e1000_phy_force_speed_duplex(struct e100
+ if ((hw->phy_type == e1000_phy_m88) ||
+ (hw->phy_type == e1000_phy_gg82563)) {
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+@@ -2251,7 +2360,7 @@ e1000_phy_force_speed_duplex(struct e100
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+@@ -2275,20 +2384,20 @@ e1000_phy_force_speed_duplex(struct e100
+ * forced whenever speed or duplex are forced.
+ */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+ /* Write back the modified PHY MII control register. */
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+@@ -2300,50 +2409,50 @@ e1000_phy_force_speed_duplex(struct e100
+ * only if the user has set wait_autoneg_complete to 1, which is
+ * the default.
+ */
+- if(hw->wait_autoneg_complete) {
++ if (hw->wait_autoneg_complete) {
+ /* We will wait for autoneg to complete. */
+ DEBUGOUT("Waiting for forced speed/duplex link.\n");
+ mii_status_reg = 0;
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+- for(i = PHY_FORCE_TIME; i > 0; i--) {
++ for (i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(mii_status_reg & MII_SR_LINK_STATUS) break;
+- msec_delay(100);
++ if (mii_status_reg & MII_SR_LINK_STATUS) break;
++ msleep(100);
+ }
+- if((i == 0) &&
++ if ((i == 0) &&
+ ((hw->phy_type == e1000_phy_m88) ||
+ (hw->phy_type == e1000_phy_gg82563))) {
+ /* We didn't get link. Reset the DSP and wait again for link. */
+ ret_val = e1000_phy_reset_dsp(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error Resetting PHY DSP\n");
+ return ret_val;
+ }
+ }
+ /* This loop will early-out if the link condition has been met. */
+- for(i = PHY_FORCE_TIME; i > 0; i--) {
+- if(mii_status_reg & MII_SR_LINK_STATUS) break;
+- msec_delay(100);
++ for (i = PHY_FORCE_TIME; i > 0; i--) {
++ if (mii_status_reg & MII_SR_LINK_STATUS) break;
++ msleep(100);
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+ }
+@@ -2354,32 +2463,31 @@ e1000_phy_force_speed_duplex(struct e100
+ * defaults back to a 2.5MHz clock when the PHY is reset.
+ */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* In addition, because of the s/w reset above, we need to enable CRS on
+ * TX. This must be set for both full and half duplex operation.
+ */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
+- (!hw->autoneg) &&
+- (hw->forced_speed_duplex == e1000_10_full ||
+- hw->forced_speed_duplex == e1000_10_half)) {
++ if ((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
++ (!hw->autoneg) && (hw->forced_speed_duplex == e1000_10_full ||
++ hw->forced_speed_duplex == e1000_10_half)) {
+ ret_val = e1000_polarity_reversal_workaround(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+@@ -2470,10 +2578,10 @@ e1000_config_mac_to_phy(struct e1000_hw
+ * registers depending on negotiated values.
+ */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(phy_data & M88E1000_PSSR_DPLX)
++ if (phy_data & M88E1000_PSSR_DPLX)
+ ctrl |= E1000_CTRL_FD;
+ else
+ ctrl &= ~E1000_CTRL_FD;
+@@ -2483,9 +2591,9 @@ e1000_config_mac_to_phy(struct e1000_hw
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+- if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
++ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+- else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
++ else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+
+ /* Write the configured values back to the Device Control Reg. */
+@@ -2533,18 +2641,18 @@ e1000_force_mac_fc(struct e1000_hw *hw)
+ */
+
+ switch (hw->fc) {
+- case e1000_fc_none:
++ case E1000_FC_NONE:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+- case e1000_fc_rx_pause:
++ case E1000_FC_RX_PAUSE:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+- case e1000_fc_tx_pause:
++ case E1000_FC_TX_PAUSE:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+- case e1000_fc_full:
++ case E1000_FC_FULL:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+@@ -2553,7 +2661,7 @@ e1000_force_mac_fc(struct e1000_hw *hw)
+ }
+
+ /* Disable TX Flow Control for 82542 (rev 2.0) */
+- if(hw->mac_type == e1000_82542_rev2_0)
++ if (hw->mac_type == e1000_82542_rev2_0)
+ ctrl &= (~E1000_CTRL_TFCE);
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+@@ -2587,11 +2695,12 @@ e1000_config_fc_after_link_up(struct e10
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+- if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+- ((hw->media_type == e1000_media_type_internal_serdes) && (hw->autoneg_failed)) ||
+- ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
++ if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
++ ((hw->media_type == e1000_media_type_internal_serdes) &&
++ (hw->autoneg_failed)) ||
++ ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+ ret_val = e1000_force_mac_fc(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+@@ -2602,19 +2711,19 @@ e1000_config_fc_after_link_up(struct e10
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+- if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
++ if ((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
++ if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement Register
+ * (Address 4) and the Auto_Negotiation Base Page Ability
+@@ -2623,11 +2732,11 @@ e1000_config_fc_after_link_up(struct e10
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
+ &mii_nway_adv_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+@@ -2642,14 +2751,14 @@ e1000_config_fc_after_link_up(struct e10
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+- * 0 | 0 | DC | DC | e1000_fc_none
+- * 0 | 1 | 0 | DC | e1000_fc_none
+- * 0 | 1 | 1 | 0 | e1000_fc_none
+- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+- * 1 | 0 | 0 | DC | e1000_fc_none
+- * 1 | DC | 1 | DC | e1000_fc_full
+- * 1 | 1 | 0 | 0 | e1000_fc_none
+- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
++ * 0 | 0 | DC | DC | E1000_FC_NONE
++ * 0 | 1 | 0 | DC | E1000_FC_NONE
++ * 0 | 1 | 1 | 0 | E1000_FC_NONE
++ * 0 | 1 | 1 | 1 | E1000_FC_TX_PAUSE
++ * 1 | 0 | 0 | DC | E1000_FC_NONE
++ * 1 | DC | 1 | DC | E1000_FC_FULL
++ * 1 | 1 | 0 | 0 | E1000_FC_NONE
++ * 1 | 1 | 0 | 1 | E1000_FC_RX_PAUSE
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+@@ -2661,22 +2770,22 @@ e1000_config_fc_after_link_up(struct e10
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+- * 1 | DC | 1 | DC | e1000_fc_full
++ * 1 | DC | 1 | DC | E1000_FC_FULL
+ *
+ */
+- if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
++ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
++ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+- if(hw->original_fc == e1000_fc_full) {
+- hw->fc = e1000_fc_full;
++ if (hw->original_fc == E1000_FC_FULL) {
++ hw->fc = E1000_FC_FULL;
+ DEBUGOUT("Flow Control = FULL.\n");
+ } else {
+- hw->fc = e1000_fc_rx_pause;
++ hw->fc = E1000_FC_RX_PAUSE;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
+ }
+ }
+@@ -2685,14 +2794,14 @@ e1000_config_fc_after_link_up(struct e10
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
++ * 0 | 1 | 1 | 1 | E1000_FC_TX_PAUSE
+ *
+ */
+- else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+- hw->fc = e1000_fc_tx_pause;
++ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
++ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
++ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
++ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
++ hw->fc = E1000_FC_TX_PAUSE;
+ DEBUGOUT("Flow Control = TX PAUSE frames only.\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+@@ -2700,14 +2809,14 @@ e1000_config_fc_after_link_up(struct e10
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
++ * 1 | 1 | 0 | 1 | E1000_FC_RX_PAUSE
+ *
+ */
+- else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+- !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+- hw->fc = e1000_fc_rx_pause;
++ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
++ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
++ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
++ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
++ hw->fc = E1000_FC_RX_PAUSE;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+@@ -2730,13 +2839,13 @@ e1000_config_fc_after_link_up(struct e10
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+- else if((hw->original_fc == e1000_fc_none ||
+- hw->original_fc == e1000_fc_tx_pause) ||
+- hw->fc_strict_ieee) {
+- hw->fc = e1000_fc_none;
++ else if ((hw->original_fc == E1000_FC_NONE ||
++ hw->original_fc == E1000_FC_TX_PAUSE) ||
++ hw->fc_strict_ieee) {
++ hw->fc = E1000_FC_NONE;
+ DEBUGOUT("Flow Control = NONE.\n");
+ } else {
+- hw->fc = e1000_fc_rx_pause;
++ hw->fc = E1000_FC_RX_PAUSE;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
+ }
+
+@@ -2745,19 +2854,19 @@ e1000_config_fc_after_link_up(struct e10
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ return ret_val;
+ }
+
+- if(duplex == HALF_DUPLEX)
+- hw->fc = e1000_fc_none;
++ if (duplex == HALF_DUPLEX)
++ hw->fc = E1000_FC_NONE;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000_force_mac_fc(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+@@ -2796,13 +2905,13 @@ e1000_check_for_link(struct e1000_hw *hw
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal. This applies to fiber media only.
+ */
+- if((hw->media_type == e1000_media_type_fiber) ||
+- (hw->media_type == e1000_media_type_internal_serdes)) {
++ if ((hw->media_type == e1000_media_type_fiber) ||
++ (hw->media_type == e1000_media_type_internal_serdes)) {
+ rxcw = E1000_READ_REG(hw, RXCW);
+
+- if(hw->media_type == e1000_media_type_fiber) {
++ if (hw->media_type == e1000_media_type_fiber) {
+ signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
+- if(status & E1000_STATUS_LU)
++ if (status & E1000_STATUS_LU)
+ hw->get_link_status = FALSE;
+ }
+ }
+@@ -2813,20 +2922,20 @@ e1000_check_for_link(struct e1000_hw *hw
+ * receive a Link Status Change interrupt or we have Rx Sequence
+ * Errors.
+ */
+- if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
++ if ((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ * Read the register twice since the link bit is sticky.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(phy_data & MII_SR_LINK_STATUS) {
++ if (phy_data & MII_SR_LINK_STATUS) {
+ hw->get_link_status = FALSE;
+ /* Check if there was DownShift, must be checked immediately after
+ * link-up */
+@@ -2840,10 +2949,10 @@ e1000_check_for_link(struct e1000_hw *hw
+ * happen due to the execution of this workaround.
+ */
+
+- if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
+- (!hw->autoneg) &&
+- (hw->forced_speed_duplex == e1000_10_full ||
+- hw->forced_speed_duplex == e1000_10_half)) {
++ if ((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
++ (!hw->autoneg) &&
++ (hw->forced_speed_duplex == e1000_10_full ||
++ hw->forced_speed_duplex == e1000_10_half)) {
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+ ret_val = e1000_polarity_reversal_workaround(hw);
+ icr = E1000_READ_REG(hw, ICR);
+@@ -2860,7 +2969,7 @@ e1000_check_for_link(struct e1000_hw *hw
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+- if(!hw->autoneg) return -E1000_ERR_CONFIG;
++ if (!hw->autoneg) return -E1000_ERR_CONFIG;
+
+ /* optimize the dsp settings for the igp phy */
+ e1000_config_dsp_after_link_change(hw, TRUE);
+@@ -2873,11 +2982,11 @@ e1000_check_for_link(struct e1000_hw *hw
+ * speed/duplex on the MAC to the current PHY speed/duplex
+ * settings.
+ */
+- if(hw->mac_type >= e1000_82544)
++ if (hw->mac_type >= e1000_82544)
+ e1000_config_collision_dist(hw);
+ else {
+ ret_val = e1000_config_mac_to_phy(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+@@ -2888,7 +2997,7 @@ e1000_check_for_link(struct e1000_hw *hw
+ * have had to re-autoneg with a different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+@@ -2900,7 +3009,7 @@ e1000_check_for_link(struct e1000_hw *hw
+ * at gigabit speed, then TBI compatibility is not needed. If we are
+ * at gigabit speed, we turn on TBI compatibility.
+ */
+- if(hw->tbi_compatibility_en) {
++ if (hw->tbi_compatibility_en) {
+ uint16_t speed, duplex;
+ ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val) {
+@@ -2911,7 +3020,7 @@ e1000_check_for_link(struct e1000_hw *hw
+ /* If link speed is not set to gigabit speed, we do not need
+ * to enable TBI compatibility.
+ */
+- if(hw->tbi_compatibility_on) {
++ if (hw->tbi_compatibility_on) {
+ /* If we previously were in the mode, turn it off. */
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl &= ~E1000_RCTL_SBP;
+@@ -2924,7 +3033,7 @@ e1000_check_for_link(struct e1000_hw *hw
+ * packets. Some frames have an additional byte on the end and
+ * will look like CRC errors to to the hardware.
+ */
+- if(!hw->tbi_compatibility_on) {
++ if (!hw->tbi_compatibility_on) {
+ hw->tbi_compatibility_on = TRUE;
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl |= E1000_RCTL_SBP;
+@@ -2940,12 +3049,12 @@ e1000_check_for_link(struct e1000_hw *hw
+ * auto-negotiation time to complete, in case the cable was just plugged
+ * in. The autoneg_failed flag does this.
+ */
+- else if((((hw->media_type == e1000_media_type_fiber) &&
++ else if ((((hw->media_type == e1000_media_type_fiber) &&
+ ((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
+- (hw->media_type == e1000_media_type_internal_serdes)) &&
+- (!(status & E1000_STATUS_LU)) &&
+- (!(rxcw & E1000_RXCW_C))) {
+- if(hw->autoneg_failed == 0) {
++ (hw->media_type == e1000_media_type_internal_serdes)) &&
++ (!(status & E1000_STATUS_LU)) &&
++ (!(rxcw & E1000_RXCW_C))) {
++ if (hw->autoneg_failed == 0) {
+ hw->autoneg_failed = 1;
+ return 0;
+ }
+@@ -2961,7 +3070,7 @@ e1000_check_for_link(struct e1000_hw *hw
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up(hw);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+@@ -2971,9 +3080,9 @@ e1000_check_for_link(struct e1000_hw *hw
+ * Device Control register in an attempt to auto-negotiate with our link
+ * partner.
+ */
+- else if(((hw->media_type == e1000_media_type_fiber) ||
+- (hw->media_type == e1000_media_type_internal_serdes)) &&
+- (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
++ else if (((hw->media_type == e1000_media_type_fiber) ||
++ (hw->media_type == e1000_media_type_internal_serdes)) &&
++ (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ E1000_WRITE_REG(hw, TXCW, hw->txcw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+@@ -2983,12 +3092,12 @@ e1000_check_for_link(struct e1000_hw *hw
+ /* If we force link for non-auto-negotiation switch, check link status
+ * based on MAC synchronization for internal serdes media type.
+ */
+- else if((hw->media_type == e1000_media_type_internal_serdes) &&
+- !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
++ else if ((hw->media_type == e1000_media_type_internal_serdes) &&
++ !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+ /* SYNCH bit and IV bit are sticky. */
+ udelay(10);
+- if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) {
+- if(!(rxcw & E1000_RXCW_IV)) {
++ if (E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) {
++ if (!(rxcw & E1000_RXCW_IV)) {
+ hw->serdes_link_down = FALSE;
+ DEBUGOUT("SERDES: Link is up.\n");
+ }
+@@ -2997,8 +3106,8 @@ e1000_check_for_link(struct e1000_hw *hw
+ DEBUGOUT("SERDES: Link is down.\n");
+ }
+ }
+- if((hw->media_type == e1000_media_type_internal_serdes) &&
+- (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
++ if ((hw->media_type == e1000_media_type_internal_serdes) &&
++ (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+ hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS));
+ }
+ return E1000_SUCCESS;
+@@ -3022,12 +3131,12 @@ e1000_get_speed_and_duplex(struct e1000_
+
+ DEBUGFUNC("e1000_get_speed_and_duplex");
+
+- if(hw->mac_type >= e1000_82543) {
++ if (hw->mac_type >= e1000_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+- if(status & E1000_STATUS_SPEED_1000) {
++ if (status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+- } else if(status & E1000_STATUS_SPEED_100) {
++ } else if (status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+@@ -3035,7 +3144,7 @@ e1000_get_speed_and_duplex(struct e1000_
+ DEBUGOUT("10 Mbs, ");
+ }
+
+- if(status & E1000_STATUS_FD) {
++ if (status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ } else {
+@@ -3052,18 +3161,18 @@ e1000_get_speed_and_duplex(struct e1000_
+ * if it is operating at half duplex. Here we set the duplex settings to
+ * match the duplex in the link partner's capabilities.
+ */
+- if(hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
++ if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
++ if (!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+ *duplex = HALF_DUPLEX;
+ else {
+ ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
++ if ((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
+ (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+ *duplex = HALF_DUPLEX;
+ }
+@@ -3104,20 +3213,20 @@ e1000_wait_autoneg(struct e1000_hw *hw)
+ DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+- for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
++ for (i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- if(phy_data & MII_SR_AUTONEG_COMPLETE) {
++ if (phy_data & MII_SR_AUTONEG_COMPLETE) {
+ return E1000_SUCCESS;
+ }
+- msec_delay(100);
++ msleep(100);
+ }
+ return E1000_SUCCESS;
+ }
+@@ -3187,14 +3296,16 @@ e1000_shift_out_mdi_bits(struct e1000_hw
+ /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+ ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+- while(mask) {
++ while (mask) {
+ /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+ * then raising and lowering the Management Data Clock. A "0" is
+ * shifted out to the PHY by setting the MDIO bit to "0" and then
+ * raising and lowering the clock.
+ */
+- if(data & mask) ctrl |= E1000_CTRL_MDIO;
+- else ctrl &= ~E1000_CTRL_MDIO;
++ if (data & mask)
++ ctrl |= E1000_CTRL_MDIO;
++ else
++ ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+@@ -3245,12 +3356,13 @@ e1000_shift_in_mdi_bits(struct e1000_hw
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+- for(data = 0, i = 0; i < 16; i++) {
++ for (data = 0, i = 0; i < 16; i++) {
+ data = data << 1;
+ e1000_raise_mdi_clk(hw, &ctrl);
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Check to see if we shifted in a "1". */
+- if(ctrl & E1000_CTRL_MDIO) data |= 1;
++ if (ctrl & E1000_CTRL_MDIO)
++ data |= 1;
+ e1000_lower_mdi_clk(hw, &ctrl);
+ }
+
+@@ -3276,7 +3388,7 @@ e1000_swfw_sync_acquire(struct e1000_hw
+ if (!hw->swfw_sync_present)
+ return e1000_get_hw_eeprom_semaphore(hw);
+
+- while(timeout) {
++ while (timeout) {
+ if (e1000_get_hw_eeprom_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+@@ -3288,7 +3400,7 @@ e1000_swfw_sync_acquire(struct e1000_hw
+ /* firmware currently using resource (fwmask) */
+ /* or other software thread currently using resource (swmask) */
+ e1000_put_hw_eeprom_semaphore(hw);
+- msec_delay_irq(5);
++ mdelay(5);
+ timeout--;
+ }
+
+@@ -3365,7 +3477,7 @@ e1000_read_phy_reg(struct e1000_hw *hw,
+ (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+ ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (uint16_t)reg_addr);
+- if(ret_val) {
++ if (ret_val) {
+ e1000_swfw_sync_release(hw, swfw);
+ return ret_val;
+ }
+@@ -3399,9 +3511,8 @@ e1000_read_phy_reg(struct e1000_hw *hw,
+ return ret_val;
+ }
+
+-int32_t
+-e1000_read_phy_reg_ex(struct e1000_hw *hw,
+- uint32_t reg_addr,
++static int32_t
++e1000_read_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t *phy_data)
+ {
+ uint32_t i;
+@@ -3410,12 +3521,12 @@ e1000_read_phy_reg_ex(struct e1000_hw *h
+
+ DEBUGFUNC("e1000_read_phy_reg_ex");
+
+- if(reg_addr > MAX_PHY_REG_ADDRESS) {
++ if (reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+- if(hw->mac_type > e1000_82543) {
++ if (hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, and register address in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+@@ -3427,16 +3538,16 @@ e1000_read_phy_reg_ex(struct e1000_hw *h
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+- for(i = 0; i < 64; i++) {
++ for (i = 0; i < 64; i++) {
+ udelay(50);
+ mdic = E1000_READ_REG(hw, MDIC);
+- if(mdic & E1000_MDIC_READY) break;
++ if (mdic & E1000_MDIC_READY) break;
+ }
+- if(!(mdic & E1000_MDIC_READY)) {
++ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+- if(mdic & E1000_MDIC_ERROR) {
++ if (mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+@@ -3481,8 +3592,7 @@ e1000_read_phy_reg_ex(struct e1000_hw *h
+ * data - data to write to the PHY
+ ******************************************************************************/
+ int32_t
+-e1000_write_phy_reg(struct e1000_hw *hw,
+- uint32_t reg_addr,
++e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t phy_data)
+ {
+ uint32_t ret_val;
+@@ -3505,7 +3615,7 @@ e1000_write_phy_reg(struct e1000_hw *hw,
+ (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+ ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (uint16_t)reg_addr);
+- if(ret_val) {
++ if (ret_val) {
+ e1000_swfw_sync_release(hw, swfw);
+ return ret_val;
+ }
+@@ -3539,10 +3649,9 @@ e1000_write_phy_reg(struct e1000_hw *hw,
+ return ret_val;
+ }
+
+-int32_t
+-e1000_write_phy_reg_ex(struct e1000_hw *hw,
+- uint32_t reg_addr,
+- uint16_t phy_data)
++static int32_t
++e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
++ uint16_t phy_data)
+ {
+ uint32_t i;
+ uint32_t mdic = 0;
+@@ -3550,12 +3659,12 @@ e1000_write_phy_reg_ex(struct e1000_hw *
+
+ DEBUGFUNC("e1000_write_phy_reg_ex");
+
+- if(reg_addr > MAX_PHY_REG_ADDRESS) {
++ if (reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+- if(hw->mac_type > e1000_82543) {
++ if (hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, register address, and data intended
+ * for the PHY register in the MDI Control register. The MAC will take
+ * care of interfacing with the PHY to send the desired data.
+@@ -3568,12 +3677,12 @@ e1000_write_phy_reg_ex(struct e1000_hw *
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+- for(i = 0; i < 640; i++) {
++ for (i = 0; i < 641; i++) {
+ udelay(5);
+ mdic = E1000_READ_REG(hw, MDIC);
+- if(mdic & E1000_MDIC_READY) break;
++ if (mdic & E1000_MDIC_READY) break;
+ }
+- if(!(mdic & E1000_MDIC_READY)) {
++ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+@@ -3685,7 +3794,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
+
+ DEBUGOUT("Resetting Phy...\n");
+
+- if(hw->mac_type > e1000_82543) {
++ if (hw->mac_type > e1000_82543) {
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+@@ -3693,7 +3802,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw)) {
+- e1000_release_software_semaphore(hw);
++ DEBUGOUT("Unable to acquire swfw sync\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+ /* Read the device control register and assert the E1000_CTRL_PHY_RST
+@@ -3707,7 +3816,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
+ E1000_WRITE_FLUSH(hw);
+
+ if (hw->mac_type < e1000_82571)
+- msec_delay(10);
++ msleep(10);
+ else
+ udelay(100);
+
+@@ -3715,7 +3824,8 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
+ E1000_WRITE_FLUSH(hw);
+
+ if (hw->mac_type >= e1000_82571)
+- msec_delay_irq(10);
++ mdelay(10);
++
+ e1000_swfw_sync_release(hw, swfw);
+ } else {
+ /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+@@ -3726,14 +3836,14 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+- msec_delay(10);
++ msleep(10);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+ udelay(150);
+
+- if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
++ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+@@ -3743,14 +3853,13 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
+
+ /* Wait for FW to finish PHY configuration. */
+ ret_val = e1000_get_phy_cfg_done(hw);
++ if (ret_val != E1000_SUCCESS)
++ return ret_val;
+ e1000_release_software_semaphore(hw);
+
+- if ((hw->mac_type == e1000_ich8lan) &&
+- (hw->phy_type == e1000_phy_igp_3)) {
+- ret_val = e1000_init_lcd_from_nvm(hw);
+- if (ret_val)
+- return ret_val;
+- }
++ if ((hw->mac_type == e1000_ich8lan) && (hw->phy_type == e1000_phy_igp_3))
++ ret_val = e1000_init_lcd_from_nvm(hw);
++
+ return ret_val;
+ }
+
+@@ -3775,31 +3884,30 @@ e1000_phy_reset(struct e1000_hw *hw)
+ if (ret_val)
+ return E1000_SUCCESS;
+
+- switch (hw->mac_type) {
+- case e1000_82541_rev_2:
+- case e1000_82571:
+- case e1000_82572:
+- case e1000_ich8lan:
++ switch (hw->phy_type) {
++ case e1000_phy_igp:
++ case e1000_phy_igp_2:
++ case e1000_phy_igp_3:
++ case e1000_phy_ife:
+ ret_val = e1000_phy_hw_reset(hw);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+-
+ break;
+ default:
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= MII_CR_RESET;
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+ break;
+ }
+
+- if(hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
++ if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
+ e1000_phy_init_script(hw);
+
+ return E1000_SUCCESS;
+@@ -3877,8 +3985,8 @@ e1000_kumeran_lock_loss_workaround(struc
+ if (hw->kmrn_lock_loss_workaround_disabled)
+ return E1000_SUCCESS;
+
+- /* Make sure link is up before proceeding. If not just return.
+- * Attempting this while link is negotiating fouls up link
++ /* Make sure link is up before proceeding. If not just return.
++ * Attempting this while link is negotiating fouled up link
+ * stability */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+@@ -3900,7 +4008,7 @@ e1000_kumeran_lock_loss_workaround(struc
+
+ /* Issue PHY reset */
+ e1000_phy_hw_reset(hw);
+- msec_delay_irq(5);
++ mdelay(5);
+ }
+ /* Disable GigE link negotiation */
+ reg = E1000_READ_REG(hw, PHY_CTRL);
+@@ -3919,7 +4027,7 @@ e1000_kumeran_lock_loss_workaround(struc
+ *
+ * hw - Struct containing variables accessed by shared code
+ ******************************************************************************/
+-int32_t
++static int32_t
+ e1000_detect_gig_phy(struct e1000_hw *hw)
+ {
+ int32_t phy_init_status, ret_val;
+@@ -3928,6 +4036,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw
+
+ DEBUGFUNC("e1000_detect_gig_phy");
+
++ if (hw->phy_id != 0)
++ return E1000_SUCCESS;
++
+ /* The 82571 firmware may still be configuring the PHY. In this
+ * case, we cannot access the PHY until the configuration is done. So
+ * we explicitly set the PHY values. */
+@@ -3955,34 +4066,34 @@ e1000_detect_gig_phy(struct e1000_hw *hw
+ hw->phy_id = (uint32_t) (phy_id_high << 16);
+ udelay(20);
+ ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+ hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82543:
+- if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
++ if (hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+ break;
+ case e1000_82544:
+- if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
++ if (hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+ break;
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+- if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
++ if (hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+ break;
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+- if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
++ if (hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+ break;
+ case e1000_82573:
+- if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
++ if (hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
+ break;
+ case e1000_80003es2lan:
+ if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE;
+@@ -4021,14 +4132,14 @@ e1000_phy_reset_dsp(struct e1000_hw *hw)
+ do {
+ if (hw->phy_type != e1000_phy_gg82563) {
+ ret_val = e1000_write_phy_reg(hw, 29, 0x001d);
+- if(ret_val) break;
++ if (ret_val) break;
+ }
+ ret_val = e1000_write_phy_reg(hw, 30, 0x00c1);
+- if(ret_val) break;
++ if (ret_val) break;
+ ret_val = e1000_write_phy_reg(hw, 30, 0x0000);
+- if(ret_val) break;
++ if (ret_val) break;
+ ret_val = E1000_SUCCESS;
+- } while(0);
++ } while (0);
+
+ return ret_val;
+ }
+@@ -4044,7 +4155,8 @@ e1000_phy_igp_get_info(struct e1000_hw *
+ struct e1000_phy_info *phy_info)
+ {
+ int32_t ret_val;
+- uint16_t phy_data, polarity, min_length, max_length, average;
++ uint16_t phy_data, min_length, max_length, average;
++ e1000_rev_polarity polarity;
+
+ DEBUGFUNC("e1000_phy_igp_get_info");
+
+@@ -4060,45 +4172,47 @@ e1000_phy_igp_get_info(struct e1000_hw *
+
+ /* Check polarity status */
+ ret_val = e1000_check_polarity(hw, &polarity);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_info->cable_polarity = polarity;
+
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
+- IGP01E1000_PSSR_MDIX_SHIFT;
++ phy_info->mdix_mode = (e1000_auto_x_mode)((phy_data & IGP01E1000_PSSR_MDIX) >>
++ IGP01E1000_PSSR_MDIX_SHIFT);
+
+- if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
++ if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+- SR_1000T_LOCAL_RX_STATUS_SHIFT;
+- phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+- SR_1000T_REMOTE_RX_STATUS_SHIFT;
++ phy_info->local_rx = ((phy_data & SR_1000T_LOCAL_RX_STATUS) >>
++ SR_1000T_LOCAL_RX_STATUS_SHIFT) ?
++ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
++ phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
++ SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
++ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
+
+ /* Get cable length */
+ ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Translate to old method */
+ average = (max_length + min_length) / 2;
+
+- if(average <= e1000_igp_cable_length_50)
++ if (average <= e1000_igp_cable_length_50)
+ phy_info->cable_length = e1000_cable_length_50;
+- else if(average <= e1000_igp_cable_length_80)
++ else if (average <= e1000_igp_cable_length_80)
+ phy_info->cable_length = e1000_cable_length_50_80;
+- else if(average <= e1000_igp_cable_length_110)
++ else if (average <= e1000_igp_cable_length_110)
+ phy_info->cable_length = e1000_cable_length_80_110;
+- else if(average <= e1000_igp_cable_length_140)
++ else if (average <= e1000_igp_cable_length_140)
+ phy_info->cable_length = e1000_cable_length_110_140;
+ else
+ phy_info->cable_length = e1000_cable_length_140;
+@@ -4118,7 +4232,8 @@ e1000_phy_ife_get_info(struct e1000_hw *
+ struct e1000_phy_info *phy_info)
+ {
+ int32_t ret_val;
+- uint16_t phy_data, polarity;
++ uint16_t phy_data;
++ e1000_rev_polarity polarity;
+
+ DEBUGFUNC("e1000_phy_ife_get_info");
+
+@@ -4129,8 +4244,9 @@ e1000_phy_ife_get_info(struct e1000_hw *
+ if (ret_val)
+ return ret_val;
+ phy_info->polarity_correction =
+- (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
+- IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT;
++ ((phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
++ IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT) ?
++ e1000_polarity_reversal_disabled : e1000_polarity_reversal_enabled;
+
+ if (phy_info->polarity_correction == e1000_polarity_reversal_enabled) {
+ ret_val = e1000_check_polarity(hw, &polarity);
+@@ -4138,8 +4254,9 @@ e1000_phy_ife_get_info(struct e1000_hw *
+ return ret_val;
+ } else {
+ /* Polarity is forced. */
+- polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >>
+- IFE_PSC_FORCE_POLARITY_SHIFT;
++ polarity = ((phy_data & IFE_PSC_FORCE_POLARITY) >>
++ IFE_PSC_FORCE_POLARITY_SHIFT) ?
++ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
+ }
+ phy_info->cable_polarity = polarity;
+
+@@ -4147,9 +4264,9 @@ e1000_phy_ife_get_info(struct e1000_hw *
+ if (ret_val)
+ return ret_val;
+
+- phy_info->mdix_mode =
+- (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
+- IFE_PMC_MDIX_MODE_SHIFT;
++ phy_info->mdix_mode = (e1000_auto_x_mode)
++ ((phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
++ IFE_PMC_MDIX_MODE_SHIFT);
+
+ return E1000_SUCCESS;
+ }
+@@ -4165,7 +4282,8 @@ e1000_phy_m88_get_info(struct e1000_hw *
+ struct e1000_phy_info *phy_info)
+ {
+ int32_t ret_val;
+- uint16_t phy_data, polarity;
++ uint16_t phy_data;
++ e1000_rev_polarity polarity;
+
+ DEBUGFUNC("e1000_phy_m88_get_info");
+
+@@ -4174,35 +4292,38 @@ e1000_phy_m88_get_info(struct e1000_hw *
+ phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
+
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_info->extended_10bt_distance =
+- (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+- M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
++ ((phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
++ M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT) ?
++ e1000_10bt_ext_dist_enable_lower : e1000_10bt_ext_dist_enable_normal;
++
+ phy_info->polarity_correction =
+- (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+- M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
++ ((phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
++ M88E1000_PSCR_POLARITY_REVERSAL_SHIFT) ?
++ e1000_polarity_reversal_disabled : e1000_polarity_reversal_enabled;
+
+ /* Check polarity status */
+ ret_val = e1000_check_polarity(hw, &polarity);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ phy_info->cable_polarity = polarity;
+
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+- M88E1000_PSSR_MDIX_SHIFT;
++ phy_info->mdix_mode = (e1000_auto_x_mode)((phy_data & M88E1000_PSSR_MDIX) >>
++ M88E1000_PSSR_MDIX_SHIFT);
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ /* Cable Length Estimation and Local/Remote Receiver Information
+ * are only valid at 1000 Mbps.
+ */
+ if (hw->phy_type != e1000_phy_gg82563) {
+- phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
++ phy_info->cable_length = (e1000_cable_length)((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE,
+@@ -4210,18 +4331,20 @@ e1000_phy_m88_get_info(struct e1000_hw *
+ if (ret_val)
+ return ret_val;
+
+- phy_info->cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH;
++ phy_info->cable_length = (e1000_cable_length)(phy_data & GG82563_DSPD_CABLE_LENGTH);
+ }
+
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+- SR_1000T_LOCAL_RX_STATUS_SHIFT;
++ phy_info->local_rx = ((phy_data & SR_1000T_LOCAL_RX_STATUS) >>
++ SR_1000T_LOCAL_RX_STATUS_SHIFT) ?
++ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
++ phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
++ SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
++ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
+
+- phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+- SR_1000T_REMOTE_RX_STATUS_SHIFT;
+ }
+
+ return E1000_SUCCESS;
+@@ -4251,20 +4374,20 @@ e1000_phy_get_info(struct e1000_hw *hw,
+ phy_info->local_rx = e1000_1000t_rx_status_undefined;
+ phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+- if(hw->media_type != e1000_media_type_copper) {
++ if (hw->media_type != e1000_media_type_copper) {
+ DEBUGOUT("PHY info is only valid for copper media\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
++ if ((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+ DEBUGOUT("PHY info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+@@ -4284,7 +4407,7 @@ e1000_validate_mdi_setting(struct e1000_
+ {
+ DEBUGFUNC("e1000_validate_mdi_settings");
+
+- if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
++ if (!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+ DEBUGOUT("Invalid MDI setting detected\n");
+ hw->mdix = 1;
+ return -E1000_ERR_CONFIG;
+@@ -4331,7 +4454,7 @@ e1000_init_eeprom_params(struct e1000_hw
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+- if(eecd & E1000_EECD_SIZE) {
++ if (eecd & E1000_EECD_SIZE) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+@@ -4399,7 +4522,7 @@ e1000_init_eeprom_params(struct e1000_hw
+ }
+ eeprom->use_eerd = TRUE;
+ eeprom->use_eewr = TRUE;
+- if(e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
++ if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
+ eeprom->type = e1000_eeprom_flash;
+ eeprom->word_size = 2048;
+
+@@ -4424,7 +4547,7 @@ e1000_init_eeprom_params(struct e1000_hw
+ eeprom->use_eewr = FALSE;
+ break;
+ case e1000_ich8lan:
+- {
++ {
+ int32_t i = 0;
+ uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG);
+
+@@ -4451,7 +4574,7 @@ e1000_init_eeprom_params(struct e1000_hw
+ hw->flash_bank_size /= 2 * sizeof(uint16_t);
+
+ break;
+- }
++ }
+ default:
+ break;
+ }
+@@ -4460,17 +4583,17 @@ e1000_init_eeprom_params(struct e1000_hw
+ /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
+ * 32KB (incremented by powers of 2).
+ */
+- if(hw->mac_type <= e1000_82547_rev_2) {
++ if (hw->mac_type <= e1000_82547_rev_2) {
+ /* Set to default value for initial eeprom read. */
+ eeprom->word_size = 64;
+ ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
+ /* 256B eeprom size was not supported in earlier hardware, so we
+ * bump eeprom_size up one to ensure that "1" (which maps to 256B)
+ * is never the result used in the shifting logic below. */
+- if(eeprom_size)
++ if (eeprom_size)
+ eeprom_size++;
+ } else {
+ eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+@@ -4555,7 +4678,7 @@ e1000_shift_out_ee_bits(struct e1000_hw
+ */
+ eecd &= ~E1000_EECD_DI;
+
+- if(data & mask)
++ if (data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+@@ -4568,7 +4691,7 @@ e1000_shift_out_ee_bits(struct e1000_hw
+
+ mask = mask >> 1;
+
+- } while(mask);
++ } while (mask);
+
+ /* We leave the "DI" bit set to "0" when we leave this routine. */
+ eecd &= ~E1000_EECD_DI;
+@@ -4600,14 +4723,14 @@ e1000_shift_in_ee_bits(struct e1000_hw *
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+- for(i = 0; i < count; i++) {
++ for (i = 0; i < count; i++) {
+ data = data << 1;
+ e1000_raise_ee_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DI);
+- if(eecd & E1000_EECD_DO)
++ if (eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_ee_clk(hw, &eecd);
+@@ -4638,17 +4761,17 @@ e1000_acquire_eeprom(struct e1000_hw *hw
+
+ if (hw->mac_type != e1000_82573) {
+ /* Request EEPROM Access */
+- if(hw->mac_type > e1000_82544) {
++ if (hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+- while((!(eecd & E1000_EECD_GNT)) &&
++ while ((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+- if(!(eecd & E1000_EECD_GNT)) {
++ if (!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+@@ -4691,7 +4814,7 @@ e1000_standby_eeprom(struct e1000_hw *hw
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+- if(eeprom->type == e1000_eeprom_microwire) {
++ if (eeprom->type == e1000_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+@@ -4714,7 +4837,7 @@ e1000_standby_eeprom(struct e1000_hw *hw
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+- } else if(eeprom->type == e1000_eeprom_spi) {
++ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+@@ -4748,7 +4871,7 @@ e1000_release_eeprom(struct e1000_hw *hw
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ udelay(hw->eeprom.delay_usec);
+- } else if(hw->eeprom.type == e1000_eeprom_microwire) {
++ } else if (hw->eeprom.type == e1000_eeprom_microwire) {
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+@@ -4770,7 +4893,7 @@ e1000_release_eeprom(struct e1000_hw *hw
+ }
+
+ /* Stop requesting EEPROM access */
+- if(hw->mac_type > e1000_82544) {
++ if (hw->mac_type > e1000_82544) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+@@ -4783,7 +4906,7 @@ e1000_release_eeprom(struct e1000_hw *hw
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+-int32_t
++static int32_t
+ e1000_spi_eeprom_ready(struct e1000_hw *hw)
+ {
+ uint16_t retry_count = 0;
+@@ -4808,12 +4931,12 @@ e1000_spi_eeprom_ready(struct e1000_hw *
+ retry_count += 5;
+
+ e1000_standby_eeprom(hw);
+- } while(retry_count < EEPROM_MAX_RETRY_SPI);
++ } while (retry_count < EEPROM_MAX_RETRY_SPI);
+
+ /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+ * only 0-5mSec on 5V devices)
+ */
+- if(retry_count >= EEPROM_MAX_RETRY_SPI) {
++ if (retry_count >= EEPROM_MAX_RETRY_SPI) {
+ DEBUGOUT("SPI EEPROM Status error\n");
+ return -E1000_ERR_EEPROM;
+ }
+@@ -4837,49 +4960,48 @@ e1000_read_eeprom(struct e1000_hw *hw,
+ {
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t i = 0;
+- int32_t ret_val;
+
+ DEBUGFUNC("e1000_read_eeprom");
+
++ /* If eeprom is not yet detected, do so now */
++ if (eeprom->word_size == 0)
++ e1000_init_eeprom_params(hw);
++
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+- if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
++ if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+- DEBUGOUT("\"words\" parameter out of bounds\n");
++ DEBUGOUT2("\"words\" parameter out of bounds. Words = %d, size = %d\n", offset, eeprom->word_size);
+ return -E1000_ERR_EEPROM;
+ }
+
+- /* FLASH reads without acquiring the semaphore are safe */
++ /* EEPROM's that don't use EERD to read require us to bit-bang the SPI
++ * directly. In this case, we need to acquire the EEPROM so that
++ * FW or other port software does not interrupt.
++ */
+ if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
+- hw->eeprom.use_eerd == FALSE) {
+- switch (hw->mac_type) {
+- case e1000_80003es2lan:
+- break;
+- default:
+- /* Prepare the EEPROM for reading */
+- if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+- return -E1000_ERR_EEPROM;
+- break;
+- }
++ hw->eeprom.use_eerd == FALSE) {
++ /* Prepare the EEPROM for bit-bang reading */
++ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
++ return -E1000_ERR_EEPROM;
+ }
+
+- if (eeprom->use_eerd == TRUE) {
+- ret_val = e1000_read_eeprom_eerd(hw, offset, words, data);
+- if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) ||
+- (hw->mac_type != e1000_82573))
+- e1000_release_eeprom(hw);
+- return ret_val;
+- }
++ /* Eerd register EEPROM access requires no eeprom aquire/release */
++ if (eeprom->use_eerd == TRUE)
++ return e1000_read_eeprom_eerd(hw, offset, words, data);
+
++ /* ICH EEPROM access is done via the ICH flash controller */
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_read_eeprom_ich8(hw, offset, words, data);
+
++ /* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
++ * acquired the EEPROM at this point, so any returns should relase it */
+ if (eeprom->type == e1000_eeprom_spi) {
+ uint16_t word_in;
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+- if(e1000_spi_eeprom_ready(hw)) {
++ if (e1000_spi_eeprom_ready(hw)) {
+ e1000_release_eeprom(hw);
+ return -E1000_ERR_EEPROM;
+ }
+@@ -4887,7 +5009,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
+ e1000_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+- if((eeprom->address_bits == 8) && (offset >= 128))
++ if ((eeprom->address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+@@ -4903,7 +5025,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
+ word_in = e1000_shift_in_ee_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+- } else if(eeprom->type == e1000_eeprom_microwire) {
++ } else if (eeprom->type == e1000_eeprom_microwire) {
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+@@ -4948,7 +5070,7 @@ e1000_read_eeprom_eerd(struct e1000_hw *
+ E1000_WRITE_REG(hw, EERD, eerd);
+ error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+
+- if(error) {
++ if (error) {
+ break;
+ }
+ data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
+@@ -4985,7 +5107,7 @@ e1000_write_eeprom_eewr(struct e1000_hw
+ E1000_EEPROM_RW_REG_START;
+
+ error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+- if(error) {
++ if (error) {
+ break;
+ }
+
+@@ -4993,7 +5115,7 @@ e1000_write_eeprom_eewr(struct e1000_hw
+
+ error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+
+- if(error) {
++ if (error) {
+ break;
+ }
+ }
+@@ -5014,13 +5136,13 @@ e1000_poll_eerd_eewr_done(struct e1000_h
+ uint32_t i, reg = 0;
+ int32_t done = E1000_ERR_EEPROM;
+
+- for(i = 0; i < attempts; i++) {
+- if(eerd == E1000_EEPROM_POLL_READ)
++ for (i = 0; i < attempts; i++) {
++ if (eerd == E1000_EEPROM_POLL_READ)
+ reg = E1000_READ_REG(hw, EERD);
+ else
+ reg = E1000_READ_REG(hw, EEWR);
+
+- if(reg & E1000_EEPROM_RW_REG_DONE) {
++ if (reg & E1000_EEPROM_RW_REG_DONE) {
+ done = E1000_SUCCESS;
+ break;
+ }
+@@ -5052,7 +5174,7 @@ e1000_is_onboard_nvm_eeprom(struct e1000
+ eecd = ((eecd >> 15) & 0x03);
+
+ /* If both bits are set, device is Flash type */
+- if(eecd == 0x03) {
++ if (eecd == 0x03) {
+ return FALSE;
+ }
+ }
+@@ -5117,7 +5239,7 @@ e1000_validate_eeprom_checksum(struct e1
+ checksum += eeprom_data;
+ }
+
+- if(checksum == (uint16_t) EEPROM_SUM)
++ if (checksum == (uint16_t) EEPROM_SUM)
+ return E1000_SUCCESS;
+ else {
+ DEBUGOUT("EEPROM Checksum Invalid\n");
+@@ -5142,15 +5264,15 @@ e1000_update_eeprom_checksum(struct e100
+
+ DEBUGFUNC("e1000_update_eeprom_checksum");
+
+- for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+- if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
++ for (i = 0; i < EEPROM_CHECKSUM_REG; i++) {
++ if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+ checksum = (uint16_t) EEPROM_SUM - checksum;
+- if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
++ if (e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
+ DEBUGOUT("EEPROM Write Error\n");
+ return -E1000_ERR_EEPROM;
+ } else if (hw->eeprom.type == e1000_eeprom_flash) {
+@@ -5162,7 +5284,7 @@ e1000_update_eeprom_checksum(struct e100
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+- msec_delay(10);
++ msleep(10);
+ }
+ return E1000_SUCCESS;
+ }
+@@ -5189,17 +5311,21 @@ e1000_write_eeprom(struct e1000_hw *hw,
+
+ DEBUGFUNC("e1000_write_eeprom");
+
++ /* If eeprom is not yet detected, do so now */
++ if (eeprom->word_size == 0)
++ e1000_init_eeprom_params(hw);
++
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+- if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
++ if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* 82573 writes only through eewr */
+- if(eeprom->use_eewr == TRUE)
++ if (eeprom->use_eewr == TRUE)
+ return e1000_write_eeprom_eewr(hw, offset, words, data);
+
+ if (eeprom->type == e1000_eeprom_ich8)
+@@ -5209,11 +5335,11 @@ e1000_write_eeprom(struct e1000_hw *hw,
+ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+
+- if(eeprom->type == e1000_eeprom_microwire) {
++ if (eeprom->type == e1000_eeprom_microwire) {
+ status = e1000_write_eeprom_microwire(hw, offset, words, data);
+ } else {
+ status = e1000_write_eeprom_spi(hw, offset, words, data);
+- msec_delay(10);
++ msleep(10);
+ }
+
+ /* Done with writing */
+@@ -5231,7 +5357,7 @@ e1000_write_eeprom(struct e1000_hw *hw,
+ * data - pointer to array of 8 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+-int32_t
++static int32_t
+ e1000_write_eeprom_spi(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+@@ -5245,7 +5371,7 @@ e1000_write_eeprom_spi(struct e1000_hw *
+ while (widx < words) {
+ uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
+
+- if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
++ if (e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+
+ e1000_standby_eeprom(hw);
+
+@@ -5256,7 +5382,7 @@ e1000_write_eeprom_spi(struct e1000_hw *
+ e1000_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+- if((eeprom->address_bits == 8) && (offset >= 128))
++ if ((eeprom->address_bits == 8) && (offset >= 128))
+ write_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+@@ -5278,7 +5404,7 @@ e1000_write_eeprom_spi(struct e1000_hw *
+ * operation, while the smaller eeproms are capable of an 8-byte
+ * PAGE WRITE operation. Break the inner loop to pass new address
+ */
+- if((((offset + widx)*2) % eeprom->page_size) == 0) {
++ if ((((offset + widx)*2) % eeprom->page_size) == 0) {
+ e1000_standby_eeprom(hw);
+ break;
+ }
+@@ -5297,7 +5423,7 @@ e1000_write_eeprom_spi(struct e1000_hw *
+ * data - pointer to array of 16 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+-int32_t
++static int32_t
+ e1000_write_eeprom_microwire(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+@@ -5344,12 +5470,12 @@ e1000_write_eeprom_microwire(struct e100
+ * signal that the command has been completed by raising the DO signal.
+ * If DO does not go high in 10 milliseconds, then error out.
+ */
+- for(i = 0; i < 200; i++) {
++ for (i = 0; i < 200; i++) {
+ eecd = E1000_READ_REG(hw, EECD);
+- if(eecd & E1000_EECD_DO) break;
++ if (eecd & E1000_EECD_DO) break;
+ udelay(50);
+ }
+- if(i == 200) {
++ if (i == 200) {
+ DEBUGOUT("EEPROM Write did not complete\n");
+ return -E1000_ERR_EEPROM;
+ }
+@@ -5394,10 +5520,8 @@ e1000_commit_shadow_ram(struct e1000_hw
+ int32_t error = E1000_SUCCESS;
+ uint32_t old_bank_offset = 0;
+ uint32_t new_bank_offset = 0;
+- uint32_t sector_retries = 0;
+ uint8_t low_byte = 0;
+ uint8_t high_byte = 0;
+- uint8_t temp_byte = 0;
+ boolean_t sector_write_failed = FALSE;
+
+ if (hw->mac_type == e1000_82573) {
+@@ -5450,41 +5574,46 @@ e1000_commit_shadow_ram(struct e1000_hw
+ e1000_erase_ich8_4k_segment(hw, 0);
+ }
+
+- do {
+- sector_write_failed = FALSE;
+- /* Loop for every byte in the shadow RAM,
+- * which is in units of words. */
+- for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+- /* Determine whether to write the value stored
+- * in the other NVM bank or a modified value stored
+- * in the shadow RAM */
+- if (hw->eeprom_shadow_ram[i].modified == TRUE) {
+- low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
+- e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+- &temp_byte);
+- udelay(100);
+- error = e1000_verify_write_ich8_byte(hw,
+- (i << 1) + new_bank_offset,
+- low_byte);
+- if (error != E1000_SUCCESS)
+- sector_write_failed = TRUE;
++ sector_write_failed = FALSE;
++ /* Loop for every byte in the shadow RAM,
++ * which is in units of words. */
++ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
++ /* Determine whether to write the value stored
++ * in the other NVM bank or a modified value stored
++ * in the shadow RAM */
++ if (hw->eeprom_shadow_ram[i].modified == TRUE) {
++ low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
++ udelay(100);
++ error = e1000_verify_write_ich8_byte(hw,
++ (i << 1) + new_bank_offset, low_byte);
++
++ if (error != E1000_SUCCESS)
++ sector_write_failed = TRUE;
++ else {
+ high_byte =
+ (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8);
+- e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+- &temp_byte);
+- udelay(100);
+- } else {
+- e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+- &low_byte);
+ udelay(100);
+- error = e1000_verify_write_ich8_byte(hw,
+- (i << 1) + new_bank_offset, low_byte);
+- if (error != E1000_SUCCESS)
+- sector_write_failed = TRUE;
++ }
++ } else {
++ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
++ &low_byte);
++ udelay(100);
++ error = e1000_verify_write_ich8_byte(hw,
++ (i << 1) + new_bank_offset, low_byte);
++
++ if (error != E1000_SUCCESS)
++ sector_write_failed = TRUE;
++ else {
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+ &high_byte);
++ udelay(100);
+ }
++ }
+
++ /* If the write of the low byte was successful, go ahread and
++ * write the high byte while checking to make sure that if it
++ * is the signature byte, then it is handled properly */
++ if (sector_write_failed == FALSE) {
+ /* If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+@@ -5495,85 +5624,51 @@ e1000_commit_shadow_ram(struct e1000_hw
+ high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte;
+
+ error = e1000_verify_write_ich8_byte(hw,
+- (i << 1) + new_bank_offset + 1, high_byte);
++ (i << 1) + new_bank_offset + 1, high_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+
+- if (sector_write_failed == FALSE) {
+- /* Clear the now not used entry in the cache */
+- hw->eeprom_shadow_ram[i].modified = FALSE;
+- hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+- }
++ } else {
++ /* If the write failed then break from the loop and
++ * return an error */
++ break;
+ }
++ }
+
+- /* Don't bother writing the segment valid bits if sector
+- * programming failed. */
+- if (sector_write_failed == FALSE) {
+- /* Finally validate the new segment by setting bit 15:14
+- * to 10b in word 0x13 , this can be done without an
+- * erase as well since these bits are 11 to start with
+- * and we need to change bit 14 to 0b */
+- e1000_read_ich8_byte(hw,
+- E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+- &high_byte);
+- high_byte &= 0xBF;
++ /* Don't bother writing the segment valid bits if sector
++ * programming failed. */
++ if (sector_write_failed == FALSE) {
++ /* Finally validate the new segment by setting bit 15:14
++ * to 10b in word 0x13 , this can be done without an
++ * erase as well since these bits are 11 to start with
++ * and we need to change bit 14 to 0b */
++ e1000_read_ich8_byte(hw,
++ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
++ &high_byte);
++ high_byte &= 0xBF;
++ error = e1000_verify_write_ich8_byte(hw,
++ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset, high_byte);
++ /* And invalidate the previously valid segment by setting
++ * its signature word (0x13) high_byte to 0b. This can be
++ * done without an erase because flash erase sets all bits
++ * to 1's. We can write 1's to 0's without an erase */
++ if (error == E1000_SUCCESS) {
+ error = e1000_verify_write_ich8_byte(hw,
+- E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+- high_byte);
+- if (error != E1000_SUCCESS)
+- sector_write_failed = TRUE;
++ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset, 0);
++ }
+
+- /* And invalidate the previously valid segment by setting
+- * its signature word (0x13) high_byte to 0b. This can be
+- * done without an erase because flash erase sets all bits
+- * to 1's. We can write 1's to 0's without an erase */
+- error = e1000_verify_write_ich8_byte(hw,
+- E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset,
+- 0);
+- if (error != E1000_SUCCESS)
+- sector_write_failed = TRUE;
++ /* Clear the now not used entry in the cache */
++ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
++ hw->eeprom_shadow_ram[i].modified = FALSE;
++ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+- } while (++sector_retries < 10 && sector_write_failed == TRUE);
++ }
+ }
+
+ return error;
+ }
+
+ /******************************************************************************
+- * Reads the adapter's part number from the EEPROM
+- *
+- * hw - Struct containing variables accessed by shared code
+- * part_num - Adapter's part number
+- *****************************************************************************/
+-int32_t
+-e1000_read_part_num(struct e1000_hw *hw,
+- uint32_t *part_num)
+-{
+- uint16_t offset = EEPROM_PBA_BYTE_1;
+- uint16_t eeprom_data;
+-
+- DEBUGFUNC("e1000_read_part_num");
+-
+- /* Get word 0 from EEPROM */
+- if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+- DEBUGOUT("EEPROM Read Error\n");
+- return -E1000_ERR_EEPROM;
+- }
+- /* Save word 0 in upper half of part_num */
+- *part_num = (uint32_t) (eeprom_data << 16);
+-
+- /* Get word 1 from EEPROM */
+- if(e1000_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
+- DEBUGOUT("EEPROM Read Error\n");
+- return -E1000_ERR_EEPROM;
+- }
+- /* Save word 1 in lower half of part_num */
+- *part_num |= eeprom_data;
+-
+- return E1000_SUCCESS;
+-}
+-
+-/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+@@ -5587,9 +5682,9 @@ e1000_read_mac_addr(struct e1000_hw * hw
+
+ DEBUGFUNC("e1000_read_mac_addr");
+
+- for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
++ for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ offset = i >> 1;
+- if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
++ if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+@@ -5604,12 +5699,12 @@ e1000_read_mac_addr(struct e1000_hw * hw
+ case e1000_82546_rev_3:
+ case e1000_82571:
+ case e1000_80003es2lan:
+- if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
++ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ hw->perm_mac_addr[5] ^= 0x01;
+ break;
+ }
+
+- for(i = 0; i < NODE_ADDRESS_SIZE; i++)
++ for (i = 0; i < NODE_ADDRESS_SIZE; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return E1000_SUCCESS;
+ }
+@@ -5648,106 +5743,13 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
+
+ /* Zero out the other 15 receive addresses. */
+ DEBUGOUT("Clearing RAR[1-15]\n");
+- for(i = 1; i < rar_num; i++) {
+- E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+- E1000_WRITE_FLUSH(hw);
+- E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+- E1000_WRITE_FLUSH(hw);
+- }
+-}
+-
+-/******************************************************************************
+- * Updates the MAC's list of multicast addresses.
+- *
+- * hw - Struct containing variables accessed by shared code
+- * mc_addr_list - the list of new multicast addresses
+- * mc_addr_count - number of addresses
+- * pad - number of bytes between addresses in the list
+- * rar_used_count - offset where to start adding mc addresses into the RAR's
+- *
+- * The given list replaces any existing list. Clears the last 15 receive
+- * address registers and the multicast table. Uses receive address registers
+- * for the first 15 multicast addresses, and hashes the rest into the
+- * multicast table.
+- *****************************************************************************/
+-#if 0
+-void
+-e1000_mc_addr_list_update(struct e1000_hw *hw,
+- uint8_t *mc_addr_list,
+- uint32_t mc_addr_count,
+- uint32_t pad,
+- uint32_t rar_used_count)
+-{
+- uint32_t hash_value;
+- uint32_t i;
+- uint32_t num_rar_entry;
+- uint32_t num_mta_entry;
+-
+- DEBUGFUNC("e1000_mc_addr_list_update");
+-
+- /* Set the new number of MC addresses that we are being requested to use. */
+- hw->num_mc_addrs = mc_addr_count;
+-
+- /* Clear RAR[1-15] */
+- DEBUGOUT(" Clearing RAR[1-15]\n");
+- num_rar_entry = E1000_RAR_ENTRIES;
+- if (hw->mac_type == e1000_ich8lan)
+- num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN;
+- /* Reserve a spot for the Locally Administered Address to work around
+- * an 82571 issue in which a reset on one port will reload the MAC on
+- * the other port. */
+- if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
+- num_rar_entry -= 1;
+-
+- for(i = rar_used_count; i < num_rar_entry; i++) {
++ for (i = 1; i < rar_num; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ E1000_WRITE_FLUSH(hw);
+ }
+-
+- /* Clear the MTA */
+- DEBUGOUT(" Clearing MTA\n");
+- num_mta_entry = E1000_NUM_MTA_REGISTERS;
+- if (hw->mac_type == e1000_ich8lan)
+- num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN;
+- for(i = 0; i < num_mta_entry; i++) {
+- E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+- E1000_WRITE_FLUSH(hw);
+- }
+-
+- /* Add the new addresses */
+- for(i = 0; i < mc_addr_count; i++) {
+- DEBUGOUT(" Adding the multicast addresses:\n");
+- DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+-
+- hash_value = e1000_hash_mc_addr(hw,
+- mc_addr_list +
+- (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+-
+- DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+-
+- /* Place this multicast address in the RAR if there is room, *
+- * else put it in the MTA
+- */
+- if (rar_used_count < num_rar_entry) {
+- e1000_rar_set(hw,
+- mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+- rar_used_count);
+- rar_used_count++;
+- } else {
+- e1000_mta_set(hw, hash_value);
+- }
+- }
+- DEBUGOUT("MC Update Complete\n");
+ }
+-#endif /* 0 */
+
+ /******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+@@ -5849,7 +5851,7 @@ e1000_mta_set(struct e1000_hw *hw,
+ * in the MTA, save off the previous entry before writing and
+ * restore the old value after writing.
+ */
+- if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
++ if ((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_FLUSH(hw);
+@@ -5999,7 +6001,7 @@ e1000_id_led_init(struct e1000_hw * hw)
+
+ DEBUGFUNC("e1000_id_led_init");
+
+- if(hw->mac_type < e1000_82540) {
++ if (hw->mac_type < e1000_82540) {
+ /* Nothing to do */
+ return E1000_SUCCESS;
+ }
+@@ -6009,7 +6011,7 @@ e1000_id_led_init(struct e1000_hw * hw)
+ hw->ledctl_mode1 = hw->ledctl_default;
+ hw->ledctl_mode2 = hw->ledctl_default;
+
+- if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
++ if (e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+@@ -6026,7 +6028,7 @@ e1000_id_led_init(struct e1000_hw * hw)
+ }
+ for (i = 0; i < 4; i++) {
+ temp = (eeprom_data >> (i << 2)) & led_mask;
+- switch(temp) {
++ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+@@ -6043,7 +6045,7 @@ e1000_id_led_init(struct e1000_hw * hw)
+ /* Do nothing */
+ break;
+ }
+- switch(temp) {
++ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+@@ -6077,7 +6079,7 @@ e1000_setup_led(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_setup_led");
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+@@ -6091,16 +6093,16 @@ e1000_setup_led(struct e1000_hw *hw)
+ /* Turn off PHY Smart Power Down (if enabled) */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ &hw->phy_spd_default);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ (uint16_t)(hw->phy_spd_default &
+ ~IGP01E1000_GMII_SPD));
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ /* Fall Through */
+ default:
+- if(hw->media_type == e1000_media_type_fiber) {
++ if (hw->media_type == e1000_media_type_fiber) {
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Save current LEDCTL settings */
+ hw->ledctl_default = ledctl;
+@@ -6111,7 +6113,7 @@ e1000_setup_led(struct e1000_hw *hw)
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+ E1000_LEDCTL_LED0_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+- } else if(hw->media_type == e1000_media_type_copper)
++ } else if (hw->media_type == e1000_media_type_copper)
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+ break;
+ }
+@@ -6119,6 +6121,7 @@ e1000_setup_led(struct e1000_hw *hw)
+ return E1000_SUCCESS;
+ }
+
++
+ /******************************************************************************
+ * Used on 82571 and later Si that has LED blink bits.
+ * Callers must use their own timer and should have already called
+@@ -6169,7 +6172,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_cleanup_led");
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+@@ -6183,7 +6186,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
+ /* Turn on PHY Smart Power Down (if previously enabled) */
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ hw->phy_spd_default);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ /* Fall Through */
+ default:
+@@ -6211,7 +6214,7 @@ e1000_led_on(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_led_on");
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+@@ -6220,7 +6223,7 @@ e1000_led_on(struct e1000_hw *hw)
+ ctrl |= E1000_CTRL_SWDPIO0;
+ break;
+ case e1000_82544:
+- if(hw->media_type == e1000_media_type_fiber) {
++ if (hw->media_type == e1000_media_type_fiber) {
+ /* Set SW Defineable Pin 0 to turn on the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+@@ -6231,7 +6234,7 @@ e1000_led_on(struct e1000_hw *hw)
+ }
+ break;
+ default:
+- if(hw->media_type == e1000_media_type_fiber) {
++ if (hw->media_type == e1000_media_type_fiber) {
+ /* Clear SW Defineable Pin 0 to turn on the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+@@ -6262,7 +6265,7 @@ e1000_led_off(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_led_off");
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+@@ -6271,7 +6274,7 @@ e1000_led_off(struct e1000_hw *hw)
+ ctrl |= E1000_CTRL_SWDPIO0;
+ break;
+ case e1000_82544:
+- if(hw->media_type == e1000_media_type_fiber) {
++ if (hw->media_type == e1000_media_type_fiber) {
+ /* Clear SW Defineable Pin 0 to turn off the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+@@ -6282,7 +6285,7 @@ e1000_led_off(struct e1000_hw *hw)
+ }
+ break;
+ default:
+- if(hw->media_type == e1000_media_type_fiber) {
++ if (hw->media_type == e1000_media_type_fiber) {
+ /* Set SW Defineable Pin 0 to turn off the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+@@ -6369,7 +6372,7 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw
+ temp = E1000_READ_REG(hw, MPTC);
+ temp = E1000_READ_REG(hw, BPTC);
+
+- if(hw->mac_type < e1000_82543) return;
++ if (hw->mac_type < e1000_82543) return;
+
+ temp = E1000_READ_REG(hw, ALGNERRC);
+ temp = E1000_READ_REG(hw, RXERRC);
+@@ -6378,13 +6381,13 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw
+ temp = E1000_READ_REG(hw, TSCTC);
+ temp = E1000_READ_REG(hw, TSCTFC);
+
+- if(hw->mac_type <= e1000_82544) return;
++ if (hw->mac_type <= e1000_82544) return;
+
+ temp = E1000_READ_REG(hw, MGTPRC);
+ temp = E1000_READ_REG(hw, MGTPDC);
+ temp = E1000_READ_REG(hw, MGTPTC);
+
+- if(hw->mac_type <= e1000_82547_rev_2) return;
++ if (hw->mac_type <= e1000_82547_rev_2) return;
+
+ temp = E1000_READ_REG(hw, IAC);
+ temp = E1000_READ_REG(hw, ICRXOC);
+@@ -6415,8 +6418,8 @@ e1000_reset_adaptive(struct e1000_hw *hw
+ {
+ DEBUGFUNC("e1000_reset_adaptive");
+
+- if(hw->adaptive_ifs) {
+- if(!hw->ifs_params_forced) {
++ if (hw->adaptive_ifs) {
++ if (!hw->ifs_params_forced) {
+ hw->current_ifs_val = 0;
+ hw->ifs_min_val = IFS_MIN;
+ hw->ifs_max_val = IFS_MAX;
+@@ -6443,12 +6446,12 @@ e1000_update_adaptive(struct e1000_hw *h
+ {
+ DEBUGFUNC("e1000_update_adaptive");
+
+- if(hw->adaptive_ifs) {
+- if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
+- if(hw->tx_packet_delta > MIN_NUM_XMITS) {
++ if (hw->adaptive_ifs) {
++ if ((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
++ if (hw->tx_packet_delta > MIN_NUM_XMITS) {
+ hw->in_ifs_mode = TRUE;
+- if(hw->current_ifs_val < hw->ifs_max_val) {
+- if(hw->current_ifs_val == 0)
++ if (hw->current_ifs_val < hw->ifs_max_val) {
++ if (hw->current_ifs_val == 0)
+ hw->current_ifs_val = hw->ifs_min_val;
+ else
+ hw->current_ifs_val += hw->ifs_step_size;
+@@ -6456,7 +6459,7 @@ e1000_update_adaptive(struct e1000_hw *h
+ }
+ }
+ } else {
+- if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
++ if (hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+ hw->current_ifs_val = 0;
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+@@ -6503,46 +6506,46 @@ e1000_tbi_adjust_stats(struct e1000_hw *
+ * This could be simplified if all environments supported
+ * 64-bit integers.
+ */
+- if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
++ if (carry_bit && ((stats->gorcl & 0x80000000) == 0))
+ stats->gorch++;
+ /* Is this a broadcast or multicast? Check broadcast first,
+ * since the test for a multicast frame will test positive on
+ * a broadcast frame.
+ */
+- if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
++ if ((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+ /* Broadcast packet */
+ stats->bprc++;
+- else if(*mac_addr & 0x01)
++ else if (*mac_addr & 0x01)
+ /* Multicast packet */
+ stats->mprc++;
+
+- if(frame_len == hw->max_frame_size) {
++ if (frame_len == hw->max_frame_size) {
+ /* In this case, the hardware has overcounted the number of
+ * oversize frames.
+ */
+- if(stats->roc > 0)
++ if (stats->roc > 0)
+ stats->roc--;
+ }
+
+ /* Adjust the bin counters when the extra byte put the frame in the
+ * wrong bin. Remember that the frame_len was adjusted above.
+ */
+- if(frame_len == 64) {
++ if (frame_len == 64) {
+ stats->prc64++;
+ stats->prc127--;
+- } else if(frame_len == 127) {
++ } else if (frame_len == 127) {
+ stats->prc127++;
+ stats->prc255--;
+- } else if(frame_len == 255) {
++ } else if (frame_len == 255) {
+ stats->prc255++;
+ stats->prc511--;
+- } else if(frame_len == 511) {
++ } else if (frame_len == 511) {
+ stats->prc511++;
+ stats->prc1023--;
+- } else if(frame_len == 1023) {
++ } else if (frame_len == 1023) {
+ stats->prc1023++;
+ stats->prc1522--;
+- } else if(frame_len == 1522) {
++ } else if (frame_len == 1522) {
+ stats->prc1522++;
+ }
+ }
+@@ -6555,6 +6558,8 @@ e1000_tbi_adjust_stats(struct e1000_hw *
+ void
+ e1000_get_bus_info(struct e1000_hw *hw)
+ {
++ int32_t ret_val;
++ uint16_t pci_ex_link_status;
+ uint32_t status;
+
+ switch (hw->mac_type) {
+@@ -6564,28 +6569,35 @@ e1000_get_bus_info(struct e1000_hw *hw)
+ hw->bus_speed = e1000_bus_speed_unknown;
+ hw->bus_width = e1000_bus_width_unknown;
+ break;
++ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
++ case e1000_80003es2lan:
+ hw->bus_type = e1000_bus_type_pci_express;
+ hw->bus_speed = e1000_bus_speed_2500;
+- hw->bus_width = e1000_bus_width_pciex_1;
++ ret_val = e1000_read_pcie_cap_reg(hw,
++ PCI_EX_LINK_STATUS,
++ &pci_ex_link_status);
++ if (ret_val)
++ hw->bus_width = e1000_bus_width_unknown;
++ else
++ hw->bus_width = (pci_ex_link_status & PCI_EX_LINK_WIDTH_MASK) >>
++ PCI_EX_LINK_WIDTH_SHIFT;
+ break;
+- case e1000_82571:
+ case e1000_ich8lan:
+- case e1000_80003es2lan:
+ hw->bus_type = e1000_bus_type_pci_express;
+ hw->bus_speed = e1000_bus_speed_2500;
+- hw->bus_width = e1000_bus_width_pciex_4;
++ hw->bus_width = e1000_bus_width_pciex_1;
+ break;
+ default:
+ status = E1000_READ_REG(hw, STATUS);
+ hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+ e1000_bus_type_pcix : e1000_bus_type_pci;
+
+- if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
++ if (hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+ hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
+ e1000_bus_speed_66 : e1000_bus_speed_120;
+- } else if(hw->bus_type == e1000_bus_type_pci) {
++ } else if (hw->bus_type == e1000_bus_type_pci) {
+ hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+ e1000_bus_speed_66 : e1000_bus_speed_33;
+ } else {
+@@ -6609,25 +6621,6 @@ e1000_get_bus_info(struct e1000_hw *hw)
+ break;
+ }
+ }
+-/******************************************************************************
+- * Reads a value from one of the devices registers using port I/O (as opposed
+- * memory mapped I/O). Only 82544 and newer devices support port I/O.
+- *
+- * hw - Struct containing variables accessed by shared code
+- * offset - offset to read from
+- *****************************************************************************/
+-#if 0
+-uint32_t
+-e1000_read_reg_io(struct e1000_hw *hw,
+- uint32_t offset)
+-{
+- unsigned long io_addr = hw->io_base;
+- unsigned long io_data = hw->io_base + 4;
+-
+- e1000_io_write(hw, io_addr, offset);
+- return e1000_io_read(hw, io_data);
+-}
+-#endif /* 0 */
+
+ /******************************************************************************
+ * Writes a value to one of the devices registers using port I/O (as opposed to
+@@ -6649,7 +6642,6 @@ e1000_write_reg_io(struct e1000_hw *hw,
+ e1000_io_write(hw, io_data, value);
+ }
+
+-
+ /******************************************************************************
+ * Estimates the cable length.
+ *
+@@ -6680,11 +6672,11 @@ e1000_get_cable_length(struct e1000_hw *
+ *min_length = *max_length = 0;
+
+ /* Use old method for Phy older than IGP */
+- if(hw->phy_type == e1000_phy_m88) {
++ if (hw->phy_type == e1000_phy_m88) {
+
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+@@ -6743,7 +6735,7 @@ e1000_get_cable_length(struct e1000_hw *
+ return -E1000_ERR_PHY;
+ break;
+ }
+- } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
++ } else if (hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+ uint16_t cur_agc_value;
+ uint16_t min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+ uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+@@ -6752,10 +6744,10 @@ e1000_get_cable_length(struct e1000_hw *
+ IGP01E1000_PHY_AGC_C,
+ IGP01E1000_PHY_AGC_D};
+ /* Read the AGC registers for all channels */
+- for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
++ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+
+ ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ cur_agc_value = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+@@ -6805,7 +6797,7 @@ e1000_get_cable_length(struct e1000_hw *
+ if (ret_val)
+ return ret_val;
+
+- /* Getting bits 15:9, which represent the combination of course and
++ /* Getting bits 15:9, which represent the combination of course and
+ * fine gain values. The result is a number that can be put into
+ * the lookup table to obtain the approximate cable length. */
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+@@ -6858,7 +6850,7 @@ e1000_get_cable_length(struct e1000_hw *
+ *****************************************************************************/
+ static int32_t
+ e1000_check_polarity(struct e1000_hw *hw,
+- uint16_t *polarity)
++ e1000_rev_polarity *polarity)
+ {
+ int32_t ret_val;
+ uint16_t phy_data;
+@@ -6870,44 +6862,49 @@ e1000_check_polarity(struct e1000_hw *hw
+ /* return the Polarity bit in the Status register. */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+- M88E1000_PSSR_REV_POLARITY_SHIFT;
++ *polarity = ((phy_data & M88E1000_PSSR_REV_POLARITY) >>
++ M88E1000_PSSR_REV_POLARITY_SHIFT) ?
++ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
++
+ } else if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
+ hw->phy_type == e1000_phy_igp_2) {
+ /* Read the Status register to check the speed */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
+ * find the polarity status */
+- if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
++ if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+
+ /* Read the GIG initialization PCS register (0x00B4) */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Check the polarity bits */
+- *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
++ *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ?
++ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
+ } else {
+ /* For 10 Mbps, read the polarity bit in the status register. (for
+ * 100 Mbps this bit is always 0) */
+- *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
++ *polarity = (phy_data & IGP01E1000_PSSR_POLARITY_REVERSED) ?
++ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
+ }
+ } else if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+- *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >>
+- IFE_PESC_POLARITY_REVERSED_SHIFT;
++ *polarity = ((phy_data & IFE_PESC_POLARITY_REVERSED) >>
++ IFE_PESC_POLARITY_REVERSED_SHIFT) ?
++ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
+ }
+ return E1000_SUCCESS;
+ }
+@@ -6940,7 +6937,7 @@ e1000_check_downshift(struct e1000_hw *h
+ hw->phy_type == e1000_phy_igp_2) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+@@ -6948,7 +6945,7 @@ e1000_check_downshift(struct e1000_hw *h
+ (hw->phy_type == e1000_phy_gg82563)) {
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
+@@ -6988,42 +6985,42 @@ e1000_config_dsp_after_link_change(struc
+
+ DEBUGFUNC("e1000_config_dsp_after_link_change");
+
+- if(hw->phy_type != e1000_phy_igp)
++ if (hw->phy_type != e1000_phy_igp)
+ return E1000_SUCCESS;
+
+- if(link_up) {
++ if (link_up) {
+ ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+- if(ret_val) {
++ if (ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ return ret_val;
+ }
+
+- if(speed == SPEED_1000) {
++ if (speed == SPEED_1000) {
+
+ ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+ if (ret_val)
+ return ret_val;
+
+- if((hw->dsp_config_state == e1000_dsp_config_enabled) &&
++ if ((hw->dsp_config_state == e1000_dsp_config_enabled) &&
+ min_length >= e1000_igp_cable_length_50) {
+
+- for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
++ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+
+ ret_val = e1000_write_phy_reg(hw, dsp_reg_array[i],
+ phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+ hw->dsp_config_state = e1000_dsp_config_activated;
+ }
+
+- if((hw->ffe_config_state == e1000_ffe_config_enabled) &&
++ if ((hw->ffe_config_state == e1000_ffe_config_enabled) &&
+ (min_length < e1000_igp_cable_length_50)) {
+
+ uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
+@@ -7032,119 +7029,119 @@ e1000_config_dsp_after_link_change(struc
+ /* clear previous idle error counts */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- for(i = 0; i < ffe_idle_err_timeout; i++) {
++ for (i = 0; i < ffe_idle_err_timeout; i++) {
+ udelay(1000);
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
+- if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
++ if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+ hw->ffe_config_state = e1000_ffe_config_active;
+
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_DSP_FFE,
+ IGP01E1000_PHY_DSP_FFE_CM_CP);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ break;
+ }
+
+- if(idle_errs)
++ if (idle_errs)
+ ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100;
+ }
+ }
+ }
+ } else {
+- if(hw->dsp_config_state == e1000_dsp_config_activated) {
++ if (hw->dsp_config_state == e1000_dsp_config_activated) {
+ /* Save off the current value of register 0x2F5B to be restored at
+ * the end of the routines. */
+ ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Disable the PHY transmitter */
+ ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- msec_delay_irq(20);
++ mdelay(20);
+
+ ret_val = e1000_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_FORCE_GIGA);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
++ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i], &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+ phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
+
+ ret_val = e1000_write_phy_reg(hw,dsp_reg_array[i], phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1000_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_RESTART_AUTONEG);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- msec_delay_irq(20);
++ mdelay(20);
+
+ /* Now enable the transmitter */
+ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ hw->dsp_config_state = e1000_dsp_config_enabled;
+ }
+
+- if(hw->ffe_config_state == e1000_ffe_config_active) {
++ if (hw->ffe_config_state == e1000_ffe_config_active) {
+ /* Save off the current value of register 0x2F5B to be restored at
+ * the end of the routines. */
+ ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Disable the PHY transmitter */
+ ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- msec_delay_irq(20);
++ mdelay(20);
+
+ ret_val = e1000_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_FORCE_GIGA);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
+ IGP01E1000_PHY_DSP_FFE_DEFAULT);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_RESTART_AUTONEG);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- msec_delay_irq(20);
++ mdelay(20);
+
+ /* Now enable the transmitter */
+ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ hw->ffe_config_state = e1000_ffe_config_enabled;
+@@ -7169,20 +7166,20 @@ e1000_set_phy_mode(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_set_phy_mode");
+
+- if((hw->mac_type == e1000_82545_rev_3) &&
+- (hw->media_type == e1000_media_type_copper)) {
++ if ((hw->mac_type == e1000_82545_rev_3) &&
++ (hw->media_type == e1000_media_type_copper)) {
+ ret_val = e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
+- if(ret_val) {
++ if (ret_val) {
+ return ret_val;
+ }
+
+- if((eeprom_data != EEPROM_RESERVED_WORD) &&
+- (eeprom_data & EEPROM_PHY_CLASS_A)) {
++ if ((eeprom_data != EEPROM_RESERVED_WORD) &&
++ (eeprom_data & EEPROM_PHY_CLASS_A)) {
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ hw->phy_reset_disable = FALSE;
+@@ -7233,16 +7230,16 @@ e1000_set_d3_lplu_state(struct e1000_hw
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+- if(!active) {
+- if(hw->mac_type == e1000_82541_rev_2 ||
+- hw->mac_type == e1000_82547_rev_2) {
++ if (!active) {
++ if (hw->mac_type == e1000_82541_rev_2 ||
++ hw->mac_type == e1000_82547_rev_2) {
+ phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else {
+ if (hw->mac_type == e1000_ich8lan) {
+@@ -7264,36 +7261,36 @@ e1000_set_d3_lplu_state(struct e1000_hw
+ if (hw->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+- if (ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+- } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
+- (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
+- (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
++ } else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
++ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
++ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+
+- if(hw->mac_type == e1000_82541_rev_2 ||
++ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ phy_data |= IGP01E1000_GMII_FLEX_SPD;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else {
+ if (hw->mac_type == e1000_ich8lan) {
+@@ -7310,12 +7307,12 @@ e1000_set_d3_lplu_state(struct e1000_hw
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ }
+@@ -7345,14 +7342,14 @@ e1000_set_d0_lplu_state(struct e1000_hw
+ uint16_t phy_data;
+ DEBUGFUNC("e1000_set_d0_lplu_state");
+
+- if(hw->mac_type <= e1000_82547_rev_2)
++ if (hw->mac_type <= e1000_82547_rev_2)
+ return E1000_SUCCESS;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+@@ -7374,24 +7371,24 @@ e1000_set_d0_lplu_state(struct e1000_hw
+ if (hw->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+- if (ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ }
+
+@@ -7410,12 +7407,12 @@ e1000_set_d0_lplu_state(struct e1000_hw
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ }
+@@ -7436,7 +7433,7 @@ e1000_set_vco_speed(struct e1000_hw *hw)
+
+ DEBUGFUNC("e1000_set_vco_speed");
+
+- switch(hw->mac_type) {
++ switch (hw->mac_type) {
+ case e1000_82545_rev_3:
+ case e1000_82546_rev_3:
+ break;
+@@ -7447,39 +7444,39 @@ e1000_set_vco_speed(struct e1000_hw *hw)
+ /* Set PHY register 30, page 5, bit 8 to 0 */
+
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* Set PHY register 30, page 4, bit 11 to 1 */
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PHY_VCO_REG_BIT11;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ return E1000_SUCCESS;
+@@ -7491,7 +7488,7 @@ e1000_set_vco_speed(struct e1000_hw *hw)
+ *
+ * returns: - E1000_SUCCESS .
+ ****************************************************************************/
+-int32_t
++static int32_t
+ e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer)
+ {
+ uint8_t i;
+@@ -7535,7 +7532,7 @@ e1000_mng_enable_host_if(struct e1000_hw
+ hicr = E1000_READ_REG(hw, HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+- msec_delay_irq(1);
++ mdelay(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+@@ -7558,7 +7555,7 @@ e1000_mng_host_if_write(struct e1000_hw
+ {
+ uint8_t *tmp;
+ uint8_t *bufptr = buffer;
+- uint32_t data;
++ uint32_t data = 0;
+ uint16_t remaining, i, j, prev_bytes;
+
+ /* sum = only sum of the data and it is not checksum */
+@@ -7638,7 +7635,7 @@ e1000_mng_write_cmd_header(struct e1000_
+
+ buffer = (uint8_t *) hdr;
+ i = length;
+- while(i--)
++ while (i--)
+ sum += buffer[i];
+
+ hdr->checksum = 0 - sum;
+@@ -7661,8 +7658,7 @@ e1000_mng_write_cmd_header(struct e1000_
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+ static int32_t
+-e1000_mng_write_commit(
+- struct e1000_hw * hw)
++e1000_mng_write_commit(struct e1000_hw * hw)
+ {
+ uint32_t hicr;
+
+@@ -7703,7 +7699,7 @@ e1000_check_mng_mode(struct e1000_hw *hw
+ ****************************************************************************/
+ int32_t
+ e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer,
+- uint16_t length)
++ uint16_t length)
+ {
+ int32_t ret_val;
+ struct e1000_host_mng_command_header hdr;
+@@ -7733,7 +7729,7 @@ e1000_mng_write_dhcp_info(struct e1000_h
+ *
+ * returns - checksum of buffer contents.
+ ****************************************************************************/
+-uint8_t
++static uint8_t
+ e1000_calculate_mng_checksum(char *buffer, uint32_t length)
+ {
+ uint8_t sum = 0;
+@@ -7834,75 +7830,75 @@ e1000_polarity_reversal_workaround(struc
+ /* Disable the transmitter on the PHY */
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* This loop will early-out if the NO link condition has been met. */
+- for(i = PHY_FORCE_TIME; i > 0; i--) {
++ for (i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Link Status bit
+ * to be clear.
+ */
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+- msec_delay_irq(100);
++ if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
++ mdelay(100);
+ }
+
+ /* Recommended delay time after link has been lost */
+- msec_delay_irq(1000);
++ mdelay(1000);
+
+ /* Now we will re-enable th transmitter on the PHY */
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- msec_delay_irq(50);
++ mdelay(50);
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- msec_delay_irq(50);
++ mdelay(50);
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+- msec_delay_irq(50);
++ mdelay(50);
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ /* This loop will early-out if the link condition has been met. */
+- for(i = PHY_FORCE_TIME; i > 0; i--) {
++ for (i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Link Status bit
+ * to be set.
+ */
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+- if(ret_val)
++ if (ret_val)
+ return ret_val;
+
+- if(mii_status_reg & MII_SR_LINK_STATUS) break;
+- msec_delay_irq(100);
++ if (mii_status_reg & MII_SR_LINK_STATUS) break;
++ mdelay(100);
+ }
+ return E1000_SUCCESS;
+ }
+@@ -7931,32 +7927,6 @@ e1000_set_pci_express_master_disable(str
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ }
+
+-/***************************************************************************
+- *
+- * Enables PCI-Express master access.
+- *
+- * hw: Struct containing variables accessed by shared code
+- *
+- * returns: - none.
+- *
+- ***************************************************************************/
+-#if 0
+-void
+-e1000_enable_pciex_master(struct e1000_hw *hw)
+-{
+- uint32_t ctrl;
+-
+- DEBUGFUNC("e1000_enable_pciex_master");
+-
+- if (hw->bus_type != e1000_bus_type_pci_express)
+- return;
+-
+- ctrl = E1000_READ_REG(hw, CTRL);
+- ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
+- E1000_WRITE_REG(hw, CTRL, ctrl);
+-}
+-#endif /* 0 */
+-
+ /*******************************************************************************
+ *
+ * Disables PCI-Express master access and verifies there are no pending requests
+@@ -7980,15 +7950,15 @@ e1000_disable_pciex_master(struct e1000_
+
+ e1000_set_pci_express_master_disable(hw);
+
+- while(timeout) {
+- if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
++ while (timeout) {
++ if (!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ else
+ udelay(100);
+ timeout--;
+ }
+
+- if(!timeout) {
++ if (!timeout) {
+ DEBUGOUT("Master requests are pending.\n");
+ return -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+@@ -8015,7 +7985,7 @@ e1000_get_auto_rd_done(struct e1000_hw *
+
+ switch (hw->mac_type) {
+ default:
+- msec_delay(5);
++ msleep(5);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+@@ -8025,11 +7995,11 @@ e1000_get_auto_rd_done(struct e1000_hw *
+ while (timeout) {
+ if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
+ break;
+- else msec_delay(1);
++ else msleep(1);
+ timeout--;
+ }
+
+- if(!timeout) {
++ if (!timeout) {
+ DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+@@ -8040,7 +8010,7 @@ e1000_get_auto_rd_done(struct e1000_hw *
+ * Need to wait for PHY configuration completion before accessing NVM
+ * and PHY. */
+ if (hw->mac_type == e1000_82573)
+- msec_delay(25);
++ msleep(25);
+
+ return E1000_SUCCESS;
+ }
+@@ -8064,7 +8034,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *
+
+ switch (hw->mac_type) {
+ default:
+- msec_delay_irq(10);
++ mdelay(10);
+ break;
+ case e1000_80003es2lan:
+ /* Separate *_CFG_DONE_* bit for each port */
+@@ -8077,10 +8047,9 @@ e1000_get_phy_cfg_done(struct e1000_hw *
+ if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+ break;
+ else
+- msec_delay(1);
++ msleep(1);
+ timeout--;
+ }
+-
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+@@ -8110,7 +8079,7 @@ e1000_get_hw_eeprom_semaphore(struct e10
+
+ DEBUGFUNC("e1000_get_hw_eeprom_semaphore");
+
+- if(!hw->eeprom_semaphore_present)
++ if (!hw->eeprom_semaphore_present)
+ return E1000_SUCCESS;
+
+ if (hw->mac_type == e1000_80003es2lan) {
+@@ -8121,20 +8090,20 @@ e1000_get_hw_eeprom_semaphore(struct e10
+
+ /* Get the FW semaphore. */
+ timeout = hw->eeprom.word_size + 1;
+- while(timeout) {
++ while (timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ swsm |= E1000_SWSM_SWESMBI;
+ E1000_WRITE_REG(hw, SWSM, swsm);
+ /* if we managed to set the bit we got the semaphore. */
+ swsm = E1000_READ_REG(hw, SWSM);
+- if(swsm & E1000_SWSM_SWESMBI)
++ if (swsm & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ timeout--;
+ }
+
+- if(!timeout) {
++ if (!timeout) {
+ /* Release semaphores */
+ e1000_put_hw_eeprom_semaphore(hw);
+ DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
+@@ -8159,7 +8128,7 @@ e1000_put_hw_eeprom_semaphore(struct e10
+
+ DEBUGFUNC("e1000_put_hw_eeprom_semaphore");
+
+- if(!hw->eeprom_semaphore_present)
++ if (!hw->eeprom_semaphore_present)
+ return;
+
+ swsm = E1000_READ_REG(hw, SWSM);
+@@ -8189,19 +8158,20 @@ e1000_get_software_semaphore(struct e100
+
+ DEBUGFUNC("e1000_get_software_semaphore");
+
+- if (hw->mac_type != e1000_80003es2lan)
++ if (hw->mac_type != e1000_80003es2lan) {
+ return E1000_SUCCESS;
++ }
+
+- while(timeout) {
++ while (timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* If SMBI bit cleared, it is now set and we hold the semaphore */
+- if(!(swsm & E1000_SWSM_SMBI))
++ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+- msec_delay_irq(1);
++ mdelay(1);
+ timeout--;
+ }
+
+- if(!timeout) {
++ if (!timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_RESET;
+ }
+@@ -8223,8 +8193,9 @@ e1000_release_software_semaphore(struct
+
+ DEBUGFUNC("e1000_release_software_semaphore");
+
+- if (hw->mac_type != e1000_80003es2lan)
++ if (hw->mac_type != e1000_80003es2lan) {
+ return;
++ }
+
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* Release the SW semaphores.*/
+@@ -8258,7 +8229,7 @@ e1000_check_phy_reset_block(struct e1000
+ if (hw->mac_type > e1000_82547_rev_2)
+ manc = E1000_READ_REG(hw, MANC);
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+- E1000_BLK_PHY_RESET : E1000_SUCCESS;
++ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+ }
+
+ static uint8_t
+@@ -8277,7 +8248,7 @@ e1000_arc_subsystem_valid(struct e1000_h
+ case e1000_82573:
+ case e1000_80003es2lan:
+ fwsm = E1000_READ_REG(hw, FWSM);
+- if((fwsm & E1000_FWSM_MODE_MASK) != 0)
++ if ((fwsm & E1000_FWSM_MODE_MASK) != 0)
+ return TRUE;
+ break;
+ case e1000_ich8lan:
+@@ -8356,7 +8327,7 @@ e1000_get_software_flag(struct e1000_hw
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+- msec_delay_irq(1);
++ mdelay(1);
+ timeout--;
+ }
+
+@@ -8394,66 +8365,6 @@ e1000_release_software_flag(struct e1000
+ return;
+ }
+
+-/***************************************************************************
+- *
+- * Disable dynamic power down mode in ife PHY.
+- * It can be used to workaround band-gap problem.
+- *
+- * hw: Struct containing variables accessed by shared code
+- *
+- ***************************************************************************/
+-#if 0
+-int32_t
+-e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw)
+-{
+- uint16_t phy_data;
+- int32_t ret_val = E1000_SUCCESS;
+-
+- DEBUGFUNC("e1000_ife_disable_dynamic_power_down");
+-
+- if (hw->phy_type == e1000_phy_ife) {
+- ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+- if (ret_val)
+- return ret_val;
+-
+- phy_data |= IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+- ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+- }
+-
+- return ret_val;
+-}
+-#endif /* 0 */
+-
+-/***************************************************************************
+- *
+- * Enable dynamic power down mode in ife PHY.
+- * It can be used to workaround band-gap problem.
+- *
+- * hw: Struct containing variables accessed by shared code
+- *
+- ***************************************************************************/
+-#if 0
+-int32_t
+-e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw)
+-{
+- uint16_t phy_data;
+- int32_t ret_val = E1000_SUCCESS;
+-
+- DEBUGFUNC("e1000_ife_enable_dynamic_power_down");
+-
+- if (hw->phy_type == e1000_phy_ife) {
+- ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+- if (ret_val)
+- return ret_val;
+-
+- phy_data &= ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+- ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+- }
+-
+- return ret_val;
+-}
+-#endif /* 0 */
+-
+ /******************************************************************************
+ * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
+ * register.
+@@ -8849,20 +8760,22 @@ static int32_t
+ e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
+ {
+ int32_t error = E1000_SUCCESS;
+- int32_t program_retries;
+- uint8_t temp_byte;
++ int32_t program_retries = 0;
+
+- e1000_write_ich8_byte(hw, index, byte);
+- udelay(100);
++ DEBUGOUT2("Byte := %2.2X Offset := %d\n", byte, index);
+
+- for (program_retries = 0; program_retries < 100; program_retries++) {
+- e1000_read_ich8_byte(hw, index, &temp_byte);
+- if (temp_byte == byte)
+- break;
+- udelay(10);
+- e1000_write_ich8_byte(hw, index, byte);
+- udelay(100);
++ error = e1000_write_ich8_byte(hw, index, byte);
++
++ if (error != E1000_SUCCESS) {
++ for (program_retries = 0; program_retries < 100; program_retries++) {
++ DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %d\n", byte, index);
++ error = e1000_write_ich8_byte(hw, index, byte);
++ udelay(100);
++ if (error == E1000_SUCCESS)
++ break;
++ }
+ }
++
+ if (program_retries == 100)
+ error = E1000_ERR_EEPROM;
+
+@@ -8903,39 +8816,27 @@ e1000_read_ich8_word(struct e1000_hw *hw
+ }
+
+ /******************************************************************************
+- * Writes a word to the NVM using the ICH8 flash access registers.
++ * Erases the bank specified. Each bank may be a 4, 8 or 64k block. Banks are 0
++ * based.
+ *
+ * hw - pointer to e1000_hw structure
+- * index - The starting byte index of the word to read.
+- * data - The word to write to the NVM.
+- *****************************************************************************/
+-#if 0
+-int32_t
+-e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data)
+-{
+- int32_t status = E1000_SUCCESS;
+- status = e1000_write_ich8_data(hw, index, 2, data);
+- return status;
+-}
+-#endif /* 0 */
+-
+-/******************************************************************************
+- * Erases the bank specified. Each bank is a 4k block. Segments are 0 based.
+- * segment N is 4096 * N + flash_reg_addr.
++ * bank - 0 for first bank, 1 for second bank
+ *
+- * hw - pointer to e1000_hw structure
+- * segment - 0 for first segment, 1 for second segment, etc.
++ * Note that this function may actually erase as much as 8 or 64 KBytes. The
++ * amount of NVM used in each bank is a *minimum* of 4 KBytes, but in fact the
++ * bank size may be 4, 8 or 64 KBytes
+ *****************************************************************************/
+-static int32_t
+-e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
++int32_t
++e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t bank)
+ {
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ int32_t count = 0;
+ int32_t error = E1000_ERR_EEPROM;
+- int32_t iteration, seg_size;
+- int32_t sector_size;
++ int32_t iteration;
++ int32_t sub_sector_size = 0;
++ int32_t bank_size;
+ int32_t j = 0;
+ int32_t error_flag = 0;
+
+@@ -8944,22 +8845,27 @@ e1000_erase_ich8_4k_segment(struct e1000
+ /* Determine HW Sector size: Read BERASE bits of Hw flash Status register */
+ /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector can be
+- * calculated as = segment * 4096 + n * 256
++ * calculated as bank * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+- * as = segment * 4096
+- * 10: Error condition
+- * 11: The Hw sector size is much bigger than the size asked to
+- * erase...error condition */
++ * as bank * 4096
++ * 10: The HW sector is 8K bytes
++ * 11: The Hw sector size is 64K bytes */
+ if (hsfsts.hsf_status.berasesz == 0x0) {
+ /* Hw sector size 256 */
+- sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256;
++ sub_sector_size = ICH8_FLASH_SEG_SIZE_256;
++ bank_size = ICH8_FLASH_SECTOR_SIZE;
+ iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256;
+ } else if (hsfsts.hsf_status.berasesz == 0x1) {
+- sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K;
++ bank_size = ICH8_FLASH_SEG_SIZE_4K;
++ iteration = 1;
++ } else if (hw->mac_type != e1000_ich8lan &&
++ hsfsts.hsf_status.berasesz == 0x2) {
++ /* 8K erase size invalid for ICH8 - added in for ICH9 */
++ bank_size = ICH9_FLASH_SEG_SIZE_8K;
+ iteration = 1;
+ } else if (hsfsts.hsf_status.berasesz == 0x3) {
+- sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K;
++ bank_size = ICH8_FLASH_SEG_SIZE_64K;
+ iteration = 1;
+ } else {
+ return error;
+@@ -8983,16 +8889,15 @@ e1000_erase_ich8_4k_segment(struct e1000
+
+ /* Write the last 24 bits of an index within the block into Flash
+ * Linear address field in Flash Address. This probably needs to
+- * be calculated here based off the on-chip segment size and the
+- * software segment size assumed (4K) */
+- /* TBD */
+- flash_linear_address = segment * sector_size + j * seg_size;
+- flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
++ * be calculated here based off the on-chip erase sector size and
++ * the software bank size (4, 8 or 64 KBytes) */
++ flash_linear_address = bank * bank_size + j * sub_sector_size;
+ flash_linear_address += hw->flash_base_addr;
++ flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+- error = e1000_ich8_flash_cycle(hw, 1000000);
++ error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_ERASE_TIMEOUT);
+ /* Check if FCERR is set to 1. If 1, clear it and try the whole
+ * sequence a few more times else Done */
+ if (error == E1000_SUCCESS) {
+@@ -9016,44 +8921,6 @@ e1000_erase_ich8_4k_segment(struct e1000
+ return error;
+ }
+
+-/******************************************************************************
+- *
+- * Reverse duplex setting without breaking the link.
+- *
+- * hw: Struct containing variables accessed by shared code
+- *
+- *****************************************************************************/
+-#if 0
+-int32_t
+-e1000_duplex_reversal(struct e1000_hw *hw)
+-{
+- int32_t ret_val;
+- uint16_t phy_data;
+-
+- if (hw->phy_type != e1000_phy_igp_3)
+- return E1000_SUCCESS;
+-
+- ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+- if (ret_val)
+- return ret_val;
+-
+- phy_data ^= MII_CR_FULL_DUPLEX;
+-
+- ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+- if (ret_val)
+- return ret_val;
+-
+- ret_val = e1000_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data);
+- if (ret_val)
+- return ret_val;
+-
+- phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET;
+- ret_val = e1000_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data);
+-
+- return ret_val;
+-}
+-#endif /* 0 */
+-
+ static int32_t
+ e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw,
+ uint32_t cnf_base_addr, uint32_t cnf_size)
+@@ -9088,6 +8955,14 @@ e1000_init_lcd_from_nvm_config_region(st
+ }
+
+
++/******************************************************************************
++ * This function initializes the PHY from the NVM on ICH8 platforms. This
++ * is needed due to an issue where the NVM configuration is not properly
++ * autoloaded after power transitions. Therefore, after each PHY reset, we
++ * will load the configuration data out of the NVM manually.
++ *
++ * hw: Struct containing variables accessed by shared code
++ *****************************************************************************/
+ static int32_t
+ e1000_init_lcd_from_nvm(struct e1000_hw *hw)
+ {
+diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
+index 375b955..449a603 100644
+--- a/drivers/net/e1000/e1000_hw.h
++++ b/drivers/net/e1000/e1000_hw.h
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -93,11 +92,11 @@ typedef enum {
+
+ /* Flow Control Settings */
+ typedef enum {
+- e1000_fc_none = 0,
+- e1000_fc_rx_pause = 1,
+- e1000_fc_tx_pause = 2,
+- e1000_fc_full = 3,
+- e1000_fc_default = 0xFF
++ E1000_FC_NONE = 0,
++ E1000_FC_RX_PAUSE = 1,
++ E1000_FC_TX_PAUSE = 2,
++ E1000_FC_FULL = 3,
++ E1000_FC_DEFAULT = 0xFF
+ } e1000_fc_type;
+
+ struct e1000_shadow_ram {
+@@ -302,6 +301,9 @@ typedef enum {
+ #define E1000_BLK_PHY_RESET 12
+ #define E1000_ERR_SWFW_SYNC 13
+
++#define E1000_BYTE_SWAP_WORD(_value) ((((_value) & 0x00ff) << 8) | \
++ (((_value) & 0xff00) >> 8))
++
+ /* Function prototypes */
+ /* Initialization */
+ int32_t e1000_reset_hw(struct e1000_hw *hw);
+@@ -314,7 +316,7 @@ int32_t e1000_setup_link(struct e1000_hw
+ int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
+ void e1000_config_collision_dist(struct e1000_hw *hw);
+ int32_t e1000_check_for_link(struct e1000_hw *hw);
+-int32_t e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
++int32_t e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed, uint16_t *duplex);
+ int32_t e1000_force_mac_fc(struct e1000_hw *hw);
+
+ /* PHY */
+@@ -322,9 +324,9 @@ int32_t e1000_read_phy_reg(struct e1000_
+ int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+ int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
+ int32_t e1000_phy_reset(struct e1000_hw *hw);
+-void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
+ int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+ int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
++void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
+
+ /* EEPROM Functions */
+ int32_t e1000_init_eeprom_params(struct e1000_hw *hw);
+@@ -336,9 +338,9 @@ uint32_t e1000_enable_mng_pass_thru(stru
+ #define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 /* Host Interface data length */
+
+ #define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 /* Time in ms to process MNG command */
+-#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */
+-#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */
+-#define E1000_MNG_IAMT_MODE 0x3
++#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */
++#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */
++#define E1000_MNG_IAMT_MODE 0x3
+ #define E1000_MNG_ICH_IAMT_MODE 0x2
+ #define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */
+
+@@ -385,7 +387,7 @@ struct e1000_host_mng_dhcp_cookie{
+ #endif
+
+ int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer,
+- uint16_t length);
++ uint16_t length);
+ boolean_t e1000_check_mng_mode(struct e1000_hw *hw);
+ boolean_t e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
+
+@@ -393,7 +395,6 @@ int32_t e1000_read_eeprom(struct e1000_h
+ int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
+ int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
+ int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
+-int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
+ int32_t e1000_read_mac_addr(struct e1000_hw * hw);
+
+ /* Filters (multicast, vlan, receive) */
+@@ -420,6 +421,7 @@ void e1000_pci_set_mwi(struct e1000_hw *
+ void e1000_pci_clear_mwi(struct e1000_hw *hw);
+ void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+ void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
++int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value);
+ /* Port I/O is only supported on 82544 and newer */
+ void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value);
+ int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
+@@ -470,6 +472,7 @@ int32_t e1000_check_phy_reset_block(stru
+ #define E1000_DEV_ID_82571EB_COPPER 0x105E
+ #define E1000_DEV_ID_82571EB_FIBER 0x105F
+ #define E1000_DEV_ID_82571EB_SERDES 0x1060
++#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+ #define E1000_DEV_ID_82572EI_COPPER 0x107D
+ #define E1000_DEV_ID_82572EI_FIBER 0x107E
+ #define E1000_DEV_ID_82572EI_SERDES 0x107F
+@@ -523,7 +526,7 @@ int32_t e1000_check_phy_reset_block(stru
+
+
+ /* 802.1q VLAN Packet Sizes */
+-#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */
++#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */
+
+ /* Ethertype field values */
+ #define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */
+@@ -573,10 +576,10 @@ int32_t e1000_check_phy_reset_block(stru
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
+ */
+ #define E1000_RAR_ENTRIES 15
+-#define E1000_RAR_ENTRIES_ICH8LAN 7
++#define E1000_RAR_ENTRIES_ICH8LAN 6
+
+-#define MIN_NUMBER_OF_DESCRIPTORS 8
+-#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
++#define MIN_NUMBER_OF_DESCRIPTORS 8
++#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+ /* Receive Descriptor */
+ struct e1000_rx_desc {
+@@ -697,6 +700,7 @@ union e1000_rx_desc_packet_split {
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
+
++
+ /* Transmit Descriptor */
+ struct e1000_tx_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+@@ -1298,6 +1302,7 @@ struct e1000_hw_stats {
+ uint64_t algnerrc;
+ uint64_t symerrs;
+ uint64_t rxerrc;
++ uint64_t txerrc;
+ uint64_t mpc;
+ uint64_t scc;
+ uint64_t ecol;
+@@ -1330,8 +1335,9 @@ struct e1000_hw_stats {
+ uint64_t gotch;
+ uint64_t rnbc;
+ uint64_t ruc;
+- uint64_t rfc;
+ uint64_t roc;
++ uint64_t rlerrc;
++ uint64_t rfc;
+ uint64_t rjc;
+ uint64_t mgprc;
+ uint64_t mgpdc;
+@@ -1365,8 +1371,8 @@ struct e1000_hw_stats {
+
+ /* Structure containing variables used by the shared code (e1000_hw.c) */
+ struct e1000_hw {
+- uint8_t *hw_addr;
+- uint8_t *flash_address;
++ uint8_t __iomem *hw_addr;
++ uint8_t __iomem *flash_address;
+ e1000_mac_type mac_type;
+ e1000_phy_type phy_type;
+ uint32_t phy_init_script;
+@@ -1438,6 +1444,7 @@ struct e1000_hw {
+ boolean_t tbi_compatibility_on;
+ boolean_t laa_is_present;
+ boolean_t phy_reset_disable;
++ boolean_t initialize_hw_bits_disable;
+ boolean_t fc_send_xon;
+ boolean_t fc_strict_ieee;
+ boolean_t report_tx_early;
+@@ -1611,16 +1618,17 @@ struct e1000_hw {
+ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+ #define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+ #define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
+-#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000
++#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000
+ #define E1000_CTRL_EXT_LINK_MODE_SERDES 0x00C00000
++#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000
+ #define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000
+ #define E1000_CTRL_EXT_WR_WMARK_256 0x00000000
+ #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
+ #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
+ #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+-#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+-#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
+-#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
++#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
++#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
++#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
+ #define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error detection enabled */
+ #define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */
+ #define E1000_CTRL_EXT_GHOST_PAREN 0x40000000
+@@ -1953,9 +1961,9 @@ struct e1000_hw {
+ #define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */
+
+ /* Transmit Descriptor Control */
+-#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
+-#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
+-#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
++#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
++#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
++#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+ #define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
+ #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+ #define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+@@ -2086,7 +2094,7 @@ struct e1000_hw {
+ #define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address
+ * filtering */
+ #define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
+-#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
++#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
+ #define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
+ #define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
+ #define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
+@@ -2172,7 +2180,7 @@ struct e1000_host_command_info {
+
+ #define E1000_MDALIGN 4096
+
+-/* PCI-Ex registers */
++/* PCI-Ex registers*/
+
+ /* PCI-Ex Control Register */
+ #define E1000_GCR_RXD_NO_SNOOP 0x00000001
+@@ -2216,6 +2224,11 @@ struct e1000_host_command_info {
+ #define E1000_FACTPS_LAN_FUNC_SEL 0x40000000
+ #define E1000_FACTPS_PM_STATE_CHANGED 0x80000000
+
++/* PCI-Ex Config Space */
++#define PCI_EX_LINK_STATUS 0x12
++#define PCI_EX_LINK_WIDTH_MASK 0x3F0
++#define PCI_EX_LINK_WIDTH_SHIFT 4
++
+ /* EEPROM Commands - Microwire */
+ #define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
+ #define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
+@@ -2224,7 +2237,7 @@ struct e1000_host_command_info {
+ #define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
+
+ /* EEPROM Commands - SPI */
+-#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
++#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+ #define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
+ #define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
+ #define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+@@ -3082,10 +3095,10 @@ struct e1000_host_command_info {
+
+ /* DSP Distance Register (Page 5, Register 26) */
+ #define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M;
+- 1 = 50-80M;
+- 2 = 80-110M;
+- 3 = 110-140M;
+- 4 = >140M */
++ 1 = 50-80M;
++ 2 = 80-110M;
++ 3 = 110-140M;
++ 4 = >140M */
+
+ /* Kumeran Mode Control Register (Page 193, Register 16) */
+ #define GG82563_KMCR_PHY_LEDS_EN 0x0020 /* 1=PHY LEDs, 0=Kumeran Inband LEDs */
+@@ -3118,6 +3131,7 @@ struct e1000_host_command_info {
+ /* I = Integrated
+ * E = External
+ */
++#define M88_VENDOR 0x0141
+ #define M88E1000_E_PHY_ID 0x01410C50
+ #define M88E1000_I_PHY_ID 0x01410C30
+ #define M88E1011_I_PHY_ID 0x01410C20
+@@ -3242,10 +3256,12 @@ struct e1000_host_command_info {
+ #define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+ #define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+-#define ICH8_FLASH_COMMAND_TIMEOUT 500 /* 500 ms , should be adjusted */
+-#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles , should be adjusted */
++#define ICH8_FLASH_COMMAND_TIMEOUT 5000 /* 5000 uSecs - adjusted */
++#define ICH8_FLASH_ERASE_TIMEOUT 3000000 /* Up to 3 seconds - worst case */
++#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles */
+ #define ICH8_FLASH_SEG_SIZE_256 256
+ #define ICH8_FLASH_SEG_SIZE_4K 4096
++#define ICH9_FLASH_SEG_SIZE_8K 8192
+ #define ICH8_FLASH_SEG_SIZE_64K 65536
+
+ #define ICH8_CYCLE_READ 0x0
+diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
+index 98ef9f8..726ec5e 100644
+--- a/drivers/net/e1000/e1000_main.c
++++ b/drivers/net/e1000/e1000_main.c
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -36,7 +35,7 @@ static char e1000_driver_string[] = "Int
+ #else
+ #define DRIVERNAPI "-NAPI"
+ #endif
+-#define DRV_VERSION "7.1.9-k4"DRIVERNAPI
++#define DRV_VERSION "7.2.9-k4"DRIVERNAPI
+ char e1000_driver_version[] = DRV_VERSION;
+ static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
+
+@@ -99,6 +98,7 @@ static struct pci_device_id e1000_pci_tb
+ INTEL_E1000_ETHERNET_DEVICE(0x1098),
+ INTEL_E1000_ETHERNET_DEVICE(0x1099),
+ INTEL_E1000_ETHERNET_DEVICE(0x109A),
++ INTEL_E1000_ETHERNET_DEVICE(0x10A4),
+ INTEL_E1000_ETHERNET_DEVICE(0x10B5),
+ INTEL_E1000_ETHERNET_DEVICE(0x10B9),
+ INTEL_E1000_ETHERNET_DEVICE(0x10BA),
+@@ -109,16 +109,24 @@ static struct pci_device_id e1000_pci_tb
+
+ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+
++int e1000_up(struct e1000_adapter *adapter);
++void e1000_down(struct e1000_adapter *adapter);
++void e1000_reinit_locked(struct e1000_adapter *adapter);
++void e1000_reset(struct e1000_adapter *adapter);
++int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
++int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
++int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
++void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
++void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
+- struct e1000_tx_ring *txdr);
++ struct e1000_tx_ring *txdr);
+ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
+- struct e1000_rx_ring *rxdr);
++ struct e1000_rx_ring *rxdr);
+ static void e1000_free_tx_resources(struct e1000_adapter *adapter,
+- struct e1000_tx_ring *tx_ring);
++ struct e1000_tx_ring *tx_ring);
+ static void e1000_free_rx_resources(struct e1000_adapter *adapter,
+- struct e1000_rx_ring *rx_ring);
+-
+-/* Local Function Prototypes */
++ struct e1000_rx_ring *rx_ring);
++void e1000_update_stats(struct e1000_adapter *adapter);
+
+ static int e1000_init_module(void);
+ static void e1000_exit_module(void);
+@@ -145,7 +153,7 @@ static int e1000_xmit_frame(struct sk_bu
+ static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
+ static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
+ static int e1000_set_mac(struct net_device *netdev, void *p);
+-static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
++static irqreturn_t e1000_intr(int irq, void *data);
+ static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
+ #ifdef CONFIG_E1000_NAPI
+@@ -171,6 +179,7 @@ static void e1000_alloc_rx_buffers_ps(st
+ static int 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);
++void e1000_set_ethtool_ops(struct net_device *netdev);
+ static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
+ static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
+ static void e1000_tx_timeout(struct net_device *dev);
+@@ -195,6 +204,8 @@ static void e1000_shutdown(struct pci_de
+ static void e1000_netpoll (struct net_device *netdev);
+ #endif
+
++extern void e1000_check_options(struct e1000_adapter *adapter);
++
+ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
+@@ -211,9 +222,9 @@ static struct pci_driver e1000_driver =
+ .id_table = e1000_pci_tbl,
+ .probe = e1000_probe,
+ .remove = __devexit_p(e1000_remove),
++#ifdef CONFIG_PM
+ /* Power Managment Hooks */
+ .suspend = e1000_suspend,
+-#ifdef CONFIG_PM
+ .resume = e1000_resume,
+ #endif
+ .shutdown = e1000_shutdown,
+@@ -245,7 +256,7 @@ e1000_init_module(void)
+
+ printk(KERN_INFO "%s\n", e1000_copyright);
+
+- ret = pci_module_init(&e1000_driver);
++ ret = pci_register_driver(&e1000_driver);
+
+ return ret;
+ }
+@@ -465,13 +476,14 @@ e1000_up(struct e1000_adapter *adapter)
+
+ adapter->tx_queue_len = netdev->tx_queue_len;
+
+- mod_timer(&adapter->watchdog_timer, jiffies);
+-
+ #ifdef CONFIG_E1000_NAPI
+ netif_poll_enable(netdev);
+ #endif
+ e1000_irq_enable(adapter);
+
++ clear_bit(__E1000_DOWN, &adapter->flags);
++
++ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+ return 0;
+ }
+
+@@ -485,7 +497,7 @@ e1000_up(struct e1000_adapter *adapter)
+ *
+ **/
+
+-static void e1000_power_up_phy(struct e1000_adapter *adapter)
++void e1000_power_up_phy(struct e1000_adapter *adapter)
+ {
+ uint16_t mii_reg = 0;
+
+@@ -501,25 +513,48 @@ static void e1000_power_up_phy(struct e1
+
+ static void e1000_power_down_phy(struct e1000_adapter *adapter)
+ {
+- boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
+- e1000_check_mng_mode(&adapter->hw);
+- /* Power down the PHY so no link is implied when interface is down
+- * The PHY cannot be powered down if any of the following is TRUE
++ /* Power down the PHY so no link is implied when interface is down *
++ * The PHY cannot be powered down if any of the following is TRUE *
+ * (a) WoL is enabled
+ * (b) AMT is active
+ * (c) SoL/IDER session is active */
+ if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
+- adapter->hw.mac_type != e1000_ich8lan &&
+- adapter->hw.media_type == e1000_media_type_copper &&
+- !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
+- !mng_mode_enabled &&
+- !e1000_check_phy_reset_block(&adapter->hw)) {
++ adapter->hw.media_type == e1000_media_type_copper) {
+ uint16_t mii_reg = 0;
++
++ switch (adapter->hw.mac_type) {
++ case e1000_82540:
++ case e1000_82545:
++ case e1000_82545_rev_3:
++ case e1000_82546:
++ case e1000_82546_rev_3:
++ case e1000_82541:
++ case e1000_82541_rev_2:
++ case e1000_82547:
++ case e1000_82547_rev_2:
++ if (E1000_READ_REG(&adapter->hw, MANC) &
++ E1000_MANC_SMBUS_EN)
++ goto out;
++ break;
++ case e1000_82571:
++ case e1000_82572:
++ case e1000_82573:
++ case e1000_80003es2lan:
++ case e1000_ich8lan:
++ if (e1000_check_mng_mode(&adapter->hw) ||
++ e1000_check_phy_reset_block(&adapter->hw))
++ goto out;
++ break;
++ default:
++ goto out;
++ }
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+ mdelay(1);
+ }
++out:
++ return;
+ }
+
+ void
+@@ -527,6 +562,10 @@ e1000_down(struct e1000_adapter *adapter
+ {
+ struct net_device *netdev = adapter->netdev;
+
++ /* signal that we're down so the interrupt handler does not
++ * reschedule our watchdog timer */
++ set_bit(__E1000_DOWN, &adapter->flags);
++
+ e1000_irq_disable(adapter);
+
+ del_timer_sync(&adapter->tx_fifo_stall_timer);
+@@ -562,6 +601,9 @@ void
+ e1000_reset(struct e1000_adapter *adapter)
+ {
+ uint32_t pba, manc;
++#ifdef DISABLE_MULR
++ uint32_t tctl;
++#endif
+ uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF;
+
+ /* Repartition Pba for greater than 9k mtu
+@@ -628,6 +670,12 @@ e1000_reset(struct e1000_adapter *adapte
+ e1000_reset_hw(&adapter->hw);
+ if (adapter->hw.mac_type >= e1000_82544)
+ E1000_WRITE_REG(&adapter->hw, WUC, 0);
++#ifdef DISABLE_MULR
++ /* disable Multiple Reads in Transmit Control Register for debugging */
++ tctl = E1000_READ_REG(hw, TCTL);
++ E1000_WRITE_REG(hw, TCTL, tctl & ~E1000_TCTL_MULR);
++
++#endif
+ if (e1000_init_hw(&adapter->hw))
+ DPRINTK(PROBE, ERR, "Hardware Error\n");
+ e1000_update_mng_vlan(adapter);
+@@ -651,9 +699,10 @@ e1000_reset(struct e1000_adapter *adapte
+ phy_data);
+ }
+
+- if (adapter->hw.mac_type < e1000_ich8lan)
+- /* FIXME: this code is duplicate and wrong for PCI Express */
+- if (adapter->en_mng_pt) {
++ if ((adapter->en_mng_pt) &&
++ (adapter->hw.mac_type >= e1000_82540) &&
++ (adapter->hw.mac_type < e1000_82571) &&
++ (adapter->hw.media_type == e1000_media_type_copper)) {
+ manc = E1000_READ_REG(&adapter->hw, MANC);
+ manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
+ E1000_WRITE_REG(&adapter->hw, MANC, manc);
+@@ -682,9 +731,9 @@ e1000_probe(struct pci_dev *pdev,
+ unsigned long flash_start, flash_len;
+
+ static int cards_found = 0;
+- static int e1000_ksp3_port_a = 0; /* global ksp3 port a indication */
++ static int global_quad_port_a = 0; /* global ksp3 port a indication */
+ int i, err, pci_using_dac;
+- uint16_t eeprom_data;
++ uint16_t eeprom_data = 0;
+ uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
+ if ((err = pci_enable_device(pdev)))
+ return err;
+@@ -696,21 +745,20 @@ e1000_probe(struct pci_dev *pdev,
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) &&
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
+ E1000_ERR("No usable DMA configuration, aborting\n");
+- return err;
++ goto err_dma;
+ }
+ pci_using_dac = 0;
+ }
+
+ if ((err = pci_request_regions(pdev, e1000_driver_name)))
+- return err;
++ goto err_pci_reg;
+
+ pci_set_master(pdev);
+
++ err = -ENOMEM;
+ netdev = alloc_etherdev(sizeof(struct e1000_adapter));
+- if (!netdev) {
+- err = -ENOMEM;
++ if (!netdev)
+ goto err_alloc_etherdev;
+- }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+@@ -725,11 +773,10 @@ e1000_probe(struct pci_dev *pdev,
+ mmio_start = pci_resource_start(pdev, BAR_0);
+ mmio_len = pci_resource_len(pdev, BAR_0);
+
++ err = -EIO;
+ adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+- if (!adapter->hw.hw_addr) {
+- err = -EIO;
++ if (!adapter->hw.hw_addr)
+ goto err_ioremap;
+- }
+
+ for (i = BAR_1; i <= BAR_5; i++) {
+ if (pci_resource_len(pdev, i) == 0)
+@@ -761,7 +808,7 @@ e1000_probe(struct pci_dev *pdev,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = e1000_netpoll;
+ #endif
+- strcpy(netdev->name, pci_name(pdev));
++ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+@@ -774,6 +821,7 @@ e1000_probe(struct pci_dev *pdev,
+ if ((err = e1000_sw_init(adapter)))
+ goto err_sw_init;
+
++ err = -EIO;
+ /* Flash BAR mapping must happen after e1000_sw_init
+ * because it depends on mac_type */
+ if ((adapter->hw.mac_type == e1000_ich8lan) &&
+@@ -781,24 +829,13 @@ e1000_probe(struct pci_dev *pdev,
+ flash_start = pci_resource_start(pdev, 1);
+ flash_len = pci_resource_len(pdev, 1);
+ adapter->hw.flash_address = ioremap(flash_start, flash_len);
+- if (!adapter->hw.flash_address) {
+- err = -EIO;
++ if (!adapter->hw.flash_address)
+ goto err_flashmap;
+- }
+ }
+
+- if ((err = e1000_check_phy_reset_block(&adapter->hw)))
++ if (e1000_check_phy_reset_block(&adapter->hw))
+ DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
+
+- /* if ksp3, indicate if it's port a being setup */
+- if (pdev->device == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 &&
+- e1000_ksp3_port_a == 0)
+- adapter->ksp3_port_a = 1;
+- e1000_ksp3_port_a++;
+- /* Reset for multiple KP3 adapters */
+- if (e1000_ksp3_port_a == 4)
+- e1000_ksp3_port_a = 0;
+-
+ if (adapter->hw.mac_type >= e1000_82543) {
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+@@ -830,7 +867,7 @@ e1000_probe(struct pci_dev *pdev,
+
+ if (e1000_init_eeprom_params(&adapter->hw)) {
+ E1000_ERR("EEPROM initialization failed\n");
+- return -EIO;
++ goto err_eeprom;
+ }
+
+ /* before reading the EEPROM, reset the controller to
+@@ -842,7 +879,6 @@ e1000_probe(struct pci_dev *pdev,
+
+ if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
+ DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
+- err = -EIO;
+ goto err_eeprom;
+ }
+
+@@ -855,12 +891,9 @@ e1000_probe(struct pci_dev *pdev,
+
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
+- err = -EIO;
+ goto err_eeprom;
+ }
+
+- e1000_read_part_num(&adapter->hw, &(adapter->part_num));
+-
+ e1000_get_bus_info(&adapter->hw);
+
+ init_timer(&adapter->tx_fifo_stall_timer);
+@@ -878,11 +911,6 @@ e1000_probe(struct pci_dev *pdev,
+ INIT_WORK(&adapter->reset_task,
+ (void (*)(void *))e1000_reset_task, netdev);
+
+- /* we're going to reset, so assume we have no link for now */
+-
+- netif_carrier_off(netdev);
+- netif_stop_queue(netdev);
+-
+ e1000_check_options(adapter);
+
+ /* Initial Wake on LAN setting
+@@ -921,7 +949,38 @@ e1000_probe(struct pci_dev *pdev,
+ break;
+ }
+ if (eeprom_data & eeprom_apme_mask)
+- adapter->wol |= E1000_WUFC_MAG;
++ adapter->eeprom_wol |= E1000_WUFC_MAG;
++
++ /* now that we have the eeprom settings, apply the special cases
++ * where the eeprom may be wrong or the board simply won't support
++ * wake on lan on a particular port */
++ switch (pdev->device) {
++ case E1000_DEV_ID_82546GB_PCIE:
++ adapter->eeprom_wol = 0;
++ break;
++ case E1000_DEV_ID_82546EB_FIBER:
++ case E1000_DEV_ID_82546GB_FIBER:
++ case E1000_DEV_ID_82571EB_FIBER:
++ /* Wake events only supported on port A for dual fiber
++ * regardless of eeprom setting */
++ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1)
++ adapter->eeprom_wol = 0;
++ break;
++ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
++ case E1000_DEV_ID_82571EB_QUAD_COPPER:
++ /* if quad port adapter, disable WoL on all but port A */
++ if (global_quad_port_a != 0)
++ adapter->eeprom_wol = 0;
++ else
++ adapter->quad_port_a = 1;
++ /* Reset for multiple quad port adapters */
++ if (++global_quad_port_a == 4)
++ global_quad_port_a = 0;
++ break;
++ }
++
++ /* initialize the wol settings based on the eeprom settings */
++ adapter->wol = adapter->eeprom_wol;
+
+ /* print bus type/speed/width info */
+ {
+@@ -958,22 +1017,43 @@ e1000_probe(struct pci_dev *pdev,
+ if ((err = register_netdev(netdev)))
+ goto err_register;
+
++ /* tell the stack to leave us alone until e1000_open() is called */
++ netif_carrier_off(netdev);
++ netif_stop_queue(netdev);
++
+ DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n");
+
+ cards_found++;
+ return 0;
+
+ err_register:
++ e1000_release_hw_control(adapter);
++err_eeprom:
++ if (!e1000_check_phy_reset_block(&adapter->hw))
++ e1000_phy_hw_reset(&adapter->hw);
++
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+ err_flashmap:
++#ifdef CONFIG_E1000_NAPI
++ for (i = 0; i < adapter->num_rx_queues; i++)
++ dev_put(&adapter->polling_netdev[i]);
++#endif
++
++ kfree(adapter->tx_ring);
++ kfree(adapter->rx_ring);
++#ifdef CONFIG_E1000_NAPI
++ kfree(adapter->polling_netdev);
++#endif
+ err_sw_init:
+-err_eeprom:
+ iounmap(adapter->hw.hw_addr);
+ err_ioremap:
+ free_netdev(netdev);
+ err_alloc_etherdev:
+ pci_release_regions(pdev);
++err_pci_reg:
++err_dma:
++ pci_disable_device(pdev);
+ return err;
+ }
+
+@@ -1000,8 +1080,8 @@ e1000_remove(struct pci_dev *pdev)
+ flush_scheduled_work();
+
+ if (adapter->hw.mac_type >= e1000_82540 &&
+- adapter->hw.mac_type != e1000_ich8lan &&
+- adapter->hw.media_type == e1000_media_type_copper) {
++ adapter->hw.mac_type < e1000_82571 &&
++ adapter->hw.media_type == e1000_media_type_copper) {
+ manc = E1000_READ_REG(&adapter->hw, MANC);
+ if (manc & E1000_MANC_SMBUS_EN) {
+ manc |= E1000_MANC_ARP_EN;
+@@ -1128,6 +1208,8 @@ e1000_sw_init(struct e1000_adapter *adap
+ atomic_set(&adapter->irq_sem, 1);
+ spin_lock_init(&adapter->stats_lock);
+
++ set_bit(__E1000_DOWN, &adapter->flags);
++
+ return 0;
+ }
+
+@@ -1193,7 +1275,7 @@ e1000_open(struct net_device *netdev)
+ int err;
+
+ /* disallow open during test */
+- if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags))
++ if (test_bit(__E1000_TESTING, &adapter->flags))
+ return -EBUSY;
+
+ /* allocate transmit descriptors */
+@@ -1208,7 +1290,7 @@ e1000_open(struct net_device *netdev)
+
+ err = e1000_request_irq(adapter);
+ if (err)
+- goto err_up;
++ goto err_req_irq;
+
+ e1000_power_up_phy(adapter);
+
+@@ -1229,6 +1311,9 @@ e1000_open(struct net_device *netdev)
+ return E1000_SUCCESS;
+
+ err_up:
++ e1000_power_down_phy(adapter);
++ e1000_free_irq(adapter);
++err_req_irq:
+ e1000_free_all_rx_resources(adapter);
+ err_setup_rx:
+ e1000_free_all_tx_resources(adapter);
+@@ -1263,8 +1348,12 @@ e1000_close(struct net_device *netdev)
+ e1000_free_all_tx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
+
++ /* kill manageability vlan ID if supported, but not if a vlan with
++ * the same ID is registered on the host OS (let 8021q kill it) */
+ if ((adapter->hw.mng_cookie.status &
+- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
++ !(adapter->vlgrp &&
++ adapter->vlgrp->vlan_devices[adapter->mng_vlan_id])) {
+ e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+ }
+
+@@ -1381,10 +1470,6 @@ setup_tx_desc_die:
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+- * If this function returns with an error, then it's possible one or
+- * more of the rings is populated (while the rest are not). It is the
+- * callers duty to clean those orphaned rings.
+- *
+ * Return 0 on success, negative on failure
+ **/
+
+@@ -1398,6 +1483,9 @@ e1000_setup_all_tx_resources(struct e100
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Tx Queue %u failed\n", i);
++ for (i-- ; i >= 0; i--)
++ e1000_free_tx_resources(adapter,
++ &adapter->tx_ring[i]);
+ break;
+ }
+ }
+@@ -1475,32 +1563,17 @@ e1000_configure_tx(struct e1000_adapter
+ /* Program the Transmit Control Register */
+
+ tctl = E1000_READ_REG(hw, TCTL);
+-
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+-#ifdef DISABLE_MULR
+- /* disable Multiple Reads for debugging */
+- tctl &= ~E1000_TCTL_MULR;
+-#endif
+-
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
+ tarc = E1000_READ_REG(hw, TARC0);
+- tarc |= ((1 << 25) | (1 << 21));
++ tarc |= (1 << 21);
+ E1000_WRITE_REG(hw, TARC0, tarc);
+- tarc = E1000_READ_REG(hw, TARC1);
+- tarc |= (1 << 25);
+- if (tctl & E1000_TCTL_MULR)
+- tarc &= ~(1 << 28);
+- else
+- tarc |= (1 << 28);
+- E1000_WRITE_REG(hw, TARC1, tarc);
+ } else if (hw->mac_type == e1000_80003es2lan) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ tarc |= 1;
+- if (hw->media_type == e1000_media_type_internal_serdes)
+- tarc |= (1 << 20);
+ E1000_WRITE_REG(hw, TARC0, tarc);
+ tarc = E1000_READ_REG(hw, TARC1);
+ tarc |= 1;
+@@ -1639,10 +1712,6 @@ setup_rx_desc_die:
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+- * If this function returns with an error, then it's possible one or
+- * more of the rings is populated (while the rest are not). It is the
+- * callers duty to clean those orphaned rings.
+- *
+ * Return 0 on success, negative on failure
+ **/
+
+@@ -1656,6 +1725,9 @@ e1000_setup_all_rx_resources(struct e100
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Rx Queue %u failed\n", i);
++ for (i-- ; i >= 0; i--)
++ e1000_free_rx_resources(adapter,
++ &adapter->rx_ring[i]);
+ break;
+ }
+ }
+@@ -1736,9 +1808,11 @@ e1000_setup_rctl(struct e1000_adapter *a
+ * followed by the page buffers. Therefore, skb->data is
+ * sized to hold the largest protocol header.
+ */
++ /* allocations using alloc_page take too long for regular MTU
++ * so only enable packet split for jumbo frames */
+ pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+- if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) &&
+- PAGE_SIZE <= 16384)
++ if ((adapter->hw.mac_type >= e1000_82571) && (pages <= 3) &&
++ PAGE_SIZE <= 16384 && (rctl & E1000_RCTL_LPE))
+ adapter->rx_ps_pages = pages;
+ else
+ adapter->rx_ps_pages = 0;
+@@ -2442,10 +2516,9 @@ e1000_watchdog(unsigned long data)
+ * disable receives in the ISR and
+ * reset device here in the watchdog
+ */
+- if (adapter->hw.mac_type == e1000_80003es2lan) {
++ if (adapter->hw.mac_type == e1000_80003es2lan)
+ /* reset device */
+ schedule_work(&adapter->reset_task);
+- }
+ }
+
+ e1000_smartspeed(adapter);
+@@ -2545,7 +2618,7 @@ e1000_tso(struct e1000_adapter *adapter,
+ cmd_length = E1000_TXD_CMD_IP;
+ ipcse = skb->h.raw - skb->data - 1;
+ #ifdef NETIF_F_TSO_IPV6
+- } else if (skb->protocol == ntohs(ETH_P_IPV6)) {
++ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ skb->nh.ipv6h->payload_len = 0;
+ skb->h.th->check =
+ ~csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+@@ -2600,7 +2673,7 @@ e1000_tx_csum(struct e1000_adapter *adap
+ unsigned int i;
+ uint8_t css;
+
+- if (likely(skb->ip_summed == CHECKSUM_HW)) {
++ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ css = skb->h.raw - skb->data;
+
+ i = tx_ring->next_to_use;
+@@ -2861,6 +2934,35 @@ e1000_transfer_dhcp_info(struct e1000_ad
+ return 0;
+ }
+
++static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
++{
++ struct e1000_adapter *adapter = netdev_priv(netdev);
++ struct e1000_tx_ring *tx_ring = adapter->tx_ring;
++
++ netif_stop_queue(netdev);
++ /* Herbert's original patch had:
++ * smp_mb__after_netif_stop_queue();
++ * but since that doesn't exist yet, just open code it. */
++ smp_mb();
++
++ /* We need to check again in a case another CPU has just
++ * made room available. */
++ if (likely(E1000_DESC_UNUSED(tx_ring) < size))
++ return -EBUSY;
++
++ /* A reprieve! */
++ netif_start_queue(netdev);
++ return 0;
++}
++
++static int e1000_maybe_stop_tx(struct net_device *netdev,
++ struct e1000_tx_ring *tx_ring, int size)
++{
++ if (likely(E1000_DESC_UNUSED(tx_ring) >= size))
++ return 0;
++ return __e1000_maybe_stop_tx(netdev, size);
++}
++
+ #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
+ static int
+ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+@@ -2879,6 +2981,10 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ unsigned int f;
+ len -= skb->data_len;
+
++ /* This goes back to the question of how to logically map a tx queue
++ * to a flow. Right now, performance is impacted slightly negatively
++ * if using multiple tx queues. If the stack breaks away from a
++ * single qdisc implementation, we can look at this again. */
+ tx_ring = adapter->tx_ring;
+
+ if (unlikely(skb->len <= 0)) {
+@@ -2886,6 +2992,11 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ return NETDEV_TX_OK;
+ }
+
++ /* 82571 and newer doesn't need the workaround that limited descriptor
++ * length to 4kB */
++ if (adapter->hw.mac_type >= e1000_82571)
++ max_per_txd = 8192;
++
+ #ifdef NETIF_F_TSO
+ mss = skb_shinfo(skb)->gso_size;
+ /* The controller does a simple calculation to
+@@ -2927,11 +3038,11 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ }
+
+ /* reserve a descriptor for the offload context */
+- if ((mss) || (skb->ip_summed == CHECKSUM_HW))
++ if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
+ count++;
+ count++;
+ #else
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ count++;
+ #endif
+
+@@ -2974,8 +3085,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
+
+ /* need: count + 2 desc gap to keep tail from touching
+ * head, otherwise try next time */
+- if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) {
+- netif_stop_queue(netdev);
++ if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2))) {
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+@@ -2983,7 +3093,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ if (unlikely(adapter->hw.mac_type == e1000_82547)) {
+ if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
+ netif_stop_queue(netdev);
+- mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
++ mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+@@ -3022,8 +3132,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ netdev->trans_start = jiffies;
+
+ /* Make sure there is space in the ring for the next send. */
+- if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2))
+- netif_stop_queue(netdev);
++ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
+
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ return NETDEV_TX_OK;
+@@ -3100,11 +3209,13 @@ e1000_change_mtu(struct net_device *netd
+ }
+ break;
+ case e1000_82573:
+- /* only enable jumbo frames if ASPM is disabled completely
+- * this means both bits must be zero in 0x1A bits 3:2 */
++ /* Jumbo Frames not supported if:
++ * - this is not an 82573L device
++ * - ASPM is enabled in any way (0x1A bits 3:2) */
+ e1000_read_eeprom(&adapter->hw, EEPROM_INIT_3GIO_3, 1,
+ &eeprom_data);
+- if (eeprom_data & EEPROM_WORD1A_ASPM_MASK) {
++ if ((adapter->hw.device_id != E1000_DEV_ID_82573L) ||
++ (eeprom_data & EEPROM_WORD1A_ASPM_MASK)) {
+ if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ DPRINTK(PROBE, ERR,
+ "Jumbo Frames not supported.\n");
+@@ -3112,6 +3223,8 @@ e1000_change_mtu(struct net_device *netd
+ }
+ break;
+ }
++ /* ERT will be enabled later to enable wire speed receives */
++
+ /* fall through to get support */
+ case e1000_82571:
+ case e1000_82572:
+@@ -3297,16 +3410,15 @@ e1000_update_stats(struct e1000_adapter
+ adapter->stats.crcerrs + adapter->stats.algnerrc +
+ adapter->stats.ruc + adapter->stats.roc +
+ adapter->stats.cexterr;
+- adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+- adapter->stats.roc;
++ adapter->stats.rlerrc = adapter->stats.ruc + adapter->stats.roc;
++ adapter->net_stats.rx_length_errors = adapter->stats.rlerrc;
+ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+ adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+ adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+ /* Tx Errors */
+-
+- adapter->net_stats.tx_errors = adapter->stats.ecol +
+- adapter->stats.latecol;
++ adapter->stats.txerrc = adapter->stats.ecol + adapter->stats.latecol;
++ adapter->net_stats.tx_errors = adapter->stats.txerrc;
+ adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+ adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+ adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+@@ -3335,11 +3447,10 @@ e1000_update_stats(struct e1000_adapter
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+- * @pt_regs: CPU registers structure
+ **/
+
+ static irqreturn_t
+-e1000_intr(int irq, void *data, struct pt_regs *regs)
++e1000_intr(int irq, void *data)
+ {
+ struct net_device *netdev = data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+@@ -3377,7 +3488,9 @@ e1000_intr(int irq, void *data, struct p
+ rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
+ }
+- mod_timer(&adapter->watchdog_timer, jiffies);
++ /* guard against interrupt when we're going down */
++ if (!test_bit(__E1000_DOWN, &adapter->flags))
++ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ #ifdef CONFIG_E1000_NAPI
+@@ -3515,13 +3628,14 @@ e1000_clean_tx_irq(struct e1000_adapter
+ tx_ring->next_to_clean = i;
+
+ #define TX_WAKE_THRESHOLD 32
+- if (unlikely(cleaned && netif_queue_stopped(netdev) &&
+- netif_carrier_ok(netdev))) {
+- spin_lock(&tx_ring->tx_lock);
+- if (netif_queue_stopped(netdev) &&
+- (E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))
++ if (unlikely(cleaned && netif_carrier_ok(netdev) &&
++ E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
++ /* Make sure that anybody stopping the queue after this
++ * sees the new next_to_clean.
++ */
++ smp_mb();
++ if (netif_queue_stopped(netdev))
+ netif_wake_queue(netdev);
+- spin_unlock(&tx_ring->tx_lock);
+ }
+
+ if (adapter->detect_tx_hung) {
+@@ -3608,7 +3722,7 @@ e1000_rx_checksum(struct e1000_adapter *
+ */
+ csum = ntohl(csum ^ 0xFFFF);
+ skb->csum = csum;
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+ adapter->hw_csum_good++;
+ }
+@@ -3672,15 +3786,12 @@ e1000_clean_rx_irq(struct e1000_adapter
+
+ length = le16_to_cpu(rx_desc->length);
+
+- /* adjust length to remove Ethernet CRC */
+- length -= 4;
+-
+ if (unlikely(!(status & E1000_RXD_STAT_EOP))) {
+ /* All receives must fit into a single buffer */
+ E1000_DBG("%s: Receive packet consumed multiple"
+ " buffers\n", netdev->name);
+ /* recycle */
+- buffer_info-> skb = skb;
++ buffer_info->skb = skb;
+ goto next_desc;
+ }
+
+@@ -3702,6 +3813,10 @@ e1000_clean_rx_irq(struct e1000_adapter
+ }
+ }
+
++ /* adjust length to remove Ethernet CRC, this must be
++ * done after the TBI_ACCEPT workaround above */
++ length -= 4;
++
+ /* code added for copybreak, this should improve
+ * performance for small packets with large amounts
+ * of reassembly being done in the stack */
+@@ -3711,7 +3826,6 @@ e1000_clean_rx_irq(struct e1000_adapter
+ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ if (new_skb) {
+ skb_reserve(new_skb, NET_IP_ALIGN);
+- new_skb->dev = netdev;
+ memcpy(new_skb->data - NET_IP_ALIGN,
+ skb->data - NET_IP_ALIGN,
+ length + NET_IP_ALIGN);
+@@ -3978,13 +4092,13 @@ e1000_alloc_rx_buffers(struct e1000_adap
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+- if (!(skb = buffer_info->skb))
+- skb = netdev_alloc_skb(netdev, bufsz);
+- else {
++ skb = buffer_info->skb;
++ if (skb) {
+ skb_trim(skb, 0);
+ goto map_skb;
+ }
+
++ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+@@ -4009,10 +4123,10 @@ e1000_alloc_rx_buffers(struct e1000_adap
+ dev_kfree_skb(skb);
+ dev_kfree_skb(oldskb);
+ break; /* while !buffer_info->skb */
+- } else {
+- /* Use new allocation */
+- dev_kfree_skb(oldskb);
+ }
++
++ /* Use new allocation */
++ dev_kfree_skb(oldskb);
+ }
+ /* Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+@@ -4020,8 +4134,6 @@ e1000_alloc_rx_buffers(struct e1000_adap
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+- skb->dev = netdev;
+-
+ buffer_info->skb = skb;
+ buffer_info->length = adapter->rx_buffer_len;
+ map_skb:
+@@ -4135,8 +4247,6 @@ e1000_alloc_rx_buffers_ps(struct e1000_a
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+- skb->dev = netdev;
+-
+ buffer_info->skb = skb;
+ buffer_info->length = adapter->rx_ps_bsize0;
+ buffer_info->dma = pci_map_single(pdev, skb->data,
+@@ -4386,13 +4496,21 @@ e1000_write_pci_cfg(struct e1000_hw *hw,
+ pci_write_config_word(adapter->pdev, reg, *value);
+ }
+
+-#if 0
+-uint32_t
+-e1000_io_read(struct e1000_hw *hw, unsigned long port)
++int32_t
++e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+ {
+- return inl(port);
++ struct e1000_adapter *adapter = hw->back;
++ uint16_t cap_offset;
++
++ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
++ if (!cap_offset)
++ return -E1000_ERR_CONFIG;
++
++ pci_read_config_word(adapter->pdev, cap_offset + reg, value);
++
++ return E1000_SUCCESS;
+ }
+-#endif /* 0 */
++
+
+ void
+ e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
+@@ -4628,7 +4746,7 @@ e1000_suspend(struct pci_dev *pdev, pm_m
+ e1000_set_multi(netdev);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+- if (adapter->wol & E1000_WUFC_MC) {
++ if (wufc & E1000_WUFC_MC) {
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl |= E1000_RCTL_MPE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+@@ -4667,10 +4785,9 @@ e1000_suspend(struct pci_dev *pdev, pm_m
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+ }
+
+- /* FIXME: this code is incorrect for PCI Express */
+ if (adapter->hw.mac_type >= e1000_82540 &&
+- adapter->hw.mac_type != e1000_ich8lan &&
+- adapter->hw.media_type == e1000_media_type_copper) {
++ adapter->hw.mac_type < e1000_82571 &&
++ adapter->hw.media_type == e1000_media_type_copper) {
+ manc = E1000_READ_REG(&adapter->hw, MANC);
+ if (manc & E1000_MANC_SMBUS_EN) {
+ manc |= E1000_MANC_ARP_EN;
+@@ -4683,6 +4800,9 @@ e1000_suspend(struct pci_dev *pdev, pm_m
+ if (adapter->hw.phy_type == e1000_phy_igp_3)
+ e1000_phy_powerdown_workaround(&adapter->hw);
+
++ if (netif_running(netdev))
++ e1000_free_irq(adapter);
++
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant. */
+ e1000_release_hw_control(adapter);
+@@ -4700,16 +4820,23 @@ e1000_resume(struct pci_dev *pdev)
+ {
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+- uint32_t manc, ret_val;
++ uint32_t manc, err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ e1000_pci_restore_state(adapter);
+- ret_val = pci_enable_device(pdev);
++ if ((err = pci_enable_device(pdev))) {
++ printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n");
++ return err;
++ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
++ if (netif_running(netdev) && (err = e1000_request_irq(adapter)))
++ return err;
++
++ e1000_power_up_phy(adapter);
+ e1000_reset(adapter);
+ E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+
+@@ -4718,10 +4845,9 @@ e1000_resume(struct pci_dev *pdev)
+
+ netif_device_attach(netdev);
+
+- /* FIXME: this code is incorrect for PCI Express */
+ if (adapter->hw.mac_type >= e1000_82540 &&
+- adapter->hw.mac_type != e1000_ich8lan &&
+- adapter->hw.media_type == e1000_media_type_copper) {
++ adapter->hw.mac_type < e1000_82571 &&
++ adapter->hw.media_type == e1000_media_type_copper) {
+ manc = E1000_READ_REG(&adapter->hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(&adapter->hw, MANC, manc);
+@@ -4756,7 +4882,7 @@ e1000_netpoll(struct net_device *netdev)
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ disable_irq(adapter->pdev->irq);
+- e1000_intr(adapter->pdev->irq, netdev, NULL);
++ e1000_intr(adapter->pdev->irq, netdev);
+ e1000_clean_tx_irq(adapter, adapter->tx_ring);
+ #ifndef CONFIG_E1000_NAPI
+ adapter->clean_rx(adapter, adapter->rx_ring);
+@@ -4782,6 +4908,7 @@ static pci_ers_result_t e1000_io_error_d
+
+ if (netif_running(netdev))
+ e1000_down(adapter);
++ pci_disable_device(pdev);
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+@@ -4805,12 +4932,8 @@ static pci_ers_result_t e1000_io_slot_re
+ }
+ pci_set_master(pdev);
+
+- pci_enable_wake(pdev, 3, 0);
+- pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+-
+- /* Perform card reset only on one instance of the card */
+- if (PCI_FUNC (pdev->devfn) != 0)
+- return PCI_ERS_RESULT_RECOVERED;
++ pci_enable_wake(pdev, PCI_D3hot, 0);
++ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ e1000_reset(adapter);
+ E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+@@ -4842,6 +4965,7 @@ static void e1000_io_resume(struct pci_d
+ netif_device_attach(netdev);
+
+ if (adapter->hw.mac_type >= e1000_82540 &&
++ adapter->hw.mac_type < e1000_82571 &&
+ adapter->hw.media_type == e1000_media_type_copper) {
+ manc = E1000_READ_REG(&adapter->hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
+index 2d3e8b0..a464cb2 100644
+--- a/drivers/net/e1000/e1000_osdep.h
++++ b/drivers/net/e1000/e1000_osdep.h
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -42,25 +41,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/sched.h>
+
+-#ifndef msec_delay
+-#define msec_delay(x) do { if(in_interrupt()) { \
+- /* Don't mdelay in interrupt context! */ \
+- BUG(); \
+- } else { \
+- msleep(x); \
+- } } while (0)
+-
+-/* Some workarounds require millisecond delays and are run during interrupt
+- * context. Most notably, when establishing link, the phy may need tweaking
+- * but cannot process phy register reads/writes faster than millisecond
+- * intervals...and we establish link due to a "link status change" interrupt.
+- */
+-#define msec_delay_irq(x) mdelay(x)
+-#endif
+-
+-#define PCI_COMMAND_REGISTER PCI_COMMAND
+-#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+-
+ typedef enum {
+ #undef FALSE
+ FALSE = 0,
+diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
+index 0ef4131..9c3c1ac 100644
+--- a/drivers/net/e1000/e1000_param.c
++++ b/drivers/net/e1000/e1000_param.c
+@@ -1,25 +1,24 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/1000 Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
+ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+@@ -324,7 +323,6 @@ e1000_check_options(struct e1000_adapter
+ DPRINTK(PROBE, NOTICE,
+ "Warning: no configuration for board #%i\n", bd);
+ DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
+- bd = E1000_MAX_NIC;
+ }
+
+ { /* Transmit Descriptor Count */
+@@ -342,9 +340,14 @@ e1000_check_options(struct e1000_adapter
+ opt.arg.r.max = mac_type < e1000_82544 ?
+ E1000_MAX_TXD : E1000_MAX_82544_TXD;
+
+- tx_ring->count = TxDescriptors[bd];
+- e1000_validate_option(&tx_ring->count, &opt, adapter);
+- E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
++ if (num_TxDescriptors > bd) {
++ tx_ring->count = TxDescriptors[bd];
++ e1000_validate_option(&tx_ring->count, &opt, adapter);
++ E1000_ROUNDUP(tx_ring->count,
++ REQ_TX_DESCRIPTOR_MULTIPLE);
++ } else {
++ tx_ring->count = opt.def;
++ }
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ tx_ring[i].count = tx_ring->count;
+ }
+@@ -363,9 +366,14 @@ e1000_check_options(struct e1000_adapter
+ opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
+ E1000_MAX_82544_RXD;
+
+- rx_ring->count = RxDescriptors[bd];
+- e1000_validate_option(&rx_ring->count, &opt, adapter);
+- E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
++ if (num_RxDescriptors > bd) {
++ rx_ring->count = RxDescriptors[bd];
++ e1000_validate_option(&rx_ring->count, &opt, adapter);
++ E1000_ROUNDUP(rx_ring->count,
++ REQ_RX_DESCRIPTOR_MULTIPLE);
++ } else {
++ rx_ring->count = opt.def;
++ }
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ rx_ring[i].count = rx_ring->count;
+ }
+@@ -377,31 +385,39 @@ e1000_check_options(struct e1000_adapter
+ .def = OPTION_ENABLED
+ };
+
+- int rx_csum = XsumRX[bd];
+- e1000_validate_option(&rx_csum, &opt, adapter);
+- adapter->rx_csum = rx_csum;
++ if (num_XsumRX > bd) {
++ int rx_csum = XsumRX[bd];
++ e1000_validate_option(&rx_csum, &opt, adapter);
++ adapter->rx_csum = rx_csum;
++ } else {
++ adapter->rx_csum = opt.def;
++ }
+ }
+ { /* Flow Control */
+
+ struct e1000_opt_list fc_list[] =
+- {{ e1000_fc_none, "Flow Control Disabled" },
+- { e1000_fc_rx_pause,"Flow Control Receive Only" },
+- { e1000_fc_tx_pause,"Flow Control Transmit Only" },
+- { e1000_fc_full, "Flow Control Enabled" },
+- { e1000_fc_default, "Flow Control Hardware Default" }};
++ {{ E1000_FC_NONE, "Flow Control Disabled" },
++ { E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
++ { E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
++ { E1000_FC_FULL, "Flow Control Enabled" },
++ { E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
+
+ struct e1000_option opt = {
+ .type = list_option,
+ .name = "Flow Control",
+ .err = "reading default settings from EEPROM",
+- .def = e1000_fc_default,
++ .def = E1000_FC_DEFAULT,
+ .arg = { .l = { .nr = ARRAY_SIZE(fc_list),
+ .p = fc_list }}
+ };
+
+- int fc = FlowControl[bd];
+- e1000_validate_option(&fc, &opt, adapter);
+- adapter->hw.fc = adapter->hw.original_fc = fc;
++ if (num_FlowControl > bd) {
++ int fc = FlowControl[bd];
++ e1000_validate_option(&fc, &opt, adapter);
++ adapter->hw.fc = adapter->hw.original_fc = fc;
++ } else {
++ adapter->hw.fc = adapter->hw.original_fc = opt.def;
++ }
+ }
+ { /* Transmit Interrupt Delay */
+ struct e1000_option opt = {
+@@ -413,8 +429,13 @@ e1000_check_options(struct e1000_adapter
+ .max = MAX_TXDELAY }}
+ };
+
+- adapter->tx_int_delay = TxIntDelay[bd];
+- e1000_validate_option(&adapter->tx_int_delay, &opt, adapter);
++ if (num_TxIntDelay > bd) {
++ adapter->tx_int_delay = TxIntDelay[bd];
++ e1000_validate_option(&adapter->tx_int_delay, &opt,
++ adapter);
++ } else {
++ adapter->tx_int_delay = opt.def;
++ }
+ }
+ { /* Transmit Absolute Interrupt Delay */
+ struct e1000_option opt = {
+@@ -426,9 +447,13 @@ e1000_check_options(struct e1000_adapter
+ .max = MAX_TXABSDELAY }}
+ };
+
+- adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+- e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
+- adapter);
++ if (num_TxAbsIntDelay > bd) {
++ adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
++ e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
++ adapter);
++ } else {
++ adapter->tx_abs_int_delay = opt.def;
++ }
+ }
+ { /* Receive Interrupt Delay */
+ struct e1000_option opt = {
+@@ -440,8 +465,13 @@ e1000_check_options(struct e1000_adapter
+ .max = MAX_RXDELAY }}
+ };
+
+- adapter->rx_int_delay = RxIntDelay[bd];
+- e1000_validate_option(&adapter->rx_int_delay, &opt, adapter);
++ if (num_RxIntDelay > bd) {
++ adapter->rx_int_delay = RxIntDelay[bd];
++ e1000_validate_option(&adapter->rx_int_delay, &opt,
++ adapter);
++ } else {
++ adapter->rx_int_delay = opt.def;
++ }
+ }
+ { /* Receive Absolute Interrupt Delay */
+ struct e1000_option opt = {
+@@ -453,9 +483,13 @@ e1000_check_options(struct e1000_adapter
+ .max = MAX_RXABSDELAY }}
+ };
+
+- adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+- e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
+- adapter);
++ if (num_RxAbsIntDelay > bd) {
++ adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
++ e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
++ adapter);
++ } else {
++ adapter->rx_abs_int_delay = opt.def;
++ }
+ }
+ { /* Interrupt Throttling Rate */
+ struct e1000_option opt = {
+@@ -467,18 +501,24 @@ e1000_check_options(struct e1000_adapter
+ .max = MAX_ITR }}
+ };
+
+- adapter->itr = InterruptThrottleRate[bd];
+- switch (adapter->itr) {
+- case 0:
+- DPRINTK(PROBE, INFO, "%s turned off\n", opt.name);
+- break;
+- case 1:
+- DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
+- opt.name);
+- break;
+- default:
+- e1000_validate_option(&adapter->itr, &opt, adapter);
+- break;
++ if (num_InterruptThrottleRate > bd) {
++ adapter->itr = InterruptThrottleRate[bd];
++ switch (adapter->itr) {
++ case 0:
++ DPRINTK(PROBE, INFO, "%s turned off\n",
++ opt.name);
++ break;
++ case 1:
++ DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
++ opt.name);
++ break;
++ default:
++ e1000_validate_option(&adapter->itr, &opt,
++ adapter);
++ break;
++ }
++ } else {
++ adapter->itr = opt.def;
+ }
+ }
+ { /* Smart Power Down */
+@@ -489,9 +529,13 @@ e1000_check_options(struct e1000_adapter
+ .def = OPTION_DISABLED
+ };
+
+- int spd = SmartPowerDownEnable[bd];
+- e1000_validate_option(&spd, &opt, adapter);
+- adapter->smart_power_down = spd;
++ if (num_SmartPowerDownEnable > bd) {
++ int spd = SmartPowerDownEnable[bd];
++ e1000_validate_option(&spd, &opt, adapter);
++ adapter->smart_power_down = spd;
++ } else {
++ adapter->smart_power_down = opt.def;
++ }
+ }
+ { /* Kumeran Lock Loss Workaround */
+ struct e1000_option opt = {
+@@ -501,9 +545,13 @@ e1000_check_options(struct e1000_adapter
+ .def = OPTION_ENABLED
+ };
+
++ if (num_KumeranLockLoss > bd) {
+ int kmrn_lock_loss = KumeranLockLoss[bd];
+ e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+ adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
++ } else {
++ adapter->hw.kmrn_lock_loss_workaround_disabled = !opt.def;
++ }
+ }
+
+ switch (adapter->hw.media_type) {
+@@ -530,18 +578,17 @@ static void __devinit
+ e1000_check_fiber_options(struct e1000_adapter *adapter)
+ {
+ int bd = adapter->bd_number;
+- bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+- if ((Speed[bd] != OPTION_UNSET)) {
++ if (num_Speed > bd) {
+ DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
+ "parameter ignored\n");
+ }
+
+- if ((Duplex[bd] != OPTION_UNSET)) {
++ if (num_Duplex > bd) {
+ DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
+ "parameter ignored\n");
+ }
+
+- if ((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) {
++ if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
+ DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
+ "not valid for fiber adapters, "
+ "parameter ignored\n");
+@@ -560,7 +607,6 @@ e1000_check_copper_options(struct e1000_
+ {
+ int speed, dplx, an;
+ int bd = adapter->bd_number;
+- bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+
+ { /* Speed */
+ struct e1000_opt_list speed_list[] = {{ 0, "" },
+@@ -577,8 +623,12 @@ e1000_check_copper_options(struct e1000_
+ .p = speed_list }}
+ };
+
+- speed = Speed[bd];
+- e1000_validate_option(&speed, &opt, adapter);
++ if (num_Speed > bd) {
++ speed = Speed[bd];
++ e1000_validate_option(&speed, &opt, adapter);
++ } else {
++ speed = opt.def;
++ }
+ }
+ { /* Duplex */
+ struct e1000_opt_list dplx_list[] = {{ 0, "" },
+@@ -600,11 +650,15 @@ e1000_check_copper_options(struct e1000_
+ "Speed/Duplex/AutoNeg parameter ignored.\n");
+ return;
+ }
+- dplx = Duplex[bd];
+- e1000_validate_option(&dplx, &opt, adapter);
++ if (num_Duplex > bd) {
++ dplx = Duplex[bd];
++ e1000_validate_option(&dplx, &opt, adapter);
++ } else {
++ dplx = opt.def;
++ }
+ }
+
+- if (AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) {
++ if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
+ DPRINTK(PROBE, INFO,
+ "AutoNeg specified along with Speed or Duplex, "
+ "parameter ignored\n");
+@@ -653,15 +707,19 @@ e1000_check_copper_options(struct e1000_
+ .p = an_list }}
+ };
+
+- an = AutoNeg[bd];
+- e1000_validate_option(&an, &opt, adapter);
++ if (num_AutoNeg > bd) {
++ an = AutoNeg[bd];
++ e1000_validate_option(&an, &opt, adapter);
++ } else {
++ an = opt.def;
++ }
+ adapter->hw.autoneg_advertised = an;
+ }
+
+ switch (speed + dplx) {
+ case 0:
+ adapter->hw.autoneg = adapter->fc_autoneg = 1;
+- if (Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
++ if ((num_Speed > bd) && (speed != 0 || dplx != 0))
+ DPRINTK(PROBE, INFO,
+ "Speed and duplex autonegotiation enabled\n");
+ break;
+diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
+index e4e733a..d39e848 100644
+--- a/drivers/net/e2100.c
++++ b/drivers/net/e2100.c
+@@ -110,7 +110,7 @@ static void e21_get_8390_hdr(struct net_
+
+ static int e21_close(struct net_device *dev);
+
+-
++
+ /* Probe for the E2100 series ethercards. These cards have an 8390 at the
+ base address and the station address at both offset 0x10 and 0x18. I read
+ the station address from offset 0x18 to avoid the dataport of NE2000
+@@ -403,7 +403,7 @@ e21_close(struct net_device *dev)
+ return 0;
+ }
+
+-
++
+ #ifdef MODULE
+ #define MAX_E21_CARDS 4 /* Max number of E21 cards per module */
+ static struct net_device *dev_e21[MAX_E21_CARDS];
+diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
+index 8dc61d6..a4eb0dc 100644
+--- a/drivers/net/eepro.c
++++ b/drivers/net/eepro.c
+@@ -154,7 +154,7 @@ static const char version[] =
+ #include <asm/dma.h>
+
+ #define DRV_NAME "eepro"
+-#define DRV_VERSION "0.13b"
++#define DRV_VERSION "0.13c"
+
+ #define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
+ /* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
+@@ -311,7 +311,7 @@ struct eepro_local {
+ static int eepro_probe1(struct net_device *dev, int autoprobe);
+ static int eepro_open(struct net_device *dev);
+ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t eepro_interrupt(int irq, void *dev_id);
+ static void eepro_rx(struct net_device *dev);
+ static void eepro_transmit_interrupt(struct net_device *dev);
+ static int eepro_close(struct net_device *dev);
+@@ -743,7 +743,7 @@ static void __init eepro_print_info (str
+ printEEPROMInfo(dev);
+ }
+
+-static struct ethtool_ops eepro_ethtool_ops;
++static const struct ethtool_ops eepro_ethtool_ops;
+
+ /* This is the real probe routine. Linux has a history of friendly device
+ probes on the ISA bus. A good device probe avoids doing writes, and
+@@ -994,16 +994,6 @@ static int eepro_open(struct net_device
+ return -EAGAIN;
+ }
+
+-#ifdef irq2dev_map
+- if (((irq2dev_map[dev->irq] != 0)
+- || (irq2dev_map[dev->irq] = dev) == 0) &&
+- (irq2dev_map[dev->irq]!=dev)) {
+- /* printk("%s: IRQ map wrong\n", dev->name); */
+- free_irq(dev->irq, dev);
+- return -EAGAIN;
+- }
+-#endif
+-
+ /* Initialize the 82595. */
+
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+@@ -1196,19 +1186,13 @@ static int eepro_send_packet(struct sk_b
+ Handle the network interface interrupts. */
+
+ static irqreturn_t
+-eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++eepro_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *)dev_id;
+- /* (struct net_device *)(irq2dev_map[irq]);*/
++ struct net_device *dev = dev_id;
+ struct eepro_local *lp;
+ int ioaddr, status, boguscount = 20;
+ int handled = 0;
+
+- if (dev == NULL) {
+- printk (KERN_ERR "eepro_interrupt(): irq %d for unknown device.\\n", irq);
+- return IRQ_NONE;
+- }
+-
+ lp = netdev_priv(dev);
+
+ spin_lock(&lp->lock);
+@@ -1288,10 +1272,6 @@ static int eepro_close(struct net_device
+ /* release the interrupt */
+ free_irq(dev->irq, dev);
+
+-#ifdef irq2dev_map
+- irq2dev_map[dev->irq] = 0;
+-#endif
+-
+ /* Update the statistics here. What statistics? */
+
+ return 0;
+@@ -1333,7 +1313,6 @@ set_multicast_list(struct net_device *de
+ mode = inb(ioaddr + REG3);
+ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+- printk(KERN_INFO "%s: promiscuous mode enabled.\n", dev->name);
+ }
+
+ else if (dev->mc_count==0 )
+@@ -1772,7 +1751,7 @@ static void eepro_ethtool_get_drvinfo(st
+ sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
+ }
+
+-static struct ethtool_ops eepro_ethtool_ops = {
++static const struct ethtool_ops eepro_ethtool_ops = {
+ .get_settings = eepro_ethtool_get_settings,
+ .get_drvinfo = eepro_ethtool_get_drvinfo,
+ };
+diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
+index e445988..e28bb1e 100644
+--- a/drivers/net/eepro100.c
++++ b/drivers/net/eepro100.c
+@@ -488,15 +488,15 @@ static int speedo_start_xmit(struct sk_b
+ static void speedo_refill_rx_buffers(struct net_device *dev, int force);
+ static int speedo_rx(struct net_device *dev);
+ static void speedo_tx_buffer_gc(struct net_device *dev);
+-static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t speedo_interrupt(int irq, void *dev_instance);
+ static int speedo_close(struct net_device *dev);
+ static struct net_device_stats *speedo_get_stats(struct net_device *dev);
+ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static void set_rx_mode(struct net_device *dev);
+ static void speedo_show_state(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
++
+
+-
+
+ #ifdef honor_default_port
+ /* Optional driver feature to allow forcing the transceiver setting.
+@@ -606,7 +606,7 @@ static void poll_speedo (struct net_devi
+ /* disable_irq is not very nice, but with the funny lockless design
+ we have no other choice. */
+ disable_irq(dev->irq);
+- speedo_interrupt (dev->irq, dev, NULL);
++ speedo_interrupt (dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -646,7 +646,7 @@ static int __devinit speedo_found1(struc
+ option = 0;
+
+ rtnl_lock();
+- if (dev_alloc_name(dev, dev->name) < 0)
++ if (dev_alloc_name(dev, dev->name) < 0)
+ goto err_free_unlock;
+
+ /* Read the station address EEPROM before doing the reset.
+@@ -825,10 +825,10 @@ static int __devinit speedo_found1(struc
+ sp->mii_if.dev = dev;
+ sp->mii_if.mdio_read = mdio_read;
+ sp->mii_if.mdio_write = mdio_write;
+-
++
+ sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
+- if (((pdev->device > 0x1030 && (pdev->device < 0x103F)))
+- || (pdev->device == 0x2449) || (pdev->device == 0x2459)
++ if (((pdev->device > 0x1030 && (pdev->device < 0x103F)))
++ || (pdev->device == 0x2449) || (pdev->device == 0x2459)
+ || (pdev->device == 0x245D)) {
+ sp->chip_id = 1;
+ }
+@@ -1208,7 +1208,7 @@ static void speedo_show_state(struct net
+ int i;
+
+ if (netif_msg_pktdata(sp)) {
+- printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n",
++ printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n",
+ dev->name, sp->cur_tx, sp->dirty_tx);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name,
+@@ -1541,7 +1541,7 @@ static void speedo_tx_buffer_gc(struct n
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t speedo_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct speedo_private *sp;
+@@ -1586,7 +1586,7 @@ static irqreturn_t speedo_interrupt(int
+
+ /* Always check if all rx buffers are allocated. --SAW */
+ speedo_refill_rx_buffers(dev, 0);
+-
++
+ spin_lock(&sp->lock);
+ /*
+ * The chip may have suspended reception for various reasons.
+@@ -1607,8 +1607,8 @@ static irqreturn_t speedo_interrupt(int
+ /* these are all reserved values */
+ break;
+ }
+-
+-
++
++
+ /* User interrupt, Command/Tx unit interrupt or CU not active. */
+ if (status & 0xA400) {
+ speedo_tx_buffer_gc(dev);
+@@ -1619,7 +1619,7 @@ static irqreturn_t speedo_interrupt(int
+ netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */
+ }
+ }
+-
++
+ spin_unlock(&sp->lock);
+
+ if (--boguscnt < 0) {
+@@ -2015,7 +2015,7 @@ static void speedo_set_msglevel(struct n
+ sp->msg_enable = v;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = speedo_get_drvinfo,
+ .get_settings = speedo_get_settings,
+ .set_settings = speedo_set_settings,
+@@ -2263,7 +2263,7 @@ static void set_rx_mode(struct net_devic
+
+ sp->rx_mode = new_rx_mode;
+ }
+-
++
+ #ifdef CONFIG_PM
+ static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state)
+ {
+@@ -2275,12 +2275,12 @@ static int eepro100_suspend(struct pci_d
+
+ if (!netif_running(dev))
+ return 0;
+-
++
+ del_timer_sync(&sp->timer);
+
+ netif_device_detach(dev);
+ iowrite32(PortPartialReset, ioaddr + SCBPort);
+-
++
+ /* XXX call pci_set_power_state ()? */
+ pci_disable_device(pdev);
+ pci_set_power_state (pdev, PCI_D3hot);
+@@ -2324,7 +2324,7 @@ static void __devexit eepro100_remove_on
+ {
+ struct net_device *dev = pci_get_drvdata (pdev);
+ struct speedo_private *sp = netdev_priv(dev);
+-
++
+ unregister_netdev(dev);
+
+ release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+@@ -2337,7 +2337,7 @@ static void __devexit eepro100_remove_on
+ pci_disable_device(pdev);
+ free_netdev(dev);
+ }
+-
++
+ static struct pci_device_id eepro100_pci_tbl[] = {
+ { PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, },
+@@ -2368,7 +2368,7 @@ static struct pci_device_id eepro100_pci
+ { 0,}
+ };
+ MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
+-
++
+ static struct pci_driver eepro100_driver = {
+ .name = "eepro100",
+ .id_table = eepro100_pci_tbl,
+@@ -2385,7 +2385,7 @@ static int __init eepro100_init_module(v
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init(&eepro100_driver);
++ return pci_register_driver(&eepro100_driver);
+ }
+
+ static void __exit eepro100_cleanup_module(void)
+@@ -2395,7 +2395,7 @@ static void __exit eepro100_cleanup_modu
+
+ module_init(eepro100_init_module);
+ module_exit(eepro100_cleanup_module);
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
+index 0701c1d..e14be02 100644
+--- a/drivers/net/eexpress.c
++++ b/drivers/net/eexpress.c
+@@ -77,7 +77,7 @@
+ * CU before submitting a packet for transmission, and then restarts it as soon
+ * as the process of handing the packet is complete. This is definitely an
+ * unnecessary slowdown if the card is running in 16-bit mode; therefore one
+- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
++ * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
+ * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
+ * ftp's, which is significantly better than I get in DOS, so the overhead of
+ * stopping and restarting the CU with each transmit is not prohibitive in
+@@ -96,7 +96,7 @@
+ #ifndef LOCKUP16
+ #define LOCKUP16 0
+ #endif
+-
++
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+@@ -177,7 +177,7 @@ static unsigned short start_code[] = {
+
+ /* 0x20 -- start of 82586 CU program */
+ #define CONF_LINK 0x20
+- 0x0000,Cmd_Config,
++ 0x0000,Cmd_Config,
+ 0x0032, /* link to next command */
+ 0x080c, /* 12 bytes follow : fifo threshold=8 */
+ 0x2e40, /* don't rx bad frames
+@@ -187,10 +187,10 @@ static unsigned short start_code[] = {
+ */
+ 0x6000, /* default backoff method & priority
+ * interframe spacing = 0x60 */
+- 0xf200, /* slot time=0x200
++ 0xf200, /* slot time=0x200
+ * max collision retry = 0xf */
+ #define CONF_PROMISC 0x2e
+- 0x0000, /* no HDLC : normal CRC : enable broadcast
++ 0x0000, /* no HDLC : normal CRC : enable broadcast
+ * disable promiscuous/multicast modes */
+ 0x003c, /* minimum frame length = 60 octets) */
+
+@@ -237,7 +237,7 @@ static unsigned short mca_iomap[] = {
+ };
+ /* bits 5-7 of the second POS register */
+ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
+-#endif
++#endif
+
+ /*
+ * Prototypes for Linux interface
+@@ -249,7 +249,7 @@ static void eexp_timeout(struct net_devi
+ static struct net_device_stats *eexp_stats(struct net_device *dev);
+ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev);
+
+-static irqreturn_t eexp_irq(int irq, void *dev_addr, struct pt_regs *regs);
++static irqreturn_t eexp_irq(int irq, void *dev_addr);
+ static void eexp_set_multicast(struct net_device *dev);
+
+ /*
+@@ -356,7 +356,7 @@ static int __init do_express_probe(struc
+ */
+ while (slot != MCA_NOTFOUND) {
+ int pos0, pos1;
+-
++
+ slot = mca_find_unused_adapter(0x628B, slot);
+ if (slot == MCA_NOTFOUND)
+ break;
+@@ -366,10 +366,10 @@ static int __init do_express_probe(struc
+ ioaddr = mca_iomap[pos1&0xf];
+
+ dev->irq = mca_irqmap[(pos1>>4)&0x7];
+-
++
+ /*
+ * XXX: Transciever selection is done
+- * differently on the MCA version.
++ * differently on the MCA version.
+ * How to get it to select something
+ * other than external/AUI is currently
+ * unknown. This code is just for looks. -- ASF
+@@ -482,7 +482,7 @@ static int eexp_open(struct net_device *
+ , ioaddr+0xc000);
+ goto err_out4;
+ }
+-
++
+ if (lp->width) {
+ printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
+ outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
+@@ -518,7 +518,7 @@ static int eexp_close(struct net_device
+ int irq = dev->irq;
+
+ netif_stop_queue(dev);
+-
++
+ outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+ lp->started = 0;
+ scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
+@@ -630,14 +630,14 @@ static void eexp_timeout(struct net_devi
+ unsigned long flags;
+ #endif
+ int status;
+-
++
+ disable_irq(dev->irq);
+
+ /*
+ * Best would be to use synchronize_irq(); spin_lock() here
+ * lets make it work first..
+ */
+-
++
+ #ifdef CONFIG_SMP
+ spin_lock_irqsave(&lp->lock, flags);
+ #endif
+@@ -653,7 +653,7 @@ static void eexp_timeout(struct net_devi
+ scb_command(dev, SCB_CUabort);
+ outb(0,dev->base_addr+SIGNAL_CA);
+ }
+- netif_wake_queue(dev);
++ netif_wake_queue(dev);
+ #ifdef CONFIG_SMP
+ spin_unlock_irqrestore(&lp->lock, flags);
+ #endif
+@@ -687,11 +687,11 @@ static int eexp_xmit(struct sk_buff *buf
+ * Best would be to use synchronize_irq(); spin_lock() here
+ * lets make it work first..
+ */
+-
++
+ #ifdef CONFIG_SMP
+ spin_lock_irqsave(&lp->lock, flags);
+ #endif
+-
++
+ {
+ unsigned short *data = (unsigned short *)buf->data;
+
+@@ -739,7 +739,7 @@ static unsigned short eexp_start_irq(str
+ outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
+ diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
+ if (diag_status & 1<<11) {
+- printk(KERN_WARNING "%s: 82586 failed self-test\n",
++ printk(KERN_WARNING "%s: 82586 failed self-test\n",
+ dev->name);
+ } else if (!(diag_status & 1<<13)) {
+ printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
+@@ -749,7 +749,7 @@ static unsigned short eexp_start_irq(str
+ tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
+ if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
+ printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
+- }
++ }
+ else if (tdr_status & TDR_XCVRPROBLEM) {
+ printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
+ }
+@@ -761,7 +761,7 @@ static unsigned short eexp_start_irq(str
+ printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
+ tdr_status);
+ }
+-
++
+ lp->started |= STARTED_CU;
+ scb_wrcbl(dev, lp->tx_link);
+ /* if the RU isn't running, start it now */
+@@ -774,7 +774,7 @@ static unsigned short eexp_start_irq(str
+ ack_cmd |= SCB_CUstart | 0x2000;
+ }
+
+- if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
++ if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
+ lp->started|=STARTED_RU;
+
+ return ack_cmd;
+@@ -788,21 +788,14 @@ static void eexp_cmd_clear(struct net_de
+ printk("%s: command didn't clear\n", dev->name);
+ }
+ }
+-
+-static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
++
++static irqreturn_t eexp_irq(int irq, void *dev_info)
+ {
+ struct net_device *dev = dev_info;
+ struct net_local *lp;
+ unsigned short ioaddr,status,ack_cmd;
+ unsigned short old_read_ptr, old_write_ptr;
+
+- if (dev==NULL)
+- {
+- printk(KERN_WARNING "eexpress: irq %d for unknown device\n",
+- irq);
+- return IRQ_NONE;
+- }
+-
+ lp = netdev_priv(dev);
+ ioaddr = dev->base_addr;
+
+@@ -813,7 +806,7 @@ static irqreturn_t eexp_irq(int irq, voi
+
+ outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+
+-
++
+ status = scb_status(dev);
+
+ #if NET_DEBUG > 4
+@@ -836,14 +829,14 @@ static irqreturn_t eexp_irq(int irq, voi
+ printk("%s: tx interrupt but no status\n", dev->name);
+ }
+ }
+-
+- if (SCB_rxdframe(status))
++
++ if (SCB_rxdframe(status))
+ eexp_hw_rx_pio(dev);
+
+ status = scb_status(dev);
+ } while (status & 0xc000);
+
+- if (SCB_RUdead(status))
++ if (SCB_RUdead(status))
+ {
+ printk(KERN_WARNING "%s: RU stopped: status %04x\n",
+ dev->name,status);
+@@ -867,9 +860,9 @@ static irqreturn_t eexp_irq(int irq, voi
+ scb_wrrfa(dev, lp->rx_buf_start);
+ scb_command(dev, SCB_RUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+- }
++ }
+ } else {
+- if (status & 0x8000)
++ if (status & 0x8000)
+ ack_cmd = eexp_start_irq(dev, status);
+ else
+ ack_cmd = SCB_ack(status);
+@@ -879,14 +872,14 @@ static irqreturn_t eexp_irq(int irq, voi
+
+ eexp_cmd_clear(dev);
+
+- outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
++ outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
+
+-#if NET_DEBUG > 6
++#if NET_DEBUG > 6
+ printk("%s: leaving eexp_irq()\n", dev->name);
+ #endif
+ outw(old_read_ptr, ioaddr+READ_PTR);
+ outw(old_write_ptr, ioaddr+WRITE_PTR);
+-
++
+ spin_unlock(&lp->lock);
+ return IRQ_HANDLED;
+ }
+@@ -934,7 +927,7 @@ static void eexp_hw_rx_pio(struct net_de
+
+ do {
+ unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
+-
++
+ outw(rx_block, ioaddr + READ_PTR);
+ status = inw(ioaddr + DATAPORT);
+
+@@ -943,7 +936,7 @@ static void eexp_hw_rx_pio(struct net_de
+ rfd_cmd = inw(ioaddr + DATAPORT);
+ rx_next = inw(ioaddr + DATAPORT);
+ pbuf = inw(ioaddr + DATAPORT);
+-
++
+ outw(pbuf, ioaddr + READ_PTR);
+ pkt_len = inw(ioaddr + DATAPORT);
+
+@@ -955,17 +948,17 @@ static void eexp_hw_rx_pio(struct net_de
+ }
+ else if (pbuf!=rx_block+0x16)
+ {
+- printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
++ printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
+ dev->name, rx_block+0x16, pbuf);
+ continue;
+ }
+- else if ((pkt_len & 0xc000)!=0xc000)
++ else if ((pkt_len & 0xc000)!=0xc000)
+ {
+ printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
+ dev->name, pkt_len & 0xc000);
+ continue;
+ }
+- else if (!FD_OK(status))
++ else if (!FD_OK(status))
+ {
+ lp->stats.rx_errors++;
+ if (FD_CRC(status))
+@@ -1025,9 +1018,9 @@ static void eexp_hw_tx_pio(struct net_de
+ if (LOCKUP16 || lp->width) {
+ /* Stop the CU so that there is no chance that it
+ jumps off to a bogus address while we are writing the
+- pointer to the next transmit packet in 8-bit mode --
++ pointer to the next transmit packet in 8-bit mode --
+ this eliminates the "CU wedged" errors in 8-bit mode.
+- (Zoltan Szilagyi 10-12-96) */
++ (Zoltan Szilagyi 10-12-96) */
+ scb_command(dev, SCB_CUsuspend);
+ outw(0xFFFF, ioaddr+SIGNAL_CA);
+ }
+@@ -1061,7 +1054,7 @@ static void eexp_hw_tx_pio(struct net_de
+ lp->tx_head += TX_BUF_SIZE;
+ if (lp->tx_head != lp->tx_reap)
+ netif_wake_queue(dev);
+-
++
+ if (LOCKUP16 || lp->width) {
+ /* Restart the CU so that the packet can actually
+ be transmitted. (Zoltan Szilagyi 10-12-96) */
+@@ -1102,7 +1095,7 @@ static int __init eexp_hw_probe(struct n
+
+ /* Standard Address or Compaq LTE Address */
+ if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
+- (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
++ (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
+ {
+ printk(" rejected: invalid address %04x%04x%04x\n",
+ hw_addr[2],hw_addr[1],hw_addr[0]);
+@@ -1140,16 +1133,16 @@ static int __init eexp_hw_probe(struct n
+ memset(lp, 0, sizeof(struct net_local));
+ spin_lock_init(&lp->lock);
+
+- printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
++ printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
+ eexp_ifmap[dev->if_port], buswidth?8:16);
+-
++
+ if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
+ return -EBUSY;
+
+ eexp_hw_set_interface(dev);
+-
++
+ release_region(dev->base_addr + 0x300e, 1);
+-
++
+ /* Find out how much RAM we have on the card */
+ outw(0, dev->base_addr + WRITE_PTR);
+ for (i = 0; i < 32768; i++)
+@@ -1284,7 +1277,7 @@ static unsigned short eexp_hw_lasttxstat
+ {
+ char *whatsup = NULL;
+ lp->stats.tx_errors++;
+- if (Stat_Abort(status))
++ if (Stat_Abort(status))
+ lp->stats.tx_aborted_errors++;
+ if (Stat_TNoCar(status)) {
+ whatsup = "aborted, no carrier";
+@@ -1460,11 +1453,11 @@ static void eexp_hw_rxinit(struct net_de
+ /* Close Rx frame descriptor ring */
+ outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
+ outw(lp->rx_first, ioaddr+DATAPORT);
+-
++
+ /* Close Rx buffer descriptor ring */
+ outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
+ outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
+-
++
+ }
+
+ /*
+@@ -1512,7 +1505,7 @@ static void eexp_hw_init586(struct net_d
+ /* Do we want promiscuous mode or multicast? */
+ outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
+ i = inw(ioaddr+SHADOW(CONF_PROMISC));
+- outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
++ outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
+ ioaddr+SHADOW(CONF_PROMISC));
+ lp->was_promisc = dev->flags & IFF_PROMISC;
+ #if 0
+@@ -1522,7 +1515,7 @@ static void eexp_hw_init586(struct net_d
+ /* Write our hardware address */
+ outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
+ outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
+- outw(((unsigned short *)dev->dev_addr)[1],
++ outw(((unsigned short *)dev->dev_addr)[1],
+ ioaddr+SHADOW(CONF_HWADDR+2));
+ outw(((unsigned short *)dev->dev_addr)[2],
+ ioaddr+SHADOW(CONF_HWADDR+4));
+@@ -1608,7 +1601,7 @@ static void eexp_setup_filter(struct net
+ dev->name, count);
+ count = 8;
+ }
+-
++
+ outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
+ outw(count, ioaddr+SHADOW(CONF_NR_MULTICAST));
+ for (i = 0; i < count; i++) {
+diff --git a/drivers/net/eexpress.h b/drivers/net/eexpress.h
+index 28b4312..707df3f 100644
+--- a/drivers/net/eexpress.h
++++ b/drivers/net/eexpress.h
+@@ -53,8 +53,8 @@
+ #define SCB_START 0x0008
+
+ /* Start of buffer region. Everything before this is used for control
+- * structures and the CU configuration program. The memory layout is
+- * determined in eexp_hw_probe(), once we know how much memory is
++ * structures and the CU configuration program. The memory layout is
++ * determined in eexp_hw_probe(), once we know how much memory is
+ * available on the card.
+ */
+
+@@ -64,7 +64,7 @@
+ #define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
+
+ /*
+- * SCB defines
++ * SCB defines
+ */
+
+ /* these functions take the SCB status word and test the relevant status bit */
+@@ -95,7 +95,7 @@
+ #define SCB_RUabort 0x0040
+
+ /*
+- * Command block defines
++ * Command block defines
+ */
+
+ #define Stat_Done(s) ((s&0x8000)!=0)
+@@ -158,9 +158,9 @@ struct rfd_header {
+ volatile unsigned short srcaddr2;
+ volatile unsigned short srcaddr3;
+ volatile unsigned short length;
+-
+- /* This is actually a Receive Buffer Descriptor. The way we
+- * arrange memory means that an RBD always follows the RFD that
++
++ /* This is actually a Receive Buffer Descriptor. The way we
++ * arrange memory means that an RBD always follows the RFD that
+ * points to it, so they might as well be in the same structure.
+ */
+ volatile unsigned short actual_count;
+diff --git a/drivers/net/ehea/Makefile b/drivers/net/ehea/Makefile
+new file mode 100644
+index 0000000..775d996
+--- /dev/null
++++ b/drivers/net/ehea/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for the eHEA ethernet device driver for IBM eServer System p
++#
++ehea-y = ehea_main.o ehea_phyp.o ehea_qmr.o ehea_ethtool.o ehea_phyp.o
++obj-$(CONFIG_EHEA) += ehea.o
++
+diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
+new file mode 100644
+index 0000000..39ad9f7
+--- /dev/null
++++ b/drivers/net/ehea/ehea.h
+@@ -0,0 +1,445 @@
++/*
++ * linux/drivers/net/ehea/ehea.h
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 __EHEA_H__
++#define __EHEA_H__
++
++#include <linux/module.h>
++#include <linux/ethtool.h>
++#include <linux/vmalloc.h>
++#include <linux/if_vlan.h>
++
++#include <asm/ibmebus.h>
++#include <asm/abs_addr.h>
++#include <asm/io.h>
++
++#define DRV_NAME "ehea"
++#define DRV_VERSION "EHEA_0043"
++
++#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
++ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
++
++#define EHEA_MAX_ENTRIES_RQ1 32767
++#define EHEA_MAX_ENTRIES_RQ2 16383
++#define EHEA_MAX_ENTRIES_RQ3 16383
++#define EHEA_MAX_ENTRIES_SQ 32767
++#define EHEA_MIN_ENTRIES_QP 127
++
++#define EHEA_SMALL_QUEUES
++#define EHEA_NUM_TX_QP 1
++
++#ifdef EHEA_SMALL_QUEUES
++#define EHEA_MAX_CQE_COUNT 1023
++#define EHEA_DEF_ENTRIES_SQ 1023
++#define EHEA_DEF_ENTRIES_RQ1 4095
++#define EHEA_DEF_ENTRIES_RQ2 1023
++#define EHEA_DEF_ENTRIES_RQ3 1023
++#else
++#define EHEA_MAX_CQE_COUNT 4080
++#define EHEA_DEF_ENTRIES_SQ 4080
++#define EHEA_DEF_ENTRIES_RQ1 8160
++#define EHEA_DEF_ENTRIES_RQ2 2040
++#define EHEA_DEF_ENTRIES_RQ3 2040
++#endif
++
++#define EHEA_MAX_ENTRIES_EQ 20
++
++#define EHEA_SG_SQ 2
++#define EHEA_SG_RQ1 1
++#define EHEA_SG_RQ2 0
++#define EHEA_SG_RQ3 0
++
++#define EHEA_MAX_PACKET_SIZE 9022 /* for jumbo frames */
++#define EHEA_RQ2_PKT_SIZE 1522
++#define EHEA_L_PKT_SIZE 256 /* low latency */
++
++#define EHEA_POLL_MAX_RWQE 1000
++
++/* Send completion signaling */
++#define EHEA_SIG_IV_LONG 1
++
++/* Protection Domain Identifier */
++#define EHEA_PD_ID 0xaabcdeff
++
++#define EHEA_RQ2_THRESHOLD 1
++#define EHEA_RQ3_THRESHOLD 9 /* use RQ3 threshold of 1522 bytes */
++
++#define EHEA_SPEED_10G 10000
++#define EHEA_SPEED_1G 1000
++#define EHEA_SPEED_100M 100
++#define EHEA_SPEED_10M 10
++#define EHEA_SPEED_AUTONEG 0
++
++/* Broadcast/Multicast registration types */
++#define EHEA_BCMC_SCOPE_ALL 0x08
++#define EHEA_BCMC_SCOPE_SINGLE 0x00
++#define EHEA_BCMC_MULTICAST 0x04
++#define EHEA_BCMC_BROADCAST 0x00
++#define EHEA_BCMC_UNTAGGED 0x02
++#define EHEA_BCMC_TAGGED 0x00
++#define EHEA_BCMC_VLANID_ALL 0x01
++#define EHEA_BCMC_VLANID_SINGLE 0x00
++
++#define EHEA_CACHE_LINE 128
++
++/* Memory Regions */
++#define EHEA_MR_MAX_TX_PAGES 20
++#define EHEA_MR_TX_DATA_PN 3
++#define EHEA_MR_ACC_CTRL 0x00800000
++#define EHEA_RWQES_PER_MR_RQ2 10
++#define EHEA_RWQES_PER_MR_RQ3 10
++
++#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
++
++/* utility functions */
++
++#define ehea_info(fmt, args...) \
++ printk(KERN_INFO DRV_NAME ": " fmt "\n", ## args)
++
++#define ehea_error(fmt, args...) \
++ printk(KERN_ERR DRV_NAME ": Error in %s: " fmt "\n", __func__, ## args)
++
++#ifdef DEBUG
++#define ehea_debug(fmt, args...) \
++ printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
++#else
++#define ehea_debug(fmt, args...) do {} while (0)
++#endif
++
++void ehea_dump(void *adr, int len, char *msg);
++
++#define EHEA_BMASK(pos, length) (((pos) << 16) + (length))
++
++#define EHEA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
++
++#define EHEA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
++
++#define EHEA_BMASK_MASK(mask) \
++ (0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
++
++#define EHEA_BMASK_SET(mask, value) \
++ ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
++
++#define EHEA_BMASK_GET(mask, value) \
++ (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
++
++/*
++ * Generic ehea page
++ */
++struct ehea_page {
++ u8 entries[PAGE_SIZE];
++};
++
++/*
++ * Generic queue in linux kernel virtual memory
++ */
++struct hw_queue {
++ u64 current_q_offset; /* current queue entry */
++ struct ehea_page **queue_pages; /* array of pages belonging to queue */
++ u32 qe_size; /* queue entry size */
++ u32 queue_length; /* queue length allocated in bytes */
++ u32 pagesize;
++ u32 toggle_state; /* toggle flag - per page */
++ u32 reserved; /* 64 bit alignment */
++};
++
++/*
++ * For pSeries this is a 64bit memory address where
++ * I/O memory is mapped into CPU address space
++ */
++struct h_epa {
++ void __iomem *addr;
++};
++
++struct h_epa_user {
++ u64 addr;
++};
++
++struct h_epas {
++ struct h_epa kernel; /* kernel space accessible resource,
++ set to 0 if unused */
++ struct h_epa_user user; /* user space accessible resource
++ set to 0 if unused */
++};
++
++struct ehea_qp;
++struct ehea_cq;
++struct ehea_eq;
++struct ehea_port;
++struct ehea_av;
++
++/*
++ * Queue attributes passed to ehea_create_qp()
++ */
++struct ehea_qp_init_attr {
++ /* input parameter */
++ u32 qp_token; /* queue token */
++ u8 low_lat_rq1;
++ u8 signalingtype; /* cqe generation flag */
++ u8 rq_count; /* num of receive queues */
++ u8 eqe_gen; /* eqe generation flag */
++ u16 max_nr_send_wqes; /* max number of send wqes */
++ u16 max_nr_rwqes_rq1; /* max number of receive wqes */
++ u16 max_nr_rwqes_rq2;
++ u16 max_nr_rwqes_rq3;
++ u8 wqe_size_enc_sq;
++ u8 wqe_size_enc_rq1;
++ u8 wqe_size_enc_rq2;
++ u8 wqe_size_enc_rq3;
++ u8 swqe_imm_data_len; /* immediate data length for swqes */
++ u16 port_nr;
++ u16 rq2_threshold;
++ u16 rq3_threshold;
++ u64 send_cq_handle;
++ u64 recv_cq_handle;
++ u64 aff_eq_handle;
++
++ /* output parameter */
++ u32 qp_nr;
++ u16 act_nr_send_wqes;
++ u16 act_nr_rwqes_rq1;
++ u16 act_nr_rwqes_rq2;
++ u16 act_nr_rwqes_rq3;
++ u8 act_wqe_size_enc_sq;
++ u8 act_wqe_size_enc_rq1;
++ u8 act_wqe_size_enc_rq2;
++ u8 act_wqe_size_enc_rq3;
++ u32 nr_sq_pages;
++ u32 nr_rq1_pages;
++ u32 nr_rq2_pages;
++ u32 nr_rq3_pages;
++ u32 liobn_sq;
++ u32 liobn_rq1;
++ u32 liobn_rq2;
++ u32 liobn_rq3;
++};
++
++/*
++ * Event Queue attributes, passed as paramter
++ */
++struct ehea_eq_attr {
++ u32 type;
++ u32 max_nr_of_eqes;
++ u8 eqe_gen; /* generate eqe flag */
++ u64 eq_handle;
++ u32 act_nr_of_eqes;
++ u32 nr_pages;
++ u32 ist1; /* Interrupt service token */
++ u32 ist2;
++ u32 ist3;
++ u32 ist4;
++};
++
++
++/*
++ * Event Queue
++ */
++struct ehea_eq {
++ struct ehea_adapter *adapter;
++ struct hw_queue hw_queue;
++ u64 fw_handle;
++ struct h_epas epas;
++ spinlock_t spinlock;
++ struct ehea_eq_attr attr;
++};
++
++/*
++ * HEA Queues
++ */
++struct ehea_qp {
++ struct ehea_adapter *adapter;
++ u64 fw_handle; /* QP handle for firmware calls */
++ struct hw_queue hw_squeue;
++ struct hw_queue hw_rqueue1;
++ struct hw_queue hw_rqueue2;
++ struct hw_queue hw_rqueue3;
++ struct h_epas epas;
++ struct ehea_qp_init_attr init_attr;
++};
++
++/*
++ * Completion Queue attributes
++ */
++struct ehea_cq_attr {
++ /* input parameter */
++ u32 max_nr_of_cqes;
++ u32 cq_token;
++ u64 eq_handle;
++
++ /* output parameter */
++ u32 act_nr_of_cqes;
++ u32 nr_pages;
++};
++
++/*
++ * Completion Queue
++ */
++struct ehea_cq {
++ struct ehea_adapter *adapter;
++ u64 fw_handle;
++ struct hw_queue hw_queue;
++ struct h_epas epas;
++ struct ehea_cq_attr attr;
++};
++
++/*
++ * Memory Region
++ */
++struct ehea_mr {
++ u64 handle;
++ u64 vaddr;
++ u32 lkey;
++};
++
++/*
++ * Port state information
++ */
++struct port_state {
++ int poll_max_processed;
++ int poll_receive_errors;
++ int ehea_poll;
++ int queue_stopped;
++ int min_swqe_avail;
++ u64 sqc_stop_sum;
++ int pkt_send;
++ int pkt_xmit;
++ int send_tasklet;
++ int nwqe;
++};
++
++#define EHEA_IRQ_NAME_SIZE 20
++
++/*
++ * Queue SKB Array
++ */
++struct ehea_q_skb_arr {
++ struct sk_buff **arr; /* skb array for queue */
++ int len; /* array length */
++ int index; /* array index */
++ int os_skbs; /* rq2/rq3 only: outstanding skbs */
++};
++
++/*
++ * Port resources
++ */
++struct ehea_port_res {
++ struct ehea_mr send_mr; /* send memory region */
++ struct ehea_mr recv_mr; /* receive memory region */
++ spinlock_t xmit_lock;
++ struct ehea_port *port;
++ char int_recv_name[EHEA_IRQ_NAME_SIZE];
++ char int_send_name[EHEA_IRQ_NAME_SIZE];
++ struct ehea_qp *qp;
++ struct ehea_cq *send_cq;
++ struct ehea_cq *recv_cq;
++ struct ehea_eq *send_eq;
++ struct ehea_eq *recv_eq;
++ spinlock_t send_lock;
++ struct ehea_q_skb_arr rq1_skba;
++ struct ehea_q_skb_arr rq2_skba;
++ struct ehea_q_skb_arr rq3_skba;
++ struct ehea_q_skb_arr sq_skba;
++ spinlock_t netif_queue;
++ int queue_stopped;
++ int swqe_refill_th;
++ atomic_t swqe_avail;
++ int swqe_ll_count;
++ int swqe_count;
++ u32 swqe_id_counter;
++ u64 tx_packets;
++ struct tasklet_struct send_comp_task;
++ spinlock_t recv_lock;
++ struct port_state p_state;
++ u64 rx_packets;
++ u32 poll_counter;
++};
++
++
++struct ehea_adapter {
++ u64 handle;
++ u8 num_ports;
++ struct ehea_port *port[16];
++ struct ehea_eq *neq; /* notification event queue */
++ struct workqueue_struct *ehea_wq;
++ struct tasklet_struct neq_tasklet;
++ struct ehea_mr mr;
++ u32 pd; /* protection domain */
++ u64 max_mc_mac; /* max number of multicast mac addresses */
++};
++
++
++struct ehea_mc_list {
++ struct list_head list;
++ u64 macaddr;
++};
++
++#define EHEA_PORT_UP 1
++#define EHEA_PORT_DOWN 0
++#define EHEA_MAX_PORT_RES 16
++struct ehea_port {
++ struct ehea_adapter *adapter; /* adapter that owns this port */
++ struct net_device *netdev;
++ struct net_device_stats stats;
++ struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
++ struct device_node *of_dev_node; /* Open Firmware Device Node */
++ struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
++ struct vlan_group *vgrp;
++ struct ehea_eq *qp_eq;
++ struct work_struct reset_task;
++ struct semaphore port_lock;
++ char int_aff_name[EHEA_IRQ_NAME_SIZE];
++ int allmulti; /* Indicates IFF_ALLMULTI state */
++ int promisc; /* Indicates IFF_PROMISC state */
++ int num_add_tx_qps;
++ int resets;
++ u64 mac_addr;
++ u32 logical_port_id;
++ u32 port_speed;
++ u32 msg_enable;
++ u32 sig_comp_iv;
++ u32 state;
++ u8 full_duplex;
++ u8 autoneg;
++ u8 num_def_qps;
++};
++
++struct port_res_cfg {
++ int max_entries_rcq;
++ int max_entries_scq;
++ int max_entries_sq;
++ int max_entries_rq1;
++ int max_entries_rq2;
++ int max_entries_rq3;
++};
++
++
++void ehea_set_ethtool_ops(struct net_device *netdev);
++int ehea_sense_port_attr(struct ehea_port *port);
++int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
++
++#endif /* __EHEA_H__ */
+diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
+new file mode 100644
+index 0000000..9f57c2e
+--- /dev/null
++++ b/drivers/net/ehea/ehea_ethtool.c
+@@ -0,0 +1,294 @@
++/*
++ * linux/drivers/net/ehea/ehea_ethtool.c
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 "ehea.h"
++#include "ehea_phyp.h"
++
++static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ int ret;
++
++ ret = ehea_sense_port_attr(port);
++
++ if (ret)
++ return ret;
++
++ if (netif_carrier_ok(dev)) {
++ switch(port->port_speed) {
++ case EHEA_SPEED_10M: cmd->speed = SPEED_10; break;
++ case EHEA_SPEED_100M: cmd->speed = SPEED_100; break;
++ case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break;
++ case EHEA_SPEED_10G: cmd->speed = SPEED_10000; break;
++ }
++ cmd->duplex = port->full_duplex == 1 ?
++ DUPLEX_FULL : DUPLEX_HALF;
++ } else {
++ cmd->speed = -1;
++ cmd->duplex = -1;
++ }
++
++ cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full
++ | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half
++ | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half
++ | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
++
++ cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg
++ | ADVERTISED_FIBRE);
++
++ cmd->port = PORT_FIBRE;
++ cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
++
++ return 0;
++}
++
++static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ int ret = 0;
++ u32 sp;
++
++ if (cmd->autoneg == AUTONEG_ENABLE) {
++ sp = EHEA_SPEED_AUTONEG;
++ goto doit;
++ }
++
++ switch(cmd->speed) {
++ case SPEED_10:
++ if (cmd->duplex == DUPLEX_FULL)
++ sp = H_SPEED_10M_F;
++ else
++ sp = H_SPEED_10M_H;
++ break;
++
++ case SPEED_100:
++ if (cmd->duplex == DUPLEX_FULL)
++ sp = H_SPEED_100M_F;
++ else
++ sp = H_SPEED_100M_H;
++ break;
++
++ case SPEED_1000:
++ if (cmd->duplex == DUPLEX_FULL)
++ sp = H_SPEED_1G_F;
++ else
++ ret = -EINVAL;
++ break;
++
++ case SPEED_10000:
++ if (cmd->duplex == DUPLEX_FULL)
++ sp = H_SPEED_10G_F;
++ else
++ ret = -EINVAL;
++ break;
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ if (ret)
++ goto out;
++doit:
++ ret = ehea_set_portspeed(port, sp);
++
++ if (!ret)
++ ehea_info("%s: Port speed succesfully set: %dMbps "
++ "%s Duplex",
++ port->netdev->name, port->port_speed,
++ port->full_duplex == 1 ? "Full" : "Half");
++out:
++ return ret;
++}
++
++static int ehea_nway_reset(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ int ret;
++
++ ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
++
++ if (!ret)
++ ehea_info("%s: Port speed succesfully set: %dMbps "
++ "%s Duplex",
++ port->netdev->name, port->port_speed,
++ port->full_duplex == 1 ? "Full" : "Half");
++ return ret;
++}
++
++static void ehea_get_drvinfo(struct net_device *dev,
++ struct ethtool_drvinfo *info)
++{
++ strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
++ strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
++}
++
++static u32 ehea_get_msglevel(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ return port->msg_enable;
++}
++
++static void ehea_set_msglevel(struct net_device *dev, u32 value)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ port->msg_enable = value;
++}
++
++static u32 ehea_get_rx_csum(struct net_device *dev)
++{
++ return 1;
++}
++
++static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
++ {"poll_max_processed"},
++ {"queue_stopped"},
++ {"min_swqe_avail"},
++ {"poll_receive_err"},
++ {"pkt_send"},
++ {"pkt_xmit"},
++ {"send_tasklet"},
++ {"ehea_poll"},
++ {"nwqe"},
++ {"swqe_available_0"},
++ {"sig_comp_iv"},
++ {"swqe_refill_th"},
++ {"port resets"},
++ {"rxo"},
++ {"rx64"},
++ {"rx65"},
++ {"rx128"},
++ {"rx256"},
++ {"rx512"},
++ {"rx1024"},
++ {"txo"},
++ {"tx64"},
++ {"tx65"},
++ {"tx128"},
++ {"tx256"},
++ {"tx512"},
++ {"tx1024"},
++};
++
++static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
++{
++ if (stringset == ETH_SS_STATS) {
++ memcpy(data, &ehea_ethtool_stats_keys,
++ sizeof(ehea_ethtool_stats_keys));
++ }
++}
++
++static int ehea_get_stats_count(struct net_device *dev)
++{
++ return ARRAY_SIZE(ehea_ethtool_stats_keys);
++}
++
++static void ehea_get_ethtool_stats(struct net_device *dev,
++ struct ethtool_stats *stats, u64 *data)
++{
++ u64 hret;
++ int i;
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_adapter *adapter = port->adapter;
++ struct ehea_port_res *pr = &port->port_res[0];
++ struct port_state *p_state = &pr->p_state;
++ struct hcp_ehea_port_cb6 *cb6;
++
++ for (i = 0; i < ehea_get_stats_count(dev); i++)
++ data[i] = 0;
++
++ i = 0;
++
++ data[i++] = p_state->poll_max_processed;
++ data[i++] = p_state->queue_stopped;
++ data[i++] = p_state->min_swqe_avail;
++ data[i++] = p_state->poll_receive_errors;
++ data[i++] = p_state->pkt_send;
++ data[i++] = p_state->pkt_xmit;
++ data[i++] = p_state->send_tasklet;
++ data[i++] = p_state->ehea_poll;
++ data[i++] = p_state->nwqe;
++ data[i++] = atomic_read(&port->port_res[0].swqe_avail);
++ data[i++] = port->sig_comp_iv;
++ data[i++] = port->port_res[0].swqe_refill_th;
++ data[i++] = port->resets;
++
++ cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb6) {
++ ehea_error("no mem for cb6");
++ return;
++ }
++
++ hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
++ H_PORT_CB6, H_PORT_CB6_ALL, cb6);
++ if (netif_msg_hw(port))
++ ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats");
++
++ if (hret == H_SUCCESS) {
++ data[i++] = cb6->rxo;
++ data[i++] = cb6->rx64;
++ data[i++] = cb6->rx65;
++ data[i++] = cb6->rx128;
++ data[i++] = cb6->rx256;
++ data[i++] = cb6->rx512;
++ data[i++] = cb6->rx1024;
++ data[i++] = cb6->txo;
++ data[i++] = cb6->tx64;
++ data[i++] = cb6->tx65;
++ data[i++] = cb6->tx128;
++ data[i++] = cb6->tx256;
++ data[i++] = cb6->tx512;
++ data[i++] = cb6->tx1024;
++ } else
++ ehea_error("query_ehea_port failed");
++
++ kfree(cb6);
++}
++
++const struct ethtool_ops ehea_ethtool_ops = {
++ .get_settings = ehea_get_settings,
++ .get_drvinfo = ehea_get_drvinfo,
++ .get_msglevel = ehea_get_msglevel,
++ .set_msglevel = ehea_set_msglevel,
++ .get_link = ethtool_op_get_link,
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = ethtool_op_set_tso,
++ .get_strings = ehea_get_strings,
++ .get_stats_count = ehea_get_stats_count,
++ .get_ethtool_stats = ehea_get_ethtool_stats,
++ .get_rx_csum = ehea_get_rx_csum,
++ .set_settings = ehea_set_settings,
++ .nway_reset = ehea_nway_reset, /* Restart autonegotiation */
++};
++
++void ehea_set_ethtool_ops(struct net_device *netdev)
++{
++ SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops);
++}
+diff --git a/drivers/net/ehea/ehea_hcall.h b/drivers/net/ehea/ehea_hcall.h
+new file mode 100644
+index 0000000..8e7d1c3
+--- /dev/null
++++ b/drivers/net/ehea/ehea_hcall.h
+@@ -0,0 +1,51 @@
++/*
++ * linux/drivers/net/ehea/ehea_hcall.h
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 __EHEA_HCALL_H__
++#define __EHEA_HCALL_H__
++
++/**
++ * This file contains HCALL defines that are to be included in the appropriate
++ * kernel files later
++ */
++
++#define H_ALLOC_HEA_RESOURCE 0x278
++#define H_MODIFY_HEA_QP 0x250
++#define H_QUERY_HEA_QP 0x254
++#define H_QUERY_HEA 0x258
++#define H_QUERY_HEA_PORT 0x25C
++#define H_MODIFY_HEA_PORT 0x260
++#define H_REG_BCMC 0x264
++#define H_DEREG_BCMC 0x268
++#define H_REGISTER_HEA_RPAGES 0x26C
++#define H_DISABLE_AND_GET_HEA 0x270
++#define H_GET_HEA_INFO 0x274
++#define H_ADD_CONN 0x284
++#define H_DEL_CONN 0x288
++
++#endif /* __EHEA_HCALL_H__ */
+diff --git a/drivers/net/ehea/ehea_hw.h b/drivers/net/ehea/ehea_hw.h
+new file mode 100644
+index 0000000..1246757
+--- /dev/null
++++ b/drivers/net/ehea/ehea_hw.h
+@@ -0,0 +1,292 @@
++/*
++ * linux/drivers/net/ehea/ehea_hw.h
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 __EHEA_HW_H__
++#define __EHEA_HW_H__
++
++#define QPX_SQA_VALUE EHEA_BMASK_IBM(48,63)
++#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48,63)
++#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48,63)
++#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48,63)
++
++#define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
++
++struct ehea_qptemm {
++ u64 qpx_hcr;
++ u64 qpx_c;
++ u64 qpx_herr;
++ u64 qpx_aer;
++ u64 qpx_sqa;
++ u64 qpx_sqc;
++ u64 qpx_rq1a;
++ u64 qpx_rq1c;
++ u64 qpx_st;
++ u64 qpx_aerr;
++ u64 qpx_tenure;
++ u64 qpx_reserved1[(0x098 - 0x058) / 8];
++ u64 qpx_portp;
++ u64 qpx_reserved2[(0x100 - 0x0A0) / 8];
++ u64 qpx_t;
++ u64 qpx_sqhp;
++ u64 qpx_sqptp;
++ u64 qpx_reserved3[(0x140 - 0x118) / 8];
++ u64 qpx_sqwsize;
++ u64 qpx_reserved4[(0x170 - 0x148) / 8];
++ u64 qpx_sqsize;
++ u64 qpx_reserved5[(0x1B0 - 0x178) / 8];
++ u64 qpx_sigt;
++ u64 qpx_wqecnt;
++ u64 qpx_rq1hp;
++ u64 qpx_rq1ptp;
++ u64 qpx_rq1size;
++ u64 qpx_reserved6[(0x220 - 0x1D8) / 8];
++ u64 qpx_rq1wsize;
++ u64 qpx_reserved7[(0x240 - 0x228) / 8];
++ u64 qpx_pd;
++ u64 qpx_scqn;
++ u64 qpx_rcqn;
++ u64 qpx_aeqn;
++ u64 reserved49;
++ u64 qpx_ram;
++ u64 qpx_reserved8[(0x300 - 0x270) / 8];
++ u64 qpx_rq2a;
++ u64 qpx_rq2c;
++ u64 qpx_rq2hp;
++ u64 qpx_rq2ptp;
++ u64 qpx_rq2size;
++ u64 qpx_rq2wsize;
++ u64 qpx_rq2th;
++ u64 qpx_rq3a;
++ u64 qpx_rq3c;
++ u64 qpx_rq3hp;
++ u64 qpx_rq3ptp;
++ u64 qpx_rq3size;
++ u64 qpx_rq3wsize;
++ u64 qpx_rq3th;
++ u64 qpx_lpn;
++ u64 qpx_reserved9[(0x400 - 0x378) / 8];
++ u64 reserved_ext[(0x500 - 0x400) / 8];
++ u64 reserved2[(0x1000 - 0x500) / 8];
++};
++
++#define MRx_HCR_LPARID_VALID EHEA_BMASK_IBM(0, 0)
++
++#define MRMWMM_OFFSET(x) offsetof(struct ehea_mrmwmm, x)
++
++struct ehea_mrmwmm {
++ u64 mrx_hcr;
++ u64 mrx_c;
++ u64 mrx_herr;
++ u64 mrx_aer;
++ u64 mrx_pp;
++ u64 reserved1;
++ u64 reserved2;
++ u64 reserved3;
++ u64 reserved4[(0x200 - 0x40) / 8];
++ u64 mrx_ctl[64];
++};
++
++#define QPEDMM_OFFSET(x) offsetof(struct ehea_qpedmm, x)
++
++struct ehea_qpedmm {
++
++ u64 reserved0[(0x400) / 8];
++ u64 qpedx_phh;
++ u64 qpedx_ppsgp;
++ u64 qpedx_ppsgu;
++ u64 qpedx_ppdgp;
++ u64 qpedx_ppdgu;
++ u64 qpedx_aph;
++ u64 qpedx_apsgp;
++ u64 qpedx_apsgu;
++ u64 qpedx_apdgp;
++ u64 qpedx_apdgu;
++ u64 qpedx_apav;
++ u64 qpedx_apsav;
++ u64 qpedx_hcr;
++ u64 reserved1[4];
++ u64 qpedx_rrl0;
++ u64 qpedx_rrrkey0;
++ u64 qpedx_rrva0;
++ u64 reserved2;
++ u64 qpedx_rrl1;
++ u64 qpedx_rrrkey1;
++ u64 qpedx_rrva1;
++ u64 reserved3;
++ u64 qpedx_rrl2;
++ u64 qpedx_rrrkey2;
++ u64 qpedx_rrva2;
++ u64 reserved4;
++ u64 qpedx_rrl3;
++ u64 qpedx_rrrkey3;
++ u64 qpedx_rrva3;
++};
++
++#define CQX_FECADDER EHEA_BMASK_IBM(32, 63)
++#define CQX_FEC_CQE_CNT EHEA_BMASK_IBM(32, 63)
++#define CQX_N1_GENERATE_COMP_EVENT EHEA_BMASK_IBM(0, 0)
++#define CQX_EP_EVENT_PENDING EHEA_BMASK_IBM(0, 0)
++
++#define CQTEMM_OFFSET(x) offsetof(struct ehea_cqtemm, x)
++
++struct ehea_cqtemm {
++ u64 cqx_hcr;
++ u64 cqx_c;
++ u64 cqx_herr;
++ u64 cqx_aer;
++ u64 cqx_ptp;
++ u64 cqx_tp;
++ u64 cqx_fec;
++ u64 cqx_feca;
++ u64 cqx_ep;
++ u64 cqx_eq;
++ u64 reserved1;
++ u64 cqx_n0;
++ u64 cqx_n1;
++ u64 reserved2[(0x1000 - 0x60) / 8];
++};
++
++#define EQTEMM_OFFSET(x) offsetof(struct ehea_eqtemm, x)
++
++struct ehea_eqtemm {
++ u64 eqx_hcr;
++ u64 eqx_c;
++ u64 eqx_herr;
++ u64 eqx_aer;
++ u64 eqx_ptp;
++ u64 eqx_tp;
++ u64 eqx_ssba;
++ u64 eqx_psba;
++ u64 eqx_cec;
++ u64 eqx_meql;
++ u64 eqx_xisbi;
++ u64 eqx_xisc;
++ u64 eqx_it;
++};
++
++/*
++ * These access functions will be changed when the dissuccsion about
++ * the new access methods for POWER has settled.
++ */
++
++static inline u64 epa_load(struct h_epa epa, u32 offset)
++{
++ return __raw_readq((void __iomem *)(epa.addr + offset));
++}
++
++static inline void epa_store(struct h_epa epa, u32 offset, u64 value)
++{
++ __raw_writeq(value, (void __iomem *)(epa.addr + offset));
++ epa_load(epa, offset); /* synchronize explicitly to eHEA */
++}
++
++static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
++{
++ __raw_writeq(value, (void __iomem *)(epa.addr + offset));
++}
++
++#define epa_store_eq(epa, offset, value)\
++ epa_store(epa, EQTEMM_OFFSET(offset), value)
++#define epa_load_eq(epa, offset)\
++ epa_load(epa, EQTEMM_OFFSET(offset))
++
++#define epa_store_cq(epa, offset, value)\
++ epa_store(epa, CQTEMM_OFFSET(offset), value)
++#define epa_load_cq(epa, offset)\
++ epa_load(epa, CQTEMM_OFFSET(offset))
++
++#define epa_store_qp(epa, offset, value)\
++ epa_store(epa, QPTEMM_OFFSET(offset), value)
++#define epa_load_qp(epa, offset)\
++ epa_load(epa, QPTEMM_OFFSET(offset))
++
++#define epa_store_qped(epa, offset, value)\
++ epa_store(epa, QPEDMM_OFFSET(offset), value)
++#define epa_load_qped(epa, offset)\
++ epa_load(epa, QPEDMM_OFFSET(offset))
++
++#define epa_store_mrmw(epa, offset, value)\
++ epa_store(epa, MRMWMM_OFFSET(offset), value)
++#define epa_load_mrmw(epa, offset)\
++ epa_load(epa, MRMWMM_OFFSET(offset))
++
++#define epa_store_base(epa, offset, value)\
++ epa_store(epa, HCAGR_OFFSET(offset), value)
++#define epa_load_base(epa, offset)\
++ epa_load(epa, HCAGR_OFFSET(offset))
++
++static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
++{
++ struct h_epa epa = qp->epas.kernel;
++ epa_store_acc(epa, QPTEMM_OFFSET(qpx_sqa),
++ EHEA_BMASK_SET(QPX_SQA_VALUE, nr_wqes));
++}
++
++static inline void ehea_update_rq3a(struct ehea_qp *qp, u16 nr_wqes)
++{
++ struct h_epa epa = qp->epas.kernel;
++ epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq3a),
++ EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
++}
++
++static inline void ehea_update_rq2a(struct ehea_qp *qp, u16 nr_wqes)
++{
++ struct h_epa epa = qp->epas.kernel;
++ epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq2a),
++ EHEA_BMASK_SET(QPX_RQ2A_VALUE, nr_wqes));
++}
++
++static inline void ehea_update_rq1a(struct ehea_qp *qp, u16 nr_wqes)
++{
++ struct h_epa epa = qp->epas.kernel;
++ epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq1a),
++ EHEA_BMASK_SET(QPX_RQ3A_VALUE, nr_wqes));
++}
++
++static inline void ehea_update_feca(struct ehea_cq *cq, u32 nr_cqes)
++{
++ struct h_epa epa = cq->epas.kernel;
++ epa_store_acc(epa, CQTEMM_OFFSET(cqx_feca),
++ EHEA_BMASK_SET(CQX_FECADDER, nr_cqes));
++}
++
++static inline void ehea_reset_cq_n1(struct ehea_cq *cq)
++{
++ struct h_epa epa = cq->epas.kernel;
++ epa_store_cq(epa, cqx_n1,
++ EHEA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, 1));
++}
++
++static inline void ehea_reset_cq_ep(struct ehea_cq *my_cq)
++{
++ struct h_epa epa = my_cq->epas.kernel;
++ epa_store_acc(epa, CQTEMM_OFFSET(cqx_ep),
++ EHEA_BMASK_SET(CQX_EP_EVENT_PENDING, 0));
++}
++
++#endif /* __EHEA_HW_H__ */
+diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
+new file mode 100644
+index 0000000..6ad6961
+--- /dev/null
++++ b/drivers/net/ehea/ehea_main.c
+@@ -0,0 +1,2649 @@
++/*
++ * linux/drivers/net/ehea/ehea_main.c
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/if.h>
++#include <linux/list.h>
++#include <linux/if_ether.h>
++#include <net/ip.h>
++
++#include "ehea.h"
++#include "ehea_qmr.h"
++#include "ehea_phyp.h"
++
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christoph Raisch <raisch at de.ibm.com>");
++MODULE_DESCRIPTION("IBM eServer HEA Driver");
++MODULE_VERSION(DRV_VERSION);
++
++
++static int msg_level = -1;
++static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
++static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
++static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
++static int sq_entries = EHEA_DEF_ENTRIES_SQ;
++
++module_param(msg_level, int, 0);
++module_param(rq1_entries, int, 0);
++module_param(rq2_entries, int, 0);
++module_param(rq3_entries, int, 0);
++module_param(sq_entries, int, 0);
++
++MODULE_PARM_DESC(msg_level, "msg_level");
++MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
++ "[2^x - 1], x = [6..14]. Default = "
++ __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
++MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
++ "[2^x - 1], x = [6..14]. Default = "
++ __MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
++MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
++ "[2^x - 1], x = [6..14]. Default = "
++ __MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
++MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
++ "[2^x - 1], x = [6..14]. Default = "
++ __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
++
++void ehea_dump(void *adr, int len, char *msg) {
++ int x;
++ unsigned char *deb = adr;
++ for (x = 0; x < len; x += 16) {
++ printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg,
++ deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
++ deb += 16;
++ }
++}
++
++static struct net_device_stats *ehea_get_stats(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct net_device_stats *stats = &port->stats;
++ struct hcp_ehea_port_cb2 *cb2;
++ u64 hret, rx_packets;
++ int i;
++
++ memset(stats, 0, sizeof(*stats));
++
++ cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb2) {
++ ehea_error("no mem for cb2");
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_port(port->adapter->handle,
++ port->logical_port_id,
++ H_PORT_CB2, H_PORT_CB2_ALL, cb2);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_port failed");
++ goto out_herr;
++ }
++
++ if (netif_msg_hw(port))
++ ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
++
++ rx_packets = 0;
++ for (i = 0; i < port->num_def_qps; i++)
++ rx_packets += port->port_res[i].rx_packets;
++
++ stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp;
++ stats->multicast = cb2->rxmcp;
++ stats->rx_errors = cb2->rxuerr;
++ stats->rx_bytes = cb2->rxo;
++ stats->tx_bytes = cb2->txo;
++ stats->rx_packets = rx_packets;
++
++out_herr:
++ kfree(cb2);
++out:
++ return stats;
++}
++
++static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
++{
++ struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
++ struct net_device *dev = pr->port->netdev;
++ int max_index_mask = pr->rq1_skba.len - 1;
++ int i;
++
++ if (!nr_of_wqes)
++ return;
++
++ for (i = 0; i < nr_of_wqes; i++) {
++ if (!skb_arr_rq1[index]) {
++ skb_arr_rq1[index] = netdev_alloc_skb(dev,
++ EHEA_L_PKT_SIZE);
++ if (!skb_arr_rq1[index]) {
++ ehea_error("%s: no mem for skb/%d wqes filled",
++ dev->name, i);
++ break;
++ }
++ }
++ index--;
++ index &= max_index_mask;
++ }
++ /* Ring doorbell */
++ ehea_update_rq1a(pr->qp, i);
++}
++
++static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
++{
++ int ret = 0;
++ struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
++ struct net_device *dev = pr->port->netdev;
++ int i;
++
++ for (i = 0; i < pr->rq1_skba.len; i++) {
++ skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
++ if (!skb_arr_rq1[i]) {
++ ehea_error("%s: no mem for skb/%d wqes filled",
++ dev->name, i);
++ ret = -ENOMEM;
++ goto out;
++ }
++ }
++ /* Ring doorbell */
++ ehea_update_rq1a(pr->qp, nr_rq1a);
++out:
++ return ret;
++}
++
++static int ehea_refill_rq_def(struct ehea_port_res *pr,
++ struct ehea_q_skb_arr *q_skba, int rq_nr,
++ int num_wqes, int wqe_type, int packet_size)
++{
++ struct net_device *dev = pr->port->netdev;
++ struct ehea_qp *qp = pr->qp;
++ struct sk_buff **skb_arr = q_skba->arr;
++ struct ehea_rwqe *rwqe;
++ int i, index, max_index_mask, fill_wqes;
++ int ret = 0;
++
++ fill_wqes = q_skba->os_skbs + num_wqes;
++
++ if (!fill_wqes)
++ return ret;
++
++ index = q_skba->index;
++ max_index_mask = q_skba->len - 1;
++ for (i = 0; i < fill_wqes; i++) {
++ struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
++ if (!skb) {
++ ehea_error("%s: no mem for skb/%d wqes filled",
++ dev->name, i);
++ q_skba->os_skbs = fill_wqes - i;
++ ret = -ENOMEM;
++ break;
++ }
++ skb_reserve(skb, NET_IP_ALIGN);
++
++ skb_arr[index] = skb;
++
++ rwqe = ehea_get_next_rwqe(qp, rq_nr);
++ rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
++ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
++ rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
++ rwqe->sg_list[0].vaddr = (u64)skb->data;
++ rwqe->sg_list[0].len = packet_size;
++ rwqe->data_segments = 1;
++
++ index++;
++ index &= max_index_mask;
++ }
++ q_skba->index = index;
++
++ /* Ring doorbell */
++ iosync();
++ if (rq_nr == 2)
++ ehea_update_rq2a(pr->qp, i);
++ else
++ ehea_update_rq3a(pr->qp, i);
++
++ return ret;
++}
++
++
++static int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes)
++{
++ return ehea_refill_rq_def(pr, &pr->rq2_skba, 2,
++ nr_of_wqes, EHEA_RWQE2_TYPE,
++ EHEA_RQ2_PKT_SIZE + NET_IP_ALIGN);
++}
++
++
++static int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes)
++{
++ return ehea_refill_rq_def(pr, &pr->rq3_skba, 3,
++ nr_of_wqes, EHEA_RWQE3_TYPE,
++ EHEA_MAX_PACKET_SIZE + NET_IP_ALIGN);
++}
++
++static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
++{
++ *rq_num = (cqe->type & EHEA_CQE_TYPE_RQ) >> 5;
++ if ((cqe->status & EHEA_CQE_STAT_ERR_MASK) == 0)
++ return 0;
++ if (((cqe->status & EHEA_CQE_STAT_ERR_TCP) != 0) &&
++ (cqe->header_length == 0))
++ return 0;
++ return -EINVAL;
++}
++
++static inline void ehea_fill_skb(struct net_device *dev,
++ struct sk_buff *skb, struct ehea_cqe *cqe)
++{
++ int length = cqe->num_bytes_transfered - 4; /*remove CRC */
++
++ skb_put(skb, length);
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ skb->protocol = eth_type_trans(skb, dev);
++}
++
++static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
++ int arr_len,
++ struct ehea_cqe *cqe)
++{
++ int skb_index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
++ struct sk_buff *skb;
++ void *pref;
++ int x;
++
++ x = skb_index + 1;
++ x &= (arr_len - 1);
++
++ pref = skb_array[x];
++ prefetchw(pref);
++ prefetchw(pref + EHEA_CACHE_LINE);
++
++ pref = (skb_array[x]->data);
++ prefetch(pref);
++ prefetch(pref + EHEA_CACHE_LINE);
++ prefetch(pref + EHEA_CACHE_LINE * 2);
++ prefetch(pref + EHEA_CACHE_LINE * 3);
++ skb = skb_array[skb_index];
++ skb_array[skb_index] = NULL;
++ return skb;
++}
++
++static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
++ int arr_len, int wqe_index)
++{
++ struct sk_buff *skb;
++ void *pref;
++ int x;
++
++ x = wqe_index + 1;
++ x &= (arr_len - 1);
++
++ pref = skb_array[x];
++ prefetchw(pref);
++ prefetchw(pref + EHEA_CACHE_LINE);
++
++ pref = (skb_array[x]->data);
++ prefetchw(pref);
++ prefetchw(pref + EHEA_CACHE_LINE);
++
++ skb = skb_array[wqe_index];
++ skb_array[wqe_index] = NULL;
++ return skb;
++}
++
++static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
++ struct ehea_cqe *cqe, int *processed_rq2,
++ int *processed_rq3)
++{
++ struct sk_buff *skb;
++
++ if (netif_msg_rx_err(pr->port)) {
++ ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr);
++ ehea_dump(cqe, sizeof(*cqe), "CQE");
++ }
++
++ if (rq == 2) {
++ *processed_rq2 += 1;
++ skb = get_skb_by_index(pr->rq2_skba.arr, pr->rq2_skba.len, cqe);
++ dev_kfree_skb(skb);
++ } else if (rq == 3) {
++ *processed_rq3 += 1;
++ skb = get_skb_by_index(pr->rq3_skba.arr, pr->rq3_skba.len, cqe);
++ dev_kfree_skb(skb);
++ }
++
++ if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
++ ehea_error("Critical receive error. Resetting port.");
++ queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task);
++ return 1;
++ }
++
++ return 0;
++}
++
++static int ehea_poll(struct net_device *dev, int *budget)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_port_res *pr = &port->port_res[0];
++ struct ehea_qp *qp = pr->qp;
++ struct ehea_cqe *cqe;
++ struct sk_buff *skb;
++ struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
++ struct sk_buff **skb_arr_rq2 = pr->rq2_skba.arr;
++ struct sk_buff **skb_arr_rq3 = pr->rq3_skba.arr;
++ int skb_arr_rq1_len = pr->rq1_skba.len;
++ int skb_arr_rq2_len = pr->rq2_skba.len;
++ int skb_arr_rq3_len = pr->rq3_skba.len;
++ int processed, processed_rq1, processed_rq2, processed_rq3;
++ int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset;
++
++ processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
++ last_wqe_index = 0;
++ my_quota = min(*budget, dev->quota);
++ my_quota = min(my_quota, EHEA_POLL_MAX_RWQE);
++
++ /* rq0 is low latency RQ */
++ cqe = ehea_poll_rq1(qp, &wqe_index);
++ while ((my_quota > 0) && cqe) {
++ ehea_inc_rq1(qp);
++ processed_rq1++;
++ processed++;
++ my_quota--;
++ if (netif_msg_rx_status(port))
++ ehea_dump(cqe, sizeof(*cqe), "CQE");
++
++ last_wqe_index = wqe_index;
++ rmb();
++ if (!ehea_check_cqe(cqe, &rq)) {
++ if (rq == 1) { /* LL RQ1 */
++ skb = get_skb_by_index_ll(skb_arr_rq1,
++ skb_arr_rq1_len,
++ wqe_index);
++ if (unlikely(!skb)) {
++ if (netif_msg_rx_err(port))
++ ehea_error("LL rq1: skb=NULL");
++ skb = netdev_alloc_skb(dev,
++ EHEA_L_PKT_SIZE);
++ if (!skb)
++ break;
++ }
++ memcpy(skb->data, ((char*)cqe) + 64,
++ cqe->num_bytes_transfered - 4);
++ ehea_fill_skb(dev, skb, cqe);
++ } else if (rq == 2) { /* RQ2 */
++ skb = get_skb_by_index(skb_arr_rq2,
++ skb_arr_rq2_len, cqe);
++ if (unlikely(!skb)) {
++ if (netif_msg_rx_err(port))
++ ehea_error("rq2: skb=NULL");
++ break;
++ }
++ ehea_fill_skb(dev, skb, cqe);
++ processed_rq2++;
++ } else { /* RQ3 */
++ skb = get_skb_by_index(skb_arr_rq3,
++ skb_arr_rq3_len, cqe);
++ if (unlikely(!skb)) {
++ if (netif_msg_rx_err(port))
++ ehea_error("rq3: skb=NULL");
++ break;
++ }
++ ehea_fill_skb(dev, skb, cqe);
++ processed_rq3++;
++ }
++
++ if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
++ vlan_hwaccel_receive_skb(skb, port->vgrp,
++ cqe->vlan_tag);
++ else
++ netif_receive_skb(skb);
++
++ } else { /* Error occured */
++ pr->p_state.poll_receive_errors++;
++ port_reset = ehea_treat_poll_error(pr, rq, cqe,
++ &processed_rq2,
++ &processed_rq3);
++ if (port_reset)
++ break;
++ }
++ cqe = ehea_poll_rq1(qp, &wqe_index);
++ }
++
++ dev->quota -= processed;
++ *budget -= processed;
++
++ pr->p_state.ehea_poll += 1;
++ pr->rx_packets += processed;
++
++ ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
++ ehea_refill_rq2(pr, processed_rq2);
++ ehea_refill_rq3(pr, processed_rq3);
++
++ intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
++
++ if (!cqe || intreq) {
++ netif_rx_complete(dev);
++ ehea_reset_cq_ep(pr->recv_cq);
++ ehea_reset_cq_n1(pr->recv_cq);
++ cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
++ if (!cqe || intreq)
++ return 0;
++ if (!netif_rx_reschedule(dev, my_quota))
++ return 0;
++ }
++ return 1;
++}
++
++void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
++{
++ struct sk_buff *skb;
++ int index, max_index_mask, i;
++
++ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
++ max_index_mask = pr->sq_skba.len - 1;
++ for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
++ skb = pr->sq_skba.arr[index];
++ if (likely(skb)) {
++ dev_kfree_skb(skb);
++ pr->sq_skba.arr[index] = NULL;
++ } else {
++ ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d",
++ cqe->wr_id, i, index);
++ }
++ index--;
++ index &= max_index_mask;
++ }
++}
++
++#define MAX_SENDCOMP_QUOTA 400
++void ehea_send_irq_tasklet(unsigned long data)
++{
++ struct ehea_port_res *pr = (struct ehea_port_res*)data;
++ struct ehea_cq *send_cq = pr->send_cq;
++ struct ehea_cqe *cqe;
++ int quota = MAX_SENDCOMP_QUOTA;
++ int cqe_counter = 0;
++ int swqe_av = 0;
++ unsigned long flags;
++
++ do {
++ cqe = ehea_poll_cq(send_cq);
++ if (!cqe) {
++ ehea_reset_cq_ep(send_cq);
++ ehea_reset_cq_n1(send_cq);
++ cqe = ehea_poll_cq(send_cq);
++ if (!cqe)
++ break;
++ }
++ cqe_counter++;
++ rmb();
++ if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
++ ehea_error("Send Completion Error: Resetting port");
++ if (netif_msg_tx_err(pr->port))
++ ehea_dump(cqe, sizeof(*cqe), "Send CQE");
++ queue_work(pr->port->adapter->ehea_wq,
++ &pr->port->reset_task);
++ break;
++ }
++
++ if (netif_msg_tx_done(pr->port))
++ ehea_dump(cqe, sizeof(*cqe), "CQE");
++
++ if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
++ == EHEA_SWQE2_TYPE))
++ free_sent_skbs(cqe, pr);
++
++ swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
++ quota--;
++ } while (quota > 0);
++
++ ehea_update_feca(send_cq, cqe_counter);
++ atomic_add(swqe_av, &pr->swqe_avail);
++
++ spin_lock_irqsave(&pr->netif_queue, flags);
++ if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
++ >= pr->swqe_refill_th)) {
++ netif_wake_queue(pr->port->netdev);
++ pr->queue_stopped = 0;
++ }
++ spin_unlock_irqrestore(&pr->netif_queue, flags);
++
++ if (unlikely(cqe))
++ tasklet_hi_schedule(&pr->send_comp_task);
++}
++
++static irqreturn_t ehea_send_irq_handler(int irq, void *param)
++{
++ struct ehea_port_res *pr = param;
++ tasklet_hi_schedule(&pr->send_comp_task);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
++{
++ struct ehea_port_res *pr = param;
++ struct ehea_port *port = pr->port;
++ netif_rx_schedule(port->netdev);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
++{
++ struct ehea_port *port = param;
++ struct ehea_eqe *eqe;
++ u32 qp_token;
++
++ eqe = ehea_poll_eq(port->qp_eq);
++ ehea_debug("eqe=%p", eqe);
++ while (eqe) {
++ ehea_debug("*eqe=%lx", *(u64*)eqe);
++ eqe = ehea_poll_eq(port->qp_eq);
++ qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
++ ehea_debug("next eqe=%p", eqe);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
++ int logical_port)
++{
++ int i;
++
++ for (i = 0; i < adapter->num_ports; i++)
++ if (adapter->port[i]->logical_port_id == logical_port)
++ return adapter->port[i];
++ return NULL;
++}
++
++int ehea_sense_port_attr(struct ehea_port *port)
++{
++ int ret;
++ u64 hret;
++ struct hcp_ehea_port_cb0 *cb0;
++
++ cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC); /* May be called via */
++ if (!cb0) { /* ehea_neq_tasklet() */
++ ehea_error("no mem for cb0");
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_port(port->adapter->handle,
++ port->logical_port_id, H_PORT_CB0,
++ EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF),
++ cb0);
++ if (hret != H_SUCCESS) {
++ ret = -EIO;
++ goto out_free;
++ }
++
++ /* MAC address */
++ port->mac_addr = cb0->port_mac_addr << 16;
++
++ if (!is_valid_ether_addr((u8*)&port->mac_addr)) {
++ ret = -EADDRNOTAVAIL;
++ goto out_free;
++ }
++
++ /* Port speed */
++ switch (cb0->port_speed) {
++ case H_SPEED_10M_H:
++ port->port_speed = EHEA_SPEED_10M;
++ port->full_duplex = 0;
++ break;
++ case H_SPEED_10M_F:
++ port->port_speed = EHEA_SPEED_10M;
++ port->full_duplex = 1;
++ break;
++ case H_SPEED_100M_H:
++ port->port_speed = EHEA_SPEED_100M;
++ port->full_duplex = 0;
++ break;
++ case H_SPEED_100M_F:
++ port->port_speed = EHEA_SPEED_100M;
++ port->full_duplex = 1;
++ break;
++ case H_SPEED_1G_F:
++ port->port_speed = EHEA_SPEED_1G;
++ port->full_duplex = 1;
++ break;
++ case H_SPEED_10G_F:
++ port->port_speed = EHEA_SPEED_10G;
++ port->full_duplex = 1;
++ break;
++ default:
++ port->port_speed = 0;
++ port->full_duplex = 0;
++ break;
++ }
++
++ /* Number of default QPs */
++ port->num_def_qps = cb0->num_default_qps;
++
++ if (!port->num_def_qps) {
++ ret = -EINVAL;
++ goto out_free;
++ }
++
++ if (port->num_def_qps >= EHEA_NUM_TX_QP)
++ port->num_add_tx_qps = 0;
++ else
++ port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
++
++ ret = 0;
++out_free:
++ if (ret || netif_msg_probe(port))
++ ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr");
++ kfree(cb0);
++out:
++ return ret;
++}
++
++int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
++{
++ struct hcp_ehea_port_cb4 *cb4;
++ u64 hret;
++ int ret = 0;
++
++ cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb4) {
++ ehea_error("no mem for cb4");
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ cb4->port_speed = port_speed;
++
++ netif_carrier_off(port->netdev);
++
++ hret = ehea_h_modify_ehea_port(port->adapter->handle,
++ port->logical_port_id,
++ H_PORT_CB4, H_PORT_CB4_SPEED, cb4);
++ if (hret == H_SUCCESS) {
++ port->autoneg = port_speed == EHEA_SPEED_AUTONEG ? 1 : 0;
++
++ hret = ehea_h_query_ehea_port(port->adapter->handle,
++ port->logical_port_id,
++ H_PORT_CB4, H_PORT_CB4_SPEED,
++ cb4);
++ if (hret == H_SUCCESS) {
++ switch (cb4->port_speed) {
++ case H_SPEED_10M_H:
++ port->port_speed = EHEA_SPEED_10M;
++ port->full_duplex = 0;
++ break;
++ case H_SPEED_10M_F:
++ port->port_speed = EHEA_SPEED_10M;
++ port->full_duplex = 1;
++ break;
++ case H_SPEED_100M_H:
++ port->port_speed = EHEA_SPEED_100M;
++ port->full_duplex = 0;
++ break;
++ case H_SPEED_100M_F:
++ port->port_speed = EHEA_SPEED_100M;
++ port->full_duplex = 1;
++ break;
++ case H_SPEED_1G_F:
++ port->port_speed = EHEA_SPEED_1G;
++ port->full_duplex = 1;
++ break;
++ case H_SPEED_10G_F:
++ port->port_speed = EHEA_SPEED_10G;
++ port->full_duplex = 1;
++ break;
++ default:
++ port->port_speed = 0;
++ port->full_duplex = 0;
++ break;
++ }
++ } else {
++ ehea_error("Failed sensing port speed");
++ ret = -EIO;
++ }
++ } else {
++ if (hret == H_AUTHORITY) {
++ ehea_info("Hypervisor denied setting port speed. Either"
++ " this partition is not authorized to set "
++ "port speed or another partition has modified"
++ " port speed first.");
++ ret = -EPERM;
++ } else {
++ ret = -EIO;
++ ehea_error("Failed setting port speed");
++ }
++ }
++ netif_carrier_on(port->netdev);
++ kfree(cb4);
++out:
++ return ret;
++}
++
++static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
++{
++ int ret;
++ u8 ec;
++ u8 portnum;
++ struct ehea_port *port;
++
++ ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
++ portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
++ port = ehea_get_port(adapter, portnum);
++
++ switch (ec) {
++ case EHEA_EC_PORTSTATE_CHG: /* port state change */
++
++ if (!port) {
++ ehea_error("unknown portnum %x", portnum);
++ break;
++ }
++
++ if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
++ if (!netif_carrier_ok(port->netdev)) {
++ ret = ehea_sense_port_attr(port);
++ if (ret) {
++ ehea_error("failed resensing port "
++ "attributes");
++ break;
++ }
++
++ if (netif_msg_link(port))
++ ehea_info("%s: Logical port up: %dMbps "
++ "%s Duplex",
++ port->netdev->name,
++ port->port_speed,
++ port->full_duplex ==
++ 1 ? "Full" : "Half");
++
++ netif_carrier_on(port->netdev);
++ netif_wake_queue(port->netdev);
++ }
++ } else
++ if (netif_carrier_ok(port->netdev)) {
++ if (netif_msg_link(port))
++ ehea_info("%s: Logical port down",
++ port->netdev->name);
++ netif_carrier_off(port->netdev);
++ netif_stop_queue(port->netdev);
++ }
++
++ if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
++ if (netif_msg_link(port))
++ ehea_info("%s: Physical port up",
++ port->netdev->name);
++ } else {
++ if (netif_msg_link(port))
++ ehea_info("%s: Physical port down",
++ port->netdev->name);
++ }
++
++ if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
++ ehea_info("External switch port is primary port");
++ else
++ ehea_info("External switch port is backup port");
++
++ break;
++ case EHEA_EC_ADAPTER_MALFUNC:
++ ehea_error("Adapter malfunction");
++ break;
++ case EHEA_EC_PORT_MALFUNC:
++ ehea_info("Port malfunction: Device: %s", port->netdev->name);
++ netif_carrier_off(port->netdev);
++ netif_stop_queue(port->netdev);
++ break;
++ default:
++ ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe);
++ break;
++ }
++}
++
++static void ehea_neq_tasklet(unsigned long data)
++{
++ struct ehea_adapter *adapter = (struct ehea_adapter*)data;
++ struct ehea_eqe *eqe;
++ u64 event_mask;
++
++ eqe = ehea_poll_eq(adapter->neq);
++ ehea_debug("eqe=%p", eqe);
++
++ while (eqe) {
++ ehea_debug("*eqe=%lx", eqe->entry);
++ ehea_parse_eqe(adapter, eqe->entry);
++ eqe = ehea_poll_eq(adapter->neq);
++ ehea_debug("next eqe=%p", eqe);
++ }
++
++ event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1)
++ | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1)
++ | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1);
++
++ ehea_h_reset_events(adapter->handle,
++ adapter->neq->fw_handle, event_mask);
++}
++
++static irqreturn_t ehea_interrupt_neq(int irq, void *param)
++{
++ struct ehea_adapter *adapter = param;
++ tasklet_hi_schedule(&adapter->neq_tasklet);
++ return IRQ_HANDLED;
++}
++
++
++static int ehea_fill_port_res(struct ehea_port_res *pr)
++{
++ int ret;
++ struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
++
++ ret = ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
++ - init_attr->act_nr_rwqes_rq2
++ - init_attr->act_nr_rwqes_rq3 - 1);
++
++ ret |= ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1);
++
++ ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3 - 1);
++
++ return ret;
++}
++
++static int ehea_reg_interrupts(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_port_res *pr;
++ int i, ret;
++
++ for (i = 0; i < port->num_def_qps; i++) {
++ pr = &port->port_res[i];
++ snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
++ , "%s-recv%d", dev->name, i);
++ ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
++ ehea_recv_irq_handler,
++ SA_INTERRUPT, pr->int_recv_name, pr);
++ if (ret) {
++ ehea_error("failed registering irq for ehea_recv_int:"
++ "port_res_nr:%d, ist=%X", i,
++ pr->recv_eq->attr.ist1);
++ goto out_free_seq;
++ }
++ if (netif_msg_ifup(port))
++ ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
++ "registered", pr->recv_eq->attr.ist1, i);
++ }
++
++ snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
++ dev->name);
++
++ ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1,
++ ehea_qp_aff_irq_handler,
++ SA_INTERRUPT, port->int_aff_name, port);
++ if (ret) {
++ ehea_error("failed registering irq for qp_aff_irq_handler:"
++ "ist=%X", port->qp_eq->attr.ist1);
++ goto out_free_qpeq;
++ }
++
++ if (netif_msg_ifup(port))
++ ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
++ "registered", port->qp_eq->attr.ist1);
++
++ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
++ pr = &port->port_res[i];
++ snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
++ "%s-send%d", dev->name, i);
++ ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
++ ehea_send_irq_handler,
++ SA_INTERRUPT, pr->int_send_name,
++ pr);
++ if (ret) {
++ ehea_error("failed registering irq for ehea_send "
++ "port_res_nr:%d, ist=%X", i,
++ pr->send_eq->attr.ist1);
++ goto out_free_req;
++ }
++ if (netif_msg_ifup(port))
++ ehea_info("irq_handle 0x%X for function ehea_send_int "
++ "%d registered", pr->send_eq->attr.ist1, i);
++ }
++out:
++ return ret;
++
++out_free_req:
++ while (--i >= 0) {
++ u32 ist = port->port_res[i].send_eq->attr.ist1;
++ ibmebus_free_irq(NULL, ist, &port->port_res[i]);
++ }
++out_free_qpeq:
++ ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
++ i = port->num_def_qps;
++out_free_seq:
++ while (--i >= 0) {
++ u32 ist = port->port_res[i].recv_eq->attr.ist1;
++ ibmebus_free_irq(NULL, ist, &port->port_res[i]);
++ }
++ goto out;
++}
++
++static void ehea_free_interrupts(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_port_res *pr;
++ int i;
++
++ /* send */
++ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
++ pr = &port->port_res[i];
++ ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr);
++ if (netif_msg_intr(port))
++ ehea_info("free send irq for res %d with handle 0x%X",
++ i, pr->send_eq->attr.ist1);
++ }
++
++ /* receive */
++ for (i = 0; i < port->num_def_qps; i++) {
++ pr = &port->port_res[i];
++ ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr);
++ if (netif_msg_intr(port))
++ ehea_info("free recv irq for res %d with handle 0x%X",
++ i, pr->recv_eq->attr.ist1);
++ }
++
++ /* associated events */
++ ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
++ if (netif_msg_intr(port))
++ ehea_info("associated event interrupt for handle 0x%X freed",
++ port->qp_eq->attr.ist1);
++}
++
++static int ehea_configure_port(struct ehea_port *port)
++{
++ int ret, i;
++ u64 hret, mask;
++ struct hcp_ehea_port_cb0 *cb0;
++
++ ret = -ENOMEM;
++ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb0)
++ goto out;
++
++ cb0->port_rc = EHEA_BMASK_SET(PXLY_RC_VALID, 1)
++ | EHEA_BMASK_SET(PXLY_RC_IP_CHKSUM, 1)
++ | EHEA_BMASK_SET(PXLY_RC_TCP_UDP_CHKSUM, 1)
++ | EHEA_BMASK_SET(PXLY_RC_VLAN_XTRACT, 1)
++ | EHEA_BMASK_SET(PXLY_RC_VLAN_TAG_FILTER,
++ PXLY_RC_VLAN_FILTER)
++ | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
++
++ for (i = 0; i < port->num_def_qps; i++)
++ cb0->default_qpn_arr[i] = port->port_res[i].qp->init_attr.qp_nr;
++
++ if (netif_msg_ifup(port))
++ ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
++
++ mask = EHEA_BMASK_SET(H_PORT_CB0_PRC, 1)
++ | EHEA_BMASK_SET(H_PORT_CB0_DEFQPNARRAY, 1);
++
++ hret = ehea_h_modify_ehea_port(port->adapter->handle,
++ port->logical_port_id,
++ H_PORT_CB0, mask, cb0);
++ ret = -EIO;
++ if (hret != H_SUCCESS)
++ goto out_free;
++
++ ret = 0;
++
++out_free:
++ kfree(cb0);
++out:
++ return ret;
++}
++
++static int ehea_gen_smrs(struct ehea_port_res *pr)
++{
++ u64 hret;
++ struct ehea_adapter *adapter = pr->port->adapter;
++
++ hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
++ adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
++ adapter->pd, &pr->send_mr);
++ if (hret != H_SUCCESS)
++ goto out;
++
++ hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
++ adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
++ adapter->pd, &pr->recv_mr);
++ if (hret != H_SUCCESS)
++ goto out_freeres;
++
++ return 0;
++
++out_freeres:
++ hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
++ if (hret != H_SUCCESS)
++ ehea_error("failed freeing SMR");
++out:
++ return -EIO;
++}
++
++static int ehea_rem_smrs(struct ehea_port_res *pr)
++{
++ struct ehea_adapter *adapter = pr->port->adapter;
++ int ret = 0;
++ u64 hret;
++
++ hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
++ if (hret != H_SUCCESS) {
++ ret = -EIO;
++ ehea_error("failed freeing send SMR for pr=%p", pr);
++ }
++
++ hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle);
++ if (hret != H_SUCCESS) {
++ ret = -EIO;
++ ehea_error("failed freeing recv SMR for pr=%p", pr);
++ }
++
++ return ret;
++}
++
++static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
++{
++ int arr_size = sizeof(void*) * max_q_entries;
++
++ q_skba->arr = vmalloc(arr_size);
++ if (!q_skba->arr)
++ return -ENOMEM;
++
++ memset(q_skba->arr, 0, arr_size);
++
++ q_skba->len = max_q_entries;
++ q_skba->index = 0;
++ q_skba->os_skbs = 0;
++
++ return 0;
++}
++
++static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
++ struct port_res_cfg *pr_cfg, int queue_token)
++{
++ struct ehea_adapter *adapter = port->adapter;
++ enum ehea_eq_type eq_type = EHEA_EQ;
++ struct ehea_qp_init_attr *init_attr = NULL;
++ int ret = -EIO;
++
++ memset(pr, 0, sizeof(struct ehea_port_res));
++
++ pr->port = port;
++ spin_lock_init(&pr->send_lock);
++ spin_lock_init(&pr->recv_lock);
++ spin_lock_init(&pr->xmit_lock);
++ spin_lock_init(&pr->netif_queue);
++
++ pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
++ if (!pr->recv_eq) {
++ ehea_error("create_eq failed (recv_eq)");
++ goto out_free;
++ }
++
++ pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
++ if (!pr->send_eq) {
++ ehea_error("create_eq failed (send_eq)");
++ goto out_free;
++ }
++
++ pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
++ pr->recv_eq->fw_handle,
++ port->logical_port_id);
++ if (!pr->recv_cq) {
++ ehea_error("create_cq failed (cq_recv)");
++ goto out_free;
++ }
++
++ pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
++ pr->send_eq->fw_handle,
++ port->logical_port_id);
++ if (!pr->send_cq) {
++ ehea_error("create_cq failed (cq_send)");
++ goto out_free;
++ }
++
++ if (netif_msg_ifup(port))
++ ehea_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d",
++ pr->send_cq->attr.act_nr_of_cqes,
++ pr->recv_cq->attr.act_nr_of_cqes);
++
++ init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
++ if (!init_attr) {
++ ret = -ENOMEM;
++ ehea_error("no mem for ehea_qp_init_attr");
++ goto out_free;
++ }
++
++ init_attr->low_lat_rq1 = 1;
++ init_attr->signalingtype = 1; /* generate CQE if specified in WQE */
++ init_attr->rq_count = 3;
++ init_attr->qp_token = queue_token;
++ init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq;
++ init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1;
++ init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2;
++ init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3;
++ init_attr->wqe_size_enc_sq = EHEA_SG_SQ;
++ init_attr->wqe_size_enc_rq1 = EHEA_SG_RQ1;
++ init_attr->wqe_size_enc_rq2 = EHEA_SG_RQ2;
++ init_attr->wqe_size_enc_rq3 = EHEA_SG_RQ3;
++ init_attr->rq2_threshold = EHEA_RQ2_THRESHOLD;
++ init_attr->rq3_threshold = EHEA_RQ3_THRESHOLD;
++ init_attr->port_nr = port->logical_port_id;
++ init_attr->send_cq_handle = pr->send_cq->fw_handle;
++ init_attr->recv_cq_handle = pr->recv_cq->fw_handle;
++ init_attr->aff_eq_handle = port->qp_eq->fw_handle;
++
++ pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr);
++ if (!pr->qp) {
++ ehea_error("create_qp failed");
++ ret = -EIO;
++ goto out_free;
++ }
++
++ if (netif_msg_ifup(port))
++ ehea_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n "
++ "nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d", init_attr->qp_nr,
++ init_attr->act_nr_send_wqes,
++ init_attr->act_nr_rwqes_rq1,
++ init_attr->act_nr_rwqes_rq2,
++ init_attr->act_nr_rwqes_rq3);
++
++ ret = ehea_init_q_skba(&pr->sq_skba, init_attr->act_nr_send_wqes + 1);
++ ret |= ehea_init_q_skba(&pr->rq1_skba, init_attr->act_nr_rwqes_rq1 + 1);
++ ret |= ehea_init_q_skba(&pr->rq2_skba, init_attr->act_nr_rwqes_rq2 + 1);
++ ret |= ehea_init_q_skba(&pr->rq3_skba, init_attr->act_nr_rwqes_rq3 + 1);
++ if (ret)
++ goto out_free;
++
++ pr->swqe_refill_th = init_attr->act_nr_send_wqes / 10;
++ if (ehea_gen_smrs(pr) != 0) {
++ ret = -EIO;
++ goto out_free;
++ }
++ tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
++ (unsigned long)pr);
++ atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
++
++ kfree(init_attr);
++ ret = 0;
++ goto out;
++
++out_free:
++ kfree(init_attr);
++ vfree(pr->sq_skba.arr);
++ vfree(pr->rq1_skba.arr);
++ vfree(pr->rq2_skba.arr);
++ vfree(pr->rq3_skba.arr);
++ ehea_destroy_qp(pr->qp);
++ ehea_destroy_cq(pr->send_cq);
++ ehea_destroy_cq(pr->recv_cq);
++ ehea_destroy_eq(pr->send_eq);
++ ehea_destroy_eq(pr->recv_eq);
++out:
++ return ret;
++}
++
++static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
++{
++ int ret, i;
++
++ ret = ehea_destroy_qp(pr->qp);
++
++ if (!ret) {
++ ehea_destroy_cq(pr->send_cq);
++ ehea_destroy_cq(pr->recv_cq);
++ ehea_destroy_eq(pr->send_eq);
++ ehea_destroy_eq(pr->recv_eq);
++
++ for (i = 0; i < pr->rq1_skba.len; i++)
++ if (pr->rq1_skba.arr[i])
++ dev_kfree_skb(pr->rq1_skba.arr[i]);
++
++ for (i = 0; i < pr->rq2_skba.len; i++)
++ if (pr->rq2_skba.arr[i])
++ dev_kfree_skb(pr->rq2_skba.arr[i]);
++
++ for (i = 0; i < pr->rq3_skba.len; i++)
++ if (pr->rq3_skba.arr[i])
++ dev_kfree_skb(pr->rq3_skba.arr[i]);
++
++ for (i = 0; i < pr->sq_skba.len; i++)
++ if (pr->sq_skba.arr[i])
++ dev_kfree_skb(pr->sq_skba.arr[i]);
++
++ vfree(pr->rq1_skba.arr);
++ vfree(pr->rq2_skba.arr);
++ vfree(pr->rq3_skba.arr);
++ vfree(pr->sq_skba.arr);
++ ret = ehea_rem_smrs(pr);
++ }
++ return ret;
++}
++
++/*
++ * The write_* functions store information in swqe which is used by
++ * the hardware to calculate the ip/tcp/udp checksum
++ */
++
++static inline void write_ip_start_end(struct ehea_swqe *swqe,
++ const struct sk_buff *skb)
++{
++ swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data));
++ swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl * 4 - 1);
++}
++
++static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
++ const struct sk_buff *skb)
++{
++ swqe->tcp_offset =
++ (u8)(swqe->ip_end + 1 + offsetof(struct tcphdr, check));
++
++ swqe->tcp_end = (u16)skb->len - 1;
++}
++
++static inline void write_udp_offset_end(struct ehea_swqe *swqe,
++ const struct sk_buff *skb)
++{
++ swqe->tcp_offset =
++ (u8)(swqe->ip_end + 1 + offsetof(struct udphdr, check));
++
++ swqe->tcp_end = (u16)skb->len - 1;
++}
++
++
++static void write_swqe2_TSO(struct sk_buff *skb,
++ struct ehea_swqe *swqe, u32 lkey)
++{
++ struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
++ u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
++ int skb_data_size = skb->len - skb->data_len;
++ int headersize;
++ u64 tmp_addr;
++
++ /* Packet is TCP with TSO enabled */
++ swqe->tx_control |= EHEA_SWQE_TSO;
++ swqe->mss = skb_shinfo(skb)->gso_size;
++ /* copy only eth/ip/tcp headers to immediate data and
++ * the rest of skb->data to sg1entry
++ */
++ headersize = ETH_HLEN + (skb->nh.iph->ihl * 4) + (skb->h.th->doff * 4);
++
++ skb_data_size = skb->len - skb->data_len;
++
++ if (skb_data_size >= headersize) {
++ /* copy immediate data */
++ memcpy(imm_data, skb->data, headersize);
++ swqe->immediate_data_length = headersize;
++
++ if (skb_data_size > headersize) {
++ /* set sg1entry data */
++ sg1entry->l_key = lkey;
++ sg1entry->len = skb_data_size - headersize;
++
++ tmp_addr = (u64)(skb->data + headersize);
++ sg1entry->vaddr = tmp_addr;
++ swqe->descriptors++;
++ }
++ } else
++ ehea_error("cannot handle fragmented headers");
++}
++
++static void write_swqe2_nonTSO(struct sk_buff *skb,
++ struct ehea_swqe *swqe, u32 lkey)
++{
++ int skb_data_size = skb->len - skb->data_len;
++ u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
++ struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
++ u64 tmp_addr;
++
++ /* Packet is any nonTSO type
++ *
++ * Copy as much as possible skb->data to immediate data and
++ * the rest to sg1entry
++ */
++ if (skb_data_size >= SWQE2_MAX_IMM) {
++ /* copy immediate data */
++ memcpy(imm_data, skb->data, SWQE2_MAX_IMM);
++
++ swqe->immediate_data_length = SWQE2_MAX_IMM;
++
++ if (skb_data_size > SWQE2_MAX_IMM) {
++ /* copy sg1entry data */
++ sg1entry->l_key = lkey;
++ sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
++ tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
++ sg1entry->vaddr = tmp_addr;
++ swqe->descriptors++;
++ }
++ } else {
++ memcpy(imm_data, skb->data, skb_data_size);
++ swqe->immediate_data_length = skb_data_size;
++ }
++}
++
++static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
++ struct ehea_swqe *swqe, u32 lkey)
++{
++ struct ehea_vsgentry *sg_list, *sg1entry, *sgentry;
++ skb_frag_t *frag;
++ int nfrags, sg1entry_contains_frag_data, i;
++ u64 tmp_addr;
++
++ nfrags = skb_shinfo(skb)->nr_frags;
++ sg1entry = &swqe->u.immdata_desc.sg_entry;
++ sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
++ swqe->descriptors = 0;
++ sg1entry_contains_frag_data = 0;
++
++ if ((dev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size)
++ write_swqe2_TSO(skb, swqe, lkey);
++ else
++ write_swqe2_nonTSO(skb, swqe, lkey);
++
++ /* write descriptors */
++ if (nfrags > 0) {
++ if (swqe->descriptors == 0) {
++ /* sg1entry not yet used */
++ frag = &skb_shinfo(skb)->frags[0];
++
++ /* copy sg1entry data */
++ sg1entry->l_key = lkey;
++ sg1entry->len = frag->size;
++ tmp_addr = (u64)(page_address(frag->page)
++ + frag->page_offset);
++ sg1entry->vaddr = tmp_addr;
++ swqe->descriptors++;
++ sg1entry_contains_frag_data = 1;
++ }
++
++ for (i = sg1entry_contains_frag_data; i < nfrags; i++) {
++
++ frag = &skb_shinfo(skb)->frags[i];
++ sgentry = &sg_list[i - sg1entry_contains_frag_data];
++
++ sgentry->l_key = lkey;
++ sgentry->len = frag->size;
++
++ tmp_addr = (u64)(page_address(frag->page)
++ + frag->page_offset);
++ sgentry->vaddr = tmp_addr;
++ swqe->descriptors++;
++ }
++ }
++}
++
++static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
++{
++ int ret = 0;
++ u64 hret;
++ u8 reg_type;
++
++ /* De/Register untagged packets */
++ reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_UNTAGGED;
++ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
++ port->logical_port_id,
++ reg_type, port->mac_addr, 0, hcallid);
++ if (hret != H_SUCCESS) {
++ ehea_error("reg_dereg_bcmc failed (tagged)");
++ ret = -EIO;
++ goto out_herr;
++ }
++
++ /* De/Register VLAN packets */
++ reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL;
++ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
++ port->logical_port_id,
++ reg_type, port->mac_addr, 0, hcallid);
++ if (hret != H_SUCCESS) {
++ ehea_error("reg_dereg_bcmc failed (vlan)");
++ ret = -EIO;
++ }
++out_herr:
++ return ret;
++}
++
++static int ehea_set_mac_addr(struct net_device *dev, void *sa)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct sockaddr *mac_addr = sa;
++ struct hcp_ehea_port_cb0 *cb0;
++ int ret;
++ u64 hret;
++
++ if (!is_valid_ether_addr(mac_addr->sa_data)) {
++ ret = -EADDRNOTAVAIL;
++ goto out;
++ }
++
++ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb0) {
++ ehea_error("no mem for cb0");
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ memcpy(&(cb0->port_mac_addr), &(mac_addr->sa_data[0]), ETH_ALEN);
++
++ cb0->port_mac_addr = cb0->port_mac_addr >> 16;
++
++ hret = ehea_h_modify_ehea_port(port->adapter->handle,
++ port->logical_port_id, H_PORT_CB0,
++ EHEA_BMASK_SET(H_PORT_CB0_MAC, 1), cb0);
++ if (hret != H_SUCCESS) {
++ ret = -EIO;
++ goto out_free;
++ }
++
++ memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
++
++ /* Deregister old MAC in pHYP */
++ ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
++ if (ret)
++ goto out_free;
++
++ port->mac_addr = cb0->port_mac_addr << 16;
++
++ /* Register new MAC in pHYP */
++ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
++ if (ret)
++ goto out_free;
++
++ ret = 0;
++out_free:
++ kfree(cb0);
++out:
++ return ret;
++}
++
++static void ehea_promiscuous_error(u64 hret, int enable)
++{
++ ehea_info("Hypervisor denied %sabling promiscuous mode.%s",
++ enable == 1 ? "en" : "dis",
++ hret != H_AUTHORITY ? "" : " Another partition owning a "
++ "logical port on the same physical port might have altered "
++ "promiscuous mode first.");
++}
++
++static void ehea_promiscuous(struct net_device *dev, int enable)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct hcp_ehea_port_cb7 *cb7;
++ u64 hret;
++
++ if ((enable && port->promisc) || (!enable && !port->promisc))
++ return;
++
++ cb7 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
++ if (!cb7) {
++ ehea_error("no mem for cb7");
++ goto out;
++ }
++
++ /* Modify Pxs_DUCQPN in CB7 */
++ cb7->def_uc_qpn = enable == 1 ? port->port_res[0].qp->fw_handle : 0;
++
++ hret = ehea_h_modify_ehea_port(port->adapter->handle,
++ port->logical_port_id,
++ H_PORT_CB7, H_PORT_CB7_DUCQPN, cb7);
++ if (hret) {
++ ehea_promiscuous_error(hret, enable);
++ goto out;
++ }
++
++ port->promisc = enable;
++out:
++ kfree(cb7);
++ return;
++}
++
++static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
++ u32 hcallid)
++{
++ u64 hret;
++ u8 reg_type;
++
++ reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
++ | EHEA_BCMC_UNTAGGED;
++
++ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
++ port->logical_port_id,
++ reg_type, mc_mac_addr, 0, hcallid);
++ if (hret)
++ goto out;
++
++ reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
++ | EHEA_BCMC_VLANID_ALL;
++
++ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
++ port->logical_port_id,
++ reg_type, mc_mac_addr, 0, hcallid);
++out:
++ return hret;
++}
++
++static int ehea_drop_multicast_list(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_mc_list *mc_entry = port->mc_list;
++ struct list_head *pos;
++ struct list_head *temp;
++ int ret = 0;
++ u64 hret;
++
++ list_for_each_safe(pos, temp, &(port->mc_list->list)) {
++ mc_entry = list_entry(pos, struct ehea_mc_list, list);
++
++ hret = ehea_multicast_reg_helper(port, mc_entry->macaddr,
++ H_DEREG_BCMC);
++ if (hret) {
++ ehea_error("failed deregistering mcast MAC");
++ ret = -EIO;
++ }
++
++ list_del(pos);
++ kfree(mc_entry);
++ }
++ return ret;
++}
++
++static void ehea_allmulti(struct net_device *dev, int enable)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ u64 hret;
++
++ if (!port->allmulti) {
++ if (enable) {
++ /* Enable ALLMULTI */
++ ehea_drop_multicast_list(dev);
++ hret = ehea_multicast_reg_helper(port, 0, H_REG_BCMC);
++ if (!hret)
++ port->allmulti = 1;
++ else
++ ehea_error("failed enabling IFF_ALLMULTI");
++ }
++ } else
++ if (!enable) {
++ /* Disable ALLMULTI */
++ hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
++ if (!hret)
++ port->allmulti = 0;
++ else
++ ehea_error("failed disabling IFF_ALLMULTI");
++ }
++}
++
++static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
++{
++ struct ehea_mc_list *ehea_mcl_entry;
++ u64 hret;
++
++ ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC);
++ if (!ehea_mcl_entry) {
++ ehea_error("no mem for mcl_entry");
++ return;
++ }
++
++ INIT_LIST_HEAD(&ehea_mcl_entry->list);
++
++ memcpy(&ehea_mcl_entry->macaddr, mc_mac_addr, ETH_ALEN);
++
++ hret = ehea_multicast_reg_helper(port, ehea_mcl_entry->macaddr,
++ H_REG_BCMC);
++ if (!hret)
++ list_add(&ehea_mcl_entry->list, &port->mc_list->list);
++ else {
++ ehea_error("failed registering mcast MAC");
++ kfree(ehea_mcl_entry);
++ }
++}
++
++static void ehea_set_multicast_list(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct dev_mc_list *k_mcl_entry;
++ int ret, i;
++
++ if (dev->flags & IFF_PROMISC) {
++ ehea_promiscuous(dev, 1);
++ return;
++ }
++ ehea_promiscuous(dev, 0);
++
++ if (dev->flags & IFF_ALLMULTI) {
++ ehea_allmulti(dev, 1);
++ return;
++ }
++ ehea_allmulti(dev, 0);
++
++ if (dev->mc_count) {
++ ret = ehea_drop_multicast_list(dev);
++ if (ret) {
++ /* Dropping the current multicast list failed.
++ * Enabling ALL_MULTI is the best we can do.
++ */
++ ehea_allmulti(dev, 1);
++ }
++
++ if (dev->mc_count > port->adapter->max_mc_mac) {
++ ehea_info("Mcast registration limit reached (0x%lx). "
++ "Use ALLMULTI!",
++ port->adapter->max_mc_mac);
++ goto out;
++ }
++
++ for (i = 0, k_mcl_entry = dev->mc_list;
++ i < dev->mc_count;
++ i++, k_mcl_entry = k_mcl_entry->next) {
++ ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr);
++ }
++ }
++out:
++ return;
++}
++
++static int ehea_change_mtu(struct net_device *dev, int new_mtu)
++{
++ if ((new_mtu < 68) || (new_mtu > EHEA_MAX_PACKET_SIZE))
++ return -EINVAL;
++ dev->mtu = new_mtu;
++ return 0;
++}
++
++static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
++ struct ehea_swqe *swqe, u32 lkey)
++{
++ if (skb->protocol == htons(ETH_P_IP)) {
++ /* IPv4 */
++ swqe->tx_control |= EHEA_SWQE_CRC
++ | EHEA_SWQE_IP_CHECKSUM
++ | EHEA_SWQE_TCP_CHECKSUM
++ | EHEA_SWQE_IMM_DATA_PRESENT
++ | EHEA_SWQE_DESCRIPTORS_PRESENT;
++
++ write_ip_start_end(swqe, skb);
++
++ if (skb->nh.iph->protocol == IPPROTO_UDP) {
++ if ((skb->nh.iph->frag_off & IP_MF) ||
++ (skb->nh.iph->frag_off & IP_OFFSET))
++ /* IP fragment, so don't change cs */
++ swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
++ else
++ write_udp_offset_end(swqe, skb);
++
++ } else if (skb->nh.iph->protocol == IPPROTO_TCP) {
++ write_tcp_offset_end(swqe, skb);
++ }
++
++ /* icmp (big data) and ip segmentation packets (all other ip
++ packets) do not require any special handling */
++
++ } else {
++ /* Other Ethernet Protocol */
++ swqe->tx_control |= EHEA_SWQE_CRC
++ | EHEA_SWQE_IMM_DATA_PRESENT
++ | EHEA_SWQE_DESCRIPTORS_PRESENT;
++ }
++
++ write_swqe2_data(skb, dev, swqe, lkey);
++}
++
++static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
++ struct ehea_swqe *swqe)
++{
++ int nfrags = skb_shinfo(skb)->nr_frags;
++ u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
++ skb_frag_t *frag;
++ int i;
++
++ if (skb->protocol == htons(ETH_P_IP)) {
++ /* IPv4 */
++ write_ip_start_end(swqe, skb);
++
++ if (skb->nh.iph->protocol == IPPROTO_TCP) {
++ swqe->tx_control |= EHEA_SWQE_CRC
++ | EHEA_SWQE_IP_CHECKSUM
++ | EHEA_SWQE_TCP_CHECKSUM
++ | EHEA_SWQE_IMM_DATA_PRESENT;
++
++ write_tcp_offset_end(swqe, skb);
++
++ } else if (skb->nh.iph->protocol == IPPROTO_UDP) {
++ if ((skb->nh.iph->frag_off & IP_MF) ||
++ (skb->nh.iph->frag_off & IP_OFFSET))
++ /* IP fragment, so don't change cs */
++ swqe->tx_control |= EHEA_SWQE_CRC
++ | EHEA_SWQE_IMM_DATA_PRESENT;
++ else {
++ swqe->tx_control |= EHEA_SWQE_CRC
++ | EHEA_SWQE_IP_CHECKSUM
++ | EHEA_SWQE_TCP_CHECKSUM
++ | EHEA_SWQE_IMM_DATA_PRESENT;
++
++ write_udp_offset_end(swqe, skb);
++ }
++ } else {
++ /* icmp (big data) and
++ ip segmentation packets (all other ip packets) */
++ swqe->tx_control |= EHEA_SWQE_CRC
++ | EHEA_SWQE_IP_CHECKSUM
++ | EHEA_SWQE_IMM_DATA_PRESENT;
++ }
++ } else {
++ /* Other Ethernet Protocol */
++ swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT;
++ }
++ /* copy (immediate) data */
++ if (nfrags == 0) {
++ /* data is in a single piece */
++ memcpy(imm_data, skb->data, skb->len);
++ } else {
++ /* first copy data from the skb->data buffer ... */
++ memcpy(imm_data, skb->data, skb->len - skb->data_len);
++ imm_data += skb->len - skb->data_len;
++
++ /* ... then copy data from the fragments */
++ for (i = 0; i < nfrags; i++) {
++ frag = &skb_shinfo(skb)->frags[i];
++ memcpy(imm_data,
++ page_address(frag->page) + frag->page_offset,
++ frag->size);
++ imm_data += frag->size;
++ }
++ }
++ swqe->immediate_data_length = skb->len;
++ dev_kfree_skb(skb);
++}
++
++static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_swqe *swqe;
++ unsigned long flags;
++ u32 lkey;
++ int swqe_index;
++ struct ehea_port_res *pr = &port->port_res[0];
++
++ spin_lock(&pr->xmit_lock);
++
++ swqe = ehea_get_swqe(pr->qp, &swqe_index);
++ memset(swqe, 0, SWQE_HEADER_SIZE);
++ atomic_dec(&pr->swqe_avail);
++
++ if (skb->len <= SWQE3_MAX_IMM) {
++ u32 sig_iv = port->sig_comp_iv;
++ u32 swqe_num = pr->swqe_id_counter;
++ ehea_xmit3(skb, dev, swqe);
++ swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE3_TYPE)
++ | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, swqe_num);
++ if (pr->swqe_ll_count >= (sig_iv - 1)) {
++ swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
++ sig_iv);
++ swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
++ pr->swqe_ll_count = 0;
++ } else
++ pr->swqe_ll_count += 1;
++ } else {
++ swqe->wr_id =
++ EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
++ | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
++ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index);
++ pr->sq_skba.arr[pr->sq_skba.index] = skb;
++
++ pr->sq_skba.index++;
++ pr->sq_skba.index &= (pr->sq_skba.len - 1);
++
++ lkey = pr->send_mr.lkey;
++ ehea_xmit2(skb, dev, swqe, lkey);
++
++ if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) {
++ swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
++ EHEA_SIG_IV_LONG);
++ swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
++ pr->swqe_count = 0;
++ } else
++ pr->swqe_count += 1;
++ }
++ pr->swqe_id_counter += 1;
++
++ if (port->vgrp && vlan_tx_tag_present(skb)) {
++ swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
++ swqe->vlan_tag = vlan_tx_tag_get(skb);
++ }
++
++ if (netif_msg_tx_queued(port)) {
++ ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
++ ehea_dump(swqe, 512, "swqe");
++ }
++
++ ehea_post_swqe(pr->qp, swqe);
++ pr->tx_packets++;
++
++ if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
++ spin_lock_irqsave(&pr->netif_queue, flags);
++ if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
++ netif_stop_queue(dev);
++ pr->queue_stopped = 1;
++ }
++ spin_unlock_irqrestore(&pr->netif_queue, flags);
++ }
++ dev->trans_start = jiffies;
++ spin_unlock(&pr->xmit_lock);
++
++ return NETDEV_TX_OK;
++}
++
++static void ehea_vlan_rx_register(struct net_device *dev,
++ struct vlan_group *grp)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_adapter *adapter = port->adapter;
++ struct hcp_ehea_port_cb1 *cb1;
++ u64 hret;
++
++ port->vgrp = grp;
++
++ cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb1) {
++ ehea_error("no mem for cb1");
++ goto out;
++ }
++
++ if (grp)
++ memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter));
++ else
++ memset(cb1->vlan_filter, 0xFF, sizeof(cb1->vlan_filter));
++
++ hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
++ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
++ if (hret != H_SUCCESS)
++ ehea_error("modify_ehea_port failed");
++
++ kfree(cb1);
++out:
++ return;
++}
++
++static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_adapter *adapter = port->adapter;
++ struct hcp_ehea_port_cb1 *cb1;
++ int index;
++ u64 hret;
++
++ cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb1) {
++ ehea_error("no mem for cb1");
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
++ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_port failed");
++ goto out;
++ }
++
++ index = (vid / 64);
++ cb1->vlan_filter[index] |= ((u64)(1 << (vid & 0x3F)));
++
++ hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
++ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
++ if (hret != H_SUCCESS)
++ ehea_error("modify_ehea_port failed");
++out:
++ kfree(cb1);
++ return;
++}
++
++static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
++{
++ struct ehea_port *port = netdev_priv(dev);
++ struct ehea_adapter *adapter = port->adapter;
++ struct hcp_ehea_port_cb1 *cb1;
++ int index;
++ u64 hret;
++
++ if (port->vgrp)
++ port->vgrp->vlan_devices[vid] = NULL;
++
++ cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb1) {
++ ehea_error("no mem for cb1");
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
++ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_port failed");
++ goto out;
++ }
++
++ index = (vid / 64);
++ cb1->vlan_filter[index] &= ~((u64)(1 << (vid & 0x3F)));
++
++ hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
++ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
++ if (hret != H_SUCCESS)
++ ehea_error("modify_ehea_port failed");
++out:
++ kfree(cb1);
++ return;
++}
++
++int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
++{
++ int ret = -EIO;
++ u64 hret;
++ u16 dummy16 = 0;
++ u64 dummy64 = 0;
++ struct hcp_modify_qp_cb0* cb0;
++
++ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb0) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_qp failed (1)");
++ goto out;
++ }
++
++ cb0->qp_ctl_reg = H_QP_CR_STATE_INITIALIZED;
++ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
++ &dummy64, &dummy64, &dummy16, &dummy16);
++ if (hret != H_SUCCESS) {
++ ehea_error("modify_ehea_qp failed (1)");
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_qp failed (2)");
++ goto out;
++ }
++
++ cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_INITIALIZED;
++ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
++ &dummy64, &dummy64, &dummy16, &dummy16);
++ if (hret != H_SUCCESS) {
++ ehea_error("modify_ehea_qp failed (2)");
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_qp failed (3)");
++ goto out;
++ }
++
++ cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RDY2SND;
++ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
++ &dummy64, &dummy64, &dummy16, &dummy16);
++ if (hret != H_SUCCESS) {
++ ehea_error("modify_ehea_qp failed (3)");
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
++ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
++ if (hret != H_SUCCESS) {
++ ehea_error("query_ehea_qp failed (4)");
++ goto out;
++ }
++
++ ret = 0;
++out:
++ kfree(cb0);
++ return ret;
++}
++
++static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
++ int add_tx_qps)
++{
++ int ret, i;
++ struct port_res_cfg pr_cfg, pr_cfg_small_rx;
++ enum ehea_eq_type eq_type = EHEA_EQ;
++
++ port->qp_eq = ehea_create_eq(port->adapter, eq_type,
++ EHEA_MAX_ENTRIES_EQ, 1);
++ if (!port->qp_eq) {
++ ret = -EINVAL;
++ ehea_error("ehea_create_eq failed (qp_eq)");
++ goto out_kill_eq;
++ }
++
++ pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
++ pr_cfg.max_entries_scq = sq_entries;
++ pr_cfg.max_entries_sq = sq_entries;
++ pr_cfg.max_entries_rq1 = rq1_entries;
++ pr_cfg.max_entries_rq2 = rq2_entries;
++ pr_cfg.max_entries_rq3 = rq3_entries;
++
++ pr_cfg_small_rx.max_entries_rcq = 1;
++ pr_cfg_small_rx.max_entries_scq = sq_entries;
++ pr_cfg_small_rx.max_entries_sq = sq_entries;
++ pr_cfg_small_rx.max_entries_rq1 = 1;
++ pr_cfg_small_rx.max_entries_rq2 = 1;
++ pr_cfg_small_rx.max_entries_rq3 = 1;
++
++ for (i = 0; i < def_qps; i++) {
++ ret = ehea_init_port_res(port, &port->port_res[i], &pr_cfg, i);
++ if (ret)
++ goto out_clean_pr;
++ }
++ for (i = def_qps; i < def_qps + add_tx_qps; i++) {
++ ret = ehea_init_port_res(port, &port->port_res[i],
++ &pr_cfg_small_rx, i);
++ if (ret)
++ goto out_clean_pr;
++ }
++
++ return 0;
++
++out_clean_pr:
++ while (--i >= 0)
++ ehea_clean_portres(port, &port->port_res[i]);
++
++out_kill_eq:
++ ehea_destroy_eq(port->qp_eq);
++ return ret;
++}
++
++static int ehea_clean_all_portres(struct ehea_port *port)
++{
++ int ret = 0;
++ int i;
++
++ for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
++ ret |= ehea_clean_portres(port, &port->port_res[i]);
++
++ ret |= ehea_destroy_eq(port->qp_eq);
++
++ return ret;
++}
++
++static int ehea_up(struct net_device *dev)
++{
++ int ret, i;
++ struct ehea_port *port = netdev_priv(dev);
++ u64 mac_addr = 0;
++
++ if (port->state == EHEA_PORT_UP)
++ return 0;
++
++ ret = ehea_port_res_setup(port, port->num_def_qps,
++ port->num_add_tx_qps);
++ if (ret) {
++ ehea_error("port_res_failed");
++ goto out;
++ }
++
++ /* Set default QP for this port */
++ ret = ehea_configure_port(port);
++ if (ret) {
++ ehea_error("ehea_configure_port failed. ret:%d", ret);
++ goto out_clean_pr;
++ }
++
++ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
++ if (ret) {
++ ret = -EIO;
++ ehea_error("out_clean_pr");
++ goto out_clean_pr;
++ }
++ mac_addr = (*(u64*)dev->dev_addr) >> 16;
++
++ ret = ehea_reg_interrupts(dev);
++ if (ret) {
++ ehea_error("out_dereg_bc");
++ goto out_dereg_bc;
++ }
++
++ for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
++ ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
++ if (ret) {
++ ehea_error("activate_qp failed");
++ goto out_free_irqs;
++ }
++ }
++
++ for(i = 0; i < port->num_def_qps; i++) {
++ ret = ehea_fill_port_res(&port->port_res[i]);
++ if (ret) {
++ ehea_error("out_free_irqs");
++ goto out_free_irqs;
++ }
++ }
++
++ ret = 0;
++ port->state = EHEA_PORT_UP;
++ goto out;
++
++out_free_irqs:
++ ehea_free_interrupts(dev);
++
++out_dereg_bc:
++ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
++
++out_clean_pr:
++ ehea_clean_all_portres(port);
++out:
++ return ret;
++}
++
++static int ehea_open(struct net_device *dev)
++{
++ int ret;
++ struct ehea_port *port = netdev_priv(dev);
++
++ down(&port->port_lock);
++
++ if (netif_msg_ifup(port))
++ ehea_info("enabling port %s", dev->name);
++
++ ret = ehea_up(dev);
++ if (!ret)
++ netif_start_queue(dev);
++
++ up(&port->port_lock);
++
++ return ret;
++}
++
++static int ehea_down(struct net_device *dev)
++{
++ int ret, i;
++ struct ehea_port *port = netdev_priv(dev);
++
++ if (port->state == EHEA_PORT_DOWN)
++ return 0;
++
++ ehea_drop_multicast_list(dev);
++ ehea_free_interrupts(dev);
++
++ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
++ tasklet_kill(&port->port_res[i].send_comp_task);
++
++ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
++ ret = ehea_clean_all_portres(port);
++ port->state = EHEA_PORT_DOWN;
++ return ret;
++}
++
++static int ehea_stop(struct net_device *dev)
++{
++ int ret;
++ struct ehea_port *port = netdev_priv(dev);
++
++ if (netif_msg_ifdown(port))
++ ehea_info("disabling port %s", dev->name);
++
++ flush_workqueue(port->adapter->ehea_wq);
++ down(&port->port_lock);
++ netif_stop_queue(dev);
++ ret = ehea_down(dev);
++ up(&port->port_lock);
++ return ret;
++}
++
++static void ehea_reset_port(void *data)
++{
++ int ret;
++ struct net_device *dev = data;
++ struct ehea_port *port = netdev_priv(dev);
++
++ port->resets++;
++ down(&port->port_lock);
++ netif_stop_queue(dev);
++ netif_poll_disable(dev);
++
++ ret = ehea_down(dev);
++ if (ret)
++ ehea_error("ehea_down failed. not all resources are freed");
++
++ ret = ehea_up(dev);
++ if (ret) {
++ ehea_error("Reset device %s failed: ret=%d", dev->name, ret);
++ goto out;
++ }
++
++ if (netif_msg_timer(port))
++ ehea_info("Device %s resetted successfully", dev->name);
++
++ netif_poll_enable(dev);
++ netif_wake_queue(dev);
++out:
++ up(&port->port_lock);
++ return;
++}
++
++static void ehea_tx_watchdog(struct net_device *dev)
++{
++ struct ehea_port *port = netdev_priv(dev);
++
++ if (netif_carrier_ok(dev))
++ queue_work(port->adapter->ehea_wq, &port->reset_task);
++}
++
++int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
++{
++ struct hcp_query_ehea *cb;
++ u64 hret;
++ int ret;
++
++ cb = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ hret = ehea_h_query_ehea(adapter->handle, cb);
++
++ if (hret != H_SUCCESS) {
++ ret = -EIO;
++ goto out_herr;
++ }
++
++ adapter->num_ports = cb->num_ports;
++ adapter->max_mc_mac = cb->max_mc_mac - 1;
++ ret = 0;
++
++out_herr:
++ kfree(cb);
++out:
++ return ret;
++}
++
++static int ehea_setup_single_port(struct ehea_port *port,
++ struct device_node *dn)
++{
++ int ret;
++ u64 hret;
++ struct net_device *dev = port->netdev;
++ struct ehea_adapter *adapter = port->adapter;
++ struct hcp_ehea_port_cb4 *cb4;
++ u32 *dn_log_port_id;
++
++ sema_init(&port->port_lock, 1);
++ port->state = EHEA_PORT_DOWN;
++ port->sig_comp_iv = sq_entries / 10;
++
++ if (!dn) {
++ ehea_error("bad device node: dn=%p", dn);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ port->of_dev_node = dn;
++
++ /* Determine logical port id */
++ dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL);
++
++ if (!dn_log_port_id) {
++ ehea_error("bad device node: dn_log_port_id=%p",
++ dn_log_port_id);
++ ret = -EINVAL;
++ goto out;
++ }
++ port->logical_port_id = *dn_log_port_id;
++
++ port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
++ if (!port->mc_list) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ INIT_LIST_HEAD(&port->mc_list->list);
++
++ ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
++
++ ret = ehea_sense_port_attr(port);
++ if (ret)
++ goto out;
++
++ /* Enable Jumbo frames */
++ cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!cb4) {
++ ehea_error("no mem for cb4");
++ } else {
++ cb4->jumbo_frame = 1;
++ hret = ehea_h_modify_ehea_port(adapter->handle,
++ port->logical_port_id,
++ H_PORT_CB4, H_PORT_CB4_JUMBO,
++ cb4);
++ if (hret != H_SUCCESS) {
++ ehea_info("Jumbo frames not activated");
++ }
++ kfree(cb4);
++ }
++
++ /* initialize net_device structure */
++ SET_MODULE_OWNER(dev);
++
++ memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
++
++ dev->open = ehea_open;
++ dev->poll = ehea_poll;
++ dev->weight = 64;
++ dev->stop = ehea_stop;
++ dev->hard_start_xmit = ehea_start_xmit;
++ dev->get_stats = ehea_get_stats;
++ dev->set_multicast_list = ehea_set_multicast_list;
++ dev->set_mac_address = ehea_set_mac_addr;
++ dev->change_mtu = ehea_change_mtu;
++ dev->vlan_rx_register = ehea_vlan_rx_register;
++ dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid;
++ dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid;
++ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
++ | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX
++ | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
++ | NETIF_F_LLTX;
++ dev->tx_timeout = &ehea_tx_watchdog;
++ dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
++
++ INIT_WORK(&port->reset_task, ehea_reset_port, dev);
++
++ ehea_set_ethtool_ops(dev);
++
++ ret = register_netdev(dev);
++ if (ret) {
++ ehea_error("register_netdev failed. ret=%d", ret);
++ goto out_free;
++ }
++
++ port->netdev = dev;
++ ret = 0;
++ goto out;
++
++out_free:
++ kfree(port->mc_list);
++out:
++ return ret;
++}
++
++static int ehea_setup_ports(struct ehea_adapter *adapter)
++{
++ int ret;
++ int port_setup_ok = 0;
++ struct ehea_port *port;
++ struct device_node *dn = NULL;
++ struct net_device *dev;
++ int i;
++
++ /* get port properties for all ports */
++ for (i = 0; i < adapter->num_ports; i++) {
++
++ if (adapter->port[i])
++ continue; /* port already up and running */
++
++ /* allocate memory for the port structures */
++ dev = alloc_etherdev(sizeof(struct ehea_port));
++
++ if (!dev) {
++ ehea_error("no mem for net_device");
++ break;
++ }
++
++ port = netdev_priv(dev);
++ port->adapter = adapter;
++ port->netdev = dev;
++ adapter->port[i] = port;
++ port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
++
++ dn = of_find_node_by_name(dn, "ethernet");
++ ret = ehea_setup_single_port(port, dn);
++ if (ret) {
++ /* Free mem for this port struct. The others will be
++ processed on rollback */
++ free_netdev(dev);
++ adapter->port[i] = NULL;
++ ehea_error("eHEA port %d setup failed, ret=%d", i, ret);
++ }
++ }
++
++ of_node_put(dn);
++
++ /* Check for succesfully set up ports */
++ for (i = 0; i < adapter->num_ports; i++)
++ if (adapter->port[i])
++ port_setup_ok++;
++
++ if (port_setup_ok)
++ ret = 0; /* At least some ports are setup correctly */
++ else
++ ret = -EINVAL;
++
++ return ret;
++}
++
++static int __devinit ehea_probe(struct ibmebus_dev *dev,
++ const struct of_device_id *id)
++{
++ struct ehea_adapter *adapter;
++ u64 *adapter_handle;
++ int ret;
++
++ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
++ if (!adapter) {
++ ret = -ENOMEM;
++ dev_err(&dev->ofdev.dev, "no mem for ehea_adapter\n");
++ goto out;
++ }
++
++ adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
++ NULL);
++ if (!adapter_handle) {
++ dev_err(&dev->ofdev.dev, "failed getting handle for adapter"
++ " '%s'\n", dev->ofdev.node->full_name);
++ ret = -ENODEV;
++ goto out_free_ad;
++ }
++
++ adapter->handle = *adapter_handle;
++ adapter->pd = EHEA_PD_ID;
++
++ dev->ofdev.dev.driver_data = adapter;
++
++ ret = ehea_reg_mr_adapter(adapter);
++ if (ret) {
++ dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n");
++ goto out_free_ad;
++ }
++
++ /* initialize adapter and ports */
++ /* get adapter properties */
++ ret = ehea_sense_adapter_attr(adapter);
++ if (ret) {
++ dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
++ goto out_free_res;
++ }
++ dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports);
++
++ adapter->neq = ehea_create_eq(adapter,
++ EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
++ if (!adapter->neq) {
++ dev_err(&dev->ofdev.dev, "NEQ creation failed");
++ goto out_free_res;
++ }
++
++ tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
++ (unsigned long)adapter);
++
++ ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1,
++ ehea_interrupt_neq, SA_INTERRUPT,
++ "ehea_neq", adapter);
++ if (ret) {
++ dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed");
++ goto out_kill_eq;
++ }
++
++ adapter->ehea_wq = create_workqueue("ehea_wq");
++ if (!adapter->ehea_wq)
++ goto out_free_irq;
++
++ ret = ehea_setup_ports(adapter);
++ if (ret) {
++ dev_err(&dev->ofdev.dev, "setup_ports failed");
++ goto out_kill_wq;
++ }
++
++ ret = 0;
++ goto out;
++
++out_kill_wq:
++ destroy_workqueue(adapter->ehea_wq);
++
++out_free_irq:
++ ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
++
++out_kill_eq:
++ ehea_destroy_eq(adapter->neq);
++
++out_free_res:
++ ehea_h_free_resource(adapter->handle, adapter->mr.handle);
++
++out_free_ad:
++ kfree(adapter);
++out:
++ return ret;
++}
++
++static void ehea_shutdown_single_port(struct ehea_port *port)
++{
++ unregister_netdev(port->netdev);
++ kfree(port->mc_list);
++ free_netdev(port->netdev);
++}
++
++static int __devexit ehea_remove(struct ibmebus_dev *dev)
++{
++ struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
++ u64 hret;
++ int i;
++
++ for (i = 0; i < adapter->num_ports; i++)
++ if (adapter->port[i]) {
++ ehea_shutdown_single_port(adapter->port[i]);
++ adapter->port[i] = NULL;
++ }
++ destroy_workqueue(adapter->ehea_wq);
++
++ ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
++
++ ehea_destroy_eq(adapter->neq);
++
++ hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle);
++ if (hret) {
++ dev_err(&dev->ofdev.dev, "free_resource_mr failed");
++ return -EIO;
++ }
++ kfree(adapter);
++ return 0;
++}
++
++static int check_module_parm(void)
++{
++ int ret = 0;
++
++ if ((rq1_entries < EHEA_MIN_ENTRIES_QP) ||
++ (rq1_entries > EHEA_MAX_ENTRIES_RQ1)) {
++ ehea_info("Bad parameter: rq1_entries");
++ ret = -EINVAL;
++ }
++ if ((rq2_entries < EHEA_MIN_ENTRIES_QP) ||
++ (rq2_entries > EHEA_MAX_ENTRIES_RQ2)) {
++ ehea_info("Bad parameter: rq2_entries");
++ ret = -EINVAL;
++ }
++ if ((rq3_entries < EHEA_MIN_ENTRIES_QP) ||
++ (rq3_entries > EHEA_MAX_ENTRIES_RQ3)) {
++ ehea_info("Bad parameter: rq3_entries");
++ ret = -EINVAL;
++ }
++ if ((sq_entries < EHEA_MIN_ENTRIES_QP) ||
++ (sq_entries > EHEA_MAX_ENTRIES_SQ)) {
++ ehea_info("Bad parameter: sq_entries");
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++static struct of_device_id ehea_device_table[] = {
++ {
++ .name = "lhea",
++ .compatible = "IBM,lhea",
++ },
++ {},
++};
++
++static struct ibmebus_driver ehea_driver = {
++ .name = "ehea",
++ .id_table = ehea_device_table,
++ .probe = ehea_probe,
++ .remove = ehea_remove,
++};
++
++int __init ehea_module_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
++ DRV_VERSION);
++
++ ret = check_module_parm();
++ if (ret)
++ goto out;
++ ret = ibmebus_register_driver(&ehea_driver);
++ if (ret)
++ ehea_error("failed registering eHEA device driver on ebus");
++
++out:
++ return ret;
++}
++
++static void __exit ehea_module_exit(void)
++{
++ ibmebus_unregister_driver(&ehea_driver);
++}
++
++module_init(ehea_module_init);
++module_exit(ehea_module_exit);
+diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
+new file mode 100644
+index 0000000..0cfc2bc
+--- /dev/null
++++ b/drivers/net/ehea/ehea_phyp.c
+@@ -0,0 +1,608 @@
++/*
++ * linux/drivers/net/ehea/ehea_phyp.c
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 "ehea_phyp.h"
++
++
++static inline u16 get_order_of_qentries(u16 queue_entries)
++{
++ u8 ld = 1; /* logarithmus dualis */
++ while (((1U << ld) - 1) < queue_entries)
++ ld++;
++ return ld - 1;
++}
++
++/* Defines for H_CALL H_ALLOC_RESOURCE */
++#define H_ALL_RES_TYPE_QP 1
++#define H_ALL_RES_TYPE_CQ 2
++#define H_ALL_RES_TYPE_EQ 3
++#define H_ALL_RES_TYPE_MR 5
++#define H_ALL_RES_TYPE_MW 6
++
++static long ehea_plpar_hcall_norets(unsigned long opcode,
++ unsigned long arg1,
++ unsigned long arg2,
++ unsigned long arg3,
++ unsigned long arg4,
++ unsigned long arg5,
++ unsigned long arg6,
++ unsigned long arg7)
++{
++ long ret;
++ int i, sleep_msecs;
++
++ for (i = 0; i < 5; i++) {
++ ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
++ arg5, arg6, arg7);
++
++ if (H_IS_LONG_BUSY(ret)) {
++ sleep_msecs = get_longbusy_msecs(ret);
++ msleep_interruptible(sleep_msecs);
++ continue;
++ }
++
++ if (ret < H_SUCCESS)
++ ehea_error("opcode=%lx ret=%lx"
++ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
++ " arg5=%lx arg6=%lx arg7=%lx ",
++ opcode, ret,
++ arg1, arg2, arg3, arg4, arg5,
++ arg6, arg7);
++
++ return ret;
++ }
++
++ return H_BUSY;
++}
++
++static long ehea_plpar_hcall9(unsigned long opcode,
++ unsigned long *outs, /* array of 9 outputs */
++ unsigned long arg1,
++ unsigned long arg2,
++ unsigned long arg3,
++ unsigned long arg4,
++ unsigned long arg5,
++ unsigned long arg6,
++ unsigned long arg7,
++ unsigned long arg8,
++ unsigned long arg9)
++{
++ long ret;
++ int i, sleep_msecs;
++
++ for (i = 0; i < 5; i++) {
++ ret = plpar_hcall9(opcode, outs,
++ arg1, arg2, arg3, arg4, arg5,
++ arg6, arg7, arg8, arg9);
++
++ if (H_IS_LONG_BUSY(ret)) {
++ sleep_msecs = get_longbusy_msecs(ret);
++ msleep_interruptible(sleep_msecs);
++ continue;
++ }
++
++ if (ret < H_SUCCESS)
++ ehea_error("opcode=%lx ret=%lx"
++ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
++ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
++ " arg9=%lx"
++ " out1=%lx out2=%lx out3=%lx out4=%lx"
++ " out5=%lx out6=%lx out7=%lx out8=%lx"
++ " out9=%lx",
++ opcode, ret,
++ arg1, arg2, arg3, arg4, arg5,
++ arg6, arg7, arg8, arg9,
++ outs[0], outs[1], outs[2], outs[3],
++ outs[4], outs[5], outs[6], outs[7],
++ outs[8]);
++
++ return ret;
++ }
++
++ return H_BUSY;
++}
++
++u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
++ const u64 qp_handle, const u64 sel_mask, void *cb_addr)
++{
++ return ehea_plpar_hcall_norets(H_QUERY_HEA_QP,
++ adapter_handle, /* R4 */
++ qp_category, /* R5 */
++ qp_handle, /* R6 */
++ sel_mask, /* R7 */
++ virt_to_abs(cb_addr), /* R8 */
++ 0, 0);
++}
++
++/* input param R5 */
++#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
++#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
++#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
++#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
++#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
++#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
++#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
++#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
++#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
++#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
++
++/* input param R9 */
++#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
++#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32,63)
++
++/* input param R10 */
++#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
++#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
++#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
++#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
++/* Max Send Scatter Gather Elements */
++#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
++#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
++/* Max Receive SG Elements RQ1 */
++#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
++#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
++
++/* input param R11 */
++#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
++/* max swqe immediate data length */
++#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
++
++/* input param R12 */
++#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
++/* Threshold RQ2 */
++#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
++/* Threshold RQ3 */
++
++/* output param R6 */
++#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
++#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
++#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
++#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
++
++/* output param, R7 */
++#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
++#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
++#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
++#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
++#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
++
++/* output param R8,R9 */
++#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
++#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
++#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
++#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
++
++/* output param R11,R12 */
++#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
++#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
++#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
++#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
++
++u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
++ struct ehea_qp_init_attr *init_attr, const u32 pd,
++ u64 *qp_handle, struct h_epas *h_epas)
++{
++ u64 hret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ u64 allocate_controls =
++ EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_QPP, 0)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_RQR, 6) /* rq1 & rq2 & rq3 */
++ | EHEA_BMASK_SET(H_ALL_RES_QP_EQEG, 0) /* EQE gen. disabled */
++ | EHEA_BMASK_SET(H_ALL_RES_QP_LL_QP, init_attr->low_lat_rq1)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_DMA128, 0)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_HSM, 0)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_SIGT, init_attr->signalingtype)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_RES_TYP, H_ALL_RES_TYPE_QP);
++
++ u64 r9_reg = EHEA_BMASK_SET(H_ALL_RES_QP_PD, pd)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_TOKEN, init_attr->qp_token);
++
++ u64 max_r10_reg =
++ EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SWQE,
++ get_order_of_qentries(init_attr->max_nr_send_wqes))
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1WQE,
++ get_order_of_qentries(init_attr->max_nr_rwqes_rq1))
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2WQE,
++ get_order_of_qentries(init_attr->max_nr_rwqes_rq2))
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3WQE,
++ get_order_of_qentries(init_attr->max_nr_rwqes_rq3))
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SSGE, init_attr->wqe_size_enc_sq)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1SGE,
++ init_attr->wqe_size_enc_rq1)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2SGE,
++ init_attr->wqe_size_enc_rq2)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3SGE,
++ init_attr->wqe_size_enc_rq3);
++
++ u64 r11_in =
++ EHEA_BMASK_SET(H_ALL_RES_QP_SWQE_IDL, init_attr->swqe_imm_data_len)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_PORT_NUM, init_attr->port_nr);
++ u64 threshold =
++ EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
++ | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
++
++ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
++ outs,
++ adapter_handle, /* R4 */
++ allocate_controls, /* R5 */
++ init_attr->send_cq_handle, /* R6 */
++ init_attr->recv_cq_handle, /* R7 */
++ init_attr->aff_eq_handle, /* R8 */
++ r9_reg, /* R9 */
++ max_r10_reg, /* R10 */
++ r11_in, /* R11 */
++ threshold); /* R12 */
++
++ *qp_handle = outs[0];
++ init_attr->qp_nr = (u32)outs[1];
++
++ init_attr->act_nr_send_wqes =
++ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, outs[2]);
++ init_attr->act_nr_rwqes_rq1 =
++ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, outs[2]);
++ init_attr->act_nr_rwqes_rq2 =
++ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, outs[2]);
++ init_attr->act_nr_rwqes_rq3 =
++ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, outs[2]);
++
++ init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
++ init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
++ init_attr->act_wqe_size_enc_rq2 = init_attr->wqe_size_enc_rq2;
++ init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
++
++ init_attr->nr_sq_pages =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, outs[4]);
++ init_attr->nr_rq1_pages =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, outs[4]);
++ init_attr->nr_rq2_pages =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, outs[5]);
++ init_attr->nr_rq3_pages =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, outs[5]);
++
++ init_attr->liobn_sq =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, outs[7]);
++ init_attr->liobn_rq1 =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, outs[7]);
++ init_attr->liobn_rq2 =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, outs[8]);
++ init_attr->liobn_rq3 =
++ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, outs[8]);
++
++ if (!hret)
++ hcp_epas_ctor(h_epas, outs[6], outs[6]);
++
++ return hret;
++}
++
++u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
++ struct ehea_cq_attr *cq_attr,
++ u64 *cq_handle, struct h_epas *epas)
++{
++ u64 hret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
++ outs,
++ adapter_handle, /* R4 */
++ H_ALL_RES_TYPE_CQ, /* R5 */
++ cq_attr->eq_handle, /* R6 */
++ cq_attr->cq_token, /* R7 */
++ cq_attr->max_nr_of_cqes, /* R8 */
++ 0, 0, 0, 0); /* R9-R12 */
++
++ *cq_handle = outs[0];
++ cq_attr->act_nr_of_cqes = outs[3];
++ cq_attr->nr_pages = outs[4];
++
++ if (!hret)
++ hcp_epas_ctor(epas, outs[5], outs[6]);
++
++ return hret;
++}
++
++/* Defines for H_CALL H_ALLOC_RESOURCE */
++#define H_ALL_RES_TYPE_QP 1
++#define H_ALL_RES_TYPE_CQ 2
++#define H_ALL_RES_TYPE_EQ 3
++#define H_ALL_RES_TYPE_MR 5
++#define H_ALL_RES_TYPE_MW 6
++
++/* input param R5 */
++#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
++#define H_ALL_RES_EQ_NON_NEQ_ISN EHEA_BMASK_IBM(6, 7)
++#define H_ALL_RES_EQ_INH_EQE_GEN EHEA_BMASK_IBM(16, 16)
++#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
++/* input param R6 */
++#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
++
++/* output param R6 */
++#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
++
++/* output param R7 */
++#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
++
++/* output param R8 */
++#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
++
++/* output param R9 */
++#define H_ALL_RES_EQ_ACT_EQ_IST_C EHEA_BMASK_IBM(30, 31)
++#define H_ALL_RES_EQ_ACT_EQ_IST_1 EHEA_BMASK_IBM(40, 63)
++
++/* output param R10 */
++#define H_ALL_RES_EQ_ACT_EQ_IST_2 EHEA_BMASK_IBM(40, 63)
++
++/* output param R11 */
++#define H_ALL_RES_EQ_ACT_EQ_IST_3 EHEA_BMASK_IBM(40, 63)
++
++/* output param R12 */
++#define H_ALL_RES_EQ_ACT_EQ_IST_4 EHEA_BMASK_IBM(40, 63)
++
++u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
++ struct ehea_eq_attr *eq_attr, u64 *eq_handle)
++{
++ u64 hret, allocate_controls;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ /* resource type */
++ allocate_controls =
++ EHEA_BMASK_SET(H_ALL_RES_EQ_RES_TYPE, H_ALL_RES_TYPE_EQ)
++ | EHEA_BMASK_SET(H_ALL_RES_EQ_NEQ, eq_attr->type ? 1 : 0)
++ | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
++ | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
++
++ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
++ outs,
++ adapter_handle, /* R4 */
++ allocate_controls, /* R5 */
++ eq_attr->max_nr_of_eqes, /* R6 */
++ 0, 0, 0, 0, 0, 0); /* R7-R10 */
++
++ *eq_handle = outs[0];
++ eq_attr->act_nr_of_eqes = outs[3];
++ eq_attr->nr_pages = outs[4];
++ eq_attr->ist1 = outs[5];
++ eq_attr->ist2 = outs[6];
++ eq_attr->ist3 = outs[7];
++ eq_attr->ist4 = outs[8];
++
++ return hret;
++}
++
++u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat,
++ const u64 qp_handle, const u64 sel_mask,
++ void *cb_addr, u64 *inv_attr_id, u64 *proc_mask,
++ u16 *out_swr, u16 *out_rwr)
++{
++ u64 hret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP,
++ outs,
++ adapter_handle, /* R4 */
++ (u64) cat, /* R5 */
++ qp_handle, /* R6 */
++ sel_mask, /* R7 */
++ virt_to_abs(cb_addr), /* R8 */
++ 0, 0, 0, 0); /* R9-R12 */
++
++ *inv_attr_id = outs[0];
++ *out_swr = outs[3];
++ *out_rwr = outs[4];
++ *proc_mask = outs[5];
++
++ return hret;
++}
++
++u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize,
++ const u8 queue_type, const u64 resource_handle,
++ const u64 log_pageaddr, u64 count)
++{
++ u64 reg_control;
++
++ reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
++ | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
++
++ return ehea_plpar_hcall_norets(H_REGISTER_HEA_RPAGES,
++ adapter_handle, /* R4 */
++ reg_control, /* R5 */
++ resource_handle, /* R6 */
++ log_pageaddr, /* R7 */
++ count, /* R8 */
++ 0, 0); /* R9-R10 */
++}
++
++u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
++ const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
++ struct ehea_mr *mr)
++{
++ u64 hret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ hret = ehea_plpar_hcall9(H_REGISTER_SMR,
++ outs,
++ adapter_handle , /* R4 */
++ orig_mr_handle, /* R5 */
++ vaddr_in, /* R6 */
++ (((u64)access_ctrl) << 32ULL), /* R7 */
++ pd, /* R8 */
++ 0, 0, 0, 0); /* R9-R12 */
++
++ mr->handle = outs[0];
++ mr->lkey = (u32)outs[2];
++
++ return hret;
++}
++
++u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
++{
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA,
++ outs,
++ adapter_handle, /* R4 */
++ H_DISABLE_GET_EHEA_WQE_P, /* R5 */
++ qp_handle, /* R6 */
++ 0, 0, 0, 0, 0, 0); /* R7-R12 */
++}
++
++u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
++{
++ return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
++ adapter_handle, /* R4 */
++ res_handle, /* R5 */
++ 0, 0, 0, 0, 0); /* R6-R10 */
++}
++
++u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
++ const u64 length, const u32 access_ctrl,
++ const u32 pd, u64 *mr_handle, u32 *lkey)
++{
++ u64 hret;
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++
++ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
++ outs,
++ adapter_handle, /* R4 */
++ 5, /* R5 */
++ vaddr, /* R6 */
++ length, /* R7 */
++ (((u64) access_ctrl) << 32ULL), /* R8 */
++ pd, /* R9 */
++ 0, 0, 0); /* R10-R12 */
++
++ *mr_handle = outs[0];
++ *lkey = (u32)outs[2];
++ return hret;
++}
++
++u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
++ const u8 pagesize, const u8 queue_type,
++ const u64 log_pageaddr, const u64 count)
++{
++ if ((count > 1) && (log_pageaddr & ~PAGE_MASK)) {
++ ehea_error("not on pageboundary");
++ return H_PARAMETER;
++ }
++
++ return ehea_h_register_rpage(adapter_handle, pagesize,
++ queue_type, mr_handle,
++ log_pageaddr, count);
++}
++
++u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr)
++{
++ u64 hret, cb_logaddr;
++
++ cb_logaddr = virt_to_abs(cb_addr);
++
++ hret = ehea_plpar_hcall_norets(H_QUERY_HEA,
++ adapter_handle, /* R4 */
++ cb_logaddr, /* R5 */
++ 0, 0, 0, 0, 0); /* R6-R10 */
++#ifdef DEBUG
++ ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
++#endif
++ return hret;
++}
++
++u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
++ const u8 cb_cat, const u64 select_mask,
++ void *cb_addr)
++{
++ u64 port_info;
++ u64 cb_logaddr = virt_to_abs(cb_addr);
++ u64 arr_index = 0;
++
++ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
++ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
++
++ return ehea_plpar_hcall_norets(H_QUERY_HEA_PORT,
++ adapter_handle, /* R4 */
++ port_info, /* R5 */
++ select_mask, /* R6 */
++ arr_index, /* R7 */
++ cb_logaddr, /* R8 */
++ 0, 0); /* R9-R10 */
++}
++
++u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
++ const u8 cb_cat, const u64 select_mask,
++ void *cb_addr)
++{
++ u64 outs[PLPAR_HCALL9_BUFSIZE];
++ u64 port_info;
++ u64 arr_index = 0;
++ u64 cb_logaddr = virt_to_abs(cb_addr);
++
++ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
++ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
++#ifdef DEBUG
++ ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL");
++#endif
++ return ehea_plpar_hcall9(H_MODIFY_HEA_PORT,
++ outs,
++ adapter_handle, /* R4 */
++ port_info, /* R5 */
++ select_mask, /* R6 */
++ arr_index, /* R7 */
++ cb_logaddr, /* R8 */
++ 0, 0, 0, 0); /* R9-R12 */
++}
++
++u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
++ const u8 reg_type, const u64 mc_mac_addr,
++ const u16 vlan_id, const u32 hcall_id)
++{
++ u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id;
++ u64 mac_addr = mc_mac_addr >> 16;
++
++ r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
++ r6_reg_type = EHEA_BMASK_SET(H_REGBCMC_REGTYPE, reg_type);
++ r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
++ r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
++
++ return ehea_plpar_hcall_norets(hcall_id,
++ adapter_handle, /* R4 */
++ r5_port_num, /* R5 */
++ r6_reg_type, /* R6 */
++ r7_mc_mac_addr, /* R7 */
++ r8_vlan_id, /* R8 */
++ 0, 0); /* R9-R12 */
++}
++
++u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
++ const u64 event_mask)
++{
++ return ehea_plpar_hcall_norets(H_RESET_EVENTS,
++ adapter_handle, /* R4 */
++ neq_handle, /* R5 */
++ event_mask, /* R6 */
++ 0, 0, 0, 0); /* R7-R12 */
++}
+diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
+new file mode 100644
+index 0000000..919f94b
+--- /dev/null
++++ b/drivers/net/ehea/ehea_phyp.h
+@@ -0,0 +1,457 @@
++/*
++ * linux/drivers/net/ehea/ehea_phyp.h
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 __EHEA_PHYP_H__
++#define __EHEA_PHYP_H__
++
++#include <linux/delay.h>
++#include <asm/hvcall.h>
++#include "ehea.h"
++#include "ehea_hw.h"
++#include "ehea_hcall.h"
++
++/* Some abbreviations used here:
++ *
++ * hcp_* - structures, variables and functions releated to Hypervisor Calls
++ */
++
++static inline u32 get_longbusy_msecs(int long_busy_ret_code)
++{
++ switch (long_busy_ret_code) {
++ case H_LONG_BUSY_ORDER_1_MSEC:
++ return 1;
++ case H_LONG_BUSY_ORDER_10_MSEC:
++ return 10;
++ case H_LONG_BUSY_ORDER_100_MSEC:
++ return 100;
++ case H_LONG_BUSY_ORDER_1_SEC:
++ return 1000;
++ case H_LONG_BUSY_ORDER_10_SEC:
++ return 10000;
++ case H_LONG_BUSY_ORDER_100_SEC:
++ return 100000;
++ default:
++ return 1;
++ }
++}
++
++/* Notification Event Queue (NEQ) Entry bit masks */
++#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
++#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)
++#define NEQE_PORT_UP EHEA_BMASK_IBM(16, 16)
++#define NEQE_EXTSWITCH_PORT_UP EHEA_BMASK_IBM(17, 17)
++#define NEQE_EXTSWITCH_PRIMARY EHEA_BMASK_IBM(18, 18)
++#define NEQE_PLID EHEA_BMASK_IBM(16, 47)
++
++/* Notification Event Codes */
++#define EHEA_EC_PORTSTATE_CHG 0x30
++#define EHEA_EC_ADAPTER_MALFUNC 0x32
++#define EHEA_EC_PORT_MALFUNC 0x33
++
++/* Notification Event Log Register (NELR) bit masks */
++#define NELR_PORT_MALFUNC EHEA_BMASK_IBM(61, 61)
++#define NELR_ADAPTER_MALFUNC EHEA_BMASK_IBM(62, 62)
++#define NELR_PORTSTATE_CHG EHEA_BMASK_IBM(63, 63)
++
++static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel,
++ u64 paddr_user)
++{
++ /* To support 64k pages we must round to 64k page boundary */
++ epas->kernel.addr = ioremap((paddr_kernel & PAGE_MASK), PAGE_SIZE) +
++ (paddr_kernel & ~PAGE_MASK);
++ epas->user.addr = paddr_user;
++}
++
++static inline void hcp_epas_dtor(struct h_epas *epas)
++{
++ if (epas->kernel.addr)
++ iounmap((void __iomem*)((u64)epas->kernel.addr & PAGE_MASK));
++
++ epas->user.addr = 0;
++ epas->kernel.addr = 0;
++}
++
++struct hcp_modify_qp_cb0 {
++ u64 qp_ctl_reg; /* 00 */
++ u32 max_swqe; /* 02 */
++ u32 max_rwqe; /* 03 */
++ u32 port_nb; /* 04 */
++ u32 reserved0; /* 05 */
++ u64 qp_aer; /* 06 */
++ u64 qp_tenure; /* 08 */
++};
++
++/* Hcall Query/Modify Queue Pair Control Block 0 Selection Mask Bits */
++#define H_QPCB0_ALL EHEA_BMASK_IBM(0, 5)
++#define H_QPCB0_QP_CTL_REG EHEA_BMASK_IBM(0, 0)
++#define H_QPCB0_MAX_SWQE EHEA_BMASK_IBM(1, 1)
++#define H_QPCB0_MAX_RWQE EHEA_BMASK_IBM(2, 2)
++#define H_QPCB0_PORT_NB EHEA_BMASK_IBM(3, 3)
++#define H_QPCB0_QP_AER EHEA_BMASK_IBM(4, 4)
++#define H_QPCB0_QP_TENURE EHEA_BMASK_IBM(5, 5)
++
++/* Queue Pair Control Register Status Bits */
++#define H_QP_CR_ENABLED 0x8000000000000000ULL /* QP enabled */
++ /* QP States: */
++#define H_QP_CR_STATE_RESET 0x0000010000000000ULL /* Reset */
++#define H_QP_CR_STATE_INITIALIZED 0x0000020000000000ULL /* Initialized */
++#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */
++#define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */
++#define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */
++
++struct hcp_modify_qp_cb1 {
++ u32 qpn; /* 00 */
++ u32 qp_asyn_ev_eq_nb; /* 01 */
++ u64 sq_cq_handle; /* 02 */
++ u64 rq_cq_handle; /* 04 */
++ /* sgel = scatter gather element */
++ u32 sgel_nb_sq; /* 06 */
++ u32 sgel_nb_rq1; /* 07 */
++ u32 sgel_nb_rq2; /* 08 */
++ u32 sgel_nb_rq3; /* 09 */
++};
++
++/* Hcall Query/Modify Queue Pair Control Block 1 Selection Mask Bits */
++#define H_QPCB1_ALL EHEA_BMASK_IBM(0, 7)
++#define H_QPCB1_QPN EHEA_BMASK_IBM(0, 0)
++#define H_QPCB1_ASYN_EV_EQ_NB EHEA_BMASK_IBM(1, 1)
++#define H_QPCB1_SQ_CQ_HANDLE EHEA_BMASK_IBM(2, 2)
++#define H_QPCB1_RQ_CQ_HANDLE EHEA_BMASK_IBM(3, 3)
++#define H_QPCB1_SGEL_NB_SQ EHEA_BMASK_IBM(4, 4)
++#define H_QPCB1_SGEL_NB_RQ1 EHEA_BMASK_IBM(5, 5)
++#define H_QPCB1_SGEL_NB_RQ2 EHEA_BMASK_IBM(6, 6)
++#define H_QPCB1_SGEL_NB_RQ3 EHEA_BMASK_IBM(7, 7)
++
++struct hcp_query_ehea {
++ u32 cur_num_qps; /* 00 */
++ u32 cur_num_cqs; /* 01 */
++ u32 cur_num_eqs; /* 02 */
++ u32 cur_num_mrs; /* 03 */
++ u32 auth_level; /* 04 */
++ u32 max_num_qps; /* 05 */
++ u32 max_num_cqs; /* 06 */
++ u32 max_num_eqs; /* 07 */
++ u32 max_num_mrs; /* 08 */
++ u32 reserved0; /* 09 */
++ u32 int_clock_freq; /* 10 */
++ u32 max_num_pds; /* 11 */
++ u32 max_num_addr_handles; /* 12 */
++ u32 max_num_cqes; /* 13 */
++ u32 max_num_wqes; /* 14 */
++ u32 max_num_sgel_rq1wqe; /* 15 */
++ u32 max_num_sgel_rq2wqe; /* 16 */
++ u32 max_num_sgel_rq3wqe; /* 17 */
++ u32 mr_page_size; /* 18 */
++ u32 reserved1; /* 19 */
++ u64 max_mr_size; /* 20 */
++ u64 reserved2; /* 22 */
++ u32 num_ports; /* 24 */
++ u32 reserved3; /* 25 */
++ u32 reserved4; /* 26 */
++ u32 reserved5; /* 27 */
++ u64 max_mc_mac; /* 28 */
++ u64 ehea_cap; /* 30 */
++ u32 max_isn_per_eq; /* 32 */
++ u32 max_num_neq; /* 33 */
++ u64 max_num_vlan_ids; /* 34 */
++ u32 max_num_port_group; /* 36 */
++ u32 max_num_phys_port; /* 37 */
++
++};
++
++/* Hcall Query/Modify Port Control Block defines */
++#define H_PORT_CB0 0
++#define H_PORT_CB1 1
++#define H_PORT_CB2 2
++#define H_PORT_CB3 3
++#define H_PORT_CB4 4
++#define H_PORT_CB5 5
++#define H_PORT_CB6 6
++#define H_PORT_CB7 7
++
++struct hcp_ehea_port_cb0 {
++ u64 port_mac_addr;
++ u64 port_rc;
++ u64 reserved0;
++ u32 port_op_state;
++ u32 port_speed;
++ u32 ext_swport_op_state;
++ u32 neg_tpf_prpf;
++ u32 num_default_qps;
++ u32 reserved1;
++ u64 default_qpn_arr[16];
++};
++
++/* Hcall Query/Modify Port Control Block 0 Selection Mask Bits */
++#define H_PORT_CB0_ALL EHEA_BMASK_IBM(0, 7) /* Set all bits */
++#define H_PORT_CB0_MAC EHEA_BMASK_IBM(0, 0) /* MAC address */
++#define H_PORT_CB0_PRC EHEA_BMASK_IBM(1, 1) /* Port Recv Control */
++#define H_PORT_CB0_DEFQPNARRAY EHEA_BMASK_IBM(7, 7) /* Default QPN Array */
++
++/* Hcall Query Port: Returned port speed values */
++#define H_SPEED_10M_H 1 /* 10 Mbps, Half Duplex */
++#define H_SPEED_10M_F 2 /* 10 Mbps, Full Duplex */
++#define H_SPEED_100M_H 3 /* 100 Mbps, Half Duplex */
++#define H_SPEED_100M_F 4 /* 100 Mbps, Full Duplex */
++#define H_SPEED_1G_F 6 /* 1 Gbps, Full Duplex */
++#define H_SPEED_10G_F 8 /* 10 Gbps, Full Duplex */
++
++/* Port Receive Control Status Bits */
++#define PXLY_RC_VALID EHEA_BMASK_IBM(49, 49)
++#define PXLY_RC_VLAN_XTRACT EHEA_BMASK_IBM(50, 50)
++#define PXLY_RC_TCP_6_TUPLE EHEA_BMASK_IBM(51, 51)
++#define PXLY_RC_UDP_6_TUPLE EHEA_BMASK_IBM(52, 52)
++#define PXLY_RC_TCP_3_TUPLE EHEA_BMASK_IBM(53, 53)
++#define PXLY_RC_TCP_2_TUPLE EHEA_BMASK_IBM(54, 54)
++#define PXLY_RC_LLC_SNAP EHEA_BMASK_IBM(55, 55)
++#define PXLY_RC_JUMBO_FRAME EHEA_BMASK_IBM(56, 56)
++#define PXLY_RC_FRAG_IP_PKT EHEA_BMASK_IBM(57, 57)
++#define PXLY_RC_TCP_UDP_CHKSUM EHEA_BMASK_IBM(58, 58)
++#define PXLY_RC_IP_CHKSUM EHEA_BMASK_IBM(59, 59)
++#define PXLY_RC_MAC_FILTER EHEA_BMASK_IBM(60, 60)
++#define PXLY_RC_UNTAG_FILTER EHEA_BMASK_IBM(61, 61)
++#define PXLY_RC_VLAN_TAG_FILTER EHEA_BMASK_IBM(62, 63)
++
++#define PXLY_RC_VLAN_FILTER 2
++#define PXLY_RC_VLAN_PERM 0
++
++
++#define H_PORT_CB1_ALL 0x8000000000000000ULL
++
++struct hcp_ehea_port_cb1 {
++ u64 vlan_filter[64];
++};
++
++#define H_PORT_CB2_ALL 0xFFE0000000000000ULL
++
++struct hcp_ehea_port_cb2 {
++ u64 rxo;
++ u64 rxucp;
++ u64 rxufd;
++ u64 rxuerr;
++ u64 rxftl;
++ u64 rxmcp;
++ u64 rxbcp;
++ u64 txo;
++ u64 txucp;
++ u64 txmcp;
++ u64 txbcp;
++};
++
++struct hcp_ehea_port_cb3 {
++ u64 vlan_bc_filter[64];
++ u64 vlan_mc_filter[64];
++ u64 vlan_un_filter[64];
++ u64 port_mac_hash_array[64];
++};
++
++#define H_PORT_CB4_ALL 0xF000000000000000ULL
++#define H_PORT_CB4_JUMBO 0x1000000000000000ULL
++#define H_PORT_CB4_SPEED 0x8000000000000000ULL
++
++struct hcp_ehea_port_cb4 {
++ u32 port_speed;
++ u32 pause_frame;
++ u32 ens_port_op_state;
++ u32 jumbo_frame;
++ u32 ens_port_wrap;
++};
++
++/* Hcall Query/Modify Port Control Block 5 Selection Mask Bits */
++#define H_PORT_CB5_RCU 0x0001000000000000ULL
++#define PXS_RCU EHEA_BMASK_IBM(61, 63)
++
++struct hcp_ehea_port_cb5 {
++ u64 prc; /* 00 */
++ u64 uaa; /* 01 */
++ u64 macvc; /* 02 */
++ u64 xpcsc; /* 03 */
++ u64 xpcsp; /* 04 */
++ u64 pcsid; /* 05 */
++ u64 xpcsst; /* 06 */
++ u64 pthlb; /* 07 */
++ u64 pthrb; /* 08 */
++ u64 pqu; /* 09 */
++ u64 pqd; /* 10 */
++ u64 prt; /* 11 */
++ u64 wsth; /* 12 */
++ u64 rcb; /* 13 */
++ u64 rcm; /* 14 */
++ u64 rcu; /* 15 */
++ u64 macc; /* 16 */
++ u64 pc; /* 17 */
++ u64 pst; /* 18 */
++ u64 ducqpn; /* 19 */
++ u64 mcqpn; /* 20 */
++ u64 mma; /* 21 */
++ u64 pmc0h; /* 22 */
++ u64 pmc0l; /* 23 */
++ u64 lbc; /* 24 */
++};
++
++#define H_PORT_CB6_ALL 0xFFFFFE7FFFFF8000ULL
++
++struct hcp_ehea_port_cb6 {
++ u64 rxo; /* 00 */
++ u64 rx64; /* 01 */
++ u64 rx65; /* 02 */
++ u64 rx128; /* 03 */
++ u64 rx256; /* 04 */
++ u64 rx512; /* 05 */
++ u64 rx1024; /* 06 */
++ u64 rxbfcs; /* 07 */
++ u64 rxime; /* 08 */
++ u64 rxrle; /* 09 */
++ u64 rxorle; /* 10 */
++ u64 rxftl; /* 11 */
++ u64 rxjab; /* 12 */
++ u64 rxse; /* 13 */
++ u64 rxce; /* 14 */
++ u64 rxrf; /* 15 */
++ u64 rxfrag; /* 16 */
++ u64 rxuoc; /* 17 */
++ u64 rxcpf; /* 18 */
++ u64 rxsb; /* 19 */
++ u64 rxfd; /* 20 */
++ u64 rxoerr; /* 21 */
++ u64 rxaln; /* 22 */
++ u64 ducqpn; /* 23 */
++ u64 reserved0; /* 24 */
++ u64 rxmcp; /* 25 */
++ u64 rxbcp; /* 26 */
++ u64 txmcp; /* 27 */
++ u64 txbcp; /* 28 */
++ u64 txo; /* 29 */
++ u64 tx64; /* 30 */
++ u64 tx65; /* 31 */
++ u64 tx128; /* 32 */
++ u64 tx256; /* 33 */
++ u64 tx512; /* 34 */
++ u64 tx1024; /* 35 */
++ u64 txbfcs; /* 36 */
++ u64 txcpf; /* 37 */
++ u64 txlf; /* 38 */
++ u64 txrf; /* 39 */
++ u64 txime; /* 40 */
++ u64 txsc; /* 41 */
++ u64 txmc; /* 42 */
++ u64 txsqe; /* 43 */
++ u64 txdef; /* 44 */
++ u64 txlcol; /* 45 */
++ u64 txexcol; /* 46 */
++ u64 txcse; /* 47 */
++ u64 txbor; /* 48 */
++};
++
++#define H_PORT_CB7_DUCQPN 0x8000000000000000ULL
++
++struct hcp_ehea_port_cb7 {
++ u64 def_uc_qpn;
++};
++
++u64 ehea_h_query_ehea_qp(const u64 adapter_handle,
++ const u8 qp_category,
++ const u64 qp_handle, const u64 sel_mask,
++ void *cb_addr);
++
++u64 ehea_h_modify_ehea_qp(const u64 adapter_handle,
++ const u8 cat,
++ const u64 qp_handle,
++ const u64 sel_mask,
++ void *cb_addr,
++ u64 * inv_attr_id,
++ u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
++
++u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
++ struct ehea_eq_attr *eq_attr, u64 * eq_handle);
++
++u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
++ struct ehea_cq_attr *cq_attr,
++ u64 * cq_handle, struct h_epas *epas);
++
++u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
++ struct ehea_qp_init_attr *init_attr,
++ const u32 pd,
++ u64 * qp_handle, struct h_epas *h_epas);
++
++#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48,55)
++#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62,63)
++
++u64 ehea_h_register_rpage(const u64 adapter_handle,
++ const u8 pagesize,
++ const u8 queue_type,
++ const u64 resource_handle,
++ const u64 log_pageaddr, u64 count);
++
++#define H_DISABLE_GET_EHEA_WQE_P 1
++#define H_DISABLE_GET_SQ_WQE_P 2
++#define H_DISABLE_GET_RQC 3
++
++u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle);
++
++u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle);
++
++u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
++ const u64 length, const u32 access_ctrl,
++ const u32 pd, u64 * mr_handle, u32 * lkey);
++
++u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
++ const u8 pagesize, const u8 queue_type,
++ const u64 log_pageaddr, const u64 count);
++
++u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
++ const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
++ struct ehea_mr *mr);
++
++u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr);
++
++/* output param R5 */
++#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40,47)
++#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48,63)
++
++u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
++ const u8 cb_cat, const u64 select_mask,
++ void *cb_addr);
++
++u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
++ const u8 cb_cat, const u64 select_mask,
++ void *cb_addr);
++
++#define H_REGBCMC_PN EHEA_BMASK_IBM(48, 63)
++#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(61, 63)
++#define H_REGBCMC_MACADDR EHEA_BMASK_IBM(16, 63)
++#define H_REGBCMC_VLANID EHEA_BMASK_IBM(52, 63)
++
++u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
++ const u8 reg_type, const u64 mc_mac_addr,
++ const u16 vlan_id, const u32 hcall_id);
++
++u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
++ const u64 event_mask);
++
++#endif /* __EHEA_PHYP_H__ */
+diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
+new file mode 100644
+index 0000000..72ef7bd
+--- /dev/null
++++ b/drivers/net/ehea/ehea_qmr.c
+@@ -0,0 +1,583 @@
++/*
++ * linux/drivers/net/ehea/ehea_qmr.c
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 "ehea.h"
++#include "ehea_phyp.h"
++#include "ehea_qmr.h"
++
++static void *hw_qpageit_get_inc(struct hw_queue *queue)
++{
++ void *retvalue = hw_qeit_get(queue);
++
++ queue->current_q_offset += queue->pagesize;
++ if (queue->current_q_offset > queue->queue_length) {
++ queue->current_q_offset -= queue->pagesize;
++ retvalue = NULL;
++ } else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) {
++ ehea_error("not on pageboundary");
++ retvalue = NULL;
++ }
++ return retvalue;
++}
++
++static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
++ const u32 pagesize, const u32 qe_size)
++{
++ int pages_per_kpage = PAGE_SIZE / pagesize;
++ int i, k;
++
++ if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) {
++ ehea_error("pagesize conflict! kernel pagesize=%d, "
++ "ehea pagesize=%d", (int)PAGE_SIZE, (int)pagesize);
++ return -EINVAL;
++ }
++
++ queue->queue_length = nr_of_pages * pagesize;
++ queue->queue_pages = kmalloc(nr_of_pages * sizeof(void*), GFP_KERNEL);
++ if (!queue->queue_pages) {
++ ehea_error("no mem for queue_pages");
++ return -ENOMEM;
++ }
++
++ /*
++ * allocate pages for queue:
++ * outer loop allocates whole kernel pages (page aligned) and
++ * inner loop divides a kernel page into smaller hea queue pages
++ */
++ i = 0;
++ while (i < nr_of_pages) {
++ u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
++ if (!kpage)
++ goto out_nomem;
++ for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
++ (queue->queue_pages)[i] = (struct ehea_page*)kpage;
++ kpage += pagesize;
++ i++;
++ }
++ }
++
++ queue->current_q_offset = 0;
++ queue->qe_size = qe_size;
++ queue->pagesize = pagesize;
++ queue->toggle_state = 1;
++
++ return 0;
++out_nomem:
++ for (i = 0; i < nr_of_pages; i += pages_per_kpage) {
++ if (!(queue->queue_pages)[i])
++ break;
++ free_page((unsigned long)(queue->queue_pages)[i]);
++ }
++ return -ENOMEM;
++}
++
++static void hw_queue_dtor(struct hw_queue *queue)
++{
++ int pages_per_kpage = PAGE_SIZE / queue->pagesize;
++ int i, nr_pages;
++
++ if (!queue || !queue->queue_pages)
++ return;
++
++ nr_pages = queue->queue_length / queue->pagesize;
++
++ for (i = 0; i < nr_pages; i += pages_per_kpage)
++ free_page((unsigned long)(queue->queue_pages)[i]);
++
++ kfree(queue->queue_pages);
++}
++
++struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
++ int nr_of_cqe, u64 eq_handle, u32 cq_token)
++{
++ struct ehea_cq *cq;
++ struct h_epa epa;
++ u64 *cq_handle_ref, hret, rpage;
++ u32 act_nr_of_entries, act_pages, counter;
++ int ret;
++ void *vpage;
++
++ cq = kzalloc(sizeof(*cq), GFP_KERNEL);
++ if (!cq) {
++ ehea_error("no mem for cq");
++ goto out_nomem;
++ }
++
++ cq->attr.max_nr_of_cqes = nr_of_cqe;
++ cq->attr.cq_token = cq_token;
++ cq->attr.eq_handle = eq_handle;
++
++ cq->adapter = adapter;
++
++ cq_handle_ref = &cq->fw_handle;
++ act_nr_of_entries = 0;
++ act_pages = 0;
++
++ hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr,
++ &cq->fw_handle, &cq->epas);
++ if (hret != H_SUCCESS) {
++ ehea_error("alloc_resource_cq failed");
++ goto out_freemem;
++ }
++
++ ret = hw_queue_ctor(&cq->hw_queue, cq->attr.nr_pages,
++ EHEA_PAGESIZE, sizeof(struct ehea_cqe));
++ if (ret)
++ goto out_freeres;
++
++ for (counter = 0; counter < cq->attr.nr_pages; counter++) {
++ vpage = hw_qpageit_get_inc(&cq->hw_queue);
++ if (!vpage) {
++ ehea_error("hw_qpageit_get_inc failed");
++ goto out_kill_hwq;
++ }
++
++ rpage = virt_to_abs(vpage);
++ hret = ehea_h_register_rpage(adapter->handle,
++ 0, EHEA_CQ_REGISTER_ORIG,
++ cq->fw_handle, rpage, 1);
++ if (hret < H_SUCCESS) {
++ ehea_error("register_rpage_cq failed ehea_cq=%p "
++ "hret=%lx counter=%i act_pages=%i",
++ cq, hret, counter, cq->attr.nr_pages);
++ goto out_kill_hwq;
++ }
++
++ if (counter == (cq->attr.nr_pages - 1)) {
++ vpage = hw_qpageit_get_inc(&cq->hw_queue);
++
++ if ((hret != H_SUCCESS) || (vpage)) {
++ ehea_error("registration of pages not "
++ "complete hret=%lx\n", hret);
++ goto out_kill_hwq;
++ }
++ } else {
++ if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
++ ehea_error("CQ: registration of page failed "
++ "hret=%lx\n", hret);
++ goto out_kill_hwq;
++ }
++ }
++ }
++
++ hw_qeit_reset(&cq->hw_queue);
++ epa = cq->epas.kernel;
++ ehea_reset_cq_ep(cq);
++ ehea_reset_cq_n1(cq);
++
++ return cq;
++
++out_kill_hwq:
++ hw_queue_dtor(&cq->hw_queue);
++
++out_freeres:
++ ehea_h_free_resource(adapter->handle, cq->fw_handle);
++
++out_freemem:
++ kfree(cq);
++
++out_nomem:
++ return NULL;
++}
++
++int ehea_destroy_cq(struct ehea_cq *cq)
++{
++ u64 adapter_handle, hret;
++
++ if (!cq)
++ return 0;
++
++ adapter_handle = cq->adapter->handle;
++
++ /* deregister all previous registered pages */
++ hret = ehea_h_free_resource(adapter_handle, cq->fw_handle);
++ if (hret != H_SUCCESS) {
++ ehea_error("destroy CQ failed");
++ return -EIO;
++ }
++
++ hw_queue_dtor(&cq->hw_queue);
++ kfree(cq);
++
++ return 0;
++}
++
++struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
++ const enum ehea_eq_type type,
++ const u32 max_nr_of_eqes, const u8 eqe_gen)
++{
++ int ret, i;
++ u64 hret, rpage;
++ void *vpage;
++ struct ehea_eq *eq;
++
++ eq = kzalloc(sizeof(*eq), GFP_KERNEL);
++ if (!eq) {
++ ehea_error("no mem for eq");
++ return NULL;
++ }
++
++ eq->adapter = adapter;
++ eq->attr.type = type;
++ eq->attr.max_nr_of_eqes = max_nr_of_eqes;
++ eq->attr.eqe_gen = eqe_gen;
++ spin_lock_init(&eq->spinlock);
++
++ hret = ehea_h_alloc_resource_eq(adapter->handle,
++ &eq->attr, &eq->fw_handle);
++ if (hret != H_SUCCESS) {
++ ehea_error("alloc_resource_eq failed");
++ goto out_freemem;
++ }
++
++ ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages,
++ EHEA_PAGESIZE, sizeof(struct ehea_eqe));
++ if (ret) {
++ ehea_error("can't allocate eq pages");
++ goto out_freeres;
++ }
++
++ for (i = 0; i < eq->attr.nr_pages; i++) {
++ vpage = hw_qpageit_get_inc(&eq->hw_queue);
++ if (!vpage) {
++ ehea_error("hw_qpageit_get_inc failed");
++ hret = H_RESOURCE;
++ goto out_kill_hwq;
++ }
++
++ rpage = virt_to_abs(vpage);
++
++ hret = ehea_h_register_rpage(adapter->handle, 0,
++ EHEA_EQ_REGISTER_ORIG,
++ eq->fw_handle, rpage, 1);
++
++ if (i == (eq->attr.nr_pages - 1)) {
++ /* last page */
++ vpage = hw_qpageit_get_inc(&eq->hw_queue);
++ if ((hret != H_SUCCESS) || (vpage)) {
++ goto out_kill_hwq;
++ }
++ } else {
++ if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
++ goto out_kill_hwq;
++ }
++ }
++ }
++
++ hw_qeit_reset(&eq->hw_queue);
++ return eq;
++
++out_kill_hwq:
++ hw_queue_dtor(&eq->hw_queue);
++
++out_freeres:
++ ehea_h_free_resource(adapter->handle, eq->fw_handle);
++
++out_freemem:
++ kfree(eq);
++ return NULL;
++}
++
++struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
++{
++ struct ehea_eqe *eqe;
++ unsigned long flags;
++
++ spin_lock_irqsave(&eq->spinlock, flags);
++ eqe = (struct ehea_eqe*)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
++ spin_unlock_irqrestore(&eq->spinlock, flags);
++
++ return eqe;
++}
++
++int ehea_destroy_eq(struct ehea_eq *eq)
++{
++ u64 hret;
++ unsigned long flags;
++
++ if (!eq)
++ return 0;
++
++ spin_lock_irqsave(&eq->spinlock, flags);
++
++ hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle);
++ spin_unlock_irqrestore(&eq->spinlock, flags);
++
++ if (hret != H_SUCCESS) {
++ ehea_error("destroy_eq failed");
++ return -EIO;
++ }
++
++ hw_queue_dtor(&eq->hw_queue);
++ kfree(eq);
++
++ return 0;
++}
++
++/**
++ * allocates memory for a queue and registers pages in phyp
++ */
++int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
++ int nr_pages, int wqe_size, int act_nr_sges,
++ struct ehea_adapter *adapter, int h_call_q_selector)
++{
++ u64 hret, rpage;
++ int ret, cnt;
++ void *vpage;
++
++ ret = hw_queue_ctor(hw_queue, nr_pages, EHEA_PAGESIZE, wqe_size);
++ if (ret)
++ return ret;
++
++ for (cnt = 0; cnt < nr_pages; cnt++) {
++ vpage = hw_qpageit_get_inc(hw_queue);
++ if (!vpage) {
++ ehea_error("hw_qpageit_get_inc failed");
++ goto out_kill_hwq;
++ }
++ rpage = virt_to_abs(vpage);
++ hret = ehea_h_register_rpage(adapter->handle,
++ 0, h_call_q_selector,
++ qp->fw_handle, rpage, 1);
++ if (hret < H_SUCCESS) {
++ ehea_error("register_rpage_qp failed");
++ goto out_kill_hwq;
++ }
++ }
++ hw_qeit_reset(hw_queue);
++ return 0;
++
++out_kill_hwq:
++ hw_queue_dtor(hw_queue);
++ return -EIO;
++}
++
++static inline u32 map_wqe_size(u8 wqe_enc_size)
++{
++ return 128 << wqe_enc_size;
++}
++
++struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
++ u32 pd, struct ehea_qp_init_attr *init_attr)
++{
++ int ret;
++ u64 hret;
++ struct ehea_qp *qp;
++ u32 wqe_size_in_bytes_sq, wqe_size_in_bytes_rq1;
++ u32 wqe_size_in_bytes_rq2, wqe_size_in_bytes_rq3;
++
++
++ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
++ if (!qp) {
++ ehea_error("no mem for qp");
++ return NULL;
++ }
++
++ qp->adapter = adapter;
++
++ hret = ehea_h_alloc_resource_qp(adapter->handle, init_attr, pd,
++ &qp->fw_handle, &qp->epas);
++ if (hret != H_SUCCESS) {
++ ehea_error("ehea_h_alloc_resource_qp failed");
++ goto out_freemem;
++ }
++
++ wqe_size_in_bytes_sq = map_wqe_size(init_attr->act_wqe_size_enc_sq);
++ wqe_size_in_bytes_rq1 = map_wqe_size(init_attr->act_wqe_size_enc_rq1);
++ wqe_size_in_bytes_rq2 = map_wqe_size(init_attr->act_wqe_size_enc_rq2);
++ wqe_size_in_bytes_rq3 = map_wqe_size(init_attr->act_wqe_size_enc_rq3);
++
++ ret = ehea_qp_alloc_register(qp, &qp->hw_squeue, init_attr->nr_sq_pages,
++ wqe_size_in_bytes_sq,
++ init_attr->act_wqe_size_enc_sq, adapter,
++ 0);
++ if (ret) {
++ ehea_error("can't register for sq ret=%x", ret);
++ goto out_freeres;
++ }
++
++ ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue1,
++ init_attr->nr_rq1_pages,
++ wqe_size_in_bytes_rq1,
++ init_attr->act_wqe_size_enc_rq1,
++ adapter, 1);
++ if (ret) {
++ ehea_error("can't register for rq1 ret=%x", ret);
++ goto out_kill_hwsq;
++ }
++
++ if (init_attr->rq_count > 1) {
++ ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue2,
++ init_attr->nr_rq2_pages,
++ wqe_size_in_bytes_rq2,
++ init_attr->act_wqe_size_enc_rq2,
++ adapter, 2);
++ if (ret) {
++ ehea_error("can't register for rq2 ret=%x", ret);
++ goto out_kill_hwr1q;
++ }
++ }
++
++ if (init_attr->rq_count > 2) {
++ ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue3,
++ init_attr->nr_rq3_pages,
++ wqe_size_in_bytes_rq3,
++ init_attr->act_wqe_size_enc_rq3,
++ adapter, 3);
++ if (ret) {
++ ehea_error("can't register for rq3 ret=%x", ret);
++ goto out_kill_hwr2q;
++ }
++ }
++
++ qp->init_attr = *init_attr;
++
++ return qp;
++
++out_kill_hwr2q:
++ hw_queue_dtor(&qp->hw_rqueue2);
++
++out_kill_hwr1q:
++ hw_queue_dtor(&qp->hw_rqueue1);
++
++out_kill_hwsq:
++ hw_queue_dtor(&qp->hw_squeue);
++
++out_freeres:
++ ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
++ ehea_h_free_resource(adapter->handle, qp->fw_handle);
++
++out_freemem:
++ kfree(qp);
++ return NULL;
++}
++
++int ehea_destroy_qp(struct ehea_qp *qp)
++{
++ u64 hret;
++ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
++
++ if (!qp)
++ return 0;
++
++ hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
++ if (hret != H_SUCCESS) {
++ ehea_error("destroy_qp failed");
++ return -EIO;
++ }
++
++ hw_queue_dtor(&qp->hw_squeue);
++ hw_queue_dtor(&qp->hw_rqueue1);
++
++ if (qp_attr->rq_count > 1)
++ hw_queue_dtor(&qp->hw_rqueue2);
++ if (qp_attr->rq_count > 2)
++ hw_queue_dtor(&qp->hw_rqueue3);
++ kfree(qp);
++
++ return 0;
++}
++
++int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
++{
++ int i, k, ret;
++ u64 hret, pt_abs, start, end, nr_pages;
++ u32 acc_ctrl = EHEA_MR_ACC_CTRL;
++ u64 *pt;
++
++ start = KERNELBASE;
++ end = (u64)high_memory;
++ nr_pages = (end - start) / EHEA_PAGESIZE;
++
++ pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!pt) {
++ ehea_error("no mem");
++ ret = -ENOMEM;
++ goto out;
++ }
++ pt_abs = virt_to_abs(pt);
++
++ hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
++ acc_ctrl, adapter->pd,
++ &adapter->mr.handle, &adapter->mr.lkey);
++ if (hret != H_SUCCESS) {
++ ehea_error("alloc_resource_mr failed");
++ ret = -EIO;
++ goto out;
++ }
++
++ adapter->mr.vaddr = KERNELBASE;
++ k = 0;
++
++ while (nr_pages > 0) {
++ if (nr_pages > 1) {
++ u64 num_pages = min(nr_pages, (u64)512);
++ for (i = 0; i < num_pages; i++)
++ pt[i] = virt_to_abs((void*)(((u64)start) +
++ ((k++) *
++ EHEA_PAGESIZE)));
++
++ hret = ehea_h_register_rpage_mr(adapter->handle,
++ adapter->mr.handle, 0,
++ 0, (u64)pt_abs,
++ num_pages);
++ nr_pages -= num_pages;
++ } else {
++ u64 abs_adr = virt_to_abs((void*)(((u64)start) +
++ (k * EHEA_PAGESIZE)));
++
++ hret = ehea_h_register_rpage_mr(adapter->handle,
++ adapter->mr.handle, 0,
++ 0, abs_adr,1);
++ nr_pages--;
++ }
++
++ if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
++ ehea_h_free_resource(adapter->handle,
++ adapter->mr.handle);
++ ehea_error("register_rpage_mr failed: hret = %lX",
++ hret);
++ ret = -EIO;
++ goto out;
++ }
++ }
++
++ if (hret != H_SUCCESS) {
++ ehea_h_free_resource(adapter->handle, adapter->mr.handle);
++ ehea_error("register_rpage failed for last page: hret = %lX",
++ hret);
++ ret = -EIO;
++ goto out;
++ }
++ ret = 0;
++out:
++ kfree(pt);
++ return ret;
++}
++
++
+diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
+new file mode 100644
+index 0000000..7efdc96
+--- /dev/null
++++ b/drivers/net/ehea/ehea_qmr.h
+@@ -0,0 +1,358 @@
++/*
++ * linux/drivers/net/ehea/ehea_qmr.h
++ *
++ * eHEA ethernet device driver for IBM eServer System p
++ *
++ * (C) Copyright IBM Corp. 2006
++ *
++ * Authors:
++ * Christoph Raisch <raisch at de.ibm.com>
++ * Jan-Bernd Themann <themann at de.ibm.com>
++ * Thomas Klein <tklein at de.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, 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 __EHEA_QMR_H__
++#define __EHEA_QMR_H__
++
++#include "ehea.h"
++#include "ehea_hw.h"
++
++/*
++ * page size of ehea hardware queues
++ */
++
++#define EHEA_PAGESHIFT 12
++#define EHEA_PAGESIZE 4096UL
++
++/* Some abbreviations used here:
++ *
++ * WQE - Work Queue Entry
++ * SWQE - Send Work Queue Entry
++ * RWQE - Receive Work Queue Entry
++ * CQE - Completion Queue Entry
++ * EQE - Event Queue Entry
++ * MR - Memory Region
++ */
++
++/* Use of WR_ID field for EHEA */
++#define EHEA_WR_ID_COUNT EHEA_BMASK_IBM(0, 19)
++#define EHEA_WR_ID_TYPE EHEA_BMASK_IBM(20, 23)
++#define EHEA_SWQE2_TYPE 0x1
++#define EHEA_SWQE3_TYPE 0x2
++#define EHEA_RWQE2_TYPE 0x3
++#define EHEA_RWQE3_TYPE 0x4
++#define EHEA_WR_ID_INDEX EHEA_BMASK_IBM(24, 47)
++#define EHEA_WR_ID_REFILL EHEA_BMASK_IBM(48, 63)
++
++struct ehea_vsgentry {
++ u64 vaddr;
++ u32 l_key;
++ u32 len;
++};
++
++/* maximum number of sg entries allowed in a WQE */
++#define EHEA_MAX_WQE_SG_ENTRIES 252
++#define SWQE2_MAX_IMM (0xD0 - 0x30)
++#define SWQE3_MAX_IMM 224
++
++/* tx control flags for swqe */
++#define EHEA_SWQE_CRC 0x8000
++#define EHEA_SWQE_IP_CHECKSUM 0x4000
++#define EHEA_SWQE_TCP_CHECKSUM 0x2000
++#define EHEA_SWQE_TSO 0x1000
++#define EHEA_SWQE_SIGNALLED_COMPLETION 0x0800
++#define EHEA_SWQE_VLAN_INSERT 0x0400
++#define EHEA_SWQE_IMM_DATA_PRESENT 0x0200
++#define EHEA_SWQE_DESCRIPTORS_PRESENT 0x0100
++#define EHEA_SWQE_WRAP_CTL_REC 0x0080
++#define EHEA_SWQE_WRAP_CTL_FORCE 0x0040
++#define EHEA_SWQE_BIND 0x0020
++#define EHEA_SWQE_PURGE 0x0010
++
++/* sizeof(struct ehea_swqe) less the union */
++#define SWQE_HEADER_SIZE 32
++
++struct ehea_swqe {
++ u64 wr_id;
++ u16 tx_control;
++ u16 vlan_tag;
++ u8 reserved1;
++ u8 ip_start;
++ u8 ip_end;
++ u8 immediate_data_length;
++ u8 tcp_offset;
++ u8 reserved2;
++ u16 tcp_end;
++ u8 wrap_tag;
++ u8 descriptors; /* number of valid descriptors in WQE */
++ u16 reserved3;
++ u16 reserved4;
++ u16 mss;
++ u32 reserved5;
++ union {
++ /* Send WQE Format 1 */
++ struct {
++ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
++ } no_immediate_data;
++
++ /* Send WQE Format 2 */
++ struct {
++ struct ehea_vsgentry sg_entry;
++ /* 0x30 */
++ u8 immediate_data[SWQE2_MAX_IMM];
++ /* 0xd0 */
++ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
++ } immdata_desc __attribute__ ((packed));
++
++ /* Send WQE Format 3 */
++ struct {
++ u8 immediate_data[SWQE3_MAX_IMM];
++ } immdata_nodesc;
++ } u;
++};
++
++struct ehea_rwqe {
++ u64 wr_id; /* work request ID */
++ u8 reserved1[5];
++ u8 data_segments;
++ u16 reserved2;
++ u64 reserved3;
++ u64 reserved4;
++ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
++};
++
++#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
++
++#define EHEA_CQE_TYPE_RQ 0x60
++#define EHEA_CQE_STAT_ERR_MASK 0x721F
++#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
++#define EHEA_CQE_STAT_ERR_TCP 0x4000
++
++struct ehea_cqe {
++ u64 wr_id; /* work request ID from WQE */
++ u8 type;
++ u8 valid;
++ u16 status;
++ u16 reserved1;
++ u16 num_bytes_transfered;
++ u16 vlan_tag;
++ u16 inet_checksum_value;
++ u8 reserved2;
++ u8 header_length;
++ u16 reserved3;
++ u16 page_offset;
++ u16 wqe_count;
++ u32 qp_token;
++ u32 timestamp;
++ u32 reserved4;
++ u64 reserved5[3];
++};
++
++#define EHEA_EQE_VALID EHEA_BMASK_IBM(0, 0)
++#define EHEA_EQE_IS_CQE EHEA_BMASK_IBM(1, 1)
++#define EHEA_EQE_IDENTIFIER EHEA_BMASK_IBM(2, 7)
++#define EHEA_EQE_QP_CQ_NUMBER EHEA_BMASK_IBM(8, 31)
++#define EHEA_EQE_QP_TOKEN EHEA_BMASK_IBM(32, 63)
++#define EHEA_EQE_CQ_TOKEN EHEA_BMASK_IBM(32, 63)
++#define EHEA_EQE_KEY EHEA_BMASK_IBM(32, 63)
++#define EHEA_EQE_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
++#define EHEA_EQE_EQ_NUMBER EHEA_BMASK_IBM(48, 63)
++#define EHEA_EQE_SM_ID EHEA_BMASK_IBM(48, 63)
++#define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55)
++#define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
++
++struct ehea_eqe {
++ u64 entry;
++};
++
++static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
++{
++ struct ehea_page *current_page;
++
++ if (q_offset >= queue->queue_length)
++ q_offset -= queue->queue_length;
++ current_page = (queue->queue_pages)[q_offset >> EHEA_PAGESHIFT];
++ return ¤t_page->entries[q_offset & (EHEA_PAGESIZE - 1)];
++}
++
++static inline void *hw_qeit_get(struct hw_queue *queue)
++{
++ return hw_qeit_calc(queue, queue->current_q_offset);
++}
++
++static inline void hw_qeit_inc(struct hw_queue *queue)
++{
++ queue->current_q_offset += queue->qe_size;
++ if (queue->current_q_offset >= queue->queue_length) {
++ queue->current_q_offset = 0;
++ /* toggle the valid flag */
++ queue->toggle_state = (~queue->toggle_state) & 1;
++ }
++}
++
++static inline void *hw_qeit_get_inc(struct hw_queue *queue)
++{
++ void *retvalue = hw_qeit_get(queue);
++ hw_qeit_inc(queue);
++ return retvalue;
++}
++
++static inline void *hw_qeit_get_inc_valid(struct hw_queue *queue)
++{
++ struct ehea_cqe *retvalue = hw_qeit_get(queue);
++ u8 valid = retvalue->valid;
++ void *pref;
++
++ if ((valid >> 7) == (queue->toggle_state & 1)) {
++ /* this is a good one */
++ hw_qeit_inc(queue);
++ pref = hw_qeit_calc(queue, queue->current_q_offset);
++ prefetch(pref);
++ prefetch(pref + 128);
++ } else
++ retvalue = NULL;
++ return retvalue;
++}
++
++static inline void *hw_qeit_get_valid(struct hw_queue *queue)
++{
++ struct ehea_cqe *retvalue = hw_qeit_get(queue);
++ void *pref;
++ u8 valid;
++
++ pref = hw_qeit_calc(queue, queue->current_q_offset);
++ prefetch(pref);
++ prefetch(pref + 128);
++ prefetch(pref + 256);
++ valid = retvalue->valid;
++ if (!((valid >> 7) == (queue->toggle_state & 1)))
++ retvalue = NULL;
++ return retvalue;
++}
++
++static inline void *hw_qeit_reset(struct hw_queue *queue)
++{
++ queue->current_q_offset = 0;
++ return hw_qeit_get(queue);
++}
++
++static inline void *hw_qeit_eq_get_inc(struct hw_queue *queue)
++{
++ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
++ void *retvalue;
++
++ retvalue = hw_qeit_get(queue);
++ queue->current_q_offset += queue->qe_size;
++ if (queue->current_q_offset > last_entry_in_q) {
++ queue->current_q_offset = 0;
++ queue->toggle_state = (~queue->toggle_state) & 1;
++ }
++ return retvalue;
++}
++
++static inline void *hw_eqit_eq_get_inc_valid(struct hw_queue *queue)
++{
++ void *retvalue = hw_qeit_get(queue);
++ u32 qe = *(u8*)retvalue;
++ if ((qe >> 7) == (queue->toggle_state & 1))
++ hw_qeit_eq_get_inc(queue);
++ else
++ retvalue = NULL;
++ return retvalue;
++}
++
++static inline struct ehea_rwqe *ehea_get_next_rwqe(struct ehea_qp *qp,
++ int rq_nr)
++{
++ struct hw_queue *queue;
++
++ if (rq_nr == 1)
++ queue = &qp->hw_rqueue1;
++ else if (rq_nr == 2)
++ queue = &qp->hw_rqueue2;
++ else
++ queue = &qp->hw_rqueue3;
++
++ return hw_qeit_get_inc(queue);
++}
++
++static inline struct ehea_swqe *ehea_get_swqe(struct ehea_qp *my_qp,
++ int *wqe_index)
++{
++ struct hw_queue *queue = &my_qp->hw_squeue;
++ struct ehea_swqe *wqe_p;
++
++ *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_SQ);
++ wqe_p = hw_qeit_get_inc(&my_qp->hw_squeue);
++
++ return wqe_p;
++}
++
++static inline void ehea_post_swqe(struct ehea_qp *my_qp, struct ehea_swqe *swqe)
++{
++ iosync();
++ ehea_update_sqa(my_qp, 1);
++}
++
++static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
++{
++ struct hw_queue *queue = &qp->hw_rqueue1;
++
++ *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_RQ1);
++ return hw_qeit_get_valid(queue);
++}
++
++static inline void ehea_inc_rq1(struct ehea_qp *qp)
++{
++ hw_qeit_inc(&qp->hw_rqueue1);
++}
++
++static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
++{
++ return hw_qeit_get_inc_valid(&my_cq->hw_queue);
++}
++
++#define EHEA_CQ_REGISTER_ORIG 0
++#define EHEA_EQ_REGISTER_ORIG 0
++
++enum ehea_eq_type {
++ EHEA_EQ = 0, /* event queue */
++ EHEA_NEQ /* notification event queue */
++};
++
++struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
++ enum ehea_eq_type type,
++ const u32 length, const u8 eqe_gen);
++
++int ehea_destroy_eq(struct ehea_eq *eq);
++
++struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq);
++
++struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
++ u64 eq_handle, u32 cq_token);
++
++int ehea_destroy_cq(struct ehea_cq *cq);
++
++struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
++ struct ehea_qp_init_attr *init_attr);
++
++int ehea_destroy_qp(struct ehea_qp *qp);
++
++int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
++
++#endif /* __EHEA_QMR_H__ */
+diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
+index a67650c..3a6a83d 100644
+--- a/drivers/net/epic100.c
++++ b/drivers/net/epic100.c
+@@ -26,8 +26,8 @@
+ */
+
+ #define DRV_NAME "epic100"
+-#define DRV_VERSION "2.0"
+-#define DRV_RELDATE "June 27, 2006"
++#define DRV_VERSION "2.1"
++#define DRV_RELDATE "Sept 11, 2006"
+
+ /* The user-configurable values.
+ These may be modified when a driver module is loaded.*/
+@@ -297,9 +297,9 @@ static void epic_init_ring(struct net_de
+ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int epic_rx(struct net_device *dev, int budget);
+ static int epic_poll(struct net_device *dev, int *budget);
+-static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t epic_interrupt(int irq, void *dev_instance);
+ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static int epic_close(struct net_device *dev);
+ static struct net_device_stats *epic_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+@@ -1081,7 +1081,7 @@ static void epic_tx(struct net_device *d
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t epic_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct epic_private *ep = dev->priv;
+@@ -1386,7 +1386,6 @@ static void set_rx_mode(struct net_devic
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ outl(0x002C, ioaddr + RxCtrl);
+ /* Unconditionally log net taps. */
+- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) {
+ /* There is apparently a chip bug, so the multicast filter
+@@ -1493,7 +1492,7 @@ static void ethtool_complete(struct net_
+ }
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_settings = netdev_get_settings,
+ .set_settings = netdev_set_settings,
+@@ -1604,7 +1603,7 @@ static int __init epic_init (void)
+ version, version2, version3);
+ #endif
+
+- return pci_module_init (&epic_driver);
++ return pci_register_driver(&epic_driver);
+ }
+
+
+diff --git a/drivers/net/eql.c b/drivers/net/eql.c
+index 815436c..a93700e 100644
+--- a/drivers/net/eql.c
++++ b/drivers/net/eql.c
+@@ -8,7 +8,7 @@
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+- *
++ *
+ * The author may be reached as simon at ncm.com, or C/O
+ * NCM
+ * Attn: Simon Janes
+@@ -23,7 +23,7 @@
+ * Inspirations:
+ * The Harried and Overworked Alan Cox
+ * Conspiracies:
+- * The Alan Cox and Mike McLagan plot to get someone else to do the code,
++ * The Alan Cox and Mike McLagan plot to get someone else to do the code,
+ * which turned out to be me.
+ */
+
+@@ -138,7 +138,7 @@ static void eql_timer(unsigned long para
+ {
+ equalizer_t *eql = (equalizer_t *) param;
+ struct list_head *this, *tmp, *head;
+-
++
+ spin_lock_bh(&eql->queue.lock);
+ head = &eql->queue.all_slaves;
+ list_for_each_safe(this, tmp, head) {
+@@ -159,7 +159,7 @@ static void eql_timer(unsigned long para
+ add_timer(&eql->timer);
+ }
+
+-static char version[] __initdata =
++static char version[] __initdata =
+ "Equalizer2002: Simon Janes (simon at ncm.com) and David S. Miller (davem at redhat.com)\n";
+
+ static void __init eql_setup(struct net_device *dev)
+@@ -182,12 +182,12 @@ static void __init eql_setup(struct net_
+ dev->do_ioctl = eql_ioctl;
+ dev->hard_start_xmit = eql_slave_xmit;
+ dev->get_stats = eql_get_stats;
+-
++
+ /*
+ * Now we undo some of the things that eth_setup does
+- * that we don't like
++ * that we don't like
+ */
+-
++
+ dev->mtu = EQL_DEFAULT_MTU; /* set to 576 in if_eql.h */
+ dev->flags = IFF_MASTER;
+
+@@ -223,7 +223,7 @@ static void eql_kill_one_slave(slave_que
+ }
+
+ static void eql_kill_slave_queue(slave_queue_t *queue)
+-{
++{
+ struct list_head *head, *tmp, *this;
+
+ spin_lock_bh(&queue->lock);
+@@ -244,7 +244,7 @@ static int eql_close(struct net_device *
+
+ /*
+ * The timer has to be stopped first before we start hacking away
+- * at the data structure it scans every so often...
++ * at the data structure it scans every so often...
+ */
+
+ del_timer_sync(&eql->timer);
+@@ -264,7 +264,7 @@ static int eql_g_master_cfg(struct net_d
+ static int eql_s_master_cfg(struct net_device *dev, master_config_t __user *mc);
+
+ static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+-{
++{
+ if (cmd != EQL_GETMASTRCFG && cmd != EQL_GETSLAVECFG &&
+ !capable(CAP_NET_ADMIN))
+ return -EPERM;
+@@ -300,15 +300,15 @@ static slave_t *__eql_schedule_slaves(sl
+ head = &queue->all_slaves;
+ list_for_each_safe(this, tmp, head) {
+ slave_t *slave = list_entry(this, slave_t, list);
+- unsigned long slave_load, bytes_queued, priority_Bps;
++ unsigned long slave_load, bytes_queued, priority_Bps;
+
+ /* Go through the slave list once, updating best_slave
+ * whenever a new best_load is found.
+ */
+ bytes_queued = slave->bytes_queued;
+- priority_Bps = slave->priority_Bps;
++ priority_Bps = slave->priority_Bps;
+ if ((slave->dev->flags & IFF_UP) == IFF_UP) {
+- slave_load = (~0UL - (~0UL / 2)) -
++ slave_load = (~0UL - (~0UL / 2)) -
+ (priority_Bps) + bytes_queued * 8;
+
+ if (slave_load < best_load) {
+@@ -336,13 +336,13 @@ static int eql_slave_xmit(struct sk_buff
+
+ skb->dev = slave_dev;
+ skb->priority = 1;
+- slave->bytes_queued += skb->len;
++ slave->bytes_queued += skb->len;
+ dev_queue_xmit(skb);
+ eql->stats.tx_packets++;
+ } else {
+ eql->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+- }
++ }
+
+ spin_unlock(&eql->queue.lock);
+
+@@ -596,7 +596,7 @@ static int __init eql_init_module(void)
+ return -ENOMEM;
+
+ err = register_netdev(dev_eql);
+- if (err)
++ if (err)
+ free_netdev(dev_eql);
+ return err;
+ }
+diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
+index ca42efa..b7b8bc2 100644
+--- a/drivers/net/eth16i.c
++++ b/drivers/net/eth16i.c
+@@ -1,7 +1,7 @@
+ /* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
+-
++
+ Written 1994-1999 by Mika Kuoppala
+-
++
+ Copyright (C) 1994-1999 by Mika Kuoppala
+ Based on skeleton.c and heavily on at1700.c by Donald Becker
+
+@@ -12,7 +12,7 @@
+
+ This driver supports following cards :
+ - ICL EtherTeam 16i
+- - ICL EtherTeam 32 EISA
++ - ICL EtherTeam 32 EISA
+ (Uses true 32 bit transfers rather than 16i compability mode)
+
+ Example Module usage:
+@@ -25,26 +25,26 @@
+
+ I have benchmarked driver with PII/300Mhz as a ftp client
+ and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
+-
++
+ Sources:
+ - skeleton.c a sample network driver core for linux,
+ written by Donald Becker <becker at scyld.com>
+- - at1700.c a driver for Allied Telesis AT1700, written
++ - at1700.c a driver for Allied Telesis AT1700, written
+ by Donald Becker.
+ - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
+ written by Markku Viima
+ - The Fujitsu MB86965 databook.
+-
+- Author thanks following persons due to their valueble assistance:
++
++ Author thanks following persons due to their valueble assistance:
+ Markku Viima (ICL)
+- Ari Valve (ICL)
++ Ari Valve (ICL)
+ Donald Becker
+ Kurt Huwig <kurt at huwig.de>
+
+ Revision history:
+
+ Version Date Description
+-
++
+ 0.01 15.12-94 Initial version (card detection)
+ 0.02 23.01-95 Interrupt is now hooked correctly
+ 0.03 01.02-95 Rewrote initialization part
+@@ -58,7 +58,7 @@
+ 0.05 08.02-95 If there were more than one packet to send,
+ transmit was jammed due to invalid
+ register write...now fixed
+- 0.06 19.02-95 Rewrote interrupt handling
++ 0.06 19.02-95 Rewrote interrupt handling
+ 0.07 13.04-95 Wrote EEPROM read routines
+ Card configuration now set according to
+ data read from EEPROM
+@@ -66,34 +66,34 @@
+ port if AUTO is selected
+
+ 0.09 01.09-95 Added module support
+-
++
+ 0.10 04.09-95 Fixed receive packet allocation to work
+ with kernels > 1.3.x
+-
+- 0.20 20.09-95 Added support for EtherTeam32 EISA
+
+- 0.21 17.10-95 Removed the unnecessary extern
++ 0.20 20.09-95 Added support for EtherTeam32 EISA
++
++ 0.21 17.10-95 Removed the unnecessary extern
+ init_etherdev() declaration. Some
+ other cleanups.
+-
++
+ 0.22 22.02-96 Receive buffer was not flushed
+ correctly when faulty packet was
+ received. Now fixed.
+
+- 0.23 26.02-96 Made resetting the adapter
++ 0.23 26.02-96 Made resetting the adapter
+ more reliable.
+-
++
+ 0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx
+
+ 0.25 22.05-96 kfree() was missing from cleanup_module.
+
+- 0.26 11.06-96 Sometimes card was not found by
++ 0.26 11.06-96 Sometimes card was not found by
+ check_signature(). Now made more reliable.
+-
+- 0.27 23.06-96 Oops. 16 consecutive collisions halted
+- adapter. Now will try to retransmit
++
++ 0.27 23.06-96 Oops. 16 consecutive collisions halted
++ adapter. Now will try to retransmit
+ MAX_COL_16 times before finally giving up.
+-
++
+ 0.28 28.10-97 Added dev_id parameter (NULL) for free_irq
+
+ 0.29 29.10-97 Multiple card support for module users
+@@ -103,16 +103,16 @@
+
+ 0.30a 21.08-98 Card detection made more relaxed. Driver
+ had problems with some TCP/IP-PROM boots
+- to find the card. Suggested by
++ to find the card. Suggested by
+ Kurt Huwig <kurt at huwig.de>
+
+ 0.31 28.08-98 Media interface port can now be selected
+ with module parameters or kernel
+- boot parameters.
++ boot parameters.
+
+- 0.32 31.08-98 IRQ was never freed if open/close
++ 0.32 31.08-98 IRQ was never freed if open/close
+ pair wasn't called. Now fixed.
+-
++
+ 0.33 10.09-98 When eth16i_open() was called after
+ eth16i_close() chip never recovered.
+ Now more shallow reset is made on
+@@ -122,15 +122,15 @@
+ Changed ioaddr -> io for consistency
+
+ 0.35 01.07-99 transmit,-receive bytes were never
+- updated in stats.
++ updated in stats.
+
+ Bugs:
+- In some cases the media interface autoprobing code doesn't find
+- the correct interface type. In this case you can
+- manually choose the interface type in DOS with E16IC.EXE which is
++ In some cases the media interface autoprobing code doesn't find
++ the correct interface type. In this case you can
++ manually choose the interface type in DOS with E16IC.EXE which is
+ configuration software for EtherTeam16i and EtherTeam32 cards.
+ This is also true for IRQ setting. You cannot use module
+- parameter to configure IRQ of the card (yet).
++ parameter to configure IRQ of the card (yet).
+
+ To do:
+ - Real multicast support
+@@ -142,18 +142,18 @@
+ irq without configuration utility.
+ */
+
+-static char *version =
++static char *version =
+ "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku at iki.fi)\n";
+
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/fcntl.h>
+-#include <linux/interrupt.h>
+-#include <linux/ioport.h>
+-#include <linux/in.h>
+-#include <linux/slab.h>
+-#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/in.h>
++#include <linux/slab.h>
++#include <linux/string.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/spinlock.h>
+@@ -162,16 +162,16 @@ static char *version =
+ #include <linux/skbuff.h>
+ #include <linux/bitops.h>
+ #include <linux/jiffies.h>
++#include <linux/io.h>
+
+-#include <asm/system.h>
+-#include <asm/io.h>
++#include <asm/system.h>
+ #include <asm/dma.h>
+
+
+
+ /* Few macros */
+-#define BIT(a) ( (1 << (a)) )
+-#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
++#define BIT(a) ( (1 << (a)) )
++#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
+ #define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
+
+ /* This is the I/O address space for Etherteam 16i adapter. */
+@@ -186,7 +186,7 @@ static char *version =
+ /* Some interrupt masks */
+ #define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */
+ #define ETH16I_INTR_OFF 0x0000
+-
++
+ /* Buffers header status byte meanings */
+ #define PKT_GOOD BIT(5)
+ #define PKT_GOOD_RMT BIT(4)
+@@ -213,7 +213,7 @@ static char *version =
+ #define ALIGN_ERR BIT(2)
+ #define CRC_ERR BIT(1)
+ #define RX_BUF_OVERFLOW BIT(0)
+-
++
+ /* Transmit Interrupt Enable Register (DLCR2) */
+ #define TX_INTR_REG 2
+ #define TX_INTR_DONE BIT(7)
+@@ -252,14 +252,14 @@ static char *version =
+ #define SRAM_CYCLE_TIME_100NS BIT(6)
+ #define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */
+ #define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */
+-#define TBS1 BIT(3)
++#define TBS1 BIT(3)
+ #define TBS0 BIT(2)
+ #define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */
+ #define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */
+
+-#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
++#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
+ #define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */
+-#endif
++#endif
+ #define TX_BUF_1x2048 0
+ #define TX_BUF_2x2048 1
+ #define TX_BUF_2x4098 2
+@@ -297,7 +297,7 @@ static char *version =
+
+ /* DMA Burst and Transceiver Mode Register (BMPR13) */
+ #define TRANSCEIVER_MODE_REG 13
+-#define TRANSCEIVER_MODE_RB 2
++#define TRANSCEIVER_MODE_RB 2
+ #define IO_BASE_UNLOCK BIT(7)
+ #define LOWER_SQUELCH_TRESH BIT(6)
+ #define LINK_TEST_DISABLE BIT(5)
+@@ -337,7 +337,7 @@ static char *version =
+ #define E_PORT_AUTO 0x03
+ #define E_PORT_FROM_EPROM 0x04
+ #define E_PRODUCT_CFG 0x30
+-
++
+
+ /* Macro to slow down io between EEPROM clock transitions */
+ #define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
+@@ -352,12 +352,12 @@ static char *version =
+
+ /* This is the I/O address list to be probed when seeking the card */
+ static unsigned int eth16i_portlist[] __initdata = {
+- 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
++ 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+ };
+
+-static unsigned int eth32i_portlist[] __initdata = {
++static unsigned int eth32i_portlist[] __initdata = {
+ 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
++ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+ };
+
+ /* This is the Interrupt lookup table for Eth16i card */
+@@ -365,7 +365,7 @@ static unsigned int eth16i_irqmap[] __in
+ #define NUM_OF_ISA_IRQS 4
+
+ /* This is the Interrupt lookup table for Eth32i card */
+-static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
++static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
+ #define EISA_IRQ_REG 0xc89
+ #define NUM_OF_EISA_IRQS 8
+
+@@ -384,7 +384,7 @@ struct eth16i_local {
+ unsigned char tx_started;
+ unsigned char tx_buf_busy;
+ unsigned short tx_queue; /* Number of packets in transmit buffer */
+- unsigned short tx_queue_len;
++ unsigned short tx_queue_len;
+ unsigned int tx_buf_size;
+ unsigned long open_time;
+ unsigned long tx_buffered_packets;
+@@ -410,11 +410,11 @@ static int eth16i_close(struct net_d
+ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev);
+ static void eth16i_rx(struct net_device *dev);
+ static void eth16i_timeout(struct net_device *dev);
+-static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t eth16i_interrupt(int irq, void *dev_id);
+ static void eth16i_reset(struct net_device *dev);
+ static void eth16i_timeout(struct net_device *dev);
+ static void eth16i_skip_packet(struct net_device *dev);
+-static void eth16i_multicast(struct net_device *dev);
++static void eth16i_multicast(struct net_device *dev);
+ static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
+ static void eth16i_initialize(struct net_device *dev, int boot);
+
+@@ -435,10 +435,10 @@ static int __init do_eth16i_probe(struct
+ int i;
+ int ioaddr;
+ int base_addr = dev->base_addr;
+-
++
+ SET_MODULE_OWNER(dev);
+
+- if(eth16i_debug > 4)
++ if(eth16i_debug > 4)
+ printk(KERN_DEBUG "Probing started for %s\n", cardname);
+
+ if(base_addr > 0x1ff) /* Check only single location */
+@@ -492,14 +492,14 @@ static int __init eth16i_probe1(struct n
+ return -EBUSY;
+
+ /*
+- The MB86985 chip has on register which holds information in which
++ The MB86985 chip has on register which holds information in which
+ io address the chip lies. First read this register and compare
+ it to our current io address and if match then this could
+ be our chip.
+ */
+
+ if(ioaddr < 0x1000) {
+- if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
++ if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
+ != ioaddr) {
+ retval = -ENODEV;
+ goto out;
+@@ -513,9 +513,9 @@ static int __init eth16i_probe1(struct n
+ goto out;
+ }
+
+- /*
++ /*
+ Now it seems that we have found a ethernet chip in this particular
+- ioaddr. The MB86985 chip has this feature, that when you read a
++ ioaddr. The MB86985 chip has this feature, that when you read a
+ certain register it will increase it's io base address to next
+ configurable slot. Now when we have found the chip, first thing is
+ to make sure that the chip's ioaddr will hold still here.
+@@ -536,7 +536,7 @@ static int __init eth16i_probe1(struct n
+ /* Try to obtain interrupt vector */
+
+ if ((retval = request_irq(dev->irq, (void *)ð16i_interrupt, 0, cardname, dev))) {
+- printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
++ printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
+ cardname, ioaddr, dev->irq);
+ goto out;
+ }
+@@ -547,7 +547,7 @@ static int __init eth16i_probe1(struct n
+
+ /* Now we will have to lock the chip's io address */
+ eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+- outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
++ outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
+
+ eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */
+
+@@ -590,7 +590,7 @@ static void eth16i_initialize(struct net
+ ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
+ }
+
+- for(i = 0; i < 6; i++) {
++ for(i = 0; i < 6; i++) {
+ outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
+ if(boot) {
+ printk("%02x", inb(ioaddr + NODE_ID_0 + i));
+@@ -601,11 +601,11 @@ static void eth16i_initialize(struct net
+
+ /* Now we will set multicast addresses to accept none */
+ eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
+- for(i = 0; i < 8; i++)
++ for(i = 0; i < 8; i++)
+ outb(0x00, ioaddr + HASH_TABLE_0 + i);
+
+ /*
+- Now let's disable the transmitter and receiver, set the buffer ram
++ Now let's disable the transmitter and receiver, set the buffer ram
+ cycle time, bus width and buffer data path width. Also we shall
+ set transmit buffer size and total buffer size.
+ */
+@@ -633,7 +633,7 @@ static void eth16i_initialize(struct net
+ #ifdef MODULE
+ /* if_port already set by init_module() */
+ #else
+- dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
++ dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
+ dev->mem_start : E_PORT_FROM_EPROM;
+ #endif
+
+@@ -651,7 +651,7 @@ static void eth16i_initialize(struct net
+ case E_PORT_AUTO:
+ dev->if_port = eth16i_probe_port(ioaddr);
+ break;
+-
++
+ case E_PORT_BNC:
+ case E_PORT_TP:
+ case E_PORT_DIX:
+@@ -721,7 +721,7 @@ static int eth16i_probe_port(int ioaddr)
+ }
+
+ static void eth16i_set_port(int ioaddr, int porttype)
+-{
++{
+ unsigned short temp = 0;
+
+ eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+@@ -742,13 +742,13 @@ static void eth16i_set_port(int ioaddr,
+ temp |= AUI_SELECT;
+ BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
+ break;
+- }
++ }
+
+ outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
+
+ if(eth16i_debug > 1) {
+ printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
+- printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
++ printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
+ inb(ioaddr+TRANSCEIVER_MODE_REG));
+ }
+ }
+@@ -760,10 +760,10 @@ static int eth16i_send_probe_packet(int
+ outb(0xff, ioaddr + TX_STATUS_REG);
+
+ outw(l, ioaddr + DATAPORT);
+- outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
++ outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
+
+ starttime = jiffies;
+- outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
++ outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
+
+ while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
+ if( time_after(jiffies, starttime + TX_TIMEOUT)) {
+@@ -815,10 +815,10 @@ static int eth16i_set_irq(struct net_dev
+ const int irq = dev->irq;
+ int i = 0;
+
+- if(ioaddr < 0x1000) {
++ if(ioaddr < 0x1000) {
+ while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
+ i++;
+-
++
+ if(i < NUM_OF_ISA_IRQS) {
+ u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+ cbyte = (cbyte & 0x3F) | (i << 6);
+@@ -829,7 +829,7 @@ static int eth16i_set_irq(struct net_dev
+ else {
+ printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
+ }
+-
++
+ return -1;
+
+ }
+@@ -863,7 +863,7 @@ static int __init eth16i_check_signature
+ creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
+
+ if(eth16i_debug > 1)
+- printk("eth16i: read signature byte %x at %x\n",
++ printk("eth16i: read signature byte %x at %x\n",
+ creg[i],
+ ioaddr + TRANSMIT_MODE_REG + i);
+ }
+@@ -872,7 +872,7 @@ static int __init eth16i_check_signature
+ creg[2] &= 0x7F; /* Mask DCLEN bit */
+
+ #if 0
+- /*
++ /*
+ This was removed because the card was sometimes left to state
+ from which it couldn't be find anymore. If there is need
+ to more strict check still this have to be fixed.
+@@ -886,14 +886,14 @@ static int __init eth16i_check_signature
+ if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
+ creg[2] &= 0x40;
+ creg[3] &= 0x03;
+-
++
+ if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
+ return -1;
+ }
+-
++
+ if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
+ return -1;
+-
++
+ if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
+ return -1;
+
+@@ -909,22 +909,22 @@ static int eth16i_read_eeprom(int ioaddr
+ data = eth16i_read_eeprom_word(ioaddr);
+ outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+
+- return(data);
++ return(data);
+ }
+
+ static int eth16i_read_eeprom_word(int ioaddr)
+ {
+ int i;
+ int data = 0;
+-
++
+ for(i = 16; i > 0; i--) {
+ outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+ eeprom_slow_io();
+ outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+ eeprom_slow_io();
+- data = (data << 1) |
++ data = (data << 1) |
+ ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+-
++
+ eeprom_slow_io();
+ }
+
+@@ -948,25 +948,25 @@ static void eth16i_eeprom_cmd(int ioaddr
+ eeprom_slow_io();
+ outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+ eeprom_slow_io();
+- }
++ }
+ }
+
+ static int eth16i_open(struct net_device *dev)
+ {
+ struct eth16i_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+-
++
+ /* Powerup the chip */
+ outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
+
+ /* Initialize the chip */
+- eth16i_initialize(dev, 0);
++ eth16i_initialize(dev, 0);
+
+ /* Set the transmit buffer size */
+ lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
+
+ if(eth16i_debug > 0)
+- printk(KERN_DEBUG "%s: transmit buffer size %d\n",
++ printk(KERN_DEBUG "%s: transmit buffer size %d\n",
+ dev->name, lp->tx_buf_size);
+
+ /* Now enable Transmitter and Receiver sections */
+@@ -981,7 +981,7 @@ static int eth16i_open(struct net_device
+ lp->tx_queue_len = 0;
+
+ /* Turn on interrupts*/
+- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
++ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+
+ netif_start_queue(dev);
+ return 0;
+@@ -995,10 +995,10 @@ static int eth16i_close(struct net_devic
+ eth16i_reset(dev);
+
+ /* Turn off interrupts*/
+- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
++ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+ netif_stop_queue(dev);
+-
++
+ lp->open_time = 0;
+
+ /* Disable transmit and receive */
+@@ -1007,7 +1007,7 @@ static int eth16i_close(struct net_devic
+ /* Reset the chip */
+ /* outb(0xff, ioaddr + RESET); */
+ /* outw(0xffff, ioaddr + TX_STATUS_REG); */
+-
++
+ outb(0x00, ioaddr + CONFIG_REG_1);
+
+ return 0;
+@@ -1017,26 +1017,26 @@ static void eth16i_timeout(struct net_de
+ {
+ struct eth16i_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+- /*
+- If we get here, some higher level has decided that
+- we are broken. There should really be a "kick me"
+- function call instead.
++ /*
++ If we get here, some higher level has decided that
++ we are broken. There should really be a "kick me"
++ function call instead.
+ */
+
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+- printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
++ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ dev->name,
+- inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
++ inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ "IRQ conflict" : "network cable problem");
+
+ dev->trans_start = jiffies;
+
+ /* Let's dump all registers */
+- if(eth16i_debug > 0) {
++ if(eth16i_debug > 0) {
+ printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+- dev->name, inb(ioaddr + 0),
+- inb(ioaddr + 1), inb(ioaddr + 2),
+- inb(ioaddr + 3), inb(ioaddr + 4),
++ dev->name, inb(ioaddr + 0),
++ inb(ioaddr + 1), inb(ioaddr + 2),
++ inb(ioaddr + 3), inb(ioaddr + 4),
+ inb(ioaddr + 5),
+ inb(ioaddr + 6), inb(ioaddr + 7));
+
+@@ -1071,31 +1071,31 @@ static int eth16i_tx(struct sk_buff *skb
+ buf = skb->data;
+
+ netif_stop_queue(dev);
+-
++
+ /* Turn off TX interrupts */
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+-
++
+ /* We would be better doing the disable_irq tricks the 3c509 does,
+ that would make this suck a lot less */
+-
++
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+- if(eth16i_debug > 0)
+- printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+- }
++ if(eth16i_debug > 0)
++ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
++ }
+ else {
+ outw(length, ioaddr + DATAPORT);
+
+- if( ioaddr < 0x1000 )
++ if( ioaddr < 0x1000 )
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+ else {
+ unsigned char frag = length % 4;
+ outsl(ioaddr + DATAPORT, buf, length >> 2);
+ if( frag != 0 ) {
+ outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+- if( frag == 3 )
+- outsw(ioaddr + DATAPORT,
++ if( frag == 3 )
++ outsw(ioaddr + DATAPORT,
+ (buf + (length & 0xFFFC) + 2), 1);
+ }
+ }
+@@ -1119,9 +1119,9 @@ static int eth16i_tx(struct sk_buff *skb
+ /* There is still more room for one more packet in tx buffer */
+ netif_wake_queue(dev);
+ }
+-
++
+ spin_unlock_irqrestore(&lp->lock, flags);
+-
++
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ /* Turn TX interrupts back on */
+ /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
+@@ -1139,36 +1139,36 @@ static void eth16i_rx(struct net_device
+ /* Loop until all packets have been read */
+ while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
+
+- /* Read status byte from receive buffer */
++ /* Read status byte from receive buffer */
+ ushort status = inw(ioaddr + DATAPORT);
+
+ /* Get the size of the packet from receive buffer */
+ ushort pkt_len = inw(ioaddr + DATAPORT);
+
+ if(eth16i_debug > 4)
+- printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
+- dev->name,
++ printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
++ dev->name,
+ inb(ioaddr + RECEIVE_MODE_REG), status);
+-
++
+ if( !(status & PKT_GOOD) ) {
+ lp->stats.rx_errors++;
+
+ if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
+ lp->stats.rx_length_errors++;
+ eth16i_reset(dev);
+- return;
++ return;
+ }
+- else {
++ else {
+ eth16i_skip_packet(dev);
+ lp->stats.rx_dropped++;
+- }
++ }
+ }
+ else { /* Ok so now we should have a good packet */
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(pkt_len + 3);
+ if( skb == NULL ) {
+- printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
++ printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
+ dev->name, pkt_len);
+ eth16i_skip_packet(dev);
+ lp->stats.rx_dropped++;
+@@ -1177,17 +1177,17 @@ static void eth16i_rx(struct net_device
+
+ skb->dev = dev;
+ skb_reserve(skb,2);
+-
+- /*
++
++ /*
+ Now let's get the packet out of buffer.
+ size is (pkt_len + 1) >> 1, cause we are now reading words
+ and it have to be even aligned.
+- */
+-
+- if(ioaddr < 0x1000)
+- insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
++ */
++
++ if(ioaddr < 0x1000)
++ insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
+ (pkt_len + 1) >> 1);
+- else {
++ else {
+ unsigned char *buf = skb_put(skb, pkt_len);
+ unsigned char frag = pkt_len % 4;
+
+@@ -1207,9 +1207,9 @@ static void eth16i_rx(struct net_device
+
+ if( eth16i_debug > 5 ) {
+ int i;
+- printk(KERN_DEBUG "%s: Received packet of length %d.\n",
++ printk(KERN_DEBUG "%s: Received packet of length %d.\n",
+ dev->name, pkt_len);
+- for(i = 0; i < 14; i++)
++ for(i = 0; i < 14; i++)
+ printk(KERN_DEBUG " %02x", skb->data[i]);
+ printk(KERN_DEBUG ".\n");
+ }
+@@ -1226,7 +1226,7 @@ static void eth16i_rx(struct net_device
+ } /* while */
+ }
+
+-static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct eth16i_local *lp;
+@@ -1255,7 +1255,7 @@ static irqreturn_t eth16i_interrupt(int
+
+ lp->stats.rx_errors++;
+
+- if(status & (BUS_RD_ERR << 8) )
++ if(status & (BUS_RD_ERR << 8) )
+ printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
+ if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++;
+ if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++;
+@@ -1269,14 +1269,14 @@ static irqreturn_t eth16i_interrupt(int
+ if(status & CR_LOST) lp->stats.tx_carrier_errors++;
+ if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
+
+-#if 0
++#if 0
+ if(status & COLLISION) {
+- lp->stats.collisions +=
++ lp->stats.collisions +=
+ ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
+ }
+ #endif
+ if(status & COLLISIONS_16) {
+- if(lp->col_16 < MAX_COL_16) {
++ if(lp->col_16 < MAX_COL_16) {
+ lp->col_16++;
+ lp->stats.collisions++;
+ /* Resume transmitting, skip failed packet */
+@@ -1293,7 +1293,7 @@ static irqreturn_t eth16i_interrupt(int
+ if(status & TX_DONE) { /* The transmit has been done */
+ lp->stats.tx_packets = lp->tx_buffered_packets;
+ lp->stats.tx_bytes += lp->tx_buffered_bytes;
+- lp->col_16 = 0;
++ lp->col_16 = 0;
+
+ if(lp->tx_queue) { /* Is there still packets ? */
+ /* There was packet(s) so start transmitting and write also
+@@ -1310,26 +1310,26 @@ static irqreturn_t eth16i_interrupt(int
+ }
+ }
+
+- if( ( status & 0x8000 ) ||
++ if( ( status & 0x8000 ) ||
+ ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
+ eth16i_rx(dev); /* We have packet in receive buffer */
+- }
+-
++ }
++
+ /* Turn interrupts back on */
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+-
++
+ if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+ /* There is still more room for one more packet in tx buffer */
+ netif_wake_queue(dev);
+ }
+-
++
+ spin_unlock(&lp->lock);
+-
++
+ return IRQ_RETVAL(handled);
+ }
+
+ static void eth16i_skip_packet(struct net_device *dev)
+-{
++{
+ int ioaddr = dev->base_addr;
+
+ inw(ioaddr + DATAPORT);
+@@ -1345,28 +1345,28 @@ static void eth16i_reset(struct net_devi
+ struct eth16i_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+- if(eth16i_debug > 1)
++ if(eth16i_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
+
+ BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+- outw(0xffff, ioaddr + TX_STATUS_REG);
++ outw(0xffff, ioaddr + TX_STATUS_REG);
+ eth16i_select_regbank(2, ioaddr);
+
+ lp->tx_started = 0;
+ lp->tx_buf_busy = 0;
+ lp->tx_queue = 0;
+- lp->tx_queue_len = 0;
++ lp->tx_queue_len = 0;
+ BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+ }
+
+ static void eth16i_multicast(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+-
+- if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
++
++ if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+ {
+ dev->flags|=IFF_PROMISC; /* Must do this */
+- outb(3, ioaddr + RECEIVE_MODE_REG);
++ outb(3, ioaddr + RECEIVE_MODE_REG);
+ } else {
+ outb(2, ioaddr + RECEIVE_MODE_REG);
+ }
+@@ -1383,7 +1383,7 @@ static void eth16i_select_regbank(unsign
+ unsigned char data;
+
+ data = inb(ioaddr + CONFIG_REG_1);
+- outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
++ outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
+ }
+
+ #ifdef MODULE
+@@ -1392,7 +1392,7 @@ static ushort eth16i_parse_mediatype(con
+ {
+ if(!s)
+ return E_PORT_FROM_EPROM;
+-
++
+ if (!strncmp(s, "bnc", 3))
+ return E_PORT_BNC;
+ else if (!strncmp(s, "tp", 2))
+@@ -1474,14 +1474,14 @@ int __init init_module(void)
+ return 0;
+ return -ENXIO;
+ }
+-
++
+ void cleanup_module(void)
+ {
+ int this_dev;
+
+ for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
+ struct net_device *dev = dev_eth16i[this_dev];
+-
++
+ if(dev->priv) {
+ unregister_netdev(dev);
+ free_irq(dev->irq, dev);
+diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
+index b987f94..c8c41f0 100644
+--- a/drivers/net/ewrk3.c
++++ b/drivers/net/ewrk3.c
+@@ -300,13 +300,13 @@ struct ewrk3_private {
+ */
+ static int ewrk3_open(struct net_device *dev);
+ static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
+ static int ewrk3_close(struct net_device *dev);
+ static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops ethtool_ops_203;
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops_203;
++static const struct ethtool_ops ethtool_ops;
+
+ /*
+ ** Private functions
+@@ -359,13 +359,13 @@ struct net_device * __init ewrk3_probe(i
+ SET_MODULE_OWNER(dev);
+
+ err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
+- if (err)
++ if (err)
+ goto out;
+ return dev;
+ out:
+ free_netdev(dev);
+ return ERR_PTR(err);
+-
++
+ }
+ #endif
+
+@@ -378,7 +378,7 @@ static int __init ewrk3_probe1(struct ne
+
+ /* Address PROM pattern */
+ err = isa_probe(dev, iobase);
+- if (err != 0)
++ if (err != 0)
+ err = eisa_probe(dev, iobase);
+
+ if (err)
+@@ -391,7 +391,7 @@ static int __init ewrk3_probe1(struct ne
+ return err;
+ }
+
+-static int __init
++static int __init
+ ewrk3_hw_init(struct net_device *dev, u_long iobase)
+ {
+ struct ewrk3_private *lp;
+@@ -435,19 +435,19 @@ ewrk3_hw_init(struct net_device *dev, u_
+ printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
+ return -ENXIO;
+ }
+-
++
+ EthwrkSignature(name, eeprom_image);
+- if (*name == '\0')
++ if (*name == '\0')
+ return -ENXIO;
+
+ dev->base_addr = iobase;
+-
++
+ if (iobase > 0x400) {
+ outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */
+ }
+ lemac = eeprom_image[EEPROM_CHIPVER];
+ cmr = inb(EWRK3_CMR);
+-
++
+ if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) ||
+ ((lemac == LeMAC2) && !(cmr & CMR_HS))) {
+ printk("%s: %s at %#4lx", dev->name, name, iobase);
+@@ -468,7 +468,7 @@ ewrk3_hw_init(struct net_device *dev, u_
+ printk("%2.2x:", dev->dev_addr[i]);
+ }
+ printk("%2.2x,\n", dev->dev_addr[i]);
+-
++
+ if (status) {
+ printk(" which has an EEPROM CRC error.\n");
+ return -ENXIO;
+@@ -490,7 +490,7 @@ ewrk3_hw_init(struct net_device *dev, u_
+ if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)
+ cmr |= CMR_DRAM;
+ outb(cmr, EWRK3_CMR);
+-
++
+ cr = inb(EWRK3_CR); /* Set up the Control Register */
+ cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
+ if (cr & SETUP_APD)
+@@ -524,7 +524,7 @@ ewrk3_hw_init(struct net_device *dev, u_
+ ** uncommenting this line.
+ */
+ /* FORCE_2K_MODE; */
+-
++
+ if (hard_strapped) {
+ printk(" is hard strapped.\n");
+ } else if (mem_start) {
+@@ -544,44 +544,44 @@ ewrk3_hw_init(struct net_device *dev, u_
+ lp->hard_strapped = hard_strapped;
+ lp->led_mask = CR_LED;
+ spin_lock_init(&lp->hw_lock);
+-
++
+ lp->mPage = 64;
+ if (cmr & CMR_DRAM)
+ lp->mPage <<= 1; /* 2 DRAMS on module */
+-
++
+ sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
+-
++
+ lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM;
+-
++
+ if (!hard_strapped) {
+ /*
+ ** Enable EWRK3 board interrupts for autoprobing
+ */
+ icr |= ICR_IE; /* Enable interrupts */
+ outb(icr, EWRK3_ICR);
+-
++
+ /* The DMA channel may be passed in on this parameter. */
+ dev->dma = 0;
+-
++
+ /* To auto-IRQ we enable the initialization-done and DMA err,
+ interrupts. For now we will always get a DMA error. */
+ if (dev->irq < 2) {
+ #ifndef MODULE
+ u_char irqnum;
+ unsigned long irq_mask;
+-
++
+
+ irq_mask = probe_irq_on();
+-
++
+ /*
+ ** Trigger a TNE interrupt.
+ */
+ icr |= ICR_TNEM;
+ outb(1, EWRK3_TDQ); /* Write to the TX done queue */
+ outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */
+-
++
+ irqnum = irq[((icr & IRQ_SEL) >> 4)];
+-
++
+ mdelay(20);
+ dev->irq = probe_irq_off(irq_mask);
+ if ((dev->irq) && (irqnum == dev->irq)) {
+@@ -622,12 +622,12 @@ ewrk3_hw_init(struct net_device *dev, u_
+ SET_ETHTOOL_OPS(dev, ðtool_ops);
+ dev->tx_timeout = ewrk3_timeout;
+ dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
+-
++
+ dev->mem_start = 0;
+
+ return 0;
+ }
+-
++
+
+ static int ewrk3_open(struct net_device *dev)
+ {
+@@ -732,14 +732,14 @@ static void ewrk3_init(struct net_device
+ /*
+ * Transmit timeout
+ */
+-
++
+ static void ewrk3_timeout(struct net_device *dev)
+ {
+ struct ewrk3_private *lp = netdev_priv(dev);
+ u_char icr, csr;
+ u_long iobase = dev->base_addr;
+-
+- if (!lp->hard_strapped)
++
++ if (!lp->hard_strapped)
+ {
+ printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
+ dev->name, inb(EWRK3_CSR));
+@@ -884,7 +884,7 @@ err_out:
+ /*
+ ** The EWRK3 interrupt handler.
+ */
+-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ewrk3_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct ewrk3_private *lp;
+@@ -1108,7 +1108,7 @@ static int ewrk3_close(struct net_device
+ u_char icr, csr;
+
+ netif_stop_queue(dev);
+-
++
+ if (ewrk3_debug > 1) {
+ printk("%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inb(EWRK3_CSR));
+@@ -1666,14 +1666,14 @@ static int ewrk3_phys_id(struct net_devi
+ return signal_pending(current) ? -ERESTARTSYS : 0;
+ }
+
+-static struct ethtool_ops ethtool_ops_203 = {
++static const struct ethtool_ops ethtool_ops_203 = {
+ .get_drvinfo = ewrk3_get_drvinfo,
+ .get_settings = ewrk3_get_settings,
+ .set_settings = ewrk3_set_settings,
+ .phys_id = ewrk3_phys_id,
+ };
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = ewrk3_get_drvinfo,
+ .get_settings = ewrk3_get_settings,
+ .set_settings = ewrk3_set_settings,
+@@ -1697,7 +1697,7 @@ static int ewrk3_ioctl(struct net_device
+ u_char addr[HASH_TABLE_LEN * ETH_ALEN];
+ u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+ };
+-
++
+ union ewrk3_addr *tmp;
+
+ /* All we handle are private IOCTLs */
+@@ -1717,7 +1717,7 @@ static int ewrk3_ioctl(struct net_device
+ if (copy_to_user(ioc->data, tmp->addr, ioc->len))
+ status = -EFAULT;
+ break;
+-
++
+ case EWRK3_SET_HWADDR: /* Set the hardware address */
+ if (capable(CAP_NET_ADMIN)) {
+ spin_lock_irqsave(&lp->hw_lock, flags);
+@@ -1990,7 +1990,7 @@ module_init(ewrk3_init_module);
+ #endif /* MODULE */
+ MODULE_LICENSE("GPL");
+
+-
++
+
+ /*
+ * Local variables:
+diff --git a/drivers/net/ewrk3.h b/drivers/net/ewrk3.h
+index fb74bd0..8e0ee90 100644
+--- a/drivers/net/ewrk3.h
++++ b/drivers/net/ewrk3.h
+@@ -63,7 +63,7 @@
+ */
+ #define CSR_RA 0x80 /* Runt Accept */
+ #define CSR_PME 0x40 /* Promiscuous Mode Enable */
+-#define CSR_MCE 0x20 /* Multicast Enable */
++#define CSR_MCE 0x20 /* Multicast Enable */
+ #define CSR_TNE 0x08 /* TX Done Queue Not Empty */
+ #define CSR_RNE 0x04 /* RX Queue Not Empty */
+ #define CSR_TXD 0x02 /* TX Disable */
+@@ -127,7 +127,7 @@
+ #define CMR_DRAM 0x02 /* 0-> 1DRAM, 1-> 2 DRAM on board */
+ #define CMR_0WS 0x01 /* Zero Wait State */
+
+-/*
++/*
+ ** MAC Receive Status Register bit definitions
+ */
+
+@@ -138,7 +138,7 @@
+ #define R_CRC 0x02 /* CRC error */
+ #define R_PLL 0x01 /* Phase Lock Lost */
+
+-/*
++/*
+ ** MAC Transmit Control Register bit definitions
+ */
+
+@@ -150,7 +150,7 @@
+ #define TCR_IFC 0x02 /* Insert Frame Check */
+ #define TCR_ISA 0x01 /* Insert Source Address */
+
+-/*
++/*
+ ** MAC Transmit Status Register bit definitions
+ */
+
+@@ -168,15 +168,15 @@
+ #define T_XUR 0x03 /* Excessive Underruns */
+ #define T_TXE 0x7f /* TX Errors */
+
+-/*
+-** EISA Configuration Register bit definitions
++/*
++** EISA Configuration Register bit definitions
+ */
+
+-#define EISA_ID iobase + 0x0c80 /* EISA ID Registers */
+-#define EISA_ID0 iobase + 0x0c80 /* EISA ID Register 0 */
+-#define EISA_ID1 iobase + 0x0c81 /* EISA ID Register 1 */
+-#define EISA_ID2 iobase + 0x0c82 /* EISA ID Register 2 */
+-#define EISA_ID3 iobase + 0x0c83 /* EISA ID Register 3 */
++#define EISA_ID iobase + 0x0c80 /* EISA ID Registers */
++#define EISA_ID0 iobase + 0x0c80 /* EISA ID Register 0 */
++#define EISA_ID1 iobase + 0x0c81 /* EISA ID Register 1 */
++#define EISA_ID2 iobase + 0x0c82 /* EISA ID Register 2 */
++#define EISA_ID3 iobase + 0x0c83 /* EISA ID Register 3 */
+ #define EISA_CR iobase + 0x0c84 /* EISA Control Register */
+
+ /*
+@@ -223,7 +223,7 @@
+ /*
+ ** EEPROM MISCELLANEOUS FLAGS
+ */
+-#define RBE_SHADOW 0x0100 /* Remote Boot Enable Shadow */
++#define RBE_SHADOW 0x0100 /* Remote Boot Enable Shadow */
+ #define READ_AHEAD 0x0080 /* Read Ahead feature */
+ #define IRQ_SEL2 0x0070 /* IRQ line selection (LeMAC2) */
+ #define IRQ_SEL 0x0060 /* IRQ line selection */
+@@ -242,7 +242,7 @@
+ /*
+ ** EEPROM SW FLAGS
+ */
+-#define SW_SQE 0x10 /* Signal Quality Error */
++#define SW_SQE 0x10 /* Signal Quality Error */
+ #define SW_LAB 0x08 /* Less Aggressive Backoff */
+ #define SW_INIT 0x04 /* Initialized */
+ #define SW_TIMEOUT 0x02 /* 0:2.5 mins, 1: 30 secs */
+@@ -299,8 +299,8 @@ struct ewrk3_ioctl {
+ unsigned char __user *data; /* Pointer to the data buffer */
+ };
+
+-/*
+-** Recognised commands for the driver
++/*
++** Recognised commands for the driver
+ */
+ #define EWRK3_GET_HWADDR 0x01 /* Get the hardware address */
+ #define EWRK3_SET_HWADDR 0x02 /* Get the hardware address */
+diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
+index 567e274..38a13f4 100644
+--- a/drivers/net/fealnx.c
++++ b/drivers/net/fealnx.c
+@@ -25,8 +25,8 @@
+ */
+
+ #define DRV_NAME "fealnx"
+-#define DRV_VERSION "2.51"
+-#define DRV_RELDATE "Nov-17-2001"
++#define DRV_VERSION "2.52"
++#define DRV_RELDATE "Sep-11-2006"
+
+ static int debug; /* 1-> print debug message */
+ static int max_interrupt_work = 20;
+@@ -434,13 +434,13 @@ static void reset_timer(unsigned long da
+ static void tx_timeout(struct net_device *dev);
+ static void init_ring(struct net_device *dev);
+ static int start_tx(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t intr_handler(int irq, void *dev_instance);
+ static int netdev_rx(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+ static void __set_rx_mode(struct net_device *dev);
+ static struct net_device_stats *get_stats(struct net_device *dev);
+ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static int netdev_close(struct net_device *dev);
+ static void reset_rx_descriptors(struct net_device *dev);
+ static void reset_tx_descriptors(struct net_device *dev);
+@@ -486,23 +486,23 @@ static int __devinit fealnx_init_one(str
+ #else
+ int bar = 1;
+ #endif
+-
++
+ /* when built into the kernel, we only print version if device is found */
+ #ifndef MODULE
+ static int printed_version;
+ if (!printed_version++)
+ printk(version);
+ #endif
+-
++
+ card_idx++;
+ sprintf(boardname, "fealnx%d", card_idx);
+-
++
+ option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+
+ i = pci_enable_device(pdev);
+ if (i) return i;
+ pci_set_master(pdev);
+-
++
+ len = pci_resource_len(pdev, bar);
+ if (len < MIN_REGION_SIZE) {
+ dev_err(&pdev->dev,
+@@ -513,7 +513,7 @@ static int __devinit fealnx_init_one(str
+ i = pci_request_regions(pdev, boardname);
+ if (i)
+ return i;
+-
++
+ irq = pdev->irq;
+
+ ioaddr = pci_iomap(pdev, bar, len);
+@@ -660,7 +660,7 @@ static int __devinit fealnx_init_one(str
+ dev->ethtool_ops = &netdev_ethtool_ops;
+ dev->tx_timeout = &tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+-
++
+ err = register_netdev(dev);
+ if (err)
+ goto err_out_free_tx;
+@@ -865,25 +865,25 @@ static int netdev_open(struct net_device
+ Tx and Rx queues and the address filter list.
+ FIXME (Ueimor): optimistic for alpha + posted writes ? */
+ #if defined(__powerpc__) || defined(__sparc__)
+-// 89/9/1 modify,
++// 89/9/1 modify,
+ // np->bcrvalue=0x04 | 0x0x38; /* big-endian, 256 burst length */
+ np->bcrvalue = 0x04 | 0x10; /* big-endian, tx 8 burst length */
+ np->crvalue = 0xe00; /* rx 128 burst length */
+ #elif defined(__alpha__) || defined(__x86_64__)
+-// 89/9/1 modify,
++// 89/9/1 modify,
+ // np->bcrvalue=0x38; /* little-endian, 256 burst length */
+ np->bcrvalue = 0x10; /* little-endian, 8 burst length */
+ np->crvalue = 0xe00; /* rx 128 burst length */
+ #elif defined(__i386__)
+ #if defined(MODULE)
+-// 89/9/1 modify,
++// 89/9/1 modify,
+ // np->bcrvalue=0x38; /* little-endian, 256 burst length */
+ np->bcrvalue = 0x10; /* little-endian, 8 burst length */
+ np->crvalue = 0xe00; /* rx 128 burst length */
+ #else
+ /* When not a module we can work around broken '486 PCI boards. */
+ #define x86 boot_cpu_data.x86
+-// 89/9/1 modify,
++// 89/9/1 modify,
+ // np->bcrvalue=(x86 <= 4 ? 0x10 : 0x38);
+ np->bcrvalue = 0x10;
+ np->crvalue = (x86 <= 4 ? 0xa00 : 0xe00);
+@@ -1160,7 +1160,7 @@ static void reset_and_disable_rxtx(struc
+ /* Reset the chip to erase previous misconfiguration. */
+ iowrite32(0x00000001, ioaddr + BCR);
+
+- /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
++ /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
+ We surely wait too long (address+data phase). Who cares? */
+ while (--delay) {
+ ioread32(ioaddr + BCR);
+@@ -1213,7 +1213,7 @@ static void reset_timer(unsigned long da
+ reset_tx_descriptors(dev); */
+ enable_rxtx(dev);
+ netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */
+-
++
+ np->reset_timer_armed = 0;
+
+ spin_unlock_irqrestore(&np->lock, flags);
+@@ -1239,7 +1239,7 @@ static void tx_timeout(struct net_device
+ printk(" %4.4x", np->tx_ring[i].status);
+ printk("\n");
+ }
+-
++
+ spin_lock_irqsave(&np->lock, flags);
+
+ reset_and_disable_rxtx(dev);
+@@ -1453,7 +1453,7 @@ static void reset_rx_descriptors(struct
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t intr_handler(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct netdev_private *np = netdev_priv(dev);
+@@ -1509,7 +1509,7 @@ static irqreturn_t intr_handler(int irq,
+ stop_nic_rx(ioaddr, np->crvalue);
+ reset_rx_descriptors(dev);
+ iowrite32(np->crvalue, ioaddr + TCRRCR);
+- }
++ }
+ }
+
+ while (np->really_tx_count) {
+@@ -1571,7 +1571,7 @@ static irqreturn_t intr_handler(int irq,
+ }
+ num_tx++;
+ } /* end of for loop */
+-
++
+ if (num_tx && np->free_tx_count >= 2)
+ netif_wake_queue(dev);
+
+@@ -1728,7 +1728,7 @@ static int netdev_rx(struct net_device *
+ /* Call copy + cksum if available. */
+
+ #if ! defined(__alpha__)
+- eth_copy_and_sum(skb,
++ eth_copy_and_sum(skb,
+ np->cur_rx->skbuff->data, pkt_len, 0);
+ skb_put(skb, pkt_len);
+ #else
+@@ -1800,8 +1800,6 @@ static void __set_rx_mode(struct net_dev
+ u32 rx_mode;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM;
+ } else if ((dev->mc_count > multicast_filter_limit)
+@@ -1887,7 +1885,7 @@ static void netdev_set_msglevel(struct n
+ debug = value;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_settings = netdev_get_settings,
+ .set_settings = netdev_set_settings,
+@@ -1984,7 +1982,7 @@ static int __init fealnx_init(void)
+ printk(version);
+ #endif
+
+- return pci_module_init(&fealnx_driver);
++ return pci_register_driver(&fealnx_driver);
+ }
+
+ static void __exit fealnx_exit(void)
+diff --git a/drivers/net/fec.c b/drivers/net/fec.c
+index 9b40300..6764281 100644
+--- a/drivers/net/fec.c
++++ b/drivers/net/fec.c
+@@ -229,7 +229,7 @@ struct fec_enet_private {
+ static int fec_enet_open(struct net_device *dev);
+ static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static void fec_enet_mii(struct net_device *dev);
+-static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
++static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
+ static void fec_enet_tx(struct net_device *dev);
+ static void fec_enet_rx(struct net_device *dev);
+ static int fec_enet_close(struct net_device *dev);
+@@ -256,7 +256,7 @@ static mii_list_t *mii_free;
+ static mii_list_t *mii_head;
+ static mii_list_t *mii_tail;
+
+-static int mii_queue(struct net_device *dev, int request,
++static int mii_queue(struct net_device *dev, int request,
+ void (*func)(uint, struct net_device *));
+
+ /* Make MII read/write commands for the FEC.
+@@ -277,7 +277,7 @@ static int mii_queue(struct net_device *
+ #define MII_REG_SR 1 /* Status Register */
+ #define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */
+ #define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */
+-#define MII_REG_ANAR 4 /* A-N Advertisement Register */
++#define MII_REG_ANAR 4 /* A-N Advertisement Register */
+ #define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */
+ #define MII_REG_ANER 6 /* A-N Expansion Register */
+ #define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */
+@@ -289,18 +289,18 @@ static int mii_queue(struct net_device *
+ #define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */
+ #define PHY_CONF_SPMASK 0x00f0 /* mask for speed */
+ #define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */
+-#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */
++#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */
+ #define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */
+-#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */
++#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */
+
+ #define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */
+ #define PHY_STAT_FAULT 0x0200 /* 1 remote fault */
+ #define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */
+ #define PHY_STAT_SPMASK 0xf000 /* mask for speed */
+ #define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */
+-#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */
++#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */
+ #define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */
+-#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */
++#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */
+
+
+ static int
+@@ -360,7 +360,7 @@ fec_enet_start_xmit(struct sk_buff *skb,
+
+ fep->stats.tx_bytes += skb->len;
+ fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
+-
++
+ /* Push the data cache so the CPM does not get stale memory
+ * data.
+ */
+@@ -422,7 +422,7 @@ fec_timeout(struct net_device *dev)
+ bdp = fep->tx_bd_base;
+ printk(" tx: %u buffers\n", TX_RING_SIZE);
+ for (i = 0 ; i < TX_RING_SIZE; i++) {
+- printk(" %08x: %04x %04x %08x\n",
++ printk(" %08x: %04x %04x %08x\n",
+ (uint) bdp,
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+@@ -450,7 +450,7 @@ fec_timeout(struct net_device *dev)
+ * This is called from the MPC core interrupt.
+ */
+ static irqreturn_t
+-fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++fec_enet_interrupt(int irq, void * dev_id)
+ {
+ struct net_device *dev = dev_id;
+ volatile fec_t *fecp;
+@@ -484,7 +484,7 @@ fec_enet_interrupt(int irq, void * dev_i
+ handled = 1;
+ fec_enet_mii(dev);
+ }
+-
++
+ }
+ return IRQ_RETVAL(handled);
+ }
+@@ -534,20 +534,20 @@ fec_enet_tx(struct net_device *dev)
+ */
+ if (status & BD_ENET_TX_DEF)
+ fep->stats.collisions++;
+-
++
+ /* Free the sk buffer associated with this last transmit.
+ */
+ dev_kfree_skb_any(skb);
+ fep->tx_skbuff[fep->skb_dirty] = NULL;
+ fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
+-
++
+ /* Update pointer to next buffer descriptor to be transmitted.
+ */
+ if (status & BD_ENET_TX_WRAP)
+ bdp = fep->tx_bd_base;
+ else
+ bdp++;
+-
++
+ /* Since we have freed up a buffer, the ring is no longer
+ * full.
+ */
+@@ -577,10 +577,10 @@ fec_enet_rx(struct net_device *dev)
+ struct sk_buff *skb;
+ ushort pkt_len;
+ __u8 *data;
+-
++
+ #ifdef CONFIG_M532x
+ flush_cache_all();
+-#endif
++#endif
+
+ fep = netdev_priv(dev);
+ fecp = (volatile fec_t*)dev->base_addr;
+@@ -606,7 +606,7 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+ /* Check for errors. */
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+ BD_ENET_RX_CR | BD_ENET_RX_OV)) {
+- fep->stats.rx_errors++;
++ fep->stats.rx_errors++;
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+ /* Frame too long or too short. */
+ fep->stats.rx_length_errors++;
+@@ -670,7 +670,7 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+ bdp = fep->rx_bd_base;
+ else
+ bdp++;
+-
++
+ #if 1
+ /* Doing this here will keep the FEC running while we process
+ * incoming frames. On a heavily loaded network, we should be
+@@ -708,7 +708,7 @@ fec_enet_mii(struct net_device *dev)
+ mii_reg = ep->fec_mii_data;
+
+ spin_lock(&fep->lock);
+-
++
+ if ((mip = mii_head) == NULL) {
+ printk("MII and no head!\n");
+ goto unlock;
+@@ -886,14 +886,14 @@ static phy_cmd_t const phy_cmd_lxt970_sh
+ { mk_mii_end, }
+ };
+ static phy_info_t const phy_info_lxt970 = {
+- .id = 0x07810000,
++ .id = 0x07810000,
+ .name = "LXT970",
+ .config = phy_cmd_lxt970_config,
+ .startup = phy_cmd_lxt970_startup,
+ .ack_int = phy_cmd_lxt970_ack_int,
+ .shutdown = phy_cmd_lxt970_shutdown
+ };
+-
++
+ /* ------------------------------------------------------------------------- */
+ /* The Level one LXT971 is used on some of my custom boards */
+
+@@ -906,7 +906,7 @@ static phy_info_t const phy_info_lxt970
+ #define MII_LXT971_LCR 20 /* LED Control Register */
+ #define MII_LXT971_TCR 30 /* Transmit Control Register */
+
+-/*
++/*
+ * I had some nice ideas of running the MDIO faster...
+ * The 971 should support 8MHz and I tried it, but things acted really
+ * weird, so 2.5 MHz ought to be enough for anyone...
+@@ -944,9 +944,9 @@ static void mii_parse_lxt971_sr2(uint mi
+
+ *s = status;
+ }
+-
++
+ static phy_cmd_t const phy_cmd_lxt971_config[] = {
+- /* limit to 10MBit because my prototype board
++ /* limit to 10MBit because my prototype board
+ * doesn't work with 100. */
+ { mk_mii_read(MII_REG_CR), mii_parse_cr },
+ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+@@ -960,7 +960,7 @@ static phy_cmd_t const phy_cmd_lxt971_st
+ /* Somehow does the 971 tell me that the link is down
+ * the first read after power-up.
+ * read here to get a valid value in ack_int */
+- { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_end, }
+ };
+ static phy_cmd_t const phy_cmd_lxt971_ack_int[] = {
+@@ -976,7 +976,7 @@ static phy_cmd_t const phy_cmd_lxt971_sh
+ { mk_mii_end, }
+ };
+ static phy_info_t const phy_info_lxt971 = {
+- .id = 0x0001378e,
++ .id = 0x0001378e,
+ .name = "LXT971",
+ .config = phy_cmd_lxt971_config,
+ .startup = phy_cmd_lxt971_startup,
+@@ -1015,7 +1015,7 @@ static void mii_parse_qs6612_pcr(uint mi
+ }
+
+ static phy_cmd_t const phy_cmd_qs6612_config[] = {
+- /* The PHY powers up isolated on the RPX,
++ /* The PHY powers up isolated on the RPX,
+ * so send a command to allow operation.
+ */
+ { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },
+@@ -1045,7 +1045,7 @@ static phy_cmd_t const phy_cmd_qs6612_sh
+ { mk_mii_end, }
+ };
+ static phy_info_t const phy_info_qs6612 = {
+- .id = 0x00181440,
++ .id = 0x00181440,
+ .name = "QS6612",
+ .config = phy_cmd_qs6612_config,
+ .startup = phy_cmd_qs6612_startup,
+@@ -1093,7 +1093,7 @@ static phy_cmd_t const phy_cmd_am79c874_
+ static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */
+ { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
+ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+- { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_end, }
+ };
+ static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
+@@ -1135,7 +1135,7 @@ static phy_cmd_t const phy_cmd_ks8721bl_
+ static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */
+ { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
+ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+- { mk_mii_read(MII_REG_SR), mii_parse_sr },
++ { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_end, }
+ };
+ static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
+@@ -1150,7 +1150,7 @@ static phy_cmd_t const phy_cmd_ks8721bl_
+ { mk_mii_end, }
+ };
+ static phy_info_t const phy_info_ks8721bl = {
+- .id = 0x00022161,
++ .id = 0x00022161,
+ .name = "KS8721BL",
+ .config = phy_cmd_ks8721bl_config,
+ .startup = phy_cmd_ks8721bl_startup,
+@@ -1236,7 +1236,7 @@ static void
+ mii_link_interrupt(void *dev_id);
+ #else
+ static irqreturn_t
+-mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
++mii_link_interrupt(int irq, void * dev_id);
+ #endif
+ #endif
+
+@@ -1251,7 +1251,7 @@ static void __inline__ fec_request_intrs
+ static const struct idesc {
+ char *name;
+ unsigned short irq;
+- irqreturn_t (*handler)(int, void *, struct pt_regs *);
++ irq_handler_t handler;
+ } *idp, id[] = {
+ { "fec(RX)", 86, fec_enet_interrupt },
+ { "fec(TX)", 87, fec_enet_interrupt },
+@@ -1420,7 +1420,7 @@ static void __inline__ fec_request_intrs
+ {
+ volatile u16 *gpio_paspar;
+ volatile u8 *gpio_pehlpar;
+-
++
+ gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
+ gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
+ *gpio_paspar |= 0x0f00;
+@@ -1667,7 +1667,7 @@ static void __inline__ fec_request_intrs
+ /* Setup interrupt handlers. */
+ for (idp = id; idp->name; idp++) {
+ if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
+- printk("FEC: Could not allocate %s IRQ(%d)!\n",
++ printk("FEC: Could not allocate %s IRQ(%d)!\n",
+ idp->name, b+idp->irq);
+ }
+
+@@ -1856,10 +1856,10 @@ static void __inline__ fec_set_mii(struc
+ immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
+ else
+ immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
+-
++
+ /* Set MII speed to 2.5 MHz
+ */
+- fecp->fec_mii_speed = fep->phy_speed =
++ fecp->fec_mii_speed = fep->phy_speed =
+ ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;
+ }
+
+@@ -1869,7 +1869,7 @@ static void __inline__ fec_enable_phy_in
+
+ fecp = fep->hwp;
+
+- /* Enable MII command finished interrupt
++ /* Enable MII command finished interrupt
+ */
+ fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+ }
+@@ -1971,7 +1971,7 @@ static void mii_display_config(struct ne
+
+ if (status & PHY_CONF_LOOP)
+ printk(", loopback enabled");
+-
++
+ printk(".\n");
+
+ fep->sequence_done = 1;
+@@ -1993,7 +1993,7 @@ static void mii_relink(struct net_device
+
+ if (fep->link) {
+ duplex = 0;
+- if (fep->phy_status
++ if (fep->phy_status
+ & (PHY_STAT_100FDX | PHY_STAT_10FDX))
+ duplex = 1;
+ fec_restart(dev, duplex);
+@@ -2070,7 +2070,7 @@ mii_discover_phy3(uint mii_reg, struct n
+ printk(" -- %s\n", phy_info[i]->name);
+ else
+ printk(" -- unknown PHY!\n");
+-
++
+ fep->phy = phy_info[i];
+ fep->phy_id_done = 1;
+ }
+@@ -2090,7 +2090,7 @@ mii_discover_phy(uint mii_reg, struct ne
+
+ if (fep->phy_addr < 32) {
+ if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {
+-
++
+ /* Got first part of ID, now get remainder.
+ */
+ fep->phy_id = phytype << 16;
+@@ -2117,7 +2117,7 @@ static void
+ mii_link_interrupt(void *dev_id)
+ #else
+ static irqreturn_t
+-mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++mii_link_interrupt(int irq, void * dev_id)
+ #endif
+ {
+ struct net_device *dev = dev_id;
+@@ -2227,8 +2227,6 @@ static void set_multicast_list(struct ne
+ ep = fep->hwp;
+
+ if (dev->flags&IFF_PROMISC) {
+- /* Log any net taps. */
+- printk("%s: Promiscuous mode enabled.\n", dev->name);
+ ep->fec_r_cntrl |= 0x0008;
+ } else {
+
+@@ -2245,7 +2243,7 @@ static void set_multicast_list(struct ne
+ */
+ ep->fec_hash_table_high = 0;
+ ep->fec_hash_table_low = 0;
+-
++
+ dmi = dev->mc_list;
+
+ for (j = 0; j < dev->mc_count; j++, dmi = dmi->next)
+@@ -2254,7 +2252,7 @@ static void set_multicast_list(struct ne
+ */
+ if (!(dmi->dmi_addr[0] & 1))
+ continue;
+-
++
+ /* calculate crc32 value of mac address
+ */
+ crc = 0xffffffff;
+@@ -2273,7 +2271,7 @@ static void set_multicast_list(struct ne
+ which point to specific bit in he hash registers
+ */
+ hash = (crc >> (32 - HASH_BITS)) & 0x3f;
+-
++
+ if (hash > 31)
+ ep->fec_hash_table_high |= 1 << (hash - 32);
+ else
+diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
+index 282b145..8e7a56f 100644
+--- a/drivers/net/fec_8xx/fec_main.c
++++ b/drivers/net/fec_8xx/fec_main.c
+@@ -30,6 +30,7 @@
+ #include <linux/mii.h>
+ #include <linux/ethtool.h>
+ #include <linux/bitops.h>
++#include <linux/dma-mapping.h>
+
+ #include <asm/8xx_immap.h>
+ #include <asm/pgtable.h>
+@@ -37,7 +38,6 @@
+ #include <asm/irq.h>
+ #include <asm/uaccess.h>
+ #include <asm/commproc.h>
+-#include <asm/dma-mapping.h>
+
+ #include "fec_8xx.h"
+
+@@ -708,7 +708,7 @@ static void fec_enet_tx(struct net_devic
+ * This is called from the MPC core interrupt.
+ */
+ static irqreturn_t
+-fec_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++fec_enet_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct fec_enet_private *fep;
+@@ -768,7 +768,7 @@ fec_enet_interrupt(int irq, void *dev_id
+
+ /* This interrupt occurs when the PHY detects a link change. */
+ static irqreturn_t
+-fec_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++fec_mii_link_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct fec_enet_private *fep;
+@@ -1034,20 +1034,20 @@ static void fec_set_msglevel(struct net_
+ fep->msg_enable = value;
+ }
+
+-static struct ethtool_ops fec_ethtool_ops = {
+- .get_drvinfo = fec_get_drvinfo,
+- .get_regs_len = fec_get_regs_len,
+- .get_settings = fec_get_settings,
+- .set_settings = fec_set_settings,
+- .nway_reset = fec_nway_reset,
+- .get_link = ethtool_op_get_link,
+- .get_msglevel = fec_get_msglevel,
+- .set_msglevel = fec_set_msglevel,
+- .get_tx_csum = ethtool_op_get_tx_csum,
+- .set_tx_csum = ethtool_op_set_tx_csum, /* local! */
+- .get_sg = ethtool_op_get_sg,
+- .set_sg = ethtool_op_set_sg,
+- .get_regs = fec_get_regs,
++static const struct ethtool_ops fec_ethtool_ops = {
++ .get_drvinfo = fec_get_drvinfo,
++ .get_regs_len = fec_get_regs_len,
++ .get_settings = fec_get_settings,
++ .set_settings = fec_set_settings,
++ .nway_reset = fec_nway_reset,
++ .get_link = ethtool_op_get_link,
++ .get_msglevel = fec_get_msglevel,
++ .set_msglevel = fec_set_msglevel,
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = ethtool_op_set_tx_csum, /* local! */
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = ethtool_op_set_sg,
++ .get_regs = fec_get_regs,
+ };
+
+ static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
+index 11b8f1b..c5ed635 100644
+--- a/drivers/net/forcedeth.c
++++ b/drivers/net/forcedeth.c
+@@ -109,6 +109,7 @@
+ * 0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
+ * 0.55: 22 Mar 2006: Add flow control (pause frame).
+ * 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
++ * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
+ *
+ * Known bugs:
+ * We suspect that on some hardware no TX done interrupts are generated.
+@@ -120,7 +121,12 @@
+ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
+ * superfluous timer interrupts from the nic.
+ */
+-#define FORCEDETH_VERSION "0.56"
++#ifdef CONFIG_FORCEDETH_NAPI
++#define DRIVERNAPI "-NAPI"
++#else
++#define DRIVERNAPI
++#endif
++#define FORCEDETH_VERSION "0.57"
+ #define DRV_NAME "forcedeth"
+
+ #include <linux/module.h>
+@@ -262,7 +268,8 @@ enum {
+ NvRegRingSizes = 0x108,
+ #define NVREG_RINGSZ_TXSHIFT 0
+ #define NVREG_RINGSZ_RXSHIFT 16
+- NvRegUnknownTransmitterReg = 0x10c,
++ NvRegTransmitPoll = 0x10c,
++#define NVREG_TRANSMITPOLL_MAC_ADDR_REV 0x00008000
+ NvRegLinkSpeed = 0x110,
+ #define NVREG_LINKSPEED_FORCE 0x10000
+ #define NVREG_LINKSPEED_10 1000
+@@ -381,21 +388,21 @@ enum {
+
+ /* Big endian: should work, but is untested */
+ struct ring_desc {
+- u32 PacketBuffer;
+- u32 FlagLen;
++ __le32 buf;
++ __le32 flaglen;
+ };
+
+ struct ring_desc_ex {
+- u32 PacketBufferHigh;
+- u32 PacketBufferLow;
+- u32 TxVlan;
+- u32 FlagLen;
++ __le32 bufhigh;
++ __le32 buflow;
++ __le32 txvlan;
++ __le32 flaglen;
+ };
+
+-typedef union _ring_type {
++union ring_type {
+ struct ring_desc* orig;
+ struct ring_desc_ex* ex;
+-} ring_type;
++};
+
+ #define FLAG_MASK_V1 0xffff0000
+ #define FLAG_MASK_V2 0xffffc000
+@@ -536,6 +543,9 @@ typedef union _ring_type {
+ #define PHYID1_OUI_SHFT 6
+ #define PHYID2_OUI_MASK 0xfc00
+ #define PHYID2_OUI_SHFT 10
++#define PHYID2_MODEL_MASK 0x03f0
++#define PHY_MODEL_MARVELL_E3016 0x220
++#define PHY_MARVELL_E3016_INITMASK 0x0300
+ #define PHY_INIT1 0x0f000
+ #define PHY_INIT2 0x0e00
+ #define PHY_INIT3 0x01000
+@@ -653,8 +663,8 @@ static const struct nv_ethtool_str nv_et
+ };
+
+ struct register_test {
+- u32 reg;
+- u32 mask;
++ __le32 reg;
++ __le32 mask;
+ };
+
+ static const struct register_test nv_registers_test[] = {
+@@ -694,6 +704,7 @@ struct fe_priv {
+ int phyaddr;
+ int wolenabled;
+ unsigned int phy_oui;
++ unsigned int phy_model;
+ u16 gigabit;
+ int intr_test;
+
+@@ -707,13 +718,14 @@ struct fe_priv {
+ u32 vlanctl_bits;
+ u32 driver_data;
+ u32 register_size;
++ int rx_csum;
+
+ void __iomem *base;
+
+ /* rx specific fields.
+ * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
+ */
+- ring_type rx_ring;
++ union ring_type rx_ring;
+ unsigned int cur_rx, refill_rx;
+ struct sk_buff **rx_skbuff;
+ dma_addr_t *rx_dma;
+@@ -733,7 +745,7 @@ struct fe_priv {
+ /*
+ * tx specific fields.
+ */
+- ring_type tx_ring;
++ union ring_type tx_ring;
+ unsigned int next_tx, nic_tx;
+ struct sk_buff **tx_skbuff;
+ dma_addr_t *tx_dma;
+@@ -826,13 +838,13 @@ static inline void pci_push(u8 __iomem *
+
+ static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
+ {
+- return le32_to_cpu(prd->FlagLen)
++ return le32_to_cpu(prd->flaglen)
+ & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
+ }
+
+ static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
+ {
+- return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
++ return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;
+ }
+
+ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
+@@ -885,7 +897,7 @@ static void free_rings(struct net_device
+ struct fe_priv *np = get_nvpriv(dev);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- if(np->rx_ring.orig)
++ if (np->rx_ring.orig)
+ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
+ np->rx_ring.orig, np->ring_addr);
+ } else {
+@@ -1020,14 +1032,13 @@ static int mii_rw(struct net_device *dev
+ return retval;
+ }
+
+-static int phy_reset(struct net_device *dev)
++static int phy_reset(struct net_device *dev, u32 bmcr_setup)
+ {
+ struct fe_priv *np = netdev_priv(dev);
+ u32 miicontrol;
+ unsigned int tries = 0;
+
+- miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+- miicontrol |= BMCR_RESET;
++ miicontrol = BMCR_RESET | bmcr_setup;
+ if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
+ return -1;
+ }
+@@ -1052,6 +1063,16 @@ static int phy_init(struct net_device *d
+ u8 __iomem *base = get_hwbase(dev);
+ u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
+
++ /* phy errata for E3016 phy */
++ if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
++ reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
++ reg &= ~PHY_MARVELL_E3016_INITMASK;
++ if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) {
++ printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev));
++ return PHY_ERROR;
++ }
++ }
++
+ /* set advertise register */
+ reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP);
+@@ -1082,8 +1103,13 @@ static int phy_init(struct net_device *d
+ else
+ np->gigabit = 0;
+
+- /* reset the phy */
+- if (phy_reset(dev)) {
++ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
++ mii_control |= BMCR_ANENABLE;
++
++ /* reset the phy
++ * (certain phys need bmcr to be setup with reset)
++ */
++ if (phy_reset(dev, mii_control)) {
+ printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+@@ -1178,7 +1204,7 @@ static void nv_stop_tx(struct net_device
+ KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
+
+ udelay(NV_TXSTOP_DELAY2);
+- writel(0, base + NvRegUnknownTransmitterReg);
++ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+ }
+
+ static void nv_txrx_reset(struct net_device *dev)
+@@ -1258,14 +1284,14 @@ static int nv_alloc_rx(struct net_device
+ np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
++ np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
+ wmb();
+- np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
++ np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ } else {
+- np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+- np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
++ np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
++ np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+ wmb();
+- np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
++ np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ }
+ dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
+ dev->name, refill_rx);
+@@ -1277,6 +1303,16 @@ static int nv_alloc_rx(struct net_device
+ return 0;
+ }
+
++/* If rx bufs are exhausted called after 50ms to attempt to refresh */
++#ifdef CONFIG_FORCEDETH_NAPI
++static void nv_do_rx_refill(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *) data;
++
++ /* Just reschedule NAPI rx processing */
++ netif_rx_schedule(dev);
++}
++#else
+ static void nv_do_rx_refill(unsigned long data)
+ {
+ struct net_device *dev = (struct net_device *) data;
+@@ -1305,6 +1341,7 @@ static void nv_do_rx_refill(unsigned lon
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+ }
+ }
++#endif
+
+ static void nv_init_rx(struct net_device *dev)
+ {
+@@ -1315,9 +1352,9 @@ static void nv_init_rx(struct net_device
+ np->refill_rx = 0;
+ for (i = 0; i < np->rx_ring_size; i++)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+- np->rx_ring.orig[i].FlagLen = 0;
++ np->rx_ring.orig[i].flaglen = 0;
+ else
+- np->rx_ring.ex[i].FlagLen = 0;
++ np->rx_ring.ex[i].flaglen = 0;
+ }
+
+ static void nv_init_tx(struct net_device *dev)
+@@ -1328,9 +1365,9 @@ static void nv_init_tx(struct net_device
+ np->next_tx = np->nic_tx = 0;
+ for (i = 0; i < np->tx_ring_size; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+- np->tx_ring.orig[i].FlagLen = 0;
++ np->tx_ring.orig[i].flaglen = 0;
+ else
+- np->tx_ring.ex[i].FlagLen = 0;
++ np->tx_ring.ex[i].flaglen = 0;
+ np->tx_skbuff[i] = NULL;
+ np->tx_dma[i] = 0;
+ }
+@@ -1373,9 +1410,9 @@ static void nv_drain_tx(struct net_devic
+
+ for (i = 0; i < np->tx_ring_size; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+- np->tx_ring.orig[i].FlagLen = 0;
++ np->tx_ring.orig[i].flaglen = 0;
+ else
+- np->tx_ring.ex[i].FlagLen = 0;
++ np->tx_ring.ex[i].flaglen = 0;
+ if (nv_release_txskb(dev, i))
+ np->stats.tx_dropped++;
+ }
+@@ -1387,9 +1424,9 @@ static void nv_drain_rx(struct net_devic
+ int i;
+ for (i = 0; i < np->rx_ring_size; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+- np->rx_ring.orig[i].FlagLen = 0;
++ np->rx_ring.orig[i].flaglen = 0;
+ else
+- np->rx_ring.ex[i].FlagLen = 0;
++ np->rx_ring.ex[i].flaglen = 0;
+ wmb();
+ if (np->rx_skbuff[i]) {
+ pci_unmap_single(np->pci_dev, np->rx_dma[i],
+@@ -1450,17 +1487,17 @@ static int nv_start_xmit(struct sk_buff
+ np->tx_dma_len[nr] = bcnt;
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+- np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
++ np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
++ np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+ } else {
+- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+- np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
++ np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
++ np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
++ np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+ }
+ tx_flags = np->tx_flags;
+ offset += bcnt;
+ size -= bcnt;
+- } while(size);
++ } while (size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+@@ -1477,12 +1514,12 @@ static int nv_start_xmit(struct sk_buff
+ np->tx_dma_len[nr] = bcnt;
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+- np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
++ np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
++ np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+ } else {
+- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+- np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
++ np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
++ np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
++ np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+ }
+ offset += bcnt;
+ size -= bcnt;
+@@ -1491,9 +1528,9 @@ static int nv_start_xmit(struct sk_buff
+
+ /* set last fragment flag */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
++ np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
+ } else {
+- np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
++ np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
+ }
+
+ np->tx_skbuff[nr] = skb;
+@@ -1503,7 +1540,8 @@ static int nv_start_xmit(struct sk_buff
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+ else
+ #endif
+- tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
++ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
++ NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+ /* vlan tag */
+ if (np->vlangrp && vlan_tx_tag_present(skb)) {
+@@ -1512,10 +1550,10 @@ static int nv_start_xmit(struct sk_buff
+
+ /* set tx flags */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
++ np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ } else {
+- np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
+- np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
++ np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
++ np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ }
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
+@@ -1547,7 +1585,7 @@ static int nv_start_xmit(struct sk_buff
+ static void nv_tx_done(struct net_device *dev)
+ {
+ struct fe_priv *np = netdev_priv(dev);
+- u32 Flags;
++ u32 flags;
+ unsigned int i;
+ struct sk_buff *skb;
+
+@@ -1555,22 +1593,22 @@ static void nv_tx_done(struct net_device
+ i = np->nic_tx % np->tx_ring_size;
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+- Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
++ flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
+ else
+- Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
++ flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
+
+- dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
+- dev->name, np->nic_tx, Flags);
+- if (Flags & NV_TX_VALID)
++ dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
++ dev->name, np->nic_tx, flags);
++ if (flags & NV_TX_VALID)
+ break;
+ if (np->desc_ver == DESC_VER_1) {
+- if (Flags & NV_TX_LASTPACKET) {
++ if (flags & NV_TX_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+- if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
++ if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+ NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+- if (Flags & NV_TX_UNDERFLOW)
++ if (flags & NV_TX_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+- if (Flags & NV_TX_CARRIERLOST)
++ if (flags & NV_TX_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+@@ -1579,13 +1617,13 @@ static void nv_tx_done(struct net_device
+ }
+ }
+ } else {
+- if (Flags & NV_TX2_LASTPACKET) {
++ if (flags & NV_TX2_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+- if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
++ if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+ NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+- if (Flags & NV_TX2_UNDERFLOW)
++ if (flags & NV_TX2_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+- if (Flags & NV_TX2_CARRIERLOST)
++ if (flags & NV_TX2_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+@@ -1638,29 +1676,29 @@ static void nv_tx_timeout(struct net_dev
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
+ i,
+- le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
+- le32_to_cpu(np->tx_ring.orig[i].FlagLen),
+- le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
+- le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
+- le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
+- le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
+- le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
+- le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
++ le32_to_cpu(np->tx_ring.orig[i].buf),
++ le32_to_cpu(np->tx_ring.orig[i].flaglen),
++ le32_to_cpu(np->tx_ring.orig[i+1].buf),
++ le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
++ le32_to_cpu(np->tx_ring.orig[i+2].buf),
++ le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
++ le32_to_cpu(np->tx_ring.orig[i+3].buf),
++ le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
+ } else {
+ printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+ i,
+- le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
+- le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
+- le32_to_cpu(np->tx_ring.ex[i].FlagLen),
+- le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
+- le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
+- le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
+- le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
+- le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
+- le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
+- le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
+- le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
+- le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
++ le32_to_cpu(np->tx_ring.ex[i].bufhigh),
++ le32_to_cpu(np->tx_ring.ex[i].buflow),
++ le32_to_cpu(np->tx_ring.ex[i].flaglen),
++ le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
++ le32_to_cpu(np->tx_ring.ex[i+1].buflow),
++ le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
++ le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
++ le32_to_cpu(np->tx_ring.ex[i+2].buflow),
++ le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
++ le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
++ le32_to_cpu(np->tx_ring.ex[i+3].buflow),
++ le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
+ }
+ }
+ }
+@@ -1697,7 +1735,7 @@ static int nv_getlen(struct net_device *
+ int protolen; /* length as stored in the proto field */
+
+ /* 1) calculate len according to header */
+- if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
++ if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
+ protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
+ hdrlen = VLAN_HLEN;
+ } else {
+@@ -1740,13 +1778,14 @@ static int nv_getlen(struct net_device *
+ }
+ }
+
+-static void nv_rx_process(struct net_device *dev)
++static int nv_rx_process(struct net_device *dev, int limit)
+ {
+ struct fe_priv *np = netdev_priv(dev);
+- u32 Flags;
++ u32 flags;
+ u32 vlanflags = 0;
++ int count;
+
+- for (;;) {
++ for (count = 0; count < limit; ++count) {
+ struct sk_buff *skb;
+ int len;
+ int i;
+@@ -1755,18 +1794,18 @@ static void nv_rx_process(struct net_dev
+
+ i = np->cur_rx % np->rx_ring_size;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
++ flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
+ len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
+ } else {
+- Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
++ flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
+ len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
+- vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow);
++ vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
+ }
+
+- dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
+- dev->name, np->cur_rx, Flags);
++ dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
++ dev->name, np->cur_rx, flags);
+
+- if (Flags & NV_RX_AVAIL)
++ if (flags & NV_RX_AVAIL)
+ break; /* still owned by hardware, */
+
+ /*
+@@ -1780,7 +1819,7 @@ static void nv_rx_process(struct net_dev
+
+ {
+ int j;
+- dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags);
++ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+@@ -1790,30 +1829,30 @@ static void nv_rx_process(struct net_dev
+ }
+ /* look at what we actually got: */
+ if (np->desc_ver == DESC_VER_1) {
+- if (!(Flags & NV_RX_DESCRIPTORVALID))
++ if (!(flags & NV_RX_DESCRIPTORVALID))
+ goto next_pkt;
+
+- if (Flags & NV_RX_ERROR) {
+- if (Flags & NV_RX_MISSEDFRAME) {
++ if (flags & NV_RX_ERROR) {
++ if (flags & NV_RX_MISSEDFRAME) {
+ np->stats.rx_missed_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
++ if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & NV_RX_CRCERR) {
++ if (flags & NV_RX_CRCERR) {
+ np->stats.rx_crc_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & NV_RX_OVERFLOW) {
++ if (flags & NV_RX_OVERFLOW) {
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & NV_RX_ERROR4) {
++ if (flags & NV_RX_ERROR4) {
+ len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+@@ -1821,32 +1860,32 @@ static void nv_rx_process(struct net_dev
+ }
+ }
+ /* framing errors are soft errors. */
+- if (Flags & NV_RX_FRAMINGERR) {
+- if (Flags & NV_RX_SUBSTRACT1) {
++ if (flags & NV_RX_FRAMINGERR) {
++ if (flags & NV_RX_SUBSTRACT1) {
+ len--;
+ }
+ }
+ }
+ } else {
+- if (!(Flags & NV_RX2_DESCRIPTORVALID))
++ if (!(flags & NV_RX2_DESCRIPTORVALID))
+ goto next_pkt;
+
+- if (Flags & NV_RX2_ERROR) {
+- if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
++ if (flags & NV_RX2_ERROR) {
++ if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & NV_RX2_CRCERR) {
++ if (flags & NV_RX2_CRCERR) {
+ np->stats.rx_crc_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & NV_RX2_OVERFLOW) {
++ if (flags & NV_RX2_OVERFLOW) {
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+- if (Flags & NV_RX2_ERROR4) {
++ if (flags & NV_RX2_ERROR4) {
+ len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+@@ -1854,17 +1893,17 @@ static void nv_rx_process(struct net_dev
+ }
+ }
+ /* framing errors are soft errors */
+- if (Flags & NV_RX2_FRAMINGERR) {
+- if (Flags & NV_RX2_SUBSTRACT1) {
++ if (flags & NV_RX2_FRAMINGERR) {
++ if (flags & NV_RX2_SUBSTRACT1) {
+ len--;
+ }
+ }
+ }
+- if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) {
+- Flags &= NV_RX2_CHECKSUMMASK;
+- if (Flags == NV_RX2_CHECKSUMOK1 ||
+- Flags == NV_RX2_CHECKSUMOK2 ||
+- Flags == NV_RX2_CHECKSUMOK3) {
++ if (np->rx_csum) {
++ flags &= NV_RX2_CHECKSUMMASK;
++ if (flags == NV_RX2_CHECKSUMOK1 ||
++ flags == NV_RX2_CHECKSUMOK2 ||
++ flags == NV_RX2_CHECKSUMOK3) {
+ dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
+ np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+@@ -1880,17 +1919,27 @@ static void nv_rx_process(struct net_dev
+ skb->protocol = eth_type_trans(skb, dev);
+ dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
+ dev->name, np->cur_rx, len, skb->protocol);
+- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) {
+- vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK);
+- } else {
++#ifdef CONFIG_FORCEDETH_NAPI
++ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
++ vlan_hwaccel_receive_skb(skb, np->vlangrp,
++ vlanflags & NV_RX3_VLAN_TAG_MASK);
++ else
++ netif_receive_skb(skb);
++#else
++ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
++ vlan_hwaccel_rx(skb, np->vlangrp,
++ vlanflags & NV_RX3_VLAN_TAG_MASK);
++ else
+ netif_rx(skb);
+- }
++#endif
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+ next_pkt:
+ np->cur_rx++;
+ }
++
++ return count;
+ }
+
+ static void set_bufsize(struct net_device *dev)
+@@ -1990,7 +2039,7 @@ static int nv_set_mac_address(struct net
+ struct fe_priv *np = netdev_priv(dev);
+ struct sockaddr *macaddr = (struct sockaddr*)addr;
+
+- if(!is_valid_ether_addr(macaddr->sa_data))
++ if (!is_valid_ether_addr(macaddr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ /* synchronized against open : rtnl_lock() held by caller */
+@@ -2032,7 +2081,6 @@ static void nv_set_multicast(struct net_
+ memset(mask, 0, sizeof(mask));
+
+ if (dev->flags & IFF_PROMISC) {
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ pff |= NVREG_PFF_PROMISC;
+ } else {
+ pff |= NVREG_PFF_MYADDR;
+@@ -2283,20 +2331,20 @@ set_speed:
+ lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
+
+ switch (adv_pause) {
+- case (ADVERTISE_PAUSE_CAP):
++ case ADVERTISE_PAUSE_CAP:
+ if (lpa_pause & LPA_PAUSE_CAP) {
+ pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
+ pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ }
+ break;
+- case (ADVERTISE_PAUSE_ASYM):
++ case ADVERTISE_PAUSE_ASYM:
+ if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
+ {
+ pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ }
+ break;
+- case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM):
++ case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
+ if (lpa_pause & LPA_PAUSE_CAP)
+ {
+ pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+@@ -2349,7 +2397,7 @@ static void nv_link_irq(struct net_devic
+ dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
+ }
+
+-static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
++static irqreturn_t nv_nic_irq(int foo, void *data)
+ {
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+@@ -2376,14 +2424,6 @@ static irqreturn_t nv_nic_irq(int foo, v
+ nv_tx_done(dev);
+ spin_unlock(&np->lock);
+
+- nv_rx_process(dev);
+- if (nv_alloc_rx(dev)) {
+- spin_lock(&np->lock);
+- if (!np->in_shutdown)
+- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+- spin_unlock(&np->lock);
+- }
+-
+ if (events & NVREG_IRQ_LINK) {
+ spin_lock(&np->lock);
+ nv_link_irq(dev);
+@@ -2403,6 +2443,29 @@ static irqreturn_t nv_nic_irq(int foo, v
+ printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+ dev->name, events);
+ }
++#ifdef CONFIG_FORCEDETH_NAPI
++ if (events & NVREG_IRQ_RX_ALL) {
++ netif_rx_schedule(dev);
++
++ /* Disable furthur receive irq's */
++ spin_lock(&np->lock);
++ np->irqmask &= ~NVREG_IRQ_RX_ALL;
++
++ if (np->msi_flags & NV_MSI_X_ENABLED)
++ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
++ else
++ writel(np->irqmask, base + NvRegIrqMask);
++ spin_unlock(&np->lock);
++ }
++#else
++ nv_rx_process(dev, dev->weight);
++ if (nv_alloc_rx(dev)) {
++ spin_lock(&np->lock);
++ if (!np->in_shutdown)
++ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
++ spin_unlock(&np->lock);
++ }
++#endif
+ if (i > max_interrupt_work) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+@@ -2427,13 +2490,14 @@ static irqreturn_t nv_nic_irq(int foo, v
+ return IRQ_RETVAL(i);
+ }
+
+-static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
++static irqreturn_t nv_nic_irq_tx(int foo, void *data)
+ {
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+ int i;
++ unsigned long flags;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name);
+
+@@ -2445,16 +2509,16 @@ static irqreturn_t nv_nic_irq_tx(int foo
+ if (!(events & np->irqmask))
+ break;
+
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ nv_tx_done(dev);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+
+ if (events & (NVREG_IRQ_TX_ERR)) {
+ dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+ dev->name, events);
+ }
+ if (i > max_interrupt_work) {
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ /* disable interrupts on the nic */
+ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
+ pci_push(base);
+@@ -2464,7 +2528,7 @@ static irqreturn_t nv_nic_irq_tx(int foo
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+ break;
+ }
+
+@@ -2474,13 +2538,71 @@ static irqreturn_t nv_nic_irq_tx(int foo
+ return IRQ_RETVAL(i);
+ }
+
+-static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
++#ifdef CONFIG_FORCEDETH_NAPI
++static int nv_napi_poll(struct net_device *dev, int *budget)
++{
++ int pkts, limit = min(*budget, dev->quota);
++ struct fe_priv *np = netdev_priv(dev);
++ u8 __iomem *base = get_hwbase(dev);
++
++ pkts = nv_rx_process(dev, limit);
++
++ if (nv_alloc_rx(dev)) {
++ spin_lock_irq(&np->lock);
++ if (!np->in_shutdown)
++ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
++ spin_unlock_irq(&np->lock);
++ }
++
++ if (pkts < limit) {
++ /* all done, no more packets present */
++ netif_rx_complete(dev);
++
++ /* re-enable receive interrupts */
++ spin_lock_irq(&np->lock);
++ np->irqmask |= NVREG_IRQ_RX_ALL;
++ if (np->msi_flags & NV_MSI_X_ENABLED)
++ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
++ else
++ writel(np->irqmask, base + NvRegIrqMask);
++ spin_unlock_irq(&np->lock);
++ return 0;
++ } else {
++ /* used up our quantum, so reschedule */
++ dev->quota -= pkts;
++ *budget -= pkts;
++ return 1;
++ }
++}
++#endif
++
++#ifdef CONFIG_FORCEDETH_NAPI
++static irqreturn_t nv_nic_irq_rx(int foo, void *data)
++{
++ struct net_device *dev = (struct net_device *) data;
++ u8 __iomem *base = get_hwbase(dev);
++ u32 events;
++
++ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
++ writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
++
++ if (events) {
++ netif_rx_schedule(dev);
++ /* disable receive interrupts on the nic */
++ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
++ pci_push(base);
++ }
++ return IRQ_HANDLED;
++}
++#else
++static irqreturn_t nv_nic_irq_rx(int foo, void *data)
+ {
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+ int i;
++ unsigned long flags;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name);
+
+@@ -2492,16 +2614,16 @@ static irqreturn_t nv_nic_irq_rx(int foo
+ if (!(events & np->irqmask))
+ break;
+
+- nv_rx_process(dev);
++ nv_rx_process(dev, dev->weight);
+ if (nv_alloc_rx(dev)) {
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+ }
+
+ if (i > max_interrupt_work) {
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ /* disable interrupts on the nic */
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ pci_push(base);
+@@ -2511,23 +2633,24 @@ static irqreturn_t nv_nic_irq_rx(int foo
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+ break;
+ }
+-
+ }
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name);
+
+ return IRQ_RETVAL(i);
+ }
++#endif
+
+-static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
++static irqreturn_t nv_nic_irq_other(int foo, void *data)
+ {
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+ int i;
++ unsigned long flags;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name);
+
+@@ -2540,14 +2663,14 @@ static irqreturn_t nv_nic_irq_other(int
+ break;
+
+ if (events & NVREG_IRQ_LINK) {
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ nv_link_irq(dev);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+ }
+ if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ nv_linkchange(dev);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+ np->link_timeout = jiffies + LINK_TIMEOUT;
+ }
+ if (events & (NVREG_IRQ_UNKNOWN)) {
+@@ -2555,7 +2678,7 @@ static irqreturn_t nv_nic_irq_other(int
+ dev->name, events);
+ }
+ if (i > max_interrupt_work) {
+- spin_lock_irq(&np->lock);
++ spin_lock_irqsave(&np->lock, flags);
+ /* disable interrupts on the nic */
+ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
+ pci_push(base);
+@@ -2565,7 +2688,7 @@ static irqreturn_t nv_nic_irq_other(int
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
+- spin_unlock_irq(&np->lock);
++ spin_unlock_irqrestore(&np->lock, flags);
+ break;
+ }
+
+@@ -2575,7 +2698,7 @@ static irqreturn_t nv_nic_irq_other(int
+ return IRQ_RETVAL(i);
+ }
+
+-static irqreturn_t nv_nic_irq_test(int foo, void *data, struct pt_regs *regs)
++static irqreturn_t nv_nic_irq_test(int foo, void *data)
+ {
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+@@ -2785,22 +2908,22 @@ static void nv_do_nic_poll(unsigned long
+ pci_push(base);
+
+ if (!using_multi_irqs(dev)) {
+- nv_nic_irq(0, dev, NULL);
++ nv_nic_irq(0, dev);
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ enable_irq_lockdep(dev->irq);
+ } else {
+ if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
+- nv_nic_irq_rx(0, dev, NULL);
++ nv_nic_irq_rx(0, dev);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+ }
+ if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
+- nv_nic_irq_tx(0, dev, NULL);
++ nv_nic_irq_tx(0, dev);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+ }
+ if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
+- nv_nic_irq_other(0, dev, NULL);
++ nv_nic_irq_other(0, dev);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+ }
+ }
+@@ -3057,9 +3180,18 @@ static int nv_set_settings(struct net_de
+ if (netif_running(dev))
+ printk(KERN_INFO "%s: link down.\n", dev->name);
+ bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+- bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+- mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+-
++ if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
++ bmcr |= BMCR_ANENABLE;
++ /* reset the phy in order for settings to stick,
++ * and cause autoneg to start */
++ if (phy_reset(dev, bmcr)) {
++ printk(KERN_INFO "%s: phy reset failed\n", dev->name);
++ return -EINVAL;
++ }
++ } else {
++ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
++ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
++ }
+ } else {
+ int adv, bmcr;
+
+@@ -3099,17 +3231,19 @@ static int nv_set_settings(struct net_de
+ bmcr |= BMCR_FULLDPLX;
+ if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL))
+ bmcr |= BMCR_SPEED100;
+- mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ if (np->phy_oui == PHY_OUI_MARVELL) {
+- /* reset the phy */
+- if (phy_reset(dev)) {
++ /* reset the phy in order for forced mode settings to stick */
++ if (phy_reset(dev, bmcr)) {
+ printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ return -EINVAL;
+ }
+- } else if (netif_running(dev)) {
+- /* Wait a bit and then reconfigure the nic. */
+- udelay(10);
+- nv_linkchange(dev);
++ } else {
++ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
++ if (netif_running(dev)) {
++ /* Wait a bit and then reconfigure the nic. */
++ udelay(10);
++ nv_linkchange(dev);
++ }
+ }
+ }
+
+@@ -3166,8 +3300,17 @@ static int nv_nway_reset(struct net_devi
+ }
+
+ bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+- bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+- mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
++ if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
++ bmcr |= BMCR_ANENABLE;
++ /* reset the phy in order for settings to stick*/
++ if (phy_reset(dev, bmcr)) {
++ printk(KERN_INFO "%s: phy reset failed\n", dev->name);
++ return -EINVAL;
++ }
++ } else {
++ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
++ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
++ }
+
+ if (netif_running(dev)) {
+ nv_start_rx(dev);
+@@ -3245,7 +3388,7 @@ static int nv_set_ringparam(struct net_d
+ if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+ /* fall back to old rings */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- if(rxtx_ring)
++ if (rxtx_ring)
+ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
+ rxtx_ring, ring_addr);
+ } else {
+@@ -3418,7 +3561,7 @@ static int nv_set_pauseparam(struct net_
+ static u32 nv_get_rx_csum(struct net_device *dev)
+ {
+ struct fe_priv *np = netdev_priv(dev);
+- return (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) != 0;
++ return (np->rx_csum) != 0;
+ }
+
+ static int nv_set_rx_csum(struct net_device *dev, u32 data)
+@@ -3428,22 +3571,15 @@ static int nv_set_rx_csum(struct net_dev
+ int retcode = 0;
+
+ if (np->driver_data & DEV_HAS_CHECKSUM) {
+-
+- if (((np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) && data) ||
+- (!(np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) && !data)) {
+- /* already set or unset */
+- return 0;
+- }
+-
+ if (data) {
++ np->rx_csum = 1;
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+- } else if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) {
+- np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
+ } else {
+- printk(KERN_INFO "Can not disable rx checksum if vlan is enabled\n");
+- return -EINVAL;
++ np->rx_csum = 0;
++ /* vlan is dependent on rx checksum offload */
++ if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE))
++ np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
+ }
+-
+ if (netif_running(dev)) {
+ spin_lock_irq(&np->lock);
+ writel(np->txrxctl_bits, base + NvRegTxRxControl);
+@@ -3481,7 +3617,7 @@ static int nv_get_stats_count(struct net
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (np->driver_data & DEV_HAS_STATISTICS)
+- return (sizeof(struct nv_ethtool_stats)/sizeof(u64));
++ return sizeof(struct nv_ethtool_stats)/sizeof(u64);
+ else
+ return 0;
+ }
+@@ -3619,7 +3755,7 @@ static int nv_loopback_test(struct net_d
+ struct sk_buff *tx_skb, *rx_skb;
+ dma_addr_t test_dma_addr;
+ u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+- u32 Flags;
++ u32 flags;
+ int len, i, pkt_len;
+ u8 *pkt_data;
+ u32 filter_flags = 0;
+@@ -3656,6 +3792,12 @@ static int nv_loopback_test(struct net_d
+ /* setup packet for tx */
+ pkt_len = ETH_DATA_LEN;
+ tx_skb = dev_alloc_skb(pkt_len);
++ if (!tx_skb) {
++ printk(KERN_ERR "dev_alloc_skb() failed during loopback test"
++ " of %s\n", dev->name);
++ ret = 0;
++ goto out;
++ }
+ pkt_data = skb_put(tx_skb, pkt_len);
+ for (i = 0; i < pkt_len; i++)
+ pkt_data[i] = (u8)(i & 0xff);
+@@ -3663,12 +3805,12 @@ static int nv_loopback_test(struct net_d
+ tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr);
+- np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
++ np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr);
++ np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ } else {
+- np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32;
+- np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+- np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
++ np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32;
++ np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
++ np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ }
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ pci_push(get_hwbase(dev));
+@@ -3677,21 +3819,21 @@ static int nv_loopback_test(struct net_d
+
+ /* check for rx of the packet */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+- Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen);
++ flags = le32_to_cpu(np->rx_ring.orig[0].flaglen);
+ len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver);
+
+ } else {
+- Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen);
++ flags = le32_to_cpu(np->rx_ring.ex[0].flaglen);
+ len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver);
+ }
+
+- if (Flags & NV_RX_AVAIL) {
++ if (flags & NV_RX_AVAIL) {
+ ret = 0;
+ } else if (np->desc_ver == DESC_VER_1) {
+- if (Flags & NV_RX_ERROR)
++ if (flags & NV_RX_ERROR)
+ ret = 0;
+ } else {
+- if (Flags & NV_RX2_ERROR) {
++ if (flags & NV_RX2_ERROR) {
+ ret = 0;
+ }
+ }
+@@ -3720,7 +3862,7 @@ static int nv_loopback_test(struct net_d
+ tx_skb->end-tx_skb->data,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(tx_skb);
+-
++ out:
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+@@ -3753,6 +3895,7 @@ static void nv_self_test(struct net_devi
+ if (test->flags & ETH_TEST_FL_OFFLINE) {
+ if (netif_running(dev)) {
+ netif_stop_queue(dev);
++ netif_poll_disable(dev);
+ netif_tx_lock_bh(dev);
+ spin_lock_irq(&np->lock);
+ nv_disable_hw_interrupts(dev, np->irqmask);
+@@ -3811,6 +3954,7 @@ static void nv_self_test(struct net_devi
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ netif_start_queue(dev);
++ netif_poll_enable(dev);
+ nv_enable_hw_interrupts(dev, np->irqmask);
+ }
+ }
+@@ -3828,7 +3972,7 @@ static void nv_get_strings(struct net_de
+ }
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = nv_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_wol = nv_get_wol,
+@@ -3895,10 +4039,9 @@ static int nv_open(struct net_device *de
+
+ dprintk(KERN_DEBUG "nv_open: begin\n");
+
+- /* 1) erase previous misconfiguration */
++ /* erase previous misconfiguration */
+ if (np->driver_data & DEV_HAS_POWER_CNTRL)
+ nv_mac_reset(dev);
+- /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
+ writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
+ writel(0, base + NvRegMulticastAddrB);
+ writel(0, base + NvRegMulticastMaskA);
+@@ -3913,26 +4056,22 @@ static int nv_open(struct net_device *de
+ if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)
+ writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame);
+
+- /* 2) initialize descriptor rings */
++ /* initialize descriptor rings */
+ set_bufsize(dev);
+ oom = nv_init_ring(dev);
+
+ writel(0, base + NvRegLinkSpeed);
+- writel(0, base + NvRegUnknownTransmitterReg);
++ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+ nv_txrx_reset(dev);
+ writel(0, base + NvRegUnknownSetupReg6);
+
+ np->in_shutdown = 0;
+
+- /* 3) set mac address */
+- nv_copy_mac_to_hw(dev);
+-
+- /* 4) give hw rings */
++ /* give hw rings */
+ setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
+ writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+
+- /* 5) continue setup */
+ writel(np->linkspeed, base + NvRegLinkSpeed);
+ if (np->desc_ver == DESC_VER_1)
+ writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark);
+@@ -3950,7 +4089,6 @@ static int nv_open(struct net_device *de
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+
+- /* 6) continue setup */
+ writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
+ writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
+ writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
+@@ -4020,6 +4158,8 @@ static int nv_open(struct net_device *de
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ netif_start_queue(dev);
++ netif_poll_enable(dev);
++
+ if (ret) {
+ netif_carrier_on(dev);
+ } else {
+@@ -4049,6 +4189,7 @@ static int nv_close(struct net_device *d
+ spin_lock_irq(&np->lock);
+ np->in_shutdown = 1;
+ spin_unlock_irq(&np->lock);
++ netif_poll_disable(dev);
+ synchronize_irq(dev->irq);
+
+ del_timer_sync(&np->oom_kick);
+@@ -4076,12 +4217,6 @@ static int nv_close(struct net_device *d
+ if (np->wolenabled)
+ nv_start_rx(dev);
+
+- /* special op: write back the misordered MAC address - otherwise
+- * the next nv_probe would see a wrong address.
+- */
+- writel(np->orig_mac[0], base + NvRegMacAddrA);
+- writel(np->orig_mac[1], base + NvRegMacAddrB);
+-
+ /* FIXME: power down nic */
+
+ return 0;
+@@ -4094,7 +4229,7 @@ static int __devinit nv_probe(struct pci
+ unsigned long addr;
+ u8 __iomem *base;
+ int err, i;
+- u32 powerstate;
++ u32 powerstate, txreg;
+
+ dev = alloc_etherdev(sizeof(struct fe_priv));
+ err = -ENOMEM;
+@@ -4190,6 +4325,7 @@ static int __devinit nv_probe(struct pci
+ np->pkt_limit = NV_PKTLIMIT_2;
+
+ if (id->driver_data & DEV_HAS_CHECKSUM) {
++ np->rx_csum = 1;
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+ #ifdef NETIF_F_TSO
+@@ -4270,6 +4406,10 @@ static int __devinit nv_probe(struct pci
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = nv_poll_controller;
+ #endif
++ dev->weight = 64;
++#ifdef CONFIG_FORCEDETH_NAPI
++ dev->poll = nv_napi_poll;
++#endif
+ SET_ETHTOOL_OPS(dev, &ops);
+ dev->tx_timeout = nv_tx_timeout;
+ dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
+@@ -4281,12 +4421,30 @@ static int __devinit nv_probe(struct pci
+ np->orig_mac[0] = readl(base + NvRegMacAddrA);
+ np->orig_mac[1] = readl(base + NvRegMacAddrB);
+
+- dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
+- dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
+- dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
+- dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
+- dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
+- dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
++ /* check the workaround bit for correct mac address order */
++ txreg = readl(base + NvRegTransmitPoll);
++ if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
++ /* mac address is already in correct order */
++ dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
++ dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
++ dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff;
++ dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
++ dev->dev_addr[4] = (np->orig_mac[1] >> 0) & 0xff;
++ dev->dev_addr[5] = (np->orig_mac[1] >> 8) & 0xff;
++ } else {
++ /* need to reverse mac address to correct order */
++ dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
++ dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
++ dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
++ dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
++ dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
++ dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
++ /* set permanent address to be correct aswell */
++ np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
++ (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
++ np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
++ writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
++ }
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ if (!is_valid_ether_addr(dev->perm_addr)) {
+@@ -4309,6 +4467,9 @@ static int __devinit nv_probe(struct pci
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
++ /* set mac address */
++ nv_copy_mac_to_hw(dev);
++
+ /* disable WOL */
+ writel(0, base + NvRegWakeUpFlags);
+ np->wolenabled = 0;
+@@ -4369,6 +4530,7 @@ static int __devinit nv_probe(struct pci
+ if (id2 < 0 || id2 == 0xffff)
+ continue;
+
++ np->phy_model = id2 & PHYID2_MODEL_MASK;
+ id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
+ id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
+ dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
+@@ -4421,9 +4583,17 @@ out:
+ static void __devexit nv_remove(struct pci_dev *pci_dev)
+ {
+ struct net_device *dev = pci_get_drvdata(pci_dev);
++ struct fe_priv *np = netdev_priv(dev);
++ u8 __iomem *base = get_hwbase(dev);
+
+ unregister_netdev(dev);
+
++ /* special op: write back the misordered MAC address - otherwise
++ * the next nv_probe would see a wrong address.
++ */
++ writel(np->orig_mac[0], base + NvRegMacAddrA);
++ writel(np->orig_mac[1], base + NvRegMacAddrB);
++
+ /* free all structures */
+ free_rings(dev);
+ iounmap(get_hwbase(dev));
+@@ -4540,7 +4710,7 @@ static struct pci_driver driver = {
+ static int __init init_nic(void)
+ {
+ printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION);
+- return pci_module_init(&driver);
++ return pci_register_driver(&driver);
+ }
+
+ static void __exit exit_nic(void)
+diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
+index df62506..cb39587 100644
+--- a/drivers/net/fs_enet/fs_enet-main.c
++++ b/drivers/net/fs_enet/fs_enet-main.c
+@@ -441,7 +441,7 @@ static void fs_enet_tx(struct net_device
+ * This is called from the MPC core interrupt.
+ */
+ static irqreturn_t
+-fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++fs_enet_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct fs_enet_private *fep;
+@@ -667,7 +667,7 @@ static int fs_enet_start_xmit(struct sk_
+ }
+
+ static int fs_request_irq(struct net_device *dev, int irq, const char *name,
+- irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs))
++ irq_handler_t irqf)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+@@ -908,7 +908,7 @@ static void fs_set_msglevel(struct net_d
+ fep->msg_enable = value;
+ }
+
+-static struct ethtool_ops fs_ethtool_ops = {
++static const struct ethtool_ops fs_ethtool_ops = {
+ .get_drvinfo = fs_get_drvinfo,
+ .get_regs_len = fs_get_regs_len,
+ .get_settings = fs_get_settings,
+@@ -944,12 +944,13 @@ extern int fs_mii_connect(struct net_dev
+ extern void fs_mii_disconnect(struct net_device *dev);
+
+ static struct net_device *fs_init_instance(struct device *dev,
+- const struct fs_platform_info *fpi)
++ struct fs_platform_info *fpi)
+ {
+ struct net_device *ndev = NULL;
+ struct fs_enet_private *fep = NULL;
+ int privsize, i, r, err = 0, registered = 0;
+
++ fpi->fs_no = fs_get_id(fpi);
+ /* guard */
+ if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX)
+ return ERR_PTR(-EINVAL);
+@@ -971,7 +972,7 @@ static struct net_device *fs_init_instan
+ dev_set_drvdata(dev, ndev);
+ fep->fpi = fpi;
+ if (fpi->init_ioports)
+- fpi->init_ioports();
++ fpi->init_ioports((struct fs_platform_info *)fpi);
+
+ #ifdef CONFIG_FS_ENET_HAS_FEC
+ if (fs_get_fec_index(fpi->fs_no) >= 0)
+diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
+index 95022c0..92590d8 100644
+--- a/drivers/net/fs_enet/fs_enet.h
++++ b/drivers/net/fs_enet/fs_enet.h
+@@ -6,11 +6,10 @@
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/phy.h>
++#include <linux/dma-mapping.h>
+
+ #include <linux/fs_enet_pd.h>
+
+-#include <asm/dma-mapping.h>
+-
+ #ifdef CONFIG_CPM1
+ #include <asm/commproc.h>
+
+diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
+index 1328e10..baaae3d 100644
+--- a/drivers/net/fs_enet/mii-fec.c
++++ b/drivers/net/fs_enet/mii-fec.c
+@@ -12,8 +12,6 @@
+ * kind, whether express or implied.
+ */
+
+-
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
+index ebbbd6c..a06d8d1 100644
+--- a/drivers/net/gianfar.c
++++ b/drivers/net/gianfar.c
+@@ -119,9 +119,9 @@ struct sk_buff *gfar_new_skb(struct net_
+ static struct net_device_stats *gfar_get_stats(struct net_device *dev);
+ 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);
+-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t gfar_error(int irq, void *dev_id);
++static irqreturn_t gfar_transmit(int irq, void *dev_id);
++static irqreturn_t gfar_interrupt(int irq, void *dev_id);
+ static void adjust_link(struct net_device *dev);
+ static void init_registers(struct net_device *dev);
+ static int init_phy(struct net_device *dev);
+@@ -143,7 +143,7 @@ void gfar_start(struct net_device *dev);
+ static void gfar_clear_exact_match(struct net_device *dev);
+ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
+
+-extern struct ethtool_ops gfar_ethtool_ops;
++extern const struct ethtool_ops gfar_ethtool_ops;
+
+ MODULE_AUTHOR("Freescale Semiconductor, Inc");
+ MODULE_DESCRIPTION("Gianfar Ethernet Driver");
+@@ -947,7 +947,7 @@ static int gfar_start_xmit(struct sk_buf
+
+ /* Set up checksumming */
+ if (likely((dev->features & NETIF_F_IP_CSUM)
+- && (CHECKSUM_HW == skb->ip_summed))) {
++ && (CHECKSUM_PARTIAL == skb->ip_summed))) {
+ fcb = gfar_add_fcb(skb, txbdp);
+ status |= TXBD_TOE;
+ gfar_tx_checksum(skb, fcb);
+@@ -1063,7 +1063,7 @@ static void gfar_vlan_rx_register(struct
+ tempval |= TCTRL_VLINS;
+
+ gfar_write(&priv->regs->tctrl, tempval);
+-
++
+ /* Enable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval |= RCTRL_VLEX;
+@@ -1173,7 +1173,7 @@ static void gfar_timeout(struct net_devi
+ }
+
+ /* Interrupt Handler for Transmit complete */
+-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t gfar_transmit(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct gfar_private *priv = netdev_priv(dev);
+@@ -1305,7 +1305,7 @@ static inline void count_errors(unsigned
+ }
+ }
+
+-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t gfar_receive(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct gfar_private *priv = netdev_priv(dev);
+@@ -1537,7 +1537,7 @@ static int gfar_poll(struct net_device *
+ #endif
+
+ /* The interrupt handler for devices with one interrupt */
+-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t gfar_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct gfar_private *priv = netdev_priv(dev);
+@@ -1550,11 +1550,11 @@ static irqreturn_t gfar_interrupt(int ir
+
+ /* Check for reception */
+ if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0))
+- gfar_receive(irq, dev_id, regs);
++ gfar_receive(irq, dev_id);
+
+ /* Check for transmit completion */
+ if ((events & IEVENT_TXF) || (events & IEVENT_TXB))
+- gfar_transmit(irq, dev_id, regs);
++ gfar_transmit(irq, dev_id);
+
+ /* Update error statistics */
+ if (events & IEVENT_TXE) {
+@@ -1578,7 +1578,7 @@ static irqreturn_t gfar_interrupt(int ir
+ priv->stats.rx_errors++;
+ priv->extra_stats.rx_bsy++;
+
+- gfar_receive(irq, dev_id, regs);
++ gfar_receive(irq, dev_id);
+
+ #ifndef CONFIG_GFAR_NAPI
+ /* Clear the halt bit in RSTAT */
+@@ -1708,9 +1708,6 @@ static void gfar_set_multi(struct net_de
+ u32 tempval;
+
+ if(dev->flags & IFF_PROMISC) {
+- if (netif_msg_drv(priv))
+- printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+- dev->name);
+ /* Set RCTRL to PROM */
+ tempval = gfar_read(®s->rctrl);
+ tempval |= RCTRL_PROM;
+@@ -1721,7 +1718,7 @@ static void gfar_set_multi(struct net_de
+ tempval &= ~(RCTRL_PROM);
+ gfar_write(®s->rctrl, tempval);
+ }
+-
++
+ if(dev->flags & IFF_ALLMULTI) {
+ /* Set the hash to rx all multicast frames */
+ gfar_write(®s->igaddr0, 0xffffffff);
+@@ -1860,7 +1857,7 @@ static void gfar_set_mac_for_addr(struct
+ }
+
+ /* GFAR error interrupt handler */
+-static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t gfar_error(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct gfar_private *priv = netdev_priv(dev);
+@@ -1901,7 +1898,7 @@ static irqreturn_t gfar_error(int irq, v
+ priv->stats.rx_errors++;
+ priv->extra_stats.rx_bsy++;
+
+- gfar_receive(irq, dev_id, regs);
++ gfar_receive(irq, dev_id);
+
+ #ifndef CONFIG_GFAR_NAPI
+ /* Clear the halt bit in RSTAT */
+@@ -1957,7 +1954,7 @@ static int __init gfar_init(void)
+
+ if (err)
+ gfar_mdio_exit();
+-
++
+ return err;
+ }
+
+diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
+index f87bbc4..9e81a50 100644
+--- a/drivers/net/gianfar.h
++++ b/drivers/net/gianfar.h
+@@ -754,9 +754,7 @@ static inline void gfar_write(volatile u
+ out_be32(addr, val);
+ }
+
+-extern struct ethtool_ops *gfar_op_array[];
+-
+-extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t gfar_receive(int irq, void *dev_id);
+ extern int startup_gfar(struct net_device *dev);
+ extern void stop_gfar(struct net_device *dev);
+ extern void gfar_halt(struct net_device *dev);
+diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
+index e0f5052..6d71bea 100644
+--- a/drivers/net/gianfar_ethtool.c
++++ b/drivers/net/gianfar_ethtool.c
+@@ -10,8 +10,8 @@
+ *
+ * Copyright (c) 2003,2004 Freescale Semiconductor, Inc.
+ *
+- * This software may be used and distributed according to
+- * the terms of the GNU Public License, Version 2, incorporated herein
++ * This software may be used and distributed according to
++ * the terms of the GNU Public License, Version 2, incorporated herein
+ * by reference.
+ */
+
+@@ -202,7 +202,7 @@ static int gfar_gsettings(struct net_dev
+
+ if (NULL == phydev)
+ return -ENODEV;
+-
++
+ cmd->maxtxpkt = priv->txcount;
+ cmd->maxrxpkt = priv->rxcount;
+
+@@ -281,7 +281,7 @@ static unsigned int gfar_ticks2usecs(str
+ 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;
+
+@@ -555,19 +555,19 @@ static uint32_t gfar_get_tx_csum(struct
+ }
+
+ 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 = {
++const struct ethtool_ops gfar_ethtool_ops = {
+ .get_settings = gfar_gsettings,
+ .set_settings = gfar_ssettings,
+ .get_drvinfo = gfar_gdrvinfo,
+diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
+index c92e659..ff684d4 100644
+--- a/drivers/net/gianfar_mii.c
++++ b/drivers/net/gianfar_mii.c
+@@ -1,4 +1,4 @@
+-/*
++/*
+ * drivers/net/gianfar_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+@@ -171,7 +171,7 @@ int gfar_mdio_probe(struct device *dev)
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+- printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
++ printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+ new_bus->name);
+ goto bus_register_fail;
+ }
+diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
+index d527cf2..5d34004 100644
+--- a/drivers/net/gianfar_mii.h
++++ b/drivers/net/gianfar_mii.h
+@@ -1,4 +1,4 @@
+-/*
++/*
+ * drivers/net/gianfar_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
+index e8a18f1..9dd387f 100644
+--- a/drivers/net/gianfar_sysfs.c
++++ b/drivers/net/gianfar_sysfs.c
+@@ -87,7 +87,7 @@ static ssize_t gfar_set_bd_stash(struct
+ priv->bd_stash_en = new_setting;
+
+ temp = gfar_read(&priv->regs->attr);
+-
++
+ if (new_setting)
+ temp |= ATTR_BDSTASH;
+ else
+diff --git a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h
+deleted file mode 100644
+index 7e7af0d..0000000
+--- a/drivers/net/gt64240eth.h
++++ /dev/null
+@@ -1,402 +0,0 @@
+-/*
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License. See the file "COPYING" in the main directory of this archive
+- * for more details.
+- *
+- * Copyright (C) 2001 Patton Electronics Company
+- * Copyright (C) 2002 Momentum Computer
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or support at mvista.com
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+- * for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+- *
+- * Ethernet driver definitions for the MIPS GT96100 Advanced
+- * Communication Controller.
+- *
+- * Modified for the Marvellous GT64240 Retarded Communication Controller.
+- */
+-#ifndef _GT64240ETH_H
+-#define _GT64240ETH_H
+-
+-#include <asm/gt64240.h>
+-
+-#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400
+-
+-/* Translate those weanie names from Galileo/VxWorks header files: */
+-
+-#define GT64240_MRR MAIN_ROUTING_REGISTER
+-#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER
+-#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL
+-#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER
+-#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER
+-#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW
+-#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH
+-#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER
+-
+-#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER
+-#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER
+-#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER
+-#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER
+-#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER
+-#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS
+-#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER
+-#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE
+-#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER
+-#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER
+-#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER
+-#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER
+-#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0
+-#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1
+-#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0
+-#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0
+-#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER
+-
+-/* Turn on NAPI by default */
+-
+-#define GT64240_NAPI 1
+-
+-/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */
+-/* (Board-specific to the DSL3224 Rev A board ONLY!) */
+-#define D3224_MPP_CTRL0_SETTING 0x66669900
+-#define D3224_MPP_CTRL1_SETTING 0x00000000
+-#define D3224_MPP_CTRL2_SETTING 0x00887700
+-#define D3224_MPP_CTRL3_SETTING 0x00000044
+-#define D3224_GPP_IO_CTRL_SETTING 0x0000e800
+-#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703
+-#define D3224_GPP_VALUE_SETTING 0x00000000
+-
+-/* Keep the ring sizes a power of two for efficiency. */
+-//-#define TX_RING_SIZE 16
+-#define TX_RING_SIZE 64 /* TESTING !!! */
+-#define RX_RING_SIZE 32
+-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
+-
+-#define RX_HASH_TABLE_SIZE 16384
+-#define HASH_HOP_NUMBER 12
+-
+-#define NUM_INTERFACES 3
+-
+-#define GT64240ETH_TX_TIMEOUT HZ/4
+-
+-#define MIPS_GT64240_BASE 0xf4000000
+-#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG)
+-#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE)
+-#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE)
+-
+-#if defined(CONFIG_MIPS_DSL3224)
+-#define GT64240_ETHER0_IRQ 4
+-#define GT64240_ETHER1_IRQ 4
+-#else
+-#define GT64240_ETHER0_IRQ -1
+-#define GT64240_ETHER1_IRQ -1
+-#endif
+-
+-#define REV_GT64240 0x1
+-#define REV_GT64240A 0x10
+-
+-#define GT64240ETH_READ(gp, offset) \
+- GT_READ((gp)->port_offset + (offset))
+-
+-#define GT64240ETH_WRITE(gp, offset, data) \
+- GT_WRITE((gp)->port_offset + (offset), (data))
+-
+-#define GT64240ETH_SETBIT(gp, offset, bits) \
+- GT64240ETH_WRITE((gp), (offset), \
+- GT64240ETH_READ((gp), (offset)) | (bits))
+-
+-#define GT64240ETH_CLRBIT(gp, offset, bits) \
+- GT64240ETH_WRITE((gp), (offset), \
+- GT64240ETH_READ((gp), (offset)) & ~(bits))
+-
+-#define GT64240_READ(ofs) GT_READ(ofs)
+-#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data))
+-
+-/* Bit definitions of the SMI Reg */
+-enum {
+- smirDataMask = 0xffff,
+- smirPhyAdMask = 0x1f << 16,
+- smirPhyAdBit = 16,
+- smirRegAdMask = 0x1f << 21,
+- smirRegAdBit = 21,
+- smirOpCode = 1 << 26,
+- smirReadValid = 1 << 27,
+- smirBusy = 1 << 28
+-};
+-
+-/* Bit definitions of the Port Config Reg */
+-enum pcr_bits {
+- pcrPM = 1 << 0,
+- pcrRBM = 1 << 1,
+- pcrPBF = 1 << 2,
+- pcrEN = 1 << 7,
+- pcrLPBKMask = 0x3 << 8,
+- pcrLPBKBit = 1 << 8,
+- pcrFC = 1 << 10,
+- pcrHS = 1 << 12,
+- pcrHM = 1 << 13,
+- pcrHDM = 1 << 14,
+- pcrHD = 1 << 15,
+- pcrISLMask = 0x7 << 28,
+- pcrISLBit = 28,
+- pcrACCS = 1 << 31
+-};
+-
+-/* Bit definitions of the Port Config Extend Reg */
+-enum pcxr_bits {
+- pcxrIGMP = 1,
+- pcxrSPAN = 2,
+- pcxrPAR = 4,
+- pcxrPRIOtxMask = 0x7 << 3,
+- pcxrPRIOtxBit = 3,
+- pcxrPRIOrxMask = 0x3 << 6,
+- pcxrPRIOrxBit = 6,
+- pcxrPRIOrxOverride = 1 << 8,
+- pcxrDPLXen = 1 << 9,
+- pcxrFCTLen = 1 << 10,
+- pcxrFLP = 1 << 11,
+- pcxrFCTL = 1 << 12,
+- pcxrMFLMask = 0x3 << 14,
+- pcxrMFLBit = 14,
+- pcxrMIBclrMode = 1 << 16,
+- pcxrSpeed = 1 << 18,
+- pcxrSpeeden = 1 << 19,
+- pcxrRMIIen = 1 << 20,
+- pcxrDSCPen = 1 << 21
+-};
+-
+-/* Bit definitions of the Port Command Reg */
+-enum pcmr_bits {
+- pcmrFJ = 1 << 15
+-};
+-
+-
+-/* Bit definitions of the Port Status Reg */
+-enum psr_bits {
+- psrSpeed = 1,
+- psrDuplex = 2,
+- psrFctl = 4,
+- psrLink = 8,
+- psrPause = 1 << 4,
+- psrTxLow = 1 << 5,
+- psrTxHigh = 1 << 6,
+- psrTxInProg = 1 << 7
+-};
+-
+-/* Bit definitions of the SDMA Config Reg */
+-enum sdcr_bits {
+- sdcrRCMask = 0xf << 2,
+- sdcrRCBit = 2,
+- sdcrBLMR = 1 << 6,
+- sdcrBLMT = 1 << 7,
+- sdcrPOVR = 1 << 8,
+- sdcrRIFB = 1 << 9,
+- sdcrBSZMask = 0x3 << 12,
+- sdcrBSZBit = 12
+-};
+-
+-/* Bit definitions of the SDMA Command Reg */
+-enum sdcmr_bits {
+- sdcmrERD = 1 << 7,
+- sdcmrAR = 1 << 15,
+- sdcmrSTDH = 1 << 16,
+- sdcmrSTDL = 1 << 17,
+- sdcmrTXDH = 1 << 23,
+- sdcmrTXDL = 1 << 24,
+- sdcmrAT = 1 << 31
+-};
+-
+-/* Bit definitions of the Interrupt Cause Reg */
+-enum icr_bits {
+- icrRxBuffer = 1,
+- icrTxBufferHigh = 1 << 2,
+- icrTxBufferLow = 1 << 3,
+- icrTxEndHigh = 1 << 6,
+- icrTxEndLow = 1 << 7,
+- icrRxError = 1 << 8,
+- icrTxErrorHigh = 1 << 10,
+- icrTxErrorLow = 1 << 11,
+- icrRxOVR = 1 << 12,
+- icrTxUdr = 1 << 13,
+- icrRxBufferQ0 = 1 << 16,
+- icrRxBufferQ1 = 1 << 17,
+- icrRxBufferQ2 = 1 << 18,
+- icrRxBufferQ3 = 1 << 19,
+- icrRxErrorQ0 = 1 << 20,
+- icrRxErrorQ1 = 1 << 21,
+- icrRxErrorQ2 = 1 << 22,
+- icrRxErrorQ3 = 1 << 23,
+- icrMIIPhySTC = 1 << 28,
+- icrSMIdone = 1 << 29,
+- icrEtherIntSum = 1 << 31
+-};
+-
+-
+-/* The Rx and Tx descriptor lists. */
+-#ifdef __LITTLE_ENDIAN
+-typedef struct {
+- u32 cmdstat;
+- u16 reserved; //-prk21aug01 u32 reserved:16;
+- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
+- u32 buff_ptr;
+- u32 next;
+-} gt64240_td_t;
+-
+-typedef struct {
+- u32 cmdstat;
+- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
+- u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
+- u32 buff_ptr;
+- u32 next;
+-} gt64240_rd_t;
+-#elif defined(__BIG_ENDIAN)
+-typedef struct {
+- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
+- u16 reserved; //-prk21aug01 u32 reserved:16;
+- u32 cmdstat;
+- u32 next;
+- u32 buff_ptr;
+-} gt64240_td_t;
+-
+-typedef struct {
+- u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
+- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
+- u32 cmdstat;
+- u32 next;
+- u32 buff_ptr;
+-} gt64240_rd_t;
+-#else
+-#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined!
+-#endif
+-
+-
+-/* Values for the Tx command-status descriptor entry. */
+-enum td_cmdstat {
+- txOwn = 1 << 31,
+- txAutoMode = 1 << 30,
+- txEI = 1 << 23,
+- txGenCRC = 1 << 22,
+- txPad = 1 << 18,
+- txFirst = 1 << 17,
+- txLast = 1 << 16,
+- txErrorSummary = 1 << 15,
+- txReTxCntMask = 0x0f << 10,
+- txReTxCntBit = 10,
+- txCollision = 1 << 9,
+- txReTxLimit = 1 << 8,
+- txUnderrun = 1 << 6,
+- txLateCollision = 1 << 5
+-};
+-
+-
+-/* Values for the Rx command-status descriptor entry. */
+-enum rd_cmdstat {
+- rxOwn = 1 << 31,
+- rxAutoMode = 1 << 30,
+- rxEI = 1 << 23,
+- rxFirst = 1 << 17,
+- rxLast = 1 << 16,
+- rxErrorSummary = 1 << 15,
+- rxIGMP = 1 << 14,
+- rxHashExpired = 1 << 13,
+- rxMissedFrame = 1 << 12,
+- rxFrameType = 1 << 11,
+- rxShortFrame = 1 << 8,
+- rxMaxFrameLen = 1 << 7,
+- rxOverrun = 1 << 6,
+- rxCollision = 1 << 4,
+- rxCRCError = 1
+-};
+-
+-/* Bit fields of a Hash Table Entry */
+-enum hash_table_entry {
+- hteValid = 1,
+- hteSkip = 2,
+- hteRD = 4
+-};
+-
+-// The MIB counters
+-typedef struct {
+- u32 byteReceived;
+- u32 byteSent;
+- u32 framesReceived;
+- u32 framesSent;
+- u32 totalByteReceived;
+- u32 totalFramesReceived;
+- u32 broadcastFramesReceived;
+- u32 multicastFramesReceived;
+- u32 cRCError;
+- u32 oversizeFrames;
+- u32 fragments;
+- u32 jabber;
+- u32 collision;
+- u32 lateCollision;
+- u32 frames64;
+- u32 frames65_127;
+- u32 frames128_255;
+- u32 frames256_511;
+- u32 frames512_1023;
+- u32 frames1024_MaxSize;
+- u32 macRxError;
+- u32 droppedFrames;
+- u32 outMulticastFrames;
+- u32 outBroadcastFrames;
+- u32 undersizeFrames;
+-} mib_counters_t;
+-
+-
+-struct gt64240_private {
+- gt64240_rd_t *rx_ring;
+- gt64240_td_t *tx_ring;
+- // The Rx and Tx rings must be 16-byte aligned
+- dma_addr_t rx_ring_dma;
+- dma_addr_t tx_ring_dma;
+- char *hash_table;
+- // The Hash Table must be 8-byte aligned
+- dma_addr_t hash_table_dma;
+- int hash_mode;
+-
+- // The Rx buffers must be 8-byte aligned
+- char *rx_buff;
+- dma_addr_t rx_buff_dma;
+- // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
+- // of payload must be 8-byte aligned
+- struct sk_buff *tx_skbuff[TX_RING_SIZE];
+- int rx_next_out; /* The next free ring entry to receive */
+- int tx_next_in; /* The next free ring entry to send */
+- int tx_next_out; /* The last ring entry the ISR processed */
+- int tx_count; /* current # of pkts waiting to be sent in Tx ring */
+- int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
+- int tx_full; /* Tx ring is full */
+-
+- mib_counters_t mib;
+- struct net_device_stats stats;
+-
+- int io_size;
+- int port_num; // 0 or 1
+- u32 port_offset;
+-
+- int phy_addr; // PHY address
+- u32 last_psr; // last value of the port status register
+-
+- int options; /* User-settable misc. driver options. */
+- int drv_flags;
+- spinlock_t lock; /* Serialise access to device */
+- struct mii_if_info mii_if;
+-
+- u32 msg_enable;
+-};
+-
+-#endif /* _GT64240ETH_H */
+diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
+deleted file mode 100644
+index 2b4db74..0000000
+--- a/drivers/net/gt96100eth.c
++++ /dev/null
+@@ -1,1566 +0,0 @@
+-/*
+- * Copyright 2000, 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at mvista.com
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+- * for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+- *
+- * Ethernet driver for the MIPS GT96100 Advanced Communication Controller.
+- *
+- * Revision history
+- *
+- * 11.11.2001 Moved to 2.4.14, ppopov at mvista.com. Modified driver to add
+- * proper gt96100A support.
+- * 12.05.2001 Moved eth port 0 to irq 3 (mapped to GT_SERINT0 on EV96100A)
+- * in order for both ports to work. Also cleaned up boot
+- * option support (mac address string parsing), fleshed out
+- * gt96100_cleanup_module(), and other general code cleanups
+- * <stevel at mvista.com>.
+- */
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/timer.h>
+-#include <linux/errno.h>
+-#include <linux/in.h>
+-#include <linux/ioport.h>
+-#include <linux/slab.h>
+-#include <linux/interrupt.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/netdevice.h>
+-#include <linux/etherdevice.h>
+-#include <linux/skbuff.h>
+-#include <linux/delay.h>
+-#include <linux/ctype.h>
+-#include <linux/bitops.h>
+-
+-#include <asm/irq.h>
+-#include <asm/io.h>
+-
+-#define DESC_BE 1
+-#define DESC_DATA_BE 1
+-
+-#define GT96100_DEBUG 2
+-
+-#include "gt96100eth.h"
+-
+-// prototypes
+-static void* dmaalloc(size_t size, dma_addr_t *dma_handle);
+-static void dmafree(size_t size, void *vaddr);
+-static void gt96100_delay(int msec);
+-static int gt96100_add_hash_entry(struct net_device *dev,
+- unsigned char* addr);
+-static void read_mib_counters(struct gt96100_private *gp);
+-static int read_MII(int phy_addr, u32 reg);
+-static int write_MII(int phy_addr, u32 reg, u16 data);
+-static int gt96100_init_module(void);
+-static void gt96100_cleanup_module(void);
+-static void dump_MII(int dbg_lvl, struct net_device *dev);
+-static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i);
+-static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i);
+-static void dump_skb(int dbg_lvl, struct net_device *dev,
+- struct sk_buff *skb);
+-static void update_stats(struct gt96100_private *gp);
+-static void abort(struct net_device *dev, u32 abort_bits);
+-static void hard_stop(struct net_device *dev);
+-static void enable_ether_irq(struct net_device *dev);
+-static void disable_ether_irq(struct net_device *dev);
+-static int gt96100_probe1(struct pci_dev *pci, int port_num);
+-static void reset_tx(struct net_device *dev);
+-static void reset_rx(struct net_device *dev);
+-static int gt96100_check_tx_consistent(struct gt96100_private *gp);
+-static int gt96100_init(struct net_device *dev);
+-static int gt96100_open(struct net_device *dev);
+-static int gt96100_close(struct net_device *dev);
+-static int gt96100_tx(struct sk_buff *skb, struct net_device *dev);
+-static int gt96100_rx(struct net_device *dev, u32 status);
+-static irqreturn_t gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-static void gt96100_tx_timeout(struct net_device *dev);
+-static void gt96100_set_rx_mode(struct net_device *dev);
+-static struct net_device_stats* gt96100_get_stats(struct net_device *dev);
+-
+-extern char * __init prom_getcmdline(void);
+-
+-static int max_interrupt_work = 32;
+-
+-#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))
+-
+-#define RUN_AT(x) (jiffies + (x))
+-
+-// For reading/writing 32-bit words and half-words from/to DMA memory
+-#ifdef DESC_BE
+-#define cpu_to_dma32 cpu_to_be32
+-#define dma32_to_cpu be32_to_cpu
+-#define cpu_to_dma16 cpu_to_be16
+-#define dma16_to_cpu be16_to_cpu
+-#else
+-#define cpu_to_dma32 cpu_to_le32
+-#define dma32_to_cpu le32_to_cpu
+-#define cpu_to_dma16 cpu_to_le16
+-#define dma16_to_cpu le16_to_cpu
+-#endif
+-
+-static char mac0[18] = "00.02.03.04.05.06";
+-static char mac1[18] = "00.01.02.03.04.05";
+-module_param_string(mac0, mac0, 18, 0);
+-module_param_string(mac1, mac0, 18, 0);
+-MODULE_PARM_DESC(mac0, "MAC address for GT96100 ethernet port 0");
+-MODULE_PARM_DESC(mac1, "MAC address for GT96100 ethernet port 1");
+-
+-/*
+- * Info for the GT96100 ethernet controller's ports.
+- */
+-static struct gt96100_if_t {
+- struct net_device *dev;
+- unsigned int iobase; // IO Base address of this port
+- int irq; // IRQ number of this port
+- char *mac_str;
+-} gt96100_iflist[NUM_INTERFACES] = {
+- {
+- NULL,
+- GT96100_ETH0_BASE, GT96100_ETHER0_IRQ,
+- mac0
+- },
+- {
+- NULL,
+- GT96100_ETH1_BASE, GT96100_ETHER1_IRQ,
+- mac1
+- }
+-};
+-
+-static inline const char*
+-chip_name(int chip_rev)
+-{
+- switch (chip_rev) {
+- case REV_GT96100:
+- return "GT96100";
+- case REV_GT96100A_1:
+- case REV_GT96100A:
+- return "GT96100A";
+- default:
+- return "Unknown GT96100";
+- }
+-}
+-
+-/*
+- DMA memory allocation, derived from pci_alloc_consistent.
+-*/
+-static void * dmaalloc(size_t size, dma_addr_t *dma_handle)
+-{
+- void *ret;
+-
+- ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(size));
+-
+- if (ret != NULL) {
+- dma_cache_inv((unsigned long)ret, size);
+- if (dma_handle != NULL)
+- *dma_handle = virt_to_phys(ret);
+-
+- /* bump virtual address up to non-cached area */
+- ret = (void*)KSEG1ADDR(ret);
+- }
+-
+- return ret;
+-}
+-
+-static void dmafree(size_t size, void *vaddr)
+-{
+- vaddr = (void*)KSEG0ADDR(vaddr);
+- free_pages((unsigned long)vaddr, get_order(size));
+-}
+-
+-static void gt96100_delay(int ms)
+-{
+- if (in_interrupt())
+- return;
+- else
+- msleep_interruptible(ms);
+-}
+-
+-static int
+-parse_mac_addr(struct net_device *dev, char* macstr)
+-{
+- int i, j;
+- unsigned char result, value;
+-
+- for (i=0; i<6; i++) {
+- result = 0;
+- if (i != 5 && *(macstr+2) != '.') {
+- err(__FILE__ "invalid mac address format: %d %c\n",
+- i, *(macstr+2));
+- return -EINVAL;
+- }
+-
+- for (j=0; j<2; j++) {
+- if (isxdigit(*macstr) &&
+- (value = isdigit(*macstr) ? *macstr-'0' :
+- toupper(*macstr)-'A'+10) < 16) {
+- result = result*16 + value;
+- macstr++;
+- } else {
+- err(__FILE__ "invalid mac address "
+- "character: %c\n", *macstr);
+- return -EINVAL;
+- }
+- }
+-
+- macstr++; // step over '.'
+- dev->dev_addr[i] = result;
+- }
+-
+- return 0;
+-}
+-
+-
+-static int
+-read_MII(int phy_addr, u32 reg)
+-{
+- int timedout = 20;
+- u32 smir = smirOpCode | (phy_addr << smirPhyAdBit) |
+- (reg << smirRegAdBit);
+-
+- // wait for last operation to complete
+- while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
+- // snooze for 1 msec and check again
+- gt96100_delay(1);
+-
+- if (--timedout == 0) {
+- printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
+- return -ENODEV;
+- }
+- }
+-
+- GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
+-
+- timedout = 20;
+- // wait for read to complete
+- while (!((smir = GT96100_READ(GT96100_ETH_SMI_REG)) & smirReadValid)) {
+- // snooze for 1 msec and check again
+- gt96100_delay(1);
+-
+- if (--timedout == 0) {
+- printk(KERN_ERR "%s: timeout!!\n", __FUNCTION__);
+- return -ENODEV;
+- }
+- }
+-
+- return (int)(smir & smirDataMask);
+-}
+-
+-static void
+-dump_tx_desc(int dbg_lvl, struct net_device *dev, int i)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- gt96100_td_t *td = &gp->tx_ring[i];
+-
+- dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td));
+- dbg(dbg_lvl,
+- " cmdstat=%04x, byte_cnt=%04x, buff_ptr=%04x, next=%04x\n",
+- dma32_to_cpu(td->cmdstat),
+- dma16_to_cpu(td->byte_cnt),
+- dma32_to_cpu(td->buff_ptr),
+- dma32_to_cpu(td->next));
+-}
+-
+-static void
+-dump_rx_desc(int dbg_lvl, struct net_device *dev, int i)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- gt96100_rd_t *rd = &gp->rx_ring[i];
+-
+- dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd));
+- dbg(dbg_lvl, " cmdstat=%04x, buff_sz=%04x, byte_cnt=%04x, "
+- "buff_ptr=%04x, next=%04x\n",
+- dma32_to_cpu(rd->cmdstat),
+- dma16_to_cpu(rd->buff_sz),
+- dma16_to_cpu(rd->byte_cnt),
+- dma32_to_cpu(rd->buff_ptr),
+- dma32_to_cpu(rd->next));
+-}
+-
+-static int
+-write_MII(int phy_addr, u32 reg, u16 data)
+-{
+- int timedout = 20;
+- u32 smir = (phy_addr << smirPhyAdBit) |
+- (reg << smirRegAdBit) | data;
+-
+- // wait for last operation to complete
+- while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
+- // snooze for 1 msec and check again
+- gt96100_delay(1);
+-
+- if (--timedout == 0) {
+- printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
+- return -1;
+- }
+- }
+-
+- GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
+- return 0;
+-}
+-
+-static void
+-dump_MII(int dbg_lvl, struct net_device *dev)
+-{
+- int i, val;
+- struct gt96100_private *gp = netdev_priv(dev);
+-
+- if (dbg_lvl <= GT96100_DEBUG) {
+- for (i=0; i<7; i++) {
+- if ((val = read_MII(gp->phy_addr, i)) >= 0)
+- printk("MII Reg %d=%x\n", i, val);
+- }
+- for (i=16; i<21; i++) {
+- if ((val = read_MII(gp->phy_addr, i)) >= 0)
+- printk("MII Reg %d=%x\n", i, val);
+- }
+- }
+-}
+-
+-static void
+-dump_hw_addr(int dbg_lvl, struct net_device *dev, const char* pfx,
+- const char* func, unsigned char* addr_str)
+-{
+- int i;
+- char buf[100], octet[5];
+-
+- if (dbg_lvl <= GT96100_DEBUG) {
+- sprintf(buf, pfx, func);
+- for (i = 0; i < 6; i++) {
+- sprintf(octet, "%2.2x%s",
+- addr_str[i], i<5 ? ":" : "\n");
+- strcat(buf, octet);
+- }
+- info("%s", buf);
+- }
+-}
+-
+-
+-static void
+-dump_skb(int dbg_lvl, struct net_device *dev, struct sk_buff *skb)
+-{
+- int i;
+- unsigned char* skbdata;
+-
+- if (dbg_lvl <= GT96100_DEBUG) {
+- dbg(dbg_lvl, "%s: skb=%p, skb->data=%p, skb->len=%d\n",
+- __FUNCTION__, skb, skb->data, skb->len);
+-
+- skbdata = (unsigned char*)KSEG1ADDR(skb->data);
+-
+- for (i=0; i<skb->len; i++) {
+- if (!(i % 16))
+- printk(KERN_DEBUG "\n %3.3x: %2.2x,",
+- i, skbdata[i]);
+- else
+- printk(KERN_DEBUG "%2.2x,", skbdata[i]);
+- }
+- printk(KERN_DEBUG "\n");
+- }
+-}
+-
+-
+-static int
+-gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- //u16 hashResult, stmp;
+- //unsigned char ctmp, hash_ea[6];
+- u32 tblEntry1, tblEntry0, *tblEntryAddr;
+- int i;
+-
+- tblEntry1 = hteValid | hteRD;
+- tblEntry1 |= (u32)addr[5] << 3;
+- tblEntry1 |= (u32)addr[4] << 11;
+- tblEntry1 |= (u32)addr[3] << 19;
+- tblEntry1 |= ((u32)addr[2] & 0x1f) << 27;
+- dbg(3, "%s: tblEntry1=%x\n", __FUNCTION__, tblEntry1);
+- tblEntry0 = ((u32)addr[2] >> 5) & 0x07;
+- tblEntry0 |= (u32)addr[1] << 3;
+- tblEntry0 |= (u32)addr[0] << 11;
+- dbg(3, "%s: tblEntry0=%x\n", __FUNCTION__, tblEntry0);
+-
+-#if 0
+-
+- for (i=0; i<6; i++) {
+- // nibble swap
+- ctmp = nibswap(addr[i]);
+- // invert every nibble
+- hash_ea[i] = ((ctmp&1)<<3) | ((ctmp&8)>>3) |
+- ((ctmp&2)<<1) | ((ctmp&4)>>1);
+- hash_ea[i] |= ((ctmp&0x10)<<3) | ((ctmp&0x80)>>3) |
+- ((ctmp&0x20)<<1) | ((ctmp&0x40)>>1);
+- }
+-
+- dump_hw_addr(3, dev, "%s: nib swap/invt addr=", __FUNCTION__, hash_ea);
+-
+- if (gp->hash_mode == 0) {
+- hashResult = ((u16)hash_ea[0] & 0xfc) << 7;
+- stmp = ((u16)hash_ea[0] & 0x03) |
+- (((u16)hash_ea[1] & 0x7f) << 2);
+- stmp ^= (((u16)hash_ea[1] >> 7) & 0x01) |
+- ((u16)hash_ea[2] << 1);
+- stmp ^= (u16)hash_ea[3] | (((u16)hash_ea[4] & 1) << 8);
+- hashResult |= stmp;
+- } else {
+- return -1; // don't support hash mode 1
+- }
+-
+- dbg(3, "%s: hashResult=%x\n", __FUNCTION__, hashResult);
+-
+- tblEntryAddr =
+- (u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]);
+-
+- dbg(3, "%s: tblEntryAddr=%p\n", tblEntryAddr, __FUNCTION__);
+-
+- for (i=0; i<HASH_HOP_NUMBER; i++) {
+- if ((*tblEntryAddr & hteValid) &&
+- !(*tblEntryAddr & hteSkip)) {
+- // This entry is already occupied, go to next entry
+- tblEntryAddr += 2;
+- dbg(3, "%s: skipping to %p\n", __FUNCTION__,
+- tblEntryAddr);
+- } else {
+- memset(tblEntryAddr, 0, 8);
+- tblEntryAddr[1] = cpu_to_dma32(tblEntry1);
+- tblEntryAddr[0] = cpu_to_dma32(tblEntry0);
+- break;
+- }
+- }
+-
+- if (i >= HASH_HOP_NUMBER) {
+- err("%s: expired!\n", __FUNCTION__);
+- return -1; // Couldn't find an unused entry
+- }
+-
+-#else
+-
+- tblEntryAddr = (u32 *)gp->hash_table;
+- for (i=0; i<RX_HASH_TABLE_SIZE/4; i+=2) {
+- tblEntryAddr[i+1] = cpu_to_dma32(tblEntry1);
+- tblEntryAddr[i] = cpu_to_dma32(tblEntry0);
+- }
+-
+-#endif
+-
+- return 0;
+-}
+-
+-
+-static void
+-read_mib_counters(struct gt96100_private *gp)
+-{
+- u32* mib_regs = (u32*)&gp->mib;
+- int i;
+-
+- for (i=0; i<sizeof(mib_counters_t)/sizeof(u32); i++)
+- mib_regs[i] = GT96100ETH_READ(gp, GT96100_ETH_MIB_COUNT_BASE +
+- i*sizeof(u32));
+-}
+-
+-
+-static void
+-update_stats(struct gt96100_private *gp)
+-{
+- mib_counters_t *mib = &gp->mib;
+- struct net_device_stats *stats = &gp->stats;
+-
+- read_mib_counters(gp);
+-
+- stats->rx_packets = mib->totalFramesReceived;
+- stats->tx_packets = mib->framesSent;
+- stats->rx_bytes = mib->totalByteReceived;
+- stats->tx_bytes = mib->byteSent;
+- stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;
+- //the tx error counters are incremented by the ISR
+- //rx_dropped incremented by gt96100_rx
+- //tx_dropped incremented by gt96100_tx
+- stats->multicast = mib->multicastFramesReceived;
+- // collisions incremented by gt96100_tx_complete
+- stats->rx_length_errors = mib->oversizeFrames + mib->fragments;
+- // The RxError condition means the Rx DMA encountered a
+- // CPU owned descriptor, which, if things are working as
+- // they should, means the Rx ring has overflowed.
+- stats->rx_over_errors = mib->macRxError;
+- stats->rx_crc_errors = mib->cRCError;
+-}
+-
+-static void
+-abort(struct net_device *dev, u32 abort_bits)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- int timedout = 100; // wait up to 100 msec for hard stop to complete
+-
+- dbg(3, "%s\n", __FUNCTION__);
+-
+- // Return if neither Rx or Tx abort bits are set
+- if (!(abort_bits & (sdcmrAR | sdcmrAT)))
+- return;
+-
+- // make sure only the Rx/Tx abort bits are set
+- abort_bits &= (sdcmrAR | sdcmrAT);
+-
+- spin_lock(&gp->lock);
+-
+- // abort any Rx/Tx DMA immediately
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
+-
+- dbg(3, "%s: SDMA comm = %x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
+-
+- // wait for abort to complete
+- while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) {
+- // snooze for 1 msec and check again
+- gt96100_delay(1);
+-
+- if (--timedout == 0) {
+- err("%s: timeout!!\n", __FUNCTION__);
+- break;
+- }
+- }
+-
+- spin_unlock(&gp->lock);
+-}
+-
+-
+-static void
+-hard_stop(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+-
+- dbg(3, "%s\n", __FUNCTION__);
+-
+- disable_ether_irq(dev);
+-
+- abort(dev, sdcmrAR | sdcmrAT);
+-
+- // disable port
+- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0);
+-}
+-
+-
+-static void
+-enable_ether_irq(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- u32 intMask;
+- /*
+- * route ethernet interrupt to GT_SERINT0 for port 0,
+- * GT_INT0 for port 1.
+- */
+- int intr_mask_reg = (gp->port_num == 0) ?
+- GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;
+-
+- if (gp->chip_rev >= REV_GT96100A_1) {
+- intMask = icrTxBufferLow | icrTxEndLow |
+- icrTxErrorLow | icrRxOVR | icrTxUdr |
+- icrRxBufferQ0 | icrRxErrorQ0 |
+- icrMIIPhySTC | icrEtherIntSum;
+- }
+- else {
+- intMask = icrTxBufferLow | icrTxEndLow |
+- icrTxErrorLow | icrRxOVR | icrTxUdr |
+- icrRxBuffer | icrRxError |
+- icrMIIPhySTC | icrEtherIntSum;
+- }
+-
+- // unmask interrupts
+- GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, intMask);
+-
+- intMask = GT96100_READ(intr_mask_reg);
+- intMask |= 1<<gp->port_num;
+- GT96100_WRITE(intr_mask_reg, intMask);
+-}
+-
+-static void
+-disable_ether_irq(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- u32 intMask;
+- int intr_mask_reg = (gp->port_num == 0) ?
+- GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;
+-
+- intMask = GT96100_READ(intr_mask_reg);
+- intMask &= ~(1<<gp->port_num);
+- GT96100_WRITE(intr_mask_reg, intMask);
+-
+- GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0);
+-}
+-
+-
+-/*
+- * Init GT96100 ethernet controller driver
+- */
+-static int gt96100_init_module(void)
+-{
+- struct pci_dev *pci;
+- int i, retval=0;
+- u32 cpuConfig;
+-
+- /*
+- * Stupid probe because this really isn't a PCI device
+- */
+- if (!(pci = pci_find_device(PCI_VENDOR_ID_MARVELL,
+- PCI_DEVICE_ID_MARVELL_GT96100, NULL)) &&
+- !(pci = pci_find_device(PCI_VENDOR_ID_MARVELL,
+- PCI_DEVICE_ID_MARVELL_GT96100A, NULL))) {
+- printk(KERN_ERR __FILE__ ": GT96100 not found!\n");
+- return -ENODEV;
+- }
+-
+- cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG);
+- if (cpuConfig & (1<<12)) {
+- printk(KERN_ERR __FILE__
+- ": must be in Big Endian mode!\n");
+- return -ENODEV;
+- }
+-
+- for (i=0; i < NUM_INTERFACES; i++)
+- retval |= gt96100_probe1(pci, i);
+-
+- return retval;
+-}
+-
+-static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
+-{
+- struct gt96100_private *gp = NULL;
+- struct gt96100_if_t *gtif = >96100_iflist[port_num];
+- int phy_addr, phy_id1, phy_id2;
+- u32 phyAD;
+- int retval;
+- unsigned char chip_rev;
+- struct net_device *dev = NULL;
+-
+- if (gtif->irq < 0) {
+- printk(KERN_ERR "%s: irq unknown - probing not supported\n",
+- __FUNCTION__);
+- return -ENODEV;
+- }
+-
+- pci_read_config_byte(pci, PCI_REVISION_ID, &chip_rev);
+-
+- if (chip_rev >= REV_GT96100A_1) {
+- phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);
+- phy_addr = (phyAD >> (5*port_num)) & 0x1f;
+- } else {
+- /*
+- * not sure what's this about -- probably a gt bug
+- */
+- phy_addr = port_num;
+- phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);
+- phyAD &= ~(0x1f << (port_num*5));
+- phyAD |= phy_addr << (port_num*5);
+- GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD);
+- }
+-
+- // probe for the external PHY
+- if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 ||
+- (phy_id2 = read_MII(phy_addr, 3)) <= 0) {
+- printk(KERN_ERR "%s: no PHY found on MII%d\n", __FUNCTION__, port_num);
+- return -ENODEV;
+- }
+-
+- if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) {
+- printk(KERN_ERR "%s: request_region failed\n", __FUNCTION__);
+- return -EBUSY;
+- }
+-
+- dev = alloc_etherdev(sizeof(struct gt96100_private));
+- if (!dev)
+- goto out;
+- gtif->dev = dev;
+-
+- /* private struct aligned and zeroed by alloc_etherdev */
+- /* Fill in the 'dev' fields. */
+- dev->base_addr = gtif->iobase;
+- dev->irq = gtif->irq;
+-
+- if ((retval = parse_mac_addr(dev, gtif->mac_str))) {
+- err("%s: MAC address parse failed\n", __FUNCTION__);
+- retval = -EINVAL;
+- goto out1;
+- }
+-
+- gp = netdev_priv(dev);
+-
+- memset(gp, 0, sizeof(*gp)); // clear it
+-
+- gp->port_num = port_num;
+- gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
+- gp->phy_addr = phy_addr;
+- gp->chip_rev = chip_rev;
+-
+- info("%s found at 0x%x, irq %d\n",
+- chip_name(gp->chip_rev), gtif->iobase, gtif->irq);
+- dump_hw_addr(0, dev, "%s: HW Address ", __FUNCTION__, dev->dev_addr);
+- info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev);
+- info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num);
+- info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2);
+-
+- // Allocate Rx and Tx descriptor rings
+- if (gp->rx_ring == NULL) {
+- // All descriptors in ring must be 16-byte aligned
+- gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE
+- + sizeof(gt96100_td_t) * TX_RING_SIZE,
+- &gp->rx_ring_dma);
+- if (gp->rx_ring == NULL) {
+- retval = -ENOMEM;
+- goto out1;
+- }
+-
+- gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE);
+- gp->tx_ring_dma =
+- gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE;
+- }
+-
+- // Allocate the Rx Data Buffers
+- if (gp->rx_buff == NULL) {
+- gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE,
+- &gp->rx_buff_dma);
+- if (gp->rx_buff == NULL) {
+- retval = -ENOMEM;
+- goto out2;
+- }
+- }
+-
+- dbg(3, "%s: rx_ring=%p, tx_ring=%p\n", __FUNCTION__,
+- gp->rx_ring, gp->tx_ring);
+-
+- // Allocate Rx Hash Table
+- if (gp->hash_table == NULL) {
+- gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE,
+- &gp->hash_table_dma);
+- if (gp->hash_table == NULL) {
+- retval = -ENOMEM;
+- goto out3;
+- }
+- }
+-
+- dbg(3, "%s: hash=%p\n", __FUNCTION__, gp->hash_table);
+-
+- spin_lock_init(&gp->lock);
+-
+- dev->open = gt96100_open;
+- dev->hard_start_xmit = gt96100_tx;
+- dev->stop = gt96100_close;
+- dev->get_stats = gt96100_get_stats;
+- //dev->do_ioctl = gt96100_ioctl;
+- dev->set_multicast_list = gt96100_set_rx_mode;
+- dev->tx_timeout = gt96100_tx_timeout;
+- dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT;
+-
+- retval = register_netdev(dev);
+- if (retval)
+- goto out4;
+- return 0;
+-
+-out4:
+- dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma);
+-out3:
+- dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff);
+-out2:
+- dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE
+- + sizeof(gt96100_td_t) * TX_RING_SIZE,
+- gp->rx_ring);
+-out1:
+- free_netdev (dev);
+-out:
+- release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
+-
+- err("%s failed. Returns %d\n", __FUNCTION__, retval);
+- return retval;
+-}
+-
+-
+-static void
+-reset_tx(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- int i;
+-
+- abort(dev, sdcmrAT);
+-
+- for (i=0; i<TX_RING_SIZE; i++) {
+- if (gp->tx_skbuff[i]) {
+- if (in_interrupt())
+- dev_kfree_skb_irq(gp->tx_skbuff[i]);
+- else
+- dev_kfree_skb(gp->tx_skbuff[i]);
+- gp->tx_skbuff[i] = NULL;
+- }
+-
+- gp->tx_ring[i].cmdstat = 0; // CPU owns
+- gp->tx_ring[i].byte_cnt = 0;
+- gp->tx_ring[i].buff_ptr = 0;
+- gp->tx_ring[i].next =
+- cpu_to_dma32(gp->tx_ring_dma +
+- sizeof(gt96100_td_t) * (i+1));
+- dump_tx_desc(4, dev, i);
+- }
+- /* Wrap the ring. */
+- gp->tx_ring[i-1].next = cpu_to_dma32(gp->tx_ring_dma);
+-
+- // setup only the lowest priority TxCDP reg
+- GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma);
+- GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0);
+-
+- // init Tx indeces and pkt counter
+- gp->tx_next_in = gp->tx_next_out = 0;
+- gp->tx_count = 0;
+-
+-}
+-
+-static void
+-reset_rx(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- int i;
+-
+- abort(dev, sdcmrAR);
+-
+- for (i=0; i<RX_RING_SIZE; i++) {
+- gp->rx_ring[i].next =
+- cpu_to_dma32(gp->rx_ring_dma +
+- sizeof(gt96100_rd_t) * (i+1));
+- gp->rx_ring[i].buff_ptr =
+- cpu_to_dma32(gp->rx_buff_dma + i*PKT_BUF_SZ);
+- gp->rx_ring[i].buff_sz = cpu_to_dma16(PKT_BUF_SZ);
+- // Give ownership to device, set first and last, enable intr
+- gp->rx_ring[i].cmdstat =
+- cpu_to_dma32((u32)(rxFirst | rxLast | rxOwn | rxEI));
+- dump_rx_desc(4, dev, i);
+- }
+- /* Wrap the ring. */
+- gp->rx_ring[i-1].next = cpu_to_dma32(gp->rx_ring_dma);
+-
+- // Setup only the lowest priority RxFDP and RxCDP regs
+- for (i=0; i<4; i++) {
+- if (i == 0) {
+- GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0,
+- gp->rx_ring_dma);
+- GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0,
+- gp->rx_ring_dma);
+- } else {
+- GT96100ETH_WRITE(gp,
+- GT96100_ETH_1ST_RX_DESC_PTR0 + i*4,
+- 0);
+- GT96100ETH_WRITE(gp,
+- GT96100_ETH_CURR_RX_DESC_PTR0 + i*4,
+- 0);
+- }
+- }
+-
+- // init Rx NextOut index
+- gp->rx_next_out = 0;
+-}
+-
+-
+-// Returns 1 if the Tx counter and indeces don't gel
+-static int
+-gt96100_check_tx_consistent(struct gt96100_private *gp)
+-{
+- int diff = gp->tx_next_in - gp->tx_next_out;
+-
+- diff = diff<0 ? TX_RING_SIZE + diff : diff;
+- diff = gp->tx_count == TX_RING_SIZE ? diff + TX_RING_SIZE : diff;
+-
+- return (diff != gp->tx_count);
+-}
+-
+-static int
+-gt96100_init(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- u32 tmp;
+- u16 mii_reg;
+-
+- dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
+- dbg(3, "%s: scs10_lo=%4x, scs10_hi=%4x\n", __FUNCTION__,
+- GT96100_READ(0x8), GT96100_READ(0x10));
+- dbg(3, "%s: scs32_lo=%4x, scs32_hi=%4x\n", __FUNCTION__,
+- GT96100_READ(0x18), GT96100_READ(0x20));
+-
+- // Stop and disable Port
+- hard_stop(dev);
+-
+- // Setup CIU Arbiter
+- tmp = GT96100_READ(GT96100_CIU_ARBITER_CONFIG);
+- tmp |= (0x0c << (gp->port_num*2)); // set Ether DMA req priority to hi
+-#ifndef DESC_BE
+- tmp &= ~(1<<31); // set desc endianess to little
+-#else
+- tmp |= (1<<31);
+-#endif
+- GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp);
+- dbg(3, "%s: CIU Config=%x/%x\n", __FUNCTION__,
+- tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
+-
+- // Set routing.
+- tmp = GT96100_READ(GT96100_ROUTE_MAIN) & (0x3f << 18);
+- tmp |= (0x07 << (18 + gp->port_num*3));
+- GT96100_WRITE(GT96100_ROUTE_MAIN, tmp);
+-
+- /* set MII as peripheral func */
+- tmp = GT96100_READ(GT96100_GPP_CONFIG2);
+- tmp |= 0x7fff << (gp->port_num*16);
+- GT96100_WRITE(GT96100_GPP_CONFIG2, tmp);
+-
+- /* Set up MII port pin directions */
+- tmp = GT96100_READ(GT96100_GPP_IO2);
+- tmp |= 0x003d << (gp->port_num*16);
+- GT96100_WRITE(GT96100_GPP_IO2, tmp);
+-
+- // Set-up hash table
+- memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it
+- gp->hash_mode = 0;
+- // Add a single entry to hash table - our ethernet address
+- gt96100_add_hash_entry(dev, dev->dev_addr);
+- // Set-up DMA ptr to hash table
+- GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
+- dbg(3, "%s: Hash Tbl Ptr=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
+-
+- // Setup Tx
+- reset_tx(dev);
+-
+- dbg(3, "%s: Curr Tx Desc Ptr0=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0));
+-
+- // Setup Rx
+- reset_rx(dev);
+-
+- dbg(3, "%s: 1st/Curr Rx Desc Ptr0=%x/%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0),
+- GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
+-
+- // eth port config register
+- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+- pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen);
+-
+- mii_reg = read_MII(gp->phy_addr, 0x11); /* int enable register */
+- mii_reg |= 2; /* enable mii interrupt */
+- write_MII(gp->phy_addr, 0x11, mii_reg);
+-
+- dbg(3, "%s: PhyAD=%x\n", __FUNCTION__,
+- GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
+-
+- // setup DMA
+-
+- // We want the Rx/Tx DMA to write/read data to/from memory in
+- // Big Endian mode. Also set DMA Burst Size to 8 64Bit words.
+-#ifdef DESC_DATA_BE
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,
+- (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
+-#else
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,
+- sdcrBLMR | sdcrBLMT |
+- (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
+-#endif
+- dbg(3, "%s: SDMA Config=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
+-
+- // start Rx DMA
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
+- dbg(3, "%s: SDMA Comm=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
+-
+- // enable this port (set hash size to 1/2K)
+- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
+- dbg(3, "%s: Port Config=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
+-
+- /*
+- * Disable all Type-of-Service queueing. All Rx packets will be
+- * treated normally and will be sent to the lowest priority
+- * queue.
+- *
+- * Disable flow-control for now. FIXME: support flow control?
+- */
+-
+- // clear all the MIB ctr regs
+- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+- pcxrFCTL | pcxrFCTLen | pcxrFLP |
+- pcxrPRIOrxOverride);
+- read_mib_counters(gp);
+- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+- pcxrFCTL | pcxrFCTLen | pcxrFLP |
+- pcxrPRIOrxOverride | pcxrMIBclrMode);
+-
+- dbg(3, "%s: Port Config Ext=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
+-
+- netif_start_queue(dev);
+-
+- dump_MII(4, dev);
+-
+- // enable interrupts
+- enable_ether_irq(dev);
+-
+- // we should now be receiving frames
+- return 0;
+-}
+-
+-
+-static int
+-gt96100_open(struct net_device *dev)
+-{
+- int retval;
+-
+- dbg(2, "%s: dev=%p\n", __FUNCTION__, dev);
+-
+- // Initialize and startup the GT-96100 ethernet port
+- if ((retval = gt96100_init(dev))) {
+- err("error in gt96100_init\n");
+- free_irq(dev->irq, dev);
+- return retval;
+- }
+-
+- if ((retval = request_irq(dev->irq, >96100_interrupt,
+- IRQF_SHARED, dev->name, dev))) {
+- err("unable to get IRQ %d\n", dev->irq);
+- return retval;
+- }
+-
+- dbg(2, "%s: Initialization done.\n", __FUNCTION__);
+-
+- return 0;
+-}
+-
+-static int
+-gt96100_close(struct net_device *dev)
+-{
+- dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
+-
+- // stop the device
+- if (netif_device_present(dev)) {
+- netif_stop_queue(dev);
+- hard_stop(dev);
+- }
+-
+- free_irq(dev->irq, dev);
+-
+- return 0;
+-}
+-
+-
+-static int
+-gt96100_tx(struct sk_buff *skb, struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- unsigned long flags;
+- int nextIn;
+-
+- spin_lock_irqsave(&gp->lock, flags);
+-
+- nextIn = gp->tx_next_in;
+-
+- dbg(3, "%s: nextIn=%d\n", __FUNCTION__, nextIn);
+-
+- if (gp->tx_count >= TX_RING_SIZE) {
+- warn("Tx Ring full, pkt dropped.\n");
+- gp->stats.tx_dropped++;
+- spin_unlock_irqrestore(&gp->lock, flags);
+- return 1;
+- }
+-
+- if (!(gp->last_psr & psrLink)) {
+- err("%s: Link down, pkt dropped.\n", __FUNCTION__);
+- gp->stats.tx_dropped++;
+- spin_unlock_irqrestore(&gp->lock, flags);
+- return 1;
+- }
+-
+- if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
+- err("%s: device owns descriptor, pkt dropped.\n", __FUNCTION__);
+- gp->stats.tx_dropped++;
+- // stop the queue, so Tx timeout can fix it
+- netif_stop_queue(dev);
+- spin_unlock_irqrestore(&gp->lock, flags);
+- return 1;
+- }
+-
+- // Prepare the Descriptor at tx_next_in
+- gp->tx_skbuff[nextIn] = skb;
+- gp->tx_ring[nextIn].byte_cnt = cpu_to_dma16(skb->len);
+- gp->tx_ring[nextIn].buff_ptr = cpu_to_dma32(virt_to_phys(skb->data));
+- // make sure packet gets written back to memory
+- dma_cache_wback_inv((unsigned long)(skb->data), skb->len);
+- // Give ownership to device, set first and last desc, enable interrupt
+- // Setting of ownership bit must be *last*!
+- gp->tx_ring[nextIn].cmdstat =
+- cpu_to_dma32((u32)(txOwn | txGenCRC | txEI |
+- txPad | txFirst | txLast));
+-
+- dump_tx_desc(4, dev, nextIn);
+- dump_skb(4, dev, skb);
+-
+- // increment tx_next_in with wrap
+- gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE;
+- // If DMA is stopped, restart
+- if (!(GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & psrTxLow))
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
+- sdcmrERD | sdcmrTXDL);
+-
+- // increment count and stop queue if full
+- if (++gp->tx_count == TX_RING_SIZE) {
+- gp->tx_full = 1;
+- netif_stop_queue(dev);
+- dbg(2, "Tx Ring now full, queue stopped.\n");
+- }
+-
+- dev->trans_start = jiffies;
+- spin_unlock_irqrestore(&gp->lock, flags);
+-
+- return 0;
+-}
+-
+-
+-static int
+-gt96100_rx(struct net_device *dev, u32 status)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- struct sk_buff *skb;
+- int pkt_len, nextOut, cdp;
+- gt96100_rd_t *rd;
+- u32 cmdstat;
+-
+- dbg(3, "%s: dev=%p, status=%x\n", __FUNCTION__, dev, status);
+-
+- cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0)
+- - gp->rx_ring_dma) / sizeof(gt96100_rd_t);
+-
+- // Continue until we reach 1st descriptor pointer
+- for (nextOut = gp->rx_next_out; nextOut != cdp;
+- nextOut = (nextOut + 1) % RX_RING_SIZE) {
+-
+- if (--gp->intr_work_done == 0)
+- break;
+-
+- rd = &gp->rx_ring[nextOut];
+- cmdstat = dma32_to_cpu(rd->cmdstat);
+-
+- dbg(4, "%s: Rx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
+- cmdstat, nextOut);
+-
+- if (cmdstat & (u32)rxOwn) {
+- //err("%s: device owns descriptor!\n", __FUNCTION__);
+- // DMA is not finished updating descriptor???
+- // Leave and come back later to pick-up where
+- // we left off.
+- break;
+- }
+-
+- // Drop this received pkt if there were any errors
+- if (((cmdstat & (u32)(rxErrorSummary)) &&
+- (cmdstat & (u32)(rxFirst))) || (status & icrRxError)) {
+- // update the detailed rx error counters that
+- // are not covered by the MIB counters.
+- if (cmdstat & (u32)rxOverrun)
+- gp->stats.rx_fifo_errors++;
+- cmdstat |= (u32)rxOwn;
+- rd->cmdstat = cpu_to_dma32(cmdstat);
+- continue;
+- }
+-
+- /*
+- * Must be first and last (ie only) descriptor of packet. We
+- * ignore (drop) any packets that do not fit in one descriptor.
+- * Every descriptor's receive buffer is large enough to hold
+- * the maximum 802.3 frame size, so a multi-descriptor packet
+- * indicates an error. Most if not all corrupted packets will
+- * have already been dropped by the above check for the
+- * rxErrorSummary status bit.
+- */
+- if (!(cmdstat & (u32)rxFirst) || !(cmdstat & (u32)rxLast)) {
+- if (cmdstat & (u32)rxFirst) {
+- /*
+- * This is the first descriptor of a
+- * multi-descriptor packet. It isn't corrupted
+- * because the above check for rxErrorSummary
+- * would have dropped it already, so what's
+- * the deal with this packet? Good question,
+- * let's dump it out.
+- */
+- err("%s: desc not first and last!\n", __FUNCTION__);
+- dump_rx_desc(0, dev, nextOut);
+- }
+- cmdstat |= (u32)rxOwn;
+- rd->cmdstat = cpu_to_dma32(cmdstat);
+- // continue to drop every descriptor of this packet
+- continue;
+- }
+-
+- pkt_len = dma16_to_cpu(rd->byte_cnt);
+-
+- /* Create new skb. */
+- skb = dev_alloc_skb(pkt_len+2);
+- if (skb == NULL) {
+- err("%s: Memory squeeze, dropping packet.\n", __FUNCTION__);
+- gp->stats.rx_dropped++;
+- cmdstat |= (u32)rxOwn;
+- rd->cmdstat = cpu_to_dma32(cmdstat);
+- continue;
+- }
+- skb->dev = dev;
+- skb_reserve(skb, 2); /* 16 byte IP header align */
+- memcpy(skb_put(skb, pkt_len),
+- &gp->rx_buff[nextOut*PKT_BUF_SZ], pkt_len);
+- skb->protocol = eth_type_trans(skb, dev);
+- dump_skb(4, dev, skb);
+-
+- netif_rx(skb); /* pass the packet to upper layers */
+- dev->last_rx = jiffies;
+-
+- // now we can release ownership of this desc back to device
+- cmdstat |= (u32)rxOwn;
+- rd->cmdstat = cpu_to_dma32(cmdstat);
+- }
+-
+- if (nextOut == gp->rx_next_out)
+- dbg(3, "%s: RxCDP did not increment?\n", __FUNCTION__);
+-
+- gp->rx_next_out = nextOut;
+- return 0;
+-}
+-
+-
+-static void
+-gt96100_tx_complete(struct net_device *dev, u32 status)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- int nextOut, cdp;
+- gt96100_td_t *td;
+- u32 cmdstat;
+-
+- cdp = (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0)
+- - gp->tx_ring_dma) / sizeof(gt96100_td_t);
+-
+- // Continue until we reach the current descriptor pointer
+- for (nextOut = gp->tx_next_out; nextOut != cdp;
+- nextOut = (nextOut + 1) % TX_RING_SIZE) {
+-
+- if (--gp->intr_work_done == 0)
+- break;
+-
+- td = &gp->tx_ring[nextOut];
+- cmdstat = dma32_to_cpu(td->cmdstat);
+-
+- dbg(3, "%s: Tx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
+- cmdstat, nextOut);
+-
+- if (cmdstat & (u32)txOwn) {
+- /*
+- * DMA is not finished writing descriptor???
+- * Leave and come back later to pick-up where
+- * we left off.
+- */
+- break;
+- }
+-
+- // increment Tx error stats
+- if (cmdstat & (u32)txErrorSummary) {
+- dbg(2, "%s: Tx error, cmdstat = %x\n", __FUNCTION__,
+- cmdstat);
+- gp->stats.tx_errors++;
+- if (cmdstat & (u32)txReTxLimit)
+- gp->stats.tx_aborted_errors++;
+- if (cmdstat & (u32)txUnderrun)
+- gp->stats.tx_fifo_errors++;
+- if (cmdstat & (u32)txLateCollision)
+- gp->stats.tx_window_errors++;
+- }
+-
+- if (cmdstat & (u32)txCollision)
+- gp->stats.collisions +=
+- (u32)((cmdstat & txReTxCntMask) >>
+- txReTxCntBit);
+-
+- // Wake the queue if the ring was full
+- if (gp->tx_full) {
+- gp->tx_full = 0;
+- if (gp->last_psr & psrLink) {
+- netif_wake_queue(dev);
+- dbg(2, "%s: Tx Ring was full, queue waked\n",
+- __FUNCTION__);
+- }
+- }
+-
+- // decrement tx ring buffer count
+- if (gp->tx_count) gp->tx_count--;
+-
+- // free the skb
+- if (gp->tx_skbuff[nextOut]) {
+- dbg(3, "%s: good Tx, skb=%p\n", __FUNCTION__,
+- gp->tx_skbuff[nextOut]);
+- dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
+- gp->tx_skbuff[nextOut] = NULL;
+- } else {
+- err("%s: no skb!\n", __FUNCTION__);
+- }
+- }
+-
+- gp->tx_next_out = nextOut;
+-
+- if (gt96100_check_tx_consistent(gp)) {
+- err("%s: Tx queue inconsistent!\n", __FUNCTION__);
+- }
+-
+- if ((status & icrTxEndLow) && gp->tx_count != 0) {
+- // we must restart the DMA
+- dbg(3, "%s: Restarting Tx DMA\n", __FUNCTION__);
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
+- sdcmrERD | sdcmrTXDL);
+- }
+-}
+-
+-
+-static irqreturn_t
+-gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct net_device *dev = (struct net_device *)dev_id;
+- struct gt96100_private *gp = netdev_priv(dev);
+- u32 status;
+- int handled = 0;
+-
+- if (dev == NULL) {
+- err("%s: null dev ptr\n", __FUNCTION__);
+- return IRQ_NONE;
+- }
+-
+- dbg(3, "%s: entry, icr=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
+-
+- spin_lock(&gp->lock);
+-
+- gp->intr_work_done = max_interrupt_work;
+-
+- while (gp->intr_work_done > 0) {
+-
+- status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE);
+- // ACK interrupts
+- GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, ~status);
+-
+- if ((status & icrEtherIntSum) == 0 &&
+- !(status & (icrTxBufferLow|icrTxBufferHigh|icrRxBuffer)))
+- break;
+-
+- handled = 1;
+-
+- if (status & icrMIIPhySTC) {
+- u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS);
+- if (gp->last_psr != psr) {
+- dbg(0, "port status:\n");
+- dbg(0, " %s MBit/s, %s-duplex, "
+- "flow-control %s, link is %s,\n",
+- psr & psrSpeed ? "100":"10",
+- psr & psrDuplex ? "full":"half",
+- psr & psrFctl ? "disabled":"enabled",
+- psr & psrLink ? "up":"down");
+- dbg(0, " TxLowQ is %s, TxHighQ is %s, "
+- "Transmitter is %s\n",
+- psr & psrTxLow ? "running":"stopped",
+- psr & psrTxHigh ? "running":"stopped",
+- psr & psrTxInProg ? "on":"off");
+-
+- if ((psr & psrLink) && !gp->tx_full &&
+- netif_queue_stopped(dev)) {
+- dbg(0, "%s: Link up, waking queue.\n",
+- __FUNCTION__);
+- netif_wake_queue(dev);
+- } else if (!(psr & psrLink) &&
+- !netif_queue_stopped(dev)) {
+- dbg(0, "%s: Link down, stopping queue.\n",
+- __FUNCTION__);
+- netif_stop_queue(dev);
+- }
+-
+- gp->last_psr = psr;
+- }
+-
+- if (--gp->intr_work_done == 0)
+- break;
+- }
+-
+- if (status & (icrTxBufferLow | icrTxEndLow))
+- gt96100_tx_complete(dev, status);
+-
+- if (status & (icrRxBuffer | icrRxError)) {
+- gt96100_rx(dev, status);
+- }
+-
+- // Now check TX errors (RX errors were handled in gt96100_rx)
+- if (status & icrTxErrorLow) {
+- err("%s: Tx resource error\n", __FUNCTION__);
+- if (--gp->intr_work_done == 0)
+- break;
+- }
+-
+- if (status & icrTxUdr) {
+- err("%s: Tx underrun error\n", __FUNCTION__);
+- if (--gp->intr_work_done == 0)
+- break;
+- }
+- }
+-
+- if (gp->intr_work_done == 0) {
+- // ACK any remaining pending interrupts
+- GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
+- dbg(3, "%s: hit max work\n", __FUNCTION__);
+- }
+-
+- dbg(3, "%s: exit, icr=%x\n", __FUNCTION__,
+- GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
+-
+- spin_unlock(&gp->lock);
+- return IRQ_RETVAL(handled);
+-}
+-
+-
+-static void
+-gt96100_tx_timeout(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- unsigned long flags;
+-
+- spin_lock_irqsave(&gp->lock, flags);
+-
+- if (!(gp->last_psr & psrLink)) {
+- err("tx_timeout: link down.\n");
+- spin_unlock_irqrestore(&gp->lock, flags);
+- } else {
+- if (gt96100_check_tx_consistent(gp))
+- err("tx_timeout: Tx ring error.\n");
+-
+- disable_ether_irq(dev);
+- spin_unlock_irqrestore(&gp->lock, flags);
+- reset_tx(dev);
+- enable_ether_irq(dev);
+-
+- netif_wake_queue(dev);
+- }
+-}
+-
+-
+-static void
+-gt96100_set_rx_mode(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- unsigned long flags;
+- //struct dev_mc_list *mcptr;
+-
+- dbg(3, "%s: dev=%p, flags=%x\n", __FUNCTION__, dev, dev->flags);
+-
+- // stop the Receiver DMA
+- abort(dev, sdcmrAR);
+-
+- spin_lock_irqsave(&gp->lock, flags);
+-
+- if (dev->flags & IFF_PROMISC) {
+- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG,
+- pcrEN | pcrHS | pcrPM);
+- }
+-
+-#if 0
+- /*
+- FIXME: currently multicast doesn't work - need to get hash table
+- working first.
+- */
+- if (dev->mc_count) {
+- // clear hash table
+- memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);
+- // Add our ethernet address
+- gt96100_add_hash_entry(dev, dev->dev_addr);
+-
+- for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
+- dump_hw_addr(2, dev, "%s: addr=", __FUNCTION__,
+- mcptr->dmi_addr);
+- gt96100_add_hash_entry(dev, mcptr->dmi_addr);
+- }
+- }
+-#endif
+-
+- // restart Rx DMA
+- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
+-
+- spin_unlock_irqrestore(&gp->lock, flags);
+-}
+-
+-static struct net_device_stats *
+-gt96100_get_stats(struct net_device *dev)
+-{
+- struct gt96100_private *gp = netdev_priv(dev);
+- unsigned long flags;
+-
+- dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
+-
+- if (netif_device_present(dev)) {
+- spin_lock_irqsave (&gp->lock, flags);
+- update_stats(gp);
+- spin_unlock_irqrestore (&gp->lock, flags);
+- }
+-
+- return &gp->stats;
+-}
+-
+-static void gt96100_cleanup_module(void)
+-{
+- int i;
+- for (i=0; i<NUM_INTERFACES; i++) {
+- struct gt96100_if_t *gtif = >96100_iflist[i];
+- if (gtif->dev != NULL) {
+- struct gt96100_private *gp = (struct gt96100_private *)
+- netdev_priv(gtif->dev);
+- unregister_netdev(gtif->dev);
+- dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma);
+- dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff);
+- dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE
+- + sizeof(gt96100_td_t) * TX_RING_SIZE,
+- gp->rx_ring);
+- free_netdev(gtif->dev);
+- release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
+- }
+- }
+-}
+-
+-static int __init gt96100_setup(char *options)
+-{
+- char *this_opt;
+-
+- if (!options || !*options)
+- return 0;
+-
+- while ((this_opt = strsep (&options, ",")) != NULL) {
+- if (!*this_opt)
+- continue;
+- if (!strncmp(this_opt, "mac0:", 5)) {
+- memcpy(mac0, this_opt+5, 17);
+- mac0[17]= '\0';
+- } else if (!strncmp(this_opt, "mac1:", 5)) {
+- memcpy(mac1, this_opt+5, 17);
+- mac1[17]= '\0';
+- }
+- }
+-
+- return 1;
+-}
+-
+-__setup("gt96100eth=", gt96100_setup);
+-
+-module_init(gt96100_init_module);
+-module_exit(gt96100_cleanup_module);
+-
+-MODULE_AUTHOR("Steve Longerbeam <stevel at mvista.com>");
+-MODULE_DESCRIPTION("GT96100 Ethernet driver");
+diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
+deleted file mode 100644
+index 3b62a87..0000000
+--- a/drivers/net/gt96100eth.h
++++ /dev/null
+@@ -1,346 +0,0 @@
+-/*
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at mvista.com
+- *
+- * ########################################################################
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+- * for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+- *
+- * ########################################################################
+- *
+- * Ethernet driver definitions for the MIPS GT96100 Advanced
+- * Communication Controller.
+- *
+- */
+-#ifndef _GT96100ETH_H
+-#define _GT96100ETH_H
+-
+-#include <asm/galileo-boards/gt96100.h>
+-
+-#define dbg(lvl, format, arg...) \
+- if (lvl <= GT96100_DEBUG) \
+- printk(KERN_DEBUG "%s: " format, dev->name , ## arg)
+-#define err(format, arg...) \
+- printk(KERN_ERR "%s: " format, dev->name , ## arg)
+-#define info(format, arg...) \
+- printk(KERN_INFO "%s: " format, dev->name , ## arg)
+-#define warn(format, arg...) \
+- printk(KERN_WARNING "%s: " format, dev->name , ## arg)
+-
+-/* Keep the ring sizes a power of two for efficiency. */
+-#define TX_RING_SIZE 16
+-#define RX_RING_SIZE 32
+-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+-
+-#define RX_HASH_TABLE_SIZE 16384
+-#define HASH_HOP_NUMBER 12
+-
+-#define NUM_INTERFACES 2
+-
+-#define GT96100ETH_TX_TIMEOUT HZ/4
+-
+-#define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG)
+-#define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE)
+-
+-#ifdef CONFIG_MIPS_EV96100
+-#define GT96100_ETHER0_IRQ 3
+-#define GT96100_ETHER1_IRQ 4
+-#else
+-#define GT96100_ETHER0_IRQ -1
+-#define GT96100_ETHER1_IRQ -1
+-#endif
+-
+-#define REV_GT96100 1
+-#define REV_GT96100A_1 2
+-#define REV_GT96100A 3
+-
+-#define GT96100ETH_READ(gp, offset) \
+- GT96100_READ((gp->port_offset + offset))
+-
+-#define GT96100ETH_WRITE(gp, offset, data) \
+- GT96100_WRITE((gp->port_offset + offset), data)
+-
+-#define GT96100ETH_SETBIT(gp, offset, bits) {\
+- u32 val = GT96100ETH_READ(gp, offset); val |= (u32)(bits); \
+- GT96100ETH_WRITE(gp, offset, val); }
+-
+-#define GT96100ETH_CLRBIT(gp, offset, bits) {\
+- u32 val = GT96100ETH_READ(gp, offset); val &= (u32)(~(bits)); \
+- GT96100ETH_WRITE(gp, offset, val); }
+-
+-
+-/* Bit definitions of the SMI Reg */
+-enum {
+- smirDataMask = 0xffff,
+- smirPhyAdMask = 0x1f<<16,
+- smirPhyAdBit = 16,
+- smirRegAdMask = 0x1f<<21,
+- smirRegAdBit = 21,
+- smirOpCode = 1<<26,
+- smirReadValid = 1<<27,
+- smirBusy = 1<<28
+-};
+-
+-/* Bit definitions of the Port Config Reg */
+-enum pcr_bits {
+- pcrPM = 1,
+- pcrRBM = 2,
+- pcrPBF = 4,
+- pcrEN = 1<<7,
+- pcrLPBKMask = 0x3<<8,
+- pcrLPBKBit = 8,
+- pcrFC = 1<<10,
+- pcrHS = 1<<12,
+- pcrHM = 1<<13,
+- pcrHDM = 1<<14,
+- pcrHD = 1<<15,
+- pcrISLMask = 0x7<<28,
+- pcrISLBit = 28,
+- pcrACCS = 1<<31
+-};
+-
+-/* Bit definitions of the Port Config Extend Reg */
+-enum pcxr_bits {
+- pcxrIGMP = 1,
+- pcxrSPAN = 2,
+- pcxrPAR = 4,
+- pcxrPRIOtxMask = 0x7<<3,
+- pcxrPRIOtxBit = 3,
+- pcxrPRIOrxMask = 0x3<<6,
+- pcxrPRIOrxBit = 6,
+- pcxrPRIOrxOverride = 1<<8,
+- pcxrDPLXen = 1<<9,
+- pcxrFCTLen = 1<<10,
+- pcxrFLP = 1<<11,
+- pcxrFCTL = 1<<12,
+- pcxrMFLMask = 0x3<<14,
+- pcxrMFLBit = 14,
+- pcxrMIBclrMode = 1<<16,
+- pcxrSpeed = 1<<18,
+- pcxrSpeeden = 1<<19,
+- pcxrRMIIen = 1<<20,
+- pcxrDSCPen = 1<<21
+-};
+-
+-/* Bit definitions of the Port Command Reg */
+-enum pcmr_bits {
+- pcmrFJ = 1<<15
+-};
+-
+-
+-/* Bit definitions of the Port Status Reg */
+-enum psr_bits {
+- psrSpeed = 1,
+- psrDuplex = 2,
+- psrFctl = 4,
+- psrLink = 8,
+- psrPause = 1<<4,
+- psrTxLow = 1<<5,
+- psrTxHigh = 1<<6,
+- psrTxInProg = 1<<7
+-};
+-
+-/* Bit definitions of the SDMA Config Reg */
+-enum sdcr_bits {
+- sdcrRCMask = 0xf<<2,
+- sdcrRCBit = 2,
+- sdcrBLMR = 1<<6,
+- sdcrBLMT = 1<<7,
+- sdcrPOVR = 1<<8,
+- sdcrRIFB = 1<<9,
+- sdcrBSZMask = 0x3<<12,
+- sdcrBSZBit = 12
+-};
+-
+-/* Bit definitions of the SDMA Command Reg */
+-enum sdcmr_bits {
+- sdcmrERD = 1<<7,
+- sdcmrAR = 1<<15,
+- sdcmrSTDH = 1<<16,
+- sdcmrSTDL = 1<<17,
+- sdcmrTXDH = 1<<23,
+- sdcmrTXDL = 1<<24,
+- sdcmrAT = 1<<31
+-};
+-
+-/* Bit definitions of the Interrupt Cause Reg */
+-enum icr_bits {
+- icrRxBuffer = 1,
+- icrTxBufferHigh = 1<<2,
+- icrTxBufferLow = 1<<3,
+- icrTxEndHigh = 1<<6,
+- icrTxEndLow = 1<<7,
+- icrRxError = 1<<8,
+- icrTxErrorHigh = 1<<10,
+- icrTxErrorLow = 1<<11,
+- icrRxOVR = 1<<12,
+- icrTxUdr = 1<<13,
+- icrRxBufferQ0 = 1<<16,
+- icrRxBufferQ1 = 1<<17,
+- icrRxBufferQ2 = 1<<18,
+- icrRxBufferQ3 = 1<<19,
+- icrRxErrorQ0 = 1<<20,
+- icrRxErrorQ1 = 1<<21,
+- icrRxErrorQ2 = 1<<22,
+- icrRxErrorQ3 = 1<<23,
+- icrMIIPhySTC = 1<<28,
+- icrSMIdone = 1<<29,
+- icrEtherIntSum = 1<<31
+-};
+-
+-
+-/* The Rx and Tx descriptor lists. */
+-typedef struct {
+-#ifdef DESC_BE
+- u16 byte_cnt;
+- u16 reserved;
+-#else
+- u16 reserved;
+- u16 byte_cnt;
+-#endif
+- u32 cmdstat;
+- u32 next;
+- u32 buff_ptr;
+-} __attribute__ ((packed)) gt96100_td_t;
+-
+-typedef struct {
+-#ifdef DESC_BE
+- u16 buff_sz;
+- u16 byte_cnt;
+-#else
+- u16 byte_cnt;
+- u16 buff_sz;
+-#endif
+- u32 cmdstat;
+- u32 next;
+- u32 buff_ptr;
+-} __attribute__ ((packed)) gt96100_rd_t;
+-
+-
+-/* Values for the Tx command-status descriptor entry. */
+-enum td_cmdstat {
+- txOwn = 1<<31,
+- txAutoMode = 1<<30,
+- txEI = 1<<23,
+- txGenCRC = 1<<22,
+- txPad = 1<<18,
+- txFirst = 1<<17,
+- txLast = 1<<16,
+- txErrorSummary = 1<<15,
+- txReTxCntMask = 0x0f<<10,
+- txReTxCntBit = 10,
+- txCollision = 1<<9,
+- txReTxLimit = 1<<8,
+- txUnderrun = 1<<6,
+- txLateCollision = 1<<5
+-};
+-
+-
+-/* Values for the Rx command-status descriptor entry. */
+-enum rd_cmdstat {
+- rxOwn = 1<<31,
+- rxAutoMode = 1<<30,
+- rxEI = 1<<23,
+- rxFirst = 1<<17,
+- rxLast = 1<<16,
+- rxErrorSummary = 1<<15,
+- rxIGMP = 1<<14,
+- rxHashExpired = 1<<13,
+- rxMissedFrame = 1<<12,
+- rxFrameType = 1<<11,
+- rxShortFrame = 1<<8,
+- rxMaxFrameLen = 1<<7,
+- rxOverrun = 1<<6,
+- rxCollision = 1<<4,
+- rxCRCError = 1
+-};
+-
+-/* Bit fields of a Hash Table Entry */
+-enum hash_table_entry {
+- hteValid = 1,
+- hteSkip = 2,
+- hteRD = 4
+-};
+-
+-// The MIB counters
+-typedef struct {
+- u32 byteReceived;
+- u32 byteSent;
+- u32 framesReceived;
+- u32 framesSent;
+- u32 totalByteReceived;
+- u32 totalFramesReceived;
+- u32 broadcastFramesReceived;
+- u32 multicastFramesReceived;
+- u32 cRCError;
+- u32 oversizeFrames;
+- u32 fragments;
+- u32 jabber;
+- u32 collision;
+- u32 lateCollision;
+- u32 frames64;
+- u32 frames65_127;
+- u32 frames128_255;
+- u32 frames256_511;
+- u32 frames512_1023;
+- u32 frames1024_MaxSize;
+- u32 macRxError;
+- u32 droppedFrames;
+- u32 outMulticastFrames;
+- u32 outBroadcastFrames;
+- u32 undersizeFrames;
+-} mib_counters_t;
+-
+-
+-struct gt96100_private {
+- gt96100_rd_t* rx_ring;
+- gt96100_td_t* tx_ring;
+- // The Rx and Tx rings must be 16-byte aligned
+- dma_addr_t rx_ring_dma;
+- dma_addr_t tx_ring_dma;
+- char* hash_table;
+- // The Hash Table must be 8-byte aligned
+- dma_addr_t hash_table_dma;
+- int hash_mode;
+-
+- // The Rx buffers must be 8-byte aligned
+- char* rx_buff;
+- dma_addr_t rx_buff_dma;
+- // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
+- // of payload must be 8-byte aligned
+- struct sk_buff* tx_skbuff[TX_RING_SIZE];
+- int rx_next_out; /* The next free ring entry to receive */
+- int tx_next_in; /* The next free ring entry to send */
+- int tx_next_out; /* The last ring entry the ISR processed */
+- int tx_count; /* current # of pkts waiting to be sent in Tx ring */
+- int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
+- int tx_full; /* Tx ring is full */
+-
+- mib_counters_t mib;
+- struct net_device_stats stats;
+-
+- int port_num; // 0 or 1
+- int chip_rev;
+- u32 port_offset;
+-
+- int phy_addr; // PHY address
+- u32 last_psr; // last value of the port status register
+-
+- int options; /* User-settable misc. driver options. */
+- struct timer_list timer;
+- spinlock_t lock; /* Serialise access to device */
+-};
+-
+-#endif
+diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
+index 409c6aa..c3c0d67 100644
+--- a/drivers/net/hamachi.c
++++ b/drivers/net/hamachi.c
+@@ -3,7 +3,7 @@
+ Written 1998-2000 by Donald Becker.
+ Updates 2000 by Keith Underwood.
+
+- This software may be used and distributed according to the terms of
++ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+@@ -27,8 +27,8 @@
+ */
+
+ #define DRV_NAME "hamachi"
+-#define DRV_VERSION "2.0"
+-#define DRV_RELDATE "June 27, 2006"
++#define DRV_VERSION "2.1"
++#define DRV_RELDATE "Sept 11, 2006"
+
+
+ /* A few user-configurable values. */
+@@ -46,7 +46,7 @@ static int mtu;
+ static int max_rx_latency = 0x11;
+ static int max_rx_gap = 0x05;
+ static int min_rx_pkt = 0x18;
+-static int max_tx_latency = 0x00;
++static int max_tx_latency = 0x00;
+ static int max_tx_gap = 0x00;
+ static int min_tx_pkt = 0x30;
+
+@@ -76,7 +76,7 @@ static int force32;
+ - The next bit can be used to force half-duplex. This is a bad
+ idea since no known implementations implement half-duplex, and,
+ in general, half-duplex for gigabit ethernet is a bad idea.
+- 0x00000080 : Force half-duplex
++ 0x00000080 : Force half-duplex
+ Default is full-duplex.
+ - In the original driver, the ninth bit could be used to force
+ full-duplex. Maintain that for compatibility
+@@ -87,7 +87,7 @@ static int options[MAX_UNITS] = {-1, -1,
+ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+ /* The Hamachi chipset supports 3 parameters each for Rx and Tx
+ * interruput management. Parameters will be loaded as specified into
+- * the TxIntControl and RxIntControl registers.
++ * the TxIntControl and RxIntControl registers.
+ *
+ * The registers are arranged as follows:
+ * 23 - 16 15 - 8 7 - 0
+@@ -95,10 +95,10 @@ static int full_duplex[MAX_UNITS] = {-1,
+ * | min_pkt | max_gap | max_latency |
+ * ---------------------------------
+ * min_pkt : The minimum number of packets processed between
+- * interrupts.
++ * interrupts.
+ * max_gap : The maximum inter-packet gap in units of 8.192 us
+ * max_latency : The absolute time between interrupts in units of 8.192 us
+- *
++ *
+ */
+ static int rx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+@@ -183,7 +183,7 @@ KERN_INFO " Further modifications by K
+ other linux headers causing many compiler warnings.
+ */
+ #ifndef IP_MF
+- #define IP_MF 0x2000 /* IP more frags from <netinet/ip.h> */
++ #define IP_MF 0x2000 /* IP more frags from <netinet/ip.h> */
+ #endif
+
+ /* Define IP_OFFSET to be IPOPT_OFFSET */
+@@ -204,9 +204,9 @@ KERN_INFO " Further modifications by K
+ /* Condensed bus+endian portability operations. */
+ #if ADDRLEN == 64
+ #define cpu_to_leXX(addr) cpu_to_le64(addr)
+-#else
++#else
+ #define cpu_to_leXX(addr) cpu_to_le32(addr)
+-#endif
++#endif
+
+
+ /*
+@@ -291,30 +291,30 @@ Hamachi Engineering Design Specification
+
+ IVc. Errata
+
+-None noted.
++None noted.
+
+ V. Recent Changes
+
+-01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears
++01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears
+ to help avoid some stall conditions -- this needs further research.
+
+-01/15/1999 EPK Creation of the hamachi_tx function. This function cleans
++01/15/1999 EPK Creation of the hamachi_tx function. This function cleans
+ the Tx ring and is called from hamachi_start_xmit (this used to be
+ called from hamachi_interrupt but it tends to delay execution of the
+ interrupt handler and thus reduce bandwidth by reducing the latency
+- between hamachi_rx()'s). Notably, some modification has been made so
+- that the cleaning loop checks only to make sure that the DescOwn bit
+- isn't set in the status flag since the card is not required
++ between hamachi_rx()'s). Notably, some modification has been made so
++ that the cleaning loop checks only to make sure that the DescOwn bit
++ isn't set in the status flag since the card is not required
+ to set the entire flag to zero after processing.
+
+-01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is
++01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is
+ checked before attempting to add a buffer to the ring. If the ring is full
+ an attempt is made to free any dirty buffers and thus find space for
+ the new buffer or the function returns non-zero which should case the
+ scheduler to reschedule the buffer later.
+
+-01/15/1999 EPK Some adjustments were made to the chip initialization.
+- End-to-end flow control should now be fully active and the interrupt
++01/15/1999 EPK Some adjustments were made to the chip initialization.
++ End-to-end flow control should now be fully active and the interrupt
+ algorithm vars have been changed. These could probably use further tuning.
+
+ 01/15/1999 EPK Added the max_{rx,tx}_latency options. These are used to
+@@ -322,7 +322,7 @@ V. Recent Changes
+ problems with network stalls, try setting these to higher values.
+ Valid values are 0x00 through 0xff.
+
+-01/15/1999 EPK In general, the overall bandwidth has increased and
++01/15/1999 EPK In general, the overall bandwidth has increased and
+ latencies are better (sometimes by a factor of 2). Stalls are rare at
+ this point, however there still appears to be a bug somewhere between the
+ hardware and driver. TCP checksum errors under load also appear to be
+@@ -334,20 +334,20 @@ V. Recent Changes
+ rings was typically getting set correctly, but the Tx ring wasn't getting
+ the DescEndRing bit set during initialization. ??? Does this mean the
+ hamachi card is using the DescEndRing in processing even if a particular
+- slot isn't in use -- hypothetically, the card might be searching the
++ slot isn't in use -- hypothetically, the card might be searching the
+ entire Tx ring for slots with the DescOwn bit set and then processing
+ them. If the DescEndRing bit isn't set, then it might just wander off
+ through memory until it hits a chunk of data with that bit set
+ and then looping back.
+
+-02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout
++02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout
+ problem (TxCmd and RxCmd need only to be set when idle or stopped.
+
+ 02/09/1999 EPK Added code to check/reset dev->tbusy in hamachi_interrupt.
+- (Michel Mueller pointed out the ``permanently busy'' potential
++ (Michel Mueller pointed out the ``permanently busy'' potential
+ problem here).
+
+-02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies.
++02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies.
+
+ 02/23/1999 EPK Verified that the interrupt status field bits for Tx were
+ incorrectly defined and corrected (as per Michel Mueller).
+@@ -363,7 +363,7 @@ V. Recent Changes
+
+ 02/20/2000 KDU Some of the control was just plain odd. Cleaned up the
+ hamachi_start_xmit() and hamachi_interrupt() code. There is still some
+-re-structuring I would like to do.
++re-structuring I would like to do.
+
+ 03/01/2000 KDU Experimenting with a WIDE range of interrupt mitigation
+ parameters on a dual P3-450 setup yielded the new default interrupt
+@@ -371,25 +371,25 @@ mitigation parameters. Tx should interr
+ Eric's scheme. Rx should be more often...
+
+ 03/13/2000 KDU Added a patch to make the Rx Checksum code interact
+-nicely with non-linux machines.
++nicely with non-linux machines.
+
+-03/13/2000 KDU Experimented with some of the configuration values:
++03/13/2000 KDU Experimented with some of the configuration values:
+
+ -It seems that enabling PCI performance commands for descriptors
+- (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal
+- performance impact for any of my tests. (ttcp, netpipe, netperf) I will
++ (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal
++ performance impact for any of my tests. (ttcp, netpipe, netperf) I will
+ leave them that way until I hear further feedback.
+
+- -Increasing the PCI_LATENCY_TIMER to 130
++ -Increasing the PCI_LATENCY_TIMER to 130
+ (2 + (burst size of 128 * (0 wait states + 1))) seems to slightly
+ degrade performance. Leaving default at 64 pending further information.
+
+-03/14/2000 KDU Further tuning:
++03/14/2000 KDU Further tuning:
+
+ -adjusted boguscnt in hamachi_rx() to depend on interrupt
+ mitigation parameters chosen.
+
+- -Selected a set of interrupt parameters based on some extensive testing.
++ -Selected a set of interrupt parameters based on some extensive testing.
+ These may change with more testing.
+
+ TO DO:
+@@ -398,14 +398,14 @@ TO DO:
+ PCI_COMMAND_INVALIDATE. Set maximum burst size to cache line size in
+ that case.
+
+--fix the reset procedure. It doesn't quite work.
++-fix the reset procedure. It doesn't quite work.
+ */
+
+ /* A few values that may be tweaked. */
+ /* Size of each temporary Rx buffer, calculated as:
+ * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for
+ * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum +
+- * 2 more because we use skb_reserve.
++ * 2 more because we use skb_reserve.
+ */
+ #define PKT_BUF_SZ 1538
+
+@@ -465,7 +465,7 @@ enum intr_status_bits {
+
+ /* The Hamachi Rx and Tx buffer descriptors. */
+ struct hamachi_desc {
+- u32 status_n_length;
++ u32 status_n_length;
+ #if ADDRLEN == 64
+ u32 pad;
+ u64 addr;
+@@ -476,7 +476,7 @@ struct hamachi_desc {
+
+ /* Bits in hamachi_desc.status_n_length */
+ enum desc_status_bits {
+- DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000,
++ DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000,
+ DescIntr=0x10000000,
+ };
+
+@@ -546,7 +546,7 @@ MODULE_PARM_DESC(tx_params, "GNIC-II min
+ MODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex");
+ MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)");
+ MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
+-
++
+ static int read_eeprom(void __iomem *ioaddr, int location);
+ static int mdio_read(struct net_device *dev, int phy_id, int location);
+ static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+@@ -556,15 +556,15 @@ static void hamachi_timer(unsigned long
+ static void hamachi_tx_timeout(struct net_device *dev);
+ static void hamachi_init_ring(struct net_device *dev);
+ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t hamachi_interrupt(int irq, void *dev_instance);
+ static int hamachi_rx(struct net_device *dev);
+ static inline int hamachi_tx(struct net_device *dev);
+ static void hamachi_error(struct net_device *dev, int intr_status);
+ static int hamachi_close(struct net_device *dev);
+ static struct net_device_stats *hamachi_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
+-static struct ethtool_ops ethtool_ops_no_mii;
++static const struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops_no_mii;
+
+ static int __devinit hamachi_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+@@ -659,7 +659,7 @@ static int __devinit hamachi_init_one (s
+ option = dev->mem_start;
+
+ /* If the bus size is misidentified, do the following. */
+- force32 = force32 ? force32 :
++ force32 = force32 ? force32 :
+ ((option >= 0) ? ((option & 0x00000070) >> 4) : 0 );
+ if (force32)
+ writeb(force32, ioaddr + VirtualJumpers);
+@@ -671,11 +671,11 @@ static int __devinit hamachi_init_one (s
+ * be valid for a moment. Wait for a little while until it is. If
+ * it takes more than 10ms, forget it.
+ */
+- udelay(10);
++ udelay(10);
+ i = readb(ioaddr + PCIClkMeas);
+ for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){
+- udelay(10);
+- i = readb(ioaddr + PCIClkMeas);
++ udelay(10);
++ i = readb(ioaddr + PCIClkMeas);
+ }
+
+ hmp->base = ioaddr;
+@@ -714,9 +714,9 @@ static int __devinit hamachi_init_one (s
+
+ rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1;
+ tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1;
+- hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var :
++ hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var :
+ (min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency);
+- hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var :
++ hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var :
+ (min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency);
+
+
+@@ -783,10 +783,10 @@ static int __devinit hamachi_init_one (s
+ return 0;
+
+ err_out_unmap_rx:
+- pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
++ pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
+ hmp->rx_ring_dma);
+ err_out_unmap_tx:
+- pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
++ pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
+ hmp->tx_ring_dma);
+ err_out_cleardev:
+ free_netdev (dev);
+@@ -856,7 +856,7 @@ static void mdio_write(struct net_device
+ return;
+ }
+
+-
++
+ static int hamachi_open(struct net_device *dev)
+ {
+ struct hamachi_private *hmp = netdev_priv(dev);
+@@ -886,7 +886,7 @@ static int hamachi_open(struct net_devic
+ writel(cpu_to_le32(hmp->tx_ring_dma), ioaddr + TxPtr);
+ #endif
+
+- /* TODO: It would make sense to organize this as words since the card
++ /* TODO: It would make sense to organize this as words since the card
+ * documentation does. -KDU
+ */
+ for (i = 0; i < 6; i++)
+@@ -898,36 +898,36 @@ static int hamachi_open(struct net_devic
+ /* Configure the FIFO */
+ fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6;
+ switch (fifo_info){
+- case 0 :
++ case 0 :
+ /* No FIFO */
+ writew(0x0000, ioaddr + FIFOcfg);
+ break;
+- case 1 :
++ case 1 :
+ /* Configure the FIFO for 512K external, 16K used for Tx. */
+ writew(0x0028, ioaddr + FIFOcfg);
+ break;
+- case 2 :
++ case 2 :
+ /* Configure the FIFO for 1024 external, 32K used for Tx. */
+ writew(0x004C, ioaddr + FIFOcfg);
+ break;
+- case 3 :
++ case 3 :
+ /* Configure the FIFO for 2048 external, 32K used for Tx. */
+ writew(0x006C, ioaddr + FIFOcfg);
+ break;
+- default :
++ default :
+ printk(KERN_WARNING "%s: Unsupported external memory config!\n",
+ dev->name);
+ /* Default to no FIFO */
+ writew(0x0000, ioaddr + FIFOcfg);
+ break;
+ }
+-
++
+ if (dev->if_port == 0)
+ dev->if_port = hmp->default_port;
+
+
+ /* Setting the Rx mode will start the Rx process. */
+- /* If someone didn't choose a duplex, default to full-duplex */
++ /* If someone didn't choose a duplex, default to full-duplex */
+ if (hmp->duplex_lock != 1)
+ hmp->mii_if.full_duplex = 1;
+
+@@ -940,7 +940,7 @@ static int hamachi_open(struct net_devic
+ #endif
+ writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */
+ writew(0x215F, ioaddr + MACCnfg);
+- writew(0x000C, ioaddr + FrameGap0);
++ writew(0x000C, ioaddr + FrameGap0);
+ /* WHAT?!?!? Why isn't this documented somewhere? -KDU */
+ writew(0x1018, ioaddr + FrameGap1);
+ /* Why do we enable receives/transmits here? -KDU */
+@@ -962,16 +962,16 @@ static int hamachi_open(struct net_devic
+
+ if (hamachi_debug > 1) {
+ printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n",
+- tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8,
++ tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8,
+ (tx_int_var & 0x00ff0000) >> 16);
+ printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n",
+- rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8,
++ rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8,
+ (rx_int_var & 0x00ff0000) >> 16);
+ printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var);
+ }
+
+- writel(tx_int_var, ioaddr + TxIntrCtrl);
+- writel(rx_int_var, ioaddr + RxIntrCtrl);
++ writel(tx_int_var, ioaddr + TxIntrCtrl);
++ writel(rx_int_var, ioaddr + RxIntrCtrl);
+
+ set_rx_mode(dev);
+
+@@ -1016,21 +1016,21 @@ static inline int hamachi_tx(struct net_
+ int entry = hmp->dirty_tx % TX_RING_SIZE;
+ struct sk_buff *skb;
+
+- if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
++ if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
+ break;
+ /* Free the original skb. */
+ skb = hmp->tx_skbuff[entry];
+ if (skb != 0) {
+- pci_unmap_single(hmp->pci_dev,
+- hmp->tx_ring[entry].addr, skb->len,
++ pci_unmap_single(hmp->pci_dev,
++ hmp->tx_ring[entry].addr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+ hmp->tx_skbuff[entry] = NULL;
+ }
+ hmp->tx_ring[entry].status_n_length = 0;
+- if (entry >= TX_RING_SIZE-1)
++ if (entry >= TX_RING_SIZE-1)
+ hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
+- cpu_to_le32(DescEndRing);
++ cpu_to_le32(DescEndRing);
+ hmp->stats.tx_packets++;
+ }
+
+@@ -1082,7 +1082,7 @@ static void hamachi_tx_timeout(struct ne
+ printk("\n");
+ }
+
+- /* Reinit the hardware and make sure the Rx and Tx processes
++ /* Reinit the hardware and make sure the Rx and Tx processes
+ are up and running.
+ */
+ dev->if_port = 0;
+@@ -1092,7 +1092,7 @@ static void hamachi_tx_timeout(struct ne
+ * -Turn off MAC receiver
+ * -Issue Reset
+ */
+-
++
+ for (i = 0; i < RX_RING_SIZE; i++)
+ hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn);
+
+@@ -1106,11 +1106,11 @@ static void hamachi_tx_timeout(struct ne
+ hmp->tx_ring[i].status_n_length = cpu_to_le32(
+ DescEndRing |
+ (hmp->tx_ring[i].status_n_length & 0x0000FFFF));
+- else
++ else
+ hmp->tx_ring[i].status_n_length &= 0x0000ffff;
+ skb = hmp->tx_skbuff[i];
+ if (skb){
+- pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr,
++ pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+ hmp->tx_skbuff[i] = NULL;
+@@ -1119,20 +1119,20 @@ static void hamachi_tx_timeout(struct ne
+
+ udelay(60); /* Sleep 60 us just for safety sake */
+ writew(0x0002, ioaddr + RxCmd); /* STOP Rx */
+-
+- writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */
++
++ writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */
+
+ hmp->tx_full = 0;
+ hmp->cur_rx = hmp->cur_tx = 0;
+ hmp->dirty_rx = hmp->dirty_tx = 0;
+ /* Rx packets are also presumed lost; however, we need to make sure a
+ * ring of buffers is in tact. -KDU
+- */
++ */
+ for (i = 0; i < RX_RING_SIZE; i++){
+ struct sk_buff *skb = hmp->rx_skbuff[i];
+
+ if (skb){
+- pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr,
++ pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr,
+ hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skb);
+ hmp->rx_skbuff[i] = NULL;
+@@ -1146,9 +1146,9 @@ static void hamachi_tx_timeout(struct ne
+ break;
+ 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,
++ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+- hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
++ hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
+ DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2));
+ }
+ hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+@@ -1187,11 +1187,11 @@ static void hamachi_init_ring(struct net
+ #endif
+ /* My attempt at a reasonable correction */
+ /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
+- * card needs room to do 8 byte alignment, +2 so we can reserve
+- * the first 2 bytes, and +16 gets room for the status word from the
++ * card needs room to do 8 byte alignment, +2 so we can reserve
++ * the first 2 bytes, and +16 gets room for the status word from the
+ * card. -KDU
+ */
+- hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ :
++ hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ :
+ (((dev->mtu+26+7) & ~7) + 2 + 16));
+
+ /* Initialize all Rx descriptors. */
+@@ -1207,10 +1207,10 @@ static void hamachi_init_ring(struct net
+ break;
+ 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,
++ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ 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 |
++ hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
+ DescEndPacket | DescIntr | (hmp->rx_buf_sz -2));
+ }
+ hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+@@ -1267,7 +1267,7 @@ static int hamachi_start_xmit(struct sk_
+ unsigned entry;
+ u16 status;
+
+- /* Ok, now make sure that the queue has space before trying to
++ /* Ok, now make sure that the queue has space before trying to
+ add another skbuff. if we return non-zero the scheduler
+ should interpret this as a queue full and requeue the buffer
+ for later.
+@@ -1282,7 +1282,7 @@ static int hamachi_start_xmit(struct sk_
+ if( !(status & 0x0001) || (status & 0x0002))
+ writew(0x0001, hmp->base + TxCmd);
+ return 1;
+- }
++ }
+
+ /* Caution: the write order is important here, set the field
+ with the "ownership" bits last. */
+@@ -1322,15 +1322,15 @@ static int hamachi_start_xmit(struct sk_
+ }
+ #endif
+
+- hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
++ hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ skb->data, skb->len, PCI_DMA_TODEVICE));
+-
++
+ /* Hmmmm, could probably put a DescIntr on these, but the way
+ the driver is currently coded makes Tx interrupts unnecessary
+ since the clearing of the Tx ring is handled by the start_xmit
+ routine. This organization helps mitigate the interrupts a
+ bit and probably renders the max_tx_latency param useless.
+-
++
+ Update: Putting a DescIntr bit on all of the descriptors and
+ mitigating interrupt frequency with the tx_min_pkt parameter. -KDU
+ */
+@@ -1359,7 +1359,7 @@ static int hamachi_start_xmit(struct sk_
+ * hence, any packet that got put off because we were in the transmit
+ * routine should IMMEDIATELY get a chance to be re-queued. -KDU
+ */
+- if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4))
++ if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4))
+ netif_wake_queue(dev); /* Typical path */
+ else {
+ hmp->tx_full = 1;
+@@ -1376,7 +1376,7 @@ static int hamachi_start_xmit(struct sk_
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t hamachi_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct hamachi_private *hmp = netdev_priv(dev);
+@@ -1412,27 +1412,27 @@ static irqreturn_t hamachi_interrupt(int
+ /* This code should RARELY need to execute. After all, this is
+ * a gigabit link, it should consume packets as fast as we put
+ * them in AND we clear the Tx ring in hamachi_start_xmit().
+- */
++ */
+ if (hmp->tx_full){
+ for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){
+ int entry = hmp->dirty_tx % TX_RING_SIZE;
+ struct sk_buff *skb;
+
+- if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
++ if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
+ break;
+ skb = hmp->tx_skbuff[entry];
+ /* Free the original skb. */
+ if (skb){
+- pci_unmap_single(hmp->pci_dev,
+- hmp->tx_ring[entry].addr,
++ pci_unmap_single(hmp->pci_dev,
++ hmp->tx_ring[entry].addr,
+ skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+ hmp->tx_skbuff[entry] = NULL;
+ }
+ hmp->tx_ring[entry].status_n_length = 0;
+- if (entry >= TX_RING_SIZE-1)
+- hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
++ if (entry >= TX_RING_SIZE-1)
++ hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
+ cpu_to_le32(DescEndRing);
+ hmp->stats.tx_packets++;
+ }
+@@ -1498,9 +1498,9 @@ static int hamachi_rx(struct net_device
+ struct hamachi_desc *desc = &(hmp->rx_ring[entry]);
+ u32 desc_status = le32_to_cpu(desc->status_n_length);
+ u16 data_size = desc_status; /* Implicit truncate */
+- u8 *buf_addr;
++ u8 *buf_addr;
+ s32 frame_status;
+-
++
+ if (desc_status & DescOwn)
+ break;
+ pci_dma_sync_single_for_cpu(hmp->pci_dev,
+@@ -1540,7 +1540,7 @@ static int hamachi_rx(struct net_device
+ } else {
+ struct sk_buff *skb;
+ /* Omit CRC */
+- u16 pkt_len = (frame_status & 0x07ff) - 4;
++ u16 pkt_len = (frame_status & 0x07ff) - 4;
+ #ifdef RX_CHECKSUM
+ u32 pfck = *(u32 *) &buf_addr[data_size - 8];
+ #endif
+@@ -1576,7 +1576,7 @@ static int hamachi_rx(struct net_device
+ PCI_DMA_FROMDEVICE);
+ /* Call copy + cksum if available. */
+ #if 1 || USE_IP_COPYSUM
+- eth_copy_and_sum(skb,
++ eth_copy_and_sum(skb,
+ hmp->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_put(skb, pkt_len);
+ #else
+@@ -1588,7 +1588,7 @@ static int hamachi_rx(struct net_device
+ hmp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ } else {
+- pci_unmap_single(hmp->pci_dev,
++ pci_unmap_single(hmp->pci_dev,
+ hmp->rx_ring[entry].addr,
+ hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ skb_put(skb = hmp->rx_skbuff[entry], pkt_len);
+@@ -1619,18 +1619,18 @@ static int hamachi_rx(struct net_device
+ p_r = *p;
+ p_r1 = *(p-1);
+ switch (inv) {
+- case 0:
++ case 0:
+ crc = (p_r & 0xffff) + (p_r >> 16);
+ break;
+- case 1:
++ case 1:
+ crc = (p_r >> 16) + (p_r & 0xffff)
+- + (p_r1 >> 16 & 0xff00);
++ + (p_r1 >> 16 & 0xff00);
+ break;
+- case 2:
+- crc = p_r + (p_r1 >> 16);
++ case 2:
++ crc = p_r + (p_r1 >> 16);
+ break;
+- case 3:
+- crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16);
++ case 3:
++ crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16);
+ break;
+ default: /*NOTREACHED*/ crc = 0;
+ }
+@@ -1648,9 +1648,9 @@ static int hamachi_rx(struct net_device
+ * could do the pseudo myself and return
+ * CHECKSUM_UNNECESSARY
+ */
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+- }
++ }
+ }
+ #endif /* RX_CHECKSUM */
+
+@@ -1675,15 +1675,15 @@ static int hamachi_rx(struct net_device
+ break; /* Better luck next round. */
+ 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,
++ desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ 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)
+- desc->status_n_length |= cpu_to_le32(DescOwn |
++ desc->status_n_length |= cpu_to_le32(DescOwn |
+ DescEndPacket | DescEndRing | DescIntr);
+ else
+- desc->status_n_length |= cpu_to_le32(DescOwn |
++ desc->status_n_length |= cpu_to_le32(DescOwn |
+ DescEndPacket | DescIntr);
+ }
+
+@@ -1794,8 +1794,8 @@ static int hamachi_close(struct net_devi
+ hmp->rx_ring[i].status_n_length = 0;
+ hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+ if (skb) {
+- pci_unmap_single(hmp->pci_dev,
+- hmp->rx_ring[i].addr, hmp->rx_buf_sz,
++ pci_unmap_single(hmp->pci_dev,
++ hmp->rx_ring[i].addr, hmp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skb);
+ hmp->rx_skbuff[i] = NULL;
+@@ -1804,8 +1804,8 @@ static int hamachi_close(struct net_devi
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ skb = hmp->tx_skbuff[i];
+ if (skb) {
+- pci_unmap_single(hmp->pci_dev,
+- hmp->tx_ring[i].addr, skb->len,
++ pci_unmap_single(hmp->pci_dev,
++ hmp->tx_ring[i].addr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+ hmp->tx_skbuff[i] = NULL;
+@@ -1829,7 +1829,7 @@ static struct net_device_stats *hamachi_
+ according to ifconfig. It does get incremented in hamachi_tx(),
+ so I think I'll comment it out here and see if better things
+ happen.
+- */
++ */
+ /* hmp->stats.tx_packets = readl(ioaddr + 0x000); */
+
+ hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */
+@@ -1851,8 +1851,6 @@ static void set_rx_mode(struct net_devic
+ void __iomem *ioaddr = hmp->base;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ writew(0x000F, ioaddr + AddrMode);
+ } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to match, or accept all multicasts. */
+@@ -1921,7 +1919,7 @@ static u32 hamachi_get_link(struct net_d
+ return mii_link_ok(&np->mii_if);
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .begin = check_if_running,
+ .get_drvinfo = hamachi_get_drvinfo,
+ .get_settings = hamachi_get_settings,
+@@ -1930,7 +1928,7 @@ static struct ethtool_ops ethtool_ops =
+ .get_link = hamachi_get_link,
+ };
+
+-static struct ethtool_ops ethtool_ops_no_mii = {
++static const struct ethtool_ops ethtool_ops_no_mii = {
+ .begin = check_if_running,
+ .get_drvinfo = hamachi_get_drvinfo,
+ };
+@@ -1978,9 +1976,9 @@ static void __devexit hamachi_remove_one
+ if (dev) {
+ struct hamachi_private *hmp = netdev_priv(dev);
+
+- pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
++ pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
+ hmp->rx_ring_dma);
+- pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
++ pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
+ hmp->tx_ring_dma);
+ unregister_netdev(dev);
+ iounmap(hmp->base);
+diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
+index 9220de9..1ed9ccc 100644
+--- a/drivers/net/hamradio/baycom_epp.c
++++ b/drivers/net/hamradio/baycom_epp.c
+@@ -323,7 +323,7 @@ static int eppconfig(struct baycom_state
+
+ /* ---------------------------------------------------------------------- */
+
+-static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void epp_interrupt(int irq, void *dev_id)
+ {
+ }
+
+diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
+index 77411a0..5930aeb 100644
+--- a/drivers/net/hamradio/baycom_par.c
++++ b/drivers/net/hamradio/baycom_par.c
+@@ -270,7 +270,7 @@ static __inline__ void par96_rx(struct n
+
+ /* --------------------------------------------------------------------- */
+
+-static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void par96_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct baycom_state *bc = netdev_priv(dev);
+diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
+index 55906c7..59214e7 100644
+--- a/drivers/net/hamradio/baycom_ser_fdx.c
++++ b/drivers/net/hamradio/baycom_ser_fdx.c
+@@ -279,7 +279,7 @@ static __inline__ void ser12_rx(struct n
+
+ /* --------------------------------------------------------------------- */
+
+-static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ser12_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct baycom_state *bc = netdev_priv(dev);
+diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
+index de95de8..3bcc57a 100644
+--- a/drivers/net/hamradio/baycom_ser_hdx.c
++++ b/drivers/net/hamradio/baycom_ser_hdx.c
+@@ -373,7 +373,7 @@ static inline void ser12_rx(struct net_d
+
+ /* --------------------------------------------------------------------- */
+
+-static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ser12_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct baycom_state *bc = netdev_priv(dev);
+diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
+index c9a46b8..0f8b9af 100644
+--- a/drivers/net/hamradio/dmascc.c
++++ b/drivers/net/hamradio/dmascc.c
+@@ -249,7 +249,7 @@ static void start_timer(struct scc_priv
+ static inline unsigned char random(void);
+
+ static inline void z8530_isr(struct scc_info *info);
+-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t scc_isr(int irq, void *dev_id);
+ static void rx_isr(struct scc_priv *priv);
+ static void special_condition(struct scc_priv *priv, int rc);
+ static void rx_bh(void *arg);
+@@ -1142,7 +1142,7 @@ static inline void z8530_isr(struct scc_
+ }
+
+
+-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t scc_isr(int irq, void *dev_id)
+ {
+ struct scc_info *info = dev_id;
+
+diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
+index df4b681..ec9b6d9 100644
+--- a/drivers/net/hamradio/scc.c
++++ b/drivers/net/hamradio/scc.c
+@@ -200,7 +200,7 @@ static void z8530_init(void);
+
+ static void init_channel(struct scc_channel *scc);
+ static void scc_key_trx (struct scc_channel *scc, char tx);
+-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t scc_isr(int irq, void *dev_id);
+ static void scc_init_timer(struct scc_channel *scc);
+
+ static int scc_net_alloc(const char *name, struct scc_channel *scc);
+@@ -626,7 +626,7 @@ static void scc_isr_dispatch(struct scc_
+
+ #define SCC_IRQTIMEOUT 30000
+
+-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t scc_isr(int irq, void *dev_id)
+ {
+ unsigned char vector;
+ struct scc_channel *scc;
+diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
+index f98f577..3c4455b 100644
+--- a/drivers/net/hamradio/yam.c
++++ b/drivers/net/hamradio/yam.c
+@@ -702,7 +702,7 @@ static void yam_tx_byte(struct net_devic
+ * ISR routine
+ ************************************************************************************/
+
+-static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t yam_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev;
+ struct yam_port *yp;
+diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
+index e26a3e4..6abcfd2 100644
+--- a/drivers/net/hp-plus.c
++++ b/drivers/net/hp-plus.c
+@@ -112,7 +112,7 @@ static void hpp_io_block_output(struct n
+ static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+
+-
++
+ /* Probe a list of addresses for an HP LAN+ adaptor.
+ This routine is almost boilerplate. */
+
+@@ -430,7 +430,7 @@ hpp_mem_block_output(struct net_device *
+ return;
+ }
+
+-
++
+ #ifdef MODULE
+ #define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */
+ static struct net_device *dev_hpp[MAX_HPP_CARDS];
+diff --git a/drivers/net/hp.c b/drivers/net/hp.c
+index 551a71b..2947097 100644
+--- a/drivers/net/hp.c
++++ b/drivers/net/hp.c
+@@ -75,7 +75,7 @@ static void hp_init_card(struct net_devi
+ /* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
+ static char irqmap[16] __initdata= { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
+
+-
++
+ /* Probe for an HP LAN adaptor.
+ Also initialize the card and fill in STATION_ADDR with the station
+ address. */
+diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
+index e7d9bf3..844c136 100644
+--- a/drivers/net/hp100.c
++++ b/drivers/net/hp100.c
+@@ -1,24 +1,24 @@
+ /*
+-** hp100.c
++** hp100.c
+ ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
+ **
+ ** $Id: hp100.c,v 1.58 2001/09/24 18:03:01 perex Exp perex $
+ **
+ ** Based on the HP100 driver written by Jaroslav Kysela <perex at jcu.cz>
+-** Extended for new busmaster capable chipsets by
++** Extended for new busmaster capable chipsets by
+ ** Siegfried "Frieder" Loeffler (dg1sek) <floeff at mathematik.uni-stuttgart.de>
+ **
+ ** Maintained by: Jaroslav Kysela <perex at suse.cz>
+-**
++**
+ ** This driver has only been tested with
+ ** -- HP J2585B 10/100 Mbit/s PCI Busmaster
+-** -- HP J2585A 10/100 Mbit/s PCI
++** -- HP J2585A 10/100 Mbit/s PCI
+ ** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC
+ ** -- HP J2973A 10 Mbit/s PCI 10base-T
+ ** -- HP J2573 10/100 ISA
+ ** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA
+ ** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI
+-**
++**
+ ** but it should also work with the other CASCADE based adapters.
+ **
+ ** TODO:
+@@ -65,7 +65,7 @@
+ ** - timing changes in xmit routines, relogin to 100VG hub added when
+ ** driver does reset
+ ** - included fix for Compex FreedomLine PCI adapter
+-**
++**
+ ** 1.54 -> 1.55
+ ** - fixed bad initialization in init_module
+ ** - added Compex FreedomLine adapter
+@@ -73,10 +73,10 @@
+ **
+ ** 1.53 -> 1.54
+ ** - added hardware multicast filter support (doesn't work)
+-** - little changes in hp100_sense_lan routine
++** - little changes in hp100_sense_lan routine
+ ** - added support for Coax and AUI (J2970)
+ ** - fix for multiple cards and hp100_mode parameter (insmod)
+-** - fix for shared IRQ
++** - fix for shared IRQ
+ **
+ ** 1.52 -> 1.53
+ ** - fixed bug in multicast support
+@@ -111,7 +111,6 @@
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
+ #include <linux/types.h>
+-#include <linux/config.h> /* for CONFIG_PCI */
+ #include <linux/delay.h>
+ #include <linux/init.h>
+ #include <linux/bitops.h>
+@@ -189,10 +188,12 @@ struct hp100_private {
+ /*
+ * variables
+ */
++#ifdef CONFIG_ISA
+ static const char *hp100_isa_tbl[] = {
+ "HWPF150", /* HP J2573 rev A */
+ "HWP1950", /* HP J2573 */
+ };
++#endif
+
+ #ifdef CONFIG_EISA
+ static struct eisa_device_id hp100_eisa_tbl[] = {
+@@ -248,7 +249,7 @@ static void hp100_misc_interrupt(struct
+ static void hp100_update_stats(struct net_device *dev);
+ static void hp100_clear_stats(struct hp100_private *lp, int ioaddr);
+ static void hp100_set_multicast_list(struct net_device *dev);
+-static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t hp100_interrupt(int irq, void *dev_id);
+ static void hp100_start_interface(struct net_device *dev);
+ static void hp100_stop_interface(struct net_device *dev);
+ static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr);
+@@ -287,7 +288,7 @@ static inline dma_addr_t virt_to_whateve
+
+ static inline u_int pdl_map_data(struct hp100_private *lp, void *data)
+ {
+- return pci_map_single(lp->pci_dev, data,
++ return pci_map_single(lp->pci_dev, data,
+ MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
+ }
+
+@@ -334,6 +335,7 @@ static __devinit const char *hp100_read_
+ return str;
+ }
+
++#ifdef CONFIG_ISA
+ static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
+ {
+ const char *sig;
+@@ -354,7 +356,7 @@ static __init int hp100_isa_probe1(struc
+ goto err;
+
+ for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) {
+- if (!strcmp(hp100_isa_tbl[i], sig))
++ if (!strcmp(hp100_isa_tbl[i], sig))
+ break;
+
+ }
+@@ -374,11 +376,11 @@ static int __init hp100_isa_probe(struc
+ {
+ int err = -ENODEV;
+
+- /* Probe for a specific ISA address */
++ /* Probe for a specific ISA address */
+ if (addr > 0xff && addr < 0x400)
+ err = hp100_isa_probe1(dev, addr);
+
+- else if (addr != 0)
++ else if (addr != 0)
+ err = -ENXIO;
+
+ else {
+@@ -391,9 +393,9 @@ static int __init hp100_isa_probe(struc
+ }
+ return err;
+ }
++#endif /* CONFIG_ISA */
+
+-
+-#ifndef MODULE
++#if !defined(MODULE) && defined(CONFIG_ISA)
+ struct net_device * __init hp100_probe(int unit)
+ {
+ struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
+@@ -423,7 +425,7 @@ struct net_device * __init hp100_probe(i
+ free_netdev(dev);
+ return ERR_PTR(err);
+ }
+-#endif
++#endif /* !MODULE && CONFIG_ISA */
+
+ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
+ u_char bus, struct pci_dev *pci_dev)
+@@ -449,7 +451,7 @@ static int __devinit hp100_probe1(struct
+ if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100"))
+ goto out1;
+
+- if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE)
++ if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE)
+ goto out2;
+
+ chip = hp100_inw(PAGING) & HP100_CHIPID_MASK;
+@@ -492,7 +494,7 @@ static int __devinit hp100_probe1(struct
+ * Use the variable "hp100_mode" upon insmod or as kernel parameter to
+ * force driver modes:
+ * hp100_mode=1 -> default, use busmaster mode if configured.
+- * hp100_mode=2 -> enable shared memory mode
++ * hp100_mode=2 -> enable shared memory mode
+ * hp100_mode=3 -> force use of i/o mapped mode.
+ * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
+ */
+@@ -690,9 +692,9 @@ static int __devinit hp100_probe1(struct
+ hp100_clear_stats(lp, ioaddr);
+
+ /* If busmaster mode is wanted, a dma-capable memory area is needed for
+- * the rx and tx PDLs
++ * the rx and tx PDLs
+ * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
+- * needed for the allocation of the memory area.
++ * needed for the allocation of the memory area.
+ */
+
+ /* TODO: We do not need this with old cards, where PDLs are stored
+@@ -719,7 +721,7 @@ static int __devinit hp100_probe1(struct
+ }
+
+ /* Initialise the card. */
+- /* (I'm not really sure if it's a good idea to do this during probing, but
++ /* (I'm not really sure if it's a good idea to do this during probing, but
+ * like this it's assured that the lan connection type can be sensed
+ * correctly)
+ */
+@@ -779,8 +781,8 @@ static int __devinit hp100_probe1(struct
+ return 0;
+ out3:
+ if (local_mode == 1)
+- pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
+- lp->page_vaddr_algn,
++ 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);
+@@ -861,7 +863,7 @@ static void hp100_hwinit(struct net_devi
+ /* Next comes code from mmuinit procedure of SCO BM driver which is
+ * called from HWconfigure in the SCO driver. */
+
+- /* Initialise MMU, eventually switch on Busmaster Mode, initialise
++ /* Initialise MMU, eventually switch on Busmaster Mode, initialise
+ * multicast filter...
+ */
+ hp100_mmuinit(dev);
+@@ -879,11 +881,11 @@ static void hp100_hwinit(struct net_devi
+ hp100_login_to_vg_hub(dev, 0); /* relogin */
+
+ }
+-
+
+-/*
++
++/*
+ * mmuinit - Reinitialise Cascade MMU and MAC settings.
+- * Note: Must already be in reset and leaves card in reset.
++ * Note: Must already be in reset and leaves card in reset.
+ */
+ static void hp100_mmuinit(struct net_device *dev)
+ {
+@@ -909,7 +911,7 @@ static void hp100_mmuinit(struct net_dev
+ hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
+
+ /*
+- * Enable Hardware
++ * Enable Hardware
+ * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
+ * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
+ * - Clear Priority, Advance Pkt and Xmit Cmd
+@@ -984,7 +986,7 @@ static void hp100_mmuinit(struct net_dev
+ * 4 bytes for header). We will leave NUM_RXPDLS * 508 (rounded
+ * to the next higher 1k boundary) bytes for the rx-pdl's
+ * Note: For non-etr chips the transmit stop register must be
+- * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
++ * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
+ */
+ pdl_stop = lp->memory_size;
+ xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff);
+@@ -1132,10 +1134,10 @@ static int hp100_close(struct net_device
+
+ return 0;
+ }
+-
++
+
+ /*
+- * Configure the PDL Rx rings and LAN
++ * Configure the PDL Rx rings and LAN
+ */
+ static void hp100_init_pdls(struct net_device *dev)
+ {
+@@ -1183,7 +1185,7 @@ static void hp100_init_pdls(struct net_d
+ }
+ }
+ }
+-
++
+
+ /* These functions "format" the entries in the pdl structure */
+ /* They return how much memory the fragments need. */
+@@ -1201,10 +1203,10 @@ static int hp100_init_rxpdl(struct net_d
+ ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
+ ringptr->skb = (void *) NULL;
+
+- /*
++ /*
+ * Write address and length of first PDL Fragment (which is used for
+ * storing the RX-Header
+- * We use the 4 bytes _before_ the PDH in the pdl memory area to
++ * We use the 4 bytes _before_ the PDH in the pdl memory area to
+ * store this information. (PDH is at offset 0x04)
+ */
+ /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
+@@ -1231,9 +1233,9 @@ static int hp100_init_txpdl(struct net_d
+ }
+
+ /*
+- * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
++ * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
+ * for possible odd word alignment rounding up to next dword and set PDL
+- * address for fragment#2
++ * address for fragment#2
+ * Returns: 0 if unable to allocate skb_buff
+ * 1 if successful
+ */
+@@ -1253,13 +1255,13 @@ static int hp100_build_rx_pdl(hp100_ring
+ #endif
+
+ /* Allocate skb buffer of maximum size */
+- /* Note: This depends on the alloc_skb functions allocating more
++ /* Note: This depends on the alloc_skb functions allocating more
+ * space than requested, i.e. aligning to 16bytes */
+
+ ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4);
+
+ if (NULL != ringptr->skb) {
+- /*
++ /*
+ * Reserve 2 bytes at the head of the buffer to land the IP header
+ * on a long word boundary (According to the Network Driver section
+ * in the Linux KHG, this should help to increase performance.)
+@@ -1271,10 +1273,10 @@ static int hp100_build_rx_pdl(hp100_ring
+
+ /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
+ /* Note: 1st Fragment is used for the 4 byte packet status
+- * (receive header). Its PDL entries are set up by init_rxpdl. So
++ * (receive header). Its PDL entries are set up by init_rxpdl. So
+ * here we only have to set up the PDL fragment entries for the data
+- * part. Those 4 bytes will be stored in the DMA memory region
+- * directly before the PDL.
++ * part. Those 4 bytes will be stored in the DMA memory region
++ * directly before the PDL.
+ */
+ #ifdef HP100_DEBUG_BM
+ printk("hp100: %s: build_rx_pdl: PDH at 0x%x, skb->data (len %d) at 0x%x\n",
+@@ -1286,7 +1288,7 @@ static int hp100_build_rx_pdl(hp100_ring
+ /* Conversion to new PCI API : map skbuf data to PCI bus.
+ * Doc says it's OK for EISA as well - Jean II */
+ ringptr->pdl[0] = 0x00020000; /* Write PDH */
+- ringptr->pdl[3] = pdl_map_data(netdev_priv(dev),
++ ringptr->pdl[3] = pdl_map_data(netdev_priv(dev),
+ ringptr->skb->data);
+ ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */
+
+@@ -1407,7 +1409,7 @@ static void hp100_BM_shutdown(struct net
+ }
+ } else { /* Shasta or Rainier Shutdown/Reset */
+ /* To ensure all bus master inloading activity has ceased,
+- * wait for no Rx PDAs or no Rx packets on card.
++ * wait for no Rx PDAs or no Rx packets on card.
+ */
+ hp100_page(PERFORMANCE);
+ /* 100 ms timeout */
+@@ -1423,7 +1425,7 @@ static void hp100_BM_shutdown(struct net
+
+ /* To ensure all bus master outloading activity has ceased,
+ * wait until the Tx PDA count goes to zero or no more Tx space
+- * available in the Tx region of the card.
++ * available in the Tx region of the card.
+ */
+ /* 100 ms timeout */
+ for (time = 0; time < 10000; time++) {
+@@ -1462,7 +1464,7 @@ static int hp100_check_lan(struct net_de
+ return 0;
+ }
+
+-/*
++/*
+ * transmit functions
+ */
+
+@@ -1486,7 +1488,7 @@ static int hp100_start_xmit_bm(struct sk
+
+ if (skb->len <= 0)
+ return 0;
+-
++
+ if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
+ return 0;
+
+@@ -1576,14 +1578,14 @@ static int hp100_start_xmit_bm(struct sk
+
+ return 0;
+ }
+-
++
+
+ /* clean_txring checks if packets have been sent by the card by reading
+ * the TX_PDL register from the performance page and comparing it to the
+ * number of commited packets. It then frees the skb's of the packets that
+ * obviously have been sent to the network.
+ *
+- * Needs the PERFORMANCE page selected.
++ * Needs the PERFORMANCE page selected.
+ */
+ static void hp100_clean_txring(struct net_device *dev)
+ {
+@@ -1744,15 +1746,15 @@ static int hp100_start_xmit(struct sk_bu
+
+ return 0;
+ }
+-
++
+
+ /*
+ * Receive Function (Non-Busmaster mode)
+- * Called when an "Receive Packet" interrupt occurs, i.e. the receive
++ * Called when an "Receive Packet" interrupt occurs, i.e. the receive
+ * packet counter is non-zero.
+ * For non-busmaster, this function does the whole work of transfering
+ * the packet to the host memory and then up to higher layers via skb
+- * and netif_rx.
++ * and netif_rx.
+ */
+
+ static void hp100_rx(struct net_device *dev)
+@@ -1855,7 +1857,7 @@ static void hp100_rx(struct net_device *
+ #endif
+ }
+
+-/*
++/*
+ * Receive Function for Busmaster Mode
+ */
+ static void hp100_rx_bm(struct net_device *dev)
+@@ -1876,7 +1878,7 @@ static void hp100_rx_bm(struct net_devic
+ printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name);
+ return;
+ } else
+- /* RX_PKT_CNT states how many PDLs are currently formatted and available to
++ /* RX_PKT_CNT states how many PDLs are currently formatted and available to
+ * the cards BM engine */
+ if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) {
+ printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n",
+@@ -1889,7 +1891,7 @@ static void hp100_rx_bm(struct net_devic
+ while ((lp->rxrcommit > hp100_inb(RX_PDL))) {
+ /*
+ * The packet was received into the pdl pointed to by lp->rxrhead (
+- * the oldest pdl in the ring
++ * the oldest pdl in the ring
+ */
+
+ /* First we get the header, which contains information about the */
+@@ -2044,7 +2046,7 @@ static void hp100_clear_stats(struct hp1
+ hp100_page(PERFORMANCE);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+-
++
+
+ /*
+ * multicast setup
+@@ -2185,7 +2187,7 @@ static void hp100_set_multicast_list(str
+ * hardware interrupt handling
+ */
+
+-static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hp100_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct hp100_private *lp = netdev_priv(dev);
+@@ -2221,9 +2223,9 @@ static irqreturn_t hp100_interrupt(int i
+ /* We're only interested in those interrupts we really enabled. */
+ /* val &= hp100_inw( IRQ_MASK ); */
+
+- /*
+- * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
+- * is considered executed whenever the RX_PDL data structure is no longer
++ /*
++ * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
++ * is considered executed whenever the RX_PDL data structure is no longer
+ * needed.
+ */
+ if (val & HP100_RX_PDL_FILL_COMPL) {
+@@ -2234,7 +2236,7 @@ static irqreturn_t hp100_interrupt(int i
+ }
+ }
+
+- /*
++ /*
+ * The RX_PACKET interrupt is set, when the receive packet counter is
+ * non zero. We use this interrupt for receiving in slave mode. In
+ * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
+@@ -2260,10 +2262,10 @@ static irqreturn_t hp100_interrupt(int i
+ hp100_outw(val, IRQ_STATUS);
+
+ /*
+- * RX_ERROR is set when a packet is dropped due to no memory resources on
+- * the card or when a RCV_ERR occurs.
+- * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
+- * only in the 802.3 MAC and happens when 16 collisions occur during a TX
++ * RX_ERROR is set when a packet is dropped due to no memory resources on
++ * the card or when a RCV_ERR occurs.
++ * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
++ * only in the 802.3 MAC and happens when 16 collisions occur during a TX
+ */
+ if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) {
+ #ifdef HP100_DEBUG_IRQ
+@@ -2276,20 +2278,20 @@ static irqreturn_t hp100_interrupt(int i
+ }
+ }
+
+- /*
+- * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
++ /*
++ * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
+ */
+ if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO)))
+ hp100_rxfill(dev);
+
+- /*
+- * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
+- * is completed
++ /*
++ * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
++ * is completed
+ */
+ if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE)))
+ hp100_clean_txring(dev);
+
+- /*
++ /*
+ * MISC_ERROR is set when either the LAN link goes down or a detected
+ * bus error occurs.
+ */
+@@ -2472,12 +2474,12 @@ static int hp100_sense_lan(struct net_de
+
+ /* Those cards don't have a 100 Mbit connector */
+ if ( !strcmp(lp->id, "HWP1920") ||
+- (lp->pci_dev &&
+- lp->pci_dev->vendor == PCI_VENDOR_ID &&
++ (lp->pci_dev &&
++ lp->pci_dev->vendor == PCI_VENDOR_ID &&
+ (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A ||
+ lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A)))
+ return HP100_LAN_ERR;
+-
++
+ if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */
+ return HP100_LAN_100;
+ return HP100_LAN_ERR;
+@@ -2823,8 +2825,8 @@ static void cleanup_dev(struct net_devic
+ release_region(d->base_addr, HP100_REGION_SIZE);
+
+ if (p->mode == 1) /* busmaster */
+- pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f,
+- p->page_vaddr_algn,
++ pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f,
++ p->page_vaddr_algn,
+ virt_to_whatever(d, p->page_vaddr_algn));
+ if (p->mem_ptr_virt)
+ iounmap(p->mem_ptr_virt);
+@@ -2850,7 +2852,7 @@ static int __init hp100_eisa_probe (stru
+ goto out1;
+
+ #ifdef HP100_DEBUG
+- printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name,
++ printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name,
+ dev->base_addr);
+ #endif
+ gendev->driver_data = dev;
+@@ -2914,12 +2916,12 @@ static int __devinit hp100_pci_probe (st
+ pci_command |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+ }
+-
++
+ ioaddr = pci_resource_start(pdev, 0);
+ err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev);
+- if (err)
++ if (err)
+ goto out1;
+-
++
+ #ifdef HP100_DEBUG
+ printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr);
+ #endif
+@@ -3004,7 +3006,7 @@ static int __init hp100_isa_init(void)
+ return cards > 0 ? 0 : -ENODEV;
+ }
+
+-static void __exit hp100_isa_cleanup(void)
++static void __exit hp100_isa_cleanup(void)
+ {
+ int i;
+
+@@ -3028,12 +3030,12 @@ static int __init hp100_module_init(void
+ goto out;
+ #ifdef CONFIG_EISA
+ err = eisa_driver_register(&hp100_eisa_driver);
+- if (err && err != -ENODEV)
++ if (err && err != -ENODEV)
+ goto out2;
+ #endif
+ #ifdef CONFIG_PCI
+ err = pci_module_init(&hp100_pci_driver);
+- if (err && err != -ENODEV)
++ if (err && err != -ENODEV)
+ goto out3;
+ #endif
+ out:
+diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
+index 236d945..e6ca128 100644
+--- a/drivers/net/hp100.h
++++ b/drivers/net/hp100.h
+@@ -8,9 +8,9 @@
+ *
+ * This driver is based on the 'hpfepkt' crynwr packet driver.
+ *
+- * This source/code is public free; you can distribute it and/or modify
++ * This source/code is public free; you can distribute it and/or modify
+ * it under terms of the GNU General Public License (published by the
+- * Free Software Foundation) either version two of this License, or any
++ * Free Software Foundation) either version two of this License, or any
+ * later version.
+ */
+
+@@ -18,7 +18,7 @@
+ * Hardware Constants
+ ****************************************************************************/
+
+-/*
++/*
+ * Page Identifiers
+ * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
+ */
+@@ -143,15 +143,15 @@
+ /* ------------------------------------------------------------------------ */
+
+
+-/*
++/*
+ * Hardware ID Register I (Always available, HW_ID, Offset 0x00)
+ */
+ #define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */
+
+-/*
++/*
+ * Hardware ID Register 2 & Paging Register
+ * (Always available, PAGING, Offset 0x02)
+- * Bits 15:4 are for the Chip ID
++ * Bits 15:4 are for the Chip ID
+ */
+ #define HP100_CHIPID_MASK 0xFFF0
+ #define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */
+@@ -162,7 +162,7 @@
+ /* LRF supported */
+
+ /*
+- * Option Registers I and II
++ * Option Registers I and II
+ * (Always available, OPTION_LSW, Offset 0x04-0x05)
+ */
+ #define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */
+@@ -187,7 +187,7 @@
+ /* NIC reset on 0 to 1 transition */
+
+ /*
+- * Option Register III
++ * Option Register III
+ * (Always available, OPTION_MSW, Offset 0x06)
+ */
+ #define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */
+@@ -253,7 +253,7 @@
+ #define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */
+
+
+-/*
++/*
+ * Mode Control Register I
+ * (Page HW_MAP, MODECTRL1, Offset0x10)
+ */
+@@ -281,7 +281,7 @@
+ #define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */
+ /* interrupt */
+
+-/*
++/*
+ * PCI Configuration and Control Register I
+ * (Page HW_MAP, PCICTRL1, Offset 0x12)
+ */
+@@ -378,7 +378,7 @@
+
+ /*
+ * 100MB LAN Control and Configuration Register
+- * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
++ * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
+ */
+ #define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */
+ #define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */
+@@ -422,7 +422,7 @@
+ #define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED
+
+ /*
+- * MAC Configuration Register II
++ * MAC Configuration Register II
+ * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
+ */
+ #define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */
+@@ -447,8 +447,8 @@
+ #define HP100_MAC2MODE7 KEEP_CRC
+
+ /*
+- * MAC Configuration Register III
+- * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
++ * MAC Configuration Register III
++ * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
+ */
+ #define HP100_PACKET_PACE 0x03 /* Packet Pacing:
+ * 00: No packet pacing
+@@ -461,7 +461,7 @@
+ #define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */
+
+ /*
+- * MAC Configuration Register IV
++ * MAC Configuration Register IV
+ * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
+ */
+ #define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL
+@@ -469,18 +469,18 @@
+ #define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion
+ * of the Misc. Interrupt */
+
+-/*
+- * 100 MB LAN Training Request/Allowed Registers
++/*
++ * 100 MB LAN Training Request/Allowed Registers
+ * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
+ */
+-#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be
++#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be
+ * a cascaded repeater
+ * 0: ... wants to be a DTE */
+ #define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode
+ * 00: Rcv only unicast packets
+ * specifically addr to this
+ * endnode
+- * 10: Rcv all pckts fwded by
++ * 10: Rcv all pckts fwded by
+ * the local repeater */
+ #define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */
+ #define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */
+@@ -492,7 +492,7 @@
+ * 00: Rcv only unicast packets
+ * specifically addr to this
+ * endnode
+- * 10: Rcv all pckts fwded by
++ * 10: Rcv all pckts fwded by
+ * the local repeater */
+ #define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format
+ * 00: 802.3 format will be used
+@@ -521,7 +521,7 @@
+ #define HP100_LAN_COAX 9 /* lan_type value for Coax */
+ #define HP100_LAN_ERR (-1) /* lan_type value for link down */
+
+-/*
++/*
+ * Bus Master Data Structures ----------------------------------------------
+ */
+
+@@ -554,7 +554,7 @@ typedef struct hp100_ring {
+ #define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */
+
+
+-/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
++/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
+ bit in the MAC Configuration Register 1 is set. */
+ #define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */
+ #define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */
+diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
+index 6856934..9c643f2 100644
+--- a/drivers/net/hplance.c
++++ b/drivers/net/hplance.c
+@@ -45,12 +45,12 @@ struct hplance_private {
+
+ /* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+- * plus board-specific init, open and close actions.
++ * plus board-specific init, open and close actions.
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+ static int __devinit hplance_init_one(struct dio_dev *d,
+ const struct dio_device_id *ent);
+-static void __devinit hplance_init(struct net_device *dev,
++static void __devinit hplance_init(struct net_device *dev,
+ struct dio_dev *d);
+ static void __devexit hplance_remove_one(struct dio_dev *d);
+ static void hplance_writerap(void *priv, unsigned short value);
+@@ -118,7 +118,7 @@ static void __init hplance_init(struct n
+ unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
+ struct hplance_private *lp;
+ int i;
+-
++
+ printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
+
+ /* reset the board */
+@@ -136,7 +136,7 @@ static void __init hplance_init(struct n
+ dev->get_stats = &lance_get_stats;
+ dev->set_multicast_list = &lance_set_multicast;
+ dev->dma = 0;
+-
++
+ for (i=0; i<6; i++) {
+ /* The NVRAM holds our ethernet address, one nibble per byte,
+ * at bytes NVRAMOFF+1,3,5,7,9...
+@@ -145,7 +145,7 @@ static void __init hplance_init(struct n
+ | (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+ printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
+ }
+-
++
+ lp = netdev_priv(dev);
+ lp->lance.name = (char*)d->name; /* discards const, shut up gcc */
+ lp->lance.base = va;
+@@ -196,7 +196,7 @@ static int hplance_open(struct net_devic
+ {
+ int status;
+ struct lance_private *lp = netdev_priv(dev);
+-
++
+ status = lance_open(dev); /* call generic lance open code */
+ if (status)
+ return status;
+diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
+index 82468e2..ffeafb2 100644
+--- a/drivers/net/ibm_emac/ibm_emac_core.c
++++ b/drivers/net/ibm_emac/ibm_emac_core.c
+@@ -184,7 +184,7 @@ static const char emac_stats_keys[EMAC_E
+ "tx_errors"
+ };
+
+-static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t emac_irq(int irq, void *dev_instance);
+ static void emac_clean_tx_ring(struct ocp_enet_private *dev);
+
+ static inline int emac_phy_supports_gige(int phy_mode)
+@@ -1036,7 +1036,7 @@ static inline u16 emac_tx_csum(struct oc
+ struct sk_buff *skb)
+ {
+ #if defined(CONFIG_IBM_EMAC_TAH)
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ ++dev->stats.tx_packets_csum;
+ return EMAC_TX_CTRL_TAH_CSUM;
+ }
+@@ -1515,7 +1515,7 @@ static void emac_rxde(void *param)
+ }
+
+ /* Hard IRQ */
+-static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t emac_irq(int irq, void *dev_instance)
+ {
+ struct ocp_enet_private *dev = dev_instance;
+ struct emac_regs __iomem *p = dev->emacp;
+@@ -1883,7 +1883,7 @@ static void emac_ethtool_get_drvinfo(str
+ info->regdump_len = emac_ethtool_get_regs_len(ndev);
+ }
+
+-static struct ethtool_ops emac_ethtool_ops = {
++static const struct ethtool_ops emac_ethtool_ops = {
+ .get_settings = emac_ethtool_get_settings,
+ .set_settings = emac_ethtool_set_settings,
+ .get_drvinfo = emac_ethtool_get_drvinfo,
+diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c
+index c364590..92f970d 100644
+--- a/drivers/net/ibm_emac/ibm_emac_debug.c
++++ b/drivers/net/ibm_emac/ibm_emac_debug.c
+@@ -179,8 +179,7 @@ void emac_dbg_dump_all(void)
+ }
+
+ #if defined(CONFIG_MAGIC_SYSRQ)
+-static void emac_sysrq_handler(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void emac_sysrq_handler(int key, struct tty_struct *tty)
+ {
+ emac_dbg_dump_all();
+ }
+diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h
+index 5761389..6c7dccc 100644
+--- a/drivers/net/ibm_emac/ibm_emac_debug.h
++++ b/drivers/net/ibm_emac/ibm_emac_debug.h
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/net/ibm_emac/ibm_ocp_debug.h
++ * drivers/net/ibm_emac/ibm_emac_debug.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
+index af50e7b..6c0f071 100644
+--- a/drivers/net/ibm_emac/ibm_emac_mal.c
++++ b/drivers/net/ibm_emac/ibm_emac_mal.c
+@@ -168,7 +168,7 @@ static inline void mal_disable_eob_irq(s
+ MAL_DBG2("%d: disable_irq" NL, mal->def->index);
+ }
+
+-static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t mal_serr(int irq, void *dev_instance)
+ {
+ struct ibm_ocp_mal *mal = dev_instance;
+ u32 esr = get_mal_dcrn(mal, MAL_ESR);
+@@ -216,7 +216,7 @@ static inline void mal_schedule_poll(str
+ MAL_DBG2("%d: already in poll" NL, mal->def->index);
+ }
+
+-static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t mal_txeob(int irq, void *dev_instance)
+ {
+ struct ibm_ocp_mal *mal = dev_instance;
+ u32 r = get_mal_dcrn(mal, MAL_TXEOBISR);
+@@ -226,7 +226,7 @@ static irqreturn_t mal_txeob(int irq, vo
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t mal_rxeob(int irq, void *dev_instance)
+ {
+ struct ibm_ocp_mal *mal = dev_instance;
+ u32 r = get_mal_dcrn(mal, MAL_RXEOBISR);
+@@ -236,7 +236,7 @@ static irqreturn_t mal_rxeob(int irq, vo
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t mal_txde(int irq, void *dev_instance)
+ {
+ struct ibm_ocp_mal *mal = dev_instance;
+ u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
+@@ -252,7 +252,7 @@ static irqreturn_t mal_txde(int irq, voi
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t mal_rxde(int irq, void *dev_instance)
+ {
+ struct ibm_ocp_mal *mal = dev_instance;
+ struct list_head *l;
+diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h
+index 94abde5..117ea48 100644
+--- a/drivers/net/ibm_emac/ibm_emac_rgmii.h
++++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/net/ibm_emac/ibm_emac_rgmii.c
++ * drivers/net/ibm_emac/ibm_emac_rgmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
+index 2a95d72..3f946c8 100644
+--- a/drivers/net/ibmlana.c
++++ b/drivers/net/ibmlana.c
+@@ -705,7 +705,7 @@ static void irqtxerr_handler(struct net_
+
+ /* general interrupt entry */
+
+-static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs)
++static irqreturn_t irq_handler(int irq, void *device)
+ {
+ struct net_device *dev = (struct net_device *) device;
+ u16 ival;
+diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
+index 0464e78..44c9f99 100644
+--- a/drivers/net/ibmveth.c
++++ b/drivers/net/ibmveth.c
+@@ -93,7 +93,7 @@ static void ibmveth_proc_register_driver
+ static void ibmveth_proc_unregister_driver(void);
+ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
+ static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
+-static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
+ static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
+ static struct kobj_type ktype_veth_pool;
+
+@@ -212,7 +212,8 @@ static void ibmveth_replenish_buffer_poo
+ break;
+ }
+
+- free_index = pool->consumer_index++ % pool->size;
++ free_index = pool->consumer_index;
++ pool->consumer_index = (pool->consumer_index + 1) % pool->size;
+ index = pool->free_map[free_index];
+
+ ibmveth_assert(index != IBM_VETH_INVALID_MAP);
+@@ -238,7 +239,10 @@ static void ibmveth_replenish_buffer_poo
+ if(lpar_rc != H_SUCCESS) {
+ pool->free_map[free_index] = index;
+ pool->skbuff[index] = NULL;
+- pool->consumer_index--;
++ if (pool->consumer_index == 0)
++ pool->consumer_index = pool->size - 1;
++ else
++ pool->consumer_index--;
+ dma_unmap_single(&adapter->vdev->dev,
+ pool->dma_addr[index], pool->buff_size,
+ DMA_FROM_DEVICE);
+@@ -325,7 +329,10 @@ static void ibmveth_remove_buffer_from_p
+ adapter->rx_buff_pool[pool].buff_size,
+ DMA_FROM_DEVICE);
+
+- free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size;
++ free_index = adapter->rx_buff_pool[pool].producer_index;
++ adapter->rx_buff_pool[pool].producer_index
++ = (adapter->rx_buff_pool[pool].producer_index + 1)
++ % adapter->rx_buff_pool[pool].size;
+ adapter->rx_buff_pool[pool].free_map[free_index] = index;
+
+ mb();
+@@ -437,6 +444,31 @@ static void ibmveth_cleanup(struct ibmve
+ &adapter->rx_buff_pool[i]);
+ }
+
++static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
++ union ibmveth_buf_desc rxq_desc, u64 mac_address)
++{
++ int rc, try_again = 1;
++
++ /* After a kexec the adapter will still be open, so our attempt to
++ * open it will fail. So if we get a failure we free the adapter and
++ * try again, but only once. */
++retry:
++ rc = h_register_logical_lan(adapter->vdev->unit_address,
++ adapter->buffer_list_dma, rxq_desc.desc,
++ adapter->filter_list_dma, mac_address);
++
++ if (rc != H_SUCCESS && try_again) {
++ do {
++ rc = h_free_logical_lan(adapter->vdev->unit_address);
++ } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
++
++ try_again = 0;
++ goto retry;
++ }
++
++ return rc;
++}
++
+ static int ibmveth_open(struct net_device *netdev)
+ {
+ struct ibmveth_adapter *adapter = netdev->priv;
+@@ -502,12 +534,9 @@ static int ibmveth_open(struct net_devic
+ ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr);
+ ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr);
+
++ h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
+
+- lpar_rc = h_register_logical_lan(adapter->vdev->unit_address,
+- adapter->buffer_list_dma,
+- rxq_desc.desc,
+- adapter->filter_list_dma,
+- mac_address);
++ lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address);
+
+ if(lpar_rc != H_SUCCESS) {
+ ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc);
+@@ -543,7 +572,7 @@ static int ibmveth_open(struct net_devic
+ }
+
+ ibmveth_debug_printk("initial replenish cycle\n");
+- ibmveth_interrupt(netdev->irq, netdev, NULL);
++ ibmveth_interrupt(netdev->irq, netdev);
+
+ netif_start_queue(netdev);
+
+@@ -606,7 +635,7 @@ static u32 netdev_get_link(struct net_de
+ return 1;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_settings = netdev_get_settings,
+ .get_link = netdev_get_link,
+@@ -702,7 +731,8 @@ static int ibmveth_start_xmit(struct sk_
+ desc[3].desc,
+ desc[4].desc,
+ desc[5].desc,
+- correlator);
++ correlator,
++ &correlator);
+ } while ((lpar_rc == H_BUSY) && (retry_count--));
+
+ if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
+@@ -815,7 +845,7 @@ static int ibmveth_poll(struct net_devic
+ return 0;
+ }
+
+-static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *netdev = dev_instance;
+ struct ibmveth_adapter *adapter = netdev->priv;
+@@ -904,6 +934,14 @@ static int ibmveth_change_mtu(struct net
+ return -EINVAL;
+ }
+
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void ibmveth_poll_controller(struct net_device *dev)
++{
++ ibmveth_replenish_task(dev->priv);
++ ibmveth_interrupt(dev->irq, dev);
++}
++#endif
++
+ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
+ {
+ int rc, i;
+@@ -976,6 +1014,9 @@ static int __devinit ibmveth_probe(struc
+ netdev->ethtool_ops = &netdev_ethtool_ops;
+ netdev->change_mtu = ibmveth_change_mtu;
+ SET_NETDEV_DEV(netdev, &dev->dev);
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ netdev->poll_controller = ibmveth_poll_controller;
++#endif
+ netdev->features |= NETIF_F_LLTX;
+ spin_lock_init(&adapter->stats_lock);
+
+@@ -1131,7 +1172,9 @@ static void ibmveth_proc_register_adapte
+ {
+ struct proc_dir_entry *entry;
+ if (ibmveth_proc_dir) {
+- entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir);
++ char u_addr[10];
++ sprintf(u_addr, "%x", adapter->vdev->unit_address);
++ entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir);
+ if (!entry) {
+ ibmveth_error_printk("Cannot create adapter proc entry");
+ } else {
+@@ -1146,7 +1189,9 @@ static void ibmveth_proc_register_adapte
+ static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
+ {
+ if (ibmveth_proc_dir) {
+- remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir);
++ char u_addr[10];
++ sprintf(u_addr, "%x", adapter->vdev->unit_address);
++ remove_proc_entry(u_addr, ibmveth_proc_dir);
+ }
+ }
+
+@@ -1260,7 +1305,7 @@ const char * buf, size_t count)
+ }
+
+ /* kick the interrupt handler to allocate/deallocate pools */
+- ibmveth_interrupt(netdev->irq, netdev, NULL);
++ ibmveth_interrupt(netdev->irq, netdev);
+ return count;
+ }
+
+diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
+index 8385bf8..f5b25bf 100644
+--- a/drivers/net/ibmveth.h
++++ b/drivers/net/ibmveth.h
+@@ -41,16 +41,6 @@
+ #define IbmVethMcastRemoveFilter 0x2UL
+ #define IbmVethMcastClearFilterTable 0x3UL
+
+-/* hcall numbers */
+-#define H_VIO_SIGNAL 0x104
+-#define H_REGISTER_LOGICAL_LAN 0x114
+-#define H_FREE_LOGICAL_LAN 0x118
+-#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+-#define H_SEND_LOGICAL_LAN 0x120
+-#define H_MULTICAST_CTRL 0x130
+-#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+-#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+-
+ /* hcall macros */
+ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
+ plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
+@@ -61,8 +51,21 @@
+ #define h_add_logical_lan_buffer(ua, buf) \
+ plpar_hcall_norets(H_ADD_LOGICAL_LAN_BUFFER, ua, buf)
+
+-#define h_send_logical_lan(ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator) \
+- plpar_hcall_8arg_2ret(H_SEND_LOGICAL_LAN, ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator, &correlator)
++static inline long h_send_logical_lan(unsigned long unit_address,
++ unsigned long desc1, unsigned long desc2, unsigned long desc3,
++ unsigned long desc4, unsigned long desc5, unsigned long desc6,
++ unsigned long corellator_in, unsigned long *corellator_out)
++{
++ long rc;
++ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
++
++ rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, desc1,
++ desc2, desc3, desc4, desc5, desc6, corellator_in);
++
++ *corellator_out = retbuf[0];
++
++ return rc;
++}
+
+ #define h_multicast_ctrl(ua, cmd, mac) \
+ plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
+diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
+index 43e3f33..c26a4b8 100644
+--- a/drivers/net/ifb.c
++++ b/drivers/net/ifb.c
+@@ -1,4 +1,4 @@
+-/* drivers/net/ifb.c:
++/* drivers/net/ifb.c:
+
+ The purpose of this driver is to provide a device that allows
+ for sharing of resources:
+@@ -8,8 +8,8 @@
+ an impression of sharing.
+
+ 2) Allows for queueing incoming traffic for shaping instead of
+- dropping.
+-
++ dropping.
++
+ The original concept is based on what is known as the IMQ
+ driver initially written by Martin Devera, later rewritten
+ by Patrick McHardy and then maintained by Andre Correa.
+@@ -21,9 +21,9 @@
+ 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: Jamal Hadi Salim (2005)
+-
++
+ */
+
+
+@@ -33,10 +33,10 @@
+ #include <linux/etherdevice.h>
+ #include <linux/init.h>
+ #include <linux/moduleparam.h>
+-#include <net/pkt_sched.h>
++#include <net/pkt_sched.h>
+
+ #define TX_TIMEOUT (2*HZ)
+-
++
+ #define TX_Q_LIMIT 32
+ struct ifb_private {
+ struct net_device_stats stats;
+@@ -64,7 +64,7 @@ static struct net_device_stats *ifb_get_
+ static int ifb_open(struct net_device *dev);
+ static int ifb_close(struct net_device *dev);
+
+-static void ri_tasklet(unsigned long dev)
++static void ri_tasklet(unsigned long dev)
+ {
+
+ struct net_device *_dev = (struct net_device *)dev;
+@@ -163,7 +163,7 @@ dropped:
+ stats->rx_dropped++;
+ return ret;
+ } else {
+- /*
++ /*
+ * note we could be going
+ * ingress -> egress or
+ * egress -> ingress
+@@ -199,9 +199,9 @@ static struct net_device_stats *ifb_get_
+ struct net_device_stats *stats = &dp->stats;
+
+ pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
+- dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
+- dp->st_rx2tx_tran dp->st_rxq_notenter, dp->st_rx_frm_egr,
+- dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch );
++ dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
++ dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr,
++ dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch);
+
+ return stats;
+ }
+@@ -250,7 +250,7 @@ static int __init ifb_init_one(int index
+ free_netdev(dev_ifb);
+ dev_ifb = NULL;
+ } else {
+- ifbs[index] = dev_ifb;
++ ifbs[index] = dev_ifb;
+ }
+
+ return err;
+@@ -260,32 +260,32 @@ static void ifb_free_one(int index)
+ {
+ unregister_netdev(ifbs[index]);
+ free_netdev(ifbs[index]);
+-}
++}
+
+ static int __init ifb_init_module(void)
+-{
++{
+ int i, err = 0;
+- ifbs = kmalloc(numifbs * sizeof(void *), GFP_KERNEL);
++ ifbs = kmalloc(numifbs * sizeof(void *), GFP_KERNEL);
+ if (!ifbs)
+- return -ENOMEM;
++ return -ENOMEM;
+ for (i = 0; i < numifbs && !err; i++)
+- err = ifb_init_one(i);
+- if (err) {
++ err = ifb_init_one(i);
++ if (err) {
+ i--;
+ while (--i >= 0)
+ ifb_free_one(i);
+ }
+
+ return err;
+-}
++}
+
+ static void __exit ifb_cleanup_module(void)
+ {
+ int i;
+
+- for (i = 0; i < numifbs; i++)
+- ifb_free_one(i);
+- kfree(ifbs);
++ for (i = 0; i < numifbs; i++)
++ ifb_free_one(i);
++ kfree(ifbs);
+ }
+
+ module_init(ifb_init_module);
+diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
+index 68d8af7..f56b00e 100644
+--- a/drivers/net/ioc3-eth.c
++++ b/drivers/net/ioc3-eth.c
+@@ -28,7 +28,7 @@
+ */
+
+ #define IOC3_NAME "ioc3-eth"
+-#define IOC3_VERSION "2.6.3-3"
++#define IOC3_VERSION "2.6.3-4"
+
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -115,7 +115,7 @@ static inline void ioc3_stop(struct ioc3
+ static void ioc3_init(struct net_device *dev);
+
+ static const char ioc3_str[] = "IOC3 Ethernet";
+-static struct ethtool_ops ioc3_ethtool_ops;
++static const struct ethtool_ops ioc3_ethtool_ops;
+
+ /* We use this to acquire receive skb's that we can DMA directly into. */
+
+@@ -750,7 +750,7 @@ static void ioc3_error(struct ioc3_priva
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs)
++static irqreturn_t ioc3_interrupt(int irq, void *_dev)
+ {
+ struct net_device *dev = (struct net_device *)_dev;
+ struct ioc3_private *ip = netdev_priv(dev);
+@@ -1017,7 +1017,7 @@ static void ioc3_init(struct net_device
+ struct ioc3_private *ip = netdev_priv(dev);
+ struct ioc3 *ioc3 = ip->regs;
+
+- del_timer(&ip->ioc3_timer); /* Kill if running */
++ del_timer_sync(&ip->ioc3_timer); /* Kill if running */
+
+ ioc3_w_emcr(EMCR_RST); /* Reset */
+ (void) ioc3_r_emcr(); /* Flush WB */
+@@ -1081,7 +1081,7 @@ static int ioc3_close(struct net_device
+ {
+ struct ioc3_private *ip = netdev_priv(dev);
+
+- del_timer(&ip->ioc3_timer);
++ del_timer_sync(&ip->ioc3_timer);
+
+ netif_stop_queue(dev);
+
+@@ -1387,7 +1387,7 @@ static int ioc3_start_xmit(struct sk_buf
+ * MAC header which should not be summed and the TCP/UDP pseudo headers
+ * manually.
+ */
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ int proto = ntohs(skb->nh.iph->protocol);
+ unsigned int csoff;
+ struct iphdr *ih = skb->nh.iph;
+@@ -1580,7 +1580,7 @@ static u32 ioc3_get_link(struct net_devi
+ return rc;
+ }
+
+-static struct ethtool_ops ioc3_ethtool_ops = {
++static const struct ethtool_ops ioc3_ethtool_ops = {
+ .get_drvinfo = ioc3_get_drvinfo,
+ .get_settings = ioc3_get_settings,
+ .set_settings = ioc3_set_settings,
+@@ -1611,8 +1611,6 @@ static void ioc3_set_multicast_list(stru
+ netif_stop_queue(dev); /* Lock out others. */
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ ip->emcr |= EMCR_PROMISC;
+ ioc3_w_emcr(ip->emcr);
+ (void) ioc3_r_emcr();
+diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
+index e9e6d99..7c8ccc0 100644
+--- a/drivers/net/irda/Kconfig
++++ b/drivers/net/irda/Kconfig
+@@ -287,6 +287,7 @@ comment "FIR device drivers"
+ config USB_IRDA
+ tristate "IrDA USB dongles"
+ depends on IRDA && USB
++ select FW_LOADER
+ ---help---
+ Say Y here if you want to build support for the USB IrDA FIR Dongle
+ device driver. To compile it as a module, choose M here: the module
+diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
+index e3c8cd5..cebf8c3 100644
+--- a/drivers/net/irda/ali-ircc.c
++++ b/drivers/net/irda/ali-ircc.c
+@@ -249,7 +249,7 @@ static void __exit ali_ircc_cleanup(void
+
+ IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
+
+- for (i=0; i < 4; i++) {
++ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
+ if (dev_self[i])
+ ali_ircc_close(dev_self[i]);
+ }
+@@ -273,6 +273,12 @@ static int ali_ircc_open(int i, chipio_t
+ int err;
+
+ IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
++
++ if (i >= ARRAY_SIZE(dev_self)) {
++ IRDA_ERROR("%s(), maximum number of supported chips reached!\n",
++ __FUNCTION__);
++ return -ENOMEM;
++ }
+
+ /* Set FIR FIFO and DMA Threshold */
+ if ((ali_ircc_setup(info)) == -1)
+@@ -654,22 +660,15 @@ static int ali_ircc_read_dongle_id (int
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+-static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct ali_ircc_cb *self;
+ int ret;
+
+ IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
+
+- if (!dev) {
+- IRDA_WARNING("%s: irq %d for unknown device.\n",
+- ALI_IRCC_DRIVER_NAME, irq);
+- return IRQ_NONE;
+- }
+-
+- self = (struct ali_ircc_cb *) dev->priv;
++ self = dev->priv;
+
+ spin_lock(&self->lock);
+
+diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
+index 7b2b413..37914dc 100644
+--- a/drivers/net/irda/au1k_ir.c
++++ b/drivers/net/irda/au1k_ir.c
+@@ -51,7 +51,7 @@ static int au1k_irda_start(struct net_de
+ static int au1k_irda_stop(struct net_device *dev);
+ static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
+ static int au1k_irda_rx(struct net_device *);
+-static void au1k_irda_interrupt(int, void *, struct pt_regs *);
++static void au1k_irda_interrupt(int, void *);
+ static void au1k_tx_timeout(struct net_device *);
+ static struct net_device_stats *au1k_irda_stats(struct net_device *);
+ static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
+@@ -627,7 +627,7 @@ static int au1k_irda_rx(struct net_devic
+ }
+
+
+-void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++void au1k_irda_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+
+diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
+index 33c07d5..16620bd 100644
+--- a/drivers/net/irda/donauboe.c
++++ b/drivers/net/irda/donauboe.c
+@@ -657,12 +657,6 @@ toshoboe_makemttpacket (struct toshoboe_
+ return xbofs;
+ }
+
+-static int toshoboe_invalid_dev(int irq)
+-{
+- printk (KERN_WARNING DRIVER_NAME ": irq %d for unknown device.\n", irq);
+- return 1;
+-}
+-
+ #ifdef USE_PROBE
+ /***********************************************************************/
+ /* Probe code */
+@@ -709,14 +703,11 @@ stuff_byte (__u8 byte, __u8 * buf)
+ }
+
+ static irqreturn_t
+-toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs)
++toshoboe_probeinterrupt (int irq, void *dev_id)
+ {
+- struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
++ struct toshoboe_cb *self = dev_id;
+ __u8 irqstat;
+
+- if (self == NULL && toshoboe_invalid_dev(irq))
+- return IRQ_NONE;
+-
+ irqstat = INB (OBOE_ISR);
+
+ /* was it us */
+@@ -1161,15 +1152,12 @@ dumpbufs(skb->data,skb->len,'>');
+
+ /*interrupt handler */
+ static irqreturn_t
+-toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
++toshoboe_interrupt (int irq, void *dev_id)
+ {
+- struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
++ struct toshoboe_cb *self = dev_id;
+ __u8 irqstat;
+ struct sk_buff *skb = NULL;
+
+- if (self == NULL && toshoboe_invalid_dev(irq))
+- return IRQ_NONE;
+-
+ irqstat = INB (OBOE_ISR);
+
+ /* was it us */
+@@ -1357,13 +1345,11 @@ toshoboe_net_open (struct net_device *de
+ {
+ struct toshoboe_cb *self;
+ unsigned long flags;
++ int rc;
+
+ IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+- IRDA_ASSERT (dev != NULL, return -1; );
+- self = (struct toshoboe_cb *) dev->priv;
+-
+- IRDA_ASSERT (self != NULL, return 0; );
++ self = netdev_priv(dev);
+
+ if (self->async)
+ return -EBUSY;
+@@ -1371,11 +1357,10 @@ toshoboe_net_open (struct net_device *de
+ if (self->stopped)
+ return 0;
+
+- if (request_irq (self->io.irq, toshoboe_interrupt,
+- IRQF_SHARED | IRQF_DISABLED, dev->name, (void *) self))
+- {
+- return -EAGAIN;
+- }
++ rc = request_irq (self->io.irq, toshoboe_interrupt,
++ IRQF_SHARED | IRQF_DISABLED, dev->name, self);
++ if (rc)
++ return rc;
+
+ spin_lock_irqsave(&self->spinlock, flags);
+ toshoboe_startchip (self);
+diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
+index 2a0d538..14bda76 100644
+--- a/drivers/net/irda/irda-usb.c
++++ b/drivers/net/irda/irda-usb.c
+@@ -114,9 +114,9 @@ static void irda_usb_change_speed_xbofs(
+ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int irda_usb_open(struct irda_usb_cb *self);
+ static void irda_usb_close(struct irda_usb_cb *self);
+-static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs);
+-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs);
+-static void irda_usb_receive(struct urb *urb, struct pt_regs *regs);
++static void speed_bulk_callback(struct urb *urb);
++static void write_bulk_callback(struct urb *urb);
++static void irda_usb_receive(struct urb *urb);
+ static void irda_usb_rx_defer_expired(unsigned long data);
+ static int irda_usb_net_open(struct net_device *dev);
+ static int irda_usb_net_close(struct net_device *dev);
+@@ -343,7 +343,7 @@ static void irda_usb_change_speed_xbofs(
+ * Speed URB callback
+ * Now, we can only get called for the speed URB.
+ */
+-static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void speed_bulk_callback(struct urb *urb)
+ {
+ struct irda_usb_cb *self = urb->context;
+
+@@ -562,7 +562,7 @@ drop:
+ /*
+ * Note : this function will be called only for tx_urb...
+ */
+-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void write_bulk_callback(struct urb *urb)
+ {
+ unsigned long flags;
+ struct sk_buff *skb = urb->context;
+@@ -671,10 +671,8 @@ static void irda_usb_net_timeout(struct
+ * Jean II */
+ done = 1;
+ break;
+- case -ECONNABORTED: /* -103 */
+- case -ECONNRESET: /* -104 */
+- case -ETIMEDOUT: /* -110 */
+- case -ENOENT: /* -2 (urb unlinked by us) */
++ case -ECONNRESET:
++ case -ENOENT: /* urb unlinked by us */
+ default: /* ??? - Play safe */
+ urb->status = 0;
+ netif_wake_queue(self->netdev);
+@@ -712,10 +710,8 @@ static void irda_usb_net_timeout(struct
+ * Jean II */
+ done = 1;
+ break;
+- case -ECONNABORTED: /* -103 */
+- case -ECONNRESET: /* -104 */
+- case -ETIMEDOUT: /* -110 */
+- case -ENOENT: /* -2 (urb unlinked by us) */
++ case -ECONNRESET:
++ case -ENOENT: /* urb unlinked by us */
+ default: /* ??? - Play safe */
+ if(skb != NULL) {
+ dev_kfree_skb_any(skb);
+@@ -813,7 +809,7 @@ static void irda_usb_submit(struct irda_
+ * Called by the USB subsystem when a frame has been received
+ *
+ */
+-static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
++static void irda_usb_receive(struct urb *urb)
+ {
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct irda_usb_cb *self;
+@@ -845,14 +841,14 @@ static void irda_usb_receive(struct urb
+ self->stats.rx_crc_errors++;
+ /* Also precursor to a hot-unplug on UHCI. */
+ /* Fallthrough... */
+- case -ECONNRESET: /* -104 */
++ case -ECONNRESET:
+ /* Random error, if I remember correctly */
+ /* uhci_cleanup_unlink() is going to kill the Rx
+ * URB just after we return. No problem, at this
+ * point the URB will be idle ;-) - Jean II */
+- case -ESHUTDOWN: /* -108 */
++ case -ESHUTDOWN:
+ /* That's usually a hot-unplug. Submit will fail... */
+- case -ETIMEDOUT: /* -110 */
++ case -ETIME:
+ /* Usually precursor to a hot-unplug on OHCI. */
+ default:
+ self->stats.rx_errors++;
+diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
+index 44efd49..654a68b 100644
+--- a/drivers/net/irda/irport.c
++++ b/drivers/net/irda/irport.c
+@@ -87,8 +87,7 @@ static struct net_device_stats *irport_n
+ static int irport_change_speed_complete(struct irda_task *task);
+ static void irport_timeout(struct net_device *dev);
+
+-static irqreturn_t irport_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t irport_interrupt(int irq, void *dev_id);
+ static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+ static void irport_change_speed(void *priv, __u32 speed);
+ static int irport_net_open(struct net_device *dev);
+@@ -761,25 +760,20 @@ static inline void irport_receive(struct
+ }
+
+ /*
+- * Function irport_interrupt (irq, dev_id, regs)
++ * Function irport_interrupt (irq, dev_id)
+ *
+ * Interrupt handler
+ */
+-static irqreturn_t irport_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t irport_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct irport_cb *self;
+ int boguscount = 0;
+ int iobase;
+ int iir, lsr;
+ int handled = 0;
+
+- if (!dev) {
+- IRDA_WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq);
+- return IRQ_NONE;
+- }
+- self = (struct irport_cb *) dev->priv;
++ self = dev->priv;
+
+ spin_lock(&self->lock);
+
+@@ -1090,7 +1084,7 @@ static int __init irport_init(void)
+ {
+ int i;
+
+- for (i=0; (io[i] < 2000) && (i < 4); i++) {
++ for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) {
+ if (irport_open(i, io[i], irq[i]) != NULL)
+ return 0;
+ }
+@@ -1112,7 +1106,7 @@ static void __exit irport_cleanup(void)
+
+ IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+
+- for (i=0; i < 4; i++) {
++ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
+ if (dev_self[i])
+ irport_close(dev_self[i]);
+ }
+diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h
+index fc89c8c..3f46b84 100644
+--- a/drivers/net/irda/irport.h
++++ b/drivers/net/irda/irport.h
+@@ -74,7 +74,7 @@ struct irport_cb {
+ /* For piggyback drivers */
+ void *priv;
+ void (*change_speed)(void *priv, __u32 speed);
+- int (*interrupt)(int irq, void *dev_id, struct pt_regs *regs);
++ irqreturn_t (*interrupt)(int irq, void *dev_id);
+ };
+
+ #endif /* IRPORT_H */
+diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
+index 47f6f64..b32c52e 100644
+--- a/drivers/net/irda/mcs7780.c
++++ b/drivers/net/irda/mcs7780.c
+@@ -45,7 +45,6 @@
+
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/errno.h>
+@@ -765,7 +764,7 @@ static struct net_device_stats *mcs_net_
+ }
+
+ /* Receive callback function. */
+-static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs)
++static void mcs_receive_irq(struct urb *urb)
+ {
+ __u8 *bytes;
+ struct mcs_cb *mcs = urb->context;
+@@ -814,7 +813,7 @@ static void mcs_receive_irq(struct urb *
+ }
+
+ /* Transmit callback funtion. */
+-static void mcs_send_irq(struct urb *urb, struct pt_regs *regs)
++static void mcs_send_irq(struct urb *urb)
+ {
+ struct mcs_cb *mcs = urb->context;
+ struct net_device *ndev = mcs->netdev;
+diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h
+index 1a723d7..b18148c 100644
+--- a/drivers/net/irda/mcs7780.h
++++ b/drivers/net/irda/mcs7780.h
+@@ -156,8 +156,8 @@ static int mcs_net_close(struct net_devi
+ static int mcs_net_open(struct net_device *netdev);
+ static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev);
+
+-static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs);
+-static void mcs_send_irq(struct urb *urb, struct pt_regs *regs);
++static void mcs_receive_irq(struct urb *urb);
++static void mcs_send_irq(struct urb *urb);
+ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *netdev);
+
+ static int mcs_probe(struct usb_interface *intf,
+diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
+index cb62f2a..29b5ccd 100644
+--- a/drivers/net/irda/nsc-ircc.c
++++ b/drivers/net/irda/nsc-ircc.c
+@@ -110,7 +110,7 @@ static nsc_chip_t chips[] = {
+ { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8,
+ nsc_ircc_probe_338, nsc_ircc_init_338 },
+ /* Contributed by Steffen Pingel - IBM X40 */
+- { "PC8738x", { 0x164e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
++ { "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff,
+ nsc_ircc_probe_39x, nsc_ircc_init_39x },
+ /* Contributed by Jan Frey - IBM A30/A31 */
+ { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
+@@ -2066,20 +2066,14 @@ static void nsc_ircc_fir_interrupt(struc
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+-static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct nsc_ircc_cb *self;
+ __u8 bsr, eir;
+ int iobase;
+
+- if (!dev) {
+- IRDA_WARNING("%s: irq %d for unknown device.\n",
+- driver_name, irq);
+- return IRQ_NONE;
+- }
+- self = (struct nsc_ircc_cb *) dev->priv;
++ self = dev->priv;
+
+ spin_lock(&self->lock);
+
+diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
+index afb19e8..f9a1c88 100644
+--- a/drivers/net/irda/pxaficp_ir.c
++++ b/drivers/net/irda/pxaficp_ir.c
+@@ -199,7 +199,7 @@ static int pxa_irda_set_speed(struct pxa
+ }
+
+ /* SIR interrupt service routine. */
+-static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct pxa_irda *si = netdev_priv(dev);
+@@ -281,7 +281,7 @@ static irqreturn_t pxa_irda_sir_irq(int
+ }
+
+ /* FIR Receive DMA interrupt handler */
+-static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *regs)
++static void pxa_irda_fir_dma_rx_irq(int channel, void *data)
+ {
+ int dcsr = DCSR(channel);
+
+@@ -291,7 +291,7 @@ static void pxa_irda_fir_dma_rx_irq(int
+ }
+
+ /* FIR Transmit DMA interrupt handler */
+-static void pxa_irda_fir_dma_tx_irq(int channel, void *data, struct pt_regs *regs)
++static void pxa_irda_fir_dma_tx_irq(int channel, void *data)
+ {
+ struct net_device *dev = data;
+ struct pxa_irda *si = netdev_priv(dev);
+@@ -388,7 +388,7 @@ static void pxa_irda_fir_irq_eif(struct
+ }
+
+ /* FIR interrupt handler */
+-static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct pxa_irda *si = netdev_priv(dev);
+diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
+index 8d5a288..937372d 100644
+--- a/drivers/net/irda/sa1100_ir.c
++++ b/drivers/net/irda/sa1100_ir.c
+@@ -579,7 +579,7 @@ static void sa1100_irda_fir_irq(struct n
+ sa1100_irda_rx_dma_start(si);
+ }
+
+-static irqreturn_t sa1100_irda_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ if (IS_FIR(((struct sa1100_irda *)dev->priv)))
+diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
+index 2eff45b..31c6233 100644
+--- a/drivers/net/irda/smsc-ircc2.c
++++ b/drivers/net/irda/smsc-ircc2.c
+@@ -196,7 +196,7 @@ static void smsc_ircc_dma_xmit(struct sm
+ static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self);
+ static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed);
+ static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed);
+-static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id);
+ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev);
+ static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
+ #if SMSC_IRCC2_C_SIR_STOP
+@@ -1455,7 +1455,7 @@ static void smsc_ircc_sir_receive(struct
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+-static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct smsc_ircc_cb *self;
+@@ -1520,7 +1520,7 @@ static irqreturn_t smsc_ircc_interrupt(i
+ }
+
+ /*
+- * Function irport_interrupt_sir (irq, dev_id, regs)
++ * Function irport_interrupt_sir (irq, dev_id)
+ *
+ * Interrupt handler for SIR modes
+ */
+@@ -2354,6 +2354,26 @@ static int __init smsc_superio_lpc(unsig
+ #define PCIID_VENDOR_INTEL 0x8086
+ #define PCIID_VENDOR_ALI 0x10b9
+ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
++ /*
++ * Subsystems needing entries:
++ * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
++ * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family
++ * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family
++ */
++ {
++ /* Guessed entry */
++ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
++ .device = 0x24cc,
++ .subvendor = 0x103c,
++ .subdevice = 0x08bc,
++ .sir_io = 0x02f8,
++ .fir_io = 0x0130,
++ .fir_irq = 0x05,
++ .fir_dma = 0x03,
++ .cfg_base = 0x004e,
++ .preconfigure = preconfigure_through_82801,
++ .name = "HP nx5000 family",
++ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+@@ -2366,7 +2386,7 @@ static struct smsc_ircc_subsystem_config
+ .fir_dma = 0x03,
+ .cfg_base = 0x004e,
+ .preconfigure = preconfigure_through_82801,
+- .name = "HP nc8000",
++ .name = "HP nc8000 family",
+ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+@@ -2379,7 +2399,21 @@ static struct smsc_ircc_subsystem_config
+ .fir_dma = 0x03,
+ .cfg_base = 0x004e,
+ .preconfigure = preconfigure_through_82801,
+- .name = "HP nc6000",
++ .name = "HP nc6000 family",
++ },
++ {
++ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
++ .device = 0x24cc,
++ .subvendor = 0x0e11,
++ .subdevice = 0x0860,
++ /* I assume these are the same for x1000 as for the others */
++ .sir_io = 0x02e8,
++ .fir_io = 0x02f8,
++ .fir_irq = 0x07,
++ .fir_dma = 0x03,
++ .cfg_base = 0x002e,
++ .preconfigure = preconfigure_through_82801,
++ .name = "Compaq x1000 family",
+ },
+ {
+ /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
+diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
+index d61b208..3b4c478 100644
+--- a/drivers/net/irda/stir4200.c
++++ b/drivers/net/irda/stir4200.c
+@@ -15,8 +15,7 @@
+ *
+ * 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 Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+@@ -149,8 +148,6 @@ enum StirFifoCtlMask {
+ FIFOCTL_DIR = 0x10,
+ FIFOCTL_CLR = 0x08,
+ FIFOCTL_EMPTY = 0x04,
+- FIFOCTL_RXERR = 0x02,
+- FIFOCTL_TXERR = 0x01,
+ };
+
+ enum StirDiagMask {
+@@ -615,19 +612,6 @@ static int fifo_txwait(struct stir_cb *s
+
+ pr_debug("fifo status 0x%lx count %lu\n", status, count);
+
+- /* error when receive/transmit fifo gets confused */
+- if (status & FIFOCTL_RXERR) {
+- stir->stats.rx_fifo_errors++;
+- stir->stats.rx_errors++;
+- break;
+- }
+-
+- if (status & FIFOCTL_TXERR) {
+- stir->stats.tx_fifo_errors++;
+- stir->stats.tx_errors++;
+- break;
+- }
+-
+ /* is fifo receiving already, or empty */
+ if (!(status & FIFOCTL_DIR)
+ || (status & FIFOCTL_EMPTY))
+@@ -819,7 +803,7 @@ static int stir_transmit_thread(void *ar
+ * Wakes up every ms (usb round trip) with wrapped
+ * data.
+ */
+-static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs)
++static void stir_rcv_irq(struct urb *urb)
+ {
+ struct stir_cb *stir = urb->context;
+ int err;
+diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
+index 8bafb45..c3ed9b3 100644
+--- a/drivers/net/irda/via-ircc.c
++++ b/drivers/net/irda/via-ircc.c
+@@ -93,8 +93,7 @@ static int via_ircc_hard_xmit_fir(struct
+ struct net_device *dev);
+ static void via_hw_init(struct via_ircc_cb *self);
+ static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud);
+-static irqreturn_t via_ircc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t via_ircc_interrupt(int irq, void *dev_id);
+ static int via_ircc_is_receiving(struct via_ircc_cb *self);
+ static int via_ircc_read_dongle_id(int iobase);
+
+@@ -279,7 +278,7 @@ static void via_ircc_clean(void)
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+- for (i=0; i < 4; i++) {
++ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
+ if (dev_self[i])
+ via_ircc_close(dev_self[i]);
+ }
+@@ -327,6 +326,9 @@ static __devinit int via_ircc_open(int i
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
++ if (i >= ARRAY_SIZE(dev_self))
++ return -ENOMEM;
++
+ /* Allocate new instance of the driver */
+ dev = alloc_irdadev(sizeof(struct via_ircc_cb));
+ if (dev == NULL)
+@@ -1220,8 +1222,13 @@ static int upload_rxdata(struct via_ircc
+
+ IRDA_DEBUG(2, "%s(): len=%x\n", __FUNCTION__, len);
+
++ if ((len - 4) < 2) {
++ self->stats.rx_dropped++;
++ return FALSE;
++ }
++
+ skb = dev_alloc_skb(len + 1);
+- if ((skb == NULL) || ((len - 4) < 2)) {
++ if (skb == NULL) {
+ self->stats.rx_dropped++;
+ return FALSE;
+ }
+@@ -1337,13 +1344,12 @@ static int RxTimerHandler(struct via_irc
+
+
+ /*
+- * Function via_ircc_interrupt (irq, dev_id, regs)
++ * Function via_ircc_interrupt (irq, dev_id)
+ *
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+-static irqreturn_t via_ircc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t via_ircc_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct via_ircc_cb *self;
+diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
+index 92d646c..18c6819 100644
+--- a/drivers/net/irda/vlsi_ir.c
++++ b/drivers/net/irda/vlsi_ir.c
+@@ -1455,8 +1455,7 @@ static int vlsi_ioctl(struct net_device
+
+ /********************************************************/
+
+-static irqreturn_t vlsi_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t vlsi_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *ndev = dev_instance;
+ vlsi_irda_dev_t *idev = ndev->priv;
+diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
+index a82a4ba..c37f0bc 100644
+--- a/drivers/net/irda/vlsi_ir.h
++++ b/drivers/net/irda/vlsi_ir.h
+@@ -58,7 +58,7 @@ typedef void irqreturn_t;
+
+ /* PDE() introduced in 2.5.4 */
+ #ifdef CONFIG_PROC_FS
+-#define PDE(inode) ((inode)->u.generic_ip)
++#define PDE(inode) ((inode)->i_private)
+ #endif
+
+ /* irda crc16 calculation exported in 2.5.42 */
+diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
+index 0ea65c4..4212657 100644
+--- a/drivers/net/irda/w83977af_ir.c
++++ b/drivers/net/irda/w83977af_ir.c
+@@ -40,7 +40,6 @@
+ ********************************************************************/
+
+ #include <linux/module.h>
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/skbuff.h>
+@@ -117,7 +116,7 @@ static int __init w83977af_init(void)
+
+ IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+
+- for (i=0; (io[i] < 2000) && (i < 4); i++) {
++ for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) {
+ if (w83977af_open(i, io[i], irq[i], dma[i]) == 0)
+ return 0;
+ }
+@@ -136,7 +135,7 @@ static void __exit w83977af_cleanup(void
+
+ IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+
+- for (i=0; i < 4; i++) {
++ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
+ if (dev_self[i])
+ w83977af_close(dev_self[i]);
+ }
+@@ -1112,20 +1111,14 @@ static __u8 w83977af_fir_interrupt(struc
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+-static irqreturn_t w83977af_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t w83977af_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct w83977af_ir *self;
+ __u8 set, icr, isr;
+ int iobase;
+
+- if (!dev) {
+- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+- driver_name, irq);
+- return IRQ_NONE;
+- }
+- self = (struct w83977af_ir *) dev->priv;
++ self = dev->priv;
+
+ iobase = self->io.fir_base;
+
+diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
+index 88ae8a0..0343f12 100644
+--- a/drivers/net/isa-skeleton.c
++++ b/drivers/net/isa-skeleton.c
+@@ -107,7 +107,7 @@ struct net_local {
+ static int netcard_probe1(struct net_device *dev, int ioaddr);
+ static int net_open(struct net_device *dev);
+ static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t net_interrupt(int irq, void *dev_id);
+ static void net_rx(struct net_device *dev);
+ static int net_close(struct net_device *dev);
+ static struct net_device_stats *net_get_stats(struct net_device *dev);
+@@ -149,7 +149,7 @@ static int __init do_netcard_probe(struc
+
+ return -ENODEV;
+ }
+-
++
+ static void cleanup_card(struct net_device *dev)
+ {
+ #ifdef jumpered_dma
+@@ -200,10 +200,10 @@ static int __init netcard_probe1(struct
+ return -EBUSY;
+
+ /*
+- * For ethernet adaptors the first three octets of the station address
++ * For ethernet adaptors the first three octets of the station address
+ * contains the manufacturer's unique code. That might be a good probe
+ * method. Ideally you would add additional checks.
+- */
++ */
+ if (inb(ioaddr + 0) != SA_ADDR0
+ || inb(ioaddr + 1) != SA_ADDR1
+ || inb(ioaddr + 2) != SA_ADDR2)
+@@ -292,7 +292,7 @@ static int __init netcard_probe1(struct
+ if (i <= 0) {
+ printk("DMA probe failed.\n");
+ goto out1;
+- }
++ }
+ if (request_dma(dev->dma, cardname)) {
+ printk("probed DMA %d allocation failed.\n", dev->dma);
+ goto out1;
+@@ -310,7 +310,7 @@ static int __init netcard_probe1(struct
+ dev->set_multicast_list = &set_multicast_list;
+
+ dev->tx_timeout = &net_tx_timeout;
+- dev->watchdog_timeo = MY_TX_TIMEOUT;
++ dev->watchdog_timeo = MY_TX_TIMEOUT;
+
+ err = register_netdev(dev);
+ if (err)
+@@ -504,7 +504,7 @@ void net_tx(struct net_device *dev)
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t net_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *np;
+@@ -551,7 +551,7 @@ net_rx(struct net_device *dev)
+ do {
+ int status = inw(ioaddr);
+ int pkt_len = inw(ioaddr);
+-
++
+ if (pkt_len == 0) /* Read all the frames? */
+ break; /* Done for now */
+
+@@ -566,7 +566,7 @@ net_rx(struct net_device *dev)
+ struct sk_buff *skb;
+
+ lp->stats.rx_bytes+=pkt_len;
+-
++
+ skb = dev_alloc_skb(pkt_len);
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+@@ -663,7 +663,7 @@ set_multicast_list(struct net_device *de
+
+ outw(MULTICAST, ioaddr);
+ }
+- else
++ else
+ outw(0, ioaddr);
+ }
+
+diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
+index cdc1440..2284e2c 100644
+--- a/drivers/net/iseries_veth.c
++++ b/drivers/net/iseries_veth.c
+@@ -586,7 +586,7 @@ static void veth_handle_int(struct veth_
+ };
+ }
+
+-static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
++static void veth_handle_event(struct HvLpEvent *event)
+ {
+ struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
+
+@@ -1029,7 +1029,7 @@ static u32 veth_get_link(struct net_devi
+ return 1;
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = veth_get_drvinfo,
+ .get_settings = veth_get_settings,
+ .get_link = veth_get_link,
+diff --git a/drivers/net/ixgb/Makefile b/drivers/net/ixgb/Makefile
+index a8a2d3d..838a508 100644
+--- a/drivers/net/ixgb/Makefile
++++ b/drivers/net/ixgb/Makefile
+@@ -1,33 +1,33 @@
+ ################################################################################
+ #
+-#
+-# Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++# Intel PRO/10GbE Linux driver
++# Copyright(c) 1999 - 2006 Intel Corporation.
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms and conditions of the GNU General Public License,
++# version 2, as published by the Free Software Foundation.
++#
++# This program is distributed in the hope it will be useful, but WITHOUT
++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ # more details.
+-#
++#
+ # You should have received a copy of the GNU General Public License along with
+-# this program; if not, write to the Free Software Foundation, Inc., 59
+-# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-#
+-# The full GNU General Public License is included in this distribution in the
+-# file called LICENSE.
+-#
++# this program; if not, write to the Free Software Foundation, Inc.,
++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++#
++# The full GNU General Public License is included in this distribution in
++# the file called "COPYING".
++#
+ # Contact Information:
+ # Linux NICS <linux.nics at intel.com>
++# e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ # Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ #
+ ################################################################################
+
+ #
+-# Makefile for the Intel(R) PRO/10GbE driver
++# Makefile for the Intel(R) PRO/10GbE ethernet driver
+ #
+
+ obj-$(CONFIG_IXGB) += ixgb.o
+diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
+index 82b67af..50ffe90 100644
+--- a/drivers/net/ixgb/ixgb.h
++++ b/drivers/net/ixgb/ixgb.h
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -110,11 +110,8 @@ struct ixgb_adapter;
+ #define IXGB_RXBUFFER_8192 8192
+ #define IXGB_RXBUFFER_16384 16384
+
+-/* How many Tx Descriptors do we need to call netif_wake_queue? */
+-#define IXGB_TX_QUEUE_WAKE 16
+-
+ /* How many Rx Buffers do we bundle into one write to the hardware ? */
+-#define IXGB_RX_BUFFER_WRITE 4 /* Must be power of 2 */
++#define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */
+
+ /* only works for sizes that are powers of 2 */
+ #define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
+@@ -173,7 +170,7 @@ struct ixgb_adapter {
+ unsigned long led_status;
+
+ /* TX */
+- struct ixgb_desc_ring tx_ring;
++ struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp;
+ unsigned long timeo_start;
+ uint32_t tx_cmd_type;
+ uint64_t hw_csum_tx_good;
+diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
+index 8357c55..f15aebd 100644
+--- a/drivers/net/ixgb/ixgb_ee.c
++++ b/drivers/net/ixgb/ixgb_ee.c
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
+index bf6fa22..ef236b9 100644
+--- a/drivers/net/ixgb/ixgb_ee.h
++++ b/drivers/net/ixgb/ixgb_ee.h
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
+index cf19b89..cd22523 100644
+--- a/drivers/net/ixgb/ixgb_ethtool.c
++++ b/drivers/net/ixgb/ixgb_ethtool.c
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -654,11 +654,7 @@ ixgb_phys_id(struct net_device *netdev,
+
+ mod_timer(&adapter->blink_timer, jiffies);
+
+- if (data)
+- schedule_timeout_interruptible(data * HZ);
+- else
+- schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
+-
++ msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ ixgb_led_off(&adapter->hw);
+ clear_bit(IXGB_LED_ON, &adapter->led_status);
+@@ -703,7 +699,7 @@ ixgb_get_strings(struct net_device *netd
+ }
+ }
+
+-static struct ethtool_ops ixgb_ethtool_ops = {
++static const struct ethtool_ops ixgb_ethtool_ops = {
+ .get_settings = ixgb_get_settings,
+ .set_settings = ixgb_set_settings,
+ .get_drvinfo = ixgb_get_drvinfo,
+diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
+index f7fa10e..02089b6 100644
+--- a/drivers/net/ixgb/ixgb_hw.c
++++ b/drivers/net/ixgb/ixgb_hw.c
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -83,7 +83,7 @@ static uint32_t ixgb_mac_reset(struct ix
+ #endif
+
+ /* Delay a few ms just to allow the reset to complete */
+- msec_delay(IXGB_DELAY_AFTER_RESET);
++ msleep(IXGB_DELAY_AFTER_RESET);
+ ctrl_reg = IXGB_READ_REG(hw, CTRL0);
+ #ifdef DBG
+ /* Make sure the self-clearing global reset bit did self clear */
+@@ -133,7 +133,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
+ */
+ IXGB_WRITE_REG(hw, RCTL, IXGB_READ_REG(hw, RCTL) & ~IXGB_RCTL_RXEN);
+ IXGB_WRITE_REG(hw, TCTL, IXGB_READ_REG(hw, TCTL) & ~IXGB_TCTL_TXEN);
+- msec_delay(IXGB_DELAY_BEFORE_RESET);
++ msleep(IXGB_DELAY_BEFORE_RESET);
+
+ /* Issue a global reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA, and link units. It will not effect
+@@ -236,6 +236,17 @@ ixgb_identify_phy(struct ixgb_hw *hw)
+ DEBUGOUT("Identified G6104 optics\n");
+ phy_type = ixgb_phy_type_g6104;
+ break;
++ case IXGB_DEVICE_ID_82597EX_CX4:
++ DEBUGOUT("Identified CX4\n");
++ xpak_vendor = ixgb_identify_xpak_vendor(hw);
++ if (xpak_vendor == ixgb_xpak_vendor_intel) {
++ DEBUGOUT("Identified TXN17201 optics\n");
++ phy_type = ixgb_phy_type_txn17201;
++ } else {
++ DEBUGOUT("Identified G6005 optics\n");
++ phy_type = ixgb_phy_type_g6005;
++ }
++ break;
+ default:
+ DEBUGOUT("Unknown physical layer module\n");
+ phy_type = ixgb_phy_type_unknown;
+@@ -289,7 +300,7 @@ ixgb_init_hw(struct ixgb_hw *hw)
+ #endif
+
+ /* Delay a few ms just to allow the reset to complete */
+- msec_delay(IXGB_DELAY_AFTER_EE_RESET);
++ msleep(IXGB_DELAY_AFTER_EE_RESET);
+
+ if (ixgb_get_eeprom_data(hw) == FALSE) {
+ return(FALSE);
+diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
+index cb45689..40ef5ca 100644
+--- a/drivers/net/ixgb/ixgb_hw.h
++++ b/drivers/net/ixgb/ixgb_hw.h
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
+index 40a085f..4376e7e 100644
+--- a/drivers/net/ixgb/ixgb_ids.h
++++ b/drivers/net/ixgb/ixgb_ids.h
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -45,6 +45,7 @@
+
+ #define IXGB_DEVICE_ID_82597EX_CX4 0x109E
+ #define IXGB_SUBDEVICE_ID_A00C 0xA00C
++#define IXGB_SUBDEVICE_ID_A01C 0xA01C
+
+ #endif /* #ifndef _IXGB_IDS_H_ */
+ /* End of File */
+diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
+index 7bbd447..e09f575 100644
+--- a/drivers/net/ixgb/ixgb_main.c
++++ b/drivers/net/ixgb/ixgb_main.c
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Inte
+ #else
+ #define DRIVERNAPI "-NAPI"
+ #endif
+-#define DRV_VERSION "1.0.109-k2"DRIVERNAPI
++#define DRV_VERSION "1.0.117-k2"DRIVERNAPI
+ char ixgb_driver_version[] = DRV_VERSION;
+ static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
+
+@@ -93,7 +93,7 @@ static int ixgb_xmit_frame(struct sk_buf
+ static struct net_device_stats *ixgb_get_stats(struct net_device *netdev);
+ static int ixgb_change_mtu(struct net_device *netdev, int new_mtu);
+ static int ixgb_set_mac(struct net_device *netdev, void *p);
+-static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs);
++static irqreturn_t ixgb_intr(int irq, void *data);
+ static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
+
+ #ifdef CONFIG_IXGB_NAPI
+@@ -118,15 +118,26 @@ static void ixgb_restore_vlan(struct ixg
+ static void ixgb_netpoll(struct net_device *dev);
+ #endif
+
+-/* Exported from other modules */
++static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
++ enum pci_channel_state state);
++static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev);
++static void ixgb_io_resume (struct pci_dev *pdev);
+
++/* Exported from other modules */
+ extern void ixgb_check_options(struct ixgb_adapter *adapter);
+
++static struct pci_error_handlers ixgb_err_handler = {
++ .error_detected = ixgb_io_error_detected,
++ .slot_reset = ixgb_io_slot_reset,
++ .resume = ixgb_io_resume,
++};
++
+ static struct pci_driver ixgb_driver = {
+ .name = ixgb_driver_name,
+ .id_table = ixgb_pci_tbl,
+ .probe = ixgb_probe,
+ .remove = __devexit_p(ixgb_remove),
++ .err_handler = &ixgb_err_handler
+ };
+
+ MODULE_AUTHOR("Intel Corporation, <linux.nics at intel.com>");
+@@ -140,12 +151,12 @@ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+ /* some defines for controlling descriptor fetches in h/w */
+-#define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */
+-#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below
+- * this */
+-#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail
+- * is pushed this many descriptors
+- * from head */
++#define RXDCTL_WTHRESH_DEFAULT 15 /* chip writes back at this many or RXT0 */
++#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below
++ * this */
++#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail
++ * is pushed this many descriptors
++ * from head */
+
+ /**
+ * ixgb_init_module - Driver Registration Routine
+@@ -162,7 +173,7 @@ ixgb_init_module(void)
+
+ printk(KERN_INFO "%s\n", ixgb_copyright);
+
+- return pci_module_init(&ixgb_driver);
++ return pci_register_driver(&ixgb_driver);
+ }
+
+ module_init(ixgb_init_module);
+@@ -426,7 +437,7 @@ ixgb_probe(struct pci_dev *pdev,
+ netdev->poll_controller = ixgb_netpoll;
+ #endif
+
+- strcpy(netdev->name, pci_name(pdev));
++ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+ netdev->base_addr = adapter->hw.io_base;
+@@ -1174,6 +1185,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
+ int err;
+
+ if (likely(skb_is_gso(skb))) {
++ struct ixgb_buffer *buffer_info;
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+@@ -1196,6 +1208,8 @@ ixgb_tso(struct ixgb_adapter *adapter, s
+
+ i = adapter->tx_ring.next_to_use;
+ context_desc = IXGB_CONTEXT_DESC(adapter->tx_ring, i);
++ buffer_info = &adapter->tx_ring.buffer_info[i];
++ WARN_ON(buffer_info->dma != 0);
+
+ context_desc->ipcss = ipcss;
+ context_desc->ipcso = ipcso;
+@@ -1232,12 +1246,15 @@ ixgb_tx_csum(struct ixgb_adapter *adapte
+ unsigned int i;
+ uint8_t css, cso;
+
+- if(likely(skb->ip_summed == CHECKSUM_HW)) {
++ if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
++ struct ixgb_buffer *buffer_info;
+ css = skb->h.raw - skb->data;
+ cso = (skb->h.raw + skb->csum) - skb->data;
+
+ i = adapter->tx_ring.next_to_use;
+ context_desc = IXGB_CONTEXT_DESC(adapter->tx_ring, i);
++ buffer_info = &adapter->tx_ring.buffer_info[i];
++ WARN_ON(buffer_info->dma != 0);
+
+ context_desc->tucss = css;
+ context_desc->tucso = cso;
+@@ -1283,6 +1300,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter
+ buffer_info = &tx_ring->buffer_info[i];
+ size = min(len, IXGB_MAX_DATA_PER_TXD);
+ buffer_info->length = size;
++ WARN_ON(buffer_info->dma != 0);
+ buffer_info->dma =
+ pci_map_single(adapter->pdev,
+ skb->data + offset,
+@@ -1543,6 +1561,11 @@ void
+ ixgb_update_stats(struct ixgb_adapter *adapter)
+ {
+ struct net_device *netdev = adapter->netdev;
++ struct pci_dev *pdev = adapter->pdev;
++
++ /* Prevent stats update while adapter is being reset */
++ if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
++ return;
+
+ if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
+ (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
+@@ -1664,11 +1687,10 @@ ixgb_update_stats(struct ixgb_adapter *a
+ * ixgb_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+- * @pt_regs: CPU registers structure
+ **/
+
+ static irqreturn_t
+-ixgb_intr(int irq, void *data, struct pt_regs *regs)
++ixgb_intr(int irq, void *data)
+ {
+ struct net_device *netdev = data;
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
+@@ -1787,7 +1809,7 @@ ixgb_clean_tx_irq(struct ixgb_adapter *a
+ if (unlikely(netif_queue_stopped(netdev))) {
+ spin_lock(&adapter->tx_lock);
+ if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
+- (IXGB_DESC_UNUSED(tx_ring) > IXGB_TX_QUEUE_WAKE))
++ (IXGB_DESC_UNUSED(tx_ring) >= DESC_NEEDED))
+ netif_wake_queue(netdev);
+ spin_unlock(&adapter->tx_lock);
+ }
+@@ -1948,10 +1970,9 @@ ixgb_clean_rx_irq(struct ixgb_adapter *a
+ #define IXGB_CB_LENGTH 256
+ if (length < IXGB_CB_LENGTH) {
+ struct sk_buff *new_skb =
+- dev_alloc_skb(length + NET_IP_ALIGN);
++ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ if (new_skb) {
+ skb_reserve(new_skb, NET_IP_ALIGN);
+- new_skb->dev = netdev;
+ memcpy(new_skb->data - NET_IP_ALIGN,
+ skb->data - NET_IP_ALIGN,
+ length + NET_IP_ALIGN);
+@@ -2031,14 +2052,14 @@ ixgb_alloc_rx_buffers(struct ixgb_adapte
+ /* leave three descriptors unused */
+ while(--cleancount > 2) {
+ /* recycle! its good for you */
+- if (!(skb = buffer_info->skb))
+- skb = dev_alloc_skb(adapter->rx_buffer_len
+- + NET_IP_ALIGN);
+- else {
++ skb = buffer_info->skb;
++ if (skb) {
+ skb_trim(skb, 0);
+ goto map_skb;
+ }
+
++ skb = netdev_alloc_skb(netdev, adapter->rx_buffer_len
++ + NET_IP_ALIGN);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+@@ -2051,8 +2072,6 @@ ixgb_alloc_rx_buffers(struct ixgb_adapte
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+- skb->dev = netdev;
+-
+ buffer_info->skb = skb;
+ buffer_info->length = adapter->rx_buffer_len;
+ map_skb:
+@@ -2190,12 +2209,106 @@ ixgb_restore_vlan(struct ixgb_adapter *a
+
+ static void ixgb_netpoll(struct net_device *dev)
+ {
+- struct ixgb_adapter *adapter = dev->priv;
++ struct ixgb_adapter *adapter = netdev_priv(dev);
+
+ disable_irq(adapter->pdev->irq);
+- ixgb_intr(adapter->pdev->irq, dev, NULL);
++ ixgb_intr(adapter->pdev->irq, dev);
+ enable_irq(adapter->pdev->irq);
+ }
+ #endif
+
++/**
++ * ixgb_io_error_detected() - called when PCI error is detected
++ * @pdev pointer to pci device with error
++ * @state pci channel state after error
++ *
++ * This callback is called by the PCI subsystem whenever
++ * a PCI bus error is detected.
++ */
++static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
++ enum pci_channel_state state)
++{
++ struct net_device *netdev = pci_get_drvdata(pdev);
++ struct ixgb_adapter *adapter = netdev_priv(netdev);
++
++ if(netif_running(netdev))
++ ixgb_down(adapter, TRUE);
++
++ pci_disable_device(pdev);
++
++ /* Request a slot reset. */
++ return PCI_ERS_RESULT_NEED_RESET;
++}
++
++/**
++ * ixgb_io_slot_reset - called after the pci bus has been reset.
++ * @pdev pointer to pci device with error
++ *
++ * This callback is called after the PCI buss has been reset.
++ * Basically, this tries to restart the card from scratch.
++ * This is a shortened version of the device probe/discovery code,
++ * it resembles the first-half of the ixgb_probe() routine.
++ */
++static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev)
++{
++ struct net_device *netdev = pci_get_drvdata(pdev);
++ struct ixgb_adapter *adapter = netdev_priv(netdev);
++
++ if(pci_enable_device(pdev)) {
++ DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n");
++ return PCI_ERS_RESULT_DISCONNECT;
++ }
++
++ /* Perform card reset only on one instance of the card */
++ if (0 != PCI_FUNC (pdev->devfn))
++ return PCI_ERS_RESULT_RECOVERED;
++
++ pci_set_master(pdev);
++
++ netif_carrier_off(netdev);
++ netif_stop_queue(netdev);
++ ixgb_reset(adapter);
++
++ /* Make sure the EEPROM is good */
++ if(!ixgb_validate_eeprom_checksum(&adapter->hw)) {
++ DPRINTK(PROBE, ERR, "After reset, the EEPROM checksum is not valid.\n");
++ return PCI_ERS_RESULT_DISCONNECT;
++ }
++ ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
++ memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
++
++ if(!is_valid_ether_addr(netdev->perm_addr)) {
++ DPRINTK(PROBE, ERR, "After reset, invalid MAC address.\n");
++ return PCI_ERS_RESULT_DISCONNECT;
++ }
++
++ return PCI_ERS_RESULT_RECOVERED;
++}
++
++/**
++ * ixgb_io_resume - called when its OK to resume normal operations
++ * @pdev pointer to pci device with error
++ *
++ * The error recovery driver tells us that its OK to resume
++ * normal operation. Implementation resembles the second-half
++ * of the ixgb_probe() routine.
++ */
++static void ixgb_io_resume (struct pci_dev *pdev)
++{
++ struct net_device *netdev = pci_get_drvdata(pdev);
++ struct ixgb_adapter *adapter = netdev_priv(netdev);
++
++ pci_set_master(pdev);
++
++ if(netif_running(netdev)) {
++ if(ixgb_up(adapter)) {
++ printk ("ixgb: can't bring device back up after reset\n");
++ return;
++ }
++ }
++
++ netif_device_attach(netdev);
++ mod_timer(&adapter->watchdog_timer, jiffies);
++}
++
+ /* ixgb_main.c */
+diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
+index ee982fe..8434d75 100644
+--- a/drivers/net/ixgb/ixgb_osdep.h
++++ b/drivers/net/ixgb/ixgb_osdep.h
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+@@ -40,18 +40,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/sched.h>
+
+-#ifndef msec_delay
+-#define msec_delay(x) do { if(in_interrupt()) { \
+- /* Don't mdelay in interrupt context! */ \
+- BUG(); \
+- } else { \
+- msleep(x); \
+- } } while(0)
+-#endif
+-
+-#define PCI_COMMAND_REGISTER PCI_COMMAND
+-#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+-
+ typedef enum {
+ #undef FALSE
+ FALSE = 0,
+diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
+index 39fbed2..b27442a 100644
+--- a/drivers/net/ixgb/ixgb_param.c
++++ b/drivers/net/ixgb/ixgb_param.c
+@@ -1,27 +1,27 @@
+ /*******************************************************************************
+
+-
+- Copyright(c) 1999 - 2006 Intel 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. See the GNU General Public License for
++ Intel PRO/10GbE Linux driver
++ Copyright(c) 1999 - 2006 Intel Corporation.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+-
++
+ You should have received a copy of the GNU General Public License along with
+- this program; if not, write to the Free Software Foundation, Inc., 59
+- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+- The full GNU General Public License is included in this distribution in the
+- file called LICENSE.
+-
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
+ Contact Information:
+ Linux NICS <linux.nics at intel.com>
++ e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ *******************************************************************************/
+diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
+index 6eeb965..a4eccb1 100644
+--- a/drivers/net/ixp2000/ixpdev.c
++++ b/drivers/net/ixp2000/ixpdev.c
+@@ -188,7 +188,7 @@ static void ixpdev_tx_complete(void)
+ }
+ }
+
+-static irqreturn_t ixpdev_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
+ {
+ u32 status;
+
+diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
+index 661d75b..d34afb5 100644
+--- a/drivers/net/jazzsonic.c
++++ b/drivers/net/jazzsonic.c
+@@ -7,10 +7,10 @@
+ * dhd's support for 16-bit cards.
+ *
+ * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend at alpha.franken.de)
+- *
++ *
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+- *
++ *
+ * (C) 1995 by Andreas Busse (andy at waldorf-gmbh.de)
+ *
+ * A driver for the onboard Sonic ethernet controller on Mips Jazz
+@@ -65,7 +65,7 @@ do { \
+ /* use 0 for production, 1 for verification, >1 for debug */
+ #ifdef SONIC_DEBUG
+ static unsigned int sonic_debug = SONIC_DEBUG;
+-#else
++#else
+ static unsigned int sonic_debug = 1;
+ #endif
+
+@@ -80,7 +80,7 @@ static struct {
+ /*
+ * We cannot use station (ethernet) address prefixes to detect the
+ * sonic controller since these are board manufacturer depended.
+- * So we check for known Silicon Revision IDs instead.
++ * So we check for known Silicon Revision IDs instead.
+ */
+ static unsigned short known_revisions[] =
+ {
+@@ -119,7 +119,7 @@ static int __init sonic_probe1(struct ne
+ silicon_revision);
+ goto out;
+ }
+-
++
+ if (sonic_debug && version_printed++ == 0)
+ printk(version);
+
+@@ -138,7 +138,7 @@ static int __init sonic_probe1(struct ne
+ }
+
+ err = -ENOMEM;
+-
++
+ /* Initialize the device structure. */
+
+ lp->dma_bitmode = SONIC_BITMODE32;
+diff --git a/drivers/net/lance.c b/drivers/net/lance.c
+index 5b4dbfe..6efbd49 100644
+--- a/drivers/net/lance.c
++++ b/drivers/net/lance.c
+@@ -19,7 +19,7 @@
+ - alignment problem with 1.3.* kernel and some minor changes.
+ Thomas Bogendoerfer (tsbogend at bigbug.franken.de):
+ - added support for Linux/Alpha, but removed most of it, because
+- it worked only for the PCI chip.
++ it worked only for the PCI chip.
+ - added hook for the 32bit lance driver
+ - added PCnetPCI II (79C970A) to chip table
+ Paul Gortmaker (gpg109 at rsphy1.anu.edu.au):
+@@ -31,7 +31,7 @@
+ before unregister_netdev() which caused NULL pointer
+ reference later in the chain (in rtnetlink_fill_ifinfo())
+ -- Mika Kuoppala <miku at iki.fi>
+-
++
+ Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
+ the 2.1 version of the old driver - Alan Cox
+
+@@ -42,7 +42,7 @@
+ Vesselin Kostadinov <vesok at yahoo dot com > - 22/4/2004
+ */
+
+-static const char version[] = "lance.c:v1.15ac 1999/11/13 dplatt at 3do.com, becker at cesdis.gsfc.nasa.gov\n";
++static const char version[] = "lance.c:v1.16 2006/11/09 dplatt at 3do.com, becker at cesdis.gsfc.nasa.gov\n";
+
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -301,13 +301,13 @@ static int lance_open(struct net_device
+ static void lance_init_ring(struct net_device *dev, gfp_t mode);
+ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int lance_rx(struct net_device *dev);
+-static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t lance_interrupt(int irq, void *dev_id);
+ static int lance_close(struct net_device *dev);
+ static struct net_device_stats *lance_get_stats(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+ static void lance_tx_timeout (struct net_device *dev);
+
+-
++
+
+ #ifdef MODULE
+ #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */
+@@ -374,7 +374,7 @@ void cleanup_module(void)
+ for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+ struct net_device *dev = dev_lance[this_dev];
+ if (dev) {
+- unregister_netdev(dev);
++ unregister_netdev(dev);
+ cleanup_card(dev);
+ free_netdev(dev);
+ }
+@@ -531,7 +531,7 @@ static int __init lance_probe1(struct ne
+
+ dev->base_addr = ioaddr;
+ /* Make certain the data structures used by the LANCE are aligned and DMAble. */
+-
++
+ lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+ if(lp==NULL)
+ return -ENODEV;
+@@ -656,7 +656,7 @@ static int __init lance_probe1(struct ne
+ outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
+ if (request_dma(dma, chipname))
+ continue;
+-
++
+ flags=claim_dma_lock();
+ set_dma_mode(dma, DMA_MODE_CASCADE);
+ enable_dma(dma);
+@@ -737,7 +737,7 @@ out_lp:
+ return err;
+ }
+
+-
++
+ static int
+ lance_open(struct net_device *dev)
+ {
+@@ -801,7 +801,7 @@ lance_open(struct net_device *dev)
+ while (i++ < 100)
+ if (inw(ioaddr+LANCE_DATA) & 0x0100)
+ break;
+- /*
++ /*
+ * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+ * reports that doing so triggers a bug in the '974.
+ */
+@@ -826,7 +826,7 @@ lance_open(struct net_device *dev)
+ restarting the chip, but I'm too lazy to do so right now. dplatt at 3do.com
+ */
+
+-static void
++static void
+ lance_purge_ring(struct net_device *dev)
+ {
+ struct lance_private *lp = dev->priv;
+@@ -972,7 +972,7 @@ static int lance_start_xmit(struct sk_bu
+ goto out;
+ lp->tx_ring[entry].length = -ETH_ZLEN;
+ }
+- else
++ else
+ lp->tx_ring[entry].length = -skb->len;
+ } else
+ lp->tx_ring[entry].length = -skb->len;
+@@ -1012,22 +1012,16 @@ out:
+ }
+
+ /* The LANCE interrupt handler. */
+-static irqreturn_t
+-lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t lance_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct lance_private *lp;
+ int csr0, ioaddr, boguscnt=10;
+ int must_restart;
+
+- if (dev == NULL) {
+- printk ("lance_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
+ ioaddr = dev->base_addr;
+ lp = dev->priv;
+-
++
+ spin_lock (&lp->devlock);
+
+ outw(0x00, dev->base_addr + LANCE_ADDR);
+@@ -1051,7 +1045,7 @@ lance_interrupt(int irq, void *dev_id, s
+ while (dirty_tx < lp->cur_tx) {
+ int entry = dirty_tx & TX_RING_MOD_MASK;
+ int status = lp->tx_ring[entry].base;
+-
++
+ if (status < 0)
+ break; /* It still hasn't been Txed */
+
+@@ -1142,7 +1136,7 @@ lance_rx(struct net_device *dev)
+ struct lance_private *lp = dev->priv;
+ int entry = lp->cur_rx & RX_RING_MOD_MASK;
+ int i;
+-
++
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while (lp->rx_ring[entry].base >= 0) {
+ int status = lp->rx_ring[entry].base >> 24;
+@@ -1160,12 +1154,12 @@ lance_rx(struct net_device *dev)
+ if (status & 0x04) lp->stats.rx_fifo_errors++;
+ lp->rx_ring[entry].base &= 0x03ffffff;
+ }
+- else
++ else
+ {
+ /* Malloc up new buffer, compatible with net3. */
+ short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
+ struct sk_buff *skb;
+-
++
+ if(pkt_len<60)
+ {
+ printk("%s: Runt packet!\n",dev->name);
+@@ -1174,14 +1168,14 @@ lance_rx(struct net_device *dev)
+ else
+ {
+ skb = dev_alloc_skb(pkt_len+2);
+- if (skb == NULL)
++ if (skb == NULL)
+ {
+ printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+ for (i=0; i < RX_RING_SIZE; i++)
+ if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0)
+ break;
+
+- if (i > RX_RING_SIZE -2)
++ if (i > RX_RING_SIZE -2)
+ {
+ lp->stats.rx_dropped++;
+ lp->rx_ring[entry].base |= 0x80000000;
+@@ -1281,8 +1275,6 @@ static void set_multicast_list(struct ne
+ outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */
+
+ if (dev->flags&IFF_PROMISC) {
+- /* Log any net taps. */
+- printk("%s: Promiscuous mode enabled.\n", dev->name);
+ outw(15, ioaddr+LANCE_ADDR);
+ outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
+ } else {
+diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
+index 1ab0944..f4d815b 100644
+--- a/drivers/net/lasi_82596.c
++++ b/drivers/net/lasi_82596.c
+@@ -5,14 +5,14 @@
+ but there were too many hoops which HP wants jumped through to
+ keep this code in there in a sane manner.
+
+- 3 primary sources of the mess --
++ 3 primary sources of the mess --
+ 1) hppa needs *lots* of cacheline flushing to keep this kind of
+ MMIO running.
+
+ 2) The 82596 needs to see all of its pointers as their physical
+ address. Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+- 3) The implementation HP is using seems to be significantly pickier
++ 3) The implementation HP is using seems to be significantly pickier
+ about when and how the command and RX units are started. some
+ command ordering was changed.
+
+@@ -21,7 +21,7 @@
+ full rewrite can be my guest.
+
+ Split 02/13/2000 Sam Creasey (sammy at oh.verio.com)
+-
++
+ 02/01/2000 Initial modifications for parisc by Helge Deller (deller at gmx.de)
+ 03/02/2000 changes for better/correct(?) cache-flushing (deller)
+ */
+@@ -172,7 +172,7 @@
+ #define PORT_ALTSCP 0x02 /* alternate SCB address */
+ #define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
+
+-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
++static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+ MODULE_AUTHOR("Richard Hirst");
+ MODULE_DESCRIPTION("i82596 driver");
+@@ -265,9 +265,9 @@ struct tx_cmd {
+ dma_addr_t dma_addr;
+ #ifdef __LP64__
+ u32 cache_pad[6]; /* Total 64 bytes... */
+-#else
++#else
+ u32 cache_pad[1]; /* Total 32 bytes... */
+-#endif
++#endif
+ };
+
+ struct tdr_cmd {
+@@ -301,9 +301,9 @@ struct i596_rfd {
+ unsigned short size;
+ struct i596_rfd *v_next; /* Address from CPUs viewpoint */
+ struct i596_rfd *v_prev;
+-#ifndef __LP64__
++#ifndef __LP64__
+ u32 cache_pad[2]; /* Total 32 bytes... */
+-#endif
++#endif
+ };
+
+ struct i596_rbd {
+@@ -322,7 +322,7 @@ struct i596_rbd {
+ /* Total 32 bytes... */
+ #ifdef __LP64__
+ u32 cache_pad[4];
+-#endif
++#endif
+ };
+
+ /* These values as chosen so struct i596_private fits in one page... */
+@@ -403,7 +403,7 @@ static char init_setup[] =
+
+ static int i596_open(struct net_device *dev);
+ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t i596_interrupt(int irq, void *dev_id);
+ static int i596_close(struct net_device *dev);
+ static struct net_device_stats *i596_get_stats(struct net_device *dev);
+ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+@@ -527,7 +527,7 @@ static void i596_display_data(struct net
+
+
+ #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+-static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
++static void i596_error(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+@@ -605,7 +605,7 @@ static inline void remove_rx_bufs(struct
+ if (rbd->skb == NULL)
+ break;
+ dma_unmap_single(lp->dev,
+- (dma_addr_t)WSWAPchar(rbd->b_data),
++ (dma_addr_t)WSWAPchar(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ dev_kfree_skb(rbd->skb);
+ }
+@@ -643,7 +643,7 @@ static int init_i596_mem(struct net_devi
+ printk("RESET 82596 port: %lx (with IRQ %d disabled)\n",
+ (dev->base_addr + PA_I82596_RESET),
+ dev->irq));
+-
++
+ gsc_writel(0, (dev->base_addr + PA_I82596_RESET)); /* Hard Reset */
+ udelay(100); /* Wait 100us - seems to help */
+
+@@ -666,7 +666,7 @@ static int init_i596_mem(struct net_devi
+ CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp));
+ CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp));
+
+- MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));
++ MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));
+
+ CA(dev);
+
+@@ -755,7 +755,7 @@ static inline int i596_rx(struct net_dev
+ }
+ DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+-
++
+ if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
+ /* a good frame */
+ int pkt_len = rbd->count & 0x3fff;
+@@ -996,7 +996,7 @@ static int i596_test(struct net_device *
+
+ tint = (volatile int *)(&(lp->scp));
+ data = virt_to_dma(lp,tint);
+-
++
+ tint[1] = -1;
+ CHECK_WBACK(tint,PAGE_SIZE);
+
+@@ -1087,7 +1087,7 @@ static int i596_start_xmit(struct sk_buf
+ return 0;
+ length = ETH_ZLEN;
+ }
+-
++
+ netif_stop_queue(dev);
+
+ tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+@@ -1194,7 +1194,7 @@ static int __devinit i82596_probe(struct
+ printk(KERN_INFO "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
+ }
+
+- dev->mem_start = (unsigned long) dma_alloc_noncoherent(gen_dev,
++ dev->mem_start = (unsigned long) dma_alloc_noncoherent(gen_dev,
+ sizeof(struct i596_private), &dma_addr, GFP_KERNEL);
+ if (!dev->mem_start) {
+ printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
+@@ -1233,7 +1233,7 @@ static int __devinit i82596_probe(struct
+ i = register_netdev(dev);
+ if (i) {
+ lp = dev->priv;
+- dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
++ dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
+ (void *)dev->mem_start, lp->dma_addr);
+ return i;
+ };
+@@ -1252,12 +1252,12 @@ static int __devinit i82596_probe(struct
+ static void i596_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- i596_interrupt(dev->irq, dev, NULL);
++ i596_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+
+-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i596_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct i596_private *lp;
+@@ -1400,7 +1400,7 @@ static irqreturn_t i596_interrupt(int ir
+ CHECK_WBACK(&lp->scb, sizeof(struct i596_scb));
+
+ /* DANGER: I suspect that some kind of interrupt
+- acknowledgement aside from acking the 82596 might be needed
++ acknowledgement aside from acking the 82596 might be needed
+ here... but it's running acceptably without */
+
+ CA(dev);
+@@ -1498,7 +1498,7 @@ static void set_multicast_list(struct ne
+ printk("%s: Only %d multicast addresses supported",
+ dev->name, cnt);
+ }
+-
++
+ if (dev->mc_count > 0) {
+ struct dev_mc_list *dmi;
+ unsigned char *cp;
+@@ -1539,7 +1539,7 @@ lan_init_chip(struct parisc_device *dev)
+
+ if (num_drivers == 0)
+ printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
+-
++
+ if (!dev->irq) {
+ printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+ __FILE__, dev->hpa.start);
+@@ -1602,15 +1602,15 @@ static void __exit lasi_82596_exit(void)
+ for (i=0; i<MAX_DRIVERS; i++) {
+ struct i596_private *lp;
+ struct net_device *netdevice;
+-
++
+ netdevice = netdevs[i];
+- if (!netdevice)
++ if (!netdevice)
+ continue;
+-
++
+ unregister_netdev(netdevice);
+
+ lp = netdevice->priv;
+- dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
++ dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
+ (void *)netdevice->mem_start, lp->dma_addr);
+ free_netdev(netdevice);
+ }
+diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
+index c0ec7f6..5795ee1 100644
+--- a/drivers/net/lne390.c
++++ b/drivers/net/lne390.c
+@@ -188,7 +188,7 @@ static int __init lne390_probe1(struct n
+ }
+
+ revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
+-
++
+ #if 0
+ /* Check the Mylex vendor ID as well. Not really required. */
+ if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
+@@ -341,7 +341,7 @@ lne390_get_8390_hdr(struct net_device *d
+ hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
+ }
+
+-/*
++/*
+ * Block input and output are easy on shared memory ethercards, the only
+ * complication is when the ring buffer wraps. The count will already
+ * be rounded up to a doubleword value via lne390_get_8390_hdr() above.
+diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
+index 997cbce..82c10de 100644
+--- a/drivers/net/loopback.c
++++ b/drivers/net/loopback.c
+@@ -58,7 +58,11 @@
+ #include <linux/tcp.h>
+ #include <linux/percpu.h>
+
+-static DEFINE_PER_CPU(struct net_device_stats, loopback_stats);
++struct pcpu_lstats {
++ unsigned long packets;
++ unsigned long bytes;
++};
++static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
+
+ #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
+
+@@ -128,7 +132,7 @@ static void emulate_large_send_offload(s
+ */
+ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+- struct net_device_stats *lb_stats;
++ struct pcpu_lstats *lb_stats;
+
+ skb_orphan(skb);
+
+@@ -149,55 +153,61 @@ static int loopback_xmit(struct sk_buff
+ #endif
+ dev->last_rx = jiffies;
+
+- lb_stats = &per_cpu(loopback_stats, get_cpu());
+- lb_stats->rx_bytes += skb->len;
+- lb_stats->tx_bytes = lb_stats->rx_bytes;
+- lb_stats->rx_packets++;
+- lb_stats->tx_packets = lb_stats->rx_packets;
+- put_cpu();
++ /* it's OK to use __get_cpu_var() because BHs are off */
++ lb_stats = &__get_cpu_var(pcpu_lstats);
++ lb_stats->bytes += skb->len;
++ lb_stats->packets++;
+
+ netif_rx(skb);
+
+- return(0);
++ return 0;
+ }
+
++static struct net_device_stats loopback_stats;
++
+ static struct net_device_stats *get_stats(struct net_device *dev)
+ {
+- struct net_device_stats *stats = dev->priv;
++ struct net_device_stats *stats = &loopback_stats;
++ unsigned long bytes = 0;
++ unsigned long packets = 0;
+ int i;
+
+- if (!stats) {
+- return NULL;
+- }
+-
+- memset(stats, 0, sizeof(struct net_device_stats));
+-
+ for_each_possible_cpu(i) {
+- struct net_device_stats *lb_stats;
++ const struct pcpu_lstats *lb_stats;
+
+- lb_stats = &per_cpu(loopback_stats, i);
+- stats->rx_bytes += lb_stats->rx_bytes;
+- stats->tx_bytes += lb_stats->tx_bytes;
+- stats->rx_packets += lb_stats->rx_packets;
+- stats->tx_packets += lb_stats->tx_packets;
++ lb_stats = &per_cpu(pcpu_lstats, i);
++ bytes += lb_stats->bytes;
++ packets += lb_stats->packets;
+ }
+-
++ stats->rx_packets = packets;
++ stats->tx_packets = packets;
++ stats->rx_bytes = bytes;
++ stats->tx_bytes = bytes;
+ return stats;
+ }
+
+-static u32 loopback_get_link(struct net_device *dev)
++static u32 always_on(struct net_device *dev)
+ {
+ return 1;
+ }
+
+-static struct ethtool_ops loopback_ethtool_ops = {
+- .get_link = loopback_get_link,
++static const struct ethtool_ops loopback_ethtool_ops = {
++ .get_link = always_on,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
++ .get_tx_csum = always_on,
++ .get_sg = always_on,
++ .get_rx_csum = always_on,
+ };
+
++/*
++ * The loopback device is special. There is only one instance and
++ * it is statically allocated. Don't do this for other devices.
++ */
+ struct net_device loopback_dev = {
+ .name = "lo",
++ .get_stats = &get_stats,
++ .priv = &loopback_stats,
+ .mtu = (16 * 1024) + 20 + 20 + 12,
+ .hard_start_xmit = loopback_xmit,
+ .hard_header = eth_header,
+@@ -221,16 +231,6 @@ struct net_device loopback_dev = {
+ /* Setup and register the loopback device. */
+ int __init loopback_init(void)
+ {
+- struct net_device_stats *stats;
+-
+- /* Can survive without statistics */
+- stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+- if (stats) {
+- memset(stats, 0, sizeof(struct net_device_stats));
+- loopback_dev.priv = stats;
+- loopback_dev.get_stats = &get_stats;
+- }
+-
+ return register_netdev(&loopback_dev);
+ };
+
+diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
+index b783a69..b833016 100644
+--- a/drivers/net/lp486e.c
++++ b/drivers/net/lp486e.c
+@@ -277,7 +277,7 @@ struct i596_rbd {
+ phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
+ phys_addr pa_data; /* va_to_pa(char *data) */
+ phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */
+-
++
+ /* Driver private part */
+ struct sk_buff *skb;
+ };
+@@ -379,7 +379,7 @@ static char init_setup[14] = {
+
+ static int i596_open(struct net_device *dev);
+ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t i596_interrupt(int irq, void *dev_id);
+ static int i596_close(struct net_device *dev);
+ static struct net_device_stats *i596_get_stats(struct net_device *dev);
+ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+@@ -442,16 +442,16 @@ init_rx_bufs(struct net_device *dev, int
+ if (rbd) {
+ rbd->pad = 0;
+ rbd->count = 0;
+- rbd->skb = dev_alloc_skb(RX_SKB_SIZE);
++ rbd->skb = dev_alloc_skb(RX_SKBSIZE);
+ if (!rbd->skb) {
+ printk("dev_alloc_skb failed");
+ }
+ rbd->next = rfd->rbd;
+ if (i) {
+ rfd->rbd->prev = rbd;
+- rbd->size = RX_SKB_SIZE;
++ rbd->size = RX_SKBSIZE;
+ } else {
+- rbd->size = (RX_SKB_SIZE | RBD_EL);
++ rbd->size = (RX_SKBSIZE | RBD_EL);
+ lp->rbd_tail = rbd;
+ }
+
+@@ -647,7 +647,7 @@ init_i596(struct net_device *dev) {
+ CA();
+
+ barrier();
+-
++
+ if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
+ return 1;
+
+@@ -676,7 +676,7 @@ i596_rx_one(struct net_device *dev, stru
+ return 1;
+ }
+
+- skb->dev = dev;
++ skb->dev = dev;
+ memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
+
+ skb->protocol = eth_type_trans(skb,dev);
+@@ -797,7 +797,7 @@ static void i596_reset(struct net_device
+ lp->scb.command = CUC_ABORT | RX_ABORT;
+ CA();
+ barrier();
+-
++
+ /* wait for shutdown */
+ if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
+ ;
+@@ -820,7 +820,7 @@ static void i596_add_cmd(struct net_devi
+ cmd->pa_next = I596_NULL;
+
+ spin_lock_irqsave(&lp->cmd_lock, flags);
+-
++
+ if (lp->cmd_head) {
+ lp->cmd_tail->pa_next = va_to_pa(cmd);
+ } else {
+@@ -847,7 +847,7 @@ static void i596_add_cmd(struct net_devi
+ }
+ }
+
+-static int i596_open(struct net_device *dev)
++static int i596_open(struct net_device *dev)
+ {
+ int i;
+
+@@ -875,13 +875,13 @@ static int i596_start_xmit (struct sk_bu
+ short length;
+
+ length = skb->len;
+-
++
+ if (length < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
+ length = ETH_ZLEN;
+ }
+-
++
+ dev->trans_start = jiffies;
+
+ tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
+@@ -941,7 +941,7 @@ i596_tx_timeout (struct net_device *dev)
+ netif_wake_queue(dev);
+ }
+
+-static void print_eth(char *add)
++static void print_eth(char *add)
+ {
+ int i;
+
+@@ -978,7 +978,7 @@ static int __init lp486e_probe(struct ne
+
+ lp = (struct i596_private *) dev->priv;
+ spin_lock_init(&lp->cmd_lock);
+-
++
+ /*
+ * Do we really have this thing?
+ */
+@@ -1132,7 +1132,7 @@ i596_handle_CU_completion(struct net_dev
+ default:
+ cmd->pa_next = I596_NULL;
+ lp->last_cmd = jiffies;
+-
++
+ }
+ barrier();
+ }
+@@ -1151,7 +1151,7 @@ i596_handle_CU_completion(struct net_dev
+ }
+
+ static irqreturn_t
+-i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) {
++i596_interrupt (int irq, void *dev_instance) {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct i596_private *lp;
+ unsigned short status, ack_cmd = 0;
+diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
+index 06cb460..ade6ff8 100644
+--- a/drivers/net/mac8390.c
++++ b/drivers/net/mac8390.c
+@@ -7,12 +7,12 @@
+ This software may be used and distributed according to the terms of
+ the GNU Public License, incorporated herein by reference. */
+
+-/* 2000-02-28: support added for Dayna and Kinetics cards by
++/* 2000-02-28: support added for Dayna and Kinetics cards by
+ A.G.deWijn at phys.uu.nl */
+ /* 2000-04-04: support added for Dayna2 by bart at etpmod.phys.tue.nl */
+ /* 2001-04-18: support for DaynaPort E/LC-M by rayk at knightsmanor.org */
+ /* 2001-05-15: support for Cabletron ported from old daynaport driver
+- * and fixed access to Sonic Sys card which masquerades as a Farallon
++ * and fixed access to Sonic Sys card which masquerades as a Farallon
+ * by rayk at knightsmanor.org */
+
+ #include <linux/module.h>
+@@ -55,7 +55,7 @@
+ #define KINETICS_8390_BASE 0x80000
+ #define KINETICS_8390_MEM 0x00000
+
+-#define CABLETRON_8390_BASE 0x90000
++#define CABLETRON_8390_BASE 0x90000
+ #define CABLETRON_8390_MEM 0x00000
+
+ enum mac8390_type {
+@@ -118,7 +118,7 @@ static int useresources[] = {
+
+ static char version[] __initdata =
+ "mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd at debian.org> and others\n";
+-
++
+ extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
+ extern int mac8390_memsize(unsigned long membase);
+ extern int mac8390_memtest(struct net_device * dev);
+@@ -168,7 +168,7 @@ enum mac8390_type __init mac8390_ident(s
+ {
+ if (dev->dr_sw == NUBUS_DRSW_ASANTE)
+ return MAC8390_ASANTE;
+- if (dev->dr_sw == NUBUS_DRSW_FARALLON)
++ if (dev->dr_sw == NUBUS_DRSW_FARALLON)
+ return MAC8390_FARALLON;
+ if (dev->dr_sw == NUBUS_DRSW_KINETICS)
+ return MAC8390_KINETICS;
+@@ -187,7 +187,7 @@ int __init mac8390_memsize(unsigned long
+ {
+ unsigned long flags;
+ int i, j;
+-
++
+ local_irq_save(flags);
+ /* Check up to 32K in 4K increments */
+ for (i = 0; i < 8; i++) {
+@@ -197,7 +197,7 @@ int __init mac8390_memsize(unsigned long
+ RAM end located */
+ if (hwreg_present(m) == 0)
+ break;
+-
++
+ /* write a distinctive byte */
+ *m = 0xA5A0 | i;
+ /* check that we read back what we wrote */
+@@ -224,7 +224,7 @@ struct net_device * __init mac8390_probe
+ int version_disp = 0;
+ struct nubus_dev * ndev = NULL;
+ int err = -ENODEV;
+-
++
+ struct nubus_dir dir;
+ struct nubus_dirent ent;
+ int offset;
+@@ -273,7 +273,7 @@ struct net_device * __init mac8390_probe
+ dev->name, ndev->board->slot);
+ continue;
+ }
+-
++
+ /* Get the MAC address */
+ if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
+ printk(KERN_INFO "%s: Couldn't get MAC address!\n",
+@@ -282,7 +282,7 @@ struct net_device * __init mac8390_probe
+ } else {
+ nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
+ /* Some Sonic Sys cards masquerade as Farallon */
+- if (cardtype == MAC8390_FARALLON &&
++ if (cardtype == MAC8390_FARALLON &&
+ dev->dev_addr[0] == 0x0 &&
+ dev->dev_addr[1] == 0x40 &&
+ dev->dev_addr[2] == 0x10) {
+@@ -290,7 +290,7 @@ struct net_device * __init mac8390_probe
+ cardtype = MAC8390_SONICSYS;
+ }
+ }
+-
++
+ if (useresources[cardtype] == 1) {
+ nubus_rewinddir(&dir);
+ if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
+@@ -318,10 +318,10 @@ struct net_device * __init mac8390_probe
+ switch (cardtype) {
+ case MAC8390_KINETICS:
+ case MAC8390_DAYNA: /* it's the same */
+- dev->base_addr =
++ dev->base_addr =
+ (int)(ndev->board->slot_addr +
+ DAYNA_8390_BASE);
+- dev->mem_start =
++ dev->mem_start =
+ (int)(ndev->board->slot_addr +
+ DAYNA_8390_MEM);
+ dev->mem_end =
+@@ -343,11 +343,11 @@ struct net_device * __init mac8390_probe
+ */
+ i = (void *)dev->base_addr;
+ *i = 0x21;
+- dev->mem_end =
++ dev->mem_end =
+ dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
+-
++
+ default:
+ printk(KERN_ERR "Card type %s is"
+ " unsupported, sorry\n",
+@@ -433,7 +433,7 @@ static int __init mac8390_initdev(struct
+ };
+
+ int access_bitmode;
+-
++
+ /* Now fill in our stuff */
+ dev->open = &mac8390_open;
+ dev->stop = &mac8390_close;
+@@ -459,7 +459,7 @@ static int __init mac8390_initdev(struct
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_end = dev->mem_end;
+ }
+-
++
+ /* Fill in model-specific information and functions */
+ switch(type) {
+ case MAC8390_SONICSYS:
+@@ -509,7 +509,7 @@ static int __init mac8390_initdev(struct
+ printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
+ return -ENODEV;
+ }
+-
++
+ NS8390_init(dev, 0);
+
+ /* Good, done, now spit out some messages */
+@@ -525,7 +525,7 @@ static int __init mac8390_initdev(struct
+ }
+ }
+ printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n",
+- dev->irq, dev->mem_start, dev->mem_end-1,
++ dev->irq, dev->mem_start, dev->mem_end-1,
+ access_bitmode?32:16);
+ return 0;
+ }
+@@ -536,7 +536,7 @@ static int mac8390_open(struct net_devic
+ if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) {
+ printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
+- }
++ }
+ return 0;
+ }
+
+@@ -639,7 +639,7 @@ static void sane_block_output(struct net
+ const unsigned char *buf, int start_page)
+ {
+ long shmem = (start_page - WD_START_PG)<<8;
+-
++
+ memcpy_toio((char *)dev->mem_start + shmem, buf, count);
+ }
+
+@@ -681,12 +681,12 @@ static void dayna_block_output(struct ne
+ int start_page)
+ {
+ long shmem = (start_page - WD_START_PG)<<8;
+-
++
+ dayna_memcpy_tocard(dev, shmem, buf, count);
+ }
+
+ /* Cabletron block I/O */
+-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
++static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page)
+ {
+ unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+@@ -750,4 +750,4 @@ static void word_memcpy_fromcard(void *t
+ *to++=*from++;
+ }
+
+-
++
+diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
+index cd3c9a5..e960138 100644
+--- a/drivers/net/mac89x0.c
++++ b/drivers/net/mac89x0.c
+@@ -12,24 +12,24 @@
+ Changelog:
+
+ Mike Cruse : mcruse at cti-ltd.com
+- : Changes for Linux 2.0 compatibility.
++ : Changes for Linux 2.0 compatibility.
+ : Added dev_id parameter in net_interrupt(),
+ : request_irq() and free_irq(). Just NULL for now.
+
+ Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
+ : in net_open() and net_close() so kerneld would know
+- : that the module is in use and wouldn't eject the
++ : that the module is in use and wouldn't eject the
+ : driver prematurely.
+
+ Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
+ : as an example. Disabled autoprobing in init_module(),
+ : not a good thing to do to other devices while Linux
+ : is running from all accounts.
+-
++
+ Alan Cox : Removed 1.2 support, added 2.1 extra counters.
+
+ David Huggins-Daines <dhd at debian.org>
+-
++
+ Split this off into mac89x0.c, and gutted it of all parts which are
+ not relevant to the existing CS8900 cards on the Macintosh
+ (i.e. basically the Daynaport CS and LC cards). To be precise:
+@@ -129,7 +129,7 @@ extern void reset_chip(struct net_device
+ #endif
+ static int net_open(struct net_device *dev);
+ static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t net_interrupt(int irq, void *dev_id);
+ static void set_multicast_list(struct net_device *dev);
+ static void net_rx(struct net_device *dev);
+ static int net_close(struct net_device *dev);
+@@ -210,7 +210,7 @@ struct net_device * __init mac89x0_probe
+ {
+ unsigned long flags;
+ int card_present;
+-
++
+ local_irq_save(flags);
+ card_present = hwreg_present((void*) ioaddr+4)
+ && hwreg_present((void*) ioaddr + DATA_PORT);
+@@ -230,7 +230,7 @@ struct net_device * __init mac89x0_probe
+
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = ioaddr;
+- dev->mem_start = (unsigned long)
++ dev->mem_start = (unsigned long)
+ nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
+ dev->mem_end = dev->mem_start + 0x1000;
+
+@@ -428,10 +428,10 @@ net_send_packet(struct sk_buff *skb, str
+
+ return 0;
+ }
+-
++
+ /* The typical workload of the driver:
+ Handle the network interface interrupts. */
+-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t net_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+@@ -596,7 +596,7 @@ static void set_multicast_list(struct ne
+ /* The multicast-accept list is initialized to accept-all, and we
+ rely on higher-level filtering for now. */
+ lp->rx_mode = RX_MULTCAST_ACCEPT;
+- }
++ }
+ else
+ lp->rx_mode = 0;
+
+@@ -653,7 +653,7 @@ cleanup_module(void)
+ free_netdev(dev_cs89x0);
+ }
+ #endif /* MODULE */
+-
++
+ /*
+ * Local variables:
+ * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c"
+diff --git a/drivers/net/mace.c b/drivers/net/mace.c
+index 29e4b5a..2907cfb 100644
+--- a/drivers/net/mace.c
++++ b/drivers/net/mace.c
+@@ -82,9 +82,9 @@ static struct net_device_stats *mace_sta
+ static void mace_set_multicast(struct net_device *dev);
+ static void mace_reset(struct net_device *dev);
+ static int mace_set_address(struct net_device *dev, void *addr);
+-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t mace_interrupt(int irq, void *dev_id);
++static irqreturn_t mace_txdma_intr(int irq, void *dev_id);
++static irqreturn_t mace_rxdma_intr(int irq, void *dev_id);
+ static void mace_set_timeout(struct net_device *dev);
+ static void mace_tx_timeout(unsigned long data);
+ static inline void dbdma_reset(volatile struct dbdma_regs __iomem *dma);
+@@ -113,7 +113,7 @@ static int __devinit mace_probe(struct m
+ struct device_node *mace = macio_get_of_node(mdev);
+ struct net_device *dev;
+ struct mace_data *mp;
+- unsigned char *addr;
++ const unsigned char *addr;
+ int j, rev, rc = -EBUSY;
+
+ if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
+@@ -177,7 +177,7 @@ static int __devinit mace_probe(struct m
+ }
+ mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
+ in_8(&mp->mace->chipid_lo);
+-
++
+
+ mp = (struct mace_data *) dev->priv;
+ mp->maccc = ENXMT | ENRCV;
+@@ -219,7 +219,7 @@ static int __devinit mace_probe(struct m
+ mp->port_aaui = 1;
+ #else
+ mp->port_aaui = 0;
+-#endif
++#endif
+ }
+ }
+
+@@ -264,7 +264,7 @@ static int __devinit mace_probe(struct m
+ printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff);
+
+ return 0;
+-
++
+ err_free_rx_irq:
+ free_irq(macio_irq(mdev, 2), dev);
+ err_free_tx_irq:
+@@ -678,7 +678,7 @@ static void mace_handle_misc_intrs(struc
+ printk(KERN_DEBUG "mace: jabbering transceiver\n");
+ }
+
+-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mace_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -890,12 +890,12 @@ out:
+ spin_unlock_irqrestore(&mp->lock, flags);
+ }
+
+-static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mace_txdma_intr(int irq, void *dev_id)
+ {
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -1008,7 +1008,7 @@ static irqreturn_t mace_rxdma_intr(int i
+ return IRQ_HANDLED;
+ }
+
+-static struct of_device_id mace_match[] =
++static struct of_device_id mace_match[] =
+ {
+ {
+ .name = "mace",
+@@ -1017,7 +1017,7 @@ static struct of_device_id mace_match[]
+ };
+ MODULE_DEVICE_TABLE (of, mace_match);
+
+-static struct macio_driver mace_driver =
++static struct macio_driver mace_driver =
+ {
+ .name = "mace",
+ .match_table = mace_match,
+diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
+index 79a6fc1..464e4a6 100644
+--- a/drivers/net/macmace.c
++++ b/drivers/net/macmace.c
+@@ -63,7 +63,7 @@ struct mace_frame {
+ u16 rcvcc;
+ u32 pad1;
+ u32 pad2;
+- u8 data[1];
++ u8 data[1];
+ /* And frame continues.. */
+ };
+
+@@ -77,8 +77,8 @@ static int mace_xmit_start(struct sk_buf
+ static struct net_device_stats *mace_stats(struct net_device *dev);
+ static void mace_set_multicast(struct net_device *dev);
+ static int mace_set_address(struct net_device *dev, void *addr);
+-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t mace_interrupt(int irq, void *dev_id);
++static irqreturn_t mace_dma_intr(int irq, void *dev_id);
+ static void mace_tx_timeout(struct net_device *dev);
+
+ /* Bit-reverse one byte of an ethernet hardware address. */
+@@ -118,17 +118,17 @@ static void mace_rxdma_reset(struct net_
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mace = mp->mace;
+ u8 maccc = mace->maccc;
+-
++
+ mace->maccc = maccc & ~ENRCV;
+-
++
+ psc_write_word(PSC_ENETRD_CTL, 0x8800);
+ mace_load_rxdma_base(dev, 0x00);
+ psc_write_word(PSC_ENETRD_CTL, 0x0400);
+-
++
+ psc_write_word(PSC_ENETRD_CTL, 0x8800);
+ mace_load_rxdma_base(dev, 0x10);
+ psc_write_word(PSC_ENETRD_CTL, 0x0400);
+-
++
+ mace->maccc = maccc;
+ mp->rx_slot = 0;
+
+@@ -139,7 +139,7 @@ static void mace_rxdma_reset(struct net_
+ /*
+ * Reset the transmit DMA subsystem
+ */
+-
++
+ static void mace_txdma_reset(struct net_device *dev)
+ {
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -161,7 +161,7 @@ static void mace_txdma_reset(struct net_
+ /*
+ * Disable DMA
+ */
+-
++
+ static void mace_dma_off(struct net_device *dev)
+ {
+ psc_write_word(PSC_ENETRD_CTL, 0x8800);
+@@ -179,7 +179,7 @@ static void mace_dma_off(struct net_devi
+ * Not really much of a probe. The hardware table tells us if this
+ * model of Macintrash has a MACE (AV macintoshes)
+ */
+-
++
+ struct net_device *mace_probe(int unit)
+ {
+ int j;
+@@ -189,7 +189,7 @@ struct net_device *mace_probe(int unit)
+ unsigned char checksum = 0;
+ static int found = 0;
+ int err;
+-
++
+ if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
+ return ERR_PTR(-ENODEV);
+
+@@ -205,7 +205,7 @@ struct net_device *mace_probe(int unit)
+ mp = (struct mace_data *) dev->priv;
+ dev->base_addr = (u32)MACE_BASE;
+ mp->mace = (volatile struct mace *) MACE_BASE;
+-
++
+ dev->irq = IRQ_MAC_MACE;
+ mp->dma_intr = IRQ_MAC_MACE_DMA;
+
+@@ -217,7 +217,7 @@ struct net_device *mace_probe(int unit)
+ */
+
+ addr = (void *)MACE_PROM;
+-
++
+ for (j = 0; j < 6; ++j) {
+ u8 v=bitrev(addr[j<<4]);
+ checksum ^= v;
+@@ -226,7 +226,7 @@ struct net_device *mace_probe(int unit)
+ for (; j < 8; ++j) {
+ checksum ^= bitrev(addr[j<<4]);
+ }
+-
++
+ if (checksum != 0xFF) {
+ free_netdev(dev);
+ return ERR_PTR(-ENODEV);
+@@ -275,7 +275,7 @@ static int mace_set_address(struct net_d
+ /* load up the hardware address */
+ mb->iac = ADDRCHG | PHYADDR;
+ while ((mb->iac & ADDRCHG) != 0);
+-
++
+ for (i = 0; i < 6; ++i) {
+ mb->padr = dev->dev_addr[i] = p[i];
+ }
+@@ -290,7 +290,7 @@ static int mace_set_address(struct net_d
+ * Open the Macintosh MACE. Most of this is playing with the DMA
+ * engine. The ethernet chip is quite friendly.
+ */
+-
++
+ static int mace_open(struct net_device *dev)
+ {
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -333,7 +333,7 @@ static int mace_open(struct net_device *
+
+ mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES);
+ mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
+-
++
+ if (mp->tx_ring==NULL || mp->rx_ring==NULL) {
+ if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES);
+ if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0);
+@@ -348,7 +348,7 @@ static int mace_open(struct net_device *
+
+ /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
+
+- kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER);
++ kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER);
+ kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH);
+
+ mace_dma_off(dev);
+@@ -362,11 +362,11 @@ static int mace_open(struct net_device *
+
+ #if 0
+ /* load up the hardware address */
+-
++
+ mb->iac = ADDRCHG | PHYADDR;
+-
++
+ while ((mb->iac & ADDRCHG) != 0);
+-
++
+ for (i = 0; i < 6; ++i)
+ mb->padr = dev->dev_addr[i];
+
+@@ -374,7 +374,7 @@ static int mace_open(struct net_device *
+ mb->iac = ADDRCHG | LOGADDR;
+
+ while ((mb->iac & ADDRCHG) != 0);
+-
++
+ for (i = 0; i < 8; ++i)
+ mb->ladrf = 0;
+
+@@ -386,14 +386,14 @@ static int mace_open(struct net_device *
+
+ mace_rxdma_reset(dev);
+ mace_txdma_reset(dev);
+-
++
+ return 0;
+ }
+
+ /*
+ * Shut down the mace and its interrupt channel
+ */
+-
++
+ static int mace_close(struct net_device *dev)
+ {
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -415,7 +415,7 @@ static int mace_close(struct net_device
+ /*
+ * Transmit a frame
+ */
+-
++
+ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -427,7 +427,7 @@ static int mace_xmit_start(struct sk_buf
+ return 1;
+ }
+ mp->tx_count--;
+-
++
+ mp->stats.tx_packets++;
+ mp->stats.tx_bytes += skb->len;
+
+@@ -488,7 +488,7 @@ static void mace_set_multicast(struct ne
+
+ mb->iac = ADDRCHG | LOGADDR;
+ while (mb->iac & ADDRCHG);
+-
++
+ for (i = 0; i < 8; ++i) {
+ mb->ladrf = multicast_filter[i];
+ }
+@@ -498,10 +498,10 @@ static void mace_set_multicast(struct ne
+ }
+
+ /*
+- * Miscellaneous interrupts are handled here. We may end up
++ * Miscellaneous interrupts are handled here. We may end up
+ * having to bash the chip on the head for bad errors
+ */
+-
++
+ static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+ {
+ volatile struct mace *mb = mp->mace;
+@@ -536,16 +536,16 @@ static void mace_handle_misc_intrs(struc
+ * A transmit error has occurred. (We kick the transmit side from
+ * the DMA completion)
+ */
+-
++
+ static void mace_xmit_error(struct net_device *dev)
+ {
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ u8 xmtfs, xmtrc;
+-
++
+ xmtfs = mb->xmtfs;
+ xmtrc = mb->xmtrc;
+-
++
+ if (xmtfs & XMTSV) {
+ if (xmtfs & UFLO) {
+ printk("%s: DMA underrun.\n", dev->name);
+@@ -556,13 +556,13 @@ static void mace_xmit_error(struct net_d
+ if (xmtfs & RTRY) {
+ mp->stats.collisions++;
+ }
+- }
++ }
+ }
+
+ /*
+ * A receive interrupt occurred.
+ */
+-
++
+ static void mace_recv_interrupt(struct net_device *dev)
+ {
+ /* struct mace_data *mp = (struct mace_data *) dev->priv; */
+@@ -572,17 +572,17 @@ static void mace_recv_interrupt(struct n
+ /*
+ * Process the chip interrupt
+ */
+-
+-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++
++static irqreturn_t mace_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ u8 ir;
+-
++
+ ir = mb->ir;
+ mace_handle_misc_intrs(mp, ir);
+-
++
+ if (ir & XMTINT) {
+ mace_xmit_error(dev);
+ }
+@@ -601,7 +601,7 @@ static void mace_tx_timeout(struct net_d
+ /*
+ * Handle a newly arrived frame
+ */
+-
++
+ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
+ {
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -614,7 +614,7 @@ static void mace_dma_rx_frame(struct net
+ }
+ if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
+ mp->stats.rx_errors++;
+-
++
+ if (mf->status&RS_CLSN) {
+ mp->stats.collisions++;
+ }
+@@ -624,7 +624,7 @@ static void mace_dma_rx_frame(struct net
+ if (mf->status&RS_FCSERR) {
+ mp->stats.rx_crc_errors++;
+ }
+-
++
+ skb = dev_alloc_skb(mf->len+2);
+ if (!skb) {
+ mp->stats.rx_dropped++;
+@@ -632,7 +632,7 @@ static void mace_dma_rx_frame(struct net
+ }
+ skb_reserve(skb,2);
+ memcpy(skb_put(skb, mf->len), mf->data, mf->len);
+-
++
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+@@ -644,8 +644,8 @@ static void mace_dma_rx_frame(struct net
+ /*
+ * The PSC has passed us a DMA interrupt event.
+ */
+-
+-static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
++
++static irqreturn_t mace_dma_intr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+@@ -661,9 +661,9 @@ static irqreturn_t mace_dma_intr(int irq
+ /*
+ * Process the read queue
+ */
+-
++
+ status = psc_read_word(PSC_ENETRD_CTL);
+-
++
+ if (status & 0x2000) {
+ mace_rxdma_reset(dev);
+ } else if (status & 0x0100) {
+@@ -678,7 +678,7 @@ static irqreturn_t mace_dma_intr(int irq
+ mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800)));
+ mp->rx_tail++;
+ }
+-
++
+ /* If we're out of buffers in this ring then switch to */
+ /* the other set, otherwise just reactivate this one. */
+
+@@ -689,7 +689,7 @@ static irqreturn_t mace_dma_intr(int irq
+ psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800);
+ }
+ }
+-
++
+ /*
+ * Process the write queue
+ */
+diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
+index f6f3daf..393d995 100644
+--- a/drivers/net/macsonic.c
++++ b/drivers/net/macsonic.c
+@@ -13,20 +13,20 @@
+ *
+ * Based on code
+ * (C) 1996 by Thomas Bogendoerfer (tsbogend at bigbug.franken.de)
+- *
++ *
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+- *
++ *
+ * (C) 1995 by Andreas Busse (andy at waldorf-gmbh.de)
+ *
+ * A driver for the Mac onboard Sonic ethernet chip.
+ *
+- * 98/12/21 MSch: judged from tests on Q800, it's basically working,
++ * 98/12/21 MSch: judged from tests on Q800, it's basically working,
+ * but eating up both receive and transmit resources
+ * and duplicating packets. Needs more testing.
+ *
+ * 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed.
+- *
++ *
+ * 00/10/31 sammy at oh.verio.com: Updated driver for 2.4 kernels, fixed problems
+ * on centris.
+ */
+@@ -76,7 +76,7 @@ static struct platform_device *mac_sonic
+ /* use 0 for production, 1 for verification, >1 for debug */
+ #ifdef SONIC_DEBUG
+ static unsigned int sonic_debug = SONIC_DEBUG;
+-#else
++#else
+ static unsigned int sonic_debug = 1;
+ #endif
+
+@@ -129,7 +129,7 @@ static inline void bit_reverse_addr(unsi
+ int i;
+
+ for(i = 0; i < 6; i++)
+- addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
++ addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
+ nibbletab[(addr[i] >> 4) &0xf]);
+ }
+
+@@ -215,7 +215,7 @@ int __init mac_onboard_sonic_ethernet_ad
+ unsigned short val;
+
+ printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
+-
++
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+ SONIC_WRITE(SONIC_CEP, 15);
+
+@@ -228,7 +228,7 @@ int __init mac_onboard_sonic_ethernet_ad
+ val = SONIC_READ(SONIC_CAP0);
+ dev->dev_addr[1] = val >> 8;
+ dev->dev_addr[0] = val & 0xff;
+-
++
+ printk(KERN_INFO "HW Address from CAM 15: ");
+ for (i = 0; i < 6; i++) {
+ printk("%2.2x", dev->dev_addr[i]);
+@@ -258,7 +258,7 @@ int __init mac_onboard_sonic_probe(struc
+ struct sonic_local* lp = netdev_priv(dev);
+ int sr;
+ int commslot = 0;
+-
++
+ if (once_is_more_than_enough)
+ return -ENODEV;
+ once_is_more_than_enough = 1;
+@@ -268,9 +268,9 @@ int __init mac_onboard_sonic_probe(struc
+
+ if (macintosh_config->ether_type != MAC_ETHER_SONIC)
+ return -ENODEV;
+-
++
+ printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
+-
++
+ /* Bogus probing, on the models which may or may not have
+ Ethernet (BTW, the Ethernet *is* always at the same
+ address, and nothing else lives there, at least if Apple's
+@@ -293,7 +293,7 @@ int __init mac_onboard_sonic_probe(struc
+ commslot = 1;
+ }
+
+- printk("yes\n");
++ printk("yes\n");
+
+ /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
+ * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
+@@ -325,7 +325,7 @@ int __init mac_onboard_sonic_probe(struc
+ lp->dma_bitmode = SONIC_BITMODE16;
+
+ sr = SONIC_READ(SONIC_SR);
+- if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101)
++ if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101)
+ /* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */
+ lp->dma_bitmode = SONIC_BITMODE32;
+ else {
+@@ -389,7 +389,7 @@ int __init mac_nubus_sonic_ethernet_addr
+
+ int __init macsonic_ident(struct nubus_dev* ndev)
+ {
+- if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
++ if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
+ ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
+ return MACSONIC_DAYNALINK;
+ if (ndev->dr_hw == NUBUS_DRHW_SONIC &&
+@@ -400,11 +400,11 @@ int __init macsonic_ident(struct nubus_d
+ else
+ return MACSONIC_APPLE;
+ }
+-
++
+ if (ndev->dr_hw == NUBUS_DRHW_SMC9194 &&
+ ndev->dr_sw == NUBUS_DRSW_DAYNA)
+ return MACSONIC_DAYNA;
+-
++
+ if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
+ ndev->dr_sw == 0) { /* huh? */
+ return MACSONIC_APPLE16;
+@@ -421,7 +421,7 @@ int __init mac_nubus_sonic_probe(struct
+ u16 sonic_dcr;
+ int id = -1;
+ int reg_offset, dma_bitmode;
+-
++
+ /* Find the first SONIC that hasn't been initialized already */
+ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
+ NUBUS_TYPE_ETHERNET, ndev)) != NULL)
+@@ -459,7 +459,7 @@ int __init mac_nubus_sonic_probe(struct
+ base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
+ sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
+- SONIC_DCR_PO1 | SONIC_DCR_BMS;
++ SONIC_DCR_PO1 | SONIC_DCR_BMS;
+ reg_offset = 0;
+ dma_bitmode = SONIC_BITMODE16;
+ break;
+@@ -467,7 +467,7 @@ int __init mac_nubus_sonic_probe(struct
+ base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
+ sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
+- SONIC_DCR_PO1 | SONIC_DCR_BMS;
++ SONIC_DCR_PO1 | SONIC_DCR_BMS;
+ reg_offset = 0;
+ dma_bitmode = SONIC_BITMODE16;
+ break;
+diff --git a/drivers/net/meth.c b/drivers/net/meth.c
+index d644bf3..c1aa60b 100644
+--- a/drivers/net/meth.c
++++ b/drivers/net/meth.c
+@@ -92,8 +92,8 @@ struct meth_private {
+ };
+
+ static void meth_tx_timeout(struct net_device *dev);
+-static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs);
+-
++static irqreturn_t meth_interrupt(int irq, void *dev_id);
++
+ /* global, initialized in ip32-setup.c */
+ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
+
+@@ -232,7 +232,7 @@ static int meth_init_rx_ring(struct meth
+ skb_reserve(priv->rx_skbs[i],METH_RX_HEAD);
+ priv->rx_ring[i]=(rx_packet*)(priv->rx_skbs[i]->head);
+ /* I'll need to re-sync it after each RX */
+- priv->rx_ring_dmas[i] =
++ priv->rx_ring_dmas[i] =
+ dma_map_single(NULL, priv->rx_ring[i],
+ METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ mace->eth.rx_fifo = priv->rx_ring_dmas[i];
+@@ -281,7 +281,7 @@ int meth_reset(struct net_device *dev)
+ /* Load ethernet address */
+ load_eaddr(dev);
+ /* Should load some "errata", but later */
+-
++
+ /* Check for device */
+ if (mdio_probe(priv) < 0) {
+ DPRINTK("Unable to find PHY\n");
+@@ -452,7 +452,7 @@ static void meth_rx(struct net_device* d
+ }
+ priv->rx_ring[priv->rx_write] = (rx_packet*)skb->head;
+ priv->rx_ring[priv->rx_write]->status.raw = 0;
+- priv->rx_ring_dmas[priv->rx_write] =
++ priv->rx_ring_dmas[priv->rx_write] =
+ dma_map_single(NULL, priv->rx_ring[priv->rx_write],
+ METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ mace->eth.rx_fifo = priv->rx_ring_dmas[priv->rx_write];
+@@ -555,7 +555,7 @@ static void meth_error(struct net_device
+ printk(KERN_WARNING "meth: Rx underflow\n");
+ spin_lock(&priv->meth_lock);
+ mace->eth.int_stat = METH_INT_RX_UNDERFLOW;
+- /* more underflow interrupts will be delivered,
++ /* more underflow interrupts will be delivered,
+ * effectively throwing us into an infinite loop.
+ * Thus I stop processing Rx in this case. */
+ priv->dma_ctrl &= ~METH_DMA_RX_EN;
+@@ -569,7 +569,7 @@ static void meth_error(struct net_device
+ /*
+ * The typical interrupt entry point
+ */
+-static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs)
++static irqreturn_t meth_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct meth_private *priv = (struct meth_private *) dev->priv;
+@@ -761,12 +761,12 @@ static void meth_tx_timeout(struct net_d
+ }
+
+ /*
+- * Ioctl commands
++ * Ioctl commands
+ */
+ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ {
+ /* XXX Not yet implemented */
+- switch(cmd) {
++ switch(cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+diff --git a/drivers/net/mii.c b/drivers/net/mii.c
+index e42aa79..2912a34 100644
+--- a/drivers/net/mii.c
++++ b/drivers/net/mii.c
+@@ -83,9 +83,9 @@ int mii_ethtool_gset(struct mii_if_info
+ if (bmcr & BMCR_ANENABLE) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ ecmd->autoneg = AUTONEG_ENABLE;
+-
++
+ nego = mii_nway_result(advert & lpa);
+- if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
++ if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
+ (lpa2 >> 2))
+ ecmd->speed = SPEED_1000;
+ else if (nego == LPA_100FULL || nego == LPA_100HALF)
+@@ -103,7 +103,7 @@ int mii_ethtool_gset(struct mii_if_info
+ } else {
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+- ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
++ ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
+ (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
+ (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
+ ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+@@ -118,8 +118,8 @@ int mii_ethtool_sset(struct mii_if_info
+ {
+ struct net_device *dev = mii->dev;
+
+- if (ecmd->speed != SPEED_10 &&
+- ecmd->speed != SPEED_100 &&
++ if (ecmd->speed != SPEED_10 &&
++ ecmd->speed != SPEED_100 &&
+ ecmd->speed != SPEED_1000)
+ return -EINVAL;
+ if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+@@ -134,9 +134,9 @@ int mii_ethtool_sset(struct mii_if_info
+ return -EINVAL;
+ if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii))
+ return -EINVAL;
+-
++
+ /* ignore supported, maxtxpkt, maxrxpkt */
+-
++
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ u32 bmcr, advert, tmp;
+ u32 advert2 = 0, tmp2 = 0;
+@@ -176,7 +176,7 @@ int mii_ethtool_sset(struct mii_if_info
+ }
+ if ((mii->supports_gmii) && (advert2 != tmp2))
+ mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
+-
++
+ /* turn on autonegotiation, and force a renegotiate */
+ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+@@ -188,7 +188,7 @@ int mii_ethtool_sset(struct mii_if_info
+
+ /* turn off auto negotiation, set speed and duplexity */
+ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+- tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
++ tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
+ BMCR_SPEED1000 | BMCR_FULLDPLX);
+ if (ecmd->speed == SPEED_1000)
+ tmp |= BMCR_SPEED1000;
+diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
+index 07e58f4..c946998 100644
+--- a/drivers/net/mipsnet.c
++++ b/drivers/net/mipsnet.c
+@@ -116,8 +116,7 @@ static inline ssize_t mipsnet_get_fromde
+ return count;
+ }
+
+-static irqreturn_t
+-mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+
+diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
+index eeab1df..9997081 100644
+--- a/drivers/net/mv643xx_eth.c
++++ b/drivers/net/mv643xx_eth.c
+@@ -74,7 +74,7 @@ static int ethernet_phy_detect(unsigned
+ static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location);
+ static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val);
+ static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+-static struct ethtool_ops mv643xx_ethtool_ops;
++static const struct ethtool_ops mv643xx_ethtool_ops;
+
+ static char mv643xx_driver_name[] = "mv643xx_eth";
+ static char mv643xx_driver_version[] = "1.0";
+@@ -385,7 +385,7 @@ static int mv643xx_eth_receive_queue(str
+ struct pkt_info pkt_info;
+
+ while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
+- dma_unmap_single(NULL, pkt_info.buf_ptr, RX_SKB_SIZE,
++ dma_unmap_single(NULL, pkt_info.buf_ptr, ETH_RX_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ mp->rx_desc_count--;
+ received_packets++;
+@@ -507,8 +507,7 @@ static void mv643xx_eth_update_pscr(stru
+ * Output : N/A
+ */
+
+-static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct mv643xx_private *mp = netdev_priv(dev);
+@@ -1147,7 +1146,7 @@ static void eth_tx_submit_descs_for_skb(
+ desc->byte_cnt = length;
+ desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ BUG_ON(skb->protocol != ETH_P_IP);
+
+ cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
+@@ -1252,7 +1251,7 @@ static void mv643xx_netpoll(struct net_d
+ /* wait for previous write to complete */
+ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+
+- mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
++ mv643xx_eth_int_handler(netdev->irq, netdev);
+
+ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
+ }
+@@ -2156,7 +2155,7 @@ static void eth_update_mib_counters(stru
+ for (offset = ETH_MIB_BAD_OCTETS_RECEIVED;
+ offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS;
+ offset += 4)
+- *(u32 *)((char *)p + offset) = read_mib(mp, offset);
++ *(u32 *)((char *)p + offset) += read_mib(mp, offset);
+
+ p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW);
+ p->good_octets_sent +=
+@@ -2165,7 +2164,7 @@ static void eth_update_mib_counters(stru
+ for (offset = ETH_MIB_GOOD_FRAMES_SENT;
+ offset <= ETH_MIB_LATE_COLLISION;
+ offset += 4)
+- *(u32 *)((char *)p + offset) = read_mib(mp, offset);
++ *(u32 *)((char *)p + offset) += read_mib(mp, offset);
+ }
+
+ /*
+@@ -2723,7 +2722,7 @@ static void mv643xx_get_ethtool_stats(st
+ eth_update_mib_counters(mp);
+
+ for (i = 0; i < MV643XX_STATS_LEN; i++) {
+- char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;
++ char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;
+ data[i] = (mv643xx_gstrings_stats[i].sizeof_stat ==
+ sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p;
+ }
+@@ -2766,7 +2765,7 @@ static int mv643xx_eth_do_ioctl(struct n
+ return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL);
+ }
+
+-static struct ethtool_ops mv643xx_ethtool_ops = {
++static const struct ethtool_ops mv643xx_ethtool_ops = {
+ .get_settings = mv643xx_get_settings,
+ .set_settings = mv643xx_set_settings,
+ .get_drvinfo = mv643xx_get_drvinfo,
+diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
+index 9bdd43a..806081b 100644
+--- a/drivers/net/myri10ge/myri10ge.c
++++ b/drivers/net/myri10ge/myri10ge.c
+@@ -187,11 +187,14 @@ struct myri10ge_priv {
+ u8 mac_addr[6]; /* eeprom mac address */
+ unsigned long serial_number;
+ int vendor_specific_offset;
++ int fw_multicast_support;
+ u32 devctl;
+ u16 msi_flags;
+ u32 read_dma;
+ u32 write_dma;
+ u32 read_write_dma;
++ u32 link_changes;
++ u32 msg_enable;
+ };
+
+ static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
+@@ -257,6 +260,12 @@ module_param(myri10ge_max_irq_loops, int
+ MODULE_PARM_DESC(myri10ge_max_irq_loops,
+ "Set stuck legacy IRQ detection threshold\n");
+
++#define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINK
++
++static int myri10ge_debug = -1; /* defaults above */
++module_param(myri10ge_debug, int, 0);
++MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
++
+ #define MYRI10GE_FW_OFFSET 1024*1024
+ #define MYRI10GE_HIGHPART_TO_U32(X) \
+ (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
+@@ -271,7 +280,7 @@ myri10ge_send_cmd(struct myri10ge_priv *
+ struct mcp_cmd *buf;
+ char buf_bytes[sizeof(*buf) + 8];
+ struct mcp_cmd_response *response = mgp->cmd;
+- char __iomem *cmd_addr = mgp->sram + MXGEFW_CMD_OFFSET;
++ char __iomem *cmd_addr = mgp->sram + MXGEFW_ETH_CMD;
+ u32 dma_low, dma_high, result, value;
+ int sleep_total = 0;
+
+@@ -320,6 +329,8 @@ myri10ge_send_cmd(struct myri10ge_priv *
+ if (result == 0) {
+ data->data0 = value;
+ return 0;
++ } else if (result == MXGEFW_CMD_UNKNOWN) {
++ return -ENOSYS;
+ } else {
+ dev_err(&mgp->pdev->dev,
+ "command %d failed, result = %d\n",
+@@ -404,7 +415,7 @@ static void myri10ge_dummy_rdma(struct m
+ buf[4] = htonl(dma_low); /* dummy addr LSW */
+ buf[5] = htonl(enable); /* enable? */
+
+- submit = mgp->sram + 0xfc01c0;
++ submit = mgp->sram + MXGEFW_BOOT_DUMMY_RDMA;
+
+ myri10ge_pio_copy(submit, &buf, sizeof(buf));
+ for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++)
+@@ -600,7 +611,7 @@ static int myri10ge_load_firmware(struct
+ buf[5] = htonl(8); /* where to copy to */
+ buf[6] = htonl(0); /* where to jump to */
+
+- submit = mgp->sram + 0xfc0000;
++ submit = mgp->sram + MXGEFW_BOOT_HANDOFF;
+
+ myri10ge_pio_copy(submit, &buf, sizeof(buf));
+ mb();
+@@ -764,6 +775,7 @@ static int myri10ge_reset(struct myri10g
+ mgp->rx_small.cnt = 0;
+ mgp->rx_done.idx = 0;
+ mgp->rx_done.cnt = 0;
++ mgp->link_changes = 0;
+ status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
+ myri10ge_change_promisc(mgp, 0, 0);
+ myri10ge_change_pause(mgp, mgp->pause);
+@@ -798,12 +810,13 @@ myri10ge_submit_8rx(struct mcp_kreq_ethe
+ * pages directly and building a fraglist in the near future.
+ */
+
+-static inline struct sk_buff *myri10ge_alloc_big(int bytes)
++static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev,
++ int bytes)
+ {
+ struct sk_buff *skb;
+ unsigned long data, roundup;
+
+- skb = dev_alloc_skb(bytes + 4096 + MXGEFW_PAD);
++ skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD);
+ if (skb == NULL)
+ return NULL;
+
+@@ -821,12 +834,13 @@ static inline struct sk_buff *myri10ge_a
+
+ /* Allocate 2x as much space as required and use whichever portion
+ * does not cross a 4KB boundary */
+-static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes)
++static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev,
++ unsigned int bytes)
+ {
+ struct sk_buff *skb;
+ unsigned long data, boundary;
+
+- skb = dev_alloc_skb(2 * (bytes + MXGEFW_PAD) - 1);
++ skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1);
+ if (unlikely(skb == NULL))
+ return NULL;
+
+@@ -847,12 +861,13 @@ static inline struct sk_buff *myri10ge_a
+
+ /* Allocate just enough space, and verify that the allocated
+ * space does not cross a 4KB boundary */
+-static inline struct sk_buff *myri10ge_alloc_small(int bytes)
++static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev,
++ int bytes)
+ {
+ struct sk_buff *skb;
+ unsigned long roundup, data, end;
+
+- skb = dev_alloc_skb(bytes + 16 + MXGEFW_PAD);
++ skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD);
+ if (unlikely(skb == NULL))
+ return NULL;
+
+@@ -868,15 +883,17 @@ static inline struct sk_buff *myri10ge_a
+ "myri10ge_alloc_small: small skb crossed 4KB boundary\n");
+ myri10ge_skb_cross_4k = 1;
+ dev_kfree_skb_any(skb);
+- skb = myri10ge_alloc_small_safe(bytes);
++ skb = myri10ge_alloc_small_safe(dev, bytes);
+ }
+ return skb;
+ }
+
+ static inline int
+-myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes,
+- int idx)
++myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp,
++ int bytes, int idx)
+ {
++ struct net_device *dev = mgp->dev;
++ struct pci_dev *pdev = mgp->pdev;
+ struct sk_buff *skb;
+ dma_addr_t bus;
+ int len, retval = 0;
+@@ -884,11 +901,11 @@ myri10ge_getbuf(struct myri10ge_rx_buf *
+ bytes += VLAN_HLEN; /* account for 802.1q vlan tag */
+
+ if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
+- skb = myri10ge_alloc_big(bytes);
++ skb = myri10ge_alloc_big(dev, bytes);
+ else if (myri10ge_skb_cross_4k)
+- skb = myri10ge_alloc_small_safe(bytes);
++ skb = myri10ge_alloc_small_safe(dev, bytes);
+ else
+- skb = myri10ge_alloc_small(bytes);
++ skb = myri10ge_alloc_small(dev, bytes);
+
+ if (unlikely(skb == NULL)) {
+ rx->alloc_fail++;
+@@ -930,7 +947,7 @@ static inline void myri10ge_vlan_ip_csum
+ (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
+ vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
+ skb->csum = hw_csum;
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+ }
+
+@@ -951,7 +968,7 @@ myri10ge_rx_done(struct myri10ge_priv *m
+ unmap_len = pci_unmap_len(&rx->info[idx], len);
+
+ /* try to replace the received skb */
+- if (myri10ge_getbuf(rx, mgp->pdev, bytes, idx)) {
++ if (myri10ge_getbuf(rx, mgp, bytes, idx)) {
+ /* drop the frame -- the old skbuf is re-cycled */
+ mgp->stats.rx_dropped += 1;
+ return 0;
+@@ -968,12 +985,11 @@ myri10ge_rx_done(struct myri10ge_priv *m
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, mgp->dev);
+- skb->dev = mgp->dev;
+ if (mgp->csum_flag) {
+ if ((skb->protocol == ntohs(ETH_P_IP)) ||
+ (skb->protocol == ntohs(ETH_P_IPV6))) {
+ skb->csum = ntohs((u16) csum);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ } else
+ myri10ge_vlan_ip_csum(skb, ntohs((u16) csum));
+ }
+@@ -1081,13 +1097,19 @@ static inline void myri10ge_check_statbl
+ if (mgp->link_state != stats->link_up) {
+ mgp->link_state = stats->link_up;
+ if (mgp->link_state) {
+- printk(KERN_INFO "myri10ge: %s: link up\n",
+- mgp->dev->name);
++ if (netif_msg_link(mgp))
++ printk(KERN_INFO
++ "myri10ge: %s: link up\n",
++ mgp->dev->name);
+ netif_carrier_on(mgp->dev);
++ mgp->link_changes++;
+ } else {
+- printk(KERN_INFO "myri10ge: %s: link down\n",
+- mgp->dev->name);
++ if (netif_msg_link(mgp))
++ printk(KERN_INFO
++ "myri10ge: %s: link down\n",
++ mgp->dev->name);
+ netif_carrier_off(mgp->dev);
++ mgp->link_changes++;
+ }
+ }
+ if (mgp->rdma_tags_available !=
+@@ -1126,7 +1148,7 @@ static int myri10ge_poll(struct net_devi
+ return 1;
+ }
+
+-static irqreturn_t myri10ge_intr(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t myri10ge_intr(int irq, void *arg)
+ {
+ struct myri10ge_priv *mgp = arg;
+ struct mcp_irq_data *stats = mgp->fw_stats;
+@@ -1289,7 +1311,8 @@ static const char myri10ge_gstrings_stat
+ "serial_number", "tx_pkt_start", "tx_pkt_done",
+ "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
+ "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
+- "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered",
++ "link_changes", "link_up", "dropped_link_overflow",
++ "dropped_link_error_or_filtered", "dropped_multicast_filtered",
+ "dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
+ "dropped_no_big_buffer"
+ };
+@@ -1341,17 +1364,32 @@ myri10ge_get_ethtool_stats(struct net_de
+ data[i++] = (unsigned int)mgp->stop_queue;
+ data[i++] = (unsigned int)mgp->watchdog_resets;
+ data[i++] = (unsigned int)mgp->tx_linearized;
++ data[i++] = (unsigned int)mgp->link_changes;
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
+ data[i++] =
+ (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
++ data[i++] =
++ (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
+ }
+
+-static struct ethtool_ops myri10ge_ethtool_ops = {
++static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
++{
++ struct myri10ge_priv *mgp = netdev_priv(netdev);
++ mgp->msg_enable = value;
++}
++
++static u32 myri10ge_get_msglevel(struct net_device *netdev)
++{
++ struct myri10ge_priv *mgp = netdev_priv(netdev);
++ return mgp->msg_enable;
++}
++
++static const struct ethtool_ops myri10ge_ethtool_ops = {
+ .get_settings = myri10ge_get_settings,
+ .get_drvinfo = myri10ge_get_drvinfo,
+ .get_coalesce = myri10ge_get_coalesce,
+@@ -1371,7 +1409,9 @@ static struct ethtool_ops myri10ge_ethto
+ #endif
+ .get_strings = myri10ge_get_strings,
+ .get_stats_count = myri10ge_get_stats_count,
+- .get_ethtool_stats = myri10ge_get_ethtool_stats
++ .get_ethtool_stats = myri10ge_get_ethtool_stats,
++ .set_msglevel = myri10ge_set_msglevel,
++ .get_msglevel = myri10ge_get_msglevel
+ };
+
+ static int myri10ge_allocate_rings(struct net_device *dev)
+@@ -1439,7 +1479,7 @@ static int myri10ge_allocate_rings(struc
+ /* Fill the receive rings */
+
+ for (i = 0; i <= mgp->rx_small.mask; i++) {
+- status = myri10ge_getbuf(&mgp->rx_small, mgp->pdev,
++ status = myri10ge_getbuf(&mgp->rx_small, mgp,
+ mgp->small_bytes, i);
+ if (status) {
+ printk(KERN_ERR
+@@ -1451,8 +1491,7 @@ static int myri10ge_allocate_rings(struc
+
+ for (i = 0; i <= mgp->rx_big.mask; i++) {
+ status =
+- myri10ge_getbuf(&mgp->rx_big, mgp->pdev,
+- dev->mtu + ETH_HLEN, i);
++ myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i);
+ if (status) {
+ printk(KERN_ERR
+ "myri10ge: %s: alloced only %d big bufs\n",
+@@ -1648,9 +1687,11 @@ static int myri10ge_open(struct net_devi
+ }
+
+ if (mgp->mtrr >= 0) {
+- mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + 0x200000;
+- mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + 0x300000;
+- mgp->rx_big.wc_fifo = (u8 __iomem *) mgp->sram + 0x340000;
++ mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
++ mgp->rx_small.wc_fifo =
++ (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
++ mgp->rx_big.wc_fifo =
++ (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
+ } else {
+ mgp->tx.wc_fifo = NULL;
+ mgp->rx_small.wc_fifo = NULL;
+@@ -1686,7 +1727,21 @@ static int myri10ge_open(struct net_devi
+
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus);
+- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA, &cmd, 0);
++ cmd.data2 = sizeof(struct mcp_irq_data);
++ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
++ if (status == -ENOSYS) {
++ dma_addr_t bus = mgp->fw_stats_bus;
++ bus += offsetof(struct mcp_irq_data, send_done_count);
++ cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
++ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
++ status = myri10ge_send_cmd(mgp,
++ MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
++ &cmd, 0);
++ /* Firmware cannot support multicast without STATS_DMA_V2 */
++ mgp->fw_multicast_support = 0;
++ } else {
++ mgp->fw_multicast_support = 1;
++ }
+ if (status) {
+ printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n",
+ dev->name);
+@@ -1841,7 +1896,8 @@ myri10ge_submit_req_wc(struct myri10ge_t
+ if (cnt > 0) {
+ /* pad it to 64 bytes. The src is 64 bytes bigger than it
+ * needs to be so that we don't overrun it */
+- myri10ge_pio_copy(tx->wc_fifo + (cnt << 18), src, 64);
++ myri10ge_pio_copy(tx->wc_fifo + MXGEFW_ETH_SEND_OFFSET(cnt),
++ src, 64);
+ mb();
+ }
+ }
+@@ -1897,13 +1953,13 @@ again:
+ pseudo_hdr_offset = 0;
+ odd_flag = 0;
+ flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST);
+- if (likely(skb->ip_summed == CHECKSUM_HW)) {
++ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ cksum_offset = (skb->h.raw - skb->data);
+ pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data;
+ /* If the headers are excessively large, then we must
+ * fall back to a software checksum */
+ if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) {
+- if (skb_checksum_help(skb, 0))
++ if (skb_checksum_help(skb))
+ goto drop;
+ cksum_offset = 0;
+ pseudo_hdr_offset = 0;
+@@ -2140,9 +2196,81 @@ static struct net_device_stats *myri10ge
+
+ static void myri10ge_set_multicast_list(struct net_device *dev)
+ {
++ struct myri10ge_cmd cmd;
++ struct myri10ge_priv *mgp;
++ struct dev_mc_list *mc_list;
++ int err;
++
++ mgp = netdev_priv(dev);
+ /* can be called from atomic contexts,
+ * pass 1 to force atomicity in myri10ge_send_cmd() */
+- myri10ge_change_promisc(netdev_priv(dev), dev->flags & IFF_PROMISC, 1);
++ myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
++
++ /* This firmware is known to not support multicast */
++ if (!mgp->fw_multicast_support)
++ return;
++
++ /* Disable multicast filtering */
++
++ err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
++ if (err != 0) {
++ printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_ENABLE_ALLMULTI,"
++ " error status: %d\n", dev->name, err);
++ goto abort;
++ }
++
++ if (dev->flags & IFF_ALLMULTI) {
++ /* request to disable multicast filtering, so quit here */
++ return;
++ }
++
++ /* Flush the filters */
++
++ err = myri10ge_send_cmd(mgp, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
++ &cmd, 1);
++ if (err != 0) {
++ printk(KERN_ERR
++ "myri10ge: %s: Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS"
++ ", error status: %d\n", dev->name, err);
++ goto abort;
++ }
++
++ /* Walk the multicast list, and add each address */
++ for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) {
++ memcpy(&cmd.data0, &mc_list->dmi_addr, 4);
++ memcpy(&cmd.data1, ((char *)&mc_list->dmi_addr) + 4, 2);
++ cmd.data0 = htonl(cmd.data0);
++ cmd.data1 = htonl(cmd.data1);
++ err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP,
++ &cmd, 1);
++
++ if (err != 0) {
++ printk(KERN_ERR "myri10ge: %s: Failed "
++ "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
++ "%d\t", dev->name, err);
++ printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
++ ((unsigned char *)&mc_list->dmi_addr)[0],
++ ((unsigned char *)&mc_list->dmi_addr)[1],
++ ((unsigned char *)&mc_list->dmi_addr)[2],
++ ((unsigned char *)&mc_list->dmi_addr)[3],
++ ((unsigned char *)&mc_list->dmi_addr)[4],
++ ((unsigned char *)&mc_list->dmi_addr)[5]
++ );
++ goto abort;
++ }
++ }
++ /* Enable multicast filtering */
++ err = myri10ge_send_cmd(mgp, MXGEFW_DISABLE_ALLMULTI, &cmd, 1);
++ if (err != 0) {
++ printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_DISABLE_ALLMULTI,"
++ "error status: %d\n", dev->name, err);
++ goto abort;
++ }
++
++ return;
++
++abort:
++ return;
+ }
+
+ static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
+@@ -2288,7 +2416,8 @@ static void myri10ge_enable_ecrc(struct
+ * firmware image, and set tx.boundary to 4KB.
+ */
+
+-#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
++#define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7
++#define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa
+
+ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+ {
+@@ -2298,15 +2427,34 @@ static void myri10ge_select_firmware(str
+ mgp->fw_name = myri10ge_fw_unaligned;
+
+ if (myri10ge_force_firmware == 0) {
++ int link_width, exp_cap;
++ u16 lnk;
++
++ exp_cap = pci_find_capability(mgp->pdev, PCI_CAP_ID_EXP);
++ pci_read_config_word(mgp->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
++ link_width = (lnk >> 4) & 0x3f;
++
+ myri10ge_enable_ecrc(mgp);
+
+- /* Check to see if the upstream bridge is known to
+- * provide aligned completions */
+- if (bridge
+- /* ServerWorks HT2000/HT1000 */
+- && bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
+- && bridge->device ==
+- PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE) {
++ /* Check to see if Link is less than 8 or if the
++ * upstream bridge is known to provide aligned
++ * completions */
++ if (link_width < 8) {
++ dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
++ link_width);
++ mgp->tx.boundary = 4096;
++ mgp->fw_name = myri10ge_fw_aligned;
++ } else if (bridge &&
++ /* ServerWorks HT2000/HT1000 */
++ ((bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
++ && bridge->device ==
++ PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE)
++ /* All Intel E5000 PCIE ports */
++ || (bridge->vendor == PCI_VENDOR_ID_INTEL
++ && bridge->device >=
++ PCI_DEVICE_ID_INTEL_E5000_PCIE23
++ && bridge->device <=
++ PCI_DEVICE_ID_INTEL_E5000_PCIE47))) {
+ dev_info(&mgp->pdev->dev,
+ "Assuming aligned completions (0x%x:0x%x)\n",
+ bridge->vendor, bridge->device);
+@@ -2581,6 +2729,7 @@ static int myri10ge_probe(struct pci_dev
+ mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
+ mgp->pause = myri10ge_flow_control;
+ mgp->intr_coal_delay = myri10ge_intr_coal_delay;
++ mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT);
+ init_waitqueue_head(&mgp->down_wq);
+
+ if (pci_enable_device(pdev)) {
+diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
+index 0a6cae6..9519ae7 100644
+--- a/drivers/net/myri10ge/myri10ge_mcp.h
++++ b/drivers/net/myri10ge/myri10ge_mcp.h
+@@ -91,7 +91,19 @@ struct mcp_kreq_ether_recv {
+
+ /* Commands */
+
+-#define MXGEFW_CMD_OFFSET 0xf80000
++#define MXGEFW_BOOT_HANDOFF 0xfc0000
++#define MXGEFW_BOOT_DUMMY_RDMA 0xfc01c0
++
++#define MXGEFW_ETH_CMD 0xf80000
++#define MXGEFW_ETH_SEND_4 0x200000
++#define MXGEFW_ETH_SEND_1 0x240000
++#define MXGEFW_ETH_SEND_2 0x280000
++#define MXGEFW_ETH_SEND_3 0x2c0000
++#define MXGEFW_ETH_RECV_SMALL 0x300000
++#define MXGEFW_ETH_RECV_BIG 0x340000
++
++#define MXGEFW_ETH_SEND(n) (0x200000 + (((n) & 0x03) * 0x40000))
++#define MXGEFW_ETH_SEND_OFFSET(n) (MXGEFW_ETH_SEND(n) - MXGEFW_ETH_SEND_4)
+
+ enum myri10ge_mcp_cmd_type {
+ MXGEFW_CMD_NONE = 0,
+@@ -154,7 +166,7 @@ enum myri10ge_mcp_cmd_type {
+ MXGEFW_CMD_SET_MTU,
+ MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */
+ MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */
+- MXGEFW_CMD_SET_STATS_DMA,
++ MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, /* replaced by SET_STATS_DMA_V2 */
+
+ MXGEFW_ENABLE_PROMISC,
+ MXGEFW_DISABLE_PROMISC,
+@@ -168,7 +180,26 @@ enum myri10ge_mcp_cmd_type {
+ * data2 = RDMA length (MSH), WDMA length (LSH)
+ * command return data = repetitions (MSH), 0.5-ms ticks (LSH)
+ */
+- MXGEFW_DMA_TEST
++ MXGEFW_DMA_TEST,
++
++ MXGEFW_ENABLE_ALLMULTI,
++ MXGEFW_DISABLE_ALLMULTI,
++
++ /* returns MXGEFW_CMD_ERROR_MULTICAST
++ * if there is no room in the cache
++ * data0,MSH(data1) = multicast group address */
++ MXGEFW_JOIN_MULTICAST_GROUP,
++ /* returns MXGEFW_CMD_ERROR_MULTICAST
++ * if the address is not in the cache,
++ * or is equal to FF-FF-FF-FF-FF-FF
++ * data0,MSH(data1) = multicast group address */
++ MXGEFW_LEAVE_MULTICAST_GROUP,
++ MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
++
++ MXGEFW_CMD_SET_STATS_DMA_V2,
++ /* data0, data1 = bus addr,
++ * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows
++ * adding new stuff to mcp_irq_data without changing the ABI */
+ };
+
+ enum myri10ge_mcp_cmd_status {
+@@ -180,11 +211,17 @@ enum myri10ge_mcp_cmd_status {
+ MXGEFW_CMD_ERROR_CLOSED,
+ MXGEFW_CMD_ERROR_HASH_ERROR,
+ MXGEFW_CMD_ERROR_BAD_PORT,
+- MXGEFW_CMD_ERROR_RESOURCES
++ MXGEFW_CMD_ERROR_RESOURCES,
++ MXGEFW_CMD_ERROR_MULTICAST
+ };
+
+-/* 40 Bytes */
++#define MXGEFW_OLD_IRQ_DATA_LEN 40
++
+ struct mcp_irq_data {
++ /* add new counters at the beginning */
++ u32 future_use[5];
++ u32 dropped_multicast_filtered;
++ /* 40 Bytes */
+ u32 send_done_count;
+
+ u32 link_up;
+diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h
+index e9c6e56..ba7b865 100644
+--- a/drivers/net/myri_code.h
++++ b/drivers/net/myri_code.h
+@@ -1,4781 +1,4781 @@
+-/* This is the Myrinet MCP code for LANai4.x */
++/* This is the Myrinet MCP code for LANai4.x */
+ /* Generated by cat $MYRI_HOME/lib/lanai/mcp4.dat > myri_code4.h */
+
+-static unsigned int lanai4_code_off = 0x0000; /* half-word offset */
+-static unsigned char lanai4_code[76256] __initdata = {
+-0xF2,0x0E,
+-0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x02, 0x05,0x3C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x02, 0x0A,0xBC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x02, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x04, 0x4A,0x9C, 0x85,0x16, 0x00,0x00, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
+-0x01,0x01, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x01,0x00, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x01,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0xF4,0x82, 0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x01,0xE0, 0xB4,0xBA,
+-0x68,0x02, 0xE0,0x00, 0x01,0xE0, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x3B,0x64, 0xF5,0x84,
+-0x4F,0x54, 0xF7,0x05, 0x7A,0x10, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x01,0x99, 0x97,0x2A,
+-0x00,0x20, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x26,0xAC, 0x00,0x01, 0x77,0x35,
+-0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA4,0xBA,
+-0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
+-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xD7,0x00, 0x0A,0x01, 0xE0,0x00,
+-0x01,0xD0, 0xF7,0x05, 0x7A,0x18, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x06,0xAC,
+-0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38,
+-0x00,0x0C, 0xA4,0xBA, 0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38,
+-0x60,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05, 0x7A,0x18, 0x97,0x2A, 0x00,0x14, 0xF5,0x05,
+-0x79,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
+-0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x02,0x4C, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x02,0x4C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x02,0x85, 0xF4,0x82, 0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+-0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x02,0x74, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF3,0x06, 0x2A,0x6C, 0xF3,0x05, 0x2C,0x10, 0xE0,0x00, 0x05,0x28, 0xF0,0x05,
+-0x7A,0x18, 0xF3,0x84, 0x79,0xD8, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+-0xFF,0xC4, 0x84,0x1E, 0x00,0x10, 0x96,0x96, 0xFF,0xD4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16,
+-0xFF,0xE0, 0x85,0x1E, 0x00,0x14, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x03,0x6C, 0x95,0x16,
+-0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
+-0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00, 0x02,0xFC, 0xC6,0x24,
+-0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
+-0x03,0x00, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x03,0x0D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
+-0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x03,0x48, 0xF5,0x02,
+-0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x03,0x50, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
+-0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0x03,0x51, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+-0x03,0x61, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+-0x03,0x70, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+-0x03,0xA5, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x04,0x18, 0x96,0x96,
+-0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
+-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x04,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x04,0x1C, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x04,0x2C, 0xF4,0x82,
+-0x00,0x01, 0xE0,0x00, 0x04,0x84, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
+-0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
+-0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
+-0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
+-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
+-0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x05,0x25, 0xF3,0x06, 0x29,0xE0, 0x86,0x96,
+-0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
+-0x6A,0x00, 0xEC,0x00, 0x04,0xF0, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
+-0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
+-0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
+-0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x04,0xB1, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
+-0x00,0x03, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
+-0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
+-0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
+-0x29,0xE0, 0xF3,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x04, 0x7A,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x05,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x05,0xCD, 0xF5,0x86, 0x4A,0x98, 0xF6,0x04, 0x79,0xD8, 0xF6,0x84, 0x4F,0x54, 0x00,0x00,
+-0x00,0x01, 0x96,0xB2, 0x00,0x1C, 0x06,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA5,0x3A, 0x58,0x02, 0x00,0x00,
+-0x00,0x01, 0x95,0x32, 0x00,0x10, 0xC7,0x38, 0x58,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05,
+-0x7A,0x18, 0x97,0x32, 0x00,0x14, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0x05,0xFC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
+-0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x05,0xF4, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF5,0x06, 0x2A,0x6C, 0xF5,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF7,0x04, 0x75,0xEC, 0x85,0x2E,
+-0x00,0x20, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0xF5,0x05, 0x7A,0x08, 0xF7,0x04,
+-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x06,0xCC, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x1C, 0xF6,0x84, 0x4F,0x54, 0xF7,0x05,
+-0x7A,0x00, 0xC7,0x34, 0x72,0x00, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x06,0x8D, 0xF5,0x02,
+-0x00,0x01, 0xE0,0x00, 0x06,0x90, 0xF5,0x05, 0x79,0xF8, 0xF0,0x85, 0x79,0xF8, 0xF6,0x84,
+-0x7A,0x00, 0xC7,0x38, 0x70,0x00, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x79,0xF8, 0xF6,0x85,
+-0x79,0xE8, 0xC7,0x38, 0x70,0x00, 0xC6,0x34, 0x70,0x00, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x06,0xCC, 0xF6,0x05, 0x79,0xF0, 0x20,0x36,
+-0x00,0x00, 0xEC,0x00, 0x06,0xF8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
+-0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x07,0x38, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00,
+-0x07,0x38, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
+-0x72,0x00, 0xEE,0x00, 0x07,0x19, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x4A,0x9C, 0xE0,0x00,
+-0x07,0x28, 0xF7,0x05, 0x79,0xF0, 0x20,0x32, 0x00,0x00, 0xEC,0x00, 0x07,0x28, 0x00,0x00,
+-0x00,0x01, 0xF0,0x85, 0x79,0xF0, 0xF5,0x85, 0x79,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xD5, 0xF4,0x02,
+-0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x07,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x00, 0x0A,0xA4, 0xF3,0x06,
+-0x2B,0x84, 0xF6,0x84, 0x79,0xE8, 0xF6,0x06, 0x4A,0x98, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x84, 0x79,0xE0, 0x07,0x38, 0x00,0x0C, 0xA3,0x3A,
+-0x60,0x02, 0xC3,0xB4, 0x00,0x00, 0x93,0x36, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
+-0x00,0x04, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x97,0x36, 0x00,0x14, 0x84,0x9E,
+-0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x94,0x96, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E,
+-0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
+-0x08,0xEC, 0x95,0x16, 0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
+-0x00,0x02, 0xC6,0xB8, 0x60,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x08,0x7C, 0xC6,0x20,
+-0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
+-0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x08,0x8D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
+-0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x08,0xC8, 0xF5,0x02,
+-0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x08,0xD0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
+-0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0x08,0xD1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+-0x08,0xE1, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+-0x08,0xF0, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x09,0x25, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x09,0x98, 0x96,0x96,
+-0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
+-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x09,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x09,0x9C, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x09,0xAC, 0xF4,0x82,
+-0x00,0x01, 0xE0,0x00, 0x0A,0x04, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
+-0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
+-0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
+-0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
+-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
+-0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x0A,0xA5, 0xF3,0x06, 0x2A,0xF8, 0x86,0x96,
+-0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
+-0x6A,0x00, 0xEC,0x00, 0x0A,0x70, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
+-0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
+-0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
+-0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x0A,0x31, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
+-0x00,0x02, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
+-0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
+-0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
+-0x2A,0xF8, 0xF3,0x05, 0x2C,0x1C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF6,0x84, 0x79,0xE8, 0xF7,0x04, 0x79,0xF8, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
+-0x70,0x00, 0xF7,0x04, 0x7A,0x20, 0xF6,0x85, 0x79,0xE8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x7A,0x20, 0xF7,0x04, 0x79,0xF0, 0xF6,0x04, 0x7A,0x20, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x0B,0x2C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x82, 0x00,0x13, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x0B,0x20, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86,
+-0x2B,0x84, 0xE0,0x00, 0x0B,0x38, 0xF5,0x85, 0x2C,0x1C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x06, 0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF0,0x05,
+-0x2D,0x38, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x18, 0xFF,0x85, 0x2E,0xDC, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
+-0x74,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x29, 0x97,0x16, 0xFF,0xF4, 0x47,0x38,
+-0xFF,0xFB, 0xF6,0x84, 0x6F,0x50, 0xCF,0xB8, 0x00,0x00, 0x83,0x96, 0xFF,0xF4, 0xF7,0x02,
+-0x00,0x3F, 0xC3,0x9C, 0x6D,0x80, 0xC7,0x1C, 0x74,0x00, 0x20,0x3A, 0x00,0x3F, 0xE2,0x00,
+-0x12,0x60, 0x93,0x96, 0xFF,0xF4, 0x77,0x39, 0x00,0x02, 0xF6,0x82, 0x0C,0x5C, 0xA6,0xB6,
+-0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x00, 0x12,0x60, 0x00,0x00,
+-0x12,0x60, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x5C, 0x00,0x00,
+-0x0D,0x5C, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x12,0x50, 0x00,0x00,
+-0x12,0x50, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE0, 0x00,0x00,
+-0x0D,0xE0, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE8, 0x00,0x00,
+-0x0D,0xF4, 0x00,0x00, 0x0E,0x00, 0x00,0x00, 0x0E,0x20, 0x00,0x00, 0x0E,0x40, 0x00,0x00,
+-0x0E,0x60, 0x00,0x00, 0x0E,0x80, 0x00,0x00, 0x0E,0xA0, 0x00,0x00, 0x0E,0xC0, 0x00,0x00,
+-0x0E,0xC8, 0x00,0x00, 0x0E,0xD0, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0E,0xD8, 0x00,0x00,
+-0x0E,0xF4, 0x00,0x00, 0x0F,0x10, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0F,0x18, 0x00,0x00,
+-0x0F,0x18, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x44, 0x00,0x00,
+-0x0F,0x44, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x84, 0x00,0x00,
+-0x0F,0x84, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x94, 0x00,0x00,
+-0x0F,0x94, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB8, 0x00,0x00,
+-0x0F,0xD8, 0x00,0x00, 0x0F,0xF8, 0x00,0x00, 0x10,0x2C, 0x00,0x00, 0x10,0x60, 0x00,0x00,
+-0x10,0x94, 0x00,0x00, 0x10,0xC8, 0x00,0x00, 0x10,0xFC, 0x00,0x00, 0x11,0x30, 0x00,0x00,
+-0x11,0x4C, 0x00,0x00, 0x11,0x68, 0x00,0x00, 0x12,0x14, 0x00,0x00, 0x11,0x84, 0x00,0x00,
+-0x11,0xB4, 0x00,0x00, 0x11,0xE4, 0x00,0x00, 0x12,0x14, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF6,0x02, 0x00,0x05, 0x20,0x32, 0x00,0x14, 0xE6,0x00,
+-0x0D,0xB5, 0x27,0x00, 0x00,0x10, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x0D,0xB5, 0xF7,0x06,
+-0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00, 0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E,
+-0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06,
+-0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x0D,0xB5, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05,
+-0x2E,0xCC, 0xF7,0x04, 0x2D,0x58, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x87,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
+-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x60, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
+-0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
+-0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
+-0x00,0x06, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+-0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
+-0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+-0x12,0x2C, 0xF3,0x82, 0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00,
+-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
+-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
+-0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
+-0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
+-0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF7,0x04,
+-0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x13,0xCC, 0xF7,0x05,
+-0x35,0x44, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x90,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x77,0x9C, 0x00,0x14, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0x12,0x9D, 0xF7,0x06, 0x04,0x00, 0xF7,0x04, 0x6F,0x5C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x6F,0x5C, 0xF7,0x04, 0x6F,0x5C, 0xE0,0x00, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0xF7,0x06, 0x04,0x00, 0xC0,0x1E, 0x74,0x00, 0xE6,0x00,
+-0x14,0x29, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2E,0xD0, 0xF6,0x84, 0x35,0x24, 0x07,0x38,
+-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF7,0x05, 0x2E,0xD0, 0xF7,0x04,
+-0xE0,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF6,0x82,
+-0x00,0x00, 0xF6,0x85, 0xE0,0x14, 0xF7,0x04, 0x2E,0xD8, 0xC5,0x34, 0x00,0x00, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x2E,0xD8, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x13,0xCC, 0xF6,0x82,
+-0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x13,0xA0, 0x05,0xB4, 0x00,0x08, 0x95,0x93,
+-0xFF,0xFC, 0x95,0x16, 0xFF,0xE8, 0x95,0x96, 0xFF,0xE4, 0x96,0x96, 0xFF,0xE0, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x64, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xE8, 0x85,0x96,
+-0xFF,0xE4, 0x86,0x96, 0xFF,0xE0, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x13,0x90, 0xF7,0x02,
+-0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00,
+-0x13,0x75, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x13,0x90, 0xF7,0x02,
+-0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38,
+-0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x12,0x00, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04,
+-0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x13,0xC0, 0x07,0x34,
+-0x14,0x94, 0xF3,0x84, 0x6F,0x44, 0xE0,0x00, 0x13,0xC4, 0xF3,0x85, 0x35,0x28, 0xF7,0x05,
+-0x35,0x28, 0xE0,0x00, 0x12,0xE8, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+-0x14,0x29, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05, 0x35,0x24, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x14,0x28, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x14,0x28, 0xF0,0x05,
+-0x2D,0x38, 0xF7,0x04, 0xE0,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x14,0x29, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0xE0,0x10, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x02,0x98, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84, 0x2D,0x38, 0xF7,0x04, 0x2D,0x3C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x0C,0x09, 0xF6,0x86, 0x2C,0x28, 0x77,0x39,
+-0x00,0x02, 0xA5,0x3A, 0x68,0x02, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00,
+-0x14,0x91, 0x27,0x28, 0x00,0x15, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x14,0x91, 0xF7,0x06,
+-0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E,
+-0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36,
+-0x00,0x1F, 0xE2,0x00, 0x14,0x91, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x06,
+-0x2D,0x44, 0x76,0xA9, 0x00,0x02, 0xA7,0x36, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x04, 0x94,0x96,
+-0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x2D,0x3C, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0x20,0x3A, 0x00,0x44, 0xE6,0x00,
+-0x14,0x2C, 0xF7,0x05, 0x2D,0x3C, 0xE0,0x00, 0x14,0x2C, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16, 0x00,0x00, 0xF7,0x02,
+-0x00,0x00, 0x85,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x21, 0xEE,0x00, 0x15,0x34, 0x95,0xA2,
+-0x00,0x00, 0xF6,0x06, 0x23,0x38, 0x07,0x20, 0x00,0x84, 0xC6,0xA0, 0x00,0x00, 0x96,0x3A,
+-0x00,0x04, 0x27,0x38, 0x00,0x04, 0xC0,0x3A, 0x6A,0x00, 0xEC,0x00, 0x15,0x20, 0x00,0x00,
+-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96,
+-0x00,0x00, 0x87,0x16, 0x00,0x04, 0xF6,0x04, 0x2D,0x40, 0x97,0x36, 0x00,0x00, 0x97,0x36,
+-0x00,0x04, 0x07,0x30, 0x00,0x01, 0xF7,0x05, 0x2D,0x40, 0x96,0x36, 0x00,0x08, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00, 0x15,0xD9, 0x27,0x28, 0x00,0x15, 0x20,0x3A,
+-0x00,0x01, 0xE2,0x00, 0x15,0xD9, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02,
+-0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
+-0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x15,0xD9, 0xB6,0x2E,
+-0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF6,0x86, 0x2D,0x44, 0x77,0x29, 0x00,0x02, 0xA6,0xBA,
+-0x68,0x02, 0x00,0x00, 0x00,0x01, 0x86,0xB6, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
+-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x87,0x16, 0x00,0x00, 0x86,0x96, 0x00,0x04, 0xF6,0x06, 0x2D,0x44, 0x76,0xB5,
+-0x00,0x02, 0x85,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xB5,0xB6, 0x60,0x02, 0xC6,0xB4,
+-0x70,0x00, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xB6, 0x00,0x04, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2,
+-0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00, 0x16,0xB4, 0xC5,0xB4, 0x00,0x00, 0x20,0x36,
+-0x00,0x0F, 0xEE,0x00, 0x16,0xB4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00,
+-0x16,0xB5, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEC,0x00, 0x16,0xD0, 0x00,0x00,
+-0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32,
+-0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00, 0x16,0xD8, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A,
+-0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x34,0x58, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
+-0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x3F,0x94, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2F,0xF8, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
+-0x3B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x02, 0x26,0xE4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x13, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x26,0xA0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
+-0x00,0x11, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05,
+-0x7A,0x78, 0xF0,0x05, 0x32,0xE8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x18,0x55, 0xF6,0x86, 0x71,0xC4, 0xE0,0x00, 0x18,0x6C, 0xF6,0x02,
+-0x00,0x00, 0xF7,0x04, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
+-0x68,0x00, 0x86,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x32,0xC4, 0x86,0xB2,
+-0x00,0x08, 0x07,0x01, 0x80,0x00, 0xC5,0xB4, 0x74,0x00, 0xF5,0x85, 0x32,0xD0, 0x87,0x32,
+-0x00,0x18, 0xF6,0x86, 0x6F,0x44, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x2E,
+-0x00,0x00, 0xF7,0x05, 0x32,0xC0, 0x07,0x38, 0x09,0xD8, 0x86,0xB2, 0x00,0x04, 0xF7,0x05,
+-0x32,0xCC, 0xE6,0x00, 0x19,0x41, 0xF6,0x85, 0x32,0xC8, 0xF7,0x04, 0x71,0x98, 0xF6,0x84,
+-0x7A,0x78, 0x27,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x19,0x10, 0xF7,0x05,
+-0x71,0x98, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x18,0xE8, 0xF3,0x02, 0x00,0x11, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05, 0x76,0xFC, 0xE0,0x00,
+-0x18,0xF8, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05,
+-0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x19,0x14, 0xF3,0x02,
+-0x00,0x01, 0xF3,0x06, 0x31,0x10, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF3,0x02,
+-0x00,0x01, 0xF3,0x05, 0x7A,0x78, 0xF3,0x06, 0x30,0x84, 0xF3,0x05, 0x32,0xD4, 0xF3,0x04,
+-0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x26,0x8C, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
+-0x00,0x00, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x1C,0xB9, 0x93,0x16, 0xFF,0xE4, 0x87,0x32,
+-0x00,0x08, 0x86,0x96, 0xFF,0xE4, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+-0x19,0x84, 0x20,0x36, 0x00,0x00, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x32,0x00, 0xE6,0x00, 0x19,0x84, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02, 0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16,
+-0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A, 0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C,
+-0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00,
+-0x1A,0x70, 0x96,0x16, 0xFF,0xEC, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
+-0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E,
+-0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x00, 0xC4,0x84,
+-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x1A,0x04, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
+-0x00,0x00, 0xE6,0x00, 0x1A,0x11, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2,
+-0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0x1A,0x4C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x54, 0x20,0x2E,
+-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0x1A,0x55, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0x1A,0x65, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26,
+-0x00,0x00, 0xE6,0x00, 0x1A,0x70, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16,
+-0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1A,0xB1, 0xF6,0x02,
+-0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1B,0x18, 0x96,0x96, 0xFF,0xF4, 0x27,0x14,
+-0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1B,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x1B,0x1C, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02,
+-0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0,
+-0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xEC,0x00, 0x1C,0x04, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8, 0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE,
+-0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x1B,0x94, 0xC4,0x84, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1B,0x98, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
+-0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x1B,0xA5, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
+-0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0x1B,0xE0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x1B,0xE8, 0x20,0x32, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x1B,0xE9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1B,0xF9, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
+-0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x1C,0x04, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
+-0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00,
+-0x1C,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
+-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
+-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1C,0xAC, 0x96,0x96,
+-0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93,
+-0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1C,0xA9, 0xF6,0x02,
+-0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00,
+-0x1C,0xB0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x1E,0x15, 0xF3,0x02, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6,
+-0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E, 0x00,0x10, 0xE2,0x00, 0x1C,0xDC, 0x20,0x32,
+-0x00,0x10, 0xE2,0x00, 0x1C,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00,
+-0x1D,0x24, 0xF7,0x02, 0x00,0x00, 0x07,0x30, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00,
+-0x1D,0x1D, 0xF6,0x82, 0x00,0x00, 0x20,0x32, 0x00,0x10, 0xE6,0x00, 0x1D,0x20, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0x1D,0x24, 0xC7,0x34, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34,
+-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0x14, 0xF3,0x02, 0x00,0x01, 0xF3,0x04,
+-0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x1D,0x91, 0x76,0xB1,
+-0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A,
+-0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00, 0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0xF3,0x02,
+-0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
+-0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
+-0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16,
+-0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+-0x1D,0xEC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00,
+-0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16,
+-0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1E,0x18, 0xF3,0x02,
+-0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+-0x00,0x00, 0xE6,0x00, 0x1F,0x35, 0xF6,0x82, 0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16,
+-0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A,
+-0x00,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
+-0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04,
+-0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0xAD, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x1E,0xAC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
+-0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x1E,0xC8, 0xF7,0x05,
+-0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
+-0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
+-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
+-0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
+-0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04, 0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA,
+-0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1F,0x60, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02,
+-0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00, 0x1F,0x68, 0xF7,0x02, 0x00,0x01, 0xF3,0x05,
+-0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1F,0x7C, 0xF3,0x06,
+-0x2F,0x6C, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94,
+-0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00, 0x22,0x84, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02,
+-0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05, 0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84,
+-0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02, 0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84,
+-0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02,
+-0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05, 0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96,
+-0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06,
+-0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05,
+-0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x34, 0x00,0x00,
+-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x25, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x26,0x8C, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82, 0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38,
+-0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x20,0x90, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04,
+-0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x20,0x84, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x20,0x94, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05,
+-0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x21,0xC0, 0x00,0x00,
+-0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05,
+-0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+-0x00,0x10, 0xE2,0x00, 0x21,0x19, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00,
+-0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13,
+-0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
+-0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
+-0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96,
+-0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x21,0x78, 0x00,0x00,
+-0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
+-0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x21,0xC0, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0x21,0xC1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04,
+-0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x21,0xFD, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x21,0xFC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
+-0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x22,0x18, 0xF7,0x05,
+-0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
+-0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
+-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
+-0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
+-0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02, 0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02,
+-0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06, 0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04,
+-0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05,
+-0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x22,0xD5, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A,
+-0x5A,0x00, 0xE6,0x00, 0x26,0x20, 0xC0,0x32, 0x6A,0x00, 0xEE,0x00, 0x26,0x21, 0x00,0x00,
+-0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00,
+-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04,
+-0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04,
+-0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04,
+-0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x23,0x45, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x23,0x48, 0xF7,0x05,
+-0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
+-0x00,0x21, 0xE2,0x00, 0x23,0x8C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x23,0x80, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
+-0x00,0x22, 0xE0,0x00, 0x23,0x90, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84,
+-0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0x87,0x02,
+-0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13,
+-0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93,
+-0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x24,0x78, 0x00,0x00,
+-0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00,
+-0x24,0x15, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x24,0x78, 0x00,0x00,
+-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1,
+-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16,
+-0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13,
+-0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30,
+-0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x24,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
+-0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A,
+-0x32,0x00, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
+-0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x24,0xBD, 0x00,0x00,
+-0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x24,0xF9, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x24,0xF8, 0xB3,0x3A,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38,
+-0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x25,0x14, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05,
+-0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36,
+-0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x25,0xD1, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
+-0x00,0x21, 0xE2,0x00, 0x25,0xC4, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x25,0xB0, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
+-0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x00, 0x25,0xC8, 0xF3,0x05,
+-0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00, 0x25,0xD8, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00,
+-0x25,0xDC, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06, 0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04,
+-0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x26,0x8C, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x26,0x8C, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x26,0x8C, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+-0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xEE,0x00, 0x26,0x41, 0xC5,0xB4,
+-0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00, 0x26,0x48, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8,
+-0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84, 0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35,
+-0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6,
+-0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04, 0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02,
+-0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85,
+-0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x7A,0x78, 0xF7,0x06,
+-0x30,0x84, 0xF7,0x05, 0x32,0xD4, 0xF7,0x04, 0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04,
+-0x32,0xD0, 0xF3,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x2A,0x71, 0x93,0x16,
+-0xFF,0xE4, 0xF6,0x84, 0x32,0xC4, 0x86,0x16, 0xFF,0xE4, 0x87,0x36, 0x00,0x08, 0xC3,0x04,
+-0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32, 0x00,0x00, 0x87,0x36,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02,
+-0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A,
+-0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C, 0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00,
+-0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00, 0x28,0x28, 0x96,0x16, 0xFF,0xEC, 0x77,0x31,
+-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30,
+-0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E, 0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x27,0xB8, 0xC4,0x84, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x27,0xBC, 0x20,0x2A,
+-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x27,0xC9, 0x00,0x00,
+-0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x04, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x28,0x0C, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x0D, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x28,0x1D, 0x20,0x26,
+-0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x28,0x28, 0xF3,0x02,
+-0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+-0x00,0x00, 0xE6,0x00, 0x28,0x69, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
+-0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+-0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
+-0x28,0xD0, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13,
+-0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x28,0xCD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
+-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
+-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E,
+-0x00,0x08, 0xE0,0x00, 0x28,0xD4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02, 0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16,
+-0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0, 0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32,
+-0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x29,0xBC, 0x96,0x96,
+-0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8,
+-0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE, 0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16,
+-0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0x4C, 0xC4,0x84, 0x00,0x00, 0x86,0xAE,
+-0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x29,0x50, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+-0x29,0x5D, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x29,0x98, 0xF6,0x02,
+-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0xA0, 0x20,0x32, 0x00,0x00, 0x86,0xAE,
+-0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0x29,0xA1, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x29,0xB1, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+-0x29,0xBC, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00,
+-0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x29,0xFD, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xF0, 0xE0,0x00, 0x2A,0x64, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13,
+-0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x2A,0x61, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
+-0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+-0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96,
+-0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x2A,0x68, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2B,0xCD, 0xF3,0x02, 0x00,0x01, 0xF6,0x84,
+-0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6, 0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E,
+-0x00,0x10, 0xE2,0x00, 0x2A,0x94, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2A,0xB1, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00, 0x2A,0xDC, 0xF7,0x02, 0x00,0x00, 0x07,0x30,
+-0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x2A,0xD5, 0xF6,0x82, 0x00,0x00, 0x20,0x32,
+-0x00,0x10, 0xE6,0x00, 0x2A,0xD8, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x2A,0xDC, 0xC7,0x34,
+-0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x2B,0xCC, 0xF3,0x02, 0x00,0x01, 0xF3,0x04, 0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16,
+-0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0x83,0x16,
+-0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+-0x00,0x10, 0xE2,0x00, 0x2B,0x49, 0x76,0xB1, 0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A, 0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00,
+-0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0xF3,0x02, 0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4,
+-0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38,
+-0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
+-0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30,
+-0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x2B,0xA4, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
+-0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02,
+-0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16, 0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+-0x00,0x00, 0xE6,0x00, 0x2B,0xD0, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16,
+-0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0xED, 0xF6,0x82,
+-0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16, 0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0x28, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+-0x2C,0x28, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x2C,0x65, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+-0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2C,0x64, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xE6,0x00, 0x2C,0x80, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
+-0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+-0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+-0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
+-0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04,
+-0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA, 0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x2D,0x18, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00,
+-0x2D,0x20, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x2D,0x34, 0xF3,0x06, 0x2F,0x6C, 0xE0,0x00, 0x34,0x44, 0xF3,0x05,
+-0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94, 0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
+-0x30,0x3C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
+-0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
+-0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
+-0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
+-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
+-0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
+-0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
+-0x74,0x00, 0xE6,0x00, 0x2D,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
+-0x2D,0xDD, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
+-0x00,0x10, 0xE6,0x00, 0x34,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
+-0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+-0x2E,0x48, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x2E,0x3C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
+-0x2E,0x4C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
+-0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x02, 0xE6,0x00, 0x2F,0x78, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C,
+-0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96,
+-0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+-0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
+-0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2E,0xD1, 0xF3,0x02,
+-0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
+-0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+-0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
+-0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38,
+-0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
+-0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
+-0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32,
+-0x00,0x11, 0xE6,0x00, 0x2F,0x30, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
+-0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+-0x2F,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
+-0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x2F,0x79, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
+-0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x2F,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+-0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2F,0xB4, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xE6,0x00, 0x2F,0xD0, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
+-0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+-0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+-0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
+-0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
+-0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06,
+-0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
+-0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x30,0x8D, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x33,0xD8, 0xC0,0x32,
+-0x6A,0x00, 0xEE,0x00, 0x33,0xD9, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x30,0xFD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0x31,0x00, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
+-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x31,0x44, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x31,0x38, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x31,0x48, 0xF3,0x05,
+-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+-0x32,0x74, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16,
+-0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x31,0xCD, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E,
+-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+-0x0F,0x00, 0xE0,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06,
+-0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+-0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16,
+-0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+-0x32,0x2C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+-0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x32,0x74, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x00, 0x32,0x75, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x32,0xB1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x32,0xB0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x32,0xCC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x33,0x91, 0xF7,0x05,
+-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x89, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x33,0x7C, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x33,0x68, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
+-0x77,0x00, 0xE0,0x00, 0x33,0x80, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+-0x33,0x90, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06,
+-0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x34,0x44, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x34,0x44, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00,
+-0x34,0x44, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xEE,0x00, 0x33,0xF9, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
+-0x34,0x00, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84,
+-0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35, 0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4,
+-0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6, 0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04,
+-0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02, 0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2,
+-0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85, 0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05,
+-0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x20, 0xF5,0x84, 0x7A,0x70, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
+-0x37,0x6C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
+-0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
+-0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
+-0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
+-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
+-0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
+-0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF4,0x86, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF4,0x85, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
+-0x74,0x00, 0xE6,0x00, 0x35,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
+-0x35,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
+-0x00,0x10, 0xE6,0x00, 0x3B,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
+-0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+-0x35,0x78, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x35,0x6C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
+-0x35,0x7C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
+-0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x02, 0xE6,0x00, 0x36,0xA8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC,
+-0x0E,0xF4, 0x94,0x96, 0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
+-0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+-0xFF,0xDC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
+-0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x36,0x01, 0xF4,0x82,
+-0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
+-0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+-0xFF,0xFC, 0xF4,0x86, 0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
+-0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38,
+-0x60,0x00, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
+-0xFF,0xDC, 0x96,0x16, 0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
+-0xFF,0xFC, 0x86,0x16, 0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32,
+-0x00,0x11, 0xE6,0x00, 0x36,0x60, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
+-0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
+-0x36,0xA8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
+-0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x36,0xA9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
+-0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x36,0xE5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+-0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x36,0xE4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xE6,0x00, 0x37,0x00, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
+-0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+-0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+-0x3A,0xC1, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00,
+-0x00,0x01, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
+-0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF4,0x86,
+-0x32,0x28, 0xF4,0x85, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
+-0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x37,0xBD, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x3B,0x08, 0xC0,0x32,
+-0x6A,0x00, 0xEE,0x00, 0x3B,0x09, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x38,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0x38,0x30, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
+-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x38,0x74, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x38,0x68, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x38,0x78, 0xF4,0x85,
+-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+-0x39,0xA4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
+-0xFF,0xE4, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xDC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x38,0xFD, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
+-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+-0x0F,0x00, 0xE0,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
+-0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xE4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+-0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x96,0x16,
+-0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+-0x39,0x5C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+-0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x39,0xA4, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x00, 0x39,0xA5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x39,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x39,0xE0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x39,0xFC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3A,0xC1, 0xF7,0x05,
+-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0xB9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3A,0xAC, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3A,0x98, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
+-0x77,0x00, 0xE0,0x00, 0x3A,0xB0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+-0x3A,0xC0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
+-0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x3B,0x70, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3B,0x70, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+-0x3B,0x70, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xEE,0x00, 0x3B,0x29, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
+-0x3B,0x30, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
+-0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
+-0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
+-0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF5,0x04,
+-0x7A,0x88, 0xF7,0x06, 0x7A,0x2C, 0xF5,0x84, 0x7A,0x90, 0x76,0xA9, 0x00,0x03, 0xA6,0xB6,
+-0x70,0x02, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x3B,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x7A,0xA0, 0x00,0x00, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x3F,0x18, 0xC0,0x2E,
+-0x6A,0x00, 0xEE,0x00, 0x3F,0x19, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0xF6,0x04,
+-0x32,0xC8, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+-0x3C,0x3D, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x32,0xE0, 0xF6,0x85, 0x7A,0x70, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0x3C,0x40, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
+-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3C,0x84, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3C,0x78, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x3C,0x88, 0xF4,0x85,
+-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+-0x3D,0xB4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
+-0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xE4, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x3D,0x0D, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
+-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+-0x0F,0x00, 0xE0,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
+-0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+-0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x96,0x16,
+-0xFF,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xE0, 0x85,0x96, 0xFF,0xE4, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+-0x3D,0x6C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+-0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x3D,0xB4, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x00, 0x3D,0xB5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x3D,0xF1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x3D,0xF0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x3E,0x0C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3E,0xD1, 0xF7,0x05,
+-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x3E,0x71, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x3E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3E,0xC9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3E,0xBC, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3E,0xA8, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
+-0x77,0x00, 0xE0,0x00, 0x3E,0xC0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+-0x3E,0xD0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3E,0xD4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
+-0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x3F,0x80, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0x80, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+-0x3F,0x80, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xEE,0x00, 0x3F,0x39, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
+-0x3F,0x40, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
+-0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
+-0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
+-0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF5,0x84,
+-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3F,0xE4, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0xD8, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xE0,0x00, 0x3F,0xE8, 0xF5,0x05,
+-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+-0x41,0x14, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x05,0x2C, 0x0E,0xF4, 0x95,0x16,
+-0xFF,0xF4, 0xF7,0x05, 0x7A,0x68, 0x95,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x40,0x6D, 0xF5,0x02, 0x00,0x4C, 0x87,0x2E,
+-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+-0x0F,0x00, 0xE0,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
+-0x7A,0x28, 0x95,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x85,0x16, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+-0x50,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x96,0x16,
+-0xFF,0xE8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xE8, 0x85,0x96, 0xFF,0xEC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+-0x40,0xCC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+-0x32,0xC0, 0xF5,0x06, 0xE0,0x30, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0x41,0x14, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x00, 0x41,0x15, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x41,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0A, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x41,0x50, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x41,0x6C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x42,0x31, 0xF7,0x05,
+-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x41,0xD1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x41,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x42,0x29, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x42,0x1C, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x08, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04,
+-0x77,0x00, 0xE0,0x00, 0x42,0x20, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+-0x42,0x30, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x42,0x34, 0xF5,0x06, 0x31,0x9C, 0xF5,0x06,
+-0x2E,0xE0, 0xF5,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x42,0x74, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
+-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x74, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
+-0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x2F,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
+-0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x43,0xD0, 0x00,0x00,
+-0x00,0x01, 0x20,0x36, 0x00,0x10, 0xE2,0x00, 0x43,0xED, 0x07,0x34, 0x00,0x01, 0x87,0x2E,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x0C, 0x87,0x2E,
+-0x00,0x0C, 0xE0,0x00, 0x44,0x14, 0xF4,0x02, 0x00,0x00, 0xC0,0x3A, 0x62,0x00, 0xE6,0x00,
+-0x44,0x11, 0xF4,0x02, 0x00,0x00, 0x20,0x36, 0x00,0x10, 0xE6,0x00, 0x44,0x14, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x44,0x14, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
+-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
+-0x00,0x01, 0xF7,0x05, 0x35,0x24, 0xF7,0x04, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x05,
+-0x35,0x28, 0xF7,0x06, 0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
+-0x45,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0D, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x02, 0x4A,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0F, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x4E,0xEC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
+-0x00,0x08, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x57,0x64, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x02, 0x00,0x07, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
+-0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x2D, 0xF6,0x86,
+-0x75,0xF8, 0xE0,0x00, 0x45,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
+-0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x5C, 0xF7,0x05, 0x35,0x48, 0xF4,0x86,
+-0x33,0x80, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0x6F,0x54, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x80, 0xF4,0x82, 0x00,0x08, 0xF4,0x82,
+-0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x45,0x88, 0xF7,0x02, 0x00,0x01, 0xF4,0x85,
+-0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0xA0, 0xF4,0x82,
+-0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF6,0x84,
+-0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82,
+-0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36,
+-0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2,
+-0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00,
+-0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
+-0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2,
+-0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82,
+-0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02,
+-0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82,
+-0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2,
+-0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96,
+-0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2,
+-0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E,
+-0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
+-0x49,0xF0, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0xA4, 0x00,0x00,
+-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0x95, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x49,0xF0, 0x00,0x00,
+-0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
+-0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+-0x47,0x08, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x46,0xFC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
+-0x47,0x0C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
+-0x47,0x71, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x47,0x69, 0xC6,0x38,
+-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x0F, 0xE2,0x00, 0x47,0xBD, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+-0x47,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+-0x00,0x08, 0xE0,0x00, 0x49,0x68, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+-0x47,0xCC, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x48,0x1C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0x48,0x81, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86,
+-0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x48,0x81, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x48,0x80, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x49,0x68, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x02, 0xE6,0x00, 0x49,0x3C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x49,0x11, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x47,0xA8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0x5C, 0x07,0x34, 0x14,0x94, 0xF4,0x84,
+-0x6F,0x44, 0xE0,0x00, 0x49,0x60, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+-0x48,0x84, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x49,0xA1, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x49,0xA8, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00, 0x49,0xA8, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82,
+-0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86,
+-0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04,
+-0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0x49,0xF1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
+-0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x2D, 0xF6,0x86,
+-0x75,0xF8, 0xE0,0x00, 0x4A,0x40, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
+-0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04,
+-0x6F,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x64, 0xF6,0x85,
+-0x35,0x48, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x4A,0x70, 0xF7,0x02,
+-0x00,0x01, 0xF4,0x82, 0x00,0x08, 0xF4,0x85, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x4A,0x88, 0xF4,0x82, 0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00,
+-0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7,
+-0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32,
+-0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85,
+-0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
+-0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6,
+-0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00,
+-0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85,
+-0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86,
+-0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4,
+-0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85,
+-0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04,
+-0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05,
+-0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00,
+-0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x4E,0xD8, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
+-0x74,0x00, 0xE6,0x00, 0x4B,0x8C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
+-0x4B,0x7D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
+-0x00,0x10, 0xE6,0x00, 0x4E,0xD8, 0x00,0x00, 0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82,
+-0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38,
+-0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x4B,0xF0, 0xF7,0x05, 0x35,0x58, 0xF7,0x04,
+-0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4B,0xE4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x4B,0xF4, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05,
+-0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84,
+-0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x4C,0x59, 0x00,0x00, 0x00,0x01, 0x86,0x36,
+-0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
+-0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4,
+-0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38,
+-0x00,0x24, 0xE6,0x00, 0x4C,0x51, 0xC6,0x38, 0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04,
+-0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00, 0x4C,0xA5, 0x07,0x38,
+-0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x4C,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x4E,0x50, 0xF7,0x05,
+-0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x4C,0xB4, 0x00,0x00, 0x00,0x01, 0xF7,0x02,
+-0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6,
+-0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x4D,0x04, 0xF7,0x05, 0x76,0x04, 0xF0,0x05,
+-0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36,
+-0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF7,0x05,
+-0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4D,0x68, 0xB4,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00,
+-0x4E,0x50, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x4E,0x24, 0x05,0xB4,
+-0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96,
+-0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
+-0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+-0x00,0x0F, 0xE2,0x00, 0x4D,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00,
+-0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+-0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C,
+-0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4C,0x90, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84,
+-0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x4E,0x44, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00, 0x4E,0x48, 0xF4,0x85,
+-0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x4D,0x6C, 0x05,0x28, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0x4E,0x89, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+-0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4E,0x90, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+-0x4E,0x90, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84,
+-0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
+-0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x4E,0xD9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
+-0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0x82,
+-0x00,0x04, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB,
+-0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32,
+-0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00,
+-0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
+-0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6,
+-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00,
+-0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04,
+-0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2,
+-0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32,
+-0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05,
+-0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38,
+-0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
+-0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32,
+-0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x53,0x4C, 0xF7,0x06,
+-0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x50,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x7E,
+-0x74,0x00, 0xE6,0x00, 0x4F,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
+-0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x53,0x4C, 0x00,0x00, 0x00,0x01, 0xFF,0x82,
+-0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85,
+-0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x50,0x64, 0xF7,0x05,
+-0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x50,0x58, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x50,0x68, 0xF4,0x85,
+-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x50,0xCD, 0x00,0x00,
+-0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4,
+-0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16,
+-0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E,
+-0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x50,0xC5, 0xC6,0x38, 0x60,0x00, 0x06,0xB4,
+-0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00,
+-0x51,0x19, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x51,0x2C, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00,
+-0x52,0xC4, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x51,0x28, 0x00,0x00,
+-0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84,
+-0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36,
+-0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04,
+-0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84,
+-0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x51,0x78, 0xF7,0x05,
+-0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05,
+-0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0x51,0xDD, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A,
+-0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0xDD, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x51,0xDC, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A,
+-0x00,0x02, 0xEE,0x00, 0x52,0xC4, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+-0x52,0x98, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96,
+-0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93,
+-0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x52,0x6D, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36,
+-0x00,0x14, 0xE0,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
+-0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38,
+-0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0x04, 0xF7,0x05,
+-0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x52,0xB8, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00,
+-0x52,0xBC, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x51,0xE0, 0x05,0x28,
+-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x52,0xFD, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x53,0x04, 0xB4,0xBA,
+-0x68,0x02, 0xE0,0x00, 0x53,0x04, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85,
+-0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x53,0x4C, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
+-0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x53,0x4D, 0x00,0x00,
+-0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF4,0x84, 0x35,0x54, 0xF6,0x84,
+-0x35,0x4C, 0xF5,0x84, 0x35,0x2C, 0x94,0x82, 0xFF,0x38, 0x76,0xB5, 0x00,0x03, 0xA5,0x2E,
+-0x68,0x02, 0x00,0x00, 0x00,0x01, 0x95,0x02, 0xFF,0x3C, 0xF3,0x84, 0x35,0x50, 0xC6,0xAC,
+-0x68,0x00, 0x93,0x82, 0xFF,0x40, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02,
+-0xFF,0x44, 0x86,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x60,0x00, 0xF7,0x05, 0x35,0x40, 0xF6,0x04, 0x35,0x28, 0x86,0xB6, 0x00,0x04, 0x87,0x32,
+-0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x97,0x32, 0x14,0x14, 0x87,0x2E,
+-0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x57,0x50, 0x95,0x16,
+-0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x54,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x53,0xF5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x57,0x50, 0x00,0x00,
+-0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
+-0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+-0x54,0x68, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x54,0x5C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82, 0x00,0x22, 0xE0,0x00,
+-0x54,0x6C, 0xF3,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x84, 0x00,0x00, 0xC0,0x3A, 0x3A,0x00, 0xE6,0x00,
+-0x54,0xD1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x54,0xC9, 0xC6,0x38,
+-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x0F, 0xE2,0x00, 0x55,0x1D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+-0x55,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+-0x00,0x08, 0xE0,0x00, 0x56,0xC8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+-0x55,0x2C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x55,0x7C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0x55,0xE1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x86,
+-0x72,0x18, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x55,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0E, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x55,0xE0, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x56,0xC8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x02, 0xE6,0x00, 0x56,0x9C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x56,0x71, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x55,0x08, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x56,0xBC, 0x07,0x34, 0x14,0x94, 0xF3,0x84,
+-0x6F,0x44, 0xE0,0x00, 0x56,0xC0, 0xF3,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+-0x55,0xE4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x57,0x01, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x57,0x08, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x57,0x08, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82,
+-0x00,0x01, 0xF3,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x86,
+-0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x57,0x50, 0xF3,0x85, 0x35,0x30, 0xF7,0x04,
+-0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0x57,0x51, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0x87,0x02,
+-0xFF,0x38, 0xF3,0x84, 0x35,0x2C, 0xF7,0x05, 0x35,0x54, 0x87,0x1E, 0x00,0x80, 0xF5,0x04,
+-0x35,0x4C, 0x27,0x38, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x5A,0x4C, 0x00,0x00,
+-0x00,0x01, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+-0x57,0xD8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x57,0xCC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
+-0x57,0xDC, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+-0x58,0x41, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x58,0x39, 0xC6,0x38,
+-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x0F, 0xE2,0x00, 0x58,0x8D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+-0x58,0xA0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+-0x00,0x08, 0xE0,0x00, 0x5A,0x38, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+-0x58,0x9C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x58,0xEC, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0x59,0x51, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
+-0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x59,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x59,0x50, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5A,0x38, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x02, 0xE6,0x00, 0x5A,0x0C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x59,0xE1, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x58,0x78, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5A,0x2C, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
+-0x6F,0x44, 0xE0,0x00, 0x5A,0x30, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+-0x59,0x54, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xC4, 0xF3,0x02,
+-0x00,0x01, 0xE0,0x00, 0x5D,0xF0, 0x00,0x00, 0x00,0x01, 0x77,0x29, 0x00,0x03, 0xC7,0x1C,
+-0x70,0x00, 0x87,0x3A, 0x00,0x04, 0x05,0x28, 0x00,0x01, 0x76,0xA9, 0x00,0x03, 0xF4,0x84,
+-0x35,0x54, 0xF6,0x04, 0x35,0x50, 0x94,0x82, 0xFF,0x38, 0xA4,0x1E, 0x68,0x02, 0xC6,0x30,
+-0x70,0x00, 0x94,0x02, 0xFF,0x3C, 0x96,0x02, 0xFF,0x40, 0xC6,0x9C, 0x68,0x00, 0x87,0x36,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02, 0xFF,0x44, 0x85,0xB6, 0x00,0x04, 0xF7,0x04,
+-0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x35,0x40, 0x85,0xB6,
+-0x00,0x04, 0xF5,0x05, 0x35,0x4C, 0xF6,0x84, 0x35,0x28, 0xF6,0x05, 0x35,0x50, 0x87,0x36,
+-0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x58,0x00, 0x97,0x36, 0x14,0x14, 0x87,0x1E,
+-0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x5E,0x3C, 0x94,0x16,
+-0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xF4, 0x00,0x00,
+-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x5E,0x3C, 0x00,0x00,
+-0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
+-0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+-0x5B,0x58, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x5B,0x4C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
+-0x5B,0x5C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+-0x5B,0xC1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x5B,0xB9, 0xC6,0x38,
+-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x0F, 0xE2,0x00, 0x5C,0x0D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+-0x5C,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+-0x00,0x08, 0xE0,0x00, 0x5D,0xB8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+-0x5C,0x1C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+-0x5C,0x6C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0x5C,0xD1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
+-0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x5C,0xD1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x5C,0xD0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5D,0xB8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x02, 0xE6,0x00, 0x5D,0x8C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x5D,0x61, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x5B,0xF8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5D,0xAC, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
+-0x6F,0x44, 0xE0,0x00, 0x5D,0xB0, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+-0x5C,0xD4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xF1, 0xF3,0x02,
+-0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x5D,0xF4, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x5D,0xF4, 0xF0,0x05, 0x2D,0x38, 0xF3,0x05,
+-0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x06, 0x32,0xF4, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x5E,0x3C, 0xF3,0x05, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
+-0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x5E,0x3D, 0x00,0x00,
+-0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2, 0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00,
+-0x5F,0x2C, 0xC5,0xB4, 0x00,0x00, 0x20,0x36, 0x00,0x0F, 0xEE,0x00, 0x5F,0x2C, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0x5F,0x2D, 0x00,0x00, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xEC,0x00, 0x5F,0x48, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32, 0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00,
+-0x5F,0x50, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A, 0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
+-0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x66,0xF8, 0x96,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
+-0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
+-0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x16, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x62,0x7C, 0x96,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
+-0x66,0xF8, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
+-0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x82, 0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x16, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
+-0x62,0x7C, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
+-0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x61,0x15, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0xE0,0x00, 0x61,0x18, 0x77,0x39,
+-0x00,0x02, 0xF7,0x02, 0x00,0xF0, 0xF7,0x05, 0x42,0x28, 0xF7,0x06, 0x40,0x8A, 0xF0,0x3B,
+-0x28,0x00, 0xF7,0x06, 0x40,0x8C, 0xF0,0x3B, 0x28,0x00, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
+-0x7A,0xC0, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x05, 0x7A,0xB0, 0xF7,0x05, 0x7A,0xC8, 0xF6,0x82,
+-0xC3,0x50, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x16, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
+-0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04,
+-0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x61,0xED, 0x76,0xB1,
+-0x00,0x1E, 0x87,0x32, 0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00, 0x61,0xEC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
+-0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0x61,0xEC, 0xF5,0x06, 0x35,0xEC, 0xF7,0x04,
+-0x42,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x62,0x11, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06,
+-0x42,0xA2, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x62,0x68, 0xF7,0x33, 0x28,0x00, 0x87,0x32,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0xE0,0x00, 0x86,0xB2, 0x00,0x08, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x62,0x3C, 0xF6,0x85, 0xE0,0x04, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+-0x62,0x40, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+-0x62,0x65, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x04, 0x42,0x3C, 0xF6,0x84, 0x6F,0x34, 0x07,0x38, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0x62,0xB1, 0xF7,0x05, 0x42,0x3C, 0x87,0x36, 0x00,0x00, 0xF5,0x9E,
+-0x00,0x02, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x62,0xBD, 0xF5,0x86, 0x35,0xEC, 0xF7,0x04,
+-0x42,0xA0, 0xE0,0x00, 0x62,0xDC, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x62,0xF9, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
+-0x63,0x0C, 0xF7,0x33, 0x28,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x63,0x20, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x20, 0x83,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x87,0x1A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x63,0x6C, 0xF7,0x02, 0x00,0x00, 0x83,0x9A, 0x00,0x1C, 0x00,0x00, 0x00,0x01, 0xF3,0x85,
+-0x7A,0xC0, 0x84,0x9A, 0x00,0x14, 0xF7,0x05, 0x7A,0xC8, 0xF4,0x85, 0x7A,0xB0, 0xF7,0x05,
+-0x7A,0xB8, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x14, 0xF7,0x04,
+-0x7A,0xB0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0xF6,0x02,
+-0x00,0x00, 0x86,0x9A, 0x00,0x1C, 0xF7,0x04, 0x7A,0xC0, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x18, 0xF7,0x04,
+-0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00,
+-0x00,0x01, 0x86,0x9A, 0x00,0x20, 0xF7,0x04, 0x7A,0xC8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x20,0x3A, 0x00,0x64, 0xEE,0x00, 0x63,0xD9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x64,0x58, 0x00,0x00, 0x00,0x01, 0x83,0x96,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x64,0x3C, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0x40,0x80, 0xF7,0x05,
+-0x40,0x84, 0xF6,0x84, 0x6E,0x50, 0xF4,0x82, 0xFF,0xFF, 0x83,0x1E, 0x00,0x0C, 0xF4,0x85,
+-0x4F,0x54, 0x93,0x36, 0x00,0x10, 0x83,0x9E, 0x00,0x10, 0x84,0x96, 0x00,0x00, 0x93,0xB6,
+-0x00,0x14, 0x84,0xA6, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x1D,0xDC, 0xF6,0x82,
+-0x00,0x64, 0xF6,0x85, 0x4A,0x98, 0xF7,0x05, 0x4A,0x9C, 0x83,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00,
+-0x64,0x7C, 0xF3,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA4, 0xF6,0x06, 0x42,0xA6, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0x66,0xE4, 0xF7,0x33, 0x28,0x00, 0x93,0x96, 0xFF,0xF4, 0x84,0x16,
+-0x00,0x00, 0xF4,0x86, 0x42,0xC8, 0x94,0x96, 0xFF,0xEC, 0xF3,0x02, 0x00,0x0C, 0x93,0x16,
+-0xFF,0xE4, 0x83,0x96, 0x00,0x00, 0x84,0x96, 0xFF,0xF4, 0x87,0x1E, 0x00,0x20, 0x00,0x00,
+-0x00,0x01, 0xC0,0x26, 0x72,0x00, 0xEC,0x00, 0x66,0x48, 0xF3,0x86, 0x4A,0x98, 0x84,0xA2,
+-0x00,0x24, 0x83,0x16, 0xFF,0xE4, 0xC5,0x04, 0x00,0x00, 0xB4,0x9A, 0x38,0x02, 0xC7,0x18,
+-0x38,0x00, 0x83,0x22, 0x00,0x28, 0x83,0x96, 0xFF,0xF4, 0x84,0x96, 0xFF,0xE4, 0x93,0x3A,
+-0x00,0x04, 0x93,0xBA, 0x00,0x08, 0xF6,0x04, 0xE0,0x00, 0xF3,0x06, 0x4A,0x98, 0xA6,0xA6,
+-0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x32, 0x6A,0x00, 0xE6,0x00, 0x65,0x10, 0xC6,0x38,
+-0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x65,0x14, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0x65,0x21, 0x00,0x00, 0x00,0x01, 0xF5,0x02, 0x00,0x00, 0xF6,0x84,
+-0xE0,0x00, 0x87,0x32, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0x65,0x5C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x65,0x64, 0x20,0x2E,
+-0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0x65,0x65, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0x65,0x75, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
+-0x00,0x00, 0xE6,0x00, 0x65,0x88, 0x00,0x00, 0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0x00,0x00,
+-0x00,0x01, 0xF3,0x85, 0x4F,0x54, 0x87,0x22, 0x00,0x2C, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x05,0xA0, 0x00,0x2E, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xF4,0x82,
+-0x00,0x00, 0x94,0x96, 0xFF,0xDC, 0x83,0x16, 0xFF,0xEC, 0x20,0x26, 0x00,0x07, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0x98,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE2,0x00, 0x66,0x1C, 0xF7,0x37,
+-0x28,0x00, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0xC7,0x2C,
+-0x40,0x00, 0x86,0xBA, 0x00,0x30, 0x06,0x28, 0x00,0x04, 0x05,0x28, 0x00,0x02, 0x05,0xAC,
+-0x00,0x02, 0x83,0x96, 0xFF,0xDC, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x03,0x9C,
+-0x00,0x01, 0x93,0x96, 0xFF,0xDC, 0x20,0x1E, 0x00,0x07, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
+-0xFF,0xF0, 0xE2,0x00, 0x65,0xE1, 0xF6,0xB3, 0x28,0x00, 0x04,0x20, 0x00,0x1C, 0x84,0x96,
+-0xFF,0xEC, 0x83,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xF4, 0x04,0xA4, 0x00,0x14, 0x94,0x96,
+-0xFF,0xEC, 0x03,0x18, 0x00,0x0C, 0x93,0x16, 0xFF,0xE4, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
+-0x64,0x94, 0x93,0x96, 0xFF,0xF4, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x26,
+-0x00,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x4A,0x9C, 0x85,0xA6, 0x00,0x20, 0xF7,0x04,
+-0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x04,
+-0x7A,0xB8, 0xF6,0x84, 0x7A,0xC8, 0x86,0x26, 0x00,0x18, 0xC6,0xB4, 0x58,0x00, 0x87,0x26,
+-0x00,0x1C, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0x47,0x0C,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x66,0xE5, 0xF6,0x85, 0x7A,0xC8, 0x83,0x26,
+-0x00,0x08, 0xF7,0x04, 0x6E,0x50, 0xF3,0x05, 0x3B,0x64, 0x83,0xA6, 0x00,0x08, 0xF6,0x82,
+-0x00,0x00, 0x93,0xBA, 0x1D,0xDC, 0x84,0xA6, 0x00,0x0C, 0x83,0x16, 0x00,0x00, 0x94,0xBA,
+-0x00,0x10, 0x83,0x1A, 0x00,0x10, 0xF6,0x85, 0x7A,0xC8, 0x93,0x3A, 0x00,0x14, 0xF7,0x02,
+-0x00,0x01, 0xF7,0x05, 0x40,0x84, 0xF6,0x85, 0x7A,0xC0, 0xF6,0x85, 0x7A,0xB8, 0xF6,0x85,
+-0x7A,0xB0, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x08, 0xF3,0x84, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0xF6,0x84,
+-0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x67,0x29, 0xF7,0x02,
+-0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE8, 0xF5,0x82,
+-0x00,0x01, 0xF7,0x04, 0xE0,0x1C, 0x86,0x9E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE9, 0xC5,0x84,
+-0x00,0x00, 0x86,0x9E, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x67,0x88, 0x05,0x1C, 0x00,0x10, 0x86,0x9E, 0x00,0x14, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x67,0x8C, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0x99, 0x00,0x00,
+-0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xAA, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xD4, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x67,0xDC, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xDD, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0xED, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x68,0x10, 0xF6,0x06,
+-0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
+-0x75,0xF4, 0x75,0xAC, 0xFF,0xE1, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x68,0x45, 0x95,0x96,
+-0xFF,0xF4, 0xF7,0x04, 0x42,0x98, 0xF6,0x06, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x04,0x1C, 0x00,0x20, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00,
+-0x68,0xC4, 0xF3,0x06, 0x15,0x54, 0xF5,0x02, 0x00,0x00, 0x05,0x9C, 0x00,0x22, 0xC4,0xAC,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00,
+-0x68,0xC0, 0xC6,0xA4, 0x60,0x00, 0xA7,0x26, 0x60,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x05,0x28, 0x00,0x01, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xE8, 0xF7,0x2F,
+-0x68,0x00, 0x05,0xAC, 0x00,0x01, 0xE0,0x00, 0x68,0x78, 0x06,0x30, 0x00,0x02, 0xF3,0x06,
+-0x15,0x54, 0x93,0x13, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
+-0xE0,0x00, 0x93,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x02, 0x00,0x01, 0x93,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x69,0x28, 0xF6,0x06, 0x42,0x9E, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+-0x00,0x00, 0xE6,0x00, 0x69,0x6C, 0xF3,0x06, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x69,0x6D, 0xF0,0x05, 0x42,0x28, 0xF3,0x06, 0x35,0x60, 0xF3,0x05, 0x42,0x30, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x04, 0x6F,0x34, 0xF7,0x04,
+-0x42,0x40, 0x86,0x2A, 0x00,0x18, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0xE0,0x1C, 0xF7,0x05,
+-0x42,0x40, 0xC0,0x36, 0x62,0x00, 0xEC,0x00, 0x69,0xB5, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
+-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x80, 0xF7,0x02, 0x00,0x01, 0xF7,0x04,
+-0xE0,0x1C, 0x86,0xAA, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x7D, 0xC5,0x84, 0x00,0x00, 0x86,0xAA,
+-0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x6A,0x14, 0x04,0xA8, 0x00,0x10, 0x86,0xAA, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x6A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x25, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+-0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0x6A,0x60, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x6A,0x68, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x6A,0x69, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x81, 0xC7,0x2C, 0x00,0x00, 0xF5,0x82,
+-0x00,0x01, 0xE0,0x00, 0x6A,0x80, 0xC7,0x2C, 0x00,0x00, 0xC7,0x04, 0x00,0x00, 0x20,0x3A,
+-0x00,0x00, 0xEE,0x00, 0x6B,0x3D, 0xF6,0x86, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x6B,0x3C, 0xF6,0x82, 0x00,0x00, 0xF6,0x85, 0x40,0x80, 0xF6,0x85,
+-0x40,0x84, 0x96,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00,
+-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x86, 0xE0,0x00, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
+-0xFF,0xFC, 0xF3,0x82, 0x00,0x02, 0x93,0x93, 0xFF,0xFC, 0x96,0x96, 0xFF,0xF4, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0x86,0x96,
+-0xFF,0xF4, 0xF7,0x04, 0x6E,0x50, 0xF3,0x86, 0x35,0xEC, 0xF6,0x85, 0x40,0x90, 0xF6,0x85,
+-0x40,0x94, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x85, 0x42,0x28, 0xF7,0x05, 0x3B,0x64, 0xF7,0x04,
+-0x42,0x30, 0xF4,0x05, 0x40,0x80, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x6B,0x3D, 0xF3,0x86, 0x35,0x60, 0xF3,0x85, 0x42,0x30, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x6D,0xD9, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x40,0x8C, 0xF6,0x06, 0x40,0x8C, 0x76,0x31,
+-0x00,0x1E, 0xF6,0x84, 0x42,0x28, 0x76,0x30, 0xFF,0xE5, 0x06,0xB4, 0x00,0x01, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6B,0xC8, 0xF6,0x85,
+-0x42,0x28, 0xF7,0x04, 0x40,0x88, 0xF6,0x86, 0x40,0x8A, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x6D,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x6C,0x35, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x6C,0x34, 0xF4,0x86, 0x36,0x78, 0xF7,0x04, 0x42,0x44, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x6C,0x35, 0xF4,0x82, 0x00,0x01, 0xF4,0xB3, 0x28,0x00, 0xE0,0x00, 0x6D,0x10, 0xF0,0x05,
+-0x42,0x2C, 0xF7,0x04, 0x40,0x8C, 0xF5,0x06, 0x40,0x8C, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x6C,0xC1, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x6C,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x2C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x20,0x3A, 0x00,0x09, 0xEE,0x00, 0x6D,0x11, 0xF7,0x05, 0x42,0x2C, 0xF0,0x2B,
+-0x28,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0xF6,0x06,
+-0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x6D,0x10, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
+-0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6D,0x14, 0x20,0x2E,
+-0x00,0x00, 0xF7,0x04, 0x40,0x88, 0xF6,0x06, 0x40,0x8A, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x6D,0x15, 0x20,0x2E, 0x00,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0x6D,0xB5, 0xF4,0x86, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x6D,0x59, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0x3C, 0xF6,0x84, 0xE0,0x28, 0xE0,0x00,
+-0x6D,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0xF0, 0xF7,0x04, 0xE0,0x28, 0x00,0x00,
+-0x00,0x01, 0x76,0xB9, 0x00,0x02, 0xF7,0x04, 0x42,0x28, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x6A,0x00, 0xEC,0x00, 0x6D,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05,
+-0x42,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+-0x00,0x19, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x6D,0xB4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF4,0x82, 0xC3,0x50, 0x94,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x16, 0x94,0x93,
+-0xFF,0xFC, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86,
+-0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x82, 0x74,0x18, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x19, 0x95,0x93,
+-0xFF,0xFC, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x74,0xAC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x78,0x00, 0x95,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+-0x78,0xFC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+-0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x82, 0x80,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x86, 0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x81,0x74, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x87,0x74, 0x95,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+-0x94,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+-0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x82, 0x8A,0x00, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x8E,0x08, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x96,0x9C, 0x95,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0xA8, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+-0x9B,0x2C, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+-0x38,0xA8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x82, 0xA2,0xDC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x9E,0x54, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xA3,0xC0, 0x95,0x93,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+-0xA7,0x64, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+-0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x82, 0xAA,0x04, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xAE,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0x4C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x50, 0xF0,0x3B,
+-0x28,0x00, 0xF7,0x06, 0x40,0x88, 0xF0,0x3B, 0x28,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x05,
+-0x40,0x80, 0xF6,0x05, 0x40,0x84, 0xF7,0x06, 0x3B,0x70, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06,
+-0x3B,0x72, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xCA,0x20, 0xF5,0x85, 0x3B,0x74, 0xF7,0x06,
+-0x3B,0x78, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x7A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+-0xB1,0x94, 0xF5,0x85, 0x3B,0x7C, 0xF7,0x06, 0x3B,0x80, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
+-0x3B,0x82, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x54, 0xF5,0x85, 0x3B,0x84, 0xF7,0x06,
+-0x3B,0x88, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x8A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+-0xBE,0xF8, 0xF5,0x85, 0x3B,0x8C, 0xF7,0x06, 0x3B,0x90, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
+-0x3B,0x92, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC8,0xF8, 0xF5,0x85, 0x3B,0x94, 0xF7,0x06,
+-0x3B,0x98, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x9A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+-0xC5,0xD8, 0xF5,0x85, 0x3B,0x9C, 0xF7,0x06, 0x3B,0xA0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
+-0x3B,0xA2, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x70, 0xF5,0x85, 0x3B,0xA4, 0xF7,0x06,
+-0x3B,0xA8, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0xAA, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+-0xC1,0xB4, 0xF5,0x85, 0x3B,0xAC, 0x96,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD5,0x40, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
+-0x00,0x01, 0x96,0x36, 0x1D,0xDC, 0xF6,0x05, 0x3B,0x64, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
+-0x28,0x00, 0x26,0x14, 0x00,0x38, 0xF0,0x33, 0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04,
+-0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x72,0x1D, 0xF5,0x02, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
+-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02,
+-0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x04, 0x86,0x16, 0x00,0x00, 0xF6,0x82,
+-0x00,0xFF, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x6C,0x00, 0xF7,0x33, 0x28,0x00, 0xF7,0x06,
+-0xE0,0x06, 0x87,0x3A, 0x00,0x00, 0x06,0xB0, 0x00,0x02, 0xF7,0x37, 0x28,0x00, 0xF6,0x84,
+-0x3B,0x64, 0x07,0x30, 0x00,0x04, 0xF6,0xBB, 0x28,0x00, 0x87,0x02, 0xFF,0x34, 0x06,0x30,
+-0x00,0x06, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x30, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x27,0x14,
+-0x00,0x38, 0xF0,0x3B, 0x28,0x00, 0x97,0x13, 0xFF,0xFC, 0x90,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x73,0x19, 0xF5,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
+-0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x1B, 0x95,0x93,
+-0xFF,0xFC, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x40, 0x26,0x14, 0x00,0x20, 0x96,0x16, 0xFF,0xC4, 0xF0,0x33,
+-0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x96,0x16,
+-0xFF,0xBC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+-0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13,
+-0xFF,0xFC, 0x86,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x73,0xE5, 0xF6,0x02,
+-0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05,
+-0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0xF6,0x02, 0x00,0x1B, 0x96,0x13, 0xFF,0xFC, 0xF6,0x06,
+-0x42,0x44, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x04, 0xF5,0x82, 0x00,0x00, 0xF5,0x85, 0x40,0x80, 0x95,0x96, 0xFF,0xF4, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCB,0x50, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0xF5,0x02,
+-0x00,0x64, 0xF5,0x05, 0x3B,0xB4, 0xF7,0x04, 0x42,0x50, 0xF4,0x86, 0x42,0x50, 0x76,0xA5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x4F,0x5C, 0xF4,0x02, 0x00,0x06, 0xF4,0x05,
+-0x42,0x54, 0xF5,0x85, 0x3B,0x6C, 0xF5,0x85, 0x3B,0xB8, 0x95,0x32, 0x00,0x00, 0x95,0xB2,
+-0x00,0x04, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x27,
+-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x06,
+-0x37,0x04, 0xF4,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2,
+-0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x77,0xEC, 0xC5,0x04,
+-0x00,0x00, 0x86,0xB2, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF3,0x02, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x75,0x18, 0x04,0xB0, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x75,0x1C, 0x20,0x1A,
+-0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x75,0x29, 0x00,0x00,
+-0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x64, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x75,0x6C, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x6D, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x75,0x7D, 0x20,0x2A,
+-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x77,0xEC, 0x00,0x00,
+-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14,
+-0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0, 0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF5,0x82,
+-0x00,0x00, 0x23,0x94, 0x00,0x22, 0xF5,0x9F, 0x28,0x00, 0x03,0xA0, 0x00,0x1A, 0x93,0x96,
+-0xFF,0xD4, 0x25,0x94, 0x00,0x22, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x15, 0x00,0x1E, 0xF5,0x9F,
+-0x28,0x00, 0xF3,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0xA2, 0x00,0x1C, 0xF5,0x84,
+-0xE0,0x04, 0x73,0x99, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
+-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xCC, 0x23,0x94, 0x00,0x42, 0x95,0xA2,
+-0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96,
+-0xFF,0xB4, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96, 0xFF,0xC4, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A,
+-0x00,0x00, 0xC4,0xA0, 0x4A,0x00, 0x74,0xA4, 0xFF,0xFA, 0xC5,0xA4, 0x00,0x00, 0xF5,0x9F,
+-0x28,0x00, 0x83,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x85,0x96, 0xFF,0xB4, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xCC, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x96, 0xFF,0xC4, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82,
+-0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x04,0x20, 0x00,0x18, 0x25,0x94, 0x00,0x22, 0x85,0xAE,
+-0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD,
+-0xFF,0xF0, 0x83,0x96, 0xFF,0xD4, 0xF5,0xA3, 0x28,0x00, 0xF4,0x9F, 0x28,0x00, 0x25,0x94,
+-0x00,0x42, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC,
+-0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x44,0xAD, 0x00,0x00, 0x94,0x93, 0xFF,0xFC, 0xF7,0x86,
+-0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x40,0x84, 0xF7,0x86,
+-0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x04, 0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x87,0x3A, 0x1D,0xDC, 0x00,0x00,
+-0x00,0x01, 0xF7,0x05, 0x3B,0x64, 0xF5,0x86, 0x36,0x78, 0xF5,0x85, 0x42,0x44, 0xF3,0x86,
+-0x35,0x60, 0xF3,0x85, 0x42,0x30, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x78,0x89, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xEE,0x00, 0x78,0x51, 0xF6,0x06, 0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x78,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85,
+-0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+-0x37,0x90, 0xF5,0x85, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF6,0x06, 0x36,0x78, 0xF6,0x05, 0x42,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
+-0x40,0x80, 0xF7,0x05, 0x40,0x94, 0xF6,0x84, 0x6E,0x50, 0xF7,0x05, 0x40,0x90, 0x97,0x36,
+-0x1D,0xDC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
+-0x00,0x01, 0xF7,0x05, 0x40,0x80, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0xA8, 0xF7,0x04, 0x42,0x50, 0xF5,0x86, 0x42,0x50, 0x76,0xAD,
+-0x00,0x1E, 0xF4,0x84, 0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xC4, 0xC7,0x38,
+-0x6F,0xC0, 0x86,0xA6, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x79,0x55, 0xF6,0x06, 0x42,0x9A, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0xF7,0x04, 0x42,0x50, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16,
+-0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0xAA, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x80,0xA8, 0xF6,0x06, 0x42,0x9A, 0x87,0x2A, 0x00,0x10, 0x86,0x2A,
+-0x00,0x1C, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xA8, 0xF6,0x82, 0x00,0x00, 0x87,0x2A,
+-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xAC, 0x20,0x36,
+-0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x7A,0x05, 0x24,0x94,
+-0x00,0x20, 0x94,0x96, 0xFF,0xBC, 0x85,0x16, 0xFF,0xC4, 0xF0,0x27, 0x28,0x00, 0x05,0x28,
+-0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+-0xFF,0xFC, 0x85,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x80,0xC4, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x80,0x6C, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
+-0x28,0x00, 0x04,0xA0, 0x00,0x02, 0x94,0x96, 0xFF,0x5C, 0xF0,0x27, 0x28,0x00, 0xF4,0x82,
+-0x00,0x00, 0x25,0x14, 0x00,0x5A, 0xF4,0xAB, 0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x25,0x14,
+-0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28,
+-0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x23,0x14,
+-0x00,0x1E, 0x76,0x19, 0x00,0x1E, 0xF5,0x3B, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x76,0x30,
+-0xFF,0xE5, 0x94,0xA2, 0x00,0x1C, 0xF5,0x04, 0xE0,0x04, 0x84,0x96, 0xFF,0x5C, 0x95,0x22,
+-0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+-0xFF,0x9C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x74,0x95,
+-0x00,0x1E, 0x85,0x16, 0xFF,0x5C, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x8C, 0x84,0x96,
+-0xFF,0x54, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x94, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
+-0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF5,0x3B,
+-0x28,0x00, 0x94,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
+-0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x24,0x94, 0x00,0x5A, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x05,0xA0,
+-0x00,0x02, 0x06,0xAC, 0x00,0x02, 0x23,0x94, 0x00,0x36, 0x75,0x1D, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x07,0x20, 0x00,0x1A, 0xF4,0xB3, 0x28,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+-0xFF,0x5C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x74,0x95,
+-0x00,0x1E, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x74, 0x85,0x2A,
+-0x00,0x34, 0x24,0x94, 0x00,0x5A, 0x95,0x16, 0xFF,0x84, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x25,0x14,
+-0x00,0x5A, 0xF4,0xAF, 0x28,0x00, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
+-0x28,0x00, 0x84,0xA6, 0x00,0x10, 0x85,0x16, 0xFF,0xC4, 0x94,0xA2, 0x00,0x1C, 0x85,0x2A,
+-0x00,0x14, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x6C, 0x95,0x22,
+-0x00,0x20, 0x87,0x16, 0xFF,0xC8, 0x85,0x16, 0xFF,0x54, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x84,0x96, 0xFF,0x5C, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0xCC, 0x23,0x94, 0x00,0x32, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x85,0x16,
+-0xFF,0x7C, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD0, 0x23,0x94, 0x00,0x2E, 0x76,0x1D,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x74, 0x85,0x16,
+-0xFF,0x6C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x23,0x94, 0x00,0x2A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x16, 0xFF,0xD8, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3, 0x28,0x00, 0x07,0x20,
+-0x00,0x18, 0x25,0x14, 0x00,0x7A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
+-0x28,0x00, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xF7,0x04,
+-0x4F,0x58, 0xE6,0x00, 0x7E,0xF9, 0x94,0x16, 0xFF,0x54, 0xC7,0x20, 0x72,0x00, 0xF6,0x84,
+-0x6E,0x50, 0x86,0x26, 0x00,0x2C, 0x77,0x38, 0xFF,0xFA, 0x25,0x14, 0x00,0x5A, 0x84,0x2A,
+-0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0x20, 0x7F,0xC0, 0x74,0x21,
+-0xFF,0xF0, 0x47,0x39, 0x00,0x00, 0x86,0xB6, 0x1D,0xDC, 0x77,0x39, 0x00,0x02, 0xC0,0x32,
+-0x6A,0x00, 0x46,0x8C, 0x00,0x01, 0xD6,0x80, 0x0A,0x68, 0x20,0x36, 0x00,0x00, 0xF6,0x86,
+-0x40,0x98, 0xE6,0x00, 0x7E,0xC0, 0xC3,0xB8, 0x68,0x00, 0xC5,0x84, 0x00,0x00, 0x86,0xA6,
+-0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x7E,0x54, 0x03,0x24, 0x00,0x24, 0x86,0xA6, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x7E,0x58, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0x65, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+-0x00,0x00, 0x86,0x9A, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0x7E,0xA0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x7E,0xA8, 0x20,0x32, 0x00,0x00, 0x86,0x9A, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x7E,0xA9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0xB9, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x7E,0xC5, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
+-0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x1F, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0x85,0x16,
+-0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x2A,
+-0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
+-0x7F,0x4C, 0xF6,0x3B, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0xF6,0x06, 0x40,0x98, 0xC7,0x24,
+-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0xB8, 0x00,0x00, 0x46,0xB5, 0x00,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x37, 0x28,0x00, 0x47,0x39,
+-0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x24,0x94, 0x00,0x5A, 0x84,0xA6,
+-0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x85,0x16,
+-0xFF,0x54, 0x84,0x96, 0xFF,0xAC, 0xC6,0xA8, 0x72,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x24,
+-0x00,0x1A, 0xF6,0xB3, 0x28,0x00, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x06,0xA8,
+-0x00,0x1A, 0xF7,0x37, 0x28,0x00, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24,
+-0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x72,0x00, 0x77,0x38,
+-0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x1C, 0x97,0x13,
+-0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x1D,0xDC, 0x87,0x36,
+-0x1D,0xDC, 0xF0,0x05, 0x40,0x84, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0xF7,0x04,
+-0x6E,0x50, 0xF0,0x05, 0x42,0x5C, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x86, 0x2C,0x28, 0xF7,0x05,
+-0x3B,0x64, 0xF7,0x04, 0x2D,0x38, 0xF5,0x06, 0x3A,0x4C, 0xF5,0x05, 0x42,0x44, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x1C, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x80,0x60, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06,
+-0x35,0xEC, 0xE0,0x00, 0x80,0x8C, 0xF5,0x05, 0x42,0x30, 0x20,0x32, 0x00,0x01, 0xE6,0x00,
+-0x80,0xC4, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+-0xFF,0xFC, 0xF4,0x86, 0x35,0x60, 0xF4,0x85, 0x42,0x30, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0x80,0xC4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86,
+-0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x81,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x81,0x29, 0xF6,0x06,
+-0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0x81,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85, 0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0xF5,0x85, 0x42,0x44, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x58, 0xF7,0x04,
+-0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04,
+-0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x82,0x50, 0xF4,0x82, 0x00,0x00, 0xC5,0x04, 0x00,0x00, 0x86,0xB2,
+-0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xC5,0xA4, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x81,0xE4, 0x04,0x30, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x81,0xE8, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x81,0xF5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
+-0x00,0x00, 0x86,0xA2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0x82,0x30, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0x82,0x38, 0x20,0x32, 0x00,0x00, 0x86,0xA2, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x82,0x39, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x82,0x49, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
+-0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x82,0x59, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
+-0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x87,0x60, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
+-0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x05, 0x3B,0xB0, 0x06,0xA0, 0x00,0x14, 0xC7,0x20,
+-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x16, 0xF7,0x37,
+-0x28,0x00, 0xF3,0x02, 0x00,0x01, 0xF3,0x23, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0,
+-0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF3,0x02, 0x00,0x00, 0x23,0x94, 0x00,0x2A, 0xF3,0x1F,
+-0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0xF3,0xBB,
+-0x28,0x00, 0xF3,0x04, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0x22, 0x00,0x1C, 0xF3,0x84,
+-0xE0,0x04, 0x23,0x14, 0x00,0x1E, 0x93,0x16, 0xFF,0xA4, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
+-0xFF,0xA4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
+-0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96,
+-0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x94, 0x00,0x1A, 0x93,0x96, 0xFF,0xA4, 0x76,0x1D,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
+-0x00,0x16, 0x93,0x16, 0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xAC, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x93,0x16,
+-0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xCC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16,
+-0xFF,0xF0, 0x83,0x16, 0xFF,0xC4, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82, 0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x23,0x14,
+-0x00,0x2A, 0x83,0x1A, 0x00,0x00, 0x77,0x99, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18,
+-0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF3,0x3B, 0x28,0x00, 0x94,0x16,
+-0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20,
+-0x00,0x02, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x24,0x80, 0x00,0x07, 0x05,0x20,
+-0x00,0x0A, 0xF3,0xBB, 0x28,0x00, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x84,0xE0, 0x06,0x28,
+-0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1,
+-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4, 0x00,0x01, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3,
+-0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0xC7,0x38, 0x34,0x00, 0xE0,0x00, 0x84,0x88, 0xF7,0x33, 0x28,0x00, 0x05,0x20,
+-0x00,0x26, 0x86,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0xF5,0x84, 0x4F,0x58, 0x76,0xB4,
+-0xFF,0xE5, 0x83,0x96, 0xFF,0xDC, 0xF3,0x02, 0x00,0xFF, 0x94,0x16, 0xFF,0xBC, 0xC7,0x1C,
+-0x5A,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
+-0x00,0x00, 0xC7,0x38, 0x34,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30, 0x6C,0x00, 0xC7,0x38,
+-0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2B, 0x28,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
+-0xFF,0xFA, 0x83,0x16, 0xFF,0xDC, 0x07,0x34, 0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x20,
+-0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x20, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x82,
+-0x00,0x03, 0xF3,0xA3, 0x28,0x00, 0x07,0x18, 0x00,0x1A, 0xF5,0xBB, 0x28,0x00, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
+-0x28,0x00, 0x24,0x80, 0x00,0x07, 0x05,0x20, 0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00,
+-0x85,0xD4, 0x06,0x28, 0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4,
+-0x00,0x01, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
+-0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x82, 0x00,0xFF, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xE0,0x00, 0x85,0x7C, 0xF7,0x33,
+-0x28,0x00, 0x05,0xA0, 0x00,0x26, 0x86,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC5,0x20, 0x00,0x00, 0x24,0x00, 0x00,0x07, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
+-0xFF,0xA4, 0xF7,0x04, 0x4F,0x58, 0x83,0x96, 0xFF,0xBC, 0x24,0x80, 0x00,0x0E, 0xC7,0x1C,
+-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
+-0x00,0x00, 0xF6,0x82, 0x00,0xFF, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30,
+-0x6C,0x00, 0xC7,0x38, 0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2F, 0x28,0x00, 0x07,0x34,
+-0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x28, 0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x28,
+-0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x02, 0x00,0x03, 0xF3,0x2B, 0x28,0x00, 0x20,0x22,
+-0x00,0x07, 0xEE,0x00, 0x86,0x94, 0xC6,0x28, 0x48,0x00, 0x06,0x30, 0x00,0x26, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x04,0x20,
+-0x00,0x01, 0x83,0x96, 0xFF,0xA4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82,
+-0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC7,0x1C, 0x70,0x00, 0xE0,0x00, 0x86,0x50, 0xF7,0x33,
+-0x28,0x00, 0x06,0x28, 0x00,0x26, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
+-0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0xF3,0x04, 0x3B,0xB0, 0x00,0x00,
+-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xB4, 0xF0,0x05, 0x40,0x7C, 0x83,0x96,
+-0xFF,0xBC, 0x23,0x00, 0x00,0x07, 0xF3,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x50, 0xF6,0x06,
+-0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x39,0x34, 0xF3,0x05,
+-0x42,0x44, 0xF5,0x05, 0x40,0x74, 0xF3,0x85, 0x42,0x60, 0xF3,0x82, 0x00,0x06, 0xF3,0x85,
+-0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06,
+-0x2C,0x28, 0x76,0xB5, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0x87,0x4C, 0xB3,0xB6, 0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x06, 0x42,0x44, 0x93,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x48, 0xF3,0x86,
+-0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x89,0xED, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x87,0xC9, 0x00,0x00,
+-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0x89,0xEC, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
+-0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x05,0xA0, 0x00,0x02, 0xF0,0x2F,
+-0x28,0x00, 0xF3,0x82, 0x00,0x00, 0x24,0x94, 0x00,0x22, 0xF3,0xA7, 0x28,0x00, 0x04,0xA0,
+-0x00,0x1A, 0x94,0x96, 0xFF,0xD4, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xAC, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x19,
+-0x00,0x1E, 0xF3,0xA7, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x94,0xA2,
+-0x00,0x1C, 0xF3,0x84, 0xE0,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+-0xFF,0xB4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xCC, 0x84,0x96,
+-0xFF,0xB4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
+-0xFF,0xE5, 0x93,0x96, 0xFF,0xBC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
+-0xFF,0xC4, 0x83,0x96, 0xFF,0xBC, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F,
+-0x28,0x00, 0xF5,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
+-0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x45,0xAD, 0x00,0x00, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0xCC, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+-0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
+-0x28,0x00, 0x04,0x20, 0x00,0x18, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x84,0x96,
+-0xFF,0xD4, 0xF3,0xA3, 0x28,0x00, 0xF3,0x82, 0x00,0x01, 0xF3,0xA7, 0x28,0x00, 0x95,0x93,
+-0xFF,0xFC, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x86,
+-0x36,0x78, 0xF4,0x85, 0x42,0x44, 0xF0,0x05, 0x40,0x84, 0xF6,0x84, 0x4F,0x5C, 0xF7,0x02,
+-0x00,0x64, 0x97,0x36, 0x00,0x00, 0x90,0x36, 0x00,0x04, 0xF7,0x02, 0x00,0x01, 0xF7,0x05,
+-0x40,0x84, 0xF3,0x86, 0x35,0xEC, 0xF3,0x85, 0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF7,0x04, 0x42,0x60, 0xF5,0x02,
+-0x00,0x00, 0x05,0xB8, 0x00,0x18, 0xF6,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+-0x00,0x07, 0xEE,0x00, 0x8A,0x70, 0xC7,0x30, 0x60,0x00, 0xC7,0x38, 0x58,0x00, 0x07,0x38,
+-0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0xC0,0x36,
+-0x52,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x8A,0x71, 0x07,0x30, 0x00,0x01, 0xE0,0x00, 0x8A,0x18, 0xF7,0x05, 0x42,0x58, 0xF4,0x04,
+-0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x07, 0xEE,0x00, 0x8D,0x94, 0x24,0x94,
+-0x00,0x36, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x38, 0x23,0x94, 0x00,0x20, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
+-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
+-0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
+-0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0x7C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x7E, 0x25,0x14, 0x00,0x80, 0x23,0x94,
+-0x00,0x68, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7C, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7A, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x78, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x76, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x74, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x72, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0x74, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x42,0x58, 0x23,0x94, 0x00,0x50, 0xC7,0x00, 0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0x6C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0x6C, 0xF6,0x86, 0x42,0x50, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
+-0x42,0x58, 0x76,0xB5, 0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x8D,0x95, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00,
+-0x8D,0xD4, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0x8D,0xF4, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x8D,0xF4, 0xF0,0x05,
+-0x2D,0x38, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86,
+-0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x88, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0xF3,0x84,
+-0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x93,0x96, 0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0x9E,
+-0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x8E,0x65, 0xF6,0x06,
+-0x42,0xA0, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x94,0xE4, 0xF7,0x33,
+-0x28,0x00, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x36, 0x85,0x16, 0xFF,0xC4, 0x23,0x94,
+-0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x85,0x2A, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x95,0x16, 0xFF,0xBC, 0xF7,0x1F, 0x28,0x00, 0x87,0x32,
+-0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x85,0x16, 0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
+-0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14, 0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00,
+-0x00,0x01, 0x87,0x1E, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0x8F,0xF0, 0xF6,0x82, 0x00,0x00, 0x87,0x1E, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0x8F,0xF4, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0x90,0x41, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xC4, 0x00,0x00,
+-0x00,0x01, 0x05,0x28, 0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x27,0x14,
+-0x00,0x20, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16,
+-0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x94,0xBC, 0x00,0x00,
+-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x02,
+-0x00,0x00, 0x23,0x94, 0x00,0x62, 0xF5,0x1F, 0x28,0x00, 0x75,0x95, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0x06,0x20, 0x00,0x02, 0x06,0xB0, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x73,0x99,
+-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x74, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
+-0xFF,0x8C, 0x85,0x16, 0xFF,0xC4, 0x73,0x95, 0x00,0x1E, 0x93,0x96, 0xFF,0x84, 0x85,0x2A,
+-0x00,0x34, 0x23,0x94, 0x00,0x62, 0x95,0x16, 0xFF,0xAC, 0xF0,0x33, 0x28,0x00, 0x05,0x20,
+-0x00,0x1A, 0x95,0x16, 0xFF,0x94, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x74,0x95, 0x00,0x1E, 0xF3,0xAB,
+-0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x85,0x2A, 0x00,0x10, 0x83,0x96,
+-0xFF,0xC4, 0x95,0x22, 0x00,0x1C, 0x83,0x9E, 0x00,0x14, 0x85,0x16, 0xFF,0x84, 0x93,0xA2,
+-0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x84, 0xF3,0x84,
+-0x4F,0x58, 0x85,0x16, 0xFF,0x74, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96, 0xFF,0xA4, 0xC0,0x22, 0x3A,0x00, 0x83,0x96,
+-0xFF,0x7C, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0x83,0x96,
+-0xFF,0x84, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF5,0x02, 0x00,0x02, 0xF5,0x23, 0x28,0x00, 0x23,0x94,
+-0x00,0x52, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
+-0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x03,0x20, 0x00,0x18, 0xE6,0x00, 0x92,0x30, 0xF3,0x9B,
+-0x28,0x00, 0xF7,0x04, 0x42,0x70, 0xE0,0x00, 0x92,0x9C, 0xF6,0x06, 0x42,0x72, 0x85,0x16,
+-0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0xAA, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x07,0x34,
+-0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00, 0x92,0x94, 0xC7,0x34, 0x68,0x00, 0xF5,0x84,
+-0x42,0x60, 0xF3,0x82, 0x00,0xFF, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+-0x00,0x00, 0x97,0x16, 0xFF,0x74, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x3C,0x00, 0x20,0x36, 0x00,0x00, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x92,0xC9, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x42,0x74, 0xF6,0x06, 0x42,0x74, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xA4, 0x83,0x96, 0xFF,0x74, 0xC7,0x20,
+-0x52,0x00, 0x74,0xB8, 0xFF,0xFA, 0xC6,0x24, 0x00,0x00, 0x87,0x1E, 0x00,0x00, 0x76,0x9D,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x52,0x00, 0x75,0xAC, 0xFF,0xFA, 0x46,0x31,
+-0x00,0x00, 0xF5,0x02, 0x00,0xFF, 0xC6,0x30, 0x54,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x1F,
+-0x28,0x00, 0x83,0x96, 0xFF,0x94, 0x85,0x16, 0xFF,0xC4, 0xF5,0x9F, 0x28,0x00, 0x87,0x2A,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xE6,0x00, 0x94,0x69, 0xF6,0x86,
+-0x40,0x98, 0xF7,0x04, 0x6E,0x50, 0x86,0x2A, 0x00,0x2C, 0xC6,0xA4, 0x00,0x00, 0x23,0x94,
+-0x00,0x62, 0x84,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4,
+-0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x46,0xB5, 0x00,0x00, 0x87,0x3A, 0x1D,0xDC, 0x76,0xB5,
+-0x00,0x02, 0xC0,0x32, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
+-0x00,0x00, 0xF7,0x06, 0x40,0x98, 0xE6,0x00, 0x94,0x34, 0xC3,0x34, 0x70,0x00, 0xC5,0x84,
+-0x00,0x00, 0x86,0xAA, 0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0x05,0x28, 0x00,0x24, 0xE6,0x00, 0x93,0xC4, 0x95,0x16, 0xFF,0x74, 0x83,0x96,
+-0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0x9E, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x93,0xC8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x93,0xD5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+-0x00,0x00, 0x85,0x16, 0xFF,0x74, 0xF7,0x04, 0xE0,0x00, 0x86,0xAA, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x14, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0x94,0x1C, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x1D, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x94,0x2D, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x94,0x39, 0x00,0x00,
+-0x00,0x01, 0xF4,0x82, 0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x9B, 0x28,0x00, 0x83,0x96,
+-0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x1E,
+-0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
+-0x94,0xE4, 0xF6,0x3B, 0x28,0x00, 0x47,0x25, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
+-0x68,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0x23,0x94,
+-0x00,0x62, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
+-0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x25,0x14, 0x00,0x62, 0xF3,0xBB, 0x28,0x00, 0x85,0x2A,
+-0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29,
+-0xFF,0xF0, 0xE0,0x00, 0x94,0xE4, 0xF5,0x1B, 0x28,0x00, 0x83,0x96, 0xFF,0xBC, 0x00,0x00,
+-0x00,0x01, 0x20,0x1E, 0x00,0x01, 0xE6,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x35,0x60, 0xF5,0x05,
+-0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x06,
+-0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x96,0x89, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
+-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEE,0x00, 0x95,0x8D, 0xF5,0x86,
+-0x42,0x50, 0xF7,0x04, 0x42,0x50, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x26,0xB4,
+-0x00,0x01, 0xF6,0x85, 0x42,0x54, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF6,0x84,
+-0x2D,0x38, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x2F,
+-0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
+-0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x96,0x88, 0xB5,0x36,
+-0x70,0x02, 0xE0,0x00, 0x96,0x88, 0xF0,0x05, 0x2D,0x38, 0xF5,0x04, 0x42,0x60, 0x00,0x00,
+-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB2,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x34, 0x00,0x40, 0xC0,0x22,
+-0x72,0x00, 0xE6,0x00, 0x95,0xEC, 0xF6,0x06, 0x42,0x76, 0xF7,0x04, 0x42,0x74, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x60, 0x00,0x00,
+-0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00, 0x96,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0xF5,0x04, 0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x40, 0x00,0x00,
+-0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE6,0x00, 0x96,0x71, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04,
+-0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF5,0x04,
+-0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xC1,0xB4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x70, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x9B,0x18, 0x06,0xB0,
+-0x00,0x02, 0x87,0x36, 0x00,0x00, 0xF4,0x04, 0x40,0x7C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00,
+-0x9B,0x18, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x23,0x94, 0x00,0x38, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
+-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
+-0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14,
+-0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04,
+-0x40,0x74, 0x94,0x16, 0xFF,0xC4, 0x07,0x20, 0x00,0x02, 0xF0,0x3B, 0x28,0x00, 0x24,0x80,
+-0x00,0x07, 0xF4,0x02, 0x00,0xFF, 0x83,0x96, 0xFF,0xC4, 0x95,0x16, 0xFF,0xBC, 0x03,0x1C,
+-0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x98,0xA8, 0x06,0x18, 0x00,0x0E, 0x86,0xB2,
+-0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+-0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x04,0xA4,
+-0x00,0x01, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x44,0x00, 0xE0,0x00,
+-0x98,0x54, 0xF7,0x33, 0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
+-0xFF,0xE5, 0x83,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x1E, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
+-0xFF,0xE5, 0x05,0x28, 0x00,0x26, 0x95,0x16, 0xFF,0x8C, 0x85,0xAA, 0x00,0x00, 0x76,0xA9,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x03,0x9C, 0x00,0x02, 0x93,0x96, 0xFF,0xB4, 0x06,0x1C,
+-0x00,0x02, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
+-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x9C, 0x83,0x96, 0xFF,0xBC, 0x75,0x15,
+-0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x95,0x16, 0xFF,0xA4, 0x85,0x16, 0xFF,0xC4, 0xC5,0xAC, 0x6F,0xC0, 0x75,0xAD,
+-0xFF,0xF0, 0xF5,0x05, 0x42,0x60, 0xF5,0x04, 0x4F,0x58, 0xF6,0x82, 0x00,0xFF, 0xC7,0x1C,
+-0x52,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82,
+-0xFF,0x00, 0xC5,0xAC, 0x6C,0x00, 0xC7,0x38, 0x58,0x00, 0x83,0x96, 0xFF,0x8C, 0xF5,0x84,
+-0x3B,0x6C, 0x85,0x16, 0xFF,0xB4, 0xF7,0x1F, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x06,0xAC,
+-0x00,0x01, 0xF6,0x85, 0x3B,0x6C, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xF5,0x04, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC0,0x1E,
+-0x52,0x00, 0xC7,0x38, 0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
+-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x99, 0x00,0x1E, 0x83,0x96,
+-0xFF,0x94, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
+-0x00,0x16, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16, 0xFF,0xAC, 0x83,0x96,
+-0xFF,0xA4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x06,0x30, 0x00,0x02, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14,
+-0x00,0x12, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0x83,0x96,
+-0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16,
+-0xFF,0xF0, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+-0x28,0x00, 0x07,0x1C, 0x00,0x3A, 0xF5,0xBB, 0x28,0x00, 0x07,0x1C, 0x00,0x36, 0xF0,0x3B,
+-0x28,0x00, 0xF5,0x02, 0x00,0x03, 0xE6,0x00, 0x9A,0xA4, 0xF5,0x1F, 0x28,0x00, 0xF7,0x04,
+-0x42,0x78, 0xF6,0x06, 0x42,0x78, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9B,0x18, 0x00,0x00,
+-0x00,0x01, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF7,0x04,
+-0x42,0x50, 0xF6,0x06, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x82,
+-0x00,0x06, 0xF3,0x85, 0x42,0x54, 0xF5,0x06, 0x39,0x34, 0xF5,0x05, 0x42,0x44, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
+-0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x9B,0x18, 0xB3,0xB6,
+-0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x78, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0x9E,0x41, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xEE,0x00, 0x9D,0x85, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14,
+-0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
+-0xFF,0x94, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94,
+-0x00,0x68, 0x93,0x96, 0xFF,0x8C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x84, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
+-0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x84, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0x9D,0x5D, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
+-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00,
+-0x00,0x01, 0xF5,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC7,0x28, 0x50,0x00, 0xC7,0x24,
+-0x70,0x00, 0x05,0xB8, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xE6,0x00,
+-0x9D,0xFD, 0xF6,0x02, 0x00,0xFF, 0xF7,0x04, 0x42,0x78, 0xF6,0x06, 0x42,0x7A, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+-0x00,0x01, 0xC7,0x38, 0x64,0x00, 0xF6,0x02, 0xFF,0x00, 0xC6,0xB4, 0x64,0x00, 0xC7,0x38,
+-0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0x07,0x28, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x94,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xD8, 0xF3,0x86,
+-0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA2,0xC9, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xA0,0x35, 0x24,0x94,
+-0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14, 0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1,
+-0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32,
+-0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
+-0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96, 0xFF,0x4C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x44, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
+-0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x44, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xA2,0x80, 0x93,0x93,
+-0xFF,0xFC, 0xF4,0x04, 0x40,0x7C, 0xF6,0x04, 0x40,0x74, 0xF3,0x82, 0x00,0x00, 0xC7,0x20,
+-0x40,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E,
+-0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xA0,0xAD, 0x93,0x96, 0xFF,0x3C, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06, 0x42,0xA0, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0xA2,0xC8, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x7E, 0x25,0x14,
+-0x00,0x80, 0x23,0x94, 0x00,0x68, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
+-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+-0x00,0x7C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+-0x00,0x7A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+-0x00,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+-0x00,0x76, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+-0x00,0x74, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+-0x00,0x72, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13,
+-0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x34, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0xB0, 0x93,0x96, 0xFF,0x2C, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0x2C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x3C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x98, 0x93,0x96, 0xFF,0x24, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+-0x00,0x06, 0xF3,0x85, 0x42,0x54, 0x87,0x02, 0xFF,0x34, 0xF3,0x86, 0x38,0xA8, 0xF3,0x85,
+-0x42,0x44, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0xA2,0xA9, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
+-0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xA3,0xAC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
+-0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0xF6,0x84,
+-0x40,0x7C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0xA3,0xAC, 0xC7,0x34,
+-0x68,0x00, 0xF5,0x84, 0x40,0x74, 0xF6,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC6,0x2C,
+-0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0xAC, 0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
+-0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02,
+-0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0xF5,0x06,
+-0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0xF5,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x80, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA3,0xF4, 0x20,0x3A, 0x00,0x07, 0xF5,0x02,
+-0x00,0x01, 0xF5,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x07, 0xEE,0x00, 0xA6,0xF0, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x23,0x14,
+-0x00,0x66, 0xF4,0x84, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x74,0x25, 0x00,0x1E, 0x74,0x20,
+-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16,
+-0xFF,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x25,0x14, 0x00,0x20, 0x95,0x16,
+-0xFF,0x94, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x85,0x16, 0xFF,0x7C, 0x05,0xA4,
+-0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
+-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x25,0x14, 0x00,0x50, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
+-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+-0x00,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+-0x00,0x62, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+-0x00,0x60, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+-0x00,0x5E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+-0x00,0x5C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+-0x00,0x5A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x05,0xAC,
+-0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x58, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
+-0xFF,0xFC, 0x95,0x16, 0xFF,0x8C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+-0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x25,0x14,
+-0x00,0x38, 0x95,0x16, 0xFF,0x84, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+-0xFF,0xFC, 0xF5,0x04, 0x42,0x64, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
+-0xFF,0x84, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16, 0xFF,0x94, 0x00,0x00,
+-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA6,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04,
+-0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00, 0xA7,0x30, 0xF5,0x02,
+-0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+-0xA7,0x50, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00, 0xA7,0x50, 0xF0,0x05, 0x2D,0x38, 0x95,0x13,
+-0xFF,0xFC, 0xF5,0x02, 0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0xF6,0x04,
+-0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0xA9,0xF0, 0x07,0x30, 0x00,0x02, 0x86,0x3A, 0x00,0x00, 0xF5,0x82,
+-0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x30,
+-0x77,0xC0, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0x76,0x31, 0xFF,0xF0, 0xC6,0x00,
+-0x62,0x00, 0x96,0x16, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
+-0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0xA8,0x34, 0xF6,0x02, 0x00,0xFF, 0x83,0x16, 0xFF,0xF4, 0x83,0x96,
+-0xFF,0xF4, 0xF7,0x04, 0x40,0x78, 0xC6,0x98, 0x38,0x00, 0xC7,0x38, 0x68,0x00, 0x07,0x38,
+-0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x64,0x00, 0xC0,0x36, 0x5A,0x00, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA8,0x3D, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xA8,0x75, 0xF6,0x06,
+-0x42,0x7C, 0xF7,0x04, 0x42,0x7C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xA9,0xF0, 0x00,0x00,
+-0x00,0x01, 0xF3,0x04, 0x42,0x60, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF4,0x04, 0x40,0x78, 0xF7,0x04,
+-0x4F,0x58, 0xF5,0x04, 0x40,0x74, 0xF3,0x84, 0x40,0x7C, 0xF3,0x04, 0x40,0x7C, 0xC6,0x20,
+-0x72,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0x9C, 0x30,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC,
+-0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x74,0xAD, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x73,0xAD,
+-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xD4, 0xC5,0x28, 0x72,0x00, 0x75,0x28,
+-0xFF,0xFA, 0x83,0x16, 0xFF,0xF4, 0x83,0x96, 0xFF,0xF4, 0x46,0x31, 0x00,0x00, 0x45,0x29,
+-0x00,0x00, 0xC7,0x18, 0x38,0x00, 0xC4,0x20, 0x70,0x00, 0x04,0x20, 0x00,0x26, 0x73,0x21,
+-0x00,0x1E, 0xC6,0xB4, 0x4F,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC6,0x30,
+-0x4C,0x00, 0xF3,0x82, 0xFF,0x00, 0xC6,0xB4, 0x3C,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
+-0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
+-0xFF,0xD4, 0x83,0x96, 0xFF,0xF4, 0xC5,0x28, 0x4C,0x00, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x76,0x9D, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4,
+-0x70,0x00, 0xF6,0xAF, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x83,0x16,
+-0xFF,0xCC, 0xF3,0x82, 0xFF,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x23, 0x28,0x00, 0x87,0x22,
+-0x00,0x00, 0xF3,0x04, 0x40,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19,
+-0x00,0x10, 0x93,0x16, 0xFF,0xEC, 0x73,0x99, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC7,0x1C,
+-0x70,0x00, 0x97,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x83,0x1A, 0x00,0x00, 0x77,0x99,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18, 0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0xF3,0x23,
+-0x28,0x00, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x98, 0xF3,0x06,
+-0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xAE,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xAD,0x89, 0x27,0x38,
+-0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x24,0x94,
+-0x00,0x66, 0x94,0x96, 0xFF,0x64, 0xF3,0x04, 0x40,0x78, 0x24,0x94, 0x00,0x20, 0x94,0x96,
+-0xFF,0x94, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0x93,0x16, 0xFF,0x74, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
+-0xFF,0xE5, 0x05,0x98, 0x00,0x02, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28,
+-0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
+-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x85,0x16, 0xFF,0x64, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+-0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
+-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14,
+-0x00,0x64, 0x93,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x24,0x94, 0x00,0x62, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
+-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x25,0x14, 0x00,0x60, 0x95,0x16, 0xFF,0x64, 0x05,0xAC,
+-0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
+-0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x24,0x94,
+-0x00,0x5C, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x95,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
+-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x50, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x58, 0x05,0xAC,
+-0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x93,0x16, 0xFF,0x64, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
+-0xFF,0xFC, 0x94,0x96, 0xFF,0x8C, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x23,0x14, 0x00,0x38, 0x95,0x13,
+-0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x93,0x16, 0xFF,0x84, 0x93,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x27,0x80,
+-0x00,0x07, 0xF7,0x85, 0x42,0x58, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84,
+-0x42,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x84, 0x00,0x00,
+-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xAD,0x5D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+-0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xAE,0xE4, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+-0xAE,0xE4, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x40,0x78, 0xF5,0x84, 0x4F,0x58, 0x07,0x38,
+-0x00,0x16, 0x86,0xBA, 0x00,0x00, 0xF4,0x06, 0x3B,0x90, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x76,0x35, 0x00,0x06, 0xA7,0x2E,
+-0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38,
+-0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x73,0xB7, 0xFF,0xF0, 0xEE,0x00, 0xAE,0x55, 0x95,0x16, 0xFF,0x64, 0xA7,0x2E,
+-0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x23,0x14,
+-0x00,0x88, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
+-0x00,0x08, 0x85,0x3A, 0x00,0x04, 0x84,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x1A,
+-0x00,0x04, 0x94,0x9A, 0x00,0x00, 0x85,0x96, 0xFF,0x7C, 0xE0,0x00, 0xAE,0x78, 0x00,0x00,
+-0x00,0x01, 0x84,0x96, 0xFF,0x64, 0xA7,0x2E, 0x60,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
+-0x40,0x00, 0x85,0xBA, 0x00,0x04, 0x85,0x16, 0xFF,0x64, 0xF6,0x06, 0x3B,0x90, 0x87,0x2A,
+-0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38,
+-0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00,
+-0xAE,0xC9, 0x76,0xB5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x78, 0x00,0x00, 0x00,0x01, 0x77,0x19,
+-0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0x84,0x96, 0xFF,0x64, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
+-0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x10, 0xF7,0x04, 0x40,0x84, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xAF,0x3C, 0xF6,0x06, 0x42,0xB8, 0xF7,0x04, 0x42,0xB8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF3,0x06, 0x36,0x78, 0xF3,0x05, 0x42,0x44, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x5C, 0xF3,0x84,
+-0x42,0x5C, 0x83,0x3A, 0x00,0x04, 0xC4,0x38, 0x00,0x00, 0x93,0x16, 0xFF,0xEC, 0x77,0x1D,
+-0x00,0x01, 0xC7,0x38, 0x38,0x00, 0x77,0x39, 0x00,0x02, 0x04,0xB8, 0x00,0x0C, 0x83,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00, 0xB0,0x70, 0xC5,0x04,
+-0x00,0x00, 0xA6,0xA2, 0x48,0x02, 0xF7,0x04, 0xE0,0x00, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0xAF,0xA8, 0xC6,0x20, 0x48,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xAF,0xAC, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xAF,0xB9, 0x00,0x00,
+-0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xF4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0xAF,0xFC, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
+-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xFD, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xB0,0x0D, 0x20,0x2A,
+-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xB0,0x59, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x7A,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xB0,0x64, 0xC7,0x20, 0x48,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x06, 0x40,0x98, 0x77,0x39,
+-0x00,0x02, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+-0xB0,0x64, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x0C, 0xE0,0x00, 0xAF,0x60, 0x03,0x9C,
+-0x00,0x01, 0x83,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00,
+-0xB1,0x04, 0xF3,0x06, 0x36,0x78, 0xF6,0x84, 0x4F,0x5C, 0x77,0x1D, 0x00,0x01, 0xC7,0x38,
+-0x38,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xC6,0xB4, 0x70,0x00, 0x87,0x36,
+-0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x96,0x93,
+-0xFF,0xFC, 0x93,0x96, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFA,0x98, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xF6,0x84, 0x42,0x6C, 0x83,0x96, 0xFF,0xF4, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0xC7,0x1C, 0x70,0x00, 0xF7,0x05, 0x42,0x5C, 0x06,0xB4,
+-0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x85, 0x42,0x6C, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x1C, 0x20,0x32,
+-0x00,0x44, 0xE6,0x00, 0xB1,0x08, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0xB1,0x08, 0xF0,0x05,
+-0x2D,0x38, 0xF3,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF4,0x02, 0x00,0x00, 0xC5,0xA0, 0x00,0x00, 0xF6,0x82, 0x07,0x70, 0xF7,0x04,
+-0x6E,0x50, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0xB1,0x6D, 0x06,0x38, 0x00,0x1C, 0x87,0x32,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC4,0x20, 0x70,0x00, 0xC0,0x22, 0x72,0x00, 0xE4,0x00,
+-0xB1,0x5D, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x01, 0x26,0xB4, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0xB1,0x40, 0x06,0x30, 0x00,0x04, 0xC4,0x20, 0x58,0x00, 0xC0,0x22,
+-0x5A,0x00, 0xE4,0x00, 0xB1,0x81, 0x00,0x00, 0x00,0x01, 0x04,0x20, 0x00,0x01, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB1,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x04, 0x40,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00,
+-0xB1,0xED, 0xF4,0x05, 0x40,0x90, 0xF7,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x86,0xBA,
+-0x1D,0xDC, 0xF5,0x82, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x96,0xBA, 0x1D,0xDC, 0x87,0x3A,
+-0x1D,0xDC, 0xE0,0x00, 0xB1,0xF0, 0xF5,0x85, 0x7A,0xD0, 0xF0,0x05, 0x7A,0xD0, 0xF5,0x84,
+-0x40,0x90, 0xF0,0x05, 0x40,0x84, 0xF5,0x85, 0x40,0x94, 0xF5,0x86, 0xE0,0x00, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x85,0xBA, 0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0xF5,0x85,
+-0x3B,0x64, 0xF5,0x84, 0xE0,0x00, 0xF0,0x05, 0x42,0x5C, 0x95,0xBA, 0x00,0x10, 0xF5,0x84,
+-0xE0,0x04, 0xF6,0x86, 0x2C,0x28, 0x95,0xBA, 0x00,0x14, 0xF7,0x04, 0x2D,0x38, 0xF5,0x86,
+-0x3A,0x4C, 0xF5,0x85, 0x42,0x44, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0xF5,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xB2,0x68, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86, 0x35,0xEC, 0xF5,0x85, 0x42,0x30, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xC8, 0xF3,0x02,
+-0x00,0x00, 0x93,0x16, 0xFF,0x94, 0x24,0x80, 0x00,0x08, 0x94,0x96, 0xFF,0x84, 0x23,0x80,
+-0x00,0x07, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0x54, 0x20,0x1E,
+-0x00,0x07, 0xEE,0x00, 0xB5,0x64, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84,
+-0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB3,0x2D, 0x20,0x36,
+-0x00,0x01, 0xE6,0x00, 0xB3,0x2D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38,
+-0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB3,0x31, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C,
+-0x00,0x00, 0xE0,0x00, 0xB3,0x30, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04,
+-0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB5,0x5D, 0x00,0x00,
+-0x00,0x01, 0xF6,0x84, 0x3B,0xBC, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFF,0x3C, 0x04,0x28,
+-0x00,0x1C, 0xF7,0x04, 0x3B,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
+-0xB4,0x40, 0x96,0x96, 0xFF,0xAC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
+-0x00,0x02, 0xF4,0x86, 0x3B,0xB4, 0xC6,0x38, 0x48,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x04,
+-0x00,0x00, 0x93,0x16, 0xFF,0x34, 0x86,0xB2, 0x00,0x00, 0x87,0x2A, 0x00,0x1C, 0x85,0x96,
+-0xFF,0x3C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0x86,0xB2,
+-0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+-0xB3,0xD1, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x34, 0x86,0xB2,
+-0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0xB4,0x0C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB4,0x14, 0x20,0x2E,
+-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0xB4,0x15, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0xB4,0x25, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
+-0xFF,0x34, 0x84,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+-0xB4,0x40, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0x3C, 0x84,0x96,
+-0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xB4,0x81, 0xF6,0x02,
+-0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06, 0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+-0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0xE0,0x00, 0xB4,0xF4, 0x96,0x96, 0xFF,0xB4, 0x27,0x14,
+-0x00,0x54, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0xF4,0x86, 0x3B,0xB4, 0x94,0x93,
+-0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xB4,0xF1, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06,
+-0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+-0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0x96,0x96,
+-0xFF,0xB4, 0xF7,0x05, 0x3B,0xBC, 0xE0,0x00, 0xB4,0xF8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xB5,0x2D, 0x27,0x14, 0x00,0x08, 0x84,0x96,
+-0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x83,0x16, 0xFF,0xB4, 0x04,0xA4,
+-0x00,0x04, 0x94,0x96, 0xFF,0x54, 0x84,0x96, 0xFF,0x94, 0x93,0x3A, 0xFF,0xC0, 0x04,0xA4,
+-0x00,0x01, 0xE0,0x00, 0xB5,0x54, 0x94,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0x54, 0x00,0x00,
+-0x00,0x01, 0xC7,0x18, 0x70,0x00, 0xF4,0x84, 0x4F,0x58, 0x03,0x18, 0x00,0x04, 0x93,0x16,
+-0xFF,0x54, 0x83,0x16, 0xFF,0x94, 0x94,0xBA, 0xFF,0xC0, 0x03,0x18, 0x00,0x01, 0x93,0x16,
+-0xFF,0x94, 0x95,0x16, 0xFF,0x3C, 0x93,0x96, 0xFF,0x8C, 0xE0,0x00, 0xB2,0xB0, 0x03,0x9C,
+-0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+-0xB5,0x84, 0xF3,0x82, 0x00,0x01, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x00,0x00,
+-0x00,0x01, 0x83,0x16, 0xFF,0xB8, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
+-0x4A,0x00, 0xEC,0x00, 0xB5,0xCC, 0x93,0x16, 0xFF,0x7C, 0x26,0x94, 0x00,0x04, 0x87,0x36,
+-0xFF,0xC0, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+-0xBB,0x98, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
+-0x4A,0x00, 0xEC,0x00, 0xB5,0xA1, 0x06,0xB4, 0x00,0x04, 0xF4,0x04, 0x4F,0x58, 0x83,0x16,
+-0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x42,0x00, 0xE6,0x00, 0xBA,0x2D, 0xF4,0x82,
+-0x00,0x00, 0x94,0x96, 0xFF,0x74, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
+-0xB7,0x48, 0xC7,0x1C, 0x38,0x00, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC7,0x18,
+-0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+-0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB6,0x69, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
+-0xB6,0x69, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
+-0x00,0x02, 0xE6,0x00, 0xB6,0x6D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
+-0xB6,0x6C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
+-0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB7,0x41, 0xC5,0x84, 0x00,0x00, 0x84,0x96,
+-0xFF,0x74, 0x86,0xAA, 0x00,0x1C, 0x83,0x16, 0xFF,0x3C, 0xF6,0x02, 0x00,0x00, 0x04,0xA4,
+-0x00,0x01, 0x94,0x96, 0xFF,0x74, 0x87,0x1A, 0x00,0x1C, 0x04,0xA8, 0x00,0x1C, 0x94,0x96,
+-0xFF,0x34, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB6,0xCC, 0x04,0x18, 0x00,0x1C, 0x86,0xAA,
+-0x00,0x20, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0xB6,0xD0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0xB6,0xDD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0x87,0x22,
+-0x00,0x00, 0x86,0x9A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0xB7,0x1C, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB7,0x24, 0x20,0x32,
+-0x00,0x00, 0x86,0x9A, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0xB7,0x25, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0xB7,0x35, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0xB7,0x40, 0x00,0x00, 0x00,0x01, 0x93,0x96, 0xFF,0x84, 0xE0,0x00,
+-0xB5,0xEC, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x74, 0x83,0x16, 0xFF,0x94, 0x00,0x00,
+-0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x00, 0x00,0x08, 0x84,0x96,
+-0xFF,0x84, 0x00,0x00, 0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x99, 0xF6,0x02,
+-0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0xC7,0x38,
+-0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x04, 0xF5,0x82,
+-0x00,0xFF, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
+-0x32,0x00, 0x84,0x96, 0xFF,0x7C, 0xC7,0x38, 0x70,0x00, 0xC7,0x24, 0x70,0x00, 0x07,0x38,
+-0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x5C,0x00, 0xC0,0x36, 0x62,0x00, 0x47,0x0C,
+-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x0D, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x80,
+-0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00, 0xB8,0xC8, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+-0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
+-0xB8,0x91, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xB8,0x91, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
+-0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
+-0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB8,0x95, 0xC6,0xB8,
+-0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00, 0xB8,0x94, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84,
+-0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00,
+-0xB8,0xC1, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00,
+-0xB8,0x14, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0xF3,0x84,
+-0x40,0x7C, 0xF5,0x04, 0x40,0x74, 0xC4,0xA4, 0x32,0x00, 0x94,0x96, 0xFF,0x34, 0x83,0x16,
+-0xFF,0x34, 0xC5,0x9C, 0x38,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
+-0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x74,0x2D, 0x00,0x1E, 0x74,0x20,
+-0xFF,0xE5, 0x73,0x9D, 0x00,0x10, 0x73,0x9D, 0xFF,0xF8, 0xC4,0xA4, 0x30,0x00, 0x94,0x96,
+-0xFF,0x3C, 0x83,0x16, 0xFF,0x7C, 0xC6,0xB4, 0x77,0xC0, 0xC4,0x98, 0x48,0x00, 0x94,0x96,
+-0xFF,0x3C, 0x04,0xA4, 0x00,0x26, 0x94,0x96, 0xFF,0x3C, 0x73,0x25, 0x00,0x1E, 0x73,0x18,
+-0xFF,0xE5, 0x93,0x16, 0xFF,0x6C, 0x74,0xA5, 0x00,0x1E, 0x94,0x96, 0xFF,0x64, 0x74,0xA4,
+-0xFF,0xE5, 0x94,0x96, 0xFF,0x64, 0x83,0x16, 0xFF,0x7C, 0xF4,0x84, 0x4F,0x58, 0x76,0xB5,
+-0xFF,0xF0, 0xC6,0x18, 0x4A,0x00, 0x76,0x30, 0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xF3,0x02,
+-0x00,0xFF, 0xC6,0x30, 0x34,0x00, 0xF4,0x82, 0xFF,0x00, 0xC6,0xB4, 0x4C,0x00, 0xC6,0x30,
+-0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0xC7,0x38,
+-0x47,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19, 0x00,0x10, 0x93,0x16, 0xFF,0x34, 0x74,0x99,
+-0xFF,0xF8, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x34,0x00, 0xC7,0x24, 0x70,0x00, 0x97,0x16,
+-0xFF,0x34, 0x24,0x94, 0x00,0xCA, 0x84,0xA6, 0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC,
+-0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x3C, 0xF4,0xAF,
+-0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0x28, 0x4A,0x00, 0x75,0x28,
+-0xFF,0xFA, 0x83,0x16, 0xFF,0x6C, 0x45,0x29, 0x00,0x00, 0xF4,0x82, 0x00,0xFF, 0xC5,0x28,
+-0x4C,0x00, 0x84,0x96, 0xFF,0x3C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF3,0x02,
+-0xFF,0x00, 0xC7,0x38, 0x34,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x27, 0x28,0x00, 0x87,0x26,
+-0x00,0x00, 0x83,0x16, 0xFF,0x64, 0x84,0x16, 0xFF,0x7C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC7,0x38, 0x4C,0x00, 0x83,0x16, 0xFF,0x3C, 0xC3,0x9C,
+-0x70,0x00, 0xE0,0x00, 0xBE,0xE4, 0xF3,0x9B, 0x28,0x00, 0xF7,0x04, 0x40,0x7C, 0xF6,0x04,
+-0x40,0x74, 0xC7,0x38, 0x70,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
+-0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0xBA,0x7D, 0x25,0x80, 0x00,0x07, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
+-0x00,0x40, 0xE0,0x00, 0xBA,0xD8, 0xC4,0x2C, 0x00,0x00, 0xC7,0x30, 0x42,0x00, 0x84,0x96,
+-0x00,0x00, 0x75,0x38, 0xFF,0xFA, 0x06,0x24, 0x00,0x0A, 0x20,0x2E, 0x00,0x07, 0xEE,0x00,
+-0xBA,0xD4, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
+-0x74,0x00, 0x47,0x29, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0xBA,0x74, 0x06,0x30, 0x00,0x02, 0xE0,0x00, 0xBA,0x8C, 0x05,0xAC,
+-0x00,0x01, 0xF4,0x02, 0x00,0x08, 0x07,0x20, 0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00,
+-0xBB,0xA4, 0xC5,0xA0, 0x40,0x00, 0x83,0x16, 0x00,0x00, 0xF5,0x04, 0x40,0x7C, 0xF4,0x82,
+-0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC5,0x98, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
+-0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x18, 0x62,0x00, 0x76,0x30,
+-0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xC6,0x30, 0x4C,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0x77,0x29, 0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0xC6,0xB4, 0x4C,0x00, 0xC7,0x38,
+-0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0xF5,0x84, 0x40,0x74, 0xC5,0x28, 0x50,0x00, 0xC5,0xAC,
+-0x50,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0x75,0x2D, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
+-0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xA1, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4, 0x70,0x00, 0xE0,0x00,
+-0xBB,0xF8, 0xF6,0xAF, 0x28,0x00, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
+-0x00,0x40, 0xF6,0x04, 0x4F,0x58, 0x83,0x16, 0x00,0x00, 0xF7,0x04, 0x40,0x7C, 0xF5,0x84,
+-0x40,0x74, 0xC6,0x18, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x70,0x00, 0xC5,0xAC,
+-0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+-0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30,
+-0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
+-0xBE,0xE0, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
+-0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+-0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xBC,0x79, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
+-0xBC,0x79, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
+-0x00,0x02, 0xE6,0x00, 0xBC,0x7D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
+-0xBC,0x7C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
+-0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xBE,0xD9, 0x06,0xA8, 0x00,0x1C, 0x83,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF4,0x86,
+-0x3B,0xB4, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x96,0x96,
+-0xFF,0x40, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF3,0x04,
+-0x4F,0x5C, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x5C, 0x86,0x96, 0xFF,0x40, 0x83,0x96,
+-0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x93,0x16, 0xFF,0x34, 0x86,0x1A, 0x00,0x08, 0x96,0x96,
+-0xFF,0x3C, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xEC,0x00,
+-0xBD,0xB8, 0x96,0x16, 0xFF,0x9C, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
+-0x00,0x02, 0xC6,0x38, 0x30,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2A,
+-0x00,0x1C, 0x85,0x96, 0xFF,0x5C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xBD,0x40, 0xC4,0x04,
+-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0xBD,0x44, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+-0x00,0x00, 0xE6,0x00, 0xBD,0x51, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x00, 0x83,0x16,
+-0xFF,0x3C, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0xBD,0x90, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0xBD,0x98, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xBD,0x99, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xBD,0xA9, 0x20,0x22, 0x00,0x00, 0xF4,0x02,
+-0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBD,0xB8, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
+-0x00,0x01, 0x94,0x96, 0xFF,0x5C, 0x83,0x16, 0xFF,0x5C, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+-0x00,0x00, 0xE6,0x00, 0xBD,0xF9, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0x9C, 0x84,0x96,
+-0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+-0x48,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xA0, 0xE0,0x00,
+-0xBE,0x70, 0x96,0x96, 0xFF,0xA4, 0x27,0x14, 0x00,0x64, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
+-0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x34, 0x00,0x00,
+-0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16,
+-0xFF,0x44, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBE,0x71, 0xF6,0x02, 0x00,0x00, 0x87,0x16,
+-0xFF,0x9C, 0x83,0x16, 0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xA0, 0x96,0x96, 0xFF,0xA4, 0x97,0x1A, 0x00,0x08, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0xBE,0x99, 0xF6,0x06, 0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC7,0x28,
+-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x28,
+-0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF4,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+-0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xBB,0xFC, 0x03,0x9C, 0x00,0x01, 0x84,0x16,
+-0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x60, 0x85,0x16, 0x00,0x00, 0x86,0x16, 0x00,0x04, 0x06,0xA8, 0x00,0x18, 0xC7,0x30,
+-0x60,0x00, 0xC5,0xB8, 0x68,0x00, 0x20,0x32, 0x00,0x07, 0xEE,0x00, 0xBF,0x64, 0x07,0x2C,
+-0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
+-0x00,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xBF,0x61, 0x05,0xAC, 0x00,0x02, 0xE0,0x00, 0xBF,0x18, 0x06,0x30, 0x00,0x01, 0x20,0x32,
+-0x00,0x07, 0xEE,0x00, 0xC0,0x4C, 0x06,0xA8, 0x00,0x16, 0xF5,0x05, 0x40,0x74, 0xF6,0x05,
+-0x40,0x7C, 0xF3,0x02, 0x00,0x06, 0xF3,0x05, 0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0x05,0x28,
+-0x00,0x02, 0x95,0x16, 0xFF,0xC4, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
+-0xFF,0xBC, 0x93,0x93, 0xFF,0xFC, 0x96,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x38, 0x94,0x93,
+-0xFF,0xFC, 0x93,0x16, 0xFF,0xB4, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x86,0x16, 0xFF,0xAC, 0xF7,0x05,
+-0x42,0x64, 0x96,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xC0,0x1D, 0xF3,0x06, 0x3A,0xD8, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
+-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0xF3,0x05, 0x42,0x44, 0xF3,0x82,
+-0x17,0x70, 0x93,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x1B, 0x94,0x93, 0xFF,0xFC, 0xF3,0x06,
+-0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0xC1,0xA0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0xF5,0x84,
+-0x4F,0x58, 0xF4,0x06, 0x3B,0x70, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C,
+-0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7,
+-0xFF,0xF0, 0xEE,0x00, 0xC1,0x15, 0x96,0x96, 0xFF,0x9C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94,
+-0x00,0x60, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
+-0x00,0x08, 0x83,0xBA, 0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6,
+-0x00,0x04, 0x93,0x26, 0x00,0x00, 0x85,0x96, 0xFF,0xA4, 0xE0,0x00, 0xC1,0x38, 0x23,0x00,
+-0x00,0x07, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x85,0xBA,
+-0x00,0x04, 0x23,0x00, 0x00,0x07, 0x93,0x13, 0xFF,0xFC, 0x87,0x2A, 0x00,0x00, 0x76,0xA9,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E,
+-0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0xEE,0x00, 0xC1,0x8D, 0x76,0xB5, 0xFF,0xF0, 0x84,0x96, 0xFF,0xA0, 0x00,0x00,
+-0x00,0x01, 0x77,0x25, 0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x70, 0x25,0x00,
+-0x00,0x07, 0x20,0x2A, 0x00,0x07, 0xEE,0x00, 0xC3,0xB8, 0xC7,0x28, 0x50,0x00, 0x83,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+-0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
+-0xC2,0x3D, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xC2,0x3D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
+-0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
+-0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xC2,0x4D, 0xC0,0x3A,
+-0x5A,0x00, 0xE0,0x00, 0xC2,0x48, 0xC7,0x2C, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF5,0x84,
+-0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0xC3,0xB1, 0xF4,0x86,
+-0x3B,0x90, 0x83,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x06,0x9C, 0x00,0x16, 0x87,0x36,
+-0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7, 0xFF,0xF0, 0xEE,0x00,
+-0xC3,0x21, 0x96,0x96, 0xFF,0x8C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x83,0x16, 0xFF,0x8C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94, 0x00,0x70, 0x77,0x39,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAA,
+-0x68,0x02, 0x77,0x19, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x83,0xBA,
+-0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6, 0x00,0x04, 0x93,0x26,
+-0x00,0x00, 0x86,0x16, 0xFF,0x94, 0xE0,0x00, 0xC3,0x44, 0x00,0x00, 0x00,0x01, 0xA7,0x2E,
+-0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x3B,0x90, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x30,0x00, 0x86,0x3A,
+-0x00,0x04, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96,
+-0xFF,0x8C, 0xF4,0x86, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xA6,0xBA, 0x48,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38, 0x48,0x00, 0x77,0x39,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC3,0x95, 0x76,0xB5,
+-0xFF,0xF0, 0x83,0x16, 0xFF,0x90, 0x00,0x00, 0x00,0x01, 0x77,0x19, 0xFF,0xF0, 0xC6,0xB8,
+-0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x30,
+-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xC5,0xC4, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
+-0xC1,0xC4, 0x05,0x28, 0x00,0x01, 0x83,0x96, 0x00,0x00, 0xF4,0x82, 0x00,0x06, 0xF4,0x85,
+-0x42,0x54, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x1E, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+-0xFF,0xAC, 0xF3,0x85, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
+-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+-0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+-0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+-0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+-0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+-0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x25,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x07,0x1C,
+-0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0xA4, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x84,0x96,
+-0xFF,0xA4, 0x23,0x14, 0x00,0x38, 0x94,0x93, 0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93,
+-0xFF,0xFC, 0x93,0x16, 0xFF,0x9C, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x27,0x80, 0x00,0x07, 0xF7,0x85,
+-0x42,0x58, 0xF7,0x05, 0x42,0x64, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x97,0x13,
+-0xFF,0xFC, 0x83,0x96, 0xFF,0x9C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96,
+-0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xC5,0x95, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x39,0xC0, 0xF3,0x05, 0x42,0x44, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82,
+-0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xC5,0xC4, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x25,0x00,
+-0x00,0x07, 0xF7,0x04, 0x40,0x74, 0xF6,0x84, 0x4F,0x58, 0xF6,0x04, 0x42,0x60, 0xC7,0x38,
+-0x6A,0x00, 0x75,0xB8, 0xFF,0xFA, 0x06,0x30, 0x00,0x0A, 0x20,0x2A, 0x00,0x07, 0xEE,0x00,
+-0xC6,0x48, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
+-0x74,0x00, 0x47,0x2D, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0xC6,0x4C, 0xC3,0x28, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xE0,0x00,
+-0xC5,0xFC, 0x05,0x28, 0x00,0x01, 0xF3,0x02, 0x00,0x08, 0xC5,0x18, 0x30,0x00, 0xF3,0x84,
+-0x42,0x60, 0xF6,0x04, 0x4F,0x58, 0xF7,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC5,0x1C,
+-0x50,0x00, 0x05,0x28, 0x00,0x26, 0x85,0xAA, 0x00,0x00, 0x74,0x29, 0x00,0x1E, 0x74,0x20,
+-0xFF,0xE5, 0xC6,0x1C, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC6,0xB8, 0x70,0x00, 0xC4,0xA4,
+-0x68,0x00, 0x04,0xA4, 0x00,0x26, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x77,0x39,
+-0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0x46,0x31, 0x00,0x00, 0xC5,0xAC, 0x47,0xC0, 0x75,0xAD,
+-0xFF,0xF0, 0xF4,0x02, 0x00,0xFF, 0xC5,0xAC, 0x44,0x00, 0xC7,0x38, 0x58,0x00, 0xF7,0x2B,
+-0x28,0x00, 0x87,0x26, 0x00,0x00, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30, 0x44,0x00, 0x75,0xAC,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38,
+-0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x27, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x76,0x99,
+-0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
+-0x44,0x00, 0xC6,0xB4, 0x70,0x00, 0xF6,0xA7, 0x28,0x00, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
+-0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x84, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
+-0x42,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x30, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x35,0xEC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x36,0x78, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x04, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x90, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x38,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x38,0xA8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0x34, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0xC0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x3A,0x4C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x3A,0xD8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+-0x00,0x00, 0xF5,0x06, 0x3B,0x90, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
+-0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37, 0xFF,0xF0, 0xEE,0x00, 0xC9,0x95, 0x00,0x00,
+-0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA,
+-0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
+-0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A, 0x00,0x00, 0xE0,0x00, 0xC9,0xB4, 0xC5,0x24,
+-0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A,
+-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32,
+-0x00,0x00, 0xF6,0x06, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC9,0xF9, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
+-0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF5,0x06, 0x3B,0x70, 0x87,0x2E,
+-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37,
+-0xFF,0xF0, 0xEE,0x00, 0xCA,0xBD, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA, 0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31,
+-0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A,
+-0x00,0x00, 0xE0,0x00, 0xCA,0xDC, 0xC5,0x24, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A, 0x00,0x04, 0x83,0x96, 0x00,0x04, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32, 0x00,0x00, 0x93,0x93, 0xFF,0xFC, 0x87,0x2E,
+-0x00,0x00, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xCB,0x29, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
+-0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x04, 0x4F,0x58, 0xF5,0x82, 0x00,0x02, 0x06,0x28,
+-0x00,0x80, 0x20,0x2E, 0x00,0x62, 0xEE,0x00, 0xCB,0x90, 0x07,0x30, 0x00,0x40, 0xF0,0x33,
+-0x28,0x00, 0xC6,0xB8, 0x52,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x30, 0x00,0x14, 0xF6,0xB3,
+-0x28,0x00, 0xC6,0x38, 0x00,0x00, 0xE0,0x00, 0xCB,0x64, 0x05,0xAC, 0x00,0x01, 0xF7,0x04,
+-0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x06,0xB8, 0x18,0xD4, 0xF4,0x82, 0x00,0x01, 0xF4,0xB7,
+-0x28,0x00, 0x07,0x38, 0x18,0xC0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x42,0xC0, 0xF4,0x82,
+-0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF6,0x84, 0x42,0xC0, 0xF6,0x06, 0x42,0xC0, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
+-0x4F,0x58, 0x76,0xB5, 0x00,0x06, 0xC4,0x38, 0x68,0x00, 0x87,0x22, 0x00,0x14, 0x76,0xA1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+-0x28,0x00, 0xF7,0x04, 0x42,0xC0, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0xCC,0x4C, 0xF6,0x06, 0x42,0x90, 0xF7,0x04,
+-0x42,0x90, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0x85,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0xCC,0xBC, 0xF5,0x86, 0x42,0xC0, 0xF7,0x04, 0x42,0x90, 0xF6,0x06, 0x42,0x92, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0xCC,0xEC, 0xF7,0x33, 0x28,0x00, 0xF0,0x2B, 0x28,0x00, 0xF6,0x84,
+-0x42,0xC0, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x06,0x28, 0x00,0x14, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x4F,0x58, 0xF6,0xB3, 0x28,0x00, 0xC7,0x28,
+-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x2F, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x02,
+-0x00,0x00, 0xC6,0xB4, 0x72,0x00, 0x77,0x34, 0xFF,0xFA, 0x27,0x38, 0x00,0x02, 0x20,0x3A,
+-0x00,0x61, 0xF7,0x02, 0x00,0x3F, 0xE2,0x00, 0xCD,0x40, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
+-0x00,0x00, 0xE6,0x00, 0xCD,0x40, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x87,0x16,
+-0x00,0x08, 0x85,0x96, 0x00,0x04, 0xC5,0x30, 0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE6,0x00,
+-0xCD,0xA1, 0x00,0x00, 0x00,0x01, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xAF, 0x68,0x00, 0x06,0x30,
+-0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE6,0x00, 0xCD,0x78, 0x05,0xAC, 0x00,0x01, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x96,
+-0x00,0x00, 0x84,0x16, 0x00,0x04, 0x85,0x96, 0x00,0x08, 0x86,0xA6, 0x00,0x00, 0x77,0x25,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x75,0x35, 0xFF,0xF0, 0x20,0x2A,
+-0x00,0x10, 0xE2,0x00, 0xCE,0x0D, 0xF6,0x06, 0x42,0x8E, 0xF5,0x02, 0x00,0x10, 0xF7,0x04,
+-0x42,0x8C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
+-0xCE,0x70, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xCE,0x71, 0x07,0x24, 0x00,0x02, 0x25,0x28,
+-0x00,0x01, 0xA5,0xBA, 0x50,0x02, 0x86,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC5,0xAC,
+-0x77,0xC0, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x75,0xAD, 0xFF,0xE8, 0xF6,0x82,
+-0x00,0xFF, 0xF7,0x02, 0xF1,0x54, 0x75,0xAD, 0x00,0x02, 0xA7,0x2E, 0x70,0x02, 0xC6,0x30,
+-0x6C,0x00, 0xC6,0x30, 0x75,0x80, 0xF6,0x23, 0x28,0x00, 0x24,0x20, 0x00,0x02, 0x25,0xA8,
+-0x00,0x01, 0xF3,0x02, 0xF2,0x46, 0x03,0xA4, 0x00,0x02, 0xC4,0xAC, 0x38,0x00, 0x25,0x2C,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xCF,0x11, 0x00,0x00, 0x00,0x01, 0xE6,0x00,
+-0xCE,0xA0, 0xC7,0x1C, 0x50,0x00, 0xE0,0x00, 0xCE,0xB4, 0xF6,0x02, 0x00,0x00, 0xA6,0x9E,
+-0x50,0x02, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x35,
+-0xFF,0xE8, 0x86,0xA6, 0x00,0x00, 0x77,0x25, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x25,0x28,
+-0x00,0x02, 0x25,0xAC, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0x77,0x31,
+-0x00,0x04, 0xC7,0x38, 0x62,0x00, 0x77,0x39, 0x00,0x01, 0xC7,0x38, 0x30,0x00, 0xC6,0xB4,
+-0x68,0x00, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x0E, 0x87,0x36, 0x00,0x00, 0x24,0xA4,
+-0x00,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xE0,0x00, 0xCE,0x84, 0x24,0x20, 0x00,0x02, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x08, 0x83,0x16,
+-0x00,0x04, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x74,0x1D,
+-0x00,0x1E, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x05,0xAC, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x74,0x20,
+-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x1F,
+-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x04,0x9C, 0x00,0x02, 0xC7,0x38, 0x47,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x25,0x38, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xD0,0xBD, 0x26,0x28,
+-0x00,0x01, 0xA7,0x26, 0x60,0x02, 0xC6,0xA4, 0x60,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC5,0xA4, 0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xE8, 0xE0,0x00, 0xD0,0x88, 0xF7,0x2F, 0x68,0x00, 0x07,0x1C, 0x00,0x02, 0xF3,0x3B,
+-0x68,0x00, 0xC4,0x1C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x86,0x16, 0x00,0x04, 0x84,0x16, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0xA0, 0x00,0x02, 0x74,0xA1, 0x00,0x1E, 0x74,0xA4,
+-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x06,0xA0, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x22,
+-0x00,0x00, 0x76,0x21, 0x00,0x1E, 0x85,0x96, 0x00,0x08, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF5,0xB7, 0x68,0x00, 0x87,0x22, 0x00,0x00, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x23,
+-0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x20, 0x27,0x14, 0x00,0x20, 0xF0,0x3B, 0x28,0x00, 0x84,0x96, 0x00,0x04, 0xF5,0x02,
+-0x00,0x00, 0x86,0xA6, 0x00,0x00, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x04,0x24,
+-0x00,0x02, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xBB, 0x28,0x00, 0x87,0x26,
+-0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00, 0xD2,0xF8, 0x76,0xA5, 0x00,0x1E, 0x87,0x26,
+-0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0x06,0x28, 0x00,0x01, 0x25,0x94, 0x00,0x1E, 0xC5,0xAC,
+-0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
+-0x52,0x00, 0xA6,0xA2, 0x70,0x02, 0xC7,0x20, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xC6,0x80, 0x6A,0x00, 0xE0,0x00,
+-0xD2,0x90, 0xF6,0xAF, 0x68,0x00, 0x87,0x16, 0xFF,0xE0, 0x76,0x15, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x83,0x96, 0x00,0x00, 0x23,0x14, 0x00,0x1E, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
+-0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x06,0x9C, 0x00,0x02, 0x73,0x95,
+-0x00,0x1E, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x67,0xC0, 0x83,0x96, 0x00,0x00, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x83,0x96, 0xFF,0xDC, 0x87,0x1A, 0x00,0x00, 0x73,0x9C,
+-0xFF,0xE5, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
+-0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0x84,0x16, 0x00,0x00, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x86,0x16, 0x00,0x00, 0x84,0x16, 0x00,0x04, 0xF6,0x84, 0x4F,0x58, 0x87,0x32,
+-0x00,0x14, 0x03,0x30, 0x00,0x14, 0x75,0x19, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC3,0xA0,
+-0x6A,0x00, 0x73,0x9C, 0xFF,0xFA, 0x04,0xA0, 0x00,0x14, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30,
+-0x6A,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0xF3,0x9B, 0x28,0x00, 0x07,0x20, 0x00,0x16, 0xF6,0x3B, 0x28,0x00, 0x87,0x22,
+-0x00,0x14, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39,
+-0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x16, 0xF3,0xB7, 0x28,0x00, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0xF5,0x84,
+-0x4F,0x58, 0x05,0x30, 0x00,0x16, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC4,0x2C,
+-0x70,0x00, 0xC0,0x22, 0x62,0x00, 0xE6,0x00, 0xD5,0x29, 0x06,0xA0, 0x00,0x16, 0x87,0x36,
+-0x00,0x00, 0xC6,0x30, 0x5A,0x00, 0x76,0x30, 0xFF,0xFA, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0x76,0xB8,
+-0xFF,0xFA, 0xF6,0xAB, 0x28,0x00, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x14, 0xE0,0x00,
+-0xD5,0x2C, 0xF6,0x3B, 0x28,0x00, 0xC4,0x2C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x4F,0x84, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05,
+-0x6F,0x30, 0xF6,0x86, 0x50,0x5C, 0x46,0xB4, 0xFF,0xFC, 0xF6,0x85, 0x6E,0x50, 0xF7,0x06,
+-0x6E,0x7C, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05, 0x6E,0x54, 0x07,0x34, 0x19,0x1C, 0xF7,0x05,
+-0x4F,0x5C, 0xF7,0x02, 0x00,0x64, 0x97,0x36, 0x19,0x1C, 0xF7,0x02, 0x00,0x00, 0x97,0x36,
+-0x19,0x20, 0x06,0xB4, 0x00,0x1C, 0xF6,0x85, 0x4F,0x58, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF3,0x02, 0xFF,0xFF, 0xF3,0x05,
+-0x4F,0x54, 0xF3,0x82, 0x00,0x00, 0x93,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+-0xFF,0x9C, 0x23,0x94, 0x00,0x38, 0x93,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0xAC, 0xF7,0x04,
+-0x4F,0x5C, 0xF3,0x82, 0x00,0x0C, 0x93,0x96, 0xFF,0x74, 0x93,0x16, 0xFF,0x8C, 0x87,0x3A,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xA4, 0x83,0x16, 0xFF,0xAC, 0x83,0x96,
+-0xFF,0xA4, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x3A,0x00, 0xEC,0x00, 0xDB,0x78, 0xF3,0x02,
+-0x04,0xBC, 0xF7,0x04, 0x4F,0x5C, 0x83,0x16, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x30,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC4,0xB4,
+-0x70,0x00, 0x94,0x93, 0xFF,0xFC, 0x94,0x96, 0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0x7C, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0xD6,0x54, 0xC5,0x04, 0x00,0x00, 0xF7,0x04, 0x42,0x88, 0xE0,0x00, 0xD8,0x7C, 0xF6,0x06,
+-0x42,0x88, 0xF6,0x04, 0x4F,0x5C, 0x83,0x96, 0x00,0x00, 0x83,0x16, 0xFF,0x74, 0x86,0x9E,
+-0x00,0x00, 0xA7,0x32, 0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0xD6,0x94, 0xC6,0x30, 0x30,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xD6,0x98, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xA5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
+-0x00,0x00, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xE4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x00, 0xD6,0xEC, 0x20,0x2E, 0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xED, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xFD, 0x20,0x2A,
+-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xD7,0x28, 0x04,0xA4,
+-0x00,0x02, 0x83,0x16, 0xFF,0xAC, 0xF7,0x06, 0x42,0xC8, 0x83,0x96, 0xFF,0x8C, 0xF3,0x05,
+-0x4F,0x54, 0xC7,0x1C, 0x70,0x00, 0xF0,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0xE0,0x00,
+-0xDB,0x50, 0xF0,0x3B, 0x28,0x00, 0x94,0x96, 0xFF,0x6C, 0x87,0x26, 0x00,0x00, 0x76,0xA5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16, 0xFF,0x6C, 0x83,0x96, 0xFF,0x9C, 0x24,0x94,
+-0x00,0x1E, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x1D,
+-0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x24,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x10, 0x76,0x31,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0xF6,0x82, 0xFF,0xFC, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x03, 0xC4,0xB8, 0x6C,0x00, 0x20,0x26, 0x00,0x10, 0xE2,0x00,
+-0xD8,0x9D, 0xF6,0x06, 0x42,0x8A, 0xF7,0x04, 0x42,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0xDB,0xA0, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x6C, 0x25,0x14,
+-0x00,0x36, 0x83,0x96, 0xFF,0x94, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x34, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x32, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x30, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2E, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2C, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2A, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x28, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x26,0xA4, 0x00,0x02, 0x74,0xA4, 0xFF,0xFF, 0x76,0x31,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
+-0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x8C, 0xF7,0x06, 0x42,0xCC, 0xC7,0x18,
+-0x70,0x00, 0xC7,0x38, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x94,0x96,
+-0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0x6C, 0x24,0x14, 0x00,0x4E, 0x25,0x14, 0x00,0x50, 0x83,0x16, 0xFF,0x8C, 0x84,0x96,
+-0xFF,0x7C, 0x87,0x1E, 0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x1C,
+-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x29, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x4C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x4A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x48, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x46, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x44, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x42, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x40, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x86,0x96,
+-0xFF,0xB0, 0xF6,0x06, 0x42,0xC8, 0xC6,0x18, 0x60,0x00, 0xF7,0x02, 0x00,0x03, 0xC6,0xB4,
+-0x57,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
+-0x6A,0x00, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xF4,0xB3, 0x28,0x00, 0x83,0x96,
+-0xFF,0x8C, 0x83,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x14, 0x93,0x96, 0xFF,0x8C, 0x03,0x18,
+-0x00,0x0C, 0x83,0x96, 0xFF,0xAC, 0x93,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
+-0xD5,0xEC, 0x93,0x96, 0xFF,0xAC, 0x93,0x13, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
+-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x01,0xA0, 0xF5,0x02,
+-0x00,0x00, 0xF3,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x1C, 0x20,0x2A, 0x00,0x63, 0xEE,0x00,
+-0xDC,0x08, 0xC5,0x9C, 0x60,0x00, 0xA6,0x9E, 0x60,0x02, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x03, 0xE6,0x00,
+-0xDB,0xFC, 0x07,0x2C, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0x06,0x30, 0x00,0x40, 0xE0,0x00,
+-0xDB,0xCC, 0x05,0x28, 0x00,0x01, 0xF5,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x86,0xAE,
+-0x00,0x08, 0xF4,0x02, 0x00,0x00, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xEC,0x00, 0xDC,0xF0, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x58,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x84,
+-0x00,0x00, 0x83,0x16, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0x7C, 0xC5,0x20, 0x00,0x00, 0x86,0xB2,
+-0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0xDC,0x80, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+-0xDC,0x8D, 0x00,0x00, 0x00,0x01, 0xF3,0x82, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x86,0xB2,
+-0x00,0x00, 0x87,0x26, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0xDC,0xCC, 0xF5,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0xD4, 0x20,0x2A,
+-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x00, 0xDC,0xD5, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
+-0x00,0x00, 0xE6,0x00, 0xDC,0xE5, 0x20,0x1E, 0x00,0x00, 0xF3,0x82, 0x00,0x01, 0x20,0x1E,
+-0x00,0x00, 0xE6,0x00, 0xDC,0xF4, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xDD,0x29, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
+-0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+-0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
+-0xDD,0x98, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96,
+-0xFE,0x70, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+-0xFE,0x70, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDD,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x2E, 0x00,0x08, 0xE0,0x00, 0xDD,0x9C, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xDD,0xB0, 0xF4,0x82,
+-0x00,0x00, 0xF7,0x04, 0x42,0x7C, 0xE0,0x00, 0xE0,0x9C, 0xF6,0x06, 0x42,0x7E, 0x94,0x96,
+-0xFF,0x44, 0x87,0x16, 0xFF,0xF4, 0xF6,0x04, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC7,0x30,
+-0x70,0x00, 0x97,0x16, 0xFF,0x54, 0x06,0xB8, 0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16,
+-0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x93,0x13,
+-0xFF,0xFC, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC6,0x30, 0x70,0x00, 0x96,0x16,
+-0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xDE,0x35, 0xF3,0x02, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00,
+-0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDE,0x38, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
+-0x00,0x01, 0x93,0x16, 0xFF,0x44, 0x84,0x96, 0xFF,0x44, 0x00,0x00, 0x00,0x01, 0x20,0x26,
+-0x00,0x00, 0xE6,0x00, 0xDE,0x59, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0xE0,0x00,
+-0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x83,0x16, 0xFF,0x4C, 0x86,0x16, 0xFF,0x4C, 0x87,0x1A,
+-0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0xDE,0x85, 0x00,0x00, 0x00,0x01, 0xF6,0x04,
+-0x4F,0x58, 0xF5,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
+-0xE0,0x25, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00, 0x00,0x01, 0x06,0xA4,
+-0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16, 0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC7,0x2C,
+-0x70,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0xDE,0xDD, 0xF6,0x06, 0x42,0x80, 0xF7,0x04,
+-0x42,0x80, 0xE0,0x00, 0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x26,0x14, 0x00,0x30, 0xF0,0x33,
+-0x28,0x00, 0x87,0x16, 0xFF,0xD0, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
+-0xFF,0x4C, 0x23,0x14, 0x00,0x2E, 0x93,0x16, 0xFE,0x64, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
+-0xFF,0xE5, 0x93,0x16, 0xFF,0x34, 0x83,0x16, 0xFE,0x64, 0x04,0x24, 0x00,0x02, 0x06,0xA0,
+-0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x3C, 0x74,0x95,
+-0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x2C, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x24,0x94,
+-0x00,0x2A, 0x94,0x96, 0xFE,0x64, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xD8, 0x23,0x14, 0x00,0x26, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
+-0x00,0x1E, 0x84,0x96, 0xFF,0x3C, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96,
+-0xFF,0x34, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x83,0x16, 0xFF,0x2C, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0xA0, 0xF7,0x37,
+-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x06,0xA0,
+-0x00,0x02, 0xF7,0x04, 0x4F,0x58, 0xF0,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x14, 0x94,0x16,
+-0xFF,0x24, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0,
+-0x00,0x16, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x01, 0xF4,0xA3, 0x28,0x00, 0x94,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xE0,0xBC, 0x26,0x94, 0x00,0x48, 0xF7,0x04, 0x42,0x80, 0xE0,0x00,
+-0xE0,0x9C, 0xF6,0x06, 0x42,0x82, 0x86,0x96, 0xFE,0xF4, 0xE0,0x00, 0xE2,0x94, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x42,0x84, 0xF6,0x06, 0x42,0x84, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0xEA,0xA4, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x4C, 0x75,0x15,
+-0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x93,0x16, 0xFF,0x1C, 0x07,0x18, 0x00,0x36, 0xF4,0x82,
+-0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0xF0,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB8, 0x76,0xB5,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0x18, 0x00,0x02, 0x06,0x20, 0x00,0x02, 0x23,0x14,
+-0x00,0x46, 0x93,0x16, 0xFF,0x14, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x95,
+-0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x0C, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
+-0xFF,0xE5, 0x93,0x16, 0xFF,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+-0xFE,0xFC, 0x23,0x00, 0x00,0x07, 0x93,0x16, 0xFE,0xF4, 0x84,0x96, 0xFF,0x1C, 0x83,0x16,
+-0xFF,0x14, 0x04,0xA4, 0x00,0x0A, 0x94,0x96, 0xFE,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xF6,0x84, 0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x87,0x1A,
+-0x00,0x00, 0xC6,0xA4, 0x6A,0x00, 0x74,0x34, 0xFF,0xFA, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xBC, 0x23,0x14,
+-0x00,0x42, 0x93,0x16, 0xFF,0x14, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30,
+-0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
+-0x00,0x02, 0x87,0x16, 0xFF,0xC0, 0x24,0x94, 0x00,0x3E, 0x94,0x96, 0xFF,0x14, 0x76,0xA5,
+-0x00,0x1E, 0x83,0x16, 0xFF,0x0C, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16,
+-0xFF,0xC4, 0x24,0x94, 0x00,0x3A, 0x94,0x96, 0xFF,0x14, 0x76,0xA5, 0x00,0x1E, 0x83,0x16,
+-0xFF,0x04, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+-0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0x84,0x96, 0xFE,0xFC, 0x06,0x30,
+-0x00,0x02, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x83,0x16,
+-0xFE,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x07, 0xEE,0x00, 0xE2,0x94, 0xF6,0x82,
+-0x00,0x08, 0x84,0x96, 0xFE,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x0E, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x47,0x21, 0x00,0x00, 0xC0,0x36,
+-0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xE0,0x88, 0x04,0xA4,
+-0x00,0x02, 0x94,0x96, 0xFE,0x7C, 0x03,0x18, 0x00,0x01, 0xE0,0x00, 0xE2,0x30, 0x93,0x16,
+-0xFE,0xF4, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x38, 0xF6,0xBB,
+-0x28,0x00, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x23,0x14,
+-0x00,0x78, 0x93,0x16, 0xFE,0xBC, 0x84,0x96, 0x00,0x00, 0x23,0x14, 0x00,0xA8, 0x86,0xA6,
+-0x00,0x04, 0x87,0x26, 0x00,0x00, 0x93,0x16, 0xFE,0x9C, 0xC6,0xB4, 0x70,0x00, 0x96,0x96,
+-0xFE,0xEC, 0xF7,0x02, 0x00,0x01, 0xC7,0x34, 0x74,0x00, 0x97,0x16, 0xFE,0xE4, 0x84,0x96,
+-0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD4,0xB4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x22,
+-0x72,0x00, 0xE6,0x00, 0xEA,0xA1, 0x94,0x16, 0xFF,0x1C, 0x86,0xA2, 0x00,0x38, 0x77,0x21,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFE,0xD4, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x96,0x96, 0xFE,0xDC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
+-0x00,0x01, 0x20,0x26, 0x00,0x0E, 0xEE,0x00, 0xE2,0xF0, 0xF3,0x02, 0x00,0x0F, 0x93,0x13,
+-0xFF,0xFC, 0x83,0x16, 0xFE,0xEC, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x48,0x00, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x27,0xE8, 0x97,0x93, 0xFF,0xFC, 0xC3,0xA0,
+-0x00,0x00, 0x84,0x96, 0xFE,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+-0xE3,0x8D, 0x23,0x9C, 0x00,0x07, 0xC3,0x80, 0x3A,0x00, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
+-0xFF,0x1C, 0xF4,0x82, 0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC7,0x18, 0x70,0x00, 0x07,0x38,
+-0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x97,0x16, 0xFE,0xC4, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x4C,0x00, 0x76,0xB5,
+-0x00,0x06, 0xC3,0x30, 0x68,0x00, 0x07,0x30, 0x00,0x40, 0xC0,0x1A, 0x72,0x00, 0xE6,0x00,
+-0xE4,0x0D, 0x93,0x16, 0xFE,0xCC, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFE,0x74, 0x96,0x16,
+-0xFE,0x6C, 0x96,0x96, 0xFE,0x68, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
+-0xFF,0xFC, 0x83,0x96, 0xFE,0x74, 0x86,0x16, 0xFE,0x6C, 0x86,0x96, 0xFE,0x68, 0x20,0x22,
+-0x00,0x00, 0xE6,0x00, 0xE0,0x95, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x4F,0x58, 0x84,0x96,
+-0xFE,0xCC, 0x07,0x2C, 0x00,0x40, 0xC0,0x26, 0x72,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00,
+-0x00,0x01, 0xA7,0x32, 0x68,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x86,0x16,
+-0xFE,0xCC, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+-0xE4,0x51, 0xC0,0x32, 0x5A,0x00, 0xC6,0x2C, 0x00,0x00, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
+-0xE6,0xE5, 0x25,0x14, 0x00,0x76, 0x83,0x16, 0xFF,0x1C, 0x84,0x96, 0xFE,0xBC, 0x06,0x18,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16,
+-0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x74, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x72, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x70, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6E, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6C, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6A, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x25,0x14, 0x00,0x68, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
+-0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x60, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
+-0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
+-0xFF,0xA0, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
+-0xFE,0x5C, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20,
+-0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFE,0xAC, 0x83,0x16,
+-0xFE,0x5C, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8,
+-0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xB4, 0x74,0x95,
+-0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
+-0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xA4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA4, 0x24,0x94,
+-0x00,0x5A, 0x94,0x96, 0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x83,0x16, 0xFE,0xB4, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA8, 0x24,0x94, 0x00,0x56, 0x94,0x96,
+-0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x47,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0xAC, 0x23,0x14, 0x00,0x52, 0x93,0x16, 0xFE,0x5C, 0x76,0x19, 0x00,0x1E, 0x84,0x96,
+-0xFE,0xAC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB0, 0x83,0x16, 0xFE,0xA4, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0x8C, 0xF7,0x37,
+-0x28,0x00, 0x84,0x96, 0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x36, 0x94,0x96,
+-0xFE,0x5C, 0x87,0x26, 0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFE,0xCC, 0x84,0x96,
+-0xFF,0x1C, 0x06,0x18, 0x00,0x3A, 0x85,0xB2, 0x00,0x00, 0x07,0x24, 0x00,0x3A, 0x86,0xBA,
+-0x00,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC5,0xAC, 0x67,0xC0, 0xC6,0xB4, 0x77,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0xB5,
+-0xFF,0xF0, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x00, 0xE7,0x64, 0xF5,0x02, 0x00,0x02, 0xF5,0x02,
+-0x00,0x01, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x36, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xE7,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x2A,
+-0x00,0x01, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFE,0x5C, 0x83,0x16,
+-0xFF,0x1C, 0xF5,0x27, 0x28,0x00, 0x06,0x18, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x25,0x14, 0x00,0xA6, 0x84,0x96, 0xFE,0x9C, 0x83,0x16,
+-0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA4, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA2, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA0, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9E, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9C, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9A, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+-0x00,0x00, 0x25,0x14, 0x00,0x98, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
+-0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x90, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
+-0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
+-0xFF,0x70, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x94, 0x00,0x8E, 0x75,0x9D,
+-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16,
+-0xFE,0x94, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
+-0xFF,0xE5, 0x93,0x16, 0xFE,0x84, 0x83,0x16, 0xFE,0x94, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8, 0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
+-0xFF,0xE5, 0x94,0x96, 0xFE,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
+-0x28,0x00, 0x84,0x96, 0xFE,0xC4, 0x87,0x1E, 0x00,0x00, 0x75,0x25, 0x00,0x1E, 0xC7,0x38,
+-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0x74, 0x23,0x94, 0x00,0x8A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
+-0xFE,0x8C, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x16, 0xFE,0x84, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+-0xFF,0x78, 0x23,0x94, 0x00,0x86, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4,
+-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+-0x00,0x02, 0x87,0x16, 0xFF,0x7C, 0x23,0x94, 0x00,0x82, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFE,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0x80, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+-0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0xF3,0x02,
+-0x00,0xFF, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xE8, 0xC6,0xB8, 0x34,0x00, 0xF7,0x02,
+-0x00,0x80, 0xC7,0x34, 0x74,0x00, 0x77,0x39, 0x00,0x10, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x00, 0xEA,0x61, 0x27,0x00, 0x01,0x00, 0xC6,0xB4, 0x75,0x80, 0x84,0x96,
+-0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x38, 0xF6,0xBB, 0x28,0x00, 0x94,0x93,
+-0xFF,0xFC, 0x83,0x16, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
+-0x00,0x01, 0x04,0xA4, 0x00,0x01, 0xE0,0x00, 0xE3,0x3C, 0x94,0x96, 0xFE,0xD4, 0xF4,0x02,
+-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
+-0x00,0x08, 0x86,0x96, 0x00,0x0C, 0xF5,0x02, 0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x84,0x16,
+-0x00,0x10, 0xF4,0x84, 0xE0,0x00, 0x07,0x30, 0x00,0x02, 0x94,0xB2, 0x00,0x10, 0xF4,0x84,
+-0xE0,0x04, 0x06,0xB4, 0x00,0x03, 0x94,0xB2, 0x00,0x14, 0xF4,0x84, 0xE0,0x1C, 0xC6,0xB4,
+-0x54,0x00, 0x94,0xB2, 0x00,0x18, 0xF4,0x82, 0x00,0x05, 0xF4,0xB3, 0x28,0x00, 0xF4,0x82,
+-0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x27,0x34, 0x00,0x08, 0x97,0x32, 0x00,0x04, 0x86,0x16,
+-0x00,0x00, 0x07,0x2C, 0x00,0x03, 0xC7,0x38, 0x54,0x00, 0xC6,0xB8, 0x68,0x00, 0x96,0x93,
+-0xFF,0xFC, 0xC6,0x30, 0x72,0x00, 0x96,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0xAC,
+-0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38, 0x5A,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xC1,0x20, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0x83,0xBA, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x93,0x96, 0xFF,0xF0, 0xF3,0x84,
+-0x6E,0x54, 0x87,0x3A, 0x00,0x04, 0x93,0x96, 0xFF,0xEC, 0x97,0x16, 0xFF,0xF4, 0x90,0x13,
+-0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x20, 0x97,0x13,
+-0xFF,0xFC, 0x94,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
+-0xFF,0xFC, 0x84,0x96, 0xFF,0xE4, 0x83,0x96, 0x00,0x08, 0x87,0x26, 0x00,0x18, 0x85,0x16,
+-0xFF,0xEC, 0xC0,0x3A, 0x3A,0x00, 0xEE,0x00, 0xEC,0x7C, 0xF5,0x82, 0x00,0x01, 0x87,0x26,
+-0x00,0x18, 0x83,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x72,0x00, 0xE6,0x00,
+-0xEC,0x7C, 0xC5,0x84, 0x00,0x00, 0x86,0xA6, 0x00,0x10, 0x87,0x16, 0xFF,0xF0, 0xF6,0x02,
+-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x1C, 0x04,0x24, 0x00,0x10, 0x86,0xA6,
+-0x00,0x14, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+-0xEC,0x20, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0xEC,0x2D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xA2, 0x00,0x00, 0x87,0x16,
+-0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEC,0x68, 0xF6,0x02,
+-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x70, 0x20,0x32, 0x00,0x00, 0x86,0xA2,
+-0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+-0xEC,0x71, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0xEC,0x81, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+-0xEC,0xAC, 0xF7,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0x9C, 0xF6,0x06, 0x42,0x9C, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x02, 0x00,0x01, 0x97,0x2A, 0x00,0x08, 0x83,0xA6,
+-0x00,0x0C, 0x77,0x2C, 0xFF,0xE1, 0x93,0xAA, 0x00,0x0C, 0x97,0x2A, 0x00,0x1C, 0x83,0xA6,
+-0x00,0x1C, 0xF7,0x04, 0x6E,0x50, 0x93,0xAA, 0x00,0x20, 0x83,0xBA, 0x1D,0xDC, 0xF6,0x82,
+-0x00,0x00, 0x93,0xAA, 0x00,0x2C, 0x83,0x96, 0x00,0x0C, 0xC5,0xB4, 0x00,0x00, 0x93,0xAA,
+-0x00,0x30, 0x83,0xBA, 0x00,0x10, 0xC6,0x34, 0x00,0x00, 0x93,0xAA, 0x00,0x24, 0x87,0x3A,
+-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x28, 0x20,0x36, 0x00,0x1F, 0xEE,0x00,
+-0xED,0x1C, 0xC7,0x30, 0x50,0x00, 0x07,0x38, 0x00,0x34, 0x95,0xBA, 0x00,0x00, 0x06,0x30,
+-0x00,0x04, 0xE0,0x00, 0xEC,0xFC, 0x06,0xB4, 0x00,0x01, 0x83,0x96, 0x00,0x10, 0x76,0xA5,
+-0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0xB4, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
+-0xFF,0xFC, 0x87,0x26, 0x00,0x20, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x86,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x16,
+-0xFF,0xF0, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0xF6,0x02,
+-0x1D,0xE0, 0x96,0x13, 0xFF,0xFC, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x13,
+-0xFF,0xFC, 0xF6,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x26,0x14,
+-0x00,0x10, 0x96,0x16, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x00, 0x87,0x36, 0x1D,0xD8, 0x96,0x16,
+-0xFF,0xE4, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF6,0x86, 0x42,0xC0, 0xF7,0x37, 0x28,0x00, 0x86,0x16, 0xFF,0xEC, 0x00,0x00,
+-0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xDB,0xB4, 0x97,0x93,
+-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00, 0x00,0x01, 0x86,0x16,
+-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00,
+-0x00,0x01, 0xF6,0x02, 0x00,0x01, 0x96,0x16, 0xFF,0xE4, 0x84,0x16, 0xFF,0xE4, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x04, 0x86,0x16,
+-0x00,0x00, 0x87,0x36, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xEE,0x99, 0x20,0x3A, 0x00,0x03, 0xE6,0x00, 0xEE,0xE9, 0xF4,0x02, 0x00,0x00, 0xE0,0x00,
+-0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0xEF,0x0D, 0xF4,0x02, 0x00,0x00, 0x85,0x16, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+-0xFF,0xFC, 0x85,0x16, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
+-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x96,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEB,0x60, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0xEF,0x0D, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xED,0x74, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x18, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF4,0x82, 0x00,0x00, 0x86,0x96,
+-0x00,0x00, 0xF6,0x04, 0x4A,0xA0, 0x23,0x94, 0x00,0x10, 0x84,0x36, 0x00,0x00, 0x96,0x16,
+-0xFF,0xE4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16, 0xFF,0xF0, 0x85,0x36, 0x00,0x04, 0xC0,0x32,
+-0x72,0x00, 0xEC,0x00, 0xF0,0x14, 0x95,0x16, 0xFF,0xF4, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
+-0x60,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4,
+-0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x42,0x00, 0xE6,0x00, 0xEF,0xA4, 0xC6,0x24, 0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0xEF,0xA8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xEF,0xB5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+-0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
+-0x72,0x00, 0xE2,0x00, 0xEF,0xF0, 0xF5,0x02, 0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00,
+-0xEF,0xF8, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEF,0xF9, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
+-0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xF0,0x09, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xF0,0x18, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
+-0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xF0,0x4D, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xE8, 0xE0,0x00, 0xF0,0xB0, 0x96,0x96, 0xFF,0xEC, 0x27,0x14, 0x00,0x1C, 0x97,0x13,
+-0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+-0xF0,0xAD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xE8, 0x96,0x96, 0xFF,0xEC, 0xF7,0x05,
+-0x4A,0xA0, 0xE0,0x00, 0xF0,0xB4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
+-0x00,0x00, 0xE6,0x00, 0xF1,0x21, 0xF4,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE8, 0xF6,0x06,
+-0x42,0xC8, 0x76,0xB9, 0x00,0x02, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xA7,0x36,
+-0x60,0x02, 0x83,0x16, 0x00,0x04, 0xC6,0xB4, 0x60,0x00, 0x76,0x35, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x05,0x34, 0x00,0x02, 0x75,0xA9, 0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x83,0x16,
+-0x00,0x08, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x83,0x16,
+-0x00,0x0C, 0x06,0xB4, 0x00,0x04, 0xE0,0x00, 0xF1,0x24, 0x96,0x9A, 0x00,0x00, 0xF4,0x02,
+-0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0xB9,0x00, 0x00,0x00, 0xBA,0x00, 0x00,0x00,
+-0xBB,0x00, 0x00,0x00, 0xBC,0x00, 0x00,0x00, 0xBD,0x00, 0x00,0x00, 0xBE,0x00, 0x00,0x00,
+-0xBF,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x81,0x00, 0x00,0x00, 0x82,0x00, 0x00,0x00,
+-0x83,0x00, 0x00,0x00, 0x84,0x00, 0x00,0x00, 0x85,0x00, 0x00,0x00, 0x86,0x00, 0x00,0x00,
+-0x87,0x00, 0xB9,0xB9, 0xB9,0xBA, 0xB9,0xBB, 0xB9,0xBC, 0xB9,0xBD, 0xB9,0xBE, 0xB9,0xBF,
+-0xB9,0x80, 0xB9,0x81, 0xB9,0x82, 0xB9,0x83, 0xB9,0x84, 0xB9,0x85, 0xB9,0x86, 0xB9,0x87,
+-0xBA,0xB9, 0xBA,0xBA, 0xBA,0xBB, 0xBA,0xBC, 0xBA,0xBD, 0xBA,0xBE, 0xBA,0xBF, 0xBA,0x80,
+-0xBA,0x81, 0xBA,0x82, 0xBA,0x83, 0xBA,0x84, 0xBA,0x85, 0xBA,0x86, 0xBA,0x87, 0xBB,0xB9,
+-0xBB,0xBA, 0xBB,0xBB, 0xBB,0xBC, 0xBB,0xBD, 0xBB,0xBE, 0xBB,0xBF, 0xBB,0x80, 0xBB,0x81,
+-0xBB,0x82, 0xBB,0x83, 0xBB,0x84, 0xBB,0x85, 0xBB,0x86, 0xBB,0x87, 0xBC,0xB9, 0xBC,0xBA,
+-0xBC,0xBB, 0xBC,0xBC, 0xBC,0xBD, 0xBC,0xBE, 0xBC,0xBF, 0xBC,0x80, 0xBC,0x81, 0xBC,0x82,
+-0xBC,0x83, 0xBC,0x84, 0xBC,0x85, 0xBC,0x86, 0xBC,0x87, 0xBD,0xB9, 0xBD,0xBA, 0xBD,0xBB,
+-0xBD,0xBC, 0xBD,0xBD, 0xBD,0xBE, 0xBD,0xBF, 0xBD,0x80, 0xBD,0x81, 0xBD,0x82, 0xBD,0x83,
+-0xBD,0x84, 0xBD,0x85, 0xBD,0x86, 0xBD,0x87, 0xBE,0xB9, 0xBE,0xBA, 0xBE,0xBB, 0xBE,0xBC,
+-0xBE,0xBD, 0xBE,0xBE, 0xBE,0xBF, 0xBE,0x80, 0xBE,0x81, 0xBE,0x82, 0xBE,0x83, 0xBE,0x84,
+-0xBE,0x85, 0xBE,0x86, 0xBE,0x87, 0xBF,0xB9, 0xBF,0xBA, 0xBF,0xBB, 0xBF,0xBC, 0xBF,0xBD,
+-0xBF,0xBE, 0xBF,0xBF, 0xBF,0x80, 0xBF,0x81, 0xBF,0x82, 0xBF,0x83, 0xBF,0x84, 0xBF,0x85,
+-0xBF,0x86, 0xBF,0x87, 0x80,0xB9, 0x80,0xBA, 0x80,0xBB, 0x80,0xBC, 0x80,0xBD, 0x80,0xBE,
+-0x80,0xBF, 0x80,0x80, 0x80,0x81, 0x80,0x82, 0x80,0x83, 0x80,0x84, 0x80,0x85, 0x80,0x86,
+-0x80,0x87, 0x81,0xB9, 0x81,0xBA, 0x81,0xBB, 0x81,0xBC, 0x81,0xBD, 0x81,0xBE, 0x81,0xBF,
+-0x81,0x80, 0x81,0x81, 0x81,0x82, 0x81,0x83, 0x81,0x84, 0x81,0x85, 0x81,0x86, 0x81,0x87,
+-0x82,0xB9, 0x82,0xBA, 0x82,0xBB, 0x82,0xBC, 0x82,0xBD, 0x82,0xBE, 0x82,0xBF, 0x82,0x80,
+-0x82,0x81, 0x82,0x82, 0x82,0x83, 0x82,0x84, 0x82,0x85, 0x82,0x86, 0x82,0x87, 0x83,0xB9,
+-0x83,0xBA, 0x83,0xBB, 0x83,0xBC, 0x83,0xBD, 0x83,0xBE, 0x83,0xBF, 0x83,0x80, 0x83,0x81,
+-0x83,0x82, 0x83,0x83, 0x83,0x84, 0x83,0x85, 0x83,0x86, 0x83,0x87, 0x84,0xB9, 0x84,0xBA,
+-0x84,0xBB, 0x84,0xBC, 0x84,0xBD, 0x84,0xBE, 0x84,0xBF, 0x84,0x80, 0x84,0x81, 0x84,0x82,
+-0x84,0x83, 0x84,0x84, 0x84,0x85, 0x84,0x86, 0x84,0x87, 0x85,0xB9, 0x85,0xBA, 0x85,0xBB,
+-0x85,0xBC, 0x85,0xBD, 0x85,0xBE, 0x85,0xBF, 0x85,0x80, 0x85,0x81, 0x85,0x82, 0x85,0x83,
+-0x85,0x84, 0x85,0x85, 0x85,0x86, 0x85,0x87, 0x86,0xB9, 0x86,0xBA, 0x86,0xBB, 0x86,0xBC,
+-0x86,0xBD, 0x86,0xBE, 0x86,0xBF, 0x86,0x80, 0x86,0x81, 0x86,0x82, 0x86,0x83, 0x86,0x84,
+-0x86,0x85, 0x86,0x86, 0x86,0x87, 0x87,0xB9, 0x87,0xBA, 0x87,0xBB, 0x87,0xBC, 0x87,0xBD,
+-0x87,0xBE, 0x87,0xBF, 0x87,0x80, 0x87,0x81, 0x87,0x82, 0x87,0x83, 0x87,0x84, 0x87,0x85,
+-0x87,0x86, 0x87,0x87, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x18, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xF3,0x7D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0xF5,0xE0, 0xF7,0x33, 0x28,0x00, 0xF3,0x84, 0x6F,0x30, 0x90,0x13,
+-0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0xF7,0x02, 0x00,0x00, 0x97,0x1E,
+-0x00,0x08, 0x83,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0x1E, 0x00,0x0C, 0x83,0x16,
+-0x00,0x08, 0x04,0x9C, 0x00,0x22, 0x93,0x1E, 0x00,0x1C, 0x83,0x16, 0x00,0x0C, 0x93,0x96,
+-0xFF,0xF4, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x18,
+-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0x06,0x9C, 0x00,0x20, 0xF7,0x37, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x96,0x96,
+-0xFF,0xE4, 0x75,0x35, 0x00,0x1E, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x04,0x9C, 0x00,0x24, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x04,0x9C, 0x00,0x26, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x04,0x9C, 0x00,0x28, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x04,0x9C, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x04,0x9C, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x04,0x9C, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x04,0x9C, 0x00,0x30, 0x76,0x31,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+-0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00, 0xF5,0x98, 0xF3,0x06, 0x14,0xD8, 0x83,0x16,
+-0xFF,0xE4, 0x87,0x1E, 0x00,0x20, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x25,0xB8, 0x00,0x01, 0xC4,0xAC, 0x58,0x00, 0x04,0x24,
+-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xF5,0x95, 0xF5,0x02, 0x00,0x00, 0x83,0x16,
+-0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x06,0x18, 0x00,0x02, 0xA7,0x32, 0x58,0x02, 0xC6,0xB0,
+-0x58,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xE8, 0xC6,0xB0, 0x40,0x00, 0x77,0xB8, 0x00,0x18, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+-0xF5,0x7D, 0xF7,0x37, 0x68,0x00, 0xF5,0x02, 0xFF,0xFF, 0xC7,0x30, 0x48,0x00, 0xF5,0x3B,
+-0x68,0x00, 0x24,0xA4, 0x00,0x02, 0x24,0x20, 0x00,0x02, 0xE0,0x00, 0xF5,0x34, 0x25,0xAC,
+-0x00,0x01, 0xF3,0x06, 0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x34, 0x93,0x13,
+-0xFF,0xFC, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF7,0x04,
+-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xF6,0x39, 0xF6,0x06,
+-0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
+-0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
+-0xF7,0x48, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00, 0x00,0x01, 0x95,0x16,
+-0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
+-0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00, 0xF6,0x99, 0x96,0x96,
+-0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x85,0x16,
+-0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28, 0x72,0x00, 0x97,0x13,
+-0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0xF7,0x02,
+-0x00,0x02, 0x97,0x2A, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xAA,
+-0x00,0x0C, 0x85,0x96, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0xAA, 0x00,0x1C, 0xF5,0x06,
+-0x14,0xD8, 0x95,0x13, 0xFF,0xFC, 0xF5,0x82, 0x00,0x20, 0x95,0x93, 0xFF,0xFC, 0x85,0x16,
+-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16,
+-0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
+-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0x00,0x04, 0x87,0x16, 0x00,0x08, 0xF6,0x02,
+-0xFF,0xFC, 0x06,0xA8, 0x00,0x03, 0xC6,0xB4, 0x64,0x00, 0x07,0x38, 0x00,0x03, 0xC7,0x38,
+-0x64,0x00, 0xC7,0x34, 0x70,0x00, 0x97,0x13, 0xFF,0xFC, 0xC5,0xAC, 0x6A,0x00, 0x95,0x93,
+-0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0x28, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
+-0x52,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x14,0xD8, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x10, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xF8,0x0D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0xF9,0x20, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00,
+-0x00,0x01, 0x95,0x16, 0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
+-0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02,
+-0x00,0x00, 0x86,0xAA, 0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00,
+-0xF8,0x6D, 0x96,0x96, 0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96,
+-0xFF,0xEC, 0x85,0x16, 0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28,
+-0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
+-0xFF,0xF4, 0xF5,0x82, 0x00,0x06, 0xF5,0xAB, 0x28,0x00, 0x85,0x96, 0x00,0x08, 0x07,0x28,
+-0x00,0x02, 0x95,0xAA, 0x00,0x04, 0x05,0x14, 0x00,0x0E, 0x85,0x2A, 0x00,0x00, 0x77,0xA9,
+-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0xF5,0x3B,
+-0x28,0x00, 0xF5,0x86, 0x14,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF5,0x02, 0x00,0x08, 0x95,0x13,
+-0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
+-0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04,
+-0x75,0xEC, 0x83,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xFA,0x64, 0xF6,0x06,
+-0x42,0x96, 0xF5,0x04, 0x6F,0x30, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
+-0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0xF4, 0x95,0x16, 0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
+-0xFF,0xFC, 0x85,0x16, 0xFF,0xF0, 0xF3,0x02, 0x00,0x07, 0x83,0x96, 0xFF,0xF4, 0xF3,0x2B,
+-0x28,0x00, 0x07,0x28, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x3B, 0x28,0x00, 0x87,0x1E,
+-0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x76,0x2D,
+-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x04,0x1C,
+-0x00,0x06, 0x83,0x16, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x06,0xA8,
+-0x00,0x04, 0xF7,0x37, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0xA8, 0x00,0x06, 0x75,0xA1,
+-0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+-0x00,0x04, 0x75,0xAC, 0xFF,0xE5, 0x06,0xA8, 0x00,0x08, 0x76,0x19, 0x00,0x1E, 0xC7,0x38,
+-0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x06,0xA8,
+-0x00,0x0A, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x06,
+-0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x0C, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xFA,0x84, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
+-0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+-0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x48, 0xF7,0x04, 0x75,0xEC, 0x85,0x96, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+-0xFD,0x98, 0xF6,0x06, 0x42,0x96, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x14, 0x00,0x1E, 0x06,0x2C, 0x00,0x02, 0x75,0x31,
+-0x00,0x1E, 0x24,0x94, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xF3,0x84, 0x6E,0x50, 0xC7,0x38,
+-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x93,0x96,
+-0xFF,0xC4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+-0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
+-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x90,0x13,
+-0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
+-0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+-0xFF,0xBC, 0x23,0x14, 0x00,0x36, 0x24,0x94, 0x00,0x38, 0x73,0xA5, 0x00,0x1E, 0x73,0x9C,
+-0xFF,0xE5, 0xF4,0x04, 0x42,0xC0, 0xF6,0x86, 0x42,0xC0, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0x87,0x2E, 0x00,0x00, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC4,0x20,
+-0x6F,0xC0, 0x74,0x20, 0xFF,0xF0, 0x05,0xAC, 0x00,0x02, 0x75,0x2D, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2E,
+-0x00,0x00, 0xF6,0x04, 0x6E,0x50, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x23,0x14, 0x00,0x34, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x23,0x14, 0x00,0x32, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x23,0x14, 0x00,0x30, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x23,0x14, 0x00,0x2E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x23,0x14, 0x00,0x2C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x23,0x14, 0x00,0x2A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x28, 0x75,0xAD,
+-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+-0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0xF6,0x82, 0x00,0x03, 0xC7,0x38, 0x3F,0xC0, 0x96,0xB2,
+-0x00,0x08, 0x06,0xB0, 0x1D,0xD8, 0xF4,0x37, 0x28,0x00, 0xF3,0x86, 0x14,0xD8, 0x93,0x93,
+-0xFF,0xFC, 0xF3,0x82, 0x1D,0xE0, 0x93,0x93, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x77,0x39,
+-0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+-0xFD,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
+-0x00,0x06, 0xE6,0x00, 0xFE,0x21, 0xF5,0x82, 0x00,0x1E, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06,
+-0x42,0xA8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0xFE,0x34, 0xF7,0x33, 0x28,0x00, 0xF6,0x05,
+-0x6F,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
+-0x00,0x00, 0x85,0x96, 0x00,0x04, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00,
+-0xFE,0x9D, 0xF4,0x02, 0x00,0x00, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06, 0x42,0xAA, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xE0,0x00, 0xFF,0x1C, 0xF7,0x33, 0x28,0x00, 0x07,0x30, 0x00,0x02, 0x86,0xBA,
+-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+-0xFF,0xF0, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xFE,0xD5, 0xF6,0x05, 0x6F,0x34, 0x20,0x36,
+-0x00,0x02, 0xE6,0x00, 0xFE,0xE5, 0xF5,0x02, 0x00,0x20, 0xE0,0x00, 0xFE,0xFC, 0xF6,0x06,
+-0x42,0xAC, 0x20,0x2E, 0x00,0x0C, 0xE6,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x00, 0xF5,0x02,
+-0x00,0x1F, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x08, 0x97,0x36, 0x00,0x04, 0x87,0x36,
+-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0xFF,0x7D, 0xF6,0x85,
+-0x6F,0x34, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x03, 0xEE,0x00,
+-0xFF,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+-0xFF,0xBD, 0xF6,0x06, 0x42,0xAE, 0xF7,0x04, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
+-0x00,0x08, 0xF6,0x82, 0xFF,0xEC, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x00,0x00,
+-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x00, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
+-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x17, 0x00,0x00,
+-0x00,0x1A, 0x00,0x00, 0x00,0x1D, 0x00,0x00, 0x00,0x18, 0x00,0x00, 0x00,0x00, 0x56,0x65,
+-0x72,0x73, 0x69,0x6F, 0x6E,0x53, 0x74,0x72, 0x69,0x6E, 0x67,0x3A, 0x20,0x6D, 0x63,0x70,
+-0x2D,0x6C, 0x34,0x76, 0x33,0x20, 0x33,0x2E, 0x30,0x38, 0x63,0x20, 0x44,0x65, 0x63,0x20,
+-0x31,0x31, 0x20,0x31, 0x39,0x39, 0x36,0x20, 0x31,0x33, 0x3A,0x30, 0x36,0x3A, 0x31,0x36,
+-0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x0C, 0xFF,0x02,
+-0x00,0x00, 0x97,0x02, 0xFF,0x84, 0xF7,0x06, 0x0C,0x3E, 0xCF,0xFC, 0x75,0x80, 0xF6,0x02,
+-0x00,0x02, 0x96,0x02, 0xFF,0x8C, 0x90,0x02, 0xFF,0x88, 0xF7,0x04, 0xE0,0x20, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x00,0x74, 0xF6,0x82, 0x00,0x00, 0xF6,0x82,
+-0x00,0x03, 0x96,0x82, 0xFF,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x0C, 0xF5,0x02, 0x14,0x94, 0xF5,0x05, 0x7B,0x00, 0xF5,0x0E,
+-0xF0,0x14, 0xF5,0x05, 0x7B,0x08, 0xF7,0x06, 0xE0,0x00, 0xF6,0x86, 0x7B,0x68, 0xC7,0x38,
+-0x6A,0x00, 0xF7,0x05, 0x7A,0xF0, 0xF5,0x02, 0x00,0x4C, 0xF6,0x82, 0x00,0x00, 0x20,0x36,
+-0x00,0x02, 0xEE,0x01, 0x01,0x24, 0xF5,0x05, 0x7A,0xF8, 0xC5,0xB4, 0x00,0x00, 0xC6,0x34,
+-0x00,0x00, 0xF7,0x06, 0xE0,0x30, 0xC7,0x2C, 0x70,0x00, 0xF5,0x06, 0x6F,0x44, 0xB7,0x32,
+-0x50,0x02, 0x90,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
+-0xFF,0xF0, 0x96,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x86,0x16, 0xFF,0xF0, 0x86,0x96, 0xFF,0xEC, 0x05,0xAC,
+-0x14,0x94, 0x06,0xB4, 0x00,0x01, 0x20,0x36, 0x00,0x02, 0xEE,0x01, 0x00,0xD5, 0x06,0x30,
+-0x00,0x04, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF0,0x05,
+-0x6F,0x50, 0xF0,0x05, 0x2D,0x40, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x29,0x58, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
+-0x00,0x03, 0xF7,0x05, 0xE0,0x08, 0xF7,0x04, 0x7A,0xD8, 0xF6,0x02, 0x00,0x01, 0x96,0x02,
+-0xFF,0x94, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x01,0x91, 0xF7,0x06, 0x7A,0xE8, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x03,0xDC, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7A,0xE8, 0xF6,0x02,
+-0x00,0x05, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06, 0x7A,0xE0, 0x86,0x82, 0xFF,0x44, 0xF6,0x02,
+-0x00,0x03, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x01,0xC9, 0xF6,0x3B, 0x28,0x00, 0xF7,0x04,
+-0x6F,0x64, 0x86,0x82, 0xFF,0x44, 0x07,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
+-0x01,0xB0, 0xF7,0x05, 0x6F,0x64, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x34, 0x97,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x8C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x44,0x28, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0xF0, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x0C,0x60, 0x97,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x04,0x08, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x0B,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1D,0x68, 0x97,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0x50, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x5F,0x68, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x6D,0xEC, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x21,0xD0, 0x97,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x22,0x2C, 0x97,0x93, 0xFF,0xFC, 0x90,0x02,
+-0xFF,0x94, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x0B,0xFC, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02,
+-0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x08, 0xF6,0x02, 0x00,0x00, 0xC5,0xB0, 0x00,0x00, 0x20,0x32, 0x00,0x02, 0xEE,0x01,
+-0x03,0x08, 0xF5,0x06, 0x6F,0x44, 0xA6,0xAE, 0x50,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xE6,0x01, 0x02,0xFC, 0xF5,0x02,
+-0x00,0x02, 0x95,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
+-0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+-0xFF,0xF0, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x04, 0xE0,0x01,
+-0x02,0xAC, 0x06,0x30, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x87,0x16, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x82, 0x00,0x08, 0x96,0x3A,
+-0x00,0x08, 0x96,0x3A, 0x00,0x0C, 0x96,0x3A, 0x09,0xD8, 0x96,0x3A, 0x09,0xDC, 0x96,0x3A,
+-0x0E,0xF4, 0x96,0x3A, 0x0E,0xF8, 0x96,0xBA, 0x14,0x20, 0x96,0x3A, 0x14,0x24, 0x90,0xBA,
+-0x14,0x8C, 0x86,0x96, 0x00,0x04, 0x90,0xBA, 0x14,0x90, 0x96,0xBA, 0x00,0x00, 0x96,0x3A,
+-0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+-0x00,0x00, 0x87,0x16, 0x00,0x08, 0x86,0x16, 0x00,0x04, 0x77,0x38, 0xFF,0xFF, 0xC5,0x30,
+-0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x03,0xC9, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
+-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE4,0x01,
+-0x03,0xA0, 0x05,0xAC, 0x00,0x02, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xE0,0x01, 0x03,0xE8, 0xF7,0x05, 0x7A,0xD8, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02,
+-0x00,0x0A, 0xF5,0x05, 0x71,0xCC, 0xF0,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD0, 0xF0,0x05,
+-0x71,0xC4, 0xF5,0x02, 0x00,0x01, 0xF6,0x82, 0x00,0x00, 0x20,0x36, 0x00,0x0A, 0xEC,0x01,
+-0x04,0x64, 0xF5,0x05, 0x71,0xC8, 0xF5,0x8A, 0x1E,0x00, 0xF6,0x06, 0x71,0xC4, 0x47,0x2C,
+-0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30, 0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04,
+-0x71,0xCC, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x04,0x41, 0x05,0xAC,
+-0x21,0x4C, 0xF0,0x05, 0x71,0x98, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
+-0x7B,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x06, 0x05,0xD4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0xA0, 0x95,0x13,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x70,0x80, 0x95,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+-0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+-0x70,0x80, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x06, 0x05,0x58, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x0A, 0x95,0x13,
+-0xFF,0xFC, 0xF5,0x06, 0x71,0x0C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+-0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0x7D, 0xF6,0x86,
+-0x71,0xC4, 0xE0,0x01, 0x05,0x94, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x71,0xD0, 0x00,0x00,
+-0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0xAC, 0xF7,0x05, 0x7B,0x10, 0xF6,0x06,
+-0x71,0x0C, 0xE0,0x01, 0x05,0xC0, 0xF6,0x05, 0x7B,0x18, 0xF6,0x06, 0x6F,0x68, 0xF6,0x05,
+-0x7B,0x18, 0x97,0x02, 0xFF,0x48, 0x07,0x38, 0x21,0x28, 0x97,0x02, 0xFF,0x4C, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0x86,0x82,
+-0xFF,0x48, 0xF4,0x86, 0x6F,0x68, 0xF4,0x85, 0x7B,0x18, 0xF5,0x04, 0x7B,0x10, 0x26,0xB4,
+-0x00,0x02, 0x85,0xB6, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x76,0x29, 0x00,0x1E, 0x76,0x30,
+-0xFF,0xE5, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x6F,0xC0, 0xC7,0x38,
+-0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0xB8, 0x00,0x10, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x06,0x45, 0x75,0xAC, 0xFF,0xF0, 0xF7,0x04, 0x71,0xAC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x71,0xAC, 0xF7,0x04, 0x71,0xAC, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
+-0x00,0x01, 0x77,0x2C, 0xFF,0xF8, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x06,0x71, 0x76,0xA9,
+-0x00,0x1E, 0xF7,0x04, 0x71,0xA8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x71,0xA8, 0xF7,0x04, 0x71,0xA8, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A,
+-0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38,
+-0x00,0x04, 0x20,0x3A, 0x00,0x03, 0xE2,0x01, 0x08,0xA4, 0x00,0x00, 0x00,0x01, 0x77,0x39,
+-0x00,0x02, 0xF6,0x86, 0x06,0xA4, 0xA6,0xB6, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34,
+-0x00,0x00, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x07,0x7C, 0x00,0x01, 0x07,0xEC, 0x00,0x01,
+-0x08,0x44, 0x87,0x2A, 0x00,0x04, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x01,
+-0x06,0xD8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+-0x52,0x00, 0x97,0x2A, 0x00,0x04, 0x87,0x2A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x21,0x00, 0xEE,0x01, 0x07,0x3C, 0xF6,0x02, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0x87,0x02,
+-0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x28, 0xC0,0x36,
+-0x72,0x00, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x01, 0x07,0x3D, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E,
+-0xFF,0xE1, 0xE6,0x01, 0x07,0x44, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x01, 0x08,0x88, 0x00,0x00, 0x00,0x01, 0x87,0x2A, 0x00,0x18, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xEE,0x01, 0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x71,0xA4, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xA4, 0xF7,0x04,
+-0x71,0xA4, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x21,0x00, 0xEE,0x01, 0x07,0xE0, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
+-0x00,0x04, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38,
+-0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
+-0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
+-0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE1, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
+-0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
+-0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x04, 0x20,0x3A, 0x00,0x08, 0xE6,0x01,
+-0x08,0x38, 0xF6,0x82, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x08,0x38, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x08,0x39, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x08,0x80, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x36,
+-0x00,0x00, 0xF7,0x02, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x08,0x78, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x08,0x79, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+-0x08,0x80, 0x20,0x3A, 0x00,0x00, 0xF7,0x02, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xA0, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x71,0xA0, 0xF7,0x04, 0x71,0xA0, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
+-0x00,0x01, 0xF7,0x04, 0x71,0x9C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x71,0x9C, 0xF7,0x04, 0x71,0x9C, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
+-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x68, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
+-0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38, 0x00,0x04, 0x20,0x3A,
+-0x00,0x03, 0xE2,0x01, 0x0B,0x50, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x09,0x0C, 0xA6,0xB6,
+-0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x01, 0x09,0x1C, 0x00,0x01,
+-0x0A,0xE0, 0x00,0x01, 0x0A,0xAC, 0x00,0x01, 0x0B,0x14, 0xF7,0x04, 0x71,0xD0, 0xF6,0x04,
+-0x71,0xCC, 0x06,0xB8, 0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0x38, 0xC7,0x34,
+-0x00,0x00, 0xF7,0x02, 0x00,0x00, 0xF5,0x84, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x85, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x71,0xB0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x71,0xB0, 0xF7,0x04, 0x71,0xB0, 0xF7,0x04, 0x71,0xB4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x71,0xB4, 0xF7,0x04, 0x71,0xB4, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
+-0x00,0x01, 0xF4,0x84, 0x71,0xC8, 0xF6,0x85, 0x71,0xD0, 0x94,0x96, 0xFF,0xF4, 0xF4,0x84,
+-0x7B,0x10, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0xA4, 0x94,0x96, 0xFF,0xEC, 0xF0,0x05,
+-0x71,0xD0, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC8, 0x84,0x96, 0xFF,0xEC, 0xC0,0x3A,
+-0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0xF7,0x05, 0x71,0xC4, 0x87,0x26, 0x00,0x08, 0x00,0x00,
+-0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x09,0xE1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x71,0x98, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0x98, 0x84,0x96,
+-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x0A,0x71, 0x00,0x00,
+-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0xF6,0x02,
+-0x00,0x09, 0x20,0x32, 0x00,0x14, 0xE6,0x01, 0x0A,0x4D, 0x27,0x00, 0x00,0x0C, 0x20,0x3A,
+-0x00,0x01, 0xE2,0x01, 0x0A,0x4D, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00,
+-0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
+-0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x01,
+-0x0A,0x4D, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x04, 0x2D,0x68, 0x00,0x00,
+-0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x28, 0x00,0x00,
+-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+-0x71,0xBC, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xBC, 0xF7,0x04,
+-0x71,0xBC, 0x86,0xA6, 0x00,0x04, 0x84,0x96, 0xFF,0xF4, 0xF7,0x04, 0x71,0xB8, 0x20,0x26,
+-0x00,0x00, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x71,0xB8, 0xE6,0x01, 0x0B,0x51, 0x00,0x00,
+-0x00,0x01, 0xE0,0x01, 0x0B,0x5C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00,
+-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF4,0x84,
+-0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0xFD,0xCC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04,
+-0x71,0xC0, 0xF4,0x84, 0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0xFF,0x30, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF6,0x84, 0x7B,0x10, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
+-0x00,0x01, 0xC7,0x38, 0x6A,0x00, 0x27,0x38, 0x00,0x04, 0x97,0x13, 0xFF,0xFC, 0x96,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFE,0x48, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x70,0x80, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x6F,0x68, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x6F,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x6F,0xF4, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x70,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x71,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02, 0x00,0x04, 0xF5,0x05, 0x76,0x00, 0xF0,0x05,
+-0x76,0x08, 0xF0,0x05, 0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF5,0x02, 0x00,0x01, 0xF6,0x82,
+-0x00,0x00, 0x20,0x36, 0x00,0x04, 0xEC,0x01, 0x0C,0xBC, 0xF5,0x05, 0x75,0xFC, 0xF5,0x8E,
+-0x6A,0xF8, 0xF6,0x06, 0x75,0xF8, 0x47,0x2C, 0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30,
+-0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xEC,0x01, 0x0C,0x99, 0x05,0xAC, 0x21,0x4C, 0xF5,0x06, 0x72,0x18, 0x95,0x13,
+-0xFF,0xFC, 0xF5,0x06, 0x76,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0xA4, 0x95,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+-0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+-0x73,0x30, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x06, 0x16,0xC8, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93,
+-0xFF,0xFC, 0xF5,0x06, 0x73,0xBC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x18,0x00, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
+-0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x16,0x40, 0x95,0x13,
+-0xFF,0xFC, 0xF7,0x82, 0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0xD4, 0x95,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+-0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x12, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
+-0x75,0x60, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+-0xFF,0xFC, 0xF0,0x05, 0x75,0xF0, 0xF0,0x05, 0x75,0xEC, 0xF0,0x05, 0x75,0xF4, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
+-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x28, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x0E,0x3D, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x59, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01,
+-0x0E,0x6C, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39,
+-0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04, 0x76,0xFC, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x90, 0xF6,0x85, 0x76,0x60, 0xF3,0x06,
+-0x76,0x48, 0xF3,0x05, 0x76,0xFC, 0xE0,0x01, 0x0E,0xA4, 0xF7,0x02, 0x00,0x01, 0xF3,0x02,
+-0x00,0x10, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x76,0x48, 0xF3,0x05, 0x77,0x00, 0xF7,0x02,
+-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x15, 0xF3,0x06, 0x74,0x48, 0xF7,0x04,
+-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0xD8, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x0E,0xED, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00,
+-0x00,0x01, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01,
+-0x0F,0x21, 0xF4,0x82, 0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x00,0xBC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4,
+-0x00,0x00, 0x84,0x1E, 0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+-0xFF,0xC4, 0x94,0x16, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04,
+-0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x10,0x0C, 0x95,0x16,
+-0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
+-0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x0F,0x9C, 0xC6,0x24,
+-0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01,
+-0x0F,0xA0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
+-0x0F,0xAD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
+-0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x0F,0xE8, 0xF5,0x02,
+-0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x01, 0x0F,0xF0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
+-0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01,
+-0x0F,0xF1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01,
+-0x10,0x01, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01,
+-0x10,0x10, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01,
+-0x10,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x10,0xB8, 0x96,0x96,
+-0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
+-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+-0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+-0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x01, 0x10,0xB5, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+-0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x10,0xBC, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x10,0xCC, 0xF4,0x82,
+-0x00,0x01, 0xE0,0x01, 0x11,0x24, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
+-0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
+-0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
+-0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
+-0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
+-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
+-0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x11,0x38, 0xF5,0x82, 0x00,0x00, 0xE0,0x01,
+-0x11,0xCC, 0xF6,0x02, 0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34,
+-0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x11,0x98, 0xC5,0x24,
+-0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2,
+-0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28,
+-0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01,
+-0x11,0x59, 0x06,0x30, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02,
+-0x00,0x01, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38,
+-0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02,
+-0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
+-0x13,0x10, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01,
+-0x12,0x30, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+-0x12,0x1C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05,
+-0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x01, 0x12,0x34, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05,
+-0x76,0xFC, 0xF7,0x04, 0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x12,0x71, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32,
+-0x00,0x44, 0xE6,0x01, 0x12,0x70, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+-0x76,0x08, 0xF6,0x84, 0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01,
+-0x12,0x8C, 0xF7,0x05, 0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04,
+-0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x12,0xB9, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01,
+-0x12,0xC8, 0xF7,0x02, 0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
+-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x09, 0xF7,0x05,
+-0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+-0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x13,0x18, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01,
+-0x13,0x18, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x72,0x18, 0xF3,0x06,
+-0x73,0x30, 0xF3,0x05, 0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x04, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x04, 0xF7,0x04,
+-0x76,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x76,0x54, 0xF7,0x04,
+-0x76,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x76,0x58, 0xF7,0x04,
+-0x75,0xF8, 0xF6,0x84, 0x76,0x58, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x9D, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+-0x13,0x9C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
+-0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x13,0xB8, 0xF7,0x05,
+-0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF7,0x04, 0x76,0x08, 0xF6,0x84, 0x76,0x04, 0xF0,0x05,
+-0x75,0xF8, 0xF5,0x84, 0x76,0xF8, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x2E,
+-0x00,0x21, 0xE2,0x01, 0x14,0x14, 0xF7,0x05, 0x75,0xFC, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
+-0x00,0x44, 0xE6,0x01, 0x14,0x00, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+-0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01, 0x14,0x18, 0xF5,0x05,
+-0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04, 0x75,0xEC, 0xF5,0x06, 0x72,0x18, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x01, 0x14,0x40, 0xF5,0x05, 0x76,0x48, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0x55, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x14,0xC4, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x14,0x71, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x14,0x88, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
+-0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
+-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0xC5, 0xF7,0x05,
+-0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+-0x14,0xBC, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06, 0x72,0xA4, 0xF5,0x05,
+-0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x40, 0xF4,0x02,
+-0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xEC, 0x86,0x96,
+-0x00,0x08, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x7B,0x38, 0x86,0x96, 0x00,0x00, 0xF7,0x04,
+-0x76,0x48, 0xF6,0x85, 0x7B,0x30, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x41, 0xF4,0x02, 0x00,0x01, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x75,0xF4, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0xBC, 0xF4,0x02, 0x00,0x00, 0x86,0x96,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xF0, 0x86,0x96, 0x00,0x08, 0x00,0x00,
+-0x00,0x01, 0xF6,0x85, 0x7B,0x48, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x76,0x48, 0xF6,0x85,
+-0x7B,0x40, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x01, 0x15,0xBD, 0xF4,0x02, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x01, 0x15,0xFC, 0xF6,0x82, 0x00,0x10, 0xF6,0x86, 0x76,0x48, 0xF6,0x85,
+-0x76,0xFC, 0xE0,0x01, 0x16,0x0C, 0xF7,0x02, 0x00,0x01, 0xF6,0x85, 0x76,0xF8, 0xF6,0x86,
+-0x76,0x48, 0xF6,0x85, 0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x16,0x20, 0xF6,0x86, 0x74,0xD4, 0xE0,0x01, 0x16,0x2C, 0xF6,0x85, 0x76,0x48, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0xE6,0x01, 0x16,0x85, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x75,0xF4, 0xF6,0x84,
+-0x7B,0x48, 0xF7,0x05, 0x76,0xF4, 0xF7,0x04, 0x7B,0x40, 0xC6,0xB0, 0x68,0x00, 0x26,0xB4,
+-0x00,0x04, 0x97,0x02, 0xFF,0x6C, 0x96,0x02, 0xFF,0x50, 0xE0,0x01, 0x16,0xA8, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0xF6,0x84, 0x7B,0x38, 0xF5,0x82, 0x00,0x01, 0xF5,0x85,
+-0x76,0xF4, 0xF6,0x04, 0x7B,0x30, 0xC6,0xB8, 0x68,0x00, 0x26,0xB4, 0x00,0x04, 0x96,0x02,
+-0xFF,0x6C, 0x97,0x02, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF5,0x86, 0x73,0xBC, 0xF5,0x85,
+-0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+-0x7B,0x28, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7B,0x28, 0xF7,0x04,
+-0x75,0xF4, 0xF6,0x84, 0x7B,0x28, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x21, 0x00,0x00,
+-0x00,0x01, 0xF0,0x05, 0x75,0xF4, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x01, 0x17,0x25, 0xF0,0x05, 0x75,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x17,0xEC, 0x00,0x00, 0x00,0x01, 0xF0,0x05,
+-0x75,0xEC, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+-0x17,0x41, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x17,0x58, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
+-0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
+-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x95, 0xF7,0x05,
+-0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+-0x17,0x8C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x17,0x98, 0xF5,0x06,
+-0x72,0xA4, 0xF5,0x06, 0x72,0x18, 0xF5,0x05, 0x76,0x48, 0xF5,0x84, 0x76,0xF8, 0x00,0x00,
+-0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x17,0xE8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+-0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x17,0xD4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
+-0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01,
+-0x17,0xEC, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x49, 0x00,0x00,
+-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01,
+-0x1C,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x18,0x7D, 0xF4,0x82,
+-0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x00,0xBC, 0x97,0x93,
+-0xFF,0xFC, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4, 0x00,0x00, 0x84,0x1E,
+-0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x94,0x16,
+-0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x19,0x68, 0x95,0x16, 0xFF,0xE4, 0x77,0x35,
+-0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8,
+-0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x18,0xF8, 0xC6,0x24, 0x00,0x00, 0x87,0x36,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01, 0x18,0xFC, 0x20,0x32,
+-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x19,0x09, 0x00,0x00,
+-0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xE0, 0x00,0x00,
+-0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x19,0x44, 0xF5,0x02, 0x00,0x00, 0xC0,0x32,
+-0x72,0x00, 0xE6,0x01, 0x19,0x4C, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16,
+-0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01, 0x19,0x4D, 0x20,0x2A,
+-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01, 0x19,0x5D, 0x20,0x2E,
+-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01, 0x19,0x6C, 0x20,0x26,
+-0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x19,0xA1, 0xF6,0x02,
+-0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+-0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x1A,0x14, 0x96,0x96, 0xFF,0xDC, 0x27,0x14,
+-0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+-0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xCC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xCC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x01, 0x1A,0x11, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06,
+-0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+-0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0x96,0x96,
+-0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x1A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1A,0x28, 0xF4,0x82, 0x00,0x01, 0xE0,0x01,
+-0x1A,0x80, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0x77,0x35,
+-0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x42,0xC8, 0xA6,0x3A,
+-0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x05,0xB8,
+-0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16, 0xFF,0xEC, 0xC6,0x30,
+-0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
+-0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF0, 0x20,0x26,
+-0x00,0x00, 0xE6,0x01, 0x1A,0x94, 0xF5,0x82, 0x00,0x00, 0xE0,0x01, 0x1B,0x28, 0xF6,0x02,
+-0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C,
+-0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x1A,0xF4, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C,
+-0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC,
+-0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+-0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16,
+-0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01, 0x1A,0xB5, 0x06,0x30,
+-0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+-0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4,
+-0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82,
+-0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1C,0x6C, 0x00,0x00,
+-0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+-0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x1B,0x8C, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x1B,0x78, 0xB5,0xBA,
+-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
+-0x77,0x00, 0xE0,0x01, 0x1B,0x90, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04,
+-0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1B,0xCD, 0xF6,0x86,
+-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+-0x1B,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
+-0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x1B,0xE8, 0xF7,0x05,
+-0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04, 0x76,0x04, 0xF0,0x05,
+-0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x01, 0x1C,0x15, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01, 0x1C,0x24, 0xF7,0x02,
+-0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1C,0x65, 0xF7,0x05, 0x76,0x60, 0xF7,0x04,
+-0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
+-0x00,0x44, 0xE6,0x01, 0x1C,0x74, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01, 0x1C,0x74, 0xF0,0x05,
+-0x2D,0x38, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x72,0x18, 0xF3,0x06, 0x73,0x30, 0xF3,0x05,
+-0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
+-0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x72,0x18, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x72,0xA4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x73,0x30, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x73,0xBC, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+-0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x74,0x48, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x74,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x75,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
+-0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x77,0x04, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x1D,0xD4, 0x96,0x93,
+-0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF6,0x86, 0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x00,0x22, 0xF7,0x05,
+-0x76,0xF4, 0xF7,0x05, 0x76,0xF8, 0xF0,0x05, 0x76,0xFC, 0xF0,0x05, 0x77,0x00, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xF4, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x22, 0xE6,0x01, 0x1E,0x01, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x77,0x04, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x76,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
+-0x78,0xA4, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF6,0x86, 0x1F,0xBC, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x14, 0x96,0x93,
+-0xFF,0xFC, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x78,0x9C, 0x90,0x02, 0xFF,0x34, 0xF7,0x02,
+-0x7F,0xFF, 0xF7,0x05, 0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x78,0x9C, 0x87,0x16, 0x00,0x00, 0x84,0x96,
+-0x00,0x08, 0xF5,0x86, 0x77,0x10, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x75,0x39,
+-0x00,0x04, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x32, 0x00,0x00, 0xC6,0xA8,
+-0x58,0x00, 0x84,0x16, 0x00,0x04, 0xC6,0x30, 0x75,0x80, 0x94,0x36, 0x00,0x04, 0xB4,0xAA,
+-0x58,0x02, 0x87,0x36, 0x00,0x08, 0xF6,0x05, 0x78,0x9C, 0x07,0x38, 0x00,0x01, 0xE6,0x01,
+-0x1F,0x2D, 0x97,0x36, 0x00,0x08, 0x87,0x02, 0xFF,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+-0x4A,0x00, 0xEE,0x01, 0x1F,0x35, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x78,0xA0, 0x94,0x82,
+-0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x77,0x39,
+-0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0xF6,0x04, 0x78,0x9C, 0xC7,0x04, 0x76,0x00, 0x86,0xAE,
+-0x00,0x08, 0xC6,0x30, 0x74,0x00, 0xF7,0x06, 0x77,0x10, 0xF6,0x05, 0x78,0x9C, 0x76,0xB5,
+-0x00,0x04, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x08, 0x20,0x32, 0x00,0x00, 0x07,0x38,
+-0x00,0x01, 0xE6,0x01, 0x1F,0xA8, 0x97,0x36, 0x00,0x08, 0xF7,0x02, 0x7F,0xFF, 0xF7,0x05,
+-0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04, 0x78,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+-0x00,0x00, 0xE6,0x01, 0x20,0xD1, 0xF6,0x02, 0x7F,0xFF, 0x96,0x16, 0xFF,0xF4, 0xF6,0x84,
+-0x2D,0x40, 0xF6,0x06, 0x77,0x10, 0x26,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x04, 0xC4,0xB8,
+-0x60,0x00, 0xC3,0x38, 0x00,0x00, 0x74,0x35, 0x00,0x02, 0xF6,0x06, 0x77,0x10, 0xC0,0x26,
+-0x62,0x00, 0xEC,0x01, 0x20,0xC1, 0xF6,0x06, 0x21,0x8C, 0xF3,0x84, 0x78,0x9C, 0xA7,0x22,
+-0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x74,0x00, 0xE6,0x01, 0x20,0xB1, 0x00,0x00,
+-0x00,0x01, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0x78,0xA0, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
+-0x72,0x00, 0x20,0x36, 0x00,0x00, 0xEE,0x01, 0x20,0x98, 0x96,0xA6, 0x00,0x00, 0xF7,0x04,
+-0x2D,0x38, 0xF6,0x06, 0x77,0x10, 0xC5,0x18, 0x60,0x00, 0xF6,0x86, 0x2C,0x28, 0x86,0x2A,
+-0x00,0x04, 0x05,0xB8, 0x00,0x01, 0xF5,0x85, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x2E,
+-0x00,0x44, 0xE6,0x01, 0x20,0x70, 0xB6,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0x86,0x2A,
+-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x96,0x2A, 0x00,0x0C, 0xF6,0x06, 0x21,0x8C, 0xA7,0x22,
+-0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC7,0x04, 0x76,0x00, 0xC7,0x1C, 0x74,0x00, 0xE0,0x01,
+-0x20,0xB0, 0xF7,0x05, 0x78,0x9C, 0x86,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x62,0x00, 0xEC,0x01, 0x20,0xB0, 0x00,0x00, 0x00,0x01, 0x96,0x96, 0xFF,0xF4, 0x24,0xA4,
+-0x00,0x10, 0x23,0x18, 0x00,0x10, 0xE0,0x01, 0x1F,0xFC, 0x24,0x20, 0x00,0x04, 0x86,0x16,
+-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x78,0xA0, 0x96,0x02, 0xFF,0x30, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x77,0x10, 0x77,0x39, 0x00,0x04, 0xC7,0x38,
+-0x68,0x00, 0x86,0xBA, 0x00,0x0C, 0x87,0x3A, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF7,0x02, 0x00,0x0F, 0x20,0x3A, 0x00,0x00, 0xEC,0x01, 0x21,0x5D, 0xF6,0x86,
+-0x77,0x18, 0x90,0x36, 0x00,0x00, 0x27,0x38, 0x00,0x01, 0xC6,0x04, 0x00,0x00, 0xC0,0x3A,
+-0x62,0x00, 0xE6,0x01, 0x21,0x44, 0x06,0xB4, 0x00,0x10, 0xF6,0x06, 0x78,0xA4, 0x96,0x13,
+-0xFF,0xFC, 0xF6,0x06, 0x78,0x10, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x01, 0x00,0x00,
+-0x00,0x02, 0x00,0x00, 0x00,0x04, 0x00,0x00, 0x00,0x08, 0x00,0x00, 0x00,0x10, 0x00,0x00,
+-0x00,0x20, 0x00,0x00, 0x00,0x40, 0x00,0x00, 0x00,0x80, 0x00,0x00, 0x01,0x00, 0x00,0x00,
+-0x02,0x00, 0x00,0x00, 0x04,0x00, 0x00,0x00, 0x08,0x00, 0x00,0x00, 0x10,0x00, 0x00,0x00,
+-0x20,0x00, 0x00,0x00, 0x40,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+-0xFF,0xFC, 0xF7,0x06, 0x22,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x15, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+-0x00,0x08, 0xF6,0x84, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x01, 0x22,0x70, 0xF6,0x02, 0x00,0x00, 0x87,0x36,
+-0x0E,0xF4, 0x86,0xB6, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0x78, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x22,0x94, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+-0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0xB1, 0xF5,0x82,
+-0x03,0xE8, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF5,0x82, 0x03,0xE8, 0x95,0x93,
+-0xFF,0xFC, 0xF5,0x82, 0x00,0x15, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86, 0x79,0xCC, 0x95,0x93,
+-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x79,0xCC, 0x97,0x13,
+-0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+-0x79,0x3C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC1,0x3C, 0x00,0x00, 0x02,0x10, 0x00,0x04, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
+-0x23,0x84, 0x27,0x14, 0x00,0x0C, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0xE0,0x01, 0x24,0x34, 0x96,0x96,
+-0xFF,0xF4, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+-0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+-0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
+-0x24,0x34, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
+-0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xEE,0x01, 0x24,0x21, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0xB8, 0x58,0x00, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
+-0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x36,
+-0x00,0x10, 0x85,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x14, 0x26,0xB4,
+-0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEE,0x01, 0x23,0xEC, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E,
+-0x00,0x04, 0x86,0x96, 0xFF,0xF4, 0x85,0x16, 0x00,0x04, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x2C, 0x70,0x00, 0x85,0x2A, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x95,0x3A, 0x00,0x0C, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x85,0x2A,
+-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x3A, 0x00,0x10, 0x85,0x16, 0x00,0x08, 0xF4,0x02,
+-0x00,0x01, 0x95,0x3A, 0x00,0x14, 0x96,0xAE, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x84,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
+-0x25,0x55, 0x27,0x14, 0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00,
+-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
+-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
+-0x00,0x00, 0xE6,0x01, 0x25,0x55, 0x00,0x00, 0x00,0x01, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
+-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xEE,0x01, 0x25,0x45, 0x77,0x31, 0x00,0x01, 0xC6,0xAC,
+-0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36,
+-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x1C, 0x00,0x00,
+-0x00,0x01, 0x95,0x36, 0x00,0x10, 0x85,0x36, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x95,0x36,
+-0x00,0x14, 0x06,0xB4, 0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x25,0x11, 0x00,0x00,
+-0x00,0x01, 0x87,0x2E, 0x00,0x04, 0xF4,0x02, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0x97,0x2E,
+-0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x08, 0x83,0x96, 0x00,0x04, 0x83,0x16, 0x00,0x00, 0xC5,0x00, 0x00,0x00, 0x84,0x1A,
+-0x00,0x04, 0xC4,0xA8, 0x00,0x00, 0x94,0x16, 0xFF,0xF4, 0xC0,0x26, 0x42,0x00, 0xE6,0x01,
+-0x26,0xD1, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x2A,
+-0x32,0x00, 0xE6,0x01, 0x26,0xD1, 0xC7,0x20, 0x4A,0x00, 0x95,0x16, 0xFF,0xF4, 0x76,0xB8,
+-0xFF,0xE1, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0xFF,0xFF, 0xC5,0x24, 0x70,0x00, 0x77,0x29,
+-0x00,0x01, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x02, 0x83,0x16, 0x00,0x00, 0x86,0x9E,
+-0x00,0x00, 0xC5,0xB8, 0x30,0x00, 0x05,0xAC, 0x00,0x0C, 0x87,0x2E, 0x00,0x00, 0xC6,0x00,
+-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x26,0x10, 0x20,0x32, 0x00,0x00, 0x86,0x9E,
+-0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x01,
+-0x26,0x10, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
+-0x26,0x25, 0x00,0x00, 0x00,0x01, 0xC7,0x00, 0x00,0x00, 0xE0,0x01, 0x26,0x78, 0x20,0x3A,
+-0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x01, 0x26,0x5C, 0x00,0x00, 0x00,0x01, 0xE6,0x01, 0x26,0x64, 0x20,0x32,
+-0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+-0x72,0x00, 0xE2,0x01, 0x26,0x65, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+-0x00,0x00, 0x47,0x04, 0xFF,0xFF, 0xE6,0x01, 0x26,0x79, 0x20,0x3A, 0x00,0x00, 0xF7,0x02,
+-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x26,0xB1, 0x20,0x3A, 0x00,0x00, 0xEE,0x01,
+-0x26,0xA0, 0x20,0x3A, 0x00,0x01, 0x43,0x04, 0xFF,0xFF, 0xC0,0x3A, 0x32,0x00, 0xE6,0x01,
+-0x26,0xC9, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0xE6,0x01,
+-0x26,0xC1, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0x83,0x16,
+-0x00,0x08, 0xF4,0x02, 0x00,0x01, 0xE0,0x01, 0x26,0xE0, 0x95,0x1A, 0x00,0x00, 0xE0,0x01,
+-0x25,0x8C, 0xC4,0xA8, 0x00,0x00, 0xE0,0x01, 0x25,0x8C, 0xC4,0x28, 0x00,0x00, 0x83,0x16,
+-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0x1A, 0x00,0x00, 0xC4,0x00, 0x00,0x00, 0x87,0x96,
+-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+-0x00,0x04, 0x84,0x16, 0x00,0x00, 0x84,0x96, 0x00,0x08, 0xF7,0x02, 0x00,0x03, 0xC6,0xA0,
+-0x4D,0x80, 0xC6,0xB6, 0x74,0x00, 0xE6,0x01, 0x27,0x71, 0xC6,0x20, 0x00,0x00, 0x20,0x36,
+-0x00,0x02, 0xE6,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20, 0x48,0x00, 0x27,0x38,
+-0x00,0x02, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0x9C, 0xC5,0x38, 0x00,0x00, 0x87,0x2E,
+-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE2,0x01,
+-0x27,0x41, 0x05,0xAC, 0x00,0x02, 0xE0,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20,
+-0x48,0x00, 0x27,0x38, 0x00,0x04, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0xA0, 0xC5,0x20,
+-0x48,0x00, 0x83,0xAD, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0xB1, 0x00,0x04, 0xC0,0x32,
+-0x72,0x00, 0xE2,0x01, 0x27,0x85, 0x00,0x00, 0x00,0x01, 0xC5,0x20, 0x48,0x00, 0xC0,0x32,
+-0x52,0x00, 0xE4,0x01, 0x27,0xD5, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
+-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xB3,
+-0x68,0x00, 0x06,0x30, 0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x27,0xAC, 0x05,0xAC,
+-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16,
+-0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC7,0x22, 0x6D,0x80, 0xE6,0x01,
+-0x28,0x10, 0x20,0x36, 0x00,0x00, 0xE0,0x01, 0x28,0x74, 0xC4,0x38, 0x00,0x00, 0xF7,0x02,
+-0x00,0x01, 0xEE,0x01, 0x28,0x41, 0xF6,0x02, 0x00,0x00, 0x76,0xB5, 0x00,0x01, 0x20,0x36,
+-0x00,0x00, 0xEE,0x01, 0x28,0x1C, 0x77,0x39, 0x00,0x01, 0xE0,0x01, 0x28,0x44, 0x20,0x22,
+-0x00,0x00, 0x74,0x21, 0x00,0x01, 0x77,0x38, 0xFF,0xFF, 0x06,0x30, 0x00,0x01, 0x20,0x22,
+-0x00,0x00, 0xEE,0x01, 0x28,0x34, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x28,0x71, 0x00,0x00,
+-0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE4,0x01, 0x28,0x64, 0x00,0x00, 0x00,0x01, 0xC4,0x20,
+-0x6A,0x00, 0x77,0x3A, 0xFF,0xFF, 0xE6,0x01, 0x28,0x54, 0x76,0xB4, 0xFF,0xFF, 0xD4,0x20,
+-0x07,0x62, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+-0x00,0x04, 0xE0,0x01, 0x28,0xCC, 0xF7,0x06, 0x29,0xDC, 0x86,0xBA, 0x00,0x00, 0x00,0x00,
+-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x28,0xC9, 0x00,0x00, 0x00,0x01, 0x97,0x16,
+-0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
+-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A,
+-0x62,0x00, 0xE4,0x01, 0x28,0x9D, 0x00,0x00, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xE0,0x01, 0x29,0x34, 0xF7,0x06,
+-0x29,0x98, 0x86,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
+-0x29,0x31, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34,
+-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+-0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A, 0x62,0x00, 0xE4,0x01, 0x29,0x04, 0x00,0x00,
+-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+-0x7B,0x50, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x29,0x84, 0xF6,0x82,
+-0x00,0x01, 0xF6,0x85, 0x7B,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x28,0xF0, 0x97,0x93,
+-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x0B,0x4C, 0x00,0x00, 0x00,0x00, 0x00,0x00,
+-0x42,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x5E,0x50, 0x00,0x00, 0x00,0x00, 0x00,0x00,
+-0xC7,0xA8, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x0B,0xD0, 0x00,0x00, 0x00,0x00, 0x00,0x01,
+-0x1C,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x1E,0x14, 0x00,0x00, 0x00,0x00, 0x00,0x01,
++static unsigned int __devinitdata lanai4_code_off = 0x0000; /* half-word offset */
++static unsigned char __devinitdata lanai4_code[76256] = {
++0xF2,0x0E,
++0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x02, 0x05,0x3C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x02, 0x0A,0xBC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x02, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x04, 0x4A,0x9C, 0x85,0x16, 0x00,0x00, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
++0x01,0x01, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x01,0x00, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x01,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0xF4,0x82, 0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x01,0xE0, 0xB4,0xBA,
++0x68,0x02, 0xE0,0x00, 0x01,0xE0, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x3B,0x64, 0xF5,0x84,
++0x4F,0x54, 0xF7,0x05, 0x7A,0x10, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x01,0x99, 0x97,0x2A,
++0x00,0x20, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x26,0xAC, 0x00,0x01, 0x77,0x35,
++0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA4,0xBA,
++0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
++0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xD7,0x00, 0x0A,0x01, 0xE0,0x00,
++0x01,0xD0, 0xF7,0x05, 0x7A,0x18, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x06,0xAC,
++0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38,
++0x00,0x0C, 0xA4,0xBA, 0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38,
++0x60,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05, 0x7A,0x18, 0x97,0x2A, 0x00,0x14, 0xF5,0x05,
++0x79,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
++0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x02,0x4C, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x02,0x4C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x02,0x85, 0xF4,0x82, 0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
++0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x02,0x74, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF3,0x06, 0x2A,0x6C, 0xF3,0x05, 0x2C,0x10, 0xE0,0x00, 0x05,0x28, 0xF0,0x05,
++0x7A,0x18, 0xF3,0x84, 0x79,0xD8, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
++0xFF,0xC4, 0x84,0x1E, 0x00,0x10, 0x96,0x96, 0xFF,0xD4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16,
++0xFF,0xE0, 0x85,0x1E, 0x00,0x14, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x03,0x6C, 0x95,0x16,
++0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
++0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00, 0x02,0xFC, 0xC6,0x24,
++0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
++0x03,0x00, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x03,0x0D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
++0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x03,0x48, 0xF5,0x02,
++0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x03,0x50, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
++0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0x03,0x51, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
++0x03,0x61, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
++0x03,0x70, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
++0x03,0xA5, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
++0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
++0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x04,0x18, 0x96,0x96,
++0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
++0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x04,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x04,0x1C, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x04,0x2C, 0xF4,0x82,
++0x00,0x01, 0xE0,0x00, 0x04,0x84, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
++0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
++0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
++0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
++0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
++0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x05,0x25, 0xF3,0x06, 0x29,0xE0, 0x86,0x96,
++0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
++0x6A,0x00, 0xEC,0x00, 0x04,0xF0, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
++0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
++0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
++0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x04,0xB1, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
++0x00,0x03, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
++0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
++0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
++0x29,0xE0, 0xF3,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x04, 0x7A,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x05,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x05,0xCD, 0xF5,0x86, 0x4A,0x98, 0xF6,0x04, 0x79,0xD8, 0xF6,0x84, 0x4F,0x54, 0x00,0x00,
++0x00,0x01, 0x96,0xB2, 0x00,0x1C, 0x06,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA5,0x3A, 0x58,0x02, 0x00,0x00,
++0x00,0x01, 0x95,0x32, 0x00,0x10, 0xC7,0x38, 0x58,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05,
++0x7A,0x18, 0x97,0x32, 0x00,0x14, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0x05,0xFC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
++0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x05,0xF4, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF5,0x06, 0x2A,0x6C, 0xF5,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF7,0x04, 0x75,0xEC, 0x85,0x2E,
++0x00,0x20, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0xF5,0x05, 0x7A,0x08, 0xF7,0x04,
++0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x06,0xCC, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x1C, 0xF6,0x84, 0x4F,0x54, 0xF7,0x05,
++0x7A,0x00, 0xC7,0x34, 0x72,0x00, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x06,0x8D, 0xF5,0x02,
++0x00,0x01, 0xE0,0x00, 0x06,0x90, 0xF5,0x05, 0x79,0xF8, 0xF0,0x85, 0x79,0xF8, 0xF6,0x84,
++0x7A,0x00, 0xC7,0x38, 0x70,0x00, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x79,0xF8, 0xF6,0x85,
++0x79,0xE8, 0xC7,0x38, 0x70,0x00, 0xC6,0x34, 0x70,0x00, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x06,0xCC, 0xF6,0x05, 0x79,0xF0, 0x20,0x36,
++0x00,0x00, 0xEC,0x00, 0x06,0xF8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
++0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x07,0x38, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00,
++0x07,0x38, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
++0x72,0x00, 0xEE,0x00, 0x07,0x19, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x4A,0x9C, 0xE0,0x00,
++0x07,0x28, 0xF7,0x05, 0x79,0xF0, 0x20,0x32, 0x00,0x00, 0xEC,0x00, 0x07,0x28, 0x00,0x00,
++0x00,0x01, 0xF0,0x85, 0x79,0xF0, 0xF5,0x85, 0x79,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xD5, 0xF4,0x02,
++0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x07,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x00, 0x0A,0xA4, 0xF3,0x06,
++0x2B,0x84, 0xF6,0x84, 0x79,0xE8, 0xF6,0x06, 0x4A,0x98, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x84, 0x79,0xE0, 0x07,0x38, 0x00,0x0C, 0xA3,0x3A,
++0x60,0x02, 0xC3,0xB4, 0x00,0x00, 0x93,0x36, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
++0x00,0x04, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x97,0x36, 0x00,0x14, 0x84,0x9E,
++0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x94,0x96, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E,
++0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
++0x08,0xEC, 0x95,0x16, 0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
++0x00,0x02, 0xC6,0xB8, 0x60,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x08,0x7C, 0xC6,0x20,
++0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
++0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x08,0x8D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
++0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x08,0xC8, 0xF5,0x02,
++0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x08,0xD0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
++0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0x08,0xD1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
++0x08,0xE1, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
++0x08,0xF0, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x09,0x25, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
++0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
++0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x09,0x98, 0x96,0x96,
++0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
++0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x09,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x09,0x9C, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x09,0xAC, 0xF4,0x82,
++0x00,0x01, 0xE0,0x00, 0x0A,0x04, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
++0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
++0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
++0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
++0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
++0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x0A,0xA5, 0xF3,0x06, 0x2A,0xF8, 0x86,0x96,
++0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
++0x6A,0x00, 0xEC,0x00, 0x0A,0x70, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
++0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
++0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
++0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x0A,0x31, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
++0x00,0x02, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
++0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
++0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
++0x2A,0xF8, 0xF3,0x05, 0x2C,0x1C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF6,0x84, 0x79,0xE8, 0xF7,0x04, 0x79,0xF8, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
++0x70,0x00, 0xF7,0x04, 0x7A,0x20, 0xF6,0x85, 0x79,0xE8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x7A,0x20, 0xF7,0x04, 0x79,0xF0, 0xF6,0x04, 0x7A,0x20, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x0B,0x2C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x82, 0x00,0x13, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x0B,0x20, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86,
++0x2B,0x84, 0xE0,0x00, 0x0B,0x38, 0xF5,0x85, 0x2C,0x1C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x06, 0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF0,0x05,
++0x2D,0x38, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x18, 0xFF,0x85, 0x2E,0xDC, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
++0x74,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x29, 0x97,0x16, 0xFF,0xF4, 0x47,0x38,
++0xFF,0xFB, 0xF6,0x84, 0x6F,0x50, 0xCF,0xB8, 0x00,0x00, 0x83,0x96, 0xFF,0xF4, 0xF7,0x02,
++0x00,0x3F, 0xC3,0x9C, 0x6D,0x80, 0xC7,0x1C, 0x74,0x00, 0x20,0x3A, 0x00,0x3F, 0xE2,0x00,
++0x12,0x60, 0x93,0x96, 0xFF,0xF4, 0x77,0x39, 0x00,0x02, 0xF6,0x82, 0x0C,0x5C, 0xA6,0xB6,
++0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x00, 0x12,0x60, 0x00,0x00,
++0x12,0x60, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x5C, 0x00,0x00,
++0x0D,0x5C, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x12,0x50, 0x00,0x00,
++0x12,0x50, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE0, 0x00,0x00,
++0x0D,0xE0, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE8, 0x00,0x00,
++0x0D,0xF4, 0x00,0x00, 0x0E,0x00, 0x00,0x00, 0x0E,0x20, 0x00,0x00, 0x0E,0x40, 0x00,0x00,
++0x0E,0x60, 0x00,0x00, 0x0E,0x80, 0x00,0x00, 0x0E,0xA0, 0x00,0x00, 0x0E,0xC0, 0x00,0x00,
++0x0E,0xC8, 0x00,0x00, 0x0E,0xD0, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0E,0xD8, 0x00,0x00,
++0x0E,0xF4, 0x00,0x00, 0x0F,0x10, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0F,0x18, 0x00,0x00,
++0x0F,0x18, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x44, 0x00,0x00,
++0x0F,0x44, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x84, 0x00,0x00,
++0x0F,0x84, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x94, 0x00,0x00,
++0x0F,0x94, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB8, 0x00,0x00,
++0x0F,0xD8, 0x00,0x00, 0x0F,0xF8, 0x00,0x00, 0x10,0x2C, 0x00,0x00, 0x10,0x60, 0x00,0x00,
++0x10,0x94, 0x00,0x00, 0x10,0xC8, 0x00,0x00, 0x10,0xFC, 0x00,0x00, 0x11,0x30, 0x00,0x00,
++0x11,0x4C, 0x00,0x00, 0x11,0x68, 0x00,0x00, 0x12,0x14, 0x00,0x00, 0x11,0x84, 0x00,0x00,
++0x11,0xB4, 0x00,0x00, 0x11,0xE4, 0x00,0x00, 0x12,0x14, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
++0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF6,0x02, 0x00,0x05, 0x20,0x32, 0x00,0x14, 0xE6,0x00,
++0x0D,0xB5, 0x27,0x00, 0x00,0x10, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x0D,0xB5, 0xF7,0x06,
++0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00, 0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E,
++0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06,
++0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x0D,0xB5, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05,
++0x2E,0xCC, 0xF7,0x04, 0x2D,0x58, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x87,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
++0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x60, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
++0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xE0,0x00,
++0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
++0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
++0x00,0x06, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
++0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
++0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
++0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
++0x12,0x2C, 0xF3,0x82, 0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00,
++0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
++0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
++0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
++0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
++0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
++0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF7,0x04,
++0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x13,0xCC, 0xF7,0x05,
++0x35,0x44, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x90,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x77,0x9C, 0x00,0x14, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0x12,0x9D, 0xF7,0x06, 0x04,0x00, 0xF7,0x04, 0x6F,0x5C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x6F,0x5C, 0xF7,0x04, 0x6F,0x5C, 0xE0,0x00, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0xF7,0x06, 0x04,0x00, 0xC0,0x1E, 0x74,0x00, 0xE6,0x00,
++0x14,0x29, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2E,0xD0, 0xF6,0x84, 0x35,0x24, 0x07,0x38,
++0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF7,0x05, 0x2E,0xD0, 0xF7,0x04,
++0xE0,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF6,0x82,
++0x00,0x00, 0xF6,0x85, 0xE0,0x14, 0xF7,0x04, 0x2E,0xD8, 0xC5,0x34, 0x00,0x00, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x2E,0xD8, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x13,0xCC, 0xF6,0x82,
++0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x13,0xA0, 0x05,0xB4, 0x00,0x08, 0x95,0x93,
++0xFF,0xFC, 0x95,0x16, 0xFF,0xE8, 0x95,0x96, 0xFF,0xE4, 0x96,0x96, 0xFF,0xE0, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x64, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xE8, 0x85,0x96,
++0xFF,0xE4, 0x86,0x96, 0xFF,0xE0, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x13,0x90, 0xF7,0x02,
++0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00,
++0x13,0x75, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x13,0x90, 0xF7,0x02,
++0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38,
++0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x12,0x00, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04,
++0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x13,0xC0, 0x07,0x34,
++0x14,0x94, 0xF3,0x84, 0x6F,0x44, 0xE0,0x00, 0x13,0xC4, 0xF3,0x85, 0x35,0x28, 0xF7,0x05,
++0x35,0x28, 0xE0,0x00, 0x12,0xE8, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
++0x14,0x29, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05, 0x35,0x24, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x14,0x28, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x14,0x28, 0xF0,0x05,
++0x2D,0x38, 0xF7,0x04, 0xE0,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x14,0x29, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0xE0,0x10, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x02,0x98, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84, 0x2D,0x38, 0xF7,0x04, 0x2D,0x3C, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x0C,0x09, 0xF6,0x86, 0x2C,0x28, 0x77,0x39,
++0x00,0x02, 0xA5,0x3A, 0x68,0x02, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00,
++0x14,0x91, 0x27,0x28, 0x00,0x15, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x14,0x91, 0xF7,0x06,
++0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E,
++0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36,
++0x00,0x1F, 0xE2,0x00, 0x14,0x91, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x06,
++0x2D,0x44, 0x76,0xA9, 0x00,0x02, 0xA7,0x36, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x04, 0x94,0x96,
++0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x2D,0x3C, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0x20,0x3A, 0x00,0x44, 0xE6,0x00,
++0x14,0x2C, 0xF7,0x05, 0x2D,0x3C, 0xE0,0x00, 0x14,0x2C, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16, 0x00,0x00, 0xF7,0x02,
++0x00,0x00, 0x85,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x21, 0xEE,0x00, 0x15,0x34, 0x95,0xA2,
++0x00,0x00, 0xF6,0x06, 0x23,0x38, 0x07,0x20, 0x00,0x84, 0xC6,0xA0, 0x00,0x00, 0x96,0x3A,
++0x00,0x04, 0x27,0x38, 0x00,0x04, 0xC0,0x3A, 0x6A,0x00, 0xEC,0x00, 0x15,0x20, 0x00,0x00,
++0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96,
++0x00,0x00, 0x87,0x16, 0x00,0x04, 0xF6,0x04, 0x2D,0x40, 0x97,0x36, 0x00,0x00, 0x97,0x36,
++0x00,0x04, 0x07,0x30, 0x00,0x01, 0xF7,0x05, 0x2D,0x40, 0x96,0x36, 0x00,0x08, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00, 0x15,0xD9, 0x27,0x28, 0x00,0x15, 0x20,0x3A,
++0x00,0x01, 0xE2,0x00, 0x15,0xD9, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02,
++0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
++0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x15,0xD9, 0xB6,0x2E,
++0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF6,0x86, 0x2D,0x44, 0x77,0x29, 0x00,0x02, 0xA6,0xBA,
++0x68,0x02, 0x00,0x00, 0x00,0x01, 0x86,0xB6, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
++0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x87,0x16, 0x00,0x00, 0x86,0x96, 0x00,0x04, 0xF6,0x06, 0x2D,0x44, 0x76,0xB5,
++0x00,0x02, 0x85,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xB5,0xB6, 0x60,0x02, 0xC6,0xB4,
++0x70,0x00, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xB6, 0x00,0x04, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2,
++0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00, 0x16,0xB4, 0xC5,0xB4, 0x00,0x00, 0x20,0x36,
++0x00,0x0F, 0xEE,0x00, 0x16,0xB4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00,
++0x16,0xB5, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEC,0x00, 0x16,0xD0, 0x00,0x00,
++0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32,
++0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00, 0x16,0xD8, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A,
++0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x34,0x58, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
++0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x3F,0x94, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2F,0xF8, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
++0x3B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x02, 0x26,0xE4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x13, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x26,0xA0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
++0x00,0x11, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05,
++0x7A,0x78, 0xF0,0x05, 0x32,0xE8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x18,0x55, 0xF6,0x86, 0x71,0xC4, 0xE0,0x00, 0x18,0x6C, 0xF6,0x02,
++0x00,0x00, 0xF7,0x04, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
++0x68,0x00, 0x86,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x32,0xC4, 0x86,0xB2,
++0x00,0x08, 0x07,0x01, 0x80,0x00, 0xC5,0xB4, 0x74,0x00, 0xF5,0x85, 0x32,0xD0, 0x87,0x32,
++0x00,0x18, 0xF6,0x86, 0x6F,0x44, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x2E,
++0x00,0x00, 0xF7,0x05, 0x32,0xC0, 0x07,0x38, 0x09,0xD8, 0x86,0xB2, 0x00,0x04, 0xF7,0x05,
++0x32,0xCC, 0xE6,0x00, 0x19,0x41, 0xF6,0x85, 0x32,0xC8, 0xF7,0x04, 0x71,0x98, 0xF6,0x84,
++0x7A,0x78, 0x27,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x19,0x10, 0xF7,0x05,
++0x71,0x98, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x18,0xE8, 0xF3,0x02, 0x00,0x11, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05, 0x76,0xFC, 0xE0,0x00,
++0x18,0xF8, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05,
++0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x19,0x14, 0xF3,0x02,
++0x00,0x01, 0xF3,0x06, 0x31,0x10, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF3,0x02,
++0x00,0x01, 0xF3,0x05, 0x7A,0x78, 0xF3,0x06, 0x30,0x84, 0xF3,0x05, 0x32,0xD4, 0xF3,0x04,
++0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x26,0x8C, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
++0x00,0x00, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x1C,0xB9, 0x93,0x16, 0xFF,0xE4, 0x87,0x32,
++0x00,0x08, 0x86,0x96, 0xFF,0xE4, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
++0x19,0x84, 0x20,0x36, 0x00,0x00, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x32,0x00, 0xE6,0x00, 0x19,0x84, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02, 0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16,
++0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A, 0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C,
++0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00,
++0x1A,0x70, 0x96,0x16, 0xFF,0xEC, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
++0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E,
++0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x00, 0xC4,0x84,
++0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x1A,0x04, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
++0x00,0x00, 0xE6,0x00, 0x1A,0x11, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2,
++0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0x1A,0x4C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x54, 0x20,0x2E,
++0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0x1A,0x55, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0x1A,0x65, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26,
++0x00,0x00, 0xE6,0x00, 0x1A,0x70, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16,
++0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1A,0xB1, 0xF6,0x02,
++0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
++0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
++0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1B,0x18, 0x96,0x96, 0xFF,0xF4, 0x27,0x14,
++0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96,
++0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1B,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x1B,0x1C, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02,
++0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0,
++0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xEC,0x00, 0x1C,0x04, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8, 0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE,
++0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x1B,0x94, 0xC4,0x84, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1B,0x98, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
++0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x1B,0xA5, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
++0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0x1B,0xE0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x1B,0xE8, 0x20,0x32, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x1B,0xE9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1B,0xF9, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
++0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x1C,0x04, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
++0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00,
++0x1C,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
++0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
++0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1C,0xAC, 0x96,0x96,
++0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93,
++0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1C,0xA9, 0xF6,0x02,
++0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
++0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
++0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00,
++0x1C,0xB0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x1E,0x15, 0xF3,0x02, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6,
++0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E, 0x00,0x10, 0xE2,0x00, 0x1C,0xDC, 0x20,0x32,
++0x00,0x10, 0xE2,0x00, 0x1C,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00,
++0x1D,0x24, 0xF7,0x02, 0x00,0x00, 0x07,0x30, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00,
++0x1D,0x1D, 0xF6,0x82, 0x00,0x00, 0x20,0x32, 0x00,0x10, 0xE6,0x00, 0x1D,0x20, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0x1D,0x24, 0xC7,0x34, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34,
++0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0x14, 0xF3,0x02, 0x00,0x01, 0xF3,0x04,
++0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x1D,0x91, 0x76,0xB1,
++0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A,
++0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00, 0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0xF3,0x02,
++0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
++0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
++0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16,
++0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
++0x1D,0xEC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00,
++0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16,
++0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1E,0x18, 0xF3,0x02,
++0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
++0x00,0x00, 0xE6,0x00, 0x1F,0x35, 0xF6,0x82, 0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16,
++0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A,
++0x00,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
++0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04,
++0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0xAD, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x1E,0xAC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
++0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x1E,0xC8, 0xF7,0x05,
++0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
++0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
++0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
++0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
++0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04, 0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA,
++0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1F,0x60, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02,
++0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00, 0x1F,0x68, 0xF7,0x02, 0x00,0x01, 0xF3,0x05,
++0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1F,0x7C, 0xF3,0x06,
++0x2F,0x6C, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94,
++0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00, 0x22,0x84, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02,
++0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05, 0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84,
++0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02, 0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84,
++0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02,
++0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
++0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05, 0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96,
++0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06,
++0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05,
++0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x34, 0x00,0x00,
++0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x25, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
++0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x26,0x8C, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82, 0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38,
++0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x20,0x90, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04,
++0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x20,0x84, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x20,0x94, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05,
++0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x21,0xC0, 0x00,0x00,
++0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05,
++0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32,
++0x00,0x10, 0xE2,0x00, 0x21,0x19, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00,
++0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13,
++0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
++0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
++0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96,
++0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x21,0x78, 0x00,0x00,
++0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
++0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x21,0xC0, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0x21,0xC1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04,
++0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x21,0xFD, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x21,0xFC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
++0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x22,0x18, 0xF7,0x05,
++0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
++0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
++0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
++0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
++0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02, 0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02,
++0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06, 0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04,
++0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05,
++0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x22,0xD5, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A,
++0x5A,0x00, 0xE6,0x00, 0x26,0x20, 0xC0,0x32, 0x6A,0x00, 0xEE,0x00, 0x26,0x21, 0x00,0x00,
++0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00,
++0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04,
++0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04,
++0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04,
++0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x23,0x45, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x23,0x48, 0xF7,0x05,
++0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
++0x00,0x21, 0xE2,0x00, 0x23,0x8C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x23,0x80, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
++0x00,0x22, 0xE0,0x00, 0x23,0x90, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84,
++0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0x87,0x02,
++0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13,
++0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93,
++0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x24,0x78, 0x00,0x00,
++0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00,
++0x24,0x15, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x24,0x78, 0x00,0x00,
++0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1,
++0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16,
++0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13,
++0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30,
++0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x24,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
++0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A,
++0x32,0x00, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
++0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x24,0xBD, 0x00,0x00,
++0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x24,0xF9, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
++0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x24,0xF8, 0xB3,0x3A,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38,
++0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x25,0x14, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05,
++0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36,
++0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x25,0xD1, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
++0x00,0x21, 0xE2,0x00, 0x25,0xC4, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x25,0xB0, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
++0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x00, 0x25,0xC8, 0xF3,0x05,
++0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00, 0x25,0xD8, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00,
++0x25,0xDC, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06, 0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04,
++0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x26,0x8C, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x26,0x8C, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x26,0x8C, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
++0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xEE,0x00, 0x26,0x41, 0xC5,0xB4,
++0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00, 0x26,0x48, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8,
++0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84, 0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35,
++0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6,
++0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04, 0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02,
++0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85,
++0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x7A,0x78, 0xF7,0x06,
++0x30,0x84, 0xF7,0x05, 0x32,0xD4, 0xF7,0x04, 0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04,
++0x32,0xD0, 0xF3,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x2A,0x71, 0x93,0x16,
++0xFF,0xE4, 0xF6,0x84, 0x32,0xC4, 0x86,0x16, 0xFF,0xE4, 0x87,0x36, 0x00,0x08, 0xC3,0x04,
++0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32, 0x00,0x00, 0x87,0x36,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02,
++0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A,
++0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C, 0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00,
++0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00, 0x28,0x28, 0x96,0x16, 0xFF,0xEC, 0x77,0x31,
++0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30,
++0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E, 0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x27,0xB8, 0xC4,0x84, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x27,0xBC, 0x20,0x2A,
++0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x27,0xC9, 0x00,0x00,
++0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x04, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x28,0x0C, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x0D, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x28,0x1D, 0x20,0x26,
++0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x28,0x28, 0xF3,0x02,
++0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
++0x00,0x00, 0xE6,0x00, 0x28,0x69, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
++0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
++0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
++0x28,0xD0, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13,
++0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x28,0xCD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
++0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
++0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E,
++0x00,0x08, 0xE0,0x00, 0x28,0xD4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02, 0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16,
++0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0, 0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32,
++0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x29,0xBC, 0x96,0x96,
++0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8,
++0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE, 0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16,
++0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0x4C, 0xC4,0x84, 0x00,0x00, 0x86,0xAE,
++0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x29,0x50, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
++0x29,0x5D, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x29,0x98, 0xF6,0x02,
++0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0xA0, 0x20,0x32, 0x00,0x00, 0x86,0xAE,
++0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0x29,0xA1, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x29,0xB1, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
++0x29,0xBC, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00,
++0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x29,0xFD, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xF0, 0xE0,0x00, 0x2A,0x64, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13,
++0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x2A,0x61, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
++0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
++0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96,
++0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x2A,0x68, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2B,0xCD, 0xF3,0x02, 0x00,0x01, 0xF6,0x84,
++0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6, 0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E,
++0x00,0x10, 0xE2,0x00, 0x2A,0x94, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2A,0xB1, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00, 0x2A,0xDC, 0xF7,0x02, 0x00,0x00, 0x07,0x30,
++0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x2A,0xD5, 0xF6,0x82, 0x00,0x00, 0x20,0x32,
++0x00,0x10, 0xE6,0x00, 0x2A,0xD8, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x2A,0xDC, 0xC7,0x34,
++0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x2B,0xCC, 0xF3,0x02, 0x00,0x01, 0xF3,0x04, 0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16,
++0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0x83,0x16,
++0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32,
++0x00,0x10, 0xE2,0x00, 0x2B,0x49, 0x76,0xB1, 0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A, 0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00,
++0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0xF3,0x02, 0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4,
++0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38,
++0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
++0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30,
++0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x2B,0xA4, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
++0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02,
++0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16, 0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
++0x00,0x00, 0xE6,0x00, 0x2B,0xD0, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16,
++0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0xED, 0xF6,0x82,
++0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16, 0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0x28, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
++0x2C,0x28, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x2C,0x65, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
++0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2C,0x64, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xE6,0x00, 0x2C,0x80, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
++0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
++0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
++0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
++0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04,
++0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA, 0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x2D,0x18, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00,
++0x2D,0x20, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x2D,0x34, 0xF3,0x06, 0x2F,0x6C, 0xE0,0x00, 0x34,0x44, 0xF3,0x05,
++0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94, 0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
++0x30,0x3C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
++0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
++0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
++0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
++0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
++0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
++0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
++0x74,0x00, 0xE6,0x00, 0x2D,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
++0x2D,0xDD, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
++0x00,0x10, 0xE6,0x00, 0x34,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
++0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
++0x2E,0x48, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x2E,0x3C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
++0x2E,0x4C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
++0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x02, 0xE6,0x00, 0x2F,0x78, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C,
++0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96,
++0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
++0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
++0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2E,0xD1, 0xF3,0x02,
++0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
++0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x13,
++0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
++0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38,
++0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
++0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
++0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32,
++0x00,0x11, 0xE6,0x00, 0x2F,0x30, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
++0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
++0x2F,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
++0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x2F,0x79, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
++0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x2F,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
++0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2F,0xB4, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xE6,0x00, 0x2F,0xD0, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
++0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
++0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
++0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
++0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
++0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06,
++0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
++0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x30,0x8D, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x33,0xD8, 0xC0,0x32,
++0x6A,0x00, 0xEE,0x00, 0x33,0xD9, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
++0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x30,0xFD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0x31,0x00, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
++0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x31,0x44, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x31,0x38, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x31,0x48, 0xF3,0x05,
++0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
++0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
++0x32,0x74, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16,
++0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x31,0xCD, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E,
++0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
++0x0F,0x00, 0xE0,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06,
++0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
++0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
++0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16,
++0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
++0x32,0x2C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
++0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x32,0x74, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x00, 0x32,0x75, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
++0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
++0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x32,0xB1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x32,0xB0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
++0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x32,0xCC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
++0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
++0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x33,0x91, 0xF7,0x05,
++0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x89, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
++0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x33,0x7C, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x33,0x68, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
++0x77,0x00, 0xE0,0x00, 0x33,0x80, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
++0x33,0x90, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06,
++0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x34,0x44, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
++0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x34,0x44, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00,
++0x34,0x44, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xEE,0x00, 0x33,0xF9, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
++0x34,0x00, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84,
++0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35, 0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4,
++0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6, 0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04,
++0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02, 0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2,
++0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85, 0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05,
++0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x20, 0xF5,0x84, 0x7A,0x70, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
++0x37,0x6C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
++0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
++0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
++0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
++0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
++0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
++0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF4,0x86, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF4,0x85, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
++0x74,0x00, 0xE6,0x00, 0x35,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
++0x35,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
++0x00,0x10, 0xE6,0x00, 0x3B,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
++0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
++0x35,0x78, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x35,0x6C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
++0x35,0x7C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
++0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x02, 0xE6,0x00, 0x36,0xA8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC,
++0x0E,0xF4, 0x94,0x96, 0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
++0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
++0xFF,0xDC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
++0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x36,0x01, 0xF4,0x82,
++0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
++0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93,
++0xFF,0xFC, 0xF4,0x86, 0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
++0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38,
++0x60,0x00, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
++0xFF,0xDC, 0x96,0x16, 0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
++0xFF,0xFC, 0x86,0x16, 0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32,
++0x00,0x11, 0xE6,0x00, 0x36,0x60, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
++0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
++0x36,0xA8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
++0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x36,0xA9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
++0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x36,0xE5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
++0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x36,0xE4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xE6,0x00, 0x37,0x00, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
++0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
++0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
++0x3A,0xC1, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00,
++0x00,0x01, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
++0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF4,0x86,
++0x32,0x28, 0xF4,0x85, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
++0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x37,0xBD, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x3B,0x08, 0xC0,0x32,
++0x6A,0x00, 0xEE,0x00, 0x3B,0x09, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
++0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x38,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0x38,0x30, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
++0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x38,0x74, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x38,0x68, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x38,0x78, 0xF4,0x85,
++0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
++0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
++0x39,0xA4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
++0xFF,0xE4, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xDC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x38,0xFD, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
++0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
++0x0F,0x00, 0xE0,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
++0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
++0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xE4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
++0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x96,0x16,
++0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
++0x39,0x5C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
++0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x39,0xA4, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x00, 0x39,0xA5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
++0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
++0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x39,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x39,0xE0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
++0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x39,0xFC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
++0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
++0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3A,0xC1, 0xF7,0x05,
++0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0xB9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
++0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3A,0xAC, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3A,0x98, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
++0x77,0x00, 0xE0,0x00, 0x3A,0xB0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
++0x3A,0xC0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
++0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x3B,0x70, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
++0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3B,0x70, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
++0x3B,0x70, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xEE,0x00, 0x3B,0x29, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
++0x3B,0x30, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
++0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
++0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
++0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF5,0x04,
++0x7A,0x88, 0xF7,0x06, 0x7A,0x2C, 0xF5,0x84, 0x7A,0x90, 0x76,0xA9, 0x00,0x03, 0xA6,0xB6,
++0x70,0x02, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x3B,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x7A,0xA0, 0x00,0x00, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x3F,0x18, 0xC0,0x2E,
++0x6A,0x00, 0xEE,0x00, 0x3F,0x19, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0xF6,0x04,
++0x32,0xC8, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
++0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
++0x3C,0x3D, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x32,0xE0, 0xF6,0x85, 0x7A,0x70, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0x3C,0x40, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
++0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3C,0x84, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3C,0x78, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x3C,0x88, 0xF4,0x85,
++0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
++0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
++0x3D,0xB4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
++0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xE4, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x3D,0x0D, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
++0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
++0x0F,0x00, 0xE0,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
++0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
++0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
++0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x96,0x16,
++0xFF,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xE0, 0x85,0x96, 0xFF,0xE4, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
++0x3D,0x6C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
++0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x3D,0xB4, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x00, 0x3D,0xB5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
++0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
++0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x3D,0xF1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x3D,0xF0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
++0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x3E,0x0C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
++0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
++0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3E,0xD1, 0xF7,0x05,
++0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x3E,0x71, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x3E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3E,0xC9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
++0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3E,0xBC, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3E,0xA8, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
++0x77,0x00, 0xE0,0x00, 0x3E,0xC0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
++0x3E,0xD0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3E,0xD4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
++0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x3F,0x80, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
++0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0x80, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
++0x3F,0x80, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xEE,0x00, 0x3F,0x39, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
++0x3F,0x40, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
++0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
++0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
++0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF5,0x84,
++0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3F,0xE4, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0xD8, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xE0,0x00, 0x3F,0xE8, 0xF5,0x05,
++0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
++0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
++0x41,0x14, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x05,0x2C, 0x0E,0xF4, 0x95,0x16,
++0xFF,0xF4, 0xF7,0x05, 0x7A,0x68, 0x95,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x40,0x6D, 0xF5,0x02, 0x00,0x4C, 0x87,0x2E,
++0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
++0x0F,0x00, 0xE0,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
++0x7A,0x28, 0x95,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
++0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x85,0x16, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
++0x50,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x96,0x16,
++0xFF,0xE8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xE8, 0x85,0x96, 0xFF,0xEC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
++0x40,0xCC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
++0x32,0xC0, 0xF5,0x06, 0xE0,0x30, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0x41,0x14, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x00, 0x41,0x15, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
++0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
++0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x41,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0A, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x41,0x50, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
++0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x41,0x6C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
++0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
++0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x42,0x31, 0xF7,0x05,
++0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x41,0xD1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x41,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x42,0x29, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
++0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x42,0x1C, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x08, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04,
++0x77,0x00, 0xE0,0x00, 0x42,0x20, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
++0x42,0x30, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x42,0x34, 0xF5,0x06, 0x31,0x9C, 0xF5,0x06,
++0x2E,0xE0, 0xF5,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x42,0x74, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
++0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x74, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
++0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x2F,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
++0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x43,0xD0, 0x00,0x00,
++0x00,0x01, 0x20,0x36, 0x00,0x10, 0xE2,0x00, 0x43,0xED, 0x07,0x34, 0x00,0x01, 0x87,0x2E,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x0C, 0x87,0x2E,
++0x00,0x0C, 0xE0,0x00, 0x44,0x14, 0xF4,0x02, 0x00,0x00, 0xC0,0x3A, 0x62,0x00, 0xE6,0x00,
++0x44,0x11, 0xF4,0x02, 0x00,0x00, 0x20,0x36, 0x00,0x10, 0xE6,0x00, 0x44,0x14, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x44,0x14, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
++0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
++0x00,0x01, 0xF7,0x05, 0x35,0x24, 0xF7,0x04, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x05,
++0x35,0x28, 0xF7,0x06, 0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
++0x45,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0D, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x02, 0x4A,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0F, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x4E,0xEC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
++0x00,0x08, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x57,0x64, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x02, 0x00,0x07, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
++0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x2D, 0xF6,0x86,
++0x75,0xF8, 0xE0,0x00, 0x45,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
++0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x5C, 0xF7,0x05, 0x35,0x48, 0xF4,0x86,
++0x33,0x80, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0x6F,0x54, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x80, 0xF4,0x82, 0x00,0x08, 0xF4,0x82,
++0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x45,0x88, 0xF7,0x02, 0x00,0x01, 0xF4,0x85,
++0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0xA0, 0xF4,0x82,
++0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF6,0x84,
++0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82,
++0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36,
++0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2,
++0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00,
++0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
++0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2,
++0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82,
++0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02,
++0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82,
++0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2,
++0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96,
++0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2,
++0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E,
++0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
++0x49,0xF0, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0xA4, 0x00,0x00,
++0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0x95, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
++0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x49,0xF0, 0x00,0x00,
++0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
++0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
++0x47,0x08, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x46,0xFC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
++0x47,0x0C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
++0x47,0x71, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
++0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
++0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
++0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x47,0x69, 0xC6,0x38,
++0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
++0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x0F, 0xE2,0x00, 0x47,0xBD, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
++0x47,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
++0x00,0x08, 0xE0,0x00, 0x49,0x68, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
++0x47,0xCC, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
++0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
++0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
++0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x48,0x1C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
++0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0x48,0x81, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86,
++0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x48,0x81, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x48,0x80, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
++0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x49,0x68, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
++0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x02, 0xE6,0x00, 0x49,0x3C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
++0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
++0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x49,0x11, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
++0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
++0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x47,0xA8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0x5C, 0x07,0x34, 0x14,0x94, 0xF4,0x84,
++0x6F,0x44, 0xE0,0x00, 0x49,0x60, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
++0x48,0x84, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x49,0xA1, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x49,0xA8, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00, 0x49,0xA8, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82,
++0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86,
++0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04,
++0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0x49,0xF1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
++0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x2D, 0xF6,0x86,
++0x75,0xF8, 0xE0,0x00, 0x4A,0x40, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
++0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04,
++0x6F,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x64, 0xF6,0x85,
++0x35,0x48, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x4A,0x70, 0xF7,0x02,
++0x00,0x01, 0xF4,0x82, 0x00,0x08, 0xF4,0x85, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x4A,0x88, 0xF4,0x82, 0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00,
++0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7,
++0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32,
++0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85,
++0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
++0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6,
++0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00,
++0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85,
++0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86,
++0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4,
++0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85,
++0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04,
++0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05,
++0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00,
++0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x4E,0xD8, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
++0x74,0x00, 0xE6,0x00, 0x4B,0x8C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
++0x4B,0x7D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
++0x00,0x10, 0xE6,0x00, 0x4E,0xD8, 0x00,0x00, 0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82,
++0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38,
++0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x4B,0xF0, 0xF7,0x05, 0x35,0x58, 0xF7,0x04,
++0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4B,0xE4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x4B,0xF4, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05,
++0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84,
++0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x4C,0x59, 0x00,0x00, 0x00,0x01, 0x86,0x36,
++0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
++0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4,
++0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38,
++0x00,0x24, 0xE6,0x00, 0x4C,0x51, 0xC6,0x38, 0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04,
++0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00, 0x4C,0xA5, 0x07,0x38,
++0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x4C,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x4E,0x50, 0xF7,0x05,
++0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x4C,0xB4, 0x00,0x00, 0x00,0x01, 0xF7,0x02,
++0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6,
++0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x4D,0x04, 0xF7,0x05, 0x76,0x04, 0xF0,0x05,
++0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36,
++0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF7,0x05,
++0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
++0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4D,0x68, 0xB4,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00,
++0x4E,0x50, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x4E,0x24, 0x05,0xB4,
++0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96,
++0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
++0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32,
++0x00,0x0F, 0xE2,0x00, 0x4D,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00,
++0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
++0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C,
++0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4C,0x90, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84,
++0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x4E,0x44, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00, 0x4E,0x48, 0xF4,0x85,
++0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x4D,0x6C, 0x05,0x28, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0x4E,0x89, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
++0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
++0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4E,0x90, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
++0x4E,0x90, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84,
++0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
++0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x4E,0xD9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
++0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0x82,
++0x00,0x04, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB,
++0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32,
++0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00,
++0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
++0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6,
++0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00,
++0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04,
++0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2,
++0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32,
++0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05,
++0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38,
++0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
++0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32,
++0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x53,0x4C, 0xF7,0x06,
++0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x50,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x7E,
++0x74,0x00, 0xE6,0x00, 0x4F,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
++0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x53,0x4C, 0x00,0x00, 0x00,0x01, 0xFF,0x82,
++0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85,
++0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x50,0x64, 0xF7,0x05,
++0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x50,0x58, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x50,0x68, 0xF4,0x85,
++0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x50,0xCD, 0x00,0x00,
++0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4,
++0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16,
++0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E,
++0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x50,0xC5, 0xC6,0x38, 0x60,0x00, 0x06,0xB4,
++0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00,
++0x51,0x19, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x51,0x2C, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00,
++0x52,0xC4, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x51,0x28, 0x00,0x00,
++0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84,
++0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36,
++0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04,
++0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84,
++0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x51,0x78, 0xF7,0x05,
++0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05,
++0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0x51,0xDD, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A,
++0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0xDD, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x51,0xDC, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A,
++0x00,0x02, 0xEE,0x00, 0x52,0xC4, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
++0x52,0x98, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96,
++0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93,
++0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x52,0x6D, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36,
++0x00,0x14, 0xE0,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
++0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38,
++0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0x04, 0xF7,0x05,
++0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x52,0xB8, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00,
++0x52,0xBC, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x51,0xE0, 0x05,0x28,
++0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x52,0xFD, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
++0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x53,0x04, 0xB4,0xBA,
++0x68,0x02, 0xE0,0x00, 0x53,0x04, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85,
++0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x53,0x4C, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
++0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x53,0x4D, 0x00,0x00,
++0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF4,0x84, 0x35,0x54, 0xF6,0x84,
++0x35,0x4C, 0xF5,0x84, 0x35,0x2C, 0x94,0x82, 0xFF,0x38, 0x76,0xB5, 0x00,0x03, 0xA5,0x2E,
++0x68,0x02, 0x00,0x00, 0x00,0x01, 0x95,0x02, 0xFF,0x3C, 0xF3,0x84, 0x35,0x50, 0xC6,0xAC,
++0x68,0x00, 0x93,0x82, 0xFF,0x40, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02,
++0xFF,0x44, 0x86,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x60,0x00, 0xF7,0x05, 0x35,0x40, 0xF6,0x04, 0x35,0x28, 0x86,0xB6, 0x00,0x04, 0x87,0x32,
++0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x97,0x32, 0x14,0x14, 0x87,0x2E,
++0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x57,0x50, 0x95,0x16,
++0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x54,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x53,0xF5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
++0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x57,0x50, 0x00,0x00,
++0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
++0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
++0x54,0x68, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x54,0x5C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82, 0x00,0x22, 0xE0,0x00,
++0x54,0x6C, 0xF3,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x84, 0x00,0x00, 0xC0,0x3A, 0x3A,0x00, 0xE6,0x00,
++0x54,0xD1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
++0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
++0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
++0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x54,0xC9, 0xC6,0x38,
++0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
++0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x0F, 0xE2,0x00, 0x55,0x1D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
++0x55,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
++0x00,0x08, 0xE0,0x00, 0x56,0xC8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
++0x55,0x2C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
++0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
++0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
++0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x55,0x7C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
++0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0x55,0xE1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x86,
++0x72,0x18, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x55,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0E, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x55,0xE0, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
++0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x56,0xC8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
++0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x02, 0xE6,0x00, 0x56,0x9C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
++0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
++0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x56,0x71, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
++0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
++0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x55,0x08, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x56,0xBC, 0x07,0x34, 0x14,0x94, 0xF3,0x84,
++0x6F,0x44, 0xE0,0x00, 0x56,0xC0, 0xF3,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
++0x55,0xE4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x57,0x01, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x57,0x08, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x57,0x08, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82,
++0x00,0x01, 0xF3,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x86,
++0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x57,0x50, 0xF3,0x85, 0x35,0x30, 0xF7,0x04,
++0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0x57,0x51, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0x87,0x02,
++0xFF,0x38, 0xF3,0x84, 0x35,0x2C, 0xF7,0x05, 0x35,0x54, 0x87,0x1E, 0x00,0x80, 0xF5,0x04,
++0x35,0x4C, 0x27,0x38, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x5A,0x4C, 0x00,0x00,
++0x00,0x01, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
++0x57,0xD8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x57,0xCC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
++0x57,0xDC, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
++0x58,0x41, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
++0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
++0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
++0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x58,0x39, 0xC6,0x38,
++0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
++0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x0F, 0xE2,0x00, 0x58,0x8D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
++0x58,0xA0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
++0x00,0x08, 0xE0,0x00, 0x5A,0x38, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
++0x58,0x9C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
++0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
++0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
++0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x58,0xEC, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
++0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0x59,0x51, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
++0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x59,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x59,0x50, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
++0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5A,0x38, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
++0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x02, 0xE6,0x00, 0x5A,0x0C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
++0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
++0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x59,0xE1, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
++0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
++0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x58,0x78, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5A,0x2C, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
++0x6F,0x44, 0xE0,0x00, 0x5A,0x30, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
++0x59,0x54, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xC4, 0xF3,0x02,
++0x00,0x01, 0xE0,0x00, 0x5D,0xF0, 0x00,0x00, 0x00,0x01, 0x77,0x29, 0x00,0x03, 0xC7,0x1C,
++0x70,0x00, 0x87,0x3A, 0x00,0x04, 0x05,0x28, 0x00,0x01, 0x76,0xA9, 0x00,0x03, 0xF4,0x84,
++0x35,0x54, 0xF6,0x04, 0x35,0x50, 0x94,0x82, 0xFF,0x38, 0xA4,0x1E, 0x68,0x02, 0xC6,0x30,
++0x70,0x00, 0x94,0x02, 0xFF,0x3C, 0x96,0x02, 0xFF,0x40, 0xC6,0x9C, 0x68,0x00, 0x87,0x36,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02, 0xFF,0x44, 0x85,0xB6, 0x00,0x04, 0xF7,0x04,
++0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x35,0x40, 0x85,0xB6,
++0x00,0x04, 0xF5,0x05, 0x35,0x4C, 0xF6,0x84, 0x35,0x28, 0xF6,0x05, 0x35,0x50, 0x87,0x36,
++0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x58,0x00, 0x97,0x36, 0x14,0x14, 0x87,0x1E,
++0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x5E,0x3C, 0x94,0x16,
++0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xF4, 0x00,0x00,
++0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
++0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x5E,0x3C, 0x00,0x00,
++0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
++0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
++0x5B,0x58, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x5B,0x4C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
++0x5B,0x5C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
++0x5B,0xC1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
++0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
++0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
++0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x5B,0xB9, 0xC6,0x38,
++0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
++0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x0F, 0xE2,0x00, 0x5C,0x0D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
++0x5C,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
++0x00,0x08, 0xE0,0x00, 0x5D,0xB8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
++0x5C,0x1C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
++0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
++0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
++0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
++0x5C,0x6C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
++0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0x5C,0xD1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
++0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x5C,0xD1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x5C,0xD0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
++0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5D,0xB8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
++0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x02, 0xE6,0x00, 0x5D,0x8C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
++0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
++0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x5D,0x61, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
++0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
++0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
++0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x5B,0xF8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5D,0xAC, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
++0x6F,0x44, 0xE0,0x00, 0x5D,0xB0, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
++0x5C,0xD4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xF1, 0xF3,0x02,
++0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x5D,0xF4, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x5D,0xF4, 0xF0,0x05, 0x2D,0x38, 0xF3,0x05,
++0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x06, 0x32,0xF4, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x5E,0x3C, 0xF3,0x05, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
++0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x5E,0x3D, 0x00,0x00,
++0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2, 0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00,
++0x5F,0x2C, 0xC5,0xB4, 0x00,0x00, 0x20,0x36, 0x00,0x0F, 0xEE,0x00, 0x5F,0x2C, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0x5F,0x2D, 0x00,0x00, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xEC,0x00, 0x5F,0x48, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32, 0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00,
++0x5F,0x50, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A, 0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
++0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x66,0xF8, 0x96,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
++0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
++0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x16, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x62,0x7C, 0x96,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
++0x66,0xF8, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
++0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x82, 0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x16, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
++0x62,0x7C, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
++0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x61,0x15, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0xE0,0x00, 0x61,0x18, 0x77,0x39,
++0x00,0x02, 0xF7,0x02, 0x00,0xF0, 0xF7,0x05, 0x42,0x28, 0xF7,0x06, 0x40,0x8A, 0xF0,0x3B,
++0x28,0x00, 0xF7,0x06, 0x40,0x8C, 0xF0,0x3B, 0x28,0x00, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
++0x7A,0xC0, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x05, 0x7A,0xB0, 0xF7,0x05, 0x7A,0xC8, 0xF6,0x82,
++0xC3,0x50, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x16, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
++0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04,
++0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x61,0xED, 0x76,0xB1,
++0x00,0x1E, 0x87,0x32, 0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00, 0x61,0xEC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
++0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0x61,0xEC, 0xF5,0x06, 0x35,0xEC, 0xF7,0x04,
++0x42,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x62,0x11, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06,
++0x42,0xA2, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x62,0x68, 0xF7,0x33, 0x28,0x00, 0x87,0x32,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0xE0,0x00, 0x86,0xB2, 0x00,0x08, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x62,0x3C, 0xF6,0x85, 0xE0,0x04, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
++0x62,0x40, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
++0x62,0x65, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x04, 0x42,0x3C, 0xF6,0x84, 0x6F,0x34, 0x07,0x38, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0x62,0xB1, 0xF7,0x05, 0x42,0x3C, 0x87,0x36, 0x00,0x00, 0xF5,0x9E,
++0x00,0x02, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x62,0xBD, 0xF5,0x86, 0x35,0xEC, 0xF7,0x04,
++0x42,0xA0, 0xE0,0x00, 0x62,0xDC, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x62,0xF9, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
++0x63,0x0C, 0xF7,0x33, 0x28,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x63,0x20, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x20, 0x83,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x87,0x1A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x63,0x6C, 0xF7,0x02, 0x00,0x00, 0x83,0x9A, 0x00,0x1C, 0x00,0x00, 0x00,0x01, 0xF3,0x85,
++0x7A,0xC0, 0x84,0x9A, 0x00,0x14, 0xF7,0x05, 0x7A,0xC8, 0xF4,0x85, 0x7A,0xB0, 0xF7,0x05,
++0x7A,0xB8, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x14, 0xF7,0x04,
++0x7A,0xB0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0xF6,0x02,
++0x00,0x00, 0x86,0x9A, 0x00,0x1C, 0xF7,0x04, 0x7A,0xC0, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x18, 0xF7,0x04,
++0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00,
++0x00,0x01, 0x86,0x9A, 0x00,0x20, 0xF7,0x04, 0x7A,0xC8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x20,0x3A, 0x00,0x64, 0xEE,0x00, 0x63,0xD9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x64,0x58, 0x00,0x00, 0x00,0x01, 0x83,0x96,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x64,0x3C, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0x40,0x80, 0xF7,0x05,
++0x40,0x84, 0xF6,0x84, 0x6E,0x50, 0xF4,0x82, 0xFF,0xFF, 0x83,0x1E, 0x00,0x0C, 0xF4,0x85,
++0x4F,0x54, 0x93,0x36, 0x00,0x10, 0x83,0x9E, 0x00,0x10, 0x84,0x96, 0x00,0x00, 0x93,0xB6,
++0x00,0x14, 0x84,0xA6, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x1D,0xDC, 0xF6,0x82,
++0x00,0x64, 0xF6,0x85, 0x4A,0x98, 0xF7,0x05, 0x4A,0x9C, 0x83,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00,
++0x64,0x7C, 0xF3,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA4, 0xF6,0x06, 0x42,0xA6, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0x66,0xE4, 0xF7,0x33, 0x28,0x00, 0x93,0x96, 0xFF,0xF4, 0x84,0x16,
++0x00,0x00, 0xF4,0x86, 0x42,0xC8, 0x94,0x96, 0xFF,0xEC, 0xF3,0x02, 0x00,0x0C, 0x93,0x16,
++0xFF,0xE4, 0x83,0x96, 0x00,0x00, 0x84,0x96, 0xFF,0xF4, 0x87,0x1E, 0x00,0x20, 0x00,0x00,
++0x00,0x01, 0xC0,0x26, 0x72,0x00, 0xEC,0x00, 0x66,0x48, 0xF3,0x86, 0x4A,0x98, 0x84,0xA2,
++0x00,0x24, 0x83,0x16, 0xFF,0xE4, 0xC5,0x04, 0x00,0x00, 0xB4,0x9A, 0x38,0x02, 0xC7,0x18,
++0x38,0x00, 0x83,0x22, 0x00,0x28, 0x83,0x96, 0xFF,0xF4, 0x84,0x96, 0xFF,0xE4, 0x93,0x3A,
++0x00,0x04, 0x93,0xBA, 0x00,0x08, 0xF6,0x04, 0xE0,0x00, 0xF3,0x06, 0x4A,0x98, 0xA6,0xA6,
++0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x32, 0x6A,0x00, 0xE6,0x00, 0x65,0x10, 0xC6,0x38,
++0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x65,0x14, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0x65,0x21, 0x00,0x00, 0x00,0x01, 0xF5,0x02, 0x00,0x00, 0xF6,0x84,
++0xE0,0x00, 0x87,0x32, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0x65,0x5C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x65,0x64, 0x20,0x2E,
++0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0x65,0x65, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0x65,0x75, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
++0x00,0x00, 0xE6,0x00, 0x65,0x88, 0x00,0x00, 0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0x00,0x00,
++0x00,0x01, 0xF3,0x85, 0x4F,0x54, 0x87,0x22, 0x00,0x2C, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x05,0xA0, 0x00,0x2E, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xF4,0x82,
++0x00,0x00, 0x94,0x96, 0xFF,0xDC, 0x83,0x16, 0xFF,0xEC, 0x20,0x26, 0x00,0x07, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0x98,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE2,0x00, 0x66,0x1C, 0xF7,0x37,
++0x28,0x00, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0xC7,0x2C,
++0x40,0x00, 0x86,0xBA, 0x00,0x30, 0x06,0x28, 0x00,0x04, 0x05,0x28, 0x00,0x02, 0x05,0xAC,
++0x00,0x02, 0x83,0x96, 0xFF,0xDC, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x03,0x9C,
++0x00,0x01, 0x93,0x96, 0xFF,0xDC, 0x20,0x1E, 0x00,0x07, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
++0xFF,0xF0, 0xE2,0x00, 0x65,0xE1, 0xF6,0xB3, 0x28,0x00, 0x04,0x20, 0x00,0x1C, 0x84,0x96,
++0xFF,0xEC, 0x83,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xF4, 0x04,0xA4, 0x00,0x14, 0x94,0x96,
++0xFF,0xEC, 0x03,0x18, 0x00,0x0C, 0x93,0x16, 0xFF,0xE4, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
++0x64,0x94, 0x93,0x96, 0xFF,0xF4, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x26,
++0x00,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x4A,0x9C, 0x85,0xA6, 0x00,0x20, 0xF7,0x04,
++0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x04,
++0x7A,0xB8, 0xF6,0x84, 0x7A,0xC8, 0x86,0x26, 0x00,0x18, 0xC6,0xB4, 0x58,0x00, 0x87,0x26,
++0x00,0x1C, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0x47,0x0C,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x66,0xE5, 0xF6,0x85, 0x7A,0xC8, 0x83,0x26,
++0x00,0x08, 0xF7,0x04, 0x6E,0x50, 0xF3,0x05, 0x3B,0x64, 0x83,0xA6, 0x00,0x08, 0xF6,0x82,
++0x00,0x00, 0x93,0xBA, 0x1D,0xDC, 0x84,0xA6, 0x00,0x0C, 0x83,0x16, 0x00,0x00, 0x94,0xBA,
++0x00,0x10, 0x83,0x1A, 0x00,0x10, 0xF6,0x85, 0x7A,0xC8, 0x93,0x3A, 0x00,0x14, 0xF7,0x02,
++0x00,0x01, 0xF7,0x05, 0x40,0x84, 0xF6,0x85, 0x7A,0xC0, 0xF6,0x85, 0x7A,0xB8, 0xF6,0x85,
++0x7A,0xB0, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x08, 0xF3,0x84, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0xF6,0x84,
++0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x67,0x29, 0xF7,0x02,
++0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE8, 0xF5,0x82,
++0x00,0x01, 0xF7,0x04, 0xE0,0x1C, 0x86,0x9E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE9, 0xC5,0x84,
++0x00,0x00, 0x86,0x9E, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x67,0x88, 0x05,0x1C, 0x00,0x10, 0x86,0x9E, 0x00,0x14, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x67,0x8C, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0x99, 0x00,0x00,
++0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xAA, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xD4, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x67,0xDC, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xDD, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0xED, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x68,0x10, 0xF6,0x06,
++0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
++0x75,0xF4, 0x75,0xAC, 0xFF,0xE1, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x68,0x45, 0x95,0x96,
++0xFF,0xF4, 0xF7,0x04, 0x42,0x98, 0xF6,0x06, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x04,0x1C, 0x00,0x20, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00,
++0x68,0xC4, 0xF3,0x06, 0x15,0x54, 0xF5,0x02, 0x00,0x00, 0x05,0x9C, 0x00,0x22, 0xC4,0xAC,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00,
++0x68,0xC0, 0xC6,0xA4, 0x60,0x00, 0xA7,0x26, 0x60,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x05,0x28, 0x00,0x01, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xE8, 0xF7,0x2F,
++0x68,0x00, 0x05,0xAC, 0x00,0x01, 0xE0,0x00, 0x68,0x78, 0x06,0x30, 0x00,0x02, 0xF3,0x06,
++0x15,0x54, 0x93,0x13, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
++0xE0,0x00, 0x93,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x02, 0x00,0x01, 0x93,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x69,0x28, 0xF6,0x06, 0x42,0x9E, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
++0x00,0x00, 0xE6,0x00, 0x69,0x6C, 0xF3,0x06, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x69,0x6D, 0xF0,0x05, 0x42,0x28, 0xF3,0x06, 0x35,0x60, 0xF3,0x05, 0x42,0x30, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x04, 0x6F,0x34, 0xF7,0x04,
++0x42,0x40, 0x86,0x2A, 0x00,0x18, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0xE0,0x1C, 0xF7,0x05,
++0x42,0x40, 0xC0,0x36, 0x62,0x00, 0xEC,0x00, 0x69,0xB5, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
++0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x80, 0xF7,0x02, 0x00,0x01, 0xF7,0x04,
++0xE0,0x1C, 0x86,0xAA, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x7D, 0xC5,0x84, 0x00,0x00, 0x86,0xAA,
++0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x6A,0x14, 0x04,0xA8, 0x00,0x10, 0x86,0xAA, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x6A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x25, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
++0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0x6A,0x60, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x6A,0x68, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x6A,0x69, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x81, 0xC7,0x2C, 0x00,0x00, 0xF5,0x82,
++0x00,0x01, 0xE0,0x00, 0x6A,0x80, 0xC7,0x2C, 0x00,0x00, 0xC7,0x04, 0x00,0x00, 0x20,0x3A,
++0x00,0x00, 0xEE,0x00, 0x6B,0x3D, 0xF6,0x86, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x6B,0x3C, 0xF6,0x82, 0x00,0x00, 0xF6,0x85, 0x40,0x80, 0xF6,0x85,
++0x40,0x84, 0x96,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00,
++0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x86, 0xE0,0x00, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
++0xFF,0xFC, 0xF3,0x82, 0x00,0x02, 0x93,0x93, 0xFF,0xFC, 0x96,0x96, 0xFF,0xF4, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0x86,0x96,
++0xFF,0xF4, 0xF7,0x04, 0x6E,0x50, 0xF3,0x86, 0x35,0xEC, 0xF6,0x85, 0x40,0x90, 0xF6,0x85,
++0x40,0x94, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x85, 0x42,0x28, 0xF7,0x05, 0x3B,0x64, 0xF7,0x04,
++0x42,0x30, 0xF4,0x05, 0x40,0x80, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x6B,0x3D, 0xF3,0x86, 0x35,0x60, 0xF3,0x85, 0x42,0x30, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x6D,0xD9, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x40,0x8C, 0xF6,0x06, 0x40,0x8C, 0x76,0x31,
++0x00,0x1E, 0xF6,0x84, 0x42,0x28, 0x76,0x30, 0xFF,0xE5, 0x06,0xB4, 0x00,0x01, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6B,0xC8, 0xF6,0x85,
++0x42,0x28, 0xF7,0x04, 0x40,0x88, 0xF6,0x86, 0x40,0x8A, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x6D,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x6C,0x35, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x6C,0x34, 0xF4,0x86, 0x36,0x78, 0xF7,0x04, 0x42,0x44, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x6C,0x35, 0xF4,0x82, 0x00,0x01, 0xF4,0xB3, 0x28,0x00, 0xE0,0x00, 0x6D,0x10, 0xF0,0x05,
++0x42,0x2C, 0xF7,0x04, 0x40,0x8C, 0xF5,0x06, 0x40,0x8C, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x6C,0xC1, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x6C,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x2C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x20,0x3A, 0x00,0x09, 0xEE,0x00, 0x6D,0x11, 0xF7,0x05, 0x42,0x2C, 0xF0,0x2B,
++0x28,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0xF6,0x06,
++0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x6D,0x10, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
++0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6D,0x14, 0x20,0x2E,
++0x00,0x00, 0xF7,0x04, 0x40,0x88, 0xF6,0x06, 0x40,0x8A, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x6D,0x15, 0x20,0x2E, 0x00,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0x6D,0xB5, 0xF4,0x86, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x6D,0x59, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0x3C, 0xF6,0x84, 0xE0,0x28, 0xE0,0x00,
++0x6D,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0xF0, 0xF7,0x04, 0xE0,0x28, 0x00,0x00,
++0x00,0x01, 0x76,0xB9, 0x00,0x02, 0xF7,0x04, 0x42,0x28, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x6A,0x00, 0xEC,0x00, 0x6D,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05,
++0x42,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
++0x00,0x19, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x6D,0xB4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF4,0x82, 0xC3,0x50, 0x94,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x16, 0x94,0x93,
++0xFF,0xFC, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86,
++0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x82, 0x74,0x18, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x19, 0x95,0x93,
++0xFF,0xFC, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x74,0xAC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x78,0x00, 0x95,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
++0x78,0xFC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
++0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x82, 0x80,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x86, 0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x81,0x74, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x87,0x74, 0x95,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
++0x94,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
++0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x82, 0x8A,0x00, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x8E,0x08, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x96,0x9C, 0x95,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0xA8, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
++0x9B,0x2C, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
++0x38,0xA8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x82, 0xA2,0xDC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x9E,0x54, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xA3,0xC0, 0x95,0x93,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
++0xA7,0x64, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
++0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x82, 0xAA,0x04, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xAE,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0x4C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x50, 0xF0,0x3B,
++0x28,0x00, 0xF7,0x06, 0x40,0x88, 0xF0,0x3B, 0x28,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x05,
++0x40,0x80, 0xF6,0x05, 0x40,0x84, 0xF7,0x06, 0x3B,0x70, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06,
++0x3B,0x72, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xCA,0x20, 0xF5,0x85, 0x3B,0x74, 0xF7,0x06,
++0x3B,0x78, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x7A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
++0xB1,0x94, 0xF5,0x85, 0x3B,0x7C, 0xF7,0x06, 0x3B,0x80, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
++0x3B,0x82, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x54, 0xF5,0x85, 0x3B,0x84, 0xF7,0x06,
++0x3B,0x88, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x8A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
++0xBE,0xF8, 0xF5,0x85, 0x3B,0x8C, 0xF7,0x06, 0x3B,0x90, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
++0x3B,0x92, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC8,0xF8, 0xF5,0x85, 0x3B,0x94, 0xF7,0x06,
++0x3B,0x98, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x9A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
++0xC5,0xD8, 0xF5,0x85, 0x3B,0x9C, 0xF7,0x06, 0x3B,0xA0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
++0x3B,0xA2, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x70, 0xF5,0x85, 0x3B,0xA4, 0xF7,0x06,
++0x3B,0xA8, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0xAA, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
++0xC1,0xB4, 0xF5,0x85, 0x3B,0xAC, 0x96,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD5,0x40, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
++0x00,0x01, 0x96,0x36, 0x1D,0xDC, 0xF6,0x05, 0x3B,0x64, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
++0x28,0x00, 0x26,0x14, 0x00,0x38, 0xF0,0x33, 0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04,
++0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x72,0x1D, 0xF5,0x02, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
++0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02,
++0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x04, 0x86,0x16, 0x00,0x00, 0xF6,0x82,
++0x00,0xFF, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x6C,0x00, 0xF7,0x33, 0x28,0x00, 0xF7,0x06,
++0xE0,0x06, 0x87,0x3A, 0x00,0x00, 0x06,0xB0, 0x00,0x02, 0xF7,0x37, 0x28,0x00, 0xF6,0x84,
++0x3B,0x64, 0x07,0x30, 0x00,0x04, 0xF6,0xBB, 0x28,0x00, 0x87,0x02, 0xFF,0x34, 0x06,0x30,
++0x00,0x06, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x30, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x27,0x14,
++0x00,0x38, 0xF0,0x3B, 0x28,0x00, 0x97,0x13, 0xFF,0xFC, 0x90,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x73,0x19, 0xF5,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
++0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x1B, 0x95,0x93,
++0xFF,0xFC, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x40, 0x26,0x14, 0x00,0x20, 0x96,0x16, 0xFF,0xC4, 0xF0,0x33,
++0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x96,0x16,
++0xFF,0xBC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
++0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13,
++0xFF,0xFC, 0x86,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x73,0xE5, 0xF6,0x02,
++0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05,
++0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0xF6,0x02, 0x00,0x1B, 0x96,0x13, 0xFF,0xFC, 0xF6,0x06,
++0x42,0x44, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x04, 0xF5,0x82, 0x00,0x00, 0xF5,0x85, 0x40,0x80, 0x95,0x96, 0xFF,0xF4, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCB,0x50, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0xF5,0x02,
++0x00,0x64, 0xF5,0x05, 0x3B,0xB4, 0xF7,0x04, 0x42,0x50, 0xF4,0x86, 0x42,0x50, 0x76,0xA5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x4F,0x5C, 0xF4,0x02, 0x00,0x06, 0xF4,0x05,
++0x42,0x54, 0xF5,0x85, 0x3B,0x6C, 0xF5,0x85, 0x3B,0xB8, 0x95,0x32, 0x00,0x00, 0x95,0xB2,
++0x00,0x04, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x27,
++0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x06,
++0x37,0x04, 0xF4,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2,
++0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x77,0xEC, 0xC5,0x04,
++0x00,0x00, 0x86,0xB2, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF3,0x02, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x75,0x18, 0x04,0xB0, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x75,0x1C, 0x20,0x1A,
++0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x75,0x29, 0x00,0x00,
++0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x64, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x75,0x6C, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x6D, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x75,0x7D, 0x20,0x2A,
++0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x77,0xEC, 0x00,0x00,
++0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14,
++0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0, 0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF5,0x82,
++0x00,0x00, 0x23,0x94, 0x00,0x22, 0xF5,0x9F, 0x28,0x00, 0x03,0xA0, 0x00,0x1A, 0x93,0x96,
++0xFF,0xD4, 0x25,0x94, 0x00,0x22, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x15, 0x00,0x1E, 0xF5,0x9F,
++0x28,0x00, 0xF3,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0xA2, 0x00,0x1C, 0xF5,0x84,
++0xE0,0x04, 0x73,0x99, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
++0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xCC, 0x23,0x94, 0x00,0x42, 0x95,0xA2,
++0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96,
++0xFF,0xB4, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96, 0xFF,0xC4, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A,
++0x00,0x00, 0xC4,0xA0, 0x4A,0x00, 0x74,0xA4, 0xFF,0xFA, 0xC5,0xA4, 0x00,0x00, 0xF5,0x9F,
++0x28,0x00, 0x83,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x85,0x96, 0xFF,0xB4, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xCC, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x96, 0xFF,0xC4, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82,
++0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x04,0x20, 0x00,0x18, 0x25,0x94, 0x00,0x22, 0x85,0xAE,
++0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD,
++0xFF,0xF0, 0x83,0x96, 0xFF,0xD4, 0xF5,0xA3, 0x28,0x00, 0xF4,0x9F, 0x28,0x00, 0x25,0x94,
++0x00,0x42, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC,
++0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x44,0xAD, 0x00,0x00, 0x94,0x93, 0xFF,0xFC, 0xF7,0x86,
++0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x40,0x84, 0xF7,0x86,
++0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x04, 0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x87,0x3A, 0x1D,0xDC, 0x00,0x00,
++0x00,0x01, 0xF7,0x05, 0x3B,0x64, 0xF5,0x86, 0x36,0x78, 0xF5,0x85, 0x42,0x44, 0xF3,0x86,
++0x35,0x60, 0xF3,0x85, 0x42,0x30, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x78,0x89, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xEE,0x00, 0x78,0x51, 0xF6,0x06, 0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x78,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85,
++0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
++0x37,0x90, 0xF5,0x85, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF6,0x06, 0x36,0x78, 0xF6,0x05, 0x42,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
++0x40,0x80, 0xF7,0x05, 0x40,0x94, 0xF6,0x84, 0x6E,0x50, 0xF7,0x05, 0x40,0x90, 0x97,0x36,
++0x1D,0xDC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
++0x00,0x01, 0xF7,0x05, 0x40,0x80, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0xA8, 0xF7,0x04, 0x42,0x50, 0xF5,0x86, 0x42,0x50, 0x76,0xAD,
++0x00,0x1E, 0xF4,0x84, 0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xC4, 0xC7,0x38,
++0x6F,0xC0, 0x86,0xA6, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x79,0x55, 0xF6,0x06, 0x42,0x9A, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0xF7,0x04, 0x42,0x50, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16,
++0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0xAA, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x80,0xA8, 0xF6,0x06, 0x42,0x9A, 0x87,0x2A, 0x00,0x10, 0x86,0x2A,
++0x00,0x1C, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xA8, 0xF6,0x82, 0x00,0x00, 0x87,0x2A,
++0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xAC, 0x20,0x36,
++0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x7A,0x05, 0x24,0x94,
++0x00,0x20, 0x94,0x96, 0xFF,0xBC, 0x85,0x16, 0xFF,0xC4, 0xF0,0x27, 0x28,0x00, 0x05,0x28,
++0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x94,0x93,
++0xFF,0xFC, 0x85,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x80,0xC4, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x80,0x6C, 0x00,0x00, 0x00,0x01, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
++0x28,0x00, 0x04,0xA0, 0x00,0x02, 0x94,0x96, 0xFF,0x5C, 0xF0,0x27, 0x28,0x00, 0xF4,0x82,
++0x00,0x00, 0x25,0x14, 0x00,0x5A, 0xF4,0xAB, 0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x25,0x14,
++0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28,
++0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x23,0x14,
++0x00,0x1E, 0x76,0x19, 0x00,0x1E, 0xF5,0x3B, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x76,0x30,
++0xFF,0xE5, 0x94,0xA2, 0x00,0x1C, 0xF5,0x04, 0xE0,0x04, 0x84,0x96, 0xFF,0x5C, 0x95,0x22,
++0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
++0xFF,0x9C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x74,0x95,
++0x00,0x1E, 0x85,0x16, 0xFF,0x5C, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x8C, 0x84,0x96,
++0xFF,0x54, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x94, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
++0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF5,0x3B,
++0x28,0x00, 0x94,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
++0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x24,0x94, 0x00,0x5A, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x05,0xA0,
++0x00,0x02, 0x06,0xAC, 0x00,0x02, 0x23,0x94, 0x00,0x36, 0x75,0x1D, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x07,0x20, 0x00,0x1A, 0xF4,0xB3, 0x28,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
++0xFF,0x5C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x74,0x95,
++0x00,0x1E, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x74, 0x85,0x2A,
++0x00,0x34, 0x24,0x94, 0x00,0x5A, 0x95,0x16, 0xFF,0x84, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x25,0x14,
++0x00,0x5A, 0xF4,0xAF, 0x28,0x00, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
++0x28,0x00, 0x84,0xA6, 0x00,0x10, 0x85,0x16, 0xFF,0xC4, 0x94,0xA2, 0x00,0x1C, 0x85,0x2A,
++0x00,0x14, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x6C, 0x95,0x22,
++0x00,0x20, 0x87,0x16, 0xFF,0xC8, 0x85,0x16, 0xFF,0x54, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x84,0x96, 0xFF,0x5C, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0xCC, 0x23,0x94, 0x00,0x32, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x85,0x16,
++0xFF,0x7C, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD0, 0x23,0x94, 0x00,0x2E, 0x76,0x1D,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x74, 0x85,0x16,
++0xFF,0x6C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x23,0x94, 0x00,0x2A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x16, 0xFF,0xD8, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3, 0x28,0x00, 0x07,0x20,
++0x00,0x18, 0x25,0x14, 0x00,0x7A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
++0x28,0x00, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xF7,0x04,
++0x4F,0x58, 0xE6,0x00, 0x7E,0xF9, 0x94,0x16, 0xFF,0x54, 0xC7,0x20, 0x72,0x00, 0xF6,0x84,
++0x6E,0x50, 0x86,0x26, 0x00,0x2C, 0x77,0x38, 0xFF,0xFA, 0x25,0x14, 0x00,0x5A, 0x84,0x2A,
++0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0x20, 0x7F,0xC0, 0x74,0x21,
++0xFF,0xF0, 0x47,0x39, 0x00,0x00, 0x86,0xB6, 0x1D,0xDC, 0x77,0x39, 0x00,0x02, 0xC0,0x32,
++0x6A,0x00, 0x46,0x8C, 0x00,0x01, 0xD6,0x80, 0x0A,0x68, 0x20,0x36, 0x00,0x00, 0xF6,0x86,
++0x40,0x98, 0xE6,0x00, 0x7E,0xC0, 0xC3,0xB8, 0x68,0x00, 0xC5,0x84, 0x00,0x00, 0x86,0xA6,
++0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x7E,0x54, 0x03,0x24, 0x00,0x24, 0x86,0xA6, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x7E,0x58, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0x65, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
++0x00,0x00, 0x86,0x9A, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0x7E,0xA0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x7E,0xA8, 0x20,0x32, 0x00,0x00, 0x86,0x9A, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x7E,0xA9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0xB9, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x7E,0xC5, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
++0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x1F, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0x85,0x16,
++0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x2A,
++0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
++0x7F,0x4C, 0xF6,0x3B, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0xF6,0x06, 0x40,0x98, 0xC7,0x24,
++0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0xB8, 0x00,0x00, 0x46,0xB5, 0x00,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x37, 0x28,0x00, 0x47,0x39,
++0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x24,0x94, 0x00,0x5A, 0x84,0xA6,
++0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5,
++0xFF,0xF0, 0x07,0x38, 0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x85,0x16,
++0xFF,0x54, 0x84,0x96, 0xFF,0xAC, 0xC6,0xA8, 0x72,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x24,
++0x00,0x1A, 0xF6,0xB3, 0x28,0x00, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x06,0xA8,
++0x00,0x1A, 0xF7,0x37, 0x28,0x00, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24,
++0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x72,0x00, 0x77,0x38,
++0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x1C, 0x97,0x13,
++0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x1D,0xDC, 0x87,0x36,
++0x1D,0xDC, 0xF0,0x05, 0x40,0x84, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0xF7,0x04,
++0x6E,0x50, 0xF0,0x05, 0x42,0x5C, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x86, 0x2C,0x28, 0xF7,0x05,
++0x3B,0x64, 0xF7,0x04, 0x2D,0x38, 0xF5,0x06, 0x3A,0x4C, 0xF5,0x05, 0x42,0x44, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x1C, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x80,0x60, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06,
++0x35,0xEC, 0xE0,0x00, 0x80,0x8C, 0xF5,0x05, 0x42,0x30, 0x20,0x32, 0x00,0x01, 0xE6,0x00,
++0x80,0xC4, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
++0xFF,0xFC, 0xF4,0x86, 0x35,0x60, 0xF4,0x85, 0x42,0x30, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0x80,0xC4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86,
++0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x81,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x81,0x29, 0xF6,0x06,
++0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0x81,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85, 0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0xF5,0x85, 0x42,0x44, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x58, 0xF7,0x04,
++0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04,
++0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x82,0x50, 0xF4,0x82, 0x00,0x00, 0xC5,0x04, 0x00,0x00, 0x86,0xB2,
++0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xC5,0xA4, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x81,0xE4, 0x04,0x30, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x81,0xE8, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x81,0xF5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
++0x00,0x00, 0x86,0xA2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0x82,0x30, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0x82,0x38, 0x20,0x32, 0x00,0x00, 0x86,0xA2, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x82,0x39, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x82,0x49, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
++0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x82,0x59, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
++0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x87,0x60, 0x00,0x00, 0x00,0x01, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
++0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x05, 0x3B,0xB0, 0x06,0xA0, 0x00,0x14, 0xC7,0x20,
++0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x16, 0xF7,0x37,
++0x28,0x00, 0xF3,0x02, 0x00,0x01, 0xF3,0x23, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0,
++0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF3,0x02, 0x00,0x00, 0x23,0x94, 0x00,0x2A, 0xF3,0x1F,
++0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0xF3,0xBB,
++0x28,0x00, 0xF3,0x04, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0x22, 0x00,0x1C, 0xF3,0x84,
++0xE0,0x04, 0x23,0x14, 0x00,0x1E, 0x93,0x16, 0xFF,0xA4, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
++0xFF,0xA4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
++0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96,
++0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x94, 0x00,0x1A, 0x93,0x96, 0xFF,0xA4, 0x76,0x1D,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
++0x00,0x16, 0x93,0x16, 0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xAC, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x93,0x16,
++0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xCC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16,
++0xFF,0xF0, 0x83,0x16, 0xFF,0xC4, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82, 0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x23,0x14,
++0x00,0x2A, 0x83,0x1A, 0x00,0x00, 0x77,0x99, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18,
++0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF3,0x3B, 0x28,0x00, 0x94,0x16,
++0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20,
++0x00,0x02, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x24,0x80, 0x00,0x07, 0x05,0x20,
++0x00,0x0A, 0xF3,0xBB, 0x28,0x00, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x84,0xE0, 0x06,0x28,
++0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1,
++0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4, 0x00,0x01, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3,
++0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0xC7,0x38, 0x34,0x00, 0xE0,0x00, 0x84,0x88, 0xF7,0x33, 0x28,0x00, 0x05,0x20,
++0x00,0x26, 0x86,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0xF5,0x84, 0x4F,0x58, 0x76,0xB4,
++0xFF,0xE5, 0x83,0x96, 0xFF,0xDC, 0xF3,0x02, 0x00,0xFF, 0x94,0x16, 0xFF,0xBC, 0xC7,0x1C,
++0x5A,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
++0x00,0x00, 0xC7,0x38, 0x34,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30, 0x6C,0x00, 0xC7,0x38,
++0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2B, 0x28,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
++0xFF,0xFA, 0x83,0x16, 0xFF,0xDC, 0x07,0x34, 0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x20,
++0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x20, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x82,
++0x00,0x03, 0xF3,0xA3, 0x28,0x00, 0x07,0x18, 0x00,0x1A, 0xF5,0xBB, 0x28,0x00, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
++0x28,0x00, 0x24,0x80, 0x00,0x07, 0x05,0x20, 0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00,
++0x85,0xD4, 0x06,0x28, 0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4,
++0x00,0x01, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
++0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x82, 0x00,0xFF, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xE0,0x00, 0x85,0x7C, 0xF7,0x33,
++0x28,0x00, 0x05,0xA0, 0x00,0x26, 0x86,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC5,0x20, 0x00,0x00, 0x24,0x00, 0x00,0x07, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
++0xFF,0xA4, 0xF7,0x04, 0x4F,0x58, 0x83,0x96, 0xFF,0xBC, 0x24,0x80, 0x00,0x0E, 0xC7,0x1C,
++0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
++0x00,0x00, 0xF6,0x82, 0x00,0xFF, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30,
++0x6C,0x00, 0xC7,0x38, 0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2F, 0x28,0x00, 0x07,0x34,
++0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x28, 0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x28,
++0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x02, 0x00,0x03, 0xF3,0x2B, 0x28,0x00, 0x20,0x22,
++0x00,0x07, 0xEE,0x00, 0x86,0x94, 0xC6,0x28, 0x48,0x00, 0x06,0x30, 0x00,0x26, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x04,0x20,
++0x00,0x01, 0x83,0x96, 0xFF,0xA4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82,
++0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC7,0x1C, 0x70,0x00, 0xE0,0x00, 0x86,0x50, 0xF7,0x33,
++0x28,0x00, 0x06,0x28, 0x00,0x26, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
++0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0xF3,0x04, 0x3B,0xB0, 0x00,0x00,
++0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xB4, 0xF0,0x05, 0x40,0x7C, 0x83,0x96,
++0xFF,0xBC, 0x23,0x00, 0x00,0x07, 0xF3,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x50, 0xF6,0x06,
++0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x39,0x34, 0xF3,0x05,
++0x42,0x44, 0xF5,0x05, 0x40,0x74, 0xF3,0x85, 0x42,0x60, 0xF3,0x82, 0x00,0x06, 0xF3,0x85,
++0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06,
++0x2C,0x28, 0x76,0xB5, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0x87,0x4C, 0xB3,0xB6, 0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x06, 0x42,0x44, 0x93,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x48, 0xF3,0x86,
++0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x89,0xED, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x87,0xC9, 0x00,0x00,
++0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0x89,0xEC, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
++0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x05,0xA0, 0x00,0x02, 0xF0,0x2F,
++0x28,0x00, 0xF3,0x82, 0x00,0x00, 0x24,0x94, 0x00,0x22, 0xF3,0xA7, 0x28,0x00, 0x04,0xA0,
++0x00,0x1A, 0x94,0x96, 0xFF,0xD4, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xAC, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x19,
++0x00,0x1E, 0xF3,0xA7, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x94,0xA2,
++0x00,0x1C, 0xF3,0x84, 0xE0,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
++0xFF,0xB4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xCC, 0x84,0x96,
++0xFF,0xB4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
++0xFF,0xE5, 0x93,0x96, 0xFF,0xBC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
++0xFF,0xC4, 0x83,0x96, 0xFF,0xBC, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F,
++0x28,0x00, 0xF5,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
++0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x45,0xAD, 0x00,0x00, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0xCC, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
++0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
++0x28,0x00, 0x04,0x20, 0x00,0x18, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x84,0x96,
++0xFF,0xD4, 0xF3,0xA3, 0x28,0x00, 0xF3,0x82, 0x00,0x01, 0xF3,0xA7, 0x28,0x00, 0x95,0x93,
++0xFF,0xFC, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x86,
++0x36,0x78, 0xF4,0x85, 0x42,0x44, 0xF0,0x05, 0x40,0x84, 0xF6,0x84, 0x4F,0x5C, 0xF7,0x02,
++0x00,0x64, 0x97,0x36, 0x00,0x00, 0x90,0x36, 0x00,0x04, 0xF7,0x02, 0x00,0x01, 0xF7,0x05,
++0x40,0x84, 0xF3,0x86, 0x35,0xEC, 0xF3,0x85, 0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF7,0x04, 0x42,0x60, 0xF5,0x02,
++0x00,0x00, 0x05,0xB8, 0x00,0x18, 0xF6,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x32,
++0x00,0x07, 0xEE,0x00, 0x8A,0x70, 0xC7,0x30, 0x60,0x00, 0xC7,0x38, 0x58,0x00, 0x07,0x38,
++0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0xC0,0x36,
++0x52,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x8A,0x71, 0x07,0x30, 0x00,0x01, 0xE0,0x00, 0x8A,0x18, 0xF7,0x05, 0x42,0x58, 0xF4,0x04,
++0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x07, 0xEE,0x00, 0x8D,0x94, 0x24,0x94,
++0x00,0x36, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x38, 0x23,0x94, 0x00,0x20, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
++0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
++0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
++0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0x7C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x7E, 0x25,0x14, 0x00,0x80, 0x23,0x94,
++0x00,0x68, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7C, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7A, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x78, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x76, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x74, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x72, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0x74, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x42,0x58, 0x23,0x94, 0x00,0x50, 0xC7,0x00, 0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0x6C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFF,0x6C, 0xF6,0x86, 0x42,0x50, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
++0x42,0x58, 0x76,0xB5, 0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96,
++0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x8D,0x95, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00,
++0x8D,0xD4, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0x8D,0xF4, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x8D,0xF4, 0xF0,0x05,
++0x2D,0x38, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86,
++0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x88, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0xF3,0x84,
++0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x93,0x96, 0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0x9E,
++0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x8E,0x65, 0xF6,0x06,
++0x42,0xA0, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x94,0xE4, 0xF7,0x33,
++0x28,0x00, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x36, 0x85,0x16, 0xFF,0xC4, 0x23,0x94,
++0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x85,0x2A, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x95,0x16, 0xFF,0xBC, 0xF7,0x1F, 0x28,0x00, 0x87,0x32,
++0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x85,0x16, 0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
++0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14, 0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00,
++0x00,0x01, 0x87,0x1E, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0x8F,0xF0, 0xF6,0x82, 0x00,0x00, 0x87,0x1E, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0x8F,0xF4, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0x90,0x41, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xC4, 0x00,0x00,
++0x00,0x01, 0x05,0x28, 0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x27,0x14,
++0x00,0x20, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16,
++0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x94,0xBC, 0x00,0x00,
++0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x02,
++0x00,0x00, 0x23,0x94, 0x00,0x62, 0xF5,0x1F, 0x28,0x00, 0x75,0x95, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0x06,0x20, 0x00,0x02, 0x06,0xB0, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x73,0x99,
++0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x74, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
++0xFF,0x8C, 0x85,0x16, 0xFF,0xC4, 0x73,0x95, 0x00,0x1E, 0x93,0x96, 0xFF,0x84, 0x85,0x2A,
++0x00,0x34, 0x23,0x94, 0x00,0x62, 0x95,0x16, 0xFF,0xAC, 0xF0,0x33, 0x28,0x00, 0x05,0x20,
++0x00,0x1A, 0x95,0x16, 0xFF,0x94, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x74,0x95, 0x00,0x1E, 0xF3,0xAB,
++0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x85,0x2A, 0x00,0x10, 0x83,0x96,
++0xFF,0xC4, 0x95,0x22, 0x00,0x1C, 0x83,0x9E, 0x00,0x14, 0x85,0x16, 0xFF,0x84, 0x93,0xA2,
++0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x84, 0xF3,0x84,
++0x4F,0x58, 0x85,0x16, 0xFF,0x74, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96, 0xFF,0xA4, 0xC0,0x22, 0x3A,0x00, 0x83,0x96,
++0xFF,0x7C, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0x83,0x96,
++0xFF,0x84, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF5,0x02, 0x00,0x02, 0xF5,0x23, 0x28,0x00, 0x23,0x94,
++0x00,0x52, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
++0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x03,0x20, 0x00,0x18, 0xE6,0x00, 0x92,0x30, 0xF3,0x9B,
++0x28,0x00, 0xF7,0x04, 0x42,0x70, 0xE0,0x00, 0x92,0x9C, 0xF6,0x06, 0x42,0x72, 0x85,0x16,
++0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0xAA, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x07,0x34,
++0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00, 0x92,0x94, 0xC7,0x34, 0x68,0x00, 0xF5,0x84,
++0x42,0x60, 0xF3,0x82, 0x00,0xFF, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
++0x00,0x00, 0x97,0x16, 0xFF,0x74, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x3C,0x00, 0x20,0x36, 0x00,0x00, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x92,0xC9, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x42,0x74, 0xF6,0x06, 0x42,0x74, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xA4, 0x83,0x96, 0xFF,0x74, 0xC7,0x20,
++0x52,0x00, 0x74,0xB8, 0xFF,0xFA, 0xC6,0x24, 0x00,0x00, 0x87,0x1E, 0x00,0x00, 0x76,0x9D,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x52,0x00, 0x75,0xAC, 0xFF,0xFA, 0x46,0x31,
++0x00,0x00, 0xF5,0x02, 0x00,0xFF, 0xC6,0x30, 0x54,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x1F,
++0x28,0x00, 0x83,0x96, 0xFF,0x94, 0x85,0x16, 0xFF,0xC4, 0xF5,0x9F, 0x28,0x00, 0x87,0x2A,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xE6,0x00, 0x94,0x69, 0xF6,0x86,
++0x40,0x98, 0xF7,0x04, 0x6E,0x50, 0x86,0x2A, 0x00,0x2C, 0xC6,0xA4, 0x00,0x00, 0x23,0x94,
++0x00,0x62, 0x84,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4,
++0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x46,0xB5, 0x00,0x00, 0x87,0x3A, 0x1D,0xDC, 0x76,0xB5,
++0x00,0x02, 0xC0,0x32, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
++0x00,0x00, 0xF7,0x06, 0x40,0x98, 0xE6,0x00, 0x94,0x34, 0xC3,0x34, 0x70,0x00, 0xC5,0x84,
++0x00,0x00, 0x86,0xAA, 0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0x05,0x28, 0x00,0x24, 0xE6,0x00, 0x93,0xC4, 0x95,0x16, 0xFF,0x74, 0x83,0x96,
++0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0x9E, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x93,0xC8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x93,0xD5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
++0x00,0x00, 0x85,0x16, 0xFF,0x74, 0xF7,0x04, 0xE0,0x00, 0x86,0xAA, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x14, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0x94,0x1C, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x1D, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x94,0x2D, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x94,0x39, 0x00,0x00,
++0x00,0x01, 0xF4,0x82, 0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x9B, 0x28,0x00, 0x83,0x96,
++0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x1E,
++0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
++0x94,0xE4, 0xF6,0x3B, 0x28,0x00, 0x47,0x25, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
++0x68,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0x23,0x94,
++0x00,0x62, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
++0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x25,0x14, 0x00,0x62, 0xF3,0xBB, 0x28,0x00, 0x85,0x2A,
++0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29,
++0xFF,0xF0, 0xE0,0x00, 0x94,0xE4, 0xF5,0x1B, 0x28,0x00, 0x83,0x96, 0xFF,0xBC, 0x00,0x00,
++0x00,0x01, 0x20,0x1E, 0x00,0x01, 0xE6,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x35,0x60, 0xF5,0x05,
++0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x06,
++0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x96,0x89, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
++0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEE,0x00, 0x95,0x8D, 0xF5,0x86,
++0x42,0x50, 0xF7,0x04, 0x42,0x50, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x26,0xB4,
++0x00,0x01, 0xF6,0x85, 0x42,0x54, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF6,0x84,
++0x2D,0x38, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x2F,
++0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
++0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x96,0x88, 0xB5,0x36,
++0x70,0x02, 0xE0,0x00, 0x96,0x88, 0xF0,0x05, 0x2D,0x38, 0xF5,0x04, 0x42,0x60, 0x00,0x00,
++0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB2,0x84, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x34, 0x00,0x40, 0xC0,0x22,
++0x72,0x00, 0xE6,0x00, 0x95,0xEC, 0xF6,0x06, 0x42,0x76, 0xF7,0x04, 0x42,0x74, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x60, 0x00,0x00,
++0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00, 0x96,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0xF5,0x04, 0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x40, 0x00,0x00,
++0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE6,0x00, 0x96,0x71, 0x00,0x00, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04,
++0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF5,0x04,
++0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xC1,0xB4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x70, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x9B,0x18, 0x06,0xB0,
++0x00,0x02, 0x87,0x36, 0x00,0x00, 0xF4,0x04, 0x40,0x7C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00,
++0x9B,0x18, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x23,0x94, 0x00,0x38, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
++0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
++0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14,
++0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04,
++0x40,0x74, 0x94,0x16, 0xFF,0xC4, 0x07,0x20, 0x00,0x02, 0xF0,0x3B, 0x28,0x00, 0x24,0x80,
++0x00,0x07, 0xF4,0x02, 0x00,0xFF, 0x83,0x96, 0xFF,0xC4, 0x95,0x16, 0xFF,0xBC, 0x03,0x1C,
++0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x98,0xA8, 0x06,0x18, 0x00,0x0E, 0x86,0xB2,
++0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
++0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x04,0xA4,
++0x00,0x01, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x44,0x00, 0xE0,0x00,
++0x98,0x54, 0xF7,0x33, 0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
++0xFF,0xE5, 0x83,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x1E, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
++0xFF,0xE5, 0x05,0x28, 0x00,0x26, 0x95,0x16, 0xFF,0x8C, 0x85,0xAA, 0x00,0x00, 0x76,0xA9,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x03,0x9C, 0x00,0x02, 0x93,0x96, 0xFF,0xB4, 0x06,0x1C,
++0x00,0x02, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
++0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x9C, 0x83,0x96, 0xFF,0xBC, 0x75,0x15,
++0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x95,0x16, 0xFF,0xA4, 0x85,0x16, 0xFF,0xC4, 0xC5,0xAC, 0x6F,0xC0, 0x75,0xAD,
++0xFF,0xF0, 0xF5,0x05, 0x42,0x60, 0xF5,0x04, 0x4F,0x58, 0xF6,0x82, 0x00,0xFF, 0xC7,0x1C,
++0x52,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82,
++0xFF,0x00, 0xC5,0xAC, 0x6C,0x00, 0xC7,0x38, 0x58,0x00, 0x83,0x96, 0xFF,0x8C, 0xF5,0x84,
++0x3B,0x6C, 0x85,0x16, 0xFF,0xB4, 0xF7,0x1F, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x06,0xAC,
++0x00,0x01, 0xF6,0x85, 0x3B,0x6C, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xF5,0x04, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC0,0x1E,
++0x52,0x00, 0xC7,0x38, 0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
++0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x99, 0x00,0x1E, 0x83,0x96,
++0xFF,0x94, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
++0x00,0x16, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16, 0xFF,0xAC, 0x83,0x96,
++0xFF,0xA4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x06,0x30, 0x00,0x02, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14,
++0x00,0x12, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0x83,0x96,
++0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16,
++0xFF,0xF0, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
++0x28,0x00, 0x07,0x1C, 0x00,0x3A, 0xF5,0xBB, 0x28,0x00, 0x07,0x1C, 0x00,0x36, 0xF0,0x3B,
++0x28,0x00, 0xF5,0x02, 0x00,0x03, 0xE6,0x00, 0x9A,0xA4, 0xF5,0x1F, 0x28,0x00, 0xF7,0x04,
++0x42,0x78, 0xF6,0x06, 0x42,0x78, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9B,0x18, 0x00,0x00,
++0x00,0x01, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF7,0x04,
++0x42,0x50, 0xF6,0x06, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x82,
++0x00,0x06, 0xF3,0x85, 0x42,0x54, 0xF5,0x06, 0x39,0x34, 0xF5,0x05, 0x42,0x44, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
++0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x9B,0x18, 0xB3,0xB6,
++0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x78, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0x9E,0x41, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xEE,0x00, 0x9D,0x85, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14,
++0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
++0xFF,0x94, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94,
++0x00,0x68, 0x93,0x96, 0xFF,0x8C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x84, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
++0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x84, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0x9D,0x5D, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
++0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00,
++0x00,0x01, 0xF5,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC7,0x28, 0x50,0x00, 0xC7,0x24,
++0x70,0x00, 0x05,0xB8, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xE6,0x00,
++0x9D,0xFD, 0xF6,0x02, 0x00,0xFF, 0xF7,0x04, 0x42,0x78, 0xF6,0x06, 0x42,0x7A, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
++0x00,0x01, 0xC7,0x38, 0x64,0x00, 0xF6,0x02, 0xFF,0x00, 0xC6,0xB4, 0x64,0x00, 0xC7,0x38,
++0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0x07,0x28, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x94,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xD8, 0xF3,0x86,
++0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA2,0xC9, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xA0,0x35, 0x24,0x94,
++0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14, 0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1,
++0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32,
++0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
++0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96, 0xFF,0x4C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x44, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
++0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x44, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xA2,0x80, 0x93,0x93,
++0xFF,0xFC, 0xF4,0x04, 0x40,0x7C, 0xF6,0x04, 0x40,0x74, 0xF3,0x82, 0x00,0x00, 0xC7,0x20,
++0x40,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E,
++0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xA0,0xAD, 0x93,0x96, 0xFF,0x3C, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06, 0x42,0xA0, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0xA2,0xC8, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x7E, 0x25,0x14,
++0x00,0x80, 0x23,0x94, 0x00,0x68, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
++0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
++0x00,0x7C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
++0x00,0x7A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
++0x00,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
++0x00,0x76, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
++0x00,0x74, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
++0x00,0x72, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13,
++0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x34, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0xB0, 0x93,0x96, 0xFF,0x2C, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0x2C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x3C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x98, 0x93,0x96, 0xFF,0x24, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
++0x00,0x06, 0xF3,0x85, 0x42,0x54, 0x87,0x02, 0xFF,0x34, 0xF3,0x86, 0x38,0xA8, 0xF3,0x85,
++0x42,0x44, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0xA2,0xA9, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
++0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xA3,0xAC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
++0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0xF6,0x84,
++0x40,0x7C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0xA3,0xAC, 0xC7,0x34,
++0x68,0x00, 0xF5,0x84, 0x40,0x74, 0xF6,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC6,0x2C,
++0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0xAC, 0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
++0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02,
++0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0xF5,0x06,
++0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0xF5,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x80, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA3,0xF4, 0x20,0x3A, 0x00,0x07, 0xF5,0x02,
++0x00,0x01, 0xF5,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x07, 0xEE,0x00, 0xA6,0xF0, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x23,0x14,
++0x00,0x66, 0xF4,0x84, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x74,0x25, 0x00,0x1E, 0x74,0x20,
++0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16,
++0xFF,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x25,0x14, 0x00,0x20, 0x95,0x16,
++0xFF,0x94, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x85,0x16, 0xFF,0x7C, 0x05,0xA4,
++0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
++0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x25,0x14, 0x00,0x50, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
++0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
++0x00,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
++0x00,0x62, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
++0x00,0x60, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
++0x00,0x5E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
++0x00,0x5C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
++0x00,0x5A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x05,0xAC,
++0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x58, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
++0xFF,0xFC, 0x95,0x16, 0xFF,0x8C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
++0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x25,0x14,
++0x00,0x38, 0x95,0x16, 0xFF,0x84, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13,
++0xFF,0xFC, 0xF5,0x04, 0x42,0x64, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
++0xFF,0x84, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16, 0xFF,0x94, 0x00,0x00,
++0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA6,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04,
++0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00, 0xA7,0x30, 0xF5,0x02,
++0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
++0xA7,0x50, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00, 0xA7,0x50, 0xF0,0x05, 0x2D,0x38, 0x95,0x13,
++0xFF,0xFC, 0xF5,0x02, 0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0xF6,0x04,
++0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0xA9,0xF0, 0x07,0x30, 0x00,0x02, 0x86,0x3A, 0x00,0x00, 0xF5,0x82,
++0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x30,
++0x77,0xC0, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0x76,0x31, 0xFF,0xF0, 0xC6,0x00,
++0x62,0x00, 0x96,0x16, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
++0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0xA8,0x34, 0xF6,0x02, 0x00,0xFF, 0x83,0x16, 0xFF,0xF4, 0x83,0x96,
++0xFF,0xF4, 0xF7,0x04, 0x40,0x78, 0xC6,0x98, 0x38,0x00, 0xC7,0x38, 0x68,0x00, 0x07,0x38,
++0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x64,0x00, 0xC0,0x36, 0x5A,0x00, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA8,0x3D, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xA8,0x75, 0xF6,0x06,
++0x42,0x7C, 0xF7,0x04, 0x42,0x7C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xA9,0xF0, 0x00,0x00,
++0x00,0x01, 0xF3,0x04, 0x42,0x60, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF4,0x04, 0x40,0x78, 0xF7,0x04,
++0x4F,0x58, 0xF5,0x04, 0x40,0x74, 0xF3,0x84, 0x40,0x7C, 0xF3,0x04, 0x40,0x7C, 0xC6,0x20,
++0x72,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0x9C, 0x30,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC,
++0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x74,0xAD, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x73,0xAD,
++0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xD4, 0xC5,0x28, 0x72,0x00, 0x75,0x28,
++0xFF,0xFA, 0x83,0x16, 0xFF,0xF4, 0x83,0x96, 0xFF,0xF4, 0x46,0x31, 0x00,0x00, 0x45,0x29,
++0x00,0x00, 0xC7,0x18, 0x38,0x00, 0xC4,0x20, 0x70,0x00, 0x04,0x20, 0x00,0x26, 0x73,0x21,
++0x00,0x1E, 0xC6,0xB4, 0x4F,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC6,0x30,
++0x4C,0x00, 0xF3,0x82, 0xFF,0x00, 0xC6,0xB4, 0x3C,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
++0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
++0xFF,0xD4, 0x83,0x96, 0xFF,0xF4, 0xC5,0x28, 0x4C,0x00, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x76,0x9D, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4,
++0x70,0x00, 0xF6,0xAF, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x83,0x16,
++0xFF,0xCC, 0xF3,0x82, 0xFF,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
++0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x23, 0x28,0x00, 0x87,0x22,
++0x00,0x00, 0xF3,0x04, 0x40,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19,
++0x00,0x10, 0x93,0x16, 0xFF,0xEC, 0x73,0x99, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC7,0x1C,
++0x70,0x00, 0x97,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x83,0x1A, 0x00,0x00, 0x77,0x99,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18, 0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0xF3,0x23,
++0x28,0x00, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x98, 0xF3,0x06,
++0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xAE,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xAD,0x89, 0x27,0x38,
++0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x24,0x94,
++0x00,0x66, 0x94,0x96, 0xFF,0x64, 0xF3,0x04, 0x40,0x78, 0x24,0x94, 0x00,0x20, 0x94,0x96,
++0xFF,0x94, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0x93,0x16, 0xFF,0x74, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
++0xFF,0xE5, 0x05,0x98, 0x00,0x02, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28,
++0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
++0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x85,0x16, 0xFF,0x64, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
++0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
++0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14,
++0x00,0x64, 0x93,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x24,0x94, 0x00,0x62, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
++0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x25,0x14, 0x00,0x60, 0x95,0x16, 0xFF,0x64, 0x05,0xAC,
++0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
++0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x24,0x94,
++0x00,0x5C, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x95,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
++0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x50, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x58, 0x05,0xAC,
++0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x93,0x16, 0xFF,0x64, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
++0xFF,0xFC, 0x94,0x96, 0xFF,0x8C, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x23,0x14, 0x00,0x38, 0x95,0x13,
++0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x93,0x16, 0xFF,0x84, 0x93,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x27,0x80,
++0x00,0x07, 0xF7,0x85, 0x42,0x58, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84,
++0x42,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x84, 0x00,0x00,
++0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xAD,0x5D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
++0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xAE,0xE4, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
++0xAE,0xE4, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x40,0x78, 0xF5,0x84, 0x4F,0x58, 0x07,0x38,
++0x00,0x16, 0x86,0xBA, 0x00,0x00, 0xF4,0x06, 0x3B,0x90, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x76,0x35, 0x00,0x06, 0xA7,0x2E,
++0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38,
++0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x73,0xB7, 0xFF,0xF0, 0xEE,0x00, 0xAE,0x55, 0x95,0x16, 0xFF,0x64, 0xA7,0x2E,
++0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x23,0x14,
++0x00,0x88, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
++0x00,0x08, 0x85,0x3A, 0x00,0x04, 0x84,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x1A,
++0x00,0x04, 0x94,0x9A, 0x00,0x00, 0x85,0x96, 0xFF,0x7C, 0xE0,0x00, 0xAE,0x78, 0x00,0x00,
++0x00,0x01, 0x84,0x96, 0xFF,0x64, 0xA7,0x2E, 0x60,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
++0x40,0x00, 0x85,0xBA, 0x00,0x04, 0x85,0x16, 0xFF,0x64, 0xF6,0x06, 0x3B,0x90, 0x87,0x2A,
++0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38,
++0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00,
++0xAE,0xC9, 0x76,0xB5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x78, 0x00,0x00, 0x00,0x01, 0x77,0x19,
++0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0x84,0x96, 0xFF,0x64, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
++0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x10, 0xF7,0x04, 0x40,0x84, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xAF,0x3C, 0xF6,0x06, 0x42,0xB8, 0xF7,0x04, 0x42,0xB8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF3,0x06, 0x36,0x78, 0xF3,0x05, 0x42,0x44, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x5C, 0xF3,0x84,
++0x42,0x5C, 0x83,0x3A, 0x00,0x04, 0xC4,0x38, 0x00,0x00, 0x93,0x16, 0xFF,0xEC, 0x77,0x1D,
++0x00,0x01, 0xC7,0x38, 0x38,0x00, 0x77,0x39, 0x00,0x02, 0x04,0xB8, 0x00,0x0C, 0x83,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00, 0xB0,0x70, 0xC5,0x04,
++0x00,0x00, 0xA6,0xA2, 0x48,0x02, 0xF7,0x04, 0xE0,0x00, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0xAF,0xA8, 0xC6,0x20, 0x48,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xAF,0xAC, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xAF,0xB9, 0x00,0x00,
++0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xF4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0xAF,0xFC, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
++0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xFD, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xB0,0x0D, 0x20,0x2A,
++0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xB0,0x59, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x7A,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xB0,0x64, 0xC7,0x20, 0x48,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x06, 0x40,0x98, 0x77,0x39,
++0x00,0x02, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
++0xB0,0x64, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x0C, 0xE0,0x00, 0xAF,0x60, 0x03,0x9C,
++0x00,0x01, 0x83,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00,
++0xB1,0x04, 0xF3,0x06, 0x36,0x78, 0xF6,0x84, 0x4F,0x5C, 0x77,0x1D, 0x00,0x01, 0xC7,0x38,
++0x38,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xC6,0xB4, 0x70,0x00, 0x87,0x36,
++0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x96,0x93,
++0xFF,0xFC, 0x93,0x96, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFA,0x98, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xF6,0x84, 0x42,0x6C, 0x83,0x96, 0xFF,0xF4, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0xC7,0x1C, 0x70,0x00, 0xF7,0x05, 0x42,0x5C, 0x06,0xB4,
++0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x85, 0x42,0x6C, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x1C, 0x20,0x32,
++0x00,0x44, 0xE6,0x00, 0xB1,0x08, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0xB1,0x08, 0xF0,0x05,
++0x2D,0x38, 0xF3,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF4,0x02, 0x00,0x00, 0xC5,0xA0, 0x00,0x00, 0xF6,0x82, 0x07,0x70, 0xF7,0x04,
++0x6E,0x50, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0xB1,0x6D, 0x06,0x38, 0x00,0x1C, 0x87,0x32,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC4,0x20, 0x70,0x00, 0xC0,0x22, 0x72,0x00, 0xE4,0x00,
++0xB1,0x5D, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x01, 0x26,0xB4, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0xB1,0x40, 0x06,0x30, 0x00,0x04, 0xC4,0x20, 0x58,0x00, 0xC0,0x22,
++0x5A,0x00, 0xE4,0x00, 0xB1,0x81, 0x00,0x00, 0x00,0x01, 0x04,0x20, 0x00,0x01, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB1,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x04, 0x40,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00,
++0xB1,0xED, 0xF4,0x05, 0x40,0x90, 0xF7,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x86,0xBA,
++0x1D,0xDC, 0xF5,0x82, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x96,0xBA, 0x1D,0xDC, 0x87,0x3A,
++0x1D,0xDC, 0xE0,0x00, 0xB1,0xF0, 0xF5,0x85, 0x7A,0xD0, 0xF0,0x05, 0x7A,0xD0, 0xF5,0x84,
++0x40,0x90, 0xF0,0x05, 0x40,0x84, 0xF5,0x85, 0x40,0x94, 0xF5,0x86, 0xE0,0x00, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x85,0xBA, 0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0xF5,0x85,
++0x3B,0x64, 0xF5,0x84, 0xE0,0x00, 0xF0,0x05, 0x42,0x5C, 0x95,0xBA, 0x00,0x10, 0xF5,0x84,
++0xE0,0x04, 0xF6,0x86, 0x2C,0x28, 0x95,0xBA, 0x00,0x14, 0xF7,0x04, 0x2D,0x38, 0xF5,0x86,
++0x3A,0x4C, 0xF5,0x85, 0x42,0x44, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0xF5,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xB2,0x68, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86, 0x35,0xEC, 0xF5,0x85, 0x42,0x30, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xC8, 0xF3,0x02,
++0x00,0x00, 0x93,0x16, 0xFF,0x94, 0x24,0x80, 0x00,0x08, 0x94,0x96, 0xFF,0x84, 0x23,0x80,
++0x00,0x07, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0x54, 0x20,0x1E,
++0x00,0x07, 0xEE,0x00, 0xB5,0x64, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84,
++0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB3,0x2D, 0x20,0x36,
++0x00,0x01, 0xE6,0x00, 0xB3,0x2D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38,
++0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB3,0x31, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C,
++0x00,0x00, 0xE0,0x00, 0xB3,0x30, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04,
++0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB5,0x5D, 0x00,0x00,
++0x00,0x01, 0xF6,0x84, 0x3B,0xBC, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFF,0x3C, 0x04,0x28,
++0x00,0x1C, 0xF7,0x04, 0x3B,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
++0xB4,0x40, 0x96,0x96, 0xFF,0xAC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
++0x00,0x02, 0xF4,0x86, 0x3B,0xB4, 0xC6,0x38, 0x48,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x04,
++0x00,0x00, 0x93,0x16, 0xFF,0x34, 0x86,0xB2, 0x00,0x00, 0x87,0x2A, 0x00,0x1C, 0x85,0x96,
++0xFF,0x3C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0x86,0xB2,
++0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
++0xB3,0xD1, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x34, 0x86,0xB2,
++0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0xB4,0x0C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB4,0x14, 0x20,0x2E,
++0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0xB4,0x15, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0xB4,0x25, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
++0xFF,0x34, 0x84,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
++0xB4,0x40, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0x3C, 0x84,0x96,
++0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xB4,0x81, 0xF6,0x02,
++0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06, 0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
++0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
++0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0xE0,0x00, 0xB4,0xF4, 0x96,0x96, 0xFF,0xB4, 0x27,0x14,
++0x00,0x54, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0xF4,0x86, 0x3B,0xB4, 0x94,0x93,
++0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xB4,0xF1, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06,
++0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
++0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0x96,0x96,
++0xFF,0xB4, 0xF7,0x05, 0x3B,0xBC, 0xE0,0x00, 0xB4,0xF8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xB5,0x2D, 0x27,0x14, 0x00,0x08, 0x84,0x96,
++0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x83,0x16, 0xFF,0xB4, 0x04,0xA4,
++0x00,0x04, 0x94,0x96, 0xFF,0x54, 0x84,0x96, 0xFF,0x94, 0x93,0x3A, 0xFF,0xC0, 0x04,0xA4,
++0x00,0x01, 0xE0,0x00, 0xB5,0x54, 0x94,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0x54, 0x00,0x00,
++0x00,0x01, 0xC7,0x18, 0x70,0x00, 0xF4,0x84, 0x4F,0x58, 0x03,0x18, 0x00,0x04, 0x93,0x16,
++0xFF,0x54, 0x83,0x16, 0xFF,0x94, 0x94,0xBA, 0xFF,0xC0, 0x03,0x18, 0x00,0x01, 0x93,0x16,
++0xFF,0x94, 0x95,0x16, 0xFF,0x3C, 0x93,0x96, 0xFF,0x8C, 0xE0,0x00, 0xB2,0xB0, 0x03,0x9C,
++0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
++0xB5,0x84, 0xF3,0x82, 0x00,0x01, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x00,0x00,
++0x00,0x01, 0x83,0x16, 0xFF,0xB8, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
++0x4A,0x00, 0xEC,0x00, 0xB5,0xCC, 0x93,0x16, 0xFF,0x7C, 0x26,0x94, 0x00,0x04, 0x87,0x36,
++0xFF,0xC0, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
++0xBB,0x98, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
++0x4A,0x00, 0xEC,0x00, 0xB5,0xA1, 0x06,0xB4, 0x00,0x04, 0xF4,0x04, 0x4F,0x58, 0x83,0x16,
++0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x42,0x00, 0xE6,0x00, 0xBA,0x2D, 0xF4,0x82,
++0x00,0x00, 0x94,0x96, 0xFF,0x74, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
++0xB7,0x48, 0xC7,0x1C, 0x38,0x00, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC7,0x18,
++0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
++0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB6,0x69, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
++0xB6,0x69, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
++0x00,0x02, 0xE6,0x00, 0xB6,0x6D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
++0xB6,0x6C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
++0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB7,0x41, 0xC5,0x84, 0x00,0x00, 0x84,0x96,
++0xFF,0x74, 0x86,0xAA, 0x00,0x1C, 0x83,0x16, 0xFF,0x3C, 0xF6,0x02, 0x00,0x00, 0x04,0xA4,
++0x00,0x01, 0x94,0x96, 0xFF,0x74, 0x87,0x1A, 0x00,0x1C, 0x04,0xA8, 0x00,0x1C, 0x94,0x96,
++0xFF,0x34, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB6,0xCC, 0x04,0x18, 0x00,0x1C, 0x86,0xAA,
++0x00,0x20, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0xB6,0xD0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0xB6,0xDD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0x87,0x22,
++0x00,0x00, 0x86,0x9A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0xB7,0x1C, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB7,0x24, 0x20,0x32,
++0x00,0x00, 0x86,0x9A, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0xB7,0x25, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0xB7,0x35, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0xB7,0x40, 0x00,0x00, 0x00,0x01, 0x93,0x96, 0xFF,0x84, 0xE0,0x00,
++0xB5,0xEC, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x74, 0x83,0x16, 0xFF,0x94, 0x00,0x00,
++0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x00, 0x00,0x08, 0x84,0x96,
++0xFF,0x84, 0x00,0x00, 0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x99, 0xF6,0x02,
++0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0xC7,0x38,
++0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x04, 0xF5,0x82,
++0x00,0xFF, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
++0x32,0x00, 0x84,0x96, 0xFF,0x7C, 0xC7,0x38, 0x70,0x00, 0xC7,0x24, 0x70,0x00, 0x07,0x38,
++0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x5C,0x00, 0xC0,0x36, 0x62,0x00, 0x47,0x0C,
++0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x0D, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x80,
++0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00, 0xB8,0xC8, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
++0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
++0xB8,0x91, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xB8,0x91, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
++0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
++0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB8,0x95, 0xC6,0xB8,
++0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00, 0xB8,0x94, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84,
++0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00,
++0xB8,0xC1, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00,
++0xB8,0x14, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0xF3,0x84,
++0x40,0x7C, 0xF5,0x04, 0x40,0x74, 0xC4,0xA4, 0x32,0x00, 0x94,0x96, 0xFF,0x34, 0x83,0x16,
++0xFF,0x34, 0xC5,0x9C, 0x38,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
++0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x74,0x2D, 0x00,0x1E, 0x74,0x20,
++0xFF,0xE5, 0x73,0x9D, 0x00,0x10, 0x73,0x9D, 0xFF,0xF8, 0xC4,0xA4, 0x30,0x00, 0x94,0x96,
++0xFF,0x3C, 0x83,0x16, 0xFF,0x7C, 0xC6,0xB4, 0x77,0xC0, 0xC4,0x98, 0x48,0x00, 0x94,0x96,
++0xFF,0x3C, 0x04,0xA4, 0x00,0x26, 0x94,0x96, 0xFF,0x3C, 0x73,0x25, 0x00,0x1E, 0x73,0x18,
++0xFF,0xE5, 0x93,0x16, 0xFF,0x6C, 0x74,0xA5, 0x00,0x1E, 0x94,0x96, 0xFF,0x64, 0x74,0xA4,
++0xFF,0xE5, 0x94,0x96, 0xFF,0x64, 0x83,0x16, 0xFF,0x7C, 0xF4,0x84, 0x4F,0x58, 0x76,0xB5,
++0xFF,0xF0, 0xC6,0x18, 0x4A,0x00, 0x76,0x30, 0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xF3,0x02,
++0x00,0xFF, 0xC6,0x30, 0x34,0x00, 0xF4,0x82, 0xFF,0x00, 0xC6,0xB4, 0x4C,0x00, 0xC6,0x30,
++0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0xC7,0x38,
++0x47,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19, 0x00,0x10, 0x93,0x16, 0xFF,0x34, 0x74,0x99,
++0xFF,0xF8, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x34,0x00, 0xC7,0x24, 0x70,0x00, 0x97,0x16,
++0xFF,0x34, 0x24,0x94, 0x00,0xCA, 0x84,0xA6, 0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC,
++0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x3C, 0xF4,0xAF,
++0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0x28, 0x4A,0x00, 0x75,0x28,
++0xFF,0xFA, 0x83,0x16, 0xFF,0x6C, 0x45,0x29, 0x00,0x00, 0xF4,0x82, 0x00,0xFF, 0xC5,0x28,
++0x4C,0x00, 0x84,0x96, 0xFF,0x3C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF3,0x02,
++0xFF,0x00, 0xC7,0x38, 0x34,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x27, 0x28,0x00, 0x87,0x26,
++0x00,0x00, 0x83,0x16, 0xFF,0x64, 0x84,0x16, 0xFF,0x7C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
++0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC7,0x38, 0x4C,0x00, 0x83,0x16, 0xFF,0x3C, 0xC3,0x9C,
++0x70,0x00, 0xE0,0x00, 0xBE,0xE4, 0xF3,0x9B, 0x28,0x00, 0xF7,0x04, 0x40,0x7C, 0xF6,0x04,
++0x40,0x74, 0xC7,0x38, 0x70,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
++0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0xBA,0x7D, 0x25,0x80, 0x00,0x07, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
++0x00,0x40, 0xE0,0x00, 0xBA,0xD8, 0xC4,0x2C, 0x00,0x00, 0xC7,0x30, 0x42,0x00, 0x84,0x96,
++0x00,0x00, 0x75,0x38, 0xFF,0xFA, 0x06,0x24, 0x00,0x0A, 0x20,0x2E, 0x00,0x07, 0xEE,0x00,
++0xBA,0xD4, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
++0x74,0x00, 0x47,0x29, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0xBA,0x74, 0x06,0x30, 0x00,0x02, 0xE0,0x00, 0xBA,0x8C, 0x05,0xAC,
++0x00,0x01, 0xF4,0x02, 0x00,0x08, 0x07,0x20, 0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00,
++0xBB,0xA4, 0xC5,0xA0, 0x40,0x00, 0x83,0x16, 0x00,0x00, 0xF5,0x04, 0x40,0x7C, 0xF4,0x82,
++0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC5,0x98, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
++0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x18, 0x62,0x00, 0x76,0x30,
++0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xC6,0x30, 0x4C,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0x77,0x29, 0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0xC6,0xB4, 0x4C,0x00, 0xC7,0x38,
++0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0xF5,0x84, 0x40,0x74, 0xC5,0x28, 0x50,0x00, 0xC5,0xAC,
++0x50,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0x75,0x2D, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
++0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xA1, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38,
++0x57,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4, 0x70,0x00, 0xE0,0x00,
++0xBB,0xF8, 0xF6,0xAF, 0x28,0x00, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
++0x00,0x40, 0xF6,0x04, 0x4F,0x58, 0x83,0x16, 0x00,0x00, 0xF7,0x04, 0x40,0x7C, 0xF5,0x84,
++0x40,0x74, 0xC6,0x18, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x70,0x00, 0xC5,0xAC,
++0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
++0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30,
++0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
++0xBE,0xE0, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
++0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
++0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xBC,0x79, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
++0xBC,0x79, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
++0x00,0x02, 0xE6,0x00, 0xBC,0x7D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
++0xBC,0x7C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
++0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xBE,0xD9, 0x06,0xA8, 0x00,0x1C, 0x83,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF4,0x86,
++0x3B,0xB4, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x96,0x96,
++0xFF,0x40, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF3,0x04,
++0x4F,0x5C, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x5C, 0x86,0x96, 0xFF,0x40, 0x83,0x96,
++0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x93,0x16, 0xFF,0x34, 0x86,0x1A, 0x00,0x08, 0x96,0x96,
++0xFF,0x3C, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xEC,0x00,
++0xBD,0xB8, 0x96,0x16, 0xFF,0x9C, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
++0x00,0x02, 0xC6,0x38, 0x30,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2A,
++0x00,0x1C, 0x85,0x96, 0xFF,0x5C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xBD,0x40, 0xC4,0x04,
++0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0xBD,0x44, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
++0x00,0x00, 0xE6,0x00, 0xBD,0x51, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x00, 0x83,0x16,
++0xFF,0x3C, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0xBD,0x90, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0xBD,0x98, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xBD,0x99, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xBD,0xA9, 0x20,0x22, 0x00,0x00, 0xF4,0x02,
++0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBD,0xB8, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
++0x00,0x01, 0x94,0x96, 0xFF,0x5C, 0x83,0x16, 0xFF,0x5C, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
++0x00,0x00, 0xE6,0x00, 0xBD,0xF9, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0x9C, 0x84,0x96,
++0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
++0x48,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xA0, 0xE0,0x00,
++0xBE,0x70, 0x96,0x96, 0xFF,0xA4, 0x27,0x14, 0x00,0x64, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
++0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x34, 0x00,0x00,
++0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16,
++0xFF,0x44, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBE,0x71, 0xF6,0x02, 0x00,0x00, 0x87,0x16,
++0xFF,0x9C, 0x83,0x16, 0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xA0, 0x96,0x96, 0xFF,0xA4, 0x97,0x1A, 0x00,0x08, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0xBE,0x99, 0xF6,0x06, 0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC7,0x28,
++0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x28,
++0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF4,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x94,0x93,
++0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xBB,0xFC, 0x03,0x9C, 0x00,0x01, 0x84,0x16,
++0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x60, 0x85,0x16, 0x00,0x00, 0x86,0x16, 0x00,0x04, 0x06,0xA8, 0x00,0x18, 0xC7,0x30,
++0x60,0x00, 0xC5,0xB8, 0x68,0x00, 0x20,0x32, 0x00,0x07, 0xEE,0x00, 0xBF,0x64, 0x07,0x2C,
++0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
++0x00,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xBF,0x61, 0x05,0xAC, 0x00,0x02, 0xE0,0x00, 0xBF,0x18, 0x06,0x30, 0x00,0x01, 0x20,0x32,
++0x00,0x07, 0xEE,0x00, 0xC0,0x4C, 0x06,0xA8, 0x00,0x16, 0xF5,0x05, 0x40,0x74, 0xF6,0x05,
++0x40,0x7C, 0xF3,0x02, 0x00,0x06, 0xF3,0x05, 0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0x05,0x28,
++0x00,0x02, 0x95,0x16, 0xFF,0xC4, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
++0xFF,0xBC, 0x93,0x93, 0xFF,0xFC, 0x96,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x38, 0x94,0x93,
++0xFF,0xFC, 0x93,0x16, 0xFF,0xB4, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x86,0x16, 0xFF,0xAC, 0xF7,0x05,
++0x42,0x64, 0x96,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x94,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xC0,0x1D, 0xF3,0x06, 0x3A,0xD8, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
++0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0xF3,0x05, 0x42,0x44, 0xF3,0x82,
++0x17,0x70, 0x93,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x1B, 0x94,0x93, 0xFF,0xFC, 0xF3,0x06,
++0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0xC1,0xA0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0xF5,0x84,
++0x4F,0x58, 0xF4,0x06, 0x3B,0x70, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C,
++0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7,
++0xFF,0xF0, 0xEE,0x00, 0xC1,0x15, 0x96,0x96, 0xFF,0x9C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94,
++0x00,0x60, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
++0x00,0x08, 0x83,0xBA, 0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6,
++0x00,0x04, 0x93,0x26, 0x00,0x00, 0x85,0x96, 0xFF,0xA4, 0xE0,0x00, 0xC1,0x38, 0x23,0x00,
++0x00,0x07, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x85,0xBA,
++0x00,0x04, 0x23,0x00, 0x00,0x07, 0x93,0x13, 0xFF,0xFC, 0x87,0x2A, 0x00,0x00, 0x76,0xA9,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E,
++0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0xEE,0x00, 0xC1,0x8D, 0x76,0xB5, 0xFF,0xF0, 0x84,0x96, 0xFF,0xA0, 0x00,0x00,
++0x00,0x01, 0x77,0x25, 0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x70, 0x25,0x00,
++0x00,0x07, 0x20,0x2A, 0x00,0x07, 0xEE,0x00, 0xC3,0xB8, 0xC7,0x28, 0x50,0x00, 0x83,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
++0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
++0xC2,0x3D, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xC2,0x3D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
++0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
++0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xC2,0x4D, 0xC0,0x3A,
++0x5A,0x00, 0xE0,0x00, 0xC2,0x48, 0xC7,0x2C, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF5,0x84,
++0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0xC3,0xB1, 0xF4,0x86,
++0x3B,0x90, 0x83,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x06,0x9C, 0x00,0x16, 0x87,0x36,
++0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7, 0xFF,0xF0, 0xEE,0x00,
++0xC3,0x21, 0x96,0x96, 0xFF,0x8C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x83,0x16, 0xFF,0x8C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94, 0x00,0x70, 0x77,0x39,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAA,
++0x68,0x02, 0x77,0x19, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x83,0xBA,
++0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6, 0x00,0x04, 0x93,0x26,
++0x00,0x00, 0x86,0x16, 0xFF,0x94, 0xE0,0x00, 0xC3,0x44, 0x00,0x00, 0x00,0x01, 0xA7,0x2E,
++0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x3B,0x90, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x30,0x00, 0x86,0x3A,
++0x00,0x04, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96,
++0xFF,0x8C, 0xF4,0x86, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xA6,0xBA, 0x48,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38, 0x48,0x00, 0x77,0x39,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC3,0x95, 0x76,0xB5,
++0xFF,0xF0, 0x83,0x16, 0xFF,0x90, 0x00,0x00, 0x00,0x01, 0x77,0x19, 0xFF,0xF0, 0xC6,0xB8,
++0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x30,
++0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xC5,0xC4, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
++0xC1,0xC4, 0x05,0x28, 0x00,0x01, 0x83,0x96, 0x00,0x00, 0xF4,0x82, 0x00,0x06, 0xF4,0x85,
++0x42,0x54, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x1E, 0x23,0x14, 0x00,0x20, 0x93,0x16,
++0xFF,0xAC, 0xF3,0x85, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
++0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
++0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
++0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
++0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
++0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
++0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
++0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x25,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x07,0x1C,
++0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0xA4, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x84,0x96,
++0xFF,0xA4, 0x23,0x14, 0x00,0x38, 0x94,0x93, 0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93,
++0xFF,0xFC, 0x93,0x16, 0xFF,0x9C, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x27,0x80, 0x00,0x07, 0xF7,0x85,
++0x42,0x58, 0xF7,0x05, 0x42,0x64, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x97,0x13,
++0xFF,0xFC, 0x83,0x96, 0xFF,0x9C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96,
++0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xC5,0x95, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x39,0xC0, 0xF3,0x05, 0x42,0x44, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82,
++0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xC5,0xC4, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x25,0x00,
++0x00,0x07, 0xF7,0x04, 0x40,0x74, 0xF6,0x84, 0x4F,0x58, 0xF6,0x04, 0x42,0x60, 0xC7,0x38,
++0x6A,0x00, 0x75,0xB8, 0xFF,0xFA, 0x06,0x30, 0x00,0x0A, 0x20,0x2A, 0x00,0x07, 0xEE,0x00,
++0xC6,0x48, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
++0x74,0x00, 0x47,0x2D, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0xC6,0x4C, 0xC3,0x28, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xE0,0x00,
++0xC5,0xFC, 0x05,0x28, 0x00,0x01, 0xF3,0x02, 0x00,0x08, 0xC5,0x18, 0x30,0x00, 0xF3,0x84,
++0x42,0x60, 0xF6,0x04, 0x4F,0x58, 0xF7,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC5,0x1C,
++0x50,0x00, 0x05,0x28, 0x00,0x26, 0x85,0xAA, 0x00,0x00, 0x74,0x29, 0x00,0x1E, 0x74,0x20,
++0xFF,0xE5, 0xC6,0x1C, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC6,0xB8, 0x70,0x00, 0xC4,0xA4,
++0x68,0x00, 0x04,0xA4, 0x00,0x26, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x77,0x39,
++0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0x46,0x31, 0x00,0x00, 0xC5,0xAC, 0x47,0xC0, 0x75,0xAD,
++0xFF,0xF0, 0xF4,0x02, 0x00,0xFF, 0xC5,0xAC, 0x44,0x00, 0xC7,0x38, 0x58,0x00, 0xF7,0x2B,
++0x28,0x00, 0x87,0x26, 0x00,0x00, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30, 0x44,0x00, 0x75,0xAC,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38,
++0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x27, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x76,0x99,
++0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
++0x44,0x00, 0xC6,0xB4, 0x70,0x00, 0xF6,0xA7, 0x28,0x00, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
++0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x84, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
++0x42,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x30, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x35,0xEC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x36,0x78, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x04, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x90, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x38,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x38,0xA8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0x34, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0xC0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x3A,0x4C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x3A,0xD8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
++0x00,0x00, 0xF5,0x06, 0x3B,0x90, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
++0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37, 0xFF,0xF0, 0xEE,0x00, 0xC9,0x95, 0x00,0x00,
++0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA,
++0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
++0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A, 0x00,0x00, 0xE0,0x00, 0xC9,0xB4, 0xC5,0x24,
++0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A,
++0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32,
++0x00,0x00, 0xF6,0x06, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC9,0xF9, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
++0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF5,0x06, 0x3B,0x70, 0x87,0x2E,
++0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37,
++0xFF,0xF0, 0xEE,0x00, 0xCA,0xBD, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA, 0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31,
++0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A,
++0x00,0x00, 0xE0,0x00, 0xCA,0xDC, 0xC5,0x24, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A, 0x00,0x04, 0x83,0x96, 0x00,0x04, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32, 0x00,0x00, 0x93,0x93, 0xFF,0xFC, 0x87,0x2E,
++0x00,0x00, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
++0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xCB,0x29, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
++0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x04, 0x4F,0x58, 0xF5,0x82, 0x00,0x02, 0x06,0x28,
++0x00,0x80, 0x20,0x2E, 0x00,0x62, 0xEE,0x00, 0xCB,0x90, 0x07,0x30, 0x00,0x40, 0xF0,0x33,
++0x28,0x00, 0xC6,0xB8, 0x52,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x30, 0x00,0x14, 0xF6,0xB3,
++0x28,0x00, 0xC6,0x38, 0x00,0x00, 0xE0,0x00, 0xCB,0x64, 0x05,0xAC, 0x00,0x01, 0xF7,0x04,
++0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x06,0xB8, 0x18,0xD4, 0xF4,0x82, 0x00,0x01, 0xF4,0xB7,
++0x28,0x00, 0x07,0x38, 0x18,0xC0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x42,0xC0, 0xF4,0x82,
++0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF6,0x84, 0x42,0xC0, 0xF6,0x06, 0x42,0xC0, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
++0x4F,0x58, 0x76,0xB5, 0x00,0x06, 0xC4,0x38, 0x68,0x00, 0x87,0x22, 0x00,0x14, 0x76,0xA1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
++0x28,0x00, 0xF7,0x04, 0x42,0xC0, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0xCC,0x4C, 0xF6,0x06, 0x42,0x90, 0xF7,0x04,
++0x42,0x90, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0x85,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0xCC,0xBC, 0xF5,0x86, 0x42,0xC0, 0xF7,0x04, 0x42,0x90, 0xF6,0x06, 0x42,0x92, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0xCC,0xEC, 0xF7,0x33, 0x28,0x00, 0xF0,0x2B, 0x28,0x00, 0xF6,0x84,
++0x42,0xC0, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x06,0x28, 0x00,0x14, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x4F,0x58, 0xF6,0xB3, 0x28,0x00, 0xC7,0x28,
++0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x2F, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x02,
++0x00,0x00, 0xC6,0xB4, 0x72,0x00, 0x77,0x34, 0xFF,0xFA, 0x27,0x38, 0x00,0x02, 0x20,0x3A,
++0x00,0x61, 0xF7,0x02, 0x00,0x3F, 0xE2,0x00, 0xCD,0x40, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
++0x00,0x00, 0xE6,0x00, 0xCD,0x40, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x87,0x16,
++0x00,0x08, 0x85,0x96, 0x00,0x04, 0xC5,0x30, 0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE6,0x00,
++0xCD,0xA1, 0x00,0x00, 0x00,0x01, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xAF, 0x68,0x00, 0x06,0x30,
++0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE6,0x00, 0xCD,0x78, 0x05,0xAC, 0x00,0x01, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x96,
++0x00,0x00, 0x84,0x16, 0x00,0x04, 0x85,0x96, 0x00,0x08, 0x86,0xA6, 0x00,0x00, 0x77,0x25,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x75,0x35, 0xFF,0xF0, 0x20,0x2A,
++0x00,0x10, 0xE2,0x00, 0xCE,0x0D, 0xF6,0x06, 0x42,0x8E, 0xF5,0x02, 0x00,0x10, 0xF7,0x04,
++0x42,0x8C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
++0xCE,0x70, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xCE,0x71, 0x07,0x24, 0x00,0x02, 0x25,0x28,
++0x00,0x01, 0xA5,0xBA, 0x50,0x02, 0x86,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC5,0xAC,
++0x77,0xC0, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x75,0xAD, 0xFF,0xE8, 0xF6,0x82,
++0x00,0xFF, 0xF7,0x02, 0xF1,0x54, 0x75,0xAD, 0x00,0x02, 0xA7,0x2E, 0x70,0x02, 0xC6,0x30,
++0x6C,0x00, 0xC6,0x30, 0x75,0x80, 0xF6,0x23, 0x28,0x00, 0x24,0x20, 0x00,0x02, 0x25,0xA8,
++0x00,0x01, 0xF3,0x02, 0xF2,0x46, 0x03,0xA4, 0x00,0x02, 0xC4,0xAC, 0x38,0x00, 0x25,0x2C,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xCF,0x11, 0x00,0x00, 0x00,0x01, 0xE6,0x00,
++0xCE,0xA0, 0xC7,0x1C, 0x50,0x00, 0xE0,0x00, 0xCE,0xB4, 0xF6,0x02, 0x00,0x00, 0xA6,0x9E,
++0x50,0x02, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x35,
++0xFF,0xE8, 0x86,0xA6, 0x00,0x00, 0x77,0x25, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x25,0x28,
++0x00,0x02, 0x25,0xAC, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0x77,0x31,
++0x00,0x04, 0xC7,0x38, 0x62,0x00, 0x77,0x39, 0x00,0x01, 0xC7,0x38, 0x30,0x00, 0xC6,0xB4,
++0x68,0x00, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x0E, 0x87,0x36, 0x00,0x00, 0x24,0xA4,
++0x00,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xE0,0x00, 0xCE,0x84, 0x24,0x20, 0x00,0x02, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x08, 0x83,0x16,
++0x00,0x04, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x74,0x1D,
++0x00,0x1E, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x05,0xAC, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x74,0x20,
++0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x1F,
++0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x04,0x9C, 0x00,0x02, 0xC7,0x38, 0x47,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x25,0x38, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xD0,0xBD, 0x26,0x28,
++0x00,0x01, 0xA7,0x26, 0x60,0x02, 0xC6,0xA4, 0x60,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC5,0xA4, 0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xE8, 0xE0,0x00, 0xD0,0x88, 0xF7,0x2F, 0x68,0x00, 0x07,0x1C, 0x00,0x02, 0xF3,0x3B,
++0x68,0x00, 0xC4,0x1C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x86,0x16, 0x00,0x04, 0x84,0x16, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0xA0, 0x00,0x02, 0x74,0xA1, 0x00,0x1E, 0x74,0xA4,
++0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x06,0xA0, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x22,
++0x00,0x00, 0x76,0x21, 0x00,0x1E, 0x85,0x96, 0x00,0x08, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF5,0xB7, 0x68,0x00, 0x87,0x22, 0x00,0x00, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x23,
++0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x20, 0x27,0x14, 0x00,0x20, 0xF0,0x3B, 0x28,0x00, 0x84,0x96, 0x00,0x04, 0xF5,0x02,
++0x00,0x00, 0x86,0xA6, 0x00,0x00, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x04,0x24,
++0x00,0x02, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xBB, 0x28,0x00, 0x87,0x26,
++0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00, 0xD2,0xF8, 0x76,0xA5, 0x00,0x1E, 0x87,0x26,
++0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0x06,0x28, 0x00,0x01, 0x25,0x94, 0x00,0x1E, 0xC5,0xAC,
++0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
++0x52,0x00, 0xA6,0xA2, 0x70,0x02, 0xC7,0x20, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xC6,0x80, 0x6A,0x00, 0xE0,0x00,
++0xD2,0x90, 0xF6,0xAF, 0x68,0x00, 0x87,0x16, 0xFF,0xE0, 0x76,0x15, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x83,0x96, 0x00,0x00, 0x23,0x14, 0x00,0x1E, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
++0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x06,0x9C, 0x00,0x02, 0x73,0x95,
++0x00,0x1E, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x67,0xC0, 0x83,0x96, 0x00,0x00, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x83,0x96, 0xFF,0xDC, 0x87,0x1A, 0x00,0x00, 0x73,0x9C,
++0xFF,0xE5, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
++0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0x84,0x16, 0x00,0x00, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x86,0x16, 0x00,0x00, 0x84,0x16, 0x00,0x04, 0xF6,0x84, 0x4F,0x58, 0x87,0x32,
++0x00,0x14, 0x03,0x30, 0x00,0x14, 0x75,0x19, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC3,0xA0,
++0x6A,0x00, 0x73,0x9C, 0xFF,0xFA, 0x04,0xA0, 0x00,0x14, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30,
++0x6A,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0xF3,0x9B, 0x28,0x00, 0x07,0x20, 0x00,0x16, 0xF6,0x3B, 0x28,0x00, 0x87,0x22,
++0x00,0x14, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39,
++0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x16, 0xF3,0xB7, 0x28,0x00, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0xF5,0x84,
++0x4F,0x58, 0x05,0x30, 0x00,0x16, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC4,0x2C,
++0x70,0x00, 0xC0,0x22, 0x62,0x00, 0xE6,0x00, 0xD5,0x29, 0x06,0xA0, 0x00,0x16, 0x87,0x36,
++0x00,0x00, 0xC6,0x30, 0x5A,0x00, 0x76,0x30, 0xFF,0xFA, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0x76,0xB8,
++0xFF,0xFA, 0xF6,0xAB, 0x28,0x00, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x14, 0xE0,0x00,
++0xD5,0x2C, 0xF6,0x3B, 0x28,0x00, 0xC4,0x2C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x4F,0x84, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05,
++0x6F,0x30, 0xF6,0x86, 0x50,0x5C, 0x46,0xB4, 0xFF,0xFC, 0xF6,0x85, 0x6E,0x50, 0xF7,0x06,
++0x6E,0x7C, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05, 0x6E,0x54, 0x07,0x34, 0x19,0x1C, 0xF7,0x05,
++0x4F,0x5C, 0xF7,0x02, 0x00,0x64, 0x97,0x36, 0x19,0x1C, 0xF7,0x02, 0x00,0x00, 0x97,0x36,
++0x19,0x20, 0x06,0xB4, 0x00,0x1C, 0xF6,0x85, 0x4F,0x58, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF3,0x02, 0xFF,0xFF, 0xF3,0x05,
++0x4F,0x54, 0xF3,0x82, 0x00,0x00, 0x93,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x20, 0x93,0x16,
++0xFF,0x9C, 0x23,0x94, 0x00,0x38, 0x93,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0xAC, 0xF7,0x04,
++0x4F,0x5C, 0xF3,0x82, 0x00,0x0C, 0x93,0x96, 0xFF,0x74, 0x93,0x16, 0xFF,0x8C, 0x87,0x3A,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xA4, 0x83,0x16, 0xFF,0xAC, 0x83,0x96,
++0xFF,0xA4, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x3A,0x00, 0xEC,0x00, 0xDB,0x78, 0xF3,0x02,
++0x04,0xBC, 0xF7,0x04, 0x4F,0x5C, 0x83,0x16, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x30,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC4,0xB4,
++0x70,0x00, 0x94,0x93, 0xFF,0xFC, 0x94,0x96, 0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0x7C, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0xD6,0x54, 0xC5,0x04, 0x00,0x00, 0xF7,0x04, 0x42,0x88, 0xE0,0x00, 0xD8,0x7C, 0xF6,0x06,
++0x42,0x88, 0xF6,0x04, 0x4F,0x5C, 0x83,0x96, 0x00,0x00, 0x83,0x16, 0xFF,0x74, 0x86,0x9E,
++0x00,0x00, 0xA7,0x32, 0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0xD6,0x94, 0xC6,0x30, 0x30,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xD6,0x98, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xA5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
++0x00,0x00, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xE4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0xE6,0x00, 0xD6,0xEC, 0x20,0x2E, 0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xED, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xFD, 0x20,0x2A,
++0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xD7,0x28, 0x04,0xA4,
++0x00,0x02, 0x83,0x16, 0xFF,0xAC, 0xF7,0x06, 0x42,0xC8, 0x83,0x96, 0xFF,0x8C, 0xF3,0x05,
++0x4F,0x54, 0xC7,0x1C, 0x70,0x00, 0xF0,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0xE0,0x00,
++0xDB,0x50, 0xF0,0x3B, 0x28,0x00, 0x94,0x96, 0xFF,0x6C, 0x87,0x26, 0x00,0x00, 0x76,0xA5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16, 0xFF,0x6C, 0x83,0x96, 0xFF,0x9C, 0x24,0x94,
++0x00,0x1E, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x1D,
++0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x24,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x10, 0x76,0x31,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0xF6,0x82, 0xFF,0xFC, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x03, 0xC4,0xB8, 0x6C,0x00, 0x20,0x26, 0x00,0x10, 0xE2,0x00,
++0xD8,0x9D, 0xF6,0x06, 0x42,0x8A, 0xF7,0x04, 0x42,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0xDB,0xA0, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x6C, 0x25,0x14,
++0x00,0x36, 0x83,0x96, 0xFF,0x94, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x34, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x32, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x30, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2E, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2C, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2A, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x28, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x26,0xA4, 0x00,0x02, 0x74,0xA4, 0xFF,0xFF, 0x76,0x31,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
++0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x8C, 0xF7,0x06, 0x42,0xCC, 0xC7,0x18,
++0x70,0x00, 0xC7,0x38, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x94,0x96,
++0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0x6C, 0x24,0x14, 0x00,0x4E, 0x25,0x14, 0x00,0x50, 0x83,0x16, 0xFF,0x8C, 0x84,0x96,
++0xFF,0x7C, 0x87,0x1E, 0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x1C,
++0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x29, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x4C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x4A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x48, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x46, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x44, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x42, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x40, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x86,0x96,
++0xFF,0xB0, 0xF6,0x06, 0x42,0xC8, 0xC6,0x18, 0x60,0x00, 0xF7,0x02, 0x00,0x03, 0xC6,0xB4,
++0x57,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
++0x6A,0x00, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xF4,0xB3, 0x28,0x00, 0x83,0x96,
++0xFF,0x8C, 0x83,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x14, 0x93,0x96, 0xFF,0x8C, 0x03,0x18,
++0x00,0x0C, 0x83,0x96, 0xFF,0xAC, 0x93,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
++0xD5,0xEC, 0x93,0x96, 0xFF,0xAC, 0x93,0x13, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
++0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x01,0xA0, 0xF5,0x02,
++0x00,0x00, 0xF3,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x1C, 0x20,0x2A, 0x00,0x63, 0xEE,0x00,
++0xDC,0x08, 0xC5,0x9C, 0x60,0x00, 0xA6,0x9E, 0x60,0x02, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x03, 0xE6,0x00,
++0xDB,0xFC, 0x07,0x2C, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0x06,0x30, 0x00,0x40, 0xE0,0x00,
++0xDB,0xCC, 0x05,0x28, 0x00,0x01, 0xF5,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x86,0xAE,
++0x00,0x08, 0xF4,0x02, 0x00,0x00, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xEC,0x00, 0xDC,0xF0, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x58,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x84,
++0x00,0x00, 0x83,0x16, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0x7C, 0xC5,0x20, 0x00,0x00, 0x86,0xB2,
++0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0xDC,0x80, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
++0xDC,0x8D, 0x00,0x00, 0x00,0x01, 0xF3,0x82, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x86,0xB2,
++0x00,0x00, 0x87,0x26, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0xDC,0xCC, 0xF5,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0xD4, 0x20,0x2A,
++0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x00, 0xDC,0xD5, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
++0x00,0x00, 0xE6,0x00, 0xDC,0xE5, 0x20,0x1E, 0x00,0x00, 0xF3,0x82, 0x00,0x01, 0x20,0x1E,
++0x00,0x00, 0xE6,0x00, 0xDC,0xF4, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xDD,0x29, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
++0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
++0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
++0xDD,0x98, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96,
++0xFE,0x70, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
++0xFE,0x70, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDD,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x2E, 0x00,0x08, 0xE0,0x00, 0xDD,0x9C, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xDD,0xB0, 0xF4,0x82,
++0x00,0x00, 0xF7,0x04, 0x42,0x7C, 0xE0,0x00, 0xE0,0x9C, 0xF6,0x06, 0x42,0x7E, 0x94,0x96,
++0xFF,0x44, 0x87,0x16, 0xFF,0xF4, 0xF6,0x04, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC7,0x30,
++0x70,0x00, 0x97,0x16, 0xFF,0x54, 0x06,0xB8, 0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16,
++0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x93,0x13,
++0xFF,0xFC, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC6,0x30, 0x70,0x00, 0x96,0x16,
++0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xDE,0x35, 0xF3,0x02, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00,
++0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDE,0x38, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
++0x00,0x01, 0x93,0x16, 0xFF,0x44, 0x84,0x96, 0xFF,0x44, 0x00,0x00, 0x00,0x01, 0x20,0x26,
++0x00,0x00, 0xE6,0x00, 0xDE,0x59, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0xE0,0x00,
++0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x83,0x16, 0xFF,0x4C, 0x86,0x16, 0xFF,0x4C, 0x87,0x1A,
++0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0xDE,0x85, 0x00,0x00, 0x00,0x01, 0xF6,0x04,
++0x4F,0x58, 0xF5,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
++0xE0,0x25, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00, 0x00,0x01, 0x06,0xA4,
++0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16, 0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC7,0x2C,
++0x70,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0xDE,0xDD, 0xF6,0x06, 0x42,0x80, 0xF7,0x04,
++0x42,0x80, 0xE0,0x00, 0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x26,0x14, 0x00,0x30, 0xF0,0x33,
++0x28,0x00, 0x87,0x16, 0xFF,0xD0, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
++0xFF,0x4C, 0x23,0x14, 0x00,0x2E, 0x93,0x16, 0xFE,0x64, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
++0xFF,0xE5, 0x93,0x16, 0xFF,0x34, 0x83,0x16, 0xFE,0x64, 0x04,0x24, 0x00,0x02, 0x06,0xA0,
++0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x3C, 0x74,0x95,
++0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x2C, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x24,0x94,
++0x00,0x2A, 0x94,0x96, 0xFE,0x64, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xD8, 0x23,0x14, 0x00,0x26, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
++0x00,0x1E, 0x84,0x96, 0xFF,0x3C, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96,
++0xFF,0x34, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x83,0x16, 0xFF,0x2C, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0xA0, 0xF7,0x37,
++0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x06,0xA0,
++0x00,0x02, 0xF7,0x04, 0x4F,0x58, 0xF0,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x14, 0x94,0x16,
++0xFF,0x24, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0,
++0x00,0x16, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x01, 0xF4,0xA3, 0x28,0x00, 0x94,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xE0,0xBC, 0x26,0x94, 0x00,0x48, 0xF7,0x04, 0x42,0x80, 0xE0,0x00,
++0xE0,0x9C, 0xF6,0x06, 0x42,0x82, 0x86,0x96, 0xFE,0xF4, 0xE0,0x00, 0xE2,0x94, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x42,0x84, 0xF6,0x06, 0x42,0x84, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0xEA,0xA4, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x4C, 0x75,0x15,
++0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x93,0x16, 0xFF,0x1C, 0x07,0x18, 0x00,0x36, 0xF4,0x82,
++0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0xF0,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB8, 0x76,0xB5,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0x18, 0x00,0x02, 0x06,0x20, 0x00,0x02, 0x23,0x14,
++0x00,0x46, 0x93,0x16, 0xFF,0x14, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x95,
++0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x0C, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
++0xFF,0xE5, 0x93,0x16, 0xFF,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
++0xFE,0xFC, 0x23,0x00, 0x00,0x07, 0x93,0x16, 0xFE,0xF4, 0x84,0x96, 0xFF,0x1C, 0x83,0x16,
++0xFF,0x14, 0x04,0xA4, 0x00,0x0A, 0x94,0x96, 0xFE,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xF6,0x84, 0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x87,0x1A,
++0x00,0x00, 0xC6,0xA4, 0x6A,0x00, 0x74,0x34, 0xFF,0xFA, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xBC, 0x23,0x14,
++0x00,0x42, 0x93,0x16, 0xFF,0x14, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30,
++0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
++0x00,0x02, 0x87,0x16, 0xFF,0xC0, 0x24,0x94, 0x00,0x3E, 0x94,0x96, 0xFF,0x14, 0x76,0xA5,
++0x00,0x1E, 0x83,0x16, 0xFF,0x0C, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16,
++0xFF,0xC4, 0x24,0x94, 0x00,0x3A, 0x94,0x96, 0xFF,0x14, 0x76,0xA5, 0x00,0x1E, 0x83,0x16,
++0xFF,0x04, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
++0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0x84,0x96, 0xFE,0xFC, 0x06,0x30,
++0x00,0x02, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x83,0x16,
++0xFE,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x07, 0xEE,0x00, 0xE2,0x94, 0xF6,0x82,
++0x00,0x08, 0x84,0x96, 0xFE,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x0E, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x47,0x21, 0x00,0x00, 0xC0,0x36,
++0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xE0,0x88, 0x04,0xA4,
++0x00,0x02, 0x94,0x96, 0xFE,0x7C, 0x03,0x18, 0x00,0x01, 0xE0,0x00, 0xE2,0x30, 0x93,0x16,
++0xFE,0xF4, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x38, 0xF6,0xBB,
++0x28,0x00, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x23,0x14,
++0x00,0x78, 0x93,0x16, 0xFE,0xBC, 0x84,0x96, 0x00,0x00, 0x23,0x14, 0x00,0xA8, 0x86,0xA6,
++0x00,0x04, 0x87,0x26, 0x00,0x00, 0x93,0x16, 0xFE,0x9C, 0xC6,0xB4, 0x70,0x00, 0x96,0x96,
++0xFE,0xEC, 0xF7,0x02, 0x00,0x01, 0xC7,0x34, 0x74,0x00, 0x97,0x16, 0xFE,0xE4, 0x84,0x96,
++0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD4,0xB4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x22,
++0x72,0x00, 0xE6,0x00, 0xEA,0xA1, 0x94,0x16, 0xFF,0x1C, 0x86,0xA2, 0x00,0x38, 0x77,0x21,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFE,0xD4, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x96,0x96, 0xFE,0xDC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
++0x00,0x01, 0x20,0x26, 0x00,0x0E, 0xEE,0x00, 0xE2,0xF0, 0xF3,0x02, 0x00,0x0F, 0x93,0x13,
++0xFF,0xFC, 0x83,0x16, 0xFE,0xEC, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x48,0x00, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x27,0xE8, 0x97,0x93, 0xFF,0xFC, 0xC3,0xA0,
++0x00,0x00, 0x84,0x96, 0xFE,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
++0xE3,0x8D, 0x23,0x9C, 0x00,0x07, 0xC3,0x80, 0x3A,0x00, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
++0xFF,0x1C, 0xF4,0x82, 0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC7,0x18, 0x70,0x00, 0x07,0x38,
++0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x97,0x16, 0xFE,0xC4, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x4C,0x00, 0x76,0xB5,
++0x00,0x06, 0xC3,0x30, 0x68,0x00, 0x07,0x30, 0x00,0x40, 0xC0,0x1A, 0x72,0x00, 0xE6,0x00,
++0xE4,0x0D, 0x93,0x16, 0xFE,0xCC, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFE,0x74, 0x96,0x16,
++0xFE,0x6C, 0x96,0x96, 0xFE,0x68, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
++0xFF,0xFC, 0x83,0x96, 0xFE,0x74, 0x86,0x16, 0xFE,0x6C, 0x86,0x96, 0xFE,0x68, 0x20,0x22,
++0x00,0x00, 0xE6,0x00, 0xE0,0x95, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x4F,0x58, 0x84,0x96,
++0xFE,0xCC, 0x07,0x2C, 0x00,0x40, 0xC0,0x26, 0x72,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00,
++0x00,0x01, 0xA7,0x32, 0x68,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x86,0x16,
++0xFE,0xCC, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
++0xE4,0x51, 0xC0,0x32, 0x5A,0x00, 0xC6,0x2C, 0x00,0x00, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
++0xE6,0xE5, 0x25,0x14, 0x00,0x76, 0x83,0x16, 0xFF,0x1C, 0x84,0x96, 0xFE,0xBC, 0x06,0x18,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16,
++0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x74, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x72, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x70, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6E, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6C, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6A, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x25,0x14, 0x00,0x68, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
++0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x60, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
++0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
++0xFF,0xA0, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
++0xFE,0x5C, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20,
++0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFE,0xAC, 0x83,0x16,
++0xFE,0x5C, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8,
++0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xB4, 0x74,0x95,
++0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
++0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xA4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA4, 0x24,0x94,
++0x00,0x5A, 0x94,0x96, 0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x83,0x16, 0xFE,0xB4, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA8, 0x24,0x94, 0x00,0x56, 0x94,0x96,
++0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x47,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0xAC, 0x23,0x14, 0x00,0x52, 0x93,0x16, 0xFE,0x5C, 0x76,0x19, 0x00,0x1E, 0x84,0x96,
++0xFE,0xAC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB0, 0x83,0x16, 0xFE,0xA4, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0x8C, 0xF7,0x37,
++0x28,0x00, 0x84,0x96, 0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x36, 0x94,0x96,
++0xFE,0x5C, 0x87,0x26, 0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFE,0xCC, 0x84,0x96,
++0xFF,0x1C, 0x06,0x18, 0x00,0x3A, 0x85,0xB2, 0x00,0x00, 0x07,0x24, 0x00,0x3A, 0x86,0xBA,
++0x00,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC5,0xAC, 0x67,0xC0, 0xC6,0xB4, 0x77,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0xB5,
++0xFF,0xF0, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x00, 0xE7,0x64, 0xF5,0x02, 0x00,0x02, 0xF5,0x02,
++0x00,0x01, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x36, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xE7,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x2A,
++0x00,0x01, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFE,0x5C, 0x83,0x16,
++0xFF,0x1C, 0xF5,0x27, 0x28,0x00, 0x06,0x18, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x25,0x14, 0x00,0xA6, 0x84,0x96, 0xFE,0x9C, 0x83,0x16,
++0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA4, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA2, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA0, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9E, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9C, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9A, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
++0x00,0x00, 0x25,0x14, 0x00,0x98, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
++0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x90, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
++0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
++0xFF,0x70, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x94, 0x00,0x8E, 0x75,0x9D,
++0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16,
++0xFE,0x94, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
++0xFF,0xE5, 0x93,0x16, 0xFE,0x84, 0x83,0x16, 0xFE,0x94, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8, 0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
++0xFF,0xE5, 0x94,0x96, 0xFE,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
++0x28,0x00, 0x84,0x96, 0xFE,0xC4, 0x87,0x1E, 0x00,0x00, 0x75,0x25, 0x00,0x1E, 0xC7,0x38,
++0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0x74, 0x23,0x94, 0x00,0x8A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
++0xFE,0x8C, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
++0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x16, 0xFE,0x84, 0xC7,0x38,
++0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
++0xFF,0x78, 0x23,0x94, 0x00,0x86, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4,
++0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
++0x00,0x02, 0x87,0x16, 0xFF,0x7C, 0x23,0x94, 0x00,0x82, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
++0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFE,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0x80, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
++0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0xF3,0x02,
++0x00,0xFF, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xE8, 0xC6,0xB8, 0x34,0x00, 0xF7,0x02,
++0x00,0x80, 0xC7,0x34, 0x74,0x00, 0x77,0x39, 0x00,0x10, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
++0x00,0x00, 0xE6,0x00, 0xEA,0x61, 0x27,0x00, 0x01,0x00, 0xC6,0xB4, 0x75,0x80, 0x84,0x96,
++0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x38, 0xF6,0xBB, 0x28,0x00, 0x94,0x93,
++0xFF,0xFC, 0x83,0x16, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
++0x00,0x01, 0x04,0xA4, 0x00,0x01, 0xE0,0x00, 0xE3,0x3C, 0x94,0x96, 0xFE,0xD4, 0xF4,0x02,
++0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
++0x00,0x08, 0x86,0x96, 0x00,0x0C, 0xF5,0x02, 0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x84,0x16,
++0x00,0x10, 0xF4,0x84, 0xE0,0x00, 0x07,0x30, 0x00,0x02, 0x94,0xB2, 0x00,0x10, 0xF4,0x84,
++0xE0,0x04, 0x06,0xB4, 0x00,0x03, 0x94,0xB2, 0x00,0x14, 0xF4,0x84, 0xE0,0x1C, 0xC6,0xB4,
++0x54,0x00, 0x94,0xB2, 0x00,0x18, 0xF4,0x82, 0x00,0x05, 0xF4,0xB3, 0x28,0x00, 0xF4,0x82,
++0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x27,0x34, 0x00,0x08, 0x97,0x32, 0x00,0x04, 0x86,0x16,
++0x00,0x00, 0x07,0x2C, 0x00,0x03, 0xC7,0x38, 0x54,0x00, 0xC6,0xB8, 0x68,0x00, 0x96,0x93,
++0xFF,0xFC, 0xC6,0x30, 0x72,0x00, 0x96,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0xAC,
++0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38, 0x5A,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xC1,0x20, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0x83,0xBA, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x93,0x96, 0xFF,0xF0, 0xF3,0x84,
++0x6E,0x54, 0x87,0x3A, 0x00,0x04, 0x93,0x96, 0xFF,0xEC, 0x97,0x16, 0xFF,0xF4, 0x90,0x13,
++0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x20, 0x97,0x13,
++0xFF,0xFC, 0x94,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
++0xFF,0xFC, 0x84,0x96, 0xFF,0xE4, 0x83,0x96, 0x00,0x08, 0x87,0x26, 0x00,0x18, 0x85,0x16,
++0xFF,0xEC, 0xC0,0x3A, 0x3A,0x00, 0xEE,0x00, 0xEC,0x7C, 0xF5,0x82, 0x00,0x01, 0x87,0x26,
++0x00,0x18, 0x83,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x72,0x00, 0xE6,0x00,
++0xEC,0x7C, 0xC5,0x84, 0x00,0x00, 0x86,0xA6, 0x00,0x10, 0x87,0x16, 0xFF,0xF0, 0xF6,0x02,
++0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x1C, 0x04,0x24, 0x00,0x10, 0x86,0xA6,
++0x00,0x14, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
++0xEC,0x20, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0xEC,0x2D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xA2, 0x00,0x00, 0x87,0x16,
++0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEC,0x68, 0xF6,0x02,
++0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x70, 0x20,0x32, 0x00,0x00, 0x86,0xA2,
++0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
++0xEC,0x71, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0xEC,0x81, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
++0xEC,0xAC, 0xF7,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0x9C, 0xF6,0x06, 0x42,0x9C, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x02, 0x00,0x01, 0x97,0x2A, 0x00,0x08, 0x83,0xA6,
++0x00,0x0C, 0x77,0x2C, 0xFF,0xE1, 0x93,0xAA, 0x00,0x0C, 0x97,0x2A, 0x00,0x1C, 0x83,0xA6,
++0x00,0x1C, 0xF7,0x04, 0x6E,0x50, 0x93,0xAA, 0x00,0x20, 0x83,0xBA, 0x1D,0xDC, 0xF6,0x82,
++0x00,0x00, 0x93,0xAA, 0x00,0x2C, 0x83,0x96, 0x00,0x0C, 0xC5,0xB4, 0x00,0x00, 0x93,0xAA,
++0x00,0x30, 0x83,0xBA, 0x00,0x10, 0xC6,0x34, 0x00,0x00, 0x93,0xAA, 0x00,0x24, 0x87,0x3A,
++0x00,0x14, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x28, 0x20,0x36, 0x00,0x1F, 0xEE,0x00,
++0xED,0x1C, 0xC7,0x30, 0x50,0x00, 0x07,0x38, 0x00,0x34, 0x95,0xBA, 0x00,0x00, 0x06,0x30,
++0x00,0x04, 0xE0,0x00, 0xEC,0xFC, 0x06,0xB4, 0x00,0x01, 0x83,0x96, 0x00,0x10, 0x76,0xA5,
++0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0xB4, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
++0xFF,0xFC, 0x87,0x26, 0x00,0x20, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x86,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x16,
++0xFF,0xF0, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0xF6,0x02,
++0x1D,0xE0, 0x96,0x13, 0xFF,0xFC, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x13,
++0xFF,0xFC, 0xF6,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x26,0x14,
++0x00,0x10, 0x96,0x16, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x00, 0x87,0x36, 0x1D,0xD8, 0x96,0x16,
++0xFF,0xE4, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF6,0x86, 0x42,0xC0, 0xF7,0x37, 0x28,0x00, 0x86,0x16, 0xFF,0xEC, 0x00,0x00,
++0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xDB,0xB4, 0x97,0x93,
++0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00, 0x00,0x01, 0x86,0x16,
++0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00,
++0x00,0x01, 0xF6,0x02, 0x00,0x01, 0x96,0x16, 0xFF,0xE4, 0x84,0x16, 0xFF,0xE4, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x04, 0x86,0x16,
++0x00,0x00, 0x87,0x36, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xEE,0x99, 0x20,0x3A, 0x00,0x03, 0xE6,0x00, 0xEE,0xE9, 0xF4,0x02, 0x00,0x00, 0xE0,0x00,
++0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0xEF,0x0D, 0xF4,0x02, 0x00,0x00, 0x85,0x16, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x95,0x13,
++0xFF,0xFC, 0x85,0x16, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
++0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x96,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEB,0x60, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0xEF,0x0D, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xED,0x74, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x18, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF4,0x82, 0x00,0x00, 0x86,0x96,
++0x00,0x00, 0xF6,0x04, 0x4A,0xA0, 0x23,0x94, 0x00,0x10, 0x84,0x36, 0x00,0x00, 0x96,0x16,
++0xFF,0xE4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16, 0xFF,0xF0, 0x85,0x36, 0x00,0x04, 0xC0,0x32,
++0x72,0x00, 0xEC,0x00, 0xF0,0x14, 0x95,0x16, 0xFF,0xF4, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
++0x60,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4,
++0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x42,0x00, 0xE6,0x00, 0xEF,0xA4, 0xC6,0x24, 0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0xEF,0xA8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xEF,0xB5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
++0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
++0x72,0x00, 0xE2,0x00, 0xEF,0xF0, 0xF5,0x02, 0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00,
++0xEF,0xF8, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEF,0xF9, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
++0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xF0,0x09, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xF0,0x18, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
++0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xF0,0x4D, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xE8, 0xE0,0x00, 0xF0,0xB0, 0x96,0x96, 0xFF,0xEC, 0x27,0x14, 0x00,0x1C, 0x97,0x13,
++0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
++0xF0,0xAD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
++0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
++0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xE8, 0x96,0x96, 0xFF,0xEC, 0xF7,0x05,
++0x4A,0xA0, 0xE0,0x00, 0xF0,0xB4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
++0x00,0x00, 0xE6,0x00, 0xF1,0x21, 0xF4,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE8, 0xF6,0x06,
++0x42,0xC8, 0x76,0xB9, 0x00,0x02, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xA7,0x36,
++0x60,0x02, 0x83,0x16, 0x00,0x04, 0xC6,0xB4, 0x60,0x00, 0x76,0x35, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x05,0x34, 0x00,0x02, 0x75,0xA9, 0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
++0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x83,0x16,
++0x00,0x08, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x83,0x16,
++0x00,0x0C, 0x06,0xB4, 0x00,0x04, 0xE0,0x00, 0xF1,0x24, 0x96,0x9A, 0x00,0x00, 0xF4,0x02,
++0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0xB9,0x00, 0x00,0x00, 0xBA,0x00, 0x00,0x00,
++0xBB,0x00, 0x00,0x00, 0xBC,0x00, 0x00,0x00, 0xBD,0x00, 0x00,0x00, 0xBE,0x00, 0x00,0x00,
++0xBF,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x81,0x00, 0x00,0x00, 0x82,0x00, 0x00,0x00,
++0x83,0x00, 0x00,0x00, 0x84,0x00, 0x00,0x00, 0x85,0x00, 0x00,0x00, 0x86,0x00, 0x00,0x00,
++0x87,0x00, 0xB9,0xB9, 0xB9,0xBA, 0xB9,0xBB, 0xB9,0xBC, 0xB9,0xBD, 0xB9,0xBE, 0xB9,0xBF,
++0xB9,0x80, 0xB9,0x81, 0xB9,0x82, 0xB9,0x83, 0xB9,0x84, 0xB9,0x85, 0xB9,0x86, 0xB9,0x87,
++0xBA,0xB9, 0xBA,0xBA, 0xBA,0xBB, 0xBA,0xBC, 0xBA,0xBD, 0xBA,0xBE, 0xBA,0xBF, 0xBA,0x80,
++0xBA,0x81, 0xBA,0x82, 0xBA,0x83, 0xBA,0x84, 0xBA,0x85, 0xBA,0x86, 0xBA,0x87, 0xBB,0xB9,
++0xBB,0xBA, 0xBB,0xBB, 0xBB,0xBC, 0xBB,0xBD, 0xBB,0xBE, 0xBB,0xBF, 0xBB,0x80, 0xBB,0x81,
++0xBB,0x82, 0xBB,0x83, 0xBB,0x84, 0xBB,0x85, 0xBB,0x86, 0xBB,0x87, 0xBC,0xB9, 0xBC,0xBA,
++0xBC,0xBB, 0xBC,0xBC, 0xBC,0xBD, 0xBC,0xBE, 0xBC,0xBF, 0xBC,0x80, 0xBC,0x81, 0xBC,0x82,
++0xBC,0x83, 0xBC,0x84, 0xBC,0x85, 0xBC,0x86, 0xBC,0x87, 0xBD,0xB9, 0xBD,0xBA, 0xBD,0xBB,
++0xBD,0xBC, 0xBD,0xBD, 0xBD,0xBE, 0xBD,0xBF, 0xBD,0x80, 0xBD,0x81, 0xBD,0x82, 0xBD,0x83,
++0xBD,0x84, 0xBD,0x85, 0xBD,0x86, 0xBD,0x87, 0xBE,0xB9, 0xBE,0xBA, 0xBE,0xBB, 0xBE,0xBC,
++0xBE,0xBD, 0xBE,0xBE, 0xBE,0xBF, 0xBE,0x80, 0xBE,0x81, 0xBE,0x82, 0xBE,0x83, 0xBE,0x84,
++0xBE,0x85, 0xBE,0x86, 0xBE,0x87, 0xBF,0xB9, 0xBF,0xBA, 0xBF,0xBB, 0xBF,0xBC, 0xBF,0xBD,
++0xBF,0xBE, 0xBF,0xBF, 0xBF,0x80, 0xBF,0x81, 0xBF,0x82, 0xBF,0x83, 0xBF,0x84, 0xBF,0x85,
++0xBF,0x86, 0xBF,0x87, 0x80,0xB9, 0x80,0xBA, 0x80,0xBB, 0x80,0xBC, 0x80,0xBD, 0x80,0xBE,
++0x80,0xBF, 0x80,0x80, 0x80,0x81, 0x80,0x82, 0x80,0x83, 0x80,0x84, 0x80,0x85, 0x80,0x86,
++0x80,0x87, 0x81,0xB9, 0x81,0xBA, 0x81,0xBB, 0x81,0xBC, 0x81,0xBD, 0x81,0xBE, 0x81,0xBF,
++0x81,0x80, 0x81,0x81, 0x81,0x82, 0x81,0x83, 0x81,0x84, 0x81,0x85, 0x81,0x86, 0x81,0x87,
++0x82,0xB9, 0x82,0xBA, 0x82,0xBB, 0x82,0xBC, 0x82,0xBD, 0x82,0xBE, 0x82,0xBF, 0x82,0x80,
++0x82,0x81, 0x82,0x82, 0x82,0x83, 0x82,0x84, 0x82,0x85, 0x82,0x86, 0x82,0x87, 0x83,0xB9,
++0x83,0xBA, 0x83,0xBB, 0x83,0xBC, 0x83,0xBD, 0x83,0xBE, 0x83,0xBF, 0x83,0x80, 0x83,0x81,
++0x83,0x82, 0x83,0x83, 0x83,0x84, 0x83,0x85, 0x83,0x86, 0x83,0x87, 0x84,0xB9, 0x84,0xBA,
++0x84,0xBB, 0x84,0xBC, 0x84,0xBD, 0x84,0xBE, 0x84,0xBF, 0x84,0x80, 0x84,0x81, 0x84,0x82,
++0x84,0x83, 0x84,0x84, 0x84,0x85, 0x84,0x86, 0x84,0x87, 0x85,0xB9, 0x85,0xBA, 0x85,0xBB,
++0x85,0xBC, 0x85,0xBD, 0x85,0xBE, 0x85,0xBF, 0x85,0x80, 0x85,0x81, 0x85,0x82, 0x85,0x83,
++0x85,0x84, 0x85,0x85, 0x85,0x86, 0x85,0x87, 0x86,0xB9, 0x86,0xBA, 0x86,0xBB, 0x86,0xBC,
++0x86,0xBD, 0x86,0xBE, 0x86,0xBF, 0x86,0x80, 0x86,0x81, 0x86,0x82, 0x86,0x83, 0x86,0x84,
++0x86,0x85, 0x86,0x86, 0x86,0x87, 0x87,0xB9, 0x87,0xBA, 0x87,0xBB, 0x87,0xBC, 0x87,0xBD,
++0x87,0xBE, 0x87,0xBF, 0x87,0x80, 0x87,0x81, 0x87,0x82, 0x87,0x83, 0x87,0x84, 0x87,0x85,
++0x87,0x86, 0x87,0x87, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x18, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xF3,0x7D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0xF5,0xE0, 0xF7,0x33, 0x28,0x00, 0xF3,0x84, 0x6F,0x30, 0x90,0x13,
++0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0xF7,0x02, 0x00,0x00, 0x97,0x1E,
++0x00,0x08, 0x83,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0x1E, 0x00,0x0C, 0x83,0x16,
++0x00,0x08, 0x04,0x9C, 0x00,0x22, 0x93,0x1E, 0x00,0x1C, 0x83,0x16, 0x00,0x0C, 0x93,0x96,
++0xFF,0xF4, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x18,
++0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0x06,0x9C, 0x00,0x20, 0xF7,0x37, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x96,0x96,
++0xFF,0xE4, 0x75,0x35, 0x00,0x1E, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x04,0x9C, 0x00,0x24, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x04,0x9C, 0x00,0x26, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x04,0x9C, 0x00,0x28, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x04,0x9C, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x04,0x9C, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x04,0x9C, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x04,0x9C, 0x00,0x30, 0x76,0x31,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
++0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00, 0xF5,0x98, 0xF3,0x06, 0x14,0xD8, 0x83,0x16,
++0xFF,0xE4, 0x87,0x1E, 0x00,0x20, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x25,0xB8, 0x00,0x01, 0xC4,0xAC, 0x58,0x00, 0x04,0x24,
++0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xF5,0x95, 0xF5,0x02, 0x00,0x00, 0x83,0x16,
++0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x06,0x18, 0x00,0x02, 0xA7,0x32, 0x58,0x02, 0xC6,0xB0,
++0x58,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xE8, 0xC6,0xB0, 0x40,0x00, 0x77,0xB8, 0x00,0x18, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
++0xF5,0x7D, 0xF7,0x37, 0x68,0x00, 0xF5,0x02, 0xFF,0xFF, 0xC7,0x30, 0x48,0x00, 0xF5,0x3B,
++0x68,0x00, 0x24,0xA4, 0x00,0x02, 0x24,0x20, 0x00,0x02, 0xE0,0x00, 0xF5,0x34, 0x25,0xAC,
++0x00,0x01, 0xF3,0x06, 0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x34, 0x93,0x13,
++0xFF,0xFC, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF7,0x04,
++0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xF6,0x39, 0xF6,0x06,
++0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
++0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
++0xF7,0x48, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00, 0x00,0x01, 0x95,0x16,
++0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
++0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00, 0xF6,0x99, 0x96,0x96,
++0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x85,0x16,
++0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28, 0x72,0x00, 0x97,0x13,
++0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0xF7,0x02,
++0x00,0x02, 0x97,0x2A, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xAA,
++0x00,0x0C, 0x85,0x96, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0xAA, 0x00,0x1C, 0xF5,0x06,
++0x14,0xD8, 0x95,0x13, 0xFF,0xFC, 0xF5,0x82, 0x00,0x20, 0x95,0x93, 0xFF,0xFC, 0x85,0x16,
++0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16,
++0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
++0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0x00,0x04, 0x87,0x16, 0x00,0x08, 0xF6,0x02,
++0xFF,0xFC, 0x06,0xA8, 0x00,0x03, 0xC6,0xB4, 0x64,0x00, 0x07,0x38, 0x00,0x03, 0xC7,0x38,
++0x64,0x00, 0xC7,0x34, 0x70,0x00, 0x97,0x13, 0xFF,0xFC, 0xC5,0xAC, 0x6A,0x00, 0x95,0x93,
++0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0x28, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
++0x52,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x14,0xD8, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x10, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xF8,0x0D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0xF9,0x20, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00,
++0x00,0x01, 0x95,0x16, 0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
++0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02,
++0x00,0x00, 0x86,0xAA, 0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00,
++0xF8,0x6D, 0x96,0x96, 0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96,
++0xFF,0xEC, 0x85,0x16, 0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28,
++0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
++0xFF,0xF4, 0xF5,0x82, 0x00,0x06, 0xF5,0xAB, 0x28,0x00, 0x85,0x96, 0x00,0x08, 0x07,0x28,
++0x00,0x02, 0x95,0xAA, 0x00,0x04, 0x05,0x14, 0x00,0x0E, 0x85,0x2A, 0x00,0x00, 0x77,0xA9,
++0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0xF5,0x3B,
++0x28,0x00, 0xF5,0x86, 0x14,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF5,0x02, 0x00,0x08, 0x95,0x13,
++0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
++0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04,
++0x75,0xEC, 0x83,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xFA,0x64, 0xF6,0x06,
++0x42,0x96, 0xF5,0x04, 0x6F,0x30, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
++0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0xF4, 0x95,0x16, 0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
++0xFF,0xFC, 0x85,0x16, 0xFF,0xF0, 0xF3,0x02, 0x00,0x07, 0x83,0x96, 0xFF,0xF4, 0xF3,0x2B,
++0x28,0x00, 0x07,0x28, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x3B, 0x28,0x00, 0x87,0x1E,
++0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x76,0x2D,
++0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x04,0x1C,
++0x00,0x06, 0x83,0x16, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x06,0xA8,
++0x00,0x04, 0xF7,0x37, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0xA8, 0x00,0x06, 0x75,0xA1,
++0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
++0x00,0x04, 0x75,0xAC, 0xFF,0xE5, 0x06,0xA8, 0x00,0x08, 0x76,0x19, 0x00,0x1E, 0xC7,0x38,
++0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x06,0xA8,
++0x00,0x0A, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x06,
++0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x0C, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
++0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xFA,0x84, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
++0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
++0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x48, 0xF7,0x04, 0x75,0xEC, 0x85,0x96, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
++0xFD,0x98, 0xF6,0x06, 0x42,0x96, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x14, 0x00,0x1E, 0x06,0x2C, 0x00,0x02, 0x75,0x31,
++0x00,0x1E, 0x24,0x94, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xF3,0x84, 0x6E,0x50, 0xC7,0x38,
++0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x93,0x96,
++0xFF,0xC4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
++0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
++0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x90,0x13,
++0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
++0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
++0xFF,0xBC, 0x23,0x14, 0x00,0x36, 0x24,0x94, 0x00,0x38, 0x73,0xA5, 0x00,0x1E, 0x73,0x9C,
++0xFF,0xE5, 0xF4,0x04, 0x42,0xC0, 0xF6,0x86, 0x42,0xC0, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0x87,0x2E, 0x00,0x00, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC4,0x20,
++0x6F,0xC0, 0x74,0x20, 0xFF,0xF0, 0x05,0xAC, 0x00,0x02, 0x75,0x2D, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2E,
++0x00,0x00, 0xF6,0x04, 0x6E,0x50, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x23,0x14, 0x00,0x34, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x23,0x14, 0x00,0x32, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x23,0x14, 0x00,0x30, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x23,0x14, 0x00,0x2E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x23,0x14, 0x00,0x2C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x23,0x14, 0x00,0x2A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x28, 0x75,0xAD,
++0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
++0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0xF6,0x82, 0x00,0x03, 0xC7,0x38, 0x3F,0xC0, 0x96,0xB2,
++0x00,0x08, 0x06,0xB0, 0x1D,0xD8, 0xF4,0x37, 0x28,0x00, 0xF3,0x86, 0x14,0xD8, 0x93,0x93,
++0xFF,0xFC, 0xF3,0x82, 0x1D,0xE0, 0x93,0x93, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x77,0x39,
++0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
++0xFD,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
++0x00,0x06, 0xE6,0x00, 0xFE,0x21, 0xF5,0x82, 0x00,0x1E, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06,
++0x42,0xA8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
++0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0xFE,0x34, 0xF7,0x33, 0x28,0x00, 0xF6,0x05,
++0x6F,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
++0x00,0x00, 0x85,0x96, 0x00,0x04, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00,
++0xFE,0x9D, 0xF4,0x02, 0x00,0x00, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06, 0x42,0xAA, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xE0,0x00, 0xFF,0x1C, 0xF7,0x33, 0x28,0x00, 0x07,0x30, 0x00,0x02, 0x86,0xBA,
++0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
++0xFF,0xF0, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xFE,0xD5, 0xF6,0x05, 0x6F,0x34, 0x20,0x36,
++0x00,0x02, 0xE6,0x00, 0xFE,0xE5, 0xF5,0x02, 0x00,0x20, 0xE0,0x00, 0xFE,0xFC, 0xF6,0x06,
++0x42,0xAC, 0x20,0x2E, 0x00,0x0C, 0xE6,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x00, 0xF5,0x02,
++0x00,0x1F, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x08, 0x97,0x36, 0x00,0x04, 0x87,0x36,
++0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0xFF,0x7D, 0xF6,0x85,
++0x6F,0x34, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x03, 0xEE,0x00,
++0xFF,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
++0xFF,0xBD, 0xF6,0x06, 0x42,0xAE, 0xF7,0x04, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
++0x00,0x08, 0xF6,0x82, 0xFF,0xEC, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x00,0x00,
++0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x00, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
++0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
++0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x17, 0x00,0x00,
++0x00,0x1A, 0x00,0x00, 0x00,0x1D, 0x00,0x00, 0x00,0x18, 0x00,0x00, 0x00,0x00, 0x56,0x65,
++0x72,0x73, 0x69,0x6F, 0x6E,0x53, 0x74,0x72, 0x69,0x6E, 0x67,0x3A, 0x20,0x6D, 0x63,0x70,
++0x2D,0x6C, 0x34,0x76, 0x33,0x20, 0x33,0x2E, 0x30,0x38, 0x63,0x20, 0x44,0x65, 0x63,0x20,
++0x31,0x31, 0x20,0x31, 0x39,0x39, 0x36,0x20, 0x31,0x33, 0x3A,0x30, 0x36,0x3A, 0x31,0x36,
++0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x0C, 0xFF,0x02,
++0x00,0x00, 0x97,0x02, 0xFF,0x84, 0xF7,0x06, 0x0C,0x3E, 0xCF,0xFC, 0x75,0x80, 0xF6,0x02,
++0x00,0x02, 0x96,0x02, 0xFF,0x8C, 0x90,0x02, 0xFF,0x88, 0xF7,0x04, 0xE0,0x20, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x00,0x74, 0xF6,0x82, 0x00,0x00, 0xF6,0x82,
++0x00,0x03, 0x96,0x82, 0xFF,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x0C, 0xF5,0x02, 0x14,0x94, 0xF5,0x05, 0x7B,0x00, 0xF5,0x0E,
++0xF0,0x14, 0xF5,0x05, 0x7B,0x08, 0xF7,0x06, 0xE0,0x00, 0xF6,0x86, 0x7B,0x68, 0xC7,0x38,
++0x6A,0x00, 0xF7,0x05, 0x7A,0xF0, 0xF5,0x02, 0x00,0x4C, 0xF6,0x82, 0x00,0x00, 0x20,0x36,
++0x00,0x02, 0xEE,0x01, 0x01,0x24, 0xF5,0x05, 0x7A,0xF8, 0xC5,0xB4, 0x00,0x00, 0xC6,0x34,
++0x00,0x00, 0xF7,0x06, 0xE0,0x30, 0xC7,0x2C, 0x70,0x00, 0xF5,0x06, 0x6F,0x44, 0xB7,0x32,
++0x50,0x02, 0x90,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
++0xFF,0xF0, 0x96,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93,
++0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x86,0x16, 0xFF,0xF0, 0x86,0x96, 0xFF,0xEC, 0x05,0xAC,
++0x14,0x94, 0x06,0xB4, 0x00,0x01, 0x20,0x36, 0x00,0x02, 0xEE,0x01, 0x00,0xD5, 0x06,0x30,
++0x00,0x04, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF0,0x05,
++0x6F,0x50, 0xF0,0x05, 0x2D,0x40, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x29,0x58, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
++0x00,0x03, 0xF7,0x05, 0xE0,0x08, 0xF7,0x04, 0x7A,0xD8, 0xF6,0x02, 0x00,0x01, 0x96,0x02,
++0xFF,0x94, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x01,0x91, 0xF7,0x06, 0x7A,0xE8, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x03,0xDC, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7A,0xE8, 0xF6,0x02,
++0x00,0x05, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06, 0x7A,0xE0, 0x86,0x82, 0xFF,0x44, 0xF6,0x02,
++0x00,0x03, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x01,0xC9, 0xF6,0x3B, 0x28,0x00, 0xF7,0x04,
++0x6F,0x64, 0x86,0x82, 0xFF,0x44, 0x07,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
++0x01,0xB0, 0xF7,0x05, 0x6F,0x64, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x34, 0x97,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x8C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x44,0x28, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0xF0, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x0C,0x60, 0x97,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x04,0x08, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x0B,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1D,0x68, 0x97,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0x50, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x5F,0x68, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x6D,0xEC, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x21,0xD0, 0x97,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x22,0x2C, 0x97,0x93, 0xFF,0xFC, 0x90,0x02,
++0xFF,0x94, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x0B,0xFC, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02,
++0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x08, 0xF6,0x02, 0x00,0x00, 0xC5,0xB0, 0x00,0x00, 0x20,0x32, 0x00,0x02, 0xEE,0x01,
++0x03,0x08, 0xF5,0x06, 0x6F,0x44, 0xA6,0xAE, 0x50,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xE6,0x01, 0x02,0xFC, 0xF5,0x02,
++0x00,0x02, 0x95,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
++0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
++0xFF,0xF0, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x04, 0xE0,0x01,
++0x02,0xAC, 0x06,0x30, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x87,0x16, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x82, 0x00,0x08, 0x96,0x3A,
++0x00,0x08, 0x96,0x3A, 0x00,0x0C, 0x96,0x3A, 0x09,0xD8, 0x96,0x3A, 0x09,0xDC, 0x96,0x3A,
++0x0E,0xF4, 0x96,0x3A, 0x0E,0xF8, 0x96,0xBA, 0x14,0x20, 0x96,0x3A, 0x14,0x24, 0x90,0xBA,
++0x14,0x8C, 0x86,0x96, 0x00,0x04, 0x90,0xBA, 0x14,0x90, 0x96,0xBA, 0x00,0x00, 0x96,0x3A,
++0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
++0x00,0x00, 0x87,0x16, 0x00,0x08, 0x86,0x16, 0x00,0x04, 0x77,0x38, 0xFF,0xFF, 0xC5,0x30,
++0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x03,0xC9, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
++0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE4,0x01,
++0x03,0xA0, 0x05,0xAC, 0x00,0x02, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xE0,0x01, 0x03,0xE8, 0xF7,0x05, 0x7A,0xD8, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02,
++0x00,0x0A, 0xF5,0x05, 0x71,0xCC, 0xF0,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD0, 0xF0,0x05,
++0x71,0xC4, 0xF5,0x02, 0x00,0x01, 0xF6,0x82, 0x00,0x00, 0x20,0x36, 0x00,0x0A, 0xEC,0x01,
++0x04,0x64, 0xF5,0x05, 0x71,0xC8, 0xF5,0x8A, 0x1E,0x00, 0xF6,0x06, 0x71,0xC4, 0x47,0x2C,
++0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30, 0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04,
++0x71,0xCC, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x04,0x41, 0x05,0xAC,
++0x21,0x4C, 0xF0,0x05, 0x71,0x98, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
++0x7B,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x06, 0x05,0xD4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0xA0, 0x95,0x13,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x70,0x80, 0x95,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
++0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
++0x70,0x80, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x06, 0x05,0x58, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x0A, 0x95,0x13,
++0xFF,0xFC, 0xF5,0x06, 0x71,0x0C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
++0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0x7D, 0xF6,0x86,
++0x71,0xC4, 0xE0,0x01, 0x05,0x94, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x71,0xD0, 0x00,0x00,
++0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0xAC, 0xF7,0x05, 0x7B,0x10, 0xF6,0x06,
++0x71,0x0C, 0xE0,0x01, 0x05,0xC0, 0xF6,0x05, 0x7B,0x18, 0xF6,0x06, 0x6F,0x68, 0xF6,0x05,
++0x7B,0x18, 0x97,0x02, 0xFF,0x48, 0x07,0x38, 0x21,0x28, 0x97,0x02, 0xFF,0x4C, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0x86,0x82,
++0xFF,0x48, 0xF4,0x86, 0x6F,0x68, 0xF4,0x85, 0x7B,0x18, 0xF5,0x04, 0x7B,0x10, 0x26,0xB4,
++0x00,0x02, 0x85,0xB6, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x76,0x29, 0x00,0x1E, 0x76,0x30,
++0xFF,0xE5, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x6F,0xC0, 0xC7,0x38,
++0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0xB8, 0x00,0x10, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x06,0x45, 0x75,0xAC, 0xFF,0xF0, 0xF7,0x04, 0x71,0xAC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x71,0xAC, 0xF7,0x04, 0x71,0xAC, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
++0x00,0x01, 0x77,0x2C, 0xFF,0xF8, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x06,0x71, 0x76,0xA9,
++0x00,0x1E, 0xF7,0x04, 0x71,0xA8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x71,0xA8, 0xF7,0x04, 0x71,0xA8, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A,
++0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38,
++0x00,0x04, 0x20,0x3A, 0x00,0x03, 0xE2,0x01, 0x08,0xA4, 0x00,0x00, 0x00,0x01, 0x77,0x39,
++0x00,0x02, 0xF6,0x86, 0x06,0xA4, 0xA6,0xB6, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34,
++0x00,0x00, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x07,0x7C, 0x00,0x01, 0x07,0xEC, 0x00,0x01,
++0x08,0x44, 0x87,0x2A, 0x00,0x04, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x01,
++0x06,0xD8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
++0x52,0x00, 0x97,0x2A, 0x00,0x04, 0x87,0x2A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x21,0x00, 0xEE,0x01, 0x07,0x3C, 0xF6,0x02, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0x87,0x02,
++0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x28, 0xC0,0x36,
++0x72,0x00, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x01, 0x07,0x3D, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E,
++0xFF,0xE1, 0xE6,0x01, 0x07,0x44, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x01, 0x08,0x88, 0x00,0x00, 0x00,0x01, 0x87,0x2A, 0x00,0x18, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xEE,0x01, 0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x71,0xA4, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xA4, 0xF7,0x04,
++0x71,0xA4, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x21,0x00, 0xEE,0x01, 0x07,0xE0, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
++0x00,0x04, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38,
++0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
++0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
++0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE1, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
++0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
++0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x04, 0x20,0x3A, 0x00,0x08, 0xE6,0x01,
++0x08,0x38, 0xF6,0x82, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x08,0x38, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x08,0x39, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x08,0x80, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x36,
++0x00,0x00, 0xF7,0x02, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x08,0x78, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x08,0x79, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
++0x08,0x80, 0x20,0x3A, 0x00,0x00, 0xF7,0x02, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xA0, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x71,0xA0, 0xF7,0x04, 0x71,0xA0, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
++0x00,0x01, 0xF7,0x04, 0x71,0x9C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x71,0x9C, 0xF7,0x04, 0x71,0x9C, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
++0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x68, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
++0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
++0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38, 0x00,0x04, 0x20,0x3A,
++0x00,0x03, 0xE2,0x01, 0x0B,0x50, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x09,0x0C, 0xA6,0xB6,
++0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x01, 0x09,0x1C, 0x00,0x01,
++0x0A,0xE0, 0x00,0x01, 0x0A,0xAC, 0x00,0x01, 0x0B,0x14, 0xF7,0x04, 0x71,0xD0, 0xF6,0x04,
++0x71,0xCC, 0x06,0xB8, 0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0x38, 0xC7,0x34,
++0x00,0x00, 0xF7,0x02, 0x00,0x00, 0xF5,0x84, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x85, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x71,0xB0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x71,0xB0, 0xF7,0x04, 0x71,0xB0, 0xF7,0x04, 0x71,0xB4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x71,0xB4, 0xF7,0x04, 0x71,0xB4, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
++0x00,0x01, 0xF4,0x84, 0x71,0xC8, 0xF6,0x85, 0x71,0xD0, 0x94,0x96, 0xFF,0xF4, 0xF4,0x84,
++0x7B,0x10, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0xA4, 0x94,0x96, 0xFF,0xEC, 0xF0,0x05,
++0x71,0xD0, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC8, 0x84,0x96, 0xFF,0xEC, 0xC0,0x3A,
++0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0xF7,0x05, 0x71,0xC4, 0x87,0x26, 0x00,0x08, 0x00,0x00,
++0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x09,0xE1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x71,0x98, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0x98, 0x84,0x96,
++0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x0A,0x71, 0x00,0x00,
++0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0xF6,0x02,
++0x00,0x09, 0x20,0x32, 0x00,0x14, 0xE6,0x01, 0x0A,0x4D, 0x27,0x00, 0x00,0x0C, 0x20,0x3A,
++0x00,0x01, 0xE2,0x01, 0x0A,0x4D, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00,
++0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
++0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x01,
++0x0A,0x4D, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x04, 0x2D,0x68, 0x00,0x00,
++0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x28, 0x00,0x00,
++0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
++0x71,0xBC, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xBC, 0xF7,0x04,
++0x71,0xBC, 0x86,0xA6, 0x00,0x04, 0x84,0x96, 0xFF,0xF4, 0xF7,0x04, 0x71,0xB8, 0x20,0x26,
++0x00,0x00, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x71,0xB8, 0xE6,0x01, 0x0B,0x51, 0x00,0x00,
++0x00,0x01, 0xE0,0x01, 0x0B,0x5C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00,
++0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF4,0x84,
++0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0xFD,0xCC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04,
++0x71,0xC0, 0xF4,0x84, 0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0xFF,0x30, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF6,0x84, 0x7B,0x10, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
++0x00,0x01, 0xC7,0x38, 0x6A,0x00, 0x27,0x38, 0x00,0x04, 0x97,0x13, 0xFF,0xFC, 0x96,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFE,0x48, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x70,0x80, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x6F,0x68, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x6F,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x6F,0xF4, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x70,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x71,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02, 0x00,0x04, 0xF5,0x05, 0x76,0x00, 0xF0,0x05,
++0x76,0x08, 0xF0,0x05, 0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF5,0x02, 0x00,0x01, 0xF6,0x82,
++0x00,0x00, 0x20,0x36, 0x00,0x04, 0xEC,0x01, 0x0C,0xBC, 0xF5,0x05, 0x75,0xFC, 0xF5,0x8E,
++0x6A,0xF8, 0xF6,0x06, 0x75,0xF8, 0x47,0x2C, 0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30,
++0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xEC,0x01, 0x0C,0x99, 0x05,0xAC, 0x21,0x4C, 0xF5,0x06, 0x72,0x18, 0x95,0x13,
++0xFF,0xFC, 0xF5,0x06, 0x76,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0xA4, 0x95,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
++0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
++0x73,0x30, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x06, 0x16,0xC8, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93,
++0xFF,0xFC, 0xF5,0x06, 0x73,0xBC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x18,0x00, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
++0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x16,0x40, 0x95,0x13,
++0xFF,0xFC, 0xF7,0x82, 0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0xD4, 0x95,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
++0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x12, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
++0x75,0x60, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
++0xFF,0xFC, 0xF0,0x05, 0x75,0xF0, 0xF0,0x05, 0x75,0xEC, 0xF0,0x05, 0x75,0xF4, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
++0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x28, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x0E,0x3D, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x59, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01,
++0x0E,0x6C, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39,
++0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04, 0x76,0xFC, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x90, 0xF6,0x85, 0x76,0x60, 0xF3,0x06,
++0x76,0x48, 0xF3,0x05, 0x76,0xFC, 0xE0,0x01, 0x0E,0xA4, 0xF7,0x02, 0x00,0x01, 0xF3,0x02,
++0x00,0x10, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x76,0x48, 0xF3,0x05, 0x77,0x00, 0xF7,0x02,
++0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x15, 0xF3,0x06, 0x74,0x48, 0xF7,0x04,
++0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0xD8, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x0E,0xED, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00,
++0x00,0x01, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01,
++0x0F,0x21, 0xF4,0x82, 0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x00,0xBC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4,
++0x00,0x00, 0x84,0x1E, 0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
++0xFF,0xC4, 0x94,0x16, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04,
++0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x10,0x0C, 0x95,0x16,
++0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
++0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x0F,0x9C, 0xC6,0x24,
++0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01,
++0x0F,0xA0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
++0x0F,0xAD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
++0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x0F,0xE8, 0xF5,0x02,
++0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x01, 0x0F,0xF0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
++0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01,
++0x0F,0xF1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01,
++0x10,0x01, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01,
++0x10,0x10, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01,
++0x10,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
++0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
++0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x10,0xB8, 0x96,0x96,
++0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
++0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
++0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
++0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x01, 0x10,0xB5, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
++0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
++0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x10,0xBC, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x10,0xCC, 0xF4,0x82,
++0x00,0x01, 0xE0,0x01, 0x11,0x24, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
++0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
++0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
++0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
++0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
++0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
++0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x11,0x38, 0xF5,0x82, 0x00,0x00, 0xE0,0x01,
++0x11,0xCC, 0xF6,0x02, 0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34,
++0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x11,0x98, 0xC5,0x24,
++0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2,
++0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
++0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28,
++0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01,
++0x11,0x59, 0x06,0x30, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02,
++0x00,0x01, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38,
++0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02,
++0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
++0x13,0x10, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01,
++0x12,0x30, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
++0x12,0x1C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05,
++0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x01, 0x12,0x34, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05,
++0x76,0xFC, 0xF7,0x04, 0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x12,0x71, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32,
++0x00,0x44, 0xE6,0x01, 0x12,0x70, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
++0x76,0x08, 0xF6,0x84, 0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01,
++0x12,0x8C, 0xF7,0x05, 0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04,
++0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x12,0xB9, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01,
++0x12,0xC8, 0xF7,0x02, 0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
++0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x09, 0xF7,0x05,
++0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
++0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x13,0x18, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01,
++0x13,0x18, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x72,0x18, 0xF3,0x06,
++0x73,0x30, 0xF3,0x05, 0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x04, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x04, 0xF7,0x04,
++0x76,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x76,0x54, 0xF7,0x04,
++0x76,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x76,0x58, 0xF7,0x04,
++0x75,0xF8, 0xF6,0x84, 0x76,0x58, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x9D, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
++0x13,0x9C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
++0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x13,0xB8, 0xF7,0x05,
++0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF7,0x04, 0x76,0x08, 0xF6,0x84, 0x76,0x04, 0xF0,0x05,
++0x75,0xF8, 0xF5,0x84, 0x76,0xF8, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x2E,
++0x00,0x21, 0xE2,0x01, 0x14,0x14, 0xF7,0x05, 0x75,0xFC, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
++0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
++0x00,0x44, 0xE6,0x01, 0x14,0x00, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
++0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01, 0x14,0x18, 0xF5,0x05,
++0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04, 0x75,0xEC, 0xF5,0x06, 0x72,0x18, 0x20,0x3A,
++0x00,0x00, 0xE6,0x01, 0x14,0x40, 0xF5,0x05, 0x76,0x48, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0x55, 0x00,0x00, 0x00,0x01, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x14,0xC4, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x14,0x71, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x14,0x88, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
++0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
++0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0xC5, 0xF7,0x05,
++0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
++0x14,0xBC, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06, 0x72,0xA4, 0xF5,0x05,
++0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
++0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x40, 0xF4,0x02,
++0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xEC, 0x86,0x96,
++0x00,0x08, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x7B,0x38, 0x86,0x96, 0x00,0x00, 0xF7,0x04,
++0x76,0x48, 0xF6,0x85, 0x7B,0x30, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x41, 0xF4,0x02, 0x00,0x01, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x75,0xF4, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0xBC, 0xF4,0x02, 0x00,0x00, 0x86,0x96,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xF0, 0x86,0x96, 0x00,0x08, 0x00,0x00,
++0x00,0x01, 0xF6,0x85, 0x7B,0x48, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x76,0x48, 0xF6,0x85,
++0x7B,0x40, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x01, 0x15,0xBD, 0xF4,0x02, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x01, 0x15,0xFC, 0xF6,0x82, 0x00,0x10, 0xF6,0x86, 0x76,0x48, 0xF6,0x85,
++0x76,0xFC, 0xE0,0x01, 0x16,0x0C, 0xF7,0x02, 0x00,0x01, 0xF6,0x85, 0x76,0xF8, 0xF6,0x86,
++0x76,0x48, 0xF6,0x85, 0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x16,0x20, 0xF6,0x86, 0x74,0xD4, 0xE0,0x01, 0x16,0x2C, 0xF6,0x85, 0x76,0x48, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0xE6,0x01, 0x16,0x85, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x75,0xF4, 0xF6,0x84,
++0x7B,0x48, 0xF7,0x05, 0x76,0xF4, 0xF7,0x04, 0x7B,0x40, 0xC6,0xB0, 0x68,0x00, 0x26,0xB4,
++0x00,0x04, 0x97,0x02, 0xFF,0x6C, 0x96,0x02, 0xFF,0x50, 0xE0,0x01, 0x16,0xA8, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0xF6,0x84, 0x7B,0x38, 0xF5,0x82, 0x00,0x01, 0xF5,0x85,
++0x76,0xF4, 0xF6,0x04, 0x7B,0x30, 0xC6,0xB8, 0x68,0x00, 0x26,0xB4, 0x00,0x04, 0x96,0x02,
++0xFF,0x6C, 0x97,0x02, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF5,0x86, 0x73,0xBC, 0xF5,0x85,
++0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
++0x7B,0x28, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7B,0x28, 0xF7,0x04,
++0x75,0xF4, 0xF6,0x84, 0x7B,0x28, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x21, 0x00,0x00,
++0x00,0x01, 0xF0,0x05, 0x75,0xF4, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x01, 0x17,0x25, 0xF0,0x05, 0x75,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x17,0xEC, 0x00,0x00, 0x00,0x01, 0xF0,0x05,
++0x75,0xEC, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
++0x17,0x41, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x17,0x58, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
++0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
++0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x95, 0xF7,0x05,
++0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
++0x17,0x8C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x17,0x98, 0xF5,0x06,
++0x72,0xA4, 0xF5,0x06, 0x72,0x18, 0xF5,0x05, 0x76,0x48, 0xF5,0x84, 0x76,0xF8, 0x00,0x00,
++0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x17,0xE8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
++0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
++0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x17,0xD4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
++0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01,
++0x17,0xEC, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x49, 0x00,0x00,
++0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01,
++0x1C,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x87,0x36,
++0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x18,0x7D, 0xF4,0x82,
++0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x00,0xBC, 0x97,0x93,
++0xFF,0xFC, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4, 0x00,0x00, 0x84,0x1E,
++0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x94,0x16,
++0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x19,0x68, 0x95,0x16, 0xFF,0xE4, 0x77,0x35,
++0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8,
++0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x18,0xF8, 0xC6,0x24, 0x00,0x00, 0x87,0x36,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01, 0x18,0xFC, 0x20,0x32,
++0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x19,0x09, 0x00,0x00,
++0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xE0, 0x00,0x00,
++0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x19,0x44, 0xF5,0x02, 0x00,0x00, 0xC0,0x32,
++0x72,0x00, 0xE6,0x01, 0x19,0x4C, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16,
++0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01, 0x19,0x4D, 0x20,0x2A,
++0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01, 0x19,0x5D, 0x20,0x2E,
++0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01, 0x19,0x6C, 0x20,0x26,
++0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x19,0xA1, 0xF6,0x02,
++0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
++0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
++0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x1A,0x14, 0x96,0x96, 0xFF,0xDC, 0x27,0x14,
++0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13,
++0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xCC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xCC, 0x20,0x22,
++0x00,0x00, 0xE6,0x01, 0x1A,0x11, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06,
++0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
++0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0x96,0x96,
++0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x1A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1A,0x28, 0xF4,0x82, 0x00,0x01, 0xE0,0x01,
++0x1A,0x80, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0x77,0x35,
++0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x42,0xC8, 0xA6,0x3A,
++0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x05,0xB8,
++0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16, 0xFF,0xEC, 0xC6,0x30,
++0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
++0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF0, 0x20,0x26,
++0x00,0x00, 0xE6,0x01, 0x1A,0x94, 0xF5,0x82, 0x00,0x00, 0xE0,0x01, 0x1B,0x28, 0xF6,0x02,
++0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C,
++0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x1A,0xF4, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C,
++0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC,
++0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
++0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16,
++0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01, 0x1A,0xB5, 0x06,0x30,
++0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
++0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4,
++0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82,
++0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1C,0x6C, 0x00,0x00,
++0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
++0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x1B,0x8C, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x1B,0x78, 0xB5,0xBA,
++0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
++0x77,0x00, 0xE0,0x01, 0x1B,0x90, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04,
++0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1B,0xCD, 0xF6,0x86,
++0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
++0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
++0x1B,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
++0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x1B,0xE8, 0xF7,0x05,
++0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04, 0x76,0x04, 0xF0,0x05,
++0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x01, 0x1C,0x15, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01, 0x1C,0x24, 0xF7,0x02,
++0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1C,0x65, 0xF7,0x05, 0x76,0x60, 0xF7,0x04,
++0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
++0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
++0x00,0x44, 0xE6,0x01, 0x1C,0x74, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01, 0x1C,0x74, 0xF0,0x05,
++0x2D,0x38, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x72,0x18, 0xF3,0x06, 0x73,0x30, 0xF3,0x05,
++0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
++0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x72,0x18, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x72,0xA4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x73,0x30, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x73,0xBC, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
++0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x74,0x48, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x74,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x75,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
++0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x77,0x04, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x1D,0xD4, 0x96,0x93,
++0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF6,0x86, 0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
++0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x00,0x22, 0xF7,0x05,
++0x76,0xF4, 0xF7,0x05, 0x76,0xF8, 0xF0,0x05, 0x76,0xFC, 0xF0,0x05, 0x77,0x00, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xF4, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x22, 0xE6,0x01, 0x1E,0x01, 0x00,0x00, 0x00,0x01, 0x97,0x13,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x77,0x04, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x76,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
++0x78,0xA4, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF6,0x86, 0x1F,0xBC, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x14, 0x96,0x93,
++0xFF,0xFC, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x78,0x9C, 0x90,0x02, 0xFF,0x34, 0xF7,0x02,
++0x7F,0xFF, 0xF7,0x05, 0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x78,0x9C, 0x87,0x16, 0x00,0x00, 0x84,0x96,
++0x00,0x08, 0xF5,0x86, 0x77,0x10, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x75,0x39,
++0x00,0x04, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x32, 0x00,0x00, 0xC6,0xA8,
++0x58,0x00, 0x84,0x16, 0x00,0x04, 0xC6,0x30, 0x75,0x80, 0x94,0x36, 0x00,0x04, 0xB4,0xAA,
++0x58,0x02, 0x87,0x36, 0x00,0x08, 0xF6,0x05, 0x78,0x9C, 0x07,0x38, 0x00,0x01, 0xE6,0x01,
++0x1F,0x2D, 0x97,0x36, 0x00,0x08, 0x87,0x02, 0xFF,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
++0x4A,0x00, 0xEE,0x01, 0x1F,0x35, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x78,0xA0, 0x94,0x82,
++0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x77,0x39,
++0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0xF6,0x04, 0x78,0x9C, 0xC7,0x04, 0x76,0x00, 0x86,0xAE,
++0x00,0x08, 0xC6,0x30, 0x74,0x00, 0xF7,0x06, 0x77,0x10, 0xF6,0x05, 0x78,0x9C, 0x76,0xB5,
++0x00,0x04, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x08, 0x20,0x32, 0x00,0x00, 0x07,0x38,
++0x00,0x01, 0xE6,0x01, 0x1F,0xA8, 0x97,0x36, 0x00,0x08, 0xF7,0x02, 0x7F,0xFF, 0xF7,0x05,
++0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04, 0x78,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
++0x00,0x00, 0xE6,0x01, 0x20,0xD1, 0xF6,0x02, 0x7F,0xFF, 0x96,0x16, 0xFF,0xF4, 0xF6,0x84,
++0x2D,0x40, 0xF6,0x06, 0x77,0x10, 0x26,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x04, 0xC4,0xB8,
++0x60,0x00, 0xC3,0x38, 0x00,0x00, 0x74,0x35, 0x00,0x02, 0xF6,0x06, 0x77,0x10, 0xC0,0x26,
++0x62,0x00, 0xEC,0x01, 0x20,0xC1, 0xF6,0x06, 0x21,0x8C, 0xF3,0x84, 0x78,0x9C, 0xA7,0x22,
++0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x74,0x00, 0xE6,0x01, 0x20,0xB1, 0x00,0x00,
++0x00,0x01, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0x78,0xA0, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
++0x72,0x00, 0x20,0x36, 0x00,0x00, 0xEE,0x01, 0x20,0x98, 0x96,0xA6, 0x00,0x00, 0xF7,0x04,
++0x2D,0x38, 0xF6,0x06, 0x77,0x10, 0xC5,0x18, 0x60,0x00, 0xF6,0x86, 0x2C,0x28, 0x86,0x2A,
++0x00,0x04, 0x05,0xB8, 0x00,0x01, 0xF5,0x85, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x2E,
++0x00,0x44, 0xE6,0x01, 0x20,0x70, 0xB6,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0x86,0x2A,
++0x00,0x08, 0x00,0x00, 0x00,0x01, 0x96,0x2A, 0x00,0x0C, 0xF6,0x06, 0x21,0x8C, 0xA7,0x22,
++0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC7,0x04, 0x76,0x00, 0xC7,0x1C, 0x74,0x00, 0xE0,0x01,
++0x20,0xB0, 0xF7,0x05, 0x78,0x9C, 0x86,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x62,0x00, 0xEC,0x01, 0x20,0xB0, 0x00,0x00, 0x00,0x01, 0x96,0x96, 0xFF,0xF4, 0x24,0xA4,
++0x00,0x10, 0x23,0x18, 0x00,0x10, 0xE0,0x01, 0x1F,0xFC, 0x24,0x20, 0x00,0x04, 0x86,0x16,
++0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x78,0xA0, 0x96,0x02, 0xFF,0x30, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x77,0x10, 0x77,0x39, 0x00,0x04, 0xC7,0x38,
++0x68,0x00, 0x86,0xBA, 0x00,0x0C, 0x87,0x3A, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF7,0x02, 0x00,0x0F, 0x20,0x3A, 0x00,0x00, 0xEC,0x01, 0x21,0x5D, 0xF6,0x86,
++0x77,0x18, 0x90,0x36, 0x00,0x00, 0x27,0x38, 0x00,0x01, 0xC6,0x04, 0x00,0x00, 0xC0,0x3A,
++0x62,0x00, 0xE6,0x01, 0x21,0x44, 0x06,0xB4, 0x00,0x10, 0xF6,0x06, 0x78,0xA4, 0x96,0x13,
++0xFF,0xFC, 0xF6,0x06, 0x78,0x10, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x01, 0x00,0x00,
++0x00,0x02, 0x00,0x00, 0x00,0x04, 0x00,0x00, 0x00,0x08, 0x00,0x00, 0x00,0x10, 0x00,0x00,
++0x00,0x20, 0x00,0x00, 0x00,0x40, 0x00,0x00, 0x00,0x80, 0x00,0x00, 0x01,0x00, 0x00,0x00,
++0x02,0x00, 0x00,0x00, 0x04,0x00, 0x00,0x00, 0x08,0x00, 0x00,0x00, 0x10,0x00, 0x00,0x00,
++0x20,0x00, 0x00,0x00, 0x40,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x00,0x00, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
++0xFF,0xFC, 0xF7,0x06, 0x22,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x15, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
++0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
++0x00,0x08, 0xF6,0x84, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x01, 0x22,0x70, 0xF6,0x02, 0x00,0x00, 0x87,0x36,
++0x0E,0xF4, 0x86,0xB6, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0x78, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x22,0x94, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
++0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0xB1, 0xF5,0x82,
++0x03,0xE8, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF5,0x82, 0x03,0xE8, 0x95,0x93,
++0xFF,0xFC, 0xF5,0x82, 0x00,0x15, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86, 0x79,0xCC, 0x95,0x93,
++0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x79,0xCC, 0x97,0x13,
++0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
++0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
++0x79,0x3C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC1,0x3C, 0x00,0x00, 0x02,0x10, 0x00,0x04, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
++0x23,0x84, 0x27,0x14, 0x00,0x0C, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0xE0,0x01, 0x24,0x34, 0x96,0x96,
++0xFF,0xF4, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x13,
++0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
++0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
++0x24,0x34, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
++0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xEE,0x01, 0x24,0x21, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0xB8, 0x58,0x00, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
++0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x36,
++0x00,0x10, 0x85,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x14, 0x26,0xB4,
++0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEE,0x01, 0x23,0xEC, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E,
++0x00,0x04, 0x86,0x96, 0xFF,0xF4, 0x85,0x16, 0x00,0x04, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
++0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x2C, 0x70,0x00, 0x85,0x2A, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x95,0x3A, 0x00,0x0C, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x85,0x2A,
++0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x3A, 0x00,0x10, 0x85,0x16, 0x00,0x08, 0xF4,0x02,
++0x00,0x01, 0x95,0x3A, 0x00,0x14, 0x96,0xAE, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x84,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
++0x25,0x55, 0x27,0x14, 0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00,
++0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
++0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
++0x00,0x00, 0xE6,0x01, 0x25,0x55, 0x00,0x00, 0x00,0x01, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
++0x00,0x01, 0x20,0x32, 0x00,0x00, 0xEE,0x01, 0x25,0x45, 0x77,0x31, 0x00,0x01, 0xC6,0xAC,
++0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36,
++0x00,0x18, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x1C, 0x00,0x00,
++0x00,0x01, 0x95,0x36, 0x00,0x10, 0x85,0x36, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x95,0x36,
++0x00,0x14, 0x06,0xB4, 0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x25,0x11, 0x00,0x00,
++0x00,0x01, 0x87,0x2E, 0x00,0x04, 0xF4,0x02, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0x97,0x2E,
++0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x08, 0x83,0x96, 0x00,0x04, 0x83,0x16, 0x00,0x00, 0xC5,0x00, 0x00,0x00, 0x84,0x1A,
++0x00,0x04, 0xC4,0xA8, 0x00,0x00, 0x94,0x16, 0xFF,0xF4, 0xC0,0x26, 0x42,0x00, 0xE6,0x01,
++0x26,0xD1, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x2A,
++0x32,0x00, 0xE6,0x01, 0x26,0xD1, 0xC7,0x20, 0x4A,0x00, 0x95,0x16, 0xFF,0xF4, 0x76,0xB8,
++0xFF,0xE1, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0xFF,0xFF, 0xC5,0x24, 0x70,0x00, 0x77,0x29,
++0x00,0x01, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x02, 0x83,0x16, 0x00,0x00, 0x86,0x9E,
++0x00,0x00, 0xC5,0xB8, 0x30,0x00, 0x05,0xAC, 0x00,0x0C, 0x87,0x2E, 0x00,0x00, 0xC6,0x00,
++0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x26,0x10, 0x20,0x32, 0x00,0x00, 0x86,0x9E,
++0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x01,
++0x26,0x10, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
++0x26,0x25, 0x00,0x00, 0x00,0x01, 0xC7,0x00, 0x00,0x00, 0xE0,0x01, 0x26,0x78, 0x20,0x3A,
++0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x01, 0x26,0x5C, 0x00,0x00, 0x00,0x01, 0xE6,0x01, 0x26,0x64, 0x20,0x32,
++0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
++0x72,0x00, 0xE2,0x01, 0x26,0x65, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
++0x00,0x00, 0x47,0x04, 0xFF,0xFF, 0xE6,0x01, 0x26,0x79, 0x20,0x3A, 0x00,0x00, 0xF7,0x02,
++0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x26,0xB1, 0x20,0x3A, 0x00,0x00, 0xEE,0x01,
++0x26,0xA0, 0x20,0x3A, 0x00,0x01, 0x43,0x04, 0xFF,0xFF, 0xC0,0x3A, 0x32,0x00, 0xE6,0x01,
++0x26,0xC9, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0xE6,0x01,
++0x26,0xC1, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0x83,0x16,
++0x00,0x08, 0xF4,0x02, 0x00,0x01, 0xE0,0x01, 0x26,0xE0, 0x95,0x1A, 0x00,0x00, 0xE0,0x01,
++0x25,0x8C, 0xC4,0xA8, 0x00,0x00, 0xE0,0x01, 0x25,0x8C, 0xC4,0x28, 0x00,0x00, 0x83,0x16,
++0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0x1A, 0x00,0x00, 0xC4,0x00, 0x00,0x00, 0x87,0x96,
++0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
++0x00,0x04, 0x84,0x16, 0x00,0x00, 0x84,0x96, 0x00,0x08, 0xF7,0x02, 0x00,0x03, 0xC6,0xA0,
++0x4D,0x80, 0xC6,0xB6, 0x74,0x00, 0xE6,0x01, 0x27,0x71, 0xC6,0x20, 0x00,0x00, 0x20,0x36,
++0x00,0x02, 0xE6,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20, 0x48,0x00, 0x27,0x38,
++0x00,0x02, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0x9C, 0xC5,0x38, 0x00,0x00, 0x87,0x2E,
++0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
++0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE2,0x01,
++0x27,0x41, 0x05,0xAC, 0x00,0x02, 0xE0,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20,
++0x48,0x00, 0x27,0x38, 0x00,0x04, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0xA0, 0xC5,0x20,
++0x48,0x00, 0x83,0xAD, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0xB1, 0x00,0x04, 0xC0,0x32,
++0x72,0x00, 0xE2,0x01, 0x27,0x85, 0x00,0x00, 0x00,0x01, 0xC5,0x20, 0x48,0x00, 0xC0,0x32,
++0x52,0x00, 0xE4,0x01, 0x27,0xD5, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
++0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xB3,
++0x68,0x00, 0x06,0x30, 0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x27,0xAC, 0x05,0xAC,
++0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16,
++0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC7,0x22, 0x6D,0x80, 0xE6,0x01,
++0x28,0x10, 0x20,0x36, 0x00,0x00, 0xE0,0x01, 0x28,0x74, 0xC4,0x38, 0x00,0x00, 0xF7,0x02,
++0x00,0x01, 0xEE,0x01, 0x28,0x41, 0xF6,0x02, 0x00,0x00, 0x76,0xB5, 0x00,0x01, 0x20,0x36,
++0x00,0x00, 0xEE,0x01, 0x28,0x1C, 0x77,0x39, 0x00,0x01, 0xE0,0x01, 0x28,0x44, 0x20,0x22,
++0x00,0x00, 0x74,0x21, 0x00,0x01, 0x77,0x38, 0xFF,0xFF, 0x06,0x30, 0x00,0x01, 0x20,0x22,
++0x00,0x00, 0xEE,0x01, 0x28,0x34, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x28,0x71, 0x00,0x00,
++0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE4,0x01, 0x28,0x64, 0x00,0x00, 0x00,0x01, 0xC4,0x20,
++0x6A,0x00, 0x77,0x3A, 0xFF,0xFF, 0xE6,0x01, 0x28,0x54, 0x76,0xB4, 0xFF,0xFF, 0xD4,0x20,
++0x07,0x62, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
++0x00,0x04, 0xE0,0x01, 0x28,0xCC, 0xF7,0x06, 0x29,0xDC, 0x86,0xBA, 0x00,0x00, 0x00,0x00,
++0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x28,0xC9, 0x00,0x00, 0x00,0x01, 0x97,0x16,
++0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
++0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A,
++0x62,0x00, 0xE4,0x01, 0x28,0x9D, 0x00,0x00, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
++0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
++0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xE0,0x01, 0x29,0x34, 0xF7,0x06,
++0x29,0x98, 0x86,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
++0x29,0x31, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34,
++0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
++0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A, 0x62,0x00, 0xE4,0x01, 0x29,0x04, 0x00,0x00,
++0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
++0x7B,0x50, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x29,0x84, 0xF6,0x82,
++0x00,0x01, 0xF6,0x85, 0x7B,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x28,0xF0, 0x97,0x93,
++0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
++0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x0B,0x4C, 0x00,0x00, 0x00,0x00, 0x00,0x00,
++0x42,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x5E,0x50, 0x00,0x00, 0x00,0x00, 0x00,0x00,
++0xC7,0xA8, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x0B,0xD0, 0x00,0x00, 0x00,0x00, 0x00,0x01,
++0x1C,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x1E,0x14, 0x00,0x00, 0x00,0x00, 0x00,0x01,
+ 0x21,0x2C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x22,0xE4, 0x00,0x00, 0x00,0x00, } ;
+
+
+-/* This is the LANai data */
++/* This is the LANai data */
+
+-static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */
+-static unsigned char lanai4_data[20472] __initdata;
++static unsigned int __devinitdata lanai4_data_off = 0x94F0; /* half-word offset */
++static unsigned char __devinitdata lanai4_data[20472];
+
+
+ #ifdef SYMBOL_DEFINES_COMPILED
+diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
+index 1b965a2..7747bfd 100644
+--- a/drivers/net/myri_sbus.c
++++ b/drivers/net/myri_sbus.c
+@@ -168,7 +168,7 @@ static int myri_do_handshake(struct myri
+ return 0;
+ }
+
+-static int myri_load_lanai(struct myri_eth *mp)
++static int __devinit myri_load_lanai(struct myri_eth *mp)
+ {
+ struct net_device *dev = mp->dev;
+ struct myri_shmem __iomem *shmem = mp->shmem;
+@@ -360,7 +360,7 @@ static void myri_tx(struct myri_eth *mp,
+ mp->tx_old = entry;
+ }
+
+-/* Determine the packet's protocol ID. The rule here is that we
++/* Determine the packet's protocol ID. The rule here is that we
+ * 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.
+ */
+@@ -368,11 +368,11 @@ static __be16 myri_type_trans(struct sk_
+ {
+ struct ethhdr *eth;
+ unsigned char *rawp;
+-
++
+ skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN);
+ skb_pull(skb, dev->hard_header_len);
+ eth = eth_hdr(skb);
+-
++
+ #ifdef DEBUG_HEADER
+ DHDR(("myri_type_trans: "));
+ dump_ehdr(eth);
+@@ -386,12 +386,12 @@ static __be16 myri_type_trans(struct sk_
+ if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+ skb->pkt_type = PACKET_OTHERHOST;
+ }
+-
++
+ if (ntohs(eth->h_proto) >= 1536)
+ return eth->h_proto;
+-
++
+ rawp = skb->data;
+-
++
+ /* This is a magic hack to spot IPX packets. Older Novell breaks
+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+@@ -399,7 +399,7 @@ static __be16 myri_type_trans(struct sk_
+ */
+ if (*(unsigned short *)rawp == 0xFFFF)
+ return htons(ETH_P_802_3);
+-
++
+ /* Real 802.2 LLC */
+ return htons(ETH_P_802_2);
+ }
+@@ -536,7 +536,7 @@ static void myri_rx(struct myri_eth *mp,
+ }
+ }
+
+-static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t myri_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct myri_eth *mp = (struct myri_eth *) dev->priv;
+@@ -678,7 +678,7 @@ static int myri_start_xmit(struct sk_buf
+ return 0;
+ }
+
+-/* Create the MyriNet MAC header for an arbitrary protocol layer
++/* Create the MyriNet MAC header for an arbitrary protocol layer
+ *
+ * saddr=NULL means use device source address
+ * daddr=NULL means leave destination address (eg unresolved arp)
+@@ -701,7 +701,7 @@ static int myri_header(struct sk_buff *s
+ /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
+ * in here instead. It is up to the 802.2 layer to carry protocol information.
+ */
+- if (type != ETH_P_802_3)
++ if (type != ETH_P_802_3)
+ eth->h_proto = htons(type);
+ else
+ eth->h_proto = htons(len);
+@@ -719,7 +719,7 @@ static int myri_header(struct sk_buff *s
+ eth->h_dest[i] = 0;
+ return(dev->hard_header_len);
+ }
+-
++
+ if (daddr) {
+ memcpy(eth->h_dest, daddr, dev->addr_len);
+ return dev->hard_header_len;
+@@ -754,16 +754,16 @@ static int myri_rebuild_header(struct sk
+ #endif
+
+ default:
+- printk(KERN_DEBUG
+- "%s: unable to resolve type %X addresses.\n",
++ printk(KERN_DEBUG
++ "%s: unable to resolve type %X addresses.\n",
+ dev->name, (int)eth->h_proto);
+-
++
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ return 0;
+ break;
+ }
+
+- return 0;
++ return 0;
+ }
+
+ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+@@ -891,7 +891,7 @@ static void dump_eeprom(struct myri_eth
+ }
+ #endif
+
+-static int __init myri_ether_init(struct sbus_dev *sdev)
++static int __devinit myri_ether_init(struct sbus_dev *sdev)
+ {
+ static int num;
+ static unsigned version_printed;
+diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
+index db0475a..ffa0afd 100644
+--- a/drivers/net/natsemi.c
++++ b/drivers/net/natsemi.c
+@@ -54,8 +54,8 @@
+ #include <asm/uaccess.h>
+
+ #define DRV_NAME "natsemi"
+-#define DRV_VERSION "2.0"
+-#define DRV_RELDATE "June 27, 2006"
++#define DRV_VERSION "2.1"
++#define DRV_RELDATE "Sept 11, 2006"
+
+ #define RX_OFFSET 2
+
+@@ -143,9 +143,9 @@ module_param_array(options, int, NULL, 0
+ module_param_array(full_duplex, int, NULL, 0);
+ MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
+ MODULE_PARM_DESC(debug, "DP8381x default debug level");
+-MODULE_PARM_DESC(rx_copybreak,
++MODULE_PARM_DESC(rx_copybreak,
+ "DP8381x copy breakpoint for copy-only-tiny-frames");
+-MODULE_PARM_DESC(options,
++MODULE_PARM_DESC(options,
+ "DP8381x: Bits 0-3: media type, bit 17: full duplex");
+ MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
+
+@@ -244,7 +244,7 @@ enum {
+ MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */
+ };
+
+-
++
+ /* array of board data directly indexed by pci_tbl[x].driver_data */
+ static const struct {
+ const char *name;
+@@ -414,7 +414,7 @@ enum TxConfig_bits {
+ TxCarrierIgn = 0x80000000
+ };
+
+-/*
++/*
+ * Tx Configuration:
+ * - 256 byte DMA burst length
+ * - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free)
+@@ -623,7 +623,7 @@ static void free_ring(struct net_device
+ static void reinit_ring(struct net_device *dev);
+ static void init_registers(struct net_device *dev);
+ static int start_tx(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t intr_handler(int irq, void *dev_instance);
+ static void netdev_error(struct net_device *dev, int intr_status);
+ static int natsemi_poll(struct net_device *dev, int *budget);
+ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
+@@ -647,7 +647,7 @@ static void enable_wol_mode(struct net_d
+ static int netdev_close(struct net_device *dev);
+ static int netdev_get_regs(struct net_device *dev, u8 *buf);
+ static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+
+ static inline void __iomem *ns_ioaddr(struct net_device *dev)
+ {
+@@ -672,7 +672,7 @@ static void move_int_phy(struct net_devi
+ void __iomem *ioaddr = ns_ioaddr(dev);
+ int target = 31;
+
+- /*
++ /*
+ * The internal phy is visible on the external mii bus. Therefore we must
+ * move it away before we can send commands to an external phy.
+ * There are two addresses we must avoid:
+@@ -1095,7 +1095,7 @@ static void init_phy_fixup(struct net_de
+ tmp |= BMCR_SPEED100;
+ if (np->duplex == DUPLEX_FULL)
+ tmp |= BMCR_FULLDPLX;
+- /*
++ /*
+ * Note: there is no good way to inform the link partner
+ * that our capabilities changed. The user has to unplug
+ * and replug the network cable after some changes, e.g.
+@@ -1236,7 +1236,7 @@ static int switch_port_internal(struct n
+ writel(cfg, ioaddr + ChipConfig);
+ readl(ioaddr + ChipConfig);
+ udelay(1);
+-
++
+ /* 2) reset the internal phy: */
+ bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2));
+ writel(bmcr | BMCR_RESET, ioaddr+BasicControl+(MII_BMCR<<2));
+@@ -1276,7 +1276,7 @@ static int find_mii(struct net_device *d
+
+ /* Switch to external phy */
+ did_switch = switch_port_external(dev);
+-
++
+ /* Scan the possible phy addresses:
+ *
+ * PHY address 0 means that the phy is in isolate mode. Not yet
+@@ -1573,7 +1573,7 @@ static void check_link(struct net_device
+ void __iomem * ioaddr = ns_ioaddr(dev);
+ int duplex;
+ u16 bmsr;
+-
++
+ /* The link status field is latched: it remains low after a temporary
+ * link failure until it's read. We need the current link status,
+ * thus read twice.
+@@ -2088,7 +2088,7 @@ static void netdev_tx_done(struct net_de
+
+ /* The interrupt handler doesn't actually handle interrupts itself, it
+ * schedules a NAPI poll if there is anything to do. */
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t intr_handler(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct netdev_private *np = netdev_priv(dev);
+@@ -2096,7 +2096,7 @@ static irqreturn_t intr_handler(int irq,
+
+ if (np->hands_off)
+ return IRQ_NONE;
+-
++
+ /* Reading automatically acknowledges. */
+ np->intr_status = readl(ioaddr + IntrStatus);
+
+@@ -2106,7 +2106,7 @@ static irqreturn_t intr_handler(int irq,
+ dev->name, np->intr_status,
+ readl(ioaddr + IntrMask));
+
+- if (!np->intr_status)
++ if (!np->intr_status)
+ return IRQ_NONE;
+
+ prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
+@@ -2141,13 +2141,13 @@ static int natsemi_poll(struct net_devic
+ /* Abnormal error summary/uncommon events handlers. */
+ if (np->intr_status & IntrAbnormalSummary)
+ netdev_error(dev, np->intr_status);
+-
++
+ if (np->intr_status &
+ (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
+ IntrRxErr | IntrRxOverrun)) {
+ netdev_rx(dev, &work_done, work_to_do);
+ }
+-
++
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+@@ -2373,7 +2373,7 @@ static struct net_device_stats *get_stat
+ static void natsemi_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- intr_handler(dev->irq, dev, NULL);
++ intr_handler(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -2387,9 +2387,6 @@ static void __set_rx_mode(struct net_dev
+ u32 rx_mode;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ rx_mode = RxFilterEnable | AcceptBroadcast
+ | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
+ } else if ((dev->mc_count > multicast_filter_limit)
+@@ -2576,7 +2573,7 @@ static int get_eeprom(struct net_device
+ return res;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = get_drvinfo,
+ .get_regs_len = get_regs_len,
+ .get_eeprom_len = get_eeprom_len,
+@@ -2747,7 +2744,7 @@ static int netdev_get_ecmd(struct net_de
+ * phy, even if the internal phy is used. This is necessary
+ * to work around a deficiency of the ethtool interface:
+ * It's only possible to query the settings of the active
+- * port. Therefore
++ * port. Therefore
+ * # ethtool -s ethX port mii
+ * actually sends an ioctl to switch to port mii with the
+ * settings that are used for the current active port.
+@@ -3246,7 +3243,7 @@ static int __init natsemi_init_mod (void
+ printk(version);
+ #endif
+
+- return pci_module_init (&natsemi_driver);
++ return pci_register_driver(&natsemi_driver);
+ }
+
+ static void __exit natsemi_exit_mod (void)
+diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
+index 7ea3d59..eb893d7 100644
+--- a/drivers/net/ne-h8300.c
++++ b/drivers/net/ne-h8300.c
+@@ -593,7 +593,7 @@ retry:
+ return;
+ }
+
+-
++
+ #ifdef MODULE
+ #define MAX_NE_CARDS 1 /* Max number of NE cards per module */
+ static struct net_device *dev_ne[MAX_NE_CARDS];
+diff --git a/drivers/net/ne.c b/drivers/net/ne.c
+index 963a11f..787aa42 100644
+--- a/drivers/net/ne.c
++++ b/drivers/net/ne.c
+@@ -160,7 +160,7 @@ static void ne_block_input(struct net_de
+ static void ne_block_output(struct net_device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+
+-
++
+ /* Probe for various non-shared-memory ethercards.
+
+ NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
+@@ -807,7 +807,7 @@ retry:
+ return;
+ }
+
+-
++
+ #ifdef MODULE
+ #define MAX_NE_CARDS 4 /* Max number of NE cards per module */
+ static struct net_device *dev_ne[MAX_NE_CARDS];
+diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
+index eebf5f0..5fccfea 100644
+--- a/drivers/net/ne2.c
++++ b/drivers/net/ne2.c
+@@ -28,7 +28,7 @@
+ - added support for Arco Electronics AE/2-card (experimental)
+
+ Mon Sep 14 09:53:42 CET 1998 (David Weinehall)
+- - added support for Compex ENET-16MC/P (experimental)
++ - added support for Compex ENET-16MC/P (experimental)
+
+ Tue Sep 15 16:21:12 CET 1998 (David Weinehall, Magnus Jonsson, Tomas Ogren)
+ - Miscellaneous bugfixes
+@@ -44,11 +44,11 @@
+ - Version# bump
+
+ Mon Nov 16 15:28:23 CET 1998 (Wim Dumon)
+- - pass 'dev' as last parameter of request_irq in stead of 'NULL'
++ - pass 'dev' as last parameter of request_irq in stead of 'NULL'
+
+ Wed Feb 7 21:24:00 CET 2001 (Alfred Arnold)
+ - added support for the D-Link DE-320CT
+-
++
+ * WARNING
+ -------
+ This is alpha-test software. It is not guaranteed to work. As a
+@@ -150,9 +150,9 @@ static void ne_block_output(struct net_d
+
+
+ /*
+- * special code to read the DE-320's MAC address EEPROM. In contrast to a
++ * special code to read the DE-320's MAC address EEPROM. In contrast to a
+ * standard NE design, this is a serial EEPROM (93C46) that has to be read
+- * bit by bit. The EEPROM cotrol port at base + 0x1e has the following
++ * bit by bit. The EEPROM cotrol port at base + 0x1e has the following
+ * layout:
+ *
+ * Bit 0 = Data out (read from EEPROM)
+@@ -218,7 +218,7 @@ static unsigned int __init dlink_get_eep
+ {
+ int z;
+ unsigned int value = 0;
+-
++
+ /* pull the CS line low for a moment. This resets the EEPROM-
+ internal logic, and makes it ready for a new command. */
+
+@@ -253,23 +253,23 @@ static int __init do_ne2_probe(struct ne
+
+ SET_MODULE_OWNER(dev);
+
+- /* Do not check any supplied i/o locations.
++ /* Do not check any supplied i/o locations.
+ POS registers usually don't fail :) */
+
+- /* MCA cards have POS registers.
+- Autodetecting MCA cards is extremely simple.
++ /* MCA cards have POS registers.
++ Autodetecting MCA cards is extremely simple.
+ Just search for the card. */
+
+ for(i = 0; (ne2_adapters[i].name != NULL) && !adapter_found; i++) {
+- current_mca_slot =
++ current_mca_slot =
+ mca_find_unused_adapter(ne2_adapters[i].id, 0);
+
+ if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) {
+ int res;
+- mca_set_adapter_name(current_mca_slot,
++ mca_set_adapter_name(current_mca_slot,
+ ne2_adapters[i].name);
+ mca_mark_as_used(current_mca_slot);
+-
++
+ res = ne2_probe1(dev, current_mca_slot);
+ if (res)
+ mca_mark_as_unused(current_mca_slot);
+@@ -307,7 +307,7 @@ static int ne2_procinfo(char *buf, int s
+
+ len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" );
+ len += sprintf(buf+len, "Driver written by Wim Dumon ");
+- len += sprintf(buf+len, "<wimpie at kotnet.org>\n");
++ len += sprintf(buf+len, "<wimpie at kotnet.org>\n");
+ len += sprintf(buf+len, "Modified by ");
+ len += sprintf(buf+len, "David Weinehall <tao at acc.umu.se>\n");
+ len += sprintf(buf+len, "and by Magnus Jonsson <bigfoot at acc.umu.se>\n");
+@@ -316,8 +316,8 @@ static int ne2_procinfo(char *buf, int s
+ len += sprintf(buf+len, "IRQ : %d\n", dev->irq);
+
+ #define HW_ADDR(i) dev->dev_addr[i]
+- len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
+- HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
++ len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
++ HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
+ HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) );
+ #undef HW_ADDR
+
+@@ -370,7 +370,7 @@ static int __init ne2_probe1(struct net_
+
+ #ifndef CRYNWR_WAY
+ /* Reset the card the way they do it in the Crynwr packet driver */
+- for (i=0; i<8; i++)
++ for (i=0; i<8; i++)
+ outb(0x0, base_addr + NE_RESET);
+ inb(base_addr + NE_RESET);
+ outb(0x21, base_addr + NE_CMD);
+@@ -388,10 +388,10 @@ static int __init ne2_probe1(struct net_
+
+ #else /* _I_ never tested it this way .. Go ahead and try ...*/
+ /* Reset card. Who knows what dain-bramaged state it was left in. */
+- {
++ {
+ unsigned long reset_start_time = jiffies;
+
+- /* DON'T change these to inb_p/outb_p or reset will fail on
++ /* DON'T change these to inb_p/outb_p or reset will fail on
+ clones.. */
+ outb(inb(base_addr + NE_RESET), base_addr + NE_RESET);
+
+@@ -408,16 +408,16 @@ static int __init ne2_probe1(struct net_
+
+
+ /* Read the 16 bytes of station address PROM.
+- We must first initialize registers, similar to
++ We must first initialize registers, similar to
+ NS8390_init(eifdev, 0).
+ We can't reliably read the SAPROM address without this.
+ (I learned the hard way!). */
+ {
+- struct {
+- unsigned char value, offset;
++ struct {
++ unsigned char value, offset;
+ } program_seq[] = {
+ /* Select page 0 */
+- {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD},
++ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD},
+ {0x49, EN0_DCFG}, /* Set WORD-wide (0x49) access. */
+ {0x00, EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, EN0_RCNTHI},
+@@ -433,7 +433,7 @@ static int __init ne2_probe1(struct net_
+ };
+
+ for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+- outb_p(program_seq[i].value, base_addr +
++ outb_p(program_seq[i].value, base_addr +
+ program_seq[i].offset);
+
+ }
+@@ -464,7 +464,7 @@ static int __init ne2_probe1(struct net_
+ share and the board will usually be enabled. */
+ retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
+ if (retval) {
+- printk (" unable to get IRQ %d (irqval=%d).\n",
++ printk (" unable to get IRQ %d (irqval=%d).\n",
+ dev->irq, retval);
+ goto out;
+ }
+@@ -496,9 +496,9 @@ static int __init ne2_probe1(struct net_
+ ei_status.block_input = &ne_block_input;
+ ei_status.block_output = &ne_block_output;
+ ei_status.get_8390_hdr = &ne_get_8390_hdr;
+-
++
+ ei_status.priv = slot;
+-
++
+ dev->open = &ne_open;
+ dev->stop = &ne_close;
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+@@ -538,7 +538,7 @@ static void ne_reset_8390(struct net_dev
+ {
+ unsigned long reset_start_time = jiffies;
+
+- if (ei_debug > 1)
++ if (ei_debug > 1)
+ printk("resetting the 8390 t=%ld...", jiffies);
+
+ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+@@ -550,7 +550,7 @@ static void ne_reset_8390(struct net_dev
+ /* This check _should_not_ be necessary, omit eventually. */
+ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+ if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
+- printk("%s: ne_reset_8390() did not complete.\n",
++ printk("%s: ne_reset_8390() did not complete.\n",
+ dev->name);
+ break;
+ }
+@@ -561,13 +561,13 @@ static void ne_reset_8390(struct net_dev
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+-static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page)
+ {
+
+ int nic_base = dev->base_addr;
+
+- /* This *shouldn't* happen.
++ /* This *shouldn't* happen.
+ If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne_get_8390_hdr "
+@@ -585,10 +585,10 @@ static void ne_get_8390_hdr(struct net_d
+ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.word16)
+- insw(NE_BASE + NE_DATAPORT, hdr,
++ insw(NE_BASE + NE_DATAPORT, hdr,
+ sizeof(struct e8390_pkt_hdr)>>1);
+ else
+- insb(NE_BASE + NE_DATAPORT, hdr,
++ insb(NE_BASE + NE_DATAPORT, hdr,
+ sizeof(struct e8390_pkt_hdr));
+
+ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+@@ -600,7 +600,7 @@ static void ne_get_8390_hdr(struct net_d
+ hints. The NEx000 doesn't share the on-board packet memory -- you have
+ to put the packet out through the "remote DMA" dataport using outb. */
+
+-static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb,
++static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb,
+ int ring_offset)
+ {
+ #ifdef NE_SANITY_CHECK
+@@ -609,7 +609,7 @@ static void ne_block_input(struct net_de
+ int nic_base = dev->base_addr;
+ char *buf = skb->data;
+
+- /* This *shouldn't* happen.
++ /* This *shouldn't* happen.
+ If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne_block_input "
+@@ -677,7 +677,7 @@ static void ne_block_output(struct net_d
+ if (ei_status.word16 && (count & 0x01))
+ count++;
+
+- /* This *shouldn't* happen.
++ /* This *shouldn't* happen.
+ If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne_block_output."
+diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
+index 34bdba9..589785d 100644
+--- a/drivers/net/ne2k-pci.c
++++ b/drivers/net/ne2k-pci.c
+@@ -175,9 +175,9 @@ static void ne2k_pci_block_input(struct
+ struct sk_buff *skb, int ring_offset);
+ static void ne2k_pci_block_output(struct net_device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+-static struct ethtool_ops ne2k_pci_ethtool_ops;
++static const struct ethtool_ops ne2k_pci_ethtool_ops;
++
+
+-
+
+ /* There is no room in the standard 8390 structure for extra info we need,
+ so we build a meta/outer-wrapper structure.. */
+@@ -386,7 +386,7 @@ err_out_free_res:
+
+ }
+
+-/*
++/*
+ * Magic incantation sequence for full duplex on the supported cards.
+ */
+ static inline int set_realtek_fdx(struct net_device *dev)
+@@ -411,7 +411,7 @@ static inline int set_holtek_fdx(struct
+
+ static int ne2k_pci_set_fdx(struct net_device *dev)
+ {
+- if (ei_status.ne2k_flags & REALTEK_FDX)
++ if (ei_status.ne2k_flags & REALTEK_FDX)
+ return set_realtek_fdx(dev);
+ else if (ei_status.ne2k_flags & HOLTEK_FDX)
+ return set_holtek_fdx(dev);
+@@ -635,7 +635,7 @@ static void ne2k_pci_get_drvinfo(struct
+ strcpy(info->bus_info, pci_name(pci_dev));
+ }
+
+-static struct ethtool_ops ne2k_pci_ethtool_ops = {
++static const struct ethtool_ops ne2k_pci_ethtool_ops = {
+ .get_drvinfo = ne2k_pci_get_drvinfo,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+@@ -702,7 +702,7 @@ static int __init ne2k_pci_init(void)
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init (&ne2k_driver);
++ return pci_register_driver(&ne2k_driver);
+ }
+
+
+diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
+index 73501d8..d663289 100644
+--- a/drivers/net/ne3210.c
++++ b/drivers/net/ne3210.c
+@@ -14,10 +14,10 @@
+ 2) The existing myriad of other Linux 8390 drivers by Donald Becker.
+ 3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
+
+- The NE3210 is an EISA shared memory NS8390 implementation. Shared
++ The NE3210 is an EISA shared memory NS8390 implementation. Shared
+ memory address > 1MB should work with this driver.
+
+- Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
++ Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
+ around (or perhaps there are some defective/backwards cards ???)
+
+ This driver WILL NOT WORK FOR THE NE3200 - it is completely different
+@@ -133,7 +133,7 @@ static int __init ne3210_eisa_probe (str
+ edev->slot, ifmap[port_index]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
+-
++
+
+ /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
+ dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
+@@ -161,13 +161,13 @@ static int __init ne3210_eisa_probe (str
+ goto out3;
+ }
+ }
+-
++
+ if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
+ printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
+ phys_mem);
+ goto out3;
+ }
+-
++
+ printk("%dkB memory at physical address %#lx\n",
+ NE3210_STOP_PG/4, phys_mem);
+
+@@ -210,7 +210,7 @@ static int __init ne3210_eisa_probe (str
+
+ if ((retval = register_netdev (dev)))
+ goto out5;
+-
++
+ NS8390_init(dev, 0);
+ return 0;
+
+@@ -226,7 +226,7 @@ static int __init ne3210_eisa_probe (str
+ release_region (ioaddr, NE3210_IO_EXTENT);
+ out:
+ free_netdev (dev);
+-
++
+ return retval;
+ }
+
+@@ -289,7 +289,7 @@ ne3210_get_8390_hdr(struct net_device *d
+ hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
+ }
+
+-/*
++/*
+ * Block input and output are easy on shared memory ethercards, the only
+ * complication is when the ring buffer wraps. The count will already
+ * be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
+@@ -343,6 +343,7 @@ static struct eisa_device_id ne3210_ids[
+ { "NVL1801" },
+ { "" },
+ };
++MODULE_DEVICE_TABLE(eisa, ne3210_ids);
+
+ static struct eisa_driver ne3210_eisa_driver = {
+ .id_table = ne3210_ids,
+diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
+index b1311ae..a53644f 100644
+--- a/drivers/net/netx-eth.c
++++ b/drivers/net/netx-eth.c
+@@ -17,7 +17,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -177,7 +176,7 @@ static void netx_eth_receive(struct net_
+ }
+
+ static irqreturn_t
+-netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++netx_eth_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *ndev = dev_id;
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
+index d4be207..8be0d03 100644
+--- a/drivers/net/ni5010.c
++++ b/drivers/net/ni5010.c
+@@ -40,7 +40,7 @@
+ *
+ * Compile with:
+ * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \
+- * -DMODULE -c ni5010.c
++ * -DMODULE -c ni5010.c
+ *
+ * Insert with e.g.:
+ * insmod ni5010.ko io=0x300 irq=5
+@@ -68,7 +68,7 @@
+ static const char boardname[] = "NI5010";
+ static char version[] __initdata =
+ "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
+-
++
+ /* bufsize_rcv == 0 means autoprobing */
+ static unsigned int bufsize_rcv;
+
+@@ -99,7 +99,7 @@ struct ni5010_local {
+ static int ni5010_probe1(struct net_device *dev, int ioaddr);
+ static int ni5010_open(struct net_device *dev);
+ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
+ static void ni5010_rx(struct net_device *dev);
+ static void ni5010_timeout(struct net_device *dev);
+ static int ni5010_close(struct net_device *dev);
+@@ -228,7 +228,7 @@ static int __init ni5010_probe1(struct n
+ * - Andreas
+ */
+
+- PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
++ PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
+ dev->name, ioaddr));
+
+ if (inb(ioaddr+0) == 0xff)
+@@ -332,7 +332,7 @@ static int __init ni5010_probe1(struct n
+ }
+ printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
+ memset(dev->priv, 0, sizeof(struct ni5010_local));
+-
++
+ dev->open = ni5010_open;
+ dev->stop = ni5010_close;
+ dev->hard_start_xmit = ni5010_send_packet;
+@@ -359,7 +359,7 @@ out:
+ return err;
+ }
+
+-/*
++/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+@@ -367,14 +367,14 @@ out:
+ * registers that "should" only need to be set once at boot, so that
+ * there is a non-reboot way to recover if something goes wrong.
+ */
+-
++
+ static int ni5010_open(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+ int i;
+
+- PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
+-
++ PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
++
+ if (request_irq(dev->irq, &ni5010_interrupt, 0, boardname, dev)) {
+ printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq);
+ return -EAGAIN;
+@@ -404,21 +404,21 @@ static int ni5010_open(struct net_device
+ for(i = 0;i < 6; i++) {
+ outb(dev->dev_addr[i], EDLC_ADDR + i);
+ }
+-
+- PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
++
++ PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
+ outb(0, EDLC_XMASK); /* No xmit interrupts for now */
+- outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
++ outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
+ /* Normal packet xmit mode */
+ outb(0xff, EDLC_XCLR); /* Clear all pending xmit interrupts */
+ outb(RMD_BROADCAST, EDLC_RMODE);
+ /* Receive broadcast and normal packets */
+ reset_receiver(dev); /* Ready ni5010 for receiving packets */
+-
++
+ outb(0, EDLC_RESET); /* Un-reset the ni5010 */
+-
++
+ netif_start_queue(dev);
+-
+- if (NI5010_DEBUG) ni5010_show_registers(dev);
++
++ if (NI5010_DEBUG) ni5010_show_registers(dev);
+
+ PRINTK((KERN_DEBUG "%s: open successful\n", dev->name));
+ return 0;
+@@ -427,7 +427,7 @@ static int ni5010_open(struct net_device
+ static void reset_receiver(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+-
++
+ PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name));
+ outw(0, IE_GP); /* Receive packet at start of buffer */
+ outb(0xff, EDLC_RCLR); /* Clear all pending rcv interrupts */
+@@ -453,10 +453,10 @@ static int ni5010_send_packet(struct sk_
+
+ PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
+
+- /*
++ /*
+ * Block sending
+ */
+-
++
+ netif_stop_queue(dev);
+ hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
+ dev->trans_start = jiffies;
+@@ -464,11 +464,11 @@ static int ni5010_send_packet(struct sk_
+ return 0;
+ }
+
+-/*
++/*
+ * The typical workload of the driver:
+- * Handle the network interface interrupts.
++ * Handle the network interface interrupts.
+ */
+-static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ni5010_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct ni5010_local *lp;
+@@ -479,11 +479,11 @@ static irqreturn_t ni5010_interrupt(int
+
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+-
++
+ spin_lock(&lp->lock);
+- status = inb(IE_ISTAT);
++ status = inb(IE_ISTAT);
+ PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status));
+-
++
+ if ((status & IS_R_INT) == 0) ni5010_rx(dev);
+
+ if ((status & IS_X_INT) == 0) {
+@@ -495,8 +495,8 @@ static irqreturn_t ni5010_interrupt(int
+ outb(0, IE_DMA_RST); /* Reset DMA int */
+ }
+
+- if (!xmit_was_error)
+- reset_receiver(dev);
++ if (!xmit_was_error)
++ reset_receiver(dev);
+ spin_unlock(&lp->lock);
+ return IRQ_HANDLED;
+ }
+@@ -505,7 +505,7 @@ static irqreturn_t ni5010_interrupt(int
+ static void dump_packet(void *buf, int len)
+ {
+ int i;
+-
++
+ printk(KERN_DEBUG "Packet length = %#4x\n", len);
+ for (i = 0; i < len; i++){
+ if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i);
+@@ -514,7 +514,7 @@ static void dump_packet(void *buf, int l
+ if (i % 16 == 15) printk("\n");
+ }
+ printk("\n");
+-
++
+ return;
+ }
+
+@@ -526,12 +526,12 @@ static void ni5010_rx(struct net_device
+ unsigned char rcv_stat;
+ struct sk_buff *skb;
+ int i_pkt_size;
+-
+- PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
+-
++
++ PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
++
+ rcv_stat = inb(EDLC_RSTAT);
+- PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
+-
++ PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
++
+ if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
+ PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
+ lp->stats.rx_errors++;
+@@ -542,12 +542,12 @@ static void ni5010_rx(struct net_device
+ outb(0xff, EDLC_RCLR); /* Clear the interrupt */
+ return;
+ }
+-
++
+ outb(0xff, EDLC_RCLR); /* Clear the interrupt */
+
+ i_pkt_size = inw(IE_RCNT);
+ if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
+- PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
++ PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
+ dev->name, i_pkt_size));
+ lp->stats.rx_errors++;
+ lp->stats.rx_length_errors++;
+@@ -561,27 +561,27 @@ static void ni5010_rx(struct net_device
+ lp->stats.rx_dropped++;
+ return;
+ }
+-
++
+ skb->dev = dev;
+ skb_reserve(skb, 2);
+-
++
+ /* Read packet into buffer */
+ outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
+ outw(0, IE_GP); /* Seek to beginning of packet */
+- insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
+-
+- if (NI5010_DEBUG >= 4)
+- dump_packet(skb->data, skb->len);
+-
++ insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
++
++ if (NI5010_DEBUG >= 4)
++ dump_packet(skb->data, skb->len);
++
+ skb->protocol = eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += i_pkt_size;
+
+- PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
++ PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
+ dev->name, i_pkt_size));
+-
++
+ }
+
+ static int process_xmt_interrupt(struct net_device *dev)
+@@ -594,12 +594,12 @@ static int process_xmt_interrupt(struct
+
+ xmit_stat = inb(EDLC_XSTAT);
+ PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat));
+-
++
+ outb(0, EDLC_XMASK); /* Disable xmit IRQ's */
+ outb(0xff, EDLC_XCLR); /* Clear all pending xmit IRQ's */
+-
++
+ if (xmit_stat & XS_COLL){
+- PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
++ PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
+ dev->name));
+ outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP);
+ /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
+@@ -614,8 +614,8 @@ static int process_xmt_interrupt(struct
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += lp->o_pkt_size;
+ netif_wake_queue(dev);
+-
+- PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
++
++ PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
+ dev->name, lp->o_pkt_size));
+
+ return 0;
+@@ -635,7 +635,7 @@ static int ni5010_close(struct net_devic
+ outb(RS_RESET, EDLC_RESET);
+
+ netif_stop_queue(dev);
+-
++
+ PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
+ return 0;
+
+@@ -648,9 +648,9 @@ static struct net_device_stats *ni5010_g
+ struct ni5010_local *lp = netdev_priv(dev);
+
+ PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name));
+-
++
+ if (NI5010_DEBUG) ni5010_show_registers(dev);
+-
++
+ /* cli(); */
+ /* Update the statistics from the device registers. */
+ /* We do this in the interrupt handler */
+@@ -667,7 +667,7 @@ static struct net_device_stats *ni5010_g
+ */
+ static void ni5010_set_multicast_list(struct net_device *dev)
+ {
+- short ioaddr = dev->base_addr;
++ short ioaddr = dev->base_addr;
+
+ PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
+
+@@ -693,7 +693,7 @@ static void hardware_send_packet(struct
+ unsigned int buf_offs;
+
+ PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name));
+-
++
+ if (length > ETH_FRAME_LEN) {
+ PRINTK((KERN_WARNING "%s: packet too large, not possible\n",
+ dev->name));
+@@ -703,11 +703,11 @@ static void hardware_send_packet(struct
+ if (NI5010_DEBUG) ni5010_show_registers(dev);
+
+ if (inb(IE_ISTAT) & IS_EN_XMT) {
+- PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
++ PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
+ dev->name));
+ return;
+ }
+-
++
+ if (NI5010_DEBUG > 3) dump_packet(buf, length);
+
+ buf_offs = NI5010_BUFSIZE - length - pad;
+@@ -723,7 +723,7 @@ static void hardware_send_packet(struct
+ outsb(IE_XBUF, buf, length); /* Put data in buffer */
+ while(pad--)
+ outb(0, IE_XBUF);
+-
++
+ outw(buf_offs, IE_GP); /* Rewrite where packet starts */
+
+ /* should work without that outb() (Crynwr used it) */
+@@ -734,8 +734,8 @@ static void hardware_send_packet(struct
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ netif_wake_queue(dev);
+-
+- if (NI5010_DEBUG) ni5010_show_registers(dev);
++
++ if (NI5010_DEBUG) ni5010_show_registers(dev);
+ }
+
+ static void chipset_init(struct net_device *dev, int startp)
+@@ -747,7 +747,7 @@ static void chipset_init(struct net_devi
+ static void ni5010_show_registers(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+-
++
+ PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT)));
+ PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK)));
+ PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT)));
+diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
+index 4d52ecf..26e42f6 100644
+--- a/drivers/net/ni52.c
++++ b/drivers/net/ni52.c
+@@ -195,7 +195,7 @@ sizeof(nop_cmd) = 8;
+ #define NI52_ADDR2 0x01
+
+ static int ni52_probe1(struct net_device *dev,int ioaddr);
+-static irqreturn_t ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
++static irqreturn_t ni52_interrupt(int irq,void *dev_id);
+ static int ni52_open(struct net_device *dev);
+ static int ni52_close(struct net_device *dev);
+ static int ni52_send_packet(struct sk_buff *,struct net_device *);
+@@ -639,7 +639,7 @@ static int init586(struct net_device *de
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+-
++
+ tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+ tdr_cmd->cmd_status = 0;
+@@ -837,7 +837,7 @@ static void *alloc_rfa(struct net_device
+ * Interrupt Handler ...
+ */
+
+-static irqreturn_t ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
++static irqreturn_t ni52_interrupt(int irq,void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ unsigned short stat;
+diff --git a/drivers/net/ni52.h b/drivers/net/ni52.h
+index 68f1917..a33ea08 100644
+--- a/drivers/net/ni52.h
++++ b/drivers/net/ni52.h
+@@ -11,7 +11,7 @@
+ * Garret A. Wollman's i82586-driver for BSD
+ */
+
+-
++
+ #define NI52_RESET 0 /* writing to this address, resets the i82586 */
+ #define NI52_ATTENTION 1 /* channel attention, kick the 586 */
+ #define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
+@@ -151,7 +151,7 @@ struct rfd_struct
+ /*
+ * Receive Buffer Descriptor (RBD)
+ */
+-struct rbd_struct
++struct rbd_struct
+ {
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+@@ -203,7 +203,7 @@ struct nop_cmd_struct
+ /*
+ * IA Setup command
+ */
+-struct iasetup_cmd_struct
++struct iasetup_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+@@ -212,7 +212,7 @@ struct iasetup_cmd_struct
+ };
+
+ /*
+- * Configure command
++ * Configure command
+ */
+ struct configure_cmd_struct
+ {
+@@ -234,9 +234,9 @@ struct configure_cmd_struct
+ };
+
+ /*
+- * Multicast Setup command
++ * Multicast Setup command
+ */
+-struct mcsetup_cmd_struct
++struct mcsetup_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+@@ -257,9 +257,9 @@ struct dump_cmd_struct
+ };
+
+ /*
+- * transmit command
++ * transmit command
+ */
+-struct transmit_cmd_struct
++struct transmit_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
+index 810cc57..340ad0d 100644
+--- a/drivers/net/ni65.c
++++ b/drivers/net/ni65.c
+@@ -248,7 +248,7 @@ struct priv
+ };
+
+ static int ni65_probe1(struct net_device *dev,int);
+-static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs);
++static irqreturn_t ni65_interrupt(int irq, void * dev_id);
+ static void ni65_recv_intr(struct net_device *dev,int);
+ static void ni65_xmit_intr(struct net_device *dev,int);
+ static int ni65_open(struct net_device *dev);
+@@ -324,7 +324,7 @@ static int ni65_close(struct net_device
+ struct priv *p = (struct priv *) dev->priv;
+
+ netif_stop_queue(dev);
+-
++
+ outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
+
+ #ifdef XMT_VIA_SKB
+@@ -489,20 +489,20 @@ static int __init ni65_probe1(struct net
+ int dma = dmatab[i];
+ if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
+ continue;
+-
++
+ flags=claim_dma_lock();
+ disable_dma(dma);
+ set_dma_mode(dma,DMA_MODE_CASCADE);
+ enable_dma(dma);
+ release_dma_lock(flags);
+-
++
+ ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
+-
++
+ flags=claim_dma_lock();
+ disable_dma(dma);
+ free_dma(dma);
+ release_dma_lock(flags);
+-
++
+ if(readreg(CSR0) & CSR0_IDON)
+ break;
+ }
+@@ -871,7 +871,7 @@ static int ni65_lance_reinit(struct net_
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++static irqreturn_t ni65_interrupt(int irq, void * dev_id)
+ {
+ int csr0 = 0;
+ struct net_device *dev = dev_id;
+@@ -881,7 +881,7 @@ static irqreturn_t ni65_interrupt(int ir
+ p = (struct priv *) dev->priv;
+
+ spin_lock(&p->ring_lock);
+-
++
+ while(--bcnt) {
+ csr0 = inw(PORT+L_DATAREG);
+
+@@ -1139,7 +1139,7 @@ static void ni65_recv_intr(struct net_de
+ /*
+ * kick xmitter ..
+ */
+-
++
+ static void ni65_timeout(struct net_device *dev)
+ {
+ int i;
+@@ -1163,7 +1163,7 @@ static int ni65_send_packet(struct sk_bu
+ struct priv *p = (struct priv *) dev->priv;
+
+ netif_stop_queue(dev);
+-
++
+ if (test_and_set_bit(0, (void*)&p->lock)) {
+ printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
+ return 1;
+@@ -1209,10 +1209,10 @@ static int ni65_send_packet(struct sk_bu
+
+ if(p->tmdnum != p->tmdlast)
+ netif_wake_queue(dev);
+-
++
+ p->lock = 0;
+ dev->trans_start = jiffies;
+-
++
+ spin_unlock_irqrestore(&p->ring_lock, flags);
+ }
+
+diff --git a/drivers/net/ni65.h b/drivers/net/ni65.h
+index b01cef1..e6217e3 100644
+--- a/drivers/net/ni65.h
++++ b/drivers/net/ni65.h
+@@ -1,12 +1,12 @@
+ /* am7990 (lance) definitions
+- *
++ *
+ * This is an extension to the Linux operating system, and is covered by
+ * same GNU General Public License that covers that work.
+- *
++ *
+ * Michael Hipp
+ * email: mhipp at student.uni-tuebingen.de
+ *
+- * sources: (mail me or ask archie if you need them)
++ * sources: (mail me or ask archie if you need them)
+ * crynwr-packet-driver
+ */
+
+diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
+index 0e76859..b0127c7 100644
+--- a/drivers/net/ns83820.c
++++ b/drivers/net/ns83820.c
+@@ -65,7 +65,7 @@
+ * 0.20 - fix stupid RFEN thinko. i am such a smurf.
+ * 20040828 0.21 - add hardware vlan accleration
+ * by Neil Horman <nhorman at redhat.com>
+- * 20050406 0.22 - improved DAC ifdefs from Andi Kleen
++ * 20050406 0.22 - improved DAC ifdefs from Andi Kleen
+ * - removal of dead code from Adrian Bunk
+ * - fix half duplex collision behaviour
+ * Driver Overview
+@@ -377,7 +377,7 @@ static int lnksts = 0; /* CFG_LNKSTS bi
+ #define LINK_DOWN 0x02
+ #define LINK_UP 0x04
+
+-#define HW_ADDR_LEN sizeof(dma_addr_t)
++#define HW_ADDR_LEN sizeof(dma_addr_t)
+ #define desc_addr_set(desc, addr) \
+ do { \
+ ((desc)[0] = cpu_to_le32(addr)); \
+@@ -493,7 +493,7 @@ static inline void kick_rx(struct net_de
+ (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE)
+
+
+-#ifdef NS83820_VLAN_ACCEL_SUPPORT
++#ifdef NS83820_VLAN_ACCEL_SUPPORT
+ static void ns83820_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
+ {
+ struct ns83820 *dev = PRIV(ndev);
+@@ -865,7 +865,7 @@ static void fastcall ns83820_rx_kick(str
+ }
+
+ /* rx_irq
+- *
++ *
+ */
+ static void FASTCALL(rx_irq(struct net_device *ndev));
+ static void fastcall rx_irq(struct net_device *ndev)
+@@ -921,14 +921,14 @@ static void fastcall rx_irq(struct net_d
+ * that are 64 bytes with a vlan header appended
+ * like arp frames, or pings, are flagged as Runts
+ * when the tag is stripped and hardware. This
+- * also means that the OK bit in the descriptor
++ * also means that the OK bit in the descriptor
+ * is cleared when the frame comes in so we have
+ * to do a specific length check here to make sure
+ * the frame would have been ok, had we not stripped
+ * the tag.
+- */
++ */
+ if (likely((CMDSTS_OK & cmdsts) ||
+- ((cmdsts & CMDSTS_RUNT) && len >= 56))) {
++ ((cmdsts & CMDSTS_RUNT) && len >= 56))) {
+ #else
+ if (likely(CMDSTS_OK & cmdsts)) {
+ #endif
+@@ -945,7 +945,7 @@ static void fastcall rx_irq(struct net_d
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ skb->protocol = eth_type_trans(skb, ndev);
+-#ifdef NS83820_VLAN_ACCEL_SUPPORT
++#ifdef NS83820_VLAN_ACCEL_SUPPORT
+ if(extsts & EXTSTS_VPKT) {
+ unsigned short tag;
+ tag = ntohs(extsts & EXTSTS_VTG_MASK);
+@@ -1047,7 +1047,7 @@ static void do_tx_done(struct net_device
+ dev_kfree_skb_irq(skb);
+ atomic_dec(&dev->nr_tx_skbs);
+ } else
+- pci_unmap_page(dev->pci_dev,
++ pci_unmap_page(dev->pci_dev,
+ addr,
+ len,
+ PCI_DMA_TODEVICE);
+@@ -1153,7 +1153,7 @@ again:
+ if (!nr_frags)
+ frag = NULL;
+ extsts = 0;
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ extsts |= EXTSTS_IPPKT;
+ if (IPPROTO_TCP == skb->nh.iph->protocol)
+ extsts |= EXTSTS_TCPPKT;
+@@ -1273,7 +1273,7 @@ static u32 ns83820_get_link(struct net_d
+ return cfg & CFG_LNKSTS ? 1 : 0;
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = ns83820_get_drvinfo,
+ .get_link = ns83820_get_link
+ };
+@@ -1288,7 +1288,7 @@ static void ns83820_mib_isr(struct ns838
+ }
+
+ static void ns83820_do_isr(struct net_device *ndev, u32 isr);
+-static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
++static irqreturn_t ns83820_irq(int foo, void *data)
+ {
+ struct net_device *ndev = data;
+ struct ns83820 *dev = PRIV(ndev);
+@@ -1359,8 +1359,8 @@ static void ns83820_do_isr(struct net_de
+ dev->tx_idx = 0;
+ }
+ /* The may have been a race between a pci originated read
+- * and the descriptor update from the cpu. Just in case,
+- * kick the transmitter if the hardware thinks it is on a
++ * and the descriptor update from the cpu. Just in case,
++ * kick the transmitter if the hardware thinks it is on a
+ * different descriptor than we are.
+ */
+ if (dev->tx_idx != dev->tx_free_idx)
+@@ -1388,8 +1388,8 @@ static void ns83820_do_isr(struct net_de
+
+ /* The TxIdle interrupt can come in before the transmit has
+ * completed. Normally we reap packets off of the combination
+- * of TxDesc and TxIdle and leave TxOk disabled (since it
+- * occurs on every packet), but when no further irqs of this
++ * of TxDesc and TxIdle and leave TxOk disabled (since it
++ * occurs on every packet), but when no further irqs of this
+ * nature are expected, we must enable TxOk.
+ */
+ if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
+@@ -1956,7 +1956,7 @@ static int __devinit ns83820_init_one(st
+ /* When compiled with 64 bit addressing, we must always enable
+ * the 64 bit descriptor format.
+ */
+- if (sizeof(dma_addr_t) == 8)
++ if (sizeof(dma_addr_t) == 8)
+ dev->CFG_cache |= CFG_M64ADDR;
+ if (using_dac)
+ dev->CFG_cache |= CFG_T64ADDR;
+@@ -1994,7 +1994,7 @@ static int __devinit ns83820_init_one(st
+ writel(dev->CFG_cache, dev->base + CFG);
+ }
+
+-#if 0 /* Huh? This sets the PCI latency register. Should be done via
++#if 0 /* Huh? This sets the PCI latency register. Should be done via
+ * the PCI layer. FIXME.
+ */
+ if (readl(dev->base + SRR))
+@@ -2006,7 +2006,7 @@ static int __devinit ns83820_init_one(st
+ * can be transmitted is 8192 - FLTH - burst size.
+ * If only the transmit fifo was larger...
+ */
+- /* Ramit : 1024 DMA is not a good idea, it ends up banging
++ /* Ramit : 1024 DMA is not a good idea, it ends up banging
+ * some DELL and COMPAQ SMP systems */
+ writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
+ | ((1600 / 32) * 0x100),
+@@ -2020,8 +2020,8 @@ static int __devinit ns83820_init_one(st
+ /* Set Rx to full duplex, don't accept runt, errored, long or length
+ * range errored packets. Use 512 byte DMA.
+ */
+- /* Ramit : 1024 DMA is not a good idea, it ends up banging
+- * some DELL and COMPAQ SMP systems
++ /* Ramit : 1024 DMA is not a good idea, it ends up banging
++ * some DELL and COMPAQ SMP systems
+ * Turn on ALP, only we are accpeting Jumbo Packets */
+ writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
+ | RXCFG_STRIPCRC
+@@ -2045,7 +2045,7 @@ static int __devinit ns83820_init_one(st
+ * also turn on tag stripping if hardware acceleration is enabled
+ */
+ #ifdef NS83820_VLAN_ACCEL_SUPPORT
+-#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN)
++#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN)
+ #else
+ #define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN)
+ #endif
+@@ -2178,7 +2178,7 @@ static struct pci_driver driver = {
+ static int __init ns83820_init(void)
+ {
+ printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n");
+- return pci_module_init(&driver);
++ return pci_register_driver(&driver);
+ }
+
+ static void __exit ns83820_exit(void)
+diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
+index d0f686d..702e3e9 100644
+--- a/drivers/net/oaknet.c
++++ b/drivers/net/oaknet.c
+@@ -9,7 +9,7 @@
+ * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
+ * various other 8390 drivers written by Donald Becker and Paul Gortmaker.
+ *
+- * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
++ * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
+ * and "enetLib.c" from IBM.
+ *
+ */
+@@ -98,7 +98,7 @@ static int __init oaknet_init(void)
+ int ret = -ENOMEM;
+ struct net_device *dev;
+ #if 0
+- unsigned long ioaddr = OAKNET_IO_BASE;
++ unsigned long ioaddr = OAKNET_IO_BASE;
+ #else
+ unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
+ #endif
+@@ -201,7 +201,7 @@ static int __init oaknet_init(void)
+ ret = register_netdev(dev);
+ if (ret)
+ goto out_irq;
+-
++
+ oaknet_devs = dev;
+ return 0;
+
+@@ -447,8 +447,8 @@ oaknet_block_input(struct net_device *de
+ * Input(s):
+ * *dev - Pointer to the device structure for this driver.
+ * count - Number of bytes to be transferred.
+- * *buf -
+- * start_page -
++ * *buf -
++ * start_page -
+ *
+ * Output(s):
+ * N/A
+@@ -584,7 +584,7 @@ retry:
+ * This was for the ALPHA version only, but enough people have
+ * been encountering problems so it is still here.
+ */
+-
++
+ {
+ /* DMA termination address check... */
+ int addr, tries = 20;
+@@ -614,7 +614,7 @@ retry:
+ break;
+ }
+ }
+-
++
+ ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+ }
+diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
+index e0e2939..00ca0fd 100644
+--- a/drivers/net/pci-skeleton.c
++++ b/drivers/net/pci-skeleton.c
+@@ -98,7 +98,7 @@ IVc. Errata
+ #include <linux/crc32.h>
+ #include <asm/io.h>
+
+-#define NETDRV_VERSION "1.0.0"
++#define NETDRV_VERSION "1.0.1"
+ #define MODNAME "netdrv"
+ #define NETDRV_DRIVER_LOAD_MSG "MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
+ #define PFX MODNAME ": "
+@@ -502,8 +502,7 @@ static void netdrv_tx_timeout (struct ne
+ static void netdrv_init_ring (struct net_device *dev);
+ static int netdrv_start_xmit (struct sk_buff *skb,
+ struct net_device *dev);
+-static irqreturn_t netdrv_interrupt (int irq, void *dev_instance,
+- struct pt_regs *regs);
++static irqreturn_t netdrv_interrupt (int irq, void *dev_instance);
+ static int netdrv_close (struct net_device *dev);
+ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+ static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
+@@ -1318,7 +1317,7 @@ static void netdrv_tx_timeout (struct ne
+
+ /* Stop a shared interrupt from scavenging while we are. */
+ spin_lock_irqsave (&tp->lock, flags);
+-
++
+ netdrv_tx_clear (tp);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+@@ -1654,8 +1653,7 @@ static void netdrv_weird_interrupt (stru
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t netdrv_interrupt (int irq, void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct netdrv_private *tp = dev->priv;
+@@ -1853,9 +1851,6 @@ static void netdrv_set_rx_mode (struct n
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+- /* Unconditionally log net taps. */
+- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+@@ -1963,7 +1958,7 @@ static int __init netdrv_init_module (vo
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init (&netdrv_pci_driver);
++ return pci_register_driver(&netdrv_pci_driver);
+ }
+
+
+diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
+index fab9336..0460099 100644
+--- a/drivers/net/pcmcia/3c574_cs.c
++++ b/drivers/net/pcmcia/3c574_cs.c
+@@ -238,14 +238,14 @@ static void tc574_reset(struct net_devic
+ static void media_check(unsigned long arg);
+ static int el3_open(struct net_device *dev);
+ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t el3_interrupt(int irq, void *dev_id);
+ static void update_stats(struct net_device *dev);
+ static struct net_device_stats *el3_get_stats(struct net_device *dev);
+ static int el3_rx(struct net_device *dev, int worklimit);
+ static int el3_close(struct net_device *dev);
+ static void el3_tx_timeout(struct net_device *dev);
+ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static void set_rx_mode(struct net_device *dev);
+
+ static void tc574_detach(struct pcmcia_device *p_dev);
+@@ -817,7 +817,7 @@ static int el3_start_xmit(struct sk_buff
+ }
+
+ /* The EL3 interrupt handler. */
+-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t el3_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct el3_private *lp = netdev_priv(dev);
+@@ -927,7 +927,7 @@ static void media_check(unsigned long ar
+ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
+ if (!lp->fast_poll)
+ printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+- el3_interrupt(dev->irq, lp, NULL);
++ el3_interrupt(dev->irq, lp);
+ lp->fast_poll = HZ;
+ }
+ if (lp->fast_poll) {
+@@ -1095,7 +1095,7 @@ static void netdev_get_drvinfo(struct ne
+ strcpy(info->driver, "3c574_cs");
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
+index 875a0fe..231fa2c 100644
+--- a/drivers/net/pcmcia/3c589_cs.c
++++ b/drivers/net/pcmcia/3c589_cs.c
+@@ -151,14 +151,14 @@ static void media_check(unsigned long ar
+ static int el3_config(struct net_device *dev, struct ifmap *map);
+ static int el3_open(struct net_device *dev);
+ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t el3_interrupt(int irq, void *dev_id);
+ static void update_stats(struct net_device *dev);
+ static struct net_device_stats *el3_get_stats(struct net_device *dev);
+ static int el3_rx(struct net_device *dev);
+ static int el3_close(struct net_device *dev);
+ static void el3_tx_timeout(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+ static void tc589_detach(struct pcmcia_device *p_dev);
+
+@@ -530,7 +530,7 @@ static void netdev_set_msglevel(struct n
+ }
+ #endif /* PCMCIA_DEBUG */
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ #ifdef PCMCIA_DEBUG
+ .get_msglevel = netdev_get_msglevel,
+@@ -645,7 +645,7 @@ static int el3_start_xmit(struct sk_buff
+ }
+
+ /* The EL3 interrupt handler. */
+-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t el3_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct el3_private *lp = netdev_priv(dev);
+@@ -748,7 +748,7 @@ static void media_check(unsigned long ar
+ (inb(ioaddr + EL3_TIMER) == 0xff)) {
+ if (!lp->fast_poll)
+ printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name);
+- el3_interrupt(dev->irq, lp, NULL);
++ el3_interrupt(dev->irq, lp);
+ lp->fast_poll = HZ;
+ }
+ if (lp->fast_poll) {
+diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
+index 297e9f8..5ddd574 100644
+--- a/drivers/net/pcmcia/axnet_cs.c
++++ b/drivers/net/pcmcia/axnet_cs.c
+@@ -91,8 +91,8 @@ static void axnet_release(struct pcmcia_
+ static int axnet_open(struct net_device *dev);
+ static int axnet_close(struct net_device *dev);
+ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops netdev_ethtool_ops;
+-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
++static const struct ethtool_ops netdev_ethtool_ops;
++static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
+ static void ei_watchdog(u_long arg);
+ static void axnet_reset_8390(struct net_device *dev);
+
+@@ -112,7 +112,7 @@ static void axdev_setup(struct net_devic
+ static void AX88190_init(struct net_device *dev, int startp);
+ static int ax_open(struct net_device *dev);
+ static int ax_close(struct net_device *dev);
+-static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ax_interrupt(int irq, void *dev_id);
+
+ /*====================================================================*/
+
+@@ -599,11 +599,11 @@ static void axnet_reset_8390(struct net_
+
+ /*====================================================================*/
+
+-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ PRIV(dev)->stale = 0;
+- return ax_interrupt(irq, dev_id, regs);
++ return ax_interrupt(irq, dev_id);
+ }
+
+ static void ei_watchdog(u_long arg)
+@@ -621,7 +621,7 @@ static void ei_watchdog(u_long arg)
+ if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
+ if (!info->fast_poll)
+ printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+- ei_irq_wrapper(dev->irq, dev, NULL);
++ ei_irq_wrapper(dev->irq, dev);
+ info->fast_poll = HZ;
+ }
+ if (info->fast_poll) {
+@@ -671,7 +671,7 @@ static void netdev_get_drvinfo(struct ne
+ strcpy(info->driver, "axnet_cs");
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+@@ -771,6 +771,7 @@ static struct pcmcia_device_id axnet_ids
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
+ PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
++ PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
+ PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
+ PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
+@@ -786,8 +787,6 @@ static struct pcmcia_device_id axnet_ids
+ 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);
+@@ -1194,7 +1193,7 @@ static int ei_start_xmit(struct sk_buff
+ * needed.
+ */
+
+-static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ax_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ long e8390_base;
+@@ -1202,14 +1201,8 @@ static irqreturn_t ax_interrupt(int irq,
+ struct ei_device *ei_local;
+ int handled = 0;
+
+- if (dev == NULL)
+- {
+- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
+ e8390_base = dev->base_addr;
+- ei_local = (struct ei_device *) netdev_priv(dev);
++ ei_local = netdev_priv(dev);
+
+ /*
+ * Protect the irq test too.
+diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
+index ea93b8f..65f6fdf 100644
+--- a/drivers/net/pcmcia/fmvj18x_cs.c
++++ b/drivers/net/pcmcia/fmvj18x_cs.c
+@@ -29,7 +29,7 @@
+ ======================================================================*/
+
+ #define DRV_NAME "fmvj18x_cs"
+-#define DRV_VERSION "2.8"
++#define DRV_VERSION "2.9"
+
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -97,13 +97,13 @@ static int fjn_config(struct net_device
+ static int fjn_open(struct net_device *dev);
+ static int fjn_close(struct net_device *dev);
+ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t fjn_interrupt(int irq, void *dev_id);
+ static void fjn_rx(struct net_device *dev);
+ static void fjn_reset(struct net_device *dev);
+ static struct net_device_stats *fjn_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+ static void fjn_tx_timeout(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+ /*
+ card type
+@@ -733,7 +733,7 @@ module_exit(exit_fmvj18x_cs);
+
+ /*====================================================================*/
+
+-static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t fjn_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ local_info_t *lp = netdev_priv(dev);
+@@ -1092,7 +1092,7 @@ static void netdev_set_msglevel(struct n
+ }
+ #endif /* PCMCIA_DEBUG */
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ #ifdef PCMCIA_DEBUG
+ .get_msglevel = netdev_get_msglevel,
+@@ -1193,8 +1193,6 @@ static void set_rx_mode(struct net_devic
+ outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
+
+ if (dev->flags & IFF_PROMISC) {
+- /* Unconditionally log net taps. */
+- printk("%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
+ } else if (dev->mc_count > MC_FILTERBREAK
+diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
+index b8fe70b..bc0ca41 100644
+--- a/drivers/net/pcmcia/ibmtr_cs.c
++++ b/drivers/net/pcmcia/ibmtr_cs.c
+@@ -126,7 +126,7 @@ static void netdev_get_drvinfo(struct ne
+ strcpy(info->driver, "ibmtr_cs");
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
+index a8f6bfc..e77110e 100644
+--- a/drivers/net/pcmcia/nmclan_cs.c
++++ b/drivers/net/pcmcia/nmclan_cs.c
+@@ -426,12 +426,12 @@ static int mace_open(struct net_device *
+ static int mace_close(struct net_device *dev);
+ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static void mace_tx_timeout(struct net_device *dev);
+-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t mace_interrupt(int irq, void *dev_id);
+ static struct net_device_stats *mace_get_stats(struct net_device *dev);
+ static int mace_rx(struct net_device *dev, unsigned char RxCnt);
+ static void restore_multicast_list(struct net_device *dev);
+ static void set_multicast_list(struct net_device *dev);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+
+ static void nmclan_detach(struct pcmcia_device *p_dev);
+@@ -907,7 +907,7 @@ static void netdev_set_msglevel(struct n
+ }
+ #endif /* PCMCIA_DEBUG */
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ #ifdef PCMCIA_DEBUG
+ .get_msglevel = netdev_get_msglevel,
+@@ -1002,7 +1002,7 @@ static int mace_start_xmit(struct sk_buf
+ mace_interrupt
+ The interrupt handler.
+ ---------------------------------------------------------------------------- */
+-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mace_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ mace_private *lp = netdev_priv(dev);
+diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
+index 0ecebfc..0c00d18 100644
+--- a/drivers/net/pcmcia/pcnet_cs.c
++++ b/drivers/net/pcmcia/pcnet_cs.c
+@@ -108,8 +108,8 @@ static void pcnet_release(struct pcmcia_
+ static int pcnet_open(struct net_device *dev);
+ static int pcnet_close(struct net_device *dev);
+ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops netdev_ethtool_ops;
+-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
++static const struct ethtool_ops netdev_ethtool_ops;
++static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
+ static void ei_watchdog(u_long arg);
+ static void pcnet_reset_8390(struct net_device *dev);
+ static int set_config(struct net_device *dev, struct ifmap *map);
+@@ -654,11 +654,8 @@ static int pcnet_config(struct pcmcia_de
+ SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+
+ if (info->flags & (IS_DL10019|IS_DL10022)) {
+- u_char id = inb(dev->base_addr + 0x1a);
+ dev->do_ioctl = &ei_ioctl;
+ mii_phy_probe(dev);
+- if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
+- info->eth_phy = 0;
+ }
+
+ link->dev_node = &info->node;
+@@ -821,15 +818,6 @@ static void mdio_write(kio_addr_t addr,
+ }
+ }
+
+-static void mdio_reset(kio_addr_t addr, int phy_id)
+-{
+- outb_p(0x08, addr);
+- outb_p(0x0c, addr);
+- outb_p(0x08, addr);
+- outb_p(0x0c, addr);
+- outb_p(0x00, addr);
+-}
+-
+ /*======================================================================
+
+ EEPROM access routines for DL10019 and DL10022 based cards
+@@ -942,7 +930,8 @@ static void set_misc_reg(struct net_devi
+ }
+ if (info->flags & IS_DL10022) {
+ if (info->flags & HAS_MII) {
+- mdio_reset(nic_base + DLINK_GPIO, info->eth_phy);
++ /* Advertise 100F, 100H, 10F, 10H */
++ mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
+ /* Restart MII autonegotiation */
+ mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
+ mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
+@@ -1082,11 +1071,11 @@ static int set_config(struct net_device
+
+ /*====================================================================*/
+
+-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ pcnet_dev_t *info;
+- irqreturn_t ret = ei_interrupt(irq, dev_id, regs);
++ irqreturn_t ret = ei_interrupt(irq, dev_id);
+
+ if (ret == IRQ_HANDLED) {
+ info = PRIV(dev);
+@@ -1111,7 +1100,7 @@ static void ei_watchdog(u_long arg)
+ if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
+ if (!info->fast_poll)
+ printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+- ei_irq_wrapper(dev->irq, dev, NULL);
++ ei_irq_wrapper(dev->irq, dev);
+ info->fast_poll = HZ;
+ }
+ if (info->fast_poll) {
+@@ -1192,7 +1181,7 @@ static void netdev_get_drvinfo(struct ne
+ strcpy(info->driver, "pcnet_cs");
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
+index a73d545..20fcc35 100644
+--- a/drivers/net/pcmcia/smc91c92_cs.c
++++ b/drivers/net/pcmcia/smc91c92_cs.c
+@@ -80,14 +80,14 @@ INT_MODULE_PARM(if_port, 0);
+ #ifdef PCMCIA_DEBUG
+ INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+ static const char *version =
+-"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker at scyld.com.\n";
++"smc91c92_cs.c 1.123 2006/11/09 Donald Becker, becker at scyld.com.\n";
+ #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+ #else
+ #define DEBUG(n, args...)
+ #endif
+
+ #define DRV_NAME "smc91c92_cs"
+-#define DRV_VERSION "1.122"
++#define DRV_VERSION "1.123"
+
+ /*====================================================================*/
+
+@@ -287,7 +287,7 @@ static int smc_close(struct net_device *
+ static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static void smc_tx_timeout(struct net_device *dev);
+ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t smc_interrupt(int irq, void *dev_id);
+ static void smc_rx(struct net_device *dev);
+ static struct net_device_stats *smc_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+@@ -299,7 +299,7 @@ static void mdio_sync(kio_addr_t addr);
+ static int mdio_read(struct net_device *dev, int phy_id, int loc);
+ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
+ static int smc_link_ok(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+
+ /*======================================================================
+
+@@ -1545,7 +1545,7 @@ static void smc_eph_irq(struct net_devic
+
+ /*====================================================================*/
+
+-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t smc_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct smc_private *smc = netdev_priv(dev);
+@@ -1780,7 +1780,6 @@ static void set_rx_mode(struct net_devic
+ u_short rx_cfg_setting;
+
+ if (dev->flags & IFF_PROMISC) {
+- printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
+ rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
+ } else if (dev->flags & IFF_ALLMULTI)
+ rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
+@@ -1967,7 +1966,7 @@ static void media_check(u_long arg)
+ if (smc->watchdog++ && ((i>>8) & i)) {
+ if (!smc->fast_poll)
+ printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+- smc_interrupt(dev->irq, smc, NULL);
++ smc_interrupt(dev->irq, smc);
+ smc->fast_poll = HZ;
+ }
+ if (smc->fast_poll) {
+@@ -2208,7 +2207,7 @@ static int smc_nway_reset(struct net_dev
+ return -EOPNOTSUPP;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .begin = check_if_running,
+ .get_drvinfo = smc_get_drvinfo,
+ .get_settings = smc_get_settings,
+diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
+index 4122bb4..f3914f5 100644
+--- a/drivers/net/pcmcia/xirc2ps_cs.c
++++ b/drivers/net/pcmcia/xirc2ps_cs.c
+@@ -308,7 +308,7 @@ static void xirc2ps_detach(struct pcmcia
+ * less on other parts of the kernel.
+ */
+
+-static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id);
+
+ /****************
+ * A linked list of "instances" of the device. Each actual
+@@ -361,7 +361,7 @@ static int set_card_type(struct pcmcia_d
+ static int do_config(struct net_device *dev, struct ifmap *map);
+ static int do_open(struct net_device *dev);
+ static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static void hardreset(struct net_device *dev);
+ static void do_reset(struct net_device *dev, int full);
+ static int init_mii(struct net_device *dev);
+@@ -1121,7 +1121,7 @@ static int xirc2ps_resume(struct pcmcia_
+ * This is the Interrupt service route.
+ */
+ static irqreturn_t
+-xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++xirc2ps_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ local_info_t *lp = netdev_priv(dev);
+@@ -1553,7 +1553,7 @@ static void netdev_get_drvinfo(struct ne
+ sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
+index d50bcb8..36f9d98 100644
+--- a/drivers/net/pcnet32.c
++++ b/drivers/net/pcnet32.c
+@@ -22,8 +22,12 @@
+ *************************************************************************/
+
+ #define DRV_NAME "pcnet32"
+-#define DRV_VERSION "1.32"
+-#define DRV_RELDATE "18.Mar.2006"
++#ifdef CONFIG_PCNET32_NAPI
++#define DRV_VERSION "1.33-NAPI"
++#else
++#define DRV_VERSION "1.33"
++#endif
++#define DRV_RELDATE "27.Jun.2006"
+ #define PFX DRV_NAME ": "
+
+ static const char *const version =
+@@ -207,7 +211,7 @@ static int homepna[MAX_UNITS];
+ /* The PCNET32 Rx and Tx ring descriptors. */
+ struct pcnet32_rx_head {
+ u32 base;
+- s16 buf_length;
++ s16 buf_length; /* two`s complement of length */
+ s16 status;
+ u32 msg_length;
+ u32 reserved;
+@@ -215,7 +219,7 @@ struct pcnet32_rx_head {
+
+ struct pcnet32_tx_head {
+ u32 base;
+- s16 length;
++ s16 length; /* two`s complement of length */
+ s16 status;
+ u32 misc;
+ u32 reserved;
+@@ -299,9 +303,8 @@ static int pcnet32_probe1(unsigned long,
+ static int pcnet32_open(struct net_device *);
+ static int pcnet32_init_ring(struct net_device *);
+ static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
+-static int pcnet32_rx(struct net_device *);
+ static void pcnet32_tx_timeout(struct net_device *dev);
+-static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t pcnet32_interrupt(int, void *);
+ static int pcnet32_close(struct net_device *);
+ static struct net_device_stats *pcnet32_get_stats(struct net_device *);
+ static void pcnet32_load_multicast(struct net_device *dev);
+@@ -671,7 +674,7 @@ static void pcnet32_purge_rx_ring(struct
+ static void pcnet32_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- pcnet32_interrupt(0, dev, NULL);
++ pcnet32_interrupt(0, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -804,7 +807,7 @@ static int pcnet32_set_ringparam(struct
+ }
+ if ((1 << i) != lp->tx_ring_size)
+ pcnet32_realloc_tx_ring(dev, lp, i);
+-
++
+ size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+ for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
+ if (size <= (1 << i))
+@@ -812,7 +815,7 @@ static int pcnet32_set_ringparam(struct
+ }
+ if ((1 << i) != lp->rx_ring_size)
+ pcnet32_realloc_rx_ring(dev, lp, i);
+-
++
+ dev->weight = lp->rx_ring_size / 2;
+
+ if (netif_running(dev)) {
+@@ -883,7 +886,11 @@ static int pcnet32_loopback_test(struct
+ rc = 1; /* default to fail */
+
+ if (netif_running(dev))
++#ifdef CONFIG_PCNET32_NAPI
++ pcnet32_netif_stop(dev);
++#else
+ pcnet32_close(dev);
++#endif
+
+ spin_lock_irqsave(&lp->lock, flags);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+@@ -892,7 +899,7 @@ static int pcnet32_loopback_test(struct
+
+ /* Reset the PCNET32 */
+ lp->a.reset(ioaddr);
+- lp->a.write_csr(ioaddr, CSR4, 0x0915);
++ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+
+ /* switch pcnet32 to 32bit mode */
+ lp->a.write_bcr(ioaddr, 20, 2);
+@@ -1015,6 +1022,16 @@ static int pcnet32_loopback_test(struct
+ x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
+ a->write_bcr(ioaddr, 32, (x & ~0x0002));
+
++#ifdef CONFIG_PCNET32_NAPI
++ if (netif_running(dev)) {
++ pcnet32_netif_start(dev);
++ pcnet32_restart(dev, CSR0_NORMAL);
++ } else {
++ pcnet32_purge_rx_ring(dev);
++ lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
++ }
++ spin_unlock_irqrestore(&lp->lock, flags);
++#else
+ if (netif_running(dev)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
+ pcnet32_open(dev);
+@@ -1023,6 +1040,7 @@ static int pcnet32_loopback_test(struct
+ lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
++#endif
+
+ return (rc);
+ } /* end pcnet32_loopback_test */
+@@ -1125,6 +1143,288 @@ static int pcnet32_suspend(struct net_de
+ return 1;
+ }
+
++/*
++ * process one receive descriptor entry
++ */
++
++static void pcnet32_rx_entry(struct net_device *dev,
++ struct pcnet32_private *lp,
++ struct pcnet32_rx_head *rxp,
++ int entry)
++{
++ int status = (short)le16_to_cpu(rxp->status) >> 8;
++ int rx_in_place = 0;
++ struct sk_buff *skb;
++ short pkt_len;
++
++ if (status != 0x03) { /* There was an error. */
++ /*
++ * There is a tricky error noted by John Murphy,
++ * <murf at perftech.com> to Russ Nelson: Even with full-sized
++ * buffers it's possible for a jabber packet to use two
++ * buffers, with only the last correctly noting the error.
++ */
++ if (status & 0x01) /* Only count a general error at the */
++ lp->stats.rx_errors++; /* end of a packet. */
++ if (status & 0x20)
++ lp->stats.rx_frame_errors++;
++ if (status & 0x10)
++ lp->stats.rx_over_errors++;
++ if (status & 0x08)
++ lp->stats.rx_crc_errors++;
++ if (status & 0x04)
++ lp->stats.rx_fifo_errors++;
++ return;
++ }
++
++ pkt_len = (le32_to_cpu(rxp->msg_length) & 0xfff) - 4;
++
++ /* Discard oversize frames. */
++ if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
++ if (netif_msg_drv(lp))
++ printk(KERN_ERR "%s: Impossible packet size %d!\n",
++ dev->name, pkt_len);
++ lp->stats.rx_errors++;
++ return;
++ }
++ if (pkt_len < 60) {
++ if (netif_msg_rx_err(lp))
++ printk(KERN_ERR "%s: Runt packet!\n", dev->name);
++ lp->stats.rx_errors++;
++ return;
++ }
++
++ if (pkt_len > rx_copybreak) {
++ struct sk_buff *newskb;
++
++ if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {
++ skb_reserve(newskb, 2);
++ skb = lp->rx_skbuff[entry];
++ pci_unmap_single(lp->pci_dev,
++ lp->rx_dma_addr[entry],
++ PKT_BUF_SZ - 2,
++ PCI_DMA_FROMDEVICE);
++ skb_put(skb, pkt_len);
++ lp->rx_skbuff[entry] = newskb;
++ newskb->dev = dev;
++ lp->rx_dma_addr[entry] =
++ pci_map_single(lp->pci_dev,
++ newskb->data,
++ PKT_BUF_SZ - 2,
++ PCI_DMA_FROMDEVICE);
++ rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
++ rx_in_place = 1;
++ } else
++ skb = NULL;
++ } else {
++ skb = dev_alloc_skb(pkt_len + 2);
++ }
++
++ if (skb == NULL) {
++ if (netif_msg_drv(lp))
++ printk(KERN_ERR
++ "%s: Memory squeeze, dropping packet.\n",
++ dev->name);
++ lp->stats.rx_dropped++;
++ return;
++ }
++ skb->dev = dev;
++ if (!rx_in_place) {
++ skb_reserve(skb, 2); /* 16 byte align */
++ skb_put(skb, pkt_len); /* Make room */
++ pci_dma_sync_single_for_cpu(lp->pci_dev,
++ lp->rx_dma_addr[entry],
++ PKT_BUF_SZ - 2,
++ PCI_DMA_FROMDEVICE);
++ eth_copy_and_sum(skb,
++ (unsigned char *)(lp->rx_skbuff[entry]->data),
++ pkt_len, 0);
++ pci_dma_sync_single_for_device(lp->pci_dev,
++ lp->rx_dma_addr[entry],
++ PKT_BUF_SZ - 2,
++ PCI_DMA_FROMDEVICE);
++ }
++ lp->stats.rx_bytes += skb->len;
++ skb->protocol = eth_type_trans(skb, dev);
++#ifdef CONFIG_PCNET32_NAPI
++ netif_receive_skb(skb);
++#else
++ netif_rx(skb);
++#endif
++ dev->last_rx = jiffies;
++ lp->stats.rx_packets++;
++ return;
++}
++
++static int pcnet32_rx(struct net_device *dev, int quota)
++{
++ struct pcnet32_private *lp = dev->priv;
++ int entry = lp->cur_rx & lp->rx_mod_mask;
++ struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
++ int npackets = 0;
++
++ /* If we own the next entry, it's a new packet. Send it up. */
++ while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
++ pcnet32_rx_entry(dev, lp, rxp, entry);
++ npackets += 1;
++ /*
++ * The docs say that the buffer length isn't touched, but Andrew
++ * Boyd of QNX reports that some revs of the 79C965 clear it.
++ */
++ rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
++ wmb(); /* Make sure owner changes after others are visible */
++ rxp->status = le16_to_cpu(0x8000);
++ entry = (++lp->cur_rx) & lp->rx_mod_mask;
++ rxp = &lp->rx_ring[entry];
++ }
++
++ return npackets;
++}
++
++static int pcnet32_tx(struct net_device *dev)
++{
++ struct pcnet32_private *lp = dev->priv;
++ unsigned int dirty_tx = lp->dirty_tx;
++ int delta;
++ int must_restart = 0;
++
++ while (dirty_tx != lp->cur_tx) {
++ int entry = dirty_tx & lp->tx_mod_mask;
++ int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
++
++ if (status < 0)
++ break; /* It still hasn't been Txed */
++
++ lp->tx_ring[entry].base = 0;
++
++ if (status & 0x4000) {
++ /* There was a major error, log it. */
++ int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
++ lp->stats.tx_errors++;
++ if (netif_msg_tx_err(lp))
++ printk(KERN_ERR
++ "%s: Tx error status=%04x err_status=%08x\n",
++ dev->name, status,
++ err_status);
++ if (err_status & 0x04000000)
++ lp->stats.tx_aborted_errors++;
++ if (err_status & 0x08000000)
++ lp->stats.tx_carrier_errors++;
++ if (err_status & 0x10000000)
++ lp->stats.tx_window_errors++;
++#ifndef DO_DXSUFLO
++ if (err_status & 0x40000000) {
++ lp->stats.tx_fifo_errors++;
++ /* Ackk! On FIFO errors the Tx unit is turned off! */
++ /* Remove this verbosity later! */
++ if (netif_msg_tx_err(lp))
++ printk(KERN_ERR
++ "%s: Tx FIFO error!\n",
++ dev->name);
++ must_restart = 1;
++ }
++#else
++ if (err_status & 0x40000000) {
++ lp->stats.tx_fifo_errors++;
++ if (!lp->dxsuflo) { /* If controller doesn't recover ... */
++ /* Ackk! On FIFO errors the Tx unit is turned off! */
++ /* Remove this verbosity later! */
++ if (netif_msg_tx_err(lp))
++ printk(KERN_ERR
++ "%s: Tx FIFO error!\n",
++ dev->name);
++ must_restart = 1;
++ }
++ }
++#endif
++ } else {
++ if (status & 0x1800)
++ lp->stats.collisions++;
++ lp->stats.tx_packets++;
++ }
++
++ /* We must free the original skb */
++ if (lp->tx_skbuff[entry]) {
++ pci_unmap_single(lp->pci_dev,
++ lp->tx_dma_addr[entry],
++ lp->tx_skbuff[entry]->
++ len, PCI_DMA_TODEVICE);
++ dev_kfree_skb_any(lp->tx_skbuff[entry]);
++ lp->tx_skbuff[entry] = NULL;
++ lp->tx_dma_addr[entry] = 0;
++ }
++ dirty_tx++;
++ }
++
++ delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);
++ if (delta > lp->tx_ring_size) {
++ if (netif_msg_drv(lp))
++ printk(KERN_ERR
++ "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
++ dev->name, dirty_tx, lp->cur_tx,
++ lp->tx_full);
++ dirty_tx += lp->tx_ring_size;
++ delta -= lp->tx_ring_size;
++ }
++
++ if (lp->tx_full &&
++ netif_queue_stopped(dev) &&
++ delta < lp->tx_ring_size - 2) {
++ /* The ring is no longer full, clear tbusy. */
++ lp->tx_full = 0;
++ netif_wake_queue(dev);
++ }
++ lp->dirty_tx = dirty_tx;
++
++ return must_restart;
++}
++
++#ifdef CONFIG_PCNET32_NAPI
++static int pcnet32_poll(struct net_device *dev, int *budget)
++{
++ struct pcnet32_private *lp = dev->priv;
++ int quota = min(dev->quota, *budget);
++ unsigned long ioaddr = dev->base_addr;
++ unsigned long flags;
++ u16 val;
++
++ quota = pcnet32_rx(dev, quota);
++
++ spin_lock_irqsave(&lp->lock, flags);
++ if (pcnet32_tx(dev)) {
++ /* reset the chip to clear the error condition, then restart */
++ lp->a.reset(ioaddr);
++ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
++ pcnet32_restart(dev, CSR0_START);
++ netif_wake_queue(dev);
++ }
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++ *budget -= quota;
++ dev->quota -= quota;
++
++ if (dev->quota == 0) {
++ return 1;
++ }
++
++ netif_rx_complete(dev);
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ /* clear interrupt masks */
++ val = lp->a.read_csr(ioaddr, CSR3);
++ val &= 0x00ff;
++ lp->a.write_csr(ioaddr, CSR3, val);
++
++ /* Set interrupt enable. */
++ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
++ mmiowb();
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++ return 0;
++}
++#endif
++
+ #define PCNET32_REGS_PER_PHY 32
+ #define PCNET32_MAX_PHYS 32
+ static int pcnet32_get_regs_len(struct net_device *dev)
+@@ -1197,7 +1497,7 @@ static void pcnet32_get_regs(struct net_
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+
+-static struct ethtool_ops pcnet32_ethtool_ops = {
++static const struct ethtool_ops pcnet32_ethtool_ops = {
+ .get_settings = pcnet32_get_settings,
+ .set_settings = pcnet32_set_settings,
+ .get_drvinfo = pcnet32_get_drvinfo,
+@@ -1602,7 +1902,7 @@ pcnet32_probe1(unsigned long ioaddr, int
+ * boards will work.
+ */
+ /* Trigger an initialization just for the interrupt. */
+- a->write_csr(ioaddr, 0, 0x41);
++ a->write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_INIT);
+ mdelay(1);
+
+ dev->irq = probe_irq_off(irq_mask);
+@@ -1661,6 +1961,10 @@ pcnet32_probe1(unsigned long ioaddr, int
+ dev->ethtool_ops = &pcnet32_ethtool_ops;
+ dev->tx_timeout = pcnet32_tx_timeout;
+ dev->watchdog_timeo = (5 * HZ);
++ dev->weight = lp->rx_ring_size / 2;
++#ifdef CONFIG_PCNET32_NAPI
++ dev->poll = pcnet32_poll;
++#endif
+
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = pcnet32_poll_controller;
+@@ -1965,9 +2269,9 @@ static int pcnet32_open(struct net_devic
+
+ #ifdef DO_DXSUFLO
+ if (lp->dxsuflo) { /* Disable transmit stop on underflow */
+- val = lp->a.read_csr(ioaddr, 3);
++ val = lp->a.read_csr(ioaddr, CSR3);
+ val |= 0x40;
+- lp->a.write_csr(ioaddr, 3, val);
++ lp->a.write_csr(ioaddr, CSR3, val);
+ }
+ #endif
+
+@@ -1988,8 +2292,8 @@ static int pcnet32_open(struct net_devic
+ (lp->dma_addr +
+ offsetof(struct pcnet32_private, init_block)) >> 16);
+
+- lp->a.write_csr(ioaddr, 4, 0x0915);
+- lp->a.write_csr(ioaddr, 0, 0x0001);
++ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
++ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
+
+ netif_start_queue(dev);
+
+@@ -2001,13 +2305,13 @@ static int pcnet32_open(struct net_devic
+
+ i = 0;
+ while (i++ < 100)
+- if (lp->a.read_csr(ioaddr, 0) & 0x0100)
++ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
+ break;
+ /*
+ * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+ * reports that doing so triggers a bug in the '974.
+ */
+- lp->a.write_csr(ioaddr, 0, 0x0042);
++ lp->a.write_csr(ioaddr, CSR0, CSR0_NORMAL);
+
+ if (netif_msg_ifup(lp))
+ printk(KERN_DEBUG
+@@ -2015,7 +2319,7 @@ static int pcnet32_open(struct net_devic
+ dev->name, i,
+ (u32) (lp->dma_addr +
+ offsetof(struct pcnet32_private, init_block)),
+- lp->a.read_csr(ioaddr, 0));
++ lp->a.read_csr(ioaddr, CSR0));
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+@@ -2086,7 +2390,7 @@ static int pcnet32_init_ring(struct net_
+ (rx_skbuff = lp->rx_skbuff[i] =
+ dev_alloc_skb(PKT_BUF_SZ))) {
+ /* there is not much, we can do at this point */
+- if (pcnet32_debug & NETIF_MSG_DRV)
++ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: pcnet32_init_ring dev_alloc_skb failed.\n",
+ dev->name);
+@@ -2136,7 +2440,7 @@ static void pcnet32_restart(struct net_d
+
+ /* wait for stop */
+ for (i = 0; i < 100; i++)
+- if (lp->a.read_csr(ioaddr, 0) & 0x0004)
++ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_STOP)
+ break;
+
+ if (i >= 100 && netif_msg_drv(lp))
+@@ -2149,13 +2453,13 @@ static void pcnet32_restart(struct net_d
+ return;
+
+ /* ReInit Ring */
+- lp->a.write_csr(ioaddr, 0, 1);
++ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
+ i = 0;
+ while (i++ < 1000)
+- if (lp->a.read_csr(ioaddr, 0) & 0x0100)
++ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
+ break;
+
+- lp->a.write_csr(ioaddr, 0, csr0_bits);
++ lp->a.write_csr(ioaddr, CSR0, csr0_bits);
+ }
+
+ static void pcnet32_tx_timeout(struct net_device *dev)
+@@ -2168,8 +2472,8 @@ static void pcnet32_tx_timeout(struct ne
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR
+ "%s: transmit timed out, status %4.4x, resetting.\n",
+- dev->name, lp->a.read_csr(ioaddr, 0));
+- lp->a.write_csr(ioaddr, 0, 0x0004);
++ dev->name, lp->a.read_csr(ioaddr, CSR0));
++ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ lp->stats.tx_errors++;
+ if (netif_msg_tx_err(lp)) {
+ int i;
+@@ -2191,7 +2495,7 @@ static void pcnet32_tx_timeout(struct ne
+ le16_to_cpu(lp->tx_ring[i].status));
+ printk("\n");
+ }
+- pcnet32_restart(dev, 0x0042);
++ pcnet32_restart(dev, CSR0_NORMAL);
+
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+@@ -2212,7 +2516,7 @@ static int pcnet32_start_xmit(struct sk_
+ if (netif_msg_tx_queued(lp)) {
+ printk(KERN_DEBUG
+ "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
+- dev->name, lp->a.read_csr(ioaddr, 0));
++ dev->name, lp->a.read_csr(ioaddr, CSR0));
+ }
+
+ /* Default status -- will not enable Successful-TxDone
+@@ -2243,7 +2547,7 @@ static int pcnet32_start_xmit(struct sk_
+ lp->stats.tx_bytes += skb->len;
+
+ /* Trigger an immediate send poll. */
+- lp->a.write_csr(ioaddr, 0, 0x0048);
++ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
+
+ dev->trans_start = jiffies;
+
+@@ -2257,162 +2561,47 @@ static int pcnet32_start_xmit(struct sk_
+
+ /* The PCNET32 interrupt handler. */
+ static irqreturn_t
+-pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++pcnet32_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct pcnet32_private *lp;
+ unsigned long ioaddr;
+- u16 csr0, rap;
++ u16 csr0;
+ int boguscnt = max_interrupt_work;
+- int must_restart;
+-
+- if (!dev) {
+- if (pcnet32_debug & NETIF_MSG_INTR)
+- printk(KERN_DEBUG "%s(): irq %d for unknown device\n",
+- __FUNCTION__, irq);
+- return IRQ_NONE;
+- }
+
+ ioaddr = dev->base_addr;
+ lp = dev->priv;
+
+ spin_lock(&lp->lock);
+
+- rap = lp->a.read_rap(ioaddr);
+- while ((csr0 = lp->a.read_csr(ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) {
++ csr0 = lp->a.read_csr(ioaddr, CSR0);
++ while ((csr0 & 0x8f00) && --boguscnt >= 0) {
+ if (csr0 == 0xffff) {
+ break; /* PCMCIA remove happened */
+ }
+ /* Acknowledge all of the current interrupt sources ASAP. */
+- lp->a.write_csr(ioaddr, 0, csr0 & ~0x004f);
+-
+- must_restart = 0;
++ lp->a.write_csr(ioaddr, CSR0, csr0 & ~0x004f);
+
+ if (netif_msg_intr(lp))
+ printk(KERN_DEBUG
+ "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
+- dev->name, csr0, lp->a.read_csr(ioaddr, 0));
+-
+- if (csr0 & 0x0400) /* Rx interrupt */
+- pcnet32_rx(dev);
+-
+- if (csr0 & 0x0200) { /* Tx-done interrupt */
+- unsigned int dirty_tx = lp->dirty_tx;
+- int delta;
+-
+- while (dirty_tx != lp->cur_tx) {
+- int entry = dirty_tx & lp->tx_mod_mask;
+- int status =
+- (short)le16_to_cpu(lp->tx_ring[entry].
+- status);
+-
+- if (status < 0)
+- break; /* It still hasn't been Txed */
+-
+- lp->tx_ring[entry].base = 0;
+-
+- if (status & 0x4000) {
+- /* There was an major error, log it. */
+- int err_status =
+- le32_to_cpu(lp->tx_ring[entry].
+- misc);
+- lp->stats.tx_errors++;
+- if (netif_msg_tx_err(lp))
+- printk(KERN_ERR
+- "%s: Tx error status=%04x err_status=%08x\n",
+- dev->name, status,
+- err_status);
+- if (err_status & 0x04000000)
+- lp->stats.tx_aborted_errors++;
+- if (err_status & 0x08000000)
+- lp->stats.tx_carrier_errors++;
+- if (err_status & 0x10000000)
+- lp->stats.tx_window_errors++;
+-#ifndef DO_DXSUFLO
+- if (err_status & 0x40000000) {
+- lp->stats.tx_fifo_errors++;
+- /* Ackk! On FIFO errors the Tx unit is turned off! */
+- /* Remove this verbosity later! */
+- if (netif_msg_tx_err(lp))
+- printk(KERN_ERR
+- "%s: Tx FIFO error! CSR0=%4.4x\n",
+- dev->name, csr0);
+- must_restart = 1;
+- }
+-#else
+- if (err_status & 0x40000000) {
+- lp->stats.tx_fifo_errors++;
+- if (!lp->dxsuflo) { /* If controller doesn't recover ... */
+- /* Ackk! On FIFO errors the Tx unit is turned off! */
+- /* Remove this verbosity later! */
+- if (netif_msg_tx_err
+- (lp))
+- printk(KERN_ERR
+- "%s: Tx FIFO error! CSR0=%4.4x\n",
+- dev->
+- name,
+- csr0);
+- must_restart = 1;
+- }
+- }
+-#endif
+- } else {
+- if (status & 0x1800)
+- lp->stats.collisions++;
+- lp->stats.tx_packets++;
+- }
+-
+- /* We must free the original skb */
+- if (lp->tx_skbuff[entry]) {
+- pci_unmap_single(lp->pci_dev,
+- lp->tx_dma_addr[entry],
+- lp->tx_skbuff[entry]->
+- len, PCI_DMA_TODEVICE);
+- dev_kfree_skb_irq(lp->tx_skbuff[entry]);
+- lp->tx_skbuff[entry] = NULL;
+- lp->tx_dma_addr[entry] = 0;
+- }
+- dirty_tx++;
+- }
+-
+- delta =
+- (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask +
+- lp->tx_ring_size);
+- if (delta > lp->tx_ring_size) {
+- if (netif_msg_drv(lp))
+- printk(KERN_ERR
+- "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+- dev->name, dirty_tx, lp->cur_tx,
+- lp->tx_full);
+- dirty_tx += lp->tx_ring_size;
+- delta -= lp->tx_ring_size;
+- }
+-
+- if (lp->tx_full &&
+- netif_queue_stopped(dev) &&
+- delta < lp->tx_ring_size - 2) {
+- /* The ring is no longer full, clear tbusy. */
+- lp->tx_full = 0;
+- netif_wake_queue(dev);
+- }
+- lp->dirty_tx = dirty_tx;
+- }
++ dev->name, csr0, lp->a.read_csr(ioaddr, CSR0));
+
+ /* Log misc errors. */
+ if (csr0 & 0x4000)
+ lp->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & 0x1000) {
+ /*
+- * this happens when our receive ring is full. This shouldn't
+- * be a problem as we will see normal rx interrupts for the frames
+- * in the receive ring. But there are some PCI chipsets (I can
+- * reproduce this on SP3G with Intel saturn chipset) which have
+- * sometimes problems and will fill up the receive ring with
+- * error descriptors. In this situation we don't get a rx
+- * interrupt, but a missed frame interrupt sooner or later.
+- * So we try to clean up our receive ring here.
++ * This happens when our receive ring is full. This
++ * shouldn't be a problem as we will see normal rx
++ * interrupts for the frames in the receive ring. But
++ * there are some PCI chipsets (I can reproduce this
++ * on SP3G with Intel saturn chipset) which have
++ * sometimes problems and will fill up the receive
++ * ring with error descriptors. In this situation we
++ * don't get a rx interrupt, but a missed frame
++ * interrupt sooner or later.
+ */
+- pcnet32_rx(dev);
+ lp->stats.rx_errors++; /* Missed a Rx frame. */
+ }
+ if (csr0 & 0x0800) {
+@@ -2422,185 +2611,44 @@ pcnet32_interrupt(int irq, void *dev_id,
+ dev->name, csr0);
+ /* unlike for the lance, there is no restart needed */
+ }
+-
+- if (must_restart) {
++#ifdef CONFIG_PCNET32_NAPI
++ if (netif_rx_schedule_prep(dev)) {
++ u16 val;
++ /* set interrupt masks */
++ val = lp->a.read_csr(ioaddr, CSR3);
++ val |= 0x5f00;
++ lp->a.write_csr(ioaddr, CSR3, val);
++ mmiowb();
++ __netif_rx_schedule(dev);
++ break;
++ }
++#else
++ pcnet32_rx(dev, dev->weight);
++ if (pcnet32_tx(dev)) {
+ /* reset the chip to clear the error condition, then restart */
+ lp->a.reset(ioaddr);
+- lp->a.write_csr(ioaddr, 4, 0x0915);
+- pcnet32_restart(dev, 0x0002);
++ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
++ pcnet32_restart(dev, CSR0_START);
+ netif_wake_queue(dev);
+ }
++#endif
++ csr0 = lp->a.read_csr(ioaddr, CSR0);
+ }
+
++#ifndef CONFIG_PCNET32_NAPI
+ /* Set interrupt enable. */
+- lp->a.write_csr(ioaddr, 0, 0x0040);
+- lp->a.write_rap(ioaddr, rap);
++ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
++#endif
+
+ if (netif_msg_intr(lp))
+ printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
+- dev->name, lp->a.read_csr(ioaddr, 0));
++ dev->name, lp->a.read_csr(ioaddr, CSR0));
+
+ spin_unlock(&lp->lock);
+
+ return IRQ_HANDLED;
+ }
+
+-static int pcnet32_rx(struct net_device *dev)
+-{
+- struct pcnet32_private *lp = dev->priv;
+- int entry = lp->cur_rx & lp->rx_mod_mask;
+- int boguscnt = lp->rx_ring_size / 2;
+-
+- /* If we own the next entry, it's a new packet. Send it up. */
+- while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+- int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+-
+- if (status != 0x03) { /* There was an error. */
+- /*
+- * There is a tricky error noted by John Murphy,
+- * <murf at perftech.com> to Russ Nelson: Even with full-sized
+- * buffers it's possible for a jabber packet to use two
+- * buffers, with only the last correctly noting the error.
+- */
+- if (status & 0x01) /* Only count a general error at the */
+- lp->stats.rx_errors++; /* end of a packet. */
+- if (status & 0x20)
+- lp->stats.rx_frame_errors++;
+- if (status & 0x10)
+- lp->stats.rx_over_errors++;
+- if (status & 0x08)
+- lp->stats.rx_crc_errors++;
+- if (status & 0x04)
+- lp->stats.rx_fifo_errors++;
+- lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+- } else {
+- /* Malloc up new buffer, compatible with net-2e. */
+- short pkt_len =
+- (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)
+- - 4;
+- struct sk_buff *skb;
+-
+- /* Discard oversize frames. */
+- if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+- if (netif_msg_drv(lp))
+- printk(KERN_ERR
+- "%s: Impossible packet size %d!\n",
+- dev->name, pkt_len);
+- lp->stats.rx_errors++;
+- } else if (pkt_len < 60) {
+- if (netif_msg_rx_err(lp))
+- printk(KERN_ERR "%s: Runt packet!\n",
+- dev->name);
+- lp->stats.rx_errors++;
+- } else {
+- int rx_in_place = 0;
+-
+- if (pkt_len > rx_copybreak) {
+- struct sk_buff *newskb;
+-
+- if ((newskb =
+- dev_alloc_skb(PKT_BUF_SZ))) {
+- skb_reserve(newskb, 2);
+- skb = lp->rx_skbuff[entry];
+- pci_unmap_single(lp->pci_dev,
+- lp->
+- rx_dma_addr
+- [entry],
+- PKT_BUF_SZ - 2,
+- PCI_DMA_FROMDEVICE);
+- skb_put(skb, pkt_len);
+- lp->rx_skbuff[entry] = newskb;
+- newskb->dev = dev;
+- lp->rx_dma_addr[entry] =
+- 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;
+- } else
+- skb = NULL;
+- } else {
+- skb = dev_alloc_skb(pkt_len + 2);
+- }
+-
+- if (skb == NULL) {
+- int i;
+- if (netif_msg_drv(lp))
+- printk(KERN_ERR
+- "%s: Memory squeeze, deferring packet.\n",
+- dev->name);
+- for (i = 0; i < lp->rx_ring_size; i++)
+- if ((short)
+- le16_to_cpu(lp->
+- rx_ring[(entry +
+- i)
+- & lp->
+- rx_mod_mask].
+- status) < 0)
+- break;
+-
+- if (i > lp->rx_ring_size - 2) {
+- lp->stats.rx_dropped++;
+- lp->rx_ring[entry].status |=
+- le16_to_cpu(0x8000);
+- wmb(); /* Make sure adapter sees owner change */
+- lp->cur_rx++;
+- }
+- break;
+- }
+- skb->dev = dev;
+- if (!rx_in_place) {
+- skb_reserve(skb, 2); /* 16 byte align */
+- skb_put(skb, pkt_len); /* Make room */
+- pci_dma_sync_single_for_cpu(lp->pci_dev,
+- lp->
+- rx_dma_addr
+- [entry],
+- PKT_BUF_SZ -
+- 2,
+- PCI_DMA_FROMDEVICE);
+- eth_copy_and_sum(skb,
+- (unsigned char *)(lp->
+- rx_skbuff
+- [entry]->
+- data),
+- pkt_len, 0);
+- pci_dma_sync_single_for_device(lp->
+- pci_dev,
+- lp->
+- rx_dma_addr
+- [entry],
+- PKT_BUF_SZ
+- - 2,
+- PCI_DMA_FROMDEVICE);
+- }
+- lp->stats.rx_bytes += skb->len;
+- skb->protocol = eth_type_trans(skb, dev);
+- netif_rx(skb);
+- dev->last_rx = jiffies;
+- lp->stats.rx_packets++;
+- }
+- }
+- /*
+- * The docs say that the buffer length isn't touched, but Andrew Boyd
+- * of QNX reports that some revs of the 79C965 clear it.
+- */
+- lp->rx_ring[entry].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+- wmb(); /* Make sure owner changes after all others are visible */
+- lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+- entry = (++lp->cur_rx) & lp->rx_mod_mask;
+- if (--boguscnt <= 0)
+- break; /* don't stay in loop forever */
+- }
+-
+- return 0;
+-}
+-
+ static int pcnet32_close(struct net_device *dev)
+ {
+ unsigned long ioaddr = dev->base_addr;
+@@ -2618,10 +2666,10 @@ static int pcnet32_close(struct net_devi
+ if (netif_msg_ifdown(lp))
+ printk(KERN_DEBUG
+ "%s: Shutting down ethercard, status was %2.2x.\n",
+- dev->name, lp->a.read_csr(ioaddr, 0));
++ dev->name, lp->a.read_csr(ioaddr, CSR0));
+
+ /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
+- lp->a.write_csr(ioaddr, 0, 0x0004);
++ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+
+ /*
+ * Switch back to 16bit mode to avoid problems with dumb
+@@ -2647,13 +2695,10 @@ static struct net_device_stats *pcnet32_
+ {
+ struct pcnet32_private *lp = dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+- u16 saved_addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lp->lock, flags);
+- saved_addr = lp->a.read_rap(ioaddr);
+ lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
+- lp->a.write_rap(ioaddr, saved_addr);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return &lp->stats;
+@@ -2739,7 +2784,7 @@ static void pcnet32_set_multicast_list(s
+ /* clear SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = lp->a.read_csr(ioaddr, CSR5);
+ lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+- } else {
++ } else {
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ netif_wake_queue(dev);
+@@ -2978,7 +3023,7 @@ static int __init pcnet32_init_module(vo
+ tx_start = tx_start_pt;
+
+ /* find the PCI devices */
+- if (!pci_module_init(&pcnet32_driver))
++ if (!pci_register_driver(&pcnet32_driver))
+ pcnet32_have_pci = 1;
+
+ /* should we find any remaining VLbus devices ? */
+diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
+index 341036d..f14e992 100644
+--- a/drivers/net/phy/fixed.c
++++ b/drivers/net/phy/fixed.c
+@@ -13,7 +13,6 @@
+ * option) any later version.
+ *
+ */
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/string.h>
+@@ -289,9 +288,13 @@ static int fixed_mdio_register_device(in
+ goto probe_fail;
+ }
+
+- device_bind_driver(&phydev->dev);
++ err = device_bind_driver(&phydev->dev);
++
+ up_write(&phydev->dev.bus->subsys.rwsem);
+
++ if (err)
++ goto probe_fail;
++
+ return 0;
+
+ probe_fail:
+@@ -313,8 +316,10 @@ MODULE_LICENSE("GPL");
+
+ static int __init fixed_init(void)
+ {
++#if 0
+ int ret;
+ int duplex = 0;
++#endif
+
+ /* register on the bus... Not expected to be matched with anything there... */
+ phy_driver_register(&fixed_mdio_driver);
+@@ -335,8 +340,10 @@ static int __init fixed_init(void)
+ */
+
+ #ifdef CONFIG_FIXED_MII_DUPLEX
++#if 0
+ duplex = 1;
+ #endif
++#endif
+
+ #ifdef CONFIG_FIXED_MII_100_FDX
+ fixed_mdio_register_device(0, 100, 1);
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index f5aad77..3af9fcf 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -480,7 +480,7 @@ void phy_error(struct phy_device *phydev
+ * description: When a PHY interrupt occurs, the handler disables
+ * interrupts, and schedules a work task to clear the interrupt.
+ */
+-static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs)
++static irqreturn_t phy_interrupt(int irq, void *phy_dat)
+ {
+ struct phy_device *phydev = phy_dat;
+
+diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
+index 2d1ecfd..3bbd5e7 100644
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -212,11 +212,13 @@ struct phy_device *phy_attach(struct net
+
+ err = d->driver->probe(d);
+
+- if (err < 0)
+- return ERR_PTR(err);
++ if (err >= 0)
++ err = device_bind_driver(d);
+
+- device_bind_driver(d);
+ up_write(&d->bus->subsys.rwsem);
++
++ if (err)
++ return ERR_PTR(err);
+ }
+
+ if (phydev->attached_dev) {
+@@ -522,7 +524,7 @@ EXPORT_SYMBOL(genphy_read_status);
+
+ static int genphy_config_init(struct phy_device *phydev)
+ {
+- u32 val;
++ int val;
+ u32 features;
+
+ /* For now, I'll claim that the generic driver supports
+diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
+index 25e31fb..b1d8ed4 100644
+--- a/drivers/net/phy/smsc.c
++++ b/drivers/net/phy/smsc.c
+@@ -14,7 +14,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mii.h>
+diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
+index ffd215d..792716b 100644
+--- a/drivers/net/phy/vitesse.c
++++ b/drivers/net/phy/vitesse.c
+@@ -12,7 +12,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mii.h>
+diff --git a/drivers/net/plip.c b/drivers/net/plip.c
+index d4449d6..71afb27 100644
+--- a/drivers/net/plip.c
++++ b/drivers/net/plip.c
+@@ -16,7 +16,7 @@
+ * parport-sharing awareness code by Philip Blundell.
+ * SMP locking by Niibe Yutaka.
+ * Support for parallel ports with no IRQ (poll mode),
+- * Modifications to use the parallel port API
++ * Modifications to use the parallel port API
+ * by Nimrod Zimerman.
+ *
+ * Fixes:
+@@ -143,7 +143,7 @@ static void plip_bh(struct net_device *d
+ static void plip_timer_bh(struct net_device *dev);
+
+ /* Interrupt handler */
+-static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static void plip_interrupt(int irq, void *dev_id);
+
+ /* Functions for DEV methods */
+ static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
+@@ -383,9 +383,9 @@ static void
+ plip_timer_bh(struct net_device *dev)
+ {
+ struct net_local *nl = netdev_priv(dev);
+-
++
+ if (!(atomic_read (&nl->kill_timer))) {
+- plip_interrupt (-1, dev, NULL);
++ plip_interrupt (-1, dev);
+
+ schedule_delayed_work(&nl->timer, 1);
+ }
+@@ -527,7 +527,7 @@ plip_receive(unsigned short nibble_timeo
+ }
+
+ /*
+- * Determine the packet's protocol ID. The rule here is that we
++ * Determine the packet's protocol ID. The rule here is that we
+ * 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.
+ *
+@@ -537,16 +537,16 @@ plip_receive(unsigned short nibble_timeo
+ * We can't fix the daddr thing as that quirk (more bug) is embedded
+ * in far too many old systems not all even running Linux.
+ */
+-
++
+ static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct ethhdr *eth;
+ unsigned char *rawp;
+-
++
+ skb->mac.raw=skb->data;
+ skb_pull(skb,dev->hard_header_len);
+ eth = eth_hdr(skb);
+-
++
+ if(*eth->h_dest&1)
+ {
+ if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
+@@ -554,17 +554,17 @@ static __be16 plip_type_trans(struct sk_
+ else
+ skb->pkt_type=PACKET_MULTICAST;
+ }
+-
++
+ /*
+ * This ALLMULTI check should be redundant by 1.4
+ * so don't forget to remove it.
+ */
+-
++
+ if (ntohs(eth->h_proto) >= 1536)
+ return eth->h_proto;
+-
++
+ rawp = skb->data;
+-
++
+ /*
+ * This is a magic hack to spot IPX packets. Older Novell breaks
+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+@@ -573,7 +573,7 @@ static __be16 plip_type_trans(struct sk_
+ */
+ if (*(unsigned short *)rawp == 0xFFFF)
+ return htons(ETH_P_802_3);
+-
++
+ /*
+ * Real 802.2 LLC
+ */
+@@ -902,18 +902,13 @@ plip_error(struct net_device *dev, struc
+
+ /* Handle the parallel port interrupts. */
+ static void
+-plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++plip_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *nl;
+ struct plip_local *rcv;
+ unsigned char c0;
+
+- if (dev == NULL) {
+- printk(KERN_DEBUG "plip_interrupt: irq %d for unknown device.\n", irq);
+- return;
+- }
+-
+ nl = netdev_priv(dev);
+ rcv = &nl->rcv_data;
+
+@@ -972,7 +967,7 @@ plip_tx_packet(struct sk_buff *skb, stru
+ }
+
+ netif_stop_queue (dev);
+-
++
+ if (skb->len > dev->mtu + dev->hard_header_len) {
+ printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len);
+ netif_start_queue (dev);
+@@ -993,7 +988,7 @@ plip_tx_packet(struct sk_buff *skb, stru
+ }
+ schedule_work(&nl->immediate);
+ spin_unlock_irq(&nl->lock);
+-
++
+ return 0;
+ }
+
+@@ -1032,7 +1027,7 @@ int plip_hard_header_cache(struct neighb
+ {
+ struct net_local *nl = neigh->dev->priv;
+ int ret;
+-
++
+ if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
+ {
+ struct ethhdr *eth;
+@@ -1041,9 +1036,9 @@ int plip_hard_header_cache(struct neighb
+ HH_DATA_OFF(sizeof(*eth)));
+ plip_rewrite_address (neigh->dev, eth);
+ }
+-
++
+ return ret;
+-}
++}
+
+ /* Open/initialize the board. This is called (in the current kernel)
+ sometime after booting when the 'ifconfig' program is run.
+@@ -1187,7 +1182,7 @@ plip_wakeup(void *handle)
+ else
+ return;
+ }
+-
++
+ if (!(dev->flags & IFF_UP))
+ /* Don't need the port when the interface is down */
+ return;
+@@ -1264,7 +1259,7 @@ static void plip_attach (struct parport
+ struct net_local *nl;
+ char name[IFNAMSIZ];
+
+- if ((parport[0] == -1 && (!timid || !port->devices)) ||
++ if ((parport[0] == -1 && (!timid || !port->devices)) ||
+ plip_searchfor(parport, port->number)) {
+ if (unit == PLIP_MAX) {
+ printk(KERN_ERR "plip: too many devices\n");
+@@ -1277,7 +1272,7 @@ static void plip_attach (struct parport
+ printk(KERN_ERR "plip: memory squeeze\n");
+ return;
+ }
+-
++
+ strcpy(dev->name, name);
+
+ SET_MODULE_OWNER(dev);
+@@ -1290,7 +1285,7 @@ static void plip_attach (struct parport
+
+ nl = netdev_priv(dev);
+ nl->pardev = parport_register_device(port, name, plip_preempt,
+- plip_wakeup, plip_interrupt,
++ plip_wakeup, plip_interrupt,
+ 0, dev);
+
+ if (!nl->pardev) {
+@@ -1384,7 +1379,7 @@ static int __init plip_setup(char *str)
+ /* disable driver on "plip=" or "plip=0" */
+ parport[0] = -2;
+ } else {
+- printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n",
++ printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n",
+ ints[1]);
+ }
+ }
+diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
+index 23659fd..933e2f3 100644
+--- a/drivers/net/ppp_async.c
++++ b/drivers/net/ppp_async.c
+@@ -125,8 +125,8 @@ static struct ppp_channel_ops async_ops
+ * way to fix this is to use a rwlock in the tty struct, but for now
+ * we use a single global rwlock for all ttys in ppp line discipline.
+ *
+- * FIXME: this is no longer true. The _close path for the ldisc is
+- * now guaranteed to be sane.
++ * FIXME: this is no longer true. The _close path for the ldisc is
++ * now guaranteed to be sane.
+ */
+ static DEFINE_RWLOCK(disc_data_lock);
+
+@@ -277,7 +277,7 @@ ppp_asynctty_write(struct tty_struct *tt
+ * Called in process context only. May be re-entered by multiple
+ * ioctl calling threads.
+ */
+-
++
+ static int
+ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
+index 3872088..f54c552 100644
+--- a/drivers/net/ppp_deflate.c
++++ b/drivers/net/ppp_deflate.c
+@@ -635,7 +635,7 @@ static struct compressor ppp_deflate_dra
+ };
+
+ static int __init deflate_init(void)
+-{
++{
+ int answer = ppp_register_compressor(&ppp_deflate);
+ if (answer == 0)
+ printk(KERN_INFO
+@@ -643,7 +643,7 @@ static int __init deflate_init(void)
+ ppp_register_compressor(&ppp_deflate_draft);
+ return answer;
+ }
+-
++
+ static void __exit deflate_cleanup(void)
+ {
+ ppp_unregister_compressor(&ppp_deflate);
+diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
+index c872f7c..f5802e7 100644
+--- a/drivers/net/ppp_generic.c
++++ b/drivers/net/ppp_generic.c
+@@ -304,7 +304,7 @@ static const int npindex_to_proto[NUM_NP
+ PPP_MPLS_UC,
+ PPP_MPLS_MC,
+ };
+-
++
+ /* Translates an ethertype into an NP index */
+ static inline int ethertype_to_npindex(int ethertype)
+ {
+@@ -1619,11 +1619,11 @@ ppp_receive_nonmp_frame(struct ppp *ppp,
+ case PPP_VJC_UNCOMP:
+ if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
+ goto err;
+-
++
+ /* Until we fix the decompressor need to make sure
+ * data portion is linear.
+ */
+- if (!pskb_may_pull(skb, skb->len))
++ if (!pskb_may_pull(skb, skb->len))
+ goto err;
+
+ if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) {
+@@ -2185,7 +2185,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_
+ switch (CCP_CODE(dp)) {
+ case CCP_CONFREQ:
+
+- /* A ConfReq starts negotiation of compression
++ /* A ConfReq starts negotiation of compression
+ * in one direction of transmission,
+ * and hence brings it down...but which way?
+ *
+@@ -2195,16 +2195,16 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_
+ if(inbound)
+ /* He is proposing what I should send */
+ ppp->xstate &= ~SC_COMP_RUN;
+- else
++ else
+ /* I am proposing to what he should send */
+ ppp->rstate &= ~SC_DECOMP_RUN;
+-
++
+ break;
+-
++
+ case CCP_TERMREQ:
+ case CCP_TERMACK:
+ /*
+- * CCP is going down, both directions of transmission
++ * CCP is going down, both directions of transmission
+ */
+ ppp->rstate &= ~SC_DECOMP_RUN;
+ ppp->xstate &= ~SC_COMP_RUN;
+diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
+index 51ff9a9..f3655fd 100644
+--- a/drivers/net/ppp_mppe.c
++++ b/drivers/net/ppp_mppe.c
+@@ -43,6 +43,7 @@
+ * deprecated in 2.6
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/version.h>
+@@ -64,12 +65,13 @@ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+ MODULE_VERSION("1.0.2");
+
+-static void
++static unsigned int
+ setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
+ {
+ sg[0].page = virt_to_page(address);
+ sg[0].offset = offset_in_page(address);
+ sg[0].length = length;
++ return length;
+ }
+
+ #define SHA1_PAD_SIZE 40
+@@ -95,8 +97,8 @@ static inline void sha_pad_init(struct s
+ * State for an MPPE (de)compressor.
+ */
+ struct ppp_mppe_state {
+- struct crypto_tfm *arc4;
+- struct crypto_tfm *sha1;
++ struct crypto_blkcipher *arc4;
++ struct crypto_hash *sha1;
+ unsigned char *sha1_digest;
+ unsigned char master_key[MPPE_MAX_KEY_LEN];
+ unsigned char session_key[MPPE_MAX_KEY_LEN];
+@@ -136,14 +138,21 @@ struct ppp_mppe_state {
+ */
+ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
+ {
++ struct hash_desc desc;
+ struct scatterlist sg[4];
++ unsigned int nbytes;
+
+- setup_sg(&sg[0], state->master_key, state->keylen);
+- setup_sg(&sg[1], sha_pad->sha_pad1, sizeof(sha_pad->sha_pad1));
+- setup_sg(&sg[2], state->session_key, state->keylen);
+- setup_sg(&sg[3], sha_pad->sha_pad2, sizeof(sha_pad->sha_pad2));
++ nbytes = setup_sg(&sg[0], state->master_key, state->keylen);
++ nbytes += setup_sg(&sg[1], sha_pad->sha_pad1,
++ sizeof(sha_pad->sha_pad1));
++ nbytes += setup_sg(&sg[2], state->session_key, state->keylen);
++ nbytes += setup_sg(&sg[3], sha_pad->sha_pad2,
++ sizeof(sha_pad->sha_pad2));
+
+- crypto_digest_digest (state->sha1, sg, 4, state->sha1_digest);
++ desc.tfm = state->sha1;
++ desc.flags = 0;
++
++ crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);
+
+ memcpy(InterimKey, state->sha1_digest, state->keylen);
+ }
+@@ -156,14 +165,15 @@ static void mppe_rekey(struct ppp_mppe_s
+ {
+ unsigned char InterimKey[MPPE_MAX_KEY_LEN];
+ struct scatterlist sg_in[1], sg_out[1];
++ struct blkcipher_desc desc = { .tfm = state->arc4 };
+
+ get_new_key_from_sha(state, InterimKey);
+ if (!initial_key) {
+- crypto_cipher_setkey(state->arc4, InterimKey, state->keylen);
++ crypto_blkcipher_setkey(state->arc4, InterimKey, state->keylen);
+ setup_sg(sg_in, InterimKey, state->keylen);
+ setup_sg(sg_out, state->session_key, state->keylen);
+- if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in,
+- state->keylen) != 0) {
++ if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
++ state->keylen) != 0) {
+ printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
+ }
+ } else {
+@@ -175,7 +185,7 @@ static void mppe_rekey(struct ppp_mppe_s
+ state->session_key[1] = 0x26;
+ state->session_key[2] = 0x9e;
+ }
+- crypto_cipher_setkey(state->arc4, state->session_key, state->keylen);
++ crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen);
+ }
+
+ /*
+@@ -196,15 +206,19 @@ static void *mppe_alloc(unsigned char *o
+
+ memset(state, 0, sizeof(*state));
+
+- state->arc4 = crypto_alloc_tfm("arc4", 0);
+- if (!state->arc4)
++ state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(state->arc4)) {
++ state->arc4 = NULL;
+ goto out_free;
++ }
+
+- state->sha1 = crypto_alloc_tfm("sha1", 0);
+- if (!state->sha1)
++ state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(state->sha1)) {
++ state->sha1 = NULL;
+ goto out_free;
++ }
+
+- digestsize = crypto_tfm_alg_digestsize(state->sha1);
++ digestsize = crypto_hash_digestsize(state->sha1);
+ if (digestsize < MPPE_MAX_KEY_LEN)
+ goto out_free;
+
+@@ -229,9 +243,9 @@ static void *mppe_alloc(unsigned char *o
+ if (state->sha1_digest)
+ kfree(state->sha1_digest);
+ if (state->sha1)
+- crypto_free_tfm(state->sha1);
++ crypto_free_hash(state->sha1);
+ if (state->arc4)
+- crypto_free_tfm(state->arc4);
++ crypto_free_blkcipher(state->arc4);
+ kfree(state);
+ out:
+ return NULL;
+@@ -247,9 +261,9 @@ static void mppe_free(void *arg)
+ if (state->sha1_digest)
+ kfree(state->sha1_digest);
+ if (state->sha1)
+- crypto_free_tfm(state->sha1);
++ crypto_free_hash(state->sha1);
+ if (state->arc4)
+- crypto_free_tfm(state->arc4);
++ crypto_free_blkcipher(state->arc4);
+ kfree(state);
+ }
+ }
+@@ -356,6 +370,7 @@ mppe_compress(void *arg, unsigned char *
+ int isize, int osize)
+ {
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
++ struct blkcipher_desc desc = { .tfm = state->arc4 };
+ int proto;
+ struct scatterlist sg_in[1], sg_out[1];
+
+@@ -413,7 +428,7 @@ mppe_compress(void *arg, unsigned char *
+ /* Encrypt packet */
+ setup_sg(sg_in, ibuf, isize);
+ setup_sg(sg_out, obuf, osize);
+- if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in, isize) != 0) {
++ if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) {
+ printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
+ return -1;
+ }
+@@ -462,6 +477,7 @@ mppe_decompress(void *arg, unsigned char
+ int osize)
+ {
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
++ struct blkcipher_desc desc = { .tfm = state->arc4 };
+ unsigned ccount;
+ int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
+ int sanity = 0;
+@@ -599,7 +615,7 @@ mppe_decompress(void *arg, unsigned char
+ */
+ setup_sg(sg_in, ibuf, 1);
+ setup_sg(sg_out, obuf, 1);
+- if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) {
++ if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) {
+ printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+ return DECOMP_ERROR;
+ }
+@@ -619,7 +635,7 @@ mppe_decompress(void *arg, unsigned char
+ /* And finally, decrypt the rest of the packet. */
+ setup_sg(sg_in, ibuf + 1, isize - 1);
+ setup_sg(sg_out, obuf + 1, osize - 1);
+- if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, isize - 1) != 0) {
++ if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) {
+ printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+ return DECOMP_ERROR;
+ }
+@@ -694,8 +710,8 @@ static struct compressor ppp_mppe = {
+ static int __init ppp_mppe_init(void)
+ {
+ int answer;
+- if (!(crypto_alg_available("arc4", 0) &&
+- crypto_alg_available("sha1", 0)))
++ if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) &&
++ crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC)))
+ return -ENODEV;
+
+ sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
+diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
+index 33255fe..b6f0e9a 100644
+--- a/drivers/net/ppp_synctty.c
++++ b/drivers/net/ppp_synctty.c
+@@ -6,7 +6,7 @@
+ *
+ * Complete PPP frames without encoding/decoding are exchanged between
+ * the channel driver and the device driver.
+- *
++ *
+ * The async map IOCTL codes are implemented to keep the user mode
+ * applications happy if they call them. Synchronous PPP does not use
+ * the async maps.
+diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
+index 0d101a1..0adee73 100644
+--- a/drivers/net/pppoe.c
++++ b/drivers/net/pppoe.c
+@@ -386,13 +386,13 @@ static int pppoe_rcv(struct sk_buff *skb
+ if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ goto drop;
+
+- if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
++ if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+ goto out;
+
+ ph = (struct pppoe_hdr *) skb->nh.raw;
+
+ po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source);
+- if (po != NULL)
++ if (po != NULL)
+ return sk_receive_skb(sk_pppox(po), skb);
+ drop:
+ kfree_skb(skb);
+@@ -418,7 +418,7 @@ static int pppoe_disc_rcv(struct sk_buff
+ if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ goto abort;
+
+- if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
++ if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+ goto out;
+
+ ph = (struct pppoe_hdr *) skb->nh.raw;
+@@ -600,6 +600,7 @@ static int pppoe_connect(struct socket *
+ po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
+ dev->hard_header_len);
+
++ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);
+ po->chan.private = sk;
+ po->chan.ops = &pppoe_chan_ops;
+
+@@ -745,7 +746,7 @@ static int pppoe_ioctl(struct socket *so
+ }
+
+
+-static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
++static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *m, size_t total_len)
+ {
+ struct sk_buff *skb = NULL;
+@@ -907,8 +908,8 @@ static int pppoe_xmit(struct ppp_channel
+ }
+
+
+-static struct ppp_channel_ops pppoe_chan_ops = {
+- .start_xmit = pppoe_xmit,
++static struct ppp_channel_ops pppoe_chan_ops = {
++ .start_xmit = pppoe_xmit,
+ };
+
+ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
+@@ -1010,7 +1011,7 @@ static void *pppoe_seq_next(struct seq_f
+ goto out;
+ }
+ po = v;
+- if (po->next)
++ if (po->next)
+ po = po->next;
+ else {
+ int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+@@ -1106,7 +1107,7 @@ static int __init pppoe_init(void)
+ err = pppoe_proc_init();
+ if (err)
+ goto out_unregister_pppox_proto;
+-
++
+ dev_add_pack(&pppoes_ptype);
+ dev_add_pack(&pppoed_ptype);
+ register_netdevice_notifier(&pppoe_notifier);
+diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
+new file mode 100644
+index 0000000..ec640f6
+--- /dev/null
++++ b/drivers/net/qla3xxx.c
+@@ -0,0 +1,3536 @@
++/*
++ * QLogic QLA3xxx NIC HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla3xxx for copyright and licensing details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/dma-mapping.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/dmapool.h>
++#include <linux/mempool.h>
++#include <linux/spinlock.h>
++#include <linux/kthread.h>
++#include <linux/interrupt.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/ip.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_vlan.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/mm.h>
++
++#include "qla3xxx.h"
++
++#define DRV_NAME "qla3xxx"
++#define DRV_STRING "QLogic ISP3XXX Network Driver"
++#define DRV_VERSION "v2.02.00-k36"
++#define PFX DRV_NAME " "
++
++static const char ql3xxx_driver_name[] = DRV_NAME;
++static const char ql3xxx_driver_version[] = DRV_VERSION;
++
++MODULE_AUTHOR("QLogic Corporation");
++MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " ");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++static const u32 default_msg
++ = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
++ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
++
++static int debug = -1; /* defaults above */
++module_param(debug, int, 0);
++MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
++
++static int msi;
++module_param(msi, int, 0);
++MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
++
++static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
++ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
++ /* required last entry */
++ {0,}
++};
++
++MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
++
++/*
++ * Caller must take hw_lock.
++ */
++static int ql_sem_spinlock(struct ql3_adapter *qdev,
++ u32 sem_mask, u32 sem_bits)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ u32 value;
++ unsigned int seconds = 3;
++
++ do {
++ writel((sem_mask | sem_bits),
++ &port_regs->CommonRegs.semaphoreReg);
++ value = readl(&port_regs->CommonRegs.semaphoreReg);
++ if ((value & (sem_mask >> 16)) == sem_bits)
++ return 0;
++ ssleep(1);
++ } while(--seconds);
++ return -1;
++}
++
++static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ writel(sem_mask, &port_regs->CommonRegs.semaphoreReg);
++ readl(&port_regs->CommonRegs.semaphoreReg);
++}
++
++static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ u32 value;
++
++ writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg);
++ value = readl(&port_regs->CommonRegs.semaphoreReg);
++ return ((value & (sem_mask >> 16)) == sem_bits);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
++{
++ int i = 0;
++
++ while (1) {
++ if (!ql_sem_lock(qdev,
++ QL_DRVR_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
++ * 2) << 1)) {
++ if (i < 10) {
++ ssleep(1);
++ i++;
++ } else {
++ printk(KERN_ERR PFX "%s: Timed out waiting for "
++ "driver lock...\n",
++ qdev->ndev->name);
++ return 0;
++ }
++ } else {
++ printk(KERN_DEBUG PFX
++ "%s: driver lock acquired.\n",
++ qdev->ndev->name);
++ return 1;
++ }
++ }
++}
++
++static void ql_set_register_page(struct ql3_adapter *qdev, u32 page)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++
++ writel(((ISP_CONTROL_NP_MASK << 16) | page),
++ &port_regs->CommonRegs.ispControlStatus);
++ readl(&port_regs->CommonRegs.ispControlStatus);
++ qdev->current_page = page;
++}
++
++static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,
++ u32 __iomem * reg)
++{
++ u32 value;
++ unsigned long hw_flags;
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ value = readl(reg);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++
++ return value;
++}
++
++static u32 ql_read_common_reg(struct ql3_adapter *qdev,
++ u32 __iomem * reg)
++{
++ return readl(reg);
++}
++
++static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
++{
++ u32 value;
++ unsigned long hw_flags;
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++
++ if (qdev->current_page != 0)
++ ql_set_register_page(qdev,0);
++ value = readl(reg);
++
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return value;
++}
++
++static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
++{
++ if (qdev->current_page != 0)
++ ql_set_register_page(qdev,0);
++ return readl(reg);
++}
++
++static void ql_write_common_reg_l(struct ql3_adapter *qdev,
++ u32 __iomem *reg, u32 value)
++{
++ unsigned long hw_flags;
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ writel(value, reg);
++ readl(reg);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return;
++}
++
++static void ql_write_common_reg(struct ql3_adapter *qdev,
++ u32 __iomem *reg, u32 value)
++{
++ writel(value, reg);
++ readl(reg);
++ return;
++}
++
++static void ql_write_page0_reg(struct ql3_adapter *qdev,
++ u32 __iomem *reg, u32 value)
++{
++ if (qdev->current_page != 0)
++ ql_set_register_page(qdev,0);
++ writel(value, reg);
++ readl(reg);
++ return;
++}
++
++/*
++ * Caller holds hw_lock. Only called during init.
++ */
++static void ql_write_page1_reg(struct ql3_adapter *qdev,
++ u32 __iomem *reg, u32 value)
++{
++ if (qdev->current_page != 1)
++ ql_set_register_page(qdev,1);
++ writel(value, reg);
++ readl(reg);
++ return;
++}
++
++/*
++ * Caller holds hw_lock. Only called during init.
++ */
++static void ql_write_page2_reg(struct ql3_adapter *qdev,
++ u32 __iomem *reg, u32 value)
++{
++ if (qdev->current_page != 2)
++ ql_set_register_page(qdev,2);
++ writel(value, reg);
++ readl(reg);
++ return;
++}
++
++static void ql_disable_interrupts(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++
++ ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
++ (ISP_IMR_ENABLE_INT << 16));
++
++}
++
++static void ql_enable_interrupts(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++
++ ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
++ ((0xff << 16) | ISP_IMR_ENABLE_INT));
++
++}
++
++static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
++ struct ql_rcv_buf_cb *lrg_buf_cb)
++{
++ u64 map;
++ lrg_buf_cb->next = NULL;
++
++ if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */
++ qdev->lrg_buf_free_head = qdev->lrg_buf_free_tail = lrg_buf_cb;
++ } else {
++ qdev->lrg_buf_free_tail->next = lrg_buf_cb;
++ qdev->lrg_buf_free_tail = lrg_buf_cb;
++ }
++
++ if (!lrg_buf_cb->skb) {
++ lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
++ if (unlikely(!lrg_buf_cb->skb)) {
++ printk(KERN_ERR PFX "%s: failed dev_alloc_skb().\n",
++ qdev->ndev->name);
++ qdev->lrg_buf_skb_check++;
++ } else {
++ /*
++ * We save some space to copy the ethhdr from first
++ * buffer
++ */
++ skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
++ map = pci_map_single(qdev->pdev,
++ lrg_buf_cb->skb->data,
++ qdev->lrg_buffer_len -
++ QL_HEADER_SPACE,
++ PCI_DMA_FROMDEVICE);
++ lrg_buf_cb->buf_phy_addr_low =
++ cpu_to_le32(LS_64BITS(map));
++ lrg_buf_cb->buf_phy_addr_high =
++ cpu_to_le32(MS_64BITS(map));
++ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
++ pci_unmap_len_set(lrg_buf_cb, maplen,
++ qdev->lrg_buffer_len -
++ QL_HEADER_SPACE);
++ }
++ }
++
++ qdev->lrg_buf_free_count++;
++}
++
++static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter
++ *qdev)
++{
++ struct ql_rcv_buf_cb *lrg_buf_cb;
++
++ if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) {
++ if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL)
++ qdev->lrg_buf_free_tail = NULL;
++ qdev->lrg_buf_free_count--;
++ }
++
++ return lrg_buf_cb;
++}
++
++static u32 addrBits = EEPROM_NO_ADDR_BITS;
++static u32 dataBits = EEPROM_NO_DATA_BITS;
++
++static void fm93c56a_deselect(struct ql3_adapter *qdev);
++static void eeprom_readword(struct ql3_adapter *qdev, u32 eepromAddr,
++ unsigned short *value);
++
++/*
++ * Caller holds hw_lock.
++ */
++static void fm93c56a_select(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
++{
++ int i;
++ u32 mask;
++ u32 dataBit;
++ u32 previousBit;
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ /* Clock in a zero, then do the start bit */
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
++ AUBURN_EEPROM_DO_1);
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
++ AUBURN_EEPROM_CLK_RISE);
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
++ AUBURN_EEPROM_CLK_FALL);
++
++ mask = 1 << (FM93C56A_CMD_BITS - 1);
++ /* Force the previous data bit to be different */
++ previousBit = 0xffff;
++ for (i = 0; i < FM93C56A_CMD_BITS; i++) {
++ dataBit =
++ (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
++ if (previousBit != dataBit) {
++ /*
++ * If the bit changed, then change the DO state to
++ * match
++ */
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | dataBit);
++ previousBit = dataBit;
++ }
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_RISE);
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_FALL);
++ cmd = cmd << 1;
++ }
++
++ mask = 1 << (addrBits - 1);
++ /* Force the previous data bit to be different */
++ previousBit = 0xffff;
++ for (i = 0; i < addrBits; i++) {
++ dataBit =
++ (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 :
++ AUBURN_EEPROM_DO_0;
++ if (previousBit != dataBit) {
++ /*
++ * If the bit changed, then change the DO state to
++ * match
++ */
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | dataBit);
++ previousBit = dataBit;
++ }
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_RISE);
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->
++ eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_FALL);
++ eepromAddr = eepromAddr << 1;
++ }
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void fm93c56a_deselect(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value)
++{
++ int i;
++ u32 data = 0;
++ u32 dataBit;
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ /* Read the data bits */
++ /* The first bit is a dummy. Clock right over it. */
++ for (i = 0; i < dataBits; i++) {
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
++ AUBURN_EEPROM_CLK_RISE);
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg,
++ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
++ AUBURN_EEPROM_CLK_FALL);
++ dataBit =
++ (ql_read_common_reg
++ (qdev,
++ &port_regs->CommonRegs.
++ serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0;
++ data = (data << 1) | dataBit;
++ }
++ *value = (u16) data;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void eeprom_readword(struct ql3_adapter *qdev,
++ u32 eepromAddr, unsigned short *value)
++{
++ fm93c56a_select(qdev);
++ fm93c56a_cmd(qdev, (int)FM93C56A_READ, eepromAddr);
++ fm93c56a_datain(qdev, value);
++ fm93c56a_deselect(qdev);
++}
++
++static void ql_swap_mac_addr(u8 * macAddress)
++{
++#ifdef __BIG_ENDIAN
++ u8 temp;
++ temp = macAddress[0];
++ macAddress[0] = macAddress[1];
++ macAddress[1] = temp;
++ temp = macAddress[2];
++ macAddress[2] = macAddress[3];
++ macAddress[3] = temp;
++ temp = macAddress[4];
++ macAddress[4] = macAddress[5];
++ macAddress[5] = temp;
++#endif
++}
++
++static int ql_get_nvram_params(struct ql3_adapter *qdev)
++{
++ u16 *pEEPROMData;
++ u16 checksum = 0;
++ u32 index;
++ unsigned long hw_flags;
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++
++ pEEPROMData = (u16 *) & qdev->nvram_data;
++ qdev->eeprom_cmd_data = 0;
++ if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 10)) {
++ printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n",
++ __func__);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return -1;
++ }
++
++ for (index = 0; index < EEPROM_SIZE; index++) {
++ eeprom_readword(qdev, index, pEEPROMData);
++ checksum += *pEEPROMData;
++ pEEPROMData++;
++ }
++ ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK);
++
++ if (checksum != 0) {
++ printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n",
++ qdev->ndev->name, checksum);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return -1;
++ }
++
++ /*
++ * We have a problem with endianness for the MAC addresses
++ * and the two 8-bit values version, and numPorts. We
++ * have to swap them on big endian systems.
++ */
++ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress);
++ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress);
++ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress);
++ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress);
++ pEEPROMData = (u16 *) & qdev->nvram_data.version;
++ *pEEPROMData = le16_to_cpu(*pEEPROMData);
++
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return checksum;
++}
++
++static const u32 PHYAddr[2] = {
++ PORT0_PHY_ADDRESS, PORT1_PHY_ADDRESS
++};
++
++static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 temp;
++ int count = 1000;
++
++ while (count) {
++ temp = ql_read_page0_reg(qdev, &port_regs->macMIIStatusReg);
++ if (!(temp & MAC_MII_STATUS_BSY))
++ return 0;
++ udelay(10);
++ count--;
++ }
++ return -1;
++}
++
++static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 scanControl;
++
++ if (qdev->numPorts > 1) {
++ /* Auto scan will cycle through multiple ports */
++ scanControl = MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC;
++ } else {
++ scanControl = MAC_MII_CONTROL_SC;
++ }
++
++ /*
++ * Scan register 1 of PHY/PETBI,
++ * Set up to scan both devices
++ * The autoscan starts from the first register, completes
++ * the last one before rolling over to the first
++ */
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
++ PHYAddr[0] | MII_SCAN_REGISTER);
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ (scanControl) |
++ ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS) << 16));
++}
++
++static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
++{
++ u8 ret;
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ /* See if scan mode is enabled before we turn it off */
++ if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) &
++ (MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC)) {
++ /* Scan is enabled */
++ ret = 1;
++ } else {
++ /* Scan is disabled */
++ ret = 0;
++ }
++
++ /*
++ * When disabling scan mode you must first change the MII register
++ * address
++ */
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
++ PHYAddr[0] | MII_SCAN_REGISTER);
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS |
++ MAC_MII_CONTROL_RC) << 16));
++
++ return ret;
++}
++
++static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
++ u16 regAddr, u16 value, u32 mac_index)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u8 scanWasEnabled;
++
++ scanWasEnabled = ql_mii_disable_scan_mode(qdev);
++
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s Timed out waiting for management port to "
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
++ PHYAddr[mac_index] | regAddr);
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
++
++ /* Wait for write to complete 9/10/04 SJP */
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to"
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ if (scanWasEnabled)
++ ql_mii_enable_scan_mode(qdev);
++
++ return 0;
++}
++
++static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
++ u16 * value, u32 mac_index)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u8 scanWasEnabled;
++ u32 temp;
++
++ scanWasEnabled = ql_mii_disable_scan_mode(qdev);
++
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to "
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
++ PHYAddr[mac_index] | regAddr);
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ (MAC_MII_CONTROL_RC << 16));
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
++
++ /* Wait for the read to complete */
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to "
++ "get free after issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
++ *value = (u16) temp;
++
++ if (scanWasEnabled)
++ ql_mii_enable_scan_mode(qdev);
++
++ return 0;
++}
++
++static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ ql_mii_disable_scan_mode(qdev);
++
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to "
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
++ qdev->PHYAddr | regAddr);
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
++
++ /* Wait for write to complete. */
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to "
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ ql_mii_enable_scan_mode(qdev);
++
++ return 0;
++}
++
++static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value)
++{
++ u32 temp;
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ ql_mii_disable_scan_mode(qdev);
++
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to "
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
++ qdev->PHYAddr | regAddr);
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ (MAC_MII_CONTROL_RC << 16));
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
++
++ /* Wait for the read to complete */
++ if (ql_wait_for_mii_ready(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Timed out waiting for management port to "
++ "get free before issuing command.\n",
++ qdev->ndev->name);
++ return -1;
++ }
++
++ temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
++ *value = (u16) temp;
++
++ ql_mii_enable_scan_mode(qdev);
++
++ return 0;
++}
++
++static void ql_petbi_reset(struct ql3_adapter *qdev)
++{
++ ql_mii_write_reg(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET);
++}
++
++static void ql_petbi_start_neg(struct ql3_adapter *qdev)
++{
++ u16 reg;
++
++ /* Enable Auto-negotiation sense */
++ ql_mii_read_reg(qdev, PETBI_TBI_CTRL, ®);
++ reg |= PETBI_TBI_AUTO_SENSE;
++ ql_mii_write_reg(qdev, PETBI_TBI_CTRL, reg);
++
++ ql_mii_write_reg(qdev, PETBI_NEG_ADVER,
++ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX);
++
++ ql_mii_write_reg(qdev, PETBI_CONTROL_REG,
++ PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
++ PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000);
++
++}
++
++static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
++{
++ ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
++ mac_index);
++}
++
++static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
++{
++ u16 reg;
++
++ /* Enable Auto-negotiation sense */
++ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, mac_index);
++ reg |= PETBI_TBI_AUTO_SENSE;
++ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
++
++ ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
++ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
++
++ ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
++ PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
++ PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
++ mac_index);
++}
++
++static void ql_petbi_init(struct ql3_adapter *qdev)
++{
++ ql_petbi_reset(qdev);
++ ql_petbi_start_neg(qdev);
++}
++
++static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
++{
++ ql_petbi_reset_ex(qdev, mac_index);
++ ql_petbi_start_neg_ex(qdev, mac_index);
++}
++
++static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
++{
++ u16 reg;
++
++ if (ql_mii_read_reg(qdev, PETBI_NEG_PARTNER, ®) < 0)
++ return 0;
++
++ return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
++}
++
++static int ql_phy_get_speed(struct ql3_adapter *qdev)
++{
++ u16 reg;
++
++ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0)
++ return 0;
++
++ reg = (((reg & 0x18) >> 3) & 3);
++
++ if (reg == 2)
++ return SPEED_1000;
++ else if (reg == 1)
++ return SPEED_100;
++ else if (reg == 0)
++ return SPEED_10;
++ else
++ return -1;
++}
++
++static int ql_is_full_dup(struct ql3_adapter *qdev)
++{
++ u16 reg;
++
++ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0)
++ return 0;
++
++ return (reg & PHY_AUX_DUPLEX_STAT) != 0;
++}
++
++static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
++{
++ u16 reg;
++
++ if (ql_mii_read_reg(qdev, PHY_NEG_PARTNER, ®) < 0)
++ return 0;
++
++ return (reg & PHY_NEG_PAUSE) != 0;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 value;
++
++ if (enable)
++ value = (MAC_CONFIG_REG_PE | (MAC_CONFIG_REG_PE << 16));
++ else
++ value = (MAC_CONFIG_REG_PE << 16);
++
++ if (qdev->mac_index)
++ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
++ else
++ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 value;
++
++ if (enable)
++ value = (MAC_CONFIG_REG_SR | (MAC_CONFIG_REG_SR << 16));
++ else
++ value = (MAC_CONFIG_REG_SR << 16);
++
++ if (qdev->mac_index)
++ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
++ else
++ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 value;
++
++ if (enable)
++ value = (MAC_CONFIG_REG_GM | (MAC_CONFIG_REG_GM << 16));
++ else
++ value = (MAC_CONFIG_REG_GM << 16);
++
++ if (qdev->mac_index)
++ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
++ else
++ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 value;
++
++ if (enable)
++ value = (MAC_CONFIG_REG_FD | (MAC_CONFIG_REG_FD << 16));
++ else
++ value = (MAC_CONFIG_REG_FD << 16);
++
++ if (qdev->mac_index)
++ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
++ else
++ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 value;
++
++ if (enable)
++ value =
++ ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) |
++ ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16));
++ else
++ value = ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16);
++
++ if (qdev->mac_index)
++ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
++ else
++ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_is_fiber(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 bitToCheck = 0;
++ u32 temp;
++
++ switch (qdev->mac_index) {
++ case 0:
++ bitToCheck = PORT_STATUS_SM0;
++ break;
++ case 1:
++ bitToCheck = PORT_STATUS_SM1;
++ break;
++ }
++
++ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ return (temp & bitToCheck) != 0;
++}
++
++static int ql_is_auto_cfg(struct ql3_adapter *qdev)
++{
++ u16 reg;
++ ql_mii_read_reg(qdev, 0x00, ®);
++ return (reg & 0x1000) != 0;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 bitToCheck = 0;
++ u32 temp;
++
++ switch (qdev->mac_index) {
++ case 0:
++ bitToCheck = PORT_STATUS_AC0;
++ break;
++ case 1:
++ bitToCheck = PORT_STATUS_AC1;
++ break;
++ }
++
++ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ if (temp & bitToCheck) {
++ if (netif_msg_link(qdev))
++ printk(KERN_INFO PFX
++ "%s: Auto-Negotiate complete.\n",
++ qdev->ndev->name);
++ return 1;
++ } else {
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Auto-Negotiate incomplete.\n",
++ qdev->ndev->name);
++ return 0;
++ }
++}
++
++/*
++ * ql_is_neg_pause() returns 1 if pause was negotiated to be on
++ */
++static int ql_is_neg_pause(struct ql3_adapter *qdev)
++{
++ if (ql_is_fiber(qdev))
++ return ql_is_petbi_neg_pause(qdev);
++ else
++ return ql_is_phy_neg_pause(qdev);
++}
++
++static int ql_auto_neg_error(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 bitToCheck = 0;
++ u32 temp;
++
++ switch (qdev->mac_index) {
++ case 0:
++ bitToCheck = PORT_STATUS_AE0;
++ break;
++ case 1:
++ bitToCheck = PORT_STATUS_AE1;
++ break;
++ }
++ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ return (temp & bitToCheck) != 0;
++}
++
++static u32 ql_get_link_speed(struct ql3_adapter *qdev)
++{
++ if (ql_is_fiber(qdev))
++ return SPEED_1000;
++ else
++ return ql_phy_get_speed(qdev);
++}
++
++static int ql_is_link_full_dup(struct ql3_adapter *qdev)
++{
++ if (ql_is_fiber(qdev))
++ return 1;
++ else
++ return ql_is_full_dup(qdev);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_link_down_detect(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 bitToCheck = 0;
++ u32 temp;
++
++ switch (qdev->mac_index) {
++ case 0:
++ bitToCheck = ISP_CONTROL_LINK_DN_0;
++ break;
++ case 1:
++ bitToCheck = ISP_CONTROL_LINK_DN_1;
++ break;
++ }
++
++ temp =
++ ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
++ return (temp & bitToCheck) != 0;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ switch (qdev->mac_index) {
++ case 0:
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.ispControlStatus,
++ (ISP_CONTROL_LINK_DN_0) |
++ (ISP_CONTROL_LINK_DN_0 << 16));
++ break;
++
++ case 1:
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.ispControlStatus,
++ (ISP_CONTROL_LINK_DN_1) |
++ (ISP_CONTROL_LINK_DN_1 << 16));
++ break;
++
++ default:
++ return 1;
++ }
++
++ return 0;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
++ u32 mac_index)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 bitToCheck = 0;
++ u32 temp;
++
++ switch (mac_index) {
++ case 0:
++ bitToCheck = PORT_STATUS_F1_ENABLED;
++ break;
++ case 1:
++ bitToCheck = PORT_STATUS_F3_ENABLED;
++ break;
++ default:
++ break;
++ }
++
++ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ if (temp & bitToCheck) {
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: is not link master.\n", qdev->ndev->name);
++ return 0;
++ } else {
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: is link master.\n", qdev->ndev->name);
++ return 1;
++ }
++}
++
++static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
++{
++ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
++}
++
++static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
++{
++ u16 reg;
++
++ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
++ PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
++
++ ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, mac_index);
++ ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
++ mac_index);
++}
++
++static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
++{
++ ql_phy_reset_ex(qdev, mac_index);
++ ql_phy_start_neg_ex(qdev, mac_index);
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static u32 ql_get_link_state(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ u32 bitToCheck = 0;
++ u32 temp, linkState;
++
++ switch (qdev->mac_index) {
++ case 0:
++ bitToCheck = PORT_STATUS_UP0;
++ break;
++ case 1:
++ bitToCheck = PORT_STATUS_UP1;
++ break;
++ }
++ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ if (temp & bitToCheck) {
++ linkState = LS_UP;
++ } else {
++ linkState = LS_DOWN;
++ if (netif_msg_link(qdev))
++ printk(KERN_WARNING PFX
++ "%s: Link is down.\n", qdev->ndev->name);
++ }
++ return linkState;
++}
++
++static int ql_port_start(struct ql3_adapter *qdev)
++{
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7))
++ return -1;
++
++ if (ql_is_fiber(qdev)) {
++ ql_petbi_init(qdev);
++ } else {
++ /* Copper port */
++ ql_phy_init_ex(qdev, qdev->mac_index);
++ }
++
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ return 0;
++}
++
++static int ql_finish_auto_neg(struct ql3_adapter *qdev)
++{
++
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7))
++ return -1;
++
++ if (!ql_auto_neg_error(qdev)) {
++ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
++ /* configure the MAC */
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: Configuring link.\n",
++ qdev->ndev->
++ name);
++ ql_mac_cfg_soft_reset(qdev, 1);
++ ql_mac_cfg_gig(qdev,
++ (ql_get_link_speed
++ (qdev) ==
++ SPEED_1000));
++ ql_mac_cfg_full_dup(qdev,
++ ql_is_link_full_dup
++ (qdev));
++ ql_mac_cfg_pause(qdev,
++ ql_is_neg_pause
++ (qdev));
++ ql_mac_cfg_soft_reset(qdev, 0);
++
++ /* enable the MAC */
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: Enabling mac.\n",
++ qdev->ndev->
++ name);
++ ql_mac_enable(qdev, 1);
++ }
++
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: Change port_link_state LS_DOWN to LS_UP.\n",
++ qdev->ndev->name);
++ qdev->port_link_state = LS_UP;
++ netif_start_queue(qdev->ndev);
++ netif_carrier_on(qdev->ndev);
++ if (netif_msg_link(qdev))
++ printk(KERN_INFO PFX
++ "%s: Link is up at %d Mbps, %s duplex.\n",
++ qdev->ndev->name,
++ ql_get_link_speed(qdev),
++ ql_is_link_full_dup(qdev)
++ ? "full" : "half");
++
++ } else { /* Remote error detected */
++
++ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: Remote error detected. "
++ "Calling ql_port_start().\n",
++ qdev->ndev->
++ name);
++ /*
++ * ql_port_start() is shared code and needs
++ * to lock the PHY on it's own.
++ */
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ if(ql_port_start(qdev)) {/* Restart port */
++ return -1;
++ } else
++ return 0;
++ }
++ }
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ return 0;
++}
++
++static void ql_link_state_machine(struct ql3_adapter *qdev)
++{
++ u32 curr_link_state;
++ unsigned long hw_flags;
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++
++ curr_link_state = ql_get_link_state(qdev);
++
++ if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_INFO PFX
++ "%s: Reset in progress, skip processing link "
++ "state.\n", qdev->ndev->name);
++ return;
++ }
++
++ switch (qdev->port_link_state) {
++ default:
++ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
++ ql_port_start(qdev);
++ }
++ qdev->port_link_state = LS_DOWN;
++ /* Fall Through */
++
++ case LS_DOWN:
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: port_link_state = LS_DOWN.\n",
++ qdev->ndev->name);
++ if (curr_link_state == LS_UP) {
++ if (netif_msg_link(qdev))
++ printk(KERN_DEBUG PFX
++ "%s: curr_link_state = LS_UP.\n",
++ qdev->ndev->name);
++ if (ql_is_auto_neg_complete(qdev))
++ ql_finish_auto_neg(qdev);
++
++ if (qdev->port_link_state == LS_UP)
++ ql_link_down_detect_clear(qdev);
++
++ }
++ break;
++
++ case LS_UP:
++ /*
++ * See if the link is currently down or went down and came
++ * back up
++ */
++ if ((curr_link_state == LS_DOWN) || ql_link_down_detect(qdev)) {
++ if (netif_msg_link(qdev))
++ printk(KERN_INFO PFX "%s: Link is down.\n",
++ qdev->ndev->name);
++ qdev->port_link_state = LS_DOWN;
++ }
++ break;
++ }
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++}
++
++/*
++ * Caller must take hw_lock and QL_PHY_GIO_SEM.
++ */
++static void ql_get_phy_owner(struct ql3_adapter *qdev)
++{
++ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
++ set_bit(QL_LINK_MASTER,&qdev->flags);
++ else
++ clear_bit(QL_LINK_MASTER,&qdev->flags);
++}
++
++/*
++ * Caller must take hw_lock and QL_PHY_GIO_SEM.
++ */
++static void ql_init_scan_mode(struct ql3_adapter *qdev)
++{
++ ql_mii_enable_scan_mode(qdev);
++
++ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
++ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
++ ql_petbi_init_ex(qdev, qdev->mac_index);
++ } else {
++ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
++ ql_phy_init_ex(qdev, qdev->mac_index);
++ }
++}
++
++/*
++ * MII_Setup needs to be called before taking the PHY out of reset so that the
++ * management interface clock speed can be set properly. It would be better if
++ * we had a way to disable MDC until after the PHY is out of reset, but we
++ * don't have that capability.
++ */
++static int ql_mii_setup(struct ql3_adapter *qdev)
++{
++ u32 reg;
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7))
++ return -1;
++
++ /* Divide 125MHz clock by 28 to meet PHY timing requirements */
++ reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
++
++ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
++ reg | ((MAC_MII_CONTROL_CLK_SEL_MASK) << 16));
++
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ return 0;
++}
++
++static u32 ql_supported_modes(struct ql3_adapter *qdev)
++{
++ u32 supported;
++
++ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
++ supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
++ | SUPPORTED_Autoneg;
++ } else {
++ supported = SUPPORTED_10baseT_Half
++ | SUPPORTED_10baseT_Full
++ | SUPPORTED_100baseT_Half
++ | SUPPORTED_100baseT_Full
++ | SUPPORTED_1000baseT_Half
++ | SUPPORTED_1000baseT_Full
++ | SUPPORTED_Autoneg | SUPPORTED_TP;
++ }
++
++ return supported;
++}
++
++static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
++{
++ int status;
++ unsigned long hw_flags;
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7))
++ return 0;
++ status = ql_is_auto_cfg(qdev);
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return status;
++}
++
++static u32 ql_get_speed(struct ql3_adapter *qdev)
++{
++ u32 status;
++ unsigned long hw_flags;
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7))
++ return 0;
++ status = ql_get_link_speed(qdev);
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return status;
++}
++
++static int ql_get_full_dup(struct ql3_adapter *qdev)
++{
++ int status;
++ unsigned long hw_flags;
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7))
++ return 0;
++ status = ql_is_link_full_dup(qdev);
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ return status;
++}
++
++
++static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++
++ ecmd->transceiver = XCVR_INTERNAL;
++ ecmd->supported = ql_supported_modes(qdev);
++
++ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
++ ecmd->port = PORT_FIBRE;
++ } else {
++ ecmd->port = PORT_TP;
++ ecmd->phy_address = qdev->PHYAddr;
++ }
++ ecmd->advertising = ql_supported_modes(qdev);
++ ecmd->autoneg = ql_get_auto_cfg_status(qdev);
++ ecmd->speed = ql_get_speed(qdev);
++ ecmd->duplex = ql_get_full_dup(qdev);
++ return 0;
++}
++
++static void ql_get_drvinfo(struct net_device *ndev,
++ struct ethtool_drvinfo *drvinfo)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ strncpy(drvinfo->driver, ql3xxx_driver_name, 32);
++ strncpy(drvinfo->version, ql3xxx_driver_version, 32);
++ strncpy(drvinfo->fw_version, "N/A", 32);
++ strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
++ drvinfo->n_stats = 0;
++ drvinfo->testinfo_len = 0;
++ drvinfo->regdump_len = 0;
++ drvinfo->eedump_len = 0;
++}
++
++static u32 ql_get_msglevel(struct net_device *ndev)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ return qdev->msg_enable;
++}
++
++static void ql_set_msglevel(struct net_device *ndev, u32 value)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ qdev->msg_enable = value;
++}
++
++static const struct ethtool_ops ql3xxx_ethtool_ops = {
++ .get_settings = ql_get_settings,
++ .get_drvinfo = ql_get_drvinfo,
++ .get_perm_addr = ethtool_op_get_perm_addr,
++ .get_link = ethtool_op_get_link,
++ .get_msglevel = ql_get_msglevel,
++ .set_msglevel = ql_set_msglevel,
++};
++
++static int ql_populate_free_queue(struct ql3_adapter *qdev)
++{
++ struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
++ u64 map;
++
++ while (lrg_buf_cb) {
++ if (!lrg_buf_cb->skb) {
++ lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
++ if (unlikely(!lrg_buf_cb->skb)) {
++ printk(KERN_DEBUG PFX
++ "%s: Failed dev_alloc_skb().\n",
++ qdev->ndev->name);
++ break;
++ } else {
++ /*
++ * We save some space to copy the ethhdr from
++ * first buffer
++ */
++ skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
++ map = pci_map_single(qdev->pdev,
++ lrg_buf_cb->skb->data,
++ qdev->lrg_buffer_len -
++ QL_HEADER_SPACE,
++ PCI_DMA_FROMDEVICE);
++ lrg_buf_cb->buf_phy_addr_low =
++ cpu_to_le32(LS_64BITS(map));
++ lrg_buf_cb->buf_phy_addr_high =
++ cpu_to_le32(MS_64BITS(map));
++ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
++ pci_unmap_len_set(lrg_buf_cb, maplen,
++ qdev->lrg_buffer_len -
++ QL_HEADER_SPACE);
++ --qdev->lrg_buf_skb_check;
++ if (!qdev->lrg_buf_skb_check)
++ return 1;
++ }
++ }
++ lrg_buf_cb = lrg_buf_cb->next;
++ }
++ return 0;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
++{
++ struct bufq_addr_element *lrg_buf_q_ele;
++ int i;
++ struct ql_rcv_buf_cb *lrg_buf_cb;
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++
++ if ((qdev->lrg_buf_free_count >= 8)
++ && (qdev->lrg_buf_release_cnt >= 16)) {
++
++ if (qdev->lrg_buf_skb_check)
++ if (!ql_populate_free_queue(qdev))
++ return;
++
++ lrg_buf_q_ele = qdev->lrg_buf_next_free;
++
++ while ((qdev->lrg_buf_release_cnt >= 16)
++ && (qdev->lrg_buf_free_count >= 8)) {
++
++ for (i = 0; i < 8; i++) {
++ lrg_buf_cb =
++ ql_get_from_lrg_buf_free_list(qdev);
++ lrg_buf_q_ele->addr_high =
++ lrg_buf_cb->buf_phy_addr_high;
++ lrg_buf_q_ele->addr_low =
++ lrg_buf_cb->buf_phy_addr_low;
++ lrg_buf_q_ele++;
++
++ qdev->lrg_buf_release_cnt--;
++ }
++
++ qdev->lrg_buf_q_producer_index++;
++
++ if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES)
++ qdev->lrg_buf_q_producer_index = 0;
++
++ if (qdev->lrg_buf_q_producer_index ==
++ (NUM_LBUFQ_ENTRIES - 1)) {
++ lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr;
++ }
++ }
++
++ qdev->lrg_buf_next_free = lrg_buf_q_ele;
++
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ rxLargeQProducerIndex,
++ qdev->lrg_buf_q_producer_index);
++ }
++}
++
++static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
++ struct ob_mac_iocb_rsp *mac_rsp)
++{
++ struct ql_tx_buf_cb *tx_cb;
++
++ tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
++ pci_unmap_single(qdev->pdev,
++ pci_unmap_addr(tx_cb, mapaddr),
++ pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
++ dev_kfree_skb_irq(tx_cb->skb);
++ qdev->stats.tx_packets++;
++ qdev->stats.tx_bytes += tx_cb->skb->len;
++ tx_cb->skb = NULL;
++ atomic_inc(&qdev->tx_count);
++}
++
++static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
++ struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
++{
++ long int offset;
++ u32 lrg_buf_phy_addr_low = 0;
++ struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
++ struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
++ u32 *curr_ial_ptr;
++ struct sk_buff *skb;
++ u16 length = le16_to_cpu(ib_mac_rsp_ptr->length);
++
++ /*
++ * Get the inbound address list (small buffer).
++ */
++ offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
++ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
++ qdev->small_buf_index = 0;
++
++ curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
++ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
++ qdev->small_buf_release_cnt++;
++
++ /* start of first buffer */
++ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
++ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
++ qdev->lrg_buf_release_cnt++;
++ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
++ qdev->lrg_buf_index = 0;
++ curr_ial_ptr++; /* 64-bit pointers require two incs. */
++ curr_ial_ptr++;
++
++ /* start of second buffer */
++ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
++ lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
++
++ /*
++ * Second buffer gets sent up the stack.
++ */
++ qdev->lrg_buf_release_cnt++;
++ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
++ qdev->lrg_buf_index = 0;
++ skb = lrg_buf_cb2->skb;
++
++ qdev->stats.rx_packets++;
++ qdev->stats.rx_bytes += length;
++
++ skb_put(skb, length);
++ pci_unmap_single(qdev->pdev,
++ pci_unmap_addr(lrg_buf_cb2, mapaddr),
++ pci_unmap_len(lrg_buf_cb2, maplen),
++ PCI_DMA_FROMDEVICE);
++ prefetch(skb->data);
++ skb->dev = qdev->ndev;
++ skb->ip_summed = CHECKSUM_NONE;
++ skb->protocol = eth_type_trans(skb, qdev->ndev);
++
++ netif_receive_skb(skb);
++ qdev->ndev->last_rx = jiffies;
++ lrg_buf_cb2->skb = NULL;
++
++ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
++ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
++}
++
++static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
++ struct ib_ip_iocb_rsp *ib_ip_rsp_ptr)
++{
++ long int offset;
++ u32 lrg_buf_phy_addr_low = 0;
++ struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
++ struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
++ u32 *curr_ial_ptr;
++ struct sk_buff *skb1, *skb2;
++ struct net_device *ndev = qdev->ndev;
++ u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
++ u16 size = 0;
++
++ /*
++ * Get the inbound address list (small buffer).
++ */
++
++ offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
++ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
++ qdev->small_buf_index = 0;
++ curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
++ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
++ qdev->small_buf_release_cnt++;
++
++ /* start of first buffer */
++ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
++ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
++
++ qdev->lrg_buf_release_cnt++;
++ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
++ qdev->lrg_buf_index = 0;
++ skb1 = lrg_buf_cb1->skb;
++ curr_ial_ptr++; /* 64-bit pointers require two incs. */
++ curr_ial_ptr++;
++
++ /* start of second buffer */
++ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
++ lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
++ skb2 = lrg_buf_cb2->skb;
++ qdev->lrg_buf_release_cnt++;
++ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
++ qdev->lrg_buf_index = 0;
++
++ qdev->stats.rx_packets++;
++ qdev->stats.rx_bytes += length;
++
++ /*
++ * Copy the ethhdr from first buffer to second. This
++ * is necessary for IP completions.
++ */
++ if (*((u16 *) skb1->data) != 0xFFFF)
++ size = VLAN_ETH_HLEN;
++ else
++ size = ETH_HLEN;
++
++ skb_put(skb2, length); /* Just the second buffer length here. */
++ pci_unmap_single(qdev->pdev,
++ pci_unmap_addr(lrg_buf_cb2, mapaddr),
++ pci_unmap_len(lrg_buf_cb2, maplen),
++ PCI_DMA_FROMDEVICE);
++ prefetch(skb2->data);
++
++ memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
++ skb2->dev = qdev->ndev;
++ skb2->ip_summed = CHECKSUM_NONE;
++ skb2->protocol = eth_type_trans(skb2, qdev->ndev);
++
++ netif_receive_skb(skb2);
++ ndev->last_rx = jiffies;
++ lrg_buf_cb2->skb = NULL;
++
++ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
++ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
++}
++
++static int ql_tx_rx_clean(struct ql3_adapter *qdev,
++ int *tx_cleaned, int *rx_cleaned, int work_to_do)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ struct net_rsp_iocb *net_rsp;
++ struct net_device *ndev = qdev->ndev;
++ unsigned long hw_flags;
++
++ /* While there are entries in the completion queue. */
++ while ((cpu_to_le32(*(qdev->prsp_producer_index)) !=
++ qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) {
++
++ net_rsp = qdev->rsp_current;
++ switch (net_rsp->opcode) {
++
++ case OPCODE_OB_MAC_IOCB_FN0:
++ case OPCODE_OB_MAC_IOCB_FN2:
++ ql_process_mac_tx_intr(qdev, (struct ob_mac_iocb_rsp *)
++ net_rsp);
++ (*tx_cleaned)++;
++ break;
++
++ case OPCODE_IB_MAC_IOCB:
++ ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
++ net_rsp);
++ (*rx_cleaned)++;
++ break;
++
++ case OPCODE_IB_IP_IOCB:
++ ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
++ net_rsp);
++ (*rx_cleaned)++;
++ break;
++ default:
++ {
++ u32 *tmp = (u32 *) net_rsp;
++ printk(KERN_ERR PFX
++ "%s: Hit default case, not "
++ "handled!\n"
++ " dropping the packet, opcode = "
++ "%x.\n",
++ ndev->name, net_rsp->opcode);
++ printk(KERN_ERR PFX
++ "0x%08lx 0x%08lx 0x%08lx 0x%08lx \n",
++ (unsigned long int)tmp[0],
++ (unsigned long int)tmp[1],
++ (unsigned long int)tmp[2],
++ (unsigned long int)tmp[3]);
++ }
++ }
++
++ qdev->rsp_consumer_index++;
++
++ if (qdev->rsp_consumer_index == NUM_RSP_Q_ENTRIES) {
++ qdev->rsp_consumer_index = 0;
++ qdev->rsp_current = qdev->rsp_q_virt_addr;
++ } else {
++ qdev->rsp_current++;
++ }
++ }
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++
++ ql_update_lrg_bufq_prod_index(qdev);
++
++ if (qdev->small_buf_release_cnt >= 16) {
++ while (qdev->small_buf_release_cnt >= 16) {
++ qdev->small_buf_q_producer_index++;
++
++ if (qdev->small_buf_q_producer_index ==
++ NUM_SBUFQ_ENTRIES)
++ qdev->small_buf_q_producer_index = 0;
++ qdev->small_buf_release_cnt -= 8;
++ }
++
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ rxSmallQProducerIndex,
++ qdev->small_buf_q_producer_index);
++ }
++
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.rspQConsumerIndex,
++ qdev->rsp_consumer_index);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++
++ if (unlikely(netif_queue_stopped(qdev->ndev))) {
++ if (netif_queue_stopped(qdev->ndev) &&
++ (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4)))
++ netif_wake_queue(qdev->ndev);
++ }
++
++ return *tx_cleaned + *rx_cleaned;
++}
++
++static int ql_poll(struct net_device *ndev, int *budget)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ int work_to_do = min(*budget, ndev->quota);
++ int rx_cleaned = 0, tx_cleaned = 0;
++
++ if (!netif_carrier_ok(ndev))
++ goto quit_polling;
++
++ ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
++ *budget -= rx_cleaned;
++ ndev->quota -= rx_cleaned;
++
++ if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) {
++quit_polling:
++ netif_rx_complete(ndev);
++ ql_enable_interrupts(qdev);
++ return 0;
++ }
++ return 1;
++}
++
++static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
++{
++
++ struct net_device *ndev = dev_id;
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ u32 value;
++ int handled = 1;
++ u32 var;
++
++ port_regs = qdev->mem_map_registers;
++
++ value =
++ ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
++
++ if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) {
++ spin_lock(&qdev->adapter_lock);
++ netif_stop_queue(qdev->ndev);
++ netif_carrier_off(qdev->ndev);
++ ql_disable_interrupts(qdev);
++ qdev->port_link_state = LS_DOWN;
++ set_bit(QL_RESET_ACTIVE,&qdev->flags) ;
++
++ if (value & ISP_CONTROL_FE) {
++ /*
++ * Chip Fatal Error.
++ */
++ var =
++ ql_read_page0_reg_l(qdev,
++ &port_regs->PortFatalErrStatus);
++ printk(KERN_WARNING PFX
++ "%s: Resetting chip. PortFatalErrStatus "
++ "register = 0x%x\n", ndev->name, var);
++ set_bit(QL_RESET_START,&qdev->flags) ;
++ } else {
++ /*
++ * Soft Reset Requested.
++ */
++ set_bit(QL_RESET_PER_SCSI,&qdev->flags) ;
++ printk(KERN_ERR PFX
++ "%s: Another function issued a reset to the "
++ "chip. ISR value = %x.\n", ndev->name, value);
++ }
++ queue_work(qdev->workqueue, &qdev->reset_work);
++ spin_unlock(&qdev->adapter_lock);
++ } else if (value & ISP_IMR_DISABLE_CMPL_INT) {
++ ql_disable_interrupts(qdev);
++ if (likely(netif_rx_schedule_prep(ndev)))
++ __netif_rx_schedule(ndev);
++ else
++ ql_enable_interrupts(qdev);
++ } else {
++ return IRQ_NONE;
++ }
++
++ return IRQ_RETVAL(handled);
++}
++
++static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
++{
++ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ struct ql_tx_buf_cb *tx_cb;
++ struct ob_mac_iocb_req *mac_iocb_ptr;
++ u64 map;
++
++ if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
++ if (!netif_queue_stopped(ndev))
++ netif_stop_queue(ndev);
++ return NETDEV_TX_BUSY;
++ }
++ tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
++ mac_iocb_ptr = tx_cb->queue_entry;
++ memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
++ mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
++ mac_iocb_ptr->flags |= qdev->mb_bit_mask;
++ mac_iocb_ptr->transaction_id = qdev->req_producer_index;
++ mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
++ tx_cb->skb = skb;
++ map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
++ mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
++ mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
++ mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
++ pci_unmap_addr_set(tx_cb, mapaddr, map);
++ pci_unmap_len_set(tx_cb, maplen, skb->len);
++ atomic_dec(&qdev->tx_count);
++
++ qdev->req_producer_index++;
++ if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
++ qdev->req_producer_index = 0;
++ wmb();
++ ql_write_common_reg_l(qdev,
++ &port_regs->CommonRegs.reqQProducerIndex,
++ qdev->req_producer_index);
++
++ ndev->trans_start = jiffies;
++ if (netif_msg_tx_queued(qdev))
++ printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
++ ndev->name, qdev->req_producer_index, skb->len);
++
++ return NETDEV_TX_OK;
++}
++static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
++{
++ qdev->req_q_size =
++ (u32) (NUM_REQ_Q_ENTRIES * sizeof(struct ob_mac_iocb_req));
++
++ qdev->req_q_virt_addr =
++ pci_alloc_consistent(qdev->pdev,
++ (size_t) qdev->req_q_size,
++ &qdev->req_q_phy_addr);
++
++ if ((qdev->req_q_virt_addr == NULL) ||
++ LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
++ printk(KERN_ERR PFX "%s: reqQ failed.\n",
++ qdev->ndev->name);
++ return -ENOMEM;
++ }
++
++ qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb);
++
++ qdev->rsp_q_virt_addr =
++ pci_alloc_consistent(qdev->pdev,
++ (size_t) qdev->rsp_q_size,
++ &qdev->rsp_q_phy_addr);
++
++ if ((qdev->rsp_q_virt_addr == NULL) ||
++ LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
++ printk(KERN_ERR PFX
++ "%s: rspQ allocation failed\n",
++ qdev->ndev->name);
++ pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
++ qdev->req_q_virt_addr,
++ qdev->req_q_phy_addr);
++ return -ENOMEM;
++ }
++
++ set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
++
++ return 0;
++}
++
++static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
++{
++ if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) {
++ printk(KERN_INFO PFX
++ "%s: Already done.\n", qdev->ndev->name);
++ return;
++ }
++
++ pci_free_consistent(qdev->pdev,
++ qdev->req_q_size,
++ qdev->req_q_virt_addr, qdev->req_q_phy_addr);
++
++ qdev->req_q_virt_addr = NULL;
++
++ pci_free_consistent(qdev->pdev,
++ qdev->rsp_q_size,
++ qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr);
++
++ qdev->rsp_q_virt_addr = NULL;
++
++ clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
++}
++
++static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
++{
++ /* Create Large Buffer Queue */
++ qdev->lrg_buf_q_size =
++ NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
++ if (qdev->lrg_buf_q_size < PAGE_SIZE)
++ qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
++ else
++ qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
++
++ qdev->lrg_buf_q_alloc_virt_addr =
++ pci_alloc_consistent(qdev->pdev,
++ qdev->lrg_buf_q_alloc_size,
++ &qdev->lrg_buf_q_alloc_phy_addr);
++
++ if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
++ printk(KERN_ERR PFX
++ "%s: lBufQ failed\n", qdev->ndev->name);
++ return -ENOMEM;
++ }
++ qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
++ qdev->lrg_buf_q_phy_addr = qdev->lrg_buf_q_alloc_phy_addr;
++
++ /* Create Small Buffer Queue */
++ qdev->small_buf_q_size =
++ NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
++ if (qdev->small_buf_q_size < PAGE_SIZE)
++ qdev->small_buf_q_alloc_size = PAGE_SIZE;
++ else
++ qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
++
++ qdev->small_buf_q_alloc_virt_addr =
++ pci_alloc_consistent(qdev->pdev,
++ qdev->small_buf_q_alloc_size,
++ &qdev->small_buf_q_alloc_phy_addr);
++
++ if (qdev->small_buf_q_alloc_virt_addr == NULL) {
++ printk(KERN_ERR PFX
++ "%s: Small Buffer Queue allocation failed.\n",
++ qdev->ndev->name);
++ pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
++ qdev->lrg_buf_q_alloc_virt_addr,
++ qdev->lrg_buf_q_alloc_phy_addr);
++ return -ENOMEM;
++ }
++
++ qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr;
++ qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr;
++ set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
++ return 0;
++}
++
++static void ql_free_buffer_queues(struct ql3_adapter *qdev)
++{
++ if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) {
++ printk(KERN_INFO PFX
++ "%s: Already done.\n", qdev->ndev->name);
++ return;
++ }
++
++ pci_free_consistent(qdev->pdev,
++ qdev->lrg_buf_q_alloc_size,
++ qdev->lrg_buf_q_alloc_virt_addr,
++ qdev->lrg_buf_q_alloc_phy_addr);
++
++ qdev->lrg_buf_q_virt_addr = NULL;
++
++ pci_free_consistent(qdev->pdev,
++ qdev->small_buf_q_alloc_size,
++ qdev->small_buf_q_alloc_virt_addr,
++ qdev->small_buf_q_alloc_phy_addr);
++
++ qdev->small_buf_q_virt_addr = NULL;
++
++ clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
++}
++
++static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
++{
++ int i;
++ struct bufq_addr_element *small_buf_q_entry;
++
++ /* Currently we allocate on one of memory and use it for smallbuffers */
++ qdev->small_buf_total_size =
++ (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
++ QL_SMALL_BUFFER_SIZE);
++
++ qdev->small_buf_virt_addr =
++ pci_alloc_consistent(qdev->pdev,
++ qdev->small_buf_total_size,
++ &qdev->small_buf_phy_addr);
++
++ if (qdev->small_buf_virt_addr == NULL) {
++ printk(KERN_ERR PFX
++ "%s: Failed to get small buffer memory.\n",
++ qdev->ndev->name);
++ return -ENOMEM;
++ }
++
++ qdev->small_buf_phy_addr_low = LS_64BITS(qdev->small_buf_phy_addr);
++ qdev->small_buf_phy_addr_high = MS_64BITS(qdev->small_buf_phy_addr);
++
++ small_buf_q_entry = qdev->small_buf_q_virt_addr;
++
++ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low;
++
++ /* Initialize the small buffer queue. */
++ for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) {
++ small_buf_q_entry->addr_high =
++ cpu_to_le32(qdev->small_buf_phy_addr_high);
++ small_buf_q_entry->addr_low =
++ cpu_to_le32(qdev->small_buf_phy_addr_low +
++ (i * QL_SMALL_BUFFER_SIZE));
++ small_buf_q_entry++;
++ }
++ qdev->small_buf_index = 0;
++ set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags);
++ return 0;
++}
++
++static void ql_free_small_buffers(struct ql3_adapter *qdev)
++{
++ if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) {
++ printk(KERN_INFO PFX
++ "%s: Already done.\n", qdev->ndev->name);
++ return;
++ }
++ if (qdev->small_buf_virt_addr != NULL) {
++ pci_free_consistent(qdev->pdev,
++ qdev->small_buf_total_size,
++ qdev->small_buf_virt_addr,
++ qdev->small_buf_phy_addr);
++
++ qdev->small_buf_virt_addr = NULL;
++ }
++}
++
++static void ql_free_large_buffers(struct ql3_adapter *qdev)
++{
++ int i = 0;
++ struct ql_rcv_buf_cb *lrg_buf_cb;
++
++ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
++ lrg_buf_cb = &qdev->lrg_buf[i];
++ if (lrg_buf_cb->skb) {
++ dev_kfree_skb(lrg_buf_cb->skb);
++ pci_unmap_single(qdev->pdev,
++ pci_unmap_addr(lrg_buf_cb, mapaddr),
++ pci_unmap_len(lrg_buf_cb, maplen),
++ PCI_DMA_FROMDEVICE);
++ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
++ } else {
++ break;
++ }
++ }
++}
++
++static void ql_init_large_buffers(struct ql3_adapter *qdev)
++{
++ int i;
++ struct ql_rcv_buf_cb *lrg_buf_cb;
++ struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr;
++
++ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
++ lrg_buf_cb = &qdev->lrg_buf[i];
++ buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high;
++ buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low;
++ buf_addr_ele++;
++ }
++ qdev->lrg_buf_index = 0;
++ qdev->lrg_buf_skb_check = 0;
++}
++
++static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
++{
++ int i;
++ struct ql_rcv_buf_cb *lrg_buf_cb;
++ struct sk_buff *skb;
++ u64 map;
++
++ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
++ skb = dev_alloc_skb(qdev->lrg_buffer_len);
++ if (unlikely(!skb)) {
++ /* Better luck next round */
++ printk(KERN_ERR PFX
++ "%s: large buff alloc failed, "
++ "for %d bytes at index %d.\n",
++ qdev->ndev->name,
++ qdev->lrg_buffer_len * 2, i);
++ ql_free_large_buffers(qdev);
++ return -ENOMEM;
++ } else {
++
++ lrg_buf_cb = &qdev->lrg_buf[i];
++ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
++ lrg_buf_cb->index = i;
++ lrg_buf_cb->skb = skb;
++ /*
++ * We save some space to copy the ethhdr from first
++ * buffer
++ */
++ skb_reserve(skb, QL_HEADER_SPACE);
++ map = pci_map_single(qdev->pdev,
++ skb->data,
++ qdev->lrg_buffer_len -
++ QL_HEADER_SPACE,
++ PCI_DMA_FROMDEVICE);
++ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
++ pci_unmap_len_set(lrg_buf_cb, maplen,
++ qdev->lrg_buffer_len -
++ QL_HEADER_SPACE);
++ lrg_buf_cb->buf_phy_addr_low =
++ cpu_to_le32(LS_64BITS(map));
++ lrg_buf_cb->buf_phy_addr_high =
++ cpu_to_le32(MS_64BITS(map));
++ }
++ }
++ return 0;
++}
++
++static void ql_create_send_free_list(struct ql3_adapter *qdev)
++{
++ struct ql_tx_buf_cb *tx_cb;
++ int i;
++ struct ob_mac_iocb_req *req_q_curr =
++ qdev->req_q_virt_addr;
++
++ /* Create free list of transmit buffers */
++ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
++ tx_cb = &qdev->tx_buf[i];
++ tx_cb->skb = NULL;
++ tx_cb->queue_entry = req_q_curr;
++ req_q_curr++;
++ }
++}
++
++static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
++{
++ if (qdev->ndev->mtu == NORMAL_MTU_SIZE)
++ qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
++ else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
++ qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
++ } else {
++ printk(KERN_ERR PFX
++ "%s: Invalid mtu size. Only 1500 and 9000 are accepted.\n",
++ qdev->ndev->name);
++ return -ENOMEM;
++ }
++ qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
++ qdev->max_frame_size =
++ (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
++
++ /*
++ * First allocate a page of shared memory and use it for shadow
++ * locations of Network Request Queue Consumer Address Register and
++ * Network Completion Queue Producer Index Register
++ */
++ qdev->shadow_reg_virt_addr =
++ pci_alloc_consistent(qdev->pdev,
++ PAGE_SIZE, &qdev->shadow_reg_phy_addr);
++
++ if (qdev->shadow_reg_virt_addr != NULL) {
++ qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr;
++ qdev->req_consumer_index_phy_addr_high =
++ MS_64BITS(qdev->shadow_reg_phy_addr);
++ qdev->req_consumer_index_phy_addr_low =
++ LS_64BITS(qdev->shadow_reg_phy_addr);
++
++ qdev->prsp_producer_index =
++ (u32 *) (((u8 *) qdev->preq_consumer_index) + 8);
++ qdev->rsp_producer_index_phy_addr_high =
++ qdev->req_consumer_index_phy_addr_high;
++ qdev->rsp_producer_index_phy_addr_low =
++ qdev->req_consumer_index_phy_addr_low + 8;
++ } else {
++ printk(KERN_ERR PFX
++ "%s: shadowReg Alloc failed.\n", qdev->ndev->name);
++ return -ENOMEM;
++ }
++
++ if (ql_alloc_net_req_rsp_queues(qdev) != 0) {
++ printk(KERN_ERR PFX
++ "%s: ql_alloc_net_req_rsp_queues failed.\n",
++ qdev->ndev->name);
++ goto err_req_rsp;
++ }
++
++ if (ql_alloc_buffer_queues(qdev) != 0) {
++ printk(KERN_ERR PFX
++ "%s: ql_alloc_buffer_queues failed.\n",
++ qdev->ndev->name);
++ goto err_buffer_queues;
++ }
++
++ if (ql_alloc_small_buffers(qdev) != 0) {
++ printk(KERN_ERR PFX
++ "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name);
++ goto err_small_buffers;
++ }
++
++ if (ql_alloc_large_buffers(qdev) != 0) {
++ printk(KERN_ERR PFX
++ "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name);
++ goto err_small_buffers;
++ }
++
++ /* Initialize the large buffer queue. */
++ ql_init_large_buffers(qdev);
++ ql_create_send_free_list(qdev);
++
++ qdev->rsp_current = qdev->rsp_q_virt_addr;
++
++ return 0;
++
++err_small_buffers:
++ ql_free_buffer_queues(qdev);
++err_buffer_queues:
++ ql_free_net_req_rsp_queues(qdev);
++err_req_rsp:
++ pci_free_consistent(qdev->pdev,
++ PAGE_SIZE,
++ qdev->shadow_reg_virt_addr,
++ qdev->shadow_reg_phy_addr);
++
++ return -ENOMEM;
++}
++
++static void ql_free_mem_resources(struct ql3_adapter *qdev)
++{
++ ql_free_large_buffers(qdev);
++ ql_free_small_buffers(qdev);
++ ql_free_buffer_queues(qdev);
++ ql_free_net_req_rsp_queues(qdev);
++ if (qdev->shadow_reg_virt_addr != NULL) {
++ pci_free_consistent(qdev->pdev,
++ PAGE_SIZE,
++ qdev->shadow_reg_virt_addr,
++ qdev->shadow_reg_phy_addr);
++ qdev->shadow_reg_virt_addr = NULL;
++ }
++}
++
++static int ql_init_misc_registers(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_local_ram_registers __iomem *local_ram =
++ (void __iomem *)qdev->mem_map_registers;
++
++ if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 4))
++ return -1;
++
++ ql_write_page2_reg(qdev,
++ &local_ram->bufletSize, qdev->nvram_data.bufletSize);
++
++ ql_write_page2_reg(qdev,
++ &local_ram->maxBufletCount,
++ qdev->nvram_data.bufletCount);
++
++ ql_write_page2_reg(qdev,
++ &local_ram->freeBufletThresholdLow,
++ (qdev->nvram_data.tcpWindowThreshold25 << 16) |
++ (qdev->nvram_data.tcpWindowThreshold0));
++
++ ql_write_page2_reg(qdev,
++ &local_ram->freeBufletThresholdHigh,
++ qdev->nvram_data.tcpWindowThreshold50);
++
++ ql_write_page2_reg(qdev,
++ &local_ram->ipHashTableBase,
++ (qdev->nvram_data.ipHashTableBaseHi << 16) |
++ qdev->nvram_data.ipHashTableBaseLo);
++ ql_write_page2_reg(qdev,
++ &local_ram->ipHashTableCount,
++ qdev->nvram_data.ipHashTableSize);
++ ql_write_page2_reg(qdev,
++ &local_ram->tcpHashTableBase,
++ (qdev->nvram_data.tcpHashTableBaseHi << 16) |
++ qdev->nvram_data.tcpHashTableBaseLo);
++ ql_write_page2_reg(qdev,
++ &local_ram->tcpHashTableCount,
++ qdev->nvram_data.tcpHashTableSize);
++ ql_write_page2_reg(qdev,
++ &local_ram->ncbBase,
++ (qdev->nvram_data.ncbTableBaseHi << 16) |
++ qdev->nvram_data.ncbTableBaseLo);
++ ql_write_page2_reg(qdev,
++ &local_ram->maxNcbCount,
++ qdev->nvram_data.ncbTableSize);
++ ql_write_page2_reg(qdev,
++ &local_ram->drbBase,
++ (qdev->nvram_data.drbTableBaseHi << 16) |
++ qdev->nvram_data.drbTableBaseLo);
++ ql_write_page2_reg(qdev,
++ &local_ram->maxDrbCount,
++ qdev->nvram_data.drbTableSize);
++ ql_sem_unlock(qdev, QL_DDR_RAM_SEM_MASK);
++ return 0;
++}
++
++static int ql_adapter_initialize(struct ql3_adapter *qdev)
++{
++ u32 value;
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ struct ql3xxx_host_memory_registers __iomem *hmem_regs =
++ (void __iomem *)port_regs;
++ u32 delay = 10;
++ int status = 0;
++
++ if(ql_mii_setup(qdev))
++ return -1;
++
++ /* Bring out PHY out of reset */
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ (ISP_SERIAL_PORT_IF_WE |
++ (ISP_SERIAL_PORT_IF_WE << 16)));
++
++ qdev->port_link_state = LS_DOWN;
++ netif_carrier_off(qdev->ndev);
++
++ /* V2 chip fix for ARS-39168. */
++ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
++ (ISP_SERIAL_PORT_IF_SDE |
++ (ISP_SERIAL_PORT_IF_SDE << 16)));
++
++ /* Request Queue Registers */
++ *((u32 *) (qdev->preq_consumer_index)) = 0;
++ atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES);
++ qdev->req_producer_index = 0;
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->reqConsumerIndexAddrHigh,
++ qdev->req_consumer_index_phy_addr_high);
++ ql_write_page1_reg(qdev,
++ &hmem_regs->reqConsumerIndexAddrLow,
++ qdev->req_consumer_index_phy_addr_low);
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->reqBaseAddrHigh,
++ MS_64BITS(qdev->req_q_phy_addr));
++ ql_write_page1_reg(qdev,
++ &hmem_regs->reqBaseAddrLow,
++ LS_64BITS(qdev->req_q_phy_addr));
++ ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES);
++
++ /* Response Queue Registers */
++ *((u16 *) (qdev->prsp_producer_index)) = 0;
++ qdev->rsp_consumer_index = 0;
++ qdev->rsp_current = qdev->rsp_q_virt_addr;
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rspProducerIndexAddrHigh,
++ qdev->rsp_producer_index_phy_addr_high);
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rspProducerIndexAddrLow,
++ qdev->rsp_producer_index_phy_addr_low);
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rspBaseAddrHigh,
++ MS_64BITS(qdev->rsp_q_phy_addr));
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rspBaseAddrLow,
++ LS_64BITS(qdev->rsp_q_phy_addr));
++
++ ql_write_page1_reg(qdev, &hmem_regs->rspLength, NUM_RSP_Q_ENTRIES);
++
++ /* Large Buffer Queue */
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rxLargeQBaseAddrHigh,
++ MS_64BITS(qdev->lrg_buf_q_phy_addr));
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rxLargeQBaseAddrLow,
++ LS_64BITS(qdev->lrg_buf_q_phy_addr));
++
++ ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES);
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rxLargeBufferLength,
++ qdev->lrg_buffer_len);
++
++ /* Small Buffer Queue */
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rxSmallQBaseAddrHigh,
++ MS_64BITS(qdev->small_buf_q_phy_addr));
++
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rxSmallQBaseAddrLow,
++ LS_64BITS(qdev->small_buf_q_phy_addr));
++
++ ql_write_page1_reg(qdev, &hmem_regs->rxSmallQLength, NUM_SBUFQ_ENTRIES);
++ ql_write_page1_reg(qdev,
++ &hmem_regs->rxSmallBufferLength,
++ QL_SMALL_BUFFER_SIZE);
++
++ qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1;
++ qdev->small_buf_release_cnt = 8;
++ qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1;
++ qdev->lrg_buf_release_cnt = 8;
++ qdev->lrg_buf_next_free =
++ (struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr;
++ qdev->small_buf_index = 0;
++ qdev->lrg_buf_index = 0;
++ qdev->lrg_buf_free_count = 0;
++ qdev->lrg_buf_free_head = NULL;
++ qdev->lrg_buf_free_tail = NULL;
++
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ rxSmallQProducerIndex,
++ qdev->small_buf_q_producer_index);
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ rxLargeQProducerIndex,
++ qdev->lrg_buf_q_producer_index);
++
++ /*
++ * Find out if the chip has already been initialized. If it has, then
++ * we skip some of the initialization.
++ */
++ clear_bit(QL_LINK_MASTER, &qdev->flags);
++ value = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ if ((value & PORT_STATUS_IC) == 0) {
++
++ /* Chip has not been configured yet, so let it rip. */
++ if(ql_init_misc_registers(qdev)) {
++ status = -1;
++ goto out;
++ }
++
++ if (qdev->mac_index)
++ ql_write_page0_reg(qdev,
++ &port_regs->mac1MaxFrameLengthReg,
++ qdev->max_frame_size);
++ else
++ ql_write_page0_reg(qdev,
++ &port_regs->mac0MaxFrameLengthReg,
++ qdev->max_frame_size);
++
++ value = qdev->nvram_data.tcpMaxWindowSize;
++ ql_write_page0_reg(qdev, &port_regs->tcpMaxWindow, value);
++
++ value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig;
++
++ if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
++ * 2) << 13)) {
++ status = -1;
++ goto out;
++ }
++ ql_write_page0_reg(qdev, &port_regs->ExternalHWConfig, value);
++ ql_write_page0_reg(qdev, &port_regs->InternalChipConfig,
++ (((INTERNAL_CHIP_SD | INTERNAL_CHIP_WE) <<
++ 16) | (INTERNAL_CHIP_SD |
++ INTERNAL_CHIP_WE)));
++ ql_sem_unlock(qdev, QL_FLASH_SEM_MASK);
++ }
++
++
++ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
++ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
++ 2) << 7)) {
++ status = -1;
++ goto out;
++ }
++
++ ql_init_scan_mode(qdev);
++ ql_get_phy_owner(qdev);
++
++ /* Load the MAC Configuration */
++
++ /* Program lower 32 bits of the MAC address */
++ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
++ (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
++ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
++ ((qdev->ndev->dev_addr[2] << 24)
++ | (qdev->ndev->dev_addr[3] << 16)
++ | (qdev->ndev->dev_addr[4] << 8)
++ | qdev->ndev->dev_addr[5]));
++
++ /* Program top 16 bits of the MAC address */
++ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
++ ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
++ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
++ ((qdev->ndev->dev_addr[0] << 8)
++ | qdev->ndev->dev_addr[1]));
++
++ /* Enable Primary MAC */
++ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
++ ((MAC_ADDR_INDIRECT_PTR_REG_PE << 16) |
++ MAC_ADDR_INDIRECT_PTR_REG_PE));
++
++ /* Clear Primary and Secondary IP addresses */
++ ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
++ ((IP_ADDR_INDEX_REG_MASK << 16) |
++ (qdev->mac_index << 2)));
++ ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
++
++ ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
++ ((IP_ADDR_INDEX_REG_MASK << 16) |
++ ((qdev->mac_index << 2) + 1)));
++ ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
++
++ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
++
++ /* Indicate Configuration Complete */
++ ql_write_page0_reg(qdev,
++ &port_regs->portControl,
++ ((PORT_CONTROL_CC << 16) | PORT_CONTROL_CC));
++
++ do {
++ value = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ if (value & PORT_STATUS_IC)
++ break;
++ msleep(500);
++ } while (--delay);
++
++ if (delay == 0) {
++ printk(KERN_ERR PFX
++ "%s: Hw Initialization timeout.\n", qdev->ndev->name);
++ status = -1;
++ goto out;
++ }
++
++ /* Enable Ethernet Function */
++ value =
++ (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
++ PORT_CONTROL_HH);
++ ql_write_page0_reg(qdev, &port_regs->portControl,
++ ((value << 16) | value));
++
++out:
++ return status;
++}
++
++/*
++ * Caller holds hw_lock.
++ */
++static int ql_adapter_reset(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ int status = 0;
++ u16 value;
++ int max_wait_time;
++
++ set_bit(QL_RESET_ACTIVE, &qdev->flags);
++ clear_bit(QL_RESET_DONE, &qdev->flags);
++
++ /*
++ * Issue soft reset to chip.
++ */
++ printk(KERN_DEBUG PFX
++ "%s: Issue soft reset to chip.\n",
++ qdev->ndev->name);
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.ispControlStatus,
++ ((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR));
++
++ /* Wait 3 seconds for reset to complete. */
++ printk(KERN_DEBUG PFX
++ "%s: Wait 10 milliseconds for reset to complete.\n",
++ qdev->ndev->name);
++
++ /* Wait until the firmware tells us the Soft Reset is done */
++ max_wait_time = 5;
++ do {
++ value =
++ ql_read_common_reg(qdev,
++ &port_regs->CommonRegs.ispControlStatus);
++ if ((value & ISP_CONTROL_SR) == 0)
++ break;
++
++ ssleep(1);
++ } while ((--max_wait_time));
++
++ /*
++ * Also, make sure that the Network Reset Interrupt bit has been
++ * cleared after the soft reset has taken place.
++ */
++ value =
++ ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
++ if (value & ISP_CONTROL_RI) {
++ printk(KERN_DEBUG PFX
++ "ql_adapter_reset: clearing RI after reset.\n");
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ ispControlStatus,
++ ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
++ }
++
++ if (max_wait_time == 0) {
++ /* Issue Force Soft Reset */
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ ispControlStatus,
++ ((ISP_CONTROL_FSR << 16) |
++ ISP_CONTROL_FSR));
++ /*
++ * Wait until the firmware tells us the Force Soft Reset is
++ * done
++ */
++ max_wait_time = 5;
++ do {
++ value =
++ ql_read_common_reg(qdev,
++ &port_regs->CommonRegs.
++ ispControlStatus);
++ if ((value & ISP_CONTROL_FSR) == 0) {
++ break;
++ }
++ ssleep(1);
++ } while ((--max_wait_time));
++ }
++ if (max_wait_time == 0)
++ status = 1;
++
++ clear_bit(QL_RESET_ACTIVE, &qdev->flags);
++ set_bit(QL_RESET_DONE, &qdev->flags);
++ return status;
++}
++
++static void ql_set_mac_info(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ u32 value, port_status;
++ u8 func_number;
++
++ /* Get the function number */
++ value =
++ ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
++ func_number = (u8) ((value >> 4) & OPCODE_FUNC_ID_MASK);
++ port_status = ql_read_page0_reg(qdev, &port_regs->portStatus);
++ switch (value & ISP_CONTROL_FN_MASK) {
++ case ISP_CONTROL_FN0_NET:
++ qdev->mac_index = 0;
++ qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
++ qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
++ qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
++ qdev->mb_bit_mask = FN0_MA_BITS_MASK;
++ qdev->PHYAddr = PORT0_PHY_ADDRESS;
++ if (port_status & PORT_STATUS_SM0)
++ set_bit(QL_LINK_OPTICAL,&qdev->flags);
++ else
++ clear_bit(QL_LINK_OPTICAL,&qdev->flags);
++ break;
++
++ case ISP_CONTROL_FN1_NET:
++ qdev->mac_index = 1;
++ qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
++ qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
++ qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
++ qdev->mb_bit_mask = FN1_MA_BITS_MASK;
++ qdev->PHYAddr = PORT1_PHY_ADDRESS;
++ if (port_status & PORT_STATUS_SM1)
++ set_bit(QL_LINK_OPTICAL,&qdev->flags);
++ else
++ clear_bit(QL_LINK_OPTICAL,&qdev->flags);
++ break;
++
++ case ISP_CONTROL_FN0_SCSI:
++ case ISP_CONTROL_FN1_SCSI:
++ default:
++ printk(KERN_DEBUG PFX
++ "%s: Invalid function number, ispControlStatus = 0x%x\n",
++ qdev->ndev->name,value);
++ break;
++ }
++ qdev->numPorts = qdev->nvram_data.numPorts;
++}
++
++static void ql_display_dev_info(struct net_device *ndev)
++{
++ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
++ struct pci_dev *pdev = qdev->pdev;
++
++ printk(KERN_INFO PFX
++ "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
++ DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
++ printk(KERN_INFO PFX
++ "%s Interface.\n",
++ test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
++
++ /*
++ * Print PCI bus width/type.
++ */
++ printk(KERN_INFO PFX
++ "Bus interface is %s %s.\n",
++ ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
++ ((qdev->pci_x) ? "PCI-X" : "PCI"));
++
++ printk(KERN_INFO PFX
++ "mem IO base address adjusted = 0x%p\n",
++ qdev->mem_map_registers);
++ printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq);
++
++ if (netif_msg_probe(qdev))
++ printk(KERN_INFO PFX
++ "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
++ ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
++ ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
++ ndev->dev_addr[5]);
++}
++
++static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
++{
++ struct net_device *ndev = qdev->ndev;
++ int retval = 0;
++
++ netif_stop_queue(ndev);
++ netif_carrier_off(ndev);
++
++ clear_bit(QL_ADAPTER_UP,&qdev->flags);
++ clear_bit(QL_LINK_MASTER,&qdev->flags);
++
++ ql_disable_interrupts(qdev);
++
++ free_irq(qdev->pdev->irq, ndev);
++
++ if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
++ printk(KERN_INFO PFX
++ "%s: calling pci_disable_msi().\n", qdev->ndev->name);
++ clear_bit(QL_MSI_ENABLED,&qdev->flags);
++ pci_disable_msi(qdev->pdev);
++ }
++
++ del_timer_sync(&qdev->adapter_timer);
++
++ netif_poll_disable(ndev);
++
++ if (do_reset) {
++ int soft_reset;
++ unsigned long hw_flags;
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ if (ql_wait_for_drvr_lock(qdev)) {
++ if ((soft_reset = ql_adapter_reset(qdev))) {
++ printk(KERN_ERR PFX
++ "%s: ql_adapter_reset(%d) FAILED!\n",
++ ndev->name, qdev->index);
++ }
++ printk(KERN_ERR PFX
++ "%s: Releaseing driver lock via chip reset.\n",ndev->name);
++ } else {
++ printk(KERN_ERR PFX
++ "%s: Could not acquire driver lock to do "
++ "reset!\n", ndev->name);
++ retval = -1;
++ }
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++ }
++ ql_free_mem_resources(qdev);
++ return retval;
++}
++
++static int ql_adapter_up(struct ql3_adapter *qdev)
++{
++ struct net_device *ndev = qdev->ndev;
++ int err;
++ unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ;
++ unsigned long hw_flags;
++
++ if (ql_alloc_mem_resources(qdev)) {
++ printk(KERN_ERR PFX
++ "%s Unable to allocate buffers.\n", ndev->name);
++ return -ENOMEM;
++ }
++
++ if (qdev->msi) {
++ if (pci_enable_msi(qdev->pdev)) {
++ printk(KERN_ERR PFX
++ "%s: User requested MSI, but MSI failed to "
++ "initialize. Continuing without MSI.\n",
++ qdev->ndev->name);
++ qdev->msi = 0;
++ } else {
++ printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
++ set_bit(QL_MSI_ENABLED,&qdev->flags);
++ irq_flags &= ~SA_SHIRQ;
++ }
++ }
++
++ if ((err = request_irq(qdev->pdev->irq,
++ ql3xxx_isr,
++ irq_flags, ndev->name, ndev))) {
++ printk(KERN_ERR PFX
++ "%s: Failed to reserve interrupt %d already in use.\n",
++ ndev->name, qdev->pdev->irq);
++ goto err_irq;
++ }
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++
++ if ((err = ql_wait_for_drvr_lock(qdev))) {
++ if ((err = ql_adapter_initialize(qdev))) {
++ printk(KERN_ERR PFX
++ "%s: Unable to initialize adapter.\n",
++ ndev->name);
++ goto err_init;
++ }
++ printk(KERN_ERR PFX
++ "%s: Releaseing driver lock.\n",ndev->name);
++ ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
++ } else {
++ printk(KERN_ERR PFX
++ "%s: Could not aquire driver lock.\n",
++ ndev->name);
++ goto err_lock;
++ }
++
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++
++ set_bit(QL_ADAPTER_UP,&qdev->flags);
++
++ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
++
++ netif_poll_enable(ndev);
++ ql_enable_interrupts(qdev);
++ return 0;
++
++err_init:
++ ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
++err_lock:
++ free_irq(qdev->pdev->irq, ndev);
++err_irq:
++ if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
++ printk(KERN_INFO PFX
++ "%s: calling pci_disable_msi().\n",
++ qdev->ndev->name);
++ clear_bit(QL_MSI_ENABLED,&qdev->flags);
++ pci_disable_msi(qdev->pdev);
++ }
++ return err;
++}
++
++static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
++{
++ if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) {
++ printk(KERN_ERR PFX
++ "%s: Driver up/down cycle failed, "
++ "closing device\n",qdev->ndev->name);
++ dev_close(qdev->ndev);
++ return -1;
++ }
++ return 0;
++}
++
++static int ql3xxx_close(struct net_device *ndev)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++
++ /*
++ * Wait for device to recover from a reset.
++ * (Rarely happens, but possible.)
++ */
++ while (!test_bit(QL_ADAPTER_UP,&qdev->flags))
++ msleep(50);
++
++ ql_adapter_down(qdev,QL_DO_RESET);
++ return 0;
++}
++
++static int ql3xxx_open(struct net_device *ndev)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ return (ql_adapter_up(qdev));
++}
++
++static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
++{
++ struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
++ return &qdev->stats;
++}
++
++static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu)
++{
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++ printk(KERN_ERR PFX "%s: new mtu size = %d.\n", ndev->name, new_mtu);
++ if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) {
++ printk(KERN_ERR PFX
++ "%s: mtu size of %d is not valid. Use exactly %d or "
++ "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE,
++ JUMBO_MTU_SIZE);
++ return -EINVAL;
++ }
++
++ if (!netif_running(ndev)) {
++ ndev->mtu = new_mtu;
++ return 0;
++ }
++
++ ndev->mtu = new_mtu;
++ return ql_cycle_adapter(qdev,QL_DO_RESET);
++}
++
++static void ql3xxx_set_multicast_list(struct net_device *ndev)
++{
++ /*
++ * We are manually parsing the list in the net_device structure.
++ */
++ return;
++}
++
++static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
++{
++ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
++ struct ql3xxx_port_registers __iomem *port_regs =
++ qdev->mem_map_registers;
++ struct sockaddr *addr = p;
++ unsigned long hw_flags;
++
++ if (netif_running(ndev))
++ return -EBUSY;
++
++ if (!is_valid_ether_addr(addr->sa_data))
++ return -EADDRNOTAVAIL;
++
++ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
++
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ /* Program lower 32 bits of the MAC address */
++ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
++ (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
++ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
++ ((ndev->dev_addr[2] << 24) | (ndev->
++ dev_addr[3] << 16) |
++ (ndev->dev_addr[4] << 8) | ndev->dev_addr[5]));
++
++ /* Program top 16 bits of the MAC address */
++ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
++ ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
++ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
++ ((ndev->dev_addr[0] << 8) | ndev->dev_addr[1]));
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++
++ return 0;
++}
++
++static void ql3xxx_tx_timeout(struct net_device *ndev)
++{
++ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
++
++ printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name);
++ /*
++ * Stop the queues, we've got a problem.
++ */
++ netif_stop_queue(ndev);
++
++ /*
++ * Wake up the worker to process this event.
++ */
++ queue_work(qdev->workqueue, &qdev->tx_timeout_work);
++}
++
++static void ql_reset_work(struct ql3_adapter *qdev)
++{
++ struct net_device *ndev = qdev->ndev;
++ u32 value;
++ struct ql_tx_buf_cb *tx_cb;
++ int max_wait_time, i;
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ unsigned long hw_flags;
++
++ if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) {
++ clear_bit(QL_LINK_MASTER,&qdev->flags);
++
++ /*
++ * Loop through the active list and return the skb.
++ */
++ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
++ tx_cb = &qdev->tx_buf[i];
++ if (tx_cb->skb) {
++
++ printk(KERN_DEBUG PFX
++ "%s: Freeing lost SKB.\n",
++ qdev->ndev->name);
++ pci_unmap_single(qdev->pdev,
++ pci_unmap_addr(tx_cb, mapaddr),
++ pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
++ dev_kfree_skb(tx_cb->skb);
++ tx_cb->skb = NULL;
++ }
++ }
++
++ printk(KERN_ERR PFX
++ "%s: Clearing NRI after reset.\n", qdev->ndev->name);
++ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
++ ql_write_common_reg(qdev,
++ &port_regs->CommonRegs.
++ ispControlStatus,
++ ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
++ /*
++ * Wait the for Soft Reset to Complete.
++ */
++ max_wait_time = 10;
++ do {
++ value = ql_read_common_reg(qdev,
++ &port_regs->CommonRegs.
++
++ ispControlStatus);
++ if ((value & ISP_CONTROL_SR) == 0) {
++ printk(KERN_DEBUG PFX
++ "%s: reset completed.\n",
++ qdev->ndev->name);
++ break;
++ }
++
++ if (value & ISP_CONTROL_RI) {
++ printk(KERN_DEBUG PFX
++ "%s: clearing NRI after reset.\n",
++ qdev->ndev->name);
++ ql_write_common_reg(qdev,
++ &port_regs->
++ CommonRegs.
++ ispControlStatus,
++ ((ISP_CONTROL_RI <<
++ 16) | ISP_CONTROL_RI));
++ }
++
++ ssleep(1);
++ } while (--max_wait_time);
++ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
++
++ if (value & ISP_CONTROL_SR) {
++
++ /*
++ * Set the reset flags and clear the board again.
++ * Nothing else to do...
++ */
++ printk(KERN_ERR PFX
++ "%s: Timed out waiting for reset to "
++ "complete.\n", ndev->name);
++ printk(KERN_ERR PFX
++ "%s: Do a reset.\n", ndev->name);
++ clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
++ clear_bit(QL_RESET_START,&qdev->flags);
++ ql_cycle_adapter(qdev,QL_DO_RESET);
++ return;
++ }
++
++ clear_bit(QL_RESET_ACTIVE,&qdev->flags);
++ clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
++ clear_bit(QL_RESET_START,&qdev->flags);
++ ql_cycle_adapter(qdev,QL_NO_RESET);
++ }
++}
++
++static void ql_tx_timeout_work(struct ql3_adapter *qdev)
++{
++ ql_cycle_adapter(qdev,QL_DO_RESET);
++}
++
++static void ql_get_board_info(struct ql3_adapter *qdev)
++{
++ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
++ u32 value;
++
++ value = ql_read_page0_reg_l(qdev, &port_regs->portStatus);
++
++ qdev->chip_rev_id = ((value & PORT_STATUS_REV_ID_MASK) >> 12);
++ if (value & PORT_STATUS_64)
++ qdev->pci_width = 64;
++ else
++ qdev->pci_width = 32;
++ if (value & PORT_STATUS_X)
++ qdev->pci_x = 1;
++ else
++ qdev->pci_x = 0;
++ qdev->pci_slot = (u8) PCI_SLOT(qdev->pdev->devfn);
++}
++
++static void ql3xxx_timer(unsigned long ptr)
++{
++ struct ql3_adapter *qdev = (struct ql3_adapter *)ptr;
++
++ if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
++ printk(KERN_DEBUG PFX
++ "%s: Reset in progress.\n",
++ qdev->ndev->name);
++ goto end;
++ }
++
++ ql_link_state_machine(qdev);
++
++ /* Restart timer on 2 second interval. */
++end:
++ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
++}
++
++static int __devinit ql3xxx_probe(struct pci_dev *pdev,
++ const struct pci_device_id *pci_entry)
++{
++ struct net_device *ndev = NULL;
++ struct ql3_adapter *qdev = NULL;
++ static int cards_found = 0;
++ int pci_using_dac, err;
++
++ err = pci_enable_device(pdev);
++ if (err) {
++ printk(KERN_ERR PFX "%s cannot enable PCI device\n",
++ pci_name(pdev));
++ goto err_out;
++ }
++
++ err = pci_request_regions(pdev, DRV_NAME);
++ if (err) {
++ printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
++ pci_name(pdev));
++ goto err_out_disable_pdev;
++ }
++
++ pci_set_master(pdev);
++
++ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
++ pci_using_dac = 1;
++ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
++ } else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
++ pci_using_dac = 0;
++ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ }
++
++ if (err) {
++ printk(KERN_ERR PFX "%s no usable DMA configuration\n",
++ pci_name(pdev));
++ goto err_out_free_regions;
++ }
++
++ ndev = alloc_etherdev(sizeof(struct ql3_adapter));
++ if (!ndev)
++ goto err_out_free_regions;
++
++ SET_MODULE_OWNER(ndev);
++ SET_NETDEV_DEV(ndev, &pdev->dev);
++
++ ndev->features = NETIF_F_LLTX;
++ if (pci_using_dac)
++ ndev->features |= NETIF_F_HIGHDMA;
++
++ pci_set_drvdata(pdev, ndev);
++
++ qdev = netdev_priv(ndev);
++ qdev->index = cards_found;
++ qdev->ndev = ndev;
++ qdev->pdev = pdev;
++ qdev->port_link_state = LS_DOWN;
++ if (msi)
++ qdev->msi = 1;
++
++ qdev->msg_enable = netif_msg_init(debug, default_msg);
++
++ qdev->mem_map_registers =
++ ioremap_nocache(pci_resource_start(pdev, 1),
++ pci_resource_len(qdev->pdev, 1));
++ if (!qdev->mem_map_registers) {
++ printk(KERN_ERR PFX "%s: cannot map device registers\n",
++ pci_name(pdev));
++ goto err_out_free_ndev;
++ }
++
++ spin_lock_init(&qdev->adapter_lock);
++ spin_lock_init(&qdev->hw_lock);
++
++ /* Set driver entry points */
++ ndev->open = ql3xxx_open;
++ ndev->hard_start_xmit = ql3xxx_send;
++ ndev->stop = ql3xxx_close;
++ ndev->get_stats = ql3xxx_get_stats;
++ ndev->change_mtu = ql3xxx_change_mtu;
++ ndev->set_multicast_list = ql3xxx_set_multicast_list;
++ SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
++ ndev->set_mac_address = ql3xxx_set_mac_address;
++ ndev->tx_timeout = ql3xxx_tx_timeout;
++ ndev->watchdog_timeo = 5 * HZ;
++
++ ndev->poll = &ql_poll;
++ ndev->weight = 64;
++
++ ndev->irq = pdev->irq;
++
++ /* make sure the EEPROM is good */
++ if (ql_get_nvram_params(qdev)) {
++ printk(KERN_ALERT PFX
++ "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
++ qdev->index);
++ goto err_out_iounmap;
++ }
++
++ ql_set_mac_info(qdev);
++
++ /* Validate and set parameters */
++ if (qdev->mac_index) {
++ memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress,
++ ETH_ALEN);
++ } else {
++ memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress,
++ ETH_ALEN);
++ }
++ memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
++
++ ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
++
++ /* Turn off support for multicasting */
++ ndev->flags &= ~IFF_MULTICAST;
++
++ /* Record PCI bus information. */
++ ql_get_board_info(qdev);
++
++ /*
++ * Set the Maximum Memory Read Byte Count value. We do this to handle
++ * jumbo frames.
++ */
++ if (qdev->pci_x) {
++ pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036);
++ }
++
++ err = register_netdev(ndev);
++ if (err) {
++ printk(KERN_ERR PFX "%s: cannot register net device\n",
++ pci_name(pdev));
++ goto err_out_iounmap;
++ }
++
++ /* we're going to reset, so assume we have no link for now */
++
++ netif_carrier_off(ndev);
++ netif_stop_queue(ndev);
++
++ qdev->workqueue = create_singlethread_workqueue(ndev->name);
++ INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev);
++ INIT_WORK(&qdev->tx_timeout_work,
++ (void (*)(void *))ql_tx_timeout_work, qdev);
++
++ init_timer(&qdev->adapter_timer);
++ qdev->adapter_timer.function = ql3xxx_timer;
++ qdev->adapter_timer.expires = jiffies + HZ * 2; /* two second delay */
++ qdev->adapter_timer.data = (unsigned long)qdev;
++
++ if(!cards_found) {
++ printk(KERN_ALERT PFX "%s\n", DRV_STRING);
++ printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n",
++ DRV_NAME, DRV_VERSION);
++ }
++ ql_display_dev_info(ndev);
++
++ cards_found++;
++ return 0;
++
++err_out_iounmap:
++ iounmap(qdev->mem_map_registers);
++err_out_free_ndev:
++ free_netdev(ndev);
++err_out_free_regions:
++ pci_release_regions(pdev);
++err_out_disable_pdev:
++ pci_disable_device(pdev);
++ pci_set_drvdata(pdev, NULL);
++err_out:
++ return err;
++}
++
++static void __devexit ql3xxx_remove(struct pci_dev *pdev)
++{
++ struct net_device *ndev = pci_get_drvdata(pdev);
++ struct ql3_adapter *qdev = netdev_priv(ndev);
++
++ unregister_netdev(ndev);
++ qdev = netdev_priv(ndev);
++
++ ql_disable_interrupts(qdev);
++
++ if (qdev->workqueue) {
++ cancel_delayed_work(&qdev->reset_work);
++ cancel_delayed_work(&qdev->tx_timeout_work);
++ destroy_workqueue(qdev->workqueue);
++ qdev->workqueue = NULL;
++ }
++
++ iounmap(qdev->mem_map_registers);
++ pci_release_regions(pdev);
++ pci_set_drvdata(pdev, NULL);
++ free_netdev(ndev);
++}
++
++static struct pci_driver ql3xxx_driver = {
++
++ .name = DRV_NAME,
++ .id_table = ql3xxx_pci_tbl,
++ .probe = ql3xxx_probe,
++ .remove = __devexit_p(ql3xxx_remove),
++};
++
++static int __init ql3xxx_init_module(void)
++{
++ return pci_register_driver(&ql3xxx_driver);
++}
++
++static void __exit ql3xxx_exit(void)
++{
++ pci_unregister_driver(&ql3xxx_driver);
++}
++
++module_init(ql3xxx_init_module);
++module_exit(ql3xxx_exit);
+diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
+new file mode 100644
+index 0000000..65da2c0
+--- /dev/null
++++ b/drivers/net/qla3xxx.h
+@@ -0,0 +1,1194 @@
++/*
++ * QLogic QLA3xxx NIC HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla3xxx for copyright and licensing details.
++ */
++#ifndef _QLA3XXX_H_
++#define _QLA3XXX_H_
++
++/*
++ * IOCB Definitions...
++ */
++#pragma pack(1)
++
++#define OPCODE_OB_MAC_IOCB_FN0 0x01
++#define OPCODE_OB_MAC_IOCB_FN2 0x21
++#define OPCODE_OB_TCP_IOCB_FN0 0x03
++#define OPCODE_OB_TCP_IOCB_FN2 0x23
++#define OPCODE_UPDATE_NCB_IOCB_FN0 0x00
++#define OPCODE_UPDATE_NCB_IOCB_FN2 0x20
++
++#define OPCODE_UPDATE_NCB_IOCB 0xF0
++#define OPCODE_IB_MAC_IOCB 0xF9
++#define OPCODE_IB_IP_IOCB 0xFA
++#define OPCODE_IB_TCP_IOCB 0xFB
++#define OPCODE_DUMP_PROTO_IOCB 0xFE
++#define OPCODE_BUFFER_ALERT_IOCB 0xFB
++
++#define OPCODE_FUNC_ID_MASK 0x30
++#define OUTBOUND_MAC_IOCB 0x01 /* plus function bits */
++#define OUTBOUND_TCP_IOCB 0x03 /* plus function bits */
++#define UPDATE_NCB_IOCB 0x00 /* plus function bits */
++
++#define FN0_MA_BITS_MASK 0x00
++#define FN1_MA_BITS_MASK 0x80
++
++struct ob_mac_iocb_req {
++ u8 opcode;
++ u8 flags;
++#define OB_MAC_IOCB_REQ_MA 0xC0
++#define OB_MAC_IOCB_REQ_F 0x20
++#define OB_MAC_IOCB_REQ_X 0x10
++#define OB_MAC_IOCB_REQ_D 0x02
++#define OB_MAC_IOCB_REQ_I 0x01
++ __le16 reserved0;
++
++ __le32 transaction_id;
++ __le16 data_len;
++ __le16 reserved1;
++ __le32 reserved2;
++ __le32 reserved3;
++ __le32 buf_addr0_low;
++ __le32 buf_addr0_high;
++ __le32 buf_0_len;
++ __le32 buf_addr1_low;
++ __le32 buf_addr1_high;
++ __le32 buf_1_len;
++ __le32 buf_addr2_low;
++ __le32 buf_addr2_high;
++ __le32 buf_2_len;
++ __le32 reserved4;
++ __le32 reserved5;
++};
++/*
++ * The following constants define control bits for buffer
++ * length fields for all IOCB's.
++ */
++#define OB_MAC_IOCB_REQ_E 0x80000000 /* Last valid buffer in list. */
++#define OB_MAC_IOCB_REQ_C 0x40000000 /* points to an OAL. (continuation) */
++#define OB_MAC_IOCB_REQ_L 0x20000000 /* Auburn local address pointer. */
++#define OB_MAC_IOCB_REQ_R 0x10000000 /* 32-bit address pointer. */
++
++struct ob_mac_iocb_rsp {
++ u8 opcode;
++ u8 flags;
++#define OB_MAC_IOCB_RSP_P 0x08
++#define OB_MAC_IOCB_RSP_S 0x02
++#define OB_MAC_IOCB_RSP_I 0x01
++
++ __le16 reserved0;
++ __le32 transaction_id;
++ __le32 reserved1;
++ __le32 reserved2;
++};
++
++struct ib_mac_iocb_rsp {
++ u8 opcode;
++ u8 flags;
++#define IB_MAC_IOCB_RSP_S 0x80
++#define IB_MAC_IOCB_RSP_H1 0x40
++#define IB_MAC_IOCB_RSP_H0 0x20
++#define IB_MAC_IOCB_RSP_B 0x10
++#define IB_MAC_IOCB_RSP_M 0x08
++#define IB_MAC_IOCB_RSP_MA 0x07
++
++ __le16 length;
++ __le32 reserved;
++ __le32 ial_low;
++ __le32 ial_high;
++
++};
++
++struct ob_ip_iocb_req {
++ u8 opcode;
++ __le16 flags;
++#define OB_IP_IOCB_REQ_O 0x100
++#define OB_IP_IOCB_REQ_H 0x008
++#define OB_IP_IOCB_REQ_U 0x004
++#define OB_IP_IOCB_REQ_D 0x002
++#define OB_IP_IOCB_REQ_I 0x001
++
++ u8 reserved0;
++
++ __le32 transaction_id;
++ __le16 data_len;
++ __le16 reserved1;
++ __le32 hncb_ptr_low;
++ __le32 hncb_ptr_high;
++ __le32 buf_addr0_low;
++ __le32 buf_addr0_high;
++ __le32 buf_0_len;
++ __le32 buf_addr1_low;
++ __le32 buf_addr1_high;
++ __le32 buf_1_len;
++ __le32 buf_addr2_low;
++ __le32 buf_addr2_high;
++ __le32 buf_2_len;
++ __le32 reserved2;
++ __le32 reserved3;
++};
++
++/* defines for BufferLength fields above */
++#define OB_IP_IOCB_REQ_E 0x80000000
++#define OB_IP_IOCB_REQ_C 0x40000000
++#define OB_IP_IOCB_REQ_L 0x20000000
++#define OB_IP_IOCB_REQ_R 0x10000000
++
++struct ob_ip_iocb_rsp {
++ u8 opcode;
++ u8 flags;
++#define OB_MAC_IOCB_RSP_E 0x08
++#define OB_MAC_IOCB_RSP_L 0x04
++#define OB_MAC_IOCB_RSP_S 0x02
++#define OB_MAC_IOCB_RSP_I 0x01
++
++ __le16 reserved0;
++ __le32 transaction_id;
++ __le32 reserved1;
++ __le32 reserved2;
++};
++
++struct ob_tcp_iocb_req {
++ u8 opcode;
++
++ u8 flags0;
++#define OB_TCP_IOCB_REQ_P 0x80
++#define OB_TCP_IOCB_REQ_CI 0x20
++#define OB_TCP_IOCB_REQ_H 0x10
++#define OB_TCP_IOCB_REQ_LN 0x08
++#define OB_TCP_IOCB_REQ_K 0x04
++#define OB_TCP_IOCB_REQ_D 0x02
++#define OB_TCP_IOCB_REQ_I 0x01
++
++ u8 flags1;
++#define OB_TCP_IOCB_REQ_OSM 0x40
++#define OB_TCP_IOCB_REQ_URG 0x20
++#define OB_TCP_IOCB_REQ_ACK 0x10
++#define OB_TCP_IOCB_REQ_PSH 0x08
++#define OB_TCP_IOCB_REQ_RST 0x04
++#define OB_TCP_IOCB_REQ_SYN 0x02
++#define OB_TCP_IOCB_REQ_FIN 0x01
++
++ u8 options_len;
++#define OB_TCP_IOCB_REQ_OMASK 0xF0
++#define OB_TCP_IOCB_REQ_SHIFT 4
++
++ __le32 transaction_id;
++ __le32 data_len;
++ __le32 hncb_ptr_low;
++ __le32 hncb_ptr_high;
++ __le32 buf_addr0_low;
++ __le32 buf_addr0_high;
++ __le32 buf_0_len;
++ __le32 buf_addr1_low;
++ __le32 buf_addr1_high;
++ __le32 buf_1_len;
++ __le32 buf_addr2_low;
++ __le32 buf_addr2_high;
++ __le32 buf_2_len;
++ __le32 time_stamp;
++ __le32 reserved1;
++};
++
++struct ob_tcp_iocb_rsp {
++ u8 opcode;
++
++ u8 flags0;
++#define OB_TCP_IOCB_RSP_C 0x20
++#define OB_TCP_IOCB_RSP_H 0x10
++#define OB_TCP_IOCB_RSP_LN 0x08
++#define OB_TCP_IOCB_RSP_K 0x04
++#define OB_TCP_IOCB_RSP_D 0x02
++#define OB_TCP_IOCB_RSP_I 0x01
++
++ u8 flags1;
++#define OB_TCP_IOCB_RSP_E 0x10
++#define OB_TCP_IOCB_RSP_W 0x08
++#define OB_TCP_IOCB_RSP_P 0x04
++#define OB_TCP_IOCB_RSP_T 0x02
++#define OB_TCP_IOCB_RSP_F 0x01
++
++ u8 state;
++#define OB_TCP_IOCB_RSP_SMASK 0xF0
++#define OB_TCP_IOCB_RSP_SHIFT 4
++
++ __le32 transaction_id;
++ __le32 local_ncb_ptr;
++ __le32 reserved0;
++};
++
++struct ib_ip_iocb_rsp {
++ u8 opcode;
++ u8 flags;
++#define IB_IP_IOCB_RSP_S 0x80
++#define IB_IP_IOCB_RSP_H1 0x40
++#define IB_IP_IOCB_RSP_H0 0x20
++#define IB_IP_IOCB_RSP_B 0x10
++#define IB_IP_IOCB_RSP_M 0x08
++#define IB_IP_IOCB_RSP_MA 0x07
++
++ __le16 length;
++ __le16 checksum;
++ __le16 reserved;
++#define IB_IP_IOCB_RSP_R 0x01
++ __le32 ial_low;
++ __le32 ial_high;
++};
++
++struct ib_tcp_iocb_rsp {
++ u8 opcode;
++ u8 flags;
++#define IB_TCP_IOCB_RSP_P 0x80
++#define IB_TCP_IOCB_RSP_T 0x40
++#define IB_TCP_IOCB_RSP_D 0x20
++#define IB_TCP_IOCB_RSP_N 0x10
++#define IB_TCP_IOCB_RSP_IP 0x03
++#define IB_TCP_FLAG_MASK 0xf0
++#define IB_TCP_FLAG_IOCB_SYN 0x00
++
++#define TCP_IB_RSP_FLAGS(x) (x->flags & ~IB_TCP_FLAG_MASK)
++
++ __le16 length;
++ __le32 hncb_ref_num;
++ __le32 ial_low;
++ __le32 ial_high;
++};
++
++struct net_rsp_iocb {
++ u8 opcode;
++ u8 flags;
++ __le16 reserved0;
++ __le32 reserved[3];
++};
++#pragma pack()
++
++/*
++ * Register Definitions...
++ */
++#define PORT0_PHY_ADDRESS 0x1e00
++#define PORT1_PHY_ADDRESS 0x1f00
++
++#define ETHERNET_CRC_SIZE 4
++
++#define MII_SCAN_REGISTER 0x00000001
++
++/* 32-bit ispControlStatus */
++enum {
++ ISP_CONTROL_NP_MASK = 0x0003,
++ ISP_CONTROL_NP_PCSR = 0x0000,
++ ISP_CONTROL_NP_HMCR = 0x0001,
++ ISP_CONTROL_NP_LRAMCR = 0x0002,
++ ISP_CONTROL_NP_PSR = 0x0003,
++ ISP_CONTROL_RI = 0x0008,
++ ISP_CONTROL_CI = 0x0010,
++ ISP_CONTROL_PI = 0x0020,
++ ISP_CONTROL_IN = 0x0040,
++ ISP_CONTROL_BE = 0x0080,
++ ISP_CONTROL_FN_MASK = 0x0700,
++ ISP_CONTROL_FN0_NET = 0x0400,
++ ISP_CONTROL_FN0_SCSI = 0x0500,
++ ISP_CONTROL_FN1_NET = 0x0600,
++ ISP_CONTROL_FN1_SCSI = 0x0700,
++ ISP_CONTROL_LINK_DN_0 = 0x0800,
++ ISP_CONTROL_LINK_DN_1 = 0x1000,
++ ISP_CONTROL_FSR = 0x2000,
++ ISP_CONTROL_FE = 0x4000,
++ ISP_CONTROL_SR = 0x8000,
++};
++
++/* 32-bit ispInterruptMaskReg */
++enum {
++ ISP_IMR_ENABLE_INT = 0x0004,
++ ISP_IMR_DISABLE_RESET_INT = 0x0008,
++ ISP_IMR_DISABLE_CMPL_INT = 0x0010,
++ ISP_IMR_DISABLE_PROC_INT = 0x0020,
++};
++
++/* 32-bit serialPortInterfaceReg */
++enum {
++ ISP_SERIAL_PORT_IF_CLK = 0x0001,
++ ISP_SERIAL_PORT_IF_CS = 0x0002,
++ ISP_SERIAL_PORT_IF_D0 = 0x0004,
++ ISP_SERIAL_PORT_IF_DI = 0x0008,
++ ISP_NVRAM_MASK = (0x000F << 16),
++ ISP_SERIAL_PORT_IF_WE = 0x0010,
++ ISP_SERIAL_PORT_IF_NVR_MASK = 0x001F,
++ ISP_SERIAL_PORT_IF_SCI = 0x0400,
++ ISP_SERIAL_PORT_IF_SC0 = 0x0800,
++ ISP_SERIAL_PORT_IF_SCE = 0x1000,
++ ISP_SERIAL_PORT_IF_SDI = 0x2000,
++ ISP_SERIAL_PORT_IF_SDO = 0x4000,
++ ISP_SERIAL_PORT_IF_SDE = 0x8000,
++ ISP_SERIAL_PORT_IF_I2C_MASK = 0xFC00,
++};
++
++/* semaphoreReg */
++enum {
++ QL_RESOURCE_MASK_BASE_CODE = 0x7,
++ QL_RESOURCE_BITS_BASE_CODE = 0x4,
++ QL_DRVR_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 1),
++ QL_DDR_RAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 4),
++ QL_PHY_GIO_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 7),
++ QL_NVRAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 10),
++ QL_FLASH_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 13),
++ QL_DRVR_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (1 + 16)),
++ QL_DDR_RAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (4 + 16)),
++ QL_PHY_GIO_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (7 + 16)),
++ QL_NVRAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (10 + 16)),
++ QL_FLASH_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (13 + 16)),
++};
++
++ /*
++ * QL3XXX memory-mapped registers
++ * QL3XXX has 4 "pages" of registers, each page occupying
++ * 256 bytes. Each page has a "common" area at the start and then
++ * page-specific registers after that.
++ */
++struct ql3xxx_common_registers {
++ u32 MB0; /* Offset 0x00 */
++ u32 MB1; /* Offset 0x04 */
++ u32 MB2; /* Offset 0x08 */
++ u32 MB3; /* Offset 0x0c */
++ u32 MB4; /* Offset 0x10 */
++ u32 MB5; /* Offset 0x14 */
++ u32 MB6; /* Offset 0x18 */
++ u32 MB7; /* Offset 0x1c */
++ u32 flashBiosAddr;
++ u32 flashBiosData;
++ u32 ispControlStatus;
++ u32 ispInterruptMaskReg;
++ u32 serialPortInterfaceReg;
++ u32 semaphoreReg;
++ u32 reqQProducerIndex;
++ u32 rspQConsumerIndex;
++
++ u32 rxLargeQProducerIndex;
++ u32 rxSmallQProducerIndex;
++ u32 arcMadiCommand;
++ u32 arcMadiData;
++};
++
++enum {
++ EXT_HW_CONFIG_SP_MASK = 0x0006,
++ EXT_HW_CONFIG_SP_NONE = 0x0000,
++ EXT_HW_CONFIG_SP_BYTE_PARITY = 0x0002,
++ EXT_HW_CONFIG_SP_ECC = 0x0004,
++ EXT_HW_CONFIG_SP_ECCx = 0x0006,
++ EXT_HW_CONFIG_SIZE_MASK = 0x0060,
++ EXT_HW_CONFIG_SIZE_128M = 0x0000,
++ EXT_HW_CONFIG_SIZE_256M = 0x0020,
++ EXT_HW_CONFIG_SIZE_512M = 0x0040,
++ EXT_HW_CONFIG_SIZE_INVALID = 0x0060,
++ EXT_HW_CONFIG_PD = 0x0080,
++ EXT_HW_CONFIG_FW = 0x0200,
++ EXT_HW_CONFIG_US = 0x0400,
++ EXT_HW_CONFIG_DCS_MASK = 0x1800,
++ EXT_HW_CONFIG_DCS_9MA = 0x0000,
++ EXT_HW_CONFIG_DCS_15MA = 0x0800,
++ EXT_HW_CONFIG_DCS_18MA = 0x1000,
++ EXT_HW_CONFIG_DCS_24MA = 0x1800,
++ EXT_HW_CONFIG_DDS_MASK = 0x6000,
++ EXT_HW_CONFIG_DDS_9MA = 0x0000,
++ EXT_HW_CONFIG_DDS_15MA = 0x2000,
++ EXT_HW_CONFIG_DDS_18MA = 0x4000,
++ EXT_HW_CONFIG_DDS_24MA = 0x6000,
++};
++
++/* InternalChipConfig */
++enum {
++ INTERNAL_CHIP_DM = 0x0001,
++ INTERNAL_CHIP_SD = 0x0002,
++ INTERNAL_CHIP_RAP_MASK = 0x000C,
++ INTERNAL_CHIP_RAP_RR = 0x0000,
++ INTERNAL_CHIP_RAP_NRM = 0x0004,
++ INTERNAL_CHIP_RAP_ERM = 0x0008,
++ INTERNAL_CHIP_RAP_ERMx = 0x000C,
++ INTERNAL_CHIP_WE = 0x0010,
++ INTERNAL_CHIP_EF = 0x0020,
++ INTERNAL_CHIP_FR = 0x0040,
++ INTERNAL_CHIP_FW = 0x0080,
++ INTERNAL_CHIP_FI = 0x0100,
++ INTERNAL_CHIP_FT = 0x0200,
++};
++
++/* portControl */
++enum {
++ PORT_CONTROL_DS = 0x0001,
++ PORT_CONTROL_HH = 0x0002,
++ PORT_CONTROL_EI = 0x0004,
++ PORT_CONTROL_ET = 0x0008,
++ PORT_CONTROL_EF = 0x0010,
++ PORT_CONTROL_DRM = 0x0020,
++ PORT_CONTROL_RLB = 0x0040,
++ PORT_CONTROL_RCB = 0x0080,
++ PORT_CONTROL_MAC = 0x0100,
++ PORT_CONTROL_IPV = 0x0200,
++ PORT_CONTROL_IFP = 0x0400,
++ PORT_CONTROL_ITP = 0x0800,
++ PORT_CONTROL_FI = 0x1000,
++ PORT_CONTROL_DFP = 0x2000,
++ PORT_CONTROL_OI = 0x4000,
++ PORT_CONTROL_CC = 0x8000,
++};
++
++/* portStatus */
++enum {
++ PORT_STATUS_SM0 = 0x0001,
++ PORT_STATUS_SM1 = 0x0002,
++ PORT_STATUS_X = 0x0008,
++ PORT_STATUS_DL = 0x0080,
++ PORT_STATUS_IC = 0x0200,
++ PORT_STATUS_MRC = 0x0400,
++ PORT_STATUS_NL = 0x0800,
++ PORT_STATUS_REV_ID_MASK = 0x7000,
++ PORT_STATUS_REV_ID_1 = 0x1000,
++ PORT_STATUS_REV_ID_2 = 0x2000,
++ PORT_STATUS_REV_ID_3 = 0x3000,
++ PORT_STATUS_64 = 0x8000,
++ PORT_STATUS_UP0 = 0x10000,
++ PORT_STATUS_AC0 = 0x20000,
++ PORT_STATUS_AE0 = 0x40000,
++ PORT_STATUS_UP1 = 0x100000,
++ PORT_STATUS_AC1 = 0x200000,
++ PORT_STATUS_AE1 = 0x400000,
++ PORT_STATUS_F0_ENABLED = 0x1000000,
++ PORT_STATUS_F1_ENABLED = 0x2000000,
++ PORT_STATUS_F2_ENABLED = 0x4000000,
++ PORT_STATUS_F3_ENABLED = 0x8000000,
++};
++
++/* macMIIMgmtControlReg */
++enum {
++ MAC_ADDR_INDIRECT_PTR_REG_RP_MASK = 0x0003,
++ MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_LWR = 0x0000,
++ MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_UPR = 0x0001,
++ MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_LWR = 0x0002,
++ MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_UPR = 0x0003,
++ MAC_ADDR_INDIRECT_PTR_REG_PR = 0x0008,
++ MAC_ADDR_INDIRECT_PTR_REG_SS = 0x0010,
++ MAC_ADDR_INDIRECT_PTR_REG_SE = 0x0020,
++ MAC_ADDR_INDIRECT_PTR_REG_SP = 0x0040,
++ MAC_ADDR_INDIRECT_PTR_REG_PE = 0x0080,
++};
++
++/* macMIIMgmtControlReg */
++enum {
++ MAC_MII_CONTROL_RC = 0x0001,
++ MAC_MII_CONTROL_SC = 0x0002,
++ MAC_MII_CONTROL_AS = 0x0004,
++ MAC_MII_CONTROL_NP = 0x0008,
++ MAC_MII_CONTROL_CLK_SEL_MASK = 0x0070,
++ MAC_MII_CONTROL_CLK_SEL_DIV2 = 0x0000,
++ MAC_MII_CONTROL_CLK_SEL_DIV4 = 0x0010,
++ MAC_MII_CONTROL_CLK_SEL_DIV6 = 0x0020,
++ MAC_MII_CONTROL_CLK_SEL_DIV8 = 0x0030,
++ MAC_MII_CONTROL_CLK_SEL_DIV10 = 0x0040,
++ MAC_MII_CONTROL_CLK_SEL_DIV14 = 0x0050,
++ MAC_MII_CONTROL_CLK_SEL_DIV20 = 0x0060,
++ MAC_MII_CONTROL_CLK_SEL_DIV28 = 0x0070,
++ MAC_MII_CONTROL_RM = 0x8000,
++};
++
++/* macMIIStatusReg */
++enum {
++ MAC_MII_STATUS_BSY = 0x0001,
++ MAC_MII_STATUS_SC = 0x0002,
++ MAC_MII_STATUS_NV = 0x0004,
++};
++
++enum {
++ MAC_CONFIG_REG_PE = 0x0001,
++ MAC_CONFIG_REG_TF = 0x0002,
++ MAC_CONFIG_REG_RF = 0x0004,
++ MAC_CONFIG_REG_FD = 0x0008,
++ MAC_CONFIG_REG_GM = 0x0010,
++ MAC_CONFIG_REG_LB = 0x0020,
++ MAC_CONFIG_REG_SR = 0x8000,
++};
++
++enum {
++ MAC_HALF_DUPLEX_REG_ED = 0x10000,
++ MAC_HALF_DUPLEX_REG_NB = 0x20000,
++ MAC_HALF_DUPLEX_REG_BNB = 0x40000,
++ MAC_HALF_DUPLEX_REG_ALT = 0x80000,
++};
++
++enum {
++ IP_ADDR_INDEX_REG_MASK = 0x000f,
++ IP_ADDR_INDEX_REG_FUNC_0_PRI = 0x0000,
++ IP_ADDR_INDEX_REG_FUNC_0_SEC = 0x0001,
++ IP_ADDR_INDEX_REG_FUNC_1_PRI = 0x0002,
++ IP_ADDR_INDEX_REG_FUNC_1_SEC = 0x0003,
++ IP_ADDR_INDEX_REG_FUNC_2_PRI = 0x0004,
++ IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
++ IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
++ IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
++};
++
++enum {
++ PROBE_MUX_ADDR_REG_MUX_SEL_MASK = 0x003f,
++ PROBE_MUX_ADDR_REG_SYSCLK = 0x0000,
++ PROBE_MUX_ADDR_REG_PCICLK = 0x0040,
++ PROBE_MUX_ADDR_REG_NRXCLK = 0x0080,
++ PROBE_MUX_ADDR_REG_CPUCLK = 0x00C0,
++ PROBE_MUX_ADDR_REG_MODULE_SEL_MASK = 0x3f00,
++ PROBE_MUX_ADDR_REG_UP = 0x4000,
++ PROBE_MUX_ADDR_REG_RE = 0x8000,
++};
++
++enum {
++ STATISTICS_INDEX_REG_MASK = 0x01ff,
++ STATISTICS_INDEX_REG_MAC0_TX_FRAME = 0x0000,
++ STATISTICS_INDEX_REG_MAC0_TX_BYTES = 0x0001,
++ STATISTICS_INDEX_REG_MAC0_TX_STAT1 = 0x0002,
++ STATISTICS_INDEX_REG_MAC0_TX_STAT2 = 0x0003,
++ STATISTICS_INDEX_REG_MAC0_TX_STAT3 = 0x0004,
++ STATISTICS_INDEX_REG_MAC0_TX_STAT4 = 0x0005,
++ STATISTICS_INDEX_REG_MAC0_TX_STAT5 = 0x0006,
++ STATISTICS_INDEX_REG_MAC0_RX_FRAME = 0x0007,
++ STATISTICS_INDEX_REG_MAC0_RX_BYTES = 0x0008,
++ STATISTICS_INDEX_REG_MAC0_RX_STAT1 = 0x0009,
++ STATISTICS_INDEX_REG_MAC0_RX_STAT2 = 0x000a,
++ STATISTICS_INDEX_REG_MAC0_RX_STAT3 = 0x000b,
++ STATISTICS_INDEX_REG_MAC0_RX_ERR_CRC = 0x000c,
++ STATISTICS_INDEX_REG_MAC0_RX_ERR_ENC = 0x000d,
++ STATISTICS_INDEX_REG_MAC0_RX_ERR_LEN = 0x000e,
++ STATISTICS_INDEX_REG_MAC0_RX_STAT4 = 0x000f,
++ STATISTICS_INDEX_REG_MAC1_TX_FRAME = 0x0010,
++ STATISTICS_INDEX_REG_MAC1_TX_BYTES = 0x0011,
++ STATISTICS_INDEX_REG_MAC1_TX_STAT1 = 0x0012,
++ STATISTICS_INDEX_REG_MAC1_TX_STAT2 = 0x0013,
++ STATISTICS_INDEX_REG_MAC1_TX_STAT3 = 0x0014,
++ STATISTICS_INDEX_REG_MAC1_TX_STAT4 = 0x0015,
++ STATISTICS_INDEX_REG_MAC1_TX_STAT5 = 0x0016,
++ STATISTICS_INDEX_REG_MAC1_RX_FRAME = 0x0017,
++ STATISTICS_INDEX_REG_MAC1_RX_BYTES = 0x0018,
++ STATISTICS_INDEX_REG_MAC1_RX_STAT1 = 0x0019,
++ STATISTICS_INDEX_REG_MAC1_RX_STAT2 = 0x001a,
++ STATISTICS_INDEX_REG_MAC1_RX_STAT3 = 0x001b,
++ STATISTICS_INDEX_REG_MAC1_RX_ERR_CRC = 0x001c,
++ STATISTICS_INDEX_REG_MAC1_RX_ERR_ENC = 0x001d,
++ STATISTICS_INDEX_REG_MAC1_RX_ERR_LEN = 0x001e,
++ STATISTICS_INDEX_REG_MAC1_RX_STAT4 = 0x001f,
++ STATISTICS_INDEX_REG_IP_TX_PKTS = 0x0020,
++ STATISTICS_INDEX_REG_IP_TX_BYTES = 0x0021,
++ STATISTICS_INDEX_REG_IP_TX_FRAG = 0x0022,
++ STATISTICS_INDEX_REG_IP_RX_PKTS = 0x0023,
++ STATISTICS_INDEX_REG_IP_RX_BYTES = 0x0024,
++ STATISTICS_INDEX_REG_IP_RX_FRAG = 0x0025,
++ STATISTICS_INDEX_REG_IP_DGRM_REASSEMBLY = 0x0026,
++ STATISTICS_INDEX_REG_IP_V6_RX_PKTS = 0x0027,
++ STATISTICS_INDEX_REG_IP_RX_PKTERR = 0x0028,
++ STATISTICS_INDEX_REG_IP_REASSEMBLY_ERR = 0x0029,
++ STATISTICS_INDEX_REG_TCP_TX_SEG = 0x0030,
++ STATISTICS_INDEX_REG_TCP_TX_BYTES = 0x0031,
++ STATISTICS_INDEX_REG_TCP_RX_SEG = 0x0032,
++ STATISTICS_INDEX_REG_TCP_RX_BYTES = 0x0033,
++ STATISTICS_INDEX_REG_TCP_TIMER_EXP = 0x0034,
++ STATISTICS_INDEX_REG_TCP_RX_ACK = 0x0035,
++ STATISTICS_INDEX_REG_TCP_TX_ACK = 0x0036,
++ STATISTICS_INDEX_REG_TCP_RX_ERR = 0x0037,
++ STATISTICS_INDEX_REG_TCP_RX_WIN_PROBE = 0x0038,
++ STATISTICS_INDEX_REG_TCP_ECC_ERR_CORR = 0x003f,
++};
++
++enum {
++ PORT_FATAL_ERROR_STATUS_OFB_RE_MAC0 = 0x00000001,
++ PORT_FATAL_ERROR_STATUS_OFB_RE_MAC1 = 0x00000002,
++ PORT_FATAL_ERROR_STATUS_OFB_WE = 0x00000004,
++ PORT_FATAL_ERROR_STATUS_IFB_RE = 0x00000008,
++ PORT_FATAL_ERROR_STATUS_IFB_WE_MAC0 = 0x00000010,
++ PORT_FATAL_ERROR_STATUS_IFB_WE_MAC1 = 0x00000020,
++ PORT_FATAL_ERROR_STATUS_ODE_RE = 0x00000040,
++ PORT_FATAL_ERROR_STATUS_ODE_WE = 0x00000080,
++ PORT_FATAL_ERROR_STATUS_IDE_RE = 0x00000100,
++ PORT_FATAL_ERROR_STATUS_IDE_WE = 0x00000200,
++ PORT_FATAL_ERROR_STATUS_SDE_RE = 0x00000400,
++ PORT_FATAL_ERROR_STATUS_SDE_WE = 0x00000800,
++ PORT_FATAL_ERROR_STATUS_BLE = 0x00001000,
++ PORT_FATAL_ERROR_STATUS_SPE = 0x00002000,
++ PORT_FATAL_ERROR_STATUS_EP0 = 0x00004000,
++ PORT_FATAL_ERROR_STATUS_EP1 = 0x00008000,
++ PORT_FATAL_ERROR_STATUS_ICE = 0x00010000,
++ PORT_FATAL_ERROR_STATUS_ILE = 0x00020000,
++ PORT_FATAL_ERROR_STATUS_OPE = 0x00040000,
++ PORT_FATAL_ERROR_STATUS_TA = 0x00080000,
++ PORT_FATAL_ERROR_STATUS_MA = 0x00100000,
++ PORT_FATAL_ERROR_STATUS_SCE = 0x00200000,
++ PORT_FATAL_ERROR_STATUS_RPE = 0x00400000,
++ PORT_FATAL_ERROR_STATUS_MPE = 0x00800000,
++ PORT_FATAL_ERROR_STATUS_OCE = 0x01000000,
++};
++
++/*
++ * port control and status page - page 0
++ */
++
++struct ql3xxx_port_registers {
++ struct ql3xxx_common_registers CommonRegs;
++
++ u32 ExternalHWConfig;
++ u32 InternalChipConfig;
++ u32 portControl;
++ u32 portStatus;
++ u32 macAddrIndirectPtrReg;
++ u32 macAddrDataReg;
++ u32 macMIIMgmtControlReg;
++ u32 macMIIMgmtAddrReg;
++ u32 macMIIMgmtDataReg;
++ u32 macMIIStatusReg;
++ u32 mac0ConfigReg;
++ u32 mac0IpgIfgReg;
++ u32 mac0HalfDuplexReg;
++ u32 mac0MaxFrameLengthReg;
++ u32 mac0PauseThresholdReg;
++ u32 mac1ConfigReg;
++ u32 mac1IpgIfgReg;
++ u32 mac1HalfDuplexReg;
++ u32 mac1MaxFrameLengthReg;
++ u32 mac1PauseThresholdReg;
++ u32 ipAddrIndexReg;
++ u32 ipAddrDataReg;
++ u32 ipReassemblyTimeout;
++ u32 tcpMaxWindow;
++ u32 currentTcpTimestamp[2];
++ u32 internalRamRWAddrReg;
++ u32 internalRamWDataReg;
++ u32 reclaimedBufferAddrRegLow;
++ u32 reclaimedBufferAddrRegHigh;
++ u32 reserved[2];
++ u32 fpgaRevID;
++ u32 localRamAddr;
++ u32 localRamDataAutoIncr;
++ u32 localRamDataNonIncr;
++ u32 gpOutput;
++ u32 gpInput;
++ u32 probeMuxAddr;
++ u32 probeMuxData;
++ u32 statisticsIndexReg;
++ u32 statisticsReadDataRegAutoIncr;
++ u32 statisticsReadDataRegNoIncr;
++ u32 PortFatalErrStatus;
++};
++
++/*
++ * port host memory config page - page 1
++ */
++struct ql3xxx_host_memory_registers {
++ struct ql3xxx_common_registers CommonRegs;
++
++ u32 reserved[12];
++
++ /* Network Request Queue */
++ u32 reqConsumerIndex;
++ u32 reqConsumerIndexAddrLow;
++ u32 reqConsumerIndexAddrHigh;
++ u32 reqBaseAddrLow;
++ u32 reqBaseAddrHigh;
++ u32 reqLength;
++
++ /* Network Completion Queue */
++ u32 rspProducerIndex;
++ u32 rspProducerIndexAddrLow;
++ u32 rspProducerIndexAddrHigh;
++ u32 rspBaseAddrLow;
++ u32 rspBaseAddrHigh;
++ u32 rspLength;
++
++ /* RX Large Buffer Queue */
++ u32 rxLargeQConsumerIndex;
++ u32 rxLargeQBaseAddrLow;
++ u32 rxLargeQBaseAddrHigh;
++ u32 rxLargeQLength;
++ u32 rxLargeBufferLength;
++
++ /* RX Small Buffer Queue */
++ u32 rxSmallQConsumerIndex;
++ u32 rxSmallQBaseAddrLow;
++ u32 rxSmallQBaseAddrHigh;
++ u32 rxSmallQLength;
++ u32 rxSmallBufferLength;
++
++};
++
++/*
++ * port local RAM page - page 2
++ */
++struct ql3xxx_local_ram_registers {
++ struct ql3xxx_common_registers CommonRegs;
++ u32 bufletSize;
++ u32 maxBufletCount;
++ u32 currentBufletCount;
++ u32 reserved;
++ u32 freeBufletThresholdLow;
++ u32 freeBufletThresholdHigh;
++ u32 ipHashTableBase;
++ u32 ipHashTableCount;
++ u32 tcpHashTableBase;
++ u32 tcpHashTableCount;
++ u32 ncbBase;
++ u32 maxNcbCount;
++ u32 currentNcbCount;
++ u32 drbBase;
++ u32 maxDrbCount;
++ u32 currentDrbCount;
++};
++
++/*
++ * definitions for Semaphore bits in Semaphore/Serial NVRAM interface register
++ */
++
++#define LS_64BITS(x) (u32)(0xffffffff & ((u64)x))
++#define MS_64BITS(x) (u32)(0xffffffff & (((u64)x)>>16>>16) )
++
++/*
++ * I/O register
++ */
++
++enum {
++ CONTROL_REG = 0,
++ STATUS_REG = 1,
++ PHY_STAT_LINK_UP = 0x0004,
++ PHY_CTRL_LOOPBACK = 0x4000,
++
++ PETBI_CONTROL_REG = 0x00,
++ PETBI_CTRL_SOFT_RESET = 0x8000,
++ PETBI_CTRL_AUTO_NEG = 0x1000,
++ PETBI_CTRL_RESTART_NEG = 0x0200,
++ PETBI_CTRL_FULL_DUPLEX = 0x0100,
++ PETBI_CTRL_SPEED_1000 = 0x0040,
++
++ PETBI_STATUS_REG = 0x01,
++ PETBI_STAT_NEG_DONE = 0x0020,
++ PETBI_STAT_LINK_UP = 0x0004,
++
++ PETBI_NEG_ADVER = 0x04,
++ PETBI_NEG_PAUSE = 0x0080,
++ PETBI_NEG_PAUSE_MASK = 0x0180,
++ PETBI_NEG_DUPLEX = 0x0020,
++ PETBI_NEG_DUPLEX_MASK = 0x0060,
++
++ PETBI_NEG_PARTNER = 0x05,
++ PETBI_NEG_ERROR_MASK = 0x3000,
++
++ PETBI_EXPANSION_REG = 0x06,
++ PETBI_EXP_PAGE_RX = 0x0002,
++
++ PETBI_TBI_CTRL = 0x11,
++ PETBI_TBI_RESET = 0x8000,
++ PETBI_TBI_AUTO_SENSE = 0x0100,
++ PETBI_TBI_SERDES_MODE = 0x0010,
++ PETBI_TBI_SERDES_WRAP = 0x0002,
++
++ AUX_CONTROL_STATUS = 0x1c,
++ PHY_AUX_NEG_DONE = 0x8000,
++ PHY_NEG_PARTNER = 5,
++ PHY_AUX_DUPLEX_STAT = 0x0020,
++ PHY_AUX_SPEED_STAT = 0x0018,
++ PHY_AUX_NO_HW_STRAP = 0x0004,
++ PHY_AUX_RESET_STICK = 0x0002,
++ PHY_NEG_PAUSE = 0x0400,
++ PHY_CTRL_SOFT_RESET = 0x8000,
++ PHY_NEG_ADVER = 4,
++ PHY_NEG_ADV_SPEED = 0x01e0,
++ PHY_CTRL_RESTART_NEG = 0x0200,
++};
++enum {
++/* AM29LV Flash definitions */
++ FM93C56A_START = 0x1,
++/* Commands */
++ FM93C56A_READ = 0x2,
++ FM93C56A_WEN = 0x0,
++ FM93C56A_WRITE = 0x1,
++ FM93C56A_WRITE_ALL = 0x0,
++ FM93C56A_WDS = 0x0,
++ FM93C56A_ERASE = 0x3,
++ FM93C56A_ERASE_ALL = 0x0,
++/* Command Extentions */
++ FM93C56A_WEN_EXT = 0x3,
++ FM93C56A_WRITE_ALL_EXT = 0x1,
++ FM93C56A_WDS_EXT = 0x0,
++ FM93C56A_ERASE_ALL_EXT = 0x2,
++/* Special Bits */
++ FM93C56A_READ_DUMMY_BITS = 1,
++ FM93C56A_READY = 0,
++ FM93C56A_BUSY = 1,
++ FM93C56A_CMD_BITS = 2,
++/* AM29LV Flash definitions */
++ FM93C56A_SIZE_8 = 0x100,
++ FM93C56A_SIZE_16 = 0x80,
++ FM93C66A_SIZE_8 = 0x200,
++ FM93C66A_SIZE_16 = 0x100,
++ FM93C86A_SIZE_16 = 0x400,
++/* Address Bits */
++ FM93C56A_NO_ADDR_BITS_16 = 8,
++ FM93C56A_NO_ADDR_BITS_8 = 9,
++ FM93C86A_NO_ADDR_BITS_16 = 10,
++/* Data Bits */
++ FM93C56A_DATA_BITS_16 = 16,
++ FM93C56A_DATA_BITS_8 = 8,
++};
++enum {
++/* Auburn Bits */
++ AUBURN_EEPROM_DI = 0x8,
++ AUBURN_EEPROM_DI_0 = 0x0,
++ AUBURN_EEPROM_DI_1 = 0x8,
++ AUBURN_EEPROM_DO = 0x4,
++ AUBURN_EEPROM_DO_0 = 0x0,
++ AUBURN_EEPROM_DO_1 = 0x4,
++ AUBURN_EEPROM_CS = 0x2,
++ AUBURN_EEPROM_CS_0 = 0x0,
++ AUBURN_EEPROM_CS_1 = 0x2,
++ AUBURN_EEPROM_CLK_RISE = 0x1,
++ AUBURN_EEPROM_CLK_FALL = 0x0,
++};
++enum {EEPROM_SIZE = FM93C86A_SIZE_16,
++ EEPROM_NO_ADDR_BITS = FM93C86A_NO_ADDR_BITS_16,
++ EEPROM_NO_DATA_BITS = FM93C56A_DATA_BITS_16,
++};
++
++/*
++ * MAC Config data structure
++ */
++ struct eeprom_port_cfg {
++ u16 etherMtu_mac;
++ u16 pauseThreshold_mac;
++ u16 resumeThreshold_mac;
++ u16 portConfiguration;
++#define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000
++#define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000
++#define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000
++#define PORT_CONFIG_HALF_DUPLEX_ENABLED 0x1000
++#define PORT_CONFIG_1000MB_SPEED 0x0400
++#define PORT_CONFIG_100MB_SPEED 0x0200
++#define PORT_CONFIG_10MB_SPEED 0x0100
++#define PORT_CONFIG_LINK_SPEED_MASK 0x0F00
++ u16 reserved[12];
++
++};
++
++/*
++ * BIOS data structure
++ */
++struct eeprom_bios_cfg {
++ u16 SpinDlyEn:1, disBios:1, EnMemMap:1, EnSelectBoot:1, Reserved:12;
++
++ u8 bootID0:7, boodID0Valid:1;
++ u8 bootLun0[8];
++
++ u8 bootID1:7, boodID1Valid:1;
++ u8 bootLun1[8];
++
++ u16 MaxLunsTrgt;
++ u8 reserved[10];
++};
++
++/*
++ * Function Specific Data structure
++ */
++struct eeprom_function_cfg {
++ u8 reserved[30];
++ u8 macAddress[6];
++ u8 macAddressSecondary[6];
++
++ u16 subsysVendorId;
++ u16 subsysDeviceId;
++};
++
++/*
++ * EEPROM format
++ */
++struct eeprom_data {
++ u8 asicId[4];
++ u8 version;
++ u8 numPorts;
++ u16 boardId;
++
++#define EEPROM_BOARDID_STR_SIZE 16
++#define EEPROM_SERIAL_NUM_SIZE 16
++
++ u8 boardIdStr[16];
++ u8 serialNumber[16];
++ u16 extHwConfig;
++ struct eeprom_port_cfg macCfg_port0;
++ struct eeprom_port_cfg macCfg_port1;
++ u16 bufletSize;
++ u16 bufletCount;
++ u16 tcpWindowThreshold50;
++ u16 tcpWindowThreshold25;
++ u16 tcpWindowThreshold0;
++ u16 ipHashTableBaseHi;
++ u16 ipHashTableBaseLo;
++ u16 ipHashTableSize;
++ u16 tcpHashTableBaseHi;
++ u16 tcpHashTableBaseLo;
++ u16 tcpHashTableSize;
++ u16 ncbTableBaseHi;
++ u16 ncbTableBaseLo;
++ u16 ncbTableSize;
++ u16 drbTableBaseHi;
++ u16 drbTableBaseLo;
++ u16 drbTableSize;
++ u16 reserved_142[4];
++ u16 ipReassemblyTimeout;
++ u16 tcpMaxWindowSize;
++ u16 ipSecurity;
++#define IPSEC_CONFIG_PRESENT 0x0001
++ u8 reserved_156[294];
++ u16 qDebug[8];
++ struct eeprom_function_cfg funcCfg_fn0;
++ u16 reserved_510;
++ u8 oemSpace[432];
++ struct eeprom_bios_cfg biosCfg_fn1;
++ struct eeprom_function_cfg funcCfg_fn1;
++ u16 reserved_1022;
++ u8 reserved_1024[464];
++ struct eeprom_function_cfg funcCfg_fn2;
++ u16 reserved_1534;
++ u8 reserved_1536[432];
++ struct eeprom_bios_cfg biosCfg_fn3;
++ struct eeprom_function_cfg funcCfg_fn3;
++ u16 checksum;
++};
++
++/*
++ * General definitions...
++ */
++
++/*
++ * Below are a number compiler switches for controlling driver behavior.
++ * Some are not supported under certain conditions and are notated as such.
++ */
++
++#define QL3XXX_VENDOR_ID 0x1077
++#define QL3022_DEVICE_ID 0x3022
++
++/* MTU & Frame Size stuff */
++#define NORMAL_MTU_SIZE ETH_DATA_LEN
++#define JUMBO_MTU_SIZE 9000
++#define VLAN_ID_LEN 2
++
++/* Request Queue Related Definitions */
++#define NUM_REQ_Q_ENTRIES 256 /* so that 64 * 64 = 4096 (1 page) */
++
++/* Response Queue Related Definitions */
++#define NUM_RSP_Q_ENTRIES 256 /* so that 256 * 16 = 4096 (1 page) */
++
++/* Transmit and Receive Buffers */
++#define NUM_LBUFQ_ENTRIES 128
++#define NUM_SBUFQ_ENTRIES 64
++#define QL_SMALL_BUFFER_SIZE 32
++#define QL_ADDR_ELE_PER_BUFQ_ENTRY \
++(sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element))
++ /* Each send has at least control block. This is how many we keep. */
++#define NUM_SMALL_BUFFERS NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
++#define NUM_LARGE_BUFFERS NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
++#define QL_HEADER_SPACE 32 /* make header space at top of skb. */
++/*
++ * Large & Small Buffers for Receives
++ */
++struct lrg_buf_q_entry {
++
++ u32 addr0_lower;
++#define IAL_LAST_ENTRY 0x00000001
++#define IAL_CONT_ENTRY 0x00000002
++#define IAL_FLAG_MASK 0x00000003
++ u32 addr0_upper;
++ u32 addr1_lower;
++ u32 addr1_upper;
++ u32 addr2_lower;
++ u32 addr2_upper;
++ u32 addr3_lower;
++ u32 addr3_upper;
++ u32 addr4_lower;
++ u32 addr4_upper;
++ u32 addr5_lower;
++ u32 addr5_upper;
++ u32 addr6_lower;
++ u32 addr6_upper;
++ u32 addr7_lower;
++ u32 addr7_upper;
++
++};
++
++struct bufq_addr_element {
++ u32 addr_low;
++ u32 addr_high;
++};
++
++#define QL_NO_RESET 0
++#define QL_DO_RESET 1
++
++enum link_state_t {
++ LS_UNKNOWN = 0,
++ LS_DOWN,
++ LS_DEGRADE,
++ LS_RECOVER,
++ LS_UP,
++};
++
++struct ql_rcv_buf_cb {
++ struct ql_rcv_buf_cb *next;
++ struct sk_buff *skb;
++ DECLARE_PCI_UNMAP_ADDR(mapaddr);
++ DECLARE_PCI_UNMAP_LEN(maplen);
++ __le32 buf_phy_addr_low;
++ __le32 buf_phy_addr_high;
++ int index;
++};
++
++struct ql_tx_buf_cb {
++ struct sk_buff *skb;
++ struct ob_mac_iocb_req *queue_entry ;
++ DECLARE_PCI_UNMAP_ADDR(mapaddr);
++ DECLARE_PCI_UNMAP_LEN(maplen);
++};
++
++/* definitions for type field */
++#define QL_BUF_TYPE_MACIOCB 0x01
++#define QL_BUF_TYPE_IPIOCB 0x02
++#define QL_BUF_TYPE_TCPIOCB 0x03
++
++/* qdev->flags definitions. */
++enum { QL_RESET_DONE = 1, /* Reset finished. */
++ QL_RESET_ACTIVE = 2, /* Waiting for reset to finish. */
++ QL_RESET_START = 3, /* Please reset the chip. */
++ QL_RESET_PER_SCSI = 4, /* SCSI driver requests reset. */
++ QL_TX_TIMEOUT = 5, /* Timeout in progress. */
++ QL_LINK_MASTER = 6, /* This driver controls the link. */
++ QL_ADAPTER_UP = 7, /* Adapter has been brought up. */
++ QL_THREAD_UP = 8, /* This flag is available. */
++ QL_LINK_UP = 9, /* Link Status. */
++ QL_ALLOC_REQ_RSP_Q_DONE = 10,
++ QL_ALLOC_BUFQS_DONE = 11,
++ QL_ALLOC_SMALL_BUF_DONE = 12,
++ QL_LINK_OPTICAL = 13,
++ QL_MSI_ENABLED = 14,
++};
++
++/*
++ * ql3_adapter - The main Adapter structure definition.
++ * This structure has all fields relevant to the hardware.
++ */
++
++struct ql3_adapter {
++ u32 reserved_00;
++ unsigned long flags;
++
++ /* PCI Configuration information for this device */
++ struct pci_dev *pdev;
++ struct net_device *ndev; /* Parent NET device */
++
++ /* Hardware information */
++ u8 chip_rev_id;
++ u8 pci_slot;
++ u8 pci_width;
++ u8 pci_x;
++ u32 msi;
++ int index;
++ struct timer_list adapter_timer; /* timer used for various functions */
++
++ spinlock_t adapter_lock;
++ spinlock_t hw_lock;
++
++ /* PCI Bus Relative Register Addresses */
++ u8 __iomem *mmap_virt_base; /* stores return value from ioremap() */
++ struct ql3xxx_port_registers __iomem *mem_map_registers;
++ u32 current_page; /* tracks current register page */
++
++ u32 msg_enable;
++ u8 reserved_01[2];
++ u8 reserved_02[2];
++
++ /* Page for Shadow Registers */
++ void *shadow_reg_virt_addr;
++ dma_addr_t shadow_reg_phy_addr;
++
++ /* Net Request Queue */
++ u32 req_q_size;
++ u32 reserved_03;
++ struct ob_mac_iocb_req *req_q_virt_addr;
++ dma_addr_t req_q_phy_addr;
++ u16 req_producer_index;
++ u16 reserved_04;
++ u16 *preq_consumer_index;
++ u32 req_consumer_index_phy_addr_high;
++ u32 req_consumer_index_phy_addr_low;
++ atomic_t tx_count;
++ struct ql_tx_buf_cb tx_buf[NUM_REQ_Q_ENTRIES];
++
++ /* Net Response Queue */
++ u32 rsp_q_size;
++ u32 eeprom_cmd_data;
++ struct net_rsp_iocb *rsp_q_virt_addr;
++ dma_addr_t rsp_q_phy_addr;
++ struct net_rsp_iocb *rsp_current;
++ u16 rsp_consumer_index;
++ u16 reserved_06;
++ u32 *prsp_producer_index;
++ u32 rsp_producer_index_phy_addr_high;
++ u32 rsp_producer_index_phy_addr_low;
++
++ /* Large Buffer Queue */
++ u32 lrg_buf_q_alloc_size;
++ u32 lrg_buf_q_size;
++ void *lrg_buf_q_alloc_virt_addr;
++ void *lrg_buf_q_virt_addr;
++ dma_addr_t lrg_buf_q_alloc_phy_addr;
++ dma_addr_t lrg_buf_q_phy_addr;
++ u32 lrg_buf_q_producer_index;
++ u32 lrg_buf_release_cnt;
++ struct bufq_addr_element *lrg_buf_next_free;
++
++ /* Large (Receive) Buffers */
++ struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS];
++ struct ql_rcv_buf_cb *lrg_buf_free_head;
++ struct ql_rcv_buf_cb *lrg_buf_free_tail;
++ u32 lrg_buf_free_count;
++ u32 lrg_buffer_len;
++ u32 lrg_buf_index;
++ u32 lrg_buf_skb_check;
++
++ /* Small Buffer Queue */
++ u32 small_buf_q_alloc_size;
++ u32 small_buf_q_size;
++ u32 small_buf_q_producer_index;
++ void *small_buf_q_alloc_virt_addr;
++ void *small_buf_q_virt_addr;
++ dma_addr_t small_buf_q_alloc_phy_addr;
++ dma_addr_t small_buf_q_phy_addr;
++ u32 small_buf_index;
++
++ /* Small (Receive) Buffers */
++ void *small_buf_virt_addr;
++ dma_addr_t small_buf_phy_addr;
++ u32 small_buf_phy_addr_low;
++ u32 small_buf_phy_addr_high;
++ u32 small_buf_release_cnt;
++ u32 small_buf_total_size;
++
++ /* ISR related, saves status for DPC. */
++ u32 control_status;
++
++ struct eeprom_data nvram_data;
++ struct timer_list ioctl_timer;
++ u32 port_link_state;
++ u32 last_rsp_offset;
++
++ /* 4022 specific */
++ u32 mac_index; /* Driver's MAC number can be 0 or 1 for first and second networking functions respectively */
++ u32 PHYAddr; /* Address of PHY 0x1e00 Port 0 and 0x1f00 Port 1 */
++ u32 mac_ob_opcode; /* Opcode to use on mac transmission */
++ u32 tcp_ob_opcode; /* Opcode to use on tcp transmission */
++ u32 update_ob_opcode; /* Opcode to use for updating NCB */
++ u32 mb_bit_mask; /* MA Bits mask to use on transmission */
++ u32 numPorts;
++ struct net_device_stats stats;
++ struct workqueue_struct *workqueue;
++ struct work_struct reset_work;
++ struct work_struct tx_timeout_work;
++ u32 max_frame_size;
++};
++
++#endif /* _QLA3XXX_H_ */
+diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
+index 4c2f575..27f90b2 100644
+--- a/drivers/net/r8169.c
++++ b/drivers/net/r8169.c
+@@ -6,26 +6,26 @@
+ History:
+ Feb 4 2002 - created initially by ShuChen <shuchen at realtek.com.tw>.
+ May 20 2002 - Add link status force-mode and TBI mode support.
+- 2004 - Massive updates. See kernel SCM system for details.
++ 2004 - Massive updates. See kernel SCM system for details.
+ =========================================================================
+ 1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
+ Command: 'insmod r8169 media = SET_MEDIA'
+ Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
+-
++
+ SET_MEDIA can be:
+ _10_Half = 0x01
+ _10_Full = 0x02
+ _100_Half = 0x04
+ _100_Full = 0x08
+ _1000_Full = 0x10
+-
++
+ 2. Support TBI mode.
+ =========================================================================
+ VERSION 1.1 <2002/10/4>
+
+ The bit4:0 of MII register 4 is called "selector field", and have to be
+ 00001b to indicate support of IEEE std 802.3 during NWay process of
+- exchanging Link Code Word (FLP).
++ exchanging Link Code Word (FLP).
+
+ VERSION 1.2 <2002/11/30>
+
+@@ -81,10 +81,10 @@ VERSION 2.2LK <2005/01/25>
+
+ #ifdef RTL8169_DEBUG
+ #define assert(expr) \
+- if(!(expr)) { \
+- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+- #expr,__FILE__,__FUNCTION__,__LINE__); \
+- }
++ if (!(expr)) { \
++ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
++ #expr,__FILE__,__FUNCTION__,__LINE__); \
++ }
+ #define dprintk(fmt, args...) do { printk(PFX fmt, ## args); } while (0)
+ #else
+ #define assert(expr) do {} while (0)
+@@ -150,11 +150,16 @@ static const int multicast_filter_limit
+ #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+
+ enum mac_version {
+- RTL_GIGA_MAC_VER_B = 0x00,
+- /* RTL_GIGA_MAC_VER_C = 0x03, */
+- RTL_GIGA_MAC_VER_D = 0x01,
+- RTL_GIGA_MAC_VER_E = 0x02,
+- RTL_GIGA_MAC_VER_X = 0x04 /* Greater than RTL_GIGA_MAC_VER_E */
++ RTL_GIGA_MAC_VER_01 = 0x00,
++ RTL_GIGA_MAC_VER_02 = 0x01,
++ RTL_GIGA_MAC_VER_03 = 0x02,
++ RTL_GIGA_MAC_VER_04 = 0x03,
++ RTL_GIGA_MAC_VER_05 = 0x04,
++ RTL_GIGA_MAC_VER_11 = 0x0b,
++ RTL_GIGA_MAC_VER_12 = 0x0c,
++ RTL_GIGA_MAC_VER_13 = 0x0d,
++ RTL_GIGA_MAC_VER_14 = 0x0e,
++ RTL_GIGA_MAC_VER_15 = 0x0f
+ };
+
+ enum phy_version {
+@@ -166,7 +171,6 @@ enum phy_version {
+ RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */
+ };
+
+-
+ #define _R(NAME,MAC,MASK) \
+ { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+@@ -175,19 +179,45 @@ static const struct {
+ u8 mac_version;
+ u32 RxConfigMask; /* Clears the bits supported by this chip */
+ } rtl_chip_info[] = {
+- _R("RTL8169", RTL_GIGA_MAC_VER_B, 0xff7e1880),
+- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_D, 0xff7e1880),
+- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_E, 0xff7e1880),
+- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_X, 0xff7e1880),
++ _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880),
++ _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_02, 0xff7e1880),
++ _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880),
++ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880),
++ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880),
++ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
++ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
++ _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
++ _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
++ _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880) // PCI-E 8139
+ };
+ #undef _R
+
++enum cfg_version {
++ RTL_CFG_0 = 0x00,
++ RTL_CFG_1,
++ RTL_CFG_2
++};
++
++static const struct {
++ unsigned int region;
++ unsigned int align;
++} rtl_cfg_info[] = {
++ [RTL_CFG_0] = { 1, NET_IP_ALIGN },
++ [RTL_CFG_1] = { 2, NET_IP_ALIGN },
++ [RTL_CFG_2] = { 2, 8 }
++};
++
+ static struct pci_device_id rtl8169_pci_tbl[] = {
+- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
+- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), },
+- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), },
+- { PCI_DEVICE(0x16ec, 0x0116), },
+- { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, },
++ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
++ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
++ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
++ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_2 },
++ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
++ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
++ { PCI_DEVICE(0x1259, 0xc107), 0, 0, RTL_CFG_0 },
++ { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
++ { PCI_VENDOR_ID_LINKSYS, 0x1032,
++ PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+ {0,},
+ };
+
+@@ -257,10 +287,11 @@ enum RTL8169_register_content {
+ RxOK = 0x01,
+
+ /* RxStatusDesc */
+- RxRES = 0x00200000,
+- RxCRC = 0x00080000,
+- RxRUNT = 0x00100000,
+- RxRWT = 0x00400000,
++ RxFOVF = (1 << 23),
++ RxRWT = (1 << 22),
++ RxRES = (1 << 21),
++ RxRUNT = (1 << 20),
++ RxCRC = (1 << 19),
+
+ /* ChipCmdBits */
+ CmdReset = 0x10,
+@@ -326,30 +357,6 @@ enum RTL8169_register_content {
+ LinkStatus = 0x02,
+ FullDup = 0x01,
+
+- /* GIGABIT_PHY_registers */
+- PHY_CTRL_REG = 0,
+- PHY_STAT_REG = 1,
+- PHY_AUTO_NEGO_REG = 4,
+- PHY_1000_CTRL_REG = 9,
+-
+- /* GIGABIT_PHY_REG_BIT */
+- PHY_Restart_Auto_Nego = 0x0200,
+- PHY_Enable_Auto_Nego = 0x1000,
+-
+- /* PHY_STAT_REG = 1 */
+- PHY_Auto_Neco_Comp = 0x0020,
+-
+- /* PHY_AUTO_NEGO_REG = 4 */
+- PHY_Cap_10_Half = 0x0020,
+- PHY_Cap_10_Full = 0x0040,
+- PHY_Cap_100_Half = 0x0080,
+- PHY_Cap_100_Full = 0x0100,
+-
+- /* PHY_1000_CTRL_REG = 9 */
+- PHY_Cap_1000_Full = 0x0200,
+-
+- PHY_Cap_Null = 0x0,
+-
+ /* _MediaType */
+ _10_Half = 0x01,
+ _10_Full = 0x02,
+@@ -433,6 +440,7 @@ struct rtl8169_private {
+ dma_addr_t RxPhyAddr;
+ struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */
+ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
++ unsigned align;
+ unsigned rx_buf_sz;
+ struct timer_list timer;
+ u16 cp_cmd;
+@@ -466,8 +474,7 @@ MODULE_VERSION(RTL8169_VERSION);
+
+ static int rtl8169_open(struct net_device *dev);
+ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
++static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance);
+ static int rtl8169_init_ring(struct net_device *dev);
+ static void rtl8169_hw_start(struct net_device *dev);
+ static int rtl8169_close(struct net_device *dev);
+@@ -488,12 +495,7 @@ static const u16 rtl8169_intr_mask =
+ static const u16 rtl8169_napi_event =
+ RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
+ static const unsigned int rtl8169_rx_config =
+- (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+-
+-#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half
+-#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less
+-#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less
+-#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less
++ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+ static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
+ {
+@@ -503,7 +505,7 @@ static void mdio_write(void __iomem *ioa
+
+ for (i = 20; i > 0; i--) {
+ /* Check if the RTL8169 has completed writing to the specified MII register */
+- if (!(RTL_R32(PHYAR) & 0x80000000))
++ if (!(RTL_R32(PHYAR) & 0x80000000))
+ break;
+ udelay(25);
+ }
+@@ -547,7 +549,7 @@ static unsigned int rtl8169_tbi_reset_pe
+
+ static unsigned int rtl8169_xmii_reset_pending(void __iomem *ioaddr)
+ {
+- return mdio_read(ioaddr, 0) & 0x8000;
++ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
+ }
+
+ static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
+@@ -569,8 +571,8 @@ static void rtl8169_xmii_reset_enable(vo
+ {
+ unsigned int val;
+
+- val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff;
+- mdio_write(ioaddr, PHY_CTRL_REG, val);
++ val = (mdio_read(ioaddr, MII_BMCR) | BMCR_RESET) & 0xffff;
++ mdio_write(ioaddr, MII_BMCR, val);
+ }
+
+ static void rtl8169_check_link_status(struct net_device *dev,
+@@ -608,7 +610,7 @@ static void rtl8169_link_option(int idx,
+ { SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff }
+ }, *p;
+ unsigned char option;
+-
++
+ option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
+
+ if ((option != 0xff) && !idx && netif_msg_drv(&debug))
+@@ -650,9 +652,9 @@ static void rtl8169_get_wol(struct net_d
+ if (options & UWF)
+ wol->wolopts |= WAKE_UCAST;
+ if (options & BWF)
+- wol->wolopts |= WAKE_BCAST;
++ wol->wolopts |= WAKE_BCAST;
+ if (options & MWF)
+- wol->wolopts |= WAKE_MCAST;
++ wol->wolopts |= WAKE_MCAST;
+
+ out_unlock:
+ spin_unlock_irq(&tp->lock);
+@@ -745,38 +747,57 @@ static int rtl8169_set_speed_xmii(struct
+ void __iomem *ioaddr = tp->mmio_addr;
+ int auto_nego, giga_ctrl;
+
+- auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
+- auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full |
+- PHY_Cap_100_Half | PHY_Cap_100_Full);
+- giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG);
+- giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null);
++ auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
++ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
++ ADVERTISE_100HALF | ADVERTISE_100FULL);
++ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
++ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
+ if (autoneg == AUTONEG_ENABLE) {
+- auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full |
+- PHY_Cap_100_Half | PHY_Cap_100_Full);
+- giga_ctrl |= PHY_Cap_1000_Full;
++ auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
++ ADVERTISE_100HALF | ADVERTISE_100FULL);
++ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+ } else {
+ if (speed == SPEED_10)
+- auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full;
++ auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+ else if (speed == SPEED_100)
+- auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full;
++ auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+ else if (speed == SPEED_1000)
+- giga_ctrl |= PHY_Cap_1000_Full;
++ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+
+ if (duplex == DUPLEX_HALF)
+- auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full);
++ auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
+
+ if (duplex == DUPLEX_FULL)
+- auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_100_Half);
++ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
++
++ /* This tweak comes straight from Realtek's driver. */
++ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
++ (tp->mac_version == RTL_GIGA_MAC_VER_13)) {
++ auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
++ }
+ }
+
++ /* The 8100e/8101e do Fast Ethernet only. */
++ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
++ if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
++ netif_msg_link(tp)) {
++ printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
++ dev->name);
++ }
++ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
++ }
++
++ auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
++
+ tp->phy_auto_nego_reg = auto_nego;
+ tp->phy_1000_ctrl_reg = giga_ctrl;
+
+- mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego);
+- mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl);
+- mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego |
+- PHY_Restart_Auto_Nego);
++ mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
++ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
++ mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+ return 0;
+ }
+
+@@ -788,7 +809,7 @@ static int rtl8169_set_speed(struct net_
+
+ ret = tp->set_speed(dev, autoneg, speed, duplex);
+
+- if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
++ if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
+ mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
+
+ return ret;
+@@ -803,7 +824,7 @@ static int rtl8169_set_settings(struct n
+ spin_lock_irqsave(&tp->lock, flags);
+ ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+ spin_unlock_irqrestore(&tp->lock, flags);
+-
++
+ return ret;
+ }
+
+@@ -936,20 +957,20 @@ static void rtl8169_gset_xmii(struct net
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+- SUPPORTED_TP;
++ SUPPORTED_TP;
+
+ cmd->autoneg = 1;
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
+
+- if (tp->phy_auto_nego_reg & PHY_Cap_10_Half)
++ if (tp->phy_auto_nego_reg & ADVERTISE_10HALF)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+- if (tp->phy_auto_nego_reg & PHY_Cap_10_Full)
++ if (tp->phy_auto_nego_reg & ADVERTISE_10FULL)
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+- if (tp->phy_auto_nego_reg & PHY_Cap_100_Half)
++ if (tp->phy_auto_nego_reg & ADVERTISE_100HALF)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+- if (tp->phy_auto_nego_reg & PHY_Cap_100_Full)
++ if (tp->phy_auto_nego_reg & ADVERTISE_100FULL)
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+- if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)
++ if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)
+ cmd->advertising |= ADVERTISED_1000baseT_Full;
+
+ status = RTL_R8(PHYstatus);
+@@ -961,6 +982,11 @@ static void rtl8169_gset_xmii(struct net
+ else if (status & _10bps)
+ cmd->speed = SPEED_10;
+
++ if (status & TxFlowCtrl)
++ cmd->advertising |= ADVERTISED_Asym_Pause;
++ if (status & RxFlowCtrl)
++ cmd->advertising |= ADVERTISED_Pause;
++
+ cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+@@ -981,15 +1007,15 @@ static int rtl8169_get_settings(struct n
+ static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *p)
+ {
+- struct rtl8169_private *tp = netdev_priv(dev);
+- unsigned long flags;
++ struct rtl8169_private *tp = netdev_priv(dev);
++ unsigned long flags;
+
+- if (regs->len > R8169_REGS_SIZE)
+- regs->len = R8169_REGS_SIZE;
++ if (regs->len > R8169_REGS_SIZE)
++ regs->len = R8169_REGS_SIZE;
+
+- spin_lock_irqsave(&tp->lock, flags);
+- memcpy_fromio(p, tp->mmio_addr, regs->len);
+- spin_unlock_irqrestore(&tp->lock, flags);
++ spin_lock_irqsave(&tp->lock, flags);
++ memcpy_fromio(p, tp->mmio_addr, regs->len);
++ spin_unlock_irqrestore(&tp->lock, flags);
+ }
+
+ static u32 rtl8169_get_msglevel(struct net_device *dev)
+@@ -1071,7 +1097,7 @@ static void rtl8169_get_ethtool_stats(st
+ RTL_W32(CounterAddrLow, 0);
+ RTL_W32(CounterAddrHigh, 0);
+
+- data[0] = le64_to_cpu(counters->tx_packets);
++ data[0] = le64_to_cpu(counters->tx_packets);
+ data[1] = le64_to_cpu(counters->rx_packets);
+ data[2] = le64_to_cpu(counters->tx_errors);
+ data[3] = le32_to_cpu(counters->rx_errors);
+@@ -1098,7 +1124,7 @@ static void rtl8169_get_strings(struct n
+ }
+
+
+-static struct ethtool_ops rtl8169_ethtool_ops = {
++static const struct ethtool_ops rtl8169_ethtool_ops = {
+ .get_drvinfo = rtl8169_get_drvinfo,
+ .get_regs_len = rtl8169_get_regs_len,
+ .get_link = ethtool_op_get_link,
+@@ -1131,7 +1157,7 @@ static void rtl8169_write_gmii_reg_bit(v
+ val = mdio_read(ioaddr, reg);
+ val = (bitval == 1) ?
+ val | (bitval << bitnum) : val & ~(0x0001 << bitnum);
+- mdio_write(ioaddr, reg, val & 0xffff);
++ mdio_write(ioaddr, reg, val & 0xffff);
+ }
+
+ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr)
+@@ -1140,10 +1166,16 @@ static void rtl8169_get_mac_version(stru
+ u32 mask;
+ int mac_version;
+ } mac_info[] = {
+- { 0x1 << 28, RTL_GIGA_MAC_VER_X },
+- { 0x1 << 26, RTL_GIGA_MAC_VER_E },
+- { 0x1 << 23, RTL_GIGA_MAC_VER_D },
+- { 0x00000000, RTL_GIGA_MAC_VER_B } /* Catch-all */
++ { 0x38800000, RTL_GIGA_MAC_VER_15 },
++ { 0x38000000, RTL_GIGA_MAC_VER_12 },
++ { 0x34000000, RTL_GIGA_MAC_VER_13 },
++ { 0x30800000, RTL_GIGA_MAC_VER_14 },
++ { 0x30000000, RTL_GIGA_MAC_VER_11 },
++ { 0x18000000, RTL_GIGA_MAC_VER_05 },
++ { 0x10000000, RTL_GIGA_MAC_VER_04 },
++ { 0x04000000, RTL_GIGA_MAC_VER_03 },
++ { 0x00800000, RTL_GIGA_MAC_VER_02 },
++ { 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
+ }, *p = mac_info;
+ u32 reg;
+
+@@ -1155,24 +1187,7 @@ static void rtl8169_get_mac_version(stru
+
+ static void rtl8169_print_mac_version(struct rtl8169_private *tp)
+ {
+- struct {
+- int version;
+- char *msg;
+- } mac_print[] = {
+- { RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" },
+- { RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" },
+- { RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" },
+- { 0, NULL }
+- }, *p;
+-
+- for (p = mac_print; p->msg; p++) {
+- if (tp->mac_version == p->version) {
+- dprintk("mac_version == %s (%04d)\n", p->msg,
+- p->version);
+- return;
+- }
+- }
+- dprintk("mac_version == Unknown\n");
++ dprintk("mac_version = 0x%02x\n", tp->mac_version);
+ }
+
+ static void rtl8169_get_phy_version(struct rtl8169_private *tp, void __iomem *ioaddr)
+@@ -1189,7 +1204,7 @@ static void rtl8169_get_phy_version(stru
+ }, *p = phy_info;
+ u16 reg;
+
+- reg = mdio_read(ioaddr, 3) & 0xffff;
++ reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
+ while ((reg & p->mask) != p->set)
+ p++;
+ tp->phy_version = p->phy_version;
+@@ -1257,7 +1272,7 @@ static void rtl8169_hw_phy_config(struct
+ rtl8169_print_mac_version(tp);
+ rtl8169_print_phy_version(tp);
+
+- if (tp->mac_version <= RTL_GIGA_MAC_VER_B)
++ if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
+ return;
+ if (tp->phy_version >= RTL_GIGA_PHY_VER_H)
+ return;
+@@ -1267,7 +1282,7 @@ static void rtl8169_hw_phy_config(struct
+
+ /* Shazam ! */
+
+- if (tp->mac_version == RTL_GIGA_MAC_VER_X) {
++ if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
+ mdio_write(ioaddr, 31, 0x0001);
+ mdio_write(ioaddr, 9, 0x273a);
+ mdio_write(ioaddr, 14, 0x7bfb);
+@@ -1306,16 +1321,16 @@ static void rtl8169_phy_timer(unsigned l
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned long timeout = RTL8169_PHY_TIMEOUT;
+
+- assert(tp->mac_version > RTL_GIGA_MAC_VER_B);
++ assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
+ assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
+
+- if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
++ if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
+ return;
+
+ spin_lock_irq(&tp->lock);
+
+ if (tp->phy_reset_pending(ioaddr)) {
+- /*
++ /*
+ * A busy loop could burn quite a few cycles on nowadays CPU.
+ * Let's delay the execution of the timer for a few ticks.
+ */
+@@ -1342,7 +1357,7 @@ static inline void rtl8169_delete_timer(
+ struct rtl8169_private *tp = netdev_priv(dev);
+ struct timer_list *timer = &tp->timer;
+
+- if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
++ if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
+ (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+ return;
+
+@@ -1354,7 +1369,7 @@ static inline void rtl8169_request_timer
+ struct rtl8169_private *tp = netdev_priv(dev);
+ struct timer_list *timer = &tp->timer;
+
+- if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
++ if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
+ (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+ return;
+
+@@ -1377,7 +1392,7 @@ static void rtl8169_netpoll(struct net_d
+ struct pci_dev *pdev = tp->pci_dev;
+
+ disable_irq(pdev->irq);
+- rtl8169_interrupt(pdev->irq, dev, NULL);
++ rtl8169_interrupt(pdev->irq, dev);
+ enable_irq(pdev->irq);
+ }
+ #endif
+@@ -1391,23 +1406,87 @@ static void rtl8169_release_board(struct
+ free_netdev(dev);
+ }
+
++static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
++{
++ void __iomem *ioaddr = tp->mmio_addr;
++ static int board_idx = -1;
++ u8 autoneg, duplex;
++ u16 speed;
++
++ board_idx++;
++
++ rtl8169_hw_phy_config(dev);
++
++ dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
++ RTL_W8(0x82, 0x01);
++
++ if (tp->mac_version < RTL_GIGA_MAC_VER_03) {
++ dprintk("Set PCI Latency=0x40\n");
++ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
++ }
++
++ if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
++ dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
++ RTL_W8(0x82, 0x01);
++ dprintk("Set PHY Reg 0x0bh = 0x00h\n");
++ mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
++ }
++
++ rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
++
++ rtl8169_set_speed(dev, autoneg, speed, duplex);
++
++ if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
++ printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
++}
++
++static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct rtl8169_private *tp = netdev_priv(dev);
++ struct mii_ioctl_data *data = if_mii(ifr);
++
++ if (!netif_running(dev))
++ return -ENODEV;
++
++ switch (cmd) {
++ case SIOCGMIIPHY:
++ data->phy_id = 32; /* Internal PHY */
++ return 0;
++
++ case SIOCGMIIREG:
++ data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f);
++ return 0;
++
++ case SIOCSMIIREG:
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in);
++ return 0;
++ }
++ return -EOPNOTSUPP;
++}
++
+ static int __devinit
+-rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
+- void __iomem **ioaddr_out)
++rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+ {
+- void __iomem *ioaddr;
+- struct net_device *dev;
++ const unsigned int region = rtl_cfg_info[ent->driver_data].region;
+ struct rtl8169_private *tp;
+- int rc = -ENOMEM, i, acpi_idle_state = 0, pm_cap;
++ struct net_device *dev;
++ void __iomem *ioaddr;
++ unsigned int i, pm_cap;
++ int rc;
+
+- assert(ioaddr_out != NULL);
++ if (netif_msg_drv(&debug)) {
++ printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
++ MODULENAME, RTL8169_VERSION);
++ }
+
+- /* dev zeroed in alloc_etherdev */
+ dev = alloc_etherdev(sizeof (*tp));
+- if (dev == NULL) {
++ if (!dev) {
+ if (netif_msg_drv(&debug))
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+- goto err_out;
++ rc = -ENOMEM;
++ goto out;
+ }
+
+ SET_MODULE_OWNER(dev);
+@@ -1420,48 +1499,53 @@ rtl8169_init_board(struct pci_dev *pdev,
+ if (rc < 0) {
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "enable failure\n");
+- goto err_out_free_dev;
++ goto err_out_free_dev_1;
+ }
+
+ rc = pci_set_mwi(pdev);
+ if (rc < 0)
+- goto err_out_disable;
++ goto err_out_disable_2;
+
+ /* save power state before pci_enable_device overwrites it */
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap) {
+- u16 pwr_command;
++ u16 pwr_command, acpi_idle_state;
+
+ pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
+ acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+ } else {
+- if (netif_msg_probe(tp))
++ if (netif_msg_probe(tp)) {
+ dev_err(&pdev->dev,
+- "PowerManagement capability not found.\n");
++ "PowerManagement capability not found.\n");
++ }
+ }
+
+ /* make sure PCI base addr 1 is MMIO */
+- if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+- if (netif_msg_probe(tp))
++ if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
++ if (netif_msg_probe(tp)) {
+ dev_err(&pdev->dev,
+- "region #1 not an MMIO resource, aborting\n");
++ "region #%d not an MMIO resource, aborting\n",
++ region);
++ }
+ rc = -ENODEV;
+- goto err_out_mwi;
++ goto err_out_mwi_3;
+ }
++
+ /* check for weird/broken PCI region reporting */
+- if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
+- if (netif_msg_probe(tp))
++ if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
++ if (netif_msg_probe(tp)) {
+ dev_err(&pdev->dev,
+- "Invalid PCI region size(s), aborting\n");
++ "Invalid PCI region size(s), aborting\n");
++ }
+ rc = -ENODEV;
+- goto err_out_mwi;
++ goto err_out_mwi_3;
+ }
+
+ rc = pci_request_regions(pdev, MODULENAME);
+ if (rc < 0) {
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "could not request regions.\n");
+- goto err_out_mwi;
++ goto err_out_mwi_3;
+ }
+
+ tp->cp_cmd = PCIMulRW | RxChkSum;
+@@ -1473,22 +1557,23 @@ rtl8169_init_board(struct pci_dev *pdev,
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc < 0) {
+- if (netif_msg_probe(tp))
++ if (netif_msg_probe(tp)) {
+ dev_err(&pdev->dev,
+- "DMA configuration failed.\n");
+- goto err_out_free_res;
++ "DMA configuration failed.\n");
++ }
++ goto err_out_free_res_4;
+ }
+ }
+
+ pci_set_master(pdev);
+
+ /* ioremap MMIO region */
+- ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
+- if (ioaddr == NULL) {
++ ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
++ if (!ioaddr) {
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+ rc = -EIO;
+- goto err_out_free_res;
++ goto err_out_free_res_4;
+ }
+
+ /* Unneeded ? Don't mess with Mrs. Murphy. */
+@@ -1498,10 +1583,10 @@ rtl8169_init_board(struct pci_dev *pdev,
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+- for (i = 1000; i > 0; i--) {
++ for (i = 100; i > 0; i--) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+- udelay(10);
++ msleep_interruptible(1);
+ }
+
+ /* Identify chip attached to board */
+@@ -1519,8 +1604,8 @@ rtl8169_init_board(struct pci_dev *pdev,
+ /* Unknown chip: assume array element #0, original RTL-8169 */
+ if (netif_msg_probe(tp)) {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+- "unknown chip version, assuming %s\n",
+- rtl_chip_info[0].name);
++ "unknown chip version, assuming %s\n",
++ rtl_chip_info[0].name);
+ }
+ i++;
+ }
+@@ -1531,56 +1616,6 @@ rtl8169_init_board(struct pci_dev *pdev,
+ RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+- *ioaddr_out = ioaddr;
+- *dev_out = dev;
+-out:
+- return rc;
+-
+-err_out_free_res:
+- pci_release_regions(pdev);
+-
+-err_out_mwi:
+- pci_clear_mwi(pdev);
+-
+-err_out_disable:
+- pci_disable_device(pdev);
+-
+-err_out_free_dev:
+- free_netdev(dev);
+-err_out:
+- *ioaddr_out = NULL;
+- *dev_out = NULL;
+- goto out;
+-}
+-
+-static int __devinit
+-rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- struct net_device *dev = NULL;
+- struct rtl8169_private *tp;
+- void __iomem *ioaddr = NULL;
+- static int board_idx = -1;
+- u8 autoneg, duplex;
+- u16 speed;
+- int i, rc;
+-
+- assert(pdev != NULL);
+- assert(ent != NULL);
+-
+- board_idx++;
+-
+- if (netif_msg_drv(&debug)) {
+- printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
+- MODULENAME, RTL8169_VERSION);
+- }
+-
+- rc = rtl8169_init_board(pdev, &dev, &ioaddr);
+- if (rc)
+- return rc;
+-
+- tp = netdev_priv(dev);
+- assert(ioaddr != NULL);
+-
+ if (RTL_R8(PHYstatus) & TBI_Enable) {
+ tp->set_speed = rtl8169_set_speed_tbi;
+ tp->get_settings = rtl8169_gset_tbi;
+@@ -1588,13 +1623,15 @@ rtl8169_init_one(struct pci_dev *pdev, c
+ tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+ tp->link_ok = rtl8169_tbi_link_ok;
+
+- tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */
++ tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
+ } else {
+ tp->set_speed = rtl8169_set_speed_xmii;
+ tp->get_settings = rtl8169_gset_xmii;
+ tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+ tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+ tp->link_ok = rtl8169_xmii_link_ok;
++
++ dev->do_ioctl = rtl8169_ioctl;
+ }
+
+ /* Get MAC address. FIXME: read EEPROM */
+@@ -1632,19 +1669,13 @@ rtl8169_init_one(struct pci_dev *pdev, c
+ tp->intr_mask = 0xffff;
+ tp->pci_dev = pdev;
+ tp->mmio_addr = ioaddr;
++ tp->align = rtl_cfg_info[ent->driver_data].align;
+
+ spin_lock_init(&tp->lock);
+
+ rc = register_netdev(dev);
+- if (rc) {
+- rtl8169_release_board(pdev, dev, ioaddr);
+- return rc;
+- }
+-
+- if (netif_msg_probe(tp)) {
+- printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n",
+- dev->name, rtl_chip_info[tp->chipset].name);
+- }
++ if (rc < 0)
++ goto err_out_unmap_5;
+
+ pci_set_drvdata(pdev, dev);
+
+@@ -1653,38 +1684,29 @@ rtl8169_init_one(struct pci_dev *pdev, c
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+ "IRQ %d\n",
+ dev->name,
+- rtl_chip_info[ent->driver_data].name,
++ rtl_chip_info[tp->chipset].name,
+ dev->base_addr,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+ }
+
+- rtl8169_hw_phy_config(dev);
+-
+- dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+- RTL_W8(0x82, 0x01);
+-
+- if (tp->mac_version < RTL_GIGA_MAC_VER_E) {
+- dprintk("Set PCI Latency=0x40\n");
+- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+- }
++ rtl8169_init_phy(dev, tp);
+
+- if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
+- dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+- RTL_W8(0x82, 0x01);
+- dprintk("Set PHY Reg 0x0bh = 0x00h\n");
+- mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+- }
+-
+- rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
+-
+- rtl8169_set_speed(dev, autoneg, speed, duplex);
+-
+- if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
+- printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
++out:
++ return rc;
+
+- return 0;
++err_out_unmap_5:
++ iounmap(ioaddr);
++err_out_free_res_4:
++ pci_release_regions(pdev);
++err_out_mwi_3:
++ pci_clear_mwi(pdev);
++err_out_disable_2:
++ pci_disable_device(pdev);
++err_out_free_dev_1:
++ free_netdev(dev);
++ goto out;
+ }
+
+ static void __devexit
+@@ -1780,20 +1802,41 @@ rtl8169_hw_start(struct net_device *dev)
+ {
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
++ struct pci_dev *pdev = tp->pci_dev;
+ u32 i;
+
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+- for (i = 1000; i > 0; i--) {
++ for (i = 100; i > 0; i--) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+- udelay(10);
++ msleep_interruptible(1);
++ }
++
++ if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
++ pci_write_config_word(pdev, 0x68, 0x00);
++ pci_write_config_word(pdev, 0x69, 0x08);
+ }
+
++ /* Undocumented stuff. */
++ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
++ u16 cmd;
++
++ /* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */
++ if ((RTL_R8(Config2) & 0x07) & 0x01)
++ RTL_W32(0x7c, 0x0007ffff);
++
++ RTL_W32(0x7c, 0x0007ff00);
++
++ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
++ cmd = cmd & 0xef;
++ pci_write_config_word(pdev, PCI_COMMAND, cmd);
++ }
++
++
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ /* Low hurts. Let's disable the filtering. */
+@@ -1805,32 +1848,40 @@ rtl8169_hw_start(struct net_device *dev)
+ RTL_W32(RxConfig, i);
+
+ /* Set DMA burst size and Interframe Gap Time */
+- RTL_W32(TxConfig,
+- (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
+- TxInterFrameGapShift));
+- tp->cp_cmd |= RTL_R16(CPlusCmd);
+- RTL_W16(CPlusCmd, tp->cp_cmd);
++ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
++ (InterFrameGap << TxInterFrameGapShift));
++
++ tp->cp_cmd |= RTL_R16(CPlusCmd) | PCIMulRW;
+
+- if ((tp->mac_version == RTL_GIGA_MAC_VER_D) ||
+- (tp->mac_version == RTL_GIGA_MAC_VER_E)) {
++ if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+ dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
+ "Bit-3 and bit-14 MUST be 1\n");
+- tp->cp_cmd |= (1 << 14) | PCIMulRW;
+- RTL_W16(CPlusCmd, tp->cp_cmd);
++ tp->cp_cmd |= (1 << 14);
+ }
+
++ RTL_W16(CPlusCmd, tp->cp_cmd);
++
+ /*
+ * Undocumented corner. Supposedly:
+ * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
+ */
+ RTL_W16(IntrMitigate, 0x0000);
+
+- RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
++ /*
++ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
++ * register to be written before TxDescAddrLow to work.
++ * Switching from MMIO to I/O access fixes the issue as well.
++ */
+ RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32));
+- RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
++ RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
+ RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32));
++ RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
++ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+- udelay(10);
++
++ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
++ RTL_R8(IntrMask);
+
+ RTL_W32(RxMissed, 0);
+
+@@ -1910,17 +1961,18 @@ static inline void rtl8169_map_to_asic(s
+ }
+
+ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+- struct RxDesc *desc, int rx_buf_sz)
++ struct RxDesc *desc, int rx_buf_sz,
++ unsigned int align)
+ {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ int ret = 0;
+
+- skb = dev_alloc_skb(rx_buf_sz + NET_IP_ALIGN);
++ skb = dev_alloc_skb(rx_buf_sz + align);
+ if (!skb)
+ goto err_out;
+
+- skb_reserve(skb, NET_IP_ALIGN);
++ skb_reserve(skb, align);
+ *sk_buff = skb;
+
+ mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
+@@ -1953,15 +2005,15 @@ static u32 rtl8169_rx_fill(struct rtl816
+ u32 start, u32 end)
+ {
+ u32 cur;
+-
++
+ for (cur = start; end - cur > 0; cur++) {
+ int ret, i = cur % NUM_RX_DESC;
+
+ if (tp->Rx_skbuff[i])
+ continue;
+-
++
+ ret = rtl8169_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
+- tp->RxDescArray + i, tp->rx_buf_sz);
++ tp->RxDescArray + i, tp->rx_buf_sz, tp->align);
+ if (ret < 0)
+ break;
+ }
+@@ -2169,7 +2221,7 @@ static inline u32 rtl8169_tso_csum(struc
+ if (mss)
+ return LargeSend | ((mss & MSSMask) << MSSShift);
+ }
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ const struct iphdr *ip = skb->nh.iph;
+
+ if (ip->protocol == IPPROTO_TCP)
+@@ -2190,8 +2242,8 @@ static int rtl8169_start_xmit(struct sk_
+ dma_addr_t mapping;
+ u32 status, len;
+ u32 opts1;
+- int ret = 0;
+-
++ int ret = NETDEV_TX_OK;
++
+ if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
+ if (netif_msg_drv(tp)) {
+ printk(KERN_ERR
+@@ -2255,7 +2307,7 @@ out:
+
+ err_stop:
+ netif_stop_queue(dev);
+- ret = 1;
++ ret = NETDEV_TX_BUSY;
+ err_update_stats:
+ tp->stats.tx_dropped++;
+ goto out;
+@@ -2372,16 +2424,17 @@ static inline void rtl8169_rx_csum(struc
+ }
+
+ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
+- struct RxDesc *desc, int rx_buf_sz)
++ struct RxDesc *desc, int rx_buf_sz,
++ unsigned int align)
+ {
+ int ret = -1;
+
+ if (pkt_size < rx_copybreak) {
+ struct sk_buff *skb;
+
+- skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
++ skb = dev_alloc_skb(pkt_size + align);
+ if (skb) {
+- skb_reserve(skb, NET_IP_ALIGN);
++ skb_reserve(skb, align);
+ eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
+ *sk_buff = skb;
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
+@@ -2427,6 +2480,10 @@ rtl8169_rx_interrupt(struct net_device *
+ tp->stats.rx_length_errors++;
+ if (status & RxCRC)
+ tp->stats.rx_crc_errors++;
++ if (status & RxFOVF) {
++ rtl8169_schedule_work(dev, rtl8169_reset_task);
++ tp->stats.rx_fifo_errors++;
++ }
+ rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+ } else {
+ struct sk_buff *skb = tp->Rx_skbuff[entry];
+@@ -2447,13 +2504,13 @@ rtl8169_rx_interrupt(struct net_device *
+ }
+
+ rtl8169_rx_csum(skb, desc);
+-
++
+ pci_dma_sync_single_for_cpu(tp->pci_dev,
+ le64_to_cpu(desc->addr), tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+
+ if (rtl8169_try_rx_copy(&skb, pkt_size, desc,
+- tp->rx_buf_sz)) {
++ tp->rx_buf_sz, tp->align)) {
+ pci_action = pci_unmap_single;
+ tp->Rx_skbuff[entry] = NULL;
+ }
+@@ -2497,7 +2554,7 @@ rtl8169_rx_interrupt(struct net_device *
+
+ /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
+ static irqreturn_t
+-rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++rtl8169_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct rtl8169_private *tp = netdev_priv(dev);
+@@ -2543,7 +2600,7 @@ rtl8169_interrupt(int irq, void *dev_ins
+ __netif_rx_schedule(dev);
+ else if (netif_msg_intr(tp)) {
+ printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
+- dev->name, status);
++ dev->name, status);
+ }
+ break;
+ #else
+@@ -2606,6 +2663,7 @@ static void rtl8169_down(struct net_devi
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned int poll_locked = 0;
++ unsigned int intrmask;
+
+ rtl8169_delete_timer(dev);
+
+@@ -2644,8 +2702,11 @@ core_down:
+ * 2) dev->change_mtu
+ * -> rtl8169_poll can not be issued again and re-enable the
+ * interruptions. Let's simply issue the IRQ down sequence again.
++ *
++ * No loop if hotpluged or major error (0xffff).
+ */
+- if (RTL_R16(IntrMask))
++ intrmask = RTL_R16(IntrMask);
++ if (intrmask && (intrmask != 0xffff))
+ goto core_down;
+
+ rtl8169_tx_clear(tp);
+@@ -2716,6 +2777,15 @@ rtl8169_set_rx_mode(struct net_device *d
+ tmp = rtl8169_rx_config | rx_mode |
+ (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+
++ if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
++ (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
++ mc_filter[0] = 0xffffffff;
++ mc_filter[1] = 0xffffffff;
++ }
++
+ RTL_W32(RxConfig, tmp);
+ RTL_W32(MAR0 + 0, mc_filter[0]);
+ RTL_W32(MAR0 + 4, mc_filter[1]);
+@@ -2741,7 +2811,7 @@ static struct net_device_stats *rtl8169_
+ RTL_W32(RxMissed, 0);
+ spin_unlock_irqrestore(&tp->lock, flags);
+ }
+-
++
+ return &tp->stats;
+ }
+
+@@ -2809,7 +2879,7 @@ static struct pci_driver rtl8169_pci_dri
+ static int __init
+ rtl8169_init_module(void)
+ {
+- return pci_module_init(&rtl8169_pci_driver);
++ return pci_register_driver(&rtl8169_pci_driver);
+ }
+
+ static void __exit
+diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
+index 12cde06..b7ff484 100644
+--- a/drivers/net/rionet.c
++++ b/drivers/net/rionet.c
+@@ -427,7 +427,7 @@ static void rionet_set_msglevel(struct n
+ rnet->msg_enable = value;
+ }
+
+-static struct ethtool_ops rionet_ethtool_ops = {
++static const struct ethtool_ops rionet_ethtool_ops = {
+ .get_drvinfo = rionet_get_drvinfo,
+ .get_msglevel = rionet_get_msglevel,
+ .set_msglevel = rionet_set_msglevel,
+diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
+index c3ed734..d81536f 100644
+--- a/drivers/net/rrunner.c
++++ b/drivers/net/rrunner.c
+@@ -214,13 +214,13 @@ static int __devinit rr_init_one(struct
+
+ out:
+ if (rrpriv->rx_ring)
+- pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring,
++ pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring,
+ rrpriv->rx_ring_dma);
+ if (rrpriv->tx_ring)
+ pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring,
+ rrpriv->tx_ring_dma);
+ if (rrpriv->regs)
+- iounmap(rrpriv->regs);
++ iounmap(rrpriv->regs);
+ if (pdev) {
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+@@ -559,7 +559,7 @@ static int __init rr_init(struct net_dev
+ htons(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA));
+ *(u32 *)(dev->dev_addr+2) =
+ htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4]));
+-
++
+ printk(" MAC: ");
+
+ for (i = 0; i < 5; i++)
+@@ -736,8 +736,8 @@ static int rr_init1(struct net_device *d
+ struct sk_buff *skb = rrpriv->rx_skbuff[i];
+
+ if (skb) {
+- pci_unmap_single(rrpriv->pci_dev,
+- rrpriv->rx_ring[i].addr.addrlo,
++ pci_unmap_single(rrpriv->pci_dev,
++ rrpriv->rx_ring[i].addr.addrlo,
+ dev->mtu + HIPPI_HLEN,
+ PCI_DMA_FROMDEVICE);
+ rrpriv->rx_ring[i].size = 0;
+@@ -792,14 +792,14 @@ static u32 rr_handle_event(struct net_de
+ case E_INTERN_ERR:
+ printk(KERN_ERR "%s: HIPPI Internal NIC error\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+ case E_HOST_ERR:
+ printk(KERN_ERR "%s: Host software error\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+@@ -823,7 +823,7 @@ static u32 rr_handle_event(struct net_de
+ case E_INT_PRTY:
+ printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+@@ -835,28 +835,28 @@ static u32 rr_handle_event(struct net_de
+ printk(KERN_WARNING "%s: Link lost during transmit\n",
+ dev->name);
+ rrpriv->stats.tx_aborted_errors++;
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+ case E_TX_INV_RNG:
+ printk(KERN_ERR "%s: Invalid send ring block\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+ case E_TX_INV_BUF:
+ printk(KERN_ERR "%s: Invalid send buffer address\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+ case E_TX_INV_DSC:
+ printk(KERN_ERR "%s: Invalid descriptor address\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+@@ -910,21 +910,21 @@ static u32 rr_handle_event(struct net_de
+ case E_RX_INV_BUF:
+ printk(KERN_ERR "%s: Invalid receive buffer "
+ "address\n", dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+ case E_RX_INV_DSC:
+ printk(KERN_ERR "%s: Invalid receive descriptor "
+ "address\n", dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+ case E_RNG_BLK:
+ printk(KERN_ERR "%s: Invalid ring block\n",
+ dev->name);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ wmb();
+ break;
+@@ -1011,15 +1011,15 @@ static void rx_int(struct net_device *de
+ if (newskb){
+ dma_addr_t addr;
+
+- pci_unmap_single(rrpriv->pci_dev,
+- desc->addr.addrlo, dev->mtu +
++ pci_unmap_single(rrpriv->pci_dev,
++ desc->addr.addrlo, dev->mtu +
+ HIPPI_HLEN, PCI_DMA_FROMDEVICE);
+ skb = rx_skb;
+ skb_put(skb, pkt_len);
+ rrpriv->rx_skbuff[index] = newskb;
+- addr = pci_map_single(rrpriv->pci_dev,
+- newskb->data,
+- dev->mtu + HIPPI_HLEN,
++ addr = pci_map_single(rrpriv->pci_dev,
++ newskb->data,
++ dev->mtu + HIPPI_HLEN,
+ PCI_DMA_FROMDEVICE);
+ set_rraddr(&desc->addr, addr);
+ } else {
+@@ -1053,7 +1053,7 @@ static void rx_int(struct net_device *de
+ }
+
+
+-static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++static irqreturn_t rr_interrupt(int irq, void *dev_id)
+ {
+ struct rr_private *rrpriv;
+ struct rr_regs __iomem *regs;
+@@ -1199,7 +1199,7 @@ static void rr_timer(unsigned long data)
+
+ if (rr_init1(dev)) {
+ spin_lock_irqsave(&rrpriv->lock, flags);
+- writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
++ writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ ®s->HostCtrl);
+ spin_unlock_irqrestore(&rrpriv->lock, flags);
+ }
+@@ -1291,7 +1291,7 @@ static int rr_open(struct net_device *de
+ }
+
+ netif_stop_queue(dev);
+-
++
+ return ecode;
+ }
+
+@@ -1527,7 +1527,7 @@ static int rr_load_firmware(struct net_d
+ return -EBUSY;
+
+ if (!(readl(®s->HostCtrl) & NIC_HALTED)){
+- printk("%s: Trying to load firmware to a running NIC.\n",
++ printk("%s: Trying to load firmware to a running NIC.\n",
+ dev->name);
+ return -EBUSY;
+ }
+@@ -1660,7 +1660,7 @@ static int rr_ioctl(struct net_device *d
+ gf_out:
+ kfree(image);
+ return error;
+-
++
+ case SIOCRRPFW:
+ if (!capable(CAP_SYS_RAWIO)){
+ return -EPERM;
+@@ -1712,7 +1712,7 @@ static int rr_ioctl(struct net_device *d
+ kfree(oldimage);
+ kfree(image);
+ return error;
+-
++
+ case SIOCRRID:
+ return put_user(0x52523032, (int __user *)rq->ifr_data);
+ default:
+@@ -1736,7 +1736,7 @@ static struct pci_driver rr_driver = {
+
+ static int __init rr_init_module(void)
+ {
+- return pci_module_init(&rr_driver);
++ return pci_register_driver(&rr_driver);
+ }
+
+ static void __exit rr_cleanup_module(void)
+diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h
+index 2c3c91e..9f3e050 100644
+--- a/drivers/net/rrunner.h
++++ b/drivers/net/rrunner.h
+@@ -167,7 +167,7 @@ struct rr_regs {
+ /*
+ * Host control register bits.
+ */
+-
++
+ #define RR_INT 0x01
+ #define RR_CLEAR_INT 0x02
+ #define NO_SWAP 0x04000004
+@@ -238,9 +238,9 @@ struct rr_regs {
+ /*
+ * Receive state
+ *
+- * RoadRunner HIPPI Receive State Register controls and monitors the
++ * RoadRunner HIPPI Receive State Register controls and monitors the
+ * HIPPI receive interface in the NIC. Look at err bits when a HIPPI
+- * receive Error Event occurs.
++ * receive Error Event occurs.
+ */
+
+ #define ENABLE_NEW_CON 0x01
+@@ -700,7 +700,7 @@ struct rr_stats {
+ u32 StatUpdtT;
+ u32 StatUpdtC;
+ u32 WatchDog;
+- u32 Trace;
++ u32 Trace;
+
+ /* Serial HIPPI */
+ u32 LnkRdyEst;
+@@ -829,7 +829,7 @@ struct rr_private
+ */
+ static int rr_init(struct net_device *dev);
+ static int rr_init1(struct net_device *dev);
+-static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t rr_interrupt(int irq, void *dev_id);
+
+ static int rr_open(struct net_device *dev);
+ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev);
+diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
+index 0ef5258..a914fef 100644
+--- a/drivers/net/s2io-regs.h
++++ b/drivers/net/s2io-regs.h
+@@ -656,8 +656,8 @@ typedef struct _XENA_dev_config {
+ u64 rmac_addr_cfg;
+ #define RMAC_ADDR_UCASTn_EN(n) mBIT(0)_n(n)
+ #define RMAC_ADDR_MCASTn_EN(n) mBIT(0)_n(n)
+-#define RMAC_ADDR_BCAST_EN vBIT(0)_48
+-#define RMAC_ADDR_ALL_ADDR_EN vBIT(0)_49
++#define RMAC_ADDR_BCAST_EN vBIT(0)_48
++#define RMAC_ADDR_ALL_ADDR_EN vBIT(0)_49
+ */
+ u64 tmac_ipg_cfg;
+
+diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
+index e72e0e0..33569ec 100644
+--- a/drivers/net/s2io.c
++++ b/drivers/net/s2io.c
+@@ -530,9 +530,9 @@ static int init_shared_mem(struct s2io_n
+ */
+ if (!tmp_p) {
+ mac_control->zerodma_virt_addr = tmp_v;
+- DBG_PRINT(INIT_DBG,
++ DBG_PRINT(INIT_DBG,
+ "%s: Zero DMA address for TxDL. ", dev->name);
+- DBG_PRINT(INIT_DBG,
++ DBG_PRINT(INIT_DBG,
+ "Virtual address %p\n", tmp_v);
+ tmp_v = pci_alloc_consistent(nic->pdev,
+ PAGE_SIZE, &tmp_p);
+@@ -756,7 +756,7 @@ static void free_shared_mem(struct s2io_
+ for (j = 0; j < page_num; j++) {
+ int mem_blks = (j * lst_per_page);
+ if (!mac_control->fifos[i].list_info)
+- return;
++ return;
+ if (!mac_control->fifos[i].list_info[mem_blks].
+ list_virt_addr)
+ break;
+@@ -775,7 +775,7 @@ static void free_shared_mem(struct s2io_
+ pci_free_consistent(nic->pdev, PAGE_SIZE,
+ mac_control->zerodma_virt_addr,
+ (dma_addr_t)0);
+- DBG_PRINT(INIT_DBG,
++ DBG_PRINT(INIT_DBG,
+ "%s: Freeing TxDL with zero DMA addr. ",
+ dev->name);
+ DBG_PRINT(INIT_DBG, "Virtual address %p\n",
+@@ -855,9 +855,10 @@ static int s2io_verify_pci_mode(nic_t *n
+ static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
+ {
+ struct pci_dev *tdev = NULL;
+- while ((tdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
+- if ((tdev->vendor == NEC_VENID) && (tdev->device == NEC_DEVID)){
++ while ((tdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
++ if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
+ if (tdev->bus == s2io_pdev->bus->parent)
++ pci_dev_put(tdev);
+ return 1;
+ }
+ }
+@@ -1276,7 +1277,7 @@ static int init_nic(struct s2io_nic *nic
+ writeq(val64, &bar0->rx_w_round_robin_1);
+ val64 = 0x0200010000010203ULL;
+ writeq(val64, &bar0->rx_w_round_robin_2);
+- val64 = 0x0001020001000001ULL;
++ val64 = 0x0001020001000001ULL;
+ writeq(val64, &bar0->rx_w_round_robin_3);
+ val64 = 0x0203000100000000ULL;
+ writeq(val64, &bar0->rx_w_round_robin_4);
+@@ -2127,7 +2128,7 @@ static struct sk_buff *s2io_txdl_getskb(
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
+ if (!txds->Buffer_Pointer)
+ break;
+- pci_unmap_page(nic->pdev, (dma_addr_t)
++ pci_unmap_page(nic->pdev, (dma_addr_t)
+ txds->Buffer_Pointer,
+ frag->size, PCI_DMA_TODEVICE);
+ }
+@@ -2397,7 +2398,7 @@ static int fill_rx_buffers(struct s2io_n
+ /* Two buffer mode */
+
+ /*
+- * Buffer2 will have L3/L4 header plus
++ * Buffer2 will have L3/L4 header plus
+ * L4 payload
+ */
+ ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
+@@ -2407,7 +2408,7 @@ static int fill_rx_buffers(struct s2io_n
+ /* Buffer-1 will be dummy buffer. Not used */
+ if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
+ ((RxD3_t*)rxdp)->Buffer1_ptr =
+- pci_map_single(nic->pdev,
++ pci_map_single(nic->pdev,
+ ba->ba_1, BUF1_LEN,
+ PCI_DMA_FROMDEVICE);
+ }
+@@ -2509,7 +2510,7 @@ static void free_rxd_blk(struct s2io_nic
+ ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_single(sp->pdev, (dma_addr_t)
+- ((RxD3_t*)rxdp)->Buffer1_ptr,
++ ((RxD3_t*)rxdp)->Buffer1_ptr,
+ l3l4hdr_size + 4,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_single(sp->pdev, (dma_addr_t)
+@@ -2663,7 +2664,7 @@ static void s2io_netpoll(struct net_devi
+ writeq(val64, &bar0->rx_traffic_int);
+ writeq(val64, &bar0->tx_traffic_int);
+
+- /* we need to free up the transmitted skbufs or else netpoll will
++ /* we need to free up the transmitted skbufs or else netpoll will
+ * run out of skbs and will fail and eventually netpoll application such
+ * as netdump will fail.
+ */
+@@ -2903,7 +2904,7 @@ static void s2io_mdio_write(u32 mmd_type
+ {
+ u64 val64 = 0x0;
+ nic_t *sp = dev->priv;
+- XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
++ XENA_dev_config_t __iomem *bar0 = sp->bar0;
+
+ //address transaction
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+@@ -2952,7 +2953,7 @@ static u64 s2io_mdio_read(u32 mmd_type,
+ u64 val64 = 0x0;
+ u64 rval64 = 0x0;
+ nic_t *sp = dev->priv;
+- XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
++ XENA_dev_config_t __iomem *bar0 = sp->bar0;
+
+ /* address transaction */
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+@@ -3209,7 +3210,7 @@ static void alarm_intr_handler(struct s2
+ if (val64 & SERR_SOURCE_ANY) {
+ nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
+ DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
+- DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
++ DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
+ (unsigned long long)val64);
+ netif_stop_queue(dev);
+ schedule_work(&nic->rst_timer_task);
+@@ -3275,7 +3276,7 @@ static void alarm_intr_handler(struct s2
+ * SUCCESS on success and FAILURE on failure.
+ */
+
+-static int wait_for_cmd_complete(void *addr, u64 busy_bit)
++static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
+ {
+ int ret = FAILURE, cnt = 0;
+ u64 val64;
+@@ -3893,7 +3894,7 @@ static int s2io_xmit(struct sk_buff *skb
+ txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
+ }
+ #endif
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ txdp->Control_2 |=
+ (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
+ TXD_TX_CKO_UDP_EN);
+@@ -4028,8 +4029,7 @@ static int s2io_chk_rx_buffers(nic_t *sp
+ return 0;
+ }
+
+-static irqreturn_t
+-s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ nic_t *sp = dev->priv;
+@@ -4062,8 +4062,7 @@ s2io_msi_handle(int irq, void *dev_id, s
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t
+-s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
+ {
+ ring_info_t *ring = (ring_info_t *)dev_id;
+ nic_t *sp = ring->nic;
+@@ -4077,8 +4076,7 @@ s2io_msix_ring_handle(int irq, void *dev
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t
+-s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
+ {
+ fifo_info_t *fifo = (fifo_info_t *)dev_id;
+ nic_t *sp = fifo->nic;
+@@ -4154,7 +4152,6 @@ static void s2io_txpic_intr_handle(nic_t
+ * s2io_isr - ISR handler of the device .
+ * @irq: the irq of the device.
+ * @dev_id: a void pointer to the dev structure of the NIC.
+- * @pt_regs: pointer to the registers pushed on the stack.
+ * Description: This function is the ISR handler of the device. It
+ * identifies the reason for the interrupt and calls the relevant
+ * service routines. As a contongency measure, this ISR allocates the
+@@ -4164,7 +4161,7 @@ static void s2io_txpic_intr_handle(nic_t
+ * IRQ_HANDLED: will be returned if IRQ was handled by this routine
+ * IRQ_NONE: will be returned if interrupt is not from our device
+ */
+-static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t s2io_isr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ nic_t *sp = dev->priv;
+@@ -4302,11 +4299,11 @@ static struct net_device_stats *s2io_get
+ sp->stats.tx_errors =
+ le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
+ sp->stats.rx_errors =
+- le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
++ le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
+ sp->stats.multicast =
+ le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
+ sp->stats.rx_length_errors =
+- le32_to_cpu(mac_control->stats_info->rmac_long_frms);
++ le64_to_cpu(mac_control->stats_info->rmac_long_frms);
+
+ return (&sp->stats);
+ }
+@@ -4816,7 +4813,7 @@ static int read_eeprom(nic_t * sp, int o
+
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
+- SPI_CONTROL_BYTECNT(0x3) |
++ SPI_CONTROL_BYTECNT(0x3) |
+ SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
+ SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
+ val64 |= SPI_CONTROL_REQ;
+@@ -4883,7 +4880,7 @@ static int write_eeprom(nic_t * sp, int
+ writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
+
+ val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
+- SPI_CONTROL_BYTECNT(write_cnt) |
++ SPI_CONTROL_BYTECNT(write_cnt) |
+ SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
+ SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
+ val64 |= SPI_CONTROL_REQ;
+@@ -5646,7 +5643,7 @@ static void s2io_get_ethtool_stats(struc
+ if (stat_info->sw_stat.num_aggregations) {
+ u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
+ int count = 0;
+- /*
++ /*
+ * Since 64-bit divide does not work on all platforms,
+ * do repeated subtraction.
+ */
+@@ -5736,7 +5733,7 @@ static int s2io_ethtool_op_set_tso(struc
+ return 0;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_settings = s2io_ethtool_gset,
+ .set_settings = s2io_ethtool_sset,
+ .get_drvinfo = s2io_ethtool_gdrvinfo,
+@@ -5988,6 +5985,11 @@ static int set_rxd_buffer_pointer(nic_t
+ ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+ } else {
+ *skb = dev_alloc_skb(size);
++ if (!(*skb)) {
++ DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
++ dev->name);
++ return -ENOMEM;
++ }
+ ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ pci_map_single(sp->pdev, (*skb)->data,
+ dev->mtu + 4,
+@@ -6010,7 +6012,11 @@ static int set_rxd_buffer_pointer(nic_t
+ ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+ } else {
+ *skb = dev_alloc_skb(size);
+-
++ if (!(*skb)) {
++ DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
++ dev->name);
++ return -ENOMEM;
++ }
+ ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
+ PCI_DMA_FROMDEVICE);
+@@ -6597,7 +6603,7 @@ static int rx_osm_handler(ring_info_t *r
+ } else {
+ send_up:
+ queue_rx_frame(skb);
+- }
++ }
+ dev->last_rx = jiffies;
+ aggregate:
+ atomic_dec(&sp->rx_bufs_left[ring_no]);
+@@ -6717,7 +6723,7 @@ static int s2io_verify_parm(struct pci_d
+ if ((*dev_intr_type == MSI_X) &&
+ ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
+ (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
+- DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
++ DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
+ "Defaulting to INTA\n");
+ *dev_intr_type = INTA;
+ }
+@@ -6845,7 +6851,7 @@ s2io_init_nic(struct pci_dev *pdev, cons
+ sp->device_type = XFRAME_I_DEVICE;
+
+ sp->lro = lro;
+-
++
+ /* Initialize some PCI/PCI-X fields of the NIC. */
+ s2io_init_pci(sp);
+
+@@ -7233,7 +7239,7 @@ static void __devexit s2io_rem_nic(struc
+
+ int __init s2io_starter(void)
+ {
+- return pci_module_init(&s2io_driver);
++ return pci_register_driver(&s2io_driver);
+ }
+
+ /**
+@@ -7250,7 +7256,7 @@ static void s2io_closer(void)
+ module_init(s2io_starter);
+ module_exit(s2io_closer);
+
+-static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
++static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
+ struct tcphdr **tcp, RxD_t *rxdp)
+ {
+ int ip_off;
+@@ -7312,7 +7318,7 @@ static void initiate_new_session(lro_t *
+ lro->sg_num = 1;
+ lro->total_len = ntohs(ip->tot_len);
+ lro->frags_len = 0;
+- /*
++ /*
+ * check if we saw TCP timestamp. Other consistency checks have
+ * already been done.
+ */
+@@ -7369,12 +7375,12 @@ static void aggregate_new_rx(lro_t *lro,
+ /* Update ack seq no. and window ad(from this pkt) in LRO object */
+ lro->tcp_ack = tcp->ack_seq;
+ lro->window = tcp->window;
+-
++
+ if (lro->saw_ts) {
+ u32 *ptr;
+ /* Update tsecr and tsval from this packet */
+ ptr = (u32 *) (tcp + 1);
+- lro->cur_tsval = *(ptr + 1);
++ lro->cur_tsval = *(ptr + 1);
+ lro->cur_tsecr = *(ptr + 2);
+ }
+ }
+@@ -7409,7 +7415,7 @@ static int verify_l3_l4_lro_capable(lro_
+ return -1;
+ }
+
+- /*
++ /*
+ * Allow only one TCP timestamp option. Don't aggregate if
+ * any other options are detected.
+ */
+@@ -7417,7 +7423,7 @@ static int verify_l3_l4_lro_capable(lro_
+ return -1;
+
+ if (tcp->doff == 8) {
+- ptr = (u8 *)(tcp + 1);
++ ptr = (u8 *)(tcp + 1);
+ while (*ptr == TCPOPT_NOP)
+ ptr++;
+ if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
+@@ -7429,7 +7435,7 @@ static int verify_l3_l4_lro_capable(lro_
+ return -1;
+
+ /* timestamp echo reply should be non-zero */
+- if (*((u32 *)(ptr+6)) == 0)
++ if (*((u32 *)(ptr+6)) == 0)
+ return -1;
+ }
+
+diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
+index 5ed49c3..12b719f 100644
+--- a/drivers/net/s2io.h
++++ b/drivers/net/s2io.h
+@@ -116,179 +116,179 @@ typedef struct {
+ /* The statistics block of Xena */
+ typedef struct stat_block {
+ /* Tx MAC statistics counters. */
+- u32 tmac_data_octets;
+- u32 tmac_frms;
+- u64 tmac_drop_frms;
+- u32 tmac_bcst_frms;
+- u32 tmac_mcst_frms;
+- u64 tmac_pause_ctrl_frms;
+- u32 tmac_ucst_frms;
+- u32 tmac_ttl_octets;
+- u32 tmac_any_err_frms;
+- u32 tmac_nucst_frms;
+- u64 tmac_ttl_less_fb_octets;
+- u64 tmac_vld_ip_octets;
+- u32 tmac_drop_ip;
+- u32 tmac_vld_ip;
+- u32 tmac_rst_tcp;
+- u32 tmac_icmp;
+- u64 tmac_tcp;
+- u32 reserved_0;
+- u32 tmac_udp;
++ __le32 tmac_data_octets;
++ __le32 tmac_frms;
++ __le64 tmac_drop_frms;
++ __le32 tmac_bcst_frms;
++ __le32 tmac_mcst_frms;
++ __le64 tmac_pause_ctrl_frms;
++ __le32 tmac_ucst_frms;
++ __le32 tmac_ttl_octets;
++ __le32 tmac_any_err_frms;
++ __le32 tmac_nucst_frms;
++ __le64 tmac_ttl_less_fb_octets;
++ __le64 tmac_vld_ip_octets;
++ __le32 tmac_drop_ip;
++ __le32 tmac_vld_ip;
++ __le32 tmac_rst_tcp;
++ __le32 tmac_icmp;
++ __le64 tmac_tcp;
++ __le32 reserved_0;
++ __le32 tmac_udp;
+
+ /* Rx MAC Statistics counters. */
+- u32 rmac_data_octets;
+- u32 rmac_vld_frms;
+- u64 rmac_fcs_err_frms;
+- u64 rmac_drop_frms;
+- u32 rmac_vld_bcst_frms;
+- u32 rmac_vld_mcst_frms;
+- u32 rmac_out_rng_len_err_frms;
+- u32 rmac_in_rng_len_err_frms;
+- u64 rmac_long_frms;
+- u64 rmac_pause_ctrl_frms;
+- u64 rmac_unsup_ctrl_frms;
+- u32 rmac_accepted_ucst_frms;
+- u32 rmac_ttl_octets;
+- u32 rmac_discarded_frms;
+- u32 rmac_accepted_nucst_frms;
+- u32 reserved_1;
+- u32 rmac_drop_events;
+- u64 rmac_ttl_less_fb_octets;
+- u64 rmac_ttl_frms;
+- u64 reserved_2;
+- u32 rmac_usized_frms;
+- u32 reserved_3;
+- u32 rmac_frag_frms;
+- u32 rmac_osized_frms;
+- u32 reserved_4;
+- u32 rmac_jabber_frms;
+- u64 rmac_ttl_64_frms;
+- u64 rmac_ttl_65_127_frms;
+- u64 reserved_5;
+- u64 rmac_ttl_128_255_frms;
+- u64 rmac_ttl_256_511_frms;
+- u64 reserved_6;
+- u64 rmac_ttl_512_1023_frms;
+- u64 rmac_ttl_1024_1518_frms;
+- u32 rmac_ip;
+- u32 reserved_7;
+- u64 rmac_ip_octets;
+- u32 rmac_drop_ip;
+- u32 rmac_hdr_err_ip;
+- u32 reserved_8;
+- u32 rmac_icmp;
+- u64 rmac_tcp;
+- u32 rmac_err_drp_udp;
+- u32 rmac_udp;
+- u64 rmac_xgmii_err_sym;
+- u64 rmac_frms_q0;
+- u64 rmac_frms_q1;
+- u64 rmac_frms_q2;
+- u64 rmac_frms_q3;
+- u64 rmac_frms_q4;
+- u64 rmac_frms_q5;
+- u64 rmac_frms_q6;
+- u64 rmac_frms_q7;
+- u16 rmac_full_q3;
+- u16 rmac_full_q2;
+- u16 rmac_full_q1;
+- u16 rmac_full_q0;
+- u16 rmac_full_q7;
+- u16 rmac_full_q6;
+- u16 rmac_full_q5;
+- u16 rmac_full_q4;
+- u32 reserved_9;
+- u32 rmac_pause_cnt;
+- u64 rmac_xgmii_data_err_cnt;
+- u64 rmac_xgmii_ctrl_err_cnt;
+- u32 rmac_err_tcp;
+- u32 rmac_accepted_ip;
++ __le32 rmac_data_octets;
++ __le32 rmac_vld_frms;
++ __le64 rmac_fcs_err_frms;
++ __le64 rmac_drop_frms;
++ __le32 rmac_vld_bcst_frms;
++ __le32 rmac_vld_mcst_frms;
++ __le32 rmac_out_rng_len_err_frms;
++ __le32 rmac_in_rng_len_err_frms;
++ __le64 rmac_long_frms;
++ __le64 rmac_pause_ctrl_frms;
++ __le64 rmac_unsup_ctrl_frms;
++ __le32 rmac_accepted_ucst_frms;
++ __le32 rmac_ttl_octets;
++ __le32 rmac_discarded_frms;
++ __le32 rmac_accepted_nucst_frms;
++ __le32 reserved_1;
++ __le32 rmac_drop_events;
++ __le64 rmac_ttl_less_fb_octets;
++ __le64 rmac_ttl_frms;
++ __le64 reserved_2;
++ __le32 rmac_usized_frms;
++ __le32 reserved_3;
++ __le32 rmac_frag_frms;
++ __le32 rmac_osized_frms;
++ __le32 reserved_4;
++ __le32 rmac_jabber_frms;
++ __le64 rmac_ttl_64_frms;
++ __le64 rmac_ttl_65_127_frms;
++ __le64 reserved_5;
++ __le64 rmac_ttl_128_255_frms;
++ __le64 rmac_ttl_256_511_frms;
++ __le64 reserved_6;
++ __le64 rmac_ttl_512_1023_frms;
++ __le64 rmac_ttl_1024_1518_frms;
++ __le32 rmac_ip;
++ __le32 reserved_7;
++ __le64 rmac_ip_octets;
++ __le32 rmac_drop_ip;
++ __le32 rmac_hdr_err_ip;
++ __le32 reserved_8;
++ __le32 rmac_icmp;
++ __le64 rmac_tcp;
++ __le32 rmac_err_drp_udp;
++ __le32 rmac_udp;
++ __le64 rmac_xgmii_err_sym;
++ __le64 rmac_frms_q0;
++ __le64 rmac_frms_q1;
++ __le64 rmac_frms_q2;
++ __le64 rmac_frms_q3;
++ __le64 rmac_frms_q4;
++ __le64 rmac_frms_q5;
++ __le64 rmac_frms_q6;
++ __le64 rmac_frms_q7;
++ __le16 rmac_full_q3;
++ __le16 rmac_full_q2;
++ __le16 rmac_full_q1;
++ __le16 rmac_full_q0;
++ __le16 rmac_full_q7;
++ __le16 rmac_full_q6;
++ __le16 rmac_full_q5;
++ __le16 rmac_full_q4;
++ __le32 reserved_9;
++ __le32 rmac_pause_cnt;
++ __le64 rmac_xgmii_data_err_cnt;
++ __le64 rmac_xgmii_ctrl_err_cnt;
++ __le32 rmac_err_tcp;
++ __le32 rmac_accepted_ip;
+
+ /* PCI/PCI-X Read transaction statistics. */
+- u32 new_rd_req_cnt;
+- u32 rd_req_cnt;
+- u32 rd_rtry_cnt;
+- u32 new_rd_req_rtry_cnt;
++ __le32 new_rd_req_cnt;
++ __le32 rd_req_cnt;
++ __le32 rd_rtry_cnt;
++ __le32 new_rd_req_rtry_cnt;
+
+ /* PCI/PCI-X Write/Read transaction statistics. */
+- u32 wr_req_cnt;
+- u32 wr_rtry_rd_ack_cnt;
+- u32 new_wr_req_rtry_cnt;
+- u32 new_wr_req_cnt;
+- u32 wr_disc_cnt;
+- u32 wr_rtry_cnt;
++ __le32 wr_req_cnt;
++ __le32 wr_rtry_rd_ack_cnt;
++ __le32 new_wr_req_rtry_cnt;
++ __le32 new_wr_req_cnt;
++ __le32 wr_disc_cnt;
++ __le32 wr_rtry_cnt;
+
+ /* PCI/PCI-X Write / DMA Transaction statistics. */
+- u32 txp_wr_cnt;
+- u32 rd_rtry_wr_ack_cnt;
+- u32 txd_wr_cnt;
+- u32 txd_rd_cnt;
+- u32 rxd_wr_cnt;
+- u32 rxd_rd_cnt;
+- u32 rxf_wr_cnt;
+- u32 txf_rd_cnt;
++ __le32 txp_wr_cnt;
++ __le32 rd_rtry_wr_ack_cnt;
++ __le32 txd_wr_cnt;
++ __le32 txd_rd_cnt;
++ __le32 rxd_wr_cnt;
++ __le32 rxd_rd_cnt;
++ __le32 rxf_wr_cnt;
++ __le32 txf_rd_cnt;
+
+ /* Tx MAC statistics overflow counters. */
+- u32 tmac_data_octets_oflow;
+- u32 tmac_frms_oflow;
+- u32 tmac_bcst_frms_oflow;
+- u32 tmac_mcst_frms_oflow;
+- u32 tmac_ucst_frms_oflow;
+- u32 tmac_ttl_octets_oflow;
+- u32 tmac_any_err_frms_oflow;
+- u32 tmac_nucst_frms_oflow;
+- u64 tmac_vlan_frms;
+- u32 tmac_drop_ip_oflow;
+- u32 tmac_vld_ip_oflow;
+- u32 tmac_rst_tcp_oflow;
+- u32 tmac_icmp_oflow;
+- u32 tpa_unknown_protocol;
+- u32 tmac_udp_oflow;
+- u32 reserved_10;
+- u32 tpa_parse_failure;
++ __le32 tmac_data_octets_oflow;
++ __le32 tmac_frms_oflow;
++ __le32 tmac_bcst_frms_oflow;
++ __le32 tmac_mcst_frms_oflow;
++ __le32 tmac_ucst_frms_oflow;
++ __le32 tmac_ttl_octets_oflow;
++ __le32 tmac_any_err_frms_oflow;
++ __le32 tmac_nucst_frms_oflow;
++ __le64 tmac_vlan_frms;
++ __le32 tmac_drop_ip_oflow;
++ __le32 tmac_vld_ip_oflow;
++ __le32 tmac_rst_tcp_oflow;
++ __le32 tmac_icmp_oflow;
++ __le32 tpa_unknown_protocol;
++ __le32 tmac_udp_oflow;
++ __le32 reserved_10;
++ __le32 tpa_parse_failure;
+
+ /* Rx MAC Statistics overflow counters. */
+- u32 rmac_data_octets_oflow;
+- u32 rmac_vld_frms_oflow;
+- u32 rmac_vld_bcst_frms_oflow;
+- u32 rmac_vld_mcst_frms_oflow;
+- u32 rmac_accepted_ucst_frms_oflow;
+- u32 rmac_ttl_octets_oflow;
+- u32 rmac_discarded_frms_oflow;
+- u32 rmac_accepted_nucst_frms_oflow;
+- u32 rmac_usized_frms_oflow;
+- u32 rmac_drop_events_oflow;
+- u32 rmac_frag_frms_oflow;
+- u32 rmac_osized_frms_oflow;
+- u32 rmac_ip_oflow;
+- u32 rmac_jabber_frms_oflow;
+- u32 rmac_icmp_oflow;
+- u32 rmac_drop_ip_oflow;
+- u32 rmac_err_drp_udp_oflow;
+- u32 rmac_udp_oflow;
+- u32 reserved_11;
+- u32 rmac_pause_cnt_oflow;
+- u64 rmac_ttl_1519_4095_frms;
+- u64 rmac_ttl_4096_8191_frms;
+- u64 rmac_ttl_8192_max_frms;
+- u64 rmac_ttl_gt_max_frms;
+- u64 rmac_osized_alt_frms;
+- u64 rmac_jabber_alt_frms;
+- u64 rmac_gt_max_alt_frms;
+- u64 rmac_vlan_frms;
+- u32 rmac_len_discard;
+- u32 rmac_fcs_discard;
+- u32 rmac_pf_discard;
+- u32 rmac_da_discard;
+- u32 rmac_red_discard;
+- u32 rmac_rts_discard;
+- u32 reserved_12;
+- u32 rmac_ingm_full_discard;
+- u32 reserved_13;
+- u32 rmac_accepted_ip_oflow;
+- u32 reserved_14;
+- u32 link_fault_cnt;
++ __le32 rmac_data_octets_oflow;
++ __le32 rmac_vld_frms_oflow;
++ __le32 rmac_vld_bcst_frms_oflow;
++ __le32 rmac_vld_mcst_frms_oflow;
++ __le32 rmac_accepted_ucst_frms_oflow;
++ __le32 rmac_ttl_octets_oflow;
++ __le32 rmac_discarded_frms_oflow;
++ __le32 rmac_accepted_nucst_frms_oflow;
++ __le32 rmac_usized_frms_oflow;
++ __le32 rmac_drop_events_oflow;
++ __le32 rmac_frag_frms_oflow;
++ __le32 rmac_osized_frms_oflow;
++ __le32 rmac_ip_oflow;
++ __le32 rmac_jabber_frms_oflow;
++ __le32 rmac_icmp_oflow;
++ __le32 rmac_drop_ip_oflow;
++ __le32 rmac_err_drp_udp_oflow;
++ __le32 rmac_udp_oflow;
++ __le32 reserved_11;
++ __le32 rmac_pause_cnt_oflow;
++ __le64 rmac_ttl_1519_4095_frms;
++ __le64 rmac_ttl_4096_8191_frms;
++ __le64 rmac_ttl_8192_max_frms;
++ __le64 rmac_ttl_gt_max_frms;
++ __le64 rmac_osized_alt_frms;
++ __le64 rmac_jabber_alt_frms;
++ __le64 rmac_gt_max_alt_frms;
++ __le64 rmac_vlan_frms;
++ __le32 rmac_len_discard;
++ __le32 rmac_fcs_discard;
++ __le32 rmac_pf_discard;
++ __le32 rmac_da_discard;
++ __le32 rmac_red_discard;
++ __le32 rmac_rts_discard;
++ __le32 reserved_12;
++ __le32 rmac_ingm_full_discard;
++ __le32 reserved_13;
++ __le32 rmac_accepted_ip_oflow;
++ __le32 reserved_14;
++ __le32 link_fault_cnt;
+ u8 buffer[20];
+ swStat_t sw_stat;
+ xpakStat_t xpak_stat;
+@@ -883,10 +883,10 @@ static inline void writeq(u64 val, void
+ }
+ #endif
+
+-/*
+- * Some registers have to be written in a particular order to
+- * expect correct hardware operation. The macro SPECIAL_REG_WRITE
+- * is used to perform such ordered writes. Defines UF (Upper First)
++/*
++ * Some registers have to be written in a particular order to
++ * expect correct hardware operation. The macro SPECIAL_REG_WRITE
++ * is used to perform such ordered writes. Defines UF (Upper First)
+ * and LF (Lower First) will be used to specify the required write order.
+ */
+ #define UF 1
+@@ -992,14 +992,14 @@ static void s2io_init_pci(nic_t * sp);
+ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+ static void s2io_alarm_handle(unsigned long data);
+ static int s2io_enable_msi(nic_t *nic);
+-static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
+ static irqreturn_t
+-s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs);
++s2io_msix_ring_handle(int irq, void *dev_id);
+ static irqreturn_t
+-s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
++s2io_msix_fifo_handle(int irq, void *dev_id);
++static irqreturn_t s2io_isr(int irq, void *dev_id);
+ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static void s2io_set_link(unsigned long data);
+ static int s2io_set_swapper(nic_t * sp);
+ static void s2io_card_down(nic_t *nic);
+diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
+index b2acedb..b269513 100644
+--- a/drivers/net/saa9730.c
++++ b/drivers/net/saa9730.c
+@@ -745,10 +745,9 @@ static int lan_saa9730_rx(struct net_dev
+ return 0;
+ }
+
+-static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct lan_saa9730_private *lp = netdev_priv(dev);
+
+ if (lan_saa9730_debug > 5)
+@@ -1131,7 +1130,7 @@ static struct pci_driver saa9730_driver
+
+ static int __init saa9730_init(void)
+ {
+- return pci_module_init(&saa9730_driver);
++ return pci_register_driver(&saa9730_driver);
+ }
+
+ static void __exit saa9730_cleanup(void)
+diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h
+index a7e9d29..f656f2f 100644
+--- a/drivers/net/saa9730.h
++++ b/drivers/net/saa9730.h
+@@ -34,9 +34,9 @@
+ /* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */
+ #define LAN_SAA9730_PACKET_SIZE 2048
+
+-/*
+- * Number of TX buffers = number of RX buffers = 2, which is fixed according
+- * to HW requirements.
++/*
++ * Number of TX buffers = number of RX buffers = 2, which is fixed according
++ * to HW requirements.
+ */
+ #define LAN_SAA9730_BUFFERS 2
+
+@@ -47,10 +47,10 @@
+ #define LAN_SAA9730_TXM_Q_SIZE 15
+
+ /*
+- * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
+- * packets received.
++ * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
++ * packets received.
+ * If however we receive less than LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
+- * packets, the hardware can timeout after a certain time and still tell
++ * packets, the hardware can timeout after a certain time and still tell
+ * us packets have arrived.
+ * The timeout value in unit of 32 PCI clocks (33Mhz).
+ * The value 200 approximates 0.0002 seconds.
+@@ -79,8 +79,8 @@
+ #define MACCM_10MB 1
+ #define MACCM_MII 2
+
+-/*
+- * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board)
++/*
++ * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board)
+ */
+ #define PHY_CONTROL 0x0
+ #define PHY_STATUS 0x1
+diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
+index 66cf226..b9fa4fb 100644
+--- a/drivers/net/sb1000.c
++++ b/drivers/net/sb1000.c
+@@ -28,7 +28,7 @@
+
+ Small changes to make it work with 2.1.x kernels. Hopefully,
+ nothing major will change before official release of Linux 2.2.
+-
++
+ Merged with 2.2 - Alan Cox
+ */
+
+@@ -84,7 +84,7 @@ extern int sb1000_probe(struct net_devic
+ static int sb1000_open(struct net_device *dev);
+ static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
+ static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t sb1000_interrupt(int irq, void *dev_id);
+ static struct net_device_stats *sb1000_stats(struct net_device *dev);
+ static int sb1000_close(struct net_device *dev);
+
+@@ -143,7 +143,7 @@ sb1000_probe_one(struct pnp_dev *pdev, c
+ unsigned short ioaddr[2], irq;
+ unsigned int serial_number;
+ int error = -ENODEV;
+-
++
+ if (pnp_device_attach(pdev) < 0)
+ return -ENODEV;
+ if (pnp_activate_dev(pdev) < 0)
+@@ -153,12 +153,12 @@ sb1000_probe_one(struct pnp_dev *pdev, c
+ goto out_disable;
+ if (!pnp_irq_valid(pdev, 0))
+ goto out_disable;
+-
++
+ serial_number = pdev->card->serial;
+-
++
+ ioaddr[0] = pnp_port_start(pdev, 0);
+ ioaddr[1] = pnp_port_start(pdev, 0);
+-
++
+ irq = pnp_irq(pdev, 0);
+
+ if (!request_region(ioaddr[0], 16, "sb1000"))
+@@ -172,7 +172,7 @@ sb1000_probe_one(struct pnp_dev *pdev, c
+ goto out_release_regions;
+ }
+
+-
++
+ dev->base_addr = ioaddr[0];
+ /* mem_start holds the second I/O address */
+ dev->mem_start = ioaddr[1];
+@@ -246,7 +246,7 @@ static struct pnp_driver sb1000_driver =
+ .remove = sb1000_remove_one,
+ };
+
+-
++
+ /*
+ * SB1000 hardware routines to be used during open/configuration phases
+ */
+@@ -351,7 +351,7 @@ card_send_command(const int ioaddr[], co
+ return 0;
+ }
+
+-
++
+ /*
+ * SB1000 hardware routines to be used during frame rx interrupt
+ */
+@@ -449,7 +449,7 @@ sb1000_issue_read_command(const int ioad
+ return;
+ }
+
+-
++
+ /*
+ * SB1000 commands for open/configuration
+ */
+@@ -697,7 +697,7 @@ sb1000_set_PIDs(const int ioaddr[], cons
+ return sb1000_end_get_set_command(ioaddr, name);
+ }
+
+-
++
+ static inline void
+ sb1000_print_status_buffer(const char* name, unsigned char st[],
+ unsigned char buffer[], int size)
+@@ -916,7 +916,7 @@ sb1000_error_dpc(struct net_device *dev)
+ return;
+ }
+
+-
++
+ /*
+ * Linux interface functions
+ */
+@@ -1079,24 +1079,18 @@ sb1000_start_xmit(struct sk_buff *skb, s
+ }
+
+ /* SB1000 interrupt handler. */
+-static irqreturn_t sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sb1000_interrupt(int irq, void *dev_id)
+ {
+ char *name;
+ unsigned char st;
+ int ioaddr[2];
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct sb1000_private *lp = netdev_priv(dev);
+
+ const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00};
+ const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00};
+ const int MaxRxErrorCount = 6;
+
+- if (dev == NULL) {
+- printk(KERN_ERR "sb1000_interrupt(): irq %d for unknown device.\n",
+- irq);
+- return IRQ_NONE;
+- }
+-
+ ioaddr[0] = dev->base_addr;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
+@@ -1155,7 +1149,7 @@ static int sb1000_close(struct net_devic
+ printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name);
+
+ netif_stop_queue(dev);
+-
++
+ ioaddr[0] = dev->base_addr;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
+diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
+index 9ab1618..1eae16b 100644
+--- a/drivers/net/sb1250-mac.c
++++ b/drivers/net/sb1250-mac.c
+@@ -294,7 +294,7 @@ static void sbmac_channel_stop(struct sb
+ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
+ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+ static uint64_t sbmac_addr2reg(unsigned char *ptr);
+-static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
++static irqreturn_t sbmac_intr(int irq,void *dev_instance);
+ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+ static void sbmac_setmulti(struct sbmac_softc *sc);
+ static int sbmac_init(struct net_device *dev, int idx);
+@@ -2049,7 +2049,7 @@ static int sbmac_set_duplex(struct sbmac
+ * Return value:
+ * nothing
+ ********************************************************************* */
+-static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
++static irqreturn_t sbmac_intr(int irq,void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct sbmac_softc *sc = netdev_priv(dev);
+@@ -2708,7 +2708,6 @@ static struct net_device_stats *sbmac_ge
+ static void sbmac_set_rx_mode(struct net_device *dev)
+ {
+ unsigned long flags;
+- int msg_flag = 0;
+ struct sbmac_softc *sc = netdev_priv(dev);
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+@@ -2718,22 +2717,14 @@ static void sbmac_set_rx_mode(struct net
+ */
+
+ if (dev->flags & IFF_PROMISC) {
+- /* Unconditionally log net taps. */
+- msg_flag = 1;
+ sbmac_promiscuous_mode(sc,1);
+ }
+ else {
+- msg_flag = 2;
+ sbmac_promiscuous_mode(sc,0);
+ }
+ }
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+- if (msg_flag) {
+- printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n",
+- dev->name,(msg_flag==1)?"en":"dis");
+- }
+-
+ /*
+ * Program the multicasts. Do this every time.
+ */
+@@ -2912,7 +2903,7 @@ sbmac_init_module(void)
+
+ dev = alloc_etherdev(sizeof(struct sbmac_softc));
+ if (!dev)
+- return -ENOMEM; /* return ENOMEM */
++ return -ENOMEM;
+
+ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
+
+diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
+index 01392bc..d9d0a3a 100644
+--- a/drivers/net/seeq8005.c
++++ b/drivers/net/seeq8005.c
+@@ -20,7 +20,7 @@ static const char version[] =
+ /*
+ Sources:
+ SEEQ 8005 databook
+-
++
+ Version history:
+ 1.00 Public release. cosmetic changes (no warnings now)
+ 0.68 Turning per- packet,interrupt debug messages off - testing for release.
+@@ -83,7 +83,7 @@ static int seeq8005_probe1(struct net_de
+ static int seeq8005_open(struct net_device *dev);
+ static void seeq8005_timeout(struct net_device *dev);
+ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
+ static void seeq8005_rx(struct net_device *dev);
+ static int seeq8005_close(struct net_device *dev);
+ static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
+@@ -95,7 +95,7 @@ static void hardware_send_packet(struct
+ extern void seeq8005_init(struct net_device *dev, int startp);
+ static inline void wait_for_buffer(struct net_device *dev);
+
+-
++
+ /* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+@@ -196,11 +196,11 @@ static int __init seeq8005_probe1(struct
+ retval = -ENODEV;
+ goto out;
+ }
+-
++
+ old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
+ old_cfg1 = inw(SEEQ_CFG1);
+ old_dmaar = inw(SEEQ_DMAAR);
+-
++
+ if (net_debug>4) {
+ printk("seeq8005: stat = 0x%04x\n",old_stat);
+ printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
+@@ -208,7 +208,7 @@ static int __init seeq8005_probe1(struct
+ printk("seeq8005: raer = 0x%04x\n",old_rear);
+ printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
+ }
+-
++
+ outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
+ outw( 0, SEEQ_DMAAR); /* set starting PROM address */
+ outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
+@@ -236,7 +236,7 @@ static int __init seeq8005_probe1(struct
+ outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
+ udelay(5);
+ outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+-
++
+ if (net_debug) {
+ printk("seeq8005: prom sum = 0x%08x\n",j);
+ for(j=0; j<32; j+=16) {
+@@ -256,10 +256,10 @@ static int __init seeq8005_probe1(struct
+ }
+ }
+
+-#if 0
+- /*
++#if 0
++ /*
+ * testing the packet buffer memory doesn't work yet
+- * but all other buffer accesses do
++ * but all other buffer accesses do
+ * - fixing is not a priority
+ */
+ if (net_debug>1) { /* test packet buffer memory */
+@@ -309,16 +309,16 @@ static int __init seeq8005_probe1(struct
+ ; /* Do nothing: a user-level program will set it. */
+ else if (dev->irq < 2) { /* "Auto-IRQ" */
+ unsigned long cookie = probe_irq_on();
+-
++
+ outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
+
+ dev->irq = probe_irq_off(cookie);
+-
++
+ if (net_debug >= 2)
+ printk(" autoirq is %d\n", dev->irq);
+ } else if (dev->irq == 2)
+ /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+- * or don't know which one to set.
++ * or don't know which one to set.
+ */
+ dev->irq = 9;
+
+@@ -348,7 +348,7 @@ out:
+ return retval;
+ }
+
+-
++
+ /* Open/initialize the board. This is called (in the current kernel)
+ sometime after booting when the 'ifconfig' program is run.
+
+@@ -404,8 +404,8 @@ static int seeq8005_send_packet(struct s
+
+ /* Block a timer-based transmit from overlapping */
+ netif_stop_queue(dev);
+-
+- hardware_send_packet(dev, buf, length);
++
++ hardware_send_packet(dev, buf, length);
+ dev->trans_start = jiffies;
+ lp->stats.tx_bytes += length;
+ dev_kfree_skb (skb);
+@@ -413,7 +413,7 @@ static int seeq8005_send_packet(struct s
+
+ return 0;
+ }
+-
++
+ /*
+ * wait_for_buffer
+ *
+@@ -426,18 +426,18 @@ inline void wait_for_buffer(struct net_d
+ int ioaddr = dev->base_addr;
+ unsigned long tmp;
+ int status;
+-
++
+ tmp = jiffies + HZ;
+ while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
+ cpu_relax();
+-
++
+ if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
+ outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+ }
+-
++
+ /* The typical workload of the driver:
+ Handle the network interface interrupts. */
+-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+@@ -452,7 +452,7 @@ static irqreturn_t seeq8005_interrupt(in
+ if (net_debug >2) {
+ printk("%s: int, status=0x%04x\n",dev->name,status);
+ }
+-
++
+ if (status & SEEQSTAT_WINDOW_INT) {
+ handled = 1;
+ outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+@@ -500,32 +500,32 @@ static void seeq8005_rx(struct net_devic
+ wait_for_buffer(dev);
+ next_packet = ntohs(inw(SEEQ_BUFFER));
+ pkt_hdr = inw(SEEQ_BUFFER);
+-
++
+ if (net_debug>2) {
+ printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
+ }
+-
++
+ if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
+ return; /* Done for now */
+ }
+-
++
+ if ((pkt_hdr & SEEQPKTS_DONE)==0)
+ break;
+-
++
+ if (next_packet < lp->receive_ptr) {
+ pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
+ } else {
+ pkt_len = next_packet - lp->receive_ptr - 4;
+ }
+-
++
+ if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
+ printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
+ seeq8005_init(dev,1);
+ return;
+ }
+-
++
+ lp->receive_ptr = next_packet;
+-
++
+ if (net_debug>2) {
+ printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
+ }
+@@ -553,9 +553,9 @@ static void seeq8005_rx(struct net_devic
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* align data on 16 byte */
+ buf = skb_put(skb,pkt_len);
+-
++
+ insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
+-
++
+ if (net_debug>2) {
+ char * p = buf;
+ printk("%s: recv ",dev->name);
+@@ -588,7 +588,7 @@ static int seeq8005_close(struct net_dev
+ lp->open_time = 0;
+
+ netif_stop_queue(dev);
+-
++
+ /* Flush the Tx and disable Rx here. */
+ outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+
+@@ -627,7 +627,7 @@ static void set_multicast_list(struct ne
+ * hmm, not even sure if my matching works _anyway_ - seem to be receiving
+ * _everything_ . . .
+ */
+-
++
+ if (num_addrs) { /* Enable promiscuous mode */
+ outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
+ dev->flags|=IFF_PROMISC;
+@@ -642,26 +642,26 @@ void seeq8005_init(struct net_device *de
+ struct net_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ int i;
+-
++
+ outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
+ udelay(5);
+-
++
+ outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+ outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
+ /* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
+ outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
+-
++
+ for(i=0;i<6;i++) { /* set Station address */
+ outb(dev->dev_addr[i], SEEQ_BUFFER);
+ udelay(2);
+ }
+-
++
+ outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
+ outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
+-
++
+ lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
+ outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
+-
++
+ outw( 0x00ff, SEEQ_REA); /* Receive Area End */
+
+ if (net_debug>4) {
+@@ -670,13 +670,13 @@ void seeq8005_init(struct net_device *de
+ outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+ outw( 0, SEEQ_DMAAR);
+ outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
+-
++
+ for(i=0;i<6;i++) {
+ printk("%02x ",inb(SEEQ_BUFFER));
+ }
+ printk("\n");
+ }
+-
++
+ outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
+ outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
+ outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
+@@ -689,9 +689,9 @@ void seeq8005_init(struct net_device *de
+ printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
+ printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
+ printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
+-
++
+ }
+-}
++}
+
+
+ static void hardware_send_packet(struct net_device * dev, char *buf, int length)
+@@ -704,32 +704,32 @@ static void hardware_send_packet(struct
+ if (net_debug>4) {
+ printk("%s: send 0x%04x\n",dev->name,length);
+ }
+-
++
+ /* Set FIFO to writemode and set packet-buffer address */
+ outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+ outw( transmit_ptr, SEEQ_DMAAR);
+-
++
+ /* output SEEQ Packet header barfage */
+ outw( htons(length + 4), SEEQ_BUFFER);
+ outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
+-
++
+ /* blat the buffer */
+ outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
+ /* paranoia !! */
+ outw( 0, SEEQ_BUFFER);
+ outw( 0, SEEQ_BUFFER);
+-
++
+ /* set address of start of transmit chain */
+ outw( transmit_ptr, SEEQ_TPR);
+-
++
+ /* drain FIFO */
+ tmp = jiffies;
+ while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
+ mb();
+-
++
+ /* doit ! */
+ outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+-
++
+ }
+
+
+@@ -758,7 +758,7 @@ void cleanup_module(void)
+ }
+
+ #endif /* MODULE */
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
+diff --git a/drivers/net/seeq8005.h b/drivers/net/seeq8005.h
+index 809ba6d..5dfb009 100644
+--- a/drivers/net/seeq8005.h
++++ b/drivers/net/seeq8005.h
+@@ -1,7 +1,7 @@
+-/*
++/*
+ * defines, etc for the seeq8005
+ */
+-
++
+ /*
+ * This file is distributed under GPL.
+ *
+diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
+index f95a5b0..a833e7f 100644
+--- a/drivers/net/sgiseeq.c
++++ b/drivers/net/sgiseeq.c
+@@ -432,7 +432,7 @@ static inline void sgiseeq_tx(struct net
+ }
+ }
+
+-static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct sgiseeq_private *sp = netdev_priv(dev);
+diff --git a/drivers/net/sgiseeq.h b/drivers/net/sgiseeq.h
+index ebcca68..523104d 100644
+--- a/drivers/net/sgiseeq.h
++++ b/drivers/net/sgiseeq.h
+@@ -16,7 +16,7 @@ struct sgiseeq_rregs {
+ volatile unsigned int collision_tx[2];
+ volatile unsigned int collision_all[2];
+ volatile unsigned int _unused0;
+- volatile unsigned int rflags;
++ volatile unsigned int rflags;
+ };
+
+ struct sgiseeq_regs {
+@@ -73,7 +73,7 @@ struct sgiseeq_regs {
+ #define SEEQ_TCMD_IC 0x02 /* IRQ on collisions */
+ #define SEEQ_TCMD_I16 0x04 /* IRQ after 16 failed attempts to tx frame */
+ #define SEEQ_TCMD_IPT 0x08 /* IRQ when packet successfully transmitted */
+-#define SEEQ_TCMD_RB1 0x20 /* Register bank one w/multi-cast low byte */
++#define SEEQ_TCMD_RB1 0x20 /* Register bank one w/multi-cast low byte */
+ #define SEEQ_TCMD_RB2 0x40 /* Register bank two w/multi-cast high byte */
+
+ /* Seeq8003 control register */
+diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
+index c7832e6..e886e8d 100644
+--- a/drivers/net/shaper.c
++++ b/drivers/net/shaper.c
+@@ -8,12 +8,12 @@
+ * 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.
+- *
+- * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+- * warranty for any of this software. This material is provided
+- * "AS-IS" and at no charge.
+ *
+- *
++ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
++ * warranty for any of this software. This material is provided
++ * "AS-IS" and at no charge.
++ *
++ *
+ * Algorithm:
+ *
+ * Queue Frame:
+@@ -26,7 +26,7 @@
+ *
+ * SHAPER_QLEN Maximum queued frames
+ * SHAPER_LATENCY Bounding latency on a frame. Leaving this latency
+- * window drops the frame. This stops us queueing
++ * window drops the frame. This stops us queueing
+ * frames for a long time and confusing a remote
+ * host.
+ * SHAPER_MAXSLIP Maximum time a priority frame may jump forward.
+@@ -42,8 +42,8 @@
+ * run off a 100-150Hz base clock typically. This gives us a resolution at
+ * 200Kbit/second of about 2Kbit or 256 bytes. Above that our timer
+ * resolution may start to cause much more burstiness in the traffic. We
+- * could avoid a lot of that by calling kick_shaper() at the end of the
+- * tied device transmissions. If you run above about 100K second you
++ * could avoid a lot of that by calling kick_shaper() at the end of the
++ * tied device transmissions. If you run above about 100K second you
+ * may need to tune the supposed speed rate for the right values.
+ *
+ * BUGS:
+@@ -68,7 +68,7 @@
+ * Use skb->cb for private data.
+ * 2000/03 Andi Kleen
+ */
+-
++
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/fcntl.h>
+@@ -87,13 +87,13 @@
+ #include <net/dst.h>
+ #include <net/arp.h>
+
+-struct shaper_cb {
++struct shaper_cb {
+ unsigned long shapeclock; /* Time it should go out */
+ unsigned long shapestamp; /* Stamp for shaper */
+ __u32 shapelatency; /* Latency on frame */
+ __u32 shapelen; /* Frame length in clocks */
+ __u16 shapepend; /* Pending */
+-};
++};
+ #define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb))
+
+ static int sh_debug; /* Debug flag */
+@@ -105,7 +105,7 @@ static void shaper_kick(struct shaper *s
+ /*
+ * Compute clocks on a buffer
+ */
+-
++
+ static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb)
+ {
+ int t=skb->len/shaper->bytespertick;
+@@ -115,9 +115,9 @@ static int shaper_clocks(struct shaper *
+ /*
+ * Set the speed of a shaper. We compute this in bytes per tick since
+ * thats how the machine wants to run. Quoted input is in bits per second
+- * as is traditional (note not BAUD). We assume 8 bit bytes.
++ * as is traditional (note not BAUD). We assume 8 bit bytes.
+ */
+-
++
+ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
+ {
+ shaper->bitspersec=bitspersec;
+@@ -129,40 +129,40 @@ static void shaper_setspeed(struct shape
+ /*
+ * Throw a frame at a shaper.
+ */
+-
++
+
+ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct shaper *shaper = dev->priv;
+ struct sk_buff *ptr;
+-
++
+ spin_lock(&shaper->lock);
+ ptr=shaper->sendq.prev;
+-
++
+ /*
+ * Set up our packet details
+ */
+-
++
+ SHAPERCB(skb)->shapelatency=0;
+ SHAPERCB(skb)->shapeclock=shaper->recovery;
+ if(time_before(SHAPERCB(skb)->shapeclock, jiffies))
+ SHAPERCB(skb)->shapeclock=jiffies;
+ skb->priority=0; /* short term bug fix */
+ SHAPERCB(skb)->shapestamp=jiffies;
+-
++
+ /*
+ * Time slots for this packet.
+ */
+-
++
+ SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb);
+-
++
+ {
+ struct sk_buff *tmp;
+ /*
+ * Up our shape clock by the time pending on the queue
+ * (Should keep this in the shaper as a variable..)
+ */
+- for(tmp=skb_peek(&shaper->sendq); tmp!=NULL &&
++ for(tmp=skb_peek(&shaper->sendq); tmp!=NULL &&
+ tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)
+ SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen;
+ /*
+@@ -191,7 +191,7 @@ static int shaper_start_xmit(struct sk_b
+ /*
+ * Transmit from a shaper
+ */
+-
++
+ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
+ {
+ struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+@@ -218,7 +218,7 @@ static void shaper_queue_xmit(struct sha
+ /*
+ * Timer handler for shaping clock
+ */
+-
++
+ static void shaper_timer(unsigned long data)
+ {
+ struct shaper *shaper = (struct shaper *)data;
+@@ -229,25 +229,25 @@ static void shaper_timer(unsigned long d
+ }
+
+ /*
+- * Kick a shaper queue and try and do something sensible with the
+- * queue.
++ * Kick a shaper queue and try and do something sensible with the
++ * queue.
+ */
+
+ static void shaper_kick(struct shaper *shaper)
+ {
+ struct sk_buff *skb;
+-
++
+ /*
+ * Walk the list (may be empty)
+ */
+-
++
+ while((skb=skb_peek(&shaper->sendq))!=NULL)
+ {
+ /*
+ * Each packet due to go out by now (within an error
+- * of SHAPER_BURST) gets kicked onto the link
++ * of SHAPER_BURST) gets kicked onto the link
+ */
+-
++
+ if(sh_debug)
+ printk("Clock = %ld, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies);
+ if(time_before_eq(SHAPERCB(skb)->shapeclock, jiffies + SHAPER_BURST))
+@@ -255,16 +255,16 @@ static void shaper_kick(struct shaper *s
+ /*
+ * Pull the frame and get interrupts back on.
+ */
+-
++
+ skb_unlink(skb, &shaper->sendq);
+- if (shaper->recovery <
++ if (shaper->recovery <
+ SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen)
+ shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen;
+ /*
+ * Pass on to the physical target device via
+ * our low level packet thrower.
+ */
+-
++
+ SHAPERCB(skb)->shapepend=0;
+ shaper_queue_xmit(shaper, skb); /* Fire */
+ }
+@@ -275,27 +275,27 @@ static void shaper_kick(struct shaper *s
+ /*
+ * Next kick.
+ */
+-
++
+ if(skb!=NULL)
+ mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
+ }
+
+
+ /*
+- * Bring the interface up. We just disallow this until a
++ * Bring the interface up. We just disallow this until a
+ * bind.
+ */
+
+ static int shaper_open(struct net_device *dev)
+ {
+ struct shaper *shaper=dev->priv;
+-
++
+ /*
+ * Can't open until attached.
+ * Also can't open until speed is set, or we'll get
+ * a division by zero.
+ */
+-
++
+ if(shaper->dev==NULL)
+ return -ENODEV;
+ if(shaper->bitspersec==0)
+@@ -306,7 +306,7 @@ static int shaper_open(struct net_device
+ /*
+ * Closing a shaper flushes the queues.
+ */
+-
++
+ static int shaper_close(struct net_device *dev)
+ {
+ struct shaper *shaper=dev->priv;
+@@ -335,7 +335,7 @@ static struct net_device_stats *shaper_g
+ return &sh->stats;
+ }
+
+-static int shaper_header(struct sk_buff *skb, struct net_device *dev,
++static int shaper_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+ {
+ struct shaper *sh=dev->priv;
+@@ -395,7 +395,7 @@ static int shaper_neigh_setup(struct nei
+ n->ops = &arp_broken_ops;
+ n->output = n->ops->output;
+ }
+-#endif
++#endif
+ return 0;
+ }
+
+@@ -407,7 +407,7 @@ static int shaper_neigh_setup_dev(struct
+ p->ucast_probes = 0;
+ p->mcast_probes = 0;
+ }
+-#endif
++#endif
+ return 0;
+ }
+
+@@ -432,7 +432,7 @@ static int shaper_attach(struct net_devi
+ }
+ else
+ shdev->hard_header = NULL;
+-
++
+ if(dev->rebuild_header)
+ {
+ sh->rebuild_header = dev->rebuild_header;
+@@ -440,7 +440,7 @@ static int shaper_attach(struct net_devi
+ }
+ else
+ shdev->rebuild_header = NULL;
+-
++
+ #if 0
+ if(dev->hard_header_cache)
+ {
+@@ -451,7 +451,7 @@ static int shaper_attach(struct net_devi
+ {
+ shdev->hard_header_cache= NULL;
+ }
+-
++
+ if(dev->header_cache_update)
+ {
+ sh->header_cache_update = dev->header_cache_update;
+@@ -464,7 +464,7 @@ static int shaper_attach(struct net_devi
+ shdev->hard_header_cache = NULL;
+ #endif
+ shdev->neigh_setup = shaper_neigh_setup_dev;
+-
++
+ shdev->hard_header_len=dev->hard_header_len;
+ shdev->type=dev->type;
+ shdev->addr_len=dev->addr_len;
+@@ -477,13 +477,13 @@ static int shaper_ioctl(struct net_devic
+ {
+ struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_ifru;
+ struct shaper *sh=dev->priv;
+-
++
+ if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED)
+ {
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ }
+-
++
+ switch(ss->ss_cmd)
+ {
+ case SHAPER_SET_DEV:
+@@ -525,7 +525,7 @@ static void shaper_init_priv(struct net_
+ /*
+ * Add a shaper device to the system
+ */
+-
++
+ static void __init shaper_setup(struct net_device *dev)
+ {
+ /*
+@@ -541,11 +541,11 @@ static void __init shaper_setup(struct n
+ dev->hard_start_xmit = shaper_start_xmit;
+ dev->get_stats = shaper_get_stats;
+ dev->set_multicast_list = NULL;
+-
++
+ /*
+ * Intialise the packet queues
+ */
+-
++
+ /*
+ * Handlers for when we attach to a device.
+ */
+@@ -566,7 +566,7 @@ static void __init shaper_setup(struct n
+ dev->tx_queue_len = 10;
+ dev->flags = 0;
+ }
+-
++
+ static int shapers = 1;
+ #ifdef MODULE
+
+@@ -610,7 +610,7 @@ static int __init shaper_init(void)
+ snprintf(name, IFNAMSIZ, "shaper%d", i);
+ dev = alloc_netdev(sizeof(struct shaper), name,
+ shaper_setup);
+- if (!dev)
++ if (!dev)
+ break;
+
+ if (register_netdev(dev)) {
+diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
+index df0cbeb..aaba458 100644
+--- a/drivers/net/sis190.c
++++ b/drivers/net/sis190.c
+@@ -713,7 +713,7 @@ static void sis190_tx_interrupt(struct n
+ * The interrupt handler does all of the Rx thread work and cleans up after
+ * the Tx thread.
+ */
+-static irqreturn_t sis190_interrupt(int irq, void *__dev, struct pt_regs *regs)
++static irqreturn_t sis190_interrupt(int irq, void *__dev)
+ {
+ struct net_device *dev = __dev;
+ struct sis190_private *tp = netdev_priv(dev);
+@@ -758,7 +758,7 @@ static void sis190_netpoll(struct net_de
+ struct pci_dev *pdev = tp->pci_dev;
+
+ disable_irq(pdev->irq);
+- sis190_interrupt(pdev->irq, dev, NULL);
++ sis190_interrupt(pdev->irq, dev);
+ enable_irq(pdev->irq);
+ }
+ #endif
+@@ -821,9 +821,6 @@ static void sis190_set_rx_mode(struct ne
+ u16 rx_mode;
+
+ if (dev->flags & IFF_PROMISC) {
+- /* Unconditionally log net taps. */
+- net_drv(tp, KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+@@ -1750,7 +1747,7 @@ static void sis190_set_msglevel(struct n
+ tp->msg_enable = value;
+ }
+
+-static struct ethtool_ops sis190_ethtool_ops = {
++static const struct ethtool_ops sis190_ethtool_ops = {
+ .get_settings = sis190_get_settings,
+ .set_settings = sis190_set_settings,
+ .get_drvinfo = sis190_get_drvinfo,
+@@ -1871,7 +1868,7 @@ static struct pci_driver sis190_pci_driv
+
+ static int __init sis190_init_module(void)
+ {
+- return pci_module_init(&sis190_pci_driver);
++ return pci_register_driver(&sis190_pci_driver);
+ }
+
+ static void __exit sis190_cleanup_module(void)
+diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
+index 29ee7ff..fb2b530 100644
+--- a/drivers/net/sis900.c
++++ b/drivers/net/sis900.c
+@@ -1,14 +1,14 @@
+ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
+- Copyright 1999 Silicon Integrated System Corporation
++ Copyright 1999 Silicon Integrated System Corporation
+ Revision: 1.08.10 Apr. 2 2006
+-
++
+ Modified from the driver which is originally written by Donald Becker.
+-
++
+ This software may be used and distributed according to the terms
+ of the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on this skeleton fall under the GPL and must retain
+ the authorship (implicit copyright) notice.
+-
++
+ References:
+ SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+ preliminary Rev. 1.0 Jan. 14, 1998
+@@ -29,7 +29,7 @@
+ Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
+ Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
+ Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
+- Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu at sis.com.tw> some bug fix & 635M/B support
++ Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu at sis.com.tw> some bug fix & 635M/B support
+ Rev 1.07.09 Feb. 9 2001 Dave Jones <davej at suse.de> PCI enable cleanup
+ Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support
+ Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix
+@@ -134,6 +134,7 @@ static const struct mii_chip_info {
+ { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN },
+ { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME},
+ { "ICS LAN PHY", 0x0015, 0xF440, LAN },
++ { "ICS LAN PHY", 0x0143, 0xBC70, LAN },
+ { "NS 83851 PHY", 0x2000, 0x5C20, MIX },
+ { "NS 83847 PHY", 0x2000, 0x5C30, MIX },
+ { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN },
+@@ -217,7 +218,7 @@ static void sis900_init_rx_ring(struct n
+ static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
+ static int sis900_rx(struct net_device *net_dev);
+ static void sis900_finish_xmit (struct net_device *net_dev);
+-static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t sis900_interrupt(int irq, void *dev_instance);
+ static int sis900_close(struct net_device *net_dev);
+ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
+ static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
+@@ -231,12 +232,12 @@ static void sis900_set_capability( struc
+ static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr);
+ static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr);
+ static void sis900_set_mode (long ioaddr, int speed, int duplex);
+-static struct ethtool_ops sis900_ethtool_ops;
++static const struct ethtool_ops sis900_ethtool_ops;
+
+ /**
+ * sis900_get_mac_addr - Get MAC address for stand alone SiS900 model
+ * @pci_dev: the sis900 pci device
+- * @net_dev: the net device to get address for
++ * @net_dev: the net device to get address for
+ *
+ * Older SiS900 and friends, use EEPROM to store MAC address.
+ * MAC address is read from read_eeprom() into @net_dev->dev_addr.
+@@ -249,9 +250,9 @@ static int __devinit sis900_get_mac_addr
+ int i;
+
+ /* check to see if we have sane EEPROM */
+- signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
++ signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
+ if (signature == 0xffff || signature == 0x0000) {
+- printk (KERN_WARNING "%s: Error EERPOM read %x\n",
++ printk (KERN_WARNING "%s: Error EERPOM read %x\n",
+ pci_name(pci_dev), signature);
+ return 0;
+ }
+@@ -266,7 +267,7 @@ static int __devinit sis900_get_mac_addr
+ /**
+ * sis630e_get_mac_addr - Get MAC address for SiS630E model
+ * @pci_dev: the sis900 pci device
+- * @net_dev: the net device to get address for
++ * @net_dev: the net device to get address for
+ *
+ * SiS630E model, use APC CMOS RAM to store MAC address.
+ * APC CMOS RAM is accessed through ISA bridge.
+@@ -293,7 +294,7 @@ static int __devinit sis630e_get_mac_add
+
+ for (i = 0; i < 6; i++) {
+ outb(0x09 + i, 0x70);
+- ((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
++ ((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
+ }
+ pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
+ pci_dev_put(isa_bridge);
+@@ -305,10 +306,10 @@ static int __devinit sis630e_get_mac_add
+ /**
+ * sis635_get_mac_addr - Get MAC address for SIS635 model
+ * @pci_dev: the sis900 pci device
+- * @net_dev: the net device to get address for
++ * @net_dev: the net device to get address for
+ *
+ * SiS635 model, set MAC Reload Bit to load Mac address from APC
+- * to rfdr. rfdr is accessed through rfcr. MAC address is read into
++ * to rfdr. rfdr is accessed through rfcr. MAC address is read into
+ * @net_dev->dev_addr.
+ */
+
+@@ -342,16 +343,16 @@ static int __devinit sis635_get_mac_addr
+ /**
+ * sis96x_get_mac_addr - Get MAC address for SiS962 or SiS963 model
+ * @pci_dev: the sis900 pci device
+- * @net_dev: the net device to get address for
++ * @net_dev: the net device to get address for
+ *
+- * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
++ * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
+ * is shared by
+- * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
+- * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
++ * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
++ * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
+ * by LAN, otherwise is not. After MAC address is read from EEPROM, send
+- * EEDONE signal to refuse EEPROM access by LAN.
+- * The EEPROM map of SiS962 or SiS963 is different to SiS900.
+- * The signature field in SiS962 or SiS963 spec is meaningless.
++ * EEDONE signal to refuse EEPROM access by LAN.
++ * The EEPROM map of SiS962 or SiS963 is different to SiS900.
++ * The signature field in SiS962 or SiS963 spec is meaningless.
+ * MAC address is read into @net_dev->dev_addr.
+ */
+
+@@ -362,7 +363,7 @@ static int __devinit sis96x_get_mac_addr
+ long ee_addr = ioaddr + mear;
+ u32 waittime = 0;
+ int i;
+-
++
+ outl(EEREQ, ee_addr);
+ while(waittime < 2000) {
+ if(inl(ee_addr) & EEGNT) {
+@@ -374,7 +375,7 @@ static int __devinit sis96x_get_mac_addr
+ outl(EEDONE, ee_addr);
+ return 1;
+ } else {
+- udelay(1);
++ udelay(1);
+ waittime ++;
+ }
+ }
+@@ -388,7 +389,7 @@ static int __devinit sis96x_get_mac_addr
+ * @pci_id: the pci device ID
+ *
+ * Check and probe sis900 net device for @pci_dev.
+- * Get mac address according to the chip revision,
++ * Get mac address according to the chip revision,
+ * and assign SiS900-specific entries in the device structure.
+ * ie: sis900_open(), sis900_start_xmit(), sis900_close(), etc.
+ */
+@@ -416,16 +417,16 @@ static int __devinit sis900_probe(struct
+ /* setup various bits in PCI command register */
+ ret = pci_enable_device(pci_dev);
+ if(ret) return ret;
+-
++
+ 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");
+ return i;
+ }
+-
++
+ pci_set_master(pci_dev);
+-
++
+ net_dev = alloc_etherdev(sizeof(struct sis900_private));
+ if (!net_dev)
+ return -ENOMEM;
+@@ -433,7 +434,7 @@ static int __devinit sis900_probe(struct
+ SET_NETDEV_DEV(net_dev, &pci_dev->dev);
+
+ /* We do a request_region() to register /proc/ioports info. */
+- ioaddr = pci_resource_start(pci_dev, 0);
++ ioaddr = pci_resource_start(pci_dev, 0);
+ ret = pci_request_regions(pci_dev, "sis900");
+ if (ret)
+ goto err_out;
+@@ -461,7 +462,7 @@ static int __devinit sis900_probe(struct
+ }
+ sis_priv->rx_ring = (BufferDesc *)ring_space;
+ sis_priv->rx_ring_dma = ring_dma;
+-
++
+ /* The SiS900-specific entries in the device structure. */
+ net_dev->open = &sis900_open;
+ net_dev->hard_start_xmit = &sis900_start_xmit;
+@@ -495,7 +496,7 @@ static int __devinit sis900_probe(struct
+ printk(KERN_DEBUG "%s: detected revision %2.2x, "
+ "trying to get MAC address...\n",
+ dev_name, sis_priv->chipset_rev);
+-
++
+ ret = 0;
+ if (sis_priv->chipset_rev == SIS630E_900_REV)
+ ret = sis630e_get_mac_addr(pci_dev, net_dev);
+@@ -511,7 +512,7 @@ static int __devinit sis900_probe(struct
+ ret = -ENODEV;
+ goto err_unmap_rx;
+ }
+-
++
+ /* 630ET : set the mii access mode as software-mode */
+ if (sis_priv->chipset_rev == SIS630ET_900_REV)
+ outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
+@@ -566,7 +567,7 @@ static int __devinit sis900_probe(struct
+ /**
+ * sis900_mii_probe - Probe MII PHY for sis900
+ * @net_dev: the net device to probe for
+- *
++ *
+ * Search for total of 32 possible mii phy addresses.
+ * Identify and set current phy if found one,
+ * return error if it failed to found.
+@@ -583,7 +584,7 @@ static int __init sis900_mii_probe(struc
+ sis_priv->mii = NULL;
+
+ /* search for total of 32 possible mii phy addresses */
+- for (phy_addr = 0; phy_addr < 32; phy_addr++) {
++ for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+ struct mii_phy * mii_phy = NULL;
+ u16 mii_status;
+ int i;
+@@ -599,7 +600,7 @@ static int __init sis900_mii_probe(struc
+ dev_name, phy_addr);
+ continue;
+ }
+-
++
+ if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING "Cannot allocate mem for struct mii_phy\n");
+ mii_phy = sis_priv->first_mii;
+@@ -611,9 +612,9 @@ static int __init sis900_mii_probe(struc
+ }
+ return 0;
+ }
+-
++
+ mii_phy->phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
+- mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
++ mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
+ mii_phy->phy_addr = phy_addr;
+ mii_phy->status = mii_status;
+ mii_phy->next = sis_priv->mii;
+@@ -634,14 +635,14 @@ static int __init sis900_mii_probe(struc
+ phy_addr);
+ break;
+ }
+-
++
+ if( !mii_chip_table[i].phy_id1 ) {
+ printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
+ dev_name, phy_addr);
+ mii_phy->phy_types = UNKNOWN;
+ }
+ }
+-
++
+ if (sis_priv->mii == NULL) {
+ printk(KERN_INFO "%s: No MII transceivers found!\n", dev_name);
+ return 0;
+@@ -655,7 +656,7 @@ static int __init sis900_mii_probe(struc
+ if ((sis_priv->mii->phy_id0 == 0x001D) &&
+ ((sis_priv->mii->phy_id1&0xFFF0) == 0x8000))
+ status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
+-
++
+ /* workaround for ICS1893 PHY */
+ if ((sis_priv->mii->phy_id0 == 0x0015) &&
+ ((sis_priv->mii->phy_id1&0xFFF0) == 0xF440))
+@@ -680,7 +681,7 @@ static int __init sis900_mii_probe(struc
+ mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22);
+ mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00);
+ mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0);
+- //mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);
++ //mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);
+ }
+
+ if (sis_priv->mii->status & MII_STAT_LINK)
+@@ -703,7 +704,7 @@ static int __init sis900_mii_probe(struc
+ static u16 sis900_default_phy(struct net_device * net_dev)
+ {
+ struct sis900_private * sis_priv = net_dev->priv;
+- struct mii_phy *phy = NULL, *phy_home = NULL,
++ struct mii_phy *phy = NULL, *phy_home = NULL,
+ *default_phy = NULL, *phy_lan = NULL;
+ u16 status;
+
+@@ -739,17 +740,17 @@ static u16 sis900_default_phy(struct net
+ printk(KERN_INFO "%s: Using transceiver found at address %d as default\n",
+ pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
+ }
+-
++
+ sis_priv->mii_info.phy_id = sis_priv->cur_phy;
+
+ status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
+ status &= (~MII_CNTL_ISOLATE);
+
+- mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status);
++ mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status);
+ status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
+ status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
+
+- return status;
++ return status;
+ }
+
+
+@@ -761,15 +762,15 @@ static u16 sis900_default_phy(struct net
+ * Set the media capability of network adapter according to
+ * mii status register. It's necessary before auto-negotiate.
+ */
+-
++
+ static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *phy)
+ {
+ u16 cap;
+ u16 status;
+-
++
+ status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+ status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+-
++
+ cap = MII_NWAY_CSMA_CD |
+ ((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) |
+ ((phy->status & MII_STAT_CAN_TX) ? MII_NWAY_TX:0) |
+@@ -974,7 +975,7 @@ static u16 sis900_reset_phy(struct net_d
+ status = mdio_read(net_dev, phy_addr, MII_STATUS);
+
+ mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET );
+-
++
+ return status;
+ }
+
+@@ -987,7 +988,7 @@ static u16 sis900_reset_phy(struct net_d
+ static void sis900_poll(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- sis900_interrupt(dev->irq, dev, NULL);
++ sis900_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1091,7 +1092,7 @@ sis900_init_rxfilter (struct net_device
+ * sis900_init_tx_ring - Initialize the Tx descriptor ring
+ * @net_dev: the net device to initialize for
+ *
+- * Initialize the Tx descriptor ring,
++ * Initialize the Tx descriptor ring,
+ */
+
+ static void
+@@ -1124,11 +1125,11 @@ sis900_init_tx_ring(struct net_device *n
+ * sis900_init_rx_ring - Initialize the Rx descriptor ring
+ * @net_dev: the net device to initialize for
+ *
+- * Initialize the Rx descriptor ring,
++ * Initialize the Rx descriptor ring,
+ * and pre-allocate recevie buffers (socket buffer)
+ */
+
+-static void
++static void
+ sis900_init_rx_ring(struct net_device *net_dev)
+ {
+ struct sis900_private *sis_priv = net_dev->priv;
+@@ -1238,8 +1239,8 @@ static void sis630_set_eq(struct net_dev
+ max_value+6 : max_value+5;
+ }
+ /* 630B0&B1 rule to determine the equalizer value */
+- if (revision == SIS630A_900_REV &&
+- (sis_priv->host_bridge_rev == SIS630B0 ||
++ if (revision == SIS630A_900_REV &&
++ (sis_priv->host_bridge_rev == SIS630B0 ||
+ sis_priv->host_bridge_rev == SIS630B1)) {
+ if (max_value == 0)
+ eq_value = 3;
+@@ -1253,9 +1254,9 @@ static void sis630_set_eq(struct net_dev
+ mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h);
+ } else {
+ reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
+- if (revision == SIS630A_900_REV &&
+- (sis_priv->host_bridge_rev == SIS630B0 ||
+- sis_priv->host_bridge_rev == SIS630B1))
++ if (revision == SIS630A_900_REV &&
++ (sis_priv->host_bridge_rev == SIS630B0 ||
++ sis_priv->host_bridge_rev == SIS630B1))
+ mdio_write(net_dev, sis_priv->cur_phy, MII_RESV,
+ (reg14h | 0x2200) & 0xBFFF);
+ else
+@@ -1269,7 +1270,7 @@ static void sis630_set_eq(struct net_dev
+ * sis900_timer - sis900 timer routine
+ * @data: pointer to sis900 net device
+ *
+- * On each timer ticks we check two things,
++ * On each timer ticks we check two things,
+ * link status (ON/OFF) and link mode (10/100/Full/Half)
+ */
+
+@@ -1318,12 +1319,12 @@ static void sis900_timer(unsigned long d
+ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+
+ /* Change mode issue */
+- if ((mii_phy->phy_id0 == 0x001D) &&
++ if ((mii_phy->phy_id0 == 0x001D) &&
+ ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
+ sis900_reset_phy(net_dev, sis_priv->cur_phy);
+-
++
+ sis630_set_eq(net_dev, sis_priv->chipset_rev);
+-
++
+ goto LookForLink;
+ }
+ }
+@@ -1428,7 +1429,7 @@ static void sis900_auto_negotiate(struct
+ struct sis900_private *sis_priv = net_dev->priv;
+ int i = 0;
+ u32 status;
+-
++
+ while (i++ < 2)
+ status = mdio_read(net_dev, phy_addr, MII_STATUS);
+
+@@ -1477,7 +1478,7 @@ static void sis900_read_mode(struct net_
+ autoadv = mdio_read(net_dev, phy_addr, MII_ANADV);
+ autorec = mdio_read(net_dev, phy_addr, MII_ANLPAR);
+ status = autoadv & autorec;
+-
++
+ *speed = HW_SPEED_10_MBPS;
+ *duplex = FDX_CAPABLE_HALF_SELECTED;
+
+@@ -1485,7 +1486,7 @@ static void sis900_read_mode(struct net_
+ *speed = HW_SPEED_100_MBPS;
+ if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
+ *duplex = FDX_CAPABLE_FULL_SELECTED;
+-
++
+ sis_priv->autong_complete = 1;
+
+ /* Workaround for Realtek RTL8201 PHY issue */
+@@ -1536,7 +1537,7 @@ static void sis900_tx_timeout(struct net
+ struct sk_buff *skb = sis_priv->tx_skbuff[i];
+
+ if (skb) {
+- pci_unmap_single(sis_priv->pci_dev,
++ pci_unmap_single(sis_priv->pci_dev,
+ sis_priv->tx_ring[i].bufptr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+@@ -1566,7 +1567,7 @@ static void sis900_tx_timeout(struct net
+ * @skb: socket buffer pointer to put the data being transmitted
+ * @net_dev: the net device to transmit with
+ *
+- * Set the transmit buffer descriptor,
++ * Set the transmit buffer descriptor,
+ * and write TxENA to enable transmit state machine.
+ * tell upper layer if the buffer is full
+ */
+@@ -1610,7 +1611,7 @@ sis900_start_xmit(struct sk_buff *skb, s
+ /* dirty_tx is met in the cycle of cur_tx, buffer full */
+ sis_priv->tx_full = 1;
+ netif_stop_queue(net_dev);
+- } else if (count_dirty_tx < NUM_TX_DESC) {
++ } else if (count_dirty_tx < NUM_TX_DESC) {
+ /* Typical path, tell upper layer that more transmission is possible */
+ netif_start_queue(net_dev);
+ } else {
+@@ -1637,11 +1638,11 @@ sis900_start_xmit(struct sk_buff *skb, s
+ * @dev_instance: the client data object
+ * @regs: snapshot of processor context
+ *
+- * The interrupt handler does all of the Rx thread work,
++ * The interrupt handler does all of the Rx thread work,
+ * and cleans up after the Tx thread
+ */
+
+-static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *net_dev = dev_instance;
+ struct sis900_private *sis_priv = net_dev->priv;
+@@ -1689,7 +1690,7 @@ static irqreturn_t sis900_interrupt(int
+ printk(KERN_DEBUG "%s: exiting interrupt, "
+ "interrupt status = 0x%#8.8x.\n",
+ net_dev->name, inl(ioaddr + isr));
+-
++
+ spin_unlock (&sis_priv->lock);
+ return IRQ_RETVAL(handled);
+ }
+@@ -1698,7 +1699,7 @@ static irqreturn_t sis900_interrupt(int
+ * sis900_rx - sis900 receive routine
+ * @net_dev: the net device which receives data
+ *
+- * Process receive interrupt events,
++ * Process receive interrupt events,
+ * put buffer to higher layer and refill buffer pool
+ * Note: This function is called by interrupt handler,
+ * don't do "too much" work here
+@@ -1747,7 +1748,7 @@ static int sis900_rx(struct net_device *
+ sis_priv->stats.rx_length_errors++;
+ if (rx_status & (RXISERR | FAERR))
+ sis_priv->stats.rx_frame_errors++;
+- if (rx_status & CRCERR)
++ if (rx_status & CRCERR)
+ sis_priv->stats.rx_crc_errors++;
+ /* reset buffer descriptor state */
+ sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
+@@ -1759,7 +1760,7 @@ static int sis900_rx(struct net_device *
+ we are working on NULL sk_buff :-( */
+ if (sis_priv->rx_skbuff[entry] == NULL) {
+ if (netif_msg_rx_err(sis_priv))
+- printk(KERN_WARNING "%s: NULL pointer "
++ printk(KERN_WARNING "%s: NULL pointer "
+ "encountered in Rx ring\n"
+ "cur_rx:%4.4d, dirty_rx:%4.4d\n",
+ net_dev->name, sis_priv->cur_rx,
+@@ -1767,8 +1768,8 @@ static int sis900_rx(struct net_device *
+ break;
+ }
+
+- pci_unmap_single(sis_priv->pci_dev,
+- sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
++ pci_unmap_single(sis_priv->pci_dev,
++ sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ /* give the socket buffer to upper layers */
+ skb = sis_priv->rx_skbuff[entry];
+@@ -1805,8 +1806,8 @@ static int sis900_rx(struct net_device *
+ skb->dev = 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->data,
++ sis_priv->rx_ring[entry].bufptr =
++ pci_map_single(sis_priv->pci_dev, skb->data,
+ RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ sis_priv->dirty_rx++;
+ }
+@@ -1853,7 +1854,7 @@ static int sis900_rx(struct net_device *
+ * sis900_finish_xmit - finish up transmission of packets
+ * @net_dev: the net device to be transmitted on
+ *
+- * Check for error condition and free socket buffer etc
++ * Check for error condition and free socket buffer etc
+ * schedule for more transmission as needed
+ * Note: This function is called by interrupt handler,
+ * don't do "too much" work here
+@@ -1901,7 +1902,7 @@ static void sis900_finish_xmit (struct n
+ }
+ /* Free the original skb. */
+ skb = sis_priv->tx_skbuff[entry];
+- pci_unmap_single(sis_priv->pci_dev,
++ pci_unmap_single(sis_priv->pci_dev,
+ sis_priv->tx_ring[entry].bufptr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+@@ -1920,10 +1921,10 @@ static void sis900_finish_xmit (struct n
+ }
+
+ /**
+- * sis900_close - close sis900 device
++ * sis900_close - close sis900 device
+ * @net_dev: the net device to be closed
+ *
+- * Disable interrupts, stop the Tx and Rx Status Machine
++ * Disable interrupts, stop the Tx and Rx Status Machine
+ * free Tx and RX socket buffer
+ */
+
+@@ -1951,7 +1952,7 @@ static int sis900_close(struct net_devic
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ skb = sis_priv->rx_skbuff[i];
+ if (skb) {
+- pci_unmap_single(sis_priv->pci_dev,
++ pci_unmap_single(sis_priv->pci_dev,
+ sis_priv->rx_ring[i].bufptr,
+ RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skb);
+@@ -1961,7 +1962,7 @@ static int sis900_close(struct net_devic
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ skb = sis_priv->tx_skbuff[i];
+ if (skb) {
+- pci_unmap_single(sis_priv->pci_dev,
++ pci_unmap_single(sis_priv->pci_dev,
+ sis_priv->tx_ring[i].bufptr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+@@ -1981,7 +1982,7 @@ static int sis900_close(struct net_devic
+ *
+ * Process ethtool command such as "ehtool -i" to show information
+ */
+-
++
+ static void sis900_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *info)
+ {
+@@ -1997,7 +1998,7 @@ static u32 sis900_get_msglevel(struct ne
+ struct sis900_private *sis_priv = net_dev->priv;
+ return sis_priv->msg_enable;
+ }
+-
++
+ static void sis900_set_msglevel(struct net_device *net_dev, u32 value)
+ {
+ struct sis900_private *sis_priv = net_dev->priv;
+@@ -2047,7 +2048,7 @@ static int sis900_nway_reset(struct net_
+ * but there is no simple way to filter them to only a subset (broadcast,
+ * multicast, unicast or arp).
+ */
+-
++
+ static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
+ {
+ struct sis900_private *sis_priv = net_dev->priv;
+@@ -2072,7 +2073,7 @@ static int sis900_set_wol(struct net_dev
+ pmctrl_bits |= MAGICPKT;
+ if (wol->wolopts & WAKE_PHY)
+ pmctrl_bits |= LINKON;
+-
++
+ outl(pmctrl_bits, pmctrl_addr);
+
+ pci_read_config_dword(sis_priv->pci_dev, CFGPMCSR, &cfgpmcsr);
+@@ -2098,7 +2099,7 @@ static void sis900_get_wol(struct net_de
+ wol->supported = (WAKE_PHY | WAKE_MAGIC);
+ }
+
+-static struct ethtool_ops sis900_ethtool_ops = {
++static const struct ethtool_ops sis900_ethtool_ops = {
+ .get_drvinfo = sis900_get_drvinfo,
+ .get_msglevel = sis900_get_msglevel,
+ .set_msglevel = sis900_set_msglevel,
+@@ -2111,7 +2112,7 @@ static struct ethtool_ops sis900_ethtool
+ };
+
+ /**
+- * mii_ioctl - process MII i/o control command
++ * mii_ioctl - process MII i/o control command
+ * @net_dev: the net device to command for
+ * @rq: parameter for command
+ * @cmd: the i/o command
+@@ -2144,7 +2145,7 @@ static int mii_ioctl(struct net_device *
+ }
+
+ /**
+- * sis900_get_stats - Get sis900 read/write statistics
++ * sis900_get_stats - Get sis900 read/write statistics
+ * @net_dev: the net device to get statistics for
+ *
+ * get tx/rx statistics for sis900
+@@ -2159,7 +2160,7 @@ sis900_get_stats(struct net_device *net_
+ }
+
+ /**
+- * sis900_set_config - Set media type by net_device.set_config
++ * sis900_set_config - Set media type by net_device.set_config
+ * @dev: the net device for media type change
+ * @map: ifmap passed by ifconfig
+ *
+@@ -2169,10 +2170,10 @@ sis900_get_stats(struct net_device *net_
+ */
+
+ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
+-{
++{
+ struct sis900_private *sis_priv = dev->priv;
+ struct mii_phy *mii_phy = sis_priv->mii;
+-
++
+ u16 status;
+
+ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+@@ -2180,10 +2181,10 @@ static int sis900_set_config(struct net_
+ * like a definition or standard for the values of that field.
+ * I think the meaning of those values is device specific. But
+ * since I would like to change the media type via the ifconfig
+- * command I use the definition from linux/netdevice.h
++ * command I use the definition from linux/netdevice.h
+ * (which seems to be different from the ifport(pcmcia) definition) */
+ switch(map->port){
+- case IF_PORT_UNKNOWN: /* use auto here */
++ case IF_PORT_UNKNOWN: /* use auto here */
+ dev->if_port = map->port;
+ /* we are going to change the media type, so the Link
+ * will be temporary down and we need to reflect that
+@@ -2191,10 +2192,10 @@ static int sis900_set_config(struct net_
+ * sensed by the sis_timer procedure, which also does
+ * all the rest for us */
+ netif_carrier_off(dev);
+-
++
+ /* read current state */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+-
++
+ /* enable auto negotiation and reset the negotioation
+ * (I don't really know what the auto negatiotiation
+ * reset really means, but it sounds for me right to
+@@ -2203,54 +2204,54 @@ static int sis900_set_config(struct net_
+ MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+
+ break;
+-
+- case IF_PORT_10BASET: /* 10BaseT */
++
++ case IF_PORT_10BASET: /* 10BaseT */
+ dev->if_port = map->port;
+-
++
+ /* we are going to change the media type, so the Link
+ * will be temporary down and we need to reflect that
+ * here. When the Link comes up again, it will be
+ * sensed by the sis_timer procedure, which also does
+ * all the rest for us */
+ netif_carrier_off(dev);
+-
++
+ /* set Speed to 10Mbps */
+ /* read current state */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+-
++
+ /* disable auto negotiation and force 10MBit mode*/
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, status & ~(MII_CNTL_SPEED |
+ MII_CNTL_AUTO));
+ break;
+-
++
+ case IF_PORT_100BASET: /* 100BaseT */
+- case IF_PORT_100BASETX: /* 100BaseTx */
++ case IF_PORT_100BASETX: /* 100BaseTx */
+ dev->if_port = map->port;
+-
++
+ /* we are going to change the media type, so the Link
+ * will be temporary down and we need to reflect that
+ * here. When the Link comes up again, it will be
+ * sensed by the sis_timer procedure, which also does
+ * all the rest for us */
+ netif_carrier_off(dev);
+-
++
+ /* set Speed to 100Mbps */
+ /* disable auto negotiation and enable 100MBit Mode */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, (status & ~MII_CNTL_SPEED) |
+ MII_CNTL_SPEED);
+-
++
+ break;
+-
++
+ case IF_PORT_10BASE2: /* 10Base2 */
+ case IF_PORT_AUI: /* AUI */
+ case IF_PORT_100BASEFX: /* 100BaseFx */
+ /* These Modes are not supported (are they?)*/
+ return -EOPNOTSUPP;
+ break;
+-
++
+ default:
+ return -EINVAL;
+ }
+@@ -2259,14 +2260,14 @@ static int sis900_set_config(struct net_
+ }
+
+ /**
+- * sis900_mcast_bitnr - compute hashtable index
++ * sis900_mcast_bitnr - compute hashtable index
+ * @addr: multicast address
+ * @revision: revision id of chip
+ *
+ * SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast
+ * hash table, which makes this function a little bit different from other drivers
+ * SiS 900 B0 & 635 M/B uses the most significat 8 bits to index 256 bits
+- * multicast hash table.
++ * multicast hash table.
+ */
+
+ static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision)
+@@ -2282,7 +2283,7 @@ static inline u16 sis900_mcast_bitnr(u8
+ }
+
+ /**
+- * set_rx_mode - Set SiS900 receive mode
++ * set_rx_mode - Set SiS900 receive mode
+ * @net_dev: the net device to be set
+ *
+ * Set SiS900 receive mode for promiscuous, multicast, or broadcast mode.
+@@ -2358,7 +2359,7 @@ static void set_rx_mode(struct net_devic
+ }
+
+ /**
+- * sis900_reset - Reset sis900 MAC
++ * sis900_reset - Reset sis900 MAC
+ * @net_dev: the net device to reset
+ *
+ * reset sis900 MAC and wait until finished
+@@ -2378,7 +2379,7 @@ static void sis900_reset(struct net_devi
+ outl(0, ioaddr + rfcr);
+
+ outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
+-
++
+ /* Check that the chip has finished the reset. */
+ while (status && (i++ < 1000)) {
+ status ^= (inl(isr + ioaddr) & status);
+@@ -2392,7 +2393,7 @@ static void sis900_reset(struct net_devi
+ }
+
+ /**
+- * sis900_remove - Remove sis900 device
++ * sis900_remove - Remove sis900 device
+ * @pci_dev: the pci device to be removed
+ *
+ * remove and release SiS900 net device
+@@ -2495,7 +2496,7 @@ static int __init sis900_init_module(voi
+ printk(version);
+ #endif
+
+- return pci_module_init(&sis900_pci_driver);
++ return pci_register_driver(&sis900_pci_driver);
+ }
+
+ static void __exit sis900_cleanup_module(void)
+diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h
+index 4834e3a..150511a 100644
+--- a/drivers/net/sis900.h
++++ b/drivers/net/sis900.h
+@@ -1,4 +1,4 @@
+-/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900
++/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900
+ * Copyright 1999 Silicon Integrated System Corporation
+ * References:
+ * SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+@@ -49,7 +49,7 @@ enum sis900_command_register_bits {
+
+ enum sis900_configuration_register_bits {
+ DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080,
+- SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010,
++ SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010,
+ PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001,
+ /* 635 & 900B Specific */
+ RND_CNT = 0x00000400, FAIR_BACKOFF = 0x00000200,
+@@ -57,7 +57,7 @@ enum sis900_configuration_register_bits
+ };
+
+ enum sis900_eeprom_access_reigster_bits {
+- MDC = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */
++ MDC = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */
+ EECS = 0x00000008, EECLK = 0x00000004, EEDO = 0x00000002,
+ EEDI = 0x00000001
+ };
+@@ -129,9 +129,9 @@ enum sis900_eeprom_address {
+
+ /* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
+ enum sis900_eeprom_command {
+- EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0,
++ EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0,
+ EEwriteEnable = 0x0130, EEwriteDisable = 0x0100,
+- EEeraseAll = 0x0120, EEwriteAll = 0x0110,
++ EEeraseAll = 0x0120, EEwriteAll = 0x0110,
+ EEaddrMask = 0x013F, EEcmdShift = 16
+ };
+
+@@ -148,7 +148,7 @@ enum sis900_pci_registers {
+
+ /* Power management capabilities bits */
+ enum sis900_cfgpmc_register_bits {
+- PMVER = 0x00070000,
++ PMVER = 0x00070000,
+ DSI = 0x00100000,
+ PMESP = 0xf8000000
+ };
+@@ -238,7 +238,7 @@ enum amd_mii_registers {
+
+ /* MII Control register bit definitions. */
+ enum mii_control_register_bits {
+- MII_CNTL_FDX = 0x0100, MII_CNTL_RST_AUTO = 0x0200,
++ MII_CNTL_FDX = 0x0100, MII_CNTL_RST_AUTO = 0x0200,
+ MII_CNTL_ISOLATE = 0x0400, MII_CNTL_PWRDWN = 0x0800,
+ MII_CNTL_AUTO = 0x1000, MII_CNTL_SPEED = 0x2000,
+ MII_CNTL_LPBK = 0x4000, MII_CNTL_RESET = 0x8000
+@@ -246,8 +246,8 @@ enum mii_control_register_bits {
+
+ /* MII Status register bit */
+ enum mii_status_register_bits {
+- MII_STAT_EXT = 0x0001, MII_STAT_JAB = 0x0002,
+- MII_STAT_LINK = 0x0004, MII_STAT_CAN_AUTO = 0x0008,
++ MII_STAT_EXT = 0x0001, MII_STAT_JAB = 0x0002,
++ MII_STAT_LINK = 0x0004, MII_STAT_CAN_AUTO = 0x0008,
+ MII_STAT_FAULT = 0x0010, MII_STAT_AUTO_DONE = 0x0020,
+ MII_STAT_CAN_T = 0x0800, MII_STAT_CAN_T_FDX = 0x1000,
+ MII_STAT_CAN_TX = 0x2000, MII_STAT_CAN_TX_FDX = 0x4000,
+diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
+index 4265ed9..e5cb5b5 100644
+--- a/drivers/net/sk98lin/skethtool.c
++++ b/drivers/net/sk98lin/skethtool.c
+@@ -581,7 +581,7 @@ static int setRxCsum(struct net_device *
+ return 0;
+ }
+
+-struct ethtool_ops SkGeEthtoolOps = {
++const struct ethtool_ops SkGeEthtoolOps = {
+ .get_settings = getSettings,
+ .set_settings = setSettings,
+ .get_drvinfo = getDriverInfo,
+diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
+index ee62845..d4913c3 100644
+--- a/drivers/net/sk98lin/skge.c
++++ b/drivers/net/sk98lin/skge.c
+@@ -196,8 +196,8 @@ static SK_BOOL BoardAllocMem(SK_AC *pAC)
+ static void BoardFreeMem(SK_AC *pAC);
+ static void BoardInitMem(SK_AC *pAC);
+ static void SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL);
+-static SkIsrRetVar SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
+-static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
++static SkIsrRetVar SkGeIsr(int irq, void *dev_id);
++static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id);
+ static int SkGeOpen(struct SK_NET_DEVICE *dev);
+ static int SkGeClose(struct SK_NET_DEVICE *dev);
+ static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+@@ -248,7 +248,7 @@ static void DumpLong(char*, int);
+
+ /* global variables *********************************************************/
+ static SK_BOOL DoPrintInterfaceChange = SK_TRUE;
+-extern struct ethtool_ops SkGeEthtoolOps;
++extern const struct ethtool_ops SkGeEthtoolOps;
+
+ /* local variables **********************************************************/
+ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
+@@ -880,7 +880,7 @@ int PortIndex) /* index of the port for
+ * Returns: N/A
+ *
+ */
+-static SkIsrRetVar SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
++static SkIsrRetVar SkGeIsr(int irq, void *dev_id)
+ {
+ struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+ DEV_NET *pNet;
+@@ -1029,7 +1029,7 @@ SK_U32 IntSrc; /* interrupts source re
+ * Returns: N/A
+ *
+ */
+-static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
++static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id)
+ {
+ struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+ DEV_NET *pNet;
+@@ -1140,7 +1140,7 @@ SK_U32 IntSrc; /* interrupts source re
+ static void SkGePollController(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- SkGeIsr(dev->irq, dev, NULL);
++ SkGeIsr(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1559,7 +1559,7 @@ struct sk_buff *pMessage) /* pointer to
+ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+ pTxd->pMBuf = pMessage;
+
+- if (pMessage->ip_summed == CHECKSUM_HW) {
++ if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+ u16 hdrlen = pMessage->h.raw - pMessage->data;
+ u16 offset = hdrlen + pMessage->csum;
+
+@@ -1678,7 +1678,7 @@ struct sk_buff *pMessage) /* pointer to
+ /*
+ ** Does the HW need to evaluate checksum for TCP or UDP packets?
+ */
+- if (pMessage->ip_summed == CHECKSUM_HW) {
++ if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+ u16 hdrlen = pMessage->h.raw - pMessage->data;
+ u16 offset = hdrlen + pMessage->csum;
+
+@@ -2158,7 +2158,7 @@ rx_start:
+
+ #ifdef USE_SK_RX_CHECKSUM
+ pMsg->csum = pRxd->TcpSums & 0xffff;
+- pMsg->ip_summed = CHECKSUM_HW;
++ pMsg->ip_summed = CHECKSUM_COMPLETE;
+ #else
+ pMsg->ip_summed = CHECKSUM_NONE;
+ #endif
+@@ -5133,7 +5133,7 @@ static struct pci_driver skge_driver = {
+
+ static int __init skge_init(void)
+ {
+- return pci_module_init(&skge_driver);
++ return pci_register_driver(&skge_driver);
+ }
+
+ static void __exit skge_exit(void)
+diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
+index 799e098..96e06c5 100644
+--- a/drivers/net/sk_mca.c
++++ b/drivers/net/sk_mca.c
+@@ -1,4 +1,4 @@
+-/*
++/*
+ net-3-driver for the SKNET MCA-based cards
+
+ This is an extension to the Linux operating system, and is covered by the
+@@ -10,9 +10,9 @@ Copyright 1999 by Alfred Arnold (alfred@
+ This driver is based both on the 3C523 driver and the SK_G16 driver.
+
+ paper sources:
+- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
++ 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
+ Hans-Peter Messmer for the basic Microchannel stuff
+-
++
+ 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
+ for help on Ethernet driver programming
+
+@@ -24,7 +24,7 @@ paper sources:
+
+ 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
+ documentation on the MC2 bord
+-
++
+ A big thank you to the S&K support for providing me so quickly with
+ documentation!
+
+@@ -34,7 +34,7 @@ paper sources:
+
+ -> set debug level via ioctl instead of compile-time switches
+ -> I didn't follow the development of the 2.1.x kernels, so my
+- assumptions about which things changed with which kernel version
++ assumptions about which things changed with which kernel version
+ are probably nonsense
+
+ History:
+@@ -57,7 +57,7 @@ History:
+ fixed problem in GetLANCE leaving interrupts turned off
+ increase TX queue to 4 packets to improve send performance
+ May 29th, 1999
+- a few corrections in statistics, caught rcvr overruns
++ a few corrections in statistics, caught rcvr overruns
+ reinitialization of LANCE/board in critical situations
+ MCA info implemented
+ implemented LANCE multicast filter
+@@ -427,7 +427,7 @@ static void InitLANCE(struct net_device
+ InitDscrs(dev);
+
+ /* next RX descriptor to be read is the first one. Since the LANCE
+- will start from the beginning after initialization, we have to
++ will start from the beginning after initialization, we have to
+ reset out pointers too. */
+
+ priv->nextrx = 0;
+@@ -732,7 +732,7 @@ static u16 irqtx_handler(struct net_devi
+
+ /* general interrupt entry */
+
+-static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs)
++static irqreturn_t irq_handler(int irq, void *device)
+ {
+ struct net_device *dev = (struct net_device *) device;
+ u16 csr0val;
+@@ -868,7 +868,7 @@ static int skmca_tx(struct sk_buff *skb,
+ int tmplen, retval = 0;
+ unsigned long flags;
+
+- /* if we get called with a NULL descriptor, the Ethernet layer thinks
++ /* if we get called with a NULL descriptor, the Ethernet layer thinks
+ our card is stuck an we should reset it. We'll do this completely: */
+
+ if (skb == NULL) {
+@@ -896,7 +896,7 @@ static int skmca_tx(struct sk_buff *skb,
+ tmplen = 60;
+ descr.Len = 65536 - tmplen;
+
+- /* copy filler into RAM - in case we're filling up...
++ /* copy filler into RAM - in case we're filling up...
+ we're filling a bit more than necessary, but that doesn't harm
+ since the buffer is far larger... */
+ if (tmplen > skb->len) {
+diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
+index d6fa182..0dae056 100644
+--- a/drivers/net/sk_mca.h
++++ b/drivers/net/sk_mca.h
+@@ -25,11 +25,11 @@ typedef struct {
+ int nextrx; /* index of next RX descriptor to
+ be read */
+ int nexttxput; /* index of next free TX descriptor */
+- int nexttxdone; /* index of next TX descriptor to
++ int nexttxdone; /* index of next TX descriptor to
+ be finished */
+ int txbusy; /* # of busy TX descriptors */
+ struct net_device_stats stat; /* packet statistics */
+- int realirq; /* memorizes actual IRQ, even when
++ int realirq; /* memorizes actual IRQ, even when
+ currently not allocated */
+ skmca_medium medium; /* physical cannector */
+ spinlock_t lock;
+diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
+index b5714a6..9733a11 100644
+--- a/drivers/net/skfp/skfddi.c
++++ b/drivers/net/skfp/skfddi.c
+@@ -101,7 +101,7 @@ static const char * const boot_msg =
+ static int skfp_driver_init(struct net_device *dev);
+ static int skfp_open(struct net_device *dev);
+ static int skfp_close(struct net_device *dev);
+-static irqreturn_t skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t skfp_interrupt(int irq, void *dev_id);
+ static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev);
+ static void skfp_ctl_set_multicast_list(struct net_device *dev);
+ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev);
+@@ -593,7 +593,6 @@ static int skfp_close(struct net_device
+ * Arguments:
+ * irq - interrupt vector
+ * dev_id - pointer to device information
+- * regs - pointer to registers structure
+ *
+ * Functional Description:
+ * This routine calls the interrupt processing routine for this adapter. It
+@@ -615,17 +614,12 @@ static int skfp_close(struct net_device
+ * Interrupts are disabled, then reenabled at the adapter.
+ */
+
+-irqreturn_t skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t skfp_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct s_smc *smc; /* private board structure pointer */
+ skfddi_priv *bp;
+
+- if (dev == NULL) {
+- printk("%s: irq %d for unknown device\n", dev->name, irq);
+- return IRQ_NONE;
+- }
+-
+ smc = netdev_priv(dev);
+ bp = &smc->os;
+
+@@ -2280,7 +2274,7 @@ static struct pci_driver skfddi_pci_driv
+
+ static int __init skfd_init(void)
+ {
+- return pci_module_init(&skfddi_pci_driver);
++ return pci_register_driver(&skfddi_pci_driver);
+ }
+
+ static void __exit skfd_exit(void)
+diff --git a/drivers/net/skge.c b/drivers/net/skge.c
+index ad878df..b294903 100644
+--- a/drivers/net/skge.c
++++ b/drivers/net/skge.c
+@@ -11,8 +11,7 @@
+ *
+ * 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 Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+@@ -43,7 +42,7 @@
+ #include "skge.h"
+
+ #define DRV_NAME "skge"
+-#define DRV_VERSION "1.6"
++#define DRV_VERSION "1.9"
+ #define PFX DRV_NAME " "
+
+ #define DEFAULT_TX_RING_SIZE 128
+@@ -58,6 +57,7 @@
+ #define TX_WATCHDOG (5 * HZ)
+ #define NAPI_WEIGHT 64
+ #define BLINK_MS 250
++#define LINK_HZ (HZ/2)
+
+ MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
+ MODULE_AUTHOR("Stephen Hemminger <shemminger at osdl.org>");
+@@ -91,7 +91,7 @@ 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_phy_reset(struct skge_port *skge);
+-static void skge_tx_clean(struct skge_port *skge);
++static void skge_tx_clean(struct net_device *dev);
+ static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+ static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+ static void genesis_get_stats(struct skge_port *skge, u64 *data);
+@@ -105,6 +105,7 @@ static const int txqaddr[] = { Q_XA1, Q_
+ 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 irqmask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F };
+
+ static int skge_get_regs_len(struct net_device *dev)
+ {
+@@ -195,8 +196,8 @@ static u32 skge_supported_modes(const st
+ else if (hw->chip_id == CHIP_ID_YUKON)
+ supported &= ~SUPPORTED_1000baseT_Half;
+ } else
+- supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+- | SUPPORTED_Autoneg;
++ supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half
++ | SUPPORTED_FIBRE | SUPPORTED_Autoneg;
+
+ return supported;
+ }
+@@ -485,31 +486,37 @@ static void skge_get_pauseparam(struct n
+ {
+ struct skge_port *skge = netdev_priv(dev);
+
+- ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND)
+- || (skge->flow_control == FLOW_MODE_SYMMETRIC);
+- ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND)
+- || (skge->flow_control == FLOW_MODE_SYMMETRIC);
++ ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC)
++ || (skge->flow_control == FLOW_MODE_SYM_OR_REM);
++ ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND);
+
+- ecmd->autoneg = skge->autoneg;
++ ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause;
+ }
+
+ static int skge_set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *ecmd)
+ {
+ struct skge_port *skge = netdev_priv(dev);
++ struct ethtool_pauseparam old;
+
+- 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)
+- skge->flow_control = FLOW_MODE_REM_SEND;
+- else if (!ecmd->rx_pause && ecmd->tx_pause)
+- skge->flow_control = FLOW_MODE_LOC_SEND;
+- else
+- skge->flow_control = FLOW_MODE_NONE;
++ skge_get_pauseparam(dev, &old);
++
++ if (ecmd->autoneg != old.autoneg)
++ skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC;
++ else {
++ if (ecmd->rx_pause && ecmd->tx_pause)
++ skge->flow_control = FLOW_MODE_SYMMETRIC;
++ else if (ecmd->rx_pause && !ecmd->tx_pause)
++ skge->flow_control = FLOW_MODE_SYM_OR_REM;
++ else if (!ecmd->rx_pause && ecmd->tx_pause)
++ skge->flow_control = FLOW_MODE_LOC_SEND;
++ else
++ skge->flow_control = FLOW_MODE_NONE;
++ }
+
+ if (netif_running(dev))
+ skge_phy_reset(skge);
++
+ return 0;
+ }
+
+@@ -604,7 +611,12 @@ static void skge_led(struct skge_port *s
+ if (hw->chip_id == CHIP_ID_GENESIS) {
+ switch (mode) {
+ case LED_MODE_OFF:
+- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
++ if (hw->phy_type == SK_PHY_BCOM)
++ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
++ else {
++ skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
++ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
++ }
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
+@@ -624,8 +636,14 @@ static void skge_led(struct skge_port *s
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+
+- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
+- break;
++ if (hw->phy_type == SK_PHY_BCOM)
++ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
++ else {
++ skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
++ skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
++ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
++ }
++
+ }
+ } else {
+ switch (mode) {
+@@ -690,7 +708,7 @@ static int skge_phys_id(struct net_devic
+ return 0;
+ }
+
+-static struct ethtool_ops skge_ethtool_ops = {
++static const struct ethtool_ops skge_ethtool_ops = {
+ .get_settings = skge_get_settings,
+ .set_settings = skge_set_settings,
+ .get_drvinfo = skge_get_drvinfo,
+@@ -818,8 +836,9 @@ static void skge_rx_clean(struct skge_po
+ /* Allocate buffers for receive ring
+ * For receive: to_clean is next received frame.
+ */
+-static int skge_rx_fill(struct skge_port *skge)
++static int skge_rx_fill(struct net_device *dev)
+ {
++ struct skge_port *skge = netdev_priv(dev);
+ struct skge_ring *ring = &skge->rx_ring;
+ struct skge_element *e;
+
+@@ -827,7 +846,8 @@ static int skge_rx_fill(struct skge_port
+ do {
+ struct sk_buff *skb;
+
+- skb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_KERNEL);
++ skb = __netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN,
++ GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+@@ -839,6 +859,23 @@ static int skge_rx_fill(struct skge_port
+ return 0;
+ }
+
++static const char *skge_pause(enum pause_status status)
++{
++ switch(status) {
++ case FLOW_STAT_NONE:
++ return "none";
++ case FLOW_STAT_REM_SEND:
++ return "rx only";
++ case FLOW_STAT_LOC_SEND:
++ return "tx_only";
++ case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */
++ return "both";
++ default:
++ return "indeterminated";
++ }
++}
++
++
+ static void skge_link_up(struct skge_port *skge)
+ {
+ skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG),
+@@ -847,16 +884,13 @@ static void skge_link_up(struct skge_por
+ netif_carrier_on(skge->netdev);
+ netif_wake_queue(skge->netdev);
+
+- if (netif_msg_link(skge))
++ if (netif_msg_link(skge)) {
+ printk(KERN_INFO PFX
+ "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
+ skge->netdev->name, skge->speed,
+ skge->duplex == DUPLEX_FULL ? "full" : "half",
+- (skge->flow_control == FLOW_MODE_NONE) ? "none" :
+- (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" :
+- (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" :
+- (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" :
+- "unknown");
++ skge_pause(skge->flow_status));
++ }
+ }
+
+ static void skge_link_down(struct skge_port *skge)
+@@ -869,6 +903,29 @@ static void skge_link_down(struct skge_p
+ printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
+ }
+
++
++static void xm_link_down(struct skge_hw *hw, int port)
++{
++ struct net_device *dev = hw->dev[port];
++ struct skge_port *skge = netdev_priv(dev);
++ u16 cmd, msk;
++
++ if (hw->phy_type == SK_PHY_XMAC) {
++ msk = xm_read16(hw, port, XM_IMSK);
++ msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND;
++ xm_write16(hw, port, XM_IMSK, msk);
++ }
++
++ 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);
++}
++
+ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
+ {
+ int i;
+@@ -876,6 +933,9 @@ static int __xm_phy_read(struct skge_hw
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ *val = xm_read16(hw, port, XM_PHY_DATA);
+
++ if (hw->phy_type == SK_PHY_XMAC)
++ goto ready;
++
+ for (i = 0; i < PHY_RETRIES; i++) {
+ if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
+ goto ready;
+@@ -962,7 +1022,8 @@ static void genesis_reset(struct skge_hw
+ xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
+
+ /* disable Broadcom PHY IRQ */
+- xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
++ if (hw->phy_type == SK_PHY_BCOM)
++ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+
+ xm_outhash(hw, port, XM_HSM, zero);
+ }
+@@ -973,7 +1034,15 @@ 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,
++ [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
++};
++
++/* special defines for FIBER (88E1011S only) */
++static const u16 fiber_pause_map[] = {
++ [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE,
++ [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD,
++ [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD,
++ [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD,
+ };
+
+
+@@ -989,68 +1058,64 @@ static void bcom_check_link(struct skge_
+ status = xm_phy_read(hw, port, PHY_BCOM_STAT);
+
+ 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;
+- }
++ xm_link_down(hw, port);
++ 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;
+- }
++ if (skge->autoneg == AUTONEG_ENABLE) {
++ u16 lpa, aux;
+
++ if (!(status & PHY_ST_AN_OVER))
++ 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;
+- }
++ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
++ if (lpa & PHY_B_AN_RF) {
++ printk(KERN_NOTICE PFX "%s: remote fault\n",
++ dev->name);
++ return;
++ }
++
++ aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+
+- skge->speed = SPEED_1000;
++ /* 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;
+ }
+
+- if (!netif_carrier_ok(dev))
+- genesis_link_up(skge);
++ /* 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_status = FLOW_STAT_SYMMETRIC;
++ break;
++ case PHY_B_AS_PRR:
++ skge->flow_status = FLOW_STAT_REM_SEND;
++ break;
++ case PHY_B_AS_PRT:
++ skge->flow_status = FLOW_STAT_LOC_SEND;
++ break;
++ default:
++ skge->flow_status = FLOW_STAT_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)
++static void bcom_phy_init(struct skge_port *skge)
+ {
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+@@ -1141,7 +1206,7 @@ static void bcom_phy_init(struct skge_po
+ phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
+
+ /* Handle Jumbo frames */
+- if (jumbo) {
++ if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
+
+@@ -1154,8 +1219,142 @@ static void bcom_phy_init(struct skge_po
+
+ /* Use link status change interrupt */
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
++}
++
++static void xm_phy_init(struct skge_port *skge)
++{
++ struct skge_hw *hw = skge->hw;
++ int port = skge->port;
++ u16 ctrl = 0;
++
++ if (skge->autoneg == AUTONEG_ENABLE) {
++ if (skge->advertising & ADVERTISED_1000baseT_Half)
++ ctrl |= PHY_X_AN_HD;
++ if (skge->advertising & ADVERTISED_1000baseT_Full)
++ ctrl |= PHY_X_AN_FD;
++
++ ctrl |= fiber_pause_map[skge->flow_control];
++
++ xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
++
++ /* Restart Auto-negotiation */
++ ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
++ } else {
++ /* Set DuplexMode in Config register */
++ if (skge->duplex == DUPLEX_FULL)
++ ctrl |= PHY_CT_DUP_MD;
++ /*
++ * Do NOT enable Auto-negotiation here. This would hold
++ * the link down because no IDLEs are transmitted
++ */
++ }
++
++ xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
++
++ /* Poll PHY for status changes */
++ schedule_delayed_work(&skge->link_thread, LINK_HZ);
++}
++
++static void xm_check_link(struct net_device *dev)
++{
++ struct skge_port *skge = netdev_priv(dev);
++ struct skge_hw *hw = skge->hw;
++ int port = skge->port;
++ u16 status;
++
++ /* read twice because of latch */
++ (void) xm_phy_read(hw, port, PHY_XMAC_STAT);
++ status = xm_phy_read(hw, port, PHY_XMAC_STAT);
++
++ if ((status & PHY_ST_LSYNC) == 0) {
++ xm_link_down(hw, port);
++ return;
++ }
++
++ if (skge->autoneg == AUTONEG_ENABLE) {
++ u16 lpa, res;
++
++ if (!(status & PHY_ST_AN_OVER))
++ return;
++
++ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
++ if (lpa & PHY_B_AN_RF) {
++ printk(KERN_NOTICE PFX "%s: remote fault\n",
++ dev->name);
++ return;
++ }
++
++ res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
++
++ /* Check Duplex mismatch */
++ switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) {
++ case PHY_X_RS_FD:
++ skge->duplex = DUPLEX_FULL;
++ break;
++ case PHY_X_RS_HD:
++ 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 */
++ if ((skge->flow_control == FLOW_MODE_SYMMETRIC ||
++ skge->flow_control == FLOW_MODE_SYM_OR_REM) &&
++ (lpa & PHY_X_P_SYM_MD))
++ skge->flow_status = FLOW_STAT_SYMMETRIC;
++ else if (skge->flow_control == FLOW_MODE_SYM_OR_REM &&
++ (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
++ /* Enable PAUSE receive, disable PAUSE transmit */
++ skge->flow_status = FLOW_STAT_REM_SEND;
++ else if (skge->flow_control == FLOW_MODE_LOC_SEND &&
++ (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
++ /* Disable PAUSE receive, enable PAUSE transmit */
++ skge->flow_status = FLOW_STAT_LOC_SEND;
++ else
++ skge->flow_status = FLOW_STAT_NONE;
++
++ skge->speed = SPEED_1000;
++ }
+
+- bcom_check_link(hw, port);
++ if (!netif_carrier_ok(dev))
++ genesis_link_up(skge);
++}
++
++/* Poll to check for link coming up.
++ * Since internal PHY is wired to a level triggered pin, can't
++ * get an interrupt when carrier is detected.
++ */
++static void xm_link_timer(void *arg)
++{
++ struct net_device *dev = arg;
++ struct skge_port *skge = netdev_priv(arg);
++ struct skge_hw *hw = skge->hw;
++ int port = skge->port;
++
++ if (!netif_running(dev))
++ return;
++
++ if (netif_carrier_ok(dev)) {
++ xm_read16(hw, port, XM_ISRC);
++ if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
++ goto nochange;
++ } else {
++ if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
++ goto nochange;
++ xm_read16(hw, port, XM_ISRC);
++ if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
++ goto nochange;
++ }
++
++ mutex_lock(&hw->phy_mutex);
++ xm_check_link(dev);
++ mutex_unlock(&hw->phy_mutex);
++
++nochange:
++ schedule_delayed_work(&skge->link_thread, LINK_HZ);
+ }
+
+ static void genesis_mac_init(struct skge_hw *hw, int port)
+@@ -1186,20 +1385,29 @@ static void genesis_mac_init(struct skge
+ * namely for the 1000baseTX cards that use the XMAC's
+ * GMII mode.
+ */
+- /* 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;
++ if (hw->phy_type != SK_PHY_XMAC) {
++ /* 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;
+
+- skge_write32(hw, B2_GP_IO, r);
++ skge_write32(hw, B2_GP_IO, r);
+
++ /* Enable GMII interface */
++ xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
++ }
+
+- /* Enable GMII interface */
+- xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+
+- bcom_phy_init(skge, jumbo);
++ switch(hw->phy_type) {
++ case SK_PHY_XMAC:
++ xm_phy_init(skge);
++ break;
++ case SK_PHY_BCOM:
++ bcom_phy_init(skge);
++ bcom_check_link(hw, port);
++ }
+
+ /* Set Station Address */
+ xm_outaddr(hw, port, XM_SA, dev->dev_addr);
+@@ -1332,16 +1540,18 @@ static void genesis_stop(struct skge_por
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+
+ /* For external PHYs there must be special handling */
+- 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;
++ if (hw->phy_type != SK_PHY_XMAC) {
++ 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_write32(hw, B2_GP_IO, reg);
+- skge_read32(hw, B2_GP_IO);
+
+ xm_write16(hw, port, XM_MMU_CMD,
+ xm_read16(hw, port, XM_MMU_CMD)
+@@ -1388,6 +1598,10 @@ static void genesis_mac_intr(struct skge
+ printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+ skge->netdev->name, status);
+
++ if (hw->phy_type == SK_PHY_XMAC &&
++ (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC)))
++ xm_link_down(hw, port);
++
+ if (status & XM_IS_TXF_UR) {
+ xm_write32(hw, port, XM_MODE, XM_MD_FTF);
+ ++skge->net_stats.tx_fifo_errors;
+@@ -1402,8 +1616,8 @@ static void genesis_link_up(struct skge_
+ {
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+- u16 cmd;
+- u32 mode, msk;
++ u16 cmd, msk;
++ u32 mode;
+
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
+
+@@ -1411,8 +1625,8 @@ static void genesis_link_up(struct skge_
+ * enabling pause frame reception is required for 1000BT
+ * because the XMAC is not reset if the link is going down
+ */
+- if (skge->flow_control == FLOW_MODE_NONE ||
+- skge->flow_control == FLOW_MODE_LOC_SEND)
++ if (skge->flow_status == FLOW_STAT_NONE ||
++ skge->flow_status == FLOW_STAT_LOC_SEND)
+ /* Disable Pause Frame Reception */
+ cmd |= XM_MMU_IGN_PF;
+ else
+@@ -1422,8 +1636,8 @@ static void genesis_link_up(struct skge_
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
+
+ mode = xm_read32(hw, port, XM_MODE);
+- if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
+- skge->flow_control == FLOW_MODE_LOC_SEND) {
++ if (skge->flow_status== FLOW_STAT_SYMMETRIC ||
++ skge->flow_status == FLOW_STAT_LOC_SEND) {
+ /*
+ * Configure Pause Frame Generation
+ * Use internal and external Pause Frame Generation.
+@@ -1451,27 +1665,28 @@ static void genesis_link_up(struct skge_
+ }
+
+ xm_write32(hw, port, XM_MODE, mode);
+-
+ msk = XM_DEF_MSK;
+- /* disable GP0 interrupt bit for external Phy */
+- msk |= XM_IS_INP_ASS;
++ if (hw->phy_type != SK_PHY_XMAC)
++ msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */
+
+ xm_write16(hw, port, XM_IMSK, msk);
+ xm_read16(hw, port, XM_ISRC);
+
+ /* get MMU Command Reg. */
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
+- if (skge->duplex == DUPLEX_FULL)
++ if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+ cmd |= XM_MMU_GMII_FD;
+
+ /*
+ * 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);
++ if (hw->phy_type == SK_PHY_BCOM) {
++ 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 */
+ xm_write16(hw, port, XM_MMU_CMD,
+@@ -1602,11 +1817,17 @@ static void yukon_init(struct skge_hw *h
+ adv |= PHY_M_AN_10_FD;
+ if (skge->advertising & ADVERTISED_10baseT_Half)
+ adv |= PHY_M_AN_10_HD;
+- } else /* special defines for FIBER (88E1011S only) */
+- adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+
+- /* Set Flow-control capabilities */
+- adv |= phy_pause_map[skge->flow_control];
++ /* Set Flow-control capabilities */
++ adv |= phy_pause_map[skge->flow_control];
++ } else {
++ if (skge->advertising & ADVERTISED_1000baseT_Full)
++ adv |= PHY_M_AN_1000X_AFD;
++ if (skge->advertising & ADVERTISED_1000baseT_Half)
++ adv |= PHY_M_AN_1000X_AHD;
++
++ adv |= fiber_pause_map[skge->flow_control];
++ }
+
+ /* Restart Auto-negotiation */
+ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+@@ -1740,6 +1961,11 @@ static void yukon_mac_init(struct skge_h
+ case FLOW_MODE_LOC_SEND:
+ /* disable Rx flow-control */
+ reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
++ break;
++ case FLOW_MODE_SYMMETRIC:
++ case FLOW_MODE_SYM_OR_REM:
++ /* enable Tx & Rx flow-control */
++ break;
+ }
+
+ gma_write16(hw, port, GM_GP_CTRL, reg);
+@@ -1934,13 +2160,11 @@ static void yukon_link_down(struct skge_
+ ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+ gma_write16(hw, port, GM_GP_CTRL, ctrl);
+
+- if (skge->flow_control == FLOW_MODE_REM_SEND) {
++ if (skge->flow_status == FLOW_STAT_REM_SEND) {
++ ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
++ ctrl |= PHY_M_AN_ASP;
+ /* restore Asymmetric Pause bit */
+- gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+- gm_phy_read(hw, port,
+- PHY_MARV_AUNE_ADV)
+- | PHY_M_AN_ASP);
+-
++ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl);
+ }
+
+ yukon_reset(hw, port);
+@@ -1987,19 +2211,19 @@ static void yukon_phy_intr(struct skge_p
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ switch (phystat & PHY_M_PS_PAUSE_MSK) {
+ case PHY_M_PS_PAUSE_MSK:
+- skge->flow_control = FLOW_MODE_SYMMETRIC;
++ skge->flow_status = FLOW_STAT_SYMMETRIC;
+ break;
+ case PHY_M_PS_RX_P_EN:
+- skge->flow_control = FLOW_MODE_REM_SEND;
++ skge->flow_status = FLOW_STAT_REM_SEND;
+ break;
+ case PHY_M_PS_TX_P_EN:
+- skge->flow_control = FLOW_MODE_LOC_SEND;
++ skge->flow_status = FLOW_STAT_LOC_SEND;
+ break;
+ default:
+- skge->flow_control = FLOW_MODE_NONE;
++ skge->flow_status = FLOW_STAT_NONE;
+ }
+
+- if (skge->flow_control == FLOW_MODE_NONE ||
++ if (skge->flow_status == FLOW_STAT_NONE ||
+ (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ else
+@@ -2178,7 +2402,7 @@ static int skge_up(struct net_device *de
+ if (err)
+ goto free_pci_mem;
+
+- err = skge_rx_fill(skge);
++ err = skge_rx_fill(dev);
+ if (err)
+ goto free_rx_ring;
+
+@@ -2237,6 +2461,8 @@ static int skge_down(struct net_device *
+ printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
+
+ netif_stop_queue(dev);
++ if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
++ cancel_rearming_delayed_work(&skge->link_thread);
+
+ skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
+ if (hw->chip_id == CHIP_ID_GENESIS)
+@@ -2281,7 +2507,7 @@ static int skge_down(struct net_device *
+ skge_led(skge, LED_MODE_OFF);
+
+ netif_poll_disable(dev);
+- skge_tx_clean(skge);
++ skge_tx_clean(dev);
+ skge_rx_clean(skge);
+
+ kfree(skge->rx_ring.start);
+@@ -2306,25 +2532,12 @@ static int skge_xmit_frame(struct sk_buf
+ int i;
+ u32 control, len;
+ u64 map;
+- unsigned long flags;
+
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+
+- if (!spin_trylock_irqsave(&skge->tx_lock, flags))
+- /* Collision - tell upper layer to requeue */
+- return NETDEV_TX_LOCKED;
+-
+- if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) {
+- if (!netif_queue_stopped(dev)) {
+- netif_stop_queue(dev);
+-
+- printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
+- dev->name);
+- }
+- spin_unlock_irqrestore(&skge->tx_lock, flags);
++ if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1))
+ return NETDEV_TX_BUSY;
+- }
+
+ e = skge->tx_ring.to_use;
+ td = e->desc;
+@@ -2338,7 +2551,7 @@ static int skge_xmit_frame(struct sk_buf
+ td->dma_lo = map;
+ td->dma_hi = map >> 32;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ int offset = skb->h.raw - skb->data;
+
+ /* This seems backwards, but it is what the sk98lin
+@@ -2399,8 +2612,6 @@ static int skge_xmit_frame(struct sk_buf
+ netif_stop_queue(dev);
+ }
+
+- spin_unlock_irqrestore(&skge->tx_lock, flags);
+-
+ dev->trans_start = jiffies;
+
+ return NETDEV_TX_OK;
+@@ -2430,18 +2641,18 @@ static void skge_tx_free(struct skge_por
+ printk(KERN_DEBUG PFX "%s: tx done slot %td\n",
+ skge->netdev->name, e - skge->tx_ring.start);
+
+- dev_kfree_skb_any(e->skb);
++ dev_kfree_skb(e->skb);
+ }
+ e->skb = NULL;
+ }
+
+ /* Free all buffers in transmit ring */
+-static void skge_tx_clean(struct skge_port *skge)
++static void skge_tx_clean(struct net_device *dev)
+ {
++ struct skge_port *skge = netdev_priv(dev);
+ struct skge_element *e;
+- unsigned long flags;
+
+- spin_lock_irqsave(&skge->tx_lock, flags);
++ netif_tx_lock_bh(dev);
+ for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
+ struct skge_tx_desc *td = e->desc;
+ skge_tx_free(skge, e, td->control);
+@@ -2449,8 +2660,8 @@ static void skge_tx_clean(struct skge_po
+ }
+
+ skge->tx_ring.to_clean = e;
+- netif_wake_queue(skge->netdev);
+- spin_unlock_irqrestore(&skge->tx_lock, flags);
++ netif_wake_queue(dev);
++ netif_tx_unlock_bh(dev);
+ }
+
+ static void skge_tx_timeout(struct net_device *dev)
+@@ -2461,7 +2672,7 @@ static void skge_tx_timeout(struct net_d
+ printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name);
+
+ skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP);
+- skge_tx_clean(skge);
++ skge_tx_clean(dev);
+ }
+
+ static int skge_change_mtu(struct net_device *dev, int new_mtu)
+@@ -2584,16 +2795,17 @@ static inline int bad_phy_status(const s
+ /* 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,
+- u32 control, u32 status, u16 csum)
++static struct sk_buff *skge_rx_get(struct net_device *dev,
++ struct skge_element *e,
++ u32 control, u32 status, u16 csum)
+ {
++ struct skge_port *skge = netdev_priv(dev);
+ struct sk_buff *skb;
+ u16 len = control & BMU_BBC;
+
+ if (unlikely(netif_msg_rx_status(skge)))
+ printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
+- skge->netdev->name, e - skge->rx_ring.start,
++ dev->name, e - skge->rx_ring.start,
+ status, len);
+
+ if (len > skge->rx_buf_size)
+@@ -2609,7 +2821,7 @@ static inline struct sk_buff *skge_rx_ge
+ goto error;
+
+ if (len < RX_COPY_THRESHOLD) {
+- skb = alloc_skb(len + 2, GFP_ATOMIC);
++ skb = netdev_alloc_skb(dev, len + 2);
+ if (!skb)
+ goto resubmit;
+
+@@ -2624,7 +2836,7 @@ static inline struct sk_buff *skge_rx_ge
+ skge_rx_reuse(e, skge->rx_buf_size);
+ } else {
+ struct sk_buff *nskb;
+- nskb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_ATOMIC);
++ nskb = netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN);
+ if (!nskb)
+ goto resubmit;
+
+@@ -2639,20 +2851,19 @@ static inline struct sk_buff *skge_rx_ge
+ }
+
+ skb_put(skb, len);
+- skb->dev = skge->netdev;
+ if (skge->rx_csum) {
+ skb->csum = csum;
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+
+- skb->protocol = eth_type_trans(skb, skge->netdev);
++ skb->protocol = eth_type_trans(skb, dev);
+
+ return skb;
+ error:
+
+ if (netif_msg_rx_err(skge))
+ printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n",
+- skge->netdev->name, e - skge->rx_ring.start,
++ dev->name, e - skge->rx_ring.start,
+ control, status);
+
+ if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+@@ -2677,15 +2888,15 @@ resubmit:
+ }
+
+ /* Free all buffers in Tx ring which are no longer owned by device */
+-static void skge_txirq(struct net_device *dev)
++static void skge_tx_done(struct net_device *dev)
+ {
+ struct skge_port *skge = netdev_priv(dev);
+ struct skge_ring *ring = &skge->tx_ring;
+ struct skge_element *e;
+
+- rmb();
++ skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
+
+- spin_lock(&skge->tx_lock);
++ netif_tx_lock(dev);
+ for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+ struct skge_tx_desc *td = e->desc;
+
+@@ -2696,11 +2907,10 @@ static void skge_txirq(struct net_device
+ }
+ skge->tx_ring.to_clean = e;
+
+- if (netif_queue_stopped(skge->netdev)
+- && skge_avail(&skge->tx_ring) > TX_LOW_WATER)
+- netif_wake_queue(skge->netdev);
++ if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
++ netif_wake_queue(dev);
+
+- spin_unlock(&skge->tx_lock);
++ netif_tx_unlock(dev);
+ }
+
+ static int skge_poll(struct net_device *dev, int *budget)
+@@ -2712,6 +2922,10 @@ static int skge_poll(struct net_device *
+ int to_do = min(dev->quota, *budget);
+ int work_done = 0;
+
++ skge_tx_done(dev);
++
++ skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
++
+ for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) {
+ struct skge_rx_desc *rd = e->desc;
+ struct sk_buff *skb;
+@@ -2722,7 +2936,7 @@ static int skge_poll(struct net_device *
+ if (control & BMU_OWN)
+ break;
+
+- skb = skge_rx_get(skge, e, control, rd->status, rd->csum2);
++ skb = skge_rx_get(dev, e, control, rd->status, rd->csum2);
+ if (likely(skb)) {
+ dev->last_rx = jiffies;
+ netif_receive_skb(skb);
+@@ -2742,12 +2956,11 @@ static int skge_poll(struct net_device *
+ if (work_done >= to_do)
+ return 1; /* not done */
+
+- netif_rx_complete(dev);
+-
+ spin_lock_irq(&hw->hw_lock);
+- hw->intr_mask |= rxirqmask[skge->port];
++ __netif_rx_complete(dev);
++ hw->intr_mask |= irqmask[skge->port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+- mmiowb();
++ skge_read32(hw, B0_IMSK);
+ spin_unlock_irq(&hw->hw_lock);
+
+ return 0;
+@@ -2872,7 +3085,7 @@ static void skge_extirq(void *arg)
+ if (netif_running(dev)) {
+ if (hw->chip_id != CHIP_ID_GENESIS)
+ yukon_phy_intr(skge);
+- else
++ else if (hw->phy_type == SK_PHY_BCOM)
+ bcom_phy_intr(skge);
+ }
+ }
+@@ -2881,34 +3094,31 @@ static void skge_extirq(void *arg)
+ spin_lock_irq(&hw->hw_lock);
+ hw->intr_mask |= IS_EXT_REG;
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
++ skge_read32(hw, B0_IMSK);
+ spin_unlock_irq(&hw->hw_lock);
+ }
+
+-static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t skge_intr(int irq, void *dev_id)
+ {
+ struct skge_hw *hw = dev_id;
+ u32 status;
++ int handled = 0;
+
++ spin_lock(&hw->hw_lock);
+ /* Reading this register masks IRQ */
+ status = skge_read32(hw, B0_SP_ISRC);
+- if (status == 0)
+- return IRQ_NONE;
++ if (status == 0 || status == ~0)
++ goto out;
+
+- spin_lock(&hw->hw_lock);
++ handled = 1;
+ status &= hw->intr_mask;
+ if (status & IS_EXT_REG) {
+ hw->intr_mask &= ~IS_EXT_REG;
+ schedule_work(&hw->phy_work);
+ }
+
+- if (status & IS_XA1_F) {
+- skge_write8(hw, Q_ADDR(Q_XA1, Q_CSR), CSR_IRQ_CL_F);
+- skge_txirq(hw->dev[0]);
+- }
+-
+- if (status & IS_R1_F) {
+- skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F);
+- hw->intr_mask &= ~IS_R1_F;
++ if (status & (IS_XA1_F|IS_R1_F)) {
++ hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
+ netif_rx_schedule(hw->dev[0]);
+ }
+
+@@ -2927,14 +3137,8 @@ static irqreturn_t skge_intr(int irq, vo
+ skge_mac_intr(hw, 0);
+
+ if (hw->dev[1]) {
+- if (status & IS_XA2_F) {
+- skge_write8(hw, Q_ADDR(Q_XA2, Q_CSR), CSR_IRQ_CL_F);
+- skge_txirq(hw->dev[1]);
+- }
+-
+- if (status & IS_R2_F) {
+- skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F);
+- hw->intr_mask &= ~IS_R2_F;
++ if (status & (IS_XA2_F|IS_R2_F)) {
++ hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
+ netif_rx_schedule(hw->dev[1]);
+ }
+
+@@ -2955,9 +3159,11 @@ static irqreturn_t skge_intr(int irq, vo
+ skge_error_irq(hw);
+
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
++ skge_read32(hw, B0_IMSK);
++out:
+ spin_unlock(&hw->hw_lock);
+
+- return IRQ_HANDLED;
++ return IRQ_RETVAL(handled);
+ }
+
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+@@ -2966,7 +3172,7 @@ static void skge_netpoll(struct net_devi
+ struct skge_port *skge = netdev_priv(dev);
+
+ disable_irq(dev->irq);
+- skge_intr(dev->irq, skge->hw, NULL);
++ skge_intr(dev->irq, skge->hw);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -3031,7 +3237,7 @@ static int skge_reset(struct skge_hw *hw
+ {
+ u32 reg;
+ u16 ctst, pci_status;
+- u8 t8, mac_cfg, pmd_type, phy_type;
++ u8 t8, mac_cfg, pmd_type;
+ int i;
+
+ ctst = skge_read16(hw, B0_CTST);
+@@ -3055,19 +3261,22 @@ static int skge_reset(struct skge_hw *hw
+ ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
+
+ hw->chip_id = skge_read8(hw, B2_CHIP_ID);
+- phy_type = skge_read8(hw, B2_E_1) & 0xf;
++ hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
+ pmd_type = skge_read8(hw, B2_PMD_TYP);
+ hw->copper = (pmd_type == 'T' || pmd_type == '1');
+
+ switch (hw->chip_id) {
+ case CHIP_ID_GENESIS:
+- switch (phy_type) {
++ 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;
+ default:
+ printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
+- pci_name(hw->pdev), phy_type);
++ pci_name(hw->pdev), hw->phy_type);
+ return -EOPNOTSUPP;
+ }
+ break;
+@@ -3075,7 +3284,7 @@ static int skge_reset(struct skge_hw *hw
+ case CHIP_ID_YUKON:
+ case CHIP_ID_YUKON_LITE:
+ case CHIP_ID_YUKON_LP:
+- if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
++ if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
+ hw->copper = 1;
+
+ hw->phy_addr = PHY_ADDR_MARV;
+@@ -3106,11 +3315,13 @@ static int skge_reset(struct skge_hw *hw
+ else
+ hw->ram_size = t8 * 4096;
+
+- spin_lock_init(&hw->hw_lock);
+- hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
++ hw->intr_mask = IS_HW_ERR | IS_PORT_1;
+ if (hw->ports > 1)
+ hw->intr_mask |= IS_PORT_2;
+
++ if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
++ hw->intr_mask |= IS_EXT_REG;
++
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ genesis_init(hw);
+ else {
+@@ -3222,7 +3433,7 @@ static struct net_device *skge_devinit(s
+ dev->poll_controller = skge_netpoll;
+ #endif
+ dev->irq = hw->pdev->irq;
+- dev->features = NETIF_F_LLTX;
++
+ if (highmem)
+ dev->features |= NETIF_F_HIGHDMA;
+
+@@ -3235,7 +3446,7 @@ static struct net_device *skge_devinit(s
+
+ /* Auto speed and flow control */
+ skge->autoneg = AUTONEG_ENABLE;
+- skge->flow_control = FLOW_MODE_SYMMETRIC;
++ skge->flow_control = FLOW_MODE_SYM_OR_REM;
+ skge->duplex = -1;
+ skge->speed = -1;
+ skge->advertising = skge_supported_modes(hw);
+@@ -3244,7 +3455,8 @@ static struct net_device *skge_devinit(s
+
+ skge->port = port;
+
+- spin_lock_init(&skge->tx_lock);
++ /* Only used for Genesis XMAC */
++ INIT_WORK(&skge->link_thread, xm_link_timer, dev);
+
+ if (hw->chip_id != CHIP_ID_GENESIS) {
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+@@ -3332,6 +3544,7 @@ static int __devinit skge_probe(struct p
+ hw->pdev = pdev;
+ mutex_init(&hw->phy_mutex);
+ INIT_WORK(&hw->phy_work, skge_extirq, hw);
++ spin_lock_init(&hw->hw_lock);
+
+ hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
+ if (!hw->regs) {
+@@ -3340,23 +3553,16 @@ static int __devinit skge_probe(struct p
+ goto err_out_free_hw;
+ }
+
+- err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, DRV_NAME, hw);
+- if (err) {
+- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+- pci_name(pdev), pdev->irq);
+- goto err_out_iounmap;
+- }
+- pci_set_drvdata(pdev, hw);
+-
+ err = skge_reset(hw);
+ if (err)
+- goto err_out_free_irq;
++ goto err_out_iounmap;
+
+ printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n",
+ (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
+ skge_board_name(hw), hw->chip_rev);
+
+- if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
++ dev = skge_devinit(hw, 0, using_dac);
++ if (!dev)
+ goto err_out_led_off;
+
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+@@ -3366,7 +3572,6 @@ static int __devinit skge_probe(struct p
+ goto err_out_free_netdev;
+ }
+
+-
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "%s: cannot register net device\n",
+@@ -3374,6 +3579,12 @@ static int __devinit skge_probe(struct p
+ goto err_out_free_netdev;
+ }
+
++ err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
++ if (err) {
++ printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
++ dev->name, pdev->irq);
++ goto err_out_unregister;
++ }
+ skge_show_addr(dev);
+
+ if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
+@@ -3386,15 +3597,16 @@ static int __devinit skge_probe(struct p
+ free_netdev(dev1);
+ }
+ }
++ pci_set_drvdata(pdev, hw);
+
+ return 0;
+
++err_out_unregister:
++ unregister_netdev(dev);
+ err_out_free_netdev:
+ free_netdev(dev);
+ err_out_led_off:
+ skge_write16(hw, B0_LED, LED_STAT_OFF);
+-err_out_free_irq:
+- free_irq(pdev->irq, hw);
+ err_out_iounmap:
+ iounmap(hw->regs);
+ err_out_free_hw:
+@@ -3424,6 +3636,7 @@ static void __devexit skge_remove(struct
+ spin_lock_irq(&hw->hw_lock);
+ hw->intr_mask = 0;
+ skge_write32(hw, B0_IMSK, 0);
++ skge_read32(hw, B0_IMSK);
+ spin_unlock_irq(&hw->hw_lock);
+
+ skge_write16(hw, B0_LED, LED_STAT_OFF);
+@@ -3449,26 +3662,25 @@ static int skge_suspend(struct pci_dev *
+ struct skge_hw *hw = pci_get_drvdata(pdev);
+ int i, wol = 0;
+
+- for (i = 0; i < 2; i++) {
++ pci_save_state(pdev);
++ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+
+- if (dev) {
++ if (netif_running(dev)) {
+ struct skge_port *skge = netdev_priv(dev);
+- if (netif_running(dev)) {
+- netif_carrier_off(dev);
+- if (skge->wol)
+- netif_stop_queue(dev);
+- else
+- skge_down(dev);
+- }
+- netif_device_detach(dev);
++
++ netif_carrier_off(dev);
++ if (skge->wol)
++ netif_stop_queue(dev);
++ else
++ skge_down(dev);
+ wol |= skge->wol;
+ }
++ netif_device_detach(dev);
+ }
+
+- pci_save_state(pdev);
++ skge_write32(hw, B0_IMSK, 0);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
+- pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+@@ -3477,23 +3689,33 @@ static int skge_suspend(struct pci_dev *
+ static int skge_resume(struct pci_dev *pdev)
+ {
+ struct skge_hw *hw = pci_get_drvdata(pdev);
+- int i;
++ int i, err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_wake(pdev, PCI_D0, 0);
+
+- skge_reset(hw);
++ err = skge_reset(hw);
++ if (err)
++ goto out;
+
+- for (i = 0; i < 2; i++) {
++ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+- if (dev) {
+- netif_device_attach(dev);
+- if (netif_running(dev) && skge_up(dev))
++
++ netif_device_attach(dev);
++ if (netif_running(dev)) {
++ err = skge_up(dev);
++
++ if (err) {
++ printk(KERN_ERR PFX "%s: could not up: %d\n",
++ dev->name, err);
+ dev_close(dev);
++ goto out;
++ }
+ }
+ }
+- return 0;
++out:
++ return err;
+ }
+ #endif
+
+@@ -3510,7 +3732,7 @@ static struct pci_driver skge_driver = {
+
+ static int __init skge_init_module(void)
+ {
+- return pci_module_init(&skge_driver);
++ return pci_register_driver(&skge_driver);
+ }
+
+ static void __exit skge_cleanup_module(void)
+diff --git a/drivers/net/skge.h b/drivers/net/skge.h
+index 593387b..537c0aa 100644
+--- a/drivers/net/skge.h
++++ b/drivers/net/skge.h
+@@ -934,7 +934,7 @@ enum {
+ PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
+ PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */
+ PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
+- PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
++ PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
+ PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
+
+ PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */
+@@ -1097,13 +1097,36 @@ enum {
+
+ /* 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 */
++ PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */
+ PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */
+ PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */
+ PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */
+ };
+
+
++/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/
++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 */
++};
++
++/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/
++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 */
++};
++
+ /* Broadcom-Specific */
+ /***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
+ enum {
+@@ -2158,8 +2181,8 @@ enum {
+ XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */
+ XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */
+ XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */
+- XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
+- XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
++ XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
++ XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
+ XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */
+ XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */
+ XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */
+@@ -2172,8 +2195,7 @@ enum {
+ XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
+ };
+
+-#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \
+- XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \
++#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \
+ XM_IS_RXF_OV | XM_IS_TXF_UR))
+
+
+@@ -2396,6 +2418,7 @@ struct skge_hw {
+ u8 chip_rev;
+ u8 copper;
+ u8 ports;
++ u8 phy_type;
+
+ u32 ram_size;
+ u32 ram_offset;
+@@ -2404,28 +2427,40 @@ struct skge_hw {
+ struct mutex phy_mutex;
+ };
+
+-enum {
+- FLOW_MODE_NONE = 0, /* No Flow-Control */
+- FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */
+- FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */
++enum pause_control {
++ FLOW_MODE_NONE = 1, /* No Flow-Control */
++ FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */
+ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */
++ FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or
++ * just the remote station may send PAUSE
++ */
+ };
+
++enum pause_status {
++ FLOW_STAT_INDETERMINATED=0, /* indeterminated */
++ FLOW_STAT_NONE, /* No Flow Control */
++ FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */
++ FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */
++ FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */
++};
++
++
+ struct skge_port {
+ u32 msg_enable;
+ struct skge_hw *hw;
+ struct net_device *netdev;
+ int port;
+
+- spinlock_t tx_lock;
+ struct skge_ring tx_ring;
+ struct skge_ring rx_ring;
+
+ struct net_device_stats net_stats;
+
++ struct work_struct link_thread;
++ enum pause_control flow_control;
++ enum pause_status flow_status;
+ u8 rx_csum;
+ u8 blink_on;
+- u8 flow_control;
+ u8 wol;
+ u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
+ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
+diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
+index 933e87f..16616f5 100644
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -10,8 +10,7 @@
+ *
+ * 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 Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+@@ -50,19 +49,18 @@
+ #include "sky2.h"
+
+ #define DRV_NAME "sky2"
+-#define DRV_VERSION "1.5"
++#define DRV_VERSION "1.10"
+ #define PFX DRV_NAME " "
+
+ /*
+ * The Yukon II chipset takes 64 bit command blocks (called list elements)
+ * that are organized into three (receive, transmit, status) different rings
+- * similar to Tigon3. A transmit can require several elements;
+- * a receive requires one (or two if using 64 bit dma).
++ * similar to Tigon3.
+ */
+
+-#define RX_LE_SIZE 512
++#define RX_LE_SIZE 1024
+ #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le))
+-#define RX_MAX_PENDING (RX_LE_SIZE/2 - 2)
++#define RX_MAX_PENDING (RX_LE_SIZE/6 - 2)
+ #define RX_DEF_PENDING RX_MAX_PENDING
+ #define RX_SKB_ALIGN 8
+ #define RX_BUF_WRITE 16
+@@ -74,7 +72,6 @@
+
+ #define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */
+ #define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le))
+-#define ETH_JUMBO_MTU 9000
+ #define TX_WATCHDOG (5 * HZ)
+ #define NAPI_WEIGHT 64
+ #define PHY_RETRIES 1000
+@@ -90,7 +87,7 @@ static int debug = -1; /* defaults abov
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+-static int copybreak __read_mostly = 256;
++static int copybreak __read_mostly = 128;
+ module_param(copybreak, int, 0);
+ MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
+@@ -98,14 +95,15 @@ static int disable_msi = 0;
+ module_param(disable_msi, int, 0);
+ MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
+
+-static int idle_timeout = 100;
++static int idle_timeout = 0;
+ module_param(idle_timeout, int, 0);
+-MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)");
++MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)");
+
+ static const struct pci_device_id sky2_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */
++ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) },
+@@ -117,10 +115,17 @@ static const struct pci_device_id sky2_i
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4350) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) },
+ { 0 }
+ };
+
+@@ -190,7 +195,6 @@ static u16 gm_phy_read(struct sky2_hw *h
+ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
+ {
+ u16 power_control;
+- u32 reg1;
+ int vaux;
+
+ pr_debug("sky2_set_power_state %d\n", state);
+@@ -223,20 +227,9 @@ static void sky2_set_power_state(struct
+ else
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+
+- /* Turn off phy power saving */
+- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+- reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
+-
+- /* looks like this XL is back asswards .. */
+- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) {
+- reg1 |= PCI_Y2_PHY1_COMA;
+- if (hw->ports > 1)
+- reg1 |= PCI_Y2_PHY2_COMA;
+- }
+- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+- udelay(100);
+-
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
++ u32 reg1;
++
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
+ reg1 &= P_ASPM_CONTROL_MSK;
+@@ -248,15 +241,6 @@ static void sky2_set_power_state(struct
+
+ case PCI_D3hot:
+ case PCI_D3cold:
+- /* Turn on phy power saving */
+- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+- reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
+- else
+- reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
+- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+- udelay(100);
+-
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+ else
+@@ -280,7 +264,7 @@ static void sky2_set_power_state(struct
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ }
+
+-static void sky2_phy_reset(struct sky2_hw *hw, unsigned port)
++static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
+ {
+ u16 reg;
+
+@@ -299,10 +283,35 @@ static void sky2_phy_reset(struct sky2_h
+ gma_write16(hw, port, GM_RX_CTRL, reg);
+ }
+
++/* flow control to advertise bits */
++static const u16 copper_fc_adv[] = {
++ [FC_NONE] = 0,
++ [FC_TX] = PHY_M_AN_ASP,
++ [FC_RX] = PHY_M_AN_PC,
++ [FC_BOTH] = PHY_M_AN_PC | PHY_M_AN_ASP,
++};
++
++/* flow control to advertise bits when using 1000BaseX */
++static const u16 fiber_fc_adv[] = {
++ [FC_BOTH] = PHY_M_P_BOTH_MD_X,
++ [FC_TX] = PHY_M_P_ASYM_MD_X,
++ [FC_RX] = PHY_M_P_SYM_MD_X,
++ [FC_NONE] = PHY_M_P_NO_PAUSE_X,
++};
++
++/* flow control to GMA disable bits */
++static const u16 gm_fc_disable[] = {
++ [FC_NONE] = GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS,
++ [FC_TX] = GM_GPCR_FC_RX_DIS,
++ [FC_RX] = GM_GPCR_FC_TX_DIS,
++ [FC_BOTH] = 0,
++};
++
++
+ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
+ {
+ struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
+- u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
++ u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
+
+ if (sky2->autoneg == AUTONEG_ENABLE &&
+ !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+@@ -321,7 +330,7 @@ static void sky2_phy_init(struct sky2_hw
+ }
+
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+- if (hw->copper) {
++ if (sky2_is_copper(hw)) {
+ if (hw->chip_id == CHIP_ID_YUKON_FE) {
+ /* enable automatic crossover */
+ ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
+@@ -338,42 +347,46 @@ static void sky2_phy_init(struct sky2_hw
+ ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
+ }
+ }
+- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+ } else {
+ /* workaround for deviation #4.88 (CRC errors) */
+ /* disable Automatic Crossover */
+
+ ctrl &= ~PHY_M_PC_MDIX_MSK;
+- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
++ }
+
+- if (hw->chip_id == CHIP_ID_YUKON_XL) {
+- /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
+- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+- ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+- ctrl &= ~PHY_M_MAC_MD_MSK;
+- ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX);
+- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
++ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
++
++ /* special setup for PHY 88E1112 Fiber */
++ if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) {
++ pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
++
++ /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
++ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
++ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
++ ctrl &= ~PHY_M_MAC_MD_MSK;
++ ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX);
++ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
++ if (hw->pmd_type == 'P') {
+ /* select page 1 to access Fiber registers */
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 1);
+- }
+- }
+
+- ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+- if (sky2->autoneg == AUTONEG_DISABLE)
+- ctrl &= ~PHY_CT_ANE;
+- else
+- ctrl |= PHY_CT_ANE;
++ /* for SFP-module set SIGDET polarity to low */
++ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
++ ctrl |= PHY_M_FIB_SIGD_POL;
++ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
++ }
+
+- ctrl |= PHY_CT_RESET;
+- gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
++ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
++ }
+
+- ctrl = 0;
++ ctrl = PHY_CT_RESET;
+ ct1000 = 0;
+ adv = PHY_AN_CSMA;
++ reg = 0;
+
+ if (sky2->autoneg == AUTONEG_ENABLE) {
+- if (hw->copper) {
++ if (sky2_is_copper(hw)) {
+ if (sky2->advertising & ADVERTISED_1000baseT_Full)
+ ct1000 |= PHY_M_1000C_AFD;
+ if (sky2->advertising & ADVERTISED_1000baseT_Half)
+@@ -386,16 +399,16 @@ static void sky2_phy_init(struct sky2_hw
+ adv |= PHY_M_AN_10_FD;
+ if (sky2->advertising & ADVERTISED_10baseT_Half)
+ adv |= PHY_M_AN_10_HD;
+- } else /* special defines for FIBER (88E1011S only) */
+- adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+
+- /* Set Flow-control capabilities */
+- if (sky2->tx_pause && sky2->rx_pause)
+- adv |= PHY_AN_PAUSE_CAP; /* symmetric */
+- else if (sky2->rx_pause && !sky2->tx_pause)
+- adv |= PHY_AN_PAUSE_ASYM | PHY_AN_PAUSE_CAP;
+- else if (!sky2->rx_pause && sky2->tx_pause)
+- adv |= PHY_AN_PAUSE_ASYM; /* local */
++ adv |= copper_fc_adv[sky2->flow_mode];
++ } else { /* special defines for FIBER (88E1040S only) */
++ if (sky2->advertising & ADVERTISED_1000baseT_Full)
++ adv |= PHY_M_AN_1000X_AFD;
++ if (sky2->advertising & ADVERTISED_1000baseT_Half)
++ adv |= PHY_M_AN_1000X_AHD;
++
++ adv |= fiber_fc_adv[sky2->flow_mode];
++ }
+
+ /* Restart Auto-negotiation */
+ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+@@ -403,21 +416,38 @@ static void sky2_phy_init(struct sky2_hw
+ /* forced speed/duplex settings */
+ ct1000 = PHY_M_1000C_MSE;
+
+- if (sky2->duplex == DUPLEX_FULL)
+- ctrl |= PHY_CT_DUP_MD;
++ /* Disable auto update for duplex flow control and speed */
++ reg |= GM_GPCR_AU_ALL_DIS;
+
+ switch (sky2->speed) {
+ case SPEED_1000:
+ ctrl |= PHY_CT_SP1000;
++ reg |= GM_GPCR_SPEED_1000;
+ break;
+ case SPEED_100:
+ ctrl |= PHY_CT_SP100;
++ reg |= GM_GPCR_SPEED_100;
+ break;
+ }
+
+- ctrl |= PHY_CT_RESET;
++ if (sky2->duplex == DUPLEX_FULL) {
++ reg |= GM_GPCR_DUP_FULL;
++ ctrl |= PHY_CT_DUP_MD;
++ } else if (sky2->speed < SPEED_1000)
++ sky2->flow_mode = FC_NONE;
++
++
++ reg |= gm_fc_disable[sky2->flow_mode];
++
++ /* Forward pause packets to GMAC? */
++ if (sky2->flow_mode & FC_RX)
++ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
++ else
++ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ }
+
++ gma_write16(hw, port, GM_GP_CTRL, reg);
++
+ if (hw->chip_id != CHIP_ID_YUKON_FE)
+ gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+
+@@ -521,6 +551,7 @@ static void sky2_phy_init(struct sky2_hw
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+
+ }
++
+ /* Enable phy interrupt on auto-negotiation complete (or link up) */
+ if (sky2->autoneg == AUTONEG_ENABLE)
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+@@ -528,6 +559,29 @@ static void sky2_phy_init(struct sky2_hw
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ }
+
++static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
++{
++ u32 reg1;
++ static const u32 phy_power[]
++ = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
++
++ /* looks like this XL is back asswards .. */
++ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
++ onoff = !onoff;
++
++ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
++
++ if (onoff)
++ /* Turn off phy power saving */
++ reg1 &= ~phy_power[port];
++ else
++ reg1 |= phy_power[port];
++
++ sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
++ sky2_pci_read32(hw, PCI_DEV_REG1);
++ udelay(100);
++}
++
+ /* Force a renegotiation */
+ static void sky2_phy_reinit(struct sky2_port *sky2)
+ {
+@@ -560,49 +614,11 @@ static void sky2_mac_init(struct sky2_hw
+ gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
+ }
+
+- if (sky2->autoneg == AUTONEG_DISABLE) {
+- reg = gma_read16(hw, port, GM_GP_CTRL);
+- reg |= GM_GPCR_AU_ALL_DIS;
+- gma_write16(hw, port, GM_GP_CTRL, reg);
+- gma_read16(hw, port, GM_GP_CTRL);
+-
+- switch (sky2->speed) {
+- case SPEED_1000:
+- reg &= ~GM_GPCR_SPEED_100;
+- reg |= GM_GPCR_SPEED_1000;
+- break;
+- case SPEED_100:
+- reg &= ~GM_GPCR_SPEED_1000;
+- reg |= GM_GPCR_SPEED_100;
+- break;
+- case SPEED_10:
+- reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
+- break;
+- }
+-
+- if (sky2->duplex == DUPLEX_FULL)
+- reg |= GM_GPCR_DUP_FULL;
+-
+- /* turn off pause in 10/100mbps half duplex */
+- else if (sky2->speed != SPEED_1000 &&
+- hw->chip_id != CHIP_ID_YUKON_EC_U)
+- sky2->tx_pause = sky2->rx_pause = 0;
+- } else
+- reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
+-
+- if (!sky2->tx_pause && !sky2->rx_pause) {
+- sky2_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;
+- } else if (sky2->tx_pause && !sky2->rx_pause) {
+- /* disable Rx flow-control */
+- reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+- }
+-
+- gma_write16(hw, port, GM_GP_CTRL, reg);
+-
+ sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
+
++ /* Enable Transmit FIFO Underrun */
++ sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
++
+ spin_lock_bh(&sky2->phy_lock);
+ sky2_phy_init(hw, port);
+ spin_unlock_bh(&sky2->phy_lock);
+@@ -670,7 +686,7 @@ static void sky2_mac_init(struct sky2_hw
+ sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+- sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
++ sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 512/8);
+ sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
+ if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+ /* set Tx GMAC FIFO Almost Empty Threshold */
+@@ -682,16 +698,10 @@ static void sky2_mac_init(struct sky2_hw
+
+ }
+
+-/* Assign Ram Buffer allocation.
+- * start and end are in units of 4k bytes
+- * ram registers are in units of 64bit words
+- */
+-static void sky2_ramset(struct sky2_hw *hw, u16 q, u8 startk, u8 endk)
++/* Assign Ram Buffer allocation in units of 64bit (8 bytes) */
++static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 end)
+ {
+- u32 start, end;
+-
+- start = startk * 4096/8;
+- end = (endk * 4096/8) - 1;
++ pr_debug(PFX "q %d %#x %#x\n", q, start, end);
+
+ sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR);
+ sky2_write32(hw, RB_ADDR(q, RB_START), start);
+@@ -700,7 +710,7 @@ static void sky2_ramset(struct sky2_hw *
+ sky2_write32(hw, RB_ADDR(q, RB_RP), start);
+
+ if (q == Q_R1 || q == Q_R2) {
+- u32 space = (endk - startk) * 4096/8;
++ u32 space = end - start + 1;
+ u32 tp = space - space/4;
+
+ /* On receive queue's set the thresholds
+@@ -754,15 +764,23 @@ static inline struct sky2_tx_le *get_tx_
+ struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod;
+
+ sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE);
++ le->ctrl = 0;
+ return le;
+ }
+
++static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
++ struct sky2_tx_le *le)
++{
++ return sky2->tx_ring + (le - sky2->tx_le);
++}
++
+ /* Update chip's next pointer */
+ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
+ {
++ q = Y2_QADDR(q, PREF_UNIT_PUT_IDX);
+ wmb();
+- sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx);
+- mmiowb();
++ sky2_write16(hw, q, idx);
++ sky2_read16(hw, q);
+ }
+
+
+@@ -770,6 +788,7 @@ static inline struct sky2_rx_le *sky2_ne
+ {
+ struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put;
+ sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE);
++ le->ctrl = 0;
+ return le;
+ }
+
+@@ -779,17 +798,16 @@ static inline u32 high32(dma_addr_t a)
+ return sizeof(a) > sizeof(u32) ? (a >> 16) >> 16 : 0;
+ }
+
+-/* Build description to hardware about buffer */
+-static void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map)
++/* Build description to hardware for one receive segment */
++static void sky2_rx_add(struct sky2_port *sky2, u8 op,
++ dma_addr_t map, unsigned len)
+ {
+ struct sky2_rx_le *le;
+ u32 hi = high32(map);
+- u16 len = sky2->rx_bufsize;
+
+ if (sky2->rx_addr64 != hi) {
+ le = sky2_next_rx(sky2);
+ le->addr = cpu_to_le32(hi);
+- le->ctrl = 0;
+ le->opcode = OP_ADDR64 | HW_OWNER;
+ sky2->rx_addr64 = high32(map + len);
+ }
+@@ -797,11 +815,53 @@ static void sky2_rx_add(struct sky2_port
+ le = sky2_next_rx(sky2);
+ le->addr = cpu_to_le32((u32) map);
+ le->length = cpu_to_le16(len);
+- le->ctrl = 0;
+- le->opcode = OP_PACKET | HW_OWNER;
++ le->opcode = op | HW_OWNER;
++}
++
++/* Build description to hardware for one possibly fragmented skb */
++static void sky2_rx_submit(struct sky2_port *sky2,
++ const struct rx_ring_info *re)
++{
++ int i;
++
++ sky2_rx_add(sky2, OP_PACKET, re->data_addr, sky2->rx_data_size);
++
++ for (i = 0; i < skb_shinfo(re->skb)->nr_frags; i++)
++ sky2_rx_add(sky2, OP_BUFFER, re->frag_addr[i], PAGE_SIZE);
+ }
+
+
++static void sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
++ unsigned size)
++{
++ struct sk_buff *skb = re->skb;
++ int i;
++
++ re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE);
++ pci_unmap_len_set(re, data_size, size);
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
++ re->frag_addr[i] = pci_map_page(pdev,
++ skb_shinfo(skb)->frags[i].page,
++ skb_shinfo(skb)->frags[i].page_offset,
++ skb_shinfo(skb)->frags[i].size,
++ PCI_DMA_FROMDEVICE);
++}
++
++static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
++{
++ struct sk_buff *skb = re->skb;
++ int i;
++
++ pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size),
++ PCI_DMA_FROMDEVICE);
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
++ pci_unmap_page(pdev, re->frag_addr[i],
++ skb_shinfo(skb)->frags[i].size,
++ PCI_DMA_FROMDEVICE);
++}
++
+ /* Tell chip where to start receive checksum.
+ * Actually has two checksums, but set both same to avoid possible byte
+ * order problems.
+@@ -811,7 +871,7 @@ static void rx_set_checksum(struct sky2_
+ struct sky2_rx_le *le;
+
+ le = sky2_next_rx(sky2);
+- le->addr = (ETH_HLEN << 16) | ETH_HLEN;
++ le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+ le->ctrl = 0;
+ le->opcode = OP_TCPSTART | HW_OWNER;
+
+@@ -861,12 +921,10 @@ static void sky2_rx_clean(struct sky2_po
+
+ memset(sky2->rx_le, 0, RX_LE_BYTES);
+ for (i = 0; i < sky2->rx_pending; i++) {
+- struct ring_info *re = sky2->rx_ring + i;
++ struct rx_ring_info *re = sky2->rx_ring + i;
+
+ if (re->skb) {
+- pci_unmap_single(sky2->hw->pdev,
+- re->mapaddr, sky2->rx_bufsize,
+- PCI_DMA_FROMDEVICE);
++ sky2_rx_unmap_skb(sky2->hw->pdev, re);
+ kfree_skb(re->skb);
+ re->skb = NULL;
+ }
+@@ -920,13 +978,13 @@ static void sky2_vlan_rx_register(struct
+ struct sky2_hw *hw = sky2->hw;
+ u16 port = sky2->port;
+
+- spin_lock_bh(&sky2->tx_lock);
++ netif_tx_lock_bh(dev);
+
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON);
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON);
+ sky2->vlgrp = grp;
+
+- spin_unlock_bh(&sky2->tx_lock);
++ netif_tx_unlock_bh(dev);
+ }
+
+ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+@@ -935,48 +993,69 @@ static void sky2_vlan_rx_kill_vid(struct
+ struct sky2_hw *hw = sky2->hw;
+ u16 port = sky2->port;
+
+- spin_lock_bh(&sky2->tx_lock);
++ netif_tx_lock_bh(dev);
+
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF);
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF);
+ if (sky2->vlgrp)
+ sky2->vlgrp->vlan_devices[vid] = NULL;
+
+- spin_unlock_bh(&sky2->tx_lock);
++ netif_tx_unlock_bh(dev);
+ }
+ #endif
+
+ /*
++ * Allocate an skb for receiving. If the MTU is large enough
++ * make the skb non-linear with a fragment list of pages.
++ *
+ * It appears the hardware has a bug in the FIFO logic that
+ * cause it to hang if the FIFO gets overrun and the receive buffer
+- * is not aligned. ALso alloc_skb() won't align properly if slab
+- * debugging is enabled.
++ * is not 64 byte aligned. The buffer returned from netdev_alloc_skb is
++ * aligned except if slab debugging is enabled.
+ */
+-static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask)
++static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2)
+ {
+ struct sk_buff *skb;
++ unsigned long p;
++ int i;
+
+- skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask);
+- if (likely(skb)) {
+- unsigned long p = (unsigned long) skb->data;
+- skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
++ skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + RX_SKB_ALIGN);
++ if (!skb)
++ goto nomem;
++
++ p = (unsigned long) skb->data;
++ skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
++
++ for (i = 0; i < sky2->rx_nfrags; i++) {
++ struct page *page = alloc_page(GFP_ATOMIC);
++
++ if (!page)
++ goto free_partial;
++ skb_fill_page_desc(skb, i, page, 0, PAGE_SIZE);
+ }
+
+ return skb;
++free_partial:
++ kfree_skb(skb);
++nomem:
++ return NULL;
+ }
+
+ /*
+ * Allocate and setup receiver buffer pool.
+- * In case of 64 bit dma, there are 2X as many list elements
+- * available as ring entries
+- * and need to reserve one list element so we don't wrap around.
++ * Normal case this ends up creating one list element for skb
++ * in the receive ring. Worst case if using large MTU and each
++ * allocation falls on a different 64 bit region, that results
++ * in 6 list elements per ring entry.
++ * One element is used for checksum enable/disable, and one
++ * extra to avoid wrap.
+ */
+ static int sky2_rx_start(struct sky2_port *sky2)
+ {
+ struct sky2_hw *hw = sky2->hw;
++ struct rx_ring_info *re;
+ unsigned rxq = rxqaddr[sky2->port];
+- int i;
+- unsigned thresh;
++ unsigned i, size, space, thresh;
+
+ sky2->rx_put = sky2->rx_next = 0;
+ sky2_qset(hw, rxq);
+@@ -989,26 +1068,56 @@ static int sky2_rx_start(struct sky2_por
+ sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
+
+ rx_set_checksum(sky2);
++
++ /* Space needed for frame data + headers rounded up */
++ size = ALIGN(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8)
++ + 8;
++
++ /* Stopping point for hardware truncation */
++ thresh = (size - 8) / sizeof(u32);
++
++ /* Account for overhead of skb - to avoid order > 0 allocation */
++ space = SKB_DATA_ALIGN(size) + NET_SKB_PAD
++ + sizeof(struct skb_shared_info);
++
++ sky2->rx_nfrags = space >> PAGE_SHIFT;
++ BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
++
++ if (sky2->rx_nfrags != 0) {
++ /* Compute residue after pages */
++ space = sky2->rx_nfrags << PAGE_SHIFT;
++
++ if (space < size)
++ size -= space;
++ else
++ size = 0;
++
++ /* Optimize to handle small packets and headers */
++ if (size < copybreak)
++ size = copybreak;
++ if (size < ETH_HLEN)
++ size = ETH_HLEN;
++ }
++ sky2->rx_data_size = size;
++
++ /* Fill Rx ring */
+ for (i = 0; i < sky2->rx_pending; i++) {
+- struct ring_info *re = sky2->rx_ring + i;
++ re = sky2->rx_ring + i;
+
+- re->skb = sky2_alloc_skb(sky2->rx_bufsize, GFP_KERNEL);
++ re->skb = sky2_rx_alloc(sky2);
+ if (!re->skb)
+ goto nomem;
+
+- re->mapaddr = pci_map_single(hw->pdev, re->skb->data,
+- sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
+- sky2_rx_add(sky2, re->mapaddr);
++ sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size);
++ sky2_rx_submit(sky2, re);
+ }
+
+-
+ /*
+ * The receiver hangs if it receives frames larger than the
+ * packet buffer. As a workaround, truncate oversize frames, but
+ * the register is limited to 9 bits, so if you do frames > 2052
+ * you better get the MTU right!
+ */
+- thresh = (sky2->rx_bufsize - 8) / sizeof(u32);
+ if (thresh > 0x1ff)
+ sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
+ else {
+@@ -1016,7 +1125,6 @@ static int sky2_rx_start(struct sky2_por
+ sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
+ }
+
+-
+ /* Tell chip about available buffers */
+ sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put);
+ return 0;
+@@ -1075,26 +1183,25 @@ static int sky2_up(struct net_device *de
+ goto err_out;
+ memset(sky2->rx_le, 0, RX_LE_BYTES);
+
+- sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct ring_info),
++ sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info),
+ GFP_KERNEL);
+ if (!sky2->rx_ring)
+ goto err_out;
+
++ sky2_phy_power(hw, port, 1);
++
+ sky2_mac_init(hw, port);
+
+- /* Determine available ram buffer space (in 4K blocks).
+- * Note: not sure about the FE setting below yet
+- */
+- if (hw->chip_id == CHIP_ID_YUKON_FE)
+- ramsize = 4;
+- else
+- ramsize = sky2_read8(hw, B2_E_0);
++ /* Determine available ram buffer space in qwords. */
++ ramsize = sky2_read8(hw, B2_E_0) * 4096/8;
+
+- /* Give transmitter one third (rounded up) */
+- rxspace = ramsize - (ramsize + 2) / 3;
++ if (ramsize > 6*1024/8)
++ rxspace = ramsize - (ramsize + 2) / 3;
++ else
++ rxspace = ramsize / 2;
+
+- sky2_ramset(hw, rxqaddr[port], 0, rxspace);
+- sky2_ramset(hw, txqaddr[port], rxspace, ramsize);
++ sky2_ramset(hw, rxqaddr[port], 0, rxspace-1);
++ sky2_ramset(hw, txqaddr[port], rxspace, ramsize-1);
+
+ /* Make sure SyncQ is disabled */
+ sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL),
+@@ -1103,7 +1210,8 @@ static int sky2_up(struct net_device *de
+ sky2_qset(hw, txqaddr[port]);
+
+ /* Set almost empty threshold */
+- if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == 1)
++ if (hw->chip_id == CHIP_ID_YUKON_EC_U
++ && hw->chip_rev == CHIP_REV_YU_EC_U_A0)
+ sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), 0x1a0);
+
+ sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
+@@ -1163,7 +1271,7 @@ static unsigned tx_le_req(const struct s
+ if (skb_is_gso(skb))
+ ++count;
+
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ ++count;
+
+ return count;
+@@ -1174,8 +1282,6 @@ static unsigned tx_le_req(const struct s
+ * A single packet can generate multiple list elements, and
+ * the number of ring elements will probably be less than the number
+ * of list elements used.
+- *
+- * No BH disabling for tx_lock here (like tg3)
+ */
+ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -1184,33 +1290,13 @@ static int sky2_xmit_frame(struct sk_buf
+ struct sky2_tx_le *le = NULL;
+ struct tx_ring_info *re;
+ unsigned i, len;
+- int avail;
+ dma_addr_t mapping;
+ u32 addr64;
+ u16 mss;
+ u8 ctrl;
+
+- /* No BH disabling for tx_lock here. We are running in BH disabled
+- * context and TX reclaim runs via poll inside of a software
+- * interrupt, and no related locks in IRQ processing.
+- */
+- if (!spin_trylock(&sky2->tx_lock))
+- return NETDEV_TX_LOCKED;
+-
+- if (unlikely(tx_avail(sky2) < tx_le_req(skb))) {
+- /* There is a known but harmless race with lockless tx
+- * and netif_stop_queue.
+- */
+- if (!netif_queue_stopped(dev)) {
+- netif_stop_queue(dev);
+- if (net_ratelimit())
+- printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
+- dev->name);
+- }
+- spin_unlock(&sky2->tx_lock);
+-
+- return NETDEV_TX_BUSY;
+- }
++ if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
++ return NETDEV_TX_BUSY;
+
+ if (unlikely(netif_msg_tx_queued(sky2)))
+ printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n",
+@@ -1220,13 +1306,10 @@ static int sky2_xmit_frame(struct sk_buf
+ mapping = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ addr64 = high32(mapping);
+
+- re = sky2->tx_ring + sky2->tx_prod;
+-
+ /* Send high bits if changed or crosses boundary */
+ if (addr64 != sky2->tx_addr64 || high32(mapping + len) != sky2->tx_addr64) {
+ le = get_tx_le(sky2);
+- le->tx.addr = cpu_to_le32(addr64);
+- le->ctrl = 0;
++ le->addr = cpu_to_le32(addr64);
+ le->opcode = OP_ADDR64 | HW_OWNER;
+ sky2->tx_addr64 = high32(mapping + len);
+ }
+@@ -1234,25 +1317,16 @@ static int sky2_xmit_frame(struct sk_buf
+ /* Check for TCP Segmentation Offload */
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss != 0) {
+- /* just drop the packet if non-linear expansion fails */
+- if (skb_header_cloned(skb) &&
+- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+- dev_kfree_skb(skb);
+- goto out_unlock;
+- }
+-
+ mss += ((skb->h.th->doff - 5) * 4); /* TCP options */
+ mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+ mss += ETH_HLEN;
+- }
+
+- if (mss != sky2->tx_last_mss) {
+- le = get_tx_le(sky2);
+- le->tx.tso.size = cpu_to_le16(mss);
+- le->tx.tso.rsvd = 0;
+- le->opcode = OP_LRGLEN | HW_OWNER;
+- le->ctrl = 0;
+- sky2->tx_last_mss = mss;
++ if (mss != sky2->tx_last_mss) {
++ le = get_tx_le(sky2);
++ le->addr = cpu_to_le32(mss);
++ le->opcode = OP_LRGLEN | HW_OWNER;
++ sky2->tx_last_mss = mss;
++ }
+ }
+
+ ctrl = 0;
+@@ -1261,9 +1335,8 @@ static int sky2_xmit_frame(struct sk_buf
+ if (sky2->vlgrp && vlan_tx_tag_present(skb)) {
+ if (!le) {
+ le = get_tx_le(sky2);
+- le->tx.addr = 0;
++ le->addr = 0;
+ le->opcode = OP_VLAN|HW_OWNER;
+- le->ctrl = 0;
+ } else
+ le->opcode |= OP_VLAN;
+ le->length = cpu_to_be16(vlan_tx_tag_get(skb));
+@@ -1272,73 +1345,72 @@ static int sky2_xmit_frame(struct sk_buf
+ #endif
+
+ /* Handle TCP checksum offload */
+- if (skb->ip_summed == CHECKSUM_HW) {
+- u16 hdr = skb->h.raw - skb->data;
+- u16 offset = hdr + skb->csum;
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
++ unsigned offset = skb->h.raw - skb->data;
++ u32 tcpsum;
++
++ tcpsum = offset << 16; /* sum start */
++ tcpsum |= offset + skb->csum; /* sum write */
+
+ ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
+ if (skb->nh.iph->protocol == IPPROTO_UDP)
+ ctrl |= UDPTCP;
+
+- le = get_tx_le(sky2);
+- le->tx.csum.start = cpu_to_le16(hdr);
+- le->tx.csum.offset = cpu_to_le16(offset);
+- le->length = 0; /* initial checksum value */
+- le->ctrl = 1; /* one packet */
+- le->opcode = OP_TCPLISW | HW_OWNER;
++ if (tcpsum != sky2->tx_tcpsum) {
++ sky2->tx_tcpsum = tcpsum;
++
++ le = get_tx_le(sky2);
++ le->addr = cpu_to_le32(tcpsum);
++ le->length = 0; /* initial checksum value */
++ le->ctrl = 1; /* one packet */
++ le->opcode = OP_TCPLISW | HW_OWNER;
++ }
+ }
+
+ le = get_tx_le(sky2);
+- le->tx.addr = cpu_to_le32((u32) mapping);
++ le->addr = cpu_to_le32((u32) mapping);
+ le->length = cpu_to_le16(len);
+ le->ctrl = ctrl;
+ le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER);
+
+- /* Record the transmit mapping info */
++ re = tx_le_re(sky2, le);
+ re->skb = skb;
+ pci_unmap_addr_set(re, mapaddr, mapping);
++ pci_unmap_len_set(re, maplen, len);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+- struct tx_ring_info *fre;
++ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ addr64 = high32(mapping);
+ if (addr64 != sky2->tx_addr64) {
+ le = get_tx_le(sky2);
+- le->tx.addr = cpu_to_le32(addr64);
++ le->addr = cpu_to_le32(addr64);
+ le->ctrl = 0;
+ le->opcode = OP_ADDR64 | HW_OWNER;
+ sky2->tx_addr64 = addr64;
+ }
+
+ le = get_tx_le(sky2);
+- le->tx.addr = cpu_to_le32((u32) mapping);
++ le->addr = cpu_to_le32((u32) mapping);
+ le->length = cpu_to_le16(frag->size);
+ le->ctrl = ctrl;
+ le->opcode = OP_BUFFER | HW_OWNER;
+
+- fre = sky2->tx_ring
+- + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE);
+- pci_unmap_addr_set(fre, mapaddr, mapping);
++ re = tx_le_re(sky2, le);
++ re->skb = skb;
++ pci_unmap_addr_set(re, mapaddr, mapping);
++ pci_unmap_len_set(re, maplen, frag->size);
+ }
+
+- re->idx = sky2->tx_prod;
+ le->ctrl |= EOP;
+
+- avail = tx_avail(sky2);
+- if (mss != 0 || avail < TX_MIN_PENDING) {
+- le->ctrl |= FRC_STAT;
+- if (avail <= MAX_SKB_TX_LE)
+- netif_stop_queue(dev);
+- }
++ if (tx_avail(sky2) <= MAX_SKB_TX_LE)
++ netif_stop_queue(dev);
+
+ sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod);
+
+-out_unlock:
+- spin_unlock(&sky2->tx_lock);
+-
+ dev->trans_start = jiffies;
+ return NETDEV_TX_OK;
+ }
+@@ -1347,59 +1419,59 @@ out_unlock:
+ * Free ring elements from starting at tx_cons until "done"
+ *
+ * NB: the hardware will tell us about partial completion of multi-part
+- * buffers; these are deferred until completion.
++ * buffers so make sure not to free skb to early.
+ */
+ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
+ {
+ struct net_device *dev = sky2->netdev;
+ struct pci_dev *pdev = sky2->hw->pdev;
+- u16 nxt, put;
+- unsigned i;
++ unsigned idx;
+
+ BUG_ON(done >= TX_RING_SIZE);
+
+- if (unlikely(netif_msg_tx_done(sky2)))
+- printk(KERN_DEBUG "%s: tx done, up to %u\n",
+- dev->name, done);
+-
+- for (put = sky2->tx_cons; put != done; put = nxt) {
+- struct tx_ring_info *re = sky2->tx_ring + put;
+- struct sk_buff *skb = re->skb;
+-
+- nxt = re->idx;
+- BUG_ON(nxt >= TX_RING_SIZE);
+- prefetch(sky2->tx_ring + nxt);
+-
+- /* Check for partial status */
+- if (tx_dist(put, done) < tx_dist(put, nxt))
++ for (idx = sky2->tx_cons; idx != done;
++ idx = RING_NEXT(idx, TX_RING_SIZE)) {
++ struct sky2_tx_le *le = sky2->tx_le + idx;
++ struct tx_ring_info *re = sky2->tx_ring + idx;
++
++ switch(le->opcode & ~HW_OWNER) {
++ case OP_LARGESEND:
++ case OP_PACKET:
++ pci_unmap_single(pdev,
++ pci_unmap_addr(re, mapaddr),
++ pci_unmap_len(re, maplen),
++ PCI_DMA_TODEVICE);
+ break;
+-
+- skb = re->skb;
+- pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
+- skb_headlen(skb), PCI_DMA_TODEVICE);
+-
+- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+- struct tx_ring_info *fre;
+- fre = sky2->tx_ring + RING_NEXT(put + i, TX_RING_SIZE);
+- pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr),
+- skb_shinfo(skb)->frags[i].size,
++ case OP_BUFFER:
++ pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
++ pci_unmap_len(re, maplen),
+ PCI_DMA_TODEVICE);
++ break;
+ }
+
+- dev_kfree_skb(skb);
++ if (le->ctrl & EOP) {
++ if (unlikely(netif_msg_tx_done(sky2)))
++ printk(KERN_DEBUG "%s: tx done %u\n",
++ dev->name, idx);
++ dev_kfree_skb(re->skb);
++ }
++
++ le->opcode = 0; /* paranoia */
+ }
+
+- sky2->tx_cons = put;
++ sky2->tx_cons = idx;
+ if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
+ netif_wake_queue(dev);
+ }
+
+ /* Cleanup all untransmitted buffers, assume transmitter not running */
+-static void sky2_tx_clean(struct sky2_port *sky2)
++static void sky2_tx_clean(struct net_device *dev)
+ {
+- spin_lock_bh(&sky2->tx_lock);
++ struct sky2_port *sky2 = netdev_priv(dev);
++
++ netif_tx_lock_bh(dev);
+ sky2_tx_complete(sky2, sky2->tx_prod);
+- spin_unlock_bh(&sky2->tx_lock);
++ netif_tx_unlock_bh(dev);
+ }
+
+ /* Network shutdown */
+@@ -1421,7 +1493,12 @@ static int sky2_down(struct net_device *
+ /* Stop more packets from being queued */
+ netif_stop_queue(dev);
+
+- sky2_phy_reset(hw, port);
++ /* Disable port IRQ */
++ imask = sky2_read32(hw, B0_IMSK);
++ imask &= ~portirq_msk[port];
++ sky2_write32(hw, B0_IMSK, imask);
++
++ sky2_gmac_reset(hw, port);
+
+ /* Stop transmitter */
+ sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_STOP);
+@@ -1430,6 +1507,13 @@ static int sky2_down(struct net_device *
+ sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL),
+ RB_RST_SET | RB_DIS_OP_MD);
+
++ /* WA for dev. #4.209 */
++ if (hw->chip_id == CHIP_ID_YUKON_EC_U
++ && hw->chip_rev == CHIP_REV_YU_EC_U_A1)
++ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
++ sky2->speed != SPEED_1000 ?
++ TX_STFW_ENA : TX_STFW_DIS);
++
+ ctrl = gma_read16(hw, port, GM_GP_CTRL);
+ ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA);
+ gma_write16(hw, port, GM_GP_CTRL, ctrl);
+@@ -1464,17 +1548,14 @@ static int sky2_down(struct net_device *
+ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+ sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+
+- /* Disable port IRQ */
+- imask = sky2_read32(hw, B0_IMSK);
+- imask &= ~portirq_msk[port];
+- sky2_write32(hw, B0_IMSK, imask);
++ sky2_phy_power(hw, port, 0);
+
+ /* turn off LED's */
+ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
+
+ synchronize_irq(hw->pdev->irq);
+
+- sky2_tx_clean(sky2);
++ sky2_tx_clean(dev);
+ sky2_rx_clean(sky2);
+
+ pci_free_consistent(hw->pdev, RX_LE_BYTES,
+@@ -1497,7 +1578,7 @@ static int sky2_down(struct net_device *
+
+ static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
+ {
+- if (!hw->copper)
++ if (!sky2_is_copper(hw))
+ return SPEED_1000;
+
+ if (hw->chip_id == CHIP_ID_YUKON_FE)
+@@ -1518,41 +1599,17 @@ static void sky2_link_up(struct sky2_por
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ u16 reg;
+-
+- /* Enable Transmit FIFO Underrun */
+- sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
+-
+- reg = gma_read16(hw, port, GM_GP_CTRL);
+- if (sky2->autoneg == AUTONEG_DISABLE) {
+- reg |= GM_GPCR_AU_ALL_DIS;
+-
+- /* Is write/read necessary? Copied from sky2_mac_init */
+- gma_write16(hw, port, GM_GP_CTRL, reg);
+- gma_read16(hw, port, GM_GP_CTRL);
+-
+- switch (sky2->speed) {
+- case SPEED_1000:
+- reg &= ~GM_GPCR_SPEED_100;
+- reg |= GM_GPCR_SPEED_1000;
+- break;
+- case SPEED_100:
+- reg &= ~GM_GPCR_SPEED_1000;
+- reg |= GM_GPCR_SPEED_100;
+- break;
+- case SPEED_10:
+- reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
+- break;
+- }
+- } else
+- reg &= ~GM_GPCR_AU_ALL_DIS;
+-
+- if (sky2->duplex == DUPLEX_FULL || sky2->autoneg == AUTONEG_ENABLE)
+- reg |= GM_GPCR_DUP_FULL;
++ static const char *fc_name[] = {
++ [FC_NONE] = "none",
++ [FC_TX] = "tx",
++ [FC_RX] = "rx",
++ [FC_BOTH] = "both",
++ };
+
+ /* enable Rx/Tx */
++ reg = gma_read16(hw, port, GM_GP_CTRL);
+ reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
+ gma_write16(hw, port, GM_GP_CTRL, reg);
+- gma_read16(hw, port, GM_GP_CTRL);
+
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+
+@@ -1591,8 +1648,7 @@ static void sky2_link_up(struct sky2_por
+ "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
+ sky2->netdev->name, sky2->speed,
+ sky2->duplex == DUPLEX_FULL ? "full" : "half",
+- (sky2->tx_pause && sky2->rx_pause) ? "both" :
+- sky2->tx_pause ? "tx" : sky2->rx_pause ? "rx" : "none");
++ fc_name[sky2->flow_status]);
+ }
+
+ static void sky2_link_down(struct sky2_port *sky2)
+@@ -1606,9 +1662,8 @@ static void sky2_link_down(struct sky2_p
+ reg = gma_read16(hw, port, GM_GP_CTRL);
+ reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
+- gma_read16(hw, port, GM_GP_CTRL); /* PCI post */
+
+- if (sky2->rx_pause && !sky2->tx_pause) {
++ if (sky2->flow_status == FC_RX) {
+ /* restore Asymmetric Pause bit */
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+ gm_phy_read(hw, port, PHY_MARV_AUNE_ADV)
+@@ -1623,9 +1678,18 @@ static void sky2_link_down(struct sky2_p
+
+ if (netif_msg_link(sky2))
+ printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
++
+ sky2_phy_init(hw, port);
+ }
+
++static enum flow_control sky2_flow(int rx, int tx)
++{
++ if (rx)
++ return tx ? FC_BOTH : FC_RX;
++ else
++ return tx ? FC_TX : FC_NONE;
++}
++
+ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
+ {
+ struct sky2_hw *hw = sky2->hw;
+@@ -1639,32 +1703,27 @@ static int sky2_autoneg_done(struct sky2
+ return -1;
+ }
+
+- if (hw->chip_id != CHIP_ID_YUKON_FE &&
+- gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
+- printk(KERN_ERR PFX "%s: master/slave fault",
+- sky2->netdev->name);
+- return -1;
+- }
+-
+ if (!(aux & PHY_M_PS_SPDUP_RES)) {
+ printk(KERN_ERR PFX "%s: speed/duplex mismatch",
+ sky2->netdev->name);
+ return -1;
+ }
+
+- sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
+-
+ sky2->speed = sky2_phy_speed(hw, aux);
++ sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
+
+ /* Pause bits are offset (9..8) */
+ if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
+ aux >>= 6;
+
+- sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
+- sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0;
++ sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
++ aux & PHY_M_PS_TX_P_EN);
++
++ if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
++ && hw->chip_id != CHIP_ID_YUKON_EC_U)
++ sky2->flow_status = FC_NONE;
+
+- if ((sky2->tx_pause || sky2->rx_pause)
+- && !(sky2->speed < SPEED_1000 && sky2->duplex == DUPLEX_HALF))
++ if (aux & PHY_M_PS_RX_P_EN)
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+ else
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+@@ -1679,18 +1738,18 @@ static void sky2_phy_intr(struct sky2_hw
+ struct sky2_port *sky2 = netdev_priv(dev);
+ u16 istatus, phystat;
+
++ if (!netif_running(dev))
++ return;
++
+ spin_lock(&sky2->phy_lock);
+ istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+ phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+
+- if (!netif_running(dev))
+- goto out;
+-
+ if (netif_msg_intr(sky2))
+ printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
+ sky2->netdev->name, istatus, phystat);
+
+- if (istatus & PHY_M_IS_AN_COMPL) {
++ if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) {
+ if (sky2_autoneg_done(sky2, phystat) == 0)
+ sky2_link_up(sky2);
+ goto out;
+@@ -1742,31 +1801,22 @@ static void sky2_tx_timeout(struct net_d
+ } else if (report != sky2->tx_cons) {
+ printk(KERN_INFO PFX "status report lost?\n");
+
+- spin_lock_bh(&sky2->tx_lock);
++ netif_tx_lock_bh(dev);
+ sky2_tx_complete(sky2, report);
+- spin_unlock_bh(&sky2->tx_lock);
++ netif_tx_unlock_bh(dev);
+ } else {
+ printk(KERN_INFO PFX "hardware hung? flushing\n");
+
+ sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
+ sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+
+- sky2_tx_clean(sky2);
++ sky2_tx_clean(dev);
+
+ sky2_qset(hw, txq);
+ sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
+ }
+ }
+
+-
+-/* Want receive buffer size to be multiple of 64 bits
+- * and incl room for vlan and truncation
+- */
+-static inline unsigned sky2_buf_size(int mtu)
+-{
+- return ALIGN(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
+-}
+-
+ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
+ {
+ struct sky2_port *sky2 = netdev_priv(dev);
+@@ -1801,7 +1851,7 @@ static int sky2_change_mtu(struct net_de
+ sky2_rx_clean(sky2);
+
+ dev->mtu = new_mtu;
+- sky2->rx_bufsize = sky2_buf_size(new_mtu);
++
+ mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
+ GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
+
+@@ -1827,20 +1877,105 @@ static int sky2_change_mtu(struct net_de
+ return err;
+ }
+
++/* For small just reuse existing skb for next receive */
++static struct sk_buff *receive_copy(struct sky2_port *sky2,
++ const struct rx_ring_info *re,
++ unsigned length)
++{
++ struct sk_buff *skb;
++
++ skb = netdev_alloc_skb(sky2->netdev, length + 2);
++ if (likely(skb)) {
++ skb_reserve(skb, 2);
++ pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr,
++ length, PCI_DMA_FROMDEVICE);
++ memcpy(skb->data, re->skb->data, length);
++ skb->ip_summed = re->skb->ip_summed;
++ skb->csum = re->skb->csum;
++ pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr,
++ length, PCI_DMA_FROMDEVICE);
++ re->skb->ip_summed = CHECKSUM_NONE;
++ skb_put(skb, length);
++ }
++ return skb;
++}
++
++/* Adjust length of skb with fragments to match received data */
++static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
++ unsigned int length)
++{
++ int i, num_frags;
++ unsigned int size;
++
++ /* put header into skb */
++ size = min(length, hdr_space);
++ skb->tail += size;
++ skb->len += size;
++ length -= size;
++
++ num_frags = skb_shinfo(skb)->nr_frags;
++ for (i = 0; i < num_frags; i++) {
++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++
++ if (length == 0) {
++ /* don't need this page */
++ __free_page(frag->page);
++ --skb_shinfo(skb)->nr_frags;
++ } else {
++ size = min(length, (unsigned) PAGE_SIZE);
++
++ frag->size = size;
++ skb->data_len += size;
++ skb->truesize += size;
++ skb->len += size;
++ length -= size;
++ }
++ }
++}
++
++/* Normal packet - take skb from ring element and put in a new one */
++static struct sk_buff *receive_new(struct sky2_port *sky2,
++ struct rx_ring_info *re,
++ unsigned int length)
++{
++ struct sk_buff *skb, *nskb;
++ unsigned hdr_space = sky2->rx_data_size;
++
++ pr_debug(PFX "receive new length=%d\n", length);
++
++ /* Don't be tricky about reusing pages (yet) */
++ nskb = sky2_rx_alloc(sky2);
++ if (unlikely(!nskb))
++ return NULL;
++
++ skb = re->skb;
++ sky2_rx_unmap_skb(sky2->hw->pdev, re);
++
++ prefetch(skb->data);
++ re->skb = nskb;
++ sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space);
++
++ if (skb_shinfo(skb)->nr_frags)
++ skb_put_frags(skb, hdr_space, length);
++ else
++ skb_put(skb, length);
++ return skb;
++}
++
+ /*
+ * Receive one packet.
+- * For small packets or errors, just reuse existing skb.
+ * For larger packets, get new buffer.
+ */
+-static struct sk_buff *sky2_receive(struct sky2_port *sky2,
++static struct sk_buff *sky2_receive(struct net_device *dev,
+ u16 length, u32 status)
+ {
+- struct ring_info *re = sky2->rx_ring + sky2->rx_next;
++ struct sky2_port *sky2 = netdev_priv(dev);
++ struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
+ struct sk_buff *skb = NULL;
+
+ if (unlikely(netif_msg_rx_status(sky2)))
+ printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
+- sky2->netdev->name, sky2->rx_next, status, length);
++ dev->name, sky2->rx_next, status, length);
+
+ sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
+ prefetch(sky2->rx_ring + sky2->rx_next);
+@@ -1851,43 +1986,15 @@ static struct sk_buff *sky2_receive(stru
+ if (!(status & GMR_FS_RX_OK))
+ goto resubmit;
+
+- if (length > sky2->netdev->mtu + ETH_HLEN)
++ if (length > dev->mtu + ETH_HLEN)
+ goto oversize;
+
+- if (length < copybreak) {
+- skb = alloc_skb(length + 2, GFP_ATOMIC);
+- if (!skb)
+- goto resubmit;
+-
+- skb_reserve(skb, 2);
+- pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->mapaddr,
+- length, PCI_DMA_FROMDEVICE);
+- memcpy(skb->data, re->skb->data, length);
+- skb->ip_summed = re->skb->ip_summed;
+- skb->csum = re->skb->csum;
+- pci_dma_sync_single_for_device(sky2->hw->pdev, re->mapaddr,
+- length, PCI_DMA_FROMDEVICE);
+- } else {
+- struct sk_buff *nskb;
+-
+- nskb = sky2_alloc_skb(sky2->rx_bufsize, GFP_ATOMIC);
+- if (!nskb)
+- goto resubmit;
+-
+- skb = re->skb;
+- re->skb = nskb;
+- pci_unmap_single(sky2->hw->pdev, re->mapaddr,
+- sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
+- prefetch(skb->data);
+-
+- re->mapaddr = pci_map_single(sky2->hw->pdev, nskb->data,
+- sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
+- }
+-
+- skb_put(skb, length);
++ if (length < copybreak)
++ skb = receive_copy(sky2, re, length);
++ else
++ skb = receive_new(sky2, re, length);
+ resubmit:
+- re->skb->ip_summed = CHECKSUM_NONE;
+- sky2_rx_add(sky2, re->mapaddr);
++ sky2_rx_submit(sky2, re);
+
+ return skb;
+
+@@ -1897,10 +2004,14 @@ oversize:
+
+ error:
+ ++sky2->net_stats.rx_errors;
++ if (status & GMR_FS_RX_FF_OV) {
++ sky2->net_stats.rx_fifo_errors++;
++ goto resubmit;
++ }
+
+ if (netif_msg_rx_err(sky2) && net_ratelimit())
+ printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n",
+- sky2->netdev->name, status, length);
++ dev->name, status, length);
+
+ if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
+ sky2->net_stats.rx_length_errors++;
+@@ -1908,8 +2019,6 @@ error:
+ sky2->net_stats.rx_frame_errors++;
+ if (status & GMR_FS_CRC_ERR)
+ sky2->net_stats.rx_crc_errors++;
+- if (status & GMR_FS_RX_FF_OV)
+- sky2->net_stats.rx_fifo_errors++;
+
+ goto resubmit;
+ }
+@@ -1920,18 +2029,12 @@ static inline void sky2_tx_done(struct n
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ if (netif_running(dev)) {
+- spin_lock(&sky2->tx_lock);
++ netif_tx_lock(dev);
+ sky2_tx_complete(sky2, last);
+- spin_unlock(&sky2->tx_lock);
++ netif_tx_unlock(dev);
+ }
+ }
+
+-/* Is status ring empty or is there more to do? */
+-static inline int sky2_more_work(const struct sky2_hw *hw)
+-{
+- return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX));
+-}
+-
+ /* Process status response ring */
+ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
+ {
+@@ -1955,16 +2058,15 @@ static int sky2_status_intr(struct sky2_
+ dev = hw->dev[le->link];
+
+ sky2 = netdev_priv(dev);
+- length = le->length;
+- status = le->status;
++ length = le16_to_cpu(le->length);
++ status = le32_to_cpu(le->status);
+
+ switch (le->opcode & ~HW_OWNER) {
+ case OP_RXSTAT:
+- skb = sky2_receive(sky2, length, status);
++ skb = sky2_receive(dev, length, status);
+ if (!skb)
+ break;
+
+- skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+
+@@ -2000,8 +2102,8 @@ static int sky2_status_intr(struct sky2_
+ #endif
+ case OP_RXCHKS:
+ skb = sky2->rx_ring[sky2->rx_next].skb;
+- skb->ip_summed = CHECKSUM_HW;
+- skb->csum = le16_to_cpu(status);
++ skb->ip_summed = CHECKSUM_COMPLETE;
++ skb->csum = status & 0xffff;
+ break;
+
+ case OP_TXINDEXLE:
+@@ -2022,6 +2124,9 @@ static int sky2_status_intr(struct sky2_
+ }
+ }
+
++ /* Fully processed status ring so clear irq */
++ sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
++
+ exit_loop:
+ if (buf_write[0]) {
+ sky2 = netdev_priv(hw->dev[0]);
+@@ -2097,7 +2202,7 @@ static void sky2_hw_intr(struct sky2_hw
+
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ sky2_pci_write16(hw, PCI_STATUS,
+- pci_err | PCI_STATUS_ERROR_BITS);
++ pci_err | PCI_STATUS_ERROR_BITS);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ }
+
+@@ -2231,22 +2336,19 @@ static int sky2_poll(struct net_device *
+ sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
+
+ work_done = sky2_status_intr(hw, work_limit);
+- *budget -= work_done;
+- dev0->quota -= work_done;
+-
+- if (status & Y2_IS_STAT_BMU)
+- sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
++ if (work_done < work_limit) {
++ netif_rx_complete(dev0);
+
+- if (sky2_more_work(hw))
++ sky2_read32(hw, B0_Y2_SP_LISR);
++ return 0;
++ } else {
++ *budget -= work_done;
++ dev0->quota -= work_done;
+ return 1;
+-
+- netif_rx_complete(dev0);
+-
+- sky2_read32(hw, B0_Y2_SP_LISR);
+- return 0;
++ }
+ }
+
+-static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sky2_intr(int irq, void *dev_id)
+ {
+ struct sky2_hw *hw = dev_id;
+ struct net_device *dev0 = hw->dev[0];
+@@ -2303,7 +2405,7 @@ static inline u32 sky2_clk2us(const stru
+ static int sky2_reset(struct sky2_hw *hw)
+ {
+ u16 status;
+- u8 t8, pmd_type;
++ u8 t8;
+ int i;
+
+ sky2_write8(hw, B0_CTST, CS_RST_CLR);
+@@ -2349,9 +2451,7 @@ static int sky2_reset(struct sky2_hw *hw
+ sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
+
+
+- pmd_type = sky2_read8(hw, B2_PMD_TYP);
+- hw->copper = !(pmd_type == 'L' || pmd_type == 'S');
+-
++ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+ hw->ports = 1;
+ t8 = sky2_read8(hw, B2_Y2_HW_RES);
+ if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+@@ -2409,7 +2509,7 @@ static int sky2_reset(struct sky2_hw *hw
+ sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK);
+
+ for (i = 0; i < hw->ports; i++)
+- sky2_phy_reset(hw, i);
++ sky2_gmac_reset(hw, i);
+
+ memset(hw->st_le, 0, STATUS_LE_BYTES);
+ hw->st_idx = 0;
+@@ -2448,21 +2548,22 @@ static int sky2_reset(struct sky2_hw *hw
+
+ static u32 sky2_supported_modes(const struct sky2_hw *hw)
+ {
+- u32 modes;
+- if (hw->copper) {
+- modes = SUPPORTED_10baseT_Half
+- | SUPPORTED_10baseT_Full
+- | SUPPORTED_100baseT_Half
+- | SUPPORTED_100baseT_Full
+- | SUPPORTED_Autoneg | SUPPORTED_TP;
++ if (sky2_is_copper(hw)) {
++ u32 modes = SUPPORTED_10baseT_Half
++ | SUPPORTED_10baseT_Full
++ | SUPPORTED_100baseT_Half
++ | SUPPORTED_100baseT_Full
++ | SUPPORTED_Autoneg | SUPPORTED_TP;
+
+ if (hw->chip_id != CHIP_ID_YUKON_FE)
+ modes |= SUPPORTED_1000baseT_Half
+- | SUPPORTED_1000baseT_Full;
++ | SUPPORTED_1000baseT_Full;
++ return modes;
+ } else
+- modes = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+- | SUPPORTED_Autoneg;
+- return modes;
++ return SUPPORTED_1000baseT_Half
++ | SUPPORTED_1000baseT_Full
++ | SUPPORTED_Autoneg
++ | SUPPORTED_FIBRE;
+ }
+
+ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+@@ -2473,7 +2574,7 @@ static int sky2_get_settings(struct net_
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = sky2_supported_modes(hw);
+ ecmd->phy_address = PHY_ADDR_MARV;
+- if (hw->copper) {
++ if (sky2_is_copper(hw)) {
+ ecmd->supported = SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+@@ -2482,12 +2583,14 @@ static int sky2_get_settings(struct net_
+ | SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP;
+ ecmd->port = PORT_TP;
+- } else
++ ecmd->speed = sky2->speed;
++ } else {
++ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_FIBRE;
++ }
+
+ ecmd->advertising = sky2->advertising;
+ ecmd->autoneg = sky2->autoneg;
+- ecmd->speed = sky2->speed;
+ ecmd->duplex = sky2->duplex;
+ return 0;
+ }
+@@ -2635,7 +2738,7 @@ static int sky2_nway_reset(struct net_de
+ {
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+- if (sky2->autoneg != AUTONEG_ENABLE)
++ if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+
+ sky2_phy_reinit(sky2);
+@@ -2737,6 +2840,14 @@ static int sky2_set_mac_address(struct n
+ return 0;
+ }
+
++static void inline sky2_add_filter(u8 filter[8], const u8 *addr)
++{
++ u32 bit;
++
++ bit = ether_crc(ETH_ALEN, addr) & 63;
++ filter[bit >> 3] |= 1 << (bit & 7);
++}
++
+ static void sky2_set_multicast(struct net_device *dev)
+ {
+ struct sky2_port *sky2 = netdev_priv(dev);
+@@ -2745,7 +2856,10 @@ static void sky2_set_multicast(struct ne
+ struct dev_mc_list *list = dev->mc_list;
+ u16 reg;
+ u8 filter[8];
++ int rx_pause;
++ static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
+
++ rx_pause = (sky2->flow_status == FC_RX || sky2->flow_status == FC_BOTH);
+ memset(filter, 0, sizeof(filter));
+
+ reg = gma_read16(hw, port, GM_RX_CTRL);
+@@ -2753,18 +2867,19 @@ static void sky2_set_multicast(struct ne
+
+ if (dev->flags & IFF_PROMISC) /* promiscuous */
+ reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+- else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16) /* all multicast */
++ else if (dev->flags & IFF_ALLMULTI)
+ memset(filter, 0xff, sizeof(filter));
+- else if (dev->mc_count == 0) /* no multicast */
++ else if (dev->mc_count == 0 && !rx_pause)
+ reg &= ~GM_RXCR_MCF_ENA;
+ else {
+ int i;
+ reg |= GM_RXCR_MCF_ENA;
+
+- 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);
+- }
++ if (rx_pause)
++ sky2_add_filter(filter, pause_mc_addr);
++
++ for (i = 0; list && i < dev->mc_count; i++, list = list->next)
++ sky2_add_filter(filter, list->dmi_addr);
+ }
+
+ gma_write16(hw, port, GM_MC_ADDR_H1,
+@@ -2877,8 +2992,20 @@ static void sky2_get_pauseparam(struct n
+ {
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+- ecmd->tx_pause = sky2->tx_pause;
+- ecmd->rx_pause = sky2->rx_pause;
++ switch (sky2->flow_mode) {
++ case FC_NONE:
++ ecmd->tx_pause = ecmd->rx_pause = 0;
++ break;
++ case FC_TX:
++ ecmd->tx_pause = 1, ecmd->rx_pause = 0;
++ break;
++ case FC_RX:
++ ecmd->tx_pause = 0, ecmd->rx_pause = 1;
++ break;
++ case FC_BOTH:
++ ecmd->tx_pause = ecmd->rx_pause = 1;
++ }
++
+ ecmd->autoneg = sky2->autoneg;
+ }
+
+@@ -2886,15 +3013,14 @@ static int sky2_set_pauseparam(struct ne
+ struct ethtool_pauseparam *ecmd)
+ {
+ struct sky2_port *sky2 = netdev_priv(dev);
+- int err = 0;
+
+ sky2->autoneg = ecmd->autoneg;
+- sky2->tx_pause = ecmd->tx_pause != 0;
+- sky2->rx_pause = ecmd->rx_pause != 0;
++ sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause);
+
+- sky2_phy_reinit(sky2);
++ if (netif_running(dev))
++ sky2_phy_reinit(sky2);
+
+- return err;
++ return 0;
+ }
+
+ static int sky2_get_coalesce(struct net_device *dev,
+@@ -3051,7 +3177,7 @@ static void sky2_get_regs(struct net_dev
+ regs->len - B3_RI_WTO_R1);
+ }
+
+-static struct ethtool_ops sky2_ethtool_ops = {
++static const struct ethtool_ops sky2_ethtool_ops = {
+ .get_settings = sky2_get_settings,
+ .set_settings = sky2_set_settings,
+ .get_drvinfo = sky2_get_drvinfo,
+@@ -3112,7 +3238,11 @@ static __devinit struct net_device *sky2
+ dev->poll = sky2_poll;
+ dev->weight = NAPI_WEIGHT;
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+- dev->poll_controller = sky2_netpoll;
++ /* Network console (only works on port 0)
++ * because netpoll makes assumptions about NAPI
++ */
++ if (port == 0)
++ dev->poll_controller = sky2_netpoll;
+ #endif
+
+ sky2 = netdev_priv(dev);
+@@ -3120,11 +3250,10 @@ static __devinit struct net_device *sky2
+ sky2->hw = hw;
+ sky2->msg_enable = netif_msg_init(debug, default_msg);
+
+- spin_lock_init(&sky2->tx_lock);
+ /* Auto speed and flow control */
+ sky2->autoneg = AUTONEG_ENABLE;
+- sky2->tx_pause = 1;
+- sky2->rx_pause = 1;
++ sky2->flow_mode = FC_BOTH;
++
+ sky2->duplex = -1;
+ sky2->speed = -1;
+ sky2->advertising = sky2_supported_modes(hw);
+@@ -3133,13 +3262,11 @@ static __devinit struct net_device *sky2
+ spin_lock_init(&sky2->phy_lock);
+ sky2->tx_pending = TX_DEF_PENDING;
+ sky2->rx_pending = RX_DEF_PENDING;
+- sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN);
+
+ hw->dev[port] = dev;
+
+ sky2->port = port;
+
+- dev->features |= NETIF_F_LLTX;
+ if (hw->chip_id != CHIP_ID_YUKON_EC_U)
+ dev->features |= NETIF_F_TSO;
+ if (highmem)
+@@ -3175,8 +3302,7 @@ static void __devinit sky2_show_addr(str
+ }
+
+ /* Handle software interrupt used during MSI test */
+-static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id)
+ {
+ struct sky2_hw *hw = dev_id;
+ u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2);
+@@ -3200,6 +3326,8 @@ static int __devinit sky2_test_msi(struc
+ struct pci_dev *pdev = hw->pdev;
+ int err;
+
++ init_waitqueue_head (&hw->msi_wait);
++
+ sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
+
+ err = request_irq(pdev->irq, sky2_test_intr, IRQF_SHARED, DRV_NAME, hw);
+@@ -3209,18 +3337,15 @@ static int __devinit sky2_test_msi(struc
+ return err;
+ }
+
+- init_waitqueue_head (&hw->msi_wait);
+-
+ sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
+- wmb();
++ sky2_read8(hw, B0_CTST);
+
+ wait_event_timeout(hw->msi_wait, hw->msi_detected, HZ/10);
+
+ if (!hw->msi_detected) {
+ /* MSI test failed, go back to INTx mode */
+- printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
+- "switching to INTx mode. Please report this failure to "
+- "the PCI maintainer and include system chipset information.\n",
++ printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
++ "switching to INTx mode.\n",
+ pci_name(pdev));
+
+ err = -EOPNOTSUPP;
+@@ -3228,6 +3353,7 @@ static int __devinit sky2_test_msi(struc
+ }
+
+ sky2_write32(hw, B0_IMSK, 0);
++ sky2_read32(hw, B0_IMSK);
+
+ free_irq(pdev->irq, hw);
+
+@@ -3304,12 +3430,13 @@ static int __devinit sky2_probe(struct p
+ hw->pm_cap = pm_cap;
+
+ #ifdef __BIG_ENDIAN
+- /* byte swap descriptors in hardware */
++ /* The sk98lin vendor driver uses hardware byte swapping but
++ * this driver uses software swapping.
++ */
+ {
+ u32 reg;
+-
+ reg = sky2_pci_read32(hw, PCI_DEV_REG2);
+- reg |= PCI_REV_DESC;
++ reg &= ~PCI_REV_DESC;
+ sky2_pci_write32(hw, PCI_DEV_REG2, reg);
+ }
+ #endif
+@@ -3333,6 +3460,14 @@ static int __devinit sky2_probe(struct p
+ if (!dev)
+ goto err_out_free_pci;
+
++ if (!disable_msi && pci_enable_msi(pdev) == 0) {
++ err = sky2_test_msi(hw);
++ if (err == -EOPNOTSUPP)
++ pci_disable_msi(pdev);
++ else if (err)
++ goto err_out_free_netdev;
++ }
++
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "%s: cannot register net device\n",
+@@ -3340,6 +3475,14 @@ static int __devinit sky2_probe(struct p
+ goto err_out_free_netdev;
+ }
+
++ err = request_irq(pdev->irq, sky2_intr, IRQF_SHARED, dev->name, hw);
++ if (err) {
++ printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
++ pci_name(pdev), pdev->irq);
++ goto err_out_unregister;
++ }
++ sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
++
+ sky2_show_addr(dev);
+
+ if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) {
+@@ -3354,23 +3497,6 @@ static int __devinit sky2_probe(struct p
+ }
+ }
+
+- if (!disable_msi && pci_enable_msi(pdev) == 0) {
+- err = sky2_test_msi(hw);
+- if (err == -EOPNOTSUPP)
+- pci_disable_msi(pdev);
+- else if (err)
+- goto err_out_unregister;
+- }
+-
+- err = request_irq(pdev->irq, sky2_intr, IRQF_SHARED, DRV_NAME, hw);
+- if (err) {
+- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+- pci_name(pdev), pdev->irq);
+- goto err_out_unregister;
+- }
+-
+- sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+-
+ setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
+ sky2_idle_start(hw);
+
+@@ -3380,10 +3506,6 @@ static int __devinit sky2_probe(struct p
+
+ err_out_unregister:
+ pci_disable_msi(pdev);
+- if (dev1) {
+- unregister_netdev(dev1);
+- free_netdev(dev1);
+- }
+ unregister_netdev(dev);
+ err_out_free_netdev:
+ free_netdev(dev);
+diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
+index 2db8d19..6d2a23f 100644
+--- a/drivers/net/sky2.h
++++ b/drivers/net/sky2.h
+@@ -4,6 +4,8 @@
+ #ifndef _SKY2_H
+ #define _SKY2_H
+
++#define ETH_JUMBO_MTU 9000 /* Maximum MTU supported */
++
+ /* PCI config registers */
+ enum {
+ PCI_DEV_REG1 = 0x40,
+@@ -1318,6 +1320,14 @@ enum {
+ };
+
+ /* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
++/***** PHY_MARV_PHY_CTRL (page 1) 16 bit r/w Fiber Specific Ctrl *****/
++enum {
++ PHY_M_FIB_FORCE_LNK = 1<<10,/* Force Link Good */
++ PHY_M_FIB_SIGD_POL = 1<<9, /* SIGDET Polarity */
++ PHY_M_FIB_TX_DIS = 1<<3, /* Transmitter Disable */
++};
++
++/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
+ /***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/
+ enum {
+ PHY_M_MAC_MD_MSK = 7<<7, /* Bit 9.. 7: Mode Select Mask */
+@@ -1566,7 +1576,7 @@ enum {
+
+ GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
+ GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
+- GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
++ GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC |
+ GMR_FS_UN_SIZE | GMR_FS_JABBER,
+ };
+
+@@ -1748,7 +1758,6 @@ enum {
+ INIT_SUM= 1<<3,
+ LOCK_SUM= 1<<4,
+ INS_VLAN= 1<<5,
+- FRC_STAT= 1<<6,
+ EOP = 1<<7,
+ };
+
+@@ -1784,21 +1793,9 @@ enum {
+ OP_TXINDEXLE = 0x68,
+ };
+
+-/* Yukon 2 hardware interface
+- * Not tested on big endian
+- */
++/* Yukon 2 hardware interface */
+ struct sky2_tx_le {
+- union {
+- __le32 addr;
+- struct {
+- __le16 offset;
+- __le16 start;
+- } csum __attribute((packed));
+- struct {
+- __le16 size;
+- __le16 rsvd;
+- } tso __attribute((packed));
+- } tx;
++ __le32 addr;
+ __le16 length; /* also vlan tag or checksum start */
+ u8 ctrl;
+ u8 opcode;
+@@ -1821,12 +1818,21 @@ struct sky2_status_le {
+ struct tx_ring_info {
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+- u16 idx;
++ DECLARE_PCI_UNMAP_ADDR(maplen);
+ };
+
+-struct ring_info {
++struct rx_ring_info {
+ struct sk_buff *skb;
+- dma_addr_t mapaddr;
++ dma_addr_t data_addr;
++ DECLARE_PCI_UNMAP_ADDR(data_size);
++ dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
++};
++
++enum flow_control {
++ FC_NONE = 0,
++ FC_TX = 1,
++ FC_RX = 2,
++ FC_BOTH = 3,
+ };
+
+ struct sky2_port {
+@@ -1836,7 +1842,6 @@ struct sky2_port {
+ u32 msg_enable;
+ spinlock_t phy_lock;
+
+- spinlock_t tx_lock ____cacheline_aligned_in_smp;
+ struct tx_ring_info *tx_ring;
+ struct sky2_tx_le *tx_le;
+ u16 tx_cons; /* next le to check */
+@@ -1844,14 +1849,17 @@ struct sky2_port {
+ u32 tx_addr64;
+ u16 tx_pending;
+ u16 tx_last_mss;
++ u32 tx_tcpsum;
+
+- struct ring_info *rx_ring ____cacheline_aligned_in_smp;
++ struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp;
+ struct sky2_rx_le *rx_le;
+ u32 rx_addr64;
+ u16 rx_next; /* next re to check */
+ u16 rx_put; /* next le index to use */
+ u16 rx_pending;
+- u16 rx_bufsize;
++ u16 rx_data_size;
++ u16 rx_nfrags;
++
+ #ifdef SKY2_VLAN_TAG_USED
+ u16 rx_tag;
+ struct vlan_group *vlgrp;
+@@ -1859,13 +1867,13 @@ struct sky2_port {
+
+ dma_addr_t rx_le_map;
+ dma_addr_t tx_le_map;
+- u32 advertising; /* ADVERTISED_ bits */
++ u16 advertising; /* ADVERTISED_ bits */
+ u16 speed; /* SPEED_1000, SPEED_100, ... */
+ u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
+ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
+- u8 rx_pause;
+- u8 tx_pause;
+ u8 rx_csum;
++ enum flow_control flow_mode;
++ enum flow_control flow_status;
+
+ struct net_device_stats net_stats;
+
+@@ -1879,7 +1887,7 @@ struct sky2_hw {
+ int pm_cap;
+ u8 chip_id;
+ u8 chip_rev;
+- u8 copper;
++ u8 pmd_type;
+ u8 ports;
+
+ struct sky2_status_le *st_le;
+@@ -1891,6 +1899,11 @@ struct sky2_hw {
+ wait_queue_head_t msi_wait;
+ };
+
++static inline int sky2_is_copper(const struct sky2_hw *hw)
++{
++ return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P');
++}
++
+ /* Register accessor for memory mapped device */
+ static inline u32 sky2_read32(const struct sky2_hw *hw, unsigned reg)
+ {
+diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
+index 3a1b713..0adab70 100644
+--- a/drivers/net/slhc.c
++++ b/drivers/net/slhc.c
+@@ -42,7 +42,7 @@
+ * Modularization.
+ * - Jan 1995 Bjorn Ekwall
+ * Use ip_fast_csum from ip.h
+- * - July 1995 Christos A. Polyzols
++ * - July 1995 Christos A. Polyzols
+ * Spotted bug in tcp option checking
+ *
+ *
+@@ -94,27 +94,23 @@ slhc_init(int rslots, int tslots)
+ register struct cstate *ts;
+ struct slcompress *comp;
+
+- comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
+- GFP_KERNEL);
++ comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
+ if (! comp)
+ goto out_fail;
+- memset(comp, 0, sizeof(struct slcompress));
+
+ if ( rslots > 0 && rslots < 256 ) {
+ size_t rsize = rslots * sizeof(struct cstate);
+- comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL);
++ comp->rstate = kzalloc(rsize, GFP_KERNEL);
+ if (! comp->rstate)
+ goto out_free;
+- memset(comp->rstate, 0, rsize);
+ comp->rslot_limit = rslots - 1;
+ }
+
+ if ( tslots > 0 && tslots < 256 ) {
+ size_t tsize = tslots * sizeof(struct cstate);
+- comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL);
++ comp->tstate = kzalloc(tsize, GFP_KERNEL);
+ if (! comp->tstate)
+ goto out_free2;
+- memset(comp->tstate, 0, tsize);
+ comp->tslot_limit = tslots - 1;
+ }
+
+@@ -141,9 +137,9 @@ slhc_init(int rslots, int tslots)
+ return comp;
+
+ out_free2:
+- kfree((unsigned char *)comp->rstate);
++ kfree(comp->rstate);
+ out_free:
+- kfree((unsigned char *)comp);
++ kfree(comp);
+ out_fail:
+ return NULL;
+ }
+@@ -242,10 +238,10 @@ slhc_compress(struct slcompress *comp, u
+ /*
+ * Don't play with runt packets.
+ */
+-
++
+ if(isize<sizeof(struct iphdr))
+ return isize;
+-
++
+ ip = (struct iphdr *) icp;
+
+ /* Bail if this packet isn't TCP, or is an IP fragment */
+@@ -700,20 +696,6 @@ EXPORT_SYMBOL(slhc_compress);
+ EXPORT_SYMBOL(slhc_uncompress);
+ EXPORT_SYMBOL(slhc_toss);
+
+-#ifdef MODULE
+-
+-int init_module(void)
+-{
+- printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n");
+- return 0;
+-}
+-
+-void cleanup_module(void)
+-{
+- return;
+-}
+-
+-#endif /* MODULE */
+ #else /* CONFIG_INET */
+
+
+diff --git a/drivers/net/slip.c b/drivers/net/slip.c
+index 1588cb7..39c2152 100644
+--- a/drivers/net/slip.c
++++ b/drivers/net/slip.c
+@@ -113,7 +113,7 @@ static int sl_ioctl(struct net_device *d
+ * on actively running device.
+ *********************************/
+
+-/*
++/*
+ Allocate channel buffers.
+ */
+
+@@ -207,7 +207,7 @@ sl_free_bufs(struct slip *sl)
+ #endif
+ }
+
+-/*
++/*
+ Reallocate slip channel buffers.
+ */
+
+@@ -354,7 +354,7 @@ sl_bump(struct slip *sl)
+ #endif /* SL_INCLUDE_CSLIP */
+
+ sl->rx_bytes+=count;
+-
++
+ skb = dev_alloc_skb(count);
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
+@@ -602,7 +602,7 @@ static int sl_init(struct net_device *de
+ struct slip *sl = netdev_priv(dev);
+
+ /*
+- * Finish setting up the DEVICE info.
++ * Finish setting up the DEVICE info.
+ */
+
+ dev->mtu = sl->mtu;
+@@ -658,7 +658,7 @@ static void sl_setup(struct net_device *
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
+ */
+-
++
+ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+ {
+ struct slip *sl = (struct slip *) tty->disc_data;
+@@ -720,7 +720,7 @@ sl_alloc(dev_t line)
+ struct net_device *dev = NULL;
+ struct slip *sl;
+
+- if (slip_devs == NULL)
++ if (slip_devs == NULL)
+ return NULL; /* Master array missing ! */
+
+ for (i = 0; i < slip_maxdev; i++) {
+@@ -788,7 +788,7 @@ sl_alloc(dev_t line)
+ slip_devs[i] = NULL;
+ }
+ }
+-
++
+ if (!dev) {
+ char name[IFNAMSIZ];
+ sprintf(name, "sl%d", i);
+@@ -815,7 +815,7 @@ sl_alloc(dev_t line)
+ sl->outfill_timer.function=sl_outfill;
+ #endif
+ slip_devs[i] = dev;
+-
++
+ return sl;
+ }
+
+@@ -836,7 +836,7 @@ static int slip_open(struct tty_struct *
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+-
++
+ /* RTnetlink lock is misused here to serialize concurrent
+ opens of slip channels. There are better ways, but it is
+ the simplest one.
+@@ -862,7 +862,7 @@ static int slip_open(struct tty_struct *
+ tty->disc_data = sl;
+ sl->line = tty_devnum(tty);
+ sl->pid = current->pid;
+-
++
+ if (!test_bit(SLF_INUSE, &sl->flags)) {
+ /* Perform the low-level SLIP initialization. */
+ if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0)
+@@ -908,7 +908,7 @@ err_exit:
+ /*
+
+ FIXME: 1,2 are fixed 3 was never true anyway.
+-
++
+ Let me to blame a bit.
+ 1. TTY module calls this funstion on soft interrupt.
+ 2. TTY module calls this function WITH MASKED INTERRUPTS!
+@@ -920,7 +920,7 @@ err_exit:
+
+ By-product (not desired): sl? does not feel hangups and remains open.
+ It is supposed, that user level program (dip, diald, slattach...)
+- will catch SIGHUP and make the rest of work.
++ will catch SIGHUP and make the rest of work.
+
+ I see no way to make more with current tty code. --ANK
+ */
+@@ -1291,7 +1291,7 @@ static int sl_ioctl(struct net_device *d
+ break;
+
+ case SIOCSLEASE:
+- /* Resolve race condition, when ioctl'ing hanged up
++ /* Resolve race condition, when ioctl'ing hanged up
+ and opened by another process device.
+ */
+ if (sl->tty != current->signal->tty && sl->pid != current->pid) {
+@@ -1350,7 +1350,7 @@ static int __init slip_init(void)
+ }
+
+ /* Clear the pointer array, we allocate devices when we need them */
+- memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
++ memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
+
+ /* Fill in our line protocol discipline, and register it */
+ if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
+@@ -1368,7 +1368,7 @@ static void __exit slip_exit(void)
+ unsigned long timeout = jiffies + HZ;
+ int busy = 0;
+
+- if (slip_devs == NULL)
++ if (slip_devs == NULL)
+ return;
+
+ /* First of all: check for active disciplines and hangup them.
+@@ -1405,7 +1405,7 @@ static void __exit slip_exit(void)
+ dev->name);
+ /* Intentionally leak the control block. */
+ dev->destructor = NULL;
+- }
++ }
+
+ unregister_netdev(dev);
+ }
+diff --git a/drivers/net/slip.h b/drivers/net/slip.h
+index 29d87dd..853e0f6 100644
+--- a/drivers/net/slip.h
++++ b/drivers/net/slip.h
+@@ -107,12 +107,12 @@ struct slip {
+ #define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP)
+ #define SL_MODE_AX25 4
+ #define SL_MODE_ADAPTIVE 8
+-#ifdef CONFIG_SLIP_SMART
++#ifdef CONFIG_SLIP_SMART
+ unsigned char outfill; /* # of sec between outfill packet */
+ unsigned char keepalive; /* keepalive seconds */
+ struct timer_list outfill_timer;
+ struct timer_list keepalive_timer;
+-#endif
++#endif
+ };
+
+ #define SLIP_MAGIC 0x5302
+diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
+index f00c476..7122932 100644
+--- a/drivers/net/smc-mca.c
++++ b/drivers/net/smc-mca.c
+@@ -250,9 +250,9 @@ static int __init ultramca_probe(struct
+ break;
+ }
+ }
+-
+- if(!tirq || !tbase
+- || (irq && irq != tirq)
++
++ if(!tirq || !tbase
++ || (irq && irq != tirq)
+ || (base_addr && tbase != base_addr))
+ /* FIXME: we're trying to force the ordering of the
+ * devices here, there should be a way of getting this
+@@ -310,7 +310,7 @@ static int __init ultramca_probe(struct
+ * the index of the 0x2000 step.
+ * beware different number of pages [hs]
+ */
+- dev->mem_start = (unsigned long)
++ dev->mem_start = (unsigned long)
+ mca_device_transform_memory(mca_dev, (void *)(0xc0000 + (0x2000 * (pos3 & 0xf))));
+ num_pages = 0x20 + (2 * (pos3 & 0x10));
+ break;
+@@ -501,7 +501,7 @@ static int ultramca_close_card(struct ne
+ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+
+ netif_stop_queue(dev);
+-
++
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
+index 4544935..889ef0d 100644
+--- a/drivers/net/smc-ultra.c
++++ b/drivers/net/smc-ultra.c
+@@ -111,7 +111,7 @@ static struct isapnp_device_id ultra_dev
+ MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
+ #endif
+
+-
++
+ #define START_PG 0x00 /* First page of TX buffer */
+
+ #define ULTRA_CMDREG 0 /* Offset to ASIC command register. */
+@@ -122,12 +122,12 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device
+ #define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
+ #define ULTRA_IO_EXTENT 32
+ #define EN0_ERWCNT 0x08 /* Early receive warning count. */
+-
++
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ static void ultra_poll(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- ei_interrupt(dev->irq, dev, NULL);
++ ei_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -536,7 +536,7 @@ ultra_close_card(struct net_device *dev)
+ return 0;
+ }
+
+-
++
+ #ifdef MODULE
+ #define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */
+ static struct net_device *dev_ultra[MAX_ULTRA_CARDS];
+diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
+index 85be22a..e10755e 100644
+--- a/drivers/net/smc-ultra32.c
++++ b/drivers/net/smc-ultra32.c
+@@ -74,7 +74,7 @@ static void ultra32_block_output(struct
+ const unsigned char *buf,
+ const int start_page);
+ static int ultra32_close(struct net_device *dev);
+-
++
+ #define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */
+ #define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */
+ #define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */
+@@ -314,7 +314,7 @@ static int ultra32_close(struct net_devi
+ int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
+
+ netif_stop_queue(dev);
+-
++
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+@@ -413,7 +413,7 @@ static void ultra32_block_output(struct
+
+ memcpy_toio(xfer_start, buf, count);
+ }
+-
++
+ #ifdef MODULE
+ #define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */
+ static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
+diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
+index 0b15290..2c43433 100644
+--- a/drivers/net/smc911x.c
++++ b/drivers/net/smc911x.c
+@@ -55,8 +55,6 @@ static const char version[] =
+ )
+ #endif
+
+-
+-#include <linux/config.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -1076,7 +1074,7 @@ static void smc911x_phy_interrupt(struct
+ * This is the main routine of the driver, to handle the device when
+ * it needs some attention.
+ */
+-static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ unsigned long ioaddr = dev->base_addr;
+@@ -1253,7 +1251,7 @@ static irqreturn_t smc911x_interrupt(int
+
+ #ifdef SMC_USE_DMA
+ static void
+-smc911x_tx_dma_irq(int dma, void *data, struct pt_regs *regs)
++smc911x_tx_dma_irq(int dma, void *data)
+ {
+ struct net_device *dev = (struct net_device *)data;
+ struct smc911x_local *lp = netdev_priv(dev);
+@@ -1287,7 +1285,7 @@ smc911x_tx_dma_irq(int dma, void *data,
+ "%s: TX DMA irq completed\n", dev->name);
+ }
+ static void
+-smc911x_rx_dma_irq(int dma, void *data, struct pt_regs *regs)
++smc911x_rx_dma_irq(int dma, void *data)
+ {
+ struct net_device *dev = (struct net_device *)data;
+ unsigned long ioaddr = dev->base_addr;
+@@ -1823,7 +1821,7 @@ static int smc911x_ethtool_geteeprom_len
+ return SMC911X_EEPROM_LEN;
+ }
+
+-static struct ethtool_ops smc911x_ethtool_ops = {
++static const struct ethtool_ops smc911x_ethtool_ops = {
+ .get_settings = smc911x_ethtool_getsettings,
+ .set_settings = smc911x_ethtool_setsettings,
+ .get_drvinfo = smc911x_ethtool_getdrvinfo,
+diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
+index 8b0321f..c0d13d6 100644
+--- a/drivers/net/smc9194.c
++++ b/drivers/net/smc9194.c
+@@ -270,7 +270,7 @@ static void smc_set_multicast_list(struc
+ /*
+ . Handles the actual interrupt
+ */
+-static irqreturn_t smc_interrupt(int irq, void *, struct pt_regs *regs);
++static irqreturn_t smc_interrupt(int irq, void *);
+ /*
+ . This is a separate procedure to handle the receipt of a packet, to
+ . leave the interrupt code looking slightly cleaner
+@@ -529,7 +529,7 @@ static int smc_wait_to_send_packet( stru
+ }
+ length = ETH_ZLEN;
+ }
+-
++
+ /*
+ ** The MMU wants the number of pages to be the number of 256 bytes
+ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+@@ -1159,7 +1159,7 @@ static int smc_open(struct net_device *d
+ address |= dev->dev_addr[ i ];
+ outw( address, ioaddr + ADDR0 + i );
+ }
+-
++
+ netif_start_queue(dev);
+ return 0;
+ }
+@@ -1391,7 +1391,7 @@ static void smc_tx( struct net_device *
+ .
+ ---------------------------------------------------------------------*/
+
+-static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++static irqreturn_t smc_interrupt(int irq, void * dev_id)
+ {
+ struct net_device *dev = dev_id;
+ int ioaddr = dev->base_addr;
+diff --git a/drivers/net/smc9194.h b/drivers/net/smc9194.h
+index 393ab90..cf69d0a 100644
+--- a/drivers/net/smc9194.h
++++ b/drivers/net/smc9194.h
+@@ -1,18 +1,18 @@
+ /*------------------------------------------------------------------------
+ . smc9194.h
+- . Copyright (C) 1996 by Erik Stahlman
++ . Copyright (C) 1996 by Erik Stahlman
+ .
+ . This software may be used and distributed according to the terms
+ . of the GNU General Public License, incorporated herein by reference.
+ .
+- . This file contains register information and access macros for
+- . the SMC91xxx chipset.
+- .
+- . Information contained in this file was obtained from the SMC91C94
+- . manual from SMC. To get a copy, if you really want one, you can find
++ . This file contains register information and access macros for
++ . the SMC91xxx chipset.
++ .
++ . Information contained in this file was obtained from the SMC91C94
++ . manual from SMC. To get a copy, if you really want one, you can find
+ . information under www.smc.com in the components division.
+ . ( this thanks to advice from Donald Becker ).
+- .
++ .
+ . Authors
+ . Erik Stahlman ( erik at vt.edu )
+ .
+@@ -38,22 +38,22 @@ typedef unsigned long int dword;
+
+
+ /*---------------------------------------------------------------
+- .
++ .
+ . A description of the SMC registers is probably in order here,
+- . although for details, the SMC datasheet is invaluable.
+- .
++ . although for details, the SMC datasheet is invaluable.
++ .
+ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
+ . are accessed by writing a number into the BANK_SELECT register
+ . ( I also use a SMC_SELECT_BANK macro for this ).
+- .
++ .
+ . The banks are configured so that for most purposes, bank 2 is all
+- . that is needed for simple run time tasks.
++ . that is needed for simple run time tasks.
+ -----------------------------------------------------------------------*/
+
+ /*
+- . Bank Select Register:
++ . Bank Select Register:
+ .
+- . yyyy yyyy 0000 00xx
++ . yyyy yyyy 0000 00xx
+ . xx = bank number
+ . yyyy yyyy = 0x33, for identification purposes.
+ */
+@@ -62,23 +62,23 @@ typedef unsigned long int dword;
+ /* BANK 0 */
+
+ #define TCR 0 /* transmit control register */
+-#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
++#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
+ #define TCR_FDUPLX 0x0800 /* receive packets sent out */
+ #define TCR_STP_SQET 0x1000 /* stop transmitting if Signal quality error */
+ #define TCR_MON_CNS 0x0400 /* monitors the carrier status */
+ #define TCR_PAD_ENABLE 0x0080 /* pads short packets to 64 bytes */
+
+ #define TCR_CLEAR 0 /* do NOTHING */
+-/* the normal settings for the TCR register : */
++/* the normal settings for the TCR register : */
+ /* QUESTION: do I want to enable padding of short packets ? */
+-#define TCR_NORMAL TCR_ENABLE
++#define TCR_NORMAL TCR_ENABLE
+
+
+ #define EPH_STATUS 2
+ #define ES_LINK_OK 0x4000 /* is the link integrity ok ? */
+
+ #define RCR 4
+-#define RCR_SOFTRESET 0x8000 /* resets the chip */
++#define RCR_SOFTRESET 0x8000 /* resets the chip */
+ #define RCR_STRIP_CRC 0x200 /* strips CRC */
+ #define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */
+ #define RCR_ALMUL 0x4 /* receive all multicast packets */
+@@ -114,12 +114,12 @@ typedef unsigned long int dword;
+ #define MC_BUSY 1 /* only readable bit in the register */
+ #define MC_NOP 0
+ #define MC_ALLOC 0x20 /* or with number of 256 byte packets */
+-#define MC_RESET 0x40
++#define MC_RESET 0x40
+ #define MC_REMOVE 0x60 /* remove the current rx packet */
+ #define MC_RELEASE 0x80 /* remove and release the current rx packet */
+ #define MC_FREEPKT 0xA0 /* Release packet in PNR register */
+ #define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */
+-
++
+ #define PNR_ARR 2
+ #define FIFO_PORTS 4
+
+@@ -139,11 +139,11 @@ typedef unsigned long int dword;
+ #define INT_MASK 13
+ #define IM_RCV_INT 0x1
+ #define IM_TX_INT 0x2
+-#define IM_TX_EMPTY_INT 0x4
++#define IM_TX_EMPTY_INT 0x4
+ #define IM_ALLOC_INT 0x8
+ #define IM_RX_OVRN_INT 0x10
+ #define IM_EPH_INT 0x20
+-#define IM_ERCV_INT 0x40 /* not on SMC9192 */
++#define IM_ERCV_INT 0x40 /* not on SMC9192 */
+
+ /* BANK 3 */
+ #define MULTICAST1 0
+@@ -162,19 +162,19 @@ typedef unsigned long int dword;
+ #define CHIP_9195 5
+ #define CHIP_91100 7
+
+-static const char * chip_ids[ 15 ] = {
+- NULL, NULL, NULL,
++static const char * chip_ids[ 15 ] = {
++ NULL, NULL, NULL,
+ /* 3 */ "SMC91C90/91C92",
+ /* 4 */ "SMC91C94",
+ /* 5 */ "SMC91C95",
+ NULL,
+- /* 7 */ "SMC91C100",
+- /* 8 */ "SMC91C100FD",
+- NULL, NULL, NULL,
+- NULL, NULL, NULL};
++ /* 7 */ "SMC91C100",
++ /* 8 */ "SMC91C100FD",
++ NULL, NULL, NULL,
++ NULL, NULL, NULL};
+
+-/*
+- . Transmit status bits
++/*
++ . Transmit status bits
+ */
+ #define TS_SUCCESS 0x0001
+ #define TS_LOSTCAR 0x0400
+@@ -190,18 +190,18 @@ static const char * chip_ids[ 15 ] = {
+ #define RS_TOOLONG 0x0800
+ #define RS_TOOSHORT 0x0400
+ #define RS_MULTICAST 0x0001
+-#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
++#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+ static const char * interfaces[ 2 ] = { "TP", "AUI" };
+
+ /*-------------------------------------------------------------------------
+ . I define some macros to make it easier to do somewhat common
+- . or slightly complicated, repeated tasks.
++ . or slightly complicated, repeated tasks.
+ --------------------------------------------------------------------------*/
+
+ /* select a register bank, 0 to 3 */
+
+-#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT ); }
++#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT ); }
+
+ /* define a small delay for the reset */
+ #define SMC_DELAY() { inw( ioaddr + RCR );\
+@@ -229,13 +229,13 @@ static const char * interfaces[ 2 ] = {
+
+ /*----------------------------------------------------------------------
+ . Define the interrupts that I want to receive from the card
+- .
+- . I want:
++ .
++ . I want:
+ . IM_EPH_INT, for nasty errors
+ . IM_RCV_INT, for happy received packets
+ . IM_RX_OVRN_INT, because I have to kick the receiver
+ --------------------------------------------------------------------------*/
+-#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT)
++#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT)
+
+ #endif /* _SMC_9194_H_ */
+
+diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
+index cf62373..95b6478 100644
+--- a/drivers/net/smc91x.c
++++ b/drivers/net/smc91x.c
+@@ -154,7 +154,7 @@ MODULE_LICENSE("GPL");
+
+ /*
+ * The maximum number of processing loops allowed for each call to the
+- * IRQ handler.
++ * IRQ handler.
+ */
+ #define MAX_IRQ_LOOPS 8
+
+@@ -765,7 +765,7 @@ static int smc_hard_start_xmit(struct sk
+ /*
+ * Allocation succeeded: push packet to the chip's own memory
+ * immediately.
+- */
++ */
+ smc_hardware_send_pkt((unsigned long)dev);
+ }
+
+@@ -1284,7 +1284,7 @@ static void smc_eph_interrupt(struct net
+ * This is the main routine of the driver, to handle the device when
+ * it needs some attention.
+ */
+-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t smc_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct smc_local *lp = netdev_priv(dev);
+@@ -1400,7 +1400,7 @@ static irqreturn_t smc_interrupt(int irq
+ static void smc_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- smc_interrupt(dev->irq, dev, NULL);
++ smc_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1739,7 +1739,7 @@ static void smc_ethtool_setmsglevel(stru
+ lp->msg_enable = level;
+ }
+
+-static struct ethtool_ops smc_ethtool_ops = {
++static const struct ethtool_ops smc_ethtool_ops = {
+ .get_settings = smc_ethtool_getsettings,
+ .set_settings = smc_ethtool_setsettings,
+ .get_drvinfo = smc_ethtool_getdrvinfo,
+@@ -2344,7 +2344,7 @@ static int __init smc_init(void)
+ #ifdef MODULE
+ #ifdef CONFIG_ISA
+ if (io == -1)
+- printk(KERN_WARNING
++ printk(KERN_WARNING
+ "%s: You shouldn't use auto-probing with insmod!\n",
+ CARDNAME);
+ #endif
+diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
+index 7aa7fba..a864016 100644
+--- a/drivers/net/smc91x.h
++++ b/drivers/net/smc91x.h
+@@ -195,6 +195,7 @@ SMC_outw(u16 val, void __iomem *ioaddr,
+ #define SMC_IRQ_FLAGS (( \
+ machine_is_omap_h2() \
+ || machine_is_omap_h3() \
++ || machine_is_omap_h4() \
+ || (machine_is_omap_innovator() && !cpu_is_omap1510()) \
+ ) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING)
+
+@@ -379,6 +380,60 @@ static inline void LPD7_SMC_outsw (unsig
+
+ #define SMC_IRQ_FLAGS (0)
+
++#elif defined(CONFIG_ARCH_VERSATILE)
++
++#define SMC_CAN_USE_8BIT 1
++#define SMC_CAN_USE_16BIT 1
++#define SMC_CAN_USE_32BIT 1
++#define SMC_NOWAIT 1
++
++#define SMC_inb(a, r) readb((a) + (r))
++#define SMC_inw(a, r) readw((a) + (r))
++#define SMC_inl(a, r) readl((a) + (r))
++#define SMC_outb(v, a, r) writeb(v, (a) + (r))
++#define SMC_outw(v, a, r) writew(v, (a) + (r))
++#define SMC_outl(v, a, r) writel(v, (a) + (r))
++#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
++#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
++
++#define SMC_IRQ_FLAGS (0)
++
++#elif defined(CONFIG_ARCH_VERSATILE)
++
++#define SMC_CAN_USE_8BIT 1
++#define SMC_CAN_USE_16BIT 1
++#define SMC_CAN_USE_32BIT 1
++#define SMC_NOWAIT 1
++
++#define SMC_inb(a, r) readb((a) + (r))
++#define SMC_inw(a, r) readw((a) + (r))
++#define SMC_inl(a, r) readl((a) + (r))
++#define SMC_outb(v, a, r) writeb(v, (a) + (r))
++#define SMC_outw(v, a, r) writew(v, (a) + (r))
++#define SMC_outl(v, a, r) writel(v, (a) + (r))
++#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
++#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
++
++#define SMC_IRQ_FLAGS (0)
++
++#elif defined(CONFIG_ARCH_VERSATILE)
++
++#define SMC_CAN_USE_8BIT 1
++#define SMC_CAN_USE_16BIT 1
++#define SMC_CAN_USE_32BIT 1
++#define SMC_NOWAIT 1
++
++#define SMC_inb(a, r) readb((a) + (r))
++#define SMC_inw(a, r) readw((a) + (r))
++#define SMC_inl(a, r) readl((a) + (r))
++#define SMC_outb(v, a, r) writeb(v, (a) + (r))
++#define SMC_outw(v, a, r) writew(v, (a) + (r))
++#define SMC_outl(v, a, r) writel(v, (a) + (r))
++#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
++#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
++
++#define SMC_IRQ_FLAGS (0)
++
+ #else
+
+ #define SMC_CAN_USE_8BIT 1
+@@ -488,7 +543,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u
+ #endif
+
+ static void
+-smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs)
++smc_pxa_dma_irq(int dma, void *dummy)
+ {
+ DCSR(dma) = 0;
+ }
+diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
+index cab0dd9..ed7aa0a 100644
+--- a/drivers/net/sonic.c
++++ b/drivers/net/sonic.c
+@@ -7,10 +7,10 @@
+ * (from the mac68k project) introduced dhd's support for 16-bit cards.
+ *
+ * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend at alpha.franken.de)
+- *
++ *
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+- *
++ *
+ * (C) 1995 by Andreas Busse (andy at waldorf-gmbh.de)
+ *
+ * Core code included by system sonic drivers
+@@ -46,7 +46,7 @@ static int sonic_open(struct net_device
+ {
+ struct sonic_local *lp = netdev_priv(dev);
+ int i;
+-
++
+ if (sonic_debug > 2)
+ printk("sonic_open: initializing sonic driver.\n");
+
+@@ -246,7 +246,7 @@ static int sonic_send_packet(struct sk_b
+ dev_kfree_skb(skb);
+ return 1;
+ }
+-
++
+ sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */
+ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */
+ sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
+@@ -293,17 +293,12 @@ static int sonic_send_packet(struct sk_b
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+-static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sonic_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
++ struct net_device *dev = dev_id;
+ struct sonic_local *lp = netdev_priv(dev);
+ int status;
+
+- if (dev == NULL) {
+- printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
+ if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
+ return IRQ_NONE;
+
+@@ -459,7 +454,7 @@ static void sonic_rx(struct net_device *
+ new_skb->dev = dev;
+ /* provide 16 byte IP header alignment unless DMA requires otherwise */
+ if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
+- skb_reserve(new_skb, 2);
++ skb_reserve(new_skb, 2);
+
+ new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
+ SONIC_RBSIZE, DMA_FROM_DEVICE);
+@@ -641,7 +636,7 @@ static int sonic_init(struct net_device
+ SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
+ lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
+ SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
+-
++
+ SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
+ SONIC_WRITE(SONIC_REA, lp->rra_end);
+ SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
+@@ -652,7 +647,7 @@ static int sonic_init(struct net_device
+ /* load the resource pointers */
+ if (sonic_debug > 3)
+ printk("sonic_init: issuing RRRA command\n");
+-
++
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
+ i = 0;
+ while (i++ < 100) {
+@@ -662,14 +657,14 @@ static int sonic_init(struct net_device
+
+ if (sonic_debug > 2)
+ printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i);
+-
++
+ /*
+ * Initialize the receive descriptors so that they
+ * become a circular linked list, ie. let the last
+ * descriptor point to the first again.
+ */
+ if (sonic_debug > 2)
+- printk("sonic_init: initialize receive descriptors\n");
++ printk("sonic_init: initialize receive descriptors\n");
+ for (i=0; i<SONIC_NUM_RDS; i++) {
+ sonic_rda_put(dev, i, SONIC_RD_STATUS, 0);
+ sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0);
+@@ -689,7 +684,7 @@ static int sonic_init(struct net_device
+ SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16);
+ SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff);
+
+- /*
++ /*
+ * initialize transmit descriptors
+ */
+ if (sonic_debug > 2)
+@@ -712,7 +707,7 @@ static int sonic_init(struct net_device
+ SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff);
+ lp->cur_tx = lp->next_tx = 0;
+ lp->eol_tx = SONIC_NUM_TDS - 1;
+-
++
+ /*
+ * put our own address to CAM desc[0]
+ */
+diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h
+index 7f5c4eb..7db13e4 100644
+--- a/drivers/net/sonic.h
++++ b/drivers/net/sonic.h
+@@ -7,7 +7,7 @@
+ * NOTE: most of the structure definitions here are endian dependent.
+ * If you want to use this driver on big endian machines, the data
+ * and pad structure members must be exchanged. Also, the structures
+- * need to be changed accordingly to the bus size.
++ * need to be changed accordingly to the bus size.
+ *
+ * 981229 MSch: did just that for the 68k Mac port (32 bit, big endian)
+ *
+@@ -181,7 +181,7 @@
+
+ #define SONIC_TCR_DEFAULT 0x0000
+
+-/*
++/*
+ * Constants for the SONIC_INTERRUPT_MASK and
+ * SONIC_INTERRUPT_STATUS registers.
+ */
+@@ -328,7 +328,7 @@ struct sonic_local {
+
+ static int sonic_open(struct net_device *dev);
+ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t sonic_interrupt(int irq, void *dev_id);
+ static void sonic_rx(struct net_device *dev);
+ static int sonic_close(struct net_device *dev);
+ static struct net_device_stats *sonic_get_stats(struct net_device *dev);
+diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
+index 8890721..418138d 100644
+--- a/drivers/net/spider_net.c
++++ b/drivers/net/spider_net.c
+@@ -55,12 +55,13 @@ MODULE_AUTHOR("Utz Bacher <utz.bacher at de
+ "<Jens.Osterkamp at de.ibm.com>");
+ MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
+ MODULE_LICENSE("GPL");
++MODULE_VERSION(VERSION);
+
+ static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
+ static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
+
+-module_param(rx_descriptors, int, 0644);
+-module_param(tx_descriptors, int, 0644);
++module_param(rx_descriptors, int, 0444);
++module_param(tx_descriptors, int, 0444);
+
+ MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
+ "in rx chains");
+@@ -300,7 +301,7 @@ static int
+ spider_net_init_chain(struct spider_net_card *card,
+ struct spider_net_descr_chain *chain,
+ struct spider_net_descr *start_descr,
+- int direction, int no)
++ int no)
+ {
+ int i;
+ struct spider_net_descr *descr;
+@@ -315,9 +316,9 @@ spider_net_init_chain(struct spider_net_
+
+ buf = pci_map_single(card->pdev, descr,
+ SPIDER_NET_DESCR_SIZE,
+- direction);
++ PCI_DMA_BIDIRECTIONAL);
+
+- if (buf == DMA_ERROR_CODE)
++ if (pci_dma_mapping_error(buf))
+ goto iommu_error;
+
+ descr->bus_addr = buf;
+@@ -329,11 +330,6 @@ spider_net_init_chain(struct spider_net_
+ (descr-1)->next = start_descr;
+ start_descr->prev = descr-1;
+
+- descr = start_descr;
+- if (direction == PCI_DMA_FROMDEVICE)
+- for (i=0; i < no; i++, descr++)
+- descr->next_descr_addr = descr->next->bus_addr;
+-
+ spin_lock_init(&chain->lock);
+ chain->head = start_descr;
+ chain->tail = start_descr;
+@@ -346,7 +342,7 @@ iommu_error:
+ if (descr->bus_addr)
+ pci_unmap_single(card->pdev, descr->bus_addr,
+ SPIDER_NET_DESCR_SIZE,
+- direction);
++ PCI_DMA_BIDIRECTIONAL);
+ return -ENOMEM;
+ }
+
+@@ -362,15 +358,15 @@ spider_net_free_rx_chain_contents(struct
+ struct spider_net_descr *descr;
+
+ descr = card->rx_chain.head;
+- while (descr->next != card->rx_chain.head) {
++ do {
+ if (descr->skb) {
+ dev_kfree_skb(descr->skb);
+ pci_unmap_single(card->pdev, descr->buf_addr,
+ SPIDER_NET_MAX_FRAME,
+- PCI_DMA_FROMDEVICE);
++ PCI_DMA_BIDIRECTIONAL);
+ }
+ descr = descr->next;
+- }
++ } while (descr != card->rx_chain.head);
+ }
+
+ /**
+@@ -403,6 +399,7 @@ spider_net_prepare_rx_descr(struct spide
+ if (!descr->skb) {
+ if (netif_msg_rx_err(card) && net_ratelimit())
+ pr_err("Not enough memory to allocate rx buffer\n");
++ card->spider_stats.alloc_rx_skb_error++;
+ return -ENOMEM;
+ }
+ descr->buf_size = bufsize;
+@@ -419,10 +416,11 @@ spider_net_prepare_rx_descr(struct spide
+ buf = pci_map_single(card->pdev, descr->skb->data,
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+ descr->buf_addr = buf;
+- if (buf == DMA_ERROR_CODE) {
++ if (pci_dma_mapping_error(buf)) {
+ dev_kfree_skb_any(descr->skb);
+ if (netif_msg_rx_err(card) && net_ratelimit())
+ pr_err("Could not iommu-map rx buffer\n");
++ card->spider_stats.rx_iommu_map_error++;
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ } else {
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+@@ -643,25 +641,41 @@ static int
+ spider_net_prepare_tx_descr(struct spider_net_card *card,
+ struct sk_buff *skb)
+ {
+- struct spider_net_descr *descr = card->tx_chain.head;
++ struct spider_net_descr *descr;
+ dma_addr_t buf;
++ unsigned long flags;
++ int length;
+
+- buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+- if (buf == DMA_ERROR_CODE) {
++ length = skb->len;
++ if (length < ETH_ZLEN) {
++ if (skb_pad(skb, ETH_ZLEN-length))
++ return 0;
++ length = ETH_ZLEN;
++ }
++
++ buf = pci_map_single(card->pdev, skb->data, length, PCI_DMA_TODEVICE);
++ if (pci_dma_mapping_error(buf)) {
+ if (netif_msg_tx_err(card) && net_ratelimit())
+ pr_err("could not iommu-map packet (%p, %i). "
+- "Dropping packet\n", skb->data, skb->len);
++ "Dropping packet\n", skb->data, length);
++ card->spider_stats.tx_iommu_map_error++;
+ return -ENOMEM;
+ }
+
++ spin_lock_irqsave(&card->tx_chain.lock, flags);
++ descr = card->tx_chain.head;
++ card->tx_chain.head = descr->next;
++
+ descr->buf_addr = buf;
+- descr->buf_size = skb->len;
++ descr->buf_size = length;
+ descr->next_descr_addr = 0;
+ descr->skb = skb;
+ descr->data_status = 0;
+
+ descr->dmac_cmd_status =
+ SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
++ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
++
+ if (skb->protocol == htons(ETH_P_IP))
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+@@ -672,32 +686,51 @@ spider_net_prepare_tx_descr(struct spide
+ break;
+ }
+
++ /* Chain the bus address, so that the DMA engine finds this descr. */
+ descr->prev->next_descr_addr = descr->bus_addr;
+
++ card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
+ return 0;
+ }
+
+-/**
+- * spider_net_release_tx_descr - processes a used tx descriptor
+- * @card: card structure
+- * @descr: descriptor to release
+- *
+- * releases a used tx descriptor (unmapping, freeing of skb)
+- */
+-static inline void
+-spider_net_release_tx_descr(struct spider_net_card *card)
++static int
++spider_net_set_low_watermark(struct spider_net_card *card)
+ {
++ unsigned long flags;
++ int status;
++ int cnt=0;
++ int i;
+ struct spider_net_descr *descr = card->tx_chain.tail;
+- struct sk_buff *skb;
+
+- card->tx_chain.tail = card->tx_chain.tail->next;
+- descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
++ /* Measure the length of the queue. Measurement does not
++ * need to be precise -- does not need a lock. */
++ while (descr != card->tx_chain.head) {
++ status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
++ if (status == SPIDER_NET_DESCR_NOT_IN_USE)
++ break;
++ descr = descr->next;
++ cnt++;
++ }
++
++ /* If TX queue is short, don't even bother with interrupts */
++ if (cnt < card->num_tx_desc/4)
++ return cnt;
+
+- /* unmap the skb */
+- skb = descr->skb;
+- pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
+- PCI_DMA_TODEVICE);
+- dev_kfree_skb_any(skb);
++ /* Set low-watermark 3/4th's of the way into the queue. */
++ descr = card->tx_chain.tail;
++ cnt = (cnt*3)/4;
++ for (i=0;i<cnt; i++)
++ descr = descr->next;
++
++ /* Set the new watermark, clear the old watermark */
++ spin_lock_irqsave(&card->tx_chain.lock, flags);
++ descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
++ if (card->low_watermark && card->low_watermark != descr)
++ card->low_watermark->dmac_cmd_status =
++ card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
++ card->low_watermark = descr;
++ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
++ return cnt;
+ }
+
+ /**
+@@ -716,21 +749,29 @@ static int
+ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+ {
+ struct spider_net_descr_chain *chain = &card->tx_chain;
++ struct spider_net_descr *descr;
++ struct sk_buff *skb;
++ u32 buf_addr;
++ unsigned long flags;
+ int status;
+
+- spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR);
+-
+ while (chain->tail != chain->head) {
+- status = spider_net_get_descr_status(chain->tail);
++ spin_lock_irqsave(&chain->lock, flags);
++ descr = chain->tail;
++
++ status = spider_net_get_descr_status(descr);
+ switch (status) {
+ case SPIDER_NET_DESCR_COMPLETE:
+ card->netdev_stats.tx_packets++;
+- card->netdev_stats.tx_bytes += chain->tail->skb->len;
++ card->netdev_stats.tx_bytes += descr->skb->len;
+ break;
+
+ case SPIDER_NET_DESCR_CARDOWNED:
+- if (!brutal)
++ if (!brutal) {
++ spin_unlock_irqrestore(&chain->lock, flags);
+ return 1;
++ }
++
+ /* fallthrough, if we release the descriptors
+ * brutally (then we don't care about
+ * SPIDER_NET_DESCR_CARDOWNED) */
+@@ -747,11 +788,25 @@ spider_net_release_tx_chain(struct spide
+
+ default:
+ card->netdev_stats.tx_dropped++;
+- return 1;
++ if (!brutal) {
++ spin_unlock_irqrestore(&chain->lock, flags);
++ return 1;
++ }
+ }
+- spider_net_release_tx_descr(card);
+- }
+
++ chain->tail = descr->next;
++ descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
++ skb = descr->skb;
++ buf_addr = descr->buf_addr;
++ spin_unlock_irqrestore(&chain->lock, flags);
++
++ /* unmap the skb */
++ if (skb) {
++ int len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
++ pci_unmap_single(card->pdev, buf_addr, len, PCI_DMA_TODEVICE);
++ dev_kfree_skb(skb);
++ }
++ }
+ return 0;
+ }
+
+@@ -760,8 +815,12 @@ spider_net_release_tx_chain(struct spide
+ * @card: card structure
+ * @descr: descriptor address to enable TX processing at
+ *
+- * spider_net_kick_tx_dma writes the current tx chain head as start address
+- * of the tx descriptor chain and enables the transmission DMA engine
++ * This routine will start the transmit DMA running if
++ * it is not already running. This routine ned only be
++ * called when queueing a new packet to an empty tx queue.
++ * Writes the current tx chain head as start address
++ * of the tx descriptor chain and enables the transmission
++ * DMA engine.
+ */
+ static inline void
+ spider_net_kick_tx_dma(struct spider_net_card *card)
+@@ -801,64 +860,43 @@ out:
+ static int
+ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+ {
++ int cnt;
+ struct spider_net_card *card = netdev_priv(netdev);
+ struct spider_net_descr_chain *chain = &card->tx_chain;
+- struct spider_net_descr *descr = chain->head;
+- unsigned long flags;
+- int result;
+-
+- spin_lock_irqsave(&chain->lock, flags);
+
+ spider_net_release_tx_chain(card, 0);
+
+- if (chain->head->next == chain->tail->prev) {
+- card->netdev_stats.tx_dropped++;
+- result = NETDEV_TX_LOCKED;
+- goto out;
+- }
++ if ((chain->head->next == chain->tail->prev) ||
++ (spider_net_prepare_tx_descr(card, skb) != 0)) {
+
+- if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) {
+- result = NETDEV_TX_LOCKED;
+- goto out;
+- }
+-
+- if (spider_net_prepare_tx_descr(card, skb) != 0) {
+ card->netdev_stats.tx_dropped++;
+- result = NETDEV_TX_BUSY;
+- goto out;
++ netif_stop_queue(netdev);
++ return NETDEV_TX_BUSY;
+ }
+
+- result = NETDEV_TX_OK;
+-
+- spider_net_kick_tx_dma(card);
+- card->tx_chain.head = card->tx_chain.head->next;
+-
+-out:
+- spin_unlock_irqrestore(&chain->lock, flags);
+- netif_wake_queue(netdev);
+- return result;
++ cnt = spider_net_set_low_watermark(card);
++ if (cnt < 5)
++ spider_net_kick_tx_dma(card);
++ return NETDEV_TX_OK;
+ }
+
+ /**
+ * spider_net_cleanup_tx_ring - cleans up the TX ring
+ * @card: card structure
+ *
+- * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
+- * interrupts to cleanup our TX ring) and returns sent packets to the stack
+- * by freeing them
++ * spider_net_cleanup_tx_ring is called by either the tx_timer
++ * or from the NAPI polling routine.
++ * This routine releases resources associted with transmitted
++ * packets, including updating the queue tail pointer.
+ */
+ static void
+ spider_net_cleanup_tx_ring(struct spider_net_card *card)
+ {
+- unsigned long flags;
+-
+- spin_lock_irqsave(&card->tx_chain.lock, flags);
+-
+ if ((spider_net_release_tx_chain(card, 0) != 0) &&
+- (card->netdev->flags & IFF_UP))
++ (card->netdev->flags & IFF_UP)) {
+ spider_net_kick_tx_dma(card);
+-
+- spin_unlock_irqrestore(&card->tx_chain.lock, flags);
++ netif_wake_queue(card->netdev);
++ }
+ }
+
+ /**
+@@ -913,6 +951,7 @@ spider_net_pass_skb_up(struct spider_net
+ pr_err("error in received descriptor found, "
+ "data_status=x%08x, data_error=x%08x\n",
+ data_status, data_error);
++ card->spider_stats.rx_desc_error++;
+ return 0;
+ }
+
+@@ -1010,9 +1049,11 @@ spider_net_decode_one_descr(struct spide
+
+ if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
+ (status != SPIDER_NET_DESCR_FRAME_END) ) {
+- if (netif_msg_rx_err(card))
++ if (netif_msg_rx_err(card)) {
+ pr_err("%s: RX descriptor with state %d\n",
+ card->netdev->name, status);
++ card->spider_stats.rx_desc_unk_state++;
++ }
+ goto refill;
+ }
+
+@@ -1046,6 +1087,7 @@ spider_net_poll(struct net_device *netde
+ int packets_to_do, packets_done = 0;
+ int no_more_packets = 0;
+
++ spider_net_cleanup_tx_ring(card);
+ packets_to_do = min(*budget, netdev->quota);
+
+ while (packets_to_do) {
+@@ -1236,12 +1278,15 @@ spider_net_handle_error_irq(struct spide
+ case SPIDER_NET_PHYINT:
+ case SPIDER_NET_GMAC2INT:
+ case SPIDER_NET_GMAC1INT:
+- case SPIDER_NET_GIPSINT:
+ case SPIDER_NET_GFIFOINT:
+ case SPIDER_NET_DMACINT:
+ case SPIDER_NET_GSYSINT:
+ break; */
+
++ case SPIDER_NET_GIPSINT:
++ show_error = 0;
++ break;
++
+ case SPIDER_NET_GPWOPCMPINT:
+ /* PHY write operation completed */
+ show_error = 0;
+@@ -1300,9 +1345,10 @@ spider_net_handle_error_irq(struct spide
+ case SPIDER_NET_GDTDCEINT:
+ /* chain end. If a descriptor should be sent, kick off
+ * tx dma
+- if (card->tx_chain.tail == card->tx_chain.head)
++ if (card->tx_chain.tail != card->tx_chain.head)
+ spider_net_kick_tx_dma(card);
+- show_error = 0; */
++ */
++ show_error = 0;
+ break;
+
+ /* case SPIDER_NET_G1TMCNTINT: not used. print a message */
+@@ -1347,7 +1393,7 @@ spider_net_handle_error_irq(struct spide
+ if (netif_msg_intr(card))
+ pr_err("got descriptor chain end interrupt, "
+ "restarting DMAC %c.\n",
+- 'D'+i-SPIDER_NET_GDDDCEINT);
++ 'D'-(i-SPIDER_NET_GDDDCEINT)/3);
+ spider_net_refill_rx_chain(card);
+ spider_net_enable_rxdmac(card);
+ show_error = 0;
+@@ -1416,8 +1462,9 @@ spider_net_handle_error_irq(struct spide
+ }
+
+ if ((show_error) && (netif_msg_intr(card)))
+- pr_err("Got error interrupt, GHIINT0STS = 0x%08x, "
++ pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
+ "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
++ card->netdev->name,
+ status_reg, error_reg1, error_reg2);
+
+ /* clear interrupt sources */
+@@ -1438,7 +1485,7 @@ spider_net_handle_error_irq(struct spide
+ * interrupts for this device and makes the stack poll the driver
+ */
+ static irqreturn_t
+-spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs)
++spider_net_interrupt(int irq, void *ptr)
+ {
+ struct net_device *netdev = ptr;
+ struct spider_net_card *card = netdev_priv(netdev);
+@@ -1453,6 +1500,8 @@ spider_net_interrupt(int irq, void *ptr,
+ spider_net_rx_irq_off(card);
+ netif_rx_schedule(netdev);
+ }
++ if (status_reg & SPIDER_NET_TXINT)
++ netif_rx_schedule(netdev);
+
+ if (status_reg & SPIDER_NET_ERRINT )
+ spider_net_handle_error_irq(card, status_reg);
+@@ -1474,7 +1523,7 @@ static void
+ spider_net_poll_controller(struct net_device *netdev)
+ {
+ disable_irq(netdev->irq);
+- spider_net_interrupt(netdev->irq, netdev, NULL);
++ spider_net_interrupt(netdev->irq, netdev);
+ enable_irq(netdev->irq);
+ }
+ #endif /* CONFIG_NET_POLL_CONTROLLER */
+@@ -1592,7 +1641,7 @@ spider_net_enable_card(struct spider_net
+ SPIDER_NET_INT2_MASK_VALUE);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+- SPIDER_NET_GDTDCEIDIS);
++ SPIDER_NET_GDTBSTA | SPIDER_NET_GDTDCEIDIS);
+ }
+
+ /**
+@@ -1608,17 +1657,26 @@ int
+ spider_net_open(struct net_device *netdev)
+ {
+ struct spider_net_card *card = netdev_priv(netdev);
+- int result;
++ struct spider_net_descr *descr;
++ int i, result;
+
+ result = -ENOMEM;
+ if (spider_net_init_chain(card, &card->tx_chain, card->descr,
+- PCI_DMA_TODEVICE, card->tx_desc))
++ card->num_tx_desc))
+ goto alloc_tx_failed;
++
++ card->low_watermark = NULL;
++
++ /* rx_chain is after tx_chain, so offset is descr + tx_count */
+ if (spider_net_init_chain(card, &card->rx_chain,
+- card->descr + card->rx_desc,
+- PCI_DMA_FROMDEVICE, card->rx_desc))
++ card->descr + card->num_tx_desc,
++ card->num_rx_desc))
+ goto alloc_rx_failed;
+
++ descr = card->rx_chain.head;
++ for (i=0; i < card->num_rx_desc; i++, descr++)
++ descr->next_descr_addr = descr->next->bus_addr;
++
+ /* allocate rx skbs */
+ if (spider_net_alloc_rx_skbs(card))
+ goto alloc_skbs_failed;
+@@ -1697,10 +1755,10 @@ spider_net_setup_phy(struct spider_net_c
+ */
+ static int
+ spider_net_download_firmware(struct spider_net_card *card,
+- u8 *firmware_ptr)
++ const void *firmware_ptr)
+ {
+ int sequencer, i;
+- u32 *fw_ptr = (u32 *)firmware_ptr;
++ const u32 *fw_ptr = firmware_ptr;
+
+ /* stop sequencers */
+ spider_net_write_reg(card, SPIDER_NET_GSINIT,
+@@ -1757,7 +1815,7 @@ spider_net_init_firmware(struct spider_n
+ {
+ struct firmware *firmware = NULL;
+ struct device_node *dn;
+- u8 *fw_prop = NULL;
++ const u8 *fw_prop = NULL;
+ int err = -ENOENT;
+ int fw_size;
+
+@@ -1783,7 +1841,7 @@ try_host_fw:
+ if (!dn)
+ goto out_err;
+
+- fw_prop = (u8 *)get_property(dn, "firmware", &fw_size);
++ fw_prop = get_property(dn, "firmware", &fw_size);
+ if (!fw_prop)
+ goto out_err;
+
+@@ -1871,10 +1929,7 @@ spider_net_stop(struct net_device *netde
+ spider_net_disable_rxdmac(card);
+
+ /* release chains */
+- if (spin_trylock(&card->tx_chain.lock)) {
+- spider_net_release_tx_chain(card, 1);
+- spin_unlock(&card->tx_chain.lock);
+- }
++ spider_net_release_tx_chain(card, 1);
+
+ spider_net_free_chain(card, &card->tx_chain);
+ spider_net_free_chain(card, &card->rx_chain);
+@@ -1934,6 +1989,7 @@ spider_net_tx_timeout(struct net_device
+ schedule_work(&card->tx_timeout_task);
+ else
+ atomic_dec(&card->tx_timeout_task_counter);
++ card->spider_stats.tx_timeouts++;
+ }
+
+ /**
+@@ -1986,7 +2042,7 @@ spider_net_setup_netdev(struct spider_ne
+ struct net_device *netdev = card->netdev;
+ struct device_node *dn;
+ struct sockaddr addr;
+- u8 *mac;
++ const u8 *mac;
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &card->pdev->dev);
+@@ -2004,8 +2060,8 @@ spider_net_setup_netdev(struct spider_ne
+
+ card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+
+- card->tx_desc = tx_descriptors;
+- card->rx_desc = rx_descriptors;
++ card->num_tx_desc = tx_descriptors;
++ card->num_rx_desc = rx_descriptors;
+
+ spider_net_setup_netdev_ops(netdev);
+
+@@ -2019,7 +2075,7 @@ spider_net_setup_netdev(struct spider_ne
+ if (!dn)
+ return -EIO;
+
+- mac = (u8 *)get_property(dn, "local-mac-address", NULL);
++ mac = get_property(dn, "local-mac-address", NULL);
+ if (!mac)
+ return -EIO;
+ memcpy(addr.sa_data, mac, ETH_ALEN);
+@@ -2244,6 +2300,8 @@ static struct pci_driver spider_net_driv
+ */
+ static int __init spider_net_init(void)
+ {
++ printk(KERN_INFO "Spidernet version %s.\n", VERSION);
++
+ if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
+ rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
+ pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
+index 30407cd..b3b4611 100644
+--- a/drivers/net/spider_net.h
++++ b/drivers/net/spider_net.h
+@@ -24,12 +24,14 @@
+ #ifndef _SPIDER_NET_H
+ #define _SPIDER_NET_H
+
++#define VERSION "1.1 A"
++
+ #include "sungem_phy.h"
+
+ extern int spider_net_stop(struct net_device *netdev);
+ extern int spider_net_open(struct net_device *netdev);
+
+-extern struct ethtool_ops spider_net_ethtool_ops;
++extern const struct ethtool_ops spider_net_ethtool_ops;
+
+ extern char spider_net_driver_name[];
+
+@@ -47,7 +49,7 @@ extern char spider_net_driver_name[];
+ #define SPIDER_NET_TX_DESCRIPTORS_MIN 16
+ #define SPIDER_NET_TX_DESCRIPTORS_MAX 512
+
+-#define SPIDER_NET_TX_TIMER 20
++#define SPIDER_NET_TX_TIMER (HZ/5)
+
+ #define SPIDER_NET_RX_CSUM_DEFAULT 1
+
+@@ -189,7 +191,9 @@ extern char spider_net_driver_name[];
+ #define SPIDER_NET_MACMODE_VALUE 0x00000001
+ #define SPIDER_NET_BURSTLMT_VALUE 0x00000200 /* about 16 us */
+
+-/* 1(0) enable r/tx dma
++/* DMAC control register GDMACCNTR
++ *
++ * 1(0) enable r/tx dma
+ * 0000000 fixed to 0
+ *
+ * 000000 fixed to 0
+@@ -198,6 +202,7 @@ extern char spider_net_driver_name[];
+ *
+ * 000000 fixed to 0
+ * 00 burst alignment: 128 bytes
++ * 11 burst alignment: 1024 bytes
+ *
+ * 00000 fixed to 0
+ * 0 descr writeback size 32 bytes
+@@ -208,10 +213,13 @@ extern char spider_net_driver_name[];
+ #define SPIDER_NET_DMA_RX_VALUE 0x80000000
+ #define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003
+ /* to set TX_DMA_EN */
+-#define SPIDER_NET_TX_DMA_EN 0x80000000
+-#define SPIDER_NET_GDTDCEIDIS 0x00000002
+-#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \
+- SPIDER_NET_GDTDCEIDIS
++#define SPIDER_NET_TX_DMA_EN 0x80000000
++#define SPIDER_NET_GDTBSTA 0x00000300
++#define SPIDER_NET_GDTDCEIDIS 0x00000002
++#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \
++ SPIDER_NET_GDTBSTA | \
++ SPIDER_NET_GDTDCEIDIS
++
+ #define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003
+
+ /* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
+@@ -320,13 +328,10 @@ enum spider_net_int2_status {
+ SPIDER_NET_GRISPDNGINT
+ };
+
+-#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \
+- (1 << SPIDER_NET_GDTDCEINT) | \
+- (1 << SPIDER_NET_GDTFDCINT) )
++#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GDTFDCINT) )
+
+-/* we rely on flagged descriptor interrupts*/
+-#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \
+- (1 << SPIDER_NET_GRMFLLINT) )
++/* We rely on flagged descriptor interrupts */
++#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) )
+
+ #define SPIDER_NET_ERRINT ( 0xffffffff & \
+ (~SPIDER_NET_TXINT) & \
+@@ -349,6 +354,7 @@ enum spider_net_int2_status {
+ #define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */
+ #define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */
+ #define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
++#define SPIDER_NET_DESCR_TXDESFLG 0x00800000
+
+ struct spider_net_descr {
+ /* as defined by the hardware */
+@@ -415,6 +421,15 @@ struct spider_net_options {
+ NETIF_MSG_HW | \
+ NETIF_MSG_WOL )
+
++struct spider_net_extra_stats {
++ unsigned long rx_desc_error;
++ unsigned long tx_timeouts;
++ unsigned long alloc_rx_skb_error;
++ unsigned long rx_iommu_map_error;
++ unsigned long tx_iommu_map_error;
++ unsigned long rx_desc_unk_state;
++};
++
+ struct spider_net_card {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+@@ -424,6 +439,7 @@ struct spider_net_card {
+
+ struct spider_net_descr_chain tx_chain;
+ struct spider_net_descr_chain rx_chain;
++ struct spider_net_descr *low_watermark;
+
+ struct net_device_stats netdev_stats;
+
+@@ -439,9 +455,9 @@ struct spider_net_card {
+
+ /* for ethtool */
+ int msg_enable;
+-
+- int rx_desc;
+- int tx_desc;
++ int num_rx_desc;
++ int num_tx_desc;
++ struct spider_net_extra_stats spider_stats;
+
+ struct spider_net_descr descr[0];
+ };
+diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
+index 0220922..91b9951 100644
+--- a/drivers/net/spider_net_ethtool.c
++++ b/drivers/net/spider_net_ethtool.c
+@@ -27,6 +27,27 @@
+
+ #include "spider_net.h"
+
++
++#define SPIDER_NET_NUM_STATS 13
++
++static struct {
++ const char str[ETH_GSTRING_LEN];
++} ethtool_stats_keys[] = {
++ { "tx_packets" },
++ { "tx_bytes" },
++ { "rx_packets" },
++ { "rx_bytes" },
++ { "tx_errors" },
++ { "tx_dropped" },
++ { "rx_dropped" },
++ { "rx_descriptor_error" },
++ { "tx_timeouts" },
++ { "alloc_rx_skb_error" },
++ { "rx_iommu_map_error" },
++ { "tx_iommu_map_error" },
++ { "rx_desc_unk_state" },
++};
++
+ static int
+ spider_net_ethtool_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+@@ -55,7 +76,7 @@ spider_net_ethtool_get_drvinfo(struct ne
+ /* clear and fill out info */
+ memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
+ strncpy(drvinfo->driver, spider_net_driver_name, 32);
+- strncpy(drvinfo->version, "0.1", 32);
++ strncpy(drvinfo->version, VERSION, 32);
+ strcpy(drvinfo->fw_version, "no information");
+ strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+ }
+@@ -137,12 +158,43 @@ spider_net_ethtool_get_ringparam(struct
+ struct spider_net_card *card = netdev->priv;
+
+ ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
+- ering->tx_pending = card->tx_desc;
++ ering->tx_pending = card->num_tx_desc;
+ ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
+- ering->rx_pending = card->rx_desc;
++ ering->rx_pending = card->num_rx_desc;
++}
++
++static int spider_net_get_stats_count(struct net_device *netdev)
++{
++ return SPIDER_NET_NUM_STATS;
++}
++
++static void spider_net_get_ethtool_stats(struct net_device *netdev,
++ struct ethtool_stats *stats, u64 *data)
++{
++ struct spider_net_card *card = netdev->priv;
++
++ data[0] = card->netdev_stats.tx_packets;
++ data[1] = card->netdev_stats.tx_bytes;
++ data[2] = card->netdev_stats.rx_packets;
++ data[3] = card->netdev_stats.rx_bytes;
++ data[4] = card->netdev_stats.tx_errors;
++ data[5] = card->netdev_stats.tx_dropped;
++ data[6] = card->netdev_stats.rx_dropped;
++ data[7] = card->spider_stats.rx_desc_error;
++ data[8] = card->spider_stats.tx_timeouts;
++ data[9] = card->spider_stats.alloc_rx_skb_error;
++ data[10] = card->spider_stats.rx_iommu_map_error;
++ data[11] = card->spider_stats.tx_iommu_map_error;
++ data[12] = card->spider_stats.rx_desc_unk_state;
++}
++
++static void spider_net_get_strings(struct net_device *netdev, u32 stringset,
++ u8 *data)
++{
++ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+ }
+
+-struct ethtool_ops spider_net_ethtool_ops = {
++const struct ethtool_ops spider_net_ethtool_ops = {
+ .get_settings = spider_net_ethtool_get_settings,
+ .get_drvinfo = spider_net_ethtool_get_drvinfo,
+ .get_wol = spider_net_ethtool_get_wol,
+@@ -154,5 +206,8 @@ struct ethtool_ops spider_net_ethtool_op
+ .get_tx_csum = spider_net_ethtool_get_tx_csum,
+ .set_tx_csum = spider_net_ethtool_set_tx_csum,
+ .get_ringparam = spider_net_ethtool_get_ringparam,
++ .get_strings = spider_net_get_strings,
++ .get_stats_count = spider_net_get_stats_count,
++ .get_ethtool_stats = spider_net_get_ethtool_stats,
+ };
+
+diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
+index c0a62b0..7a0aee6 100644
+--- a/drivers/net/starfire.c
++++ b/drivers/net/starfire.c
+@@ -632,7 +632,7 @@ static void check_duplex(struct net_devi
+ static void tx_timeout(struct net_device *dev);
+ static void init_ring(struct net_device *dev);
+ static int start_tx(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t intr_handler(int irq, void *dev_instance);
+ static void netdev_error(struct net_device *dev, int intr_status);
+ static int __netdev_rx(struct net_device *dev, int *quota);
+ static void refill_rx_ring(struct net_device *dev);
+@@ -642,7 +642,7 @@ static struct net_device_stats *get_stat
+ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static int netdev_close(struct net_device *dev);
+ static void netdev_media_change(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+
+
+ #ifdef VLAN_SUPPORT
+@@ -1230,7 +1230,7 @@ static int start_tx(struct sk_buff *skb,
+ }
+
+ #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK))
+ return NETDEV_TX_OK;
+ }
+@@ -1252,7 +1252,7 @@ static int start_tx(struct sk_buff *skb,
+ status |= TxDescIntr;
+ np->reap_tx = 0;
+ }
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ status |= TxCalTCP;
+ np->stats.tx_compressed++;
+ }
+@@ -1307,7 +1307,7 @@ static int start_tx(struct sk_buff *skb,
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t intr_handler(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct netdev_private *np = netdev_priv(dev);
+@@ -1499,7 +1499,7 @@ static int __netdev_rx(struct net_device
+ * Until then, the printk stays. :-) -Ion
+ */
+ else if (le16_to_cpu(desc->status2) & 0x0040) {
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = le16_to_cpu(desc->csum);
+ printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2));
+ }
+@@ -1868,7 +1868,7 @@ static void set_msglevel(struct net_devi
+ debug = val;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .begin = check_if_running,
+ .get_drvinfo = get_drvinfo,
+ .get_settings = get_settings,
+@@ -1984,7 +1984,7 @@ static int starfire_suspend(struct pci_d
+ static int starfire_resume(struct pci_dev *pdev)
+ {
+ struct net_device *dev = pci_get_drvdata(pdev);
+-
++
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+@@ -2053,7 +2053,7 @@ static int __init starfire_init (void)
+ return -ENODEV;
+ }
+
+- return pci_module_init (&starfire_driver);
++ return pci_register_driver(&starfire_driver);
+ }
+
+
+diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
+index 7422834..e6f9042 100644
+--- a/drivers/net/stnic.c
++++ b/drivers/net/stnic.c
+@@ -19,9 +19,9 @@
+
+ #include <asm/system.h>
+ #include <asm/io.h>
+-#include <asm/se/se.h>
++#include <asm/se.h>
+ #include <asm/machvec.h>
+-#ifdef CONFIG_SH_STANDARD_BIOS
++#ifdef CONFIG_SH_STANDARD_BIOS
+ #include <asm/sh_bios.h>
+ #endif
+
+@@ -98,7 +98,7 @@ STNIC_WRITE (int reg, byte val)
+ *(vhalf *) (PA_83902 + ((reg) << 1)) = ((half) (val) << 8);
+ STNIC_DELAY ();
+ }
+-
++
+ static int __init stnic_probe(void)
+ {
+ struct net_device *dev;
+@@ -114,7 +114,7 @@ static int __init stnic_probe(void)
+ return -ENOMEM;
+ SET_MODULE_OWNER(dev);
+
+-#ifdef CONFIG_SH_STANDARD_BIOS
++#ifdef CONFIG_SH_STANDARD_BIOS
+ sh_bios_get_node_addr (stnic_eadr);
+ #endif
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+@@ -140,7 +140,7 @@ static int __init stnic_probe(void)
+
+ ei_status.name = dev->name;
+ ei_status.word16 = 1;
+-#ifdef __LITTLE_ENDIAN__
++#ifdef __LITTLE_ENDIAN__
+ ei_status.bigendian = 0;
+ #else
+ ei_status.bigendian = 1;
+diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
+index d5a58fb..a3220a9 100644
+--- a/drivers/net/sun3_82586.c
++++ b/drivers/net/sun3_82586.c
+@@ -14,10 +14,10 @@
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm at informatik.uni-tuebingen.de)
+ * --------------------------
+- *
++ *
+ * Consult ni52.c for further notes from the original driver.
+ *
+- * This incarnation currently supports the OBIO version of the i82586 chip
++ * This incarnation currently supports the OBIO version of the i82586 chip
+ * used in certain sun3 models. It should be fairly doable to expand this
+ * to support VME if I should every acquire such a board.
+ *
+@@ -122,7 +122,7 @@ sizeof(nop_cmd) = 8;
+ DELAY_16(); DELAY_16(); } }
+
+ static int sun3_82586_probe1(struct net_device *dev,int ioaddr);
+-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
++static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id);
+ static int sun3_82586_open(struct net_device *dev);
+ static int sun3_82586_close(struct net_device *dev);
+ static int sun3_82586_send_packet(struct sk_buff *,struct net_device *);
+@@ -227,7 +227,7 @@ static int check586(struct net_device *d
+ return 0;
+
+ iscp_addr = (char *)dvma_btov((unsigned long)where);
+-
++
+ p->iscp = (struct iscp_struct *) iscp_addr;
+ memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+@@ -237,7 +237,7 @@ static int check586(struct net_device *d
+ sun3_reset586();
+ sun3_attn586();
+ DELAY(1); /* wait a while... */
+-
++
+ if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+ return 0;
+
+@@ -286,7 +286,7 @@ struct net_device * __init sun3_82586_pr
+ unsigned long ioaddr;
+ static int found = 0;
+ int err = -ENOMEM;
+-
++
+ /* check that this machine has an onboard 82586 */
+ switch(idprom->id_machtype) {
+ case SM_SUN3|SM_3_160:
+@@ -300,12 +300,12 @@ struct net_device * __init sun3_82586_pr
+
+ if (found)
+ return ERR_PTR(-ENODEV);
+-
++
+ ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE);
+ if (!ioaddr)
+ return ERR_PTR(-ENOMEM);
+ found = 1;
+-
++
+ dev = alloc_etherdev(sizeof(struct priv));
+ if (!dev)
+ goto out;
+@@ -330,7 +330,7 @@ out2:
+ out1:
+ free_netdev(dev);
+ out:
+- iounmap((void *)ioaddr);
++ iounmap((void __iomem *)ioaddr);
+ return ERR_PTR(err);
+ }
+
+@@ -379,7 +379,7 @@ static int __init sun3_82586_probe1(stru
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32;
+
+ printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
+-
++
+ dev->open = sun3_82586_open;
+ dev->stop = sun3_82586_close;
+ dev->get_stats = sun3_82586_get_stats;
+@@ -479,7 +479,7 @@ static int init586(struct net_device *de
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+-
++
+ tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+ tdr_cmd->cmd_status = 0;
+@@ -678,7 +678,7 @@ static void *alloc_rfa(struct net_device
+ * Interrupt Handler ...
+ */
+
+-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
++static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ unsigned short stat;
+diff --git a/drivers/net/sun3_82586.h b/drivers/net/sun3_82586.h
+index 81cfb09..93346f0 100644
+--- a/drivers/net/sun3_82586.h
++++ b/drivers/net/sun3_82586.h
+@@ -12,13 +12,13 @@
+ */
+
+ /*
+- * Cloned from ni52.h, copyright as above.
++ * Cloned from ni52.h, copyright as above.
+ *
+ * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy at sammy.net)
+ */
+
+
+-/* defines for the obio chip (not vme) */
++/* defines for the obio chip (not vme) */
+ #define IEOB_NORSET 0x80 /* don't reset the board */
+ #define IEOB_ONAIR 0x40 /* put us on the air */
+ #define IEOB_ATTEN 0x20 /* attention! */
+@@ -159,7 +159,7 @@ struct rfd_struct
+ /*
+ * Receive Buffer Descriptor (RBD)
+ */
+-struct rbd_struct
++struct rbd_struct
+ {
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+@@ -211,7 +211,7 @@ struct nop_cmd_struct
+ /*
+ * IA Setup command
+ */
+-struct iasetup_cmd_struct
++struct iasetup_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+@@ -220,7 +220,7 @@ struct iasetup_cmd_struct
+ };
+
+ /*
+- * Configure command
++ * Configure command
+ */
+ struct configure_cmd_struct
+ {
+@@ -242,9 +242,9 @@ struct configure_cmd_struct
+ };
+
+ /*
+- * Multicast Setup command
++ * Multicast Setup command
+ */
+-struct mcsetup_cmd_struct
++struct mcsetup_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+@@ -265,9 +265,9 @@ struct dump_cmd_struct
+ };
+
+ /*
+- * transmit command
++ * transmit command
+ */
+-struct transmit_cmd_struct
++struct transmit_cmd_struct
+ {
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
+index 2dcadb1..b865db3 100644
+--- a/drivers/net/sun3lance.c
++++ b/drivers/net/sun3lance.c
+@@ -1,24 +1,24 @@
+ /* sun3lance.c: Ethernet driver for SUN3 Lance chip */
+ /*
+
+- Sun3 Lance ethernet driver, by Sam Creasey (sammy at users.qual.net).
++ Sun3 Lance ethernet driver, by Sam Creasey (sammy at users.qual.net).
+ This driver is a part of the linux kernel, and is thus distributed
+ under the GNU General Public License.
+-
++
+ The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically
+ true for the correct IRQ and address of the lance registers. They
+ have not been widely tested, however. What we probably need is a
+ "proper" way to search for a device in the sun3's prom, but, alas,
+- linux has no such thing.
++ linux has no such thing.
+
+ This driver is largely based on atarilance.c, by Roman Hodek. Other
+ sources of inspiration were the NetBSD sun3 am7990 driver, and the
+- linux sparc lance driver (sunlance.c).
++ linux sparc lance driver (sunlance.c).
+
+ There are more assumptions made throughout this driver, it almost
+ certainly still needs work, but it does work at least for RARP/BOOTP and
+ mounting the root NFS filesystem.
+-
++
+ */
+
+ static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy at sammy.net)\n";
+@@ -237,7 +237,7 @@ static int lance_probe( struct net_devic
+ static int lance_open( struct net_device *dev );
+ static void lance_init_ring( struct net_device *dev );
+ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
++static irqreturn_t lance_interrupt( int irq, void *dev_id);
+ static int lance_rx( struct net_device *dev );
+ static int lance_close( struct net_device *dev );
+ static struct net_device_stats *lance_get_stats( struct net_device *dev );
+@@ -286,7 +286,7 @@ struct net_device * __init sun3lance_pro
+
+ out1:
+ #ifdef CONFIG_SUN3
+- iounmap((void *)dev->base_addr);
++ iounmap((void __iomem *)dev->base_addr);
+ #endif
+ out:
+ free_netdev(dev);
+@@ -294,9 +294,9 @@ out:
+ }
+
+ static int __init lance_probe( struct net_device *dev)
+-{
++{
+ unsigned long ioaddr;
+-
++
+ struct lance_private *lp;
+ int i;
+ static int did_version;
+@@ -313,7 +313,7 @@ static int __init lance_probe( struct ne
+
+ /* test to see if there's really a lance here */
+ /* (CSRO_INIT shouldn't be readable) */
+-
++
+ ioaddr_probe = (volatile unsigned short *)ioaddr;
+ tmp1 = ioaddr_probe[0];
+ tmp2 = ioaddr_probe[1];
+@@ -326,7 +326,7 @@ static int __init lance_probe( struct ne
+ ioaddr_probe[1] = tmp2;
+
+ #ifdef CONFIG_SUN3
+- iounmap((void *)ioaddr);
++ iounmap((void __iomem *)ioaddr);
+ #endif
+ return 0;
+ }
+@@ -339,7 +339,7 @@ static int __init lance_probe( struct ne
+ lp->iobase = (volatile unsigned short *)ioaddr;
+ dev->base_addr = (unsigned long)ioaddr; /* informational only */
+
+- REGA(CSR0) = CSR0_STOP;
++ REGA(CSR0) = CSR0_STOP;
+
+ request_irq(LANCE_IRQ, lance_interrupt, IRQF_DISABLED, "SUN3 Lance", dev);
+ dev->irq = (unsigned short)LANCE_IRQ;
+@@ -378,7 +378,7 @@ static int __init lance_probe( struct ne
+
+ DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
+ dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head),
+- (dvma_vtob(MEM->tx_head))));
++ (dvma_vtob(MEM->tx_head))));
+
+ if (did_version++ == 0)
+ printk( version );
+@@ -427,7 +427,7 @@ static int lance_open( struct net_device
+ DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
+
+ netif_start_queue(dev);
+-
++
+ DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
+
+ return( 0 );
+@@ -449,7 +449,7 @@ static void lance_init_ring( struct net_
+ for( i = 0; i < TX_RING_SIZE; i++ ) {
+ MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
+ MEM->tx_head[i].flag = 0;
+- MEM->tx_head[i].base_hi =
++ MEM->tx_head[i].base_hi =
+ (dvma_vtob(MEM->tx_data[i])) >>16;
+ MEM->tx_head[i].length = 0;
+ MEM->tx_head[i].misc = 0;
+@@ -458,7 +458,7 @@ static void lance_init_ring( struct net_
+ for( i = 0; i < RX_RING_SIZE; i++ ) {
+ MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]);
+ MEM->rx_head[i].flag = RMD1_OWN_CHIP;
+- MEM->rx_head[i].base_hi =
++ MEM->rx_head[i].base_hi =
+ (dvma_vtob(MEM->rx_data[i])) >> 16;
+ MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
+ MEM->rx_head[i].msg_length = 0;
+@@ -542,22 +542,22 @@ static int lance_start_xmit( struct sk_b
+
+ lance_init_ring(dev);
+ REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
+-
++
+ netif_start_queue(dev);
+ dev->trans_start = jiffies;
+-
++
+ return 0;
+ }
+
+-
++
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+
+ /* Block a timer-based transmit from overlapping with us by
+ stopping the queue for a bit... */
+-
++
+ netif_stop_queue(dev);
+-
++
+ if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
+ printk( "%s: tx queue lock!.\n", dev->name);
+ /* don't clear dev->tbusy flag. */
+@@ -593,7 +593,7 @@ static int lance_start_xmit( struct sk_b
+ printk(" data at 0x%08x len %d\n", (int)skb->data,
+ (int)skb->len );
+ }
+-#endif
++#endif
+ /* We're not prepared for the int until the last flags are set/reset.
+ * And the int may happen already after setting the OWN_CHIP... */
+ local_irq_save(flags);
+@@ -632,7 +632,7 @@ static int lance_start_xmit( struct sk_b
+
+ lp->lock = 0;
+ if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
+- TMD1_OWN_HOST)
++ TMD1_OWN_HOST)
+ netif_start_queue(dev);
+
+ local_irq_restore(flags);
+@@ -642,7 +642,7 @@ static int lance_start_xmit( struct sk_b
+
+ /* The LANCE interrupt handler. */
+
+-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t lance_interrupt( int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct lance_private *lp = netdev_priv(dev);
+@@ -657,10 +657,10 @@ static irqreturn_t lance_interrupt( int
+ if (in_interrupt)
+ DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
+ in_interrupt = 1;
+-
++
+ still_more:
+ flush_cache_all();
+-
++
+ AREG = CSR0;
+ csr0 = DREG;
+
+@@ -680,22 +680,22 @@ static irqreturn_t lance_interrupt( int
+
+ // if(lance_debug >= 3) {
+ // int i;
+-//
++//
+ // printk("%s: tx int\n", dev->name);
+-//
++//
+ // for(i = 0; i < TX_RING_SIZE; i++)
+ // printk("ring %d flag=%04x\n", i,
+ // MEM->tx_head[i].flag);
+ // }
+-
++
+ while( old_tx != lp->new_tx) {
+- struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
+-
++ struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
++
+ DPRINTK(3, ("on tx_ring %d\n", old_tx));
+
+ if (head->flag & TMD1_OWN_CHIP)
+ break; /* It still hasn't been Txed */
+-
++
+ if (head->flag & TMD1_ERR) {
+ int status = head->misc;
+ lp->stats.tx_errors++;
+@@ -705,7 +705,7 @@ static irqreturn_t lance_interrupt( int
+ if (status & (TMD3_UFLO | TMD3_BUFF)) {
+ lp->stats.tx_fifo_errors++;
+ printk("%s: Tx FIFO error\n",
+- dev->name);
++ dev->name);
+ REGA(CSR0) = CSR0_STOP;
+ REGA(CSR3) = CSR3_BSWP;
+ lance_init_ring(dev);
+@@ -713,11 +713,11 @@ static irqreturn_t lance_interrupt( int
+ return IRQ_HANDLED;
+ }
+ } else if(head->flag & (TMD1_ENP | TMD1_STP)) {
+-
++
+ head->flag &= ~(TMD1_ENP | TMD1_STP);
+ if(head->flag & (TMD1_ONE | TMD1_MORE))
+ lp->stats.collisions++;
+-
++
+ lp->stats.tx_packets++;
+ DPRINTK(3, ("cleared tx ring %d\n", old_tx));
+ }
+@@ -736,7 +736,7 @@ static irqreturn_t lance_interrupt( int
+
+ if (csr0 & CSR0_RINT) /* Rx interrupt */
+ lance_rx( dev );
+-
++
+ /* Log misc errors. */
+ if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+@@ -778,10 +778,10 @@ static int lance_rx( struct net_device *
+ while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
+ struct lance_rx_head *head = &(MEM->rx_head[entry]);
+ int status = head->flag;
+-
++
+ if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */
+ /* There is a tricky error noted by John Murphy,
+- <murf at perftech.com> to Russ Nelson: Even with
++ <murf at perftech.com> to Russ Nelson: Even with
+ full-sized buffers it's possible for a jabber packet to use two
+ buffers, with only the last correctly noting the error. */
+ if (status & RMD1_ENP) /* Only count a general error at the */
+@@ -806,7 +806,7 @@ static int lance_rx( struct net_device *
+ if (skb == NULL) {
+ DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
+ dev->name ));
+-
++
+ lp->stats.rx_dropped++;
+ head->msg_length = 0;
+ head->flag |= RMD1_OWN_CHIP;
+@@ -833,7 +833,7 @@ static int lance_rx( struct net_device *
+ if (lance_debug >= 3) {
+ u_char *data = PKTBUF_ADDR(head);
+ printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len);
+- }
++ }
+
+
+ skb->dev = dev;
+@@ -914,7 +914,7 @@ static void set_multicast_list( struct n
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Log any net taps. */
+- DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
++ DPRINTK( 3, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+ REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
+ } else {
+ short multicast_table[4];
+@@ -956,7 +956,7 @@ void cleanup_module(void)
+ {
+ unregister_netdev(sun3lance_dev);
+ #ifdef CONFIG_SUN3
+- iounmap((void *)sun3lance_dev->base_addr);
++ iounmap((void __iomem *)sun3lance_dev->base_addr);
+ #endif
+ free_netdev(sun3lance_dev);
+ }
+diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
+index d468915..18f8885 100644
+--- a/drivers/net/sunbmac.c
++++ b/drivers/net/sunbmac.c
+@@ -42,7 +42,7 @@
+ #define DRV_RELDATE "11/24/03"
+ #define DRV_AUTHOR "David S. Miller (davem at redhat.com)"
+
+-static char version[] __initdata =
++static char version[] =
+ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+
+ MODULE_VERSION(DRV_VERSION);
+@@ -888,7 +888,7 @@ static void bigmac_rx(struct bigmac *bp)
+ printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);
+ }
+
+-static irqreturn_t bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bigmac_interrupt(int irq, void *dev_id)
+ {
+ struct bigmac *bp = (struct bigmac *) dev_id;
+ u32 qec_status, bmac_status;
+@@ -1071,7 +1071,7 @@ static u32 bigmac_get_link(struct net_de
+ return (bp->sw_bmsr & BMSR_LSTATUS);
+ }
+
+-static struct ethtool_ops bigmac_ethtool_ops = {
++static const struct ethtool_ops bigmac_ethtool_ops = {
+ .get_drvinfo = bigmac_get_drvinfo,
+ .get_link = bigmac_get_link,
+ };
+diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
+index 698568e..41c503d 100644
+--- a/drivers/net/sundance.c
++++ b/drivers/net/sundance.c
+@@ -17,12 +17,14 @@
+ Support and updates available at
+ http://www.scyld.com/network/sundance.html
+ [link no longer provides useful info -jgarzik]
++ Archives of the mailing list are still available at
++ http://www.beowulf.org/pipermail/netdrivers/
+
+ */
+
+ #define DRV_NAME "sundance"
+-#define DRV_VERSION "1.1"
+-#define DRV_RELDATE "27-Jun-2006"
++#define DRV_VERSION "1.2"
++#define DRV_RELDATE "11-Sep-2006"
+
+
+ /* The user-configurable values.
+@@ -418,7 +420,7 @@ static void tx_timeout(struct net_device
+ static void init_ring(struct net_device *dev);
+ static int start_tx(struct sk_buff *skb, struct net_device *dev);
+ static int reset_tx (struct net_device *dev);
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t intr_handler(int irq, void *dev_instance);
+ static void rx_poll(unsigned long data);
+ static void tx_poll(unsigned long data);
+ static void refill_rx (struct net_device *dev);
+@@ -429,7 +431,7 @@ static int __set_mac_addr(struct net_dev
+ static struct net_device_stats *get_stats(struct net_device *dev);
+ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static int netdev_close(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+
+ static void sundance_reset(struct net_device *dev, unsigned long reset_cmd)
+ {
+@@ -646,7 +648,7 @@ static int __devinit sundance_probe1 (st
+ /* Reset the chip to erase previous misconfiguration. */
+ if (netif_msg_hw(np))
+ printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
+- iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
++ sundance_reset(dev, 0x00ff << 16);
+ if (netif_msg_hw(np))
+ printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
+
+@@ -905,7 +907,7 @@ static void tx_timeout(struct net_device
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
+ unsigned long flag;
+-
++
+ netif_stop_queue(dev);
+ tasklet_disable(&np->tx_tasklet);
+ iowrite16(0, ioaddr + IntrEnable);
+@@ -922,13 +924,13 @@ static void tx_timeout(struct net_device
+ le32_to_cpu(np->tx_ring[i].next_desc),
+ le32_to_cpu(np->tx_ring[i].status),
+ (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
+- le32_to_cpu(np->tx_ring[i].frag[0].addr),
++ le32_to_cpu(np->tx_ring[i].frag[0].addr),
+ le32_to_cpu(np->tx_ring[i].frag[0].length));
+ }
+- printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+- ioread32(np->base + TxListPtr),
++ printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
++ ioread32(np->base + TxListPtr),
+ netif_queue_stopped(dev));
+- printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
++ printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+ np->cur_tx, np->cur_tx % TX_RING_SIZE,
+ np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+ printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+@@ -1000,9 +1002,9 @@ static void tx_poll (unsigned long data)
+ struct net_device *dev = (struct net_device *)data;
+ struct netdev_private *np = netdev_priv(dev);
+ unsigned head = np->cur_task % TX_RING_SIZE;
+- struct netdev_desc *txdesc =
++ struct netdev_desc *txdesc =
+ &np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
+-
++
+ /* Chain the next pointer */
+ for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
+ int entry = np->cur_task % TX_RING_SIZE;
+@@ -1072,21 +1074,16 @@ reset_tx (struct net_device *dev)
+ struct sk_buff *skb;
+ int i;
+ int irq = in_interrupt();
+-
++
+ /* Reset tx logic, TxListPtr will be cleaned */
+ iowrite16 (TxDisable, ioaddr + MACCtrl1);
+- iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset,
+- ioaddr + ASICCtrl + 2);
+- for (i=50; i > 0; i--) {
+- if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+- break;
+- mdelay(1);
+- }
++ sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16);
++
+ /* free all tx skbuff */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ skb = np->tx_skbuff[i];
+ if (skb) {
+- pci_unmap_single(np->pci_dev,
++ pci_unmap_single(np->pci_dev,
+ np->tx_ring[i].frag[0].addr, skb->len,
+ PCI_DMA_TODEVICE);
+ if (irq)
+@@ -1103,9 +1100,9 @@ reset_tx (struct net_device *dev)
+ return 0;
+ }
+
+-/* The interrupt handler cleans up after the Tx thread,
++/* The interrupt handler cleans up after the Tx thread,
+ and schedule a Rx thread work */
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t intr_handler(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct netdev_private *np = netdev_priv(dev);
+@@ -1184,8 +1181,8 @@ static irqreturn_t intr_handler(int irq,
+ } else {
+ hw_frame_id = ioread8(ioaddr + TxFrameId);
+ }
+-
+- if (np->pci_rev_id >= 0x14) {
++
++ if (np->pci_rev_id >= 0x14) {
+ spin_lock(&np->lock);
+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+ int entry = np->dirty_tx % TX_RING_SIZE;
+@@ -1197,7 +1194,7 @@ static irqreturn_t intr_handler(int irq,
+ !(le32_to_cpu(np->tx_ring[entry].status)
+ & 0x00010000))
+ break;
+- if (sw_frame_id == (hw_frame_id + 1) %
++ if (sw_frame_id == (hw_frame_id + 1) %
+ TX_RING_SIZE)
+ break;
+ skb = np->tx_skbuff[entry];
+@@ -1216,7 +1213,7 @@ static irqreturn_t intr_handler(int irq,
+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+ int entry = np->dirty_tx % TX_RING_SIZE;
+ struct sk_buff *skb;
+- if (!(le32_to_cpu(np->tx_ring[entry].status)
++ if (!(le32_to_cpu(np->tx_ring[entry].status)
+ & 0x00010000))
+ break;
+ skb = np->tx_skbuff[entry];
+@@ -1231,7 +1228,7 @@ static irqreturn_t intr_handler(int irq,
+ }
+ spin_unlock(&np->lock);
+ }
+-
++
+ if (netif_queue_stopped(dev) &&
+ np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+ /* The ring is no longer full, clear busy flag. */
+@@ -1467,8 +1464,6 @@ static void set_rx_mode(struct net_devic
+ int i;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
+ } else if ((dev->mc_count > multicast_filter_limit)
+@@ -1574,7 +1569,7 @@ static void set_msglevel(struct net_devi
+ np->msg_enable = val;
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .begin = check_if_running,
+ .get_drvinfo = get_drvinfo,
+ .get_settings = get_settings,
+@@ -1603,18 +1598,18 @@ static int netdev_ioctl(struct net_devic
+ case SIOCDEVPRIVATE:
+ for (i=0; i<TX_RING_SIZE; i++) {
+ printk(KERN_DEBUG "%02x %08llx %08x %08x(%02x) %08x %08x\n", i,
+- (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
++ (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
+ le32_to_cpu(np->tx_ring[i].next_desc),
+ le32_to_cpu(np->tx_ring[i].status),
+- (le32_to_cpu(np->tx_ring[i].status) >> 2)
++ (le32_to_cpu(np->tx_ring[i].status) >> 2)
+ & 0xff,
+- le32_to_cpu(np->tx_ring[i].frag[0].addr),
++ le32_to_cpu(np->tx_ring[i].frag[0].addr),
+ le32_to_cpu(np->tx_ring[i].frag[0].length));
+ }
+- printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+- ioread32(np->base + TxListPtr),
++ printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
++ ioread32(np->base + TxListPtr),
+ netif_queue_stopped(dev));
+- printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
++ printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+ np->cur_tx, np->cur_tx % TX_RING_SIZE,
+ np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+ printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+@@ -1622,7 +1617,7 @@ static int netdev_ioctl(struct net_devic
+ printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus));
+ return 0;
+ }
+-
++
+
+ return rc;
+ }
+@@ -1736,7 +1731,7 @@ static int __init sundance_init(void)
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init(&sundance_driver);
++ return pci_register_driver(&sundance_driver);
+ }
+
+ static void __exit sundance_exit(void)
+diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
+index b70bbd7..253e96e 100644
+--- a/drivers/net/sungem.c
++++ b/drivers/net/sungem.c
+@@ -2,21 +2,21 @@
+ * sungem.c: Sun GEM ethernet driver.
+ *
+ * Copyright (C) 2000, 2001, 2002, 2003 David S. Miller (davem at redhat.com)
+- *
++ *
+ * Support for Apple GMAC and assorted PHYs, WOL, Power Management
+ * (C) 2001,2002,2003 Benjamin Herrenscmidt (benh at kernel.crashing.org)
+ * (C) 2004,2005 Benjamin Herrenscmidt, IBM Corp.
+ *
+ * NAPI and NETPOLL support
+ * (C) 2004 by Eric Lemoine (eric.lemoine at gmail.com)
+- *
+- * TODO:
++ *
++ * TODO:
+ * - Now that the driver was significantly simplified, I need to rework
+ * the locking. I'm sure we don't need _2_ spinlocks, and we probably
+ * can avoid taking most of them for so long period of time (and schedule
+ * instead). The main issues at this point are caused by the netdev layer
+ * though:
+- *
++ *
+ * gem_change_mtu() and gem_set_multicast() are called with a read_lock()
+ * help by net/core/dev.c, thus they can't schedule. That means they can't
+ * call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock
+@@ -113,7 +113,7 @@ static struct pci_device_id gem_pci_tbl[
+ /* These models only differ from the original GEM in
+ * that their tx/rx fifos are of a different size and
+ * they only support 10/100 speeds. -DaveM
+- *
++ *
+ * Apple's GMAC does support gigabit on machines with
+ * the BCM54xx PHYs. -BenH
+ */
+@@ -855,7 +855,7 @@ static int gem_rx(struct gem *gp, int wo
+ }
+
+ skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->protocol = eth_type_trans(skb, gp->dev);
+
+ netif_receive_skb(skb);
+@@ -885,7 +885,7 @@ static int gem_poll(struct net_device *d
+ unsigned long flags;
+
+ /*
+- * NAPI locking nightmare: See comment at head of driver
++ * NAPI locking nightmare: See comment at head of driver
+ */
+ spin_lock_irqsave(&gp->lock, flags);
+
+@@ -905,8 +905,8 @@ static int gem_poll(struct net_device *d
+
+ spin_unlock_irqrestore(&gp->lock, flags);
+
+- /* Run RX thread. We don't use any locking here,
+- * code willing to do bad things - like cleaning the
++ /* Run RX thread. We don't use any locking here,
++ * code willing to do bad things - like cleaning the
+ * rx ring - must call netif_poll_disable(), which
+ * schedule_timeout()'s if polling is already disabled.
+ */
+@@ -921,7 +921,7 @@ static int gem_poll(struct net_device *d
+ return 1;
+
+ spin_lock_irqsave(&gp->lock, flags);
+-
++
+ gp->status = readl(gp->regs + GREG_STAT);
+ } while (gp->status & GREG_STAT_NAPI);
+
+@@ -932,7 +932,7 @@ static int gem_poll(struct net_device *d
+ return 0;
+ }
+
+-static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t gem_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct gem *gp = dev->priv;
+@@ -946,7 +946,7 @@ static irqreturn_t gem_interrupt(int irq
+ return IRQ_HANDLED;
+
+ spin_lock_irqsave(&gp->lock, flags);
+-
++
+ if (netif_rx_schedule_prep(dev)) {
+ u32 gem_status = readl(gp->regs + GREG_STAT);
+
+@@ -961,9 +961,9 @@ static irqreturn_t gem_interrupt(int irq
+ }
+
+ spin_unlock_irqrestore(&gp->lock, flags);
+-
++
+ /* If polling was disabled at the time we received that
+- * interrupt, we may return IRQ_HANDLED here while we
++ * interrupt, we may return IRQ_HANDLED here while we
+ * should return IRQ_NONE. No big deal...
+ */
+ return IRQ_HANDLED;
+@@ -975,7 +975,7 @@ static void gem_poll_controller(struct n
+ /* gem_interrupt is safe to reentrance so no need
+ * to disable_irq here.
+ */
+- gem_interrupt(dev->irq, dev, NULL);
++ gem_interrupt(dev->irq, dev);
+ }
+ #endif
+
+@@ -1026,7 +1026,7 @@ static int gem_start_xmit(struct sk_buff
+ unsigned long flags;
+
+ ctrl = 0;
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u64 csum_start_off, csum_stuff_off;
+
+ csum_start_off = (u64) (skb->h.raw - skb->data);
+@@ -1112,7 +1112,7 @@ static int gem_start_xmit(struct sk_buff
+ this_ctrl = ctrl;
+ if (frag == skb_shinfo(skb)->nr_frags - 1)
+ this_ctrl |= TXDCTRL_EOF;
+-
++
+ txd = &gp->init_block->txd[entry];
+ txd->buffer = cpu_to_le64(mapping);
+ wmb();
+@@ -1178,7 +1178,7 @@ static void gem_reset(struct gem *gp)
+ static void gem_start_dma(struct gem *gp)
+ {
+ u32 val;
+-
++
+ /* We are ready to rock, turn everything on. */
+ val = readl(gp->regs + TXDMA_CFG);
+ writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
+@@ -1246,7 +1246,7 @@ static void gem_begin_auto_negotiation(s
+ autoneg = gp->want_autoneg;
+ speed = gp->phy_mii.speed;
+ duplex = gp->phy_mii.duplex;
+-
++
+ /* Setup link parameters */
+ if (!ep)
+ goto start_aneg;
+@@ -1276,7 +1276,7 @@ start_aneg:
+ duplex = DUPLEX_HALF;
+ if (speed == 0)
+ speed = SPEED_10;
+-
++
+ /* If we are asleep, we don't try to actually setup the PHY, we
+ * just store the settings
+ */
+@@ -1345,7 +1345,7 @@ static int gem_set_link_modes(struct gem
+ val |= (MAC_TXCFG_ICS | MAC_TXCFG_ICOLL);
+ } else {
+ /* MAC_TXCFG_NBO must be zero. */
+- }
++ }
+ writel(val, gp->regs + MAC_TXCFG);
+
+ val = (MAC_XIFCFG_OE | MAC_XIFCFG_LLED);
+@@ -1470,7 +1470,7 @@ static void gem_link_timer(unsigned long
+ {
+ struct gem *gp = (struct gem *) data;
+ int restart_aneg = 0;
+-
++
+ if (gp->asleep)
+ return;
+
+@@ -1483,7 +1483,7 @@ static void gem_link_timer(unsigned long
+ */
+ if (gp->reset_task_pending)
+ goto restart;
+-
++
+ if (gp->phy_type == phy_serialink ||
+ gp->phy_type == phy_serdes) {
+ u32 val = readl(gp->regs + PCS_MIISTAT);
+@@ -1660,7 +1660,7 @@ static void gem_init_phy(struct gem *gp)
+ mifcfg = readl(gp->regs + MIF_CFG);
+ mifcfg &= ~MIF_CFG_BBMODE;
+ writel(mifcfg, gp->regs + MIF_CFG);
+-
++
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ int i;
+
+@@ -1823,7 +1823,7 @@ static u32 gem_setup_multicast(struct ge
+ {
+ u32 rxcfg = 0;
+ int i;
+-
++
+ if ((gp->dev->flags & IFF_ALLMULTI) ||
+ (gp->dev->mc_count > 256)) {
+ for (i=0; i<16; i++)
+@@ -1985,7 +1985,7 @@ static void gem_init_pause_thresholds(st
+ cfg = ((2 << 1) & GREG_CFG_TXDMALIM);
+ cfg |= ((8 << 6) & GREG_CFG_RXDMALIM);
+ writel(cfg, gp->regs + GREG_CFG);
+- }
++ }
+ }
+
+ static int gem_check_invariants(struct gem *gp)
+@@ -2039,7 +2039,7 @@ static int gem_check_invariants(struct g
+ /* Determine initial PHY interface type guess. MDIO1 is the
+ * external PHY and thus takes precedence over MDIO0.
+ */
+-
++
+ if (mif_cfg & MIF_CFG_MDI1) {
+ gp->phy_type = phy_mii_mdio1;
+ mif_cfg |= MIF_CFG_PSELECT;
+@@ -2141,7 +2141,7 @@ static void gem_stop_phy(struct gem *gp,
+
+ /* Setup wake-on-lan for MAGIC packet */
+ writel(MAC_RXCFG_HFE | MAC_RXCFG_SFCS | MAC_RXCFG_ENAB,
+- gp->regs + MAC_RXCFG);
++ gp->regs + MAC_RXCFG);
+ writel((e[4] << 8) | e[5], gp->regs + WOL_MATCH0);
+ writel((e[2] << 8) | e[3], gp->regs + WOL_MATCH1);
+ writel((e[0] << 8) | e[1], gp->regs + WOL_MATCH2);
+@@ -2230,7 +2230,7 @@ static int gem_do_start(struct net_devic
+ gem_reset(gp);
+ gem_clean_rings(gp);
+ gem_put_cell(gp);
+-
++
+ spin_unlock(&gp->tx_lock);
+ spin_unlock_irqrestore(&gp->lock, flags);
+
+@@ -2343,12 +2343,12 @@ static int gem_close(struct net_device *
+
+ mutex_lock(&gp->pm_mutex);
+
+- gp->opened = 0;
++ gp->opened = 0;
+ if (!gp->asleep)
+ gem_do_stop(dev, 0);
+
+ mutex_unlock(&gp->pm_mutex);
+-
++
+ return 0;
+ }
+
+@@ -2366,7 +2366,7 @@ static int gem_suspend(struct pci_dev *p
+ printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
+ dev->name,
+ (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
+-
++
+ /* Keep the cell enabled during the entire operation */
+ spin_lock_irqsave(&gp->lock, flags);
+ spin_lock(&gp->tx_lock);
+@@ -2486,7 +2486,7 @@ static int gem_resume(struct pci_dev *pd
+ spin_unlock_irqrestore(&gp->lock, flags);
+
+ netif_poll_enable(dev);
+-
++
+ mutex_unlock(&gp->pm_mutex);
+
+ return 0;
+@@ -2533,7 +2533,7 @@ static void gem_set_multicast(struct net
+ struct gem *gp = dev->priv;
+ u32 rxcfg, rxcfg_new;
+ int limit = 10000;
+-
++
+
+ spin_lock_irq(&gp->lock);
+ spin_lock(&gp->tx_lock);
+@@ -2549,7 +2549,7 @@ static void gem_set_multicast(struct net
+ rxcfg_new |= MAC_RXCFG_SFCS;
+ #endif
+ gp->mac_rx_cfg = rxcfg_new;
+-
++
+ writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+ while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
+ if (!limit--)
+@@ -2611,12 +2611,12 @@ static int gem_change_mtu(struct net_dev
+ static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+ {
+ struct gem *gp = dev->priv;
+-
++
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(gp->pdev));
+ }
+-
++
+ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct gem *gp = dev->priv;
+@@ -2638,7 +2638,7 @@ static int gem_get_settings(struct net_d
+ spin_lock_irq(&gp->lock);
+ cmd->autoneg = gp->want_autoneg;
+ cmd->speed = gp->phy_mii.speed;
+- cmd->duplex = gp->phy_mii.duplex;
++ cmd->duplex = gp->phy_mii.duplex;
+ cmd->advertising = gp->phy_mii.advertising;
+
+ /* If we started with a forced mode, we don't have a default
+@@ -2683,7 +2683,7 @@ static int gem_set_settings(struct net_d
+ (cmd->duplex != DUPLEX_HALF &&
+ cmd->duplex != DUPLEX_FULL)))
+ return -EINVAL;
+-
++
+ /* Apply settings and restart link process. */
+ spin_lock_irq(&gp->lock);
+ gem_get_cell(gp);
+@@ -2716,7 +2716,7 @@ static u32 gem_get_msglevel(struct net_d
+ struct gem *gp = dev->priv;
+ return gp->msg_enable;
+ }
+-
++
+ static void gem_set_msglevel(struct net_device *dev, u32 value)
+ {
+ struct gem *gp = dev->priv;
+@@ -2753,7 +2753,7 @@ static int gem_set_wol(struct net_device
+ return 0;
+ }
+
+-static struct ethtool_ops gem_ethtool_ops = {
++static const struct ethtool_ops gem_ethtool_ops = {
+ .get_drvinfo = gem_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_settings = gem_get_settings,
+@@ -2776,7 +2776,7 @@ static int gem_ioctl(struct net_device *
+ * with power management.
+ */
+ mutex_lock(&gp->pm_mutex);
+-
++
+ spin_lock_irqsave(&gp->lock, flags);
+ gem_get_cell(gp);
+ spin_unlock_irqrestore(&gp->lock, flags);
+@@ -2808,13 +2808,13 @@ static int gem_ioctl(struct net_device *
+ }
+ break;
+ };
+-
++
+ spin_lock_irqsave(&gp->lock, flags);
+ gem_put_cell(gp);
+ spin_unlock_irqrestore(&gp->lock, flags);
+
+ mutex_unlock(&gp->pm_mutex);
+-
++
+ return rc;
+ }
+
+@@ -2896,7 +2896,7 @@ static int __devinit gem_get_device_addr
+ if (use_idprom)
+ memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ #elif defined(CONFIG_PPC_PMAC)
+- unsigned char *addr;
++ const unsigned char *addr;
+
+ addr = get_property(gp->of_node, "local-mac-address", NULL);
+ if (addr == NULL) {
+@@ -3000,7 +3000,7 @@ static int __devinit gem_init_one(struct
+ }
+ pci_using_dac = 0;
+ }
+-
++
+ gemreg_base = pci_resource_start(pdev, 0);
+ gemreg_len = pci_resource_len(pdev, 0);
+
+@@ -3044,7 +3044,7 @@ static int __devinit gem_init_one(struct
+ gp->link_timer.data = (unsigned long) gp;
+
+ INIT_WORK(&gp->reset_task, gem_reset_task, gp);
+-
++
+ gp->lstate = link_down;
+ gp->timer_ticks = 0;
+ netif_carrier_off(dev);
+@@ -3153,7 +3153,7 @@ static int __devinit gem_init_one(struct
+
+ if (gp->phy_type == phy_mii_mdio0 ||
+ gp->phy_type == phy_mii_mdio1)
+- printk(KERN_INFO "%s: Found %s PHY\n", dev->name,
++ printk(KERN_INFO "%s: Found %s PHY\n", dev->name,
+ gp->phy_mii.def ? gp->phy_mii.def->name : "no");
+
+ /* GEM can do it all... */
+@@ -3194,7 +3194,7 @@ static struct pci_driver gem_driver = {
+
+ static int __init gem_init(void)
+ {
+- return pci_module_init(&gem_driver);
++ return pci_register_driver(&gem_driver);
+ }
+
+ static void __exit gem_cleanup(void)
+diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
+index 8984721..a70067c 100644
+--- a/drivers/net/sungem.h
++++ b/drivers/net/sungem.h
+@@ -813,7 +813,7 @@
+ /* MII BCM5400 AUXSTATUS register */
+ #define MII_BCM5400_AUXSTATUS 0x19
+ #define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
+-#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
++#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+
+ /* When it can, GEM internally caches 4 aligned TX descriptors
+ * at a time, so that it can use full cacheline DMA reads.
+@@ -984,10 +984,10 @@ struct gem {
+ unsigned int asleep_wol : 1; /* was asleep with WOL enabled */
+ unsigned int opened : 1; /* driver opened, protected by pm_mutex */
+ unsigned int running : 1; /* chip running, protected by lock */
+-
++
+ /* cell enable count, protected by lock */
+- int cell_enabled;
+-
++ int cell_enabled;
++
+ struct mutex pm_mutex;
+
+ u32 msg_enable;
+@@ -1017,7 +1017,7 @@ struct gem {
+ enum gem_phy_type phy_type;
+ struct mii_phy phy_mii;
+ int mii_phy_addr;
+-
++
+ struct gem_init_block *init_block;
+ struct sk_buff *rx_skbs[RX_RING_SIZE];
+ struct sk_buff *tx_skbs[TX_RING_SIZE];
+@@ -1032,7 +1032,7 @@ struct gem {
+
+ #define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) \
+ && gp->phy_mii.def && gp->phy_mii.def->ops)
+-
++
+ #define ALIGNED_RX_SKB_ADDR(addr) \
+ ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr))
+ static __inline__ struct sk_buff *gem_alloc_skb(int size,
+diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
+index 278c7cb..49800b2 100644
+--- a/drivers/net/sungem_phy.c
++++ b/drivers/net/sungem_phy.c
+@@ -1,8 +1,8 @@
+ /*
+ * PHY drivers for the sungem ethernet driver.
+- *
++ *
+ * This file could be shared with other drivers.
+- *
++ *
+ * (c) 2002, Benjamin Herrenscmidt (benh at kernel.crashing.org)
+ *
+ * TODO:
+@@ -73,7 +73,7 @@ static int reset_one_mii_phy(struct mii_
+ {
+ u16 val;
+ int limit = 10000;
+-
++
+ val = __phy_read(phy, phy_id, MII_BMCR);
+ val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
+ val |= BMCR_RESET;
+@@ -89,7 +89,7 @@ static int reset_one_mii_phy(struct mii_
+ }
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
+-
++
+ return (limit <= 0);
+ }
+
+@@ -160,16 +160,16 @@ static int bcm5400_init(struct mii_phy*
+ data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+ data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+-
++
+ data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+-
++
+ udelay(100);
+
+ /* Reset and configure cascaded 10/100 PHY */
+ (void)reset_one_mii_phy(phy, 0x1f);
+-
++
+ data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+@@ -199,7 +199,7 @@ static int bcm5401_init(struct mii_phy*
+ /* Some revisions of 5401 appear to need this
+ * initialisation sequence to disable, according
+ * to OF, "tap power management"
+- *
++ *
+ * WARNING ! OF and Darwin don't agree on the
+ * register addresses. OF seem to interpret the
+ * register numbers below as decimal
+@@ -219,7 +219,7 @@ static int bcm5401_init(struct mii_phy*
+ phy_write(phy, 0x17, 0x201f);
+ phy_write(phy, 0x15, 0x0a20);
+ }
+-
++
+ /* Configure for gigabit full duplex */
+ data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+@@ -229,7 +229,7 @@ static int bcm5401_init(struct mii_phy*
+
+ /* Reset and configure cascaded 10/100 PHY */
+ (void)reset_one_mii_phy(phy, 0x1f);
+-
++
+ data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+@@ -270,7 +270,7 @@ static int bcm5411_init(struct mii_phy*
+
+ /* Reset and configure cascaded 10/100 PHY */
+ (void)reset_one_mii_phy(phy, 0x1f);
+-
++
+ return 0;
+ }
+
+@@ -355,7 +355,7 @@ static int bcm5461_enable_fiber(struct m
+ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
+ {
+ u16 ctl, adv;
+-
++
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+@@ -395,7 +395,7 @@ static int bcm54xx_setup_aneg(struct mii
+ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
+ {
+ u16 ctl;
+-
++
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+@@ -421,7 +421,7 @@ static int bcm54xx_setup_forced(struct m
+ ctl |= BMCR_FULLDPLX;
+
+ // XXX Should we set the sungem to GII now on 1000BT ?
+-
++
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+@@ -429,9 +429,9 @@ static int bcm54xx_setup_forced(struct m
+
+ static int bcm54xx_read_link(struct mii_phy *phy)
+ {
+- int link_mode;
++ int link_mode;
+ u16 val;
+-
++
+ if (phy->autoneg) {
+ val = phy_read(phy, MII_BCM5400_AUXSTATUS);
+ link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+@@ -453,7 +453,7 @@ static int bcm54xx_read_link(struct mii_
+ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
+ {
+ u16 ctl, adv;
+-
++
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+@@ -500,7 +500,7 @@ static int marvell_setup_aneg(struct mii
+ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
+ {
+ u16 ctl, ctl2;
+-
++
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+@@ -541,7 +541,7 @@ static int marvell_setup_forced(struct m
+ phy_write(phy, MII_1000BASETCONTROL, ctl2);
+
+ // XXX Should we set the sungem to GII now on 1000BT ?
+-
++
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+@@ -577,7 +577,7 @@ static int marvell_read_link(struct mii_
+ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+ {
+ u16 ctl, adv;
+-
++
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+@@ -608,7 +608,7 @@ static int genmii_setup_aneg(struct mii_
+ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+ {
+ u16 ctl;
+-
++
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+@@ -641,7 +641,7 @@ static int genmii_setup_forced(struct mi
+ static int genmii_poll_link(struct mii_phy *phy)
+ {
+ u16 status;
+-
++
+ (void)phy_read(phy, MII_BMSR);
+ status = phy_read(phy, MII_BMSR);
+ if ((status & BMSR_LSTATUS) == 0)
+@@ -918,13 +918,13 @@ int mii_phy_probe(struct mii_phy *phy, i
+ * may re-probe the PHY regulary
+ */
+ phy->mii_id = mii_id;
+-
++
+ /* Take PHY out of isloate mode and reset it. */
+ rc = reset_one_mii_phy(phy, mii_id);
+ if (rc)
+ goto fail;
+
+- /* Read ID and find matching entry */
++ /* Read ID and find matching entry */
+ id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+ printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
+ for (i=0; (def = mii_phy_table[i]) != NULL; i++)
+@@ -935,7 +935,7 @@ int mii_phy_probe(struct mii_phy *phy, i
+ goto fail;
+
+ phy->def = def;
+-
++
+ return 0;
+ fail:
+ phy->speed = 0;
+diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
+index 69e1251..8ee1ca0 100644
+--- a/drivers/net/sungem_phy.h
++++ b/drivers/net/sungem_phy.h
+@@ -96,7 +96,7 @@ extern int mii_phy_probe(struct mii_phy
+ /* MII BCM5400 AUXSTATUS register */
+ #define MII_BCM5400_AUXSTATUS 0x19
+ #define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
+-#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
++#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+
+ /* 1000BT control (Marvell & BCM54xx at least) */
+ #define MII_1000BASETCONTROL 0x09
+diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
+index c6f5bc3..9d7cd13 100644
+--- a/drivers/net/sunhme.c
++++ b/drivers/net/sunhme.c
+@@ -505,7 +505,7 @@ static void happy_meal_tcvr_write(struct
+ unsigned short value)
+ {
+ int tries = TCVR_WRITE_TRIES;
+-
++
+ ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));
+
+ /* Welcome to Sun Microsystems, can I take your order please? */
+@@ -1207,7 +1207,7 @@ static void happy_meal_transceiver_check
+ * flags, thus:
+ *
+ * skb->csum = rxd->rx_flags & 0xffff;
+- * skb->ip_summed = CHECKSUM_HW;
++ * skb->ip_summed = CHECKSUM_COMPLETE;
+ *
+ * before sending off the skb to the protocols, and we are good as gold.
+ */
+@@ -1778,7 +1778,7 @@ static void happy_meal_set_initial_adver
+ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
+ {
+ int reset = 0;
+-
++
+ /* Only print messages for non-counter related interrupts. */
+ if (status & (GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND |
+ GREG_STAT_MAXPKTERR | GREG_STAT_RXERR |
+@@ -2074,7 +2074,7 @@ static void happy_meal_rx(struct happy_m
+
+ /* This card is _fucking_ hot... */
+ skb->csum = ntohs(csum ^ 0xffff);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+
+ RXD(("len=%d csum=%4x]", len, csum));
+ skb->protocol = eth_type_trans(skb, dev);
+@@ -2093,10 +2093,10 @@ static void happy_meal_rx(struct happy_m
+ RXD((">"));
+ }
+
+-static irqreturn_t happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t happy_meal_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
+- struct happy_meal *hp = dev->priv;
++ struct net_device *dev = dev_id;
++ struct happy_meal *hp = netdev_priv(dev);
+ u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT);
+
+ HMD(("happy_meal_interrupt: status=%08x ", happy_status));
+@@ -2132,7 +2132,7 @@ out:
+ }
+
+ #ifdef CONFIG_SBUS
+-static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs)
++static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie)
+ {
+ struct quattro *qp = (struct quattro *) cookie;
+ int i;
+@@ -2268,7 +2268,7 @@ static int happy_meal_start_xmit(struct
+ u32 tx_flags;
+
+ tx_flags = TXFLAG_OWN;
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u32 csum_start_off, csum_stuff_off;
+
+ csum_start_off = (u32) (skb->h.raw - skb->data);
+@@ -2512,7 +2512,7 @@ static u32 hme_get_link(struct net_devic
+ return (hp->sw_bmsr & BMSR_LSTATUS);
+ }
+
+-static struct ethtool_ops hme_ethtool_ops = {
++static const struct ethtool_ops hme_ethtool_ops = {
+ .get_settings = hme_get_settings,
+ .set_settings = hme_set_settings,
+ .get_drvinfo = hme_get_drvinfo,
+@@ -3002,7 +3002,7 @@ static int __devinit happy_meal_pci_prob
+ printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
+ return -ENODEV;
+ }
+-
++
+ strcpy(prom_name, pcp->prom_node->name);
+ #else
+ if (is_quattro_p(pdev))
+@@ -3046,7 +3046,7 @@ static int __devinit happy_meal_pci_prob
+ hp->qfe_parent = qp;
+ hp->qfe_ent = qfe_slot;
+ qp->happy_meals[qfe_slot] = dev;
+- }
++ }
+
+ hpreg_res = pci_resource_start(pdev, 0);
+ err = -ENODEV;
+@@ -3090,7 +3090,7 @@ static int __devinit happy_meal_pci_prob
+ get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
+ #endif
+ }
+-
++
+ /* Layout registers. */
+ hp->gregs = (hpreg_base + 0x0000UL);
+ hp->etxregs = (hpreg_base + 0x2000UL);
+@@ -3201,7 +3201,7 @@ static int __devinit happy_meal_pci_prob
+ qpdev->device == PCI_DEVICE_ID_DEC_21153)
+ printk("DEC 21153 PCI Bridge\n");
+ else
+- printk("unknown bridge %04x.%04x\n",
++ printk("unknown bridge %04x.%04x\n",
+ qpdev->vendor, qpdev->device);
+ }
+
+diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
+index ec04136..5b00d79 100644
+--- a/drivers/net/sunlance.c
++++ b/drivers/net/sunlance.c
+@@ -64,7 +64,7 @@
+ * David S. Miller (davem at redhat.com)
+ * 2.01:
+ * 11/08/01: Use library crc32 functions (Matt_Domsch at dell.com)
+- *
++ *
+ */
+
+ #undef DEBUG_DRIVER
+@@ -209,7 +209,7 @@ struct lance_tx_desc {
+ s16 length; /* Length is 2s complement (negative)! */
+ u16 misc;
+ };
+-
++
+ /* The LANCE initialization block, described in databook. */
+ /* On the Sparc, this block should be on a DMA region */
+ struct lance_init_block {
+@@ -222,11 +222,11 @@ struct lance_init_block {
+ u16 rx_len; /* receive len and high addr */
+ u16 tx_ptr; /* transmit descriptor addr */
+ u16 tx_len; /* transmit len and high addr */
+-
++
+ /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
+ struct lance_rx_desc brx_ring[RX_RING_SIZE];
+ struct lance_tx_desc btx_ring[TX_RING_SIZE];
+-
++
+ u8 tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+ u8 pad[2]; /* align rx_buf for copy_and_sum(). */
+ u8 rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
+@@ -243,12 +243,12 @@ struct lance_private {
+ void __iomem *dregs; /* DMA controller regs. */
+ struct lance_init_block __iomem *init_block_iomem;
+ struct lance_init_block *init_block_mem;
+-
++
+ spinlock_t lock;
+
+ int rx_new, tx_new;
+ int rx_old, tx_old;
+-
++
+ struct net_device_stats stats;
+ struct sbus_dma *ledma; /* If set this points to ledma */
+ char tpe; /* cable-selection is TPE */
+@@ -325,7 +325,7 @@ static void lance_init_ring_dvma(struct
+ dma_addr_t aib = lp->init_block_dvma;
+ __u32 leptr;
+ int i;
+-
++
+ /* Lock out other processes while setting up hardware */
+ netif_stop_queue(dev);
+ lp->rx_new = lp->tx_new = 0;
+@@ -363,12 +363,12 @@ static void lance_init_ring_dvma(struct
+ }
+
+ /* Setup the initialization block */
+-
++
+ /* Setup rx descriptor pointer */
+ leptr = LANCE_ADDR(aib + libdesc_offset(brx_ring, 0));
+ ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
+ ib->rx_ptr = leptr;
+-
++
+ /* Setup tx descriptor pointer */
+ leptr = LANCE_ADDR(aib + libdesc_offset(btx_ring, 0));
+ ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
+@@ -381,7 +381,7 @@ static void lance_init_ring_pio(struct n
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
+ u32 leptr;
+ int i;
+-
++
+ /* Lock out other processes while setting up hardware */
+ netif_stop_queue(dev);
+ lp->rx_new = lp->tx_new = 0;
+@@ -422,13 +422,13 @@ static void lance_init_ring_pio(struct n
+ }
+
+ /* Setup the initialization block */
+-
++
+ /* Setup rx descriptor pointer */
+ leptr = libdesc_offset(brx_ring, 0);
+ sbus_writew((LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16),
+ &ib->rx_len);
+ sbus_writew(leptr, &ib->rx_ptr);
+-
++
+ /* Setup tx descriptor pointer */
+ leptr = libdesc_offset(btx_ring, 0);
+ sbus_writew((LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16),
+@@ -544,7 +544,7 @@ static void lance_rx_dvma(struct net_dev
+ lp->rx_new = RX_NEXT(entry);
+ return;
+ }
+-
++
+ lp->stats.rx_bytes += len;
+
+ skb->dev = dev;
+@@ -584,10 +584,10 @@ static void lance_tx_dvma(struct net_dev
+ /* If we hit a packet not owned by us, stop */
+ if (bits & LE_T1_OWN)
+ break;
+-
++
+ if (bits & LE_T1_ERR) {
+ u16 status = td->misc;
+-
++
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+@@ -636,7 +636,7 @@ static void lance_tx_dvma(struct net_dev
+
+ lp->stats.tx_packets++;
+ }
+-
++
+ j = TX_NEXT(j);
+ }
+ lp->tx_old = j;
+@@ -718,7 +718,7 @@ static void lance_rx_pio(struct net_devi
+ lp->rx_new = RX_NEXT(entry);
+ return;
+ }
+-
++
+ lp->stats.rx_bytes += len;
+
+ skb->dev = dev;
+@@ -756,10 +756,10 @@ static void lance_tx_pio(struct net_devi
+ /* If we hit a packet not owned by us, stop */
+ if (bits & LE_T1_OWN)
+ break;
+-
++
+ if (bits & LE_T1_ERR) {
+ u16 status = sbus_readw(&td->misc);
+-
++
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+@@ -808,7 +808,7 @@ static void lance_tx_pio(struct net_devi
+
+ lp->stats.tx_packets++;
+ }
+-
++
+ j = TX_NEXT(j);
+ }
+ lp->tx_old = j;
+@@ -820,32 +820,32 @@ out:
+ spin_unlock(&lp->lock);
+ }
+
+-static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t lance_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *)dev_id;
++ struct net_device *dev = dev_id;
+ struct lance_private *lp = netdev_priv(dev);
+ int csr0;
+-
++
+ sbus_writew(LE_CSR0, lp->lregs + RAP);
+ csr0 = sbus_readw(lp->lregs + RDP);
+
+ /* Acknowledge all the interrupt sources ASAP */
+ sbus_writew(csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT),
+ lp->lregs + RDP);
+-
++
+ if ((csr0 & LE_C0_ERR) != 0) {
+ /* Clear the error condition */
+ sbus_writew((LE_C0_BABL | LE_C0_ERR | LE_C0_MISS |
+ LE_C0_CERR | LE_C0_MERR),
+ lp->lregs + RDP);
+ }
+-
++
+ if (csr0 & LE_C0_RINT)
+ lp->rx(dev);
+-
++
+ if (csr0 & LE_C0_TINT)
+ lp->tx(dev);
+-
++
+ if (csr0 & LE_C0_BABL)
+ lp->stats.tx_errors++;
+
+@@ -992,7 +992,7 @@ static int lance_reset(struct net_device
+ {
+ struct lance_private *lp = netdev_priv(dev);
+ int status;
+-
++
+ STOP_LANCE(lp);
+
+ /* On the 4m, reset the dma too */
+@@ -1169,7 +1169,7 @@ static int lance_start_xmit(struct sk_bu
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb);
+-
++
+ return 0;
+ }
+
+@@ -1189,7 +1189,7 @@ static void lance_load_multicast(struct
+ int i;
+ u32 crc;
+ u32 val;
+-
++
+ /* set all multicast bits */
+ if (dev->flags & IFF_ALLMULTI)
+ val = ~0;
+@@ -1208,7 +1208,7 @@ static void lance_load_multicast(struct
+
+ if (dev->flags & IFF_ALLMULTI)
+ return;
+-
++
+ /* Add addresses */
+ for (i = 0; i < dev->mc_count; i++) {
+ addrs = dmi->dmi_addr;
+@@ -1318,14 +1318,14 @@ static u32 sparc_lance_get_link(struct n
+ return 1;
+ }
+
+-static struct ethtool_ops sparc_lance_ethtool_ops = {
++static const struct ethtool_ops sparc_lance_ethtool_ops = {
+ .get_drvinfo = sparc_lance_get_drvinfo,
+ .get_link = sparc_lance_get_link,
+ };
+
+-static int __init sparc_lance_probe_one(struct sbus_dev *sdev,
+- struct sbus_dma *ledma,
+- struct sbus_dev *lebuffer)
++static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
++ struct sbus_dma *ledma,
++ struct sbus_dev *lebuffer)
+ {
+ static unsigned version_printed;
+ struct net_device *dev;
+@@ -1515,7 +1515,7 @@ fail:
+ }
+
+ /* On 4m, find the associated dma for the lance chip */
+-static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
++static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
+ {
+ struct sbus_dma *p;
+
+@@ -1533,7 +1533,7 @@ static inline struct sbus_dma *find_ledm
+
+ /* Find all the lance cards on the system and initialize them */
+ static struct sbus_dev sun4_sdev;
+-static int __init sparc_lance_init(void)
++static int __devinit sparc_lance_init(void)
+ {
+ if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
+ (idprom->id_machtype == (SM_SUN4|SM_4_470))) {
+diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
+index 817a40b..7874eb1 100644
+--- a/drivers/net/sunqe.c
++++ b/drivers/net/sunqe.c
+@@ -451,7 +451,7 @@ static void qe_rx(struct sunqe *qep)
+ }
+ end_rxd->rx_addr = this_qbuf_dvma;
+ end_rxd->rx_flags = (RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
+-
++
+ elem = NEXT_RX(elem);
+ this = &rxbase[elem];
+ }
+@@ -466,9 +466,9 @@ static void qe_tx_reclaim(struct sunqe *
+ * so we just run through each qe and check to see who is signaling
+ * and thus needs to be serviced.
+ */
+-static irqreturn_t qec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t qec_interrupt(int irq, void *dev_id)
+ {
+- struct sunqec *qecp = (struct sunqec *) dev_id;
++ struct sunqec *qecp = dev_id;
+ u32 qec_status;
+ int channel = 0;
+
+@@ -718,7 +718,7 @@ static u32 qe_get_link(struct net_device
+ return (phyconfig & MREGS_PHYCONFIG_LSTAT);
+ }
+
+-static struct ethtool_ops qe_ethtool_ops = {
++static const struct ethtool_ops qe_ethtool_ops = {
+ .get_drvinfo = qe_get_drvinfo,
+ .get_link = qe_get_link,
+ };
+@@ -858,7 +858,7 @@ static int __init qec_ether_init(struct
+ }
+ qe->channel = i;
+ spin_lock_init(&qe->lock);
+-
++
+ res = -ENODEV;
+ qecp = get_qec(sdev);
+ if (!qecp)
+diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
+index 8b53ded..81ed82f 100644
+--- a/drivers/net/tc35815.c
++++ b/drivers/net/tc35815.c
+@@ -1,7 +1,7 @@
+ /* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
++ * Author: MontaVista Software, Inc.
+ * ahennessy at mvista.com
+ *
+ * Based on skelton.c by Donald Becker.
+@@ -453,7 +453,7 @@ static int __devinit tc35815_probe1(stru
+ static int tc35815_open(struct net_device *dev);
+ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+ static void tc35815_tx_timeout(struct net_device *dev);
+-static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+ static void tc35815_rx(struct net_device *dev);
+ static void tc35815_txdone(struct net_device *dev);
+ static int tc35815_close(struct net_device *dev);
+@@ -663,7 +663,7 @@ tc35815_init_queues(struct net_device *d
+ #endif
+ }
+ #ifdef __mips__
+- fd_addr = (unsigned long)vtonocache(lp->fd_buf);
++ fd_addr = (unsigned long)vtonocache(lp->fd_buf);
+ #else
+ fd_addr = (unsigned long)lp->fd_buf;
+ #endif
+@@ -1044,7 +1044,7 @@ static void tc35815_fatal_error_interrup
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+-static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct tc35815_regs *tr;
+@@ -1136,7 +1136,7 @@ tc35815_rx(struct net_device *dev)
+ int cur_bd, offset;
+
+ lp->stats.rx_bytes += pkt_len;
+-
++
+ skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+@@ -1523,7 +1523,7 @@ static unsigned long tc_phy_read(struct
+ struct tc35815_local *lp = dev->priv;
+ unsigned long data;
+ unsigned long flags;
+-
++
+ spin_lock_irqsave(&lp->lock, flags);
+
+ tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+@@ -1725,7 +1725,7 @@ static struct pci_driver tc35815_driver
+
+ static int __init tc35815_init_module(void)
+ {
+- return pci_module_init(&tc35815_driver);
++ return pci_register_driver(&tc35815_driver);
+ }
+
+ static void __exit tc35815_cleanup_module(void)
+diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
+index eafabb2..8f059b7 100644
+--- a/drivers/net/tg3.c
++++ b/drivers/net/tg3.c
+@@ -68,8 +68,8 @@
+
+ #define DRV_MODULE_NAME "tg3"
+ #define PFX DRV_MODULE_NAME ": "
+-#define DRV_MODULE_VERSION "3.65"
+-#define DRV_MODULE_RELDATE "August 07, 2006"
++#define DRV_MODULE_VERSION "3.68"
++#define DRV_MODULE_RELDATE "November 02, 2006"
+
+ #define TG3_DEF_MAC_MODE 0
+ #define TG3_DEF_RX_MODE 0
+@@ -129,7 +129,7 @@
+ #define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64)
+
+ /* minimum number of free TX descriptors required to wake up TX process */
+-#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4)
++#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4)
+
+ /* number of ETHTOOL_GSTATS u64's */
+ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64))
+@@ -149,122 +149,71 @@ module_param(tg3_debug, int, 0);
+ MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
+
+ static struct pci_device_id tg3_pci_tbl[] = {
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+- { 0, }
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5756)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
++ {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
++ {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)},
++ {PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)},
++ {}
+ };
+
+ MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
+
+-static struct {
++static const struct {
+ const char string[ETH_GSTRING_LEN];
+ } ethtool_stats_keys[TG3_NUM_STATS] = {
+ { "rx_octets" },
+@@ -345,7 +294,7 @@ static struct {
+ { "nic_tx_threshold_hit" }
+ };
+
+-static struct {
++static const struct {
+ const char string[ETH_GSTRING_LEN];
+ } ethtool_test_keys[TG3_NUM_TEST] = {
+ { "nvram test (online) " },
+@@ -363,7 +312,7 @@ static void tg3_write32(struct tg3 *tp,
+
+ static u32 tg3_read32(struct tg3 *tp, u32 off)
+ {
+- return (readl(tp->regs + off));
++ return (readl(tp->regs + off));
+ }
+
+ static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
+@@ -479,6 +428,16 @@ static void tg3_write32_tx_mbox(struct t
+ readl(mbox);
+ }
+
++static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off)
++{
++ return (readl(tp->regs + off + GRCMBOX_BASE));
++}
++
++static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
++{
++ writel(val, tp->regs + off + GRCMBOX_BASE);
++}
++
+ #define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val)
+ #define tw32_mailbox_f(reg, val) tw32_mailbox_flush(tp, (reg), (val))
+ #define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val)
+@@ -494,6 +453,10 @@ static void tg3_write_mem(struct tg3 *tp
+ {
+ unsigned long flags;
+
++ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
++ (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
++ return;
++
+ spin_lock_irqsave(&tp->indirect_lock, flags);
+ if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+@@ -515,6 +478,12 @@ static void tg3_read_mem(struct tg3 *tp,
+ {
+ unsigned long flags;
+
++ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
++ (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
++ *val = 0;
++ return;
++ }
++
+ spin_lock_irqsave(&tp->indirect_lock, flags);
+ if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+@@ -544,6 +513,9 @@ static inline void tg3_cond_int(struct t
+ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
+ (tp->hw_status->status & SD_STATUS_UPDATED))
+ tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
++ else
++ tw32(HOSTCC_MODE, tp->coalesce_mode |
++ (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
+ }
+
+ static void tg3_enable_ints(struct tg3 *tp)
+@@ -584,7 +556,7 @@ static inline unsigned int tg3_has_work(
+ /* tg3_restart_ints
+ * similar to tg3_enable_ints, but it accurately determines whether there
+ * is new work pending and can return without flushing the PIO write
+- * which reenables interrupts
++ * which reenables interrupts
+ */
+ static void tg3_restart_ints(struct tg3 *tp)
+ {
+@@ -673,7 +645,7 @@ static int tg3_readphy(struct tg3 *tp, i
+ frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+ MI_COM_REG_ADDR_MASK);
+ frame_val |= (MI_COM_CMD_READ | MI_COM_START);
+-
++
+ tw32_f(MAC_MI_COM, frame_val);
+
+ loops = PHY_BUSY_LOOPS;
+@@ -709,6 +681,10 @@ static int tg3_writephy(struct tg3 *tp,
+ unsigned int loops;
+ int ret;
+
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
++ (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
++ return 0;
++
+ if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+ tw32_f(MAC_MI_MODE,
+ (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+@@ -721,7 +697,7 @@ static int tg3_writephy(struct tg3 *tp,
+ MI_COM_REG_ADDR_MASK);
+ frame_val |= (val & MI_COM_DATA_MASK);
+ frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
+-
++
+ tw32_f(MAC_MI_COM, frame_val);
+
+ loops = PHY_BUSY_LOOPS;
+@@ -1059,6 +1035,24 @@ out:
+ phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
+ }
+
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ u32 phy_reg;
++
++ /* adjust output voltage */
++ tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12);
++
++ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phy_reg)) {
++ u32 phy_reg2;
++
++ tg3_writephy(tp, MII_TG3_EPHY_TEST,
++ phy_reg | MII_TG3_EPHY_SHADOW_EN);
++ /* Enable auto-MDIX */
++ if (!tg3_readphy(tp, 0x10, &phy_reg2))
++ tg3_writephy(tp, 0x10, phy_reg2 | 0x4000);
++ tg3_writephy(tp, MII_TG3_EPHY_TEST, phy_reg);
++ }
++ }
++
+ tg3_phy_set_wirespeed(tp);
+ return 0;
+ }
+@@ -1172,6 +1166,15 @@ static void tg3_nvram_unlock(struct tg3
+
+ static void tg3_power_down_phy(struct tg3 *tp)
+ {
++ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
++ return;
++
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
++ tg3_writephy(tp, MII_TG3_EXT_CTRL,
++ MII_TG3_EXT_CTRL_FORCE_LED_OFF);
++ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
++ }
++
+ /* The PHY should not be powered down on some chips because
+ * of bugs.
+ */
+@@ -1254,7 +1257,12 @@ static int tg3_set_power_state(struct tg
+ tg3_setup_phy(tp, 0);
+ }
+
+- if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ u32 val;
++
++ val = tr32(GRC_VCPU_EXT_CTRL);
++ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL);
++ } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+ int i;
+ u32 val;
+
+@@ -1278,7 +1286,10 @@ static int tg3_set_power_state(struct tg
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+ udelay(40);
+
+- mac_mode = MAC_MODE_PORT_MODE_MII;
++ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
++ mac_mode = MAC_MODE_PORT_MODE_GMII;
++ else
++ mac_mode = MAC_MODE_PORT_MODE_MII;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
+ !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
+@@ -1356,15 +1367,8 @@ static int tg3_set_power_state(struct tg
+ }
+
+ if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
+- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+- /* Turn off the PHY */
+- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+- tg3_writephy(tp, MII_TG3_EXT_CTRL,
+- MII_TG3_EXT_CTRL_FORCE_LED_OFF);
+- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
+- tg3_power_down_phy(tp);
+- }
+- }
++ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
++ tg3_power_down_phy(tp);
+
+ tg3_frob_aux_power(tp);
+
+@@ -1477,7 +1481,7 @@ static void tg3_setup_flow_control(struc
+ if (old_rx_mode != tp->rx_mode) {
+ tw32_f(MAC_RX_MODE, tp->rx_mode);
+ }
+-
++
+ if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
+ tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+ else
+@@ -1522,6 +1526,13 @@ static void tg3_aux_stat_to_speed_duplex
+ break;
+
+ default:
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
++ SPEED_10;
++ *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
++ DUPLEX_HALF;
++ break;
++ }
+ *speed = SPEED_INVALID;
+ *duplex = DUPLEX_INVALID;
+ break;
+@@ -1804,7 +1815,7 @@ static int tg3_setup_copper_phy(struct t
+
+ if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
+ tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
+- else
++ else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+ tg3_writephy(tp, MII_TG3_IMASK, ~0);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+@@ -2461,24 +2472,27 @@ static int tg3_setup_fiber_hw_autoneg(st
+ expected_sg_dig_ctrl |= (1 << 12);
+
+ if (sg_dig_ctrl != expected_sg_dig_ctrl) {
++ if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
++ tp->serdes_counter &&
++ ((mac_status & (MAC_STATUS_PCS_SYNCED |
++ MAC_STATUS_RCVD_CFG)) ==
++ MAC_STATUS_PCS_SYNCED)) {
++ tp->serdes_counter--;
++ current_link_up = 1;
++ goto out;
++ }
++restart_autoneg:
+ if (workaround)
+ tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
+ tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+ udelay(5);
+ tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
+
+- tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
++ tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
++ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ } else if (mac_status & (MAC_STATUS_PCS_SYNCED |
+ MAC_STATUS_SIGNAL_DET)) {
+- int i;
+-
+- /* Giver time to negotiate (~200ms) */
+- for (i = 0; i < 40000; i++) {
+- sg_dig_status = tr32(SG_DIG_STATUS);
+- if (sg_dig_status & (0x3))
+- break;
+- udelay(5);
+- }
++ sg_dig_status = tr32(SG_DIG_STATUS);
+ mac_status = tr32(MAC_STATUS);
+
+ if ((sg_dig_status & (1 << 1)) &&
+@@ -2494,10 +2508,11 @@ static int tg3_setup_fiber_hw_autoneg(st
+
+ tg3_setup_flow_control(tp, local_adv, remote_adv);
+ current_link_up = 1;
+- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
++ tp->serdes_counter = 0;
++ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ } else if (!(sg_dig_status & (1 << 1))) {
+- if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED)
+- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
++ if (tp->serdes_counter)
++ tp->serdes_counter--;
+ else {
+ if (workaround) {
+ u32 val = serdes_cfg;
+@@ -2521,9 +2536,17 @@ static int tg3_setup_fiber_hw_autoneg(st
+ !(mac_status & MAC_STATUS_RCVD_CFG)) {
+ tg3_setup_flow_control(tp, 0, 0);
+ current_link_up = 1;
+- }
++ tp->tg3_flags2 |=
++ TG3_FLG2_PARALLEL_DETECT;
++ tp->serdes_counter =
++ SERDES_PARALLEL_DET_TIMEOUT;
++ } else
++ goto restart_autoneg;
+ }
+ }
++ } else {
++ tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
++ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ }
+
+ out:
+@@ -2542,7 +2565,7 @@ static int tg3_setup_fiber_by_hand(struc
+ if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ u32 flags;
+ int i;
+-
++
+ if (fiber_autoneg(tp, &flags)) {
+ u32 local_adv, remote_adv;
+
+@@ -2654,14 +2677,16 @@ static int tg3_setup_fiber_phy(struct tg
+ MAC_STATUS_CFG_CHANGED));
+ udelay(5);
+ if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
+- MAC_STATUS_CFG_CHANGED)) == 0)
++ MAC_STATUS_CFG_CHANGED |
++ MAC_STATUS_LNKSTATE_CHANGED)) == 0)
+ break;
+ }
+
+ mac_status = tr32(MAC_STATUS);
+ if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
+ current_link_up = 0;
+- if (tp->link_config.autoneg == AUTONEG_ENABLE) {
++ if (tp->link_config.autoneg == AUTONEG_ENABLE &&
++ tp->serdes_counter == 0) {
+ tw32_f(MAC_MODE, (tp->mac_mode |
+ MAC_MODE_SEND_CONFIGS));
+ udelay(1);
+@@ -2766,7 +2791,7 @@ static int tg3_setup_fiber_mii_phy(struc
+ tg3_writephy(tp, MII_BMCR, bmcr);
+
+ tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+- tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
++ tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+
+ return err;
+@@ -2871,9 +2896,9 @@ static int tg3_setup_fiber_mii_phy(struc
+
+ static void tg3_serdes_parallel_detect(struct tg3 *tp)
+ {
+- if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) {
++ if (tp->serdes_counter) {
+ /* Give autoneg time to complete. */
+- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
++ tp->serdes_counter--;
+ return;
+ }
+ if (!netif_carrier_ok(tp->dev) &&
+@@ -3050,10 +3075,10 @@ static void tg3_tx(struct tg3 *tp)
+ smp_mb();
+
+ if (unlikely(netif_queue_stopped(tp->dev) &&
+- (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) {
++ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) {
+ netif_tx_lock(tp->dev);
+ if (netif_queue_stopped(tp->dev) &&
+- (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))
++ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))
+ netif_wake_queue(tp->dev);
+ netif_tx_unlock(tp->dev);
+ }
+@@ -3258,7 +3283,7 @@ static int tg3_rx(struct tg3 *tp, int bu
+
+ len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
+
+- if (len > RX_COPY_THRESHOLD
++ if (len > RX_COPY_THRESHOLD
+ && tp->rx_offset == 2
+ /* rx_offset != 2 iff this is a 5701 card running
+ * in PCI-X mode [see tg3_get_invariants()] */
+@@ -3456,7 +3481,7 @@ static inline void tg3_full_unlock(struc
+ /* One-shot MSI handler - Chip automatically disables interrupt
+ * after sending MSI so driver doesn't have to do it.
+ */
+-static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tg3_msi_1shot(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct tg3 *tp = netdev_priv(dev);
+@@ -3474,7 +3499,7 @@ static irqreturn_t tg3_msi_1shot(int irq
+ * flush status block and interrupt mailbox. PCI ordering rules
+ * guarantee that MSI will arrive after the status block.
+ */
+-static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tg3_msi(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct tg3 *tp = netdev_priv(dev);
+@@ -3495,7 +3520,7 @@ static irqreturn_t tg3_msi(int irq, void
+ return IRQ_RETVAL(1);
+ }
+
+-static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tg3_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct tg3 *tp = netdev_priv(dev);
+@@ -3538,7 +3563,7 @@ out:
+ return IRQ_RETVAL(handled);
+ }
+
+-static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct tg3 *tp = netdev_priv(dev);
+@@ -3581,8 +3606,7 @@ out:
+ }
+
+ /* ISR for interrupt test */
+-static irqreturn_t tg3_test_isr(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t tg3_test_isr(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct tg3 *tp = netdev_priv(dev);
+@@ -3590,8 +3614,7 @@ static irqreturn_t tg3_test_isr(int irq,
+
+ if ((sblk->status & SD_STATUS_UPDATED) ||
+ !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
+- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+- 0x00000001);
++ tg3_disable_ints(tp);
+ return IRQ_RETVAL(1);
+ }
+ return IRQ_RETVAL(0);
+@@ -3627,7 +3650,7 @@ static void tg3_poll_controller(struct n
+ {
+ struct tg3 *tp = netdev_priv(dev);
+
+- tg3_interrupt(tp->pdev->irq, dev, NULL);
++ tg3_interrupt(tp->pdev->irq, dev);
+ }
+ #endif
+
+@@ -3851,11 +3874,11 @@ static int tg3_start_xmit(struct sk_buff
+ skb->h.th->check = 0;
+
+ }
+- else if (skb->ip_summed == CHECKSUM_HW)
++ else if (skb->ip_summed == CHECKSUM_PARTIAL)
+ base_flags |= TXD_FLAG_TCPUDP_CSUM;
+ #else
+ mss = 0;
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ base_flags |= TXD_FLAG_TCPUDP_CSUM;
+ #endif
+ #if TG3_VLAN_TAG_USED
+@@ -3905,7 +3928,7 @@ static int tg3_start_xmit(struct sk_buff
+ tp->tx_prod = entry;
+ if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
+ netif_stop_queue(dev);
+- if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
++ if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
+ netif_wake_queue(tp->dev);
+ }
+
+@@ -3981,7 +4004,7 @@ static int tg3_start_xmit_dma_bug(struct
+
+ entry = tp->tx_prod;
+ base_flags = 0;
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ base_flags |= TXD_FLAG_TCPUDP_CSUM;
+ #if TG3_TSO_SUPPORT != 0
+ mss = 0;
+@@ -4120,7 +4143,7 @@ static int tg3_start_xmit_dma_bug(struct
+ tp->tx_prod = entry;
+ if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
+ netif_stop_queue(dev);
+- if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
++ if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
+ netif_wake_queue(tp->dev);
+ }
+
+@@ -4699,6 +4722,44 @@ static void tg3_write_sig_legacy(struct
+ }
+ }
+
++static int tg3_poll_fw(struct tg3 *tp)
++{
++ int i;
++ u32 val;
++
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ for (i = 0; i < 400; i++) {
++ if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
++ return 0;
++ udelay(10);
++ }
++ return -ENODEV;
++ }
++
++ /* Wait for firmware initialization to complete. */
++ for (i = 0; i < 100000; i++) {
++ tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
++ if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
++ break;
++ udelay(10);
++ }
++
++ /* Chip might not be fitted with firmware. Some Sun onboard
++ * parts are configured like that. So don't signal the timeout
++ * of the above loop as an error, but do report the lack of
++ * running firmware once.
++ */
++ if (i >= 100000 &&
++ !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
++ tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
++
++ printk(KERN_INFO PFX "%s: No firmware running.\n",
++ tp->dev->name);
++ }
++
++ return 0;
++}
++
+ static void tg3_stop_fw(struct tg3 *);
+
+ /* tp->lock is held. */
+@@ -4706,7 +4767,7 @@ static int tg3_chip_reset(struct tg3 *tp
+ {
+ u32 val;
+ void (*write_op)(struct tg3 *, u32, u32);
+- int i;
++ int err;
+
+ tg3_nvram_lock(tp);
+
+@@ -4743,6 +4804,12 @@ static int tg3_chip_reset(struct tg3 *tp
+ }
+ }
+
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
++ tw32(GRC_VCPU_EXT_CTRL,
++ tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
++ }
++
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
+ tw32(GRC_MISC_CFG, val);
+@@ -4866,26 +4933,9 @@ static int tg3_chip_reset(struct tg3 *tp
+ tw32_f(MAC_MODE, 0);
+ udelay(40);
+
+- /* Wait for firmware initialization to complete. */
+- for (i = 0; i < 100000; i++) {
+- tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+- if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+- break;
+- udelay(10);
+- }
+-
+- /* Chip might not be fitted with firmare. Some Sun onboard
+- * parts are configured like that. So don't signal the timeout
+- * of the above loop as an error, but do report the lack of
+- * running firmware once.
+- */
+- if (i >= 100000 &&
+- !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
+- tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
+-
+- printk(KERN_INFO PFX "%s: No firmware running.\n",
+- tp->dev->name);
+- }
++ err = tg3_poll_fw(tp);
++ if (err)
++ return err;
+
+ if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+ tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
+@@ -4969,7 +5019,7 @@ static int tg3_halt(struct tg3 *tp, int
+ #define TG3_FW_BSS_ADDR 0x08000a70
+ #define TG3_FW_BSS_LEN 0x10
+
+-static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
++static const u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
+ 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
+ 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000,
+ 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034,
+@@ -5063,7 +5113,7 @@ static u32 tg3FwText[(TG3_FW_TEXT_LEN /
+ 0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000
+ };
+
+-static u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
++static const u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
+ 0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430,
+ 0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
+@@ -5091,6 +5141,12 @@ static int tg3_halt_cpu(struct tg3 *tp,
+ BUG_ON(offset == TX_CPU_BASE &&
+ (tp->tg3_flags2 & TG3_FLG2_5705_PLUS));
+
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ u32 val = tr32(GRC_VCPU_EXT_CTRL);
++
++ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
++ return 0;
++ }
+ if (offset == RX_CPU_BASE) {
+ for (i = 0; i < 10000; i++) {
+ tw32(offset + CPU_STATE, 0xffffffff);
+@@ -5128,13 +5184,13 @@ static int tg3_halt_cpu(struct tg3 *tp,
+ struct fw_info {
+ unsigned int text_base;
+ unsigned int text_len;
+- u32 *text_data;
++ const u32 *text_data;
+ unsigned int rodata_base;
+ unsigned int rodata_len;
+- u32 *rodata_data;
++ const u32 *rodata_data;
+ unsigned int data_base;
+ unsigned int data_len;
+- u32 *data_data;
++ const u32 *data_data;
+ };
+
+ /* tp->lock is held. */
+@@ -5266,7 +5322,7 @@ static int tg3_load_5701_a0_firmware_fix
+ #define TG3_TSO_FW_BSS_ADDR 0x08001b80
+ #define TG3_TSO_FW_BSS_LEN 0x894
+
+-static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
++static const u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
+ 0x0e000003, 0x00000000, 0x08001b24, 0x00000000, 0x10000003, 0x00000000,
+ 0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd4000, 0x03a0f021, 0x3c100800,
+ 0x26100000, 0x0e000010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
+@@ -5553,7 +5609,7 @@ static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT
+ 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000,
+ };
+
+-static u32 tg3TsoFwRodata[] = {
++static const u32 tg3TsoFwRodata[] = {
+ 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
+ 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f,
+ 0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000,
+@@ -5561,7 +5617,7 @@ static u32 tg3TsoFwRodata[] = {
+ 0x00000000,
+ };
+
+-static u32 tg3TsoFwData[] = {
++static const u32 tg3TsoFwData[] = {
+ 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000,
+@@ -5583,7 +5639,7 @@ static u32 tg3TsoFwData[] = {
+ #define TG3_TSO5_FW_BSS_ADDR 0x00010f50
+ #define TG3_TSO5_FW_BSS_LEN 0x88
+
+-static u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
++static const u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
+ 0x0c004003, 0x00000000, 0x00010f04, 0x00000000, 0x10000003, 0x00000000,
+ 0x0000000d, 0x0000000d, 0x3c1d0001, 0x37bde000, 0x03a0f021, 0x3c100001,
+ 0x26100000, 0x0c004010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
+@@ -5742,14 +5798,14 @@ static u32 tg3Tso5FwText[(TG3_TSO5_FW_TE
+ 0x00000000, 0x00000000, 0x00000000,
+ };
+
+-static u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
++static const u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
+ 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
+ 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000,
+ 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
+ 0x00000000, 0x00000000, 0x00000000,
+ };
+
+-static u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
++static const u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
+ 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000,
+ };
+@@ -5958,7 +6014,7 @@ static int tg3_reset_hw(struct tg3 *tp,
+ tg3_abort_hw(tp, 1);
+ }
+
+- if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) && reset_phy)
++ if (reset_phy)
+ tg3_phy_reset(tp);
+
+ err = tg3_chip_reset(tp);
+@@ -6095,6 +6151,13 @@ static int tg3_reset_hw(struct tg3 *tp,
+ val = 1;
+ else if (val > tp->rx_std_max_post)
+ val = tp->rx_std_max_post;
++ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
++ tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
++
++ if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2))
++ val = TG3_RX_INTERNAL_RING_SZ_5906 / 2;
++ }
+
+ tw32(RCVBDI_STD_THRESH, val);
+
+@@ -6511,11 +6574,12 @@ static int tg3_reset_hw(struct tg3 *tp,
+ tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+ }
+
+- err = tg3_setup_phy(tp, reset_phy);
++ err = tg3_setup_phy(tp, 0);
+ if (err)
+ return err;
+
+- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
++ if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
++ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+ u32 tmp;
+
+ /* Clear CRC stats. */
+@@ -6715,12 +6779,14 @@ static void tg3_timer(unsigned long __op
+ need_setup = 1;
+ }
+ if (need_setup) {
+- tw32_f(MAC_MODE,
+- (tp->mac_mode &
+- ~MAC_MODE_PORT_MODE_MASK));
+- udelay(40);
+- tw32_f(MAC_MODE, tp->mac_mode);
+- udelay(40);
++ if (!tp->serdes_counter) {
++ tw32_f(MAC_MODE,
++ (tp->mac_mode &
++ ~MAC_MODE_PORT_MODE_MASK));
++ udelay(40);
++ tw32_f(MAC_MODE, tp->mac_mode);
++ udelay(40);
++ }
+ tg3_setup_phy(tp, 0);
+ }
+ } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+@@ -6729,13 +6795,29 @@ static void tg3_timer(unsigned long __op
+ tp->timer_counter = tp->timer_multiplier;
+ }
+
+- /* Heartbeat is only sent once every 2 seconds. */
++ /* Heartbeat is only sent once every 2 seconds.
++ *
++ * The heartbeat is to tell the ASF firmware that the host
++ * driver is still alive. In the event that the OS crashes,
++ * ASF needs to reset the hardware to free up the FIFO space
++ * that may be filled with rx packets destined for the host.
++ * If the FIFO is full, ASF will no longer function properly.
++ *
++ * Unintended resets have been reported on real time kernels
++ * where the timer doesn't run on time. Netpoll will also have
++ * same problem.
++ *
++ * The new FWCMD_NICDRV_ALIVE3 command tells the ASF firmware
++ * to check the ring condition when the heartbeat is expiring
++ * before doing the reset. This will prevent most unintended
++ * resets.
++ */
+ if (!--tp->asf_counter) {
+ if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ u32 val;
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
+- FWCMD_NICDRV_ALIVE2);
++ FWCMD_NICDRV_ALIVE3);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+ /* 5 seconds timeout */
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
+@@ -6755,7 +6837,7 @@ restart_timer:
+
+ static int tg3_request_irq(struct tg3 *tp)
+ {
+- irqreturn_t (*fn)(int, void *, struct pt_regs *);
++ irq_handler_t fn;
+ unsigned long flags;
+ struct net_device *dev = tp->dev;
+
+@@ -6776,8 +6858,7 @@ static int tg3_request_irq(struct tg3 *t
+ static int tg3_test_interrupt(struct tg3 *tp)
+ {
+ struct net_device *dev = tp->dev;
+- int err, i;
+- u32 int_mbox = 0;
++ int err, i, intr_ok = 0;
+
+ if (!netif_running(dev))
+ return -ENODEV;
+@@ -6798,23 +6879,31 @@ static int tg3_test_interrupt(struct tg3
+ HOSTCC_MODE_NOW);
+
+ for (i = 0; i < 5; i++) {
++ u32 int_mbox, misc_host_ctrl;
++
+ int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 +
+ TG3_64BIT_REG_LOW);
+- if (int_mbox != 0)
++ misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
++
++ if ((int_mbox != 0) ||
++ (misc_host_ctrl & MISC_HOST_CTRL_MASK_PCI_INT)) {
++ intr_ok = 1;
+ break;
++ }
++
+ msleep(10);
+ }
+
+ tg3_disable_ints(tp);
+
+ free_irq(tp->pdev->irq, dev);
+-
++
+ err = tg3_request_irq(tp);
+
+ if (err)
+ return err;
+
+- if (int_mbox != 0)
++ if (intr_ok)
+ return 0;
+
+ return -EIO;
+@@ -6991,9 +7080,10 @@ static int tg3_open(struct net_device *d
+
+ if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+ if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) {
+- u32 val = tr32(0x7c04);
++ u32 val = tr32(PCIE_TRANSACTION_CFG);
+
+- tw32(0x7c04, val | (1 << 29));
++ tw32(PCIE_TRANSACTION_CFG,
++ val | PCIE_TRANS_CFG_1SHOT_MSI);
+ }
+ }
+ }
+@@ -7435,7 +7525,7 @@ static struct net_device_stats *tg3_get_
+ get_stat64(&hw_stats->rx_ucast_packets) +
+ get_stat64(&hw_stats->rx_mcast_packets) +
+ get_stat64(&hw_stats->rx_bcast_packets);
+-
++
+ stats->tx_packets = old_stats->tx_packets +
+ get_stat64(&hw_stats->tx_ucast_packets) +
+ get_stat64(&hw_stats->tx_mcast_packets) +
+@@ -7743,7 +7833,7 @@ static int tg3_get_eeprom(struct net_dev
+ return 0;
+ }
+
+-static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf);
++static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf);
+
+ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
+ {
+@@ -7807,7 +7897,7 @@ static int tg3_set_eeprom(struct net_dev
+ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ cmd->supported = (SUPPORTED_Autoneg);
+
+ if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+@@ -7825,7 +7915,7 @@ static int tg3_get_settings(struct net_d
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ }
+-
++
+ cmd->advertising = tp->link_config.advertising;
+ if (netif_running(dev)) {
+ cmd->speed = tp->link_config.active_speed;
+@@ -7838,12 +7928,12 @@ static int tg3_get_settings(struct net_d
+ cmd->maxrxpkt = 0;
+ return 0;
+ }
+-
++
+ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
+- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
++
++ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+ /* These are the only valid advertisement bits allowed. */
+ if (cmd->autoneg == AUTONEG_ENABLE &&
+ (cmd->advertising & ~(ADVERTISED_1000baseT_Half |
+@@ -7875,69 +7965,69 @@ static int tg3_set_settings(struct net_d
+ tp->link_config.speed = cmd->speed;
+ tp->link_config.duplex = cmd->duplex;
+ }
+-
++
+ if (netif_running(dev))
+ tg3_setup_phy(tp, 1);
+
+ tg3_full_unlock(tp);
+-
++
+ return 0;
+ }
+-
++
+ static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ strcpy(info->driver, DRV_MODULE_NAME);
+ strcpy(info->version, DRV_MODULE_VERSION);
+ strcpy(info->fw_version, tp->fw_ver);
+ strcpy(info->bus_info, pci_name(tp->pdev));
+ }
+-
++
+ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = 0;
+ if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+ wol->wolopts = WAKE_MAGIC;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+ }
+-
++
+ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+ if ((wol->wolopts & WAKE_MAGIC) &&
+- tp->tg3_flags2 & TG3_FLG2_PHY_SERDES &&
++ tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
+ !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+ return -EINVAL;
+-
++
+ 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_bh(&tp->lock);
+-
++
+ return 0;
+ }
+-
++
+ static u32 tg3_get_msglevel(struct net_device *dev)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+ return tp->msg_enable;
+ }
+-
++
+ static void tg3_set_msglevel(struct net_device *dev, u32 value)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+ tp->msg_enable = value;
+ }
+-
++
+ #if TG3_TSO_SUPPORT != 0
+ static int tg3_set_tso(struct net_device *dev, u32 value)
+ {
+@@ -7948,7 +8038,8 @@ static int tg3_set_tso(struct net_device
+ return -EINVAL;
+ return 0;
+ }
+- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) {
++ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
++ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
+ if (value)
+ dev->features |= NETIF_F_TSO6;
+ else
+@@ -7957,13 +8048,13 @@ static int tg3_set_tso(struct net_device
+ return ethtool_op_set_tso(dev, value);
+ }
+ #endif
+-
++
+ static int tg3_nway_reset(struct net_device *dev)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+ u32 bmcr;
+ int r;
+-
++
+ if (!netif_running(dev))
+ return -EAGAIN;
+
+@@ -7981,14 +8072,14 @@ static int tg3_nway_reset(struct net_dev
+ r = 0;
+ }
+ spin_unlock_bh(&tp->lock);
+-
++
+ return r;
+ }
+-
++
+ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
+ ering->rx_mini_max_pending = 0;
+ if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
+@@ -8007,24 +8098,27 @@ static void tg3_get_ringparam(struct net
+
+ ering->tx_pending = tp->tx_pending;
+ }
+-
++
+ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+ int irq_sync = 0, err = 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))
++ (ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
++ (ering->tx_pending <= MAX_SKB_FRAGS) ||
++ ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) &&
++ (ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
+ return -EINVAL;
+-
++
+ if (netif_running(dev)) {
+ tg3_netif_stop(tp);
+ irq_sync = 1;
+ }
+
+ tg3_full_lock(tp, irq_sync);
+-
++
+ tp->rx_pending = ering->rx_pending;
+
+ if ((tp->tg3_flags2 & TG3_FLG2_MAX_RXPEND_64) &&
+@@ -8041,24 +8135,24 @@ static int tg3_set_ringparam(struct net_
+ }
+
+ tg3_full_unlock(tp);
+-
++
+ return err;
+ }
+-
++
+ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
+ epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
+ epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
+ }
+-
++
+ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+ int irq_sync = 0, err = 0;
+-
++
+ if (netif_running(dev)) {
+ tg3_netif_stop(tp);
+ irq_sync = 1;
+@@ -8087,46 +8181,46 @@ static int tg3_set_pauseparam(struct net
+ }
+
+ tg3_full_unlock(tp);
+-
++
+ return err;
+ }
+-
++
+ static u32 tg3_get_rx_csum(struct net_device *dev)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+ return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
+ }
+-
++
+ static int tg3_set_rx_csum(struct net_device *dev, u32 data)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
+ if (data != 0)
+ return -EINVAL;
+ return 0;
+ }
+-
++
+ spin_lock_bh(&tp->lock);
+ if (data)
+ tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
+ else
+ tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
+ spin_unlock_bh(&tp->lock);
+-
++
+ return 0;
+ }
+-
++
+ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
+ {
+ struct tg3 *tp = netdev_priv(dev);
+-
++
+ if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
+ if (data != 0)
+ return -EINVAL;
+ return 0;
+ }
+-
++
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ ethtool_op_set_tx_hw_csum(dev, data);
+@@ -8181,7 +8275,7 @@ static int tg3_phys_id(struct net_device
+ LED_CTRL_TRAFFIC_OVERRIDE |
+ LED_CTRL_TRAFFIC_BLINK |
+ LED_CTRL_TRAFFIC_LED);
+-
++
+ else
+ tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_TRAFFIC_OVERRIDE);
+@@ -8202,6 +8296,8 @@ static void tg3_get_ethtool_stats (struc
+
+ #define NVRAM_TEST_SIZE 0x100
+ #define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
++#define NVRAM_SELFBOOT_HW_SIZE 0x20
++#define NVRAM_SELFBOOT_DATA_SIZE 0x1c
+
+ static int tg3_test_nvram(struct tg3 *tp)
+ {
+@@ -8213,12 +8309,14 @@ static int tg3_test_nvram(struct tg3 *tp
+
+ if (magic == TG3_EEPROM_MAGIC)
+ size = NVRAM_TEST_SIZE;
+- else if ((magic & 0xff000000) == 0xa5000000) {
++ else if ((magic & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) {
+ if ((magic & 0xe00000) == 0x200000)
+ size = NVRAM_SELFBOOT_FORMAT1_SIZE;
+ else
+ return 0;
+- } else
++ } else if ((magic & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
++ size = NVRAM_SELFBOOT_HW_SIZE;
++ else
+ return -EIO;
+
+ buf = kmalloc(size, GFP_KERNEL);
+@@ -8237,7 +8335,8 @@ static int tg3_test_nvram(struct tg3 *tp
+ goto out;
+
+ /* Selfboot format */
+- if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) {
++ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_FW_MSK) ==
++ TG3_EEPROM_MAGIC_FW) {
+ u8 *buf8 = (u8 *) buf, csum8 = 0;
+
+ for (i = 0; i < size; i++)
+@@ -8252,6 +8351,51 @@ static int tg3_test_nvram(struct tg3 *tp
+ goto out;
+ }
+
++ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_HW_MSK) ==
++ TG3_EEPROM_MAGIC_HW) {
++ u8 data[NVRAM_SELFBOOT_DATA_SIZE];
++ u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
++ u8 *buf8 = (u8 *) buf;
++ int j, k;
++
++ /* Separate the parity bits and the data bytes. */
++ for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
++ if ((i == 0) || (i == 8)) {
++ int l;
++ u8 msk;
++
++ for (l = 0, msk = 0x80; l < 7; l++, msk >>= 1)
++ parity[k++] = buf8[i] & msk;
++ i++;
++ }
++ else if (i == 16) {
++ int l;
++ u8 msk;
++
++ for (l = 0, msk = 0x20; l < 6; l++, msk >>= 1)
++ parity[k++] = buf8[i] & msk;
++ i++;
++
++ for (l = 0, msk = 0x80; l < 8; l++, msk >>= 1)
++ parity[k++] = buf8[i] & msk;
++ i++;
++ }
++ data[j++] = buf8[i];
++ }
++
++ err = -EIO;
++ for (i = 0; i < NVRAM_SELFBOOT_DATA_SIZE; i++) {
++ u8 hw8 = hweight8(data[i]);
++
++ if ((hw8 & 0x1) && parity[i])
++ goto out;
++ else if (!(hw8 & 0x1) && !parity[i])
++ goto out;
++ }
++ err = 0;
++ goto out;
++ }
++
+ /* Bootstrap checksum at offset 0x10 */
+ csum = calc_crc((unsigned char *) buf, 0x10);
+ if(csum != cpu_to_le32(buf[0x10/4]))
+@@ -8298,7 +8442,7 @@ static int tg3_test_link(struct tg3 *tp)
+ /* Only test the commonly used registers */
+ static int tg3_test_registers(struct tg3 *tp)
+ {
+- int i, is_5705;
++ int i, is_5705, is_5750;
+ u32 offset, read_mask, write_mask, val, save_val, read_val;
+ static struct {
+ u16 offset;
+@@ -8306,6 +8450,7 @@ static int tg3_test_registers(struct tg3
+ #define TG3_FL_5705 0x1
+ #define TG3_FL_NOT_5705 0x2
+ #define TG3_FL_NOT_5788 0x4
++#define TG3_FL_NOT_5750 0x8
+ u32 read_mask;
+ u32 write_mask;
+ } reg_tbl[] = {
+@@ -8358,7 +8503,7 @@ static int tg3_test_registers(struct tg3
+ 0x00000000, 0xffff0002 },
+ { RCVDBDI_STD_BD+0xc, 0x0000,
+ 0x00000000, 0xffffffff },
+-
++
+ /* Receive BD Initiator Control Registers. */
+ { RCVBDI_STD_THRESH, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+@@ -8366,7 +8511,7 @@ static int tg3_test_registers(struct tg3
+ 0x00000000, 0x000003ff },
+ { RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+-
++
+ /* Host Coalescing Control Registers. */
+ { HOSTCC_MODE, TG3_FL_NOT_5705,
+ 0x00000000, 0x00000004 },
+@@ -8416,9 +8561,9 @@ static int tg3_test_registers(struct tg3
+ 0xffffffff, 0x00000000 },
+
+ /* Buffer Manager Control Registers. */
+- { BUFMGR_MB_POOL_ADDR, 0x0000,
++ { BUFMGR_MB_POOL_ADDR, TG3_FL_NOT_5750,
+ 0x00000000, 0x007fff80 },
+- { BUFMGR_MB_POOL_SIZE, 0x0000,
++ { BUFMGR_MB_POOL_SIZE, TG3_FL_NOT_5750,
+ 0x00000000, 0x007fffff },
+ { BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
+ 0x00000000, 0x0000003f },
+@@ -8430,7 +8575,7 @@ static int tg3_test_registers(struct tg3
+ 0xffffffff, 0x00000000 },
+ { BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705,
+ 0xffffffff, 0x00000000 },
+-
++
+ /* Mailbox Registers */
+ { GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000,
+ 0x00000000, 0x000001ff },
+@@ -8444,10 +8589,12 @@ static int tg3_test_registers(struct tg3
+ { 0xffff, 0x0000, 0x00000000, 0x00000000 },
+ };
+
+- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
++ is_5705 = is_5750 = 0;
++ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ is_5705 = 1;
+- else
+- is_5705 = 0;
++ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
++ is_5750 = 1;
++ }
+
+ for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
+ if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
+@@ -8460,6 +8607,9 @@ static int tg3_test_registers(struct tg3
+ (reg_tbl[i].flags & TG3_FL_NOT_5788))
+ continue;
+
++ if (is_5750 && (reg_tbl[i].flags & TG3_FL_NOT_5750))
++ continue;
++
+ offset = (u32) reg_tbl[i].offset;
+ read_mask = reg_tbl[i].read_mask;
+ write_mask = reg_tbl[i].write_mask;
+@@ -8551,6 +8701,13 @@ static int tg3_test_memory(struct tg3 *t
+ { 0x00008000, 0x02000},
+ { 0x00010000, 0x0c000},
+ { 0xffffffff, 0x00000}
++ }, mem_tbl_5906[] = {
++ { 0x00000200, 0x00008},
++ { 0x00004000, 0x00400},
++ { 0x00006000, 0x00400},
++ { 0x00008000, 0x01000},
++ { 0x00010000, 0x01000},
++ { 0xffffffff, 0x00000}
+ };
+ struct mem_entry *mem_tbl;
+ int err = 0;
+@@ -8560,6 +8717,8 @@ static int tg3_test_memory(struct tg3 *t
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ mem_tbl = mem_tbl_5755;
++ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
++ mem_tbl = mem_tbl_5906;
+ else
+ mem_tbl = mem_tbl_5705;
+ } else
+@@ -8570,7 +8729,7 @@ static int tg3_test_memory(struct tg3 *t
+ mem_tbl[i].len)) != 0)
+ break;
+ }
+-
++
+ return err;
+ }
+
+@@ -8596,13 +8755,41 @@ static int tg3_run_loopback(struct tg3 *
+ return 0;
+
+ mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+- MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
+- MAC_MODE_PORT_MODE_GMII;
++ MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY;
++ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
++ mac_mode |= MAC_MODE_PORT_MODE_MII;
++ else
++ mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ tw32(MAC_MODE, mac_mode);
+ } else if (loopback_mode == TG3_PHY_LOOPBACK) {
+- tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+- BMCR_SPEED1000);
++ u32 val;
++
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ u32 phytest;
++
++ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phytest)) {
++ u32 phy;
++
++ tg3_writephy(tp, MII_TG3_EPHY_TEST,
++ phytest | MII_TG3_EPHY_SHADOW_EN);
++ if (!tg3_readphy(tp, 0x1b, &phy))
++ tg3_writephy(tp, 0x1b, phy & ~0x20);
++ if (!tg3_readphy(tp, 0x10, &phy))
++ tg3_writephy(tp, 0x10, phy & ~0x4000);
++ tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest);
++ }
++ }
++ val = BMCR_LOOPBACK | BMCR_FULLDPLX;
++ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
++ val |= BMCR_SPEED100;
++ else
++ val |= BMCR_SPEED1000;
++
++ tg3_writephy(tp, MII_BMCR, val);
+ udelay(40);
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
++ tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800);
++
+ /* reset to prevent losing 1st rx packet intermittently */
+ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+ tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+@@ -8610,7 +8797,11 @@ static int tg3_run_loopback(struct tg3 *
+ tw32_f(MAC_RX_MODE, tp->rx_mode);
+ }
+ mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+- MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
++ MAC_MODE_LINK_POLARITY;
++ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
++ mac_mode |= MAC_MODE_PORT_MODE_MII;
++ else
++ mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+ mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ tg3_writephy(tp, MII_TG3_EXT_CTRL,
+@@ -8659,7 +8850,8 @@ static int tg3_run_loopback(struct tg3 *
+
+ udelay(10);
+
+- for (i = 0; i < 10; i++) {
++ /* 250 usec to allow enough time on some 10/100 Mbps devices. */
++ for (i = 0; i < 25; i++) {
+ tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
+ HOSTCC_MODE_NOW);
+
+@@ -8705,7 +8897,7 @@ static int tg3_run_loopback(struct tg3 *
+ goto out;
+ }
+ err = 0;
+-
++
+ /* tg3_free_rings will unmap and free the rx_skb */
+ out:
+ return err;
+@@ -8962,7 +9154,7 @@ static int tg3_set_coalesce(struct net_d
+ return 0;
+ }
+
+-static struct ethtool_ops tg3_ethtool_ops = {
++static const struct ethtool_ops tg3_ethtool_ops = {
+ .get_settings = tg3_get_settings,
+ .set_settings = tg3_set_settings,
+ .get_drvinfo = tg3_get_drvinfo,
+@@ -9011,7 +9203,9 @@ static void __devinit tg3_get_eeprom_siz
+ if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
+ return;
+
+- if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000))
++ if ((magic != TG3_EEPROM_MAGIC) &&
++ ((magic & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW) &&
++ ((magic & TG3_EEPROM_MAGIC_HW_MSK) != TG3_EEPROM_MAGIC_HW))
+ return;
+
+ /*
+@@ -9033,7 +9227,7 @@ static void __devinit tg3_get_eeprom_siz
+
+ tp->nvram_size = cursize;
+ }
+-
++
+ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
+ {
+ u32 val;
+@@ -9249,6 +9443,13 @@ static void __devinit tg3_get_5787_nvram
+ }
+ }
+
++static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
++{
++ tp->nvram_jedecnum = JEDEC_ATMEL;
++ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
++ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
++}
++
+ /* Chips other than 5700/5701 use the NVRAM for fetching info. */
+ static void __devinit tg3_nvram_init(struct tg3 *tp)
+ {
+@@ -9285,6 +9486,8 @@ static void __devinit tg3_nvram_init(str
+ tg3_get_5755_nvram_info(tp);
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ tg3_get_5787_nvram_info(tp);
++ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
++ tg3_get_5906_nvram_info(tp);
+ else
+ tg3_get_nvram_info(tp);
+
+@@ -9449,7 +9652,7 @@ static int tg3_nvram_write_block_using_e
+ (addr & EEPROM_ADDR_ADDR_MASK) |
+ EEPROM_ADDR_START |
+ EEPROM_ADDR_WRITE);
+-
++
+ for (j = 0; j < 10000; j++) {
+ val = tr32(GRC_EEPROM_ADDR);
+
+@@ -9485,7 +9688,7 @@ static int tg3_nvram_write_block_unbuffe
+ u32 phy_addr, page_off, size;
+
+ phy_addr = offset & ~pagemask;
+-
++
+ for (j = 0; j < pagesize; j += 4) {
+ if ((ret = tg3_nvram_read(tp, phy_addr + j,
+ (u32 *) (tmp + j))))
+@@ -9758,6 +9961,12 @@ static void __devinit tg3_get_eeprom_hw_
+ /* Assume an onboard device by default. */
+ tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM))
++ tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
++ return;
++ }
++
+ tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
+ if (val == NIC_SRAM_DATA_SIG_MAGIC) {
+ u32 nic_cfg, led_cfg;
+@@ -9941,7 +10150,7 @@ static int __devinit tg3_phy_probe(struc
+ if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+ (bmsr & BMSR_LSTATUS))
+ goto skip_phy_reset;
+-
++
+ err = tg3_phy_reset(tp);
+ if (err)
+ return err;
+@@ -10089,7 +10298,10 @@ static void __devinit tg3_read_partno(st
+ }
+
+ out_not_found:
+- strcpy(tp->board_part_number, "none");
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
++ strcpy(tp->board_part_number, "BCM95906");
++ else
++ strcpy(tp->board_part_number, "none");
+ }
+
+ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
+@@ -10291,6 +10503,7 @@ static int __devinit tg3_get_invariants(
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
+ tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
+
+@@ -10300,7 +10513,8 @@ static int __devinit tg3_get_invariants(
+
+ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
+ tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
+ } else {
+@@ -10317,7 +10531,8 @@ static int __devinit tg3_get_invariants(
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
+- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)
++ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
++ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+ tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
+
+ if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
+@@ -10447,6 +10662,12 @@ static int __devinit tg3_get_invariants(
+ pci_cmd &= ~PCI_COMMAND_MEMORY;
+ pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+ }
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ tp->read32_mbox = tg3_read32_mbox_5906;
++ tp->write32_mbox = tg3_write32_mbox_5906;
++ tp->write32_tx_mbox = tg3_write32_mbox_5906;
++ tp->write32_rx_mbox = tg3_write32_mbox_5906;
++ }
+
+ if (tp->write32 == tg3_write_indirect_reg32 ||
+ ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
+@@ -10461,7 +10682,7 @@ static int __devinit tg3_get_invariants(
+ * When the flag is set, it means that GPIO1 is used for eeprom
+ * write protect and also implies that it is a LOM where GPIOs
+ * are not used to switch power.
+- */
++ */
+ tg3_get_eeprom_hw_cfg(tp);
+
+ /* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
+@@ -10518,6 +10739,7 @@ static int __devinit tg3_get_invariants(
+ ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+ (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
+ (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
++ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) ||
+ (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+ tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
+
+@@ -10531,7 +10753,7 @@ static int __devinit tg3_get_invariants(
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
+- else
++ else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+ tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
+ }
+
+@@ -10621,7 +10843,8 @@ static int __devinit tg3_get_invariants(
+ tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
+ (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
+ (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
+- tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)))
++ tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)) ||
++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
+
+ err = tg3_phy_probe(tp);
+@@ -10672,7 +10895,8 @@ static int __devinit tg3_get_invariants(
+ * straddle the 4GB address boundary in some cases.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tp->dev->hard_start_xmit = tg3_start_xmit;
+ else
+ tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
+@@ -10753,6 +10977,8 @@ static int __devinit tg3_get_device_addr
+ else
+ tg3_nvram_unlock(tp);
+ }
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
++ mac_offset = 0x10;
+
+ /* First try to get it from MAC address mailbox. */
+ tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
+@@ -11236,6 +11462,12 @@ static void __devinit tg3_init_bufmgr_co
+ DEFAULT_MB_MACRX_LOW_WATER_5705;
+ tp->bufmgr_config.mbuf_high_water =
+ DEFAULT_MB_HIGH_WATER_5705;
++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
++ tp->bufmgr_config.mbuf_mac_rx_low_water =
++ DEFAULT_MB_MACRX_LOW_WATER_5906;
++ tp->bufmgr_config.mbuf_high_water =
++ DEFAULT_MB_HIGH_WATER_5906;
++ }
+
+ tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+ DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
+@@ -11279,6 +11511,8 @@ static char * __devinit tg3_phy_string(s
+ case PHY_ID_BCM5780: return "5780";
+ case PHY_ID_BCM5755: return "5755";
+ case PHY_ID_BCM5787: return "5787";
++ case PHY_ID_BCM5756: return "5722/5756";
++ case PHY_ID_BCM5906: return "5906";
+ case PHY_ID_BCM8002: return "8002/serdes";
+ case 0: return "serdes";
+ default: return "unknown";
+@@ -11581,7 +11815,8 @@ static int __devinit tg3_init_one(struct
+ */
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
+ dev->features |= NETIF_F_TSO;
+- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)
++ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
++ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
+ dev->features |= NETIF_F_TSO6;
+ }
+
+@@ -11819,7 +12054,7 @@ static struct pci_driver tg3_driver = {
+
+ static int __init tg3_init(void)
+ {
+- return pci_module_init(&tg3_driver);
++ return pci_register_driver(&tg3_driver);
+ }
+
+ static void __exit tg3_cleanup(void)
+diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
+index 3ecf356..92f5300 100644
+--- a/drivers/net/tg3.h
++++ b/drivers/net/tg3.h
+@@ -24,6 +24,8 @@
+
+ #define RX_COPY_THRESHOLD 256
+
++#define TG3_RX_INTERNAL_RING_SZ_5906 32
++
+ #define RX_STD_MAX_SIZE 1536
+ #define RX_STD_MAX_SIZE_5705 512
+ #define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */
+@@ -129,6 +131,7 @@
+ #define CHIPREV_ID_5752_A0_HW 0x5000
+ #define CHIPREV_ID_5752_A0 0x6000
+ #define CHIPREV_ID_5752_A1 0x6001
++#define CHIPREV_ID_5906_A1 0xc001
+ #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
+ #define ASIC_REV_5700 0x07
+ #define ASIC_REV_5701 0x00
+@@ -141,6 +144,7 @@
+ #define ASIC_REV_5714 0x09
+ #define ASIC_REV_5755 0x0a
+ #define ASIC_REV_5787 0x0b
++#define ASIC_REV_5906 0x0c
+ #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
+ #define CHIPREV_5700_AX 0x70
+ #define CHIPREV_5700_BX 0x71
+@@ -646,7 +650,8 @@
+ #define SNDDATAI_SCTRL_FORCE_ZERO 0x00000010
+ #define SNDDATAI_STATSENAB 0x00000c0c
+ #define SNDDATAI_STATSINCMASK 0x00000c10
+-/* 0xc14 --> 0xc80 unused */
++#define ISO_PKT_TX 0x00000c20
++/* 0xc24 --> 0xc80 unused */
+ #define SNDDATAI_COS_CNT_0 0x00000c80
+ #define SNDDATAI_COS_CNT_1 0x00000c84
+ #define SNDDATAI_COS_CNT_2 0x00000c88
+@@ -997,11 +1002,13 @@
+ #define BUFMGR_MB_MACRX_LOW_WATER 0x00004414
+ #define DEFAULT_MB_MACRX_LOW_WATER 0x00000020
+ #define DEFAULT_MB_MACRX_LOW_WATER_5705 0x00000010
++#define DEFAULT_MB_MACRX_LOW_WATER_5906 0x00000004
+ #define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
+ #define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b
+ #define BUFMGR_MB_HIGH_WATER 0x00004418
+ #define DEFAULT_MB_HIGH_WATER 0x00000060
+ #define DEFAULT_MB_HIGH_WATER_5705 0x00000060
++#define DEFAULT_MB_HIGH_WATER_5906 0x00000010
+ #define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c
+ #define DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096
+ #define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c
+@@ -1138,7 +1145,12 @@
+ #define TX_CPU_STATE 0x00005404
+ #define TX_CPU_PGMCTR 0x0000541c
+
++#define VCPU_STATUS 0x00005100
++#define VCPU_STATUS_INIT_DONE 0x04000000
++#define VCPU_STATUS_DRV_RESET 0x08000000
++
+ /* Mailboxes */
++#define GRCMBOX_BASE 0x00005600
+ #define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */
+ #define GRCMBOX_INTERRUPT_1 0x00005808 /* 64-bit */
+ #define GRCMBOX_INTERRUPT_2 0x00005810 /* 64-bit */
+@@ -1398,7 +1410,10 @@
+ #define GRC_EEPROM_CTRL 0x00006840
+ #define GRC_MDI_CTRL 0x00006844
+ #define GRC_SEEPROM_DELAY 0x00006848
+-/* 0x684c --> 0x6c00 unused */
++/* 0x684c --> 0x6890 unused */
++#define GRC_VCPU_EXT_CTRL 0x00006890
++#define GRC_VCPU_EXT_CTRL_HALT_CPU 0x00400000
++#define GRC_VCPU_EXT_CTRL_DISABLE_WOL 0x20000000
+ #define GRC_FASTBOOT_PC 0x00006894 /* 5752, 5755, 5787 */
+
+ /* 0x6c00 --> 0x7000 unused */
+@@ -1485,9 +1500,17 @@
+ #define NVRAM_WRITE1 0x00007028
+ /* 0x702c --> 0x7400 unused */
+
+-/* 0x7400 --> 0x8000 unused */
++/* 0x7400 --> 0x7c00 unused */
++#define PCIE_TRANSACTION_CFG 0x00007c04
++#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000
++#define PCIE_TRANS_CFG_LOM 0x00000020
++
+
+ #define TG3_EEPROM_MAGIC 0x669955aa
++#define TG3_EEPROM_MAGIC_FW 0xa5000000
++#define TG3_EEPROM_MAGIC_FW_MSK 0xff000000
++#define TG3_EEPROM_MAGIC_HW 0xabcd
++#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
+
+ /* 32K Window into NIC internal memory */
+ #define NIC_SRAM_WIN_BASE 0x00008000
+@@ -1537,6 +1560,7 @@
+ #define FWCMD_NICDRV_FIX_DMAR 0x00000005
+ #define FWCMD_NICDRV_FIX_DMAW 0x00000006
+ #define FWCMD_NICDRV_ALIVE2 0x0000000d
++#define FWCMD_NICDRV_ALIVE3 0x0000000e
+ #define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c
+ #define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80
+ #define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00
+@@ -1604,6 +1628,7 @@
+ #define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */
+
+ #define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */
++#define MII_TG3_EPHY_PTEST 0x17 /* 5906 PHY register */
+
+ #define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */
+
+@@ -1617,6 +1642,8 @@
+ #define MII_TG3_AUX_STAT_100FULL 0x0500
+ #define MII_TG3_AUX_STAT_1000HALF 0x0600
+ #define MII_TG3_AUX_STAT_1000FULL 0x0700
++#define MII_TG3_AUX_STAT_100 0x0008
++#define MII_TG3_AUX_STAT_FULL 0x0001
+
+ #define MII_TG3_ISTAT 0x1a /* IRQ status register */
+ #define MII_TG3_IMASK 0x1b /* IRQ mask register */
+@@ -1627,6 +1654,9 @@
+ #define MII_TG3_INT_DUPLEXCHG 0x0008
+ #define MII_TG3_INT_ANEG_PAGE_RX 0x0400
+
++#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */
++#define MII_TG3_EPHY_SHADOW_EN 0x80
++
+ /* There are two ways to manage the TX descriptors on the tigon3.
+ * Either the descriptors are in host DMA'able memory, or they
+ * exist only in the cards on-chip SRAM. All 16 send bds are under
+@@ -2203,7 +2233,6 @@ struct tg3 {
+ #define TG3_FLG2_PCI_EXPRESS 0x00000200
+ #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400
+ #define TG3_FLG2_HW_AUTONEG 0x00000800
+-#define TG3_FLG2_PHY_JUST_INITTED 0x00001000
+ #define TG3_FLG2_PHY_SERDES 0x00002000
+ #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000
+ #define TG3_FLG2_FLASH 0x00008000
+@@ -2236,6 +2265,12 @@ struct tg3 {
+ u16 asf_counter;
+ u16 asf_multiplier;
+
++ /* 1 second counter for transient serdes link events */
++ u32 serdes_counter;
++#define SERDES_AN_TIMEOUT_5704S 2
++#define SERDES_PARALLEL_DET_TIMEOUT 1
++#define SERDES_AN_TIMEOUT_5714S 1
++
+ struct tg3_link_config link_config;
+ struct tg3_bufmgr_config bufmgr_config;
+
+@@ -2276,6 +2311,8 @@ struct tg3 {
+ #define PHY_ID_BCM5780 0x60008350
+ #define PHY_ID_BCM5755 0xbc050cc0
+ #define PHY_ID_BCM5787 0xbc050ce0
++#define PHY_ID_BCM5756 0xbc050ed0
++#define PHY_ID_BCM5906 0xdc00ac40
+ #define PHY_ID_BCM8002 0x60010140
+ #define PHY_ID_INVALID 0xffffffff
+ #define PHY_ID_REV_MASK 0x0000000f
+@@ -2302,7 +2339,8 @@ struct tg3 {
+ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
+ (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
+ (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
+- (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM8002)
++ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
++ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
+
+ struct tg3_hw_stats *hw_stats;
+ dma_addr_t stats_mapping;
+diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
+index 23c0017..e14f5a0 100644
+--- a/drivers/net/tlan.c
++++ b/drivers/net/tlan.c
+@@ -33,33 +33,33 @@
+ * new PCI BIOS interface.
+ * Alan Cox <alan at redhat.com>: Fixed the out of memory
+ * handling.
+- *
++ *
+ * Torben Mathiasen <torben.mathiasen at compaq.com> New Maintainer!
+ *
+ * v1.1 Dec 20, 1999 - Removed linux version checking
+- * Patch from Tigran Aivazian.
++ * Patch from Tigran Aivazian.
+ * - v1.1 includes Alan's SMP updates.
+ * - We still have problems on SMP though,
+- * but I'm looking into that.
+- *
++ * but I'm looking into that.
++ *
+ * v1.2 Jan 02, 2000 - Hopefully fixed the SMP deadlock.
+ * - Removed dependency of HZ being 100.
+- * - We now allow higher priority timers to
++ * - We now allow higher priority timers to
+ * overwrite timers like TLAN_TIMER_ACTIVITY
+ * Patch from John Cagle <john.cagle at compaq.com>.
+ * - Fixed a few compiler warnings.
+ *
+ * v1.3 Feb 04, 2000 - Fixed the remaining HZ issues.
+- * - Removed call to pci_present().
++ * - Removed call to pci_present().
+ * - Removed SA_INTERRUPT flag from irq handler.
+- * - Added __init and __initdata to reduce resisdent
++ * - Added __init and __initdata to reduce resisdent
+ * code size.
+ * - Driver now uses module_init/module_exit.
+ * - Rewrote init_module and tlan_probe to
+ * share a lot more code. We now use tlan_probe
+ * with builtin and module driver.
+- * - Driver ported to new net API.
+- * - tlan.txt has been reworked to reflect current
++ * - Driver ported to new net API.
++ * - tlan.txt has been reworked to reflect current
+ * driver (almost)
+ * - Other minor stuff
+ *
+@@ -74,11 +74,11 @@
+ * Auto-Neg fallback.
+ *
+ * v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. Haven't
+- * tested it though, as the kernel support is currently
++ * tested it though, as the kernel support is currently
+ * broken (2.3.99p4p3).
+ * - Updated tlan.txt accordingly.
+ * - Adjusted minimum/maximum frame length.
+- * - There is now a TLAN website up at
++ * - There is now a TLAN website up at
+ * http://tlan.kernel.dk
+ *
+ * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now
+@@ -92,10 +92,10 @@
+ * link partner abilities. When forced link is used,
+ * the driver will report status of the established
+ * link.
+- * Please read tlan.txt for additional information.
+- * - Removed call to check_region(), and used
++ * Please read tlan.txt for additional information.
++ * - Removed call to check_region(), and used
+ * return value of request_region() instead.
+- *
++ *
+ * v1.8a May 28, 2000 - Minor updates.
+ *
+ * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues.
+@@ -104,25 +104,25 @@
+ * - Added routine to monitor PHY status.
+ * - Added activity led support for Proliant devices.
+ *
+- * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers
+- * like the Compaq NetFlex3/E.
++ * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers
++ * like the Compaq NetFlex3/E.
+ * - Rewrote tlan_probe to better handle multiple
+ * bus probes. Probing and device setup is now
+ * done through TLan_Probe and TLan_init_one. Actual
+- * hardware probe is done with kernel API and
++ * hardware probe is done with kernel API and
+ * TLan_EisaProbe.
+ * - Adjusted debug information for probing.
+- * - Fixed bug that would cause general debug information
+- * to be printed after driver removal.
++ * - Fixed bug that would cause general debug information
++ * to be printed after driver removal.
+ * - Added transmit timeout handling.
+- * - Fixed OOM return values in tlan_probe.
+- * - Fixed possible mem leak in tlan_exit
++ * - Fixed OOM return values in tlan_probe.
++ * - Fixed possible mem leak in tlan_exit
+ * (now tlan_remove_one).
+ * - Fixed timer bug in TLan_phyMonitor.
+ * - This driver version is alpha quality, please
+ * send me any bug issues you may encounter.
+ *
+- * v1.11 Aug 31, 2000 - Do not try to register irq 0 if no irq line was
++ * v1.11 Aug 31, 2000 - Do not try to register irq 0 if no irq line was
+ * set for EISA cards.
+ * - Added support for NetFlex3/E with nibble-rate
+ * 10Base-T PHY. This is untestet as I haven't got
+@@ -142,7 +142,7 @@
+ * - Added the bbuf option as a kernel parameter.
+ * - Fixed ioaddr probe bug.
+ * - Fixed stupid deadlock with MII interrupts.
+- * - Added support for speed/duplex selection with
++ * - Added support for speed/duplex selection with
+ * multiple nics.
+ * - Added partly fix for TX Channel lockup with
+ * TLAN v1.0 silicon. This needs to be investigated
+@@ -226,7 +226,7 @@ static int tlan_have_pci;
+ static int tlan_have_eisa;
+
+ static const char *media[] = {
+- "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
++ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
+ "100baseTx-FD", "100baseT4", NULL
+ };
+
+@@ -249,7 +249,7 @@ static struct board {
+ { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
+ { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 },
+ { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */
+- TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
++ TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
+ { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */
+ };
+
+@@ -282,14 +282,14 @@ static struct pci_device_id tlan_pci_tbl
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+ { 0,}
+ };
+-MODULE_DEVICE_TABLE(pci, tlan_pci_tbl);
++MODULE_DEVICE_TABLE(pci, tlan_pci_tbl);
+
+ static void TLan_EisaProbe( void );
+ static void TLan_Eisa_Cleanup( void );
+ static int TLan_Init( struct net_device * );
+ static int TLan_Open( struct net_device *dev );
+ static int TLan_StartTx( struct sk_buff *, struct net_device *);
+-static irqreturn_t TLan_HandleInterrupt( int, void *, struct pt_regs *);
++static irqreturn_t TLan_HandleInterrupt( int, void *);
+ static int TLan_Close( struct net_device *);
+ static struct net_device_stats *TLan_GetStats( struct net_device *);
+ static void TLan_SetMulticastList( struct net_device *);
+@@ -347,7 +347,7 @@ static void TLan_EeReceiveByte( u16, u8
+ static int TLan_EeReadByte( struct net_device *, u8, u8 * );
+
+
+-static void
++static void
+ TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb)
+ {
+ unsigned long addr = (unsigned long)skb;
+@@ -384,11 +384,11 @@ TLan_SetTimer( struct net_device *dev, u
+ {
+ TLanPrivateInfo *priv = netdev_priv(dev);
+ unsigned long flags = 0;
+-
++
+ if (!in_irq())
+ spin_lock_irqsave(&priv->lock, flags);
+ if ( priv->timer.function != NULL &&
+- priv->timerType != TLAN_TIMER_ACTIVITY ) {
++ priv->timerType != TLAN_TIMER_ACTIVITY ) {
+ if (!in_irq())
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+@@ -401,7 +401,7 @@ TLan_SetTimer( struct net_device *dev, u
+ priv->timerSetAt = jiffies;
+ priv->timerType = type;
+ mod_timer(&priv->timer, jiffies + ticks);
+-
++
+ } /* TLan_SetTimer */
+
+
+@@ -439,7 +439,7 @@ static void __devexit tlan_remove_one( s
+ {
+ struct net_device *dev = pci_get_drvdata( pdev );
+ TLanPrivateInfo *priv = netdev_priv(dev);
+-
++
+ unregister_netdev( dev );
+
+ if ( priv->dmaStorage ) {
+@@ -449,25 +449,25 @@ static void __devexit tlan_remove_one( s
+ #ifdef CONFIG_PCI
+ pci_release_regions(pdev);
+ #endif
+-
++
+ free_netdev( dev );
+-
++
+ pci_set_drvdata( pdev, NULL );
+-}
++}
+
+ static struct pci_driver tlan_driver = {
+ .name = "tlan",
+ .id_table = tlan_pci_tbl,
+ .probe = tlan_init_one,
+- .remove = __devexit_p(tlan_remove_one),
++ .remove = __devexit_p(tlan_remove_one),
+ };
+
+ static int __init tlan_probe(void)
+ {
+ static int pad_allocated;
+-
++
+ printk(KERN_INFO "%s", tlan_banner);
+-
++
+ TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA);
+
+ if (TLanPadBuffer == NULL) {
+@@ -479,15 +479,15 @@ static int __init tlan_probe(void)
+ pad_allocated = 1;
+
+ TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
+-
++
+ /* Use new style PCI probing. Now the kernel will
+ do most of this for us */
+ pci_register_driver(&tlan_driver);
+
+ TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n");
+ TLan_EisaProbe();
+-
+- printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n",
++
++ printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n",
+ TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s",
+ tlan_have_pci, tlan_have_eisa);
+
+@@ -498,7 +498,7 @@ static int __init tlan_probe(void)
+ }
+ return 0;
+ }
+-
++
+
+ static int __devinit tlan_init_one( struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+@@ -513,11 +513,11 @@ static int __devinit tlan_init_one( stru
+ *
+ * Returns:
+ * 0 on success, error code on error
+- * Parms:
++ * Parms:
+ * none
+ *
+ * The name is lower case to fit in with all the rest of
+- * the netcard_probe names. This function looks for
++ * the netcard_probe names. This function looks for
+ * another TLan based adapter, setting it up with the
+ * allocated device struct if one is found.
+ * tlan_probe has been ported to the new net API and
+@@ -526,7 +526,7 @@ static int __devinit tlan_init_one( stru
+ *
+ **************************************************************/
+
+-static int __devinit TLan_probe1(struct pci_dev *pdev,
++static int __devinit TLan_probe1(struct pci_dev *pdev,
+ long ioaddr, int irq, int rev, const struct pci_device_id *ent )
+ {
+
+@@ -558,11 +558,11 @@ static int __devinit TLan_probe1(struct
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+-
++
+ priv = netdev_priv(dev);
+
+ priv->pciDev = pdev;
+-
++
+ /* Is this a PCI device? */
+ if (pdev) {
+ u32 pci_io_base = 0;
+@@ -590,10 +590,10 @@ static int __devinit TLan_probe1(struct
+ rc = -EIO;
+ goto err_out_free_dev;
+ }
+-
++
+ dev->base_addr = pci_io_base;
+ dev->irq = pdev->irq;
+- priv->adapterRev = pci_rev;
++ priv->adapterRev = pci_rev;
+ pci_set_master(pdev);
+ pci_set_drvdata(pdev, dev);
+
+@@ -618,7 +618,7 @@ static int __devinit TLan_probe1(struct
+ priv->aui = dev->mem_start & 0x01;
+ priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1;
+ priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3;
+-
++
+ if (priv->speed == 0x1) {
+ priv->speed = TLAN_SPEED_10;
+ } else if (priv->speed == 0x2) {
+@@ -631,13 +631,13 @@ static int __devinit TLan_probe1(struct
+ priv->duplex = duplex[boards_found];
+ priv->debug = debug;
+ }
+-
++
+ /* This will be used when we get an adapter error from
+ * within our irq handler */
+ INIT_WORK(&priv->tlan_tqueue, (void *)(void*)TLan_tx_timeout, dev);
+
+ spin_lock_init(&priv->lock);
+-
++
+ rc = TLan_Init(dev);
+ if (rc) {
+ printk(KERN_ERR "TLAN: Could not set up device.\n");
+@@ -650,10 +650,10 @@ static int __devinit TLan_probe1(struct
+ goto err_out_uninit;
+ }
+
+-
++
+ TLanDevicesInstalled++;
+ boards_found++;
+-
++
+ /* pdev is NULL if this is an EISA device */
+ if (pdev)
+ tlan_have_pci++;
+@@ -662,7 +662,7 @@ static int __devinit TLan_probe1(struct
+ TLan_Eisa_Devices = dev;
+ tlan_have_eisa++;
+ }
+-
++
+ printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n",
+ dev->name,
+ (int) dev->irq,
+@@ -692,7 +692,7 @@ static void TLan_Eisa_Cleanup(void)
+ {
+ struct net_device *dev;
+ TLanPrivateInfo *priv;
+-
++
+ while( tlan_have_eisa ) {
+ dev = TLan_Eisa_Devices;
+ priv = netdev_priv(dev);
+@@ -706,8 +706,8 @@ static void TLan_Eisa_Cleanup(void)
+ tlan_have_eisa--;
+ }
+ }
+-
+-
++
++
+ static void __exit tlan_exit(void)
+ {
+ pci_unregister_driver(&tlan_driver);
+@@ -734,52 +734,52 @@ module_exit(tlan_exit);
+ * Parms: None
+ *
+ *
+- * This functions probes for EISA devices and calls
+- * TLan_probe1 when one is found.
++ * This functions probes for EISA devices and calls
++ * TLan_probe1 when one is found.
+ *
+ *************************************************************/
+
+-static void __init TLan_EisaProbe (void)
++static void __init TLan_EisaProbe (void)
+ {
+ long ioaddr;
+ int rc = -ENODEV;
+ int irq;
+ u16 device_id;
+
+- if (!EISA_bus) {
++ if (!EISA_bus) {
+ TLAN_DBG(TLAN_DEBUG_PROBE, "No EISA bus present\n");
+ return;
+ }
+-
++
+ /* Loop through all slots of the EISA bus */
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+-
+- TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
++
++ TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
+ TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2));
+
+
+ TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ",
+ (int) ioaddr);
+- if (request_region(ioaddr, 0x10, TLanSignature) == NULL)
++ if (request_region(ioaddr, 0x10, TLanSignature) == NULL)
+ goto out;
+
+- if (inw(ioaddr + EISA_ID) != 0x110E) {
++ if (inw(ioaddr + EISA_ID) != 0x110E) {
+ release_region(ioaddr, 0x10);
+ goto out;
+ }
+-
++
+ device_id = inw(ioaddr + EISA_ID2);
+- if (device_id != 0x20F1 && device_id != 0x40F1) {
++ if (device_id != 0x20F1 && device_id != 0x40F1) {
+ release_region (ioaddr, 0x10);
+ goto out;
+ }
+-
++
+ if (inb(ioaddr + EISA_CR) != 0x1) { /* Check if adapter is enabled */
+ release_region (ioaddr, 0x10);
+ goto out2;
+ }
+-
+- if (debug == 0x10)
++
++ if (debug == 0x10)
+ printk("Found one\n");
+
+
+@@ -799,14 +799,14 @@ static void __init TLan_EisaProbe (void
+ break;
+ default:
+ goto out;
+- }
+-
+-
++ }
++
++
+ /* Setup the newly found eisa adapter */
+ rc = TLan_probe1( NULL, ioaddr, irq,
+ 12, NULL);
+ continue;
+-
++
+ out:
+ if (debug == 0x10)
+ printk("None found\n");
+@@ -815,7 +815,7 @@ static void __init TLan_EisaProbe (void
+ out2: if (debug == 0x10)
+ printk("Card found but it is not enabled, skipping\n");
+ continue;
+-
++
+ }
+
+ } /* TLan_EisaProbe */
+@@ -824,12 +824,12 @@ static void __init TLan_EisaProbe (void
+ static void TLan_Poll(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- TLan_HandleInterrupt(dev->irq, dev, NULL);
++ TLan_HandleInterrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+
+-
++
+
+
+ /***************************************************************
+@@ -846,7 +846,7 @@ static void TLan_Poll(struct net_device
+ * addresses, allocates memory for the lists and bounce
+ * buffers, retrieves the MAC address from the eeprom
+ * and assignes the device's methods.
+- *
++ *
+ **************************************************************/
+
+ static int TLan_Init( struct net_device *dev )
+@@ -857,7 +857,7 @@ static int TLan_Init( struct net_device
+ TLanPrivateInfo *priv;
+
+ priv = netdev_priv(dev);
+-
++
+ if ( bbuf ) {
+ dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+ * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
+@@ -867,14 +867,14 @@ static int TLan_Init( struct net_device
+ }
+ priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA);
+ priv->dmaSize = dma_size;
+-
++
+ if ( priv->dmaStorage == NULL ) {
+ printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n",
+ dev->name );
+ return -ENOMEM;
+ }
+ memset( priv->dmaStorage, 0, dma_size );
+- priv->rxList = (TLanList *)
++ priv->rxList = (TLanList *)
+ ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
+ priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 );
+ priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
+@@ -941,18 +941,18 @@ static int TLan_Open( struct net_device
+ {
+ TLanPrivateInfo *priv = netdev_priv(dev);
+ int err;
+-
++
+ priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
+ err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, TLanSignature, dev );
+-
++
+ if ( err ) {
+ printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
+ return err;
+ }
+-
++
+ init_timer(&priv->timer);
+ netif_start_queue(dev);
+-
++
+ /* NOTE: It might not be necessary to read the stats before a
+ reset if you don't care what the values are.
+ */
+@@ -970,12 +970,12 @@ static int TLan_Open( struct net_device
+
+ /**************************************************************
+ * TLan_ioctl
+- *
++ *
+ * Returns:
+ * 0 on success, error code otherwise
+ * Params:
+ * dev structure of device to receive ioctl.
+- *
++ *
+ * rq ifreq structure to hold userspace data.
+ *
+ * cmd ioctl command.
+@@ -988,7 +988,7 @@ static int TLan_ioctl(struct net_device
+ TLanPrivateInfo *priv = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(rq);
+ u32 phy = priv->phy[priv->phyNum];
+-
++
+ if (!priv->phyOnline)
+ return -EAGAIN;
+
+@@ -1000,7 +1000,7 @@ static int TLan_ioctl(struct net_device
+ case SIOCGMIIREG: /* Read MII PHY register. */
+ TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out);
+ return 0;
+-
++
+
+ case SIOCSMIIREG: /* Write MII PHY register. */
+ if (!capable(CAP_NET_ADMIN))
+@@ -1019,31 +1019,31 @@ static int TLan_ioctl(struct net_device
+ * Returns: nothing
+ *
+ * Params:
+- * dev structure of device which timed out
++ * dev structure of device which timed out
+ * during transmit.
+ *
+ **************************************************************/
+
+ static void TLan_tx_timeout(struct net_device *dev)
+ {
+-
++
+ TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name);
+-
++
+ /* Ok so we timed out, lets see what we can do about it...*/
+ TLan_FreeLists( dev );
+- TLan_ResetLists( dev );
++ TLan_ResetLists( dev );
+ TLan_ReadAndClearStats( dev, TLAN_IGNORE );
+ TLan_ResetAdapter( dev );
+ dev->trans_start = jiffies;
+- netif_wake_queue( dev );
++ netif_wake_queue( dev );
+
+ }
+-
++
+
+
+ /***************************************************************
+ * TLan_StartTx
+- *
++ *
+ * Returns:
+ * 0 on success, non-zero on failure.
+ * Parms:
+@@ -1079,7 +1079,7 @@ static int TLan_StartTx( struct sk_buff
+
+ tail_list = priv->txList + priv->txTail;
+ tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail;
+-
++
+ if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
+ netif_stop_queue(dev);
+@@ -1132,7 +1132,7 @@ static int TLan_StartTx( struct sk_buff
+
+ if ( bbuf )
+ dev_kfree_skb_any(skb);
+-
++
+ dev->trans_start = jiffies;
+ return 0;
+
+@@ -1143,15 +1143,14 @@ static int TLan_StartTx( struct sk_buff
+
+ /***************************************************************
+ * TLan_HandleInterrupt
+- *
+- * Returns:
++ *
++ * Returns:
+ * Nothing
+ * Parms:
+ * irq The line on which the interrupt
+ * occurred.
+ * dev_id A pointer to the device assigned to
+ * this irq line.
+- * regs ???
+ *
+ * This function handles an interrupt generated by its
+ * assigned TLAN adapter. The function deactivates
+@@ -1162,7 +1161,7 @@ static int TLan_StartTx( struct sk_buff
+ *
+ **************************************************************/
+
+-static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id)
+ {
+ u32 ack;
+ struct net_device *dev;
+@@ -1198,7 +1197,7 @@ static irqreturn_t TLan_HandleInterrupt(
+
+ /***************************************************************
+ * TLan_Close
+- *
++ *
+ * Returns:
+ * An error code.
+ * Parms:
+@@ -1224,7 +1223,7 @@ static int TLan_Close(struct net_device
+ del_timer_sync( &priv->timer );
+ priv->timer.function = NULL;
+ }
+-
++
+ free_irq( dev->irq, dev );
+ TLan_FreeLists( dev );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name );
+@@ -1238,7 +1237,7 @@ static int TLan_Close(struct net_device
+
+ /***************************************************************
+ * TLan_GetStats
+- *
++ *
+ * Returns:
+ * A pointer to the device's statistics structure.
+ * Parms:
+@@ -1263,7 +1262,7 @@ static struct net_device_stats *TLan_Get
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount );
+ if ( debug & TLAN_DEBUG_GNRL ) {
+ TLan_PrintDio( dev->base_addr );
+- TLan_PhyPrint( dev );
++ TLan_PhyPrint( dev );
+ }
+ if ( debug & TLAN_DEBUG_LIST ) {
+ for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )
+@@ -1271,7 +1270,7 @@ static struct net_device_stats *TLan_Get
+ for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )
+ TLan_PrintList( priv->txList + i, "TX", i );
+ }
+-
++
+ return ( &( (TLanPrivateInfo *) netdev_priv(dev) )->stats );
+
+ } /* TLan_GetStats */
+@@ -1281,7 +1280,7 @@ static struct net_device_stats *TLan_Get
+
+ /***************************************************************
+ * TLan_SetMulticastList
+- *
++ *
+ * Returns:
+ * Nothing
+ * Parms:
+@@ -1300,7 +1299,7 @@ static struct net_device_stats *TLan_Get
+ **************************************************************/
+
+ static void TLan_SetMulticastList( struct net_device *dev )
+-{
++{
+ struct dev_mc_list *dmi = dev->mc_list;
+ u32 hash1 = 0;
+ u32 hash2 = 0;
+@@ -1315,7 +1314,7 @@ static void TLan_SetMulticastList( struc
+ tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
+ TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
+ if ( dev->flags & IFF_ALLMULTI ) {
+- for ( i = 0; i < 3; i++ )
++ for ( i = 0; i < 3; i++ )
+ TLan_SetMac( dev, i + 1, NULL );
+ TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );
+ TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
+@@ -1325,14 +1324,14 @@ static void TLan_SetMulticastList( struc
+ TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );
+ } else {
+ offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
+- if ( offset < 32 )
++ if ( offset < 32 )
+ hash1 |= ( 1 << offset );
+ else
+ hash2 |= ( 1 << ( offset - 32 ) );
+ }
+ dmi = dmi->next;
+ }
+- for ( ; i < 3; i++ )
++ for ( ; i < 3; i++ )
+ TLan_SetMac( dev, i + 1, NULL );
+ TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 );
+ TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 );
+@@ -1350,7 +1349,7 @@ static void TLan_SetMulticastList( struc
+
+ Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN
+ Programmer's Guide" for more informations on handling interrupts
+- generated by TLAN based adapters.
++ generated by TLAN based adapters.
+
+ ******************************************************************************
+ *****************************************************************************/
+@@ -1413,7 +1412,7 @@ u32 TLan_HandleTxEOF( struct net_device
+ dma_addr_t head_list_phys;
+ u32 ack = 0;
+ u16 tmpCStat;
+-
++
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+ head_list = priv->txList + priv->txHead;
+
+@@ -1426,21 +1425,21 @@ u32 TLan_HandleTxEOF( struct net_device
+ head_list->buffer[8].address = 0;
+ head_list->buffer[9].address = 0;
+ }
+-
++
+ if ( tmpCStat & TLAN_CSTAT_EOC )
+ eoc = 1;
+-
++
+ priv->stats.tx_bytes += head_list->frameSize;
+
+ head_list->cStat = TLAN_CSTAT_UNUSED;
+- netif_start_queue(dev);
+- CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
++ netif_start_queue(dev);
++ CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
+ head_list = priv->txList + priv->txHead;
+ }
+
+ if (!ack)
+ printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n");
+-
++
+ if ( eoc ) {
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+ head_list = priv->txList + priv->txHead;
+@@ -1452,7 +1451,7 @@ u32 TLan_HandleTxEOF( struct net_device
+ priv->txInProgress = 0;
+ }
+ }
+-
++
+ if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+ if ( priv->timer.function == NULL ) {
+@@ -1544,13 +1543,13 @@ u32 TLan_HandleRxEOF( struct net_device
+ TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+ head_list = priv->rxList + priv->rxHead;
+ head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
+-
++
+ while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
+ frameSize = head_list->frameSize;
+ ack++;
+ if (tmpCStat & TLAN_CSTAT_EOC)
+ eoc = 1;
+-
++
+ if (bbuf) {
+ skb = dev_alloc_skb(frameSize + 7);
+ if (skb == NULL)
+@@ -1560,7 +1559,7 @@ u32 TLan_HandleRxEOF( struct net_device
+ skb->dev = dev;
+ skb_reserve(skb, 2);
+ t = (void *) skb_put(skb, frameSize);
+-
++
+ priv->stats.rx_bytes += head_list->frameSize;
+
+ memcpy( t, head_buffer, frameSize );
+@@ -1569,15 +1568,15 @@ u32 TLan_HandleRxEOF( struct net_device
+ }
+ } else {
+ struct sk_buff *new_skb;
+-
++
+ /*
+ * I changed the algorithm here. What we now do
+ * is allocate the new frame. If this fails we
+ * simply recycle the frame.
+ */
+-
++
+ new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+-
++
+ if ( new_skb != NULL ) {
+ skb = TLan_GetSKB(head_list);
+ pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+@@ -1587,14 +1586,14 @@ u32 TLan_HandleRxEOF( struct net_device
+
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
+-
++
+ new_skb->dev = dev;
+ skb_reserve( new_skb, 2 );
+ t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
+ head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+ head_list->buffer[8].address = (u32) t;
+ TLan_StoreSKB(head_list, new_skb);
+- } else
++ } else
+ printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" );
+ }
+
+@@ -1611,11 +1610,11 @@ u32 TLan_HandleRxEOF( struct net_device
+
+ if (!ack)
+ printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n");
+-
+
+
+
+- if ( eoc ) {
++
++ if ( eoc ) {
+ TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+ head_list = priv->rxList + priv->rxHead;
+ head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
+@@ -1639,7 +1638,7 @@ u32 TLan_HandleRxEOF( struct net_device
+ }
+
+ dev->last_rx = jiffies;
+-
++
+ return ack;
+
+ } /* TLan_HandleRxEOF */
+@@ -1700,7 +1699,7 @@ u32 TLan_HandleTxEOC( struct net_device
+ TLanList *head_list;
+ dma_addr_t head_list_phys;
+ u32 ack = 1;
+-
++
+ host_int = 0;
+ if ( priv->tlanRev < 0x30 ) {
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
+@@ -1743,7 +1742,7 @@ u32 TLan_HandleTxEOC( struct net_device
+ **************************************************************/
+
+ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
+-{
++{
+ TLanPrivateInfo *priv = netdev_priv(dev);
+ u32 ack;
+ u32 error;
+@@ -1751,7 +1750,7 @@ u32 TLan_HandleStatusCheck( struct net_d
+ u32 phy;
+ u16 tlphy_ctl;
+ u16 tlphy_sts;
+-
++
+ ack = 1;
+ if ( host_int & TLAN_HI_IV_MASK ) {
+ netif_stop_queue( dev );
+@@ -1785,7 +1784,7 @@ u32 TLan_HandleStatusCheck( struct net_d
+ }
+
+ if (debug) {
+- TLan_PhyPrint( dev );
++ TLan_PhyPrint( dev );
+ }
+ }
+ }
+@@ -1887,7 +1886,7 @@ void TLan_Timer( unsigned long data )
+ priv->timer.function = NULL;
+
+ switch ( priv->timerType ) {
+-#ifdef MONITOR
++#ifdef MONITOR
+ case TLAN_TIMER_LINK_BEAT:
+ TLan_PhyMonitor( dev );
+ break;
+@@ -1946,7 +1945,7 @@ void TLan_Timer( unsigned long data )
+
+ /***************************************************************
+ * TLan_ResetLists
+- *
++ *
+ * Returns:
+ * Nothing
+ * Parms:
+@@ -2055,7 +2054,7 @@ void TLan_FreeLists( struct net_device *
+
+ /***************************************************************
+ * TLan_PrintDio
+- *
++ *
+ * Returns:
+ * Nothing
+ * Parms:
+@@ -2087,7 +2086,7 @@ void TLan_PrintDio( u16 io_base )
+
+ /***************************************************************
+ * TLan_PrintList
+- *
++ *
+ * Returns:
+ * Nothing
+ * Parms:
+@@ -2128,7 +2127,7 @@ void TLan_PrintList( TLanList *list, cha
+ * Parms:
+ * dev Pointer to device structure of adapter
+ * to which to read stats.
+- * record Flag indicating whether to add
++ * record Flag indicating whether to add
+ *
+ * This functions reads all the internal status registers
+ * of the TLAN chip, which clears them as a side effect.
+@@ -2158,13 +2157,13 @@ void TLan_ReadAndClearStats( struct net_
+ rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+ rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;
+ rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+-
++
+ outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR );
+ def_tx = inb( dev->base_addr + TLAN_DIO_DATA );
+ def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+ crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+ code = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+-
++
+ outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR );
+ multi_col = inb( dev->base_addr + TLAN_DIO_DATA );
+ multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+@@ -2190,7 +2189,7 @@ void TLan_ReadAndClearStats( struct net_
+ priv->stats.tx_aborted_errors += tx_under;
+ priv->stats.tx_carrier_errors += loss;
+ }
+-
++
+ } /* TLan_ReadAndClearStats */
+
+
+@@ -2231,7 +2230,7 @@ TLan_ResetAdapter( struct net_device *de
+ data = inl(dev->base_addr + TLAN_HOST_CMD);
+ data |= TLAN_HC_AD_RST;
+ outl(data, dev->base_addr + TLAN_HOST_CMD);
+-
++
+ udelay(1000);
+
+ /* 2. Turn off interrupts. ( Probably isn't necessary ) */
+@@ -2270,7 +2269,7 @@ TLan_ResetAdapter( struct net_device *de
+ }
+ TLan_PhyDetect( dev );
+ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
+-
++
+ if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) {
+ data |= TLAN_NET_CFG_BIT;
+ if ( priv->aui == 1 ) {
+@@ -2320,15 +2319,15 @@ TLan_FinishReset( struct net_device *dev
+ data |= TLAN_NET_CMD_DUPLEX;
+ }
+ TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data );
+- data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
++ data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
+ if ( priv->phyNum == 0 ) {
+- data |= TLAN_NET_MASK_MASK7;
++ data |= TLAN_NET_MASK_MASK7;
+ }
+ TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data );
+ TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 );
+ TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 );
+ TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 );
+-
++
+ if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
+ status = MII_GS_LINK;
+ printk( "TLAN: %s: Link forced.\n", dev->name );
+@@ -2336,15 +2335,15 @@ TLan_FinishReset( struct net_device *dev
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+ udelay( 1000 );
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+- if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */
++ if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */
+ (tlphy_id1 == NAT_SEM_ID1) &&
+ (tlphy_id2 == NAT_SEM_ID2) ) {
+ TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner );
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par );
+-
++
+ printk( "TLAN: %s: Link active with ", dev->name );
+ if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
+- printk( "forced 10%sMbps %s-Duplex\n",
++ printk( "forced 10%sMbps %s-Duplex\n",
+ tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
+ tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
+ } else {
+@@ -2359,12 +2358,12 @@ TLan_FinishReset( struct net_device *dev
+ }
+
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+-#ifdef MONITOR
++#ifdef MONITOR
+ /* We have link beat..for now anyway */
+ priv->link = 1;
+ /*Enabling link beat monitoring */
+ TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT );
+-#endif
++#endif
+ } else if (status & MII_GS_LINK) {
+ printk( "TLAN: %s: Link active\n", dev->name );
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+@@ -2426,7 +2425,7 @@ TLan_FinishReset( struct net_device *dev
+ void TLan_SetMac( struct net_device *dev, int areg, char *mac )
+ {
+ int i;
+-
++
+ areg *= 6;
+
+ if ( mac != NULL ) {
+@@ -2460,7 +2459,7 @@ void TLan_SetMac( struct net_device *dev
+ * Parms:
+ * dev A pointer to the device structure of the
+ * TLAN device having the PHYs to be detailed.
+- *
++ *
+ * This function prints the registers a PHY (aka transceiver).
+ *
+ ********************************************************************/
+@@ -2528,7 +2527,7 @@ void TLan_PhyDetect( struct net_device *
+ }
+
+ TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi );
+-
++
+ if ( hi != 0xFFFF ) {
+ priv->phy[0] = TLAN_PHY_MAX_ADDR;
+ } else {
+@@ -2650,10 +2649,10 @@ void TLan_PhyStartLink( struct net_devic
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability );
+
+- if ( ( status & MII_GS_AUTONEG ) &&
++ if ( ( status & MII_GS_AUTONEG ) &&
+ ( ! priv->aui ) ) {
+ ability = status >> 11;
+- if ( priv->speed == TLAN_SPEED_10 &&
++ if ( priv->speed == TLAN_SPEED_10 &&
+ priv->duplex == TLAN_DUPLEX_HALF) {
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000);
+ } else if ( priv->speed == TLAN_SPEED_10 &&
+@@ -2668,7 +2667,7 @@ void TLan_PhyStartLink( struct net_devic
+ priv->tlanFullDuplex = TRUE;
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100);
+ } else {
+-
++
+ /* Set Auto-Neg advertisement */
+ TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1);
+ /* Enablee Auto-Neg */
+@@ -2684,9 +2683,9 @@ void TLan_PhyStartLink( struct net_devic
+ TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN );
+ return;
+ }
+-
+- }
+-
++
++ }
++
+ if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
+ priv->phyNum = 0;
+ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+@@ -2698,7 +2697,7 @@ void TLan_PhyStartLink( struct net_devic
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
+ if ( priv->aui ) {
+ tctl |= TLAN_TC_AUISEL;
+- } else {
++ } else {
+ tctl &= ~TLAN_TC_AUISEL;
+ if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+ control |= MII_GC_DUPLEX;
+@@ -2731,7 +2730,7 @@ void TLan_PhyFinishAutoNeg( struct net_d
+ u16 mode;
+ u16 phy;
+ u16 status;
+-
++
+ phy = priv->phy[priv->phyNum];
+
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+@@ -2783,7 +2782,7 @@ void TLan_PhyFinishAutoNeg( struct net_d
+ /* Wait for 100 ms. No reason in partiticular.
+ */
+ TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET );
+-
++
+ } /* TLan_PhyFinishAutoNeg */
+
+ #ifdef MONITOR
+@@ -2792,13 +2791,13 @@ void TLan_PhyFinishAutoNeg( struct net_d
+ *
+ * TLan_phyMonitor
+ *
+- * Returns:
++ * Returns:
+ * None
+ *
+ * Params:
+ * dev The device structure of this device.
+ *
+- *
++ *
+ * This function monitors PHY condition by reading the status
+ * register via the MII bus. This can be used to give info
+ * about link changes (up/down), and possible switch to alternate
+@@ -2818,7 +2817,7 @@ void TLan_PhyMonitor( struct net_device
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status );
+
+ /* Check if link has been lost */
+- if (!(phy_status & MII_GS_LINK)) {
++ if (!(phy_status & MII_GS_LINK)) {
+ if (priv->link) {
+ priv->link = 0;
+ printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name);
+@@ -2837,7 +2836,7 @@ void TLan_PhyMonitor( struct net_device
+
+ /* Setup a new monitor */
+ TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT );
+-}
++}
+
+ #endif /* MONITOR */
+
+@@ -2891,7 +2890,7 @@ int TLan_MiiReadReg( struct net_device *
+ err = FALSE;
+ outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
+ sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
+-
++
+ if (!in_irq())
+ spin_lock_irqsave(&priv->lock, flags);
+
+@@ -2939,7 +2938,7 @@ int TLan_MiiReadReg( struct net_device *
+ TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
+
+ *val = tmp;
+-
++
+ if (!in_irq())
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+@@ -3058,7 +3057,7 @@ void TLan_MiiWriteReg( struct net_device
+
+ outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
+ sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
+-
++
+ if (!in_irq())
+ spin_lock_irqsave(&priv->lock, flags);
+
+@@ -3081,7 +3080,7 @@ void TLan_MiiWriteReg( struct net_device
+
+ if ( minten )
+ TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
+-
++
+ if (!in_irq())
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+@@ -3109,7 +3108,7 @@ void TLan_MiiWriteReg( struct net_device
+ *
+ * Returns:
+ * Nothing
+- * Parms:
++ * Parms:
+ * io_base The IO port base address for the
+ * TLAN device with the EEPROM to
+ * use.
+diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
+index 5d32bc6..a44e2f2 100644
+--- a/drivers/net/tlan.h
++++ b/drivers/net/tlan.h
+@@ -9,13 +9,13 @@
+ *
+ * (C) 1997-1998 Caldera, Inc.
+ * (C) 1999-2001 Torben Mathiasen
+- *
++ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ ** This file is best viewed/edited with tabstop=4, colums>=132
+ *
+- *
++ *
+ * Dec 10, 1999 Torben Mathiasen <torben.mathiasen at compaq.com>
+ * New Maintainer
+ *
+@@ -48,7 +48,7 @@
+ #define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args );
+ #define TLAN_DEBUG_GNRL 0x0001
+ #define TLAN_DEBUG_TX 0x0002
+-#define TLAN_DEBUG_RX 0x0004
++#define TLAN_DEBUG_RX 0x0004
+ #define TLAN_DEBUG_LIST 0x0008
+ #define TLAN_DEBUG_PROBE 0x0010
+
+@@ -60,7 +60,7 @@
+ * Device Identification Definitions
+ *
+ ****************************************************************/
+-
++
+ #define PCI_DEVICE_ID_NETELLIGENT_10_T2 0xB012
+ #define PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100 0xB030
+ #ifndef PCI_DEVICE_ID_OLICOM_OC2183
+@@ -102,11 +102,11 @@ typedef struct tlan_adapter_entry {
+ *
+ ****************************************************************/
+
+-#define EISA_ID 0xc80 /* EISA ID Registers */
+-#define EISA_ID0 0xc80 /* EISA ID Register 0 */
+-#define EISA_ID1 0xc81 /* EISA ID Register 1 */
+-#define EISA_ID2 0xc82 /* EISA ID Register 2 */
+-#define EISA_ID3 0xc83 /* EISA ID Register 3 */
++#define EISA_ID 0xc80 /* EISA ID Registers */
++#define EISA_ID0 0xc80 /* EISA ID Register 0 */
++#define EISA_ID1 0xc81 /* EISA ID Register 1 */
++#define EISA_ID2 0xc82 /* EISA ID Register 2 */
++#define EISA_ID3 0xc83 /* EISA ID Register 3 */
+ #define EISA_CR 0xc84 /* EISA Control Register */
+ #define EISA_REG0 0xc88 /* EISA Configuration Register 0 */
+ #define EISA_REG1 0xc89 /* EISA Configuration Register 1 */
+@@ -447,7 +447,7 @@ static inline u8 TLan_DioRead8(u16 base_
+ {
+ outw(internal_addr, base_addr + TLAN_DIO_ADR);
+ return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)));
+-
++
+ } /* TLan_DioRead8 */
+
+
+@@ -505,8 +505,8 @@ static inline void TLan_DioWrite32(u16 b
+ #define TLan_SetBit( bit, port ) outb_p(inb_p(port) | bit, port)
+
+ /*
+- * given 6 bytes, view them as 8 6-bit numbers and return the XOR of those
+- * the code below is about seven times as fast as the original code
++ * given 6 bytes, view them as 8 6-bit numbers and return the XOR of those
++ * the code below is about seven times as fast as the original code
+ *
+ * The original code was:
+ *
+diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
+index 465921e..7580bde 100644
+--- a/drivers/net/tokenring/3c359.c
++++ b/drivers/net/tokenring/3c359.c
+@@ -130,7 +130,7 @@ static int xl_xmit(struct sk_buff *skb,
+ static void xl_dn_comp(struct net_device *dev);
+ static int xl_close(struct net_device *dev);
+ static void xl_set_rx_mode(struct net_device *dev);
+-static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t xl_interrupt(int irq, void *dev_id);
+ static struct net_device_stats * xl_get_stats(struct net_device *dev);
+ static int xl_set_mac_address(struct net_device *dev, void *addr) ;
+ static void xl_arb_cmd(struct net_device *dev);
+@@ -1042,7 +1042,7 @@ static void xl_freemem(struct net_device
+ return ;
+ }
+
+-static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t xl_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct xl_private *xl_priv =(struct xl_private *)dev->priv;
+@@ -1815,7 +1815,7 @@ static struct pci_driver xl_3c359_driver
+
+ static int __init xl_pci_init (void)
+ {
+- return pci_module_init (&xl_3c359_driver);
++ return pci_register_driver(&xl_3c359_driver);
+ }
+
+
+diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
+index 4470025..bfe5986 100644
+--- a/drivers/net/tokenring/ibmtr.c
++++ b/drivers/net/tokenring/ibmtr.c
+@@ -197,7 +197,7 @@ static void open_sap(unsigned char type
+ 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);
+-static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t tok_interrupt(int irq, void *dev_id);
+ 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);
+@@ -1166,7 +1166,7 @@ static void dir_open_adapter (struct net
+
+ /******************************************************************************/
+
+-static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t tok_interrupt(int irq, void *dev_id)
+ {
+ unsigned char status;
+ /* unsigned char status_even ; */
+@@ -1178,7 +1178,7 @@ static irqreturn_t tok_interrupt(int irq
+
+ dev = dev_id;
+ #if TR_VERBOSE
+- DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs);
++ DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq);
+ #endif
+ ti = (struct tok_info *) dev->priv;
+ if (ti->sram_phys & 1)
+diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
+index 28d968f..e999feb 100644
+--- a/drivers/net/tokenring/lanstreamer.c
++++ b/drivers/net/tokenring/lanstreamer.c
+@@ -206,8 +206,7 @@ static int streamer_open(struct net_devi
+ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int streamer_close(struct net_device *dev);
+ static void streamer_set_rx_mode(struct net_device *dev);
+-static irqreturn_t streamer_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t streamer_interrupt(int irq, void *dev_id);
+ static struct net_device_stats *streamer_get_stats(struct net_device *dev);
+ static int streamer_set_mac_address(struct net_device *dev, void *addr);
+ static void streamer_arb_cmd(struct net_device *dev);
+@@ -1028,7 +1027,7 @@ static void streamer_rx(struct net_devic
+ } /* end for all completed rx descriptors */
+ }
+
+-static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t streamer_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct streamer_private *streamer_priv =
+@@ -1876,7 +1875,6 @@ static int sprintf_info(char *buffer, st
+ datap[size+1]=io_word & 0xff;
+ }
+
+-
+ size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name);
+
+ size += sprintf(buffer + size,
+@@ -1932,64 +1930,6 @@ static int sprintf_info(char *buffer, st
+ #endif
+ #endif
+
+-#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+-static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+-{
+- int i;
+- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+- u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
+-
+- switch(cmd) {
+- case IOCTL_SISR_MASK:
+- writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+- break;
+- case IOCTL_SPIN_LOCK_TEST:
+- printk(KERN_INFO "spin_lock() called.\n");
+- spin_lock(&streamer_priv->streamer_lock);
+- spin_unlock(&streamer_priv->streamer_lock);
+- printk(KERN_INFO "spin_unlock() finished.\n");
+- break;
+- case IOCTL_PRINT_BDAS:
+- printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
+- readw(streamer_mmio + RXBDA),
+- readw(streamer_mmio + RXLBDA),
+- readw(streamer_mmio + TX2FDA),
+- readw(streamer_mmio + TX2LFDA));
+- break;
+- case IOCTL_PRINT_REGISTERS:
+- printk(KERN_INFO "registers:\n");
+- printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n",
+- readw(streamer_mmio + SISR),
+- readw(streamer_mmio + MISR_RUM),
+- readw(streamer_mmio + LISR),
+- readw(streamer_mmio + BCTL),
+- readw(streamer_mmio + BMCTL_SUM),
+- readw(streamer_mmio + SISR_MASK),
+- readw(streamer_mmio + MISR_MASK));
+- break;
+- case IOCTL_PRINT_RX_BUFS:
+- printk(KERN_INFO "Print rx bufs:\n");
+- for(i=0; i<STREAMER_RX_RING_SIZE; i++)
+- printk(KERN_INFO "rx_ring %d status: 0x%x\n", i,
+- streamer_priv->streamer_rx_ring[i].status);
+- break;
+- case IOCTL_PRINT_TX_BUFS:
+- printk(KERN_INFO "Print tx bufs:\n");
+- for(i=0; i<STREAMER_TX_RING_SIZE; i++)
+- printk(KERN_INFO "tx_ring %d status: 0x%x\n", i,
+- streamer_priv->streamer_tx_ring[i].status);
+- break;
+- case IOCTL_RX_CMD:
+- streamer_rx(dev);
+- printk(KERN_INFO "Sent rx command.\n");
+- break;
+- default:
+- printk(KERN_INFO "Bad ioctl!\n");
+- }
+- return 0;
+-}
+-#endif
+-
+ static struct pci_driver streamer_pci_driver = {
+ .name = "lanstreamer",
+ .id_table = streamer_pci_tbl,
+@@ -1998,7 +1938,7 @@ static struct pci_driver streamer_pci_dr
+ };
+
+ static int __init streamer_init_module(void) {
+- return pci_module_init(&streamer_pci_driver);
++ return pci_register_driver(&streamer_pci_driver);
+ }
+
+ static void __exit streamer_cleanup_module(void) {
+diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h
+index 5557d8e..e7bb349 100644
+--- a/drivers/net/tokenring/lanstreamer.h
++++ b/drivers/net/tokenring/lanstreamer.h
+@@ -62,18 +62,6 @@
+
+ #include <linux/version.h>
+
+-#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+-#include <asm/ioctl.h>
+-#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE
+-#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1
+-#define IOCTL_RX_CMD SIOCDEVPRIVATE+2
+-#define IOCTL_TX_CMD SIOCDEVPRIVATE+3
+-#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
+-#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5
+-#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6
+-#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7
+-#endif
+-
+ /* MAX_INTR - the maximum number of times we can loop
+ * inside the interrupt function before returning
+ * control to the OS (maximum value is 256)
+diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
+index 666bbaa..ed274d6 100644
+--- a/drivers/net/tokenring/madgemc.c
++++ b/drivers/net/tokenring/madgemc.c
+@@ -70,7 +70,7 @@ static void madgemc_setregpage(struct ne
+ static void madgemc_setsifsel(struct net_device *dev, int val);
+ static void madgemc_setint(struct net_device *dev, int val);
+
+-static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t madgemc_interrupt(int irq, void *dev_id);
+
+ /*
+ * These work around paging, however they don't guarentee you're on the
+@@ -417,7 +417,7 @@ getout:
+ * exhausted all contiguous interrupts.
+ *
+ */
+-static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t madgemc_interrupt(int irq, void *dev_id)
+ {
+ int pending,reg1;
+ struct net_device *dev;
+@@ -451,7 +451,7 @@ static irqreturn_t madgemc_interrupt(int
+ outb(reg1, dev->base_addr + MC_CONTROL_REG1);
+
+ /* Continue handling as normal */
+- tms380tr_interrupt(irq, dev_id, regs);
++ tms380tr_interrupt(irq, dev_id);
+
+ pending = SIFREADW(SIFSTS); /* restart - the SIF way */
+
+diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
+index 8583148..cd142d0 100644
+--- a/drivers/net/tokenring/olympic.c
++++ b/drivers/net/tokenring/olympic.c
+@@ -185,7 +185,7 @@ static int olympic_xmit(struct sk_buff *
+ static int olympic_close(struct net_device *dev);
+ static void olympic_set_rx_mode(struct net_device *dev);
+ static void olympic_freemem(struct net_device *dev) ;
+-static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t olympic_interrupt(int irq, void *dev_id);
+ static struct net_device_stats * olympic_get_stats(struct net_device *dev);
+ static int olympic_set_mac_address(struct net_device *dev, void *addr) ;
+ static void olympic_arb_cmd(struct net_device *dev);
+@@ -925,7 +925,7 @@ static void olympic_freemem(struct net_d
+ return ;
+ }
+
+-static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t olympic_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev= (struct net_device *)dev_id;
+ struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
+index 4f75696..cb7dbb6 100644
+--- a/drivers/net/tokenring/proteon.c
++++ b/drivers/net/tokenring/proteon.c
+@@ -370,6 +370,10 @@ static int __init proteon_init(void)
+ dev->dma = dma[i];
+ pdev = platform_device_register_simple("proteon",
+ i, NULL, 0);
++ if (IS_ERR(pdev)) {
++ free_netdev(dev);
++ continue;
++ }
+ err = setup_card(dev, &pdev->dev);
+ if (!err) {
+ proteon_dev[i] = pdev;
+@@ -385,9 +389,10 @@ static int __init proteon_init(void)
+ /* Probe for cards. */
+ if (num == 0) {
+ printk(KERN_NOTICE "proteon.c: No cards found.\n");
+- return (-ENODEV);
++ platform_driver_unregister(&proteon_driver);
++ return -ENODEV;
+ }
+- return (0);
++ return 0;
+ }
+
+ static void __exit proteon_cleanup(void)
+diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
+index d6ba41c..33afea3 100644
+--- a/drivers/net/tokenring/skisa.c
++++ b/drivers/net/tokenring/skisa.c
+@@ -380,6 +380,10 @@ static int __init sk_isa_init(void)
+ dev->dma = dma[i];
+ pdev = platform_device_register_simple("skisa",
+ i, NULL, 0);
++ if (IS_ERR(pdev)) {
++ free_netdev(dev);
++ continue;
++ }
+ err = setup_card(dev, &pdev->dev);
+ if (!err) {
+ sk_isa_dev[i] = pdev;
+@@ -395,9 +399,10 @@ static int __init sk_isa_init(void)
+ /* Probe for cards. */
+ if (num == 0) {
+ printk(KERN_NOTICE "skisa.c: No cards found.\n");
+- return (-ENODEV);
++ platform_driver_unregister(&sk_isa_driver);
++ return -ENODEV;
+ }
+- return (0);
++ return 0;
+ }
+
+ static void __exit sk_isa_cleanup(void)
+diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
+index 85a7f79..46dabdb 100644
+--- a/drivers/net/tokenring/smctr.c
++++ b/drivers/net/tokenring/smctr.c
+@@ -141,7 +141,7 @@ static int smctr_init_shared_memory(stru
+ static int smctr_init_tx_bdbs(struct net_device *dev);
+ static int smctr_init_tx_fcbs(struct net_device *dev);
+ static int smctr_internal_self_test(struct net_device *dev);
+-static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t smctr_interrupt(int irq, void *dev_id);
+ static int smctr_issue_enable_int_cmd(struct net_device *dev,
+ __u16 interrupt_enable_mask);
+ static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code,
+@@ -1980,7 +1980,7 @@ static int smctr_internal_self_test(stru
+ /*
+ * The typical workload of the driver: Handle the network interface interrupts.
+ */
+-static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t smctr_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *tp;
+@@ -1990,15 +1990,8 @@ static irqreturn_t smctr_interrupt(int i
+ __u8 isb_type, isb_subtype;
+ __u16 isb_index;
+
+- if(dev == NULL)
+- {
+- printk(KERN_CRIT "%s: irq %d for unknown device.\n", dev->name, irq);
+- return IRQ_NONE;
+- }
+-
+ ioaddr = dev->base_addr;
+ tp = netdev_priv(dev);
+-
+
+ if(tp->status == NOT_INITIALIZED)
+ return IRQ_NONE;
+diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
+index c192559..ea797ca 100644
+--- a/drivers/net/tokenring/tms380tr.c
++++ b/drivers/net/tokenring/tms380tr.c
+@@ -744,18 +744,13 @@ static void tms380tr_timer_chk(unsigned
+ /*
+ * The typical workload of the driver: Handle the network interface interrupts.
+ */
+-irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t tms380tr_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct net_local *tp;
+ unsigned short irq_type;
+ int handled = 0;
+
+- if(dev == NULL) {
+- printk(KERN_INFO "%s: irq %d for unknown device.\n", dev->name, irq);
+- return IRQ_NONE;
+- }
+-
+ tp = netdev_priv(dev);
+
+ irq_type = SIFREADW(SIFSTS);
+diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h
+index 30452c6..2a16078 100644
+--- a/drivers/net/tokenring/tms380tr.h
++++ b/drivers/net/tokenring/tms380tr.h
+@@ -16,7 +16,7 @@
+ /* module prototypes */
+ int tms380tr_open(struct net_device *dev);
+ int tms380tr_close(struct net_device *dev);
+-irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t tms380tr_interrupt(int irq, void *dev_id);
+ int tmsdev_init(struct net_device *dev, struct device *pdev);
+ void tmsdev_term(struct net_device *dev);
+ void tms380tr_wait(unsigned long time);
+diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
+index 7d3e270..3b2f00b 100644
+--- a/drivers/net/tokenring/tmspci.c
++++ b/drivers/net/tokenring/tmspci.c
+@@ -224,8 +224,7 @@ static void __devexit tms_pci_detach (st
+ {
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+- if (!dev)
+- BUG();
++ BUG_ON(!dev);
+ unregister_netdev(dev);
+ release_region(dev->base_addr, TMS_PCI_IO_EXTENT);
+ free_irq(dev->irq, dev);
+diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
+index 683f14b..fa3a2bb 100644
+--- a/drivers/net/tulip/21142.c
++++ b/drivers/net/tulip/21142.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/21142.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+@@ -26,9 +26,9 @@ static u16 t21142_csr15[] = { 0x0008, 0x
+
+ /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+ of available transceivers. */
+-void t21142_timer(unsigned long data)
++void t21142_media_task(void *data)
+ {
+- struct net_device *dev = (struct net_device *)data;
++ struct net_device *dev = data;
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
+ int csr12 = ioread32(ioaddr + CSR12);
+diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
+index d05c5aa..f6b3a94 100644
+--- a/drivers/net/tulip/de2104x.c
++++ b/drivers/net/tulip/de2104x.c
+@@ -484,7 +484,7 @@ rx_next:
+ de->rx_tail = rx_tail;
+ }
+
+-static irqreturn_t de_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t de_interrupt (int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct de_private *de = dev->priv;
+@@ -1670,7 +1670,7 @@ static void de_get_regs(struct net_devic
+ spin_unlock_irq(&de->lock);
+ }
+
+-static struct ethtool_ops de_ethtool_ops = {
++static const struct ethtool_ops de_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+@@ -1730,7 +1730,7 @@ static void __init de21040_get_media_inf
+ }
+
+ /* Note: this routine returns extra data bits for size detection. */
+-static unsigned __init tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
++static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
+ {
+ int i;
+ unsigned retval = 0;
+@@ -1926,7 +1926,7 @@ bad_srom:
+ goto fill_defaults;
+ }
+
+-static int __init de_init_one (struct pci_dev *pdev,
++static int __devinit de_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
+ struct net_device *dev;
+@@ -2082,7 +2082,7 @@ err_out_free:
+ return rc;
+ }
+
+-static void __exit de_remove_one (struct pci_dev *pdev)
++static void __devexit de_remove_one (struct pci_dev *pdev)
+ {
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct de_private *de = dev->priv;
+@@ -2138,17 +2138,21 @@ static int de_resume (struct pci_dev *pd
+ {
+ struct net_device *dev = pci_get_drvdata (pdev);
+ struct de_private *de = dev->priv;
++ int retval = 0;
+
+ rtnl_lock();
+ if (netif_device_present(dev))
+ goto out;
+- if (netif_running(dev)) {
+- pci_enable_device(pdev);
+- de_init_hw(de);
+- netif_device_attach(dev);
+- } else {
+- netif_device_attach(dev);
++ if (!netif_running(dev))
++ goto out_attach;
++ if ((retval = pci_enable_device(pdev))) {
++ printk (KERN_ERR "%s: pci_enable_device failed in resume\n",
++ dev->name);
++ goto out;
+ }
++ de_init_hw(de);
++out_attach:
++ netif_device_attach(dev);
+ out:
+ rtnl_unlock();
+ return 0;
+@@ -2160,7 +2164,7 @@ static struct pci_driver de_driver = {
+ .name = DRV_NAME,
+ .id_table = de_pci_tbl,
+ .probe = de_init_one,
+- .remove = __exit_p(de_remove_one),
++ .remove = __devexit_p(de_remove_one),
+ #ifdef CONFIG_PM
+ .suspend = de_suspend,
+ .resume = de_resume,
+@@ -2172,7 +2176,7 @@ static int __init de_init (void)
+ #ifdef MODULE
+ printk("%s", version);
+ #endif
+- return pci_module_init (&de_driver);
++ return pci_register_driver(&de_driver);
+ }
+
+ static void __exit de_exit (void)
+diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
+index 75ff14a..3f4b640 100644
+--- a/drivers/net/tulip/de4x5.c
++++ b/drivers/net/tulip/de4x5.c
+@@ -896,7 +896,7 @@ static struct {
+ */
+ static int de4x5_open(struct net_device *dev);
+ static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t de4x5_interrupt(int irq, void *dev_id);
+ static int de4x5_close(struct net_device *dev);
+ static struct net_device_stats *de4x5_get_stats(struct net_device *dev);
+ static void de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len);
+@@ -1538,18 +1538,14 @@ de4x5_queue_pkt(struct sk_buff *skb, str
+ ** interrupt is asserted and this routine entered.
+ */
+ static irqreturn_t
+-de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++de4x5_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *)dev_id;
++ struct net_device *dev = dev_id;
+ struct de4x5_private *lp;
+ s32 imr, omr, sts, limit;
+ u_long iobase;
+ unsigned int handled = 0;
+
+- if (dev == NULL) {
+- printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+ lp = netdev_priv(dev);
+ spin_lock(&lp->lock);
+ iobase = dev->base_addr;
+@@ -2114,6 +2110,7 @@ static struct eisa_device_id de4x5_eisa_
+ { "DEC4250", 0 }, /* 0 is the board name index... */
+ { "" }
+ };
++MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
+
+ static struct eisa_driver de4x5_eisa_driver = {
+ .id_table = de4x5_eisa_ids,
+@@ -5754,7 +5751,7 @@ static int __init de4x5_module_init (voi
+ int err = 0;
+
+ #ifdef CONFIG_PCI
+- err = pci_module_init (&de4x5_pci_driver);
++ err = pci_register_driver(&de4x5_pci_driver);
+ #endif
+ #ifdef CONFIG_EISA
+ err |= eisa_driver_register (&de4x5_eisa_driver);
+diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
+index 4e5b0f2..4dd8a0b 100644
+--- a/drivers/net/tulip/dmfe.c
++++ b/drivers/net/tulip/dmfe.c
+@@ -298,9 +298,9 @@ static int dmfe_start_xmit(struct sk_buf
+ static int dmfe_stop(struct DEVICE *);
+ static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
+ static void dmfe_set_filter_mode(struct DEVICE *);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static u16 read_srom_word(long ,int);
+-static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
++static irqreturn_t dmfe_interrupt(int , void *);
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ static void poll_dmfe (struct net_device *dev);
+ #endif
+@@ -735,7 +735,7 @@ static int dmfe_stop(struct DEVICE *dev)
+ * receive the packet to upper layer, free the transmitted packet
+ */
+
+-static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t dmfe_interrupt(int irq, void *dev_id)
+ {
+ struct DEVICE *dev = dev_id;
+ struct dmfe_board_info *db = netdev_priv(dev);
+@@ -806,7 +806,7 @@ static void poll_dmfe (struct net_device
+ /* disable_irq here is not very nice, but with the lockless
+ interrupt handler we have no other choice. */
+ disable_irq(dev->irq);
+- dmfe_interrupt (dev->irq, dev, NULL);
++ dmfe_interrupt (dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1048,7 +1048,7 @@ static void netdev_get_drvinfo(struct ne
+ dev->base_addr, dev->irq);
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+@@ -2039,7 +2039,7 @@ static int __init dmfe_init_module(void)
+ if (HPNA_NoiseFloor > 15)
+ HPNA_NoiseFloor = 0;
+
+- rc = pci_module_init(&dmfe_driver);
++ rc = pci_register_driver(&dmfe_driver);
+ if (rc < 0)
+ return rc;
+
+diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
+index 5ffbd5b..206918b 100644
+--- a/drivers/net/tulip/eeprom.c
++++ b/drivers/net/tulip/eeprom.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/eeprom.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
+index 99ccf2e..e3488d7 100644
+--- a/drivers/net/tulip/interrupt.c
++++ b/drivers/net/tulip/interrupt.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/interrupt.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+@@ -496,7 +496,7 @@ static inline unsigned int phy_interrupt
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++irqreturn_t tulip_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct tulip_private *tp = netdev_priv(dev);
+diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
+index e9bc2a9..20bd52b 100644
+--- a/drivers/net/tulip/media.c
++++ b/drivers/net/tulip/media.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/media.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
+index ca7e532..85a521e 100644
+--- a/drivers/net/tulip/pnic.c
++++ b/drivers/net/tulip/pnic.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/pnic.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
+index ab98502..c31be0e 100644
+--- a/drivers/net/tulip/pnic2.c
++++ b/drivers/net/tulip/pnic2.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/pnic2.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+ Modified to hep support PNIC_II by Kevin B. Hendricks
+diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
+index e058a9f..066e5d6 100644
+--- a/drivers/net/tulip/timer.c
++++ b/drivers/net/tulip/timer.c
+@@ -1,7 +1,7 @@
+ /*
+ drivers/net/tulip/timer.c
+
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+@@ -18,13 +18,14 @@
+ #include "tulip.h"
+
+
+-void tulip_timer(unsigned long data)
++void tulip_media_task(void *data)
+ {
+- struct net_device *dev = (struct net_device *)data;
++ struct net_device *dev = data;
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
+ u32 csr12 = ioread32(ioaddr + CSR12);
+ int next_tick = 2*HZ;
++ unsigned long flags;
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
+@@ -126,6 +127,15 @@ void tulip_timer(unsigned long data)
+ }
+ break;
+ }
++
++
++ spin_lock_irqsave(&tp->lock, flags);
++ if (tp->timeout_recovery) {
++ tulip_tx_timeout_complete(tp, ioaddr);
++ tp->timeout_recovery = 0;
++ }
++ spin_unlock_irqrestore(&tp->lock, flags);
++
+ /* mod_timer synchronizes us with potential add_timer calls
+ * from interrupts.
+ */
+diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
+index 3bcfbf3..ad107f4 100644
+--- a/drivers/net/tulip/tulip.h
++++ b/drivers/net/tulip/tulip.h
+@@ -30,11 +30,10 @@
+ /* undefine, or define to various debugging levels (>4 == obscene levels) */
+ #define TULIP_DEBUG 1
+
+-/* undefine USE_IO_OPS for MMIO, define for PIO */
+ #ifdef CONFIG_TULIP_MMIO
+-# undef USE_IO_OPS
++#define TULIP_BAR 1 /* CBMA */
+ #else
+-# define USE_IO_OPS 1
++#define TULIP_BAR 0 /* CBIO */
+ #endif
+
+
+@@ -44,7 +43,8 @@ struct tulip_chip_table {
+ int io_size;
+ int valid_intrs; /* CSR7 interrupt enable settings */
+ int flags;
+- void (*media_timer) (unsigned long data);
++ void (*media_timer) (unsigned long);
++ void (*media_task) (void *);
+ };
+
+
+@@ -142,6 +142,7 @@ enum status_bits {
+ RxNoBuf = 0x80,
+ RxIntr = 0x40,
+ TxFIFOUnderflow = 0x20,
++ RxErrIntr = 0x10,
+ TxJabber = 0x08,
+ TxNoBuf = 0x04,
+ TxDied = 0x02,
+@@ -192,9 +193,14 @@ struct tulip_tx_desc {
+
+
+ enum desc_status_bits {
+- DescOwned = 0x80000000,
+- RxDescFatalErr = 0x8000,
+- RxWholePkt = 0x0300,
++ DescOwned = 0x80000000,
++ DescWholePkt = 0x60000000,
++ DescEndPkt = 0x40000000,
++ DescStartPkt = 0x20000000,
++ DescEndRing = 0x02000000,
++ DescUseLink = 0x01000000,
++ RxDescFatalErr = 0x008000,
++ RxWholePkt = 0x00000300,
+ };
+
+
+@@ -366,6 +372,7 @@ struct tulip_private {
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
++ unsigned int timeout_recovery:1;
+ unsigned int csr0; /* CSR0 setting. */
+ unsigned int csr6; /* Current CSR6 control settings. */
+ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
+@@ -384,6 +391,7 @@ struct tulip_private {
+ void __iomem *base_addr;
+ int csr12_shadow;
+ int pad0; /* Used for 8-byte alignment */
++ struct work_struct media_work;
+ };
+
+
+@@ -398,7 +406,7 @@ struct eeprom_fixup {
+
+ /* 21142.c */
+ extern u16 t21142_csr14[];
+-void t21142_timer(unsigned long data);
++void t21142_media_task(void *data);
+ void t21142_start_nway(struct net_device *dev);
+ void t21142_lnk_change(struct net_device *dev, int csr5);
+
+@@ -416,7 +424,7 @@ int tulip_read_eeprom(struct net_device
+ /* interrupt.c */
+ extern unsigned int tulip_max_interrupt_work;
+ extern int tulip_rx_copybreak;
+-irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++irqreturn_t tulip_interrupt(int irq, void *dev_instance);
+ int tulip_refill_rx(struct net_device *dev);
+ #ifdef CONFIG_TULIP_NAPI
+ int tulip_poll(struct net_device *dev, int *budget);
+@@ -436,7 +444,7 @@ void pnic_lnk_change(struct net_device *
+ void pnic_timer(unsigned long data);
+
+ /* timer.c */
+-void tulip_timer(unsigned long data);
++void tulip_media_task(void *data);
+ void mxic_timer(unsigned long data);
+ void comet_timer(unsigned long data);
+
+@@ -485,4 +493,14 @@ static inline void tulip_restart_rxtx(st
+ tulip_start_rxtx(tp);
+ }
+
++static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr)
++{
++ /* Stop and restart the chip's Tx processes. */
++ tulip_restart_rxtx(tp);
++ /* Trigger an immediate transmit demand. */
++ iowrite32(0, ioaddr + CSR1);
++
++ tp->stats.tx_errors++;
++}
++
+ #endif /* __NET_TULIP_H__ */
+diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
+index 7351831..0aee618 100644
+--- a/drivers/net/tulip/tulip_core.c
++++ b/drivers/net/tulip/tulip_core.c
+@@ -1,7 +1,7 @@
+ /* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. */
+
+ /*
+- Maintained by Jeff Garzik <jgarzik at pobox.com>
++ Maintained by Valerie Henson <val_henson at linux.intel.com>
+ Copyright 2000,2001 The Linux Kernel Team
+ Written/copyright 1994-2001 by Donald Becker.
+
+@@ -17,9 +17,9 @@
+
+ #define DRV_NAME "tulip"
+ #ifdef CONFIG_TULIP_NAPI
+-#define DRV_VERSION "1.1.13-NAPI" /* Keep at least for test */
++#define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */
+ #else
+-#define DRV_VERSION "1.1.13"
++#define DRV_VERSION "1.1.14"
+ #endif
+ #define DRV_RELDATE "May 11, 2002"
+
+@@ -130,7 +130,14 @@ int tulip_debug = TULIP_DEBUG;
+ int tulip_debug = 1;
+ #endif
+
++static void tulip_timer(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct tulip_private *tp = netdev_priv(dev);
+
++ if (netif_running(dev))
++ schedule_work(&tp->media_work);
++}
+
+ /*
+ * This table use during operation for capabilities and media timer.
+@@ -144,59 +151,60 @@ struct tulip_chip_table tulip_tbl[] = {
+
+ /* DC21140 */
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
+- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer },
++ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer,
++ tulip_media_task },
+
+ /* DC21142, DC21143 */
+- { "Digital DS21143 Tulip", 128, 0x0801fbff,
++ { "Digital DS21142/43 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
+- | HAS_INTR_MITIGATION | HAS_PCI_MWI, t21142_timer },
++ | HAS_INTR_MITIGATION | HAS_PCI_MWI, tulip_timer, t21142_media_task },
+
+ /* LC82C168 */
+ { "Lite-On 82c168 PNIC", 256, 0x0001fbef,
+- HAS_MII | HAS_PNICNWAY, pnic_timer },
++ HAS_MII | HAS_PNICNWAY, pnic_timer, },
+
+ /* MX98713 */
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
++ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer, },
+
+ /* MX98715 */
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+- HAS_MEDIA_TABLE, mxic_timer },
++ HAS_MEDIA_TABLE, mxic_timer, },
+
+ /* MX98725 */
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+- HAS_MEDIA_TABLE, mxic_timer },
++ HAS_MEDIA_TABLE, mxic_timer, },
+
+ /* AX88140 */
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY
+- | IS_ASIX, tulip_timer },
++ | IS_ASIX, tulip_timer, tulip_media_task },
+
+ /* PNIC2 */
+ { "Lite-On PNIC-II", 256, 0x0801fbff,
+- HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer },
++ HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer, },
+
+ /* COMET */
+ { "ADMtek Comet", 256, 0x0001abef,
+- HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
++ HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer, },
+
+ /* COMPEX9881 */
+ { "Compex 9881 PMAC", 128, 0x0001ebef,
+- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
++ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer, },
+
+ /* I21145 */
+ { "Intel DS21145 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI
+- | HAS_NWAY | HAS_PCI_MWI, t21142_timer },
++ | HAS_NWAY | HAS_PCI_MWI, tulip_timer, tulip_media_task },
+
+ /* DM910X */
+ { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
+- tulip_timer },
++ tulip_timer, tulip_media_task },
+
+ /* RS7112 */
+ { "Conexant LANfinity", 256, 0x0001ebef,
+- HAS_MII | HAS_ACPI, tulip_timer },
++ HAS_MII | HAS_ACPI, tulip_timer, tulip_media_task },
+
+ };
+
+@@ -295,12 +303,14 @@ static void tulip_up(struct net_device *
+
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ iowrite32(0x00000001, ioaddr + CSR0);
++ pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ udelay(100);
+
+ /* Deassert reset.
+ Wait the specified 50 PCI cycles after a reset by initializing
+ Tx and Rx queues and the address filter list. */
+ iowrite32(tp->csr0, ioaddr + CSR0);
++ pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ udelay(100);
+
+ if (tulip_debug > 1)
+@@ -522,20 +532,9 @@ static void tulip_tx_timeout(struct net_
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
+ ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+- if ( ! tp->medialock && tp->mtable) {
+- do
+- --tp->cur_index;
+- while (tp->cur_index >= 0
+- && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media]
+- & MediaIsFD));
+- if (--tp->cur_index < 0) {
+- /* We start again, but should instead look for default. */
+- tp->cur_index = tp->mtable->leafcount - 1;
+- }
+- tulip_select_media(dev, 0);
+- printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+- "media.\n", dev->name, medianame[dev->if_port]);
+- }
++ tp->timeout_recovery = 1;
++ schedule_work(&tp->media_work);
++ goto out_unlock;
+ } else if (tp->chip_id == PNIC2) {
+ printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
+ "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
+@@ -575,14 +574,9 @@ static void tulip_tx_timeout(struct net_
+ }
+ #endif
+
+- /* Stop and restart the chip's Tx processes . */
+-
+- tulip_restart_rxtx(tp);
+- /* Trigger an immediate transmit demand. */
+- iowrite32(0, ioaddr + CSR1);
+-
+- tp->stats.tx_errors++;
++ tulip_tx_timeout_complete(tp, ioaddr);
+
++out_unlock:
+ spin_unlock_irqrestore (&tp->lock, flags);
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+@@ -732,6 +726,8 @@ static void tulip_down (struct net_devic
+ void __iomem *ioaddr = tp->base_addr;
+ unsigned long flags;
+
++ flush_scheduled_work();
++
+ del_timer_sync (&tp->timer);
+ #ifdef CONFIG_TULIP_NAPI
+ del_timer_sync (&tp->oom_timer);
+@@ -841,7 +837,7 @@ static void tulip_get_drvinfo(struct net
+ strcpy(info->bus_info, pci_name(np->pdev));
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = tulip_get_drvinfo
+ };
+
+@@ -1023,8 +1019,6 @@ static void set_rx_mode(struct net_devic
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ tp->csr6 |= AcceptAllMulticast | AcceptAllPhys;
+ csr6 |= AcceptAllMulticast | AcceptAllPhys;
+- /* Unconditionally log net taps. */
+- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter well -- accept all multicasts. */
+ tp->csr6 |= AcceptAllMulticast;
+@@ -1361,11 +1355,8 @@ static int __devinit tulip_init_one (str
+ if (pci_request_regions (pdev, "tulip"))
+ goto err_out_free_netdev;
+
+-#ifndef USE_IO_OPS
+- ioaddr = pci_iomap(pdev, 1, tulip_tbl[chip_idx].io_size);
+-#else
+- ioaddr = pci_iomap(pdev, 0, tulip_tbl[chip_idx].io_size);
+-#endif
++ ioaddr = pci_iomap(pdev, TULIP_BAR, tulip_tbl[chip_idx].io_size);
++
+ if (!ioaddr)
+ goto err_out_free_res;
+
+@@ -1398,6 +1389,8 @@ static int __devinit tulip_init_one (str
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+
++ INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task, dev);
++
+ dev->base_addr = (unsigned long)ioaddr;
+
+ #ifdef CONFIG_TULIP_MWI
+@@ -1552,7 +1545,7 @@ static int __devinit tulip_init_one (str
+ if (pcp) {
+ unsigned char *addr;
+ int len;
+-
++
+ addr = of_get_property(pcp->prom_node,
+ "local-mac-address", &len);
+ if (addr && len == 6)
+@@ -1644,8 +1637,14 @@ static int __devinit tulip_init_one (str
+ if (register_netdev(dev))
+ goto err_out_free_ring;
+
+- printk(KERN_INFO "%s: %s rev %d at %p,",
+- dev->name, chip_name, chip_rev, ioaddr);
++ printk(KERN_INFO "%s: %s rev %d at "
++#ifdef CONFIG_TULIP_MMIO
++ "MMIO"
++#else
++ "Port"
++#endif
++ " %#llx,", dev->name, chip_name, chip_rev,
++ (unsigned long long) pci_resource_start(pdev, TULIP_BAR));
+ pci_set_drvdata(pdev, dev);
+
+ if (eeprom_missing)
+@@ -1768,7 +1767,10 @@ static int tulip_resume(struct pci_dev *
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+- pci_enable_device(pdev);
++ if ((retval = pci_enable_device(pdev))) {
++ printk (KERN_ERR "tulip: pci_enable_device failed in resume\n");
++ return retval;
++ }
+
+ if ((retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev))) {
+ printk (KERN_ERR "tulip: request_irq failed in resume\n");
+@@ -1821,7 +1823,7 @@ static void poll_tulip (struct net_devic
+ /* disable_irq here is not very nice, but with the lockless
+ interrupt handler we have no other choice. */
+ disable_irq(dev->irq);
+- tulip_interrupt (dev->irq, dev, NULL);
++ tulip_interrupt (dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1849,7 +1851,7 @@ static int __init tulip_init (void)
+ tulip_max_interrupt_work = max_interrupt_work;
+
+ /* probe for and init boards */
+- return pci_module_init (&tulip_driver);
++ return pci_register_driver(&tulip_driver);
+ }
+
+
+diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
+index fd64b2b..229158e 100644
+--- a/drivers/net/tulip/uli526x.c
++++ b/drivers/net/tulip/uli526x.c
+@@ -222,9 +222,9 @@ static int uli526x_start_xmit(struct sk_
+ static int uli526x_stop(struct net_device *);
+ static struct net_device_stats * uli526x_get_stats(struct net_device *);
+ static void uli526x_set_filter_mode(struct net_device *);
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+ static u16 read_srom_word(long, int);
+-static irqreturn_t uli526x_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t uli526x_interrupt(int, void *);
+ static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
+ static void allocate_rx_buffer(struct uli526x_board_info *);
+ static void update_cr6(u32, unsigned long);
+@@ -659,7 +659,7 @@ static int uli526x_stop(struct net_devic
+ * receive the packet to upper layer, free the transmitted packet
+ */
+
+-static irqreturn_t uli526x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct uli526x_board_info *db = netdev_priv(dev);
+@@ -985,7 +985,7 @@ static void uli526x_get_wol(struct net_d
+ wol->wolopts = 0;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_settings = netdev_get_settings,
+ .get_link = netdev_get_link,
+@@ -1702,7 +1702,6 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263:
+
+ static int __init uli526x_init_module(void)
+ {
+- int rc;
+
+ printk(version);
+ printed_version = 1;
+@@ -1714,22 +1713,19 @@ static int __init uli526x_init_module(vo
+ if (cr6set)
+ uli526x_cr6_user_set = cr6set;
+
+- switch(mode) {
++ switch (mode) {
+ case ULI526X_10MHF:
+ case ULI526X_100MHF:
+ case ULI526X_10MFD:
+ case ULI526X_100MFD:
+ uli526x_media_mode = mode;
+ break;
+- default:uli526x_media_mode = ULI526X_AUTO;
++ default:
++ uli526x_media_mode = ULI526X_AUTO;
+ break;
+ }
+
+- rc = pci_module_init(&uli526x_driver);
+- if (rc < 0)
+- return rc;
+-
+- return 0;
++ return pci_register_driver(&uli526x_driver);
+ }
+
+
+diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
+index eba9083..002a05e 100644
+--- a/drivers/net/tulip/winbond-840.c
++++ b/drivers/net/tulip/winbond-840.c
+@@ -45,8 +45,8 @@
+ */
+
+ #define DRV_NAME "winbond-840"
+-#define DRV_VERSION "1.01-d"
+-#define DRV_RELDATE "Nov-17-2001"
++#define DRV_VERSION "1.01-e"
++#define DRV_RELDATE "Sep-11-2006"
+
+
+ /* Automatically extracted configuration info:
+@@ -90,10 +90,8 @@ static int full_duplex[MAX_UNITS] = {-1,
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+-#define TX_RING_SIZE 16
+ #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
+ #define TX_QUEUE_LEN_RESTART 5
+-#define RX_RING_SIZE 32
+
+ #define TX_BUFLIMIT (1024-128)
+
+@@ -137,6 +135,8 @@ static int full_duplex[MAX_UNITS] = {-1,
+ #include <asm/io.h>
+ #include <asm/irq.h>
+
++#include "tulip.h"
++
+ /* These identify the driver base version and may not be removed. */
+ static char version[] =
+ KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker <becker at scyld.com>\n"
+@@ -242,8 +242,8 @@ static const struct pci_id_info pci_id_t
+ };
+
+ /* This driver was written to use PCI memory space, however some x86 systems
+- work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space
+- accesses instead of memory space. */
++ work only with I/O space accesses. See CONFIG_TULIP_MMIO in .config
++*/
+
+ /* Offsets to the Command and Status Registers, "CSRs".
+ While similar to the Tulip, these registers are longword aligned.
+@@ -261,21 +261,11 @@ enum w840_offsets {
+ CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
+ };
+
+-/* Bits in the interrupt status/enable registers. */
+-/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
+-enum intr_status_bits {
+- NormalIntr=0x10000, AbnormalIntr=0x8000,
+- IntrPCIErr=0x2000, TimerInt=0x800,
+- IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
+- TxFIFOUnderflow=0x20, RxErrIntr=0x10,
+- TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
+-};
+-
+ /* Bits in the NetworkConfig register. */
+ enum rx_mode_bits {
+- AcceptErr=0x80, AcceptRunt=0x40,
+- AcceptBroadcast=0x20, AcceptMulticast=0x10,
+- AcceptAllPhys=0x08, AcceptMyPhys=0x02,
++ AcceptErr=0x80,
++ RxAcceptBroadcast=0x20, AcceptMulticast=0x10,
++ RxAcceptAllPhys=0x08, AcceptMyPhys=0x02,
+ };
+
+ enum mii_reg_bits {
+@@ -297,13 +287,6 @@ struct w840_tx_desc {
+ u32 buffer1, buffer2;
+ };
+
+-/* Bits in network_desc.status */
+-enum desc_status_bits {
+- DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
+- DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
+- DescIntr=0x80000000,
+-};
+-
+ #define MII_CNT 1 /* winbond only supports one MII */
+ struct netdev_private {
+ struct w840_rx_desc *rx_ring;
+@@ -349,14 +332,14 @@ static void tx_timeout(struct net_device
+ static int alloc_ringdesc(struct net_device *dev);
+ static void free_ringdesc(struct netdev_private *np);
+ static int start_tx(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t intr_handler(int irq, void *dev_instance);
+ static void netdev_error(struct net_device *dev, int intr_status);
+ static int netdev_rx(struct net_device *dev);
+ static u32 __set_rx_mode(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+ static struct net_device_stats *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 const struct ethtool_ops netdev_ethtool_ops;
+ static int netdev_close(struct net_device *dev);
+
+
+@@ -371,7 +354,6 @@ static int __devinit w840_probe1 (struct
+ int irq;
+ int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
+ void __iomem *ioaddr;
+- int bar = 1;
+
+ i = pci_enable_device(pdev);
+ if (i) return i;
+@@ -393,10 +375,8 @@ static int __devinit w840_probe1 (struct
+
+ if (pci_request_regions(pdev, DRV_NAME))
+ goto err_out_netdev;
+-#ifdef USE_IO_OPS
+- bar = 0;
+-#endif
+- ioaddr = pci_iomap(pdev, bar, netdev_res_size);
++
++ ioaddr = pci_iomap(pdev, TULIP_BAR, netdev_res_size);
+ if (!ioaddr)
+ goto err_out_free_res;
+
+@@ -838,7 +818,7 @@ static void init_rxtx_rings(struct net_d
+ np->rx_buf_sz,PCI_DMA_FROMDEVICE);
+
+ np->rx_ring[i].buffer1 = np->rx_addr[i];
+- np->rx_ring[i].status = DescOwn;
++ np->rx_ring[i].status = DescOwned;
+ }
+
+ np->cur_rx = 0;
+@@ -923,7 +903,7 @@ static void init_registers(struct net_de
+ }
+ #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
+ i |= 0xE000;
+-#elif defined(__sparc__)
++#elif defined(__sparc__) || defined (CONFIG_PARISC)
+ i |= 0x4800;
+ #else
+ #warning Processor architecture undefined
+@@ -1043,11 +1023,11 @@ static int start_tx(struct sk_buff *skb,
+
+ /* Now acquire the irq spinlock.
+ * The difficult race is the the ordering between
+- * increasing np->cur_tx and setting DescOwn:
++ * increasing np->cur_tx and setting DescOwned:
+ * - if np->cur_tx is increased first the interrupt
+ * handler could consider the packet as transmitted
+- * since DescOwn is cleared.
+- * - If DescOwn is set first the NIC could report the
++ * since DescOwned is cleared.
++ * - If DescOwned is set first the NIC could report the
+ * packet as sent, but the interrupt handler would ignore it
+ * since the np->cur_tx was not yet increased.
+ */
+@@ -1055,7 +1035,7 @@ static int start_tx(struct sk_buff *skb,
+ np->cur_tx++;
+
+ wmb(); /* flush length, buffer1, buffer2 */
+- np->tx_ring[entry].status = DescOwn;
++ np->tx_ring[entry].status = DescOwned;
+ wmb(); /* flush status and kick the hardware */
+ iowrite32(0, np->base_addr + TxStartDemand);
+ np->tx_q_bytes += skb->len;
+@@ -1130,7 +1110,7 @@ static void netdev_tx_done(struct net_de
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t intr_handler(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct netdev_private *np = netdev_priv(dev);
+@@ -1155,12 +1135,12 @@ static irqreturn_t intr_handler(int irq,
+
+ handled = 1;
+
+- if (intr_status & (IntrRxDone | RxNoBuf))
++ if (intr_status & (RxIntr | RxNoBuf))
+ netdev_rx(dev);
+ if (intr_status & RxNoBuf)
+ iowrite32(0, ioaddr + RxStartDemand);
+
+- if (intr_status & (TxIdle | IntrTxDone) &&
++ if (intr_status & (TxNoBuf | TxIntr) &&
+ np->cur_tx != np->dirty_tx) {
+ spin_lock(&np->lock);
+ netdev_tx_done(dev);
+@@ -1168,8 +1148,8 @@ static irqreturn_t intr_handler(int irq,
+ }
+
+ /* Abnormal error summary/uncommon events handlers. */
+- if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |
+- TimerInt | IntrTxStopped))
++ if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
++ TimerInt | TxDied))
+ netdev_error(dev, intr_status);
+
+ if (--work_limit < 0) {
+@@ -1305,7 +1285,7 @@ static int netdev_rx(struct net_device *
+ np->rx_ring[entry].buffer1 = np->rx_addr[entry];
+ }
+ wmb();
+- np->rx_ring[entry].status = DescOwn;
++ np->rx_ring[entry].status = DescOwned;
+ }
+
+ return 0;
+@@ -1342,7 +1322,7 @@ static void netdev_error(struct net_devi
+ dev->name, new);
+ update_csr6(dev, new);
+ }
+- if (intr_status & IntrRxDied) { /* Missed a Rx frame. */
++ if (intr_status & RxDied) { /* Missed a Rx frame. */
+ np->stats.rx_errors++;
+ }
+ if (intr_status & TimerInt) {
+@@ -1378,16 +1358,14 @@ static u32 __set_rx_mode(struct net_devi
+ u32 rx_mode;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
++ rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys
+ | AcceptMyPhys;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to match, or accept all multicasts. */
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
++ rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ } else {
+ struct dev_mc_list *mclist;
+ int i;
+@@ -1398,7 +1376,7 @@ static u32 __set_rx_mode(struct net_devi
+ filterbit &= 0x3f;
+ mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
+ }
+- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
++ rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ }
+ iowrite32(mc_filter[0], ioaddr + MulticastFilter0);
+ iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
+@@ -1469,7 +1447,7 @@ static void netdev_set_msglevel(struct n
+ debug = value;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_settings = netdev_get_settings,
+ .set_settings = netdev_set_settings,
+@@ -1624,7 +1602,7 @@ static int w840_suspend (struct pci_dev
+
+ synchronize_irq(dev->irq);
+ netif_tx_disable(dev);
+-
++
+ np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
+
+ /* no more hardware accesses behind this line. */
+@@ -1646,14 +1624,18 @@ static int w840_resume (struct pci_dev *
+ {
+ struct net_device *dev = pci_get_drvdata (pdev);
+ struct netdev_private *np = netdev_priv(dev);
++ int retval = 0;
+
+ rtnl_lock();
+ if (netif_device_present(dev))
+ goto out; /* device not suspended */
+ if (netif_running(dev)) {
+- pci_enable_device(pdev);
+- /* pci_power_on(pdev); */
+-
++ if ((retval = pci_enable_device(pdev))) {
++ printk (KERN_ERR
++ "%s: pci_enable_device failed in resume\n",
++ dev->name);
++ goto out;
++ }
+ spin_lock_irq(&np->lock);
+ iowrite32(1, np->base_addr+PCIBusCfg);
+ ioread32(np->base_addr+PCIBusCfg);
+@@ -1671,7 +1653,7 @@ static int w840_resume (struct pci_dev *
+ }
+ out:
+ rtnl_unlock();
+- return 0;
++ return retval;
+ }
+ #endif
+
+@@ -1689,7 +1671,7 @@ static struct pci_driver w840_driver = {
+ static int __init w840_init(void)
+ {
+ printk(version);
+- return pci_module_init(&w840_driver);
++ return pci_register_driver(&w840_driver);
+ }
+
+ static void __exit w840_exit(void)
+diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
+index cf43390..61d3130 100644
+--- a/drivers/net/tulip/xircom_cb.c
++++ b/drivers/net/tulip/xircom_cb.c
+@@ -114,7 +114,7 @@ struct xircom_private {
+ /* Function prototypes */
+ static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+ static void xircom_remove(struct pci_dev *pdev);
+-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t xircom_interrupt(int irq, void *dev_instance);
+ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int xircom_open(struct net_device *dev);
+ static int xircom_close(struct net_device *dev);
+@@ -190,7 +190,7 @@ static void netdev_get_drvinfo(struct ne
+ strcpy(info->bus_info, pci_name(private->pdev));
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+@@ -334,7 +334,7 @@ static void __devexit xircom_remove(stru
+ leave("xircom_remove");
+ }
+
+-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct xircom_private *card = netdev_priv(dev);
+@@ -513,7 +513,7 @@ static struct net_device_stats *xircom_g
+ static void xircom_poll_controller(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- xircom_interrupt(dev->irq, dev, NULL);
++ xircom_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
+index 17ca7dc..a998c5d 100644
+--- a/drivers/net/tulip/xircom_tulip_cb.c
++++ b/drivers/net/tulip/xircom_tulip_cb.c
+@@ -328,13 +328,13 @@ static void xircom_init_ring(struct net_
+ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int xircom_rx(struct net_device *dev);
+ static void xircom_media_change(struct net_device *dev);
+-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t xircom_interrupt(int irq, void *dev_instance);
+ static int xircom_close(struct net_device *dev);
+ static struct net_device_stats *xircom_get_stats(struct net_device *dev);
+ static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static void set_rx_mode(struct net_device *dev);
+ static void check_duplex(struct net_device *dev);
+-static struct ethtool_ops ops;
++static const struct ethtool_ops ops;
+
+
+ /* The Xircom cards are picky about when certain bits in CSR6 can be
+@@ -1044,7 +1044,7 @@ static void check_duplex(struct net_devi
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct xircom_private *tp = netdev_priv(dev);
+@@ -1430,7 +1430,7 @@ static void xircom_get_drvinfo(struct ne
+ strcpy(info->bus_info, pci_name(tp->pdev));
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_settings = xircom_get_settings,
+ .set_settings = xircom_set_settings,
+ .get_drvinfo = xircom_get_drvinfo,
+@@ -1707,7 +1707,7 @@ static int __init xircom_init(void)
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init(&xircom_driver);
++ return pci_register_driver(&xircom_driver);
+ }
+
+
+diff --git a/drivers/net/tun.c b/drivers/net/tun.c
+index 329d9fe..151a2e1 100644
+--- a/drivers/net/tun.c
++++ b/drivers/net/tun.c
+@@ -69,7 +69,7 @@ static int debug;
+ /* Network device part of the driver */
+
+ static LIST_HEAD(tun_dev_list);
+-static struct ethtool_ops tun_ethtool_ops;
++static const struct ethtool_ops tun_ethtool_ops;
+
+ /* Net device open. */
+ static int tun_net_open(struct net_device *dev)
+@@ -177,7 +177,7 @@ static struct net_device_stats *tun_net_
+ static void tun_net_init(struct net_device *dev)
+ {
+ struct tun_struct *tun = netdev_priv(dev);
+-
++
+ switch (tun->flags & TUN_TYPE_MASK) {
+ case TUN_TUN_DEV:
+ /* Point-to-Point TUN Device */
+@@ -186,7 +186,7 @@ static void tun_net_init(struct net_devi
+ dev->mtu = 1500;
+
+ /* Zero header length */
+- dev->type = ARPHRD_NONE;
++ dev->type = ARPHRD_NONE;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+ dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
+ break;
+@@ -206,7 +206,7 @@ static void tun_net_init(struct net_devi
+
+ /* Poll */
+ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
+-{
++{
+ struct tun_struct *tun = file->private_data;
+ unsigned int mask = POLLOUT | POLLWRNORM;
+
+@@ -216,7 +216,7 @@ static unsigned int tun_chr_poll(struct
+ DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
+
+ poll_wait(file, &tun->read_wait, wait);
+-
++
+ if (!skb_queue_empty(&tun->readq))
+ mask |= POLLIN | POLLRDNORM;
+
+@@ -240,7 +240,7 @@ static __inline__ ssize_t tun_get_user(s
+
+ if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV)
+ align = NET_IP_ALIGN;
+-
++
+ if (!(skb = alloc_skb(len + align, GFP_KERNEL))) {
+ tun->stats.rx_dropped++;
+ return -ENOMEM;
+@@ -267,32 +267,31 @@ static __inline__ ssize_t tun_get_user(s
+
+ if (tun->flags & TUN_NOCHECKSUM)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+-
++
+ netif_rx_ni(skb);
+ tun->dev->last_rx = jiffies;
+-
++
+ tun->stats.rx_packets++;
+ tun->stats.rx_bytes += len;
+
+ return count;
+-}
++}
+
+ static inline size_t iov_total(const struct iovec *iv, unsigned long count)
+ {
+ unsigned long i;
+ size_t len;
+
+- for (i = 0, len = 0; i < count; i++)
++ for (i = 0, len = 0; i < count; i++)
+ len += iv[i].iov_len;
+
+ return len;
+ }
+
+-/* Writev */
+-static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
+- unsigned long count, loff_t *pos)
++static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
++ unsigned long count, loff_t pos)
+ {
+- struct tun_struct *tun = file->private_data;
++ struct tun_struct *tun = iocb->ki_filp->private_data;
+
+ if (!tun)
+ return -EBADFD;
+@@ -302,14 +301,6 @@ static ssize_t tun_chr_writev(struct fil
+ return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
+ }
+
+-/* Write */
+-static ssize_t tun_chr_write(struct file * file, const char __user * buf,
+- size_t count, loff_t *pos)
+-{
+- struct iovec iv = { (void __user *) buf, count };
+- return tun_chr_writev(file, &iv, 1, pos);
+-}
+-
+ /* Put packet to the user space buffer */
+ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
+ struct sk_buff *skb,
+@@ -326,11 +317,11 @@ static __inline__ ssize_t tun_put_user(s
+ /* Packet will be striped */
+ pi.flags |= TUN_PKT_STRIP;
+ }
+-
++
+ if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi)))
+ return -EFAULT;
+ total += sizeof(pi);
+- }
++ }
+
+ len = min_t(int, skb->len, len);
+
+@@ -343,10 +334,10 @@ static __inline__ ssize_t tun_put_user(s
+ return total;
+ }
+
+-/* Readv */
+-static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
+- unsigned long count, loff_t *pos)
++static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
++ unsigned long count, loff_t pos)
+ {
++ struct file *file = iocb->ki_filp;
+ struct tun_struct *tun = file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ struct sk_buff *skb;
+@@ -426,14 +417,6 @@ static ssize_t tun_chr_readv(struct file
+ return ret;
+ }
+
+-/* Read */
+-static ssize_t tun_chr_read(struct file * file, char __user * buf,
+- size_t count, loff_t *pos)
+-{
+- struct iovec iv = { buf, count };
+- return tun_chr_readv(file, &iv, 1, pos);
+-}
+-
+ static void tun_setup(struct net_device *dev)
+ {
+ struct tun_struct *tun = netdev_priv(dev);
+@@ -480,8 +463,8 @@ static int tun_set_iff(struct file *file
+ if (tun->owner != -1 &&
+ current->euid != tun->owner && !capable(CAP_NET_ADMIN))
+ return -EPERM;
+- }
+- else if (__dev_get_by_name(ifr->ifr_name))
++ }
++ else if (__dev_get_by_name(ifr->ifr_name))
+ return -EINVAL;
+ else {
+ char *name;
+@@ -501,9 +484,9 @@ static int tun_set_iff(struct file *file
+ /* TAP device */
+ flags |= TUN_TAP_DEV;
+ name = "tap%d";
+- } else
++ } else
+ goto failed;
+-
++
+ if (*ifr->ifr_name)
+ name = ifr->ifr_name;
+
+@@ -533,7 +516,7 @@ static int tun_set_iff(struct file *file
+ err = register_netdevice(tun->dev);
+ if (err < 0)
+ goto err_free_dev;
+-
++
+ list_add(&tun->list, &tun_dev_list);
+ }
+
+@@ -557,7 +540,7 @@ static int tun_set_iff(struct file *file
+ return err;
+ }
+
+-static int tun_chr_ioctl(struct inode *inode, struct file *file,
++static int tun_chr_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+ struct tun_struct *tun = file->private_data;
+@@ -711,14 +694,14 @@ static int tun_chr_fasync(int fd, struct
+ DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on);
+
+ if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0)
+- return ret;
+-
++ return ret;
++
+ if (on) {
+- ret = f_setown(file, current->pid, 0);
++ ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
+ if (ret)
+ return ret;
+ tun->flags |= TUN_FASYNC;
+- } else
++ } else
+ tun->flags &= ~TUN_FASYNC;
+
+ return 0;
+@@ -762,17 +745,17 @@ static int tun_chr_close(struct inode *i
+ }
+
+ static struct file_operations tun_fops = {
+- .owner = THIS_MODULE,
++ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+- .read = tun_chr_read,
+- .readv = tun_chr_readv,
+- .write = tun_chr_write,
+- .writev = tun_chr_writev,
++ .read = do_sync_read,
++ .aio_read = tun_chr_aio_read,
++ .write = do_sync_write,
++ .aio_write = tun_chr_aio_write,
+ .poll = tun_chr_poll,
+ .ioctl = tun_chr_ioctl,
+ .open = tun_chr_open,
+ .release = tun_chr_close,
+- .fasync = tun_chr_fasync
++ .fasync = tun_chr_fasync
+ };
+
+ static struct miscdevice tun_miscdev = {
+@@ -856,7 +839,7 @@ static int tun_set_rx_csum(struct net_de
+ return 0;
+ }
+
+-static struct ethtool_ops tun_ethtool_ops = {
++static const struct ethtool_ops tun_ethtool_ops = {
+ .get_settings = tun_get_settings,
+ .get_drvinfo = tun_get_drvinfo,
+ .get_msglevel = tun_get_msglevel,
+@@ -883,7 +866,7 @@ static void tun_cleanup(void)
+ {
+ struct tun_struct *tun, *nxt;
+
+- misc_deregister(&tun_miscdev);
++ misc_deregister(&tun_miscdev);
+
+ rtnl_lock();
+ list_for_each_entry_safe(tun, nxt, &tun_dev_list, list) {
+@@ -891,7 +874,7 @@ static void tun_cleanup(void)
+ unregister_netdevice(tun->dev);
+ }
+ rtnl_unlock();
+-
++
+ }
+
+ module_init(tun_init);
+diff --git a/drivers/net/typhoon-firmware.h b/drivers/net/typhoon-firmware.h
+index 2bf47d9..182d69e 100644
+--- a/drivers/net/typhoon-firmware.h
++++ b/drivers/net/typhoon-firmware.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 1999-2004 3Com Corporation. All Rights Reserved.
++ * Copyright 1999-2004 3Com Corporation. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms of the 3c990img.h
+ * microcode software are permitted provided that the following conditions
+@@ -29,3750 +29,3750 @@
+ * (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
+ * EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
+ * COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
+- */
++ */
+
+ /* ver 03.001.008 */
+ static const u8 typhoon_firmware_image[] = {
+-0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00,
+-0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0xb1, 0xd4,
+-0x4c, 0xb8, 0xd0, 0x4b, 0x32, 0x02, 0xd4, 0xee, 0x73, 0x7e, 0x0b, 0x13,
+-0x9b, 0xc0, 0xae, 0xf4, 0x40, 0x01, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00,
+-0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea,
+-0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
+-0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc5, 0x14, 0x00, 0xea,
+-0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1,
+-0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
+-0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1,
+-0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 0x00, 0xa0, 0xa0, 0xe1,
+-0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0xa8, 0x10, 0x9f, 0xe5,
+-0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5,
+-0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe3,
+-0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+-0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+-0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+-0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+-0x6c, 0xd0, 0x9f, 0xe5, 0x9b, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3,
+-0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5,
+-0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb,
+-0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
+-0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 0x54, 0x10, 0x9f, 0xe5,
+-0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1,
+-0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb,
+-0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea,
+-0x15, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00,
+-0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
+-0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80,
+-0xad, 0xde, 0xad, 0xde, 0xb0, 0xbb, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40,
+-0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xbd, 0xba, 0x21, 0x40,
+-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x58, 0x57, 0x00, 0x00, 0x86, 0x4b, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff,
+-0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4d, 0x00, 0x24, 0x28, 0x68, 0x00, 0x28,
+-0x1e, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x7b, 0xfd, 0x29, 0x68,
+-0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x15, 0xd0, 0x38, 0x01, 0x0d, 0x49,
+-0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29,
+-0x0c, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x28, 0x68, 0xc1, 0x69, 0xc0, 0x46,
+-0x29, 0x60, 0x39, 0x07, 0x41, 0x60, 0x04, 0x62, 0xc7, 0x62, 0xb0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0xe8, 0x17, 0x00, 0x80,
+-0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68,
+-0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47,
+-0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
+-0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0x00, 0x10, 0xa0, 0xe1,
+-0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
+-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
+-0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
+-0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x80, 0xe3,
+-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
+-0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+-0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3,
+-0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 0x00, 0xf0, 0x21, 0xe1,
+-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
+-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x91, 0x00, 0x00, 0xe0,
+-0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0,
+-0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3,
+-0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63,
+-0x04, 0x49, 0x05, 0xf0, 0x01, 0xfb, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00,
+-0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2,
+-0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc,
+-0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 0xbb, 0x42, 0x05, 0xd2,
+-0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 0xc8, 0x63, 0xf1, 0xe7,
+-0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x04, 0x48, 0xc1, 0x6b,
+-0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 0x68, 0x0e, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
+-0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 0x0b, 0xd2, 0xb9, 0x6e,
+-0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2,
+-0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62,
+-0x38, 0x6b, 0x02, 0xf0, 0x2d, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xe8, 0xfa,
+-0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49,
+-0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18,
+-0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
+-0xa4, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 0xc0, 0x6d, 0x02, 0x23,
+-0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 0x03, 0xd0, 0xd1, 0x63,
+-0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 0x07, 0x68, 0x7b, 0x1c,
+-0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 0xf3, 0xe7, 0x00, 0x00,
+-0xa4, 0x2a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xe0, 0x01, 0x00, 0x80,
+-0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 0x10, 0x18, 0x0a, 0x04,
+-0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 0x01, 0x0c, 0x05, 0xd0,
+-0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 0x01, 0x0c, 0xf9, 0xd1,
+-0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 0x00, 0x22, 0x00, 0x29,
+-0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f,
+-0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b,
+-0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 0x00, 0x88, 0x00, 0x06,
+-0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c,
+-0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c,
+-0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 0xc7, 0x89, 0xfb, 0x18,
+-0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 0x40, 0x7a, 0x00, 0x02,
+-0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 0x00, 0x0c, 0x3b, 0x0c,
+-0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 0x11, 0x1c, 0xff, 0xf7,
+-0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xff, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 0x82, 0x68, 0x1a, 0x40,
+-0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 0x93, 0x69, 0x01, 0x33,
+-0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 0x00, 0x68, 0x1c, 0x18,
+-0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43,
+-0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 0x82, 0x68, 0x1a, 0x40,
+-0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 0x52, 0x09, 0x0e, 0xd3,
+-0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 0xcb, 0x68, 0x02, 0x68,
+-0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68,
+-0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x80, 0x23,
+-0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 0x15, 0xd0, 0x4a, 0x68,
+-0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 0x01, 0x33, 0xd3, 0x61,
+-0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a,
+-0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 0x00, 0x28, 0x00, 0xd1,
+-0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+-0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 0x38, 0x69, 0xb9, 0x68,
+-0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 0xc0, 0x43, 0x01, 0x04,
+-0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x04, 0x1c, 0xb8, 0x68,
+-0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 0x0c, 0xd2, 0x2a, 0x68,
+-0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x05, 0xf9, 0xc0, 0x43,
+-0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x26, 0xff, 0x04, 0x1c,
+-0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 0x1a, 0xd3, 0xb8, 0x6a,
+-0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 0xed, 0xf8, 0xc0, 0x43,
+-0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 0x20, 0x23, 0xb9, 0x69,
+-0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x07, 0xe0,
+-0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x41, 0x6a,
+-0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x0c, 0x2b, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x41, 0x09,
+-0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
+-0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x53, 0xf8, 0x01, 0x1c,
+-0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69,
+-0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0,
+-0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0xc1, 0x6a,
+-0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x0c, 0x2b, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x81, 0x09,
+-0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
+-0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 0x40, 0x18, 0x01, 0x23,
+-0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 0x05, 0x04, 0x2d, 0x0c,
+-0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0x28,
+-0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 0x98, 0x42, 0x07, 0xd0,
+-0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x60, 0x6b, 0x01, 0x30,
+-0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 0xb8, 0x69, 0x18, 0x43,
+-0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 0x00, 0x20, 0xb0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+-0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 0xe0, 0x6b, 0x61, 0x6c,
+-0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 0x00, 0x20, 0x8a, 0x08,
+-0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 0x9f, 0x58, 0x03, 0xae,
+-0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 0xf7, 0xd8, 0x60, 0x6a,
+-0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
+-0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 0xff, 0xf7, 0x87, 0xfe,
+-0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x6d, 0xfe,
+-0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 0x61, 0x6a, 0x01, 0x23,
+-0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x01, 0x91,
+-0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 0x0c, 0xd2, 0xa2, 0x6a,
+-0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x2f, 0xf8, 0xc0, 0x43,
+-0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0x07, 0x1c,
+-0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 0x08, 0x18, 0x69, 0x8a,
+-0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 0xa1, 0x6c, 0x62, 0x6c,
+-0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
+-0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 0x05, 0xd0, 0x08, 0x04,
+-0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 0xf9, 0xd1, 0x38, 0x1c,
+-0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0xb0,
+-0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb4, 0x00, 0x22,
+-0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 0xdc, 0x00, 0x47, 0x18,
+-0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 0xff, 0x00, 0x80, 0x08,
+-0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 0x4d, 0x1e, 0x02, 0xc8,
+-0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 0x09, 0xd0, 0x0c, 0x04,
+-0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 0x02, 0xc8, 0x1c, 0x1c,
+-0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 0x08, 0x1c, 0xf8, 0x40,
+-0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 0x42, 0x18, 0x10, 0x0c,
+-0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c,
+-0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00,
+-0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 0x42, 0x00, 0x12, 0x18,
+-0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23,
+-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58,
+-0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 0x01, 0x30, 0x04, 0x28,
+-0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 0x09, 0x0b, 0x07, 0x48,
+-0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 0x02, 0xd0, 0x38, 0x1c,
+-0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0xa8, 0x03, 0x00, 0x80,
+-0x00, 0x40, 0x14, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x98, 0xb4, 0x14, 0x4a,
+-0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 0xc0, 0x58, 0x07, 0x03,
+-0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 0x12, 0x0b, 0x11, 0x48,
+-0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 0xe4, 0x58, 0x01, 0x23,
+-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 0xcc, 0x00, 0x01, 0x21,
+-0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 0x98, 0x42, 0x03, 0xd9,
+-0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 0x18, 0x1a, 0x84, 0x42,
+-0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 0x55, 0x55, 0x55, 0x55,
+-0x20, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x08, 0x04, 0x00, 0x80,
+-0x18, 0x04, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 0x00, 0xd0, 0x01, 0x3a,
+-0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 0xc0, 0x46, 0x3b, 0x60,
+-0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 0x08, 0x32, 0x10, 0x4b,
+-0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 0x12, 0x58, 0x0f, 0x4b,
+-0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x1b, 0x68, 0x9b, 0x00,
+-0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 0x0a, 0x48, 0xc1, 0x68,
+-0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x08, 0x4b,
+-0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 0x00, 0x20, 0xf6, 0xe7,
+-0x08, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x80,
+-0x18, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x10, 0x04, 0x00, 0x80,
+-0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 0x01, 0xb6, 0xa0, 0xe3,
+-0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 0x01, 0x7a, 0xa0, 0xe3,
+-0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 0xc8, 0x60, 0x9f, 0xe5,
+-0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 0x00, 0x00, 0x54, 0xe3,
+-0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 0x11, 0x00, 0x00, 0x0a,
+-0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x21, 0x00, 0x00, 0x0a,
+-0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
+-0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
+-0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 0x02, 0x0a, 0x14, 0xe3,
+-0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x02, 0x0a, 0xc0, 0xe3,
+-0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x80, 0x85, 0xe5,
+-0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
+-0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
+-0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x00, 0x1b,
+-0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 0x02, 0x0b, 0x14, 0xe3,
+-0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 0x20, 0x00, 0x00, 0x1b,
+-0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x18, 0x00, 0x89, 0xe5,
+-0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3,
+-0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
+-0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8,
+-0x04, 0xf0, 0x5e, 0xe2, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
+-0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 0x00, 0x20, 0xc3, 0xe1,
+-0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x0c, 0x20, 0x81, 0xe5,
+-0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0x18, 0x10, 0x9f, 0xe5,
+-0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 0xb0, 0x24, 0xc1, 0xe1,
+-0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 0x3c, 0x00, 0x81, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 0xff, 0xff, 0xff, 0xea,
+-0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 0x01, 0x16, 0xa0, 0xe3,
+-0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 0x24, 0x20, 0x91, 0xe5,
+-0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20, 0x80, 0xe5,
+-0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x80, 0xe5,
+-0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 0x2c, 0x20, 0x80, 0xe5,
+-0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11,
+-0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x10, 0x81, 0xe2,
+-0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 0x0b, 0x02, 0xa0, 0xe3,
+-0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x04, 0x00, 0x80,
+-0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5,
+-0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2,
+-0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1,
+-0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3,
+-0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5,
+-0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0x00,
+-0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
+-0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2,
+-0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0c, 0x10, 0xa0, 0xe3,
+-0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5,
+-0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5,
+-0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3,
+-0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x4c, 0x00, 0x1f, 0xe5,
+-0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea,
+-0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 0x01, 0x06, 0xa0, 0xe3,
+-0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x21, 0x1f, 0xe5,
+-0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0xe5,
+-0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 0x01, 0x06, 0xa0, 0xe3,
+-0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x92, 0xe5,
+-0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1,
+-0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x82, 0xe5,
+-0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 0x0c, 0x00, 0x81, 0xe5,
+-0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x81, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0,
+-0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c,
+-0x00, 0xf0, 0x92, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x00, 0x28,
+-0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x84, 0xf8, 0x00, 0x20, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 0x3a, 0x78, 0xd2, 0x07,
+-0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 0xff, 0x22, 0x01, 0x32,
+-0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02,
+-0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 0x5b, 0x02, 0x42, 0x68,
+-0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 0x82, 0x60, 0x00, 0xe0,
+-0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x08, 0x2a,
+-0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
+-0x0e, 0x31, 0x3c, 0xe0, 0xc1, 0x23, 0xdb, 0x00, 0x9a, 0x42, 0x03, 0xd1,
+-0x41, 0x68, 0x24, 0x4b, 0x19, 0x43, 0x3e, 0xe0, 0x23, 0x4b, 0x9a, 0x42,
+-0x04, 0xd1, 0x01, 0x23, 0x1b, 0x03, 0x41, 0x68, 0x19, 0x43, 0x36, 0xe0,
+-0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
+-0x12, 0x0c, 0x2e, 0x3a, 0x1c, 0x4b, 0x9a, 0x42, 0x2d, 0xd8, 0x01, 0x25,
+-0x42, 0x68, 0x15, 0x43, 0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02,
+-0x1a, 0x43, 0x18, 0x4b, 0x9a, 0x42, 0x22, 0xd1, 0xfb, 0x1d, 0x09, 0x33,
+-0x44, 0xcb, 0x9b, 0x07, 0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33,
+-0x9e, 0x40, 0x16, 0x43, 0x03, 0x2e, 0x18, 0xd1, 0x39, 0x7d, 0x7b, 0x7d,
+-0x1b, 0x02, 0x19, 0x43, 0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43,
+-0x41, 0x60, 0x81, 0x68, 0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x0a, 0xe0,
+-0xc1, 0x23, 0xdb, 0x00, 0x99, 0x42, 0x04, 0xd1, 0x01, 0x21, 0x89, 0x03,
+-0x29, 0x43, 0x41, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x00, 0x21, 0x08, 0x1c,
+-0xf0, 0xbc, 0x70, 0x47, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x00, 0x00,
+-0xae, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68,
+-0xd1, 0x08, 0x3f, 0xd3, 0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39,
+-0x8f, 0x78, 0x3f, 0x07, 0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d,
+-0x0d, 0x32, 0xc2, 0x60, 0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60,
+-0x08, 0x23, 0x1a, 0x43, 0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f,
+-0x92, 0x00, 0x02, 0x61, 0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43,
+-0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
+-0x12, 0x0c, 0x42, 0x61, 0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23,
+-0x42, 0x68, 0x1a, 0x43, 0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23,
+-0x42, 0x68, 0x1a, 0x43, 0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23,
+-0x42, 0x68, 0x1a, 0x43, 0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23,
+-0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76,
+-0x80, 0xbc, 0x70, 0x47, 0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78,
+-0x1b, 0x02, 0x1a, 0x43, 0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43,
+-0x02, 0x60, 0xc9, 0x78, 0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47,
+-0x80, 0xb5, 0x07, 0x1c, 0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a,
+-0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43,
+-0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42,
+-0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46,
+-0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xda, 0xf8, 0x38, 0x1c, 0x01, 0xf0,
+-0x95, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49,
+-0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18,
+-0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7,
+-0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80,
+-0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x01, 0x23, 0x9b, 0x07,
+-0x01, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02,
+-0x12, 0x0e, 0x12, 0x06, 0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40,
+-0x10, 0x43, 0x0a, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02,
+-0x1b, 0x0a, 0x19, 0x40, 0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07,
+-0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04,
+-0x1a, 0x40, 0x11, 0x43, 0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43,
+-0x00, 0x0e, 0x08, 0x43, 0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23,
+-0x81, 0x6b, 0x19, 0x40, 0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d,
+-0x39, 0x37, 0x39, 0x7b, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1,
+-0x01, 0x6b, 0xc0, 0x46, 0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d,
+-0x2d, 0x35, 0x00, 0x22, 0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50,
+-0x01, 0x32, 0x07, 0x2a, 0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63,
+-0x82, 0x6a, 0xc0, 0x46, 0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33,
+-0x5a, 0x83, 0x40, 0x6a, 0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27,
+-0x42, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1,
+-0x42, 0x69, 0x00, 0x2a, 0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a,
+-0x02, 0x29, 0x02, 0xd3, 0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0,
+-0x13, 0xf8, 0x09, 0xe0, 0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61,
+-0xc1, 0x60, 0x03, 0xe0, 0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61,
+-0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7,
+-0x6c, 0x06, 0x00, 0x80, 0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68,
+-0x00, 0x2b, 0x34, 0xd0, 0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68,
+-0x9b, 0x6a, 0xc0, 0x46, 0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19,
+-0x7f, 0x02, 0x17, 0x4b, 0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63,
+-0x07, 0x63, 0xcb, 0x1d, 0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69,
+-0x00, 0x2b, 0x01, 0xd0, 0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61,
+-0x0f, 0x1c, 0xc9, 0x68, 0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63,
+-0xf8, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60,
+-0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30,
+-0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+-0xac, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31,
+-0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32,
+-0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18,
+-0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a,
+-0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38,
+-0x92, 0x04, 0x92, 0x0c, 0x00, 0x26, 0x25, 0x4d,
+-0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 0x04, 0xd0, 0x20, 0x8a,
+-0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 0x01, 0x23, 0x9b, 0x07,
+-0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30,
+-0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c,
+-0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c,
+-0x02, 0xf0, 0x02, 0xf8, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23,
+-0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
+-0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8,
+-0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43,
+-0x20, 0x82, 0x21, 0x8a, 0x38, 0x1c, 0x00, 0xf0, 0xa2, 0xfb, 0xe8, 0x68,
+-0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
+-0xe8, 0x60, 0x30, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20,
+-0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c,
+-0xfc, 0x1d, 0xf9, 0x34, 0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35,
+-0x38, 0x48, 0xc0, 0x6a, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18,
+-0x01, 0x20, 0x80, 0x07, 0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
+-0x00, 0x90, 0x01, 0x23, 0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43,
+-0x00, 0x68, 0x38, 0x1c, 0x29, 0x1c, 0x00, 0xf0, 0xc2, 0xfa, 0xa8, 0x88,
+-0x41, 0x07, 0x01, 0xd0, 0x00, 0x20, 0x51, 0xe0, 0x29, 0x89, 0x09, 0x18,
+-0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18,
+-0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a,
+-0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0,
+-0x33, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69,
+-0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58,
+-0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28,
+-0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31,
+-0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28,
+-0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xae, 0xfb,
+-0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b,
+-0xff, 0xf7, 0xa6, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43,
+-0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0x9e, 0xfb, 0xa1, 0x6b, 0x08, 0x4a,
+-0x01, 0x20, 0xff, 0xf7, 0x99, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46,
+-0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x4c, 0x2a, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00,
+-0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a,
+-0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49,
+-0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48,
+-0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00,
+-0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d,
+-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68,
+-0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a,
+-0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b,
+-0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69,
+-0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x26, 0xf9, 0x28, 0x6b, 0x79, 0x69,
+-0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b,
+-0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50,
+-0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00,
+-0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
+-0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90,
+-0x90, 0x49, 0x42, 0x00, 0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0,
+-0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28,
+-0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a,
+-0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0,
+-0x67, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98,
+-0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28,
+-0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a,
+-0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60,
+-0x62, 0xe0, 0x0a, 0x98, 0x02, 0x28, 0x5f, 0xd1, 0x09, 0x98, 0x40, 0x0c,
+-0x73, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43,
+-0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18,
+-0x0c, 0x38, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x8a, 0x00, 0x6b, 0x4b,
+-0xd6, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
+-0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x00, 0x21, 0x83, 0x1e,
+-0x0c, 0x93, 0x68, 0x4a, 0x16, 0x6b, 0xc0, 0x46, 0x0b, 0x96, 0x8a, 0x00,
+-0x0c, 0x9b, 0x9b, 0x18, 0x0b, 0x9e, 0x9e, 0x19, 0x01, 0x23, 0x9b, 0x07,
+-0x33, 0x43, 0x1b, 0x68, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x04, 0x29,
+-0xf1, 0xd3, 0x69, 0x46, 0x8b, 0x1c, 0x07, 0x93, 0x00, 0x21, 0x08, 0x91,
+-0x04, 0xae, 0x4a, 0x00, 0x07, 0x9b, 0x9b, 0x5a, 0xb2, 0x5a, 0x93, 0x42,
+-0x11, 0xd0, 0x58, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xf8, 0x68,
+-0x41, 0x1c, 0xf9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x20, 0x23,
+-0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x80, 0x23, 0x18, 0x43, 0x38, 0x82,
+-0x8f, 0xe7, 0x01, 0x31, 0x06, 0x29, 0xe4, 0xd3, 0x08, 0x99, 0x00, 0x29,
+-0x0d, 0xd1, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0x04, 0xd1,
+-0x39, 0x8a, 0x02, 0x23, 0x19, 0x43, 0x03, 0xe0, 0x0c, 0xe0, 0x39, 0x8a,
+-0x08, 0x23, 0x19, 0x43, 0x39, 0x82, 0x29, 0x6b, 0x08, 0x18, 0x01, 0x23,
+-0x9b, 0x07, 0x01, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x20, 0x76,
+-0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x11, 0x30, 0x18, 0x43, 0x00, 0x68,
+-0x01, 0x06, 0x09, 0x0e, 0x00, 0xe0, 0x19, 0xe0, 0x35, 0x48, 0x2a, 0x6b,
+-0xc0, 0x46, 0xea, 0x62, 0x04, 0x29, 0x4f, 0xd1, 0x01, 0x21, 0xc6, 0x1d,
+-0xff, 0x36, 0x5a, 0x36, 0x31, 0x72, 0x0a, 0x99, 0x02, 0x29, 0x1e, 0xd1,
+-0x09, 0x99, 0x09, 0x0e, 0x49, 0x06, 0x1a, 0xd1, 0xe1, 0x1d, 0x05, 0x31,
+-0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x39, 0x1a, 0xe0,
+-0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68,
+-0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04,
+-0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1,
+-0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d,
+-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60,
+-0xe8, 0x6a, 0xc0, 0x46, 0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x88, 0xfc,
+-0x20, 0x7e, 0x33, 0x28, 0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21,
+-0x14, 0x4c, 0xc0, 0x46, 0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0,
+-0x85, 0xf8, 0x28, 0x6b, 0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c,
+-0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20,
+-0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1,
+-0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd,
+-0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x70, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00,
+-0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80,
+-0xac, 0xab, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80,
+-0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48,
+-0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31,
+-0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22,
+-0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46,
+-0x9a, 0x61, 0xfa, 0x1d, 0xff, 0x32, 0x5a, 0x32, 0x13, 0x7a, 0x1b, 0x4a,
+-0x00, 0x2b, 0x0b, 0xd0, 0x15, 0x8a, 0x2e, 0x0a, 0x36, 0x02, 0x33, 0x23,
+-0x2b, 0x40, 0x9b, 0x00, 0x1e, 0x43, 0xcc, 0x23, 0x2b, 0x40, 0x9b, 0x08,
+-0x33, 0x43, 0x13, 0x82, 0x12, 0x8a, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x83,
+-0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46,
+-0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46,
+-0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a,
+-0x01, 0xf0, 0x32, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30,
+-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
+-0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a,
+-0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68,
+-0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31,
+-0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0,
+-0x0f, 0xf8, 0x06, 0xe0, 0x32, 0x2b, 0x08, 0xd1, 0x8b, 0x70, 0x01, 0x1c,
+-0x10, 0x1c, 0x00, 0xf0, 0x3c, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x20, 0x88, 0x70, 0xf9, 0xe7, 0x90, 0xb4, 0xca, 0x1d,
+-0xf9, 0x32, 0x33, 0x27, 0xcc, 0x1d, 0xff, 0x34, 0x4a, 0x34, 0xd3, 0x6a,
+-0xc0, 0x46, 0xa7, 0x70, 0xff, 0x31, 0x41, 0x31, 0x07, 0x6c, 0xc0, 0x46,
+-0x4f, 0x61, 0xfb, 0x18, 0x39, 0x1c, 0x9f, 0x1e, 0x01, 0x23, 0x9b, 0x07,
+-0xfc, 0x1c, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x9b, 0x00,
+-0x1b, 0x04, 0x1b, 0x0c, 0xc9, 0x18, 0x08, 0x31, 0x01, 0x64, 0x01, 0x23,
+-0x9b, 0x07, 0xb9, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x34, 0x30, 0x01, 0x76,
+-0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d,
+-0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43,
+-0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32,
+-0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d,
+-0xff, 0x37, 0x4a, 0x37, 0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d,
+-0xff, 0x34, 0x3a, 0x34, 0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30,
+-0xe8, 0x60, 0x60, 0x69, 0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07,
+-0x38, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43,
+-0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63,
+-0xf8, 0x1d, 0x03, 0x30, 0xff, 0xf7, 0xfc, 0xfb, 0x20, 0x62, 0xf8, 0x1d,
+-0x07, 0x30, 0xff, 0xf7, 0xf7, 0xfb, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76,
+-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98,
+-0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
+-0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40,
+-0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c,
+-0x80, 0x23, 0x23, 0x40, 0x01, 0x9f, 0xff, 0x37, 0x41, 0x37, 0x00, 0x2b,
+-0x3c, 0xd0, 0x0c, 0x23, 0x00, 0x93, 0x00, 0x23, 0x9d, 0x00, 0xae, 0x18,
+-0x36, 0x69, 0x6d, 0x18, 0x6e, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3,
+-0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 0x76, 0x6a, 0x6d, 0x18, 0xae, 0x62,
+-0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x01, 0x9b, 0xff, 0x33, 0x51, 0x33,
+-0x9b, 0x78, 0x33, 0x2b, 0x0e, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
+-0x01, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23,
+-0x9b, 0x07, 0xc5, 0x1d, 0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x16, 0xe0,
+-0x7b, 0x69, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
+-0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x7d, 0x69, 0x5d, 0x1b, 0x01, 0x23,
+-0x9b, 0x07, 0xc6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0xeb, 0x18,
+-0x0c, 0x3b, 0x02, 0xe0, 0x00, 0x23, 0x00, 0x93, 0x4b, 0x81, 0xcb, 0x80,
+-0x63, 0x09, 0x49, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xc4, 0x1d, 0x05, 0x34,
+-0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x81, 0x01, 0x23, 0x9b, 0x07,
+-0xc4, 0x1d, 0x0d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0x0c, 0x89, 0x1b, 0x1b,
+-0x00, 0x9c, 0x1c, 0x1b, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43,
+-0x00, 0x68, 0x20, 0x18, 0x88, 0x80, 0x38, 0x6a, 0x04, 0x0e, 0xff, 0x23,
+-0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 0x1c, 0x43, 0xff, 0x23, 0x1b, 0x02,
+-0x03, 0x40, 0x1b, 0x02, 0x23, 0x43, 0x00, 0x06, 0x18, 0x43, 0xc8, 0x60,
+-0x78, 0x6a, 0x07, 0x0e, 0xff, 0x23, 0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a,
+-0x1f, 0x43, 0xff, 0x23, 0x1b, 0x02, 0x03, 0x40, 0x1b, 0x02, 0x3b, 0x43,
+-0x00, 0x06, 0x18, 0x43, 0x08, 0x61, 0xd0, 0x6b, 0xc0, 0x46, 0xc8, 0x63,
+-0x90, 0x6b, 0xc0, 0x46, 0x08, 0x64, 0x50, 0x6c, 0xc0, 0x46, 0x48, 0x64,
+-0x10, 0x6c, 0xc0, 0x46, 0x88, 0x64, 0xd0, 0x6c, 0xc0, 0x46, 0xc8, 0x64,
+-0x90, 0x6c, 0xc0, 0x46, 0x08, 0x65, 0x02, 0xe0, 0x00, 0x23, 0x0b, 0x81,
+-0x8b, 0x80, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+-0x0f, 0x4a, 0x93, 0x89, 0x01, 0x33, 0x93, 0x81, 0xc2, 0x1d, 0xf9, 0x32,
+-0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61,
+-0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b,
+-0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83,
+-0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xc2, 0xf8,
+-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
+-0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20,
+-0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30,
+-0x00, 0x29, 0x15, 0xd0, 0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25,
+-0x0a, 0xe0, 0xff, 0xf7, 0x89, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a,
+-0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0,
+-0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69,
+-0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0xa8, 0xfc,
+-0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x5a, 0xf8,
+-0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80,
+-0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x01, 0x24,
+-0x00, 0x25, 0x00, 0x28, 0x0b, 0xd1, 0x38, 0x6a, 0x00, 0x28, 0x03, 0xd1,
+-0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1f, 0x48, 0x01, 0x6e,
+-0x01, 0x31, 0x01, 0x66, 0x03, 0xe0, 0x48, 0x68, 0xc4, 0x23, 0x18, 0x40,
+-0x03, 0xd1, 0x38, 0x6a, 0x00, 0xf0, 0x0c, 0xfc, 0x2f, 0xe0, 0x38, 0x1c,
+-0x00, 0xf0, 0x1c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7b, 0xfa, 0xb8, 0x68,
+-0xc0, 0x08, 0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd1, 0xfb, 0xb8, 0x68,
+-0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60,
+-0x10, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29,
+-0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46,
+-0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x14, 0xf8, 0x0b, 0xe0, 0x39, 0x6a,
+-0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68,
+-0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c,
+-0xbd, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
+-0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c,
+-0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68,
+-0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xc3, 0xfb, 0x00, 0x20,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00,
+-0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36,
+-0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 0x33, 0x4c, 0x34, 0x4b,
+-0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x00, 0xf0,
+-0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18,
+-0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
+-0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d,
+-0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d,
+-0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30,
+-0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20,
+-0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3,
+-0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 0x09, 0x18, 0x78, 0x68,
+-0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 0x61, 0x89, 0xe2, 0x88,
+-0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x5a, 0xff,
+-0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43,
+-0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x52, 0xff, 0x01, 0x22, 0x52, 0x04,
+-0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x4a, 0xff,
+-0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 0x45, 0xff, 0x01, 0x20,
+-0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 0xea, 0x1d, 0xf9, 0x32,
+-0x51, 0x62, 0xd9, 0xe7, 0x28, 0xac, 0x20, 0x40, 0xff, 0xff, 0x00, 0x00,
+-0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00,
+-0x14, 0xac, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0,
+-0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21,
+-0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31,
+-0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 0x00, 0x68, 0x03, 0xf0,
+-0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34,
+-0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 0x44, 0x4a, 0x92, 0x6a,
+-0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xea, 0x1d,
+-0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68,
+-0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 0x3c, 0x4d, 0x01, 0x2b,
+-0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68,
+-0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 0xc5, 0xfc, 0x20, 0x78,
+-0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20,
+-0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30,
+-0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20,
+-0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 0x01, 0x30, 0x06, 0x28,
+-0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 0x11, 0x0a, 0x29, 0xd3,
+-0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50,
+-0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19,
+-0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00,
+-0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 0x06, 0x29, 0xf8, 0xd3,
+-0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 0x00, 0x9d, 0x55, 0x40,
+-0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 0x89, 0x6a, 0x08, 0x18,
+-0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 0x51, 0x40, 0x41, 0x65,
+-0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 0x38, 0x1c,
+-0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x08, 0x4a, 0x50, 0x68,
+-0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xa4, 0xfa,
+-0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 0x01, 0xf0, 0xde, 0xfa,
+-0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x6c, 0x06, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
+-0xac, 0xab, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
+-0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43,
+-0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07,
+-0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 0x43, 0x68, 0x1c, 0x04,
+-0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 0x33, 0x43, 0x1b, 0x68,
+-0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 0xff, 0x26, 0x36, 0x02,
+-0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c,
+-0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79,
+-0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89,
+-0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18,
+-0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
+-0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3,
+-0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36,
+-0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18,
+-0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23,
+-0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c,
+-0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33,
+-0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b,
+-0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43,
+-0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
+-0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x64, 0xab, 0x0e,
+-0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x3d, 0x34, 0x23, 0x43,
+-0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
+-0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x64, 0x01, 0x23,
+-0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46,
+-0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x41, 0x34, 0x23, 0x43,
+-0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 0x0f, 0xe0, 0xfb, 0x1f,
+-0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 0xff, 0x18, 0x03, 0x69,
+-0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 0x2c, 0xe0, 0x00, 0x23,
+-0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 0x8b, 0x80, 0x0b, 0x81,
+-0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00,
+-0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 0x00, 0x20, 0x87, 0x00,
+-0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43,
+-0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3,
+-0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23,
+-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30,
+-0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2,
+-0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46,
+-0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68,
+-0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69,
+-0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc,
+-0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60,
+-0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 0x01, 0x61, 0xf2, 0xe7,
+-0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98,
+-0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27,
+-0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 0x00, 0x2b, 0x19, 0xd0,
+-0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18,
+-0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04,
+-0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0,
+-0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23,
+-0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b,
+-0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43,
+-0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68,
+-0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0,
+-0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0,
+-0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89,
+-0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68,
+-0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c,
+-0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46,
+-0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87,
+-0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b,
+-0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c,
+-0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 0x07, 0x9b, 0x5b, 0x89,
+-0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 0x07, 0x9b, 0x9b, 0x89,
+-0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00,
+-0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a,
+-0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 0xc0, 0x46, 0xab, 0x83,
+-0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23,
+-0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07,
+-0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31,
+-0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42,
+-0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x05, 0x9b,
+-0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b,
+-0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33,
+-0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 0xbb, 0x08, 0x9b, 0x07,
+-0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b,
+-0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07,
+-0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95,
+-0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9d, 0xc0, 0x46,
+-0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 0x1b, 0x02, 0x1d, 0x43,
+-0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 0x2b, 0x43, 0x55, 0x00,
+-0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b,
+-0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e,
+-0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f,
+-0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40,
+-0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c,
+-0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78,
+-0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3,
+-0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00,
+-0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33,
+-0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93,
+-0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35,
+-0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68,
+-0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0,
+-0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1,
+-0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46,
+-0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b,
+-0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46,
+-0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61,
+-0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83,
+-0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+-0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68,
+-0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68,
+-0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48,
+-0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0,
+-0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98,
+-0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xe1, 0xff, 0x68, 0x46,
+-0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0,
+-0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43,
+-0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x84, 0xfe,
+-0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
+-0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46,
+-0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68,
+-0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68,
+-0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69,
+-0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28,
+-0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7,
+-0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60,
+-0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22,
+-0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 0x03, 0x23, 0xfc, 0x1d,
+-0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68,
+-0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68,
+-0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62,
+-0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60,
+-0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64,
+-0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
+-0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
+-0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23,
+-0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0x20, 0x6b, 0x01, 0x30,
+-0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69,
+-0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29,
+-0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68,
+-0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c,
+-0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe,
+-0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29,
+-0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0,
+-0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46,
+-0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31,
+-0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1,
+-0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 0x00, 0x28, 0x03, 0xd0,
+-0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 0x30, 0x7b, 0x00, 0x28,
+-0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 0x1b, 0x23, 0xdb, 0x01,
+-0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 0xe0, 0x6a, 0xb0, 0x42,
+-0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3,
+-0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30,
+-0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x90, 0xff,
+-0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60,
+-0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xe0, 0x6b,
+-0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0x07, 0xfc, 0x02, 0x23,
+-0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60,
+-0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0x64, 0x2d, 0x00, 0x80,
+-0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x1d, 0x48,
+-0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 0x09, 0x31, 0x01, 0x27,
+-0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 0xa3, 0x42, 0x10, 0xd0,
+-0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 0x00, 0x2b, 0x0a, 0xd0,
+-0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 0x13, 0x4b, 0xc0, 0x46,
+-0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 0x93, 0x82, 0xc3, 0x8b,
+-0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 0x0e, 0xdb, 0x84, 0x8a,
+-0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 0x44, 0x8a, 0xc5, 0x8a,
+-0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 0x4f, 0x70, 0x43, 0x82,
+-0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 0x51, 0x82, 0x80, 0x8a,
+-0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 0xe8, 0x0e, 0x00, 0x80,
+-0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0,
+-0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20,
+-0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06,
+-0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00,
+-0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00,
+-0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28,
+-0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46,
+-0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3,
+-0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73,
+-0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c,
+-0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06,
+-0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9,
+-0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0,
+-0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22,
+-0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9,
+-0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18,
+-0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d,
+-0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 0x08, 0xd0, 0x8b, 0x00,
+-0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e,
+-0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0,
+-0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 0x01, 0x30, 0x00, 0x06,
+-0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4,
+-0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a,
+-0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70,
+-0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72,
+-0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a,
+-0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47,
+-0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48,
+-0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61,
+-0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c,
+-0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18,
+-0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 0x61, 0xfe, 0x08, 0xbc,
+-0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40,
+-0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x95, 0x4a, 0xd0, 0x68,
+-0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 0x38, 0x89, 0x00, 0x28,
+-0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60,
+-0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 0x8e, 0x48, 0xc3, 0x6b,
+-0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xd4, 0x18,
+-0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 0x81, 0x42, 0x05, 0xd1,
+-0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf3, 0xe0,
+-0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 0x01, 0x20, 0x00, 0x21,
+-0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 0x58, 0x70, 0xb9, 0x82,
+-0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x05, 0x93, 0x5b, 0x69,
+-0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 0xc0, 0x46, 0x39, 0x61,
+-0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c,
+-0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 0x05, 0xd1, 0x3b, 0x2a,
+-0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x73,
+-0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68,
+-0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x09, 0x04,
+-0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 0x09, 0x06, 0x09, 0x0e,
+-0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46,
+-0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32,
+-0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 0xb3, 0x07, 0x1a, 0x43,
+-0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20,
+-0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b,
+-0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 0x01, 0x20, 0x09, 0x01,
+-0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 0x65, 0xd1, 0x51, 0x49,
+-0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 0x48, 0x69, 0x01, 0x30,
+-0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
+-0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 0x22, 0x6a, 0xa3, 0x6b,
+-0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 0x22, 0x6b, 0xc0, 0x46,
+-0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 0x00, 0x22, 0xfa, 0x61,
+-0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 0x01, 0x22, 0x00, 0xe0,
+-0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 0x7a, 0x68, 0xc0, 0x46,
+-0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0xb0, 0x83,
+-0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 0x60, 0x20, 0xb0, 0x83,
+-0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 0x9a, 0x42, 0x03, 0xd8,
+-0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 0x21, 0x6b, 0xc0, 0x46,
+-0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 0x2d, 0x49, 0x78, 0x6b,
+-0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 0xc0, 0x46, 0xfa, 0x60,
+-0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 0xc0, 0x46, 0xb8, 0x61,
+-0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 0x37, 0xf9, 0x04, 0x98,
+-0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 0x78, 0x8a, 0xf1, 0x8b,
+-0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 0x04, 0xe0, 0x38, 0xe0,
+-0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 0x81, 0x07, 0x02, 0xd0,
+-0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 0x09, 0x1a, 0xa2, 0x6b,
+-0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 0x20, 0x62, 0xe8, 0x7b,
+-0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 0x05, 0x99, 0x48, 0x69,
+-0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 0x73, 0xfa, 0x18, 0x48,
+-0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 0x0a, 0xd1, 0x20, 0x6a,
+-0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 0x88, 0x42, 0x03, 0xd0,
+-0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x40, 0x04,
+-0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 0xe0, 0x68, 0x00, 0x28,
+-0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 0xa8, 0x73, 0xed, 0xe7,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xa4, 0x2a, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55,
+-0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 0xc4, 0x0b, 0x00, 0x00,
+-0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89,
+-0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c,
+-0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2,
+-0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31,
+-0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b,
+-0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0xb3, 0xf8, 0x01, 0x20,
+-0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x18, 0x1a, 0x00, 0x80,
+-0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c,
+-0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89,
+-0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7,
+-0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 0x00, 0x09, 0x1f, 0xd3,
+-0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a,
+-0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
+-0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
+-0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0,
+-0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 0x46, 0xe0, 0x01, 0x30,
+-0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 0x5c, 0x18, 0xe4, 0x88,
+-0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
+-0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 0xd8, 0x42, 0xf0, 0xdc,
+-0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 0x0b, 0x23, 0x1b, 0x02,
+-0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x98,
+-0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 0x9b, 0x01,
+-0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 0x17, 0xd0, 0xfe, 0x1d,
+-0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18,
+-0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7b, 0xfc, 0x01, 0x28,
+-0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 0x9b, 0x01,
+-0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 0x01, 0x2a,
+-0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0xf8, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
+-0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
+-0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89,
+-0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08,
+-0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 0x38, 0x1c, 0x00, 0xf0,
+-0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c,
+-0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47,
+-0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04,
+-0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29,
+-0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43,
+-0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c,
+-0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0,
+-0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68,
+-0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91,
+-0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab,
+-0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43,
+-0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69,
+-0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b,
+-0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a,
+-0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26,
+-0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0,
+-0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0,
+-0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42,
+-0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43,
+-0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43,
+-0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43,
+-0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a,
+-0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68,
+-0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43,
+-0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43,
+-0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43,
+-0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68,
+-0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c,
+-0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c,
+-0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c,
+-0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 0x91, 0x42, 0x00, 0xdd,
+-0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d,
+-0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 0x33, 0x4a, 0xc0, 0x46,
+-0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 0xe1, 0x6d, 0x41, 0x18,
+-0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0,
+-0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 0xb1, 0x6a, 0x81, 0x42,
+-0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 0x2f, 0x23, 0x9b, 0x01,
+-0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 0x92, 0x00, 0x27, 0x4b,
+-0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 0x4a, 0x08, 0x05, 0xd3,
+-0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd6, 0xff,
+-0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x0b, 0x78, 0x00, 0x2b,
+-0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 0x1e, 0x4a, 0xc0, 0x46,
+-0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce,
+-0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 0xc7, 0xfe, 0x14, 0x48,
+-0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 0x00, 0xd3, 0x25, 0x60,
+-0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 0x3a, 0x6b, 0xc0, 0x46,
+-0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x68, 0x00, 0x29,
+-0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0x04, 0xe0, 0x39, 0x6b,
+-0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0xc1, 0x60,
+-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00,
+-0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
+-0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02,
+-0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35,
+-0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 0x01, 0x38, 0x78, 0x61,
+-0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0xb8, 0x60,
+-0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa,
+-0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71,
+-0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1b, 0x00, 0x80,
+-0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40,
+-0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47,
+-0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08,
+-0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30,
+-0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x23,
+-0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 0x00, 0x68, 0x16, 0x4c,
+-0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68,
+-0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 0x00, 0xf0, 0x22, 0xf8,
+-0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21,
+-0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 0xf2, 0xd0, 0x51, 0x21,
+-0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 0x02, 0xd1, 0x60, 0x6b,
+-0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xf7, 0xe7,
+-0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 0x01, 0x23, 0x9b, 0x07,
+-0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c,
+-0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00,
+-0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 0x4b, 0x6b, 0x9a, 0x42,
+-0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
+-0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0,
+-0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
+-0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49,
+-0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20,
+-0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68,
+-0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 0xdf, 0xfd, 0x88, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 0xf5, 0x2c, 0xff, 0xff,
+-0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
+-0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60,
+-0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x4c, 0xfc,
+-0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0,
+-0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18,
+-0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23,
+-0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48,
+-0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 0x35, 0x4d, 0x10, 0x29,
+-0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e,
+-0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x68, 0x6a,
+-0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2,
+-0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 0x68, 0x6a, 0xb8, 0x42,
+-0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b,
+-0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49,
+-0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c,
+-0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 0x09, 0x6e, 0x8c, 0x18,
+-0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b,
+-0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18,
+-0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31,
+-0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 0x52, 0x05, 0x3a, 0x43,
+-0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18,
+-0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 0x02, 0xf0, 0x4a, 0xfd,
+-0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 0xe9, 0x6a, 0x2a, 0x6b,
+-0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66,
+-0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 0x68, 0x0e, 0x00, 0x80,
+-0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x5d, 0x2e, 0xff, 0xff,
+-0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40,
+-0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 0xd1, 0x60, 0x02, 0x23,
+-0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0x90, 0xee, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x01, 0x20, 0x80, 0x02,
+-0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23,
+-0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c,
+-0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 0x68, 0x46, 0x00, 0xf0,
+-0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30,
+-0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73,
+-0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0,
+-0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23,
+-0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21,
+-0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+-0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40,
+-0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f,
+-0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b,
+-0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18,
+-0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 0x04, 0x68, 0xc0, 0x46,
+-0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46,
+-0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0x08, 0x69,
+-0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 0x38, 0x6a, 0xc0, 0x46,
+-0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 0x18, 0x1c, 0x90, 0xbc,
+-0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 0xc8, 0x69, 0x19, 0x23,
+-0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b,
+-0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 0xca, 0x61, 0x70, 0x47,
+-0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 0x40, 0x32, 0x00, 0x29,
+-0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0xd0, 0x61,
+-0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68,
+-0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69,
+-0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00,
+-0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21,
+-0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a,
+-0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23,
+-0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07,
+-0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0,
+-0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 0x04, 0x29, 0xe4, 0xd3,
+-0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0,
+-0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a,
+-0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40,
+-0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 0xa3, 0x40, 0x00, 0x25,
+-0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 0x5d, 0xd9, 0x1c, 0x1c,
+-0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96,
+-0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92,
+-0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 0x05, 0x9c, 0xe3, 0x40,
+-0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c,
+-0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23,
+-0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
+-0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d,
+-0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96,
+-0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68,
+-0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36,
+-0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23,
+-0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b,
+-0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14,
+-0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0,
+-0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a,
+-0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28,
+-0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x2b, 0xf8, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f,
+-0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3,
+-0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0xde, 0xfe,
+-0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20,
+-0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28,
+-0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60,
+-0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28,
+-0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28,
+-0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7,
+-0xb9, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3,
+-0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79,
+-0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+-0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x8c, 0x06, 0x00, 0x80,
+-0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
+-0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46,
+-0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
+-0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a,
+-0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65,
+-0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18,
+-0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18,
+-0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d,
+-0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xfc, 0xf7, 0xca, 0xff,
+-0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
+-0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 0x01, 0xf0, 0xc6, 0xfb,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+-0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20,
+-0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x59, 0xfc, 0x07, 0x1c,
+-0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01,
+-0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46,
+-0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d,
+-0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 0x89, 0xf9, 0x38, 0x1c,
+-0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80,
+-0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68,
+-0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59,
+-0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42,
+-0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c,
+-0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31,
+-0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 0x5d, 0xfc, 0xf8, 0x6d,
+-0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02,
+-0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73,
+-0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x4c, 0xfc, 0xb8, 0x6d, 0xc0, 0x46,
+-0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2,
+-0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xcc, 0xfc,
+-0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0,
+-0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64,
+-0x20, 0x1c, 0xfc, 0xf7, 0x31, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43,
+-0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c,
+-0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07,
+-0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68,
+-0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31,
+-0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19,
+-0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18,
+-0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42,
+-0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a,
+-0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
+-0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
+-0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0,
+-0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62,
+-0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c,
+-0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0,
+-0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18,
+-0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9,
+-0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
+-0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 0x82, 0x42, 0xf3, 0xd8,
+-0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40,
+-0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68,
+-0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x78, 0x6c,
+-0xfc, 0xf7, 0x95, 0xff, 0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c,
+-0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04,
+-0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
+-0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
+-0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c,
+-0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68,
+-0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0,
+-0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7,
+-0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69,
+-0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40,
+-0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68,
+-0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c,
+-0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c,
+-0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c,
+-0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 0x7d, 0x4e, 0x0b, 0x23,
+-0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25,
+-0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 0x00, 0x28, 0x12, 0xd0,
+-0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x68,
+-0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 0x01, 0x35, 0xa8, 0x00,
+-0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x68, 0x00, 0x28,
+-0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68,
+-0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c,
+-0x28, 0x1c, 0xfc, 0xf7, 0x10, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e,
+-0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18,
+-0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88,
+-0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04,
+-0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
+-0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
+-0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89,
+-0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61,
+-0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46,
+-0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60,
+-0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 0xe8, 0xfe, 0x38, 0x86,
+-0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 0x03, 0xff, 0x78, 0x86,
+-0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 0xc8, 0xfe, 0x00, 0x90,
+-0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04,
+-0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02,
+-0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42,
+-0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02,
+-0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c,
+-0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xa3, 0xfe,
+-0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 0x9e, 0xfe, 0x06, 0x1c,
+-0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
+-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c,
+-0xfc, 0xf7, 0x8f, 0xfe, 0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61,
+-0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22,
+-0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02,
+-0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c,
+-0xfc, 0xf7, 0x77, 0xfe, 0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61,
+-0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69,
+-0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7,
+-0x66, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08,
+-0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04,
+-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46,
+-0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c,
+-0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81,
+-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
+-0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69,
+-0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98,
+-0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18,
+-0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1,
+-0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61,
+-0x04, 0x98, 0xfc, 0xf7, 0x09, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69,
+-0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42,
+-0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a,
+-0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62,
+-0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1,
+-0x38, 0x1c, 0xfc, 0xf7, 0x19, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60,
+-0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68,
+-0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c,
+-0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68,
+-0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c,
+-0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98,
+-0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e,
+-0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
+-0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
+-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x20, 0x8e,
+-0xfc, 0xf7, 0xcb, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 0x02, 0x99, 0xfc, 0xf7,
+-0xc6, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02,
+-0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46,
+-0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xb7, 0xfd, 0x61, 0x69, 0x01, 0x31,
+-0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e,
+-0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
+-0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
+-0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x71, 0x60, 0x03, 0x98,
+-0xfc, 0xf7, 0x9b, 0xfd, 0x21, 0x69, 0x49, 0x19, 0x21, 0x61, 0xa1, 0x68,
+-0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43,
+-0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x8d, 0xfd, 0x38, 0x82, 0x61, 0x6e,
+-0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99,
+-0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d,
+-0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38,
+-0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68,
+-0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04,
+-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46,
+-0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
+-0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04,
+-0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x51, 0xfd, 0x40, 0xc7, 0x02, 0x9a,
+-0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29,
+-0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c,
+-0x16, 0x1c, 0xfc, 0xf7, 0x40, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e,
+-0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32,
+-0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0,
+-0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5,
+-0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b,
+-0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99,
+-0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0,
+-0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91,
+-0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42,
+-0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a,
+-0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88,
+-0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21,
+-0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06,
+-0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1,
+-0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a,
+-0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c,
+-0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 0x07, 0x9b, 0x01, 0xf0,
+-0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0,
+-0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+-0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8,
+-0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90,
+-0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60,
+-0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 0x01, 0x98, 0x01, 0x38,
+-0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 0x44, 0x63, 0x01, 0x98,
+-0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0,
+-0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92,
+-0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x09, 0x9b, 0x01, 0xf0,
+-0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02,
+-0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07,
+-0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0x85, 0xfc,
+-0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68,
+-0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 0x8b, 0xf9, 0x38, 0x1c,
+-0xfc, 0xf7, 0x8c, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3,
+-0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80,
+-0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71,
+-0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60,
+-0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 0x49, 0x08, 0x49, 0x00,
+-0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 0x38, 0x1c, 0x00, 0xf0,
+-0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43,
+-0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8,
+-0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c,
+-0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0,
+-0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68,
+-0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68,
+-0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42,
+-0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 0x31, 0x1c, 0x01, 0x3e,
+-0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
+-0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60,
+-0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68,
+-0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47,
+-0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68,
+-0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46,
+-0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80,
+-0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46,
+-0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80,
+-0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
+-0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
+-0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b,
+-0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7,
+-0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7,
+-0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb,
+-0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xee, 0xe7,
+-0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
+-0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
+-0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43,
+-0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88,
+-0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47,
+-0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xf8, 0xe7, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c,
+-0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33,
+-0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68,
+-0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1,
+-0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18,
+-0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20,
+-0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60,
+-0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46,
+-0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a,
+-0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80,
+-0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7,
+-0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23,
+-0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55,
+-0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 0x7c, 0x29, 0x00, 0x80,
+-0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
+-0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40,
+-0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18,
+-0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08,
+-0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c,
+-0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d,
+-0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65,
+-0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68,
+-0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60,
+-0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20,
+-0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c,
+-0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80,
+-0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x38, 0x1c, 0xfc, 0xf7, 0x07, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18,
+-0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63,
+-0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+-0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27,
+-0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 0x42, 0x63, 0x00, 0x2a,
+-0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 0xc0, 0x6a, 0x01, 0xf0,
+-0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 0x38, 0x01, 0x00, 0x19,
+-0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1,
+-0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x90, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+-0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x0f, 0x49, 0xc8, 0x68,
+-0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 0x02, 0x89, 0x00, 0x2a,
+-0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 0x00, 0x2a, 0x0d, 0xd1,
+-0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 0x02, 0x23, 0x0a, 0x68,
+-0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 0x01, 0x21, 0x00, 0xe0,
+-0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x01, 0x23, 0xf8, 0x1d,
+-0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 0x79, 0x32, 0x54, 0x8a,
+-0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 0xac, 0x42, 0x04, 0xdb,
+-0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 0xd1, 0x83, 0x01, 0x23,
+-0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61,
+-0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46,
+-0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0x61, 0x41, 0x69,
+-0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 0x00, 0x05, 0xc1, 0x60,
+-0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a,
+-0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8,
+-0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3,
+-0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23,
+-0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e,
+-0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1,
+-0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72,
+-0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+-0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 0x00, 0x20, 0xf8, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49,
+-0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31,
+-0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x63,
+-0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22,
+-0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1,
+-0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18,
+-0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92,
+-0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0,
+-0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e,
+-0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x73, 0xfc, 0x20, 0x6b,
+-0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8,
+-0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7,
+-0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80,
+-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49,
+-0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a,
+-0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7,
+-0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a,
+-0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x2d, 0xff, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x64, 0x2d, 0x00, 0x80,
+-0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49,
+-0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48,
+-0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31,
+-0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x61, 0x6b,
+-0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 0x78, 0x68, 0x80, 0x00,
+-0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 0x01, 0x23, 0x78, 0x68,
+-0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f,
+-0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1,
+-0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
+-0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68,
+-0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7,
+-0x59, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31,
+-0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49,
+-0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0,
+-0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0,
+-0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09,
+-0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62,
+-0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0,
+-0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a,
+-0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19,
+-0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a,
+-0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62,
+-0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62,
+-0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1,
+-0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42,
+-0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19,
+-0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0,
+-0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38,
+-0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+-0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90,
+-0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0xc0, 0x6a, 0xc0, 0x46,
+-0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46,
+-0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60,
+-0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46,
+-0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a,
+-0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46,
+-0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3,
+-0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20,
+-0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0,
+-0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30,
+-0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61,
+-0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+-0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 0x38, 0x1c, 0x5c, 0xe3,
+-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c,
+-0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07,
+-0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06,
+-0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1,
+-0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2,
+-0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0,
+-0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c,
+-0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68,
+-0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49,
+-0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0,
+-0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 0x7a, 0x68, 0xc0, 0x46,
+-0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49,
+-0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c,
+-0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a,
+-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c,
+-0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61,
+-0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69,
+-0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a,
+-0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28,
+-0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f,
+-0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92,
+-0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48,
+-0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80,
+-0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60,
+-0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a,
+-0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64,
+-0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18,
+-0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30,
+-0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61,
+-0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88,
+-0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0,
+-0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93,
+-0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68,
+-0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46,
+-0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46,
+-0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49,
+-0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0,
+-0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71,
+-0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37,
+-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
+-0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18,
+-0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x7d, 0xfb, 0x01, 0x9a,
+-0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65,
+-0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20,
+-0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8,
+-0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07,
+-0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99,
+-0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c,
+-0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c,
+-0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 0x41, 0x49, 0x00, 0x20,
+-0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b,
+-0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
+-0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a,
+-0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b,
+-0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98,
+-0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90,
+-0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
+-0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20,
+-0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90,
+-0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42,
+-0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90,
+-0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98,
+-0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42,
+-0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20,
+-0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1,
+-0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0,
+-0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb,
+-0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29,
+-0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a,
+-0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90,
+-0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98,
+-0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 0x01, 0x49, 0xff, 0xff,
+-0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80,
+-0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 0x60, 0x04, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x55, 0x32, 0xff, 0xff,
+-0xac, 0x5e, 0x21, 0x40, 0x0d, 0x3d, 0xff, 0xff, 0xcd, 0x31, 0xff, 0xff,
+-0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
+-0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98,
+-0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1,
+-0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98,
+-0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48,
+-0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x51, 0xf9, 0x00, 0x20,
+-0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b,
+-0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c,
+-0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a,
+-0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80,
+-0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98,
+-0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9,
+-0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09,
+-0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a,
+-0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a,
+-0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a,
+-0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2,
+-0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92,
+-0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
+-0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40,
+-0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22,
+-0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d,
+-0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x02, 0x90,
+-0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06,
+-0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a,
+-0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d,
+-0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37,
+-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa,
+-0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46,
+-0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99,
+-0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0,
+-0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23,
+-0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07,
+-0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b,
+-0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0,
+-0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98,
+-0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92,
+-0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
+-0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28,
+-0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20,
+-0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92,
+-0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20,
+-0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42,
+-0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98,
+-0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90,
+-0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04,
+-0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0,
+-0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e,
+-0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b,
+-0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x89, 0xf9, 0x01, 0x9a,
+-0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63,
+-0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68,
+-0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04,
+-0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68,
+-0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92,
+-0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+-0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d,
+-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42,
+-0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5,
+-0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69,
+-0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a,
+-0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28,
+-0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c,
+-0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61,
+-0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61,
+-0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61,
+-0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xcc, 0xfa,
+-0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18,
+-0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80,
+-0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0x68, 0x0e, 0x00, 0x80,
+-0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
+-0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0,
+-0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68,
+-0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18,
+-0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0,
+-0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e,
+-0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 0x19, 0x43, 0xe9, 0x63,
+-0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e,
+-0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0xa9, 0x6b,
+-0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 0xa8, 0x63, 0x01, 0x20,
+-0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xe8, 0x63,
+-0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18,
+-0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c,
+-0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0,
+-0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x06, 0xfc, 0x20, 0x1c, 0x00, 0xf0,
+-0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0,
+-0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30,
+-0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c,
+-0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68,
+-0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a,
+-0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42,
+-0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 0xf8, 0xe7, 0x78, 0x68,
+-0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7,
+-0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90,
+-0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x80, 0x69,
+-0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23,
+-0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
+-0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23,
+-0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0,
+-0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0,
+-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0,
+-0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18,
+-0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68,
+-0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 0x00, 0x2d, 0x13, 0xd0,
+-0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43,
+-0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68,
+-0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xdf, 0xfe, 0xb8, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7,
+-0x90, 0xee, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 0xf8, 0x0e, 0x00, 0x80,
+-0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
+-0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0xc8, 0x60,
+-0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68,
+-0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47,
+-0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40,
+-0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a,
+-0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46,
+-0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c,
+-0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18,
+-0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68,
+-0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60,
+-0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32,
+-0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61,
+-0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c,
+-0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff,
+-0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 0x01, 0x20, 0xf9, 0x1d,
+-0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61,
+-0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48,
+-0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe,
+-0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02,
+-0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68,
+-0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9,
+-0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00,
+-0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00,
+-0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02,
+-0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71,
+-0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
+-0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18,
+-0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49,
+-0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0xe4, 0x2d, 0x00, 0x80,
+-0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71,
+-0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00,
+-0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d,
+-0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c,
+-0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42,
+-0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9,
+-0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30,
+-0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8,
+-0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8,
+-0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7,
+-0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58,
+-0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08,
+-0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68,
+-0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9,
+-0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0,
+-0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40,
+-0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40,
+-0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04,
+-0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a,
+-0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68,
+-0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00,
+-0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69,
+-0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c,
+-0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79,
+-0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30,
+-0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7,
+-0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x04, 0x00, 0x80,
+-0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
+-0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68,
+-0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
+-0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21,
+-0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a,
+-0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68,
+-0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c,
+-0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28,
+-0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0,
+-0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
+-0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b,
+-0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18,
+-0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63,
+-0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b,
+-0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00,
+-0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
+-0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24,
+-0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68,
+-0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60,
+-0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b,
+-0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19,
+-0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b,
+-0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f,
+-0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68,
+-0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c,
+-0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80,
+-0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2e, 0x4b,
+-0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62,
+-0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c,
+-0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31,
+-0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29,
+-0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c,
+-0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00,
+-0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61,
+-0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3,
+-0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 0x3a, 0x6f, 0xfd, 0x68,
+-0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 0xdb, 0x6d, 0x5b, 0x08,
+-0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 0xfd, 0x6f, 0x03, 0x3b,
+-0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 0x0b, 0x81, 0x10, 0x60,
+-0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 0x00, 0xd0, 0x01, 0x38,
+-0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 0x00, 0xd8, 0x07, 0x4a,
+-0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 0x82, 0x61, 0x3a, 0x67,
+-0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
+-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
+-0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49,
+-0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f,
+-0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 0x00, 0x19, 0xe1, 0x60,
+-0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28,
+-0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69,
+-0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0,
+-0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0x65, 0x60, 0x20, 0x68,
+-0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80,
+-0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23,
+-0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b,
+-0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 0x02, 0x68, 0x15, 0x68,
+-0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2,
+-0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07,
+-0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47,
+-0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3,
+-0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68,
+-0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60,
+-0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d,
+-0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f,
+-0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d,
+-0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d,
+-0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60,
+-0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e,
+-0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20,
+-0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a,
+-0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68,
+-0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60,
+-0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46,
+-0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1,
+-0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69,
+-0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a,
+-0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d,
+-0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b,
+-0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68,
+-0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
+-0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47,
+-0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5,
+-0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a,
+-0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5,
+-0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5,
+-0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
+-0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5,
+-0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55,
+-0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5,
+-0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
+-0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5,
+-0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 0x02, 0x36, 0x83, 0xe3,
+-0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 0xf2, 0xff, 0xff, 0x1a,
+-0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 0x01, 0x06, 0x1c, 0xe3,
+-0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 0x02, 0xc6, 0xcc, 0xe3,
+-0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 0x50, 0x10, 0x91, 0xe5,
+-0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5,
+-0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a,
+-0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 0x94, 0x00, 0x00, 0xe0,
+-0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5,
+-0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3,
+-0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5,
+-0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
+-0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1,
+-0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a,
+-0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2,
+-0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2,
+-0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3,
+-0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2,
+-0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea,
+-0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8,
+-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1,
+-0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3,
+-0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
+-0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3,
+-0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1,
+-0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9,
+-0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3,
+-0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
+-0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5,
+-0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b,
+-0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3,
+-0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b,
+-0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3,
+-0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b,
+-0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3,
+-0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5,
+-0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5,
+-0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1,
+-0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a,
+-0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
+-0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
+-0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15,
+-0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x04, 0x14, 0xe3,
+-0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11,
+-0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11,
+-0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
+-0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 0x04, 0x00, 0x14, 0xe3,
+-0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3,
+-0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3,
+-0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x02, 0x14, 0xe3,
+-0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3,
+-0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3,
+-0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b,
+-0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b,
+-0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2,
+-0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2,
+-0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea,
+-0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
+-0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5,
+-0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
+-0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
+-0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5,
+-0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
+-0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
+-0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5,
+-0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5,
+-0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5,
+-0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba,
+-0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5,
+-0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7,
+-0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5,
+-0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5,
+-0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5,
+-0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5,
+-0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3,
+-0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
+-0xcc, 0x04, 0x00, 0x80, 0x71, 0x2b, 0xff, 0xff, 0xd1, 0x3d, 0xff, 0xff,
+-0xc9, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08,
+-0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68,
+-0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
+-0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0,
+-0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1,
+-0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2,
+-0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5,
+-0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 0x74, 0x10, 0x9f, 0xe5,
+-0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5,
+-0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2,
+-0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea,
+-0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x4c, 0x00, 0x9f, 0xe5,
+-0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5,
+-0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a,
+-0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a,
+-0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80,
+-0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80,
+-0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
+-0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00,
+-0x71, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea,
+-0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00,
+-0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x6b, 0xea, 0xff, 0xea,
+-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+-0x28, 0x04, 0x00, 0x00, 0xf8, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80,
+-0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff,
+-0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54,
+-0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+-0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00,
+-0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff,
+-0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff,
+-0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 0x01, 0xff, 0x04, 0x00,
+-0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+-0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
+-0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff,
+-0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x3d, 0x50, 0xff, 0xff, 0x81, 0x50, 0xff, 0xff,
+-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x48, 0x05, 0x00, 0x80, 0x11, 0x75, 0x21, 0x40, 0x1b, 0x75, 0x21, 0x40,
+-0x31, 0x75, 0x21, 0x40, 0x49, 0x75, 0x21, 0x40,
+-0x55, 0x75, 0x21, 0x40, 0x63, 0x75, 0x21, 0x40, 0x7d, 0x75, 0x21, 0x40,
+-0xa9, 0x75, 0x21, 0x40, 0x6d, 0x76, 0x21, 0x40, 0xc5, 0x76, 0x21, 0x40,
+-0xd3, 0x76, 0x21, 0x40, 0xdd, 0x76, 0x21, 0x40, 0xe7, 0x76, 0x21, 0x40,
+-0x99, 0x77, 0x21, 0x40, 0xa7, 0x77, 0x21, 0x40, 0xb5, 0x77, 0x21, 0x40,
+-0x61, 0x78, 0x21, 0x40, 0x5f, 0x7c, 0x21, 0x40, 0xe9, 0x7c, 0x21, 0x40,
+-0x89, 0x7d, 0x21, 0x40, 0xbd, 0x7e, 0x21, 0x40, 0xc9, 0x7e, 0x21, 0x40,
+-0x29, 0x7f, 0x21, 0x40, 0x8d, 0x7f, 0x21, 0x40, 0xb9, 0x7f, 0x21, 0x40,
+-0xdd, 0x7f, 0x21, 0x40, 0x1d, 0x80, 0x21, 0x40, 0x45, 0x80, 0x21, 0x40,
+-0x8d, 0x80, 0x21, 0x40, 0x9d, 0x80, 0x21, 0x40, 0xc5, 0x80, 0x21, 0x40,
+-0xd5, 0x80, 0x21, 0x40, 0x1d, 0x81, 0x21, 0x40, 0x5b, 0x81, 0x21, 0x40,
+-0xb1, 0x81, 0x21, 0x40, 0x11, 0x82, 0x21, 0x40, 0x1b, 0x82, 0x21, 0x40,
+-0x1f, 0x82, 0x21, 0x40, 0x8d, 0x82, 0x21, 0x40, 0xd9, 0x82, 0x21, 0x40,
+-0x31, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0xd1, 0x83, 0x21, 0x40,
+-0x09, 0x84, 0x21, 0x40, 0x19, 0x84, 0x21, 0x40, 0x51, 0x84, 0x21, 0x40,
+-0x61, 0x84, 0x21, 0x40, 0x75, 0x84, 0x21, 0x40, 0x9d, 0x84, 0x21, 0x40,
+-0xa7, 0x84, 0x21, 0x40, 0xb1, 0x84, 0x21, 0x40, 0x15, 0x85, 0x21, 0x40,
+-0x45, 0x85, 0x21, 0x40, 0x51, 0x85, 0x21, 0x40, 0xc5, 0x85, 0x21, 0x40,
+-0xcf, 0x85, 0x21, 0x40, 0xd9, 0x85, 0x21, 0x40, 0xe3, 0x85, 0x21, 0x40,
+-0xed, 0x85, 0x21, 0x40, 0xf7, 0x85, 0x21, 0x40, 0x01, 0x86, 0x21, 0x40,
+-0x0b, 0x86, 0x21, 0x40, 0x15, 0x86, 0x21, 0x40, 0x01, 0x89, 0x21, 0x40,
+-0x1f, 0x86, 0x21, 0x40, 0x29, 0x86, 0x21, 0x40, 0x33, 0x86, 0x21, 0x40,
+-0x3d, 0x86, 0x21, 0x40, 0x65, 0x86, 0x21, 0x40, 0x6f, 0x86, 0x21, 0x40,
+-0xd1, 0x86, 0x21, 0x40, 0xdb, 0x86, 0x21, 0x40, 0xe5, 0x86, 0x21, 0x40,
+-0xef, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+-0x03, 0x87, 0x21, 0x40, 0x69, 0x87, 0x21, 0x40, 0xb5, 0x87, 0x21, 0x40,
+-0xf9, 0x87, 0x21, 0x40, 0x09, 0x88, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+-0x55, 0x88, 0x21, 0x40, 0x59, 0x88, 0x21, 0x40, 0x5d, 0x88, 0x21, 0x40,
+-0xb5, 0x88, 0x21, 0x40, 0xdd, 0x88, 0x21, 0x40, 0xe9, 0x88, 0x21, 0x40,
+-0xed, 0x88, 0x21, 0x40, 0xf1, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40,
+-0xf9, 0x88, 0x21, 0x40, 0xfd, 0x88, 0x21, 0x40, 0x2d, 0x85, 0x21, 0x40,
+-0x89, 0x85, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+-0x0d, 0x89, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0xe1, 0x74, 0x21, 0x40,
+-0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+-0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+-0x6b, 0x78, 0x21, 0x40, 0xf5, 0x7b, 0x21, 0x40, 0x31, 0x7c, 0x21, 0x40,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40,
+-0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40,
+-0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40,
+-0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00,
+-0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
+-0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+-0xd1, 0xa8, 0x21, 0x40, 0x2d, 0xaa, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
+-0x89, 0x70, 0x21, 0x40, 0xc9, 0xa1, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x57, 0x89, 0x21, 0x40, 0xd1, 0xa8, 0x21, 0x40, 0xc5, 0x2f, 0xff, 0xff,
+-0x05, 0x21, 0xff, 0xff, 0xef, 0x20, 0xff, 0xff, 0x59, 0xa7, 0x21, 0x40,
+-0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 0x5c, 0x2e, 0x00, 0x80,
+-0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 0x00, 0x30, 0x37, 0x2f,
+-0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35,
+-0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
+-0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43,
+-0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
+-0x6f, 0x6e, 0x0a, 0x00, 0x08, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x53, 0xff, 0xff,
+-0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00,
+-0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
+-0x69, 0x3e, 0xff, 0xff, 0xc9, 0x4f, 0xff, 0xff, 0xd5, 0x24, 0xff, 0xff,
+-0xc9, 0x3b, 0xff, 0xff, 0x29, 0x3c, 0xff, 0xff, 0x19, 0x1a, 0xff, 0xff,
+-0x65, 0x11, 0xff, 0xff, 0xcc, 0x53, 0xff, 0xff, 0x21, 0x40, 0xff, 0xff,
+-0x89, 0x70, 0x21, 0x40, 0x49, 0x72, 0x21, 0x40, 0xd9, 0x3f, 0xff, 0xff,
+-0x21, 0x9a, 0x21, 0x40, 0x85, 0x24, 0xff, 0xff, 0x64, 0x53, 0xff, 0xff,
+-0x8c, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+-0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+-0x00, 0x00, 0x20, 0x40, 0xb0, 0x50, 0x00, 0x00, 0x7b, 0x0e, 0x00, 0x00,
+-0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0xed, 0x89, 0x21, 0x40, 0x8b, 0x89, 0x21, 0x40, 0xa5, 0x8c, 0x21, 0x40,
+-0x05, 0x8d, 0x21, 0x40, 0xcd, 0x8d, 0x21, 0x40, 0x8b, 0x8b, 0x21, 0x40,
+-0xa9, 0x8e, 0x21, 0x40, 0x15, 0x8f, 0x21, 0x40, 0x69, 0x8b, 0x21, 0x40,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x59, 0xbd, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x2d, 0xbe, 0x21, 0x40,
+-0x00, 0x20, 0x0a, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23,
+-0x9b, 0x01, 0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32,
+-0xc8, 0x60, 0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x03, 0x48, 0xc0, 0x46,
+-0x48, 0x60, 0x88, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c,
+-0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xde, 0xff, 0x68, 0x49, 0x0b, 0x23,
+-0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40,
+-0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61,
+-0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a,
+-0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68,
+-0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20,
+-0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xd4, 0xfa, 0xf8, 0x68, 0x00, 0x28,
+-0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23,
+-0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95,
+-0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0,
+-0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 0x9b, 0x5c, 0x1e, 0x1c,
+-0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 0x5b, 0x78, 0x83, 0x42,
+-0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 0x03, 0x9d, 0xed, 0x6a,
+-0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 0xeb, 0x62, 0x53, 0x68,
+-0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 0x86, 0x42, 0x0a, 0xd1,
+-0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 0x9b, 0x00, 0x3c, 0x4e,
+-0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 0x9d, 0x61, 0x53, 0x78,
+-0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 0x5d, 0x1c, 0x01, 0x95,
+-0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xeb, 0x18,
+-0xda, 0x60, 0x3a, 0x69, 0x01, 0x32, 0x3a, 0x61, 0x64, 0x00, 0x01, 0x31,
+-0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xb8, 0xd3, 0x00, 0x20,
+-0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02,
+-0xc9, 0x18, 0x88, 0x61, 0x01, 0x9b, 0x99, 0x00, 0x89, 0x18, 0x2d, 0x23,
+-0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1,
+-0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69,
+-0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0,
+-0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 0x03, 0xd2, 0x30, 0x20,
+-0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 0x78, 0x69, 0x00, 0x28,
+-0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 0x78, 0x61, 0x00, 0x20,
+-0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0,
+-0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78,
+-0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 0x9b, 0x00, 0x9e, 0x19,
+-0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00,
+-0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3,
+-0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01,
+-0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0x30, 0x53, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80,
+-0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46,
+-0x18, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
+-0x10, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
+-0x08, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x38, 0x52, 0xff, 0xff,
+-0x88, 0x51, 0xff, 0xff, 0xd5, 0xb0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20,
+-0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01,
+-0xf8, 0x18, 0x05, 0x73, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20,
+-0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0,
+-0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
+-0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20,
+-0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 0xc3, 0xff, 0x00, 0x28,
+-0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61,
+-0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61,
+-0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80,
+-0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
+-0x7d, 0x71, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48,
+-0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42,
+-0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18,
+-0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92,
+-0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7,
+-0x8d, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92,
+-0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x82, 0xff,
+-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x7c, 0x29, 0x00, 0x80,
+-0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
+-0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68,
+-0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 0x63, 0xff, 0x01, 0x20,
+-0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c,
+-0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29,
+-0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1,
+-0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0,
+-0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff,
+-0x22, 0xe0, 0x09, 0x01, 0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a,
+-0x17, 0x49, 0xff, 0xf7, 0x35, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73,
+-0x04, 0x23, 0xa8, 0x69, 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61,
+-0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60,
+-0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0,
+-0x17, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0,
+-0x02, 0x23, 0xf8, 0x6b, 0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00,
+-0x28, 0x05, 0x00, 0x80, 0xa5, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0,
+-0x68, 0x0e, 0x00, 0x80, 0xe4, 0x01, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
+-0x7d, 0x71, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49,
+-0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30,
+-0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0,
+-0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0,
+-0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
+-0xc1, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80,
+-0xe8, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88,
+-0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0,
+-0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c,
+-0xff, 0xf7, 0xcb, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09,
+-0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46,
+-0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20,
+-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b,
+-0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0,
+-0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00,
+-0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01,
+-0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46,
+-0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0,
+-0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c,
+-0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30,
+-0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48,
+-0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a,
+-0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8,
+-0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0,
+-0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43,
+-0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c,
+-0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18,
+-0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x5e, 0xfe,
+-0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48,
+-0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x53, 0xfe, 0x01, 0x20,
+-0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18,
+-0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61,
+-0x00, 0xe0, 0x88, 0x61, 0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
+-0xc1, 0x63, 0x00, 0x20, 0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73,
+-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80,
+-0x50, 0xba, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
+-0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80,
+-0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a,
+-0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a,
+-0x88, 0x66, 0x88, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40,
+-0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42,
+-0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46,
+-0x08, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
+-0x90, 0xee, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46,
+-0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80,
+-0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60,
+-0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60,
+-0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48,
+-0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46,
+-0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90,
+-0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46,
+-0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c,
+-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a,
+-0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20,
+-0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
+-0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc,
+-0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xa1, 0x21,
+-0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
+-0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xff, 0x21, 0xa1, 0x22,
+-0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
+-0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47,
+-0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20,
+-0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03,
+-0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 0x00, 0x20, 0x70, 0x47,
+-0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b,
+-0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab,
+-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20,
+-0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40,
+-0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
+-0x5b, 0xff, 0xf8, 0x88, 0x04, 0xa9, 0x03, 0xf0, 0xc9, 0xff, 0x01, 0xab,
+-0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8,
+-0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b,
+-0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68,
+-0xc0, 0x46, 0x03, 0x90, 0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
+-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31,
+-0x68, 0x46, 0xff, 0xf7, 0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b,
+-0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78,
+-0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22,
+-0x00, 0xab, 0x5a, 0x80, 0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70,
+-0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68,
+-0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31,
+-0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80,
+-0xa4, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
+-0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48,
+-0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xe4, 0xfc, 0x00, 0x28,
+-0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xdf, 0xfc,
+-0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21,
+-0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+-0x0d, 0x76, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x59, 0xbd, 0x21, 0x40,
+-0x00, 0xb5, 0xc0, 0x88, 0x03, 0xf0, 0x2e, 0xff, 0x00, 0x20, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+-0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47,
+-0xb0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7,
+-0xb5, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0xa4, 0xfc, 0x04, 0x1c, 0x20, 0x4a,
+-0x00, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 0x27, 0xd0,
+-0x04, 0xa9, 0x1d, 0x4a, 0x38, 0x1c, 0xff, 0xf7, 0x99, 0xfc, 0x04, 0xa8,
+-0x00, 0x23, 0x01, 0x2f, 0x06, 0xd1, 0x0c, 0xaa, 0x02, 0x32, 0x00, 0x21,
+-0x13, 0x60, 0x01, 0x31, 0x10, 0x29, 0xfb, 0xd3, 0x01, 0x68, 0x04, 0x29,
+-0x04, 0xd9, 0x89, 0x08, 0x03, 0x39, 0x89, 0x08, 0x01, 0x31, 0x00, 0xe0,
+-0x19, 0x1c, 0x00, 0xab, 0x59, 0x70, 0x06, 0xa9, 0x09, 0x78, 0xc0, 0x46,
+-0xd9, 0x80, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46,
+-0x03, 0x90, 0x04, 0x33, 0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
+-0x18, 0x70, 0x09, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x6e, 0xfc, 0x68, 0x46,
+-0x29, 0x1c, 0xff, 0xf7, 0xb7, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
+-0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c,
+-0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+-0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xa2, 0xff, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc,
+-0x18, 0x47, 0xf0, 0xb5, 0xc7, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x1c,
+-0x01, 0xa9, 0xff, 0xf7, 0x4d, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0x3c, 0xfc,
+-0x00, 0x90, 0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a,
+-0x25, 0xd8, 0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x21, 0xd8, 0x19, 0x2c,
+-0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0xf9, 0x1d,
+-0x09, 0x31, 0x06, 0xab, 0x00, 0x20, 0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd,
+-0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3,
+-0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78,
+-0x86, 0x42, 0xf1, 0xdc, 0x20, 0x1c, 0x05, 0xa9, 0x2b, 0x1c, 0xff, 0xf7,
+-0x21, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x01, 0xa8, 0x00, 0x78, 0x40, 0x23,
+-0x18, 0x43, 0x01, 0xab, 0x18, 0x70, 0x07, 0x49, 0x00, 0x98, 0xff, 0xf7,
+-0x06, 0xfc, 0x00, 0x21, 0x01, 0xa8, 0xff, 0xf7, 0x4f, 0xfd, 0x01, 0x20,
+-0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff,
+-0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x1b, 0xfe, 0x08, 0xbc,
+-0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d,
+-0x68, 0x68, 0x01, 0x30, 0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7,
+-0xf5, 0xfd, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
+-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0,
+-0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68,
+-0x00, 0x2a, 0x15, 0xd9, 0x40, 0xcb, 0x0f, 0x1c,
+-0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 0x12, 0x78, 0x40, 0x23,
+-0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 0xda, 0x80, 0x02, 0x90,
+-0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 0x15, 0xe0, 0x01, 0x30,
+-0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 0x02, 0x94, 0x69, 0x68,
+-0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a,
+-0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42,
+-0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 0xf7, 0xfc, 0x01, 0x20,
+-0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x9c, 0x03, 0x00, 0x80,
+-0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3,
+-0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 0x00, 0xd2, 0x02, 0x22,
+-0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 0x01, 0x2b, 0x2e, 0xd1,
+-0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0x1b, 0x23,
+-0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 0x00, 0xd2, 0x04, 0x27,
+-0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 0x07, 0xd2, 0xd1, 0x1d,
+-0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23,
+-0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x79, 0x03, 0x29,
+-0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a,
+-0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07,
+-0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c,
+-0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00,
+-0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40,
+-0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x04, 0xf0, 0x07, 0xfa, 0x39, 0x48,
+-0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 0x37, 0x4e, 0xc5, 0x1d,
+-0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 0x5b, 0x5c, 0x5b, 0x00,
+-0x9f, 0x44, 0x00, 0x1c, 0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20,
+-0xb8, 0x71, 0x00, 0x20, 0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23,
+-0x98, 0x43, 0x00, 0xf0, 0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff,
+-0xc0, 0x08, 0x06, 0xd3, 0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28,
+-0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22,
+-0x20, 0x1c, 0x2b, 0xe0, 0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68,
+-0x19, 0x43, 0x01, 0x60, 0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a,
+-0x00, 0x21, 0x04, 0xf0, 0x99, 0xf9, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68,
+-0x99, 0x43, 0x01, 0x60, 0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68,
+-0x04, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68,
+-0x19, 0x43, 0x01, 0x60, 0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43,
+-0x00, 0xf0, 0x34, 0xf8, 0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x04, 0xf0,
+-0x77, 0xf9, 0xe5, 0xe7, 0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43,
+-0x00, 0xf0, 0x28, 0xf8, 0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23,
+-0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xff, 0xf7, 0xe3, 0xfa, 0xd5, 0xe7,
+-0x06, 0x20, 0xb8, 0x71, 0xd2, 0xe7, 0x00, 0x00, 0xa9, 0x79, 0x21, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00,
+-0x10, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20,
+-0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
+-0x04, 0xf0, 0x4e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x98, 0x1c, 0x00, 0x80,
+-0xa9, 0x79, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x31, 0x48, 0x00, 0x68,
+-0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0,
+-0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 0x01, 0x2a, 0x05, 0xd1,
+-0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43,
+-0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 0x01, 0x60, 0xe0, 0x68,
+-0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x80, 0x8b,
+-0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43,
+-0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20,
+-0x02, 0xf0, 0x1a, 0xfb, 0x38, 0x09, 0x07, 0xd3, 0xe0, 0x6f, 0x80, 0x23,
+-0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 0x00, 0x68, 0x00, 0xe0,
+-0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x15, 0x48,
+-0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43,
+-0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08,
+-0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 0x10, 0x43, 0x88, 0x42,
+-0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29,
+-0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 0x04, 0x33, 0x18, 0x40,
+-0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80,
+-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7,
+-0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 0xe3, 0x23, 0x1b, 0x01,
+-0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 0x01, 0x22, 0x4a, 0x71,
+-0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 0x99, 0x43,
+-0x01, 0x60, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x02, 0xf0, 0x8c, 0xfc,
+-0x07, 0x20, 0x02, 0xf0, 0x5b, 0xfc, 0x38, 0x1c, 0xff, 0xf7, 0x36, 0xfa,
+-0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
+-0x37, 0xfc, 0xff, 0xf7, 0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48,
+-0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46,
+-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x67, 0xfb, 0x01, 0x20,
+-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+-0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
+-0x38, 0x1c, 0xff, 0xf7, 0x17, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff,
+-0xff, 0xf7, 0x62, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
+-0xff, 0xf7, 0x4c, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7,
+-0x01, 0xfc, 0x01, 0x24, 0x1a, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8,
+-0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20,
+-0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x20, 0xe0, 0x14, 0x48, 0xff, 0xf7,
+-0xe1, 0xf9, 0x05, 0x1c, 0x13, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7,
+-0xdd, 0xf9, 0x12, 0x49, 0x28, 0x1c, 0xff, 0xf7, 0xd8, 0xf9, 0x01, 0x2f,
+-0x06, 0xd1, 0x0c, 0xa9, 0x00, 0x20, 0x00, 0x22,
+-0x0a, 0x60, 0x01, 0x30, 0x10, 0x28, 0xfb, 0xd3, 0x10, 0x20, 0x00, 0xab,
+-0x58, 0x70, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46,
+-0x03, 0x90, 0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x0f, 0xfb, 0x20, 0x1c,
+-0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x01, 0x00, 0x00,
+-0x24, 0x02, 0xff, 0xff, 0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff,
+-0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
+-0xbb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x01, 0xd1,
+-0x19, 0x2c, 0x09, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43,
+-0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 0x27, 0xe0,
+-0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90,
+-0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28,
+-0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04,
+-0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 0x09, 0x0c,
+-0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0b, 0x48, 0xff, 0xf7, 0x7e, 0xf9,
+-0x07, 0x1c, 0x0a, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0x7a, 0xf9,
+-0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x75, 0xf9, 0x68, 0x46, 0x00, 0x21,
+-0xff, 0xf7, 0xbe, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0xc5, 0xaf, 0x21, 0x40,
+-0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27,
+-0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0,
+-0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0,
+-0x04, 0x2e, 0x00, 0xd1, 0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e,
+-0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c,
+-0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0,
+-0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0,
+-0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33,
+-0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 0x01, 0x23, 0x5b, 0x02,
+-0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22,
+-0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 0xff, 0x23, 0xe1, 0x33,
+-0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 0xff, 0x33, 0x9e, 0x42,
+-0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1,
+-0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21,
+-0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0x40, 0x88,
+-0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0,
+-0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1,
+-0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43,
+-0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0,
+-0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x09, 0x21,
+-0x49, 0x02, 0x00, 0x20, 0x02, 0xf0, 0x70, 0xf9, 0x00, 0x2f, 0x02, 0xd1,
+-0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7,
+-0xef, 0xfa, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab,
+-0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33,
+-0xff, 0xf7, 0x22, 0xfa, 0x28, 0x1c, 0x04, 0xb0,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62,
+-0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28,
+-0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21,
+-0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18,
+-0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0,
+-0x33, 0xf9, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80,
+-0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23,
+-0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20,
+-0x02, 0xf0, 0x20, 0xf9, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28,
+-0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23,
+-0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01,
+-0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c,
+-0x10, 0x20, 0x02, 0xf0, 0x01, 0xf9, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01,
+-0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18,
+-0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02,
+-0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xee, 0xf8, 0x00, 0x20, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0,
+-0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x69, 0xfa, 0xb8, 0x05,
+-0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
+-0xa1, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49,
+-0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49,
+-0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40,
+-0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a,
+-0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1,
+-0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02,
+-0x69, 0x46, 0xff, 0xf7, 0x35, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46,
+-0x00, 0x21, 0xff, 0xf7, 0x6f, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20,
+-0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1,
+-0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1,
+-0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47,
+-0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 0x9f, 0xf8, 0x69, 0x46,
+-0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x0a, 0xfa, 0x01, 0xab, 0x5c, 0x80,
+-0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21,
+-0xff, 0xf7, 0x40, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49,
+-0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
+-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47,
+-0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
+-0xe3, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab,
+-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf9, 0x01, 0x20,
+-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
+-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47,
+-0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68,
+-0xff, 0xf7, 0xc6, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49,
+-0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0,
+-0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70,
+-0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
+-0xef, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68,
+-0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0x17, 0xf8, 0x00, 0x20,
+-0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0x9a, 0xf9, 0x00, 0xa8, 0x00, 0x78,
+-0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80,
+-0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xcd, 0xf8, 0x01, 0x20,
+-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88,
+-0x69, 0x46, 0xff, 0xf7, 0x83, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x72, 0xff,
+-0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0xf2, 0xff, 0x00, 0x28, 0x06, 0xd0,
+-0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0x36, 0xff, 0x01, 0xab, 0x58, 0x80,
+-0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c,
+-0xfe, 0xf7, 0x5f, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa8, 0xf8,
+-0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0,
+-0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x57, 0xf9, 0x10, 0x48,
+-0xfe, 0xf7, 0x46, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7,
+-0x43, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c,
+-0x22, 0x1c, 0xfe, 0xf7, 0x3c, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
+-0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 0x32, 0xff, 0x68, 0x46,
+-0x00, 0x21, 0xff, 0xf7, 0x7b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
+-0x59, 0xb0, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7,
+-0x43, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4,
+-0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1,
+-0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1,
+-0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a,
+-0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40,
+-0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30,
+-0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c,
+-0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37,
+-0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28,
+-0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40,
+-0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43,
+-0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0c, 0x4b,
+-0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02,
+-0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80,
+-0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04,
+-0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
+-0x40, 0x00, 0x14, 0x00, 0x28, 0x1b, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0,
+-0x13, 0x49, 0x0a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12,
+-0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02,
+-0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02,
+-0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c,
+-0xff, 0xf7, 0xae, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43,
+-0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xe5, 0xff, 0x01, 0x20,
+-0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40,
+-0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04,
+-0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02,
+-0x00, 0x12, 0x18, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04,
+-0x00, 0x0c, 0x02, 0x02, 0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c,
+-0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00,
+-0x90, 0xb5, 0x84, 0xb0, 0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c,
+-0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c,
+-0x17, 0x02, 0x12, 0x12, 0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c,
+-0x1f, 0x02, 0x1b, 0x12, 0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23,
+-0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b,
+-0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04,
+-0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
+-0x95, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a,
+-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
+-0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
+-0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x79, 0xff, 0x01, 0x20,
+-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
+-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47,
+-0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a,
+-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
+-0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
+-0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x55, 0xff, 0x01, 0x20,
+-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
+-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47,
+-0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7,
+-0xf4, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff,
+-0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x06, 0x48,
+-0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
+-0x2f, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xfd, 0xff, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf8, 0xff,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf3, 0xff, 0x08, 0xbc,
+-0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xc6, 0xfd,
+-0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21,
+-0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c,
+-0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a,
+-0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48,
+-0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0xd5, 0x94, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
+-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
+-0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff,
+-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
+-0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff,
+-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0,
+-0xf9, 0xff, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0,
+-0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xfe, 0xf8, 0x00, 0x28, 0x0c, 0xd1,
+-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x82, 0xff, 0x06, 0x48, 0x01, 0xab,
+-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xbb, 0xfe, 0x01, 0x20,
+-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7,
+-0x6d, 0xff, 0x01, 0x27, 0x01, 0xab, 0x5f, 0x80, 0x09, 0x48, 0x81, 0x89,
+-0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04,
+-0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
+-0x9b, 0xfe, 0x38, 0x1c, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0xb5, 0xfe, 0xf7, 0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+-0xfe, 0xf7, 0x5a, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+-0x55, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0xb5, 0xfe, 0xf7, 0x41, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+-0xfe, 0xf7, 0x3c, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+-0x37, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x32, 0xff,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7,
+-0x13, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x02, 0xf0, 0xa9, 0xff, 0x02, 0x20,
+-0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x48, 0xfe,
+-0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+-0x19, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
+-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf8, 0xfe, 0xfa, 0x88, 0x12, 0x49,
+-0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 0x0f, 0xd0, 0x04, 0x70,
+-0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 0xc8, 0x82, 0xb8, 0x68,
+-0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 0x48, 0x83, 0xf8, 0x68,
+-0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21,
+-0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
+-0x00, 0x21, 0xfe, 0xf7, 0x17, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+-0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+-0xfe, 0xf7, 0xde, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+-0xd9, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xd4, 0xfe,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xcf, 0xfe, 0x08, 0xbc,
+-0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c,
+-0xfe, 0xf7, 0xae, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43,
+-0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42,
+-0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
+-0xfe, 0xf7, 0xdc, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68,
+-0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80,
+-0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xcc, 0xfd,
+-0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0,
+-0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x7b, 0xfe, 0xf8, 0x88,
+-0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b,
+-0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
+-0x00, 0x21, 0xfe, 0xf7, 0xab, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68,
+-0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00,
+-0x80, 0xb5, 0x86, 0xb0, 0x02, 0xa9, 0xfe, 0xf7, 0x57, 0xfe, 0x01, 0x27,
+-0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68,
+-0xc0, 0x46, 0x04, 0x91, 0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68,
+-0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46,
+-0x02, 0xa8, 0xfe, 0xf7, 0x81, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68,
+-0x80, 0x68, 0xfe, 0xf7, 0x47, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c,
+-0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x36, 0xfe, 0x01, 0xab, 0x5c, 0x80,
+-0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x61, 0xfd, 0x04, 0xb0,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
+-0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x24, 0xfe, 0x01, 0xab, 0x5f, 0x80,
+-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x50, 0xfd, 0x04, 0xb0, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
+-0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a,
+-0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0,
+-0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27,
+-0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27,
+-0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xec, 0xfd, 0x01, 0xab, 0x5f, 0x80,
+-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x26, 0xfd, 0x20, 0x1c, 0x04, 0xb0,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0,
+-0x69, 0x46, 0xfe, 0xf7, 0xd7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab,
+-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x0f, 0xfd, 0x01, 0x20,
+-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
+-0x00, 0xb5, 0xfe, 0xf7, 0xdd, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47,
+-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
+-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
+-0x00, 0xb5, 0xfe, 0xf7, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xab, 0xfd, 0x00, 0x20,
+-0x01, 0xab, 0x58, 0x70, 0x0c, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29,
+-0x02, 0xd1, 0x03, 0x97, 0x04, 0x97, 0x01, 0xe0, 0x03, 0x97, 0x04, 0x90,
+-0x68, 0x46, 0x01, 0xf0, 0x33, 0xfd, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46,
+-0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xd3, 0xfc, 0x38, 0x1c,
+-0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30,
+-0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40,
+-0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42,
+-0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 0x02, 0xd3, 0x40, 0x1a,
+-0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 0x01, 0x1c, 0xff, 0x27,
+-0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 0x43, 0x00, 0x1b, 0x18,
+-0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 0x4b, 0x00, 0x59, 0x18,
+-0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd7, 0x50,
+-0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 0x57, 0x60, 0x8b, 0x68,
+-0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69,
+-0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc,
+-0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb,
+-0x38, 0x1c, 0xf6, 0xe7, 0x40, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0,
+-0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0,
+-0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58,
+-0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0,
+-0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 0x00, 0x28,
+-0x5b, 0xd0, 0x00, 0x26, 0x00, 0x22, 0x00, 0x92, 0x40, 0x23, 0x00, 0x21,
+-0x00, 0x20, 0x02, 0xaa, 0x00, 0xf0, 0x88, 0xfa, 0x04, 0xa9, 0x00, 0x20,
+-0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0xa2, 0x42, 0x03, 0xd1,
+-0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06,
+-0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c,
+-0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22,
+-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 0x00, 0xf0, 0x68, 0xfa,
+-0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05,
+-0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42,
+-0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
+-0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x50, 0xfa,
+-0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06,
+-0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22,
+-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0,
+-0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1,
+-0x01, 0x99, 0x00, 0x29, 0x0f, 0xd1, 0xff, 0x20, 0x3d, 0xe0, 0x40, 0xe0,
+-0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
+-0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x28, 0xfa,
+-0x02, 0x9d, 0x01, 0x20, 0x00, 0x04, 0x46, 0x9a, 0x10, 0x43, 0x79, 0x00,
+-0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0x30, 0x1c,
+-0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x04, 0x2c, 0x00, 0xd0, 0x0c, 0x20,
+-0x04, 0x1c, 0xb0, 0x60, 0x00, 0x20, 0x20, 0x21, 0x46, 0x9a, 0x11, 0x40,
+-0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 0x28, 0x19, 0xff, 0x21,
+-0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 0xff, 0xf7, 0x19, 0xff, 0x43, 0x01,
+-0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21,
+-0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60,
+-0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20,
+-0xf9, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23,
+-0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06,
+-0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06,
+-0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28,
+-0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x45, 0x91, 0x41, 0x4a,
+-0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 0xc0, 0x43, 0x76, 0xe0,
+-0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00,
+-0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 0x00, 0x21, 0x02, 0x91,
+-0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 0xff, 0x21, 0x68, 0x1e,
+-0x09, 0x31, 0xff, 0xf7, 0xcd, 0xfe, 0x61, 0x68, 0x40, 0x18, 0x01, 0x90,
+-0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 0xaf, 0x1b, 0x09, 0xe0,
+-0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe,
+-0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 0x00, 0x22, 0x00, 0x92,
+-0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 0x00, 0xf0, 0x9e, 0xf9,
+-0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, 0x02, 0x99,
+-0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 0xed, 0x1b, 0xa0, 0x68,
+-0xa8, 0x42, 0x00, 0xd1, 0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99,
+-0xcf, 0x43, 0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68,
+-0x03, 0xaa, 0x00, 0xf0, 0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90,
+-0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43,
+-0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21,
+-0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99,
+-0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90,
+-0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xca, 0xf9,
+-0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43,
+-0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40,
+-0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb,
+-0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d,
+-0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0,
+-0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0,
+-0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 0x0f, 0xd3, 0x05, 0xe0,
+-0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b,
+-0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19,
+-0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00,
+-0x40, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c,
+-0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49,
+-0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43,
+-0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c,
+-0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x21, 0x69, 0x8a, 0x42,
+-0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 0xa0, 0x68, 0xe1, 0x68,
+-0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x0d, 0xfe, 0x61, 0x68,
+-0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31,
+-0xff, 0xf7, 0x0d, 0xfe, 0xc2, 0x19, 0xff, 0x21, 0x09, 0x31, 0x8a, 0x42,
+-0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x0b, 0x1a, 0x03, 0x93,
+-0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0xe1, 0xf8, 0xe0, 0x68,
+-0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 0x5d, 0x19, 0xff, 0x1a,
+-0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 0x01, 0x9a, 0xc0, 0x46,
+-0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0,
+-0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98,
+-0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98,
+-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0xab, 0x20, 0x40,
+-0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91,
+-0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58,
+-0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda,
+-0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 0x02, 0x9a, 0x54, 0x18,
+-0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 0x01, 0xd9, 0x22, 0x69,
+-0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 0xa0, 0x68, 0xe1, 0x68,
+-0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0xa7, 0xfd, 0x61, 0x68,
+-0x40, 0x18, 0x00, 0x90, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21,
+-0x09, 0x31, 0xff, 0xf7, 0xa6, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23,
+-0x5b, 0x04, 0x19, 0x43, 0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32,
+-0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c,
+-0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19,
+-0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b,
+-0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e,
+-0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 0xcb, 0xf8, 0xe0, 0x68,
+-0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9,
+-0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f,
+-0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x40, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0,
+-0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00,
+-0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2,
+-0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09,
+-0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 0x40, 0x68, 0x0c, 0x23,
+-0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 0x11, 0x2c, 0x0d, 0xd0,
+-0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1,
+-0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06,
+-0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c,
+-0xdb, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20,
+-0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47,
+-0x40, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x6f, 0xfa, 0x57, 0x20,
+-0x02, 0xf0, 0xcc, 0xf9, 0x02, 0xf0, 0x40, 0xf9, 0x00, 0x0a, 0xfb, 0xd3,
+-0x02, 0xf0, 0x4e, 0xfa, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0,
+-0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23,
+-0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32,
+-0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c,
+-0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x4b, 0xfa, 0x53, 0x20,
+-0x02, 0xf0, 0xa8, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0,
+-0xa3, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0xa0, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
+-0x9d, 0xf9, 0x02, 0xf0, 0x23, 0xfa, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0,
+-0x37, 0xfa, 0x54, 0x20, 0x02, 0xf0, 0x94, 0xf9, 0x00, 0x98, 0x02, 0xf0,
+-0x91, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x8e, 0xf9, 0x30, 0x1c, 0x14, 0xe0,
+-0x02, 0xf0, 0x2a, 0xfa, 0x52, 0x20, 0x02, 0xf0, 0x87, 0xf9, 0x01, 0x98,
+-0x02, 0xf0, 0x84, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x81, 0xf9, 0x30, 0x1c,
+-0x02, 0xf0, 0x7e, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xf9, 0x00, 0x20,
+-0x02, 0xf0, 0x78, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x00, 0x20,
+-0x02, 0xf0, 0x72, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0xe4, 0xf8,
+-0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xf0, 0xf9,
+-0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
+-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x42, 0x02, 0x0a, 0x43,
+-0x15, 0x1c, 0x01, 0x28, 0x54, 0xd0, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23,
+-0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68,
+-0x19, 0x43, 0x01, 0x60, 0x02, 0xf0, 0xe6, 0xf9, 0x53, 0x20, 0x02, 0xf0,
+-0x43, 0xf9, 0x28, 0x0c, 0x06, 0x1c, 0x02, 0xf0, 0x3f, 0xf9, 0x28, 0x0a,
+-0x01, 0x90, 0x00, 0x90, 0x02, 0xf0, 0x3a, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
+-0x37, 0xf9, 0x02, 0xf0, 0xbd, 0xf9, 0xff, 0xf7, 0x61, 0xff, 0x02, 0xf0,
+-0xd1, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x2e, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
+-0x2b, 0xf9, 0x00, 0x98, 0x02, 0xf0, 0x28, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
+-0x25, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0,
+-0x1f, 0xf9, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xa3, 0xf9, 0x02, 0xf0,
+-0xb9, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x16, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
+-0x13, 0xf9, 0x01, 0x98, 0x02, 0xf0, 0x10, 0xf9,
+-0x28, 0x1c, 0x02, 0xf0, 0x0d, 0xf9, 0x02, 0xf0, 0x93, 0xf9, 0xff, 0xf7,
+-0x37, 0xff, 0x07, 0x49, 0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43,
+-0x02, 0x60, 0xc8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
+-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0xf0, 0x8f, 0xf8, 0x06, 0x4f,
+-0xc0, 0x46, 0xf8, 0x60, 0x01, 0xf0, 0xf2, 0xf8, 0x78, 0x80, 0x01, 0xf0,
+-0xb1, 0xf8, 0x38, 0x71, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 0x05, 0xf9, 0x02, 0x49,
+-0xc0, 0x46, 0x08, 0x80, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0x0b, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23,
+-0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68,
+-0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68,
+-0x1a, 0x43, 0x02, 0x60, 0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32,
+-0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28,
+-0xfa, 0xd3, 0x46, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30,
+-0x20, 0x28, 0xfa, 0xd3, 0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50,
+-0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65,
+-0x8f, 0x65, 0x3f, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60,
+-0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00,
+-0x09, 0x18, 0x49, 0x01, 0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d,
+-0xf9, 0x33, 0x34, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01,
+-0xcb, 0x18, 0x63, 0x63, 0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18,
+-0xe3, 0x63, 0x23, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30,
+-0x02, 0x28, 0xe4, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c,
+-0xc0, 0x46, 0xa1, 0x62, 0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62,
+-0xc1, 0x18, 0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21,
+-0xe1, 0x64, 0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69,
+-0xc0, 0x46, 0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66,
+-0x8b, 0x68, 0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66,
+-0x1e, 0x4b, 0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01,
+-0xc3, 0x18, 0xa3, 0x67, 0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33,
+-0x66, 0x61, 0xe7, 0x61, 0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b,
+-0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d,
+-0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46,
+-0x53, 0x66, 0x89, 0x69, 0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46,
+-0xd1, 0x66, 0x16, 0x67, 0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67,
+-0x56, 0x67, 0xd7, 0x61, 0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73,
+-0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
+-0x64, 0x2d, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00,
+-0x7c, 0x29, 0x00, 0x80, 0x00, 0x55, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00,
+-0x10, 0x55, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23,
+-0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23,
+-0xdb, 0x01, 0xd0, 0x18, 0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18,
+-0xc1, 0x61, 0x1c, 0x70, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60,
+-0xb9, 0x73, 0x59, 0x61, 0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60,
+-0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69,
+-0xe4, 0x18, 0x44, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02,
+-0x84, 0x63, 0x0e, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46,
+-0x44, 0x62, 0x84, 0x69, 0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60,
+-0x03, 0x6b, 0xc0, 0x46, 0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62,
+-0xc1, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc,
+-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
+-0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22,
+-0x1b, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20,
+-0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c,
+-0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37,
+-0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18,
+-0x33, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20,
+-0xf8, 0x60, 0xda, 0x61, 0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48,
+-0xc0, 0x46, 0xc2, 0x60, 0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e,
+-0xf8, 0x63, 0x0a, 0x48, 0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68,
+-0xc0, 0x46, 0x59, 0x80, 0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc,
+-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xbc, 0x20, 0x40,
+-0x90, 0xee, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40,
+-0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33,
+-0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46,
+-0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23,
+-0x1b, 0x01, 0xd1, 0x18, 0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80,
+-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46,
+-0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48,
+-0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23,
+-0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34,
+-0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61,
+-0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62,
+-0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d,
+-0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26,
+-0xb6, 0x03, 0x37, 0x61, 0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67,
+-0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60,
+-0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36,
+-0x7e, 0x61, 0x19, 0x4f, 0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c,
+-0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50,
+-0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27,
+-0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3,
+-0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3,
+-0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40,
+-0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40,
+-0x80, 0x01, 0x18, 0x00, 0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
+-0x08, 0x04, 0x00, 0x80, 0xb8, 0xb5, 0x2c, 0x48, 0xfd, 0xf7, 0xba, 0xfd,
+-0x01, 0x20, 0x2b, 0x49, 0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68,
+-0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20,
+-0x04, 0x06, 0x24, 0x0e, 0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23,
+-0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3,
+-0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61,
+-0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62,
+-0x00, 0x27, 0x1b, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69,
+-0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46,
+-0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46,
+-0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f,
+-0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43,
+-0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2,
+-0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49,
+-0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40,
+-0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01,
+-0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64,
+-0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67,
+-0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46,
+-0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc,
+-0x70, 0x47, 0x00, 0x00, 0xac, 0x66, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80,
+-0xd0, 0x2c, 0x00, 0x80, 0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63,
+-0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63,
+-0x01, 0x64, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20,
+-0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60,
+-0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a,
+-0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28,
+-0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80,
+-0xf4, 0x2d, 0x00, 0x80, 0x5d, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48,
+-0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b,
+-0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48,
+-0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b,
+-0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49,
+-0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b,
+-0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00,
+-0xac, 0x1e, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00,
+-0xac, 0xee, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00,
+-0xac, 0x3e, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80,
+-0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19,
+-0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63,
+-0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46,
+-0x08, 0x63, 0x48, 0x63, 0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d,
+-0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72,
+-0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32,
+-0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70,
+-0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72,
+-0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22,
+-0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73,
+-0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
+-0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73,
+-0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73,
+-0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71,
+-0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73,
+-0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73,
+-0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
+-0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73,
+-0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73,
+-0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71,
+-0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61,
+-0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00,
+-0xa0, 0x1c, 0x00, 0x80, 0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02,
+-0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00,
+-0x09, 0x49, 0x0a, 0x4b, 0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60,
+-0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31,
+-0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61,
+-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00,
+-0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20,
+-0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61,
+-0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
+-0x6c, 0x06, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32,
+-0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30,
+-0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+-0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d,
+-0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3,
+-0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60,
+-0x70, 0x47, 0x00, 0x00, 0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
+-0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfd, 0xf7, 0xea, 0xfb, 0x0b, 0x48,
+-0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46,
+-0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
+-0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47,
+-0xc1, 0xbd, 0x21, 0x40, 0x75, 0x98, 0x21, 0x40,
+-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x00, 0xb5, 0x0f, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
+-0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48,
+-0x0c, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xbf, 0xfb, 0x0b, 0x48, 0x41, 0x8d,
+-0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a,
+-0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x59, 0xbd, 0x21, 0x40,
+-0x75, 0x98, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0x1b, 0x4c,
+-0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28,
+-0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67,
+-0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18,
+-0xc1, 0x43, 0xe8, 0x61, 0x69, 0x62, 0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03,
+-0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x71,
+-0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 0xb8, 0x60, 0x00, 0xf0, 0x4c, 0xfa,
+-0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x20, 0xb8, 0x60, 0x07, 0x20, 0x78, 0x61,
+-0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0xc0, 0x8b, 0x04, 0x23,
+-0x18, 0x40, 0xe8, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x02, 0x1c, 0x00, 0x20, 0xff, 0x23,
+-0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 0x00, 0xd1, 0x01, 0x20,
+-0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 0x90, 0xbc, 0x70, 0x47,
+-0x1b, 0x4a, 0xd7, 0x68, 0x1a, 0x4b, 0x19, 0x79, 0x1c, 0x1c, 0x37, 0x23,
+-0x9b, 0x01, 0xe3, 0x18, 0x01, 0x2f, 0x0d, 0xd1, 0x57, 0x88, 0x00, 0x2f,
+-0x0a, 0xd1, 0x00, 0x29, 0x0a, 0xd1, 0x59, 0x8b, 0x0a, 0x09, 0x00, 0xd3,
+-0x02, 0x20, 0x49, 0x09, 0xe8, 0xd3, 0x01, 0x23, 0x18, 0x43, 0xe5, 0xe7,
+-0x00, 0x29, 0x03, 0xd0, 0x98, 0x8a, 0x80, 0x07, 0x80, 0x0f, 0xdf, 0xe7,
+-0x6d, 0x23, 0x5b, 0x01, 0xd1, 0x18, 0x8a, 0x88, 0xff, 0x27, 0x01, 0x37,
+-0x17, 0x40, 0x0a, 0x49, 0xc9, 0x88, 0x03, 0xd0, 0x4b, 0x0a, 0x01, 0xd3,
+-0x03, 0x20, 0xd1, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 0x0b, 0x0a, 0x01, 0xd3,
+-0x02, 0x20, 0xcb, 0xe7, 0xd2, 0x09, 0xc9, 0xd3, 0xc9, 0x09, 0xc7, 0xd3,
+-0x01, 0x20, 0xc5, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x1c, 0x00, 0x80,
+-0xf0, 0xb5, 0xc1, 0xb0, 0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46,
+-0x08, 0x60, 0x52, 0x48, 0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03,
+-0x48, 0x60, 0x50, 0x48, 0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21,
+-0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b,
+-0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33,
+-0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43,
+-0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07,
+-0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30,
+-0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03,
+-0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03,
+-0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62,
+-0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a,
+-0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34,
+-0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c,
+-0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42,
+-0xf5, 0xd1, 0x30, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68,
+-0x1b, 0x0c, 0x08, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24,
+-0x2b, 0x4b, 0xc0, 0x46, 0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b,
+-0x23, 0x4c, 0x51, 0x26, 0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0x3d, 0x6a,
+-0xc0, 0x46, 0x75, 0x61, 0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60,
+-0x01, 0x25, 0xb5, 0x60, 0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x71, 0x88, 0x42,
+-0x21, 0xd0, 0x25, 0x1c, 0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f,
+-0x6b, 0x44, 0x34, 0x60, 0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60,
+-0x2b, 0x6f, 0x08, 0x33, 0x2b, 0x67, 0x3c, 0x6a, 0xa3, 0x42, 0x02, 0xd3,
+-0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44,
+-0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03,
+-0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b,
+-0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfd, 0xf7, 0x74, 0xfa, 0x41, 0xb0,
+-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+-0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80,
+-0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00,
+-0xc9, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22,
+-0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33,
+-0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61,
+-0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61,
+-0x3f, 0x4d, 0xab, 0x6f, 0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23,
+-0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f,
+-0x9e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61,
+-0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23,
+-0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43,
+-0x3b, 0x61, 0x02, 0x23, 0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43,
+-0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00,
+-0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
+-0x2b, 0x43, 0x3b, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
+-0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08,
+-0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
+-0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
+-0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25,
+-0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43,
+-0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43,
+-0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61,
+-0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61,
+-0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40,
+-0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30,
+-0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61,
+-0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08,
+-0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x80, 0x00, 0x14, 0x40, 0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27,
+-0x44, 0x4a, 0xc0, 0x46, 0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c,
+-0xf9, 0xd3, 0x04, 0x26, 0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61,
+-0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61,
+-0x3c, 0x4b, 0x9b, 0x6f, 0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c,
+-0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f,
+-0x9d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
+-0x25, 0x43, 0x15, 0x61, 0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23,
+-0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61,
+-0x2d, 0x4b, 0x9d, 0x6f, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
+-0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00,
+-0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
+-0x15, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
+-0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40,
+-0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08,
+-0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
+-0x15, 0x61, 0x02, 0x25, 0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
+-0x25, 0x43, 0x15, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c,
+-0x33, 0x43, 0x13, 0x61, 0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23,
+-0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21,
+-0x25, 0x1c, 0xcd, 0x40, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43,
+-0x13, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39,
+-0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61,
+-0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
+-0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d,
+-0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfd, 0xf7, 0x27, 0xf9, 0x4d, 0x4c,
+-0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20,
+-0x2a, 0x1c, 0xfd, 0xf7, 0x1d, 0xf9, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28,
+-0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1,
+-0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02,
+-0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28,
+-0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21,
+-0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26,
+-0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe,
+-0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 0x00, 0x25, 0x05, 0xe0,
+-0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x2b, 0xff, 0x01, 0x35,
+-0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 0xb5, 0x42,
+-0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 0xff, 0x23, 0xe1, 0x33,
+-0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 0xff, 0x23, 0x01, 0x33,
+-0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01,
+-0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28,
+-0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23,
+-0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28,
+-0x03, 0xd1, 0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23,
+-0x19, 0x43, 0x04, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0x09, 0x21, 0x49, 0x02,
+-0x00, 0x20, 0xff, 0xf7, 0xf3, 0xfe, 0xe0, 0x68, 0x00, 0x28, 0x0c, 0xd1,
+-0x00, 0x21, 0x1b, 0x20, 0xff, 0xf7, 0xec, 0xfe, 0x1a, 0x20, 0xff, 0xf7,
+-0x4f, 0xfe, 0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7,
+-0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f,
+-0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19,
+-0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f,
+-0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xed, 0xaf, 0x21, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48,
+-0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91,
+-0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91,
+-0x01, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91,
+-0x81, 0x69, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91,
+-0x01, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91,
+-0x81, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90,
+-0x01, 0xb0, 0x70, 0x47, 0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0,
+-0x68, 0x4d, 0x1b, 0x23, 0xdb, 0x01, 0xef, 0x18, 0xf8, 0x8b, 0x04, 0x22,
+-0x02, 0x40, 0x02, 0x92, 0x71, 0x23, 0x5b, 0x01, 0xe8, 0x18, 0x01, 0x88,
+-0xc0, 0x46, 0x01, 0x91, 0x40, 0x88, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24,
+-0x03, 0xe0, 0x08, 0x2c, 0x01, 0xd3, 0x0f, 0x2c, 0x08, 0xd9, 0x20, 0x1c,
+-0xff, 0xf7, 0xe8, 0xfd, 0x61, 0x00, 0x49, 0x19, 0x1b, 0x23, 0xdb, 0x01,
+-0xc9, 0x18, 0x88, 0x83, 0x01, 0x34, 0x20, 0x2c, 0xef, 0xd3, 0x58, 0x4c,
+-0xe0, 0x69, 0x00, 0x28, 0x15, 0xd0, 0x57, 0x4e, 0x20, 0x25, 0x01, 0x3d,
+-0x53, 0x49, 0xe0, 0x69, 0x30, 0x40, 0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18,
+-0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x8b, 0x28, 0x1c, 0xff, 0xf7,
+-0x65, 0xfe, 0xe0, 0x69, 0xb0, 0x43, 0xe0, 0x61, 0x76, 0x08, 0x00, 0x2d,
+-0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 0xc2, 0xfd, 0x48, 0x49, 0xc0, 0x46,
+-0xf8, 0x83, 0xf8, 0x8b, 0xc2, 0x08, 0x25, 0xd3, 0xca, 0x68, 0x01, 0x2a,
+-0x13, 0xd1, 0x0a, 0x79, 0x00, 0x2a, 0x1f, 0xd1, 0x49, 0x88, 0x00, 0x29,
+-0x1c, 0xd1, 0x01, 0x99, 0x43, 0x4a, 0x00, 0x29, 0x05, 0xd0, 0x01, 0x29,
+-0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b,
+-0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1,
+-0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40,
+-0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x98, 0x43, 0xf8, 0x83,
+-0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 0x1f, 0xd0, 0xb9, 0x8b,
+-0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 0xff, 0x23, 0x01, 0x98,
+-0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 0x00, 0x98, 0x01, 0x28,
+-0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23,
+-0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0,
+-0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20,
+-0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2,
+-0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20,
+-0x40, 0x02, 0xb8, 0x83, 0xf8, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 0x1d, 0x48,
+-0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x51, 0xfc, 0xc2, 0x07,
+-0xd2, 0x0f, 0x1a, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 0x2b, 0x43,
+-0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65,
+-0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 0x03, 0xe0,
+-0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 0x61, 0x6a,
+-0x81, 0x42, 0x0c, 0xd0, 0x60, 0x62, 0x0e, 0x48, 0x00, 0x2a, 0x03, 0xd0,
+-0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x21, 0x33,
+-0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
+-0x00, 0x00, 0x00, 0x80, 0x28, 0x1c, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40,
+-0xa4, 0x2a, 0x00, 0x80, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22,
+-0x20, 0x28, 0x0f, 0xd2, 0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18,
+-0x37, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0x9f, 0x83, 0x82, 0x40, 0x07, 0x23,
+-0x5b, 0x02, 0xc9, 0x18, 0x10, 0x1c, 0xca, 0x69, 0x10, 0x43, 0xc8, 0x61,
+-0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69,
+-0x0b, 0x49, 0xc9, 0x8b, 0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0,
+-0x01, 0x23, 0xdb, 0x02, 0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43,
+-0x05, 0xe0, 0x01, 0x23, 0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08,
+-0x52, 0x00, 0xca, 0x65, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
+-0xe8, 0x1b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0,
+-0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20,
+-0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab,
+-0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91,
+-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfd, 0xf7, 0x79, 0xf8, 0x04, 0xb0,
+-0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68,
+-0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68,
+-0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0,
+-0x0a, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x4b, 0x98, 0x42,
+-0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x07, 0x4b, 0x98, 0x42,
+-0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x00,
+-0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80,
+-0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24,
+-0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68,
+-0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21,
+-0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 0x02, 0xd0, 0x38, 0x68,
+-0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x4b,
+-0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x05, 0xd0, 0x0e, 0x4b,
+-0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29,
+-0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0,
+-0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e,
+-0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40,
+-0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00,
+-0x07, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2,
+-0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x02, 0xd3,
+-0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 0x40, 0x6c, 0x00, 0x04,
+-0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 0x40, 0x08, 0x01, 0xd3,
+-0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 0x00, 0x00, 0x10, 0x40,
+-0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x27,
+-0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x72, 0xff, 0x03, 0x1c, 0x19, 0x4a,
+-0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 0x1b, 0xd1, 0xcb, 0x04,
+-0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 0x43, 0x60, 0x06, 0x68,
+-0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 0x43, 0x60, 0x03, 0x68,
+-0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 0x05, 0x23, 0x0f, 0x4f,
+-0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 0xc0, 0x46, 0x3b, 0x60,
+-0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 0x23, 0x60, 0x04, 0x23,
+-0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x06, 0x60, 0x27, 0x68,
+-0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x22, 0x40,
+-0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x28, 0x40,
+-0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x28, 0x05, 0xd1,
+-0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 0x08, 0x40, 0x22, 0xe0,
+-0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c,
+-0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x14, 0x48, 0x00, 0x68,
+-0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c,
+-0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 0x01, 0xa3, 0x1b, 0x5c,
+-0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03,
+-0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21,
+-0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e,
+-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x34, 0x6e, 0x21, 0x40,
+-0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40,
+-0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x82, 0xb0,
+-0x07, 0x1c, 0x01, 0x20, 0x01, 0x90, 0xff, 0xf7, 0xe7, 0xfe, 0x01, 0x28,
+-0x13, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x07, 0xd1, 0x00, 0x26,
+-0xf6, 0x43, 0x34, 0x1c, 0xa8, 0x2f, 0x02, 0xd1, 0x30, 0x1c, 0x00, 0x96,
+-0x35, 0x1c, 0x11, 0x20, 0x00, 0x04, 0x06, 0x62, 0x44, 0x62, 0x85, 0x62,
+-0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x08, 0x48, 0xc0, 0x46,
+-0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21,
+-0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x01, 0x98,
+-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x34, 0x6e, 0x21, 0x40,
+-0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
+-0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 0x0b, 0xd0, 0x00, 0x23,
+-0x21, 0x1c, 0xe2, 0x1d, 0xc1, 0x32, 0x00, 0xe0,
+-0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xc8, 0x20, 0xa0, 0x80,
+-0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48,
+-0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19,
+-0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80,
+-0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80,
+-0xee, 0xff, 0xc0, 0xd0, 0x08, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a,
+-0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7a, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23,
+-0x0b, 0x72, 0x07, 0x1c, 0x08, 0x7a, 0x43, 0x1c, 0x0b, 0x72, 0x80, 0x18,
+-0x90, 0x30, 0x47, 0x72, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80,
+-0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20,
+-0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68,
+-0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40,
+-0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7,
+-0x91, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42,
+-0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7,
+-0xc5, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x66, 0x21, 0x40,
+-0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c,
+-0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89,
+-0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c,
+-0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c,
+-0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e,
+-0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 0x79, 0x6c, 0x59, 0x43,
+-0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 0x01, 0x32, 0x12, 0x04,
+-0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22,
+-0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88,
+-0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23,
+-0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49,
+-0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81,
+-0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20,
+-0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfb, 0xf0, 0x88,
+-0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04,
+-0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80,
+-0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0,
+-0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 0xf9, 0x7a, 0x00, 0x29,
+-0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 0x79, 0x64, 0x2a, 0xd0,
+-0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 0x01, 0x31, 0xe1, 0x80,
+-0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 0xdb, 0x03, 0x78, 0x6c,
+-0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0,
+-0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18,
+-0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xfb, 0xe0, 0x6a,
+-0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39,
+-0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 0x89, 0xfb, 0xb6, 0xe7,
+-0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04,
+-0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80,
+-0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b,
+-0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d,
+-0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
+-0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88,
+-0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30,
+-0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19,
+-0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xfa, 0x71, 0x88,
+-0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0,
+-0x4d, 0xfb, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35,
+-0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25,
+-0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc,
+-0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
+-0xc4, 0x66, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03,
+-0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d,
+-0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a,
+-0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e,
+-0x6d, 0xd0, 0xed, 0x6a, 0x5e, 0x1e, 0x73, 0x00, 0x9b, 0x19, 0x5b, 0x01,
+-0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0,
+-0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x35, 0xad, 0x8b, 0xad, 0x00,
+-0x35, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0x70, 0x51, 0x55, 0x89, 0x01, 0x35,
+-0x55, 0x81, 0x32, 0x4e, 0xf2, 0x6a, 0xd2, 0x18, 0x90, 0x60, 0xf2, 0x6a,
+-0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a,
+-0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a,
+-0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88,
+-0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 0x88, 0x81, 0x24, 0x49,
+-0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 0x00, 0x2e, 0x38, 0xd9,
+-0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 0x00, 0x2b, 0x2c, 0xd0,
+-0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 0xad, 0x6a, 0x58, 0x23,
+-0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e,
+-0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0xa8, 0x60,
+-0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0xe8, 0x63,
+-0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 0xed, 0x18, 0x68, 0x64,
+-0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 0xeb, 0x18, 0xd8, 0x64,
+-0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 0xc0, 0x46, 0x48, 0x81,
+-0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 0x03, 0xe0, 0x17, 0x80,
+-0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81,
+-0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
+-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49,
+-0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0,
+-0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69,
+-0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61,
+-0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a,
+-0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46,
+-0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+-0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 0x4c, 0xd0, 0x08, 0x22,
+-0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 0xd9, 0x1d, 0xb9, 0x31,
+-0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
+-0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
+-0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
+-0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
+-0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
+-0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
+-0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 0xcc, 0x82, 0x4f, 0x83,
+-0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 0x8c, 0x00, 0x05, 0x19,
+-0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 0x01, 0x34, 0x65, 0x62,
+-0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00,
+-0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29,
+-0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xac, 0xab, 0x20, 0x40,
+-0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+-0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00,
+-0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
+-0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36,
+-0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d,
+-0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
+-0x44, 0xfb, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c,
+-0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x3b, 0xfb, 0x29, 0x1c, 0x23, 0x1c,
+-0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x35, 0xfb, 0x39, 0x1c, 0x23, 0x1c,
+-0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x2f, 0xfb, 0x00, 0x21, 0x0b, 0x48,
+-0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30,
+-0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0xac, 0xab, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00,
+-0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 0x6c, 0x06, 0x00, 0x80,
+-0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30,
+-0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29,
+-0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1,
+-0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23,
+-0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33,
+-0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43,
+-0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68,
+-0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0,
+-0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46,
+-0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c,
+-0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00,
+-0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35,
+-0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2,
+-0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32,
+-0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 0xbc, 0xe7, 0x00, 0x21,
+-0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31,
+-0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43,
+-0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46,
+-0x50, 0x61, 0x09, 0x48, 0xfc, 0xf7, 0xa4, 0xfa, 0xa4, 0xe7, 0x00, 0x00,
+-0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01,
+-0xac, 0xab, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00,
+-0x5c, 0x5c, 0x5c, 0x5c, 0x11, 0x31, 0xff, 0xff, 0xf0, 0xb5, 0x07, 0x1c,
+-0x3b, 0x48, 0x3c, 0x4c, 0x08, 0x21, 0x20, 0x60, 0xa1, 0x80, 0x00, 0x20,
+-0x20, 0x81, 0xe1, 0x80, 0x60, 0x81, 0x39, 0x48, 0xc0, 0x46, 0xe0, 0x60,
+-0x38, 0x48, 0xc0, 0x46, 0x20, 0x61, 0x38, 0x48, 0xc0, 0x46, 0x60, 0x61,
+-0x37, 0x48, 0xc0, 0x46, 0xa0, 0x61, 0x37, 0x48, 0xc0, 0x46, 0xe0, 0x61,
+-0x36, 0x48, 0xc0, 0x46, 0x20, 0x62, 0x36, 0x48, 0xc0, 0x46, 0x60, 0x62,
+-0x35, 0x48, 0xc0, 0x46, 0xa0, 0x62, 0x35, 0x48, 0xc0, 0x46, 0xe0, 0x62,
+-0x34, 0x48, 0xc0, 0x46, 0x20, 0x63, 0x34, 0x48, 0xc0, 0x46, 0x60, 0x63,
+-0x33, 0x48, 0xc0, 0x46, 0xa0, 0x63, 0x33, 0x48, 0xc0, 0x46, 0xe0, 0x63,
+-0x32, 0x48, 0xc0, 0x46, 0x20, 0x64, 0x32, 0x48, 0xc0, 0x46, 0x60, 0x64,
+-0x31, 0x48, 0xc0, 0x46, 0xa0, 0x64, 0x31, 0x48, 0xc0, 0x46, 0xe0, 0x64,
+-0x30, 0x48, 0xc0, 0x46, 0x20, 0x65, 0x30, 0x49, 0xc8, 0x68, 0x02, 0x04,
+-0x89, 0x69, 0x4a, 0x40, 0xe3, 0x1d, 0x79, 0x33, 0x09, 0x04, 0xc9, 0x43,
+-0xc0, 0x43, 0x48, 0x40, 0xe1, 0x1d, 0xb9, 0x31, 0xda, 0x63, 0x08, 0x60,
+-0x29, 0x4d, 0x21, 0x1c, 0x2b, 0x1c, 0x29, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
+-0x3e, 0xfa, 0x28, 0x4a, 0xe1, 0x1d, 0xb5, 0x31, 0x01, 0x20, 0x2b, 0x1c,
+-0x0e, 0x1c, 0xfc, 0xf7, 0x36, 0xfa, 0x24, 0x4a, 0x00, 0x20, 0x31, 0x1c,
+-0x2b, 0x1c, 0xfc, 0xf7, 0x30, 0xfa, 0xe1, 0x1d, 0x4d, 0x31, 0x2b, 0x1c,
+-0x20, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x29, 0xfa, 0xe0, 0x1d, 0x5d, 0x30,
+-0x01, 0x68, 0x00, 0x29, 0xfc, 0xd0, 0x60, 0x6d, 0xc0, 0x46, 0x38, 0x65,
+-0x20, 0x6e, 0xc0, 0x46, 0x78, 0x65, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x80, 0x00, 0x08, 0x00, 0x8c, 0xb9, 0x20, 0x40, 0x81, 0x81, 0x48, 0xbd,
+-0x79, 0x56, 0x23, 0x8c, 0x93, 0x0c, 0x82, 0x95, 0x1d, 0x0e, 0x12, 0xcf,
+-0x9b, 0x3b, 0xc0, 0xe9, 0xe6, 0x55, 0x7c, 0x82, 0x99, 0xf6, 0x78, 0x02,
+-0xd1, 0xd7, 0x25, 0x73, 0x72, 0x8c, 0x33, 0x10, 0xf7, 0x03, 0xf1, 0x42,
+-0x6c, 0x9b, 0x4a, 0xa7, 0x82, 0x8e, 0x23, 0xa9, 0x90, 0xb1, 0x82, 0x8e,
+-0xdc, 0x3f, 0xfb, 0x29, 0x00, 0x62, 0x22, 0x45, 0x88, 0x2b, 0xf1, 0x85,
+-0x12, 0x61, 0xd1, 0x73, 0x6e, 0xb1, 0x11, 0x16, 0x08, 0x83, 0x20, 0x40,
+-0x75, 0x08, 0xff, 0xff, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00,
+-0x14, 0x00, 0x03, 0x00, 0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0,
+-0x33, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x4c, 0xff, 0x03, 0x48, 0x01, 0x89,
+-0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
+-0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68,
+-0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43,
+-0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06,
+-0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69,
+-0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81,
+-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
+-0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18,
+-0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08,
+-0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b,
+-0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b,
+-0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c,
+-0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88,
+-0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 0x03, 0x7a, 0x1b, 0x04,
+-0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 0x43, 0x7a, 0xdb, 0x07,
+-0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 0x5a, 0x08, 0x05, 0xd3,
+-0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 0x15, 0x22, 0x00, 0xe0,
+-0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3,
+-0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a,
+-0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c,
+-0xff, 0xf7, 0x78, 0xfd, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23,
+-0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31,
+-0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
+-0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40,
+-0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 0x2e, 0x1c, 0x45, 0x6d,
+-0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 0xfd, 0x40, 0x2f, 0x1c,
+-0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 0x08, 0xd0, 0x23, 0x69,
+-0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 0xbe, 0x00, 0xae, 0x59,
+-0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 0x11, 0x43, 0x05, 0x4b,
+-0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 0x87, 0x83, 0xf0, 0xbc,
+-0x70, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+-0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78,
+-0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43,
+-0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c,
+-0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x9a, 0xf8,
+-0x00, 0xf0, 0xb8, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xc7, 0xfa, 0x3d, 0x70,
+-0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x93, 0xf8, 0x00, 0xf0,
+-0xa7, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x38, 0x0a, 0xf6, 0xd3,
+-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x82, 0xb0, 0x02, 0x98,
+-0x41, 0x02, 0x53, 0x20, 0x00, 0xf0, 0x64, 0xf8, 0x00, 0xf0, 0xa8, 0xfa,
+-0xff, 0xf7, 0xe8, 0xff, 0x00, 0x24, 0x00, 0x20, 0x01, 0x90, 0x2e, 0x20,
+-0x00, 0x90, 0x00, 0x25, 0x00, 0x27, 0x02, 0x98, 0x01, 0x28, 0x04, 0xd1,
+-0x00, 0x98, 0x84, 0x42, 0x01, 0xd3, 0x00, 0x26,
+-0x09, 0xe0, 0x01, 0x98, 0x41, 0x1c, 0x01, 0x91, 0x00, 0xf0, 0x60, 0xf8,
+-0x00, 0xf0, 0x7e, 0xf9, 0x06, 0x1c, 0x00, 0xf0, 0x8d, 0xfa, 0xf8, 0x00,
+-0x86, 0x40, 0x35, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xe6, 0xd3,
+-0x03, 0x99, 0x20, 0xc1, 0x03, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42,
+-0xdd, 0xd3, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5,
+-0x04, 0x1c, 0x0f, 0x1c, 0x01, 0x2c, 0x2a, 0xd0, 0x16, 0x48, 0xc0, 0x6f,
+-0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x00, 0x26, 0x20, 0xcf,
+-0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x28, 0x1c, 0x00, 0xf0,
+-0xdf, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xdc, 0xf9, 0x28, 0x0c, 0x00, 0xf0,
+-0xd9, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xd6, 0xf9, 0x00, 0xf0, 0x5c, 0xfa,
+-0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 0x83, 0x20, 0x00, 0xf0,
+-0x0f, 0xf8, 0x00, 0xf0, 0x53, 0xfa, 0xff, 0xf7, 0x93, 0xff, 0x04, 0x48,
+-0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
+-0x0f, 0x1c, 0x00, 0xf0, 0x59, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9,
+-0x38, 0x0c, 0x00, 0xf0, 0xb3, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xb0, 0xf9,
+-0x38, 0x1c, 0x00, 0xf0, 0xad, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x00, 0xb5, 0x01, 0x1c, 0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20,
+-0x00, 0xf0, 0xa2, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
+-0x3d, 0xfa, 0x57, 0x20, 0x00, 0xf0, 0x9a, 0xf9, 0x08, 0xbc, 0x18, 0x47,
+-0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43,
+-0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0xf8, 0x6f, 0x20, 0x23,
+-0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23,
+-0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x87, 0xff,
+-0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x04, 0x1c,
+-0x0f, 0x1c, 0x18, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x99, 0x43,
+-0x01, 0x60, 0x61, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0x00, 0xf0,
+-0xe9, 0xf9, 0xff, 0xf7, 0x29, 0xff, 0xf8, 0x1d, 0x05, 0x30, 0x01, 0x2c,
+-0x03, 0xd1, 0x22, 0x2f, 0x01, 0xd3, 0x00, 0x27, 0x0f, 0xe0, 0x44, 0x1c,
+-0xff, 0xf7, 0xaa, 0xff, 0x00, 0xf0, 0xc8, 0xf8, 0x07, 0x1c, 0x00, 0xf0,
+-0xd7, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 0xa2, 0xff, 0x00, 0xf0, 0xc0, 0xf8,
+-0x05, 0x1c, 0x00, 0xf0, 0xcf, 0xf9, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68,
+-0x19, 0x43, 0x01, 0x60, 0x28, 0x02, 0x38, 0x43, 0xf0, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0,
+-0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0x01, 0x2f, 0x2f, 0xd0, 0x79, 0x02,
+-0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
+-0x53, 0x20, 0xff, 0xf7, 0x6b, 0xff, 0x00, 0xf0, 0xaf, 0xf9, 0xff, 0xf7,
+-0xef, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0xd6, 0xfe, 0x6a, 0x46, 0xe8, 0x1d,
+-0x05, 0x30, 0x14, 0x54, 0x21, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46,
+-0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xba, 0xfe, 0x02, 0xab, 0x18, 0x70,
+-0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21,
+-0xff, 0xf7, 0xb2, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x38, 0x1c,
+-0xff, 0xf7, 0x15, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43,
+-0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x01, 0x2f,
+-0x01, 0xd1, 0x01, 0x20, 0x36, 0xe0, 0x6b, 0x46, 0x00, 0x20, 0xc4, 0x43,
+-0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30,
+-0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46,
+-0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31,
+-0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c,
+-0xff, 0xf7, 0x7c, 0xfe, 0x04, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x02, 0xab,
+-0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7,
+-0x71, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 0x1d, 0x06, 0x2d, 0x0e,
+-0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x3e, 0xff,
+-0x01, 0x20, 0xac, 0x42, 0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02,
+-0x14, 0x4c, 0xe0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
+-0x53, 0x20, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7,
+-0x73, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0x5a, 0xfe, 0xe0, 0x6f, 0x20, 0x23,
+-0x01, 0x68, 0x19, 0x43, 0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24,
+-0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x3c, 0xfe,
+-0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c,
+-0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3,
+-0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+-0x81, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1,
+-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x93, 0xe5, 0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+-0x01, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1,
+-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x93, 0xe5, 0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+-0x81, 0x00, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+-0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47,
+-0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 0xa0, 0x13, 0xa0, 0xe1,
+-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
+-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1,
+-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
+-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1,
+-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
+-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5,
+-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5,
+-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5,
+-0x3c, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+-0x00, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+-0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40,
+-0x04, 0x01, 0x18, 0x40, 0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40,
+-0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0,
+-0x47, 0xf8, 0x78, 0x1c, 0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd,
+-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1d, 0x48,
+-0x02, 0x68, 0x1d, 0x49, 0x8b, 0x69, 0xd2, 0x18, 0x02, 0x60, 0x02, 0x66,
+-0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 0x02, 0xd2,
+-0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 0xd2, 0x18,
+-0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 0xc2, 0x69,
+-0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 0xd2, 0x18,
+-0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 0x02, 0x6b,
+-0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18,
+-0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63,
+-0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 0xc9, 0x6a,
+-0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
+-0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8,
+-0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22,
+-0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42,
+-0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
+-0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22,
+-0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0,
+-0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c,
+-0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60,
+-0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00,
+-0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
+-0xa0, 0x82, 0x20, 0x40, 0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a,
+-0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60,
+-0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30,
+-0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31,
+-0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30,
+-0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20,
+-0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31,
+-0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47,
+-0x08, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x04, 0x00, 0x80,
+-0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x23,
+-0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 0x00, 0x22, 0x0a, 0x70,
+-0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 0x43, 0x83, 0x7d, 0x21,
+-0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
+-0x00, 0xf0, 0x8e, 0xfb, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0xb5, 0x22, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48,
+-0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x80, 0xfb, 0x01, 0x23, 0xd8, 0x42,
+-0x0a, 0xd1, 0x10, 0x48, 0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32,
+-0xca, 0x80, 0x81, 0x79, 0x01, 0x31, 0x81, 0x71, 0xfd, 0xf7, 0x70, 0xf9,
+-0x0b, 0x48, 0xc0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22,
+-0xd2, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x68, 0xfb, 0x08, 0x48, 0xfb, 0xf7,
+-0xe1, 0xfc, 0x08, 0x48, 0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x60, 0xfb,
+-0x08, 0xbc, 0x18, 0x47, 0x79, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40,
+-0x68, 0x0e, 0x00, 0x80, 0xa5, 0x7b, 0x21, 0x40,
+-0x95, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20,
+-0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21,
+-0xfb, 0xf7, 0xc6, 0xfc, 0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68,
+-0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c,
+-0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46,
+-0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64,
+-0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa5, 0x55, 0xff, 0xff,
+-0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
+-0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 0x01, 0x22, 0x12, 0x04,
+-0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68,
+-0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x21, 0x48,
+-0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 0xc0, 0x46, 0x01, 0x64,
+-0x1f, 0x48, 0xfb, 0xf7, 0x87, 0xfc, 0x1f, 0x48, 0xc1, 0x6b, 0xff, 0x29,
+-0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 0x0f, 0x1c, 0x1c, 0x4c,
+-0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43,
+-0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x28, 0x61,
+-0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfb, 0xf7, 0x6f, 0xfc, 0x16, 0x4a,
+-0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 0x39, 0x1c, 0x32, 0x1c,
+-0xfb, 0xf7, 0x6e, 0xfc, 0x13, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1,
+-0x12, 0x48, 0xfb, 0xf7, 0x5d, 0xfc, 0x10, 0x23, 0x60, 0x69, 0x98, 0x43,
+-0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18,
+-0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40,
+-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
+-0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
+-0xb5, 0xb6, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 0x44, 0x80, 0x20, 0x40,
+-0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0xfd, 0xf7,
+-0x01, 0xff, 0x06, 0x48, 0xfb, 0xf7, 0x32, 0xfc, 0xfd, 0xf7, 0xd6, 0xfe,
+-0xfe, 0xf7, 0x04, 0xf8, 0xfe, 0xf7, 0x16, 0xf8, 0xfe, 0xf7, 0x24, 0xf8,
+-0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 0x90, 0xb5, 0xfd, 0xf7,
+-0x6b, 0xfc, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 0xf8, 0x1d, 0x79, 0x30,
+-0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 0xf9, 0x67, 0x31, 0x49,
+-0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 0x0c, 0x60, 0x4c, 0x60,
+-0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 0x8c, 0x61, 0x04, 0xe0,
+-0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 0x08, 0x38, 0x00, 0x68,
+-0x60, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23,
+-0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68,
+-0x99, 0x43, 0x01, 0x60, 0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x4e, 0xfc,
+-0x00, 0xf0, 0x5e, 0xf9, 0xfd, 0xf7, 0x73, 0xf8, 0xff, 0xf7, 0x0c, 0xfe,
+-0xfd, 0xf7, 0x2e, 0xfe, 0xfd, 0xf7, 0xb6, 0xfd, 0xfd, 0xf7, 0xc2, 0xfe,
+-0xfd, 0xf7, 0x54, 0xfd, 0xfd, 0xf7, 0x0a, 0xfd, 0xfd, 0xf7, 0x94, 0xfd,
+-0x00, 0xf0, 0x1a, 0xfa, 0xfd, 0xf7, 0x9c, 0xff, 0xfd, 0xf7, 0x0a, 0xff,
+-0xfd, 0xf7, 0xd2, 0xfe, 0xfd, 0xf7, 0x3c, 0xfc, 0xfb, 0xf7, 0xdc, 0xfa,
+-0xff, 0xf7, 0x9c, 0xff, 0x71, 0x23, 0x5b, 0x01,
+-0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 0xf8, 0x18,
+-0x04, 0x63, 0xf8, 0x68, 0x01, 0x28, 0x02, 0xd1, 0xa8, 0x20, 0xfe, 0xf7,
+-0xb1, 0xfd, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 0x18, 0xfa,
+-0x07, 0x48, 0xfb, 0xf7, 0xbd, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 0x04, 0x01, 0x11, 0x40,
+-0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x15, 0x8f, 0x21, 0x40,
+-0x00, 0xb5, 0x04, 0x48, 0xfb, 0xf7, 0xaa, 0xfb, 0xfd, 0xf7, 0x5e, 0xff,
+-0xfd, 0xf7, 0x24, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x15, 0x99, 0x21, 0x40,
+-0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62,
+-0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69,
+-0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61,
+-0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61,
+-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10,
+-0x00, 0xb5, 0x02, 0x48, 0xfb, 0xf7, 0x80, 0xfb, 0x08, 0xbc, 0x18, 0x47,
+-0xc8, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 0x01, 0x21, 0x09, 0x04,
+-0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 0x22, 0x4d, 0x00, 0x29,
+-0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a,
+-0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 0x1d, 0x48, 0xfb, 0xf7,
+-0x65, 0xfb, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 0x01, 0x30, 0x88, 0x61,
+-0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 0x00, 0x28, 0x1f, 0xd0,
+-0x19, 0x48, 0xfb, 0xf7, 0x57, 0xfb, 0x19, 0x48, 0xfb, 0xf7, 0x54, 0xfb,
+-0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x16, 0x48,
+-0xfb, 0xf7, 0x4c, 0xfb, 0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40,
+-0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1,
+-0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x01, 0xe0, 0x28, 0x64,
+-0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0x65, 0xfd, 0x0b, 0x48, 0xfb, 0xf7,
+-0x35, 0xfb, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40,
+-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
+-0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf4, 0x01, 0xff, 0xff,
+-0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9f, 0x21, 0x40,
+-0x00, 0x20, 0x07, 0x4a, 0x01, 0x21, 0x09, 0x05, 0x50, 0x61, 0xc8, 0x60,
+-0xd0, 0x61, 0xc8, 0x61, 0x03, 0x23, 0xdb, 0x04, 0x03, 0x4a, 0x01, 0x21,
+-0xd1, 0x63, 0x58, 0x60, 0xfc, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xc0, 0xb0, 0x01, 0x22, 0x00, 0x21,
+-0x0a, 0x20, 0xfc, 0xf7, 0xd1, 0xff, 0x07, 0x1c, 0xff, 0x2f, 0x28, 0xd0,
+-0x69, 0x46, 0xff, 0x22, 0x38, 0x1c, 0x01, 0x32, 0xfd, 0xf7, 0x54, 0xf9,
+-0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x1b, 0xd1, 0x0d, 0x98, 0x00, 0x09,
+-0x18, 0xd3, 0x38, 0x1c, 0xfd, 0xf7, 0x8d, 0xf8, 0x0e, 0x49, 0x01, 0x22,
+-0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x0d, 0x48, 0x05, 0xd1, 0x0a, 0x68,
+-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x0a, 0x49,
+-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x64,
+-0xff, 0xf7, 0xbc, 0xff, 0x38, 0x1c, 0xfd, 0xf7, 0x74, 0xf8, 0x40, 0xb0,
+-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+-0x00, 0x00, 0x10, 0x40, 0x07, 0x80, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
+-0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x17, 0x49, 0x01, 0x22, 0x12, 0x04,
+-0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68,
+-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x11, 0x49,
+-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x64,
+-0x03, 0x20, 0xfe, 0xf7, 0xd3, 0xfc, 0xfb, 0xf7, 0x0d, 0xff, 0x01, 0x23,
+-0x18, 0x43, 0xfb, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0x83, 0xfe, 0xff, 0xf7,
+-0x9d, 0xff, 0xff, 0xf7, 0x05, 0xfe, 0xff, 0xf7, 0xf5, 0xfe, 0xff, 0xf7,
+-0x09, 0xff, 0xff, 0xf7, 0x9b, 0xfd, 0xff, 0xf7, 0x21, 0xff, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
+-0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03,
+-0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88,
+-0x40, 0x04, 0x43, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x04, 0x20, 0xaf, 0x60,
+-0x41, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x08, 0x20, 0xc8, 0x23, 0x43, 0x43,
+-0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3d, 0x4e, 0xc0, 0x46, 0x31, 0x61,
+-0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3a, 0x4e, 0xc0, 0x46, 0xf3, 0x61,
+-0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 0x81, 0x42,
+-0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 0x41, 0x1e,
+-0x32, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 0x02, 0x38,
+-0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 0x06, 0xe0,
+-0x2c, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 0x88, 0x42,
+-0xd2, 0xd9, 0x2a, 0x49, 0x00, 0x20, 0xa3, 0x69, 0x9b, 0x08, 0x07, 0xd0,
+-0x28, 0x4b, 0x87, 0x00, 0xcb, 0x51, 0xa7, 0x69, 0xbf, 0x08, 0x01, 0x30,
+-0x87, 0x42, 0xf8, 0xd8, 0x22, 0x49, 0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89,
+-0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 0x00, 0x20, 0x00, 0x22, 0x00, 0x2c,
+-0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30,
+-0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc,
+-0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 0x00, 0x19, 0x40, 0x01, 0xc7, 0x19,
+-0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01,
+-0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60,
+-0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69,
+-0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51,
+-0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00,
+-0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
+-0xb0, 0xbe, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
+-0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00,
+-0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09,
+-0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61,
+-0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x81, 0x61, 0x01, 0x20, 0x00, 0x06,
+-0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18,
+-0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61,
+-0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05,
+-0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20,
+-0x40, 0x03, 0x81, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
+-0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8,
+-0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23,
+-0x9b, 0x01, 0xfb, 0x18, 0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3,
+-0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc,
+-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1d, 0x3e, 0xff, 0xff,
+-0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47,
+-0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b,
+-0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c,
+-0x59, 0x69, 0x53, 0x01, 0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43,
+-0x87, 0x61, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc,
+-0x70, 0x47, 0x18, 0x1c, 0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43,
+-0x47, 0x61, 0xd7, 0x60, 0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00,
+-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c,
+-0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9d, 0x6a,
+-0xbd, 0x42, 0x05, 0xd1, 0x1d, 0x6b, 0x95, 0x42, 0x02, 0xd1, 0xdb, 0x6a,
+-0x8b, 0x42, 0x1c, 0xd0, 0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20,
+-0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9b, 0x6a,
+-0x00, 0x2b, 0x09, 0xd1, 0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01,
+-0xe3, 0x18, 0x1a, 0x63, 0xd9, 0x62, 0x5a, 0x63, 0x9f, 0x62, 0x02, 0xe0,
+-0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20,
+-0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+-0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0,
+-0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01,
+-0xe3, 0x18, 0x9b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19,
+-0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61,
+-0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62,
+-0x53, 0x6b, 0xc0, 0x46, 0x53, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28,
+-0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x9a, 0x68, 0x8a, 0x42,
+-0x03, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20,
+-0xc0, 0x43, 0xfa, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80,
+-0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69,
+-0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01,
+-0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0xc0, 0x46,
+-0x43, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61,
+-0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x68, 0x0e, 0x00, 0x80,
+-0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69,
+-0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a,
+-0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47,
+-0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
+-0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0xff, 0xf7, 0xe3, 0xff, 0x01, 0x34,
+-0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc,
+-0x18, 0x47, 0x00, 0x00,
++0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00,
++0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0xb1, 0xd4,
++0x4c, 0xb8, 0xd0, 0x4b, 0x32, 0x02, 0xd4, 0xee, 0x73, 0x7e, 0x0b, 0x13,
++0x9b, 0xc0, 0xae, 0xf4, 0x40, 0x01, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00,
++0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea,
++0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
++0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc5, 0x14, 0x00, 0xea,
++0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1,
++0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
++0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1,
++0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 0x00, 0xa0, 0xa0, 0xe1,
++0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0xa8, 0x10, 0x9f, 0xe5,
++0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5,
++0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe3,
++0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
++0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
++0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
++0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
++0x6c, 0xd0, 0x9f, 0xe5, 0x9b, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3,
++0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5,
++0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb,
++0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
++0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 0x54, 0x10, 0x9f, 0xe5,
++0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1,
++0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb,
++0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea,
++0x15, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00,
++0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
++0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80,
++0xad, 0xde, 0xad, 0xde, 0xb0, 0xbb, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40,
++0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xbd, 0xba, 0x21, 0x40,
++0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x58, 0x57, 0x00, 0x00, 0x86, 0x4b, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff,
++0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4d, 0x00, 0x24, 0x28, 0x68, 0x00, 0x28,
++0x1e, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x7b, 0xfd, 0x29, 0x68,
++0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x15, 0xd0, 0x38, 0x01, 0x0d, 0x49,
++0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29,
++0x0c, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x28, 0x68, 0xc1, 0x69, 0xc0, 0x46,
++0x29, 0x60, 0x39, 0x07, 0x41, 0x60, 0x04, 0x62, 0xc7, 0x62, 0xb0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0xe8, 0x17, 0x00, 0x80,
++0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68,
++0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47,
++0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
++0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0x00, 0x10, 0xa0, 0xe1,
++0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
++0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
++0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
++0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
++0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x80, 0xe3,
++0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
++0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
++0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3,
++0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 0x00, 0xf0, 0x21, 0xe1,
++0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
++0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x91, 0x00, 0x00, 0xe0,
++0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0,
++0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3,
++0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63,
++0x04, 0x49, 0x05, 0xf0, 0x01, 0xfb, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00,
++0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2,
++0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc,
++0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 0xbb, 0x42, 0x05, 0xd2,
++0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 0xc8, 0x63, 0xf1, 0xe7,
++0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x04, 0x48, 0xc1, 0x6b,
++0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 0x68, 0x0e, 0x00, 0x80,
++0x00, 0x00, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
++0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 0x0b, 0xd2, 0xb9, 0x6e,
++0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2,
++0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62,
++0x38, 0x6b, 0x02, 0xf0, 0x2d, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xe8, 0xfa,
++0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49,
++0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18,
++0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
++0xa4, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 0xc0, 0x6d, 0x02, 0x23,
++0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 0x03, 0xd0, 0xd1, 0x63,
++0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 0x07, 0x68, 0x7b, 0x1c,
++0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 0xf3, 0xe7, 0x00, 0x00,
++0xa4, 0x2a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xe0, 0x01, 0x00, 0x80,
++0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 0x10, 0x18, 0x0a, 0x04,
++0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 0x01, 0x0c, 0x05, 0xd0,
++0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 0x01, 0x0c, 0xf9, 0xd1,
++0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 0x00, 0x22, 0x00, 0x29,
++0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f,
++0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b,
++0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 0x00, 0x88, 0x00, 0x06,
++0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c,
++0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c,
++0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 0xc7, 0x89, 0xfb, 0x18,
++0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 0x40, 0x7a, 0x00, 0x02,
++0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 0x00, 0x0c, 0x3b, 0x0c,
++0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 0x11, 0x1c, 0xff, 0xf7,
++0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xff, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 0x82, 0x68, 0x1a, 0x40,
++0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 0x93, 0x69, 0x01, 0x33,
++0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 0x00, 0x68, 0x1c, 0x18,
++0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43,
++0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 0x82, 0x68, 0x1a, 0x40,
++0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 0x52, 0x09, 0x0e, 0xd3,
++0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 0xcb, 0x68, 0x02, 0x68,
++0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68,
++0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x80, 0x23,
++0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 0x15, 0xd0, 0x4a, 0x68,
++0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 0x01, 0x33, 0xd3, 0x61,
++0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a,
++0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 0x00, 0x28, 0x00, 0xd1,
++0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
++0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 0x38, 0x69, 0xb9, 0x68,
++0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 0xc0, 0x43, 0x01, 0x04,
++0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x04, 0x1c, 0xb8, 0x68,
++0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 0x0c, 0xd2, 0x2a, 0x68,
++0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x05, 0xf9, 0xc0, 0x43,
++0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x26, 0xff, 0x04, 0x1c,
++0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 0x1a, 0xd3, 0xb8, 0x6a,
++0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 0xed, 0xf8, 0xc0, 0x43,
++0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 0x20, 0x23, 0xb9, 0x69,
++0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x07, 0xe0,
++0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x41, 0x6a,
++0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x0c, 0x2b, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x41, 0x09,
++0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
++0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x53, 0xf8, 0x01, 0x1c,
++0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69,
++0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0,
++0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0xc1, 0x6a,
++0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x0c, 0x2b, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x81, 0x09,
++0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
++0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 0x40, 0x18, 0x01, 0x23,
++0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 0x05, 0x04, 0x2d, 0x0c,
++0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0x28,
++0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 0x98, 0x42, 0x07, 0xd0,
++0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x60, 0x6b, 0x01, 0x30,
++0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 0xb8, 0x69, 0x18, 0x43,
++0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 0x00, 0x20, 0xb0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
++0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 0xe0, 0x6b, 0x61, 0x6c,
++0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 0x00, 0x20, 0x8a, 0x08,
++0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 0x9f, 0x58, 0x03, 0xae,
++0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 0xf7, 0xd8, 0x60, 0x6a,
++0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
++0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 0xff, 0xf7, 0x87, 0xfe,
++0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x6d, 0xfe,
++0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 0x61, 0x6a, 0x01, 0x23,
++0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x01, 0x91,
++0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 0x0c, 0xd2, 0xa2, 0x6a,
++0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x2f, 0xf8, 0xc0, 0x43,
++0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0x07, 0x1c,
++0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 0x08, 0x18, 0x69, 0x8a,
++0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 0xa1, 0x6c, 0x62, 0x6c,
++0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
++0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 0x05, 0xd0, 0x08, 0x04,
++0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 0xf9, 0xd1, 0x38, 0x1c,
++0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0xb0,
++0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb4, 0x00, 0x22,
++0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 0xdc, 0x00, 0x47, 0x18,
++0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 0xff, 0x00, 0x80, 0x08,
++0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 0x4d, 0x1e, 0x02, 0xc8,
++0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 0x09, 0xd0, 0x0c, 0x04,
++0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 0x02, 0xc8, 0x1c, 0x1c,
++0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 0x08, 0x1c, 0xf8, 0x40,
++0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 0x42, 0x18, 0x10, 0x0c,
++0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c,
++0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00,
++0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 0x42, 0x00, 0x12, 0x18,
++0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23,
++0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58,
++0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 0x01, 0x30, 0x04, 0x28,
++0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 0x09, 0x0b, 0x07, 0x48,
++0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 0x02, 0xd0, 0x38, 0x1c,
++0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0xa8, 0x03, 0x00, 0x80,
++0x00, 0x40, 0x14, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x98, 0xb4, 0x14, 0x4a,
++0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 0xc0, 0x58, 0x07, 0x03,
++0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 0x12, 0x0b, 0x11, 0x48,
++0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 0xe4, 0x58, 0x01, 0x23,
++0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 0xcc, 0x00, 0x01, 0x21,
++0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 0x98, 0x42, 0x03, 0xd9,
++0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 0x18, 0x1a, 0x84, 0x42,
++0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 0x55, 0x55, 0x55, 0x55,
++0x20, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x08, 0x04, 0x00, 0x80,
++0x18, 0x04, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 0x00, 0xd0, 0x01, 0x3a,
++0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 0xc0, 0x46, 0x3b, 0x60,
++0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 0x08, 0x32, 0x10, 0x4b,
++0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 0x12, 0x58, 0x0f, 0x4b,
++0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x1b, 0x68, 0x9b, 0x00,
++0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 0x0a, 0x48, 0xc1, 0x68,
++0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x08, 0x4b,
++0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 0x00, 0x20, 0xf6, 0xe7,
++0x08, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x80,
++0x18, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x10, 0x04, 0x00, 0x80,
++0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 0x01, 0xb6, 0xa0, 0xe3,
++0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 0x01, 0x7a, 0xa0, 0xe3,
++0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 0xc8, 0x60, 0x9f, 0xe5,
++0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 0x00, 0x00, 0x54, 0xe3,
++0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 0x11, 0x00, 0x00, 0x0a,
++0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x21, 0x00, 0x00, 0x0a,
++0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
++0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
++0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 0x02, 0x0a, 0x14, 0xe3,
++0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x02, 0x0a, 0xc0, 0xe3,
++0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x80, 0x85, 0xe5,
++0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
++0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
++0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x00, 0x1b,
++0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 0x02, 0x0b, 0x14, 0xe3,
++0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 0x20, 0x00, 0x00, 0x1b,
++0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x18, 0x00, 0x89, 0xe5,
++0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3,
++0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
++0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8,
++0x04, 0xf0, 0x5e, 0xe2, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
++0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 0x00, 0x20, 0xc3, 0xe1,
++0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x0c, 0x20, 0x81, 0xe5,
++0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0x18, 0x10, 0x9f, 0xe5,
++0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 0xb0, 0x24, 0xc1, 0xe1,
++0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 0x3c, 0x00, 0x81, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 0xff, 0xff, 0xff, 0xea,
++0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 0x01, 0x16, 0xa0, 0xe3,
++0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 0x24, 0x20, 0x91, 0xe5,
++0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20, 0x80, 0xe5,
++0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x80, 0xe5,
++0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 0x2c, 0x20, 0x80, 0xe5,
++0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11,
++0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x10, 0x81, 0xe2,
++0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 0x0b, 0x02, 0xa0, 0xe3,
++0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x04, 0x00, 0x80,
++0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5,
++0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2,
++0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1,
++0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3,
++0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5,
++0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0x00,
++0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
++0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2,
++0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0c, 0x10, 0xa0, 0xe3,
++0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5,
++0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5,
++0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3,
++0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x4c, 0x00, 0x1f, 0xe5,
++0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea,
++0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 0x01, 0x06, 0xa0, 0xe3,
++0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x21, 0x1f, 0xe5,
++0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0xe5,
++0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 0x01, 0x06, 0xa0, 0xe3,
++0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x92, 0xe5,
++0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1,
++0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x82, 0xe5,
++0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 0x0c, 0x00, 0x81, 0xe5,
++0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x81, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0,
++0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c,
++0x00, 0xf0, 0x92, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x00, 0x28,
++0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x84, 0xf8, 0x00, 0x20, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 0x3a, 0x78, 0xd2, 0x07,
++0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 0xff, 0x22, 0x01, 0x32,
++0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02,
++0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 0x5b, 0x02, 0x42, 0x68,
++0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 0x82, 0x60, 0x00, 0xe0,
++0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x08, 0x2a,
++0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
++0x0e, 0x31, 0x3c, 0xe0, 0xc1, 0x23, 0xdb, 0x00, 0x9a, 0x42, 0x03, 0xd1,
++0x41, 0x68, 0x24, 0x4b, 0x19, 0x43, 0x3e, 0xe0, 0x23, 0x4b, 0x9a, 0x42,
++0x04, 0xd1, 0x01, 0x23, 0x1b, 0x03, 0x41, 0x68, 0x19, 0x43, 0x36, 0xe0,
++0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
++0x12, 0x0c, 0x2e, 0x3a, 0x1c, 0x4b, 0x9a, 0x42, 0x2d, 0xd8, 0x01, 0x25,
++0x42, 0x68, 0x15, 0x43, 0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02,
++0x1a, 0x43, 0x18, 0x4b, 0x9a, 0x42, 0x22, 0xd1, 0xfb, 0x1d, 0x09, 0x33,
++0x44, 0xcb, 0x9b, 0x07, 0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33,
++0x9e, 0x40, 0x16, 0x43, 0x03, 0x2e, 0x18, 0xd1, 0x39, 0x7d, 0x7b, 0x7d,
++0x1b, 0x02, 0x19, 0x43, 0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43,
++0x41, 0x60, 0x81, 0x68, 0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x0a, 0xe0,
++0xc1, 0x23, 0xdb, 0x00, 0x99, 0x42, 0x04, 0xd1, 0x01, 0x21, 0x89, 0x03,
++0x29, 0x43, 0x41, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x00, 0x21, 0x08, 0x1c,
++0xf0, 0xbc, 0x70, 0x47, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x00, 0x00,
++0xae, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68,
++0xd1, 0x08, 0x3f, 0xd3, 0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39,
++0x8f, 0x78, 0x3f, 0x07, 0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d,
++0x0d, 0x32, 0xc2, 0x60, 0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60,
++0x08, 0x23, 0x1a, 0x43, 0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f,
++0x92, 0x00, 0x02, 0x61, 0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43,
++0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
++0x12, 0x0c, 0x42, 0x61, 0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23,
++0x42, 0x68, 0x1a, 0x43, 0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23,
++0x42, 0x68, 0x1a, 0x43, 0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23,
++0x42, 0x68, 0x1a, 0x43, 0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23,
++0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76,
++0x80, 0xbc, 0x70, 0x47, 0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78,
++0x1b, 0x02, 0x1a, 0x43, 0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43,
++0x02, 0x60, 0xc9, 0x78, 0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47,
++0x80, 0xb5, 0x07, 0x1c, 0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a,
++0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43,
++0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42,
++0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46,
++0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xda, 0xf8, 0x38, 0x1c, 0x01, 0xf0,
++0x95, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49,
++0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18,
++0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7,
++0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80,
++0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x01, 0x23, 0x9b, 0x07,
++0x01, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02,
++0x12, 0x0e, 0x12, 0x06, 0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40,
++0x10, 0x43, 0x0a, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02,
++0x1b, 0x0a, 0x19, 0x40, 0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07,
++0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04,
++0x1a, 0x40, 0x11, 0x43, 0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43,
++0x00, 0x0e, 0x08, 0x43, 0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23,
++0x81, 0x6b, 0x19, 0x40, 0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d,
++0x39, 0x37, 0x39, 0x7b, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1,
++0x01, 0x6b, 0xc0, 0x46, 0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d,
++0x2d, 0x35, 0x00, 0x22, 0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50,
++0x01, 0x32, 0x07, 0x2a, 0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63,
++0x82, 0x6a, 0xc0, 0x46, 0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33,
++0x5a, 0x83, 0x40, 0x6a, 0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27,
++0x42, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1,
++0x42, 0x69, 0x00, 0x2a, 0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a,
++0x02, 0x29, 0x02, 0xd3, 0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0,
++0x13, 0xf8, 0x09, 0xe0, 0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61,
++0xc1, 0x60, 0x03, 0xe0, 0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61,
++0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7,
++0x6c, 0x06, 0x00, 0x80, 0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68,
++0x00, 0x2b, 0x34, 0xd0, 0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68,
++0x9b, 0x6a, 0xc0, 0x46, 0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19,
++0x7f, 0x02, 0x17, 0x4b, 0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63,
++0x07, 0x63, 0xcb, 0x1d, 0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69,
++0x00, 0x2b, 0x01, 0xd0, 0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61,
++0x0f, 0x1c, 0xc9, 0x68, 0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63,
++0xf8, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60,
++0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30,
++0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
++0xac, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31,
++0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32,
++0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18,
++0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a,
++0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38,
++0x92, 0x04, 0x92, 0x0c, 0x00, 0x26, 0x25, 0x4d,
++0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 0x04, 0xd0, 0x20, 0x8a,
++0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 0x01, 0x23, 0x9b, 0x07,
++0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30,
++0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c,
++0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c,
++0x02, 0xf0, 0x02, 0xf8, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23,
++0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
++0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8,
++0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43,
++0x20, 0x82, 0x21, 0x8a, 0x38, 0x1c, 0x00, 0xf0, 0xa2, 0xfb, 0xe8, 0x68,
++0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
++0xe8, 0x60, 0x30, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20,
++0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c,
++0xfc, 0x1d, 0xf9, 0x34, 0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35,
++0x38, 0x48, 0xc0, 0x6a, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18,
++0x01, 0x20, 0x80, 0x07, 0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
++0x00, 0x90, 0x01, 0x23, 0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43,
++0x00, 0x68, 0x38, 0x1c, 0x29, 0x1c, 0x00, 0xf0, 0xc2, 0xfa, 0xa8, 0x88,
++0x41, 0x07, 0x01, 0xd0, 0x00, 0x20, 0x51, 0xe0, 0x29, 0x89, 0x09, 0x18,
++0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18,
++0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a,
++0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0,
++0x33, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69,
++0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58,
++0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28,
++0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31,
++0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28,
++0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xae, 0xfb,
++0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b,
++0xff, 0xf7, 0xa6, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43,
++0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0x9e, 0xfb, 0xa1, 0x6b, 0x08, 0x4a,
++0x01, 0x20, 0xff, 0xf7, 0x99, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46,
++0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x4c, 0x2a, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00,
++0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a,
++0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49,
++0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48,
++0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00,
++0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d,
++0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68,
++0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a,
++0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b,
++0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69,
++0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x26, 0xf9, 0x28, 0x6b, 0x79, 0x69,
++0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b,
++0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50,
++0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00,
++0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
++0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90,
++0x90, 0x49, 0x42, 0x00, 0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0,
++0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28,
++0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a,
++0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0,
++0x67, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98,
++0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28,
++0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a,
++0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60,
++0x62, 0xe0, 0x0a, 0x98, 0x02, 0x28, 0x5f, 0xd1, 0x09, 0x98, 0x40, 0x0c,
++0x73, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43,
++0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18,
++0x0c, 0x38, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x8a, 0x00, 0x6b, 0x4b,
++0xd6, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
++0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x00, 0x21, 0x83, 0x1e,
++0x0c, 0x93, 0x68, 0x4a, 0x16, 0x6b, 0xc0, 0x46, 0x0b, 0x96, 0x8a, 0x00,
++0x0c, 0x9b, 0x9b, 0x18, 0x0b, 0x9e, 0x9e, 0x19, 0x01, 0x23, 0x9b, 0x07,
++0x33, 0x43, 0x1b, 0x68, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x04, 0x29,
++0xf1, 0xd3, 0x69, 0x46, 0x8b, 0x1c, 0x07, 0x93, 0x00, 0x21, 0x08, 0x91,
++0x04, 0xae, 0x4a, 0x00, 0x07, 0x9b, 0x9b, 0x5a, 0xb2, 0x5a, 0x93, 0x42,
++0x11, 0xd0, 0x58, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xf8, 0x68,
++0x41, 0x1c, 0xf9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x20, 0x23,
++0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x80, 0x23, 0x18, 0x43, 0x38, 0x82,
++0x8f, 0xe7, 0x01, 0x31, 0x06, 0x29, 0xe4, 0xd3, 0x08, 0x99, 0x00, 0x29,
++0x0d, 0xd1, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0x04, 0xd1,
++0x39, 0x8a, 0x02, 0x23, 0x19, 0x43, 0x03, 0xe0, 0x0c, 0xe0, 0x39, 0x8a,
++0x08, 0x23, 0x19, 0x43, 0x39, 0x82, 0x29, 0x6b, 0x08, 0x18, 0x01, 0x23,
++0x9b, 0x07, 0x01, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x20, 0x76,
++0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x11, 0x30, 0x18, 0x43, 0x00, 0x68,
++0x01, 0x06, 0x09, 0x0e, 0x00, 0xe0, 0x19, 0xe0, 0x35, 0x48, 0x2a, 0x6b,
++0xc0, 0x46, 0xea, 0x62, 0x04, 0x29, 0x4f, 0xd1, 0x01, 0x21, 0xc6, 0x1d,
++0xff, 0x36, 0x5a, 0x36, 0x31, 0x72, 0x0a, 0x99, 0x02, 0x29, 0x1e, 0xd1,
++0x09, 0x99, 0x09, 0x0e, 0x49, 0x06, 0x1a, 0xd1, 0xe1, 0x1d, 0x05, 0x31,
++0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x39, 0x1a, 0xe0,
++0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68,
++0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04,
++0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1,
++0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d,
++0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60,
++0xe8, 0x6a, 0xc0, 0x46, 0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x88, 0xfc,
++0x20, 0x7e, 0x33, 0x28, 0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21,
++0x14, 0x4c, 0xc0, 0x46, 0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0,
++0x85, 0xf8, 0x28, 0x6b, 0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c,
++0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20,
++0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1,
++0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd,
++0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x70, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00,
++0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80,
++0xac, 0xab, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80,
++0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48,
++0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31,
++0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22,
++0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46,
++0x9a, 0x61, 0xfa, 0x1d, 0xff, 0x32, 0x5a, 0x32, 0x13, 0x7a, 0x1b, 0x4a,
++0x00, 0x2b, 0x0b, 0xd0, 0x15, 0x8a, 0x2e, 0x0a, 0x36, 0x02, 0x33, 0x23,
++0x2b, 0x40, 0x9b, 0x00, 0x1e, 0x43, 0xcc, 0x23, 0x2b, 0x40, 0x9b, 0x08,
++0x33, 0x43, 0x13, 0x82, 0x12, 0x8a, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x83,
++0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46,
++0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46,
++0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a,
++0x01, 0xf0, 0x32, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30,
++0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
++0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a,
++0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68,
++0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31,
++0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0,
++0x0f, 0xf8, 0x06, 0xe0, 0x32, 0x2b, 0x08, 0xd1, 0x8b, 0x70, 0x01, 0x1c,
++0x10, 0x1c, 0x00, 0xf0, 0x3c, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x20, 0x88, 0x70, 0xf9, 0xe7, 0x90, 0xb4, 0xca, 0x1d,
++0xf9, 0x32, 0x33, 0x27, 0xcc, 0x1d, 0xff, 0x34, 0x4a, 0x34, 0xd3, 0x6a,
++0xc0, 0x46, 0xa7, 0x70, 0xff, 0x31, 0x41, 0x31, 0x07, 0x6c, 0xc0, 0x46,
++0x4f, 0x61, 0xfb, 0x18, 0x39, 0x1c, 0x9f, 0x1e, 0x01, 0x23, 0x9b, 0x07,
++0xfc, 0x1c, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x9b, 0x00,
++0x1b, 0x04, 0x1b, 0x0c, 0xc9, 0x18, 0x08, 0x31, 0x01, 0x64, 0x01, 0x23,
++0x9b, 0x07, 0xb9, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x34, 0x30, 0x01, 0x76,
++0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d,
++0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43,
++0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32,
++0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d,
++0xff, 0x37, 0x4a, 0x37, 0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d,
++0xff, 0x34, 0x3a, 0x34, 0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30,
++0xe8, 0x60, 0x60, 0x69, 0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07,
++0x38, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43,
++0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63,
++0xf8, 0x1d, 0x03, 0x30, 0xff, 0xf7, 0xfc, 0xfb, 0x20, 0x62, 0xf8, 0x1d,
++0x07, 0x30, 0xff, 0xf7, 0xf7, 0xfb, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76,
++0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98,
++0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
++0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40,
++0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c,
++0x80, 0x23, 0x23, 0x40, 0x01, 0x9f, 0xff, 0x37, 0x41, 0x37, 0x00, 0x2b,
++0x3c, 0xd0, 0x0c, 0x23, 0x00, 0x93, 0x00, 0x23, 0x9d, 0x00, 0xae, 0x18,
++0x36, 0x69, 0x6d, 0x18, 0x6e, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3,
++0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 0x76, 0x6a, 0x6d, 0x18, 0xae, 0x62,
++0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x01, 0x9b, 0xff, 0x33, 0x51, 0x33,
++0x9b, 0x78, 0x33, 0x2b, 0x0e, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
++0x01, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23,
++0x9b, 0x07, 0xc5, 0x1d, 0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x16, 0xe0,
++0x7b, 0x69, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
++0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x7d, 0x69, 0x5d, 0x1b, 0x01, 0x23,
++0x9b, 0x07, 0xc6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0xeb, 0x18,
++0x0c, 0x3b, 0x02, 0xe0, 0x00, 0x23, 0x00, 0x93, 0x4b, 0x81, 0xcb, 0x80,
++0x63, 0x09, 0x49, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xc4, 0x1d, 0x05, 0x34,
++0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x81, 0x01, 0x23, 0x9b, 0x07,
++0xc4, 0x1d, 0x0d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0x0c, 0x89, 0x1b, 0x1b,
++0x00, 0x9c, 0x1c, 0x1b, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43,
++0x00, 0x68, 0x20, 0x18, 0x88, 0x80, 0x38, 0x6a, 0x04, 0x0e, 0xff, 0x23,
++0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 0x1c, 0x43, 0xff, 0x23, 0x1b, 0x02,
++0x03, 0x40, 0x1b, 0x02, 0x23, 0x43, 0x00, 0x06, 0x18, 0x43, 0xc8, 0x60,
++0x78, 0x6a, 0x07, 0x0e, 0xff, 0x23, 0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a,
++0x1f, 0x43, 0xff, 0x23, 0x1b, 0x02, 0x03, 0x40, 0x1b, 0x02, 0x3b, 0x43,
++0x00, 0x06, 0x18, 0x43, 0x08, 0x61, 0xd0, 0x6b, 0xc0, 0x46, 0xc8, 0x63,
++0x90, 0x6b, 0xc0, 0x46, 0x08, 0x64, 0x50, 0x6c, 0xc0, 0x46, 0x48, 0x64,
++0x10, 0x6c, 0xc0, 0x46, 0x88, 0x64, 0xd0, 0x6c, 0xc0, 0x46, 0xc8, 0x64,
++0x90, 0x6c, 0xc0, 0x46, 0x08, 0x65, 0x02, 0xe0, 0x00, 0x23, 0x0b, 0x81,
++0x8b, 0x80, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
++0x0f, 0x4a, 0x93, 0x89, 0x01, 0x33, 0x93, 0x81, 0xc2, 0x1d, 0xf9, 0x32,
++0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61,
++0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b,
++0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83,
++0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xc2, 0xf8,
++0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
++0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20,
++0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30,
++0x00, 0x29, 0x15, 0xd0, 0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25,
++0x0a, 0xe0, 0xff, 0xf7, 0x89, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a,
++0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0,
++0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69,
++0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0xa8, 0xfc,
++0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x5a, 0xf8,
++0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80,
++0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x01, 0x24,
++0x00, 0x25, 0x00, 0x28, 0x0b, 0xd1, 0x38, 0x6a, 0x00, 0x28, 0x03, 0xd1,
++0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1f, 0x48, 0x01, 0x6e,
++0x01, 0x31, 0x01, 0x66, 0x03, 0xe0, 0x48, 0x68, 0xc4, 0x23, 0x18, 0x40,
++0x03, 0xd1, 0x38, 0x6a, 0x00, 0xf0, 0x0c, 0xfc, 0x2f, 0xe0, 0x38, 0x1c,
++0x00, 0xf0, 0x1c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7b, 0xfa, 0xb8, 0x68,
++0xc0, 0x08, 0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd1, 0xfb, 0xb8, 0x68,
++0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60,
++0x10, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29,
++0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46,
++0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x14, 0xf8, 0x0b, 0xe0, 0x39, 0x6a,
++0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68,
++0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c,
++0xbd, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
++0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c,
++0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68,
++0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xc3, 0xfb, 0x00, 0x20,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00,
++0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36,
++0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 0x33, 0x4c, 0x34, 0x4b,
++0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x00, 0xf0,
++0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18,
++0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
++0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d,
++0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d,
++0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30,
++0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20,
++0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3,
++0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 0x09, 0x18, 0x78, 0x68,
++0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 0x61, 0x89, 0xe2, 0x88,
++0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x5a, 0xff,
++0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43,
++0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x52, 0xff, 0x01, 0x22, 0x52, 0x04,
++0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x4a, 0xff,
++0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 0x45, 0xff, 0x01, 0x20,
++0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 0xea, 0x1d, 0xf9, 0x32,
++0x51, 0x62, 0xd9, 0xe7, 0x28, 0xac, 0x20, 0x40, 0xff, 0xff, 0x00, 0x00,
++0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00,
++0x14, 0xac, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0,
++0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21,
++0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31,
++0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 0x00, 0x68, 0x03, 0xf0,
++0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34,
++0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 0x44, 0x4a, 0x92, 0x6a,
++0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xea, 0x1d,
++0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68,
++0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 0x3c, 0x4d, 0x01, 0x2b,
++0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68,
++0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 0xc5, 0xfc, 0x20, 0x78,
++0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20,
++0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30,
++0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20,
++0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 0x01, 0x30, 0x06, 0x28,
++0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 0x11, 0x0a, 0x29, 0xd3,
++0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50,
++0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19,
++0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00,
++0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 0x06, 0x29, 0xf8, 0xd3,
++0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 0x00, 0x9d, 0x55, 0x40,
++0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 0x89, 0x6a, 0x08, 0x18,
++0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 0x51, 0x40, 0x41, 0x65,
++0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 0x38, 0x1c,
++0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x08, 0x4a, 0x50, 0x68,
++0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xa4, 0xfa,
++0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 0x01, 0xf0, 0xde, 0xfa,
++0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x6c, 0x06, 0x00, 0x80,
++0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
++0xac, 0xab, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
++0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43,
++0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07,
++0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 0x43, 0x68, 0x1c, 0x04,
++0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 0x33, 0x43, 0x1b, 0x68,
++0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 0xff, 0x26, 0x36, 0x02,
++0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c,
++0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79,
++0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89,
++0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18,
++0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
++0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3,
++0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36,
++0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18,
++0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23,
++0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c,
++0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33,
++0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b,
++0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43,
++0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
++0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x64, 0xab, 0x0e,
++0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x3d, 0x34, 0x23, 0x43,
++0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
++0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x64, 0x01, 0x23,
++0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46,
++0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x41, 0x34, 0x23, 0x43,
++0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 0x0f, 0xe0, 0xfb, 0x1f,
++0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 0xff, 0x18, 0x03, 0x69,
++0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 0x2c, 0xe0, 0x00, 0x23,
++0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 0x8b, 0x80, 0x0b, 0x81,
++0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00,
++0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 0x00, 0x20, 0x87, 0x00,
++0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43,
++0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3,
++0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23,
++0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30,
++0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2,
++0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46,
++0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68,
++0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69,
++0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc,
++0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60,
++0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 0x01, 0x61, 0xf2, 0xe7,
++0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98,
++0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27,
++0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 0x00, 0x2b, 0x19, 0xd0,
++0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18,
++0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04,
++0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0,
++0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23,
++0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b,
++0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43,
++0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68,
++0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0,
++0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0,
++0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89,
++0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68,
++0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c,
++0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46,
++0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87,
++0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b,
++0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c,
++0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 0x07, 0x9b, 0x5b, 0x89,
++0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 0x07, 0x9b, 0x9b, 0x89,
++0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00,
++0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a,
++0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 0xc0, 0x46, 0xab, 0x83,
++0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23,
++0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07,
++0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31,
++0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42,
++0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x05, 0x9b,
++0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b,
++0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33,
++0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 0xbb, 0x08, 0x9b, 0x07,
++0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b,
++0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07,
++0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95,
++0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9d, 0xc0, 0x46,
++0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 0x1b, 0x02, 0x1d, 0x43,
++0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 0x2b, 0x43, 0x55, 0x00,
++0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b,
++0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e,
++0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f,
++0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40,
++0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c,
++0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78,
++0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3,
++0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00,
++0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33,
++0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93,
++0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35,
++0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68,
++0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0,
++0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1,
++0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46,
++0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b,
++0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46,
++0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61,
++0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83,
++0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
++0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68,
++0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68,
++0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48,
++0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0,
++0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98,
++0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xe1, 0xff, 0x68, 0x46,
++0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0,
++0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43,
++0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x84, 0xfe,
++0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
++0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46,
++0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68,
++0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68,
++0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69,
++0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28,
++0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7,
++0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60,
++0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22,
++0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 0x03, 0x23, 0xfc, 0x1d,
++0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68,
++0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68,
++0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62,
++0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60,
++0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64,
++0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
++0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
++0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23,
++0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0x20, 0x6b, 0x01, 0x30,
++0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69,
++0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29,
++0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68,
++0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c,
++0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe,
++0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29,
++0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0,
++0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46,
++0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31,
++0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1,
++0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 0x00, 0x28, 0x03, 0xd0,
++0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 0x30, 0x7b, 0x00, 0x28,
++0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 0x1b, 0x23, 0xdb, 0x01,
++0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 0xe0, 0x6a, 0xb0, 0x42,
++0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3,
++0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30,
++0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x90, 0xff,
++0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60,
++0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xe0, 0x6b,
++0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0x07, 0xfc, 0x02, 0x23,
++0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60,
++0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0x64, 0x2d, 0x00, 0x80,
++0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x1d, 0x48,
++0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 0x09, 0x31, 0x01, 0x27,
++0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 0xa3, 0x42, 0x10, 0xd0,
++0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 0x00, 0x2b, 0x0a, 0xd0,
++0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 0x13, 0x4b, 0xc0, 0x46,
++0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 0x93, 0x82, 0xc3, 0x8b,
++0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 0x0e, 0xdb, 0x84, 0x8a,
++0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 0x44, 0x8a, 0xc5, 0x8a,
++0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 0x4f, 0x70, 0x43, 0x82,
++0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 0x51, 0x82, 0x80, 0x8a,
++0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 0xe8, 0x0e, 0x00, 0x80,
++0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0,
++0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20,
++0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06,
++0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00,
++0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00,
++0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28,
++0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46,
++0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3,
++0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73,
++0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c,
++0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06,
++0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9,
++0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0,
++0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22,
++0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9,
++0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18,
++0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d,
++0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 0x08, 0xd0, 0x8b, 0x00,
++0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e,
++0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0,
++0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 0x01, 0x30, 0x00, 0x06,
++0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4,
++0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a,
++0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70,
++0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72,
++0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a,
++0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47,
++0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48,
++0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61,
++0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c,
++0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18,
++0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 0x61, 0xfe, 0x08, 0xbc,
++0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40,
++0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x95, 0x4a, 0xd0, 0x68,
++0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 0x38, 0x89, 0x00, 0x28,
++0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60,
++0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 0x8e, 0x48, 0xc3, 0x6b,
++0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xd4, 0x18,
++0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 0x81, 0x42, 0x05, 0xd1,
++0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf3, 0xe0,
++0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 0x01, 0x20, 0x00, 0x21,
++0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 0x58, 0x70, 0xb9, 0x82,
++0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x05, 0x93, 0x5b, 0x69,
++0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 0xc0, 0x46, 0x39, 0x61,
++0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c,
++0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 0x05, 0xd1, 0x3b, 0x2a,
++0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x73,
++0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68,
++0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x09, 0x04,
++0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 0x09, 0x06, 0x09, 0x0e,
++0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46,
++0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32,
++0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 0xb3, 0x07, 0x1a, 0x43,
++0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20,
++0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b,
++0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 0x01, 0x20, 0x09, 0x01,
++0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 0x65, 0xd1, 0x51, 0x49,
++0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 0x48, 0x69, 0x01, 0x30,
++0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
++0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 0x22, 0x6a, 0xa3, 0x6b,
++0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 0x22, 0x6b, 0xc0, 0x46,
++0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 0x00, 0x22, 0xfa, 0x61,
++0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 0x01, 0x22, 0x00, 0xe0,
++0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 0x7a, 0x68, 0xc0, 0x46,
++0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0xb0, 0x83,
++0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 0x60, 0x20, 0xb0, 0x83,
++0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 0x9a, 0x42, 0x03, 0xd8,
++0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 0x21, 0x6b, 0xc0, 0x46,
++0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 0x2d, 0x49, 0x78, 0x6b,
++0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 0xc0, 0x46, 0xfa, 0x60,
++0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 0xc0, 0x46, 0xb8, 0x61,
++0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 0x37, 0xf9, 0x04, 0x98,
++0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 0x78, 0x8a, 0xf1, 0x8b,
++0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 0x04, 0xe0, 0x38, 0xe0,
++0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 0x81, 0x07, 0x02, 0xd0,
++0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 0x09, 0x1a, 0xa2, 0x6b,
++0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 0x20, 0x62, 0xe8, 0x7b,
++0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 0x05, 0x99, 0x48, 0x69,
++0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 0x73, 0xfa, 0x18, 0x48,
++0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 0x0a, 0xd1, 0x20, 0x6a,
++0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 0x88, 0x42, 0x03, 0xd0,
++0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x40, 0x04,
++0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 0xe0, 0x68, 0x00, 0x28,
++0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 0xa8, 0x73, 0xed, 0xe7,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xa4, 0x2a, 0x00, 0x80,
++0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55,
++0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 0xc4, 0x0b, 0x00, 0x00,
++0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89,
++0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c,
++0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2,
++0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31,
++0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b,
++0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0xb3, 0xf8, 0x01, 0x20,
++0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x18, 0x1a, 0x00, 0x80,
++0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c,
++0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89,
++0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7,
++0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 0x00, 0x09, 0x1f, 0xd3,
++0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a,
++0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
++0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
++0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0,
++0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 0x46, 0xe0, 0x01, 0x30,
++0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 0x5c, 0x18, 0xe4, 0x88,
++0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
++0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 0xd8, 0x42, 0xf0, 0xdc,
++0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 0x0b, 0x23, 0x1b, 0x02,
++0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x98,
++0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 0x9b, 0x01,
++0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 0x17, 0xd0, 0xfe, 0x1d,
++0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18,
++0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7b, 0xfc, 0x01, 0x28,
++0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 0x9b, 0x01,
++0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 0x01, 0x2a,
++0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0xf8, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
++0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
++0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89,
++0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08,
++0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 0x38, 0x1c, 0x00, 0xf0,
++0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c,
++0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47,
++0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04,
++0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29,
++0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43,
++0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c,
++0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0,
++0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68,
++0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91,
++0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab,
++0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43,
++0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69,
++0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b,
++0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a,
++0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26,
++0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0,
++0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0,
++0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42,
++0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43,
++0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43,
++0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43,
++0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a,
++0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68,
++0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43,
++0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43,
++0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43,
++0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68,
++0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c,
++0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c,
++0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c,
++0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 0x91, 0x42, 0x00, 0xdd,
++0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d,
++0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 0x33, 0x4a, 0xc0, 0x46,
++0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 0xe1, 0x6d, 0x41, 0x18,
++0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0,
++0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 0xb1, 0x6a, 0x81, 0x42,
++0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 0x2f, 0x23, 0x9b, 0x01,
++0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 0x92, 0x00, 0x27, 0x4b,
++0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 0x4a, 0x08, 0x05, 0xd3,
++0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd6, 0xff,
++0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x0b, 0x78, 0x00, 0x2b,
++0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 0x1e, 0x4a, 0xc0, 0x46,
++0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce,
++0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 0xc7, 0xfe, 0x14, 0x48,
++0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 0x00, 0xd3, 0x25, 0x60,
++0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 0x3a, 0x6b, 0xc0, 0x46,
++0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x68, 0x00, 0x29,
++0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0x04, 0xe0, 0x39, 0x6b,
++0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0xc1, 0x60,
++0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00,
++0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
++0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02,
++0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35,
++0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 0x01, 0x38, 0x78, 0x61,
++0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0xb8, 0x60,
++0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa,
++0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71,
++0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1b, 0x00, 0x80,
++0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40,
++0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47,
++0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08,
++0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30,
++0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x23,
++0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 0x00, 0x68, 0x16, 0x4c,
++0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68,
++0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 0x00, 0xf0, 0x22, 0xf8,
++0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21,
++0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 0xf2, 0xd0, 0x51, 0x21,
++0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 0x02, 0xd1, 0x60, 0x6b,
++0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xf7, 0xe7,
++0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 0x01, 0x23, 0x9b, 0x07,
++0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c,
++0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00,
++0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 0x4b, 0x6b, 0x9a, 0x42,
++0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
++0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0,
++0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
++0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49,
++0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20,
++0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68,
++0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 0xdf, 0xfd, 0x88, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 0xf5, 0x2c, 0xff, 0xff,
++0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
++0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60,
++0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x4c, 0xfc,
++0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0,
++0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18,
++0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23,
++0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48,
++0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 0x35, 0x4d, 0x10, 0x29,
++0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e,
++0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x68, 0x6a,
++0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2,
++0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 0x68, 0x6a, 0xb8, 0x42,
++0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b,
++0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49,
++0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c,
++0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 0x09, 0x6e, 0x8c, 0x18,
++0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b,
++0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18,
++0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31,
++0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 0x52, 0x05, 0x3a, 0x43,
++0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18,
++0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 0x02, 0xf0, 0x4a, 0xfd,
++0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 0xe9, 0x6a, 0x2a, 0x6b,
++0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66,
++0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 0x68, 0x0e, 0x00, 0x80,
++0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x5d, 0x2e, 0xff, 0xff,
++0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40,
++0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 0xd1, 0x60, 0x02, 0x23,
++0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0x90, 0xee, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x01, 0x20, 0x80, 0x02,
++0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23,
++0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c,
++0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 0x68, 0x46, 0x00, 0xf0,
++0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30,
++0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73,
++0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0,
++0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23,
++0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21,
++0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
++0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40,
++0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f,
++0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b,
++0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18,
++0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 0x04, 0x68, 0xc0, 0x46,
++0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46,
++0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0x08, 0x69,
++0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 0x38, 0x6a, 0xc0, 0x46,
++0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 0x18, 0x1c, 0x90, 0xbc,
++0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 0xc8, 0x69, 0x19, 0x23,
++0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b,
++0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 0xca, 0x61, 0x70, 0x47,
++0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 0x40, 0x32, 0x00, 0x29,
++0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0xd0, 0x61,
++0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68,
++0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69,
++0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00,
++0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21,
++0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a,
++0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23,
++0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07,
++0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0,
++0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 0x04, 0x29, 0xe4, 0xd3,
++0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0,
++0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a,
++0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40,
++0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 0xa3, 0x40, 0x00, 0x25,
++0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 0x5d, 0xd9, 0x1c, 0x1c,
++0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96,
++0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92,
++0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 0x05, 0x9c, 0xe3, 0x40,
++0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c,
++0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23,
++0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
++0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d,
++0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96,
++0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68,
++0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36,
++0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23,
++0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b,
++0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14,
++0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0,
++0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a,
++0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
++0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28,
++0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x2b, 0xf8, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f,
++0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3,
++0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0xde, 0xfe,
++0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20,
++0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28,
++0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60,
++0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28,
++0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28,
++0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7,
++0xb9, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3,
++0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79,
++0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
++0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x8c, 0x06, 0x00, 0x80,
++0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
++0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46,
++0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
++0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a,
++0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65,
++0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18,
++0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18,
++0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d,
++0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xfc, 0xf7, 0xca, 0xff,
++0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
++0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 0x01, 0xf0, 0xc6, 0xfb,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
++0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20,
++0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x59, 0xfc, 0x07, 0x1c,
++0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01,
++0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46,
++0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d,
++0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 0x89, 0xf9, 0x38, 0x1c,
++0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80,
++0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68,
++0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59,
++0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42,
++0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c,
++0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31,
++0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 0x5d, 0xfc, 0xf8, 0x6d,
++0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02,
++0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73,
++0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x4c, 0xfc, 0xb8, 0x6d, 0xc0, 0x46,
++0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2,
++0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xcc, 0xfc,
++0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0,
++0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64,
++0x20, 0x1c, 0xfc, 0xf7, 0x31, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43,
++0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c,
++0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07,
++0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68,
++0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31,
++0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19,
++0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18,
++0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42,
++0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a,
++0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
++0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
++0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0,
++0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62,
++0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c,
++0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0,
++0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18,
++0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9,
++0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
++0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 0x82, 0x42, 0xf3, 0xd8,
++0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40,
++0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68,
++0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x78, 0x6c,
++0xfc, 0xf7, 0x95, 0xff, 0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c,
++0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04,
++0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
++0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
++0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c,
++0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68,
++0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0,
++0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7,
++0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69,
++0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40,
++0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68,
++0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c,
++0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c,
++0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c,
++0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 0x7d, 0x4e, 0x0b, 0x23,
++0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25,
++0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 0x00, 0x28, 0x12, 0xd0,
++0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x68,
++0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 0x01, 0x35, 0xa8, 0x00,
++0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x68, 0x00, 0x28,
++0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68,
++0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c,
++0x28, 0x1c, 0xfc, 0xf7, 0x10, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e,
++0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18,
++0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88,
++0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04,
++0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
++0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
++0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89,
++0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61,
++0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46,
++0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60,
++0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 0xe8, 0xfe, 0x38, 0x86,
++0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 0x03, 0xff, 0x78, 0x86,
++0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 0xc8, 0xfe, 0x00, 0x90,
++0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04,
++0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02,
++0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42,
++0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02,
++0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c,
++0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xa3, 0xfe,
++0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 0x9e, 0xfe, 0x06, 0x1c,
++0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
++0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c,
++0xfc, 0xf7, 0x8f, 0xfe, 0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61,
++0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22,
++0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02,
++0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c,
++0xfc, 0xf7, 0x77, 0xfe, 0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61,
++0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69,
++0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7,
++0x66, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08,
++0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04,
++0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46,
++0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c,
++0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81,
++0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
++0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69,
++0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98,
++0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18,
++0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1,
++0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61,
++0x04, 0x98, 0xfc, 0xf7, 0x09, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69,
++0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42,
++0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a,
++0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62,
++0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1,
++0x38, 0x1c, 0xfc, 0xf7, 0x19, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60,
++0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68,
++0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c,
++0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68,
++0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c,
++0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98,
++0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e,
++0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
++0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
++0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x20, 0x8e,
++0xfc, 0xf7, 0xcb, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 0x02, 0x99, 0xfc, 0xf7,
++0xc6, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02,
++0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46,
++0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xb7, 0xfd, 0x61, 0x69, 0x01, 0x31,
++0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e,
++0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
++0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
++0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x71, 0x60, 0x03, 0x98,
++0xfc, 0xf7, 0x9b, 0xfd, 0x21, 0x69, 0x49, 0x19, 0x21, 0x61, 0xa1, 0x68,
++0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43,
++0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x8d, 0xfd, 0x38, 0x82, 0x61, 0x6e,
++0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99,
++0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d,
++0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38,
++0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68,
++0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04,
++0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46,
++0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
++0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04,
++0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x51, 0xfd, 0x40, 0xc7, 0x02, 0x9a,
++0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29,
++0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c,
++0x16, 0x1c, 0xfc, 0xf7, 0x40, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e,
++0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32,
++0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0,
++0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5,
++0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b,
++0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99,
++0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0,
++0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91,
++0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42,
++0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a,
++0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88,
++0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21,
++0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06,
++0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1,
++0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a,
++0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c,
++0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 0x07, 0x9b, 0x01, 0xf0,
++0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0,
++0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 0x01, 0x6d, 0x42, 0x6d,
++0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8,
++0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90,
++0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60,
++0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 0x01, 0x98, 0x01, 0x38,
++0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 0x44, 0x63, 0x01, 0x98,
++0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0,
++0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92,
++0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x09, 0x9b, 0x01, 0xf0,
++0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02,
++0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07,
++0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0x85, 0xfc,
++0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68,
++0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 0x8b, 0xf9, 0x38, 0x1c,
++0xfc, 0xf7, 0x8c, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3,
++0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80,
++0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71,
++0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60,
++0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 0x49, 0x08, 0x49, 0x00,
++0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 0x38, 0x1c, 0x00, 0xf0,
++0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43,
++0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8,
++0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c,
++0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0,
++0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68,
++0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68,
++0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42,
++0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 0x31, 0x1c, 0x01, 0x3e,
++0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
++0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60,
++0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68,
++0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47,
++0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68,
++0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46,
++0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80,
++0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46,
++0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80,
++0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
++0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
++0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b,
++0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7,
++0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7,
++0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb,
++0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xee, 0xe7,
++0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
++0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
++0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43,
++0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88,
++0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47,
++0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xf8, 0xe7, 0x00, 0x00,
++0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c,
++0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33,
++0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68,
++0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1,
++0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18,
++0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20,
++0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60,
++0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46,
++0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a,
++0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80,
++0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7,
++0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23,
++0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55,
++0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 0x7c, 0x29, 0x00, 0x80,
++0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
++0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40,
++0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18,
++0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08,
++0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c,
++0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d,
++0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65,
++0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68,
++0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60,
++0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20,
++0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c,
++0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80,
++0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x38, 0x1c, 0xfc, 0xf7, 0x07, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18,
++0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63,
++0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
++0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27,
++0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 0x42, 0x63, 0x00, 0x2a,
++0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 0xc0, 0x6a, 0x01, 0xf0,
++0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 0x38, 0x01, 0x00, 0x19,
++0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1,
++0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x90, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
++0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x0f, 0x49, 0xc8, 0x68,
++0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 0x02, 0x89, 0x00, 0x2a,
++0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 0x00, 0x2a, 0x0d, 0xd1,
++0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 0x02, 0x23, 0x0a, 0x68,
++0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 0x01, 0x21, 0x00, 0xe0,
++0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x01, 0x23, 0xf8, 0x1d,
++0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 0x79, 0x32, 0x54, 0x8a,
++0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 0xac, 0x42, 0x04, 0xdb,
++0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 0xd1, 0x83, 0x01, 0x23,
++0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61,
++0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46,
++0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0x61, 0x41, 0x69,
++0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 0x00, 0x05, 0xc1, 0x60,
++0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a,
++0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8,
++0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3,
++0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23,
++0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e,
++0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1,
++0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72,
++0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d,
++0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 0x00, 0x20, 0xf8, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49,
++0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31,
++0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x63,
++0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22,
++0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1,
++0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18,
++0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92,
++0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0,
++0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e,
++0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x73, 0xfc, 0x20, 0x6b,
++0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8,
++0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7,
++0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80,
++0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49,
++0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a,
++0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7,
++0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a,
++0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x2d, 0xff, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x64, 0x2d, 0x00, 0x80,
++0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49,
++0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48,
++0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31,
++0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x61, 0x6b,
++0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 0x78, 0x68, 0x80, 0x00,
++0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 0x01, 0x23, 0x78, 0x68,
++0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f,
++0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1,
++0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
++0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68,
++0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7,
++0x59, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31,
++0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49,
++0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0,
++0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0,
++0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09,
++0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62,
++0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0,
++0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a,
++0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19,
++0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a,
++0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62,
++0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62,
++0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1,
++0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42,
++0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19,
++0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0,
++0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38,
++0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
++0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90,
++0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0xc0, 0x6a, 0xc0, 0x46,
++0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46,
++0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60,
++0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46,
++0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a,
++0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46,
++0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3,
++0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20,
++0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0,
++0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30,
++0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61,
++0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d,
++0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 0x38, 0x1c, 0x5c, 0xe3,
++0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c,
++0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07,
++0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06,
++0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1,
++0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2,
++0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0,
++0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c,
++0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68,
++0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49,
++0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0,
++0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 0x7a, 0x68, 0xc0, 0x46,
++0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49,
++0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c,
++0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a,
++0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c,
++0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61,
++0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69,
++0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a,
++0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28,
++0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f,
++0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92,
++0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48,
++0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80,
++0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60,
++0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a,
++0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64,
++0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18,
++0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30,
++0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61,
++0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88,
++0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0,
++0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93,
++0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68,
++0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46,
++0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46,
++0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49,
++0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0,
++0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71,
++0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37,
++0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
++0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18,
++0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x7d, 0xfb, 0x01, 0x9a,
++0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65,
++0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20,
++0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8,
++0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07,
++0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99,
++0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c,
++0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c,
++0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 0x41, 0x49, 0x00, 0x20,
++0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b,
++0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
++0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a,
++0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b,
++0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98,
++0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90,
++0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
++0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20,
++0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90,
++0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42,
++0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90,
++0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98,
++0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42,
++0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20,
++0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1,
++0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0,
++0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb,
++0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29,
++0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a,
++0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90,
++0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98,
++0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 0x01, 0x49, 0xff, 0xff,
++0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80,
++0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 0x60, 0x04, 0x00, 0x80,
++0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x55, 0x32, 0xff, 0xff,
++0xac, 0x5e, 0x21, 0x40, 0x0d, 0x3d, 0xff, 0xff, 0xcd, 0x31, 0xff, 0xff,
++0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
++0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98,
++0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1,
++0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98,
++0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48,
++0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x51, 0xf9, 0x00, 0x20,
++0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b,
++0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c,
++0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a,
++0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80,
++0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98,
++0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9,
++0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09,
++0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a,
++0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a,
++0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a,
++0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2,
++0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92,
++0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
++0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40,
++0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22,
++0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d,
++0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x02, 0x90,
++0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06,
++0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a,
++0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d,
++0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37,
++0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa,
++0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46,
++0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99,
++0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0,
++0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23,
++0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07,
++0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b,
++0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0,
++0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98,
++0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92,
++0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
++0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28,
++0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20,
++0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92,
++0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20,
++0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42,
++0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98,
++0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90,
++0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04,
++0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0,
++0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e,
++0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b,
++0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x89, 0xf9, 0x01, 0x9a,
++0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63,
++0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68,
++0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04,
++0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68,
++0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92,
++0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d,
++0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d,
++0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42,
++0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5,
++0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69,
++0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a,
++0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28,
++0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c,
++0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61,
++0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61,
++0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61,
++0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xcc, 0xfa,
++0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18,
++0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80,
++0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0x68, 0x0e, 0x00, 0x80,
++0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
++0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0,
++0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68,
++0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18,
++0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0,
++0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e,
++0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 0x19, 0x43, 0xe9, 0x63,
++0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e,
++0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0xa9, 0x6b,
++0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 0xa8, 0x63, 0x01, 0x20,
++0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xe8, 0x63,
++0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18,
++0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c,
++0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0,
++0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x06, 0xfc, 0x20, 0x1c, 0x00, 0xf0,
++0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0,
++0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30,
++0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c,
++0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68,
++0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a,
++0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42,
++0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 0xf8, 0xe7, 0x78, 0x68,
++0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7,
++0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90,
++0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x80, 0x69,
++0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23,
++0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
++0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23,
++0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0,
++0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0,
++0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0,
++0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18,
++0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68,
++0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 0x00, 0x2d, 0x13, 0xd0,
++0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43,
++0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68,
++0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xdf, 0xfe, 0xb8, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7,
++0x90, 0xee, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 0xf8, 0x0e, 0x00, 0x80,
++0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
++0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0xc8, 0x60,
++0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68,
++0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47,
++0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40,
++0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a,
++0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46,
++0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c,
++0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18,
++0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68,
++0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60,
++0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32,
++0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61,
++0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c,
++0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff,
++0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 0x01, 0x20, 0xf9, 0x1d,
++0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61,
++0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48,
++0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe,
++0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02,
++0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68,
++0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9,
++0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00,
++0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00,
++0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02,
++0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71,
++0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
++0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18,
++0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49,
++0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0xe4, 0x2d, 0x00, 0x80,
++0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71,
++0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00,
++0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d,
++0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c,
++0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42,
++0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9,
++0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30,
++0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8,
++0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8,
++0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7,
++0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58,
++0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08,
++0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68,
++0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9,
++0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0,
++0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40,
++0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40,
++0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04,
++0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a,
++0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68,
++0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00,
++0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69,
++0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c,
++0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79,
++0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30,
++0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7,
++0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x04, 0x00, 0x80,
++0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
++0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68,
++0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
++0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21,
++0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a,
++0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68,
++0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c,
++0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28,
++0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0,
++0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
++0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b,
++0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18,
++0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63,
++0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b,
++0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00,
++0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
++0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24,
++0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68,
++0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60,
++0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b,
++0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19,
++0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b,
++0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f,
++0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68,
++0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c,
++0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80,
++0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2e, 0x4b,
++0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62,
++0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c,
++0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31,
++0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29,
++0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c,
++0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00,
++0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61,
++0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3,
++0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 0x3a, 0x6f, 0xfd, 0x68,
++0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 0xdb, 0x6d, 0x5b, 0x08,
++0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 0xfd, 0x6f, 0x03, 0x3b,
++0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 0x0b, 0x81, 0x10, 0x60,
++0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 0x00, 0xd0, 0x01, 0x38,
++0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 0x00, 0xd8, 0x07, 0x4a,
++0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 0x82, 0x61, 0x3a, 0x67,
++0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
++0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
++0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49,
++0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f,
++0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 0x00, 0x19, 0xe1, 0x60,
++0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28,
++0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69,
++0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0,
++0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0x65, 0x60, 0x20, 0x68,
++0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80,
++0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23,
++0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b,
++0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 0x02, 0x68, 0x15, 0x68,
++0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2,
++0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07,
++0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47,
++0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3,
++0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68,
++0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60,
++0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d,
++0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f,
++0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d,
++0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d,
++0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60,
++0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e,
++0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20,
++0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a,
++0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68,
++0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60,
++0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46,
++0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1,
++0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69,
++0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a,
++0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d,
++0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b,
++0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68,
++0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
++0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47,
++0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5,
++0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a,
++0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5,
++0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5,
++0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
++0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5,
++0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55,
++0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5,
++0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
++0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5,
++0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 0x02, 0x36, 0x83, 0xe3,
++0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 0xf2, 0xff, 0xff, 0x1a,
++0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 0x01, 0x06, 0x1c, 0xe3,
++0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 0x02, 0xc6, 0xcc, 0xe3,
++0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 0x50, 0x10, 0x91, 0xe5,
++0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5,
++0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a,
++0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 0x94, 0x00, 0x00, 0xe0,
++0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5,
++0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3,
++0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5,
++0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
++0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1,
++0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a,
++0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2,
++0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2,
++0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3,
++0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2,
++0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea,
++0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8,
++0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1,
++0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3,
++0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
++0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3,
++0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1,
++0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9,
++0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3,
++0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
++0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5,
++0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b,
++0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3,
++0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b,
++0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3,
++0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b,
++0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3,
++0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5,
++0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5,
++0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1,
++0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a,
++0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
++0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
++0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15,
++0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x04, 0x14, 0xe3,
++0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11,
++0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11,
++0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
++0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 0x04, 0x00, 0x14, 0xe3,
++0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3,
++0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3,
++0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x02, 0x14, 0xe3,
++0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3,
++0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3,
++0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b,
++0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b,
++0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2,
++0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2,
++0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea,
++0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
++0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5,
++0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
++0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
++0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5,
++0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
++0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
++0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5,
++0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5,
++0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5,
++0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba,
++0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5,
++0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7,
++0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5,
++0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5,
++0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5,
++0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5,
++0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3,
++0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
++0xcc, 0x04, 0x00, 0x80, 0x71, 0x2b, 0xff, 0xff, 0xd1, 0x3d, 0xff, 0xff,
++0xc9, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08,
++0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68,
++0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
++0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0,
++0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1,
++0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2,
++0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5,
++0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 0x74, 0x10, 0x9f, 0xe5,
++0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5,
++0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2,
++0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea,
++0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x4c, 0x00, 0x9f, 0xe5,
++0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5,
++0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a,
++0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a,
++0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80,
++0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80,
++0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
++0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00,
++0x71, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea,
++0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00,
++0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x6b, 0xea, 0xff, 0xea,
++0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
++0x28, 0x04, 0x00, 0x00, 0xf8, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80,
++0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff,
++0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54,
++0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00,
++0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff,
++0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff,
++0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 0x01, 0xff, 0x04, 0x00,
++0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
++0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff,
++0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x3d, 0x50, 0xff, 0xff, 0x81, 0x50, 0xff, 0xff,
++0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x48, 0x05, 0x00, 0x80, 0x11, 0x75, 0x21, 0x40, 0x1b, 0x75, 0x21, 0x40,
++0x31, 0x75, 0x21, 0x40, 0x49, 0x75, 0x21, 0x40,
++0x55, 0x75, 0x21, 0x40, 0x63, 0x75, 0x21, 0x40, 0x7d, 0x75, 0x21, 0x40,
++0xa9, 0x75, 0x21, 0x40, 0x6d, 0x76, 0x21, 0x40, 0xc5, 0x76, 0x21, 0x40,
++0xd3, 0x76, 0x21, 0x40, 0xdd, 0x76, 0x21, 0x40, 0xe7, 0x76, 0x21, 0x40,
++0x99, 0x77, 0x21, 0x40, 0xa7, 0x77, 0x21, 0x40, 0xb5, 0x77, 0x21, 0x40,
++0x61, 0x78, 0x21, 0x40, 0x5f, 0x7c, 0x21, 0x40, 0xe9, 0x7c, 0x21, 0x40,
++0x89, 0x7d, 0x21, 0x40, 0xbd, 0x7e, 0x21, 0x40, 0xc9, 0x7e, 0x21, 0x40,
++0x29, 0x7f, 0x21, 0x40, 0x8d, 0x7f, 0x21, 0x40, 0xb9, 0x7f, 0x21, 0x40,
++0xdd, 0x7f, 0x21, 0x40, 0x1d, 0x80, 0x21, 0x40, 0x45, 0x80, 0x21, 0x40,
++0x8d, 0x80, 0x21, 0x40, 0x9d, 0x80, 0x21, 0x40, 0xc5, 0x80, 0x21, 0x40,
++0xd5, 0x80, 0x21, 0x40, 0x1d, 0x81, 0x21, 0x40, 0x5b, 0x81, 0x21, 0x40,
++0xb1, 0x81, 0x21, 0x40, 0x11, 0x82, 0x21, 0x40, 0x1b, 0x82, 0x21, 0x40,
++0x1f, 0x82, 0x21, 0x40, 0x8d, 0x82, 0x21, 0x40, 0xd9, 0x82, 0x21, 0x40,
++0x31, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0xd1, 0x83, 0x21, 0x40,
++0x09, 0x84, 0x21, 0x40, 0x19, 0x84, 0x21, 0x40, 0x51, 0x84, 0x21, 0x40,
++0x61, 0x84, 0x21, 0x40, 0x75, 0x84, 0x21, 0x40, 0x9d, 0x84, 0x21, 0x40,
++0xa7, 0x84, 0x21, 0x40, 0xb1, 0x84, 0x21, 0x40, 0x15, 0x85, 0x21, 0x40,
++0x45, 0x85, 0x21, 0x40, 0x51, 0x85, 0x21, 0x40, 0xc5, 0x85, 0x21, 0x40,
++0xcf, 0x85, 0x21, 0x40, 0xd9, 0x85, 0x21, 0x40, 0xe3, 0x85, 0x21, 0x40,
++0xed, 0x85, 0x21, 0x40, 0xf7, 0x85, 0x21, 0x40, 0x01, 0x86, 0x21, 0x40,
++0x0b, 0x86, 0x21, 0x40, 0x15, 0x86, 0x21, 0x40, 0x01, 0x89, 0x21, 0x40,
++0x1f, 0x86, 0x21, 0x40, 0x29, 0x86, 0x21, 0x40, 0x33, 0x86, 0x21, 0x40,
++0x3d, 0x86, 0x21, 0x40, 0x65, 0x86, 0x21, 0x40, 0x6f, 0x86, 0x21, 0x40,
++0xd1, 0x86, 0x21, 0x40, 0xdb, 0x86, 0x21, 0x40, 0xe5, 0x86, 0x21, 0x40,
++0xef, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
++0x03, 0x87, 0x21, 0x40, 0x69, 0x87, 0x21, 0x40, 0xb5, 0x87, 0x21, 0x40,
++0xf9, 0x87, 0x21, 0x40, 0x09, 0x88, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
++0x55, 0x88, 0x21, 0x40, 0x59, 0x88, 0x21, 0x40, 0x5d, 0x88, 0x21, 0x40,
++0xb5, 0x88, 0x21, 0x40, 0xdd, 0x88, 0x21, 0x40, 0xe9, 0x88, 0x21, 0x40,
++0xed, 0x88, 0x21, 0x40, 0xf1, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40,
++0xf9, 0x88, 0x21, 0x40, 0xfd, 0x88, 0x21, 0x40, 0x2d, 0x85, 0x21, 0x40,
++0x89, 0x85, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
++0x0d, 0x89, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0xe1, 0x74, 0x21, 0x40,
++0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
++0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
++0x6b, 0x78, 0x21, 0x40, 0xf5, 0x7b, 0x21, 0x40, 0x31, 0x7c, 0x21, 0x40,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40,
++0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40,
++0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40,
++0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00,
++0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
++0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
++0xd1, 0xa8, 0x21, 0x40, 0x2d, 0xaa, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
++0x89, 0x70, 0x21, 0x40, 0xc9, 0xa1, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x57, 0x89, 0x21, 0x40, 0xd1, 0xa8, 0x21, 0x40, 0xc5, 0x2f, 0xff, 0xff,
++0x05, 0x21, 0xff, 0xff, 0xef, 0x20, 0xff, 0xff, 0x59, 0xa7, 0x21, 0x40,
++0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 0x5c, 0x2e, 0x00, 0x80,
++0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 0x00, 0x30, 0x37, 0x2f,
++0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35,
++0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
++0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43,
++0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
++0x6f, 0x6e, 0x0a, 0x00, 0x08, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x53, 0xff, 0xff,
++0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00,
++0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
++0x69, 0x3e, 0xff, 0xff, 0xc9, 0x4f, 0xff, 0xff, 0xd5, 0x24, 0xff, 0xff,
++0xc9, 0x3b, 0xff, 0xff, 0x29, 0x3c, 0xff, 0xff, 0x19, 0x1a, 0xff, 0xff,
++0x65, 0x11, 0xff, 0xff, 0xcc, 0x53, 0xff, 0xff, 0x21, 0x40, 0xff, 0xff,
++0x89, 0x70, 0x21, 0x40, 0x49, 0x72, 0x21, 0x40, 0xd9, 0x3f, 0xff, 0xff,
++0x21, 0x9a, 0x21, 0x40, 0x85, 0x24, 0xff, 0xff, 0x64, 0x53, 0xff, 0xff,
++0x8c, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
++0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
++0x00, 0x00, 0x20, 0x40, 0xb0, 0x50, 0x00, 0x00, 0x7b, 0x0e, 0x00, 0x00,
++0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0xed, 0x89, 0x21, 0x40, 0x8b, 0x89, 0x21, 0x40, 0xa5, 0x8c, 0x21, 0x40,
++0x05, 0x8d, 0x21, 0x40, 0xcd, 0x8d, 0x21, 0x40, 0x8b, 0x8b, 0x21, 0x40,
++0xa9, 0x8e, 0x21, 0x40, 0x15, 0x8f, 0x21, 0x40, 0x69, 0x8b, 0x21, 0x40,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++0x59, 0xbd, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x2d, 0xbe, 0x21, 0x40,
++0x00, 0x20, 0x0a, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23,
++0x9b, 0x01, 0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32,
++0xc8, 0x60, 0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x03, 0x48, 0xc0, 0x46,
++0x48, 0x60, 0x88, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c,
++0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xde, 0xff, 0x68, 0x49, 0x0b, 0x23,
++0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40,
++0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61,
++0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a,
++0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68,
++0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20,
++0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xd4, 0xfa, 0xf8, 0x68, 0x00, 0x28,
++0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23,
++0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95,
++0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0,
++0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 0x9b, 0x5c, 0x1e, 0x1c,
++0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 0x5b, 0x78, 0x83, 0x42,
++0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 0x03, 0x9d, 0xed, 0x6a,
++0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 0xeb, 0x62, 0x53, 0x68,
++0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 0x86, 0x42, 0x0a, 0xd1,
++0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 0x9b, 0x00, 0x3c, 0x4e,
++0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 0x9d, 0x61, 0x53, 0x78,
++0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 0x5d, 0x1c, 0x01, 0x95,
++0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xeb, 0x18,
++0xda, 0x60, 0x3a, 0x69, 0x01, 0x32, 0x3a, 0x61, 0x64, 0x00, 0x01, 0x31,
++0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xb8, 0xd3, 0x00, 0x20,
++0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02,
++0xc9, 0x18, 0x88, 0x61, 0x01, 0x9b, 0x99, 0x00, 0x89, 0x18, 0x2d, 0x23,
++0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1,
++0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69,
++0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0,
++0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 0x03, 0xd2, 0x30, 0x20,
++0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 0x78, 0x69, 0x00, 0x28,
++0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 0x78, 0x61, 0x00, 0x20,
++0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0,
++0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78,
++0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 0x9b, 0x00, 0x9e, 0x19,
++0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00,
++0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3,
++0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01,
++0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0x30, 0x53, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80,
++0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46,
++0x18, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
++0x10, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
++0x08, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x38, 0x52, 0xff, 0xff,
++0x88, 0x51, 0xff, 0xff, 0xd5, 0xb0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20,
++0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01,
++0xf8, 0x18, 0x05, 0x73, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20,
++0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0,
++0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
++0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20,
++0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 0xc3, 0xff, 0x00, 0x28,
++0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61,
++0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61,
++0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80,
++0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
++0x7d, 0x71, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48,
++0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42,
++0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18,
++0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92,
++0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7,
++0x8d, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92,
++0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x82, 0xff,
++0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x7c, 0x29, 0x00, 0x80,
++0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
++0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68,
++0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 0x63, 0xff, 0x01, 0x20,
++0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c,
++0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29,
++0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1,
++0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0,
++0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff,
++0x22, 0xe0, 0x09, 0x01, 0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a,
++0x17, 0x49, 0xff, 0xf7, 0x35, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73,
++0x04, 0x23, 0xa8, 0x69, 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61,
++0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60,
++0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0,
++0x17, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0,
++0x02, 0x23, 0xf8, 0x6b, 0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00,
++0x28, 0x05, 0x00, 0x80, 0xa5, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0,
++0x68, 0x0e, 0x00, 0x80, 0xe4, 0x01, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
++0x7d, 0x71, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49,
++0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30,
++0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0,
++0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0,
++0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
++0xc1, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80,
++0xe8, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88,
++0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0,
++0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c,
++0xff, 0xf7, 0xcb, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09,
++0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46,
++0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20,
++0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b,
++0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0,
++0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00,
++0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01,
++0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46,
++0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0,
++0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c,
++0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30,
++0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48,
++0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a,
++0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8,
++0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0,
++0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43,
++0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c,
++0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18,
++0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x5e, 0xfe,
++0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48,
++0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x53, 0xfe, 0x01, 0x20,
++0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18,
++0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61,
++0x00, 0xe0, 0x88, 0x61, 0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
++0xc1, 0x63, 0x00, 0x20, 0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73,
++0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80,
++0x50, 0xba, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
++0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80,
++0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a,
++0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a,
++0x88, 0x66, 0x88, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40,
++0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42,
++0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46,
++0x08, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
++0x90, 0xee, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46,
++0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80,
++0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60,
++0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60,
++0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48,
++0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46,
++0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90,
++0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46,
++0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c,
++0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a,
++0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20,
++0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
++0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc,
++0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xa1, 0x21,
++0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
++0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xff, 0x21, 0xa1, 0x22,
++0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
++0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47,
++0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20,
++0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03,
++0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 0x00, 0x20, 0x70, 0x47,
++0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b,
++0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab,
++0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20,
++0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40,
++0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
++0x5b, 0xff, 0xf8, 0x88, 0x04, 0xa9, 0x03, 0xf0, 0xc9, 0xff, 0x01, 0xab,
++0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8,
++0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b,
++0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68,
++0xc0, 0x46, 0x03, 0x90, 0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
++0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31,
++0x68, 0x46, 0xff, 0xf7, 0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b,
++0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78,
++0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22,
++0x00, 0xab, 0x5a, 0x80, 0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70,
++0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68,
++0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31,
++0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80,
++0xa4, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
++0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48,
++0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xe4, 0xfc, 0x00, 0x28,
++0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xdf, 0xfc,
++0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21,
++0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
++0x0d, 0x76, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x59, 0xbd, 0x21, 0x40,
++0x00, 0xb5, 0xc0, 0x88, 0x03, 0xf0, 0x2e, 0xff, 0x00, 0x20, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
++0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47,
++0xb0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7,
++0xb5, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0xa4, 0xfc, 0x04, 0x1c, 0x20, 0x4a,
++0x00, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 0x27, 0xd0,
++0x04, 0xa9, 0x1d, 0x4a, 0x38, 0x1c, 0xff, 0xf7, 0x99, 0xfc, 0x04, 0xa8,
++0x00, 0x23, 0x01, 0x2f, 0x06, 0xd1, 0x0c, 0xaa, 0x02, 0x32, 0x00, 0x21,
++0x13, 0x60, 0x01, 0x31, 0x10, 0x29, 0xfb, 0xd3, 0x01, 0x68, 0x04, 0x29,
++0x04, 0xd9, 0x89, 0x08, 0x03, 0x39, 0x89, 0x08, 0x01, 0x31, 0x00, 0xe0,
++0x19, 0x1c, 0x00, 0xab, 0x59, 0x70, 0x06, 0xa9, 0x09, 0x78, 0xc0, 0x46,
++0xd9, 0x80, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46,
++0x03, 0x90, 0x04, 0x33, 0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
++0x18, 0x70, 0x09, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x6e, 0xfc, 0x68, 0x46,
++0x29, 0x1c, 0xff, 0xf7, 0xb7, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
++0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c,
++0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
++0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xa2, 0xff, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc,
++0x18, 0x47, 0xf0, 0xb5, 0xc7, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x1c,
++0x01, 0xa9, 0xff, 0xf7, 0x4d, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0x3c, 0xfc,
++0x00, 0x90, 0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a,
++0x25, 0xd8, 0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x21, 0xd8, 0x19, 0x2c,
++0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0xf9, 0x1d,
++0x09, 0x31, 0x06, 0xab, 0x00, 0x20, 0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd,
++0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3,
++0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78,
++0x86, 0x42, 0xf1, 0xdc, 0x20, 0x1c, 0x05, 0xa9, 0x2b, 0x1c, 0xff, 0xf7,
++0x21, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x01, 0xa8, 0x00, 0x78, 0x40, 0x23,
++0x18, 0x43, 0x01, 0xab, 0x18, 0x70, 0x07, 0x49, 0x00, 0x98, 0xff, 0xf7,
++0x06, 0xfc, 0x00, 0x21, 0x01, 0xa8, 0xff, 0xf7, 0x4f, 0xfd, 0x01, 0x20,
++0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff,
++0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x1b, 0xfe, 0x08, 0xbc,
++0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d,
++0x68, 0x68, 0x01, 0x30, 0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7,
++0xf5, 0xfd, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
++0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0,
++0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68,
++0x00, 0x2a, 0x15, 0xd9, 0x40, 0xcb, 0x0f, 0x1c,
++0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 0x12, 0x78, 0x40, 0x23,
++0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 0xda, 0x80, 0x02, 0x90,
++0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 0x15, 0xe0, 0x01, 0x30,
++0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 0x02, 0x94, 0x69, 0x68,
++0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a,
++0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42,
++0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 0xf7, 0xfc, 0x01, 0x20,
++0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x9c, 0x03, 0x00, 0x80,
++0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3,
++0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 0x00, 0xd2, 0x02, 0x22,
++0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 0x01, 0x2b, 0x2e, 0xd1,
++0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0x1b, 0x23,
++0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 0x00, 0xd2, 0x04, 0x27,
++0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 0x07, 0xd2, 0xd1, 0x1d,
++0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23,
++0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x79, 0x03, 0x29,
++0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a,
++0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07,
++0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c,
++0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00,
++0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40,
++0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x04, 0xf0, 0x07, 0xfa, 0x39, 0x48,
++0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 0x37, 0x4e, 0xc5, 0x1d,
++0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 0x5b, 0x5c, 0x5b, 0x00,
++0x9f, 0x44, 0x00, 0x1c, 0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20,
++0xb8, 0x71, 0x00, 0x20, 0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23,
++0x98, 0x43, 0x00, 0xf0, 0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff,
++0xc0, 0x08, 0x06, 0xd3, 0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28,
++0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22,
++0x20, 0x1c, 0x2b, 0xe0, 0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68,
++0x19, 0x43, 0x01, 0x60, 0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a,
++0x00, 0x21, 0x04, 0xf0, 0x99, 0xf9, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68,
++0x99, 0x43, 0x01, 0x60, 0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68,
++0x04, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68,
++0x19, 0x43, 0x01, 0x60, 0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43,
++0x00, 0xf0, 0x34, 0xf8, 0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x04, 0xf0,
++0x77, 0xf9, 0xe5, 0xe7, 0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43,
++0x00, 0xf0, 0x28, 0xf8, 0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23,
++0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xff, 0xf7, 0xe3, 0xfa, 0xd5, 0xe7,
++0x06, 0x20, 0xb8, 0x71, 0xd2, 0xe7, 0x00, 0x00, 0xa9, 0x79, 0x21, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00,
++0x10, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20,
++0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
++0x04, 0xf0, 0x4e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x98, 0x1c, 0x00, 0x80,
++0xa9, 0x79, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x31, 0x48, 0x00, 0x68,
++0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0,
++0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 0x01, 0x2a, 0x05, 0xd1,
++0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43,
++0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 0x01, 0x60, 0xe0, 0x68,
++0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x80, 0x8b,
++0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43,
++0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20,
++0x02, 0xf0, 0x1a, 0xfb, 0x38, 0x09, 0x07, 0xd3, 0xe0, 0x6f, 0x80, 0x23,
++0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 0x00, 0x68, 0x00, 0xe0,
++0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x15, 0x48,
++0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43,
++0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08,
++0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 0x10, 0x43, 0x88, 0x42,
++0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29,
++0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 0x04, 0x33, 0x18, 0x40,
++0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80,
++0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7,
++0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 0xe3, 0x23, 0x1b, 0x01,
++0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 0x01, 0x22, 0x4a, 0x71,
++0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 0x99, 0x43,
++0x01, 0x60, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x02, 0xf0, 0x8c, 0xfc,
++0x07, 0x20, 0x02, 0xf0, 0x5b, 0xfc, 0x38, 0x1c, 0xff, 0xf7, 0x36, 0xfa,
++0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
++0x37, 0xfc, 0xff, 0xf7, 0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48,
++0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46,
++0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x67, 0xfb, 0x01, 0x20,
++0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
++0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
++0x38, 0x1c, 0xff, 0xf7, 0x17, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff,
++0xff, 0xf7, 0x62, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
++0xff, 0xf7, 0x4c, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7,
++0x01, 0xfc, 0x01, 0x24, 0x1a, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8,
++0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20,
++0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x20, 0xe0, 0x14, 0x48, 0xff, 0xf7,
++0xe1, 0xf9, 0x05, 0x1c, 0x13, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7,
++0xdd, 0xf9, 0x12, 0x49, 0x28, 0x1c, 0xff, 0xf7, 0xd8, 0xf9, 0x01, 0x2f,
++0x06, 0xd1, 0x0c, 0xa9, 0x00, 0x20, 0x00, 0x22,
++0x0a, 0x60, 0x01, 0x30, 0x10, 0x28, 0xfb, 0xd3, 0x10, 0x20, 0x00, 0xab,
++0x58, 0x70, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46,
++0x03, 0x90, 0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x0f, 0xfb, 0x20, 0x1c,
++0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x01, 0x00, 0x00,
++0x24, 0x02, 0xff, 0xff, 0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff,
++0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
++0xbb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x01, 0xd1,
++0x19, 0x2c, 0x09, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43,
++0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 0x27, 0xe0,
++0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90,
++0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28,
++0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04,
++0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 0x09, 0x0c,
++0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0b, 0x48, 0xff, 0xf7, 0x7e, 0xf9,
++0x07, 0x1c, 0x0a, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0x7a, 0xf9,
++0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x75, 0xf9, 0x68, 0x46, 0x00, 0x21,
++0xff, 0xf7, 0xbe, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0xc5, 0xaf, 0x21, 0x40,
++0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27,
++0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0,
++0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0,
++0x04, 0x2e, 0x00, 0xd1, 0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e,
++0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c,
++0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0,
++0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0,
++0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33,
++0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 0x01, 0x23, 0x5b, 0x02,
++0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22,
++0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 0xff, 0x23, 0xe1, 0x33,
++0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 0xff, 0x33, 0x9e, 0x42,
++0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1,
++0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21,
++0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0x40, 0x88,
++0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0,
++0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1,
++0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43,
++0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0,
++0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x09, 0x21,
++0x49, 0x02, 0x00, 0x20, 0x02, 0xf0, 0x70, 0xf9, 0x00, 0x2f, 0x02, 0xd1,
++0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7,
++0xef, 0xfa, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab,
++0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33,
++0xff, 0xf7, 0x22, 0xfa, 0x28, 0x1c, 0x04, 0xb0,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62,
++0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28,
++0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21,
++0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18,
++0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0,
++0x33, 0xf9, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80,
++0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23,
++0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20,
++0x02, 0xf0, 0x20, 0xf9, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28,
++0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23,
++0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01,
++0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c,
++0x10, 0x20, 0x02, 0xf0, 0x01, 0xf9, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01,
++0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18,
++0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02,
++0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xee, 0xf8, 0x00, 0x20, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0,
++0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x69, 0xfa, 0xb8, 0x05,
++0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
++0xa1, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49,
++0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49,
++0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40,
++0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a,
++0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1,
++0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02,
++0x69, 0x46, 0xff, 0xf7, 0x35, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46,
++0x00, 0x21, 0xff, 0xf7, 0x6f, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20,
++0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1,
++0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1,
++0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47,
++0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 0x9f, 0xf8, 0x69, 0x46,
++0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x0a, 0xfa, 0x01, 0xab, 0x5c, 0x80,
++0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21,
++0xff, 0xf7, 0x40, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49,
++0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
++0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47,
++0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
++0xe3, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab,
++0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf9, 0x01, 0x20,
++0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
++0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47,
++0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68,
++0xff, 0xf7, 0xc6, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49,
++0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0,
++0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70,
++0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
++0xef, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68,
++0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0x17, 0xf8, 0x00, 0x20,
++0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0x9a, 0xf9, 0x00, 0xa8, 0x00, 0x78,
++0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80,
++0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xcd, 0xf8, 0x01, 0x20,
++0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88,
++0x69, 0x46, 0xff, 0xf7, 0x83, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x72, 0xff,
++0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0xf2, 0xff, 0x00, 0x28, 0x06, 0xd0,
++0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0x36, 0xff, 0x01, 0xab, 0x58, 0x80,
++0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c,
++0xfe, 0xf7, 0x5f, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa8, 0xf8,
++0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0,
++0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x57, 0xf9, 0x10, 0x48,
++0xfe, 0xf7, 0x46, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7,
++0x43, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c,
++0x22, 0x1c, 0xfe, 0xf7, 0x3c, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
++0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 0x32, 0xff, 0x68, 0x46,
++0x00, 0x21, 0xff, 0xf7, 0x7b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
++0x59, 0xb0, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7,
++0x43, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4,
++0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1,
++0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1,
++0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a,
++0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40,
++0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30,
++0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c,
++0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37,
++0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28,
++0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40,
++0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43,
++0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0c, 0x4b,
++0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02,
++0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80,
++0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04,
++0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
++0x40, 0x00, 0x14, 0x00, 0x28, 0x1b, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0,
++0x13, 0x49, 0x0a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12,
++0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02,
++0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02,
++0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c,
++0xff, 0xf7, 0xae, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43,
++0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xe5, 0xff, 0x01, 0x20,
++0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40,
++0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04,
++0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02,
++0x00, 0x12, 0x18, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04,
++0x00, 0x0c, 0x02, 0x02, 0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c,
++0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00,
++0x90, 0xb5, 0x84, 0xb0, 0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c,
++0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c,
++0x17, 0x02, 0x12, 0x12, 0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c,
++0x1f, 0x02, 0x1b, 0x12, 0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23,
++0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b,
++0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04,
++0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
++0x95, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a,
++0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
++0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
++0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x79, 0xff, 0x01, 0x20,
++0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
++0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47,
++0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a,
++0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
++0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
++0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x55, 0xff, 0x01, 0x20,
++0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
++0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47,
++0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7,
++0xf4, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff,
++0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x06, 0x48,
++0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
++0x2f, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xfd, 0xff, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf8, 0xff,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf3, 0xff, 0x08, 0xbc,
++0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xc6, 0xfd,
++0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21,
++0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c,
++0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a,
++0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48,
++0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0xd5, 0x94, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
++0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
++0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff,
++0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
++0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff,
++0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0,
++0xf9, 0xff, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0,
++0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xfe, 0xf8, 0x00, 0x28, 0x0c, 0xd1,
++0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x82, 0xff, 0x06, 0x48, 0x01, 0xab,
++0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xbb, 0xfe, 0x01, 0x20,
++0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7,
++0x6d, 0xff, 0x01, 0x27, 0x01, 0xab, 0x5f, 0x80, 0x09, 0x48, 0x81, 0x89,
++0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04,
++0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
++0x9b, 0xfe, 0x38, 0x1c, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0xb5, 0xfe, 0xf7, 0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
++0xfe, 0xf7, 0x5a, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
++0x55, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0xb5, 0xfe, 0xf7, 0x41, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
++0xfe, 0xf7, 0x3c, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
++0x37, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x32, 0xff,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7,
++0x13, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x02, 0xf0, 0xa9, 0xff, 0x02, 0x20,
++0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x48, 0xfe,
++0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
++0x19, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
++0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf8, 0xfe, 0xfa, 0x88, 0x12, 0x49,
++0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 0x0f, 0xd0, 0x04, 0x70,
++0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 0xc8, 0x82, 0xb8, 0x68,
++0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 0x48, 0x83, 0xf8, 0x68,
++0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21,
++0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
++0x00, 0x21, 0xfe, 0xf7, 0x17, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
++0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
++0xfe, 0xf7, 0xde, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
++0xd9, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xd4, 0xfe,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xcf, 0xfe, 0x08, 0xbc,
++0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c,
++0xfe, 0xf7, 0xae, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43,
++0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42,
++0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
++0xfe, 0xf7, 0xdc, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68,
++0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80,
++0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xcc, 0xfd,
++0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0,
++0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x7b, 0xfe, 0xf8, 0x88,
++0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b,
++0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
++0x00, 0x21, 0xfe, 0xf7, 0xab, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68,
++0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00,
++0x80, 0xb5, 0x86, 0xb0, 0x02, 0xa9, 0xfe, 0xf7, 0x57, 0xfe, 0x01, 0x27,
++0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68,
++0xc0, 0x46, 0x04, 0x91, 0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68,
++0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46,
++0x02, 0xa8, 0xfe, 0xf7, 0x81, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68,
++0x80, 0x68, 0xfe, 0xf7, 0x47, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c,
++0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x36, 0xfe, 0x01, 0xab, 0x5c, 0x80,
++0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x61, 0xfd, 0x04, 0xb0,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
++0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x24, 0xfe, 0x01, 0xab, 0x5f, 0x80,
++0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x50, 0xfd, 0x04, 0xb0, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
++0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a,
++0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0,
++0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27,
++0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27,
++0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xec, 0xfd, 0x01, 0xab, 0x5f, 0x80,
++0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x26, 0xfd, 0x20, 0x1c, 0x04, 0xb0,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0,
++0x69, 0x46, 0xfe, 0xf7, 0xd7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab,
++0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x0f, 0xfd, 0x01, 0x20,
++0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
++0x00, 0xb5, 0xfe, 0xf7, 0xdd, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47,
++0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
++0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
++0x00, 0xb5, 0xfe, 0xf7, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xab, 0xfd, 0x00, 0x20,
++0x01, 0xab, 0x58, 0x70, 0x0c, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29,
++0x02, 0xd1, 0x03, 0x97, 0x04, 0x97, 0x01, 0xe0, 0x03, 0x97, 0x04, 0x90,
++0x68, 0x46, 0x01, 0xf0, 0x33, 0xfd, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46,
++0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xd3, 0xfc, 0x38, 0x1c,
++0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30,
++0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40,
++0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42,
++0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 0x02, 0xd3, 0x40, 0x1a,
++0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 0x01, 0x1c, 0xff, 0x27,
++0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 0x43, 0x00, 0x1b, 0x18,
++0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 0x4b, 0x00, 0x59, 0x18,
++0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd7, 0x50,
++0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 0x57, 0x60, 0x8b, 0x68,
++0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69,
++0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc,
++0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb,
++0x38, 0x1c, 0xf6, 0xe7, 0x40, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0,
++0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0,
++0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58,
++0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0,
++0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 0x00, 0x28,
++0x5b, 0xd0, 0x00, 0x26, 0x00, 0x22, 0x00, 0x92, 0x40, 0x23, 0x00, 0x21,
++0x00, 0x20, 0x02, 0xaa, 0x00, 0xf0, 0x88, 0xfa, 0x04, 0xa9, 0x00, 0x20,
++0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0xa2, 0x42, 0x03, 0xd1,
++0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06,
++0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c,
++0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22,
++0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 0x00, 0xf0, 0x68, 0xfa,
++0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05,
++0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42,
++0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
++0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x50, 0xfa,
++0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06,
++0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22,
++0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0,
++0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1,
++0x01, 0x99, 0x00, 0x29, 0x0f, 0xd1, 0xff, 0x20, 0x3d, 0xe0, 0x40, 0xe0,
++0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
++0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x28, 0xfa,
++0x02, 0x9d, 0x01, 0x20, 0x00, 0x04, 0x46, 0x9a, 0x10, 0x43, 0x79, 0x00,
++0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0x30, 0x1c,
++0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x04, 0x2c, 0x00, 0xd0, 0x0c, 0x20,
++0x04, 0x1c, 0xb0, 0x60, 0x00, 0x20, 0x20, 0x21, 0x46, 0x9a, 0x11, 0x40,
++0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 0x28, 0x19, 0xff, 0x21,
++0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 0xff, 0xf7, 0x19, 0xff, 0x43, 0x01,
++0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21,
++0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60,
++0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20,
++0xf9, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23,
++0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06,
++0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06,
++0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28,
++0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x45, 0x91, 0x41, 0x4a,
++0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 0xc0, 0x43, 0x76, 0xe0,
++0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00,
++0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 0x00, 0x21, 0x02, 0x91,
++0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 0xff, 0x21, 0x68, 0x1e,
++0x09, 0x31, 0xff, 0xf7, 0xcd, 0xfe, 0x61, 0x68, 0x40, 0x18, 0x01, 0x90,
++0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 0xaf, 0x1b, 0x09, 0xe0,
++0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe,
++0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 0x00, 0x22, 0x00, 0x92,
++0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 0x00, 0xf0, 0x9e, 0xf9,
++0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, 0x02, 0x99,
++0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 0xed, 0x1b, 0xa0, 0x68,
++0xa8, 0x42, 0x00, 0xd1, 0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99,
++0xcf, 0x43, 0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68,
++0x03, 0xaa, 0x00, 0xf0, 0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90,
++0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43,
++0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21,
++0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99,
++0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90,
++0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xca, 0xf9,
++0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43,
++0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40,
++0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb,
++0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d,
++0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0,
++0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0,
++0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 0x0f, 0xd3, 0x05, 0xe0,
++0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b,
++0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19,
++0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00,
++0x40, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c,
++0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49,
++0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43,
++0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c,
++0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x21, 0x69, 0x8a, 0x42,
++0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 0xa0, 0x68, 0xe1, 0x68,
++0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x0d, 0xfe, 0x61, 0x68,
++0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31,
++0xff, 0xf7, 0x0d, 0xfe, 0xc2, 0x19, 0xff, 0x21, 0x09, 0x31, 0x8a, 0x42,
++0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x0b, 0x1a, 0x03, 0x93,
++0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0xe1, 0xf8, 0xe0, 0x68,
++0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 0x5d, 0x19, 0xff, 0x1a,
++0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 0x01, 0x9a, 0xc0, 0x46,
++0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0,
++0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98,
++0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98,
++0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0xab, 0x20, 0x40,
++0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91,
++0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58,
++0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda,
++0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 0x02, 0x9a, 0x54, 0x18,
++0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 0x01, 0xd9, 0x22, 0x69,
++0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 0xa0, 0x68, 0xe1, 0x68,
++0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0xa7, 0xfd, 0x61, 0x68,
++0x40, 0x18, 0x00, 0x90, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21,
++0x09, 0x31, 0xff, 0xf7, 0xa6, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23,
++0x5b, 0x04, 0x19, 0x43, 0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32,
++0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c,
++0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19,
++0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b,
++0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e,
++0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 0xcb, 0xf8, 0xe0, 0x68,
++0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9,
++0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f,
++0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x40, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0,
++0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00,
++0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2,
++0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09,
++0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 0x40, 0x68, 0x0c, 0x23,
++0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 0x11, 0x2c, 0x0d, 0xd0,
++0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1,
++0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06,
++0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c,
++0xdb, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20,
++0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47,
++0x40, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x6f, 0xfa, 0x57, 0x20,
++0x02, 0xf0, 0xcc, 0xf9, 0x02, 0xf0, 0x40, 0xf9, 0x00, 0x0a, 0xfb, 0xd3,
++0x02, 0xf0, 0x4e, 0xfa, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0,
++0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23,
++0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32,
++0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c,
++0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x4b, 0xfa, 0x53, 0x20,
++0x02, 0xf0, 0xa8, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0,
++0xa3, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0xa0, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
++0x9d, 0xf9, 0x02, 0xf0, 0x23, 0xfa, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0,
++0x37, 0xfa, 0x54, 0x20, 0x02, 0xf0, 0x94, 0xf9, 0x00, 0x98, 0x02, 0xf0,
++0x91, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x8e, 0xf9, 0x30, 0x1c, 0x14, 0xe0,
++0x02, 0xf0, 0x2a, 0xfa, 0x52, 0x20, 0x02, 0xf0, 0x87, 0xf9, 0x01, 0x98,
++0x02, 0xf0, 0x84, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x81, 0xf9, 0x30, 0x1c,
++0x02, 0xf0, 0x7e, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xf9, 0x00, 0x20,
++0x02, 0xf0, 0x78, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x00, 0x20,
++0x02, 0xf0, 0x72, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0xe4, 0xf8,
++0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xf0, 0xf9,
++0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
++0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x42, 0x02, 0x0a, 0x43,
++0x15, 0x1c, 0x01, 0x28, 0x54, 0xd0, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23,
++0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68,
++0x19, 0x43, 0x01, 0x60, 0x02, 0xf0, 0xe6, 0xf9, 0x53, 0x20, 0x02, 0xf0,
++0x43, 0xf9, 0x28, 0x0c, 0x06, 0x1c, 0x02, 0xf0, 0x3f, 0xf9, 0x28, 0x0a,
++0x01, 0x90, 0x00, 0x90, 0x02, 0xf0, 0x3a, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
++0x37, 0xf9, 0x02, 0xf0, 0xbd, 0xf9, 0xff, 0xf7, 0x61, 0xff, 0x02, 0xf0,
++0xd1, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x2e, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
++0x2b, 0xf9, 0x00, 0x98, 0x02, 0xf0, 0x28, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
++0x25, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0,
++0x1f, 0xf9, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xa3, 0xf9, 0x02, 0xf0,
++0xb9, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x16, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
++0x13, 0xf9, 0x01, 0x98, 0x02, 0xf0, 0x10, 0xf9,
++0x28, 0x1c, 0x02, 0xf0, 0x0d, 0xf9, 0x02, 0xf0, 0x93, 0xf9, 0xff, 0xf7,
++0x37, 0xff, 0x07, 0x49, 0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43,
++0x02, 0x60, 0xc8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
++0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0xf0, 0x8f, 0xf8, 0x06, 0x4f,
++0xc0, 0x46, 0xf8, 0x60, 0x01, 0xf0, 0xf2, 0xf8, 0x78, 0x80, 0x01, 0xf0,
++0xb1, 0xf8, 0x38, 0x71, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 0x05, 0xf9, 0x02, 0x49,
++0xc0, 0x46, 0x08, 0x80, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0x0b, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23,
++0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68,
++0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68,
++0x1a, 0x43, 0x02, 0x60, 0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32,
++0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28,
++0xfa, 0xd3, 0x46, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30,
++0x20, 0x28, 0xfa, 0xd3, 0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50,
++0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65,
++0x8f, 0x65, 0x3f, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60,
++0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00,
++0x09, 0x18, 0x49, 0x01, 0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d,
++0xf9, 0x33, 0x34, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01,
++0xcb, 0x18, 0x63, 0x63, 0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18,
++0xe3, 0x63, 0x23, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30,
++0x02, 0x28, 0xe4, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c,
++0xc0, 0x46, 0xa1, 0x62, 0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62,
++0xc1, 0x18, 0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21,
++0xe1, 0x64, 0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69,
++0xc0, 0x46, 0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66,
++0x8b, 0x68, 0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66,
++0x1e, 0x4b, 0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01,
++0xc3, 0x18, 0xa3, 0x67, 0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33,
++0x66, 0x61, 0xe7, 0x61, 0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b,
++0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d,
++0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46,
++0x53, 0x66, 0x89, 0x69, 0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46,
++0xd1, 0x66, 0x16, 0x67, 0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67,
++0x56, 0x67, 0xd7, 0x61, 0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73,
++0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
++0x64, 0x2d, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00,
++0x7c, 0x29, 0x00, 0x80, 0x00, 0x55, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00,
++0x10, 0x55, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23,
++0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23,
++0xdb, 0x01, 0xd0, 0x18, 0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18,
++0xc1, 0x61, 0x1c, 0x70, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60,
++0xb9, 0x73, 0x59, 0x61, 0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60,
++0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69,
++0xe4, 0x18, 0x44, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02,
++0x84, 0x63, 0x0e, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46,
++0x44, 0x62, 0x84, 0x69, 0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60,
++0x03, 0x6b, 0xc0, 0x46, 0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62,
++0xc1, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc,
++0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
++0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22,
++0x1b, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20,
++0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c,
++0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37,
++0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18,
++0x33, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20,
++0xf8, 0x60, 0xda, 0x61, 0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48,
++0xc0, 0x46, 0xc2, 0x60, 0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e,
++0xf8, 0x63, 0x0a, 0x48, 0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68,
++0xc0, 0x46, 0x59, 0x80, 0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc,
++0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xbc, 0x20, 0x40,
++0x90, 0xee, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40,
++0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33,
++0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46,
++0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23,
++0x1b, 0x01, 0xd1, 0x18, 0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80,
++0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46,
++0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48,
++0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23,
++0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34,
++0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61,
++0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62,
++0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d,
++0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26,
++0xb6, 0x03, 0x37, 0x61, 0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67,
++0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60,
++0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36,
++0x7e, 0x61, 0x19, 0x4f, 0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c,
++0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50,
++0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27,
++0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3,
++0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3,
++0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40,
++0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40,
++0x80, 0x01, 0x18, 0x00, 0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
++0x08, 0x04, 0x00, 0x80, 0xb8, 0xb5, 0x2c, 0x48, 0xfd, 0xf7, 0xba, 0xfd,
++0x01, 0x20, 0x2b, 0x49, 0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68,
++0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20,
++0x04, 0x06, 0x24, 0x0e, 0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23,
++0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3,
++0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61,
++0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62,
++0x00, 0x27, 0x1b, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69,
++0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46,
++0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46,
++0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f,
++0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43,
++0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2,
++0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49,
++0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40,
++0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01,
++0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64,
++0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67,
++0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46,
++0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc,
++0x70, 0x47, 0x00, 0x00, 0xac, 0x66, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80,
++0xd0, 0x2c, 0x00, 0x80, 0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63,
++0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63,
++0x01, 0x64, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20,
++0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60,
++0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a,
++0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28,
++0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80,
++0xf4, 0x2d, 0x00, 0x80, 0x5d, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48,
++0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b,
++0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48,
++0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b,
++0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49,
++0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b,
++0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00,
++0xac, 0x1e, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00,
++0xac, 0xee, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00,
++0xac, 0x3e, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80,
++0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19,
++0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63,
++0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46,
++0x08, 0x63, 0x48, 0x63, 0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d,
++0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72,
++0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32,
++0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70,
++0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72,
++0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22,
++0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73,
++0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
++0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73,
++0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73,
++0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71,
++0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73,
++0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73,
++0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
++0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73,
++0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73,
++0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71,
++0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61,
++0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00,
++0xa0, 0x1c, 0x00, 0x80, 0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02,
++0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00,
++0x09, 0x49, 0x0a, 0x4b, 0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60,
++0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31,
++0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61,
++0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00,
++0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20,
++0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61,
++0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
++0x6c, 0x06, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32,
++0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30,
++0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
++0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d,
++0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3,
++0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60,
++0x70, 0x47, 0x00, 0x00, 0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
++0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfd, 0xf7, 0xea, 0xfb, 0x0b, 0x48,
++0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46,
++0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
++0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47,
++0xc1, 0xbd, 0x21, 0x40, 0x75, 0x98, 0x21, 0x40,
++0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x00, 0xb5, 0x0f, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
++0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48,
++0x0c, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xbf, 0xfb, 0x0b, 0x48, 0x41, 0x8d,
++0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a,
++0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x59, 0xbd, 0x21, 0x40,
++0x75, 0x98, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
++0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0x1b, 0x4c,
++0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28,
++0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67,
++0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18,
++0xc1, 0x43, 0xe8, 0x61, 0x69, 0x62, 0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03,
++0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x71,
++0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 0xb8, 0x60, 0x00, 0xf0, 0x4c, 0xfa,
++0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x20, 0xb8, 0x60, 0x07, 0x20, 0x78, 0x61,
++0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0xc0, 0x8b, 0x04, 0x23,
++0x18, 0x40, 0xe8, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x02, 0x1c, 0x00, 0x20, 0xff, 0x23,
++0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 0x00, 0xd1, 0x01, 0x20,
++0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 0x90, 0xbc, 0x70, 0x47,
++0x1b, 0x4a, 0xd7, 0x68, 0x1a, 0x4b, 0x19, 0x79, 0x1c, 0x1c, 0x37, 0x23,
++0x9b, 0x01, 0xe3, 0x18, 0x01, 0x2f, 0x0d, 0xd1, 0x57, 0x88, 0x00, 0x2f,
++0x0a, 0xd1, 0x00, 0x29, 0x0a, 0xd1, 0x59, 0x8b, 0x0a, 0x09, 0x00, 0xd3,
++0x02, 0x20, 0x49, 0x09, 0xe8, 0xd3, 0x01, 0x23, 0x18, 0x43, 0xe5, 0xe7,
++0x00, 0x29, 0x03, 0xd0, 0x98, 0x8a, 0x80, 0x07, 0x80, 0x0f, 0xdf, 0xe7,
++0x6d, 0x23, 0x5b, 0x01, 0xd1, 0x18, 0x8a, 0x88, 0xff, 0x27, 0x01, 0x37,
++0x17, 0x40, 0x0a, 0x49, 0xc9, 0x88, 0x03, 0xd0, 0x4b, 0x0a, 0x01, 0xd3,
++0x03, 0x20, 0xd1, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 0x0b, 0x0a, 0x01, 0xd3,
++0x02, 0x20, 0xcb, 0xe7, 0xd2, 0x09, 0xc9, 0xd3, 0xc9, 0x09, 0xc7, 0xd3,
++0x01, 0x20, 0xc5, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x1c, 0x00, 0x80,
++0xf0, 0xb5, 0xc1, 0xb0, 0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46,
++0x08, 0x60, 0x52, 0x48, 0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03,
++0x48, 0x60, 0x50, 0x48, 0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21,
++0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b,
++0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33,
++0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43,
++0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07,
++0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30,
++0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03,
++0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03,
++0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62,
++0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a,
++0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34,
++0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c,
++0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42,
++0xf5, 0xd1, 0x30, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68,
++0x1b, 0x0c, 0x08, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24,
++0x2b, 0x4b, 0xc0, 0x46, 0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b,
++0x23, 0x4c, 0x51, 0x26, 0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0x3d, 0x6a,
++0xc0, 0x46, 0x75, 0x61, 0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60,
++0x01, 0x25, 0xb5, 0x60, 0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x71, 0x88, 0x42,
++0x21, 0xd0, 0x25, 0x1c, 0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f,
++0x6b, 0x44, 0x34, 0x60, 0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60,
++0x2b, 0x6f, 0x08, 0x33, 0x2b, 0x67, 0x3c, 0x6a, 0xa3, 0x42, 0x02, 0xd3,
++0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44,
++0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03,
++0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b,
++0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfd, 0xf7, 0x74, 0xfa, 0x41, 0xb0,
++0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
++0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80,
++0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00,
++0xc9, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22,
++0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33,
++0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61,
++0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61,
++0x3f, 0x4d, 0xab, 0x6f, 0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23,
++0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f,
++0x9e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61,
++0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23,
++0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43,
++0x3b, 0x61, 0x02, 0x23, 0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43,
++0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00,
++0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
++0x2b, 0x43, 0x3b, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
++0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08,
++0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
++0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
++0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25,
++0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43,
++0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43,
++0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61,
++0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61,
++0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40,
++0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30,
++0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61,
++0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08,
++0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x80, 0x00, 0x14, 0x40, 0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27,
++0x44, 0x4a, 0xc0, 0x46, 0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c,
++0xf9, 0xd3, 0x04, 0x26, 0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61,
++0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61,
++0x3c, 0x4b, 0x9b, 0x6f, 0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c,
++0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f,
++0x9d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
++0x25, 0x43, 0x15, 0x61, 0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23,
++0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61,
++0x2d, 0x4b, 0x9d, 0x6f, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
++0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00,
++0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
++0x15, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
++0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40,
++0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08,
++0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
++0x15, 0x61, 0x02, 0x25, 0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
++0x25, 0x43, 0x15, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c,
++0x33, 0x43, 0x13, 0x61, 0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23,
++0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21,
++0x25, 0x1c, 0xcd, 0x40, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43,
++0x13, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39,
++0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61,
++0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
++0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d,
++0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfd, 0xf7, 0x27, 0xf9, 0x4d, 0x4c,
++0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20,
++0x2a, 0x1c, 0xfd, 0xf7, 0x1d, 0xf9, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28,
++0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1,
++0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02,
++0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28,
++0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21,
++0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26,
++0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe,
++0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 0x00, 0x25, 0x05, 0xe0,
++0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x2b, 0xff, 0x01, 0x35,
++0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 0xb5, 0x42,
++0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 0xff, 0x23, 0xe1, 0x33,
++0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 0xff, 0x23, 0x01, 0x33,
++0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01,
++0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28,
++0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23,
++0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28,
++0x03, 0xd1, 0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23,
++0x19, 0x43, 0x04, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0x09, 0x21, 0x49, 0x02,
++0x00, 0x20, 0xff, 0xf7, 0xf3, 0xfe, 0xe0, 0x68, 0x00, 0x28, 0x0c, 0xd1,
++0x00, 0x21, 0x1b, 0x20, 0xff, 0xf7, 0xec, 0xfe, 0x1a, 0x20, 0xff, 0xf7,
++0x4f, 0xfe, 0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7,
++0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f,
++0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19,
++0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f,
++0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xed, 0xaf, 0x21, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48,
++0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91,
++0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91,
++0x01, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91,
++0x81, 0x69, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91,
++0x01, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91,
++0x81, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90,
++0x01, 0xb0, 0x70, 0x47, 0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0,
++0x68, 0x4d, 0x1b, 0x23, 0xdb, 0x01, 0xef, 0x18, 0xf8, 0x8b, 0x04, 0x22,
++0x02, 0x40, 0x02, 0x92, 0x71, 0x23, 0x5b, 0x01, 0xe8, 0x18, 0x01, 0x88,
++0xc0, 0x46, 0x01, 0x91, 0x40, 0x88, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24,
++0x03, 0xe0, 0x08, 0x2c, 0x01, 0xd3, 0x0f, 0x2c, 0x08, 0xd9, 0x20, 0x1c,
++0xff, 0xf7, 0xe8, 0xfd, 0x61, 0x00, 0x49, 0x19, 0x1b, 0x23, 0xdb, 0x01,
++0xc9, 0x18, 0x88, 0x83, 0x01, 0x34, 0x20, 0x2c, 0xef, 0xd3, 0x58, 0x4c,
++0xe0, 0x69, 0x00, 0x28, 0x15, 0xd0, 0x57, 0x4e, 0x20, 0x25, 0x01, 0x3d,
++0x53, 0x49, 0xe0, 0x69, 0x30, 0x40, 0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18,
++0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x8b, 0x28, 0x1c, 0xff, 0xf7,
++0x65, 0xfe, 0xe0, 0x69, 0xb0, 0x43, 0xe0, 0x61, 0x76, 0x08, 0x00, 0x2d,
++0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 0xc2, 0xfd, 0x48, 0x49, 0xc0, 0x46,
++0xf8, 0x83, 0xf8, 0x8b, 0xc2, 0x08, 0x25, 0xd3, 0xca, 0x68, 0x01, 0x2a,
++0x13, 0xd1, 0x0a, 0x79, 0x00, 0x2a, 0x1f, 0xd1, 0x49, 0x88, 0x00, 0x29,
++0x1c, 0xd1, 0x01, 0x99, 0x43, 0x4a, 0x00, 0x29, 0x05, 0xd0, 0x01, 0x29,
++0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b,
++0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1,
++0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40,
++0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x98, 0x43, 0xf8, 0x83,
++0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 0x1f, 0xd0, 0xb9, 0x8b,
++0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 0xff, 0x23, 0x01, 0x98,
++0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 0x00, 0x98, 0x01, 0x28,
++0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23,
++0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0,
++0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20,
++0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2,
++0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20,
++0x40, 0x02, 0xb8, 0x83, 0xf8, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 0x1d, 0x48,
++0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x51, 0xfc, 0xc2, 0x07,
++0xd2, 0x0f, 0x1a, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 0x2b, 0x43,
++0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65,
++0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 0x03, 0xe0,
++0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 0x61, 0x6a,
++0x81, 0x42, 0x0c, 0xd0, 0x60, 0x62, 0x0e, 0x48, 0x00, 0x2a, 0x03, 0xd0,
++0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x21, 0x33,
++0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
++0x00, 0x00, 0x00, 0x80, 0x28, 0x1c, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40,
++0xa4, 0x2a, 0x00, 0x80, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22,
++0x20, 0x28, 0x0f, 0xd2, 0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18,
++0x37, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0x9f, 0x83, 0x82, 0x40, 0x07, 0x23,
++0x5b, 0x02, 0xc9, 0x18, 0x10, 0x1c, 0xca, 0x69, 0x10, 0x43, 0xc8, 0x61,
++0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69,
++0x0b, 0x49, 0xc9, 0x8b, 0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0,
++0x01, 0x23, 0xdb, 0x02, 0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43,
++0x05, 0xe0, 0x01, 0x23, 0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08,
++0x52, 0x00, 0xca, 0x65, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
++0xe8, 0x1b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0,
++0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20,
++0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab,
++0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91,
++0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfd, 0xf7, 0x79, 0xf8, 0x04, 0xb0,
++0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68,
++0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68,
++0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0,
++0x0a, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x4b, 0x98, 0x42,
++0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x07, 0x4b, 0x98, 0x42,
++0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x00,
++0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80,
++0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24,
++0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68,
++0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21,
++0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 0x02, 0xd0, 0x38, 0x68,
++0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x4b,
++0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x05, 0xd0, 0x0e, 0x4b,
++0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29,
++0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0,
++0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e,
++0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40,
++0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00,
++0x07, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2,
++0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x02, 0xd3,
++0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 0x40, 0x6c, 0x00, 0x04,
++0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 0x40, 0x08, 0x01, 0xd3,
++0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 0x00, 0x00, 0x10, 0x40,
++0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x27,
++0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x72, 0xff, 0x03, 0x1c, 0x19, 0x4a,
++0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 0x1b, 0xd1, 0xcb, 0x04,
++0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 0x43, 0x60, 0x06, 0x68,
++0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 0x43, 0x60, 0x03, 0x68,
++0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 0x05, 0x23, 0x0f, 0x4f,
++0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 0xc0, 0x46, 0x3b, 0x60,
++0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 0x23, 0x60, 0x04, 0x23,
++0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x06, 0x60, 0x27, 0x68,
++0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x22, 0x40,
++0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x28, 0x40,
++0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x28, 0x05, 0xd1,
++0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 0x08, 0x40, 0x22, 0xe0,
++0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c,
++0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x14, 0x48, 0x00, 0x68,
++0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c,
++0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 0x01, 0xa3, 0x1b, 0x5c,
++0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03,
++0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21,
++0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e,
++0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x34, 0x6e, 0x21, 0x40,
++0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40,
++0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x82, 0xb0,
++0x07, 0x1c, 0x01, 0x20, 0x01, 0x90, 0xff, 0xf7, 0xe7, 0xfe, 0x01, 0x28,
++0x13, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x07, 0xd1, 0x00, 0x26,
++0xf6, 0x43, 0x34, 0x1c, 0xa8, 0x2f, 0x02, 0xd1, 0x30, 0x1c, 0x00, 0x96,
++0x35, 0x1c, 0x11, 0x20, 0x00, 0x04, 0x06, 0x62, 0x44, 0x62, 0x85, 0x62,
++0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x08, 0x48, 0xc0, 0x46,
++0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21,
++0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x01, 0x98,
++0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x34, 0x6e, 0x21, 0x40,
++0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
++0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 0x0b, 0xd0, 0x00, 0x23,
++0x21, 0x1c, 0xe2, 0x1d, 0xc1, 0x32, 0x00, 0xe0,
++0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xc8, 0x20, 0xa0, 0x80,
++0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48,
++0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19,
++0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80,
++0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80,
++0xee, 0xff, 0xc0, 0xd0, 0x08, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a,
++0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7a, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23,
++0x0b, 0x72, 0x07, 0x1c, 0x08, 0x7a, 0x43, 0x1c, 0x0b, 0x72, 0x80, 0x18,
++0x90, 0x30, 0x47, 0x72, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80,
++0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20,
++0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68,
++0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40,
++0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7,
++0x91, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42,
++0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7,
++0xc5, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x66, 0x21, 0x40,
++0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c,
++0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89,
++0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c,
++0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c,
++0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e,
++0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 0x79, 0x6c, 0x59, 0x43,
++0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 0x01, 0x32, 0x12, 0x04,
++0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22,
++0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88,
++0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23,
++0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49,
++0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81,
++0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20,
++0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfb, 0xf0, 0x88,
++0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04,
++0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80,
++0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0,
++0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 0xf9, 0x7a, 0x00, 0x29,
++0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 0x79, 0x64, 0x2a, 0xd0,
++0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 0x01, 0x31, 0xe1, 0x80,
++0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 0xdb, 0x03, 0x78, 0x6c,
++0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0,
++0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18,
++0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xfb, 0xe0, 0x6a,
++0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39,
++0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 0x89, 0xfb, 0xb6, 0xe7,
++0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04,
++0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80,
++0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b,
++0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d,
++0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
++0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88,
++0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30,
++0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19,
++0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xfa, 0x71, 0x88,
++0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0,
++0x4d, 0xfb, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35,
++0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25,
++0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc,
++0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
++0xc4, 0x66, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03,
++0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d,
++0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a,
++0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e,
++0x6d, 0xd0, 0xed, 0x6a, 0x5e, 0x1e, 0x73, 0x00, 0x9b, 0x19, 0x5b, 0x01,
++0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0,
++0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x35, 0xad, 0x8b, 0xad, 0x00,
++0x35, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0x70, 0x51, 0x55, 0x89, 0x01, 0x35,
++0x55, 0x81, 0x32, 0x4e, 0xf2, 0x6a, 0xd2, 0x18, 0x90, 0x60, 0xf2, 0x6a,
++0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a,
++0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a,
++0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88,
++0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 0x88, 0x81, 0x24, 0x49,
++0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 0x00, 0x2e, 0x38, 0xd9,
++0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 0x00, 0x2b, 0x2c, 0xd0,
++0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 0xad, 0x6a, 0x58, 0x23,
++0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e,
++0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0xa8, 0x60,
++0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0xe8, 0x63,
++0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 0xed, 0x18, 0x68, 0x64,
++0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 0xeb, 0x18, 0xd8, 0x64,
++0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 0xc0, 0x46, 0x48, 0x81,
++0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 0x03, 0xe0, 0x17, 0x80,
++0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81,
++0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
++0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49,
++0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0,
++0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69,
++0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61,
++0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a,
++0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46,
++0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
++0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 0x4c, 0xd0, 0x08, 0x22,
++0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 0xd9, 0x1d, 0xb9, 0x31,
++0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
++0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
++0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
++0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
++0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
++0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
++0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 0xcc, 0x82, 0x4f, 0x83,
++0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 0x8c, 0x00, 0x05, 0x19,
++0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 0x01, 0x34, 0x65, 0x62,
++0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00,
++0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29,
++0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xac, 0xab, 0x20, 0x40,
++0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
++0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00,
++0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
++0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36,
++0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d,
++0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
++0x44, 0xfb, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c,
++0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x3b, 0xfb, 0x29, 0x1c, 0x23, 0x1c,
++0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x35, 0xfb, 0x39, 0x1c, 0x23, 0x1c,
++0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x2f, 0xfb, 0x00, 0x21, 0x0b, 0x48,
++0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30,
++0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0xac, 0xab, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00,
++0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 0x6c, 0x06, 0x00, 0x80,
++0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30,
++0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29,
++0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1,
++0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23,
++0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33,
++0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43,
++0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68,
++0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0,
++0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46,
++0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c,
++0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00,
++0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35,
++0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2,
++0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32,
++0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 0xbc, 0xe7, 0x00, 0x21,
++0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31,
++0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43,
++0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46,
++0x50, 0x61, 0x09, 0x48, 0xfc, 0xf7, 0xa4, 0xfa, 0xa4, 0xe7, 0x00, 0x00,
++0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01,
++0xac, 0xab, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00,
++0x5c, 0x5c, 0x5c, 0x5c, 0x11, 0x31, 0xff, 0xff, 0xf0, 0xb5, 0x07, 0x1c,
++0x3b, 0x48, 0x3c, 0x4c, 0x08, 0x21, 0x20, 0x60, 0xa1, 0x80, 0x00, 0x20,
++0x20, 0x81, 0xe1, 0x80, 0x60, 0x81, 0x39, 0x48, 0xc0, 0x46, 0xe0, 0x60,
++0x38, 0x48, 0xc0, 0x46, 0x20, 0x61, 0x38, 0x48, 0xc0, 0x46, 0x60, 0x61,
++0x37, 0x48, 0xc0, 0x46, 0xa0, 0x61, 0x37, 0x48, 0xc0, 0x46, 0xe0, 0x61,
++0x36, 0x48, 0xc0, 0x46, 0x20, 0x62, 0x36, 0x48, 0xc0, 0x46, 0x60, 0x62,
++0x35, 0x48, 0xc0, 0x46, 0xa0, 0x62, 0x35, 0x48, 0xc0, 0x46, 0xe0, 0x62,
++0x34, 0x48, 0xc0, 0x46, 0x20, 0x63, 0x34, 0x48, 0xc0, 0x46, 0x60, 0x63,
++0x33, 0x48, 0xc0, 0x46, 0xa0, 0x63, 0x33, 0x48, 0xc0, 0x46, 0xe0, 0x63,
++0x32, 0x48, 0xc0, 0x46, 0x20, 0x64, 0x32, 0x48, 0xc0, 0x46, 0x60, 0x64,
++0x31, 0x48, 0xc0, 0x46, 0xa0, 0x64, 0x31, 0x48, 0xc0, 0x46, 0xe0, 0x64,
++0x30, 0x48, 0xc0, 0x46, 0x20, 0x65, 0x30, 0x49, 0xc8, 0x68, 0x02, 0x04,
++0x89, 0x69, 0x4a, 0x40, 0xe3, 0x1d, 0x79, 0x33, 0x09, 0x04, 0xc9, 0x43,
++0xc0, 0x43, 0x48, 0x40, 0xe1, 0x1d, 0xb9, 0x31, 0xda, 0x63, 0x08, 0x60,
++0x29, 0x4d, 0x21, 0x1c, 0x2b, 0x1c, 0x29, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
++0x3e, 0xfa, 0x28, 0x4a, 0xe1, 0x1d, 0xb5, 0x31, 0x01, 0x20, 0x2b, 0x1c,
++0x0e, 0x1c, 0xfc, 0xf7, 0x36, 0xfa, 0x24, 0x4a, 0x00, 0x20, 0x31, 0x1c,
++0x2b, 0x1c, 0xfc, 0xf7, 0x30, 0xfa, 0xe1, 0x1d, 0x4d, 0x31, 0x2b, 0x1c,
++0x20, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x29, 0xfa, 0xe0, 0x1d, 0x5d, 0x30,
++0x01, 0x68, 0x00, 0x29, 0xfc, 0xd0, 0x60, 0x6d, 0xc0, 0x46, 0x38, 0x65,
++0x20, 0x6e, 0xc0, 0x46, 0x78, 0x65, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x80, 0x00, 0x08, 0x00, 0x8c, 0xb9, 0x20, 0x40, 0x81, 0x81, 0x48, 0xbd,
++0x79, 0x56, 0x23, 0x8c, 0x93, 0x0c, 0x82, 0x95, 0x1d, 0x0e, 0x12, 0xcf,
++0x9b, 0x3b, 0xc0, 0xe9, 0xe6, 0x55, 0x7c, 0x82, 0x99, 0xf6, 0x78, 0x02,
++0xd1, 0xd7, 0x25, 0x73, 0x72, 0x8c, 0x33, 0x10, 0xf7, 0x03, 0xf1, 0x42,
++0x6c, 0x9b, 0x4a, 0xa7, 0x82, 0x8e, 0x23, 0xa9, 0x90, 0xb1, 0x82, 0x8e,
++0xdc, 0x3f, 0xfb, 0x29, 0x00, 0x62, 0x22, 0x45, 0x88, 0x2b, 0xf1, 0x85,
++0x12, 0x61, 0xd1, 0x73, 0x6e, 0xb1, 0x11, 0x16, 0x08, 0x83, 0x20, 0x40,
++0x75, 0x08, 0xff, 0xff, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00,
++0x14, 0x00, 0x03, 0x00, 0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0,
++0x33, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x4c, 0xff, 0x03, 0x48, 0x01, 0x89,
++0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
++0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68,
++0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43,
++0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06,
++0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69,
++0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81,
++0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
++0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18,
++0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08,
++0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b,
++0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b,
++0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c,
++0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88,
++0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 0x03, 0x7a, 0x1b, 0x04,
++0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 0x43, 0x7a, 0xdb, 0x07,
++0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 0x5a, 0x08, 0x05, 0xd3,
++0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 0x15, 0x22, 0x00, 0xe0,
++0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3,
++0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a,
++0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c,
++0xff, 0xf7, 0x78, 0xfd, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23,
++0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31,
++0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
++0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40,
++0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 0x2e, 0x1c, 0x45, 0x6d,
++0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 0xfd, 0x40, 0x2f, 0x1c,
++0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 0x08, 0xd0, 0x23, 0x69,
++0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 0xbe, 0x00, 0xae, 0x59,
++0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 0x11, 0x43, 0x05, 0x4b,
++0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 0x87, 0x83, 0xf0, 0xbc,
++0x70, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78,
++0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43,
++0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c,
++0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x9a, 0xf8,
++0x00, 0xf0, 0xb8, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xc7, 0xfa, 0x3d, 0x70,
++0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x93, 0xf8, 0x00, 0xf0,
++0xa7, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x38, 0x0a, 0xf6, 0xd3,
++0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x82, 0xb0, 0x02, 0x98,
++0x41, 0x02, 0x53, 0x20, 0x00, 0xf0, 0x64, 0xf8, 0x00, 0xf0, 0xa8, 0xfa,
++0xff, 0xf7, 0xe8, 0xff, 0x00, 0x24, 0x00, 0x20, 0x01, 0x90, 0x2e, 0x20,
++0x00, 0x90, 0x00, 0x25, 0x00, 0x27, 0x02, 0x98, 0x01, 0x28, 0x04, 0xd1,
++0x00, 0x98, 0x84, 0x42, 0x01, 0xd3, 0x00, 0x26,
++0x09, 0xe0, 0x01, 0x98, 0x41, 0x1c, 0x01, 0x91, 0x00, 0xf0, 0x60, 0xf8,
++0x00, 0xf0, 0x7e, 0xf9, 0x06, 0x1c, 0x00, 0xf0, 0x8d, 0xfa, 0xf8, 0x00,
++0x86, 0x40, 0x35, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xe6, 0xd3,
++0x03, 0x99, 0x20, 0xc1, 0x03, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42,
++0xdd, 0xd3, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5,
++0x04, 0x1c, 0x0f, 0x1c, 0x01, 0x2c, 0x2a, 0xd0, 0x16, 0x48, 0xc0, 0x6f,
++0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x00, 0x26, 0x20, 0xcf,
++0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x28, 0x1c, 0x00, 0xf0,
++0xdf, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xdc, 0xf9, 0x28, 0x0c, 0x00, 0xf0,
++0xd9, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xd6, 0xf9, 0x00, 0xf0, 0x5c, 0xfa,
++0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 0x83, 0x20, 0x00, 0xf0,
++0x0f, 0xf8, 0x00, 0xf0, 0x53, 0xfa, 0xff, 0xf7, 0x93, 0xff, 0x04, 0x48,
++0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
++0x0f, 0x1c, 0x00, 0xf0, 0x59, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9,
++0x38, 0x0c, 0x00, 0xf0, 0xb3, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xb0, 0xf9,
++0x38, 0x1c, 0x00, 0xf0, 0xad, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x00, 0xb5, 0x01, 0x1c, 0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20,
++0x00, 0xf0, 0xa2, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
++0x3d, 0xfa, 0x57, 0x20, 0x00, 0xf0, 0x9a, 0xf9, 0x08, 0xbc, 0x18, 0x47,
++0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43,
++0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0xf8, 0x6f, 0x20, 0x23,
++0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23,
++0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x87, 0xff,
++0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x04, 0x1c,
++0x0f, 0x1c, 0x18, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x99, 0x43,
++0x01, 0x60, 0x61, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0x00, 0xf0,
++0xe9, 0xf9, 0xff, 0xf7, 0x29, 0xff, 0xf8, 0x1d, 0x05, 0x30, 0x01, 0x2c,
++0x03, 0xd1, 0x22, 0x2f, 0x01, 0xd3, 0x00, 0x27, 0x0f, 0xe0, 0x44, 0x1c,
++0xff, 0xf7, 0xaa, 0xff, 0x00, 0xf0, 0xc8, 0xf8, 0x07, 0x1c, 0x00, 0xf0,
++0xd7, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 0xa2, 0xff, 0x00, 0xf0, 0xc0, 0xf8,
++0x05, 0x1c, 0x00, 0xf0, 0xcf, 0xf9, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68,
++0x19, 0x43, 0x01, 0x60, 0x28, 0x02, 0x38, 0x43, 0xf0, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0,
++0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0x01, 0x2f, 0x2f, 0xd0, 0x79, 0x02,
++0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
++0x53, 0x20, 0xff, 0xf7, 0x6b, 0xff, 0x00, 0xf0, 0xaf, 0xf9, 0xff, 0xf7,
++0xef, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0xd6, 0xfe, 0x6a, 0x46, 0xe8, 0x1d,
++0x05, 0x30, 0x14, 0x54, 0x21, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46,
++0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xba, 0xfe, 0x02, 0xab, 0x18, 0x70,
++0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21,
++0xff, 0xf7, 0xb2, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x38, 0x1c,
++0xff, 0xf7, 0x15, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43,
++0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x01, 0x2f,
++0x01, 0xd1, 0x01, 0x20, 0x36, 0xe0, 0x6b, 0x46, 0x00, 0x20, 0xc4, 0x43,
++0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30,
++0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46,
++0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31,
++0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c,
++0xff, 0xf7, 0x7c, 0xfe, 0x04, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x02, 0xab,
++0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7,
++0x71, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 0x1d, 0x06, 0x2d, 0x0e,
++0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x3e, 0xff,
++0x01, 0x20, 0xac, 0x42, 0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02,
++0x14, 0x4c, 0xe0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
++0x53, 0x20, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7,
++0x73, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0x5a, 0xfe, 0xe0, 0x6f, 0x20, 0x23,
++0x01, 0x68, 0x19, 0x43, 0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24,
++0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x3c, 0xfe,
++0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c,
++0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3,
++0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
++0x81, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1,
++0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x93, 0xe5, 0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
++0x01, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1,
++0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x93, 0xe5, 0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
++0x81, 0x00, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
++0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47,
++0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 0xa0, 0x13, 0xa0, 0xe1,
++0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
++0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1,
++0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
++0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1,
++0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
++0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5,
++0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5,
++0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5,
++0x3c, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
++0x00, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
++0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40,
++0x04, 0x01, 0x18, 0x40, 0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40,
++0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0,
++0x47, 0xf8, 0x78, 0x1c, 0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd,
++0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1d, 0x48,
++0x02, 0x68, 0x1d, 0x49, 0x8b, 0x69, 0xd2, 0x18, 0x02, 0x60, 0x02, 0x66,
++0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 0x02, 0xd2,
++0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 0xd2, 0x18,
++0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 0xc2, 0x69,
++0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 0xd2, 0x18,
++0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 0x02, 0x6b,
++0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18,
++0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63,
++0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 0xc9, 0x6a,
++0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
++0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8,
++0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22,
++0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42,
++0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
++0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22,
++0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0,
++0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c,
++0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60,
++0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00,
++0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
++0xa0, 0x82, 0x20, 0x40, 0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a,
++0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60,
++0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30,
++0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31,
++0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30,
++0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20,
++0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31,
++0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47,
++0x08, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x04, 0x00, 0x80,
++0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x23,
++0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 0x00, 0x22, 0x0a, 0x70,
++0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 0x43, 0x83, 0x7d, 0x21,
++0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
++0x00, 0xf0, 0x8e, 0xfb, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0xb5, 0x22, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48,
++0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x80, 0xfb, 0x01, 0x23, 0xd8, 0x42,
++0x0a, 0xd1, 0x10, 0x48, 0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32,
++0xca, 0x80, 0x81, 0x79, 0x01, 0x31, 0x81, 0x71, 0xfd, 0xf7, 0x70, 0xf9,
++0x0b, 0x48, 0xc0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22,
++0xd2, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x68, 0xfb, 0x08, 0x48, 0xfb, 0xf7,
++0xe1, 0xfc, 0x08, 0x48, 0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x60, 0xfb,
++0x08, 0xbc, 0x18, 0x47, 0x79, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40,
++0x68, 0x0e, 0x00, 0x80, 0xa5, 0x7b, 0x21, 0x40,
++0x95, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20,
++0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21,
++0xfb, 0xf7, 0xc6, 0xfc, 0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68,
++0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c,
++0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46,
++0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64,
++0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa5, 0x55, 0xff, 0xff,
++0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
++0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 0x01, 0x22, 0x12, 0x04,
++0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68,
++0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x21, 0x48,
++0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 0xc0, 0x46, 0x01, 0x64,
++0x1f, 0x48, 0xfb, 0xf7, 0x87, 0xfc, 0x1f, 0x48, 0xc1, 0x6b, 0xff, 0x29,
++0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 0x0f, 0x1c, 0x1c, 0x4c,
++0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43,
++0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x28, 0x61,
++0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfb, 0xf7, 0x6f, 0xfc, 0x16, 0x4a,
++0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 0x39, 0x1c, 0x32, 0x1c,
++0xfb, 0xf7, 0x6e, 0xfc, 0x13, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1,
++0x12, 0x48, 0xfb, 0xf7, 0x5d, 0xfc, 0x10, 0x23, 0x60, 0x69, 0x98, 0x43,
++0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18,
++0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40,
++0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
++0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
++0xb5, 0xb6, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 0x44, 0x80, 0x20, 0x40,
++0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0xfd, 0xf7,
++0x01, 0xff, 0x06, 0x48, 0xfb, 0xf7, 0x32, 0xfc, 0xfd, 0xf7, 0xd6, 0xfe,
++0xfe, 0xf7, 0x04, 0xf8, 0xfe, 0xf7, 0x16, 0xf8, 0xfe, 0xf7, 0x24, 0xf8,
++0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 0x90, 0xb5, 0xfd, 0xf7,
++0x6b, 0xfc, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 0xf8, 0x1d, 0x79, 0x30,
++0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 0xf9, 0x67, 0x31, 0x49,
++0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 0x0c, 0x60, 0x4c, 0x60,
++0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 0x8c, 0x61, 0x04, 0xe0,
++0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 0x08, 0x38, 0x00, 0x68,
++0x60, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23,
++0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68,
++0x99, 0x43, 0x01, 0x60, 0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x4e, 0xfc,
++0x00, 0xf0, 0x5e, 0xf9, 0xfd, 0xf7, 0x73, 0xf8, 0xff, 0xf7, 0x0c, 0xfe,
++0xfd, 0xf7, 0x2e, 0xfe, 0xfd, 0xf7, 0xb6, 0xfd, 0xfd, 0xf7, 0xc2, 0xfe,
++0xfd, 0xf7, 0x54, 0xfd, 0xfd, 0xf7, 0x0a, 0xfd, 0xfd, 0xf7, 0x94, 0xfd,
++0x00, 0xf0, 0x1a, 0xfa, 0xfd, 0xf7, 0x9c, 0xff, 0xfd, 0xf7, 0x0a, 0xff,
++0xfd, 0xf7, 0xd2, 0xfe, 0xfd, 0xf7, 0x3c, 0xfc, 0xfb, 0xf7, 0xdc, 0xfa,
++0xff, 0xf7, 0x9c, 0xff, 0x71, 0x23, 0x5b, 0x01,
++0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 0xf8, 0x18,
++0x04, 0x63, 0xf8, 0x68, 0x01, 0x28, 0x02, 0xd1, 0xa8, 0x20, 0xfe, 0xf7,
++0xb1, 0xfd, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 0x18, 0xfa,
++0x07, 0x48, 0xfb, 0xf7, 0xbd, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
++0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 0x04, 0x01, 0x11, 0x40,
++0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x15, 0x8f, 0x21, 0x40,
++0x00, 0xb5, 0x04, 0x48, 0xfb, 0xf7, 0xaa, 0xfb, 0xfd, 0xf7, 0x5e, 0xff,
++0xfd, 0xf7, 0x24, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x15, 0x99, 0x21, 0x40,
++0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62,
++0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69,
++0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61,
++0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61,
++0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10,
++0x00, 0xb5, 0x02, 0x48, 0xfb, 0xf7, 0x80, 0xfb, 0x08, 0xbc, 0x18, 0x47,
++0xc8, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 0x01, 0x21, 0x09, 0x04,
++0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 0x22, 0x4d, 0x00, 0x29,
++0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a,
++0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 0x1d, 0x48, 0xfb, 0xf7,
++0x65, 0xfb, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 0x01, 0x30, 0x88, 0x61,
++0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 0x00, 0x28, 0x1f, 0xd0,
++0x19, 0x48, 0xfb, 0xf7, 0x57, 0xfb, 0x19, 0x48, 0xfb, 0xf7, 0x54, 0xfb,
++0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x16, 0x48,
++0xfb, 0xf7, 0x4c, 0xfb, 0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40,
++0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1,
++0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x01, 0xe0, 0x28, 0x64,
++0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0x65, 0xfd, 0x0b, 0x48, 0xfb, 0xf7,
++0x35, 0xfb, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40,
++0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
++0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf4, 0x01, 0xff, 0xff,
++0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9f, 0x21, 0x40,
++0x00, 0x20, 0x07, 0x4a, 0x01, 0x21, 0x09, 0x05, 0x50, 0x61, 0xc8, 0x60,
++0xd0, 0x61, 0xc8, 0x61, 0x03, 0x23, 0xdb, 0x04, 0x03, 0x4a, 0x01, 0x21,
++0xd1, 0x63, 0x58, 0x60, 0xfc, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xc0, 0xb0, 0x01, 0x22, 0x00, 0x21,
++0x0a, 0x20, 0xfc, 0xf7, 0xd1, 0xff, 0x07, 0x1c, 0xff, 0x2f, 0x28, 0xd0,
++0x69, 0x46, 0xff, 0x22, 0x38, 0x1c, 0x01, 0x32, 0xfd, 0xf7, 0x54, 0xf9,
++0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x1b, 0xd1, 0x0d, 0x98, 0x00, 0x09,
++0x18, 0xd3, 0x38, 0x1c, 0xfd, 0xf7, 0x8d, 0xf8, 0x0e, 0x49, 0x01, 0x22,
++0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x0d, 0x48, 0x05, 0xd1, 0x0a, 0x68,
++0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x0a, 0x49,
++0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x64,
++0xff, 0xf7, 0xbc, 0xff, 0x38, 0x1c, 0xfd, 0xf7, 0x74, 0xf8, 0x40, 0xb0,
++0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
++0x00, 0x00, 0x10, 0x40, 0x07, 0x80, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
++0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x17, 0x49, 0x01, 0x22, 0x12, 0x04,
++0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68,
++0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x11, 0x49,
++0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x64,
++0x03, 0x20, 0xfe, 0xf7, 0xd3, 0xfc, 0xfb, 0xf7, 0x0d, 0xff, 0x01, 0x23,
++0x18, 0x43, 0xfb, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0x83, 0xfe, 0xff, 0xf7,
++0x9d, 0xff, 0xff, 0xf7, 0x05, 0xfe, 0xff, 0xf7, 0xf5, 0xfe, 0xff, 0xf7,
++0x09, 0xff, 0xff, 0xf7, 0x9b, 0xfd, 0xff, 0xf7, 0x21, 0xff, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
++0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03,
++0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88,
++0x40, 0x04, 0x43, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x04, 0x20, 0xaf, 0x60,
++0x41, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x08, 0x20, 0xc8, 0x23, 0x43, 0x43,
++0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3d, 0x4e, 0xc0, 0x46, 0x31, 0x61,
++0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3a, 0x4e, 0xc0, 0x46, 0xf3, 0x61,
++0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 0x81, 0x42,
++0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 0x41, 0x1e,
++0x32, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 0x02, 0x38,
++0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 0x06, 0xe0,
++0x2c, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 0x88, 0x42,
++0xd2, 0xd9, 0x2a, 0x49, 0x00, 0x20, 0xa3, 0x69, 0x9b, 0x08, 0x07, 0xd0,
++0x28, 0x4b, 0x87, 0x00, 0xcb, 0x51, 0xa7, 0x69, 0xbf, 0x08, 0x01, 0x30,
++0x87, 0x42, 0xf8, 0xd8, 0x22, 0x49, 0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89,
++0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 0x00, 0x20, 0x00, 0x22, 0x00, 0x2c,
++0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30,
++0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc,
++0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 0x00, 0x19, 0x40, 0x01, 0xc7, 0x19,
++0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01,
++0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60,
++0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69,
++0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51,
++0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00,
++0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
++0xb0, 0xbe, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
++0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00,
++0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09,
++0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61,
++0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x81, 0x61, 0x01, 0x20, 0x00, 0x06,
++0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18,
++0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61,
++0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05,
++0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20,
++0x40, 0x03, 0x81, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
++0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8,
++0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23,
++0x9b, 0x01, 0xfb, 0x18, 0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3,
++0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc,
++0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1d, 0x3e, 0xff, 0xff,
++0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47,
++0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b,
++0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c,
++0x59, 0x69, 0x53, 0x01, 0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43,
++0x87, 0x61, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc,
++0x70, 0x47, 0x18, 0x1c, 0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43,
++0x47, 0x61, 0xd7, 0x60, 0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00,
++0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c,
++0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9d, 0x6a,
++0xbd, 0x42, 0x05, 0xd1, 0x1d, 0x6b, 0x95, 0x42, 0x02, 0xd1, 0xdb, 0x6a,
++0x8b, 0x42, 0x1c, 0xd0, 0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20,
++0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9b, 0x6a,
++0x00, 0x2b, 0x09, 0xd1, 0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01,
++0xe3, 0x18, 0x1a, 0x63, 0xd9, 0x62, 0x5a, 0x63, 0x9f, 0x62, 0x02, 0xe0,
++0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20,
++0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
++0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0,
++0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01,
++0xe3, 0x18, 0x9b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19,
++0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61,
++0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62,
++0x53, 0x6b, 0xc0, 0x46, 0x53, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28,
++0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x9a, 0x68, 0x8a, 0x42,
++0x03, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20,
++0xc0, 0x43, 0xfa, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80,
++0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69,
++0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01,
++0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0xc0, 0x46,
++0x43, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61,
++0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x68, 0x0e, 0x00, 0x80,
++0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69,
++0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a,
++0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47,
++0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
++0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0xff, 0xf7, 0xe3, 0xff, 0x01, 0x34,
++0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc,
++0x18, 0x47, 0x00, 0x00,
+ };
+diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
+index 4103c37..3bf9e63 100644
+--- a/drivers/net/typhoon.c
++++ b/drivers/net/typhoon.c
+@@ -86,7 +86,7 @@ static const int multicast_filter_limit
+ #define RESPONSE_RING_SIZE (RESPONSE_ENTRIES * sizeof(struct resp_desc))
+
+ /* The 3XP will preload and remove 64 entries from the free buffer
+- * list, and we need one entry to keep the ring from wrapping, so
++ * list, and we need one entry to keep the ring from wrapping, so
+ * to keep this a power of two, we use 128 entries.
+ */
+ #define RXFREE_ENTRIES 128
+@@ -100,8 +100,8 @@ static const int multicast_filter_limit
+ #define PKT_BUF_SZ 1536
+
+ #define DRV_MODULE_NAME "typhoon"
+-#define DRV_MODULE_VERSION "1.5.7"
+-#define DRV_MODULE_RELDATE "05/01/07"
++#define DRV_MODULE_VERSION "1.5.8"
++#define DRV_MODULE_RELDATE "06/11/09"
+ #define PFX DRV_MODULE_NAME ": "
+ #define ERR_PFX KERN_ERR PFX
+
+@@ -269,7 +269,7 @@ struct rxbuff_ent {
+
+ struct typhoon {
+ /* Tx cache line section */
+- struct transmit_ring txLoRing ____cacheline_aligned;
++ struct transmit_ring txLoRing ____cacheline_aligned;
+ struct pci_dev * tx_pdev;
+ void __iomem *tx_ioaddr;
+ u32 txlo_dma_addr;
+@@ -333,11 +333,7 @@ enum state_values {
+ #define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
+ #define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
+-#define typhoon_synchronize_irq(x) synchronize_irq()
+-#else
+ #define typhoon_synchronize_irq(x) synchronize_irq(x)
+-#endif
+
+ #if defined(NETIF_F_TSO)
+ #define skb_tso_size(x) (skb_shinfo(x)->gso_size)
+@@ -830,7 +826,7 @@ typhoon_start_tx(struct sk_buff *skb, st
+ first_txd->addrHi = (u64)((unsigned long) skb) >> 32;
+ first_txd->processFlags = 0;
+
+- if(skb->ip_summed == CHECKSUM_HW) {
++ if(skb->ip_summed == CHECKSUM_PARTIAL) {
+ /* The 3XP will figure out if this is UDP/TCP */
+ first_txd->processFlags |= TYPHOON_TX_PF_TCP_CHKSUM;
+ first_txd->processFlags |= TYPHOON_TX_PF_UDP_CHKSUM;
+@@ -937,8 +933,6 @@ typhoon_set_rx_mode(struct net_device *d
+
+ filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
+ if(dev->flags & IFF_PROMISC) {
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ filter |= TYPHOON_RX_FILTER_PROMISCOUS;
+ } else if((dev->mc_count > multicast_filter_limit) ||
+ (dev->flags & IFF_ALLMULTI)) {
+@@ -1073,7 +1067,7 @@ typhoon_get_drvinfo(struct net_device *d
+ } else {
+ u32 sleep_ver = xp_resp[0].parm2;
+ snprintf(info->fw_version, 32, "%02x.%03x.%03x",
+- sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
++ sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
+ sleep_ver & 0xfff);
+ }
+ }
+@@ -1243,7 +1237,7 @@ typhoon_get_ringparam(struct net_device
+ ering->tx_pending = TXLO_ENTRIES - 1;
+ }
+
+-static struct ethtool_ops typhoon_ethtool_ops = {
++static const struct ethtool_ops typhoon_ethtool_ops = {
+ .get_settings = typhoon_get_settings,
+ .set_settings = typhoon_set_settings,
+ .get_drvinfo = typhoon_get_drvinfo,
+@@ -1832,7 +1826,7 @@ typhoon_poll(struct net_device *dev, int
+ }
+
+ static irqreturn_t
+-typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
++typhoon_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct typhoon *tp = dev->priv;
+@@ -2154,7 +2148,7 @@ out_sleep:
+ goto out;
+ }
+
+- if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
++ if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
+ printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name);
+
+ out:
+@@ -2602,7 +2596,7 @@ typhoon_init_one(struct pci_dev *pdev, c
+ "(%u:%04x)\n", dev->name, xp_resp[0].numDesc,
+ le32_to_cpu(xp_resp[0].parm2));
+ }
+-
++
+ return 0;
+
+ error_out_reset:
+@@ -2660,7 +2654,7 @@ static struct pci_driver typhoon_driver
+ static int __init
+ typhoon_init(void)
+ {
+- return pci_module_init(&typhoon_driver);
++ return pci_register_driver(&typhoon_driver);
+ }
+
+ static void __exit
+diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
+index 738ee71..2f14a05 100644
+--- a/drivers/net/typhoon.h
++++ b/drivers/net/typhoon.h
+@@ -46,7 +46,7 @@ struct transmit_ring {
+
+ /* The host<->Typhoon ring index structure
+ * This indicates the current positions in the rings
+- *
++ *
+ * All values must be in little endian format for the 3XP
+ *
+ * rxHiCleared: entry we've cleared to in the Hi receive ring
+@@ -131,7 +131,7 @@ struct typhoon_interface {
+ *
+ * A packet is described by a packet descriptor, followed by option descriptors,
+ * if any, then one or more fragment descriptors.
+- *
++ *
+ * Packet descriptor:
+ * flags: Descriptor type
+ * len:i zero, or length of this packet
+diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
+index 47f49ef..b378880 100644
+--- a/drivers/net/ucc_geth.c
++++ b/drivers/net/ucc_geth.c
+@@ -2,14 +2,11 @@
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
+ *
+ * Description:
+ * QE UCC Gigabit Ethernet Driver
+ *
+- * Changelog:
+- * Jul 6, 2006 Li Yang <LeoLi at freescale.com>
+- * - Rearrange code and style fixes
+- *
+ * 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
+@@ -31,9 +28,9 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/fsl_devices.h>
+ #include <linux/ethtool.h>
+-#include <linux/platform_device.h>
+ #include <linux/mii.h>
+
++#include <asm/of_device.h>
+ #include <asm/uaccess.h>
+ #include <asm/irq.h>
+ #include <asm/io.h>
+@@ -47,7 +44,7 @@
+
+ #undef DEBUG
+
+-#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:June 20, 2006"
++#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006"
+ #define DRV_NAME "ucc_geth"
+
+ #define ugeth_printk(level, format, arg...) \
+@@ -70,7 +67,7 @@
+
+ static DEFINE_SPINLOCK(ugeth_lock);
+
+-static ucc_geth_info_t ugeth_primary_info = {
++static struct ucc_geth_info ugeth_primary_info = {
+ .uf_info = {
+ .bd_mem_part = MEM_PART_SYSTEM,
+ .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
+@@ -163,7 +160,7 @@ static ucc_geth_info_t ugeth_primary_inf
+ .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+ };
+
+-static ucc_geth_info_t ugeth_info[8];
++static struct ucc_geth_info ugeth_info[8];
+
+ #ifdef DEBUG
+ static void mem_disp(u8 *addr, int size)
+@@ -219,8 +216,8 @@ static struct list_head *dequeue(struct
+ }
+ }
+
+-static int get_interface_details(enet_interface_e enet_interface,
+- enet_speed_e *speed,
++static int get_interface_details(enum enet_interface enet_interface,
++ enum enet_speed *speed,
+ int *r10m,
+ int *rmm,
+ int *rpm,
+@@ -283,7 +280,7 @@ static int get_interface_details(enet_in
+ return 0;
+ }
+
+-static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd)
++static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
+ {
+ struct sk_buff *skb = NULL;
+
+@@ -303,21 +300,19 @@ static struct sk_buff *get_new_skb(ucc_g
+
+ skb->dev = ugeth->dev;
+
+- BD_BUFFER_SET(bd,
++ out_be32(&((struct qe_bd *)bd)->buf,
+ dma_map_single(NULL,
+ skb->data,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT,
+ DMA_FROM_DEVICE));
+
+- BD_STATUS_AND_LENGTH_SET(bd,
+- (R_E | R_I |
+- (BD_STATUS_AND_LENGTH(bd) & R_W)));
++ out_be32((u32 *)bd, (R_E | R_I | (in_be32((u32 *)bd) & R_W)));
+
+ return skb;
+ }
+
+-static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ)
++static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ)
+ {
+ u8 *bd;
+ u32 bd_status;
+@@ -328,7 +323,7 @@ static int rx_bd_buffer_set(ucc_geth_pri
+ i = 0;
+
+ do {
+- bd_status = BD_STATUS_AND_LENGTH(bd);
++ bd_status = in_be32((u32*)bd);
+ skb = get_new_skb(ugeth, bd);
+
+ if (!skb) /* If can not allocate data buffer,
+@@ -338,19 +333,19 @@ static int rx_bd_buffer_set(ucc_geth_pri
+ ugeth->rx_skbuff[rxQ][i] = skb;
+
+ /* advance the BD pointer */
+- bd += UCC_GETH_SIZE_OF_BD;
++ bd += sizeof(struct qe_bd);
+ i++;
+ } while (!(bd_status & R_W));
+
+ return 0;
+ }
+
+-static int fill_init_enet_entries(ucc_geth_private_t *ugeth,
++static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
+ volatile u32 *p_start,
+ u8 num_entries,
+ u32 thread_size,
+ u32 thread_alignment,
+- qe_risc_allocation_e risc,
++ enum qe_risc_allocation risc,
+ int skip_page_for_first_entry)
+ {
+ u32 init_enet_offset;
+@@ -383,10 +378,10 @@ static int fill_init_enet_entries(ucc_ge
+ return 0;
+ }
+
+-static int return_init_enet_entries(ucc_geth_private_t *ugeth,
++static int return_init_enet_entries(struct ucc_geth_private *ugeth,
+ volatile u32 *p_start,
+ u8 num_entries,
+- qe_risc_allocation_e risc,
++ enum qe_risc_allocation risc,
+ int skip_page_for_first_entry)
+ {
+ u32 init_enet_offset;
+@@ -416,11 +411,11 @@ static int return_init_enet_entries(ucc_
+ }
+
+ #ifdef DEBUG
+-static int dump_init_enet_entries(ucc_geth_private_t *ugeth,
++static int dump_init_enet_entries(struct ucc_geth_private *ugeth,
+ volatile u32 *p_start,
+ u8 num_entries,
+ u32 thread_size,
+- qe_risc_allocation_e risc,
++ enum qe_risc_allocation risc,
+ int skip_page_for_first_entry)
+ {
+ u32 init_enet_offset;
+@@ -456,14 +451,14 @@ static int dump_init_enet_entries(ucc_ge
+ #endif
+
+ #ifdef CONFIG_UGETH_FILTERING
+-static enet_addr_container_t *get_enet_addr_container(void)
++static struct enet_addr_container *get_enet_addr_container(void)
+ {
+- enet_addr_container_t *enet_addr_cont;
++ struct enet_addr_container *enet_addr_cont;
+
+ /* allocate memory */
+- enet_addr_cont = kmalloc(sizeof(enet_addr_container_t), GFP_KERNEL);
++ enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL);
+ if (!enet_addr_cont) {
+- ugeth_err("%s: No memory for enet_addr_container_t object.",
++ ugeth_err("%s: No memory for enet_addr_container object.",
+ __FUNCTION__);
+ return NULL;
+ }
+@@ -472,45 +467,43 @@ static enet_addr_container_t *get_enet_a
+ }
+ #endif /* CONFIG_UGETH_FILTERING */
+
+-static void put_enet_addr_container(enet_addr_container_t *enet_addr_cont)
++static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont)
+ {
+ kfree(enet_addr_cont);
+ }
+
++static int set_mac_addr(__be16 __iomem *reg, u8 *mac)
++{
++ out_be16(®[0], ((u16)mac[5] << 8) | mac[4]);
++ out_be16(®[1], ((u16)mac[3] << 8) | mac[2]);
++ out_be16(®[2], ((u16)mac[1] << 8) | mac[0]);
++}
++
+ #ifdef CONFIG_UGETH_FILTERING
+-static int hw_add_addr_in_paddr(ucc_geth_private_t *ugeth,
+- enet_addr_t *p_enet_addr, u8 paddr_num)
++static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth,
++ u8 *p_enet_addr, u8 paddr_num)
+ {
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+
+ if (!(paddr_num < NUM_OF_PADDRS)) {
+- ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
++ ugeth_warn("%s: Illegal paddr_num.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ /* Ethernet frames are defined in Little Endian mode, */
+ /* therefore to insert the address we reverse the bytes. */
+- out_be16(&p_82xx_addr_filt->paddr[paddr_num].h,
+- (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) |
+- (u16) (*p_enet_addr)[4]));
+- out_be16(&p_82xx_addr_filt->paddr[paddr_num].m,
+- (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) |
+- (u16) (*p_enet_addr)[2]));
+- out_be16(&p_82xx_addr_filt->paddr[paddr_num].l,
+- (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) |
+- (u16) (*p_enet_addr)[0]));
+-
++ set_mac_addr(&p_82xx_addr_filt->paddr[paddr_num].h, p_enet_addr);
+ return 0;
+ }
+ #endif /* CONFIG_UGETH_FILTERING */
+
+-static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num)
++static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
+ {
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+
+ if (!(paddr_num < NUM_OF_PADDRS)) {
+ ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
+@@ -518,7 +511,7 @@ static int hw_clear_addr_in_paddr(ucc_ge
+ }
+
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ /* Writing address ff.ff.ff.ff.ff.ff disables address
+@@ -530,14 +523,14 @@ static int hw_clear_addr_in_paddr(ucc_ge
+ return 0;
+ }
+
+-static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth,
+- enet_addr_t *p_enet_addr)
++static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
++ u8 *p_enet_addr)
+ {
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ u32 cecr_subblock;
+
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ cecr_subblock =
+@@ -546,25 +539,18 @@ static void hw_add_addr_in_hash(ucc_geth
+ /* Ethernet frames are defined in Little Endian mode,
+ therefor to insert */
+ /* the address to the hash (Big Endian mode), we reverse the bytes.*/
+- out_be16(&p_82xx_addr_filt->taddr.h,
+- (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) |
+- (u16) (*p_enet_addr)[4]));
+- out_be16(&p_82xx_addr_filt->taddr.m,
+- (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) |
+- (u16) (*p_enet_addr)[2]));
+- out_be16(&p_82xx_addr_filt->taddr.l,
+- (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) |
+- (u16) (*p_enet_addr)[0]));
++
++ set_mac_addr(&p_82xx_addr_filt->taddr.h, p_enet_addr);
+
+ qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock,
+- (u8) QE_CR_PROTOCOL_ETHERNET, 0);
++ QE_CR_PROTOCOL_ETHERNET, 0);
+ }
+
+ #ifdef CONFIG_UGETH_MAGIC_PACKET
+-static void magic_packet_detection_enable(ucc_geth_private_t *ugeth)
++static void magic_packet_detection_enable(struct ucc_geth_private *ugeth)
+ {
+- ucc_fast_private_t *uccf;
+- ucc_geth_t *ug_regs;
++ struct ucc_fast_private *uccf;
++ struct ucc_geth *ug_regs;
+ u32 maccfg2, uccm;
+
+ uccf = ugeth->uccf;
+@@ -581,10 +567,10 @@ static void magic_packet_detection_enabl
+ out_be32(&ug_regs->maccfg2, maccfg2);
+ }
+
+-static void magic_packet_detection_disable(ucc_geth_private_t *ugeth)
++static void magic_packet_detection_disable(struct ucc_geth_private *ugeth)
+ {
+- ucc_fast_private_t *uccf;
+- ucc_geth_t *ug_regs;
++ struct ucc_fast_private *uccf;
++ struct ucc_geth *ug_regs;
+ u32 maccfg2, uccm;
+
+ uccf = ugeth->uccf;
+@@ -602,26 +588,26 @@ static void magic_packet_detection_disab
+ }
+ #endif /* MAGIC_PACKET */
+
+-static inline int compare_addr(enet_addr_t *addr1, enet_addr_t *addr2)
++static inline int compare_addr(u8 **addr1, u8 **addr2)
+ {
+ return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
+ }
+
+ #ifdef DEBUG
+-static void get_statistics(ucc_geth_private_t *ugeth,
+- ucc_geth_tx_firmware_statistics_t *
++static void get_statistics(struct ucc_geth_private *ugeth,
++ struct ucc_geth_tx_firmware_statistics *
+ tx_firmware_statistics,
+- ucc_geth_rx_firmware_statistics_t *
++ struct ucc_geth_rx_firmware_statistics *
+ rx_firmware_statistics,
+- ucc_geth_hardware_statistics_t *hardware_statistics)
++ struct ucc_geth_hardware_statistics *hardware_statistics)
+ {
+- ucc_fast_t *uf_regs;
+- ucc_geth_t *ug_regs;
+- ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram;
+- ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram;
++ struct ucc_fast *uf_regs;
++ struct ucc_geth *ug_regs;
++ struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram;
++ struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram;
+
+ ug_regs = ugeth->ug_regs;
+- uf_regs = (ucc_fast_t *) ug_regs;
++ uf_regs = (struct ucc_fast *) ug_regs;
+ p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram;
+ p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram;
+
+@@ -727,7 +713,7 @@ static void get_statistics(ucc_geth_priv
+ }
+ }
+
+-static void dump_bds(ucc_geth_private_t *ugeth)
++static void dump_bds(struct ucc_geth_private *ugeth)
+ {
+ int i;
+ int length;
+@@ -736,7 +722,7 @@ static void dump_bds(ucc_geth_private_t
+ if (ugeth->p_tx_bd_ring[i]) {
+ length =
+ (ugeth->ug_info->bdRingLenTx[i] *
+- UCC_GETH_SIZE_OF_BD);
++ sizeof(struct qe_bd));
+ ugeth_info("TX BDs[%d]", i);
+ mem_disp(ugeth->p_tx_bd_ring[i], length);
+ }
+@@ -745,14 +731,14 @@ static void dump_bds(ucc_geth_private_t
+ if (ugeth->p_rx_bd_ring[i]) {
+ length =
+ (ugeth->ug_info->bdRingLenRx[i] *
+- UCC_GETH_SIZE_OF_BD);
++ sizeof(struct qe_bd));
+ ugeth_info("RX BDs[%d]", i);
+ mem_disp(ugeth->p_rx_bd_ring[i], length);
+ }
+ }
+ }
+
+-static void dump_regs(ucc_geth_private_t *ugeth)
++static void dump_regs(struct ucc_geth_private *ugeth)
+ {
+ int i;
+
+@@ -893,7 +879,7 @@ static void dump_regs(ucc_geth_private_t
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_thread_data_tx[i]);
+ mem_disp((u8 *) & ugeth->p_thread_data_tx[i],
+- sizeof(ucc_geth_thread_data_tx_t));
++ sizeof(struct ucc_geth_thread_data_tx));
+ }
+ }
+ if (ugeth->p_thread_data_rx) {
+@@ -927,7 +913,7 @@ static void dump_regs(ucc_geth_private_t
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_thread_data_rx[i]);
+ mem_disp((u8 *) & ugeth->p_thread_data_rx[i],
+- sizeof(ucc_geth_thread_data_rx_t));
++ sizeof(struct ucc_geth_thread_data_rx));
+ }
+ }
+ if (ugeth->p_exf_glbl_param) {
+@@ -1105,7 +1091,7 @@ static void dump_regs(ucc_geth_private_t
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_send_q_mem_reg->sqqd[i]);
+ mem_disp((u8 *) & ugeth->p_send_q_mem_reg->sqqd[i],
+- sizeof(ucc_geth_send_queue_qd_t));
++ sizeof(struct ucc_geth_send_queue_qd));
+ }
+ }
+ if (ugeth->p_scheduler) {
+@@ -1187,7 +1173,7 @@ static void dump_regs(ucc_geth_private_t
+ qe_muram_addr(in_be32
+ (&ugeth->p_rx_bd_qs_tbl[i].
+ bdbaseptr)),
+- sizeof(ucc_geth_rx_prefetched_bds_t));
++ sizeof(struct ucc_geth_rx_prefetched_bds));
+ }
+ }
+ if (ugeth->p_init_enet_param_shadow) {
+@@ -1198,7 +1184,7 @@ static void dump_regs(ucc_geth_private_t
+ mem_disp((u8 *) ugeth->p_init_enet_param_shadow,
+ sizeof(*ugeth->p_init_enet_param_shadow));
+
+- size = sizeof(ucc_geth_thread_rx_pram_t);
++ size = sizeof(struct ucc_geth_thread_rx_pram);
+ if (ugeth->ug_info->rxExtendedFiltering) {
+ size +=
+ THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
+@@ -1216,7 +1202,7 @@ static void dump_regs(ucc_geth_private_t
+ &(ugeth->p_init_enet_param_shadow->
+ txthread[0]),
+ ENET_INIT_PARAM_MAX_ENTRIES_TX,
+- sizeof(ucc_geth_thread_tx_pram_t),
++ sizeof(struct ucc_geth_thread_tx_pram),
+ ugeth->ug_info->riscTx, 0);
+ dump_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+@@ -1578,12 +1564,12 @@ static int init_min_frame_len(u16 min_fr
+ return 0;
+ }
+
+-static int adjust_enet_interface(ucc_geth_private_t *ugeth)
++static int adjust_enet_interface(struct ucc_geth_private *ugeth)
+ {
+- ucc_geth_info_t *ug_info;
+- ucc_geth_t *ug_regs;
+- ucc_fast_t *uf_regs;
+- enet_speed_e speed;
++ struct ucc_geth_info *ug_info;
++ struct ucc_geth *ug_regs;
++ struct ucc_fast *uf_regs;
++ enum enet_speed speed;
+ int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
+ 0, limited_to_full_duplex = 0;
+ u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+@@ -1691,8 +1677,8 @@ static int adjust_enet_interface(ucc_get
+ */
+ static void adjust_link(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
+- ucc_geth_t *ug_regs;
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
++ struct ucc_geth *ug_regs;
+ u32 tempval;
+ struct ugeth_mii_info *mii_info = ugeth->mii_info;
+
+@@ -1722,7 +1708,7 @@ static void adjust_link(struct net_devic
+ if (mii_info->speed != ugeth->oldspeed) {
+ switch (mii_info->speed) {
+ case 1000:
+-#ifdef CONFIG_MPC836x
++#ifdef CONFIG_PPC_MPC836x
+ /* FIXME: This code is for 100Mbs BUG fixing,
+ remove this when it is fixed!!! */
+ if (ugeth->ug_info->enet_interface ==
+@@ -1768,7 +1754,7 @@ remove this when it is fixed!!! */
+ break;
+ case 100:
+ case 10:
+-#ifdef CONFIG_MPC836x
++#ifdef CONFIG_PPC_MPC836x
+ /* FIXME: This code is for 100Mbs BUG fixing,
+ remove this lines when it will be fixed!!! */
+ ugeth->ug_info->enet_interface = ENET_100_RGMII;
+@@ -1827,9 +1813,9 @@ remove this lines when it will be fixed!
+ */
+ static int init_phy(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct phy_info *curphy;
+- ucc_mii_mng_t *mii_regs;
++ struct ucc_mii_mng *mii_regs;
+ struct ugeth_mii_info *mii_info;
+ int err;
+
+@@ -1914,17 +1900,17 @@ static int init_phy(struct net_device *d
+ }
+
+ #ifdef CONFIG_UGETH_TX_ON_DEMOND
+-static int ugeth_transmit_on_demand(ucc_geth_private_t *ugeth)
++static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth)
+ {
+- ucc_fast_transmit_on_demand(ugeth->uccf);
++ struct ucc_fastransmit_on_demand(ugeth->uccf);
+
+ return 0;
+ }
+ #endif
+
+-static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth)
++static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
+ {
+- ucc_fast_private_t *uccf;
++ struct ucc_fast_private *uccf;
+ u32 cecr_subblock;
+ u32 temp;
+
+@@ -1940,7 +1926,7 @@ static int ugeth_graceful_stop_tx(ucc_ge
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
+- (u8) QE_CR_PROTOCOL_ETHERNET, 0);
++ QE_CR_PROTOCOL_ETHERNET, 0);
+
+ /* Wait for command to complete */
+ do {
+@@ -1952,9 +1938,9 @@ static int ugeth_graceful_stop_tx(ucc_ge
+ return 0;
+ }
+
+-static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth)
++static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
+ {
+- ucc_fast_private_t *uccf;
++ struct ucc_fast_private *uccf;
+ u32 cecr_subblock;
+ u8 temp;
+
+@@ -1973,7 +1959,7 @@ static int ugeth_graceful_stop_rx(ucc_ge
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.
+ ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
+- (u8) QE_CR_PROTOCOL_ETHERNET, 0);
++ QE_CR_PROTOCOL_ETHERNET, 0);
+
+ temp = ugeth->p_rx_glbl_pram->rxgstpack;
+ } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
+@@ -1983,41 +1969,40 @@ static int ugeth_graceful_stop_rx(ucc_ge
+ return 0;
+ }
+
+-static int ugeth_restart_tx(ucc_geth_private_t *ugeth)
++static int ugeth_restart_tx(struct ucc_geth_private *ugeth)
+ {
+- ucc_fast_private_t *uccf;
++ struct ucc_fast_private *uccf;
+ u32 cecr_subblock;
+
+ uccf = ugeth->uccf;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+- qe_issue_cmd(QE_RESTART_TX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
+- 0);
++ qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0);
+ uccf->stopped_tx = 0;
+
+ return 0;
+ }
+
+-static int ugeth_restart_rx(ucc_geth_private_t *ugeth)
++static int ugeth_restart_rx(struct ucc_geth_private *ugeth)
+ {
+- ucc_fast_private_t *uccf;
++ struct ucc_fast_private *uccf;
+ u32 cecr_subblock;
+
+ uccf = ugeth->uccf;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+- qe_issue_cmd(QE_RESTART_RX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
++ qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET,
+ 0);
+ uccf->stopped_rx = 0;
+
+ return 0;
+ }
+
+-static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode)
++static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode)
+ {
+- ucc_fast_private_t *uccf;
++ struct ucc_fast_private *uccf;
+ int enabled_tx, enabled_rx;
+
+ uccf = ugeth->uccf;
+@@ -2044,9 +2029,9 @@ static int ugeth_enable(ucc_geth_private
+
+ }
+
+-static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode)
++static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode)
+ {
+- ucc_fast_private_t *uccf;
++ struct ucc_fast_private *uccf;
+
+ uccf = ugeth->uccf;
+
+@@ -2069,7 +2054,7 @@ static int ugeth_disable(ucc_geth_privat
+ return 0;
+ }
+
+-static void ugeth_dump_regs(ucc_geth_private_t *ugeth)
++static void ugeth_dump_regs(struct ucc_geth_private *ugeth)
+ {
+ #ifdef DEBUG
+ ucc_fast_dump_regs(ugeth->uccf);
+@@ -2079,9 +2064,9 @@ static void ugeth_dump_regs(ucc_geth_pri
+ }
+
+ #ifdef CONFIG_UGETH_FILTERING
+-static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t *
++static int ugeth_ext_filtering_serialize_tad(struct ucc_geth_tad_params *
+ p_UccGethTadParams,
+- qe_fltr_tad_t *qe_fltr_tad)
++ struct qe_fltr_tad *qe_fltr_tad)
+ {
+ u16 temp;
+
+@@ -2119,11 +2104,11 @@ static int ugeth_ext_filtering_serialize
+ return 0;
+ }
+
+-static enet_addr_container_t
+- *ugeth_82xx_filtering_get_match_addr_in_hash(ucc_geth_private_t *ugeth,
+- enet_addr_t *p_enet_addr)
++static struct enet_addr_container_t
++ *ugeth_82xx_filtering_get_match_addr_in_hash(struct ucc_geth_private *ugeth,
++ struct enet_addr *p_enet_addr)
+ {
+- enet_addr_container_t *enet_addr_cont;
++ struct enet_addr_container *enet_addr_cont;
+ struct list_head *p_lh;
+ u16 i, num;
+ int32_t j;
+@@ -2144,7 +2129,7 @@ static enet_addr_container_t
+
+ for (i = 0; i < num; i++) {
+ enet_addr_cont =
+- (enet_addr_container_t *)
++ (struct enet_addr_container *)
+ ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
+ for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) {
+ if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j])
+@@ -2157,11 +2142,11 @@ static enet_addr_container_t
+ return NULL;
+ }
+
+-static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t *ugeth,
+- enet_addr_t *p_enet_addr)
++static int ugeth_82xx_filtering_add_addr_in_hash(struct ucc_geth_private *ugeth,
++ struct enet_addr *p_enet_addr)
+ {
+- ucc_geth_enet_address_recognition_location_e location;
+- enet_addr_container_t *enet_addr_cont;
++ enum ucc_geth_enet_address_recognition_location location;
++ struct enet_addr_container *enet_addr_cont;
+ struct list_head *p_lh;
+ u8 i;
+ u32 limit;
+@@ -2196,18 +2181,17 @@ static int ugeth_82xx_filtering_add_addr
+ enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
+ ++(*p_counter);
+
+- hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address));
+-
++ hw_add_addr_in_hash(ugeth, enet_addr_cont->address);
+ return 0;
+ }
+
+-static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth,
+- enet_addr_t *p_enet_addr)
++static int ugeth_82xx_filtering_clear_addr_in_hash(struct ucc_geth_private *ugeth,
++ struct enet_addr *p_enet_addr)
+ {
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+- enet_addr_container_t *enet_addr_cont;
+- ucc_fast_private_t *uccf;
+- comm_dir_e comm_dir;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
++ struct enet_addr_container *enet_addr_cont;
++ struct ucc_fast_private *uccf;
++ enum comm_dir comm_dir;
+ u16 i, num;
+ struct list_head *p_lh;
+ u32 *addr_h, *addr_l;
+@@ -2216,7 +2200,7 @@ static int ugeth_82xx_filtering_clear_ad
+ uccf = ugeth->uccf;
+
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ if (!
+@@ -2256,9 +2240,9 @@ static int ugeth_82xx_filtering_clear_ad
+ num = --(*p_counter);
+ for (i = 0; i < num; i++) {
+ enet_addr_cont =
+- (enet_addr_container_t *)
++ (struct enet_addr_container *)
+ ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
+- hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address));
++ hw_add_addr_in_hash(ugeth, enet_addr_cont->address);
+ enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
+ }
+
+@@ -2269,14 +2253,14 @@ static int ugeth_82xx_filtering_clear_ad
+ }
+ #endif /* CONFIG_UGETH_FILTERING */
+
+-static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t *
++static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private *
+ ugeth,
+- enet_addr_type_e
++ enum enet_addr_type
+ enet_addr_type)
+ {
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+- ucc_fast_private_t *uccf;
+- comm_dir_e comm_dir;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
++ struct ucc_fast_private *uccf;
++ enum comm_dir comm_dir;
+ struct list_head *p_lh;
+ u16 i, num;
+ u32 *addr_h, *addr_l;
+@@ -2285,7 +2269,7 @@ static int ugeth_82xx_filtering_clear_al
+ uccf = ugeth->uccf;
+
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ if (enet_addr_type == ENET_ADDR_TYPE_GROUP) {
+@@ -2331,8 +2315,8 @@ static int ugeth_82xx_filtering_clear_al
+ }
+
+ #ifdef CONFIG_UGETH_FILTERING
+-static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t *ugeth,
+- enet_addr_t *p_enet_addr,
++static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth,
++ struct enet_addr *p_enet_addr,
+ u8 paddr_num)
+ {
+ int i;
+@@ -2352,14 +2336,14 @@ static int ugeth_82xx_filtering_add_addr
+ }
+ #endif /* CONFIG_UGETH_FILTERING */
+
+-static int ugeth_82xx_filtering_clear_addr_in_paddr(ucc_geth_private_t *ugeth,
++static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth,
+ u8 paddr_num)
+ {
+ ugeth->indAddrRegUsed[paddr_num] = 0; /* mark this paddr as not used */
+ return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */
+ }
+
+-static void ucc_geth_memclean(ucc_geth_private_t *ugeth)
++static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
+ {
+ u16 i, j;
+ u8 *bd;
+@@ -2433,8 +2417,8 @@ static void ucc_geth_memclean(ucc_geth_p
+ for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
+ if (ugeth->tx_skbuff[i][j]) {
+ dma_unmap_single(NULL,
+- BD_BUFFER_ARG(bd),
+- (BD_STATUS_AND_LENGTH(bd) &
++ ((qe_bd_t *)bd)->buf,
++ (in_be32((u32 *)bd) &
+ BD_LENGTH_MASK),
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(ugeth->tx_skbuff[i][j]);
+@@ -2460,18 +2444,17 @@ static void ucc_geth_memclean(ucc_geth_p
+ bd = ugeth->p_rx_bd_ring[i];
+ for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
+ if (ugeth->rx_skbuff[i][j]) {
+- dma_unmap_single(NULL, BD_BUFFER(bd),
+- ugeth->ug_info->
+- uf_info.
+- max_rx_buf_length +
+- UCC_GETH_RX_DATA_BUF_ALIGNMENT,
+- DMA_FROM_DEVICE);
+-
+- dev_kfree_skb_any(ugeth->
+- rx_skbuff[i][j]);
++ dma_unmap_single(NULL,
++ ((struct qe_bd *)bd)->buf,
++ ugeth->ug_info->
++ uf_info.max_rx_buf_length +
++ UCC_GETH_RX_DATA_BUF_ALIGNMENT,
++ DMA_FROM_DEVICE);
++ dev_kfree_skb_any(
++ ugeth->rx_skbuff[i][j]);
+ ugeth->rx_skbuff[i][j] = NULL;
+ }
+- bd += UCC_GETH_SIZE_OF_BD;
++ bd += sizeof(struct qe_bd);
+ }
+
+ kfree(ugeth->rx_skbuff[i]);
+@@ -2496,11 +2479,11 @@ static void ucc_geth_memclean(ucc_geth_p
+
+ static void ucc_geth_set_multi(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth;
++ struct ucc_geth_private *ugeth;
+ struct dev_mc_list *dmi;
+- ucc_fast_t *uf_regs;
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+- enet_addr_t tempaddr;
++ struct ucc_fast *uf_regs;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
++ u8 tempaddr[6];
+ u8 *mcptr, *tdptr;
+ int i, j;
+
+@@ -2510,8 +2493,6 @@ static void ucc_geth_set_multi(struct ne
+
+ if (dev->flags & IFF_PROMISC) {
+
+- /* Log any net taps. */
+- printk("%s: Promiscuous mode enabled.\n", dev->name);
+ uf_regs->upsmr |= UPSMR_PRO;
+
+ } else {
+@@ -2519,7 +2500,7 @@ static void ucc_geth_set_multi(struct ne
+ uf_regs->upsmr &= ~UPSMR_PRO;
+
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->
+ p_rx_glbl_pram->addressfiltering;
+
+ if (dev->flags & IFF_ALLMULTI) {
+@@ -2548,23 +2529,22 @@ static void ucc_geth_set_multi(struct ne
+ * copy bytes MSB first from dmi_addr.
+ */
+ mcptr = (u8 *) dmi->dmi_addr + 5;
+- tdptr = (u8 *) & tempaddr;
++ tdptr = (u8 *) tempaddr;
+ for (j = 0; j < 6; j++)
+ *tdptr++ = *mcptr--;
+
+ /* Ask CPM to run CRC and set bit in
+ * filter mask.
+ */
+- hw_add_addr_in_hash(ugeth, &tempaddr);
+-
++ hw_add_addr_in_hash(ugeth, tempaddr);
+ }
+ }
+ }
+ }
+
+-static void ucc_geth_stop(ucc_geth_private_t *ugeth)
++static void ucc_geth_stop(struct ucc_geth_private *ugeth)
+ {
+- ucc_geth_t *ug_regs = ugeth->ug_regs;
++ struct ucc_geth *ug_regs = ugeth->ug_regs;
+ u32 tempval;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+@@ -2607,15 +2587,15 @@ static void ucc_geth_stop(ucc_geth_priva
+ ucc_geth_memclean(ugeth);
+ }
+
+-static int ucc_geth_startup(ucc_geth_private_t *ugeth)
++static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+ {
+- ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+- ucc_geth_init_pram_t *p_init_enet_pram;
+- ucc_fast_private_t *uccf;
+- ucc_geth_info_t *ug_info;
+- ucc_fast_info_t *uf_info;
+- ucc_fast_t *uf_regs;
+- ucc_geth_t *ug_regs;
++ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
++ struct ucc_geth_init_pram *p_init_enet_pram;
++ struct ucc_fast_private *uccf;
++ struct ucc_geth_info *ug_info;
++ struct ucc_fast_info *uf_info;
++ struct ucc_fast *uf_regs;
++ struct ucc_geth *ug_regs;
+ int ret_val = -EINVAL;
+ u32 remoder = UCC_GETH_REMODER_INIT;
+ u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+@@ -2790,7 +2770,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
+
+ uf_regs = uccf->uf_regs;
+- ug_regs = (ucc_geth_t *) (uccf->uf_regs);
++ ug_regs = (struct ucc_geth *) (uccf->uf_regs);
+ ugeth->ug_regs = ug_regs;
+
+ init_default_reg_vals(&uf_regs->upsmr,
+@@ -2871,10 +2851,10 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Allocate in multiple of
+ UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT,
+ according to spec */
+- length = ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD)
++ length = ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd))
+ / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+- if ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) %
++ if ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)) %
+ UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+ if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
+@@ -2906,13 +2886,13 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+ /* Zero unused end of bd ring, according to spec */
+ memset(ugeth->p_tx_bd_ring[j] +
+- ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD, 0,
+- length - ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD);
++ ug_info->bdRingLenTx[j] * sizeof(struct qe_bd), 0,
++ length - ug_info->bdRingLenTx[j] * sizeof(struct qe_bd));
+ }
+
+ /* Allocate Rx bds */
+ for (j = 0; j < ug_info->numQueuesRx; j++) {
+- length = ug_info->bdRingLenRx[j] * UCC_GETH_SIZE_OF_BD;
++ length = ug_info->bdRingLenRx[j] * sizeof(struct qe_bd);
+ if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
+ u32 align = 4;
+ if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
+@@ -2962,12 +2942,15 @@ static int ucc_geth_startup(ucc_geth_pri
+ ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0;
+ bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j];
+ for (i = 0; i < ug_info->bdRingLenTx[j]; i++) {
+- BD_BUFFER_CLEAR(bd);
+- BD_STATUS_AND_LENGTH_SET(bd, 0);
+- bd += UCC_GETH_SIZE_OF_BD;
++ /* clear bd buffer */
++ out_be32(&((struct qe_bd *)bd)->buf, 0);
++ /* set bd status and length */
++ out_be32((u32 *)bd, 0);
++ bd += sizeof(struct qe_bd);
+ }
+- bd -= UCC_GETH_SIZE_OF_BD;
+- BD_STATUS_AND_LENGTH_SET(bd, T_W);/* for last BD set Wrap bit */
++ bd -= sizeof(struct qe_bd);
++ /* set bd status and length */
++ out_be32((u32 *)bd, T_W); /* for last BD set Wrap bit */
+ }
+
+ /* Init Rx bds */
+@@ -2991,12 +2974,15 @@ static int ucc_geth_startup(ucc_geth_pri
+ ugeth->skb_currx[j] = 0;
+ bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j];
+ for (i = 0; i < ug_info->bdRingLenRx[j]; i++) {
+- BD_STATUS_AND_LENGTH_SET(bd, R_I);
+- BD_BUFFER_CLEAR(bd);
+- bd += UCC_GETH_SIZE_OF_BD;
++ /* set bd status and length */
++ out_be32((u32 *)bd, R_I);
++ /* clear bd buffer */
++ out_be32(&((struct qe_bd *)bd)->buf, 0);
++ bd += sizeof(struct qe_bd);
+ }
+- bd -= UCC_GETH_SIZE_OF_BD;
+- BD_STATUS_AND_LENGTH_SET(bd, R_W);/* for last BD set Wrap bit */
++ bd -= sizeof(struct qe_bd);
++ /* set bd status and length */
++ out_be32((u32 *)bd, R_W); /* for last BD set Wrap bit */
+ }
+
+ /*
+@@ -3005,7 +2991,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Tx global PRAM */
+ /* Allocate global tx parameter RAM page */
+ ugeth->tx_glbl_pram_offset =
+- qe_muram_alloc(sizeof(ucc_geth_tx_global_pram_t),
++ qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram),
+ UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) {
+ ugeth_err
+@@ -3015,10 +3001,10 @@ static int ucc_geth_startup(ucc_geth_pri
+ return -ENOMEM;
+ }
+ ugeth->p_tx_glbl_pram =
+- (ucc_geth_tx_global_pram_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_tx_global_pram *) qe_muram_addr(ugeth->
+ tx_glbl_pram_offset);
+ /* Zero out p_tx_glbl_pram */
+- memset(ugeth->p_tx_glbl_pram, 0, sizeof(ucc_geth_tx_global_pram_t));
++ memset(ugeth->p_tx_glbl_pram, 0, sizeof(struct ucc_geth_tx_global_pram));
+
+ /* Fill global PRAM */
+
+@@ -3026,7 +3012,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Size varies with number of Tx threads */
+ ugeth->thread_dat_tx_offset =
+ qe_muram_alloc(numThreadsTxNumerical *
+- sizeof(ucc_geth_thread_data_tx_t) +
++ sizeof(struct ucc_geth_thread_data_tx) +
+ 32 * (numThreadsTxNumerical == 1),
+ UCC_GETH_THREAD_DATA_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) {
+@@ -3038,7 +3024,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_thread_data_tx =
+- (ucc_geth_thread_data_tx_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_thread_data_tx *) qe_muram_addr(ugeth->
+ thread_dat_tx_offset);
+ out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset);
+
+@@ -3055,7 +3041,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Size varies with number of Tx queues */
+ ugeth->send_q_mem_reg_offset =
+ qe_muram_alloc(ug_info->numQueuesTx *
+- sizeof(ucc_geth_send_queue_qd_t),
++ sizeof(struct ucc_geth_send_queue_qd),
+ UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) {
+ ugeth_err
+@@ -3066,7 +3052,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_send_q_mem_reg =
+- (ucc_geth_send_queue_mem_region_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_send_queue_mem_region *) qe_muram_addr(ugeth->
+ send_q_mem_reg_offset);
+ out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset);
+
+@@ -3075,7 +3061,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ for (i = 0; i < ug_info->numQueuesTx; i++) {
+ endOfRing =
+ ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] -
+- 1) * UCC_GETH_SIZE_OF_BD;
++ 1) * sizeof(struct qe_bd);
+ if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) {
+ out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
+ (u32) virt_to_phys(ugeth->p_tx_bd_ring[i]));
+@@ -3098,7 +3084,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ if (ug_info->numQueuesTx > 1) {
+ /* scheduler exists only if more than 1 tx queue */
+ ugeth->scheduler_offset =
+- qe_muram_alloc(sizeof(ucc_geth_scheduler_t),
++ qe_muram_alloc(sizeof(struct ucc_geth_scheduler),
+ UCC_GETH_SCHEDULER_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->scheduler_offset)) {
+ ugeth_err
+@@ -3109,12 +3095,12 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_scheduler =
+- (ucc_geth_scheduler_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_scheduler *) qe_muram_addr(ugeth->
+ scheduler_offset);
+ out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer,
+ ugeth->scheduler_offset);
+ /* Zero out p_scheduler */
+- memset(ugeth->p_scheduler, 0, sizeof(ucc_geth_scheduler_t));
++ memset(ugeth->p_scheduler, 0, sizeof(struct ucc_geth_scheduler));
+
+ /* Set values in scheduler */
+ out_be32(&ugeth->p_scheduler->mblinterval,
+@@ -3146,7 +3132,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+ ugeth->tx_fw_statistics_pram_offset =
+ qe_muram_alloc(sizeof
+- (ucc_geth_tx_firmware_statistics_pram_t),
++ (struct ucc_geth_tx_firmware_statistics_pram),
+ UCC_GETH_TX_STATISTICS_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) {
+ ugeth_err
+@@ -3156,11 +3142,11 @@ static int ucc_geth_startup(ucc_geth_pri
+ return -ENOMEM;
+ }
+ ugeth->p_tx_fw_statistics_pram =
+- (ucc_geth_tx_firmware_statistics_pram_t *)
++ (struct ucc_geth_tx_firmware_statistics_pram *)
+ qe_muram_addr(ugeth->tx_fw_statistics_pram_offset);
+ /* Zero out p_tx_fw_statistics_pram */
+ memset(ugeth->p_tx_fw_statistics_pram,
+- 0, sizeof(ucc_geth_tx_firmware_statistics_pram_t));
++ 0, sizeof(struct ucc_geth_tx_firmware_statistics_pram));
+ }
+
+ /* temoder */
+@@ -3185,7 +3171,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Rx global PRAM */
+ /* Allocate global rx parameter RAM page */
+ ugeth->rx_glbl_pram_offset =
+- qe_muram_alloc(sizeof(ucc_geth_rx_global_pram_t),
++ qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram),
+ UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) {
+ ugeth_err
+@@ -3195,10 +3181,10 @@ static int ucc_geth_startup(ucc_geth_pri
+ return -ENOMEM;
+ }
+ ugeth->p_rx_glbl_pram =
+- (ucc_geth_rx_global_pram_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_rx_global_pram *) qe_muram_addr(ugeth->
+ rx_glbl_pram_offset);
+ /* Zero out p_rx_glbl_pram */
+- memset(ugeth->p_rx_glbl_pram, 0, sizeof(ucc_geth_rx_global_pram_t));
++ memset(ugeth->p_rx_glbl_pram, 0, sizeof(struct ucc_geth_rx_global_pram));
+
+ /* Fill global PRAM */
+
+@@ -3206,7 +3192,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Size varies with number of Rx threads */
+ ugeth->thread_dat_rx_offset =
+ qe_muram_alloc(numThreadsRxNumerical *
+- sizeof(ucc_geth_thread_data_rx_t),
++ sizeof(struct ucc_geth_thread_data_rx),
+ UCC_GETH_THREAD_DATA_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) {
+ ugeth_err
+@@ -3217,7 +3203,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_thread_data_rx =
+- (ucc_geth_thread_data_rx_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_thread_data_rx *) qe_muram_addr(ugeth->
+ thread_dat_rx_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset);
+
+@@ -3229,7 +3215,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
+ ugeth->rx_fw_statistics_pram_offset =
+ qe_muram_alloc(sizeof
+- (ucc_geth_rx_firmware_statistics_pram_t),
++ (struct ucc_geth_rx_firmware_statistics_pram),
+ UCC_GETH_RX_STATISTICS_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) {
+ ugeth_err
+@@ -3239,11 +3225,11 @@ static int ucc_geth_startup(ucc_geth_pri
+ return -ENOMEM;
+ }
+ ugeth->p_rx_fw_statistics_pram =
+- (ucc_geth_rx_firmware_statistics_pram_t *)
++ (struct ucc_geth_rx_firmware_statistics_pram *)
+ qe_muram_addr(ugeth->rx_fw_statistics_pram_offset);
+ /* Zero out p_rx_fw_statistics_pram */
+ memset(ugeth->p_rx_fw_statistics_pram, 0,
+- sizeof(ucc_geth_rx_firmware_statistics_pram_t));
++ sizeof(struct ucc_geth_rx_firmware_statistics_pram));
+ }
+
+ /* intCoalescingPtr */
+@@ -3251,7 +3237,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Size varies with number of Rx queues */
+ ugeth->rx_irq_coalescing_tbl_offset =
+ qe_muram_alloc(ug_info->numQueuesRx *
+- sizeof(ucc_geth_rx_interrupt_coalescing_entry_t),
++ sizeof(struct ucc_geth_rx_interrupt_coalescing_entry),
+ UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
+ ugeth_err
+@@ -3262,7 +3248,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_rx_irq_coalescing_tbl =
+- (ucc_geth_rx_interrupt_coalescing_table_t *)
++ (struct ucc_geth_rx_interrupt_coalescing_table *)
+ qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr,
+ ugeth->rx_irq_coalescing_tbl_offset);
+@@ -3302,7 +3288,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ l3qt = 0;
+ for (i = 0; i < 8; i++)
+ l3qt |= (ug_info->l3qt[j + i] << (28 - 4 * i));
+- out_be32(&ugeth->p_rx_glbl_pram->l3qt[j], l3qt);
++ out_be32(&ugeth->p_rx_glbl_pram->l3qt[j/8], l3qt);
+ }
+
+ /* vlantype */
+@@ -3318,8 +3304,8 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Size varies with number of Rx queues */
+ ugeth->rx_bd_qs_tbl_offset =
+ qe_muram_alloc(ug_info->numQueuesRx *
+- (sizeof(ucc_geth_rx_bd_queues_entry_t) +
+- sizeof(ucc_geth_rx_prefetched_bds_t)),
++ (sizeof(struct ucc_geth_rx_bd_queues_entry) +
++ sizeof(struct ucc_geth_rx_prefetched_bds)),
+ UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) {
+ ugeth_err
+@@ -3330,14 +3316,14 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_rx_bd_qs_tbl =
+- (ucc_geth_rx_bd_queues_entry_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_rx_bd_queues_entry *) qe_muram_addr(ugeth->
+ rx_bd_qs_tbl_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->rbdqptr, ugeth->rx_bd_qs_tbl_offset);
+ /* Zero out p_rx_bd_qs_tbl */
+ memset(ugeth->p_rx_bd_qs_tbl,
+ 0,
+- ug_info->numQueuesRx * (sizeof(ucc_geth_rx_bd_queues_entry_t) +
+- sizeof(ucc_geth_rx_prefetched_bds_t)));
++ ug_info->numQueuesRx * (sizeof(struct ucc_geth_rx_bd_queues_entry) +
++ sizeof(struct ucc_geth_rx_prefetched_bds)));
+
+ /* Setup the table */
+ /* Assume BD rings are already established */
+@@ -3408,7 +3394,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Allocate memory for extended filtering Mode Global
+ Parameters */
+ ugeth->exf_glbl_param_offset =
+- qe_muram_alloc(sizeof(ucc_geth_exf_global_pram_t),
++ qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram),
+ UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) {
+ ugeth_err
+@@ -3419,7 +3405,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ ugeth->p_exf_glbl_param =
+- (ucc_geth_exf_global_pram_t *) qe_muram_addr(ugeth->
++ (struct ucc_geth_exf_global_pram *) qe_muram_addr(ugeth->
+ exf_glbl_param_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam,
+ ugeth->exf_glbl_param_offset);
+@@ -3441,7 +3427,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ INIT_LIST_HEAD(&ugeth->ind_hash_q);
+ }
+ p_82xx_addr_filt =
+- (ucc_geth_82xx_address_filtering_pram_t *) ugeth->
++ (struct ucc_geth_82xx_address_filtering_pram *) ugeth->
+ p_rx_glbl_pram->addressfiltering;
+
+ ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth,
+@@ -3464,7 +3450,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ * allocated resources can be released when the channel is freed.
+ */
+ if (!(ugeth->p_init_enet_param_shadow =
+- (ucc_geth_init_pram_t *) kmalloc(sizeof(ucc_geth_init_pram_t),
++ (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram),
+ GFP_KERNEL))) {
+ ugeth_err
+ ("%s: Can not allocate memory for"
+@@ -3474,7 +3460,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+ /* Zero out *p_init_enet_param_shadow */
+ memset((char *)ugeth->p_init_enet_param_shadow,
+- 0, sizeof(ucc_geth_init_pram_t));
++ 0, sizeof(struct ucc_geth_init_pram));
+
+ /* Fill shadow InitEnet command parameter structure */
+
+@@ -3508,7 +3494,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+ ugeth->p_init_enet_param_shadow->largestexternallookupkeysize =
+ ug_info->largestexternallookupkeysize;
+- size = sizeof(ucc_geth_thread_rx_pram_t);
++ size = sizeof(struct ucc_geth_thread_rx_pram);
+ if (ug_info->rxExtendedFiltering) {
+ size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
+ if (ug_info->largestexternallookupkeysize ==
+@@ -3539,7 +3525,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ fill_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+ txthread[0]), numThreadsTxNumerical,
+- sizeof(ucc_geth_thread_tx_pram_t),
++ sizeof(struct ucc_geth_thread_tx_pram),
+ UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
+ ug_info->riscTx, 0)) != 0) {
+ ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+@@ -3559,7 +3545,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ }
+
+ /* Allocate InitEnet command parameter structure */
+- init_enet_pram_offset = qe_muram_alloc(sizeof(ucc_geth_init_pram_t), 4);
++ init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4);
+ if (IS_MURAM_ERR(init_enet_pram_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
+@@ -3568,7 +3554,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ return -ENOMEM;
+ }
+ p_init_enet_pram =
+- (ucc_geth_init_pram_t *) qe_muram_addr(init_enet_pram_offset);
++ (struct ucc_geth_init_pram *) qe_muram_addr(init_enet_pram_offset);
+
+ /* Copy shadow InitEnet command parameter structure into PRAM */
+ p_init_enet_pram->resinit1 = ugeth->p_init_enet_param_shadow->resinit1;
+@@ -3593,7 +3579,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* Issue QE command */
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+- qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
++ qe_issue_cmd(command, cecr_subblock, QE_CR_PROTOCOL_ETHERNET,
+ init_enet_pram_offset);
+
+ /* Free InitEnet command parameter */
+@@ -3605,7 +3591,7 @@ static int ucc_geth_startup(ucc_geth_pri
+ /* returns a net_device_stats structure pointer */
+ static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ return &(ugeth->stats);
+ }
+@@ -3616,7 +3602,7 @@ static struct net_device_stats *ucc_geth
+ * starting over will fix the problem. */
+ static void ucc_geth_timeout(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+@@ -3636,7 +3622,7 @@ static void ucc_geth_timeout(struct net_
+ /* It is pointed to by the dev->hard_start_xmit function pointer */
+ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ u8 *bd; /* BD pointer */
+ u32 bd_status;
+ u8 txQ = 0;
+@@ -3649,7 +3635,7 @@ static int ucc_geth_start_xmit(struct sk
+
+ /* Start from the next BD that should be filled */
+ bd = ugeth->txBd[txQ];
+- bd_status = BD_STATUS_AND_LENGTH(bd);
++ bd_status = in_be32((u32 *)bd);
+ /* Save the skb pointer so we can free it later */
+ ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb;
+
+@@ -3659,20 +3645,21 @@ static int ucc_geth_start_xmit(struct sk
+ 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
+
+ /* set up the buffer descriptor */
+- BD_BUFFER_SET(bd,
++ out_be32(&((struct qe_bd *)bd)->buf,
+ dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE));
+
+- //printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data);
++ /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
+
+ bd_status = (bd_status & T_W) | T_R | T_I | T_L | skb->len;
+
+- BD_STATUS_AND_LENGTH_SET(bd, bd_status);
++ /* set bd status and length */
++ out_be32((u32 *)bd, bd_status);
+
+ dev->trans_start = jiffies;
+
+ /* Move to next BD in the ring */
+ if (!(bd_status & T_W))
+- ugeth->txBd[txQ] = bd + UCC_GETH_SIZE_OF_BD;
++ ugeth->txBd[txQ] = bd + sizeof(struct qe_bd);
+ else
+ ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ];
+
+@@ -3697,7 +3684,7 @@ static int ucc_geth_start_xmit(struct sk
+ return 0;
+ }
+
+-static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit)
++static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
+ {
+ struct sk_buff *skb;
+ u8 *bd;
+@@ -3711,11 +3698,11 @@ static int ucc_geth_rx(ucc_geth_private_
+ /* collect received buffers */
+ bd = ugeth->rxBd[rxQ];
+
+- bd_status = BD_STATUS_AND_LENGTH(bd);
++ bd_status = in_be32((u32 *)bd);
+
+ /* while there are received buffers and BD is full (~R_E) */
+ while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) {
+- bdBuffer = (u8 *) BD_BUFFER(bd);
++ bdBuffer = (u8 *) in_be32(&((struct qe_bd *)bd)->buf);
+ length = (u16) ((bd_status & BD_LENGTH_MASK) - 4);
+ skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]];
+
+@@ -3770,9 +3757,9 @@ static int ucc_geth_rx(ucc_geth_private_
+ if (bd_status & R_W)
+ bd = ugeth->p_rx_bd_ring[rxQ];
+ else
+- bd += UCC_GETH_SIZE_OF_BD;
++ bd += sizeof(struct qe_bd);
+
+- bd_status = BD_STATUS_AND_LENGTH(bd);
++ bd_status = in_be32((u32 *)bd);
+ }
+
+ ugeth->rxBd[rxQ] = bd;
+@@ -3783,12 +3770,12 @@ static int ucc_geth_rx(ucc_geth_private_
+ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
+ {
+ /* Start from the next BD that should be filled */
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ u8 *bd; /* BD pointer */
+ u32 bd_status;
+
+ bd = ugeth->confBd[txQ];
+- bd_status = BD_STATUS_AND_LENGTH(bd);
++ bd_status = in_be32((u32 *)bd);
+
+ /* Normal processing. */
+ while ((bd_status & T_R) == 0) {
+@@ -3815,7 +3802,7 @@ static int ucc_geth_tx(struct net_device
+
+ /* Advance the confirmation BD pointer */
+ if (!(bd_status & T_W))
+- ugeth->confBd[txQ] += UCC_GETH_SIZE_OF_BD;
++ ugeth->confBd[txQ] += sizeof(struct qe_bd);
+ else
+ ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ];
+ }
+@@ -3825,7 +3812,7 @@ static int ucc_geth_tx(struct net_device
+ #ifdef CONFIG_UGETH_NAPI
+ static int ucc_geth_poll(struct net_device *dev, int *budget)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ int howmany;
+ int rx_work_limit = *budget;
+ u8 rxQ = 0;
+@@ -3846,13 +3833,12 @@ static int ucc_geth_poll(struct net_devi
+ }
+ #endif /* CONFIG_UGETH_NAPI */
+
+-static irqreturn_t ucc_geth_irq_handler(int irq, void *info,
+- struct pt_regs *regs)
++static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
+ {
+ struct net_device *dev = (struct net_device *)info;
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
+- ucc_fast_private_t *uccf;
+- ucc_geth_info_t *ug_info;
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
++ struct ucc_fast_private *uccf;
++ struct ucc_geth_info *ug_info;
+ register u32 ucce = 0;
+ register u32 bit_mask = UCCE_RXBF_SINGLE_MASK;
+ register u32 tx_mask = UCCE_TXBF_SINGLE_MASK;
+@@ -3912,10 +3898,10 @@ static irqreturn_t ucc_geth_irq_handler(
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t phy_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+@@ -3935,8 +3921,8 @@ static irqreturn_t phy_interrupt(int irq
+ static void ugeth_phy_change(void *data)
+ {
+ struct net_device *dev = (struct net_device *)data;
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
+- ucc_geth_t *ug_regs;
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
++ struct ucc_geth *ug_regs;
+ int result = 0;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+@@ -3966,7 +3952,7 @@ static void ugeth_phy_change(void *data)
+ static void ugeth_phy_timer(unsigned long data)
+ {
+ struct net_device *dev = (struct net_device *)data;
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ schedule_work(&ugeth->tq);
+
+@@ -3982,7 +3968,7 @@ static void ugeth_phy_timer(unsigned lon
+ static void ugeth_phy_startup_timer(unsigned long data)
+ {
+ struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
+- ucc_geth_private_t *ugeth = netdev_priv(mii_info->dev);
++ struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
+ static int secondary = UGETH_AN_TIMEOUT;
+ int result;
+
+@@ -4037,7 +4023,7 @@ static void ugeth_phy_startup_timer(unsi
+ /* Returns 0 for success. */
+ static int ucc_geth_open(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ int err;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+@@ -4114,7 +4100,7 @@ static int ucc_geth_open(struct net_devi
+ /* Stops the kernel queue, and halts the controller */
+ static int ucc_geth_close(struct net_device *dev)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+@@ -4131,45 +4117,55 @@ static int ucc_geth_close(struct net_dev
+ return 0;
+ }
+
+-struct ethtool_ops ucc_geth_ethtool_ops = {
+- .get_settings = NULL,
+- .get_drvinfo = NULL,
+- .get_regs_len = NULL,
+- .get_regs = NULL,
+- .get_link = NULL,
+- .get_coalesce = NULL,
+- .set_coalesce = NULL,
+- .get_ringparam = NULL,
+- .set_ringparam = NULL,
+- .get_strings = NULL,
+- .get_stats_count = NULL,
+- .get_ethtool_stats = NULL,
+-};
++const struct ethtool_ops ucc_geth_ethtool_ops = { };
+
+-static int ucc_geth_probe(struct device *device)
++static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
+ {
+- struct platform_device *pdev = to_platform_device(device);
+- struct ucc_geth_platform_data *ugeth_pdata;
++ struct device *device = &ofdev->dev;
++ struct device_node *np = ofdev->node;
+ struct net_device *dev = NULL;
+ struct ucc_geth_private *ugeth = NULL;
+ struct ucc_geth_info *ug_info;
+- int err;
++ struct resource res;
++ struct device_node *phy;
++ int err, ucc_num, phy_interface;
+ static int mii_mng_configured = 0;
++ const phandle *ph;
++ const unsigned int *prop;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+- ugeth_pdata = (struct ucc_geth_platform_data *)pdev->dev.platform_data;
++ prop = get_property(np, "device-id", NULL);
++ ucc_num = *prop - 1;
++ if ((ucc_num < 0) || (ucc_num > 7))
++ return -ENODEV;
++
++ ug_info = &ugeth_info[ucc_num];
++ ug_info->uf_info.ucc_num = ucc_num;
++ prop = get_property(np, "rx-clock", NULL);
++ ug_info->uf_info.rx_clock = *prop;
++ prop = get_property(np, "tx-clock", NULL);
++ ug_info->uf_info.tx_clock = *prop;
++ err = of_address_to_resource(np, 0, &res);
++ if (err)
++ return -EINVAL;
++
++ ug_info->uf_info.regs = res.start;
++ ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
++
++ ph = get_property(np, "phy-handle", NULL);
++ phy = of_find_node_by_phandle(*ph);
+
+- ug_info = &ugeth_info[pdev->id];
+- ug_info->uf_info.ucc_num = pdev->id;
+- ug_info->uf_info.rx_clock = ugeth_pdata->rx_clock;
+- ug_info->uf_info.tx_clock = ugeth_pdata->tx_clock;
+- ug_info->uf_info.regs = ugeth_pdata->phy_reg_addr;
+- ug_info->uf_info.irq = platform_get_irq(pdev, 0);
+- ug_info->phy_address = ugeth_pdata->phy_id;
+- ug_info->enet_interface = ugeth_pdata->phy_interface;
+- ug_info->board_flags = ugeth_pdata->board_flags;
+- ug_info->phy_interrupt = ugeth_pdata->phy_interrupt;
++ if (phy == NULL)
++ return -ENODEV;
++
++ prop = get_property(phy, "reg", NULL);
++ ug_info->phy_address = *prop;
++ prop = get_property(phy, "interface", NULL);
++ ug_info->enet_interface = *prop;
++ ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0);
++ ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)?
++ 0:FSL_UGETH_BRD_HAS_PHY_INTR;
+
+ printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
+ ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
+@@ -4177,12 +4173,44 @@ static int ucc_geth_probe(struct device
+
+ if (ug_info == NULL) {
+ ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__,
+- pdev->id);
++ ucc_num);
+ return -ENODEV;
+ }
+
++ /* FIXME: Work around for early chip rev. */
++ /* There's a bug in initial chip rev(s) in the RGMII ac */
++ /* timing. */
++ /* The following compensates by writing to the reserved */
++ /* QE Port Output Hold Registers (CPOH1?). */
++ prop = get_property(phy, "interface", NULL);
++ phy_interface = *prop;
++ if ((phy_interface == ENET_1000_RGMII) ||
++ (phy_interface == ENET_100_RGMII) ||
++ (phy_interface == ENET_10_RGMII)) {
++ struct device_node *soc;
++ phys_addr_t immrbase = -1;
++ u32 *tmp_reg;
++ u32 tmp_val;
++
++ soc = of_find_node_by_type(NULL, "soc");
++ if (soc) {
++ unsigned int size;
++ const void *prop = get_property(soc, "reg", &size);
++ immrbase = of_translate_address(soc, prop);
++ of_node_put(soc);
++ };
++
++ tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4);
++ tmp_val = in_be32(tmp_reg);
++ if (ucc_num == 1)
++ out_be32(tmp_reg, tmp_val | 0x00003000);
++ else if (ucc_num == 2)
++ out_be32(tmp_reg, tmp_val | 0x0c000000);
++ iounmap(tmp_reg);
++ }
++
+ if (!mii_mng_configured) {
+- ucc_set_qe_mux_mii_mng(ug_info->uf_info.ucc_num);
++ ucc_set_qe_mux_mii_mng(ucc_num);
+ mii_mng_configured = 1;
+ }
+
+@@ -4229,13 +4257,14 @@ static int ucc_geth_probe(struct device
+
+ ugeth->ug_info = ug_info;
+ ugeth->dev = dev;
+- memcpy(dev->dev_addr, ugeth_pdata->mac_addr, 6);
++ memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6);
+
+ return 0;
+ }
+
+-static int ucc_geth_remove(struct device *device)
++static int ucc_geth_remove(struct of_device* ofdev)
+ {
++ struct device *device = &ofdev->dev;
+ struct net_device *dev = dev_get_drvdata(device);
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+@@ -4246,28 +4275,38 @@ static int ucc_geth_remove(struct device
+ return 0;
+ }
+
+-/* Structure for a device driver */
+-static struct device_driver ucc_geth_driver = {
+- .name = DRV_NAME,
+- .bus = &platform_bus_type,
+- .probe = ucc_geth_probe,
+- .remove = ucc_geth_remove,
++static struct of_device_id ucc_geth_match[] = {
++ {
++ .type = "network",
++ .compatible = "ucc_geth",
++ },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, ucc_geth_match);
++
++static struct of_platform_driver ucc_geth_driver = {
++ .name = DRV_NAME,
++ .match_table = ucc_geth_match,
++ .probe = ucc_geth_probe,
++ .remove = ucc_geth_remove,
+ };
+
+ static int __init ucc_geth_init(void)
+ {
+ int i;
++
+ printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
+ for (i = 0; i < 8; i++)
+ memcpy(&(ugeth_info[i]), &ugeth_primary_info,
+ sizeof(ugeth_primary_info));
+
+- return driver_register(&ucc_geth_driver);
++ return of_register_driver(&ucc_geth_driver);
+ }
+
+ static void __exit ucc_geth_exit(void)
+ {
+- driver_unregister(&ucc_geth_driver);
++ of_unregister_driver(&ucc_geth_driver);
+ }
+
+ module_init(ucc_geth_init);
+diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
+index 005965f..a665612 100644
+--- a/drivers/net/ucc_geth.h
++++ b/drivers/net/ucc_geth.h
+@@ -36,24 +36,24 @@
+ #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9
+ #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8
+
+-typedef struct ucc_mii_mng {
++struct ucc_mii_mng {
+ u32 miimcfg; /* MII management configuration reg */
+ u32 miimcom; /* MII management command reg */
+ u32 miimadd; /* MII management address reg */
+ u32 miimcon; /* MII management control reg */
+ u32 miimstat; /* MII management status reg */
+ u32 miimind; /* MII management indication reg */
+-} __attribute__ ((packed)) ucc_mii_mng_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth {
+- ucc_fast_t uccf;
++struct ucc_geth {
++ struct ucc_fast uccf;
+
+ u32 maccfg1; /* mac configuration reg. 1 */
+ u32 maccfg2; /* mac configuration reg. 2 */
+ u32 ipgifg; /* interframe gap reg. */
+ u32 hafdup; /* half-duplex reg. */
+ u8 res1[0x10];
+- ucc_mii_mng_t miimng; /* MII management structure */
++ struct ucc_mii_mng miimng; /* MII management structure */
+ u32 ifctl; /* interface control reg */
+ u32 ifstat; /* interface statux reg */
+ u32 macstnaddr1; /* mac station address part 1 reg */
+@@ -111,7 +111,7 @@ typedef struct ucc_geth {
+ u32 scar; /* Statistics carry register */
+ u32 scam; /* Statistics caryy mask register */
+ u8 res5[0x200 - 0x1c4];
+-} __attribute__ ((packed)) ucc_geth_t;
++} __attribute__ ((packed));
+
+ /* UCC GETH TEMODR Register */
+ #define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics
+@@ -508,39 +508,39 @@ typedef struct ucc_geth {
+ /* UCC GETH UDSR (Data Synchronization Register) */
+ #define UDSR_MAGIC 0x067E
+
+-typedef struct ucc_geth_thread_data_tx {
++struct ucc_geth_thread_data_tx {
+ u8 res0[104];
+-} __attribute__ ((packed)) ucc_geth_thread_data_tx_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_thread_data_rx {
++struct ucc_geth_thread_data_rx {
+ u8 res0[40];
+-} __attribute__ ((packed)) ucc_geth_thread_data_rx_t;
++} __attribute__ ((packed));
+
+ /* Send Queue Queue-Descriptor */
+-typedef struct ucc_geth_send_queue_qd {
++struct ucc_geth_send_queue_qd {
+ u32 bd_ring_base; /* pointer to BD ring base address */
+ u8 res0[0x8];
+ u32 last_bd_completed_address;/* initialize to last entry in BD ring */
+ u8 res1[0x30];
+-} __attribute__ ((packed)) ucc_geth_send_queue_qd_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_send_queue_mem_region {
+- ucc_geth_send_queue_qd_t sqqd[NUM_TX_QUEUES];
+-} __attribute__ ((packed)) ucc_geth_send_queue_mem_region_t;
++struct ucc_geth_send_queue_mem_region {
++ struct ucc_geth_send_queue_qd sqqd[NUM_TX_QUEUES];
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_thread_tx_pram {
++struct ucc_geth_thread_tx_pram {
+ u8 res0[64];
+-} __attribute__ ((packed)) ucc_geth_thread_tx_pram_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_thread_rx_pram {
++struct ucc_geth_thread_rx_pram {
+ u8 res0[128];
+-} __attribute__ ((packed)) ucc_geth_thread_rx_pram_t;
++} __attribute__ ((packed));
+
+ #define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING 64
+ #define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8 64
+ #define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16 96
+
+-typedef struct ucc_geth_scheduler {
++struct ucc_geth_scheduler {
+ u16 cpucount0; /* CPU packet counter */
+ u16 cpucount1; /* CPU packet counter */
+ u16 cecount0; /* QE packet counter */
+@@ -574,9 +574,9 @@ typedef struct ucc_geth_scheduler {
+ /**< weight factor for queues */
+ u32 minw; /* temporary variable handled by QE */
+ u8 res1[0x70 - 0x64];
+-} __attribute__ ((packed)) ucc_geth_scheduler_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_tx_firmware_statistics_pram {
++struct ucc_geth_tx_firmware_statistics_pram {
+ u32 sicoltx; /* single collision */
+ u32 mulcoltx; /* multiple collision */
+ u32 latecoltxfr; /* late collision */
+@@ -596,9 +596,9 @@ typedef struct ucc_geth_tx_firmware_stat
+ and 1518 octets */
+ u32 txpktsjumbo; /* total packets (including bad) between 1024
+ and MAXLength octets */
+-} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_pram_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_rx_firmware_statistics_pram {
++struct ucc_geth_rx_firmware_statistics_pram {
+ u32 frrxfcser; /* frames with crc error */
+ u32 fraligner; /* frames with alignment error */
+ u32 inrangelenrxer; /* in range length error */
+@@ -630,33 +630,33 @@ typedef struct ucc_geth_rx_firmware_stat
+ replaced */
+ u32 insertvlan; /* total frames that had their VLAN tag
+ inserted */
+-} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_pram_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_rx_interrupt_coalescing_entry {
++struct ucc_geth_rx_interrupt_coalescing_entry {
+ u32 interruptcoalescingmaxvalue; /* interrupt coalescing max
+ value */
+ u32 interruptcoalescingcounter; /* interrupt coalescing counter,
+ initialize to
+ interruptcoalescingmaxvalue */
+-} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_entry_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_rx_interrupt_coalescing_table {
+- ucc_geth_rx_interrupt_coalescing_entry_t coalescingentry[NUM_RX_QUEUES];
++struct ucc_geth_rx_interrupt_coalescing_table {
++ struct ucc_geth_rx_interrupt_coalescing_entry coalescingentry[NUM_RX_QUEUES];
+ /**< interrupt coalescing entry */
+-} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_table_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_rx_prefetched_bds {
+- qe_bd_t bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */
+-} __attribute__ ((packed)) ucc_geth_rx_prefetched_bds_t;
++struct ucc_geth_rx_prefetched_bds {
++ struct qe_bd bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_rx_bd_queues_entry {
++struct ucc_geth_rx_bd_queues_entry {
+ u32 bdbaseptr; /* BD base pointer */
+ u32 bdptr; /* BD pointer */
+ u32 externalbdbaseptr; /* external BD base pointer */
+ u32 externalbdptr; /* external BD pointer */
+-} __attribute__ ((packed)) ucc_geth_rx_bd_queues_entry_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_tx_global_pram {
++struct ucc_geth_tx_global_pram {
+ u16 temoder;
+ u8 res0[0x38 - 0x02];
+ u32 sqptr; /* a base pointer to send queue memory region */
+@@ -670,15 +670,15 @@ typedef struct ucc_geth_tx_global_pram {
+ u32 tqptr; /* a base pointer to the Tx Queues Memory
+ Region */
+ u8 res2[0x80 - 0x74];
+-} __attribute__ ((packed)) ucc_geth_tx_global_pram_t;
++} __attribute__ ((packed));
+
+ /* structure representing Extended Filtering Global Parameters in PRAM */
+-typedef struct ucc_geth_exf_global_pram {
++struct ucc_geth_exf_global_pram {
+ u32 l2pcdptr; /* individual address filter, high */
+ u8 res0[0x10 - 0x04];
+-} __attribute__ ((packed)) ucc_geth_exf_global_pram_t;
++} __attribute__ ((packed));
+
+-typedef struct ucc_geth_rx_global_pram {
++struct ucc_geth_rx_global_pram {
+ u32 remoder; /* ethernet mode reg. */
+ u32 rqptr; /* base pointer to the Rx Queues Memory Region*/
+ u32 res0[0x1];
+@@ -710,12 +710,12 @@ typedef struct ucc_geth_rx_global_pram {
+ u32 exfGlobalParam; /* base address for extended filtering global
+ parameters */
+ u8 res6[0x100 - 0xC4]; /* Initialize to zero */
+-} __attribute__ ((packed)) ucc_geth_rx_global_pram_t;
++} __attribute__ ((packed));
+
+ #define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01
+
+ /* structure representing InitEnet command */
+-typedef struct ucc_geth_init_pram {
++struct ucc_geth_init_pram {
+ u8 resinit1;
+ u8 resinit2;
+ u8 resinit3;
+@@ -729,7 +729,7 @@ typedef struct ucc_geth_init_pram {
+ u32 txglobal; /* tx global */
+ u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */
+ u8 res3[0x1];
+-} __attribute__ ((packed)) ucc_geth_init_pram_t;
++} __attribute__ ((packed));
+
+ #define ENET_INIT_PARAM_RGF_SHIFT (32 - 4)
+ #define ENET_INIT_PARAM_TGF_SHIFT (32 - 8)
+@@ -746,27 +746,27 @@ typedef struct ucc_geth_init_pram {
+ #define ENET_INIT_PARAM_MAGIC_RES_INIT5 0x0400
+
+ /* structure representing 82xx Address Filtering Enet Address in PRAM */
+-typedef struct ucc_geth_82xx_enet_address {
++struct ucc_geth_82xx_enet_address {
+ u8 res1[0x2];
+ u16 h; /* address (MSB) */
+ u16 m; /* address */
+ u16 l; /* address (LSB) */
+-} __attribute__ ((packed)) ucc_geth_82xx_enet_address_t;
++} __attribute__ ((packed));
+
+ /* structure representing 82xx Address Filtering PRAM */
+-typedef struct ucc_geth_82xx_address_filtering_pram {
++struct ucc_geth_82xx_address_filtering_pram {
+ u32 iaddr_h; /* individual address filter, high */
+ u32 iaddr_l; /* individual address filter, low */
+ u32 gaddr_h; /* group address filter, high */
+ u32 gaddr_l; /* group address filter, low */
+- ucc_geth_82xx_enet_address_t taddr;
+- ucc_geth_82xx_enet_address_t paddr[NUM_OF_PADDRS];
++ struct ucc_geth_82xx_enet_address taddr;
++ struct ucc_geth_82xx_enet_address paddr[NUM_OF_PADDRS];
+ u8 res0[0x40 - 0x38];
+-} __attribute__ ((packed)) ucc_geth_82xx_address_filtering_pram_t;
++} __attribute__ ((packed));
+
+ /* GETH Tx firmware statistics structure, used when calling
+ UCC_GETH_GetStatistics. */
+-typedef struct ucc_geth_tx_firmware_statistics {
++struct ucc_geth_tx_firmware_statistics {
+ u32 sicoltx; /* single collision */
+ u32 mulcoltx; /* multiple collision */
+ u32 latecoltxfr; /* late collision */
+@@ -786,11 +786,11 @@ typedef struct ucc_geth_tx_firmware_stat
+ and 1518 octets */
+ u32 txpktsjumbo; /* total packets (including bad) between 1024
+ and MAXLength octets */
+-} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_t;
++} __attribute__ ((packed));
+
+ /* GETH Rx firmware statistics structure, used when calling
+ UCC_GETH_GetStatistics. */
+-typedef struct ucc_geth_rx_firmware_statistics {
++struct ucc_geth_rx_firmware_statistics {
+ u32 frrxfcser; /* frames with crc error */
+ u32 fraligner; /* frames with alignment error */
+ u32 inrangelenrxer; /* in range length error */
+@@ -822,11 +822,11 @@ typedef struct ucc_geth_rx_firmware_stat
+ replaced */
+ u32 insertvlan; /* total frames that had their VLAN tag
+ inserted */
+-} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_t;
++} __attribute__ ((packed));
+
+ /* GETH hardware statistics structure, used when calling
+ UCC_GETH_GetStatistics. */
+-typedef struct ucc_geth_hardware_statistics {
++struct ucc_geth_hardware_statistics {
+ u32 tx64; /* Total number of frames (including bad
+ frames) transmitted that were exactly of the
+ minimal length (64 for un tagged, 68 for
+@@ -871,7 +871,7 @@ typedef struct ucc_geth_hardware_statist
+ u32 rbca; /* Total number of frames received succesfully
+ that had destination address equal to the
+ broadcast address */
+-} __attribute__ ((packed)) ucc_geth_hardware_statistics_t;
++} __attribute__ ((packed));
+
+ /* UCC GETH Tx errors returned via TxConf callback */
+ #define TX_ERRORS_DEF 0x0200
+@@ -1013,21 +1013,21 @@ typedef struct ucc_geth_hardware_statist
+ (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
+
+ /* Ethernet speed */
+-typedef enum enet_speed {
++enum enet_speed {
+ ENET_SPEED_10BT, /* 10 Base T */
+ ENET_SPEED_100BT, /* 100 Base T */
+ ENET_SPEED_1000BT /* 1000 Base T */
+-} enet_speed_e;
++};
+
+ /* Ethernet Address Type. */
+-typedef enum enet_addr_type {
++enum enet_addr_type {
+ ENET_ADDR_TYPE_INDIVIDUAL,
+ ENET_ADDR_TYPE_GROUP,
+ ENET_ADDR_TYPE_BROADCAST
+-} enet_addr_type_e;
++};
+
+ /* TBI / MII Set Register */
+-typedef enum enet_tbi_mii_reg {
++enum enet_tbi_mii_reg {
+ ENET_TBI_MII_CR = 0x00, /* Control (CR ) */
+ ENET_TBI_MII_SR = 0x01, /* Status (SR ) */
+ ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */
+@@ -1040,10 +1040,10 @@ typedef enum enet_tbi_mii_reg {
+ ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */
+ ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */
+ ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */
+-} enet_tbi_mii_reg_e;
++};
+
+ /* UCC GETH 82xx Ethernet Address Recognition Location */
+-typedef enum ucc_geth_enet_address_recognition_location {
++enum ucc_geth_enet_address_recognition_location {
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
+ address */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_FIRST, /* additional
+@@ -1065,10 +1065,10 @@ typedef enum ucc_geth_enet_address_recog
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH, /* group hash */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH /* individual
+ hash */
+-} ucc_geth_enet_address_recognition_location_e;
++};
+
+ /* UCC GETH vlan operation tagged */
+-typedef enum ucc_geth_vlan_operation_tagged {
++enum ucc_geth_vlan_operation_tagged {
+ UCC_GETH_VLAN_OPERATION_TAGGED_NOP = 0x0, /* Tagged - nop */
+ UCC_GETH_VLAN_OPERATION_TAGGED_REPLACE_VID_PORTION_OF_Q_TAG
+ = 0x1, /* Tagged - replace vid portion of q tag */
+@@ -1076,18 +1076,18 @@ typedef enum ucc_geth_vlan_operation_tag
+ = 0x2, /* Tagged - if vid0 replace vid with default value */
+ UCC_GETH_VLAN_OPERATION_TAGGED_EXTRACT_Q_TAG_FROM_FRAME
+ = 0x3 /* Tagged - extract q tag from frame */
+-} ucc_geth_vlan_operation_tagged_e;
++};
+
+ /* UCC GETH vlan operation non-tagged */
+-typedef enum ucc_geth_vlan_operation_non_tagged {
++enum ucc_geth_vlan_operation_non_tagged {
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP = 0x0, /* Non tagged - nop */
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT = 0x1 /* Non tagged -
+ q tag insert
+ */
+-} ucc_geth_vlan_operation_non_tagged_e;
++};
+
+ /* UCC GETH Rx Quality of Service Mode */
+-typedef enum ucc_geth_qos_mode {
++enum ucc_geth_qos_mode {
+ UCC_GETH_QOS_MODE_DEFAULT = 0x0, /* default queue */
+ UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L2_CRITERIA = 0x1, /* queue
+ determined
+@@ -1097,11 +1097,11 @@ typedef enum ucc_geth_qos_mode {
+ determined
+ by L3
+ criteria */
+-} ucc_geth_qos_mode_e;
++};
+
+ /* UCC GETH Statistics Gathering Mode - These are bit flags, 'or' them together
+ for combined functionality */
+-typedef enum ucc_geth_statistics_gathering_mode {
++enum ucc_geth_statistics_gathering_mode {
+ UCC_GETH_STATISTICS_GATHERING_MODE_NONE = 0x00000000, /* No
+ statistics
+ gathering */
+@@ -1122,10 +1122,10 @@ typedef enum ucc_geth_statistics_gatheri
+ statistics
+ gathering
+ */
+-} ucc_geth_statistics_gathering_mode_e;
++};
+
+ /* UCC GETH Pad and CRC Mode - Note, Padding without CRC is not possible */
+-typedef enum ucc_geth_maccfg2_pad_and_crc_mode {
++enum ucc_geth_maccfg2_pad_and_crc_mode {
+ UCC_GETH_PAD_AND_CRC_MODE_NONE
+ = MACCFG2_PAD_AND_CRC_MODE_NONE, /* Neither Padding
+ short frames
+@@ -1135,61 +1135,59 @@ typedef enum ucc_geth_maccfg2_pad_and_cr
+ CRC only */
+ UCC_GETH_PAD_AND_CRC_MODE_PAD_AND_CRC =
+ MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC
+-} ucc_geth_maccfg2_pad_and_crc_mode_e;
++};
+
+ /* UCC GETH upsmr Flow Control Mode */
+-typedef enum ucc_geth_flow_control_mode {
++enum ucc_geth_flow_control_mode {
+ UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE = 0x00000000, /* No automatic
+ flow control
+ */
+ UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_PAUSE_WHEN_EMERGENCY
+ = 0x00004000 /* Send pause frame when RxFIFO reaches its
+ emergency threshold */
+-} ucc_geth_flow_control_mode_e;
++};
+
+ /* UCC GETH number of threads */
+-typedef enum ucc_geth_num_of_threads {
++enum ucc_geth_num_of_threads {
+ UCC_GETH_NUM_OF_THREADS_1 = 0x1, /* 1 */
+ UCC_GETH_NUM_OF_THREADS_2 = 0x2, /* 2 */
+ UCC_GETH_NUM_OF_THREADS_4 = 0x0, /* 4 */
+ UCC_GETH_NUM_OF_THREADS_6 = 0x3, /* 6 */
+ UCC_GETH_NUM_OF_THREADS_8 = 0x4 /* 8 */
+-} ucc_geth_num_of_threads_e;
++};
+
+ /* UCC GETH number of station addresses */
+-typedef enum ucc_geth_num_of_station_addresses {
++enum ucc_geth_num_of_station_addresses {
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_1, /* 1 */
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_5 /* 5 */
+-} ucc_geth_num_of_station_addresses_e;
+-
+-typedef u8 enet_addr_t[ENET_NUM_OCTETS_PER_ADDRESS];
++};
+
+ /* UCC GETH 82xx Ethernet Address Container */
+-typedef struct enet_addr_container {
+- enet_addr_t address; /* ethernet address */
+- ucc_geth_enet_address_recognition_location_e location; /* location in
++struct enet_addr_container {
++ u8 address[ENET_NUM_OCTETS_PER_ADDRESS]; /* ethernet address */
++ enum ucc_geth_enet_address_recognition_location location; /* location in
+ 82xx address
+ recognition
+ hardware */
+ struct list_head node;
+-} enet_addr_container_t;
++};
+
+-#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr, enet_addr_container_t, node)
++#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr, struct enet_addr_container, node)
+
+ /* UCC GETH Termination Action Descriptor (TAD) structure. */
+-typedef struct ucc_geth_tad_params {
++struct ucc_geth_tad_params {
+ int rx_non_dynamic_extended_features_mode;
+ int reject_frame;
+- ucc_geth_vlan_operation_tagged_e vtag_op;
+- ucc_geth_vlan_operation_non_tagged_e vnontag_op;
+- ucc_geth_qos_mode_e rqos;
++ enum ucc_geth_vlan_operation_tagged vtag_op;
++ enum ucc_geth_vlan_operation_non_tagged vnontag_op;
++ enum ucc_geth_qos_mode rqos;
+ u8 vpri;
+ u16 vid;
+-} ucc_geth_tad_params_t;
++};
+
+ /* GETH protocol initialization structure */
+-typedef struct ucc_geth_info {
+- ucc_fast_info_t uf_info;
++struct ucc_geth_info {
++ struct ucc_fast_info uf_info;
+ u8 numQueuesTx;
+ u8 numQueuesRx;
+ int ipCheckSumCheck;
+@@ -1251,51 +1249,51 @@ typedef struct ucc_geth_info {
+ u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
+ u16 bdRingLenTx[NUM_TX_QUEUES];
+ u16 bdRingLenRx[NUM_RX_QUEUES];
+- enet_interface_e enet_interface;
+- ucc_geth_num_of_station_addresses_e numStationAddresses;
+- qe_fltr_largest_external_tbl_lookup_key_size_e
++ enum enet_interface enet_interface;
++ enum ucc_geth_num_of_station_addresses numStationAddresses;
++ enum qe_fltr_largest_external_tbl_lookup_key_size
+ largestexternallookupkeysize;
+- ucc_geth_statistics_gathering_mode_e statisticsMode;
+- ucc_geth_vlan_operation_tagged_e vlanOperationTagged;
+- ucc_geth_vlan_operation_non_tagged_e vlanOperationNonTagged;
+- ucc_geth_qos_mode_e rxQoSMode;
+- ucc_geth_flow_control_mode_e aufc;
+- ucc_geth_maccfg2_pad_and_crc_mode_e padAndCrc;
+- ucc_geth_num_of_threads_e numThreadsTx;
+- ucc_geth_num_of_threads_e numThreadsRx;
+- qe_risc_allocation_e riscTx;
+- qe_risc_allocation_e riscRx;
+-} ucc_geth_info_t;
++ enum ucc_geth_statistics_gathering_mode statisticsMode;
++ enum ucc_geth_vlan_operation_tagged vlanOperationTagged;
++ enum ucc_geth_vlan_operation_non_tagged vlanOperationNonTagged;
++ enum ucc_geth_qos_mode rxQoSMode;
++ enum ucc_geth_flow_control_mode aufc;
++ enum ucc_geth_maccfg2_pad_and_crc_mode padAndCrc;
++ enum ucc_geth_num_of_threads numThreadsTx;
++ enum ucc_geth_num_of_threads numThreadsRx;
++ enum qe_risc_allocation riscTx;
++ enum qe_risc_allocation riscRx;
++};
+
+ /* structure representing UCC GETH */
+-typedef struct ucc_geth_private {
+- ucc_geth_info_t *ug_info;
+- ucc_fast_private_t *uccf;
++struct ucc_geth_private {
++ struct ucc_geth_info *ug_info;
++ struct ucc_fast_private *uccf;
+ struct net_device *dev;
+ struct net_device_stats stats; /* linux network statistics */
+- ucc_geth_t *ug_regs;
+- ucc_geth_init_pram_t *p_init_enet_param_shadow;
+- ucc_geth_exf_global_pram_t *p_exf_glbl_param;
++ struct ucc_geth *ug_regs;
++ struct ucc_geth_init_pram *p_init_enet_param_shadow;
++ struct ucc_geth_exf_global_pram *p_exf_glbl_param;
+ u32 exf_glbl_param_offset;
+- ucc_geth_rx_global_pram_t *p_rx_glbl_pram;
++ struct ucc_geth_rx_global_pram *p_rx_glbl_pram;
+ u32 rx_glbl_pram_offset;
+- ucc_geth_tx_global_pram_t *p_tx_glbl_pram;
++ struct ucc_geth_tx_global_pram *p_tx_glbl_pram;
+ u32 tx_glbl_pram_offset;
+- ucc_geth_send_queue_mem_region_t *p_send_q_mem_reg;
++ struct ucc_geth_send_queue_mem_region *p_send_q_mem_reg;
+ u32 send_q_mem_reg_offset;
+- ucc_geth_thread_data_tx_t *p_thread_data_tx;
++ struct ucc_geth_thread_data_tx *p_thread_data_tx;
+ u32 thread_dat_tx_offset;
+- ucc_geth_thread_data_rx_t *p_thread_data_rx;
++ struct ucc_geth_thread_data_rx *p_thread_data_rx;
+ u32 thread_dat_rx_offset;
+- ucc_geth_scheduler_t *p_scheduler;
++ struct ucc_geth_scheduler *p_scheduler;
+ u32 scheduler_offset;
+- ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram;
++ struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram;
+ u32 tx_fw_statistics_pram_offset;
+- ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram;
++ struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram;
+ u32 rx_fw_statistics_pram_offset;
+- ucc_geth_rx_interrupt_coalescing_table_t *p_rx_irq_coalescing_tbl;
++ struct ucc_geth_rx_interrupt_coalescing_table *p_rx_irq_coalescing_tbl;
+ u32 rx_irq_coalescing_tbl_offset;
+- ucc_geth_rx_bd_queues_entry_t *p_rx_bd_qs_tbl;
++ struct ucc_geth_rx_bd_queues_entry *p_rx_bd_qs_tbl;
+ u32 rx_bd_qs_tbl_offset;
+ u8 *p_tx_bd_ring[NUM_TX_QUEUES];
+ u32 tx_bd_ring_offset[NUM_TX_QUEUES];
+@@ -1308,7 +1306,7 @@ typedef struct ucc_geth_private {
+ u16 cpucount[NUM_TX_QUEUES];
+ volatile u16 *p_cpucount[NUM_TX_QUEUES];
+ int indAddrRegUsed[NUM_OF_PADDRS];
+- enet_addr_t paddr[NUM_OF_PADDRS];
++ u8 paddr[NUM_OF_PADDRS][ENET_NUM_OCTETS_PER_ADDRESS]; /* ethernet address */
+ u8 numGroupAddrInHash;
+ u8 numIndAddrInHash;
+ u8 numIndAddrInReg;
+@@ -1334,6 +1332,6 @@ typedef struct ucc_geth_private {
+ int oldspeed;
+ int oldduplex;
+ int oldlink;
+-} ucc_geth_private_t;
++};
+
+ #endif /* __UCC_GETH_H__ */
+diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
+index f91028c..5360ec0 100644
+--- a/drivers/net/ucc_geth_phy.c
++++ b/drivers/net/ucc_geth_phy.c
+@@ -17,7 +17,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/string.h>
+@@ -43,7 +42,6 @@
+
+ #include "ucc_geth.h"
+ #include "ucc_geth_phy.h"
+-#include <platforms/83xx/mpc8360e_pb.h>
+
+ #define ugphy_printk(level, format, arg...) \
+ printk(level format "\n", ## arg)
+@@ -73,16 +71,14 @@ static int genmii_read_status(struct uge
+ u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
+ void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val);
+
+-static u8 *bcsr_regs = NULL;
+-
+ /* Write value to the PHY for this device to the register at regnum, */
+ /* waiting until the write is done before it returns. All PHY */
+ /* configuration has to be done through the TSEC1 MIIM regs */
+ void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
+- ucc_mii_mng_t *mii_regs;
+- enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
++ struct ucc_mii_mng *mii_regs;
++ enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
+ u32 tmp_reg;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+@@ -117,9 +113,9 @@ void write_phy_reg(struct net_device *de
+ /* configuration has to be done through the TSEC1 MIIM regs */
+ int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
+ {
+- ucc_geth_private_t *ugeth = netdev_priv(dev);
+- ucc_mii_mng_t *mii_regs;
+- enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
++ struct ucc_geth_private *ugeth = netdev_priv(dev);
++ struct ucc_mii_mng *mii_regs;
++ enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
+ u32 tmp_reg;
+ u16 value;
+
+@@ -635,11 +631,6 @@ static void dm9161_close(struct ugeth_mi
+
+ static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
+ {
+-/* FIXME: This lines are for BUG fixing in the mpc8325.
+-Remove this from here when it's fixed */
+- if (bcsr_regs == NULL)
+- bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+- bcsr_regs[14] |= 0x40;
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Clear the interrupts by reading the reg */
+@@ -651,12 +642,6 @@ Remove this from here when it's fixed */
+
+ static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
+ {
+-/* FIXME: This lines are for BUG fixing in the mpc8325.
+-Remove this from here when it's fixed */
+- if (bcsr_regs == NULL) {
+- bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+- bcsr_regs[14] &= ~0x40;
+- }
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
+diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
+index 2f98b8f..f574078 100644
+--- a/drivers/net/ucc_geth_phy.h
++++ b/drivers/net/ucc_geth_phy.h
+@@ -126,7 +126,7 @@ struct ugeth_mii_info {
+ /* And management functions */
+ struct phy_info *phyinfo;
+
+- ucc_mii_mng_t *mii_regs;
++ struct ucc_mii_mng *mii_regs;
+
+ /* forced speed & duplex (no autoneg)
+ * partner speed & duplex & pause (autoneg)
+diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
+index ae97108..ebbda1d 100644
+--- a/drivers/net/via-rhine.c
++++ b/drivers/net/via-rhine.c
+@@ -30,8 +30,8 @@
+ */
+
+ #define DRV_NAME "via-rhine"
+-#define DRV_VERSION "1.4.1"
+-#define DRV_RELDATE "July-24-2006"
++#define DRV_VERSION "1.4.2"
++#define DRV_RELDATE "Sept-11-2006"
+
+
+ /* A few user-configurable values.
+@@ -404,14 +404,14 @@ static void mdio_write(struct net_device
+ static int rhine_open(struct net_device *dev);
+ static void rhine_tx_timeout(struct net_device *dev);
+ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
+ static void rhine_tx(struct net_device *dev);
+ static int rhine_rx(struct net_device *dev, int limit);
+ static void rhine_error(struct net_device *dev, int intr_status);
+ static void rhine_set_rx_mode(struct net_device *dev);
+ 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 const struct ethtool_ops netdev_ethtool_ops;
+ static int rhine_close(struct net_device *dev);
+ static void rhine_shutdown (struct pci_dev *pdev);
+
+@@ -569,7 +569,7 @@ static void __devinit rhine_reload_eepro
+ static void rhine_poll(struct net_device *dev)
+ {
+ disable_irq(dev->irq);
+- rhine_interrupt(dev->irq, (void *)dev, NULL);
++ rhine_interrupt(dev->irq, (void *)dev);
+ enable_irq(dev->irq);
+ }
+ #endif
+@@ -1230,7 +1230,7 @@ static int rhine_start_tx(struct sk_buff
+ rp->tx_skbuff[entry] = skb;
+
+ if ((rp->quirks & rqRhineI) &&
+- (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW)) {
++ (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_PARTIAL)) {
+ /* Must use alignment buffer. */
+ if (skb->len > PKT_BUF_SZ) {
+ /* packet too long, drop it */
+@@ -1290,7 +1290,7 @@ static int rhine_start_tx(struct sk_buff
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
++static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct rhine_private *rp = netdev_priv(dev);
+@@ -1679,9 +1679,6 @@ static void rhine_set_rx_mode(struct net
+ u8 rx_mode; /* Note: 0x02=accept runt, 0x01=accept errs */
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+- dev->name);
+ rx_mode = 0x1C;
+ iowrite32(0xffffffff, ioaddr + MulticastFilter0);
+ iowrite32(0xffffffff, ioaddr + MulticastFilter1);
+@@ -1799,7 +1796,7 @@ static int rhine_set_wol(struct net_devi
+ return 0;
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_settings = netdev_get_settings,
+ .set_settings = netdev_set_settings,
+@@ -2005,7 +2002,7 @@ static int __init rhine_init(void)
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init(&rhine_driver);
++ return pci_register_driver(&rhine_driver);
+ }
+
+
+diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
+index aa9cd92..74f8947 100644
+--- a/drivers/net/via-velocity.c
++++ b/drivers/net/via-velocity.c
+@@ -86,7 +86,7 @@ static int msglevel = MSG_LEVEL_INFO;
+
+
+ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+-static struct ethtool_ops velocity_ethtool_ops;
++static const struct ethtool_ops velocity_ethtool_ops;
+
+ /*
+ Define module options
+@@ -236,7 +236,7 @@ static void velocity_print_info(struct v
+ static int velocity_open(struct net_device *dev);
+ static int velocity_change_mtu(struct net_device *dev, int mtu);
+ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
+-static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs);
++static int velocity_intr(int irq, void *dev_instance);
+ static void velocity_set_multi(struct net_device *dev);
+ static struct net_device_stats *velocity_get_stats(struct net_device *dev);
+ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+@@ -411,11 +411,11 @@ static void __devinit velocity_set_bool_
+ if (val == -1)
+ *opt |= (def ? flag : 0);
+ else if (val < 0 || val > 1) {
+- printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
++ printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
+ devname, name);
+ *opt |= (def ? flag : 0);
+ } else {
+- printk(KERN_INFO "%s: set parameter %s to %s\n",
++ printk(KERN_INFO "%s: set parameter %s to %s\n",
+ devname, name, val ? "TRUE" : "FALSE");
+ *opt |= (val ? flag : 0);
+ }
+@@ -527,7 +527,7 @@ static void velocity_rx_reset(struct vel
+ * hardware.
+ */
+
+-static void velocity_init_registers(struct velocity_info *vptr,
++static void velocity_init_registers(struct velocity_info *vptr,
+ enum velocity_init_type type)
+ {
+ struct mac_regs __iomem * regs = vptr->mac_regs;
+@@ -559,7 +559,7 @@ static void velocity_init_registers(stru
+
+ mac_clear_isr(regs);
+ writel(CR0_STOP, ®s->CR0Clr);
+- writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
++ writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+ ®s->CR0Set);
+
+ break;
+@@ -695,7 +695,7 @@ static int __devinit velocity_found1(str
+ * can support more than MAX_UNITS.
+ */
+ if (velocity_nics >= MAX_UNITS) {
+- dev_notice(&pdev->dev, "already found %d NICs.\n",
++ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
+ return -ENODEV;
+ }
+@@ -705,16 +705,16 @@ static int __devinit velocity_found1(str
+ dev_err(&pdev->dev, "allocate net device failed.\n");
+ goto out;
+ }
+-
++
+ /* Chain it all together */
+-
++
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ vptr = netdev_priv(dev);
+
+
+ if (first) {
+- printk(KERN_INFO "%s Ver. %s\n",
++ printk(KERN_INFO "%s Ver. %s\n",
+ VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+ printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+ printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+@@ -728,7 +728,7 @@ static int __devinit velocity_found1(str
+ dev->irq = pdev->irq;
+
+ ret = pci_enable_device(pdev);
+- if (ret < 0)
++ if (ret < 0)
+ goto err_free_dev;
+
+ ret = velocity_get_pci_info(vptr, pdev);
+@@ -761,16 +761,16 @@ static int __devinit velocity_found1(str
+
+ velocity_get_options(&vptr->options, velocity_nics, dev->name);
+
+- /*
++ /*
+ * Mask out the options cannot be set to the chip
+ */
+-
++
+ vptr->options.flags &= info->flags;
+
+ /*
+ * Enable the chip specified capbilities
+ */
+-
++
+ vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
+
+ vptr->wol_opts = vptr->options.wol_opts;
+@@ -804,9 +804,9 @@ static int __devinit velocity_found1(str
+
+ velocity_print_info(vptr);
+ pci_set_drvdata(pdev, dev);
+-
++
+ /* and leave the chip powered down */
+-
++
+ pci_set_power_state(pdev, PCI_D3hot);
+ #ifdef CONFIG_PM
+ {
+@@ -845,9 +845,9 @@ static void __devinit velocity_print_inf
+ struct net_device *dev = vptr->dev;
+
+ printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+- printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+- dev->name,
+- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
++ printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
++ dev->name,
++ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ }
+
+@@ -888,12 +888,12 @@ static int __devinit velocity_get_pci_in
+ {
+ if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+ return -EIO;
+-
++
+ pci_set_master(pdev);
+
+ vptr->ioaddr = pci_resource_start(pdev, 0);
+ vptr->memaddr = pci_resource_start(pdev, 1);
+-
++
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
+@@ -932,10 +932,10 @@ static int velocity_init_rings(struct ve
+ u8 *pool;
+
+ /*
+- * Allocate all RD/TD rings a single pool
++ * Allocate all RD/TD rings a single pool
+ */
+-
+- psize = vptr->options.numrx * sizeof(struct rx_desc) +
++
++ psize = vptr->options.numrx * sizeof(struct rx_desc) +
+ vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+
+ /*
+@@ -945,7 +945,7 @@ static int velocity_init_rings(struct ve
+ pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma);
+
+ if (pool == NULL) {
+- printk(KERN_ERR "%s : DMA memory allocation failed.\n",
++ printk(KERN_ERR "%s : DMA memory allocation failed.\n",
+ vptr->dev->name);
+ return -ENOMEM;
+ }
+@@ -957,11 +957,11 @@ static int velocity_init_rings(struct ve
+ vptr->rd_pool_dma = pool_dma;
+
+ tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+- vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize,
++ vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize,
+ &vptr->tx_bufs_dma);
+
+ if (vptr->tx_bufs == NULL) {
+- printk(KERN_ERR "%s: DMA memory allocation failed.\n",
++ printk(KERN_ERR "%s: DMA memory allocation failed.\n",
+ vptr->dev->name);
+ pci_free_consistent(vptr->pdev, psize, pool, pool_dma);
+ return -ENOMEM;
+@@ -994,7 +994,7 @@ static void velocity_free_rings(struct v
+ {
+ int size;
+
+- size = vptr->options.numrx * sizeof(struct rx_desc) +
++ size = vptr->options.numrx * sizeof(struct rx_desc) +
+ vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+
+ pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma);
+@@ -1046,7 +1046,7 @@ static int velocity_rx_refill(struct vel
+ break;
+ }
+ done++;
+- dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
++ dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
+ } while (dirty != vptr->rd_curr);
+
+ if (done) {
+@@ -1069,7 +1069,7 @@ static int velocity_rx_refill(struct vel
+ static int velocity_init_rd_ring(struct velocity_info *vptr)
+ {
+ int ret = -ENOMEM;
+- unsigned int rsize = sizeof(struct velocity_rd_info) *
++ unsigned int rsize = sizeof(struct velocity_rd_info) *
+ vptr->options.numrx;
+
+ vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
+@@ -1132,14 +1132,14 @@ static void velocity_free_rd_ring(struct
+ * Returns zero on success or a negative posix errno code for
+ * failure.
+ */
+-
++
+ static int velocity_init_td_ring(struct velocity_info *vptr)
+ {
+ int i, j;
+ dma_addr_t curr;
+ struct tx_desc *td;
+ struct velocity_td_info *td_info;
+- unsigned int tsize = sizeof(struct velocity_td_info) *
++ unsigned int tsize = sizeof(struct velocity_td_info) *
+ vptr->options.numtx;
+
+ /* Init the TD ring entries */
+@@ -1177,15 +1177,15 @@ static void velocity_free_td_ring_entry(
+ {
+ struct velocity_td_info * td_info = &(vptr->td_infos[q][n]);
+ int i;
+-
++
+ if (td_info == NULL)
+ return;
+-
++
+ if (td_info->skb) {
+ for (i = 0; i < td_info->nskb_dma; i++)
+ {
+ if (td_info->skb_dma[i]) {
+- pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
++ pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
+ td_info->skb->len, PCI_DMA_TODEVICE);
+ td_info->skb_dma[i] = (dma_addr_t) NULL;
+ }
+@@ -1202,7 +1202,7 @@ static void velocity_free_td_ring_entry(
+ * Free up the transmit ring for this particular velocity adapter.
+ * We free the ring contents but not the ring itself.
+ */
+-
++
+ static void velocity_free_td_ring(struct velocity_info *vptr)
+ {
+ int i, j;
+@@ -1228,7 +1228,7 @@ static void velocity_free_td_ring(struct
+ * any received packets from the receive queue. Hand the ring
+ * slots back to the adapter for reuse.
+ */
+-
++
+ static int velocity_rx_srv(struct velocity_info *vptr, int status)
+ {
+ struct net_device_stats *stats = &vptr->stats;
+@@ -1289,14 +1289,14 @@ static int velocity_rx_srv(struct veloci
+ * Process the status bits for the received packet and determine
+ * if the checksum was computed and verified by the hardware
+ */
+-
++
+ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
+ {
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (rd->rdesc1.CSM & CSM_IPKT) {
+ if (rd->rdesc1.CSM & CSM_IPOK) {
+- if ((rd->rdesc1.CSM & CSM_TCPKT) ||
++ if ((rd->rdesc1.CSM & CSM_TCPKT) ||
+ (rd->rdesc1.CSM & CSM_UDPKT)) {
+ if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+ return;
+@@ -1339,7 +1339,7 @@ static inline int velocity_rx_copy(struc
+ *rx_skb = new_skb;
+ ret = 0;
+ }
+-
++
+ }
+ return ret;
+ }
+@@ -1370,11 +1370,11 @@ static inline void velocity_iph_realign(
+ * velocity_receive_frame - received packet processor
+ * @vptr: velocity we are handling
+ * @idx: ring index
+- *
++ *
+ * A packet has arrived. We process the packet and if appropriate
+ * pass the frame up the network stack
+ */
+-
++
+ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
+ {
+ void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
+@@ -1402,7 +1402,7 @@ static int velocity_receive_frame(struct
+ /*
+ * Drop frame not meeting IEEE 802.3
+ */
+-
++
+ if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
+ if (rd->rdesc0.RSR & RSR_RL) {
+ stats->rx_length_errors++;
+@@ -1424,7 +1424,7 @@ static int velocity_receive_frame(struct
+ PCI_DMA_FROMDEVICE);
+
+ skb_put(skb, pkt_len - 4);
+- skb->protocol = eth_type_trans(skb, skb->dev);
++ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ stats->rx_bytes += pkt_len;
+ netif_rx(skb);
+@@ -1442,7 +1442,7 @@ static int velocity_receive_frame(struct
+ * requires *64* byte alignment of the buffer which makes life
+ * less fun than would be ideal.
+ */
+-
++
+ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
+ {
+ struct rx_desc *rd = &(vptr->rd_ring[idx]);
+@@ -1459,11 +1459,11 @@ static int velocity_alloc_rx_buf(struct
+ 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->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
+-
++
+ /*
+ * Fill in the descriptor to match
+- */
+-
++ */
++
+ *((u32 *) & (rd->rdesc0)) = 0;
+ rd->len = cpu_to_le32(vptr->rx_buf_sz);
+ rd->inten = 1;
+@@ -1481,7 +1481,7 @@ static int velocity_alloc_rx_buf(struct
+ * we can complete and clean up. Update any statistics as
+ * neccessary/
+ */
+-
++
+ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+ {
+ struct tx_desc *td;
+@@ -1493,7 +1493,7 @@ static int velocity_tx_srv(struct veloci
+ struct net_device_stats *stats = &vptr->stats;
+
+ for (qnum = 0; qnum < vptr->num_txq; qnum++) {
+- for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0;
++ for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0;
+ idx = (idx + 1) % vptr->options.numtx) {
+
+ /*
+@@ -1598,12 +1598,12 @@ static void velocity_print_link_status(s
+ * @status: card status
+ *
+ * Process an error report from the hardware and attempt to recover
+- * the card itself. At the moment we cannot recover from some
++ * the card itself. At the moment we cannot recover from some
+ * theoretically impossible errors but this could be fixed using
+ * the pci_device_failed logic to bounce the hardware
+ *
+ */
+-
++
+ static void velocity_error(struct velocity_info *vptr, int status)
+ {
+
+@@ -1614,7 +1614,7 @@ static void velocity_error(struct veloci
+ BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR);
+ writew(TRDCSR_RUN, ®s->TDCSRClr);
+ netif_stop_queue(vptr->dev);
+-
++
+ /* FIXME: port over the pci_device_failed code and use it
+ here */
+ }
+@@ -1627,7 +1627,7 @@ static void velocity_error(struct veloci
+ vptr->mii_status = check_connection_type(regs);
+
+ /*
+- * If it is a 3119, disable frame bursting in
++ * If it is a 3119, disable frame bursting in
+ * halfduplex mode and enable it in fullduplex
+ * mode
+ */
+@@ -1663,10 +1663,10 @@ static void velocity_error(struct veloci
+ enable_flow_control_ability(vptr);
+
+ /*
+- * Re-enable auto-polling because SRCI will disable
++ * Re-enable auto-polling because SRCI will disable
+ * auto-polling
+ */
+-
++
+ enable_mii_autopoll(regs);
+
+ if (vptr->mii_status & VELOCITY_LINK_FAIL)
+@@ -1689,7 +1689,7 @@ static void velocity_error(struct veloci
+ * Release an transmit buffer. If the buffer was preallocated then
+ * recycle it, if not then unmap the buffer.
+ */
+-
++
+ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+ {
+ struct sk_buff *skb = tdinfo->skb;
+@@ -1723,7 +1723,7 @@ static void velocity_free_tx_buf(struct
+ * All the ring allocation and set up is done on open for this
+ * adapter to minimise memory usage when inactive
+ */
+-
++
+ static int velocity_open(struct net_device *dev)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -1742,10 +1742,10 @@ static int velocity_open(struct net_devi
+ ret = velocity_init_td_ring(vptr);
+ if (ret < 0)
+ goto err_free_rd_ring;
+-
+- /* Ensure chip is running */
++
++ /* Ensure chip is running */
+ pci_set_power_state(vptr->pdev, PCI_D0);
+-
++
+ velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+ ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED,
+@@ -1771,7 +1771,7 @@ err_free_desc_rings:
+ goto out;
+ }
+
+-/**
++/**
+ * velocity_change_mtu - MTU change callback
+ * @dev: network device
+ * @new_mtu: desired MTU
+@@ -1780,7 +1780,7 @@ err_free_desc_rings:
+ * this interface. It gets called on a change by the network layer.
+ * Return zero for success or negative posix error code.
+ */
+-
++
+ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -1789,7 +1789,7 @@ static int velocity_change_mtu(struct ne
+ int ret = 0;
+
+ if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
+- VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
++ VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
+ vptr->dev->name);
+ return -EINVAL;
+ }
+@@ -1837,7 +1837,7 @@ out_unlock:
+ * Shuts down the internal operations of the velocity and
+ * disables interrupts, autopolling, transmit and receive
+ */
+-
++
+ static void velocity_shutdown(struct velocity_info *vptr)
+ {
+ struct mac_regs __iomem * regs = vptr->mac_regs;
+@@ -1868,10 +1868,10 @@ static int velocity_close(struct net_dev
+ velocity_get_ip(vptr);
+ if (dev->irq != 0)
+ free_irq(dev->irq, dev);
+-
++
+ /* Power down the chip */
+ pci_set_power_state(vptr->pdev, PCI_D3hot);
+-
++
+ /* Free the resources */
+ velocity_free_td_ring(vptr);
+ velocity_free_rd_ring(vptr);
+@@ -1889,7 +1889,7 @@ static int velocity_close(struct net_dev
+ * Called by the networ layer to request a packet is queued to
+ * the velocity. Returns zero on success.
+ */
+-
++
+ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -1919,7 +1919,7 @@ static int velocity_xmit(struct sk_buff
+ td_ptr->td_buf[0].queue = 0;
+
+ /*
+- * Pad short frames.
++ * Pad short frames.
+ */
+ if (pktlen < ETH_ZLEN) {
+ /* Cannot occur until ZC support */
+@@ -1942,7 +1942,7 @@ static int velocity_xmit(struct sk_buff
+ if (nfrags > 6) {
+ memcpy(tdinfo->buf, skb->data, skb->len);
+ tdinfo->skb_dma[0] = tdinfo->buf_dma;
+- td_ptr->tdesc0.pktsize =
++ td_ptr->tdesc0.pktsize =
+ td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+ td_ptr->td_buf[0].pa_high = 0;
+ td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+@@ -2002,7 +2002,7 @@ static int velocity_xmit(struct sk_buff
+ * Handle hardware checksum
+ */
+ if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+- && (skb->ip_summed == CHECKSUM_HW)) {
++ && (skb->ip_summed == CHECKSUM_PARTIAL)) {
+ struct iphdr *ip = skb->nh.iph;
+ if (ip->protocol == IPPROTO_TCP)
+ td_ptr->tdesc1.TCR |= TCR0_TCPCK;
+@@ -2036,15 +2036,14 @@ static int velocity_xmit(struct sk_buff
+ * velocity_intr - interrupt callback
+ * @irq: interrupt number
+ * @dev_instance: interrupting device
+- * @pt_regs: CPU register state at interrupt
+ *
+ * Called whenever an interrupt is generated by the velocity
+ * adapter IRQ line. We may not be the source of the interrupt
+ * and need to identify initially if we are, and if not exit as
+ * efficiently as possible.
+ */
+-
+-static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
++
++static int velocity_intr(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -2067,7 +2066,7 @@ static int velocity_intr(int irq, void *
+ * Keep processing the ISR until we have completed
+ * processing and the isr_status becomes zero
+ */
+-
++
+ while (isr_status != 0) {
+ mac_write_isr(vptr->mac_regs, isr_status);
+ if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+@@ -2079,7 +2078,7 @@ static int velocity_intr(int irq, void *
+ isr_status = mac_read_isr(vptr->mac_regs);
+ if (max_count > vptr->options.int_works)
+ {
+- printk(KERN_WARNING "%s: excessive work at interrupt.\n",
++ printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+ dev->name);
+ max_count = 0;
+ }
+@@ -2099,7 +2098,7 @@ static int velocity_intr(int irq, void *
+ * for a velocity adapter. Reload the CAMs with the new address
+ * filter ruleset.
+ */
+-
++
+ static void velocity_set_multi(struct net_device *dev)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -2109,8 +2108,6 @@ static void velocity_set_multi(struct ne
+ struct dev_mc_list *mclist;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ writel(0xffffffff, ®s->MARCAM[0]);
+ writel(0xffffffff, ®s->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+@@ -2148,11 +2145,11 @@ static void velocity_set_multi(struct ne
+ * the hardware into the counters before letting the network
+ * layer display them.
+ */
+-
++
+ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+-
++
+ /* If the hardware is down, don't touch MII */
+ if(!netif_running(dev))
+ return &vptr->stats;
+@@ -2191,7 +2188,7 @@ static struct net_device_stats *velocity
+ * Called when the user issues an ioctl request to the network
+ * device in question. The velocity interface supports MII.
+ */
+-
++
+ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -2199,10 +2196,10 @@ static int velocity_ioctl(struct net_dev
+
+ /* If we are asked for information and the device is power
+ saving then we need to bring the device back up to talk to it */
+-
++
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D0);
+-
++
+ switch (cmd) {
+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
+ case SIOCGMIIREG: /* Read MII PHY register. */
+@@ -2215,8 +2212,8 @@ static int velocity_ioctl(struct net_dev
+ }
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D3hot);
+-
+-
++
++
+ return ret;
+ }
+
+@@ -2224,7 +2221,7 @@ static int velocity_ioctl(struct net_dev
+ * Definition for our device driver. The PCI layer interface
+ * uses this to handle all our card discover and plugging
+ */
+-
++
+ static struct pci_driver velocity_driver = {
+ .name = VELOCITY_NAME,
+ .id_table = velocity_id_table,
+@@ -2244,13 +2241,13 @@ static struct pci_driver velocity_driver
+ * the probe functions for each velocity adapter installed
+ * in the system.
+ */
+-
++
+ static int __init velocity_init_module(void)
+ {
+ int ret;
+
+ velocity_register_notifier();
+- ret = pci_module_init(&velocity_driver);
++ ret = pci_register_driver(&velocity_driver);
+ if (ret < 0)
+ velocity_unregister_notifier();
+ return ret;
+@@ -2260,11 +2257,11 @@ static int __init velocity_init_module(v
+ * velocity_cleanup - module unload
+ *
+ * When the velocity hardware is unloaded this function is called.
+- * It will clean up the notifiers and the unregister the PCI
++ * It will clean up the notifiers and the unregister the PCI
+ * driver interface for this hardware. This in turn cleans up
+ * all discovered interfaces before returning from the function
+ */
+-
++
+ static void __exit velocity_cleanup_module(void)
+ {
+ velocity_unregister_notifier();
+@@ -2278,8 +2275,8 @@ module_exit(velocity_cleanup_module);
+ /*
+ * MII access , media link mode setting functions
+ */
+-
+-
++
++
+ /**
+ * mii_init - set up MII
+ * @vptr: velocity adapter
+@@ -2287,7 +2284,7 @@ module_exit(velocity_cleanup_module);
+ *
+ * Set up the PHY for the current link state.
+ */
+-
++
+ static void mii_init(struct velocity_info *vptr, u32 mii_status)
+ {
+ u16 BMCR;
+@@ -2300,7 +2297,7 @@ static void mii_init(struct velocity_inf
+ MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+- * off it in NWay-forced half mode for NWay-forced v.s.
++ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue.
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+@@ -2320,7 +2317,7 @@ static void mii_init(struct velocity_inf
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+- * off it in NWay-forced half mode for NWay-forced v.s.
++ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+@@ -2332,11 +2329,11 @@ static void mii_init(struct velocity_inf
+ case PHYID_MARVELL_1000:
+ case PHYID_MARVELL_1000S:
+ /*
+- * Assert CRS on Transmit
++ * Assert CRS on Transmit
+ */
+ MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+ /*
+- * Reset to hardware default
++ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ break;
+@@ -2356,7 +2353,7 @@ static void mii_init(struct velocity_inf
+ *
+ * Turn off the autopoll and wait for it to disable on the chip
+ */
+-
++
+ static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
+ {
+ u16 ww;
+@@ -2410,7 +2407,7 @@ static void enable_mii_autopoll(struct m
+ * Perform a single read of an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+-
++
+ static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
+ {
+ u16 ww;
+@@ -2446,7 +2443,7 @@ static int velocity_mii_read(struct mac_
+ * Perform a single write to an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+-
++
+ static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+ {
+ u16 ww;
+@@ -2485,7 +2482,7 @@ static int velocity_mii_write(struct mac
+ * mii_status accordingly. The requested link state information
+ * is also returned.
+ */
+-
++
+ static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+ {
+ u32 status = 0;
+@@ -2517,7 +2514,7 @@ static u32 velocity_get_opt_media_mode(s
+ *
+ * Enable autonegotation on this interface
+ */
+-
++
+ static void mii_set_auto_on(struct velocity_info *vptr)
+ {
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+@@ -2541,7 +2538,7 @@ static void mii_set_auto_off(struct velo
+ * Set up the flow control on this interface according to
+ * the supplied user/eeprom options.
+ */
+-
++
+ static void set_mii_flow_control(struct velocity_info *vptr)
+ {
+ /*Enable or Disable PAUSE in ANAR */
+@@ -2578,7 +2575,7 @@ static void set_mii_flow_control(struct
+ * PHY and also velocity hardware setup accordingly. In particular
+ * we need to set up CD polling and frame bursting.
+ */
+-
++
+ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+ {
+ u32 curr_status;
+@@ -2688,7 +2685,7 @@ static int velocity_set_media_mode(struc
+ * Check the current MII status and determine the link status
+ * accordingly
+ */
+-
++
+ static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
+ {
+ u32 status = 0;
+@@ -2820,14 +2817,14 @@ static void enable_flow_control_ability(
+ * Called before an ethtool operation. We need to make sure the
+ * chip is out of D3 state before we poke at it.
+ */
+-
++
+ static int velocity_ethtool_up(struct net_device *dev)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D0);
+ return 0;
+-}
++}
+
+ /**
+ * velocity_ethtool_down - post hook for ethtool
+@@ -2836,7 +2833,7 @@ static int velocity_ethtool_up(struct ne
+ * Called after an ethtool operation. Restore the chip back to D3
+ * state if it isn't running.
+ */
+-
++
+ static void velocity_ethtool_down(struct net_device *dev)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -2874,7 +2871,7 @@ static int velocity_get_settings(struct
+ cmd->duplex = DUPLEX_FULL;
+ else
+ cmd->duplex = DUPLEX_HALF;
+-
++
+ return 0;
+ }
+
+@@ -2884,7 +2881,7 @@ static int velocity_set_settings(struct
+ u32 curr_status;
+ u32 new_status = 0;
+ int ret = 0;
+-
++
+ curr_status = check_connection_type(vptr->mac_regs);
+ curr_status &= (~VELOCITY_LINK_FAIL);
+
+@@ -2973,7 +2970,7 @@ static void velocity_set_msglevel(struct
+ msglevel = value;
+ }
+
+-static struct ethtool_ops velocity_ethtool_ops = {
++static const struct ethtool_ops velocity_ethtool_ops = {
+ .get_settings = velocity_get_settings,
+ .set_settings = velocity_set_settings,
+ .get_drvinfo = velocity_get_drvinfo,
+@@ -2996,7 +2993,7 @@ static struct ethtool_ops velocity_ethto
+ * are used by tools like kudzu to interrogate the link state of the
+ * hardware
+ */
+-
++
+ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+ struct velocity_info *vptr = netdev_priv(dev);
+@@ -3004,7 +3001,7 @@ static int velocity_mii_ioctl(struct net
+ unsigned long flags;
+ struct mii_ioctl_data *miidata = if_mii(ifr);
+ int err;
+-
++
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ miidata->phy_id = readb(®s->MIIADR) & 0x1f;
+@@ -3035,7 +3032,7 @@ static int velocity_mii_ioctl(struct net
+
+ /**
+ * velocity_save_context - save registers
+- * @vptr: velocity
++ * @vptr: velocity
+ * @context: buffer for stored context
+ *
+ * Retrieve the current configuration from the velocity hardware
+@@ -3043,7 +3040,7 @@ static int velocity_mii_ioctl(struct net
+ * restore functions. This allows us to save things we need across
+ * power down states
+ */
+-
++
+ static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+ {
+ struct mac_regs __iomem * regs = vptr->mac_regs;
+@@ -3063,13 +3060,13 @@ static void velocity_save_context(struct
+
+ /**
+ * velocity_restore_context - restore registers
+- * @vptr: velocity
++ * @vptr: velocity
+ * @context: buffer for stored context
+ *
+- * Reload the register configuration from the velocity context
++ * Reload the register configuration from the velocity context
+ * created by velocity_save_context.
+ */
+-
++
+ static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+ {
+ struct mac_regs __iomem * regs = vptr->mac_regs;
+diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
+index 496c3d5..b9e114d 100644
+--- a/drivers/net/via-velocity.h
++++ b/drivers/net/via-velocity.h
+@@ -29,7 +29,7 @@
+
+ #define VELOCITY_NAME "via-velocity"
+ #define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
+-#define VELOCITY_VERSION "1.13"
++#define VELOCITY_VERSION "1.14"
+
+ #define VELOCITY_IO_SIZE 256
+
+@@ -246,7 +246,7 @@ struct tdesc1 {
+ struct td_buf {
+ u32 pa_low;
+ u16 pa_high;
+- u16 bufsize:14;
++ u16 bufsize:14;
+ u16 reserved:1;
+ u16 queue:1;
+ } __attribute__ ((__packed__));
+@@ -262,25 +262,6 @@ struct velocity_rd_info {
+ dma_addr_t skb_dma;
+ };
+
+-/**
+- * alloc_rd_info - allocate an rd info block
+- *
+- * Alocate and initialize a receive info structure used for keeping
+- * track of kernel side information related to each receive
+- * descriptor we are using
+- */
+-
+-static inline struct velocity_rd_info *alloc_rd_info(void)
+-{
+- struct velocity_rd_info *ptr;
+- if ((ptr = kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL)
+- return NULL;
+- else {
+- memset(ptr, 0, sizeof(struct velocity_rd_info));
+- return ptr;
+- }
+-}
+-
+ /*
+ * Used to track transmit side buffers.
+ */
+diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
+index 54b8e49..b5d0d7f 100644
+--- a/drivers/net/wan/Kconfig
++++ b/drivers/net/wan/Kconfig
+@@ -127,7 +127,7 @@ config LANMEDIA
+ # There is no way to detect a Sealevel board. Force it modular
+ config SEALEVEL_4021
+ tristate "Sealevel Systems 4021 support"
+- depends on WAN && ISA && m && ISA_DMA_API
++ depends on WAN && ISA && m && ISA_DMA_API && INET
+ help
+ This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
+
+@@ -154,7 +154,7 @@ config HDLC
+ If unsure, say N.
+
+ config HDLC_RAW
+- bool "Raw HDLC support"
++ tristate "Raw HDLC support"
+ depends on HDLC
+ help
+ Generic HDLC driver supporting raw HDLC over WAN connections.
+@@ -162,7 +162,7 @@ config HDLC_RAW
+ If unsure, say N.
+
+ config HDLC_RAW_ETH
+- bool "Raw HDLC Ethernet device support"
++ tristate "Raw HDLC Ethernet device support"
+ depends on HDLC
+ help
+ Generic HDLC driver supporting raw HDLC Ethernet device emulation
+@@ -173,7 +173,7 @@ config HDLC_RAW_ETH
+ If unsure, say N.
+
+ config HDLC_CISCO
+- bool "Cisco HDLC support"
++ tristate "Cisco HDLC support"
+ depends on HDLC
+ help
+ Generic HDLC driver supporting Cisco HDLC over WAN connections.
+@@ -181,7 +181,7 @@ config HDLC_CISCO
+ If unsure, say N.
+
+ config HDLC_FR
+- bool "Frame Relay support"
++ tristate "Frame Relay support"
+ depends on HDLC
+ help
+ Generic HDLC driver supporting Frame Relay over WAN connections.
+@@ -189,7 +189,7 @@ config HDLC_FR
+ If unsure, say N.
+
+ config HDLC_PPP
+- bool "Synchronous Point-to-Point Protocol (PPP) support"
++ tristate "Synchronous Point-to-Point Protocol (PPP) support"
+ depends on HDLC
+ help
+ Generic HDLC driver supporting PPP over WAN connections.
+@@ -197,7 +197,7 @@ config HDLC_PPP
+ If unsure, say N.
+
+ config HDLC_X25
+- bool "X.25 protocol support"
++ tristate "X.25 protocol support"
+ depends on HDLC && (LAPB=m && HDLC=m || LAPB=y)
+ help
+ Generic HDLC driver supporting X.25 over WAN connections.
+diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
+index 316ca68..83ec2c8 100644
+--- a/drivers/net/wan/Makefile
++++ b/drivers/net/wan/Makefile
+@@ -9,14 +9,13 @@ cyclomx-y := cycx_
+ cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
+ cyclomx-objs := $(cyclomx-y)
+
+-hdlc-y := hdlc_generic.o
+-hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o
+-hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
+-hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
+-hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o
+-hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
+-hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o
+-hdlc-objs := $(hdlc-y)
++obj-$(CONFIG_HDLC) += hdlc.o
++obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
++obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
++obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
++obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
++obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
++obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
+
+ pc300-y := pc300_drv.o
+ pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
+@@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.
+ obj-$(CONFIG_LAPBETHER) += lapbether.o
+ obj-$(CONFIG_SBNI) += sbni.o
+ obj-$(CONFIG_PC300) += pc300.o
+-obj-$(CONFIG_HDLC) += hdlc.o
+-ifeq ($(CONFIG_HDLC_PPP),y)
+- obj-$(CONFIG_HDLC) += syncppp.o
+-endif
+ obj-$(CONFIG_N2) += n2.o
+ obj-$(CONFIG_C101) += c101.o
+ obj-$(CONFIG_WANXL) += wanxl.o
+diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
+index 1f95b48..e1bf8b9 100644
+--- a/drivers/net/wan/cosa.c
++++ b/drivers/net/wan/cosa.c
+@@ -345,7 +345,7 @@ static void put_driver_status(struct cos
+ static void put_driver_status_nolock(struct cosa_data *cosa);
+
+ /* Interrupt handling */
+-static irqreturn_t cosa_interrupt(int irq, void *cosa, struct pt_regs *regs);
++static irqreturn_t cosa_interrupt(int irq, void *cosa);
+
+ /* I/O ops debugging */
+ #ifdef DEBUG_IO
+@@ -1972,7 +1972,7 @@ out:
+ spin_unlock_irqrestore(&cosa->lock, flags);
+ }
+
+-static irqreturn_t cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs)
++static irqreturn_t cosa_interrupt(int irq, void *cosa_)
+ {
+ unsigned status;
+ int count = 0;
+diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
+index 430b1f6..6e5f1c8 100644
+--- a/drivers/net/wan/cycx_main.c
++++ b/drivers/net/wan/cycx_main.c
+@@ -40,7 +40,6 @@
+ * 1998/08/08 acme Initial version.
+ */
+
+-#include <linux/config.h> /* OS configuration options */
+ #include <linux/stddef.h> /* offsetof(), etc. */
+ #include <linux/errno.h> /* return codes */
+ #include <linux/string.h> /* inline memset(), etc. */
+@@ -75,7 +74,7 @@ static int cycx_wan_setup(struct wan_dev
+ static int cycx_wan_shutdown(struct wan_device *wandev);
+
+ /* Miscellaneous functions */
+-static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t cycx_isr(int irq, void *dev_id);
+
+ /* Global Data
+ * Note: All data must be explicitly initialized!!!
+@@ -302,11 +301,11 @@ out: return ret;
+ * o acknowledge Cyclom 2X hardware interrupt.
+ * o call protocol-specific interrupt service routine, if any.
+ */
+-static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cycx_isr(int irq, void *dev_id)
+ {
+- struct cycx_device *card = (struct cycx_device *)dev_id;
++ struct cycx_device *card = dev_id;
+
+- if (!card || card->wandev.state == WAN_UNCONFIGURED)
++ if (card->wandev.state == WAN_UNCONFIGURED)
+ goto out;
+
+ if (card->in_isr) {
+diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
+index 6e1ec5b..7369875 100644
+--- a/drivers/net/wan/dlci.c
++++ b/drivers/net/wan/dlci.c
+@@ -28,7 +28,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
+index 684af43..25021a7 100644
+--- a/drivers/net/wan/dscc4.c
++++ b/drivers/net/wan/dscc4.c
+@@ -365,7 +365,7 @@ static int dscc4_init_ring(struct net_de
+ static void dscc4_release_ring(struct dscc4_dev_priv *);
+ static void dscc4_timer(unsigned long);
+ static void dscc4_tx_timeout(struct net_device *);
+-static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);
++static irqreturn_t dscc4_irq(int irq, void *dev_id);
+ static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short);
+ static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *);
+ #ifdef DSCC4_POLLING
+@@ -1476,7 +1476,7 @@ static int dscc4_set_iface(struct dscc4_
+ return ret;
+ }
+
+-static irqreturn_t dscc4_irq(int irq, void *token, struct pt_regs *ptregs)
++static irqreturn_t dscc4_irq(int irq, void *token)
+ {
+ struct dscc4_dev_priv *root = token;
+ struct dscc4_pci_priv *priv;
+@@ -2062,7 +2062,7 @@ static struct pci_driver dscc4_driver =
+
+ static int __init dscc4_init_module(void)
+ {
+- return pci_module_init(&dscc4_driver);
++ return pci_register_driver(&dscc4_driver);
+ }
+
+ static void __exit dscc4_cleanup_module(void)
+diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
+index 3705db0..c45d6a8 100644
+--- a/drivers/net/wan/farsync.c
++++ b/drivers/net/wan/farsync.c
+@@ -1498,7 +1498,7 @@ do_bottom_half_rx(struct fst_card_info *
+ * Dev_id is our fst_card_info pointer
+ */
+ static irqreturn_t
+-fst_intr(int irq, void *dev_id, struct pt_regs *regs)
++fst_intr(int irq, void *dev_id)
+ {
+ struct fst_card_info *card;
+ struct fst_port_info *port;
+@@ -2697,7 +2697,7 @@ fst_init(void)
+ for (i = 0; i < FST_MAX_CARDS; i++)
+ fst_card_array[i] = NULL;
+ spin_lock_init(&fst_work_q_lock);
+- return pci_module_init(&fst_driver);
++ return pci_register_driver(&fst_driver);
+ }
+
+ static void __exit
+diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
+index dce2bb3..8d0a1f2 100644
+--- a/drivers/net/wan/hd6457x.c
++++ b/drivers/net/wan/hd6457x.c
+@@ -424,7 +424,7 @@ static inline void sca_tx_intr(port_t *p
+
+
+
+-static irqreturn_t sca_intr(int irq, void* dev_id, struct pt_regs *regs)
++static irqreturn_t sca_intr(int irq, void* dev_id)
+ {
+ card_t *card = dev_id;
+ int i;
+diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
+new file mode 100644
+index 0000000..db354e0
+--- /dev/null
++++ b/drivers/net/wan/hdlc.c
+@@ -0,0 +1,368 @@
++/*
++ * Generic HDLC support routines for Linux
++ *
++ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc at pm.waw.pl>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License
++ * as published by the Free Software Foundation.
++ *
++ * Currently supported:
++ * * raw IP-in-HDLC
++ * * Cisco HDLC
++ * * Frame Relay with ANSI or CCITT LMI (both user and network side)
++ * * PPP
++ * * X.25
++ *
++ * Use sethdlc utility to set line parameters, protocol and PVCs
++ *
++ * How does it work:
++ * - proto->open(), close(), start(), stop() calls are serialized.
++ * The order is: open, [ start, stop ... ] close ...
++ * - proto->start() and stop() are called with spin_lock_irq held.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/errno.h>
++#include <linux/if_arp.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/pkt_sched.h>
++#include <linux/inetdevice.h>
++#include <linux/lapb.h>
++#include <linux/rtnetlink.h>
++#include <linux/notifier.h>
++#include <linux/hdlc.h>
++
++
++static const char* version = "HDLC support module revision 1.20";
++
++#undef DEBUG_LINK
++
++static struct hdlc_proto *first_proto = NULL;
++
++
++static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
++{
++ if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
++ return -EINVAL;
++ dev->mtu = new_mtu;
++ return 0;
++}
++
++
++
++static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
++{
++ return hdlc_stats(dev);
++}
++
++
++
++static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
++ struct packet_type *p, struct net_device *orig_dev)
++{
++ struct hdlc_device_desc *desc = dev_to_desc(dev);
++ if (desc->netif_rx)
++ return desc->netif_rx(skb);
++
++ desc->stats.rx_dropped++; /* Shouldn't happen */
++ dev_kfree_skb(skb);
++ return NET_RX_DROP;
++}
++
++
++
++static inline void hdlc_proto_start(struct net_device *dev)
++{
++ hdlc_device *hdlc = dev_to_hdlc(dev);
++ if (hdlc->proto->start)
++ return hdlc->proto->start(dev);
++}
++
++
++
++static inline void hdlc_proto_stop(struct net_device *dev)
++{
++ hdlc_device *hdlc = dev_to_hdlc(dev);
++ if (hdlc->proto->stop)
++ return hdlc->proto->stop(dev);
++}
++
++
++
++static int hdlc_device_event(struct notifier_block *this, unsigned long event,
++ void *ptr)
++{
++ struct net_device *dev = ptr;
++ hdlc_device *hdlc;
++ unsigned long flags;
++ int on;
++
++ if (dev->get_stats != hdlc_get_stats)
++ return NOTIFY_DONE; /* not an HDLC device */
++
++ if (event != NETDEV_CHANGE)
++ return NOTIFY_DONE; /* Only interrested in carrier changes */
++
++ on = netif_carrier_ok(dev);
++
++#ifdef DEBUG_LINK
++ printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",
++ dev->name, on);
++#endif
++
++ hdlc = dev_to_hdlc(dev);
++ spin_lock_irqsave(&hdlc->state_lock, flags);
++
++ if (hdlc->carrier == on)
++ goto carrier_exit; /* no change in DCD line level */
++
++ hdlc->carrier = on;
++
++ if (!hdlc->open)
++ goto carrier_exit;
++
++ if (hdlc->carrier) {
++ printk(KERN_INFO "%s: Carrier detected\n", dev->name);
++ hdlc_proto_start(dev);
++ } else {
++ printk(KERN_INFO "%s: Carrier lost\n", dev->name);
++ hdlc_proto_stop(dev);
++ }
++
++carrier_exit:
++ spin_unlock_irqrestore(&hdlc->state_lock, flags);
++ return NOTIFY_DONE;
++}
++
++
++
++/* Must be called by hardware driver when HDLC device is being opened */
++int hdlc_open(struct net_device *dev)
++{
++ hdlc_device *hdlc = dev_to_hdlc(dev);
++#ifdef DEBUG_LINK
++ printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
++ hdlc->carrier, hdlc->open);
++#endif
++
++ if (hdlc->proto == NULL)
++ return -ENOSYS; /* no protocol attached */
++
++ if (hdlc->proto->open) {
++ int result = hdlc->proto->open(dev);
++ if (result)
++ return result;
++ }
++
++ spin_lock_irq(&hdlc->state_lock);
++
++ if (hdlc->carrier) {
++ printk(KERN_INFO "%s: Carrier detected\n", dev->name);
++ hdlc_proto_start(dev);
++ } else
++ printk(KERN_INFO "%s: No carrier\n", dev->name);
++
++ hdlc->open = 1;
++
++ spin_unlock_irq(&hdlc->state_lock);
++ return 0;
++}
++
++
++
++/* Must be called by hardware driver when HDLC device is being closed */
++void hdlc_close(struct net_device *dev)
++{
++ hdlc_device *hdlc = dev_to_hdlc(dev);
++#ifdef DEBUG_LINK
++ printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
++ hdlc->carrier, hdlc->open);
++#endif
++
++ spin_lock_irq(&hdlc->state_lock);
++
++ hdlc->open = 0;
++ if (hdlc->carrier)
++ hdlc_proto_stop(dev);
++
++ spin_unlock_irq(&hdlc->state_lock);
++
++ if (hdlc->proto->close)
++ hdlc->proto->close(dev);
++}
++
++
++
++int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct hdlc_proto *proto = first_proto;
++ int result;
++
++ if (cmd != SIOCWANDEV)
++ return -EINVAL;
++
++ if (dev_to_hdlc(dev)->proto) {
++ result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
++ if (result != -EINVAL)
++ return result;
++ }
++
++ /* Not handled by currently attached protocol (if any) */
++
++ while (proto) {
++ if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
++ return result;
++ proto = proto->next;
++ }
++ return -EINVAL;
++}
++
++void hdlc_setup(struct net_device *dev)
++{
++ hdlc_device *hdlc = dev_to_hdlc(dev);
++
++ dev->get_stats = hdlc_get_stats;
++ dev->change_mtu = hdlc_change_mtu;
++ dev->mtu = HDLC_MAX_MTU;
++
++ dev->type = ARPHRD_RAWHDLC;
++ dev->hard_header_len = 16;
++
++ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
++
++ hdlc->carrier = 1;
++ hdlc->open = 0;
++ spin_lock_init(&hdlc->state_lock);
++}
++
++struct net_device *alloc_hdlcdev(void *priv)
++{
++ struct net_device *dev;
++ dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
++ sizeof(hdlc_device), "hdlc%d", hdlc_setup);
++ if (dev)
++ dev_to_hdlc(dev)->priv = priv;
++ return dev;
++}
++
++void unregister_hdlc_device(struct net_device *dev)
++{
++ rtnl_lock();
++ unregister_netdevice(dev);
++ detach_hdlc_protocol(dev);
++ rtnl_unlock();
++}
++
++
++
++int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
++ int (*rx)(struct sk_buff *skb), size_t size)
++{
++ detach_hdlc_protocol(dev);
++
++ if (!try_module_get(proto->module))
++ return -ENOSYS;
++
++ if (size)
++ if ((dev_to_hdlc(dev)->state = kmalloc(size,
++ GFP_KERNEL)) == NULL) {
++ printk(KERN_WARNING "Memory squeeze on"
++ " hdlc_proto_attach()\n");
++ module_put(proto->module);
++ return -ENOBUFS;
++ }
++ dev_to_hdlc(dev)->proto = proto;
++ dev_to_desc(dev)->netif_rx = rx;
++ return 0;
++}
++
++
++void detach_hdlc_protocol(struct net_device *dev)
++{
++ hdlc_device *hdlc = dev_to_hdlc(dev);
++
++ if (hdlc->proto) {
++ if (hdlc->proto->detach)
++ hdlc->proto->detach(dev);
++ module_put(hdlc->proto->module);
++ hdlc->proto = NULL;
++ }
++ kfree(hdlc->state);
++ hdlc->state = NULL;
++}
++
++
++void register_hdlc_protocol(struct hdlc_proto *proto)
++{
++ proto->next = first_proto;
++ first_proto = proto;
++}
++
++
++void unregister_hdlc_protocol(struct hdlc_proto *proto)
++{
++ struct hdlc_proto **p = &first_proto;
++ while (*p) {
++ if (*p == proto) {
++ *p = proto->next;
++ return;
++ }
++ p = &((*p)->next);
++ }
++}
++
++
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("HDLC support module");
++MODULE_LICENSE("GPL v2");
++
++EXPORT_SYMBOL(hdlc_open);
++EXPORT_SYMBOL(hdlc_close);
++EXPORT_SYMBOL(hdlc_ioctl);
++EXPORT_SYMBOL(hdlc_setup);
++EXPORT_SYMBOL(alloc_hdlcdev);
++EXPORT_SYMBOL(unregister_hdlc_device);
++EXPORT_SYMBOL(register_hdlc_protocol);
++EXPORT_SYMBOL(unregister_hdlc_protocol);
++EXPORT_SYMBOL(attach_hdlc_protocol);
++EXPORT_SYMBOL(detach_hdlc_protocol);
++
++static struct packet_type hdlc_packet_type = {
++ .type = __constant_htons(ETH_P_HDLC),
++ .func = hdlc_rcv,
++};
++
++
++static struct notifier_block hdlc_notifier = {
++ .notifier_call = hdlc_device_event,
++};
++
++
++static int __init hdlc_module_init(void)
++{
++ int result;
++
++ printk(KERN_INFO "%s\n", version);
++ if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0)
++ return result;
++ dev_add_pack(&hdlc_packet_type);
++ return 0;
++}
++
++
++
++static void __exit hdlc_module_exit(void)
++{
++ dev_remove_pack(&hdlc_packet_type);
++ unregister_netdevice_notifier(&hdlc_notifier);
++}
++
++
++module_init(hdlc_module_init);
++module_exit(hdlc_module_exit);
+diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
+index f289dab..b0bc5dd 100644
+--- a/drivers/net/wan/hdlc_cisco.c
++++ b/drivers/net/wan/hdlc_cisco.c
+@@ -2,7 +2,7 @@
+ * Generic HDLC support routines for Linux
+ * Cisco HDLC support
+ *
+- * Copyright (C) 2000 - 2003 Krzysztof Halasa <khc at pm.waw.pl>
++ * Copyright (C) 2000 - 2006 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+@@ -34,17 +34,56 @@
+ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+
+
++struct hdlc_header {
++ u8 address;
++ u8 control;
++ u16 protocol;
++}__attribute__ ((packed));
++
++
++struct cisco_packet {
++ u32 type; /* code */
++ u32 par1;
++ u32 par2;
++ u16 rel; /* reliability */
++ u32 time;
++}__attribute__ ((packed));
++#define CISCO_PACKET_LEN 18
++#define CISCO_BIG_PACKET_LEN 20
++
++
++struct cisco_state {
++ cisco_proto settings;
++
++ struct timer_list timer;
++ unsigned long last_poll;
++ int up;
++ int request_sent;
++ u32 txseq; /* TX sequence number */
++ u32 rxseq; /* RX sequence number */
++};
++
++
++static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
++
++
++static inline struct cisco_state * state(hdlc_device *hdlc)
++{
++ return(struct cisco_state *)(hdlc->state);
++}
++
++
+ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
+ u16 type, void *daddr, void *saddr,
+ unsigned int len)
+ {
+- hdlc_header *data;
++ struct hdlc_header *data;
+ #ifdef DEBUG_HARD_HEADER
+ printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
+ #endif
+
+- skb_push(skb, sizeof(hdlc_header));
+- data = (hdlc_header*)skb->data;
++ skb_push(skb, sizeof(struct hdlc_header));
++ data = (struct hdlc_header*)skb->data;
+ if (type == CISCO_KEEPALIVE)
+ data->address = CISCO_MULTICAST;
+ else
+@@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_b
+ data->control = 0;
+ data->protocol = htons(type);
+
+- return sizeof(hdlc_header);
++ return sizeof(struct hdlc_header);
+ }
+
+
+@@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct
+ u32 par1, u32 par2)
+ {
+ struct sk_buff *skb;
+- cisco_packet *data;
++ struct cisco_packet *data;
+
+- skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
++ skb = dev_alloc_skb(sizeof(struct hdlc_header) +
++ sizeof(struct cisco_packet));
+ if (!skb) {
+ printk(KERN_WARNING
+ "%s: Memory squeeze on cisco_keepalive_send()\n",
+@@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct
+ }
+ skb_reserve(skb, 4);
+ cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
+- data = (cisco_packet*)(skb->data + 4);
++ data = (struct cisco_packet*)(skb->data + 4);
+
+ data->type = htonl(type);
+ data->par1 = htonl(par1);
+@@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct
+ /* we will need do_div here if 1000 % HZ != 0 */
+ data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
+
+- skb_put(skb, sizeof(cisco_packet));
++ skb_put(skb, sizeof(struct cisco_packet));
+ skb->priority = TC_PRIO_CONTROL;
+ skb->dev = dev;
+ skb->nh.raw = skb->data;
+@@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct
+
+ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
+ {
+- hdlc_header *data = (hdlc_header*)skb->data;
++ struct hdlc_header *data = (struct hdlc_header*)skb->data;
+
+- if (skb->len < sizeof(hdlc_header))
++ if (skb->len < sizeof(struct hdlc_header))
+ return __constant_htons(ETH_P_HDLC);
+
+ if (data->address != CISCO_MULTICAST &&
+@@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk
+ case __constant_htons(ETH_P_IP):
+ case __constant_htons(ETH_P_IPX):
+ case __constant_htons(ETH_P_IPV6):
+- skb_pull(skb, sizeof(hdlc_header));
++ skb_pull(skb, sizeof(struct hdlc_header));
+ return data->protocol;
+ default:
+ return __constant_htons(ETH_P_HDLC);
+@@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb)
+ {
+ struct net_device *dev = skb->dev;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+- hdlc_header *data = (hdlc_header*)skb->data;
+- cisco_packet *cisco_data;
++ struct hdlc_header *data = (struct hdlc_header*)skb->data;
++ struct cisco_packet *cisco_data;
+ struct in_device *in_dev;
+- u32 addr, mask;
++ __be32 addr, mask;
+
+- if (skb->len < sizeof(hdlc_header))
++ if (skb->len < sizeof(struct hdlc_header))
+ goto rx_error;
+
+ if (data->address != CISCO_MULTICAST &&
+@@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb)
+ return NET_RX_SUCCESS;
+
+ case CISCO_KEEPALIVE:
+- if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
+- skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
+- printk(KERN_INFO "%s: Invalid length of Cisco "
+- "control packet (%d bytes)\n",
+- dev->name, skb->len);
++ if ((skb->len != sizeof(struct hdlc_header) +
++ CISCO_PACKET_LEN) &&
++ (skb->len != sizeof(struct hdlc_header) +
++ CISCO_BIG_PACKET_LEN)) {
++ printk(KERN_INFO "%s: Invalid length of Cisco control"
++ " packet (%d bytes)\n", dev->name, skb->len);
+ goto rx_error;
+ }
+
+- cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header));
++ cisco_data = (struct cisco_packet*)(skb->data + sizeof
++ (struct hdlc_header));
+
+ switch(ntohl (cisco_data->type)) {
+ case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
+@@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb)
+ goto rx_error;
+
+ case CISCO_KEEPALIVE_REQ:
+- hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
+- if (hdlc->state.cisco.request_sent &&
+- ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
+- hdlc->state.cisco.last_poll = jiffies;
+- if (!hdlc->state.cisco.up) {
++ state(hdlc)->rxseq = ntohl(cisco_data->par1);
++ if (state(hdlc)->request_sent &&
++ ntohl(cisco_data->par2) == state(hdlc)->txseq) {
++ state(hdlc)->last_poll = jiffies;
++ if (!state(hdlc)->up) {
+ u32 sec, min, hrs, days;
+ sec = ntohl(cisco_data->time) / 1000;
+ min = sec / 60; sec -= min * 60;
+@@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb)
+ dev->name, days, hrs,
+ min, sec);
+ netif_dormant_off(dev);
+- hdlc->state.cisco.up = 1;
++ state(hdlc)->up = 1;
+ }
+ }
+
+@@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
+ return NET_RX_DROP;
+
+ rx_error:
+- hdlc->stats.rx_errors++; /* Mark error */
++ dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+@@ -220,23 +262,22 @@ static void cisco_timer(unsigned long ar
+ struct net_device *dev = (struct net_device *)arg;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+
+- if (hdlc->state.cisco.up &&
+- time_after(jiffies, hdlc->state.cisco.last_poll +
+- hdlc->state.cisco.settings.timeout * HZ)) {
+- hdlc->state.cisco.up = 0;
++ if (state(hdlc)->up &&
++ time_after(jiffies, state(hdlc)->last_poll +
++ state(hdlc)->settings.timeout * HZ)) {
++ state(hdlc)->up = 0;
+ printk(KERN_INFO "%s: Link down\n", dev->name);
+ netif_dormant_on(dev);
+ }
+
+- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+- ++hdlc->state.cisco.txseq,
+- hdlc->state.cisco.rxseq);
+- hdlc->state.cisco.request_sent = 1;
+- hdlc->state.cisco.timer.expires = jiffies +
+- hdlc->state.cisco.settings.interval * HZ;
+- hdlc->state.cisco.timer.function = cisco_timer;
+- hdlc->state.cisco.timer.data = arg;
+- add_timer(&hdlc->state.cisco.timer);
++ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
++ state(hdlc)->rxseq);
++ state(hdlc)->request_sent = 1;
++ state(hdlc)->timer.expires = jiffies +
++ state(hdlc)->settings.interval * HZ;
++ state(hdlc)->timer.function = cisco_timer;
++ state(hdlc)->timer.data = arg;
++ add_timer(&state(hdlc)->timer);
+ }
+
+
+@@ -244,15 +285,15 @@ static void cisco_timer(unsigned long ar
+ static void cisco_start(struct net_device *dev)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+- hdlc->state.cisco.up = 0;
+- hdlc->state.cisco.request_sent = 0;
+- hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
+-
+- init_timer(&hdlc->state.cisco.timer);
+- hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
+- hdlc->state.cisco.timer.function = cisco_timer;
+- hdlc->state.cisco.timer.data = (unsigned long)dev;
+- add_timer(&hdlc->state.cisco.timer);
++ state(hdlc)->up = 0;
++ state(hdlc)->request_sent = 0;
++ state(hdlc)->txseq = state(hdlc)->rxseq = 0;
++
++ init_timer(&state(hdlc)->timer);
++ state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
++ state(hdlc)->timer.function = cisco_timer;
++ state(hdlc)->timer.data = (unsigned long)dev;
++ add_timer(&state(hdlc)->timer);
+ }
+
+
+@@ -260,15 +301,24 @@ static void cisco_start(struct net_devic
+ static void cisco_stop(struct net_device *dev)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+- del_timer_sync(&hdlc->state.cisco.timer);
++ del_timer_sync(&state(hdlc)->timer);
+ netif_dormant_on(dev);
+- hdlc->state.cisco.up = 0;
+- hdlc->state.cisco.request_sent = 0;
++ state(hdlc)->up = 0;
++ state(hdlc)->request_sent = 0;
+ }
+
+
+
+-int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
++static struct hdlc_proto proto = {
++ .start = cisco_start,
++ .stop = cisco_stop,
++ .type_trans = cisco_type_trans,
++ .ioctl = cisco_ioctl,
++ .module = THIS_MODULE,
++};
++
++
++static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
+ {
+ cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
+ const size_t size = sizeof(cisco_proto);
+@@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
++ if (dev_to_hdlc(dev)->proto != &proto)
++ return -EINVAL;
+ ifr->ifr_settings.type = IF_PROTO_CISCO;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+- if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
++ if (copy_to_user(cisco_s, &state(hdlc)->settings, size))
+ return -EFAULT;
+ return 0;
+
+@@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *
+ return -EINVAL;
+
+ result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+-
+ if (result)
+ return result;
+
+- hdlc_proto_detach(hdlc);
+- memcpy(&hdlc->state.cisco.settings, &new_settings, size);
+- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
++ result = attach_hdlc_protocol(dev, &proto, cisco_rx,
++ sizeof(struct cisco_state));
++ if (result)
++ return result;
+
+- hdlc->proto.start = cisco_start;
+- hdlc->proto.stop = cisco_stop;
+- hdlc->proto.netif_rx = cisco_rx;
+- hdlc->proto.type_trans = cisco_type_trans;
+- hdlc->proto.id = IF_PROTO_CISCO;
++ memcpy(&state(hdlc)->settings, &new_settings, size);
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = cisco_hard_header;
+ dev->hard_header_cache = NULL;
+@@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *
+
+ return -EINVAL;
+ }
++
++
++static int __init mod_init(void)
++{
++ register_hdlc_protocol(&proto);
++ return 0;
++}
++
++
++
++static void __exit mod_exit(void)
++{
++ unregister_hdlc_protocol(&proto);
++}
++
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
+index 7bb737b..b45ab68 100644
+--- a/drivers/net/wan/hdlc_fr.c
++++ b/drivers/net/wan/hdlc_fr.c
+@@ -2,7 +2,7 @@
+ * Generic HDLC support routines for Linux
+ * Frame Relay support
+ *
+- * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc at pm.waw.pl>
++ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+@@ -52,6 +52,8 @@
+ #undef DEBUG_PKT
+ #undef DEBUG_ECN
+ #undef DEBUG_LINK
++#undef DEBUG_PROTO
++#undef DEBUG_PVC
+
+ #define FR_UI 0x03
+ #define FR_PAD 0x00
+@@ -115,13 +117,53 @@ typedef struct {
+ }__attribute__ ((packed)) fr_hdr;
+
+
++typedef struct pvc_device_struct {
++ struct net_device *frad;
++ struct net_device *main;
++ struct net_device *ether; /* bridged Ethernet interface */
++ struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
++ int dlci;
++ int open_count;
++
++ struct {
++ unsigned int new: 1;
++ unsigned int active: 1;
++ unsigned int exist: 1;
++ unsigned int deleted: 1;
++ unsigned int fecn: 1;
++ unsigned int becn: 1;
++ unsigned int bandwidth; /* Cisco LMI reporting only */
++ }state;
++}pvc_device;
++
++
++struct frad_state {
++ fr_proto settings;
++ pvc_device *first_pvc;
++ int dce_pvc_count;
++
++ struct timer_list timer;
++ unsigned long last_poll;
++ int reliable;
++ int dce_changed;
++ int request;
++ int fullrep_sent;
++ u32 last_errors; /* last errors bit list */
++ u8 n391cnt;
++ u8 txseq; /* TX sequence number */
++ u8 rxseq; /* RX sequence number */
++};
++
++
++static int fr_ioctl(struct net_device *dev, struct ifreq *ifr);
++
++
+ static inline u16 q922_to_dlci(u8 *hdr)
+ {
+ return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
+ }
+
+
+-
+ static inline void dlci_to_q922(u8 *hdr, u16 dlci)
+ {
+ hdr[0] = (dlci >> 2) & 0xFC;
+@@ -129,10 +171,21 @@ static inline void dlci_to_q922(u8 *hdr,
+ }
+
+
++static inline struct frad_state * state(hdlc_device *hdlc)
++{
++ return(struct frad_state *)(hdlc->state);
++}
++
++
++static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
++{
++ return dev->priv;
++}
++
+
+ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+ {
+- pvc_device *pvc = hdlc->state.fr.first_pvc;
++ pvc_device *pvc = state(hdlc)->first_pvc;
+
+ while (pvc) {
+ if (pvc->dlci == dlci)
+@@ -146,10 +199,10 @@ static inline pvc_device* find_pvc(hdlc_
+ }
+
+
+-static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
++static pvc_device* add_pvc(struct net_device *dev, u16 dlci)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+- pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
++ pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc;
+
+ while (*pvc_p) {
+ if ((*pvc_p)->dlci == dlci)
+@@ -160,12 +213,15 @@ static inline pvc_device* add_pvc(struct
+ }
+
+ pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
++#ifdef DEBUG_PVC
++ printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev);
++#endif
+ if (!pvc)
+ return NULL;
+
+ memset(pvc, 0, sizeof(pvc_device));
+ pvc->dlci = dlci;
+- pvc->master = dev;
++ pvc->frad = dev;
+ pvc->next = *pvc_p; /* Put it in the chain */
+ *pvc_p = pvc;
+ return pvc;
+@@ -174,7 +230,7 @@ static inline pvc_device* add_pvc(struct
+
+ static inline int pvc_is_used(pvc_device *pvc)
+ {
+- return pvc->main != NULL || pvc->ether != NULL;
++ return pvc->main || pvc->ether;
+ }
+
+
+@@ -200,11 +256,14 @@ static inline void pvc_carrier(int on, p
+
+ static inline void delete_unused_pvcs(hdlc_device *hdlc)
+ {
+- pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
++ pvc_device **pvc_p = &state(hdlc)->first_pvc;
+
+ while (*pvc_p) {
+ if (!pvc_is_used(*pvc_p)) {
+ pvc_device *pvc = *pvc_p;
++#ifdef DEBUG_PVC
++ printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc);
++#endif
+ *pvc_p = pvc->next;
+ kfree(pvc);
+ continue;
+@@ -295,16 +354,16 @@ static int pvc_open(struct net_device *d
+ {
+ pvc_device *pvc = dev_to_pvc(dev);
+
+- if ((pvc->master->flags & IFF_UP) == 0)
+- return -EIO; /* Master must be UP in order to activate PVC */
++ if ((pvc->frad->flags & IFF_UP) == 0)
++ return -EIO; /* Frad must be UP in order to activate PVC */
+
+ if (pvc->open_count++ == 0) {
+- hdlc_device *hdlc = dev_to_hdlc(pvc->master);
+- if (hdlc->state.fr.settings.lmi == LMI_NONE)
+- pvc->state.active = netif_carrier_ok(pvc->master);
++ hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
++ if (state(hdlc)->settings.lmi == LMI_NONE)
++ pvc->state.active = netif_carrier_ok(pvc->frad);
+
+ pvc_carrier(pvc->state.active, pvc);
+- hdlc->state.fr.dce_changed = 1;
++ state(hdlc)->dce_changed = 1;
+ }
+ return 0;
+ }
+@@ -316,12 +375,12 @@ static int pvc_close(struct net_device *
+ pvc_device *pvc = dev_to_pvc(dev);
+
+ if (--pvc->open_count == 0) {
+- hdlc_device *hdlc = dev_to_hdlc(pvc->master);
+- if (hdlc->state.fr.settings.lmi == LMI_NONE)
++ hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
++ if (state(hdlc)->settings.lmi == LMI_NONE)
+ pvc->state.active = 0;
+
+- if (hdlc->state.fr.settings.dce) {
+- hdlc->state.fr.dce_changed = 1;
++ if (state(hdlc)->settings.dce) {
++ state(hdlc)->dce_changed = 1;
+ pvc->state.active = 0;
+ }
+ }
+@@ -348,7 +407,7 @@ static int pvc_ioctl(struct net_device *
+ }
+
+ info.dlci = pvc->dlci;
+- memcpy(info.master, pvc->master->name, IFNAMSIZ);
++ memcpy(info.master, pvc->frad->name, IFNAMSIZ);
+ if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
+ &info, sizeof(info)))
+ return -EFAULT;
+@@ -361,7 +420,7 @@ static int pvc_ioctl(struct net_device *
+
+ static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
+ {
+- return netdev_priv(dev);
++ return &dev_to_desc(dev)->stats;
+ }
+
+
+@@ -393,7 +452,7 @@ static int pvc_xmit(struct sk_buff *skb,
+ stats->tx_packets++;
+ if (pvc->state.fecn) /* TX Congestion counter */
+ stats->tx_compressed++;
+- skb->dev = pvc->master;
++ skb->dev = pvc->frad;
+ dev_queue_xmit(skb);
+ return 0;
+ }
+@@ -419,7 +478,7 @@ static int pvc_change_mtu(struct net_dev
+ static inline void fr_log_dlci_active(pvc_device *pvc)
+ {
+ printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
+- pvc->master->name,
++ pvc->frad->name,
+ pvc->dlci,
+ pvc->main ? pvc->main->name : "",
+ pvc->main && pvc->ether ? " " : "",
+@@ -438,21 +497,20 @@ static inline u8 fr_lmi_nextseq(u8 x)
+ }
+
+
+-
+ static void fr_lmi_send(struct net_device *dev, int fullrep)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct sk_buff *skb;
+- pvc_device *pvc = hdlc->state.fr.first_pvc;
+- int lmi = hdlc->state.fr.settings.lmi;
+- int dce = hdlc->state.fr.settings.dce;
++ pvc_device *pvc = state(hdlc)->first_pvc;
++ int lmi = state(hdlc)->settings.lmi;
++ int dce = state(hdlc)->settings.dce;
+ int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
+ int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
+ u8 *data;
+ int i = 0;
+
+ if (dce && fullrep) {
+- len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
++ len += state(hdlc)->dce_pvc_count * (2 + stat_len);
+ if (len > HDLC_MAX_MRU) {
+ printk(KERN_WARNING "%s: Too many PVCs while sending "
+ "LMI full report\n", dev->name);
+@@ -486,8 +544,9 @@ static void fr_lmi_send(struct net_devic
+ data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
+ data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
+ data[i++] = LMI_INTEG_LEN;
+- data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
+- data[i++] = hdlc->state.fr.rxseq;
++ data[i++] = state(hdlc)->txseq =
++ fr_lmi_nextseq(state(hdlc)->txseq);
++ data[i++] = state(hdlc)->rxseq;
+
+ if (dce && fullrep) {
+ while (pvc) {
+@@ -496,7 +555,7 @@ static void fr_lmi_send(struct net_devic
+ data[i++] = stat_len;
+
+ /* LMI start/restart */
+- if (hdlc->state.fr.reliable && !pvc->state.exist) {
++ if (state(hdlc)->reliable && !pvc->state.exist) {
+ pvc->state.exist = pvc->state.new = 1;
+ fr_log_dlci_active(pvc);
+ }
+@@ -541,15 +600,15 @@ static void fr_lmi_send(struct net_devic
+ static void fr_set_link_state(int reliable, struct net_device *dev)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+- pvc_device *pvc = hdlc->state.fr.first_pvc;
++ pvc_device *pvc = state(hdlc)->first_pvc;
+
+- hdlc->state.fr.reliable = reliable;
++ state(hdlc)->reliable = reliable;
+ if (reliable) {
+ netif_dormant_off(dev);
+- hdlc->state.fr.n391cnt = 0; /* Request full status */
+- hdlc->state.fr.dce_changed = 1;
++ state(hdlc)->n391cnt = 0; /* Request full status */
++ state(hdlc)->dce_changed = 1;
+
+- if (hdlc->state.fr.settings.lmi == LMI_NONE) {
++ if (state(hdlc)->settings.lmi == LMI_NONE) {
+ while (pvc) { /* Activate all PVCs */
+ pvc_carrier(1, pvc);
+ pvc->state.exist = pvc->state.active = 1;
+@@ -563,7 +622,7 @@ static void fr_set_link_state(int reliab
+ pvc_carrier(0, pvc);
+ pvc->state.exist = pvc->state.active = 0;
+ pvc->state.new = 0;
+- if (!hdlc->state.fr.settings.dce)
++ if (!state(hdlc)->settings.dce)
+ pvc->state.bandwidth = 0;
+ pvc = pvc->next;
+ }
+@@ -571,7 +630,6 @@ static void fr_set_link_state(int reliab
+ }
+
+
+-
+ static void fr_timer(unsigned long arg)
+ {
+ struct net_device *dev = (struct net_device *)arg;
+@@ -579,62 +637,61 @@ static void fr_timer(unsigned long arg)
+ int i, cnt = 0, reliable;
+ u32 list;
+
+- if (hdlc->state.fr.settings.dce) {
+- reliable = hdlc->state.fr.request &&
+- time_before(jiffies, hdlc->state.fr.last_poll +
+- hdlc->state.fr.settings.t392 * HZ);
+- hdlc->state.fr.request = 0;
++ if (state(hdlc)->settings.dce) {
++ reliable = state(hdlc)->request &&
++ time_before(jiffies, state(hdlc)->last_poll +
++ state(hdlc)->settings.t392 * HZ);
++ state(hdlc)->request = 0;
+ } else {
+- hdlc->state.fr.last_errors <<= 1; /* Shift the list */
+- if (hdlc->state.fr.request) {
+- if (hdlc->state.fr.reliable)
++ state(hdlc)->last_errors <<= 1; /* Shift the list */
++ if (state(hdlc)->request) {
++ if (state(hdlc)->reliable)
+ printk(KERN_INFO "%s: No LMI status reply "
+ "received\n", dev->name);
+- hdlc->state.fr.last_errors |= 1;
++ state(hdlc)->last_errors |= 1;
+ }
+
+- list = hdlc->state.fr.last_errors;
+- for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
++ list = state(hdlc)->last_errors;
++ for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1)
+ cnt += (list & 1); /* errors count */
+
+- reliable = (cnt < hdlc->state.fr.settings.n392);
++ reliable = (cnt < state(hdlc)->settings.n392);
+ }
+
+- if (hdlc->state.fr.reliable != reliable) {
++ if (state(hdlc)->reliable != reliable) {
+ printk(KERN_INFO "%s: Link %sreliable\n", dev->name,
+ reliable ? "" : "un");
+ fr_set_link_state(reliable, dev);
+ }
+
+- if (hdlc->state.fr.settings.dce)
+- hdlc->state.fr.timer.expires = jiffies +
+- hdlc->state.fr.settings.t392 * HZ;
++ if (state(hdlc)->settings.dce)
++ state(hdlc)->timer.expires = jiffies +
++ state(hdlc)->settings.t392 * HZ;
+ else {
+- if (hdlc->state.fr.n391cnt)
+- hdlc->state.fr.n391cnt--;
++ if (state(hdlc)->n391cnt)
++ state(hdlc)->n391cnt--;
+
+- fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
++ fr_lmi_send(dev, state(hdlc)->n391cnt == 0);
+
+- hdlc->state.fr.last_poll = jiffies;
+- hdlc->state.fr.request = 1;
+- hdlc->state.fr.timer.expires = jiffies +
+- hdlc->state.fr.settings.t391 * HZ;
++ state(hdlc)->last_poll = jiffies;
++ state(hdlc)->request = 1;
++ state(hdlc)->timer.expires = jiffies +
++ state(hdlc)->settings.t391 * HZ;
+ }
+
+- hdlc->state.fr.timer.function = fr_timer;
+- hdlc->state.fr.timer.data = arg;
+- add_timer(&hdlc->state.fr.timer);
++ state(hdlc)->timer.function = fr_timer;
++ state(hdlc)->timer.data = arg;
++ add_timer(&state(hdlc)->timer);
+ }
+
+
+-
+ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ pvc_device *pvc;
+ u8 rxseq, txseq;
+- int lmi = hdlc->state.fr.settings.lmi;
+- int dce = hdlc->state.fr.settings.dce;
++ int lmi = state(hdlc)->settings.lmi;
++ int dce = state(hdlc)->settings.dce;
+ int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
+
+ if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
+@@ -645,8 +702,8 @@ static int fr_lmi_recv(struct net_device
+
+ if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
+ NLPID_CCITT_ANSI_LMI)) {
+- printk(KERN_INFO "%s: Received non-LMI frame with LMI"
+- " DLCI\n", dev->name);
++ printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
++ dev->name);
+ return 1;
+ }
+
+@@ -706,53 +763,53 @@ static int fr_lmi_recv(struct net_device
+ }
+ i++;
+
+- hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
++ state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */
+ rxseq = skb->data[i++]; /* Should confirm our sequence */
+
+- txseq = hdlc->state.fr.txseq;
++ txseq = state(hdlc)->txseq;
+
+ if (dce)
+- hdlc->state.fr.last_poll = jiffies;
++ state(hdlc)->last_poll = jiffies;
+
+ error = 0;
+- if (!hdlc->state.fr.reliable)
++ if (!state(hdlc)->reliable)
+ error = 1;
+
+- if (rxseq == 0 || rxseq != txseq) {
+- hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
++ if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */
++ state(hdlc)->n391cnt = 0;
+ error = 1;
+ }
+
+ if (dce) {
+- if (hdlc->state.fr.fullrep_sent && !error) {
++ if (state(hdlc)->fullrep_sent && !error) {
+ /* Stop sending full report - the last one has been confirmed by DTE */
+- hdlc->state.fr.fullrep_sent = 0;
+- pvc = hdlc->state.fr.first_pvc;
++ state(hdlc)->fullrep_sent = 0;
++ pvc = state(hdlc)->first_pvc;
+ while (pvc) {
+ if (pvc->state.new) {
+ pvc->state.new = 0;
+
+ /* Tell DTE that new PVC is now active */
+- hdlc->state.fr.dce_changed = 1;
++ state(hdlc)->dce_changed = 1;
+ }
+ pvc = pvc->next;
+ }
+ }
+
+- if (hdlc->state.fr.dce_changed) {
++ if (state(hdlc)->dce_changed) {
+ reptype = LMI_FULLREP;
+- hdlc->state.fr.fullrep_sent = 1;
+- hdlc->state.fr.dce_changed = 0;
++ state(hdlc)->fullrep_sent = 1;
++ state(hdlc)->dce_changed = 0;
+ }
+
+- hdlc->state.fr.request = 1; /* got request */
++ state(hdlc)->request = 1; /* got request */
+ fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
+ return 0;
+ }
+
+ /* DTE */
+
+- hdlc->state.fr.request = 0; /* got response, no request pending */
++ state(hdlc)->request = 0; /* got response, no request pending */
+
+ if (error)
+ return 0;
+@@ -760,7 +817,7 @@ static int fr_lmi_recv(struct net_device
+ if (reptype != LMI_FULLREP)
+ return 0;
+
+- pvc = hdlc->state.fr.first_pvc;
++ pvc = state(hdlc)->first_pvc;
+
+ while (pvc) {
+ pvc->state.deleted = 1;
+@@ -827,7 +884,7 @@ static int fr_lmi_recv(struct net_device
+ i += stat_len;
+ }
+
+- pvc = hdlc->state.fr.first_pvc;
++ pvc = state(hdlc)->first_pvc;
+
+ while (pvc) {
+ if (pvc->state.deleted && pvc->state.exist) {
+@@ -841,17 +898,16 @@ static int fr_lmi_recv(struct net_device
+ }
+
+ /* Next full report after N391 polls */
+- hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
++ state(hdlc)->n391cnt = state(hdlc)->settings.n391;
+
+ return 0;
+ }
+
+
+-
+ static int fr_rx(struct sk_buff *skb)
+ {
+- struct net_device *ndev = skb->dev;
+- hdlc_device *hdlc = dev_to_hdlc(ndev);
++ struct net_device *frad = skb->dev;
++ hdlc_device *hdlc = dev_to_hdlc(frad);
+ fr_hdr *fh = (fr_hdr*)skb->data;
+ u8 *data = skb->data;
+ u16 dlci;
+@@ -864,11 +920,11 @@ static int fr_rx(struct sk_buff *skb)
+ dlci = q922_to_dlci(skb->data);
+
+ if ((dlci == LMI_CCITT_ANSI_DLCI &&
+- (hdlc->state.fr.settings.lmi == LMI_ANSI ||
+- hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
++ (state(hdlc)->settings.lmi == LMI_ANSI ||
++ state(hdlc)->settings.lmi == LMI_CCITT)) ||
+ (dlci == LMI_CISCO_DLCI &&
+- hdlc->state.fr.settings.lmi == LMI_CISCO)) {
+- if (fr_lmi_recv(ndev, skb))
++ state(hdlc)->settings.lmi == LMI_CISCO)) {
++ if (fr_lmi_recv(frad, skb))
+ goto rx_error;
+ dev_kfree_skb_any(skb);
+ return NET_RX_SUCCESS;
+@@ -878,7 +934,7 @@ static int fr_rx(struct sk_buff *skb)
+ if (!pvc) {
+ #ifdef DEBUG_PKT
+ printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
+- ndev->name, dlci);
++ frad->name, dlci);
+ #endif
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+@@ -886,7 +942,7 @@ static int fr_rx(struct sk_buff *skb)
+
+ if (pvc->state.fecn != fh->fecn) {
+ #ifdef DEBUG_ECN
+- printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name,
++ printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name,
+ dlci, fh->fecn ? "N" : "FF");
+ #endif
+ pvc->state.fecn ^= 1;
+@@ -894,7 +950,7 @@ static int fr_rx(struct sk_buff *skb)
+
+ if (pvc->state.becn != fh->becn) {
+ #ifdef DEBUG_ECN
+- printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name,
++ printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name,
+ dlci, fh->becn ? "N" : "FF");
+ #endif
+ pvc->state.becn ^= 1;
+@@ -902,7 +958,7 @@ static int fr_rx(struct sk_buff *skb)
+
+
+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+- hdlc->stats.rx_dropped++;
++ dev_to_desc(frad)->stats.rx_dropped++;
+ return NET_RX_DROP;
+ }
+
+@@ -938,13 +994,13 @@ static int fr_rx(struct sk_buff *skb)
+
+ default:
+ printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
+- "PID=%x\n", ndev->name, oui, pid);
++ "PID=%x\n", frad->name, oui, pid);
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+ } else {
+ printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
+- "length = %i\n", ndev->name, data[3], skb->len);
++ "length = %i\n", frad->name, data[3], skb->len);
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+@@ -964,7 +1020,7 @@ static int fr_rx(struct sk_buff *skb)
+ }
+
+ rx_error:
+- hdlc->stats.rx_errors++; /* Mark error */
++ dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+@@ -977,44 +1033,42 @@ static void fr_start(struct net_device *
+ #ifdef DEBUG_LINK
+ printk(KERN_DEBUG "fr_start\n");
+ #endif
+- if (hdlc->state.fr.settings.lmi != LMI_NONE) {
+- hdlc->state.fr.reliable = 0;
+- hdlc->state.fr.dce_changed = 1;
+- hdlc->state.fr.request = 0;
+- hdlc->state.fr.fullrep_sent = 0;
+- hdlc->state.fr.last_errors = 0xFFFFFFFF;
+- hdlc->state.fr.n391cnt = 0;
+- hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
+-
+- init_timer(&hdlc->state.fr.timer);
++ if (state(hdlc)->settings.lmi != LMI_NONE) {
++ state(hdlc)->reliable = 0;
++ state(hdlc)->dce_changed = 1;
++ state(hdlc)->request = 0;
++ state(hdlc)->fullrep_sent = 0;
++ state(hdlc)->last_errors = 0xFFFFFFFF;
++ state(hdlc)->n391cnt = 0;
++ state(hdlc)->txseq = state(hdlc)->rxseq = 0;
++
++ init_timer(&state(hdlc)->timer);
+ /* First poll after 1 s */
+- hdlc->state.fr.timer.expires = jiffies + HZ;
+- hdlc->state.fr.timer.function = fr_timer;
+- hdlc->state.fr.timer.data = (unsigned long)dev;
+- add_timer(&hdlc->state.fr.timer);
++ state(hdlc)->timer.expires = jiffies + HZ;
++ state(hdlc)->timer.function = fr_timer;
++ state(hdlc)->timer.data = (unsigned long)dev;
++ add_timer(&state(hdlc)->timer);
+ } else
+ fr_set_link_state(1, dev);
+ }
+
+
+-
+ static void fr_stop(struct net_device *dev)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ #ifdef DEBUG_LINK
+ printk(KERN_DEBUG "fr_stop\n");
+ #endif
+- if (hdlc->state.fr.settings.lmi != LMI_NONE)
+- del_timer_sync(&hdlc->state.fr.timer);
++ if (state(hdlc)->settings.lmi != LMI_NONE)
++ del_timer_sync(&state(hdlc)->timer);
+ fr_set_link_state(0, dev);
+ }
+
+
+-
+ static void fr_close(struct net_device *dev)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+- pvc_device *pvc = hdlc->state.fr.first_pvc;
++ pvc_device *pvc = state(hdlc)->first_pvc;
+
+ while (pvc) { /* Shutdown all PVCs for this FRAD */
+ if (pvc->main)
+@@ -1025,7 +1079,8 @@ static void fr_close(struct net_device *
+ }
+ }
+
+-static void dlci_setup(struct net_device *dev)
++
++static void pvc_setup(struct net_device *dev)
+ {
+ dev->type = ARPHRD_DLCI;
+ dev->flags = IFF_POINTOPOINT;
+@@ -1033,9 +1088,9 @@ static void dlci_setup(struct net_device
+ dev->addr_len = 2;
+ }
+
+-static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
++static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
+ {
+- hdlc_device *hdlc = dev_to_hdlc(master);
++ hdlc_device *hdlc = dev_to_hdlc(frad);
+ pvc_device *pvc = NULL;
+ struct net_device *dev;
+ int result, used;
+@@ -1044,9 +1099,9 @@ static int fr_add_pvc(struct net_device
+ if (type == ARPHRD_ETHER)
+ prefix = "pvceth%d";
+
+- if ((pvc = add_pvc(master, dlci)) == NULL) {
++ if ((pvc = add_pvc(frad, dlci)) == NULL) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
+- master->name);
++ frad->name);
+ return -ENOBUFS;
+ }
+
+@@ -1060,11 +1115,11 @@ static int fr_add_pvc(struct net_device
+ "pvceth%d", ether_setup);
+ else
+ dev = alloc_netdev(sizeof(struct net_device_stats),
+- "pvc%d", dlci_setup);
++ "pvc%d", pvc_setup);
+
+ if (!dev) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
+- master->name);
++ frad->name);
+ delete_unused_pvcs(hdlc);
+ return -ENOBUFS;
+ }
+@@ -1102,8 +1157,8 @@ static int fr_add_pvc(struct net_device
+ dev->destructor = free_netdev;
+ *get_dev_p(pvc, type) = dev;
+ if (!used) {
+- hdlc->state.fr.dce_changed = 1;
+- hdlc->state.fr.dce_pvc_count++;
++ state(hdlc)->dce_changed = 1;
++ state(hdlc)->dce_pvc_count++;
+ }
+ return 0;
+ }
+@@ -1128,8 +1183,8 @@ static int fr_del_pvc(hdlc_device *hdlc,
+ *get_dev_p(pvc, type) = NULL;
+
+ if (!pvc_is_used(pvc)) {
+- hdlc->state.fr.dce_pvc_count--;
+- hdlc->state.fr.dce_changed = 1;
++ state(hdlc)->dce_pvc_count--;
++ state(hdlc)->dce_changed = 1;
+ }
+ delete_unused_pvcs(hdlc);
+ return 0;
+@@ -1137,14 +1192,13 @@ static int fr_del_pvc(hdlc_device *hdlc,
+
+
+
+-static void fr_destroy(hdlc_device *hdlc)
++static void fr_destroy(struct net_device *frad)
+ {
+- pvc_device *pvc;
+-
+- pvc = hdlc->state.fr.first_pvc;
+- hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
+- hdlc->state.fr.dce_pvc_count = 0;
+- hdlc->state.fr.dce_changed = 1;
++ hdlc_device *hdlc = dev_to_hdlc(frad);
++ pvc_device *pvc = state(hdlc)->first_pvc;
++ state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */
++ state(hdlc)->dce_pvc_count = 0;
++ state(hdlc)->dce_changed = 1;
+
+ while (pvc) {
+ pvc_device *next = pvc->next;
+@@ -1161,8 +1215,17 @@ static void fr_destroy(hdlc_device *hdlc
+ }
+
+
++static struct hdlc_proto proto = {
++ .close = fr_close,
++ .start = fr_start,
++ .stop = fr_stop,
++ .detach = fr_destroy,
++ .ioctl = fr_ioctl,
++ .module = THIS_MODULE,
++};
++
+
+-int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
++static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
+ {
+ fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
+ const size_t size = sizeof(fr_proto);
+@@ -1173,12 +1236,14 @@ int hdlc_fr_ioctl(struct net_device *dev
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
++ if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
++ return -EINVAL;
+ ifr->ifr_settings.type = IF_PROTO_FR;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+- if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
++ if (copy_to_user(fr_s, &state(hdlc)->settings, size))
+ return -EFAULT;
+ return 0;
+
+@@ -1213,20 +1278,16 @@ int hdlc_fr_ioctl(struct net_device *dev
+ if (result)
+ return result;
+
+- if (hdlc->proto.id != IF_PROTO_FR) {
+- hdlc_proto_detach(hdlc);
+- hdlc->state.fr.first_pvc = NULL;
+- hdlc->state.fr.dce_pvc_count = 0;
++ if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
++ result = attach_hdlc_protocol(dev, &proto, fr_rx,
++ sizeof(struct frad_state));
++ if (result)
++ return result;
++ state(hdlc)->first_pvc = NULL;
++ state(hdlc)->dce_pvc_count = 0;
+ }
+- memcpy(&hdlc->state.fr.settings, &new_settings, size);
+- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+-
+- hdlc->proto.close = fr_close;
+- hdlc->proto.start = fr_start;
+- hdlc->proto.stop = fr_stop;
+- hdlc->proto.detach = fr_destroy;
+- hdlc->proto.netif_rx = fr_rx;
+- hdlc->proto.id = IF_PROTO_FR;
++ memcpy(&state(hdlc)->settings, &new_settings, size);
++
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_FRAD;
+@@ -1238,6 +1299,9 @@ int hdlc_fr_ioctl(struct net_device *dev
+ case IF_PROTO_FR_DEL_PVC:
+ case IF_PROTO_FR_ADD_ETH_PVC:
+ case IF_PROTO_FR_DEL_ETH_PVC:
++ if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
++ return -EINVAL;
++
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+@@ -1263,3 +1327,24 @@ int hdlc_fr_ioctl(struct net_device *dev
+
+ return -EINVAL;
+ }
++
++
++static int __init mod_init(void)
++{
++ register_hdlc_protocol(&proto);
++ return 0;
++}
++
++
++static void __exit mod_exit(void)
++{
++ unregister_hdlc_protocol(&proto);
++}
++
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c
+deleted file mode 100644
+index 04ca1f7..0000000
+--- a/drivers/net/wan/hdlc_generic.c
++++ /dev/null
+@@ -1,339 +0,0 @@
+-/*
+- * Generic HDLC support routines for Linux
+- *
+- * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc at pm.waw.pl>
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of version 2 of the GNU General Public License
+- * as published by the Free Software Foundation.
+- *
+- * Currently supported:
+- * * raw IP-in-HDLC
+- * * Cisco HDLC
+- * * Frame Relay with ANSI or CCITT LMI (both user and network side)
+- * * PPP
+- * * X.25
+- *
+- * Use sethdlc utility to set line parameters, protocol and PVCs
+- *
+- * How does it work:
+- * - proto.open(), close(), start(), stop() calls are serialized.
+- * The order is: open, [ start, stop ... ] close ...
+- * - proto.start() and stop() are called with spin_lock_irq held.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/poll.h>
+-#include <linux/errno.h>
+-#include <linux/if_arp.h>
+-#include <linux/init.h>
+-#include <linux/skbuff.h>
+-#include <linux/pkt_sched.h>
+-#include <linux/inetdevice.h>
+-#include <linux/lapb.h>
+-#include <linux/rtnetlink.h>
+-#include <linux/notifier.h>
+-#include <linux/hdlc.h>
+-
+-
+-static const char* version = "HDLC support module revision 1.19";
+-
+-#undef DEBUG_LINK
+-
+-
+-static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
+-{
+- if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+- return -EINVAL;
+- dev->mtu = new_mtu;
+- return 0;
+-}
+-
+-
+-
+-static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
+-{
+- return hdlc_stats(dev);
+-}
+-
+-
+-
+-static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
+- struct packet_type *p, struct net_device *orig_dev)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+- if (hdlc->proto.netif_rx)
+- return hdlc->proto.netif_rx(skb);
+-
+- hdlc->stats.rx_dropped++; /* Shouldn't happen */
+- dev_kfree_skb(skb);
+- return NET_RX_DROP;
+-}
+-
+-
+-
+-static inline void hdlc_proto_start(struct net_device *dev)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+- if (hdlc->proto.start)
+- return hdlc->proto.start(dev);
+-}
+-
+-
+-
+-static inline void hdlc_proto_stop(struct net_device *dev)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+- if (hdlc->proto.stop)
+- return hdlc->proto.stop(dev);
+-}
+-
+-
+-
+-static int hdlc_device_event(struct notifier_block *this, unsigned long event,
+- void *ptr)
+-{
+- struct net_device *dev = ptr;
+- hdlc_device *hdlc;
+- unsigned long flags;
+- int on;
+-
+- if (dev->get_stats != hdlc_get_stats)
+- return NOTIFY_DONE; /* not an HDLC device */
+-
+- if (event != NETDEV_CHANGE)
+- return NOTIFY_DONE; /* Only interrested in carrier changes */
+-
+- on = netif_carrier_ok(dev);
+-
+-#ifdef DEBUG_LINK
+- printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",
+- dev->name, on);
+-#endif
+-
+- hdlc = dev_to_hdlc(dev);
+- spin_lock_irqsave(&hdlc->state_lock, flags);
+-
+- if (hdlc->carrier == on)
+- goto carrier_exit; /* no change in DCD line level */
+-
+- hdlc->carrier = on;
+-
+- if (!hdlc->open)
+- goto carrier_exit;
+-
+- if (hdlc->carrier) {
+- printk(KERN_INFO "%s: Carrier detected\n", dev->name);
+- hdlc_proto_start(dev);
+- } else {
+- printk(KERN_INFO "%s: Carrier lost\n", dev->name);
+- hdlc_proto_stop(dev);
+- }
+-
+-carrier_exit:
+- spin_unlock_irqrestore(&hdlc->state_lock, flags);
+- return NOTIFY_DONE;
+-}
+-
+-
+-
+-/* Must be called by hardware driver when HDLC device is being opened */
+-int hdlc_open(struct net_device *dev)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+-#ifdef DEBUG_LINK
+- printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n",
+- hdlc->carrier, hdlc->open);
+-#endif
+-
+- if (hdlc->proto.id == -1)
+- return -ENOSYS; /* no protocol attached */
+-
+- if (hdlc->proto.open) {
+- int result = hdlc->proto.open(dev);
+- if (result)
+- return result;
+- }
+-
+- spin_lock_irq(&hdlc->state_lock);
+-
+- if (hdlc->carrier) {
+- printk(KERN_INFO "%s: Carrier detected\n", dev->name);
+- hdlc_proto_start(dev);
+- } else
+- printk(KERN_INFO "%s: No carrier\n", dev->name);
+-
+- hdlc->open = 1;
+-
+- spin_unlock_irq(&hdlc->state_lock);
+- return 0;
+-}
+-
+-
+-
+-/* Must be called by hardware driver when HDLC device is being closed */
+-void hdlc_close(struct net_device *dev)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+-#ifdef DEBUG_LINK
+- printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n",
+- hdlc->carrier, hdlc->open);
+-#endif
+-
+- spin_lock_irq(&hdlc->state_lock);
+-
+- hdlc->open = 0;
+- if (hdlc->carrier)
+- hdlc_proto_stop(dev);
+-
+- spin_unlock_irq(&hdlc->state_lock);
+-
+- if (hdlc->proto.close)
+- hdlc->proto.close(dev);
+-}
+-
+-
+-
+-#ifndef CONFIG_HDLC_RAW
+-#define hdlc_raw_ioctl(dev, ifr) -ENOSYS
+-#endif
+-
+-#ifndef CONFIG_HDLC_RAW_ETH
+-#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS
+-#endif
+-
+-#ifndef CONFIG_HDLC_PPP
+-#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS
+-#endif
+-
+-#ifndef CONFIG_HDLC_CISCO
+-#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS
+-#endif
+-
+-#ifndef CONFIG_HDLC_FR
+-#define hdlc_fr_ioctl(dev, ifr) -ENOSYS
+-#endif
+-
+-#ifndef CONFIG_HDLC_X25
+-#define hdlc_x25_ioctl(dev, ifr) -ENOSYS
+-#endif
+-
+-
+-int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+- unsigned int proto;
+-
+- if (cmd != SIOCWANDEV)
+- return -EINVAL;
+-
+- switch(ifr->ifr_settings.type) {
+- case IF_PROTO_HDLC:
+- case IF_PROTO_HDLC_ETH:
+- case IF_PROTO_PPP:
+- case IF_PROTO_CISCO:
+- case IF_PROTO_FR:
+- case IF_PROTO_X25:
+- proto = ifr->ifr_settings.type;
+- break;
+-
+- default:
+- proto = hdlc->proto.id;
+- }
+-
+- switch(proto) {
+- case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
+- case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr);
+- case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr);
+- case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr);
+- case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr);
+- case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
+- default: return -EINVAL;
+- }
+-}
+-
+-void hdlc_setup(struct net_device *dev)
+-{
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+-
+- dev->get_stats = hdlc_get_stats;
+- dev->change_mtu = hdlc_change_mtu;
+- dev->mtu = HDLC_MAX_MTU;
+-
+- dev->type = ARPHRD_RAWHDLC;
+- dev->hard_header_len = 16;
+-
+- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+-
+- hdlc->proto.id = -1;
+- hdlc->proto.detach = NULL;
+- hdlc->carrier = 1;
+- hdlc->open = 0;
+- spin_lock_init(&hdlc->state_lock);
+-}
+-
+-struct net_device *alloc_hdlcdev(void *priv)
+-{
+- struct net_device *dev;
+- dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+- if (dev)
+- dev_to_hdlc(dev)->priv = priv;
+- return dev;
+-}
+-
+-void unregister_hdlc_device(struct net_device *dev)
+-{
+- rtnl_lock();
+- hdlc_proto_detach(dev_to_hdlc(dev));
+- unregister_netdevice(dev);
+- rtnl_unlock();
+-}
+-
+-
+-
+-MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
+-MODULE_DESCRIPTION("HDLC support module");
+-MODULE_LICENSE("GPL v2");
+-
+-EXPORT_SYMBOL(hdlc_open);
+-EXPORT_SYMBOL(hdlc_close);
+-EXPORT_SYMBOL(hdlc_ioctl);
+-EXPORT_SYMBOL(hdlc_setup);
+-EXPORT_SYMBOL(alloc_hdlcdev);
+-EXPORT_SYMBOL(unregister_hdlc_device);
+-
+-static struct packet_type hdlc_packet_type = {
+- .type = __constant_htons(ETH_P_HDLC),
+- .func = hdlc_rcv,
+-};
+-
+-
+-static struct notifier_block hdlc_notifier = {
+- .notifier_call = hdlc_device_event,
+-};
+-
+-
+-static int __init hdlc_module_init(void)
+-{
+- int result;
+-
+- printk(KERN_INFO "%s\n", version);
+- if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0)
+- return result;
+- dev_add_pack(&hdlc_packet_type);
+- return 0;
+-}
+-
+-
+-
+-static void __exit hdlc_module_exit(void)
+-{
+- dev_remove_pack(&hdlc_packet_type);
+- unregister_netdevice_notifier(&hdlc_notifier);
+-}
+-
+-
+-module_init(hdlc_module_init);
+-module_exit(hdlc_module_exit);
+diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
+index fbaab5b..e9f7170 100644
+--- a/drivers/net/wan/hdlc_ppp.c
++++ b/drivers/net/wan/hdlc_ppp.c
+@@ -2,7 +2,7 @@
+ * Generic HDLC support routines for Linux
+ * Point-to-point protocol support
+ *
+- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc at pm.waw.pl>
++ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+@@ -22,6 +22,21 @@
+ #include <linux/lapb.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/hdlc.h>
++#include <net/syncppp.h>
++
++struct ppp_state {
++ struct ppp_device pppdev;
++ struct ppp_device *syncppp_ptr;
++ int (*old_change_mtu)(struct net_device *dev, int new_mtu);
++};
++
++static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
++
++
++static inline struct ppp_state* state(hdlc_device *hdlc)
++{
++ return(struct ppp_state *)(hdlc->state);
++}
+
+
+ static int ppp_open(struct net_device *dev)
+@@ -30,16 +45,16 @@ static int ppp_open(struct net_device *d
+ void *old_ioctl;
+ int result;
+
+- dev->priv = &hdlc->state.ppp.syncppp_ptr;
+- hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
+- hdlc->state.ppp.pppdev.dev = dev;
++ dev->priv = &state(hdlc)->syncppp_ptr;
++ state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
++ state(hdlc)->pppdev.dev = dev;
+
+ old_ioctl = dev->do_ioctl;
+- hdlc->state.ppp.old_change_mtu = dev->change_mtu;
+- sppp_attach(&hdlc->state.ppp.pppdev);
++ state(hdlc)->old_change_mtu = dev->change_mtu;
++ sppp_attach(&state(hdlc)->pppdev);
+ /* sppp_attach nukes them. We don't need syncppp's ioctl */
+ dev->do_ioctl = old_ioctl;
+- hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
++ state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
+ dev->type = ARPHRD_PPP;
+ result = sppp_open(dev);
+ if (result) {
+@@ -59,7 +74,7 @@ static void ppp_close(struct net_device
+ sppp_close(dev);
+ sppp_detach(dev);
+ dev->rebuild_header = NULL;
+- dev->change_mtu = hdlc->state.ppp.old_change_mtu;
++ dev->change_mtu = state(hdlc)->old_change_mtu;
+ dev->mtu = HDLC_MAX_MTU;
+ dev->hard_header_len = 16;
+ }
+@@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_b
+
+
+
+-int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
++static struct hdlc_proto proto = {
++ .open = ppp_open,
++ .close = ppp_close,
++ .type_trans = ppp_type_trans,
++ .ioctl = ppp_ioctl,
++ .module = THIS_MODULE,
++};
++
++
++static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
++ if (dev_to_hdlc(dev)->proto != &proto)
++ return -EINVAL;
+ ifr->ifr_settings.type = IF_PROTO_PPP;
+ return 0; /* return protocol only, no settable parameters */
+
+@@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *de
+ if (result)
+ return result;
+
+- hdlc_proto_detach(hdlc);
+- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+-
+- hdlc->proto.open = ppp_open;
+- hdlc->proto.close = ppp_close;
+- hdlc->proto.type_trans = ppp_type_trans;
+- hdlc->proto.id = IF_PROTO_PPP;
++ result = attach_hdlc_protocol(dev, &proto, NULL,
++ sizeof(struct ppp_state));
++ if (result)
++ return result;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_PPP;
+@@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *de
+
+ return -EINVAL;
+ }
++
++
++static int __init mod_init(void)
++{
++ register_hdlc_protocol(&proto);
++ return 0;
++}
++
++
++
++static void __exit mod_exit(void)
++{
++ unregister_hdlc_protocol(&proto);
++}
++
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("PPP protocol support for generic HDLC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
+index f15aa6b..fe3cae5 100644
+--- a/drivers/net/wan/hdlc_raw.c
++++ b/drivers/net/wan/hdlc_raw.c
+@@ -2,7 +2,7 @@
+ * Generic HDLC support routines for Linux
+ * HDLC support
+ *
+- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc at pm.waw.pl>
++ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+@@ -24,6 +24,8 @@
+ #include <linux/hdlc.h>
+
+
++static int raw_ioctl(struct net_device *dev, struct ifreq *ifr);
++
+ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
+ {
+ return __constant_htons(ETH_P_IP);
+@@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_b
+
+
+
+-int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
++static struct hdlc_proto proto = {
++ .type_trans = raw_type_trans,
++ .ioctl = raw_ioctl,
++ .module = THIS_MODULE,
++};
++
++
++static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
+ {
+ raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
+ const size_t size = sizeof(raw_hdlc_proto);
+@@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *de
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
++ if (dev_to_hdlc(dev)->proto != &proto)
++ return -EINVAL;
+ ifr->ifr_settings.type = IF_PROTO_HDLC;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+- if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
++ if (copy_to_user(raw_s, hdlc->state, size))
+ return -EFAULT;
+ return 0;
+
+@@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *de
+ if (result)
+ return result;
+
+- hdlc_proto_detach(hdlc);
+- memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+-
+- hdlc->proto.type_trans = raw_type_trans;
+- hdlc->proto.id = IF_PROTO_HDLC;
++ result = attach_hdlc_protocol(dev, &proto, NULL,
++ sizeof(raw_hdlc_proto));
++ if (result)
++ return result;
++ memcpy(hdlc->state, &new_settings, size);
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_RAWHDLC;
+@@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *de
+
+ return -EINVAL;
+ }
++
++
++static int __init mod_init(void)
++{
++ register_hdlc_protocol(&proto);
++ return 0;
++}
++
++
++
++static void __exit mod_exit(void)
++{
++ unregister_hdlc_protocol(&proto);
++}
++
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
+index d188498..1a69a9a 100644
+--- a/drivers/net/wan/hdlc_raw_eth.c
++++ b/drivers/net/wan/hdlc_raw_eth.c
+@@ -2,7 +2,7 @@
+ * Generic HDLC support routines for Linux
+ * HDLC Ethernet emulation support
+ *
+- * Copyright (C) 2002-2003 Krzysztof Halasa <khc at pm.waw.pl>
++ * Copyright (C) 2002-2006 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+@@ -25,6 +25,7 @@
+ #include <linux/etherdevice.h>
+ #include <linux/hdlc.h>
+
++static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+ static int eth_tx(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, s
+ }
+
+
+-int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
++static struct hdlc_proto proto = {
++ .type_trans = eth_type_trans,
++ .ioctl = raw_eth_ioctl,
++ .module = THIS_MODULE,
++};
++
++
++static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
+ {
+ raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
+ const size_t size = sizeof(raw_hdlc_proto);
+@@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
++ if (dev_to_hdlc(dev)->proto != &proto)
++ return -EINVAL;
+ ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+- if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
++ if (copy_to_user(raw_s, hdlc->state, size))
+ return -EFAULT;
+ return 0;
+
+@@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device
+ if (result)
+ return result;
+
+- hdlc_proto_detach(hdlc);
+- memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+-
+- hdlc->proto.type_trans = eth_type_trans;
+- hdlc->proto.id = IF_PROTO_HDLC_ETH;
++ result = attach_hdlc_protocol(dev, &proto, NULL,
++ sizeof(raw_hdlc_proto));
++ if (result)
++ return result;
++ memcpy(hdlc->state, &new_settings, size);
+ dev->hard_start_xmit = eth_tx;
+ old_ch_mtu = dev->change_mtu;
+ old_qlen = dev->tx_queue_len;
+@@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device
+
+ return -EINVAL;
+ }
++
++
++static int __init mod_init(void)
++{
++ register_hdlc_protocol(&proto);
++ return 0;
++}
++
++
++
++static void __exit mod_exit(void)
++{
++ unregister_hdlc_protocol(&proto);
++}
++
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
+index a867fb4..e4bb9f8 100644
+--- a/drivers/net/wan/hdlc_x25.c
++++ b/drivers/net/wan/hdlc_x25.c
+@@ -2,7 +2,7 @@
+ * Generic HDLC support routines for Linux
+ * X.25 support
+ *
+- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc at pm.waw.pl>
++ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+@@ -25,6 +25,8 @@
+
+ #include <net/x25device.h>
+
++static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
++
+ /* These functions are callbacks called by LAPB layer */
+
+ static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
+@@ -162,30 +164,39 @@ static void x25_close(struct net_device
+
+ static int x25_rx(struct sk_buff *skb)
+ {
+- hdlc_device *hdlc = dev_to_hdlc(skb->dev);
++ struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
+
+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+- hdlc->stats.rx_dropped++;
++ desc->stats.rx_dropped++;
+ return NET_RX_DROP;
+ }
+
+ if (lapb_data_received(skb->dev, skb) == LAPB_OK)
+ return NET_RX_SUCCESS;
+
+- hdlc->stats.rx_errors++;
++ desc->stats.rx_errors++;
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+
+
++static struct hdlc_proto proto = {
++ .open = x25_open,
++ .close = x25_close,
++ .ioctl = x25_ioctl,
++ .module = THIS_MODULE,
++};
++
+
+-int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
++static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
++ if (dev_to_hdlc(dev)->proto != &proto)
++ return -EINVAL;
+ ifr->ifr_settings.type = IF_PROTO_X25;
+ return 0; /* return protocol only, no settable parameters */
+
+@@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *de
+ if (result)
+ return result;
+
+- hdlc_proto_detach(hdlc);
+- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+-
+- hdlc->proto.open = x25_open;
+- hdlc->proto.close = x25_close;
+- hdlc->proto.netif_rx = x25_rx;
+- hdlc->proto.type_trans = NULL;
+- hdlc->proto.id = IF_PROTO_X25;
++ if ((result = attach_hdlc_protocol(dev, &proto,
++ x25_rx, 0)) != 0)
++ return result;
+ dev->hard_start_xmit = x25_xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_X25;
+@@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *de
+
+ return -EINVAL;
+ }
++
++
++static int __init mod_init(void)
++{
++ register_hdlc_protocol(&proto);
++ return 0;
++}
++
++
++
++static void __exit mod_exit(void)
++{
++ unregister_hdlc_protocol(&proto);
++}
++
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_AUTHOR("Krzysztof Halasa <khc at pm.waw.pl>");
++MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
+index 39f4424..2b54f1b 100644
+--- a/drivers/net/wan/lmc/lmc_main.c
++++ b/drivers/net/wan/lmc/lmc_main.c
+@@ -100,7 +100,7 @@ static int lmc_rx (struct net_device *de
+ static int lmc_open(struct net_device *dev);
+ static int lmc_close(struct net_device *dev);
+ static struct net_device_stats *lmc_get_stats(struct net_device *dev);
+-static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t lmc_interrupt(int irq, void *dev_instance);
+ static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
+ static void lmc_softreset(lmc_softc_t * const);
+ static void lmc_running_reset(struct net_device *dev);
+@@ -1273,7 +1273,7 @@ static int lmc_ifdown (struct net_device
+ /* Interrupt handling routine. This will take an incoming packet, or clean
+ * up after a trasmit.
+ */
+-static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
++static irqreturn_t lmc_interrupt (int irq, void *dev_instance) /*fold00*/
+ {
+ struct net_device *dev = (struct net_device *) dev_instance;
+ lmc_softc_t *sc;
+@@ -1790,7 +1790,7 @@ static struct pci_driver lmc_driver = {
+
+ static int __init init_lmc(void)
+ {
+- return pci_module_init(&lmc_driver);
++ return pci_register_driver(&lmc_driver);
+ }
+
+ static void __exit exit_lmc(void)
+diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
+index dcf46ad..5c322df 100644
+--- a/drivers/net/wan/n2.c
++++ b/drivers/net/wan/n2.c
+@@ -500,7 +500,7 @@ static int __init n2_init(void)
+ #ifdef MODULE
+ printk(KERN_INFO "n2: no card initialized\n");
+ #endif
+- return -ENOSYS; /* no parameters specified, abort */
++ return -EINVAL; /* no parameters specified, abort */
+ }
+
+ printk(KERN_INFO "%s\n", version);
+@@ -538,11 +538,11 @@ static int __init n2_init(void)
+ n2_run(io, irq, ram, valid[0], valid[1]);
+
+ if (*hw == '\x0')
+- return first_card ? 0 : -ENOSYS;
++ return first_card ? 0 : -EINVAL;
+ }while(*hw++ == ':');
+
+ printk(KERN_ERR "n2: invalid hardware parameters\n");
+- return first_card ? 0 : -ENOSYS;
++ return first_card ? 0 : -EINVAL;
+ }
+
+
+diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h
+index 2024b26..63e9fcf 100644
+--- a/drivers/net/wan/pc300.h
++++ b/drivers/net/wan/pc300.h
+@@ -100,6 +100,7 @@
+ #define _PC300_H
+
+ #include <linux/hdlc.h>
++#include <net/syncppp.h>
+ #include "hd64572.h"
+ #include "pc300-falc-lh.h"
+
+diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
+index 567efff..36d1c3f 100644
+--- a/drivers/net/wan/pc300_drv.c
++++ b/drivers/net/wan/pc300_drv.c
+@@ -284,7 +284,7 @@ static void rx_dma_buf_pt_init(pc300_t *
+ static void rx_dma_buf_init(pc300_t *, int);
+ static void tx_dma_buf_check(pc300_t *, int);
+ static void rx_dma_buf_check(pc300_t *, int);
+-static irqreturn_t cpc_intr(int, void *, struct pt_regs *);
++static irqreturn_t cpc_intr(int, void *);
+ static struct net_device_stats *cpc_get_stats(struct net_device *);
+ static int clock_rate_calc(uclong, uclong, int *);
+ static uclong detect_ram(pc300_t *);
+@@ -2016,7 +2016,6 @@ static void sca_intr(pc300_t * card)
+ pc300ch_t *chan = &card->chan[ch];
+ pc300dev_t *d = &chan->d;
+ struct net_device *dev = d->dev;
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+
+ spin_lock(&card->card_lock);
+
+@@ -2049,8 +2048,8 @@ static void sca_intr(pc300_t * card)
+ }
+ cpc_net_rx(dev);
+ /* Discard invalid frames */
+- hdlc->stats.rx_errors++;
+- hdlc->stats.rx_over_errors++;
++ hdlc_stats(dev)->rx_errors++;
++ hdlc_stats(dev)->rx_over_errors++;
+ chan->rx_first_bd = 0;
+ chan->rx_last_bd = N_DMA_RX_BUF - 1;
+ rx_dma_start(card, ch);
+@@ -2116,8 +2115,8 @@ static void sca_intr(pc300_t * card)
+ card->hw.cpld_reg2) &
+ ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
+ }
+- hdlc->stats.tx_errors++;
+- hdlc->stats.tx_fifo_errors++;
++ hdlc_stats(dev)->tx_errors++;
++ hdlc_stats(dev)->tx_fifo_errors++;
+ sca_tx_intr(d);
+ }
+ }
+@@ -2364,7 +2363,7 @@ static void falc_intr(pc300_t * card)
+ }
+ }
+
+-static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cpc_intr(int irq, void *dev_id)
+ {
+ pc300_t *card;
+ volatile ucchar plx_status;
+@@ -2534,7 +2533,6 @@ static int cpc_change_mtu(struct net_dev
+
+ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+ pc300dev_t *d = (pc300dev_t *) dev->priv;
+ pc300ch_t *chan = (pc300ch_t *) d->chan;
+ pc300_t *card = (pc300_t *) chan->card;
+@@ -2552,10 +2550,10 @@ static int cpc_ioctl(struct net_device *
+ case SIOCGPC300CONF:
+ #ifdef CONFIG_PC300_MLPPP
+ if (conf->proto != PC300_PROTO_MLPPP) {
+- conf->proto = hdlc->proto.id;
++ conf->proto = /* FIXME hdlc->proto.id */ 0;
+ }
+ #else
+- conf->proto = hdlc->proto.id;
++ conf->proto = /* FIXME hdlc->proto.id */ 0;
+ #endif
+ memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t));
+ memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t));
+@@ -2588,12 +2586,12 @@ static int cpc_ioctl(struct net_device *
+ }
+ } else {
+ memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
+- hdlc->proto.id = conf->proto;
++ /* FIXME hdlc->proto.id = conf->proto; */
+ }
+ }
+ #else
+ memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
+- hdlc->proto.id = conf->proto;
++ /* FIXME hdlc->proto.id = conf->proto; */
+ #endif
+ return 0;
+ case SIOCGPC300STATUS:
+@@ -2606,7 +2604,7 @@ static int cpc_ioctl(struct net_device *
+ case SIOCGPC300UTILSTATS:
+ {
+ if (!arg) { /* clear statistics */
+- memset(&hdlc->stats, 0, sizeof(struct net_device_stats));
++ memset(hdlc_stats(dev), 0, sizeof(struct net_device_stats));
+ if (card->hw.type == PC300_TE) {
+ memset(&chan->falc, 0, sizeof(falc_t));
+ }
+@@ -2617,7 +2615,7 @@ static int cpc_ioctl(struct net_device *
+ pc300stats.hw_type = card->hw.type;
+ pc300stats.line_on = card->chan[ch].d.line_on;
+ pc300stats.line_off = card->chan[ch].d.line_off;
+- memcpy(&pc300stats.gen_stats, &hdlc->stats,
++ memcpy(&pc300stats.gen_stats, hdlc_stats(dev),
+ sizeof(struct net_device_stats));
+ if (card->hw.type == PC300_TE)
+ memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
+@@ -2869,7 +2867,6 @@ static int ch_config(pc300dev_t * d)
+ uclong clktype = chan->conf.phys_settings.clock_type;
+ ucshort encoding = chan->conf.proto_settings.encoding;
+ ucshort parity = chan->conf.proto_settings.parity;
+- int tmc, br;
+ ucchar md0, md2;
+
+ /* Reset the channel */
+@@ -2942,8 +2939,12 @@ static int ch_config(pc300dev_t * d)
+ case PC300_RSV:
+ case PC300_X21:
+ if (clktype == CLOCK_INT || clktype == CLOCK_TXINT) {
++ int tmc, br;
++
+ /* Calculate the clkrate parameters */
+ tmc = clock_rate_calc(clkrate, card->hw.clock, &br);
++ if (tmc < 0)
++ return -EIO;
+ cpc_writeb(scabase + M_REG(TMCT, ch), tmc);
+ cpc_writeb(scabase + M_REG(TXS, ch),
+ (TXS_DTRXC | TXS_IBRG | br));
+@@ -3099,14 +3100,16 @@ static int cpc_attach(struct net_device
+ return 0;
+ }
+
+-static void cpc_opench(pc300dev_t * d)
++static int cpc_opench(pc300dev_t * d)
+ {
+ pc300ch_t *chan = (pc300ch_t *) d->chan;
+ pc300_t *card = (pc300_t *) chan->card;
+- int ch = chan->channel;
++ int ch = chan->channel, rc;
+ void __iomem *scabase = card->hw.scabase;
+
+- ch_config(d);
++ rc = ch_config(d);
++ if (rc)
++ return rc;
+
+ rx_config(d);
+
+@@ -3115,6 +3118,8 @@ static void cpc_opench(pc300dev_t * d)
+ /* Assert RTS and DTR */
+ cpc_writeb(scabase + M_REG(CTL, ch),
+ cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR));
++
++ return 0;
+ }
+
+ static void cpc_closech(pc300dev_t * d)
+@@ -3147,7 +3152,6 @@ static void cpc_closech(pc300dev_t * d)
+
+ int cpc_open(struct net_device *dev)
+ {
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+ pc300dev_t *d = (pc300dev_t *) dev->priv;
+ struct ifreq ifr;
+ int result;
+@@ -3156,12 +3160,14 @@ int cpc_open(struct net_device *dev)
+ printk("pc300: cpc_open");
+ #endif
+
++#ifdef FIXME
+ if (hdlc->proto.id == IF_PROTO_PPP) {
+ d->if_ptr = &hdlc->state.ppp.pppdev;
+ }
++#endif
+
+ result = hdlc_open(dev);
+- if (hdlc->proto.id == IF_PROTO_PPP) {
++ if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
+ dev->priv = d;
+ }
+ if (result) {
+@@ -3169,14 +3175,20 @@ int cpc_open(struct net_device *dev)
+ }
+
+ sprintf(ifr.ifr_name, "%s", dev->name);
+- cpc_opench(d);
++ result = cpc_opench(d);
++ if (result)
++ goto err_out;
++
+ netif_start_queue(dev);
+ return 0;
++
++err_out:
++ hdlc_close(dev);
++ return result;
+ }
+
+ static int cpc_close(struct net_device *dev)
+ {
+- hdlc_device *hdlc = dev_to_hdlc(dev);
+ pc300dev_t *d = (pc300dev_t *) dev->priv;
+ pc300ch_t *chan = (pc300ch_t *) d->chan;
+ pc300_t *card = (pc300_t *) chan->card;
+@@ -3193,7 +3205,7 @@ static int cpc_close(struct net_device *
+ CPC_UNLOCK(card, flags);
+
+ hdlc_close(dev);
+- if (hdlc->proto.id == IF_PROTO_PPP) {
++ if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
+ d->if_ptr = NULL;
+ }
+ #ifdef CONFIG_PC300_MLPPP
+@@ -3677,7 +3689,7 @@ static struct pci_driver cpc_driver = {
+
+ static int __init cpc_init(void)
+ {
+- return pci_module_init(&cpc_driver);
++ return pci_register_driver(&cpc_driver);
+ }
+
+ static void __exit cpc_cleanup_module(void)
+diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
+index 4df61fa..a6b9c33 100644
+--- a/drivers/net/wan/pci200syn.c
++++ b/drivers/net/wan/pci200syn.c
+@@ -476,7 +476,7 @@ static int __init pci200_init_module(voi
+ printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
+ return -EINVAL;
+ }
+- return pci_module_init(&pci200_pci_driver);
++ return pci_register_driver(&pci200_pci_driver);
+ }
+
+
+diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
+index fc75bec..fc5c0c6 100644
+--- a/drivers/net/wan/sbni.c
++++ b/drivers/net/wan/sbni.c
+@@ -119,7 +119,7 @@ static int sbni_ioctl( struct net_devic
+ static struct net_device_stats *sbni_get_stats( struct net_device * );
+ static void set_multicast_list( struct net_device * );
+
+-static irqreturn_t sbni_interrupt( int, void *, struct pt_regs * );
++static irqreturn_t sbni_interrupt( int, void * );
+ static void handle_channel( struct net_device * );
+ static int recv_frame( struct net_device * );
+ static void send_frame( struct net_device * );
+@@ -501,7 +501,7 @@ sbni_start_xmit( struct sk_buff *skb,
+ */
+
+ static irqreturn_t
+-sbni_interrupt( int irq, void *dev_id, struct pt_regs *regs )
++sbni_interrupt( int irq, void *dev_id )
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct net_local *nl = (struct net_local *) dev->priv;
+diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
+index 7628c2d..6a485f0 100644
+--- a/drivers/net/wan/sdla.c
++++ b/drivers/net/wan/sdla.c
+@@ -32,7 +32,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h> /* for CONFIG_DLCI_MAX */
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+@@ -868,7 +867,7 @@ static void sdla_receive(struct net_devi
+ spin_unlock_irqrestore(&sdla_lock, flags);
+ }
+
+-static irqreturn_t sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t sdla_isr(int irq, void *dev_id)
+ {
+ struct net_device *dev;
+ struct frad_local *flp;
+@@ -876,13 +875,7 @@ static irqreturn_t sdla_isr(int irq, voi
+
+ dev = dev_id;
+
+- if (dev == NULL)
+- {
+- printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
+- flp = dev->priv;
++ flp = netdev_priv(dev);
+
+ if (!flp->initialized)
+ {
+diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
+index c13b459..218f7b5 100644
+--- a/drivers/net/wan/syncppp.c
++++ b/drivers/net/wan/syncppp.c
+@@ -469,7 +469,7 @@ static void sppp_lcp_input (struct sppp
+ struct net_device *dev = sp->pp_if;
+ int len = skb->len;
+ u8 *p, opt[6];
+- u32 rmagic;
++ u32 rmagic = 0;
+
+ if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
+ if (sp->pp_flags & PP_DEBUG)
+@@ -763,7 +763,7 @@ static void sppp_cisco_input (struct spp
+ {
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa;
+- u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
++ __be32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
+ #ifdef CONFIG_INET
+ rcu_read_lock();
+ if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
+diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
+index b2031df..c736015 100644
+--- a/drivers/net/wan/wanxl.c
++++ b/drivers/net/wan/wanxl.c
+@@ -244,7 +244,7 @@ static inline void wanxl_rx_intr(card_t
+
+
+
+-static irqreturn_t wanxl_intr(int irq, void* dev_id, struct pt_regs *regs)
++static irqreturn_t wanxl_intr(int irq, void* dev_id)
+ {
+ card_t *card = dev_id;
+ int i;
+@@ -837,7 +837,7 @@ static int __init wanxl_init_module(void
+ #ifdef MODULE
+ printk(KERN_INFO "%s\n", version);
+ #endif
+- return pci_module_init(&wanxl_pci_driver);
++ return pci_register_driver(&wanxl_pci_driver);
+ }
+
+ static void __exit wanxl_cleanup_module(void)
+diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
+index caa48f1..59ddd21 100644
+--- a/drivers/net/wan/z85230.c
++++ b/drivers/net/wan/z85230.c
+@@ -728,7 +728,7 @@ EXPORT_SYMBOL(z8530_nop);
+ * channel). c->lock for both channels points to dev->lock
+ */
+
+-irqreturn_t z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t z8530_interrupt(int irq, void *dev_id)
+ {
+ struct z8530_dev *dev=dev_id;
+ u8 intr;
+diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
+index 77e5320..158aea7 100644
+--- a/drivers/net/wan/z85230.h
++++ b/drivers/net/wan/z85230.h
+@@ -396,7 +396,7 @@ struct z8530_dev
+ extern u8 z8530_dead_port[];
+ extern u8 z8530_hdlc_kilostream_85230[];
+ extern u8 z8530_hdlc_kilostream[];
+-extern irqreturn_t z8530_interrupt(int, void *, struct pt_regs *);
++extern irqreturn_t z8530_interrupt(int, void *);
+ extern void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io);
+ extern int z8530_init(struct z8530_dev *);
+ extern int z8530_shutdown(struct z8530_dev *);
+diff --git a/drivers/net/wd.c b/drivers/net/wd.c
+index b1ba187..41f1d67 100644
+--- a/drivers/net/wd.c
++++ b/drivers/net/wd.c
+@@ -61,7 +61,7 @@ static void wd_block_output(struct net_d
+ const unsigned char *buf, int start_page);
+ static int wd_close(struct net_device *dev);
+
+-
++
+ #define WD_START_PG 0x00 /* First page of TX buffer */
+ #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
+ #define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
+@@ -75,7 +75,7 @@ static int wd_close(struct net_device *d
+ #define WD_NIC_OFFSET 16 /* Offset to the 8390 from the base_addr. */
+ #define WD_IO_EXTENT 32
+
+-
++
+ /* Probe for the WD8003 and WD8013. These cards have the station
+ address PROM at I/O ports <base>+8 to <base>+13, with a checksum
+ following. A Soundblaster can have the same checksum as an WDethercard,
+@@ -100,7 +100,7 @@ static int __init do_wd_probe(struct net
+ if ( r == NULL)
+ return -EBUSY;
+ i = wd_probe1(dev, base_addr);
+- if (i != 0)
++ if (i != 0)
+ release_region(base_addr, WD_IO_EXTENT);
+ else
+ r->name = dev->name;
+@@ -272,7 +272,7 @@ static int __init wd_probe1(struct net_d
+ a reliable way to trigger an interrupt. */
+ outb_p(E8390_NODMA + E8390_STOP, nic_addr);
+ outb(0x00, nic_addr+EN0_IMR); /* Disable all intrs. */
+-
++
+ irq_mask = probe_irq_on();
+ outb_p(0xff, nic_addr + EN0_IMR); /* Enable all interrupts. */
+ outb_p(0x00, nic_addr + EN0_RCNTLO);
+@@ -280,7 +280,7 @@ static int __init wd_probe1(struct net_d
+ outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
+ mdelay(20);
+ dev->irq = probe_irq_off(irq_mask);
+-
++
+ outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
+
+ if (ei_debug > 2)
+@@ -478,7 +478,7 @@ wd_close(struct net_device *dev)
+ return 0;
+ }
+
+-
++
+ #ifdef MODULE
+ #define MAX_WD_CARDS 4 /* Max number of wd cards per module */
+ static struct net_device *dev_wd[MAX_WD_CARDS];
+diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
+index 2e8ac99..ece3d9c 100644
+--- a/drivers/net/wireless/Kconfig
++++ b/drivers/net/wireless/Kconfig
+@@ -271,25 +271,14 @@ config IPW2200_DEBUG
+ bool "Enable full debugging output in IPW2200 module."
+ depends on IPW2200
+ ---help---
+- This option will enable debug tracing output for the IPW2200.
++ This option will enable low level debug tracing output for IPW2200.
+
+- This will result in the kernel module being ~100k larger. You can
+- control which debug output is sent to the kernel log by setting the
+- value in
+-
+- /sys/bus/pci/drivers/ipw2200/debug_level
+-
+- This entry will only exist if this option is enabled.
++ Note, normal debug code is already compiled in. This low level
++ debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
++ will result in the kernel module being ~70 larger. Most users
++ will typically not need this high verbosity debug information.
+
+- To set a value, simply echo an 8-byte hex value to the same file:
+-
+- % echo 0x00000FFO > /sys/bus/pci/drivers/ipw2200/debug_level
+-
+- You can find the list of debug mask values in
+- drivers/net/wireless/ipw2200.h
+-
+- If you are not trying to debug or develop the IPW2200 driver, you
+- most likely want to say N here.
++ If you are not sure, say N here.
+
+ config AIRO
+ tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
+@@ -312,7 +301,7 @@ config HERMES
+ tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
+ depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA)
+ ---help---
+- A driver for 802.11b wireless cards based based on the "Hermes" or
++ A driver for 802.11b wireless cards based on the "Hermes" or
+ Intersil HFA384x (Prism 2) MAC controller. This includes the vast
+ majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
+ - except for the Cisco/Aironet cards. Cards supported include the
+diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
+index a4dd139..efcdaf1 100644
+--- a/drivers/net/wireless/airo.c
++++ b/drivers/net/wireless/airo.c
+@@ -19,6 +19,7 @@
+
+ ======================================================================*/
+
++#include <linux/err.h>
+ #include <linux/init.h>
+
+ #include <linux/kernel.h>
+@@ -47,6 +48,7 @@
+ #include <linux/pci.h>
+ #include <asm/uaccess.h>
+ #include <net/ieee80211.h>
++#include <linux/kthread.h>
+
+ #include "airo.h"
+
+@@ -1118,8 +1120,7 @@ static void mpi_receive_802_3(struct air
+ static void mpi_receive_802_11(struct airo_info *ai);
+ static int waitbusy (struct airo_info *ai);
+
+-static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
+- *regs);
++static irqreturn_t airo_interrupt( int irq, void* dev_id);
+ static int airo_thread(void *data);
+ static void timer_func( struct net_device *dev );
+ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+@@ -1187,11 +1188,10 @@ struct airo_info {
+ int whichbap);
+ unsigned short *flash;
+ tdsRssiEntry *rssi;
+- struct task_struct *task;
++ struct task_struct *list_bss_task;
++ struct task_struct *airo_thread_task;
+ struct semaphore sem;
+- pid_t thr_pid;
+ wait_queue_head_t thr_wait;
+- struct completion thr_exited;
+ unsigned long expires;
+ struct {
+ struct sk_buff *skb;
+@@ -1203,7 +1203,7 @@ struct airo_info {
+ struct iw_spy_data spy_data;
+ struct iw_public_data wireless_data;
+ /* MIC stuff */
+- struct crypto_tfm *tfm;
++ struct crypto_cipher *tfm;
+ mic_module mod[2];
+ mic_statistics micstats;
+ HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
+@@ -1271,7 +1271,8 @@ static int flashrestart(struct airo_info
+
+ static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
+ static void MoveWindow(miccntx *context, u32 micSeq);
+-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
++static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
++ struct crypto_cipher *tfm);
+ static void emmh32_init(emmh32_context *context);
+ static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
+ static void emmh32_final(emmh32_context *context, u8 digest[4]);
+@@ -1339,10 +1340,11 @@ static int micsetup(struct airo_info *ai
+ int i;
+
+ if (ai->tfm == NULL)
+- ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
++ ai->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
+
+- if (ai->tfm == NULL) {
++ if (IS_ERR(ai->tfm)) {
+ airo_print_err(ai->dev->name, "failed to load transform for AES");
++ ai->tfm = NULL;
+ return ERROR;
+ }
+
+@@ -1608,7 +1610,8 @@ static void MoveWindow(miccntx *context,
+ static unsigned char aes_counter[16];
+
+ /* expand the key to fill the MMH coefficient array */
+-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
++static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
++ struct crypto_cipher *tfm)
+ {
+ /* take the keying material, expand if necessary, truncate at 16-bytes */
+ /* run through AES counter mode to generate context->coeff[] */
+@@ -1616,7 +1619,6 @@ static void emmh32_setseed(emmh32_contex
+ int i,j;
+ u32 counter;
+ u8 *cipher, plain[16];
+- struct scatterlist sg[1];
+
+ crypto_cipher_setkey(tfm, pkey, 16);
+ counter = 0;
+@@ -1627,9 +1629,8 @@ static void emmh32_setseed(emmh32_contex
+ aes_counter[12] = (u8)(counter >> 24);
+ counter++;
+ memcpy (plain, aes_counter, 16);
+- sg_set_buf(sg, plain, 16);
+- crypto_cipher_encrypt(tfm, sg, sg, 16);
+- cipher = kmap(sg->page) + sg->offset;
++ crypto_cipher_encrypt_one(tfm, plain, plain);
++ cipher = plain;
+ for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
+ context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
+ j += 4;
+@@ -1733,12 +1734,12 @@ static int readBSSListRid(struct airo_in
+ cmd.cmd=CMD_LISTBSS;
+ if (down_interruptible(&ai->sem))
+ return -ERESTARTSYS;
++ ai->list_bss_task = current;
+ issuecommand(ai, &cmd, &rsp);
+ up(&ai->sem);
+ /* Let the command take effect */
+- ai->task = current;
+- ssleep(3);
+- ai->task = NULL;
++ schedule_timeout_uninterruptible(3 * HZ);
++ ai->list_bss_task = NULL;
+ }
+ rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
+ list, ai->bssListRidLen, 1);
+@@ -2400,8 +2401,7 @@ void stop_airo_card( struct net_device *
+ clear_bit(FLAG_REGISTERED, &ai->flags);
+ }
+ set_bit(JOB_DIE, &ai->jobs);
+- kill_proc(ai->thr_pid, SIGTERM, 1);
+- wait_for_completion(&ai->thr_exited);
++ kthread_stop(ai->airo_thread_task);
+
+ /*
+ * Clean out tx queue
+@@ -2432,7 +2432,7 @@ void stop_airo_card( struct net_device *
+ ai->shared, ai->shared_dma);
+ }
+ }
+- crypto_free_tfm(ai->tfm);
++ crypto_free_cipher(ai->tfm);
+ del_airo_dev( dev );
+ free_netdev( dev );
+ }
+@@ -2811,9 +2811,8 @@ static struct net_device *_init_airo_car
+ ai->config.len = 0;
+ ai->pci = pci;
+ init_waitqueue_head (&ai->thr_wait);
+- init_completion (&ai->thr_exited);
+- ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
+- if (ai->thr_pid < 0)
++ ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
++ if (IS_ERR(ai->airo_thread_task))
+ goto err_out_free;
+ ai->tfm = NULL;
+ rc = add_airo_dev( dev );
+@@ -2898,6 +2897,8 @@ static struct net_device *_init_airo_car
+ goto err_out_map;
+ }
+ ai->wifidev = init_wifidev(ai, dev);
++ if (!ai->wifidev)
++ goto err_out_reg;
+
+ set_bit(FLAG_REGISTERED,&ai->flags);
+ airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
+@@ -2909,11 +2910,18 @@ static struct net_device *_init_airo_car
+ for( i = 0; i < MAX_FIDS; i++ )
+ ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
+
+- setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
++ if (setup_proc_entry(dev, dev->priv) < 0)
++ goto err_out_wifi;
++
+ netif_start_queue(dev);
+ SET_MODULE_OWNER(dev);
+ return dev;
+
++err_out_wifi:
++ unregister_netdev(ai->wifidev);
++ free_netdev(ai->wifidev);
++err_out_reg:
++ unregister_netdev(dev);
+ err_out_map:
+ if (test_bit(FLAG_MPI,&ai->flags) && pci) {
+ pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
+@@ -2930,8 +2938,7 @@ err_out_unlink:
+ del_airo_dev(dev);
+ err_out_thr:
+ set_bit(JOB_DIE, &ai->jobs);
+- kill_proc(ai->thr_pid, SIGTERM, 1);
+- wait_for_completion(&ai->thr_exited);
++ kthread_stop(ai->airo_thread_task);
+ err_out_free:
+ free_netdev(dev);
+ return NULL;
+@@ -3063,13 +3070,7 @@ static int airo_thread(void *data) {
+ struct airo_info *ai = dev->priv;
+ int locked;
+
+- daemonize("%s", dev->name);
+- allow_signal(SIGTERM);
+-
+ while(1) {
+- if (signal_pending(current))
+- flush_signals(current);
+-
+ /* make swsusp happy with our thread */
+ try_to_freeze();
+
+@@ -3097,7 +3098,8 @@ static int airo_thread(void *data) {
+ set_bit(JOB_AUTOWEP, &ai->jobs);
+ break;
+ }
+- if (!signal_pending(current)) {
++ if (!kthread_should_stop() &&
++ !freezing(current)) {
+ unsigned long wake_at;
+ if (!ai->expires || !ai->scan_timeout) {
+ wake_at = max(ai->expires,
+@@ -3109,7 +3111,8 @@ static int airo_thread(void *data) {
+ schedule_timeout(wake_at - jiffies);
+ continue;
+ }
+- } else if (!signal_pending(current)) {
++ } else if (!kthread_should_stop() &&
++ !freezing(current)) {
+ schedule();
+ continue;
+ }
+@@ -3154,10 +3157,11 @@ static int airo_thread(void *data) {
+ else /* Shouldn't get here, but we make sure to unlock */
+ up(&ai->sem);
+ }
+- complete_and_exit (&ai->thr_exited, 0);
++
++ return 0;
+ }
+
+-static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
++static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
+ struct net_device *dev = (struct net_device *)dev_id;
+ u16 status;
+ u16 fid;
+@@ -3235,8 +3239,8 @@ static irqreturn_t airo_interrupt ( int
+ if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
+ if (auto_wep)
+ apriv->expires = 0;
+- if (apriv->task)
+- wake_up_process (apriv->task);
++ if (apriv->list_bss_task)
++ wake_up_process(apriv->list_bss_task);
+ set_bit(FLAG_UPDATE_UNI, &apriv->flags);
+ set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
+
+@@ -3950,13 +3954,11 @@ static u16 issuecommand(struct airo_info
+ pRsp->rsp0 = IN4500(ai, RESP0);
+ pRsp->rsp1 = IN4500(ai, RESP1);
+ pRsp->rsp2 = IN4500(ai, RESP2);
+- if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
+- airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
+- airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
+- airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
+- airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
+- airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
+- }
++ if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
++ airo_print_err(ai->dev->name,
++ "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
++ pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
++ pRsp->rsp2);
+
+ // clear stuck command busy if necessary
+ if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
+@@ -4504,91 +4506,128 @@ static int setup_proc_entry( struct net_
+ apriv->proc_entry = create_proc_entry(apriv->proc_name,
+ S_IFDIR|airo_perm,
+ airo_entry);
+- apriv->proc_entry->uid = proc_uid;
+- apriv->proc_entry->gid = proc_gid;
+- apriv->proc_entry->owner = THIS_MODULE;
++ if (!apriv->proc_entry)
++ goto fail;
++ apriv->proc_entry->uid = proc_uid;
++ apriv->proc_entry->gid = proc_gid;
++ apriv->proc_entry->owner = THIS_MODULE;
+
+ /* Setup the StatsDelta */
+ entry = create_proc_entry("StatsDelta",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_stats_delta;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_statsdelta_ops);
+
+ /* Setup the Stats */
+ entry = create_proc_entry("Stats",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_stats;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_stats_ops);
+
+ /* Setup the Status */
+ entry = create_proc_entry("Status",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_status;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_status_ops);
+
+ /* Setup the Config */
+ entry = create_proc_entry("Config",
+ S_IFREG | proc_perm,
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_config;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_config_ops);
+
+ /* Setup the SSID */
+ entry = create_proc_entry("SSID",
+ S_IFREG | proc_perm,
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_ssid;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_SSID_ops);
+
+ /* Setup the APList */
+ entry = create_proc_entry("APList",
+ S_IFREG | proc_perm,
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_aplist;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_APList_ops);
+
+ /* Setup the BSSList */
+ entry = create_proc_entry("BSSList",
+ S_IFREG | proc_perm,
+ apriv->proc_entry);
++ if (!entry)
++ goto fail_bsslist;
+ entry->uid = proc_uid;
+ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_BSSList_ops);
+
+ /* Setup the WepKey */
+ entry = create_proc_entry("WepKey",
+ S_IFREG | proc_perm,
+ apriv->proc_entry);
+- entry->uid = proc_uid;
+- entry->gid = proc_gid;
++ if (!entry)
++ goto fail_wepkey;
++ entry->uid = proc_uid;
++ entry->gid = proc_gid;
+ entry->data = dev;
+- entry->owner = THIS_MODULE;
++ entry->owner = THIS_MODULE;
+ SETPROC_OPS(entry, proc_wepkey_ops);
+
+ return 0;
++
++fail_wepkey:
++ remove_proc_entry("BSSList", apriv->proc_entry);
++fail_bsslist:
++ remove_proc_entry("APList", apriv->proc_entry);
++fail_aplist:
++ remove_proc_entry("SSID", apriv->proc_entry);
++fail_ssid:
++ remove_proc_entry("Config", apriv->proc_entry);
++fail_config:
++ remove_proc_entry("Status", apriv->proc_entry);
++fail_status:
++ remove_proc_entry("Stats", apriv->proc_entry);
++fail_stats:
++ remove_proc_entry("StatsDelta", apriv->proc_entry);
++fail_stats_delta:
++ remove_proc_entry(apriv->proc_name, airo_entry);
++fail:
++ return -ENOMEM;
+ }
+
+ static int takedown_proc_entry( struct net_device *dev,
+@@ -5667,25 +5706,40 @@ static int airo_pci_resume(struct pci_de
+
+ static int __init airo_init_module( void )
+ {
+- int i, have_isa_dev = 0;
++ int i;
++#if 0
++ int have_isa_dev = 0;
++#endif
+
+ airo_entry = create_proc_entry("aironet",
+ S_IFDIR | airo_perm,
+ proc_root_driver);
+- airo_entry->uid = proc_uid;
+- airo_entry->gid = proc_gid;
++
++ if (airo_entry) {
++ airo_entry->uid = proc_uid;
++ airo_entry->gid = proc_gid;
++ }
+
+ for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
+ airo_print_info("", "Trying to configure ISA adapter at irq=%d "
+ "io=0x%x", irq[i], io[i] );
+ if (init_airo_card( irq[i], io[i], 0, NULL ))
++#if 0
+ have_isa_dev = 1;
++#else
++ /* do nothing */ ;
++#endif
+ }
+
+ #ifdef CONFIG_PCI
+ airo_print_info("", "Probing for PCI adapters");
+- pci_register_driver(&airo_driver);
++ i = pci_register_driver(&airo_driver);
+ airo_print_info("", "Finished probing for PCI adapters");
++
++ if (i) {
++ remove_proc_entry("aironet", proc_root_driver);
++ return i;
++ }
+ #endif
+
+ /* Always exit with success, as we are a library module
+@@ -5876,7 +5930,7 @@ static int airo_set_essid(struct net_dev
+ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+ /* Check the size of the string */
+- if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
++ if(dwrq->length > IW_ESSID_MAX_SIZE) {
+ return -E2BIG ;
+ }
+ /* Check if index is valid */
+@@ -5888,7 +5942,7 @@ static int airo_set_essid(struct net_dev
+ memset(SSID_rid.ssids[index].ssid, 0,
+ sizeof(SSID_rid.ssids[index].ssid));
+ memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
+- SSID_rid.ssids[index].len = dwrq->length - 1;
++ SSID_rid.ssids[index].len = dwrq->length;
+ }
+ SSID_rid.len = sizeof(SSID_rid);
+ /* Write it to the card */
+@@ -5918,7 +5972,6 @@ static int airo_get_essid(struct net_dev
+
+ /* Get the current SSID */
+ memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
+- extra[status_rid.SSIDlen] = '\0';
+ /* If none, we may want to get the one that was set */
+
+ /* Push it out ! */
+@@ -5998,7 +6051,7 @@ static int airo_set_nick(struct net_devi
+ struct airo_info *local = dev->priv;
+
+ /* Check the size of the string */
+- if(dwrq->length > 16 + 1) {
++ if(dwrq->length > 16) {
+ return -E2BIG;
+ }
+ readConfigRid(local, 1);
+@@ -6023,7 +6076,7 @@ static int airo_get_nick(struct net_devi
+ readConfigRid(local, 1);
+ strncpy(extra, local->config.nodeName, 16);
+ extra[16] = '\0';
+- dwrq->length = strlen(extra) + 1;
++ dwrq->length = strlen(extra);
+
+ return 0;
+ }
+@@ -6775,9 +6828,9 @@ static int airo_set_retry(struct net_dev
+ }
+ readConfigRid(local, 1);
+ if(vwrq->flags & IW_RETRY_LIMIT) {
+- if(vwrq->flags & IW_RETRY_MAX)
++ if(vwrq->flags & IW_RETRY_LONG)
+ local->config.longRetryLimit = vwrq->value;
+- else if (vwrq->flags & IW_RETRY_MIN)
++ else if (vwrq->flags & IW_RETRY_SHORT)
+ local->config.shortRetryLimit = vwrq->value;
+ else {
+ /* No modifier : set both */
+@@ -6813,14 +6866,14 @@ static int airo_get_retry(struct net_dev
+ if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+ vwrq->flags = IW_RETRY_LIFETIME;
+ vwrq->value = (int)local->config.txLifetime * 1024;
+- } else if((vwrq->flags & IW_RETRY_MAX)) {
+- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ } else if((vwrq->flags & IW_RETRY_LONG)) {
++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ vwrq->value = (int)local->config.longRetryLimit;
+ } else {
+ vwrq->flags = IW_RETRY_LIMIT;
+ vwrq->value = (int)local->config.shortRetryLimit;
+ if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
+- vwrq->flags |= IW_RETRY_MIN;
++ vwrq->flags |= IW_RETRY_SHORT;
+ }
+
+ return 0;
+@@ -6998,6 +7051,7 @@ static int airo_set_power(struct net_dev
+ local->config.rmode |= RXMODE_BC_MC_ADDR;
+ set_bit (FLAG_COMMIT, &local->flags);
+ case IW_POWER_ON:
++ /* This is broken, fixme ;-) */
+ break;
+ default:
+ return -EINVAL;
+diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
+index bb6bea4..4688e56 100644
+--- a/drivers/net/wireless/arlan-main.c
++++ b/drivers/net/wireless/arlan-main.c
+@@ -78,7 +78,7 @@ static int arlans_found;
+
+ static int arlan_open(struct net_device *dev);
+ static int arlan_tx(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t arlan_interrupt(int irq, void *dev_id);
+ static int arlan_close(struct net_device *dev);
+ static struct net_device_stats *
+ arlan_statistics (struct net_device *dev);
+@@ -1651,7 +1651,7 @@ end_int_process:
+ return;
+ }
+
+-static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t arlan_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct arlan_private *priv = netdev_priv(dev);
+diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
+index 995c7be..0c07b8b 100644
+--- a/drivers/net/wireless/atmel.c
++++ b/drivers/net/wireless/atmel.c
+@@ -1145,7 +1145,7 @@ next:
+ }
+ }
+
+-static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t service_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct atmel_private *priv = netdev_priv(dev);
+@@ -1656,13 +1656,13 @@ static int atmel_set_essid(struct net_de
+ priv->connect_to_any_BSS = 0;
+
+ /* Check the size of the string */
+- if (dwrq->length > MAX_SSID_LENGTH + 1)
++ if (dwrq->length > MAX_SSID_LENGTH)
+ return -E2BIG;
+ if (index != 0)
+ return -EINVAL;
+
+- memcpy(priv->new_SSID, extra, dwrq->length - 1);
+- priv->new_SSID_size = dwrq->length - 1;
++ memcpy(priv->new_SSID, extra, dwrq->length);
++ priv->new_SSID_size = dwrq->length;
+ }
+
+ return -EINPROGRESS;
+@@ -1678,11 +1678,9 @@ static int atmel_get_essid(struct net_de
+ /* Get the current SSID */
+ if (priv->new_SSID_size != 0) {
+ memcpy(extra, priv->new_SSID, priv->new_SSID_size);
+- extra[priv->new_SSID_size] = '\0';
+ dwrq->length = priv->new_SSID_size;
+ } else {
+ memcpy(extra, priv->SSID, priv->SSID_size);
+- extra[priv->SSID_size] = '\0';
+ dwrq->length = priv->SSID_size;
+ }
+
+@@ -2120,9 +2118,9 @@ static int atmel_set_retry(struct net_de
+ struct atmel_private *priv = netdev_priv(dev);
+
+ if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
+- if (vwrq->flags & IW_RETRY_MAX)
++ if (vwrq->flags & IW_RETRY_LONG)
+ priv->long_retry = vwrq->value;
+- else if (vwrq->flags & IW_RETRY_MIN)
++ else if (vwrq->flags & IW_RETRY_SHORT)
+ priv->short_retry = vwrq->value;
+ else {
+ /* No modifier : set both */
+@@ -2144,15 +2142,15 @@ static int atmel_get_retry(struct net_de
+
+ vwrq->disabled = 0; /* Can't be disabled */
+
+- /* Note : by default, display the min retry number */
+- if (vwrq->flags & IW_RETRY_MAX) {
+- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ /* Note : by default, display the short retry number */
++ if (vwrq->flags & IW_RETRY_LONG) {
++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ vwrq->value = priv->long_retry;
+ } else {
+ vwrq->flags = IW_RETRY_LIMIT;
+ vwrq->value = priv->short_retry;
+ if (priv->long_retry != priv->short_retry)
+- vwrq->flags |= IW_RETRY_MIN;
++ vwrq->flags |= IW_RETRY_SHORT;
+ }
+
+ return 0;
+diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
+index d425c3c..3bfa791 100644
+--- a/drivers/net/wireless/atmel_pci.c
++++ b/drivers/net/wireless/atmel_pci.c
+@@ -76,7 +76,7 @@ static void __devexit atmel_pci_remove(s
+
+ static int __init atmel_init_module(void)
+ {
+- return pci_module_init(&atmel_driver);
++ return pci_register_driver(&atmel_driver);
+ }
+
+ static void __exit atmel_cleanup_module(void)
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
+index 17a5682..d6a8bf0 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
++++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
+@@ -33,14 +33,18 @@
+ #define BCM43xx_PCICFG_ICR 0x94
+
+ /* MMIO offsets */
+-#define BCM43xx_MMIO_DMA1_REASON 0x20
+-#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24
+-#define BCM43xx_MMIO_DMA2_REASON 0x28
+-#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C
+-#define BCM43xx_MMIO_DMA3_REASON 0x30
+-#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34
+-#define BCM43xx_MMIO_DMA4_REASON 0x38
+-#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C
++#define BCM43xx_MMIO_DMA0_REASON 0x20
++#define BCM43xx_MMIO_DMA0_IRQ_MASK 0x24
++#define BCM43xx_MMIO_DMA1_REASON 0x28
++#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x2C
++#define BCM43xx_MMIO_DMA2_REASON 0x30
++#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x34
++#define BCM43xx_MMIO_DMA3_REASON 0x38
++#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x3C
++#define BCM43xx_MMIO_DMA4_REASON 0x40
++#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x44
++#define BCM43xx_MMIO_DMA5_REASON 0x48
++#define BCM43xx_MMIO_DMA5_IRQ_MASK 0x4C
+ #define BCM43xx_MMIO_STATUS_BITFIELD 0x120
+ #define BCM43xx_MMIO_STATUS2_BITFIELD 0x124
+ #define BCM43xx_MMIO_GEN_IRQ_REASON 0x128
+@@ -56,14 +60,27 @@
+ #define BCM43xx_MMIO_XMITSTAT_1 0x174
+ #define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
+ #define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+-#define BCM43xx_MMIO_DMA1_BASE 0x200
+-#define BCM43xx_MMIO_DMA2_BASE 0x220
+-#define BCM43xx_MMIO_DMA3_BASE 0x240
+-#define BCM43xx_MMIO_DMA4_BASE 0x260
++
++/* 32-bit DMA */
++#define BCM43xx_MMIO_DMA32_BASE0 0x200
++#define BCM43xx_MMIO_DMA32_BASE1 0x220
++#define BCM43xx_MMIO_DMA32_BASE2 0x240
++#define BCM43xx_MMIO_DMA32_BASE3 0x260
++#define BCM43xx_MMIO_DMA32_BASE4 0x280
++#define BCM43xx_MMIO_DMA32_BASE5 0x2A0
++/* 64-bit DMA */
++#define BCM43xx_MMIO_DMA64_BASE0 0x200
++#define BCM43xx_MMIO_DMA64_BASE1 0x240
++#define BCM43xx_MMIO_DMA64_BASE2 0x280
++#define BCM43xx_MMIO_DMA64_BASE3 0x2C0
++#define BCM43xx_MMIO_DMA64_BASE4 0x300
++#define BCM43xx_MMIO_DMA64_BASE5 0x340
++/* PIO */
+ #define BCM43xx_MMIO_PIO1_BASE 0x300
+ #define BCM43xx_MMIO_PIO2_BASE 0x310
+ #define BCM43xx_MMIO_PIO3_BASE 0x320
+ #define BCM43xx_MMIO_PIO4_BASE 0x330
++
+ #define BCM43xx_MMIO_PHY_VER 0x3E0
+ #define BCM43xx_MMIO_PHY_RADIO 0x3E2
+ #define BCM43xx_MMIO_ANTENNA 0x3E8
+@@ -233,8 +250,14 @@
+ #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
+
+ /* sbtmstatehigh state flags */
+-#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1
+-#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4
++#define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001
++#define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004
++#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020
++#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
++#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000
++#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000
++#define BCM43xx_SBTMSTATEHIGH_BISTFAILED 0x40000000
++#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
+
+ /* sbimstate flags */
+ #define BCM43xx_SBIMSTATE_IB_ERROR 0x20000
+@@ -283,6 +306,13 @@
+ #define BCM43xx_SBF_TIME_UPDATE 0x10000000
+ #define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
+
++/* Microcode */
++#define BCM43xx_UCODE_REVISION 0x0000
++#define BCM43xx_UCODE_PATCHLEVEL 0x0002
++#define BCM43xx_UCODE_DATE 0x0004
++#define BCM43xx_UCODE_TIME 0x0006
++#define BCM43xx_UCODE_STATUS 0x0040
++
+ /* MicrocodeFlagsBitfield (addr + lo-word values?)*/
+ #define BCM43xx_UCODEFLAGS_OFFSET 0x005E
+
+@@ -504,6 +534,12 @@ struct bcm43xx_phyinfo {
+ * This lock is only used by bcm43xx_phy_{un}lock()
+ */
+ spinlock_t lock;
++
++ /* Firmware. */
++ const struct firmware *ucode;
++ const struct firmware *pcm;
++ const struct firmware *initvals0;
++ const struct firmware *initvals1;
+ };
+
+
+@@ -568,8 +604,11 @@ struct bcm43xx_dma {
+ struct bcm43xx_dmaring *tx_ring1;
+ struct bcm43xx_dmaring *tx_ring2;
+ struct bcm43xx_dmaring *tx_ring3;
++ struct bcm43xx_dmaring *tx_ring4;
++ struct bcm43xx_dmaring *tx_ring5;
++
+ struct bcm43xx_dmaring *rx_ring0;
+- struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
++ struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */
+ };
+
+ /* Data structures for PIO transmission, per 80211 core. */
+@@ -593,12 +632,14 @@ struct bcm43xx_coreinfo {
+ u8 available:1,
+ enabled:1,
+ initialized:1;
+- /** core_id ID number */
+- u16 id;
+ /** core_rev revision number */
+ u8 rev;
+ /** Index number for _switch_core() */
+ u8 index;
++ /** core_id ID number */
++ u16 id;
++ /** Core-specific data. */
++ void *priv;
+ };
+
+ /* Additional information for each 80211 core. */
+@@ -625,7 +666,6 @@ struct bcm43xx_noise_calculation {
+ };
+
+ struct bcm43xx_stats {
+- u8 link_quality;
+ u8 noise;
+ struct iw_statistics wstats;
+ /* Store the last TX/RX times here for updating the leds. */
+@@ -647,7 +687,23 @@ enum {
+ BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
+ };
+ #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
+-#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat))
++#define bcm43xx_set_status(bcm, stat) do { \
++ atomic_set(&(bcm)->init_status, (stat)); \
++ smp_wmb(); \
++ } while (0)
++
++/* *** THEORY OF LOCKING ***
++ *
++ * We have two different locks in the bcm43xx driver.
++ * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
++ * and the device registers. This mutex does _not_ protect
++ * against concurrency from the IRQ handler.
++ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
++ *
++ * Please note that, if you only take the irq_lock, you are not protected
++ * against concurrency from the periodic work handlers.
++ * Most times you want to take _both_ locks.
++ */
+
+ struct bcm43xx_private {
+ struct ieee80211_device *ieee;
+@@ -659,7 +715,6 @@ struct bcm43xx_private {
+
+ void __iomem *mmio_addr;
+
+- /* Locking, see "theory of locking" text below. */
+ spinlock_t irq_lock;
+ struct mutex mutex;
+
+@@ -691,6 +746,7 @@ struct bcm43xx_private {
+ struct bcm43xx_sprominfo sprom;
+ #define BCM43xx_NR_LEDS 4
+ struct bcm43xx_led leds[BCM43xx_NR_LEDS];
++ spinlock_t leds_lock;
+
+ /* The currently active core. */
+ struct bcm43xx_coreinfo *current_core;
+@@ -708,10 +764,6 @@ struct bcm43xx_private {
+ struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
+ /* Additional information, specific to the 80211 cores. */
+ struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
+- /* Index of the current 80211 core. If current_core is not
+- * an 80211 core, this is -1.
+- */
+- int current_80211_core_idx;
+ /* Number of available 80211 cores. */
+ int nr_80211_available;
+
+@@ -719,11 +771,13 @@ struct bcm43xx_private {
+
+ /* Reason code of the last interrupt. */
+ u32 irq_reason;
+- u32 dma_reason[4];
++ u32 dma_reason[6];
+ /* saved irq enable/disable state bitfield. */
+ u32 irq_savedstate;
+ /* Link Quality calculation context. */
+ struct bcm43xx_noise_calculation noisecalc;
++ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
++ int mac_suspended;
+
+ /* Threshold values. */
+ //TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
+@@ -746,12 +800,6 @@ struct bcm43xx_private {
+ struct bcm43xx_key key[54];
+ u8 default_key_idx;
+
+- /* Firmware. */
+- const struct firmware *ucode;
+- const struct firmware *pcm;
+- const struct firmware *initvals0;
+- const struct firmware *initvals1;
+-
+ /* Random Number Generator. */
+ struct hwrng rng;
+ char rng_name[20 + 1];
+@@ -763,55 +811,6 @@ struct bcm43xx_private {
+ };
+
+
+-/* *** THEORY OF LOCKING ***
+- *
+- * We have two different locks in the bcm43xx driver.
+- * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
+- * and the device registers.
+- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+- *
+- * We have three types of helper function pairs to utilize these locks.
+- * (Always use the helper functions.)
+- * 1) bcm43xx_{un}lock_noirq():
+- * Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
+- * so it is almost always unsafe, if device IRQs are enabled.
+- * So only use this, if device IRQs are masked.
+- * Locking may sleep.
+- * You can sleep within the critical section.
+- * 2) bcm43xx_{un}lock_irqonly():
+- * Takes bcm->irq_lock. Does _not_ protect against
+- * bcm43xx_lock_noirq() critical sections.
+- * Does only protect against the IRQ handler path and other
+- * irqonly() critical sections.
+- * Locking does not sleep.
+- * You must not sleep within the critical section.
+- * 3) bcm43xx_{un}lock_irqsafe():
+- * This is the cummulative lock and takes both, mutex and irq_lock.
+- * Protects against noirq() and irqonly() critical sections (and
+- * the IRQ handler path).
+- * Locking may sleep.
+- * You must not sleep within the critical section.
+- */
+-
+-/* Lock type 1 */
+-#define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex)
+-#define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex)
+-/* Lock type 2 */
+-#define bcm43xx_lock_irqonly(bcm, flags) \
+- spin_lock_irqsave(&(bcm)->irq_lock, flags)
+-#define bcm43xx_unlock_irqonly(bcm, flags) \
+- spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
+-/* Lock type 3 */
+-#define bcm43xx_lock_irqsafe(bcm, flags) do { \
+- bcm43xx_lock_noirq(bcm); \
+- bcm43xx_lock_irqonly(bcm, flags); \
+- } while (0)
+-#define bcm43xx_unlock_irqsafe(bcm, flags) do { \
+- bcm43xx_unlock_irqonly(bcm, flags); \
+- bcm43xx_unlock_noirq(bcm); \
+- } while (0)
+-
+-
+ static inline
+ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
+ {
+@@ -863,34 +862,33 @@ int bcm43xx_using_pio(struct bcm43xx_pri
+ * any of these functions.
+ */
+ static inline
++struct bcm43xx_coreinfo_80211 *
++bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
++{
++ assert(bcm->current_core->id == BCM43xx_COREID_80211);
++ return bcm->current_core->priv;
++}
++static inline
+ struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
+ {
+ assert(bcm43xx_using_pio(bcm));
+- assert(bcm->current_80211_core_idx >= 0);
+- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
++ return &(bcm43xx_current_80211_priv(bcm)->pio);
+ }
+ static inline
+ struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
+ {
+ assert(!bcm43xx_using_pio(bcm));
+- assert(bcm->current_80211_core_idx >= 0);
+- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
++ return &(bcm43xx_current_80211_priv(bcm)->dma);
+ }
+ static inline
+ struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
+ {
+- assert(bcm->current_80211_core_idx >= 0);
+- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
++ return &(bcm43xx_current_80211_priv(bcm)->phy);
+ }
+ static inline
+ struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
+ {
+- assert(bcm->current_80211_core_idx >= 0);
+- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
++ return &(bcm43xx_current_80211_priv(bcm)->radio);
+ }
+
+
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+index ce2e40b..b9df06a 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+@@ -54,7 +54,7 @@ static ssize_t write_file_dummy(struct f
+
+ static int open_file_generic(struct inode *inode, struct file *file)
+ {
+- file->private_data = inode->u.generic_ip;
++ file->private_data = inode->i_private;
+ return 0;
+ }
+
+@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct
+
+ down(&big_buffer_sem);
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+ fappend("Board not initialized.\n");
+ goto out;
+@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct
+ fappend("\n");
+
+ out:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ up(&big_buffer_sem);
+ return res;
+@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struc
+ unsigned long flags;
+
+ down(&big_buffer_sem);
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+ fappend("Board not initialized.\n");
+ goto out;
+@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struc
+ fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
+
+ out:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ up(&big_buffer_sem);
+ return res;
+@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file
+ u64 tsf;
+
+ down(&big_buffer_sem);
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+ fappend("Board not initialized.\n");
+ goto out;
+@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file
+ (unsigned int)(tsf & 0xFFFFFFFFULL));
+
+ out:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ up(&big_buffer_sem);
+ return res;
+@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct fil
+ res = -EFAULT;
+ goto out_up;
+ }
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+ printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+ res = -EFAULT;
+@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct fil
+ res = buf_size;
+
+ out_unlock:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ out_up:
+ up(&big_buffer_sem);
+ return res;
+@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct f
+ int i, cnt, j = 0;
+
+ down(&big_buffer_sem);
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+
+ fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
+ BCM43xx_NR_LOGGED_XMITSTATUS);
+@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct f
+ i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+ }
+
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- bcm43xx_lock_irqsafe(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (*ppos == pos) {
+ /* Done. Drop the copied data. */
+ e->xmitstatus_printing = 0;
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
++ up(&big_buffer_sem);
++ return res;
++}
++
++static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct bcm43xx_private *bcm = file->private_data;
++ char *buf = really_big_buffer;
++ ssize_t buf_size;
++ ssize_t res;
++ unsigned long flags;
++
++ buf_size = min(count, sizeof (really_big_buffer) - 1);
++ down(&big_buffer_sem);
++ if (copy_from_user(buf, user_buf, buf_size)) {
++ res = -EFAULT;
++ goto out_up;
++ }
++ mutex_lock(&(bcm)->mutex);
++ spin_lock_irqsave(&(bcm)->irq_lock, flags);
++ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
++ printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
++ res = -EFAULT;
++ goto out_unlock;
++ }
++ if (count > 0 && buf[0] == '1') {
++ bcm43xx_controller_restart(bcm, "manually restarted");
++ res = count;
++ } else
++ res = -EINVAL;
++
++out_unlock:
++ spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
++ mutex_unlock(&(bcm)->mutex);
++out_up:
+ up(&big_buffer_sem);
+ return res;
+ }
+@@ -339,6 +385,11 @@ static struct file_operations txstat_fop
+ .open = open_file_generic,
+ };
+
++static struct file_operations restart_fops = {
++ .write = restart_write_file,
++ .open = open_file_generic,
++};
++
+
+ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
+ {
+@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct b
+ bcm, &txstat_fops);
+ if (!e->dentry_txstat)
+ printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
++ e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
++ bcm, &restart_fops);
++ if (!e->dentry_restart)
++ printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
+ }
+
+ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
+@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struc
+ debugfs_remove(e->dentry_devinfo);
+ debugfs_remove(e->dentry_tsf);
+ debugfs_remove(e->dentry_txstat);
++ debugfs_remove(e->dentry_restart);
+ debugfs_remove(e->subdir);
+ kfree(e->xmitstatus_buffer);
+ kfree(e->xmitstatus_print_buffer);
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+index 50ce267..a40d1af 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
+ struct dentry *dentry_spromdump;
+ struct dentry *dentry_tsf;
+ struct dentry *dentry_txstat;
++ struct dentry *dentry_restart;
+
+ struct bcm43xx_private *bcm;
+
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+index d0318e5..978ed09 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+@@ -4,7 +4,7 @@
+
+ DMA ringbuffer and descriptor allocation/management
+
+- Copyright (c) 2005 Michael Buesch <mbuesch at freenet.de>
++ Copyright (c) 2005, 2006 Michael Buesch <mbuesch at freenet.de>
+
+ Some code in this file is derived from the b44.c driver
+ Copyright (C) 2002 David S. Miller
+@@ -109,6 +109,35 @@ void return_slot(struct bcm43xx_dmaring
+ }
+ }
+
++u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
++{
++ static const u16 map64[] = {
++ BCM43xx_MMIO_DMA64_BASE0,
++ BCM43xx_MMIO_DMA64_BASE1,
++ BCM43xx_MMIO_DMA64_BASE2,
++ BCM43xx_MMIO_DMA64_BASE3,
++ BCM43xx_MMIO_DMA64_BASE4,
++ BCM43xx_MMIO_DMA64_BASE5,
++ };
++ static const u16 map32[] = {
++ BCM43xx_MMIO_DMA32_BASE0,
++ BCM43xx_MMIO_DMA32_BASE1,
++ BCM43xx_MMIO_DMA32_BASE2,
++ BCM43xx_MMIO_DMA32_BASE3,
++ BCM43xx_MMIO_DMA32_BASE4,
++ BCM43xx_MMIO_DMA32_BASE5,
++ };
++
++ if (dma64bit) {
++ assert(controller_idx >= 0 &&
++ controller_idx < ARRAY_SIZE(map64));
++ return map64[controller_idx];
++ }
++ assert(controller_idx >= 0 &&
++ controller_idx < ARRAY_SIZE(map32));
++ return map32[controller_idx];
++}
++
+ static inline
+ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
+ unsigned char *buf,
+@@ -172,7 +201,6 @@ void sync_descbuffer_for_device(struct b
+ /* Unmap and free a descriptor buffer. */
+ static inline
+ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
+- struct bcm43xx_dmadesc *desc,
+ struct bcm43xx_dmadesc_meta *meta,
+ int irq_context)
+ {
+@@ -188,23 +216,13 @@ static int alloc_ringmemory(struct bcm43
+ {
+ struct device *dev = &(ring->bcm->pci_dev->dev);
+
+- ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+- &(ring->dmabase), GFP_KERNEL);
+- if (!ring->vbase) {
++ ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
++ &(ring->dmabase), GFP_KERNEL);
++ if (!ring->descbase) {
+ printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+ return -ENOMEM;
+ }
+- if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
+- printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G "
+- "(0x%llx, len: %lu)\n",
+- (unsigned long long)ring->dmabase,
+- BCM43xx_DMA_RINGMEMSIZE);
+- dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+- ring->vbase, ring->dmabase);
+- return -ENOMEM;
+- }
+- assert(!(ring->dmabase & 0x000003FF));
+- memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
++ memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+
+ return 0;
+ }
+@@ -214,26 +232,34 @@ static void free_ringmemory(struct bcm43
+ struct device *dev = &(ring->bcm->pci_dev->dev);
+
+ dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+- ring->vbase, ring->dmabase);
++ ring->descbase, ring->dmabase);
+ }
+
+ /* Reset the RX DMA channel */
+ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+- u16 mmio_base)
++ u16 mmio_base, int dma64)
+ {
+ int i;
+ u32 value;
++ u16 offset;
+
+- bcm43xx_write32(bcm,
+- mmio_base + BCM43xx_DMA_RX_CONTROL,
+- 0x00000000);
++ offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
++ bcm43xx_write32(bcm, mmio_base + offset, 0);
+ for (i = 0; i < 1000; i++) {
+- value = bcm43xx_read32(bcm,
+- mmio_base + BCM43xx_DMA_RX_STATUS);
+- value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
+- if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
+- i = -1;
+- break;
++ offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
++ value = bcm43xx_read32(bcm, mmio_base + offset);
++ if (dma64) {
++ value &= BCM43xx_DMA64_RXSTAT;
++ if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
++ i = -1;
++ break;
++ }
++ } else {
++ value &= BCM43xx_DMA32_RXSTATE;
++ if (value == BCM43xx_DMA32_RXSTAT_DISABLED) {
++ i = -1;
++ break;
++ }
+ }
+ udelay(10);
+ }
+@@ -247,31 +273,47 @@ int bcm43xx_dmacontroller_rx_reset(struc
+
+ /* Reset the RX DMA channel */
+ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+- u16 mmio_base)
++ u16 mmio_base, int dma64)
+ {
+ int i;
+ u32 value;
++ u16 offset;
+
+ for (i = 0; i < 1000; i++) {
+- value = bcm43xx_read32(bcm,
+- mmio_base + BCM43xx_DMA_TX_STATUS);
+- value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
+- if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
+- value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
+- value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
+- break;
++ offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
++ value = bcm43xx_read32(bcm, mmio_base + offset);
++ if (dma64) {
++ value &= BCM43xx_DMA64_TXSTAT;
++ if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
++ value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
++ value == BCM43xx_DMA64_TXSTAT_STOPPED)
++ break;
++ } else {
++ value &= BCM43xx_DMA32_TXSTATE;
++ if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
++ value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
++ value == BCM43xx_DMA32_TXSTAT_STOPPED)
++ break;
++ }
+ udelay(10);
+ }
+- bcm43xx_write32(bcm,
+- mmio_base + BCM43xx_DMA_TX_CONTROL,
+- 0x00000000);
++ offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
++ bcm43xx_write32(bcm, mmio_base + offset, 0);
+ for (i = 0; i < 1000; i++) {
+- value = bcm43xx_read32(bcm,
+- mmio_base + BCM43xx_DMA_TX_STATUS);
+- value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
+- if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
+- i = -1;
+- break;
++ offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
++ value = bcm43xx_read32(bcm, mmio_base + offset);
++ if (dma64) {
++ value &= BCM43xx_DMA64_TXSTAT;
++ if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
++ i = -1;
++ break;
++ }
++ } else {
++ value &= BCM43xx_DMA32_TXSTATE;
++ if (value == BCM43xx_DMA32_TXSTAT_DISABLED) {
++ i = -1;
++ break;
++ }
+ }
+ udelay(10);
+ }
+@@ -285,47 +327,98 @@ int bcm43xx_dmacontroller_tx_reset(struc
+ return 0;
+ }
+
++static void fill_descriptor(struct bcm43xx_dmaring *ring,
++ struct bcm43xx_dmadesc_generic *desc,
++ dma_addr_t dmaaddr,
++ u16 bufsize,
++ int start, int end, int irq)
++{
++ int slot;
++
++ slot = bcm43xx_dma_desc2idx(ring, desc);
++ assert(slot >= 0 && slot < ring->nr_slots);
++
++ if (ring->dma64) {
++ u32 ctl0 = 0, ctl1 = 0;
++ u32 addrlo, addrhi;
++ u32 addrext;
++
++ addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
++ addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
++ addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
++ addrhi |= ring->routing;
++ if (slot == ring->nr_slots - 1)
++ ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
++ if (start)
++ ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
++ if (end)
++ ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
++ if (irq)
++ ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
++ ctl1 |= (bufsize - ring->frameoffset)
++ & BCM43xx_DMA64_DCTL1_BYTECNT;
++ ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
++ & BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
++
++ desc->dma64.control0 = cpu_to_le32(ctl0);
++ desc->dma64.control1 = cpu_to_le32(ctl1);
++ desc->dma64.address_low = cpu_to_le32(addrlo);
++ desc->dma64.address_high = cpu_to_le32(addrhi);
++ } else {
++ u32 ctl;
++ u32 addr;
++ u32 addrext;
++
++ addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
++ addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
++ >> BCM43xx_DMA32_ROUTING_SHIFT;
++ addr |= ring->routing;
++ ctl = (bufsize - ring->frameoffset)
++ & BCM43xx_DMA32_DCTL_BYTECNT;
++ if (slot == ring->nr_slots - 1)
++ ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
++ if (start)
++ ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
++ if (end)
++ ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
++ if (irq)
++ ctl |= BCM43xx_DMA32_DCTL_IRQ;
++ ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
++ & BCM43xx_DMA32_DCTL_ADDREXT_MASK;
++
++ desc->dma32.control = cpu_to_le32(ctl);
++ desc->dma32.address = cpu_to_le32(addr);
++ }
++}
++
+ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
+- struct bcm43xx_dmadesc *desc,
++ struct bcm43xx_dmadesc_generic *desc,
+ struct bcm43xx_dmadesc_meta *meta,
+ gfp_t gfp_flags)
+ {
+ struct bcm43xx_rxhdr *rxhdr;
++ struct bcm43xx_hwxmitstatus *xmitstat;
+ dma_addr_t dmaaddr;
+- u32 desc_addr;
+- u32 desc_ctl;
+- const int slot = (int)(desc - ring->vbase);
+ struct sk_buff *skb;
+
+- assert(slot >= 0 && slot < ring->nr_slots);
+ assert(!ring->tx);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+- if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
+- unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+- dev_kfree_skb_any(skb);
+- printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G "
+- "(0x%llx, len: %u)\n",
+- (unsigned long long)dmaaddr, ring->rx_buffersize);
+- return -ENOMEM;
+- }
+ meta->skb = skb;
+ meta->dmaaddr = dmaaddr;
+ skb->dev = ring->bcm->net_dev;
+- desc_addr = (u32)(dmaaddr + ring->memoffset);
+- desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
+- (u32)(ring->rx_buffersize - ring->frameoffset));
+- if (slot == ring->nr_slots - 1)
+- desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+- set_desc_addr(desc, desc_addr);
+- set_desc_ctl(desc, desc_ctl);
++
++ fill_descriptor(ring, desc, dmaaddr,
++ ring->rx_buffersize, 0, 0, 0);
+
+ rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
+ rxhdr->frame_length = 0;
+ rxhdr->flags1 = 0;
++ xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
++ xmitstat->cookie = 0;
+
+ return 0;
+ }
+@@ -336,17 +429,17 @@ static int setup_rx_descbuffer(struct bc
+ static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
+ {
+ int i, err = -ENOMEM;
+- struct bcm43xx_dmadesc *desc;
++ struct bcm43xx_dmadesc_generic *desc;
+ struct bcm43xx_dmadesc_meta *meta;
+
+ for (i = 0; i < ring->nr_slots; i++) {
+- desc = ring->vbase + i;
+- meta = ring->meta + i;
++ desc = bcm43xx_dma_idx2desc(ring, i, &meta);
+
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+ if (err)
+ goto err_unwind;
+ }
++ mb();
+ ring->used_slots = ring->nr_slots;
+ err = 0;
+ out:
+@@ -354,8 +447,7 @@ out:
+
+ err_unwind:
+ for (i--; i >= 0; i--) {
+- desc = ring->vbase + i;
+- meta = ring->meta + i;
++ desc = bcm43xx_dma_idx2desc(ring, i, &meta);
+
+ unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+ dev_kfree_skb(meta->skb);
+@@ -371,27 +463,67 @@ static int dmacontroller_setup(struct bc
+ {
+ int err = 0;
+ u32 value;
++ u32 addrext;
+
+ if (ring->tx) {
+- /* Set Transmit Control register to "transmit enable" */
+- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+- BCM43xx_DMA_TXCTRL_ENABLE);
+- /* Set Transmit Descriptor ring address. */
+- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
+- ring->dmabase + ring->memoffset);
++ if (ring->dma64) {
++ u64 ringbase = (u64)(ring->dmabase);
++
++ addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
++ value = BCM43xx_DMA64_TXENABLE;
++ value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
++ & BCM43xx_DMA64_TXADDREXT_MASK;
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
++ (ringbase & 0xFFFFFFFF));
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
++ ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
++ | ring->routing);
++ } else {
++ u32 ringbase = (u32)(ring->dmabase);
++
++ addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
++ value = BCM43xx_DMA32_TXENABLE;
++ value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
++ & BCM43xx_DMA32_TXADDREXT_MASK;
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
++ (ringbase & ~BCM43xx_DMA32_ROUTING)
++ | ring->routing);
++ }
+ } else {
+ err = alloc_initial_descbuffers(ring);
+ if (err)
+ goto out;
+- /* Set Receive Control "receive enable" and frame offset */
+- value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
+- value |= BCM43xx_DMA_RXCTRL_ENABLE;
+- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
+- /* Set Receive Descriptor ring address. */
+- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
+- ring->dmabase + ring->memoffset);
+- /* Init the descriptor pointer. */
+- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
++ if (ring->dma64) {
++ u64 ringbase = (u64)(ring->dmabase);
++
++ addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
++ value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
++ value |= BCM43xx_DMA64_RXENABLE;
++ value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
++ & BCM43xx_DMA64_RXADDREXT_MASK;
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
++ (ringbase & 0xFFFFFFFF));
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
++ ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
++ | ring->routing);
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
++ } else {
++ u32 ringbase = (u32)(ring->dmabase);
++
++ addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
++ value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
++ value |= BCM43xx_DMA32_RXENABLE;
++ value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
++ & BCM43xx_DMA32_RXADDREXT_MASK;
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
++ (ringbase & ~BCM43xx_DMA32_ROUTING)
++ | ring->routing);
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
++ }
+ }
+
+ out:
+@@ -402,27 +534,32 @@ out:
+ static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
+ {
+ if (ring->tx) {
+- bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
+- /* Zero out Transmit Descriptor ring address. */
+- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
++ bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
++ if (ring->dma64) {
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
++ } else
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
+ } else {
+- bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
+- /* Zero out Receive Descriptor ring address. */
+- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
++ bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
++ if (ring->dma64) {
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
++ } else
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
+ }
+ }
+
+ static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
+ {
+- struct bcm43xx_dmadesc *desc;
++ struct bcm43xx_dmadesc_generic *desc;
+ struct bcm43xx_dmadesc_meta *meta;
+ int i;
+
+ if (!ring->used_slots)
+ return;
+ for (i = 0; i < ring->nr_slots; i++) {
+- desc = ring->vbase + i;
+- meta = ring->meta + i;
++ desc = bcm43xx_dma_idx2desc(ring, i, &meta);
+
+ if (!meta->skb) {
+ assert(ring->tx);
+@@ -430,62 +567,67 @@ static void free_all_descbuffers(struct
+ }
+ if (ring->tx) {
+ unmap_descbuffer(ring, meta->dmaaddr,
+- meta->skb->len, 1);
++ meta->skb->len, 1);
+ } else {
+ unmap_descbuffer(ring, meta->dmaaddr,
+- ring->rx_buffersize, 0);
++ ring->rx_buffersize, 0);
+ }
+- free_descriptor_buffer(ring, desc, meta, 0);
++ free_descriptor_buffer(ring, meta, 0);
+ }
+ }
+
+ /* Main initialization function. */
+ static
+ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
+- u16 dma_controller_base,
+- int nr_descriptor_slots,
+- int tx)
++ int controller_index,
++ int for_tx,
++ int dma64)
+ {
+ struct bcm43xx_dmaring *ring;
+ int err;
++ int nr_slots;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out;
+
+- ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
++ nr_slots = BCM43xx_RXRING_SLOTS;
++ if (for_tx)
++ nr_slots = BCM43xx_TXRING_SLOTS;
++
++ ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta),
+ GFP_KERNEL);
+ if (!ring->meta)
+ goto err_kfree_ring;
+
+- ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
++ ring->routing = BCM43xx_DMA32_CLIENTTRANS;
++ if (dma64)
++ ring->routing = BCM43xx_DMA64_CLIENTTRANS;
+ #ifdef CONFIG_BCM947XX
+ if (bcm->pci_dev->bus->number == 0)
+- ring->memoffset = 0;
++ ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
+ #endif
+
+ ring->bcm = bcm;
+- ring->nr_slots = nr_descriptor_slots;
++ ring->nr_slots = nr_slots;
+ ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
+ ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
+ assert(ring->suspend_mark < ring->resume_mark);
+- ring->mmio_base = dma_controller_base;
+- if (tx) {
++ ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index);
++ ring->index = controller_index;
++ ring->dma64 = !!dma64;
++ if (for_tx) {
+ ring->tx = 1;
+ ring->current_slot = -1;
+ } else {
+- switch (dma_controller_base) {
+- case BCM43xx_MMIO_DMA1_BASE:
+- ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
+- ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
+- break;
+- case BCM43xx_MMIO_DMA4_BASE:
+- ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
+- ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
+- break;
+- default:
++ if (ring->index == 0) {
++ ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
++ ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
++ } else if (ring->index == 3) {
++ ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
++ ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
++ } else
+ assert(0);
+- }
+ }
+
+ err = alloc_ringmemory(ring);
+@@ -514,7 +656,8 @@ static void bcm43xx_destroy_dmaring(stru
+ if (!ring)
+ return;
+
+- dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
++ dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
++ (ring->dma64) ? "64" : "32",
+ ring->mmio_base,
+ (ring->tx) ? "TX" : "RX",
+ ring->max_used_slots, ring->nr_slots);
+@@ -537,10 +680,15 @@ void bcm43xx_dma_free(struct bcm43xx_pri
+ return;
+ dma = bcm43xx_current_dma(bcm);
+
+- bcm43xx_destroy_dmaring(dma->rx_ring1);
+- dma->rx_ring1 = NULL;
++ bcm43xx_destroy_dmaring(dma->rx_ring3);
++ dma->rx_ring3 = NULL;
+ bcm43xx_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
++
++ bcm43xx_destroy_dmaring(dma->tx_ring5);
++ dma->tx_ring5 = NULL;
++ bcm43xx_destroy_dmaring(dma->tx_ring4);
++ dma->tx_ring4 = NULL;
+ bcm43xx_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ bcm43xx_destroy_dmaring(dma->tx_ring2);
+@@ -556,48 +704,77 @@ int bcm43xx_dma_init(struct bcm43xx_priv
+ struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+ struct bcm43xx_dmaring *ring;
+ int err = -ENOMEM;
++ int dma64 = 0;
++ u64 mask = bcm43xx_get_supported_dma_mask(bcm);
++ int nobits;
++
++ if (mask == DMA_64BIT_MASK) {
++ dma64 = 1;
++ nobits = 64;
++ } else if (mask == DMA_32BIT_MASK)
++ nobits = 32;
++ else
++ nobits = 30;
++ err = pci_set_dma_mask(bcm->pci_dev, mask);
++ err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
++ if (err) {
++#ifdef CONFIG_BCM43XX_PIO
++ printk(KERN_WARNING PFX "DMA not supported on this device."
++ " Falling back to PIO.\n");
++ bcm->__using_pio = 1;
++ return -ENOSYS;
++#else
++ printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
++ "Please recompile the driver with PIO support.\n");
++ return -ENODEV;
++#endif /* CONFIG_BCM43XX_PIO */
++ }
+
+ /* setup TX DMA channels. */
+- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
+- BCM43xx_TXRING_SLOTS, 1);
++ ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
+ if (!ring)
+ goto out;
+ dma->tx_ring0 = ring;
+
+- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
+- BCM43xx_TXRING_SLOTS, 1);
++ ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx0;
+ dma->tx_ring1 = ring;
+
+- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
+- BCM43xx_TXRING_SLOTS, 1);
++ ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx1;
+ dma->tx_ring2 = ring;
+
+- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
+- BCM43xx_TXRING_SLOTS, 1);
++ ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx2;
+ dma->tx_ring3 = ring;
+
+- /* setup RX DMA channels. */
+- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
+- BCM43xx_RXRING_SLOTS, 0);
++ ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx3;
++ dma->tx_ring4 = ring;
++
++ ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
++ if (!ring)
++ goto err_destroy_tx4;
++ dma->tx_ring5 = ring;
++
++ /* setup RX DMA channels. */
++ ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
++ if (!ring)
++ goto err_destroy_tx5;
+ dma->rx_ring0 = ring;
+
+ if (bcm->current_core->rev < 5) {
+- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
+- BCM43xx_RXRING_SLOTS, 0);
++ ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
+ if (!ring)
+ goto err_destroy_rx0;
+- dma->rx_ring1 = ring;
++ dma->rx_ring3 = ring;
+ }
+
+- dprintk(KERN_INFO PFX "DMA initialized\n");
++ dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+ err = 0;
+ out:
+ return err;
+@@ -605,6 +782,12 @@ out:
+ err_destroy_rx0:
+ bcm43xx_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
++err_destroy_tx5:
++ bcm43xx_destroy_dmaring(dma->tx_ring5);
++ dma->tx_ring5 = NULL;
++err_destroy_tx4:
++ bcm43xx_destroy_dmaring(dma->tx_ring4);
++ dma->tx_ring4 = NULL;
+ err_destroy_tx3:
+ bcm43xx_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+@@ -624,7 +807,7 @@ err_destroy_tx0:
+ static u16 generate_cookie(struct bcm43xx_dmaring *ring,
+ int slot)
+ {
+- u16 cookie = 0xF000;
++ u16 cookie = 0x1000;
+
+ /* Use the upper 4 bits of the cookie as
+ * DMA controller ID and store the slot number
+@@ -632,21 +815,25 @@ static u16 generate_cookie(struct bcm43x
+ * Note that the cookie must never be 0, as this
+ * is a special value used in RX path.
+ */
+- switch (ring->mmio_base) {
+- default:
+- assert(0);
+- case BCM43xx_MMIO_DMA1_BASE:
++ switch (ring->index) {
++ case 0:
+ cookie = 0xA000;
+ break;
+- case BCM43xx_MMIO_DMA2_BASE:
++ case 1:
+ cookie = 0xB000;
+ break;
+- case BCM43xx_MMIO_DMA3_BASE:
++ case 2:
+ cookie = 0xC000;
+ break;
+- case BCM43xx_MMIO_DMA4_BASE:
++ case 3:
+ cookie = 0xD000;
+ break;
++ case 4:
++ cookie = 0xE000;
++ break;
++ case 5:
++ cookie = 0xF000;
++ break;
+ }
+ assert(((u16)slot & 0xF000) == 0x0000);
+ cookie |= (u16)slot;
+@@ -675,6 +862,12 @@ struct bcm43xx_dmaring * parse_cookie(st
+ case 0xD000:
+ ring = dma->tx_ring3;
+ break;
++ case 0xE000:
++ ring = dma->tx_ring4;
++ break;
++ case 0xF000:
++ ring = dma->tx_ring5;
++ break;
+ default:
+ assert(0);
+ }
+@@ -687,6 +880,9 @@ struct bcm43xx_dmaring * parse_cookie(st
+ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
+ int slot)
+ {
++ u16 offset;
++ int descsize;
++
+ /* Everything is ready to start. Buffers are DMA mapped and
+ * associated with slots.
+ * "slot" is the last slot of the new frame we want to transmit.
+@@ -694,25 +890,26 @@ static void dmacontroller_poke_tx(struct
+ */
+ wmb();
+ slot = next_slot(ring, slot);
+- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
+- (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
++ offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX;
++ descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64)
++ : sizeof(struct bcm43xx_dmadesc32);
++ bcm43xx_dma_write(ring, offset,
++ (u32)(slot * descsize));
+ }
+
+-static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
+- struct sk_buff *skb,
+- u8 cur_frag)
++static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
++ struct sk_buff *skb,
++ u8 cur_frag)
+ {
+ int slot;
+- struct bcm43xx_dmadesc *desc;
++ struct bcm43xx_dmadesc_generic *desc;
+ struct bcm43xx_dmadesc_meta *meta;
+- u32 desc_ctl;
+- u32 desc_addr;
++ dma_addr_t dmaaddr;
+
+ assert(skb_shinfo(skb)->nr_frags == 0);
+
+ slot = request_slot(ring);
+- desc = ring->vbase + slot;
+- meta = ring->meta + slot;
++ desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
+
+ /* Add a device specific TX header. */
+ assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
+@@ -729,29 +926,14 @@ static int dma_tx_fragment(struct bcm43x
+ generate_cookie(ring, slot));
+
+ meta->skb = skb;
+- meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+- if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
+- return_slot(ring, slot);
+- printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G "
+- "(0x%llx, len: %u)\n",
+- (unsigned long long)meta->dmaaddr, skb->len);
+- return -ENOMEM;
+- }
++ dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
++ meta->dmaaddr = dmaaddr;
+
+- desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
+- desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
+- desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
+- desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
+- (u32)(meta->skb->len - ring->frameoffset));
+- if (slot == ring->nr_slots - 1)
+- desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
++ fill_descriptor(ring, desc, dmaaddr,
++ skb->len, 1, 1, 1);
+
+- set_desc_ctl(desc, desc_ctl);
+- set_desc_addr(desc, desc_addr);
+ /* Now transfer the whole frame. */
+ dmacontroller_poke_tx(ring, slot);
+-
+- return 0;
+ }
+
+ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+@@ -781,7 +963,6 @@ int bcm43xx_dma_tx(struct bcm43xx_privat
+ /* Take skb from ieee80211_txb_free */
+ txb->fragments[i] = NULL;
+ dma_tx_fragment(ring, skb, i);
+- //TODO: handle failure of dma_tx_fragment
+ }
+ ieee80211_txb_free(txb);
+
+@@ -792,23 +973,28 @@ void bcm43xx_dma_handle_xmitstatus(struc
+ struct bcm43xx_xmitstatus *status)
+ {
+ struct bcm43xx_dmaring *ring;
+- struct bcm43xx_dmadesc *desc;
++ struct bcm43xx_dmadesc_generic *desc;
+ struct bcm43xx_dmadesc_meta *meta;
+ int is_last_fragment;
+ int slot;
++ u32 tmp;
+
+ ring = parse_cookie(bcm, status->cookie, &slot);
+ assert(ring);
+ assert(ring->tx);
+- assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
+ while (1) {
+ assert(slot >= 0 && slot < ring->nr_slots);
+- desc = ring->vbase + slot;
+- meta = ring->meta + slot;
++ desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
+
+- is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
++ if (ring->dma64) {
++ tmp = le32_to_cpu(desc->dma64.control0);
++ is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND);
++ } else {
++ tmp = le32_to_cpu(desc->dma32.control);
++ is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND);
++ }
+ unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
+- free_descriptor_buffer(ring, desc, meta, 1);
++ free_descriptor_buffer(ring, meta, 1);
+ /* Everything belonging to the slot is unmapped
+ * and freed, so we can return it.
+ */
+@@ -824,7 +1010,7 @@ void bcm43xx_dma_handle_xmitstatus(struc
+ static void dma_rx(struct bcm43xx_dmaring *ring,
+ int *slot)
+ {
+- struct bcm43xx_dmadesc *desc;
++ struct bcm43xx_dmadesc_generic *desc;
+ struct bcm43xx_dmadesc_meta *meta;
+ struct bcm43xx_rxhdr *rxhdr;
+ struct sk_buff *skb;
+@@ -832,13 +1018,12 @@ static void dma_rx(struct bcm43xx_dmarin
+ int err;
+ dma_addr_t dmaaddr;
+
+- desc = ring->vbase + *slot;
+- meta = ring->meta + *slot;
++ desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
+
+ sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+ skb = meta->skb;
+
+- if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
++ if (ring->index == 3) {
+ /* We received an xmit status. */
+ struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
+ struct bcm43xx_xmitstatus stat;
+@@ -894,8 +1079,7 @@ static void dma_rx(struct bcm43xx_dmarin
+ s32 tmp = len;
+
+ while (1) {
+- desc = ring->vbase + *slot;
+- meta = ring->meta + *slot;
++ desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+@@ -906,8 +1090,8 @@ static void dma_rx(struct bcm43xx_dmarin
+ break;
+ }
+ printkl(KERN_ERR PFX "DMA RX buffer too small "
+- "(len: %u, buffer: %u, nr-dropped: %d)\n",
+- len, ring->rx_buffersize, cnt);
++ "(len: %u, buffer: %u, nr-dropped: %d)\n",
++ len, ring->rx_buffersize, cnt);
+ goto drop;
+ }
+ len -= IEEE80211_FCS_LEN;
+@@ -945,9 +1129,15 @@ void bcm43xx_dma_rx(struct bcm43xx_dmari
+ #endif
+
+ assert(!ring->tx);
+- status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
+- descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
+- current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
++ if (ring->dma64) {
++ status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS);
++ descptr = (status & BCM43xx_DMA64_RXSTATDPTR);
++ current_slot = descptr / sizeof(struct bcm43xx_dmadesc64);
++ } else {
++ status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS);
++ descptr = (status & BCM43xx_DMA32_RXDPTR);
++ current_slot = descptr / sizeof(struct bcm43xx_dmadesc32);
++ }
+ assert(current_slot >= 0 && current_slot < ring->nr_slots);
+
+ slot = ring->current_slot;
+@@ -958,8 +1148,13 @@ void bcm43xx_dma_rx(struct bcm43xx_dmari
+ ring->max_used_slots = used_slots;
+ #endif
+ }
+- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
+- (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
++ if (ring->dma64) {
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX,
++ (u32)(slot * sizeof(struct bcm43xx_dmadesc64)));
++ } else {
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX,
++ (u32)(slot * sizeof(struct bcm43xx_dmadesc32)));
++ }
+ ring->current_slot = slot;
+ }
+
+@@ -967,16 +1162,28 @@ void bcm43xx_dma_tx_suspend(struct bcm43
+ {
+ assert(ring->tx);
+ bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
+- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+- bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
+- | BCM43xx_DMA_TXCTRL_SUSPEND);
++ if (ring->dma64) {
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
++ bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
++ | BCM43xx_DMA64_TXSUSPEND);
++ } else {
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
++ bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
++ | BCM43xx_DMA32_TXSUSPEND);
++ }
+ }
+
+ void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
+ {
+ assert(ring->tx);
+- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+- bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
+- & ~BCM43xx_DMA_TXCTRL_SUSPEND);
++ if (ring->dma64) {
++ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
++ bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
++ & ~BCM43xx_DMA64_TXSUSPEND);
++ } else {
++ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
++ bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
++ & ~BCM43xx_DMA32_TXSUSPEND);
++ }
+ bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
+ }
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
+index b7d7763..d1105e5 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
+@@ -4,6 +4,7 @@
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
+ #include <linux/workqueue.h>
++#include <linux/dma-mapping.h>
+ #include <linux/linkage.h>
+ #include <asm/atomic.h>
+
+@@ -14,63 +15,179 @@
+ #define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13)
+ #define BCM43xx_DMAIRQ_RX_DONE (1 << 16)
+
+-/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
+-#define BCM43xx_DMA_TX_CONTROL 0x00
+-#define BCM43xx_DMA_TX_DESC_RING 0x04
+-#define BCM43xx_DMA_TX_DESC_INDEX 0x08
+-#define BCM43xx_DMA_TX_STATUS 0x0c
+-#define BCM43xx_DMA_RX_CONTROL 0x10
+-#define BCM43xx_DMA_RX_DESC_RING 0x14
+-#define BCM43xx_DMA_RX_DESC_INDEX 0x18
+-#define BCM43xx_DMA_RX_STATUS 0x1c
+-
+-/* DMA controller channel control word values. */
+-#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0)
+-#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1)
+-#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2)
+-#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4)
+-#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0)
+-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe
+-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1
+-#define BCM43xx_DMA_RXCTRL_PIO (1 << 8)
+-/* DMA controller channel status word values. */
+-#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff
+-#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000
+-#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000
+-#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000
+-#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000
+-#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000
+-#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000
+-#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000
+-#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20)
+-#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff
+-#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000
+-#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000
+-#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000
+-#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000
+-#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000
+-#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000
+-#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000
+-
+-/* DMA descriptor control field values. */
+-#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff
+-#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */
+-#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */
+-#define BCM43xx_DMADTOR_FRAMEEND (1 << 30)
+-#define BCM43xx_DMADTOR_FRAMESTART (1 << 31)
++
++/*** 32-bit DMA Engine. ***/
++
++/* 32-bit DMA controller registers. */
++#define BCM43xx_DMA32_TXCTL 0x00
++#define BCM43xx_DMA32_TXENABLE 0x00000001
++#define BCM43xx_DMA32_TXSUSPEND 0x00000002
++#define BCM43xx_DMA32_TXLOOPBACK 0x00000004
++#define BCM43xx_DMA32_TXFLUSH 0x00000010
++#define BCM43xx_DMA32_TXADDREXT_MASK 0x00030000
++#define BCM43xx_DMA32_TXADDREXT_SHIFT 16
++#define BCM43xx_DMA32_TXRING 0x04
++#define BCM43xx_DMA32_TXINDEX 0x08
++#define BCM43xx_DMA32_TXSTATUS 0x0C
++#define BCM43xx_DMA32_TXDPTR 0x00000FFF
++#define BCM43xx_DMA32_TXSTATE 0x0000F000
++#define BCM43xx_DMA32_TXSTAT_DISABLED 0x00000000
++#define BCM43xx_DMA32_TXSTAT_ACTIVE 0x00001000
++#define BCM43xx_DMA32_TXSTAT_IDLEWAIT 0x00002000
++#define BCM43xx_DMA32_TXSTAT_STOPPED 0x00003000
++#define BCM43xx_DMA32_TXSTAT_SUSP 0x00004000
++#define BCM43xx_DMA32_TXERROR 0x000F0000
++#define BCM43xx_DMA32_TXERR_NOERR 0x00000000
++#define BCM43xx_DMA32_TXERR_PROT 0x00010000
++#define BCM43xx_DMA32_TXERR_UNDERRUN 0x00020000
++#define BCM43xx_DMA32_TXERR_BUFREAD 0x00030000
++#define BCM43xx_DMA32_TXERR_DESCREAD 0x00040000
++#define BCM43xx_DMA32_TXACTIVE 0xFFF00000
++#define BCM43xx_DMA32_RXCTL 0x10
++#define BCM43xx_DMA32_RXENABLE 0x00000001
++#define BCM43xx_DMA32_RXFROFF_MASK 0x000000FE
++#define BCM43xx_DMA32_RXFROFF_SHIFT 1
++#define BCM43xx_DMA32_RXDIRECTFIFO 0x00000100
++#define BCM43xx_DMA32_RXADDREXT_MASK 0x00030000
++#define BCM43xx_DMA32_RXADDREXT_SHIFT 16
++#define BCM43xx_DMA32_RXRING 0x14
++#define BCM43xx_DMA32_RXINDEX 0x18
++#define BCM43xx_DMA32_RXSTATUS 0x1C
++#define BCM43xx_DMA32_RXDPTR 0x00000FFF
++#define BCM43xx_DMA32_RXSTATE 0x0000F000
++#define BCM43xx_DMA32_RXSTAT_DISABLED 0x00000000
++#define BCM43xx_DMA32_RXSTAT_ACTIVE 0x00001000
++#define BCM43xx_DMA32_RXSTAT_IDLEWAIT 0x00002000
++#define BCM43xx_DMA32_RXSTAT_STOPPED 0x00003000
++#define BCM43xx_DMA32_RXERROR 0x000F0000
++#define BCM43xx_DMA32_RXERR_NOERR 0x00000000
++#define BCM43xx_DMA32_RXERR_PROT 0x00010000
++#define BCM43xx_DMA32_RXERR_OVERFLOW 0x00020000
++#define BCM43xx_DMA32_RXERR_BUFWRITE 0x00030000
++#define BCM43xx_DMA32_RXERR_DESCREAD 0x00040000
++#define BCM43xx_DMA32_RXACTIVE 0xFFF00000
++
++/* 32-bit DMA descriptor. */
++struct bcm43xx_dmadesc32 {
++ __le32 control;
++ __le32 address;
++} __attribute__((__packed__));
++#define BCM43xx_DMA32_DCTL_BYTECNT 0x00001FFF
++#define BCM43xx_DMA32_DCTL_ADDREXT_MASK 0x00030000
++#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT 16
++#define BCM43xx_DMA32_DCTL_DTABLEEND 0x10000000
++#define BCM43xx_DMA32_DCTL_IRQ 0x20000000
++#define BCM43xx_DMA32_DCTL_FRAMEEND 0x40000000
++#define BCM43xx_DMA32_DCTL_FRAMESTART 0x80000000
++
++/* Address field Routing value. */
++#define BCM43xx_DMA32_ROUTING 0xC0000000
++#define BCM43xx_DMA32_ROUTING_SHIFT 30
++#define BCM43xx_DMA32_NOTRANS 0x00000000
++#define BCM43xx_DMA32_CLIENTTRANS 0x40000000
++
++
++
++/*** 64-bit DMA Engine. ***/
++
++/* 64-bit DMA controller registers. */
++#define BCM43xx_DMA64_TXCTL 0x00
++#define BCM43xx_DMA64_TXENABLE 0x00000001
++#define BCM43xx_DMA64_TXSUSPEND 0x00000002
++#define BCM43xx_DMA64_TXLOOPBACK 0x00000004
++#define BCM43xx_DMA64_TXFLUSH 0x00000010
++#define BCM43xx_DMA64_TXADDREXT_MASK 0x00030000
++#define BCM43xx_DMA64_TXADDREXT_SHIFT 16
++#define BCM43xx_DMA64_TXINDEX 0x04
++#define BCM43xx_DMA64_TXRINGLO 0x08
++#define BCM43xx_DMA64_TXRINGHI 0x0C
++#define BCM43xx_DMA64_TXSTATUS 0x10
++#define BCM43xx_DMA64_TXSTATDPTR 0x00001FFF
++#define BCM43xx_DMA64_TXSTAT 0xF0000000
++#define BCM43xx_DMA64_TXSTAT_DISABLED 0x00000000
++#define BCM43xx_DMA64_TXSTAT_ACTIVE 0x10000000
++#define BCM43xx_DMA64_TXSTAT_IDLEWAIT 0x20000000
++#define BCM43xx_DMA64_TXSTAT_STOPPED 0x30000000
++#define BCM43xx_DMA64_TXSTAT_SUSP 0x40000000
++#define BCM43xx_DMA64_TXERROR 0x14
++#define BCM43xx_DMA64_TXERRDPTR 0x0001FFFF
++#define BCM43xx_DMA64_TXERR 0xF0000000
++#define BCM43xx_DMA64_TXERR_NOERR 0x00000000
++#define BCM43xx_DMA64_TXERR_PROT 0x10000000
++#define BCM43xx_DMA64_TXERR_UNDERRUN 0x20000000
++#define BCM43xx_DMA64_TXERR_TRANSFER 0x30000000
++#define BCM43xx_DMA64_TXERR_DESCREAD 0x40000000
++#define BCM43xx_DMA64_TXERR_CORE 0x50000000
++#define BCM43xx_DMA64_RXCTL 0x20
++#define BCM43xx_DMA64_RXENABLE 0x00000001
++#define BCM43xx_DMA64_RXFROFF_MASK 0x000000FE
++#define BCM43xx_DMA64_RXFROFF_SHIFT 1
++#define BCM43xx_DMA64_RXDIRECTFIFO 0x00000100
++#define BCM43xx_DMA64_RXADDREXT_MASK 0x00030000
++#define BCM43xx_DMA64_RXADDREXT_SHIFT 16
++#define BCM43xx_DMA64_RXINDEX 0x24
++#define BCM43xx_DMA64_RXRINGLO 0x28
++#define BCM43xx_DMA64_RXRINGHI 0x2C
++#define BCM43xx_DMA64_RXSTATUS 0x30
++#define BCM43xx_DMA64_RXSTATDPTR 0x00001FFF
++#define BCM43xx_DMA64_RXSTAT 0xF0000000
++#define BCM43xx_DMA64_RXSTAT_DISABLED 0x00000000
++#define BCM43xx_DMA64_RXSTAT_ACTIVE 0x10000000
++#define BCM43xx_DMA64_RXSTAT_IDLEWAIT 0x20000000
++#define BCM43xx_DMA64_RXSTAT_STOPPED 0x30000000
++#define BCM43xx_DMA64_RXSTAT_SUSP 0x40000000
++#define BCM43xx_DMA64_RXERROR 0x34
++#define BCM43xx_DMA64_RXERRDPTR 0x0001FFFF
++#define BCM43xx_DMA64_RXERR 0xF0000000
++#define BCM43xx_DMA64_RXERR_NOERR 0x00000000
++#define BCM43xx_DMA64_RXERR_PROT 0x10000000
++#define BCM43xx_DMA64_RXERR_UNDERRUN 0x20000000
++#define BCM43xx_DMA64_RXERR_TRANSFER 0x30000000
++#define BCM43xx_DMA64_RXERR_DESCREAD 0x40000000
++#define BCM43xx_DMA64_RXERR_CORE 0x50000000
++
++/* 64-bit DMA descriptor. */
++struct bcm43xx_dmadesc64 {
++ __le32 control0;
++ __le32 control1;
++ __le32 address_low;
++ __le32 address_high;
++} __attribute__((__packed__));
++#define BCM43xx_DMA64_DCTL0_DTABLEEND 0x10000000
++#define BCM43xx_DMA64_DCTL0_IRQ 0x20000000
++#define BCM43xx_DMA64_DCTL0_FRAMEEND 0x40000000
++#define BCM43xx_DMA64_DCTL0_FRAMESTART 0x80000000
++#define BCM43xx_DMA64_DCTL1_BYTECNT 0x00001FFF
++#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK 0x00030000
++#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT 16
++
++/* Address field Routing value. */
++#define BCM43xx_DMA64_ROUTING 0xC0000000
++#define BCM43xx_DMA64_ROUTING_SHIFT 30
++#define BCM43xx_DMA64_NOTRANS 0x00000000
++#define BCM43xx_DMA64_CLIENTTRANS 0x80000000
++
++
++
++struct bcm43xx_dmadesc_generic {
++ union {
++ struct bcm43xx_dmadesc32 dma32;
++ struct bcm43xx_dmadesc64 dma64;
++ } __attribute__((__packed__));
++} __attribute__((__packed__));
++
+
+ /* Misc DMA constants */
+ #define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
+-#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF
+-#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30)
+-#define BCM43xx_DMA1_RX_FRAMEOFFSET 30
+-#define BCM43xx_DMA4_RX_FRAMEOFFSET 0
++#define BCM43xx_DMA0_RX_FRAMEOFFSET 30
++#define BCM43xx_DMA3_RX_FRAMEOFFSET 0
++
+
+ /* DMA engine tuning knobs */
+ #define BCM43xx_TXRING_SLOTS 512
+ #define BCM43xx_RXRING_SLOTS 64
+-#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100)
+-#define BCM43xx_DMA4_RXBUFFERSIZE 16
++#define BCM43xx_DMA0_RX_BUFFERSIZE (2304 + 100)
++#define BCM43xx_DMA3_RX_BUFFERSIZE 16
+ /* Suspend the tx queue, if less than this percent slots are free. */
+ #define BCM43xx_TXSUSPEND_PERCENT 20
+ /* Resume the tx queue, if more than this percent slots are free. */
+@@ -86,17 +203,6 @@ struct bcm43xx_private;
+ struct bcm43xx_xmitstatus;
+
+
+-struct bcm43xx_dmadesc {
+- __le32 _control;
+- __le32 _address;
+-} __attribute__((__packed__));
+-
+-/* Macros to access the bcm43xx_dmadesc struct */
+-#define get_desc_ctl(desc) le32_to_cpu((desc)->_control)
+-#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0)
+-#define get_desc_addr(desc) le32_to_cpu((desc)->_address)
+-#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0)
+-
+ struct bcm43xx_dmadesc_meta {
+ /* The kernel DMA-able buffer. */
+ struct sk_buff *skb;
+@@ -105,15 +211,14 @@ struct bcm43xx_dmadesc_meta {
+ };
+
+ struct bcm43xx_dmaring {
+- struct bcm43xx_private *bcm;
+ /* Kernel virtual base address of the ring memory. */
+- struct bcm43xx_dmadesc *vbase;
+- /* DMA memory offset */
+- dma_addr_t memoffset;
+- /* (Unadjusted) DMA base bus-address of the ring memory. */
+- dma_addr_t dmabase;
++ void *descbase;
+ /* Meta data about all descriptors. */
+ struct bcm43xx_dmadesc_meta *meta;
++ /* DMA Routing value. */
++ u32 routing;
++ /* (Unadjusted) DMA base bus-address of the ring memory. */
++ dma_addr_t dmabase;
+ /* Number of descriptor slots in the ring. */
+ int nr_slots;
+ /* Number of used descriptor slots. */
+@@ -127,12 +232,17 @@ struct bcm43xx_dmaring {
+ u32 frameoffset;
+ /* Descriptor buffer size. */
+ u16 rx_buffersize;
+- /* The MMIO base register of the DMA controller, this
+- * ring is posted to.
+- */
++ /* The MMIO base register of the DMA controller. */
+ u16 mmio_base;
+- u8 tx:1, /* TRUE, if this is a TX ring. */
+- suspended:1; /* TRUE, if transfers are suspended on this ring. */
++ /* DMA controller index number (0-5). */
++ int index;
++ /* Boolean. Is this a TX ring? */
++ u8 tx;
++ /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
++ u8 dma64;
++ /* Boolean. Are transfers suspended on this ring? */
++ u8 suspended;
++ struct bcm43xx_private *bcm;
+ #ifdef CONFIG_BCM43XX_DEBUG
+ /* Maximum number of used slots. */
+ int max_used_slots;
+@@ -141,6 +251,34 @@ struct bcm43xx_dmaring {
+
+
+ static inline
++int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring,
++ struct bcm43xx_dmadesc_generic *desc)
++{
++ if (ring->dma64) {
++ struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
++ return (int)(&(desc->dma64) - dd64);
++ } else {
++ struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
++ return (int)(&(desc->dma32) - dd32);
++ }
++}
++
++static inline
++struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring,
++ int slot,
++ struct bcm43xx_dmadesc_meta **meta)
++{
++ *meta = &(ring->meta[slot]);
++ if (ring->dma64) {
++ struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
++ return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot]));
++ } else {
++ struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
++ return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot]));
++ }
++}
++
++static inline
+ u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
+ u16 offset)
+ {
+@@ -159,9 +297,13 @@ int bcm43xx_dma_init(struct bcm43xx_priv
+ void bcm43xx_dma_free(struct bcm43xx_private *bcm);
+
+ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+- u16 dmacontroller_mmio_base);
++ u16 dmacontroller_mmio_base,
++ int dma64);
+ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+- u16 dmacontroller_mmio_base);
++ u16 dmacontroller_mmio_base,
++ int dma64);
++
++u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+ void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
+ void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
+@@ -173,6 +315,22 @@ int bcm43xx_dma_tx(struct bcm43xx_privat
+ struct ieee80211_txb *txb);
+ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
+
++/* Helper function that returns the dma mask for this device. */
++static inline
++u64 bcm43xx_get_supported_dma_mask(struct bcm43xx_private *bcm)
++{
++ int dma64 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH) &
++ BCM43xx_SBTMSTATEHIGH_DMA64BIT;
++ u16 mmio_base = bcm43xx_dmacontroller_base(dma64, 0);
++ u32 mask = BCM43xx_DMA32_TXADDREXT_MASK;
++
++ if (dma64)
++ return DMA_64BIT_MASK;
++ bcm43xx_write32(bcm, mmio_base + BCM43xx_DMA32_TXCTL, mask);
++ if (bcm43xx_read32(bcm, mmio_base + BCM43xx_DMA32_TXCTL) & mask)
++ return DMA_32BIT_MASK;
++ return DMA_30BIT_MASK;
++}
+
+ #else /* CONFIG_BCM43XX_DMA */
+
+@@ -188,13 +346,15 @@ void bcm43xx_dma_free(struct bcm43xx_pri
+ }
+ static inline
+ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+- u16 dmacontroller_mmio_base)
++ u16 dmacontroller_mmio_base,
++ int dma64)
+ {
+ return 0;
+ }
+ static inline
+ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+- u16 dmacontroller_mmio_base)
++ u16 dmacontroller_mmio_base,
++ int dma64)
+ {
+ return 0;
+ }
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+index e386dcc..c947025 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+@@ -44,7 +44,7 @@ static void bcm43xx_get_drvinfo(struct n
+ strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
+ }
+
+-struct ethtool_ops bcm43xx_ethtool_ops = {
++const struct ethtool_ops bcm43xx_ethtool_ops = {
+ .get_drvinfo = bcm43xx_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ };
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
+index 8137049..6f8d42d 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
+@@ -3,6 +3,6 @@
+
+ #include <linux/ethtool.h>
+
+-extern struct ethtool_ops bcm43xx_ethtool_ops;
++extern const struct ethtool_ops bcm43xx_ethtool_ops;
+
+ #endif /* BCM43xx_ETHTOOL_H_ */
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+index ec80692..7d383a2 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned l
+ struct bcm43xx_private *bcm = led->bcm;
+ unsigned long flags;
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&bcm->leds_lock, flags);
+ if (led->blink_interval) {
+ bcm43xx_led_changestate(led);
+ mod_timer(&led->blink_timer, jiffies + led->blink_interval);
+ }
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->leds_lock, flags);
+ }
+
+ static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
+@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_
+ int i, turn_on;
+ unsigned long interval = 0;
+ u16 ledctl;
++ unsigned long flags;
+
++ spin_lock_irqsave(&bcm->leds_lock, flags);
+ ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+ for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+ led = &(bcm->leds[i]);
+@@ -187,20 +189,24 @@ void bcm43xx_leds_update(struct bcm43xx_
+ case BCM43xx_LED_INACTIVE:
+ continue;
+ case BCM43xx_LED_OFF:
++ case BCM43xx_LED_BCM4303_3:
+ break;
+ case BCM43xx_LED_ON:
+ turn_on = 1;
+ break;
+ case BCM43xx_LED_ACTIVITY:
++ case BCM43xx_LED_BCM4303_0:
+ turn_on = activity;
+ break;
+ case BCM43xx_LED_RADIO_ALL:
+ turn_on = radio->enabled;
+ break;
+ case BCM43xx_LED_RADIO_A:
++ case BCM43xx_LED_BCM4303_2:
+ turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+ break;
+ case BCM43xx_LED_RADIO_B:
++ case BCM43xx_LED_BCM4303_1:
+ turn_on = (radio->enabled &&
+ (phy->type == BCM43xx_PHYTYPE_B ||
+ phy->type == BCM43xx_PHYTYPE_G));
+@@ -240,7 +246,7 @@ void bcm43xx_leds_update(struct bcm43xx_
+ //TODO
+ break;
+ case BCM43xx_LED_ASSOC:
+- if (bcm->softmac->associated)
++ if (bcm->softmac->associnfo.associated)
+ turn_on = 1;
+ break;
+ #ifdef CONFIG_BCM43XX_DEBUG
+@@ -255,7 +261,8 @@ void bcm43xx_leds_update(struct bcm43xx_
+ continue;
+ #endif /* CONFIG_BCM43XX_DEBUG */
+ default:
+- assert(0);
++ dprintkl(KERN_INFO PFX "Bad value in leds_update,"
++ " led->behaviour: 0x%x\n", led->behaviour);
+ };
+
+ if (led->activelow)
+@@ -266,6 +273,7 @@ void bcm43xx_leds_update(struct bcm43xx_
+ ledctl &= ~(1 << i);
+ }
+ bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
++ spin_unlock_irqrestore(&bcm->leds_lock, flags);
+ }
+
+ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
+@@ -274,7 +282,9 @@ void bcm43xx_leds_switch_all(struct bcm4
+ u16 ledctl;
+ int i;
+ int bit_on;
++ unsigned long flags;
+
++ spin_lock_irqsave(&bcm->leds_lock, flags);
+ ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+ for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+ led = &(bcm->leds[i]);
+@@ -290,4 +300,5 @@ void bcm43xx_leds_switch_all(struct bcm4
+ ledctl &= ~(1 << i);
+ }
+ bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
++ spin_unlock_irqrestore(&bcm->leds_lock, flags);
+ }
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
+index d3716cf..811e14a 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
+@@ -46,6 +46,12 @@ enum { /* LED behaviour values */
+ BCM43xx_LED_TEST_BLINKSLOW,
+ BCM43xx_LED_TEST_BLINKMEDIUM,
+ BCM43xx_LED_TEST_BLINKFAST,
++
++ /* Misc values for BCM4303 */
++ BCM43xx_LED_BCM4303_0 = 0x2B,
++ BCM43xx_LED_BCM4303_1 = 0x78,
++ BCM43xx_LED_BCM4303_2 = 0x2E,
++ BCM43xx_LED_BCM4303_3 = 0x19,
+ };
+
+ int bcm43xx_leds_init(struct bcm43xx_private *bcm);
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+index df317c1..65edb56 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+@@ -509,23 +509,20 @@ static void bcm43xx_synchronize_irq(stru
+ }
+
+ /* Make sure we don't receive more data from the device. */
+-static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
++static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
+ {
+ unsigned long flags;
+- u32 old;
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ return -EBUSY;
+ }
+- old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+- bcm43xx_unlock_irqonly(bcm, flags);
++ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
++ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ bcm43xx_synchronize_irq(bcm);
+
+- if (oldstate)
+- *oldstate = old;
+-
+ return 0;
+ }
+
+@@ -537,7 +534,6 @@ static int bcm43xx_read_radioinfo(struct
+ u16 manufact;
+ u16 version;
+ u8 revision;
+- s8 i;
+
+ if (bcm->chip_id == 0x4317) {
+ if (bcm->chip_rev == 0x00)
+@@ -580,20 +576,11 @@ static int bcm43xx_read_radioinfo(struct
+ radio->version = version;
+ radio->revision = revision;
+
+- /* Set default attenuation values. */
+- radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+- radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+- radio->txctl1 = bcm43xx_default_txctl1(bcm);
+- radio->txctl2 = 0xFFFF;
+ if (phy->type == BCM43xx_PHYTYPE_A)
+ radio->txpower_desired = bcm->sprom.maxpower_aphy;
+ else
+ radio->txpower_desired = bcm->sprom.maxpower_bgphy;
+
+- /* Initialize the in-memory nrssi Lookup Table. */
+- for (i = 0; i < 64; i++)
+- radio->nrssi_lt[i] = i;
+-
+ return 0;
+
+ err_unsupported_radio:
+@@ -1250,10 +1237,6 @@ int bcm43xx_switch_core(struct bcm43xx_p
+ goto out;
+
+ bcm->current_core = new_core;
+- bcm->current_80211_core_idx = -1;
+- if (new_core->id == BCM43xx_COREID_80211)
+- bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
+-
+ out:
+ return err;
+ }
+@@ -1389,6 +1372,7 @@ void bcm43xx_wireless_core_reset(struct
+ if ((bcm43xx_core_enabled(bcm)) &&
+ !bcm43xx_using_pio(bcm)) {
+ //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
++#if 0
+ #ifndef CONFIG_BCM947XX
+ /* reset all used DMA controllers. */
+ bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
+@@ -1399,6 +1383,7 @@ void bcm43xx_wireless_core_reset(struct
+ if (bcm->current_core->rev < 5)
+ bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
+ #endif
++#endif
+ }
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+@@ -1423,43 +1408,23 @@ static void bcm43xx_wireless_core_disabl
+ bcm43xx_core_disable(bcm, 0);
+ }
+
+-/* Mark the current 80211 core inactive.
+- * "active_80211_core" is the other 80211 core, which is used.
+- */
+-static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
+- struct bcm43xx_coreinfo *active_80211_core)
++/* Mark the current 80211 core inactive. */
++static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
+ {
+ u32 sbtmstatelow;
+- struct bcm43xx_coreinfo *old_core;
+- int err = 0;
+
+ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ bcm43xx_radio_turn_off(bcm);
+ sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+- sbtmstatelow &= ~0x200a0000;
+- sbtmstatelow |= 0xa0000;
++ sbtmstatelow &= 0xDFF5FFFF;
++ sbtmstatelow |= 0x000A0000;
+ bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+ udelay(1);
+ sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+- sbtmstatelow &= ~0xa0000;
+- sbtmstatelow |= 0x80000;
++ sbtmstatelow &= 0xFFF5FFFF;
++ sbtmstatelow |= 0x00080000;
+ bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+ udelay(1);
+-
+- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
+- old_core = bcm->current_core;
+- err = bcm43xx_switch_core(bcm, active_80211_core);
+- if (err)
+- goto out;
+- sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+- sbtmstatelow &= ~0x20000000;
+- sbtmstatelow |= 0x20000000;
+- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+- err = bcm43xx_switch_core(bcm, old_core);
+- }
+-
+-out:
+- return err;
+ }
+
+ static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
+@@ -1581,17 +1546,7 @@ static void handle_irq_noise(struct bcm4
+ else
+ average -= 48;
+
+-/* FIXME: This is wrong, but people want fancy stats. well... */
+-bcm->stats.noise = average;
+- if (average > -65)
+- bcm->stats.link_quality = 0;
+- else if (average > -75)
+- bcm->stats.link_quality = 1;
+- else if (average > -85)
+- bcm->stats.link_quality = 2;
+- else
+- bcm->stats.link_quality = 3;
+-// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
++ bcm->stats.noise = average;
+ drop_calculation:
+ bcm->noisecalc.calculation_running = 0;
+ return;
+@@ -1709,8 +1664,9 @@ static void handle_irq_beacon(struct bcm
+ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
+ {
+ u32 reason;
+- u32 dma_reason[4];
+- int activity = 0;
++ u32 dma_reason[6];
++ u32 merged_dma_reason = 0;
++ int i, activity = 0;
+ unsigned long flags;
+
+ #ifdef CONFIG_BCM43XX_DEBUG
+@@ -1720,12 +1676,12 @@ static void bcm43xx_interrupt_tasklet(st
+ # define bcmirq_handled(irq) do { /* nothing */ } while (0)
+ #endif /* CONFIG_BCM43XX_DEBUG*/
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ reason = bcm->irq_reason;
+- dma_reason[0] = bcm->dma_reason[0];
+- dma_reason[1] = bcm->dma_reason[1];
+- dma_reason[2] = bcm->dma_reason[2];
+- dma_reason[3] = bcm->dma_reason[3];
++ for (i = 5; i >= 0; i--) {
++ dma_reason[i] = bcm->dma_reason[i];
++ merged_dma_reason |= dma_reason[i];
++ }
+
+ if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
+ /* TX error. We get this when Template Ram is written in wrong endianess
+@@ -1736,27 +1692,25 @@ static void bcm43xx_interrupt_tasklet(st
+ printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
+ bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
+ }
+- if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
+- (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
+- (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
+- (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
++ if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {
+ printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
+- "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
++ "0x%08X, 0x%08X, 0x%08X, "
++ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+- dma_reason[2], dma_reason[3]);
++ dma_reason[2], dma_reason[3],
++ dma_reason[4], dma_reason[5]);
+ bcm43xx_controller_restart(bcm, "DMA error");
+ mmiowb();
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ return;
+ }
+- if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
+- (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
+- (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
+- (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
++ if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {
+ printkl(KERN_ERR PFX "DMA error: "
+- "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
++ "0x%08X, 0x%08X, 0x%08X, "
++ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+- dma_reason[2], dma_reason[3]);
++ dma_reason[2], dma_reason[3],
++ dma_reason[4], dma_reason[5]);
+ }
+
+ if (reason & BCM43xx_IRQ_PS) {
+@@ -1791,8 +1745,6 @@ static void bcm43xx_interrupt_tasklet(st
+ }
+
+ /* Check the DMA reason registers for received data. */
+- assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
+- assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
+ if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
+@@ -1800,13 +1752,17 @@ static void bcm43xx_interrupt_tasklet(st
+ bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
+ /* We intentionally don't set "activity" to 1, here. */
+ }
++ assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
++ assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
+ if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
+ else
+- bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
++ bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);
+ activity = 1;
+ }
++ assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));
++ assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));
+ bcmirq_handled(BCM43xx_IRQ_RX);
+
+ if (reason & BCM43xx_IRQ_XMIT_STATUS) {
+@@ -1834,7 +1790,7 @@ static void bcm43xx_interrupt_tasklet(st
+ bcm43xx_leds_update(bcm, activity);
+ bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+ mmiowb();
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ }
+
+ static void pio_irq_workaround(struct bcm43xx_private *bcm,
+@@ -1863,18 +1819,22 @@ static void bcm43xx_interrupt_ack(struct
+
+ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
+
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,
+ bcm->dma_reason[0]);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
+ bcm->dma_reason[1]);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
+ bcm->dma_reason[2]);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
+ bcm->dma_reason[3]);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
++ bcm->dma_reason[4]);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,
++ bcm->dma_reason[5]);
+ }
+
+ /* Interrupt handler top-half */
+-static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id)
+ {
+ irqreturn_t ret = IRQ_HANDLED;
+ struct bcm43xx_private *bcm = dev_id;
+@@ -1885,14 +1845,8 @@ static irqreturn_t bcm43xx_interrupt_han
+
+ spin_lock(&bcm->irq_lock);
+
+- /* Only accept IRQs, if we are initialized properly.
+- * This avoids an RX race while initializing.
+- * We should probably not enable IRQs before we are initialized
+- * completely, but some careful work is needed to fix this. I think it
+- * is best to stay with this cheap workaround for now... .
+- */
+- if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
+- goto out;
++ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
++ assert(bcm->current_core->id == BCM43xx_COREID_80211);
+
+ reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+ if (reason == 0xffffffff) {
+@@ -1904,14 +1858,18 @@ static irqreturn_t bcm43xx_interrupt_han
+ if (!reason)
+ goto out;
+
+- bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+- & 0x0001dc00;
+- bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+- & 0x0000dc00;
+- bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+- & 0x0000dc00;
+- bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+- & 0x0001dc00;
++ bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
++ & 0x0001DC00;
++ bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
++ & 0x0000DC00;
++ bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
++ & 0x0000DC00;
++ bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
++ & 0x0001DC00;
++ bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
++ & 0x0000DC00;
++ bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)
++ & 0x0000DC00;
+
+ bcm43xx_interrupt_ack(bcm, reason);
+
+@@ -1930,16 +1888,18 @@ out:
+
+ static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
+ {
++ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
++
+ if (bcm->firmware_norelease && !force)
+ return; /* Suspending or controller reset. */
+- release_firmware(bcm->ucode);
+- bcm->ucode = NULL;
+- release_firmware(bcm->pcm);
+- bcm->pcm = NULL;
+- release_firmware(bcm->initvals0);
+- bcm->initvals0 = NULL;
+- release_firmware(bcm->initvals1);
+- bcm->initvals1 = NULL;
++ release_firmware(phy->ucode);
++ phy->ucode = NULL;
++ release_firmware(phy->pcm);
++ phy->pcm = NULL;
++ release_firmware(phy->initvals0);
++ phy->initvals0 = NULL;
++ release_firmware(phy->initvals1);
++ phy->initvals1 = NULL;
+ }
+
+ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
+@@ -1950,11 +1910,11 @@ static int bcm43xx_request_firmware(stru
+ int nr;
+ char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
+
+- if (!bcm->ucode) {
++ if (!phy->ucode) {
+ snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
+ (rev >= 5 ? 5 : rev),
+ modparam_fwpostfix);
+- err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
++ err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
+ if (err) {
+ printk(KERN_ERR PFX
+ "Error: Microcode \"%s\" not available or load failed.\n",
+@@ -1963,12 +1923,12 @@ static int bcm43xx_request_firmware(stru
+ }
+ }
+
+- if (!bcm->pcm) {
++ if (!phy->pcm) {
+ snprintf(buf, ARRAY_SIZE(buf),
+ "bcm43xx_pcm%d%s.fw",
+ (rev < 5 ? 4 : 5),
+ modparam_fwpostfix);
+- err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
++ err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
+ if (err) {
+ printk(KERN_ERR PFX
+ "Error: PCM \"%s\" not available or load failed.\n",
+@@ -1977,7 +1937,7 @@ static int bcm43xx_request_firmware(stru
+ }
+ }
+
+- if (!bcm->initvals0) {
++ if (!phy->initvals0) {
+ if (rev == 2 || rev == 4) {
+ switch (phy->type) {
+ case BCM43xx_PHYTYPE_A:
+@@ -2008,20 +1968,20 @@ static int bcm43xx_request_firmware(stru
+ snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
+ nr, modparam_fwpostfix);
+
+- err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
++ err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
+ if (err) {
+ printk(KERN_ERR PFX
+ "Error: InitVals \"%s\" not available or load failed.\n",
+ buf);
+ goto error;
+ }
+- if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
++ if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
+ printk(KERN_ERR PFX "InitVals fileformat error.\n");
+ goto error;
+ }
+ }
+
+- if (!bcm->initvals1) {
++ if (!phy->initvals1) {
+ if (rev >= 5) {
+ u32 sbtmstatehigh;
+
+@@ -2043,14 +2003,14 @@ static int bcm43xx_request_firmware(stru
+ snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
+ nr, modparam_fwpostfix);
+
+- err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
++ err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
+ if (err) {
+ printk(KERN_ERR PFX
+ "Error: InitVals \"%s\" not available or load failed.\n",
+ buf);
+ goto error;
+ }
+- if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
++ if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
+ printk(KERN_ERR PFX "InitVals fileformat error.\n");
+ goto error;
+ }
+@@ -2070,12 +2030,13 @@ err_noinitval:
+
+ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
+ {
++ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ const u32 *data;
+ unsigned int i, len;
+
+ /* Upload Microcode. */
+- data = (u32 *)(bcm->ucode->data);
+- len = bcm->ucode->size / sizeof(u32);
++ data = (u32 *)(phy->ucode->data);
++ len = phy->ucode->size / sizeof(u32);
+ bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
+ for (i = 0; i < len; i++) {
+ bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
+@@ -2084,8 +2045,8 @@ static void bcm43xx_upload_microcode(str
+ }
+
+ /* Upload PCM data. */
+- data = (u32 *)(bcm->pcm->data);
+- len = bcm->pcm->size / sizeof(u32);
++ data = (u32 *)(phy->pcm->data);
++ len = phy->pcm->size / sizeof(u32);
+ bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
+ bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
+@@ -2131,15 +2092,16 @@ err_format:
+
+ static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
+ {
++ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ int err;
+
+- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
+- bcm->initvals0->size / sizeof(struct bcm43xx_initval));
++ err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
++ phy->initvals0->size / sizeof(struct bcm43xx_initval));
+ if (err)
+ goto out;
+- if (bcm->initvals1) {
+- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
+- bcm->initvals1->size / sizeof(struct bcm43xx_initval));
++ if (phy->initvals1) {
++ err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
++ phy->initvals1->size / sizeof(struct bcm43xx_initval));
+ if (err)
+ goto out;
+ }
+@@ -2156,9 +2118,7 @@ static struct pci_device_id bcm43xx_47xx
+
+ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
+ {
+- int res;
+- unsigned int i;
+- u32 data;
++ int err;
+
+ bcm->irq = bcm->pci_dev->irq;
+ #ifdef CONFIG_BCM947XX
+@@ -2175,32 +2135,12 @@ static int bcm43xx_initialize_irq(struct
+ }
+ }
+ #endif
+- res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
++ err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+ IRQF_SHARED, KBUILD_MODNAME, bcm);
+- if (res) {
++ if (err)
+ printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
+- return -ENODEV;
+- }
+- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+- i = 0;
+- while (1) {
+- data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+- if (data == BCM43xx_IRQ_READY)
+- break;
+- i++;
+- if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+- printk(KERN_ERR PFX "Card IRQ register not responding. "
+- "Giving up.\n");
+- free_irq(bcm->irq, bcm);
+- return -ENODEV;
+- }
+- udelay(10);
+- }
+- // dummy read
+- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+
+- return 0;
++ return err;
+ }
+
+ /* Switch to the core used to write the GPIO register.
+@@ -2298,13 +2238,17 @@ static int bcm43xx_gpio_cleanup(struct b
+ /* http://bcm-specs.sipsolutions.net/EnableMac */
+ void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
+ {
+- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+- | BCM43xx_SBF_MAC_ENABLED);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+- bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
++ bcm->mac_suspended--;
++ assert(bcm->mac_suspended >= 0);
++ if (bcm->mac_suspended == 0) {
++ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
++ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
++ | BCM43xx_SBF_MAC_ENABLED);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
++ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
++ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
++ bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
++ }
+ }
+
+ /* http://bcm-specs.sipsolutions.net/SuspendMAC */
+@@ -2313,18 +2257,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_
+ int i;
+ u32 tmp;
+
+- bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+- & ~BCM43xx_SBF_MAC_ENABLED);
+- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+- for (i = 100000; i; i--) {
+- tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+- if (tmp & BCM43xx_IRQ_READY)
+- return;
+- udelay(10);
++ assert(bcm->mac_suspended >= 0);
++ if (bcm->mac_suspended == 0) {
++ bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
++ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
++ & ~BCM43xx_SBF_MAC_ENABLED);
++ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
++ for (i = 10000; i; i--) {
++ tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
++ if (tmp & BCM43xx_IRQ_READY)
++ goto out;
++ udelay(1);
++ }
++ printkl(KERN_ERR PFX "MAC suspend failed\n");
+ }
+- printkl(KERN_ERR PFX "MAC suspend failed\n");
++out:
++ bcm->mac_suspended++;
+ }
+
+ void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
+@@ -2394,7 +2343,6 @@ static void bcm43xx_chip_cleanup(struct
+ if (!modparam_noleds)
+ bcm43xx_leds_exit(bcm);
+ bcm43xx_gpio_cleanup(bcm);
+- free_irq(bcm->irq, bcm);
+ bcm43xx_release_firmware(bcm, 0);
+ }
+
+@@ -2406,7 +2354,7 @@ static int bcm43xx_chip_init(struct bcm4
+ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ int err;
+- int tmp;
++ int i, tmp;
+ u32 value32;
+ u16 value16;
+
+@@ -2419,13 +2367,54 @@ static int bcm43xx_chip_init(struct bcm4
+ goto out;
+ bcm43xx_upload_microcode(bcm);
+
+- err = bcm43xx_initialize_irq(bcm);
+- if (err)
++ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
++ i = 0;
++ while (1) {
++ value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
++ if (value32 == BCM43xx_IRQ_READY)
++ break;
++ i++;
++ if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
++ printk(KERN_ERR PFX "IRQ_READY timeout\n");
++ err = -ENODEV;
++ goto err_release_fw;
++ }
++ udelay(10);
++ }
++ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
++
++ value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_REVISION);
++
++ dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "
++ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", value16,
++ bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_PATCHLEVEL),
++ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_DATE) >> 12) & 0xf,
++ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_DATE) >> 8) & 0xf,
++ bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_DATE) & 0xff,
++ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_TIME) >> 11) & 0x1f,
++ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_TIME) >> 5) & 0x3f,
++ bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_TIME) & 0x1f);
++
++ if ( value16 > 0x128 ) {
++ printk(KERN_ERR PFX
++ "Firmware: no support for microcode extracted "
++ "from version 4.x binary drivers.\n");
++ err = -EOPNOTSUPP;
+ goto err_release_fw;
++ }
+
+ err = bcm43xx_gpio_init(bcm);
+ if (err)
+- goto err_free_irq;
++ goto err_release_fw;
+
+ err = bcm43xx_upload_initvals(bcm);
+ if (err)
+@@ -2489,10 +2478,12 @@ static int bcm43xx_chip_init(struct bcm4
+ bcm43xx_write32(bcm, 0x018C, 0x02000000);
+ }
+ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
+- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
++ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+ value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+ value32 |= 0x00100000;
+@@ -2509,8 +2500,6 @@ err_radio_off:
+ bcm43xx_radio_turn_off(bcm);
+ err_gpio_cleanup:
+ bcm43xx_gpio_cleanup(bcm);
+-err_free_irq:
+- free_irq(bcm->irq, bcm);
+ err_release_fw:
+ bcm43xx_release_firmware(bcm, 1);
+ goto out;
+@@ -2550,11 +2539,9 @@ static void bcm43xx_init_struct_phyinfo(
+ {
+ /* Initialize a "phyinfo" structure. The structure is already
+ * zeroed out.
++ * This is called on insmod time to initialize members.
+ */
+- phy->antenna_diversity = 0xFFFF;
+ phy->savedpctlreg = 0xFFFF;
+- phy->minlowsig[0] = 0xFFFF;
+- phy->minlowsig[1] = 0xFFFF;
+ spin_lock_init(&phy->lock);
+ }
+
+@@ -2562,14 +2549,11 @@ static void bcm43xx_init_struct_radioinf
+ {
+ /* Initialize a "radioinfo" structure. The structure is already
+ * zeroed out.
++ * This is called on insmod time to initialize members.
+ */
+ radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
+ radio->channel = 0xFF;
+ radio->initial_channel = 0xFF;
+- radio->lofcal = 0xFFFF;
+- radio->initval = 0xFFFF;
+- radio->nrssi[0] = -1000;
+- radio->nrssi[1] = -1000;
+ }
+
+ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
+@@ -2587,7 +2571,6 @@ static int bcm43xx_probe_cores(struct bc
+ * BCM43xx_MAX_80211_CORES);
+ memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
+ * BCM43xx_MAX_80211_CORES);
+- bcm->current_80211_core_idx = -1;
+ bcm->nr_80211_available = 0;
+ bcm->current_core = NULL;
+ bcm->active_80211_core = NULL;
+@@ -2757,6 +2740,7 @@ static int bcm43xx_probe_cores(struct bc
+ goto out;
+ }
+ bcm->nr_80211_available++;
++ core->priv = ext_80211;
+ bcm43xx_init_struct_phyinfo(&ext_80211->phy);
+ bcm43xx_init_struct_radioinfo(&ext_80211->radio);
+ break;
+@@ -2857,7 +2841,8 @@ static void bcm43xx_wireless_core_cleanu
+ }
+
+ /* http://bcm-specs.sipsolutions.net/80211Init */
+-static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
++static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
++ int active_wlcore)
+ {
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+@@ -2939,19 +2924,29 @@ static int bcm43xx_wireless_core_init(st
+ if (bcm->current_core->rev >= 5)
+ bcm43xx_write16(bcm, 0x043C, 0x000C);
+
+- if (bcm43xx_using_pio(bcm))
+- err = bcm43xx_pio_init(bcm);
+- else
+- err = bcm43xx_dma_init(bcm);
+- if (err)
+- goto err_chip_cleanup;
++ if (active_wlcore) {
++ if (bcm43xx_using_pio(bcm)) {
++ err = bcm43xx_pio_init(bcm);
++ } else {
++ err = bcm43xx_dma_init(bcm);
++ if (err == -ENOSYS)
++ err = bcm43xx_pio_init(bcm);
++ }
++ if (err)
++ goto err_chip_cleanup;
++ }
+ bcm43xx_write16(bcm, 0x0612, 0x0050);
+ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
+ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
+
+- bcm43xx_mac_enable(bcm);
+- bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
++ if (active_wlcore) {
++ if (radio->initial_channel != 0xFF)
++ bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
++ }
+
++ /* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
++ * We enable it later.
++ */
+ bcm->current_core->initialized = 1;
+ out:
+ return err;
+@@ -3066,11 +3061,6 @@ out:
+ return err;
+ }
+
+-static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
+-{
+- ieee80211softmac_start(bcm->net_dev);
+-}
+-
+ static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
+ {
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+@@ -3173,56 +3163,67 @@ static int estimate_periodic_work_badnes
+ static void bcm43xx_periodic_work_handler(void *d)
+ {
+ struct bcm43xx_private *bcm = d;
++ struct net_device *net_dev = bcm->net_dev;
+ unsigned long flags;
+ u32 savedirqs = 0;
+ int badness;
++ unsigned long orig_trans_start = 0;
+
++ mutex_lock(&bcm->mutex);
+ badness = estimate_periodic_work_badness(bcm->periodic_state);
+ if (badness > BADNESS_LIMIT) {
+ /* Periodic work will take a long time, so we want it to
+ * be preemtible.
+ */
+- bcm43xx_lock_irqonly(bcm, flags);
+- netif_stop_queue(bcm->net_dev);
++
++ netif_tx_lock_bh(net_dev);
++ /* We must fake a started transmission here, as we are going to
++ * disable TX. If we wouldn't fake a TX, it would be possible to
++ * trigger the netdev watchdog, if the last real TX is already
++ * some time on the past (slightly less than 5secs)
++ */
++ orig_trans_start = net_dev->trans_start;
++ net_dev->trans_start = jiffies;
++ netif_stop_queue(net_dev);
++ netif_tx_unlock_bh(net_dev);
++
++ spin_lock_irqsave(&bcm->irq_lock, flags);
++ bcm43xx_mac_suspend(bcm);
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_freeze_txqueues(bcm);
+ savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+- bcm43xx_unlock_irqonly(bcm, flags);
+- bcm43xx_lock_noirq(bcm);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ bcm43xx_synchronize_irq(bcm);
+ } else {
+ /* Periodic work should take short time, so we want low
+ * locking overhead.
+ */
+- bcm43xx_lock_irqsafe(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ }
+
+ do_periodic_work(bcm);
+
+ if (badness > BADNESS_LIMIT) {
+- bcm43xx_lock_irqonly(bcm, flags);
+- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
+- tasklet_enable(&bcm->isr_tasklet);
+- bcm43xx_interrupt_enable(bcm, savedirqs);
+- if (bcm43xx_using_pio(bcm))
+- bcm43xx_pio_thaw_txqueues(bcm);
+- }
++ spin_lock_irqsave(&bcm->irq_lock, flags);
++ tasklet_enable(&bcm->isr_tasklet);
++ bcm43xx_interrupt_enable(bcm, savedirqs);
++ if (bcm43xx_using_pio(bcm))
++ bcm43xx_pio_thaw_txqueues(bcm);
++ bcm43xx_mac_enable(bcm);
+ netif_wake_queue(bcm->net_dev);
+- mmiowb();
+- bcm43xx_unlock_irqonly(bcm, flags);
+- bcm43xx_unlock_noirq(bcm);
+- } else {
+- mmiowb();
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ net_dev->trans_start = orig_trans_start;
+ }
++ mmiowb();
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ }
+
+-static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
++void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
+ {
+ cancel_rearming_delayed_work(&bcm->periodic_work);
+ }
+
+-static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
++void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
+ {
+ struct work_struct *work = &(bcm->periodic_work);
+
+@@ -3243,9 +3244,9 @@ static int bcm43xx_rng_read(struct hwrng
+ struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
+ unsigned long flags;
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&(bcm)->irq_lock, flags);
+ *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+
+ return (sizeof(u16));
+ }
+@@ -3271,139 +3272,329 @@ static int bcm43xx_rng_init(struct bcm43
+ return err;
+ }
+
+-/* This is the opposite of bcm43xx_init_board() */
+-static void bcm43xx_free_board(struct bcm43xx_private *bcm)
++static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
+ {
++ int ret = 0;
+ int i, err;
++ struct bcm43xx_coreinfo *core;
+
+- bcm43xx_lock_noirq(bcm);
++ bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
++ for (i = 0; i < bcm->nr_80211_available; i++) {
++ core = &(bcm->core_80211[i]);
++ assert(core->available);
++ if (!core->initialized)
++ continue;
++ err = bcm43xx_switch_core(bcm, core);
++ if (err) {
++ dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
++ "switch_core failed (%d)\n", err);
++ ret = err;
++ continue;
++ }
++ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
++ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
++ bcm43xx_wireless_core_cleanup(bcm);
++ if (core == bcm->active_80211_core)
++ bcm->active_80211_core = NULL;
++ }
++ free_irq(bcm->irq, bcm);
++ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
++
++ return ret;
++}
++
++/* This is the opposite of bcm43xx_init_board() */
++static void bcm43xx_free_board(struct bcm43xx_private *bcm)
++{
++ bcm43xx_rng_exit(bcm);
+ bcm43xx_sysfs_unregister(bcm);
+ bcm43xx_periodic_tasks_delete(bcm);
+
+- bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
++ mutex_lock(&(bcm)->mutex);
++ bcm43xx_shutdown_all_wireless_cores(bcm);
++ bcm43xx_pctl_set_crystal(bcm, 0);
++ mutex_unlock(&(bcm)->mutex);
++}
+
+- bcm43xx_rng_exit(bcm);
++static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
++{
++ phy->antenna_diversity = 0xFFFF;
++ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
++ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
++
++ /* Flags */
++ phy->calibrated = 0;
++ phy->is_locked = 0;
++
++ if (phy->_lo_pairs) {
++ memset(phy->_lo_pairs, 0,
++ sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
++ }
++ memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
++}
++
++static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
++ struct bcm43xx_radioinfo *radio)
++{
++ int i;
++
++ /* Set default attenuation values. */
++ radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
++ radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
++ radio->txctl1 = bcm43xx_default_txctl1(bcm);
++ radio->txctl2 = 0xFFFF;
++ radio->txpwr_offset = 0;
++
++ /* NRSSI */
++ radio->nrssislope = 0;
++ for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
++ radio->nrssi[i] = -1000;
++ for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
++ radio->nrssi_lt[i] = i;
++
++ radio->lofcal = 0xFFFF;
++ radio->initval = 0xFFFF;
++
++ radio->aci_enable = 0;
++ radio->aci_wlan_automatic = 0;
++ radio->aci_hw_rssi = 0;
++}
++
++static void prepare_priv_for_init(struct bcm43xx_private *bcm)
++{
++ int i;
++ struct bcm43xx_coreinfo *core;
++ struct bcm43xx_coreinfo_80211 *wlext;
++
++ assert(!bcm->active_80211_core);
++
++ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
++
++ /* Flags */
++ bcm->was_initialized = 0;
++ bcm->reg124_set_0x4 = 0;
++
++ /* Stats */
++ memset(&bcm->stats, 0, sizeof(bcm->stats));
++
++ /* Wireless core data */
+ for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+- if (!bcm->core_80211[i].available)
+- continue;
+- if (!bcm->core_80211[i].initialized)
++ core = &(bcm->core_80211[i]);
++ wlext = core->priv;
++
++ if (!core->available)
+ continue;
++ assert(wlext == &(bcm->core_80211_ext[i]));
+
+- err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+- assert(err == 0);
+- bcm43xx_wireless_core_cleanup(bcm);
++ prepare_phydata_for_init(&wlext->phy);
++ prepare_radiodata_for_init(bcm, &wlext->radio);
+ }
+
+- bcm43xx_pctl_set_crystal(bcm, 0);
++ /* IRQ related flags */
++ bcm->irq_reason = 0;
++ memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
++ bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+
+- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+- bcm43xx_unlock_noirq(bcm);
++ bcm->mac_suspended = 1;
++
++ /* Noise calculation context */
++ memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
++
++ /* Periodic work context */
++ bcm->periodic_state = 0;
+ }
+
+-static int bcm43xx_init_board(struct bcm43xx_private *bcm)
++static int wireless_core_up(struct bcm43xx_private *bcm,
++ int active_wlcore)
++{
++ int err;
++
++ if (!bcm43xx_core_enabled(bcm))
++ bcm43xx_wireless_core_reset(bcm, 1);
++ if (!active_wlcore)
++ bcm43xx_wireless_core_mark_inactive(bcm);
++ err = bcm43xx_wireless_core_init(bcm, active_wlcore);
++ if (err)
++ goto out;
++ if (!active_wlcore)
++ bcm43xx_radio_turn_off(bcm);
++out:
++ return err;
++}
++
++/* Select and enable the "to be used" wireless core.
++ * Locking: bcm->mutex must be aquired before calling this.
++ * bcm->irq_lock must not be aquired.
++ */
++int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
++ int phytype)
+ {
+ int i, err;
+- int connect_phy;
++ struct bcm43xx_coreinfo *active_core = NULL;
++ struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
++ struct bcm43xx_coreinfo *core;
++ struct bcm43xx_coreinfo_80211 *wlext;
++ int adjust_active_sbtmstatelow = 0;
+
+ might_sleep();
+
+- bcm43xx_lock_noirq(bcm);
+- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
++ if (phytype < 0) {
++ /* If no phytype is requested, select the first core. */
++ assert(bcm->core_80211[0].available);
++ wlext = bcm->core_80211[0].priv;
++ phytype = wlext->phy.type;
++ }
++ /* Find the requested core. */
++ for (i = 0; i < bcm->nr_80211_available; i++) {
++ core = &(bcm->core_80211[i]);
++ wlext = core->priv;
++ if (wlext->phy.type == phytype) {
++ active_core = core;
++ active_wlext = wlext;
++ break;
++ }
++ }
++ if (!active_core)
++ return -ESRCH; /* No such PHYTYPE on this board. */
++
++ if (bcm->active_80211_core) {
++ /* We already selected a wl core in the past.
++ * So first clean up everything.
++ */
++ dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
++ ieee80211softmac_stop(bcm->net_dev);
++ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
++ err = bcm43xx_disable_interrupts_sync(bcm);
++ assert(!err);
++ tasklet_enable(&bcm->isr_tasklet);
++ err = bcm43xx_shutdown_all_wireless_cores(bcm);
++ if (err)
++ goto error;
++ /* Ok, everything down, continue to re-initialize. */
++ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
++ }
++
++ /* Reset all data structures. */
++ prepare_priv_for_init(bcm);
+
+- err = bcm43xx_pctl_set_crystal(bcm, 1);
+- if (err)
+- goto out;
+- err = bcm43xx_pctl_init(bcm);
+- if (err)
+- goto err_crystal_off;
+ err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
+ if (err)
+- goto err_crystal_off;
++ goto error;
+
+- tasklet_enable(&bcm->isr_tasklet);
++ /* Mark all unused cores "inactive". */
+ for (i = 0; i < bcm->nr_80211_available; i++) {
+- err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+- assert(err != -ENODEV);
+- if (err)
+- goto err_80211_unwind;
++ core = &(bcm->core_80211[i]);
++ wlext = core->priv;
+
+- /* Enable the selected wireless core.
+- * Connect PHY only on the first core.
+- */
+- if (!bcm43xx_core_enabled(bcm)) {
+- if (bcm->nr_80211_available == 1) {
+- connect_phy = bcm43xx_current_phy(bcm)->connected;
+- } else {
+- if (i == 0)
+- connect_phy = 1;
+- else
+- connect_phy = 0;
+- }
+- bcm43xx_wireless_core_reset(bcm, connect_phy);
++ if (core == active_core)
++ continue;
++ err = bcm43xx_switch_core(bcm, core);
++ if (err) {
++ dprintk(KERN_ERR PFX "Could not switch to inactive "
++ "802.11 core (%d)\n", err);
++ goto error;
+ }
++ err = wireless_core_up(bcm, 0);
++ if (err) {
++ dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
++ "failed (%d)\n", err);
++ goto error;
++ }
++ adjust_active_sbtmstatelow = 1;
++ }
+
+- if (i != 0)
+- bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
+-
+- err = bcm43xx_wireless_core_init(bcm);
+- if (err)
+- goto err_80211_unwind;
++ /* Now initialize the active 802.11 core. */
++ err = bcm43xx_switch_core(bcm, active_core);
++ if (err) {
++ dprintk(KERN_ERR PFX "Could not switch to active "
++ "802.11 core (%d)\n", err);
++ goto error;
++ }
++ if (adjust_active_sbtmstatelow &&
++ active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
++ u32 sbtmstatelow;
+
+- if (i != 0) {
+- bcm43xx_mac_suspend(bcm);
+- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+- bcm43xx_radio_turn_off(bcm);
+- }
++ sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
++ sbtmstatelow |= 0x20000000;
++ bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+ }
+- bcm->active_80211_core = &bcm->core_80211[0];
+- if (bcm->nr_80211_available >= 2) {
+- bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
+- bcm43xx_mac_enable(bcm);
++ err = wireless_core_up(bcm, 1);
++ if (err) {
++ dprintk(KERN_ERR PFX "core_up for active 802.11 core "
++ "failed (%d)\n", err);
++ goto error;
+ }
+- err = bcm43xx_rng_init(bcm);
++ err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+ if (err)
+- goto err_80211_unwind;
++ goto error;
++ bcm->active_80211_core = active_core;
++
+ bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
+ bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
+- dprintk(KERN_INFO PFX "80211 cores initialized\n");
+ bcm43xx_security_init(bcm);
+- bcm43xx_softmac_init(bcm);
++ ieee80211softmac_start(bcm->net_dev);
+
+- bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
++ /* Let's go! Be careful after enabling the IRQs.
++ * Don't switch cores, for example.
++ */
++ bcm43xx_mac_enable(bcm);
++ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
++ err = bcm43xx_initialize_irq(bcm);
++ if (err)
++ goto error;
++ bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+
+- if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
+- bcm43xx_mac_suspend(bcm);
+- bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
+- bcm43xx_mac_enable(bcm);
+- }
++ dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
++ active_wlext->phy.type);
+
+- /* Initialization of the board is done. Flag it as such. */
+- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
++ return 0;
++
++error:
++ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
++ bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
++ return err;
++}
++
++static int bcm43xx_init_board(struct bcm43xx_private *bcm)
++{
++ int err;
+
++ mutex_lock(&(bcm)->mutex);
++
++ tasklet_enable(&bcm->isr_tasklet);
++ err = bcm43xx_pctl_set_crystal(bcm, 1);
++ if (err)
++ goto err_tasklet;
++ err = bcm43xx_pctl_init(bcm);
++ if (err)
++ goto err_crystal_off;
++ err = bcm43xx_select_wireless_core(bcm, -1);
++ if (err)
++ goto err_crystal_off;
++ err = bcm43xx_sysfs_register(bcm);
++ if (err)
++ goto err_wlshutdown;
++ err = bcm43xx_rng_init(bcm);
++ if (err)
++ goto err_sysfs_unreg;
+ bcm43xx_periodic_tasks_setup(bcm);
+- bcm43xx_sysfs_register(bcm);
+- //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+
+ /*FIXME: This should be handled by softmac instead. */
+ schedule_work(&bcm->softmac->associnfo.work);
+
+- assert(err == 0);
+ out:
+- bcm43xx_unlock_noirq(bcm);
++ mutex_unlock(&(bcm)->mutex);
+
+ return err;
+
+-err_80211_unwind:
+- tasklet_disable(&bcm->isr_tasklet);
+- /* unwind all 80211 initialization */
+- for (i = 0; i < bcm->nr_80211_available; i++) {
+- if (!bcm->core_80211[i].initialized)
+- continue;
+- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+- bcm43xx_wireless_core_cleanup(bcm);
+- }
++err_sysfs_unreg:
++ bcm43xx_sysfs_unregister(bcm);
++err_wlshutdown:
++ bcm43xx_shutdown_all_wireless_cores(bcm);
+ err_crystal_off:
+ bcm43xx_pctl_set_crystal(bcm, 0);
++err_tasklet:
++ tasklet_disable(&bcm->isr_tasklet);
+ goto out;
+ }
+
+@@ -3647,7 +3838,8 @@ static void bcm43xx_ieee80211_set_chan(s
+ struct bcm43xx_radioinfo *radio;
+ unsigned long flags;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ bcm43xx_mac_suspend(bcm);
+ bcm43xx_radio_selectchannel(bcm, channel, 0);
+@@ -3656,7 +3848,8 @@ static void bcm43xx_ieee80211_set_chan(s
+ radio = bcm43xx_current_radio(bcm);
+ radio->initial_channel = channel;
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ }
+
+ /* set_security() callback in struct ieee80211_device */
+@@ -3670,7 +3863,8 @@ static void bcm43xx_ieee80211_set_securi
+
+ dprintk(KERN_INFO PFX "set security called");
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+
+ for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
+ if (sec->flags & (1<<keyidx)) {
+@@ -3739,7 +3933,8 @@ static void bcm43xx_ieee80211_set_securi
+ } else
+ bcm43xx_clear_keys(bcm);
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ }
+
+ /* hard_start_xmit() callback in struct ieee80211_device */
+@@ -3751,12 +3946,14 @@ static int bcm43xx_ieee80211_hard_start_
+ int err = -ENODEV;
+ unsigned long flags;
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
+ err = bcm43xx_tx(bcm, txb);
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+
+- return err;
++ if (unlikely(err))
++ return NETDEV_TX_BUSY;
++ return NETDEV_TX_OK;
+ }
+
+ static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
+@@ -3769,9 +3966,9 @@ static void bcm43xx_net_tx_timeout(struc
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ unsigned long flags;
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ bcm43xx_controller_restart(bcm, "TX timeout");
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ }
+
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+@@ -3781,7 +3978,8 @@ static void bcm43xx_net_poll_controller(
+ unsigned long flags;
+
+ local_irq_save(flags);
+- bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
++ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
++ bcm43xx_interrupt_handler(bcm->irq, bcm);
+ local_irq_restore(flags);
+ }
+ #endif /* CONFIG_NET_POLL_CONTROLLER */
+@@ -3799,9 +3997,10 @@ static int bcm43xx_net_stop(struct net_d
+ int err;
+
+ ieee80211softmac_stop(net_dev);
+- err = bcm43xx_disable_interrupts_sync(bcm, NULL);
++ err = bcm43xx_disable_interrupts_sync(bcm);
+ assert(!err);
+ bcm43xx_free_board(bcm);
++ flush_scheduled_work();
+
+ return 0;
+ }
+@@ -3810,39 +4009,25 @@ static int bcm43xx_init_private(struct b
+ struct net_device *net_dev,
+ struct pci_dev *pci_dev)
+ {
+- int err;
+-
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ bcm->ieee = netdev_priv(net_dev);
+ bcm->softmac = ieee80211_priv(net_dev);
+ bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
+
+ bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
++ bcm->mac_suspended = 1;
+ bcm->pci_dev = pci_dev;
+ bcm->net_dev = net_dev;
+ bcm->bad_frames_preempt = modparam_bad_frames_preempt;
+ spin_lock_init(&bcm->irq_lock);
++ spin_lock_init(&bcm->leds_lock);
+ mutex_init(&bcm->mutex);
+ tasklet_init(&bcm->isr_tasklet,
+ (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
+ (unsigned long)bcm);
+ tasklet_disable_nosync(&bcm->isr_tasklet);
+- if (modparam_pio) {
++ if (modparam_pio)
+ bcm->__using_pio = 1;
+- } else {
+- err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
+- err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
+- if (err) {
+-#ifdef CONFIG_BCM43XX_PIO
+- printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
+- bcm->__using_pio = 1;
+-#else
+- printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+- "Recompile the driver with PIO support, please.\n");
+- return -ENODEV;
+-#endif /* CONFIG_BCM43XX_PIO */
+- }
+- }
+ bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
+
+ /* default to sw encryption for now */
+@@ -3940,7 +4125,6 @@ static void __devexit bcm43xx_remove_one
+ bcm43xx_debugfs_remove_device(bcm);
+ unregister_netdev(net_dev);
+ bcm43xx_detach_board(bcm);
+- assert(bcm->ucode == NULL);
+ free_ieee80211softmac(net_dev);
+ }
+
+@@ -3950,47 +4134,31 @@ static void __devexit bcm43xx_remove_one
+ static void bcm43xx_chip_reset(void *_bcm)
+ {
+ struct bcm43xx_private *bcm = _bcm;
+- struct net_device *net_dev = bcm->net_dev;
+- struct pci_dev *pci_dev = bcm->pci_dev;
+- int err;
+- int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+-
+- netif_stop_queue(bcm->net_dev);
+- tasklet_disable(&bcm->isr_tasklet);
++ struct bcm43xx_phyinfo *phy;
++ int err = -ENODEV;
+
+- bcm->firmware_norelease = 1;
+- if (was_initialized)
+- bcm43xx_free_board(bcm);
+- bcm->firmware_norelease = 0;
+- bcm43xx_detach_board(bcm);
+- err = bcm43xx_init_private(bcm, net_dev, pci_dev);
+- if (err)
+- goto failure;
+- err = bcm43xx_attach_board(bcm);
+- if (err)
+- goto failure;
+- if (was_initialized) {
+- err = bcm43xx_init_board(bcm);
+- if (err)
+- goto failure;
++ mutex_lock(&(bcm)->mutex);
++ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
++ bcm43xx_periodic_tasks_delete(bcm);
++ phy = bcm43xx_current_phy(bcm);
++ err = bcm43xx_select_wireless_core(bcm, phy->type);
++ if (!err)
++ bcm43xx_periodic_tasks_setup(bcm);
+ }
+- netif_wake_queue(bcm->net_dev);
+- printk(KERN_INFO PFX "Controller restarted\n");
++ mutex_unlock(&(bcm)->mutex);
+
+- return;
+-failure:
+- printk(KERN_ERR PFX "Controller restart failed\n");
++ printk(KERN_ERR PFX "Controller restart%s\n",
++ (err == 0) ? "ed" : " failed");
+ }
+
+ /* Hard-reset the chip.
+ * This can be called from interrupt or process context.
+- * Make sure to _not_ re-enable device interrupts after this has been called.
+-*/
++ * bcm->irq_lock must be locked.
++ */
+ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
+ {
+- bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
+- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
++ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
++ return;
+ printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
+ INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
+ schedule_work(&bcm->restart_work);
+@@ -4002,21 +4170,16 @@ static int bcm43xx_suspend(struct pci_de
+ {
+ struct net_device *net_dev = pci_get_drvdata(pdev);
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+- int try_to_shutdown = 0, err;
++ int err;
+
+ dprintk(KERN_INFO PFX "Suspending...\n");
+
+- bcm43xx_lock_irqsafe(bcm, flags);
+- bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+- if (bcm->was_initialized)
+- try_to_shutdown = 1;
+- bcm43xx_unlock_irqsafe(bcm, flags);
+-
+ netif_device_detach(net_dev);
+- if (try_to_shutdown) {
++ bcm->was_initialized = 0;
++ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
++ bcm->was_initialized = 1;
+ ieee80211softmac_stop(net_dev);
+- err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
++ err = bcm43xx_disable_interrupts_sync(bcm);
+ if (unlikely(err)) {
+ dprintk(KERN_ERR PFX "Suspend failed.\n");
+ return -EAGAIN;
+@@ -4045,21 +4208,22 @@ static int bcm43xx_resume(struct pci_dev
+ dprintk(KERN_INFO PFX "Resuming...\n");
+
+ pci_set_power_state(pdev, 0);
+- pci_enable_device(pdev);
++ err = pci_enable_device(pdev);
++ if (err) {
++ printk(KERN_ERR PFX "Failure with pci_enable_device!\n");
++ return err;
++ }
+ pci_restore_state(pdev);
+
+ bcm43xx_chipset_attach(bcm);
+- if (bcm->was_initialized) {
+- bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
++ if (bcm->was_initialized)
+ err = bcm43xx_init_board(bcm);
+- }
+ if (err) {
+ printk(KERN_ERR PFX "Resume failed!\n");
+ return err;
+ }
+-
+ netif_device_attach(net_dev);
+-
++
+ dprintk(KERN_INFO PFX "Device resumed.\n");
+
+ return 0;
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+index 1164936..f763571 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+@@ -133,11 +133,17 @@ void bcm43xx_dummy_transmission(struct b
+
+ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
+
++int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
++ int phytype);
++
+ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
+
+ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
+ void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
+
++void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
++void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
++
+ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
+
+ int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+index f8200de..52ce2a9 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table
+ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
+
+
++static inline
++void bcm43xx_voluntary_preempt(void)
++{
++ assert(!in_atomic() && !in_irq() &&
++ !in_interrupt() && !irqs_disabled());
++#ifndef CONFIG_PREEMPT
++ cond_resched();
++#endif /* CONFIG_PREEMPT */
++}
++
+ void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
+ {
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_pr
+ void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
+ {
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+- unsigned long flags;
+
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
+ if (phy->calibrated)
+ return;
+ if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
+- /* We do not want to be preempted while calibrating
+- * the hardware.
+- */
+- local_irq_save(flags);
+-
+ bcm43xx_wireless_core_reset(bcm, 0);
+ bcm43xx_phy_initg(bcm);
+ bcm43xx_wireless_core_reset(bcm, 1);
+-
+- local_irq_restore(flags);
+ }
+ phy->calibrated = 1;
+ }
+@@ -359,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bc
+ if (phy->rev <= 2)
+ for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+ bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
+- else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
++ else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
+ for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+ bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
+ else
+@@ -369,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bc
+ if (phy->rev == 2)
+ for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+ bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
+- else if ((phy->rev > 2) && (phy->rev <= 7))
++ else if ((phy->rev > 2) && (phy->rev <= 8))
+ for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+ bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
+
+@@ -1195,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm
+
+ if (phy->rev == 1)
+ bcm43xx_phy_initb5(bcm);
+- else if (phy->rev >= 2 && phy->rev <= 7)
++ else
+ bcm43xx_phy_initb6(bcm);
+ if (phy->rev >= 2 || phy->connected)
+ bcm43xx_phy_inita(bcm);
+@@ -1239,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm
+ bcm43xx_phy_lo_g_measure(bcm);
+ } else {
+ if (radio->version == 0x2050 && radio->revision == 8) {
+- //FIXME
++ bcm43xx_radio_write16(bcm, 0x0052,
++ (radio->txctl1 << 4) | radio->txctl2);
+ } else {
+ bcm43xx_radio_write16(bcm, 0x0052,
+ (bcm43xx_radio_read16(bcm, 0x0052)
+ & 0xFFF0) | radio->txctl1);
+ }
+ if (phy->rev >= 6) {
+- /*
+ bcm43xx_phy_write(bcm, 0x0036,
+ (bcm43xx_phy_read(bcm, 0x0036)
+- & 0xF000) | (FIXME << 12));
+- */
++ & 0xF000) | (radio->txctl2 << 12));
+ }
+ if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+ bcm43xx_phy_write(bcm, 0x002E, 0x8075);
+ else
+- bcm43xx_phy_write(bcm, 0x003E, 0x807F);
++ bcm43xx_phy_write(bcm, 0x002E, 0x807F);
+ if (phy->rev < 2)
+ bcm43xx_phy_write(bcm, 0x002F, 0x0101);
+ else
+@@ -1299,7 +1300,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(str
+ {
+ int i;
+ u16 ret = 0;
++ unsigned long flags;
+
++ local_irq_save(flags);
+ for (i = 0; i < 10; i++){
+ bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
+ udelay(1);
+@@ -1309,6 +1312,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(str
+ udelay(40);
+ ret += bcm43xx_phy_read(bcm, 0x002C);
+ }
++ local_irq_restore(flags);
++ bcm43xx_voluntary_preempt();
+
+ return ret;
+ }
+@@ -1435,6 +1440,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(st
+ }
+ ret = bcm43xx_phy_read(bcm, 0x002D);
+ local_irq_restore(flags);
++ bcm43xx_voluntary_preempt();
+
+ return ret;
+ }
+@@ -1760,6 +1766,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm
+ bcm43xx_radio_write16(bcm, 0x43, i);
+ bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
+ udelay(10);
++ bcm43xx_voluntary_preempt();
+
+ bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
+
+@@ -1803,6 +1810,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm
+ radio->txctl2
+ | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
+ udelay(10);
++ bcm43xx_voluntary_preempt();
+
+ bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
+
+@@ -1824,6 +1832,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm
+ bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
+ udelay(2);
+ bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
++ bcm43xx_voluntary_preempt();
+ } else
+ bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
+ bcm43xx_phy_lo_adjust(bcm, is_initializing);
+@@ -2188,12 +2197,6 @@ int bcm43xx_phy_init(struct bcm43xx_priv
+ {
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ int err = -ENODEV;
+- unsigned long flags;
+-
+- /* We do not want to be preempted while calibrating
+- * the hardware.
+- */
+- local_irq_save(flags);
+
+ switch (phy->type) {
+ case BCM43xx_PHYTYPE_A:
+@@ -2227,7 +2230,6 @@ int bcm43xx_phy_init(struct bcm43xx_priv
+ err = 0;
+ break;
+ }
+- local_irq_restore(flags);
+ if (err)
+ printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
+
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+index 574085c..c60c174 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d)
+ int err;
+ u16 txctl;
+
+- bcm43xx_lock_irqonly(bcm, flags);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+
+ if (queue->tx_frozen)
+ goto out_unlock;
+@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d)
+ continue;
+ }
+ out_unlock:
+- bcm43xx_unlock_irqonly(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ }
+
+ static void setup_txqueues(struct bcm43xx_pioqueue *queue)
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+index 6a23bdc..c71b998 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(s
+ GFP_KERNEL);
+ if (!sprom)
+ return -ENOMEM;
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ err = bcm43xx_sprom_read(bcm, sprom);
+ if (!err)
+ err = sprom2hex(sprom, buf, PAGE_SIZE);
+ mmiowb();
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ kfree(sprom);
+
+ return err;
+@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(
+ err = hex2sprom(sprom, buf, count);
+ if (err)
+ goto out_kfree;
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
++ spin_lock(&bcm->leds_lock);
+ err = bcm43xx_sprom_write(bcm, sprom);
+ mmiowb();
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock(&bcm->leds_lock);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ out_kfree:
+ kfree(sprom);
+
+@@ -170,13 +176,12 @@ static ssize_t bcm43xx_attr_interfmode_s
+ char *buf)
+ {
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+- int err;
+ ssize_t count = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+- bcm43xx_lock_noirq(bcm);
++ mutex_lock(&bcm->mutex);
+
+ switch (bcm43xx_current_radio(bcm)->interfmode) {
+ case BCM43xx_RADIO_INTERFMODE_NONE:
+@@ -191,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_s
+ default:
+ assert(0);
+ }
+- err = 0;
+
+- bcm43xx_unlock_noirq(bcm);
++ mutex_unlock(&bcm->mutex);
+
+- return err ? err : count;
++ return count;
+
+ }
+
+@@ -229,7 +233,8 @@ static ssize_t bcm43xx_attr_interfmode_s
+ return -EINVAL;
+ }
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+
+ err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
+ if (err) {
+@@ -237,7 +242,8 @@ static ssize_t bcm43xx_attr_interfmode_s
+ "supported by device\n");
+ }
+ mmiowb();
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err ? err : count;
+ }
+@@ -251,23 +257,21 @@ static ssize_t bcm43xx_attr_preamble_sho
+ char *buf)
+ {
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+- int err;
+ ssize_t count;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+- bcm43xx_lock_noirq(bcm);
++ mutex_lock(&bcm->mutex);
+
+ if (bcm->short_preamble)
+ count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+ else
+ count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+
+- err = 0;
+- bcm43xx_unlock_noirq(bcm);
++ mutex_unlock(&bcm->mutex);
+
+- return err ? err : count;
++ return count;
+ }
+
+ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
+@@ -276,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_sto
+ {
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ unsigned long flags;
+- int err;
+ int value;
+
+ if (!capable(CAP_NET_ADMIN))
+@@ -285,20 +288,141 @@ static ssize_t bcm43xx_attr_preamble_sto
+ value = get_boolean(buf, count);
+ if (value < 0)
+ return value;
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+
+ bcm->short_preamble = !!value;
+
+- err = 0;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+- return err ? err : count;
++ return count;
+ }
+
+ static DEVICE_ATTR(shortpreamble, 0644,
+ bcm43xx_attr_preamble_show,
+ bcm43xx_attr_preamble_store);
+
++static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct bcm43xx_private *bcm = dev_to_bcm(dev);
++ int phytype;
++ int err = -EINVAL;
++
++ if (count < 1)
++ goto out;
++ switch (buf[0]) {
++ case 'a': case 'A':
++ phytype = BCM43xx_PHYTYPE_A;
++ break;
++ case 'b': case 'B':
++ phytype = BCM43xx_PHYTYPE_B;
++ break;
++ case 'g': case 'G':
++ phytype = BCM43xx_PHYTYPE_G;
++ break;
++ default:
++ goto out;
++ }
++
++ bcm43xx_periodic_tasks_delete(bcm);
++ mutex_lock(&(bcm)->mutex);
++ err = bcm43xx_select_wireless_core(bcm, phytype);
++ if (!err)
++ bcm43xx_periodic_tasks_setup(bcm);
++ mutex_unlock(&(bcm)->mutex);
++ if (err == -ESRCH)
++ err = -ENODEV;
++
++out:
++ return err ? err : count;
++}
++
++static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct bcm43xx_private *bcm = dev_to_bcm(dev);
++ ssize_t count = 0;
++
++ mutex_lock(&(bcm)->mutex);
++ switch (bcm43xx_current_phy(bcm)->type) {
++ case BCM43xx_PHYTYPE_A:
++ snprintf(buf, PAGE_SIZE, "A");
++ break;
++ case BCM43xx_PHYTYPE_B:
++ snprintf(buf, PAGE_SIZE, "B");
++ break;
++ case BCM43xx_PHYTYPE_G:
++ snprintf(buf, PAGE_SIZE, "G");
++ break;
++ default:
++ assert(0);
++ }
++ mutex_unlock(&(bcm)->mutex);
++
++ return count;
++}
++
++static DEVICE_ATTR(phymode, 0644,
++ bcm43xx_attr_phymode_show,
++ bcm43xx_attr_phymode_store);
++
++static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ unsigned long flags;
++ struct bcm43xx_private *bcm = dev_to_bcm(dev);
++ ssize_t count = 0;
++ u16 status;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ mutex_lock(&(bcm)->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
++ status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
++ BCM43xx_UCODE_STATUS);
++
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&(bcm)->mutex);
++ switch (status) {
++ case 0x0000:
++ count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
++ status);
++ break;
++ case 0x0001:
++ count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
++ status);
++ break;
++ case 0x0002:
++ count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
++ status);
++ break;
++ case 0x0003:
++ count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
++ status);
++ break;
++ case 0x0004:
++ count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
++ status);
++ break;
++ default:
++ count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
++ status);
++ break;
++ }
++
++ return count;
++}
++
++static DEVICE_ATTR(microcodestatus, 0444,
++ bcm43xx_attr_microcode_show,
++ NULL);
++
+ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
+ {
+ struct device *dev = &bcm->pci_dev->dev;
+@@ -315,9 +439,19 @@ int bcm43xx_sysfs_register(struct bcm43x
+ err = device_create_file(dev, &dev_attr_shortpreamble);
+ if (err)
+ goto err_remove_interfmode;
++ err = device_create_file(dev, &dev_attr_phymode);
++ if (err)
++ goto err_remove_shortpreamble;
++ err = device_create_file(dev, &dev_attr_microcodestatus);
++ if (err)
++ goto err_remove_phymode;
+
+ out:
+ return err;
++err_remove_phymode:
++ device_remove_file(dev, &dev_attr_phymode);
++err_remove_shortpreamble:
++ device_remove_file(dev, &dev_attr_shortpreamble);
+ err_remove_interfmode:
+ device_remove_file(dev, &dev_attr_interference);
+ err_remove_sprom:
+@@ -329,6 +463,8 @@ void bcm43xx_sysfs_unregister(struct bcm
+ {
+ struct device *dev = &bcm->pci_dev->dev;
+
++ device_remove_file(dev, &dev_attr_microcodestatus);
++ device_remove_file(dev, &dev_attr_phymode);
+ device_remove_file(dev, &dev_attr_shortpreamble);
+ device_remove_file(dev, &dev_attr_interference);
+ device_remove_file(dev, &dev_attr_sprom);
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+index 5c36e29..d27016f 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+@@ -47,6 +47,8 @@
+ #define BCM43xx_WX_VERSION 18
+
+ #define MAX_WX_STRING 80
++/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
++#define RX_RSSI_MAX 60
+
+
+ static int bcm43xx_wx_get_name(struct net_device *net_dev,
+@@ -56,12 +58,11 @@ static int bcm43xx_wx_get_name(struct ne
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ int i;
+- unsigned long flags;
+ struct bcm43xx_phyinfo *phy;
+ char suffix[7] = { 0 };
+ int have_a = 0, have_b = 0, have_g = 0;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ for (i = 0; i < bcm->nr_80211_available; i++) {
+ phy = &(bcm->core_80211_ext[i].phy);
+ switch (phy->type) {
+@@ -77,7 +78,7 @@ static int bcm43xx_wx_get_name(struct ne
+ assert(0);
+ }
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ i = 0;
+ if (have_a) {
+@@ -111,7 +112,9 @@ static int bcm43xx_wx_set_channelfreq(st
+ int freq;
+ int err = -EINVAL;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
++
+ if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
+ channel = data->freq.m;
+ freq = bcm43xx_channel_to_freq(bcm, channel);
+@@ -131,7 +134,8 @@ static int bcm43xx_wx_set_channelfreq(st
+ err = 0;
+ }
+ out_unlock:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -143,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(st
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ struct bcm43xx_radioinfo *radio;
+- unsigned long flags;
+ int err = -ENODEV;
+ u16 channel;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ radio = bcm43xx_current_radio(bcm);
+ channel = radio->channel;
+ if (channel == 0xFF) {
+@@ -162,7 +165,7 @@ static int bcm43xx_wx_get_channelfreq(st
+
+ err = 0;
+ out_unlock:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -180,13 +183,15 @@ static int bcm43xx_wx_set_mode(struct ne
+ if (mode == IW_MODE_AUTO)
+ mode = BCM43xx_INITIAL_IWMODE;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ if (bcm->ieee->iw_mode != mode)
+ bcm43xx_set_iwmode(bcm, mode);
+ } else
+ bcm->ieee->iw_mode = mode;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -197,11 +202,10 @@ static int bcm43xx_wx_get_mode(struct ne
+ char *extra)
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ data->mode = bcm->ieee->iw_mode;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -214,7 +218,6 @@ static int bcm43xx_wx_get_rangeparams(st
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ struct iw_range *range = (struct iw_range *)extra;
+ const struct ieee80211_geo *geo;
+- unsigned long flags;
+ int i, j;
+ struct bcm43xx_phyinfo *phy;
+
+@@ -226,15 +229,14 @@ static int bcm43xx_wx_get_rangeparams(st
+ range->throughput = 27 * 1000 * 1000;
+
+ range->max_qual.qual = 100;
+- /* TODO: Real max RSSI */
+- range->max_qual.level = 3;
+- range->max_qual.noise = 100;
+- range->max_qual.updated = 7;
++ range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
++ range->max_qual.noise = 146;
++ range->max_qual.updated = IW_QUAL_ALL_UPDATED;
+
+- range->avg_qual.qual = 70;
+- range->avg_qual.level = 2;
+- range->avg_qual.noise = 40;
+- range->avg_qual.updated = 7;
++ range->avg_qual.qual = 50;
++ range->avg_qual.level = 0;
++ range->avg_qual.noise = 0;
++ range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
+
+ range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
+ range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
+@@ -254,7 +256,7 @@ static int bcm43xx_wx_get_rangeparams(st
+ IW_ENC_CAPA_CIPHER_TKIP |
+ IW_ENC_CAPA_CIPHER_CCMP;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ phy = bcm43xx_current_phy(bcm);
+
+ range->num_bitrates = 0;
+@@ -301,7 +303,7 @@ static int bcm43xx_wx_get_rangeparams(st
+ }
+ range->num_frequency = j;
+
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -314,11 +316,11 @@ static int bcm43xx_wx_set_nick(struct ne
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ size_t len;
+
+- bcm43xx_lock_noirq(bcm);
++ mutex_lock(&bcm->mutex);
+ len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
+ memcpy(bcm->nick, extra, len);
+ bcm->nick[len] = '\0';
+- bcm43xx_unlock_noirq(bcm);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -331,12 +333,12 @@ static int bcm43xx_wx_get_nick(struct ne
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ size_t len;
+
+- bcm43xx_lock_noirq(bcm);
+- len = strlen(bcm->nick) + 1;
++ mutex_lock(&bcm->mutex);
++ len = strlen(bcm->nick);
+ memcpy(extra, bcm->nick, len);
+ data->data.length = (__u16)len;
+ data->data.flags = 1;
+- bcm43xx_unlock_noirq(bcm);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -350,7 +352,8 @@ static int bcm43xx_wx_set_rts(struct net
+ unsigned long flags;
+ int err = -EINVAL;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (data->rts.disabled) {
+ bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
+ err = 0;
+@@ -361,7 +364,8 @@ static int bcm43xx_wx_set_rts(struct net
+ err = 0;
+ }
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -372,13 +376,12 @@ static int bcm43xx_wx_get_rts(struct net
+ char *extra)
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ data->rts.value = bcm->rts_threshold;
+ data->rts.fixed = 0;
+ data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -392,7 +395,8 @@ static int bcm43xx_wx_set_frag(struct ne
+ unsigned long flags;
+ int err = -EINVAL;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (data->frag.disabled) {
+ bcm->ieee->fts = MAX_FRAG_THRESHOLD;
+ err = 0;
+@@ -403,7 +407,8 @@ static int bcm43xx_wx_set_frag(struct ne
+ err = 0;
+ }
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -414,13 +419,12 @@ static int bcm43xx_wx_get_frag(struct ne
+ char *extra)
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ data->frag.value = bcm->ieee->fts;
+ data->frag.fixed = 0;
+ data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -442,7 +446,8 @@ static int bcm43xx_wx_set_xmitpower(stru
+ return -EOPNOTSUPP;
+ }
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
+ goto out_unlock;
+ radio = bcm43xx_current_radio(bcm);
+@@ -466,7 +471,8 @@ static int bcm43xx_wx_set_xmitpower(stru
+ err = 0;
+
+ out_unlock:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -478,10 +484,9 @@ static int bcm43xx_wx_get_xmitpower(stru
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ struct bcm43xx_radioinfo *radio;
+- unsigned long flags;
+ int err = -ENODEV;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
+ goto out_unlock;
+ radio = bcm43xx_current_radio(bcm);
+@@ -493,7 +498,7 @@ static int bcm43xx_wx_get_xmitpower(stru
+
+ err = 0;
+ out_unlock:
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -580,7 +585,8 @@ static int bcm43xx_wx_set_interfmode(str
+ return -EINVAL;
+ }
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
+ if (err) {
+@@ -595,7 +601,8 @@ static int bcm43xx_wx_set_interfmode(str
+ } else
+ bcm43xx_current_radio(bcm)->interfmode = mode;
+ }
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return err;
+ }
+@@ -606,12 +613,11 @@ static int bcm43xx_wx_get_interfmode(str
+ char *extra)
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+ int mode;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ mode = bcm43xx_current_radio(bcm)->interfmode;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ switch (mode) {
+ case BCM43xx_RADIO_INTERFMODE_NONE:
+@@ -641,9 +647,11 @@ static int bcm43xx_wx_set_shortpreamble(
+ int on;
+
+ on = *((int *)extra);
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ bcm->short_preamble = !!on;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -654,12 +662,11 @@ static int bcm43xx_wx_get_shortpreamble(
+ char *extra)
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+ int on;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ on = bcm->short_preamble;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ if (on)
+ strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
+@@ -681,11 +688,13 @@ static int bcm43xx_wx_set_swencryption(s
+
+ on = *((int *)extra);
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ bcm->ieee->host_encrypt = !!on;
+ bcm->ieee->host_decrypt = !!on;
+ bcm->ieee->host_build_iv = !on;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+
+ return 0;
+ }
+@@ -696,12 +705,11 @@ static int bcm43xx_wx_get_swencryption(s
+ char *extra)
+ {
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+- unsigned long flags;
+ int on;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
+ on = bcm->ieee->host_encrypt;
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ mutex_unlock(&bcm->mutex);
+
+ if (on)
+ strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
+@@ -764,11 +772,13 @@ static int bcm43xx_wx_sprom_read(struct
+ if (!sprom)
+ goto out;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
+ err = -ENODEV;
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+ err = bcm43xx_sprom_read(bcm, sprom);
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ if (!err)
+ data->data.length = sprom2hex(sprom, extra);
+ kfree(sprom);
+@@ -809,11 +819,15 @@ static int bcm43xx_wx_sprom_write(struct
+ if (err)
+ goto out_kfree;
+
+- bcm43xx_lock_irqsafe(bcm, flags);
++ mutex_lock(&bcm->mutex);
++ spin_lock_irqsave(&bcm->irq_lock, flags);
++ spin_lock(&bcm->leds_lock);
+ err = -ENODEV;
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+ err = bcm43xx_sprom_write(bcm, sprom);
+- bcm43xx_unlock_irqsafe(bcm, flags);
++ spin_unlock(&bcm->leds_lock);
++ spin_unlock_irqrestore(&bcm->irq_lock, flags);
++ mutex_unlock(&bcm->mutex);
+ out_kfree:
+ kfree(sprom);
+ out:
+@@ -827,9 +841,13 @@ static struct iw_statistics *bcm43xx_get
+ struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+ struct iw_statistics *wstats;
++ struct ieee80211_network *network = NULL;
++ static int tmp_level = 0;
++ static int tmp_qual = 0;
++ unsigned long flags;
+
+ wstats = &bcm->stats.wstats;
+- if (!mac->associated) {
++ if (!mac->associnfo.associated) {
+ wstats->miss.beacon = 0;
+ // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
+ wstats->discard.retries = 0;
+@@ -844,16 +862,28 @@ static struct iw_statistics *bcm43xx_get
+ wstats->qual.level = 0;
+ wstats->qual.noise = 0;
+ wstats->qual.updated = 7;
+- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
+- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
++ wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+ return wstats;
+ }
+ /* fill in the real statistics when iface associated */
+- wstats->qual.qual = 100; // TODO: get the real signal quality
+- wstats->qual.level = 3 - bcm->stats.link_quality;
++ spin_lock_irqsave(&mac->ieee->lock, flags);
++ list_for_each_entry(network, &mac->ieee->network_list, list) {
++ if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
++ if (!tmp_level) { /* get initial values */
++ tmp_level = network->stats.signal;
++ tmp_qual = network->stats.rssi;
++ } else { /* smooth results */
++ tmp_level = (15 * tmp_level + network->stats.signal)/16;
++ tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
++ }
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&mac->ieee->lock, flags);
++ wstats->qual.level = tmp_level;
++ wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
+ wstats->qual.noise = bcm->stats.noise;
+- wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
+- IW_QUAL_NOISE_UPDATED;
++ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+ wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
+ wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
+ wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
+diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+index 6dbd855..0159e4e 100644
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+@@ -492,20 +492,18 @@ int bcm43xx_rx(struct bcm43xx_private *b
+
+ memset(&stats, 0, sizeof(stats));
+ stats.mac_time = le16_to_cpu(rxhdr->mactime);
+- stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
++ stats.rssi = rxhdr->rssi;
++ stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+ !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
+ !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
+- stats.signal = rxhdr->signal_quality; //FIXME
+-//TODO stats.noise =
++ stats.noise = bcm->stats.noise;
+ if (is_ofdm)
+ stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
+ else
+ stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
+-//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
+ stats.received_channel = radio->channel;
+-//TODO stats.control =
+ stats.mask = IEEE80211_STATMASK_SIGNAL |
+-//TODO IEEE80211_STATMASK_NOISE |
++ IEEE80211_STATMASK_NOISE |
+ IEEE80211_STATMASK_RATE |
+ IEEE80211_STATMASK_RSSI;
+ if (phy->type == BCM43xx_PHYTYPE_A)
+diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
+index 5e63765..e663518 100644
+--- a/drivers/net/wireless/hostap/hostap.h
++++ b/drivers/net/wireless/hostap/hostap.h
+@@ -86,7 +86,7 @@ void hostap_info_process(local_info_t *l
+ /* hostap_ioctl.c */
+
+ extern const struct iw_handler_def hostap_iw_handler_def;
+-extern struct ethtool_ops prism2_ethtool_ops;
++extern const struct ethtool_ops prism2_ethtool_ops;
+
+ int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
+index 52e6df5..f63909e 100644
+--- a/drivers/net/wireless/hostap/hostap_cs.c
++++ b/drivers/net/wireless/hostap/hostap_cs.c
+@@ -847,6 +847,7 @@ static struct pcmcia_device_id hostap_cs
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
++ PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
+ 0x74c5e40d),
+ PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
+@@ -886,6 +887,13 @@ static struct pcmcia_device_id hostap_cs
+ PCMCIA_DEVICE_PROD_ID123(
+ "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
+ 0xc7b8df9d, 0x1700d087, 0x4b74baa0),
++ PCMCIA_DEVICE_PROD_ID123(
++ "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
++ "Ver. 1.00",
++ 0x5cd01705, 0x4271660f, 0x9d08ee12),
++ PCMCIA_DEVICE_PROD_ID123(
++ "corega", "WL PCCL-11", "ISL37300P",
++ 0xa21501a, 0x59868926, 0xc9049a39),
+ PCMCIA_DEVICE_NULL
+ };
+ MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
+diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
+index d500012..ed00ebb 100644
+--- a/drivers/net/wireless/hostap/hostap_hw.c
++++ b/drivers/net/wireless/hostap/hostap_hw.c
+@@ -2622,7 +2622,7 @@ static void prism2_check_magic(local_inf
+
+
+ /* Called only from hardware IRQ */
+-static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t prism2_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct hostap_interface *iface;
+diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
+index 8399de5..d061fb3 100644
+--- a/drivers/net/wireless/hostap/hostap_ioctl.c
++++ b/drivers/net/wireless/hostap/hostap_ioctl.c
+@@ -1412,9 +1412,9 @@ static int prism2_ioctl_siwretry(struct
+ /* what could be done, if firmware would support this.. */
+
+ if (rrq->flags & IW_RETRY_LIMIT) {
+- if (rrq->flags & IW_RETRY_MAX)
++ if (rrq->flags & IW_RETRY_LONG)
+ HFA384X_RID_LONGRETRYLIMIT = rrq->value;
+- else if (rrq->flags & IW_RETRY_MIN)
++ else if (rrq->flags & IW_RETRY_SHORT)
+ HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
+ else {
+ HFA384X_RID_LONGRETRYLIMIT = rrq->value;
+@@ -1468,14 +1468,14 @@ static int prism2_ioctl_giwretry(struct
+ rrq->value = le16_to_cpu(altretry);
+ else
+ rrq->value = local->manual_retry_count;
+- } else if ((rrq->flags & IW_RETRY_MAX)) {
+- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ } else if ((rrq->flags & IW_RETRY_LONG)) {
++ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ rrq->value = longretry;
+ } else {
+ rrq->flags = IW_RETRY_LIMIT;
+ rrq->value = shortretry;
+ if (shortretry != longretry)
+- rrq->flags |= IW_RETRY_MIN;
++ rrq->flags |= IW_RETRY_SHORT;
+ }
+ }
+ return 0;
+@@ -3908,7 +3908,7 @@ static void prism2_get_drvinfo(struct ne
+ local->sta_fw_ver & 0xff);
+ }
+
+-struct ethtool_ops prism2_ethtool_ops = {
++const struct ethtool_ops prism2_ethtool_ops = {
+ .get_drvinfo = prism2_get_drvinfo
+ };
+
+diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
+index 6dfa041..bc81b13 100644
+--- a/drivers/net/wireless/hostap/hostap_plx.c
++++ b/drivers/net/wireless/hostap/hostap_plx.c
+@@ -364,7 +364,7 @@ static int prism2_plx_check_cis(void __i
+
+ pos = 0;
+ while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
+- if (pos + cis[pos + 1] >= CIS_MAX_LEN)
++ if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
+ goto cis_error;
+
+ switch (cis[pos]) {
+@@ -391,7 +391,7 @@ static int prism2_plx_check_cis(void __i
+ break;
+
+ case CISTPL_MANFID:
+- if (cis[pos + 1] < 5)
++ if (cis[pos + 1] < 4)
+ goto cis_error;
+ manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
+ manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
+diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
+index e955db4..4e4eaa2 100644
+--- a/drivers/net/wireless/ipw2100.c
++++ b/drivers/net/wireless/ipw2100.c
+@@ -150,7 +150,6 @@ that only one external action is invoked
+ #include <linux/skbuff.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+-#define __KERNEL_SYSCALLS__
+ #include <linux/fs.h>
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+@@ -163,6 +162,7 @@ that only one external action is invoked
+ #include <linux/firmware.h>
+ #include <linux/acpi.h>
+ #include <linux/ctype.h>
++#include <linux/latency.h>
+
+ #include "ipw2100.h"
+
+@@ -1697,6 +1697,11 @@ static int ipw2100_up(struct ipw2100_pri
+ return 0;
+ }
+
++ /* the ipw2100 hardware really doesn't want power management delays
++ * longer than 175usec
++ */
++ modify_acceptable_latency("ipw2100", 175);
++
+ /* If the interrupt is enabled, turn it off... */
+ spin_lock_irqsave(&priv->low_lock, flags);
+ ipw2100_disable_interrupts(priv);
+@@ -1849,6 +1854,8 @@ static void ipw2100_down(struct ipw2100_
+ ipw2100_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
++ modify_acceptable_latency("ipw2100", INFINITE_LATENCY);
++
+ #ifdef ACPI_CSTATE_LIMIT_DEFINED
+ if (priv->config & CFG_C3_DISABLED) {
+ IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
+@@ -3248,7 +3255,7 @@ static void ipw2100_irq_tasklet(struct i
+ IPW_DEBUG_ISR("exit\n");
+ }
+
+-static irqreturn_t ipw2100_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t ipw2100_interrupt(int irq, void *data)
+ {
+ struct ipw2100_priv *priv = data;
+ u32 inta, inta_mask;
+@@ -5911,7 +5918,7 @@ static u32 ipw2100_ethtool_get_link(stru
+ return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
+ }
+
+-static struct ethtool_ops ipw2100_ethtool_ops = {
++static const struct ethtool_ops ipw2100_ethtool_ops = {
+ .get_link = ipw2100_ethtool_get_link,
+ .get_drvinfo = ipw_ethtool_get_drvinfo,
+ };
+@@ -6254,19 +6261,22 @@ static int ipw2100_pci_init_one(struct p
+ * member to call a function that then just turns and calls ipw2100_up.
+ * net_dev->init is called after name allocation but before the
+ * notifier chain is called */
+- mutex_lock(&priv->action_mutex);
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling register_netdev.\n");
+- goto fail_unlock;
++ goto fail;
+ }
++
++ mutex_lock(&priv->action_mutex);
+ registered = 1;
+
+ IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
+
+ /* perform this after register_netdev so that dev->name is set */
+- sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
++ err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
++ if (err)
++ goto fail_unlock;
+
+ /* If the RF Kill switch is disabled, go ahead and complete the
+ * startup sequence */
+@@ -6531,14 +6541,18 @@ static int __init ipw2100_init(void)
+ printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+ printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
+
+- ret = pci_module_init(&ipw2100_pci_driver);
++ ret = pci_register_driver(&ipw2100_pci_driver);
++ if (ret)
++ goto out;
+
++ set_acceptable_latency("ipw2100", INFINITE_LATENCY);
+ #ifdef CONFIG_IPW2100_DEBUG
+ ipw2100_debug_level = debug;
+- driver_create_file(&ipw2100_pci_driver.driver,
+- &driver_attr_debug_level);
++ ret = driver_create_file(&ipw2100_pci_driver.driver,
++ &driver_attr_debug_level);
+ #endif
+
++out:
+ return ret;
+ }
+
+@@ -6553,6 +6567,7 @@ static void __exit ipw2100_exit(void)
+ &driver_attr_debug_level);
+ #endif
+ pci_unregister_driver(&ipw2100_pci_driver);
++ remove_acceptable_latency("ipw2100");
+ }
+
+ module_init(ipw2100_init);
+@@ -6957,7 +6972,7 @@ static int ipw2100_wx_set_essid(struct n
+ }
+
+ if (wrqu->essid.flags && wrqu->essid.length) {
+- length = wrqu->essid.length - 1;
++ length = wrqu->essid.length;
+ essid = extra;
+ }
+
+@@ -7050,7 +7065,7 @@ static int ipw2100_wx_get_nick(struct ne
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+- wrqu->data.length = strlen(priv->nick) + 1;
++ wrqu->data.length = strlen(priv->nick);
+ memcpy(extra, priv->nick, wrqu->data.length);
+ wrqu->data.flags = 1; /* active */
+
+@@ -7342,14 +7357,14 @@ static int ipw2100_wx_set_retry(struct n
+ goto done;
+ }
+
+- if (wrqu->retry.flags & IW_RETRY_MIN) {
++ if (wrqu->retry.flags & IW_RETRY_SHORT) {
+ err = ipw2100_set_short_retry(priv, wrqu->retry.value);
+ IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
+ wrqu->retry.value);
+ goto done;
+ }
+
+- if (wrqu->retry.flags & IW_RETRY_MAX) {
++ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ err = ipw2100_set_long_retry(priv, wrqu->retry.value);
+ IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
+ wrqu->retry.value);
+@@ -7382,14 +7397,14 @@ static int ipw2100_wx_get_retry(struct n
+ if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
+ return -EINVAL;
+
+- if (wrqu->retry.flags & IW_RETRY_MAX) {
+- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ if (wrqu->retry.flags & IW_RETRY_LONG) {
++ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ wrqu->retry.value = priv->long_retry_limit;
+ } else {
+ wrqu->retry.flags =
+ (priv->short_retry_limit !=
+ priv->long_retry_limit) ?
+- IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT;
++ IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
+
+ wrqu->retry.value = priv->short_retry_limit;
+ }
+diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
+index b3300ff..1f74281 100644
+--- a/drivers/net/wireless/ipw2200.c
++++ b/drivers/net/wireless/ipw2200.c
+@@ -70,7 +70,7 @@
+ #define VQ
+ #endif
+
+-#define IPW2200_VERSION "1.1.2" VK VD VM VP VR VQ
++#define IPW2200_VERSION "1.1.4" VK VD VM VP VR VQ
+ #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
+ #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
+ #define DRV_VERSION IPW2200_VERSION
+@@ -83,9 +83,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT);
+ MODULE_LICENSE("GPL");
+
+ static int cmdlog = 0;
+-#ifdef CONFIG_IPW2200_DEBUG
+ static int debug = 0;
+-#endif
+ static int channel = 0;
+ static int mode = 0;
+
+@@ -567,7 +565,6 @@ static inline void ipw_disable_interrupt
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+ }
+
+-#ifdef CONFIG_IPW2200_DEBUG
+ static char *ipw_error_desc(u32 val)
+ {
+ switch (val) {
+@@ -634,7 +631,6 @@ static void ipw_dump_error_log(struct ip
+ error->log[i].time,
+ error->log[i].data, error->log[i].event);
+ }
+-#endif
+
+ static inline int ipw_is_init(struct ipw_priv *priv)
+ {
+@@ -1435,9 +1431,7 @@ static ssize_t store_scan_age(struct dev
+ const char *buf, size_t count)
+ {
+ struct ipw_priv *priv = dev_get_drvdata(d);
+-#ifdef CONFIG_IPW2200_DEBUG
+ struct net_device *dev = priv->net_dev;
+-#endif
+ char buffer[] = "00000000";
+ unsigned long len =
+ (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
+@@ -1958,14 +1952,12 @@ static void ipw_irq_tasklet(struct ipw_p
+ IPW_WARNING("Firmware error detected. Restarting.\n");
+ if (priv->error) {
+ IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
+-#ifdef CONFIG_IPW2200_DEBUG
+ if (ipw_debug_level & IPW_DL_FW_ERRORS) {
+ struct ipw_fw_error *error =
+ ipw_alloc_error_log(priv);
+ ipw_dump_error_log(priv, error);
+ kfree(error);
+ }
+-#endif
+ } else {
+ priv->error = ipw_alloc_error_log(priv);
+ if (priv->error)
+@@ -1973,10 +1965,8 @@ static void ipw_irq_tasklet(struct ipw_p
+ else
+ IPW_DEBUG_FW("Error allocating sysfs 'error' "
+ "log.\n");
+-#ifdef CONFIG_IPW2200_DEBUG
+ if (ipw_debug_level & IPW_DL_FW_ERRORS)
+ ipw_dump_error_log(priv, priv->error);
+-#endif
+ }
+
+ /* XXX: If hardware encryption is for WPA/WPA2,
+@@ -2287,7 +2277,7 @@ static int ipw_send_scan_abort(struct ip
+ static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
+ {
+ struct ipw_sensitivity_calib calib = {
+- .beacon_rssi_raw = sens,
++ .beacon_rssi_raw = cpu_to_le16(sens),
+ };
+
+ return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
+@@ -2353,6 +2343,7 @@ static int ipw_send_card_disable(struct
+ return -1;
+ }
+
++ phy_off = cpu_to_le32(phy_off);
+ return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off),
+ &phy_off);
+ }
+@@ -2414,7 +2405,7 @@ static int ipw_set_tx_power(struct ipw_p
+ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
+ {
+ struct ipw_rts_threshold rts_threshold = {
+- .rts_threshold = rts,
++ .rts_threshold = cpu_to_le16(rts),
+ };
+
+ if (!priv) {
+@@ -2429,7 +2420,7 @@ static int ipw_send_rts_threshold(struct
+ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
+ {
+ struct ipw_frag_threshold frag_threshold = {
+- .frag_threshold = frag,
++ .frag_threshold = cpu_to_le16(frag),
+ };
+
+ if (!priv) {
+@@ -2464,6 +2455,7 @@ static int ipw_send_power_mode(struct ip
+ break;
+ }
+
++ param = cpu_to_le32(mode);
+ return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
+ ¶m);
+ }
+@@ -2667,7 +2659,7 @@ static void ipw_fw_dma_abort(struct ipw_
+
+ IPW_DEBUG_FW(">> :\n");
+
+- //set the Stop and Abort bit
++ /* set the Stop and Abort bit */
+ control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
+ ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
+ priv->sram_desc.last_cb_index = 0;
+@@ -3002,8 +2994,6 @@ static int ipw_load_ucode(struct ipw_pri
+ if (rc < 0)
+ return rc;
+
+-// spin_lock_irqsave(&priv->lock, flags);
+-
+ for (addr = IPW_SHARED_LOWER_BOUND;
+ addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
+ ipw_write32(priv, addr, 0);
+@@ -3097,8 +3087,6 @@ static int ipw_load_ucode(struct ipw_pri
+ firmware have problem getting alive resp. */
+ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
+
+-// spin_unlock_irqrestore(&priv->lock, flags);
+-
+ return rc;
+ }
+
+@@ -3919,7 +3907,6 @@ static const struct ipw_status_code ipw_
+ {0x2E, "Cipher suite is rejected per security policy"},
+ };
+
+-#ifdef CONFIG_IPW2200_DEBUG
+ static const char *ipw_get_status_code(u16 status)
+ {
+ int i;
+@@ -3928,7 +3915,6 @@ static const char *ipw_get_status_code(u
+ return ipw_status_codes[i].reason;
+ return "Unknown status value.";
+ }
+-#endif
+
+ static void inline average_init(struct average *avg)
+ {
+@@ -4398,7 +4384,6 @@ static void ipw_rx_notification(struct i
+ if (priv->
+ status & (STATUS_ASSOCIATED |
+ STATUS_AUTH)) {
+-#ifdef CONFIG_IPW2200_DEBUG
+ struct notif_authenticate *auth
+ = ¬if->u.auth;
+ IPW_DEBUG(IPW_DL_NOTIF |
+@@ -4416,7 +4401,6 @@ static void ipw_rx_notification(struct i
+ ipw_get_status_code
+ (ntohs
+ (auth->status)));
+-#endif
+
+ priv->status &=
+ ~(STATUS_ASSOCIATING |
+@@ -5059,7 +5043,6 @@ static void ipw_rx_queue_replenish(void
+ }
+ list_del(element);
+
+- rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+@@ -5838,8 +5821,8 @@ static void ipw_send_tgi_tx_key(struct i
+ key.station_index = 0; /* always 0 for BSS */
+ key.flags = 0;
+ /* 0 for new key; previous value of counter (after fatal error) */
+- key.tx_counter[0] = 0;
+- key.tx_counter[1] = 0;
++ key.tx_counter[0] = cpu_to_le32(0);
++ key.tx_counter[1] = cpu_to_le32(0);
+
+ ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
+ }
+@@ -5973,7 +5956,6 @@ static void ipw_bg_adhoc_check(void *dat
+ mutex_unlock(&priv->mutex);
+ }
+
+-#ifdef CONFIG_IPW2200_DEBUG
+ static void ipw_debug_config(struct ipw_priv *priv)
+ {
+ IPW_DEBUG_INFO("Scan completed, no valid APs matched "
+@@ -5998,9 +5980,6 @@ static void ipw_debug_config(struct ipw_
+ IPW_DEBUG_INFO("PRIVACY off\n");
+ IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
+ }
+-#else
+-#define ipw_debug_config(x) do {} while (0)
+-#endif
+
+ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
+ {
+@@ -6188,7 +6167,7 @@ static void ipw_add_scan_channels(struct
+ }
+ }
+
+-static int ipw_request_scan(struct ipw_priv *priv)
++static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
+ {
+ struct ipw_scan_request_ext scan;
+ int err = 0, scan_type;
+@@ -6219,19 +6198,29 @@ static int ipw_request_scan(struct ipw_p
+ }
+
+ memset(&scan, 0, sizeof(scan));
++ scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+
+- if (priv->config & CFG_SPEED_SCAN)
++ if (type == IW_SCAN_TYPE_PASSIVE) {
++ IPW_DEBUG_WX("use passive scanning\n");
++ scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
++ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
++ cpu_to_le16(120);
++ ipw_add_scan_channels(priv, &scan, scan_type);
++ goto send_request;
++ }
++
++ /* Use active scan by default. */
++ if (priv->config & CFG_SPEED_SCAN)
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+- cpu_to_le16(30);
++ cpu_to_le16(30);
+ else
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+- cpu_to_le16(20);
++ cpu_to_le16(20);
+
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
+- cpu_to_le16(20);
+- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
++ cpu_to_le16(20);
+
+- scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
++ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+
+ #ifdef CONFIG_IPW2200_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+@@ -6268,7 +6257,7 @@ static int ipw_request_scan(struct ipw_p
+ *
+ * TODO: Move SPEED SCAN support to all modes and bands */
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+- cpu_to_le16(2000);
++ cpu_to_le16(2000);
+ } else {
+ #endif /* CONFIG_IPW2200_MONITOR */
+ /* If we are roaming, then make this a directed scan for the
+@@ -6294,6 +6283,7 @@ static int ipw_request_scan(struct ipw_p
+ }
+ #endif
+
++send_request:
+ err = ipw_send_scan_request_ext(priv, &scan);
+ if (err) {
+ IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+@@ -6304,11 +6294,19 @@ static int ipw_request_scan(struct ipw_p
+ priv->status &= ~STATUS_SCAN_PENDING;
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IPW_SCAN_CHECK_WATCHDOG);
+- done:
++done:
+ mutex_unlock(&priv->mutex);
+ return err;
+ }
+
++static int ipw_request_passive_scan(struct ipw_priv *priv) {
++ return ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
++}
++
++static int ipw_request_scan(struct ipw_priv *priv) {
++ return ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
++}
++
+ static void ipw_bg_abort_scan(void *data)
+ {
+ struct ipw_priv *priv = data;
+@@ -6387,13 +6385,6 @@ static int ipw_wx_set_genie(struct net_d
+ (wrqu->data.length && extra == NULL))
+ return -EINVAL;
+
+- //mutex_lock(&priv->mutex);
+-
+- //if (!ieee->wpa_enabled) {
+- // err = -EOPNOTSUPP;
+- // goto out;
+- //}
+-
+ if (wrqu->data.length) {
+ buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ if (buf == NULL) {
+@@ -6413,7 +6404,6 @@ static int ipw_wx_set_genie(struct net_d
+
+ ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+ out:
+- //mutex_unlock(&priv->mutex);
+ return err;
+ }
+
+@@ -6426,13 +6416,6 @@ static int ipw_wx_get_genie(struct net_d
+ struct ieee80211_device *ieee = priv->ieee;
+ int err = 0;
+
+- //mutex_lock(&priv->mutex);
+-
+- //if (!ieee->wpa_enabled) {
+- // err = -EOPNOTSUPP;
+- // goto out;
+- //}
+-
+ if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
+ wrqu->data.length = 0;
+ goto out;
+@@ -6447,7 +6430,6 @@ static int ipw_wx_get_genie(struct net_d
+ memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
+
+ out:
+- //mutex_unlock(&priv->mutex);
+ return err;
+ }
+
+@@ -6558,7 +6540,6 @@ static int ipw_wx_set_auth(struct net_de
+ ieee->ieee802_1x = param->value;
+ break;
+
+- //case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ ieee->privacy_invoked = param->value;
+ break;
+@@ -6680,7 +6661,7 @@ static int ipw_wx_set_mlme(struct net_de
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+- // silently ignore
++ /* silently ignore */
+ break;
+
+ case IW_MLME_DISASSOC:
+@@ -6811,7 +6792,7 @@ static int ipw_qos_activate(struct ipw_p
+ burst_duration = ipw_qos_get_burst_duration(priv);
+ for (i = 0; i < QOS_QUEUE_NUM; i++)
+ qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
+- (u16) burst_duration;
++ (u16)burst_duration;
+ } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ if (type == IEEE_B) {
+ IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n",
+@@ -6843,11 +6824,20 @@ static int ipw_qos_activate(struct ipw_p
+ burst_duration = ipw_qos_get_burst_duration(priv);
+ for (i = 0; i < QOS_QUEUE_NUM; i++)
+ qos_parameters[QOS_PARAM_SET_ACTIVE].
+- tx_op_limit[i] = (u16) burst_duration;
++ tx_op_limit[i] = (u16)burst_duration;
+ }
+ }
+
+ IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
++ for (i = 0; i < 3; i++) {
++ int j;
++ for (j = 0; j < QOS_QUEUE_NUM; j++) {
++ qos_parameters[i].cw_min[j] = cpu_to_le16(qos_parameters[i].cw_min[j]);
++ qos_parameters[i].cw_max[j] = cpu_to_le16(qos_parameters[i].cw_max[j]);
++ qos_parameters[i].tx_op_limit[j] = cpu_to_le16(qos_parameters[i].tx_op_limit[j]);
++ }
++ }
++
+ err = ipw_send_qos_params_command(priv,
+ (struct ieee80211_qos_parameters *)
+ &(qos_parameters[0]));
+@@ -7086,7 +7076,7 @@ static int ipw_qos_set_tx_queue_command(
+
+ if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) {
+ tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
+- tfd->tfd.tfd_26.mchdr.qos_ctrl |= CTRL_QOS_NO_ACK;
++ tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK);
+ }
+ return 0;
+ }
+@@ -7667,7 +7657,6 @@ static void ipw_handle_data_packet_monit
+ /* Big bitfield of all the fields we provide in radiotap */
+ ipw_rt->rt_hdr.it_present =
+ ((1 << IEEE80211_RADIOTAP_FLAGS) |
+- (1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+@@ -7676,6 +7665,7 @@ static void ipw_handle_data_packet_monit
+
+ /* Zero the flags, we'll add to them as we go */
+ ipw_rt->rt_flags = 0;
++ ipw_rt->rt_tsf = 0ULL;
+
+ /* Convert signal to DBM */
+ ipw_rt->rt_dbmsignal = antsignal;
+@@ -7794,7 +7784,6 @@ static void ipw_handle_promiscuous_rx(st
+ s8 noise = frame->noise;
+ u8 rate = frame->rate;
+ short len = le16_to_cpu(pkt->u.frame.length);
+- u64 tsf = 0;
+ struct sk_buff *skb;
+ int hdr_only = 0;
+ u16 filter = priv->prom_priv->filter;
+@@ -7829,17 +7818,17 @@ static void ipw_handle_promiscuous_rx(st
+ }
+
+ hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
+- if (ieee80211_is_management(hdr->frame_ctl)) {
++ if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
+ if (filter & IPW_PROM_NO_MGMT)
+ return;
+ if (filter & IPW_PROM_MGMT_HEADER_ONLY)
+ hdr_only = 1;
+- } else if (ieee80211_is_control(hdr->frame_ctl)) {
++ } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
+ if (filter & IPW_PROM_NO_CTL)
+ return;
+ if (filter & IPW_PROM_CTL_HEADER_ONLY)
+ hdr_only = 1;
+- } else if (ieee80211_is_data(hdr->frame_ctl)) {
++ } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
+ if (filter & IPW_PROM_NO_DATA)
+ return;
+ if (filter & IPW_PROM_DATA_HEADER_ONLY)
+@@ -7857,7 +7846,7 @@ static void ipw_handle_promiscuous_rx(st
+ ipw_rt = (void *)skb->data;
+
+ if (hdr_only)
+- len = ieee80211_get_hdrlen(hdr->frame_ctl);
++ len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ memcpy(ipw_rt->payload, hdr, len);
+
+@@ -7880,7 +7869,6 @@ static void ipw_handle_promiscuous_rx(st
+ /* Big bitfield of all the fields we provide in radiotap */
+ ipw_rt->rt_hdr.it_present =
+ ((1 << IEEE80211_RADIOTAP_FLAGS) |
+- (1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+@@ -7889,8 +7877,7 @@ static void ipw_handle_promiscuous_rx(st
+
+ /* Zero the flags, we'll add to them as we go */
+ ipw_rt->rt_flags = 0;
+-
+- ipw_rt->rt_tsf = tsf;
++ ipw_rt->rt_tsf = 0ULL;
+
+ /* Convert to DBM */
+ ipw_rt->rt_dbmsignal = signal;
+@@ -8163,8 +8150,7 @@ static void ipw_rx(struct ipw_priv *priv
+ switch (pkt->header.message_type) {
+ case RX_FRAME_TYPE: /* 802.11 frame */ {
+ struct ieee80211_rx_stats stats = {
+- .rssi =
+- le16_to_cpu(pkt->u.frame.rssi_dbm) -
++ .rssi = pkt->u.frame.rssi_dbm -
+ IPW_RSSI_TO_DBM,
+ .signal =
+ le16_to_cpu(pkt->u.frame.rssi_dbm) -
+@@ -8599,9 +8585,26 @@ static int ipw_wx_get_freq(struct net_de
+ * configured CHANNEL then return that; otherwise return ANY */
+ mutex_lock(&priv->mutex);
+ if (priv->config & CFG_STATIC_CHANNEL ||
+- priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
+- wrqu->freq.m = priv->channel;
+- else
++ priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
++ int i;
++
++ i = ieee80211_channel_to_index(priv->ieee, priv->channel);
++ BUG_ON(i == -1);
++ wrqu->freq.e = 1;
++
++ switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
++ case IEEE80211_52GHZ_BAND:
++ wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
++ break;
++
++ case IEEE80211_24GHZ_BAND:
++ wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
++ break;
++
++ default:
++ BUG();
++ }
++ } else
+ wrqu->freq.m = 0;
+
+ mutex_unlock(&priv->mutex);
+@@ -8857,42 +8860,36 @@ static int ipw_wx_set_essid(struct net_d
+ union iwreq_data *wrqu, char *extra)
+ {
+ struct ipw_priv *priv = ieee80211_priv(dev);
+- char *essid = ""; /* ANY */
+- int length = 0;
+- mutex_lock(&priv->mutex);
+- if (wrqu->essid.flags && wrqu->essid.length) {
+- length = wrqu->essid.length - 1;
+- essid = extra;
+- }
+- if (length == 0) {
+- IPW_DEBUG_WX("Setting ESSID to ANY\n");
+- if ((priv->config & CFG_STATIC_ESSID) &&
+- !(priv->status & (STATUS_ASSOCIATED |
+- STATUS_ASSOCIATING))) {
+- IPW_DEBUG_ASSOC("Attempting to associate with new "
+- "parameters.\n");
+- priv->config &= ~CFG_STATIC_ESSID;
+- ipw_associate(priv);
+- }
+- mutex_unlock(&priv->mutex);
+- return 0;
+- }
++ int length;
+
+- length = min(length, IW_ESSID_MAX_SIZE);
++ mutex_lock(&priv->mutex);
++
++ if (!wrqu->essid.flags)
++ {
++ IPW_DEBUG_WX("Setting ESSID to ANY\n");
++ ipw_disassociate(priv);
++ priv->config &= ~CFG_STATIC_ESSID;
++ ipw_associate(priv);
++ mutex_unlock(&priv->mutex);
++ return 0;
++ }
++
++ length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
+
+ priv->config |= CFG_STATIC_ESSID;
+
+- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
++ if (priv->essid_len == length && !memcmp(priv->essid, extra, length)
++ && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) {
+ IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+- IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
++ IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length),
+ length);
+
+ priv->essid_len = length;
+- memcpy(priv->essid, essid, priv->essid_len);
++ memcpy(priv->essid, extra, priv->essid_len);
+
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
+@@ -8954,7 +8951,7 @@ static int ipw_wx_get_nick(struct net_de
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ IPW_DEBUG_WX("Getting nick\n");
+ mutex_lock(&priv->mutex);
+- wrqu->data.length = strlen(priv->nick) + 1;
++ wrqu->data.length = strlen(priv->nick);
+ memcpy(extra, priv->nick, wrqu->data.length);
+ wrqu->data.flags = 1; /* active */
+ mutex_unlock(&priv->mutex);
+@@ -9273,13 +9270,13 @@ static int ipw_wx_set_retry(struct net_d
+ if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
+ return 0;
+
+- if (wrqu->retry.value < 0 || wrqu->retry.value > 255)
++ if (wrqu->retry.value < 0 || wrqu->retry.value >= 255)
+ return -EINVAL;
+
+ mutex_lock(&priv->mutex);
+- if (wrqu->retry.flags & IW_RETRY_MIN)
++ if (wrqu->retry.flags & IW_RETRY_SHORT)
+ priv->short_retry_limit = (u8) wrqu->retry.value;
+- else if (wrqu->retry.flags & IW_RETRY_MAX)
++ else if (wrqu->retry.flags & IW_RETRY_LONG)
+ priv->long_retry_limit = (u8) wrqu->retry.value;
+ else {
+ priv->short_retry_limit = (u8) wrqu->retry.value;
+@@ -9308,11 +9305,11 @@ static int ipw_wx_get_retry(struct net_d
+ return -EINVAL;
+ }
+
+- if (wrqu->retry.flags & IW_RETRY_MAX) {
+- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ if (wrqu->retry.flags & IW_RETRY_LONG) {
++ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ wrqu->retry.value = priv->long_retry_limit;
+- } else if (wrqu->retry.flags & IW_RETRY_MIN) {
+- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
++ } else if (wrqu->retry.flags & IW_RETRY_SHORT) {
++ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
+ wrqu->retry.value = priv->short_retry_limit;
+ } else {
+ wrqu->retry.flags = IW_RETRY_LIMIT;
+@@ -9396,15 +9393,19 @@ static int ipw_wx_set_scan(struct net_de
+ union iwreq_data *wrqu, char *extra)
+ {
+ struct ipw_priv *priv = ieee80211_priv(dev);
+- struct iw_scan_req *req = NULL;
+- if (wrqu->data.length
+- && wrqu->data.length == sizeof(struct iw_scan_req)) {
+- req = (struct iw_scan_req *)extra;
++ struct iw_scan_req *req = (struct iw_scan_req *)extra;
++
++ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ ipw_request_direct_scan(priv, req->essid,
+ req->essid_len);
+ return 0;
+ }
++ if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
++ queue_work(priv->workqueue,
++ &priv->request_passive_scan);
++ return 0;
++ }
+ }
+
+ IPW_DEBUG_WX("Start scan\n");
+@@ -9766,7 +9767,7 @@ static int ipw_wx_set_monitor(struct net
+ return 0;
+ }
+
+-#endif // CONFIG_IPW2200_MONITOR
++#endif /* CONFIG_IPW2200_MONITOR */
+
+ static int ipw_wx_reset(struct net_device *dev,
+ struct iw_request_info *info,
+@@ -10009,7 +10010,7 @@ static void init_sys_config(struct ipw_
+ sys_config->dot11g_auto_detection = 0;
+ sys_config->enable_cts_to_self = 0;
+ sys_config->bt_coexist_collision_thr = 0;
+- sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256
++ sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
+ sys_config->silence_threshold = 0x1e;
+ }
+
+@@ -10113,7 +10114,7 @@ static int ipw_tx_skb(struct ipw_priv *p
+ switch (priv->ieee->sec.level) {
+ case SEC_LEVEL_3:
+ tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+- IEEE80211_FCTL_PROTECTED;
++ cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ /* XXX: ACK flag must be set for CCMP even if it
+ * is a multicast/broadcast packet, because CCMP
+ * group communication encrypted by GTK is
+@@ -10128,14 +10129,14 @@ static int ipw_tx_skb(struct ipw_priv *p
+ break;
+ case SEC_LEVEL_2:
+ tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+- IEEE80211_FCTL_PROTECTED;
++ cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
+ tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
+ tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
+ break;
+ case SEC_LEVEL_1:
+ tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+- IEEE80211_FCTL_PROTECTED;
++ cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ tfd->u.data.key_index = priv->ieee->tx_keyidx;
+ if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
+ 40)
+@@ -10267,17 +10268,17 @@ static void ipw_handle_promiscuous_tx(st
+
+ /* Filtering of fragment chains is done agains the first fragment */
+ hdr = (void *)txb->fragments[0]->data;
+- if (ieee80211_is_management(hdr->frame_ctl)) {
++ if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
+ if (filter & IPW_PROM_NO_MGMT)
+ return;
+ if (filter & IPW_PROM_MGMT_HEADER_ONLY)
+ hdr_only = 1;
+- } else if (ieee80211_is_control(hdr->frame_ctl)) {
++ } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
+ if (filter & IPW_PROM_NO_CTL)
+ return;
+ if (filter & IPW_PROM_CTL_HEADER_ONLY)
+ hdr_only = 1;
+- } else if (ieee80211_is_data(hdr->frame_ctl)) {
++ } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
+ if (filter & IPW_PROM_NO_DATA)
+ return;
+ if (filter & IPW_PROM_DATA_HEADER_ONLY)
+@@ -10292,7 +10293,7 @@ static void ipw_handle_promiscuous_tx(st
+
+ if (hdr_only) {
+ hdr = (void *)src->data;
+- len = ieee80211_get_hdrlen(hdr->frame_ctl);
++ len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+ } else
+ len = src->len;
+
+@@ -10458,7 +10459,7 @@ static int ipw_ethtool_set_eeprom(struct
+ return 0;
+ }
+
+-static struct ethtool_ops ipw_ethtool_ops = {
++static const struct ethtool_ops ipw_ethtool_ops = {
+ .get_link = ipw_ethtool_get_link,
+ .get_drvinfo = ipw_ethtool_get_drvinfo,
+ .get_eeprom_len = ipw_ethtool_get_eeprom_len,
+@@ -10466,7 +10467,7 @@ static struct ethtool_ops ipw_ethtool_op
+ .set_eeprom = ipw_ethtool_set_eeprom,
+ };
+
+-static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t ipw_isr(int irq, void *data)
+ {
+ struct ipw_priv *priv = data;
+ u32 inta, inta_mask;
+@@ -10636,6 +10637,8 @@ static int ipw_setup_deferred_work(struc
+ INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv);
+ INIT_WORK(&priv->request_scan,
+ (void (*)(void *))ipw_request_scan, priv);
++ INIT_WORK(&priv->request_passive_scan,
++ (void (*)(void *))ipw_request_passive_scan, priv);
+ INIT_WORK(&priv->gather_stats,
+ (void (*)(void *))ipw_bg_gather_stats, priv);
+ INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv);
+@@ -11488,9 +11491,7 @@ static int ipw_pci_probe(struct pci_dev
+
+ priv->net_dev = net_dev;
+ priv->pci_dev = pdev;
+-#ifdef CONFIG_IPW2200_DEBUG
+ ipw_debug_level = debug;
+-#endif
+ spin_lock_init(&priv->irq_lock);
+ spin_lock_init(&priv->lock);
+ for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
+@@ -11755,6 +11756,16 @@ static int ipw_pci_resume(struct pci_dev
+ }
+ #endif
+
++static void ipw_pci_shutdown(struct pci_dev *pdev)
++{
++ struct ipw_priv *priv = pci_get_drvdata(pdev);
++
++ /* Take down the device; powers it off, etc. */
++ ipw_down(priv);
++
++ pci_disable_device(pdev);
++}
++
+ /* driver initialization stuff */
+ static struct pci_driver ipw_driver = {
+ .name = DRV_NAME,
+@@ -11765,6 +11776,7 @@ static struct pci_driver ipw_driver = {
+ .suspend = ipw_pci_suspend,
+ .resume = ipw_pci_resume,
+ #endif
++ .shutdown = ipw_pci_shutdown,
+ };
+
+ static int __init ipw_init(void)
+@@ -11774,7 +11786,7 @@ static int __init ipw_init(void)
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+- ret = pci_module_init(&ipw_driver);
++ ret = pci_register_driver(&ipw_driver);
+ if (ret) {
+ IPW_ERROR("Unable to initialize PCI module\n");
+ return ret;
+@@ -11808,10 +11820,8 @@ MODULE_PARM_DESC(auto_create, "auto crea
+ module_param(led, int, 0444);
+ MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n");
+
+-#ifdef CONFIG_IPW2200_DEBUG
+ module_param(debug, int, 0444);
+ MODULE_PARM_DESC(debug, "debug output mask");
+-#endif
+
+ module_param(channel, int, 0444);
+ MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
+diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
+index 8b1cd7c..dad5eed 100644
+--- a/drivers/net/wireless/ipw2200.h
++++ b/drivers/net/wireless/ipw2200.h
+@@ -713,7 +713,6 @@ struct ipw_rx_packet {
+
+ struct ipw_rx_mem_buffer {
+ dma_addr_t dma_addr;
+- struct ipw_rx_buffer *rxb;
+ struct sk_buff *skb;
+ struct list_head list;
+ }; /* Not transferred over network, so not __attribute__ ((packed)) */
+@@ -1297,6 +1296,7 @@ struct ipw_priv {
+ struct work_struct system_config;
+ struct work_struct rx_replenish;
+ struct work_struct request_scan;
++ struct work_struct request_passive_scan;
+ struct work_struct adapter_restart;
+ struct work_struct rf_kill;
+ struct work_struct up;
+@@ -1381,13 +1381,18 @@ BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,
+ BIT_ARG16(x)
+
+
+-#ifdef CONFIG_IPW2200_DEBUG
+ #define IPW_DEBUG(level, fmt, args...) \
+ do { if (ipw_debug_level & (level)) \
+ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
++
++#ifdef CONFIG_IPW2200_DEBUG
++#define IPW_LL_DEBUG(level, fmt, args...) \
++do { if (ipw_debug_level & (level)) \
++ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
++ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+ #else
+-#define IPW_DEBUG(level, fmt, args...) do {} while (0)
++#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
+ #endif /* CONFIG_IPW2200_DEBUG */
+
+ /*
+@@ -1457,28 +1462,27 @@ do { if (ipw_debug_level & (level)) \
+
+ #define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a)
+ #define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a)
+-#define IPW_DEBUG_STATUS(f, a...) IPW_DEBUG(IPW_DL_STATUS, f, ## a)
+-#define IPW_DEBUG_TRACE(f, a...) IPW_DEBUG(IPW_DL_TRACE, f, ## a)
+-#define IPW_DEBUG_RX(f, a...) IPW_DEBUG(IPW_DL_RX, f, ## a)
+-#define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a)
+-#define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a)
++#define IPW_DEBUG_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a)
++#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a)
++#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a)
++#define IPW_DEBUG_ISR(f, a...) IPW_LL_DEBUG(IPW_DL_ISR, f, ## a)
+ #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
+-#define IPW_DEBUG_LED(f, a...) IPW_DEBUG(IPW_DL_LED, f, ## a)
+-#define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a)
+-#define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
+-#define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a)
+-#define IPW_DEBUG_FW(f, a...) IPW_DEBUG(IPW_DL_FW, f, ## a)
++#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a)
++#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a)
++#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
++#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a)
++#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a)
+ #define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
+ #define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
+-#define IPW_DEBUG_IO(f, a...) IPW_DEBUG(IPW_DL_IO, f, ## a)
+-#define IPW_DEBUG_ORD(f, a...) IPW_DEBUG(IPW_DL_ORD, f, ## a)
+-#define IPW_DEBUG_FW_INFO(f, a...) IPW_DEBUG(IPW_DL_FW_INFO, f, ## a)
++#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a)
++#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a)
++#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a)
+ #define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
+ #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+ #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+-#define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a)
+-#define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a)
+-#define IPW_DEBUG_QOS(f, a...) IPW_DEBUG(IPW_DL_QOS, f, ## a)
++#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a)
++#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a)
++#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a)
+
+ #include <linux/ctype.h>
+
+@@ -1947,10 +1951,17 @@ struct host_cmd {
+ u32 *param;
+ } __attribute__ ((packed));
+
++struct cmdlog_host_cmd {
++ u8 cmd;
++ u8 len;
++ u16 reserved;
++ char param[124];
++} __attribute__ ((packed));
++
+ struct ipw_cmd_log {
+ unsigned long jiffies;
+ int retcode;
+- struct host_cmd cmd;
++ struct cmdlog_host_cmd cmd;
+ };
+
+ /* SysConfig command parameters ... */
+diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
+index 36b5e00..6714e0d 100644
+--- a/drivers/net/wireless/netwave_cs.c
++++ b/drivers/net/wireless/netwave_cs.c
+@@ -207,7 +207,7 @@ static int netwave_start_xmit( struct sk
+ static int netwave_rx( struct net_device *dev);
+
+ /* Interrupt routines */
+-static irqreturn_t netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t netwave_interrupt(int irq, void *dev_id);
+ static void netwave_watchdog(struct net_device *);
+
+ /* Statistics */
+@@ -1072,7 +1072,7 @@ static int netwave_start_xmit(struct sk_
+ } /* netwave_start_xmit */
+
+ /*
+- * Function netwave_interrupt (irq, dev_id, regs)
++ * Function netwave_interrupt (irq, dev_id)
+ *
+ * This function is the interrupt handler for the Netwave card. This
+ * routine will be called whenever:
+@@ -1081,7 +1081,7 @@ static int netwave_start_xmit(struct sk_
+ * ready to transmit another packet.
+ * 3. A command has completed execution.
+ */
+-static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs)
++static irqreturn_t netwave_interrupt(int irq, void* dev_id)
+ {
+ kio_addr_t iobase;
+ u_char __iomem *ramBase;
+diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
+index 317ace7..336caba 100644
+--- a/drivers/net/wireless/orinoco.c
++++ b/drivers/net/wireless/orinoco.c
+@@ -82,6 +82,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/ethtool.h>
++#include <linux/if_arp.h>
+ #include <linux/wireless.h>
+ #include <net/iw_handler.h>
+ #include <net/ieee80211.h>
+@@ -164,7 +165,7 @@ static const u8 encaps_hdr[] = {0xaa, 0x
+ #define MAX_RID_LEN 1024
+
+ static const struct iw_handler_def orinoco_handler_def;
+-static struct ethtool_ops orinoco_ethtool_ops;
++static const struct ethtool_ops orinoco_ethtool_ops;
+
+ /********************************************************************/
+ /* Data tables */
+@@ -1951,9 +1952,9 @@ static void __orinoco_ev_wterr(struct ne
+ dev->name);
+ }
+
+-irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t orinoco_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *)dev_id;
++ struct net_device *dev = dev_id;
+ struct orinoco_private *priv = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int count = MAX_IRQLOOPS_PER_IRQ;
+@@ -2456,6 +2457,7 @@ void free_orinocodev(struct net_device *
+ /* Wireless extensions */
+ /********************************************************************/
+
++/* Return : < 0 -> error code ; >= 0 -> length */
+ static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
+ char buf[IW_ESSID_MAX_SIZE+1])
+ {
+@@ -2500,9 +2502,9 @@ static int orinoco_hw_get_essid(struct o
+ len = le16_to_cpu(essidbuf.len);
+ BUG_ON(len > IW_ESSID_MAX_SIZE);
+
+- memset(buf, 0, IW_ESSID_MAX_SIZE+1);
++ memset(buf, 0, IW_ESSID_MAX_SIZE);
+ memcpy(buf, p, len);
+- buf[len] = '\0';
++ err = len;
+
+ fail_unlock:
+ orinoco_unlock(priv, &flags);
+@@ -3026,17 +3028,18 @@ static int orinoco_ioctl_getessid(struct
+
+ if (netif_running(dev)) {
+ err = orinoco_hw_get_essid(priv, &active, essidbuf);
+- if (err)
++ if (err < 0)
+ return err;
++ erq->length = err;
+ } else {
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+- memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
++ memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
++ erq->length = strlen(priv->desired_essid);
+ orinoco_unlock(priv, &flags);
+ }
+
+ erq->flags = 1;
+- erq->length = strlen(essidbuf) + 1;
+
+ return 0;
+ }
+@@ -3074,10 +3077,10 @@ static int orinoco_ioctl_getnick(struct
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+- memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
++ memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
+ orinoco_unlock(priv, &flags);
+
+- nrq->length = strlen(nickbuf)+1;
++ nrq->length = strlen(priv->nick);
+
+ return 0;
+ }
+@@ -3574,14 +3577,14 @@ static int orinoco_ioctl_getretry(struct
+ rrq->value = lifetime * 1000; /* ??? */
+ } else {
+ /* By default, display the min number */
+- if ((rrq->flags & IW_RETRY_MAX)) {
+- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ if ((rrq->flags & IW_RETRY_LONG)) {
++ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ rrq->value = long_limit;
+ } else {
+ rrq->flags = IW_RETRY_LIMIT;
+ rrq->value = short_limit;
+ if(short_limit != long_limit)
+- rrq->flags |= IW_RETRY_MIN;
++ rrq->flags |= IW_RETRY_SHORT;
+ }
+ }
+
+@@ -4292,7 +4295,7 @@ static void orinoco_get_drvinfo(struct n
+ "PCMCIA %p", priv->hw.iobase);
+ }
+
+-static struct ethtool_ops orinoco_ethtool_ops = {
++static const struct ethtool_ops orinoco_ethtool_ops = {
+ .get_drvinfo = orinoco_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ };
+diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
+index 16db3e1..4720fb2 100644
+--- a/drivers/net/wireless/orinoco.h
++++ b/drivers/net/wireless/orinoco.h
+@@ -128,17 +128,13 @@ extern void free_orinocodev(struct net_d
+ extern int __orinoco_up(struct net_device *dev);
+ extern int __orinoco_down(struct net_device *dev);
+ extern int orinoco_reinit_firmware(struct net_device *dev);
+-extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
++extern irqreturn_t orinoco_interrupt(int irq, void * dev_id);
+
+ /********************************************************************/
+ /* Locking and synchronization functions */
+ /********************************************************************/
+
+-/* These functions *must* be inline or they will break horribly on
+- * SPARC, due to its weird semantics for save/restore flags. extern
+- * inline should prevent the kernel from linking or module from
+- * loading if they are not inlined. */
+-extern inline int orinoco_lock(struct orinoco_private *priv,
++static inline int orinoco_lock(struct orinoco_private *priv,
+ unsigned long *flags)
+ {
+ spin_lock_irqsave(&priv->lock, *flags);
+@@ -151,7 +147,7 @@ extern inline int orinoco_lock(struct or
+ return 0;
+ }
+
+-extern inline void orinoco_unlock(struct orinoco_private *priv,
++static inline void orinoco_unlock(struct orinoco_private *priv,
+ unsigned long *flags)
+ {
+ spin_unlock_irqrestore(&priv->lock, *flags);
+diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
+index bf05b90..eaf3d13 100644
+--- a/drivers/net/wireless/orinoco_nortel.c
++++ b/drivers/net/wireless/orinoco_nortel.c
+@@ -304,7 +304,7 @@ MODULE_LICENSE("Dual MPL/GPL");
+ static int __init orinoco_nortel_init(void)
+ {
+ printk(KERN_DEBUG "%s\n", version);
+- return pci_module_init(&orinoco_nortel_driver);
++ return pci_register_driver(&orinoco_nortel_driver);
+ }
+
+ static void __exit orinoco_nortel_exit(void)
+diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
+index 1759c54..97a8b4f 100644
+--- a/drivers/net/wireless/orinoco_pci.c
++++ b/drivers/net/wireless/orinoco_pci.c
+@@ -244,7 +244,7 @@ MODULE_LICENSE("Dual MPL/GPL");
+ static int __init orinoco_pci_init(void)
+ {
+ printk(KERN_DEBUG "%s\n", version);
+- return pci_module_init(&orinoco_pci_driver);
++ return pci_register_driver(&orinoco_pci_driver);
+ }
+
+ static void __exit orinoco_pci_exit(void)
+diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
+index 7f006f6..31162ac 100644
+--- a/drivers/net/wireless/orinoco_plx.c
++++ b/drivers/net/wireless/orinoco_plx.c
+@@ -351,7 +351,7 @@ MODULE_LICENSE("Dual MPL/GPL");
+ static int __init orinoco_plx_init(void)
+ {
+ printk(KERN_DEBUG "%s\n", version);
+- return pci_module_init(&orinoco_plx_driver);
++ return pci_register_driver(&orinoco_plx_driver);
+ }
+
+ static void __exit orinoco_plx_exit(void)
+diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
+index 0831721..7c7b960 100644
+--- a/drivers/net/wireless/orinoco_tmd.c
++++ b/drivers/net/wireless/orinoco_tmd.c
+@@ -228,7 +228,7 @@ MODULE_LICENSE("Dual MPL/GPL");
+ static int __init orinoco_tmd_init(void)
+ {
+ printk(KERN_DEBUG "%s\n", version);
+- return pci_module_init(&orinoco_tmd_driver);
++ return pci_register_driver(&orinoco_tmd_driver);
+ }
+
+ static void __exit orinoco_tmd_exit(void)
+diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
+index 989599a..286325c 100644
+--- a/drivers/net/wireless/prism54/isl_ioctl.c
++++ b/drivers/net/wireless/prism54/isl_ioctl.c
+@@ -35,13 +35,21 @@
+
+ #include <net/iw_handler.h> /* New driver API */
+
++#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */
++#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */
++/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
++#define KEY_SIZE_TKIP 32 /* TKIP keys */
+
+-static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
++static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
+ u8 *wpa_ie, size_t wpa_ie_len);
+-static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
++static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+ static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
+ __u32 *, char *);
+
++/* In 500 kbps */
++static const unsigned char scan_rate_list[] = { 2, 4, 11, 22,
++ 12, 18, 24, 36,
++ 48, 72, 96, 108 };
+
+ /**
+ * prism54_mib_mode_helper - MIB change mode helper function
+@@ -468,6 +476,9 @@ prism54_get_range(struct net_device *nde
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+ range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
+
++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
++ IW_ENC_CAPA_CIPHER_TKIP;
++
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+@@ -567,6 +578,8 @@ prism54_translate_bss(struct net_device
+ struct iw_event iwe; /* Temporary buffer */
+ short cap;
+ islpci_private *priv = netdev_priv(ndev);
++ u8 wpa_ie[MAX_WPA_IE_LEN];
++ size_t wpa_ie_len;
+
+ /* The first entry must be the MAC address */
+ memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
+@@ -627,28 +640,40 @@ prism54_translate_bss(struct net_device
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+- if (priv->wpa) {
+- u8 wpa_ie[MAX_WPA_IE_LEN];
+- char *buf, *p;
+- size_t wpa_ie_len;
++ /* Add WPA/RSN Information Element, if any */
++ wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
++ if (wpa_ie_len > 0) {
++ iwe.cmd = IWEVGENIE;
++ iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
++ current_ev = iwe_stream_add_point(current_ev, end_buf,
++ &iwe, wpa_ie);
++ }
++ /* Do the bitrates */
++ {
++ char * current_val = current_ev + IW_EV_LCP_LEN;
+ int i;
+-
+- wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
+- if (wpa_ie_len > 0 &&
+- (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
+- p = buf;
+- p += sprintf(p, "wpa_ie=");
+- for (i = 0; i < wpa_ie_len; i++) {
+- p += sprintf(p, "%02x", wpa_ie[i]);
++ int mask;
++
++ iwe.cmd = SIOCGIWRATE;
++ /* Those two flags are ignored... */
++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
++
++ /* Parse the bitmask */
++ mask = 0x1;
++ for(i = 0; i < sizeof(scan_rate_list); i++) {
++ if(bss->rates & mask) {
++ iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
++ current_val = iwe_stream_add_value(current_ev, current_val,
++ end_buf, &iwe,
++ IW_EV_PARAM_LEN);
+ }
+- memset(&iwe, 0, sizeof (iwe));
+- iwe.cmd = IWEVCUSTOM;
+- iwe.u.data.length = strlen(buf);
+- current_ev = iwe_stream_add_point(current_ev, end_buf,
+- &iwe, buf);
+- kfree(buf);
++ mask <<= 1;
+ }
++ /* Check if we added any event */
++ if ((current_val - current_ev) > IW_EV_LCP_LEN)
++ current_ev = current_val;
+ }
++
+ return current_ev;
+ }
+
+@@ -717,9 +742,9 @@ prism54_set_essid(struct net_device *nde
+
+ /* Check if we were asked for `any' */
+ if (dwrq->flags && dwrq->length) {
+- if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
++ if (dwrq->length > 32)
+ return -E2BIG;
+- essid.length = dwrq->length - 1;
++ essid.length = dwrq->length;
+ memcpy(essid.octets, extra, dwrq->length);
+ } else
+ essid.length = 0;
+@@ -789,7 +814,7 @@ prism54_get_nick(struct net_device *ndev
+ dwrq->length = 0;
+
+ down_read(&priv->mib_sem);
+- dwrq->length = strlen(priv->nickname) + 1;
++ dwrq->length = strlen(priv->nickname);
+ memcpy(extra, priv->nickname, dwrq->length);
+ up_read(&priv->mib_sem);
+
+@@ -967,9 +992,9 @@ prism54_set_retry(struct net_device *nde
+ return -EINVAL;
+
+ if (vwrq->flags & IW_RETRY_LIMIT) {
+- if (vwrq->flags & IW_RETRY_MIN)
++ if (vwrq->flags & IW_RETRY_SHORT)
+ slimit = vwrq->value;
+- else if (vwrq->flags & IW_RETRY_MAX)
++ else if (vwrq->flags & IW_RETRY_LONG)
+ llimit = vwrq->value;
+ else {
+ /* we are asked to set both */
+@@ -1010,18 +1035,18 @@ prism54_get_retry(struct net_device *nde
+ mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
+ vwrq->value = r.u * 1024;
+ vwrq->flags = IW_RETRY_LIFETIME;
+- } else if ((vwrq->flags & IW_RETRY_MAX)) {
++ } else if ((vwrq->flags & IW_RETRY_LONG)) {
+ /* we are asked for the long retry limit */
+ rvalue |=
+ mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
+ vwrq->value = r.u;
+- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ } else {
+ /* default. get the short retry limit */
+ rvalue |=
+ mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
+ vwrq->value = r.u;
+- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
+ }
+
+ return rvalue;
+@@ -1051,12 +1076,24 @@ prism54_set_encode(struct net_device *nd
+ current_index = r.u;
+ /* Verify that the key is not marked as invalid */
+ if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
+- key.length = dwrq->length > sizeof (key.key) ?
+- sizeof (key.key) : dwrq->length;
+- memcpy(key.key, extra, key.length);
+- if (key.length == 32)
+- /* we want WPA-PSK */
++ if (dwrq->length > KEY_SIZE_TKIP) {
++ /* User-provided key data too big */
++ return -EINVAL;
++ }
++ if (dwrq->length > KEY_SIZE_WEP104) {
++ /* WPA-PSK TKIP */
+ key.type = DOT11_PRIV_TKIP;
++ key.length = KEY_SIZE_TKIP;
++ } else if (dwrq->length > KEY_SIZE_WEP40) {
++ /* WEP 104/128 */
++ key.length = KEY_SIZE_WEP104;
++ } else {
++ /* WEP 40/64 */
++ key.length = KEY_SIZE_WEP40;
++ }
++ memset(key.key, 0, sizeof (key.key));
++ memcpy(key.key, extra, dwrq->length);
++
+ if ((index < 0) || (index > 3))
+ /* no index provided use the current one */
+ index = current_index;
+@@ -1210,6 +1247,489 @@ prism54_set_txpower(struct net_device *n
+ }
+ }
+
++static int prism54_set_genie(struct net_device *ndev,
++ struct iw_request_info *info,
++ struct iw_point *data, char *extra)
++{
++ islpci_private *priv = netdev_priv(ndev);
++ int alen, ret = 0;
++ struct obj_attachment *attach;
++
++ if (data->length > MAX_WPA_IE_LEN ||
++ (data->length && extra == NULL))
++ return -EINVAL;
++
++ memcpy(priv->wpa_ie, extra, data->length);
++ priv->wpa_ie_len = data->length;
++
++ alen = sizeof(*attach) + priv->wpa_ie_len;
++ attach = kzalloc(alen, GFP_KERNEL);
++ if (attach == NULL)
++ return -ENOMEM;
++
++#define WLAN_FC_TYPE_MGMT 0
++#define WLAN_FC_STYPE_ASSOC_REQ 0
++#define WLAN_FC_STYPE_REASSOC_REQ 2
++
++ /* Note: endianness is covered by mgt_set_varlen */
++ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
++ (WLAN_FC_STYPE_ASSOC_REQ << 4);
++ attach->id = -1;
++ attach->size = priv->wpa_ie_len;
++ memcpy(attach->data, extra, priv->wpa_ie_len);
++
++ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
++ priv->wpa_ie_len);
++ if (ret == 0) {
++ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
++ (WLAN_FC_STYPE_REASSOC_REQ << 4);
++
++ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
++ priv->wpa_ie_len);
++ if (ret == 0)
++ printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
++ ndev->name);
++ }
++
++ kfree(attach);
++ return ret;
++}
++
++
++static int prism54_get_genie(struct net_device *ndev,
++ struct iw_request_info *info,
++ struct iw_point *data, char *extra)
++{
++ islpci_private *priv = netdev_priv(ndev);
++ int len = priv->wpa_ie_len;
++
++ if (len <= 0) {
++ data->length = 0;
++ return 0;
++ }
++
++ if (data->length < len)
++ return -E2BIG;
++
++ data->length = len;
++ memcpy(extra, priv->wpa_ie, len);
++
++ return 0;
++}
++
++static int prism54_set_auth(struct net_device *ndev,
++ struct iw_request_info *info,
++ union iwreq_data *wrqu, char *extra)
++{
++ islpci_private *priv = netdev_priv(ndev);
++ struct iw_param *param = &wrqu->param;
++ u32 mlmelevel = 0, authen = 0, dot1x = 0;
++ u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
++ u32 old_wpa;
++ int ret = 0;
++ union oid_res_t r;
++
++ if (islpci_get_state(priv) < PRV_STATE_INIT)
++ return 0;
++
++ /* first get the flags */
++ down_write(&priv->mib_sem);
++ wpa = old_wpa = priv->wpa;
++ up_write(&priv->mib_sem);
++ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
++ authen = r.u;
++ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
++ privinvoked = r.u;
++ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
++ exunencrypt = r.u;
++ ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
++ dot1x = r.u;
++ ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
++ mlmelevel = r.u;
++
++ if (ret < 0)
++ goto out;
++
++ switch (param->flags & IW_AUTH_INDEX) {
++ case IW_AUTH_CIPHER_PAIRWISE:
++ case IW_AUTH_CIPHER_GROUP:
++ case IW_AUTH_KEY_MGMT:
++ break;
++
++ case IW_AUTH_WPA_ENABLED:
++ /* Do the same thing as IW_AUTH_WPA_VERSION */
++ if (param->value) {
++ wpa = 1;
++ privinvoked = 1; /* For privacy invoked */
++ exunencrypt = 1; /* Filter out all unencrypted frames */
++ dot1x = 0x01; /* To enable eap filter */
++ mlmelevel = DOT11_MLME_EXTENDED;
++ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
++ } else {
++ wpa = 0;
++ privinvoked = 0;
++ exunencrypt = 0; /* Do not filter un-encrypted data */
++ dot1x = 0;
++ mlmelevel = DOT11_MLME_AUTO;
++ }
++ break;
++
++ case IW_AUTH_WPA_VERSION:
++ if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
++ wpa = 0;
++ privinvoked = 0;
++ exunencrypt = 0; /* Do not filter un-encrypted data */
++ dot1x = 0;
++ mlmelevel = DOT11_MLME_AUTO;
++ } else {
++ if (param->value & IW_AUTH_WPA_VERSION_WPA)
++ wpa = 1;
++ else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
++ wpa = 2;
++ privinvoked = 1; /* For privacy invoked */
++ exunencrypt = 1; /* Filter out all unencrypted frames */
++ dot1x = 0x01; /* To enable eap filter */
++ mlmelevel = DOT11_MLME_EXTENDED;
++ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
++ }
++ break;
++
++ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
++ dot1x = param->value ? 1 : 0;
++ break;
++
++ case IW_AUTH_PRIVACY_INVOKED:
++ privinvoked = param->value ? 1 : 0;
++
++ case IW_AUTH_DROP_UNENCRYPTED:
++ exunencrypt = param->value ? 1 : 0;
++ break;
++
++ case IW_AUTH_80211_AUTH_ALG:
++ if (param->value & IW_AUTH_ALG_SHARED_KEY) {
++ /* Only WEP uses _SK and _BOTH */
++ if (wpa > 0) {
++ ret = -EINVAL;
++ goto out;
++ }
++ authen = DOT11_AUTH_SK;
++ } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
++ authen = DOT11_AUTH_OS;
++ } else {
++ ret = -EINVAL;
++ goto out;
++ }
++ break;
++
++ default:
++ return -EOPNOTSUPP;
++ }
++
++ /* Set all the values */
++ down_write(&priv->mib_sem);
++ priv->wpa = wpa;
++ up_write(&priv->mib_sem);
++ mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
++ mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
++ mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
++ mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
++ mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
++
++out:
++ return ret;
++}
++
++static int prism54_get_auth(struct net_device *ndev,
++ struct iw_request_info *info,
++ union iwreq_data *wrqu, char *extra)
++{
++ islpci_private *priv = netdev_priv(ndev);
++ struct iw_param *param = &wrqu->param;
++ u32 wpa = 0;
++ int ret = 0;
++ union oid_res_t r;
++
++ if (islpci_get_state(priv) < PRV_STATE_INIT)
++ return 0;
++
++ /* first get the flags */
++ down_write(&priv->mib_sem);
++ wpa = priv->wpa;
++ up_write(&priv->mib_sem);
++
++ switch (param->flags & IW_AUTH_INDEX) {
++ case IW_AUTH_CIPHER_PAIRWISE:
++ case IW_AUTH_CIPHER_GROUP:
++ case IW_AUTH_KEY_MGMT:
++ /*
++ * wpa_supplicant will control these internally
++ */
++ ret = -EOPNOTSUPP;
++ break;
++
++ case IW_AUTH_WPA_VERSION:
++ switch (wpa) {
++ case 1:
++ param->value = IW_AUTH_WPA_VERSION_WPA;
++ break;
++ case 2:
++ param->value = IW_AUTH_WPA_VERSION_WPA2;
++ break;
++ case 0:
++ default:
++ param->value = IW_AUTH_WPA_VERSION_DISABLED;
++ break;
++ }
++ break;
++
++ case IW_AUTH_DROP_UNENCRYPTED:
++ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
++ if (ret >= 0)
++ param->value = r.u > 0 ? 1 : 0;
++ break;
++
++ case IW_AUTH_80211_AUTH_ALG:
++ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
++ if (ret >= 0) {
++ switch (r.u) {
++ case DOT11_AUTH_OS:
++ param->value = IW_AUTH_ALG_OPEN_SYSTEM;
++ break;
++ case DOT11_AUTH_BOTH:
++ case DOT11_AUTH_SK:
++ param->value = IW_AUTH_ALG_SHARED_KEY;
++ case DOT11_AUTH_NONE:
++ default:
++ param->value = 0;
++ break;
++ }
++ }
++ break;
++
++ case IW_AUTH_WPA_ENABLED:
++ param->value = wpa > 0 ? 1 : 0;
++ break;
++
++ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
++ ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
++ if (ret >= 0)
++ param->value = r.u > 0 ? 1 : 0;
++ break;
++
++ case IW_AUTH_PRIVACY_INVOKED:
++ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
++ if (ret >= 0)
++ param->value = r.u > 0 ? 1 : 0;
++ break;
++
++ default:
++ return -EOPNOTSUPP;
++ }
++ return ret;
++}
++
++static int prism54_set_encodeext(struct net_device *ndev,
++ struct iw_request_info *info,
++ union iwreq_data *wrqu,
++ char *extra)
++{
++ islpci_private *priv = netdev_priv(ndev);
++ struct iw_point *encoding = &wrqu->encoding;
++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
++ int idx, alg = ext->alg, set_key = 1;
++ union oid_res_t r;
++ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
++ int ret = 0;
++
++ if (islpci_get_state(priv) < PRV_STATE_INIT)
++ return 0;
++
++ /* Determine and validate the key index */
++ idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
++ if (idx) {
++ if (idx < 0 || idx > 3)
++ return -EINVAL;
++ } else {
++ ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
++ if (ret < 0)
++ goto out;
++ idx = r.u;
++ }
++
++ if (encoding->flags & IW_ENCODE_DISABLED)
++ alg = IW_ENCODE_ALG_NONE;
++
++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
++ /* Only set transmit key index here, actual
++ * key is set below if needed.
++ */
++ ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
++ set_key = ext->key_len > 0 ? 1 : 0;
++ }
++
++ if (set_key) {
++ struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
++ switch (alg) {
++ case IW_ENCODE_ALG_NONE:
++ break;
++ case IW_ENCODE_ALG_WEP:
++ if (ext->key_len > KEY_SIZE_WEP104) {
++ ret = -EINVAL;
++ goto out;
++ }
++ if (ext->key_len > KEY_SIZE_WEP40)
++ key.length = KEY_SIZE_WEP104;
++ else
++ key.length = KEY_SIZE_WEP40;
++ break;
++ case IW_ENCODE_ALG_TKIP:
++ if (ext->key_len > KEY_SIZE_TKIP) {
++ ret = -EINVAL;
++ goto out;
++ }
++ key.type = DOT11_PRIV_TKIP;
++ key.length = KEY_SIZE_TKIP;
++ default:
++ return -EINVAL;
++ }
++
++ if (key.length) {
++ memset(key.key, 0, sizeof(key.key));
++ memcpy(key.key, ext->key, ext->key_len);
++ ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
++ &key);
++ if (ret < 0)
++ goto out;
++ }
++ }
++
++ /* Read the flags */
++ if (encoding->flags & IW_ENCODE_DISABLED) {
++ /* Encoding disabled,
++ * authen = DOT11_AUTH_OS;
++ * invoke = 0;
++ * exunencrypt = 0; */
++ }
++ if (encoding->flags & IW_ENCODE_OPEN) {
++ /* Encode but accept non-encoded packets. No auth */
++ invoke = 1;
++ }
++ if (encoding->flags & IW_ENCODE_RESTRICTED) {
++ /* Refuse non-encoded packets. Auth */
++ authen = DOT11_AUTH_BOTH;
++ invoke = 1;
++ exunencrypt = 1;
++ }
++
++ /* do the change if requested */
++ if (encoding->flags & IW_ENCODE_MODE) {
++ ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
++ &authen);
++ ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
++ &invoke);
++ ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
++ &exunencrypt);
++ }
++
++out:
++ return ret;
++}
++
++
++static int prism54_get_encodeext(struct net_device *ndev,
++ struct iw_request_info *info,
++ union iwreq_data *wrqu,
++ char *extra)
++{
++ islpci_private *priv = netdev_priv(ndev);
++ struct iw_point *encoding = &wrqu->encoding;
++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
++ int idx, max_key_len;
++ union oid_res_t r;
++ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
++ int ret = 0;
++
++ if (islpci_get_state(priv) < PRV_STATE_INIT)
++ return 0;
++
++ /* first get the flags */
++ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
++ authen = r.u;
++ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
++ invoke = r.u;
++ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
++ exunencrypt = r.u;
++ if (ret < 0)
++ goto out;
++
++ max_key_len = encoding->length - sizeof(*ext);
++ if (max_key_len < 0)
++ return -EINVAL;
++
++ idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
++ if (idx) {
++ if (idx < 0 || idx > 3)
++ return -EINVAL;
++ } else {
++ ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
++ if (ret < 0)
++ goto out;
++ idx = r.u;
++ }
++
++ encoding->flags = idx + 1;
++ memset(ext, 0, sizeof(*ext));
++
++ switch (authen) {
++ case DOT11_AUTH_BOTH:
++ case DOT11_AUTH_SK:
++ wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
++ case DOT11_AUTH_OS:
++ default:
++ wrqu->encoding.flags |= IW_ENCODE_OPEN;
++ break;
++ }
++
++ down_write(&priv->mib_sem);
++ wpa = priv->wpa;
++ up_write(&priv->mib_sem);
++
++ if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
++ /* No encryption */
++ ext->alg = IW_ENCODE_ALG_NONE;
++ ext->key_len = 0;
++ wrqu->encoding.flags |= IW_ENCODE_DISABLED;
++ } else {
++ struct obj_key *key;
++
++ ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
++ if (ret < 0)
++ goto out;
++ key = r.ptr;
++ if (max_key_len < key->length) {
++ ret = -E2BIG;
++ goto out;
++ }
++ memcpy(ext->key, key->key, key->length);
++ ext->key_len = key->length;
++
++ switch (key->type) {
++ case DOT11_PRIV_TKIP:
++ ext->alg = IW_ENCODE_ALG_TKIP;
++ break;
++ default:
++ case DOT11_PRIV_WEP:
++ ext->alg = IW_ENCODE_ALG_WEP;
++ break;
++ }
++ wrqu->encoding.flags |= IW_ENCODE_ENABLED;
++ }
++
++out:
++ return ret;
++}
++
++
+ static int
+ prism54_reset(struct net_device *ndev, struct iw_request_info *info,
+ __u32 * uwrq, char *extra)
+@@ -1591,8 +2111,8 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf
+ #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+ static void
+-prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+- u8 *wpa_ie, size_t wpa_ie_len)
++prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
++ u8 *wpa_ie, size_t wpa_ie_len)
+ {
+ struct list_head *ptr;
+ struct islpci_bss_wpa_ie *bss = NULL;
+@@ -1658,7 +2178,7 @@ prism54_wpa_ie_add(islpci_private *priv,
+ }
+
+ static size_t
+-prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
++prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+ {
+ struct list_head *ptr;
+ struct islpci_bss_wpa_ie *bss = NULL;
+@@ -1683,14 +2203,14 @@ prism54_wpa_ie_get(islpci_private *priv,
+ }
+
+ void
+-prism54_wpa_ie_init(islpci_private *priv)
++prism54_wpa_bss_ie_init(islpci_private *priv)
+ {
+ INIT_LIST_HEAD(&priv->bss_wpa_list);
+ sema_init(&priv->wpa_sem, 1);
+ }
+
+ void
+-prism54_wpa_ie_clean(islpci_private *priv)
++prism54_wpa_bss_ie_clean(islpci_private *priv)
+ {
+ struct list_head *ptr, *n;
+
+@@ -1722,7 +2242,7 @@ prism54_process_bss_data(islpci_private
+ }
+ if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
+ memcmp(pos + 2, wpa_oid, 4) == 0) {
+- prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
++ prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
+ return;
+ }
+ pos += 2 + pos[1];
+@@ -1879,7 +2399,7 @@ prism54_process_trap_helper(islpci_priva
+ send_formatted_event(priv, "Associate request (ex)", mlme, 1);
+
+ if (priv->iw_mode != IW_MODE_MASTER
+- && mlmeex->state != DOT11_STATE_AUTHING)
++ && mlmeex->state != DOT11_STATE_ASSOCING)
+ break;
+
+ confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+@@ -1893,7 +2413,7 @@ prism54_process_trap_helper(islpci_priva
+ confirm->state = 0; /* not used */
+ confirm->code = 0;
+
+- wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
++ wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
+
+ if (!wpa_ie_len) {
+ printk(KERN_DEBUG "No WPA IE found from "
+@@ -1937,7 +2457,7 @@ prism54_process_trap_helper(islpci_priva
+ confirm->state = 0; /* not used */
+ confirm->code = 0;
+
+- wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
++ wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
+
+ if (!wpa_ie_len) {
+ printk(KERN_DEBUG "No WPA IE found from "
+@@ -2553,6 +3073,15 @@ static const iw_handler prism54_handler[
+ (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) NULL, /* SIOCSIWPOWER */
+ (iw_handler) NULL, /* SIOCGIWPOWER */
++ NULL, /* -- hole -- */
++ NULL, /* -- hole -- */
++ (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
++ (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
++ (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */
++ (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */
++ (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
++ (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
++ NULL, /* SIOCSIWPMKSA */
+ };
+
+ /* The low order bit identify a SET (0) or a GET (1) ioctl. */
+diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
+index 46d5cde..65f33ac 100644
+--- a/drivers/net/wireless/prism54/isl_ioctl.h
++++ b/drivers/net/wireless/prism54/isl_ioctl.h
+@@ -27,7 +27,7 @@
+
+ #include <net/iw_handler.h> /* New driver API */
+
+-#define SUPPORTED_WIRELESS_EXT 16
++#define SUPPORTED_WIRELESS_EXT 19
+
+ void prism54_mib_init(islpci_private *);
+
+@@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl
+
+ void prism54_process_trap(void *);
+
+-void prism54_wpa_ie_init(islpci_private *priv);
+-void prism54_wpa_ie_clean(islpci_private *priv);
++void prism54_wpa_bss_ie_init(islpci_private *priv);
++void prism54_wpa_bss_ie_clean(islpci_private *priv);
+
+ int prism54_set_mac_address(struct net_device *, void *);
+
+diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
+index 5ddf295..ec1c00f 100644
+--- a/drivers/net/wireless/prism54/islpci_dev.c
++++ b/drivers/net/wireless/prism54/islpci_dev.c
+@@ -182,7 +182,7 @@ isl_upload_firmware(islpci_private *priv
+ ******************************************************************************/
+
+ irqreturn_t
+-islpci_interrupt(int irq, void *config, struct pt_regs *regs)
++islpci_interrupt(int irq, void *config)
+ {
+ u32 reg;
+ islpci_private *priv = config;
+@@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv
+ }
+
+ prism54_acl_init(&priv->acl);
+- prism54_wpa_ie_init(priv);
++ prism54_wpa_bss_ie_init(priv);
+ if (mgt_init(priv))
+ goto out_free;
+
+@@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv)
+
+ /* Free the acces control list and the WPA list */
+ prism54_acl_clean(&priv->acl);
+- prism54_wpa_ie_clean(priv);
++ prism54_wpa_bss_ie_clean(priv);
+ mgt_clean(priv);
+
+ return 0;
+diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
+index 0705316..2f7e525 100644
+--- a/drivers/net/wireless/prism54/islpci_dev.h
++++ b/drivers/net/wireless/prism54/islpci_dev.h
+@@ -179,6 +179,8 @@ typedef struct {
+ struct list_head bss_wpa_list;
+ int num_bss_wpa;
+ struct semaphore wpa_sem;
++ u8 wpa_ie[MAX_WPA_IE_LEN];
++ size_t wpa_ie_len;
+
+ struct work_struct reset_task;
+ int reset_task_pending;
+@@ -196,7 +198,7 @@ islpci_state_t islpci_set_state(islpci_p
+
+ #define ISLPCI_TX_TIMEOUT (2*HZ)
+
+-irqreturn_t islpci_interrupt(int, void *, struct pt_regs *);
++irqreturn_t islpci_interrupt(int, void *);
+
+ int prism54_post_setup(islpci_private *, int);
+ int islpci_reset(islpci_private *, int);
+diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
+index 09fc17a..f692dcc 100644
+--- a/drivers/net/wireless/prism54/islpci_hotplug.c
++++ b/drivers/net/wireless/prism54/islpci_hotplug.c
+@@ -313,7 +313,7 @@ prism54_module_init(void)
+
+ __bug_on_wrong_struct_sizes ();
+
+- return pci_module_init(&prism54_driver);
++ return pci_register_driver(&prism54_driver);
+ }
+
+ /* by the time prism54_module_exit() terminates, as a postcondition
+diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
+index 61b83a5..7fbfc9e 100644
+--- a/drivers/net/wireless/ray_cs.c
++++ b/drivers/net/wireless/ray_cs.c
+@@ -52,8 +52,8 @@
+ #include <pcmcia/ds.h>
+ #include <pcmcia/mem_op.h>
+
+-#include <net/ieee80211.h>
+ #include <linux/wireless.h>
++#include <net/iw_handler.h>
+
+ #include <asm/io.h>
+ #include <asm/system.h>
+@@ -99,7 +99,7 @@ static int ray_dev_config(struct net_dev
+ static struct net_device_stats *ray_get_stats(struct net_device *dev);
+ static int ray_dev_init(struct net_device *dev);
+
+-static struct ethtool_ops netdev_ethtool_ops;
++static const struct ethtool_ops netdev_ethtool_ops;
+
+ static int ray_open(struct net_device *dev);
+ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+@@ -130,7 +130,7 @@ static void ray_update_parm(struct net_d
+ static void verify_dl_startup(u_long);
+
+ /* Prototypes for interrpt time functions **********************************/
+-static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs);
++static irqreturn_t ray_interrupt (int reg, void *dev_id);
+ static void clear_interrupt(ray_dev_t *local);
+ static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
+ unsigned int pkt_addr, int rx_len);
+@@ -1092,7 +1092,7 @@ static void netdev_get_drvinfo(struct ne
+ strcpy(info->driver, "ray_cs");
+ }
+
+-static struct ethtool_ops netdev_ethtool_ops = {
++static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ };
+
+@@ -1173,7 +1173,7 @@ static int ray_set_essid(struct net_devi
+ return -EOPNOTSUPP;
+ } else {
+ /* Check the size of the string */
+- if(dwrq->length > IW_ESSID_MAX_SIZE + 1) {
++ if(dwrq->length > IW_ESSID_MAX_SIZE) {
+ return -E2BIG;
+ }
+
+@@ -1198,7 +1198,6 @@ static int ray_get_essid(struct net_devi
+
+ /* Get the essid that was set */
+ memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+- extra[IW_ESSID_MAX_SIZE] = '\0';
+
+ /* Push it out ! */
+ dwrq->length = strlen(extra);
+@@ -1940,7 +1939,7 @@ static void set_multicast_list(struct ne
+ /*=============================================================================
+ * All routines below here are run at interrupt time.
+ =============================================================================*/
+-static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t ray_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct pcmcia_device *link;
+diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
+index ccaf28e..337c692 100644
+--- a/drivers/net/wireless/strip.c
++++ b/drivers/net/wireless/strip.c
+@@ -1342,7 +1342,7 @@ static unsigned char *strip_make_packet(
+ * 'broadcast hub' radio (First byte of address being 0xFF means broadcast)
+ */
+ if (haddr.c[0] == 0xFF) {
+- u32 brd = 0;
++ __be32 brd = 0;
+ struct in_device *in_dev;
+
+ rcu_read_lock();
+@@ -1406,7 +1406,7 @@ static void strip_send(struct strip *str
+ int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0;
+ int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0
+ && !doreset;
+- u32 addr, brd;
++ __be32 addr, brd;
+
+ /*
+ * 1. If we have a packet, encapsulate it and put it in the buffer
+diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
+index 5b69bef..24221e4 100644
+--- a/drivers/net/wireless/wavelan.c
++++ b/drivers/net/wireless/wavelan.c
+@@ -3768,7 +3768,7 @@ static int wv_check_ioaddr(unsigned long
+ * This function is the interrupt handler for the WaveLAN card. This
+ * routine will be called whenever:
+ */
+-static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wavelan_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev;
+ unsigned long ioaddr;
+diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
+index 5cb0bc8..72b646c 100644
+--- a/drivers/net/wireless/wavelan.p.h
++++ b/drivers/net/wireless/wavelan.p.h
+@@ -642,8 +642,7 @@ static int
+ /* ---------------------- INTERRUPT HANDLING ---------------------- */
+ static irqreturn_t
+ wavelan_interrupt(int, /* interrupt handler */
+- void *,
+- struct pt_regs *);
++ void *);
+ static void
+ wavelan_watchdog(struct net_device *); /* transmission watchdog */
+ /* ------------------- CONFIGURATION CALLBACKS ------------------- */
+diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
+index 561250f..aafb301 100644
+--- a/drivers/net/wireless/wavelan_cs.c
++++ b/drivers/net/wireless/wavelan_cs.c
+@@ -1837,7 +1837,7 @@ static void wl_get_drvinfo(struct net_de
+ strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1);
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = wl_get_drvinfo
+ };
+
+@@ -4117,24 +4117,14 @@ wv_pcmcia_release(struct pcmcia_device *
+ */
+ static irqreturn_t
+ wavelan_interrupt(int irq,
+- void * dev_id,
+- struct pt_regs * regs)
++ void * dev_id)
+ {
+- struct net_device * dev;
++ struct net_device * dev = dev_id;
+ net_local * lp;
+ kio_addr_t base;
+ int status0;
+ u_int tx_status;
+
+- if ((dev = dev_id) == NULL)
+- {
+-#ifdef DEBUG_INTERRUPT_ERROR
+- printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
+- irq);
+-#endif
+- return IRQ_NONE;
+- }
+-
+ #ifdef DEBUG_INTERRUPT_TRACE
+ printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+ #endif
+diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
+index f34a36b..4d1c490 100644
+--- a/drivers/net/wireless/wavelan_cs.p.h
++++ b/drivers/net/wireless/wavelan_cs.p.h
+@@ -738,8 +738,7 @@ static void
+ /* ---------------------- INTERRUPT HANDLING ---------------------- */
+ static irqreturn_t
+ wavelan_interrupt(int, /* Interrupt handler */
+- void *,
+- struct pt_regs *);
++ void *);
+ static void
+ wavelan_watchdog(struct net_device *); /* Transmission watchdog */
+ /* ------------------- CONFIGURATION CALLBACKS ------------------- */
+diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
+index c03e400..5b98a78 100644
+--- a/drivers/net/wireless/wl3501_cs.c
++++ b/drivers/net/wireless/wl3501_cs.c
+@@ -1145,7 +1145,6 @@ static inline void wl3501_ack_interrupt(
+ * wl3501_interrupt - Hardware interrupt from card.
+ * @irq - Interrupt number
+ * @dev_id - net_device
+- * @regs - registers
+ *
+ * We must acknowledge the interrupt as soon as possible, and block the
+ * interrupt from the same card immediately to prevent re-entry.
+@@ -1154,27 +1153,20 @@ static inline void wl3501_ack_interrupt(
+ * On the other hand, to prevent SUTRO from malfunctioning, we must
+ * unlock the SUTRO as soon as possible.
+ */
+-static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wl3501_interrupt(int irq, void *dev_id)
+ {
+- struct net_device *dev = (struct net_device *)dev_id;
++ struct net_device *dev = dev_id;
+ struct wl3501_card *this;
+- int handled = 1;
+
+- if (!dev)
+- goto unknown;
+- this = dev->priv;
++ this = netdev_priv(dev);
+ spin_lock(&this->lock);
+ wl3501_ack_interrupt(this);
+ wl3501_block_interrupt(this);
+ wl3501_rx_interrupt(dev);
+ wl3501_unblock_interrupt(this);
+ spin_unlock(&this->lock);
+-out:
+- return IRQ_RETVAL(handled);
+-unknown:
+- handled = 0;
+- printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq);
+- goto out;
++
++ return IRQ_HANDLED;
+ }
+
+ static int wl3501_reset_board(struct wl3501_card *this)
+@@ -1464,7 +1456,7 @@ static void wl3501_get_drvinfo(struct ne
+ strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));
+ }
+
+-static struct ethtool_ops ops = {
++static const struct ethtool_ops ops = {
+ .get_drvinfo = wl3501_get_drvinfo
+ };
+
+@@ -1802,15 +1794,15 @@ static int wl3501_get_retry(struct net_d
+ &retry, sizeof(retry));
+ if (rc)
+ goto out;
+- if (wrqu->retry.flags & IW_RETRY_MAX) {
+- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ if (wrqu->retry.flags & IW_RETRY_LONG) {
++ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ goto set_value;
+ }
+ rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
+ &retry, sizeof(retry));
+ if (rc)
+ goto out;
+- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
++ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
+ set_value:
+ wrqu->retry.value = retry;
+ wrqu->retry.disabled = 0;
+diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
+index c52e9bc..36b29ff 100644
+--- a/drivers/net/wireless/zd1201.c
++++ b/drivers/net/wireless/zd1201.c
+@@ -112,14 +112,14 @@ exit:
+ return err;
+ }
+
+-static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
++static void zd1201_usbfree(struct urb *urb)
+ {
+ struct zd1201 *zd = urb->context;
+
+ switch(urb->status) {
+ case -EILSEQ:
+ case -ENODEV:
+- case -ETIMEDOUT:
++ case -ETIME:
+ case -ENOENT:
+ case -EPIPE:
+ case -EOVERFLOW:
+@@ -177,7 +177,7 @@ static int zd1201_docmd(struct zd1201 *z
+ }
+
+ /* Callback after sending out a packet */
+-static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs)
++static void zd1201_usbtx(struct urb *urb)
+ {
+ struct zd1201 *zd = urb->context;
+ netif_wake_queue(zd->dev);
+@@ -185,7 +185,7 @@ static void zd1201_usbtx(struct urb *urb
+ }
+
+ /* Incoming data */
+-static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
++static void zd1201_usbrx(struct urb *urb)
+ {
+ struct zd1201 *zd = urb->context;
+ int free = 0;
+@@ -193,15 +193,13 @@ static void zd1201_usbrx(struct urb *urb
+ struct sk_buff *skb;
+ unsigned char type;
+
+- if (!zd) {
+- free = 1;
+- goto exit;
+- }
++ if (!zd)
++ return;
+
+ switch(urb->status) {
+ case -EILSEQ:
+ case -ENODEV:
+- case -ETIMEDOUT:
++ case -ETIME:
+ case -ENOENT:
+ case -EPIPE:
+ case -EOVERFLOW:
+@@ -1218,7 +1216,7 @@ static int zd1201_set_essid(struct net_d
+ return -EINVAL;
+ if (data->length < 1)
+ data->length = 1;
+- zd->essidlen = data->length-1;
++ zd->essidlen = data->length;
+ memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
+ memcpy(zd->essid, essid, data->length);
+ return zd1201_join(zd, zd->essid, zd->essidlen);
+diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
+index 500314f..6603ad5 100644
+--- a/drivers/net/wireless/zd1211rw/Makefile
++++ b/drivers/net/wireless/zd1211rw/Makefile
+@@ -3,6 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
+ zd1211rw-objs := zd_chip.o zd_ieee80211.o \
+ zd_mac.o zd_netdev.o \
+ zd_rf_al2230.o zd_rf_rf2959.o \
++ zd_rf_al7230b.o \
+ zd_rf.o zd_usb.o zd_util.o
+
+ ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
+diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
+index aa79282..aa661b2 100644
+--- a/drivers/net/wireless/zd1211rw/zd_chip.c
++++ b/drivers/net/wireless/zd1211rw/zd_chip.c
+@@ -42,12 +42,11 @@ void zd_chip_init(struct zd_chip *chip,
+
+ void zd_chip_clear(struct zd_chip *chip)
+ {
+- mutex_lock(&chip->mutex);
++ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ zd_usb_clear(&chip->usb);
+ zd_rf_clear(&chip->rf);
+- mutex_unlock(&chip->mutex);
+ mutex_destroy(&chip->mutex);
+- memset(chip, 0, sizeof(*chip));
++ ZD_MEMCLEAR(chip, sizeof(*chip));
+ }
+
+ static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
+@@ -68,10 +67,11 @@ static int scnprint_id(struct zd_chip *c
+ i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
+- i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
++ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
+ chip->patch_cck_gain ? 'g' : '-',
+ chip->patch_cr157 ? '7' : '-',
+- chip->patch_6m_band_edge ? '6' : '-');
++ chip->patch_6m_band_edge ? '6' : '-',
++ chip->new_phy_layout ? 'N' : '-');
+ return i;
+ }
+
+@@ -249,7 +249,6 @@ int zd_ioread16(struct zd_chip *chip, zd
+ {
+ int r;
+
+- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+@@ -260,7 +259,6 @@ int zd_ioread32(struct zd_chip *chip, zd
+ {
+ int r;
+
+- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+@@ -271,7 +269,6 @@ int zd_iowrite16(struct zd_chip *chip, z
+ {
+ int r;
+
+- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+@@ -282,7 +279,6 @@ int zd_iowrite32(struct zd_chip *chip, z
+ {
+ int r;
+
+- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+@@ -294,7 +290,6 @@ int zd_ioread32v(struct zd_chip *chip, c
+ {
+ int r;
+
+- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32v_locked(chip, values, addresses, count);
+ mutex_unlock(&chip->mutex);
+@@ -306,7 +301,6 @@ int zd_iowrite32a(struct zd_chip *chip,
+ {
+ int r;
+
+- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, ioreqs, count);
+ mutex_unlock(&chip->mutex);
+@@ -330,13 +324,23 @@ static int read_pod(struct zd_chip *chip
+ chip->patch_cck_gain = (value >> 8) & 0x1;
+ chip->patch_cr157 = (value >> 13) & 0x1;
+ chip->patch_6m_band_edge = (value >> 21) & 0x1;
++ chip->new_phy_layout = (value >> 31) & 0x1;
++ chip->link_led = ((value >> 4) & 1) ? LED1 : LED2;
++ chip->supports_tx_led = 1;
++ if (value & (1 << 24)) { /* LED scenario */
++ if (value & (1 << 29))
++ chip->supports_tx_led = 0;
++ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
+- "patch 6M %d\n",
++ "patch 6M %d new PHY %d link LED%d tx led %d\n",
+ zd_rf_name(*rf_type), *rf_type,
+ chip->pa_type, chip->patch_cck_gain,
+- chip->patch_cr157, chip->patch_6m_band_edge);
++ chip->patch_cr157, chip->patch_6m_band_edge,
++ chip->new_phy_layout,
++ chip->link_led == LED1 ? 1 : 2,
++ chip->supports_tx_led);
+ return 0;
+ error:
+ *rf_type = 0;
+@@ -344,6 +348,7 @@ error:
+ chip->patch_cck_gain = 0;
+ chip->patch_cr157 = 0;
+ chip->patch_6m_band_edge = 0;
++ chip->new_phy_layout = 0;
+ return r;
+ }
+
+@@ -717,7 +722,7 @@ static int zd1211b_hw_reset_phy(struct z
+ { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
+ { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
+ { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
+- { CR30, 0x49 }, /* jointly decoder, no ASIC */
++ { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+@@ -807,7 +812,6 @@ static int zd1211_hw_init_hmac(struct zd
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+- { CR_IFS_VALUE, 0x547c032 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+@@ -854,11 +858,10 @@ static int zd1211b_hw_init_hmac(struct z
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+- { CR_IFS_VALUE, 0x547c032 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+- { CR_RX_THRESHOLD, 0x000c0640 },
++ { CR_RX_THRESHOLD, 0x000c0eff, },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+@@ -970,10 +973,15 @@ static int hw_init(struct zd_chip *chip)
+ r = hw_init_hmac(chip);
+ if (r)
+ return r;
+- r = set_beacon_interval(chip, 100);
++
++ /* Although the vendor driver defaults to a different value during
++ * init, it overwrites the IFS value with the following every time
++ * the channel changes. We should aim to be more intelligent... */
++ r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
+ if (r)
+ return r;
+- return 0;
++
++ return set_beacon_interval(chip, 100);
+ }
+
+ #ifdef DEBUG
+@@ -1176,7 +1184,7 @@ static int update_pwr_int(struct zd_chip
+ u8 value = chip->pwr_int_values[channel - 1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
+ channel, value);
+- return zd_iowrite32_locked(chip, value, CR31);
++ return zd_iowrite16_locked(chip, value, CR31);
+ }
+
+ static int update_pwr_cal(struct zd_chip *chip, u8 channel)
+@@ -1184,12 +1192,12 @@ static int update_pwr_cal(struct zd_chip
+ u8 value = chip->pwr_cal_values[channel-1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
+ channel, value);
+- return zd_iowrite32_locked(chip, value, CR68);
++ return zd_iowrite16_locked(chip, value, CR68);
+ }
+
+ static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
+ {
+- struct zd_ioreq32 ioreqs[3];
++ struct zd_ioreq16 ioreqs[3];
+
+ ioreqs[0].addr = CR67;
+ ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
+@@ -1201,7 +1209,7 @@ static int update_ofdm_cal(struct zd_chi
+ dev_dbg_f(zd_chip_dev(chip),
+ "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
+ channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
+- return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ }
+
+ static int update_channel_integration_and_calibration(struct zd_chip *chip,
+@@ -1213,7 +1221,7 @@ static int update_channel_integration_an
+ if (r)
+ return r;
+ if (chip->is_zd1211b) {
+- static const struct zd_ioreq32 ioreqs[] = {
++ static const struct zd_ioreq16 ioreqs[] = {
+ { CR69, 0x28 },
+ {},
+ { CR69, 0x2a },
+@@ -1225,7 +1233,7 @@ static int update_channel_integration_an
+ r = update_pwr_cal(chip, channel);
+ if (r)
+ return r;
+- r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+ }
+@@ -1247,7 +1255,7 @@ static int patch_cck_gain(struct zd_chip
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
+- return zd_iowrite32_locked(chip, value & 0xff, CR47);
++ return zd_iowrite16_locked(chip, value & 0xff, CR47);
+ }
+
+ int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
+@@ -1290,89 +1298,60 @@ u8 zd_chip_get_channel(struct zd_chip *c
+ return channel;
+ }
+
+-static u16 led_mask(int led)
++int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
+ {
+- switch (led) {
+- case 1:
+- return LED1;
+- case 2:
+- return LED2;
+- default:
+- return 0;
+- }
+-}
+-
+-static int read_led_reg(struct zd_chip *chip, u16 *status)
+-{
+- ZD_ASSERT(mutex_is_locked(&chip->mutex));
+- return zd_ioread16_locked(chip, status, CR_LED);
+-}
+-
+-static int write_led_reg(struct zd_chip *chip, u16 status)
+-{
+- ZD_ASSERT(mutex_is_locked(&chip->mutex));
+- return zd_iowrite16_locked(chip, status, CR_LED);
+-}
++ static const zd_addr_t a[] = {
++ FW_LINK_STATUS,
++ CR_LED,
++ };
+
+-int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status)
+-{
+- int r, ret;
+- u16 mask = led_mask(led);
+- u16 reg;
++ int r;
++ u16 v[ARRAY_SIZE(a)];
++ struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
++ [0] = { FW_LINK_STATUS },
++ [1] = { CR_LED },
++ };
++ u16 other_led;
+
+- if (!mask)
+- return -EINVAL;
+ mutex_lock(&chip->mutex);
+- r = read_led_reg(chip, ®);
++ r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a));
+ if (r)
+- return r;
++ goto out;
++
++ other_led = chip->link_led == LED1 ? LED2 : LED1;
++
+ switch (status) {
+- case LED_STATUS:
+- return (reg & mask) ? LED_ON : LED_OFF;
+ case LED_OFF:
+- reg &= ~mask;
+- ret = LED_OFF;
++ ioreqs[0].value = FW_LINK_OFF;
++ ioreqs[1].value = v[1] & ~(LED1|LED2);
+ break;
+- case LED_FLIP:
+- reg ^= mask;
+- ret = (reg&mask) ? LED_ON : LED_OFF;
++ case LED_SCANNING:
++ ioreqs[0].value = FW_LINK_OFF;
++ ioreqs[1].value = v[1] & ~other_led;
++ if (get_seconds() % 3 == 0) {
++ ioreqs[1].value &= ~chip->link_led;
++ } else {
++ ioreqs[1].value |= chip->link_led;
++ }
+ break;
+- case LED_ON:
+- reg |= mask;
+- ret = LED_ON;
++ case LED_ASSOCIATED:
++ ioreqs[0].value = FW_LINK_TX;
++ ioreqs[1].value = v[1] & ~other_led;
++ ioreqs[1].value |= chip->link_led;
+ break;
+ default:
+- return -EINVAL;
+- }
+- r = write_led_reg(chip, reg);
+- if (r) {
+- ret = r;
++ r = -EINVAL;
+ goto out;
+ }
+-out:
+- mutex_unlock(&chip->mutex);
+- return r;
+-}
+-
+-int zd_chip_led_flip(struct zd_chip *chip, int led,
+- const unsigned int *phases_msecs, unsigned int count)
+-{
+- int i, r;
+- enum led_status status;
+
+- r = zd_chip_led_status(chip, led, LED_STATUS);
+- if (r)
+- return r;
+- status = r;
+- for (i = 0; i < count; i++) {
+- r = zd_chip_led_status(chip, led, LED_FLIP);
+- if (r < 0)
++ if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) {
++ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++ if (r)
+ goto out;
+- msleep(phases_msecs[i]);
+ }
+-
++ r = 0;
+ out:
+- zd_chip_led_status(chip, led, status);
++ mutex_unlock(&chip->mutex);
+ return r;
+ }
+
+@@ -1644,3 +1623,33 @@ int zd_rfwritev_locked(struct zd_chip *c
+
+ return 0;
+ }
++
++/*
++ * We can optionally program the RF directly through CR regs, if supported by
++ * the hardware. This is much faster than the older method.
++ */
++int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
++{
++ struct zd_ioreq16 ioreqs[] = {
++ { CR244, (value >> 16) & 0xff },
++ { CR243, (value >> 8) & 0xff },
++ { CR242, value & 0xff },
++ };
++ ZD_ASSERT(mutex_is_locked(&chip->mutex));
++ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++}
++
++int zd_rfwritev_cr_locked(struct zd_chip *chip,
++ const u32 *values, unsigned int count)
++{
++ int r;
++ unsigned int i;
++
++ for (i = 0; i < count; i++) {
++ r = zd_rfwrite_cr_locked(chip, values[i]);
++ if (r)
++ return r;
++ }
++
++ return 0;
++}
+diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
+index 069d2b4..ae59597 100644
+--- a/drivers/net/wireless/zd1211rw/zd_chip.h
++++ b/drivers/net/wireless/zd1211rw/zd_chip.h
+@@ -428,6 +428,7 @@
+ /* masks for controlling LEDs */
+ #define LED1 0x0100
+ #define LED2 0x0200
++#define LED_SW 0x0400
+
+ /* Seems to indicate that the configuration is over.
+ */
+@@ -473,7 +474,15 @@
+
+ #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
+ #define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694)
++
+ #define CR_IFS_VALUE CTL_REG(0x0698)
++#define IFS_VALUE_DIFS_SH 0
++#define IFS_VALUE_EIFS_SH 12
++#define IFS_VALUE_SIFS_SH 24
++#define IFS_VALUE_DEFAULT (( 50 << IFS_VALUE_DIFS_SH) | \
++ (1148 << IFS_VALUE_EIFS_SH) | \
++ ( 10 << IFS_VALUE_SIFS_SH))
++
+ #define CR_RX_TIME_OUT CTL_REG(0x069C)
+ #define CR_TOTAL_RX_FRM CTL_REG(0x06A0)
+ #define CR_CRC32_CNT CTL_REG(0x06A4)
+@@ -621,6 +630,10 @@
+ #define FW_SOFT_RESET FW_REG(4)
+ #define FW_FLASH_CHK FW_REG(5)
+
++#define FW_LINK_OFF 0x0
++#define FW_LINK_TX 0x1
++/* 0x2 - link led on? */
++
+ enum {
+ CR_BASE_OFFSET = 0x9000,
+ FW_START_OFFSET = 0xee00,
+@@ -630,6 +643,7 @@ enum {
+ LOAD_CODE_SIZE = 0xe, /* words */
+ LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
+ EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
++ EEPROM_REGS_SIZE = 0x7e, /* words */
+ E2P_BASE_OFFSET = EEPROM_START_OFFSET +
+ EEPROM_REGS_OFFSET,
+ };
+@@ -654,8 +668,11 @@ struct zd_chip {
+ u8 pwr_int_values[E2P_CHANNEL_COUNT];
+ /* SetPointOFDM in the vendor driver */
+ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
+- u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
+- is_zd1211b:1;
++ u16 link_led;
++ unsigned int pa_type:4,
++ patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
++ new_phy_layout:1,
++ is_zd1211b:1, supports_tx_led:1;
+ };
+
+ static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
+@@ -739,8 +756,12 @@ static inline int zd_rfwrite_locked(stru
+ return zd_usb_rfwrite(&chip->usb, value, bits);
+ }
+
++int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value);
++
+ int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits);
++int zd_rfwritev_cr_locked(struct zd_chip *chip,
++ const u32* values, unsigned int count);
+
+ /* Locking functions for reading and writing registers.
+ * The different parameters are intentional.
+@@ -799,15 +820,12 @@ int zd_chip_lock_phy_regs(struct zd_chip
+ int zd_chip_unlock_phy_regs(struct zd_chip *chip);
+
+ enum led_status {
+- LED_OFF = 0,
+- LED_ON = 1,
+- LED_FLIP = 2,
+- LED_STATUS = 3,
++ LED_OFF = 0,
++ LED_SCANNING = 1,
++ LED_ASSOCIATED = 2,
+ };
+
+-int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
+-int zd_chip_led_flip(struct zd_chip *chip, int led,
+- const unsigned int *phases_msecs, unsigned int count);
++int zd_chip_control_leds(struct zd_chip *chip, enum led_status status);
+
+ int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
+
+diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
+index 4659068..a13ec72 100644
+--- a/drivers/net/wireless/zd1211rw/zd_def.h
++++ b/drivers/net/wireless/zd1211rw/zd_def.h
+@@ -45,4 +45,10 @@ do { \
+ # define ZD_ASSERT(x) do { } while (0)
+ #endif
+
++#ifdef DEBUG
++# define ZD_MEMCLEAR(pointer, size) memset((pointer), 0xff, (size))
++#else
++# define ZD_MEMCLEAR(pointer, size) do { } while (0)
++#endif
++
+ #endif /* _ZD_DEF_H */
+diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+index 3632989..f63245b 100644
+--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
++++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+@@ -64,7 +64,7 @@ struct cck_plcp_header {
+ u8 service;
+ __le16 length;
+ __le16 crc16;
+-} __attribute__((packed));
++};
+
+ static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+ {
+diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
+index a9bd80a..a7d29bd 100644
+--- a/drivers/net/wireless/zd1211rw/zd_mac.c
++++ b/drivers/net/wireless/zd1211rw/zd_mac.c
+@@ -33,6 +33,10 @@
+ static void ieee_init(struct ieee80211_device *ieee);
+ static void softmac_init(struct ieee80211softmac_device *sm);
+
++static void housekeeping_init(struct zd_mac *mac);
++static void housekeeping_enable(struct zd_mac *mac);
++static void housekeeping_disable(struct zd_mac *mac);
++
+ int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+@@ -46,6 +50,7 @@ int zd_mac_init(struct zd_mac *mac,
+ ieee_init(ieee);
+ softmac_init(ieee80211_priv(netdev));
+ zd_chip_init(&mac->chip, netdev, intf);
++ housekeeping_init(mac);
+ return 0;
+ }
+
+@@ -127,11 +132,9 @@ out:
+
+ void zd_mac_clear(struct zd_mac *mac)
+ {
+- /* Aquire the lock. */
+- spin_lock(&mac->lock);
+- spin_unlock(&mac->lock);
+ zd_chip_clear(&mac->chip);
+- memset(mac, 0, sizeof(*mac));
++ ZD_ASSERT(!spin_is_locked(&mac->lock));
++ ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
+ }
+
+ static int reset_mode(struct zd_mac *mac)
+@@ -180,6 +183,7 @@ int zd_mac_open(struct net_device *netde
+ if (r < 0)
+ goto disable_rx;
+
++ housekeeping_enable(mac);
+ ieee80211softmac_start(netdev);
+ return 0;
+ disable_rx:
+@@ -206,6 +210,7 @@ int zd_mac_stop(struct net_device *netde
+ */
+
+ zd_chip_disable_rx(chip);
++ housekeeping_disable(mac);
+ ieee80211softmac_stop(netdev);
+
+ zd_chip_disable_hwint(chip);
+@@ -716,7 +721,7 @@ struct zd_rt_hdr {
+ u8 rt_rate;
+ u16 rt_channel;
+ u16 rt_chbitmask;
+-} __attribute__((packed));
++};
+
+ static void fill_rt_header(void *buffer, struct zd_mac *mac,
+ const struct ieee80211_rx_stats *stats,
+@@ -1082,3 +1087,46 @@ void zd_dump_rx_status(const struct rx_s
+ }
+ }
+ #endif /* DEBUG */
++
++#define LINK_LED_WORK_DELAY HZ
++
++static void link_led_handler(void *p)
++{
++ struct zd_mac *mac = p;
++ struct zd_chip *chip = &mac->chip;
++ struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
++ int is_associated;
++ int r;
++
++ spin_lock_irq(&mac->lock);
++ is_associated = sm->associnfo.associated != 0;
++ spin_unlock_irq(&mac->lock);
++
++ r = zd_chip_control_leds(chip,
++ is_associated ? LED_ASSOCIATED : LED_SCANNING);
++ if (r)
++ dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
++
++ queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
++ LINK_LED_WORK_DELAY);
++}
++
++static void housekeeping_init(struct zd_mac *mac)
++{
++ INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
++}
++
++static void housekeeping_enable(struct zd_mac *mac)
++{
++ dev_dbg_f(zd_mac_dev(mac), "\n");
++ queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
++ 0);
++}
++
++static void housekeeping_disable(struct zd_mac *mac)
++{
++ dev_dbg_f(zd_mac_dev(mac), "\n");
++ cancel_rearming_delayed_workqueue(zd_workqueue,
++ &mac->housekeeping.link_led_work);
++ zd_chip_control_leds(&mac->chip, LED_OFF);
++}
+diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
+index b3ba49b..b8ea3de 100644
+--- a/drivers/net/wireless/zd1211rw/zd_mac.h
++++ b/drivers/net/wireless/zd1211rw/zd_mac.h
+@@ -82,7 +82,7 @@ struct zd_ctrlset {
+ struct rx_length_info {
+ __le16 length[3];
+ __le16 tag;
+-} __attribute__((packed));
++};
+
+ #define RX_LENGTH_INFO_TAG 0x697e
+
+@@ -93,7 +93,7 @@ struct rx_status {
+ u8 signal_quality_ofdm;
+ u8 decryption_type;
+ u8 frame_status;
+-} __attribute__((packed));
++};
+
+ /* rx_status field decryption_type */
+ #define ZD_RX_NO_WEP 0
+@@ -120,14 +120,19 @@ enum mac_flags {
+ MAC_FIXED_CHANNEL = 0x01,
+ };
+
++struct housekeeping {
++ struct work_struct link_led_work;
++};
++
+ #define ZD_MAC_STATS_BUFFER_SIZE 16
+
+ struct zd_mac {
+- struct net_device *netdev;
+ struct zd_chip chip;
+ spinlock_t lock;
++ struct net_device *netdev;
+ /* Unlocked reading possible */
+ struct iw_statistics iw_stats;
++ struct housekeeping housekeeping;
+ unsigned int stats_count;
+ u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
+ u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
+diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
+index 9df232c..af3a7b3 100644
+--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
++++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
+@@ -72,10 +72,18 @@ static int iw_get_name(struct net_device
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+ {
+- /* FIXME: check whether 802.11a will also supported, add also
+- * zd1211B, if we support it.
+- */
+- strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
++ /* FIXME: check whether 802.11a will also supported */
++ strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
++ return 0;
++}
++
++static int iw_get_nick(struct net_device *netdev,
++ struct iw_request_info *info,
++ union iwreq_data *req, char *extra)
++{
++ strcpy(extra, "zd1211");
++ req->data.length = strlen(extra);
++ req->data.flags = 1;
+ return 0;
+ }
+
+@@ -181,6 +189,7 @@ static int iw_get_encodeext(struct net_d
+
+ static const iw_handler zd_standard_iw_handlers[] = {
+ WX(SIOCGIWNAME) = iw_get_name,
++ WX(SIOCGIWNICKN) = iw_get_nick,
+ WX(SIOCSIWFREQ) = iw_set_freq,
+ WX(SIOCGIWFREQ) = iw_get_freq,
+ WX(SIOCSIWMODE) = iw_set_mode,
+diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
+index d3770d2..f50cff3 100644
+--- a/drivers/net/wireless/zd1211rw/zd_rf.c
++++ b/drivers/net/wireless/zd1211rw/zd_rf.c
+@@ -56,7 +56,7 @@ void zd_rf_init(struct zd_rf *rf)
+
+ void zd_rf_clear(struct zd_rf *rf)
+ {
+- memset(rf, 0, sizeof(*rf));
++ ZD_MEMCLEAR(rf, sizeof(*rf));
+ }
+
+ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
+@@ -76,6 +76,11 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 t
+ if (r)
+ return r;
+ break;
++ case AL7230B_RF:
++ r = zd_rf_init_al7230b(rf);
++ if (r)
++ return r;
++ break;
+ default:
+ dev_err(zd_chip_dev(chip),
+ "RF %s %#x is not supported\n", zd_rf_name(type), type);
+diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
+index ea30f69..676b373 100644
+--- a/drivers/net/wireless/zd1211rw/zd_rf.h
++++ b/drivers/net/wireless/zd1211rw/zd_rf.h
+@@ -78,5 +78,6 @@ int zd_switch_radio_off(struct zd_rf *rf
+
+ int zd_rf_init_rf2959(struct zd_rf *rf);
+ int zd_rf_init_al2230(struct zd_rf *rf);
++int zd_rf_init_al7230b(struct zd_rf *rf);
+
+ #endif /* _ZD_RF_H */
+diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+index 0948b25..25323a1 100644
+--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
++++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+@@ -21,7 +21,7 @@
+ #include "zd_usb.h"
+ #include "zd_chip.h"
+
+-static const u32 al2230_table[][3] = {
++static const u32 zd1211_al2230_table[][3] = {
+ RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
+@@ -38,6 +38,53 @@ static const u32 al2230_table[][3] = {
+ RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
+ };
+
++static const u32 zd1211b_al2230_table[][3] = {
++ RF_CHANNEL( 1) = { 0x09efc0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL( 2) = { 0x09efc0, 0x8cccd0, 0xb00000, },
++ RF_CHANNEL( 3) = { 0x09e7c0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL( 4) = { 0x09e7c0, 0x8cccd0, 0xb00000, },
++ RF_CHANNEL( 5) = { 0x05efc0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL( 6) = { 0x05efc0, 0x8cccd0, 0xb00000, },
++ RF_CHANNEL( 7) = { 0x05e7c0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL( 8) = { 0x05e7c0, 0x8cccd0, 0xb00000, },
++ RF_CHANNEL( 9) = { 0x0defc0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL(10) = { 0x0defc0, 0x8cccd0, 0xb00000, },
++ RF_CHANNEL(11) = { 0x0de7c0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL(12) = { 0x0de7c0, 0x8cccd0, 0xb00000, },
++ RF_CHANNEL(13) = { 0x03efc0, 0x8cccc0, 0xb00000, },
++ RF_CHANNEL(14) = { 0x03e7c0, 0x866660, 0xb00000, },
++};
++
++static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
++ { CR240, 0x57 }, { CR9, 0xe0 },
++};
++
++static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
++{
++ int r;
++ static const struct zd_ioreq16 ioreqs[] = {
++ { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
++ { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
++ { CR203, 0x06 },
++ { },
++
++ { CR240, 0x80 },
++ };
++
++ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++ if (r)
++ return r;
++
++ /* related to antenna selection? */
++ if (chip->new_phy_layout) {
++ r = zd_iowrite16_locked(chip, 0xe1, CR9);
++ if (r)
++ return r;
++ }
++
++ return zd_iowrite16_locked(chip, 0x06, CR203);
++}
++
+ static int zd1211_al2230_init_hw(struct zd_rf *rf)
+ {
+ int r;
+@@ -139,7 +186,7 @@ static int zd1211b_al2230_init_hw(struct
+ { CR47, 0x1e },
+
+ /* ZD1211B 05.06.10 */
+- { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
++ { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 },
+ { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
+ { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
+ { CR69, 0x28 },
+@@ -172,79 +219,78 @@ static int zd1211b_al2230_init_hw(struct
+ { CR137, 0x50 }, /* 5614 */
+ { CR138, 0xa8 },
+ { CR144, 0xac }, /* 5621 */
+- { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
++ { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
+ };
+
+ static const u32 rv1[] = {
+- /* channel 1 */
+- 0x03f790,
+- 0x033331,
+- 0x00000d,
+-
+- 0x0b3331,
+- 0x03b812,
+- 0x00fff3,
+- 0x0005a4,
+- 0x0f4dc5, /* fix freq shift 0x044dc5 */
+- 0x0805b6,
+- 0x0146c7,
+- 0x000688,
+- 0x0403b9, /* External control TX power (CR31) */
+- 0x00dbba,
+- 0x00099b,
+- 0x0bdffc,
+- 0x00000d,
+- 0x00580f,
++ 0x8cccd0,
++ 0x481dc0,
++ 0xcfff00,
++ 0x25a000,
++
++ /* To improve AL2230 yield, improve phase noise, 4713 */
++ 0x25a000,
++ 0xa3b2f0,
++
++ 0x6da010, /* Reg6 update for MP versio */
++ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
++ 0x116000,
++ 0x9dc020, /* External control TX power (CR31) */
++ 0x5ddb00, /* RegA update for MP version */
++ 0xd99000, /* RegB update for MP version */
++ 0x3ffbd0, /* RegC update for MP version */
++ 0xb00000, /* RegD update for MP version */
++
++ /* improve phase noise and remove phase calibration,4713 */
++ 0xf01a00,
+ };
+
+ static const struct zd_ioreq16 ioreqs2[] = {
+- { CR47, 0x1e }, { CR_RFCFG, 0x03 },
++ { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
++ { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
+ };
+
+ static const u32 rv2[] = {
+- 0x00880f,
+- 0x00080f,
++ /* To improve AL2230 yield, 4713 */
++ 0xf01b00,
++ 0xf01e00,
++ 0xf01a00,
+ };
+
+ static const struct zd_ioreq16 ioreqs3[] = {
+- { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
+- };
+-
+- static const u32 rv3[] = {
+- 0x00d80f,
+- 0x00780f,
+- 0x00580f,
+- };
+-
+- static const struct zd_ioreq16 ioreqs4[] = {
+- { CR138, 0x28 }, { CR203, 0x06 },
++ /* related to 6M band edge patching, happens unconditionally */
++ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ };
+
++ r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
++ ARRAY_SIZE(zd1211b_ioreqs_shared_1));
++ if (r)
++ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
+ if (r)
+ return r;
+- r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
++ r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
+ if (r)
+ return r;
+- r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
++ r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
+ if (r)
+ return r;
+- r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
++ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ if (r)
+ return r;
+- r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
++ r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
+ if (r)
+ return r;
+- r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
++ r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+ if (r)
+ return r;
+- return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
++ return zd1211b_al2230_finalize_rf(chip);
+ }
+
+-static int al2230_set_channel(struct zd_rf *rf, u8 channel)
++static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel)
+ {
+ int r;
+- const u32 *rv = al2230_table[channel-1];
++ const u32 *rv = zd1211_al2230_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR138, 0x28 },
+@@ -257,6 +303,24 @@ static int al2230_set_channel(struct zd_
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ }
+
++static int zd1211b_al2230_set_channel(struct zd_rf *rf, u8 channel)
++{
++ int r;
++ const u32 *rv = zd1211b_al2230_table[channel-1];
++ struct zd_chip *chip = zd_rf_to_chip(rf);
++
++ r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
++ ARRAY_SIZE(zd1211b_ioreqs_shared_1));
++ if (r)
++ return r;
++
++ r = zd_rfwritev_cr_locked(chip, rv, 3);
++ if (r)
++ return r;
++
++ return zd1211b_al2230_finalize_rf(chip);
++}
++
+ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
+ {
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+@@ -294,13 +358,14 @@ int zd_rf_init_al2230(struct zd_rf *rf)
+ {
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+- rf->set_channel = al2230_set_channel;
+ rf->switch_radio_off = al2230_switch_radio_off;
+ if (chip->is_zd1211b) {
+ rf->init_hw = zd1211b_al2230_init_hw;
++ rf->set_channel = zd1211b_al2230_set_channel;
+ rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
+ } else {
+ rf->init_hw = zd1211_al2230_init_hw;
++ rf->set_channel = zd1211_al2230_set_channel;
+ rf->switch_radio_on = zd1211_al2230_switch_radio_on;
+ }
+ rf->patch_6m_band_edge = 1;
+diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+new file mode 100644
+index 0000000..a289f95
+--- /dev/null
++++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+@@ -0,0 +1,274 @@
++/* zd_rf_al7230b.c: Functions for the AL7230B RF controller
++ *
++ * 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 "zd_rf.h"
++#include "zd_usb.h"
++#include "zd_chip.h"
++
++static const u32 chan_rv[][2] = {
++ RF_CHANNEL( 1) = { 0x09ec00, 0x8cccc8 },
++ RF_CHANNEL( 2) = { 0x09ec00, 0x8cccd8 },
++ RF_CHANNEL( 3) = { 0x09ec00, 0x8cccc0 },
++ RF_CHANNEL( 4) = { 0x09ec00, 0x8cccd0 },
++ RF_CHANNEL( 5) = { 0x05ec00, 0x8cccc8 },
++ RF_CHANNEL( 6) = { 0x05ec00, 0x8cccd8 },
++ RF_CHANNEL( 7) = { 0x05ec00, 0x8cccc0 },
++ RF_CHANNEL( 8) = { 0x05ec00, 0x8cccd0 },
++ RF_CHANNEL( 9) = { 0x0dec00, 0x8cccc8 },
++ RF_CHANNEL(10) = { 0x0dec00, 0x8cccd8 },
++ RF_CHANNEL(11) = { 0x0dec00, 0x8cccc0 },
++ RF_CHANNEL(12) = { 0x0dec00, 0x8cccd0 },
++ RF_CHANNEL(13) = { 0x03ec00, 0x8cccc8 },
++ RF_CHANNEL(14) = { 0x03ec00, 0x866660 },
++};
++
++static const u32 std_rv[] = {
++ 0x4ff821,
++ 0xc5fbfc,
++ 0x21ebfe,
++ 0xafd401, /* freq shift 0xaad401 */
++ 0x6cf56a,
++ 0xe04073,
++ 0x193d76,
++ 0x9dd844,
++ 0x500007,
++ 0xd8c010,
++};
++
++static int al7230b_init_hw(struct zd_rf *rf)
++{
++ int i, r;
++ struct zd_chip *chip = zd_rf_to_chip(rf);
++
++ /* All of these writes are identical to AL2230 unless otherwise
++ * specified */
++ static const struct zd_ioreq16 ioreqs_1[] = {
++ /* This one is 7230-specific, and happens before the rest */
++ { CR240, 0x57 },
++ { },
++
++ { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
++ { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
++ { CR44, 0x33 },
++ /* This value is different for 7230 (was: 0x2a) */
++ { CR106, 0x22 },
++ { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 },
++ { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a },
++ /* This happened further down in AL2230,
++ * and the value changed (was: 0xe0) */
++ { CR122, 0xfc },
++ { CR10, 0x89 },
++ /* for newest (3rd cut) AL2300 */
++ { CR17, 0x28 },
++ { CR26, 0x93 }, { CR34, 0x30 },
++ /* for newest (3rd cut) AL2300 */
++ { CR35, 0x3e },
++ { CR41, 0x24 }, { CR44, 0x32 },
++ /* for newest (3rd cut) AL2300 */
++ { CR46, 0x96 },
++ { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
++ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
++ { CR92, 0x0a }, { CR99, 0x28 },
++ /* This value is different for 7230 (was: 0x00) */
++ { CR100, 0x02 },
++ { CR101, 0x13 }, { CR102, 0x27 },
++ /* This value is different for 7230 (was: 0x24) */
++ { CR106, 0x22 },
++ /* This value is different for 7230 (was: 0x2a) */
++ { CR107, 0x3f },
++ { CR109, 0x09 },
++ /* This value is different for 7230 (was: 0x13) */
++ { CR110, 0x1f },
++ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
++ { CR114, 0x27 },
++ /* for newest (3rd cut) AL2300 */
++ { CR115, 0x24 },
++ /* This value is different for 7230 (was: 0x24) */
++ { CR116, 0x3f },
++ /* This value is different for 7230 (was: 0xf4) */
++ { CR117, 0xfa },
++ { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f },
++ { CR121, 0x77 }, { CR137, 0x88 },
++ /* This one is 7230-specific */
++ { CR138, 0xa8 },
++ /* This value is different for 7230 (was: 0xff) */
++ { CR252, 0x34 },
++ /* This value is different for 7230 (was: 0xff) */
++ { CR253, 0x34 },
++
++ /* PLL_OFF */
++ { CR251, 0x2f },
++ };
++
++ static const struct zd_ioreq16 ioreqs_2[] = {
++ /* PLL_ON */
++ { CR251, 0x3f },
++ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
++ { CR38, 0x38 }, { CR136, 0xdf },
++ };
++
++ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
++ if (r)
++ return r;
++
++ r = zd_rfwrite_cr_locked(chip, 0x09ec04);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
++ if (r)
++ return r;
++
++ for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
++ r = zd_rfwrite_cr_locked(chip, std_rv[i]);
++ if (r)
++ return r;
++ }
++
++ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0xbfffff);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0x700000);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
++ if (r)
++ return r;
++
++ r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
++ if (r)
++ return r;
++
++ r = zd_rfwrite_cr_locked(chip, 0xf15d59);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
++ if (r)
++ return r;
++
++ r = zd_iowrite16_locked(chip, 0x06, CR203);
++ if (r)
++ return r;
++ r = zd_iowrite16_locked(chip, 0x80, CR240);
++ if (r)
++ return r;
++
++ return 0;
++}
++
++static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
++{
++ int i, r;
++ const u32 *rv = chan_rv[channel-1];
++ struct zd_chip *chip = zd_rf_to_chip(rf);
++
++ struct zd_ioreq16 ioreqs_1[] = {
++ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
++ { CR38, 0x38 }, { CR136, 0xdf },
++ };
++
++ struct zd_ioreq16 ioreqs_2[] = {
++ /* PLL_ON */
++ { CR251, 0x3f },
++ { CR203, 0x06 }, { CR240, 0x08 },
++ };
++
++ r = zd_iowrite16_locked(chip, 0x57, CR240);
++ if (r)
++ return r;
++
++ /* PLL_OFF */
++ r = zd_iowrite16_locked(chip, 0x2f, CR251);
++ if (r)
++ return r;
++
++ for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
++ r = zd_rfwrite_cr_locked(chip, std_rv[i]);
++ if (r)
++ return r;
++ }
++
++ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
++ if (r)
++ return r;
++ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
++ if (r)
++ return r;
++
++ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
++ if (r)
++ return r;
++
++ for (i = 0; i < 2; i++) {
++ r = zd_rfwrite_cr_locked(chip, rv[i]);
++ if (r)
++ return r;
++ }
++
++ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
++ if (r)
++ return r;
++
++ return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
++}
++
++static int al7230b_switch_radio_on(struct zd_rf *rf)
++{
++ struct zd_chip *chip = zd_rf_to_chip(rf);
++ static const struct zd_ioreq16 ioreqs[] = {
++ { CR11, 0x00 },
++ { CR251, 0x3f },
++ };
++
++ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++}
++
++static int al7230b_switch_radio_off(struct zd_rf *rf)
++{
++ struct zd_chip *chip = zd_rf_to_chip(rf);
++ static const struct zd_ioreq16 ioreqs[] = {
++ { CR11, 0x04 },
++ { CR251, 0x2f },
++ };
++
++ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
++}
++
++int zd_rf_init_al7230b(struct zd_rf *rf)
++{
++ struct zd_chip *chip = zd_rf_to_chip(rf);
++
++ if (chip->is_zd1211b) {
++ dev_err(zd_chip_dev(chip), "AL7230B is currently not "
++ "supported for ZD1211B devices\n");
++ return -ENODEV;
++ }
++
++ rf->init_hw = al7230b_init_hw;
++ rf->set_channel = al7230b_set_channel;
++ rf->switch_radio_on = al7230b_switch_radio_on;
++ rf->switch_radio_off = al7230b_switch_radio_off;
++ rf->patch_6m_band_edge = 1;
++ return 0;
++}
+diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
+index 6320984..3faaeb2 100644
+--- a/drivers/net/wireless/zd1211rw/zd_usb.c
++++ b/drivers/net/wireless/zd1211rw/zd_usb.c
+@@ -16,6 +16,7 @@
+ */
+
+ #include <asm/unaligned.h>
++#include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/firmware.h>
+@@ -23,6 +24,7 @@
+ #include <linux/errno.h>
+ #include <linux/skbuff.h>
+ #include <linux/usb.h>
++#include <linux/workqueue.h>
+ #include <net/ieee80211.h>
+
+ #include "zd_def.h"
+@@ -39,9 +41,19 @@ static struct usb_device_id usb_ids[] =
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
++ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
++ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
++ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
++ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
++ { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
++ { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ /* ZD1211B */
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
++ { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
++ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
++ /* "Driverless" devices that need ejecting */
++ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
+ {}
+ };
+
+@@ -263,6 +275,39 @@ static char *get_fw_name(char *buffer, s
+ return buffer;
+ }
+
++static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
++ const struct firmware *ub_fw)
++{
++ const struct firmware *ur_fw = NULL;
++ int offset;
++ int r = 0;
++ char fw_name[128];
++
++ r = request_fw_file(&ur_fw,
++ get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
++ &udev->dev);
++ if (r)
++ goto error;
++
++ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
++ REBOOT);
++ if (r)
++ goto error;
++
++ offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
++ r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
++ E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
++
++ /* At this point, the vendor driver downloads the whole firmware
++ * image, hacks around with version IDs, and uploads it again,
++ * completely overwriting the boot code. We do not do this here as
++ * it is not required on any tested devices, and it is suspected to
++ * cause problems. */
++error:
++ release_firmware(ur_fw);
++ return r;
++}
++
+ static int upload_firmware(struct usb_device *udev, u8 device_type)
+ {
+ int r;
+@@ -282,15 +327,17 @@ static int upload_firmware(struct usb_de
+
+ fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+
+- /* FIXME: do we have any reason to perform the kludge that the vendor
+- * driver does when there is a version mismatch? (their driver uploads
+- * different firmwares and stuff)
+- */
+ if (fw_bcdDevice != bcdDevice) {
+ dev_info(&udev->dev,
+- "firmware device id %#06x and actual device id "
+- "%#06x differ, continuing anyway\n",
+- fw_bcdDevice, bcdDevice);
++ "firmware version %#06x and device bootcode version "
++ "%#06x differ\n", fw_bcdDevice, bcdDevice);
++ if (bcdDevice <= 0x4313)
++ dev_warn(&udev->dev, "device has old bootcode, please "
++ "report success or failure\n");
++
++ r = handle_version_mismatch(udev, device_type, ub_fw);
++ if (r)
++ goto error;
+ } else {
+ dev_dbg_f(&udev->dev,
+ "firmware device id %#06x is equal to the "
+@@ -361,7 +408,7 @@ static inline void handle_retry_failed_i
+ }
+
+
+-static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
++static void int_urb_complete(struct urb *urb)
+ {
+ int r;
+ struct usb_int_header *hdr;
+@@ -562,7 +609,7 @@ static void handle_rx_packet(struct zd_u
+ }
+ }
+
+-static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
++static void rx_urb_complete(struct urb *urb)
+ {
+ struct zd_usb *usb;
+ struct zd_usb_rx *rx;
+@@ -620,7 +667,7 @@ resubmit:
+ usb_submit_urb(urb, GFP_ATOMIC);
+ }
+
+-struct urb *alloc_urb(struct zd_usb *usb)
++static struct urb *alloc_urb(struct zd_usb *usb)
+ {
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+@@ -644,7 +691,7 @@ struct urb *alloc_urb(struct zd_usb *usb
+ return urb;
+ }
+
+-void free_urb(struct urb *urb)
++static void free_urb(struct urb *urb)
+ {
+ if (!urb)
+ return;
+@@ -732,7 +779,7 @@ void zd_usb_disable_rx(struct zd_usb *us
+ spin_unlock_irqrestore(&rx->lock, flags);
+ }
+
+-static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
++static void tx_urb_complete(struct urb *urb)
+ {
+ int r;
+
+@@ -864,7 +911,7 @@ void zd_usb_clear(struct zd_usb *usb)
+ {
+ usb_set_intfdata(usb->intf, NULL);
+ usb_put_intf(usb->intf);
+- memset(usb, 0, sizeof(*usb));
++ ZD_MEMCLEAR(usb, sizeof(*usb));
+ /* FIXME: usb_interrupt, usb_tx, usb_rx? */
+ }
+
+@@ -910,6 +957,55 @@ static void print_id(struct usb_device *
+ #define print_id(udev) do { } while (0)
+ #endif
+
++static int eject_installer(struct usb_interface *intf)
++{
++ struct usb_device *udev = interface_to_usbdev(intf);
++ struct usb_host_interface *iface_desc = &intf->altsetting[0];
++ struct usb_endpoint_descriptor *endpoint;
++ unsigned char *cmd;
++ u8 bulk_out_ep;
++ int r;
++
++ /* Find bulk out endpoint */
++ endpoint = &iface_desc->endpoint[1].desc;
++ if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
++ (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ USB_ENDPOINT_XFER_BULK) {
++ bulk_out_ep = endpoint->bEndpointAddress;
++ } else {
++ dev_err(&udev->dev,
++ "zd1211rw: Could not find bulk out endpoint\n");
++ return -ENODEV;
++ }
++
++ cmd = kzalloc(31, GFP_KERNEL);
++ if (cmd == NULL)
++ return -ENODEV;
++
++ /* USB bulk command block */
++ cmd[0] = 0x55; /* bulk command signature */
++ cmd[1] = 0x53; /* bulk command signature */
++ cmd[2] = 0x42; /* bulk command signature */
++ cmd[3] = 0x43; /* bulk command signature */
++ cmd[14] = 6; /* command length */
++
++ cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
++ cmd[19] = 0x2; /* eject disc */
++
++ dev_info(&udev->dev, "Ejecting virtual installer media...\n");
++ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
++ cmd, 31, NULL, 2000);
++ kfree(cmd);
++ if (r)
++ return r;
++
++ /* At this point, the device disconnects and reconnects with the real
++ * ID numbers. */
++
++ usb_set_intfdata(intf, NULL);
++ return 0;
++}
++
+ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ int r;
+@@ -918,6 +1014,9 @@ static int probe(struct usb_interface *i
+
+ print_id(udev);
+
++ if (id->driver_info & DEVICE_INSTALLER)
++ return eject_installer(intf);
++
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+@@ -983,6 +1082,11 @@ static void disconnect(struct usb_interf
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_usb *usb = &mac->chip.usb;
+
++ /* Either something really bad happened, or we're just dealing with
++ * a DEVICE_INSTALLER. */
++ if (netdev == NULL)
++ return;
++
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ zd_netdev_disconnect(netdev);
+@@ -998,7 +1102,6 @@ static void disconnect(struct usb_interf
+ */
+ usb_reset_device(interface_to_usbdev(intf));
+
+- /* If somebody still waits on this lock now, this is an error. */
+ zd_netdev_free(netdev);
+ dev_dbg(&intf->dev, "disconnected\n");
+ }
+@@ -1010,12 +1113,20 @@ static struct usb_driver driver = {
+ .disconnect = disconnect,
+ };
+
++struct workqueue_struct *zd_workqueue;
++
+ static int __init usb_init(void)
+ {
+ int r;
+
+ pr_debug("usb_init()\n");
+
++ zd_workqueue = create_singlethread_workqueue(driver.name);
++ if (zd_workqueue == NULL) {
++ printk(KERN_ERR "%s: couldn't create workqueue\n", driver.name);
++ return -ENOMEM;
++ }
++
+ r = usb_register(&driver);
+ if (r) {
+ printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
+@@ -1030,6 +1141,7 @@ static void __exit usb_exit(void)
+ {
+ pr_debug("usb_exit()\n");
+ usb_deregister(&driver);
++ destroy_workqueue(zd_workqueue);
+ }
+
+ module_init(usb_init);
+diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
+index d642028..e81a2d3 100644
+--- a/drivers/net/wireless/zd1211rw/zd_usb.h
++++ b/drivers/net/wireless/zd1211rw/zd_usb.h
+@@ -30,6 +30,7 @@
+ enum devicetype {
+ DEVICE_ZD1211 = 0,
+ DEVICE_ZD1211B = 1,
++ DEVICE_INSTALLER = 2,
+ };
+
+ enum endpoints {
+@@ -73,17 +74,17 @@ enum control_requests {
+ struct usb_req_read_regs {
+ __le16 id;
+ __le16 addr[0];
+-} __attribute__((packed));
++};
+
+ struct reg_data {
+ __le16 addr;
+ __le16 value;
+-} __attribute__((packed));
++};
+
+ struct usb_req_write_regs {
+ __le16 id;
+ struct reg_data reg_writes[0];
+-} __attribute__((packed));
++};
+
+ enum {
+ RF_IF_LE = 0x02,
+@@ -100,7 +101,7 @@ struct usb_req_rfwrite {
+ /* RF2595: 24 */
+ __le16 bit_values[0];
+ /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+-} __attribute__((packed));
++};
+
+ /* USB interrupt */
+
+@@ -117,12 +118,12 @@ enum usb_int_flags {
+ struct usb_int_header {
+ u8 type; /* must always be 1 */
+ u8 id;
+-} __attribute__((packed));
++};
+
+ struct usb_int_regs {
+ struct usb_int_header hdr;
+ struct reg_data regs[0];
+-} __attribute__((packed));
++};
+
+ struct usb_int_retry_fail {
+ struct usb_int_header hdr;
+@@ -130,7 +131,7 @@ struct usb_int_retry_fail {
+ u8 _dummy;
+ u8 addr[ETH_ALEN];
+ u8 ibss_wakeup_dest;
+-} __attribute__((packed));
++};
+
+ struct read_regs_int {
+ struct completion completion;
+@@ -237,4 +238,6 @@ int zd_usb_iowrite16v(struct zd_usb *usb
+
+ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+
++extern struct workqueue_struct *zd_workqueue;
++
+ #endif /* _ZD_USB_H */
+diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
+index 8459a18..2412ce4 100644
+--- a/drivers/net/yellowfin.c
++++ b/drivers/net/yellowfin.c
+@@ -24,8 +24,8 @@
+ */
+
+ #define DRV_NAME "yellowfin"
+-#define DRV_VERSION "2.0"
+-#define DRV_RELDATE "Jun 27, 2006"
++#define DRV_VERSION "2.1"
++#define DRV_RELDATE "Sep 11, 2006"
+
+ #define PFX DRV_NAME ": "
+
+@@ -137,7 +137,7 @@ MODULE_PARM_DESC(gx_fix, "G-NIC: enable
+ I. Board Compatibility
+
+ This device driver is designed for the Packet Engines "Yellowfin" Gigabit
+-Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the
++Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the
+ Symbios 53C885E dual function chip.
+
+ II. Board-specific settings
+@@ -208,7 +208,7 @@ IVc. Errata
+ See Packet Engines confidential appendix (prototype chips only).
+ */
+
+-
++
+
+ enum capability_flags {
+ HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
+@@ -350,13 +350,13 @@ static void yellowfin_timer(unsigned lon
+ static void yellowfin_tx_timeout(struct net_device *dev);
+ static void yellowfin_init_ring(struct net_device *dev);
+ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
+ static int yellowfin_rx(struct net_device *dev);
+ static void yellowfin_error(struct net_device *dev, int intr_status);
+ static int yellowfin_close(struct net_device *dev);
+ static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
+ static void set_rx_mode(struct net_device *dev);
+-static struct ethtool_ops ethtool_ops;
++static const struct ethtool_ops ethtool_ops;
+
+
+ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
+@@ -377,7 +377,7 @@ static int __devinit yellowfin_init_one(
+ #else
+ int bar = 1;
+ #endif
+-
++
+ /* when built into the kernel, we only print version if device is found */
+ #ifndef MODULE
+ static int printed_version;
+@@ -508,11 +508,11 @@ static int __devinit yellowfin_init_one(
+ }
+
+ find_cnt++;
+-
++
+ return 0;
+
+ err_out_unmap_status:
+- pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
++ pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
+ np->tx_status_dma);
+ err_out_unmap_rx:
+ pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
+@@ -569,7 +569,7 @@ static void mdio_write(void __iomem *ioa
+ return;
+ }
+
+-
++
+ static int yellowfin_open(struct net_device *dev)
+ {
+ struct yellowfin_private *yp = netdev_priv(dev);
+@@ -673,7 +673,7 @@ static void yellowfin_timer(unsigned lon
+ dev->name, yp->phys[0], bmsr, lpa);
+
+ yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated);
+-
++
+ iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
+
+ if (bmsr & BMSR_LSTATUS)
+@@ -792,10 +792,10 @@ static void yellowfin_init_ring(struct n
+ /* Om pade ummmmm... */
+ yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma +
+ i*sizeof(struct tx_status_words) +
+- &(yp->tx_status[0].tx_errs) -
++ &(yp->tx_status[0].tx_errs) -
+ &(yp->tx_status[0]));
+ }
+- yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
++ yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
+ ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc));
+ }
+ /* Wrap ring */
+@@ -835,7 +835,7 @@ static int yellowfin_start_xmit(struct s
+ yp->tx_skbuff[entry] = skb;
+
+ #ifdef NO_TXSTATS
+- yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
++ yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
+ skb->data, len, PCI_DMA_TODEVICE));
+ yp->tx_ring[entry].result_status = 0;
+ if (entry >= TX_RING_SIZE-1) {
+@@ -851,9 +851,9 @@ static int yellowfin_start_xmit(struct s
+ yp->cur_tx++;
+ #else
+ yp->tx_ring[entry<<1].request_cnt = len;
+- yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
++ yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
+ skb->data, len, PCI_DMA_TODEVICE));
+- /* The input_last (status-write) command is constant, but we must
++ /* The input_last (status-write) command is constant, but we must
+ rewrite the subsequent 'stop' command. */
+
+ yp->cur_tx++;
+@@ -888,7 +888,7 @@ static int yellowfin_start_xmit(struct s
+
+ /* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+-static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
+ {
+ struct net_device *dev = dev_instance;
+ struct yellowfin_private *yp;
+@@ -896,16 +896,9 @@ static irqreturn_t yellowfin_interrupt(i
+ int boguscnt = max_interrupt_work;
+ unsigned int handled = 0;
+
+-#ifndef final_version /* Can never occur. */
+- if (dev == NULL) {
+- printk (KERN_ERR "yellowfin_interrupt(): irq %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-#endif
+-
+ yp = netdev_priv(dev);
+ ioaddr = yp->base;
+-
++
+ spin_lock (&yp->lock);
+
+ do {
+@@ -993,8 +986,8 @@ static irqreturn_t yellowfin_interrupt(i
+ yp->stats.tx_packets++;
+ }
+ /* Free the original skb. */
+- pci_unmap_single(yp->pci_dev,
+- yp->tx_ring[entry<<1].addr, skb->len,
++ pci_unmap_single(yp->pci_dev,
++ yp->tx_ring[entry<<1].addr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+ yp->tx_skbuff[entry] = 0;
+@@ -1073,7 +1066,7 @@ static int yellowfin_rx(struct net_devic
+ yp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ desc_status = le32_to_cpu(desc->result_status) >> 16;
+ buf_addr = rx_skb->data;
+- data_size = (le32_to_cpu(desc->dbdma_cmd) -
++ 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])));
+ if (yellowfin_debug > 4)
+@@ -1109,7 +1102,7 @@ static int yellowfin_rx(struct net_devic
+ } else if ((yp->flags & HasMACAddrBug) &&
+ memcmp(le32_to_cpu(yp->rx_ring_dma +
+ entry*sizeof(struct yellowfin_desc)),
+- dev->dev_addr, 6) != 0 &&
++ dev->dev_addr, 6) != 0 &&
+ memcmp(le32_to_cpu(yp->rx_ring_dma +
+ entry*sizeof(struct yellowfin_desc)),
+ "\377\377\377\377\377\377", 6) != 0) {
+@@ -1135,9 +1128,9 @@ static int yellowfin_rx(struct net_devic
+ without copying to a properly sized skbuff. */
+ if (pkt_len > rx_copybreak) {
+ skb_put(skb = rx_skb, pkt_len);
+- pci_unmap_single(yp->pci_dev,
+- yp->rx_ring[entry].addr,
+- yp->rx_buf_sz,
++ pci_unmap_single(yp->pci_dev,
++ yp->rx_ring[entry].addr,
++ yp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ yp->rx_skbuff[entry] = NULL;
+ } else {
+@@ -1307,8 +1300,6 @@ static void set_rx_mode(struct net_devic
+ /* Stop the Rx process to change any value. */
+ iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg);
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+- /* Unconditionally log net taps. */
+- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ iowrite16(0x000F, ioaddr + AddrMode);
+ } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter well, or accept all multicasts. */
+@@ -1354,7 +1345,7 @@ static void yellowfin_get_drvinfo(struct
+ strcpy(info->bus_info, pci_name(np->pci_dev));
+ }
+
+-static struct ethtool_ops ethtool_ops = {
++static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = yellowfin_get_drvinfo
+ };
+
+@@ -1405,7 +1396,7 @@ static void __devexit yellowfin_remove_o
+ BUG_ON(!dev);
+ np = netdev_priv(dev);
+
+- pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
++ pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
+ np->tx_status_dma);
+ pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
+ pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
+@@ -1434,7 +1425,7 @@ static int __init yellowfin_init (void)
+ #ifdef MODULE
+ printk(version);
+ #endif
+- return pci_module_init (&yellowfin_driver);
++ return pci_register_driver(&yellowfin_driver);
+ }
+
+
+@@ -1446,7 +1437,7 @@ static void __exit yellowfin_cleanup (vo
+
+ module_init(yellowfin_init);
+ module_exit(yellowfin_cleanup);
+-
++
+ /*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
+diff --git a/drivers/net/znet.c b/drivers/net/znet.c
+index 9f0291f..b24b072 100644
+--- a/drivers/net/znet.c
++++ b/drivers/net/znet.c
+@@ -75,7 +75,7 @@
+ - Now survives unplugging/replugging cable.
+
+ Some code was taken from wavelan_cs.
+-
++
+ Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
+ anything else. Testers (and detailed bug reports) are welcome :-).
+
+@@ -158,7 +158,7 @@ struct netidblk {
+
+ static int znet_open(struct net_device *dev);
+ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev);
+-static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t znet_interrupt(int irq, void *dev_id);
+ static void znet_rx(struct net_device *dev);
+ static int znet_close(struct net_device *dev);
+ static struct net_device_stats *net_get_stats(struct net_device *dev);
+@@ -171,7 +171,7 @@ static int znet_request_resources (struc
+ {
+ struct znet_private *znet = dev->priv;
+ unsigned long flags;
+-
++
+ if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev))
+ goto failed;
+ if (request_dma (znet->rx_dma, "ZNet rx"))
+@@ -205,7 +205,7 @@ static void znet_release_resources (stru
+ {
+ struct znet_private *znet = dev->priv;
+ unsigned long flags;
+-
++
+ release_region (znet->sia_base, znet->sia_size);
+ release_region (dev->base_addr, znet->io_size);
+ flags = claim_dma_lock();
+@@ -229,7 +229,7 @@ static void znet_transceiver_power (stru
+ v = inb(znet->sia_base + 1) | 0x84;
+ else
+ v = inb(znet->sia_base + 1) & ~0x84;
+-
++
+ outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
+ }
+
+@@ -242,7 +242,7 @@ static void znet_set_multicast_list (str
+ struct i82593_conf_block *cfblk = &znet->i593_init;
+
+ memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
+-
++
+ /* The configuration block. What an undocumented nightmare.
+ The first set of values are those suggested (without explanation)
+ for ethernet in the Intel 82586 databook. The rest appear to be
+@@ -251,7 +251,7 @@ static void znet_set_multicast_list (str
+
+ /* maz : Rewritten to take advantage of the wanvelan includes.
+ At least we have names, not just blind values */
+-
++
+ /* Byte 0 */
+ cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
+ cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */
+@@ -269,23 +269,23 @@ static void znet_set_multicast_list (str
+ cfblk->acloc = 1; /* Disable source addr insertion by i82593 */
+ cfblk->preamb_len = 2; /* 8 bytes preamble */
+ cfblk->loopback = 0; /* Loopback off */
+-
++
+ /* Byte 3 */
+ cfblk->lin_prio = 0; /* Default priorities & backoff methods. */
+ cfblk->tbofstop = 0;
+ cfblk->exp_prio = 0;
+ cfblk->bof_met = 0;
+-
++
+ /* Byte 4 */
+ cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */
+-
++
+ /* Byte 5 */
+ cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
+-
++
+ /* Byte 6 */
+ cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */
+ cfblk->max_retr = 15; /* 15 collisions retries */
+-
++
+ /* Byte 7 */
+ cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
+ cfblk->bc_dis = 0; /* Enable broadcast reception */
+@@ -293,15 +293,15 @@ static void znet_set_multicast_list (str
+ cfblk->nocrc_ins = 0; /* i82593 generates CRC */
+ cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */
+ cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */
+-
++
+ /* Byte 8 */
+ cfblk->cs_filter = 0; /* CS is recognized immediately */
+ cfblk->crs_src = 0; /* External carrier sense */
+ cfblk->cd_filter = 0; /* CD is recognized immediately */
+-
++
+ /* Byte 9 */
+ cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
+-
++
+ /* Byte A */
+ cfblk->lng_typ = 1; /* Type/length checks OFF */
+ cfblk->lng_fld = 1; /* Disable 802.3 length field check */
+@@ -311,15 +311,15 @@ static void znet_set_multicast_list (str
+ cfblk->tx_jabber = 0; /* Disable jabber jam sequence */
+ cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */
+ cfblk->lbpkpol = 0; /* Loopback pin active high */
+-
++
+ /* Byte B */
+ cfblk->fdx = 0; /* Disable full duplex operation */
+-
++
+ /* Byte C */
+ cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */
+ cfblk->mult_ia = 0; /* No multiple individual addresses */
+ cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */
+-
++
+ /* Byte D */
+ cfblk->dummy_1 = 1; /* set to 1 */
+ cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
+@@ -327,7 +327,7 @@ static void znet_set_multicast_list (str
+ cfblk->rcv_mon = 0; /* Monitor mode disabled */
+ cfblk->frag_acpt = 0; /* Do not accept fragments */
+ cfblk->tstrttrs = 0; /* No start transmission threshold */
+-
++
+ /* Byte E */
+ cfblk->fretx = 1; /* FIFO automatic retransmission */
+ cfblk->runt_eop = 0; /* drop "runt" packets */
+@@ -350,7 +350,7 @@ static void znet_set_multicast_list (str
+ printk ("%02X ", c[i]);
+ printk ("\n");
+ }
+-
++
+ *znet->tx_cur++ = sizeof(struct i82593_conf_block);
+ memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
+ znet->tx_cur += sizeof(struct i82593_conf_block)/2;
+@@ -359,7 +359,7 @@ static void znet_set_multicast_list (str
+ /* XXX FIXME maz : Add multicast addresses here, so having a
+ * multicast address configured isn't equal to IFF_ALLMULTI */
+ }
+-
++
+ /* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe
+ BIOS area. We just scan for the signature, and pull the vital parameters
+ out of the structure. */
+@@ -438,7 +438,7 @@ static int __init znet_probe (void)
+ printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
+ goto free_tx;
+ }
+-
++
+ znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
+ znet->tx_buf_len = TX_BUF_SIZE/2;
+ znet->tx_end = znet->tx_start + znet->tx_buf_len;
+@@ -466,7 +466,7 @@ static int __init znet_probe (void)
+ return err;
+ }
+
+-
++
+ static int znet_open(struct net_device *dev)
+ {
+ int ioaddr = dev->base_addr;
+@@ -481,7 +481,7 @@ static int znet_open(struct net_device *
+ }
+
+ znet_transceiver_power (dev, 1);
+-
++
+ /* According to the Crynwr driver we should wait 50 msec. for the
+ LAN clock to stabilize. My experiments indicates that the '593 can
+ be initialized immediately. The delay is probably needed for the
+@@ -496,7 +496,7 @@ static int znet_open(struct net_device *
+ * all, even if the message is completly harmless on my
+ * setup. */
+ mdelay (50);
+-
++
+ /* This follows the packet driver's lead, and checks for success. */
+ if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
+ printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
+@@ -547,9 +547,9 @@ static int znet_send_packet(struct sk_bu
+ return 0;
+ length = ETH_ZLEN;
+ }
+-
++
+ netif_stop_queue (dev);
+-
++
+ /* Check that the part hasn't reset itself, probably from suspend. */
+ outb(CR0_STATUS_0, ioaddr);
+ if (inw(ioaddr) == 0x0010 &&
+@@ -565,7 +565,7 @@ static int znet_send_packet(struct sk_bu
+ unsigned char *buf = (void *)skb->data;
+ ushort *tx_link = znet->tx_cur - 1;
+ ushort rnd_len = (length + 1)>>1;
+-
++
+ znet->stats.tx_bytes+=length;
+
+ if (znet->tx_cur >= znet->tx_end)
+@@ -597,12 +597,12 @@ static int znet_send_packet(struct sk_bu
+ if (znet_debug > 4)
+ printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
+ }
+- dev_kfree_skb(skb);
++ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ /* The ZNET interrupt handler. */
+-static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t znet_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = dev_id;
+ struct znet_private *znet = dev->priv;
+@@ -610,13 +610,8 @@ static irqreturn_t znet_interrupt(int ir
+ int boguscnt = 20;
+ int handled = 0;
+
+- if (dev == NULL) {
+- printk(KERN_WARNING "znet_interrupt(): IRQ %d for unknown device.\n", irq);
+- return IRQ_NONE;
+- }
+-
+ spin_lock (&znet->lock);
+-
++
+ ioaddr = dev->base_addr;
+
+ outb(CR0_STATUS_0, ioaddr);
+@@ -666,7 +661,7 @@ static irqreturn_t znet_interrupt(int ir
+ * packet. Flip it off, then on to
+ * reset it. This is very empirical,
+ * but it seems to work. */
+-
++
+ znet_transceiver_power (dev, 0);
+ znet_transceiver_power (dev, 1);
+ }
+@@ -682,7 +677,7 @@ static irqreturn_t znet_interrupt(int ir
+ } while (boguscnt--);
+
+ spin_unlock (&znet->lock);
+-
++
+ return IRQ_RETVAL(handled);
+ }
+
+@@ -748,7 +743,7 @@ static void znet_rx(struct net_device *d
+ ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
+ int status = this_rfp_ptr[-4];
+ int pkt_len = this_rfp_ptr[-2];
+-
++
+ if (znet_debug > 5)
+ printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
+ " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
+@@ -829,9 +824,9 @@ static int znet_close(struct net_device
+ printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+ /* Turn off transceiver power. */
+ znet_transceiver_power (dev, 0);
+-
++
+ znet_release_resources (dev);
+-
++
+ return 0;
+ }
+
+@@ -856,7 +851,7 @@ static void show_dma(struct net_device *
+
+ addr |= inb(dma_port) << 8;
+ residue = get_dma_residue(znet->tx_dma);
+-
++
+ if (znet_debug > 1) {
+ flags=claim_dma_lock();
+ printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
+@@ -894,7 +889,7 @@ static void hardware_init(struct net_dev
+ set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
+ enable_dma(znet->tx_dma);
+ release_dma_lock(flags);
+-
++
+ if (znet_debug > 1)
+ printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
+ dev->name, znet->rx_start,znet->tx_start);
+diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
+index 71c2da2..5756401 100644
+--- a/drivers/oprofile/oprofilefs.c
++++ b/drivers/oprofile/oprofilefs.c
+@@ -31,7 +31,6 @@ static struct inode * oprofilefs_get_ino
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ }
+@@ -110,8 +109,8 @@ static ssize_t ulong_write_file(struct f
+
+ static int default_open(struct inode * inode, struct file * filp)
+ {
+- if (inode->u.generic_ip)
+- filp->private_data = inode->u.generic_ip;
++ if (inode->i_private)
++ filp->private_data = inode->i_private;
+ return 0;
+ }
+
+@@ -158,7 +157,7 @@ int oprofilefs_create_ulong(struct super
+ if (!d)
+ return -EFAULT;
+
+- d->d_inode->u.generic_ip = val;
++ d->d_inode->i_private = val;
+ return 0;
+ }
+
+@@ -171,7 +170,7 @@ int oprofilefs_create_ro_ulong(struct su
+ if (!d)
+ return -EFAULT;
+
+- d->d_inode->u.generic_ip = val;
++ d->d_inode->i_private = val;
+ return 0;
+ }
+
+@@ -197,7 +196,7 @@ int oprofilefs_create_ro_atomic(struct s
+ if (!d)
+ return -EFAULT;
+
+- d->d_inode->u.generic_ip = val;
++ d->d_inode->i_private = val;
+ return 0;
+ }
+
+diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
+index 0d96c50..03c763c 100644
+--- a/drivers/parisc/dino.c
++++ b/drivers/parisc/dino.c
+@@ -368,8 +368,7 @@ static struct hw_interrupt_type dino_int
+ * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from
+ * wedging the CPU. Could be removed or made optional at some point.
+ */
+-static irqreturn_t
+-dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
++static irqreturn_t dino_isr(int irq, void *intr_dev)
+ {
+ struct dino_device *dino_dev = intr_dev;
+ u32 mask;
+@@ -390,7 +389,7 @@ ilr_again:
+ int irq = dino_dev->global_irq[local_irq];
+ DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
+ __FUNCTION__, irq, intr_dev, mask);
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+ mask &= ~(1 << local_irq);
+ } while (mask);
+
+diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
+index 884965c..e97cecb 100644
+--- a/drivers/parisc/eisa.c
++++ b/drivers/parisc/eisa.c
+@@ -199,7 +199,7 @@ static struct hw_interrupt_type eisa_int
+ .end = no_end_irq,
+ };
+
+-static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs)
++static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
+ {
+ int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */
+ unsigned long flags;
+@@ -234,7 +234,7 @@ static irqreturn_t eisa_irq(int wax_irq,
+ }
+ spin_unlock_irqrestore(&eisa_irq_lock, flags);
+
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+
+ spin_lock_irqsave(&eisa_irq_lock, flags);
+ /* unmask */
+@@ -249,7 +249,7 @@ static irqreturn_t eisa_irq(int wax_irq,
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t dummy_irq2_handler(int _, void *dev, struct pt_regs *regs)
++static irqreturn_t dummy_irq2_handler(int _, void *dev)
+ {
+ printk(KERN_ALERT "eisa: uhh, irq2?\n");
+ return IRQ_HANDLED;
+diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
+index b45aa5c..1b3e3fd 100644
+--- a/drivers/parisc/gsc.c
++++ b/drivers/parisc/gsc.c
+@@ -73,7 +73,7 @@ EXPORT_SYMBOL(gsc_alloc_irq);
+ EXPORT_SYMBOL(gsc_claim_irq);
+
+ /* Common interrupt demultiplexer used by Asp, Lasi & Wax. */
+-irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev, struct pt_regs *regs)
++irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev)
+ {
+ unsigned long irr;
+ struct gsc_asic *gsc_asic = dev;
+@@ -87,7 +87,7 @@ irqreturn_t gsc_asic_intr(int gsc_asic_i
+ do {
+ int local_irq = __ffs(irr);
+ unsigned int irq = gsc_asic->global_irq[local_irq];
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
+ irr &= ~(1 << local_irq);
+ } while (irr);
+
+diff --git a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h
+index a3dc456..762a1ba 100644
+--- a/drivers/parisc/gsc.h
++++ b/drivers/parisc/gsc.h
+@@ -44,4 +44,4 @@ void gsc_fixup_irqs(struct parisc_device
+ void (*choose)(struct parisc_device *child, void *ctrl));
+ void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp);
+
+-irqreturn_t gsc_asic_intr(int irq, void *dev, struct pt_regs *regs);
++irqreturn_t gsc_asic_intr(int irq, void *dev);
+diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
+index 1fbda77..c2949b4 100644
+--- a/drivers/parisc/iosapic.c
++++ b/drivers/parisc/iosapic.c
+@@ -146,7 +146,7 @@
+ #include <asm/superio.h>
+ #endif
+
+-#include <asm/iosapic.h>
++#include <asm/ropes.h>
+ #include "./iosapic_private.h"
+
+ #define MODULE_NAME "iosapic"
+@@ -692,6 +692,7 @@ static void iosapic_end_irq(unsigned int
+ DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
+ vi->eoi_addr, vi->eoi_data);
+ iosapic_eoi(vi->eoi_addr, vi->eoi_data);
++ cpu_end_irq(irq);
+ }
+
+ static unsigned int iosapic_startup_irq(unsigned int irq)
+@@ -728,7 +729,7 @@ static struct hw_interrupt_type iosapic_
+ .shutdown = iosapic_disable_irq,
+ .enable = iosapic_enable_irq,
+ .disable = iosapic_disable_irq,
+- .ack = no_ack_irq,
++ .ack = cpu_ack_irq,
+ .end = iosapic_end_irq,
+ #ifdef CONFIG_SMP
+ .set_affinity = iosapic_set_affinity_irq,
+diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
+index 3fe4a77..ba67699 100644
+--- a/drivers/parisc/lba_pci.c
++++ b/drivers/parisc/lba_pci.c
+@@ -46,9 +46,9 @@
+ #include <asm/page.h>
+ #include <asm/system.h>
+
++#include <asm/ropes.h>
+ #include <asm/hardware.h> /* for register_parisc_driver() stuff */
+ #include <asm/parisc-device.h>
+-#include <asm/iosapic.h> /* for iosapic_register() */
+ #include <asm/io.h> /* read/write stuff */
+
+ #undef DEBUG_LBA /* general stuff */
+@@ -100,113 +100,10 @@
+
+ #define MODULE_NAME "LBA"
+
+-#define LBA_FUNC_ID 0x0000 /* function id */
+-#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+-#define LBA_CAPABLE 0x0030 /* capabilities register */
+-
+-#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
+-#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
+-
+-#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
+-#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
+-#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
+-
+-#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
+-#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
+-#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
+-#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
+-
+-#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
+-
+-#define LBA_STAT_CTL 0x0108 /* Status & Control */
+-#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
+-#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
+-#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
+-#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
+-
+-#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
+-#define LBA_LMMIO_MASK 0x0208
+-
+-#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
+-#define LBA_GMMIO_MASK 0x0218
+-
+-#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
+-#define LBA_WLMMIO_MASK 0x0228
+-
+-#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
+-#define LBA_WGMMIO_MASK 0x0238
+-
+-#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
+-#define LBA_IOS_MASK 0x0248
+-
+-#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
+-#define LBA_ELMMIO_MASK 0x0258
+-
+-#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
+-#define LBA_EIOS_MASK 0x0268
+-
+-#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
+-#define LBA_DMA_CTL 0x0278 /* firmware sets this */
+-
+-#define LBA_IBASE 0x0300 /* SBA DMA support */
+-#define LBA_IMASK 0x0308
+-
+-/* FIXME: ignore DMA Hint stuff until we can measure performance */
+-#define LBA_HINT_CFG 0x0310
+-#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
+-
+-#define LBA_BUS_MODE 0x0620
+-
+-/* ERROR regs are needed for config cycle kluges */
+-#define LBA_ERROR_CONFIG 0x0680
+-#define LBA_SMART_MODE 0x20
+-#define LBA_ERROR_STATUS 0x0688
+-#define LBA_ROPE_CTL 0x06A0
+-
+-#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
+-
+ /* non-postable I/O port space, densely packed */
+ #define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL)
+ static void __iomem *astro_iop_base __read_mostly;
+
+-#define ELROY_HVERS 0x782
+-#define MERCURY_HVERS 0x783
+-#define QUICKSILVER_HVERS 0x784
+-
+-static inline int IS_ELROY(struct parisc_device *d)
+-{
+- return (d->id.hversion == ELROY_HVERS);
+-}
+-
+-static inline int IS_MERCURY(struct parisc_device *d)
+-{
+- return (d->id.hversion == MERCURY_HVERS);
+-}
+-
+-static inline int IS_QUICKSILVER(struct parisc_device *d)
+-{
+- return (d->id.hversion == QUICKSILVER_HVERS);
+-}
+-
+-
+-/*
+-** lba_device: Per instance Elroy data structure
+-*/
+-struct lba_device {
+- struct pci_hba_data hba;
+-
+- spinlock_t lba_lock;
+- void *iosapic_obj;
+-
+-#ifdef CONFIG_64BIT
+- void __iomem * iop_base; /* PA_VIEW - for IO port accessor funcs */
+-#endif
+-
+- int flags; /* state/functionality enabled */
+- int hw_rev; /* HW revision of chip */
+-};
+-
+-
+ static u32 lba_t32;
+
+ /* lba flags */
+@@ -1542,8 +1439,8 @@ lba_driver_probe(struct parisc_device *d
+ default: version = "TR4+";
+ }
+
+- printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+- MODULE_NAME, version, func_class & 0xf, dev->hpa.start);
++ printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
++ version, func_class & 0xf, dev->hpa.start);
+
+ if (func_class < 2) {
+ printk(KERN_WARNING "Can't support LBA older than "
+@@ -1563,14 +1460,18 @@ lba_driver_probe(struct parisc_device *d
+ }
+
+ } else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
++ int major, minor;
++
+ func_class &= 0xff;
+- version = kmalloc(6, GFP_KERNEL);
+- snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf));
++ major = func_class >> 4, minor = func_class & 0xf;
++
+ /* We could use one printk for both Elroy and Mercury,
+ * but for the mask for func_class.
+ */
+- printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+- MODULE_NAME, version, func_class & 0xff, dev->hpa.start);
++ printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
++ IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
++ minor, func_class, dev->hpa.start);
++
+ cfg_ops = &mercury_cfg_ops;
+ } else {
+ printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
+@@ -1600,6 +1501,7 @@ lba_driver_probe(struct parisc_device *d
+ lba_dev->hba.dev = dev;
+ lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */
+ lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */
++ parisc_set_drvdata(dev, lba_dev);
+
+ /* ------------ Second : initialize common stuff ---------- */
+ pci_bios = &lba_bios_ops;
+diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
+index bf00fa2..8dac2ba 100644
+--- a/drivers/parisc/led.c
++++ b/drivers/parisc/led.c
+@@ -684,7 +684,7 @@ int __init led_init(void)
+ int ret;
+
+ snprintf(lcd_text_default, sizeof(lcd_text_default),
+- "Linux %s", system_utsname.release);
++ "Linux %s", init_utsname()->release);
+
+ /* Work around the buggy PDC of KittyHawk-machines */
+ switch (CPU_HVERSION) {
+diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
+index fad5a33..97e9dc0 100644
+--- a/drivers/parisc/power.c
++++ b/drivers/parisc/power.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/parisc/kernel/power.c
++ * linux/drivers/parisc/power.c
+ * HP PARISC soft power switch support driver
+ *
+ * Copyright (c) 2001-2005 Helge Deller <deller at gmx.de>
+@@ -84,8 +84,7 @@
+
+ static void deferred_poweroff(void *dummy)
+ {
+- extern int cad_pid; /* from kernel/sys.c */
+- if (kill_proc(cad_pid, SIGINT, 1)) {
++ if (kill_cad_pid(SIGINT, 1)) {
+ /* just in case killing init process failed */
+ machine_power_off();
+ }
+@@ -189,7 +188,7 @@ static void polling_tasklet_func(unsigne
+ * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2)
+ */
+ #if 0
+-static void powerfail_interrupt(int code, void *x, struct pt_regs *regs)
++static void powerfail_interrupt(int code, void *x)
+ {
+ printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");
+ poweroff();
+diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
+index 8b47328..f1e7ccd 100644
+--- a/drivers/parisc/sba_iommu.c
++++ b/drivers/parisc/sba_iommu.c
+@@ -38,22 +38,15 @@
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+
++#include <asm/ropes.h>
++#include <asm/mckinley.h> /* for proc_mckinley_root */
+ #include <asm/runway.h> /* for proc_runway_root */
+ #include <asm/pdc.h> /* for PDC_MODEL_* */
+ #include <asm/pdcpat.h> /* for is_pdc_pat() */
+ #include <asm/parisc-device.h>
+
+-
+-/* declared in arch/parisc/kernel/setup.c */
+-extern struct proc_dir_entry * proc_mckinley_root;
+-
+ #define MODULE_NAME "SBA"
+
+-#ifdef CONFIG_PROC_FS
+-/* depends on proc fs support. But costs CPU performance */
+-#undef SBA_COLLECT_STATS
+-#endif
+-
+ /*
+ ** The number of debug flags is a clue - this code is fragile.
+ ** Don't even think about messing with it unless you have
+@@ -92,202 +85,12 @@ extern struct proc_dir_entry * proc_mcki
+ #define DBG_RES(x...)
+ #endif
+
+-#if defined(CONFIG_64BIT)
+-/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
+-#define ZX1_SUPPORT
+-#endif
+-
+ #define SBA_INLINE __inline__
+
+-
+-/*
+-** The number of pdir entries to "free" before issueing
+-** a read to PCOM register to flush out PCOM writes.
+-** Interacts with allocation granularity (ie 4 or 8 entries
+-** allocated and free'd/purged at a time might make this
+-** less interesting).
+-*/
+-#define DELAYED_RESOURCE_CNT 16
+-
+ #define DEFAULT_DMA_HINT_REG 0
+
+-#define ASTRO_RUNWAY_PORT 0x582
+-#define IKE_MERCED_PORT 0x803
+-#define REO_MERCED_PORT 0x804
+-#define REOG_MERCED_PORT 0x805
+-#define PLUTO_MCKINLEY_PORT 0x880
+-
+-#define SBA_FUNC_ID 0x0000 /* function id */
+-#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+-
+-#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT)
+-#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT)
+-#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT)
+-
+-#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
+-
+-#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
+-#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
+-/* Ike's IOC's occupy functions 2 and 3 */
+-#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
+-
+-#define IOC_CTRL 0x8 /* IOC_CTRL offset */
+-#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
+-#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
+-#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
+-#define IOC_CTRL_RM (1 << 8) /* Real Mode */
+-#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
+-#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
+-#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
+-
+-#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
+-
+-#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
+-
+-
+-/*
+-** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
+-** Firmware programs this stuff. Don't touch it.
+-*/
+-#define LMMIO_DIRECT0_BASE 0x300
+-#define LMMIO_DIRECT0_MASK 0x308
+-#define LMMIO_DIRECT0_ROUTE 0x310
+-
+-#define LMMIO_DIST_BASE 0x360
+-#define LMMIO_DIST_MASK 0x368
+-#define LMMIO_DIST_ROUTE 0x370
+-
+-#define IOS_DIST_BASE 0x390
+-#define IOS_DIST_MASK 0x398
+-#define IOS_DIST_ROUTE 0x3A0
+-
+-#define IOS_DIRECT_BASE 0x3C0
+-#define IOS_DIRECT_MASK 0x3C8
+-#define IOS_DIRECT_ROUTE 0x3D0
+-
+-/*
+-** Offsets into I/O TLB (Function 2 and 3 on Ike)
+-*/
+-#define ROPE0_CTL 0x200 /* "regbus pci0" */
+-#define ROPE1_CTL 0x208
+-#define ROPE2_CTL 0x210
+-#define ROPE3_CTL 0x218
+-#define ROPE4_CTL 0x220
+-#define ROPE5_CTL 0x228
+-#define ROPE6_CTL 0x230
+-#define ROPE7_CTL 0x238
+-
+-#define IOC_ROPE0_CFG 0x500 /* pluto only */
+-#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
+-
+-
+-
+-#define HF_ENABLE 0x40
+-
+-
+-#define IOC_IBASE 0x300 /* IO TLB */
+-#define IOC_IMASK 0x308
+-#define IOC_PCOM 0x310
+-#define IOC_TCNFG 0x318
+-#define IOC_PDIR_BASE 0x320
+-
+-/* AGP GART driver looks for this */
+-#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
+-
+-
+-/*
+-** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+-** It's safer (avoid memory corruption) to keep DMA page mappings
+-** equivalently sized to VM PAGE_SIZE.
+-**
+-** We really can't avoid generating a new mapping for each
+-** page since the Virtual Coherence Index has to be generated
+-** and updated for each page.
+-**
+-** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
+-*/
+-#define IOVP_SIZE PAGE_SIZE
+-#define IOVP_SHIFT PAGE_SHIFT
+-#define IOVP_MASK PAGE_MASK
+-
+-#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
+-#define SBA_PERF_MASK1 0x718
+-#define SBA_PERF_MASK2 0x730
+-
+-
+-/*
+-** Offsets into PCI Performance Counters (functions 12 and 13)
+-** Controlled by PERF registers in function 2 & 3 respectively.
+-*/
+-#define SBA_PERF_CNT1 0x200
+-#define SBA_PERF_CNT2 0x208
+-#define SBA_PERF_CNT3 0x210
+-
+-
+-struct ioc {
+- void __iomem *ioc_hpa; /* I/O MMU base address */
+- char *res_map; /* resource map, bit == pdir entry */
+- u64 *pdir_base; /* physical base address */
+- unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
+- unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
+-#ifdef ZX1_SUPPORT
+- unsigned long iovp_mask; /* help convert IOVA to IOVP */
+-#endif
+- unsigned long *res_hint; /* next avail IOVP - circular search */
+- spinlock_t res_lock;
+- unsigned int res_bitshift; /* from the LEFT! */
+- unsigned int res_size; /* size of resource map in bytes */
+-#ifdef SBA_HINT_SUPPORT
+-/* FIXME : DMA HINTs not used */
+- unsigned long hint_mask_pdir; /* bits used for DMA hints */
+- unsigned int hint_shift_pdir;
+-#endif
+-#if DELAYED_RESOURCE_CNT > 0
+- int saved_cnt;
+- struct sba_dma_pair {
+- dma_addr_t iova;
+- size_t size;
+- } saved[DELAYED_RESOURCE_CNT];
+-#endif
+-
+-#ifdef SBA_COLLECT_STATS
+-#define SBA_SEARCH_SAMPLE 0x100
+- unsigned long avg_search[SBA_SEARCH_SAMPLE];
+- unsigned long avg_idx; /* current index into avg_search */
+- unsigned long used_pages;
+- unsigned long msingle_calls;
+- unsigned long msingle_pages;
+- unsigned long msg_calls;
+- unsigned long msg_pages;
+- unsigned long usingle_calls;
+- unsigned long usingle_pages;
+- unsigned long usg_calls;
+- unsigned long usg_pages;
+-#endif
+-
+- /* STUFF We don't need in performance path */
+- unsigned int pdir_size; /* in bytes, determined by IOV Space size */
+-};
+-
+-struct sba_device {
+- struct sba_device *next; /* list of SBA's in system */
+- struct parisc_device *dev; /* dev found in bus walk */
+- struct parisc_device_id *iodc; /* data about dev from firmware */
+- const char *name;
+- void __iomem *sba_hpa; /* base address */
+- spinlock_t sba_lock;
+- unsigned int flags; /* state/functionality enabled */
+- unsigned int hw_rev; /* HW revision of chip */
+-
+- struct resource chip_resv; /* MMIO reserved for chip */
+- struct resource iommu_resv; /* MMIO reserved for iommu */
+-
+- unsigned int num_ioc; /* number of on-board IOC's */
+- struct ioc ioc[MAX_IOC];
+-};
+-
+-
+-static struct sba_device *sba_list;
++struct sba_device *sba_list;
++EXPORT_SYMBOL_GPL(sba_list);
+
+ static unsigned long ioc_needs_fdc = 0;
+
+@@ -300,8 +103,14 @@ static unsigned long piranha_bad_128k =
+ /* Looks nice and keeps the compiler happy */
+ #define SBA_DEV(d) ((struct sba_device *) (d))
+
++#ifdef CONFIG_AGP_PARISC
++#define SBA_AGP_SUPPORT
++#endif /*CONFIG_AGP_PARISC*/
++
+ #ifdef SBA_AGP_SUPPORT
+-static int reserve_sba_gart = 1;
++static int sba_reserve_agpgart = 1;
++module_param(sba_reserve_agpgart, int, 1);
++MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
+ #endif
+
+ #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
+@@ -741,7 +550,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t
+ asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+ pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */
+
+- pa |= 0x8000000000000000ULL; /* set "valid" bit */
++ pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
+ *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
+
+ /*
+@@ -1498,6 +1307,10 @@ sba_ioc_init_pluto(struct parisc_device
+ WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
+
+ #ifdef SBA_AGP_SUPPORT
++{
++ struct klist_iter i;
++ struct device *dev = NULL;
++
+ /*
+ ** If an AGP device is present, only use half of the IOV space
+ ** for PCI DMA. Unfortunately we can't know ahead of time
+@@ -1506,20 +1319,22 @@ sba_ioc_init_pluto(struct parisc_device
+ ** We program the next pdir index after we stop w/ a key for
+ ** the GART code to handshake on.
+ */
+- device=NULL;
+- for (lba = sba->child; lba; lba = lba->sibling) {
++ klist_iter_init(&sba->dev.klist_children, &i);
++ while ((dev = next_device(&i))) {
++ struct parisc_device *lba = to_parisc_device(dev);
+ if (IS_QUICKSILVER(lba))
+- break;
++ agp_found = 1;
+ }
++ klist_iter_exit(&i);
+
+- if (lba) {
+- DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
++ if (agp_found && sba_reserve_agpgart) {
++ printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
++ __FUNCTION__, (iova_space_size/2) >> 20);
+ ioc->pdir_size /= 2;
+- ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
+- } else {
+- DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
++ ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
+ }
+-#endif /* 0 */
++}
++#endif /*SBA_AGP_SUPPORT*/
+
+ }
+
+@@ -1701,7 +1516,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ }
+ #endif
+
+- if (!IS_PLUTO(sba_dev->iodc)) {
++ if (!IS_PLUTO(sba_dev->dev)) {
+ ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
+ DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
+ __FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
+@@ -1718,9 +1533,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ #endif
+ } /* if !PLUTO */
+
+- if (IS_ASTRO(sba_dev->iodc)) {
++ if (IS_ASTRO(sba_dev->dev)) {
+ int err;
+- /* PAT_PDC (L-class) also reports the same goofy base */
+ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
+ num_ioc = 1;
+
+@@ -1730,13 +1544,9 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
+ BUG_ON(err < 0);
+
+- } else if (IS_PLUTO(sba_dev->iodc)) {
++ } else if (IS_PLUTO(sba_dev->dev)) {
+ int err;
+
+- /* We use a negative value for IOC HPA so it gets
+- * corrected when we add it with IKE's IOC offset.
+- * Doesnt look clean, but fewer code.
+- */
+ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
+ num_ioc = 1;
+
+@@ -1752,14 +1562,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
+ WARN_ON(err < 0);
+ } else {
+- /* IS_IKE (ie N-class, L3000, L1500) */
++ /* IKE, REO */
+ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
+ sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
+ num_ioc = 2;
+
+ /* TODO - LOOKUP Ike/Stretch chipset mem map */
+ }
+- /* XXX: What about Reo? */
++ /* XXX: What about Reo Grande? */
+
+ sba_dev->num_ioc = num_ioc;
+ for (i = 0; i < num_ioc; i++) {
+@@ -1774,7 +1584,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ * Overrides bit 1 in DMA Hint Sets.
+ * Improves netperf UDP_STREAM by ~10% for bcm5701.
+ */
+- if (IS_PLUTO(sba_dev->iodc)) {
++ if (IS_PLUTO(sba_dev->dev)) {
+ void __iomem *rope_cfg;
+ unsigned long cfg_val;
+
+@@ -1803,7 +1613,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
+ );
+
+- if (IS_PLUTO(sba_dev->iodc)) {
++ if (IS_PLUTO(sba_dev->dev)) {
+ sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
+ } else {
+ sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
+@@ -2067,7 +1877,7 @@ sba_driver_callback(struct parisc_device
+ /* Read HW Rev First */
+ func_class = READ_REG(sba_addr + SBA_FCLASS);
+
+- if (IS_ASTRO(&dev->id)) {
++ if (IS_ASTRO(dev)) {
+ unsigned long fclass;
+ static char astro_rev[]="Astro ?.?";
+
+@@ -2078,11 +1888,11 @@ sba_driver_callback(struct parisc_device
+ astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
+ version = astro_rev;
+
+- } else if (IS_IKE(&dev->id)) {
++ } else if (IS_IKE(dev)) {
+ static char ike_rev[] = "Ike rev ?";
+ ike_rev[8] = '0' + (char) (func_class & 0xff);
+ version = ike_rev;
+- } else if (IS_PLUTO(&dev->id)) {
++ } else if (IS_PLUTO(dev)) {
+ static char pluto_rev[]="Pluto ?.?";
+ pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4);
+ pluto_rev[8] = '0' + (char) (func_class & 0x0f);
+@@ -2097,7 +1907,7 @@ sba_driver_callback(struct parisc_device
+ global_ioc_cnt = count_parisc_driver(&sba_driver);
+
+ /* Astro and Pluto have one IOC per SBA */
+- if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id)))
++ if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))
+ global_ioc_cnt *= 2;
+ }
+
+@@ -2117,7 +1927,6 @@ sba_driver_callback(struct parisc_device
+
+ sba_dev->dev = dev;
+ sba_dev->hw_rev = func_class;
+- sba_dev->iodc = &dev->id;
+ sba_dev->name = dev->name;
+ sba_dev->sba_hpa = sba_addr;
+
+diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
+index 4ee26a6..1fd97f7 100644
+--- a/drivers/parisc/superio.c
++++ b/drivers/parisc/superio.c
+@@ -94,7 +94,7 @@ static struct superio_device sio_dev;
+ #define PFX SUPERIO ": "
+
+ static irqreturn_t
+-superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
++superio_interrupt(int parent_irq, void *devp)
+ {
+ u8 results;
+ u8 local_irq;
+@@ -138,7 +138,7 @@ superio_interrupt(int parent_irq, void *
+ }
+
+ /* Call the appropriate device's interrupt */
+- __do_IRQ(local_irq, regs);
++ __do_IRQ(local_irq);
+
+ /* set EOI - forces a new interrupt if a lower priority device
+ * still needs service.
+diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
+index fd41e28..ff9f344 100644
+--- a/drivers/parport/daisy.c
++++ b/drivers/parport/daisy.c
+@@ -30,7 +30,7 @@
+ #undef DEBUG
+
+ #ifdef DEBUG
+-#define DPRINTK(stuff...) printk (stuff)
++#define DPRINTK(stuff...) printk(stuff)
+ #else
+ #define DPRINTK(stuff...)
+ #endif
+@@ -46,16 +46,16 @@ static DEFINE_SPINLOCK(topology_lock);
+ static int numdevs = 0;
+
+ /* Forward-declaration of lower-level functions. */
+-static int mux_present (struct parport *port);
+-static int num_mux_ports (struct parport *port);
+-static int select_port (struct parport *port);
+-static int assign_addrs (struct parport *port);
++static int mux_present(struct parport *port);
++static int num_mux_ports(struct parport *port);
++static int select_port(struct parport *port);
++static int assign_addrs(struct parport *port);
+
+ /* Add a device to the discovered topology. */
+-static void add_dev (int devnum, struct parport *port, int daisy)
++static void add_dev(int devnum, struct parport *port, int daisy)
+ {
+ struct daisydev *newdev, **p;
+- newdev = kmalloc (sizeof (struct daisydev), GFP_KERNEL);
++ newdev = kmalloc(sizeof(struct daisydev), GFP_KERNEL);
+ if (newdev) {
+ newdev->port = port;
+ newdev->daisy = daisy;
+@@ -70,9 +70,9 @@ static void add_dev (int devnum, struct
+ }
+
+ /* Clone a parport (actually, make an alias). */
+-static struct parport *clone_parport (struct parport *real, int muxport)
++static struct parport *clone_parport(struct parport *real, int muxport)
+ {
+- struct parport *extra = parport_register_port (real->base,
++ struct parport *extra = parport_register_port(real->base,
+ real->irq,
+ real->dma,
+ real->ops);
+@@ -88,7 +88,7 @@ static struct parport *clone_parport (st
+
+ /* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains.
+ * Return value is number of devices actually detected. */
+-int parport_daisy_init (struct parport *port)
++int parport_daisy_init(struct parport *port)
+ {
+ int detected = 0;
+ char *deviceid;
+@@ -103,26 +103,26 @@ again:
+
+ /* If mux present on normal port, need to create new
+ * parports for each extra port. */
+- if (port->muxport < 0 && mux_present (port) &&
++ if (port->muxport < 0 && mux_present(port) &&
+ /* don't be fooled: a mux must have 2 or 4 ports. */
+- ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
++ ((num_ports = num_mux_ports(port)) == 2 || num_ports == 4)) {
+ /* Leave original as port zero. */
+ port->muxport = 0;
+- printk (KERN_INFO
++ printk(KERN_INFO
+ "%s: 1st (default) port of %d-way multiplexor\n",
+ port->name, num_ports);
+ for (i = 1; i < num_ports; i++) {
+ /* Clone the port. */
+- struct parport *extra = clone_parport (port, i);
++ struct parport *extra = clone_parport(port, i);
+ if (!extra) {
+- if (signal_pending (current))
++ if (signal_pending(current))
+ break;
+
+- schedule ();
++ schedule();
+ continue;
+ }
+
+- printk (KERN_INFO
++ printk(KERN_INFO
+ "%s: %d%s port of %d-way multiplexor on %s\n",
+ extra->name, i + 1, th[i + 1], num_ports,
+ port->name);
+@@ -135,34 +135,34 @@ again:
+ }
+
+ if (port->muxport >= 0)
+- select_port (port);
++ select_port(port);
+
+- parport_daisy_deselect_all (port);
+- detected += assign_addrs (port);
++ parport_daisy_deselect_all(port);
++ detected += assign_addrs(port);
+
+ /* Count the potential legacy device at the end. */
+- add_dev (numdevs++, port, -1);
++ add_dev(numdevs++, port, -1);
+
+ /* Find out the legacy device's IEEE 1284 device ID. */
+- deviceid = kmalloc (1024, GFP_KERNEL);
++ deviceid = kmalloc(1024, GFP_KERNEL);
+ if (deviceid) {
+- if (parport_device_id (numdevs - 1, deviceid, 1024) > 2)
++ if (parport_device_id(numdevs - 1, deviceid, 1024) > 2)
+ detected++;
+
+- kfree (deviceid);
++ kfree(deviceid);
+ }
+
+ if (!detected && !last_try) {
+ /* No devices were detected. Perhaps they are in some
+ funny state; let's try to reset them and see if
+ they wake up. */
+- parport_daisy_fini (port);
+- parport_write_control (port, PARPORT_CONTROL_SELECT);
+- udelay (50);
+- parport_write_control (port,
++ parport_daisy_fini(port);
++ parport_write_control(port, PARPORT_CONTROL_SELECT);
++ udelay(50);
++ parport_write_control(port,
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_INIT);
+- udelay (50);
++ udelay(50);
+ last_try = 1;
+ goto again;
+ }
+@@ -171,7 +171,7 @@ again:
+ }
+
+ /* Forget about devices on a physical port. */
+-void parport_daisy_fini (struct parport *port)
++void parport_daisy_fini(struct parport *port)
+ {
+ struct daisydev **p;
+
+@@ -214,9 +214,9 @@ void parport_daisy_fini (struct parport
+ * for parport_register_device().
+ **/
+
+-struct pardevice *parport_open (int devnum, const char *name,
++struct pardevice *parport_open(int devnum, const char *name,
+ int (*pf) (void *), void (*kf) (void *),
+- void (*irqf) (int, void *, struct pt_regs *),
++ void (*irqf) (int, void *),
+ int flags, void *handle)
+ {
+ struct daisydev *p = topology;
+@@ -237,7 +237,7 @@ struct pardevice *parport_open (int devn
+ port = parport_get_port(p->port);
+ spin_unlock(&topology_lock);
+
+- dev = parport_register_device (port, name, pf, kf,
++ dev = parport_register_device(port, name, pf, kf,
+ irqf, flags, handle);
+ parport_put_port(port);
+ if (!dev)
+@@ -248,13 +248,13 @@ struct pardevice *parport_open (int devn
+ /* Check that there really is a device to select. */
+ if (daisy >= 0) {
+ int selected;
+- parport_claim_or_block (dev);
++ parport_claim_or_block(dev);
+ selected = port->daisy;
+- parport_release (dev);
++ parport_release(dev);
+
+ if (selected != daisy) {
+ /* No corresponding device. */
+- parport_unregister_device (dev);
++ parport_unregister_device(dev);
+ return NULL;
+ }
+ }
+@@ -270,9 +270,9 @@ struct pardevice *parport_open (int devn
+ * parport_register_device().
+ **/
+
+-void parport_close (struct pardevice *dev)
++void parport_close(struct pardevice *dev)
+ {
+- parport_unregister_device (dev);
++ parport_unregister_device(dev);
+ }
+
+ /**
+@@ -287,7 +287,7 @@ void parport_close (struct pardevice *de
+ * exists.
+ **/
+
+-int parport_device_num (int parport, int mux, int daisy)
++int parport_device_num(int parport, int mux, int daisy)
+ {
+ int res = -ENXIO;
+ struct daisydev *dev;
+@@ -305,16 +305,16 @@ int parport_device_num (int parport, int
+ }
+
+ /* Send a daisy-chain-style CPP command packet. */
+-static int cpp_daisy (struct parport *port, int cmd)
++static int cpp_daisy(struct parport *port, int cmd)
+ {
+ unsigned char s;
+
+- parport_data_forward (port);
+- parport_write_data (port, 0xaa); udelay (2);
+- parport_write_data (port, 0x55); udelay (2);
+- parport_write_data (port, 0x00); udelay (2);
+- parport_write_data (port, 0xff); udelay (2);
+- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
++ parport_data_forward(port);
++ parport_write_data(port, 0xaa); udelay(2);
++ parport_write_data(port, 0x55); udelay(2);
++ parport_write_data(port, 0x00); udelay(2);
++ parport_write_data(port, 0xff); udelay(2);
++ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+@@ -322,54 +322,54 @@ static int cpp_daisy (struct parport *po
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR)) {
+- DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
++ DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+- parport_write_data (port, 0x87); udelay (2);
+- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
++ parport_write_data(port, 0x87); udelay(2);
++ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+- DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
++ DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+- parport_write_data (port, 0x78); udelay (2);
+- parport_write_data (port, cmd); udelay (2);
+- parport_frob_control (port,
++ parport_write_data(port, 0x78); udelay(2);
++ parport_write_data(port, cmd); udelay(2);
++ parport_frob_control(port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+- udelay (1);
+- s = parport_read_status (port);
+- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+- udelay (1);
+- parport_write_data (port, 0xff); udelay (2);
++ udelay(1);
++ s = parport_read_status(port);
++ parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
++ udelay(1);
++ parport_write_data(port, 0xff); udelay(2);
+
+ return s;
+ }
+
+ /* Send a mux-style CPP command packet. */
+-static int cpp_mux (struct parport *port, int cmd)
++static int cpp_mux(struct parport *port, int cmd)
+ {
+ unsigned char s;
+ int rc;
+
+- parport_data_forward (port);
+- parport_write_data (port, 0xaa); udelay (2);
+- parport_write_data (port, 0x55); udelay (2);
+- parport_write_data (port, 0xf0); udelay (2);
+- parport_write_data (port, 0x0f); udelay (2);
+- parport_write_data (port, 0x52); udelay (2);
+- parport_write_data (port, 0xad); udelay (2);
+- parport_write_data (port, cmd); udelay (2);
++ parport_data_forward(port);
++ parport_write_data(port, 0xaa); udelay(2);
++ parport_write_data(port, 0x55); udelay(2);
++ parport_write_data(port, 0xf0); udelay(2);
++ parport_write_data(port, 0x0f); udelay(2);
++ parport_write_data(port, 0x52); udelay(2);
++ parport_write_data(port, 0xad); udelay(2);
++ parport_write_data(port, cmd); udelay(2);
+
+- s = parport_read_status (port);
++ s = parport_read_status(port);
+ if (!(s & PARPORT_STATUS_ACK)) {
+- DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
++ DPRINTK(KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+ port->name, cmd, s);
+ return -EIO;
+ }
+@@ -382,12 +382,12 @@ static int cpp_mux (struct parport *port
+ return rc;
+ }
+
+-void parport_daisy_deselect_all (struct parport *port)
++void parport_daisy_deselect_all(struct parport *port)
+ {
+- cpp_daisy (port, 0x30);
++ cpp_daisy(port, 0x30);
+ }
+
+-int parport_daisy_select (struct parport *port, int daisy, int mode)
++int parport_daisy_select(struct parport *port, int daisy, int mode)
+ {
+ switch (mode)
+ {
+@@ -395,14 +395,14 @@ int parport_daisy_select (struct parport
+ case IEEE1284_MODE_EPP:
+ case IEEE1284_MODE_EPPSL:
+ case IEEE1284_MODE_EPPSWE:
+- return !(cpp_daisy (port, 0x20 + daisy) &
++ return !(cpp_daisy(port, 0x20 + daisy) &
+ PARPORT_STATUS_ERROR);
+
+ // For these modes we should switch to ECP mode:
+ case IEEE1284_MODE_ECP:
+ case IEEE1284_MODE_ECPRLE:
+ case IEEE1284_MODE_ECPSWE:
+- return !(cpp_daisy (port, 0xd0 + daisy) &
++ return !(cpp_daisy(port, 0xd0 + daisy) &
+ PARPORT_STATUS_ERROR);
+
+ // Nothing was told for BECP in Daisy chain specification.
+@@ -413,28 +413,28 @@ int parport_daisy_select (struct parport
+ case IEEE1284_MODE_BYTE:
+ case IEEE1284_MODE_COMPAT:
+ default:
+- return !(cpp_daisy (port, 0xe0 + daisy) &
++ return !(cpp_daisy(port, 0xe0 + daisy) &
+ PARPORT_STATUS_ERROR);
+ }
+ }
+
+-static int mux_present (struct parport *port)
++static int mux_present(struct parport *port)
+ {
+- return cpp_mux (port, 0x51) == 3;
++ return cpp_mux(port, 0x51) == 3;
+ }
+
+-static int num_mux_ports (struct parport *port)
++static int num_mux_ports(struct parport *port)
+ {
+- return cpp_mux (port, 0x58);
++ return cpp_mux(port, 0x58);
+ }
+
+-static int select_port (struct parport *port)
++static int select_port(struct parport *port)
+ {
+ int muxport = port->muxport;
+- return cpp_mux (port, 0x60 + muxport) == muxport;
++ return cpp_mux(port, 0x60 + muxport) == muxport;
+ }
+
+-static int assign_addrs (struct parport *port)
++static int assign_addrs(struct parport *port)
+ {
+ unsigned char s;
+ unsigned char daisy;
+@@ -442,12 +442,12 @@ static int assign_addrs (struct parport
+ int detected;
+ char *deviceid;
+
+- parport_data_forward (port);
+- parport_write_data (port, 0xaa); udelay (2);
+- parport_write_data (port, 0x55); udelay (2);
+- parport_write_data (port, 0x00); udelay (2);
+- parport_write_data (port, 0xff); udelay (2);
+- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
++ parport_data_forward(port);
++ parport_write_data(port, 0xaa); udelay(2);
++ parport_write_data(port, 0x55); udelay(2);
++ parport_write_data(port, 0x00); udelay(2);
++ parport_write_data(port, 0xff); udelay(2);
++ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+@@ -455,40 +455,40 @@ static int assign_addrs (struct parport
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR)) {
+- DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
++ DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+ port->name, s);
+ return 0;
+ }
+
+- parport_write_data (port, 0x87); udelay (2);
+- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
++ parport_write_data(port, 0x87); udelay(2);
++ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+- DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
++ DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+ port->name, s);
+ return 0;
+ }
+
+- parport_write_data (port, 0x78); udelay (2);
+- s = parport_read_status (port);
++ parport_write_data(port, 0x78); udelay(2);
++ s = parport_read_status(port);
+
+ for (daisy = 0;
+ (s & (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT))
+ == (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT)
+ && daisy < 4;
+ ++daisy) {
+- parport_write_data (port, daisy);
+- udelay (2);
+- parport_frob_control (port,
++ parport_write_data(port, daisy);
++ udelay(2);
++ parport_frob_control(port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+- udelay (1);
+- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+- udelay (1);
++ udelay(1);
++ parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
++ udelay(1);
+
+- add_dev (numdevs++, port, daisy);
++ add_dev(numdevs++, port, daisy);
+
+ /* See if this device thought it was the last in the
+ * chain. */
+@@ -499,21 +499,21 @@ static int assign_addrs (struct parport
+ last_dev from next device or if last_dev does not
+ work status lines from some non-daisy chain
+ device. */
+- s = parport_read_status (port);
++ s = parport_read_status(port);
+ }
+
+- parport_write_data (port, 0xff); udelay (2);
++ parport_write_data(port, 0xff); udelay(2);
+ detected = numdevs - thisdev;
+- DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
++ DPRINTK(KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+ detected);
+
+ /* Ask the new devices to introduce themselves. */
+- deviceid = kmalloc (1024, GFP_KERNEL);
++ deviceid = kmalloc(1024, GFP_KERNEL);
+ if (!deviceid) return 0;
+
+ for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
+- parport_device_id (thisdev, deviceid, 1024);
++ parport_device_id(thisdev, deviceid, 1024);
+
+- kfree (deviceid);
++ kfree(deviceid);
+ return detected;
+ }
+diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
+index 7ff09f0..5accaa7 100644
+--- a/drivers/parport/ieee1284.c
++++ b/drivers/parport/ieee1284.c
+@@ -571,7 +571,7 @@ static int parport_ieee1284_ack_data_ava
+ #endif /* IEEE1284 support */
+
+ /* Handle an interrupt. */
+-void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
++void parport_ieee1284_interrupt (int which, void *handle)
+ {
+ struct parport *port = handle;
+ parport_ieee1284_wakeup (port);
+diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
+index 5126e74..a0afaee 100644
+--- a/drivers/parport/parport_amiga.c
++++ b/drivers/parport/parport_amiga.c
+@@ -138,9 +138,9 @@ static unsigned char amiga_read_status(s
+ }
+
+ /* as this ports irq handling is already done, we use a generic funktion */
+-static irqreturn_t amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t amiga_interrupt(int irq, void *dev_id)
+ {
+- parport_generic_irq(irq, (struct parport *) dev_id, regs);
++ parport_generic_irq(irq, (struct parport *) dev_id);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
+index 78c3f34..6ea9929 100644
+--- a/drivers/parport/parport_atari.c
++++ b/drivers/parport/parport_atari.c
+@@ -104,9 +104,9 @@ parport_atari_restore_state(struct parpo
+ }
+
+ static irqreturn_t
+-parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++parport_atari_interrupt(int irq, void *dev_id)
+ {
+- parport_generic_irq(irq, (struct parport *) dev_id, regs);
++ parport_generic_irq(irq, (struct parport *) dev_id);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
+index 1850632..74f4e97 100644
+--- a/drivers/parport/parport_ax88796.c
++++ b/drivers/parport/parport_ax88796.c
+@@ -233,9 +233,9 @@ parport_ax88796_restore_state(struct par
+ }
+
+ static irqreturn_t
+-parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++parport_ax88796_interrupt(int irq, void *dev_id)
+ {
+- parport_generic_irq(irq, dev_id, regs);
++ parport_generic_irq(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
+index 7352104..a7c5ead 100644
+--- a/drivers/parport/parport_gsc.c
++++ b/drivers/parport/parport_gsc.c
+@@ -81,9 +81,9 @@ static int clear_epp_timeout(struct parp
+ * of these are in parport_gsc.h.
+ */
+
+-static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id)
+ {
+- parport_generic_irq(irq, (struct parport *) dev_id, regs);
++ parport_generic_irq(irq, (struct parport *) dev_id);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
+index 46e06e5..e3e1927 100644
+--- a/drivers/parport/parport_ip32.c
++++ b/drivers/parport/parport_ip32.c
+@@ -548,10 +548,8 @@ static void parport_ip32_dma_setup_conte
+ * parport_ip32_dma_interrupt - DMA interrupt handler
+ * @irq: interrupt number
+ * @dev_id: unused
+- * @regs: pointer to &struct pt_regs
+ */
+-static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id)
+ {
+ if (parport_ip32_dma.left)
+ pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx);
+@@ -560,8 +558,7 @@ static irqreturn_t parport_ip32_dma_inte
+ }
+
+ #if DEBUG_PARPORT_IP32
+-static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id)
+ {
+ pr_trace1(NULL, "(%d)", irq);
+ return IRQ_HANDLED;
+@@ -772,13 +769,11 @@ static inline void parport_ip32_wakeup(s
+ * parport_ip32_interrupt - interrupt handler
+ * @irq: interrupt number
+ * @dev_id: pointer to &struct parport
+- * @regs: pointer to &struct pt_regs
+ *
+ * Caught interrupts are forwarded to the upper parport layer if IRQ_mode is
+ * %PARPORT_IP32_IRQ_FWD.
+ */
+-static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id)
+ {
+ struct parport * const p = dev_id;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
+index b2b8092..e5b0a54 100644
+--- a/drivers/parport/parport_mfc3.c
++++ b/drivers/parport/parport_mfc3.c
+@@ -211,7 +211,7 @@ static void mfc3_change_mode( struct par
+
+ static int use_cnt = 0;
+
+-static irqreturn_t mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
+ {
+ int i;
+
+@@ -219,7 +219,7 @@ static irqreturn_t mfc3_interrupt(int ir
+ if (this_port[i] != NULL)
+ if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+ dummy = pia(this_port[i])->pprb; /* clear irq bit */
+- parport_generic_irq(irq, this_port[i], regs);
++ parport_generic_irq(irq, this_port[i]);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
+index fe800dc..39c9664 100644
+--- a/drivers/parport/parport_pc.c
++++ b/drivers/parport/parport_pc.c
+@@ -270,9 +270,9 @@ static int clear_epp_timeout(struct parp
+ * of these are in parport_pc.h.
+ */
+
+-static irqreturn_t parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t parport_pc_interrupt(int irq, void *dev_id)
+ {
+- parport_generic_irq(irq, (struct parport *) dev_id, regs);
++ parport_generic_irq(irq, (struct parport *) dev_id);
+ /* FIXME! Was it really ours? */
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
+index 98b83a8..78c0a26 100644
+--- a/drivers/parport/parport_serial.c
++++ b/drivers/parport/parport_serial.c
+@@ -374,6 +374,7 @@ static void __devexit parport_serial_pci
+ return;
+ }
+
++#ifdef CONFIG_PM
+ static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state)
+ {
+ struct parport_serial_private *priv = pci_get_drvdata(dev);
+@@ -407,14 +408,17 @@ static int parport_serial_pci_resume(str
+
+ return 0;
+ }
++#endif
+
+ static struct pci_driver parport_serial_pci_driver = {
+ .name = "parport_serial",
+ .id_table = parport_serial_pci_tbl,
+ .probe = parport_serial_pci_probe,
+ .remove = __devexit_p(parport_serial_pci_remove),
++#ifdef CONFIG_PM
+ .suspend = parport_serial_pci_suspend,
+ .resume = parport_serial_pci_resume,
++#endif
+ };
+
+
+diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
+index fac333b..9793533 100644
+--- a/drivers/parport/parport_sunbpp.c
++++ b/drivers/parport/parport_sunbpp.c
+@@ -46,9 +46,9 @@
+ #define dprintk(x)
+ #endif
+
+-static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id)
+ {
+- parport_generic_irq(irq, (struct parport *) dev_id, regs);
++ parport_generic_irq(irq, (struct parport *) dev_id);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/parport/share.c b/drivers/parport/share.c
+index 94dc506..fd9129e 100644
+--- a/drivers/parport/share.c
++++ b/drivers/parport/share.c
+@@ -519,7 +519,7 @@ void parport_remove_port(struct parport
+ struct pardevice *
+ parport_register_device(struct parport *port, const char *name,
+ int (*pf)(void *), void (*kf)(void *),
+- void (*irq_func)(int, void *, struct pt_regs *),
++ void (*irq_func)(int, void *),
+ int flags, void *handle)
+ {
+ struct pardevice *tmp;
+diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
+index 4d762fc..5f1b9f5 100644
+--- a/drivers/pci/Kconfig
++++ b/drivers/pci/Kconfig
+@@ -17,6 +17,31 @@ config PCI_MSI
+
+ If you don't know what to do here, say N.
+
++config PCI_MULTITHREAD_PROBE
++ bool "PCI Multi-threaded probe (EXPERIMENTAL)"
++ depends on PCI && EXPERIMENTAL && BROKEN
++ help
++ Say Y here if you want the PCI core to spawn a new thread for
++ every PCI device that is probed. This can cause a huge
++ speedup in boot times on multiprocessor machines, and even a
++ smaller speedup on single processor machines.
++
++ But it can also cause lots of bad things to happen. A number
++ of PCI drivers can not properly handle running in this way,
++ some will just not work properly at all, while others might
++ decide to blow up power supplies with a huge load all at once,
++ so use this option at your own risk.
++
++ It is very unwise to use this option if you are not using a
++ boot process that can handle devices being created in any
++ order. A program that can create persistant block and network
++ device names (like udev) is a good idea if you wish to use
++ this option.
++
++ Again, use this option at your own risk, you have been warned!
++
++ When in doubt, say N.
++
+ config PCI_DEBUG
+ bool "PCI Debugging"
+ depends on PCI && DEBUG_KERNEL
+@@ -27,3 +52,11 @@ config PCI_DEBUG
+
+ When in doubt, say N.
+
++config HT_IRQ
++ bool "Interrupts on hypertransport devices"
++ default y
++ depends on PCI && X86_LOCAL_APIC && X86_IO_APIC
++ help
++ This allows native hypertransport devices to use interrupts.
++
++ If unsure say Y.
+diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
+index f2d152b..e3beb78 100644
+--- a/drivers/pci/Makefile
++++ b/drivers/pci/Makefile
+@@ -14,6 +14,12 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o
+ # Build the PCI Hotplug drivers if we were asked to
+ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
+
++# Build the PCI MSI interrupt support
++obj-$(CONFIG_PCI_MSI) += msi.o
++
++# Build the Hypertransport interrupt support
++obj-$(CONFIG_HT_IRQ) += htirq.o
++
+ #
+ # Some architectures use the generic PCI setup functions
+ #
+@@ -27,11 +33,6 @@ obj-$(CONFIG_PPC64) += setup-bus.o
+ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
+ obj-$(CONFIG_X86_VISWS) += setup-irq.o
+
+-msiobj-y := msi.o msi-apic.o
+-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
+-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+-obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
+-
+ #
+ # ACPI Related PCI FW Functions
+ #
+diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
+index 5f7db9d..aadaa3c 100644
+--- a/drivers/pci/bus.c
++++ b/drivers/pci/bus.c
+@@ -77,9 +77,12 @@ pci_bus_alloc_resource(struct pci_bus *b
+ * This adds a single pci device to the global
+ * device list and adds sysfs and procfs entries
+ */
+-void __devinit pci_bus_add_device(struct pci_dev *dev)
++int __devinit pci_bus_add_device(struct pci_dev *dev)
+ {
+- device_add(&dev->dev);
++ int retval;
++ retval = device_add(&dev->dev);
++ if (retval)
++ return retval;
+
+ down_write(&pci_bus_sem);
+ list_add_tail(&dev->global_list, &pci_devices);
+@@ -87,6 +90,7 @@ void __devinit pci_bus_add_device(struct
+
+ pci_proc_attach_device(dev);
+ pci_create_sysfs_dev_files(dev);
++ return 0;
+ }
+
+ /**
+@@ -104,6 +108,7 @@ void __devinit pci_bus_add_device(struct
+ void __devinit pci_bus_add_devices(struct pci_bus *bus)
+ {
+ struct pci_dev *dev;
++ int retval;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /*
+@@ -112,7 +117,9 @@ void __devinit pci_bus_add_devices(struc
+ */
+ if (!list_empty(&dev->global_list))
+ continue;
+- pci_bus_add_device(dev);
++ retval = pci_bus_add_device(dev);
++ if (retval)
++ dev_err(&dev->dev, "Error adding device, continuing\n");
+ }
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+@@ -129,10 +136,13 @@ void __devinit pci_bus_add_devices(struc
+ list_add_tail(&dev->subordinate->node,
+ &dev->bus->children);
+ up_write(&pci_bus_sem);
+- }
++ }
+ pci_bus_add_devices(dev->subordinate);
+-
+- sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
++ retval = sysfs_create_link(&dev->subordinate->class_dev.kobj,
++ &dev->dev.kobj, "bridge");
++ if (retval)
++ dev_err(&dev->dev, "Error creating sysfs "
++ "bridge symlink, continuing...\n");
+ }
+ }
+ }
+diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
+index 8a60f39..6e780db 100644
+--- a/drivers/pci/hotplug/Kconfig
++++ b/drivers/pci/hotplug/Kconfig
+@@ -157,7 +157,7 @@ config HOTPLUG_PCI_RPA
+ tristate "RPA PCI Hotplug driver"
+ depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
+ help
+- Say Y here if you have a a RPA system that supports PCI Hotplug.
++ Say Y here if you have a RPA system that supports PCI Hotplug.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rpaphp.
+diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c
+index 51cb9f8..270a33c 100644
+--- a/drivers/pci/hotplug/acpi_pcihp.c
++++ b/drivers/pci/hotplug/acpi_pcihp.c
+@@ -29,10 +29,10 @@
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <acpi/acpi.h>
+ #include <acpi/acpi_bus.h>
+ #include <acpi/actypes.h>
+-#include "pci_hotplug.h"
+
+ #define MY_NAME "acpi_pcihp"
+
+diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
+index be104ec..59c5b24 100644
+--- a/drivers/pci/hotplug/acpiphp.h
++++ b/drivers/pci/hotplug/acpiphp.h
+@@ -38,7 +38,7 @@
+ #include <linux/acpi.h>
+ #include <linux/kobject.h> /* for KOBJ_NAME_LEN */
+ #include <linux/mutex.h>
+-#include "pci_hotplug.h"
++#include <linux/pci_hotplug.h>
+
+ #define dbg(format, arg...) \
+ do { \
+@@ -150,6 +150,11 @@ struct acpiphp_attention_info
+ struct module *owner;
+ };
+
++struct acpiphp_ioapic {
++ struct pci_dev *dev;
++ u32 gsi_base;
++ struct list_head list;
++};
+
+ /* PCI bus bridge HID */
+ #define ACPI_PCI_HOST_HID "PNP0A03"
+diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
+index e2fef60..c57d9d5 100644
+--- a/drivers/pci/hotplug/acpiphp_core.c
++++ b/drivers/pci/hotplug/acpiphp_core.c
+@@ -37,10 +37,10 @@
+
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/slab.h>
+ #include <linux/smp.h>
+ #include <linux/smp_lock.h>
+-#include "pci_hotplug.h"
+ #include "acpiphp.h"
+
+ #define MY_NAME "acpiphp"
+diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
+index ae67a8f..16167b0 100644
+--- a/drivers/pci/hotplug/acpiphp_glue.c
++++ b/drivers/pci/hotplug/acpiphp_glue.c
+@@ -45,14 +45,16 @@
+
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/smp_lock.h>
+ #include <linux/mutex.h>
+
+ #include "../pci.h"
+-#include "pci_hotplug.h"
+ #include "acpiphp.h"
+
+ static LIST_HEAD(bridge_list);
++static LIST_HEAD(ioapic_list);
++static DEFINE_SPINLOCK(ioapic_list_lock);
+
+ #define MY_NAME "acpiphp_glue"
+
+@@ -797,6 +799,7 @@ ioapic_add(acpi_handle handle, u32 lvl,
+ struct pci_dev *pdev;
+ u32 gsi_base;
+ u64 phys_addr;
++ struct acpiphp_ioapic *ioapic;
+
+ /* Evaluate _STA if present */
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+@@ -811,41 +814,107 @@ ioapic_add(acpi_handle handle, u32 lvl,
+ if (get_gsi_base(handle, &gsi_base))
+ return AE_OK;
+
++ ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
++ if (!ioapic)
++ return AE_NO_MEMORY;
++
+ pdev = get_apic_pci_info(handle);
+ if (!pdev)
+- return AE_OK;
++ goto exit_kfree;
+
+- if (pci_enable_device(pdev)) {
+- pci_dev_put(pdev);
+- return AE_OK;
+- }
++ if (pci_enable_device(pdev))
++ goto exit_pci_dev_put;
+
+ 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;
+- }
++ if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
++ goto exit_pci_disable_device;
+
+ 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);
++ if (acpi_register_ioapic(handle, phys_addr, gsi_base))
++ goto exit_pci_release_region;
++
++ ioapic->gsi_base = gsi_base;
++ ioapic->dev = pdev;
++ spin_lock(&ioapic_list_lock);
++ list_add_tail(&ioapic->list, &ioapic_list);
++ spin_unlock(&ioapic_list_lock);
++
++ return AE_OK;
++
++ exit_pci_release_region:
++ pci_release_region(pdev, 0);
++ exit_pci_disable_device:
++ pci_disable_device(pdev);
++ exit_pci_dev_put:
++ pci_dev_put(pdev);
++ exit_kfree:
++ kfree(ioapic);
++
++ return AE_OK;
++}
++
++static acpi_status
++ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
++{
++ acpi_status status;
++ unsigned long sta;
++ acpi_handle tmp;
++ u32 gsi_base;
++ struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
++
++ /* 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;
++
++ acpi_unregister_ioapic(handle, gsi_base);
++
++ spin_lock(&ioapic_list_lock);
++ list_for_each_entry_safe(pos, n, &ioapic_list, list) {
++ if (pos->gsi_base != gsi_base)
++ continue;
++ ioapic = pos;
++ list_del(&ioapic->list);
++ break;
+ }
++ spin_unlock(&ioapic_list_lock);
++
++ if (!ioapic)
++ return AE_OK;
++
++ pci_release_region(ioapic->dev, 0);
++ pci_disable_device(ioapic->dev);
++ pci_dev_put(ioapic->dev);
++ kfree(ioapic);
+
+ return AE_OK;
+ }
+
+ static int acpiphp_configure_ioapics(acpi_handle handle)
+ {
++ ioapic_add(handle, 0, NULL, NULL);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
+ return 0;
+ }
+
++static int acpiphp_unconfigure_ioapics(acpi_handle handle)
++{
++ ioapic_remove(handle, 0, NULL, NULL);
++ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
++ ACPI_UINT32_MAX, ioapic_remove, NULL, NULL);
++ return 0;
++}
++
+ static int power_on_slot(struct acpiphp_slot *slot)
+ {
+ acpi_status status;
+@@ -997,7 +1066,7 @@ acpiphp_bus_add_out:
+ * @handle: handle to acpi namespace
+ *
+ */
+-int acpiphp_bus_trim(acpi_handle handle)
++static int acpiphp_bus_trim(acpi_handle handle)
+ {
+ struct acpi_device *device;
+ int retval;
+@@ -1074,10 +1143,11 @@ static int enable_device(struct acpiphp_
+
+ pci_bus_assign_resources(bus);
+ acpiphp_sanitize_bus(bus);
++ acpiphp_set_hpp_values(slot->bridge->handle, bus);
++ list_for_each_entry(func, &slot->funcs, sibling)
++ acpiphp_configure_ioapics(func->handle);
+ pci_enable_bridges(bus);
+ pci_bus_add_devices(bus);
+- acpiphp_set_hpp_values(slot->bridge->handle, bus);
+- acpiphp_configure_ioapics(slot->bridge->handle);
+
+ /* associate pci_dev to our representation */
+ list_for_each (l, &slot->funcs) {
+@@ -1103,6 +1173,16 @@ static int enable_device(struct acpiphp_
+ return retval;
+ }
+
++static void disable_bridges(struct pci_bus *bus)
++{
++ struct pci_dev *dev;
++ list_for_each_entry(dev, &bus->devices, bus_list) {
++ if (dev->subordinate) {
++ disable_bridges(dev->subordinate);
++ pci_disable_device(dev);
++ }
++ }
++}
+
+ /**
+ * disable_device - disable a slot
+@@ -1127,6 +1207,19 @@ static int disable_device(struct acpiphp
+ func->bridge = NULL;
+ }
+
++ if (func->pci_dev) {
++ pci_stop_bus_device(func->pci_dev);
++ if (func->pci_dev->subordinate) {
++ disable_bridges(func->pci_dev->subordinate);
++ pci_disable_device(func->pci_dev);
++ }
++ }
++ }
++
++ list_for_each (l, &slot->funcs) {
++ func = list_entry(l, struct acpiphp_func, sibling);
++
++ acpiphp_unconfigure_ioapics(func->handle);
+ acpiphp_bus_trim(func->handle);
+ /* try to remove anyway.
+ * acpiphp_bus_add might have been failed */
+@@ -1714,8 +1807,8 @@ u8 acpiphp_get_power_status(struct acpip
+
+
+ /*
+- * latch closed: 1
+- * latch open: 0
++ * latch open: 1
++ * latch closed: 0
+ */
+ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
+ {
+@@ -1723,7 +1816,7 @@ u8 acpiphp_get_latch_status(struct acpip
+
+ sta = get_slot_status(slot);
+
+- return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
++ return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1;
+ }
+
+
+diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
+index 317457d..bd40aee 100644
+--- a/drivers/pci/hotplug/acpiphp_ibm.c
++++ b/drivers/pci/hotplug/acpiphp_ibm.c
+@@ -35,7 +35,6 @@
+ #include <linux/moduleparam.h>
+
+ #include "acpiphp.h"
+-#include "pci_hotplug.h"
+
+ #define DRIVER_VERSION "1.0.1"
+ #define DRIVER_AUTHOR "Irene Zubarev <zubarev at us.ibm.com>, Vernon Mauery <vernux at us.ibm.com>"
+@@ -487,9 +486,7 @@ static void __exit ibm_acpiphp_exit(void
+ if (ACPI_FAILURE(status))
+ err("%s: Notification handler removal failed\n", __FUNCTION__);
+ /* remove the /sys entries */
+- if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr))
+- err("%s: removal of sysfs file apci_table failed\n",
+- __FUNCTION__);
++ sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr);
+ }
+
+ module_init(ibm_acpiphp_init);
+diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
+index d5df587..6845515 100644
+--- a/drivers/pci/hotplug/cpci_hotplug_core.c
++++ b/drivers/pci/hotplug/cpci_hotplug_core.c
+@@ -29,12 +29,12 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/smp_lock.h>
+ #include <asm/atomic.h>
+ #include <linux/delay.h>
+-#include "pci_hotplug.h"
+ #include "cpci_hotplug.h"
+
+ #define DRIVER_AUTHOR "Scott Murray <scottm at somanetworks.com>"
+@@ -342,7 +342,7 @@ cpci_hp_unregister_bus(struct pci_bus *b
+
+ /* This is the interrupt mode interrupt handler */
+ static irqreturn_t
+-cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
++cpci_hp_intr(int irq, void *data)
+ {
+ dbg("entered cpci_hp_intr");
+
+diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
+index 4afcaff..7b1beaa 100644
+--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
++++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
+@@ -26,9 +26,9 @@
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/proc_fs.h>
+ #include "../pci.h"
+-#include "pci_hotplug.h"
+ #include "cpci_hotplug.h"
+
+ #define MY_NAME "cpci_hotplug"
+diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
+index e847f0d..f3852a6 100644
+--- a/drivers/pci/hotplug/cpcihp_generic.c
++++ b/drivers/pci/hotplug/cpcihp_generic.c
+@@ -84,7 +84,7 @@ static int __init validate_parameters(vo
+
+ if(!bridge) {
+ info("not configured, disabling.");
+- return 1;
++ return -EINVAL;
+ }
+ str = bridge;
+ if(!*str)
+@@ -147,7 +147,7 @@ static int __init cpcihp_generic_init(vo
+
+ info(DRIVER_DESC " version: " DRIVER_VERSION);
+ status = validate_parameters();
+- if(status != 0)
++ if (status)
+ return status;
+
+ r = request_region(port, 1, "#ENUM hotswap signal register");
+diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
+index c74e9e3..298ad7f 100644
+--- a/drivers/pci/hotplug/cpqphp.h
++++ b/drivers/pci/hotplug/cpqphp.h
+@@ -28,7 +28,6 @@
+ #ifndef _CPQPHP_H
+ #define _CPQPHP_H
+
+-#include "pci_hotplug.h"
+ #include <linux/interrupt.h>
+ #include <asm/io.h> /* for read? and write? functions */
+ #include <linux/delay.h> /* for delays */
+@@ -409,7 +408,7 @@ extern void cpqhp_remove_debugfs_files
+
+ /* controller functions */
+ extern void cpqhp_pushbutton_thread (unsigned long event_pointer);
+-extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs);
++extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data);
+ extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start);
+ extern int cpqhp_event_start_thread (void);
+ extern void cpqhp_event_stop_thread (void);
+diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
+index 1fc2599..5617cfd 100644
+--- a/drivers/pci/hotplug/cpqphp_core.c
++++ b/drivers/pci/hotplug/cpqphp_core.c
+@@ -37,6 +37,7 @@
+ #include <linux/slab.h>
+ #include <linux/workqueue.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+
+diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
+index ae2dd36..79ff6b4 100644
+--- a/drivers/pci/hotplug/cpqphp_ctrl.c
++++ b/drivers/pci/hotplug/cpqphp_ctrl.c
+@@ -36,6 +36,7 @@
+ #include <linux/wait.h>
+ #include <linux/smp_lock.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include "cpqphp.h"
+
+ static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
+@@ -889,7 +890,7 @@ int cpqhp_resource_sort_and_combine(stru
+ }
+
+
+-irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
++irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
+ {
+ struct controller *ctrl = data;
+ u8 schedule_flag = 0;
+diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c
+index cf08789..298a6cf 100644
+--- a/drivers/pci/hotplug/cpqphp_nvram.c
++++ b/drivers/pci/hotplug/cpqphp_nvram.c
+@@ -33,6 +33,7 @@
+ #include <linux/slab.h>
+ #include <linux/workqueue.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/init.h>
+ #include <asm/uaccess.h>
+ #include "cpqphp.h"
+diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
+index 0d96889..fc7c74d 100644
+--- a/drivers/pci/hotplug/cpqphp_pci.c
++++ b/drivers/pci/hotplug/cpqphp_pci.c
+@@ -33,6 +33,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/proc_fs.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include "../pci.h"
+ #include "cpqphp.h"
+ #include "cpqphp_nvram.h"
+diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c
+index 8b3da00..634f74d 100644
+--- a/drivers/pci/hotplug/cpqphp_sysfs.c
++++ b/drivers/pci/hotplug/cpqphp_sysfs.c
+@@ -32,6 +32,7 @@
+ #include <linux/proc_fs.h>
+ #include <linux/workqueue.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/debugfs.h>
+ #include "cpqphp.h"
+
+@@ -140,7 +141,7 @@ struct ctrl_dbg {
+
+ static int open(struct inode *inode, struct file *file)
+ {
+- struct controller *ctrl = inode->u.generic_ip;
++ struct controller *ctrl = inode->i_private;
+ struct ctrl_dbg *dbg;
+ int retval = -ENOMEM;
+
+diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
+index dd2b762..e27907c 100644
+--- a/drivers/pci/hotplug/fakephp.c
++++ b/drivers/pci/hotplug/fakephp.c
+@@ -35,10 +35,10 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/init.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
+-#include "pci_hotplug.h"
+ #include "../pci.h"
+
+ #if !defined(MODULE)
+@@ -176,17 +176,25 @@ static void pci_rescan_slot(struct pci_d
+ struct pci_bus *bus = temp->bus;
+ struct pci_dev *dev;
+ int func;
++ int retval;
+ u8 hdr_type;
++
+ if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
+ temp->hdr_type = hdr_type & 0x7f;
+- if (!pci_find_slot(bus->number, temp->devfn)) {
++ if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
++ pci_dev_put(dev);
++ else {
+ dev = pci_scan_single_device(bus, temp->devfn);
+ if (dev) {
+ dbg("New device on %s function %x:%x\n",
+ bus->name, temp->devfn >> 3,
+ temp->devfn & 7);
+- pci_bus_add_device(dev);
+- add_slot(dev);
++ retval = pci_bus_add_device(dev);
++ if (retval)
++ dev_err(&dev->dev, "error adding "
++ "device, continuing.\n");
++ else
++ add_slot(dev);
+ }
+ }
+ /* multifunction device? */
+@@ -199,14 +207,20 @@ static void pci_rescan_slot(struct pci_d
+ continue;
+ temp->hdr_type = hdr_type & 0x7f;
+
+- if (!pci_find_slot(bus->number, temp->devfn)) {
++ if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
++ pci_dev_put(dev);
++ else {
+ dev = pci_scan_single_device(bus, temp->devfn);
+ if (dev) {
+ dbg("New device on %s function %x:%x\n",
+ bus->name, temp->devfn >> 3,
+ temp->devfn & 7);
+- pci_bus_add_device(dev);
+- add_slot(dev);
++ retval = pci_bus_add_device(dev);
++ if (retval)
++ dev_err(&dev->dev, "error adding "
++ "device, continuing.\n");
++ else
++ add_slot(dev);
+ }
+ }
+ }
+@@ -295,7 +309,7 @@ static int disable_slot(struct hotplug_s
+ /* search for subfunctions and disable them first */
+ if (!(dslot->dev->devfn & 7)) {
+ for (func = 1; func < 8; func++) {
+- dev = pci_find_slot(dslot->dev->bus->number,
++ dev = pci_get_slot(dslot->dev->bus,
+ dslot->dev->devfn + func);
+ if (dev) {
+ hslot = get_slot_from_dev(dev);
+@@ -305,6 +319,7 @@ static int disable_slot(struct hotplug_s
+ err("Hotplug slot not found for subfunction of PCI device\n");
+ return -ENODEV;
+ }
++ pci_dev_put(dev);
+ } else
+ dbg("No device in slot found\n");
+ }
+diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
+index dba6d8c..612d963 100644
+--- a/drivers/pci/hotplug/ibmphp.h
++++ b/drivers/pci/hotplug/ibmphp.h
+@@ -30,7 +30,7 @@
+ *
+ */
+
+-#include "pci_hotplug.h"
++#include <linux/pci_hotplug.h>
+
+ extern int ibmphp_debug;
+
+diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h
+deleted file mode 100644
+index e929b7c..0000000
+--- a/drivers/pci/hotplug/pci_hotplug.h
++++ /dev/null
+@@ -1,236 +0,0 @@
+-/*
+- * PCI HotPlug Core Functions
+- *
+- * Copyright (C) 1995,2001 Compaq Computer Corporation
+- * Copyright (C) 2001 Greg Kroah-Hartman (greg at kroah.com)
+- * Copyright (C) 2001 IBM Corp.
+- *
+- * All rights reserved.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or (at
+- * your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+- * NON INFRINGEMENT. See the GNU General Public License for more
+- * details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- * Send feedback to <greg at kroah.com>
+- *
+- */
+-#ifndef _PCI_HOTPLUG_H
+-#define _PCI_HOTPLUG_H
+-
+-
+-/* These values come from the PCI Hotplug Spec */
+-enum pci_bus_speed {
+- PCI_SPEED_33MHz = 0x00,
+- PCI_SPEED_66MHz = 0x01,
+- PCI_SPEED_66MHz_PCIX = 0x02,
+- PCI_SPEED_100MHz_PCIX = 0x03,
+- PCI_SPEED_133MHz_PCIX = 0x04,
+- PCI_SPEED_66MHz_PCIX_ECC = 0x05,
+- PCI_SPEED_100MHz_PCIX_ECC = 0x06,
+- PCI_SPEED_133MHz_PCIX_ECC = 0x07,
+- PCI_SPEED_66MHz_PCIX_266 = 0x09,
+- PCI_SPEED_100MHz_PCIX_266 = 0x0a,
+- PCI_SPEED_133MHz_PCIX_266 = 0x0b,
+- PCI_SPEED_66MHz_PCIX_533 = 0x11,
+- PCI_SPEED_100MHz_PCIX_533 = 0x12,
+- PCI_SPEED_133MHz_PCIX_533 = 0x13,
+- PCI_SPEED_UNKNOWN = 0xff,
+-};
+-
+-/* These values come from the PCI Express Spec */
+-enum pcie_link_width {
+- PCIE_LNK_WIDTH_RESRV = 0x00,
+- PCIE_LNK_X1 = 0x01,
+- PCIE_LNK_X2 = 0x02,
+- PCIE_LNK_X4 = 0x04,
+- PCIE_LNK_X8 = 0x08,
+- PCIE_LNK_X12 = 0x0C,
+- PCIE_LNK_X16 = 0x10,
+- PCIE_LNK_X32 = 0x20,
+- PCIE_LNK_WIDTH_UNKNOWN = 0xFF,
+-};
+-
+-enum pcie_link_speed {
+- PCIE_2PT5GB = 0x14,
+- PCIE_LNK_SPEED_UNKNOWN = 0xFF,
+-};
+-
+-struct hotplug_slot;
+-struct hotplug_slot_attribute {
+- struct attribute attr;
+- ssize_t (*show)(struct hotplug_slot *, char *);
+- ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
+-};
+-#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr);
+-
+-/**
+- * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
+- * @owner: The module owner of this structure
+- * @enable_slot: Called when the user wants to enable a specific pci slot
+- * @disable_slot: Called when the user wants to disable a specific pci slot
+- * @set_attention_status: Called to set the specific slot's attention LED to
+- * the specified value
+- * @hardware_test: Called to run a specified hardware test on the specified
+- * slot.
+- * @get_power_status: Called to get the current power status of a slot.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- * @get_attention_status: Called to get the current attention status of a slot.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- * @get_latch_status: Called to get the current latch status of a slot.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- * @get_address: Called to get pci address of a slot.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- * @get_max_bus_speed: Called to get the max bus speed for a slot.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- * @get_cur_bus_speed: Called to get the current bus speed for a slot.
+- * If this field is NULL, the value passed in the struct hotplug_slot_info
+- * will be used when this value is requested by a user.
+- *
+- * The table of function pointers that is passed to the hotplug pci core by a
+- * hotplug pci driver. These functions are called by the hotplug pci core when
+- * the user wants to do something to a specific slot (query it for information,
+- * set an LED, enable / disable power, etc.)
+- */
+-struct hotplug_slot_ops {
+- struct module *owner;
+- int (*enable_slot) (struct hotplug_slot *slot);
+- int (*disable_slot) (struct hotplug_slot *slot);
+- int (*set_attention_status) (struct hotplug_slot *slot, u8 value);
+- int (*hardware_test) (struct hotplug_slot *slot, u32 value);
+- int (*get_power_status) (struct hotplug_slot *slot, u8 *value);
+- int (*get_attention_status) (struct hotplug_slot *slot, u8 *value);
+- int (*get_latch_status) (struct hotplug_slot *slot, u8 *value);
+- int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value);
+- int (*get_address) (struct hotplug_slot *slot, u32 *value);
+- int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value);
+- int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value);
+-};
+-
+-/**
+- * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot
+- * @power: if power is enabled or not (1/0)
+- * @attention_status: if the attention light is enabled or not (1/0)
+- * @latch_status: if the latch (if any) is open or closed (1/0)
+- * @adapter_present: if there is a pci board present in the slot or not (1/0)
+- * @address: (domain << 16 | bus << 8 | dev)
+- *
+- * Used to notify the hotplug pci core of the status of a specific slot.
+- */
+-struct hotplug_slot_info {
+- u8 power_status;
+- u8 attention_status;
+- u8 latch_status;
+- u8 adapter_status;
+- u32 address;
+- enum pci_bus_speed max_bus_speed;
+- enum pci_bus_speed cur_bus_speed;
+-};
+-
+-/**
+- * struct hotplug_slot - used to register a physical slot with the hotplug pci core
+- * @name: the name of the slot being registered. This string must
+- * be unique amoung slots registered on this system.
+- * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
+- * @info: pointer to the &struct hotplug_slot_info for the initial values for
+- * this slot.
+- * @release: called during pci_hp_deregister to free memory allocated in a
+- * hotplug_slot structure.
+- * @private: used by the hotplug pci controller driver to store whatever it
+- * needs.
+- */
+-struct hotplug_slot {
+- char *name;
+- struct hotplug_slot_ops *ops;
+- struct hotplug_slot_info *info;
+- void (*release) (struct hotplug_slot *slot);
+- void *private;
+-
+- /* Variables below this are for use only by the hotplug pci core. */
+- struct list_head slot_list;
+- struct kobject kobj;
+-};
+-#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)
+-
+-extern int pci_hp_register (struct hotplug_slot *slot);
+-extern int pci_hp_deregister (struct hotplug_slot *slot);
+-extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
+- struct hotplug_slot_info *info);
+-extern struct subsystem pci_hotplug_slots_subsys;
+-
+-/* PCI Setting Record (Type 0) */
+-struct hpp_type0 {
+- u32 revision;
+- u8 cache_line_size;
+- u8 latency_timer;
+- u8 enable_serr;
+- u8 enable_perr;
+-};
+-
+-/* PCI-X Setting Record (Type 1) */
+-struct hpp_type1 {
+- u32 revision;
+- u8 max_mem_read;
+- u8 avg_max_split;
+- u16 tot_max_split;
+-};
+-
+-/* PCI Express Setting Record (Type 2) */
+-struct hpp_type2 {
+- u32 revision;
+- u32 unc_err_mask_and;
+- u32 unc_err_mask_or;
+- u32 unc_err_sever_and;
+- u32 unc_err_sever_or;
+- u32 cor_err_mask_and;
+- u32 cor_err_mask_or;
+- u32 adv_err_cap_and;
+- u32 adv_err_cap_or;
+- u16 pci_exp_devctl_and;
+- u16 pci_exp_devctl_or;
+- u16 pci_exp_lnkctl_and;
+- u16 pci_exp_lnkctl_or;
+- u32 sec_unc_err_sever_and;
+- u32 sec_unc_err_sever_or;
+- u32 sec_unc_err_mask_and;
+- u32 sec_unc_err_mask_or;
+-};
+-
+-struct hotplug_params {
+- struct hpp_type0 *t0; /* Type0: NULL if not available */
+- struct hpp_type1 *t1; /* Type1: NULL if not available */
+- struct hpp_type2 *t2; /* Type2: NULL if not available */
+- struct hpp_type0 type0_data;
+- struct hpp_type1 type1_data;
+- struct hpp_type2 type2_data;
+-};
+-
+-#ifdef CONFIG_ACPI
+-#include <acpi/acpi.h>
+-#include <acpi/acpi_bus.h>
+-#include <acpi/actypes.h>
+-extern acpi_status acpi_run_oshp(acpi_handle handle);
+-extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
+- struct hotplug_params *hpp);
+-int acpi_root_bridge(acpi_handle handle);
+-#endif
+-#endif
+-
+diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
+index b7b378d..f5d632e 100644
+--- a/drivers/pci/hotplug/pci_hotplug_core.c
++++ b/drivers/pci/hotplug/pci_hotplug_core.c
+@@ -21,9 +21,7 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+- * Send feedback to <greg at kroah.com>
+- *
+- * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
++ * Send feedback to <kristen.c.accardi at intel.com>
+ *
+ */
+
+@@ -32,6 +30,8 @@
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/list.h>
++#include <linux/kobject.h>
++#include <linux/sysfs.h>
+ #include <linux/pagemap.h>
+ #include <linux/slab.h>
+ #include <linux/smp_lock.h>
+@@ -39,11 +39,8 @@
+ #include <linux/mount.h>
+ #include <linux/namei.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <asm/uaccess.h>
+-#include <linux/kobject.h>
+-#include <linux/sysfs.h>
+-#include "pci_hotplug.h"
+-
+
+ #define MY_NAME "pci_hotplug"
+
+@@ -482,31 +479,95 @@ static int has_test_file (struct hotplug
+
+ static int fs_add_slot (struct hotplug_slot *slot)
+ {
+- if (has_power_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
++ int retval = 0;
+
+- if (has_attention_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
++ if (has_power_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
++ if (retval)
++ goto exit_power;
++ }
+
+- if (has_latch_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
++ if (has_attention_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_attention.attr);
++ if (retval)
++ goto exit_attention;
++ }
+
+- if (has_adapter_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
++ if (has_latch_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_latch.attr);
++ if (retval)
++ goto exit_latch;
++ }
+
+- if (has_address_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr);
++ if (has_adapter_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_presence.attr);
++ if (retval)
++ goto exit_adapter;
++ }
+
+- if (has_max_bus_speed_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
++ if (has_address_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_address.attr);
++ if (retval)
++ goto exit_address;
++ }
++
++ if (has_max_bus_speed_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_max_bus_speed.attr);
++ if (retval)
++ goto exit_max_speed;
++ }
++
++ if (has_cur_bus_speed_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_cur_bus_speed.attr);
++ if (retval)
++ goto exit_cur_speed;
++ }
++
++ if (has_test_file(slot) == 0) {
++ retval = sysfs_create_file(&slot->kobj,
++ &hotplug_slot_attr_test.attr);
++ if (retval)
++ goto exit_test;
++ }
+
++ goto exit;
++
++exit_test:
+ if (has_cur_bus_speed_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+
+- if (has_test_file(slot) == 0)
+- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr);
++exit_cur_speed:
++ if (has_max_bus_speed_file(slot) == 0)
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+
+- return 0;
++exit_max_speed:
++ if (has_address_file(slot) == 0)
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
++
++exit_address:
++ if (has_adapter_file(slot) == 0)
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
++
++exit_adapter:
++ if (has_latch_file(slot) == 0)
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
++
++exit_latch:
++ if (has_attention_file(slot) == 0)
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
++
++exit_attention:
++ if (has_power_file(slot) == 0)
++ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
++exit_power:
++exit:
++ return retval;
+ }
+
+ static void fs_remove_slot (struct hotplug_slot *slot)
+@@ -626,8 +687,11 @@ int pci_hp_deregister (struct hotplug_sl
+ *
+ * Returns 0 if successful, anything else for an error.
+ */
+-int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info)
++int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
++ struct hotplug_slot_info *info)
+ {
++ int retval;
++
+ if ((slot == NULL) || (info == NULL))
+ return -ENODEV;
+
+@@ -636,32 +700,60 @@ int pci_hp_change_slot_info (struct hotp
+ * for the files referring to the fields that have now changed.
+ */
+ if ((has_power_file(slot) == 0) &&
+- (slot->info->power_status != info->power_status))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr);
++ (slot->info->power_status != info->power_status)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_power.attr);
++ if (retval)
++ return retval;
++ }
+
+ if ((has_attention_file(slot) == 0) &&
+- (slot->info->attention_status != info->attention_status))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
++ (slot->info->attention_status != info->attention_status)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_attention.attr);
++ if (retval)
++ return retval;
++ }
+
+ if ((has_latch_file(slot) == 0) &&
+- (slot->info->latch_status != info->latch_status))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
++ (slot->info->latch_status != info->latch_status)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_latch.attr);
++ if (retval)
++ return retval;
++ }
+
+ if ((has_adapter_file(slot) == 0) &&
+- (slot->info->adapter_status != info->adapter_status))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
++ (slot->info->adapter_status != info->adapter_status)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_presence.attr);
++ if (retval)
++ return retval;
++ }
+
+ if ((has_address_file(slot) == 0) &&
+- (slot->info->address != info->address))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr);
++ (slot->info->address != info->address)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_address.attr);
++ if (retval)
++ return retval;
++ }
+
+ if ((has_max_bus_speed_file(slot) == 0) &&
+- (slot->info->max_bus_speed != info->max_bus_speed))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
++ (slot->info->max_bus_speed != info->max_bus_speed)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_max_bus_speed.attr);
++ if (retval)
++ return retval;
++ }
+
+ if ((has_cur_bus_speed_file(slot) == 0) &&
+- (slot->info->cur_bus_speed != info->cur_bus_speed))
+- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
++ (slot->info->cur_bus_speed != info->cur_bus_speed)) {
++ retval = sysfs_update_file(&slot->kobj,
++ &hotplug_slot_attr_cur_bus_speed.attr);
++ if (retval)
++ return retval;
++ }
+
+ memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
+
+diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
+index eaea9d3..4fb12fc 100644
+--- a/drivers/pci/hotplug/pciehp.h
++++ b/drivers/pci/hotplug/pciehp.h
+@@ -31,11 +31,11 @@
+
+ #include <linux/types.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/delay.h>
+ #include <linux/sched.h> /* signal_pending() */
+ #include <linux/pcieport_if.h>
+ #include <linux/mutex.h>
+-#include "pci_hotplug.h"
+
+ #define MY_NAME "pciehp"
+
+@@ -92,6 +92,7 @@ struct php_ctlr_state_s {
+ struct controller {
+ struct controller *next;
+ struct mutex crit_sect; /* critical section mutex */
++ struct mutex ctrl_lock; /* controller lock */
+ struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
+ int num_slots; /* Number of slots on ctlr */
+ int slot_num_inc; /* 1 or -1 */
+@@ -166,10 +167,10 @@ struct controller {
+ * error Messages
+ */
+ #define msg_initialization_err "Initialization failure, error=%d\n"
+-#define msg_button_on "PCI slot #%d - powering on due to button press.\n"
+-#define msg_button_off "PCI slot #%d - powering off due to button press.\n"
+-#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n"
+-#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n"
++#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
++#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
++#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
++#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n"
+
+ /* controller functions */
+ extern int pciehp_event_start_thread (void);
+diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
+index c67b7c3..f93e81e 100644
+--- a/drivers/pci/hotplug/pciehp_core.c
++++ b/drivers/pci/hotplug/pciehp_core.c
+@@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_devi
+ }
+
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
+
+@@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_devi
+ rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
+ if (rc) {
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ goto err_out_free_ctrl_slot;
+ } else
+ /* Wait for the command to complete */
+@@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_devi
+ }
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+
+ return 0;
+
+diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
+index 33d1987..372c63e 100644
+--- a/drivers/pci/hotplug/pciehp_ctrl.c
++++ b/drivers/pci/hotplug/pciehp_ctrl.c
+@@ -43,6 +43,11 @@ static int event_finished;
+ static unsigned long pushbutton_pending; /* = 0 */
+ static unsigned long surprise_rm_pending; /* = 0 */
+
++static inline char *slot_name(struct slot *p_slot)
++{
++ return p_slot->hotplug_slot->name;
++}
++
+ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+ {
+ struct controller *ctrl = (struct controller *) inst_id;
+@@ -68,7 +73,7 @@ u8 pciehp_handle_attention_button(u8 hp_
+ /*
+ * Button pressed - See if need to TAKE ACTION!!!
+ */
+- info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Button pressed on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_BUTTON_PRESS;
+
+ if ((p_slot->state == BLINKINGON_STATE)
+@@ -78,7 +83,7 @@ u8 pciehp_handle_attention_button(u8 hp_
+ * or hot-remove
+ */
+ taskInfo->event_type = INT_BUTTON_CANCEL;
+- info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Button cancel on Slot(%s)\n", slot_name(p_slot));
+ } else if ((p_slot->state == POWERON_STATE)
+ || (p_slot->state == POWEROFF_STATE)) {
+ /* Ignore if the slot is on power-on or power-off state; this
+@@ -86,7 +91,7 @@ u8 pciehp_handle_attention_button(u8 hp_
+ * hot-remove is undergoing
+ */
+ taskInfo->event_type = INT_BUTTON_IGNORE;
+- info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Button ignore on Slot(%s)\n", slot_name(p_slot));
+ }
+
+ if (rc)
+@@ -122,13 +127,13 @@ u8 pciehp_handle_switch_change(u8 hp_slo
+ /*
+ * Switch opened
+ */
+- info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Latch open on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_SWITCH_OPEN;
+ } else {
+ /*
+ * Switch closed
+ */
+- info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Latch close on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_SWITCH_CLOSE;
+ }
+
+@@ -166,13 +171,13 @@ u8 pciehp_handle_presence_change(u8 hp_s
+ /*
+ * Card Present
+ */
+- info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Card present on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_PRESENCE_ON;
+ } else {
+ /*
+ * Not Present
+ */
+- info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Card not present on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_PRESENCE_OFF;
+ }
+
+@@ -206,13 +211,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot,
+ /*
+ * power fault Cleared
+ */
+- info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+ } else {
+ /*
+ * power fault
+ */
+- info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
++ info("Power fault on Slot(%s)\n", slot_name(p_slot));
+ taskInfo->event_type = INT_POWER_FAULT;
+ info("power fault bit %x set\n", hp_slot);
+ }
+@@ -229,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot,
+ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
+ {
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
+ if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (pslot->hpc_ops->power_off_slot(pslot)) {
+ err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ return;
+ }
+ wait_for_ctrl_irq (ctrl);
+@@ -249,14 +254,14 @@ static void set_slot_off(struct controll
+ if (ATTN_LED(ctrl->ctrlcap)) {
+ if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
+ err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ return;
+ }
+ wait_for_ctrl_irq (ctrl);
+ }
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ }
+
+ /**
+@@ -279,13 +284,13 @@ static int board_added(struct slot *p_sl
+ ctrl->slot_device_offset, hp_slot);
+
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ if (POWER_CTRL(ctrl->ctrlcap)) {
+ /* Power on slot */
+ rc = p_slot->hpc_ops->power_on_slot(p_slot);
+ if (rc) {
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ return -1;
+ }
+
+@@ -301,7 +306,7 @@ static int board_added(struct slot *p_sl
+ }
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+
+ /* Wait for ~1 second */
+ wait_for_ctrl_irq (ctrl);
+@@ -335,7 +340,7 @@ static int board_added(struct slot *p_sl
+ pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
+ if (PWR_LED(ctrl->ctrlcap)) {
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ p_slot->hpc_ops->green_led_on(p_slot);
+
+@@ -343,7 +348,7 @@ static int board_added(struct slot *p_sl
+ wait_for_ctrl_irq (ctrl);
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ }
+ return 0;
+
+@@ -375,14 +380,14 @@ static int remove_board(struct slot *p_s
+ dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ if (POWER_CTRL(ctrl->ctrlcap)) {
+ /* power off slot */
+ rc = p_slot->hpc_ops->power_off_slot(p_slot);
+ if (rc) {
+ err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ return rc;
+ }
+ /* Wait for the command to complete */
+@@ -398,7 +403,7 @@ static int remove_board(struct slot *p_s
+ }
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+
+ return 0;
+ }
+@@ -445,7 +450,7 @@ static void pciehp_pushbutton_thread(uns
+
+ if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&p_slot->ctrl->crit_sect);
++ mutex_lock(&p_slot->ctrl->ctrl_lock);
+
+ p_slot->hpc_ops->green_led_off(p_slot);
+
+@@ -453,7 +458,7 @@ static void pciehp_pushbutton_thread(uns
+ wait_for_ctrl_irq (p_slot->ctrl);
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&p_slot->ctrl->crit_sect);
++ mutex_unlock(&p_slot->ctrl->ctrl_lock);
+ }
+ p_slot->state = STATIC_STATE;
+ }
+@@ -495,7 +500,7 @@ static void pciehp_surprise_rm_thread(un
+
+ if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&p_slot->ctrl->crit_sect);
++ mutex_lock(&p_slot->ctrl->ctrl_lock);
+
+ p_slot->hpc_ops->green_led_off(p_slot);
+
+@@ -503,7 +508,7 @@ static void pciehp_surprise_rm_thread(un
+ wait_for_ctrl_irq (p_slot->ctrl);
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&p_slot->ctrl->crit_sect);
++ mutex_unlock(&p_slot->ctrl->ctrl_lock);
+ }
+ p_slot->state = STATIC_STATE;
+ }
+@@ -616,7 +621,7 @@ static void interrupt_event_handler(stru
+ switch (p_slot->state) {
+ case BLINKINGOFF_STATE:
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ if (PWR_LED(ctrl->ctrlcap)) {
+ p_slot->hpc_ops->green_led_on(p_slot);
+@@ -630,11 +635,11 @@ static void interrupt_event_handler(stru
+ wait_for_ctrl_irq (ctrl);
+ }
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ break;
+ case BLINKINGON_STATE:
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ if (PWR_LED(ctrl->ctrlcap)) {
+ p_slot->hpc_ops->green_led_off(p_slot);
+@@ -647,14 +652,14 @@ static void interrupt_event_handler(stru
+ wait_for_ctrl_irq (ctrl);
+ }
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+
+ break;
+ default:
+ warn("Not a valid state\n");
+ return;
+ }
+- info(msg_button_cancel, p_slot->number);
++ info(msg_button_cancel, slot_name(p_slot));
+ p_slot->state = STATIC_STATE;
+ }
+ /* ***********Button Pressed (No action on 1st press...) */
+@@ -667,16 +672,16 @@ static void interrupt_event_handler(stru
+ /* slot is on */
+ dbg("slot is on\n");
+ p_slot->state = BLINKINGOFF_STATE;
+- info(msg_button_off, p_slot->number);
++ info(msg_button_off, slot_name(p_slot));
+ } else {
+ /* slot is off */
+ dbg("slot is off\n");
+ p_slot->state = BLINKINGON_STATE;
+- info(msg_button_on, p_slot->number);
++ info(msg_button_on, slot_name(p_slot));
+ }
+
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ /* blink green LED and turn off amber */
+ if (PWR_LED(ctrl->ctrlcap)) {
+@@ -693,7 +698,7 @@ static void interrupt_event_handler(stru
+ }
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+
+ init_timer(&p_slot->task_event);
+ p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
+@@ -708,7 +713,7 @@ static void interrupt_event_handler(stru
+ if (POWER_CTRL(ctrl->ctrlcap)) {
+ dbg("power fault\n");
+ /* Wait for exclusive access to hardware */
+- mutex_lock(&ctrl->crit_sect);
++ mutex_lock(&ctrl->ctrl_lock);
+
+ if (ATTN_LED(ctrl->ctrlcap)) {
+ p_slot->hpc_ops->set_attention_status(p_slot, 1);
+@@ -721,7 +726,7 @@ static void interrupt_event_handler(stru
+ }
+
+ /* Done with exclusive hardware access */
+- mutex_unlock(&ctrl->crit_sect);
++ mutex_unlock(&ctrl->ctrl_lock);
+ }
+ }
+ /***********SURPRISE REMOVAL********************/
+@@ -760,28 +765,30 @@ int pciehp_enable_slot(struct slot *p_sl
+
+ rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ if (rc || !getstatus) {
+- info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
++ info("%s: no adapter on slot(%s)\n", __FUNCTION__,
++ slot_name(p_slot));
+ mutex_unlock(&p_slot->ctrl->crit_sect);
+- return 1;
++ return -ENODEV;
+ }
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ if (rc || getstatus) {
+- info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
++ info("%s: latch open on slot(%s)\n", __FUNCTION__,
++ slot_name(p_slot));
+ mutex_unlock(&p_slot->ctrl->crit_sect);
+- return 1;
++ return -ENODEV;
+ }
+ }
+
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ if (rc || getstatus) {
+- info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
++ info("%s: already enabled on slot(%s)\n", __FUNCTION__,
++ slot_name(p_slot));
+ mutex_unlock(&p_slot->ctrl->crit_sect);
+- return 1;
++ return -EINVAL;
+ }
+ }
+- mutex_unlock(&p_slot->ctrl->crit_sect);
+
+ p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+
+@@ -790,9 +797,9 @@ int pciehp_enable_slot(struct slot *p_sl
+ p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ }
+
+- if (p_slot)
+- update_slot_info(p_slot);
++ update_slot_info(p_slot);
+
++ mutex_unlock(&p_slot->ctrl->crit_sect);
+ return rc;
+ }
+
+@@ -811,34 +818,37 @@ int pciehp_disable_slot(struct slot *p_s
+ if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
+ ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ if (ret || !getstatus) {
+- info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
++ info("%s: no adapter on slot(%s)\n", __FUNCTION__,
++ slot_name(p_slot));
+ mutex_unlock(&p_slot->ctrl->crit_sect);
+- return 1;
++ return -ENODEV;
+ }
+ }
+
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ if (ret || getstatus) {
+- info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
++ info("%s: latch open on slot(%s)\n", __FUNCTION__,
++ slot_name(p_slot));
+ mutex_unlock(&p_slot->ctrl->crit_sect);
+- return 1;
++ return -ENODEV;
+ }
+ }
+
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ if (ret || !getstatus) {
+- info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
++ info("%s: already disabled slot(%s)\n", __FUNCTION__,
++ slot_name(p_slot));
+ mutex_unlock(&p_slot->ctrl->crit_sect);
+- return 1;
++ return -EINVAL;
+ }
+ }
+
+- mutex_unlock(&p_slot->ctrl->crit_sect);
+-
+ ret = remove_board(p_slot);
+ update_slot_info(p_slot);
++
++ mutex_unlock(&p_slot->ctrl->crit_sect);
+ return ret;
+ }
+
+diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
+index 6ab3b6c..1c551c6 100644
+--- a/drivers/pci/hotplug/pciehp_hpc.c
++++ b/drivers/pci/hotplug/pciehp_hpc.c
+@@ -222,7 +222,7 @@ static struct php_ctlr_state_s *php_ctlr
+ static int ctlr_seq_num = 0; /* Controller sequence # */
+ static spinlock_t list_lock;
+
+-static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);
++static irqreturn_t pcie_isr(int IRQ, void *dev_id);
+
+ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+@@ -239,7 +239,7 @@ static void int_poll_timeout(unsigned lo
+ }
+
+ /* Poll for interrupt events. regs == NULL => polling */
+- pcie_isr( 0, (void *)php_ctlr, NULL );
++ pcie_isr( 0, (void *)php_ctlr );
+
+ init_timer(&php_ctlr->int_poll_timer);
+
+@@ -863,7 +863,7 @@ static int hpc_power_off_slot(struct slo
+ return retval;
+ }
+
+-static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+ {
+ struct controller *ctrl = NULL;
+ struct php_ctlr_state_s *php_ctlr;
+@@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl,
+ pdev->subsystem_vendor, pdev->subsystem_device);
+
+ mutex_init(&ctrl->crit_sect);
++ mutex_init(&ctrl->ctrl_lock);
++
+ /* setup wait queue */
+ init_waitqueue_head(&ctrl->queue);
+
+diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c
+index 8ad4466..50bcd3f 100644
+--- a/drivers/pci/hotplug/pcihp_skeleton.c
++++ b/drivers/pci/hotplug/pcihp_skeleton.c
+@@ -1,5 +1,5 @@
+ /*
+- * PCI Hot Plug Controller Skeleton Driver - 0.2
++ * PCI Hot Plug Controller Skeleton Driver - 0.3
+ *
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg at kroah.com)
+ * Copyright (C) 2001,2003 IBM Corp.
+@@ -21,7 +21,7 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+- * This driver is to be used as a skeleton driver to be show how to interface
++ * This driver is to be used as a skeleton driver to show how to interface
+ * with the pci hotplug core easily.
+ *
+ * Send feedback to <greg at kroah.com>
+@@ -33,8 +33,8 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/init.h>
+-#include "pci_hotplug.h"
+
+ #define SLOT_NAME_SIZE 10
+ struct slot {
+@@ -58,8 +58,6 @@ static LIST_HEAD(slot_list);
+ #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+ #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+-
+-
+ /* local variables */
+ static int debug;
+ static int num_slots;
+@@ -109,7 +107,6 @@ static int enable_slot(struct hotplug_sl
+ return retval;
+ }
+
+-
+ static int disable_slot(struct hotplug_slot *hotplug_slot)
+ {
+ struct slot *slot = hotplug_slot->private;
+@@ -342,7 +339,7 @@ static int __init pcihp_skel_init(void)
+ info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ /*
+ * Do specific initialization stuff for your driver here
+- * Like initializing your controller hardware (if any) and
++ * like initializing your controller hardware (if any) and
+ * determining the number of slots you have in the system
+ * right now.
+ */
+diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
+index db69be8..6c5be3f 100644
+--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
++++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
+@@ -14,7 +14,7 @@
+ */
+ #include <linux/kobject.h>
+ #include <linux/string.h>
+-#include "pci_hotplug.h"
++#include <linux/pci_hotplug.h>
+ #include "rpadlpar.h"
+
+ #define DLPAR_KOBJ_NAME "control"
+diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
+index 310b618..2e7accf 100644
+--- a/drivers/pci/hotplug/rpaphp.h
++++ b/drivers/pci/hotplug/rpaphp.h
+@@ -28,7 +28,7 @@
+ #define _PPC64PHP_H
+
+ #include <linux/pci.h>
+-#include "pci_hotplug.h"
++#include <linux/pci_hotplug.h>
+
+ #define DR_INDICATOR 9002
+ #define DR_ENTITY_SENSE 9003
+diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
+index 076bd6d..141486d 100644
+--- a/drivers/pci/hotplug/rpaphp_core.c
++++ b/drivers/pci/hotplug/rpaphp_core.c
+@@ -26,6 +26,7 @@
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/slab.h>
+ #include <linux/smp.h>
+ #include <linux/smp_lock.h>
+@@ -36,7 +37,6 @@
+ #include "../pci.h" /* for pci_add_new_bus */
+ /* and pci_do_scan_bus */
+ #include "rpaphp.h"
+-#include "pci_hotplug.h"
+
+ int debug;
+ static struct semaphore rpaphp_sem;
+@@ -176,16 +176,16 @@ static int get_max_bus_speed(struct hotp
+ return 0;
+ }
+
+-static int get_children_props(struct device_node *dn, int **drc_indexes,
+- int **drc_names, int **drc_types, int **drc_power_domains)
++static int get_children_props(struct device_node *dn, const int **drc_indexes,
++ const int **drc_names, const int **drc_types,
++ const int **drc_power_domains)
+ {
+- int *indexes, *names;
+- int *types, *domains;
++ const int *indexes, *names, *types, *domains;
+
+- indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL);
+- names = (int *) get_property(dn, "ibm,drc-names", NULL);
+- types = (int *) get_property(dn, "ibm,drc-types", NULL);
+- domains = (int *) get_property(dn, "ibm,drc-power-domains", NULL);
++ indexes = get_property(dn, "ibm,drc-indexes", NULL);
++ names = get_property(dn, "ibm,drc-names", NULL);
++ types = get_property(dn, "ibm,drc-types", NULL);
++ domains = get_property(dn, "ibm,drc-power-domains", NULL);
+
+ if (!indexes || !names || !types || !domains) {
+ /* Slot does not have dynamically-removable children */
+@@ -212,13 +212,13 @@ static int get_children_props(struct dev
+ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
+ char **drc_name, char **drc_type, int *drc_power_domain)
+ {
+- int *indexes, *names;
+- int *types, *domains;
+- unsigned int *my_index;
++ const int *indexes, *names;
++ const int *types, *domains;
++ const unsigned int *my_index;
+ char *name_tmp, *type_tmp;
+ int i, rc;
+
+- my_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
++ my_index = get_property(dn, "ibm,my-drc-index", NULL);
+ if (!my_index) {
+ /* Node isn't DLPAR/hotplug capable */
+ return -EINVAL;
+@@ -265,10 +265,10 @@ static int is_php_type(char *drc_type)
+ return 1;
+ }
+
+-static int is_php_dn(struct device_node *dn, int **indexes, int **names,
+- int **types, int **power_domains)
++static int is_php_dn(struct device_node *dn, const int **indexes,
++ const int **names, const int **types, const int **power_domains)
+ {
+- int *drc_types;
++ const int *drc_types;
+ int rc;
+
+ rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
+@@ -296,7 +296,7 @@ int rpaphp_add_slot(struct device_node *
+ struct slot *slot;
+ int retval = 0;
+ int i;
+- int *indexes, *names, *types, *power_domains;
++ const int *indexes, *names, *types, *power_domains;
+ char *name, *type;
+
+ dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
+diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
+index f31d83c..b62ad31 100644
+--- a/drivers/pci/hotplug/sgi_hotplug.c
++++ b/drivers/pci/hotplug/sgi_hotplug.c
+@@ -13,6 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/proc_fs.h>
+ #include <linux/types.h>
+ #include <linux/mutex.h>
+@@ -29,7 +30,6 @@
+ #include <asm/sn/types.h>
+
+ #include "../pci.h"
+-#include "pci_hotplug.h"
+
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("SGI (prarit at sgi.com, dickie at sgi.com, habeck at sgi.com)");
+diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
+index 7208b95..ea2087c 100644
+--- a/drivers/pci/hotplug/shpchp.h
++++ b/drivers/pci/hotplug/shpchp.h
+@@ -31,12 +31,11 @@
+
+ #include <linux/types.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ #include <linux/delay.h>
+ #include <linux/sched.h> /* signal_pending(), struct timer_list */
+ #include <linux/mutex.h>
+
+-#include "pci_hotplug.h"
+-
+ #if !defined(MODULE)
+ #define MY_NAME "shpchp"
+ #else
+@@ -103,7 +102,6 @@ struct controller {
+ u32 cap_offset;
+ unsigned long mmio_base;
+ unsigned long mmio_size;
+- volatile int cmd_busy;
+ };
+
+
+@@ -173,7 +171,7 @@ struct controller {
+ #define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
+
+ /* sysfs functions for the hotplug controller info */
+-extern void shpchp_create_ctrl_files (struct controller *ctrl);
++extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
+
+ extern int shpchp_sysfs_enable_slot(struct slot *slot);
+ extern int shpchp_sysfs_disable_slot(struct slot *slot);
+diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
+index a14e7de..235c18a 100644
+--- a/drivers/pci/hotplug/shpchp_core.c
++++ b/drivers/pci/hotplug/shpchp_core.c
+@@ -449,10 +449,14 @@ static int shpc_probe(struct pci_dev *pd
+ ctrl->speed = PCI_SPEED_33MHz;
+ }
+
+- shpchp_create_ctrl_files(ctrl);
++ rc = shpchp_create_ctrl_files(ctrl);
++ if (rc)
++ goto err_cleanup_slots;
+
+ return 0;
+
++err_cleanup_slots:
++ cleanup_slots(ctrl);
+ err_out_release_ctlr:
+ ctrl->hpc_ops->release_ctlr(ctrl);
+ err_out_free_ctrl:
+diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
+index 0f9798d..83a5226 100644
+--- a/drivers/pci/hotplug/shpchp_hpc.c
++++ b/drivers/pci/hotplug/shpchp_hpc.c
+@@ -218,7 +218,7 @@ static spinlock_t list_lock;
+
+ static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
+
+-static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t shpc_isr(int irq, void *dev_id);
+ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec);
+ static int hpc_check_cmd_status(struct controller *ctrl);
+
+@@ -276,7 +276,7 @@ static void int_poll_timeout(unsigned lo
+ DBG_ENTER_ROUTINE
+
+ /* Poll for interrupt events. regs == NULL => polling */
+- shpc_isr(0, php_ctlr->callback_instance_id, NULL);
++ shpc_isr(0, php_ctlr->callback_instance_id);
+
+ init_timer(&php_ctlr->int_poll_timer);
+ if (!shpchp_poll_time)
+@@ -302,21 +302,51 @@ static void start_int_poll_timer(struct
+ add_timer(&php_ctlr->int_poll_timer);
+ }
+
++static inline int is_ctrl_busy(struct controller *ctrl)
++{
++ u16 cmd_status = shpc_readw(ctrl, CMD_STATUS);
++ return cmd_status & 0x1;
++}
++
++/*
++ * Returns 1 if SHPC finishes executing a command within 1 sec,
++ * otherwise returns 0.
++ */
++static inline int shpc_poll_ctrl_busy(struct controller *ctrl)
++{
++ int i;
++
++ if (!is_ctrl_busy(ctrl))
++ return 1;
++
++ /* Check every 0.1 sec for a total of 1 sec */
++ for (i = 0; i < 10; i++) {
++ msleep(100);
++ if (!is_ctrl_busy(ctrl))
++ return 1;
++ }
++
++ return 0;
++}
++
+ static inline int shpc_wait_cmd(struct controller *ctrl)
+ {
+ int retval = 0;
+- unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;
+- unsigned long timeout = msecs_to_jiffies(timeout_msec);
+- int rc = wait_event_interruptible_timeout(ctrl->queue,
+- !ctrl->cmd_busy, timeout);
+- if (!rc) {
++ unsigned long timeout = msecs_to_jiffies(1000);
++ int rc;
++
++ if (shpchp_poll_mode)
++ rc = shpc_poll_ctrl_busy(ctrl);
++ else
++ rc = wait_event_interruptible_timeout(ctrl->queue,
++ !is_ctrl_busy(ctrl), timeout);
++ if (!rc && is_ctrl_busy(ctrl)) {
+ retval = -EIO;
+- err("Command not completed in %d msec\n", timeout_msec);
++ err("Command not completed in 1000 msec\n");
+ } else if (rc < 0) {
+ retval = -EINTR;
+ info("Command was interrupted by a signal\n");
+ }
+- ctrl->cmd_busy = 0;
+
+ return retval;
+ }
+@@ -327,26 +357,15 @@ static int shpc_write_cmd(struct slot *s
+ u16 cmd_status;
+ int retval = 0;
+ u16 temp_word;
+- int i;
+
+ DBG_ENTER_ROUTINE
+
+ mutex_lock(&slot->ctrl->cmd_lock);
+
+- for (i = 0; i < 10; i++) {
+- cmd_status = shpc_readw(ctrl, CMD_STATUS);
+-
+- if (!(cmd_status & 0x1))
+- break;
+- /* Check every 0.1 sec for a total of 1 sec*/
+- msleep(100);
+- }
+-
+- cmd_status = shpc_readw(ctrl, CMD_STATUS);
+-
+- if (cmd_status & 0x1) {
++ if (!shpc_poll_ctrl_busy(ctrl)) {
+ /* After 1 sec and and the controller is still busy */
+- err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
++ err("%s : Controller is still busy after 1 sec.\n",
++ __FUNCTION__);
+ retval = -EBUSY;
+ goto out;
+ }
+@@ -358,7 +377,6 @@ static int shpc_write_cmd(struct slot *s
+ /* To make sure the Controller Busy bit is 0 before we send out the
+ * command.
+ */
+- slot->ctrl->cmd_busy = 1;
+ shpc_writew(ctrl, CMD, temp_word);
+
+ /*
+@@ -870,7 +888,7 @@ static int hpc_set_bus_speed_mode(struct
+ return retval;
+ }
+
+-static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t shpc_isr(int irq, void *dev_id)
+ {
+ struct controller *ctrl = (struct controller *)dev_id;
+ struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
+@@ -908,7 +926,6 @@ static irqreturn_t shpc_isr(int irq, voi
+ serr_int &= ~SERR_INTR_RSVDZ_MASK;
+ shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
+
+- ctrl->cmd_busy = 0;
+ wake_up_interruptible(&ctrl->queue);
+ }
+
+@@ -1101,7 +1118,7 @@ int shpc_init(struct controller * ctrl,
+ {
+ struct php_ctlr_state_s *php_ctlr, *p;
+ void *instance_id = ctrl;
+- int rc, num_slots = 0;
++ int rc = -1, num_slots = 0;
+ u8 hp_slot;
+ u32 shpc_base_offset;
+ u32 tempdword, slot_reg, slot_config;
+@@ -1167,11 +1184,15 @@ int shpc_init(struct controller * ctrl,
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
+
+- if (pci_enable_device(pdev))
++ rc = pci_enable_device(pdev);
++ if (rc) {
++ err("%s: pci_enable_device failed\n", __FUNCTION__);
+ goto abort_free_ctlr;
++ }
+
+ if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
+ err("%s: cannot reserve MMIO region\n", __FUNCTION__);
++ rc = -1;
+ goto abort_free_ctlr;
+ }
+
+@@ -1180,6 +1201,7 @@ int shpc_init(struct controller * ctrl,
+ err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
+ ctrl->mmio_size, ctrl->mmio_base);
+ release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
++ rc = -1;
+ goto abort_free_ctlr;
+ }
+ dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
+@@ -1282,8 +1304,10 @@ int shpc_init(struct controller * ctrl,
+ */
+ if (atomic_add_return(1, &shpchp_num_controllers) == 1) {
+ shpchp_wq = create_singlethread_workqueue("shpchpd");
+- if (!shpchp_wq)
+- return -ENOMEM;
++ if (!shpchp_wq) {
++ rc = -ENOMEM;
++ goto abort_free_ctlr;
++ }
+ }
+
+ /*
+@@ -1313,8 +1337,10 @@ int shpc_init(struct controller * ctrl,
+
+ /* We end up here for the many possible ways to fail this API. */
+ abort_free_ctlr:
++ if (php_ctlr->creg)
++ iounmap(php_ctlr->creg);
+ kfree(php_ctlr);
+ abort:
+ DBG_LEAVE_ROUTINE
+- return -1;
++ return rc;
+ }
+diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
+index 620e113..29fa9d2 100644
+--- a/drivers/pci/hotplug/shpchp_sysfs.c
++++ b/drivers/pci/hotplug/shpchp_sysfs.c
+@@ -91,9 +91,9 @@ static ssize_t show_ctrl (struct device
+ }
+ static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
+
+-void shpchp_create_ctrl_files (struct controller *ctrl)
++int __must_check shpchp_create_ctrl_files (struct controller *ctrl)
+ {
+- device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
++ return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
+ }
+
+ void shpchp_remove_ctrl_files(struct controller *ctrl)
+diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
+new file mode 100644
+index 0000000..0e27f24
+--- /dev/null
++++ b/drivers/pci/htirq.c
+@@ -0,0 +1,190 @@
++/*
++ * File: htirq.c
++ * Purpose: Hypertransport Interrupt Capability
++ *
++ * Copyright (C) 2006 Linux Networx
++ * Copyright (C) Eric Biederman <ebiederman at lnxi.com>
++ */
++
++#include <linux/irq.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/gfp.h>
++#include <linux/htirq.h>
++
++/* Global ht irq lock.
++ *
++ * This is needed to serialize access to the data port in hypertransport
++ * irq capability.
++ *
++ * With multiple simultaneous hypertransport irq devices it might pay
++ * to make this more fine grained. But start with simple, stupid, and correct.
++ */
++static DEFINE_SPINLOCK(ht_irq_lock);
++
++struct ht_irq_cfg {
++ struct pci_dev *dev;
++ unsigned pos;
++ unsigned idx;
++};
++
++void write_ht_irq_low(unsigned int irq, u32 data)
++{
++ struct ht_irq_cfg *cfg = get_irq_data(irq);
++ unsigned long flags;
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
++ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++}
++
++void write_ht_irq_high(unsigned int irq, u32 data)
++{
++ struct ht_irq_cfg *cfg = get_irq_data(irq);
++ unsigned long flags;
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
++ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++}
++
++u32 read_ht_irq_low(unsigned int irq)
++{
++ struct ht_irq_cfg *cfg = get_irq_data(irq);
++ unsigned long flags;
++ u32 data;
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
++ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++ return data;
++}
++
++u32 read_ht_irq_high(unsigned int irq)
++{
++ struct ht_irq_cfg *cfg = get_irq_data(irq);
++ unsigned long flags;
++ u32 data;
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
++ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++ return data;
++}
++
++void mask_ht_irq(unsigned int irq)
++{
++ struct ht_irq_cfg *cfg;
++ unsigned long flags;
++ u32 data;
++
++ cfg = get_irq_data(irq);
++
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
++ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
++ data |= 1;
++ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++}
++
++void unmask_ht_irq(unsigned int irq)
++{
++ struct ht_irq_cfg *cfg;
++ unsigned long flags;
++ u32 data;
++
++ cfg = get_irq_data(irq);
++
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
++ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
++ data &= ~1;
++ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++}
++
++/**
++ * ht_create_irq - create an irq and attach it to a device.
++ * @dev: The hypertransport device to find the irq capability on.
++ * @idx: Which of the possible irqs to attach to.
++ *
++ * ht_create_irq is needs to be called for all hypertransport devices
++ * that generate irqs.
++ *
++ * The irq number of the new irq or a negative error value is returned.
++ */
++int ht_create_irq(struct pci_dev *dev, int idx)
++{
++ struct ht_irq_cfg *cfg;
++ unsigned long flags;
++ u32 data;
++ int max_irq;
++ int pos;
++ int irq;
++
++ pos = pci_find_capability(dev, PCI_CAP_ID_HT);
++ while (pos) {
++ u8 subtype;
++ pci_read_config_byte(dev, pos + 3, &subtype);
++ if (subtype == HT_CAPTYPE_IRQ)
++ break;
++ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT);
++ }
++ if (!pos)
++ return -EINVAL;
++
++ /* Verify the idx I want to use is in range */
++ spin_lock_irqsave(&ht_irq_lock, flags);
++ pci_write_config_byte(dev, pos + 2, 1);
++ pci_read_config_dword(dev, pos + 4, &data);
++ spin_unlock_irqrestore(&ht_irq_lock, flags);
++
++ max_irq = (data >> 16) & 0xff;
++ if ( idx > max_irq)
++ return -EINVAL;
++
++ cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
++ if (!cfg)
++ return -ENOMEM;
++
++ cfg->dev = dev;
++ cfg->pos = pos;
++ cfg->idx = 0x10 + (idx * 2);
++
++ irq = create_irq();
++ if (irq < 0) {
++ kfree(cfg);
++ return -EBUSY;
++ }
++ set_irq_data(irq, cfg);
++
++ if (arch_setup_ht_irq(irq, dev) < 0) {
++ ht_destroy_irq(irq);
++ return -EBUSY;
++ }
++
++ return irq;
++}
++
++/**
++ * ht_destroy_irq - destroy an irq created with ht_create_irq
++ *
++ * This reverses ht_create_irq removing the specified irq from
++ * existence. The irq should be free before this happens.
++ */
++void ht_destroy_irq(unsigned int irq)
++{
++ struct ht_irq_cfg *cfg;
++
++ cfg = get_irq_data(irq);
++ set_irq_chip(irq, NULL);
++ set_irq_data(irq, NULL);
++ destroy_irq(irq);
++
++ kfree(cfg);
++}
++
++EXPORT_SYMBOL(ht_create_irq);
++EXPORT_SYMBOL(ht_destroy_irq);
+diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c
+deleted file mode 100644
+index bed4183..0000000
+--- a/drivers/pci/msi-altix.c
++++ /dev/null
+@@ -1,210 +0,0 @@
+-/*
+- * 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) 2006 Silicon Graphics, Inc. All Rights Reserved.
+- */
+-
+-#include <linux/types.h>
+-#include <linux/pci.h>
+-#include <linux/cpumask.h>
+-
+-#include <asm/sn/addrs.h>
+-#include <asm/sn/intr.h>
+-#include <asm/sn/pcibus_provider_defs.h>
+-#include <asm/sn/pcidev.h>
+-#include <asm/sn/nodepda.h>
+-
+-#include "msi.h"
+-
+-struct sn_msi_info {
+- u64 pci_addr;
+- struct sn_irq_info *sn_irq_info;
+-};
+-
+-static struct sn_msi_info *sn_msi_info;
+-
+-static void
+-sn_msi_teardown(unsigned int vector)
+-{
+- nasid_t nasid;
+- int widget;
+- struct pci_dev *pdev;
+- struct pcidev_info *sn_pdev;
+- struct sn_irq_info *sn_irq_info;
+- struct pcibus_bussoft *bussoft;
+- struct sn_pcibus_provider *provider;
+-
+- sn_irq_info = sn_msi_info[vector].sn_irq_info;
+- if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+- return;
+-
+- sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+- pdev = sn_pdev->pdi_linux_pcidev;
+- provider = SN_PCIDEV_BUSPROVIDER(pdev);
+-
+- (*provider->dma_unmap)(pdev,
+- sn_msi_info[vector].pci_addr,
+- PCI_DMA_FROMDEVICE);
+- sn_msi_info[vector].pci_addr = 0;
+-
+- bussoft = SN_PCIDEV_BUSSOFT(pdev);
+- nasid = NASID_GET(bussoft->bs_base);
+- widget = (nasid & 1) ?
+- TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+- SWIN_WIDGETNUM(bussoft->bs_base);
+-
+- sn_intr_free(nasid, widget, sn_irq_info);
+- sn_msi_info[vector].sn_irq_info = NULL;
+-
+- return;
+-}
+-
+-int
+-sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
+- u32 *addr_hi, u32 *addr_lo, u32 *data)
+-{
+- int widget;
+- int status;
+- nasid_t nasid;
+- u64 bus_addr;
+- struct sn_irq_info *sn_irq_info;
+- struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
+- struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+-
+- if (bussoft == NULL)
+- return -EINVAL;
+-
+- if (provider == NULL || provider->dma_map_consistent == NULL)
+- return -EINVAL;
+-
+- /*
+- * Set up the vector plumbing. Let the prom (via sn_intr_alloc)
+- * decide which cpu to direct this msi at by default.
+- */
+-
+- nasid = NASID_GET(bussoft->bs_base);
+- widget = (nasid & 1) ?
+- TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+- SWIN_WIDGETNUM(bussoft->bs_base);
+-
+- sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+- if (! sn_irq_info)
+- return -ENOMEM;
+-
+- status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
+- if (status) {
+- kfree(sn_irq_info);
+- return -ENOMEM;
+- }
+-
+- sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */
+- sn_irq_fixup(pdev, sn_irq_info);
+-
+- /* Prom probably should fill these in, but doesn't ... */
+- sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
+- sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
+-
+- /*
+- * Map the xio address into bus space
+- */
+- bus_addr = (*provider->dma_map_consistent)(pdev,
+- sn_irq_info->irq_xtalkaddr,
+- sizeof(sn_irq_info->irq_xtalkaddr),
+- SN_DMA_MSI|SN_DMA_ADDR_XIO);
+- if (! bus_addr) {
+- sn_intr_free(nasid, widget, sn_irq_info);
+- kfree(sn_irq_info);
+- return -ENOMEM;
+- }
+-
+- sn_msi_info[vector].sn_irq_info = sn_irq_info;
+- sn_msi_info[vector].pci_addr = bus_addr;
+-
+- *addr_hi = (u32)(bus_addr >> 32);
+- *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+-
+- /*
+- * In the SN platform, bit 16 is a "send vector" bit which
+- * must be present in order to move the vector through the system.
+- */
+- *data = 0x100 + (unsigned int)vector;
+-
+-#ifdef CONFIG_SMP
+- set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
+-#endif
+-
+- return 0;
+-}
+-
+-static void
+-sn_msi_target(unsigned int vector, unsigned int cpu,
+- u32 *addr_hi, u32 *addr_lo)
+-{
+- int slice;
+- nasid_t nasid;
+- u64 bus_addr;
+- struct pci_dev *pdev;
+- struct pcidev_info *sn_pdev;
+- struct sn_irq_info *sn_irq_info;
+- struct sn_irq_info *new_irq_info;
+- struct sn_pcibus_provider *provider;
+-
+- sn_irq_info = sn_msi_info[vector].sn_irq_info;
+- if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+- return;
+-
+- /*
+- * Release XIO resources for the old MSI PCI address
+- */
+-
+- sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+- pdev = sn_pdev->pdi_linux_pcidev;
+- provider = SN_PCIDEV_BUSPROVIDER(pdev);
+-
+- bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
+- (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
+- sn_msi_info[vector].pci_addr = 0;
+-
+- nasid = cpuid_to_nasid(cpu);
+- slice = cpuid_to_slice(cpu);
+-
+- new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
+- sn_msi_info[vector].sn_irq_info = new_irq_info;
+- if (new_irq_info == NULL)
+- return;
+-
+- /*
+- * Map the xio address into bus space
+- */
+-
+- bus_addr = (*provider->dma_map_consistent)(pdev,
+- new_irq_info->irq_xtalkaddr,
+- sizeof(new_irq_info->irq_xtalkaddr),
+- SN_DMA_MSI|SN_DMA_ADDR_XIO);
+-
+- sn_msi_info[vector].pci_addr = bus_addr;
+- *addr_hi = (u32)(bus_addr >> 32);
+- *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+-}
+-
+-struct msi_ops sn_msi_ops = {
+- .setup = sn_msi_setup,
+- .teardown = sn_msi_teardown,
+-#ifdef CONFIG_SMP
+- .target = sn_msi_target,
+-#endif
+-};
+-
+-int
+-sn_msi_init(void)
+-{
+- sn_msi_info =
+- kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
+- if (! sn_msi_info)
+- return -ENOMEM;
+-
+- msi_register(&sn_msi_ops);
+- return 0;
+-}
+diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
+deleted file mode 100644
+index 5ed798b..0000000
+--- a/drivers/pci/msi-apic.c
++++ /dev/null
+@@ -1,101 +0,0 @@
+-/*
+- * MSI hooks for standard x86 apic
+- */
+-
+-#include <linux/pci.h>
+-#include <linux/irq.h>
+-#include <asm/smp.h>
+-
+-#include "msi.h"
+-
+-/*
+- * Shifts for APIC-based data
+- */
+-
+-#define MSI_DATA_VECTOR_SHIFT 0
+-#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+-
+-#define MSI_DATA_DELIVERY_SHIFT 8
+-#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
+-#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
+-
+-#define MSI_DATA_LEVEL_SHIFT 14
+-#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+-#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+-
+-#define MSI_DATA_TRIGGER_SHIFT 15
+-#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+-#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+-
+-/*
+- * Shift/mask fields for APIC-based bus address
+- */
+-
+-#define MSI_ADDR_HEADER 0xfee00000
+-
+-#define MSI_ADDR_DESTID_MASK 0xfff0000f
+-#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
+-
+-#define MSI_ADDR_DESTMODE_SHIFT 2
+-#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
+-#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
+-
+-#define MSI_ADDR_REDIRECTION_SHIFT 3
+-#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
+-#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
+-
+-
+-static void
+-msi_target_apic(unsigned int vector,
+- unsigned int dest_cpu,
+- u32 *address_hi, /* in/out */
+- u32 *address_lo) /* in/out */
+-{
+- u32 addr = *address_lo;
+-
+- addr &= MSI_ADDR_DESTID_MASK;
+- addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+-
+- *address_lo = addr;
+-}
+-
+-static int
+-msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
+- unsigned int vector,
+- u32 *address_hi,
+- u32 *address_lo,
+- u32 *data)
+-{
+- unsigned long dest_phys_id;
+-
+- dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+-
+- *address_hi = 0;
+- *address_lo = MSI_ADDR_HEADER |
+- MSI_ADDR_DESTMODE_PHYS |
+- MSI_ADDR_REDIRECTION_CPU |
+- MSI_ADDR_DESTID_CPU(dest_phys_id);
+-
+- *data = MSI_DATA_TRIGGER_EDGE |
+- MSI_DATA_LEVEL_ASSERT |
+- MSI_DATA_DELIVERY_FIXED |
+- MSI_DATA_VECTOR(vector);
+-
+- return 0;
+-}
+-
+-static void
+-msi_teardown_apic(unsigned int vector)
+-{
+- return; /* no-op */
+-}
+-
+-/*
+- * Generic ops used on most IA archs/platforms. Set with msi_register()
+- */
+-
+-struct msi_ops msi_apic_ops = {
+- .setup = msi_setup_apic,
+- .teardown = msi_teardown_apic,
+- .target = msi_target_apic,
+-};
+diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
+index a83c1f5..9fc9a34 100644
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -6,6 +6,7 @@
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen at intel.com)
+ */
+
++#include <linux/err.h>
+ #include <linux/mm.h>
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+@@ -14,6 +15,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/pci.h>
+ #include <linux/proc_fs.h>
++#include <linux/msi.h>
+
+ #include <asm/errno.h>
+ #include <asm/io.h>
+@@ -27,60 +29,36 @@ static struct msi_desc* msi_desc[NR_IRQS
+ static kmem_cache_t* msi_cachep;
+
+ static int pci_msi_enable = 1;
+-static int last_alloc_vector;
+-static int nr_released_vectors;
+-static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
+-static int nr_msix_devices;
+-
+-#ifndef CONFIG_X86_IO_APIC
+-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+-#endif
+-
+-static struct msi_ops *msi_ops;
+-
+-int
+-msi_register(struct msi_ops *ops)
+-{
+- msi_ops = ops;
+- return 0;
+-}
+-
+-static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
+-{
+- memset(p, 0, sizeof(struct msi_desc));
+-}
+
+ static int msi_cache_init(void)
+ {
+- msi_cachep = kmem_cache_create("msi_cache",
+- sizeof(struct msi_desc),
+- 0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
++ msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc),
++ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!msi_cachep)
+ return -ENOMEM;
+
+ return 0;
+ }
+
+-static void msi_set_mask_bit(unsigned int vector, int flag)
++static void msi_set_mask_bit(unsigned int irq, int flag)
+ {
+ struct msi_desc *entry;
+
+- entry = (struct msi_desc *)msi_desc[vector];
+- if (!entry || !entry->dev || !entry->mask_base)
+- return;
++ entry = msi_desc[irq];
++ BUG_ON(!entry || !entry->dev);
+ switch (entry->msi_attrib.type) {
+ case PCI_CAP_ID_MSI:
+- {
+- int pos;
+- u32 mask_bits;
+-
+- pos = (long)entry->mask_base;
+- pci_read_config_dword(entry->dev, pos, &mask_bits);
+- mask_bits &= ~(1);
+- mask_bits |= flag;
+- pci_write_config_dword(entry->dev, pos, mask_bits);
++ if (entry->msi_attrib.maskbit) {
++ int pos;
++ u32 mask_bits;
++
++ pos = (long)entry->mask_base;
++ pci_read_config_dword(entry->dev, pos, &mask_bits);
++ mask_bits &= ~(1);
++ mask_bits |= flag;
++ pci_write_config_dword(entry->dev, pos, mask_bits);
++ }
+ break;
+- }
+ case PCI_CAP_ID_MSIX:
+ {
+ int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+@@ -89,261 +67,101 @@ static void msi_set_mask_bit(unsigned in
+ break;
+ }
+ default:
++ BUG();
+ break;
+ }
+ }
+
+-#ifdef CONFIG_SMP
+-static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
++void read_msi_msg(unsigned int irq, struct msi_msg *msg)
+ {
+- struct msi_desc *entry;
+- u32 address_hi, address_lo;
+- unsigned int irq = vector;
+- unsigned int dest_cpu = first_cpu(cpu_mask);
+-
+- entry = (struct msi_desc *)msi_desc[vector];
+- if (!entry || !entry->dev)
+- return;
+-
+- switch (entry->msi_attrib.type) {
++ struct msi_desc *entry = get_irq_data(irq);
++ switch(entry->msi_attrib.type) {
+ case PCI_CAP_ID_MSI:
+ {
+- int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI);
+-
+- if (!pos)
+- return;
+-
+- pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+- &address_hi);
+- pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
+- &address_lo);
+-
+- msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+-
+- pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+- address_hi);
+- pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
+- address_lo);
+- set_native_irq_info(irq, cpu_mask);
++ struct pci_dev *dev = entry->dev;
++ int pos = entry->msi_attrib.pos;
++ u16 data;
++
++ pci_read_config_dword(dev, msi_lower_address_reg(pos),
++ &msg->address_lo);
++ if (entry->msi_attrib.is_64) {
++ pci_read_config_dword(dev, msi_upper_address_reg(pos),
++ &msg->address_hi);
++ pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
++ } else {
++ msg->address_hi = 0;
++ pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
++ }
++ msg->data = data;
+ break;
+ }
+ case PCI_CAP_ID_MSIX:
+ {
+- int offset_hi =
+- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+- int offset_lo =
+- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+-
+- address_hi = readl(entry->mask_base + offset_hi);
+- address_lo = readl(entry->mask_base + offset_lo);
++ void __iomem *base;
++ base = entry->mask_base +
++ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+- msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
++ msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++ msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
++ msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
++ break;
++ }
++ default:
++ BUG();
++ }
++}
+
+- writel(address_hi, entry->mask_base + offset_hi);
+- writel(address_lo, entry->mask_base + offset_lo);
+- set_native_irq_info(irq, cpu_mask);
++void write_msi_msg(unsigned int irq, struct msi_msg *msg)
++{
++ struct msi_desc *entry = get_irq_data(irq);
++ switch (entry->msi_attrib.type) {
++ case PCI_CAP_ID_MSI:
++ {
++ struct pci_dev *dev = entry->dev;
++ int pos = entry->msi_attrib.pos;
++
++ pci_write_config_dword(dev, msi_lower_address_reg(pos),
++ msg->address_lo);
++ if (entry->msi_attrib.is_64) {
++ pci_write_config_dword(dev, msi_upper_address_reg(pos),
++ msg->address_hi);
++ pci_write_config_word(dev, msi_data_reg(pos, 1),
++ msg->data);
++ } else {
++ pci_write_config_word(dev, msi_data_reg(pos, 0),
++ msg->data);
++ }
+ break;
+ }
+- default:
++ case PCI_CAP_ID_MSIX:
++ {
++ void __iomem *base;
++ base = entry->mask_base +
++ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
++
++ writel(msg->address_lo,
++ base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++ writel(msg->address_hi,
++ base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
++ writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
+ break;
+ }
+-}
+-#else
+-#define set_msi_affinity NULL
+-#endif /* CONFIG_SMP */
+-
+-static void mask_MSI_irq(unsigned int vector)
+-{
+- msi_set_mask_bit(vector, 1);
+-}
+-
+-static void unmask_MSI_irq(unsigned int vector)
+-{
+- msi_set_mask_bit(vector, 0);
+-}
+-
+-static unsigned int startup_msi_irq_wo_maskbit(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;
++ default:
++ BUG();
+ }
+- entry->msi_attrib.state = 1; /* Mark it active */
+- spin_unlock_irqrestore(&msi_lock, flags);
+-
+- return 0; /* never anything pending */
+-}
+-
+-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
+-{
+- startup_msi_irq_wo_maskbit(vector);
+- unmask_MSI_irq(vector);
+- return 0; /* never anything pending */
+-}
+-
+-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)
+- entry->msi_attrib.state = 0; /* Mark it not active */
+- spin_unlock_irqrestore(&msi_lock, flags);
+-}
+-
+-static void end_msi_irq_wo_maskbit(unsigned int vector)
+-{
+- move_native_irq(vector);
+- ack_APIC_irq();
+ }
+
+-static void end_msi_irq_w_maskbit(unsigned int vector)
++void mask_msi_irq(unsigned int irq)
+ {
+- move_native_irq(vector);
+- unmask_MSI_irq(vector);
+- ack_APIC_irq();
++ msi_set_mask_bit(irq, 1);
+ }
+
+-static void do_nothing(unsigned int vector)
++void unmask_msi_irq(unsigned int irq)
+ {
++ msi_set_mask_bit(irq, 0);
+ }
+
+-/*
+- * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
+- * which implement the MSI-X Capability Structure.
+- */
+-static struct hw_interrupt_type msix_irq_type = {
+- .typename = "PCI-MSI-X",
+- .startup = startup_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_affinity
+-};
+-
+-/*
+- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
+- * which implement the MSI Capability Structure with
+- * Mask-and-Pending Bits.
+- */
+-static struct hw_interrupt_type msi_irq_w_maskbit_type = {
+- .typename = "PCI-MSI",
+- .startup = startup_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_affinity
+-};
+-
+-/*
+- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
+- * which implement the MSI Capability Structure without
+- * Mask-and-Pending Bits.
+- */
+-static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
+- .typename = "PCI-MSI",
+- .startup = startup_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_affinity
+-};
+-
+-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
+-static int assign_msi_vector(void)
+-{
+- static int new_vector_avail = 1;
+- int vector;
+- unsigned long flags;
+-
+- /*
+- * msi_lock is provided to ensure that successful allocation of MSI
+- * vector is assigned unique among drivers.
+- */
+- spin_lock_irqsave(&msi_lock, flags);
+-
+- if (!new_vector_avail) {
+- int free_vector = 0;
+-
+- /*
+- * vector_irq[] = -1 indicates that this specific vector is:
+- * - assigned for MSI (since MSI have no associated IRQ) or
+- * - assigned for legacy if less than 16, or
+- * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping
+- * vector_irq[] = 0 indicates that this vector, previously
+- * assigned for MSI, is freed by hotplug removed operations.
+- * This vector will be reused for any subsequent hotplug added
+- * operations.
+- * vector_irq[] > 0 indicates that this vector is assigned for
+- * IOxAPIC IRQs. This vector and its value provides a 1-to-1
+- * vector-to-IOxAPIC IRQ mapping.
+- */
+- for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
+- if (vector_irq[vector] != 0)
+- continue;
+- free_vector = vector;
+- if (!msi_desc[vector])
+- break;
+- else
+- continue;
+- }
+- if (!free_vector) {
+- spin_unlock_irqrestore(&msi_lock, flags);
+- return -EBUSY;
+- }
+- vector_irq[free_vector] = -1;
+- nr_released_vectors--;
+- spin_unlock_irqrestore(&msi_lock, flags);
+- if (msi_desc[free_vector] != NULL) {
+- struct pci_dev *dev;
+- int tail;
+-
+- /* free all linked vectors before re-assign */
+- do {
+- spin_lock_irqsave(&msi_lock, flags);
+- dev = msi_desc[free_vector]->dev;
+- tail = msi_desc[free_vector]->link.tail;
+- spin_unlock_irqrestore(&msi_lock, flags);
+- msi_free_vector(dev, tail, 1);
+- } while (free_vector != tail);
+- }
+-
+- return free_vector;
+- }
+- vector = assign_irq_vector(AUTO_ASSIGN);
+- last_alloc_vector = vector;
+- if (vector == LAST_DEVICE_VECTOR)
+- new_vector_avail = 0;
+-
+- spin_unlock_irqrestore(&msi_lock, flags);
+- return vector;
+-}
+-
+-static int get_new_vector(void)
+-{
+- int vector = assign_msi_vector();
+-
+- if (vector > 0)
+- set_intr_gate(vector, interrupt[vector]);
+-
+- return vector;
+-}
+-
++static int msi_free_irq(struct pci_dev* dev, int irq);
+ static int msi_init(void)
+ {
+ static int status = -ENOMEM;
+@@ -358,22 +176,6 @@ static int msi_init(void)
+ return status;
+ }
+
+- status = msi_arch_init();
+- if (status < 0) {
+- pci_msi_enable = 0;
+- printk(KERN_WARNING
+- "PCI: MSI arch init failed. MSI disabled.\n");
+- return status;
+- }
+-
+- if (! msi_ops) {
+- printk(KERN_WARNING
+- "PCI: MSI ops not registered. MSI disabled.\n");
+- status = -EINVAL;
+- return status;
+- }
+-
+- last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
+ status = msi_cache_init();
+ if (status < 0) {
+ pci_msi_enable = 0;
+@@ -381,61 +183,61 @@ static int msi_init(void)
+ return status;
+ }
+
+- if (last_alloc_vector < 0) {
+- pci_msi_enable = 0;
+- printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
+- status = -EBUSY;
+- return status;
+- }
+- vector_irq[last_alloc_vector] = 0;
+- nr_released_vectors++;
+-
+ return status;
+ }
+
+-static int get_msi_vector(struct pci_dev *dev)
+-{
+- return get_new_vector();
+-}
+-
+ static struct msi_desc* alloc_msi_entry(void)
+ {
+ struct msi_desc *entry;
+
+- entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
++ entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL);
+ if (!entry)
+ return NULL;
+
+- memset(entry, 0, sizeof(struct msi_desc));
+ entry->link.tail = entry->link.head = 0; /* single message */
+ entry->dev = NULL;
+
+ return entry;
+ }
+
+-static void attach_msi_entry(struct msi_desc *entry, int vector)
++static void attach_msi_entry(struct msi_desc *entry, int irq)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&msi_lock, flags);
+- msi_desc[vector] = entry;
++ msi_desc[irq] = entry;
+ spin_unlock_irqrestore(&msi_lock, flags);
+ }
+
+-static void irq_handler_init(int cap_id, int pos, int mask)
++static int create_msi_irq(void)
+ {
+- unsigned long flags;
++ struct msi_desc *entry;
++ int irq;
+
+- spin_lock_irqsave(&irq_desc[pos].lock, flags);
+- if (cap_id == PCI_CAP_ID_MSIX)
+- irq_desc[pos].chip = &msix_irq_type;
+- else {
+- if (!mask)
+- irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
+- else
+- irq_desc[pos].chip = &msi_irq_w_maskbit_type;
++ entry = alloc_msi_entry();
++ if (!entry)
++ return -ENOMEM;
++
++ irq = create_irq();
++ if (irq < 0) {
++ kmem_cache_free(msi_cachep, entry);
++ return -EBUSY;
+ }
+- spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
++
++ set_irq_data(irq, entry);
++
++ return irq;
++}
++
++static void destroy_msi_irq(unsigned int irq)
++{
++ struct msi_desc *entry;
++
++ entry = get_irq_data(irq);
++ set_irq_chip(irq, NULL);
++ set_irq_data(irq, NULL);
++ destroy_irq(irq);
++ kmem_cache_free(msi_cachep, entry);
+ }
+
+ static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
+@@ -480,21 +282,21 @@ void disable_msi_mode(struct pci_dev *de
+ }
+ }
+
+-static int msi_lookup_vector(struct pci_dev *dev, int type)
++static int msi_lookup_irq(struct pci_dev *dev, int type)
+ {
+- int vector;
++ int irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msi_lock, flags);
+- for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
+- if (!msi_desc[vector] || msi_desc[vector]->dev != dev ||
+- msi_desc[vector]->msi_attrib.type != type ||
+- msi_desc[vector]->msi_attrib.default_vector != dev->irq)
++ for (irq = 0; irq < NR_IRQS; irq++) {
++ if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
++ msi_desc[irq]->msi_attrib.type != type ||
++ msi_desc[irq]->msi_attrib.default_irq != dev->irq)
+ continue;
+ spin_unlock_irqrestore(&msi_lock, flags);
+- /* This pre-assigned MSI vector for this device
+- already exits. Override dev->irq with this vector */
+- dev->irq = vector;
++ /* This pre-assigned MSI irq for this device
++ already exits. Override dev->irq with this irq */
++ dev->irq = irq;
+ return 0;
+ }
+ spin_unlock_irqrestore(&msi_lock, flags);
+@@ -506,11 +308,6 @@ void pci_scan_msi_device(struct pci_dev
+ {
+ if (!dev)
+ return;
+-
+- if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0)
+- nr_msix_devices++;
+- else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0)
+- nr_reserved_vectors++;
+ }
+
+ #ifdef CONFIG_PM
+@@ -584,7 +381,7 @@ int pci_save_msix_state(struct pci_dev *
+ {
+ int pos;
+ int temp;
+- int vector, head, tail = 0;
++ int irq, head, tail = 0;
+ u16 control;
+ struct pci_cap_saved_state *save_state;
+
+@@ -606,33 +403,20 @@ int pci_save_msix_state(struct pci_dev *
+
+ /* save the table */
+ temp = dev->irq;
+- if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
++ if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ kfree(save_state);
+ return -EINVAL;
+ }
+
+- vector = head = dev->irq;
++ irq = head = dev->irq;
+ while (head != tail) {
+- int j;
+- void __iomem *base;
+ struct msi_desc *entry;
+
+- entry = msi_desc[vector];
+- base = entry->mask_base;
+- j = entry->msi_attrib.entry_nr;
+-
+- entry->address_lo_save =
+- readl(base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+- entry->address_hi_save =
+- readl(base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+- entry->data_save =
+- readl(base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_DATA_OFFSET);
+-
+- tail = msi_desc[vector]->link.tail;
+- vector = tail;
++ entry = msi_desc[irq];
++ read_msi_msg(irq, &entry->msg_save);
++
++ tail = msi_desc[irq]->link.tail;
++ irq = tail;
+ }
+ dev->irq = temp;
+
+@@ -645,9 +429,7 @@ void pci_restore_msix_state(struct pci_d
+ {
+ u16 save;
+ int pos;
+- int vector, head, tail = 0;
+- void __iomem *base;
+- int j;
++ int irq, head, tail = 0;
+ struct msi_desc *entry;
+ int temp;
+ struct pci_cap_saved_state *save_state;
+@@ -665,26 +447,15 @@ void pci_restore_msix_state(struct pci_d
+
+ /* route the table */
+ temp = dev->irq;
+- if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX))
++ if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
+ return;
+- vector = head = dev->irq;
++ irq = head = dev->irq;
+ while (head != tail) {
+- entry = msi_desc[vector];
+- base = entry->mask_base;
+- j = entry->msi_attrib.entry_nr;
+-
+- writel(entry->address_lo_save,
+- base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+- writel(entry->address_hi_save,
+- base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+- writel(entry->data_save,
+- base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_DATA_OFFSET);
+-
+- tail = msi_desc[vector]->link.tail;
+- vector = tail;
++ entry = msi_desc[irq];
++ write_msi_msg(irq, &entry->msg_save);
++
++ tail = msi_desc[irq]->link.tail;
++ irq = tail;
+ }
+ dev->irq = temp;
+
+@@ -693,104 +464,68 @@ void pci_restore_msix_state(struct pci_d
+ }
+ #endif
+
+-static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
+-{
+- int status;
+- u32 address_hi;
+- u32 address_lo;
+- u32 data;
+- int pos, vector = dev->irq;
+- u16 control;
+-
+- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+- pci_read_config_word(dev, msi_control_reg(pos), &control);
+-
+- /* Configure MSI capability structure */
+- status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data);
+- if (status < 0)
+- return status;
+-
+- pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
+- if (is_64bit_address(control)) {
+- pci_write_config_dword(dev,
+- msi_upper_address_reg(pos), address_hi);
+- pci_write_config_word(dev,
+- msi_data_reg(pos, 1), data);
+- } else
+- pci_write_config_word(dev,
+- msi_data_reg(pos, 0), data);
+- if (entry->msi_attrib.maskbit) {
+- unsigned int maskbits, temp;
+- /* All MSIs are unmasked by default, Mask them all */
+- pci_read_config_dword(dev,
+- msi_mask_bits_reg(pos, is_64bit_address(control)),
+- &maskbits);
+- temp = (1 << multi_msi_capable(control));
+- temp = ((temp - 1) & ~temp);
+- maskbits |= temp;
+- pci_write_config_dword(dev,
+- msi_mask_bits_reg(pos, is_64bit_address(control)),
+- maskbits);
+- }
+-
+- return 0;
+-}
+-
+ /**
+ * msi_capability_init - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with a single
+- * MSI vector, regardless of device function is capable of handling
++ * MSI irq, regardless of device function is capable of handling
+ * multiple messages. A return of zero indicates the successful setup
+- * of an entry zero with the new MSI vector or non-zero for otherwise.
++ * of an entry zero with the new MSI irq or non-zero for otherwise.
+ **/
+ static int msi_capability_init(struct pci_dev *dev)
+ {
+ int status;
+ struct msi_desc *entry;
+- int pos, vector;
++ int pos, irq;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+ /* MSI Entry Initialization */
+- entry = alloc_msi_entry();
+- if (!entry)
+- return -ENOMEM;
++ irq = create_msi_irq();
++ if (irq < 0)
++ return irq;
+
+- vector = get_msi_vector(dev);
+- if (vector < 0) {
+- kmem_cache_free(msi_cachep, entry);
+- return -EBUSY;
+- }
+- entry->link.head = vector;
+- entry->link.tail = vector;
++ entry = get_irq_data(irq);
++ entry->link.head = irq;
++ entry->link.tail = irq;
+ entry->msi_attrib.type = PCI_CAP_ID_MSI;
+- entry->msi_attrib.state = 0; /* Mark it not active */
++ entry->msi_attrib.is_64 = is_64bit_address(control);
+ entry->msi_attrib.entry_nr = 0;
+ entry->msi_attrib.maskbit = is_mask_bit_support(control);
+- entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */
+- dev->irq = vector;
+- entry->dev = dev;
++ entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
++ entry->msi_attrib.pos = pos;
+ if (is_mask_bit_support(control)) {
+ entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
+ is_64bit_address(control));
+ }
+- /* Replace with MSI handler */
+- irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
++ entry->dev = dev;
++ if (entry->msi_attrib.maskbit) {
++ unsigned int maskbits, temp;
++ /* All MSIs are unmasked by default, Mask them all */
++ pci_read_config_dword(dev,
++ msi_mask_bits_reg(pos, is_64bit_address(control)),
++ &maskbits);
++ temp = (1 << multi_msi_capable(control));
++ temp = ((temp - 1) & ~temp);
++ maskbits |= temp;
++ pci_write_config_dword(dev,
++ msi_mask_bits_reg(pos, is_64bit_address(control)),
++ maskbits);
++ }
+ /* Configure MSI capability structure */
+- status = msi_register_init(dev, entry);
+- if (status != 0) {
+- dev->irq = entry->msi_attrib.default_vector;
+- kmem_cache_free(msi_cachep, entry);
++ status = arch_setup_msi_irq(irq, dev);
++ if (status < 0) {
++ destroy_msi_irq(irq);
+ return status;
+ }
+
+- attach_msi_entry(entry, vector);
++ attach_msi_entry(entry, irq);
+ /* Set MSI enabled bits */
+ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+
++ dev->irq = irq;
+ return 0;
+ }
+
+@@ -801,18 +536,15 @@ static int msi_capability_init(struct pc
+ * @nvec: number of @entries
+ *
+ * Setup the MSI-X capability structure of device function with a
+- * single MSI-X vector. A return of zero indicates the successful setup of
+- * requested MSI-X entries with allocated vectors or non-zero for otherwise.
++ * single MSI-X irq. A return of zero indicates the successful setup of
++ * requested MSI-X entries with allocated irqs or non-zero for otherwise.
+ **/
+ static int msix_capability_init(struct pci_dev *dev,
+ struct msix_entry *entries, int nvec)
+ {
+ struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
+- u32 address_hi;
+- u32 address_lo;
+- u32 data;
+ int status;
+- int vector, pos, i, j, nr_entries, temp = 0;
++ int irq, pos, i, j, nr_entries, temp = 0;
+ unsigned long phys_addr;
+ u32 table_offset;
+ u16 control;
+@@ -834,65 +566,56 @@ static int msix_capability_init(struct p
+
+ /* MSI-X Table Initialization */
+ for (i = 0; i < nvec; i++) {
+- entry = alloc_msi_entry();
+- if (!entry)
+- break;
+- vector = get_msi_vector(dev);
+- if (vector < 0) {
+- kmem_cache_free(msi_cachep, entry);
++ irq = create_msi_irq();
++ if (irq < 0)
+ break;
+- }
+
++ entry = get_irq_data(irq);
+ j = entries[i].entry;
+- entries[i].vector = vector;
++ entries[i].vector = irq;
+ entry->msi_attrib.type = PCI_CAP_ID_MSIX;
+- entry->msi_attrib.state = 0; /* Mark it not active */
++ entry->msi_attrib.is_64 = 1;
+ entry->msi_attrib.entry_nr = j;
+ entry->msi_attrib.maskbit = 1;
+- entry->msi_attrib.default_vector = dev->irq;
++ entry->msi_attrib.default_irq = dev->irq;
++ entry->msi_attrib.pos = pos;
+ entry->dev = dev;
+ entry->mask_base = base;
+ if (!head) {
+- entry->link.head = vector;
+- entry->link.tail = vector;
++ entry->link.head = irq;
++ entry->link.tail = irq;
+ head = entry;
+ } else {
+ entry->link.head = temp;
+ entry->link.tail = tail->link.tail;
+- tail->link.tail = vector;
+- head->link.head = vector;
++ tail->link.tail = irq;
++ head->link.head = irq;
+ }
+- temp = vector;
++ temp = irq;
+ tail = entry;
+- /* Replace with MSI-X handler */
+- irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
+ /* Configure MSI-X capability structure */
+- status = msi_ops->setup(dev, vector,
+- &address_hi,
+- &address_lo,
+- &data);
+- if (status < 0)
++ status = arch_setup_msi_irq(irq, dev);
++ if (status < 0) {
++ destroy_msi_irq(irq);
+ break;
++ }
+
+- writel(address_lo,
+- base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+- writel(address_hi,
+- base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+- writel(data,
+- base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_DATA_OFFSET);
+- attach_msi_entry(entry, vector);
++ attach_msi_entry(entry, irq);
+ }
+ if (i != nvec) {
++ int avail = i - 1;
+ i--;
+ for (; i >= 0; i--) {
+- vector = (entries + i)->vector;
+- msi_free_vector(dev, vector, 0);
++ irq = (entries + i)->vector;
++ msi_free_irq(dev, irq);
+ (entries + i)->vector = 0;
+ }
+- return -EBUSY;
++ /* If we had some success report the number of irqs
++ * we succeeded in setting up.
++ */
++ if (avail <= 0)
++ avail = -EBUSY;
++ return avail;
+ }
+ /* Set MSI-X enabled bits */
+ enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+@@ -901,31 +624,51 @@ static int msix_capability_init(struct p
+ }
+
+ /**
+- * pci_enable_msi - configure device's MSI capability structure
++ * pci_msi_supported - check whether MSI may be enabled on device
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+- * Setup the MSI capability structure of device function with
+- * a single MSI vector upon its software driver call to request for
+- * MSI mode enabled on its hardware device function. A return of zero
+- * indicates the successful setup of an entry zero with the new MSI
+- * vector or non-zero for otherwise.
++ * Look at global flags, the device itself, and its parent busses
++ * to return 0 if MSI are supported for the device.
+ **/
+-int pci_enable_msi(struct pci_dev* dev)
++static
++int pci_msi_supported(struct pci_dev * dev)
+ {
+ struct pci_bus *bus;
+- int pos, temp, status = -EINVAL;
+- u16 control;
+
+- if (!pci_msi_enable || !dev)
+- return status;
+-
+- if (dev->no_msi)
+- return status;
++ /* MSI must be globally enabled and supported by the device */
++ if (!pci_msi_enable || !dev || dev->no_msi)
++ return -EINVAL;
+
++ /* Any bridge which does NOT route MSI transactions from it's
++ * secondary bus to it's primary bus must set NO_MSI flag on
++ * the secondary pci_bus.
++ * We expect only arch-specific PCI host bus controller driver
++ * or quirks for specific PCI bridges to be setting NO_MSI.
++ */
+ for (bus = dev->bus; bus; bus = bus->parent)
+ if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+ return -EINVAL;
+
++ return 0;
++}
++
++/**
++ * pci_enable_msi - configure device's MSI capability structure
++ * @dev: pointer to the pci_dev data structure of MSI device function
++ *
++ * Setup the MSI capability structure of device function with
++ * a single MSI irq upon its software driver call to request for
++ * MSI mode enabled on its hardware device function. A return of zero
++ * indicates the successful setup of an entry zero with the new MSI
++ * irq or non-zero for otherwise.
++ **/
++int pci_enable_msi(struct pci_dev* dev)
++{
++ int pos, temp, status;
++
++ if (pci_msi_supported(dev) < 0)
++ return -EINVAL;
++
+ temp = dev->irq;
+
+ status = msi_init();
+@@ -936,52 +679,25 @@ int pci_enable_msi(struct pci_dev* dev)
+ if (!pos)
+ return -EINVAL;
+
+- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+- /* Lookup Sucess */
+- unsigned long flags;
++ WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+
+- pci_read_config_word(dev, msi_control_reg(pos), &control);
+- if (control & PCI_MSI_FLAGS_ENABLE)
+- return 0; /* Already in MSI mode */
+- spin_lock_irqsave(&msi_lock, flags);
+- if (!vector_irq[dev->irq]) {
+- msi_desc[dev->irq]->msi_attrib.state = 0;
+- vector_irq[dev->irq] = -1;
+- nr_released_vectors--;
+- spin_unlock_irqrestore(&msi_lock, flags);
+- status = msi_register_init(dev, msi_desc[dev->irq]);
+- if (status == 0)
+- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+- return status;
+- }
+- spin_unlock_irqrestore(&msi_lock, flags);
+- dev->irq = temp;
+- }
+- /* Check whether driver already requested for MSI-X vectors */
++ /* Check whether driver already requested for MSI-X irqs */
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
++ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ printk(KERN_INFO "PCI: %s: Can't enable MSI. "
+- "Device already has MSI-X vectors assigned\n",
++ "Device already has MSI-X irq assigned\n",
+ pci_name(dev));
+ dev->irq = temp;
+ return -EINVAL;
+ }
+ status = msi_capability_init(dev);
+- if (!status) {
+- if (!pos)
+- nr_reserved_vectors--; /* Only MSI capable */
+- else if (nr_msix_devices > 0)
+- nr_msix_devices--; /* Both MSI and MSI-X capable,
+- but choose enabling MSI */
+- }
+-
+ return status;
+ }
+
+ void pci_disable_msi(struct pci_dev* dev)
+ {
+ struct msi_desc *entry;
+- int pos, default_vector;
++ int pos, default_irq;
+ u16 control;
+ unsigned long flags;
+
+@@ -998,41 +714,41 @@ void pci_disable_msi(struct pci_dev* dev
+ if (!(control & PCI_MSI_FLAGS_ENABLE))
+ return;
+
++ disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++
+ spin_lock_irqsave(&msi_lock, flags);
+ entry = msi_desc[dev->irq];
+ if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
+ spin_unlock_irqrestore(&msi_lock, flags);
+ return;
+ }
+- if (entry->msi_attrib.state) {
++ if (irq_has_action(dev->irq)) {
+ spin_unlock_irqrestore(&msi_lock, flags);
+ printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
+- "free_irq() on MSI vector %d\n",
++ "free_irq() on MSI irq %d\n",
+ pci_name(dev), dev->irq);
+- BUG_ON(entry->msi_attrib.state > 0);
++ BUG_ON(irq_has_action(dev->irq));
+ } else {
+- vector_irq[dev->irq] = 0; /* free it */
+- nr_released_vectors++;
+- default_vector = entry->msi_attrib.default_vector;
++ default_irq = entry->msi_attrib.default_irq;
+ spin_unlock_irqrestore(&msi_lock, flags);
+- /* Restore dev->irq to its default pin-assertion vector */
+- dev->irq = default_vector;
+- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
+- PCI_CAP_ID_MSI);
++ msi_free_irq(dev, dev->irq);
++
++ /* Restore dev->irq to its default pin-assertion irq */
++ dev->irq = default_irq;
+ }
+ }
+
+-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
++static int msi_free_irq(struct pci_dev* dev, int irq)
+ {
+ struct msi_desc *entry;
+ int head, entry_nr, type;
+ void __iomem *base;
+ unsigned long flags;
+
+- msi_ops->teardown(vector);
++ arch_teardown_msi_irq(irq);
+
+ spin_lock_irqsave(&msi_lock, flags);
+- entry = msi_desc[vector];
++ entry = msi_desc[irq];
+ if (!entry || entry->dev != dev) {
+ spin_unlock_irqrestore(&msi_lock, flags);
+ return -EINVAL;
+@@ -1044,112 +760,46 @@ static int msi_free_vector(struct pci_de
+ msi_desc[entry->link.head]->link.tail = entry->link.tail;
+ msi_desc[entry->link.tail]->link.head = entry->link.head;
+ entry->dev = NULL;
+- if (!reassign) {
+- vector_irq[vector] = 0;
+- nr_released_vectors++;
+- }
+- msi_desc[vector] = NULL;
++ msi_desc[irq] = NULL;
+ spin_unlock_irqrestore(&msi_lock, flags);
+
+- kmem_cache_free(msi_cachep, entry);
++ destroy_msi_irq(irq);
+
+ if (type == PCI_CAP_ID_MSIX) {
+- if (!reassign)
+- writel(1, base +
+- entry_nr * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
++ writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
++ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+
+- if (head == vector)
++ if (head == irq)
+ iounmap(base);
+ }
+
+ return 0;
+ }
+
+-static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
+-{
+- int vector = head, tail = 0;
+- int i, j = 0, nr_entries = 0;
+- void __iomem *base;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&msi_lock, flags);
+- while (head != tail) {
+- nr_entries++;
+- tail = msi_desc[vector]->link.tail;
+- if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr)
+- j = vector;
+- vector = tail;
+- }
+- if (*nvec > nr_entries) {
+- spin_unlock_irqrestore(&msi_lock, flags);
+- *nvec = nr_entries;
+- return -EINVAL;
+- }
+- vector = ((j > 0) ? j : head);
+- for (i = 0; i < *nvec; i++) {
+- j = msi_desc[vector]->msi_attrib.entry_nr;
+- msi_desc[vector]->msi_attrib.state = 0; /* Mark it not active */
+- vector_irq[vector] = -1; /* Mark it busy */
+- nr_released_vectors--;
+- entries[i].vector = vector;
+- if (j != (entries + i)->entry) {
+- base = msi_desc[vector]->mask_base;
+- msi_desc[vector]->msi_attrib.entry_nr =
+- (entries + i)->entry;
+- writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base +
+- (entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+- writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base +
+- (entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+- writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector,
+- base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_DATA_OFFSET);
+- }
+- vector = msi_desc[vector]->link.tail;
+- }
+- spin_unlock_irqrestore(&msi_lock, flags);
+-
+- return 0;
+-}
+-
+ /**
+ * pci_enable_msix - configure device's MSI-X capability structure
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ * @entries: pointer to an array of MSI-X entries
+- * @nvec: number of MSI-X vectors requested for allocation by device driver
++ * @nvec: number of MSI-X irqs requested for allocation by device driver
+ *
+ * Setup the MSI-X capability structure of device function with the number
+- * of requested vectors upon its software driver call to request for
++ * of requested irqs upon its software driver call to request for
+ * MSI-X mode enabled on its hardware device function. A return of zero
+ * indicates the successful configuration of MSI-X capability structure
+- * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
++ * with new allocated MSI-X irqs. A return of < 0 indicates a failure.
+ * Or a return of > 0 indicates that driver request is exceeding the number
+- * of vectors available. Driver should use the returned value to re-send
++ * of irqs available. Driver should use the returned value to re-send
+ * its request.
+ **/
+ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
+ {
+- struct pci_bus *bus;
+- int status, pos, nr_entries, free_vectors;
++ int status, pos, nr_entries;
+ int i, j, temp;
+ u16 control;
+- unsigned long flags;
+
+- if (!pci_msi_enable || !dev || !entries)
++ if (!entries || pci_msi_supported(dev) < 0)
+ return -EINVAL;
+
+- if (dev->no_msi)
+- return -EINVAL;
+-
+- for (bus = dev->bus; bus; bus = bus->parent)
+- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+- return -EINVAL;
+-
+ status = msi_init();
+ if (status < 0)
+ return status;
+@@ -1159,9 +809,6 @@ int pci_enable_msix(struct pci_dev* dev,
+ return -EINVAL;
+
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+- if (control & PCI_MSIX_FLAGS_ENABLE)
+- return -EINVAL; /* Already in MSI-X mode */
+-
+ nr_entries = multi_msix_capable(control);
+ if (nvec > nr_entries)
+ return -EINVAL;
+@@ -1176,56 +823,18 @@ int pci_enable_msix(struct pci_dev* dev,
+ }
+ }
+ temp = dev->irq;
+- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+- /* Lookup Sucess */
+- nr_entries = nvec;
+- /* Reroute MSI-X table */
+- if (reroute_msix_table(dev->irq, entries, &nr_entries)) {
+- /* #requested > #previous-assigned */
+- dev->irq = temp;
+- return nr_entries;
+- }
+- dev->irq = temp;
+- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+- return 0;
+- }
+- /* Check whether driver already requested for MSI vector */
++ WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
++
++ /* Check whether driver already requested for MSI irq */
+ if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
+- !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
++ !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
+- "Device already has an MSI vector assigned\n",
++ "Device already has an MSI irq assigned\n",
+ pci_name(dev));
+ dev->irq = temp;
+ return -EINVAL;
+ }
+-
+- spin_lock_irqsave(&msi_lock, flags);
+- /*
+- * msi_lock is provided to ensure that enough vectors resources are
+- * available before granting.
+- */
+- free_vectors = pci_vector_resources(last_alloc_vector,
+- nr_released_vectors);
+- /* Ensure that each MSI/MSI-X device has one vector reserved by
+- default to avoid any MSI-X driver to take all available
+- resources */
+- free_vectors -= nr_reserved_vectors;
+- /* Find the average of free vectors among MSI-X devices */
+- if (nr_msix_devices > 0)
+- free_vectors /= nr_msix_devices;
+- spin_unlock_irqrestore(&msi_lock, flags);
+-
+- if (nvec > free_vectors) {
+- if (free_vectors > 0)
+- return free_vectors;
+- else
+- return -EBUSY;
+- }
+-
+ status = msix_capability_init(dev, entries, nvec);
+- if (!status && nr_msix_devices > 0)
+- nr_msix_devices--;
+-
+ return status;
+ }
+
+@@ -1247,53 +856,47 @@ void pci_disable_msix(struct pci_dev* de
+ if (!(control & PCI_MSIX_FLAGS_ENABLE))
+ return;
+
++ disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++
+ temp = dev->irq;
+- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+- int state, vector, head, tail = 0, warning = 0;
++ if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
++ int irq, head, tail = 0, warning = 0;
+ unsigned long flags;
+
+- vector = head = dev->irq;
+- spin_lock_irqsave(&msi_lock, flags);
++ irq = head = dev->irq;
++ dev->irq = temp; /* Restore pin IRQ */
+ while (head != tail) {
+- state = msi_desc[vector]->msi_attrib.state;
+- if (state)
++ spin_lock_irqsave(&msi_lock, flags);
++ tail = msi_desc[irq]->link.tail;
++ spin_unlock_irqrestore(&msi_lock, flags);
++ if (irq_has_action(irq))
+ warning = 1;
+- else {
+- vector_irq[vector] = 0; /* free it */
+- nr_released_vectors++;
+- }
+- tail = msi_desc[vector]->link.tail;
+- vector = tail;
++ else if (irq != head) /* Release MSI-X irq */
++ msi_free_irq(dev, irq);
++ irq = tail;
+ }
+- spin_unlock_irqrestore(&msi_lock, flags);
++ msi_free_irq(dev, irq);
+ if (warning) {
+- dev->irq = temp;
+ printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+- "free_irq() on all MSI-X vectors\n",
++ "free_irq() on all MSI-X irqs\n",
+ pci_name(dev));
+ BUG_ON(warning > 0);
+- } else {
+- dev->irq = temp;
+- disable_msi_mode(dev,
+- pci_find_capability(dev, PCI_CAP_ID_MSIX),
+- PCI_CAP_ID_MSIX);
+-
+ }
+ }
+ }
+
+ /**
+- * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
++ * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
+ * @dev: pointer to the pci_dev data structure of MSI(X) device function
+ *
+ * Being called during hotplug remove, from which the device function
+- * is hot-removed. All previous assigned MSI/MSI-X vectors, if
++ * is hot-removed. All previous assigned MSI/MSI-X irqs, if
+ * allocated for this device function, are reclaimed to unused state,
+ * which may be used later on.
+ **/
+ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
+ {
+- int state, pos, temp;
++ int pos, temp;
+ unsigned long flags;
+
+ if (!pci_msi_enable || !dev)
+@@ -1301,42 +904,38 @@ void msi_remove_pci_irq_vectors(struct p
+
+ temp = dev->irq; /* Save IOAPIC IRQ */
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+- spin_lock_irqsave(&msi_lock, flags);
+- state = msi_desc[dev->irq]->msi_attrib.state;
+- spin_unlock_irqrestore(&msi_lock, flags);
+- if (state) {
++ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
++ if (irq_has_action(dev->irq)) {
+ printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
+- "called without free_irq() on MSI vector %d\n",
++ "called without free_irq() on MSI irq %d\n",
+ pci_name(dev), dev->irq);
+- BUG_ON(state > 0);
+- } else /* Release MSI vector assigned to this device */
+- msi_free_vector(dev, dev->irq, 0);
++ BUG_ON(irq_has_action(dev->irq));
++ } else /* Release MSI irq assigned to this device */
++ msi_free_irq(dev, dev->irq);
+ dev->irq = temp; /* Restore IOAPIC IRQ */
+ }
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+- int vector, head, tail = 0, warning = 0;
++ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
++ int irq, head, tail = 0, warning = 0;
+ void __iomem *base = NULL;
+
+- vector = head = dev->irq;
++ irq = head = dev->irq;
+ while (head != tail) {
+ spin_lock_irqsave(&msi_lock, flags);
+- state = msi_desc[vector]->msi_attrib.state;
+- tail = msi_desc[vector]->link.tail;
+- base = msi_desc[vector]->mask_base;
++ tail = msi_desc[irq]->link.tail;
++ base = msi_desc[irq]->mask_base;
+ spin_unlock_irqrestore(&msi_lock, flags);
+- if (state)
++ if (irq_has_action(irq))
+ warning = 1;
+- else if (vector != head) /* Release MSI-X vector */
+- msi_free_vector(dev, vector, 0);
+- vector = tail;
++ else if (irq != head) /* Release MSI-X irq */
++ msi_free_irq(dev, irq);
++ irq = tail;
+ }
+- msi_free_vector(dev, vector, 0);
++ msi_free_irq(dev, irq);
+ if (warning) {
+ iounmap(base);
+ printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
+- "called without free_irq() on all MSI-X vectors\n",
++ "called without free_irq() on all MSI-X irqs\n",
+ pci_name(dev));
+ BUG_ON(warning > 0);
+ }
+diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
+index 56951c3..f0cca17 100644
+--- a/drivers/pci/msi.h
++++ b/drivers/pci/msi.h
+@@ -7,84 +7,6 @@
+ #define MSI_H
+
+ /*
+- * MSI operation vector. Used by the msi core code (drivers/pci/msi.c)
+- * to abstract platform-specific tasks relating to MSI address generation
+- * and resource management.
+- */
+-struct msi_ops {
+- /**
+- * setup - generate an MSI bus address and data for a given vector
+- * @pdev: PCI device context (in)
+- * @vector: vector allocated by the msi core (in)
+- * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+- * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+- * @data: MSI data payload (out)
+- *
+- * Description: The setup op is used to generate a PCI bus addres and
+- * data which the msi core will program into the card MSI capability
+- * registers. The setup routine is responsible for picking an initial
+- * cpu to target the MSI at. The setup routine is responsible for
+- * examining pdev to determine the MSI capabilities of the card and
+- * generating a suitable address/data. The setup routine is
+- * responsible for allocating and tracking any system resources it
+- * needs to route the MSI to the cpu it picks, and for associating
+- * those resources with the passed in vector.
+- *
+- * Returns 0 if the MSI address/data was successfully setup.
+- **/
+-
+- int (*setup) (struct pci_dev *pdev, unsigned int vector,
+- u32 *addr_hi, u32 *addr_lo, u32 *data);
+-
+- /**
+- * teardown - release resources allocated by setup
+- * @vector: vector context for resources (in)
+- *
+- * Description: The teardown op is used to release any resources
+- * that were allocated in the setup routine associated with the passed
+- * in vector.
+- **/
+-
+- void (*teardown) (unsigned int vector);
+-
+- /**
+- * target - retarget an MSI at a different cpu
+- * @vector: vector context for resources (in)
+- * @cpu: new cpu to direct vector at (in)
+- * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+- * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+- *
+- * Description: The target op is used to redirect an MSI vector
+- * at a different cpu. addr_hi/addr_lo coming in are the existing
+- * values that the MSI core has programmed into the card. The
+- * target code is responsible for freeing any resources (if any)
+- * associated with the old address, and generating a new PCI bus
+- * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+- **/
+-
+- void (*target) (unsigned int vector, unsigned int cpu,
+- u32 *addr_hi, u32 *addr_lo);
+-};
+-
+-extern int msi_register(struct msi_ops *ops);
+-
+-#include <asm/msi.h>
+-
+-/*
+- * Assume the maximum number of hot plug slots supported by the system is about
+- * ten. The worstcase is that each of these slots is hot-added with a device,
+- * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
+- * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
+- * as below to ensure at least one message is assigned to each detected MSI/
+- * MSI-X device function.
+- */
+-#define NR_HP_RESERVED_VECTORS 20
+-
+-extern int vector_irq[NR_VECTORS];
+-extern void (*interrupt[NR_IRQS])(void);
+-extern int pci_vector_resources(int last, int nr_released);
+-
+-/*
+ * MSI-X Address Register
+ */
+ #define PCI_MSIX_FLAGS_QSIZE 0x7FF
+@@ -110,8 +32,8 @@ extern int pci_vector_resources(int last
+ (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
+ #define multi_msi_enable(control, num) \
+ control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
+-#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT)
+-#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT)
++#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
++#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
+ #define msi_enable(control, num) multi_msi_enable(control, num); \
+ control |= PCI_MSI_FLAGS_ENABLE
+
+@@ -125,32 +47,4 @@ extern int pci_vector_resources(int last
+ #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
+ #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
+
+-struct msi_desc {
+- struct {
+- __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
+- __u8 maskbit : 1; /* mask-pending bit supported ? */
+- __u8 state : 1; /* {0: free, 1: busy} */
+- __u8 reserved: 1; /* reserved */
+- __u8 entry_nr; /* specific enabled entry */
+- __u8 default_vector; /* default pre-assigned vector */
+- __u8 unused; /* formerly unused destination cpu*/
+- }msi_attrib;
+-
+- struct {
+- __u16 head;
+- __u16 tail;
+- }link;
+-
+- void __iomem *mask_base;
+- struct pci_dev *dev;
+-
+-#ifdef CONFIG_PM
+- /* PM save area for MSIX address/data */
+-
+- u32 address_hi_save;
+- u32 address_lo_save;
+- u32 data_save;
+-#endif
+-};
+-
+ #endif /* MSI_H */
+diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
+index 474e9cd..194f1d2 100644
+--- a/drivers/pci/pci-driver.c
++++ b/drivers/pci/pci-driver.c
+@@ -17,6 +17,16 @@
+ * Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
++/* multithreaded probe logic */
++static int pci_multithread_probe =
++#ifdef CONFIG_PCI_MULTITHREAD_PROBE
++ 1;
++#else
++ 0;
++#endif
++__module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644);
++
++
+ /*
+ * Dynamic device IDs are disabled for !CONFIG_HOTPLUG
+ */
+@@ -46,6 +56,7 @@ store_new_id(struct device_driver *drive
+ subdevice=PCI_ANY_ID, class=0, class_mask=0;
+ unsigned long driver_data=0;
+ int fields=0;
++ int retval = 0;
+
+ fields = sscanf(buf, "%x %x %x %x %x %x %lux",
+ &vendor, &device, &subvendor, &subdevice,
+@@ -72,10 +83,12 @@ store_new_id(struct device_driver *drive
+ spin_unlock(&pdrv->dynids.lock);
+
+ if (get_driver(&pdrv->driver)) {
+- driver_attach(&pdrv->driver);
++ retval = driver_attach(&pdrv->driver);
+ put_driver(&pdrv->driver);
+ }
+
++ if (retval)
++ return retval;
+ return count;
+ }
+ static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+@@ -252,6 +265,13 @@ static int pci_device_remove(struct devi
+ }
+
+ /*
++ * If the device is still on, set the power state as "unknown",
++ * since it might change by the next time we load the driver.
++ */
++ if (pci_dev->current_state == PCI_D0)
++ pci_dev->current_state = PCI_UNKNOWN;
++
++ /*
+ * We would love to complain here if pci_dev->is_enabled is set, that
+ * the driver should have called pci_disable_device(), but the
+ * unfortunate fact is there are too many odd BIOS and bridge setups
+@@ -275,10 +295,28 @@ static int pci_device_suspend(struct dev
+ suspend_report_result(drv->suspend, i);
+ } else {
+ pci_save_state(pci_dev);
++ /*
++ * mark its power state as "unknown", since we don't know if
++ * e.g. the BIOS will change its device state when we suspend.
++ */
++ if (pci_dev->current_state == PCI_D0)
++ pci_dev->current_state = PCI_UNKNOWN;
+ }
+ return i;
+ }
+
++static int pci_device_suspend_late(struct device * dev, pm_message_t state)
++{
++ struct pci_dev * pci_dev = to_pci_dev(dev);
++ struct pci_driver * drv = pci_dev->driver;
++ int i = 0;
++
++ if (drv && drv->suspend_late) {
++ i = drv->suspend_late(pci_dev, state);
++ suspend_report_result(drv->suspend_late, i);
++ }
++ return i;
++}
+
+ /*
+ * Default resume method for devices that have no driver provided resume,
+@@ -313,6 +351,17 @@ static int pci_device_resume(struct devi
+ return error;
+ }
+
++static int pci_device_resume_early(struct device * dev)
++{
++ int error = 0;
++ struct pci_dev * pci_dev = to_pci_dev(dev);
++ struct pci_driver * drv = pci_dev->driver;
++
++ if (drv && drv->resume_early)
++ error = drv->resume_early(pci_dev);
++ return error;
++}
++
+ static void pci_device_shutdown(struct device *dev)
+ {
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+@@ -386,6 +435,11 @@ int __pci_register_driver(struct pci_dri
+ drv->driver.owner = owner;
+ drv->driver.kobj.ktype = &pci_driver_kobj_type;
+
++ if (pci_multithread_probe)
++ drv->driver.multithread_probe = pci_multithread_probe;
++ else
++ drv->driver.multithread_probe = drv->multithread_probe;
++
+ spin_lock_init(&drv->dynids.lock);
+ INIT_LIST_HEAD(&drv->dynids.list);
+
+@@ -509,8 +563,10 @@ struct bus_type pci_bus_type = {
+ .probe = pci_device_probe,
+ .remove = pci_device_remove,
+ .suspend = pci_device_suspend,
+- .shutdown = pci_device_shutdown,
++ .suspend_late = pci_device_suspend_late,
++ .resume_early = pci_device_resume_early,
+ .resume = pci_device_resume,
++ .shutdown = pci_device_shutdown,
+ .dev_attrs = pci_dev_attrs,
+ };
+
+diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
+index fdefa7d..a1d2e97 100644
+--- a/drivers/pci/pci-sysfs.c
++++ b/drivers/pci/pci-sysfs.c
+@@ -117,6 +117,7 @@ is_enabled_store(struct device *dev, str
+ const char *buf, size_t count)
+ {
+ struct pci_dev *pdev = to_pci_dev(dev);
++ int retval = 0;
+
+ /* this can crash the machine when done on the "wrong" device */
+ if (!capable(CAP_SYS_ADMIN))
+@@ -126,11 +127,53 @@ is_enabled_store(struct device *dev, str
+ pci_disable_device(pdev);
+
+ if (*buf == '1')
+- pci_enable_device(pdev);
++ retval = pci_enable_device(pdev);
+
++ if (retval)
++ return retval;
+ return count;
+ }
+
++static ssize_t
++msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++
++ if (!pdev->subordinate)
++ return 0;
++
++ return sprintf (buf, "%u\n",
++ !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
++}
++
++static ssize_t
++msi_bus_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++
++ /* bad things may happen if the no_msi flag is changed
++ * while some drivers are loaded */
++ if (!capable(CAP_SYS_ADMIN))
++ return count;
++
++ if (!pdev->subordinate)
++ return count;
++
++ if (*buf == '0') {
++ pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
++ dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"
++ " bad things could happen.\n");
++ }
++
++ if (*buf == '1') {
++ pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
++ dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
++ " bad things could happen.\n");
++ }
++
++ return count;
++}
+
+ struct device_attribute pci_dev_attrs[] = {
+ __ATTR_RO(resource),
+@@ -145,6 +188,7 @@ struct device_attribute pci_dev_attrs[]
+ __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
+ __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
+ broken_parity_status_show,broken_parity_status_store),
++ __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
+ __ATTR_NULL,
+ };
+
+@@ -385,15 +429,38 @@ pci_mmap_resource(struct kobject *kobj,
+ }
+
+ /**
++ * pci_remove_resource_files - cleanup resource files
++ * @dev: dev to cleanup
++ *
++ * If we created resource files for @dev, remove them from sysfs and
++ * free their resources.
++ */
++static void
++pci_remove_resource_files(struct pci_dev *pdev)
++{
++ int i;
++
++ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
++ struct bin_attribute *res_attr;
++
++ res_attr = pdev->res_attr[i];
++ if (res_attr) {
++ sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
++ kfree(res_attr);
++ }
++ }
++}
++
++/**
+ * pci_create_resource_files - create resource files in sysfs for @dev
+ * @dev: dev in question
+ *
+ * Walk the resources in @dev creating files for each resource available.
+ */
+-static void
+-pci_create_resource_files(struct pci_dev *pdev)
++static int pci_create_resource_files(struct pci_dev *pdev)
+ {
+ int i;
++ int retval;
+
+ /* Expose the PCI resources from this device as files */
+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+@@ -416,35 +483,19 @@ pci_create_resource_files(struct pci_dev
+ res_attr->size = pci_resource_len(pdev, i);
+ res_attr->mmap = pci_mmap_resource;
+ res_attr->private = &pdev->resource[i];
+- sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+- }
+- }
+-}
+-
+-/**
+- * pci_remove_resource_files - cleanup resource files
+- * @dev: dev to cleanup
+- *
+- * If we created resource files for @dev, remove them from sysfs and
+- * free their resources.
+- */
+-static void
+-pci_remove_resource_files(struct pci_dev *pdev)
+-{
+- int i;
+-
+- for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+- struct bin_attribute *res_attr;
+-
+- res_attr = pdev->res_attr[i];
+- if (res_attr) {
+- sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+- kfree(res_attr);
++ retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
++ if (retval) {
++ pci_remove_resource_files(pdev);
++ return retval;
++ }
++ } else {
++ return -ENOMEM;
+ }
+ }
++ return 0;
+ }
+ #else /* !HAVE_PCI_MMAP */
+-static inline void pci_create_resource_files(struct pci_dev *dev) { return; }
++static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
+ static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
+ #endif /* HAVE_PCI_MMAP */
+
+@@ -529,22 +580,27 @@ static struct bin_attribute pcie_config_
+ .write = pci_write_config,
+ };
+
+-int pci_create_sysfs_dev_files (struct pci_dev *pdev)
++int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
+ {
++ struct bin_attribute *rom_attr = NULL;
++ int retval;
++
+ if (!sysfs_initialized)
+ return -EACCES;
+
+ if (pdev->cfg_size < 4096)
+- sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
++ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
+ else
+- sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
++ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
++ if (retval)
++ goto err;
+
+- pci_create_resource_files(pdev);
++ retval = pci_create_resource_files(pdev);
++ if (retval)
++ goto err_bin_file;
+
+ /* If the device has a ROM, try to expose it in sysfs. */
+ if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
+- struct bin_attribute *rom_attr;
+-
+ rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
+ if (rom_attr) {
+ pdev->rom_attr = rom_attr;
+@@ -554,13 +610,28 @@ int pci_create_sysfs_dev_files (struct p
+ rom_attr->attr.owner = THIS_MODULE;
+ rom_attr->read = pci_read_rom;
+ rom_attr->write = pci_write_rom;
+- sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
++ retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
++ if (retval)
++ goto err_rom;
++ } else {
++ retval = -ENOMEM;
++ goto err_bin_file;
+ }
+ }
+ /* add platform-specific attributes */
+ pcibios_add_platform_entries(pdev);
+-
++
+ return 0;
++
++err_rom:
++ kfree(rom_attr);
++err_bin_file:
++ if (pdev->cfg_size < 4096)
++ sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
++ else
++ sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
++err:
++ return retval;
+ }
+
+ /**
+@@ -589,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct p
+ static int __init pci_sysfs_init(void)
+ {
+ struct pci_dev *pdev = NULL;
+-
++ int retval;
++
+ sysfs_initialized = 1;
+- for_each_pci_dev(pdev)
+- pci_create_sysfs_dev_files(pdev);
++ for_each_pci_dev(pdev) {
++ retval = pci_create_sysfs_dev_files(pdev);
++ if (retval)
++ return retval;
++ }
+
+ return 0;
+ }
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index 9f79dd6..a544997 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -432,10 +432,12 @@ pci_power_t pci_choose_state(struct pci_
+ case PM_EVENT_ON:
+ return PCI_D0;
+ case PM_EVENT_FREEZE:
++ case PM_EVENT_PRETHAW:
++ /* REVISIT both freeze and pre-thaw "should" use D0 */
+ case PM_EVENT_SUSPEND:
+ return PCI_D3hot;
+ default:
+- printk("They asked me for state %d\n", state.event);
++ printk("Unrecognized suspend event %d\n", state.event);
+ BUG();
+ }
+ return PCI_D0;
+@@ -443,6 +445,51 @@ pci_power_t pci_choose_state(struct pci_
+
+ EXPORT_SYMBOL(pci_choose_state);
+
++static int pci_save_pcie_state(struct pci_dev *dev)
++{
++ int pos, i = 0;
++ struct pci_cap_saved_state *save_state;
++ u16 *cap;
++
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ if (pos <= 0)
++ return 0;
++
++ save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
++ if (!save_state) {
++ dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
++ return -ENOMEM;
++ }
++ cap = (u16 *)&save_state->data[0];
++
++ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
++ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
++ pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
++ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
++ pci_add_saved_cap(dev, save_state);
++ return 0;
++}
++
++static void pci_restore_pcie_state(struct pci_dev *dev)
++{
++ int i = 0, pos;
++ struct pci_cap_saved_state *save_state;
++ u16 *cap;
++
++ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ if (!save_state || pos <= 0)
++ return;
++ cap = (u16 *)&save_state->data[0];
++
++ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
++ pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
++ pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
++ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
++ pci_remove_saved_cap(save_state);
++ kfree(save_state);
++}
++
+ /**
+ * pci_save_state - save the PCI configuration space of a device before suspending
+ * @dev: - PCI device that we're dealing with
+@@ -458,6 +505,8 @@ pci_save_state(struct pci_dev *dev)
+ return i;
+ if ((i = pci_save_msix_state(dev)) != 0)
+ return i;
++ if ((i = pci_save_pcie_state(dev)) != 0)
++ return i;
+ return 0;
+ }
+
+@@ -471,6 +520,9 @@ pci_restore_state(struct pci_dev *dev)
+ int i;
+ int val;
+
++ /* PCI Express register must be restored first */
++ pci_restore_pcie_state(dev);
++
+ /*
+ * The Base Address register should be programmed before the command
+ * register(s)
+@@ -953,13 +1005,12 @@ static int __devinit pci_setup(char *str
+ }
+ str = k;
+ }
+- return 1;
++ return 0;
+ }
++early_param("pci", pci_setup);
+
+ device_initcall(pci_init);
+
+-__setup("pci=", pci_setup);
+-
+ #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
+ /* FIXME: Some boxes have multiple ISA bridges! */
+ struct pci_dev *isa_bridge;
+diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
+index 08d58fc..6bf327d 100644
+--- a/drivers/pci/pci.h
++++ b/drivers/pci/pci.h
+@@ -42,7 +42,7 @@ extern void pci_remove_legacy_files(stru
+ /* Lock for read/write access to pci device and bus lists */
+ extern struct rw_semaphore pci_bus_sem;
+
+-#ifdef CONFIG_X86_IO_APIC
++#ifdef CONFIG_PCI_MSI
+ extern int pci_msi_quirk;
+ #else
+ #define pci_msi_quirk 0
+diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
+index 1012db8..0ad92a8 100644
+--- a/drivers/pci/pcie/Kconfig
++++ b/drivers/pci/pcie/Kconfig
+@@ -34,3 +34,4 @@ config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
+
+ When in doubt, say N.
+
++source "drivers/pci/pcie/aer/Kconfig"
+diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
+index 984fa87..e00fb99 100644
+--- a/drivers/pci/pcie/Makefile
++++ b/drivers/pci/pcie/Makefile
+@@ -5,3 +5,6 @@
+ pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o
+
+ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
++
++# Build PCI Express AER if needed
++obj-$(CONFIG_PCIEAER) += aer/
+diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
+new file mode 100644
+index 0000000..3f37a60
+--- /dev/null
++++ b/drivers/pci/pcie/aer/Kconfig
+@@ -0,0 +1,12 @@
++#
++# PCI Express Root Port Device AER Configuration
++#
++
++config PCIEAER
++ boolean "Root Port Advanced Error Reporting support"
++ depends on PCIEPORTBUS && ACPI
++ default y
++ help
++ This enables PCI Express Root Port Advanced Error Reporting
++ (AER) driver support. Error reporting messages sent to Root
++ Port will be handled by PCI Express AER driver.
+diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile
+new file mode 100644
+index 0000000..15a4f40
+--- /dev/null
++++ b/drivers/pci/pcie/aer/Makefile
+@@ -0,0 +1,8 @@
++#
++# Makefile for PCI-Express Root Port Advanced Error Reporting Driver
++#
++
++obj-$(CONFIG_PCIEAER) += aerdriver.o
++
++aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o
++
+diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
+new file mode 100644
+index 0000000..04c43ef
+--- /dev/null
++++ b/drivers/pci/pcie/aer/aerdrv.c
+@@ -0,0 +1,345 @@
++/*
++ * drivers/pci/pcie/aer/aerdrv.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.
++ *
++ * This file implements the AER root port service driver. The driver will
++ * register an irq handler. When root port triggers an AER interrupt, the irq
++ * handler will collect root port status and schedule a work.
++ *
++ * Copyright (C) 2006 Intel Corp.
++ * Tom Long Nguyen (tom.l.nguyen at intel.com)
++ * Zhang Yanmin (yanmin.zhang at intel.com)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/pm.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/pcieport_if.h>
++
++#include "aerdrv.h"
++
++/*
++ * Version Information
++ */
++#define DRIVER_VERSION "v1.0"
++#define DRIVER_AUTHOR "tom.l.nguyen at intel.com"
++#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++static int __devinit aer_probe (struct pcie_device *dev,
++ const struct pcie_port_service_id *id );
++static void aer_remove(struct pcie_device *dev);
++static int aer_suspend(struct pcie_device *dev, pm_message_t state)
++{return 0;}
++static int aer_resume(struct pcie_device *dev) {return 0;}
++static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
++ enum pci_channel_state error);
++static void aer_error_resume(struct pci_dev *dev);
++static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
++
++/*
++ * PCI Express bus's AER Root service driver data structure
++ */
++static struct pcie_port_service_id aer_id[] = {
++ {
++ .vendor = PCI_ANY_ID,
++ .device = PCI_ANY_ID,
++ .port_type = PCIE_RC_PORT,
++ .service_type = PCIE_PORT_SERVICE_AER,
++ },
++ { /* end: all zeroes */ }
++};
++
++static struct pci_error_handlers aer_error_handlers = {
++ .error_detected = aer_error_detected,
++ .resume = aer_error_resume,
++};
++
++static struct pcie_port_service_driver aerdrv = {
++ .name = "aer",
++ .id_table = &aer_id[0],
++
++ .probe = aer_probe,
++ .remove = aer_remove,
++
++ .suspend = aer_suspend,
++ .resume = aer_resume,
++
++ .err_handler = &aer_error_handlers,
++
++ .reset_link = aer_root_reset,
++};
++
++/**
++ * aer_irq - Root Port's ISR
++ * @irq: IRQ assigned to Root Port
++ * @context: pointer to Root Port data structure
++ *
++ * Invoked when Root Port detects AER messages.
++ **/
++static irqreturn_t aer_irq(int irq, void *context)
++{
++ unsigned int status, id;
++ struct pcie_device *pdev = (struct pcie_device *)context;
++ struct aer_rpc *rpc = get_service_data(pdev);
++ int next_prod_idx;
++ unsigned long flags;
++ int pos;
++
++ pos = pci_find_aer_capability(pdev->port);
++ /*
++ * Must lock access to Root Error Status Reg, Root Error ID Reg,
++ * and Root error producer/consumer index
++ */
++ spin_lock_irqsave(&rpc->e_lock, flags);
++
++ /* Read error status */
++ pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
++ if (!(status & ROOT_ERR_STATUS_MASKS)) {
++ spin_unlock_irqrestore(&rpc->e_lock, flags);
++ return IRQ_NONE;
++ }
++
++ /* Read error source and clear error status */
++ pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
++ pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
++
++ /* Store error source for later DPC handler */
++ next_prod_idx = rpc->prod_idx + 1;
++ if (next_prod_idx == AER_ERROR_SOURCES_MAX)
++ next_prod_idx = 0;
++ if (next_prod_idx == rpc->cons_idx) {
++ /*
++ * Error Storm Condition - possibly the same error occurred.
++ * Drop the error.
++ */
++ spin_unlock_irqrestore(&rpc->e_lock, flags);
++ return IRQ_HANDLED;
++ }
++ rpc->e_sources[rpc->prod_idx].status = status;
++ rpc->e_sources[rpc->prod_idx].id = id;
++ rpc->prod_idx = next_prod_idx;
++ spin_unlock_irqrestore(&rpc->e_lock, flags);
++
++ /* Invoke DPC handler */
++ schedule_work(&rpc->dpc_handler);
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * aer_alloc_rpc - allocate Root Port data structure
++ * @dev: pointer to the pcie_dev data structure
++ *
++ * Invoked when Root Port's AER service is loaded.
++ **/
++static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
++{
++ struct aer_rpc *rpc;
++
++ if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc),
++ GFP_KERNEL)))
++ return NULL;
++
++ memset(rpc, 0, sizeof(struct aer_rpc));
++ /*
++ * Initialize Root lock access, e_lock, to Root Error Status Reg,
++ * Root Error ID Reg, and Root error producer/consumer index.
++ */
++ rpc->e_lock = SPIN_LOCK_UNLOCKED;
++
++ rpc->rpd = dev;
++ INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev);
++ rpc->prod_idx = rpc->cons_idx = 0;
++ mutex_init(&rpc->rpc_mutex);
++ init_waitqueue_head(&rpc->wait_release);
++
++ /* Use PCIE bus function to store rpc into PCIE device */
++ set_service_data(dev, rpc);
++
++ return rpc;
++}
++
++/**
++ * aer_remove - clean up resources
++ * @dev: pointer to the pcie_dev data structure
++ *
++ * Invoked when PCI Express bus unloads or AER probe fails.
++ **/
++static void aer_remove(struct pcie_device *dev)
++{
++ struct aer_rpc *rpc = get_service_data(dev);
++
++ if (rpc) {
++ /* If register interrupt service, it must be free. */
++ if (rpc->isr)
++ free_irq(dev->irq, dev);
++
++ wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
++
++ aer_delete_rootport(rpc);
++ set_service_data(dev, NULL);
++ }
++}
++
++/**
++ * aer_probe - initialize resources
++ * @dev: pointer to the pcie_dev data structure
++ * @id: pointer to the service id data structure
++ *
++ * Invoked when PCI Express bus loads AER service driver.
++ **/
++static int __devinit aer_probe (struct pcie_device *dev,
++ const struct pcie_port_service_id *id )
++{
++ int status;
++ struct aer_rpc *rpc;
++ struct device *device = &dev->device;
++
++ /* Init */
++ if ((status = aer_init(dev)))
++ return status;
++
++ /* Alloc rpc data structure */
++ if (!(rpc = aer_alloc_rpc(dev))) {
++ printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n",
++ __FUNCTION__, device->bus_id);
++ aer_remove(dev);
++ return -ENOMEM;
++ }
++
++ /* Request IRQ ISR */
++ if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv",
++ dev))) {
++ printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n",
++ __FUNCTION__, device->bus_id);
++ aer_remove(dev);
++ return status;
++ }
++
++ rpc->isr = 1;
++
++ aer_enable_rootport(rpc);
++
++ return status;
++}
++
++/**
++ * aer_root_reset - reset link on Root Port
++ * @dev: pointer to Root Port's pci_dev data structure
++ *
++ * Invoked by Port Bus driver when performing link reset at Root Port.
++ **/
++static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
++{
++ u16 p2p_ctrl;
++ u32 status;
++ int pos;
++
++ pos = pci_find_aer_capability(dev);
++
++ /* Disable Root's interrupt in response to error messages */
++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
++
++ /* Assert Secondary Bus Reset */
++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
++ p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
++
++ /* De-assert Secondary Bus Reset */
++ p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
++
++ /*
++ * System software must wait for at least 100ms from the end
++ * of a reset of one or more device before it is permitted
++ * to issue Configuration Requests to those devices.
++ */
++ msleep(200);
++ printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id);
++
++ /* Enable Root Port's interrupt in response to error messages */
++ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
++ pci_write_config_dword(dev,
++ pos + PCI_ERR_ROOT_COMMAND,
++ ROOT_PORT_INTR_ON_MESG_MASK);
++
++ return PCI_ERS_RESULT_RECOVERED;
++}
++
++/**
++ * aer_error_detected - update severity status
++ * @dev: pointer to Root Port's pci_dev data structure
++ * @error: error severity being notified by port bus
++ *
++ * Invoked by Port Bus driver during error recovery.
++ **/
++static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
++ enum pci_channel_state error)
++{
++ /* Root Port has no impact. Always recovers. */
++ return PCI_ERS_RESULT_CAN_RECOVER;
++}
++
++/**
++ * aer_error_resume - clean up corresponding error status bits
++ * @dev: pointer to Root Port's pci_dev data structure
++ *
++ * Invoked by Port Bus driver during nonfatal recovery.
++ **/
++static void aer_error_resume(struct pci_dev *dev)
++{
++ int pos;
++ u32 status, mask;
++ u16 reg16;
++
++ /* Clean up Root device status */
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16);
++ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
++
++ /* Clean AER Root Error Status */
++ pos = pci_find_aer_capability(dev);
++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
++ if (dev->error_state == pci_channel_io_normal)
++ status &= ~mask; /* Clear corresponding nonfatal bits */
++ else
++ status &= mask; /* Clear corresponding fatal bits */
++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
++}
++
++/**
++ * aer_service_init - register AER root service driver
++ *
++ * Invoked when AER root service driver is loaded.
++ **/
++static int __init aer_service_init(void)
++{
++ return pcie_port_service_register(&aerdrv);
++}
++
++/**
++ * aer_service_exit - unregister AER root service driver
++ *
++ * Invoked when AER root service driver is unloaded.
++ **/
++static void __exit aer_service_exit(void)
++{
++ pcie_port_service_unregister(&aerdrv);
++}
++
++module_init(aer_service_init);
++module_exit(aer_service_exit);
+diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
+new file mode 100644
+index 0000000..daf0cad
+--- /dev/null
++++ b/drivers/pci/pcie/aer/aerdrv.h
+@@ -0,0 +1,125 @@
++/*
++ * Copyright (C) 2006 Intel Corp.
++ * Tom Long Nguyen (tom.l.nguyen at intel.com)
++ * Zhang Yanmin (yanmin.zhang at intel.com)
++ *
++ */
++
++#ifndef _AERDRV_H_
++#define _AERDRV_H_
++
++#include <linux/pcieport_if.h>
++#include <linux/aer.h>
++
++#define AER_NONFATAL 0
++#define AER_FATAL 1
++#define AER_CORRECTABLE 2
++#define AER_UNCORRECTABLE 4
++#define AER_ERROR_MASK 0x001fffff
++#define AER_ERROR(d) (d & AER_ERROR_MASK)
++
++#define OSC_METHOD_RUN_SUCCESS 0
++#define OSC_METHOD_NOT_SUPPORTED 1
++#define OSC_METHOD_RUN_FAILURE 2
++
++/* Root Error Status Register Bits */
++#define ROOT_ERR_STATUS_MASKS 0x0f
++
++#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \
++ PCI_EXP_RTCTL_SENFEE| \
++ PCI_EXP_RTCTL_SEFEE)
++#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \
++ PCI_ERR_ROOT_CMD_NONFATAL_EN| \
++ PCI_ERR_ROOT_CMD_FATAL_EN)
++#define ERR_COR_ID(d) (d & 0xffff)
++#define ERR_UNCOR_ID(d) (d >> 16)
++
++#define AER_SUCCESS 0
++#define AER_UNSUCCESS 1
++#define AER_ERROR_SOURCES_MAX 100
++
++#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \
++ PCI_ERR_UNC_ECRC| \
++ PCI_ERR_UNC_UNSUP| \
++ PCI_ERR_UNC_COMP_ABORT| \
++ PCI_ERR_UNC_UNX_COMP| \
++ PCI_ERR_UNC_MALF_TLP)
++
++/* AER Error Info Flags */
++#define AER_TLP_HEADER_VALID_FLAG 0x00000001
++#define AER_MULTI_ERROR_VALID_FLAG 0x00000002
++
++#define ERR_CORRECTABLE_ERROR_MASK 0x000031c1
++#define ERR_UNCORRECTABLE_ERROR_MASK 0x001ff010
++
++struct header_log_regs {
++ unsigned int dw0;
++ unsigned int dw1;
++ unsigned int dw2;
++ unsigned int dw3;
++};
++
++struct aer_err_info {
++ int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */
++ int flags;
++ unsigned int status; /* COR/UNCOR Error Status */
++ struct header_log_regs tlp; /* TLP Header */
++};
++
++struct aer_err_source {
++ unsigned int status;
++ unsigned int id;
++};
++
++struct aer_rpc {
++ struct pcie_device *rpd; /* Root Port device */
++ struct work_struct dpc_handler;
++ struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
++ unsigned short prod_idx; /* Error Producer Index */
++ unsigned short cons_idx; /* Error Consumer Index */
++ int isr;
++ spinlock_t e_lock; /*
++ * Lock access to Error Status/ID Regs
++ * and error producer/consumer index
++ */
++ struct mutex rpc_mutex; /*
++ * only one thread could do
++ * recovery on the same
++ * root port hierachy
++ */
++ wait_queue_head_t wait_release;
++};
++
++struct aer_broadcast_data {
++ enum pci_channel_state state;
++ enum pci_ers_result result;
++};
++
++static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
++ enum pci_ers_result new)
++{
++ switch (orig) {
++ case PCI_ERS_RESULT_CAN_RECOVER:
++ case PCI_ERS_RESULT_RECOVERED:
++ orig = new;
++ break;
++ case PCI_ERS_RESULT_DISCONNECT:
++ if (new == PCI_ERS_RESULT_NEED_RESET)
++ orig = new;
++ break;
++ default:
++ break;
++ }
++
++ return orig;
++}
++
++extern struct bus_type pcie_port_bus_type;
++extern void aer_enable_rootport(struct aer_rpc *rpc);
++extern void aer_delete_rootport(struct aer_rpc *rpc);
++extern int aer_init(struct pcie_device *dev);
++extern void aer_isr(void *context);
++extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
++extern int aer_osc_setup(struct pci_dev *dev);
++
++#endif //_AERDRV_H_
+diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
+new file mode 100644
+index 0000000..fa68e89
+--- /dev/null
++++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
+@@ -0,0 +1,68 @@
++/*
++ * Access ACPI _OSC method
++ *
++ * Copyright (C) 2006 Intel Corp.
++ * Tom Long Nguyen (tom.l.nguyen at intel.com)
++ * Zhang Yanmin (yanmin.zhang at intel.com)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/pm.h>
++#include <linux/suspend.h>
++#include <linux/acpi.h>
++#include <linux/pci-acpi.h>
++#include <linux/delay.h>
++#include "aerdrv.h"
++
++/**
++ * aer_osc_setup - run ACPI _OSC method
++ *
++ * Return:
++ * Zero if success. Nonzero for otherwise.
++ *
++ * Invoked when PCIE bus loads AER service driver. To avoid conflict with
++ * BIOS AER support requires BIOS to yield AER control to OS native driver.
++ **/
++int aer_osc_setup(struct pci_dev *dev)
++{
++ int retval = OSC_METHOD_RUN_SUCCESS;
++ acpi_status status;
++ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
++ struct pci_dev *pdev = dev;
++ struct pci_bus *parent;
++
++ while (!handle) {
++ if (!pdev || !pdev->bus->parent)
++ break;
++ parent = pdev->bus->parent;
++ if (!parent->self)
++ /* Parent must be a host bridge */
++ handle = acpi_get_pci_rootbridge_handle(
++ pci_domain_nr(parent),
++ parent->number);
++ else
++ handle = DEVICE_ACPI_HANDLE(
++ &(parent->self->dev));
++ pdev = parent->self;
++ }
++
++ if (!handle)
++ return OSC_METHOD_NOT_SUPPORTED;
++
++ pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
++ status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL |
++ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
++ if (ACPI_FAILURE(status)) {
++ if (status == AE_SUPPORT)
++ retval = OSC_METHOD_NOT_SUPPORTED;
++ else
++ retval = OSC_METHOD_RUN_FAILURE;
++ }
++
++ return retval;
++}
++
+diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
+new file mode 100644
+index 0000000..1c7e660
+--- /dev/null
++++ b/drivers/pci/pcie/aer/aerdrv_core.c
+@@ -0,0 +1,758 @@
++/*
++ * drivers/pci/pcie/aer/aerdrv_core.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.
++ *
++ * This file implements the core part of PCI-Express AER. When an pci-express
++ * error is delivered, an error message will be collected and printed to
++ * console, then, an error recovery procedure will be executed by following
++ * the pci error recovery rules.
++ *
++ * Copyright (C) 2006 Intel Corp.
++ * Tom Long Nguyen (tom.l.nguyen at intel.com)
++ * Zhang Yanmin (yanmin.zhang at intel.com)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/pm.h>
++#include <linux/suspend.h>
++#include <linux/acpi.h>
++#include <linux/pci-acpi.h>
++#include <linux/delay.h>
++#include "aerdrv.h"
++
++static int forceload;
++module_param(forceload, bool, 0);
++
++#define PCI_CFG_SPACE_SIZE (0x100)
++int pci_find_aer_capability(struct pci_dev *dev)
++{
++ int pos;
++ u32 reg32 = 0;
++
++ /* Check if it's a pci-express device */
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ if (!pos)
++ return 0;
++
++ /* Check if it supports pci-express AER */
++ pos = PCI_CFG_SPACE_SIZE;
++ while (pos) {
++ if (pci_read_config_dword(dev, pos, ®32))
++ return 0;
++
++ /* some broken boards return ~0 */
++ if (reg32 == 0xffffffff)
++ return 0;
++
++ if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
++ break;
++
++ pos = reg32 >> 20;
++ }
++
++ return pos;
++}
++
++int pci_enable_pcie_error_reporting(struct pci_dev *dev)
++{
++ u16 reg16 = 0;
++ int pos;
++
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ if (!pos)
++ return -EIO;
++
++ pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16);
++ reg16 = reg16 |
++ PCI_EXP_DEVCTL_CERE |
++ PCI_EXP_DEVCTL_NFERE |
++ PCI_EXP_DEVCTL_FERE |
++ PCI_EXP_DEVCTL_URRE;
++ pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
++ reg16);
++ return 0;
++}
++
++int pci_disable_pcie_error_reporting(struct pci_dev *dev)
++{
++ u16 reg16 = 0;
++ int pos;
++
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ if (!pos)
++ return -EIO;
++
++ pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16);
++ reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE |
++ PCI_EXP_DEVCTL_NFERE |
++ PCI_EXP_DEVCTL_FERE |
++ PCI_EXP_DEVCTL_URRE);
++ pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
++ reg16);
++ return 0;
++}
++
++int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
++{
++ int pos;
++ u32 status, mask;
++
++ pos = pci_find_aer_capability(dev);
++ if (!pos)
++ return -EIO;
++
++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
++ if (dev->error_state == pci_channel_io_normal)
++ status &= ~mask; /* Clear corresponding nonfatal bits */
++ else
++ status &= mask; /* Clear corresponding fatal bits */
++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
++
++ return 0;
++}
++
++static int find_device_iter(struct device *device, void *data)
++{
++ struct pci_dev *dev;
++ u16 id = *(unsigned long *)data;
++ u8 secondary, subordinate, d_bus = id >> 8;
++
++ if (device->bus == &pci_bus_type) {
++ dev = to_pci_dev(device);
++ if (id == ((dev->bus->number << 8) | dev->devfn)) {
++ /*
++ * Device ID match
++ */
++ *(unsigned long*)data = (unsigned long)device;
++ return 1;
++ }
++
++ /*
++ * If device is P2P, check if it is an upstream?
++ */
++ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
++ pci_read_config_byte(dev, PCI_SECONDARY_BUS,
++ &secondary);
++ pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
++ &subordinate);
++ if (d_bus >= secondary && d_bus <= subordinate) {
++ *(unsigned long*)data = (unsigned long)device;
++ return 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * find_source_device - search through device hierarchy for source device
++ * @p_dev: pointer to Root Port pci_dev data structure
++ * @id: device ID of agent who sends an error message to this Root Port
++ *
++ * Invoked when error is detected at the Root Port.
++ **/
++static struct device* find_source_device(struct pci_dev *parent, u16 id)
++{
++ struct pci_dev *dev = parent;
++ struct device *device;
++ unsigned long device_addr;
++ int status;
++
++ /* Is Root Port an agent that sends error message? */
++ if (id == ((dev->bus->number << 8) | dev->devfn))
++ return &dev->dev;
++
++ do {
++ device_addr = id;
++ if ((status = device_for_each_child(&dev->dev,
++ &device_addr, find_device_iter))) {
++ device = (struct device*)device_addr;
++ dev = to_pci_dev(device);
++ if (id == ((dev->bus->number << 8) | dev->devfn))
++ return device;
++ }
++ }while (status);
++
++ return NULL;
++}
++
++static void report_error_detected(struct pci_dev *dev, void *data)
++{
++ pci_ers_result_t vote;
++ struct pci_error_handlers *err_handler;
++ struct aer_broadcast_data *result_data;
++ result_data = (struct aer_broadcast_data *) data;
++
++ dev->error_state = result_data->state;
++
++ if (!dev->driver ||
++ !dev->driver->err_handler ||
++ !dev->driver->err_handler->error_detected) {
++ if (result_data->state == pci_channel_io_frozen &&
++ !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) {
++ /*
++ * In case of fatal recovery, if one of down-
++ * stream device has no driver. We might be
++ * unable to recover because a later insmod
++ * of a driver for this device is unaware of
++ * its hw state.
++ */
++ printk(KERN_DEBUG "Device ID[%s] has %s\n",
++ dev->dev.bus_id, (dev->driver) ?
++ "no AER-aware driver" : "no driver");
++ }
++ return;
++ }
++
++ err_handler = dev->driver->err_handler;
++ vote = err_handler->error_detected(dev, result_data->state);
++ result_data->result = merge_result(result_data->result, vote);
++ return;
++}
++
++static void report_mmio_enabled(struct pci_dev *dev, void *data)
++{
++ pci_ers_result_t vote;
++ struct pci_error_handlers *err_handler;
++ struct aer_broadcast_data *result_data;
++ result_data = (struct aer_broadcast_data *) data;
++
++ if (!dev->driver ||
++ !dev->driver->err_handler ||
++ !dev->driver->err_handler->mmio_enabled)
++ return;
++
++ err_handler = dev->driver->err_handler;
++ vote = err_handler->mmio_enabled(dev);
++ result_data->result = merge_result(result_data->result, vote);
++ return;
++}
++
++static void report_slot_reset(struct pci_dev *dev, void *data)
++{
++ pci_ers_result_t vote;
++ struct pci_error_handlers *err_handler;
++ struct aer_broadcast_data *result_data;
++ result_data = (struct aer_broadcast_data *) data;
++
++ if (!dev->driver ||
++ !dev->driver->err_handler ||
++ !dev->driver->err_handler->slot_reset)
++ return;
++
++ err_handler = dev->driver->err_handler;
++ vote = err_handler->slot_reset(dev);
++ result_data->result = merge_result(result_data->result, vote);
++ return;
++}
++
++static void report_resume(struct pci_dev *dev, void *data)
++{
++ struct pci_error_handlers *err_handler;
++
++ dev->error_state = pci_channel_io_normal;
++
++ if (!dev->driver ||
++ !dev->driver->err_handler ||
++ !dev->driver->err_handler->slot_reset)
++ return;
++
++ err_handler = dev->driver->err_handler;
++ err_handler->resume(dev);
++ return;
++}
++
++/**
++ * broadcast_error_message - handle message broadcast to downstream drivers
++ * @device: pointer to from where in a hierarchy message is broadcasted down
++ * @api: callback to be broadcasted
++ * @state: error state
++ *
++ * Invoked during error recovery process. Once being invoked, the content
++ * of error severity will be broadcasted to all downstream drivers in a
++ * hierarchy in question.
++ **/
++static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
++ enum pci_channel_state state,
++ char *error_mesg,
++ void (*cb)(struct pci_dev *, void *))
++{
++ struct aer_broadcast_data result_data;
++
++ printk(KERN_DEBUG "Broadcast %s message\n", error_mesg);
++ result_data.state = state;
++ if (cb == report_error_detected)
++ result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
++ else
++ result_data.result = PCI_ERS_RESULT_RECOVERED;
++
++ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
++ /*
++ * If the error is reported by a bridge, we think this error
++ * is related to the downstream link of the bridge, so we
++ * do error recovery on all subordinates of the bridge instead
++ * of the bridge and clear the error status of the bridge.
++ */
++ if (cb == report_error_detected)
++ dev->error_state = state;
++ pci_walk_bus(dev->subordinate, cb, &result_data);
++ if (cb == report_resume) {
++ pci_cleanup_aer_uncorrect_error_status(dev);
++ dev->error_state = pci_channel_io_normal;
++ }
++ }
++ else {
++ /*
++ * If the error is reported by an end point, we think this
++ * error is related to the upstream link of the end point.
++ */
++ pci_walk_bus(dev->bus, cb, &result_data);
++ }
++
++ return result_data.result;
++}
++
++struct find_aer_service_data {
++ struct pcie_port_service_driver *aer_driver;
++ int is_downstream;
++};
++
++static int find_aer_service_iter(struct device *device, void *data)
++{
++ struct device_driver *driver;
++ struct pcie_port_service_driver *service_driver;
++ struct pcie_device *pcie_dev;
++ struct find_aer_service_data *result;
++
++ result = (struct find_aer_service_data *) data;
++
++ if (device->bus == &pcie_port_bus_type) {
++ pcie_dev = to_pcie_device(device);
++ if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
++ result->is_downstream = 1;
++
++ driver = device->driver;
++ if (driver) {
++ service_driver = to_service_driver(driver);
++ if (service_driver->id_table->service_type ==
++ PCIE_PORT_SERVICE_AER) {
++ result->aer_driver = service_driver;
++ return 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++static void find_aer_service(struct pci_dev *dev,
++ struct find_aer_service_data *data)
++{
++ int retval;
++ retval = device_for_each_child(&dev->dev, data, find_aer_service_iter);
++}
++
++static pci_ers_result_t reset_link(struct pcie_device *aerdev,
++ struct pci_dev *dev)
++{
++ struct pci_dev *udev;
++ pci_ers_result_t status;
++ struct find_aer_service_data data;
++
++ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
++ udev = dev;
++ else
++ udev= dev->bus->self;
++
++ data.is_downstream = 0;
++ data.aer_driver = NULL;
++ find_aer_service(udev, &data);
++
++ /*
++ * Use the aer driver of the error agent firstly.
++ * If it hasn't the aer driver, use the root port's
++ */
++ if (!data.aer_driver || !data.aer_driver->reset_link) {
++ if (data.is_downstream &&
++ aerdev->device.driver &&
++ to_service_driver(aerdev->device.driver)->reset_link) {
++ data.aer_driver =
++ to_service_driver(aerdev->device.driver);
++ } else {
++ printk(KERN_DEBUG "No link-reset support to Device ID"
++ "[%s]\n",
++ dev->dev.bus_id);
++ return PCI_ERS_RESULT_DISCONNECT;
++ }
++ }
++
++ status = data.aer_driver->reset_link(udev);
++ if (status != PCI_ERS_RESULT_RECOVERED) {
++ printk(KERN_DEBUG "Link reset at upstream Device ID"
++ "[%s] failed\n",
++ udev->dev.bus_id);
++ return PCI_ERS_RESULT_DISCONNECT;
++ }
++
++ return status;
++}
++
++/**
++ * do_recovery - handle nonfatal/fatal error recovery process
++ * @aerdev: pointer to a pcie_device data structure of root port
++ * @dev: pointer to a pci_dev data structure of agent detecting an error
++ * @severity: error severity type
++ *
++ * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
++ * error detected message to all downstream drivers within a hierarchy in
++ * question and return the returned code.
++ **/
++static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
++ struct pci_dev *dev,
++ int severity)
++{
++ pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
++ enum pci_channel_state state;
++
++ if (severity == AER_FATAL)
++ state = pci_channel_io_frozen;
++ else
++ state = pci_channel_io_normal;
++
++ status = broadcast_error_message(dev,
++ state,
++ "error_detected",
++ report_error_detected);
++
++ if (severity == AER_FATAL) {
++ result = reset_link(aerdev, dev);
++ if (result != PCI_ERS_RESULT_RECOVERED) {
++ /* TODO: Should panic here? */
++ return result;
++ }
++ }
++
++ if (status == PCI_ERS_RESULT_CAN_RECOVER)
++ status = broadcast_error_message(dev,
++ state,
++ "mmio_enabled",
++ report_mmio_enabled);
++
++ if (status == PCI_ERS_RESULT_NEED_RESET) {
++ /*
++ * TODO: Should call platform-specific
++ * functions to reset slot before calling
++ * drivers' slot_reset callbacks?
++ */
++ status = broadcast_error_message(dev,
++ state,
++ "slot_reset",
++ report_slot_reset);
++ }
++
++ if (status == PCI_ERS_RESULT_RECOVERED)
++ broadcast_error_message(dev,
++ state,
++ "resume",
++ report_resume);
++
++ return status;
++}
++
++/**
++ * handle_error_source - handle logging error into an event log
++ * @aerdev: pointer to pcie_device data structure of the root port
++ * @dev: pointer to pci_dev data structure of error source device
++ * @info: comprehensive error information
++ *
++ * Invoked when an error being detected by Root Port.
++ **/
++static void handle_error_source(struct pcie_device * aerdev,
++ struct pci_dev *dev,
++ struct aer_err_info info)
++{
++ pci_ers_result_t status = 0;
++ int pos;
++
++ if (info.severity == AER_CORRECTABLE) {
++ /*
++ * Correctable error does not need software intevention.
++ * No need to go through error recovery process.
++ */
++ pos = pci_find_aer_capability(dev);
++ if (pos)
++ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
++ info.status);
++ } else {
++ status = do_recovery(aerdev, dev, info.severity);
++ if (status == PCI_ERS_RESULT_RECOVERED) {
++ printk(KERN_DEBUG "AER driver successfully recovered\n");
++ } else {
++ /* TODO: Should kernel panic here? */
++ printk(KERN_DEBUG "AER driver didn't recover\n");
++ }
++ }
++}
++
++/**
++ * aer_enable_rootport - enable Root Port's interrupts when receiving messages
++ * @rpc: pointer to a Root Port data structure
++ *
++ * Invoked when PCIE bus loads AER service driver.
++ **/
++void aer_enable_rootport(struct aer_rpc *rpc)
++{
++ struct pci_dev *pdev = rpc->rpd->port;
++ int pos, aer_pos;
++ u16 reg16;
++ u32 reg32;
++
++ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
++ /* Clear PCIE Capability's Device Status */
++ pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16);
++ pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
++
++ /* Disable system error generation in response to error messages */
++ pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, ®16);
++ reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
++ pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
++
++ aer_pos = pci_find_aer_capability(pdev);
++ /* Clear error status */
++ pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32);
++ pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
++ pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32);
++ pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
++ pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32);
++ pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
++
++ /* Enable Root Port device reporting error itself */
++ pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, ®16);
++ reg16 = reg16 |
++ PCI_EXP_DEVCTL_CERE |
++ PCI_EXP_DEVCTL_NFERE |
++ PCI_EXP_DEVCTL_FERE |
++ PCI_EXP_DEVCTL_URRE;
++ pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
++ reg16);
++
++ /* Enable Root Port's interrupt in response to error messages */
++ pci_write_config_dword(pdev,
++ aer_pos + PCI_ERR_ROOT_COMMAND,
++ ROOT_PORT_INTR_ON_MESG_MASK);
++}
++
++/**
++ * disable_root_aer - disable Root Port's interrupts when receiving messages
++ * @rpc: pointer to a Root Port data structure
++ *
++ * Invoked when PCIE bus unloads AER service driver.
++ **/
++static void disable_root_aer(struct aer_rpc *rpc)
++{
++ struct pci_dev *pdev = rpc->rpd->port;
++ u32 reg32;
++ int pos;
++
++ pos = pci_find_aer_capability(pdev);
++ /* Disable Root's interrupt in response to error messages */
++ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
++
++ /* Clear Root's error status reg */
++ pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32);
++ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
++}
++
++/**
++ * get_e_source - retrieve an error source
++ * @rpc: pointer to the root port which holds an error
++ *
++ * Invoked by DPC handler to consume an error.
++ **/
++static struct aer_err_source* get_e_source(struct aer_rpc *rpc)
++{
++ struct aer_err_source *e_source;
++ unsigned long flags;
++
++ /* Lock access to Root error producer/consumer index */
++ spin_lock_irqsave(&rpc->e_lock, flags);
++ if (rpc->prod_idx == rpc->cons_idx) {
++ spin_unlock_irqrestore(&rpc->e_lock, flags);
++ return NULL;
++ }
++ e_source = &rpc->e_sources[rpc->cons_idx];
++ rpc->cons_idx++;
++ if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
++ rpc->cons_idx = 0;
++ spin_unlock_irqrestore(&rpc->e_lock, flags);
++
++ return e_source;
++}
++
++static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
++{
++ int pos;
++
++ pos = pci_find_aer_capability(dev);
++
++ /* The device might not support AER */
++ if (!pos)
++ return AER_SUCCESS;
++
++ if (info->severity == AER_CORRECTABLE) {
++ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
++ &info->status);
++ if (!(info->status & ERR_CORRECTABLE_ERROR_MASK))
++ return AER_UNSUCCESS;
++ } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||
++ info->severity == AER_NONFATAL) {
++
++ /* Link is still healthy for IO reads */
++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
++ &info->status);
++ if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK))
++ return AER_UNSUCCESS;
++
++ if (info->status & AER_LOG_TLP_MASKS) {
++ info->flags |= AER_TLP_HEADER_VALID_FLAG;
++ pci_read_config_dword(dev,
++ pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
++ pci_read_config_dword(dev,
++ pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
++ pci_read_config_dword(dev,
++ pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
++ pci_read_config_dword(dev,
++ pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
++ }
++ }
++
++ return AER_SUCCESS;
++}
++
++/**
++ * aer_isr_one_error - consume an error detected by root port
++ * @p_device: pointer to error root port service device
++ * @e_src: pointer to an error source
++ **/
++static void aer_isr_one_error(struct pcie_device *p_device,
++ struct aer_err_source *e_src)
++{
++ struct device *s_device;
++ struct aer_err_info e_info = {0, 0, 0,};
++ int i;
++ u16 id;
++
++ /*
++ * There is a possibility that both correctable error and
++ * uncorrectable error being logged. Report correctable error first.
++ */
++ for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {
++ if (i > 4)
++ break;
++ if (!(e_src->status & i))
++ continue;
++
++ /* Init comprehensive error information */
++ if (i & PCI_ERR_ROOT_COR_RCV) {
++ id = ERR_COR_ID(e_src->id);
++ e_info.severity = AER_CORRECTABLE;
++ } else {
++ id = ERR_UNCOR_ID(e_src->id);
++ e_info.severity = ((e_src->status >> 6) & 1);
++ }
++ if (e_src->status &
++ (PCI_ERR_ROOT_MULTI_COR_RCV |
++ PCI_ERR_ROOT_MULTI_UNCOR_RCV))
++ e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
++ if (!(s_device = find_source_device(p_device->port, id))) {
++ printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
++ __FUNCTION__, id);
++ continue;
++ }
++ if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
++ AER_SUCCESS) {
++ aer_print_error(to_pci_dev(s_device), &e_info);
++ handle_error_source(p_device,
++ to_pci_dev(s_device),
++ e_info);
++ }
++ }
++}
++
++/**
++ * aer_isr - consume errors detected by root port
++ * @context: pointer to a private data of pcie device
++ *
++ * Invoked, as DPC, when root port records new detected error
++ **/
++void aer_isr(void *context)
++{
++ struct pcie_device *p_device = (struct pcie_device *) context;
++ struct aer_rpc *rpc = get_service_data(p_device);
++ struct aer_err_source *e_src;
++
++ mutex_lock(&rpc->rpc_mutex);
++ e_src = get_e_source(rpc);
++ while (e_src) {
++ aer_isr_one_error(p_device, e_src);
++ e_src = get_e_source(rpc);
++ }
++ mutex_unlock(&rpc->rpc_mutex);
++
++ wake_up(&rpc->wait_release);
++}
++
++/**
++ * aer_delete_rootport - disable root port aer and delete service data
++ * @rpc: pointer to a root port device being deleted
++ *
++ * Invoked when AER service unloaded on a specific Root Port
++ **/
++void aer_delete_rootport(struct aer_rpc *rpc)
++{
++ /* Disable root port AER itself */
++ disable_root_aer(rpc);
++
++ kfree(rpc);
++}
++
++/**
++ * aer_init - provide AER initialization
++ * @dev: pointer to AER pcie device
++ *
++ * Invoked when AER service driver is loaded.
++ **/
++int aer_init(struct pcie_device *dev)
++{
++ int status;
++
++ /* Run _OSC Method */
++ status = aer_osc_setup(dev->port);
++
++ if(status != OSC_METHOD_RUN_SUCCESS) {
++ printk(KERN_DEBUG "%s: AER service init fails - %s\n",
++ __FUNCTION__,
++ (status == OSC_METHOD_NOT_SUPPORTED) ?
++ "No ACPI _OSC support" : "Run ACPI _OSC fails");
++
++ if (!forceload)
++ return status;
++ }
++
++ return AER_SUCCESS;
++}
++
++EXPORT_SYMBOL_GPL(pci_find_aer_capability);
++EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
++EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
++EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
++
+diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
+new file mode 100644
+index 0000000..3933d4f
+--- /dev/null
++++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
+@@ -0,0 +1,248 @@
++/*
++ * drivers/pci/pcie/aer/aerdrv_errprint.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.
++ *
++ * Format error messages and print them to console.
++ *
++ * Copyright (C) 2006 Intel Corp.
++ * Tom Long Nguyen (tom.l.nguyen at intel.com)
++ * Zhang Yanmin (yanmin.zhang at intel.com)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/pm.h>
++#include <linux/suspend.h>
++
++#include "aerdrv.h"
++
++#define AER_AGENT_RECEIVER 0
++#define AER_AGENT_REQUESTER 1
++#define AER_AGENT_COMPLETER 2
++#define AER_AGENT_TRANSMITTER 3
++
++#define AER_AGENT_REQUESTER_MASK (PCI_ERR_UNC_COMP_TIME| \
++ PCI_ERR_UNC_UNSUP)
++
++#define AER_AGENT_COMPLETER_MASK PCI_ERR_UNC_COMP_ABORT
++
++#define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \
++ ((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0)))
++
++#define AER_GET_AGENT(t, e) \
++ ((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER : \
++ (e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER : \
++ (AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER : \
++ AER_AGENT_RECEIVER)
++
++#define AER_PHYSICAL_LAYER_ERROR_MASK PCI_ERR_COR_RCVR
++#define AER_DATA_LINK_LAYER_ERROR_MASK(t, e) \
++ (PCI_ERR_UNC_DLP| \
++ PCI_ERR_COR_BAD_TLP| \
++ PCI_ERR_COR_BAD_DLLP| \
++ PCI_ERR_COR_REP_ROLL| \
++ ((t == AER_CORRECTABLE) ? \
++ PCI_ERR_COR_REP_TIMER: 0))
++
++#define AER_PHYSICAL_LAYER_ERROR 0
++#define AER_DATA_LINK_LAYER_ERROR 1
++#define AER_TRANSACTION_LAYER_ERROR 2
++
++#define AER_GET_LAYER_ERROR(t, e) \
++ ((e & AER_PHYSICAL_LAYER_ERROR_MASK) ? \
++ AER_PHYSICAL_LAYER_ERROR : \
++ (e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ? \
++ AER_DATA_LINK_LAYER_ERROR : \
++ AER_TRANSACTION_LAYER_ERROR)
++
++/*
++ * AER error strings
++ */
++static char* aer_error_severity_string[] = {
++ "Uncorrected (Non-Fatal)",
++ "Uncorrected (Fatal)",
++ "Corrected"
++};
++
++static char* aer_error_layer[] = {
++ "Physical Layer",
++ "Data Link Layer",
++ "Transaction Layer"
++};
++static char* aer_correctable_error_string[] = {
++ "Receiver Error ", /* Bit Position 0 */
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ "Bad TLP ", /* Bit Position 6 */
++ "Bad DLLP ", /* Bit Position 7 */
++ "RELAY_NUM Rollover ", /* Bit Position 8 */
++ NULL,
++ NULL,
++ NULL,
++ "Replay Timer Timeout ", /* Bit Position 12 */
++ "Advisory Non-Fatal ", /* Bit Position 13 */
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++};
++
++static char* aer_uncorrectable_error_string[] = {
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ "Data Link Protocol ", /* Bit Position 4 */
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ "Poisoned TLP ", /* Bit Position 12 */
++ "Flow Control Protocol ", /* Bit Position 13 */
++ "Completion Timeout ", /* Bit Position 14 */
++ "Completer Abort ", /* Bit Position 15 */
++ "Unexpected Completion ", /* Bit Position 16 */
++ "Receiver Overflow ", /* Bit Position 17 */
++ "Malformed TLP ", /* Bit Position 18 */
++ "ECRC ", /* Bit Position 19 */
++ "Unsupported Request ", /* Bit Position 20 */
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++};
++
++static char* aer_agent_string[] = {
++ "Receiver ID",
++ "Requester ID",
++ "Completer ID",
++ "Transmitter ID"
++};
++
++static char * aer_get_error_source_name(int severity,
++ unsigned int status,
++ char errmsg_buff[])
++{
++ int i;
++ char * errmsg = NULL;
++
++ for (i = 0; i < 32; i++) {
++ if (!(status & (1 << i)))
++ continue;
++
++ if (severity == AER_CORRECTABLE)
++ errmsg = aer_correctable_error_string[i];
++ else
++ errmsg = aer_uncorrectable_error_string[i];
++
++ if (!errmsg) {
++ sprintf(errmsg_buff, "Unknown Error Bit %2d ", i);
++ errmsg = errmsg_buff;
++ }
++
++ break;
++ }
++
++ return errmsg;
++}
++
++static DEFINE_SPINLOCK(logbuf_lock);
++static char errmsg_buff[100];
++void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
++{
++ char * errmsg;
++ int err_layer, agent;
++ char * loglevel;
++
++ if (info->severity == AER_CORRECTABLE)
++ loglevel = KERN_WARNING;
++ else
++ loglevel = KERN_ERR;
++
++ printk("%s+------ PCI-Express Device Error ------+\n", loglevel);
++ printk("%sError Severity\t\t: %s\n", loglevel,
++ aer_error_severity_string[info->severity]);
++
++ if ( info->status == 0) {
++ printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel);
++ printk("%sUnaccessible Received\t: %s\n", loglevel,
++ info->flags & AER_MULTI_ERROR_VALID_FLAG ?
++ "Multiple" : "First");
++ printk("%sUnregistered Agent ID\t: %04x\n", loglevel,
++ (dev->bus->number << 8) | dev->devfn);
++ } else {
++ err_layer = AER_GET_LAYER_ERROR(info->severity, info->status);
++ printk("%sPCIE Bus Error type\t: %s\n", loglevel,
++ aer_error_layer[err_layer]);
++
++ spin_lock(&logbuf_lock);
++ errmsg = aer_get_error_source_name(info->severity,
++ info->status,
++ errmsg_buff);
++ printk("%s%s\t: %s\n", loglevel, errmsg,
++ info->flags & AER_MULTI_ERROR_VALID_FLAG ?
++ "Multiple" : "First");
++ spin_unlock(&logbuf_lock);
++
++ agent = AER_GET_AGENT(info->severity, info->status);
++ printk("%s%s\t\t: %04x\n", loglevel,
++ aer_agent_string[agent],
++ (dev->bus->number << 8) | dev->devfn);
++
++ printk("%sVendorID=%04xh, DeviceID=%04xh,"
++ " Bus=%02xh, Device=%02xh, Function=%02xh\n",
++ loglevel,
++ dev->vendor,
++ dev->device,
++ dev->bus->number,
++ PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn));
++
++ if (info->flags & AER_TLP_HEADER_VALID_FLAG) {
++ unsigned char *tlp = (unsigned char *) &info->tlp;
++ printk("%sTLB Header:\n", loglevel);
++ printk("%s%02x%02x%02x%02x %02x%02x%02x%02x"
++ " %02x%02x%02x%02x %02x%02x%02x%02x\n",
++ loglevel,
++ *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
++ *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
++ *(tlp + 11), *(tlp + 10), *(tlp + 9),
++ *(tlp + 8), *(tlp + 15), *(tlp + 14),
++ *(tlp + 13), *(tlp + 12));
++ }
++ }
++}
++
+diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
+index 1d317d2..3656e03 100644
+--- a/drivers/pci/pcie/portdrv.h
++++ b/drivers/pci/pcie/portdrv.h
+@@ -9,6 +9,8 @@
+ #ifndef _PORTDRV_H_
+ #define _PORTDRV_H_
+
++#include <linux/compiler.h>
++
+ #if !defined(PCI_CAP_ID_PME)
+ #define PCI_CAP_ID_PME 1
+ #endif
+@@ -39,7 +41,7 @@ extern int pcie_port_device_suspend(stru
+ extern int pcie_port_device_resume(struct pci_dev *dev);
+ #endif
+ extern void pcie_port_device_remove(struct pci_dev *dev);
+-extern void pcie_port_bus_register(void);
++extern int __must_check pcie_port_bus_register(void);
+ extern void pcie_port_bus_unregister(void);
+
+ #endif /* _PORTDRV_H_ */
+diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
+index 3e84b50..3f09768 100644
+--- a/drivers/pci/pcie/portdrv_bus.c
++++ b/drivers/pci/pcie/portdrv_bus.c
+@@ -24,6 +24,7 @@ struct bus_type pcie_port_bus_type = {
+ .suspend = pcie_port_bus_suspend,
+ .resume = pcie_port_bus_resume,
+ };
++EXPORT_SYMBOL_GPL(pcie_port_bus_type);
+
+ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
+ {
+diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
+index 55c6622..b20a9b8 100644
+--- a/drivers/pci/pcie/portdrv_core.c
++++ b/drivers/pci/pcie/portdrv_core.c
+@@ -339,8 +339,7 @@ static int suspend_iter(struct device *d
+
+ int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
+ {
+- device_for_each_child(&dev->dev, &state, suspend_iter);
+- return 0;
++ return device_for_each_child(&dev->dev, &state, suspend_iter);
+ }
+
+ static int resume_iter(struct device *dev, void *data)
+@@ -358,8 +357,7 @@ static int resume_iter(struct device *de
+
+ int pcie_port_device_resume(struct pci_dev *dev)
+ {
+- device_for_each_child(&dev->dev, NULL, resume_iter);
+- return 0;
++ return device_for_each_child(&dev->dev, NULL, resume_iter);
+ }
+ #endif
+
+@@ -402,9 +400,9 @@ void pcie_port_device_remove(struct pci_
+ pci_disable_msi(dev);
+ }
+
+-void pcie_port_bus_register(void)
++int pcie_port_bus_register(void)
+ {
+- bus_register(&pcie_port_bus_type);
++ return bus_register(&pcie_port_bus_type);
+ }
+
+ void pcie_port_bus_unregister(void)
+diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
+index 478d0d2..b4da795 100644
+--- a/drivers/pci/pcie/portdrv_pci.c
++++ b/drivers/pci/pcie/portdrv_pci.c
+@@ -14,8 +14,10 @@
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/pcieport_if.h>
++#include <linux/aer.h>
+
+ #include "portdrv.h"
++#include "aer/aerdrv.h"
+
+ /*
+ * Version Information
+@@ -30,6 +32,43 @@ MODULE_LICENSE("GPL");
+ /* global data */
+ static const char device_name[] = "pcieport-driver";
+
++static int pcie_portdrv_save_config(struct pci_dev *dev)
++{
++ return pci_save_state(dev);
++}
++
++static int pcie_portdrv_restore_config(struct pci_dev *dev)
++{
++ int retval;
++
++ pci_restore_state(dev);
++ retval = pci_enable_device(dev);
++ if (retval)
++ return retval;
++ pci_set_master(dev);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
++{
++ int ret = pcie_port_device_suspend(dev, state);
++
++ if (!ret)
++ ret = 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);
++}
++#else
++#define pcie_portdrv_suspend NULL
++#define pcie_portdrv_resume NULL
++#endif
++
+ /*
+ * pcie_portdrv_probe - Probe PCI-Express port devices
+ * @dev: PCI-Express port device being probed
+@@ -61,6 +100,10 @@ static int __devinit pcie_portdrv_probe
+ return -ENOMEM;
+ }
+
++ pcie_portdrv_save_config(dev);
++
++ pci_enable_pcie_error_reporting(dev);
++
+ return 0;
+ }
+
+@@ -70,39 +113,151 @@ static void pcie_portdrv_remove (struct
+ kfree(pci_get_drvdata(dev));
+ }
+
+-#ifdef CONFIG_PM
+-static int pcie_portdrv_save_config(struct pci_dev *dev)
++static int error_detected_iter(struct device *device, void *data)
+ {
+- return pci_save_state(dev);
++ struct pcie_device *pcie_device;
++ struct pcie_port_service_driver *driver;
++ struct aer_broadcast_data *result_data;
++ pci_ers_result_t status;
++
++ result_data = (struct aer_broadcast_data *) data;
++
++ if (device->bus == &pcie_port_bus_type && device->driver) {
++ driver = to_service_driver(device->driver);
++ if (!driver ||
++ !driver->err_handler ||
++ !driver->err_handler->error_detected)
++ return 0;
++
++ pcie_device = to_pcie_device(device);
++
++ /* Forward error detected message to service drivers */
++ status = driver->err_handler->error_detected(
++ pcie_device->port,
++ result_data->state);
++ result_data->result =
++ merge_result(result_data->result, status);
++ }
++
++ return 0;
+ }
+
+-static int pcie_portdrv_restore_config(struct pci_dev *dev)
++static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
++ enum pci_channel_state error)
+ {
++ struct aer_broadcast_data result_data =
++ {error, PCI_ERS_RESULT_CAN_RECOVER};
+ int retval;
+
+- pci_restore_state(dev);
+- retval = pci_enable_device(dev);
+- if (retval)
+- return retval;
+- pci_set_master(dev);
++ /* can not fail */
++ retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter);
++
++ return result_data.result;
++}
++
++static int mmio_enabled_iter(struct device *device, void *data)
++{
++ struct pcie_device *pcie_device;
++ struct pcie_port_service_driver *driver;
++ pci_ers_result_t status, *result;
++
++ result = (pci_ers_result_t *) data;
++
++ if (device->bus == &pcie_port_bus_type && device->driver) {
++ driver = to_service_driver(device->driver);
++ if (driver &&
++ driver->err_handler &&
++ driver->err_handler->mmio_enabled) {
++ pcie_device = to_pcie_device(device);
++
++ /* Forward error message to service drivers */
++ status = driver->err_handler->mmio_enabled(
++ pcie_device->port);
++ *result = merge_result(*result, status);
++ }
++ }
++
+ return 0;
+ }
+
+-static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
++static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
+ {
+- int ret = pcie_port_device_suspend(dev, state);
++ pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
++ int retval;
+
+- if (!ret)
+- ret = pcie_portdrv_save_config(dev);
+- return ret;
++ /* get true return value from &status */
++ retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
++ return status;
+ }
+
+-static int pcie_portdrv_resume (struct pci_dev *dev)
++static int slot_reset_iter(struct device *device, void *data)
+ {
+- pcie_portdrv_restore_config(dev);
+- return pcie_port_device_resume(dev);
++ struct pcie_device *pcie_device;
++ struct pcie_port_service_driver *driver;
++ pci_ers_result_t status, *result;
++
++ result = (pci_ers_result_t *) data;
++
++ if (device->bus == &pcie_port_bus_type && device->driver) {
++ driver = to_service_driver(device->driver);
++ if (driver &&
++ driver->err_handler &&
++ driver->err_handler->slot_reset) {
++ pcie_device = to_pcie_device(device);
++
++ /* Forward error message to service drivers */
++ status = driver->err_handler->slot_reset(
++ pcie_device->port);
++ *result = merge_result(*result, status);
++ }
++ }
++
++ return 0;
++}
++
++static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
++{
++ pci_ers_result_t status;
++ int retval;
++
++ /* If fatal, restore cfg space for possible link reset at upstream */
++ if (dev->error_state == pci_channel_io_frozen) {
++ pcie_portdrv_restore_config(dev);
++ pci_enable_pcie_error_reporting(dev);
++ }
++
++ /* get true return value from &status */
++ retval = device_for_each_child(&dev->dev, &status, slot_reset_iter);
++
++ return status;
++}
++
++static int resume_iter(struct device *device, void *data)
++{
++ struct pcie_device *pcie_device;
++ struct pcie_port_service_driver *driver;
++
++ if (device->bus == &pcie_port_bus_type && device->driver) {
++ driver = to_service_driver(device->driver);
++ if (driver &&
++ driver->err_handler &&
++ driver->err_handler->resume) {
++ pcie_device = to_pcie_device(device);
++
++ /* Forward error message to service drivers */
++ driver->err_handler->resume(pcie_device->port);
++ }
++ }
++
++ return 0;
++}
++
++static void pcie_portdrv_err_resume(struct pci_dev *dev)
++{
++ int retval;
++ /* nothing to do with error value, if it ever happens */
++ retval = device_for_each_child(&dev->dev, NULL, resume_iter);
+ }
+-#endif
+
+ /*
+ * LINUX Device Driver Model
+@@ -114,6 +269,13 @@ static const struct pci_device_id port_p
+ };
+ MODULE_DEVICE_TABLE(pci, port_pci_ids);
+
++static struct pci_error_handlers pcie_portdrv_err_handler = {
++ .error_detected = pcie_portdrv_error_detected,
++ .mmio_enabled = pcie_portdrv_mmio_enabled,
++ .slot_reset = pcie_portdrv_slot_reset,
++ .resume = pcie_portdrv_err_resume,
++};
++
+ static struct pci_driver pcie_portdrv = {
+ .name = (char *)device_name,
+ .id_table = &port_pci_ids[0],
+@@ -121,20 +283,25 @@ static struct pci_driver pcie_portdrv =
+ .probe = pcie_portdrv_probe,
+ .remove = pcie_portdrv_remove,
+
+-#ifdef CONFIG_PM
+ .suspend = pcie_portdrv_suspend,
+ .resume = pcie_portdrv_resume,
+-#endif /* PM */
++
++ .err_handler = &pcie_portdrv_err_handler,
+ };
+
+ static int __init pcie_portdrv_init(void)
+ {
+- int retval = 0;
++ int retval;
+
+- pcie_port_bus_register();
++ retval = pcie_port_bus_register();
++ if (retval) {
++ printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
++ goto out;
++ }
+ retval = pci_register_driver(&pcie_portdrv);
+ if (retval)
+ pcie_port_bus_unregister();
++ out:
+ return retval;
+ }
+
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index c5a58d1..e159d66 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -339,6 +339,7 @@ pci_alloc_child_bus(struct pci_bus *pare
+ {
+ struct pci_bus *child;
+ int i;
++ int retval;
+
+ /*
+ * Allocate a new bus, and inherit stuff from the parent..
+@@ -356,8 +357,13 @@ pci_alloc_child_bus(struct pci_bus *pare
+
+ child->class_dev.class = &pcibus_class;
+ sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
+- class_device_register(&child->class_dev);
+- class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity);
++ retval = class_device_register(&child->class_dev);
++ if (retval)
++ goto error_register;
++ retval = class_device_create_file(&child->class_dev,
++ &class_device_attr_cpuaffinity);
++ if (retval)
++ goto error_file_create;
+
+ /*
+ * Set up the primary, secondary and subordinate
+@@ -375,6 +381,12 @@ pci_alloc_child_bus(struct pci_bus *pare
+ bridge->subordinate = child;
+
+ return child;
++
++error_file_create:
++ class_device_unregister(&child->class_dev);
++error_register:
++ kfree(child);
++ return NULL;
+ }
+
+ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+@@ -1055,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge);
+ EXPORT_SYMBOL(pci_scan_single_device);
+ EXPORT_SYMBOL_GPL(pci_scan_child_bus);
+ #endif
++
++static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b)
++{
++ if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1;
++ else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1;
++
++ if (a->bus->number < b->bus->number) return -1;
++ else if (a->bus->number > b->bus->number) return 1;
++
++ if (a->devfn < b->devfn) return -1;
++ else if (a->devfn > b->devfn) return 1;
++
++ return 0;
++}
++
++/*
++ * Yes, this forcably breaks the klist abstraction temporarily. It
++ * just wants to sort the klist, not change reference counts and
++ * take/drop locks rapidly in the process. It does all this while
++ * holding the lock for the list, so objects can't otherwise be
++ * added/removed while we're swizzling.
++ */
++static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list)
++{
++ struct list_head *pos;
++ struct klist_node *n;
++ struct device *dev;
++ struct pci_dev *b;
++
++ list_for_each(pos, list) {
++ n = container_of(pos, struct klist_node, n_node);
++ dev = container_of(n, struct device, knode_bus);
++ b = to_pci_dev(dev);
++ if (pci_sort_bf_cmp(a, b) <= 0) {
++ list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node);
++ return;
++ }
++ }
++ list_move_tail(&a->dev.knode_bus.n_node, list);
++}
++
++static void __init pci_sort_breadthfirst_klist(void)
++{
++ LIST_HEAD(sorted_devices);
++ struct list_head *pos, *tmp;
++ struct klist_node *n;
++ struct device *dev;
++ struct pci_dev *pdev;
++
++ spin_lock(&pci_bus_type.klist_devices.k_lock);
++ list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
++ n = container_of(pos, struct klist_node, n_node);
++ dev = container_of(n, struct device, knode_bus);
++ pdev = to_pci_dev(dev);
++ pci_insertion_sort_klist(pdev, &sorted_devices);
++ }
++ list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
++ spin_unlock(&pci_bus_type.klist_devices.k_lock);
++}
++
++static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
++{
++ struct pci_dev *b;
++
++ list_for_each_entry(b, list, global_list) {
++ if (pci_sort_bf_cmp(a, b) <= 0) {
++ list_move_tail(&a->global_list, &b->global_list);
++ return;
++ }
++ }
++ list_move_tail(&a->global_list, list);
++}
++
++static void __init pci_sort_breadthfirst_devices(void)
++{
++ LIST_HEAD(sorted_devices);
++ struct pci_dev *dev, *tmp;
++
++ down_write(&pci_bus_sem);
++ list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) {
++ pci_insertion_sort_devices(dev, &sorted_devices);
++ }
++ list_splice(&sorted_devices, &pci_devices);
++ up_write(&pci_bus_sem);
++}
++
++void __init pci_sort_breadthfirst(void)
++{
++ pci_sort_breadthfirst_devices();
++ pci_sort_breadthfirst_klist();
++}
++
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 17e709e..204b1c8 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -93,8 +93,21 @@ static void __devinit quirk_nopcipci(str
+ pci_pci_problems |= PCIPCI_FAIL;
+ }
+ }
++
++static void __devinit quirk_nopciamd(struct pci_dev *dev)
++{
++ u8 rev;
++ pci_read_config_byte(dev, 0x08, &rev);
++ if (rev == 0x13) {
++ /* Erratum 24 */
++ printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n");
++ pci_pci_problems |= PCIAGP_FAIL;
++ }
++}
++
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd );
+
+ /*
+ * Triton requires workarounds to be used by the drivers
+@@ -440,6 +453,12 @@ static void __devinit quirk_ich6_lpc_acp
+ }
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
+
+ /*
+ * VIA ACPI: One IO region pointed to by longword at
+@@ -555,7 +574,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VI
+ * is currently marked NoFix
+ *
+ * We have multiple reports of hangs with this chipset that went away with
+- * noapic specified. For the moment we assume its the errata. We may be wrong
++ * noapic specified. For the moment we assume it's the erratum. We may be wrong
+ * of course. However the advice is demonstrably good even if so..
+ */
+ static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
+@@ -564,7 +583,7 @@ static void __devinit quirk_amd_ioapic(s
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+ if (rev >= 0x02) {
+- printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n");
++ printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
+ printk(KERN_WARNING " : booting with the \"noapic\" option.\n");
+ }
+ }
+@@ -577,8 +596,6 @@ static void __init quirk_ioapic_rmw(stru
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
+
+-int pci_msi_quirk;
+-
+ #define AMD8131_revA0 0x01
+ #define AMD8131_revB0 0x11
+ #define AMD8131_MISC 0x40
+@@ -587,12 +604,6 @@ static void __init quirk_amd_8131_ioapic
+ {
+ unsigned char revid, tmp;
+
+- if (dev->subordinate) {
+- printk(KERN_WARNING "PCI: MSI quirk detected. "
+- "PCI_BUS_FLAGS_NO_MSI set for subordinate bus.\n");
+- dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+- }
+-
+ if (nr_ioapics == 0)
+ return;
+
+@@ -605,13 +616,6 @@ static void __init quirk_amd_8131_ioapic
+ }
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
+-
+-static void __init quirk_svw_msi(struct pci_dev *dev)
+-{
+- pci_msi_quirk = 1;
+- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+-}
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi );
+ #endif /* CONFIG_X86_IO_APIC */
+
+
+@@ -650,11 +654,43 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_V
+ * Some of the on-chip devices are actually '586 devices' so they are
+ * listed here.
+ */
++
++static int via_irq_fixup_needed = -1;
++
++/*
++ * As some VIA hardware is available in PCI-card form, we need to restrict
++ * this quirk to VIA PCI hardware built onto VIA-based motherboards only.
++ * We try to locate a VIA southbridge before deciding whether the quirk
++ * should be applied.
++ */
++static const struct pci_device_id via_irq_fixup_tbl[] = {
++ {
++ .vendor = PCI_VENDOR_ID_VIA,
++ .device = PCI_ANY_ID,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .class = PCI_CLASS_BRIDGE_ISA << 8,
++ .class_mask = 0xffff00,
++ },
++ { 0, },
++};
++
+ static void quirk_via_irq(struct pci_dev *dev)
+ {
+ u8 irq, new_irq;
+
+- new_irq = dev->irq & 0xf;
++ if (via_irq_fixup_needed == -1)
++ via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl);
++
++ if (!via_irq_fixup_needed)
++ return;
++
++ new_irq = dev->irq;
++
++ /* Don't quirk interrupts outside the legacy IRQ range */
++ if (!new_irq || new_irq > 15)
++ return;
++
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ if (new_irq != irq) {
+ printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n",
+@@ -663,14 +699,7 @@ static void quirk_via_irq(struct pci_dev
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
+ }
+ }
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq);
+-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq);
++DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
+
+ /*
+ * VIA VT82C598 has its device ID settable and many BIOSes
+@@ -685,33 +714,6 @@ static void __devinit quirk_vt82c598_id(
+ }
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id );
+
+-#ifdef CONFIG_ACPI_SLEEP
+-
+-/*
+- * Some VIA systems boot with the abnormal status flag set. This can cause
+- * the BIOS to re-POST the system on resume rather than passing control
+- * back to the OS. Clear the flag on boot
+- */
+-static void __devinit quirk_via_abnormal_poweroff(struct pci_dev *dev)
+-{
+- u32 reg;
+-
+- acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS,
+- ®);
+-
+- if (reg & 0x800) {
+- printk("Clearing abnormal poweroff flag\n");
+- acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
+- ACPI_REGISTER_PM1_STATUS,
+- (u16)0x800);
+- }
+-}
+-
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_abnormal_poweroff);
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_abnormal_poweroff);
+-
+-#endif
+-
+ /*
+ * CardBus controllers have a legacy base address that enables them
+ * to respond as i82365 pcmcia controllers. We don't want them to
+@@ -1210,7 +1212,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+
+-#if defined(CONFIG_SCSI_SATA) || defined(CONFIG_SCSI_SATA_MODULE)
++#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
+
+ /*
+ * If we are using libata we can drive this chip properly but must
+@@ -1300,7 +1302,7 @@ static int __init combined_setup(char *s
+ }
+ __setup("combined_mode=", combined_setup);
+
+-#ifdef CONFIG_SCSI_SATA_INTEL_COMBINED
++#ifdef CONFIG_SATA_INTEL_COMBINED
+ static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
+ {
+ u8 prog, comb, tmp;
+@@ -1393,7 +1395,7 @@ static void __devinit quirk_intel_ide_co
+ request_region(0x170, 8, "libata"); /* port 1 */
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined );
+-#endif /* CONFIG_SCSI_SATA_INTEL_COMBINED */
++#endif /* CONFIG_SATA_INTEL_COMBINED */
+
+
+ int pcie_mch_quirk;
+@@ -1590,7 +1592,6 @@ static void __devinit fixup_rev1_53c810(
+ }
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
+
+-
+ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
+ {
+ while (f < end) {
+@@ -1690,6 +1691,96 @@ static void __devinit quirk_nvidia_ck804
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_pcie_aer_ext_cap);
+
++#ifdef CONFIG_PCI_MSI
++/* To disable MSI globally */
++int pci_msi_quirk;
++
++/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
++ * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
++ * some other busses controlled by the chipset even if Linux is not aware of it.
++ * Instead of setting the flag on all busses in the machine, simply disable MSI
++ * globally.
++ */
++static void __init quirk_svw_msi(struct pci_dev *dev)
++{
++ pci_msi_quirk = 1;
++ printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
++
++/* Disable MSI on chipsets that are known to not support it */
++static void __devinit quirk_disable_msi(struct pci_dev *dev)
++{
++ if (dev->subordinate) {
++ printk(KERN_WARNING "PCI: MSI quirk detected. "
++ "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
++ pci_name(dev));
++ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
++ }
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
++
++/* Go through the list of Hypertransport capabilities and
++ * return 1 if a HT MSI capability is found and enabled */
++static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
++{
++ u8 pos;
++ int ttl;
++ for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48;
++ pos && ttl;
++ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) {
++ u32 cap_hdr;
++ /* MSI mapping section according to Hypertransport spec */
++ if (pci_read_config_dword(dev, pos, &cap_hdr) == 0
++ && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) {
++ printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n",
++ pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled");
++ return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */
++ }
++ }
++ return 0;
++}
++
++/* Check the hypertransport MSI mapping to know whether MSI is enabled or not */
++static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
++{
++ if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
++ printk(KERN_WARNING "PCI: MSI quirk detected. "
++ "MSI disabled on chipset %s.\n",
++ pci_name(dev));
++ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
++ }
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
++ quirk_msi_ht_cap);
++
++/* The nVidia CK804 chipset may have 2 HT MSI mappings.
++ * MSI are supported if the MSI capability set in any of these mappings.
++ */
++static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
++{
++ struct pci_dev *pdev;
++
++ if (!dev->subordinate)
++ return;
++
++ /* check HT MSI cap on this chipset and the root one.
++ * a single one having MSI is enough to be sure that MSI are supported.
++ */
++ pdev = pci_get_slot(dev->bus, 0);
++ if (dev->subordinate && !msi_ht_cap_enabled(dev)
++ && !msi_ht_cap_enabled(pdev)) {
++ printk(KERN_WARNING "PCI: MSI quirk detected. "
++ "MSI disabled on chipset %s.\n",
++ pci_name(dev));
++ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
++ }
++ pci_dev_put(pdev);
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
++ quirk_nvidia_ck804_msi_ht_cap);
++#endif /* CONFIG_PCI_MSI */
++
+ EXPORT_SYMBOL(pcie_mch_quirk);
+ #ifdef CONFIG_HOTPLUG
+ EXPORT_SYMBOL(pci_fixup_device);
+diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
+index 99ffbd4..430281b 100644
+--- a/drivers/pci/remove.c
++++ b/drivers/pci/remove.c
+@@ -16,8 +16,11 @@ static void pci_free_resources(struct pc
+ }
+ }
+
+-static void pci_destroy_dev(struct pci_dev *dev)
++static void pci_stop_dev(struct pci_dev *dev)
+ {
++ if (!dev->global_list.next)
++ return;
++
+ if (!list_empty(&dev->global_list)) {
+ pci_proc_detach_device(dev);
+ pci_remove_sysfs_dev_files(dev);
+@@ -27,6 +30,11 @@ static void pci_destroy_dev(struct pci_d
+ dev->global_list.next = dev->global_list.prev = NULL;
+ up_write(&pci_bus_sem);
+ }
++}
++
++static void pci_destroy_dev(struct pci_dev *dev)
++{
++ pci_stop_dev(dev);
+
+ /* Remove the device from the device lists, and prevent any further
+ * list accesses from this device */
+@@ -119,5 +127,32 @@ void pci_remove_behind_bridge(struct pci
+ }
+ }
+
++static void pci_stop_bus_devices(struct pci_bus *bus)
++{
++ struct list_head *l, *n;
++
++ list_for_each_safe(l, n, &bus->devices) {
++ struct pci_dev *dev = pci_dev_b(l);
++ pci_stop_bus_device(dev);
++ }
++}
++
++/**
++ * pci_stop_bus_device - stop a PCI device and any children
++ * @dev: the device to stop
++ *
++ * Stop a PCI device (detach the driver, remove from the global list
++ * and so on). This also stop any subordinate buses and children in a
++ * depth-first manner.
++ */
++void pci_stop_bus_device(struct pci_dev *dev)
++{
++ if (dev->subordinate)
++ pci_stop_bus_devices(dev->subordinate);
++
++ pci_stop_dev(dev);
++}
++
+ EXPORT_SYMBOL(pci_remove_bus_device);
+ EXPORT_SYMBOL(pci_remove_behind_bridge);
++EXPORT_SYMBOL_GPL(pci_stop_bus_device);
+diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
+index f5ee7ce..e1dcefc 100644
+--- a/drivers/pci/rom.c
++++ b/drivers/pci/rom.c
+@@ -71,7 +71,11 @@ void __iomem *pci_map_rom(struct pci_dev
+ void __iomem *image;
+ int last_image;
+
+- /* IORESOURCE_ROM_SHADOW only set on x86 */
++ /*
++ * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
++ * memory map if the VGA enable bit of the Bridge Control register is
++ * set for embedded VGA.
++ */
+ if (res->flags & IORESOURCE_ROM_SHADOW) {
+ /* primary video rom always starts here */
+ start = (loff_t)0xC0000;
+diff --git a/drivers/pci/search.c b/drivers/pci/search.c
+index d529462..2f13eba 100644
+--- a/drivers/pci/search.c
++++ b/drivers/pci/search.c
+@@ -140,6 +140,31 @@ struct pci_dev * pci_get_slot(struct pci
+ }
+
+ /**
++ * pci_get_bus_and_slot - locate PCI device from a given PCI slot
++ * @bus: number of PCI bus on which desired PCI device resides
++ * @devfn: encodes number of PCI slot in which the desired PCI
++ * device resides and the logical device number within that slot
++ * in case of multi-function devices.
++ *
++ * Given a PCI bus and slot/function number, the desired PCI device
++ * is located in system global list of PCI devices. If the device
++ * is found, a pointer to its data structure is returned. If no
++ * device is found, %NULL is returned. The returned device has its
++ * reference count bumped by one.
++ */
++
++struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
++{
++ struct pci_dev *dev = NULL;
++
++ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
++ if (dev->bus->number == bus && dev->devfn == devfn)
++ return dev;
++ }
++ return NULL;
++}
++
++/**
+ * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+@@ -274,6 +299,45 @@ pci_get_device(unsigned int vendor, unsi
+ return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+ }
+
++/**
++ * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id
++ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
++ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
++ * @from: Previous PCI device found in search, or %NULL for new search.
++ *
++ * Iterates through the list of known PCI devices in the reverse order of
++ * pci_get_device.
++ * If a PCI device is found with a matching @vendor and @device, the reference
++ * count to the device is incremented and a pointer to its device structure
++ * is returned Otherwise, %NULL is returned. A new search is initiated by
++ * passing %NULL as the @from argument. Otherwise if @from is not %NULL,
++ * searches continue from next device on the global list. The reference
++ * count for @from is always decremented if it is not %NULL.
++ */
++struct pci_dev *
++pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from)
++{
++ struct list_head *n;
++ struct pci_dev *dev;
++
++ WARN_ON(in_interrupt());
++ down_read(&pci_bus_sem);
++ n = from ? from->global_list.prev : pci_devices.prev;
++
++ while (n && (n != &pci_devices)) {
++ dev = pci_dev_g(n);
++ if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
++ (device == PCI_ANY_ID || dev->device == device))
++ goto exit;
++ n = n->prev;
++ }
++ dev = NULL;
++exit:
++ dev = pci_dev_get(dev);
++ up_read(&pci_bus_sem);
++ pci_dev_put(from);
++ return dev;
++}
+
+ /**
+ * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
+@@ -382,12 +446,16 @@ 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);
++/* For boot time work */
++EXPORT_SYMBOL(pci_find_bus);
++EXPORT_SYMBOL(pci_find_next_bus);
++/* For everyone */
+ EXPORT_SYMBOL(pci_get_device);
++EXPORT_SYMBOL(pci_get_device_reverse);
+ EXPORT_SYMBOL(pci_get_subsys);
+ EXPORT_SYMBOL(pci_get_slot);
++EXPORT_SYMBOL(pci_get_bus_and_slot);
+ EXPORT_SYMBOL(pci_get_class);
+diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
+index 47c1071..8f7bcf5 100644
+--- a/drivers/pci/setup-bus.c
++++ b/drivers/pci/setup-bus.c
+@@ -57,10 +57,17 @@ pbus_assign_resources_sorted(struct pci_
+
+ /* Don't touch classless devices or host bridges or ioapics. */
+ if (class == PCI_CLASS_NOT_DEFINED ||
+- class == PCI_CLASS_BRIDGE_HOST ||
+- class == PCI_CLASS_SYSTEM_PIC)
++ class == PCI_CLASS_BRIDGE_HOST)
+ continue;
+
++ /* Don't touch ioapic devices already enabled by firmware */
++ if (class == PCI_CLASS_SYSTEM_PIC) {
++ u16 command;
++ pci_read_config_word(dev, PCI_COMMAND, &command);
++ if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
++ continue;
++ }
++
+ pdev_sort_resources(dev, &head);
+ }
+
+diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
+index 40569f4..3bcb7dc 100644
+--- a/drivers/pcmcia/at91_cf.c
++++ b/drivers/pcmcia/at91_cf.c
+@@ -64,9 +64,9 @@ static int at91_cf_ss_init(struct pcmcia
+ return 0;
+ }
+
+-static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r)
++static irqreturn_t at91_cf_irq(int irq, void *_cf)
+ {
+- struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf;
++ struct at91_cf_socket *cf = _cf;
+
+ if (irq == cf->board->det_pin) {
+ unsigned present = at91_cf_present(cf);
+@@ -241,12 +241,6 @@ static int __init at91_cf_probe(struct p
+ csa = at91_sys_read(AT91_EBI_CSA);
+ at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
+
+- /* force poweron defaults for these pins ... */
+- (void) at91_set_A_periph(AT91_PIN_PC9, 0); /* A25/CFRNW */
+- (void) at91_set_A_periph(AT91_PIN_PC10, 0); /* NCS4/CFCS */
+- (void) at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS5/CFCE1 */
+- (void) at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */
+-
+ /* nWAIT is _not_ a default setting */
+ (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
+
+@@ -316,12 +310,14 @@ static int __init at91_cf_probe(struct p
+ return 0;
+
+ fail2:
+- iounmap((void __iomem *) cf->socket.io_offset);
+ release_mem_region(io->start, io->end + 1 - io->start);
+ fail1:
++ if (cf->socket.io_offset)
++ iounmap((void __iomem *) cf->socket.io_offset);
+ if (board->irq_pin)
+ free_irq(board->irq_pin, cf);
+ fail0a:
++ device_init_wakeup(&pdev->dev, 0);
+ free_irq(board->det_pin, cf);
+ device_init_wakeup(&pdev->dev, 0);
+ fail0:
+@@ -360,26 +356,20 @@ static int at91_cf_suspend(struct platfo
+ struct at91_cf_data *board = cf->board;
+
+ pcmcia_socket_dev_suspend(&pdev->dev, mesg);
+- if (device_may_wakeup(&pdev->dev))
++ if (device_may_wakeup(&pdev->dev)) {
+ enable_irq_wake(board->det_pin);
+- else {
++ if (board->irq_pin)
++ enable_irq_wake(board->irq_pin);
++ } else {
+ disable_irq_wake(board->det_pin);
+- disable_irq(board->det_pin);
++ if (board->irq_pin)
++ disable_irq_wake(board->irq_pin);
+ }
+- if (board->irq_pin)
+- disable_irq(board->irq_pin);
+ return 0;
+ }
+
+ static int at91_cf_resume(struct platform_device *pdev)
+ {
+- struct at91_cf_socket *cf = platform_get_drvdata(pdev);
+- struct at91_cf_data *board = cf->board;
+-
+- if (board->irq_pin)
+- enable_irq(board->irq_pin);
+- if (!device_may_wakeup(&pdev->dev))
+- enable_irq(board->det_pin);
+ pcmcia_socket_dev_resume(&pdev->dev);
+ return 0;
+ }
+diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
+index d5dd0ce..551bde5 100644
+--- a/drivers/pcmcia/au1000_generic.c
++++ b/drivers/pcmcia/au1000_generic.c
+@@ -351,6 +351,7 @@ struct skt_dev_info {
+ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
+ {
+ struct skt_dev_info *sinfo;
++ struct au1000_pcmcia_socket *skt;
+ int ret, i;
+
+ sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL);
+@@ -365,7 +366,7 @@ int au1x00_pcmcia_socket_probe(struct de
+ * Initialise the per-socket structure.
+ */
+ for (i = 0; i < nr; i++) {
+- struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
++ skt = PCMCIA_SOCKET(i);
+ memset(skt, 0, sizeof(*skt));
+
+ skt->socket.resource_ops = &pccard_static_ops;
+@@ -438,17 +439,29 @@ int au1x00_pcmcia_socket_probe(struct de
+ dev_set_drvdata(dev, sinfo);
+ return 0;
+
+- do {
+- struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
++
++out_err:
++ flush_scheduled_work();
++ ops->hw_shutdown(skt);
++ while (i-- > 0) {
++ skt = PCMCIA_SOCKET(i);
+
+ del_timer_sync(&skt->poll_timer);
+ pcmcia_unregister_socket(&skt->socket);
+-out_err:
+ flush_scheduled_work();
++ if (i == 0) {
++ iounmap(skt->virt_io + (u32)mips_io_port_base);
++ skt->virt_io = NULL;
++ }
++#ifndef CONFIG_MIPS_XXS1500
++ else {
++ iounmap(skt->virt_io + (u32)mips_io_port_base);
++ skt->virt_io = NULL;
++ }
++#endif
+ ops->hw_shutdown(skt);
+
+- i--;
+- } while (i > 0);
++ }
+ kfree(sinfo);
+ out:
+ return ret;
+diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
+index 3f6d51d..2d7effe 100644
+--- a/drivers/pcmcia/cardbus.c
++++ b/drivers/pcmcia/cardbus.c
+@@ -138,7 +138,7 @@ int read_cb_mem(struct pcmcia_socket * s
+
+ cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len);
+
+- dev = pci_find_slot(s->cb_dev->subordinate->number, 0);
++ dev = pci_get_slot(s->cb_dev->subordinate, 0);
+ if (!dev)
+ goto fail;
+
+@@ -152,6 +152,9 @@ int read_cb_mem(struct pcmcia_socket * s
+ }
+
+ res = dev->resource + space - 1;
++
++ pci_dev_put(dev);
++
+ if (!res->flags)
+ goto fail;
+
+diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
+index 74b3124..0f70192 100644
+--- a/drivers/pcmcia/ds.c
++++ b/drivers/pcmcia/ds.c
+@@ -717,6 +717,7 @@ static int pcmcia_requery(struct device
+ static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
+ {
+ int no_devices=0;
++ int ret = 0;
+ unsigned long flags;
+
+ /* must be called with skt_mutex held */
+@@ -729,7 +730,7 @@ static void pcmcia_bus_rescan(struct pcm
+ * missing resource information or other trouble, we need to
+ * do this now. */
+ if (no_devices) {
+- int ret = pcmcia_card_add(skt);
++ ret = pcmcia_card_add(skt);
+ if (ret)
+ return;
+ }
+@@ -741,7 +742,9 @@ static void pcmcia_bus_rescan(struct pcm
+
+ /* we re-scan all devices, not just the ones connected to this
+ * socket. This does not matter, though. */
+- bus_rescan_devices(&pcmcia_bus_type);
++ ret = bus_rescan_devices(&pcmcia_bus_type);
++ if (ret)
++ printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n");
+ }
+
+ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
+@@ -1001,6 +1004,7 @@ static ssize_t pcmcia_store_allow_func_i
+ struct device_attribute *attr, const char *buf, size_t count)
+ {
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
++ int ret;
+
+ if (!count)
+ return -EINVAL;
+@@ -1009,7 +1013,10 @@ static ssize_t pcmcia_store_allow_func_i
+ p_dev->allow_func_id_match = 1;
+ mutex_unlock(&p_dev->socket->skt_mutex);
+
+- bus_rescan_devices(&pcmcia_bus_type);
++ ret = bus_rescan_devices(&pcmcia_bus_type);
++ if (ret)
++ printk(KERN_INFO "pcmcia: bus_rescan_devices failed after "
++ "allowing func_id matches\n");
+
+ return count;
+ }
+@@ -1292,10 +1299,22 @@ struct bus_type pcmcia_bus_type = {
+
+ static int __init init_pcmcia_bus(void)
+ {
++ int ret;
++
+ spin_lock_init(&pcmcia_dev_list_lock);
+
+- bus_register(&pcmcia_bus_type);
+- class_interface_register(&pcmcia_bus_interface);
++ ret = bus_register(&pcmcia_bus_type);
++ if (ret < 0) {
++ printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
++ return ret;
++ }
++ ret = class_interface_register(&pcmcia_bus_interface);
++ if (ret < 0) {
++ printk(KERN_WARNING
++ "pcmcia: class_interface_register error: %d\n", ret);
++ bus_unregister(&pcmcia_bus_type);
++ return ret;
++ }
+
+ pcmcia_setup_ioctl();
+
+diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
+index ad02629..caca0dc 100644
+--- a/drivers/pcmcia/hd64465_ss.c
++++ b/drivers/pcmcia/hd64465_ss.c
+@@ -650,7 +650,7 @@ static int hs_set_mem_map(struct pcmcia_
+ */
+ static int hs_irq_demux(int irq, void *dev)
+ {
+- hs_socket_t *sp = (hs_socket_t *)dev;
++ hs_socket_t *sp = dev;
+ u_int cscr;
+
+ DPRINTK("hs_irq_demux(irq=%d)\n", irq);
+@@ -671,13 +671,12 @@ static int hs_irq_demux(int irq, void *d
+ * Interrupt handling routine.
+ */
+
+-static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t hs_interrupt(int irq, void *dev)
+ {
+- hs_socket_t *sp = (hs_socket_t *)dev;
++ hs_socket_t *sp = dev;
+ u_int events = 0;
+ u_int cscr;
+-
+-
++
+ cscr = hs_in(sp, CSCR);
+
+ DPRINTK("hs_interrupt, cscr=%04x\n", cscr);
+diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
+index 2163aa7..c2ea07a 100644
+--- a/drivers/pcmcia/i82092.c
++++ b/drivers/pcmcia/i82092.c
+@@ -41,6 +41,7 @@ static struct pci_device_id i82092aa_pci
+ };
+ MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
+
++#ifdef CONFIG_PM
+ static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state)
+ {
+ return pcmcia_socket_dev_suspend(&dev->dev, state);
+@@ -50,14 +51,17 @@ static int i82092aa_socket_resume (struc
+ {
+ return pcmcia_socket_dev_resume(&dev->dev);
+ }
++#endif
+
+ static struct pci_driver i82092aa_pci_drv = {
+ .name = "i82092aa",
+ .id_table = i82092aa_pci_ids,
+ .probe = i82092aa_pci_probe,
+ .remove = __devexit_p(i82092aa_pci_remove),
++#ifdef CONFIG_PM
+ .suspend = i82092aa_socket_suspend,
+ .resume = i82092aa_socket_resume,
++#endif
+ };
+
+
+@@ -315,7 +319,7 @@ static int to_cycles(int ns)
+
+ /* Interrupt handler functionality */
+
+-static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t i82092aa_interrupt(int irq, void *dev)
+ {
+ int i;
+ int loopcount = 0;
+@@ -705,10 +709,7 @@ static int i82092aa_set_mem_map(struct p
+
+ static int i82092aa_module_init(void)
+ {
+- enter("i82092aa_module_init");
+- pci_register_driver(&i82092aa_pci_drv);
+- leave("i82092aa_module_init");
+- return 0;
++ return pci_register_driver(&i82092aa_pci_drv);
+ }
+
+ static void i82092aa_module_exit(void)
+diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h
+index 9c14599..b0d4533 100644
+--- a/drivers/pcmcia/i82092aa.h
++++ b/drivers/pcmcia/i82092aa.h
+@@ -23,7 +23,7 @@
+ static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+ static void i82092aa_pci_remove(struct pci_dev *dev);
+ static int card_present(int socketno);
+-static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs);
++static irqreturn_t i82092aa_interrupt(int irq, void *dev);
+
+
+
+diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
+index 1cc2682..ea74f98 100644
+--- a/drivers/pcmcia/i82365.c
++++ b/drivers/pcmcia/i82365.c
+@@ -80,7 +80,7 @@ module_param(pc_debug, int, 0644);
+ #define debug(lvl, fmt, arg...) do { } while (0)
+ #endif
+
+-static irqreturn_t i365_count_irq(int, void *, struct pt_regs *);
++static irqreturn_t i365_count_irq(int, void *);
+ static inline int _check_irq(int irq, int flags)
+ {
+ if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
+@@ -498,7 +498,7 @@ static u_int __init set_bridge_opts(u_sh
+ static volatile u_int irq_hits;
+ static u_short irq_sock;
+
+-static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t i365_count_irq(int irq, void *dev)
+ {
+ i365_get(irq_sock, I365_CSC);
+ irq_hits++;
+@@ -848,8 +848,7 @@ static void __init isa_probe(void)
+
+ /*====================================================================*/
+
+-static irqreturn_t pcic_interrupt(int irq, void *dev,
+- struct pt_regs *regs)
++static irqreturn_t pcic_interrupt(int irq, void *dev)
+ {
+ int i, j, csc;
+ u_int events, active;
+@@ -898,7 +897,7 @@ static irqreturn_t pcic_interrupt(int ir
+
+ static void pcic_interrupt_wrapper(u_long data)
+ {
+- pcic_interrupt(0, NULL, NULL);
++ pcic_interrupt(0, NULL);
+ poll_timer.expires = jiffies + poll_interval;
+ add_timer(&poll_timer);
+ }
+diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
+index 9e768ea..36fdaa5 100644
+--- a/drivers/pcmcia/m32r_cfc.c
++++ b/drivers/pcmcia/m32r_cfc.c
+@@ -254,7 +254,7 @@ static pcc_t pcc[] = {
+ #endif /* CONFIG_PLAT_USRV */
+ };
+
+-static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t pcc_interrupt(int, void *);
+
+ /*====================================================================*/
+
+@@ -372,14 +372,13 @@ static void add_pcc_socket(ulong base, i
+
+ /*====================================================================*/
+
+-static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t pcc_interrupt(int irq, void *dev)
+ {
+ int i;
+ u_int events = 0;
+ int handled = 0;
+
+- debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p, regs=%p\n",
+- irq, dev, regs);
++ debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev);
+ for (i = 0; i < pcc_sockets; i++) {
+ if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq)
+ continue;
+diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
+index 61d50b5..bbf0258 100644
+--- a/drivers/pcmcia/m32r_pcc.c
++++ b/drivers/pcmcia/m32r_pcc.c
+@@ -267,7 +267,7 @@ static pcc_t pcc[] = {
+ { "xnux2", 0 }, { "xnux2", 0 },
+ };
+
+-static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t pcc_interrupt(int, void *);
+
+ /*====================================================================*/
+
+@@ -352,7 +352,7 @@ static void add_pcc_socket(ulong base, i
+
+ /*====================================================================*/
+
+-static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t pcc_interrupt(int irq, void *dev)
+ {
+ int i, j, irc;
+ u_int events, active;
+@@ -395,7 +395,7 @@ static irqreturn_t pcc_interrupt(int irq
+
+ static void pcc_interrupt_wrapper(u_long data)
+ {
+- pcc_interrupt(0, NULL, NULL);
++ pcc_interrupt(0, NULL);
+ init_timer(&poll_timer);
+ poll_timer.expires = jiffies + poll_interval;
+ add_timer(&poll_timer);
+diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
+index d0f68ab..3b72be8 100644
+--- a/drivers/pcmcia/m8xx_pcmcia.c
++++ b/drivers/pcmcia/m8xx_pcmcia.c
+@@ -266,7 +266,7 @@ static const u32 m8xx_size_to_gray[M8XX_
+
+ /* ------------------------------------------------------------------------- */
+
+-static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs);
++static irqreturn_t m8xx_interrupt(int irq, void *dev);
+
+ #define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */
+
+@@ -427,7 +427,7 @@ static int voltage_set(int slot, int vcc
+ reg |= BCSR1_PCCVCC1;
+ break;
+ default:
+- return 1;
++ goto out_unmap;
+ }
+
+ switch(vpp) {
+@@ -438,15 +438,15 @@ static int voltage_set(int slot, int vcc
+ if(vcc == vpp)
+ reg |= BCSR1_PCCVPP1;
+ else
+- return 1;
++ goto out_unmap;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= BCSR1_PCCVPP0;
+ else
+- return 1;
++ goto out_unmap;
+ default:
+- return 1;
++ goto out_unmap;
+ }
+
+ /* first, turn off all power */
+@@ -457,6 +457,10 @@ static int voltage_set(int slot, int vcc
+
+ iounmap(bcsr_io);
+ return 0;
++
++out_unmap:
++ iounmap(bcsr_io);
++ return 1;
+ }
+
+ #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+@@ -646,7 +650,7 @@ static struct platform_device m8xx_devic
+ static u32 pending_events[PCMCIA_SOCKETS_NO];
+ static DEFINE_SPINLOCK(pending_event_lock);
+
+-static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t m8xx_interrupt(int irq, void *dev)
+ {
+ struct socket_info *s;
+ struct event_table *e;
+diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
+index 420e10a..06bf7f4 100644
+--- a/drivers/pcmcia/omap_cf.c
++++ b/drivers/pcmcia/omap_cf.c
+@@ -67,6 +67,7 @@ struct omap_cf_socket {
+ struct platform_device *pdev;
+ unsigned long phys_cf;
+ u_int irq;
++ struct resource iomem;
+ };
+
+ #define POLL_INTERVAL (2 * HZ)
+@@ -101,7 +102,7 @@ static void omap_cf_timer(unsigned long
+ * claim the card's IRQ. It may also detect some card insertions, but
+ * not removals; it can't always eliminate timer irqs.
+ */
+-static irqreturn_t omap_cf_irq(int irq, void *_cf, struct pt_regs *r)
++static irqreturn_t omap_cf_irq(int irq, void *_cf)
+ {
+ omap_cf_timer((unsigned long)_cf);
+ return IRQ_HANDLED;
+@@ -112,16 +113,14 @@ static int omap_cf_get_status(struct pcm
+ if (!sp)
+ return -EINVAL;
+
+- /* FIXME power management should probably be board-specific:
+- * - 3VCARD vs XVCARD (OSK only handles 3VCARD)
+- * - POWERON (switched on/off by set_socket)
+- */
++ /* NOTE CF is always 3VCARD */
+ if (omap_cf_present()) {
+ struct omap_cf_socket *cf;
+
+ *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
+ cf = container_of(s, struct omap_cf_socket, socket);
+- s->irq.AssignedIRQ = cf->irq;
++ s->irq.AssignedIRQ = 0;
++ s->pci_irq = cf->irq;
+ } else
+ *sp = 0;
+ return 0;
+@@ -132,7 +131,7 @@ omap_cf_set_socket(struct pcmcia_socket
+ {
+ u16 control;
+
+- /* FIXME some non-OSK boards will support power switching */
++ /* REVISIT some non-OSK boards may support power switching */
+ switch (s->Vcc) {
+ case 0:
+ case 33:
+@@ -204,7 +203,7 @@ static struct pccard_operations omap_cf_
+ * "what chipselect is used". Boards could want more.
+ */
+
+-static int __init omap_cf_probe(struct device *dev)
++static int __devinit omap_cf_probe(struct device *dev)
+ {
+ unsigned seg;
+ struct omap_cf_socket *cf;
+@@ -253,6 +252,9 @@ static int __init omap_cf_probe(struct d
+ default:
+ goto fail1;
+ }
++ cf->iomem.start = cf->phys_cf;
++ cf->iomem.end = cf->iomem.end + SZ_8K - 1;
++ cf->iomem.flags = IORESOURCE_MEM;
+
+ /* pcmcia layer only remaps "real" memory */
+ cf->socket.io_offset = (unsigned long)
+@@ -296,6 +298,7 @@ static int __init omap_cf_probe(struct d
+ cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+ | SS_CAP_MEM_ALIGN;
+ cf->socket.map_size = SZ_2K;
++ cf->socket.io[0].res = &cf->iomem;
+
+ status = pcmcia_register_socket(&cf->socket);
+ if (status < 0)
+@@ -306,9 +309,10 @@ static int __init omap_cf_probe(struct d
+ return 0;
+
+ fail2:
+- iounmap((void __iomem *) cf->socket.io_offset);
+ release_mem_region(cf->phys_cf, SZ_8K);
+ fail1:
++ if (cf->socket.io_offset)
++ iounmap((void __iomem *) cf->socket.io_offset);
+ free_irq(irq, cf);
+ fail0:
+ kfree(cf);
+@@ -334,15 +338,15 @@ static struct device_driver omap_cf_driv
+ .bus = &platform_bus_type,
+ .probe = omap_cf_probe,
+ .remove = __devexit_p(omap_cf_remove),
+- .suspend = pcmcia_socket_dev_suspend,
+- .resume = pcmcia_socket_dev_resume,
++ .suspend = pcmcia_socket_dev_suspend,
++ .resume = pcmcia_socket_dev_resume,
+ };
+
+ static int __init omap_cf_init(void)
+ {
+ if (cpu_is_omap16xx())
+- driver_register(&omap_cf_driver);
+- return 0;
++ return driver_register(&omap_cf_driver);
++ return -ENODEV;
+ }
+
+ static void __exit omap_cf_exit(void)
+diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
+index 9ad18e6..310ede5 100644
+--- a/drivers/pcmcia/pcmcia_ioctl.c
++++ b/drivers/pcmcia/pcmcia_ioctl.c
+@@ -128,9 +128,12 @@ static int proc_read_drivers(char *buf,
+ int count, int *eof, void *data)
+ {
+ char *p = buf;
++ int rc;
+
+- bus_for_each_drv(&pcmcia_bus_type, NULL,
+- (void *) &p, proc_read_drivers_callback);
++ rc = bus_for_each_drv(&pcmcia_bus_type, NULL,
++ (void *) &p, proc_read_drivers_callback);
++ if (rc < 0)
++ return rc;
+
+ return (p - buf);
+ }
+@@ -269,8 +272,10 @@ rescan:
+ * Prevent this racing with a card insertion.
+ */
+ mutex_lock(&s->skt_mutex);
+- bus_rescan_devices(&pcmcia_bus_type);
++ ret = bus_rescan_devices(&pcmcia_bus_type);
+ mutex_unlock(&s->skt_mutex);
++ if (ret)
++ goto err_put_module;
+
+ /* check whether the driver indeed matched. I don't care if this
+ * is racy or not, because it can only happen on cardmgr access
+diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
+index c832339..b9201c2 100644
+--- a/drivers/pcmcia/pcmcia_resource.c
++++ b/drivers/pcmcia/pcmcia_resource.c
+@@ -95,7 +95,7 @@ static int alloc_io_space(struct pcmcia_
+ * potential conflicts, just the most obvious ones.
+ */
+ for (i = 0; i < MAX_IO_WIN; i++)
+- if ((s->io[i].res) &&
++ if ((s->io[i].res) && *base &&
+ ((s->io[i].res->start & (align-1)) == *base))
+ return 1;
+ for (i = 0; i < MAX_IO_WIN; i++) {
+@@ -784,7 +784,7 @@ EXPORT_SYMBOL(pcmcia_request_io);
+ */
+
+ #ifdef CONFIG_PCMCIA_PROBE
+-static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
++static irqreturn_t test_action(int cpl, void *dev_id)
+ {
+ return IRQ_NONE;
+ }
+diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
+index 22c5e74..a70f97f 100644
+--- a/drivers/pcmcia/pd6729.c
++++ b/drivers/pcmcia/pd6729.c
+@@ -182,7 +182,7 @@ static void indirect_write16(struct pd67
+
+ /* Interrupt handler functionality */
+
+-static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t pd6729_interrupt(int irq, void *dev)
+ {
+ struct pd6729_socket *socket = (struct pd6729_socket *)dev;
+ int i;
+@@ -249,7 +249,7 @@ static void pd6729_interrupt_wrapper(uns
+ {
+ struct pd6729_socket *socket = (struct pd6729_socket *) data;
+
+- pd6729_interrupt(0, (void *)socket, NULL);
++ pd6729_interrupt(0, (void *)socket);
+ mod_timer(&socket->poll_timer, jiffies + HZ);
+ }
+
+@@ -575,7 +575,7 @@ static struct pccard_operations pd6729_o
+ .set_mem_map = pd6729_set_mem_map,
+ };
+
+-static irqreturn_t pd6729_test(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t pd6729_test(int irq, void *dev)
+ {
+ dprintk("-> hit on irq %d\n", irq);
+ return IRQ_HANDLED;
+@@ -755,6 +755,7 @@ static void __devexit pd6729_pci_remove(
+ kfree(socket);
+ }
+
++#ifdef CONFIG_PM
+ static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state)
+ {
+ return pcmcia_socket_dev_suspend(&dev->dev, state);
+@@ -764,6 +765,7 @@ static int pd6729_socket_resume(struct p
+ {
+ return pcmcia_socket_dev_resume(&dev->dev);
+ }
++#endif
+
+ static struct pci_device_id pd6729_pci_ids[] = {
+ {
+@@ -781,8 +783,10 @@ static struct pci_driver pd6729_pci_drv
+ .id_table = pd6729_pci_ids,
+ .probe = pd6729_pci_probe,
+ .remove = __devexit_p(pd6729_pci_remove),
++#ifdef CONFIG_PM
+ .suspend = pd6729_socket_suspend,
+ .resume = pd6729_socket_resume,
++#endif
+ };
+
+ static int pd6729_module_init(void)
+diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
+index b351813..dca9f85 100644
+--- a/drivers/pcmcia/pxa2xx_base.c
++++ b/drivers/pcmcia/pxa2xx_base.c
+@@ -166,7 +166,7 @@ pxa2xx_pcmcia_frequency_change(struct so
+ }
+ #endif
+
+-int pxa2xx_drv_pcmcia_probe(struct device *dev)
++int __pxa2xx_drv_pcmcia_probe(struct device *dev)
+ {
+ int ret;
+ struct pcmcia_low_level *ops;
+@@ -203,35 +203,52 @@ int pxa2xx_drv_pcmcia_probe(struct devic
+
+ return ret;
+ }
+-EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe);
++EXPORT_SYMBOL(__pxa2xx_drv_pcmcia_probe);
+
+-static int pxa2xx_drv_pcmcia_resume(struct device *dev)
++
++static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
++{
++ return __pxa2xx_drv_pcmcia_probe(&dev->dev);
++}
++
++static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
++{
++ return soc_common_drv_pcmcia_remove(&dev->dev);
++}
++
++static int pxa2xx_drv_pcmcia_suspend(struct platform_device *dev, pm_message_t state)
++{
++ return pcmcia_socket_dev_suspend(&dev->dev, state);
++}
++
++static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev)
+ {
+- struct pcmcia_low_level *ops = dev->platform_data;
++ struct pcmcia_low_level *ops = dev->dev.platform_data;
+ int nr = ops ? ops->nr : 0;
+
+ MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0);
+
+- return pcmcia_socket_dev_resume(dev);
++ return pcmcia_socket_dev_resume(&dev->dev);
+ }
+
+-static struct device_driver pxa2xx_pcmcia_driver = {
++static struct platform_driver pxa2xx_pcmcia_driver = {
+ .probe = pxa2xx_drv_pcmcia_probe,
+- .remove = soc_common_drv_pcmcia_remove,
+- .suspend = pcmcia_socket_dev_suspend,
++ .remove = pxa2xx_drv_pcmcia_remove,
++ .suspend = pxa2xx_drv_pcmcia_suspend,
+ .resume = pxa2xx_drv_pcmcia_resume,
+- .name = "pxa2xx-pcmcia",
+- .bus = &platform_bus_type,
++ .driver = {
++ .name = "pxa2xx-pcmcia",
++ },
+ };
+
+ static int __init pxa2xx_pcmcia_init(void)
+ {
+- return driver_register(&pxa2xx_pcmcia_driver);
++ return platform_driver_register(&pxa2xx_pcmcia_driver);
+ }
+
+ static void __exit pxa2xx_pcmcia_exit(void)
+ {
+- driver_unregister(&pxa2xx_pcmcia_driver);
++ platform_driver_unregister(&pxa2xx_pcmcia_driver);
+ }
+
+ fs_initcall(pxa2xx_pcmcia_init);
+diff --git a/drivers/pcmcia/pxa2xx_base.h b/drivers/pcmcia/pxa2xx_base.h
+index e46cff3..235d681 100644
+--- a/drivers/pcmcia/pxa2xx_base.h
++++ b/drivers/pcmcia/pxa2xx_base.h
+@@ -1,3 +1,3 @@
+ /* temporary measure */
+-extern int pxa2xx_drv_pcmcia_probe(struct device *);
++extern int __pxa2xx_drv_pcmcia_probe(struct device *);
+
+diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
+index fd1f691..a92f111 100644
+--- a/drivers/pcmcia/pxa2xx_lubbock.c
++++ b/drivers/pcmcia/pxa2xx_lubbock.c
+@@ -260,7 +260,7 @@ int __init pcmcia_lubbock_init(struct sa
+ lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
+
+ sadev->dev.platform_data = &lubbock_pcmcia_ops;
+- ret = pxa2xx_drv_pcmcia_probe(&sadev->dev);
++ ret = __pxa2xx_drv_pcmcia_probe(&sadev->dev);
+ }
+
+ return ret;
+diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
+index ecaa132..e433704 100644
+--- a/drivers/pcmcia/soc_common.c
++++ b/drivers/pcmcia/soc_common.c
+@@ -256,7 +256,7 @@ static void soc_common_pcmcia_poll_event
+ * handling code performs scheduling operations which cannot be
+ * executed from within an interrupt context.
+ */
+-static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
+ {
+ struct soc_pcmcia_socket *skt = dev;
+
+@@ -824,3 +824,4 @@ int soc_common_drv_pcmcia_remove(struct
+
+ return 0;
+ }
++EXPORT_SYMBOL(soc_common_drv_pcmcia_remove);
+diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
+index c5d7476..933cd86 100644
+--- a/drivers/pcmcia/socket_sysfs.c
++++ b/drivers/pcmcia/socket_sysfs.c
+@@ -298,7 +298,7 @@ static ssize_t pccard_store_cis(struct k
+ {
+ struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+ cisdump_t *cis;
+- ssize_t ret = count;
++ int error;
+
+ if (off)
+ return -EINVAL;
+@@ -316,25 +316,22 @@ static ssize_t pccard_store_cis(struct k
+ cis->Length = count + 1;
+ memcpy(cis->Data, buf, count);
+
+- if (pcmcia_replace_cis(s, cis))
+- ret = -EIO;
+-
++ error = pcmcia_replace_cis(s, cis);
+ kfree(cis);
++ if (error)
++ return -EIO;
+
+- if (!ret) {
+- mutex_lock(&s->skt_mutex);
+- 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);
+- }
++ mutex_lock(&s->skt_mutex);
++ 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);
+ }
+- mutex_unlock(&s->skt_mutex);
+ }
++ mutex_unlock(&s->skt_mutex);
+
+-
+- return (ret);
++ return count;
+ }
+
+
+diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
+index 65a6067..2d2f415 100644
+--- a/drivers/pcmcia/tcic.c
++++ b/drivers/pcmcia/tcic.c
+@@ -116,7 +116,7 @@ module_param(cycle_time, int, 0444);
+
+ /*====================================================================*/
+
+-static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs);
++static irqreturn_t tcic_interrupt(int irq, void *dev);
+ static void tcic_timer(u_long data);
+ static struct pccard_operations tcic_operations;
+
+@@ -218,7 +218,7 @@ static int to_cycles(int ns)
+
+ static volatile u_int irq_hits;
+
+-static irqreturn_t __init tcic_irq_count(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t __init tcic_irq_count(int irq, void *dev)
+ {
+ irq_hits++;
+ return IRQ_HANDLED;
+@@ -505,7 +505,7 @@ static int __init init_tcic(void)
+ }
+
+ /* jump start interrupt handler, if needed */
+- tcic_interrupt(0, NULL, NULL);
++ tcic_interrupt(0, NULL);
+
+ platform_device_register(&tcic_device);
+
+@@ -547,7 +547,7 @@ static void __exit exit_tcic(void)
+
+ /*====================================================================*/
+
+-static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t tcic_interrupt(int irq, void *dev)
+ {
+ int i, quick = 0;
+ u_char latch, sstat;
+@@ -606,7 +606,7 @@ static void tcic_timer(u_long data)
+ {
+ debug(2, "tcic_timer()\n");
+ tcic_timer_pending = 0;
+- tcic_interrupt(0, NULL, NULL);
++ tcic_interrupt(0, NULL);
+ } /* tcic_timer */
+
+ /*====================================================================*/
+diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
+index e076a13..e90d8e8 100644
+--- a/drivers/pcmcia/vrc4171_card.c
++++ b/drivers/pcmcia/vrc4171_card.c
+@@ -514,7 +514,7 @@ static inline unsigned int get_events(in
+ return events;
+ }
+
+-static irqreturn_t pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pccard_interrupt(int irq, void *dev_id)
+ {
+ vrc4171_socket_t *socket;
+ unsigned int events;
+diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
+index d19a913..812f038 100644
+--- a/drivers/pcmcia/vrc4173_cardu.c
++++ b/drivers/pcmcia/vrc4173_cardu.c
+@@ -440,7 +440,7 @@ static uint16_t get_events(vrc4173_socke
+ return events;
+ }
+
+-static void cardu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void cardu_interrupt(int irq, void *dev_id)
+ {
+ vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id;
+ uint16_t events;
+diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
+index 1344746..da471bd 100644
+--- a/drivers/pcmcia/yenta_socket.c
++++ b/drivers/pcmcia/yenta_socket.c
+@@ -442,7 +442,7 @@ static int yenta_set_mem_map(struct pcmc
+
+
+
+-static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t yenta_interrupt(int irq, void *dev_id)
+ {
+ unsigned int events;
+ struct yenta_socket *socket = (struct yenta_socket *) dev_id;
+@@ -478,7 +478,7 @@ static void yenta_interrupt_wrapper(unsi
+ {
+ struct yenta_socket *socket = (struct yenta_socket *) data;
+
+- yenta_interrupt(0, (void *)socket, NULL);
++ yenta_interrupt(0, (void *)socket);
+ socket->poll_timer.expires = jiffies + HZ;
+ add_timer(&socket->poll_timer);
+ }
+@@ -896,7 +896,7 @@ static unsigned int yenta_probe_irq(stru
+ #ifdef CONFIG_YENTA_TI
+
+ /* interrupt handler, only used during probing */
+-static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t yenta_probe_handler(int irq, void *dev_id)
+ {
+ struct yenta_socket *socket = (struct yenta_socket *) dev_id;
+ u8 csc;
+@@ -1197,8 +1197,12 @@ static int __devinit yenta_probe (struct
+ ret = pcmcia_register_socket(&socket->socket);
+ if (ret == 0) {
+ /* Add the yenta register attributes */
+- device_create_file(&dev->dev, &dev_attr_yenta_registers);
+- goto out;
++ ret = device_create_file(&dev->dev, &dev_attr_yenta_registers);
++ if (ret == 0)
++ goto out;
++
++ /* error path... */
++ pcmcia_unregister_socket(&socket->socket);
+ }
+
+ unmap:
+@@ -1213,7 +1217,7 @@ static int __devinit yenta_probe (struct
+ return ret;
+ }
+
+-
++#ifdef CONFIG_PM
+ static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state)
+ {
+ struct yenta_socket *socket = pci_get_drvdata(dev);
+@@ -1248,12 +1252,18 @@ static int yenta_dev_resume (struct pci_
+ struct yenta_socket *socket = pci_get_drvdata(dev);
+
+ if (socket) {
++ int rc;
++
+ pci_set_power_state(dev, 0);
+ /* FIXME: pci_restore_state needs to have a better interface */
+ 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);
++
++ rc = pci_enable_device(dev);
++ if (rc)
++ return rc;
++
+ pci_set_master(dev);
+
+ if (socket->type && socket->type->restore_state)
+@@ -1262,7 +1272,7 @@ static int yenta_dev_resume (struct pci_
+
+ return pcmcia_socket_dev_resume(&dev->dev);
+ }
+-
++#endif
+
+ #define CB_ID(vend,dev,type) \
+ { \
+@@ -1359,8 +1369,10 @@ static struct pci_driver yenta_cardbus_d
+ .id_table = yenta_table,
+ .probe = yenta_probe,
+ .remove = __devexit_p(yenta_close),
++#ifdef CONFIG_PM
+ .suspend = yenta_dev_suspend,
+ .resume = yenta_dev_resume,
++#endif
+ };
+
+
+diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
+index f2e0179..3ac5b12 100644
+--- a/drivers/pnp/isapnp/core.c
++++ b/drivers/pnp/isapnp/core.c
+@@ -1049,6 +1049,10 @@ static int __init isapnp_init(void)
+ printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
+ return 0;
+ }
++#ifdef CONFIG_PPC_MERGE
++ if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP))
++ return -EINVAL;
++#endif
+ #ifdef ISAPNP_REGION_OK
+ if (!request_region(_PIDXR, 1, "isapnp index")) {
+ printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
+diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
+index dc79b0a..379048f 100644
+--- a/drivers/pnp/pnpacpi/rsparser.c
++++ b/drivers/pnp/pnpacpi/rsparser.c
+@@ -776,21 +776,32 @@ static void pnpacpi_encode_dma(struct ac
+ struct resource *p)
+ {
+ /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
+- if (p->flags & IORESOURCE_DMA_COMPATIBLE)
+- resource->data.dma.type = ACPI_COMPATIBILITY;
+- else if (p->flags & IORESOURCE_DMA_TYPEA)
+- resource->data.dma.type = ACPI_TYPE_A;
+- else if (p->flags & IORESOURCE_DMA_TYPEB)
+- resource->data.dma.type = ACPI_TYPE_B;
+- else if (p->flags & IORESOURCE_DMA_TYPEF)
+- resource->data.dma.type = ACPI_TYPE_F;
+- if (p->flags & IORESOURCE_DMA_8BIT)
+- resource->data.dma.transfer = ACPI_TRANSFER_8;
+- else if (p->flags & IORESOURCE_DMA_8AND16BIT)
+- resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+- else if (p->flags & IORESOURCE_DMA_16BIT)
+- resource->data.dma.transfer = ACPI_TRANSFER_16;
+- resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
++ switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
++ case IORESOURCE_DMA_TYPEA:
++ resource->data.dma.type = ACPI_TYPE_A;
++ break;
++ case IORESOURCE_DMA_TYPEB:
++ resource->data.dma.type = ACPI_TYPE_B;
++ break;
++ case IORESOURCE_DMA_TYPEF:
++ resource->data.dma.type = ACPI_TYPE_F;
++ break;
++ default:
++ resource->data.dma.type = ACPI_COMPATIBILITY;
++ }
++
++ switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
++ case IORESOURCE_DMA_8BIT:
++ resource->data.dma.transfer = ACPI_TRANSFER_8;
++ break;
++ case IORESOURCE_DMA_8AND16BIT:
++ resource->data.dma.transfer = ACPI_TRANSFER_8_16;
++ break;
++ default:
++ resource->data.dma.transfer = ACPI_TRANSFER_16;
++ }
++
++ resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
+ resource->data.dma.channel_count = 1;
+ resource->data.dma.channels[0] = p->start;
+ }
+diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
+index 551f58e..81a6c83 100644
+--- a/drivers/pnp/pnpbios/core.c
++++ b/drivers/pnp/pnpbios/core.c
+@@ -526,6 +526,10 @@ static int __init pnpbios_init(void)
+ {
+ int ret;
+
++#if defined(CONFIG_PPC_MERGE)
++ if (check_legacy_ioport(PNPBIOS_BASE))
++ return -ENODEV;
++#endif
+ if (pnpbios_disabled || dmi_check_system(pnpbios_dmi_table)) {
+ printk(KERN_INFO "PnPBIOS: Disabled\n");
+ return -ENODEV;
+@@ -575,6 +579,10 @@ subsys_initcall(pnpbios_init);
+
+ static int __init pnpbios_thread_init(void)
+ {
++#if defined(CONFIG_PPC_MERGE)
++ if (check_legacy_ioport(PNPBIOS_BASE))
++ return 0;
++#endif
+ if (pnpbios_disabled)
+ return 0;
+ #ifdef CONFIG_HOTPLUG
+diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
+index 5c8ec21..a685fbe 100644
+--- a/drivers/pnp/resource.c
++++ b/drivers/pnp/resource.c
+@@ -348,7 +348,7 @@ int pnp_check_mem(struct pnp_dev * dev,
+ return 1;
+ }
+
+-static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pnp_test_handler(int irq, void *dev_id)
+ {
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
+index 0b2d2c3..4142115 100644
+--- a/drivers/rapidio/Kconfig
++++ b/drivers/rapidio/Kconfig
+@@ -15,4 +15,4 @@ config RAPIDIO_DISC_TIMEOUT
+ default "30"
+ ---help---
+ Amount of time a discovery node waits for a host to complete
+- enumeration beforing giving up.
++ enumeration before giving up.
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index 7ff1d88..fc766a7 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -27,7 +27,7 @@ config RTC_HCTOSYS
+ help
+ If you say yes here, the system time will be set using
+ the value read from the specified RTC device. This is useful
+- in order to avoid unnecessary fschk runs.
++ in order to avoid unnecessary fsck runs.
+
+ config RTC_HCTOSYS_DEVICE
+ string "The RTC to read the time from"
+@@ -37,6 +37,13 @@ config RTC_HCTOSYS_DEVICE
+ The RTC device that will be used as the source for
+ the system time, usually rtc0.
+
++config RTC_DEBUG
++ bool "RTC debug support"
++ depends on RTC_CLASS = y
++ help
++ Say yes here to enable debugging support in the RTC framework
++ and individual RTC drivers.
++
+ comment "RTC interfaces"
+ depends on RTC_CLASS
+
+@@ -45,8 +52,8 @@ config RTC_INTF_SYSFS
+ depends on RTC_CLASS && SYSFS
+ default RTC_CLASS
+ help
+- Say yes here if you want to use your RTC using the sysfs
+- interface, /sys/class/rtc/rtcX .
++ Say yes here if you want to use your RTCs using sysfs interfaces,
++ /sys/class/rtc/rtc0 through /sys/.../rtcN.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-sysfs.
+@@ -56,8 +63,9 @@ config RTC_INTF_PROC
+ depends on RTC_CLASS && PROC_FS
+ default RTC_CLASS
+ help
+- Say yes here if you want to use your RTC using the proc
+- interface, /proc/driver/rtc .
++ Say yes here if you want to use your first RTC through the proc
++ interface, /proc/driver/rtc. Other RTCs will not be available
++ through that API.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-proc.
+@@ -67,8 +75,11 @@ config RTC_INTF_DEV
+ depends on RTC_CLASS
+ default RTC_CLASS
+ help
+- Say yes here if you want to use your RTC using the dev
+- interface, /dev/rtc .
++ Say yes here if you want to use your RTCs using the /dev
++ interfaces, which "udev" sets up as /dev/rtc0 through
++ /dev/rtcN. You may want to set up a symbolic link so one
++ of these can be accessed as /dev/rtc, which is a name
++ expected by "hwclock" and some other programs.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-dev.
+@@ -78,7 +89,8 @@ config RTC_INTF_DEV_UIE_EMUL
+ depends on RTC_INTF_DEV
+ help
+ Provides an emulation for RTC_UIE if the underlaying rtc chip
+- driver did not provide RTC_UIE ioctls.
++ driver does not expose RTC_UIE ioctls. Those requests generate
++ once-per-second update interrupts, used for synchronization.
+
+ comment "RTC drivers"
+ depends on RTC_CLASS
+@@ -238,6 +250,16 @@ config RTC_DRV_SA1100
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-sa1100.
+
++config RTC_DRV_SH
++ tristate "SuperH On-Chip RTC"
++ depends on RTC_CLASS && SUPERH
++ help
++ Say Y here to enable support for the on-chip RTC found in
++ most SuperH processors.
++
++ To compile this driver as a module, choose M here: the
++ module will be called rtc-sh.
++
+ config RTC_DRV_VR41XX
+ tristate "NEC VR41XX"
+ depends on RTC_CLASS && CPU_VR41XX
+diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
+index bbcfb09..3ba5ff6 100644
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -2,6 +2,10 @@
+ # Makefile for RTC class/drivers.
+ #
+
++ifeq ($(CONFIG_RTC_DEBUG),y)
++ EXTRA_CFLAGS += -DDEBUG
++endif
++
+ obj-$(CONFIG_RTC_LIB) += rtc-lib.o
+ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
+ obj-$(CONFIG_RTC_CLASS) += rtc-core.o
+@@ -31,3 +35,4 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031
+ obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
+ obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o
++obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
+diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
+index 1cb61a7..7a0d8ee 100644
+--- a/drivers/rtc/class.c
++++ b/drivers/rtc/class.c
+@@ -39,7 +39,7 @@ static void rtc_device_release(struct cl
+ * Returns the pointer to the new struct class device.
+ */
+ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
+- struct rtc_class_ops *ops,
++ const struct rtc_class_ops *ops,
+ struct module *owner)
+ {
+ struct rtc_device *rtc;
+@@ -142,9 +142,9 @@ static void __exit rtc_exit(void)
+ class_destroy(rtc_class);
+ }
+
+-module_init(rtc_init);
++subsys_initcall(rtc_init);
+ module_exit(rtc_exit);
+
+-MODULE_AUTHOR("Alessandro Zummo <a.zummo at towerteh.it>");
++MODULE_AUTHOR("Alessandro Zummo <a.zummo at towertech.it>");
+ MODULE_DESCRIPTION("RTC class support");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c
+index dfd0ce8..bd61e99 100644
+--- a/drivers/rtc/rtc-at91.c
++++ b/drivers/rtc/rtc-at91.c
+@@ -238,8 +238,7 @@ static int at91_rtc_proc(struct device *
+ /*
+ * IRQ handler for the RTC
+ */
+-static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
+ {
+ struct platform_device *pdev = dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+@@ -267,7 +266,7 @@ static irqreturn_t at91_rtc_interrupt(in
+ return IRQ_NONE; /* not handled */
+ }
+
+-static struct rtc_class_ops at91_rtc_ops = {
++static const struct rtc_class_ops at91_rtc_ops = {
+ .ioctl = at91_rtc_ioctl,
+ .read_time = at91_rtc_readtime,
+ .set_time = at91_rtc_settime,
+@@ -307,6 +306,7 @@ static int __init at91_rtc_probe(struct
+ return PTR_ERR(rtc);
+ }
+ platform_set_drvdata(pdev, rtc);
++ device_init_wakeup(&pdev->dev, 1);
+
+ printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+ return 0;
+@@ -327,6 +327,7 @@ static int __devexit at91_rtc_remove(str
+
+ rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
++ device_init_wakeup(&pdev->dev, 0);
+
+ return 0;
+ }
+@@ -336,6 +337,7 @@ static int __devexit at91_rtc_remove(str
+ /* AT91RM9200 RTC Power management control */
+
+ static struct timespec at91_rtc_delta;
++static u32 at91_rtc_imr;
+
+ static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+@@ -349,6 +351,18 @@ static int at91_rtc_suspend(struct platf
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ save_time_delta(&at91_rtc_delta, &time);
+
++ /* this IRQ is shared with DBGU and other hardware which isn't
++ * necessarily doing PM like we are...
++ */
++ at91_rtc_imr = at91_sys_read(AT91_RTC_IMR)
++ & (AT91_RTC_ALARM|AT91_RTC_SECEV);
++ if (at91_rtc_imr) {
++ if (device_may_wakeup(&pdev->dev))
++ enable_irq_wake(AT91_ID_SYS);
++ else
++ at91_sys_write(AT91_RTC_IDR, at91_rtc_imr);
++ }
++
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+@@ -367,6 +381,13 @@ static int at91_rtc_resume(struct platfo
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ restore_time_delta(&at91_rtc_delta, &time);
+
++ if (at91_rtc_imr) {
++ if (device_may_wakeup(&pdev->dev))
++ disable_irq_wake(AT91_ID_SYS);
++ else
++ at91_sys_write(AT91_RTC_IER, at91_rtc_imr);
++ }
++
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
+index 61a5825..583789c 100644
+--- a/drivers/rtc/rtc-dev.c
++++ b/drivers/rtc/rtc-dev.c
+@@ -24,7 +24,7 @@ static int rtc_dev_open(struct inode *in
+ int err;
+ struct rtc_device *rtc = container_of(inode->i_cdev,
+ struct rtc_device, char_dev);
+- struct rtc_class_ops *ops = rtc->ops;
++ const struct rtc_class_ops *ops = rtc->ops;
+
+ /* We keep the lock as long as the device is in use
+ * and return immediately if busy
+@@ -209,7 +209,7 @@ static int rtc_dev_ioctl(struct inode *i
+ int err = 0;
+ struct class_device *class_dev = file->private_data;
+ struct rtc_device *rtc = to_rtc_device(class_dev);
+- struct rtc_class_ops *ops = rtc->ops;
++ const struct rtc_class_ops *ops = rtc->ops;
+ struct rtc_time tm;
+ struct rtc_wkalrm alarm;
+ void __user *uarg = (void __user *) arg;
+@@ -406,7 +406,6 @@ static int rtc_dev_add_device(struct cla
+ rtc->char_dev.owner = rtc->owner;
+
+ if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
+- cdev_del(&rtc->char_dev);
+ dev_err(class_dev->dev,
+ "failed to add char device %d:%d\n",
+ MAJOR(rtc_devt), rtc->id);
+@@ -496,7 +495,7 @@ static void __exit rtc_dev_exit(void)
+ unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+ }
+
+-module_init(rtc_dev_init);
++subsys_initcall(rtc_dev_init);
+ module_exit(rtc_dev_exit);
+
+ MODULE_AUTHOR("Alessandro Zummo <a.zummo at towertech.it>");
+diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
+index e8afb93..3f0f7b8 100644
+--- a/drivers/rtc/rtc-ds1307.c
++++ b/drivers/rtc/rtc-ds1307.c
+@@ -141,9 +141,9 @@ static int ds1307_set_time(struct device
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+- "write", dt->tm_sec, dt->tm_min,
+- dt->tm_hour, dt->tm_mday,
+- dt->tm_mon, dt->tm_year, dt->tm_wday);
++ "write", t->tm_sec, t->tm_min,
++ t->tm_hour, t->tm_mday,
++ t->tm_mon, t->tm_year, t->tm_wday);
+
+ *buf++ = 0; /* first register addr */
+ buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
+@@ -178,7 +178,7 @@ static int ds1307_set_time(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops ds13xx_rtc_ops = {
++static const struct rtc_class_ops ds13xx_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+ };
+diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
+index 2090014..78552e6 100644
+--- a/drivers/rtc/rtc-ds1553.c
++++ b/drivers/rtc/rtc-ds1553.c
+@@ -18,7 +18,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
+
+-#define DRV_VERSION "0.1"
++#define DRV_VERSION "0.2"
+
+ #define RTC_REG_SIZE 0x2000
+ #define RTC_OFFSET 0x1ff0
+@@ -189,8 +189,7 @@ static int ds1553_rtc_read_alarm(struct
+ return 0;
+ }
+
+-static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
+ {
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+@@ -250,7 +249,7 @@ static int ds1553_rtc_ioctl(struct devic
+ return 0;
+ }
+
+-static struct rtc_class_ops ds1553_rtc_ops = {
++static const struct rtc_class_ops ds1553_rtc_ops = {
+ .read_time = ds1553_rtc_read_time,
+ .set_time = ds1553_rtc_set_time,
+ .read_alarm = ds1553_rtc_read_alarm,
+@@ -357,9 +356,13 @@ static int __init ds1553_rtc_probe(struc
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+- sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
++ ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
++ if (ret)
++ goto out;
+ return 0;
+ out:
++ if (pdata->rtc)
++ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ if (ioaddr)
+diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
+index 9be81fd..67e816a 100644
+--- a/drivers/rtc/rtc-ds1672.c
++++ b/drivers/rtc/rtc-ds1672.c
+@@ -55,7 +55,7 @@ static int ds1672_get_datetime(struct i2
+ }
+
+ dev_dbg(&client->dev,
+- "%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
++ "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
+ __FUNCTION__, buf[0], buf[1], buf[2], buf[3]);
+
+ time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+@@ -96,7 +96,7 @@ static int ds1672_set_datetime(struct i2
+ unsigned long secs;
+
+ dev_dbg(&client->dev,
+- "%s: secs=%d, mins=%d, hours=%d, ",
++ "%s: secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+@@ -156,7 +156,7 @@ static ssize_t show_control(struct devic
+ }
+ static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
+
+-static struct rtc_class_ops ds1672_rtc_ops = {
++static const struct rtc_class_ops ds1672_rtc_ops = {
+ .read_time = ds1672_rtc_read_time,
+ .set_time = ds1672_rtc_set_time,
+ .set_mmss = ds1672_rtc_set_mmss,
+diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
+index 8e47e5a..6273a3d 100644
+--- a/drivers/rtc/rtc-ds1742.c
++++ b/drivers/rtc/rtc-ds1742.c
+@@ -17,7 +17,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
+
+-#define DRV_VERSION "0.1"
++#define DRV_VERSION "0.2"
+
+ #define RTC_REG_SIZE 0x800
+ #define RTC_OFFSET 0x7f8
+@@ -116,7 +116,7 @@ static int ds1742_rtc_read_time(struct d
+ return 0;
+ }
+
+-static struct rtc_class_ops ds1742_rtc_ops = {
++static const struct rtc_class_ops ds1742_rtc_ops = {
+ .read_time = ds1742_rtc_read_time,
+ .set_time = ds1742_rtc_set_time,
+ };
+@@ -196,7 +196,7 @@ static int __init ds1742_rtc_probe(struc
+ writeb(sec, ioaddr + RTC_SECONDS);
+ writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ }
+- if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)
++ if (!(readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG))
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+@@ -208,9 +208,13 @@ static int __init ds1742_rtc_probe(struc
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+- sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
++ ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
++ if (ret)
++ goto out;
+ return 0;
+ out:
++ if (pdata->rtc)
++ rtc_device_unregister(pdata->rtc);
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
+index e1a1169..ef4f147 100644
+--- a/drivers/rtc/rtc-ep93xx.c
++++ b/drivers/rtc/rtc-ep93xx.c
+@@ -73,7 +73,7 @@ static int ep93xx_rtc_proc(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops ep93xx_rtc_ops = {
++static const struct rtc_class_ops ep93xx_rtc_ops = {
+ .read_time = ep93xx_rtc_read_time,
+ .set_time = ep93xx_rtc_set_time,
+ .set_mmss = ep93xx_rtc_set_mmss,
+diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
+index f324d0a..1c74364 100644
+--- a/drivers/rtc/rtc-isl1208.c
++++ b/drivers/rtc/rtc-isl1208.c
+@@ -390,7 +390,7 @@ static int isl1208_rtc_read_alarm(struct
+ return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
+ }
+
+-static struct rtc_class_ops isl1208_rtc_ops = {
++static const struct rtc_class_ops isl1208_rtc_ops = {
+ .proc = isl1208_rtc_proc,
+ .read_time = isl1208_rtc_read_time,
+ .set_time = isl1208_rtc_set_time,
+diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
+index 9812120..ba795a4 100644
+--- a/drivers/rtc/rtc-lib.c
++++ b/drivers/rtc/rtc-lib.c
+@@ -94,12 +94,12 @@ EXPORT_SYMBOL(rtc_time_to_tm);
+ int rtc_valid_tm(struct rtc_time *tm)
+ {
+ if (tm->tm_year < 70
+- || tm->tm_mon >= 12
++ || ((unsigned)tm->tm_mon) >= 12
+ || tm->tm_mday < 1
+ || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
+- || tm->tm_hour >= 24
+- || tm->tm_min >= 60
+- || tm->tm_sec >= 60)
++ || ((unsigned)tm->tm_hour) >= 24
++ || ((unsigned)tm->tm_min) >= 60
++ || ((unsigned)tm->tm_sec) >= 60)
+ return -EINVAL;
+
+ return 0;
+diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
+index 8c0d1a6..8ff4a12 100644
+--- a/drivers/rtc/rtc-m48t86.c
++++ b/drivers/rtc/rtc-m48t86.c
+@@ -138,7 +138,7 @@ static int m48t86_rtc_proc(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops m48t86_rtc_ops = {
++static const struct rtc_class_ops m48t86_rtc_ops = {
+ .read_time = m48t86_rtc_read_time,
+ .set_time = m48t86_rtc_set_time,
+ .proc = m48t86_rtc_proc,
+diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
+index 2c97395..d941707 100644
+--- a/drivers/rtc/rtc-max6902.c
++++ b/drivers/rtc/rtc-max6902.c
+@@ -1,4 +1,4 @@
+-/* drivers/char/max6902.c
++/* drivers/rtc/rtc-max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+@@ -19,7 +19,6 @@
+ * - Initial driver creation.
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/version.h>
+
+@@ -137,7 +136,7 @@ static int max6902_get_datetime(struct d
+ dt->tm_min = BCD2BIN(chip->buf[2]);
+ dt->tm_hour = BCD2BIN(chip->buf[3]);
+ dt->tm_mday = BCD2BIN(chip->buf[4]);
+- dt->tm_mon = BCD2BIN(chip->buf[5] - 1);
++ dt->tm_mon = BCD2BIN(chip->buf[5]) - 1;
+ dt->tm_wday = BCD2BIN(chip->buf[6]);
+ dt->tm_year = BCD2BIN(chip->buf[7]);
+
+@@ -207,7 +206,7 @@ static int max6902_set_time(struct devic
+ return max6902_set_datetime(dev, tm);
+ }
+
+-static struct rtc_class_ops max6902_rtc_ops = {
++static const struct rtc_class_ops max6902_rtc_ops = {
+ .read_time = max6902_read_time,
+ .set_time = max6902_set_time,
+ };
+diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
+index ba9a583..a760cf6 100644
+--- a/drivers/rtc/rtc-pcf8563.c
++++ b/drivers/rtc/rtc-pcf8563.c
+@@ -95,7 +95,7 @@ static int pcf8563_get_datetime(struct i
+ tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
+ tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+ tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
+- + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 100 : 0);
++ + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100);
+
+ dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+@@ -135,7 +135,7 @@ static int pcf8563_set_datetime(struct i
+
+ /* year and century */
+ buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
+- if (tm->tm_year / 100)
++ if (tm->tm_year < 100)
+ buf[PCF8563_REG_MO] |= PCF8563_MO_C;
+
+ buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
+@@ -227,7 +227,7 @@ static int pcf8563_rtc_set_time(struct d
+ return pcf8563_set_datetime(to_i2c_client(dev), tm);
+ }
+
+-static struct rtc_class_ops pcf8563_rtc_ops = {
++static const struct rtc_class_ops pcf8563_rtc_ops = {
+ .read_time = pcf8563_rtc_read_time,
+ .set_time = pcf8563_rtc_set_time,
+ };
+diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
+index b235a30..5875ebb 100644
+--- a/drivers/rtc/rtc-pcf8583.c
++++ b/drivers/rtc/rtc-pcf8583.c
+@@ -273,7 +273,7 @@ static int pcf8583_rtc_set_time(struct d
+ return ret;
+ }
+
+-static struct rtc_class_ops pcf8583_rtc_ops = {
++static const struct rtc_class_ops pcf8583_rtc_ops = {
+ .read_time = pcf8583_rtc_read_time,
+ .set_time = pcf8583_rtc_set_time,
+ };
+diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
+index d6d1c57..f13daa9 100644
+--- a/drivers/rtc/rtc-pl031.c
++++ b/drivers/rtc/rtc-pl031.c
+@@ -47,7 +47,7 @@ struct pl031_local {
+ void __iomem *base;
+ };
+
+-static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+ {
+ struct rtc_device *rtc = dev_id;
+
+@@ -128,7 +128,7 @@ static int pl031_set_alarm(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops pl031_ops = {
++static const struct rtc_class_ops pl031_ops = {
+ .open = pl031_open,
+ .release = pl031_release,
+ .ioctl = pl031_ioctl,
+diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
+index cef5f5a..d51d8f2 100644
+--- a/drivers/rtc/rtc-proc.c
++++ b/drivers/rtc/rtc-proc.c
+@@ -23,7 +23,7 @@ static int rtc_proc_show(struct seq_file
+ {
+ int err;
+ struct class_device *class_dev = seq->private;
+- struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++ const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+ struct rtc_wkalrm alrm;
+ struct rtc_time tm;
+
+@@ -61,7 +61,7 @@ static int rtc_proc_show(struct seq_file
+ seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
+ else
+ seq_printf(seq, "**-");
+- if ((unsigned int)alrm.time.tm_mday <= 31)
++ if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
+ seq_printf(seq, "%02d\n", alrm.time.tm_mday);
+ else
+ seq_printf(seq, "**\n");
+@@ -156,7 +156,7 @@ static void __exit rtc_proc_exit(void)
+ class_interface_unregister(&rtc_proc_interface);
+ }
+
+-module_init(rtc_proc_init);
++subsys_initcall(rtc_proc_init);
+ module_exit(rtc_proc_exit);
+
+ MODULE_AUTHOR("Alessandro Zummo <a.zummo at towertech.it>");
+diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
+index 0964d1d..f50f3fc 100644
+--- a/drivers/rtc/rtc-rs5c348.c
++++ b/drivers/rtc/rtc-rs5c348.c
+@@ -23,7 +23,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/spi/spi.h>
+
+-#define DRV_VERSION "0.1"
++#define DRV_VERSION "0.2"
+
+ #define RS5C348_REG_SECS 0
+ #define RS5C348_REG_MINS 1
+@@ -140,7 +140,7 @@ rs5c348_rtc_read_time(struct device *dev
+ return 0;
+ }
+
+-static struct rtc_class_ops rs5c348_rtc_ops = {
++static const struct rtc_class_ops rs5c348_rtc_ops = {
+ .read_time = rs5c348_rtc_read_time,
+ .set_time = rs5c348_rtc_set_time,
+ };
+@@ -175,8 +175,15 @@ static int __devinit rs5c348_probe(struc
+ goto kfree_exit;
+ if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
+ u8 buf[2];
++ struct rtc_time tm;
+ if (ret & RS5C348_BIT_VDET)
+ dev_warn(&spi->dev, "voltage-low detected.\n");
++ if (ret & RS5C348_BIT_XSTP)
++ dev_warn(&spi->dev, "oscillator-stop detected.\n");
++ rtc_time_to_tm(0, &tm); /* 1970/1/1 */
++ ret = rs5c348_rtc_set_time(&spi->dev, &tm);
++ if (ret < 0)
++ goto kfree_exit;
+ buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
+ buf[1] = 0;
+ ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
+diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
+index 7553d79..2a86632 100644
+--- a/drivers/rtc/rtc-rs5c372.c
++++ b/drivers/rtc/rtc-rs5c372.c
+@@ -91,7 +91,7 @@ static int rs5c372_set_datetime(struct i
+ unsigned char buf[8] = { RS5C372_REG_BASE };
+
+ dev_dbg(&client->dev,
+- "%s: secs=%d, mins=%d, hours=%d ",
++ "%s: secs=%d, mins=%d, hours=%d "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+@@ -126,7 +126,7 @@ static int rs5c372_get_trim(struct i2c_c
+ return -EIO;
+ }
+
+- dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim);
++ dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim);
+
+ if (osc)
+ *osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768;
+@@ -160,7 +160,7 @@ static int rs5c372_rtc_proc(struct devic
+ return 0;
+ }
+
+-static struct rtc_class_ops rs5c372_rtc_ops = {
++static const struct rtc_class_ops rs5c372_rtc_ops = {
+ .proc = rs5c372_rtc_proc,
+ .read_time = rs5c372_rtc_read_time,
+ .set_time = rs5c372_rtc_set_time,
+diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
+index 2c7de79..e301dea 100644
+--- a/drivers/rtc/rtc-s3c.c
++++ b/drivers/rtc/rtc-s3c.c
+@@ -46,7 +46,7 @@ static unsigned int tick_count;
+
+ /* IRQ Handlers */
+
+-static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
++static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
+ {
+ struct rtc_device *rdev = id;
+
+@@ -54,7 +54,7 @@ static irqreturn_t s3c_rtc_alarmirq(int
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t s3c_rtc_tickirq(int irq, void *id, struct pt_regs *r)
++static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
+ {
+ struct rtc_device *rdev = id;
+
+@@ -386,7 +386,7 @@ static void s3c_rtc_release(struct devic
+ free_irq(s3c_rtc_tickno, rtc_dev);
+ }
+
+-static struct rtc_class_ops s3c_rtcops = {
++static const struct rtc_class_ops s3c_rtcops = {
+ .open = s3c_rtc_open,
+ .release = s3c_rtc_release,
+ .ioctl = s3c_rtc_ioctl,
+diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
+index ee4b61e..bd4d7d1 100644
+--- a/drivers/rtc/rtc-sa1100.c
++++ b/drivers/rtc/rtc-sa1100.c
+@@ -68,8 +68,7 @@ static int rtc_update_alarm(struct rtc_t
+ return ret;
+ }
+
+-static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
+ {
+ struct platform_device *pdev = to_platform_device(dev_id);
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+@@ -106,8 +105,7 @@ static irqreturn_t sa1100_rtc_interrupt(
+
+ static int rtc_timer1_count;
+
+-static irqreturn_t timer1_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t timer1_interrupt(int irq, void *dev_id)
+ {
+ struct platform_device *pdev = to_platform_device(dev_id);
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+@@ -303,7 +301,7 @@ static int sa1100_rtc_proc(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops sa1100_rtc_ops = {
++static const struct rtc_class_ops sa1100_rtc_ops = {
+ .open = sa1100_rtc_open,
+ .read_callback = sa1100_rtc_read_callback,
+ .release = sa1100_rtc_release,
+diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
+new file mode 100644
+index 0000000..143302a
+--- /dev/null
++++ b/drivers/rtc/rtc-sh.c
+@@ -0,0 +1,467 @@
++/*
++ * SuperH On-Chip RTC Support
++ *
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * Based on the old arch/sh/kernel/cpu/rtc.c by:
++ *
++ * Copyright (C) 2000 Philipp Rumpf <prumpf at tux.org>
++ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/bcd.h>
++#include <linux/rtc.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/seq_file.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_CPU_SH3
++#define rtc_reg_size sizeof(u16)
++#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
++#elif defined(CONFIG_CPU_SH4)
++#define rtc_reg_size sizeof(u32)
++#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
++#endif
++
++#define RTC_REG(r) ((r) * rtc_reg_size)
++
++#define R64CNT RTC_REG(0)
++#define RSECCNT RTC_REG(1)
++#define RMINCNT RTC_REG(2)
++#define RHRCNT RTC_REG(3)
++#define RWKCNT RTC_REG(4)
++#define RDAYCNT RTC_REG(5)
++#define RMONCNT RTC_REG(6)
++#define RYRCNT RTC_REG(7)
++#define RSECAR RTC_REG(8)
++#define RMINAR RTC_REG(9)
++#define RHRAR RTC_REG(10)
++#define RWKAR RTC_REG(11)
++#define RDAYAR RTC_REG(12)
++#define RMONAR RTC_REG(13)
++#define RCR1 RTC_REG(14)
++#define RCR2 RTC_REG(15)
++
++/* RCR1 Bits */
++#define RCR1_CF 0x80 /* Carry Flag */
++#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
++#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
++#define RCR1_AF 0x01 /* Alarm Flag */
++
++/* RCR2 Bits */
++#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
++#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
++#define RCR2_RTCEN 0x08 /* ENable RTC */
++#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
++#define RCR2_RESET 0x02 /* Reset bit */
++#define RCR2_START 0x01 /* Start bit */
++
++struct sh_rtc {
++ void __iomem *regbase;
++ unsigned long regsize;
++ struct resource *res;
++ unsigned int alarm_irq, periodic_irq, carry_irq;
++ struct rtc_device *rtc_dev;
++ spinlock_t lock;
++};
++
++static irqreturn_t sh_rtc_interrupt(int irq, void *id)
++{
++ struct platform_device *pdev = id;
++ struct sh_rtc *rtc = platform_get_drvdata(pdev);
++ unsigned int tmp, events = 0;
++
++ spin_lock(&rtc->lock);
++
++ tmp = readb(rtc->regbase + RCR1);
++
++ if (tmp & RCR1_AF)
++ events |= RTC_AF | RTC_IRQF;
++
++ tmp &= ~(RCR1_CF | RCR1_AF);
++
++ writeb(tmp, rtc->regbase + RCR1);
++
++ rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
++
++ spin_unlock(&rtc->lock);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t sh_rtc_periodic(int irq, void *id)
++{
++ struct sh_rtc *rtc = dev_get_drvdata(id);
++
++ spin_lock(&rtc->lock);
++
++ rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF);
++
++ spin_unlock(&rtc->lock);
++
++ return IRQ_HANDLED;
++}
++
++static inline void sh_rtc_setpie(struct device *dev, unsigned int enable)
++{
++ struct sh_rtc *rtc = dev_get_drvdata(dev);
++ unsigned int tmp;
++
++ spin_lock_irq(&rtc->lock);
++
++ tmp = readb(rtc->regbase + RCR2);
++
++ if (enable) {
++ tmp &= ~RCR2_PESMASK;
++ tmp |= RCR2_PEF | (2 << 4);
++ } else
++ tmp &= ~(RCR2_PESMASK | RCR2_PEF);
++
++ writeb(tmp, rtc->regbase + RCR2);
++
++ spin_unlock_irq(&rtc->lock);
++}
++
++static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
++{
++ struct sh_rtc *rtc = dev_get_drvdata(dev);
++ unsigned int tmp;
++
++ spin_lock_irq(&rtc->lock);
++
++ tmp = readb(rtc->regbase + RCR1);
++
++ if (enable)
++ tmp |= RCR1_AIE;
++ else
++ tmp &= ~RCR1_AIE;
++
++ writeb(tmp, rtc->regbase + RCR1);
++
++ spin_unlock_irq(&rtc->lock);
++}
++
++static int sh_rtc_open(struct device *dev)
++{
++ struct sh_rtc *rtc = dev_get_drvdata(dev);
++ unsigned int tmp;
++ int ret;
++
++ tmp = readb(rtc->regbase + RCR1);
++ tmp &= ~RCR1_CF;
++ tmp |= RCR1_CIE;
++ writeb(tmp, rtc->regbase + RCR1);
++
++ ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED,
++ "sh-rtc period", dev);
++ if (unlikely(ret)) {
++ dev_err(dev, "request period IRQ failed with %d, IRQ %d\n",
++ ret, rtc->periodic_irq);
++ return ret;
++ }
++
++ ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED,
++ "sh-rtc carry", dev);
++ if (unlikely(ret)) {
++ dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n",
++ ret, rtc->carry_irq);
++ free_irq(rtc->periodic_irq, dev);
++ goto err_bad_carry;
++ }
++
++ ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, IRQF_DISABLED,
++ "sh-rtc alarm", dev);
++ if (unlikely(ret)) {
++ dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
++ ret, rtc->alarm_irq);
++ goto err_bad_alarm;
++ }
++
++ return 0;
++
++err_bad_alarm:
++ free_irq(rtc->carry_irq, dev);
++err_bad_carry:
++ free_irq(rtc->periodic_irq, dev);
++
++ return ret;
++}
++
++static void sh_rtc_release(struct device *dev)
++{
++ struct sh_rtc *rtc = dev_get_drvdata(dev);
++
++ sh_rtc_setpie(dev, 0);
++
++ free_irq(rtc->periodic_irq, dev);
++ free_irq(rtc->carry_irq, dev);
++ free_irq(rtc->alarm_irq, dev);
++}
++
++static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
++{
++ struct sh_rtc *rtc = dev_get_drvdata(dev);
++ unsigned int tmp;
++
++ tmp = readb(rtc->regbase + RCR1);
++ seq_printf(seq, "alarm_IRQ\t: %s\n",
++ (tmp & RCR1_AIE) ? "yes" : "no");
++ seq_printf(seq, "carry_IRQ\t: %s\n",
++ (tmp & RCR1_CIE) ? "yes" : "no");
++
++ tmp = readb(rtc->regbase + RCR2);
++ seq_printf(seq, "periodic_IRQ\t: %s\n",
++ (tmp & RCR2_PEF) ? "yes" : "no");
++
++ return 0;
++}
++
++static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
++{
++ unsigned int ret = -ENOIOCTLCMD;
++
++ switch (cmd) {
++ case RTC_PIE_OFF:
++ case RTC_PIE_ON:
++ sh_rtc_setpie(dev, cmd == RTC_PIE_ON);
++ ret = 0;
++ break;
++ case RTC_AIE_OFF:
++ case RTC_AIE_ON:
++ sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct sh_rtc *rtc = platform_get_drvdata(pdev);
++ unsigned int sec128, sec2, yr, yr100, cf_bit;
++
++ do {
++ unsigned int tmp;
++
++ spin_lock_irq(&rtc->lock);
++
++ tmp = readb(rtc->regbase + RCR1);
++ tmp &= ~RCR1_CF; /* Clear CF-bit */
++ tmp |= RCR1_CIE;
++ writeb(tmp, rtc->regbase + RCR1);
++
++ sec128 = readb(rtc->regbase + R64CNT);
++
++ tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
++ tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
++ tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
++ tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
++ tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
++ tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT));
++
++#if defined(CONFIG_CPU_SH4)
++ yr = readw(rtc->regbase + RYRCNT);
++ yr100 = BCD2BIN(yr >> 8);
++ yr &= 0xff;
++#else
++ yr = readb(rtc->regbase + RYRCNT);
++ yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
++#endif
++
++ tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
++
++ sec2 = readb(rtc->regbase + R64CNT);
++ cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF;
++
++ spin_unlock_irq(&rtc->lock);
++ } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
++
++#if RTC_BIT_INVERTED != 0
++ if ((sec128 & RTC_BIT_INVERTED))
++ tm->tm_sec--;
++#endif
++
++ dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
++ "mday=%d, mon=%d, year=%d, wday=%d\n",
++ __FUNCTION__,
++ tm->tm_sec, tm->tm_min, tm->tm_hour,
++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++ if (rtc_valid_tm(tm) < 0)
++ dev_err(dev, "invalid date\n");
++
++ return 0;
++}
++
++static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct sh_rtc *rtc = platform_get_drvdata(pdev);
++ unsigned int tmp;
++ int year;
++
++ spin_lock_irq(&rtc->lock);
++
++ /* Reset pre-scaler & stop RTC */
++ tmp = readb(rtc->regbase + RCR2);
++ tmp |= RCR2_RESET;
++ writeb(tmp, rtc->regbase + RCR2);
++
++ writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
++ writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
++ writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
++ writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
++ writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
++ writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT);
++
++#ifdef CONFIG_CPU_SH3
++ year = tm->tm_year % 100;
++ writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
++#else
++ year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
++ BIN2BCD(tm->tm_year % 100);
++ writew(year, rtc->regbase + RYRCNT);
++#endif
++
++ /* Start RTC */
++ tmp = readb(rtc->regbase + RCR2);
++ tmp &= ~RCR2_RESET;
++ tmp |= RCR2_RTCEN | RCR2_START;
++ writeb(tmp, rtc->regbase + RCR2);
++
++ spin_unlock_irq(&rtc->lock);
++
++ return 0;
++}
++
++static struct rtc_class_ops sh_rtc_ops = {
++ .open = sh_rtc_open,
++ .release = sh_rtc_release,
++ .ioctl = sh_rtc_ioctl,
++ .read_time = sh_rtc_read_time,
++ .set_time = sh_rtc_set_time,
++ .proc = sh_rtc_proc,
++};
++
++static int __devinit sh_rtc_probe(struct platform_device *pdev)
++{
++ struct sh_rtc *rtc;
++ struct resource *res;
++ int ret = -ENOENT;
++
++ rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
++ if (unlikely(!rtc))
++ return -ENOMEM;
++
++ spin_lock_init(&rtc->lock);
++
++ rtc->periodic_irq = platform_get_irq(pdev, 0);
++ if (unlikely(rtc->periodic_irq < 0)) {
++ dev_err(&pdev->dev, "No IRQ for period\n");
++ goto err_badres;
++ }
++
++ rtc->carry_irq = platform_get_irq(pdev, 1);
++ if (unlikely(rtc->carry_irq < 0)) {
++ dev_err(&pdev->dev, "No IRQ for carry\n");
++ goto err_badres;
++ }
++
++ rtc->alarm_irq = platform_get_irq(pdev, 2);
++ if (unlikely(rtc->alarm_irq < 0)) {
++ dev_err(&pdev->dev, "No IRQ for alarm\n");
++ goto err_badres;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
++ if (unlikely(res == NULL)) {
++ dev_err(&pdev->dev, "No IO resource\n");
++ goto err_badres;
++ }
++
++ rtc->regsize = res->end - res->start + 1;
++
++ rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name);
++ if (unlikely(!rtc->res)) {
++ ret = -EBUSY;
++ goto err_badres;
++ }
++
++ rtc->regbase = (void __iomem *)rtc->res->start;
++ if (unlikely(!rtc->regbase)) {
++ ret = -EINVAL;
++ goto err_badmap;
++ }
++
++ rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
++ &sh_rtc_ops, THIS_MODULE);
++ if (IS_ERR(rtc)) {
++ ret = PTR_ERR(rtc->rtc_dev);
++ goto err_badmap;
++ }
++
++ platform_set_drvdata(pdev, rtc);
++
++ return 0;
++
++err_badmap:
++ release_resource(rtc->res);
++err_badres:
++ kfree(rtc);
++
++ return ret;
++}
++
++static int __devexit sh_rtc_remove(struct platform_device *pdev)
++{
++ struct sh_rtc *rtc = platform_get_drvdata(pdev);
++
++ if (likely(rtc->rtc_dev))
++ rtc_device_unregister(rtc->rtc_dev);
++
++ sh_rtc_setpie(&pdev->dev, 0);
++ sh_rtc_setaie(&pdev->dev, 0);
++
++ release_resource(rtc->res);
++
++ platform_set_drvdata(pdev, NULL);
++
++ kfree(rtc);
++
++ return 0;
++}
++static struct platform_driver sh_rtc_platform_driver = {
++ .driver = {
++ .name = "sh-rtc",
++ .owner = THIS_MODULE,
++ },
++ .probe = sh_rtc_probe,
++ .remove = __devexit_p(sh_rtc_remove),
++};
++
++static int __init sh_rtc_init(void)
++{
++ return platform_driver_register(&sh_rtc_platform_driver);
++}
++
++static void __exit sh_rtc_exit(void)
++{
++ platform_driver_unregister(&sh_rtc_platform_driver);
++}
++
++module_init(sh_rtc_init);
++module_exit(sh_rtc_exit);
++
++MODULE_DESCRIPTION("SuperH on-chip RTC driver");
++MODULE_AUTHOR("Paul Mundt <lethal at linux-sh.org>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
+index 7c1f3d2..625637b 100644
+--- a/drivers/rtc/rtc-sysfs.c
++++ b/drivers/rtc/rtc-sysfs.c
+@@ -116,7 +116,7 @@ static void __exit rtc_sysfs_exit(void)
+ class_interface_unregister(&rtc_sysfs_interface);
+ }
+
+-module_init(rtc_sysfs_init);
++subsys_initcall(rtc_sysfs_init);
+ module_exit(rtc_sysfs_exit);
+
+ MODULE_AUTHOR("Alessandro Zummo <a.zummo at towertech.it>");
+diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
+index e1fa5fe..bc4bd24 100644
+--- a/drivers/rtc/rtc-test.c
++++ b/drivers/rtc/rtc-test.c
+@@ -75,7 +75,7 @@ static int test_rtc_ioctl(struct device
+ }
+ }
+
+-static struct rtc_class_ops test_rtc_ops = {
++static const struct rtc_class_ops test_rtc_ops = {
+ .proc = test_rtc_proc,
+ .read_time = test_rtc_read_time,
+ .set_time = test_rtc_set_time,
+diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
+index a40f400..3b58d3d 100644
+--- a/drivers/rtc/rtc-v3020.c
++++ b/drivers/rtc/rtc-v3020.c
+@@ -149,7 +149,7 @@ static int v3020_set_time(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops v3020_rtc_ops = {
++static const struct rtc_class_ops v3020_rtc_ops = {
+ .read_time = v3020_read_time,
+ .set_time = v3020_set_time,
+ };
+@@ -169,9 +169,6 @@ static int rtc_probe(struct platform_dev
+ if (pdev->resource[0].flags != IORESOURCE_MEM)
+ return -EBUSY;
+
+- if (pdev == NULL)
+- return -EBUSY;
+-
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+@@ -198,9 +195,9 @@ static int rtc_probe(struct platform_dev
+ * are all disabled */
+ v3020_set_reg(chip, V3020_STATUS_0, 0x0);
+
+- dev_info(&pdev->dev, "Chip available at physical address 0x%p,"
++ dev_info(&pdev->dev, "Chip available at physical address 0x%llx,"
+ "data connected to D%d\n",
+- (void*)pdev->resource[0].start,
++ (unsigned long long)pdev->resource[0].start,
+ chip->leftshift);
+
+ platform_set_drvdata(pdev, chip);
+diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
+index 596764f..e40322b 100644
+--- a/drivers/rtc/rtc-vr41xx.c
++++ b/drivers/rtc/rtc-vr41xx.c
+@@ -268,7 +268,7 @@ static int vr41xx_rtc_ioctl(struct devic
+ return 0;
+ }
+
+-static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
+ {
+ struct platform_device *pdev = (struct platform_device *)dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+@@ -280,7 +280,7 @@ static irqreturn_t elapsedtime_interrupt
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
+ {
+ struct platform_device *pdev = (struct platform_device *)dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+@@ -296,7 +296,7 @@ static irqreturn_t rtclong1_interrupt(in
+ return IRQ_HANDLED;
+ }
+
+-static struct rtc_class_ops vr41xx_rtc_ops = {
++static const struct rtc_class_ops vr41xx_rtc_ops = {
+ .release = vr41xx_rtc_release,
+ .ioctl = vr41xx_rtc_ioctl,
+ .read_time = vr41xx_rtc_read_time,
+diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
+index 788b6d1..522c697 100644
+--- a/drivers/rtc/rtc-x1205.c
++++ b/drivers/rtc/rtc-x1205.c
+@@ -460,7 +460,7 @@ static int x1205_rtc_proc(struct device
+ return 0;
+ }
+
+-static struct rtc_class_ops x1205_rtc_ops = {
++static const struct rtc_class_ops x1205_rtc_ops = {
+ .proc = x1205_rtc_proc,
+ .read_time = x1205_rtc_read_time,
+ .set_time = x1205_rtc_set_time,
+diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
+index 4d36208..ae89b9b 100644
+--- a/drivers/s390/Kconfig
++++ b/drivers/s390/Kconfig
+@@ -213,17 +213,35 @@ config MONREADER
+ help
+ Character device driver for reading z/VM monitor service records
+
++config MONWRITER
++ tristate "API for writing z/VM monitor service records"
++ default "m"
++ help
++ Character device driver for writing z/VM monitor service records
++
+ endmenu
+
+ menu "Cryptographic devices"
+
+-config Z90CRYPT
++config ZCRYPT
+ tristate "Support for PCI-attached cryptographic adapters"
+- default "m"
+- help
++ select ZCRYPT_MONOLITHIC if ZCRYPT="y"
++ default "m"
++ help
+ Select this option if you want to use a PCI-attached cryptographic
+- adapter like the PCI Cryptographic Accelerator (PCICA) or the PCI
+- Cryptographic Coprocessor (PCICC). This option is also available
+- as a module called z90crypt.ko.
++ adapter like:
++ + PCI Cryptographic Accelerator (PCICA)
++ + PCI Cryptographic Coprocessor (PCICC)
++ + PCI-X Cryptographic Coprocessor (PCIXCC)
++ + Crypto Express2 Coprocessor (CEX2C)
++ + Crypto Express2 Accelerator (CEX2A)
++
++config ZCRYPT_MONOLITHIC
++ bool "Monolithic zcrypt module"
++ depends on ZCRYPT="m"
++ help
++ Select this option if you want to have a single module z90crypt.ko
++ that contains all parts of the crypto device driver (ap bus,
++ request router and all the card drivers).
+
+ endmenu
+diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
+index 929d6ff..b250c53 100644
+--- a/drivers/s390/block/Kconfig
++++ b/drivers/s390/block/Kconfig
+@@ -1,4 +1,4 @@
+-if S390
++if S390 && BLOCK
+
+ comment "S/390 block device drivers"
+ depends on S390
+diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
+index 25c1ef6..79ffef6 100644
+--- a/drivers/s390/block/dasd.c
++++ b/drivers/s390/block/dasd.c
+@@ -184,7 +184,7 @@ dasd_state_known_to_basic(struct dasd_de
+ 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);
++ debug_set_level(device->debug_area, DBF_WARNING);
+ DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
+
+ device->state = DASD_STATE_BASIC;
+@@ -203,6 +203,7 @@ dasd_state_basic_to_known(struct dasd_de
+ rc = dasd_flush_ccw_queue(device, 1);
+ if (rc)
+ return rc;
++ dasd_clear_timer(device);
+
+ DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
+ if (device->debug_area != NULL) {
+@@ -893,7 +894,7 @@ dasd_handle_killed_request(struct ccw_de
+
+ device = (struct dasd_device *) cqr->device;
+ if (device == NULL ||
+- device != dasd_device_from_cdev(cdev) ||
++ device != dasd_device_from_cdev_locked(cdev) ||
+ strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+ MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
+ cdev->dev.bus_id);
+@@ -970,7 +971,7 @@ dasd_int_handler(struct ccw_device *cdev
+ /* first of all check for state change pending interrupt */
+ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+ if ((irb->scsw.dstat & mask) == mask) {
+- device = dasd_device_from_cdev(cdev);
++ device = dasd_device_from_cdev_locked(cdev);
+ if (!IS_ERR(device)) {
+ dasd_handle_state_change_pending(device);
+ dasd_put_device(device);
+@@ -2169,7 +2170,7 @@ dasd_init(void)
+ goto failed;
+ }
+ debug_register_view(dasd_debug_area, &debug_sprintf_view);
+- debug_set_level(dasd_debug_area, DBF_EMERG);
++ debug_set_level(dasd_debug_area, DBF_WARNING);
+
+ DBF_EVENT(DBF_EMERG, "%s", "debug area created");
+
+diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
+index 9af02c7..91cf971 100644
+--- a/drivers/s390/block/dasd_devmap.c
++++ b/drivers/s390/block/dasd_devmap.c
+@@ -258,8 +258,12 @@ dasd_parse_keyword( char *parsestring )
+ return residual_str;
+ }
+ if (strncmp("nopav", parsestring, length) == 0) {
+- dasd_nopav = 1;
+- MESSAGE(KERN_INFO, "%s", "disable PAV mode");
++ if (MACHINE_IS_VM)
++ MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM");
++ else {
++ dasd_nopav = 1;
++ MESSAGE(KERN_INFO, "%s", "disable PAV mode");
++ }
+ return residual_str;
+ }
+ if (strncmp("fixedbuffers", parsestring, length) == 0) {
+@@ -523,17 +527,17 @@ dasd_create_device(struct ccw_device *cd
+ {
+ struct dasd_devmap *devmap;
+ struct dasd_device *device;
++ unsigned long flags;
+ int rc;
+
+ devmap = dasd_devmap_from_cdev(cdev);
+ if (IS_ERR(devmap))
+ return (void *) devmap;
+- cdev->dev.driver_data = devmap;
+
+ device = dasd_alloc_device();
+ if (IS_ERR(device))
+ return device;
+- atomic_set(&device->ref_count, 2);
++ atomic_set(&device->ref_count, 3);
+
+ spin_lock(&dasd_devmap_lock);
+ if (!devmap->device) {
+@@ -552,6 +556,11 @@ dasd_create_device(struct ccw_device *cd
+ dasd_free_device(device);
+ return ERR_PTR(rc);
+ }
++
++ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
++ cdev->dev.driver_data = device;
++ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
++
+ return device;
+ }
+
+@@ -569,6 +578,7 @@ dasd_delete_device(struct dasd_device *d
+ {
+ struct ccw_device *cdev;
+ struct dasd_devmap *devmap;
++ unsigned long flags;
+
+ /* First remove device pointer from devmap. */
+ devmap = dasd_find_busid(device->cdev->dev.bus_id);
+@@ -582,9 +592,16 @@ dasd_delete_device(struct dasd_device *d
+ devmap->device = NULL;
+ spin_unlock(&dasd_devmap_lock);
+
+- /* Drop ref_count by 2, one for the devmap reference and
+- * one for the passed reference. */
+- atomic_sub(2, &device->ref_count);
++ /* Disconnect dasd_device structure from ccw_device structure. */
++ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
++ device->cdev->dev.driver_data = NULL;
++ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++
++ /*
++ * Drop ref_count by 3, one for the devmap reference, one for
++ * the cdev reference and one for the passed reference.
++ */
++ atomic_sub(3, &device->ref_count);
+
+ /* Wait for reference counter to drop to zero. */
+ wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
+@@ -593,9 +610,6 @@ dasd_delete_device(struct dasd_device *d
+ cdev = device->cdev;
+ device->cdev = NULL;
+
+- /* Disconnect dasd_devmap structure from ccw_device structure. */
+- cdev->dev.driver_data = NULL;
+-
+ /* Put ccw_device structure. */
+ put_device(&cdev->dev);
+
+@@ -615,21 +629,32 @@ dasd_put_device_wake(struct dasd_device
+
+ /*
+ * Return dasd_device structure associated with cdev.
++ * This function needs to be called with the ccw device
++ * lock held. It can be used from interrupt context.
++ */
++struct dasd_device *
++dasd_device_from_cdev_locked(struct ccw_device *cdev)
++{
++ struct dasd_device *device = cdev->dev.driver_data;
++
++ if (!device)
++ return ERR_PTR(-ENODEV);
++ dasd_get_device(device);
++ return device;
++}
++
++/*
++ * Return dasd_device structure associated with cdev.
+ */
+ struct dasd_device *
+ dasd_device_from_cdev(struct ccw_device *cdev)
+ {
+- struct dasd_devmap *devmap;
+ struct dasd_device *device;
++ unsigned long flags;
+
+- device = ERR_PTR(-ENODEV);
+- spin_lock(&dasd_devmap_lock);
+- devmap = cdev->dev.driver_data;
+- if (devmap && devmap->device) {
+- device = devmap->device;
+- dasd_get_device(device);
+- }
+- spin_unlock(&dasd_devmap_lock);
++ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
++ device = dasd_device_from_cdev_locked(cdev);
++ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return device;
+ }
+
+@@ -730,16 +755,17 @@ static ssize_t
+ dasd_discipline_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+ {
+- struct dasd_devmap *devmap;
+- char *dname;
++ struct dasd_device *device;
++ ssize_t len;
+
+- spin_lock(&dasd_devmap_lock);
+- dname = "none";
+- devmap = dev->driver_data;
+- if (devmap && devmap->device && devmap->device->discipline)
+- dname = devmap->device->discipline->name;
+- spin_unlock(&dasd_devmap_lock);
+- return snprintf(buf, PAGE_SIZE, "%s\n", dname);
++ device = dasd_device_from_cdev(to_ccwdev(dev));
++ if (!IS_ERR(device) && device->discipline) {
++ len = snprintf(buf, PAGE_SIZE, "%s\n",
++ device->discipline->name);
++ dasd_put_device(device);
++ } else
++ len = snprintf(buf, PAGE_SIZE, "none\n");
++ return len;
+ }
+
+ static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
+diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
+index 23fa0b2..53db58a 100644
+--- a/drivers/s390/block/dasd_diag.c
++++ b/drivers/s390/block/dasd_diag.c
+@@ -63,44 +63,26 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc
+ * and function code cmd.
+ * In case of an exception return 3. Otherwise return result of bitwise OR of
+ * resulting condition code and DIAG return code. */
+-static __inline__ int
+-dia250(void *iob, int cmd)
++static inline int dia250(void *iob, int cmd)
+ {
++ register unsigned long reg0 asm ("0") = (unsigned long) iob;
+ typedef union {
+ struct dasd_diag_init_io init_io;
+ struct dasd_diag_rw_io rw_io;
+ } addr_type;
+ int rc;
+
+- __asm__ __volatile__(
+-#ifdef CONFIG_64BIT
+- " lghi %0,3\n"
+- " lgr 0,%3\n"
+- " diag 0,%2,0x250\n"
+- "0: ipm %0\n"
+- " srl %0,28\n"
+- " or %0,1\n"
+- "1:\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous\n"
+-#else
+- " lhi %0,3\n"
+- " lr 0,%3\n"
++ rc = 3;
++ asm volatile(
+ " diag 0,%2,0x250\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ " or %0,1\n"
+ "1:\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous\n"
+-#endif
+- : "=&d" (rc), "=m" (*(addr_type *) iob)
+- : "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
+- : "0", "1", "cc");
++ EX_TABLE(0b,1b)
++ : "+d" (rc), "=m" (*(addr_type *) iob)
++ : "d" (cmd), "d" (reg0), "m" (*(addr_type *) iob)
++ : "1", "cc");
+ return rc;
+ }
+
+@@ -236,7 +218,7 @@ dasd_diag_term_IO(struct dasd_ccw_req *
+
+ /* Handle external interruption. */
+ static void
+-dasd_ext_handler(struct pt_regs *regs, __u16 code)
++dasd_ext_handler(__u16 code)
+ {
+ struct dasd_ccw_req *cqr, *next;
+ struct dasd_device *device;
+@@ -547,7 +529,7 @@ dasd_diag_build_cp(struct dasd_device *
+ }
+ cqr->retries = DIAG_MAX_RETRIES;
+ cqr->buildclk = get_clock();
+- if (req->flags & REQ_FAILFAST)
++ if (req->cmd_flags & REQ_FAILFAST)
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ cqr->device = device;
+ cqr->expires = DIAG_TIMEOUT;
+diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
+index b7a7fac..5ecea3e 100644
+--- a/drivers/s390/block/dasd_eckd.c
++++ b/drivers/s390/block/dasd_eckd.c
+@@ -1266,7 +1266,7 @@ dasd_eckd_build_cp(struct dasd_device *
+ recid++;
+ }
+ }
+- if (req->flags & REQ_FAILFAST)
++ if (req->cmd_flags & REQ_FAILFAST)
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ cqr->device = device;
+ cqr->expires = 5 * 60 * HZ; /* 5 minutes */
+diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
+index da65f1b..e0bf30e 100644
+--- a/drivers/s390/block/dasd_eer.c
++++ b/drivers/s390/block/dasd_eer.c
+@@ -678,7 +678,7 @@ int __init dasd_eer_init(void)
+ return 0;
+ }
+
+-void __exit dasd_eer_exit(void)
++void dasd_eer_exit(void)
+ {
+ WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+ }
+diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
+index e85015b..80926c5 100644
+--- a/drivers/s390/block/dasd_fba.c
++++ b/drivers/s390/block/dasd_fba.c
+@@ -344,7 +344,7 @@ dasd_fba_build_cp(struct dasd_device * d
+ recid++;
+ }
+ }
+- if (req->flags & REQ_FAILFAST)
++ if (req->cmd_flags & REQ_FAILFAST)
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ cqr->device = device;
+ cqr->expires = 5 * 60 * HZ; /* 5 minutes */
+diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
+index 3ccf06d..9f52004 100644
+--- a/drivers/s390/block/dasd_int.h
++++ b/drivers/s390/block/dasd_int.h
+@@ -534,6 +534,7 @@ int dasd_add_sysfs_files(struct ccw_devi
+ void dasd_remove_sysfs_files(struct ccw_device *);
+
+ struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
++struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
+ struct dasd_device *dasd_device_from_devindex(int);
+
+ int dasd_parse(void);
+diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
+index ca7d51f..a04d912 100644
+--- a/drivers/s390/block/xpram.c
++++ b/drivers/s390/block/xpram.c
+@@ -89,28 +89,15 @@ MODULE_LICENSE("GPL");
+ */
+ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
+ {
+- int cc;
++ int cc = 2; /* return unused cc 2 if pgin traps */
+
+- __asm__ __volatile__ (
+- " lhi %0,2\n" /* return unused cc 2 if pgin traps */
+- " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */
+- "0: ipm %0\n"
+- " srl %0,28\n"
++ asm volatile(
++ " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */
++ "0: ipm %0\n"
++ " srl %0,28\n"
+ "1:\n"
+-#ifndef CONFIG_64BIT
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous"
+-#else
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous"
+-#endif
+- : "=&d" (cc)
+- : "a" (__pa(page_addr)), "a" (xpage_index)
+- : "cc" );
++ EX_TABLE(0b,1b)
++ : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
+ if (cc == 3)
+ return -ENXIO;
+ if (cc == 2) {
+@@ -137,28 +124,15 @@ static int xpram_page_in (unsigned long
+ */
+ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
+ {
+- int cc;
++ int cc = 2; /* return unused cc 2 if pgin traps */
+
+- __asm__ __volatile__ (
+- " lhi %0,2\n" /* return unused cc 2 if pgout traps */
+- " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */
+- "0: ipm %0\n"
+- " srl %0,28\n"
++ asm volatile(
++ " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */
++ "0: ipm %0\n"
++ " srl %0,28\n"
+ "1:\n"
+-#ifndef CONFIG_64BIT
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous"
+-#else
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous"
+-#endif
+- : "=&d" (cc)
+- : "a" (__pa(page_addr)), "a" (xpage_index)
+- : "cc" );
++ EX_TABLE(0b,1b)
++ : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
+ if (cc == 3)
+ return -ENXIO;
+ if (cc == 2) {
+@@ -453,7 +427,7 @@ static int __init xpram_init(void)
+ PRINT_WARN("No expanded memory available\n");
+ return -ENODEV;
+ }
+- xpram_pages = xpram_highest_page_index();
++ xpram_pages = xpram_highest_page_index() + 1;
+ PRINT_INFO(" %u pages expanded memory found (%lu KB).\n",
+ xpram_pages, (unsigned long) xpram_pages*4);
+ rc = xpram_setup_sizes(xpram_pages);
+diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
+index 0c0162f..c3e97b4 100644
+--- a/drivers/s390/char/Makefile
++++ b/drivers/s390/char/Makefile
+@@ -28,3 +28,4 @@ obj-$(CONFIG_S390_TAPE) += tape.o tape_c
+ obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
+ obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
+ obj-$(CONFIG_MONREADER) += monreader.o
++obj-$(CONFIG_MONWRITER) += monwriter.o
+diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
+index 2fa566f..d7de175 100644
+--- a/drivers/s390/char/con3215.c
++++ b/drivers/s390/char/con3215.c
+@@ -1103,7 +1103,7 @@ tty3215_start(struct tty_struct *tty)
+ }
+ }
+
+-static struct tty_operations tty3215_ops = {
++static const struct tty_operations tty3215_ops = {
+ .open = tty3215_open,
+ .close = tty3215_close,
+ .write = tty3215_write,
+diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c
+index d83eb63..49e9628 100644
+--- a/drivers/s390/char/ctrlchar.c
++++ b/drivers/s390/char/ctrlchar.c
+@@ -20,7 +20,7 @@ static int ctrlchar_sysrq_key;
+ static void
+ ctrlchar_handle_sysrq(void *tty)
+ {
+- handle_sysrq(ctrlchar_sysrq_key, NULL, (struct tty_struct *) tty);
++ handle_sysrq(ctrlchar_sysrq_key, (struct tty_struct *) tty);
+ }
+
+ static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
+diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
+index ef004d0..78f8bda 100644
+--- a/drivers/s390/char/fs3270.c
++++ b/drivers/s390/char/fs3270.c
+@@ -17,7 +17,6 @@
+
+ #include <asm/ccwdev.h>
+ #include <asm/cio.h>
+-#include <asm/cpcmd.h>
+ #include <asm/ebcdic.h>
+ #include <asm/idals.h>
+
+@@ -28,7 +27,7 @@ struct raw3270_fn fs3270_fn;
+
+ struct fs3270 {
+ struct raw3270_view view;
+- pid_t fs_pid; /* Pid of controlling program. */
++ struct pid *fs_pid; /* Pid of controlling program. */
+ int read_command; /* ccw command to use for reads. */
+ int write_command; /* ccw command to use for writes. */
+ int attention; /* Got attention. */
+@@ -103,7 +102,7 @@ fs3270_restore_callback(struct raw3270_r
+ fp = (struct fs3270 *) rq->view;
+ if (rq->rc != 0 || rq->rescnt != 0) {
+ if (fp->fs_pid)
+- kill_proc(fp->fs_pid, SIGHUP, 1);
++ kill_pid(fp->fs_pid, SIGHUP, 1);
+ }
+ fp->rdbuf_size = 0;
+ raw3270_request_reset(rq);
+@@ -174,7 +173,7 @@ fs3270_save_callback(struct raw3270_requ
+ */
+ if (rq->rc != 0 || rq->rescnt == 0) {
+ if (fp->fs_pid)
+- kill_proc(fp->fs_pid, SIGHUP, 1);
++ kill_pid(fp->fs_pid, SIGHUP, 1);
+ fp->rdbuf_size = 0;
+ } else
+ fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
+@@ -443,7 +442,7 @@ fs3270_open(struct inode *inode, struct
+ return PTR_ERR(fp);
+
+ init_waitqueue_head(&fp->wait);
+- fp->fs_pid = current->pid;
++ fp->fs_pid = get_pid(task_pid(current));
+ rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
+ if (rc) {
+ fs3270_free_view(&fp->view);
+@@ -481,7 +480,8 @@ fs3270_close(struct inode *inode, struct
+ fp = filp->private_data;
+ filp->private_data = NULL;
+ if (fp) {
+- fp->fs_pid = 0;
++ put_pid(fp->fs_pid);
++ fp->fs_pid = NULL;
+ raw3270_reset(&fp->view);
+ raw3270_put_view(&fp->view);
+ raw3270_del_view(&fp->view);
+diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
+index 3be0656..e3491a5 100644
+--- a/drivers/s390/char/keyboard.c
++++ b/drivers/s390/char/keyboard.c
+@@ -304,7 +304,7 @@ kbd_keycode(struct kbd_data *kbd, unsign
+ if (kbd->sysrq) {
+ if (kbd->sysrq == K(KT_LATIN, '-')) {
+ kbd->sysrq = 0;
+- handle_sysrq(value, NULL, kbd->tty);
++ handle_sysrq(value, kbd->tty);
+ return;
+ }
+ if (value == '-') {
+diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
+new file mode 100644
+index 0000000..b9b0fc3
+--- /dev/null
++++ b/drivers/s390/char/monwriter.c
+@@ -0,0 +1,298 @@
++/*
++ * drivers/s390/char/monwriter.c
++ *
++ * Character device driver for writing z/VM *MONITOR service records.
++ *
++ * Copyright (C) IBM Corp. 2006
++ *
++ * Author(s): Melissa Howland <Melissa.Howland at us.ibm.com>
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/ctype.h>
++#include <linux/poll.h>
++#include <asm/uaccess.h>
++#include <asm/ebcdic.h>
++#include <asm/io.h>
++#include <asm/appldata.h>
++#include <asm/monwriter.h>
++
++#define MONWRITE_MAX_DATALEN 4024
++
++static int mon_max_bufs = 255;
++static int mon_buf_count;
++
++struct mon_buf {
++ struct list_head list;
++ struct monwrite_hdr hdr;
++ int diag_done;
++ char *data;
++};
++
++struct mon_private {
++ struct list_head list;
++ struct monwrite_hdr hdr;
++ size_t hdr_to_read;
++ size_t data_to_read;
++ struct mon_buf *current_buf;
++};
++
++/*
++ * helper functions
++ */
++
++static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
++{
++ struct appldata_product_id id;
++ int rc;
++
++ strcpy(id.prod_nr, "LNXAPPL");
++ id.prod_fn = myhdr->applid;
++ id.record_nr = myhdr->record_num;
++ id.version_nr = myhdr->version;
++ id.release_nr = myhdr->release;
++ id.mod_lvl = myhdr->mod_level;
++ rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
++ if (rc <= 0)
++ return rc;
++ if (rc == 5)
++ return -EPERM;
++ printk("DIAG X'DC' error with return code: %i\n", rc);
++ return -EINVAL;
++}
++
++static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
++ struct monwrite_hdr *monhdr)
++{
++ struct mon_buf *entry, *next;
++
++ list_for_each_entry_safe(entry, next, &monpriv->list, list)
++ if ((entry->hdr.mon_function == monhdr->mon_function ||
++ monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
++ entry->hdr.applid == monhdr->applid &&
++ entry->hdr.record_num == monhdr->record_num &&
++ entry->hdr.version == monhdr->version &&
++ entry->hdr.release == monhdr->release &&
++ entry->hdr.mod_level == monhdr->mod_level)
++ return entry;
++
++ return NULL;
++}
++
++static int monwrite_new_hdr(struct mon_private *monpriv)
++{
++ struct monwrite_hdr *monhdr = &monpriv->hdr;
++ struct mon_buf *monbuf;
++ int rc;
++
++ if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
++ monhdr->mon_function > MONWRITE_START_CONFIG ||
++ monhdr->hdrlen != sizeof(struct monwrite_hdr))
++ return -EINVAL;
++ monbuf = NULL;
++ if (monhdr->mon_function != MONWRITE_GEN_EVENT)
++ monbuf = monwrite_find_hdr(monpriv, monhdr);
++ if (monbuf) {
++ if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
++ monhdr->datalen = monbuf->hdr.datalen;
++ rc = monwrite_diag(monhdr, monbuf->data,
++ APPLDATA_STOP_REC);
++ list_del(&monbuf->list);
++ mon_buf_count--;
++ kfree(monbuf->data);
++ kfree(monbuf);
++ monbuf = NULL;
++ }
++ } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
++ if (mon_buf_count >= mon_max_bufs)
++ return -ENOSPC;
++ monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
++ if (!monbuf)
++ return -ENOMEM;
++ monbuf->data = kzalloc(monhdr->datalen,
++ GFP_KERNEL | GFP_DMA);
++ if (!monbuf->data) {
++ kfree(monbuf);
++ return -ENOMEM;
++ }
++ monbuf->hdr = *monhdr;
++ list_add_tail(&monbuf->list, &monpriv->list);
++ if (monhdr->mon_function != MONWRITE_GEN_EVENT)
++ mon_buf_count++;
++ }
++ monpriv->current_buf = monbuf;
++ return 0;
++}
++
++static int monwrite_new_data(struct mon_private *monpriv)
++{
++ struct monwrite_hdr *monhdr = &monpriv->hdr;
++ struct mon_buf *monbuf = monpriv->current_buf;
++ int rc = 0;
++
++ switch (monhdr->mon_function) {
++ case MONWRITE_START_INTERVAL:
++ if (!monbuf->diag_done) {
++ rc = monwrite_diag(monhdr, monbuf->data,
++ APPLDATA_START_INTERVAL_REC);
++ monbuf->diag_done = 1;
++ }
++ break;
++ case MONWRITE_START_CONFIG:
++ if (!monbuf->diag_done) {
++ rc = monwrite_diag(monhdr, monbuf->data,
++ APPLDATA_START_CONFIG_REC);
++ monbuf->diag_done = 1;
++ }
++ break;
++ case MONWRITE_GEN_EVENT:
++ rc = monwrite_diag(monhdr, monbuf->data,
++ APPLDATA_GEN_EVENT_REC);
++ list_del(&monpriv->current_buf->list);
++ kfree(monpriv->current_buf->data);
++ kfree(monpriv->current_buf);
++ monpriv->current_buf = NULL;
++ break;
++ default:
++ /* monhdr->mon_function is checked in monwrite_new_hdr */
++ BUG();
++ }
++ return rc;
++}
++
++/*
++ * file operations
++ */
++
++static int monwrite_open(struct inode *inode, struct file *filp)
++{
++ struct mon_private *monpriv;
++
++ monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
++ if (!monpriv)
++ return -ENOMEM;
++ INIT_LIST_HEAD(&monpriv->list);
++ monpriv->hdr_to_read = sizeof(monpriv->hdr);
++ filp->private_data = monpriv;
++ return nonseekable_open(inode, filp);
++}
++
++static int monwrite_close(struct inode *inode, struct file *filp)
++{
++ struct mon_private *monpriv = filp->private_data;
++ struct mon_buf *entry, *next;
++
++ list_for_each_entry_safe(entry, next, &monpriv->list, list) {
++ if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
++ monwrite_diag(&entry->hdr, entry->data,
++ APPLDATA_STOP_REC);
++ mon_buf_count--;
++ list_del(&entry->list);
++ kfree(entry->data);
++ kfree(entry);
++ }
++ kfree(monpriv);
++ return 0;
++}
++
++static ssize_t monwrite_write(struct file *filp, const char __user *data,
++ size_t count, loff_t *ppos)
++{
++ struct mon_private *monpriv = filp->private_data;
++ size_t len, written;
++ void *to;
++ int rc;
++
++ for (written = 0; written < count; ) {
++ if (monpriv->hdr_to_read) {
++ len = min(count - written, monpriv->hdr_to_read);
++ to = (char *) &monpriv->hdr +
++ sizeof(monpriv->hdr) - monpriv->hdr_to_read;
++ if (copy_from_user(to, data + written, len)) {
++ rc = -EFAULT;
++ goto out_error;
++ }
++ monpriv->hdr_to_read -= len;
++ written += len;
++ if (monpriv->hdr_to_read > 0)
++ continue;
++ rc = monwrite_new_hdr(monpriv);
++ if (rc)
++ goto out_error;
++ monpriv->data_to_read = monpriv->current_buf ?
++ monpriv->current_buf->hdr.datalen : 0;
++ }
++
++ if (monpriv->data_to_read) {
++ len = min(count - written, monpriv->data_to_read);
++ to = monpriv->current_buf->data +
++ monpriv->hdr.datalen - monpriv->data_to_read;
++ if (copy_from_user(to, data + written, len)) {
++ rc = -EFAULT;
++ goto out_error;
++ }
++ monpriv->data_to_read -= len;
++ written += len;
++ if (monpriv->data_to_read > 0)
++ continue;
++ rc = monwrite_new_data(monpriv);
++ if (rc)
++ goto out_error;
++ }
++ monpriv->hdr_to_read = sizeof(monpriv->hdr);
++ }
++ return written;
++
++out_error:
++ monpriv->data_to_read = 0;
++ monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
++ return rc;
++}
++
++static struct file_operations monwrite_fops = {
++ .owner = THIS_MODULE,
++ .open = &monwrite_open,
++ .release = &monwrite_close,
++ .write = &monwrite_write,
++};
++
++static struct miscdevice mon_dev = {
++ .name = "monwriter",
++ .fops = &monwrite_fops,
++ .minor = MISC_DYNAMIC_MINOR,
++};
++
++/*
++ * module init/exit
++ */
++
++static int __init mon_init(void)
++{
++ if (MACHINE_IS_VM)
++ return misc_register(&mon_dev);
++ else
++ return -ENODEV;
++}
++
++static void __exit mon_exit(void)
++{
++ WARN_ON(misc_deregister(&mon_dev) != 0);
++}
++
++module_init(mon_init);
++module_exit(mon_exit);
++
++module_param_named(max_bufs, mon_max_bufs, int, 0644);
++MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
++ "that can be active at one time");
++
++MODULE_AUTHOR("Melissa Howland <Melissa.Howland at us.ibm.com>");
++MODULE_DESCRIPTION("Character device driver for writing z/VM "
++ "APPLDATA monitor records.");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
+index 985d161..8a056df 100644
+--- a/drivers/s390/char/sclp.c
++++ b/drivers/s390/char/sclp.c
+@@ -100,13 +100,12 @@ service_call(sclp_cmdw_t command, void *
+ {
+ int cc;
+
+- __asm__ __volatile__(
+- " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
+- " ipm %0\n"
+- " srl %0,28"
+- : "=&d" (cc)
+- : "d" (command), "a" (__pa(sccb))
+- : "cc", "memory" );
++ asm volatile(
++ " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
++ " ipm %0\n"
++ " srl %0,28"
++ : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
++ : "cc", "memory");
+ if (cc == 3)
+ return -EIO;
+ if (cc == 2)
+@@ -325,7 +324,7 @@ __sclp_find_req(u32 sccb)
+ * Prepare read event data request if necessary. Start processing of next
+ * request on queue. */
+ static void
+-sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
++sclp_interrupt_handler(__u16 code)
+ {
+ struct sclp_req *req;
+ u32 finished_sccb;
+@@ -360,16 +359,6 @@ sclp_interrupt_handler(struct pt_regs *r
+ sclp_process_queue();
+ }
+
+-/* Return current Time-Of-Day clock. */
+-static inline u64
+-sclp_get_clock(void)
+-{
+- u64 result;
+-
+- asm volatile ("STCK 0(%1)" : "=m" (result) : "a" (&(result)) : "cc");
+- return result;
+-}
+-
+ /* Convert interval in jiffies to TOD ticks. */
+ static inline u64
+ sclp_tod_from_jiffies(unsigned long jiffies)
+@@ -382,7 +371,6 @@ sclp_tod_from_jiffies(unsigned long jiff
+ void
+ sclp_sync_wait(void)
+ {
+- unsigned long psw_mask;
+ unsigned long flags;
+ unsigned long cr0, cr0_sync;
+ u64 timeout;
+@@ -392,7 +380,7 @@ sclp_sync_wait(void)
+ timeout = 0;
+ if (timer_pending(&sclp_request_timer)) {
+ /* Get timeout TOD value */
+- timeout = sclp_get_clock() +
++ timeout = get_clock() +
+ sclp_tod_from_jiffies(sclp_request_timer.expires -
+ jiffies);
+ }
+@@ -406,13 +394,12 @@ sclp_sync_wait(void)
+ cr0_sync |= 0x00000200;
+ cr0_sync &= 0xFFFFF3AC;
+ __ctl_load(cr0_sync, 0, 0);
+- asm volatile ("STOSM 0(%1),0x01"
+- : "=m" (psw_mask) : "a" (&psw_mask) : "memory");
++ __raw_local_irq_stosm(0x01);
+ /* Loop until driver state indicates finished request */
+ while (sclp_running_state != sclp_running_state_idle) {
+ /* Check for expired request timer */
+ if (timer_pending(&sclp_request_timer) &&
+- sclp_get_clock() > timeout &&
++ get_clock() > timeout &&
+ del_timer(&sclp_request_timer))
+ sclp_request_timer.function(sclp_request_timer.data);
+ barrier();
+@@ -756,7 +743,7 @@ EXPORT_SYMBOL(sclp_reactivate);
+ /* Handler for external interruption used during initialization. Modify
+ * request state to done. */
+ static void
+-sclp_check_handler(struct pt_regs *regs, __u16 code)
++sclp_check_handler(__u16 code)
+ {
+ u32 finished_sccb;
+
+diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
+index f6cf902..6f43e04 100644
+--- a/drivers/s390/char/sclp_tty.c
++++ b/drivers/s390/char/sclp_tty.c
+@@ -711,7 +711,7 @@ static struct sclp_register sclp_input_e
+ .receiver_fn = sclp_tty_receiver
+ };
+
+-static struct tty_operations sclp_ops = {
++static const struct tty_operations sclp_ops = {
+ .open = sclp_tty_open,
+ .close = sclp_tty_close,
+ .write = sclp_tty_write,
+diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
+index 54fba6f..723bf41 100644
+--- a/drivers/s390/char/sclp_vt220.c
++++ b/drivers/s390/char/sclp_vt220.c
+@@ -655,7 +655,7 @@ __sclp_vt220_init(int early)
+ return 0;
+ }
+
+-static struct tty_operations sclp_vt220_ops = {
++static const struct tty_operations sclp_vt220_ops = {
+ .open = sclp_vt220_open,
+ .close = sclp_vt220_close,
+ .write = sclp_vt220_write,
+diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
+index 2971804..4717c36 100644
+--- a/drivers/s390/char/tty3270.c
++++ b/drivers/s390/char/tty3270.c
+@@ -698,7 +698,6 @@ tty3270_alloc_view(void)
+ if (!tp->freemem_pages)
+ goto out_tp;
+ INIT_LIST_HEAD(&tp->freemem);
+- init_timer(&tp->timer);
+ for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
+ tp->freemem_pages[pages] = (void *)
+ __get_free_pages(GFP_KERNEL|GFP_DMA, 0);
+@@ -1738,7 +1737,7 @@ tty3270_ioctl(struct tty_struct *tty, st
+ return kbd_ioctl(tp->kbd, file, cmd, arg);
+ }
+
+-static struct tty_operations tty3270_ops = {
++static const struct tty_operations tty3270_ops = {
+ .open = tty3270_open,
+ .close = tty3270_close,
+ .write = tty3270_write,
+diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
+index 19762f3..1678b6c 100644
+--- a/drivers/s390/char/vmcp.c
++++ b/drivers/s390/char/vmcp.c
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (C) 2004,2005 IBM Corporation
+- * Interface implementation for communication with the v/VM control program
++ * Interface implementation for communication with the z/VM control program
+ * Author(s): Christian Borntraeger <cborntra at de.ibm.com>
+ *
+ *
+diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h
+index 87389e7..8a5975f 100644
+--- a/drivers/s390/char/vmcp.h
++++ b/drivers/s390/char/vmcp.h
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (C) 2004, 2005 IBM Corporation
+- * Interface implementation for communication with the v/VM control program
++ * Interface implementation for communication with the z/VM control program
+ * Version 1.0
+ * Author(s): Christian Borntraeger <cborntra at de.ibm.com>
+ *
+diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
+index 807320a..4b868f7 100644
+--- a/drivers/s390/char/vmwatchdog.c
++++ b/drivers/s390/char/vmwatchdog.c
+@@ -54,48 +54,20 @@ enum vmwdt_func {
+ static int __diag288(enum vmwdt_func func, unsigned int timeout,
+ char *cmd, size_t len)
+ {
+- register unsigned long __func asm("2");
+- register unsigned long __timeout asm("3");
+- register unsigned long __cmdp asm("4");
+- register unsigned long __cmdl asm("5");
++ register unsigned long __func asm("2") = func;
++ register unsigned long __timeout asm("3") = timeout;
++ register unsigned long __cmdp asm("4") = virt_to_phys(cmd);
++ register unsigned long __cmdl asm("5") = len;
+ int err;
+
+- __func = func;
+- __timeout = timeout;
+- __cmdp = virt_to_phys(cmd);
+- __cmdl = len;
+- err = 0;
+- asm volatile (
+-#ifdef CONFIG_64BIT
+- "diag %2,%4,0x288\n"
+- "1: \n"
+- ".section .fixup,\"ax\"\n"
+- "2: lghi %0,%1\n"
+- " jg 1b\n"
+- ".previous\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 1b,2b\n"
+- ".previous\n"
+-#else
+- "diag %2,%4,0x288\n"
+- "1: \n"
+- ".section .fixup,\"ax\"\n"
+- "2: lhi %0,%1\n"
+- " bras 1,3f\n"
+- " .long 1b\n"
+- "3: l 1,0(1)\n"
+- " br 1\n"
+- ".previous\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 1b,2b\n"
+- ".previous\n"
+-#endif
+- : "+&d"(err)
+- : "i"(-EINVAL), "d"(__func), "d"(__timeout),
+- "d"(__cmdp), "d"(__cmdl)
+- : "1", "cc");
++ err = -EINVAL;
++ asm volatile(
++ " diag %1,%3,0x288\n"
++ "0: la %0,0\n"
++ "1:\n"
++ EX_TABLE(0b,1b)
++ : "=d" (err) : "d"(__func), "d"(__timeout),
++ "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+ return err;
+ }
+
+diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
+index c28444a..2d78f0f 100644
+--- a/drivers/s390/cio/chsc.c
++++ b/drivers/s390/cio/chsc.c
+@@ -200,11 +200,13 @@ css_get_ssd_info(struct subchannel *sch)
+ spin_unlock_irq(&sch->lock);
+ free_page((unsigned long)page);
+ if (!ret) {
+- int j, chpid;
++ int j, chpid, mask;
+ /* Allocate channel path structures, if needed. */
+ for (j = 0; j < 8; j++) {
++ mask = 0x80 >> j;
+ chpid = sch->ssd_info.chpid[j];
+- if (chpid && (get_chp_status(chpid) < 0))
++ if ((sch->schib.pmcw.pim & mask) &&
++ (get_chp_status(chpid) < 0))
+ new_channel_path(chpid);
+ }
+ }
+@@ -222,13 +224,15 @@ s390_subchannel_remove_chpid(struct devi
+
+ sch = to_subchannel(dev);
+ chpid = data;
+- for (j = 0; j < 8; j++)
+- if (sch->schib.pmcw.chpid[j] == chpid->id)
++ for (j = 0; j < 8; j++) {
++ mask = 0x80 >> j;
++ if ((sch->schib.pmcw.pim & mask) &&
++ (sch->schib.pmcw.chpid[j] == chpid->id))
+ break;
++ }
+ if (j >= 8)
+ return 0;
+
+- mask = 0x80 >> j;
+ spin_lock_irq(&sch->lock);
+
+ stsch(sch->schid, &schib);
+@@ -256,7 +260,7 @@ s390_subchannel_remove_chpid(struct devi
+ /* trigger path verification. */
+ if (sch->driver && sch->driver->verify)
+ sch->driver->verify(&sch->dev);
+- else if (sch->vpm == mask)
++ else if (sch->lpm == mask)
+ goto out_unreg;
+ out_unlock:
+ spin_unlock_irq(&sch->lock);
+@@ -366,7 +370,7 @@ __s390_process_res_acc(struct subchannel
+ struct res_acc_data *res_data;
+ struct subchannel *sch;
+
+- res_data = (struct res_acc_data *)data;
++ res_data = data;
+ sch = get_subchannel_by_schid(schid);
+ if (!sch)
+ /* Check if a subchannel is newly available. */
+@@ -378,6 +382,7 @@ __s390_process_res_acc(struct subchannel
+
+ if (chp_mask == 0) {
+ spin_unlock_irq(&sch->lock);
++ put_device(&sch->dev);
+ return 0;
+ }
+ old_lpm = sch->lpm;
+@@ -392,7 +397,7 @@ __s390_process_res_acc(struct subchannel
+
+ spin_unlock_irq(&sch->lock);
+ put_device(&sch->dev);
+- return (res_data->fla_mask == 0xffff) ? -ENODEV : 0;
++ return 0;
+ }
+
+
+@@ -439,7 +444,7 @@ __get_chpid_from_lir(void *data)
+ u32 isinfo[28];
+ } *lir;
+
+- lir = (struct lir*) data;
++ lir = data;
+ if (!(lir->iq&0x80))
+ /* NULL link incident record */
+ return -EINVAL;
+@@ -619,18 +624,20 @@ __chp_add_new_sch(struct subchannel_id s
+ static int
+ __chp_add(struct subchannel_id schid, void *data)
+ {
+- int i;
++ int i, mask;
+ struct channel_path *chp;
+ struct subchannel *sch;
+
+- chp = (struct channel_path *)data;
++ chp = data;
+ sch = get_subchannel_by_schid(schid);
+ if (!sch)
+ /* Check if the subchannel is now available. */
+ return __chp_add_new_sch(schid);
+ spin_lock_irq(&sch->lock);
+- for (i=0; i<8; i++)
+- if (sch->schib.pmcw.chpid[i] == chp->id) {
++ for (i=0; i<8; i++) {
++ mask = 0x80 >> i;
++ if ((sch->schib.pmcw.pim & mask) &&
++ (sch->schib.pmcw.chpid[i] == chp->id)) {
+ if (stsch(sch->schid, &sch->schib) != 0) {
+ /* Endgame. */
+ spin_unlock_irq(&sch->lock);
+@@ -638,6 +645,7 @@ __chp_add(struct subchannel_id schid, vo
+ }
+ break;
+ }
++ }
+ if (i==8) {
+ spin_unlock_irq(&sch->lock);
+ return 0;
+@@ -645,7 +653,7 @@ __chp_add(struct subchannel_id schid, vo
+ sch->lpm = ((sch->schib.pmcw.pim &
+ sch->schib.pmcw.pam &
+ sch->schib.pmcw.pom)
+- | 0x80 >> i) & sch->opm;
++ | mask) & sch->opm;
+
+ if (sch->driver && sch->driver->verify)
+ sch->driver->verify(&sch->dev);
+@@ -699,8 +707,7 @@ chp_process_crw(int chpid, int on)
+ return chp_add(chpid);
+ }
+
+-static inline int
+-__check_for_io_and_kill(struct subchannel *sch, int index)
++static inline int check_for_io_on_path(struct subchannel *sch, int index)
+ {
+ int cc;
+
+@@ -710,10 +717,8 @@ __check_for_io_and_kill(struct subchanne
+ cc = stsch(sch->schid, &sch->schib);
+ if (cc)
+ return 0;
+- if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) {
+- device_set_waiting(sch);
++ if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index))
+ return 1;
+- }
+ return 0;
+ }
+
+@@ -742,12 +747,10 @@ __s390_subchannel_vary_chpid(struct subc
+ } else {
+ sch->opm &= ~(0x80 >> chp);
+ sch->lpm &= ~(0x80 >> chp);
+- /*
+- * Give running I/O a grace period in which it
+- * can successfully terminate, even using the
+- * just varied off path. Then kill it.
+- */
+- if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {
++ if (check_for_io_on_path(sch, chp))
++ /* Path verification is done after killing. */
++ device_kill_io(sch);
++ else if (!sch->lpm) {
+ if (css_enqueue_subchannel_slow(sch->schid)) {
+ css_clear_subchannel_slow_list();
+ need_rescan = 1;
+diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
+index 89320c1..8936e46 100644
+--- a/drivers/s390/cio/cio.c
++++ b/drivers/s390/cio/cio.c
+@@ -16,11 +16,11 @@
+ #include <linux/device.h>
+ #include <linux/kernel_stat.h>
+ #include <linux/interrupt.h>
+-
+ #include <asm/cio.h>
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+-
++#include <asm/irq_regs.h>
++#include <asm/setup.h>
+ #include "airq.h"
+ #include "cio.h"
+ #include "css.h"
+@@ -192,7 +192,7 @@ cio_start_key (struct subchannel *sch, /
+ sch->orb.pfch = sch->options.prefetch == 0;
+ sch->orb.spnd = sch->options.suspend;
+ sch->orb.ssic = sch->options.suspend && sch->options.inter;
+- sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm;
++ sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
+ #ifdef CONFIG_64BIT
+ /*
+ * for 64 bit we always support 64 bit IDAWs with 4k page size only
+@@ -570,10 +570,7 @@ cio_validate_subchannel (struct subchann
+ sch->opm = 0xff;
+ if (!cio_is_console(sch->schid))
+ chsc_validate_chpids(sch);
+- sch->lpm = sch->schib.pmcw.pim &
+- sch->schib.pmcw.pam &
+- sch->schib.pmcw.pom &
+- sch->opm;
++ sch->lpm = sch->schib.pmcw.pam & sch->opm;
+
+ CIO_DEBUG(KERN_INFO, 0,
+ "Detected device %04x on subchannel 0.%x.%04X"
+@@ -610,15 +607,17 @@ do_IRQ (struct pt_regs *regs)
+ struct tpi_info *tpi_info;
+ struct subchannel *sch;
+ struct irb *irb;
++ struct pt_regs *old_regs;
+
+- irq_enter ();
++ old_regs = set_irq_regs(regs);
++ irq_enter();
+ asm volatile ("mc 0,0");
+ if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+ /**
+ * Make sure that the i/o interrupt did not "overtake"
+ * the last HZ timer interrupt.
+ */
+- account_ticks(regs);
++ account_ticks();
+ /*
+ * Get interrupt information from lowcore
+ */
+@@ -656,7 +655,8 @@ do_IRQ (struct pt_regs *regs)
+ * out of the sie which costs more cycles than it saves.
+ */
+ } while (!MACHINE_IS_VM && tpi (NULL) != 0);
+- irq_exit ();
++ irq_exit();
++ set_irq_regs(old_regs);
+ }
+
+ #ifdef CONFIG_CCW_CONSOLE
+@@ -841,14 +841,26 @@ __clear_subchannel_easy(struct subchanne
+ return -EBUSY;
+ }
+
+-extern void do_reipl(unsigned long devno);
+-static int
+-__shutdown_subchannel_easy(struct subchannel_id schid, void *data)
++struct sch_match_id {
++ struct subchannel_id schid;
++ struct ccw_dev_id devid;
++ int rc;
++};
++
++static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid,
++ void *data)
+ {
+ struct schib schib;
++ struct sch_match_id *match_id = data;
+
+ if (stsch_err(schid, &schib))
+ return -ENXIO;
++ if (match_id && schib.pmcw.dnv &&
++ (schib.pmcw.dev == match_id->devid.devno) &&
++ (schid.ssid == match_id->devid.ssid)) {
++ match_id->schid = schid;
++ match_id->rc = 0;
++ }
+ if (!schib.pmcw.ena)
+ return 0;
+ switch(__disable_subchannel_easy(schid, &schib)) {
+@@ -864,18 +876,71 @@ __shutdown_subchannel_easy(struct subcha
+ return 0;
+ }
+
+-void
+-clear_all_subchannels(void)
++static int clear_all_subchannels_and_match(struct ccw_dev_id *devid,
++ struct subchannel_id *schid)
++{
++ struct sch_match_id match_id;
++
++ match_id.devid = *devid;
++ match_id.rc = -ENODEV;
++ local_irq_disable();
++ for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id);
++ if (match_id.rc == 0)
++ *schid = match_id.schid;
++ return match_id.rc;
++}
++
++
++void clear_all_subchannels(void)
+ {
+ local_irq_disable();
+- for_each_subchannel(__shutdown_subchannel_easy, NULL);
++ for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL);
+ }
+
++extern void do_reipl_asm(__u32 schid);
++
+ /* Make sure all subchannels are quiet before we re-ipl an lpar. */
+-void
+-reipl(unsigned long devno)
++void reipl_ccw_dev(struct ccw_dev_id *devid)
+ {
+- clear_all_subchannels();
++ struct subchannel_id schid;
++
++ if (clear_all_subchannels_and_match(devid, &schid))
++ panic("IPL Device not found\n");
+ cio_reset_channel_paths();
+- do_reipl(devno);
++ do_reipl_asm(*((__u32*)&schid));
++}
++
++extern struct schib ipl_schib;
++
++/*
++ * ipl_save_parameters gets called very early. It is not allowed to access
++ * anything in the bss section at all. The bss section is not cleared yet,
++ * but may contain some ipl parameters written by the firmware.
++ * These parameters (if present) are copied to 0x2000.
++ * To avoid corruption of the ipl parameters, all variables used by this
++ * function must reside on the stack or in the data section.
++ */
++void ipl_save_parameters(void)
++{
++ struct subchannel_id schid;
++ unsigned int *ipl_ptr;
++ void *src, *dst;
++
++ schid = *(struct subchannel_id *)__LC_SUBCHANNEL_ID;
++ if (!schid.one)
++ return;
++ if (stsch(schid, &ipl_schib))
++ return;
++ if (!ipl_schib.pmcw.dnv)
++ return;
++ ipl_devno = ipl_schib.pmcw.dev;
++ ipl_flags |= IPL_DEVNO_VALID;
++ if (!ipl_schib.pmcw.qf)
++ return;
++ ipl_flags |= IPL_PARMBLOCK_VALID;
++ ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR;
++ src = (void *)(unsigned long)*ipl_ptr;
++ dst = (void *)IPL_PARMBLOCK_ORIGIN;
++ memmove(dst, src, PAGE_SIZE);
++ *ipl_ptr = IPL_PARMBLOCK_ORIGIN;
+ }
+diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
+index 13eeea3..ad7f7e1 100644
+--- a/drivers/s390/cio/css.c
++++ b/drivers/s390/cio/css.c
+@@ -177,141 +177,145 @@ get_subchannel_by_schid(struct subchanne
+ struct device *dev;
+
+ dev = bus_find_device(&css_bus_type, NULL,
+- (void *)&schid, check_subchannel);
++ &schid, check_subchannel);
+
+ return dev ? to_subchannel(dev) : NULL;
+ }
+
+-
+-static inline int
+-css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid)
++static inline int css_get_subchannel_status(struct subchannel *sch)
+ {
+ struct schib schib;
+- int cc;
+
+- cc = stsch(schid, &schib);
+- if (cc)
+- return CIO_GONE;
+- if (!schib.pmcw.dnv)
++ if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
+ return CIO_GONE;
+- if (sch && sch->schib.pmcw.dnv &&
+- (schib.pmcw.dev != sch->schib.pmcw.dev))
++ if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
+ return CIO_REVALIDATE;
+- if (sch && !sch->lpm)
++ if (!sch->lpm)
+ return CIO_NO_PATH;
+ return CIO_OPER;
+ }
+-
+-static int
+-css_evaluate_subchannel(struct subchannel_id schid, int slow)
++
++static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
+ {
+ int event, ret, disc;
+- struct subchannel *sch;
+ unsigned long flags;
++ enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
+
+- sch = get_subchannel_by_schid(schid);
+- disc = sch ? device_is_disconnected(sch) : 0;
++ spin_lock_irqsave(&sch->lock, flags);
++ disc = device_is_disconnected(sch);
+ if (disc && slow) {
+- if (sch)
+- put_device(&sch->dev);
+- return 0; /* Already processed. */
++ /* Disconnected devices are evaluated directly only.*/
++ spin_unlock_irqrestore(&sch->lock, flags);
++ return 0;
+ }
+- /*
+- * We've got a machine check, so running I/O won't get an interrupt.
+- * Kill any pending timers.
+- */
+- if (sch)
+- device_kill_pending_timer(sch);
++ /* No interrupt after machine check - kill pending timers. */
++ device_kill_pending_timer(sch);
+ if (!disc && !slow) {
+- if (sch)
+- put_device(&sch->dev);
+- return -EAGAIN; /* Will be done on the slow path. */
++ /* Non-disconnected devices are evaluated on the slow path. */
++ spin_unlock_irqrestore(&sch->lock, flags);
++ return -EAGAIN;
+ }
+- event = css_get_subchannel_status(sch, schid);
++ event = css_get_subchannel_status(sch);
+ CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
+- schid.ssid, schid.sch_no, event,
+- sch?(disc?"disconnected":"normal"):"unknown",
+- slow?"slow":"fast");
++ sch->schid.ssid, sch->schid.sch_no, event,
++ disc ? "disconnected" : "normal",
++ slow ? "slow" : "fast");
++ /* Analyze subchannel status. */
++ action = NONE;
+ switch (event) {
+ case CIO_NO_PATH:
+- case CIO_GONE:
+- if (!sch) {
+- /* Never used this subchannel. Ignore. */
+- ret = 0;
++ if (disc) {
++ /* Check if paths have become available. */
++ action = REPROBE;
+ break;
+ }
+- if (disc && (event == CIO_NO_PATH)) {
+- /*
+- * Uargh, hack again. Because we don't get a machine
+- * check on configure on, our path bookkeeping can
+- * be out of date here (it's fine while we only do
+- * logical varying or get chsc machine checks). We
+- * need to force reprobing or we might miss devices
+- * coming operational again. It won't do harm in real
+- * no path situations.
+- */
+- spin_lock_irqsave(&sch->lock, flags);
+- device_trigger_reprobe(sch);
++ /* fall through */
++ case CIO_GONE:
++ /* Prevent unwanted effects when opening lock. */
++ cio_disable_subchannel(sch);
++ device_set_disconnected(sch);
++ /* Ask driver what to do with device. */
++ action = UNREGISTER;
++ if (sch->driver && sch->driver->notify) {
+ spin_unlock_irqrestore(&sch->lock, flags);
+- ret = 0;
+- break;
+- }
+- if (sch->driver && sch->driver->notify &&
+- sch->driver->notify(&sch->dev, event)) {
+- cio_disable_subchannel(sch);
+- device_set_disconnected(sch);
+- ret = 0;
+- break;
++ ret = sch->driver->notify(&sch->dev, event);
++ spin_lock_irqsave(&sch->lock, flags);
++ if (ret)
++ action = NONE;
+ }
+- /*
+- * Unregister subchannel.
+- * The device will be killed automatically.
+- */
+- cio_disable_subchannel(sch);
+- css_sch_device_unregister(sch);
+- /* Reset intparm to zeroes. */
+- sch->schib.pmcw.intparm = 0;
+- cio_modify(sch);
+- put_device(&sch->dev);
+- ret = 0;
+ break;
+ case CIO_REVALIDATE:
+- /*
+- * Revalidation machine check. Sick.
+- * We don't notify the driver since we have to throw the device
+- * away in any case.
+- */
+- if (!disc) {
+- css_sch_device_unregister(sch);
+- /* Reset intparm to zeroes. */
+- sch->schib.pmcw.intparm = 0;
+- cio_modify(sch);
+- put_device(&sch->dev);
+- ret = css_probe_device(schid);
+- } else {
+- /*
+- * We can't immediately deregister the disconnected
+- * device since it might block.
+- */
+- spin_lock_irqsave(&sch->lock, flags);
+- device_trigger_reprobe(sch);
+- spin_unlock_irqrestore(&sch->lock, flags);
+- ret = 0;
+- }
++ /* Device will be removed, so no notify necessary. */
++ if (disc)
++ /* Reprobe because immediate unregister might block. */
++ action = REPROBE;
++ else
++ action = UNREGISTER_PROBE;
+ break;
+ case CIO_OPER:
+- if (disc) {
+- spin_lock_irqsave(&sch->lock, flags);
++ if (disc)
+ /* Get device operational again. */
+- device_trigger_reprobe(sch);
+- spin_unlock_irqrestore(&sch->lock, flags);
+- }
+- ret = sch ? 0 : css_probe_device(schid);
++ action = REPROBE;
++ break;
++ }
++ /* Perform action. */
++ ret = 0;
++ switch (action) {
++ case UNREGISTER:
++ case UNREGISTER_PROBE:
++ /* Unregister device (will use subchannel lock). */
++ spin_unlock_irqrestore(&sch->lock, flags);
++ css_sch_device_unregister(sch);
++ spin_lock_irqsave(&sch->lock, flags);
++
++ /* Reset intparm to zeroes. */
++ sch->schib.pmcw.intparm = 0;
++ cio_modify(sch);
++ break;
++ case REPROBE:
++ device_trigger_reprobe(sch);
+ break;
+ default:
+- BUG();
+- ret = 0;
++ break;
++ }
++ spin_unlock_irqrestore(&sch->lock, flags);
++ /* Probe if necessary. */
++ if (action == UNREGISTER_PROBE)
++ ret = css_probe_device(sch->schid);
++
++ return ret;
++}
++
++static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
++{
++ struct schib schib;
++
++ if (!slow) {
++ /* Will be done on the slow path. */
++ return -EAGAIN;
+ }
++ if (stsch(schid, &schib) || !schib.pmcw.dnv) {
++ /* Unusable - ignore. */
++ return 0;
++ }
++ CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, unknown, "
++ "slow path.\n", schid.ssid, schid.sch_no, CIO_OPER);
++
++ return css_probe_device(schid);
++}
++
++static int css_evaluate_subchannel(struct subchannel_id schid, int slow)
++{
++ struct subchannel *sch;
++ int ret;
++
++ sch = get_subchannel_by_schid(schid);
++ if (sch) {
++ ret = css_evaluate_known_subchannel(sch, slow);
++ put_device(&sch->dev);
++ } else
++ ret = css_evaluate_new_subchannel(schid, slow);
++
+ return ret;
+ }
+
+diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
+index 8aabb4a..4c2ff83 100644
+--- a/drivers/s390/cio/css.h
++++ b/drivers/s390/cio/css.h
+@@ -76,9 +76,8 @@ struct ccw_device_private {
+ int state; /* device state */
+ atomic_t onoff;
+ unsigned long registered;
+- __u16 devno; /* device number */
+- __u16 sch_no; /* subchannel number */
+- __u8 ssid; /* subchannel set id */
++ struct ccw_dev_id dev_id; /* device id */
++ struct subchannel_id schid; /* subchannel number */
+ __u8 imask; /* lpm mask for SNID/SID/SPGID */
+ int iretry; /* retry counter SNID/SID/SPGID */
+ struct {
+@@ -171,7 +170,7 @@ void device_trigger_reprobe(struct subch
+
+ /* Helper functions for vary on/off. */
+ int device_is_online(struct subchannel *);
+-void device_set_waiting(struct subchannel *);
++void device_kill_io(struct subchannel *);
+
+ /* Machine check helper function. */
+ void device_kill_pending_timer(struct subchannel *);
+diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
+index 646da56..39c98f9 100644
+--- a/drivers/s390/cio/device.c
++++ b/drivers/s390/cio/device.c
+@@ -52,53 +52,81 @@ ccw_bus_match (struct device * dev, stru
+ return 1;
+ }
+
+-/*
+- * Hotplugging interface for ccw devices.
+- * Heavily modeled on pci and usb hotplug.
+- */
+-static int
+-ccw_uevent (struct device *dev, char **envp, int num_envp,
+- char *buffer, int buffer_size)
++/* Store modalias string delimited by prefix/suffix string into buffer with
++ * specified size. Return length of resulting string (excluding trailing '\0')
++ * even if string doesn't fit buffer (snprintf semantics). */
++static int snprint_alias(char *buf, size_t size, const char *prefix,
++ struct ccw_device_id *id, const char *suffix)
+ {
+- struct ccw_device *cdev = to_ccwdev(dev);
+- int i = 0;
+- int length = 0;
++ int len;
+
+- if (!cdev)
+- return -ENODEV;
++ len = snprintf(buf, size, "%sccw:t%04Xm%02X", prefix, id->cu_type,
++ id->cu_model);
++ if (len > size)
++ return len;
++ buf += len;
++ size -= len;
+
+- /* what we want to pass to /sbin/hotplug */
++ if (id->dev_type != 0)
++ len += snprintf(buf, size, "dt%04Xdm%02X%s", id->dev_type,
++ id->dev_model, suffix);
++ else
++ len += snprintf(buf, size, "dtdm%s", suffix);
+
+- envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "CU_TYPE=%04X",
+- cdev->id.cu_type);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
+- return -ENOMEM;
+- ++length;
+- buffer += length;
++ return len;
++}
++
++/* Set up environment variables for ccw device uevent. Return 0 on success,
++ * non-zero otherwise. */
++static int ccw_uevent(struct device *dev, char **envp, int num_envp,
++ char *buffer, int buffer_size)
++{
++ struct ccw_device *cdev = to_ccwdev(dev);
++ struct ccw_device_id *id = &(cdev->id);
++ int i = 0;
++ int len;
+
++ /* CU_TYPE= */
++ len = snprintf(buffer, buffer_size, "CU_TYPE=%04X", id->cu_type) + 1;
++ if (len > buffer_size || i >= num_envp)
++ return -ENOMEM;
+ envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "CU_MODEL=%02X",
+- cdev->id.cu_model);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
++ buffer += len;
++ buffer_size -= len;
++
++ /* CU_MODEL= */
++ len = snprintf(buffer, buffer_size, "CU_MODEL=%02X", id->cu_model) + 1;
++ if (len > buffer_size || i >= num_envp)
+ return -ENOMEM;
+- ++length;
+- buffer += length;
++ envp[i++] = buffer;
++ buffer += len;
++ buffer_size -= len;
+
+ /* The next two can be zero, that's ok for us */
+- envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "DEV_TYPE=%04X",
+- cdev->id.dev_type);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
++ /* DEV_TYPE= */
++ len = snprintf(buffer, buffer_size, "DEV_TYPE=%04X", id->dev_type) + 1;
++ if (len > buffer_size || i >= num_envp)
+ return -ENOMEM;
+- ++length;
+- buffer += length;
++ envp[i++] = buffer;
++ buffer += len;
++ buffer_size -= len;
+
++ /* DEV_MODEL= */
++ len = snprintf(buffer, buffer_size, "DEV_MODEL=%02X",
++ (unsigned char) id->dev_model) + 1;
++ if (len > buffer_size || i >= num_envp)
++ return -ENOMEM;
+ envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "DEV_MODEL=%02X",
+- cdev->id.dev_model);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
++ buffer += len;
++ buffer_size -= len;
++
++ /* MODALIAS= */
++ len = snprint_alias(buffer, buffer_size, "MODALIAS=", id, "") + 1;
++ if (len > buffer_size || i >= num_envp)
+ return -ENOMEM;
++ envp[i++] = buffer;
++ buffer += len;
++ buffer_size -= len;
+
+ envp[i] = NULL;
+
+@@ -251,16 +279,11 @@ modalias_show (struct device *dev, struc
+ {
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct ccw_device_id *id = &(cdev->id);
+- int ret;
++ int len;
+
+- ret = sprintf(buf, "ccw:t%04Xm%02X",
+- id->cu_type, id->cu_model);
+- if (id->dev_type != 0)
+- ret += sprintf(buf + ret, "dt%04Xdm%02X\n",
+- id->dev_type, id->dev_model);
+- else
+- ret += sprintf(buf + ret, "dtdm\n");
+- return ret;
++ len = snprint_alias(buf, PAGE_SIZE, "", id, "\n") + 1;
++
++ return len > PAGE_SIZE ? PAGE_SIZE : len;
+ }
+
+ static ssize_t
+@@ -509,8 +532,7 @@ device_remove_files(struct device *dev)
+
+ /* this is a simple abstraction for device_register that sets the
+ * correct bus type and adds the bus specific files */
+-int
+-ccw_device_register(struct ccw_device *cdev)
++static int ccw_device_register(struct ccw_device *cdev)
+ {
+ struct device *dev = &cdev->dev;
+ int ret;
+@@ -529,21 +551,19 @@ ccw_device_register(struct ccw_device *c
+ }
+
+ struct match_data {
+- unsigned int devno;
+- unsigned int ssid;
++ struct ccw_dev_id dev_id;
+ struct ccw_device * sibling;
+ };
+
+ static int
+ match_devno(struct device * dev, void * data)
+ {
+- struct match_data * d = (struct match_data *)data;
++ struct match_data * d = data;
+ struct ccw_device * cdev;
+
+ cdev = to_ccwdev(dev);
+ if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
+- (cdev->private->devno == d->devno) &&
+- (cdev->private->ssid == d->ssid) &&
++ ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
+ (cdev != d->sibling)) {
+ cdev->private->state = DEV_STATE_NOT_OPER;
+ return 1;
+@@ -551,15 +571,13 @@ match_devno(struct device * dev, void *
+ return 0;
+ }
+
+-static struct ccw_device *
+-get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid,
+- struct ccw_device *sibling)
++static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
++ struct ccw_device *sibling)
+ {
+ struct device *dev;
+ struct match_data data;
+
+- data.devno = devno;
+- data.ssid = ssid;
++ data.dev_id = *dev_id;
+ data.sibling = sibling;
+ dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno);
+
+@@ -572,7 +590,7 @@ ccw_device_add_changed(void *data)
+
+ struct ccw_device *cdev;
+
+- cdev = (struct ccw_device *)data;
++ cdev = data;
+ if (device_add(&cdev->dev)) {
+ put_device(&cdev->dev);
+ return;
+@@ -593,9 +611,9 @@ ccw_device_do_unreg_rereg(void *data)
+ struct subchannel *sch;
+ int need_rename;
+
+- cdev = (struct ccw_device *)data;
++ cdev = data;
+ sch = to_subchannel(cdev->dev.parent);
+- if (cdev->private->devno != sch->schib.pmcw.dev) {
++ if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
+ /*
+ * The device number has changed. This is usually only when
+ * a device has been detached under VM and then re-appeared
+@@ -610,10 +628,12 @@ ccw_device_do_unreg_rereg(void *data)
+ * get possibly sick...
+ */
+ struct ccw_device *other_cdev;
++ struct ccw_dev_id dev_id;
+
+ need_rename = 1;
+- other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev,
+- sch->schid.ssid, cdev);
++ dev_id.devno = sch->schib.pmcw.dev;
++ dev_id.ssid = sch->schid.ssid;
++ other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
+ if (other_cdev) {
+ struct subchannel *other_sch;
+
+@@ -629,7 +649,7 @@ ccw_device_do_unreg_rereg(void *data)
+ }
+ /* Update ssd info here. */
+ css_get_ssd_info(sch);
+- cdev->private->devno = sch->schib.pmcw.dev;
++ cdev->private->dev_id.devno = sch->schib.pmcw.dev;
+ } else
+ need_rename = 0;
+ device_remove_files(&cdev->dev);
+@@ -639,7 +659,7 @@ ccw_device_do_unreg_rereg(void *data)
+ snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
+ sch->schid.ssid, sch->schib.pmcw.dev);
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_add_changed, (void *)cdev);
++ ccw_device_add_changed, cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+
+@@ -664,7 +684,7 @@ io_subchannel_register(void *data)
+ int ret;
+ unsigned long flags;
+
+- cdev = (struct ccw_device *) data;
++ cdev = data;
+ sch = to_subchannel(cdev->dev.parent);
+
+ if (klist_node_attached(&cdev->dev.knode_parent)) {
+@@ -736,7 +756,7 @@ io_subchannel_recog_done(struct ccw_devi
+ break;
+ sch = to_subchannel(cdev->dev.parent);
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_call_sch_unregister, (void *) cdev);
++ ccw_device_call_sch_unregister, cdev);
+ queue_work(slow_path_wq, &cdev->private->kick_work);
+ if (atomic_dec_and_test(&ccw_device_init_count))
+ wake_up(&ccw_device_init_wq);
+@@ -751,7 +771,7 @@ io_subchannel_recog_done(struct ccw_devi
+ if (!get_device(&cdev->dev))
+ break;
+ PREPARE_WORK(&cdev->private->kick_work,
+- io_subchannel_register, (void *) cdev);
++ io_subchannel_register, cdev);
+ queue_work(slow_path_wq, &cdev->private->kick_work);
+ break;
+ }
+@@ -769,9 +789,9 @@ io_subchannel_recog(struct ccw_device *c
+
+ /* Init private data. */
+ priv = cdev->private;
+- priv->devno = sch->schib.pmcw.dev;
+- priv->ssid = sch->schid.ssid;
+- priv->sch_no = sch->schid.sch_no;
++ priv->dev_id.devno = sch->schib.pmcw.dev;
++ priv->dev_id.ssid = sch->schid.ssid;
++ priv->schid = sch->schid;
+ priv->state = DEV_STATE_NOT_OPER;
+ INIT_LIST_HEAD(&priv->cmb_list);
+ init_waitqueue_head(&priv->wait_q);
+@@ -889,7 +909,7 @@ io_subchannel_remove (struct subchannel
+ */
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_unregister, (void *) cdev);
++ ccw_device_unregister, cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ return 0;
+@@ -1032,7 +1052,7 @@ __ccwdev_check_busid(struct device *dev,
+ {
+ char *bus_id;
+
+- bus_id = (char *)id;
++ bus_id = id;
+
+ return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0);
+ }
+diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
+index 00be9a5..9233b5c 100644
+--- a/drivers/s390/cio/device.h
++++ b/drivers/s390/cio/device.h
+@@ -21,7 +21,6 @@ enum dev_state {
+ /* states to wait for i/o completion before doing something */
+ DEV_STATE_CLEAR_VERIFY,
+ DEV_STATE_TIMEOUT_KILL,
+- DEV_STATE_WAIT4IO,
+ DEV_STATE_QUIESCE,
+ /* special states for devices gone not operational */
+ DEV_STATE_DISCONNECTED,
+@@ -79,7 +78,6 @@ void io_subchannel_recog_done(struct ccw
+
+ int ccw_device_cancel_halt_clear(struct ccw_device *);
+
+-int ccw_device_register(struct ccw_device *);
+ void ccw_device_do_unreg_rereg(void *);
+ void ccw_device_call_sch_unregister(void *);
+
+diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
+index 35e162b..de3d085 100644
+--- a/drivers/s390/cio/device_fsm.c
++++ b/drivers/s390/cio/device_fsm.c
+@@ -59,18 +59,6 @@ device_set_disconnected(struct subchanne
+ cdev->private->state = DEV_STATE_DISCONNECTED;
+ }
+
+-void
+-device_set_waiting(struct subchannel *sch)
+-{
+- struct ccw_device *cdev;
+-
+- if (!sch->dev.driver_data)
+- return;
+- cdev = sch->dev.driver_data;
+- ccw_device_set_timeout(cdev, 10*HZ);
+- cdev->private->state = DEV_STATE_WAIT4IO;
+-}
+-
+ /*
+ * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
+ */
+@@ -183,9 +171,9 @@ ccw_device_handle_oper(struct ccw_device
+ cdev->id.cu_model != cdev->private->senseid.cu_model ||
+ cdev->id.dev_type != cdev->private->senseid.dev_type ||
+ cdev->id.dev_model != cdev->private->senseid.dev_model ||
+- cdev->private->devno != sch->schib.pmcw.dev) {
++ cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_do_unreg_rereg, (void *)cdev);
++ ccw_device_do_unreg_rereg, cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ return 0;
+ }
+@@ -232,10 +220,7 @@ ccw_device_recog_done(struct ccw_device
+ */
+ old_lpm = sch->lpm;
+ stsch(sch->schid, &sch->schib);
+- sch->lpm = sch->schib.pmcw.pim &
+- sch->schib.pmcw.pam &
+- sch->schib.pmcw.pom &
+- sch->opm;
++ sch->lpm = sch->schib.pmcw.pam & sch->opm;
+ /* Check since device may again have become not operational. */
+ if (!sch->schib.pmcw.dnv)
+ state = DEV_STATE_NOT_OPER;
+@@ -258,7 +243,7 @@ ccw_device_recog_done(struct ccw_device
+ case DEV_STATE_NOT_OPER:
+ CIO_DEBUG(KERN_WARNING, 2,
+ "SenseID : unknown device %04x on subchannel "
+- "0.%x.%04x\n", cdev->private->devno,
++ "0.%x.%04x\n", cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
+ break;
+ case DEV_STATE_OFFLINE:
+@@ -267,6 +252,7 @@ ccw_device_recog_done(struct ccw_device
+ notify = 1;
+ }
+ /* fill out sense information */
++ memset(&cdev->id, 0, sizeof(cdev->id));
+ cdev->id.cu_type = cdev->private->senseid.cu_type;
+ cdev->id.cu_model = cdev->private->senseid.cu_model;
+ cdev->id.dev_type = cdev->private->senseid.dev_type;
+@@ -284,14 +270,15 @@ ccw_device_recog_done(struct ccw_device
+ CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: "
+ "CU Type/Mod = %04X/%02X, Dev Type/Mod = "
+ "%04X/%02X\n",
+- cdev->private->ssid, cdev->private->devno,
++ cdev->private->dev_id.ssid,
++ cdev->private->dev_id.devno,
+ cdev->id.cu_type, cdev->id.cu_model,
+ cdev->id.dev_type, cdev->id.dev_model);
+ break;
+ case DEV_STATE_BOXED:
+ CIO_DEBUG(KERN_WARNING, 2,
+ "SenseID : boxed device %04x on subchannel "
+- "0.%x.%04x\n", cdev->private->devno,
++ "0.%x.%04x\n", cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
+ break;
+ }
+@@ -327,13 +314,13 @@ ccw_device_oper_notify(void *data)
+ struct subchannel *sch;
+ int ret;
+
+- cdev = (struct ccw_device *)data;
++ cdev = data;
+ sch = to_subchannel(cdev->dev.parent);
+ ret = (sch->driver && sch->driver->notify) ?
+ sch->driver->notify(&sch->dev, CIO_OPER) : 0;
+ if (!ret)
+ /* Driver doesn't want device back. */
+- ccw_device_do_unreg_rereg((void *)cdev);
++ ccw_device_do_unreg_rereg(cdev);
+ else {
+ /* Reenable channel measurements, if needed. */
+ cmf_reenable(cdev);
+@@ -351,6 +338,8 @@ ccw_device_done(struct ccw_device *cdev,
+
+ sch = to_subchannel(cdev->dev.parent);
+
++ ccw_device_set_timeout(cdev, 0);
++
+ if (state != DEV_STATE_ONLINE)
+ cio_disable_subchannel(sch);
+
+@@ -363,12 +352,12 @@ ccw_device_done(struct ccw_device *cdev,
+ if (state == DEV_STATE_BOXED)
+ CIO_DEBUG(KERN_WARNING, 2,
+ "Boxed device %04x on subchannel %04x\n",
+- cdev->private->devno, sch->schid.sch_no);
++ cdev->private->dev_id.devno, sch->schid.sch_no);
+
+ if (cdev->private->flags.donotify) {
+ cdev->private->flags.donotify = 0;
+ PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify,
+- (void *)cdev);
++ cdev);
+ queue_work(ccw_device_notify_work, &cdev->private->kick_work);
+ }
+ wake_up(&cdev->private->wait_q);
+@@ -412,7 +401,8 @@ static void __ccw_device_get_common_pgid
+ /* PGID mismatch, can't pathgroup. */
+ CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
+ "0.%x.%04x, can't pathgroup\n",
+- cdev->private->ssid, cdev->private->devno);
++ cdev->private->dev_id.ssid,
++ cdev->private->dev_id.devno);
+ cdev->private->options.pgroup = 0;
+ return;
+ }
+@@ -454,8 +444,8 @@ ccw_device_sense_pgid_done(struct ccw_de
+ return;
+ }
+ /* Start Path Group verification. */
+- sch->vpm = 0; /* Start with no path groups set. */
+ cdev->private->state = DEV_STATE_VERIFY;
++ cdev->private->flags.doverify = 0;
+ ccw_device_verify_start(cdev);
+ }
+
+@@ -523,7 +513,7 @@ ccw_device_nopath_notify(void *data)
+ struct subchannel *sch;
+ int ret;
+
+- cdev = (struct ccw_device *)data;
++ cdev = data;
+ sch = to_subchannel(cdev->dev.parent);
+ /* Extra sanity. */
+ if (sch->lpm)
+@@ -537,7 +527,7 @@ ccw_device_nopath_notify(void *data)
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister,
+- (void *)cdev);
++ cdev);
+ queue_work(ccw_device_work,
+ &cdev->private->kick_work);
+ } else
+@@ -555,7 +545,19 @@ ccw_device_nopath_notify(void *data)
+ void
+ ccw_device_verify_done(struct ccw_device *cdev, int err)
+ {
+- cdev->private->flags.doverify = 0;
++ struct subchannel *sch;
++
++ sch = to_subchannel(cdev->dev.parent);
++ /* Update schib - pom may have changed. */
++ stsch(sch->schid, &sch->schib);
++ /* Update lpm with verified path mask. */
++ sch->lpm = sch->vpm;
++ /* Repeat path verification? */
++ if (cdev->private->flags.doverify) {
++ cdev->private->flags.doverify = 0;
++ ccw_device_verify_start(cdev);
++ return;
++ }
+ switch (err) {
+ case -EOPNOTSUPP: /* path grouping not supported, just set online. */
+ cdev->private->options.pgroup = 0;
+@@ -576,11 +578,15 @@ ccw_device_verify_done(struct ccw_device
+ }
+ break;
+ case -ETIME:
++ /* Reset oper notify indication after verify error. */
++ cdev->private->flags.donotify = 0;
+ ccw_device_done(cdev, DEV_STATE_BOXED);
+ break;
+ default:
++ /* Reset oper notify indication after verify error. */
++ cdev->private->flags.donotify = 0;
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
++ ccw_device_nopath_notify, cdev);
+ queue_work(ccw_device_notify_work, &cdev->private->kick_work);
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ break;
+@@ -613,6 +619,7 @@ ccw_device_online(struct ccw_device *cde
+ if (!cdev->private->options.pgroup) {
+ /* Start initial path verification. */
+ cdev->private->state = DEV_STATE_VERIFY;
++ cdev->private->flags.doverify = 0;
+ ccw_device_verify_start(cdev);
+ return 0;
+ }
+@@ -659,7 +666,6 @@ ccw_device_offline(struct ccw_device *cd
+ /* Are we doing path grouping? */
+ if (!cdev->private->options.pgroup) {
+ /* No, set state offline immediately. */
+- sch->vpm = 0;
+ ccw_device_done(cdev, DEV_STATE_OFFLINE);
+ return 0;
+ }
+@@ -711,7 +717,7 @@ ccw_device_offline_notoper(struct ccw_de
+ sch = to_subchannel(cdev->dev.parent);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_call_sch_unregister, (void *)cdev);
++ ccw_device_call_sch_unregister, cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ wake_up(&cdev->private->wait_q);
+@@ -742,7 +748,7 @@ ccw_device_online_notoper(struct ccw_dev
+ }
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_call_sch_unregister, (void *)cdev);
++ ccw_device_call_sch_unregister, cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ wake_up(&cdev->private->wait_q);
+@@ -780,6 +786,7 @@ ccw_device_online_verify(struct ccw_devi
+ }
+ /* Device is idle, we can do the path verification. */
+ cdev->private->state = DEV_STATE_VERIFY;
++ cdev->private->flags.doverify = 0;
+ ccw_device_verify_start(cdev);
+ }
+
+@@ -846,7 +853,7 @@ ccw_device_online_timeout(struct ccw_dev
+ sch = to_subchannel(cdev->dev.parent);
+ if (!sch->lpm) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
++ ccw_device_nopath_notify, cdev);
+ queue_work(ccw_device_notify_work,
+ &cdev->private->kick_work);
+ } else
+@@ -872,7 +879,8 @@ ccw_device_w4sense(struct ccw_device *cd
+ /* Basic sense hasn't started. Try again. */
+ ccw_device_do_sense(cdev, irb);
+ else {
+- printk("Huh? %s(%s): unsolicited interrupt...\n",
++ printk(KERN_INFO "Huh? %s(%s): unsolicited "
++ "interrupt...\n",
+ __FUNCTION__, cdev->dev.bus_id);
+ if (cdev->handler)
+ cdev->handler (cdev, 0, irb);
+@@ -931,10 +939,10 @@ ccw_device_killing_irq(struct ccw_device
+ cdev->private->state = DEV_STATE_ONLINE;
+ if (cdev->handler)
+ cdev->handler(cdev, cdev->private->intparm,
+- ERR_PTR(-ETIMEDOUT));
++ ERR_PTR(-EIO));
+ if (!sch->lpm) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
++ ccw_device_nopath_notify, cdev);
+ queue_work(ccw_device_notify_work, &cdev->private->kick_work);
+ } else if (cdev->private->flags.doverify)
+ /* Start delayed path verification. */
+@@ -957,7 +965,7 @@ ccw_device_killing_timeout(struct ccw_de
+ sch = to_subchannel(cdev->dev.parent);
+ if (!sch->lpm) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
++ ccw_device_nopath_notify, cdev);
+ queue_work(ccw_device_notify_work,
+ &cdev->private->kick_work);
+ } else
+@@ -968,51 +976,15 @@ ccw_device_killing_timeout(struct ccw_de
+ cdev->private->state = DEV_STATE_ONLINE;
+ if (cdev->handler)
+ cdev->handler(cdev, cdev->private->intparm,
+- ERR_PTR(-ETIMEDOUT));
++ ERR_PTR(-EIO));
+ }
+
+-static void
+-ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event)
+-{
+- struct irb *irb;
+- struct subchannel *sch;
+-
+- irb = (struct irb *) __LC_IRB;
+- /*
+- * Accumulate status and find out if a basic sense is needed.
+- * This is fine since we have already adapted the lpm.
+- */
+- ccw_device_accumulate_irb(cdev, irb);
+- if (cdev->private->flags.dosense) {
+- if (ccw_device_do_sense(cdev, irb) == 0) {
+- cdev->private->state = DEV_STATE_W4SENSE;
+- }
+- return;
+- }
+-
+- /* Iff device is idle, reset timeout. */
+- sch = to_subchannel(cdev->dev.parent);
+- if (!stsch(sch->schid, &sch->schib))
+- if (sch->schib.scsw.actl == 0)
+- ccw_device_set_timeout(cdev, 0);
+- /* Call the handler. */
+- ccw_device_call_handler(cdev);
+- if (!sch->lpm) {
+- PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
+- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
+- } else if (cdev->private->flags.doverify)
+- ccw_device_online_verify(cdev, 0);
+-}
+-
+-static void
+-ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
++void device_kill_io(struct subchannel *sch)
+ {
+ int ret;
+- struct subchannel *sch;
++ struct ccw_device *cdev;
+
+- sch = to_subchannel(cdev->dev.parent);
+- ccw_device_set_timeout(cdev, 0);
++ cdev = sch->dev.driver_data;
+ ret = ccw_device_cancel_halt_clear(cdev);
+ if (ret == -EBUSY) {
+ ccw_device_set_timeout(cdev, 3*HZ);
+@@ -1022,7 +994,7 @@ ccw_device_wait4io_timeout(struct ccw_de
+ if (ret == -ENODEV) {
+ if (!sch->lpm) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
++ ccw_device_nopath_notify, cdev);
+ queue_work(ccw_device_notify_work,
+ &cdev->private->kick_work);
+ } else
+@@ -1031,20 +1003,20 @@ ccw_device_wait4io_timeout(struct ccw_de
+ }
+ if (cdev->handler)
+ cdev->handler(cdev, cdev->private->intparm,
+- ERR_PTR(-ETIMEDOUT));
++ ERR_PTR(-EIO));
+ if (!sch->lpm) {
+ PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_nopath_notify, (void *)cdev);
++ ccw_device_nopath_notify, cdev);
+ queue_work(ccw_device_notify_work, &cdev->private->kick_work);
+- } else if (cdev->private->flags.doverify)
++ } else
+ /* Start delayed path verification. */
+ ccw_device_online_verify(cdev, 0);
+ }
+
+ static void
+-ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
++ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event)
+ {
+- /* When the I/O has terminated, we have to start verification. */
++ /* Start verification after current task finished. */
+ cdev->private->flags.doverify = 1;
+ }
+
+@@ -1110,10 +1082,7 @@ device_trigger_reprobe(struct subchannel
+ * The pim, pam, pom values may not be accurate, but they are the best
+ * we have before performing device selection :/
+ */
+- sch->lpm = sch->schib.pmcw.pim &
+- sch->schib.pmcw.pam &
+- sch->schib.pmcw.pom &
+- sch->opm;
++ sch->lpm = sch->schib.pmcw.pam & sch->opm;
+ /* Re-set some bits in the pmcw that were lost. */
+ sch->schib.pmcw.isc = 3;
+ sch->schib.pmcw.csense = 1;
+@@ -1237,7 +1206,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES]
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+- [DEV_EVENT_VERIFY] = ccw_device_nop,
++ [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
+ },
+ [DEV_STATE_ONLINE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+@@ -1276,12 +1245,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES]
+ [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
+ },
+- [DEV_STATE_WAIT4IO] = {
+- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+- [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq,
+- [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout,
+- [DEV_EVENT_VERIFY] = ccw_device_wait4io_verify,
+- },
+ [DEV_STATE_QUIESCE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done,
+ [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done,
+@@ -1293,7 +1256,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES]
+ [DEV_EVENT_NOTOPER] = ccw_device_nop,
+ [DEV_EVENT_INTERRUPT] = ccw_device_start_id,
+ [DEV_EVENT_TIMEOUT] = ccw_device_bug,
+- [DEV_EVENT_VERIFY] = ccw_device_nop,
++ [DEV_EVENT_VERIFY] = ccw_device_start_id,
+ },
+ [DEV_STATE_DISCONNECTED_SENSE_ID] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
+diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
+index 438db48..a74785b 100644
+--- a/drivers/s390/cio/device_id.c
++++ b/drivers/s390/cio/device_id.c
+@@ -42,18 +42,15 @@ diag210(struct diag210 * addr)
+ spin_lock_irqsave(&diag210_lock, flags);
+ diag210_tmp = *addr;
+
+- asm volatile (
+- " lhi %0,-1\n"
+- " sam31\n"
+- " diag %1,0,0x210\n"
+- "0: ipm %0\n"
+- " srl %0,28\n"
+- "1: sam64\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous"
+- : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory" );
++ asm volatile(
++ " lhi %0,-1\n"
++ " sam31\n"
++ " diag %1,0,0x210\n"
++ "0: ipm %0\n"
++ " srl %0,28\n"
++ "1: sam64\n"
++ EX_TABLE(0b,1b)
++ : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory");
+
+ *addr = diag210_tmp;
+ spin_unlock_irqrestore(&diag210_lock, flags);
+@@ -66,17 +63,14 @@ diag210(struct diag210 * addr)
+ {
+ int ccode;
+
+- asm volatile (
+- " lhi %0,-1\n"
+- " diag %1,0,0x210\n"
+- "0: ipm %0\n"
+- " srl %0,28\n"
++ asm volatile(
++ " lhi %0,-1\n"
++ " diag %1,0,0x210\n"
++ "0: ipm %0\n"
++ " srl %0,28\n"
+ "1:\n"
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous"
+- : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory" );
++ EX_TABLE(0b,1b)
++ : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory");
+
+ return ccode;
+ }
+@@ -257,7 +251,7 @@ ccw_device_check_sense_id(struct ccw_dev
+ */
+ CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel "
+ "0.%x.%04x reports cmd reject\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no);
+ return -EOPNOTSUPP;
+ }
+@@ -265,7 +259,8 @@ ccw_device_check_sense_id(struct ccw_dev
+ CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, "
+ "lpum %02X, cnt %02d, sns :"
+ " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+- cdev->private->ssid, cdev->private->devno,
++ cdev->private->dev_id.ssid,
++ cdev->private->dev_id.devno,
+ irb->esw.esw0.sublog.lpum,
+ irb->esw.esw0.erw.scnt,
+ irb->ecw[0], irb->ecw[1],
+@@ -280,14 +275,15 @@ ccw_device_check_sense_id(struct ccw_dev
+ CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
+ "on subchannel 0.%x.%04x is "
+ "'not operational'\n", sch->orb.lpm,
+- cdev->private->devno, sch->schid.ssid,
+- sch->schid.sch_no);
++ cdev->private->dev_id.devno,
++ sch->schid.ssid, sch->schid.sch_no);
+ return -EACCES;
+ }
+ /* Hmm, whatever happened, try again. */
+ CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
+ "subchannel 0.%x.%04x returns status %02X%02X\n",
+- cdev->private->devno, sch->schid.ssid, sch->schid.sch_no,
++ cdev->private->dev_id.devno, sch->schid.ssid,
++ sch->schid.sch_no,
+ irb->scsw.dstat, irb->scsw.cstat);
+ return -EAGAIN;
+ }
+@@ -336,7 +332,7 @@ ccw_device_sense_id_irq(struct ccw_devic
+ /* fall through. */
+ default: /* Sense ID failed. Try asking VM. */
+ if (MACHINE_IS_VM) {
+- VM_virtual_device_info (cdev->private->devno,
++ VM_virtual_device_info (cdev->private->dev_id.devno,
+ &cdev->private->senseid);
+ if (cdev->private->senseid.cu_type != 0xFFFF) {
+ /* Got the device information from VM. */
+diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
+index 9e3de0b..b39c1fa 100644
+--- a/drivers/s390/cio/device_ops.c
++++ b/drivers/s390/cio/device_ops.c
+@@ -50,7 +50,6 @@ ccw_device_clear(struct ccw_device *cdev
+ if (cdev->private->state == DEV_STATE_NOT_OPER)
+ return -ENODEV;
+ if (cdev->private->state != DEV_STATE_ONLINE &&
+- cdev->private->state != DEV_STATE_WAIT4IO &&
+ cdev->private->state != DEV_STATE_W4SENSE)
+ return -EINVAL;
+ sch = to_subchannel(cdev->dev.parent);
+@@ -96,6 +95,12 @@ ccw_device_start_key(struct ccw_device *
+ ret = cio_set_options (sch, flags);
+ if (ret)
+ return ret;
++ /* Adjust requested path mask to excluded varied off paths. */
++ if (lpm) {
++ lpm &= sch->opm;
++ if (lpm == 0)
++ return -EACCES;
++ }
+ ret = cio_start_key (sch, cpa, lpm, key);
+ if (ret == 0)
+ cdev->private->intparm = intparm;
+@@ -149,7 +154,6 @@ ccw_device_halt(struct ccw_device *cdev,
+ if (cdev->private->state == DEV_STATE_NOT_OPER)
+ return -ENODEV;
+ if (cdev->private->state != DEV_STATE_ONLINE &&
+- cdev->private->state != DEV_STATE_WAIT4IO &&
+ cdev->private->state != DEV_STATE_W4SENSE)
+ return -EINVAL;
+ sch = to_subchannel(cdev->dev.parent);
+@@ -210,6 +214,9 @@ ccw_device_call_handler(struct ccw_devic
+ (stctl & SCSW_STCTL_PRIM_STATUS)))
+ return 0;
+
++ /* Clear pending timers for device driver initiated I/O. */
++ if (ending_status)
++ ccw_device_set_timeout(cdev, 0);
+ /*
+ * Now we are ready to call the device driver interrupt handler.
+ */
+@@ -250,7 +257,7 @@ ccw_device_get_path_mask(struct ccw_devi
+ if (!sch)
+ return 0;
+ else
+- return sch->vpm;
++ return sch->lpm;
+ }
+
+ static void
+@@ -279,10 +286,10 @@ ccw_device_wake_up(struct ccw_device *cd
+ if (cdev->private->flags.doverify ||
+ cdev->private->state == DEV_STATE_VERIFY)
+ cdev->private->intparm = -EAGAIN;
+- if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+- !(irb->ecw[0] &
+- (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
+- cdev->private->intparm = -EAGAIN;
++ else if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
++ !(irb->ecw[0] &
++ (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
++ cdev->private->intparm = -EAGAIN;
+ else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
+ (irb->scsw.dstat & DEV_STAT_DEV_END) &&
+ (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
+@@ -303,8 +310,11 @@ __ccw_device_retry_loop(struct ccw_devic
+
+ sch = to_subchannel(cdev->dev.parent);
+ do {
++ ccw_device_set_timeout(cdev, 60 * HZ);
+ ret = cio_start (sch, ccw, lpm);
+- if ((ret == -EBUSY) || (ret == -EACCES)) {
++ if (ret != 0)
++ ccw_device_set_timeout(cdev, 0);
++ if (ret == -EBUSY) {
+ /* Try again later. */
+ spin_unlock_irq(&sch->lock);
+ msleep(10);
+@@ -433,6 +443,13 @@ read_conf_data_lpm (struct ccw_device *c
+ if (!ciw || ciw->cmd == 0)
+ return -EOPNOTSUPP;
+
++ /* Adjust requested path mask to excluded varied off paths. */
++ if (lpm) {
++ lpm &= sch->opm;
++ if (lpm == 0)
++ return -EACCES;
++ }
++
+ rcd_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+ if (!rcd_ccw)
+ return -ENOMEM;
+@@ -573,13 +590,13 @@ ccw_device_get_chp_desc(struct ccw_devic
+ int
+ _ccw_device_get_subchannel_number(struct ccw_device *cdev)
+ {
+- return cdev->private->sch_no;
++ return cdev->private->schid.sch_no;
+ }
+
+ int
+ _ccw_device_get_device_number(struct ccw_device *cdev)
+ {
+- return cdev->private->devno;
++ return cdev->private->dev_id.devno;
+ }
+
+
+diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
+index 1693a10..2975ce8 100644
+--- a/drivers/s390/cio/device_pgid.c
++++ b/drivers/s390/cio/device_pgid.c
+@@ -79,7 +79,8 @@ __ccw_device_sense_pgid_start(struct ccw
+ CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
+ "0.%x.%04x, lpm %02X, became 'not "
+ "operational'\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno,
++ sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+
+ }
+@@ -96,6 +97,9 @@ ccw_device_sense_pgid_start(struct ccw_d
+ {
+ int ret;
+
++ /* Set a timeout of 60s */
++ ccw_device_set_timeout(cdev, 60*HZ);
++
+ cdev->private->state = DEV_STATE_SENSE_PGID;
+ cdev->private->imask = 0x80;
+ cdev->private->iretry = 5;
+@@ -132,7 +136,8 @@ __ccw_device_check_sense_pgid(struct ccw
+ CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, "
+ "lpum %02X, cnt %02d, sns : "
+ "%02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+- cdev->private->ssid, cdev->private->devno,
++ cdev->private->dev_id.ssid,
++ cdev->private->dev_id.devno,
+ irb->esw.esw0.sublog.lpum,
+ irb->esw.esw0.erw.scnt,
+ irb->ecw[0], irb->ecw[1],
+@@ -144,7 +149,7 @@ __ccw_device_check_sense_pgid(struct ccw
+ if (irb->scsw.cc == 3) {
+ CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
+ " lpm %02X, became 'not operational'\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, sch->orb.lpm);
+ return -EACCES;
+ }
+@@ -152,7 +157,7 @@ __ccw_device_check_sense_pgid(struct ccw
+ if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
+ CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
+ "is reserved by someone else\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no);
+ return -EUSERS;
+ }
+@@ -245,21 +250,20 @@ __ccw_device_do_pgid(struct ccw_device *
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+
+ /* Try multiple times. */
+- ret = -ENODEV;
++ ret = -EACCES;
+ if (cdev->private->iretry > 0) {
+ cdev->private->iretry--;
+ ret = cio_start (sch, cdev->private->iccws,
+ cdev->private->imask);
+- /* ret is 0, -EBUSY, -EACCES or -ENODEV */
+- if ((ret != -EACCES) && (ret != -ENODEV))
++ /* We expect an interrupt in case of success or busy
++ * indication. */
++ if ((ret == 0) || (ret == -EBUSY))
+ return ret;
+ }
+- /* PGID command failed on this path. Switch it off. */
+- sch->lpm &= ~cdev->private->imask;
+- sch->vpm &= ~cdev->private->imask;
++ /* PGID command failed on this path. */
+ CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
+ "0.%x.%04x, lpm %02X, became 'not operational'\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return ret;
+ }
+@@ -286,21 +290,20 @@ static int __ccw_device_do_nop(struct cc
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+
+ /* Try multiple times. */
+- ret = -ENODEV;
++ ret = -EACCES;
+ if (cdev->private->iretry > 0) {
+ cdev->private->iretry--;
+ ret = cio_start (sch, cdev->private->iccws,
+ cdev->private->imask);
+- /* ret is 0, -EBUSY, -EACCES or -ENODEV */
+- if ((ret != -EACCES) && (ret != -ENODEV))
++ /* We expect an interrupt in case of success or busy
++ * indication. */
++ if ((ret == 0) || (ret == -EBUSY))
+ return ret;
+ }
+- /* nop command failed on this path. Switch it off. */
+- sch->lpm &= ~cdev->private->imask;
+- sch->vpm &= ~cdev->private->imask;
++ /* nop command failed on this path. */
+ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
+ "0.%x.%04x, lpm %02X, became 'not operational'\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return ret;
+ }
+@@ -327,8 +330,9 @@ __ccw_device_check_pgid(struct ccw_devic
+ CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
+ "cnt %02d, "
+ "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+- cdev->private->ssid,
+- cdev->private->devno, irb->esw.esw0.erw.scnt,
++ cdev->private->dev_id.ssid,
++ cdev->private->dev_id.devno,
++ irb->esw.esw0.erw.scnt,
+ irb->ecw[0], irb->ecw[1],
+ irb->ecw[2], irb->ecw[3],
+ irb->ecw[4], irb->ecw[5],
+@@ -338,7 +342,7 @@ __ccw_device_check_pgid(struct ccw_devic
+ if (irb->scsw.cc == 3) {
+ CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x,"
+ " lpm %02X, became 'not operational'\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return -EACCES;
+ }
+@@ -361,7 +365,7 @@ static int __ccw_device_check_nop(struct
+ if (irb->scsw.cc == 3) {
+ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
+ " lpm %02X, became 'not operational'\n",
+- cdev->private->devno, sch->schid.ssid,
++ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return -EACCES;
+ }
+@@ -372,27 +376,32 @@ static void
+ __ccw_device_verify_start(struct ccw_device *cdev)
+ {
+ struct subchannel *sch;
+- __u8 imask, func;
++ __u8 func;
+ int ret;
+
+ sch = to_subchannel(cdev->dev.parent);
+- while (sch->vpm != sch->lpm) {
+- /* Find first unequal bit in vpm vs. lpm */
+- for (imask = 0x80; imask != 0; imask >>= 1)
+- if ((sch->vpm & imask) != (sch->lpm & imask))
+- break;
+- cdev->private->imask = imask;
++ /* Repeat for all paths. */
++ for (; cdev->private->imask; cdev->private->imask >>= 1,
++ cdev->private->iretry = 5) {
++ if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
++ /* Path not available, try next. */
++ continue;
+ if (cdev->private->options.pgroup) {
+- func = (sch->vpm & imask) ?
+- SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH;
++ if (sch->opm & cdev->private->imask)
++ func = SPID_FUNC_ESTABLISH;
++ else
++ func = SPID_FUNC_RESIGN;
+ ret = __ccw_device_do_pgid(cdev, func);
+ } else
+ ret = __ccw_device_do_nop(cdev);
++ /* We expect an interrupt in case of success or busy
++ * indication. */
+ if (ret == 0 || ret == -EBUSY)
+ return;
+- cdev->private->iretry = 5;
++ /* Permanent path failure, try next. */
+ }
+- ccw_device_verify_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);
++ /* Done with all paths. */
++ ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
+ }
+
+ /*
+@@ -421,14 +430,14 @@ ccw_device_verify_irq(struct ccw_device
+ else
+ ret = __ccw_device_check_nop(cdev);
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
++
+ switch (ret) {
+ /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
+ case 0:
+- /* Establish or Resign Path Group done. Update vpm. */
+- if ((sch->lpm & cdev->private->imask) != 0)
+- sch->vpm |= cdev->private->imask;
+- else
+- sch->vpm &= ~cdev->private->imask;
++ /* Path verification ccw finished successfully, update lpm. */
++ sch->vpm |= sch->opm & cdev->private->imask;
++ /* Go on with next path. */
++ cdev->private->imask >>= 1;
+ cdev->private->iretry = 5;
+ __ccw_device_verify_start(cdev);
+ break;
+@@ -441,6 +450,10 @@ ccw_device_verify_irq(struct ccw_device
+ cdev->private->options.pgroup = 0;
+ else
+ cdev->private->flags.pgid_single = 1;
++ /* Retry */
++ sch->vpm = 0;
++ cdev->private->imask = 0x80;
++ cdev->private->iretry = 5;
+ /* fall through. */
+ case -EAGAIN: /* Try again. */
+ __ccw_device_verify_start(cdev);
+@@ -449,8 +462,7 @@ ccw_device_verify_irq(struct ccw_device
+ ccw_device_verify_done(cdev, -ETIME);
+ break;
+ case -EACCES: /* channel is not operational. */
+- sch->lpm &= ~cdev->private->imask;
+- sch->vpm &= ~cdev->private->imask;
++ cdev->private->imask >>= 1;
+ cdev->private->iretry = 5;
+ __ccw_device_verify_start(cdev);
+ break;
+@@ -463,19 +475,19 @@ ccw_device_verify_start(struct ccw_devic
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+ cdev->private->flags.pgid_single = 0;
++ cdev->private->imask = 0x80;
+ cdev->private->iretry = 5;
+- /*
+- * Update sch->lpm with current values to catch paths becoming
+- * available again.
+- */
++
++ /* Start with empty vpm. */
++ sch->vpm = 0;
++
++ /* Get current pam. */
+ if (stsch(sch->schid, &sch->schib)) {
+ ccw_device_verify_done(cdev, -ENODEV);
+ return;
+ }
+- sch->lpm = sch->schib.pmcw.pim &
+- sch->schib.pmcw.pam &
+- sch->schib.pmcw.pom &
+- sch->opm;
++ /* After 60s path verification is considered to have failed. */
++ ccw_device_set_timeout(cdev, 60*HZ);
+ __ccw_device_verify_start(cdev);
+ }
+
+@@ -524,7 +536,6 @@ ccw_device_disband_irq(struct ccw_device
+ switch (ret) {
+ /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
+ case 0: /* disband successful. */
+- sch->vpm = 0;
+ ccw_device_disband_done(cdev, ret);
+ break;
+ case -EOPNOTSUPP:
+@@ -551,6 +562,9 @@ ccw_device_disband_irq(struct ccw_device
+ void
+ ccw_device_disband_start(struct ccw_device *cdev)
+ {
++ /* After 60s disbanding is considered to have failed. */
++ ccw_device_set_timeout(cdev, 60*HZ);
++
+ cdev->private->flags.pgid_single = 0;
+ cdev->private->iretry = 5;
+ cdev->private->imask = 0x80;
+diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
+index caf148d..3f7cbce 100644
+--- a/drivers/s390/cio/device_status.c
++++ b/drivers/s390/cio/device_status.c
+@@ -32,19 +32,18 @@ ccw_device_msg_control_check(struct ccw_
+ SCHN_STAT_CHN_CTRL_CHK |
+ SCHN_STAT_INTF_CTRL_CHK)))
+ return;
+-
+ CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
+ "received"
+ " ... device %04x on subchannel 0.%x.%04x, dev_stat "
+ ": %02X sch_stat : %02X\n",
+- cdev->private->devno, cdev->private->ssid,
+- cdev->private->sch_no,
++ cdev->private->dev_id.devno, cdev->private->schid.ssid,
++ cdev->private->schid.sch_no,
+ irb->scsw.dstat, irb->scsw.cstat);
+
+ if (irb->scsw.cc != 3) {
+ char dbf_text[15];
+
+- sprintf(dbf_text, "chk%x", cdev->private->sch_no);
++ sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no);
+ CIO_TRACE_EVENT(0, dbf_text);
+ CIO_HEX_EVENT(0, irb, sizeof (struct irb));
+ }
+diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
+index 95a9462..ad6d829 100644
+--- a/drivers/s390/cio/ioasm.h
++++ b/drivers/s390/cio/ioasm.h
+@@ -25,106 +25,74 @@ struct tpi_info {
+ static inline int stsch(struct subchannel_id schid,
+ volatile struct schib *addr)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " stsch 0(%2)\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid), "a" (addr), "m" (*addr)
+- : "cc", "1" );
++ asm volatile(
++ " stsch 0(%2)\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+ static inline int stsch_err(struct subchannel_id schid,
+ volatile struct schib *addr)
+ {
+- int ccode;
++ register struct subchannel_id reg1 asm ("1") = schid;
++ int ccode = -EIO;
+
+- __asm__ __volatile__(
+- " lhi %0,%3\n"
+- " lr 1,%1\n"
+- " stsch 0(%2)\n"
+- "0: ipm %0\n"
+- " srl %0,28\n"
++ asm volatile(
++ " stsch 0(%2)\n"
++ "0: ipm %0\n"
++ " srl %0,28\n"
+ "1:\n"
+-#ifdef CONFIG_64BIT
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous"
+-#else
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous"
+-#endif
+- : "=&d" (ccode)
+- : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
+- : "cc", "1" );
++ EX_TABLE(0b,1b)
++ : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+ static inline int msch(struct subchannel_id schid,
+ volatile struct schib *addr)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " msch 0(%2)\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid), "a" (addr), "m" (*addr)
+- : "cc", "1" );
++ asm volatile(
++ " msch 0(%2)\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+ static inline int msch_err(struct subchannel_id schid,
+ volatile struct schib *addr)
+ {
+- int ccode;
++ register struct subchannel_id reg1 asm ("1") = schid;
++ int ccode = -EIO;
+
+- __asm__ __volatile__(
+- " lhi %0,%3\n"
+- " lr 1,%1\n"
+- " msch 0(%2)\n"
+- "0: ipm %0\n"
+- " srl %0,28\n"
++ asm volatile(
++ " msch 0(%2)\n"
++ "0: ipm %0\n"
++ " srl %0,28\n"
+ "1:\n"
+-#ifdef CONFIG_64BIT
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous"
+-#else
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous"
+-#endif
+- : "=&d" (ccode)
+- : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
+- : "cc", "1" );
++ EX_TABLE(0b,1b)
++ : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+ static inline int tsch(struct subchannel_id schid,
+ volatile struct irb *addr)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " tsch 0(%2)\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid), "a" (addr), "m" (*addr)
+- : "cc", "1" );
++ asm volatile(
++ " tsch 0(%2)\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+@@ -132,89 +100,77 @@ static inline int tpi( volatile struct t
+ {
+ int ccode;
+
+- __asm__ __volatile__(
+- " tpi 0(%1)\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "a" (addr), "m" (*addr)
+- : "cc", "1" );
++ asm volatile(
++ " tpi 0(%1)\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+ static inline int ssch(struct subchannel_id schid,
+ volatile struct orb *addr)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " ssch 0(%2)\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid), "a" (addr), "m" (*addr)
+- : "cc", "1" );
++ asm volatile(
++ " ssch 0(%2)\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ return ccode;
+ }
+
+ static inline int rsch(struct subchannel_id schid)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " rsch\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid)
+- : "cc", "1" );
++ asm volatile(
++ " rsch\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1) : "cc");
+ return ccode;
+ }
+
+ static inline int csch(struct subchannel_id schid)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " csch\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid)
+- : "cc", "1" );
++ asm volatile(
++ " csch\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1) : "cc");
+ return ccode;
+ }
+
+ static inline int hsch(struct subchannel_id schid)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " hsch\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid)
+- : "cc", "1" );
++ asm volatile(
++ " hsch\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1) : "cc");
+ return ccode;
+ }
+
+ static inline int xsch(struct subchannel_id schid)
+ {
++ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " .insn rre,0xb2760000,%1,0\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (schid)
+- : "cc", "1" );
++ asm volatile(
++ " .insn rre,0xb2760000,%1,0\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1) : "cc");
+ return ccode;
+ }
+
+@@ -223,41 +179,27 @@ static inline int chsc(void *chsc_area)
+ typedef struct { char _[4096]; } addr_type;
+ int cc;
+
+- __asm__ __volatile__ (
+- ".insn rre,0xb25f0000,%2,0 \n\t"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
++ asm volatile(
++ " .insn rre,0xb25f0000,%2,0\n"
++ " ipm %0\n"
++ " srl %0,28\n"
+ : "=d" (cc), "=m" (*(addr_type *) chsc_area)
+ : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
+- : "cc" );
+-
++ : "cc");
+ return cc;
+ }
+
+-static inline int iac( void)
+-{
+- int ccode;
+-
+- __asm__ __volatile__(
+- " iac 1\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode) : : "cc", "1" );
+- return ccode;
+-}
+-
+ static inline int rchp(int chpid)
+ {
++ register unsigned int reg1 asm ("1") = chpid;
+ int ccode;
+
+- __asm__ __volatile__(
+- " lr 1,%1\n"
+- " rchp\n"
+- " ipm %0\n"
+- " srl %0,28"
+- : "=d" (ccode)
+- : "d" (chpid)
+- : "cc", "1" );
++ asm volatile(
++ " lr 1,%1\n"
++ " rchp\n"
++ " ipm %0\n"
++ " srl %0,28"
++ : "=d" (ccode) : "d" (reg1) : "cc");
+ return ccode;
+ }
+
+diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
+index 7c93a87..476aa1d 100644
+--- a/drivers/s390/cio/qdio.c
++++ b/drivers/s390/cio/qdio.c
+@@ -115,7 +115,7 @@ qdio_min(int a,int b)
+ static inline __u64
+ qdio_get_micros(void)
+ {
+- return (get_clock() >> 10); /* time>>12 is microseconds */
++ return (get_clock() >> 12); /* time>>12 is microseconds */
+ }
+
+ /*
+@@ -1129,7 +1129,7 @@ out:
+
+ #ifdef QDIO_USE_PROCESSING_STATE
+ if (last_position>=0)
+- set_slsb(q, &last_position, SLSB_P_INPUT_NOT_INIT, &count);
++ set_slsb(q, &last_position, SLSB_P_INPUT_PROCESSING, &count);
+ #endif /* QDIO_USE_PROCESSING_STATE */
+
+ QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
+@@ -1741,7 +1741,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, s
+ void *ptr;
+ int available;
+
+- sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no);
++ sprintf(dbf_text,"qfqs%4x",cdev->private->schid.sch_no);
+ QDIO_DBF_TEXT0(0,setup,dbf_text);
+ for (i=0;i<no_input_qs;i++) {
+ q=irq_ptr->input_qs[i];
+@@ -2924,7 +2924,7 @@ qdio_establish_handle_irq(struct ccw_dev
+
+ irq_ptr = cdev->private->qdio_data;
+
+- sprintf(dbf_text,"qehi%4x",cdev->private->sch_no);
++ sprintf(dbf_text,"qehi%4x",cdev->private->schid.sch_no);
+ QDIO_DBF_TEXT0(0,setup,dbf_text);
+ QDIO_DBF_TEXT0(0,trace,dbf_text);
+
+@@ -2943,7 +2943,7 @@ qdio_initialize(struct qdio_initialize *
+ int rc;
+ char dbf_text[15];
+
+- sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no);
++ sprintf(dbf_text,"qini%4x",init_data->cdev->private->schid.sch_no);
+ QDIO_DBF_TEXT0(0,setup,dbf_text);
+ QDIO_DBF_TEXT0(0,trace,dbf_text);
+
+@@ -2964,7 +2964,7 @@ qdio_allocate(struct qdio_initialize *in
+ struct qdio_irq *irq_ptr;
+ char dbf_text[15];
+
+- sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no);
++ sprintf(dbf_text,"qalc%4x",init_data->cdev->private->schid.sch_no);
+ QDIO_DBF_TEXT0(0,setup,dbf_text);
+ QDIO_DBF_TEXT0(0,trace,dbf_text);
+ if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
+@@ -3187,7 +3187,7 @@ qdio_establish(struct qdio_initialize *i
+ tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
+ }
+
+- sprintf(dbf_text,"qest%4x",cdev->private->sch_no);
++ sprintf(dbf_text,"qest%4x",cdev->private->schid.sch_no);
+ QDIO_DBF_TEXT0(0,setup,dbf_text);
+ QDIO_DBF_TEXT0(0,trace,dbf_text);
+
+@@ -3529,7 +3529,7 @@ do_QDIO(struct ccw_device *cdev,unsigned
+ #ifdef CONFIG_QDIO_DEBUG
+ char dbf_text[20];
+
+- sprintf(dbf_text,"doQD%04x",cdev->private->sch_no);
++ sprintf(dbf_text,"doQD%04x",cdev->private->schid.sch_no);
+ QDIO_DBF_TEXT3(0,trace,dbf_text);
+ #endif /* CONFIG_QDIO_DEBUG */
+
+diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
+index ceb3ab3..49bb9e3 100644
+--- a/drivers/s390/cio/qdio.h
++++ b/drivers/s390/cio/qdio.h
+@@ -191,49 +191,49 @@ enum qdio_irq_states {
+ #if QDIO_VERBOSE_LEVEL>8
+ #define QDIO_PRINT_STUPID(x...) printk( KERN_DEBUG QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_STUPID(x...)
++#define QDIO_PRINT_STUPID(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>7
+ #define QDIO_PRINT_ALL(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_ALL(x...)
++#define QDIO_PRINT_ALL(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>6
+ #define QDIO_PRINT_INFO(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_INFO(x...)
++#define QDIO_PRINT_INFO(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>5
+ #define QDIO_PRINT_WARN(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_WARN(x...)
++#define QDIO_PRINT_WARN(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>4
+ #define QDIO_PRINT_ERR(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_ERR(x...)
++#define QDIO_PRINT_ERR(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>3
+ #define QDIO_PRINT_CRIT(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_CRIT(x...)
++#define QDIO_PRINT_CRIT(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>2
+ #define QDIO_PRINT_ALERT(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_ALERT(x...)
++#define QDIO_PRINT_ALERT(x...) do { } while (0)
+ #endif
+
+ #if QDIO_VERBOSE_LEVEL>1
+ #define QDIO_PRINT_EMERG(x...) printk( QDIO_PRINTK_HEADER x)
+ #else
+-#define QDIO_PRINT_EMERG(x...)
++#define QDIO_PRINT_EMERG(x...) do { } while (0)
+ #endif
+
+ #define HEXDUMP16(importance,header,ptr) \
+@@ -274,12 +274,11 @@ do_sqbs(unsigned long sch, unsigned char
+ register unsigned long _sch asm ("1") = sch;
+ unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
+
+- asm volatile (
+- " .insn rsy,0xeb000000008A,%1,0,0(%2)\n\t"
+- : "+d" (_ccq), "+d" (_queuestart)
+- : "d" ((unsigned long)state), "d" (_sch)
+- : "memory", "cc"
+- );
++ asm volatile(
++ " .insn rsy,0xeb000000008A,%1,0,0(%2)"
++ : "+d" (_ccq), "+d" (_queuestart)
++ : "d" ((unsigned long)state), "d" (_sch)
++ : "memory", "cc");
+ *count = _ccq & 0xff;
+ *start = _queuestart & 0xff;
+
+@@ -299,12 +298,11 @@ do_eqbs(unsigned long sch, unsigned char
+ unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
+ unsigned long _state = 0;
+
+- asm volatile (
+- " .insn rrf,0xB99c0000,%1,%2,0,0 \n\t"
+- : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
+- : "d" (_sch)
+- : "memory", "cc"
+- );
++ asm volatile(
++ " .insn rrf,0xB99c0000,%1,%2,0,0"
++ : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
++ : "d" (_sch)
++ : "memory", "cc" );
+ *count = _ccq & 0xff;
+ *start = _queuestart & 0xff;
+ *state = _state & 0xff;
+@@ -319,69 +317,35 @@ do_eqbs(unsigned long sch, unsigned char
+ static inline int
+ do_siga_sync(struct subchannel_id schid, unsigned int mask1, unsigned int mask2)
+ {
++ register unsigned long reg0 asm ("0") = 2;
++ register struct subchannel_id reg1 asm ("1") = schid;
++ register unsigned long reg2 asm ("2") = mask1;
++ register unsigned long reg3 asm ("3") = mask2;
+ int cc;
+
+-#ifndef CONFIG_64BIT
+- asm volatile (
+- "lhi 0,2 \n\t"
+- "lr 1,%1 \n\t"
+- "lr 2,%2 \n\t"
+- "lr 3,%3 \n\t"
+- "siga 0 \n\t"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
++ asm volatile(
++ " siga 0\n"
++ " ipm %0\n"
++ " srl %0,28\n"
+ : "=d" (cc)
+- : "d" (schid), "d" (mask1), "d" (mask2)
+- : "cc", "0", "1", "2", "3"
+- );
+-#else /* CONFIG_64BIT */
+- asm volatile (
+- "lghi 0,2 \n\t"
+- "llgfr 1,%1 \n\t"
+- "llgfr 2,%2 \n\t"
+- "llgfr 3,%3 \n\t"
+- "siga 0 \n\t"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
+- : "=d" (cc)
+- : "d" (schid), "d" (mask1), "d" (mask2)
+- : "cc", "0", "1", "2", "3"
+- );
+-#endif /* CONFIG_64BIT */
++ : "d" (reg0), "d" (reg1), "d" (reg2), "d" (reg3) : "cc");
+ return cc;
+ }
+
+ static inline int
+ do_siga_input(struct subchannel_id schid, unsigned int mask)
+ {
++ register unsigned long reg0 asm ("0") = 1;
++ register struct subchannel_id reg1 asm ("1") = schid;
++ register unsigned long reg2 asm ("2") = mask;
+ int cc;
+
+-#ifndef CONFIG_64BIT
+- asm volatile (
+- "lhi 0,1 \n\t"
+- "lr 1,%1 \n\t"
+- "lr 2,%2 \n\t"
+- "siga 0 \n\t"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
+- : "=d" (cc)
+- : "d" (schid), "d" (mask)
+- : "cc", "0", "1", "2", "memory"
+- );
+-#else /* CONFIG_64BIT */
+- asm volatile (
+- "lghi 0,1 \n\t"
+- "llgfr 1,%1 \n\t"
+- "llgfr 2,%2 \n\t"
+- "siga 0 \n\t"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
++ asm volatile(
++ " siga 0\n"
++ " ipm %0\n"
++ " srl %0,28\n"
+ : "=d" (cc)
+- : "d" (schid), "d" (mask)
+- : "cc", "0", "1", "2", "memory"
+- );
+-#endif /* CONFIG_64BIT */
+-
++ : "d" (reg0), "d" (reg1), "d" (reg2) : "cc", "memory");
+ return cc;
+ }
+
+@@ -389,93 +353,35 @@ static inline int
+ do_siga_output(unsigned long schid, unsigned long mask, __u32 *bb,
+ unsigned int fc)
+ {
++ register unsigned long __fc asm("0") = fc;
++ register unsigned long __schid asm("1") = schid;
++ register unsigned long __mask asm("2") = mask;
+ int cc;
+- __u32 busy_bit;
+-
+-#ifndef CONFIG_64BIT
+- asm volatile (
+- "lhi 0,0 \n\t"
+- "lr 1,%2 \n\t"
+- "lr 2,%3 \n\t"
+- "siga 0 \n\t"
+- "0:"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
+- "srl 0,31 \n\t"
+- "lr %1,0 \n\t"
+- "1: \n\t"
+- ".section .fixup,\"ax\"\n\t"
+- "2: \n\t"
+- "lhi %0,%4 \n\t"
+- "bras 1,3f \n\t"
+- ".long 1b \n\t"
+- "3: \n\t"
+- "l 1,0(1) \n\t"
+- "br 1 \n\t"
+- ".previous \n\t"
+- ".section __ex_table,\"a\"\n\t"
+- ".align 4 \n\t"
+- ".long 0b,2b \n\t"
+- ".previous \n\t"
+- : "=d" (cc), "=d" (busy_bit)
+- : "d" (schid), "d" (mask),
+- "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
+- : "cc", "0", "1", "2", "memory"
+- );
+-#else /* CONFIG_64BIT */
+- asm volatile (
+- "llgfr 0,%5 \n\t"
+- "lgr 1,%2 \n\t"
+- "llgfr 2,%3 \n\t"
+- "siga 0 \n\t"
+- "0:"
+- "ipm %0 \n\t"
+- "srl %0,28 \n\t"
+- "srl 0,31 \n\t"
+- "llgfr %1,0 \n\t"
+- "1: \n\t"
+- ".section .fixup,\"ax\"\n\t"
+- "lghi %0,%4 \n\t"
+- "jg 1b \n\t"
+- ".previous\n\t"
+- ".section __ex_table,\"a\"\n\t"
+- ".align 8 \n\t"
+- ".quad 0b,1b \n\t"
+- ".previous \n\t"
+- : "=d" (cc), "=d" (busy_bit)
+- : "d" (schid), "d" (mask),
+- "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc)
+- : "cc", "0", "1", "2", "memory"
+- );
+-#endif /* CONFIG_64BIT */
+-
+- (*bb) = busy_bit;
++
++ asm volatile(
++ " siga 0\n"
++ "0: ipm %0\n"
++ " srl %0,28\n"
++ "1:\n"
++ EX_TABLE(0b,1b)
++ : "=d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask)
++ : "0" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
++ : "cc", "memory");
++ (*bb) = ((unsigned int) __fc) >> 31;
+ return cc;
+ }
+
+ static inline unsigned long
+ do_clear_global_summary(void)
+ {
+-
+- unsigned long time;
+-
+-#ifndef CONFIG_64BIT
+- asm volatile (
+- "lhi 1,3 \n\t"
+- ".insn rre,0xb2650000,2,0 \n\t"
+- "lr %0,3 \n\t"
+- : "=d" (time) : : "cc", "1", "2", "3"
+- );
+-#else /* CONFIG_64BIT */
+- asm volatile (
+- "lghi 1,3 \n\t"
+- ".insn rre,0xb2650000,2,0 \n\t"
+- "lgr %0,3 \n\t"
+- : "=d" (time) : : "cc", "1", "2", "3"
+- );
+-#endif /* CONFIG_64BIT */
+-
+- return time;
++ register unsigned long __fn asm("1") = 3;
++ register unsigned long __tmp asm("2");
++ register unsigned long __time asm("3");
++
++ asm volatile(
++ " .insn rre,0xb2650000,2,0"
++ : "+d" (__fn), "=d" (__tmp), "=d" (__time));
++ return __time;
+ }
+
+ /*
+diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
+index 15edebb..f0a12d2 100644
+--- a/drivers/s390/crypto/Makefile
++++ b/drivers/s390/crypto/Makefile
+@@ -2,5 +2,16 @@
+ # S/390 crypto devices
+ #
+
+-z90crypt-objs := z90main.o z90hardware.o
+-obj-$(CONFIG_Z90CRYPT) += z90crypt.o
++ifdef CONFIG_ZCRYPT_MONOLITHIC
++
++z90crypt-objs := zcrypt_mono.o ap_bus.o zcrypt_api.o \
++ zcrypt_pcica.o zcrypt_pcicc.o zcrypt_pcixcc.o zcrypt_cex2a.o
++obj-$(CONFIG_ZCRYPT) += z90crypt.o
++
++else
++
++ap-objs := ap_bus.o
++obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o
++obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o
++
++endif
+diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
+new file mode 100644
+index 0000000..79d89c3
+--- /dev/null
++++ b/drivers/s390/crypto/ap_bus.c
+@@ -0,0 +1,1227 @@
++/*
++ * linux/drivers/s390/crypto/ap_bus.c
++ *
++ * Copyright (C) 2006 IBM Corporation
++ * Author(s): Cornelia Huck <cornelia.huck at de.ibm.com>
++ * Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.ibm.com>
++ *
++ * Adjunct processor bus.
++ *
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/notifier.h>
++#include <linux/kthread.h>
++#include <linux/mutex.h>
++#include <asm/s390_rdev.h>
++
++#include "ap_bus.h"
++
++/* Some prototypes. */
++static void ap_scan_bus(void *);
++static void ap_poll_all(unsigned long);
++static void ap_poll_timeout(unsigned long);
++static int ap_poll_thread_start(void);
++static void ap_poll_thread_stop(void);
++
++/**
++ * Module description.
++ */
++MODULE_AUTHOR("IBM Corporation");
++MODULE_DESCRIPTION("Adjunct Processor Bus driver, "
++ "Copyright 2006 IBM Corporation");
++MODULE_LICENSE("GPL");
++
++/**
++ * Module parameter
++ */
++int ap_domain_index = -1; /* Adjunct Processor Domain Index */
++module_param_named(domain, ap_domain_index, int, 0000);
++MODULE_PARM_DESC(domain, "domain index for ap devices");
++EXPORT_SYMBOL(ap_domain_index);
++
++static int ap_thread_flag = 1;
++module_param_named(poll_thread, ap_thread_flag, int, 0000);
++MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 1 (on).");
++
++static struct device *ap_root_device = NULL;
++
++/**
++ * Workqueue & timer for bus rescan.
++ */
++static struct workqueue_struct *ap_work_queue;
++static struct timer_list ap_config_timer;
++static int ap_config_time = AP_CONFIG_TIME;
++static DECLARE_WORK(ap_config_work, ap_scan_bus, NULL);
++
++/**
++ * Tasklet & timer for AP request polling.
++ */
++static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0);
++static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
++static atomic_t ap_poll_requests = ATOMIC_INIT(0);
++static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
++static struct task_struct *ap_poll_kthread = NULL;
++static DEFINE_MUTEX(ap_poll_thread_mutex);
++
++/**
++ * Test if ap instructions are available.
++ *
++ * Returns 0 if the ap instructions are installed.
++ */
++static inline int ap_instructions_available(void)
++{
++ register unsigned long reg0 asm ("0") = AP_MKQID(0,0);
++ register unsigned long reg1 asm ("1") = -ENODEV;
++ register unsigned long reg2 asm ("2") = 0UL;
++
++ asm volatile(
++ " .long 0xb2af0000\n" /* PQAP(TAPQ) */
++ "0: la %1,0\n"
++ "1:\n"
++ EX_TABLE(0b, 1b)
++ : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" );
++ return reg1;
++}
++
++/**
++ * Test adjunct processor queue.
++ * @qid: the ap queue number
++ * @queue_depth: pointer to queue depth value
++ * @device_type: pointer to device type value
++ *
++ * Returns ap queue status structure.
++ */
++static inline struct ap_queue_status
++ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
++{
++ register unsigned long reg0 asm ("0") = qid;
++ register struct ap_queue_status reg1 asm ("1");
++ register unsigned long reg2 asm ("2") = 0UL;
++
++ asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
++ : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
++ *device_type = (int) (reg2 >> 24);
++ *queue_depth = (int) (reg2 & 0xff);
++ return reg1;
++}
++
++/**
++ * Reset adjunct processor queue.
++ * @qid: the ap queue number
++ *
++ * Returns ap queue status structure.
++ */
++static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid)
++{
++ register unsigned long reg0 asm ("0") = qid | 0x01000000UL;
++ register struct ap_queue_status reg1 asm ("1");
++ register unsigned long reg2 asm ("2") = 0UL;
++
++ asm volatile(
++ ".long 0xb2af0000" /* PQAP(RAPQ) */
++ : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
++ return reg1;
++}
++
++/**
++ * Send message to adjunct processor queue.
++ * @qid: the ap queue number
++ * @psmid: the program supplied message identifier
++ * @msg: the message text
++ * @length: the message length
++ *
++ * Returns ap queue status structure.
++ *
++ * Condition code 1 on NQAP can't happen because the L bit is 1.
++ *
++ * Condition code 2 on NQAP also means the send is incomplete,
++ * because a segment boundary was reached. The NQAP is repeated.
++ */
++static inline struct ap_queue_status
++__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
++{
++ typedef struct { char _[length]; } msgblock;
++ register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
++ register struct ap_queue_status reg1 asm ("1");
++ register unsigned long reg2 asm ("2") = (unsigned long) msg;
++ register unsigned long reg3 asm ("3") = (unsigned long) length;
++ register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
++ register unsigned long reg5 asm ("5") = (unsigned int) psmid;
++
++ asm volatile (
++ "0: .long 0xb2ad0042\n" /* DQAP */
++ " brc 2,0b"
++ : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
++ : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg)
++ : "cc" );
++ return reg1;
++}
++
++int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
++{
++ struct ap_queue_status status;
++
++ status = __ap_send(qid, psmid, msg, length);
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ return 0;
++ case AP_RESPONSE_Q_FULL:
++ return -EBUSY;
++ default: /* Device is gone. */
++ return -ENODEV;
++ }
++}
++EXPORT_SYMBOL(ap_send);
++
++/*
++ * Receive message from adjunct processor queue.
++ * @qid: the ap queue number
++ * @psmid: pointer to program supplied message identifier
++ * @msg: the message text
++ * @length: the message length
++ *
++ * Returns ap queue status structure.
++ *
++ * Condition code 1 on DQAP means the receive has taken place
++ * but only partially. The response is incomplete, hence the
++ * DQAP is repeated.
++ *
++ * Condition code 2 on DQAP also means the receive is incomplete,
++ * this time because a segment boundary was reached. Again, the
++ * DQAP is repeated.
++ *
++ * Note that gpr2 is used by the DQAP instruction to keep track of
++ * any 'residual' length, in case the instruction gets interrupted.
++ * Hence it gets zeroed before the instruction.
++ */
++static inline struct ap_queue_status
++__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
++{
++ typedef struct { char _[length]; } msgblock;
++ register unsigned long reg0 asm("0") = qid | 0x80000000UL;
++ register struct ap_queue_status reg1 asm ("1");
++ register unsigned long reg2 asm("2") = 0UL;
++ register unsigned long reg4 asm("4") = (unsigned long) msg;
++ register unsigned long reg5 asm("5") = (unsigned long) length;
++ register unsigned long reg6 asm("6") = 0UL;
++ register unsigned long reg7 asm("7") = 0UL;
++
++
++ asm volatile(
++ "0: .long 0xb2ae0064\n"
++ " brc 6,0b\n"
++ : "+d" (reg0), "=d" (reg1), "+d" (reg2),
++ "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
++ "=m" (*(msgblock *) msg) : : "cc" );
++ *psmid = (((unsigned long long) reg6) << 32) + reg7;
++ return reg1;
++}
++
++int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
++{
++ struct ap_queue_status status;
++
++ status = __ap_recv(qid, psmid, msg, length);
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ return 0;
++ case AP_RESPONSE_NO_PENDING_REPLY:
++ if (status.queue_empty)
++ return -ENOENT;
++ return -EBUSY;
++ default:
++ return -ENODEV;
++ }
++}
++EXPORT_SYMBOL(ap_recv);
++
++/**
++ * Check if an AP queue is available. The test is repeated for
++ * AP_MAX_RESET times.
++ * @qid: the ap queue number
++ * @queue_depth: pointer to queue depth value
++ * @device_type: pointer to device type value
++ */
++static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type)
++{
++ struct ap_queue_status status;
++ int t_depth, t_device_type, rc, i;
++
++ rc = -EBUSY;
++ for (i = 0; i < AP_MAX_RESET; i++) {
++ status = ap_test_queue(qid, &t_depth, &t_device_type);
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ *queue_depth = t_depth + 1;
++ *device_type = t_device_type;
++ rc = 0;
++ break;
++ case AP_RESPONSE_Q_NOT_AVAIL:
++ rc = -ENODEV;
++ break;
++ case AP_RESPONSE_RESET_IN_PROGRESS:
++ break;
++ case AP_RESPONSE_DECONFIGURED:
++ rc = -ENODEV;
++ break;
++ case AP_RESPONSE_CHECKSTOPPED:
++ rc = -ENODEV;
++ break;
++ case AP_RESPONSE_BUSY:
++ break;
++ default:
++ BUG();
++ }
++ if (rc != -EBUSY)
++ break;
++ if (i < AP_MAX_RESET - 1)
++ udelay(5);
++ }
++ return rc;
++}
++
++/**
++ * Reset an AP queue and wait for it to become available again.
++ * @qid: the ap queue number
++ */
++static int ap_init_queue(ap_qid_t qid)
++{
++ struct ap_queue_status status;
++ int rc, dummy, i;
++
++ rc = -ENODEV;
++ status = ap_reset_queue(qid);
++ for (i = 0; i < AP_MAX_RESET; i++) {
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ if (status.queue_empty)
++ rc = 0;
++ break;
++ case AP_RESPONSE_Q_NOT_AVAIL:
++ case AP_RESPONSE_DECONFIGURED:
++ case AP_RESPONSE_CHECKSTOPPED:
++ i = AP_MAX_RESET; /* return with -ENODEV */
++ break;
++ case AP_RESPONSE_RESET_IN_PROGRESS:
++ case AP_RESPONSE_BUSY:
++ default:
++ break;
++ }
++ if (rc != -ENODEV)
++ break;
++ if (i < AP_MAX_RESET - 1) {
++ udelay(5);
++ status = ap_test_queue(qid, &dummy, &dummy);
++ }
++ }
++ return rc;
++}
++
++/**
++ * AP device related attributes.
++ */
++static ssize_t ap_hwtype_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type);
++}
++static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
++
++static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth);
++}
++static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
++
++static ssize_t ap_request_count_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ int rc;
++
++ spin_lock_bh(&ap_dev->lock);
++ rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count);
++ spin_unlock_bh(&ap_dev->lock);
++ return rc;
++}
++
++static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
++
++static ssize_t ap_modalias_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "ap:t%02X", to_ap_dev(dev)->device_type);
++}
++
++static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
++
++static struct attribute *ap_dev_attrs[] = {
++ &dev_attr_hwtype.attr,
++ &dev_attr_depth.attr,
++ &dev_attr_request_count.attr,
++ &dev_attr_modalias.attr,
++ NULL
++};
++static struct attribute_group ap_dev_attr_group = {
++ .attrs = ap_dev_attrs
++};
++
++/**
++ * AP bus driver registration/unregistration.
++ */
++static int ap_bus_match(struct device *dev, struct device_driver *drv)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ struct ap_driver *ap_drv = to_ap_drv(drv);
++ struct ap_device_id *id;
++
++ /**
++ * Compare device type of the device with the list of
++ * supported types of the device_driver.
++ */
++ for (id = ap_drv->ids; id->match_flags; id++) {
++ if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) &&
++ (id->dev_type != ap_dev->device_type))
++ continue;
++ return 1;
++ }
++ return 0;
++}
++
++/**
++ * uevent function for AP devices. It sets up a single environment
++ * variable DEV_TYPE which contains the hardware device type.
++ */
++static int ap_uevent (struct device *dev, char **envp, int num_envp,
++ char *buffer, int buffer_size)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ int length;
++
++ if (!ap_dev)
++ return -ENODEV;
++
++ /* Set up DEV_TYPE environment variable. */
++ envp[0] = buffer;
++ length = scnprintf(buffer, buffer_size, "DEV_TYPE=%04X",
++ ap_dev->device_type);
++ if (buffer_size - length <= 0)
++ return -ENOMEM;
++ envp[1] = 0;
++ return 0;
++}
++
++static struct bus_type ap_bus_type = {
++ .name = "ap",
++ .match = &ap_bus_match,
++ .uevent = &ap_uevent,
++};
++
++static int ap_device_probe(struct device *dev)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ struct ap_driver *ap_drv = to_ap_drv(dev->driver);
++ int rc;
++
++ ap_dev->drv = ap_drv;
++ rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
++ return rc;
++}
++
++/**
++ * Flush all requests from the request/pending queue of an AP device.
++ * @ap_dev: pointer to the AP device.
++ */
++static inline void __ap_flush_queue(struct ap_device *ap_dev)
++{
++ struct ap_message *ap_msg, *next;
++
++ list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {
++ list_del_init(&ap_msg->list);
++ ap_dev->pendingq_count--;
++ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
++ }
++ list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {
++ list_del_init(&ap_msg->list);
++ ap_dev->requestq_count--;
++ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
++ }
++}
++
++void ap_flush_queue(struct ap_device *ap_dev)
++{
++ spin_lock_bh(&ap_dev->lock);
++ __ap_flush_queue(ap_dev);
++ spin_unlock_bh(&ap_dev->lock);
++}
++EXPORT_SYMBOL(ap_flush_queue);
++
++static int ap_device_remove(struct device *dev)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ struct ap_driver *ap_drv = ap_dev->drv;
++
++ ap_flush_queue(ap_dev);
++ if (ap_drv->remove)
++ ap_drv->remove(ap_dev);
++ return 0;
++}
++
++int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
++ char *name)
++{
++ struct device_driver *drv = &ap_drv->driver;
++
++ drv->bus = &ap_bus_type;
++ drv->probe = ap_device_probe;
++ drv->remove = ap_device_remove;
++ drv->owner = owner;
++ drv->name = name;
++ return driver_register(drv);
++}
++EXPORT_SYMBOL(ap_driver_register);
++
++void ap_driver_unregister(struct ap_driver *ap_drv)
++{
++ driver_unregister(&ap_drv->driver);
++}
++EXPORT_SYMBOL(ap_driver_unregister);
++
++/**
++ * AP bus attributes.
++ */
++static ssize_t ap_domain_show(struct bus_type *bus, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index);
++}
++
++static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL);
++
++static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
++}
++
++static ssize_t ap_config_time_store(struct bus_type *bus,
++ const char *buf, size_t count)
++{
++ int time;
++
++ if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120)
++ return -EINVAL;
++ ap_config_time = time;
++ if (!timer_pending(&ap_config_timer) ||
++ !mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ)) {
++ ap_config_timer.expires = jiffies + ap_config_time * HZ;
++ add_timer(&ap_config_timer);
++ }
++ return count;
++}
++
++static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store);
++
++static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0);
++}
++
++static ssize_t ap_poll_thread_store(struct bus_type *bus,
++ const char *buf, size_t count)
++{
++ int flag, rc;
++
++ if (sscanf(buf, "%d\n", &flag) != 1)
++ return -EINVAL;
++ if (flag) {
++ rc = ap_poll_thread_start();
++ if (rc)
++ return rc;
++ }
++ else
++ ap_poll_thread_stop();
++ return count;
++}
++
++static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store);
++
++static struct bus_attribute *const ap_bus_attrs[] = {
++ &bus_attr_ap_domain,
++ &bus_attr_config_time,
++ &bus_attr_poll_thread,
++ NULL
++};
++
++/**
++ * Pick one of the 16 ap domains.
++ */
++static inline int ap_select_domain(void)
++{
++ int queue_depth, device_type, count, max_count, best_domain;
++ int rc, i, j;
++
++ /**
++ * We want to use a single domain. Either the one specified with
++ * the "domain=" parameter or the domain with the maximum number
++ * of devices.
++ */
++ if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS)
++ /* Domain has already been selected. */
++ return 0;
++ best_domain = -1;
++ max_count = 0;
++ for (i = 0; i < AP_DOMAINS; i++) {
++ count = 0;
++ for (j = 0; j < AP_DEVICES; j++) {
++ ap_qid_t qid = AP_MKQID(j, i);
++ rc = ap_query_queue(qid, &queue_depth, &device_type);
++ if (rc)
++ continue;
++ count++;
++ }
++ if (count > max_count) {
++ max_count = count;
++ best_domain = i;
++ }
++ }
++ if (best_domain >= 0){
++ ap_domain_index = best_domain;
++ return 0;
++ }
++ return -ENODEV;
++}
++
++/**
++ * Find the device type if query queue returned a device type of 0.
++ * @ap_dev: pointer to the AP device.
++ */
++static int ap_probe_device_type(struct ap_device *ap_dev)
++{
++ static unsigned char msg[] = {
++ 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x01,0x00,0x43,0x43,0x41,0x2d,0x41,0x50,
++ 0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,
++ 0x00,0x00,0x00,0x00,0x50,0x4b,0x00,0x00,
++ 0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x54,0x32,0x01,0x00,0xa0,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0xb8,0x05,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
++ 0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20,
++ 0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,
++ 0x2d,0x31,0x2e,0x32,0x37,0x00,0x11,0x22,
++ 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
++ 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
++ 0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
++ 0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
++ 0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,
++ 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
++ 0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,
++ 0x88,0x1e,0x00,0x00,0x57,0x00,0x00,0x00,
++ 0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,
++ 0x03,0x02,0x00,0x00,0x40,0x01,0x00,0x01,
++ 0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,
++ 0xf6,0xd2,0x7b,0x58,0x4b,0xf9,0x28,0x68,
++ 0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,
++ 0x63,0x42,0xef,0xf8,0xfd,0xa4,0xf8,0xb0,
++ 0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,
++ 0x53,0x8c,0x6f,0x4e,0x72,0x8f,0x6c,0x04,
++ 0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,
++ 0xf7,0xdd,0xfd,0x4f,0x11,0x36,0x95,0x5d,
++ };
++ struct ap_queue_status status;
++ unsigned long long psmid;
++ char *reply;
++ int rc, i;
++
++ reply = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!reply) {
++ rc = -ENOMEM;
++ goto out;
++ }
++
++ status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
++ msg, sizeof(msg));
++ if (status.response_code != AP_RESPONSE_NORMAL) {
++ rc = -ENODEV;
++ goto out_free;
++ }
++
++ /* Wait for the test message to complete. */
++ for (i = 0; i < 6; i++) {
++ mdelay(300);
++ status = __ap_recv(ap_dev->qid, &psmid, reply, 4096);
++ if (status.response_code == AP_RESPONSE_NORMAL &&
++ psmid == 0x0102030405060708ULL)
++ break;
++ }
++ if (i < 6) {
++ /* Got an answer. */
++ if (reply[0] == 0x00 && reply[1] == 0x86)
++ ap_dev->device_type = AP_DEVICE_TYPE_PCICC;
++ else
++ ap_dev->device_type = AP_DEVICE_TYPE_PCICA;
++ rc = 0;
++ } else
++ rc = -ENODEV;
++
++out_free:
++ free_page((unsigned long) reply);
++out:
++ return rc;
++}
++
++/**
++ * Scan the ap bus for new devices.
++ */
++static int __ap_scan_bus(struct device *dev, void *data)
++{
++ return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data;
++}
++
++static void ap_device_release(struct device *dev)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++
++ kfree(ap_dev);
++}
++
++static void ap_scan_bus(void *data)
++{
++ struct ap_device *ap_dev;
++ struct device *dev;
++ ap_qid_t qid;
++ int queue_depth, device_type;
++ int rc, i;
++
++ if (ap_select_domain() != 0)
++ return;
++ for (i = 0; i < AP_DEVICES; i++) {
++ qid = AP_MKQID(i, ap_domain_index);
++ dev = bus_find_device(&ap_bus_type, NULL,
++ (void *)(unsigned long)qid,
++ __ap_scan_bus);
++ rc = ap_query_queue(qid, &queue_depth, &device_type);
++ if (dev && rc) {
++ put_device(dev);
++ device_unregister(dev);
++ continue;
++ }
++ if (dev) {
++ put_device(dev);
++ continue;
++ }
++ if (rc)
++ continue;
++ rc = ap_init_queue(qid);
++ if (rc)
++ continue;
++ ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);
++ if (!ap_dev)
++ break;
++ ap_dev->qid = qid;
++ ap_dev->queue_depth = queue_depth;
++ ap_dev->unregistered = 1;
++ spin_lock_init(&ap_dev->lock);
++ INIT_LIST_HEAD(&ap_dev->pendingq);
++ INIT_LIST_HEAD(&ap_dev->requestq);
++ if (device_type == 0)
++ ap_probe_device_type(ap_dev);
++ else
++ ap_dev->device_type = device_type;
++
++ ap_dev->device.bus = &ap_bus_type;
++ ap_dev->device.parent = ap_root_device;
++ snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x",
++ AP_QID_DEVICE(ap_dev->qid));
++ ap_dev->device.release = ap_device_release;
++ rc = device_register(&ap_dev->device);
++ if (rc) {
++ kfree(ap_dev);
++ continue;
++ }
++ /* Add device attributes. */
++ rc = sysfs_create_group(&ap_dev->device.kobj,
++ &ap_dev_attr_group);
++ if (!rc) {
++ spin_lock_bh(&ap_dev->lock);
++ ap_dev->unregistered = 0;
++ spin_unlock_bh(&ap_dev->lock);
++ }
++ else
++ device_unregister(&ap_dev->device);
++ }
++}
++
++static void
++ap_config_timeout(unsigned long ptr)
++{
++ queue_work(ap_work_queue, &ap_config_work);
++ ap_config_timer.expires = jiffies + ap_config_time * HZ;
++ add_timer(&ap_config_timer);
++}
++
++/**
++ * Set up the timer to run the poll tasklet
++ */
++static inline void ap_schedule_poll_timer(void)
++{
++ if (timer_pending(&ap_poll_timer))
++ return;
++ mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME);
++}
++
++/**
++ * Receive pending reply messages from an AP device.
++ * @ap_dev: pointer to the AP device
++ * @flags: pointer to control flags, bit 2^0 is set if another poll is
++ * required, bit 2^1 is set if the poll timer needs to get armed
++ * Returns 0 if the device is still present, -ENODEV if not.
++ */
++static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
++{
++ struct ap_queue_status status;
++ struct ap_message *ap_msg;
++
++ if (ap_dev->queue_count <= 0)
++ return 0;
++ status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid,
++ ap_dev->reply->message, ap_dev->reply->length);
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ atomic_dec(&ap_poll_requests);
++ ap_dev->queue_count--;
++ list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {
++ if (ap_msg->psmid != ap_dev->reply->psmid)
++ continue;
++ list_del_init(&ap_msg->list);
++ ap_dev->pendingq_count--;
++ ap_dev->drv->receive(ap_dev, ap_msg, ap_dev->reply);
++ break;
++ }
++ if (ap_dev->queue_count > 0)
++ *flags |= 1;
++ break;
++ case AP_RESPONSE_NO_PENDING_REPLY:
++ if (status.queue_empty) {
++ /* The card shouldn't forget requests but who knows. */
++ ap_dev->queue_count = 0;
++ list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
++ ap_dev->requestq_count += ap_dev->pendingq_count;
++ ap_dev->pendingq_count = 0;
++ } else
++ *flags |= 2;
++ break;
++ default:
++ return -ENODEV;
++ }
++ return 0;
++}
++
++/**
++ * Send messages from the request queue to an AP device.
++ * @ap_dev: pointer to the AP device
++ * @flags: pointer to control flags, bit 2^0 is set if another poll is
++ * required, bit 2^1 is set if the poll timer needs to get armed
++ * Returns 0 if the device is still present, -ENODEV if not.
++ */
++static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
++{
++ struct ap_queue_status status;
++ struct ap_message *ap_msg;
++
++ if (ap_dev->requestq_count <= 0 ||
++ ap_dev->queue_count >= ap_dev->queue_depth)
++ return 0;
++ /* Start the next request on the queue. */
++ ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
++ status = __ap_send(ap_dev->qid, ap_msg->psmid,
++ ap_msg->message, ap_msg->length);
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ atomic_inc(&ap_poll_requests);
++ ap_dev->queue_count++;
++ list_move_tail(&ap_msg->list, &ap_dev->pendingq);
++ ap_dev->requestq_count--;
++ ap_dev->pendingq_count++;
++ if (ap_dev->queue_count < ap_dev->queue_depth &&
++ ap_dev->requestq_count > 0)
++ *flags |= 1;
++ *flags |= 2;
++ break;
++ case AP_RESPONSE_Q_FULL:
++ *flags |= 2;
++ break;
++ case AP_RESPONSE_MESSAGE_TOO_BIG:
++ return -EINVAL;
++ default:
++ return -ENODEV;
++ }
++ return 0;
++}
++
++/**
++ * Poll AP device for pending replies and send new messages. If either
++ * ap_poll_read or ap_poll_write returns -ENODEV unregister the device.
++ * @ap_dev: pointer to the bus device
++ * @flags: pointer to control flags, bit 2^0 is set if another poll is
++ * required, bit 2^1 is set if the poll timer needs to get armed
++ * Returns 0.
++ */
++static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags)
++{
++ int rc;
++
++ rc = ap_poll_read(ap_dev, flags);
++ if (rc)
++ return rc;
++ return ap_poll_write(ap_dev, flags);
++}
++
++/**
++ * Queue a message to a device.
++ * @ap_dev: pointer to the AP device
++ * @ap_msg: the message to be queued
++ */
++static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
++{
++ struct ap_queue_status status;
++
++ if (list_empty(&ap_dev->requestq) &&
++ ap_dev->queue_count < ap_dev->queue_depth) {
++ status = __ap_send(ap_dev->qid, ap_msg->psmid,
++ ap_msg->message, ap_msg->length);
++ switch (status.response_code) {
++ case AP_RESPONSE_NORMAL:
++ list_add_tail(&ap_msg->list, &ap_dev->pendingq);
++ atomic_inc(&ap_poll_requests);
++ ap_dev->pendingq_count++;
++ ap_dev->queue_count++;
++ ap_dev->total_request_count++;
++ break;
++ case AP_RESPONSE_Q_FULL:
++ list_add_tail(&ap_msg->list, &ap_dev->requestq);
++ ap_dev->requestq_count++;
++ ap_dev->total_request_count++;
++ return -EBUSY;
++ case AP_RESPONSE_MESSAGE_TOO_BIG:
++ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
++ return -EINVAL;
++ default: /* Device is gone. */
++ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
++ return -ENODEV;
++ }
++ } else {
++ list_add_tail(&ap_msg->list, &ap_dev->requestq);
++ ap_dev->requestq_count++;
++ ap_dev->total_request_count++;
++ return -EBUSY;
++ }
++ ap_schedule_poll_timer();
++ return 0;
++}
++
++void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
++{
++ unsigned long flags;
++ int rc;
++
++ spin_lock_bh(&ap_dev->lock);
++ if (!ap_dev->unregistered) {
++ /* Make room on the queue by polling for finished requests. */
++ rc = ap_poll_queue(ap_dev, &flags);
++ if (!rc)
++ rc = __ap_queue_message(ap_dev, ap_msg);
++ if (!rc)
++ wake_up(&ap_poll_wait);
++ if (rc == -ENODEV)
++ ap_dev->unregistered = 1;
++ } else {
++ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
++ rc = 0;
++ }
++ spin_unlock_bh(&ap_dev->lock);
++ if (rc == -ENODEV)
++ device_unregister(&ap_dev->device);
++}
++EXPORT_SYMBOL(ap_queue_message);
++
++/**
++ * Cancel a crypto request. This is done by removing the request
++ * from the devive pendingq or requestq queue. Note that the
++ * request stays on the AP queue. When it finishes the message
++ * reply will be discarded because the psmid can't be found.
++ * @ap_dev: AP device that has the message queued
++ * @ap_msg: the message that is to be removed
++ */
++void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
++{
++ struct ap_message *tmp;
++
++ spin_lock_bh(&ap_dev->lock);
++ if (!list_empty(&ap_msg->list)) {
++ list_for_each_entry(tmp, &ap_dev->pendingq, list)
++ if (tmp->psmid == ap_msg->psmid) {
++ ap_dev->pendingq_count--;
++ goto found;
++ }
++ ap_dev->requestq_count--;
++ found:
++ list_del_init(&ap_msg->list);
++ }
++ spin_unlock_bh(&ap_dev->lock);
++}
++EXPORT_SYMBOL(ap_cancel_message);
++
++/**
++ * AP receive polling for finished AP requests
++ */
++static void ap_poll_timeout(unsigned long unused)
++{
++ tasklet_schedule(&ap_tasklet);
++}
++
++/**
++ * Poll all AP devices on the bus in a round robin fashion. Continue
++ * polling until bit 2^0 of the control flags is not set. If bit 2^1
++ * of the control flags has been set arm the poll timer.
++ */
++static int __ap_poll_all(struct device *dev, void *data)
++{
++ struct ap_device *ap_dev = to_ap_dev(dev);
++ int rc;
++
++ spin_lock(&ap_dev->lock);
++ if (!ap_dev->unregistered) {
++ rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data);
++ if (rc)
++ ap_dev->unregistered = 1;
++ } else
++ rc = 0;
++ spin_unlock(&ap_dev->lock);
++ if (rc)
++ device_unregister(&ap_dev->device);
++ return 0;
++}
++
++static void ap_poll_all(unsigned long dummy)
++{
++ unsigned long flags;
++
++ do {
++ flags = 0;
++ bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
++ } while (flags & 1);
++ if (flags & 2)
++ ap_schedule_poll_timer();
++}
++
++/**
++ * AP bus poll thread. The purpose of this thread is to poll for
++ * finished requests in a loop if there is a "free" cpu - that is
++ * a cpu that doesn't have anything better to do. The polling stops
++ * as soon as there is another task or if all messages have been
++ * delivered.
++ */
++static int ap_poll_thread(void *data)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ unsigned long flags;
++ int requests;
++
++ set_user_nice(current, 19);
++ while (1) {
++ if (need_resched()) {
++ schedule();
++ continue;
++ }
++ add_wait_queue(&ap_poll_wait, &wait);
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (kthread_should_stop())
++ break;
++ requests = atomic_read(&ap_poll_requests);
++ if (requests <= 0)
++ schedule();
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&ap_poll_wait, &wait);
++
++ local_bh_disable();
++ flags = 0;
++ bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
++ local_bh_enable();
++ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&ap_poll_wait, &wait);
++ return 0;
++}
++
++static int ap_poll_thread_start(void)
++{
++ int rc;
++
++ mutex_lock(&ap_poll_thread_mutex);
++ if (!ap_poll_kthread) {
++ ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
++ rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0;
++ if (rc)
++ ap_poll_kthread = NULL;
++ }
++ else
++ rc = 0;
++ mutex_unlock(&ap_poll_thread_mutex);
++ return rc;
++}
++
++static void ap_poll_thread_stop(void)
++{
++ mutex_lock(&ap_poll_thread_mutex);
++ if (ap_poll_kthread) {
++ kthread_stop(ap_poll_kthread);
++ ap_poll_kthread = NULL;
++ }
++ mutex_unlock(&ap_poll_thread_mutex);
++}
++
++/**
++ * The module initialization code.
++ */
++int __init ap_module_init(void)
++{
++ int rc, i;
++
++ if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) {
++ printk(KERN_WARNING "Invalid param: domain = %d. "
++ " Not loading.\n", ap_domain_index);
++ return -EINVAL;
++ }
++ if (ap_instructions_available() != 0) {
++ printk(KERN_WARNING "AP instructions not installed.\n");
++ return -ENODEV;
++ }
++
++ /* Create /sys/bus/ap. */
++ rc = bus_register(&ap_bus_type);
++ if (rc)
++ goto out;
++ for (i = 0; ap_bus_attrs[i]; i++) {
++ rc = bus_create_file(&ap_bus_type, ap_bus_attrs[i]);
++ if (rc)
++ goto out_bus;
++ }
++
++ /* Create /sys/devices/ap. */
++ ap_root_device = s390_root_dev_register("ap");
++ rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0;
++ if (rc)
++ goto out_bus;
++
++ ap_work_queue = create_singlethread_workqueue("kapwork");
++ if (!ap_work_queue) {
++ rc = -ENOMEM;
++ goto out_root;
++ }
++
++ if (ap_select_domain() == 0)
++ ap_scan_bus(NULL);
++
++ /* Setup the ap bus rescan timer. */
++ init_timer(&ap_config_timer);
++ ap_config_timer.function = ap_config_timeout;
++ ap_config_timer.data = 0;
++ ap_config_timer.expires = jiffies + ap_config_time * HZ;
++ add_timer(&ap_config_timer);
++
++ /* Start the low priority AP bus poll thread. */
++ if (ap_thread_flag) {
++ rc = ap_poll_thread_start();
++ if (rc)
++ goto out_work;
++ }
++
++ return 0;
++
++out_work:
++ del_timer_sync(&ap_config_timer);
++ del_timer_sync(&ap_poll_timer);
++ destroy_workqueue(ap_work_queue);
++out_root:
++ s390_root_dev_unregister(ap_root_device);
++out_bus:
++ while (i--)
++ bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
++ bus_unregister(&ap_bus_type);
++out:
++ return rc;
++}
++
++static int __ap_match_all(struct device *dev, void *data)
++{
++ return 1;
++}
++
++/**
++ * The module termination code
++ */
++void ap_module_exit(void)
++{
++ int i;
++ struct device *dev;
++
++ ap_poll_thread_stop();
++ del_timer_sync(&ap_config_timer);
++ del_timer_sync(&ap_poll_timer);
++ destroy_workqueue(ap_work_queue);
++ s390_root_dev_unregister(ap_root_device);
++ while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
++ __ap_match_all)))
++ {
++ device_unregister(dev);
++ put_device(dev);
++ }
++ for (i = 0; ap_bus_attrs[i]; i++)
++ bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
++ bus_unregister(&ap_bus_type);
++}
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++module_init(ap_module_init);
++module_exit(ap_module_exit);
++#endif
+diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
+new file mode 100644
+index 0000000..83b69c0
+--- /dev/null
++++ b/drivers/s390/crypto/ap_bus.h
+@@ -0,0 +1,158 @@
++/*
++ * linux/drivers/s390/crypto/ap_bus.h
++ *
++ * Copyright (C) 2006 IBM Corporation
++ * Author(s): Cornelia Huck <cornelia.huck at de.ibm.com>
++ * Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.ibm.com>
++ *
++ * Adjunct processor bus header file.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, 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 _AP_BUS_H_
++#define _AP_BUS_H_
++
++#include <linux/device.h>
++#include <linux/mod_devicetable.h>
++#include <linux/types.h>
++
++#define AP_DEVICES 64 /* Number of AP devices. */
++#define AP_DOMAINS 16 /* Number of AP domains. */
++#define AP_MAX_RESET 90 /* Maximum number of resets. */
++#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
++#define AP_POLL_TIME 1 /* Time in ticks between receive polls. */
++
++extern int ap_domain_index;
++
++/**
++ * The ap_qid_t identifier of an ap queue. It contains a
++ * 6 bit device index and a 4 bit queue index (domain).
++ */
++typedef unsigned int ap_qid_t;
++
++#define AP_MKQID(_device,_queue) (((_device) & 63) << 8 | ((_queue) & 15))
++#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
++#define AP_QID_QUEUE(_qid) ((_qid) & 15)
++
++/**
++ * The ap queue status word is returned by all three AP functions
++ * (PQAP, NQAP and DQAP). There's a set of flags in the first
++ * byte, followed by a 1 byte response code.
++ */
++struct ap_queue_status {
++ unsigned int queue_empty : 1;
++ unsigned int replies_waiting : 1;
++ unsigned int queue_full : 1;
++ unsigned int pad1 : 5;
++ unsigned int response_code : 8;
++ unsigned int pad2 : 16;
++};
++
++#define AP_RESPONSE_NORMAL 0x00
++#define AP_RESPONSE_Q_NOT_AVAIL 0x01
++#define AP_RESPONSE_RESET_IN_PROGRESS 0x02
++#define AP_RESPONSE_DECONFIGURED 0x03
++#define AP_RESPONSE_CHECKSTOPPED 0x04
++#define AP_RESPONSE_BUSY 0x05
++#define AP_RESPONSE_Q_FULL 0x10
++#define AP_RESPONSE_NO_PENDING_REPLY 0x10
++#define AP_RESPONSE_INDEX_TOO_BIG 0x11
++#define AP_RESPONSE_NO_FIRST_PART 0x13
++#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
++
++/**
++ * Known device types
++ */
++#define AP_DEVICE_TYPE_PCICC 3
++#define AP_DEVICE_TYPE_PCICA 4
++#define AP_DEVICE_TYPE_PCIXCC 5
++#define AP_DEVICE_TYPE_CEX2A 6
++#define AP_DEVICE_TYPE_CEX2C 7
++
++struct ap_device;
++struct ap_message;
++
++struct ap_driver {
++ struct device_driver driver;
++ struct ap_device_id *ids;
++
++ int (*probe)(struct ap_device *);
++ void (*remove)(struct ap_device *);
++ /* receive is called from tasklet context */
++ void (*receive)(struct ap_device *, struct ap_message *,
++ struct ap_message *);
++};
++
++#define to_ap_drv(x) container_of((x), struct ap_driver, driver)
++
++int ap_driver_register(struct ap_driver *, struct module *, char *);
++void ap_driver_unregister(struct ap_driver *);
++
++struct ap_device {
++ struct device device;
++ struct ap_driver *drv; /* Pointer to AP device driver. */
++ spinlock_t lock; /* Per device lock. */
++
++ ap_qid_t qid; /* AP queue id. */
++ int queue_depth; /* AP queue depth.*/
++ int device_type; /* AP device type. */
++ int unregistered; /* marks AP device as unregistered */
++
++ int queue_count; /* # messages currently on AP queue. */
++
++ struct list_head pendingq; /* List of message sent to AP queue. */
++ int pendingq_count; /* # requests on pendingq list. */
++ struct list_head requestq; /* List of message yet to be sent. */
++ int requestq_count; /* # requests on requestq list. */
++ int total_request_count; /* # requests ever for this AP device. */
++
++ struct ap_message *reply; /* Per device reply message. */
++
++ void *private; /* ap driver private pointer. */
++};
++
++#define to_ap_dev(x) container_of((x), struct ap_device, device)
++
++struct ap_message {
++ struct list_head list; /* Request queueing. */
++ unsigned long long psmid; /* Message id. */
++ void *message; /* Pointer to message buffer. */
++ size_t length; /* Message length. */
++
++ void *private; /* ap driver private pointer. */
++};
++
++#define AP_DEVICE(dt) \
++ .dev_type=(dt), \
++ .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
++
++/**
++ * Note: don't use ap_send/ap_recv after using ap_queue_message
++ * for the first time. Otherwise the ap message queue will get
++ * confused.
++ */
++int ap_send(ap_qid_t, unsigned long long, void *, size_t);
++int ap_recv(ap_qid_t, unsigned long long *, void *, size_t);
++
++void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
++void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
++void ap_flush_queue(struct ap_device *ap_dev);
++
++int ap_module_init(void);
++void ap_module_exit(void);
++
++#endif /* _AP_BUS_H_ */
+diff --git a/drivers/s390/crypto/z90common.h b/drivers/s390/crypto/z90common.h
+deleted file mode 100644
+index dbbcda3..0000000
+--- a/drivers/s390/crypto/z90common.h
++++ /dev/null
+@@ -1,166 +0,0 @@
+-/*
+- * linux/drivers/s390/crypto/z90common.h
+- *
+- * z90crypt 1.3.3
+- *
+- * Copyright (C) 2001, 2005 IBM Corporation
+- * Author(s): Robert Burroughs (burrough at us.ibm.com)
+- * Eric Rossman (edrossma at us.ibm.com)
+- *
+- * Hotplug & misc device support: Jochen Roehrig (roehrig at de.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, 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 _Z90COMMON_H_
+-#define _Z90COMMON_H_
+-
+-
+-#define RESPBUFFSIZE 256
+-#define PCI_FUNC_KEY_DECRYPT 0x5044
+-#define PCI_FUNC_KEY_ENCRYPT 0x504B
+-extern int ext_bitlens;
+-
+-enum devstat {
+- DEV_GONE,
+- DEV_ONLINE,
+- DEV_QUEUE_FULL,
+- DEV_EMPTY,
+- DEV_NO_WORK,
+- DEV_BAD_MESSAGE,
+- DEV_TSQ_EXCEPTION,
+- DEV_RSQ_EXCEPTION,
+- DEV_SEN_EXCEPTION,
+- DEV_REC_EXCEPTION
+-};
+-
+-enum hdstat {
+- HD_NOT_THERE,
+- HD_BUSY,
+- HD_DECONFIGURED,
+- HD_CHECKSTOPPED,
+- HD_ONLINE,
+- HD_TSQ_EXCEPTION
+-};
+-
+-#define Z90C_NO_DEVICES 1
+-#define Z90C_AMBIGUOUS_DOMAIN 2
+-#define Z90C_INCORRECT_DOMAIN 3
+-#define ENOTINIT 4
+-
+-#define SEN_BUSY 7
+-#define SEN_USER_ERROR 8
+-#define SEN_QUEUE_FULL 11
+-#define SEN_NOT_AVAIL 16
+-#define SEN_PAD_ERROR 17
+-#define SEN_RETRY 18
+-#define SEN_RELEASED 24
+-
+-#define REC_EMPTY 4
+-#define REC_BUSY 6
+-#define REC_OPERAND_INV 8
+-#define REC_OPERAND_SIZE 9
+-#define REC_EVEN_MOD 10
+-#define REC_NO_WORK 11
+-#define REC_HARDWAR_ERR 12
+-#define REC_NO_RESPONSE 13
+-#define REC_RETRY_DEV 14
+-#define REC_USER_GONE 15
+-#define REC_BAD_MESSAGE 16
+-#define REC_INVALID_PAD 17
+-#define REC_USE_PCICA 18
+-
+-#define WRONG_DEVICE_TYPE 20
+-
+-#define REC_FATAL_ERROR 32
+-#define SEN_FATAL_ERROR 33
+-#define TSQ_FATAL_ERROR 34
+-#define RSQ_FATAL_ERROR 35
+-
+-#define Z90CRYPT_NUM_TYPES 6
+-#define PCICA 0
+-#define PCICC 1
+-#define PCIXCC_MCL2 2
+-#define PCIXCC_MCL3 3
+-#define CEX2C 4
+-#define CEX2A 5
+-#define NILDEV -1
+-#define ANYDEV -1
+-#define PCIXCC_UNK -2
+-
+-enum hdevice_type {
+- PCICC_HW = 3,
+- PCICA_HW = 4,
+- PCIXCC_HW = 5,
+- CEX2A_HW = 6,
+- CEX2C_HW = 7
+-};
+-
+-struct CPRBX {
+- unsigned short cprb_len;
+- unsigned char cprb_ver_id;
+- unsigned char pad_000[3];
+- unsigned char func_id[2];
+- unsigned char cprb_flags[4];
+- unsigned int req_parml;
+- unsigned int req_datal;
+- unsigned int rpl_msgbl;
+- unsigned int rpld_parml;
+- unsigned int rpl_datal;
+- unsigned int rpld_datal;
+- unsigned int req_extbl;
+- unsigned char pad_001[4];
+- unsigned int rpld_extbl;
+- unsigned char req_parmb[16];
+- unsigned char req_datab[16];
+- unsigned char rpl_parmb[16];
+- unsigned char rpl_datab[16];
+- unsigned char req_extb[16];
+- unsigned char rpl_extb[16];
+- unsigned short ccp_rtcode;
+- unsigned short ccp_rscode;
+- unsigned int mac_data_len;
+- unsigned char logon_id[8];
+- unsigned char mac_value[8];
+- unsigned char mac_content_flgs;
+- unsigned char pad_002;
+- unsigned short domain;
+- unsigned char pad_003[12];
+- unsigned char pad_004[36];
+-};
+-
+-#ifndef DEV_NAME
+-#define DEV_NAME "z90crypt"
+-#endif
+-#define PRINTK(fmt, args...) \
+- printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+-#define PRINTKN(fmt, args...) \
+- printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
+-#define PRINTKW(fmt, args...) \
+- printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+-#define PRINTKC(fmt, args...) \
+- printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+-
+-#ifdef Z90CRYPT_DEBUG
+-#define PDEBUG(fmt, args...) \
+- printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+-#else
+-#define PDEBUG(fmt, args...) do {} while (0)
+-#endif
+-
+-#define UMIN(a,b) ((a) < (b) ? (a) : (b))
+-#define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
+-
+-#endif
+diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h
+deleted file mode 100644
+index 0ca1d12..0000000
+--- a/drivers/s390/crypto/z90crypt.h
++++ /dev/null
+@@ -1,71 +0,0 @@
+-/*
+- * linux/drivers/s390/crypto/z90crypt.h
+- *
+- * z90crypt 1.3.3 (kernel-private header)
+- *
+- * Copyright (C) 2001, 2005 IBM Corporation
+- * Author(s): Robert Burroughs (burrough at us.ibm.com)
+- * Eric Rossman (edrossma at us.ibm.com)
+- *
+- * Hotplug & misc device support: Jochen Roehrig (roehrig at de.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, 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 _Z90CRYPT_H_
+-#define _Z90CRYPT_H_
+-
+-#include <asm/z90crypt.h>
+-
+-/**
+- * local errno definitions
+- */
+-#define ENOBUFF 129 // filp->private_data->...>work_elem_p->buffer is NULL
+-#define EWORKPEND 130 // user issues ioctl while another pending
+-#define ERELEASED 131 // user released while ioctl pending
+-#define EQUIESCE 132 // z90crypt quiescing (no more work allowed)
+-#define ETIMEOUT 133 // request timed out
+-#define EUNKNOWN 134 // some unrecognized error occured (retry may succeed)
+-#define EGETBUFF 135 // Error getting buffer or hardware lacks capability
+- // (retry in software)
+-
+-/**
+- * DEPRECATED STRUCTURES
+- */
+-
+-/**
+- * This structure is DEPRECATED and the corresponding ioctl() has been
+- * replaced with individual ioctl()s for each piece of data!
+- * This structure will NOT survive past version 1.3.1, so switch to the
+- * new ioctl()s.
+- */
+-#define MASK_LENGTH 64 // mask length
+-struct ica_z90_status {
+- int totalcount;
+- int leedslitecount; // PCICA
+- int leeds2count; // PCICC
+- // int PCIXCCCount; is not in struct for backward compatibility
+- int requestqWaitCount;
+- int pendingqWaitCount;
+- int totalOpenCount;
+- int cryptoDomain;
+- // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3,
+- // 5=CEX2C
+- unsigned char status[MASK_LENGTH];
+- // qdepth: # work elements waiting for each device
+- unsigned char qdepth[MASK_LENGTH];
+-};
+-
+-#endif /* _Z90CRYPT_H_ */
+diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c
+deleted file mode 100644
+index be60795..0000000
+--- a/drivers/s390/crypto/z90hardware.c
++++ /dev/null
+@@ -1,2531 +0,0 @@
+-/*
+- * linux/drivers/s390/crypto/z90hardware.c
+- *
+- * z90crypt 1.3.3
+- *
+- * Copyright (C) 2001, 2005 IBM Corporation
+- * Author(s): Robert Burroughs (burrough at us.ibm.com)
+- * Eric Rossman (edrossma at us.ibm.com)
+- *
+- * Hotplug & misc device support: Jochen Roehrig (roehrig at de.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, 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 <asm/uaccess.h>
+-#include <linux/compiler.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include "z90crypt.h"
+-#include "z90common.h"
+-
+-struct cca_token_hdr {
+- unsigned char token_identifier;
+- unsigned char version;
+- unsigned short token_length;
+- unsigned char reserved[4];
+-};
+-
+-#define CCA_TKN_HDR_ID_EXT 0x1E
+-
+-struct cca_private_ext_ME_sec {
+- unsigned char section_identifier;
+- unsigned char version;
+- unsigned short section_length;
+- unsigned char private_key_hash[20];
+- unsigned char reserved1[4];
+- unsigned char key_format;
+- unsigned char reserved2;
+- unsigned char key_name_hash[20];
+- unsigned char key_use_flags[4];
+- unsigned char reserved3[6];
+- unsigned char reserved4[24];
+- unsigned char confounder[24];
+- unsigned char exponent[128];
+- unsigned char modulus[128];
+-};
+-
+-#define CCA_PVT_USAGE_ALL 0x80
+-
+-struct cca_public_sec {
+- unsigned char section_identifier;
+- unsigned char version;
+- unsigned short section_length;
+- unsigned char reserved[2];
+- unsigned short exponent_len;
+- unsigned short modulus_bit_len;
+- unsigned short modulus_byte_len;
+- unsigned char exponent[3];
+-};
+-
+-struct cca_private_ext_ME {
+- struct cca_token_hdr pvtMEHdr;
+- struct cca_private_ext_ME_sec pvtMESec;
+- struct cca_public_sec pubMESec;
+-};
+-
+-struct cca_public_key {
+- struct cca_token_hdr pubHdr;
+- struct cca_public_sec pubSec;
+-};
+-
+-struct cca_pvt_ext_CRT_sec {
+- unsigned char section_identifier;
+- unsigned char version;
+- unsigned short section_length;
+- unsigned char private_key_hash[20];
+- unsigned char reserved1[4];
+- unsigned char key_format;
+- unsigned char reserved2;
+- unsigned char key_name_hash[20];
+- unsigned char key_use_flags[4];
+- unsigned short p_len;
+- unsigned short q_len;
+- unsigned short dp_len;
+- unsigned short dq_len;
+- unsigned short u_len;
+- unsigned short mod_len;
+- unsigned char reserved3[4];
+- unsigned short pad_len;
+- unsigned char reserved4[52];
+- unsigned char confounder[8];
+-};
+-
+-#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
+-#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
+-
+-struct cca_private_ext_CRT {
+- struct cca_token_hdr pvtCrtHdr;
+- struct cca_pvt_ext_CRT_sec pvtCrtSec;
+- struct cca_public_sec pubCrtSec;
+-};
+-
+-struct ap_status_word {
+- unsigned char q_stat_flags;
+- unsigned char response_code;
+- unsigned char reserved[2];
+-};
+-
+-#define AP_Q_STATUS_EMPTY 0x80
+-#define AP_Q_STATUS_REPLIES_WAITING 0x40
+-#define AP_Q_STATUS_ARRAY_FULL 0x20
+-
+-#define AP_RESPONSE_NORMAL 0x00
+-#define AP_RESPONSE_Q_NOT_AVAIL 0x01
+-#define AP_RESPONSE_RESET_IN_PROGRESS 0x02
+-#define AP_RESPONSE_DECONFIGURED 0x03
+-#define AP_RESPONSE_CHECKSTOPPED 0x04
+-#define AP_RESPONSE_BUSY 0x05
+-#define AP_RESPONSE_Q_FULL 0x10
+-#define AP_RESPONSE_NO_PENDING_REPLY 0x10
+-#define AP_RESPONSE_INDEX_TOO_BIG 0x11
+-#define AP_RESPONSE_NO_FIRST_PART 0x13
+-#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
+-
+-#define AP_MAX_CDX_BITL 4
+-#define AP_RQID_RESERVED_BITL 4
+-#define SKIP_BITL (AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL)
+-
+-struct type4_hdr {
+- unsigned char reserved1;
+- unsigned char msg_type_code;
+- unsigned short msg_len;
+- unsigned char request_code;
+- unsigned char msg_fmt;
+- unsigned short reserved2;
+-};
+-
+-#define TYPE4_TYPE_CODE 0x04
+-#define TYPE4_REQU_CODE 0x40
+-
+-#define TYPE4_SME_LEN 0x0188
+-#define TYPE4_LME_LEN 0x0308
+-#define TYPE4_SCR_LEN 0x01E0
+-#define TYPE4_LCR_LEN 0x03A0
+-
+-#define TYPE4_SME_FMT 0x00
+-#define TYPE4_LME_FMT 0x10
+-#define TYPE4_SCR_FMT 0x40
+-#define TYPE4_LCR_FMT 0x50
+-
+-struct type4_sme {
+- struct type4_hdr header;
+- unsigned char message[128];
+- unsigned char exponent[128];
+- unsigned char modulus[128];
+-};
+-
+-struct type4_lme {
+- struct type4_hdr header;
+- unsigned char message[256];
+- unsigned char exponent[256];
+- unsigned char modulus[256];
+-};
+-
+-struct type4_scr {
+- struct type4_hdr header;
+- unsigned char message[128];
+- unsigned char dp[72];
+- unsigned char dq[64];
+- unsigned char p[72];
+- unsigned char q[64];
+- unsigned char u[72];
+-};
+-
+-struct type4_lcr {
+- struct type4_hdr header;
+- unsigned char message[256];
+- unsigned char dp[136];
+- unsigned char dq[128];
+- unsigned char p[136];
+- unsigned char q[128];
+- unsigned char u[136];
+-};
+-
+-union type4_msg {
+- struct type4_sme sme;
+- struct type4_lme lme;
+- struct type4_scr scr;
+- struct type4_lcr lcr;
+-};
+-
+-struct type84_hdr {
+- unsigned char reserved1;
+- unsigned char code;
+- unsigned short len;
+- unsigned char reserved2[4];
+-};
+-
+-#define TYPE84_RSP_CODE 0x84
+-
+-struct type6_hdr {
+- unsigned char reserved1;
+- unsigned char type;
+- unsigned char reserved2[2];
+- unsigned char right[4];
+- unsigned char reserved3[2];
+- unsigned char reserved4[2];
+- unsigned char apfs[4];
+- unsigned int offset1;
+- unsigned int offset2;
+- unsigned int offset3;
+- unsigned int offset4;
+- unsigned char agent_id[16];
+- unsigned char rqid[2];
+- unsigned char reserved5[2];
+- unsigned char function_code[2];
+- unsigned char reserved6[2];
+- unsigned int ToCardLen1;
+- unsigned int ToCardLen2;
+- unsigned int ToCardLen3;
+- unsigned int ToCardLen4;
+- unsigned int FromCardLen1;
+- unsigned int FromCardLen2;
+- unsigned int FromCardLen3;
+- unsigned int FromCardLen4;
+-};
+-
+-struct CPRB {
+- unsigned char cprb_len[2];
+- unsigned char cprb_ver_id;
+- unsigned char pad_000;
+- unsigned char srpi_rtcode[4];
+- unsigned char srpi_verb;
+- unsigned char flags;
+- unsigned char func_id[2];
+- unsigned char checkpoint_flag;
+- unsigned char resv2;
+- unsigned char req_parml[2];
+- unsigned char req_parmp[4];
+- unsigned char req_datal[4];
+- unsigned char req_datap[4];
+- unsigned char rpl_parml[2];
+- unsigned char pad_001[2];
+- unsigned char rpl_parmp[4];
+- unsigned char rpl_datal[4];
+- unsigned char rpl_datap[4];
+- unsigned char ccp_rscode[2];
+- unsigned char ccp_rtcode[2];
+- unsigned char repd_parml[2];
+- unsigned char mac_data_len[2];
+- unsigned char repd_datal[4];
+- unsigned char req_pc[2];
+- unsigned char res_origin[8];
+- unsigned char mac_value[8];
+- unsigned char logon_id[8];
+- unsigned char usage_domain[2];
+- unsigned char resv3[18];
+- unsigned char svr_namel[2];
+- unsigned char svr_name[8];
+-};
+-
+-struct type6_msg {
+- struct type6_hdr header;
+- struct CPRB CPRB;
+-};
+-
+-struct type86_hdr {
+- unsigned char reserved1;
+- unsigned char type;
+- unsigned char format;
+- unsigned char reserved2;
+- unsigned char reply_code;
+- unsigned char reserved3[3];
+-};
+-
+-#define TYPE86_RSP_CODE 0x86
+-#define TYPE86_FMT2 0x02
+-
+-struct type86_fmt2_msg {
+- struct type86_hdr header;
+- unsigned char reserved[4];
+- unsigned char apfs[4];
+- unsigned int count1;
+- unsigned int offset1;
+- unsigned int count2;
+- unsigned int offset2;
+- unsigned int count3;
+- unsigned int offset3;
+- unsigned int count4;
+- unsigned int offset4;
+-};
+-
+-static struct type6_hdr static_type6_hdr = {
+- 0x00,
+- 0x06,
+- {0x00,0x00},
+- {0x00,0x00,0x00,0x00},
+- {0x00,0x00},
+- {0x00,0x00},
+- {0x00,0x00,0x00,0x00},
+- 0x00000058,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
+- 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
+- {0x00,0x00},
+- {0x00,0x00},
+- {0x50,0x44},
+- {0x00,0x00},
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000
+-};
+-
+-static struct type6_hdr static_type6_hdrX = {
+- 0x00,
+- 0x06,
+- {0x00,0x00},
+- {0x00,0x00,0x00,0x00},
+- {0x00,0x00},
+- {0x00,0x00},
+- {0x00,0x00,0x00,0x00},
+- 0x00000058,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- {0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00},
+- {0x00,0x00},
+- {0x50,0x44},
+- {0x00,0x00},
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000
+-};
+-
+-static struct CPRB static_cprb = {
+- {0x70,0x00},
+- 0x41,
+- 0x00,
+- {0x00,0x00,0x00,0x00},
+- 0x00,
+- 0x00,
+- {0x54,0x32},
+- 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},
+- {0x08,0x00},
+- {0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20}
+-};
+-
+-struct function_and_rules_block {
+- unsigned char function_code[2];
+- unsigned char ulen[2];
+- unsigned char only_rule[8];
+-};
+-
+-static struct function_and_rules_block static_pkd_function_and_rules = {
+- {0x50,0x44},
+- {0x0A,0x00},
+- {'P','K','C','S','-','1','.','2'}
+-};
+-
+-static struct function_and_rules_block static_pke_function_and_rules = {
+- {0x50,0x4B},
+- {0x0A,0x00},
+- {'P','K','C','S','-','1','.','2'}
+-};
+-
+-struct T6_keyBlock_hdr {
+- unsigned char blen[2];
+- unsigned char ulen[2];
+- unsigned char flags[2];
+-};
+-
+-static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = {
+- {0x89,0x01},
+- {0x87,0x01},
+- {0x00}
+-};
+-
+-static struct CPRBX static_cprbx = {
+- 0x00DC,
+- 0x02,
+- {0x00,0x00,0x00},
+- {0x54,0x32},
+- {0x00,0x00,0x00,0x00},
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- 0x00000000,
+- {0x00,0x00,0x00,0x00},
+- 0x00000000,
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- 0x0000,
+- 0x0000,
+- 0x00000000,
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- 0x00,
+- 0x00,
+- 0x0000,
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 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 struct function_and_rules_block static_pkd_function_and_rulesX_MCL2 = {
+- {0x50,0x44},
+- {0x00,0x0A},
+- {'P','K','C','S','-','1','.','2'}
+-};
+-
+-static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = {
+- {0x50,0x4B},
+- {0x00,0x0A},
+- {'Z','E','R','O','-','P','A','D'}
+-};
+-
+-static struct function_and_rules_block static_pkd_function_and_rulesX = {
+- {0x50,0x44},
+- {0x00,0x0A},
+- {'Z','E','R','O','-','P','A','D'}
+-};
+-
+-static struct function_and_rules_block static_pke_function_and_rulesX = {
+- {0x50,0x4B},
+- {0x00,0x0A},
+- {'M','R','P',' ',' ',' ',' ',' '}
+-};
+-
+-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+-
+-struct T6_keyBlock_hdrX {
+- unsigned short blen;
+- unsigned short ulen;
+- unsigned char flags[2];
+-};
+-
+-static unsigned char static_pad[256] = {
+-0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
+-0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
+-0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
+-0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
+-0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
+-0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
+-0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
+-0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
+-0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
+-0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
+-0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
+-0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
+-0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
+-0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
+-0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
+-0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
+-};
+-
+-static struct cca_private_ext_ME static_pvt_me_key = {
+- {
+- 0x1E,
+- 0x00,
+- 0x0183,
+- {0x00,0x00,0x00,0x00}
+- },
+-
+- {
+- 0x02,
+- 0x00,
+- 0x016C,
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00},
+- 0x00,
+- 0x00,
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00},
+- {0x80,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+- },
+-
+- {
+- 0x04,
+- 0x00,
+- 0x000F,
+- {0x00,0x00},
+- 0x0003,
+- 0x0000,
+- 0x0000,
+- {0x01,0x00,0x01}
+- }
+-};
+-
+-static struct cca_public_key static_public_key = {
+- {
+- 0x1E,
+- 0x00,
+- 0x0000,
+- {0x00,0x00,0x00,0x00}
+- },
+-
+- {
+- 0x04,
+- 0x00,
+- 0x0000,
+- {0x00,0x00},
+- 0x0000,
+- 0x0000,
+- 0x0000,
+- {0x01,0x00,0x01}
+- }
+-};
+-
+-#define FIXED_TYPE6_ME_LEN 0x0000025F
+-
+-#define FIXED_TYPE6_ME_EN_LEN 0x000000F0
+-
+-#define FIXED_TYPE6_ME_LENX 0x000002CB
+-
+-#define FIXED_TYPE6_ME_EN_LENX 0x0000015C
+-
+-static struct cca_public_sec static_cca_pub_sec = {
+- 0x04,
+- 0x00,
+- 0x000f,
+- {0x00,0x00},
+- 0x0003,
+- 0x0000,
+- 0x0000,
+- {0x01,0x00,0x01}
+-};
+-
+-#define FIXED_TYPE6_CR_LEN 0x00000177
+-
+-#define FIXED_TYPE6_CR_LENX 0x000001E3
+-
+-#define MAX_RESPONSE_SIZE 0x00000710
+-
+-#define MAX_RESPONSEX_SIZE 0x0000077C
+-
+-#define RESPONSE_CPRB_SIZE 0x000006B8
+-#define RESPONSE_CPRBX_SIZE 0x00000724
+-
+-struct type50_hdr {
+- u8 reserved1;
+- u8 msg_type_code;
+- u16 msg_len;
+- u8 reserved2;
+- u8 ignored;
+- u16 reserved3;
+-};
+-
+-#define TYPE50_TYPE_CODE 0x50
+-
+-#define TYPE50_MEB1_LEN (sizeof(struct type50_meb1_msg))
+-#define TYPE50_MEB2_LEN (sizeof(struct type50_meb2_msg))
+-#define TYPE50_CRB1_LEN (sizeof(struct type50_crb1_msg))
+-#define TYPE50_CRB2_LEN (sizeof(struct type50_crb2_msg))
+-
+-#define TYPE50_MEB1_FMT 0x0001
+-#define TYPE50_MEB2_FMT 0x0002
+-#define TYPE50_CRB1_FMT 0x0011
+-#define TYPE50_CRB2_FMT 0x0012
+-
+-struct type50_meb1_msg {
+- struct type50_hdr header;
+- u16 keyblock_type;
+- u8 reserved[6];
+- u8 exponent[128];
+- u8 modulus[128];
+- u8 message[128];
+-};
+-
+-struct type50_meb2_msg {
+- struct type50_hdr header;
+- u16 keyblock_type;
+- u8 reserved[6];
+- u8 exponent[256];
+- u8 modulus[256];
+- u8 message[256];
+-};
+-
+-struct type50_crb1_msg {
+- struct type50_hdr header;
+- u16 keyblock_type;
+- u8 reserved[6];
+- u8 p[64];
+- u8 q[64];
+- u8 dp[64];
+- u8 dq[64];
+- u8 u[64];
+- u8 message[128];
+-};
+-
+-struct type50_crb2_msg {
+- struct type50_hdr header;
+- u16 keyblock_type;
+- u8 reserved[6];
+- u8 p[128];
+- u8 q[128];
+- u8 dp[128];
+- u8 dq[128];
+- u8 u[128];
+- u8 message[256];
+-};
+-
+-union type50_msg {
+- struct type50_meb1_msg meb1;
+- struct type50_meb2_msg meb2;
+- struct type50_crb1_msg crb1;
+- struct type50_crb2_msg crb2;
+-};
+-
+-struct type80_hdr {
+- u8 reserved1;
+- u8 type;
+- u16 len;
+- u8 code;
+- u8 reserved2[3];
+- u8 reserved3[8];
+-};
+-
+-#define TYPE80_RSP_CODE 0x80
+-
+-struct error_hdr {
+- unsigned char reserved1;
+- unsigned char type;
+- unsigned char reserved2[2];
+- unsigned char reply_code;
+- unsigned char reserved3[3];
+-};
+-
+-#define TYPE82_RSP_CODE 0x82
+-#define TYPE88_RSP_CODE 0x88
+-
+-#define REP82_ERROR_MACHINE_FAILURE 0x10
+-#define REP82_ERROR_PREEMPT_FAILURE 0x12
+-#define REP82_ERROR_CHECKPT_FAILURE 0x14
+-#define REP82_ERROR_MESSAGE_TYPE 0x20
+-#define REP82_ERROR_INVALID_COMM_CD 0x21
+-#define REP82_ERROR_INVALID_MSG_LEN 0x23
+-#define REP82_ERROR_RESERVD_FIELD 0x24
+-#define REP82_ERROR_FORMAT_FIELD 0x29
+-#define REP82_ERROR_INVALID_COMMAND 0x30
+-#define REP82_ERROR_MALFORMED_MSG 0x40
+-#define REP82_ERROR_RESERVED_FIELDO 0x50
+-#define REP82_ERROR_WORD_ALIGNMENT 0x60
+-#define REP82_ERROR_MESSAGE_LENGTH 0x80
+-#define REP82_ERROR_OPERAND_INVALID 0x82
+-#define REP82_ERROR_OPERAND_SIZE 0x84
+-#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+-#define REP82_ERROR_RESERVED_FIELD 0x88
+-#define REP82_ERROR_TRANSPORT_FAIL 0x90
+-#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+-#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
+-
+-#define REP88_ERROR_MODULE_FAILURE 0x10
+-#define REP88_ERROR_MODULE_TIMEOUT 0x11
+-#define REP88_ERROR_MODULE_NOTINIT 0x13
+-#define REP88_ERROR_MODULE_NOTAVAIL 0x14
+-#define REP88_ERROR_MODULE_DISABLED 0x15
+-#define REP88_ERROR_MODULE_IN_DIAGN 0x17
+-#define REP88_ERROR_FASTPATH_DISABLD 0x19
+-#define REP88_ERROR_MESSAGE_TYPE 0x20
+-#define REP88_ERROR_MESSAGE_MALFORMD 0x22
+-#define REP88_ERROR_MESSAGE_LENGTH 0x23
+-#define REP88_ERROR_RESERVED_FIELD 0x24
+-#define REP88_ERROR_KEY_TYPE 0x34
+-#define REP88_ERROR_INVALID_KEY 0x82
+-#define REP88_ERROR_OPERAND 0x84
+-#define REP88_ERROR_OPERAND_EVEN_MOD 0x85
+-
+-#define CALLER_HEADER 12
+-
+-static inline int
+-testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
+-{
+- int ccode;
+-
+- asm volatile
+-#ifdef CONFIG_64BIT
+- (" llgfr 0,%4 \n"
+- " slgr 1,1 \n"
+- " lgr 2,1 \n"
+- "0: .long 0xb2af0000 \n"
+- "1: ipm %0 \n"
+- " srl %0,28 \n"
+- " iihh %0,0 \n"
+- " iihl %0,0 \n"
+- " lgr %1,1 \n"
+- " lgr %3,2 \n"
+- " srl %3,24 \n"
+- " sll 2,24 \n"
+- " srl 2,24 \n"
+- " lgr %2,2 \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h5 \n"
+- " jg 2b \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 8 \n"
+- " .quad 0b,3b \n"
+- " .quad 1b,3b \n"
+- ".previous"
+- :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
+- :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
+- :"cc","0","1","2","memory");
+-#else
+- (" lr 0,%4 \n"
+- " slr 1,1 \n"
+- " lr 2,1 \n"
+- "0: .long 0xb2af0000 \n"
+- "1: ipm %0 \n"
+- " srl %0,28 \n"
+- " lr %1,1 \n"
+- " lr %3,2 \n"
+- " srl %3,24 \n"
+- " sll 2,24 \n"
+- " srl 2,24 \n"
+- " lr %2,2 \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h5 \n"
+- " bras 1,4f \n"
+- " .long 2b \n"
+- "4: \n"
+- " l 1,0(1) \n"
+- " br 1 \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 4 \n"
+- " .long 0b,3b \n"
+- " .long 1b,3b \n"
+- ".previous"
+- :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
+- :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
+- :"cc","0","1","2","memory");
+-#endif
+- return ccode;
+-}
+-
+-static inline int
+-resetq(int q_nr, struct ap_status_word *stat_p)
+-{
+- int ccode;
+-
+- asm volatile
+-#ifdef CONFIG_64BIT
+- (" llgfr 0,%2 \n"
+- " lghi 1,1 \n"
+- " sll 1,24 \n"
+- " or 0,1 \n"
+- " slgr 1,1 \n"
+- " lgr 2,1 \n"
+- "0: .long 0xb2af0000 \n"
+- "1: ipm %0 \n"
+- " srl %0,28 \n"
+- " iihh %0,0 \n"
+- " iihl %0,0 \n"
+- " lgr %1,1 \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h3 \n"
+- " jg 2b \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 8 \n"
+- " .quad 0b,3b \n"
+- " .quad 1b,3b \n"
+- ".previous"
+- :"=d" (ccode),"=d" (*stat_p)
+- :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
+- :"cc","0","1","2","memory");
+-#else
+- (" lr 0,%2 \n"
+- " lhi 1,1 \n"
+- " sll 1,24 \n"
+- " or 0,1 \n"
+- " slr 1,1 \n"
+- " lr 2,1 \n"
+- "0: .long 0xb2af0000 \n"
+- "1: ipm %0 \n"
+- " srl %0,28 \n"
+- " lr %1,1 \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h3 \n"
+- " bras 1,4f \n"
+- " .long 2b \n"
+- "4: \n"
+- " l 1,0(1) \n"
+- " br 1 \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 4 \n"
+- " .long 0b,3b \n"
+- " .long 1b,3b \n"
+- ".previous"
+- :"=d" (ccode),"=d" (*stat_p)
+- :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
+- :"cc","0","1","2","memory");
+-#endif
+- return ccode;
+-}
+-
+-static inline int
+-sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
+-{
+- int ccode;
+-
+- asm volatile
+-#ifdef CONFIG_64BIT
+- (" lgr 6,%3 \n"
+- " llgfr 7,%2 \n"
+- " llgt 0,0(6) \n"
+- " lghi 1,64 \n"
+- " sll 1,24 \n"
+- " or 0,1 \n"
+- " la 6,4(6) \n"
+- " llgt 2,0(6) \n"
+- " llgt 3,4(6) \n"
+- " la 6,8(6) \n"
+- " slr 1,1 \n"
+- "0: .long 0xb2ad0026 \n"
+- "1: brc 2,0b \n"
+- " ipm %0 \n"
+- " srl %0,28 \n"
+- " iihh %0,0 \n"
+- " iihl %0,0 \n"
+- " lgr %1,1 \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h4 \n"
+- " jg 2b \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 8 \n"
+- " .quad 0b,3b \n"
+- " .quad 1b,3b \n"
+- ".previous"
+- :"=d" (ccode),"=d" (*stat)
+- :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
+- :"cc","0","1","2","3","6","7","memory");
+-#else
+- (" lr 6,%3 \n"
+- " lr 7,%2 \n"
+- " l 0,0(6) \n"
+- " lhi 1,64 \n"
+- " sll 1,24 \n"
+- " or 0,1 \n"
+- " la 6,4(6) \n"
+- " l 2,0(6) \n"
+- " l 3,4(6) \n"
+- " la 6,8(6) \n"
+- " slr 1,1 \n"
+- "0: .long 0xb2ad0026 \n"
+- "1: brc 2,0b \n"
+- " ipm %0 \n"
+- " srl %0,28 \n"
+- " lr %1,1 \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h4 \n"
+- " bras 1,4f \n"
+- " .long 2b \n"
+- "4: \n"
+- " l 1,0(1) \n"
+- " br 1 \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 4 \n"
+- " .long 0b,3b \n"
+- " .long 1b,3b \n"
+- ".previous"
+- :"=d" (ccode),"=d" (*stat)
+- :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
+- :"cc","0","1","2","3","6","7","memory");
+-#endif
+- return ccode;
+-}
+-
+-static inline int
+-rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
+- struct ap_status_word *st)
+-{
+- int ccode;
+-
+- asm volatile
+-#ifdef CONFIG_64BIT
+- (" llgfr 0,%2 \n"
+- " lgr 3,%4 \n"
+- " lgr 6,%3 \n"
+- " llgfr 7,%5 \n"
+- " lghi 1,128 \n"
+- " sll 1,24 \n"
+- " or 0,1 \n"
+- " slgr 1,1 \n"
+- " lgr 2,1 \n"
+- " lgr 4,1 \n"
+- " lgr 5,1 \n"
+- "0: .long 0xb2ae0046 \n"
+- "1: brc 2,0b \n"
+- " brc 4,0b \n"
+- " ipm %0 \n"
+- " srl %0,28 \n"
+- " iihh %0,0 \n"
+- " iihl %0,0 \n"
+- " lgr %1,1 \n"
+- " st 4,0(3) \n"
+- " st 5,4(3) \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h6 \n"
+- " jg 2b \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 8 \n"
+- " .quad 0b,3b \n"
+- " .quad 1b,3b \n"
+- ".previous"
+- :"=d"(ccode),"=d"(*st)
+- :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
+- :"cc","0","1","2","3","4","5","6","7","memory");
+-#else
+- (" lr 0,%2 \n"
+- " lr 3,%4 \n"
+- " lr 6,%3 \n"
+- " lr 7,%5 \n"
+- " lhi 1,128 \n"
+- " sll 1,24 \n"
+- " or 0,1 \n"
+- " slr 1,1 \n"
+- " lr 2,1 \n"
+- " lr 4,1 \n"
+- " lr 5,1 \n"
+- "0: .long 0xb2ae0046 \n"
+- "1: brc 2,0b \n"
+- " brc 4,0b \n"
+- " ipm %0 \n"
+- " srl %0,28 \n"
+- " lr %1,1 \n"
+- " st 4,0(3) \n"
+- " st 5,4(3) \n"
+- "2: \n"
+- ".section .fixup,\"ax\" \n"
+- "3: \n"
+- " lhi %0,%h6 \n"
+- " bras 1,4f \n"
+- " .long 2b \n"
+- "4: \n"
+- " l 1,0(1) \n"
+- " br 1 \n"
+- ".previous \n"
+- ".section __ex_table,\"a\" \n"
+- " .align 4 \n"
+- " .long 0b,3b \n"
+- " .long 1b,3b \n"
+- ".previous"
+- :"=d"(ccode),"=d"(*st)
+- :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
+- :"cc","0","1","2","3","4","5","6","7","memory");
+-#endif
+- return ccode;
+-}
+-
+-static inline void
+-itoLe2(int *i_p, unsigned char *lechars)
+-{
+- *lechars = *((unsigned char *) i_p + sizeof(int) - 1);
+- *(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2);
+-}
+-
+-static inline void
+-le2toI(unsigned char *lechars, int *i_p)
+-{
+- unsigned char *ic_p;
+- *i_p = 0;
+- ic_p = (unsigned char *) i_p;
+- *(ic_p + 2) = *(lechars + 1);
+- *(ic_p + 3) = *(lechars);
+-}
+-
+-static inline int
+-is_empty(unsigned char *ptr, int len)
+-{
+- return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len);
+-}
+-
+-enum hdstat
+-query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
+-{
+- int q_nr, i, t_depth, t_dev_type;
+- enum devstat ccode;
+- struct ap_status_word stat_word;
+- enum hdstat stat;
+- int break_out;
+-
+- q_nr = (deviceNr << SKIP_BITL) + cdx;
+- stat = HD_BUSY;
+- ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
+- PDEBUG("ccode %d response_code %02X\n", ccode, stat_word.response_code);
+- break_out = 0;
+- for (i = 0; i < resetNr; i++) {
+- if (ccode > 3) {
+- PRINTKC("Exception testing device %d\n", i);
+- return HD_TSQ_EXCEPTION;
+- }
+- switch (ccode) {
+- case 0:
+- PDEBUG("t_dev_type %d\n", t_dev_type);
+- break_out = 1;
+- stat = HD_ONLINE;
+- *q_depth = t_depth + 1;
+- switch (t_dev_type) {
+- case PCICA_HW:
+- *dev_type = PCICA;
+- break;
+- case PCICC_HW:
+- *dev_type = PCICC;
+- break;
+- case PCIXCC_HW:
+- *dev_type = PCIXCC_UNK;
+- break;
+- case CEX2C_HW:
+- *dev_type = CEX2C;
+- break;
+- case CEX2A_HW:
+- *dev_type = CEX2A;
+- break;
+- default:
+- *dev_type = NILDEV;
+- break;
+- }
+- PDEBUG("available device %d: Q depth = %d, dev "
+- "type = %d, stat = %02X%02X%02X%02X\n",
+- deviceNr, *q_depth, *dev_type,
+- stat_word.q_stat_flags,
+- stat_word.response_code,
+- stat_word.reserved[0],
+- stat_word.reserved[1]);
+- break;
+- case 3:
+- switch (stat_word.response_code) {
+- case AP_RESPONSE_NORMAL:
+- stat = HD_ONLINE;
+- break_out = 1;
+- *q_depth = t_depth + 1;
+- *dev_type = t_dev_type;
+- PDEBUG("cc3, available device "
+- "%d: Q depth = %d, dev "
+- "type = %d, stat = "
+- "%02X%02X%02X%02X\n",
+- deviceNr, *q_depth,
+- *dev_type,
+- stat_word.q_stat_flags,
+- stat_word.response_code,
+- stat_word.reserved[0],
+- stat_word.reserved[1]);
+- break;
+- case AP_RESPONSE_Q_NOT_AVAIL:
+- stat = HD_NOT_THERE;
+- break_out = 1;
+- break;
+- case AP_RESPONSE_RESET_IN_PROGRESS:
+- PDEBUG("device %d in reset\n",
+- deviceNr);
+- break;
+- case AP_RESPONSE_DECONFIGURED:
+- stat = HD_DECONFIGURED;
+- break_out = 1;
+- break;
+- case AP_RESPONSE_CHECKSTOPPED:
+- stat = HD_CHECKSTOPPED;
+- break_out = 1;
+- break;
+- case AP_RESPONSE_BUSY:
+- PDEBUG("device %d busy\n",
+- deviceNr);
+- break;
+- default:
+- break;
+- }
+- break;
+- default:
+- stat = HD_NOT_THERE;
+- break_out = 1;
+- break;
+- }
+- if (break_out)
+- break;
+-
+- udelay(5);
+-
+- ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
+- }
+- return stat;
+-}
+-
+-enum devstat
+-reset_device(int deviceNr, int cdx, int resetNr)
+-{
+- int q_nr, ccode = 0, dummy_qdepth, dummy_devType, i;
+- struct ap_status_word stat_word;
+- enum devstat stat;
+- int break_out;
+-
+- q_nr = (deviceNr << SKIP_BITL) + cdx;
+- stat = DEV_GONE;
+- ccode = resetq(q_nr, &stat_word);
+- if (ccode > 3)
+- return DEV_RSQ_EXCEPTION;
+-
+- break_out = 0;
+- for (i = 0; i < resetNr; i++) {
+- switch (ccode) {
+- case 0:
+- stat = DEV_ONLINE;
+- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
+- break_out = 1;
+- break;
+- case 3:
+- switch (stat_word.response_code) {
+- case AP_RESPONSE_NORMAL:
+- stat = DEV_ONLINE;
+- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
+- break_out = 1;
+- break;
+- case AP_RESPONSE_Q_NOT_AVAIL:
+- case AP_RESPONSE_DECONFIGURED:
+- case AP_RESPONSE_CHECKSTOPPED:
+- stat = DEV_GONE;
+- break_out = 1;
+- break;
+- case AP_RESPONSE_RESET_IN_PROGRESS:
+- case AP_RESPONSE_BUSY:
+- default:
+- break;
+- }
+- break;
+- default:
+- stat = DEV_GONE;
+- break_out = 1;
+- break;
+- }
+- if (break_out == 1)
+- break;
+- udelay(5);
+-
+- ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word);
+- if (ccode > 3) {
+- stat = DEV_TSQ_EXCEPTION;
+- break;
+- }
+- }
+- PDEBUG("Number of testq's needed for reset: %d\n", i);
+-
+- if (i >= resetNr) {
+- stat = DEV_GONE;
+- }
+-
+- return stat;
+-}
+-
+-#ifdef DEBUG_HYDRA_MSGS
+-static inline void
+-print_buffer(unsigned char *buffer, int bufflen)
+-{
+- int i;
+- for (i = 0; i < bufflen; i += 16) {
+- PRINTK("%04X: %02X%02X%02X%02X %02X%02X%02X%02X "
+- "%02X%02X%02X%02X %02X%02X%02X%02X\n", i,
+- buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3],
+- buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7],
+- buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11],
+- buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
+- }
+-}
+-#endif
+-
+-enum devstat
+-send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
+-{
+- struct ap_status_word stat_word;
+- enum devstat stat;
+- int ccode;
+- u32 *q_nr_p = (u32 *)msg_ext;
+-
+- *q_nr_p = (dev_nr << SKIP_BITL) + cdx;
+- PDEBUG("msg_len passed to sen: %d\n", msg_len);
+- PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
+- msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
+- stat = DEV_GONE;
+-
+-#ifdef DEBUG_HYDRA_MSGS
+- PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X "
+- "%02X%02X%02X%02X\n",
+- msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
+- msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
+- msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
+- print_buffer(msg_ext+CALLER_HEADER, msg_len);
+-#endif
+-
+- ccode = sen(msg_len, msg_ext, &stat_word);
+- if (ccode > 3)
+- return DEV_SEN_EXCEPTION;
+-
+- PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n",
+- ccode, stat_word.q_stat_flags, stat_word.response_code,
+- stat_word.reserved[0], stat_word.reserved[1]);
+- switch (ccode) {
+- case 0:
+- stat = DEV_ONLINE;
+- break;
+- case 1:
+- stat = DEV_GONE;
+- break;
+- case 3:
+- switch (stat_word.response_code) {
+- case AP_RESPONSE_NORMAL:
+- stat = DEV_ONLINE;
+- break;
+- case AP_RESPONSE_Q_FULL:
+- stat = DEV_QUEUE_FULL;
+- break;
+- default:
+- stat = DEV_GONE;
+- break;
+- }
+- break;
+- default:
+- stat = DEV_GONE;
+- break;
+- }
+-
+- return stat;
+-}
+-
+-enum devstat
+-receive_from_AP(int dev_nr, int cdx, int resplen, unsigned char *resp,
+- unsigned char *psmid)
+-{
+- int ccode;
+- struct ap_status_word stat_word;
+- enum devstat stat;
+-
+- memset(resp, 0x00, 8);
+-
+- ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid,
+- &stat_word);
+- if (ccode > 3)
+- return DEV_REC_EXCEPTION;
+-
+- PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n",
+- ccode, stat_word.q_stat_flags, stat_word.response_code,
+- stat_word.reserved[0], stat_word.reserved[1]);
+-
+- stat = DEV_GONE;
+- switch (ccode) {
+- case 0:
+- stat = DEV_ONLINE;
+-#ifdef DEBUG_HYDRA_MSGS
+- print_buffer(resp, resplen);
+-#endif
+- break;
+- case 3:
+- switch (stat_word.response_code) {
+- case AP_RESPONSE_NORMAL:
+- stat = DEV_ONLINE;
+- break;
+- case AP_RESPONSE_NO_PENDING_REPLY:
+- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
+- stat = DEV_EMPTY;
+- else
+- stat = DEV_NO_WORK;
+- break;
+- case AP_RESPONSE_INDEX_TOO_BIG:
+- case AP_RESPONSE_NO_FIRST_PART:
+- case AP_RESPONSE_MESSAGE_TOO_BIG:
+- stat = DEV_BAD_MESSAGE;
+- break;
+- default:
+- break;
+- }
+- break;
+- default:
+- break;
+- }
+-
+- return stat;
+-}
+-
+-static inline int
+-pad_msg(unsigned char *buffer, int totalLength, int msgLength)
+-{
+- int pad_len;
+-
+- for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++)
+- if (buffer[pad_len] != 0x00)
+- break;
+- pad_len -= 3;
+- if (pad_len < 8)
+- return SEN_PAD_ERROR;
+-
+- buffer[0] = 0x00;
+- buffer[1] = 0x02;
+-
+- memcpy(buffer+2, static_pad, pad_len);
+-
+- buffer[pad_len + 2] = 0x00;
+-
+- return 0;
+-}
+-
+-static inline int
+-is_common_public_key(unsigned char *key, int len)
+-{
+- int i;
+-
+- for (i = 0; i < len; i++)
+- if (key[i])
+- break;
+- key += i;
+- len -= i;
+- if (((len == 1) && (key[0] == 3)) ||
+- ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1)))
+- return 1;
+-
+- return 0;
+-}
+-
+-static int
+-ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
+- union type4_msg *z90cMsg_p)
+-{
+- int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
+- unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
+- union type4_msg *tmp_type4_msg;
+-
+- mod_len = icaMex_p->inputdatalength;
+-
+- msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) +
+- CALLER_HEADER;
+-
+- memset(z90cMsg_p, 0, msg_size);
+-
+- tmp_type4_msg = (union type4_msg *)
+- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+-
+- tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE;
+- tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE;
+-
+- if (mod_len <= 128) {
+- tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT;
+- tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN;
+- mod_tgt = tmp_type4_msg->sme.modulus;
+- mod_tgt_len = sizeof(tmp_type4_msg->sme.modulus);
+- exp_tgt = tmp_type4_msg->sme.exponent;
+- exp_tgt_len = sizeof(tmp_type4_msg->sme.exponent);
+- inp_tgt = tmp_type4_msg->sme.message;
+- inp_tgt_len = sizeof(tmp_type4_msg->sme.message);
+- } else {
+- tmp_type4_msg->lme.header.msg_fmt = TYPE4_LME_FMT;
+- tmp_type4_msg->lme.header.msg_len = TYPE4_LME_LEN;
+- mod_tgt = tmp_type4_msg->lme.modulus;
+- mod_tgt_len = sizeof(tmp_type4_msg->lme.modulus);
+- exp_tgt = tmp_type4_msg->lme.exponent;
+- exp_tgt_len = sizeof(tmp_type4_msg->lme.exponent);
+- inp_tgt = tmp_type4_msg->lme.message;
+- inp_tgt_len = sizeof(tmp_type4_msg->lme.message);
+- }
+-
+- mod_tgt += (mod_tgt_len - mod_len);
+- if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(mod_tgt, mod_len))
+- return SEN_USER_ERROR;
+- exp_tgt += (exp_tgt_len - mod_len);
+- if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(exp_tgt, mod_len))
+- return SEN_USER_ERROR;
+- inp_tgt += (inp_tgt_len - mod_len);
+- if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(inp_tgt, mod_len))
+- return SEN_USER_ERROR;
+-
+- *z90cMsg_l_p = msg_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
+- int *z90cMsg_l_p, union type4_msg *z90cMsg_p)
+-{
+- int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
+- dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len;
+- unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt;
+- union type4_msg *tmp_type4_msg;
+-
+- mod_len = icaMsg_p->inputdatalength;
+- short_len = mod_len / 2;
+- long_len = mod_len / 2 + 8;
+-
+- tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) +
+- CALLER_HEADER;
+-
+- memset(z90cMsg_p, 0, tmp_size);
+-
+- tmp_type4_msg = (union type4_msg *)
+- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+-
+- tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE;
+- tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE;
+- if (mod_len <= 128) {
+- tmp_type4_msg->scr.header.msg_fmt = TYPE4_SCR_FMT;
+- tmp_type4_msg->scr.header.msg_len = TYPE4_SCR_LEN;
+- p_tgt = tmp_type4_msg->scr.p;
+- p_tgt_len = sizeof(tmp_type4_msg->scr.p);
+- q_tgt = tmp_type4_msg->scr.q;
+- q_tgt_len = sizeof(tmp_type4_msg->scr.q);
+- dp_tgt = tmp_type4_msg->scr.dp;
+- dp_tgt_len = sizeof(tmp_type4_msg->scr.dp);
+- dq_tgt = tmp_type4_msg->scr.dq;
+- dq_tgt_len = sizeof(tmp_type4_msg->scr.dq);
+- u_tgt = tmp_type4_msg->scr.u;
+- u_tgt_len = sizeof(tmp_type4_msg->scr.u);
+- inp_tgt = tmp_type4_msg->scr.message;
+- inp_tgt_len = sizeof(tmp_type4_msg->scr.message);
+- } else {
+- tmp_type4_msg->lcr.header.msg_fmt = TYPE4_LCR_FMT;
+- tmp_type4_msg->lcr.header.msg_len = TYPE4_LCR_LEN;
+- p_tgt = tmp_type4_msg->lcr.p;
+- p_tgt_len = sizeof(tmp_type4_msg->lcr.p);
+- q_tgt = tmp_type4_msg->lcr.q;
+- q_tgt_len = sizeof(tmp_type4_msg->lcr.q);
+- dp_tgt = tmp_type4_msg->lcr.dp;
+- dp_tgt_len = sizeof(tmp_type4_msg->lcr.dp);
+- dq_tgt = tmp_type4_msg->lcr.dq;
+- dq_tgt_len = sizeof(tmp_type4_msg->lcr.dq);
+- u_tgt = tmp_type4_msg->lcr.u;
+- u_tgt_len = sizeof(tmp_type4_msg->lcr.u);
+- inp_tgt = tmp_type4_msg->lcr.message;
+- inp_tgt_len = sizeof(tmp_type4_msg->lcr.message);
+- }
+-
+- p_tgt += (p_tgt_len - long_len);
+- if (copy_from_user(p_tgt, icaMsg_p->np_prime, long_len))
+- return SEN_RELEASED;
+- if (is_empty(p_tgt, long_len))
+- return SEN_USER_ERROR;
+- q_tgt += (q_tgt_len - short_len);
+- if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
+- return SEN_RELEASED;
+- if (is_empty(q_tgt, short_len))
+- return SEN_USER_ERROR;
+- dp_tgt += (dp_tgt_len - long_len);
+- if (copy_from_user(dp_tgt, icaMsg_p->bp_key, long_len))
+- return SEN_RELEASED;
+- if (is_empty(dp_tgt, long_len))
+- return SEN_USER_ERROR;
+- dq_tgt += (dq_tgt_len - short_len);
+- if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
+- return SEN_RELEASED;
+- if (is_empty(dq_tgt, short_len))
+- return SEN_USER_ERROR;
+- u_tgt += (u_tgt_len - long_len);
+- if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv, long_len))
+- return SEN_RELEASED;
+- if (is_empty(u_tgt, long_len))
+- return SEN_USER_ERROR;
+- inp_tgt += (inp_tgt_len - mod_len);
+- if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(inp_tgt, mod_len))
+- return SEN_USER_ERROR;
+-
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+-{
+- int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
+- unsigned char *temp;
+- struct type6_hdr *tp6Hdr_p;
+- struct CPRB *cprb_p;
+- struct cca_private_ext_ME *key_p;
+- static int deprecated_msg_count = 0;
+-
+- mod_len = icaMsg_p->inputdatalength;
+- tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
+- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+- parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
+- tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+-
+- memset(z90cMsg_p, 0, tmp_size);
+-
+- temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+- memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
+- tp6Hdr_p = (struct type6_hdr *)temp;
+- tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
+- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
+-
+- temp += sizeof(struct type6_hdr);
+- memcpy(temp, &static_cprb, sizeof(struct CPRB));
+- cprb_p = (struct CPRB *) temp;
+- cprb_p->usage_domain[0]= (unsigned char)cdx;
+- itoLe2(&parmBlock_l, cprb_p->req_parml);
+- itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
+-
+- temp += sizeof(struct CPRB);
+- memcpy(temp, &static_pkd_function_and_rules,
+- sizeof(struct function_and_rules_block));
+-
+- temp += sizeof(struct function_and_rules_block);
+- vud_len = 2 + icaMsg_p->inputdatalength;
+- itoLe2(&vud_len, temp);
+-
+- temp += 2;
+- if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(temp, mod_len))
+- return SEN_USER_ERROR;
+-
+- temp += mod_len;
+- memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr));
+-
+- temp += sizeof(struct T6_keyBlock_hdr);
+- memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME));
+- key_p = (struct cca_private_ext_ME *)temp;
+- temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent)
+- - mod_len;
+- if (copy_from_user(temp, icaMsg_p->b_key, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(temp, mod_len))
+- return SEN_USER_ERROR;
+-
+- if (is_common_public_key(temp, mod_len)) {
+- if (deprecated_msg_count < 20) {
+- PRINTK("Common public key used for modex decrypt\n");
+- deprecated_msg_count++;
+- if (deprecated_msg_count == 20)
+- PRINTK("No longer issuing messages about common"
+- " public key for modex decrypt.\n");
+- }
+- return SEN_NOT_AVAIL;
+- }
+-
+- temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
+- - mod_len;
+- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(temp, mod_len))
+- return SEN_USER_ERROR;
+-
+- key_p->pubMESec.modulus_bit_len = 8 * mod_len;
+-
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+-{
+- int mod_len, vud_len, exp_len, key_len;
+- int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i;
+- unsigned char *temp_exp, *exp_p, *temp;
+- struct type6_hdr *tp6Hdr_p;
+- struct CPRB *cprb_p;
+- struct cca_public_key *key_p;
+- struct T6_keyBlock_hdr *keyb_p;
+-
+- temp_exp = kmalloc(256, GFP_KERNEL);
+- if (!temp_exp)
+- return EGETBUFF;
+- mod_len = icaMsg_p->inputdatalength;
+- if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
+- kfree(temp_exp);
+- return SEN_RELEASED;
+- }
+- if (is_empty(temp_exp, mod_len)) {
+- kfree(temp_exp);
+- return SEN_USER_ERROR;
+- }
+-
+- exp_p = temp_exp;
+- for (i = 0; i < mod_len; i++)
+- if (exp_p[i])
+- break;
+- if (i >= mod_len) {
+- kfree(temp_exp);
+- return SEN_USER_ERROR;
+- }
+-
+- exp_len = mod_len - i;
+- exp_p += i;
+-
+- PDEBUG("exp_len after computation: %08x\n", exp_len);
+- tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len;
+- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+- parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
+- tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+-
+- vud_len = 2 + mod_len;
+- memset(z90cMsg_p, 0, tmp_size);
+-
+- temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+- memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
+- tp6Hdr_p = (struct type6_hdr *)temp;
+- tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
+- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
+- memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
+- sizeof(static_PKE_function_code));
+- temp += sizeof(struct type6_hdr);
+- memcpy(temp, &static_cprb, sizeof(struct CPRB));
+- cprb_p = (struct CPRB *) temp;
+- cprb_p->usage_domain[0]= (unsigned char)cdx;
+- itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
+- temp += sizeof(struct CPRB);
+- memcpy(temp, &static_pke_function_and_rules,
+- sizeof(struct function_and_rules_block));
+- temp += sizeof(struct function_and_rules_block);
+- temp += 2;
+- if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) {
+- kfree(temp_exp);
+- return SEN_RELEASED;
+- }
+- if (is_empty(temp, mod_len)) {
+- kfree(temp_exp);
+- return SEN_USER_ERROR;
+- }
+- if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
+- kfree(temp_exp);
+- return SEN_NOT_AVAIL;
+- }
+- for (i = 2; i < mod_len; i++)
+- if (temp[i] == 0x00)
+- break;
+- if ((i < 9) || (i > (mod_len - 2))) {
+- kfree(temp_exp);
+- return SEN_NOT_AVAIL;
+- }
+- pad_len = i + 1;
+- vud_len = mod_len - pad_len;
+- memmove(temp, temp+pad_len, vud_len);
+- temp -= 2;
+- vud_len += 2;
+- itoLe2(&vud_len, temp);
+- temp += (vud_len);
+- keyb_p = (struct T6_keyBlock_hdr *)temp;
+- temp += sizeof(struct T6_keyBlock_hdr);
+- memcpy(temp, &static_public_key, sizeof(static_public_key));
+- key_p = (struct cca_public_key *)temp;
+- temp = key_p->pubSec.exponent;
+- memcpy(temp, exp_p, exp_len);
+- kfree(temp_exp);
+- temp += exp_len;
+- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(temp, mod_len))
+- return SEN_USER_ERROR;
+- key_p->pubSec.modulus_bit_len = 8 * mod_len;
+- key_p->pubSec.modulus_byte_len = mod_len;
+- key_p->pubSec.exponent_len = exp_len;
+- key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
+- key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
+- key_p->pubHdr.token_length = key_len;
+- key_len += 4;
+- itoLe2(&key_len, keyb_p->ulen);
+- key_len += 2;
+- itoLe2(&key_len, keyb_p->blen);
+- parmBlock_l -= pad_len;
+- itoLe2(&parmBlock_l, cprb_p->req_parml);
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
+- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+-{
+- int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
+- int long_len, pad_len, keyPartsLen, tmp_l;
+- unsigned char *tgt_p, *temp;
+- struct type6_hdr *tp6Hdr_p;
+- struct CPRB *cprb_p;
+- struct cca_token_hdr *keyHdr_p;
+- struct cca_pvt_ext_CRT_sec *pvtSec_p;
+- struct cca_public_sec *pubSec_p;
+-
+- mod_len = icaMsg_p->inputdatalength;
+- short_len = mod_len / 2;
+- long_len = 8 + short_len;
+- keyPartsLen = 3 * long_len + 2 * short_len;
+- pad_len = (8 - (keyPartsLen % 8)) % 8;
+- keyPartsLen += pad_len + mod_len;
+- tmp_size = FIXED_TYPE6_CR_LEN + keyPartsLen + mod_len;
+- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+- parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
+- vud_len = 2 + mod_len;
+- tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+-
+- memset(z90cMsg_p, 0, tmp_size);
+- tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+- memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr));
+- tp6Hdr_p = (struct type6_hdr *)tgt_p;
+- tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
+- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
+- tgt_p += sizeof(struct type6_hdr);
+- cprb_p = (struct CPRB *) tgt_p;
+- memcpy(tgt_p, &static_cprb, sizeof(struct CPRB));
+- cprb_p->usage_domain[0]= *((unsigned char *)(&(cdx))+3);
+- itoLe2(&parmBlock_l, cprb_p->req_parml);
+- memcpy(cprb_p->rpl_parml, cprb_p->req_parml,
+- sizeof(cprb_p->req_parml));
+- tgt_p += sizeof(struct CPRB);
+- memcpy(tgt_p, &static_pkd_function_and_rules,
+- sizeof(struct function_and_rules_block));
+- tgt_p += sizeof(struct function_and_rules_block);
+- itoLe2(&vud_len, tgt_p);
+- tgt_p += 2;
+- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, mod_len))
+- return SEN_USER_ERROR;
+- tgt_p += mod_len;
+- tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
+- sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
+- itoLe2(&tmp_l, tgt_p);
+- temp = tgt_p + 2;
+- tmp_l -= 2;
+- itoLe2(&tmp_l, temp);
+- tgt_p += sizeof(struct T6_keyBlock_hdr);
+- keyHdr_p = (struct cca_token_hdr *)tgt_p;
+- keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
+- tmp_l -= 4;
+- keyHdr_p->token_length = tmp_l;
+- tgt_p += sizeof(struct cca_token_hdr);
+- pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
+- pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
+- pvtSec_p->section_length =
+- sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
+- pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
+- pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
+- pvtSec_p->p_len = long_len;
+- pvtSec_p->q_len = short_len;
+- pvtSec_p->dp_len = long_len;
+- pvtSec_p->dq_len = short_len;
+- pvtSec_p->u_len = long_len;
+- pvtSec_p->mod_len = mod_len;
+- pvtSec_p->pad_len = pad_len;
+- tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
+- if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, long_len))
+- return SEN_USER_ERROR;
+- tgt_p += long_len;
+- if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, short_len))
+- return SEN_USER_ERROR;
+- tgt_p += short_len;
+- if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, long_len))
+- return SEN_USER_ERROR;
+- tgt_p += long_len;
+- if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, short_len))
+- return SEN_USER_ERROR;
+- tgt_p += short_len;
+- if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, long_len))
+- return SEN_USER_ERROR;
+- tgt_p += long_len;
+- tgt_p += pad_len;
+- memset(tgt_p, 0xFF, mod_len);
+- tgt_p += mod_len;
+- memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
+- pubSec_p = (struct cca_public_sec *) tgt_p;
+- pubSec_p->modulus_bit_len = 8 * mod_len;
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
+- int dev_type)
+-{
+- int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
+- int key_len, i;
+- unsigned char *temp_exp, *tgt_p, *temp, *exp_p;
+- struct type6_hdr *tp6Hdr_p;
+- struct CPRBX *cprbx_p;
+- struct cca_public_key *key_p;
+- struct T6_keyBlock_hdrX *keyb_p;
+-
+- temp_exp = kmalloc(256, GFP_KERNEL);
+- if (!temp_exp)
+- return EGETBUFF;
+- mod_len = icaMsg_p->inputdatalength;
+- if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
+- kfree(temp_exp);
+- return SEN_RELEASED;
+- }
+- if (is_empty(temp_exp, mod_len)) {
+- kfree(temp_exp);
+- return SEN_USER_ERROR;
+- }
+- exp_p = temp_exp;
+- for (i = 0; i < mod_len; i++)
+- if (exp_p[i])
+- break;
+- if (i >= mod_len) {
+- kfree(temp_exp);
+- return SEN_USER_ERROR;
+- }
+- exp_len = mod_len - i;
+- exp_p += i;
+- PDEBUG("exp_len after computation: %08x\n", exp_len);
+- tmp_size = FIXED_TYPE6_ME_EN_LENX + 2 * mod_len + exp_len;
+- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+- parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
+- tmp_size = tmp_size + CALLER_HEADER;
+- vud_len = 2 + mod_len;
+- memset(z90cMsg_p, 0, tmp_size);
+- tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+- memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
+- tp6Hdr_p = (struct type6_hdr *)tgt_p;
+- tp6Hdr_p->ToCardLen1 = total_CPRB_len;
+- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
+- memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
+- sizeof(static_PKE_function_code));
+- tgt_p += sizeof(struct type6_hdr);
+- memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
+- cprbx_p = (struct CPRBX *) tgt_p;
+- cprbx_p->domain = (unsigned short)cdx;
+- cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
+- tgt_p += sizeof(struct CPRBX);
+- if (dev_type == PCIXCC_MCL2)
+- memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2,
+- sizeof(struct function_and_rules_block));
+- else
+- memcpy(tgt_p, &static_pke_function_and_rulesX,
+- sizeof(struct function_and_rules_block));
+- tgt_p += sizeof(struct function_and_rules_block);
+-
+- tgt_p += 2;
+- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) {
+- kfree(temp_exp);
+- return SEN_RELEASED;
+- }
+- if (is_empty(tgt_p, mod_len)) {
+- kfree(temp_exp);
+- return SEN_USER_ERROR;
+- }
+- tgt_p -= 2;
+- *((short *)tgt_p) = (short) vud_len;
+- tgt_p += vud_len;
+- keyb_p = (struct T6_keyBlock_hdrX *)tgt_p;
+- tgt_p += sizeof(struct T6_keyBlock_hdrX);
+- memcpy(tgt_p, &static_public_key, sizeof(static_public_key));
+- key_p = (struct cca_public_key *)tgt_p;
+- temp = key_p->pubSec.exponent;
+- memcpy(temp, exp_p, exp_len);
+- kfree(temp_exp);
+- temp += exp_len;
+- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(temp, mod_len))
+- return SEN_USER_ERROR;
+- key_p->pubSec.modulus_bit_len = 8 * mod_len;
+- key_p->pubSec.modulus_byte_len = mod_len;
+- key_p->pubSec.exponent_len = exp_len;
+- key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
+- key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
+- key_p->pubHdr.token_length = key_len;
+- key_len += 4;
+- keyb_p->ulen = (unsigned short)key_len;
+- key_len += 2;
+- keyb_p->blen = (unsigned short)key_len;
+- cprbx_p->req_parml = parmBlock_l;
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
+- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
+- int dev_type)
+-{
+- int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
+- int long_len, pad_len, keyPartsLen, tmp_l;
+- unsigned char *tgt_p, *temp;
+- struct type6_hdr *tp6Hdr_p;
+- struct CPRBX *cprbx_p;
+- struct cca_token_hdr *keyHdr_p;
+- struct cca_pvt_ext_CRT_sec *pvtSec_p;
+- struct cca_public_sec *pubSec_p;
+-
+- mod_len = icaMsg_p->inputdatalength;
+- short_len = mod_len / 2;
+- long_len = 8 + short_len;
+- keyPartsLen = 3 * long_len + 2 * short_len;
+- pad_len = (8 - (keyPartsLen % 8)) % 8;
+- keyPartsLen += pad_len + mod_len;
+- tmp_size = FIXED_TYPE6_CR_LENX + keyPartsLen + mod_len;
+- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+- parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
+- vud_len = 2 + mod_len;
+- tmp_size = tmp_size + CALLER_HEADER;
+- memset(z90cMsg_p, 0, tmp_size);
+- tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+- memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
+- tp6Hdr_p = (struct type6_hdr *)tgt_p;
+- tp6Hdr_p->ToCardLen1 = total_CPRB_len;
+- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
+- tgt_p += sizeof(struct type6_hdr);
+- cprbx_p = (struct CPRBX *) tgt_p;
+- memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
+- cprbx_p->domain = (unsigned short)cdx;
+- cprbx_p->req_parml = parmBlock_l;
+- cprbx_p->rpl_msgbl = parmBlock_l;
+- tgt_p += sizeof(struct CPRBX);
+- if (dev_type == PCIXCC_MCL2)
+- memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2,
+- sizeof(struct function_and_rules_block));
+- else
+- memcpy(tgt_p, &static_pkd_function_and_rulesX,
+- sizeof(struct function_and_rules_block));
+- tgt_p += sizeof(struct function_and_rules_block);
+- *((short *)tgt_p) = (short) vud_len;
+- tgt_p += 2;
+- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, mod_len))
+- return SEN_USER_ERROR;
+- tgt_p += mod_len;
+- tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
+- sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
+- *((short *)tgt_p) = (short) tmp_l;
+- temp = tgt_p + 2;
+- tmp_l -= 2;
+- *((short *)temp) = (short) tmp_l;
+- tgt_p += sizeof(struct T6_keyBlock_hdr);
+- keyHdr_p = (struct cca_token_hdr *)tgt_p;
+- keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
+- tmp_l -= 4;
+- keyHdr_p->token_length = tmp_l;
+- tgt_p += sizeof(struct cca_token_hdr);
+- pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
+- pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
+- pvtSec_p->section_length =
+- sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
+- pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
+- pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
+- pvtSec_p->p_len = long_len;
+- pvtSec_p->q_len = short_len;
+- pvtSec_p->dp_len = long_len;
+- pvtSec_p->dq_len = short_len;
+- pvtSec_p->u_len = long_len;
+- pvtSec_p->mod_len = mod_len;
+- pvtSec_p->pad_len = pad_len;
+- tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
+- if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, long_len))
+- return SEN_USER_ERROR;
+- tgt_p += long_len;
+- if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, short_len))
+- return SEN_USER_ERROR;
+- tgt_p += short_len;
+- if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, long_len))
+- return SEN_USER_ERROR;
+- tgt_p += long_len;
+- if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, short_len))
+- return SEN_USER_ERROR;
+- tgt_p += short_len;
+- if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
+- return SEN_RELEASED;
+- if (is_empty(tgt_p, long_len))
+- return SEN_USER_ERROR;
+- tgt_p += long_len;
+- tgt_p += pad_len;
+- memset(tgt_p, 0xFF, mod_len);
+- tgt_p += mod_len;
+- memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
+- pubSec_p = (struct cca_public_sec *) tgt_p;
+- pubSec_p->modulus_bit_len = 8 * mod_len;
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICAMEX_msg_to_type50MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
+- union type50_msg *z90cMsg_p)
+-{
+- int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
+- unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
+- union type50_msg *tmp_type50_msg;
+-
+- mod_len = icaMex_p->inputdatalength;
+-
+- msg_size = ((mod_len <= 128) ? TYPE50_MEB1_LEN : TYPE50_MEB2_LEN) +
+- CALLER_HEADER;
+-
+- memset(z90cMsg_p, 0, msg_size);
+-
+- tmp_type50_msg = (union type50_msg *)
+- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+-
+- tmp_type50_msg->meb1.header.msg_type_code = TYPE50_TYPE_CODE;
+-
+- if (mod_len <= 128) {
+- tmp_type50_msg->meb1.header.msg_len = TYPE50_MEB1_LEN;
+- tmp_type50_msg->meb1.keyblock_type = TYPE50_MEB1_FMT;
+- mod_tgt = tmp_type50_msg->meb1.modulus;
+- mod_tgt_len = sizeof(tmp_type50_msg->meb1.modulus);
+- exp_tgt = tmp_type50_msg->meb1.exponent;
+- exp_tgt_len = sizeof(tmp_type50_msg->meb1.exponent);
+- inp_tgt = tmp_type50_msg->meb1.message;
+- inp_tgt_len = sizeof(tmp_type50_msg->meb1.message);
+- } else {
+- tmp_type50_msg->meb2.header.msg_len = TYPE50_MEB2_LEN;
+- tmp_type50_msg->meb2.keyblock_type = TYPE50_MEB2_FMT;
+- mod_tgt = tmp_type50_msg->meb2.modulus;
+- mod_tgt_len = sizeof(tmp_type50_msg->meb2.modulus);
+- exp_tgt = tmp_type50_msg->meb2.exponent;
+- exp_tgt_len = sizeof(tmp_type50_msg->meb2.exponent);
+- inp_tgt = tmp_type50_msg->meb2.message;
+- inp_tgt_len = sizeof(tmp_type50_msg->meb2.message);
+- }
+-
+- mod_tgt += (mod_tgt_len - mod_len);
+- if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(mod_tgt, mod_len))
+- return SEN_USER_ERROR;
+- exp_tgt += (exp_tgt_len - mod_len);
+- if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(exp_tgt, mod_len))
+- return SEN_USER_ERROR;
+- inp_tgt += (inp_tgt_len - mod_len);
+- if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(inp_tgt, mod_len))
+- return SEN_USER_ERROR;
+-
+- *z90cMsg_l_p = msg_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-static int
+-ICACRT_msg_to_type50CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
+- int *z90cMsg_l_p, union type50_msg *z90cMsg_p)
+-{
+- int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
+- dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len, long_offset;
+- unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt,
+- temp[8];
+- union type50_msg *tmp_type50_msg;
+-
+- mod_len = icaMsg_p->inputdatalength;
+- short_len = mod_len / 2;
+- long_len = mod_len / 2 + 8;
+- long_offset = 0;
+-
+- if (long_len > 128) {
+- memset(temp, 0x00, sizeof(temp));
+- if (copy_from_user(temp, icaMsg_p->np_prime, long_len-128))
+- return SEN_RELEASED;
+- if (!is_empty(temp, 8))
+- return SEN_NOT_AVAIL;
+- if (copy_from_user(temp, icaMsg_p->bp_key, long_len-128))
+- return SEN_RELEASED;
+- if (!is_empty(temp, 8))
+- return SEN_NOT_AVAIL;
+- if (copy_from_user(temp, icaMsg_p->u_mult_inv, long_len-128))
+- return SEN_RELEASED;
+- if (!is_empty(temp, 8))
+- return SEN_NOT_AVAIL;
+- long_offset = long_len - 128;
+- long_len = 128;
+- }
+-
+- tmp_size = ((long_len <= 64) ? TYPE50_CRB1_LEN : TYPE50_CRB2_LEN) +
+- CALLER_HEADER;
+-
+- memset(z90cMsg_p, 0, tmp_size);
+-
+- tmp_type50_msg = (union type50_msg *)
+- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+-
+- tmp_type50_msg->crb1.header.msg_type_code = TYPE50_TYPE_CODE;
+- if (long_len <= 64) {
+- tmp_type50_msg->crb1.header.msg_len = TYPE50_CRB1_LEN;
+- tmp_type50_msg->crb1.keyblock_type = TYPE50_CRB1_FMT;
+- p_tgt = tmp_type50_msg->crb1.p;
+- p_tgt_len = sizeof(tmp_type50_msg->crb1.p);
+- q_tgt = tmp_type50_msg->crb1.q;
+- q_tgt_len = sizeof(tmp_type50_msg->crb1.q);
+- dp_tgt = tmp_type50_msg->crb1.dp;
+- dp_tgt_len = sizeof(tmp_type50_msg->crb1.dp);
+- dq_tgt = tmp_type50_msg->crb1.dq;
+- dq_tgt_len = sizeof(tmp_type50_msg->crb1.dq);
+- u_tgt = tmp_type50_msg->crb1.u;
+- u_tgt_len = sizeof(tmp_type50_msg->crb1.u);
+- inp_tgt = tmp_type50_msg->crb1.message;
+- inp_tgt_len = sizeof(tmp_type50_msg->crb1.message);
+- } else {
+- tmp_type50_msg->crb2.header.msg_len = TYPE50_CRB2_LEN;
+- tmp_type50_msg->crb2.keyblock_type = TYPE50_CRB2_FMT;
+- p_tgt = tmp_type50_msg->crb2.p;
+- p_tgt_len = sizeof(tmp_type50_msg->crb2.p);
+- q_tgt = tmp_type50_msg->crb2.q;
+- q_tgt_len = sizeof(tmp_type50_msg->crb2.q);
+- dp_tgt = tmp_type50_msg->crb2.dp;
+- dp_tgt_len = sizeof(tmp_type50_msg->crb2.dp);
+- dq_tgt = tmp_type50_msg->crb2.dq;
+- dq_tgt_len = sizeof(tmp_type50_msg->crb2.dq);
+- u_tgt = tmp_type50_msg->crb2.u;
+- u_tgt_len = sizeof(tmp_type50_msg->crb2.u);
+- inp_tgt = tmp_type50_msg->crb2.message;
+- inp_tgt_len = sizeof(tmp_type50_msg->crb2.message);
+- }
+-
+- p_tgt += (p_tgt_len - long_len);
+- if (copy_from_user(p_tgt, icaMsg_p->np_prime + long_offset, long_len))
+- return SEN_RELEASED;
+- if (is_empty(p_tgt, long_len))
+- return SEN_USER_ERROR;
+- q_tgt += (q_tgt_len - short_len);
+- if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
+- return SEN_RELEASED;
+- if (is_empty(q_tgt, short_len))
+- return SEN_USER_ERROR;
+- dp_tgt += (dp_tgt_len - long_len);
+- if (copy_from_user(dp_tgt, icaMsg_p->bp_key + long_offset, long_len))
+- return SEN_RELEASED;
+- if (is_empty(dp_tgt, long_len))
+- return SEN_USER_ERROR;
+- dq_tgt += (dq_tgt_len - short_len);
+- if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
+- return SEN_RELEASED;
+- if (is_empty(dq_tgt, short_len))
+- return SEN_USER_ERROR;
+- u_tgt += (u_tgt_len - long_len);
+- if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv + long_offset, long_len))
+- return SEN_RELEASED;
+- if (is_empty(u_tgt, long_len))
+- return SEN_USER_ERROR;
+- inp_tgt += (inp_tgt_len - mod_len);
+- if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
+- return SEN_RELEASED;
+- if (is_empty(inp_tgt, mod_len))
+- return SEN_USER_ERROR;
+-
+- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+-
+- return 0;
+-}
+-
+-int
+-convert_request(unsigned char *buffer, int func, unsigned short function,
+- int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p)
+-{
+- if (dev_type == PCICA) {
+- if (func == ICARSACRT)
+- return ICACRT_msg_to_type4CRT_msg(
+- (struct ica_rsa_modexpo_crt *) buffer,
+- msg_l_p, (union type4_msg *) msg_p);
+- else
+- return ICAMEX_msg_to_type4MEX_msg(
+- (struct ica_rsa_modexpo *) buffer,
+- msg_l_p, (union type4_msg *) msg_p);
+- }
+- if (dev_type == PCICC) {
+- if (func == ICARSACRT)
+- return ICACRT_msg_to_type6CRT_msg(
+- (struct ica_rsa_modexpo_crt *) buffer,
+- cdx, msg_l_p, (struct type6_msg *)msg_p);
+- if (function == PCI_FUNC_KEY_ENCRYPT)
+- return ICAMEX_msg_to_type6MEX_en_msg(
+- (struct ica_rsa_modexpo *) buffer,
+- cdx, msg_l_p, (struct type6_msg *) msg_p);
+- else
+- return ICAMEX_msg_to_type6MEX_de_msg(
+- (struct ica_rsa_modexpo *) buffer,
+- cdx, msg_l_p, (struct type6_msg *) msg_p);
+- }
+- if ((dev_type == PCIXCC_MCL2) ||
+- (dev_type == PCIXCC_MCL3) ||
+- (dev_type == CEX2C)) {
+- if (func == ICARSACRT)
+- return ICACRT_msg_to_type6CRT_msgX(
+- (struct ica_rsa_modexpo_crt *) buffer,
+- cdx, msg_l_p, (struct type6_msg *) msg_p,
+- dev_type);
+- else
+- return ICAMEX_msg_to_type6MEX_msgX(
+- (struct ica_rsa_modexpo *) buffer,
+- cdx, msg_l_p, (struct type6_msg *) msg_p,
+- dev_type);
+- }
+- if (dev_type == CEX2A) {
+- if (func == ICARSACRT)
+- return ICACRT_msg_to_type50CRT_msg(
+- (struct ica_rsa_modexpo_crt *) buffer,
+- msg_l_p, (union type50_msg *) msg_p);
+- else
+- return ICAMEX_msg_to_type50MEX_msg(
+- (struct ica_rsa_modexpo *) buffer,
+- msg_l_p, (union type50_msg *) msg_p);
+- }
+-
+- return 0;
+-}
+-
+-int ext_bitlens_msg_count = 0;
+-static inline void
+-unset_ext_bitlens(void)
+-{
+- if (!ext_bitlens_msg_count) {
+- PRINTK("Unable to use coprocessors for extended bitlengths. "
+- "Using PCICAs/CEX2As (if present) for extended "
+- "bitlengths. This is not an error.\n");
+- ext_bitlens_msg_count++;
+- }
+- ext_bitlens = 0;
+-}
+-
+-int
+-convert_response(unsigned char *response, unsigned char *buffer,
+- int *respbufflen_p, unsigned char *resp_buff)
+-{
+- struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
+- struct error_hdr *errh_p = (struct error_hdr *) response;
+- struct type80_hdr *t80h_p = (struct type80_hdr *) response;
+- struct type84_hdr *t84h_p = (struct type84_hdr *) response;
+- struct type86_fmt2_msg *t86m_p = (struct type86_fmt2_msg *) response;
+- int reply_code, service_rc, service_rs, src_l;
+- unsigned char *src_p, *tgt_p;
+- struct CPRB *cprb_p;
+- struct CPRBX *cprbx_p;
+-
+- src_p = 0;
+- reply_code = 0;
+- service_rc = 0;
+- service_rs = 0;
+- src_l = 0;
+- switch (errh_p->type) {
+- case TYPE82_RSP_CODE:
+- case TYPE88_RSP_CODE:
+- reply_code = errh_p->reply_code;
+- src_p = (unsigned char *)errh_p;
+- PRINTK("Hardware error: Type %02X Message Header: "
+- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+- errh_p->type,
+- src_p[0], src_p[1], src_p[2], src_p[3],
+- src_p[4], src_p[5], src_p[6], src_p[7]);
+- break;
+- case TYPE80_RSP_CODE:
+- src_l = icaMsg_p->outputdatalength;
+- src_p = response + (int)t80h_p->len - src_l;
+- break;
+- case TYPE84_RSP_CODE:
+- src_l = icaMsg_p->outputdatalength;
+- src_p = response + (int)t84h_p->len - src_l;
+- break;
+- case TYPE86_RSP_CODE:
+- reply_code = t86m_p->header.reply_code;
+- if (reply_code != 0)
+- break;
+- cprb_p = (struct CPRB *)
+- (response + sizeof(struct type86_fmt2_msg));
+- cprbx_p = (struct CPRBX *) cprb_p;
+- if (cprb_p->cprb_ver_id != 0x02) {
+- le2toI(cprb_p->ccp_rtcode, &service_rc);
+- if (service_rc != 0) {
+- le2toI(cprb_p->ccp_rscode, &service_rs);
+- if ((service_rc == 8) && (service_rs == 66))
+- PDEBUG("Bad block format on PCICC\n");
+- else if ((service_rc == 8) && (service_rs == 65))
+- PDEBUG("Probably an even modulus on "
+- "PCICC\n");
+- else if ((service_rc == 8) && (service_rs == 770)) {
+- PDEBUG("Invalid key length on PCICC\n");
+- unset_ext_bitlens();
+- return REC_USE_PCICA;
+- }
+- else if ((service_rc == 8) && (service_rs == 783)) {
+- PDEBUG("Extended bitlengths not enabled"
+- "on PCICC\n");
+- unset_ext_bitlens();
+- return REC_USE_PCICA;
+- }
+- else
+- PRINTK("service rc/rs (PCICC): %d/%d\n",
+- service_rc, service_rs);
+- return REC_OPERAND_INV;
+- }
+- src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
+- src_p += 4;
+- le2toI(src_p, &src_l);
+- src_l -= 2;
+- src_p += 2;
+- } else {
+- service_rc = (int)cprbx_p->ccp_rtcode;
+- if (service_rc != 0) {
+- service_rs = (int) cprbx_p->ccp_rscode;
+- if ((service_rc == 8) && (service_rs == 66))
+- PDEBUG("Bad block format on PCIXCC\n");
+- else if ((service_rc == 8) && (service_rs == 65))
+- PDEBUG("Probably an even modulus on "
+- "PCIXCC\n");
+- else if ((service_rc == 8) && (service_rs == 770)) {
+- PDEBUG("Invalid key length on PCIXCC\n");
+- unset_ext_bitlens();
+- return REC_USE_PCICA;
+- }
+- else if ((service_rc == 8) && (service_rs == 783)) {
+- PDEBUG("Extended bitlengths not enabled"
+- "on PCIXCC\n");
+- unset_ext_bitlens();
+- return REC_USE_PCICA;
+- }
+- else
+- PRINTK("service rc/rs (PCIXCC): %d/%d\n",
+- service_rc, service_rs);
+- return REC_OPERAND_INV;
+- }
+- src_p = (unsigned char *)
+- cprbx_p + sizeof(struct CPRBX);
+- src_p += 4;
+- src_l = (int)(*((short *) src_p));
+- src_l -= 2;
+- src_p += 2;
+- }
+- break;
+- default:
+- src_p = (unsigned char *)errh_p;
+- PRINTK("Unrecognized Message Header: "
+- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+- src_p[0], src_p[1], src_p[2], src_p[3],
+- src_p[4], src_p[5], src_p[6], src_p[7]);
+- return REC_BAD_MESSAGE;
+- }
+-
+- if (reply_code)
+- switch (reply_code) {
+- case REP82_ERROR_MACHINE_FAILURE:
+- if (errh_p->type == TYPE82_RSP_CODE)
+- PRINTKW("Machine check failure\n");
+- else
+- PRINTKW("Module failure\n");
+- return REC_HARDWAR_ERR;
+- case REP82_ERROR_OPERAND_INVALID:
+- return REC_OPERAND_INV;
+- case REP88_ERROR_MESSAGE_MALFORMD:
+- PRINTKW("Message malformed\n");
+- return REC_OPERAND_INV;
+- case REP82_ERROR_OPERAND_SIZE:
+- return REC_OPERAND_SIZE;
+- case REP82_ERROR_EVEN_MOD_IN_OPND:
+- return REC_EVEN_MOD;
+- case REP82_ERROR_MESSAGE_TYPE:
+- return WRONG_DEVICE_TYPE;
+- case REP82_ERROR_TRANSPORT_FAIL:
+- PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
+- t86m_p->apfs[0], t86m_p->apfs[1],
+- t86m_p->apfs[2], t86m_p->apfs[3]);
+- return REC_HARDWAR_ERR;
+- default:
+- PRINTKW("reply code = %d\n", reply_code);
+- return REC_HARDWAR_ERR;
+- }
+-
+- if (service_rc != 0)
+- return REC_OPERAND_INV;
+-
+- if ((src_l > icaMsg_p->outputdatalength) ||
+- (src_l > RESPBUFFSIZE) ||
+- (src_l <= 0))
+- return REC_OPERAND_SIZE;
+-
+- PDEBUG("Length returned = %d\n", src_l);
+- tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
+- memcpy(tgt_p, src_p, src_l);
+- if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
+- memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
+- if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
+- return REC_INVALID_PAD;
+- }
+- *respbufflen_p = icaMsg_p->outputdatalength;
+- if (*respbufflen_p == 0)
+- PRINTK("Zero *respbufflen_p\n");
+-
+- return 0;
+-}
+-
+diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
+deleted file mode 100644
+index b2f20ab..0000000
+--- a/drivers/s390/crypto/z90main.c
++++ /dev/null
+@@ -1,3379 +0,0 @@
+-/*
+- * linux/drivers/s390/crypto/z90main.c
+- *
+- * z90crypt 1.3.3
+- *
+- * Copyright (C) 2001, 2005 IBM Corporation
+- * Author(s): Robert Burroughs (burrough at us.ibm.com)
+- * Eric Rossman (edrossma at us.ibm.com)
+- *
+- * Hotplug & misc device support: Jochen Roehrig (roehrig at de.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, 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 <asm/uaccess.h> // copy_(from|to)_user
+-#include <linux/compat.h>
+-#include <linux/compiler.h>
+-#include <linux/delay.h> // mdelay
+-#include <linux/init.h>
+-#include <linux/interrupt.h> // for tasklets
+-#include <linux/miscdevice.h>
+-#include <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/proc_fs.h>
+-#include <linux/syscalls.h>
+-#include "z90crypt.h"
+-#include "z90common.h"
+-
+-/**
+- * Defaults that may be modified.
+- */
+-
+-/**
+- * You can specify a different minor at compile time.
+- */
+-#ifndef Z90CRYPT_MINOR
+-#define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR
+-#endif
+-
+-/**
+- * You can specify a different domain at compile time or on the insmod
+- * command line.
+- */
+-#ifndef DOMAIN_INDEX
+-#define DOMAIN_INDEX -1
+-#endif
+-
+-/**
+- * This is the name under which the device is registered in /proc/modules.
+- */
+-#define REG_NAME "z90crypt"
+-
+-/**
+- * Cleanup should run every CLEANUPTIME seconds and should clean up requests
+- * older than CLEANUPTIME seconds in the past.
+- */
+-#ifndef CLEANUPTIME
+-#define CLEANUPTIME 15
+-#endif
+-
+-/**
+- * Config should run every CONFIGTIME seconds
+- */
+-#ifndef CONFIGTIME
+-#define CONFIGTIME 30
+-#endif
+-
+-/**
+- * The first execution of the config task should take place
+- * immediately after initialization
+- */
+-#ifndef INITIAL_CONFIGTIME
+-#define INITIAL_CONFIGTIME 1
+-#endif
+-
+-/**
+- * Reader should run every READERTIME milliseconds
+- * With the 100Hz patch for s390, z90crypt can lock the system solid while
+- * under heavy load. We'll try to avoid that.
+- */
+-#ifndef READERTIME
+-#if HZ > 1000
+-#define READERTIME 2
+-#else
+-#define READERTIME 10
+-#endif
+-#endif
+-
+-/**
+- * turn long device array index into device pointer
+- */
+-#define LONG2DEVPTR(ndx) (z90crypt.device_p[(ndx)])
+-
+-/**
+- * turn short device array index into long device array index
+- */
+-#define SHRT2LONG(ndx) (z90crypt.overall_device_x.device_index[(ndx)])
+-
+-/**
+- * turn short device array index into device pointer
+- */
+-#define SHRT2DEVPTR(ndx) LONG2DEVPTR(SHRT2LONG(ndx))
+-
+-/**
+- * Status for a work-element
+- */
+-#define STAT_DEFAULT 0x00 // request has not been processed
+-
+-#define STAT_ROUTED 0x80 // bit 7: requests get routed to specific device
+- // else, device is determined each write
+-#define STAT_FAILED 0x40 // bit 6: this bit is set if the request failed
+- // before being sent to the hardware.
+-#define STAT_WRITTEN 0x30 // bits 5-4: work to be done, not sent to device
+-// 0x20 // UNUSED state
+-#define STAT_READPEND 0x10 // bits 5-4: work done, we're returning data now
+-#define STAT_NOWORK 0x00 // bits off: no work on any queue
+-#define STAT_RDWRMASK 0x30 // mask for bits 5-4
+-
+-/**
+- * Macros to check the status RDWRMASK
+- */
+-#define CHK_RDWRMASK(statbyte) ((statbyte) & STAT_RDWRMASK)
+-#define SET_RDWRMASK(statbyte, newval) \
+- {(statbyte) &= ~STAT_RDWRMASK; (statbyte) |= newval;}
+-
+-/**
+- * Audit Trail. Progress of a Work element
+- * audit[0]: Unless noted otherwise, these bits are all set by the process
+- */
+-#define FP_COPYFROM 0x80 // Caller's buffer has been copied to work element
+-#define FP_BUFFREQ 0x40 // Low Level buffer requested
+-#define FP_BUFFGOT 0x20 // Low Level buffer obtained
+-#define FP_SENT 0x10 // Work element sent to a crypto device
+- // (may be set by process or by reader task)
+-#define FP_PENDING 0x08 // Work element placed on pending queue
+- // (may be set by process or by reader task)
+-#define FP_REQUEST 0x04 // Work element placed on request queue
+-#define FP_ASLEEP 0x02 // Work element about to sleep
+-#define FP_AWAKE 0x01 // Work element has been awakened
+-
+-/**
+- * audit[1]: These bits are set by the reader task and/or the cleanup task
+- */
+-#define FP_NOTPENDING 0x80 // Work element removed from pending queue
+-#define FP_AWAKENING 0x40 // Caller about to be awakened
+-#define FP_TIMEDOUT 0x20 // Caller timed out
+-#define FP_RESPSIZESET 0x10 // Response size copied to work element
+-#define FP_RESPADDRCOPIED 0x08 // Response address copied to work element
+-#define FP_RESPBUFFCOPIED 0x04 // Response buffer copied to work element
+-#define FP_REMREQUEST 0x02 // Work element removed from request queue
+-#define FP_SIGNALED 0x01 // Work element was awakened by a signal
+-
+-/**
+- * audit[2]: unused
+- */
+-
+-/**
+- * state of the file handle in private_data.status
+- */
+-#define STAT_OPEN 0
+-#define STAT_CLOSED 1
+-
+-/**
+- * PID() expands to the process ID of the current process
+- */
+-#define PID() (current->pid)
+-
+-/**
+- * Selected Constants. The number of APs and the number of devices
+- */
+-#ifndef Z90CRYPT_NUM_APS
+-#define Z90CRYPT_NUM_APS 64
+-#endif
+-#ifndef Z90CRYPT_NUM_DEVS
+-#define Z90CRYPT_NUM_DEVS Z90CRYPT_NUM_APS
+-#endif
+-
+-/**
+- * Buffer size for receiving responses. The maximum Response Size
+- * is actually the maximum request size, since in an error condition
+- * the request itself may be returned unchanged.
+- */
+-#define MAX_RESPONSE_SIZE 0x0000077C
+-
+-/**
+- * A count and status-byte mask
+- */
+-struct status {
+- int st_count; // # of enabled devices
+- int disabled_count; // # of disabled devices
+- int user_disabled_count; // # of devices disabled via proc fs
+- unsigned char st_mask[Z90CRYPT_NUM_APS]; // current status mask
+-};
+-
+-/**
+- * The array of device indexes is a mechanism for fast indexing into
+- * a long (and sparse) array. For instance, if APs 3, 9 and 47 are
+- * installed, z90CDeviceIndex[0] is 3, z90CDeviceIndex[1] is 9, and
+- * z90CDeviceIndex[2] is 47.
+- */
+-struct device_x {
+- int device_index[Z90CRYPT_NUM_DEVS];
+-};
+-
+-/**
+- * All devices are arranged in a single array: 64 APs
+- */
+-struct device {
+- int dev_type; // PCICA, PCICC, PCIXCC_MCL2,
+- // PCIXCC_MCL3, CEX2C, CEX2A
+- enum devstat dev_stat; // current device status
+- int dev_self_x; // Index in array
+- int disabled; // Set when device is in error
+- int user_disabled; // Set when device is disabled by user
+- int dev_q_depth; // q depth
+- unsigned char * dev_resp_p; // Response buffer address
+- int dev_resp_l; // Response Buffer length
+- int dev_caller_count; // Number of callers
+- int dev_total_req_cnt; // # requests for device since load
+- struct list_head dev_caller_list; // List of callers
+-};
+-
+-/**
+- * There's a struct status and a struct device_x for each device type.
+- */
+-struct hdware_block {
+- struct status hdware_mask;
+- struct status type_mask[Z90CRYPT_NUM_TYPES];
+- struct device_x type_x_addr[Z90CRYPT_NUM_TYPES];
+- unsigned char device_type_array[Z90CRYPT_NUM_APS];
+-};
+-
+-/**
+- * z90crypt is the topmost data structure in the hierarchy.
+- */
+-struct z90crypt {
+- int max_count; // Nr of possible crypto devices
+- struct status mask;
+- int q_depth_array[Z90CRYPT_NUM_DEVS];
+- int dev_type_array[Z90CRYPT_NUM_DEVS];
+- struct device_x overall_device_x; // array device indexes
+- struct device * device_p[Z90CRYPT_NUM_DEVS];
+- int terminating;
+- int domain_established;// TRUE: domain has been found
+- int cdx; // Crypto Domain Index
+- int len; // Length of this data structure
+- struct hdware_block *hdware_info;
+-};
+-
+-/**
+- * An array of these structures is pointed to from dev_caller
+- * The length of the array depends on the device type. For APs,
+- * there are 8.
+- *
+- * The caller buffer is allocated to the user at OPEN. At WRITE,
+- * it contains the request; at READ, the response. The function
+- * send_to_crypto_device converts the request to device-dependent
+- * form and use the caller's OPEN-allocated buffer for the response.
+- *
+- * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
+- * because that points to it, see the discussion in z90hardware.c.
+- * Search for "extended request message block".
+- */
+-struct caller {
+- int caller_buf_l; // length of original request
+- unsigned char * caller_buf_p; // Original request on WRITE
+- int caller_dev_dep_req_l; // len device dependent request
+- unsigned char * caller_dev_dep_req_p; // Device dependent form
+- unsigned char caller_id[8]; // caller-supplied message id
+- struct list_head caller_liste;
+- unsigned char caller_dev_dep_req[MAX_RESPONSE_SIZE];
+-};
+-
+-/**
+- * Function prototypes from z90hardware.c
+- */
+-enum hdstat query_online(int deviceNr, int cdx, int resetNr, int *q_depth,
+- int *dev_type);
+-enum devstat reset_device(int deviceNr, int cdx, int resetNr);
+-enum devstat send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext);
+-enum devstat receive_from_AP(int dev_nr, int cdx, int resplen,
+- unsigned char *resp, unsigned char *psmid);
+-int convert_request(unsigned char *buffer, int func, unsigned short function,
+- int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p);
+-int convert_response(unsigned char *response, unsigned char *buffer,
+- int *respbufflen_p, unsigned char *resp_buff);
+-
+-/**
+- * Low level function prototypes
+- */
+-static int create_z90crypt(int *cdx_p);
+-static int refresh_z90crypt(int *cdx_p);
+-static int find_crypto_devices(struct status *deviceMask);
+-static int create_crypto_device(int index);
+-static int destroy_crypto_device(int index);
+-static void destroy_z90crypt(void);
+-static int refresh_index_array(struct status *status_str,
+- struct device_x *index_array);
+-static int probe_device_type(struct device *devPtr);
+-static int probe_PCIXCC_type(struct device *devPtr);
+-
+-/**
+- * proc fs definitions
+- */
+-static struct proc_dir_entry *z90crypt_entry;
+-
+-/**
+- * data structures
+- */
+-
+-/**
+- * work_element.opener points back to this structure
+- */
+-struct priv_data {
+- pid_t opener_pid;
+- unsigned char status; // 0: open 1: closed
+-};
+-
+-/**
+- * A work element is allocated for each request
+- */
+-struct work_element {
+- struct priv_data *priv_data;
+- pid_t pid;
+- int devindex; // index of device processing this w_e
+- // (If request did not specify device,
+- // -1 until placed onto a queue)
+- int devtype;
+- struct list_head liste; // used for requestq and pendingq
+- char buffer[128]; // local copy of user request
+- int buff_size; // size of the buffer for the request
+- char resp_buff[RESPBUFFSIZE];
+- int resp_buff_size;
+- char __user * resp_addr; // address of response in user space
+- unsigned int funccode; // function code of request
+- wait_queue_head_t waitq;
+- unsigned long requestsent; // time at which the request was sent
+- atomic_t alarmrung; // wake-up signal
+- unsigned char caller_id[8]; // pid + counter, for this w_e
+- unsigned char status[1]; // bits to mark status of the request
+- unsigned char audit[3]; // record of work element's progress
+- unsigned char * requestptr; // address of request buffer
+- int retcode; // return code of request
+-};
+-
+-/**
+- * High level function prototypes
+- */
+-static int z90crypt_open(struct inode *, struct file *);
+-static int z90crypt_release(struct inode *, struct file *);
+-static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *);
+-static ssize_t z90crypt_write(struct file *, const char __user *,
+- size_t, loff_t *);
+-static long z90crypt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
+-static long z90crypt_compat_ioctl(struct file *, unsigned int, unsigned long);
+-
+-static void z90crypt_reader_task(unsigned long);
+-static void z90crypt_schedule_reader_task(unsigned long);
+-static void z90crypt_config_task(unsigned long);
+-static void z90crypt_cleanup_task(unsigned long);
+-
+-static int z90crypt_status(char *, char **, off_t, int, int *, void *);
+-static int z90crypt_status_write(struct file *, const char __user *,
+- unsigned long, void *);
+-
+-/**
+- * Storage allocated at initialization and used throughout the life of
+- * this insmod
+- */
+-static int domain = DOMAIN_INDEX;
+-static struct z90crypt z90crypt;
+-static int quiesce_z90crypt;
+-static spinlock_t queuespinlock;
+-static struct list_head request_list;
+-static int requestq_count;
+-static struct list_head pending_list;
+-static int pendingq_count;
+-
+-static struct tasklet_struct reader_tasklet;
+-static struct timer_list reader_timer;
+-static struct timer_list config_timer;
+-static struct timer_list cleanup_timer;
+-static atomic_t total_open;
+-static atomic_t z90crypt_step;
+-
+-static struct file_operations z90crypt_fops = {
+- .owner = THIS_MODULE,
+- .read = z90crypt_read,
+- .write = z90crypt_write,
+- .unlocked_ioctl = z90crypt_unlocked_ioctl,
+-#ifdef CONFIG_COMPAT
+- .compat_ioctl = z90crypt_compat_ioctl,
+-#endif
+- .open = z90crypt_open,
+- .release = z90crypt_release
+-};
+-
+-static struct miscdevice z90crypt_misc_device = {
+- .minor = Z90CRYPT_MINOR,
+- .name = DEV_NAME,
+- .fops = &z90crypt_fops,
+-};
+-
+-/**
+- * Documentation values.
+- */
+-MODULE_AUTHOR("zSeries Linux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
+- "and Jochen Roehrig");
+-MODULE_DESCRIPTION("zSeries Linux Cryptographic Coprocessor device driver, "
+- "Copyright 2001, 2005 IBM Corporation");
+-MODULE_LICENSE("GPL");
+-module_param(domain, int, 0);
+-MODULE_PARM_DESC(domain, "domain index for device");
+-
+-#ifdef CONFIG_COMPAT
+-/**
+- * ioctl32 conversion routines
+- */
+-struct ica_rsa_modexpo_32 { // For 32-bit callers
+- compat_uptr_t inputdata;
+- unsigned int inputdatalength;
+- compat_uptr_t outputdata;
+- unsigned int outputdatalength;
+- compat_uptr_t b_key;
+- compat_uptr_t n_modulus;
+-};
+-
+-static long
+-trans_modexpo32(struct file *filp, unsigned int cmd, unsigned long arg)
+-{
+- struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg);
+- struct ica_rsa_modexpo_32 mex32k;
+- struct ica_rsa_modexpo __user *mex64;
+- long ret = 0;
+- unsigned int i;
+-
+- if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32)))
+- return -EFAULT;
+- mex64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo));
+- if (!access_ok(VERIFY_WRITE, mex64, sizeof(struct ica_rsa_modexpo)))
+- return -EFAULT;
+- if (copy_from_user(&mex32k, mex32u, sizeof(struct ica_rsa_modexpo_32)))
+- return -EFAULT;
+- if (__put_user(compat_ptr(mex32k.inputdata), &mex64->inputdata) ||
+- __put_user(mex32k.inputdatalength, &mex64->inputdatalength) ||
+- __put_user(compat_ptr(mex32k.outputdata), &mex64->outputdata) ||
+- __put_user(mex32k.outputdatalength, &mex64->outputdatalength) ||
+- __put_user(compat_ptr(mex32k.b_key), &mex64->b_key) ||
+- __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus))
+- return -EFAULT;
+- ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)mex64);
+- if (!ret)
+- if (__get_user(i, &mex64->outputdatalength) ||
+- __put_user(i, &mex32u->outputdatalength))
+- ret = -EFAULT;
+- return ret;
+-}
+-
+-struct ica_rsa_modexpo_crt_32 { // For 32-bit callers
+- compat_uptr_t inputdata;
+- unsigned int inputdatalength;
+- compat_uptr_t outputdata;
+- unsigned int outputdatalength;
+- compat_uptr_t bp_key;
+- compat_uptr_t bq_key;
+- compat_uptr_t np_prime;
+- compat_uptr_t nq_prime;
+- compat_uptr_t u_mult_inv;
+-};
+-
+-static long
+-trans_modexpo_crt32(struct file *filp, unsigned int cmd, unsigned long arg)
+-{
+- struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg);
+- struct ica_rsa_modexpo_crt_32 crt32k;
+- struct ica_rsa_modexpo_crt __user *crt64;
+- long ret = 0;
+- unsigned int i;
+-
+- if (!access_ok(VERIFY_WRITE, crt32u,
+- sizeof(struct ica_rsa_modexpo_crt_32)))
+- return -EFAULT;
+- crt64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo_crt));
+- if (!access_ok(VERIFY_WRITE, crt64, sizeof(struct ica_rsa_modexpo_crt)))
+- return -EFAULT;
+- if (copy_from_user(&crt32k, crt32u,
+- sizeof(struct ica_rsa_modexpo_crt_32)))
+- return -EFAULT;
+- if (__put_user(compat_ptr(crt32k.inputdata), &crt64->inputdata) ||
+- __put_user(crt32k.inputdatalength, &crt64->inputdatalength) ||
+- __put_user(compat_ptr(crt32k.outputdata), &crt64->outputdata) ||
+- __put_user(crt32k.outputdatalength, &crt64->outputdatalength) ||
+- __put_user(compat_ptr(crt32k.bp_key), &crt64->bp_key) ||
+- __put_user(compat_ptr(crt32k.bq_key), &crt64->bq_key) ||
+- __put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime) ||
+- __put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime) ||
+- __put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv))
+- return -EFAULT;
+- ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)crt64);
+- if (!ret)
+- if (__get_user(i, &crt64->outputdatalength) ||
+- __put_user(i, &crt32u->outputdatalength))
+- ret = -EFAULT;
+- return ret;
+-}
+-
+-static long
+-z90crypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+-{
+- switch (cmd) {
+- case ICAZ90STATUS:
+- case Z90QUIESCE:
+- case Z90STAT_TOTALCOUNT:
+- case Z90STAT_PCICACOUNT:
+- case Z90STAT_PCICCCOUNT:
+- case Z90STAT_PCIXCCCOUNT:
+- case Z90STAT_PCIXCCMCL2COUNT:
+- case Z90STAT_PCIXCCMCL3COUNT:
+- case Z90STAT_CEX2CCOUNT:
+- case Z90STAT_REQUESTQ_COUNT:
+- case Z90STAT_PENDINGQ_COUNT:
+- case Z90STAT_TOTALOPEN_COUNT:
+- case Z90STAT_DOMAIN_INDEX:
+- case Z90STAT_STATUS_MASK:
+- case Z90STAT_QDEPTH_MASK:
+- case Z90STAT_PERDEV_REQCNT:
+- return z90crypt_unlocked_ioctl(filp, cmd, arg);
+- case ICARSAMODEXPO:
+- return trans_modexpo32(filp, cmd, arg);
+- case ICARSACRT:
+- return trans_modexpo_crt32(filp, cmd, arg);
+- default:
+- return -ENOIOCTLCMD;
+- }
+-}
+-#endif
+-
+-/**
+- * The module initialization code.
+- */
+-static int __init
+-z90crypt_init_module(void)
+-{
+- int result, nresult;
+- struct proc_dir_entry *entry;
+-
+- PDEBUG("PID %d\n", PID());
+-
+- if ((domain < -1) || (domain > 15)) {
+- PRINTKW("Invalid param: domain = %d. Not loading.\n", domain);
+- return -EINVAL;
+- }
+-
+- /* Register as misc device with given minor (or get a dynamic one). */
+- result = misc_register(&z90crypt_misc_device);
+- if (result < 0) {
+- PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
+- z90crypt_misc_device.minor, result);
+- return result;
+- }
+-
+- PDEBUG("Registered " DEV_NAME " with result %d\n", result);
+-
+- result = create_z90crypt(&domain);
+- if (result != 0) {
+- PRINTKW("create_z90crypt (domain index %d) failed with %d.\n",
+- domain, result);
+- result = -ENOMEM;
+- goto init_module_cleanup;
+- }
+-
+- if (result == 0) {
+- PRINTKN("Version %d.%d.%d loaded, built on %s %s\n",
+- z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT,
+- __DATE__, __TIME__);
+- PDEBUG("create_z90crypt (domain index %d) successful.\n",
+- domain);
+- } else
+- PRINTK("No devices at startup\n");
+-
+- /* Initialize globals. */
+- spin_lock_init(&queuespinlock);
+-
+- INIT_LIST_HEAD(&pending_list);
+- pendingq_count = 0;
+-
+- INIT_LIST_HEAD(&request_list);
+- requestq_count = 0;
+-
+- quiesce_z90crypt = 0;
+-
+- atomic_set(&total_open, 0);
+- atomic_set(&z90crypt_step, 0);
+-
+- /* Set up the cleanup task. */
+- init_timer(&cleanup_timer);
+- cleanup_timer.function = z90crypt_cleanup_task;
+- cleanup_timer.data = 0;
+- cleanup_timer.expires = jiffies + (CLEANUPTIME * HZ);
+- add_timer(&cleanup_timer);
+-
+- /* Set up the proc file system */
+- entry = create_proc_entry("driver/z90crypt", 0644, 0);
+- if (entry) {
+- entry->nlink = 1;
+- entry->data = 0;
+- entry->read_proc = z90crypt_status;
+- entry->write_proc = z90crypt_status_write;
+- }
+- else
+- PRINTK("Couldn't create z90crypt proc entry\n");
+- z90crypt_entry = entry;
+-
+- /* Set up the configuration task. */
+- init_timer(&config_timer);
+- config_timer.function = z90crypt_config_task;
+- config_timer.data = 0;
+- config_timer.expires = jiffies + (INITIAL_CONFIGTIME * HZ);
+- add_timer(&config_timer);
+-
+- /* Set up the reader task */
+- tasklet_init(&reader_tasklet, z90crypt_reader_task, 0);
+- init_timer(&reader_timer);
+- reader_timer.function = z90crypt_schedule_reader_task;
+- reader_timer.data = 0;
+- reader_timer.expires = jiffies + (READERTIME * HZ / 1000);
+- add_timer(&reader_timer);
+-
+- return 0; // success
+-
+-init_module_cleanup:
+- if ((nresult = misc_deregister(&z90crypt_misc_device)))
+- PRINTK("misc_deregister failed with %d.\n", nresult);
+- else
+- PDEBUG("misc_deregister successful.\n");
+-
+- return result; // failure
+-}
+-
+-/**
+- * The module termination code
+- */
+-static void __exit
+-z90crypt_cleanup_module(void)
+-{
+- int nresult;
+-
+- PDEBUG("PID %d\n", PID());
+-
+- remove_proc_entry("driver/z90crypt", 0);
+-
+- if ((nresult = misc_deregister(&z90crypt_misc_device)))
+- PRINTK("misc_deregister failed with %d.\n", nresult);
+- else
+- PDEBUG("misc_deregister successful.\n");
+-
+- /* Remove the tasks */
+- tasklet_kill(&reader_tasklet);
+- del_timer(&reader_timer);
+- del_timer(&config_timer);
+- del_timer(&cleanup_timer);
+-
+- destroy_z90crypt();
+-
+- PRINTKN("Unloaded.\n");
+-}
+-
+-/**
+- * Functions running under a process id
+- *
+- * The I/O functions:
+- * z90crypt_open
+- * z90crypt_release
+- * z90crypt_read
+- * z90crypt_write
+- * z90crypt_unlocked_ioctl
+- * z90crypt_status
+- * z90crypt_status_write
+- * disable_card
+- * enable_card
+- *
+- * Helper functions:
+- * z90crypt_rsa
+- * z90crypt_prepare
+- * z90crypt_send
+- * z90crypt_process_results
+- *
+- */
+-static int
+-z90crypt_open(struct inode *inode, struct file *filp)
+-{
+- struct priv_data *private_data_p;
+-
+- if (quiesce_z90crypt)
+- return -EQUIESCE;
+-
+- private_data_p = kzalloc(sizeof(struct priv_data), GFP_KERNEL);
+- if (!private_data_p) {
+- PRINTK("Memory allocate failed\n");
+- return -ENOMEM;
+- }
+-
+- private_data_p->status = STAT_OPEN;
+- private_data_p->opener_pid = PID();
+- filp->private_data = private_data_p;
+- atomic_inc(&total_open);
+-
+- return 0;
+-}
+-
+-static int
+-z90crypt_release(struct inode *inode, struct file *filp)
+-{
+- struct priv_data *private_data_p = filp->private_data;
+-
+- PDEBUG("PID %d (filp %p)\n", PID(), filp);
+-
+- private_data_p->status = STAT_CLOSED;
+- memset(private_data_p, 0, sizeof(struct priv_data));
+- kfree(private_data_p);
+- atomic_dec(&total_open);
+-
+- return 0;
+-}
+-
+-/*
+- * there are two read functions, of which compile options will choose one
+- * without USE_GET_RANDOM_BYTES
+- * => read() always returns -EPERM;
+- * otherwise
+- * => read() uses get_random_bytes() kernel function
+- */
+-#ifndef USE_GET_RANDOM_BYTES
+-/**
+- * z90crypt_read will not be supported beyond z90crypt 1.3.1
+- */
+-static ssize_t
+-z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+-{
+- PDEBUG("filp %p (PID %d)\n", filp, PID());
+- return -EPERM;
+-}
+-#else // we want to use get_random_bytes
+-/**
+- * read() just returns a string of random bytes. Since we have no way
+- * to generate these cryptographically, we just execute get_random_bytes
+- * for the length specified.
+- */
+-#include <linux/random.h>
+-static ssize_t
+-z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+-{
+- unsigned char *temp_buff;
+-
+- PDEBUG("filp %p (PID %d)\n", filp, PID());
+-
+- if (quiesce_z90crypt)
+- return -EQUIESCE;
+- if (count < 0) {
+- PRINTK("Requested random byte count negative: %ld\n", count);
+- return -EINVAL;
+- }
+- if (count > RESPBUFFSIZE) {
+- PDEBUG("count[%d] > RESPBUFFSIZE", count);
+- return -EINVAL;
+- }
+- if (count == 0)
+- return 0;
+- temp_buff = kmalloc(RESPBUFFSIZE, GFP_KERNEL);
+- if (!temp_buff) {
+- PRINTK("Memory allocate failed\n");
+- return -ENOMEM;
+- }
+- get_random_bytes(temp_buff, count);
+-
+- if (copy_to_user(buf, temp_buff, count) != 0) {
+- kfree(temp_buff);
+- return -EFAULT;
+- }
+- kfree(temp_buff);
+- return count;
+-}
+-#endif
+-
+-/**
+- * Write is is not allowed
+- */
+-static ssize_t
+-z90crypt_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+-{
+- PDEBUG("filp %p (PID %d)\n", filp, PID());
+- return -EPERM;
+-}
+-
+-/**
+- * New status functions
+- */
+-static inline int
+-get_status_totalcount(void)
+-{
+- return z90crypt.hdware_info->hdware_mask.st_count;
+-}
+-
+-static inline int
+-get_status_PCICAcount(void)
+-{
+- return z90crypt.hdware_info->type_mask[PCICA].st_count;
+-}
+-
+-static inline int
+-get_status_PCICCcount(void)
+-{
+- return z90crypt.hdware_info->type_mask[PCICC].st_count;
+-}
+-
+-static inline int
+-get_status_PCIXCCcount(void)
+-{
+- return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count +
+- z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
+-}
+-
+-static inline int
+-get_status_PCIXCCMCL2count(void)
+-{
+- return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count;
+-}
+-
+-static inline int
+-get_status_PCIXCCMCL3count(void)
+-{
+- return z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
+-}
+-
+-static inline int
+-get_status_CEX2Ccount(void)
+-{
+- return z90crypt.hdware_info->type_mask[CEX2C].st_count;
+-}
+-
+-static inline int
+-get_status_CEX2Acount(void)
+-{
+- return z90crypt.hdware_info->type_mask[CEX2A].st_count;
+-}
+-
+-static inline int
+-get_status_requestq_count(void)
+-{
+- return requestq_count;
+-}
+-
+-static inline int
+-get_status_pendingq_count(void)
+-{
+- return pendingq_count;
+-}
+-
+-static inline int
+-get_status_totalopen_count(void)
+-{
+- return atomic_read(&total_open);
+-}
+-
+-static inline int
+-get_status_domain_index(void)
+-{
+- return z90crypt.cdx;
+-}
+-
+-static inline unsigned char *
+-get_status_status_mask(unsigned char status[Z90CRYPT_NUM_APS])
+-{
+- int i, ix;
+-
+- memcpy(status, z90crypt.hdware_info->device_type_array,
+- Z90CRYPT_NUM_APS);
+-
+- for (i = 0; i < get_status_totalcount(); i++) {
+- ix = SHRT2LONG(i);
+- if (LONG2DEVPTR(ix)->user_disabled)
+- status[ix] = 0x0d;
+- }
+-
+- return status;
+-}
+-
+-static inline unsigned char *
+-get_status_qdepth_mask(unsigned char qdepth[Z90CRYPT_NUM_APS])
+-{
+- int i, ix;
+-
+- memset(qdepth, 0, Z90CRYPT_NUM_APS);
+-
+- for (i = 0; i < get_status_totalcount(); i++) {
+- ix = SHRT2LONG(i);
+- qdepth[ix] = LONG2DEVPTR(ix)->dev_caller_count;
+- }
+-
+- return qdepth;
+-}
+-
+-static inline unsigned int *
+-get_status_perdevice_reqcnt(unsigned int reqcnt[Z90CRYPT_NUM_APS])
+-{
+- int i, ix;
+-
+- memset(reqcnt, 0, Z90CRYPT_NUM_APS * sizeof(int));
+-
+- for (i = 0; i < get_status_totalcount(); i++) {
+- ix = SHRT2LONG(i);
+- reqcnt[ix] = LONG2DEVPTR(ix)->dev_total_req_cnt;
+- }
+-
+- return reqcnt;
+-}
+-
+-static inline void
+-init_work_element(struct work_element *we_p,
+- struct priv_data *priv_data, pid_t pid)
+-{
+- int step;
+-
+- we_p->requestptr = (unsigned char *)we_p + sizeof(struct work_element);
+- /* Come up with a unique id for this caller. */
+- step = atomic_inc_return(&z90crypt_step);
+- memcpy(we_p->caller_id+0, (void *) &pid, sizeof(pid));
+- memcpy(we_p->caller_id+4, (void *) &step, sizeof(step));
+- we_p->pid = pid;
+- we_p->priv_data = priv_data;
+- we_p->status[0] = STAT_DEFAULT;
+- we_p->audit[0] = 0x00;
+- we_p->audit[1] = 0x00;
+- we_p->audit[2] = 0x00;
+- we_p->resp_buff_size = 0;
+- we_p->retcode = 0;
+- we_p->devindex = -1;
+- we_p->devtype = -1;
+- atomic_set(&we_p->alarmrung, 0);
+- init_waitqueue_head(&we_p->waitq);
+- INIT_LIST_HEAD(&(we_p->liste));
+-}
+-
+-static inline int
+-allocate_work_element(struct work_element **we_pp,
+- struct priv_data *priv_data_p, pid_t pid)
+-{
+- struct work_element *we_p;
+-
+- we_p = (struct work_element *) get_zeroed_page(GFP_KERNEL);
+- if (!we_p)
+- return -ENOMEM;
+- init_work_element(we_p, priv_data_p, pid);
+- *we_pp = we_p;
+- return 0;
+-}
+-
+-static inline void
+-remove_device(struct device *device_p)
+-{
+- if (!device_p || (device_p->disabled != 0))
+- return;
+- device_p->disabled = 1;
+- z90crypt.hdware_info->type_mask[device_p->dev_type].disabled_count++;
+- z90crypt.hdware_info->hdware_mask.disabled_count++;
+-}
+-
+-/**
+- * Bitlength limits for each card
+- *
+- * There are new MCLs which allow more bitlengths. See the table for details.
+- * The MCL must be applied and the newer bitlengths enabled for these to work.
+- *
+- * Card Type Old limit New limit
+- * PCICA ??-2048 same (the lower limit is less than 128 bit...)
+- * PCICC 512-1024 512-2048
+- * PCIXCC_MCL2 512-2048 ----- (applying any GA LIC will make an MCL3 card)
+- * PCIXCC_MCL3 ----- 128-2048
+- * CEX2C 512-2048 128-2048
+- * CEX2A ??-2048 same (the lower limit is less than 128 bit...)
+- *
+- * ext_bitlens (extended bitlengths) is a global, since you should not apply an
+- * MCL to just one card in a machine. We assume, at first, that all cards have
+- * these capabilities.
+- */
+-int ext_bitlens = 1; // This is global
+-#define PCIXCC_MIN_MOD_SIZE 16 // 128 bits
+-#define OLD_PCIXCC_MIN_MOD_SIZE 64 // 512 bits
+-#define PCICC_MIN_MOD_SIZE 64 // 512 bits
+-#define OLD_PCICC_MAX_MOD_SIZE 128 // 1024 bits
+-#define MAX_MOD_SIZE 256 // 2048 bits
+-
+-static inline int
+-select_device_type(int *dev_type_p, int bytelength)
+-{
+- static int count = 0;
+- int PCICA_avail, PCIXCC_MCL3_avail, CEX2C_avail, CEX2A_avail,
+- index_to_use;
+- struct status *stat;
+- if ((*dev_type_p != PCICC) && (*dev_type_p != PCICA) &&
+- (*dev_type_p != PCIXCC_MCL2) && (*dev_type_p != PCIXCC_MCL3) &&
+- (*dev_type_p != CEX2C) && (*dev_type_p != CEX2A) &&
+- (*dev_type_p != ANYDEV))
+- return -1;
+- if (*dev_type_p != ANYDEV) {
+- stat = &z90crypt.hdware_info->type_mask[*dev_type_p];
+- if (stat->st_count >
+- (stat->disabled_count + stat->user_disabled_count))
+- return 0;
+- return -1;
+- }
+-
+- /**
+- * Assumption: PCICA, PCIXCC_MCL3, CEX2C, and CEX2A are all similar in
+- * speed.
+- *
+- * PCICA and CEX2A do NOT co-exist, so it would be either one or the
+- * other present.
+- */
+- stat = &z90crypt.hdware_info->type_mask[PCICA];
+- PCICA_avail = stat->st_count -
+- (stat->disabled_count + stat->user_disabled_count);
+- stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL3];
+- PCIXCC_MCL3_avail = stat->st_count -
+- (stat->disabled_count + stat->user_disabled_count);
+- stat = &z90crypt.hdware_info->type_mask[CEX2C];
+- CEX2C_avail = stat->st_count -
+- (stat->disabled_count + stat->user_disabled_count);
+- stat = &z90crypt.hdware_info->type_mask[CEX2A];
+- CEX2A_avail = stat->st_count -
+- (stat->disabled_count + stat->user_disabled_count);
+- if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail || CEX2A_avail) {
+- /**
+- * bitlength is a factor, PCICA or CEX2A are the most capable,
+- * even with the new MCL for PCIXCC.
+- */
+- if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
+- (!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
+- if (PCICA_avail) {
+- *dev_type_p = PCICA;
+- return 0;
+- }
+- if (CEX2A_avail) {
+- *dev_type_p = CEX2A;
+- return 0;
+- }
+- return -1;
+- }
+-
+- index_to_use = count % (PCICA_avail + PCIXCC_MCL3_avail +
+- CEX2C_avail + CEX2A_avail);
+- if (index_to_use < PCICA_avail)
+- *dev_type_p = PCICA;
+- else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail))
+- *dev_type_p = PCIXCC_MCL3;
+- else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail +
+- CEX2C_avail))
+- *dev_type_p = CEX2C;
+- else
+- *dev_type_p = CEX2A;
+- count++;
+- return 0;
+- }
+-
+- /* Less than OLD_PCIXCC_MIN_MOD_SIZE cannot go to a PCIXCC_MCL2 */
+- if (bytelength < OLD_PCIXCC_MIN_MOD_SIZE)
+- return -1;
+- stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL2];
+- if (stat->st_count >
+- (stat->disabled_count + stat->user_disabled_count)) {
+- *dev_type_p = PCIXCC_MCL2;
+- return 0;
+- }
+-
+- /**
+- * Less than PCICC_MIN_MOD_SIZE or more than OLD_PCICC_MAX_MOD_SIZE
+- * (if we don't have the MCL applied and the newer bitlengths enabled)
+- * cannot go to a PCICC
+- */
+- if ((bytelength < PCICC_MIN_MOD_SIZE) ||
+- (!ext_bitlens && (bytelength > OLD_PCICC_MAX_MOD_SIZE))) {
+- return -1;
+- }
+- stat = &z90crypt.hdware_info->type_mask[PCICC];
+- if (stat->st_count >
+- (stat->disabled_count + stat->user_disabled_count)) {
+- *dev_type_p = PCICC;
+- return 0;
+- }
+-
+- return -1;
+-}
+-
+-/**
+- * Try the selected number, then the selected type (can be ANYDEV)
+- */
+-static inline int
+-select_device(int *dev_type_p, int *device_nr_p, int bytelength)
+-{
+- int i, indx, devTp, low_count, low_indx;
+- struct device_x *index_p;
+- struct device *dev_ptr;
+-
+- PDEBUG("device type = %d, index = %d\n", *dev_type_p, *device_nr_p);
+- if ((*device_nr_p >= 0) && (*device_nr_p < Z90CRYPT_NUM_DEVS)) {
+- PDEBUG("trying index = %d\n", *device_nr_p);
+- dev_ptr = z90crypt.device_p[*device_nr_p];
+-
+- if (dev_ptr &&
+- (dev_ptr->dev_stat != DEV_GONE) &&
+- (dev_ptr->disabled == 0) &&
+- (dev_ptr->user_disabled == 0)) {
+- PDEBUG("selected by number, index = %d\n",
+- *device_nr_p);
+- *dev_type_p = dev_ptr->dev_type;
+- return *device_nr_p;
+- }
+- }
+- *device_nr_p = -1;
+- PDEBUG("trying type = %d\n", *dev_type_p);
+- devTp = *dev_type_p;
+- if (select_device_type(&devTp, bytelength) == -1) {
+- PDEBUG("failed to select by type\n");
+- return -1;
+- }
+- PDEBUG("selected type = %d\n", devTp);
+- index_p = &z90crypt.hdware_info->type_x_addr[devTp];
+- low_count = 0x0000FFFF;
+- low_indx = -1;
+- for (i = 0; i < z90crypt.hdware_info->type_mask[devTp].st_count; i++) {
+- indx = index_p->device_index[i];
+- dev_ptr = z90crypt.device_p[indx];
+- if (dev_ptr &&
+- (dev_ptr->dev_stat != DEV_GONE) &&
+- (dev_ptr->disabled == 0) &&
+- (dev_ptr->user_disabled == 0) &&
+- (devTp == dev_ptr->dev_type) &&
+- (low_count > dev_ptr->dev_caller_count)) {
+- low_count = dev_ptr->dev_caller_count;
+- low_indx = indx;
+- }
+- }
+- *device_nr_p = low_indx;
+- return low_indx;
+-}
+-
+-static inline int
+-send_to_crypto_device(struct work_element *we_p)
+-{
+- struct caller *caller_p;
+- struct device *device_p;
+- int dev_nr;
+- int bytelen = ((struct ica_rsa_modexpo *)we_p->buffer)->inputdatalength;
+-
+- if (!we_p->requestptr)
+- return SEN_FATAL_ERROR;
+- caller_p = (struct caller *)we_p->requestptr;
+- dev_nr = we_p->devindex;
+- if (select_device(&we_p->devtype, &dev_nr, bytelen) == -1) {
+- if (z90crypt.hdware_info->hdware_mask.st_count != 0)
+- return SEN_RETRY;
+- else
+- return SEN_NOT_AVAIL;
+- }
+- we_p->devindex = dev_nr;
+- device_p = z90crypt.device_p[dev_nr];
+- if (!device_p)
+- return SEN_NOT_AVAIL;
+- if (device_p->dev_type != we_p->devtype)
+- return SEN_RETRY;
+- if (device_p->dev_caller_count >= device_p->dev_q_depth)
+- return SEN_QUEUE_FULL;
+- PDEBUG("device number prior to send: %d\n", dev_nr);
+- switch (send_to_AP(dev_nr, z90crypt.cdx,
+- caller_p->caller_dev_dep_req_l,
+- caller_p->caller_dev_dep_req_p)) {
+- case DEV_SEN_EXCEPTION:
+- PRINTKC("Exception during send to device %d\n", dev_nr);
+- z90crypt.terminating = 1;
+- return SEN_FATAL_ERROR;
+- case DEV_GONE:
+- PRINTK("Device %d not available\n", dev_nr);
+- remove_device(device_p);
+- return SEN_NOT_AVAIL;
+- case DEV_EMPTY:
+- return SEN_NOT_AVAIL;
+- case DEV_NO_WORK:
+- return SEN_FATAL_ERROR;
+- case DEV_BAD_MESSAGE:
+- return SEN_USER_ERROR;
+- case DEV_QUEUE_FULL:
+- return SEN_QUEUE_FULL;
+- default:
+- case DEV_ONLINE:
+- break;
+- }
+- list_add_tail(&(caller_p->caller_liste), &(device_p->dev_caller_list));
+- device_p->dev_caller_count++;
+- return 0;
+-}
+-
+-/**
+- * Send puts the user's work on one of two queues:
+- * the pending queue if the send was successful
+- * the request queue if the send failed because device full or busy
+- */
+-static inline int
+-z90crypt_send(struct work_element *we_p, const char *buf)
+-{
+- int rv;
+-
+- PDEBUG("PID %d\n", PID());
+-
+- if (CHK_RDWRMASK(we_p->status[0]) != STAT_NOWORK) {
+- PDEBUG("PID %d tried to send more work but has outstanding "
+- "work.\n", PID());
+- return -EWORKPEND;
+- }
+- we_p->devindex = -1; // Reset device number
+- spin_lock_irq(&queuespinlock);
+- rv = send_to_crypto_device(we_p);
+- switch (rv) {
+- case 0:
+- we_p->requestsent = jiffies;
+- we_p->audit[0] |= FP_SENT;
+- list_add_tail(&we_p->liste, &pending_list);
+- ++pendingq_count;
+- we_p->audit[0] |= FP_PENDING;
+- break;
+- case SEN_BUSY:
+- case SEN_QUEUE_FULL:
+- rv = 0;
+- we_p->devindex = -1; // any device will do
+- we_p->requestsent = jiffies;
+- list_add_tail(&we_p->liste, &request_list);
+- ++requestq_count;
+- we_p->audit[0] |= FP_REQUEST;
+- break;
+- case SEN_RETRY:
+- rv = -ERESTARTSYS;
+- break;
+- case SEN_NOT_AVAIL:
+- PRINTK("*** No devices available.\n");
+- rv = we_p->retcode = -ENODEV;
+- we_p->status[0] |= STAT_FAILED;
+- break;
+- case REC_OPERAND_INV:
+- case REC_OPERAND_SIZE:
+- case REC_EVEN_MOD:
+- case REC_INVALID_PAD:
+- rv = we_p->retcode = -EINVAL;
+- we_p->status[0] |= STAT_FAILED;
+- break;
+- default:
+- we_p->retcode = rv;
+- we_p->status[0] |= STAT_FAILED;
+- break;
+- }
+- if (rv != -ERESTARTSYS)
+- SET_RDWRMASK(we_p->status[0], STAT_WRITTEN);
+- spin_unlock_irq(&queuespinlock);
+- if (rv == 0)
+- tasklet_schedule(&reader_tasklet);
+- return rv;
+-}
+-
+-/**
+- * process_results copies the user's work from kernel space.
+- */
+-static inline int
+-z90crypt_process_results(struct work_element *we_p, char __user *buf)
+-{
+- int rv;
+-
+- PDEBUG("we_p %p (PID %d)\n", we_p, PID());
+-
+- LONG2DEVPTR(we_p->devindex)->dev_total_req_cnt++;
+- SET_RDWRMASK(we_p->status[0], STAT_READPEND);
+-
+- rv = 0;
+- if (!we_p->buffer) {
+- PRINTK("we_p %p PID %d in STAT_READPEND: buffer NULL.\n",
+- we_p, PID());
+- rv = -ENOBUFF;
+- }
+-
+- if (!rv)
+- if ((rv = copy_to_user(buf, we_p->buffer, we_p->buff_size))) {
+- PDEBUG("copy_to_user failed: rv = %d\n", rv);
+- rv = -EFAULT;
+- }
+-
+- if (!rv)
+- rv = we_p->retcode;
+- if (!rv)
+- if (we_p->resp_buff_size
+- && copy_to_user(we_p->resp_addr, we_p->resp_buff,
+- we_p->resp_buff_size))
+- rv = -EFAULT;
+-
+- SET_RDWRMASK(we_p->status[0], STAT_NOWORK);
+- return rv;
+-}
+-
+-static unsigned char NULL_psmid[8] =
+-{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+-
+-/**
+- * Used in device configuration functions
+- */
+-#define MAX_RESET 90
+-
+-/**
+- * This is used only for PCICC support
+- */
+-static inline int
+-is_PKCS11_padded(unsigned char *buffer, int length)
+-{
+- int i;
+- if ((buffer[0] != 0x00) || (buffer[1] != 0x01))
+- return 0;
+- for (i = 2; i < length; i++)
+- if (buffer[i] != 0xFF)
+- break;
+- if ((i < 10) || (i == length))
+- return 0;
+- if (buffer[i] != 0x00)
+- return 0;
+- return 1;
+-}
+-
+-/**
+- * This is used only for PCICC support
+- */
+-static inline int
+-is_PKCS12_padded(unsigned char *buffer, int length)
+-{
+- int i;
+- if ((buffer[0] != 0x00) || (buffer[1] != 0x02))
+- return 0;
+- for (i = 2; i < length; i++)
+- if (buffer[i] == 0x00)
+- break;
+- if ((i < 10) || (i == length))
+- return 0;
+- if (buffer[i] != 0x00)
+- return 0;
+- return 1;
+-}
+-
+-/**
+- * builds struct caller and converts message from generic format to
+- * device-dependent format
+- * func is ICARSAMODEXPO or ICARSACRT
+- * function is PCI_FUNC_KEY_ENCRYPT or PCI_FUNC_KEY_DECRYPT
+- */
+-static inline int
+-build_caller(struct work_element *we_p, short function)
+-{
+- int rv;
+- struct caller *caller_p = (struct caller *)we_p->requestptr;
+-
+- if ((we_p->devtype != PCICC) && (we_p->devtype != PCICA) &&
+- (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
+- (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A))
+- return SEN_NOT_AVAIL;
+-
+- memcpy(caller_p->caller_id, we_p->caller_id,
+- sizeof(caller_p->caller_id));
+- caller_p->caller_dev_dep_req_p = caller_p->caller_dev_dep_req;
+- caller_p->caller_dev_dep_req_l = MAX_RESPONSE_SIZE;
+- caller_p->caller_buf_p = we_p->buffer;
+- INIT_LIST_HEAD(&(caller_p->caller_liste));
+-
+- rv = convert_request(we_p->buffer, we_p->funccode, function,
+- z90crypt.cdx, we_p->devtype,
+- &caller_p->caller_dev_dep_req_l,
+- caller_p->caller_dev_dep_req_p);
+- if (rv) {
+- if (rv == SEN_NOT_AVAIL)
+- PDEBUG("request can't be processed on hdwr avail\n");
+- else
+- PRINTK("Error from convert_request: %d\n", rv);
+- }
+- else
+- memcpy(&(caller_p->caller_dev_dep_req_p[4]), we_p->caller_id,8);
+- return rv;
+-}
+-
+-static inline void
+-unbuild_caller(struct device *device_p, struct caller *caller_p)
+-{
+- if (!caller_p)
+- return;
+- if (caller_p->caller_liste.next && caller_p->caller_liste.prev)
+- if (!list_empty(&caller_p->caller_liste)) {
+- list_del_init(&caller_p->caller_liste);
+- device_p->dev_caller_count--;
+- }
+- memset(caller_p->caller_id, 0, sizeof(caller_p->caller_id));
+-}
+-
+-static inline int
+-get_crypto_request_buffer(struct work_element *we_p)
+-{
+- struct ica_rsa_modexpo *mex_p;
+- struct ica_rsa_modexpo_crt *crt_p;
+- unsigned char *temp_buffer;
+- short function;
+- int rv;
+-
+- mex_p = (struct ica_rsa_modexpo *) we_p->buffer;
+- crt_p = (struct ica_rsa_modexpo_crt *) we_p->buffer;
+-
+- PDEBUG("device type input = %d\n", we_p->devtype);
+-
+- if (z90crypt.terminating)
+- return REC_NO_RESPONSE;
+- if (memcmp(we_p->caller_id, NULL_psmid, 8) == 0) {
+- PRINTK("psmid zeroes\n");
+- return SEN_FATAL_ERROR;
+- }
+- if (!we_p->buffer) {
+- PRINTK("buffer pointer NULL\n");
+- return SEN_USER_ERROR;
+- }
+- if (!we_p->requestptr) {
+- PRINTK("caller pointer NULL\n");
+- return SEN_USER_ERROR;
+- }
+-
+- if ((we_p->devtype != PCICA) && (we_p->devtype != PCICC) &&
+- (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
+- (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A) &&
+- (we_p->devtype != ANYDEV)) {
+- PRINTK("invalid device type\n");
+- return SEN_USER_ERROR;
+- }
+-
+- if ((mex_p->inputdatalength < 1) ||
+- (mex_p->inputdatalength > MAX_MOD_SIZE)) {
+- PRINTK("inputdatalength[%d] is not valid\n",
+- mex_p->inputdatalength);
+- return SEN_USER_ERROR;
+- }
+-
+- if (mex_p->outputdatalength < mex_p->inputdatalength) {
+- PRINTK("outputdatalength[%d] < inputdatalength[%d]\n",
+- mex_p->outputdatalength, mex_p->inputdatalength);
+- return SEN_USER_ERROR;
+- }
+-
+- if (!mex_p->inputdata || !mex_p->outputdata) {
+- PRINTK("inputdata[%p] or outputdata[%p] is NULL\n",
+- mex_p->outputdata, mex_p->inputdata);
+- return SEN_USER_ERROR;
+- }
+-
+- /**
+- * As long as outputdatalength is big enough, we can set the
+- * outputdatalength equal to the inputdatalength, since that is the
+- * number of bytes we will copy in any case
+- */
+- mex_p->outputdatalength = mex_p->inputdatalength;
+-
+- rv = 0;
+- switch (we_p->funccode) {
+- case ICARSAMODEXPO:
+- if (!mex_p->b_key || !mex_p->n_modulus)
+- rv = SEN_USER_ERROR;
+- break;
+- case ICARSACRT:
+- if (!IS_EVEN(crt_p->inputdatalength)) {
+- PRINTK("inputdatalength[%d] is odd, CRT form\n",
+- crt_p->inputdatalength);
+- rv = SEN_USER_ERROR;
+- break;
+- }
+- if (!crt_p->bp_key ||
+- !crt_p->bq_key ||
+- !crt_p->np_prime ||
+- !crt_p->nq_prime ||
+- !crt_p->u_mult_inv) {
+- PRINTK("CRT form, bad data: %p/%p/%p/%p/%p\n",
+- crt_p->bp_key, crt_p->bq_key,
+- crt_p->np_prime, crt_p->nq_prime,
+- crt_p->u_mult_inv);
+- rv = SEN_USER_ERROR;
+- }
+- break;
+- default:
+- PRINTK("bad func = %d\n", we_p->funccode);
+- rv = SEN_USER_ERROR;
+- break;
+- }
+- if (rv != 0)
+- return rv;
+-
+- if (select_device_type(&we_p->devtype, mex_p->inputdatalength) < 0)
+- return SEN_NOT_AVAIL;
+-
+- temp_buffer = (unsigned char *)we_p + sizeof(struct work_element) +
+- sizeof(struct caller);
+- if (copy_from_user(temp_buffer, mex_p->inputdata,
+- mex_p->inputdatalength) != 0)
+- return SEN_RELEASED;
+-
+- function = PCI_FUNC_KEY_ENCRYPT;
+- switch (we_p->devtype) {
+- /* PCICA and CEX2A do everything with a simple RSA mod-expo operation */
+- case PCICA:
+- case CEX2A:
+- function = PCI_FUNC_KEY_ENCRYPT;
+- break;
+- /**
+- * PCIXCC_MCL2 does all Mod-Expo form with a simple RSA mod-expo
+- * operation, and all CRT forms with a PKCS-1.2 format decrypt.
+- * PCIXCC_MCL3 and CEX2C do all Mod-Expo and CRT forms with a simple RSA
+- * mod-expo operation
+- */
+- case PCIXCC_MCL2:
+- if (we_p->funccode == ICARSAMODEXPO)
+- function = PCI_FUNC_KEY_ENCRYPT;
+- else
+- function = PCI_FUNC_KEY_DECRYPT;
+- break;
+- case PCIXCC_MCL3:
+- case CEX2C:
+- if (we_p->funccode == ICARSAMODEXPO)
+- function = PCI_FUNC_KEY_ENCRYPT;
+- else
+- function = PCI_FUNC_KEY_DECRYPT;
+- break;
+- /**
+- * PCICC does everything as a PKCS-1.2 format request
+- */
+- case PCICC:
+- /* PCICC cannot handle input that is is PKCS#1.1 padded */
+- if (is_PKCS11_padded(temp_buffer, mex_p->inputdatalength)) {
+- return SEN_NOT_AVAIL;
+- }
+- if (we_p->funccode == ICARSAMODEXPO) {
+- if (is_PKCS12_padded(temp_buffer,
+- mex_p->inputdatalength))
+- function = PCI_FUNC_KEY_ENCRYPT;
+- else
+- function = PCI_FUNC_KEY_DECRYPT;
+- } else
+- /* all CRT forms are decrypts */
+- function = PCI_FUNC_KEY_DECRYPT;
+- break;
+- }
+- PDEBUG("function: %04x\n", function);
+- rv = build_caller(we_p, function);
+- PDEBUG("rv from build_caller = %d\n", rv);
+- return rv;
+-}
+-
+-static inline int
+-z90crypt_prepare(struct work_element *we_p, unsigned int funccode,
+- const char __user *buffer)
+-{
+- int rv;
+-
+- we_p->devindex = -1;
+- if (funccode == ICARSAMODEXPO)
+- we_p->buff_size = sizeof(struct ica_rsa_modexpo);
+- else
+- we_p->buff_size = sizeof(struct ica_rsa_modexpo_crt);
+-
+- if (copy_from_user(we_p->buffer, buffer, we_p->buff_size))
+- return -EFAULT;
+-
+- we_p->audit[0] |= FP_COPYFROM;
+- SET_RDWRMASK(we_p->status[0], STAT_WRITTEN);
+- we_p->funccode = funccode;
+- we_p->devtype = -1;
+- we_p->audit[0] |= FP_BUFFREQ;
+- rv = get_crypto_request_buffer(we_p);
+- switch (rv) {
+- case 0:
+- we_p->audit[0] |= FP_BUFFGOT;
+- break;
+- case SEN_USER_ERROR:
+- rv = -EINVAL;
+- break;
+- case SEN_QUEUE_FULL:
+- rv = 0;
+- break;
+- case SEN_RELEASED:
+- rv = -EFAULT;
+- break;
+- case REC_NO_RESPONSE:
+- rv = -ENODEV;
+- break;
+- case SEN_NOT_AVAIL:
+- case EGETBUFF:
+- rv = -EGETBUFF;
+- break;
+- default:
+- PRINTK("rv = %d\n", rv);
+- rv = -EGETBUFF;
+- break;
+- }
+- if (CHK_RDWRMASK(we_p->status[0]) == STAT_WRITTEN)
+- SET_RDWRMASK(we_p->status[0], STAT_DEFAULT);
+- return rv;
+-}
+-
+-static inline void
+-purge_work_element(struct work_element *we_p)
+-{
+- struct list_head *lptr;
+-
+- spin_lock_irq(&queuespinlock);
+- list_for_each(lptr, &request_list) {
+- if (lptr == &we_p->liste) {
+- list_del_init(lptr);
+- requestq_count--;
+- break;
+- }
+- }
+- list_for_each(lptr, &pending_list) {
+- if (lptr == &we_p->liste) {
+- list_del_init(lptr);
+- pendingq_count--;
+- break;
+- }
+- }
+- spin_unlock_irq(&queuespinlock);
+-}
+-
+-/**
+- * Build the request and send it.
+- */
+-static inline int
+-z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct work_element *we_p;
+- int rv;
+-
+- if ((rv = allocate_work_element(&we_p, private_data_p, pid))) {
+- PDEBUG("PID %d: allocate_work_element returned ENOMEM\n", pid);
+- return rv;
+- }
+- if ((rv = z90crypt_prepare(we_p, cmd, (const char __user *)arg)))
+- PDEBUG("PID %d: rv = %d from z90crypt_prepare\n", pid, rv);
+- if (!rv)
+- if ((rv = z90crypt_send(we_p, (const char *)arg)))
+- PDEBUG("PID %d: rv %d from z90crypt_send.\n", pid, rv);
+- if (!rv) {
+- we_p->audit[0] |= FP_ASLEEP;
+- wait_event(we_p->waitq, atomic_read(&we_p->alarmrung));
+- we_p->audit[0] |= FP_AWAKE;
+- rv = we_p->retcode;
+- }
+- if (!rv)
+- rv = z90crypt_process_results(we_p, (char __user *)arg);
+-
+- if ((we_p->status[0] & STAT_FAILED)) {
+- switch (rv) {
+- /**
+- * EINVAL *after* receive is almost always a padding error or
+- * length error issued by a coprocessor (not an accelerator).
+- * We convert this return value to -EGETBUFF which should
+- * trigger a fallback to software.
+- */
+- case -EINVAL:
+- if ((we_p->devtype != PCICA) &&
+- (we_p->devtype != CEX2A))
+- rv = -EGETBUFF;
+- break;
+- case -ETIMEOUT:
+- if (z90crypt.mask.st_count > 0)
+- rv = -ERESTARTSYS; // retry with another
+- else
+- rv = -ENODEV; // no cards left
+- /* fall through to clean up request queue */
+- case -ERESTARTSYS:
+- case -ERELEASED:
+- switch (CHK_RDWRMASK(we_p->status[0])) {
+- case STAT_WRITTEN:
+- purge_work_element(we_p);
+- break;
+- case STAT_READPEND:
+- case STAT_NOWORK:
+- default:
+- break;
+- }
+- break;
+- default:
+- we_p->status[0] ^= STAT_FAILED;
+- break;
+- }
+- }
+- free_page((long)we_p);
+- return rv;
+-}
+-
+-/**
+- * This function is a little long, but it's really just one large switch
+- * statement.
+- */
+-static long
+-z90crypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+-{
+- struct priv_data *private_data_p = filp->private_data;
+- unsigned char *status;
+- unsigned char *qdepth;
+- unsigned int *reqcnt;
+- struct ica_z90_status *pstat;
+- int ret, i, loopLim, tempstat;
+- static int deprecated_msg_count1 = 0;
+- static int deprecated_msg_count2 = 0;
+-
+- PDEBUG("filp %p (PID %d), cmd 0x%08X\n", filp, PID(), cmd);
+- PDEBUG("cmd 0x%08X: dir %s, size 0x%04X, type 0x%02X, nr 0x%02X\n",
+- cmd,
+- !_IOC_DIR(cmd) ? "NO"
+- : ((_IOC_DIR(cmd) == (_IOC_READ|_IOC_WRITE)) ? "RW"
+- : ((_IOC_DIR(cmd) == _IOC_READ) ? "RD"
+- : "WR")),
+- _IOC_SIZE(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd));
+-
+- if (_IOC_TYPE(cmd) != Z90_IOCTL_MAGIC) {
+- PRINTK("cmd 0x%08X contains bad magic\n", cmd);
+- return -ENOTTY;
+- }
+-
+- ret = 0;
+- switch (cmd) {
+- case ICARSAMODEXPO:
+- case ICARSACRT:
+- if (quiesce_z90crypt) {
+- ret = -EQUIESCE;
+- break;
+- }
+- ret = -ENODEV; // Default if no devices
+- loopLim = z90crypt.hdware_info->hdware_mask.st_count -
+- (z90crypt.hdware_info->hdware_mask.disabled_count +
+- z90crypt.hdware_info->hdware_mask.user_disabled_count);
+- for (i = 0; i < loopLim; i++) {
+- ret = z90crypt_rsa(private_data_p, PID(), cmd, arg);
+- if (ret != -ERESTARTSYS)
+- break;
+- }
+- if (ret == -ERESTARTSYS)
+- ret = -ENODEV;
+- break;
+-
+- case Z90STAT_TOTALCOUNT:
+- tempstat = get_status_totalcount();
+- if (copy_to_user((int __user *)arg, &tempstat,sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_PCICACOUNT:
+- tempstat = get_status_PCICAcount();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_PCICCCOUNT:
+- tempstat = get_status_PCICCcount();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_PCIXCCMCL2COUNT:
+- tempstat = get_status_PCIXCCMCL2count();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_PCIXCCMCL3COUNT:
+- tempstat = get_status_PCIXCCMCL3count();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_CEX2CCOUNT:
+- tempstat = get_status_CEX2Ccount();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_CEX2ACOUNT:
+- tempstat = get_status_CEX2Acount();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_REQUESTQ_COUNT:
+- tempstat = get_status_requestq_count();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_PENDINGQ_COUNT:
+- tempstat = get_status_pendingq_count();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_TOTALOPEN_COUNT:
+- tempstat = get_status_totalopen_count();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_DOMAIN_INDEX:
+- tempstat = get_status_domain_index();
+- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90STAT_STATUS_MASK:
+- status = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
+- if (!status) {
+- PRINTK("kmalloc for status failed!\n");
+- ret = -ENOMEM;
+- break;
+- }
+- get_status_status_mask(status);
+- if (copy_to_user((char __user *) arg, status, Z90CRYPT_NUM_APS)
+- != 0)
+- ret = -EFAULT;
+- kfree(status);
+- break;
+-
+- case Z90STAT_QDEPTH_MASK:
+- qdepth = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
+- if (!qdepth) {
+- PRINTK("kmalloc for qdepth failed!\n");
+- ret = -ENOMEM;
+- break;
+- }
+- get_status_qdepth_mask(qdepth);
+- if (copy_to_user((char __user *) arg, qdepth, Z90CRYPT_NUM_APS) != 0)
+- ret = -EFAULT;
+- kfree(qdepth);
+- break;
+-
+- case Z90STAT_PERDEV_REQCNT:
+- reqcnt = kmalloc(sizeof(int) * Z90CRYPT_NUM_APS, GFP_KERNEL);
+- if (!reqcnt) {
+- PRINTK("kmalloc for reqcnt failed!\n");
+- ret = -ENOMEM;
+- break;
+- }
+- get_status_perdevice_reqcnt(reqcnt);
+- if (copy_to_user((char __user *) arg, reqcnt,
+- Z90CRYPT_NUM_APS * sizeof(int)) != 0)
+- ret = -EFAULT;
+- kfree(reqcnt);
+- break;
+-
+- /* THIS IS DEPRECATED. USE THE NEW STATUS CALLS */
+- case ICAZ90STATUS:
+- if (deprecated_msg_count1 < 20) {
+- PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
+- deprecated_msg_count1++;
+- if (deprecated_msg_count1 == 20)
+- PRINTK("No longer issuing messages related to "
+- "deprecated call to ICAZ90STATUS.\n");
+- }
+-
+- pstat = kmalloc(sizeof(struct ica_z90_status), GFP_KERNEL);
+- if (!pstat) {
+- PRINTK("kmalloc for pstat failed!\n");
+- ret = -ENOMEM;
+- break;
+- }
+-
+- pstat->totalcount = get_status_totalcount();
+- pstat->leedslitecount = get_status_PCICAcount();
+- pstat->leeds2count = get_status_PCICCcount();
+- pstat->requestqWaitCount = get_status_requestq_count();
+- pstat->pendingqWaitCount = get_status_pendingq_count();
+- pstat->totalOpenCount = get_status_totalopen_count();
+- pstat->cryptoDomain = get_status_domain_index();
+- get_status_status_mask(pstat->status);
+- get_status_qdepth_mask(pstat->qdepth);
+-
+- if (copy_to_user((struct ica_z90_status __user *) arg, pstat,
+- sizeof(struct ica_z90_status)) != 0)
+- ret = -EFAULT;
+- kfree(pstat);
+- break;
+-
+- /* THIS IS DEPRECATED. USE THE NEW STATUS CALLS */
+- case Z90STAT_PCIXCCCOUNT:
+- if (deprecated_msg_count2 < 20) {
+- PRINTK("deprecated ioctl (Z90STAT_PCIXCCCOUNT)!\n");
+- deprecated_msg_count2++;
+- if (deprecated_msg_count2 == 20)
+- PRINTK("No longer issuing messages about depre"
+- "cated ioctl Z90STAT_PCIXCCCOUNT.\n");
+- }
+-
+- tempstat = get_status_PCIXCCcount();
+- if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
+- ret = -EFAULT;
+- break;
+-
+- case Z90QUIESCE:
+- if (current->euid != 0) {
+- PRINTK("QUIESCE fails: euid %d\n",
+- current->euid);
+- ret = -EACCES;
+- } else {
+- PRINTK("QUIESCE device from PID %d\n", PID());
+- quiesce_z90crypt = 1;
+- }
+- break;
+-
+- default:
+- /* user passed an invalid IOCTL number */
+- PDEBUG("cmd 0x%08X contains invalid ioctl code\n", cmd);
+- ret = -ENOTTY;
+- break;
+- }
+-
+- return ret;
+-}
+-
+-static inline int
+-sprintcl(unsigned char *outaddr, unsigned char *addr, unsigned int len)
+-{
+- int hl, i;
+-
+- hl = 0;
+- for (i = 0; i < len; i++)
+- hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
+- hl += sprintf(outaddr+hl, " ");
+-
+- return hl;
+-}
+-
+-static inline int
+-sprintrw(unsigned char *outaddr, unsigned char *addr, unsigned int len)
+-{
+- int hl, inl, c, cx;
+-
+- hl = sprintf(outaddr, " ");
+- inl = 0;
+- for (c = 0; c < (len / 16); c++) {
+- hl += sprintcl(outaddr+hl, addr+inl, 16);
+- inl += 16;
+- }
+-
+- cx = len%16;
+- if (cx) {
+- hl += sprintcl(outaddr+hl, addr+inl, cx);
+- inl += cx;
+- }
+-
+- hl += sprintf(outaddr+hl, "\n");
+-
+- return hl;
+-}
+-
+-static inline int
+-sprinthx(unsigned char *title, unsigned char *outaddr,
+- unsigned char *addr, unsigned int len)
+-{
+- int hl, inl, r, rx;
+-
+- hl = sprintf(outaddr, "\n%s\n", title);
+- inl = 0;
+- for (r = 0; r < (len / 64); r++) {
+- hl += sprintrw(outaddr+hl, addr+inl, 64);
+- inl += 64;
+- }
+- rx = len % 64;
+- if (rx) {
+- hl += sprintrw(outaddr+hl, addr+inl, rx);
+- inl += rx;
+- }
+-
+- hl += sprintf(outaddr+hl, "\n");
+-
+- return hl;
+-}
+-
+-static inline int
+-sprinthx4(unsigned char *title, unsigned char *outaddr,
+- unsigned int *array, unsigned int len)
+-{
+- int hl, r;
+-
+- hl = sprintf(outaddr, "\n%s\n", title);
+-
+- for (r = 0; r < len; r++) {
+- if ((r % 8) == 0)
+- hl += sprintf(outaddr+hl, " ");
+- hl += sprintf(outaddr+hl, "%08X ", array[r]);
+- if ((r % 8) == 7)
+- hl += sprintf(outaddr+hl, "\n");
+- }
+-
+- hl += sprintf(outaddr+hl, "\n");
+-
+- return hl;
+-}
+-
+-static int
+-z90crypt_status(char *resp_buff, char **start, off_t offset,
+- int count, int *eof, void *data)
+-{
+- unsigned char *workarea;
+- int len;
+-
+- /* resp_buff is a page. Use the right half for a work area */
+- workarea = resp_buff+2000;
+- len = 0;
+- len += sprintf(resp_buff+len, "\nz90crypt version: %d.%d.%d\n",
+- z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT);
+- len += sprintf(resp_buff+len, "Cryptographic domain: %d\n",
+- get_status_domain_index());
+- len += sprintf(resp_buff+len, "Total device count: %d\n",
+- get_status_totalcount());
+- len += sprintf(resp_buff+len, "PCICA count: %d\n",
+- get_status_PCICAcount());
+- len += sprintf(resp_buff+len, "PCICC count: %d\n",
+- get_status_PCICCcount());
+- len += sprintf(resp_buff+len, "PCIXCC MCL2 count: %d\n",
+- get_status_PCIXCCMCL2count());
+- len += sprintf(resp_buff+len, "PCIXCC MCL3 count: %d\n",
+- get_status_PCIXCCMCL3count());
+- len += sprintf(resp_buff+len, "CEX2C count: %d\n",
+- get_status_CEX2Ccount());
+- len += sprintf(resp_buff+len, "CEX2A count: %d\n",
+- get_status_CEX2Acount());
+- len += sprintf(resp_buff+len, "requestq count: %d\n",
+- get_status_requestq_count());
+- len += sprintf(resp_buff+len, "pendingq count: %d\n",
+- get_status_pendingq_count());
+- len += sprintf(resp_buff+len, "Total open handles: %d\n\n",
+- get_status_totalopen_count());
+- len += sprinthx(
+- "Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
+- "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
+- resp_buff+len,
+- get_status_status_mask(workarea),
+- Z90CRYPT_NUM_APS);
+- len += sprinthx("Waiting work element counts",
+- resp_buff+len,
+- get_status_qdepth_mask(workarea),
+- Z90CRYPT_NUM_APS);
+- len += sprinthx4(
+- "Per-device successfully completed request counts",
+- resp_buff+len,
+- get_status_perdevice_reqcnt((unsigned int *)workarea),
+- Z90CRYPT_NUM_APS);
+- *eof = 1;
+- memset(workarea, 0, Z90CRYPT_NUM_APS * sizeof(unsigned int));
+- return len;
+-}
+-
+-static inline void
+-disable_card(int card_index)
+-{
+- struct device *devp;
+-
+- devp = LONG2DEVPTR(card_index);
+- if (!devp || devp->user_disabled)
+- return;
+- devp->user_disabled = 1;
+- z90crypt.hdware_info->hdware_mask.user_disabled_count++;
+- if (devp->dev_type == -1)
+- return;
+- z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count++;
+-}
+-
+-static inline void
+-enable_card(int card_index)
+-{
+- struct device *devp;
+-
+- devp = LONG2DEVPTR(card_index);
+- if (!devp || !devp->user_disabled)
+- return;
+- devp->user_disabled = 0;
+- z90crypt.hdware_info->hdware_mask.user_disabled_count--;
+- if (devp->dev_type == -1)
+- return;
+- z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
+-}
+-
+-static int
+-z90crypt_status_write(struct file *file, const char __user *buffer,
+- unsigned long count, void *data)
+-{
+- int j, eol;
+- unsigned char *lbuf, *ptr;
+- unsigned int local_count;
+-
+-#define LBUFSIZE 1200
+- lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
+- if (!lbuf) {
+- PRINTK("kmalloc failed!\n");
+- return 0;
+- }
+-
+- if (count <= 0)
+- return 0;
+-
+- local_count = UMIN((unsigned int)count, LBUFSIZE-1);
+-
+- if (copy_from_user(lbuf, buffer, local_count) != 0) {
+- kfree(lbuf);
+- return -EFAULT;
+- }
+-
+- lbuf[local_count] = '\0';
+-
+- ptr = strstr(lbuf, "Online devices");
+- if (ptr == 0) {
+- PRINTK("Unable to parse data (missing \"Online devices\")\n");
+- kfree(lbuf);
+- return count;
+- }
+-
+- ptr = strstr(ptr, "\n");
+- if (ptr == 0) {
+- PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
+- kfree(lbuf);
+- return count;
+- }
+- ptr++;
+-
+- if (strstr(ptr, "Waiting work element counts") == NULL) {
+- PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
+- kfree(lbuf);
+- return count;
+- }
+-
+- j = 0;
+- eol = 0;
+- while ((j < 64) && (*ptr != '\0')) {
+- switch (*ptr) {
+- case '\t':
+- case ' ':
+- break;
+- case '\n':
+- default:
+- eol = 1;
+- break;
+- case '0': // no device
+- case '1': // PCICA
+- case '2': // PCICC
+- case '3': // PCIXCC_MCL2
+- case '4': // PCIXCC_MCL3
+- case '5': // CEX2C
+- case '6': // CEX2A
+- j++;
+- break;
+- case 'd':
+- case 'D':
+- disable_card(j);
+- j++;
+- break;
+- case 'e':
+- case 'E':
+- enable_card(j);
+- j++;
+- break;
+- }
+- if (eol)
+- break;
+- ptr++;
+- }
+-
+- kfree(lbuf);
+- return count;
+-}
+-
+-/**
+- * Functions that run under a timer, with no process id
+- *
+- * The task functions:
+- * z90crypt_reader_task
+- * helper_send_work
+- * helper_handle_work_element
+- * helper_receive_rc
+- * z90crypt_config_task
+- * z90crypt_cleanup_task
+- *
+- * Helper functions:
+- * z90crypt_schedule_reader_timer
+- * z90crypt_schedule_reader_task
+- * z90crypt_schedule_config_task
+- * z90crypt_schedule_cleanup_task
+- */
+-static inline int
+-receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
+- unsigned char *buff, unsigned char __user **dest_p_p)
+-{
+- int dv, rv;
+- struct device *dev_ptr;
+- struct caller *caller_p;
+- struct ica_rsa_modexpo *icaMsg_p;
+- struct list_head *ptr, *tptr;
+-
+- memcpy(psmid, NULL_psmid, sizeof(NULL_psmid));
+-
+- if (z90crypt.terminating)
+- return REC_FATAL_ERROR;
+-
+- caller_p = 0;
+- dev_ptr = z90crypt.device_p[index];
+- rv = 0;
+- do {
+- if (!dev_ptr || dev_ptr->disabled) {
+- rv = REC_NO_WORK; // a disabled device can't return work
+- break;
+- }
+- if (dev_ptr->dev_self_x != index) {
+- PRINTKC("Corrupt dev ptr\n");
+- z90crypt.terminating = 1;
+- rv = REC_FATAL_ERROR;
+- break;
+- }
+- if (!dev_ptr->dev_resp_l || !dev_ptr->dev_resp_p) {
+- dv = DEV_REC_EXCEPTION;
+- PRINTK("dev_resp_l = %d, dev_resp_p = %p\n",
+- dev_ptr->dev_resp_l, dev_ptr->dev_resp_p);
+- } else {
+- PDEBUG("Dequeue called for device %d\n", index);
+- dv = receive_from_AP(index, z90crypt.cdx,
+- dev_ptr->dev_resp_l,
+- dev_ptr->dev_resp_p, psmid);
+- }
+- switch (dv) {
+- case DEV_REC_EXCEPTION:
+- rv = REC_FATAL_ERROR;
+- z90crypt.terminating = 1;
+- PRINTKC("Exception in receive from device %d\n",
+- index);
+- break;
+- case DEV_ONLINE:
+- rv = 0;
+- break;
+- case DEV_EMPTY:
+- rv = REC_EMPTY;
+- break;
+- case DEV_NO_WORK:
+- rv = REC_NO_WORK;
+- break;
+- case DEV_BAD_MESSAGE:
+- case DEV_GONE:
+- case REC_HARDWAR_ERR:
+- default:
+- rv = REC_NO_RESPONSE;
+- break;
+- }
+- if (rv)
+- break;
+- if (dev_ptr->dev_caller_count <= 0) {
+- rv = REC_USER_GONE;
+- break;
+- }
+-
+- list_for_each_safe(ptr, tptr, &dev_ptr->dev_caller_list) {
+- caller_p = list_entry(ptr, struct caller, caller_liste);
+- if (!memcmp(caller_p->caller_id, psmid,
+- sizeof(caller_p->caller_id))) {
+- if (!list_empty(&caller_p->caller_liste)) {
+- list_del_init(ptr);
+- dev_ptr->dev_caller_count--;
+- break;
+- }
+- }
+- caller_p = 0;
+- }
+- if (!caller_p) {
+- PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
+- "%02X%02X%02X in device list\n",
+- psmid[0], psmid[1], psmid[2], psmid[3],
+- psmid[4], psmid[5], psmid[6], psmid[7]);
+- rv = REC_USER_GONE;
+- break;
+- }
+-
+- PDEBUG("caller_p after successful receive: %p\n", caller_p);
+- rv = convert_response(dev_ptr->dev_resp_p,
+- caller_p->caller_buf_p, buff_len_p, buff);
+- switch (rv) {
+- case REC_USE_PCICA:
+- break;
+- case REC_OPERAND_INV:
+- case REC_OPERAND_SIZE:
+- case REC_EVEN_MOD:
+- case REC_INVALID_PAD:
+- PDEBUG("device %d: 'user error' %d\n", index, rv);
+- break;
+- case WRONG_DEVICE_TYPE:
+- case REC_HARDWAR_ERR:
+- case REC_BAD_MESSAGE:
+- PRINTKW("device %d: hardware error %d\n", index, rv);
+- rv = REC_NO_RESPONSE;
+- break;
+- default:
+- PDEBUG("device %d: rv = %d\n", index, rv);
+- break;
+- }
+- } while (0);
+-
+- switch (rv) {
+- case 0:
+- PDEBUG("Successful receive from device %d\n", index);
+- icaMsg_p = (struct ica_rsa_modexpo *)caller_p->caller_buf_p;
+- *dest_p_p = icaMsg_p->outputdata;
+- if (*buff_len_p == 0)
+- PRINTK("Zero *buff_len_p\n");
+- break;
+- case REC_NO_RESPONSE:
+- PRINTKW("Removing device %d from availability\n", index);
+- remove_device(dev_ptr);
+- break;
+- }
+-
+- if (caller_p)
+- unbuild_caller(dev_ptr, caller_p);
+-
+- return rv;
+-}
+-
+-static inline void
+-helper_send_work(int index)
+-{
+- struct work_element *rq_p;
+- int rv;
+-
+- if (list_empty(&request_list))
+- return;
+- requestq_count--;
+- rq_p = list_entry(request_list.next, struct work_element, liste);
+- list_del_init(&rq_p->liste);
+- rq_p->audit[1] |= FP_REMREQUEST;
+- if (rq_p->devtype == SHRT2DEVPTR(index)->dev_type) {
+- rq_p->devindex = SHRT2LONG(index);
+- rv = send_to_crypto_device(rq_p);
+- if (rv == 0) {
+- rq_p->requestsent = jiffies;
+- rq_p->audit[0] |= FP_SENT;
+- list_add_tail(&rq_p->liste, &pending_list);
+- ++pendingq_count;
+- rq_p->audit[0] |= FP_PENDING;
+- } else {
+- switch (rv) {
+- case REC_OPERAND_INV:
+- case REC_OPERAND_SIZE:
+- case REC_EVEN_MOD:
+- case REC_INVALID_PAD:
+- rq_p->retcode = -EINVAL;
+- break;
+- case SEN_NOT_AVAIL:
+- case SEN_RETRY:
+- case REC_NO_RESPONSE:
+- default:
+- if (z90crypt.mask.st_count > 1)
+- rq_p->retcode =
+- -ERESTARTSYS;
+- else
+- rq_p->retcode = -ENODEV;
+- break;
+- }
+- rq_p->status[0] |= STAT_FAILED;
+- rq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&rq_p->alarmrung, 1);
+- wake_up(&rq_p->waitq);
+- }
+- } else {
+- if (z90crypt.mask.st_count > 1)
+- rq_p->retcode = -ERESTARTSYS;
+- else
+- rq_p->retcode = -ENODEV;
+- rq_p->status[0] |= STAT_FAILED;
+- rq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&rq_p->alarmrung, 1);
+- wake_up(&rq_p->waitq);
+- }
+-}
+-
+-static inline void
+-helper_handle_work_element(int index, unsigned char psmid[8], int rc,
+- int buff_len, unsigned char *buff,
+- unsigned char __user *resp_addr)
+-{
+- struct work_element *pq_p;
+- struct list_head *lptr, *tptr;
+-
+- pq_p = 0;
+- list_for_each_safe(lptr, tptr, &pending_list) {
+- pq_p = list_entry(lptr, struct work_element, liste);
+- if (!memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id))) {
+- list_del_init(lptr);
+- pendingq_count--;
+- pq_p->audit[1] |= FP_NOTPENDING;
+- break;
+- }
+- pq_p = 0;
+- }
+-
+- if (!pq_p) {
+- PRINTK("device %d has work but no caller exists on pending Q\n",
+- SHRT2LONG(index));
+- return;
+- }
+-
+- switch (rc) {
+- case 0:
+- pq_p->resp_buff_size = buff_len;
+- pq_p->audit[1] |= FP_RESPSIZESET;
+- if (buff_len) {
+- pq_p->resp_addr = resp_addr;
+- pq_p->audit[1] |= FP_RESPADDRCOPIED;
+- memcpy(pq_p->resp_buff, buff, buff_len);
+- pq_p->audit[1] |= FP_RESPBUFFCOPIED;
+- }
+- break;
+- case REC_OPERAND_INV:
+- case REC_OPERAND_SIZE:
+- case REC_EVEN_MOD:
+- case REC_INVALID_PAD:
+- PDEBUG("-EINVAL after application error %d\n", rc);
+- pq_p->retcode = -EINVAL;
+- pq_p->status[0] |= STAT_FAILED;
+- break;
+- case REC_USE_PCICA:
+- pq_p->retcode = -ERESTARTSYS;
+- pq_p->status[0] |= STAT_FAILED;
+- break;
+- case REC_NO_RESPONSE:
+- default:
+- if (z90crypt.mask.st_count > 1)
+- pq_p->retcode = -ERESTARTSYS;
+- else
+- pq_p->retcode = -ENODEV;
+- pq_p->status[0] |= STAT_FAILED;
+- break;
+- }
+- if ((pq_p->status[0] != STAT_FAILED) || (pq_p->retcode != -ERELEASED)) {
+- pq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&pq_p->alarmrung, 1);
+- wake_up(&pq_p->waitq);
+- }
+-}
+-
+-/**
+- * return TRUE if the work element should be removed from the queue
+- */
+-static inline int
+-helper_receive_rc(int index, int *rc_p)
+-{
+- switch (*rc_p) {
+- case 0:
+- case REC_OPERAND_INV:
+- case REC_OPERAND_SIZE:
+- case REC_EVEN_MOD:
+- case REC_INVALID_PAD:
+- case REC_USE_PCICA:
+- break;
+-
+- case REC_BUSY:
+- case REC_NO_WORK:
+- case REC_EMPTY:
+- case REC_RETRY_DEV:
+- case REC_FATAL_ERROR:
+- return 0;
+-
+- case REC_NO_RESPONSE:
+- break;
+-
+- default:
+- PRINTK("rc %d, device %d converted to REC_NO_RESPONSE\n",
+- *rc_p, SHRT2LONG(index));
+- *rc_p = REC_NO_RESPONSE;
+- break;
+- }
+- return 1;
+-}
+-
+-static inline void
+-z90crypt_schedule_reader_timer(void)
+-{
+- if (timer_pending(&reader_timer))
+- return;
+- if (mod_timer(&reader_timer, jiffies+(READERTIME*HZ/1000)) != 0)
+- PRINTK("Timer pending while modifying reader timer\n");
+-}
+-
+-static void
+-z90crypt_reader_task(unsigned long ptr)
+-{
+- int workavail, index, rc, buff_len;
+- unsigned char psmid[8];
+- unsigned char __user *resp_addr;
+- static unsigned char buff[1024];
+-
+- /**
+- * we use workavail = 2 to ensure 2 passes with nothing dequeued before
+- * exiting the loop. If (pendingq_count+requestq_count) == 0 after the
+- * loop, there is no work remaining on the queues.
+- */
+- resp_addr = 0;
+- workavail = 2;
+- buff_len = 0;
+- while (workavail) {
+- workavail--;
+- rc = 0;
+- spin_lock_irq(&queuespinlock);
+- memset(buff, 0x00, sizeof(buff));
+-
+- /* Dequeue once from each device in round robin. */
+- for (index = 0; index < z90crypt.mask.st_count; index++) {
+- PDEBUG("About to receive.\n");
+- rc = receive_from_crypto_device(SHRT2LONG(index),
+- psmid,
+- &buff_len,
+- buff,
+- &resp_addr);
+- PDEBUG("Dequeued: rc = %d.\n", rc);
+-
+- if (helper_receive_rc(index, &rc)) {
+- if (rc != REC_NO_RESPONSE) {
+- helper_send_work(index);
+- workavail = 2;
+- }
+-
+- helper_handle_work_element(index, psmid, rc,
+- buff_len, buff,
+- resp_addr);
+- }
+-
+- if (rc == REC_FATAL_ERROR)
+- PRINTKW("REC_FATAL_ERROR from device %d!\n",
+- SHRT2LONG(index));
+- }
+- spin_unlock_irq(&queuespinlock);
+- }
+-
+- if (pendingq_count + requestq_count)
+- z90crypt_schedule_reader_timer();
+-}
+-
+-static inline void
+-z90crypt_schedule_config_task(unsigned int expiration)
+-{
+- if (timer_pending(&config_timer))
+- return;
+- if (mod_timer(&config_timer, jiffies+(expiration*HZ)) != 0)
+- PRINTK("Timer pending while modifying config timer\n");
+-}
+-
+-static void
+-z90crypt_config_task(unsigned long ptr)
+-{
+- int rc;
+-
+- PDEBUG("jiffies %ld\n", jiffies);
+-
+- if ((rc = refresh_z90crypt(&z90crypt.cdx)))
+- PRINTK("Error %d detected in refresh_z90crypt.\n", rc);
+- /* If return was fatal, don't bother reconfiguring */
+- if ((rc != TSQ_FATAL_ERROR) && (rc != RSQ_FATAL_ERROR))
+- z90crypt_schedule_config_task(CONFIGTIME);
+-}
+-
+-static inline void
+-z90crypt_schedule_cleanup_task(void)
+-{
+- if (timer_pending(&cleanup_timer))
+- return;
+- if (mod_timer(&cleanup_timer, jiffies+(CLEANUPTIME*HZ)) != 0)
+- PRINTK("Timer pending while modifying cleanup timer\n");
+-}
+-
+-static inline void
+-helper_drain_queues(void)
+-{
+- struct work_element *pq_p;
+- struct list_head *lptr, *tptr;
+-
+- list_for_each_safe(lptr, tptr, &pending_list) {
+- pq_p = list_entry(lptr, struct work_element, liste);
+- pq_p->retcode = -ENODEV;
+- pq_p->status[0] |= STAT_FAILED;
+- unbuild_caller(LONG2DEVPTR(pq_p->devindex),
+- (struct caller *)pq_p->requestptr);
+- list_del_init(lptr);
+- pendingq_count--;
+- pq_p->audit[1] |= FP_NOTPENDING;
+- pq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&pq_p->alarmrung, 1);
+- wake_up(&pq_p->waitq);
+- }
+-
+- list_for_each_safe(lptr, tptr, &request_list) {
+- pq_p = list_entry(lptr, struct work_element, liste);
+- pq_p->retcode = -ENODEV;
+- pq_p->status[0] |= STAT_FAILED;
+- list_del_init(lptr);
+- requestq_count--;
+- pq_p->audit[1] |= FP_REMREQUEST;
+- pq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&pq_p->alarmrung, 1);
+- wake_up(&pq_p->waitq);
+- }
+-}
+-
+-static inline void
+-helper_timeout_requests(void)
+-{
+- struct work_element *pq_p;
+- struct list_head *lptr, *tptr;
+- long timelimit;
+-
+- timelimit = jiffies - (CLEANUPTIME * HZ);
+- /* The list is in strict chronological order */
+- list_for_each_safe(lptr, tptr, &pending_list) {
+- pq_p = list_entry(lptr, struct work_element, liste);
+- if (pq_p->requestsent >= timelimit)
+- break;
+- PRINTKW("Purging(PQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+- ((struct caller *)pq_p->requestptr)->caller_id[0],
+- ((struct caller *)pq_p->requestptr)->caller_id[1],
+- ((struct caller *)pq_p->requestptr)->caller_id[2],
+- ((struct caller *)pq_p->requestptr)->caller_id[3],
+- ((struct caller *)pq_p->requestptr)->caller_id[4],
+- ((struct caller *)pq_p->requestptr)->caller_id[5],
+- ((struct caller *)pq_p->requestptr)->caller_id[6],
+- ((struct caller *)pq_p->requestptr)->caller_id[7]);
+- pq_p->retcode = -ETIMEOUT;
+- pq_p->status[0] |= STAT_FAILED;
+- /* get this off any caller queue it may be on */
+- unbuild_caller(LONG2DEVPTR(pq_p->devindex),
+- (struct caller *) pq_p->requestptr);
+- list_del_init(lptr);
+- pendingq_count--;
+- pq_p->audit[1] |= FP_TIMEDOUT;
+- pq_p->audit[1] |= FP_NOTPENDING;
+- pq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&pq_p->alarmrung, 1);
+- wake_up(&pq_p->waitq);
+- }
+-
+- /**
+- * If pending count is zero, items left on the request queue may
+- * never be processed.
+- */
+- if (pendingq_count <= 0) {
+- list_for_each_safe(lptr, tptr, &request_list) {
+- pq_p = list_entry(lptr, struct work_element, liste);
+- if (pq_p->requestsent >= timelimit)
+- break;
+- PRINTKW("Purging(RQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+- ((struct caller *)pq_p->requestptr)->caller_id[0],
+- ((struct caller *)pq_p->requestptr)->caller_id[1],
+- ((struct caller *)pq_p->requestptr)->caller_id[2],
+- ((struct caller *)pq_p->requestptr)->caller_id[3],
+- ((struct caller *)pq_p->requestptr)->caller_id[4],
+- ((struct caller *)pq_p->requestptr)->caller_id[5],
+- ((struct caller *)pq_p->requestptr)->caller_id[6],
+- ((struct caller *)pq_p->requestptr)->caller_id[7]);
+- pq_p->retcode = -ETIMEOUT;
+- pq_p->status[0] |= STAT_FAILED;
+- list_del_init(lptr);
+- requestq_count--;
+- pq_p->audit[1] |= FP_TIMEDOUT;
+- pq_p->audit[1] |= FP_REMREQUEST;
+- pq_p->audit[1] |= FP_AWAKENING;
+- atomic_set(&pq_p->alarmrung, 1);
+- wake_up(&pq_p->waitq);
+- }
+- }
+-}
+-
+-static void
+-z90crypt_cleanup_task(unsigned long ptr)
+-{
+- PDEBUG("jiffies %ld\n", jiffies);
+- spin_lock_irq(&queuespinlock);
+- if (z90crypt.mask.st_count <= 0) // no devices!
+- helper_drain_queues();
+- else
+- helper_timeout_requests();
+- spin_unlock_irq(&queuespinlock);
+- z90crypt_schedule_cleanup_task();
+-}
+-
+-static void
+-z90crypt_schedule_reader_task(unsigned long ptr)
+-{
+- tasklet_schedule(&reader_tasklet);
+-}
+-
+-/**
+- * Lowlevel Functions:
+- *
+- * create_z90crypt: creates and initializes basic data structures
+- * refresh_z90crypt: re-initializes basic data structures
+- * find_crypto_devices: returns a count and mask of hardware status
+- * create_crypto_device: builds the descriptor for a device
+- * destroy_crypto_device: unallocates the descriptor for a device
+- * destroy_z90crypt: drains all work, unallocates structs
+- */
+-
+-/**
+- * build the z90crypt root structure using the given domain index
+- */
+-static int
+-create_z90crypt(int *cdx_p)
+-{
+- struct hdware_block *hdware_blk_p;
+-
+- memset(&z90crypt, 0x00, sizeof(struct z90crypt));
+- z90crypt.domain_established = 0;
+- z90crypt.len = sizeof(struct z90crypt);
+- z90crypt.max_count = Z90CRYPT_NUM_DEVS;
+- z90crypt.cdx = *cdx_p;
+-
+- hdware_blk_p = kzalloc(sizeof(struct hdware_block), GFP_ATOMIC);
+- if (!hdware_blk_p) {
+- PDEBUG("kmalloc for hardware block failed\n");
+- return ENOMEM;
+- }
+- z90crypt.hdware_info = hdware_blk_p;
+-
+- return 0;
+-}
+-
+-static inline int
+-helper_scan_devices(int cdx_array[16], int *cdx_p, int *correct_cdx_found)
+-{
+- enum hdstat hd_stat;
+- int q_depth, dev_type;
+- int indx, chkdom, numdomains;
+-
+- q_depth = dev_type = numdomains = 0;
+- for (chkdom = 0; chkdom <= 15; cdx_array[chkdom++] = -1);
+- for (indx = 0; indx < z90crypt.max_count; indx++) {
+- hd_stat = HD_NOT_THERE;
+- numdomains = 0;
+- for (chkdom = 0; chkdom <= 15; chkdom++) {
+- hd_stat = query_online(indx, chkdom, MAX_RESET,
+- &q_depth, &dev_type);
+- if (hd_stat == HD_TSQ_EXCEPTION) {
+- z90crypt.terminating = 1;
+- PRINTKC("exception taken!\n");
+- break;
+- }
+- if (hd_stat == HD_ONLINE) {
+- cdx_array[numdomains++] = chkdom;
+- if (*cdx_p == chkdom) {
+- *correct_cdx_found = 1;
+- break;
+- }
+- }
+- }
+- if ((*correct_cdx_found == 1) || (numdomains != 0))
+- break;
+- if (z90crypt.terminating)
+- break;
+- }
+- return numdomains;
+-}
+-
+-static inline int
+-probe_crypto_domain(int *cdx_p)
+-{
+- int cdx_array[16];
+- char cdx_array_text[53], temp[5];
+- int correct_cdx_found, numdomains;
+-
+- correct_cdx_found = 0;
+- numdomains = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
+-
+- if (z90crypt.terminating)
+- return TSQ_FATAL_ERROR;
+-
+- if (correct_cdx_found)
+- return 0;
+-
+- if (numdomains == 0) {
+- PRINTKW("Unable to find crypto domain: No devices found\n");
+- return Z90C_NO_DEVICES;
+- }
+-
+- if (numdomains == 1) {
+- if (*cdx_p == -1) {
+- *cdx_p = cdx_array[0];
+- return 0;
+- }
+- PRINTKW("incorrect domain: specified = %d, found = %d\n",
+- *cdx_p, cdx_array[0]);
+- return Z90C_INCORRECT_DOMAIN;
+- }
+-
+- numdomains--;
+- sprintf(cdx_array_text, "%d", cdx_array[numdomains]);
+- while (numdomains) {
+- numdomains--;
+- sprintf(temp, ", %d", cdx_array[numdomains]);
+- strcat(cdx_array_text, temp);
+- }
+-
+- PRINTKW("ambiguous domain detected: specified = %d, found array = %s\n",
+- *cdx_p, cdx_array_text);
+- return Z90C_AMBIGUOUS_DOMAIN;
+-}
+-
+-static int
+-refresh_z90crypt(int *cdx_p)
+-{
+- int i, j, indx, rv;
+- static struct status local_mask;
+- struct device *devPtr;
+- unsigned char oldStat, newStat;
+- int return_unchanged;
+-
+- if (z90crypt.len != sizeof(z90crypt))
+- return ENOTINIT;
+- if (z90crypt.terminating)
+- return TSQ_FATAL_ERROR;
+- rv = 0;
+- if (!z90crypt.hdware_info->hdware_mask.st_count &&
+- !z90crypt.domain_established) {
+- rv = probe_crypto_domain(cdx_p);
+- if (z90crypt.terminating)
+- return TSQ_FATAL_ERROR;
+- if (rv == Z90C_NO_DEVICES)
+- return 0; // try later
+- if (rv)
+- return rv;
+- z90crypt.cdx = *cdx_p;
+- z90crypt.domain_established = 1;
+- }
+- rv = find_crypto_devices(&local_mask);
+- if (rv) {
+- PRINTK("find crypto devices returned %d\n", rv);
+- return rv;
+- }
+- if (!memcmp(&local_mask, &z90crypt.hdware_info->hdware_mask,
+- sizeof(struct status))) {
+- return_unchanged = 1;
+- for (i = 0; i < Z90CRYPT_NUM_TYPES; i++) {
+- /**
+- * Check for disabled cards. If any device is marked
+- * disabled, destroy it.
+- */
+- for (j = 0;
+- j < z90crypt.hdware_info->type_mask[i].st_count;
+- j++) {
+- indx = z90crypt.hdware_info->type_x_addr[i].
+- device_index[j];
+- devPtr = z90crypt.device_p[indx];
+- if (devPtr && devPtr->disabled) {
+- local_mask.st_mask[indx] = HD_NOT_THERE;
+- return_unchanged = 0;
+- }
+- }
+- }
+- if (return_unchanged == 1)
+- return 0;
+- }
+-
+- spin_lock_irq(&queuespinlock);
+- for (i = 0; i < z90crypt.max_count; i++) {
+- oldStat = z90crypt.hdware_info->hdware_mask.st_mask[i];
+- newStat = local_mask.st_mask[i];
+- if ((oldStat == HD_ONLINE) && (newStat != HD_ONLINE))
+- destroy_crypto_device(i);
+- else if ((oldStat != HD_ONLINE) && (newStat == HD_ONLINE)) {
+- rv = create_crypto_device(i);
+- if (rv >= REC_FATAL_ERROR)
+- return rv;
+- if (rv != 0) {
+- local_mask.st_mask[i] = HD_NOT_THERE;
+- local_mask.st_count--;
+- }
+- }
+- }
+- memcpy(z90crypt.hdware_info->hdware_mask.st_mask, local_mask.st_mask,
+- sizeof(local_mask.st_mask));
+- z90crypt.hdware_info->hdware_mask.st_count = local_mask.st_count;
+- z90crypt.hdware_info->hdware_mask.disabled_count =
+- local_mask.disabled_count;
+- refresh_index_array(&z90crypt.mask, &z90crypt.overall_device_x);
+- for (i = 0; i < Z90CRYPT_NUM_TYPES; i++)
+- refresh_index_array(&(z90crypt.hdware_info->type_mask[i]),
+- &(z90crypt.hdware_info->type_x_addr[i]));
+- spin_unlock_irq(&queuespinlock);
+-
+- return rv;
+-}
+-
+-static int
+-find_crypto_devices(struct status *deviceMask)
+-{
+- int i, q_depth, dev_type;
+- enum hdstat hd_stat;
+-
+- deviceMask->st_count = 0;
+- deviceMask->disabled_count = 0;
+- deviceMask->user_disabled_count = 0;
+-
+- for (i = 0; i < z90crypt.max_count; i++) {
+- hd_stat = query_online(i, z90crypt.cdx, MAX_RESET, &q_depth,
+- &dev_type);
+- if (hd_stat == HD_TSQ_EXCEPTION) {
+- z90crypt.terminating = 1;
+- PRINTKC("Exception during probe for crypto devices\n");
+- return TSQ_FATAL_ERROR;
+- }
+- deviceMask->st_mask[i] = hd_stat;
+- if (hd_stat == HD_ONLINE) {
+- PDEBUG("Got an online crypto!: %d\n", i);
+- PDEBUG("Got a queue depth of %d\n", q_depth);
+- PDEBUG("Got a device type of %d\n", dev_type);
+- if (q_depth <= 0)
+- return TSQ_FATAL_ERROR;
+- deviceMask->st_count++;
+- z90crypt.q_depth_array[i] = q_depth;
+- z90crypt.dev_type_array[i] = dev_type;
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int
+-refresh_index_array(struct status *status_str, struct device_x *index_array)
+-{
+- int i, count;
+- enum devstat stat;
+-
+- i = -1;
+- count = 0;
+- do {
+- stat = status_str->st_mask[++i];
+- if (stat == DEV_ONLINE)
+- index_array->device_index[count++] = i;
+- } while ((i < Z90CRYPT_NUM_DEVS) && (count < status_str->st_count));
+-
+- return count;
+-}
+-
+-static int
+-create_crypto_device(int index)
+-{
+- int rv, devstat, total_size;
+- struct device *dev_ptr;
+- struct status *type_str_p;
+- int deviceType;
+-
+- dev_ptr = z90crypt.device_p[index];
+- if (!dev_ptr) {
+- total_size = sizeof(struct device) +
+- z90crypt.q_depth_array[index] * sizeof(int);
+-
+- dev_ptr = kzalloc(total_size, GFP_ATOMIC);
+- if (!dev_ptr) {
+- PRINTK("kmalloc device %d failed\n", index);
+- return ENOMEM;
+- }
+- dev_ptr->dev_resp_p = kmalloc(MAX_RESPONSE_SIZE, GFP_ATOMIC);
+- if (!dev_ptr->dev_resp_p) {
+- kfree(dev_ptr);
+- PRINTK("kmalloc device %d rec buffer failed\n", index);
+- return ENOMEM;
+- }
+- dev_ptr->dev_resp_l = MAX_RESPONSE_SIZE;
+- INIT_LIST_HEAD(&(dev_ptr->dev_caller_list));
+- }
+-
+- devstat = reset_device(index, z90crypt.cdx, MAX_RESET);
+- if (devstat == DEV_RSQ_EXCEPTION) {
+- PRINTK("exception during reset device %d\n", index);
+- kfree(dev_ptr->dev_resp_p);
+- kfree(dev_ptr);
+- return RSQ_FATAL_ERROR;
+- }
+- if (devstat == DEV_ONLINE) {
+- dev_ptr->dev_self_x = index;
+- dev_ptr->dev_type = z90crypt.dev_type_array[index];
+- if (dev_ptr->dev_type == NILDEV) {
+- rv = probe_device_type(dev_ptr);
+- if (rv) {
+- PRINTK("rv = %d from probe_device_type %d\n",
+- rv, index);
+- kfree(dev_ptr->dev_resp_p);
+- kfree(dev_ptr);
+- return rv;
+- }
+- }
+- if (dev_ptr->dev_type == PCIXCC_UNK) {
+- rv = probe_PCIXCC_type(dev_ptr);
+- if (rv) {
+- PRINTK("rv = %d from probe_PCIXCC_type %d\n",
+- rv, index);
+- kfree(dev_ptr->dev_resp_p);
+- kfree(dev_ptr);
+- return rv;
+- }
+- }
+- deviceType = dev_ptr->dev_type;
+- z90crypt.dev_type_array[index] = deviceType;
+- if (deviceType == PCICA)
+- z90crypt.hdware_info->device_type_array[index] = 1;
+- else if (deviceType == PCICC)
+- z90crypt.hdware_info->device_type_array[index] = 2;
+- else if (deviceType == PCIXCC_MCL2)
+- z90crypt.hdware_info->device_type_array[index] = 3;
+- else if (deviceType == PCIXCC_MCL3)
+- z90crypt.hdware_info->device_type_array[index] = 4;
+- else if (deviceType == CEX2C)
+- z90crypt.hdware_info->device_type_array[index] = 5;
+- else if (deviceType == CEX2A)
+- z90crypt.hdware_info->device_type_array[index] = 6;
+- else // No idea how this would happen.
+- z90crypt.hdware_info->device_type_array[index] = -1;
+- }
+-
+- /**
+- * 'q_depth' returned by the hardware is one less than
+- * the actual depth
+- */
+- dev_ptr->dev_q_depth = z90crypt.q_depth_array[index];
+- dev_ptr->dev_type = z90crypt.dev_type_array[index];
+- dev_ptr->dev_stat = devstat;
+- dev_ptr->disabled = 0;
+- z90crypt.device_p[index] = dev_ptr;
+-
+- if (devstat == DEV_ONLINE) {
+- if (z90crypt.mask.st_mask[index] != DEV_ONLINE) {
+- z90crypt.mask.st_mask[index] = DEV_ONLINE;
+- z90crypt.mask.st_count++;
+- }
+- deviceType = dev_ptr->dev_type;
+- type_str_p = &z90crypt.hdware_info->type_mask[deviceType];
+- if (type_str_p->st_mask[index] != DEV_ONLINE) {
+- type_str_p->st_mask[index] = DEV_ONLINE;
+- type_str_p->st_count++;
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int
+-destroy_crypto_device(int index)
+-{
+- struct device *dev_ptr;
+- int t, disabledFlag;
+-
+- dev_ptr = z90crypt.device_p[index];
+-
+- /* remember device type; get rid of device struct */
+- if (dev_ptr) {
+- disabledFlag = dev_ptr->disabled;
+- t = dev_ptr->dev_type;
+- kfree(dev_ptr->dev_resp_p);
+- kfree(dev_ptr);
+- } else {
+- disabledFlag = 0;
+- t = -1;
+- }
+- z90crypt.device_p[index] = 0;
+-
+- /* if the type is valid, remove the device from the type_mask */
+- if ((t != -1) && z90crypt.hdware_info->type_mask[t].st_mask[index]) {
+- z90crypt.hdware_info->type_mask[t].st_mask[index] = 0x00;
+- z90crypt.hdware_info->type_mask[t].st_count--;
+- if (disabledFlag == 1)
+- z90crypt.hdware_info->type_mask[t].disabled_count--;
+- }
+- if (z90crypt.mask.st_mask[index] != DEV_GONE) {
+- z90crypt.mask.st_mask[index] = DEV_GONE;
+- z90crypt.mask.st_count--;
+- }
+- z90crypt.hdware_info->device_type_array[index] = 0;
+-
+- return 0;
+-}
+-
+-static void
+-destroy_z90crypt(void)
+-{
+- int i;
+-
+- for (i = 0; i < z90crypt.max_count; i++)
+- if (z90crypt.device_p[i])
+- destroy_crypto_device(i);
+- kfree(z90crypt.hdware_info);
+- memset((void *)&z90crypt, 0, sizeof(z90crypt));
+-}
+-
+-static unsigned char static_testmsg[384] = {
+-0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x06,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x43,0x43,
+-0x41,0x2d,0x41,0x50,0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
+-0x50,0x4b,0x00,0x00,0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x32,
+-0x01,0x00,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0xb8,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x49,0x43,0x53,0x46,
+-0x20,0x20,0x20,0x20,0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,0x2d,0x31,0x2e,0x32,
+-0x37,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
+-0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
+-0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
+-0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,0x88,0x1e,0x00,0x00,
+-0x57,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,0x03,0x02,0x00,0x00,
+-0x40,0x01,0x00,0x01,0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,0xf6,0xd2,0x7b,0x58,
+-0x4b,0xf9,0x28,0x68,0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,0x63,0x42,0xef,0xf8,
+-0xfd,0xa4,0xf8,0xb0,0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,0x53,0x8c,0x6f,0x4e,
+-0x72,0x8f,0x6c,0x04,0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,0xf7,0xdd,0xfd,0x4f,
+-0x11,0x36,0x95,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+-};
+-
+-static int
+-probe_device_type(struct device *devPtr)
+-{
+- int rv, dv, i, index, length;
+- unsigned char psmid[8];
+- static unsigned char loc_testmsg[sizeof(static_testmsg)];
+-
+- index = devPtr->dev_self_x;
+- rv = 0;
+- do {
+- memcpy(loc_testmsg, static_testmsg, sizeof(static_testmsg));
+- length = sizeof(static_testmsg) - 24;
+- /* the -24 allows for the header */
+- dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
+- if (dv) {
+- PDEBUG("dv returned by send during probe: %d\n", dv);
+- if (dv == DEV_SEN_EXCEPTION) {
+- rv = SEN_FATAL_ERROR;
+- PRINTKC("exception in send to AP %d\n", index);
+- break;
+- }
+- PDEBUG("return value from send_to_AP: %d\n", rv);
+- switch (dv) {
+- case DEV_GONE:
+- PDEBUG("dev %d not available\n", index);
+- rv = SEN_NOT_AVAIL;
+- break;
+- case DEV_ONLINE:
+- rv = 0;
+- break;
+- case DEV_EMPTY:
+- rv = SEN_NOT_AVAIL;
+- break;
+- case DEV_NO_WORK:
+- rv = SEN_FATAL_ERROR;
+- break;
+- case DEV_BAD_MESSAGE:
+- rv = SEN_USER_ERROR;
+- break;
+- case DEV_QUEUE_FULL:
+- rv = SEN_QUEUE_FULL;
+- break;
+- default:
+- PRINTK("unknown dv=%d for dev %d\n", dv, index);
+- rv = SEN_NOT_AVAIL;
+- break;
+- }
+- }
+-
+- if (rv)
+- break;
+-
+- for (i = 0; i < 6; i++) {
+- mdelay(300);
+- dv = receive_from_AP(index, z90crypt.cdx,
+- devPtr->dev_resp_l,
+- devPtr->dev_resp_p, psmid);
+- PDEBUG("dv returned by DQ = %d\n", dv);
+- if (dv == DEV_REC_EXCEPTION) {
+- rv = REC_FATAL_ERROR;
+- PRINTKC("exception in dequeue %d\n",
+- index);
+- break;
+- }
+- switch (dv) {
+- case DEV_ONLINE:
+- rv = 0;
+- break;
+- case DEV_EMPTY:
+- rv = REC_EMPTY;
+- break;
+- case DEV_NO_WORK:
+- rv = REC_NO_WORK;
+- break;
+- case DEV_BAD_MESSAGE:
+- case DEV_GONE:
+- default:
+- rv = REC_NO_RESPONSE;
+- break;
+- }
+- if ((rv != 0) && (rv != REC_NO_WORK))
+- break;
+- if (rv == 0)
+- break;
+- }
+- if (rv)
+- break;
+- rv = (devPtr->dev_resp_p[0] == 0x00) &&
+- (devPtr->dev_resp_p[1] == 0x86);
+- if (rv)
+- devPtr->dev_type = PCICC;
+- else
+- devPtr->dev_type = PCICA;
+- rv = 0;
+- } while (0);
+- /* In a general error case, the card is not marked online */
+- return rv;
+-}
+-
+-static unsigned char MCL3_testmsg[] = {
+-0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
+-0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
+-0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
+-0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
+-0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
+-0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
+-0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
+-0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
+-0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
+-0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
+-0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
+-0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
+-0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
+-0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
+-0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
+-0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,0xF1,0x3D,0x93,0x53
+-};
+-
+-static int
+-probe_PCIXCC_type(struct device *devPtr)
+-{
+- int rv, dv, i, index, length;
+- unsigned char psmid[8];
+- static unsigned char loc_testmsg[548];
+- struct CPRBX *cprbx_p;
+-
+- index = devPtr->dev_self_x;
+- rv = 0;
+- do {
+- memcpy(loc_testmsg, MCL3_testmsg, sizeof(MCL3_testmsg));
+- length = sizeof(MCL3_testmsg) - 0x0C;
+- dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
+- if (dv) {
+- PDEBUG("dv returned = %d\n", dv);
+- if (dv == DEV_SEN_EXCEPTION) {
+- rv = SEN_FATAL_ERROR;
+- PRINTKC("exception in send to AP %d\n", index);
+- break;
+- }
+- PDEBUG("return value from send_to_AP: %d\n", rv);
+- switch (dv) {
+- case DEV_GONE:
+- PDEBUG("dev %d not available\n", index);
+- rv = SEN_NOT_AVAIL;
+- break;
+- case DEV_ONLINE:
+- rv = 0;
+- break;
+- case DEV_EMPTY:
+- rv = SEN_NOT_AVAIL;
+- break;
+- case DEV_NO_WORK:
+- rv = SEN_FATAL_ERROR;
+- break;
+- case DEV_BAD_MESSAGE:
+- rv = SEN_USER_ERROR;
+- break;
+- case DEV_QUEUE_FULL:
+- rv = SEN_QUEUE_FULL;
+- break;
+- default:
+- PRINTK("unknown dv=%d for dev %d\n", dv, index);
+- rv = SEN_NOT_AVAIL;
+- break;
+- }
+- }
+-
+- if (rv)
+- break;
+-
+- for (i = 0; i < 6; i++) {
+- mdelay(300);
+- dv = receive_from_AP(index, z90crypt.cdx,
+- devPtr->dev_resp_l,
+- devPtr->dev_resp_p, psmid);
+- PDEBUG("dv returned by DQ = %d\n", dv);
+- if (dv == DEV_REC_EXCEPTION) {
+- rv = REC_FATAL_ERROR;
+- PRINTKC("exception in dequeue %d\n",
+- index);
+- break;
+- }
+- switch (dv) {
+- case DEV_ONLINE:
+- rv = 0;
+- break;
+- case DEV_EMPTY:
+- rv = REC_EMPTY;
+- break;
+- case DEV_NO_WORK:
+- rv = REC_NO_WORK;
+- break;
+- case DEV_BAD_MESSAGE:
+- case DEV_GONE:
+- default:
+- rv = REC_NO_RESPONSE;
+- break;
+- }
+- if ((rv != 0) && (rv != REC_NO_WORK))
+- break;
+- if (rv == 0)
+- break;
+- }
+- if (rv)
+- break;
+- cprbx_p = (struct CPRBX *) (devPtr->dev_resp_p + 48);
+- if ((cprbx_p->ccp_rtcode == 8) && (cprbx_p->ccp_rscode == 33)) {
+- devPtr->dev_type = PCIXCC_MCL2;
+- PDEBUG("device %d is MCL2\n", index);
+- } else {
+- devPtr->dev_type = PCIXCC_MCL3;
+- PDEBUG("device %d is MCL3\n", index);
+- }
+- } while (0);
+- /* In a general error case, the card is not marked online */
+- return rv;
+-}
+-
+-module_init(z90crypt_init_module);
+-module_exit(z90crypt_cleanup_module);
+diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
+new file mode 100644
+index 0000000..1edc10a
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_api.c
+@@ -0,0 +1,1091 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_api.c
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ * Cornelia Huck <cornelia.huck at de.ibm.com>
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.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, 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/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/compat.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#include "zcrypt_api.h"
++
++/**
++ * Module description.
++ */
++MODULE_AUTHOR("IBM Corporation");
++MODULE_DESCRIPTION("Cryptographic Coprocessor interface, "
++ "Copyright 2001, 2006 IBM Corporation");
++MODULE_LICENSE("GPL");
++
++static DEFINE_SPINLOCK(zcrypt_device_lock);
++static LIST_HEAD(zcrypt_device_list);
++static int zcrypt_device_count = 0;
++static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
++
++/**
++ * Device attributes common for all crypto devices.
++ */
++static ssize_t zcrypt_type_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct zcrypt_device *zdev = to_ap_dev(dev)->private;
++ return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string);
++}
++
++static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL);
++
++static ssize_t zcrypt_online_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct zcrypt_device *zdev = to_ap_dev(dev)->private;
++ return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online);
++}
++
++static ssize_t zcrypt_online_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct zcrypt_device *zdev = to_ap_dev(dev)->private;
++ int online;
++
++ if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
++ return -EINVAL;
++ zdev->online = online;
++ if (!online)
++ ap_flush_queue(zdev->ap_dev);
++ return count;
++}
++
++static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store);
++
++static struct attribute * zcrypt_device_attrs[] = {
++ &dev_attr_type.attr,
++ &dev_attr_online.attr,
++ NULL,
++};
++
++static struct attribute_group zcrypt_device_attr_group = {
++ .attrs = zcrypt_device_attrs,
++};
++
++/**
++ * Move the device towards the head of the device list.
++ * Need to be called while holding the zcrypt device list lock.
++ * Note: cards with speed_rating of 0 are kept at the end of the list.
++ */
++static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
++{
++ struct zcrypt_device *tmp;
++ struct list_head *l;
++
++ if (zdev->speed_rating == 0)
++ return;
++ for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) {
++ tmp = list_entry(l, struct zcrypt_device, list);
++ if ((tmp->request_count + 1) * tmp->speed_rating <=
++ (zdev->request_count + 1) * zdev->speed_rating &&
++ tmp->speed_rating != 0)
++ break;
++ }
++ if (l == zdev->list.prev)
++ return;
++ /* Move zdev behind l */
++ list_del(&zdev->list);
++ list_add(&zdev->list, l);
++}
++
++/**
++ * Move the device towards the tail of the device list.
++ * Need to be called while holding the zcrypt device list lock.
++ * Note: cards with speed_rating of 0 are kept at the end of the list.
++ */
++static void __zcrypt_decrease_preference(struct zcrypt_device *zdev)
++{
++ struct zcrypt_device *tmp;
++ struct list_head *l;
++
++ if (zdev->speed_rating == 0)
++ return;
++ for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) {
++ tmp = list_entry(l, struct zcrypt_device, list);
++ if ((tmp->request_count + 1) * tmp->speed_rating >
++ (zdev->request_count + 1) * zdev->speed_rating ||
++ tmp->speed_rating == 0)
++ break;
++ }
++ if (l == zdev->list.next)
++ return;
++ /* Move zdev before l */
++ list_del(&zdev->list);
++ list_add_tail(&zdev->list, l);
++}
++
++static void zcrypt_device_release(struct kref *kref)
++{
++ struct zcrypt_device *zdev =
++ container_of(kref, struct zcrypt_device, refcount);
++ zcrypt_device_free(zdev);
++}
++
++void zcrypt_device_get(struct zcrypt_device *zdev)
++{
++ kref_get(&zdev->refcount);
++}
++EXPORT_SYMBOL(zcrypt_device_get);
++
++int zcrypt_device_put(struct zcrypt_device *zdev)
++{
++ return kref_put(&zdev->refcount, zcrypt_device_release);
++}
++EXPORT_SYMBOL(zcrypt_device_put);
++
++struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size)
++{
++ struct zcrypt_device *zdev;
++
++ zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL);
++ if (!zdev)
++ return NULL;
++ zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL);
++ if (!zdev->reply.message)
++ goto out_free;
++ zdev->reply.length = max_response_size;
++ spin_lock_init(&zdev->lock);
++ INIT_LIST_HEAD(&zdev->list);
++ return zdev;
++
++out_free:
++ kfree(zdev);
++ return NULL;
++}
++EXPORT_SYMBOL(zcrypt_device_alloc);
++
++void zcrypt_device_free(struct zcrypt_device *zdev)
++{
++ kfree(zdev->reply.message);
++ kfree(zdev);
++}
++EXPORT_SYMBOL(zcrypt_device_free);
++
++/**
++ * Register a crypto device.
++ */
++int zcrypt_device_register(struct zcrypt_device *zdev)
++{
++ int rc;
++
++ rc = sysfs_create_group(&zdev->ap_dev->device.kobj,
++ &zcrypt_device_attr_group);
++ if (rc)
++ goto out;
++ get_device(&zdev->ap_dev->device);
++ kref_init(&zdev->refcount);
++ spin_lock_bh(&zcrypt_device_lock);
++ zdev->online = 1; /* New devices are online by default. */
++ list_add_tail(&zdev->list, &zcrypt_device_list);
++ __zcrypt_increase_preference(zdev);
++ zcrypt_device_count++;
++ spin_unlock_bh(&zcrypt_device_lock);
++out:
++ return rc;
++}
++EXPORT_SYMBOL(zcrypt_device_register);
++
++/**
++ * Unregister a crypto device.
++ */
++void zcrypt_device_unregister(struct zcrypt_device *zdev)
++{
++ spin_lock_bh(&zcrypt_device_lock);
++ zcrypt_device_count--;
++ list_del_init(&zdev->list);
++ spin_unlock_bh(&zcrypt_device_lock);
++ sysfs_remove_group(&zdev->ap_dev->device.kobj,
++ &zcrypt_device_attr_group);
++ put_device(&zdev->ap_dev->device);
++ zcrypt_device_put(zdev);
++}
++EXPORT_SYMBOL(zcrypt_device_unregister);
++
++/**
++ * zcrypt_read is not be supported beyond zcrypt 1.3.1
++ */
++static ssize_t zcrypt_read(struct file *filp, char __user *buf,
++ size_t count, loff_t *f_pos)
++{
++ return -EPERM;
++}
++
++/**
++ * Write is is not allowed
++ */
++static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
++ size_t count, loff_t *f_pos)
++{
++ return -EPERM;
++}
++
++/**
++ * Device open/close functions to count number of users.
++ */
++static int zcrypt_open(struct inode *inode, struct file *filp)
++{
++ atomic_inc(&zcrypt_open_count);
++ return 0;
++}
++
++static int zcrypt_release(struct inode *inode, struct file *filp)
++{
++ atomic_dec(&zcrypt_open_count);
++ return 0;
++}
++
++/**
++ * zcrypt ioctls.
++ */
++static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
++{
++ struct zcrypt_device *zdev;
++ int rc;
++
++ if (mex->outputdatalength < mex->inputdatalength)
++ return -EINVAL;
++ /**
++ * As long as outputdatalength is big enough, we can set the
++ * outputdatalength equal to the inputdatalength, since that is the
++ * number of bytes we will copy in any case
++ */
++ mex->outputdatalength = mex->inputdatalength;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ if (!zdev->online ||
++ !zdev->ops->rsa_modexpo ||
++ zdev->min_mod_size > mex->inputdatalength ||
++ zdev->max_mod_size < mex->inputdatalength)
++ continue;
++ zcrypt_device_get(zdev);
++ get_device(&zdev->ap_dev->device);
++ zdev->request_count++;
++ __zcrypt_decrease_preference(zdev);
++ spin_unlock_bh(&zcrypt_device_lock);
++ if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
++ rc = zdev->ops->rsa_modexpo(zdev, mex);
++ module_put(zdev->ap_dev->drv->driver.owner);
++ }
++ else
++ rc = -EAGAIN;
++ spin_lock_bh(&zcrypt_device_lock);
++ zdev->request_count--;
++ __zcrypt_increase_preference(zdev);
++ put_device(&zdev->ap_dev->device);
++ zcrypt_device_put(zdev);
++ spin_unlock_bh(&zcrypt_device_lock);
++ return rc;
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++ return -ENODEV;
++}
++
++static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
++{
++ struct zcrypt_device *zdev;
++ unsigned long long z1, z2, z3;
++ int rc, copied;
++
++ if (crt->outputdatalength < crt->inputdatalength ||
++ (crt->inputdatalength & 1))
++ return -EINVAL;
++ /**
++ * As long as outputdatalength is big enough, we can set the
++ * outputdatalength equal to the inputdatalength, since that is the
++ * number of bytes we will copy in any case
++ */
++ crt->outputdatalength = crt->inputdatalength;
++
++ copied = 0;
++ restart:
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ if (!zdev->online ||
++ !zdev->ops->rsa_modexpo_crt ||
++ zdev->min_mod_size > crt->inputdatalength ||
++ zdev->max_mod_size < crt->inputdatalength)
++ continue;
++ if (zdev->short_crt && crt->inputdatalength > 240) {
++ /**
++ * Check inputdata for leading zeros for cards
++ * that can't handle np_prime, bp_key, or
++ * u_mult_inv > 128 bytes.
++ */
++ if (copied == 0) {
++ int len;
++ spin_unlock_bh(&zcrypt_device_lock);
++ /* len is max 256 / 2 - 120 = 8 */
++ len = crt->inputdatalength / 2 - 120;
++ z1 = z2 = z3 = 0;
++ if (copy_from_user(&z1, crt->np_prime, len) ||
++ copy_from_user(&z2, crt->bp_key, len) ||
++ copy_from_user(&z3, crt->u_mult_inv, len))
++ return -EFAULT;
++ copied = 1;
++ /**
++ * We have to restart device lookup -
++ * the device list may have changed by now.
++ */
++ goto restart;
++ }
++ if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL)
++ /* The device can't handle this request. */
++ continue;
++ }
++ zcrypt_device_get(zdev);
++ get_device(&zdev->ap_dev->device);
++ zdev->request_count++;
++ __zcrypt_decrease_preference(zdev);
++ spin_unlock_bh(&zcrypt_device_lock);
++ if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
++ rc = zdev->ops->rsa_modexpo_crt(zdev, crt);
++ module_put(zdev->ap_dev->drv->driver.owner);
++ }
++ else
++ rc = -EAGAIN;
++ spin_lock_bh(&zcrypt_device_lock);
++ zdev->request_count--;
++ __zcrypt_increase_preference(zdev);
++ put_device(&zdev->ap_dev->device);
++ zcrypt_device_put(zdev);
++ spin_unlock_bh(&zcrypt_device_lock);
++ return rc;
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++ return -ENODEV;
++}
++
++static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
++{
++ struct zcrypt_device *zdev;
++ int rc;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ if (!zdev->online || !zdev->ops->send_cprb ||
++ (xcRB->user_defined != AUTOSELECT &&
++ AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)
++ )
++ continue;
++ zcrypt_device_get(zdev);
++ get_device(&zdev->ap_dev->device);
++ zdev->request_count++;
++ __zcrypt_decrease_preference(zdev);
++ spin_unlock_bh(&zcrypt_device_lock);
++ if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
++ rc = zdev->ops->send_cprb(zdev, xcRB);
++ module_put(zdev->ap_dev->drv->driver.owner);
++ }
++ else
++ rc = -EAGAIN;
++ spin_lock_bh(&zcrypt_device_lock);
++ zdev->request_count--;
++ __zcrypt_increase_preference(zdev);
++ put_device(&zdev->ap_dev->device);
++ zcrypt_device_put(zdev);
++ spin_unlock_bh(&zcrypt_device_lock);
++ return rc;
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++ return -ENODEV;
++}
++
++static void zcrypt_status_mask(char status[AP_DEVICES])
++{
++ struct zcrypt_device *zdev;
++
++ memset(status, 0, sizeof(char) * AP_DEVICES);
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list)
++ status[AP_QID_DEVICE(zdev->ap_dev->qid)] =
++ zdev->online ? zdev->user_space_type : 0x0d;
++ spin_unlock_bh(&zcrypt_device_lock);
++}
++
++static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES])
++{
++ struct zcrypt_device *zdev;
++
++ memset(qdepth, 0, sizeof(char) * AP_DEVICES);
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ spin_lock(&zdev->ap_dev->lock);
++ qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] =
++ zdev->ap_dev->pendingq_count +
++ zdev->ap_dev->requestq_count;
++ spin_unlock(&zdev->ap_dev->lock);
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++}
++
++static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES])
++{
++ struct zcrypt_device *zdev;
++
++ memset(reqcnt, 0, sizeof(int) * AP_DEVICES);
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ spin_lock(&zdev->ap_dev->lock);
++ reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] =
++ zdev->ap_dev->total_request_count;
++ spin_unlock(&zdev->ap_dev->lock);
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++}
++
++static int zcrypt_pendingq_count(void)
++{
++ struct zcrypt_device *zdev;
++ int pendingq_count = 0;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ spin_lock(&zdev->ap_dev->lock);
++ pendingq_count += zdev->ap_dev->pendingq_count;
++ spin_unlock(&zdev->ap_dev->lock);
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++ return pendingq_count;
++}
++
++static int zcrypt_requestq_count(void)
++{
++ struct zcrypt_device *zdev;
++ int requestq_count = 0;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list) {
++ spin_lock(&zdev->ap_dev->lock);
++ requestq_count += zdev->ap_dev->requestq_count;
++ spin_unlock(&zdev->ap_dev->lock);
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++ return requestq_count;
++}
++
++static int zcrypt_count_type(int type)
++{
++ struct zcrypt_device *zdev;
++ int device_count = 0;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list)
++ if (zdev->user_space_type == type)
++ device_count++;
++ spin_unlock_bh(&zcrypt_device_lock);
++ return device_count;
++}
++
++/**
++ * Old, deprecated combi status call.
++ */
++static long zcrypt_ica_status(struct file *filp, unsigned long arg)
++{
++ struct ica_z90_status *pstat;
++ int ret;
++
++ pstat = kzalloc(sizeof(*pstat), GFP_KERNEL);
++ if (!pstat)
++ return -ENOMEM;
++ pstat->totalcount = zcrypt_device_count;
++ pstat->leedslitecount = zcrypt_count_type(ZCRYPT_PCICA);
++ pstat->leeds2count = zcrypt_count_type(ZCRYPT_PCICC);
++ pstat->requestqWaitCount = zcrypt_requestq_count();
++ pstat->pendingqWaitCount = zcrypt_pendingq_count();
++ pstat->totalOpenCount = atomic_read(&zcrypt_open_count);
++ pstat->cryptoDomain = ap_domain_index;
++ zcrypt_status_mask(pstat->status);
++ zcrypt_qdepth_mask(pstat->qdepth);
++ ret = 0;
++ if (copy_to_user((void __user *) arg, pstat, sizeof(*pstat)))
++ ret = -EFAULT;
++ kfree(pstat);
++ return ret;
++}
++
++static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ int rc;
++
++ switch (cmd) {
++ case ICARSAMODEXPO: {
++ struct ica_rsa_modexpo __user *umex = (void __user *) arg;
++ struct ica_rsa_modexpo mex;
++ if (copy_from_user(&mex, umex, sizeof(mex)))
++ return -EFAULT;
++ do {
++ rc = zcrypt_rsa_modexpo(&mex);
++ } while (rc == -EAGAIN);
++ if (rc)
++ return rc;
++ return put_user(mex.outputdatalength, &umex->outputdatalength);
++ }
++ case ICARSACRT: {
++ struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg;
++ struct ica_rsa_modexpo_crt crt;
++ if (copy_from_user(&crt, ucrt, sizeof(crt)))
++ return -EFAULT;
++ do {
++ rc = zcrypt_rsa_crt(&crt);
++ } while (rc == -EAGAIN);
++ if (rc)
++ return rc;
++ return put_user(crt.outputdatalength, &ucrt->outputdatalength);
++ }
++ case ZSECSENDCPRB: {
++ struct ica_xcRB __user *uxcRB = (void __user *) arg;
++ struct ica_xcRB xcRB;
++ if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
++ return -EFAULT;
++ do {
++ rc = zcrypt_send_cprb(&xcRB);
++ } while (rc == -EAGAIN);
++ if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
++ return -EFAULT;
++ return rc;
++ }
++ case Z90STAT_STATUS_MASK: {
++ char status[AP_DEVICES];
++ zcrypt_status_mask(status);
++ if (copy_to_user((char __user *) arg, status,
++ sizeof(char) * AP_DEVICES))
++ return -EFAULT;
++ return 0;
++ }
++ case Z90STAT_QDEPTH_MASK: {
++ char qdepth[AP_DEVICES];
++ zcrypt_qdepth_mask(qdepth);
++ if (copy_to_user((char __user *) arg, qdepth,
++ sizeof(char) * AP_DEVICES))
++ return -EFAULT;
++ return 0;
++ }
++ case Z90STAT_PERDEV_REQCNT: {
++ int reqcnt[AP_DEVICES];
++ zcrypt_perdev_reqcnt(reqcnt);
++ if (copy_to_user((int __user *) arg, reqcnt,
++ sizeof(int) * AP_DEVICES))
++ return -EFAULT;
++ return 0;
++ }
++ case Z90STAT_REQUESTQ_COUNT:
++ return put_user(zcrypt_requestq_count(), (int __user *) arg);
++ case Z90STAT_PENDINGQ_COUNT:
++ return put_user(zcrypt_pendingq_count(), (int __user *) arg);
++ case Z90STAT_TOTALOPEN_COUNT:
++ return put_user(atomic_read(&zcrypt_open_count),
++ (int __user *) arg);
++ case Z90STAT_DOMAIN_INDEX:
++ return put_user(ap_domain_index, (int __user *) arg);
++ /**
++ * Deprecated ioctls. Don't add another device count ioctl,
++ * you can count them yourself in the user space with the
++ * output of the Z90STAT_STATUS_MASK ioctl.
++ */
++ case ICAZ90STATUS:
++ return zcrypt_ica_status(filp, arg);
++ case Z90STAT_TOTALCOUNT:
++ return put_user(zcrypt_device_count, (int __user *) arg);
++ case Z90STAT_PCICACOUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_PCICA),
++ (int __user *) arg);
++ case Z90STAT_PCICCCOUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_PCICC),
++ (int __user *) arg);
++ case Z90STAT_PCIXCCMCL2COUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2),
++ (int __user *) arg);
++ case Z90STAT_PCIXCCMCL3COUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL3),
++ (int __user *) arg);
++ case Z90STAT_PCIXCCCOUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2) +
++ zcrypt_count_type(ZCRYPT_PCIXCC_MCL3),
++ (int __user *) arg);
++ case Z90STAT_CEX2CCOUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_CEX2C),
++ (int __user *) arg);
++ case Z90STAT_CEX2ACOUNT:
++ return put_user(zcrypt_count_type(ZCRYPT_CEX2A),
++ (int __user *) arg);
++ default:
++ /* unknown ioctl number */
++ return -ENOIOCTLCMD;
++ }
++}
++
++#ifdef CONFIG_COMPAT
++/**
++ * ioctl32 conversion routines
++ */
++struct compat_ica_rsa_modexpo {
++ compat_uptr_t inputdata;
++ unsigned int inputdatalength;
++ compat_uptr_t outputdata;
++ unsigned int outputdatalength;
++ compat_uptr_t b_key;
++ compat_uptr_t n_modulus;
++};
++
++static long trans_modexpo32(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
++ struct compat_ica_rsa_modexpo mex32;
++ struct ica_rsa_modexpo mex64;
++ long rc;
++
++ if (copy_from_user(&mex32, umex32, sizeof(mex32)))
++ return -EFAULT;
++ mex64.inputdata = compat_ptr(mex32.inputdata);
++ mex64.inputdatalength = mex32.inputdatalength;
++ mex64.outputdata = compat_ptr(mex32.outputdata);
++ mex64.outputdatalength = mex32.outputdatalength;
++ mex64.b_key = compat_ptr(mex32.b_key);
++ mex64.n_modulus = compat_ptr(mex32.n_modulus);
++ do {
++ rc = zcrypt_rsa_modexpo(&mex64);
++ } while (rc == -EAGAIN);
++ if (!rc)
++ rc = put_user(mex64.outputdatalength,
++ &umex32->outputdatalength);
++ return rc;
++}
++
++struct compat_ica_rsa_modexpo_crt {
++ compat_uptr_t inputdata;
++ unsigned int inputdatalength;
++ compat_uptr_t outputdata;
++ unsigned int outputdatalength;
++ compat_uptr_t bp_key;
++ compat_uptr_t bq_key;
++ compat_uptr_t np_prime;
++ compat_uptr_t nq_prime;
++ compat_uptr_t u_mult_inv;
++};
++
++static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
++ struct compat_ica_rsa_modexpo_crt crt32;
++ struct ica_rsa_modexpo_crt crt64;
++ long rc;
++
++ if (copy_from_user(&crt32, ucrt32, sizeof(crt32)))
++ return -EFAULT;
++ crt64.inputdata = compat_ptr(crt32.inputdata);
++ crt64.inputdatalength = crt32.inputdatalength;
++ crt64.outputdata= compat_ptr(crt32.outputdata);
++ crt64.outputdatalength = crt32.outputdatalength;
++ crt64.bp_key = compat_ptr(crt32.bp_key);
++ crt64.bq_key = compat_ptr(crt32.bq_key);
++ crt64.np_prime = compat_ptr(crt32.np_prime);
++ crt64.nq_prime = compat_ptr(crt32.nq_prime);
++ crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
++ do {
++ rc = zcrypt_rsa_crt(&crt64);
++ } while (rc == -EAGAIN);
++ if (!rc)
++ rc = put_user(crt64.outputdatalength,
++ &ucrt32->outputdatalength);
++ return rc;
++}
++
++struct compat_ica_xcRB {
++ unsigned short agent_ID;
++ unsigned int user_defined;
++ unsigned short request_ID;
++ unsigned int request_control_blk_length;
++ unsigned char padding1[16 - sizeof (compat_uptr_t)];
++ compat_uptr_t request_control_blk_addr;
++ unsigned int request_data_length;
++ char padding2[16 - sizeof (compat_uptr_t)];
++ compat_uptr_t request_data_address;
++ unsigned int reply_control_blk_length;
++ char padding3[16 - sizeof (compat_uptr_t)];
++ compat_uptr_t reply_control_blk_addr;
++ unsigned int reply_data_length;
++ char padding4[16 - sizeof (compat_uptr_t)];
++ compat_uptr_t reply_data_addr;
++ unsigned short priority_window;
++ unsigned int status;
++} __attribute__((packed));
++
++static long trans_xcRB32(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
++ struct compat_ica_xcRB xcRB32;
++ struct ica_xcRB xcRB64;
++ long rc;
++
++ if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32)))
++ return -EFAULT;
++ xcRB64.agent_ID = xcRB32.agent_ID;
++ xcRB64.user_defined = xcRB32.user_defined;
++ xcRB64.request_ID = xcRB32.request_ID;
++ xcRB64.request_control_blk_length =
++ xcRB32.request_control_blk_length;
++ xcRB64.request_control_blk_addr =
++ compat_ptr(xcRB32.request_control_blk_addr);
++ xcRB64.request_data_length =
++ xcRB32.request_data_length;
++ xcRB64.request_data_address =
++ compat_ptr(xcRB32.request_data_address);
++ xcRB64.reply_control_blk_length =
++ xcRB32.reply_control_blk_length;
++ xcRB64.reply_control_blk_addr =
++ compat_ptr(xcRB32.reply_control_blk_addr);
++ xcRB64.reply_data_length = xcRB32.reply_data_length;
++ xcRB64.reply_data_addr =
++ compat_ptr(xcRB32.reply_data_addr);
++ xcRB64.priority_window = xcRB32.priority_window;
++ xcRB64.status = xcRB32.status;
++ do {
++ rc = zcrypt_send_cprb(&xcRB64);
++ } while (rc == -EAGAIN);
++ xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
++ xcRB32.reply_data_length = xcRB64.reply_data_length;
++ xcRB32.status = xcRB64.status;
++ if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32)))
++ return -EFAULT;
++ return rc;
++}
++
++long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ if (cmd == ICARSAMODEXPO)
++ return trans_modexpo32(filp, cmd, arg);
++ if (cmd == ICARSACRT)
++ return trans_modexpo_crt32(filp, cmd, arg);
++ if (cmd == ZSECSENDCPRB)
++ return trans_xcRB32(filp, cmd, arg);
++ return zcrypt_unlocked_ioctl(filp, cmd, arg);
++}
++#endif
++
++/**
++ * Misc device file operations.
++ */
++static struct file_operations zcrypt_fops = {
++ .owner = THIS_MODULE,
++ .read = zcrypt_read,
++ .write = zcrypt_write,
++ .unlocked_ioctl = zcrypt_unlocked_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = zcrypt_compat_ioctl,
++#endif
++ .open = zcrypt_open,
++ .release = zcrypt_release
++};
++
++/**
++ * Misc device.
++ */
++static struct miscdevice zcrypt_misc_device = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "z90crypt",
++ .fops = &zcrypt_fops,
++};
++
++/**
++ * Deprecated /proc entry support.
++ */
++static struct proc_dir_entry *zcrypt_entry;
++
++static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
++ unsigned int len)
++{
++ int hl, i;
++
++ hl = 0;
++ for (i = 0; i < len; i++)
++ hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
++ hl += sprintf(outaddr+hl, " ");
++ return hl;
++}
++
++static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
++ unsigned int len)
++{
++ int hl, inl, c, cx;
++
++ hl = sprintf(outaddr, " ");
++ inl = 0;
++ for (c = 0; c < (len / 16); c++) {
++ hl += sprintcl(outaddr+hl, addr+inl, 16);
++ inl += 16;
++ }
++ cx = len%16;
++ if (cx) {
++ hl += sprintcl(outaddr+hl, addr+inl, cx);
++ inl += cx;
++ }
++ hl += sprintf(outaddr+hl, "\n");
++ return hl;
++}
++
++static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
++ unsigned char *addr, unsigned int len)
++{
++ int hl, inl, r, rx;
++
++ hl = sprintf(outaddr, "\n%s\n", title);
++ inl = 0;
++ for (r = 0; r < (len / 64); r++) {
++ hl += sprintrw(outaddr+hl, addr+inl, 64);
++ inl += 64;
++ }
++ rx = len % 64;
++ if (rx) {
++ hl += sprintrw(outaddr+hl, addr+inl, rx);
++ inl += rx;
++ }
++ hl += sprintf(outaddr+hl, "\n");
++ return hl;
++}
++
++static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
++ unsigned int *array, unsigned int len)
++{
++ int hl, r;
++
++ hl = sprintf(outaddr, "\n%s\n", title);
++ for (r = 0; r < len; r++) {
++ if ((r % 8) == 0)
++ hl += sprintf(outaddr+hl, " ");
++ hl += sprintf(outaddr+hl, "%08X ", array[r]);
++ if ((r % 8) == 7)
++ hl += sprintf(outaddr+hl, "\n");
++ }
++ hl += sprintf(outaddr+hl, "\n");
++ return hl;
++}
++
++static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ unsigned char *workarea;
++ int len;
++
++ len = 0;
++
++ /* resp_buff is a page. Use the right half for a work area */
++ workarea = resp_buff + 2000;
++ len += sprintf(resp_buff + len, "\nzcrypt version: %d.%d.%d\n",
++ ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT);
++ len += sprintf(resp_buff + len, "Cryptographic domain: %d\n",
++ ap_domain_index);
++ len += sprintf(resp_buff + len, "Total device count: %d\n",
++ zcrypt_device_count);
++ len += sprintf(resp_buff + len, "PCICA count: %d\n",
++ zcrypt_count_type(ZCRYPT_PCICA));
++ len += sprintf(resp_buff + len, "PCICC count: %d\n",
++ zcrypt_count_type(ZCRYPT_PCICC));
++ len += sprintf(resp_buff + len, "PCIXCC MCL2 count: %d\n",
++ zcrypt_count_type(ZCRYPT_PCIXCC_MCL2));
++ len += sprintf(resp_buff + len, "PCIXCC MCL3 count: %d\n",
++ zcrypt_count_type(ZCRYPT_PCIXCC_MCL3));
++ len += sprintf(resp_buff + len, "CEX2C count: %d\n",
++ zcrypt_count_type(ZCRYPT_CEX2C));
++ len += sprintf(resp_buff + len, "CEX2A count: %d\n",
++ zcrypt_count_type(ZCRYPT_CEX2A));
++ len += sprintf(resp_buff + len, "requestq count: %d\n",
++ zcrypt_requestq_count());
++ len += sprintf(resp_buff + len, "pendingq count: %d\n",
++ zcrypt_pendingq_count());
++ len += sprintf(resp_buff + len, "Total open handles: %d\n\n",
++ atomic_read(&zcrypt_open_count));
++ zcrypt_status_mask(workarea);
++ len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
++ "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
++ resp_buff+len, workarea, AP_DEVICES);
++ zcrypt_qdepth_mask(workarea);
++ len += sprinthx("Waiting work element counts",
++ resp_buff+len, workarea, AP_DEVICES);
++ zcrypt_perdev_reqcnt((unsigned int *) workarea);
++ len += sprinthx4("Per-device successfully completed request counts",
++ resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
++ *eof = 1;
++ memset((void *) workarea, 0x00, AP_DEVICES * sizeof(unsigned int));
++ return len;
++}
++
++static void zcrypt_disable_card(int index)
++{
++ struct zcrypt_device *zdev;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list)
++ if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
++ zdev->online = 0;
++ ap_flush_queue(zdev->ap_dev);
++ break;
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++}
++
++static void zcrypt_enable_card(int index)
++{
++ struct zcrypt_device *zdev;
++
++ spin_lock_bh(&zcrypt_device_lock);
++ list_for_each_entry(zdev, &zcrypt_device_list, list)
++ if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
++ zdev->online = 1;
++ break;
++ }
++ spin_unlock_bh(&zcrypt_device_lock);
++}
++
++static int zcrypt_status_write(struct file *file, const char __user *buffer,
++ unsigned long count, void *data)
++{
++ unsigned char *lbuf, *ptr;
++ unsigned long local_count;
++ int j;
++
++ if (count <= 0)
++ return 0;
++
++#define LBUFSIZE 1200UL
++ lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
++ if (!lbuf) {
++ PRINTK("kmalloc failed!\n");
++ return 0;
++ }
++
++ local_count = min(LBUFSIZE - 1, count);
++ if (copy_from_user(lbuf, buffer, local_count) != 0) {
++ kfree(lbuf);
++ return -EFAULT;
++ }
++ lbuf[local_count] = '\0';
++
++ ptr = strstr(lbuf, "Online devices");
++ if (!ptr) {
++ PRINTK("Unable to parse data (missing \"Online devices\")\n");
++ goto out;
++ }
++ ptr = strstr(ptr, "\n");
++ if (!ptr) {
++ PRINTK("Unable to parse data (missing newline "
++ "after \"Online devices\")\n");
++ goto out;
++ }
++ ptr++;
++
++ if (strstr(ptr, "Waiting work element counts") == NULL) {
++ PRINTK("Unable to parse data (missing "
++ "\"Waiting work element counts\")\n");
++ goto out;
++ }
++
++ for (j = 0; j < 64 && *ptr; ptr++) {
++ /**
++ * '0' for no device, '1' for PCICA, '2' for PCICC,
++ * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3,
++ * '5' for CEX2C and '6' for CEX2A'
++ */
++ if (*ptr >= '0' && *ptr <= '6')
++ j++;
++ else if (*ptr == 'd' || *ptr == 'D')
++ zcrypt_disable_card(j++);
++ else if (*ptr == 'e' || *ptr == 'E')
++ zcrypt_enable_card(j++);
++ else if (*ptr != ' ' && *ptr != '\t')
++ break;
++ }
++out:
++ kfree(lbuf);
++ return count;
++}
++
++/**
++ * The module initialization code.
++ */
++int __init zcrypt_api_init(void)
++{
++ int rc;
++
++ /* Register the request sprayer. */
++ rc = misc_register(&zcrypt_misc_device);
++ if (rc < 0) {
++ PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
++ zcrypt_misc_device.minor, rc);
++ goto out;
++ }
++
++ /* Set up the proc file system */
++ zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL);
++ if (!zcrypt_entry) {
++ PRINTK("Couldn't create z90crypt proc entry\n");
++ rc = -ENOMEM;
++ goto out_misc;
++ }
++ zcrypt_entry->nlink = 1;
++ zcrypt_entry->data = NULL;
++ zcrypt_entry->read_proc = zcrypt_status_read;
++ zcrypt_entry->write_proc = zcrypt_status_write;
++
++ return 0;
++
++out_misc:
++ misc_deregister(&zcrypt_misc_device);
++out:
++ return rc;
++}
++
++/**
++ * The module termination code.
++ */
++void zcrypt_api_exit(void)
++{
++ remove_proc_entry("driver/z90crypt", NULL);
++ misc_deregister(&zcrypt_misc_device);
++}
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++module_init(zcrypt_api_init);
++module_exit(zcrypt_api_exit);
++#endif
+diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
+new file mode 100644
+index 0000000..de4877e
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_api.h
+@@ -0,0 +1,141 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_api.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ * Cornelia Huck <cornelia.huck at de.ibm.com>
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.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, 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 _ZCRYPT_API_H_
++#define _ZCRYPT_API_H_
++
++/**
++ * Macro definitions
++ *
++ * PDEBUG debugs in the form "zcrypt: function_name -> message"
++ *
++ * PRINTK is like PDEBUG, except that it is always enabled
++ * PRINTKN is like PRINTK, except that it does not include the function name
++ * PRINTKW is like PRINTK, except that it uses KERN_WARNING
++ * PRINTKC is like PRINTK, except that it uses KERN_CRIT
++ */
++#define DEV_NAME "zcrypt"
++
++#define PRINTK(fmt, args...) \
++ printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
++#define PRINTKN(fmt, args...) \
++ printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
++#define PRINTKW(fmt, args...) \
++ printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
++#define PRINTKC(fmt, args...) \
++ printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
++
++#ifdef ZCRYPT_DEBUG
++#define PDEBUG(fmt, args...) \
++ printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
++#else
++#define PDEBUG(fmt, args...) do {} while (0)
++#endif
++
++#include "ap_bus.h"
++#include <asm/zcrypt.h>
++
++/* deprecated status calls */
++#define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status)
++#define Z90STAT_PCIXCCCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x43, int)
++
++/**
++ * This structure is deprecated and the corresponding ioctl() has been
++ * replaced with individual ioctl()s for each piece of data!
++ */
++struct ica_z90_status {
++ int totalcount;
++ int leedslitecount; // PCICA
++ int leeds2count; // PCICC
++ // int PCIXCCCount; is not in struct for backward compatibility
++ int requestqWaitCount;
++ int pendingqWaitCount;
++ int totalOpenCount;
++ int cryptoDomain;
++ // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3,
++ // 5=CEX2C
++ unsigned char status[64];
++ // qdepth: # work elements waiting for each device
++ unsigned char qdepth[64];
++};
++
++/**
++ * device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2,
++ * PCIXCC_MCL3, CEX2C, or CEX2A
++ *
++ * NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed
++ * Internal Code (LIC) (EC J12220 level 29).
++ * PCIXCC_MCL2 refers to any LIC before this level.
++ */
++#define ZCRYPT_PCICA 1
++#define ZCRYPT_PCICC 2
++#define ZCRYPT_PCIXCC_MCL2 3
++#define ZCRYPT_PCIXCC_MCL3 4
++#define ZCRYPT_CEX2C 5
++#define ZCRYPT_CEX2A 6
++
++struct zcrypt_device;
++
++struct zcrypt_ops {
++ long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
++ long (*rsa_modexpo_crt)(struct zcrypt_device *,
++ struct ica_rsa_modexpo_crt *);
++ long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *);
++};
++
++struct zcrypt_device {
++ struct list_head list; /* Device list. */
++ spinlock_t lock; /* Per device lock. */
++ struct kref refcount; /* device refcounting */
++ struct ap_device *ap_dev; /* The "real" ap device. */
++ struct zcrypt_ops *ops; /* Crypto operations. */
++ int online; /* User online/offline */
++
++ int user_space_type; /* User space device id. */
++ char *type_string; /* User space device name. */
++ int min_mod_size; /* Min number of bits. */
++ int max_mod_size; /* Max number of bits. */
++ int short_crt; /* Card has crt length restriction. */
++ int speed_rating; /* Speed of the crypto device. */
++
++ int request_count; /* # current requests. */
++
++ struct ap_message reply; /* Per-device reply structure. */
++};
++
++struct zcrypt_device *zcrypt_device_alloc(size_t);
++void zcrypt_device_free(struct zcrypt_device *);
++void zcrypt_device_get(struct zcrypt_device *);
++int zcrypt_device_put(struct zcrypt_device *);
++int zcrypt_device_register(struct zcrypt_device *);
++void zcrypt_device_unregister(struct zcrypt_device *);
++int zcrypt_api_init(void);
++void zcrypt_api_exit(void);
++
++#endif /* _ZCRYPT_API_H_ */
+diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h
+new file mode 100644
+index 0000000..8dbcf0e
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_cca_key.h
+@@ -0,0 +1,350 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_cca_key.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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 _ZCRYPT_CCA_KEY_H_
++#define _ZCRYPT_CCA_KEY_H_
++
++struct T6_keyBlock_hdr {
++ unsigned short blen;
++ unsigned short ulen;
++ unsigned short flags;
++};
++
++/**
++ * mapping for the cca private ME key token.
++ * Three parts of interest here: the header, the private section and
++ * the public section.
++ *
++ * mapping for the cca key token header
++ */
++struct cca_token_hdr {
++ unsigned char token_identifier;
++ unsigned char version;
++ unsigned short token_length;
++ unsigned char reserved[4];
++} __attribute__((packed));
++
++#define CCA_TKN_HDR_ID_EXT 0x1E
++
++/**
++ * mapping for the cca private ME section
++ */
++struct cca_private_ext_ME_sec {
++ unsigned char section_identifier;
++ unsigned char version;
++ unsigned short section_length;
++ unsigned char private_key_hash[20];
++ unsigned char reserved1[4];
++ unsigned char key_format;
++ unsigned char reserved2;
++ unsigned char key_name_hash[20];
++ unsigned char key_use_flags[4];
++ unsigned char reserved3[6];
++ unsigned char reserved4[24];
++ unsigned char confounder[24];
++ unsigned char exponent[128];
++ unsigned char modulus[128];
++} __attribute__((packed));
++
++#define CCA_PVT_USAGE_ALL 0x80
++
++/**
++ * mapping for the cca public section
++ * In a private key, the modulus doesn't appear in the public
++ * section. So, an arbitrary public exponent of 0x010001 will be
++ * used, for a section length of 0x0F always.
++ */
++struct cca_public_sec {
++ unsigned char section_identifier;
++ unsigned char version;
++ unsigned short section_length;
++ unsigned char reserved[2];
++ unsigned short exponent_len;
++ unsigned short modulus_bit_len;
++ unsigned short modulus_byte_len; /* In a private key, this is 0 */
++} __attribute__((packed));
++
++/**
++ * mapping for the cca private CRT key 'token'
++ * The first three parts (the only parts considered in this release)
++ * are: the header, the private section and the public section.
++ * The header and public section are the same as for the
++ * struct cca_private_ext_ME
++ *
++ * Following the structure are the quantities p, q, dp, dq, u, pad,
++ * and modulus, in that order, where pad_len is the modulo 8
++ * complement of the residue modulo 8 of the sum of
++ * (p_len + q_len + dp_len + dq_len + u_len).
++ */
++struct cca_pvt_ext_CRT_sec {
++ unsigned char section_identifier;
++ unsigned char version;
++ unsigned short section_length;
++ unsigned char private_key_hash[20];
++ unsigned char reserved1[4];
++ unsigned char key_format;
++ unsigned char reserved2;
++ unsigned char key_name_hash[20];
++ unsigned char key_use_flags[4];
++ unsigned short p_len;
++ unsigned short q_len;
++ unsigned short dp_len;
++ unsigned short dq_len;
++ unsigned short u_len;
++ unsigned short mod_len;
++ unsigned char reserved3[4];
++ unsigned short pad_len;
++ unsigned char reserved4[52];
++ unsigned char confounder[8];
++} __attribute__((packed));
++
++#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
++#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
++
++/**
++ * Set up private key fields of a type6 MEX message.
++ * Note that all numerics in the key token are big-endian,
++ * while the entries in the key block header are little-endian.
++ *
++ * @mex: pointer to user input data
++ * @p: pointer to memory area for the key
++ *
++ * Returns the size of the key area or -EFAULT
++ */
++static inline int zcrypt_type6_mex_key_de(struct ica_rsa_modexpo *mex,
++ void *p, int big_endian)
++{
++ static struct cca_token_hdr static_pvt_me_hdr = {
++ .token_identifier = 0x1E,
++ .token_length = 0x0183,
++ };
++ static struct cca_private_ext_ME_sec static_pvt_me_sec = {
++ .section_identifier = 0x02,
++ .section_length = 0x016C,
++ .key_use_flags = {0x80,0x00,0x00,0x00},
++ };
++ static struct cca_public_sec static_pub_me_sec = {
++ .section_identifier = 0x04,
++ .section_length = 0x000F,
++ .exponent_len = 0x0003,
++ };
++ static char pk_exponent[3] = { 0x01, 0x00, 0x01 };
++ struct {
++ struct T6_keyBlock_hdr t6_hdr;
++ struct cca_token_hdr pvtMeHdr;
++ struct cca_private_ext_ME_sec pvtMeSec;
++ struct cca_public_sec pubMeSec;
++ char exponent[3];
++ } __attribute__((packed)) *key = p;
++ unsigned char *temp;
++
++ memset(key, 0, sizeof(*key));
++
++ if (big_endian) {
++ key->t6_hdr.blen = cpu_to_be16(0x189);
++ key->t6_hdr.ulen = cpu_to_be16(0x189 - 2);
++ } else {
++ key->t6_hdr.blen = cpu_to_le16(0x189);
++ key->t6_hdr.ulen = cpu_to_le16(0x189 - 2);
++ }
++ key->pvtMeHdr = static_pvt_me_hdr;
++ key->pvtMeSec = static_pvt_me_sec;
++ key->pubMeSec = static_pub_me_sec;
++ /**
++ * In a private key, the modulus doesn't appear in the public
++ * section. So, an arbitrary public exponent of 0x010001 will be
++ * used.
++ */
++ memcpy(key->exponent, pk_exponent, 3);
++
++ /* key parameter block */
++ temp = key->pvtMeSec.exponent +
++ sizeof(key->pvtMeSec.exponent) - mex->inputdatalength;
++ if (copy_from_user(temp, mex->b_key, mex->inputdatalength))
++ return -EFAULT;
++
++ /* modulus */
++ temp = key->pvtMeSec.modulus +
++ sizeof(key->pvtMeSec.modulus) - mex->inputdatalength;
++ if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength))
++ return -EFAULT;
++ key->pubMeSec.modulus_bit_len = 8 * mex->inputdatalength;
++ return sizeof(*key);
++}
++
++/**
++ * Set up private key fields of a type6 MEX message. The _pad variant
++ * strips leading zeroes from the b_key.
++ * Note that all numerics in the key token are big-endian,
++ * while the entries in the key block header are little-endian.
++ *
++ * @mex: pointer to user input data
++ * @p: pointer to memory area for the key
++ *
++ * Returns the size of the key area or -EFAULT
++ */
++static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex,
++ void *p, int big_endian)
++{
++ static struct cca_token_hdr static_pub_hdr = {
++ .token_identifier = 0x1E,
++ };
++ static struct cca_public_sec static_pub_sec = {
++ .section_identifier = 0x04,
++ };
++ struct {
++ struct T6_keyBlock_hdr t6_hdr;
++ struct cca_token_hdr pubHdr;
++ struct cca_public_sec pubSec;
++ char exponent[0];
++ } __attribute__((packed)) *key = p;
++ unsigned char *temp;
++ int i;
++
++ memset(key, 0, sizeof(*key));
++
++ key->pubHdr = static_pub_hdr;
++ key->pubSec = static_pub_sec;
++
++ /* key parameter block */
++ temp = key->exponent;
++ if (copy_from_user(temp, mex->b_key, mex->inputdatalength))
++ return -EFAULT;
++ /* Strip leading zeroes from b_key. */
++ for (i = 0; i < mex->inputdatalength; i++)
++ if (temp[i])
++ break;
++ if (i >= mex->inputdatalength)
++ return -EINVAL;
++ memmove(temp, temp + i, mex->inputdatalength - i);
++ temp += mex->inputdatalength - i;
++ /* modulus */
++ if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength))
++ return -EFAULT;
++
++ key->pubSec.modulus_bit_len = 8 * mex->inputdatalength;
++ key->pubSec.modulus_byte_len = mex->inputdatalength;
++ key->pubSec.exponent_len = mex->inputdatalength - i;
++ key->pubSec.section_length = sizeof(key->pubSec) +
++ 2*mex->inputdatalength - i;
++ key->pubHdr.token_length =
++ key->pubSec.section_length + sizeof(key->pubHdr);
++ if (big_endian) {
++ key->t6_hdr.ulen = cpu_to_be16(key->pubHdr.token_length + 4);
++ key->t6_hdr.blen = cpu_to_be16(key->pubHdr.token_length + 6);
++ } else {
++ key->t6_hdr.ulen = cpu_to_le16(key->pubHdr.token_length + 4);
++ key->t6_hdr.blen = cpu_to_le16(key->pubHdr.token_length + 6);
++ }
++ return sizeof(*key) + 2*mex->inputdatalength - i;
++}
++
++/**
++ * Set up private key fields of a type6 CRT message.
++ * Note that all numerics in the key token are big-endian,
++ * while the entries in the key block header are little-endian.
++ *
++ * @mex: pointer to user input data
++ * @p: pointer to memory area for the key
++ *
++ * Returns the size of the key area or -EFAULT
++ */
++static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt,
++ void *p, int big_endian)
++{
++ static struct cca_public_sec static_cca_pub_sec = {
++ .section_identifier = 4,
++ .section_length = 0x000f,
++ .exponent_len = 0x0003,
++ };
++ static char pk_exponent[3] = { 0x01, 0x00, 0x01 };
++ struct {
++ struct T6_keyBlock_hdr t6_hdr;
++ struct cca_token_hdr token;
++ struct cca_pvt_ext_CRT_sec pvt;
++ char key_parts[0];
++ } __attribute__((packed)) *key = p;
++ struct cca_public_sec *pub;
++ int short_len, long_len, pad_len, key_len, size;
++
++ memset(key, 0, sizeof(*key));
++
++ short_len = crt->inputdatalength / 2;
++ long_len = short_len + 8;
++ pad_len = -(3*long_len + 2*short_len) & 7;
++ key_len = 3*long_len + 2*short_len + pad_len + crt->inputdatalength;
++ size = sizeof(*key) + key_len + sizeof(*pub) + 3;
++
++ /* parameter block.key block */
++ if (big_endian) {
++ key->t6_hdr.blen = cpu_to_be16(size);
++ key->t6_hdr.ulen = cpu_to_be16(size - 2);
++ } else {
++ key->t6_hdr.blen = cpu_to_le16(size);
++ key->t6_hdr.ulen = cpu_to_le16(size - 2);
++ }
++
++ /* key token header */
++ key->token.token_identifier = CCA_TKN_HDR_ID_EXT;
++ key->token.token_length = size - 6;
++
++ /* private section */
++ key->pvt.section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
++ key->pvt.section_length = sizeof(key->pvt) + key_len;
++ key->pvt.key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
++ key->pvt.key_use_flags[0] = CCA_PVT_USAGE_ALL;
++ key->pvt.p_len = key->pvt.dp_len = key->pvt.u_len = long_len;
++ key->pvt.q_len = key->pvt.dq_len = short_len;
++ key->pvt.mod_len = crt->inputdatalength;
++ key->pvt.pad_len = pad_len;
++
++ /* key parts */
++ if (copy_from_user(key->key_parts, crt->np_prime, long_len) ||
++ copy_from_user(key->key_parts + long_len,
++ crt->nq_prime, short_len) ||
++ copy_from_user(key->key_parts + long_len + short_len,
++ crt->bp_key, long_len) ||
++ copy_from_user(key->key_parts + 2*long_len + short_len,
++ crt->bq_key, short_len) ||
++ copy_from_user(key->key_parts + 2*long_len + 2*short_len,
++ crt->u_mult_inv, long_len))
++ return -EFAULT;
++ memset(key->key_parts + 3*long_len + 2*short_len + pad_len,
++ 0xff, crt->inputdatalength);
++ pub = (struct cca_public_sec *)(key->key_parts + key_len);
++ *pub = static_cca_pub_sec;
++ pub->modulus_bit_len = 8 * crt->inputdatalength;
++ /**
++ * In a private key, the modulus doesn't appear in the public
++ * section. So, an arbitrary public exponent of 0x010001 will be
++ * used.
++ */
++ memcpy((char *) (pub + 1), pk_exponent, 3);
++ return size;
++}
++
++#endif /* _ZCRYPT_CCA_KEY_H_ */
+diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
+new file mode 100644
+index 0000000..a62b000
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_cex2a.c
+@@ -0,0 +1,435 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_cex2a.c
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.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, 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/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#include "ap_bus.h"
++#include "zcrypt_api.h"
++#include "zcrypt_error.h"
++#include "zcrypt_cex2a.h"
++
++#define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */
++#define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */
++
++#define CEX2A_SPEED_RATING 970
++
++#define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
++#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
++
++#define CEX2A_CLEANUP_TIME (15*HZ)
++
++static struct ap_device_id zcrypt_cex2a_ids[] = {
++ { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
++ { /* end of list */ },
++};
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
++MODULE_AUTHOR("IBM Corporation");
++MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, "
++ "Copyright 2001, 2006 IBM Corporation");
++MODULE_LICENSE("GPL");
++#endif
++
++static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
++static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
++static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
++ struct ap_message *);
++
++static struct ap_driver zcrypt_cex2a_driver = {
++ .probe = zcrypt_cex2a_probe,
++ .remove = zcrypt_cex2a_remove,
++ .receive = zcrypt_cex2a_receive,
++ .ids = zcrypt_cex2a_ids,
++};
++
++/**
++ * Convert a ICAMEX message to a type50 MEX message.
++ *
++ * @zdev: crypto device pointer
++ * @zreq: crypto request pointer
++ * @mex: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo *mex)
++{
++ unsigned char *mod, *exp, *inp;
++ int mod_len;
++
++ mod_len = mex->inputdatalength;
++
++ if (mod_len <= 128) {
++ struct type50_meb1_msg *meb1 = ap_msg->message;
++ memset(meb1, 0, sizeof(*meb1));
++ ap_msg->length = sizeof(*meb1);
++ meb1->header.msg_type_code = TYPE50_TYPE_CODE;
++ meb1->header.msg_len = sizeof(*meb1);
++ meb1->keyblock_type = TYPE50_MEB1_FMT;
++ mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
++ exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
++ inp = meb1->message + sizeof(meb1->message) - mod_len;
++ } else {
++ struct type50_meb2_msg *meb2 = ap_msg->message;
++ memset(meb2, 0, sizeof(*meb2));
++ ap_msg->length = sizeof(*meb2);
++ meb2->header.msg_type_code = TYPE50_TYPE_CODE;
++ meb2->header.msg_len = sizeof(*meb2);
++ meb2->keyblock_type = TYPE50_MEB2_FMT;
++ mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
++ exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
++ inp = meb2->message + sizeof(meb2->message) - mod_len;
++ }
++
++ if (copy_from_user(mod, mex->n_modulus, mod_len) ||
++ copy_from_user(exp, mex->b_key, mod_len) ||
++ copy_from_user(inp, mex->inputdata, mod_len))
++ return -EFAULT;
++ return 0;
++}
++
++/**
++ * Convert a ICACRT message to a type50 CRT message.
++ *
++ * @zdev: crypto device pointer
++ * @zreq: crypto request pointer
++ * @crt: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ int mod_len, short_len, long_len, long_offset;
++ unsigned char *p, *q, *dp, *dq, *u, *inp;
++
++ mod_len = crt->inputdatalength;
++ short_len = mod_len / 2;
++ long_len = mod_len / 2 + 8;
++
++ /*
++ * CEX2A cannot handle p, dp, or U > 128 bytes.
++ * If we have one of these, we need to do extra checking.
++ */
++ if (long_len > 128) {
++ /*
++ * zcrypt_rsa_crt already checked for the leading
++ * zeroes of np_prime, bp_key and u_mult_inc.
++ */
++ long_offset = long_len - 128;
++ long_len = 128;
++ } else
++ long_offset = 0;
++
++ /*
++ * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use
++ * the larger message structure.
++ */
++ if (long_len <= 64) {
++ struct type50_crb1_msg *crb1 = ap_msg->message;
++ memset(crb1, 0, sizeof(*crb1));
++ ap_msg->length = sizeof(*crb1);
++ crb1->header.msg_type_code = TYPE50_TYPE_CODE;
++ crb1->header.msg_len = sizeof(*crb1);
++ crb1->keyblock_type = TYPE50_CRB1_FMT;
++ p = crb1->p + sizeof(crb1->p) - long_len;
++ q = crb1->q + sizeof(crb1->q) - short_len;
++ dp = crb1->dp + sizeof(crb1->dp) - long_len;
++ dq = crb1->dq + sizeof(crb1->dq) - short_len;
++ u = crb1->u + sizeof(crb1->u) - long_len;
++ inp = crb1->message + sizeof(crb1->message) - mod_len;
++ } else {
++ struct type50_crb2_msg *crb2 = ap_msg->message;
++ memset(crb2, 0, sizeof(*crb2));
++ ap_msg->length = sizeof(*crb2);
++ crb2->header.msg_type_code = TYPE50_TYPE_CODE;
++ crb2->header.msg_len = sizeof(*crb2);
++ crb2->keyblock_type = TYPE50_CRB2_FMT;
++ p = crb2->p + sizeof(crb2->p) - long_len;
++ q = crb2->q + sizeof(crb2->q) - short_len;
++ dp = crb2->dp + sizeof(crb2->dp) - long_len;
++ dq = crb2->dq + sizeof(crb2->dq) - short_len;
++ u = crb2->u + sizeof(crb2->u) - long_len;
++ inp = crb2->message + sizeof(crb2->message) - mod_len;
++ }
++
++ if (copy_from_user(p, crt->np_prime + long_offset, long_len) ||
++ copy_from_user(q, crt->nq_prime, short_len) ||
++ copy_from_user(dp, crt->bp_key + long_offset, long_len) ||
++ copy_from_user(dq, crt->bq_key, short_len) ||
++ copy_from_user(u, crt->u_mult_inv + long_offset, long_len) ||
++ copy_from_user(inp, crt->inputdata, mod_len))
++ return -EFAULT;
++
++
++ return 0;
++}
++
++/**
++ * Copy results from a type 80 reply message back to user space.
++ *
++ * @zdev: crypto device pointer
++ * @reply: reply AP message.
++ * @data: pointer to user output data
++ * @length: size of user output data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int convert_type80(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ struct type80_hdr *t80h = reply->message;
++ unsigned char *data;
++
++ if (t80h->len < sizeof(*t80h) + outputdatalength) {
++ /* The result is too short, the CEX2A card may not do that.. */
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++ BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
++ data = reply->message + t80h->len - outputdatalength;
++ if (copy_to_user(outputdata, data, outputdatalength))
++ return -EFAULT;
++ return 0;
++}
++
++static int convert_response(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ /* Response type byte is the second byte in the response. */
++ switch (((unsigned char *) reply->message)[1]) {
++ case TYPE82_RSP_CODE:
++ case TYPE88_RSP_CODE:
++ return convert_error(zdev, reply);
++ case TYPE80_RSP_CODE:
++ return convert_type80(zdev, reply,
++ outputdata, outputdatalength);
++ default: /* Unknown response type, this should NEVER EVER happen */
++ PRINTK("Unrecognized Message Header: %08x%08x\n",
++ *(unsigned int *) reply->message,
++ *(unsigned int *) (reply->message+4));
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++}
++
++/**
++ * This function is called from the AP bus code after a crypto request
++ * "msg" has finished with the reply message "reply".
++ * It is called from tasklet context.
++ * @ap_dev: pointer to the AP device
++ * @msg: pointer to the AP message
++ * @reply: pointer to the AP reply message
++ */
++static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
++ struct ap_message *msg,
++ struct ap_message *reply)
++{
++ static struct error_hdr error_reply = {
++ .type = TYPE82_RSP_CODE,
++ .reply_code = REP82_ERROR_MACHINE_FAILURE,
++ };
++ struct type80_hdr *t80h = reply->message;
++ int length;
++
++ /* Copy the reply message to the request message buffer. */
++ if (IS_ERR(reply))
++ memcpy(msg->message, &error_reply, sizeof(error_reply));
++ else if (t80h->type == TYPE80_RSP_CODE) {
++ length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
++ memcpy(msg->message, reply->message, length);
++ } else
++ memcpy(msg->message, reply->message, sizeof error_reply);
++ complete((struct completion *) msg->private);
++}
++
++static atomic_t zcrypt_step = ATOMIC_INIT(0);
++
++/**
++ * The request distributor calls this function if it picked the CEX2A
++ * device to handle a modexpo request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * CEX2A device to the request distributor
++ * @mex: pointer to the modexpo request buffer
++ */
++static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo *mex)
++{
++ struct ap_message ap_msg;
++ struct completion work;
++ int rc;
++
++ ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &work;
++ rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
++ if (rc)
++ goto out_free;
++ init_completion(&work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &work, CEX2A_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response(zdev, &ap_msg, mex->outputdata,
++ mex->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ kfree(ap_msg.message);
++ return rc;
++}
++
++/**
++ * The request distributor calls this function if it picked the CEX2A
++ * device to handle a modexpo_crt request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * CEX2A device to the request distributor
++ * @crt: pointer to the modexpoc_crt request buffer
++ */
++static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ struct ap_message ap_msg;
++ struct completion work;
++ int rc;
++
++ ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &work;
++ rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
++ if (rc)
++ goto out_free;
++ init_completion(&work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &work, CEX2A_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response(zdev, &ap_msg, crt->outputdata,
++ crt->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ kfree(ap_msg.message);
++ return rc;
++}
++
++/**
++ * The crypto operations for a CEX2A card.
++ */
++static struct zcrypt_ops zcrypt_cex2a_ops = {
++ .rsa_modexpo = zcrypt_cex2a_modexpo,
++ .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
++};
++
++/**
++ * Probe function for CEX2A cards. It always accepts the AP device
++ * since the bus_match already checked the hardware type.
++ * @ap_dev: pointer to the AP device.
++ */
++static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev;
++ int rc;
++
++ zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
++ if (!zdev)
++ return -ENOMEM;
++ zdev->ap_dev = ap_dev;
++ zdev->ops = &zcrypt_cex2a_ops;
++ zdev->online = 1;
++ zdev->user_space_type = ZCRYPT_CEX2A;
++ zdev->type_string = "CEX2A";
++ zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
++ zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
++ zdev->short_crt = 1;
++ zdev->speed_rating = CEX2A_SPEED_RATING;
++ ap_dev->reply = &zdev->reply;
++ ap_dev->private = zdev;
++ rc = zcrypt_device_register(zdev);
++ if (rc)
++ goto out_free;
++ return 0;
++
++out_free:
++ ap_dev->private = NULL;
++ zcrypt_device_free(zdev);
++ return rc;
++}
++
++/**
++ * This is called to remove the extended CEX2A driver information
++ * if an AP device is removed.
++ */
++static void zcrypt_cex2a_remove(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev = ap_dev->private;
++
++ zcrypt_device_unregister(zdev);
++}
++
++int __init zcrypt_cex2a_init(void)
++{
++ return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a");
++}
++
++void __exit zcrypt_cex2a_exit(void)
++{
++ ap_driver_unregister(&zcrypt_cex2a_driver);
++}
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++module_init(zcrypt_cex2a_init);
++module_exit(zcrypt_cex2a_exit);
++#endif
+diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h
+new file mode 100644
+index 0000000..8f69d1d
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_cex2a.h
+@@ -0,0 +1,126 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_cex2a.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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 _ZCRYPT_CEX2A_H_
++#define _ZCRYPT_CEX2A_H_
++
++/**
++ * The type 50 message family is associated with a CEX2A card.
++ *
++ * The four members of the family are described below.
++ *
++ * Note that all unsigned char arrays are right-justified and left-padded
++ * with zeroes.
++ *
++ * Note that all reserved fields must be zeroes.
++ */
++struct type50_hdr {
++ unsigned char reserved1;
++ unsigned char msg_type_code; /* 0x50 */
++ unsigned short msg_len;
++ unsigned char reserved2;
++ unsigned char ignored;
++ unsigned short reserved3;
++} __attribute__((packed));
++
++#define TYPE50_TYPE_CODE 0x50
++
++#define TYPE50_MEB1_FMT 0x0001
++#define TYPE50_MEB2_FMT 0x0002
++#define TYPE50_CRB1_FMT 0x0011
++#define TYPE50_CRB2_FMT 0x0012
++
++/* Mod-Exp, with a small modulus */
++struct type50_meb1_msg {
++ struct type50_hdr header;
++ unsigned short keyblock_type; /* 0x0001 */
++ unsigned char reserved[6];
++ unsigned char exponent[128];
++ unsigned char modulus[128];
++ unsigned char message[128];
++} __attribute__((packed));
++
++/* Mod-Exp, with a large modulus */
++struct type50_meb2_msg {
++ struct type50_hdr header;
++ unsigned short keyblock_type; /* 0x0002 */
++ unsigned char reserved[6];
++ unsigned char exponent[256];
++ unsigned char modulus[256];
++ unsigned char message[256];
++} __attribute__((packed));
++
++/* CRT, with a small modulus */
++struct type50_crb1_msg {
++ struct type50_hdr header;
++ unsigned short keyblock_type; /* 0x0011 */
++ unsigned char reserved[6];
++ unsigned char p[64];
++ unsigned char q[64];
++ unsigned char dp[64];
++ unsigned char dq[64];
++ unsigned char u[64];
++ unsigned char message[128];
++} __attribute__((packed));
++
++/* CRT, with a large modulus */
++struct type50_crb2_msg {
++ struct type50_hdr header;
++ unsigned short keyblock_type; /* 0x0012 */
++ unsigned char reserved[6];
++ unsigned char p[128];
++ unsigned char q[128];
++ unsigned char dp[128];
++ unsigned char dq[128];
++ unsigned char u[128];
++ unsigned char message[256];
++} __attribute__((packed));
++
++/**
++ * The type 80 response family is associated with a CEX2A card.
++ *
++ * Note that all unsigned char arrays are right-justified and left-padded
++ * with zeroes.
++ *
++ * Note that all reserved fields must be zeroes.
++ */
++
++#define TYPE80_RSP_CODE 0x80
++
++struct type80_hdr {
++ unsigned char reserved1;
++ unsigned char type; /* 0x80 */
++ unsigned short len;
++ unsigned char code; /* 0x00 */
++ unsigned char reserved2[3];
++ unsigned char reserved3[8];
++} __attribute__((packed));
++
++int zcrypt_cex2a_init(void);
++void zcrypt_cex2a_exit(void);
++
++#endif /* _ZCRYPT_CEX2A_H_ */
+diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h
+new file mode 100644
+index 0000000..2cb616b
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_error.h
+@@ -0,0 +1,133 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_error.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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 _ZCRYPT_ERROR_H_
++#define _ZCRYPT_ERROR_H_
++
++#include "zcrypt_api.h"
++
++/**
++ * Reply Messages
++ *
++ * Error reply messages are of two types:
++ * 82: Error (see below)
++ * 88: Error (see below)
++ * Both type 82 and type 88 have the same structure in the header.
++ *
++ * Request reply messages are of three known types:
++ * 80: Reply from a Type 50 Request (see CEX2A-RELATED STRUCTS)
++ * 84: Reply from a Type 4 Request (see PCICA-RELATED STRUCTS)
++ * 86: Reply from a Type 6 Request (see PCICC/PCIXCC/CEX2C-RELATED STRUCTS)
++ *
++ */
++struct error_hdr {
++ unsigned char reserved1; /* 0x00 */
++ unsigned char type; /* 0x82 or 0x88 */
++ unsigned char reserved2[2]; /* 0x0000 */
++ unsigned char reply_code; /* reply code */
++ unsigned char reserved3[3]; /* 0x000000 */
++};
++
++#define TYPE82_RSP_CODE 0x82
++#define TYPE88_RSP_CODE 0x88
++
++#define REP82_ERROR_MACHINE_FAILURE 0x10
++#define REP82_ERROR_PREEMPT_FAILURE 0x12
++#define REP82_ERROR_CHECKPT_FAILURE 0x14
++#define REP82_ERROR_MESSAGE_TYPE 0x20
++#define REP82_ERROR_INVALID_COMM_CD 0x21 /* Type 84 */
++#define REP82_ERROR_INVALID_MSG_LEN 0x23
++#define REP82_ERROR_RESERVD_FIELD 0x24 /* was 0x50 */
++#define REP82_ERROR_FORMAT_FIELD 0x29
++#define REP82_ERROR_INVALID_COMMAND 0x30
++#define REP82_ERROR_MALFORMED_MSG 0x40
++#define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */
++#define REP82_ERROR_WORD_ALIGNMENT 0x60
++#define REP82_ERROR_MESSAGE_LENGTH 0x80
++#define REP82_ERROR_OPERAND_INVALID 0x82
++#define REP82_ERROR_OPERAND_SIZE 0x84
++#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
++#define REP82_ERROR_RESERVED_FIELD 0x88
++#define REP82_ERROR_TRANSPORT_FAIL 0x90
++#define REP82_ERROR_PACKET_TRUNCATED 0xA0
++#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
++
++#define REP88_ERROR_MODULE_FAILURE 0x10
++
++#define REP88_ERROR_MESSAGE_TYPE 0x20
++#define REP88_ERROR_MESSAGE_MALFORMD 0x22
++#define REP88_ERROR_MESSAGE_LENGTH 0x23
++#define REP88_ERROR_RESERVED_FIELD 0x24
++#define REP88_ERROR_KEY_TYPE 0x34
++#define REP88_ERROR_INVALID_KEY 0x82 /* CEX2A */
++#define REP88_ERROR_OPERAND 0x84 /* CEX2A */
++#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */
++
++static inline int convert_error(struct zcrypt_device *zdev,
++ struct ap_message *reply)
++{
++ struct error_hdr *ehdr = reply->message;
++
++ PRINTK("Hardware error : Type %02x Message Header: %08x%08x\n",
++ ehdr->type, *(unsigned int *) reply->message,
++ *(unsigned int *) (reply->message + 4));
++
++ switch (ehdr->reply_code) {
++ case REP82_ERROR_OPERAND_INVALID:
++ case REP82_ERROR_OPERAND_SIZE:
++ case REP82_ERROR_EVEN_MOD_IN_OPND:
++ case REP88_ERROR_MESSAGE_MALFORMD:
++ // REP88_ERROR_INVALID_KEY // '82' CEX2A
++ // REP88_ERROR_OPERAND // '84' CEX2A
++ // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A
++ /* Invalid input data. */
++ return -EINVAL;
++ case REP82_ERROR_MESSAGE_TYPE:
++ // REP88_ERROR_MESSAGE_TYPE // '20' CEX2A
++ /**
++ * To sent a message of the wrong type is a bug in the
++ * device driver. Warn about it, disable the device
++ * and then repeat the request.
++ */
++ WARN_ON(1);
++ zdev->online = 0;
++ return -EAGAIN;
++ case REP82_ERROR_TRANSPORT_FAIL:
++ case REP82_ERROR_MACHINE_FAILURE:
++ // REP88_ERROR_MODULE_FAILURE // '10' CEX2A
++ /* If a card fails disable it and repeat the request. */
++ zdev->online = 0;
++ return -EAGAIN;
++ default:
++ PRINTKW("unknown type %02x reply code = %d\n",
++ ehdr->type, ehdr->reply_code);
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++}
++
++#endif /* _ZCRYPT_ERROR_H_ */
+diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
+new file mode 100644
+index 0000000..2a9349a
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_mono.c
+@@ -0,0 +1,100 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_mono.c
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/compat.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#include "ap_bus.h"
++#include "zcrypt_api.h"
++#include "zcrypt_pcica.h"
++#include "zcrypt_pcicc.h"
++#include "zcrypt_pcixcc.h"
++#include "zcrypt_cex2a.h"
++
++/**
++ * The module initialization code.
++ */
++int __init zcrypt_init(void)
++{
++ int rc;
++
++ rc = ap_module_init();
++ if (rc)
++ goto out;
++ rc = zcrypt_api_init();
++ if (rc)
++ goto out_ap;
++ rc = zcrypt_pcica_init();
++ if (rc)
++ goto out_api;
++ rc = zcrypt_pcicc_init();
++ if (rc)
++ goto out_pcica;
++ rc = zcrypt_pcixcc_init();
++ if (rc)
++ goto out_pcicc;
++ rc = zcrypt_cex2a_init();
++ if (rc)
++ goto out_pcixcc;
++ return 0;
++
++out_pcixcc:
++ zcrypt_pcixcc_exit();
++out_pcicc:
++ zcrypt_pcicc_exit();
++out_pcica:
++ zcrypt_pcica_exit();
++out_api:
++ zcrypt_api_exit();
++out_ap:
++ ap_module_exit();
++out:
++ return rc;
++}
++
++/**
++ * The module termination code.
++ */
++void __exit zcrypt_exit(void)
++{
++ zcrypt_cex2a_exit();
++ zcrypt_pcixcc_exit();
++ zcrypt_pcicc_exit();
++ zcrypt_pcica_exit();
++ zcrypt_api_exit();
++ ap_module_exit();
++}
++
++module_init(zcrypt_init);
++module_exit(zcrypt_exit);
+diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
+new file mode 100644
+index 0000000..b6a4ecd
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_pcica.c
+@@ -0,0 +1,418 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_pcica.c
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.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, 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/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#include "ap_bus.h"
++#include "zcrypt_api.h"
++#include "zcrypt_error.h"
++#include "zcrypt_pcica.h"
++
++#define PCICA_MIN_MOD_SIZE 1 /* 8 bits */
++#define PCICA_MAX_MOD_SIZE 256 /* 2048 bits */
++
++#define PCICA_SPEED_RATING 2800
++
++#define PCICA_MAX_MESSAGE_SIZE 0x3a0 /* sizeof(struct type4_lcr) */
++#define PCICA_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
++
++#define PCICA_CLEANUP_TIME (15*HZ)
++
++static struct ap_device_id zcrypt_pcica_ids[] = {
++ { AP_DEVICE(AP_DEVICE_TYPE_PCICA) },
++ { /* end of list */ },
++};
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++MODULE_DEVICE_TABLE(ap, zcrypt_pcica_ids);
++MODULE_AUTHOR("IBM Corporation");
++MODULE_DESCRIPTION("PCICA Cryptographic Coprocessor device driver, "
++ "Copyright 2001, 2006 IBM Corporation");
++MODULE_LICENSE("GPL");
++#endif
++
++static int zcrypt_pcica_probe(struct ap_device *ap_dev);
++static void zcrypt_pcica_remove(struct ap_device *ap_dev);
++static void zcrypt_pcica_receive(struct ap_device *, struct ap_message *,
++ struct ap_message *);
++
++static struct ap_driver zcrypt_pcica_driver = {
++ .probe = zcrypt_pcica_probe,
++ .remove = zcrypt_pcica_remove,
++ .receive = zcrypt_pcica_receive,
++ .ids = zcrypt_pcica_ids,
++};
++
++/**
++ * Convert a ICAMEX message to a type4 MEX message.
++ *
++ * @zdev: crypto device pointer
++ * @zreq: crypto request pointer
++ * @mex: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICAMEX_msg_to_type4MEX_msg(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo *mex)
++{
++ unsigned char *modulus, *exponent, *message;
++ int mod_len;
++
++ mod_len = mex->inputdatalength;
++
++ if (mod_len <= 128) {
++ struct type4_sme *sme = ap_msg->message;
++ memset(sme, 0, sizeof(*sme));
++ ap_msg->length = sizeof(*sme);
++ sme->header.msg_fmt = TYPE4_SME_FMT;
++ sme->header.msg_len = sizeof(*sme);
++ sme->header.msg_type_code = TYPE4_TYPE_CODE;
++ sme->header.request_code = TYPE4_REQU_CODE;
++ modulus = sme->modulus + sizeof(sme->modulus) - mod_len;
++ exponent = sme->exponent + sizeof(sme->exponent) - mod_len;
++ message = sme->message + sizeof(sme->message) - mod_len;
++ } else {
++ struct type4_lme *lme = ap_msg->message;
++ memset(lme, 0, sizeof(*lme));
++ ap_msg->length = sizeof(*lme);
++ lme->header.msg_fmt = TYPE4_LME_FMT;
++ lme->header.msg_len = sizeof(*lme);
++ lme->header.msg_type_code = TYPE4_TYPE_CODE;
++ lme->header.request_code = TYPE4_REQU_CODE;
++ modulus = lme->modulus + sizeof(lme->modulus) - mod_len;
++ exponent = lme->exponent + sizeof(lme->exponent) - mod_len;
++ message = lme->message + sizeof(lme->message) - mod_len;
++ }
++
++ if (copy_from_user(modulus, mex->n_modulus, mod_len) ||
++ copy_from_user(exponent, mex->b_key, mod_len) ||
++ copy_from_user(message, mex->inputdata, mod_len))
++ return -EFAULT;
++ return 0;
++}
++
++/**
++ * Convert a ICACRT message to a type4 CRT message.
++ *
++ * @zdev: crypto device pointer
++ * @zreq: crypto request pointer
++ * @crt: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ unsigned char *p, *q, *dp, *dq, *u, *inp;
++ int mod_len, short_len, long_len;
++
++ mod_len = crt->inputdatalength;
++ short_len = mod_len / 2;
++ long_len = mod_len / 2 + 8;
++
++ if (mod_len <= 128) {
++ struct type4_scr *scr = ap_msg->message;
++ memset(scr, 0, sizeof(*scr));
++ ap_msg->length = sizeof(*scr);
++ scr->header.msg_type_code = TYPE4_TYPE_CODE;
++ scr->header.request_code = TYPE4_REQU_CODE;
++ scr->header.msg_fmt = TYPE4_SCR_FMT;
++ scr->header.msg_len = sizeof(*scr);
++ p = scr->p + sizeof(scr->p) - long_len;
++ q = scr->q + sizeof(scr->q) - short_len;
++ dp = scr->dp + sizeof(scr->dp) - long_len;
++ dq = scr->dq + sizeof(scr->dq) - short_len;
++ u = scr->u + sizeof(scr->u) - long_len;
++ inp = scr->message + sizeof(scr->message) - mod_len;
++ } else {
++ struct type4_lcr *lcr = ap_msg->message;
++ memset(lcr, 0, sizeof(*lcr));
++ ap_msg->length = sizeof(*lcr);
++ lcr->header.msg_type_code = TYPE4_TYPE_CODE;
++ lcr->header.request_code = TYPE4_REQU_CODE;
++ lcr->header.msg_fmt = TYPE4_LCR_FMT;
++ lcr->header.msg_len = sizeof(*lcr);
++ p = lcr->p + sizeof(lcr->p) - long_len;
++ q = lcr->q + sizeof(lcr->q) - short_len;
++ dp = lcr->dp + sizeof(lcr->dp) - long_len;
++ dq = lcr->dq + sizeof(lcr->dq) - short_len;
++ u = lcr->u + sizeof(lcr->u) - long_len;
++ inp = lcr->message + sizeof(lcr->message) - mod_len;
++ }
++
++ if (copy_from_user(p, crt->np_prime, long_len) ||
++ copy_from_user(q, crt->nq_prime, short_len) ||
++ copy_from_user(dp, crt->bp_key, long_len) ||
++ copy_from_user(dq, crt->bq_key, short_len) ||
++ copy_from_user(u, crt->u_mult_inv, long_len) ||
++ copy_from_user(inp, crt->inputdata, mod_len))
++ return -EFAULT;
++ return 0;
++}
++
++/**
++ * Copy results from a type 84 reply message back to user space.
++ *
++ * @zdev: crypto device pointer
++ * @reply: reply AP message.
++ * @data: pointer to user output data
++ * @length: size of user output data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static inline int convert_type84(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ struct type84_hdr *t84h = reply->message;
++ char *data;
++
++ if (t84h->len < sizeof(*t84h) + outputdatalength) {
++ /* The result is too short, the PCICA card may not do that.. */
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++ BUG_ON(t84h->len > PCICA_MAX_RESPONSE_SIZE);
++ data = reply->message + t84h->len - outputdatalength;
++ if (copy_to_user(outputdata, data, outputdatalength))
++ return -EFAULT;
++ return 0;
++}
++
++static int convert_response(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ /* Response type byte is the second byte in the response. */
++ switch (((unsigned char *) reply->message)[1]) {
++ case TYPE82_RSP_CODE:
++ case TYPE88_RSP_CODE:
++ return convert_error(zdev, reply);
++ case TYPE84_RSP_CODE:
++ return convert_type84(zdev, reply,
++ outputdata, outputdatalength);
++ default: /* Unknown response type, this should NEVER EVER happen */
++ PRINTK("Unrecognized Message Header: %08x%08x\n",
++ *(unsigned int *) reply->message,
++ *(unsigned int *) (reply->message+4));
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++}
++
++/**
++ * This function is called from the AP bus code after a crypto request
++ * "msg" has finished with the reply message "reply".
++ * It is called from tasklet context.
++ * @ap_dev: pointer to the AP device
++ * @msg: pointer to the AP message
++ * @reply: pointer to the AP reply message
++ */
++static void zcrypt_pcica_receive(struct ap_device *ap_dev,
++ struct ap_message *msg,
++ struct ap_message *reply)
++{
++ static struct error_hdr error_reply = {
++ .type = TYPE82_RSP_CODE,
++ .reply_code = REP82_ERROR_MACHINE_FAILURE,
++ };
++ struct type84_hdr *t84h = reply->message;
++ int length;
++
++ /* Copy the reply message to the request message buffer. */
++ if (IS_ERR(reply))
++ memcpy(msg->message, &error_reply, sizeof(error_reply));
++ else if (t84h->code == TYPE84_RSP_CODE) {
++ length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len);
++ memcpy(msg->message, reply->message, length);
++ } else
++ memcpy(msg->message, reply->message, sizeof error_reply);
++ complete((struct completion *) msg->private);
++}
++
++static atomic_t zcrypt_step = ATOMIC_INIT(0);
++
++/**
++ * The request distributor calls this function if it picked the PCICA
++ * device to handle a modexpo request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCICA device to the request distributor
++ * @mex: pointer to the modexpo request buffer
++ */
++static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo *mex)
++{
++ struct ap_message ap_msg;
++ struct completion work;
++ int rc;
++
++ ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &work;
++ rc = ICAMEX_msg_to_type4MEX_msg(zdev, &ap_msg, mex);
++ if (rc)
++ goto out_free;
++ init_completion(&work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &work, PCICA_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response(zdev, &ap_msg, mex->outputdata,
++ mex->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ kfree(ap_msg.message);
++ return rc;
++}
++
++/**
++ * The request distributor calls this function if it picked the PCICA
++ * device to handle a modexpo_crt request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCICA device to the request distributor
++ * @crt: pointer to the modexpoc_crt request buffer
++ */
++static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ struct ap_message ap_msg;
++ struct completion work;
++ int rc;
++
++ ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &work;
++ rc = ICACRT_msg_to_type4CRT_msg(zdev, &ap_msg, crt);
++ if (rc)
++ goto out_free;
++ init_completion(&work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &work, PCICA_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response(zdev, &ap_msg, crt->outputdata,
++ crt->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ kfree(ap_msg.message);
++ return rc;
++}
++
++/**
++ * The crypto operations for a PCICA card.
++ */
++static struct zcrypt_ops zcrypt_pcica_ops = {
++ .rsa_modexpo = zcrypt_pcica_modexpo,
++ .rsa_modexpo_crt = zcrypt_pcica_modexpo_crt,
++};
++
++/**
++ * Probe function for PCICA cards. It always accepts the AP device
++ * since the bus_match already checked the hardware type.
++ * @ap_dev: pointer to the AP device.
++ */
++static int zcrypt_pcica_probe(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev;
++ int rc;
++
++ zdev = zcrypt_device_alloc(PCICA_MAX_RESPONSE_SIZE);
++ if (!zdev)
++ return -ENOMEM;
++ zdev->ap_dev = ap_dev;
++ zdev->ops = &zcrypt_pcica_ops;
++ zdev->online = 1;
++ zdev->user_space_type = ZCRYPT_PCICA;
++ zdev->type_string = "PCICA";
++ zdev->min_mod_size = PCICA_MIN_MOD_SIZE;
++ zdev->max_mod_size = PCICA_MAX_MOD_SIZE;
++ zdev->speed_rating = PCICA_SPEED_RATING;
++ ap_dev->reply = &zdev->reply;
++ ap_dev->private = zdev;
++ rc = zcrypt_device_register(zdev);
++ if (rc)
++ goto out_free;
++ return 0;
++
++out_free:
++ ap_dev->private = NULL;
++ zcrypt_device_free(zdev);
++ return rc;
++}
++
++/**
++ * This is called to remove the extended PCICA driver information
++ * if an AP device is removed.
++ */
++static void zcrypt_pcica_remove(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev = ap_dev->private;
++
++ zcrypt_device_unregister(zdev);
++}
++
++int __init zcrypt_pcica_init(void)
++{
++ return ap_driver_register(&zcrypt_pcica_driver, THIS_MODULE, "pcica");
++}
++
++void zcrypt_pcica_exit(void)
++{
++ ap_driver_unregister(&zcrypt_pcica_driver);
++}
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++module_init(zcrypt_pcica_init);
++module_exit(zcrypt_pcica_exit);
++#endif
+diff --git a/drivers/s390/crypto/zcrypt_pcica.h b/drivers/s390/crypto/zcrypt_pcica.h
+new file mode 100644
+index 0000000..3be1118
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_pcica.h
+@@ -0,0 +1,117 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_pcica.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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 _ZCRYPT_PCICA_H_
++#define _ZCRYPT_PCICA_H_
++
++/**
++ * The type 4 message family is associated with a PCICA card.
++ *
++ * The four members of the family are described below.
++ *
++ * Note that all unsigned char arrays are right-justified and left-padded
++ * with zeroes.
++ *
++ * Note that all reserved fields must be zeroes.
++ */
++struct type4_hdr {
++ unsigned char reserved1;
++ unsigned char msg_type_code; /* 0x04 */
++ unsigned short msg_len;
++ unsigned char request_code; /* 0x40 */
++ unsigned char msg_fmt;
++ unsigned short reserved2;
++} __attribute__((packed));
++
++#define TYPE4_TYPE_CODE 0x04
++#define TYPE4_REQU_CODE 0x40
++
++#define TYPE4_SME_FMT 0x00
++#define TYPE4_LME_FMT 0x10
++#define TYPE4_SCR_FMT 0x40
++#define TYPE4_LCR_FMT 0x50
++
++/* Mod-Exp, with a small modulus */
++struct type4_sme {
++ struct type4_hdr header;
++ unsigned char message[128];
++ unsigned char exponent[128];
++ unsigned char modulus[128];
++} __attribute__((packed));
++
++/* Mod-Exp, with a large modulus */
++struct type4_lme {
++ struct type4_hdr header;
++ unsigned char message[256];
++ unsigned char exponent[256];
++ unsigned char modulus[256];
++} __attribute__((packed));
++
++/* CRT, with a small modulus */
++struct type4_scr {
++ struct type4_hdr header;
++ unsigned char message[128];
++ unsigned char dp[72];
++ unsigned char dq[64];
++ unsigned char p[72];
++ unsigned char q[64];
++ unsigned char u[72];
++} __attribute__((packed));
++
++/* CRT, with a large modulus */
++struct type4_lcr {
++ struct type4_hdr header;
++ unsigned char message[256];
++ unsigned char dp[136];
++ unsigned char dq[128];
++ unsigned char p[136];
++ unsigned char q[128];
++ unsigned char u[136];
++} __attribute__((packed));
++
++/**
++ * The type 84 response family is associated with a PCICA card.
++ *
++ * Note that all unsigned char arrays are right-justified and left-padded
++ * with zeroes.
++ *
++ * Note that all reserved fields must be zeroes.
++ */
++
++struct type84_hdr {
++ unsigned char reserved1;
++ unsigned char code;
++ unsigned short len;
++ unsigned char reserved2[4];
++} __attribute__((packed));
++
++#define TYPE84_RSP_CODE 0x84
++
++int zcrypt_pcica_init(void);
++void zcrypt_pcica_exit(void);
++
++#endif /* _ZCRYPT_PCICA_H_ */
+diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
+new file mode 100644
+index 0000000..f295a40
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_pcicc.c
+@@ -0,0 +1,630 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_pcicc.c
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.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, 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/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#include "ap_bus.h"
++#include "zcrypt_api.h"
++#include "zcrypt_error.h"
++#include "zcrypt_pcicc.h"
++#include "zcrypt_cca_key.h"
++
++#define PCICC_MIN_MOD_SIZE 64 /* 512 bits */
++#define PCICC_MAX_MOD_SIZE_OLD 128 /* 1024 bits */
++#define PCICC_MAX_MOD_SIZE 256 /* 2048 bits */
++
++/**
++ * PCICC cards need a speed rating of 0. This keeps them at the end of
++ * the zcrypt device list (see zcrypt_api.c). PCICC cards are only
++ * used if no other cards are present because they are slow and can only
++ * cope with PKCS12 padded requests. The logic is queer. PKCS11 padded
++ * requests are rejected. The modexpo function encrypts PKCS12 padded data
++ * and decrypts any non-PKCS12 padded data (except PKCS11) in the assumption
++ * that it's encrypted PKCS12 data. The modexpo_crt function always decrypts
++ * the data in the assumption that its PKCS12 encrypted data.
++ */
++#define PCICC_SPEED_RATING 0
++
++#define PCICC_MAX_MESSAGE_SIZE 0x710 /* max size type6 v1 crt message */
++#define PCICC_MAX_RESPONSE_SIZE 0x710 /* max size type86 v1 reply */
++
++#define PCICC_CLEANUP_TIME (15*HZ)
++
++static struct ap_device_id zcrypt_pcicc_ids[] = {
++ { AP_DEVICE(AP_DEVICE_TYPE_PCICC) },
++ { /* end of list */ },
++};
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++MODULE_DEVICE_TABLE(ap, zcrypt_pcicc_ids);
++MODULE_AUTHOR("IBM Corporation");
++MODULE_DESCRIPTION("PCICC Cryptographic Coprocessor device driver, "
++ "Copyright 2001, 2006 IBM Corporation");
++MODULE_LICENSE("GPL");
++#endif
++
++static int zcrypt_pcicc_probe(struct ap_device *ap_dev);
++static void zcrypt_pcicc_remove(struct ap_device *ap_dev);
++static void zcrypt_pcicc_receive(struct ap_device *, struct ap_message *,
++ struct ap_message *);
++
++static struct ap_driver zcrypt_pcicc_driver = {
++ .probe = zcrypt_pcicc_probe,
++ .remove = zcrypt_pcicc_remove,
++ .receive = zcrypt_pcicc_receive,
++ .ids = zcrypt_pcicc_ids,
++};
++
++/**
++ * The following is used to initialize the CPRB passed to the PCICC card
++ * in a type6 message. The 3 fields that must be filled in at execution
++ * time are req_parml, rpl_parml and usage_domain. Note that all three
++ * fields are *little*-endian. Actually, everything about this interface
++ * is ascii/little-endian, since the device has 'Intel inside'.
++ *
++ * The CPRB is followed immediately by the parm block.
++ * The parm block contains:
++ * - function code ('PD' 0x5044 or 'PK' 0x504B)
++ * - rule block (0x0A00 'PKCS-1.2' or 0x0A00 'ZERO-PAD')
++ * - VUD block
++ */
++static struct CPRB static_cprb = {
++ .cprb_len = __constant_cpu_to_le16(0x0070),
++ .cprb_ver_id = 0x41,
++ .func_id = {0x54,0x32},
++ .checkpoint_flag= 0x01,
++ .svr_namel = __constant_cpu_to_le16(0x0008),
++ .svr_name = {'I','C','S','F',' ',' ',' ',' '}
++};
++
++/**
++ * Check the message for PKCS11 padding.
++ */
++static inline int is_PKCS11_padded(unsigned char *buffer, int length)
++{
++ int i;
++ if ((buffer[0] != 0x00) || (buffer[1] != 0x01))
++ return 0;
++ for (i = 2; i < length; i++)
++ if (buffer[i] != 0xFF)
++ break;
++ if (i < 10 || i == length)
++ return 0;
++ if (buffer[i] != 0x00)
++ return 0;
++ return 1;
++}
++
++/**
++ * Check the message for PKCS12 padding.
++ */
++static inline int is_PKCS12_padded(unsigned char *buffer, int length)
++{
++ int i;
++ if ((buffer[0] != 0x00) || (buffer[1] != 0x02))
++ return 0;
++ for (i = 2; i < length; i++)
++ if (buffer[i] == 0x00)
++ break;
++ if ((i < 10) || (i == length))
++ return 0;
++ if (buffer[i] != 0x00)
++ return 0;
++ return 1;
++}
++
++/**
++ * Convert a ICAMEX message to a type6 MEX message.
++ *
++ * @zdev: crypto device pointer
++ * @zreq: crypto request pointer
++ * @mex: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICAMEX_msg_to_type6MEX_msg(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo *mex)
++{
++ static struct type6_hdr static_type6_hdr = {
++ .type = 0x06,
++ .offset1 = 0x00000058,
++ .agent_id = {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
++ 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
++ .function_code = {'P','K'},
++ };
++ static struct function_and_rules_block static_pke_function_and_rules ={
++ .function_code = {'P','K'},
++ .ulen = __constant_cpu_to_le16(10),
++ .only_rule = {'P','K','C','S','-','1','.','2'}
++ };
++ struct {
++ struct type6_hdr hdr;
++ struct CPRB cprb;
++ struct function_and_rules_block fr;
++ unsigned short length;
++ char text[0];
++ } __attribute__((packed)) *msg = ap_msg->message;
++ int vud_len, pad_len, size;
++
++ /* VUD.ciphertext */
++ if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
++ return -EFAULT;
++
++ if (is_PKCS11_padded(msg->text, mex->inputdatalength))
++ return -EINVAL;
++
++ /* static message header and f&r */
++ msg->hdr = static_type6_hdr;
++ msg->fr = static_pke_function_and_rules;
++
++ if (is_PKCS12_padded(msg->text, mex->inputdatalength)) {
++ /* strip the padding and adjust the data length */
++ pad_len = strnlen(msg->text + 2, mex->inputdatalength - 2) + 3;
++ if (pad_len <= 9 || pad_len >= mex->inputdatalength)
++ return -ENODEV;
++ vud_len = mex->inputdatalength - pad_len;
++ memmove(msg->text, msg->text + pad_len, vud_len);
++ msg->length = cpu_to_le16(vud_len + 2);
++
++ /* Set up key after the variable length text. */
++ size = zcrypt_type6_mex_key_en(mex, msg->text + vud_len, 0);
++ if (size < 0)
++ return size;
++ size += sizeof(*msg) + vud_len; /* total size of msg */
++ } else {
++ vud_len = mex->inputdatalength;
++ msg->length = cpu_to_le16(2 + vud_len);
++
++ msg->hdr.function_code[1] = 'D';
++ msg->fr.function_code[1] = 'D';
++
++ /* Set up key after the variable length text. */
++ size = zcrypt_type6_mex_key_de(mex, msg->text + vud_len, 0);
++ if (size < 0)
++ return size;
++ size += sizeof(*msg) + vud_len; /* total size of msg */
++ }
++
++ /* message header, cprb and f&r */
++ msg->hdr.ToCardLen1 = (size - sizeof(msg->hdr) + 3) & -4;
++ msg->hdr.FromCardLen1 = PCICC_MAX_RESPONSE_SIZE - sizeof(msg->hdr);
++
++ msg->cprb = static_cprb;
++ msg->cprb.usage_domain[0]= AP_QID_QUEUE(zdev->ap_dev->qid);
++ msg->cprb.req_parml = cpu_to_le16(size - sizeof(msg->hdr) -
++ sizeof(msg->cprb));
++ msg->cprb.rpl_parml = cpu_to_le16(msg->hdr.FromCardLen1);
++
++ ap_msg->length = (size + 3) & -4;
++ return 0;
++}
++
++/**
++ * Convert a ICACRT message to a type6 CRT message.
++ *
++ * @zdev: crypto device pointer
++ * @zreq: crypto request pointer
++ * @crt: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICACRT_msg_to_type6CRT_msg(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ static struct type6_hdr static_type6_hdr = {
++ .type = 0x06,
++ .offset1 = 0x00000058,
++ .agent_id = {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
++ 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
++ .function_code = {'P','D'},
++ };
++ static struct function_and_rules_block static_pkd_function_and_rules ={
++ .function_code = {'P','D'},
++ .ulen = __constant_cpu_to_le16(10),
++ .only_rule = {'P','K','C','S','-','1','.','2'}
++ };
++ struct {
++ struct type6_hdr hdr;
++ struct CPRB cprb;
++ struct function_and_rules_block fr;
++ unsigned short length;
++ char text[0];
++ } __attribute__((packed)) *msg = ap_msg->message;
++ int size;
++
++ /* VUD.ciphertext */
++ msg->length = cpu_to_le16(2 + crt->inputdatalength);
++ if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
++ return -EFAULT;
++
++ if (is_PKCS11_padded(msg->text, crt->inputdatalength))
++ return -EINVAL;
++
++ /* Set up key after the variable length text. */
++ size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 0);
++ if (size < 0)
++ return size;
++ size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
++
++ /* message header, cprb and f&r */
++ msg->hdr = static_type6_hdr;
++ msg->hdr.ToCardLen1 = (size - sizeof(msg->hdr) + 3) & -4;
++ msg->hdr.FromCardLen1 = PCICC_MAX_RESPONSE_SIZE - sizeof(msg->hdr);
++
++ msg->cprb = static_cprb;
++ msg->cprb.usage_domain[0] = AP_QID_QUEUE(zdev->ap_dev->qid);
++ msg->cprb.req_parml = msg->cprb.rpl_parml =
++ cpu_to_le16(size - sizeof(msg->hdr) - sizeof(msg->cprb));
++
++ msg->fr = static_pkd_function_and_rules;
++
++ ap_msg->length = (size + 3) & -4;
++ return 0;
++}
++
++/**
++ * Copy results from a type 86 reply message back to user space.
++ *
++ * @zdev: crypto device pointer
++ * @reply: reply AP message.
++ * @data: pointer to user output data
++ * @length: size of user output data
++ *
++ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
++ */
++struct type86_reply {
++ struct type86_hdr hdr;
++ struct type86_fmt2_ext fmt2;
++ struct CPRB cprb;
++ unsigned char pad[4]; /* 4 byte function code/rules block ? */
++ unsigned short length;
++ char text[0];
++} __attribute__((packed));
++
++static int convert_type86(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ static unsigned char static_pad[] = {
++ 0x00,0x02,
++ 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
++ 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
++ 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
++ 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
++ 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
++ 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
++ 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
++ 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
++ 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
++ 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
++ 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
++ 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
++ 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
++ 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
++ 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
++ 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
++ 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
++ 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
++ 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
++ 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
++ 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
++ 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
++ 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
++ 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
++ 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
++ 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
++ 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
++ 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
++ 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
++ 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
++ 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
++ 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
++ };
++ struct type86_reply *msg = reply->message;
++ unsigned short service_rc, service_rs;
++ unsigned int reply_len, pad_len;
++ char *data;
++
++ service_rc = le16_to_cpu(msg->cprb.ccp_rtcode);
++ if (unlikely(service_rc != 0)) {
++ service_rs = le16_to_cpu(msg->cprb.ccp_rscode);
++ if (service_rc == 8 && service_rs == 66) {
++ PDEBUG("Bad block format on PCICC\n");
++ return -EINVAL;
++ }
++ if (service_rc == 8 && service_rs == 65) {
++ PDEBUG("Probably an even modulus on PCICC\n");
++ return -EINVAL;
++ }
++ if (service_rc == 8 && service_rs == 770) {
++ PDEBUG("Invalid key length on PCICC\n");
++ zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
++ return -EAGAIN;
++ }
++ if (service_rc == 8 && service_rs == 783) {
++ PDEBUG("Extended bitlengths not enabled on PCICC\n");
++ zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
++ return -EAGAIN;
++ }
++ PRINTK("Unknown service rc/rs (PCICC): %d/%d\n",
++ service_rc, service_rs);
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++ data = msg->text;
++ reply_len = le16_to_cpu(msg->length) - 2;
++ if (reply_len > outputdatalength)
++ return -EINVAL;
++ /**
++ * For all encipher requests, the length of the ciphertext (reply_len)
++ * will always equal the modulus length. For MEX decipher requests
++ * the output needs to get padded. Minimum pad size is 10.
++ *
++ * Currently, the cases where padding will be added is for:
++ * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
++ * ZERO-PAD and CRT is only supported for PKD requests)
++ * - PCICC, always
++ */
++ pad_len = outputdatalength - reply_len;
++ if (pad_len > 0) {
++ if (pad_len < 10)
++ return -EINVAL;
++ /* 'restore' padding left in the PCICC/PCIXCC card. */
++ if (copy_to_user(outputdata, static_pad, pad_len - 1))
++ return -EFAULT;
++ if (put_user(0, outputdata + pad_len - 1))
++ return -EFAULT;
++ }
++ /* Copy the crypto response to user space. */
++ if (copy_to_user(outputdata + pad_len, data, reply_len))
++ return -EFAULT;
++ return 0;
++}
++
++static int convert_response(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ struct type86_reply *msg = reply->message;
++
++ /* Response type byte is the second byte in the response. */
++ switch (msg->hdr.type) {
++ case TYPE82_RSP_CODE:
++ case TYPE88_RSP_CODE:
++ return convert_error(zdev, reply);
++ case TYPE86_RSP_CODE:
++ if (msg->hdr.reply_code)
++ return convert_error(zdev, reply);
++ if (msg->cprb.cprb_ver_id == 0x01)
++ return convert_type86(zdev, reply,
++ outputdata, outputdatalength);
++ /* no break, incorrect cprb version is an unknown response */
++ default: /* Unknown response type, this should NEVER EVER happen */
++ PRINTK("Unrecognized Message Header: %08x%08x\n",
++ *(unsigned int *) reply->message,
++ *(unsigned int *) (reply->message+4));
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++}
++
++/**
++ * This function is called from the AP bus code after a crypto request
++ * "msg" has finished with the reply message "reply".
++ * It is called from tasklet context.
++ * @ap_dev: pointer to the AP device
++ * @msg: pointer to the AP message
++ * @reply: pointer to the AP reply message
++ */
++static void zcrypt_pcicc_receive(struct ap_device *ap_dev,
++ struct ap_message *msg,
++ struct ap_message *reply)
++{
++ static struct error_hdr error_reply = {
++ .type = TYPE82_RSP_CODE,
++ .reply_code = REP82_ERROR_MACHINE_FAILURE,
++ };
++ struct type86_reply *t86r = reply->message;
++ int length;
++
++ /* Copy the reply message to the request message buffer. */
++ if (IS_ERR(reply))
++ memcpy(msg->message, &error_reply, sizeof(error_reply));
++ else if (t86r->hdr.type == TYPE86_RSP_CODE &&
++ t86r->cprb.cprb_ver_id == 0x01) {
++ length = sizeof(struct type86_reply) + t86r->length - 2;
++ length = min(PCICC_MAX_RESPONSE_SIZE, length);
++ memcpy(msg->message, reply->message, length);
++ } else
++ memcpy(msg->message, reply->message, sizeof error_reply);
++ complete((struct completion *) msg->private);
++}
++
++static atomic_t zcrypt_step = ATOMIC_INIT(0);
++
++/**
++ * The request distributor calls this function if it picked the PCICC
++ * device to handle a modexpo request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCICC device to the request distributor
++ * @mex: pointer to the modexpo request buffer
++ */
++static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo *mex)
++{
++ struct ap_message ap_msg;
++ struct completion work;
++ int rc;
++
++ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.length = PAGE_SIZE;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &work;
++ rc = ICAMEX_msg_to_type6MEX_msg(zdev, &ap_msg, mex);
++ if (rc)
++ goto out_free;
++ init_completion(&work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &work, PCICC_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response(zdev, &ap_msg, mex->outputdata,
++ mex->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ free_page((unsigned long) ap_msg.message);
++ return rc;
++}
++
++/**
++ * The request distributor calls this function if it picked the PCICC
++ * device to handle a modexpo_crt request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCICC device to the request distributor
++ * @crt: pointer to the modexpoc_crt request buffer
++ */
++static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ struct ap_message ap_msg;
++ struct completion work;
++ int rc;
++
++ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.length = PAGE_SIZE;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &work;
++ rc = ICACRT_msg_to_type6CRT_msg(zdev, &ap_msg, crt);
++ if (rc)
++ goto out_free;
++ init_completion(&work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &work, PCICC_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response(zdev, &ap_msg, crt->outputdata,
++ crt->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ free_page((unsigned long) ap_msg.message);
++ return rc;
++}
++
++/**
++ * The crypto operations for a PCICC card.
++ */
++static struct zcrypt_ops zcrypt_pcicc_ops = {
++ .rsa_modexpo = zcrypt_pcicc_modexpo,
++ .rsa_modexpo_crt = zcrypt_pcicc_modexpo_crt,
++};
++
++/**
++ * Probe function for PCICC cards. It always accepts the AP device
++ * since the bus_match already checked the hardware type.
++ * @ap_dev: pointer to the AP device.
++ */
++static int zcrypt_pcicc_probe(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev;
++ int rc;
++
++ zdev = zcrypt_device_alloc(PCICC_MAX_RESPONSE_SIZE);
++ if (!zdev)
++ return -ENOMEM;
++ zdev->ap_dev = ap_dev;
++ zdev->ops = &zcrypt_pcicc_ops;
++ zdev->online = 1;
++ zdev->user_space_type = ZCRYPT_PCICC;
++ zdev->type_string = "PCICC";
++ zdev->min_mod_size = PCICC_MIN_MOD_SIZE;
++ zdev->max_mod_size = PCICC_MAX_MOD_SIZE;
++ zdev->speed_rating = PCICC_SPEED_RATING;
++ ap_dev->reply = &zdev->reply;
++ ap_dev->private = zdev;
++ rc = zcrypt_device_register(zdev);
++ if (rc)
++ goto out_free;
++ return 0;
++
++ out_free:
++ ap_dev->private = NULL;
++ zcrypt_device_free(zdev);
++ return rc;
++}
++
++/**
++ * This is called to remove the extended PCICC driver information
++ * if an AP device is removed.
++ */
++static void zcrypt_pcicc_remove(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev = ap_dev->private;
++
++ zcrypt_device_unregister(zdev);
++}
++
++int __init zcrypt_pcicc_init(void)
++{
++ return ap_driver_register(&zcrypt_pcicc_driver, THIS_MODULE, "pcicc");
++}
++
++void zcrypt_pcicc_exit(void)
++{
++ ap_driver_unregister(&zcrypt_pcicc_driver);
++}
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++module_init(zcrypt_pcicc_init);
++module_exit(zcrypt_pcicc_exit);
++#endif
+diff --git a/drivers/s390/crypto/zcrypt_pcicc.h b/drivers/s390/crypto/zcrypt_pcicc.h
+new file mode 100644
+index 0000000..6d44548
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_pcicc.h
+@@ -0,0 +1,176 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_pcicc.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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 _ZCRYPT_PCICC_H_
++#define _ZCRYPT_PCICC_H_
++
++/**
++ * The type 6 message family is associated with PCICC or PCIXCC cards.
++ *
++ * It contains a message header followed by a CPRB, both of which
++ * are described below.
++ *
++ * Note that all reserved fields must be zeroes.
++ */
++struct type6_hdr {
++ unsigned char reserved1; /* 0x00 */
++ unsigned char type; /* 0x06 */
++ unsigned char reserved2[2]; /* 0x0000 */
++ unsigned char right[4]; /* 0x00000000 */
++ unsigned char reserved3[2]; /* 0x0000 */
++ unsigned char reserved4[2]; /* 0x0000 */
++ unsigned char apfs[4]; /* 0x00000000 */
++ unsigned int offset1; /* 0x00000058 (offset to CPRB) */
++ unsigned int offset2; /* 0x00000000 */
++ unsigned int offset3; /* 0x00000000 */
++ unsigned int offset4; /* 0x00000000 */
++ unsigned char agent_id[16]; /* PCICC: */
++ /* 0x0100 */
++ /* 0x4343412d4150504c202020 */
++ /* 0x010101 */
++ /* PCIXCC: */
++ /* 0x4341000000000000 */
++ /* 0x0000000000000000 */
++ unsigned char rqid[2]; /* rqid. internal to 603 */
++ unsigned char reserved5[2]; /* 0x0000 */
++ unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */
++ unsigned char reserved6[2]; /* 0x0000 */
++ unsigned int ToCardLen1; /* (request CPRB len + 3) & -4 */
++ unsigned int ToCardLen2; /* db len 0x00000000 for PKD */
++ unsigned int ToCardLen3; /* 0x00000000 */
++ unsigned int ToCardLen4; /* 0x00000000 */
++ unsigned int FromCardLen1; /* response buffer length */
++ unsigned int FromCardLen2; /* db len 0x00000000 for PKD */
++ unsigned int FromCardLen3; /* 0x00000000 */
++ unsigned int FromCardLen4; /* 0x00000000 */
++} __attribute__((packed));
++
++/**
++ * CPRB
++ * Note that all shorts, ints and longs are little-endian.
++ * All pointer fields are 32-bits long, and mean nothing
++ *
++ * A request CPRB is followed by a request_parameter_block.
++ *
++ * The request (or reply) parameter block is organized thus:
++ * function code
++ * VUD block
++ * key block
++ */
++struct CPRB {
++ unsigned short cprb_len; /* CPRB length */
++ unsigned char cprb_ver_id; /* CPRB version id. */
++ unsigned char pad_000; /* Alignment pad byte. */
++ unsigned char srpi_rtcode[4]; /* SRPI return code LELONG */
++ unsigned char srpi_verb; /* SRPI verb type */
++ unsigned char flags; /* flags */
++ unsigned char func_id[2]; /* function id */
++ unsigned char checkpoint_flag; /* */
++ unsigned char resv2; /* reserved */
++ unsigned short req_parml; /* request parameter buffer */
++ /* length 16-bit little endian */
++ unsigned char req_parmp[4]; /* request parameter buffer *
++ * pointer (means nothing: the *
++ * parameter buffer follows *
++ * the CPRB). */
++ unsigned char req_datal[4]; /* request data buffer */
++ /* length ULELONG */
++ unsigned char req_datap[4]; /* request data buffer */
++ /* pointer */
++ unsigned short rpl_parml; /* reply parameter buffer */
++ /* length 16-bit little endian */
++ unsigned char pad_001[2]; /* Alignment pad bytes. ULESHORT */
++ unsigned char rpl_parmp[4]; /* reply parameter buffer *
++ * pointer (means nothing: the *
++ * parameter buffer follows *
++ * the CPRB). */
++ unsigned char rpl_datal[4]; /* reply data buffer len ULELONG */
++ unsigned char rpl_datap[4]; /* reply data buffer */
++ /* pointer */
++ unsigned short ccp_rscode; /* server reason code ULESHORT */
++ unsigned short ccp_rtcode; /* server return code ULESHORT */
++ unsigned char repd_parml[2]; /* replied parameter len ULESHORT*/
++ unsigned char mac_data_len[2]; /* Mac Data Length ULESHORT */
++ unsigned char repd_datal[4]; /* replied data length ULELONG */
++ unsigned char req_pc[2]; /* PC identifier */
++ unsigned char res_origin[8]; /* resource origin */
++ unsigned char mac_value[8]; /* Mac Value */
++ unsigned char logon_id[8]; /* Logon Identifier */
++ unsigned char usage_domain[2]; /* cdx */
++ unsigned char resv3[18]; /* reserved for requestor */
++ unsigned short svr_namel; /* server name length ULESHORT */
++ unsigned char svr_name[8]; /* server name */
++} __attribute__((packed));
++
++/**
++ * The type 86 message family is associated with PCICC and PCIXCC cards.
++ *
++ * It contains a message header followed by a CPRB. The CPRB is
++ * the same as the request CPRB, which is described above.
++ *
++ * If format is 1, an error condition exists and no data beyond
++ * the 8-byte message header is of interest.
++ *
++ * The non-error message is shown below.
++ *
++ * Note that all reserved fields must be zeroes.
++ */
++struct type86_hdr {
++ unsigned char reserved1; /* 0x00 */
++ unsigned char type; /* 0x86 */
++ unsigned char format; /* 0x01 (error) or 0x02 (ok) */
++ unsigned char reserved2; /* 0x00 */
++ unsigned char reply_code; /* reply code (see above) */
++ unsigned char reserved3[3]; /* 0x000000 */
++} __attribute__((packed));
++
++#define TYPE86_RSP_CODE 0x86
++#define TYPE86_FMT2 0x02
++
++struct type86_fmt2_ext {
++ unsigned char reserved[4]; /* 0x00000000 */
++ unsigned char apfs[4]; /* final status */
++ unsigned int count1; /* length of CPRB + parameters */
++ unsigned int offset1; /* offset to CPRB */
++ unsigned int count2; /* 0x00000000 */
++ unsigned int offset2; /* db offset 0x00000000 for PKD */
++ unsigned int count3; /* 0x00000000 */
++ unsigned int offset3; /* 0x00000000 */
++ unsigned int count4; /* 0x00000000 */
++ unsigned int offset4; /* 0x00000000 */
++} __attribute__((packed));
++
++struct function_and_rules_block {
++ unsigned char function_code[2];
++ unsigned short ulen;
++ unsigned char only_rule[8];
++} __attribute__((packed));
++
++int zcrypt_pcicc_init(void);
++void zcrypt_pcicc_exit(void);
++
++#endif /* _ZCRYPT_PCICC_H_ */
+diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
+new file mode 100644
+index 0000000..2da8b93
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_pcixcc.c
+@@ -0,0 +1,951 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_pcixcc.c
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.ibm.com>
++ * Ralph Wuerthner <rwuerthn at de.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, 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/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#include "ap_bus.h"
++#include "zcrypt_api.h"
++#include "zcrypt_error.h"
++#include "zcrypt_pcicc.h"
++#include "zcrypt_pcixcc.h"
++#include "zcrypt_cca_key.h"
++
++#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
++#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
++#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
++
++#define PCIXCC_MCL2_SPEED_RATING 7870 /* FIXME: needs finetuning */
++#define PCIXCC_MCL3_SPEED_RATING 7870
++#define CEX2C_SPEED_RATING 8540
++
++#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
++#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
++
++#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
++#define PCIXCC_MAX_XCRB_RESPONSE_SIZE PCIXCC_MAX_XCRB_MESSAGE_SIZE
++#define PCIXCC_MAX_XCRB_DATA_SIZE (11*1024)
++#define PCIXCC_MAX_XCRB_REPLY_SIZE (5*1024)
++
++#define PCIXCC_MAX_RESPONSE_SIZE PCIXCC_MAX_XCRB_RESPONSE_SIZE
++
++#define PCIXCC_CLEANUP_TIME (15*HZ)
++
++#define CEIL4(x) ((((x)+3)/4)*4)
++
++struct response_type {
++ struct completion work;
++ int type;
++};
++#define PCIXCC_RESPONSE_TYPE_ICA 0
++#define PCIXCC_RESPONSE_TYPE_XCRB 1
++
++static struct ap_device_id zcrypt_pcixcc_ids[] = {
++ { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
++ { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
++ { /* end of list */ },
++};
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
++MODULE_AUTHOR("IBM Corporation");
++MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
++ "Copyright 2001, 2006 IBM Corporation");
++MODULE_LICENSE("GPL");
++#endif
++
++static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
++static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
++static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
++ struct ap_message *);
++
++static struct ap_driver zcrypt_pcixcc_driver = {
++ .probe = zcrypt_pcixcc_probe,
++ .remove = zcrypt_pcixcc_remove,
++ .receive = zcrypt_pcixcc_receive,
++ .ids = zcrypt_pcixcc_ids,
++};
++
++/**
++ * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
++ * card in a type6 message. The 3 fields that must be filled in at execution
++ * time are req_parml, rpl_parml and usage_domain.
++ * Everything about this interface is ascii/big-endian, since the
++ * device does *not* have 'Intel inside'.
++ *
++ * The CPRBX is followed immediately by the parm block.
++ * The parm block contains:
++ * - function code ('PD' 0x5044 or 'PK' 0x504B)
++ * - rule block (one of:)
++ * + 0x000A 'PKCS-1.2' (MCL2 'PD')
++ * + 0x000A 'ZERO-PAD' (MCL2 'PK')
++ * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
++ * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
++ * - VUD block
++ */
++static struct CPRBX static_cprbx = {
++ .cprb_len = 0x00DC,
++ .cprb_ver_id = 0x02,
++ .func_id = {0x54,0x32},
++};
++
++/**
++ * Convert a ICAMEX message to a type6 MEX message.
++ *
++ * @zdev: crypto device pointer
++ * @ap_msg: pointer to AP message
++ * @mex: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo *mex)
++{
++ static struct type6_hdr static_type6_hdrX = {
++ .type = 0x06,
++ .offset1 = 0x00000058,
++ .agent_id = {'C','A',},
++ .function_code = {'P','K'},
++ };
++ static struct function_and_rules_block static_pke_fnr = {
++ .function_code = {'P','K'},
++ .ulen = 10,
++ .only_rule = {'M','R','P',' ',' ',' ',' ',' '}
++ };
++ static struct function_and_rules_block static_pke_fnr_MCL2 = {
++ .function_code = {'P','K'},
++ .ulen = 10,
++ .only_rule = {'Z','E','R','O','-','P','A','D'}
++ };
++ struct {
++ struct type6_hdr hdr;
++ struct CPRBX cprbx;
++ struct function_and_rules_block fr;
++ unsigned short length;
++ char text[0];
++ } __attribute__((packed)) *msg = ap_msg->message;
++ int size;
++
++ /* VUD.ciphertext */
++ msg->length = mex->inputdatalength + 2;
++ if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
++ return -EFAULT;
++
++ /* Set up key which is located after the variable length text. */
++ size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
++ if (size < 0)
++ return size;
++ size += sizeof(*msg) + mex->inputdatalength;
++
++ /* message header, cprbx and f&r */
++ msg->hdr = static_type6_hdrX;
++ msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
++ msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
++
++ msg->cprbx = static_cprbx;
++ msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
++ msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
++
++ msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
++ static_pke_fnr_MCL2 : static_pke_fnr;
++
++ msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
++
++ ap_msg->length = size;
++ return 0;
++}
++
++/**
++ * Convert a ICACRT message to a type6 CRT message.
++ *
++ * @zdev: crypto device pointer
++ * @ap_msg: pointer to AP message
++ * @crt: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ static struct type6_hdr static_type6_hdrX = {
++ .type = 0x06,
++ .offset1 = 0x00000058,
++ .agent_id = {'C','A',},
++ .function_code = {'P','D'},
++ };
++ static struct function_and_rules_block static_pkd_fnr = {
++ .function_code = {'P','D'},
++ .ulen = 10,
++ .only_rule = {'Z','E','R','O','-','P','A','D'}
++ };
++
++ static struct function_and_rules_block static_pkd_fnr_MCL2 = {
++ .function_code = {'P','D'},
++ .ulen = 10,
++ .only_rule = {'P','K','C','S','-','1','.','2'}
++ };
++ struct {
++ struct type6_hdr hdr;
++ struct CPRBX cprbx;
++ struct function_and_rules_block fr;
++ unsigned short length;
++ char text[0];
++ } __attribute__((packed)) *msg = ap_msg->message;
++ int size;
++
++ /* VUD.ciphertext */
++ msg->length = crt->inputdatalength + 2;
++ if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
++ return -EFAULT;
++
++ /* Set up key which is located after the variable length text. */
++ size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
++ if (size < 0)
++ return size;
++ size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
++
++ /* message header, cprbx and f&r */
++ msg->hdr = static_type6_hdrX;
++ msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
++ msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
++
++ msg->cprbx = static_cprbx;
++ msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
++ msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
++ size - sizeof(msg->hdr) - sizeof(msg->cprbx);
++
++ msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
++ static_pkd_fnr_MCL2 : static_pkd_fnr;
++
++ ap_msg->length = size;
++ return 0;
++}
++
++/**
++ * Convert a XCRB message to a type6 CPRB message.
++ *
++ * @zdev: crypto device pointer
++ * @ap_msg: pointer to AP message
++ * @xcRB: pointer to user input data
++ *
++ * Returns 0 on success or -EFAULT.
++ */
++struct type86_fmt2_msg {
++ struct type86_hdr hdr;
++ struct type86_fmt2_ext fmt2;
++} __attribute__((packed));
++
++static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
++ struct ap_message *ap_msg,
++ struct ica_xcRB *xcRB)
++{
++ static struct type6_hdr static_type6_hdrX = {
++ .type = 0x06,
++ .offset1 = 0x00000058,
++ };
++ struct {
++ struct type6_hdr hdr;
++ struct ica_CPRBX cprbx;
++ } __attribute__((packed)) *msg = ap_msg->message;
++
++ int rcblen = CEIL4(xcRB->request_control_blk_length);
++ int replylen;
++ char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
++ char *function_code;
++
++ /* length checks */
++ ap_msg->length = sizeof(struct type6_hdr) +
++ CEIL4(xcRB->request_control_blk_length) +
++ xcRB->request_data_length;
++ if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) {
++ PRINTK("Combined message is too large (%ld/%d/%d).\n",
++ sizeof(struct type6_hdr),
++ xcRB->request_control_blk_length,
++ xcRB->request_data_length);
++ return -EFAULT;
++ }
++ if (CEIL4(xcRB->reply_control_blk_length) >
++ PCIXCC_MAX_XCRB_REPLY_SIZE) {
++ PDEBUG("Reply CPRB length is too large (%d).\n",
++ xcRB->request_control_blk_length);
++ return -EFAULT;
++ }
++ if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) {
++ PDEBUG("Reply data block length is too large (%d).\n",
++ xcRB->reply_data_length);
++ return -EFAULT;
++ }
++ replylen = CEIL4(xcRB->reply_control_blk_length) +
++ CEIL4(xcRB->reply_data_length) +
++ sizeof(struct type86_fmt2_msg);
++ if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
++ PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE"
++ " (%d/%d/%d).\n",
++ sizeof(struct type86_fmt2_msg),
++ xcRB->reply_control_blk_length,
++ xcRB->reply_data_length);
++ xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
++ (sizeof(struct type86_fmt2_msg) +
++ CEIL4(xcRB->reply_data_length));
++ PDEBUG("Capping Reply CPRB length at %d\n",
++ xcRB->reply_control_blk_length);
++ }
++
++ /* prepare type6 header */
++ msg->hdr = static_type6_hdrX;
++ memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
++ msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
++ if (xcRB->request_data_length) {
++ msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
++ msg->hdr.ToCardLen2 = xcRB->request_data_length;
++ }
++ msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
++ msg->hdr.FromCardLen2 = xcRB->reply_data_length;
++
++ /* prepare CPRB */
++ if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
++ xcRB->request_control_blk_length))
++ return -EFAULT;
++ if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
++ xcRB->request_control_blk_length) {
++ PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len,
++ xcRB->request_control_blk_length);
++ return -EFAULT;
++ }
++ function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
++ memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
++
++ /* copy data block */
++ if (xcRB->request_data_length &&
++ copy_from_user(req_data, xcRB->request_data_address,
++ xcRB->request_data_length))
++ return -EFAULT;
++ return 0;
++}
++
++/**
++ * Copy results from a type 86 ICA reply message back to user space.
++ *
++ * @zdev: crypto device pointer
++ * @reply: reply AP message.
++ * @data: pointer to user output data
++ * @length: size of user output data
++ *
++ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
++ */
++struct type86x_reply {
++ struct type86_hdr hdr;
++ struct type86_fmt2_ext fmt2;
++ struct CPRBX cprbx;
++ unsigned char pad[4]; /* 4 byte function code/rules block ? */
++ unsigned short length;
++ char text[0];
++} __attribute__((packed));
++
++static int convert_type86_ica(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ static unsigned char static_pad[] = {
++ 0x00,0x02,
++ 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
++ 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
++ 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
++ 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
++ 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
++ 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
++ 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
++ 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
++ 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
++ 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
++ 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
++ 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
++ 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
++ 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
++ 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
++ 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
++ 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
++ 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
++ 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
++ 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
++ 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
++ 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
++ 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
++ 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
++ 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
++ 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
++ 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
++ 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
++ 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
++ 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
++ 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
++ 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
++ };
++ struct type86x_reply *msg = reply->message;
++ unsigned short service_rc, service_rs;
++ unsigned int reply_len, pad_len;
++ char *data;
++
++ service_rc = msg->cprbx.ccp_rtcode;
++ if (unlikely(service_rc != 0)) {
++ service_rs = msg->cprbx.ccp_rscode;
++ if (service_rc == 8 && service_rs == 66) {
++ PDEBUG("Bad block format on PCIXCC/CEX2C\n");
++ return -EINVAL;
++ }
++ if (service_rc == 8 && service_rs == 65) {
++ PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n");
++ return -EINVAL;
++ }
++ if (service_rc == 8 && service_rs == 770) {
++ PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
++ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
++ return -EAGAIN;
++ }
++ if (service_rc == 8 && service_rs == 783) {
++ PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
++ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
++ return -EAGAIN;
++ }
++ PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
++ service_rc, service_rs);
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++ data = msg->text;
++ reply_len = msg->length - 2;
++ if (reply_len > outputdatalength)
++ return -EINVAL;
++ /**
++ * For all encipher requests, the length of the ciphertext (reply_len)
++ * will always equal the modulus length. For MEX decipher requests
++ * the output needs to get padded. Minimum pad size is 10.
++ *
++ * Currently, the cases where padding will be added is for:
++ * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
++ * ZERO-PAD and CRT is only supported for PKD requests)
++ * - PCICC, always
++ */
++ pad_len = outputdatalength - reply_len;
++ if (pad_len > 0) {
++ if (pad_len < 10)
++ return -EINVAL;
++ /* 'restore' padding left in the PCICC/PCIXCC card. */
++ if (copy_to_user(outputdata, static_pad, pad_len - 1))
++ return -EFAULT;
++ if (put_user(0, outputdata + pad_len - 1))
++ return -EFAULT;
++ }
++ /* Copy the crypto response to user space. */
++ if (copy_to_user(outputdata + pad_len, data, reply_len))
++ return -EFAULT;
++ return 0;
++}
++
++/**
++ * Copy results from a type 86 XCRB reply message back to user space.
++ *
++ * @zdev: crypto device pointer
++ * @reply: reply AP message.
++ * @xcRB: pointer to XCRB
++ *
++ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
++ */
++static int convert_type86_xcrb(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ struct ica_xcRB *xcRB)
++{
++ struct type86_fmt2_msg *msg = reply->message;
++ char *data = reply->message;
++
++ /* Copy CPRB to user */
++ if (copy_to_user(xcRB->reply_control_blk_addr,
++ data + msg->fmt2.offset1, msg->fmt2.count1))
++ return -EFAULT;
++ xcRB->reply_control_blk_length = msg->fmt2.count1;
++
++ /* Copy data buffer to user */
++ if (msg->fmt2.count2)
++ if (copy_to_user(xcRB->reply_data_addr,
++ data + msg->fmt2.offset2, msg->fmt2.count2))
++ return -EFAULT;
++ xcRB->reply_data_length = msg->fmt2.count2;
++ return 0;
++}
++
++static int convert_response_ica(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ char __user *outputdata,
++ unsigned int outputdatalength)
++{
++ struct type86x_reply *msg = reply->message;
++
++ /* Response type byte is the second byte in the response. */
++ switch (((unsigned char *) reply->message)[1]) {
++ case TYPE82_RSP_CODE:
++ case TYPE88_RSP_CODE:
++ return convert_error(zdev, reply);
++ case TYPE86_RSP_CODE:
++ if (msg->hdr.reply_code)
++ return convert_error(zdev, reply);
++ if (msg->cprbx.cprb_ver_id == 0x02)
++ return convert_type86_ica(zdev, reply,
++ outputdata, outputdatalength);
++ /* no break, incorrect cprb version is an unknown response */
++ default: /* Unknown response type, this should NEVER EVER happen */
++ PRINTK("Unrecognized Message Header: %08x%08x\n",
++ *(unsigned int *) reply->message,
++ *(unsigned int *) (reply->message+4));
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++}
++
++static int convert_response_xcrb(struct zcrypt_device *zdev,
++ struct ap_message *reply,
++ struct ica_xcRB *xcRB)
++{
++ struct type86x_reply *msg = reply->message;
++
++ /* Response type byte is the second byte in the response. */
++ switch (((unsigned char *) reply->message)[1]) {
++ case TYPE82_RSP_CODE:
++ case TYPE88_RSP_CODE:
++ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
++ return convert_error(zdev, reply);
++ case TYPE86_RSP_CODE:
++ if (msg->hdr.reply_code) {
++ memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
++ return convert_error(zdev, reply);
++ }
++ if (msg->cprbx.cprb_ver_id == 0x02)
++ return convert_type86_xcrb(zdev, reply, xcRB);
++ /* no break, incorrect cprb version is an unknown response */
++ default: /* Unknown response type, this should NEVER EVER happen */
++ PRINTK("Unrecognized Message Header: %08x%08x\n",
++ *(unsigned int *) reply->message,
++ *(unsigned int *) (reply->message+4));
++ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
++ zdev->online = 0;
++ return -EAGAIN; /* repeat the request on a different device. */
++ }
++}
++
++/**
++ * This function is called from the AP bus code after a crypto request
++ * "msg" has finished with the reply message "reply".
++ * It is called from tasklet context.
++ * @ap_dev: pointer to the AP device
++ * @msg: pointer to the AP message
++ * @reply: pointer to the AP reply message
++ */
++static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
++ struct ap_message *msg,
++ struct ap_message *reply)
++{
++ static struct error_hdr error_reply = {
++ .type = TYPE82_RSP_CODE,
++ .reply_code = REP82_ERROR_MACHINE_FAILURE,
++ };
++ struct response_type *resp_type =
++ (struct response_type *) msg->private;
++ struct type86x_reply *t86r = reply->message;
++ int length;
++
++ /* Copy the reply message to the request message buffer. */
++ if (IS_ERR(reply))
++ memcpy(msg->message, &error_reply, sizeof(error_reply));
++ else if (t86r->hdr.type == TYPE86_RSP_CODE &&
++ t86r->cprbx.cprb_ver_id == 0x02) {
++ switch (resp_type->type) {
++ case PCIXCC_RESPONSE_TYPE_ICA:
++ length = sizeof(struct type86x_reply)
++ + t86r->length - 2;
++ length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
++ memcpy(msg->message, reply->message, length);
++ break;
++ case PCIXCC_RESPONSE_TYPE_XCRB:
++ length = t86r->fmt2.offset2 + t86r->fmt2.count2;
++ length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length);
++ memcpy(msg->message, reply->message, length);
++ break;
++ default:
++ PRINTK("Invalid internal response type: %i\n",
++ resp_type->type);
++ memcpy(msg->message, &error_reply,
++ sizeof error_reply);
++ }
++ } else
++ memcpy(msg->message, reply->message, sizeof error_reply);
++ complete(&(resp_type->work));
++}
++
++static atomic_t zcrypt_step = ATOMIC_INIT(0);
++
++/**
++ * The request distributor calls this function if it picked the PCIXCC/CEX2C
++ * device to handle a modexpo request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCIXCC/CEX2C device to the request distributor
++ * @mex: pointer to the modexpo request buffer
++ */
++static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo *mex)
++{
++ struct ap_message ap_msg;
++ struct response_type resp_type = {
++ .type = PCIXCC_RESPONSE_TYPE_ICA,
++ };
++ int rc;
++
++ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &resp_type;
++ rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
++ if (rc)
++ goto out_free;
++ init_completion(&resp_type.work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &resp_type.work, PCIXCC_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
++ mex->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ free_page((unsigned long) ap_msg.message);
++ return rc;
++}
++
++/**
++ * The request distributor calls this function if it picked the PCIXCC/CEX2C
++ * device to handle a modexpo_crt request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCIXCC/CEX2C device to the request distributor
++ * @crt: pointer to the modexpoc_crt request buffer
++ */
++static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
++ struct ica_rsa_modexpo_crt *crt)
++{
++ struct ap_message ap_msg;
++ struct response_type resp_type = {
++ .type = PCIXCC_RESPONSE_TYPE_ICA,
++ };
++ int rc;
++
++ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &resp_type;
++ rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
++ if (rc)
++ goto out_free;
++ init_completion(&resp_type.work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &resp_type.work, PCIXCC_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
++ crt->outputdatalength);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ free_page((unsigned long) ap_msg.message);
++ return rc;
++}
++
++/**
++ * The request distributor calls this function if it picked the PCIXCC/CEX2C
++ * device to handle a send_cprb request.
++ * @zdev: pointer to zcrypt_device structure that identifies the
++ * PCIXCC/CEX2C device to the request distributor
++ * @xcRB: pointer to the send_cprb request buffer
++ */
++long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
++{
++ struct ap_message ap_msg;
++ struct response_type resp_type = {
++ .type = PCIXCC_RESPONSE_TYPE_XCRB,
++ };
++ int rc;
++
++ ap_msg.message = (void *) kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
++ if (!ap_msg.message)
++ return -ENOMEM;
++ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
++ atomic_inc_return(&zcrypt_step);
++ ap_msg.private = &resp_type;
++ rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
++ if (rc)
++ goto out_free;
++ init_completion(&resp_type.work);
++ ap_queue_message(zdev->ap_dev, &ap_msg);
++ rc = wait_for_completion_interruptible_timeout(
++ &resp_type.work, PCIXCC_CLEANUP_TIME);
++ if (rc > 0)
++ rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
++ else {
++ /* Signal pending or message timed out. */
++ ap_cancel_message(zdev->ap_dev, &ap_msg);
++ if (rc == 0)
++ /* Message timed out. */
++ rc = -ETIME;
++ }
++out_free:
++ memset(ap_msg.message, 0x0, ap_msg.length);
++ kfree(ap_msg.message);
++ return rc;
++}
++
++/**
++ * The crypto operations for a PCIXCC/CEX2C card.
++ */
++static struct zcrypt_ops zcrypt_pcixcc_ops = {
++ .rsa_modexpo = zcrypt_pcixcc_modexpo,
++ .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
++ .send_cprb = zcrypt_pcixcc_send_cprb,
++};
++
++/**
++ * Micro-code detection function. Its sends a message to a pcixcc card
++ * to find out the microcode level.
++ * @ap_dev: pointer to the AP device.
++ */
++static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
++{
++ static unsigned char msg[] = {
++ 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
++ 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
++ 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
++ 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
++ 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
++ 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
++ 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
++ 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
++ 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
++ 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
++ 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
++ 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
++ 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
++ 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
++ 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
++ 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
++ 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
++ 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
++ 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
++ 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
++ 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
++ 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
++ 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
++ 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
++ 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
++ 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
++ 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
++ 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
++ 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
++ 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
++ 0xF1,0x3D,0x93,0x53
++ };
++ unsigned long long psmid;
++ struct CPRBX *cprbx;
++ char *reply;
++ int rc, i;
++
++ reply = (void *) get_zeroed_page(GFP_KERNEL);
++ if (!reply)
++ return -ENOMEM;
++
++ rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
++ if (rc)
++ goto out_free;
++
++ /* Wait for the test message to complete. */
++ for (i = 0; i < 6; i++) {
++ mdelay(300);
++ rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
++ if (rc == 0 && psmid == 0x0102030405060708ULL)
++ break;
++ }
++
++ if (i >= 6) {
++ /* Got no answer. */
++ rc = -ENODEV;
++ goto out_free;
++ }
++
++ cprbx = (struct CPRBX *) (reply + 48);
++ if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
++ rc = ZCRYPT_PCIXCC_MCL2;
++ else
++ rc = ZCRYPT_PCIXCC_MCL3;
++out_free:
++ free_page((unsigned long) reply);
++ return rc;
++}
++
++/**
++ * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
++ * since the bus_match already checked the hardware type. The PCIXCC
++ * cards come in two flavours: micro code level 2 and micro code level 3.
++ * This is checked by sending a test message to the device.
++ * @ap_dev: pointer to the AP device.
++ */
++static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev;
++ int rc;
++
++ zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
++ if (!zdev)
++ return -ENOMEM;
++ zdev->ap_dev = ap_dev;
++ zdev->ops = &zcrypt_pcixcc_ops;
++ zdev->online = 1;
++ if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {
++ rc = zcrypt_pcixcc_mcl(ap_dev);
++ if (rc < 0) {
++ zcrypt_device_free(zdev);
++ return rc;
++ }
++ zdev->user_space_type = rc;
++ if (rc == ZCRYPT_PCIXCC_MCL2) {
++ zdev->type_string = "PCIXCC_MCL2";
++ zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
++ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
++ zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
++ } else {
++ zdev->type_string = "PCIXCC_MCL3";
++ zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
++ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
++ zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
++ }
++ } else {
++ zdev->user_space_type = ZCRYPT_CEX2C;
++ zdev->type_string = "CEX2C";
++ zdev->speed_rating = CEX2C_SPEED_RATING;
++ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
++ zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
++ }
++ ap_dev->reply = &zdev->reply;
++ ap_dev->private = zdev;
++ rc = zcrypt_device_register(zdev);
++ if (rc)
++ goto out_free;
++ return 0;
++
++ out_free:
++ ap_dev->private = NULL;
++ zcrypt_device_free(zdev);
++ return rc;
++}
++
++/**
++ * This is called to remove the extended PCIXCC/CEX2C driver information
++ * if an AP device is removed.
++ */
++static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
++{
++ struct zcrypt_device *zdev = ap_dev->private;
++
++ zcrypt_device_unregister(zdev);
++}
++
++int __init zcrypt_pcixcc_init(void)
++{
++ return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
++}
++
++void zcrypt_pcixcc_exit(void)
++{
++ ap_driver_unregister(&zcrypt_pcixcc_driver);
++}
++
++#ifndef CONFIG_ZCRYPT_MONOLITHIC
++module_init(zcrypt_pcixcc_init);
++module_exit(zcrypt_pcixcc_exit);
++#endif
+diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
+new file mode 100644
+index 0000000..a78ff30
+--- /dev/null
++++ b/drivers/s390/crypto/zcrypt_pcixcc.h
+@@ -0,0 +1,79 @@
++/*
++ * linux/drivers/s390/crypto/zcrypt_pcixcc.h
++ *
++ * zcrypt 2.1.0
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.ibm.com)
++ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky at de.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, 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 _ZCRYPT_PCIXCC_H_
++#define _ZCRYPT_PCIXCC_H_
++
++/**
++ * CPRBX
++ * Note that all shorts and ints are big-endian.
++ * All pointer fields are 16 bytes long, and mean nothing.
++ *
++ * A request CPRB is followed by a request_parameter_block.
++ *
++ * The request (or reply) parameter block is organized thus:
++ * function code
++ * VUD block
++ * key block
++ */
++struct CPRBX {
++ unsigned short cprb_len; /* CPRB length 220 */
++ unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
++ unsigned char pad_000[3]; /* Alignment pad bytes */
++ unsigned char func_id[2]; /* function id 0x5432 */
++ unsigned char cprb_flags[4]; /* Flags */
++ unsigned int req_parml; /* request parameter buffer len */
++ unsigned int req_datal; /* request data buffer */
++ unsigned int rpl_msgbl; /* reply message block length */
++ unsigned int rpld_parml; /* replied parameter block len */
++ unsigned int rpl_datal; /* reply data block len */
++ unsigned int rpld_datal; /* replied data block len */
++ unsigned int req_extbl; /* request extension block len */
++ unsigned char pad_001[4]; /* reserved */
++ unsigned int rpld_extbl; /* replied extension block len */
++ unsigned char req_parmb[16]; /* request parm block 'address' */
++ unsigned char req_datab[16]; /* request data block 'address' */
++ unsigned char rpl_parmb[16]; /* reply parm block 'address' */
++ unsigned char rpl_datab[16]; /* reply data block 'address' */
++ unsigned char req_extb[16]; /* request extension block 'addr'*/
++ unsigned char rpl_extb[16]; /* reply extension block 'addres'*/
++ unsigned short ccp_rtcode; /* server return code */
++ unsigned short ccp_rscode; /* server reason code */
++ unsigned int mac_data_len; /* Mac Data Length */
++ unsigned char logon_id[8]; /* Logon Identifier */
++ unsigned char mac_value[8]; /* Mac Value */
++ unsigned char mac_content_flgs;/* Mac content flag byte */
++ unsigned char pad_002; /* Alignment */
++ unsigned short domain; /* Domain */
++ unsigned char pad_003[12]; /* Domain masks */
++ unsigned char pad_004[36]; /* reserved */
++} __attribute__((packed));
++
++int zcrypt_pcixcc_init(void);
++void zcrypt_pcixcc_exit(void);
++
++#endif /* _ZCRYPT_PCIXCC_H_ */
+diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
+index 821dde8..1476ce2 100644
+--- a/drivers/s390/net/iucv.c
++++ b/drivers/s390/net/iucv.c
+@@ -116,7 +116,7 @@ static DEFINE_SPINLOCK(iucv_irq_queue_lo
+ *Internal function prototypes
+ */
+ static void iucv_tasklet_handler(unsigned long);
+-static void iucv_irq_handler(struct pt_regs *, __u16);
++static void iucv_irq_handler(__u16);
+
+ static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
+
+@@ -534,19 +534,15 @@ iucv_add_handler (handler *new)
+ *
+ * Returns: return code from CP's IUCV call
+ */
+-static __inline__ ulong
+-b2f0(__u32 code, void *parm)
++static inline ulong b2f0(__u32 code, void *parm)
+ {
++ register unsigned long reg0 asm ("0");
++ register unsigned long reg1 asm ("1");
+ iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
+
+- asm volatile (
+- "LRA 1,0(%1)\n\t"
+- "LR 0,%0\n\t"
+- ".long 0xb2f01000"
+- :
+- : "d" (code), "a" (parm)
+- : "0", "1"
+- );
++ reg0 = code;
++ reg1 = virt_to_phys(parm);
++ asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
+
+ iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
+
+@@ -1248,6 +1244,8 @@ iucv_purge (__u16 pathid, __u32 msgid, _
+ static int
+ iucv_query_generic(int want_maxconn)
+ {
++ register unsigned long reg0 asm ("0");
++ register unsigned long reg1 asm ("1");
+ iparml_purge *parm = (iparml_purge *)grab_param();
+ int bufsize, maxconn;
+ int ccode;
+@@ -1256,18 +1254,15 @@ iucv_query_generic(int want_maxconn)
+ * Call b2f0 and store R0 (max buffer size),
+ * R1 (max connections) and CC.
+ */
+- asm volatile (
+- "LRA 1,0(%4)\n\t"
+- "LR 0,%3\n\t"
+- ".long 0xb2f01000\n\t"
+- "IPM %0\n\t"
+- "SRL %0,28\n\t"
+- "ST 0,%1\n\t"
+- "ST 1,%2\n\t"
+- : "=d" (ccode), "=m" (bufsize), "=m" (maxconn)
+- : "d" (QUERY), "a" (parm)
+- : "0", "1", "cc"
+- );
++ reg0 = QUERY;
++ reg1 = virt_to_phys(parm);
++ asm volatile(
++ " .long 0xb2f01000\n"
++ " ipm %0\n"
++ " srl %0,28\n"
++ : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
++ bufsize = reg0;
++ maxconn = reg1;
+ release_param(parm);
+
+ if (ccode)
+@@ -2256,7 +2251,7 @@ iucv_sever(__u16 pathid, __u8 user_data[
+ * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
+ */
+ static void
+-iucv_irq_handler(struct pt_regs *regs, __u16 code)
++iucv_irq_handler(__u16 code)
+ {
+ iucv_irqdata *irqdata;
+
+diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
+index 5613b45..8364d54 100644
+--- a/drivers/s390/net/qeth_main.c
++++ b/drivers/s390/net/qeth_main.c
+@@ -8067,7 +8067,7 @@ qeth_arp_constructor(struct neighbour *n
+ neigh->parms = neigh_parms_clone(parms);
+ rcu_read_unlock();
+
+- neigh->type = inet_addr_type(*(u32 *) neigh->primary_key);
++ neigh->type = inet_addr_type(*(__be32 *) neigh->primary_key);
+ neigh->nud_state = NUD_NOARP;
+ neigh->ops = arp_direct_ops;
+ neigh->output = neigh->ops->queue_xmit;
+diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
+index 5399c5d..e088b5e 100644
+--- a/drivers/s390/s390mach.c
++++ b/drivers/s390/s390mach.c
+@@ -19,9 +19,6 @@
+
+ #include "s390mach.h"
+
+-#define DBG printk
+-// #define DBG(args,...) do {} while (0);
+-
+ static struct semaphore m_sem;
+
+ extern int css_process_crw(int, int);
+@@ -83,11 +80,11 @@ repeat:
+ ccode = stcrw(&crw[chain]);
+ if (ccode != 0)
+ break;
+- DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
+- "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
+- crw[chain].slct, crw[chain].oflw, crw[chain].chn,
+- crw[chain].rsc, crw[chain].anc, crw[chain].erc,
+- crw[chain].rsid);
++ printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
++ "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
++ crw[chain].slct, crw[chain].oflw, crw[chain].chn,
++ crw[chain].rsc, crw[chain].anc, crw[chain].erc,
++ crw[chain].rsid);
+ /* Check for overflows. */
+ if (crw[chain].oflw) {
+ pr_debug("%s: crw overflow detected!\n", __FUNCTION__);
+@@ -117,8 +114,8 @@ repeat:
+ * reported to the common I/O layer.
+ */
+ if (crw[chain].slct) {
+- DBG(KERN_INFO"solicited machine check for "
+- "channel path %02X\n", crw[0].rsid);
++ pr_debug("solicited machine check for "
++ "channel path %02X\n", crw[0].rsid);
+ break;
+ }
+ switch (crw[0].erc) {
+@@ -211,7 +208,7 @@ s390_handle_mcck(void)
+ */
+ __ctl_clear_bit(14, 24); /* Disable WARNING MCH */
+ if (xchg(&mchchk_wng_posted, 1) == 0)
+- kill_proc(1, SIGPWR, 1);
++ kill_cad_pid(SIGPWR, 1);
+ }
+ #endif
+
+@@ -256,11 +253,12 @@ s390_revalidate_registers(struct mci *mc
+ kill_task = 1;
+
+ #ifndef CONFIG_64BIT
+- 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));
++ 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) {
+@@ -277,37 +275,36 @@ s390_revalidate_registers(struct mci *mc
+ * Floating point control register can't be restored.
+ * Task will be terminated.
+ */
+- asm volatile ("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
++ asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (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));
++ } 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));
++ asm volatile(
++ " lam 0,15,0(%0)"
++ : : "a" (&S390_lowcore.access_regs_save_area));
+ if (!mci->ar)
+ /*
+ * Access registers have unknown contents.
+@@ -324,11 +321,13 @@ s390_revalidate_registers(struct mci *mc
+ s390_handle_damage("invalid control registers.");
+ else
+ #ifdef CONFIG_64BIT
+- asm volatile("lctlg 0,15,0(%0)"
+- : : "a" (&S390_lowcore.cregs_save_area));
++ 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));
++ asm volatile(
++ " lctl 0,15,0(%0)"
++ : : "a" (&S390_lowcore.cregs_save_area));
+ #endif
+
+ /*
+@@ -342,20 +341,23 @@ s390_revalidate_registers(struct mci *mc
+ * old contents (should be zero) otherwise set it to zero.
+ */
+ if (!mci->pr)
+- asm volatile("sr 0,0\n"
+- "sckpf"
+- : : : "0", "cc");
++ 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");
++ " 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");
++ asm volatile(
++ " stck 0(%1)\n"
++ " sckc 0(%1)"
++ : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
+
+ /* Check if old PSW is valid */
+ if (!mci->wp)
+diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
+index adc9d8f..5d39b2d 100644
+--- a/drivers/s390/scsi/zfcp_aux.c
++++ b/drivers/s390/scsi/zfcp_aux.c
+@@ -189,6 +189,10 @@ struct zfcp_fsf_req *zfcp_reqlist_ismemb
+ struct zfcp_fsf_req *request, *tmp;
+ unsigned int i;
+
++ /* 0 is reserved as an invalid req_id */
++ if (req_id == 0)
++ return NULL;
++
+ i = req_id % REQUEST_LIST_SIZE;
+
+ list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
+@@ -299,11 +303,45 @@ zfcp_init_device_configure(void)
+ return;
+ }
+
++static int calc_alignment(int size)
++{
++ int align = 1;
++
++ if (!size)
++ return 0;
++
++ while ((size - align) > 0)
++ align <<= 1;
++
++ return align;
++}
++
+ static int __init
+ zfcp_module_init(void)
+ {
++ int retval = -ENOMEM;
++ int size, align;
++
++ size = sizeof(struct zfcp_fsf_req_qtcb);
++ align = calc_alignment(size);
++ zfcp_data.fsf_req_qtcb_cache =
++ kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL);
++ if (!zfcp_data.fsf_req_qtcb_cache)
++ goto out;
+
+- int retval = 0;
++ size = sizeof(struct fsf_status_read_buffer);
++ align = calc_alignment(size);
++ zfcp_data.sr_buffer_cache =
++ kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL);
++ if (!zfcp_data.sr_buffer_cache)
++ goto out_sr_cache;
++
++ size = sizeof(struct zfcp_gid_pn_data);
++ align = calc_alignment(size);
++ zfcp_data.gid_pn_cache =
++ kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL);
++ if (!zfcp_data.gid_pn_cache)
++ goto out_gid_cache;
+
+ atomic_set(&zfcp_data.loglevel, loglevel);
+
+@@ -313,15 +351,16 @@ zfcp_module_init(void)
+ /* initialize adapters to be removed list head */
+ INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh);
+
+- zfcp_transport_template = fc_attach_transport(&zfcp_transport_functions);
+- if (!zfcp_transport_template)
+- return -ENODEV;
++ zfcp_data.scsi_transport_template =
++ fc_attach_transport(&zfcp_transport_functions);
++ if (!zfcp_data.scsi_transport_template)
++ goto out_transport;
+
+ retval = misc_register(&zfcp_cfdc_misc);
+ if (retval != 0) {
+ ZFCP_LOG_INFO("registration of misc device "
+ "zfcp_cfdc failed\n");
+- goto out;
++ goto out_misc;
+ }
+
+ ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n",
+@@ -333,9 +372,6 @@ zfcp_module_init(void)
+ /* initialise configuration rw lock */
+ rwlock_init(&zfcp_data.config_lock);
+
+- /* save address of data structure managing the driver module */
+- zfcp_data.scsi_host_template.module = THIS_MODULE;
+-
+ /* setup dynamic I/O */
+ retval = zfcp_ccw_register();
+ if (retval) {
+@@ -350,6 +386,14 @@ zfcp_module_init(void)
+
+ out_ccw_register:
+ misc_deregister(&zfcp_cfdc_misc);
++ out_misc:
++ fc_release_transport(zfcp_data.scsi_transport_template);
++ out_transport:
++ kmem_cache_destroy(zfcp_data.gid_pn_cache);
++ out_gid_cache:
++ kmem_cache_destroy(zfcp_data.sr_buffer_cache);
++ out_sr_cache:
++ kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache);
+ out:
+ return retval;
+ }
+@@ -935,20 +979,20 @@ static int
+ zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
+ {
+ adapter->pool.fsf_req_erp =
+- mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ERP_NR,
+- sizeof(struct zfcp_fsf_req_pool_element));
++ mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ERP_NR,
++ zfcp_data.fsf_req_qtcb_cache);
+ if (!adapter->pool.fsf_req_erp)
+ return -ENOMEM;
+
+ adapter->pool.fsf_req_scsi =
+- mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_SCSI_NR,
+- sizeof(struct zfcp_fsf_req_pool_element));
++ mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_SCSI_NR,
++ zfcp_data.fsf_req_qtcb_cache);
+ if (!adapter->pool.fsf_req_scsi)
+ return -ENOMEM;
+
+ adapter->pool.fsf_req_abort =
+- mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ABORT_NR,
+- sizeof(struct zfcp_fsf_req_pool_element));
++ mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ABORT_NR,
++ zfcp_data.fsf_req_qtcb_cache);
+ if (!adapter->pool.fsf_req_abort)
+ return -ENOMEM;
+
+@@ -959,14 +1003,14 @@ zfcp_allocate_low_mem_buffers(struct zfc
+ return -ENOMEM;
+
+ adapter->pool.data_status_read =
+- mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR,
+- sizeof(struct fsf_status_read_buffer));
++ mempool_create_slab_pool(ZFCP_POOL_STATUS_READ_NR,
++ zfcp_data.sr_buffer_cache);
+ if (!adapter->pool.data_status_read)
+ return -ENOMEM;
+
+ adapter->pool.data_gid_pn =
+- mempool_create_kmalloc_pool(ZFCP_POOL_DATA_GID_PN_NR,
+- sizeof(struct zfcp_gid_pn_data));
++ mempool_create_slab_pool(ZFCP_POOL_DATA_GID_PN_NR,
++ zfcp_data.gid_pn_cache);
+ if (!adapter->pool.data_gid_pn)
+ return -ENOMEM;
+
+@@ -1091,9 +1135,6 @@ zfcp_adapter_enqueue(struct ccw_device *
+ /* initialize lock of associated request queue */
+ rwlock_init(&adapter->request_queue.queue_lock);
+
+- /* intitialise SCSI ER timer */
+- init_timer(&adapter->scsi_er_timer);
+-
+ /* mark adapter unusable as long as sysfs registration is not complete */
+ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
+
+@@ -1609,7 +1650,6 @@ zfcp_ns_gid_pn_request(struct zfcp_erp_a
+ gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
+ gid_pn->ct.handler_data = (unsigned long) gid_pn;
+ gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
+- gid_pn->ct.timer = &erp_action->timer;
+ gid_pn->port = erp_action->port;
+
+ ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
+diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
+index fdabade..81680ef 100644
+--- a/drivers/s390/scsi/zfcp_ccw.c
++++ b/drivers/s390/scsi/zfcp_ccw.c
+@@ -275,19 +275,6 @@ zfcp_ccw_register(void)
+ }
+
+ /**
+- * zfcp_ccw_unregister - ccw unregister function
+- *
+- * Unregisters the driver from common i/o layer. Function will be called at
+- * module unload/system shutdown.
+- */
+-void __exit
+-zfcp_ccw_unregister(void)
+-{
+- zfcp_sysfs_driver_remove_files(&zfcp_ccw_driver.driver);
+- ccw_driver_unregister(&zfcp_ccw_driver);
+-}
+-
+-/**
+ * zfcp_ccw_shutdown - gets called on reboot/shutdown
+ *
+ * Makes sure that QDIO queues are down when the system gets stopped.
+diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
+index c033145..0aa3b1a 100644
+--- a/drivers/s390/scsi/zfcp_dbf.c
++++ b/drivers/s390/scsi/zfcp_dbf.c
+@@ -707,7 +707,7 @@ _zfcp_scsi_dbf_event_common(const char *
+ struct zfcp_adapter *adapter,
+ struct scsi_cmnd *scsi_cmnd,
+ struct zfcp_fsf_req *fsf_req,
+- struct zfcp_fsf_req *old_fsf_req)
++ unsigned long old_req_id)
+ {
+ struct zfcp_scsi_dbf_record *rec = &adapter->scsi_dbf_buf;
+ struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
+@@ -768,8 +768,7 @@ _zfcp_scsi_dbf_event_common(const char *
+ rec->fsf_seqno = fsf_req->seq_no;
+ rec->fsf_issued = fsf_req->issued;
+ }
+- rec->type.old_fsf_reqid =
+- (unsigned long) old_fsf_req;
++ rec->type.old_fsf_reqid = old_req_id;
+ } else {
+ strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
+ dump->total_size = buflen;
+@@ -794,17 +793,17 @@ zfcp_scsi_dbf_event_result(const char *t
+ struct zfcp_fsf_req *fsf_req)
+ {
+ _zfcp_scsi_dbf_event_common("rslt", tag, level,
+- adapter, scsi_cmnd, fsf_req, NULL);
++ adapter, scsi_cmnd, fsf_req, 0);
+ }
+
+ inline void
+ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
+ struct scsi_cmnd *scsi_cmnd,
+ struct zfcp_fsf_req *new_fsf_req,
+- struct zfcp_fsf_req *old_fsf_req)
++ unsigned long old_req_id)
+ {
+ _zfcp_scsi_dbf_event_common("abrt", tag, 1,
+- adapter, scsi_cmnd, new_fsf_req, old_fsf_req);
++ adapter, scsi_cmnd, new_fsf_req, old_req_id);
+ }
+
+ inline void
+@@ -814,7 +813,7 @@ zfcp_scsi_dbf_event_devreset(const char
+ struct zfcp_adapter *adapter = unit->port->adapter;
+
+ _zfcp_scsi_dbf_event_common(flag == FCP_TARGET_RESET ? "trst" : "lrst",
+- tag, 1, adapter, scsi_cmnd, NULL, NULL);
++ tag, 1, adapter, scsi_cmnd, NULL, 0);
+ }
+
+ static int
+diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
+index 94d1b74..74c0eac 100644
+--- a/drivers/s390/scsi/zfcp_def.h
++++ b/drivers/s390/scsi/zfcp_def.h
+@@ -19,7 +19,6 @@
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+-
+ #ifndef ZFCP_DEF_H
+ #define ZFCP_DEF_H
+
+@@ -32,6 +31,10 @@
+ #include <linux/blkdev.h>
+ #include <linux/delay.h>
+ #include <linux/timer.h>
++#include <linux/slab.h>
++#include <linux/mempool.h>
++#include <linux/syscalls.h>
++#include <linux/ioctl.h>
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_tcq.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -39,14 +42,11 @@
+ #include <scsi/scsi_host.h>
+ #include <scsi/scsi_transport.h>
+ #include <scsi/scsi_transport_fc.h>
+-#include "zfcp_fsf.h"
+ #include <asm/ccwdev.h>
+ #include <asm/qdio.h>
+ #include <asm/debug.h>
+ #include <asm/ebcdic.h>
+-#include <linux/mempool.h>
+-#include <linux/syscalls.h>
+-#include <linux/ioctl.h>
++#include "zfcp_fsf.h"
+
+
+ /********************* GENERAL DEFINES *********************************/
+@@ -107,6 +107,10 @@ zfcp_address_to_sg(void *address, struct
+ (ZFCP_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2)
+ /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
+
++#define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8)
++ /* max. number of (data buffer) SBALEs in largest SBAL chain
++ multiplied with number of sectors per 4k block */
++
+ /* FIXME(tune): free space should be one max. SBAL chain plus what? */
+ #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \
+ - (ZFCP_MAX_SBALS_PER_REQ + 4))
+@@ -137,7 +141,7 @@ zfcp_address_to_sg(void *address, struct
+ #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7
+
+ /* timeout value for "default timer" for fsf requests */
+-#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ);
++#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ)
+
+ /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
+
+@@ -543,7 +547,7 @@ do { \
+ } while (0)
+
+ #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
+-# define ZFCP_LOG_NORMAL(fmt, args...)
++# define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0)
+ #else
+ # define ZFCP_LOG_NORMAL(fmt, args...) \
+ do { \
+@@ -553,7 +557,7 @@ do { \
+ #endif
+
+ #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO
+-# define ZFCP_LOG_INFO(fmt, args...)
++# define ZFCP_LOG_INFO(fmt, args...) do { } while (0)
+ #else
+ # define ZFCP_LOG_INFO(fmt, args...) \
+ do { \
+@@ -563,14 +567,14 @@ do { \
+ #endif
+
+ #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG
+-# define ZFCP_LOG_DEBUG(fmt, args...)
++# define ZFCP_LOG_DEBUG(fmt, args...) do { } while (0)
+ #else
+ # define ZFCP_LOG_DEBUG(fmt, args...) \
+ ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args)
+ #endif
+
+ #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE
+-# define ZFCP_LOG_TRACE(fmt, args...)
++# define ZFCP_LOG_TRACE(fmt, args...) do { } while (0)
+ #else
+ # define ZFCP_LOG_TRACE(fmt, args...) \
+ ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
+@@ -779,7 +783,6 @@ typedef void (*zfcp_send_ct_handler_t)(u
+ * @handler_data: data passed to handler function
+ * @pool: pointer to memory pool for ct request structure
+ * @timeout: FSF timeout for this request
+- * @timer: timer (e.g. for request initiated by erp)
+ * @completion: completion for synchronization purposes
+ * @status: used to pass error status to calling function
+ */
+@@ -793,7 +796,6 @@ struct zfcp_send_ct {
+ unsigned long handler_data;
+ mempool_t *pool;
+ int timeout;
+- struct timer_list *timer;
+ struct completion *completion;
+ int status;
+ };
+@@ -821,7 +823,6 @@ typedef void (*zfcp_send_els_handler_t)(
+ * @resp_count: number of elements in response scatter-gather list
+ * @handler: handler function (called for response to the request)
+ * @handler_data: data passed to handler function
+- * @timer: timer (e.g. for request initiated by erp)
+ * @completion: completion for synchronization purposes
+ * @ls_code: hex code of ELS command
+ * @status: used to pass error status to calling function
+@@ -836,7 +837,6 @@ struct zfcp_send_els {
+ unsigned int resp_count;
+ zfcp_send_els_handler_t handler;
+ unsigned long handler_data;
+- struct timer_list *timer;
+ struct completion *completion;
+ int ls_code;
+ int status;
+@@ -886,7 +886,6 @@ struct zfcp_adapter {
+ struct list_head port_remove_lh; /* head of ports to be
+ removed */
+ u32 ports; /* number of remote ports */
+- struct timer_list scsi_er_timer; /* SCSI err recovery watch */
+ atomic_t reqs_active; /* # active FSF reqs */
+ unsigned long req_no; /* unique FSF req number */
+ struct list_head *req_list; /* list of pending reqs */
+@@ -1003,6 +1002,7 @@ struct zfcp_fsf_req {
+ struct fsf_qtcb *qtcb; /* address of associated QTCB */
+ u32 seq_no; /* Sequence number of request */
+ unsigned long data; /* private data of request */
++ struct timer_list timer; /* used for erp or scsi er */
+ struct zfcp_erp_action *erp_action; /* used if this request is
+ issued on behalf of erp */
+ mempool_t *pool; /* used if request was alloacted
+@@ -1016,6 +1016,7 @@ typedef void zfcp_fsf_req_handler_t(stru
+ /* driver data */
+ struct zfcp_data {
+ struct scsi_host_template scsi_host_template;
++ struct scsi_transport_template *scsi_transport_template;
+ atomic_t status; /* Module status flags */
+ struct list_head adapter_list_head; /* head of adapter list */
+ struct list_head adapter_remove_lh; /* head of adapters to be
+@@ -1031,6 +1032,9 @@ struct zfcp_data {
+ wwn_t init_wwpn;
+ fcp_lun_t init_fcp_lun;
+ char *driver_version;
++ kmem_cache_t *fsf_req_qtcb_cache;
++ kmem_cache_t *sr_buffer_cache;
++ kmem_cache_t *gid_pn_cache;
+ };
+
+ /**
+@@ -1051,7 +1055,7 @@ struct zfcp_sg_list {
+ #define ZFCP_POOL_DATA_GID_PN_NR 1
+
+ /* struct used by memory pools for fsf_requests */
+-struct zfcp_fsf_req_pool_element {
++struct zfcp_fsf_req_qtcb {
+ struct zfcp_fsf_req fsf_req;
+ struct fsf_qtcb qtcb;
+ };
+diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
+index 7f60b6f..c88babc 100644
+--- a/drivers/s390/scsi/zfcp_erp.c
++++ b/drivers/s390/scsi/zfcp_erp.c
+@@ -64,8 +64,6 @@ static int zfcp_erp_strategy_check_actio
+ static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *);
+ static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int);
+ static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *);
+-static void zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *);
+-static void zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *);
+ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *);
+ static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *);
+ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *);
+@@ -93,6 +91,7 @@ static int zfcp_erp_unit_strategy_clears
+ static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *);
+ static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *);
+
++static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
+ static void zfcp_erp_action_dismiss_port(struct zfcp_port *);
+ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
+ static void zfcp_erp_action_dismiss(struct zfcp_erp_action *);
+@@ -111,64 +110,86 @@ static inline void zfcp_erp_action_to_re
+ static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+
+ static void zfcp_erp_memwait_handler(unsigned long);
+-static void zfcp_erp_timeout_handler(unsigned long);
+-static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *);
+
+ /**
+- * zfcp_fsf_request_timeout_handler - called if a request timed out
+- * @data: pointer to adapter for handler function
+- *
+- * This function needs to be called if requests (ELS, Generic Service,
+- * or SCSI commands) exceed a certain time limit. The assumption is
+- * that after the time limit the adapter get stuck. So we trigger a reopen of
+- * the adapter. This should not be used for error recovery, SCSI abort
+- * commands and SCSI requests from SCSI mid-layer.
++ * zfcp_close_qdio - close qdio queues for an adapter
+ */
+-void
+-zfcp_fsf_request_timeout_handler(unsigned long data)
++static void zfcp_close_qdio(struct zfcp_adapter *adapter)
+ {
+- struct zfcp_adapter *adapter;
++ struct zfcp_qdio_queue *req_queue;
++ int first, count;
+
+- adapter = (struct zfcp_adapter *) data;
++ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
++ return;
+
+- zfcp_erp_adapter_reopen(adapter, 0);
++ /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
++ req_queue = &adapter->request_queue;
++ write_lock_irq(&req_queue->queue_lock);
++ atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
++ write_unlock_irq(&req_queue->queue_lock);
++
++ debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
++ while (qdio_shutdown(adapter->ccw_device,
++ QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
++ msleep(1000);
++ debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
++
++ /* cleanup used outbound sbals */
++ count = atomic_read(&req_queue->free_count);
++ if (count < QDIO_MAX_BUFFERS_PER_Q) {
++ first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q;
++ count = QDIO_MAX_BUFFERS_PER_Q - count;
++ zfcp_qdio_zero_sbals(req_queue->buffer, first, count);
++ }
++ req_queue->free_index = 0;
++ atomic_set(&req_queue->free_count, 0);
++ req_queue->distance_from_int = 0;
++ adapter->response_queue.free_index = 0;
++ atomic_set(&adapter->response_queue.free_count, 0);
+ }
+
+ /**
+- * zfcp_fsf_scsi_er_timeout_handler - timeout handler for scsi eh tasks
++ * zfcp_close_fsf - stop FSF operations for an adapter
+ *
+- * This function needs to be called whenever a SCSI error recovery
+- * action (abort/reset) does not return. Re-opening the adapter means
+- * that the abort/reset command can be returned by zfcp. It won't complete
+- * via the adapter anymore (because qdio queues are closed). If ERP is
+- * already running on this adapter it will be stopped.
++ * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of
++ * requests waiting for completion; especially this returns SCSI commands
++ * with error state).
+ */
+-void zfcp_fsf_scsi_er_timeout_handler(unsigned long data)
++static void zfcp_close_fsf(struct zfcp_adapter *adapter)
+ {
+- struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
+- unsigned long flags;
+-
+- ZFCP_LOG_NORMAL("warning: SCSI error recovery timed out. "
+- "Restarting all operations on the adapter %s\n",
+- zfcp_get_busid_by_adapter(adapter));
+- debug_text_event(adapter->erp_dbf, 1, "eh_lmem_tout");
++ /* close queues to ensure that buffers are not accessed by adapter */
++ zfcp_close_qdio(adapter);
++ zfcp_fsf_req_dismiss_all(adapter);
++ /* reset FSF request sequence number */
++ adapter->fsf_req_seq_no = 0;
++ /* all ports and units are closed */
++ zfcp_erp_modify_adapter_status(adapter,
++ ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
++}
+
+- write_lock_irqsave(&adapter->erp_lock, flags);
+- if (atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
+- &adapter->status)) {
+- zfcp_erp_modify_adapter_status(adapter,
+- ZFCP_STATUS_COMMON_UNBLOCKED|ZFCP_STATUS_COMMON_OPEN,
+- ZFCP_CLEAR);
+- zfcp_erp_action_dismiss_adapter(adapter);
+- write_unlock_irqrestore(&adapter->erp_lock, flags);
+- /* dismiss all pending requests including requests for ERP */
+- zfcp_fsf_req_dismiss_all(adapter);
+- adapter->fsf_req_seq_no = 0;
+- } else
+- write_unlock_irqrestore(&adapter->erp_lock, flags);
++/**
++ * zfcp_fsf_request_timeout_handler - called if a request timed out
++ * @data: pointer to adapter for handler function
++ *
++ * This function needs to be called if requests (ELS, Generic Service,
++ * or SCSI commands) exceed a certain time limit. The assumption is
++ * that after the time limit the adapter get stuck. So we trigger a reopen of
++ * the adapter.
++ */
++static void zfcp_fsf_request_timeout_handler(unsigned long data)
++{
++ struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
+ zfcp_erp_adapter_reopen(adapter, 0);
+ }
+
++void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
++{
++ fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
++ fsf_req->timer.data = (unsigned long) fsf_req->adapter;
++ fsf_req->timer.expires = timeout;
++ add_timer(&fsf_req->timer);
++}
++
+ /*
+ * function:
+ *
+@@ -282,7 +303,6 @@ zfcp_erp_adisc(struct zfcp_port *port)
+ struct zfcp_ls_adisc *adisc;
+ void *address = NULL;
+ int retval = 0;
+- struct timer_list *timer;
+
+ send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
+ if (send_els == NULL)
+@@ -329,22 +349,11 @@ zfcp_erp_adisc(struct zfcp_port *port)
+ (wwn_t) adisc->wwnn, adisc->hard_nport_id,
+ adisc->nport_id);
+
+- timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
+- if (!timer)
+- goto nomem;
+-
+- init_timer(timer);
+- timer->function = zfcp_fsf_request_timeout_handler;
+- timer->data = (unsigned long) adapter;
+- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
+- send_els->timer = timer;
+-
+ retval = zfcp_fsf_send_els(send_els);
+ if (retval != 0) {
+ ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
+ "0x%08x on adapter %s\n", send_els->d_id,
+ zfcp_get_busid_by_adapter(adapter));
+- del_timer(send_els->timer);
+ goto freemem;
+ }
+
+@@ -356,7 +365,6 @@ zfcp_erp_adisc(struct zfcp_port *port)
+ if (address != NULL)
+ __free_pages(send_els->req->page, 0);
+ if (send_els != NULL) {
+- kfree(send_els->timer);
+ kfree(send_els->req);
+ kfree(send_els->resp);
+ kfree(send_els);
+@@ -382,9 +390,6 @@ zfcp_erp_adisc_handler(unsigned long dat
+ struct zfcp_ls_adisc_acc *adisc;
+
+ send_els = (struct zfcp_send_els *) data;
+-
+- del_timer(send_els->timer);
+-
+ adapter = send_els->adapter;
+ port = send_els->port;
+ d_id = send_els->d_id;
+@@ -433,7 +438,6 @@ zfcp_erp_adisc_handler(unsigned long dat
+ out:
+ zfcp_port_put(port);
+ __free_pages(send_els->req->page, 0);
+- kfree(send_els->timer);
+ kfree(send_els->req);
+ kfree(send_els->resp);
+ kfree(send_els);
+@@ -909,8 +913,6 @@ static void zfcp_erp_async_handler_noloc
+ debug_text_event(adapter->erp_dbf, 2, "a_asyh_ex");
+ debug_event(adapter->erp_dbf, 2, &erp_action->action,
+ sizeof (int));
+- if (!(set_mask & ZFCP_STATUS_ERP_TIMEDOUT))
+- del_timer(&erp_action->timer);
+ erp_action->status |= set_mask;
+ zfcp_erp_action_ready(erp_action);
+ } else {
+@@ -957,8 +959,7 @@ zfcp_erp_memwait_handler(unsigned long d
+ * action gets an appropriate flag and will be processed
+ * accordingly
+ */
+-static void
+-zfcp_erp_timeout_handler(unsigned long data)
++void zfcp_erp_timeout_handler(unsigned long data)
+ {
+ struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
+ struct zfcp_adapter *adapter = erp_action->adapter;
+@@ -1934,8 +1935,7 @@ zfcp_erp_adapter_strategy_generic(struct
+ &erp_action->adapter->status);
+
+ failed_openfcp:
+- zfcp_erp_adapter_strategy_close_qdio(erp_action);
+- zfcp_erp_adapter_strategy_close_fsf(erp_action);
++ zfcp_close_fsf(erp_action->adapter);
+ failed_qdio:
+ out:
+ return retval;
+@@ -1987,7 +1987,7 @@ zfcp_erp_adapter_strategy_open_qdio(stru
+ sbale = &(adapter->response_queue.buffer[i]->element[0]);
+ sbale->length = 0;
+ sbale->flags = SBAL_FLAGS_LAST_ENTRY;
+- sbale->addr = 0;
++ sbale->addr = NULL;
+ }
+
+ ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, "
+@@ -2040,59 +2040,6 @@ zfcp_erp_adapter_strategy_open_qdio(stru
+ return retval;
+ }
+
+-/**
+- * zfcp_erp_adapter_strategy_close_qdio - close qdio queues for an adapter
+- */
+-static void
+-zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
+-{
+- int first_used;
+- int used_count;
+- struct zfcp_adapter *adapter = erp_action->adapter;
+-
+- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
+- ZFCP_LOG_DEBUG("error: attempt to shut down inactive QDIO "
+- "queues on adapter %s\n",
+- zfcp_get_busid_by_adapter(adapter));
+- return;
+- }
+-
+- /*
+- * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that
+- * do_QDIO won't be called while qdio_shutdown is in progress.
+- */
+- write_lock_irq(&adapter->request_queue.queue_lock);
+- atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
+- write_unlock_irq(&adapter->request_queue.queue_lock);
+-
+- debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
+- while (qdio_shutdown(adapter->ccw_device,
+- QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
+- msleep(1000);
+- debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
+-
+- /*
+- * First we had to stop QDIO operation.
+- * Now it is safe to take the following actions.
+- */
+-
+- /* Cleanup only necessary when there are unacknowledged buffers */
+- if (atomic_read(&adapter->request_queue.free_count)
+- < QDIO_MAX_BUFFERS_PER_Q) {
+- first_used = (adapter->request_queue.free_index +
+- atomic_read(&adapter->request_queue.free_count))
+- % QDIO_MAX_BUFFERS_PER_Q;
+- used_count = QDIO_MAX_BUFFERS_PER_Q -
+- atomic_read(&adapter->request_queue.free_count);
+- zfcp_qdio_zero_sbals(adapter->request_queue.buffer,
+- first_used, used_count);
+- }
+- adapter->response_queue.free_index = 0;
+- atomic_set(&adapter->response_queue.free_count, 0);
+- adapter->request_queue.free_index = 0;
+- atomic_set(&adapter->request_queue.free_count, 0);
+- adapter->request_queue.distance_from_int = 0;
+-}
+
+ static int
+ zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action)
+@@ -2127,7 +2074,6 @@ zfcp_erp_adapter_strategy_open_fsf_xconf
+ write_lock_irq(&adapter->erp_lock);
+ zfcp_erp_action_to_running(erp_action);
+ write_unlock_irq(&adapter->erp_lock);
+- zfcp_erp_timeout_init(erp_action);
+ if (zfcp_fsf_exchange_config_data(erp_action)) {
+ retval = ZFCP_ERP_FAILED;
+ debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf");
+@@ -2196,7 +2142,6 @@ zfcp_erp_adapter_strategy_open_fsf_xport
+ zfcp_erp_action_to_running(erp_action);
+ write_unlock_irq(&adapter->erp_lock);
+
+- zfcp_erp_timeout_init(erp_action);
+ ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
+ if (ret == -EOPNOTSUPP) {
+ debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
+@@ -2248,27 +2193,6 @@ zfcp_erp_adapter_strategy_open_fsf_statu
+ return retval;
+ }
+
+-/**
+- * zfcp_erp_adapter_strategy_close_fsf - stop FSF operations for an adapter
+- */
+-static void
+-zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action)
+-{
+- struct zfcp_adapter *adapter = erp_action->adapter;
+-
+- /*
+- * wake waiting initiators of requests,
+- * return SCSI commands (with error status),
+- * clean up all requests (synchronously)
+- */
+- zfcp_fsf_req_dismiss_all(adapter);
+- /* reset FSF request sequence number */
+- adapter->fsf_req_seq_no = 0;
+- /* all ports and units are closed */
+- zfcp_erp_modify_adapter_status(adapter,
+- ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
+-}
+-
+ /*
+ * function:
+ *
+@@ -2605,7 +2529,6 @@ zfcp_erp_port_forced_strategy_close(stru
+ struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_port *port = erp_action->port;
+
+- zfcp_erp_timeout_init(erp_action);
+ retval = zfcp_fsf_close_physical_port(erp_action);
+ if (retval == -ENOMEM) {
+ debug_text_event(adapter->erp_dbf, 5, "o_pfstc_nomem");
+@@ -2662,7 +2585,6 @@ zfcp_erp_port_strategy_close(struct zfcp
+ struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_port *port = erp_action->port;
+
+- zfcp_erp_timeout_init(erp_action);
+ retval = zfcp_fsf_close_port(erp_action);
+ if (retval == -ENOMEM) {
+ debug_text_event(adapter->erp_dbf, 5, "p_pstc_nomem");
+@@ -2700,7 +2622,6 @@ zfcp_erp_port_strategy_open_port(struct
+ struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_port *port = erp_action->port;
+
+- zfcp_erp_timeout_init(erp_action);
+ retval = zfcp_fsf_open_port(erp_action);
+ if (retval == -ENOMEM) {
+ debug_text_event(adapter->erp_dbf, 5, "p_psto_nomem");
+@@ -2738,7 +2659,6 @@ zfcp_erp_port_strategy_open_common_looku
+ struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_port *port = erp_action->port;
+
+- zfcp_erp_timeout_init(erp_action);
+ retval = zfcp_ns_gid_pn_request(erp_action);
+ if (retval == -ENOMEM) {
+ debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
+@@ -2864,7 +2784,6 @@ zfcp_erp_unit_strategy_close(struct zfcp
+ struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_unit *unit = erp_action->unit;
+
+- zfcp_erp_timeout_init(erp_action);
+ retval = zfcp_fsf_close_unit(erp_action);
+ if (retval == -ENOMEM) {
+ debug_text_event(adapter->erp_dbf, 5, "u_ustc_nomem");
+@@ -2905,7 +2824,6 @@ zfcp_erp_unit_strategy_open(struct zfcp_
+ struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_unit *unit = erp_action->unit;
+
+- zfcp_erp_timeout_init(erp_action);
+ retval = zfcp_fsf_open_unit(erp_action);
+ if (retval == -ENOMEM) {
+ debug_text_event(adapter->erp_dbf, 5, "u_usto_nomem");
+@@ -2930,14 +2848,13 @@ zfcp_erp_unit_strategy_open(struct zfcp_
+ return retval;
+ }
+
+-static inline void
+-zfcp_erp_timeout_init(struct zfcp_erp_action *erp_action)
++void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
+ {
+- init_timer(&erp_action->timer);
+- erp_action->timer.function = zfcp_erp_timeout_handler;
+- erp_action->timer.data = (unsigned long) erp_action;
+- /* jiffies will be added in zfcp_fsf_req_send */
+- erp_action->timer.expires = ZFCP_ERP_FSFREQ_TIMEOUT;
++ BUG_ON(!fsf_req->erp_action);
++ fsf_req->timer.function = zfcp_erp_timeout_handler;
++ fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
++ fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT;
++ add_timer(&fsf_req->timer);
+ }
+
+ /*
+@@ -3241,7 +3158,7 @@ zfcp_erp_action_cleanup(int action, stru
+ }
+
+
+-void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
++static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
+ {
+ struct zfcp_port *port;
+
+diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
+index 146d7a2..b8794d7 100644
+--- a/drivers/s390/scsi/zfcp_ext.h
++++ b/drivers/s390/scsi/zfcp_ext.h
+@@ -55,7 +55,6 @@ extern void zfcp_unit_dequeue(struct z
+
+ /******************************* S/390 IO ************************************/
+ extern int zfcp_ccw_register(void);
+-extern void zfcp_ccw_unregister(void);
+
+ extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int);
+ extern int zfcp_qdio_allocate(struct zfcp_adapter *);
+@@ -88,8 +87,8 @@ extern int zfcp_fsf_exchange_port_data(
+ struct fsf_qtcb_bottom_port *);
+ extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
+ u32, u32, struct zfcp_sg_list *);
+-extern void zfcp_fsf_request_timeout_handler(unsigned long);
+-extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long);
++extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
++extern void zfcp_erp_start_timer(struct zfcp_fsf_req *);
+ extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
+ extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
+ extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
+@@ -99,8 +98,7 @@ extern int zfcp_fsf_send_ct(struct zfcp_
+ extern int zfcp_fsf_send_els(struct zfcp_send_els *);
+ extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
+ struct zfcp_unit *,
+- struct scsi_cmnd *,
+- struct timer_list*, int);
++ struct scsi_cmnd *, int, int);
+ extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *);
+ extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *);
+ extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
+@@ -124,14 +122,11 @@ extern char *zfcp_get_fcp_rsp_info_ptr(s
+ extern void set_host_byte(u32 *, char);
+ extern void set_driver_byte(u32 *, char);
+ extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
+-extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *);
+ extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
+
+ extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *,
+- struct scsi_cmnd *, struct timer_list *);
+-extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *,
+- struct timer_list *);
+-extern struct scsi_transport_template *zfcp_transport_template;
++ struct scsi_cmnd *, int);
++extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, int);
+ extern struct fc_function_template zfcp_transport_functions;
+
+ /******************************** ERP ****************************************/
+@@ -139,7 +134,6 @@ extern void zfcp_erp_modify_adapter_stat
+ extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int);
+ extern int zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int);
+ extern void zfcp_erp_adapter_failed(struct zfcp_adapter *);
+-extern void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
+
+ extern void zfcp_erp_modify_port_status(struct zfcp_port *, u32, int);
+ extern int zfcp_erp_port_reopen(struct zfcp_port *, int);
+@@ -187,7 +181,7 @@ extern void zfcp_scsi_dbf_event_result(c
+ struct zfcp_fsf_req *);
+ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
+ struct scsi_cmnd *, struct zfcp_fsf_req *,
+- struct zfcp_fsf_req *);
++ unsigned long);
+ extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
+ struct scsi_cmnd *);
+ extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
+diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
+index ff2eacf..277826c 100644
+--- a/drivers/s390/scsi/zfcp_fsf.c
++++ b/drivers/s390/scsi/zfcp_fsf.c
+@@ -42,7 +42,7 @@ static inline int zfcp_fsf_req_sbal_chec
+ static inline int zfcp_use_one_sbal(
+ struct scatterlist *, int, struct scatterlist *, int);
+ static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
+-static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);
++static int zfcp_fsf_req_send(struct zfcp_fsf_req *);
+ static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
+ static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
+ static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
+@@ -100,14 +100,19 @@ zfcp_fsf_req_alloc(mempool_t *pool, int
+ if (req_flags & ZFCP_REQ_NO_QTCB)
+ size = sizeof(struct zfcp_fsf_req);
+ else
+- size = sizeof(struct zfcp_fsf_req_pool_element);
++ size = sizeof(struct zfcp_fsf_req_qtcb);
+
+- if (likely(pool != NULL))
++ if (likely(pool))
+ ptr = mempool_alloc(pool, GFP_ATOMIC);
+- else
+- ptr = kmalloc(size, GFP_ATOMIC);
++ else {
++ if (req_flags & ZFCP_REQ_NO_QTCB)
++ ptr = kmalloc(size, GFP_ATOMIC);
++ else
++ ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
++ SLAB_ATOMIC);
++ }
+
+- if (unlikely(NULL == ptr))
++ if (unlikely(!ptr))
+ goto out;
+
+ memset(ptr, 0, size);
+@@ -115,9 +120,8 @@ zfcp_fsf_req_alloc(mempool_t *pool, int
+ if (req_flags & ZFCP_REQ_NO_QTCB) {
+ fsf_req = (struct zfcp_fsf_req *) ptr;
+ } else {
+- fsf_req = &((struct zfcp_fsf_req_pool_element *) ptr)->fsf_req;
+- fsf_req->qtcb =
+- &((struct zfcp_fsf_req_pool_element *) ptr)->qtcb;
++ fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req;
++ fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb;
+ }
+
+ fsf_req->pool = pool;
+@@ -139,10 +143,17 @@ zfcp_fsf_req_alloc(mempool_t *pool, int
+ void
+ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
+ {
+- if (likely(fsf_req->pool != NULL))
++ if (likely(fsf_req->pool)) {
+ mempool_free(fsf_req, fsf_req->pool);
+- else
+- kfree(fsf_req);
++ return;
++ }
++
++ if (fsf_req->qtcb) {
++ kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req);
++ return;
++ }
++
++ kfree(fsf_req);
+ }
+
+ /**
+@@ -214,8 +225,10 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re
+ */
+ zfcp_fsf_status_read_handler(fsf_req);
+ goto out;
+- } else
++ } else {
++ del_timer(&fsf_req->timer);
+ zfcp_fsf_protstatus_eval(fsf_req);
++ }
+
+ /*
+ * fsf_req may be deleted due to waking up functions, so
+@@ -774,8 +787,7 @@ zfcp_fsf_status_read(struct zfcp_adapter
+ sbale->addr = (void *) status_buffer;
+ sbale->length = sizeof(struct fsf_status_read_buffer);
+
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(fsf_req, NULL);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+ ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status "
+ "environment.\n");
+@@ -1101,8 +1113,8 @@ zfcp_fsf_abort_fcp_command(unsigned long
+ struct zfcp_unit *unit, int req_flags)
+ {
+ volatile struct qdio_buffer_element *sbale;
+- unsigned long lock_flags;
+ struct zfcp_fsf_req *fsf_req = NULL;
++ unsigned long lock_flags;
+ int retval = 0;
+
+ /* setup new FSF request */
+@@ -1132,12 +1144,9 @@ zfcp_fsf_abort_fcp_command(unsigned long
+ /* set handle of request which should be aborted */
+ fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
+
+- /* start QDIO request for this FSF request */
+-
+- zfcp_fsf_start_scsi_er_timer(adapter);
+- retval = zfcp_fsf_req_send(fsf_req, NULL);
++ zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+- del_timer(&adapter->scsi_er_timer);
+ ZFCP_LOG_INFO("error: Failed to send abort command request "
+ "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
+ zfcp_get_busid_by_adapter(adapter),
+@@ -1173,8 +1182,6 @@ zfcp_fsf_abort_fcp_command_handler(struc
+ unsigned char status_qual =
+ new_fsf_req->qtcb->header.fsf_status_qual.word[0];
+
+- del_timer(&new_fsf_req->adapter->scsi_er_timer);
+-
+ if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+ /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
+ goto skip_fsfstatus;
+@@ -1380,11 +1387,6 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct
+ goto failed_req;
+ }
+
+- if (erp_action != NULL) {
+- erp_action->fsf_req = fsf_req;
+- fsf_req->erp_action = erp_action;
+- }
+-
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ if (zfcp_use_one_sbal(ct->req, ct->req_count,
+ ct->resp, ct->resp_count)){
+@@ -1451,8 +1453,14 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct
+
+ zfcp_san_dbf_event_ct_request(fsf_req);
+
+- /* start QDIO request for this FSF request */
+- ret = zfcp_fsf_req_send(fsf_req, ct->timer);
++ if (erp_action) {
++ erp_action->fsf_req = fsf_req;
++ fsf_req->erp_action = erp_action;
++ zfcp_erp_start_timer(fsf_req);
++ } else
++ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
++
++ ret = zfcp_fsf_req_send(fsf_req);
+ if (ret) {
+ ZFCP_LOG_DEBUG("error: initiation of CT request failed "
+ "(adapter %s, port 0x%016Lx)\n",
+@@ -1749,8 +1757,8 @@ zfcp_fsf_send_els(struct zfcp_send_els *
+
+ zfcp_san_dbf_event_els_request(fsf_req);
+
+- /* start QDIO request for this FSF request */
+- ret = zfcp_fsf_req_send(fsf_req, els->timer);
++ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
++ ret = zfcp_fsf_req_send(fsf_req);
+ if (ret) {
+ ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
+ "(adapter %s, port d_id: 0x%08x)\n",
+@@ -1947,6 +1955,7 @@ int
+ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
+ {
+ volatile struct qdio_buffer_element *sbale;
++ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval = 0;
+
+@@ -1955,7 +1964,7 @@ zfcp_fsf_exchange_config_data(struct zfc
+ FSF_QTCB_EXCHANGE_CONFIG_DATA,
+ ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+- &lock_flags, &(erp_action->fsf_req));
++ &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create exchange configuration "
+ "data request for adapter %s.\n",
+@@ -1963,26 +1972,26 @@ zfcp_fsf_exchange_config_data(struct zfc
+ goto out;
+ }
+
+- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+- erp_action->fsf_req->sbal_curr, 0);
++ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+- erp_action->fsf_req->erp_action = erp_action;
+- erp_action->fsf_req->qtcb->bottom.config.feature_selection =
++ fsf_req->qtcb->bottom.config.feature_selection =
+ FSF_FEATURE_CFDC |
+ FSF_FEATURE_LUN_SHARING |
+ FSF_FEATURE_NOTIFICATION_LOST |
+ FSF_FEATURE_UPDATE_ALERT;
++ fsf_req->erp_action = erp_action;
++ erp_action->fsf_req = fsf_req;
+
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
++ zfcp_erp_start_timer(fsf_req);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO
+ ("error: Could not send exchange configuration data "
+ "command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(erp_action->adapter));
+- zfcp_fsf_req_free(erp_action->fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ erp_action->fsf_req = NULL;
+ goto out;
+ }
+@@ -2212,10 +2221,9 @@ zfcp_fsf_exchange_port_data(struct zfcp_
+ struct fsf_qtcb_bottom_port *data)
+ {
+ volatile struct qdio_buffer_element *sbale;
+- int retval = 0;
+- unsigned long lock_flags;
+ struct zfcp_fsf_req *fsf_req;
+- struct timer_list *timer;
++ unsigned long lock_flags;
++ int retval = 0;
+
+ if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
+ ZFCP_LOG_INFO("error: exchange port data "
+@@ -2248,22 +2256,11 @@ zfcp_fsf_exchange_port_data(struct zfcp_
+ if (erp_action) {
+ erp_action->fsf_req = fsf_req;
+ fsf_req->erp_action = erp_action;
+- timer = &erp_action->timer;
+- } else {
+- timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
+- if (!timer) {
+- write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+- lock_flags);
+- zfcp_fsf_req_free(fsf_req);
+- return -ENOMEM;
+- }
+- init_timer(timer);
+- timer->function = zfcp_fsf_request_timeout_handler;
+- timer->data = (unsigned long) adapter;
+- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
+- }
++ zfcp_erp_start_timer(fsf_req);
++ } else
++ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+
+- retval = zfcp_fsf_req_send(fsf_req, timer);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send an exchange port data "
+ "command on the adapter %s\n",
+@@ -2271,8 +2268,6 @@ zfcp_fsf_exchange_port_data(struct zfcp_
+ zfcp_fsf_req_free(fsf_req);
+ if (erp_action)
+ erp_action->fsf_req = NULL;
+- else
+- kfree(timer);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ return retval;
+@@ -2283,9 +2278,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_
+ if (!erp_action) {
+ wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+- del_timer_sync(timer);
+ zfcp_fsf_req_free(fsf_req);
+- kfree(timer);
+ }
+ return retval;
+ }
+@@ -2367,6 +2360,7 @@ int
+ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
+ {
+ volatile struct qdio_buffer_element *sbale;
++ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval = 0;
+
+@@ -2375,7 +2369,7 @@ zfcp_fsf_open_port(struct zfcp_erp_actio
+ FSF_QTCB_OPEN_PORT_WITH_DID,
+ ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+- &lock_flags, &(erp_action->fsf_req));
++ &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create open port request "
+ "for port 0x%016Lx on adapter %s.\n",
+@@ -2384,24 +2378,24 @@ zfcp_fsf_open_port(struct zfcp_erp_actio
+ goto out;
+ }
+
+- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+- erp_action->fsf_req->sbal_curr, 0);
++ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+- erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
++ fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
+ atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
+- erp_action->fsf_req->data = (unsigned long) erp_action->port;
+- erp_action->fsf_req->erp_action = erp_action;
++ fsf_req->data = (unsigned long) erp_action->port;
++ fsf_req->erp_action = erp_action;
++ erp_action->fsf_req = fsf_req;
+
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
++ zfcp_erp_start_timer(fsf_req);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send open port request for "
+ "port 0x%016Lx on adapter %s.\n",
+ erp_action->port->wwpn,
+ zfcp_get_busid_by_adapter(erp_action->adapter));
+- zfcp_fsf_req_free(erp_action->fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ erp_action->fsf_req = NULL;
+ goto out;
+ }
+@@ -2623,6 +2617,7 @@ int
+ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
+ {
+ volatile struct qdio_buffer_element *sbale;
++ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval = 0;
+
+@@ -2631,7 +2626,7 @@ zfcp_fsf_close_port(struct zfcp_erp_acti
+ FSF_QTCB_CLOSE_PORT,
+ ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+- &lock_flags, &(erp_action->fsf_req));
++ &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create a close port request "
+ "for port 0x%016Lx on adapter %s.\n",
+@@ -2640,25 +2635,25 @@ zfcp_fsf_close_port(struct zfcp_erp_acti
+ goto out;
+ }
+
+- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+- erp_action->fsf_req->sbal_curr, 0);
++ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
+- erp_action->fsf_req->data = (unsigned long) erp_action->port;
+- erp_action->fsf_req->erp_action = erp_action;
+- erp_action->fsf_req->qtcb->header.port_handle =
+- erp_action->port->handle;
+-
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
++ fsf_req->data = (unsigned long) erp_action->port;
++ fsf_req->erp_action = erp_action;
++ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
++ fsf_req->erp_action = erp_action;
++ erp_action->fsf_req = fsf_req;
++
++ zfcp_erp_start_timer(fsf_req);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send a close port request for "
+ "port 0x%016Lx on adapter %s.\n",
+ erp_action->port->wwpn,
+ zfcp_get_busid_by_adapter(erp_action->adapter));
+- zfcp_fsf_req_free(erp_action->fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ erp_action->fsf_req = NULL;
+ goto out;
+ }
+@@ -2755,16 +2750,17 @@ zfcp_fsf_close_port_handler(struct zfcp_
+ int
+ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
+ {
+- int retval = 0;
+- unsigned long lock_flags;
+ volatile struct qdio_buffer_element *sbale;
++ struct zfcp_fsf_req *fsf_req;
++ unsigned long lock_flags;
++ int retval = 0;
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(erp_action->adapter,
+ FSF_QTCB_CLOSE_PHYSICAL_PORT,
+ ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+- &lock_flags, &erp_action->fsf_req);
++ &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create close physical port "
+ "request (adapter %s, port 0x%016Lx)\n",
+@@ -2774,8 +2770,7 @@ zfcp_fsf_close_physical_port(struct zfcp
+ goto out;
+ }
+
+- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+- erp_action->fsf_req->sbal_curr, 0);
++ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+@@ -2783,20 +2778,19 @@ zfcp_fsf_close_physical_port(struct zfcp
+ atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
+ &erp_action->port->status);
+ /* save a pointer to this port */
+- erp_action->fsf_req->data = (unsigned long) erp_action->port;
+- /* port to be closed */
+- erp_action->fsf_req->qtcb->header.port_handle =
+- erp_action->port->handle;
+- erp_action->fsf_req->erp_action = erp_action;
+-
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
++ fsf_req->data = (unsigned long) erp_action->port;
++ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
++ fsf_req->erp_action = erp_action;
++ erp_action->fsf_req = fsf_req;
++
++ zfcp_erp_start_timer(fsf_req);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send close physical port "
+ "request (adapter %s, port 0x%016Lx)\n",
+ zfcp_get_busid_by_adapter(erp_action->adapter),
+ erp_action->port->wwpn);
+- zfcp_fsf_req_free(erp_action->fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ erp_action->fsf_req = NULL;
+ goto out;
+ }
+@@ -2961,6 +2955,7 @@ int
+ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
+ {
+ volatile struct qdio_buffer_element *sbale;
++ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval = 0;
+
+@@ -2969,7 +2964,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio
+ FSF_QTCB_OPEN_LUN,
+ ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+- &lock_flags, &(erp_action->fsf_req));
++ &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create open unit request for "
+ "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
+@@ -2979,24 +2974,22 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio
+ goto out;
+ }
+
+- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+- erp_action->fsf_req->sbal_curr, 0);
++ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+- erp_action->fsf_req->qtcb->header.port_handle =
+- erp_action->port->handle;
+- erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
+- erp_action->unit->fcp_lun;
++ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
++ fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
+ if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE))
+- erp_action->fsf_req->qtcb->bottom.support.option =
++ fsf_req->qtcb->bottom.support.option =
+ FSF_OPEN_LUN_SUPPRESS_BOXING;
+ atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
+- erp_action->fsf_req->data = (unsigned long) erp_action->unit;
+- erp_action->fsf_req->erp_action = erp_action;
++ fsf_req->data = (unsigned long) erp_action->unit;
++ fsf_req->erp_action = erp_action;
++ erp_action->fsf_req = fsf_req;
+
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
++ zfcp_erp_start_timer(fsf_req);
++ retval = zfcp_fsf_req_send(erp_action->fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send an open unit request "
+ "on the adapter %s, port 0x%016Lx for "
+@@ -3004,7 +2997,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio
+ zfcp_get_busid_by_adapter(erp_action->adapter),
+ erp_action->port->wwpn,
+ erp_action->unit->fcp_lun);
+- zfcp_fsf_req_free(erp_action->fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ erp_action->fsf_req = NULL;
+ goto out;
+ }
+@@ -3297,6 +3290,7 @@ int
+ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
+ {
+ volatile struct qdio_buffer_element *sbale;
++ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval = 0;
+
+@@ -3305,7 +3299,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_acti
+ FSF_QTCB_CLOSE_LUN,
+ ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+ erp_action->adapter->pool.fsf_req_erp,
+- &lock_flags, &(erp_action->fsf_req));
++ &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Could not create close unit request for "
+ "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
+@@ -3315,27 +3309,26 @@ zfcp_fsf_close_unit(struct zfcp_erp_acti
+ goto out;
+ }
+
+- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+- erp_action->fsf_req->sbal_curr, 0);
++ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+- erp_action->fsf_req->qtcb->header.port_handle =
+- erp_action->port->handle;
+- erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
++ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
++ fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
+ atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
+- erp_action->fsf_req->data = (unsigned long) erp_action->unit;
+- erp_action->fsf_req->erp_action = erp_action;
++ fsf_req->data = (unsigned long) erp_action->unit;
++ fsf_req->erp_action = erp_action;
++ erp_action->fsf_req = fsf_req;
+
+- /* start QDIO request for this FSF request */
+- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
++ zfcp_erp_start_timer(fsf_req);
++ retval = zfcp_fsf_req_send(erp_action->fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send a close unit request for "
+ "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n",
+ erp_action->unit->fcp_lun,
+ erp_action->port->wwpn,
+ zfcp_get_busid_by_adapter(erp_action->adapter));
+- zfcp_fsf_req_free(erp_action->fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ erp_action->fsf_req = NULL;
+ goto out;
+ }
+@@ -3488,7 +3481,7 @@ int
+ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
+ struct zfcp_unit *unit,
+ struct scsi_cmnd * scsi_cmnd,
+- struct timer_list *timer, int req_flags)
++ int use_timer, int req_flags)
+ {
+ struct zfcp_fsf_req *fsf_req = NULL;
+ struct fcp_cmnd_iu *fcp_cmnd_iu;
+@@ -3516,7 +3509,7 @@ zfcp_fsf_send_fcp_command_task(struct zf
+ fsf_req->unit = unit;
+
+ /* associate FSF request with SCSI request (for look up on abort) */
+- scsi_cmnd->host_scribble = (char *) fsf_req;
++ scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id;
+
+ /* associate SCSI command with FSF request */
+ fsf_req->data = (unsigned long) scsi_cmnd;
+@@ -3629,11 +3622,10 @@ zfcp_fsf_send_fcp_command_task(struct zf
+ ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
+ (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
+
+- /*
+- * start QDIO request for this FSF request
+- * covered by an SBALE)
+- */
+- retval = zfcp_fsf_req_send(fsf_req, timer);
++ if (use_timer)
++ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
++
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (unlikely(retval < 0)) {
+ ZFCP_LOG_INFO("error: Could not send FCP command request "
+ "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
+@@ -3718,11 +3710,9 @@ zfcp_fsf_send_fcp_command_task_managemen
+ fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
+ fcp_cmnd_iu->task_management_flags = tm_flags;
+
+- /* start QDIO request for this FSF request */
+- zfcp_fsf_start_scsi_er_timer(adapter);
+- retval = zfcp_fsf_req_send(fsf_req, NULL);
++ zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval) {
+- del_timer(&adapter->scsi_er_timer);
+ ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
+ "management) on adapter %s, port 0x%016Lx for "
+ "unit LUN 0x%016Lx\n",
+@@ -4226,7 +4216,6 @@ zfcp_fsf_send_fcp_command_task_managemen
+ char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
+ struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data;
+
+- del_timer(&fsf_req->adapter->scsi_er_timer);
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
+ goto skip_fsfstatus;
+@@ -4295,7 +4284,6 @@ zfcp_fsf_control_file(struct zfcp_adapte
+ struct zfcp_fsf_req *fsf_req;
+ struct fsf_qtcb_bottom_support *bottom;
+ volatile struct qdio_buffer_element *sbale;
+- struct timer_list *timer;
+ unsigned long lock_flags;
+ int req_flags = 0;
+ int direction;
+@@ -4327,12 +4315,6 @@ zfcp_fsf_control_file(struct zfcp_adapte
+ goto out;
+ }
+
+- timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
+- if (!timer) {
+- retval = -ENOMEM;
+- goto out;
+- }
+-
+ retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
+ NULL, &lock_flags, &fsf_req);
+ if (retval < 0) {
+@@ -4367,12 +4349,8 @@ zfcp_fsf_control_file(struct zfcp_adapte
+ } else
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+- init_timer(timer);
+- timer->function = zfcp_fsf_request_timeout_handler;
+- timer->data = (unsigned long) adapter;
+- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
+-
+- retval = zfcp_fsf_req_send(fsf_req, timer);
++ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
++ retval = zfcp_fsf_req_send(fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("initiation of cfdc up/download failed"
+ "(adapter %s)\n",
+@@ -4392,15 +4370,12 @@ zfcp_fsf_control_file(struct zfcp_adapte
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+ *fsf_req_ptr = fsf_req;
+- del_timer_sync(timer);
+- goto free_timer;
++ goto out;
+
+ free_fsf_req:
+ zfcp_fsf_req_free(fsf_req);
+ unlock_queue_lock:
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+- free_timer:
+- kfree(timer);
+ out:
+ return retval;
+ }
+@@ -4656,7 +4631,6 @@ zfcp_fsf_req_create(struct zfcp_adapter
+ {
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req = NULL;
+- unsigned long flags;
+ int ret = 0;
+ struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
+
+@@ -4673,12 +4647,13 @@ zfcp_fsf_req_create(struct zfcp_adapter
+ fsf_req->fsf_command = fsf_cmd;
+ INIT_LIST_HEAD(&fsf_req->list);
+
+- /* unique request id */
+- spin_lock_irqsave(&adapter->req_list_lock, flags);
++ /* this is serialized (we are holding req_queue-lock of adapter */
++ if (adapter->req_no == 0)
++ adapter->req_no++;
+ fsf_req->req_id = adapter->req_no++;
+- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+
+- zfcp_fsf_req_qtcb_init(fsf_req);
++ init_timer(&fsf_req->timer);
++ zfcp_fsf_req_qtcb_init(fsf_req);
+
+ /* initialize waitqueue which may be used to wait on
+ this request completion */
+@@ -4748,8 +4723,7 @@ zfcp_fsf_req_create(struct zfcp_adapter
+ * returns: 0 - request transfer succesfully started
+ * !0 - start of request transfer failed
+ */
+-static int
+-zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
++static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
+ {
+ struct zfcp_adapter *adapter;
+ struct zfcp_qdio_queue *req_queue;
+@@ -4777,12 +4751,6 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
+
+ inc_seq_no = (fsf_req->qtcb != NULL);
+
+- /* figure out expiration time of timeout and start timeout */
+- if (unlikely(timer)) {
+- timer->expires += jiffies;
+- add_timer(timer);
+- }
+-
+ ZFCP_LOG_TRACE("request queue of adapter %s: "
+ "next free SBAL is %i, %i free SBALs\n",
+ zfcp_get_busid_by_adapter(adapter),
+@@ -4819,12 +4787,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
+ if (unlikely(retval)) {
+ /* Queues are down..... */
+ retval = -EIO;
+- /*
+- * FIXME(potential race):
+- * timer might be expired (absolutely unlikely)
+- */
+- if (timer)
+- del_timer(timer);
++ del_timer(&fsf_req->timer);
+ spin_lock(&adapter->req_list_lock);
+ zfcp_reqlist_remove(adapter, fsf_req->req_id);
+ spin_unlock(&adapter->req_list_lock);
+diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
+index 1bb5508..452d96f 100644
+--- a/drivers/s390/scsi/zfcp_scsi.c
++++ b/drivers/s390/scsi/zfcp_scsi.c
+@@ -39,11 +39,10 @@ static struct zfcp_unit *zfcp_unit_looku
+
+ static struct device_attribute *zfcp_sysfs_sdev_attrs[];
+
+-struct scsi_transport_template *zfcp_transport_template;
+-
+ struct zfcp_data zfcp_data = {
+ .scsi_host_template = {
+ .name = ZFCP_NAME,
++ .module = THIS_MODULE,
+ .proc_name = "zfcp",
+ .slave_alloc = zfcp_scsi_slave_alloc,
+ .slave_configure = zfcp_scsi_slave_configure,
+@@ -59,6 +58,7 @@ struct zfcp_data zfcp_data = {
+ .cmd_per_lun = 1,
+ .use_clustering = 1,
+ .sdev_attrs = zfcp_sysfs_sdev_attrs,
++ .max_sectors = ZFCP_MAX_SECTORS,
+ },
+ .driver_version = ZFCP_VERSION,
+ };
+@@ -232,7 +232,7 @@ zfcp_scsi_command_fail(struct scsi_cmnd
+ */
+ int
+ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
+- struct scsi_cmnd *scpnt, struct timer_list *timer)
++ struct scsi_cmnd *scpnt, int use_timer)
+ {
+ int tmp;
+ int retval;
+@@ -268,7 +268,7 @@ zfcp_scsi_command_async(struct zfcp_adap
+ goto out;
+ }
+
+- tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, timer,
++ tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
+ ZFCP_REQ_AUTO_CLEANUP);
+
+ if (unlikely(tmp < 0)) {
+@@ -292,21 +292,22 @@ zfcp_scsi_command_sync_handler(struct sc
+ * zfcp_scsi_command_sync - send a SCSI command and wait for completion
+ * @unit: unit where command is sent to
+ * @scpnt: scsi command to be sent
+- * @timer: timer to be started if request is successfully initiated
++ * @use_timer: indicates whether timer should be setup or not
+ * Return: 0
+ *
+ * Errors are indicated in scpnt->result
+ */
+ int
+ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
+- struct timer_list *timer)
++ int use_timer)
+ {
+ int ret;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+
+ scpnt->SCp.ptr = (void *) &wait; /* silent re-use */
+ scpnt->scsi_done = zfcp_scsi_command_sync_handler;
+- ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, timer);
++ ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt,
++ use_timer);
+ if (ret == 0)
+ wait_for_completion(&wait);
+
+@@ -342,7 +343,7 @@ zfcp_scsi_queuecommand(struct scsi_cmnd
+ adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+ unit = (struct zfcp_unit *) scpnt->device->hostdata;
+
+- return zfcp_scsi_command_async(adapter, unit, scpnt, NULL);
++ return zfcp_scsi_command_async(adapter, unit, scpnt, 0);
+ }
+
+ static struct zfcp_unit *
+@@ -379,16 +380,15 @@ zfcp_unit_lookup(struct zfcp_adapter *ad
+ * will handle late commands. (Usually, the normal completion of late
+ * commands is ignored with respect to the running abort operation.)
+ */
+-int
+-zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
++int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+ {
+ struct Scsi_Host *scsi_host;
+ struct zfcp_adapter *adapter;
+ struct zfcp_unit *unit;
+- int retval = SUCCESS;
+- struct zfcp_fsf_req *new_fsf_req = NULL;
+- struct zfcp_fsf_req *old_fsf_req;
++ struct zfcp_fsf_req *fsf_req;
+ unsigned long flags;
++ unsigned long old_req_id;
++ int retval = SUCCESS;
+
+ scsi_host = scpnt->device->host;
+ adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
+@@ -400,55 +400,47 @@ zfcp_scsi_eh_abort_handler(struct scsi_c
+ /* avoid race condition between late normal completion and abort */
+ write_lock_irqsave(&adapter->abort_lock, flags);
+
+- /*
+- * Check whether command has just completed and can not be aborted.
+- * Even if the command has just been completed late, we can access
+- * scpnt since the SCSI stack does not release it at least until
+- * this routine returns. (scpnt is parameter passed to this routine
+- * and must not disappear during abort even on late completion.)
+- */
+- old_fsf_req = (struct zfcp_fsf_req *) scpnt->host_scribble;
+- if (!old_fsf_req) {
++ /* Check whether corresponding fsf_req is still pending */
++ spin_lock(&adapter->req_list_lock);
++ fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
++ scpnt->host_scribble);
++ spin_unlock(&adapter->req_list_lock);
++ if (!fsf_req) {
+ write_unlock_irqrestore(&adapter->abort_lock, flags);
+- zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, NULL);
++ zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0);
+ retval = SUCCESS;
+ goto out;
+ }
+- old_fsf_req->data = 0;
+- old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
++ fsf_req->data = 0;
++ fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
++ old_req_id = fsf_req->req_id;
+
+- /* don't access old_fsf_req after releasing the abort_lock */
++ /* don't access old fsf_req after releasing the abort_lock */
+ write_unlock_irqrestore(&adapter->abort_lock, flags);
+- /* call FSF routine which does the abort */
+- new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req,
+- adapter, unit, 0);
+- if (!new_fsf_req) {
++
++ fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0);
++ if (!fsf_req) {
+ ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n");
+ zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
+- old_fsf_req);
++ old_req_id);
+ retval = FAILED;
+ goto out;
+ }
+
+- /* wait for completion of abort */
+- __wait_event(new_fsf_req->completion_wq,
+- new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
++ __wait_event(fsf_req->completion_wq,
++ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+- /* status should be valid since signals were not permitted */
+- if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
+- zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, new_fsf_req,
+- NULL);
++ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
++ zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0);
+ retval = SUCCESS;
+- } else if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
+- zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, new_fsf_req,
+- NULL);
++ } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
++ zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0);
+ retval = SUCCESS;
+ } else {
+- zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, new_fsf_req,
+- NULL);
++ zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0);
+ retval = FAILED;
+ }
+- zfcp_fsf_req_free(new_fsf_req);
++ zfcp_fsf_req_free(fsf_req);
+ out:
+ return retval;
+ }
+@@ -548,14 +540,11 @@ zfcp_task_management_function(struct zfc
+
+ /**
+ * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
+- *
+- * If ERP is already running it will be stopped.
+ */
+ int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+ {
+ struct zfcp_unit *unit;
+ struct zfcp_adapter *adapter;
+- unsigned long flags;
+
+ unit = (struct zfcp_unit*) scpnt->device->hostdata;
+ adapter = unit->port->adapter;
+@@ -563,22 +552,8 @@ int zfcp_scsi_eh_host_reset_handler(stru
+ ZFCP_LOG_NORMAL("host/bus reset because of problems with "
+ "unit 0x%016Lx\n", unit->fcp_lun);
+
+- write_lock_irqsave(&adapter->erp_lock, flags);
+- if (atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
+- &adapter->status)) {
+- zfcp_erp_modify_adapter_status(adapter,
+- ZFCP_STATUS_COMMON_UNBLOCKED|ZFCP_STATUS_COMMON_OPEN,
+- ZFCP_CLEAR);
+- zfcp_erp_action_dismiss_adapter(adapter);
+- write_unlock_irqrestore(&adapter->erp_lock, flags);
+- zfcp_fsf_req_dismiss_all(adapter);
+- adapter->fsf_req_seq_no = 0;
+- zfcp_erp_adapter_reopen(adapter, 0);
+- } else {
+- write_unlock_irqrestore(&adapter->erp_lock, flags);
+- zfcp_erp_adapter_reopen(adapter, 0);
+- zfcp_erp_wait(adapter);
+- }
++ zfcp_erp_adapter_reopen(adapter, 0);
++ zfcp_erp_wait(adapter);
+
+ return SUCCESS;
+ }
+@@ -607,7 +582,7 @@ zfcp_adapter_scsi_register(struct zfcp_a
+ adapter->scsi_host->max_channel = 0;
+ adapter->scsi_host->unique_id = unique_id++; /* FIXME */
+ adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH;
+- adapter->scsi_host->transportt = zfcp_transport_template;
++ adapter->scsi_host->transportt = zfcp_data.scsi_transport_template;
+
+ /*
+ * save a pointer to our own adapter data structure within
+@@ -648,16 +623,6 @@ zfcp_adapter_scsi_unregister(struct zfcp
+ return;
+ }
+
+-
+-void
+-zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
+-{
+- adapter->scsi_er_timer.function = zfcp_fsf_scsi_er_timeout_handler;
+- adapter->scsi_er_timer.data = (unsigned long) adapter;
+- adapter->scsi_er_timer.expires = jiffies + ZFCP_SCSI_ER_TIMEOUT;
+- add_timer(&adapter->scsi_er_timer);
+-}
+-
+ /*
+ * Support functions for FC transport class
+ */
+diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
+index d1c1e75..1e788e8 100644
+--- a/drivers/s390/sysinfo.c
++++ b/drivers/s390/sysinfo.c
+@@ -11,19 +11,18 @@
+ #include <linux/init.h>
+ #include <asm/ebcdic.h>
+
+-struct sysinfo_1_1_1
+-{
++struct sysinfo_1_1_1 {
+ char reserved_0[32];
+ char manufacturer[16];
+ char type[4];
+ char reserved_1[12];
+- char model[16];
++ char model_capacity[16];
+ char sequence[16];
+ char plant[4];
++ char model[16];
+ };
+
+-struct sysinfo_1_2_1
+-{
++struct sysinfo_1_2_1 {
+ char reserved_0[80];
+ char sequence[16];
+ char plant[4];
+@@ -31,9 +30,12 @@ struct sysinfo_1_2_1
+ unsigned short cpu_address;
+ };
+
+-struct sysinfo_1_2_2
+-{
+- char reserved_0[32];
++struct sysinfo_1_2_2 {
++ char format;
++ char reserved_0[1];
++ unsigned short acc_offset;
++ char reserved_1[24];
++ unsigned int secondary_capability;
+ unsigned int capability;
+ unsigned short cpus_total;
+ unsigned short cpus_configured;
+@@ -42,8 +44,12 @@ struct sysinfo_1_2_2
+ unsigned short adjustment[0];
+ };
+
+-struct sysinfo_2_2_1
+-{
++struct sysinfo_1_2_2_extension {
++ unsigned int alt_capability;
++ unsigned short alt_adjustment[0];
++};
++
++struct sysinfo_2_2_1 {
+ char reserved_0[80];
+ char sequence[16];
+ char plant[4];
+@@ -51,15 +57,11 @@ struct sysinfo_2_2_1
+ unsigned short cpu_address;
+ };
+
+-struct sysinfo_2_2_2
+-{
++struct sysinfo_2_2_2 {
+ char reserved_0[32];
+ unsigned short lpar_number;
+ char reserved_1;
+ unsigned char characteristics;
+- #define LPAR_CHAR_DEDICATED (1 << 7)
+- #define LPAR_CHAR_SHARED (1 << 6)
+- #define LPAR_CHAR_LIMITED (1 << 5)
+ unsigned short cpus_total;
+ unsigned short cpus_configured;
+ unsigned short cpus_standby;
+@@ -71,12 +73,14 @@ struct sysinfo_2_2_2
+ unsigned short cpus_shared;
+ };
+
+-struct sysinfo_3_2_2
+-{
++#define LPAR_CHAR_DEDICATED (1 << 7)
++#define LPAR_CHAR_SHARED (1 << 6)
++#define LPAR_CHAR_LIMITED (1 << 5)
++
++struct sysinfo_3_2_2 {
+ char reserved_0[31];
+ unsigned char count;
+- struct
+- {
++ struct {
+ char reserved_0[4];
+ unsigned short cpus_total;
+ unsigned short cpus_configured;
+@@ -90,136 +94,223 @@ struct sysinfo_3_2_2
+ } vm[8];
+ };
+
+-union s390_sysinfo
++static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
+ {
+- struct sysinfo_1_1_1 sysinfo_1_1_1;
+- struct sysinfo_1_2_1 sysinfo_1_2_1;
+- struct sysinfo_1_2_2 sysinfo_1_2_2;
+- struct sysinfo_2_2_1 sysinfo_2_2_1;
+- struct sysinfo_2_2_2 sysinfo_2_2_2;
+- struct sysinfo_3_2_2 sysinfo_3_2_2;
+-};
+-
+-static inline int stsi (void *sysinfo,
+- int fc, int sel1, int sel2)
+-{
+- int cc, retv;
+-
+-#ifndef CONFIG_64BIT
+- __asm__ __volatile__ ( "lr\t0,%2\n"
+- "\tlr\t1,%3\n"
+- "\tstsi\t0(%4)\n"
+- "0:\tipm\t%0\n"
+- "\tsrl\t%0,28\n"
+- "1:lr\t%1,0\n"
+- ".section .fixup,\"ax\"\n"
+- "2:\tlhi\t%0,3\n"
+- "\tbras\t1,3f\n"
+- "\t.long 1b\n"
+- "3:\tl\t1,0(1)\n"
+- "\tbr\t1\n"
+- ".previous\n"
+- ".section __ex_table,\"a\"\n"
+- "\t.align 4\n"
+- "\t.long 0b,2b\n"
+- ".previous\n"
+- : "=d" (cc), "=d" (retv)
+- : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo)
+- : "cc", "memory", "0", "1" );
+-#else
+- __asm__ __volatile__ ( "lr\t0,%2\n"
+- "lr\t1,%3\n"
+- "\tstsi\t0(%4)\n"
+- "0:\tipm\t%0\n"
+- "\tsrl\t%0,28\n"
+- "1:lr\t%1,0\n"
+- ".section .fixup,\"ax\"\n"
+- "2:\tlhi\t%0,3\n"
+- "\tjg\t1b\n"
+- ".previous\n"
+- ".section __ex_table,\"a\"\n"
+- "\t.align 8\n"
+- "\t.quad 0b,2b\n"
+- ".previous\n"
+- : "=d" (cc), "=d" (retv)
+- : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo)
+- : "cc", "memory", "0", "1" );
+-#endif
+-
+- return cc? -1 : retv;
++ register int r0 asm("0") = (fc << 28) | sel1;
++ register int r1 asm("1") = sel2;
++
++ asm volatile(
++ " stsi 0(%2)\n"
++ "0: jz 2f\n"
++ "1: lhi %0,%3\n"
++ "2:\n"
++ EX_TABLE(0b,1b)
++ : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS)
++ : "cc", "memory" );
++ return r0;
+ }
+
+-static inline int stsi_0 (void)
++static inline int stsi_0(void)
+ {
+ int rc = stsi (NULL, 0, 0, 0);
+- return rc == -1 ? rc : (((unsigned int)rc) >> 28);
++ return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
+ }
+
+-static inline int stsi_1_1_1 (struct sysinfo_1_1_1 *info)
++static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
+ {
+- int rc = stsi (info, 1, 1, 1);
+- if (rc != -1)
+- {
+- EBCASC (info->manufacturer, sizeof(info->manufacturer));
+- EBCASC (info->type, sizeof(info->type));
+- EBCASC (info->model, sizeof(info->model));
+- EBCASC (info->sequence, sizeof(info->sequence));
+- EBCASC (info->plant, sizeof(info->plant));
+- }
+- return rc == -1 ? rc : 0;
++ if (stsi(info, 1, 1, 1) == -ENOSYS)
++ return len;
++
++ EBCASC(info->manufacturer, sizeof(info->manufacturer));
++ EBCASC(info->type, sizeof(info->type));
++ EBCASC(info->model, sizeof(info->model));
++ EBCASC(info->sequence, sizeof(info->sequence));
++ EBCASC(info->plant, sizeof(info->plant));
++ EBCASC(info->model_capacity, sizeof(info->model_capacity));
++ len += sprintf(page + len, "Manufacturer: %-16.16s\n",
++ info->manufacturer);
++ len += sprintf(page + len, "Type: %-4.4s\n",
++ info->type);
++ if (info->model[0] != '\0')
++ /*
++ * Sigh: the model field has been renamed with System z9
++ * to model_capacity and a new model field has been added
++ * after the plant field. To avoid confusing older programs
++ * the "Model:" prints "model_capacity model" or just
++ * "model_capacity" if the model string is empty .
++ */
++ len += sprintf(page + len,
++ "Model: %-16.16s %-16.16s\n",
++ info->model_capacity, info->model);
++ else
++ len += sprintf(page + len, "Model: %-16.16s\n",
++ info->model_capacity);
++ len += sprintf(page + len, "Sequence Code: %-16.16s\n",
++ info->sequence);
++ len += sprintf(page + len, "Plant: %-4.4s\n",
++ info->plant);
++ len += sprintf(page + len, "Model Capacity: %-16.16s\n",
++ info->model_capacity);
++ return len;
+ }
+
+-static inline int stsi_1_2_1 (struct sysinfo_1_2_1 *info)
++#if 0 /* Currently unused */
++static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len)
+ {
+- int rc = stsi (info, 1, 2, 1);
+- if (rc != -1)
+- {
+- EBCASC (info->sequence, sizeof(info->sequence));
+- EBCASC (info->plant, sizeof(info->plant));
+- }
+- return rc == -1 ? rc : 0;
++ if (stsi(info, 1, 2, 1) == -ENOSYS)
++ return len;
++
++ len += sprintf(page + len, "\n");
++ EBCASC(info->sequence, sizeof(info->sequence));
++ EBCASC(info->plant, sizeof(info->plant));
++ len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n",
++ info->sequence);
++ len += sprintf(page + len, "Plant of CPU: %-16.16s\n",
++ info->plant);
++ return len;
+ }
++#endif
+
+-static inline int stsi_1_2_2 (struct sysinfo_1_2_2 *info)
++static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
+ {
+- int rc = stsi (info, 1, 2, 2);
+- return rc == -1 ? rc : 0;
++ struct sysinfo_1_2_2_extension *ext;
++ int i;
++
++ if (stsi(info, 1, 2, 2) == -ENOSYS)
++ return len;
++ ext = (struct sysinfo_1_2_2_extension *)
++ ((unsigned long) info + info->acc_offset);
++
++ len += sprintf(page + len, "\n");
++ len += sprintf(page + len, "CPUs Total: %d\n",
++ info->cpus_total);
++ len += sprintf(page + len, "CPUs Configured: %d\n",
++ info->cpus_configured);
++ len += sprintf(page + len, "CPUs Standby: %d\n",
++ info->cpus_standby);
++ len += sprintf(page + len, "CPUs Reserved: %d\n",
++ info->cpus_reserved);
++
++ if (info->format == 1) {
++ /*
++ * Sigh 2. According to the specification the alternate
++ * capability field is a 32 bit floating point number
++ * if the higher order 8 bits are not zero. Printing
++ * a floating point number in the kernel is a no-no,
++ * always print the number as 32 bit unsigned integer.
++ * The user-space needs to know about the stange
++ * encoding of the alternate cpu capability.
++ */
++ len += sprintf(page + len, "Capability: %u %u\n",
++ info->capability, ext->alt_capability);
++ for (i = 2; i <= info->cpus_total; i++)
++ len += sprintf(page + len,
++ "Adjustment %02d-way: %u %u\n",
++ i, info->adjustment[i-2],
++ ext->alt_adjustment[i-2]);
++
++ } else {
++ len += sprintf(page + len, "Capability: %u\n",
++ info->capability);
++ for (i = 2; i <= info->cpus_total; i++)
++ len += sprintf(page + len,
++ "Adjustment %02d-way: %u\n",
++ i, info->adjustment[i-2]);
++ }
++
++ if (info->secondary_capability != 0)
++ len += sprintf(page + len, "Secondary Capability: %d\n",
++ info->secondary_capability);
++
++ return len;
+ }
+
+-static inline int stsi_2_2_1 (struct sysinfo_2_2_1 *info)
++#if 0 /* Currently unused */
++static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len)
+ {
+- int rc = stsi (info, 2, 2, 1);
+- if (rc != -1)
+- {
+- EBCASC (info->sequence, sizeof(info->sequence));
+- EBCASC (info->plant, sizeof(info->plant));
+- }
+- return rc == -1 ? rc : 0;
++ if (stsi(info, 2, 2, 1) == -ENOSYS)
++ return len;
++
++ len += sprintf(page + len, "\n");
++ EBCASC (info->sequence, sizeof(info->sequence));
++ EBCASC (info->plant, sizeof(info->plant));
++ len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n",
++ info->sequence);
++ len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n",
++ info->plant);
++ return len;
+ }
++#endif
+
+-static inline int stsi_2_2_2 (struct sysinfo_2_2_2 *info)
++static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
+ {
+- int rc = stsi (info, 2, 2, 2);
+- if (rc != -1)
+- {
+- EBCASC (info->name, sizeof(info->name));
+- }
+- return rc == -1 ? rc : 0;
++ if (stsi(info, 2, 2, 2) == -ENOSYS)
++ return len;
++
++ EBCASC (info->name, sizeof(info->name));
++
++ len += sprintf(page + len, "\n");
++ len += sprintf(page + len, "LPAR Number: %d\n",
++ info->lpar_number);
++
++ len += sprintf(page + len, "LPAR Characteristics: ");
++ if (info->characteristics & LPAR_CHAR_DEDICATED)
++ len += sprintf(page + len, "Dedicated ");
++ if (info->characteristics & LPAR_CHAR_SHARED)
++ len += sprintf(page + len, "Shared ");
++ if (info->characteristics & LPAR_CHAR_LIMITED)
++ len += sprintf(page + len, "Limited ");
++ len += sprintf(page + len, "\n");
++
++ len += sprintf(page + len, "LPAR Name: %-8.8s\n",
++ info->name);
++
++ len += sprintf(page + len, "LPAR Adjustment: %d\n",
++ info->caf);
++
++ len += sprintf(page + len, "LPAR CPUs Total: %d\n",
++ info->cpus_total);
++ len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
++ info->cpus_configured);
++ len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
++ info->cpus_standby);
++ len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
++ info->cpus_reserved);
++ len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
++ info->cpus_dedicated);
++ len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
++ info->cpus_shared);
++ return len;
+ }
+
+-static inline int stsi_3_2_2 (struct sysinfo_3_2_2 *info)
++static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
+ {
+- int rc = stsi (info, 3, 2, 2);
+- if (rc != -1)
+- {
+- int i;
+- for (i = 0; i < info->count; i++)
+- {
+- EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
+- EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
+- }
++ int i;
++
++ if (stsi(info, 3, 2, 2) == -ENOSYS)
++ return len;
++ for (i = 0; i < info->count; i++) {
++ EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
++ EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
++ len += sprintf(page + len, "\n");
++ len += sprintf(page + len, "VM%02d Name: %-8.8s\n",
++ i, info->vm[i].name);
++ len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
++ i, info->vm[i].cpi);
++
++ len += sprintf(page + len, "VM%02d Adjustment: %d\n",
++ i, info->vm[i].caf);
++
++ len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
++ i, info->vm[i].cpus_total);
++ len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
++ i, info->vm[i].cpus_configured);
++ len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
++ i, info->vm[i].cpus_standby);
++ len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
++ i, info->vm[i].cpus_reserved);
+ }
+- return rc == -1 ? rc : 0;
++ return len;
+ }
+
+
+@@ -227,118 +318,34 @@ static int proc_read_sysinfo(char *page,
+ off_t off, int count,
+ int *eof, void *data)
+ {
+- unsigned long info_page = get_zeroed_page (GFP_KERNEL);
+- union s390_sysinfo *info = (union s390_sysinfo *) info_page;
+- int len = 0;
+- int level;
+- int i;
++ unsigned long info = get_zeroed_page (GFP_KERNEL);
++ int level, len;
+
+ if (!info)
+ return 0;
+
+- level = stsi_0 ();
+-
+- if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0)
+- {
+- len += sprintf (page+len, "Manufacturer: %-16.16s\n",
+- info->sysinfo_1_1_1.manufacturer);
+- len += sprintf (page+len, "Type: %-4.4s\n",
+- info->sysinfo_1_1_1.type);
+- len += sprintf (page+len, "Model: %-16.16s\n",
+- info->sysinfo_1_1_1.model);
+- len += sprintf (page+len, "Sequence Code: %-16.16s\n",
+- info->sysinfo_1_1_1.sequence);
+- len += sprintf (page+len, "Plant: %-4.4s\n",
+- info->sysinfo_1_1_1.plant);
+- }
+-
+- if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0)
+- {
+- len += sprintf (page+len, "\n");
+- len += sprintf (page+len, "CPUs Total: %d\n",
+- info->sysinfo_1_2_2.cpus_total);
+- len += sprintf (page+len, "CPUs Configured: %d\n",
+- info->sysinfo_1_2_2.cpus_configured);
+- len += sprintf (page+len, "CPUs Standby: %d\n",
+- info->sysinfo_1_2_2.cpus_standby);
+- len += sprintf (page+len, "CPUs Reserved: %d\n",
+- info->sysinfo_1_2_2.cpus_reserved);
+-
+- len += sprintf (page+len, "Capability: %d\n",
+- info->sysinfo_1_2_2.capability);
++ len = 0;
++ level = stsi_0();
++ if (level >= 1)
++ len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
+
+- for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
+- len += sprintf (page+len, "Adjustment %02d-way: %d\n",
+- i, info->sysinfo_1_2_2.adjustment[i-2]);
+- }
++ if (level >= 1)
++ len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
+
+- if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0)
+- {
+- len += sprintf (page+len, "\n");
+- len += sprintf (page+len, "LPAR Number: %d\n",
+- info->sysinfo_2_2_2.lpar_number);
+-
+- len += sprintf (page+len, "LPAR Characteristics: ");
+- if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
+- len += sprintf (page+len, "Dedicated ");
+- if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
+- len += sprintf (page+len, "Shared ");
+- if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
+- len += sprintf (page+len, "Limited ");
+- len += sprintf (page+len, "\n");
+-
+- len += sprintf (page+len, "LPAR Name: %-8.8s\n",
+- info->sysinfo_2_2_2.name);
+-
+- len += sprintf (page+len, "LPAR Adjustment: %d\n",
+- info->sysinfo_2_2_2.caf);
+-
+- len += sprintf (page+len, "LPAR CPUs Total: %d\n",
+- info->sysinfo_2_2_2.cpus_total);
+- len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
+- info->sysinfo_2_2_2.cpus_configured);
+- len += sprintf (page+len, "LPAR CPUs Standby: %d\n",
+- info->sysinfo_2_2_2.cpus_standby);
+- len += sprintf (page+len, "LPAR CPUs Reserved: %d\n",
+- info->sysinfo_2_2_2.cpus_reserved);
+- len += sprintf (page+len, "LPAR CPUs Dedicated: %d\n",
+- info->sysinfo_2_2_2.cpus_dedicated);
+- len += sprintf (page+len, "LPAR CPUs Shared: %d\n",
+- info->sysinfo_2_2_2.cpus_shared);
+- }
++ if (level >= 2)
++ len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
+
+- if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0)
+- {
+- for (i = 0; i < info->sysinfo_3_2_2.count; i++)
+- {
+- len += sprintf (page+len, "\n");
+- len += sprintf (page+len, "VM%02d Name: %-8.8s\n",
+- i, info->sysinfo_3_2_2.vm[i].name);
+- len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
+- i, info->sysinfo_3_2_2.vm[i].cpi);
+-
+- len += sprintf (page+len, "VM%02d Adjustment: %d\n",
+- i, info->sysinfo_3_2_2.vm[i].caf);
+-
+- len += sprintf (page+len, "VM%02d CPUs Total: %d\n",
+- i, info->sysinfo_3_2_2.vm[i].cpus_total);
+- len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
+- i, info->sysinfo_3_2_2.vm[i].cpus_configured);
+- len += sprintf (page+len, "VM%02d CPUs Standby: %d\n",
+- i, info->sysinfo_3_2_2.vm[i].cpus_standby);
+- len += sprintf (page+len, "VM%02d CPUs Reserved: %d\n",
+- i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
+- }
+- }
++ if (level >= 3)
++ len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
+
+- free_page (info_page);
++ free_page (info);
+ return len;
+ }
+
+ static __init int create_proc_sysinfo(void)
+ {
+- create_proc_read_entry ("sysinfo", 0444, NULL,
+- proc_read_sysinfo, NULL);
++ create_proc_read_entry("sysinfo", 0444, NULL,
++ proc_read_sysinfo, NULL);
+ return 0;
+ }
+
+diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
+index 4fdb2c9..a54b4ac 100644
+--- a/drivers/sbus/char/aurora.c
++++ b/drivers/sbus/char/aurora.c
+@@ -254,7 +254,7 @@ for(i=0;i<TYPE_1_IRQS;i++)
+ return 0;
+ }
+
+-static irqreturn_t aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs);
++static irqreturn_t aurora_interrupt(int irq, void * dev_id);
+
+ /* Main probing routine, also sets irq. */
+ static int aurora_probe(void)
+@@ -689,7 +689,7 @@ static void aurora_check_modem(struct Au
+ }
+
+ /* The main interrupt processing routine */
+-static irqreturn_t aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++static irqreturn_t aurora_interrupt(int irq, void * dev_id)
+ {
+ unsigned char status;
+ unsigned char ack,chip/*,chip_id*/;
+@@ -2187,7 +2187,7 @@ static void do_softint(void *private_)
+ #endif
+ }
+
+-static struct tty_operations aurora_ops = {
++static const struct tty_operations aurora_ops = {
+ .open = aurora_open,
+ .close = aurora_close,
+ .write = aurora_write,
+diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
+index 1cc706e..a54e414 100644
+--- a/drivers/sbus/char/bbc_envctrl.c
++++ b/drivers/sbus/char/bbc_envctrl.c
+@@ -4,14 +4,9 @@
+ * Copyright (C) 2001 David S. Miller (davem at redhat.com)
+ */
+
+-#define __KERNEL_SYSCALLS__
+-static int errno;
+-
+-#include <linux/kernel.h>
+ #include <linux/kthread.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+ #include <linux/delay.h>
++#include <linux/kmod.h>
+ #include <asm/oplib.h>
+ #include <asm/ebus.h>
+
+@@ -200,7 +195,7 @@ static void do_envctrl_shutdown(struct b
+ printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
+
+ shutting_down = 1;
+- if (execve("/sbin/shutdown", argv, envp) < 0)
++ if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+ printk(KERN_CRIT "envctrl: shutdown execution failed\n");
+ }
+
+diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
+index 7186235..22631f8 100644
+--- a/drivers/sbus/char/bbc_i2c.c
++++ b/drivers/sbus/char/bbc_i2c.c
+@@ -331,7 +331,7 @@ EXPORT_SYMBOL(bbc_i2c_readb);
+ EXPORT_SYMBOL(bbc_i2c_write_buf);
+ EXPORT_SYMBOL(bbc_i2c_read_buf);
+
+-static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
+ {
+ struct bbc_i2c_bus *bp = dev_id;
+
+diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
+index 836a58b..f5803ec 100644
+--- a/drivers/sbus/char/cpwatchdog.c
++++ b/drivers/sbus/char/cpwatchdog.c
+@@ -10,8 +10,6 @@
+ * timer interrupts. We use a timer to periodically
+ * reset 'stopped' watchdogs on affected platforms.
+ *
+- * TODO: DevFS support (/dev/watchdogs/0 ... /dev/watchdogs/2)
+- *
+ * Copyright (c) 2000 Eric Brower (ebrower at usa.net)
+ */
+
+@@ -187,7 +185,7 @@ MODULE_SUPPORTED_DEVICE
+ #ifdef WD_DEBUG
+ static void wd_dumpregs(void);
+ #endif
+-static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t wd_interrupt(int irq, void *dev_id);
+ static void wd_toggleintr(struct wd_timer* pTimer, int enable);
+ static void wd_pingtimer(struct wd_timer* pTimer);
+ static void wd_starttimer(struct wd_timer* pTimer);
+@@ -446,7 +444,7 @@ static ssize_t wd_read(struct file * fil
+ #endif /* ifdef WD_DEBUG */
+ }
+
+-static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wd_interrupt(int irq, void *dev_id)
+ {
+ /* Only WD0 will interrupt-- others are NMI and we won't
+ * see them here....
+diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
+index 063e676..fff4660 100644
+--- a/drivers/sbus/char/envctrl.c
++++ b/drivers/sbus/char/envctrl.c
+@@ -19,20 +19,13 @@
+ * Daniele Bellucci <bellucda at tiscali.it>
+ */
+
+-#define __KERNEL_SYSCALLS__
+-static int errno;
+-
+ #include <linux/module.h>
+-#include <linux/sched.h>
++#include <linux/init.h>
+ #include <linux/kthread.h>
+-#include <linux/errno.h>
+ #include <linux/delay.h>
+ #include <linux/ioport.h>
+-#include <linux/init.h>
+ #include <linux/miscdevice.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <linux/kernel.h>
++#include <linux/kmod.h>
+
+ #include <asm/ebus.h>
+ #include <asm/uaccess.h>
+@@ -976,13 +969,15 @@ static void envctrl_do_shutdown(void)
+ "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+ char *argv[] = {
+ "/sbin/shutdown", "-h", "now", NULL };
++ int ret;
+
+ if (inprog != 0)
+ return;
+
+ inprog = 1;
+ printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
+- if (0 > execve("/sbin/shutdown", argv, envp)) {
++ ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
++ if (ret < 0) {
+ printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n");
+ inprog = 0; /* unlikely to succeed, but we could try again */
+ }
+diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
+index 2f69876..81ba2d7 100644
+--- a/drivers/sbus/char/openprom.c
++++ b/drivers/sbus/char/openprom.c
+@@ -630,7 +630,7 @@ static int openprom_ioctl(struct inode *
+ case OPROMPATH2NODE:
+ if ((file->f_mode & FMODE_READ) == 0)
+ return -EPERM;
+- return openprom_sunos_ioctl(inode, file, cmd, arg, 0);
++ return openprom_sunos_ioctl(inode, file, cmd, arg, NULL);
+
+ case OPIOCGET:
+ case OPIOCNEXTPROP:
+diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
+index 575b1f7..b30372f 100644
+--- a/drivers/sbus/char/uctrl.c
++++ b/drivers/sbus/char/uctrl.c
+@@ -217,7 +217,7 @@ uctrl_open(struct inode *inode, struct f
+ return 0;
+ }
+
+-static irqreturn_t uctrl_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
+ {
+ struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
+ printk("in uctrl_interrupt\n");
+@@ -400,7 +400,7 @@ static int __init ts102_uctrl_init(void)
+ }
+
+ driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
+- printk("uctrl: 0x%x (irq %d)\n", driver->regs, driver->irq);
++ printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
+ uctrl_get_event_status();
+ uctrl_get_external_status();
+ return 0;
+diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
+index 935952e..98fcbb3 100644
+--- a/drivers/sbus/sbus.c
++++ b/drivers/sbus/sbus.c
+@@ -61,11 +61,11 @@ static void __init fill_sbus_device(stru
+ else
+ sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
+ sdev->ofdev.dev.bus = &sbus_bus_type;
+- strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name);
++ sprintf(sdev->ofdev.dev.bus_id, "sbus[%08x]", dp->node);
+
+ if (of_device_register(&sdev->ofdev) != 0)
+ printk(KERN_DEBUG "sbus: device registration error for %s!\n",
+- sdev->ofdev.dev.bus_id);
++ dp->path_component_name);
+ }
+
+ static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
+diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
+index 5a9475e..5f8c26c 100644
+--- a/drivers/scsi/3w-9xxx.c
++++ b/drivers/scsi/3w-9xxx.c
+@@ -1192,7 +1192,7 @@ out:
+ } /* End twa_initialize_device_extension() */
+
+ /* This function is the interrupt service routine */
+-static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t twa_interrupt(int irq, void *dev_instance)
+ {
+ int request_id, error = 0;
+ u32 status_reg_value;
+@@ -2211,7 +2211,7 @@ static int __init twa_init(void)
+ {
+ printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
+
+- return pci_module_init(&twa_driver);
++ return pci_register_driver(&twa_driver);
+ } /* End twa_init() */
+
+ /* This function is called on driver exit */
+diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
+index f3a5f42..99a259c 100644
+--- a/drivers/scsi/3w-xxxx.c
++++ b/drivers/scsi/3w-xxxx.c
+@@ -2078,8 +2078,7 @@ static int tw_scsi_queue(struct scsi_cmn
+ } /* End tw_scsi_queue() */
+
+ /* This function is the interrupt service routine */
+-static irqreturn_t tw_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t tw_interrupt(int irq, void *dev_instance)
+ {
+ int request_id;
+ u32 status_reg_value;
+@@ -2486,7 +2485,7 @@ static int __init tw_init(void)
+ {
+ printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
+
+- return pci_module_init(&tw_driver);
++ return pci_register_driver(&tw_driver);
+ } /* End tw_init() */
+
+ /* This function is called on driver exit */
+diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
+index 31fe5ea..bbd654a 100644
+--- a/drivers/scsi/3w-xxxx.h
++++ b/drivers/scsi/3w-xxxx.h
+@@ -74,7 +74,7 @@ static char *tw_aen_string[] = {
+ [0x00D] = "ERROR: Logical unit deleted: Unit #",
+ [0x00F] = "WARNING: SMART threshold exceeded: Port #",
+ [0x021] = "WARNING: ATA UDMA downgrade: Port #",
+- [0x021] = "WARNING: ATA UDMA upgrade: Port #",
++ [0x022] = "WARNING: ATA UDMA upgrade: Port #",
+ [0x023] = "WARNING: Sector repair occurred: Port #",
+ [0x024] = "ERROR: SBUF integrity check failure",
+ [0x025] = "ERROR: Lost cached write: Port #",
+diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
+index 657a3ab..562432d 100644
+--- a/drivers/scsi/53c700.c
++++ b/drivers/scsi/53c700.c
+@@ -1462,7 +1462,7 @@ NCR_700_start_command(struct scsi_cmnd *
+ }
+
+ irqreturn_t
+-NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
++NCR_700_intr(int irq, void *dev_id)
+ {
+ struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+ struct NCR_700_Host_Parameters *hostdata =
+@@ -1939,7 +1939,7 @@ NCR_700_abort(struct scsi_cmnd * SCp)
+ STATIC int
+ NCR_700_bus_reset(struct scsi_cmnd * SCp)
+ {
+- DECLARE_COMPLETION(complete);
++ DECLARE_COMPLETION_ONSTACK(complete);
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
+
+diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
+index 97ebe71..f5c3caf 100644
+--- a/drivers/scsi/53c700.h
++++ b/drivers/scsi/53c700.h
+@@ -57,7 +57,7 @@ struct NCR_700_Host_Parameters;
+ struct Scsi_Host *NCR_700_detect(struct scsi_host_template *,
+ struct NCR_700_Host_Parameters *, struct device *);
+ int NCR_700_release(struct Scsi_Host *host);
+-irqreturn_t NCR_700_intr(int, void *, struct pt_regs *);
++irqreturn_t NCR_700_intr(int, void *);
+
+
+ enum NCR_700_Host_State {
+diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
+index acf2927..640536e 100644
+--- a/drivers/scsi/53c7xx.c
++++ b/drivers/scsi/53c7xx.c
+@@ -323,7 +323,7 @@ static int shutdown (struct Scsi_Host *h
+ static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
+ static int disable (struct Scsi_Host *host);
+ static int NCR53c7xx_run_tests (struct Scsi_Host *host);
+-static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id);
+ static void NCR53c7x0_intfly (struct Scsi_Host *host);
+ static int ncr_halt (struct Scsi_Host *host);
+ static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
+@@ -4227,7 +4227,7 @@ restart:
+ }
+
+ /*
+- * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
++ * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id)
+ *
+ * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
+ * the same IRQ line.
+@@ -4241,7 +4241,7 @@ restart:
+ */
+
+ static irqreturn_t
+-NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
++NCR53c7x0_intr (int irq, void *dev_id)
+ {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host; /* Host we are looking at */
+diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
+index 16a12a3..cdd0337 100644
+--- a/drivers/scsi/BusLogic.c
++++ b/drivers/scsi/BusLogic.c
+@@ -662,7 +662,7 @@ static int __init BusLogic_InitializeMul
+ particular standard ISA I/O Address need not be probed.
+ */
+ PrimaryProbeInfo->IO_Address = 0;
+- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
++ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
+ struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter;
+ struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation;
+ enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest;
+@@ -762,7 +762,7 @@ static int __init BusLogic_InitializeMul
+ PrimaryProbeInfo->Bus = Bus;
+ PrimaryProbeInfo->Device = Device;
+ PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
+- PrimaryProbeInfo->PCI_Device = PCI_Device;
++ PrimaryProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
+ PCIMultiMasterCount++;
+ } else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) {
+ struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+@@ -773,7 +773,7 @@ static int __init BusLogic_InitializeMul
+ ProbeInfo->Bus = Bus;
+ ProbeInfo->Device = Device;
+ ProbeInfo->IRQ_Channel = IRQ_Channel;
+- ProbeInfo->PCI_Device = PCI_Device;
++ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
+ NonPrimaryPCIMultiMasterCount++;
+ PCIMultiMasterCount++;
+ } else
+@@ -823,7 +823,7 @@ static int __init BusLogic_InitializeMul
+ noting the PCI bus location and assigned IRQ Channel.
+ */
+ PCI_Device = NULL;
+- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
++ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
+ unsigned char Bus;
+ unsigned char Device;
+ unsigned int IRQ_Channel;
+@@ -850,7 +850,7 @@ static int __init BusLogic_InitializeMul
+ ProbeInfo->Bus = Bus;
+ ProbeInfo->Device = Device;
+ ProbeInfo->IRQ_Channel = IRQ_Channel;
+- ProbeInfo->PCI_Device = PCI_Device;
++ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
+ break;
+ }
+ }
+@@ -874,7 +874,7 @@ static int __init BusLogic_InitializeFla
+ /*
+ Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
+ */
+- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
++ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
+ unsigned char Bus;
+ unsigned char Device;
+ unsigned int IRQ_Channel;
+@@ -923,7 +923,7 @@ static int __init BusLogic_InitializeFla
+ ProbeInfo->Bus = Bus;
+ ProbeInfo->Device = Device;
+ ProbeInfo->IRQ_Channel = IRQ_Channel;
+- ProbeInfo->PCI_Device = PCI_Device;
++ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
+ FlashPointCount++;
+ } else
+ BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL);
+@@ -1890,6 +1890,7 @@ static void BusLogic_ReleaseResources(st
+ */
+ if (HostAdapter->MailboxSpace)
+ pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle);
++ pci_dev_put(HostAdapter->PCI_Device);
+ HostAdapter->MailboxSpace = NULL;
+ HostAdapter->MailboxSpaceHandle = 0;
+ HostAdapter->MailboxSize = 0;
+@@ -2176,6 +2177,7 @@ static int __init BusLogic_init(void)
+ {
+ int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
+ struct BusLogic_HostAdapter *PrototypeHostAdapter;
++ int ret = 0;
+
+ #ifdef MODULE
+ if (BusLogic)
+@@ -2282,25 +2284,49 @@ static int __init BusLogic_init(void)
+ perform Target Device Inquiry.
+ */
+ if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
+- BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) {
++ BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
++ BusLogic_AcquireResources(HostAdapter) &&
++ BusLogic_CreateInitialCCBs(HostAdapter) &&
++ BusLogic_InitializeHostAdapter(HostAdapter) &&
++ BusLogic_TargetDeviceInquiry(HostAdapter)) {
+ /*
+ Initialization has been completed successfully. Release and
+ re-register usage of the I/O Address range so that the Model
+ Name of the Host Adapter will appear, and initialize the SCSI
+ Host structure.
+ */
+- release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
+- if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) {
+- printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address);
++ release_region(HostAdapter->IO_Address,
++ HostAdapter->AddressCount);
++ if (!request_region(HostAdapter->IO_Address,
++ HostAdapter->AddressCount,
++ HostAdapter->FullModelName)) {
++ printk(KERN_WARNING
++ "BusLogic: Release and re-register of "
++ "port 0x%04lx failed \n",
++ (unsigned long)HostAdapter->IO_Address);
+ BusLogic_DestroyCCBs(HostAdapter);
+ BusLogic_ReleaseResources(HostAdapter);
+ list_del(&HostAdapter->host_list);
+ scsi_host_put(Host);
++ ret = -ENOMEM;
+ } else {
+- BusLogic_InitializeHostStructure(HostAdapter, Host);
+- scsi_add_host(Host, HostAdapter->PCI_Device ? &HostAdapter->PCI_Device->dev : NULL);
+- scsi_scan_host(Host);
+- BusLogicHostAdapterCount++;
++ BusLogic_InitializeHostStructure(HostAdapter,
++ Host);
++ if (scsi_add_host(Host, HostAdapter->PCI_Device
++ ? &HostAdapter->PCI_Device->dev
++ : NULL)) {
++ printk(KERN_WARNING
++ "BusLogic: scsi_add_host()"
++ "failed!\n");
++ BusLogic_DestroyCCBs(HostAdapter);
++ BusLogic_ReleaseResources(HostAdapter);
++ list_del(&HostAdapter->host_list);
++ scsi_host_put(Host);
++ ret = -ENODEV;
++ } else {
++ scsi_scan_host(Host);
++ BusLogicHostAdapterCount++;
++ }
+ }
+ } else {
+ /*
+@@ -2315,12 +2341,13 @@ static int __init BusLogic_init(void)
+ BusLogic_ReleaseResources(HostAdapter);
+ list_del(&HostAdapter->host_list);
+ scsi_host_put(Host);
++ ret = -ENODEV;
+ }
+ }
+ kfree(PrototypeHostAdapter);
+ kfree(BusLogic_ProbeInfoList);
+ BusLogic_ProbeInfoList = NULL;
+- return 0;
++ return ret;
+ }
+
+
+@@ -2626,7 +2653,7 @@ static void BusLogic_ProcessCompletedCCB
+ Adapters.
+ */
+
+-static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier, struct pt_regs *InterruptRegisters)
++static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier)
+ {
+ struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier;
+ unsigned long ProcessorFlags;
+@@ -2954,6 +2981,7 @@ static int BusLogic_QueueCommand(struct
+ }
+
+
++#if 0
+ /*
+ BusLogic_AbortCommand aborts Command if possible.
+ */
+@@ -3024,6 +3052,7 @@ static int BusLogic_AbortCommand(struct
+ return SUCCESS;
+ }
+
++#endif
+ /*
+ BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all
+ currently executing SCSI Commands as having been Reset.
+@@ -3571,5 +3600,16 @@ static void __exit BusLogic_exit(void)
+
+ __setup("BusLogic=", BusLogic_Setup);
+
++static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
++};
++MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl);
++
+ module_init(BusLogic_init);
+ module_exit(BusLogic_exit);
+diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
+index 9792e5a..cca6d45 100644
+--- a/drivers/scsi/BusLogic.h
++++ b/drivers/scsi/BusLogic.h
+@@ -237,10 +237,7 @@ enum BusLogic_BIOS_DiskGeometryTranslati
+ Define a Boolean data type.
+ */
+
+-typedef enum {
+- false,
+- true
+-} PACKED boolean;
++typedef bool boolean;
+
+ /*
+ Define a 10^18 Statistics Byte Counter data type.
+@@ -1350,7 +1347,7 @@ static int BusLogic_BIOSDiskParameters(s
+ static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
+ static int BusLogic_SlaveConfigure(struct scsi_device *);
+ static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *);
+-static irqreturn_t BusLogic_InterruptHandler(int, void *, struct pt_regs *);
++static irqreturn_t BusLogic_InterruptHandler(int, void *);
+ static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset);
+ static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...);
+ static int __init BusLogic_Setup(char *);
+diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
+index 96a81cd..9540eb8 100644
+--- a/drivers/scsi/Kconfig
++++ b/drivers/scsi/Kconfig
+@@ -3,11 +3,13 @@ menu "SCSI device support"
+ config RAID_ATTRS
+ tristate "RAID Transport Class"
+ default n
++ depends on BLOCK
+ ---help---
+ Provides RAID
+
+ config SCSI
+ tristate "SCSI device support"
++ depends on BLOCK
+ ---help---
+ If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+ any other SCSI device under Linux, say Y and make sure that you know
+@@ -27,16 +29,21 @@ config SCSI
+ However, do not compile this as a module if your root file system
+ (the one containing the directory /) is located on a SCSI device.
+
++config SCSI_NETLINK
++ bool
++ default n
++ select NET
++
+ config SCSI_PROC_FS
+ bool "legacy /proc/scsi/ support"
+ depends on SCSI && PROC_FS
+ default y
+ ---help---
+ This option enables support for the various files in
+- /proc/scsi. In Linux 2.6 this has been superceeded by
++ /proc/scsi. In Linux 2.6 this has been superseded by
+ files in sysfs but many legacy applications rely on this.
+
+- If unusure say Y.
++ If unsure say Y.
+
+ comment "SCSI support type (disk, tape, CD-ROM)"
+ depends on SCSI
+@@ -78,7 +85,7 @@ config CHR_DEV_OSST
+ tristate "SCSI OnStream SC-x0 tape support"
+ depends on SCSI
+ ---help---
+- The OnStream SC-x0 SCSI tape drives can not be driven by the
++ The OnStream SC-x0 SCSI tape drives cannot be driven by the
+ standard st driver, but instead need this special osst driver and
+ use the /dev/osstX char device nodes (major 206). Via usb-storage
+ and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
+@@ -209,7 +216,7 @@ config SCSI_LOGGING
+ there should be no noticeable performance impact as long as you have
+ logging turned off.
+
+-menu "SCSI Transport Attributes"
++menu "SCSI Transports"
+ depends on SCSI
+
+ config SCSI_SPI_ATTRS
+@@ -222,6 +229,7 @@ config SCSI_SPI_ATTRS
+ config SCSI_FC_ATTRS
+ tristate "FiberChannel Transport Attributes"
+ depends on SCSI
++ select SCSI_NETLINK
+ help
+ If you wish to export transport-specific information about
+ each attached FiberChannel device to sysfs, say Y.
+@@ -242,6 +250,8 @@ config SCSI_SAS_ATTRS
+ If you wish to export transport-specific information about
+ each attached SAS device to sysfs, say Y.
+
++source "drivers/scsi/libsas/Kconfig"
++
+ endmenu
+
+ menu "SCSI low-level drivers"
+@@ -431,6 +441,7 @@ config SCSI_AIC7XXX_OLD
+ module will be called aic7xxx_old.
+
+ source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
++source "drivers/scsi/aic94xx/Kconfig"
+
+ # All the I2O code and drivers do not seem to be 64bit safe.
+ config SCSI_DPT_I2O
+@@ -469,68 +480,21 @@ config SCSI_IN2000
+ To compile this driver as a module, choose M here: the
+ module will be called in2000.
+
+-source "drivers/scsi/megaraid/Kconfig.megaraid"
+-
+-config SCSI_SATA
+- tristate "Serial ATA (SATA) support"
+- depends on SCSI
+- help
+- This driver family supports Serial ATA host controllers
+- and devices.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_AHCI
+- tristate "AHCI SATA support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for AHCI Serial ATA.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_SVW
+- tristate "ServerWorks Frodo / Apple K2 SATA support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for Broadcom/Serverworks/Apple K2
+- SATA support.
+-
+- If unsure, say N.
+-
+-config SCSI_ATA_PIIX
+- tristate "Intel PIIX/ICH SATA support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for ICH5/6/7/8 Serial ATA.
+- If PATA support was enabled previously, this enables
+- support for select Intel PIIX/ICH PATA host controllers.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_MV
+- tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
+- help
+- This option enables support for the Marvell Serial ATA family.
+- Currently supports 88SX[56]0[48][01] chips.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_NV
+- tristate "NVIDIA SATA support"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
++config SCSI_ARCMSR
++ tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
++ depends on PCI && SCSI
+ help
+- This option enables support for NVIDIA Serial ATA.
++ This driver supports all of ARECA's SATA RAID controller cards.
++ This is an ARECA-maintained driver by Erich Chen.
++ If you have any problems, please mail to: < erich at areca.com.tw >
++ Areca supports Linux RAID config tools.
+
+- If unsure, say N.
++ < http://www.areca.com.tw >
+
+-config SCSI_PDC_ADMA
+- tristate "Pacific Digital ADMA support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for Pacific Digital ADMA controllers
++ To compile this driver as a module, choose M here: the
++ module will be called arcmsr (modprobe arcmsr).
+
+- If unsure, say N.
++source "drivers/scsi/megaraid/Kconfig.megaraid"
+
+ config SCSI_HPTIOP
+ tristate "HighPoint RocketRAID 3xxx Controller support"
+@@ -542,83 +506,6 @@ config SCSI_HPTIOP
+ To compile this driver as a module, choose M here; the module
+ will be called hptiop. If unsure, say N.
+
+-config SCSI_SATA_QSTOR
+- tristate "Pacific Digital SATA QStor support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for Pacific Digital Serial ATA QStor.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_PROMISE
+- tristate "Promise SATA TX2/TX4 support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for Promise Serial ATA TX2/TX4.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_SX4
+- tristate "Promise SATA SX4 support"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
+- help
+- This option enables support for Promise Serial ATA SX4.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_SIL
+- tristate "Silicon Image SATA support"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
+- help
+- This option enables support for Silicon Image Serial ATA.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_SIL24
+- tristate "Silicon Image 3124/3132 SATA support"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
+- help
+- This option enables support for Silicon Image 3124/3132 Serial ATA.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_SIS
+- tristate "SiS 964/180 SATA support"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
+- help
+- This option enables support for SiS Serial ATA 964/180.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_ULI
+- tristate "ULi Electronics SATA support"
+- depends on SCSI_SATA && PCI && EXPERIMENTAL
+- help
+- This option enables support for ULi Electronics SATA.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_VIA
+- tristate "VIA SATA support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for VIA Serial ATA.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_VITESSE
+- tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
+- depends on SCSI_SATA && PCI
+- help
+- This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
+-
+- If unsure, say N.
+-
+-config SCSI_SATA_INTEL_COMBINED
+- bool
+- depends on IDE=y && !BLK_DEV_IDE_SATA && (SCSI_SATA_AHCI || SCSI_ATA_PIIX)
+- default y
+-
+ config SCSI_BUSLOGIC
+ tristate "BusLogic SCSI support"
+ depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
+@@ -1053,6 +940,13 @@ config 53C700_LE_ON_BE
+ depends on SCSI_LASI700
+ default y
+
++config SCSI_STEX
++ tristate "Promise SuperTrak EX Series support"
++ depends on PCI && SCSI
++ ---help---
++ This driver supports Promise SuperTrak EX8350/8300/16350/16300
++ Storage controllers.
++
+ config SCSI_SYM53C8XX_2
+ tristate "SYM53C8XX Version 2 SCSI support"
+ depends on PCI && SCSI
+@@ -1122,7 +1016,7 @@ config SCSI_SYM53C8XX_MMIO
+
+ config SCSI_IPR
+ tristate "IBM Power Linux RAID adapter support"
+- depends on PCI && SCSI
++ depends on PCI && SCSI && ATA
+ select FW_LOADER
+ ---help---
+ This driver supports the IBM Power Linux family RAID adapters.
+@@ -1352,6 +1246,7 @@ config SCSI_QLOGICPTI
+ module will be called qlogicpti.
+
+ source "drivers/scsi/qla2xxx/Kconfig"
++source "drivers/scsi/qla4xxx/Kconfig"
+
+ config SCSI_LPFC
+ tristate "Emulex LightPulse Fibre Channel Support"
+@@ -1368,8 +1263,8 @@ config SCSI_SEAGATE
+ These are 8-bit SCSI controllers; the ST-01 is also supported by
+ this driver. It is explained in section 3.9 of the SCSI-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>. If it
+- doesn't work out of the box, you may have to change some settings in
+- <file:drivers/scsi/seagate.h>.
++ doesn't work out of the box, you may have to change some macros at
++ compiletime, which are described in <file:drivers/scsi/seagate.c>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called seagate.
+diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
+index ebd0cf0..bcca39c 100644
+--- a/drivers/scsi/Makefile
++++ b/drivers/scsi/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_tra
+ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
+ obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
+ obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
++obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
+
+ obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
+ obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
+@@ -59,6 +60,7 @@ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
+ obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o
+ obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o
+ obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o
++obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/
+ obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o
+ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
+ obj-$(CONFIG_SCSI_AHA1542) += aha1542.o
+@@ -67,6 +69,7 @@ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/
+ obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/
+ obj-$(CONFIG_SCSI_AACRAID) += aacraid/
+ obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
++obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
+ obj-$(CONFIG_SCSI_IPS) += ips.o
+ obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
+ obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
+@@ -81,6 +84,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicf
+ obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
+ obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
+ obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
++obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
+ obj-$(CONFIG_SCSI_LPFC) += lpfc/
+ obj-$(CONFIG_SCSI_PAS16) += pas16.o
+ obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
+@@ -122,22 +126,8 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o l
+ obj-$(CONFIG_SCSI_NSP32) += nsp32.o
+ obj-$(CONFIG_SCSI_IPR) += ipr.o
+ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
+-obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o
+-obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
+-obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
+-obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o
+-obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o
+-obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
+-obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o
+-obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o
+-obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o
+-obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o
+-obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o
+-obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o
+-obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o
+-obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o
+-obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o
+ obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
++obj-$(CONFIG_SCSI_STEX) += stex.o
+
+ obj-$(CONFIG_ARM) += arm/
+
+@@ -155,6 +145,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioct
+ scsicam.o scsi_error.o scsi_lib.o \
+ scsi_scan.o scsi_sysfs.o \
+ scsi_devinfo.o
++scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
+ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
+ scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
+
+@@ -166,7 +157,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
+ CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
+ zalon7xx-objs := zalon.o ncr53c8xx.o
+ NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
+-libata-objs := libata-core.o libata-scsi.o libata-bmdma.o libata-eh.o
+ oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
+
+ # Files generated that shall be removed upon make clean
+diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
+index 616810a..a6aa910 100644
+--- a/drivers/scsi/NCR5380.c
++++ b/drivers/scsi/NCR5380.c
+@@ -558,8 +558,7 @@ static int probe_irq __initdata = 0;
+ * used by the IRQ probe code.
+ */
+
+-static irqreturn_t __init probe_intr(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t __init probe_intr(int irq, void *dev_id)
+ {
+ probe_irq = irq;
+ return IRQ_HANDLED;
+@@ -1148,7 +1147,6 @@ static void NCR5380_main(void *p)
+ * NCR5380_intr - generic NCR5380 irq handler
+ * @irq: interrupt number
+ * @dev_id: device info
+- * @regs: registers (unused)
+ *
+ * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+@@ -1157,7 +1155,7 @@ static void NCR5380_main(void *p)
+ * Locks: takes the needed instance locks
+ */
+
+-static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t NCR5380_intr(int irq, void *dev_id)
+ {
+ NCR5380_local_declare();
+ struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
+diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
+index c3462e3..1bc73de 100644
+--- a/drivers/scsi/NCR5380.h
++++ b/drivers/scsi/NCR5380.h
+@@ -296,7 +296,7 @@ static int NCR5380_init(struct Scsi_Host
+ static void NCR5380_exit(struct Scsi_Host *instance);
+ static void NCR5380_information_transfer(struct Scsi_Host *instance);
+ #ifndef DONT_USE_INTR
+-static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t NCR5380_intr(int irq, void *dev_id);
+ #endif
+ static void NCR5380_main(void *ptr);
+ static void NCR5380_print_options(struct Scsi_Host *instance);
+diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
+index bdc6bb2..3c912ee 100644
+--- a/drivers/scsi/NCR53C9x.c
++++ b/drivers/scsi/NCR53C9x.c
+@@ -96,7 +96,7 @@ enum {
+ static struct NCR_ESP *espchain;
+ int nesps = 0, esps_in_use = 0, esps_running = 0;
+
+-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
++irqreturn_t esp_intr(int irq, void *dev_id);
+
+ /* Debugging routines */
+ static struct esp_cmdstrings {
+@@ -3533,7 +3533,7 @@ state_machine:
+ }
+
+ #ifndef CONFIG_SMP
+-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
++irqreturn_t esp_intr(int irq, void *dev_id)
+ {
+ struct NCR_ESP *esp;
+ unsigned long flags;
+@@ -3570,7 +3570,7 @@ repeat:
+ }
+ #else
+ /* For SMP we only service one ESP on the list list at our IRQ level! */
+-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
++irqreturn_t esp_intr(int irq, void *dev_id)
+ {
+ struct NCR_ESP *esp;
+ unsigned long flags;
+diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
+index 481653c..521e3f8 100644
+--- a/drivers/scsi/NCR53C9x.h
++++ b/drivers/scsi/NCR53C9x.h
+@@ -656,7 +656,7 @@ extern struct NCR_ESP *esp_allocate(stru
+ extern void esp_deallocate(struct NCR_ESP *);
+ extern void esp_release(void);
+ extern void esp_initialize(struct NCR_ESP *);
+-extern irqreturn_t esp_intr(int, void *, struct pt_regs *);
++extern irqreturn_t esp_intr(int, void *);
+ extern const char *esp_info(struct Scsi_Host *);
+ extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+ extern int esp_abort(Scsi_Cmnd *);
+diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
+index 8472c53..d461381 100644
+--- a/drivers/scsi/NCR53c406a.c
++++ b/drivers/scsi/NCR53c406a.c
+@@ -168,8 +168,8 @@ enum Phase {
+ };
+
+ /* Static function prototypes */
+-static void NCR53c406a_intr(int, void *, struct pt_regs *);
+-static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *);
++static void NCR53c406a_intr(void *);
++static irqreturn_t do_NCR53c406a_intr(int, void *);
+ static void chip_init(void);
+ static void calc_port_addr(void);
+ #ifndef IRQ_LEV
+@@ -685,7 +685,7 @@ static void wait_intr(void)
+ return;
+ }
+
+- NCR53c406a_intr(0, NULL, NULL);
++ NCR53c406a_intr(NULL);
+ }
+ #endif
+
+@@ -761,19 +761,18 @@ static int NCR53c406a_biosparm(struct sc
+ return 0;
+ }
+
+-static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+- NCR53c406a_intr(0, dev_id, regs);
++ NCR53c406a_intr(dev_id);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+-static void NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs)
++static void NCR53c406a_intr(void *dev_id)
+ {
+ DEB(unsigned char fifo_size;
+ )
+diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
+index d05681f..9859cd1 100644
+--- a/drivers/scsi/NCR_D700.c
++++ b/drivers/scsi/NCR_D700.c
+@@ -226,14 +226,14 @@ NCR_D700_probe_one(struct NCR_D700_priva
+ }
+
+ static int
+-NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
++NCR_D700_intr(int irq, void *data)
+ {
+ struct NCR_D700_private *p = (struct NCR_D700_private *)data;
+ int i, found = 0;
+
+ for (i = 0; i < 2; i++)
+ if (p->hosts[i] &&
+- NCR_700_intr(irq, p->hosts[i], regs) == IRQ_HANDLED)
++ NCR_700_intr(irq, p->hosts[i]) == IRQ_HANDLED)
+ found++;
+
+ return found ? IRQ_HANDLED : IRQ_NONE;
+diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
+index c39ffbb..778844c 100644
+--- a/drivers/scsi/NCR_Q720.c
++++ b/drivers/scsi/NCR_Q720.c
+@@ -54,7 +54,7 @@ static struct scsi_host_template NCR_Q72
+ };
+
+ static irqreturn_t
+-NCR_Q720_intr(int irq, void *data, struct pt_regs * regs)
++NCR_Q720_intr(int irq, void *data)
+ {
+ struct NCR_Q720_private *p = (struct NCR_Q720_private *)data;
+ __u8 sir = (readb(p->mem_base + 0x0d) & 0xf0) >> 4;
+@@ -68,7 +68,7 @@ NCR_Q720_intr(int irq, void *data, struc
+
+ while((siop = ffz(sir)) < p->siops) {
+ sir |= 1<<siop;
+- ncr53c8xx_intr(irq, p->hosts[siop], regs);
++ ncr53c8xx_intr(irq, p->hosts[siop]);
+ }
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
+index d7e9fab..2650a5d 100644
+--- a/drivers/scsi/a100u2w.c
++++ b/drivers/scsi/a100u2w.c
+@@ -1013,7 +1013,7 @@ static void inia100SCBPost(BYTE * pHcb,
+ /*
+ * Interrupt handler (main routine of the driver)
+ */
+-static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs)
++static irqreturn_t inia100_intr(int irqno, void *devid)
+ {
+ struct Scsi_Host *host = (struct Scsi_Host *)devid;
+ ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
+@@ -1187,7 +1187,7 @@ static struct pci_driver inia100_pci_dri
+
+ static int __init inia100_init(void)
+ {
+- return pci_module_init(&inia100_pci_driver);
++ return pci_register_driver(&inia100_pci_driver);
+ }
+
+ static void __exit inia100_exit(void)
+diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
+index fddfa2e..f77016d 100644
+--- a/drivers/scsi/a2091.c
++++ b/drivers/scsi/a2091.c
+@@ -24,7 +24,7 @@
+ #define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
+ #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+-static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
++static irqreturn_t a2091_intr (int irq, void *_instance)
+ {
+ unsigned long flags;
+ unsigned int status;
+@@ -40,7 +40,7 @@ static irqreturn_t a2091_intr (int irq,
+ return IRQ_HANDLED;
+ }
+
+-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
++static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
+ {
+ unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+ unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+@@ -115,7 +115,7 @@ static int dma_setup (Scsi_Cmnd *cmd, in
+ return 0;
+ }
+
+-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
++static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
+ {
+ /* disable SCSI interrupts */
+@@ -217,7 +217,7 @@ int __init a2091_detect(struct scsi_host
+ return num_a2091;
+ }
+
+-static int a2091_bus_reset(Scsi_Cmnd *cmd)
++static int a2091_bus_reset(struct scsi_cmnd *cmd)
+ {
+ /* FIXME perform bus-specific reset */
+
+diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
+index 22d6a13..fe809bc 100644
+--- a/drivers/scsi/a2091.h
++++ b/drivers/scsi/a2091.h
+@@ -13,10 +13,6 @@
+
+ int a2091_detect(struct scsi_host_template *);
+ int a2091_release(struct Scsi_Host *);
+-const char *wd33c93_info(void);
+-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int wd33c93_abort(Scsi_Cmnd *);
+-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 2
+diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
+index ae9ab4b..1299bc8 100644
+--- a/drivers/scsi/a3000.c
++++ b/drivers/scsi/a3000.c
+@@ -26,7 +26,7 @@
+
+ static struct Scsi_Host *a3000_host = NULL;
+
+-static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t a3000_intr (int irq, void *dummy)
+ {
+ unsigned long flags;
+ unsigned int status = DMA(a3000_host)->ISTR;
+@@ -44,7 +44,7 @@ static irqreturn_t a3000_intr (int irq,
+ return IRQ_NONE;
+ }
+
+-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
++static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
+ {
+ unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+ unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+@@ -110,8 +110,8 @@ static int dma_setup (Scsi_Cmnd *cmd, in
+ return 0;
+ }
+
+-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+- int status)
++static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
++ int status)
+ {
+ /* disable SCSI interrupts */
+ unsigned short cntr = CNTR_PDMD;
+@@ -205,7 +205,7 @@ fail_register:
+ return 0;
+ }
+
+-static int a3000_bus_reset(Scsi_Cmnd *cmd)
++static int a3000_bus_reset(struct scsi_cmnd *cmd)
+ {
+ /* FIXME perform bus-specific reset */
+
+diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
+index 5535a65..44a4ec7 100644
+--- a/drivers/scsi/a3000.h
++++ b/drivers/scsi/a3000.h
+@@ -13,10 +13,6 @@
+
+ int a3000_detect(struct scsi_host_template *);
+ int a3000_release(struct Scsi_Host *);
+-const char *wd33c93_info(void);
+-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int wd33c93_abort(Scsi_Cmnd *);
+-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 2
+diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
+index 83b5c7d..ac108f9 100644
+--- a/drivers/scsi/aacraid/aachba.c
++++ b/drivers/scsi/aacraid/aachba.c
+@@ -169,13 +169,17 @@ MODULE_PARM_DESC(numacb, "Request a limi
+ int acbsize = -1;
+ module_param(acbsize, int, S_IRUGO|S_IWUSR);
+ MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
++
++int expose_physicals = 0;
++module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. 0=off, 1=on");
+ /**
+ * aac_get_config_status - check the adapter configuration
+ * @common: adapter to query
+ *
+ * Query config status, and commit the configuration if needed.
+ */
+-int aac_get_config_status(struct aac_dev *dev)
++int aac_get_config_status(struct aac_dev *dev, int commit_flag)
+ {
+ int status = 0;
+ struct fib * fibptr;
+@@ -219,7 +223,7 @@ int aac_get_config_status(struct aac_dev
+ aac_fib_complete(fibptr);
+ /* Send a CT_COMMIT_CONFIG to enable discovery of devices */
+ if (status >= 0) {
+- if (commit == 1) {
++ if ((commit == 1) || commit_flag) {
+ struct aac_commit_config * dinfo;
+ aac_fib_init(fibptr);
+ dinfo = (struct aac_commit_config *) fib_data(fibptr);
+@@ -489,6 +493,8 @@ int aac_probe_container(struct aac_dev *
+ unsigned instance;
+
+ fsa_dev_ptr = dev->fsa_dev;
++ if (!fsa_dev_ptr)
++ return -ENOMEM;
+ instance = dev->scsi_host_ptr->unique_id;
+
+ if (!(fibptr = aac_fib_alloc(dev)))
+@@ -782,8 +788,9 @@ int aac_get_adapter_info(struct aac_dev*
+ dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
+ }
+
+- tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+- printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
++ if (!dev->in_reset) {
++ tmp = le32_to_cpu(dev->adapter_info.kernelrev);
++ printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
+ dev->name,
+ dev->id,
+ tmp>>24,
+@@ -792,20 +799,21 @@ int aac_get_adapter_info(struct aac_dev*
+ le32_to_cpu(dev->adapter_info.kernelbuild),
+ (int)sizeof(dev->supplement_adapter_info.BuildDate),
+ dev->supplement_adapter_info.BuildDate);
+- tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+- printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
++ tmp = le32_to_cpu(dev->adapter_info.monitorrev);
++ printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
+ dev->name, dev->id,
+ tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+ le32_to_cpu(dev->adapter_info.monitorbuild));
+- tmp = le32_to_cpu(dev->adapter_info.biosrev);
+- printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
++ tmp = le32_to_cpu(dev->adapter_info.biosrev);
++ printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
+ dev->name, dev->id,
+ tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+ le32_to_cpu(dev->adapter_info.biosbuild));
+- if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+- printk(KERN_INFO "%s%d: serial %x\n",
+- dev->name, dev->id,
+- le32_to_cpu(dev->adapter_info.serial[0]));
++ if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
++ printk(KERN_INFO "%s%d: serial %x\n",
++ dev->name, dev->id,
++ le32_to_cpu(dev->adapter_info.serial[0]));
++ }
+
+ dev->nondasd_support = 0;
+ dev->raid_scsi_mode = 0;
+@@ -1392,6 +1400,7 @@ static int aac_synchronize(struct scsi_c
+ struct scsi_cmnd *cmd;
+ struct scsi_device *sdev = scsicmd->device;
+ int active = 0;
++ struct aac_dev *aac;
+ unsigned long flags;
+
+ /*
+@@ -1413,11 +1422,14 @@ static int aac_synchronize(struct scsi_c
+ if (active)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
++ aac = (struct aac_dev *)scsicmd->device->host->hostdata;
++ if (aac->in_reset)
++ return SCSI_MLQUEUE_HOST_BUSY;
++
+ /*
+ * Allocate and initialize a Fib
+ */
+- if (!(cmd_fibcontext =
+- aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata)))
++ if (!(cmd_fibcontext = aac_fib_alloc(aac)))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ aac_fib_init(cmd_fibcontext);
+@@ -1470,6 +1482,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
+ struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+ struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
+
++ if (fsa_dev_ptr == NULL)
++ return -1;
+ /*
+ * If the bus, id or lun is out of range, return fail
+ * Test does not apply to ID 16, the pseudo id for the controller
+@@ -1499,6 +1513,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
+ case INQUIRY:
+ case READ_CAPACITY:
+ case TEST_UNIT_READY:
++ if (dev->in_reset)
++ return -1;
+ spin_unlock_irq(host->host_lock);
+ aac_probe_container(dev, cid);
+ if ((fsa_dev_ptr[cid].valid & 1) == 0)
+@@ -1523,7 +1539,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
+ return 0;
+ }
+ } else { /* check for physical non-dasd devices */
+- if(dev->nondasd_support == 1){
++ if ((dev->nondasd_support == 1) || expose_physicals) {
++ if (dev->in_reset)
++ return -1;
+ return aac_send_srb_fib(scsicmd);
+ } else {
+ scsicmd->result = DID_NO_CONNECT << 16;
+@@ -1579,6 +1597,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
++ if (dev->in_reset)
++ return -1;
+ setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
+ inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
+ aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
+@@ -1734,6 +1754,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
+ case READ_10:
+ case READ_12:
+ case READ_16:
++ if (dev->in_reset)
++ return -1;
+ /*
+ * Hack to keep track of ordinal number of the device that
+ * corresponds to a container. Needed to convert
+@@ -1752,6 +1774,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
++ if (dev->in_reset)
++ return -1;
+ return aac_write(scsicmd, cid);
+
+ case SYNCHRONIZE_CACHE:
+@@ -1782,6 +1806,8 @@ static int query_disk(struct aac_dev *de
+ struct fsa_dev_info *fsa_dev_ptr;
+
+ fsa_dev_ptr = dev->fsa_dev;
++ if (!fsa_dev_ptr)
++ return -EBUSY;
+ if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
+ return -EFAULT;
+ if (qd.cnum == -1)
+@@ -1820,6 +1846,8 @@ static int force_delete_disk(struct aac_
+ struct fsa_dev_info *fsa_dev_ptr;
+
+ fsa_dev_ptr = dev->fsa_dev;
++ if (!fsa_dev_ptr)
++ return -EBUSY;
+
+ if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
+ return -EFAULT;
+@@ -1843,6 +1871,8 @@ static int delete_disk(struct aac_dev *d
+ struct fsa_dev_info *fsa_dev_ptr;
+
+ fsa_dev_ptr = dev->fsa_dev;
++ if (!fsa_dev_ptr)
++ return -EBUSY;
+
+ if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
+ return -EFAULT;
+diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
+index d0eecd4..eb3ed91 100644
+--- a/drivers/scsi/aacraid/aacraid.h
++++ b/drivers/scsi/aacraid/aacraid.h
+@@ -494,6 +494,7 @@ struct adapter_ops
+ int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
+ int (*adapter_check_health)(struct aac_dev *dev);
+ int (*adapter_send)(struct fib * fib);
++ int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
+ };
+
+ /*
+@@ -682,14 +683,6 @@ struct rx_inbound {
+ __le32 Mailbox[8];
+ };
+
+-#define InboundMailbox0 IndexRegs.Mailbox[0]
+-#define InboundMailbox1 IndexRegs.Mailbox[1]
+-#define InboundMailbox2 IndexRegs.Mailbox[2]
+-#define InboundMailbox3 IndexRegs.Mailbox[3]
+-#define InboundMailbox4 IndexRegs.Mailbox[4]
+-#define InboundMailbox5 IndexRegs.Mailbox[5]
+-#define InboundMailbox6 IndexRegs.Mailbox[6]
+-
+ #define INBOUNDDOORBELL_0 0x00000001
+ #define INBOUNDDOORBELL_1 0x00000002
+ #define INBOUNDDOORBELL_2 0x00000004
+@@ -1010,6 +1003,8 @@ struct aac_dev
+ struct rx_registers __iomem *rx;
+ struct rkt_registers __iomem *rkt;
+ } regs;
++ volatile void __iomem *base;
++ volatile struct rx_inbound __iomem *IndexRegs;
+ u32 OIMR; /* Mask Register Cache */
+ /*
+ * AIF thread states
+@@ -1029,6 +1024,7 @@ struct aac_dev
+ init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
+ u8 raw_io_64;
+ u8 printf_enabled;
++ u8 in_reset;
+ };
+
+ #define aac_adapter_interrupt(dev) \
+@@ -1049,6 +1045,9 @@ struct aac_dev
+ #define aac_adapter_send(fib) \
+ ((fib)->dev)->a_ops.adapter_send(fib)
+
++#define aac_adapter_ioremap(dev, size) \
++ (dev)->a_ops.adapter_ioremap(dev, size)
++
+ #define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001)
+
+ /*
+@@ -1524,7 +1523,6 @@ struct aac_get_name {
+ __le32 count; /* sizeof(((struct aac_get_name_resp *)NULL)->data) */
+ };
+
+-#define CT_OK 218
+ struct aac_get_name_resp {
+ __le32 dummy0;
+ __le32 dummy1;
+@@ -1670,6 +1668,7 @@ extern struct aac_common aac_config;
+ #define RCV_TEMP_READINGS 0x00000025
+ #define GET_COMM_PREFERRED_SETTINGS 0x00000026
+ #define IOP_RESET 0x00001000
++#define IOP_RESET_ALWAYS 0x00001001
+ #define RE_INIT_ADAPTER 0x000000ee
+
+ /*
+@@ -1788,7 +1787,7 @@ void aac_consumer_free(struct aac_dev *
+ int aac_fib_complete(struct fib * context);
+ #define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
+ struct aac_dev *aac_init_adapter(struct aac_dev *dev);
+-int aac_get_config_status(struct aac_dev *dev);
++int aac_get_config_status(struct aac_dev *dev, int commit_flag);
+ int aac_get_containers(struct aac_dev *dev);
+ int aac_scsi_cmd(struct scsi_cmnd *cmd);
+ int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
+@@ -1799,6 +1798,7 @@ int aac_sa_init(struct aac_dev *dev);
+ unsigned int aac_response_normal(struct aac_queue * q);
+ unsigned int aac_command_normal(struct aac_queue * q);
+ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
++int aac_check_health(struct aac_dev * dev);
+ int aac_command_thread(void *data);
+ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
+ int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size);
+diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
+index 255421d..da1d3a9 100644
+--- a/drivers/scsi/aacraid/commctrl.c
++++ b/drivers/scsi/aacraid/commctrl.c
+@@ -38,7 +38,7 @@
+ #include <linux/completion.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/blkdev.h>
+-#include <linux/delay.h>
++#include <linux/delay.h> /* ssleep prototype */
+ #include <linux/kthread.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
+@@ -140,7 +140,8 @@ cleanup:
+ fibptr->hw_fib_pa = hw_fib_pa;
+ fibptr->hw_fib = hw_fib;
+ }
+- aac_fib_free(fibptr);
++ if (retval != -EINTR)
++ aac_fib_free(fibptr);
+ return retval;
+ }
+
+@@ -297,7 +298,7 @@ return_fib:
+ spin_unlock_irqrestore(&dev->fib_lock, flags);
+ /* If someone killed the AIF aacraid thread, restart it */
+ status = !dev->aif_thread;
+- if (status && dev->queues && dev->fsa_dev) {
++ if (status && !dev->in_reset && dev->queues && dev->fsa_dev) {
+ /* Be paranoid, be very paranoid! */
+ kthread_stop(dev->thread);
+ ssleep(1);
+@@ -621,7 +622,13 @@ static int aac_send_raw_srb(struct aac_d
+
+ actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+ if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+- dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
++ dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
++ "Raw SRB command calculated fibsize=%d "
++ "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
++ "issued fibsize=%d\n",
++ actual_fibsize, user_srbcmd->sg.count,
++ sizeof(struct aac_srb), sizeof(struct sgentry),
++ fibsize));
+ rcode = -EINVAL;
+ goto cleanup;
+ }
+@@ -663,6 +670,10 @@ static int aac_send_raw_srb(struct aac_d
+ psg->count = cpu_to_le32(sg_indx+1);
+ status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
+ }
++ if (status == -EINTR) {
++ rcode = -EINTR;
++ goto cleanup;
++ }
+
+ if (status != 0){
+ dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
+@@ -696,8 +707,10 @@ cleanup:
+ for(i=0; i <= sg_indx; i++){
+ kfree(sg_list[i]);
+ }
+- aac_fib_complete(srbfib);
+- aac_fib_free(srbfib);
++ if (rcode != -EINTR) {
++ aac_fib_complete(srbfib);
++ aac_fib_free(srbfib);
++ }
+
+ return rcode;
+ }
+diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
+index 1cd3584..d5cf8b9 100644
+--- a/drivers/scsi/aacraid/comminit.c
++++ b/drivers/scsi/aacraid/comminit.c
+@@ -180,7 +180,7 @@ int aac_send_shutdown(struct aac_dev * d
+ -2 /* Timeout silently */, 1,
+ NULL, NULL);
+
+- if (status == 0)
++ if (status >= 0)
+ aac_fib_complete(fibctx);
+ aac_fib_free(fibctx);
+ return status;
+@@ -307,17 +307,12 @@ struct aac_dev *aac_init_adapter(struct
+ if (status[1] & AAC_OPT_NEW_COMM)
+ dev->new_comm_interface = dev->a_ops.adapter_send != 0;
+ if (dev->new_comm_interface && (status[2] > dev->base_size)) {
+- iounmap(dev->regs.sa);
++ aac_adapter_ioremap(dev, 0);
+ dev->base_size = status[2];
+- dprintk((KERN_DEBUG "ioremap(%lx,%d)\n",
+- host->base, status[2]));
+- dev->regs.sa = ioremap(host->base, status[2]);
+- if (dev->regs.sa == NULL) {
++ if (aac_adapter_ioremap(dev, status[2])) {
+ /* remap failed, go back ... */
+ dev->new_comm_interface = 0;
+- dev->regs.sa = ioremap(host->base,
+- AAC_MIN_FOOTPRINT_SIZE);
+- if (dev->regs.sa == NULL) {
++ if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) {
+ printk(KERN_WARNING
+ "aacraid: unable to map adapter.\n");
+ return NULL;
+diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
+index 3f27419..19e42ac 100644
+--- a/drivers/scsi/aacraid/commsup.c
++++ b/drivers/scsi/aacraid/commsup.c
+@@ -40,8 +40,11 @@
+ #include <linux/blkdev.h>
+ #include <linux/delay.h>
+ #include <linux/kthread.h>
++#include <linux/interrupt.h>
++#include <scsi/scsi.h>
+ #include <scsi/scsi_host.h>
+ #include <scsi/scsi_device.h>
++#include <scsi/scsi_cmnd.h>
+ #include <asm/semaphore.h>
+
+ #include "aacraid.h"
+@@ -464,6 +467,8 @@ int aac_fib_send(u16 command, struct fib
+ dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
+ dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr));
+
++ if (!dev->queues)
++ return -EBUSY;
+ q = &dev->queues->queue[AdapNormCmdQueue];
+
+ if(wait)
+@@ -527,8 +532,15 @@ int aac_fib_send(u16 command, struct fib
+ }
+ udelay(5);
+ }
+- } else
+- down(&fibptr->event_wait);
++ } else if (down_interruptible(&fibptr->event_wait)) {
++ spin_lock_irqsave(&fibptr->event_lock, flags);
++ if (fibptr->done == 0) {
++ fibptr->done = 2; /* Tell interrupt we aborted */
++ spin_unlock_irqrestore(&fibptr->event_lock, flags);
++ return -EINTR;
++ }
++ spin_unlock_irqrestore(&fibptr->event_lock, flags);
++ }
+ BUG_ON(fibptr->done == 0);
+
+ if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
+@@ -795,7 +807,7 @@ static void aac_handle_aif(struct aac_de
+
+ /* Sniff for container changes */
+
+- if (!dev)
++ if (!dev || !dev->fsa_dev)
+ return;
+ container = (u32)-1;
+
+@@ -1022,13 +1034,7 @@ static void aac_handle_aif(struct aac_de
+ if (device) {
+ switch (device_config_needed) {
+ case DELETE:
+- scsi_remove_device(device);
+- break;
+ case CHANGE:
+- if (!dev->fsa_dev[container].valid) {
+- scsi_remove_device(device);
+- break;
+- }
+ scsi_rescan_device(&device->sdev_gendev);
+
+ default:
+@@ -1045,6 +1051,262 @@ static void aac_handle_aif(struct aac_de
+
+ }
+
++static int _aac_reset_adapter(struct aac_dev *aac)
++{
++ int index, quirks;
++ u32 ret;
++ int retval;
++ struct Scsi_Host *host;
++ struct scsi_device *dev;
++ struct scsi_cmnd *command;
++ struct scsi_cmnd *command_list;
++
++ /*
++ * Assumptions:
++ * - host is locked.
++ * - in_reset is asserted, so no new i/o is getting to the
++ * card.
++ * - The card is dead.
++ */
++ host = aac->scsi_host_ptr;
++ scsi_block_requests(host);
++ aac_adapter_disable_int(aac);
++ spin_unlock_irq(host->host_lock);
++ kthread_stop(aac->thread);
++
++ /*
++ * If a positive health, means in a known DEAD PANIC
++ * state and the adapter could be reset to `try again'.
++ */
++ retval = aac_adapter_check_health(aac);
++ if (retval == 0)
++ retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS,
++ 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
++ if (retval)
++ retval = aac_adapter_sync_cmd(aac, IOP_RESET,
++ 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
++
++ if (retval)
++ goto out;
++ if (ret != 0x00000001) {
++ retval = -ENODEV;
++ goto out;
++ }
++
++ index = aac->cardtype;
++
++ /*
++ * Re-initialize the adapter, first free resources, then carefully
++ * apply the initialization sequence to come back again. Only risk
++ * is a change in Firmware dropping cache, it is assumed the caller
++ * will ensure that i/o is queisced and the card is flushed in that
++ * case.
++ */
++ aac_fib_map_free(aac);
++ aac->hw_fib_va = NULL;
++ aac->hw_fib_pa = 0;
++ pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
++ aac->comm_addr = NULL;
++ aac->comm_phys = 0;
++ kfree(aac->queues);
++ aac->queues = NULL;
++ free_irq(aac->pdev->irq, aac);
++ kfree(aac->fsa_dev);
++ aac->fsa_dev = NULL;
++ if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
++ if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
++ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
++ goto out;
++ } else {
++ if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
++ ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
++ goto out;
++ }
++ if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
++ goto out;
++ if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
++ if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
++ goto out;
++ aac->thread = kthread_run(aac_command_thread, aac, aac->name);
++ if (IS_ERR(aac->thread)) {
++ retval = PTR_ERR(aac->thread);
++ goto out;
++ }
++ (void)aac_get_adapter_info(aac);
++ quirks = aac_get_driver_ident(index)->quirks;
++ if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
++ host->sg_tablesize = 34;
++ host->max_sectors = (host->sg_tablesize * 8) + 112;
++ }
++ if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
++ host->sg_tablesize = 17;
++ host->max_sectors = (host->sg_tablesize * 8) + 112;
++ }
++ aac_get_config_status(aac, 1);
++ aac_get_containers(aac);
++ /*
++ * This is where the assumption that the Adapter is quiesced
++ * is important.
++ */
++ command_list = NULL;
++ __shost_for_each_device(dev, host) {
++ unsigned long flags;
++ spin_lock_irqsave(&dev->list_lock, flags);
++ list_for_each_entry(command, &dev->cmd_list, list)
++ if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
++ command->SCp.buffer = (struct scatterlist *)command_list;
++ command_list = command;
++ }
++ spin_unlock_irqrestore(&dev->list_lock, flags);
++ }
++ while ((command = command_list)) {
++ command_list = (struct scsi_cmnd *)command->SCp.buffer;
++ command->SCp.buffer = NULL;
++ command->result = DID_OK << 16
++ | COMMAND_COMPLETE << 8
++ | SAM_STAT_TASK_SET_FULL;
++ command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
++ command->scsi_done(command);
++ }
++ retval = 0;
++
++out:
++ aac->in_reset = 0;
++ scsi_unblock_requests(host);
++ spin_lock_irq(host->host_lock);
++ return retval;
++}
++
++int aac_check_health(struct aac_dev * aac)
++{
++ int BlinkLED;
++ unsigned long time_now, flagv = 0;
++ struct list_head * entry;
++ struct Scsi_Host * host;
++
++ /* Extending the scope of fib_lock slightly to protect aac->in_reset */
++ if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
++ return 0;
++
++ if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) {
++ spin_unlock_irqrestore(&aac->fib_lock, flagv);
++ return 0; /* OK */
++ }
++
++ aac->in_reset = 1;
++
++ /* Fake up an AIF:
++ * aac_aifcmd.command = AifCmdEventNotify = 1
++ * aac_aifcmd.seqnum = 0xFFFFFFFF
++ * aac_aifcmd.data[0] = AifEnExpEvent = 23
++ * aac_aifcmd.data[1] = AifExeFirmwarePanic = 3
++ * aac.aifcmd.data[2] = AifHighPriority = 3
++ * aac.aifcmd.data[3] = BlinkLED
++ */
++
++ time_now = jiffies/HZ;
++ entry = aac->fib_list.next;
++
++ /*
++ * For each Context that is on the
++ * fibctxList, make a copy of the
++ * fib, and then set the event to wake up the
++ * thread that is waiting for it.
++ */
++ while (entry != &aac->fib_list) {
++ /*
++ * Extract the fibctx
++ */
++ struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next);
++ struct hw_fib * hw_fib;
++ struct fib * fib;
++ /*
++ * Check if the queue is getting
++ * backlogged
++ */
++ if (fibctx->count > 20) {
++ /*
++ * It's *not* jiffies folks,
++ * but jiffies / HZ, so do not
++ * panic ...
++ */
++ u32 time_last = fibctx->jiffies;
++ /*
++ * Has it been > 2 minutes
++ * since the last read off
++ * the queue?
++ */
++ if ((time_now - time_last) > aif_timeout) {
++ entry = entry->next;
++ aac_close_fib_context(aac, fibctx);
++ continue;
++ }
++ }
++ /*
++ * Warning: no sleep allowed while
++ * holding spinlock
++ */
++ hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
++ fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
++ if (fib && hw_fib) {
++ struct aac_aifcmd * aif;
++
++ memset(hw_fib, 0, sizeof(struct hw_fib));
++ memset(fib, 0, sizeof(struct fib));
++ fib->hw_fib = hw_fib;
++ fib->dev = aac;
++ aac_fib_init(fib);
++ fib->type = FSAFS_NTC_FIB_CONTEXT;
++ fib->size = sizeof (struct fib);
++ fib->data = hw_fib->data;
++ aif = (struct aac_aifcmd *)hw_fib->data;
++ aif->command = cpu_to_le32(AifCmdEventNotify);
++ aif->seqnum = cpu_to_le32(0xFFFFFFFF);
++ aif->data[0] = cpu_to_le32(AifEnExpEvent);
++ aif->data[1] = cpu_to_le32(AifExeFirmwarePanic);
++ aif->data[2] = cpu_to_le32(AifHighPriority);
++ aif->data[3] = cpu_to_le32(BlinkLED);
++
++ /*
++ * Put the FIB onto the
++ * fibctx's fibs
++ */
++ list_add_tail(&fib->fiblink, &fibctx->fib_list);
++ fibctx->count++;
++ /*
++ * Set the event to wake up the
++ * thread that will waiting.
++ */
++ up(&fibctx->wait_sem);
++ } else {
++ printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
++ kfree(fib);
++ kfree(hw_fib);
++ }
++ entry = entry->next;
++ }
++
++ spin_unlock_irqrestore(&aac->fib_lock, flagv);
++
++ if (BlinkLED < 0) {
++ printk(KERN_ERR "%s: Host adapter dead %d\n", aac->name, BlinkLED);
++ goto out;
++ }
++
++ printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
++
++ host = aac->scsi_host_ptr;
++ spin_lock_irqsave(host->host_lock, flagv);
++ BlinkLED = _aac_reset_adapter(aac);
++ spin_unlock_irqrestore(host->host_lock, flagv);
++ return BlinkLED;
++
++out:
++ aac->in_reset = 0;
++ return BlinkLED;
++}
++
++
+ /**
+ * aac_command_thread - command processing thread
+ * @dev: Adapter to monitor
+diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
+index b2a5c72..8335f07 100644
+--- a/drivers/scsi/aacraid/dpcsup.c
++++ b/drivers/scsi/aacraid/dpcsup.c
+@@ -124,10 +124,15 @@ unsigned int aac_response_normal(struct
+ } else {
+ unsigned long flagv;
+ spin_lock_irqsave(&fib->event_lock, flagv);
+- fib->done = 1;
++ if (!fib->done)
++ fib->done = 1;
+ up(&fib->event_wait);
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
+ FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
++ if (fib->done == 2) {
++ aac_fib_complete(fib);
++ aac_fib_free(fib);
++ }
+ }
+ consumed++;
+ spin_lock_irqsave(q->lock, flags);
+@@ -316,7 +321,8 @@ unsigned int aac_intr_normal(struct aac_
+ unsigned long flagv;
+ dprintk((KERN_INFO "event_wait up\n"));
+ spin_lock_irqsave(&fib->event_lock, flagv);
+- fib->done = 1;
++ if (!fib->done)
++ fib->done = 1;
+ up(&fib->event_wait);
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
+ FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
+index e42a479..359e7dd 100644
+--- a/drivers/scsi/aacraid/linit.c
++++ b/drivers/scsi/aacraid/linit.c
+@@ -82,6 +82,8 @@ static LIST_HEAD(aac_devices);
+ static int aac_cfg_major = -1;
+ char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
+
++extern int expose_physicals;
++
+ /*
+ * Because of the way Linux names scsi devices, the order in this table has
+ * become important. Check for on-board Raid first, add-in cards second.
+@@ -394,6 +396,7 @@ static int aac_slave_configure(struct sc
+ sdev->skip_ms_page_3f = 1;
+ }
+ if ((sdev->type == TYPE_DISK) &&
++ !expose_physicals &&
+ (sdev_channel(sdev) != CONTAINER_CHANNEL)) {
+ struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+ if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
+@@ -454,17 +457,17 @@ static int aac_eh_reset(struct scsi_cmnd
+ printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
+ AAC_DRIVERNAME);
+ aac = (struct aac_dev *)host->hostdata;
+- if (aac_adapter_check_health(aac)) {
+- printk(KERN_ERR "%s: Host adapter appears dead\n",
+- AAC_DRIVERNAME);
+- return -ENODEV;
+- }
++
++ if ((count = aac_check_health(aac)))
++ return count;
+ /*
+ * Wait for all commands to complete to this specific
+ * target (block maximum 60 seconds).
+ */
+ for (count = 60; count; --count) {
+- int active = 0;
++ int active = aac->in_reset;
++
++ if (active == 0)
+ __shost_for_each_device(dev, host) {
+ spin_lock_irqsave(&dev->list_lock, flags);
+ list_for_each_entry(command, &dev->cmd_list, list) {
+@@ -864,13 +867,6 @@ static int __devinit aac_probe_one(struc
+ * Map in the registers from the adapter.
+ */
+ aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
+- if ((aac->regs.sa = ioremap(
+- (unsigned long)aac->scsi_host_ptr->base, AAC_MIN_FOOTPRINT_SIZE))
+- == NULL) {
+- printk(KERN_WARNING "%s: unable to map adapter.\n",
+- AAC_DRIVERNAME);
+- goto out_free_fibs;
+- }
+ if ((*aac_drivers[index].init)(aac))
+ goto out_unmap;
+
+@@ -928,12 +924,12 @@ static int __devinit aac_probe_one(struc
+ * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
+ * physical channels are address by their actual physical number+1
+ */
+- if (aac->nondasd_support == 1)
++ if ((aac->nondasd_support == 1) || expose_physicals)
+ shost->max_channel = aac->maximum_num_channels;
+ else
+ shost->max_channel = 0;
+
+- aac_get_config_status(aac);
++ aac_get_config_status(aac, 0);
+ aac_get_containers(aac);
+ list_add(&aac->entry, insert);
+
+@@ -969,8 +965,7 @@ static int __devinit aac_probe_one(struc
+ aac_fib_map_free(aac);
+ pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+ kfree(aac->queues);
+- iounmap(aac->regs.sa);
+- out_free_fibs:
++ aac_adapter_ioremap(aac, 0);
+ kfree(aac->fibs);
+ kfree(aac->fsa_dev);
+ out_free_host:
+@@ -1005,7 +1000,7 @@ static void __devexit aac_remove_one(str
+ kfree(aac->queues);
+
+ free_irq(pdev->irq, aac);
+- iounmap(aac->regs.sa);
++ aac_adapter_ioremap(aac, 0);
+
+ kfree(aac->fibs);
+ kfree(aac->fsa_dev);
+@@ -1013,6 +1008,10 @@ static void __devexit aac_remove_one(str
+ list_del(&aac->entry);
+ scsi_host_put(shost);
+ pci_disable_device(pdev);
++ if (list_empty(&aac_devices)) {
++ unregister_chrdev(aac_cfg_major, "aac");
++ aac_cfg_major = -1;
++ }
+ }
+
+ static struct pci_driver aac_pci_driver = {
+diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
+index 458ea89..643f23b 100644
+--- a/drivers/scsi/aacraid/rkt.c
++++ b/drivers/scsi/aacraid/rkt.c
+@@ -28,370 +28,27 @@
+ *
+ */
+
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/types.h>
+-#include <linux/sched.h>
+-#include <linux/pci.h>
+-#include <linux/spinlock.h>
+-#include <linux/slab.h>
+ #include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/completion.h>
+-#include <linux/time.h>
+-#include <linux/interrupt.h>
+-#include <asm/semaphore.h>
+
+ #include <scsi/scsi_host.h>
+
+ #include "aacraid.h"
+
+-static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct aac_dev *dev = dev_id;
+-
+- if (dev->new_comm_interface) {
+- u32 Index = rkt_readl(dev, MUnit.OutboundQueue);
+- if (Index == 0xFFFFFFFFL)
+- Index = rkt_readl(dev, MUnit.OutboundQueue);
+- if (Index != 0xFFFFFFFFL) {
+- do {
+- if (aac_intr_normal(dev, Index)) {
+- rkt_writel(dev, MUnit.OutboundQueue, Index);
+- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
+- }
+- Index = rkt_readl(dev, MUnit.OutboundQueue);
+- } while (Index != 0xFFFFFFFFL);
+- return IRQ_HANDLED;
+- }
+- } else {
+- unsigned long bellbits;
+- u8 intstat;
+- intstat = rkt_readb(dev, MUnit.OISR);
+- /*
+- * Read mask and invert because drawbridge is reversed.
+- * This allows us to only service interrupts that have
+- * been enabled.
+- * Check to see if this is our interrupt. If it isn't just return
+- */
+- if (intstat & ~(dev->OIMR))
+- {
+- bellbits = rkt_readl(dev, OutboundDoorbellReg);
+- if (bellbits & DoorBellPrintfReady) {
+- aac_printf(dev, rkt_readl (dev, IndexRegs.Mailbox[5]));
+- rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+- rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+- }
+- else if (bellbits & DoorBellAdapterNormCmdReady) {
+- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+- aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+-// rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+- }
+- else if (bellbits & DoorBellAdapterNormRespReady) {
+- rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+- aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+- }
+- else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+- }
+- else if (bellbits & DoorBellAdapterNormRespNotFull) {
+- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+- }
+- return IRQ_HANDLED;
+- }
+- }
+- return IRQ_NONE;
+-}
+-
+-/**
+- * aac_rkt_disable_interrupt - Disable interrupts
+- * @dev: Adapter
+- */
+-
+-static void aac_rkt_disable_interrupt(struct aac_dev *dev)
+-{
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
+-}
+-
+ /**
+- * rkt_sync_cmd - send a command and wait
+- * @dev: Adapter
+- * @command: Command to execute
+- * @p1: first parameter
+- * @ret: adapter status
++ * aac_rkt_ioremap
++ * @size: mapping resize request
+ *
+- * This routine will send a synchronous command to the adapter and wait
+- * for its completion.
+ */
+-
+-static int rkt_sync_cmd(struct aac_dev *dev, u32 command,
+- u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
+- u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
++static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
+ {
+- unsigned long start;
+- int ok;
+- /*
+- * Write the command into Mailbox 0
+- */
+- rkt_writel(dev, InboundMailbox0, command);
+- /*
+- * Write the parameters into Mailboxes 1 - 6
+- */
+- rkt_writel(dev, InboundMailbox1, p1);
+- rkt_writel(dev, InboundMailbox2, p2);
+- rkt_writel(dev, InboundMailbox3, p3);
+- rkt_writel(dev, InboundMailbox4, p4);
+- /*
+- * Clear the synch command doorbell to start on a clean slate.
+- */
+- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+- /*
+- * Disable doorbell interrupts
+- */
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
+- /*
+- * Force the completion of the mask register write before issuing
+- * the interrupt.
+- */
+- rkt_readb (dev, MUnit.OIMR);
+- /*
+- * Signal that there is a new synch command
+- */
+- rkt_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
+-
+- ok = 0;
+- start = jiffies;
+-
+- /*
+- * Wait up to 30 seconds
+- */
+- while (time_before(jiffies, start+30*HZ))
+- {
+- udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
+- /*
+- * Mon960 will set doorbell0 bit when it has completed the command.
+- */
+- if (rkt_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+- /*
+- * Clear the doorbell.
+- */
+- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+- ok = 1;
+- break;
+- }
+- /*
+- * Yield the processor in case we are slow
+- */
+- msleep(1);
++ if (!size) {
++ iounmap(dev->regs.rkt);
++ return 0;
+ }
+- if (ok != 1) {
+- /*
+- * Restore interrupt mask even though we timed out
+- */
+- if (dev->new_comm_interface)
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+- else
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+- return -ETIMEDOUT;
+- }
+- /*
+- * Pull the synch status from Mailbox 0.
+- */
+- if (status)
+- *status = rkt_readl(dev, IndexRegs.Mailbox[0]);
+- if (r1)
+- *r1 = rkt_readl(dev, IndexRegs.Mailbox[1]);
+- if (r2)
+- *r2 = rkt_readl(dev, IndexRegs.Mailbox[2]);
+- if (r3)
+- *r3 = rkt_readl(dev, IndexRegs.Mailbox[3]);
+- if (r4)
+- *r4 = rkt_readl(dev, IndexRegs.Mailbox[4]);
+- /*
+- * Clear the synch command doorbell.
+- */
+- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+- /*
+- * Restore interrupt mask
+- */
+- if (dev->new_comm_interface)
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+- else
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+- return 0;
+-
+-}
+-
+-/**
+- * aac_rkt_interrupt_adapter - interrupt adapter
+- * @dev: Adapter
+- *
+- * Send an interrupt to the i960 and breakpoint it.
+- */
+-
+-static void aac_rkt_interrupt_adapter(struct aac_dev *dev)
+-{
+- rkt_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
+- NULL, NULL, NULL, NULL, NULL);
+-}
+-
+-/**
+- * aac_rkt_notify_adapter - send an event to the adapter
+- * @dev: Adapter
+- * @event: Event to send
+- *
+- * Notify the i960 that something it probably cares about has
+- * happened.
+- */
+-
+-static void aac_rkt_notify_adapter(struct aac_dev *dev, u32 event)
+-{
+- switch (event) {
+-
+- case AdapNormCmdQue:
+- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
+- break;
+- case HostNormRespNotFull:
+- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
+- break;
+- case AdapNormRespQue:
+- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
+- break;
+- case HostNormCmdNotFull:
+- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+- break;
+- case HostShutdown:
+-// rkt_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
+-// NULL, NULL, NULL, NULL, NULL);
+- break;
+- case FastIo:
+- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+- break;
+- case AdapPrintfDone:
+- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
+- break;
+- default:
+- BUG();
+- break;
+- }
+-}
+-
+-/**
+- * aac_rkt_start_adapter - activate adapter
+- * @dev: Adapter
+- *
+- * Start up processing on an i960 based AAC adapter
+- */
+-
+-static void aac_rkt_start_adapter(struct aac_dev *dev)
+-{
+- struct aac_init *init;
+-
+- init = dev->init;
+- init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+- // We can only use a 32 bit address here
+- rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
+- 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
+-}
+-
+-/**
+- * aac_rkt_check_health
+- * @dev: device to check if healthy
+- *
+- * Will attempt to determine if the specified adapter is alive and
+- * capable of handling requests, returning 0 if alive.
+- */
+-static int aac_rkt_check_health(struct aac_dev *dev)
+-{
+- u32 status = rkt_readl(dev, MUnit.OMRx[0]);
+-
+- /*
+- * Check to see if the board failed any self tests.
+- */
+- if (status & SELF_TEST_FAILED)
++ dev->base = dev->regs.rkt = ioremap(dev->scsi_host_ptr->base, size);
++ if (dev->base == NULL)
+ return -1;
+- /*
+- * Check to see if the board panic'd.
+- */
+- if (status & KERNEL_PANIC) {
+- char * buffer;
+- struct POSTSTATUS {
+- __le32 Post_Command;
+- __le32 Post_Address;
+- } * post;
+- dma_addr_t paddr, baddr;
+- int ret;
+-
+- if ((status & 0xFF000000L) == 0xBC000000L)
+- return (status >> 16) & 0xFF;
+- buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
+- ret = -2;
+- if (buffer == NULL)
+- return ret;
+- post = pci_alloc_consistent(dev->pdev,
+- sizeof(struct POSTSTATUS), &paddr);
+- if (post == NULL) {
+- pci_free_consistent(dev->pdev, 512, buffer, baddr);
+- return ret;
+- }
+- memset(buffer, 0, 512);
+- post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
+- post->Post_Address = cpu_to_le32(baddr);
+- rkt_writel(dev, MUnit.IMRx[0], paddr);
+- rkt_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0,
+- NULL, NULL, NULL, NULL, NULL);
+- pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
+- post, paddr);
+- if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
+- ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
+- ret <<= 4;
+- ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
+- }
+- pci_free_consistent(dev->pdev, 512, buffer, baddr);
+- return ret;
+- }
+- /*
+- * Wait for the adapter to be up and running.
+- */
+- if (!(status & KERNEL_UP_AND_RUNNING))
+- return -3;
+- /*
+- * Everything is OK
+- */
+- return 0;
+-}
+-
+-/**
+- * aac_rkt_send
+- * @fib: fib to issue
+- *
+- * Will send a fib, returning 0 if successful.
+- */
+-static int aac_rkt_send(struct fib * fib)
+-{
+- u64 addr = fib->hw_fib_pa;
+- struct aac_dev *dev = fib->dev;
+- volatile void __iomem *device = dev->regs.rkt;
+- u32 Index;
+-
+- dprintk((KERN_DEBUG "%p->aac_rkt_send(%p->%llx)\n", dev, fib, addr));
+- Index = rkt_readl(dev, MUnit.InboundQueue);
+- if (Index == 0xFFFFFFFFL)
+- Index = rkt_readl(dev, MUnit.InboundQueue);
+- dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
+- if (Index == 0xFFFFFFFFL)
+- return Index;
+- device += Index;
+- dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
+- (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
+- writel((u32)(addr & 0xffffffff), device);
+- device += sizeof(u32);
+- writel((u32)(addr >> 32), device);
+- device += sizeof(u32);
+- writel(le16_to_cpu(fib->hw_fib->header.Size), device);
+- rkt_writel(dev, MUnit.InboundQueue, Index);
+- dprintk((KERN_DEBUG "aac_rkt_send - return 0\n"));
++ dev->IndexRegs = &dev->regs.rkt->IndexRegs;
+ return 0;
+ }
+
+@@ -406,78 +63,18 @@ static int aac_rkt_send(struct fib * fib
+
+ int aac_rkt_init(struct aac_dev *dev)
+ {
+- unsigned long start;
+- unsigned long status;
+- int instance;
+- const char * name;
+-
+- instance = dev->id;
+- name = dev->name;
++ int retval;
++ extern int _aac_rx_init(struct aac_dev *dev);
++ extern void aac_rx_start_adapter(struct aac_dev *dev);
+
+ /*
+- * Check to see if the board panic'd while booting.
+- */
+- /*
+- * Check to see if the board failed any self tests.
+- */
+- if (rkt_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
+- printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+- goto error_iounmap;
+- }
+- /*
+- * Check to see if the monitor panic'd while booting.
+- */
+- if (rkt_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
+- printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
+- goto error_iounmap;
+- }
+- /*
+- * Check to see if the board panic'd while booting.
+- */
+- if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
+- printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
+- goto error_iounmap;
+- }
+- start = jiffies;
+- /*
+- * Wait for the adapter to be up and running. Wait up to 3 minutes
+- */
+- while (!(rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING))
+- {
+- if(time_after(jiffies, start+startup_timeout*HZ))
+- {
+- status = rkt_readl(dev, MUnit.OMRx[0]);
+- printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
+- dev->name, instance, status);
+- goto error_iounmap;
+- }
+- msleep(1);
+- }
+- if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev)<0)
+- {
+- printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
+- goto error_iounmap;
+- }
+- /*
+ * Fill in the function dispatch table.
+ */
+- dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
+- dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
+- dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
+- dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
+- dev->a_ops.adapter_check_health = aac_rkt_check_health;
+- dev->a_ops.adapter_send = aac_rkt_send;
+-
+- /*
+- * First clear out all interrupts. Then enable the one's that we
+- * can handle.
+- */
+- rkt_writeb(dev, MUnit.OIMR, 0xff);
+- rkt_writel(dev, MUnit.ODR, 0xffffffff);
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
++ dev->a_ops.adapter_ioremap = aac_rkt_ioremap;
+
+- if (aac_init_adapter(dev) == NULL)
+- goto error_irq;
++ retval = _aac_rx_init(dev);
++ if (retval)
++ return retval;
+ if (dev->new_comm_interface) {
+ /*
+ * FIB Setup has already been done, but we can minimize the
+@@ -494,20 +91,11 @@ int aac_rkt_init(struct aac_dev *dev)
+ dev->init->MaxIoCommands = cpu_to_le32(246);
+ dev->scsi_host_ptr->can_queue = 246 - AAC_NUM_MGT_FIB;
+ }
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+ }
+ /*
+ * Tell the adapter that all is configured, and it can start
+ * accepting requests
+ */
+- aac_rkt_start_adapter(dev);
++ aac_rx_start_adapter(dev);
+ return 0;
+-
+-error_irq:
+- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
+- free_irq(dev->scsi_host_ptr->irq, (void *)dev);
+-
+-error_iounmap:
+-
+- return -1;
+ }
+diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
+index 035018d..dcc8b0e 100644
+--- a/drivers/scsi/aacraid/rx.c
++++ b/drivers/scsi/aacraid/rx.c
+@@ -46,11 +46,11 @@
+
+ #include "aacraid.h"
+
+-static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t aac_rx_intr(int irq, void *dev_id)
+ {
+ struct aac_dev *dev = dev_id;
+
+- dprintk((KERN_DEBUG "aac_rx_intr(%d,%p,%p)\n", irq, dev_id, regs));
++ dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id));
+ if (dev->new_comm_interface) {
+ u32 Index = rx_readl(dev, MUnit.OutboundQueue);
+ if (Index == 0xFFFFFFFFL)
+@@ -79,7 +79,7 @@ static irqreturn_t aac_rx_intr(int irq,
+ {
+ bellbits = rx_readl(dev, OutboundDoorbellReg);
+ if (bellbits & DoorBellPrintfReady) {
+- aac_printf(dev, rx_readl (dev, IndexRegs.Mailbox[5]));
++ aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
+ rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+ rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+ }
+@@ -134,14 +134,14 @@ static int rx_sync_cmd(struct aac_dev *d
+ /*
+ * Write the command into Mailbox 0
+ */
+- rx_writel(dev, InboundMailbox0, command);
++ writel(command, &dev->IndexRegs->Mailbox[0]);
+ /*
+ * Write the parameters into Mailboxes 1 - 6
+ */
+- rx_writel(dev, InboundMailbox1, p1);
+- rx_writel(dev, InboundMailbox2, p2);
+- rx_writel(dev, InboundMailbox3, p3);
+- rx_writel(dev, InboundMailbox4, p4);
++ writel(p1, &dev->IndexRegs->Mailbox[1]);
++ writel(p2, &dev->IndexRegs->Mailbox[2]);
++ writel(p3, &dev->IndexRegs->Mailbox[3]);
++ writel(p4, &dev->IndexRegs->Mailbox[4]);
+ /*
+ * Clear the synch command doorbell to start on a clean slate.
+ */
+@@ -199,15 +199,15 @@ static int rx_sync_cmd(struct aac_dev *d
+ * Pull the synch status from Mailbox 0.
+ */
+ if (status)
+- *status = rx_readl(dev, IndexRegs.Mailbox[0]);
++ *status = readl(&dev->IndexRegs->Mailbox[0]);
+ if (r1)
+- *r1 = rx_readl(dev, IndexRegs.Mailbox[1]);
++ *r1 = readl(&dev->IndexRegs->Mailbox[1]);
+ if (r2)
+- *r2 = rx_readl(dev, IndexRegs.Mailbox[2]);
++ *r2 = readl(&dev->IndexRegs->Mailbox[2]);
+ if (r3)
+- *r3 = rx_readl(dev, IndexRegs.Mailbox[3]);
++ *r3 = readl(&dev->IndexRegs->Mailbox[3]);
+ if (r4)
+- *r4 = rx_readl(dev, IndexRegs.Mailbox[4]);
++ *r4 = readl(&dev->IndexRegs->Mailbox[4]);
+ /*
+ * Clear the synch command doorbell.
+ */
+@@ -261,8 +261,6 @@ static void aac_rx_notify_adapter(struct
+ rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+ break;
+ case HostShutdown:
+-// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
+-// NULL, NULL, NULL, NULL, NULL);
+ break;
+ case FastIo:
+ rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+@@ -283,7 +281,7 @@ static void aac_rx_notify_adapter(struct
+ * Start up processing on an i960 based AAC adapter
+ */
+
+-static void aac_rx_start_adapter(struct aac_dev *dev)
++void aac_rx_start_adapter(struct aac_dev *dev)
+ {
+ struct aac_init *init;
+
+@@ -381,7 +379,7 @@ static int aac_rx_send(struct fib * fib)
+ dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
+ if (Index == 0xFFFFFFFFL)
+ return Index;
+- device += Index;
++ device = dev->base + Index;
+ dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
+ (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
+ writel((u32)(addr & 0xffffffff), device);
+@@ -395,6 +393,43 @@ static int aac_rx_send(struct fib * fib)
+ }
+
+ /**
++ * aac_rx_ioremap
++ * @size: mapping resize request
++ *
++ */
++static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
++{
++ if (!size) {
++ iounmap(dev->regs.rx);
++ return 0;
++ }
++ dev->base = dev->regs.rx = ioremap(dev->scsi_host_ptr->base, size);
++ if (dev->base == NULL)
++ return -1;
++ dev->IndexRegs = &dev->regs.rx->IndexRegs;
++ return 0;
++}
++
++static int aac_rx_restart_adapter(struct aac_dev *dev)
++{
++ u32 var;
++
++ printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
++ dev->name, dev->id);
++
++ if (aac_rx_check_health(dev) <= 0)
++ return 1;
++ if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
++ &var, NULL, NULL, NULL, NULL))
++ return 1;
++ if (var != 0x00000001)
++ return 1;
++ if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
++ return 1;
++ return 0;
++}
++
++/**
+ * aac_rx_init - initialize an i960 based AAC card
+ * @dev: device to configure
+ *
+@@ -403,7 +438,7 @@ static int aac_rx_send(struct fib * fib)
+ * to the comm region.
+ */
+
+-int aac_rx_init(struct aac_dev *dev)
++int _aac_rx_init(struct aac_dev *dev)
+ {
+ unsigned long start;
+ unsigned long status;
+@@ -413,27 +448,30 @@ int aac_rx_init(struct aac_dev *dev)
+ instance = dev->id;
+ name = dev->name;
+
++ if (aac_adapter_ioremap(dev, dev->base_size)) {
++ printk(KERN_WARNING "%s: unable to map adapter.\n", name);
++ goto error_iounmap;
++ }
++
+ /*
+ * Check to see if the board panic'd while booting.
+ */
++ status = rx_readl(dev, MUnit.OMRx[0]);
++ if (status & KERNEL_PANIC)
++ if (aac_rx_restart_adapter(dev))
++ goto error_iounmap;
+ /*
+ * Check to see if the board failed any self tests.
+ */
+- if (rx_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
++ status = rx_readl(dev, MUnit.OMRx[0]);
++ if (status & SELF_TEST_FAILED) {
+ printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+ goto error_iounmap;
+ }
+ /*
+- * Check to see if the board panic'd while booting.
+- */
+- if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
+- printk(KERN_ERR "%s%d: adapter kernel panic.\n", dev->name, instance);
+- goto error_iounmap;
+- }
+- /*
+ * Check to see if the monitor panic'd while booting.
+ */
+- if (rx_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
++ if (status & MONITOR_PANIC) {
+ printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
+ goto error_iounmap;
+ }
+@@ -441,12 +479,10 @@ int aac_rx_init(struct aac_dev *dev)
+ /*
+ * Wait for the adapter to be up and running. Wait up to 3 minutes
+ */
+- while ((!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING))
+- || (!(rx_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING)))
++ while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
+ {
+ if(time_after(jiffies, start+startup_timeout*HZ))
+ {
+- status = rx_readl(dev, IndexRegs.Mailbox[7]);
+ printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
+ dev->name, instance, status);
+ goto error_iounmap;
+@@ -481,11 +517,6 @@ int aac_rx_init(struct aac_dev *dev)
+ if (dev->new_comm_interface)
+ rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+
+- /*
+- * Tell the adapter that all is configured, and it can start
+- * accepting requests
+- */
+- aac_rx_start_adapter(dev);
+ return 0;
+
+ error_irq:
+@@ -496,3 +527,23 @@ error_iounmap:
+
+ return -1;
+ }
++
++int aac_rx_init(struct aac_dev *dev)
++{
++ int retval;
++
++ /*
++ * Fill in the function dispatch table.
++ */
++ dev->a_ops.adapter_ioremap = aac_rx_ioremap;
++
++ retval = _aac_rx_init(dev);
++ if (!retval) {
++ /*
++ * Tell the adapter that all is configured, and it can
++ * start accepting requests
++ */
++ aac_rx_start_adapter(dev);
++ }
++ return retval;
++}
+diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
+index cd586cc..511b0a9 100644
+--- a/drivers/scsi/aacraid/sa.c
++++ b/drivers/scsi/aacraid/sa.c
+@@ -46,7 +46,7 @@
+
+ #include "aacraid.h"
+
+-static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t aac_sa_intr(int irq, void *dev_id)
+ {
+ struct aac_dev *dev = dev_id;
+ unsigned short intstat, mask;
+@@ -281,6 +281,21 @@ static int aac_sa_check_health(struct aa
+ }
+
+ /**
++ * aac_sa_ioremap
++ * @size: mapping resize request
++ *
++ */
++static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
++{
++ if (!size) {
++ iounmap(dev->regs.sa);
++ return 0;
++ }
++ dev->base = dev->regs.sa = ioremap(dev->scsi_host_ptr->base, size);
++ return (dev->base == NULL) ? -1 : 0;
++}
++
++/**
+ * aac_sa_init - initialize an ARM based AAC card
+ * @dev: device to configure
+ *
+@@ -299,6 +314,11 @@ int aac_sa_init(struct aac_dev *dev)
+ instance = dev->id;
+ name = dev->name;
+
++ if (aac_sa_ioremap(dev, dev->base_size)) {
++ printk(KERN_WARNING "%s: unable to map adapter.\n", name);
++ goto error_iounmap;
++ }
++
+ /*
+ * Check to see if the board failed any self tests.
+ */
+@@ -341,6 +361,7 @@ int aac_sa_init(struct aac_dev *dev)
+ dev->a_ops.adapter_notify = aac_sa_notify_adapter;
+ dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
+ dev->a_ops.adapter_check_health = aac_sa_check_health;
++ dev->a_ops.adapter_ioremap = aac_sa_ioremap;
+
+ /*
+ * First clear out all interrupts. Then enable the one's that
+diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
+index e32b4ab..2b34435 100644
+--- a/drivers/scsi/advansys.c
++++ b/drivers/scsi/advansys.c
+@@ -888,10 +888,6 @@ typedef unsigned char uchar;
+ #define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
+ #define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
+ #define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
+-#define ASC_PCI_VENDORID 0x10CD
+-#define ASC_PCI_DEVICEID_1200A 0x1100
+-#define ASC_PCI_DEVICEID_1200B 0x1200
+-#define ASC_PCI_DEVICEID_ULTRA 0x1300
+ #define ASC_PCI_REVISION_3150 0x02
+ #define ASC_PCI_REVISION_3050 0x03
+
+@@ -899,6 +895,14 @@ typedef unsigned char uchar;
+ #define ASC_DVCLIB_CALL_FAILED (0)
+ #define ASC_DVCLIB_CALL_ERROR (-1)
+
++#define PCI_VENDOR_ID_ASP 0x10cd
++#define PCI_DEVICE_ID_ASP_1200A 0x1100
++#define PCI_DEVICE_ID_ASP_ABP940 0x1200
++#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
++#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
++#define PCI_DEVICE_ID_38C0800_REV1 0x2500
++#define PCI_DEVICE_ID_38C1600_REV1 0x2700
++
+ /*
+ * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
+ * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
+@@ -1492,8 +1496,6 @@ typedef struct asc_dvc_cfg {
+ #define ASC_INIT_STATE_END_INQUIRY 0x0080
+ #define ASC_INIT_RESET_SCSI_DONE 0x0100
+ #define ASC_INIT_STATE_WITHOUT_EEP 0x8000
+-#define ASC_PCI_DEVICE_ID_REV_A 0x1100
+-#define ASC_PCI_DEVICE_ID_REV_B 0x1200
+ #define ASC_BUG_FIX_IF_NOT_DWB 0x0001
+ #define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
+ #define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+@@ -2100,12 +2102,6 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushor
+ #define ADV_NUM_PAGE_CROSSING \
+ ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+
+-/* a_condor.h */
+-#define ADV_PCI_VENDOR_ID 0x10CD
+-#define ADV_PCI_DEVICE_ID_REV_A 0x2300
+-#define ADV_PCI_DEVID_38C0800_REV1 0x2500
+-#define ADV_PCI_DEVID_38C1600_REV1 0x2700
+-
+ #define ADV_EEP_DVC_CFG_BEGIN (0x00)
+ #define ADV_EEP_DVC_CFG_END (0x15)
+ #define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
+@@ -3569,14 +3565,7 @@ typedef struct scsi_cmnd REQ, *REQP;
+ #define PCI_MAX_SLOT 0x1F
+ #define PCI_MAX_BUS 0xFF
+ #define PCI_IOADDRESS_MASK 0xFFFE
+-#define ASC_PCI_VENDORID 0x10CD
+ #define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
+-#define ASC_PCI_DEVICE_ID_1100 0x1100
+-#define ASC_PCI_DEVICE_ID_1200 0x1200
+-#define ASC_PCI_DEVICE_ID_1300 0x1300
+-#define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */
+-#define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */
+-#define ASC_PCI_DEVICE_ID_2700 0x2700 /* ASC-38C1600 */
+
+ #ifndef ADVANSYS_STATS
+ #define ASC_STATS(shp, counter)
+@@ -3892,7 +3881,7 @@ typedef struct asc_board {
+ /*
+ * The following fields are used only for Wide Boards.
+ */
+- void *ioremap_addr; /* I/O Memory remap address. */
++ void __iomem *ioremap_addr; /* I/O Memory remap address. */
+ ushort ioport; /* I/O Port address. */
+ ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
+ adv_req_t *orig_reqp; /* adv_req_t memory block. */
+@@ -3962,7 +3951,7 @@ typedef struct _PCI_CONFIG_SPACE_
+
+ /* Number of boards detected in system. */
+ STATIC int asc_board_count = 0;
+-STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
++STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
+
+ /* Overrun buffer used by all narrow boards. */
+ STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
+@@ -4010,7 +3999,7 @@ STATIC PortAddr _asc_def_iop_base[];
+ * advansys.h contains function prototypes for functions global to Linux.
+ */
+
+-STATIC irqreturn_t advansys_interrupt(int, void *, struct pt_regs *);
++STATIC irqreturn_t advansys_interrupt(int, void *);
+ STATIC int advansys_slave_configure(struct scsi_device *);
+ STATIC void asc_scsi_done_list(struct scsi_cmnd *);
+ STATIC int asc_execute_scsi_cmnd(struct scsi_cmnd *);
+@@ -4330,12 +4319,12 @@ advansys_detect(struct scsi_host_templat
+ struct pci_dev *pci_devp = NULL;
+ int pci_device_id_cnt = 0;
+ unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
+- ASC_PCI_DEVICE_ID_1100,
+- ASC_PCI_DEVICE_ID_1200,
+- ASC_PCI_DEVICE_ID_1300,
+- ASC_PCI_DEVICE_ID_2300,
+- ASC_PCI_DEVICE_ID_2500,
+- ASC_PCI_DEVICE_ID_2700
++ PCI_DEVICE_ID_ASP_1200A,
++ PCI_DEVICE_ID_ASP_ABP940,
++ PCI_DEVICE_ID_ASP_ABP940U,
++ PCI_DEVICE_ID_ASP_ABP940UW,
++ PCI_DEVICE_ID_38C0800_REV1,
++ PCI_DEVICE_ID_38C1600_REV1
+ };
+ ADV_PADDR pci_memory_address;
+ #endif /* CONFIG_PCI */
+@@ -4471,7 +4460,7 @@ advansys_detect(struct scsi_host_templat
+
+ /* Find all PCI cards. */
+ while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
+- if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
++ if ((pci_devp = pci_find_device(PCI_VENDOR_ID_ASP,
+ pci_device_id[pci_device_id_cnt], pci_devp)) ==
+ NULL) {
+ pci_device_id_cnt++;
+@@ -4575,9 +4564,9 @@ advansys_detect(struct scsi_host_templat
+ */
+ #ifdef CONFIG_PCI
+ if (asc_bus[bus] == ASC_IS_PCI &&
+- (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
+- pci_devp->device == ASC_PCI_DEVICE_ID_2500 ||
+- pci_devp->device == ASC_PCI_DEVICE_ID_2700))
++ (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW ||
++ pci_devp->device == PCI_DEVICE_ID_38C0800_REV1 ||
++ pci_devp->device == PCI_DEVICE_ID_38C1600_REV1))
+ {
+ boardp->flags |= ASC_IS_WIDE_BOARD;
+ }
+@@ -4600,11 +4589,11 @@ advansys_detect(struct scsi_host_templat
+ adv_dvc_varp->isr_callback = adv_isr_callback;
+ adv_dvc_varp->async_callback = adv_async_callback;
+ #ifdef CONFIG_PCI
+- if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
++ if (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW)
+ {
+ ASC_DBG(1, "advansys_detect: ASC-3550\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+- } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500)
++ } else if (pci_devp->device == PCI_DEVICE_ID_38C0800_REV1)
+ {
+ ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+@@ -6008,7 +5997,7 @@ static struct scsi_host_template driver_
+ * an AdvanSys adapter.
+ */
+ STATIC irqreturn_t
+-advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++advansys_interrupt(int irq, void *dev_id)
+ {
+ ulong flags;
+ int i;
+@@ -6632,7 +6621,7 @@ adv_build_req(asc_board_t *boardp, struc
+ dma_map_single(dev, scp->request_buffer,
+ scp->request_bufflen, scp->sc_data_direction);
+ } else {
+- scsiqp->vdata_addr = 0;
++ scsiqp->vdata_addr = NULL;
+ scp->SCp.dma_handle = 0;
+ }
+ scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
+@@ -11922,7 +11911,7 @@ AscInitGetConfig(
+ PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigRevisionIDRegister);
+
+- if (PCIVendorID != ASC_PCI_VENDORID) {
++ if (PCIVendorID != PCI_VENDOR_ID_ASP) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
+@@ -11942,15 +11931,15 @@ AscInitGetConfig(
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
+- if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) ||
+- (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) {
++ if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
++ (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
+ DvcWritePCIConfigByte(asc_dvc,
+ AscPCIConfigLatencyTimer, 0x00);
+ if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
+ != 0x00) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+- } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) {
++ } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
+ if (DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigLatencyTimer) < 0x20) {
+ DvcWritePCIConfigByte(asc_dvc,
+@@ -12037,8 +12026,8 @@ AscInitFromAscDvcVar(
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+ } else {
+- if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
+- (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
++ if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
++ (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+@@ -14275,8 +14264,8 @@ Default_38C0800_EEPROM_Config __initdata
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+- ADV_PCI_VENDOR_ID, /* 58 subsysvid */
+- ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
++ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
++ PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+@@ -14405,8 +14394,8 @@ Default_38C1600_EEPROM_Config __initdata
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+- ADV_PCI_VENDOR_ID, /* 58 subsysvid */
+- ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */
++ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
++ PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+@@ -18225,3 +18214,22 @@ AdvInquiryHandling(
+ }
+ }
+ MODULE_LICENSE("Dual BSD/GPL");
++
++/* PCI Devices supported by this driver */
++static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
++};
++MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
++
+diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
+index f974869..306f46b 100644
+--- a/drivers/scsi/aha152x.c
++++ b/drivers/scsi/aha152x.c
+@@ -238,7 +238,7 @@
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <asm/irq.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <linux/blkdev.h>
+ #include <asm/system.h>
+ #include <linux/errno.h>
+@@ -253,6 +253,7 @@
+ #include <linux/isapnp.h>
+ #include <linux/spinlock.h>
+ #include <linux/workqueue.h>
++#include <linux/list.h>
+ #include <asm/semaphore.h>
+ #include <scsi/scsicam.h>
+
+@@ -262,6 +263,8 @@
+ #include <scsi/scsi_transport_spi.h>
+ #include "aha152x.h"
+
++static LIST_HEAD(aha152x_host_list);
++
+
+ /* DEFINES */
+
+@@ -423,8 +426,6 @@ MODULE_DEVICE_TABLE(isapnp, id_table);
+
+ #endif /* !PCMCIA */
+
+-static int registered_count=0;
+-static struct Scsi_Host *aha152x_host[2];
+ static struct scsi_host_template aha152x_driver_template;
+
+ /*
+@@ -541,6 +542,7 @@ struct aha152x_hostdata {
+ #ifdef __ISAPNP__
+ struct pnp_dev *pnpdev;
+ #endif
++ struct list_head host_list;
+ };
+
+
+@@ -671,7 +673,7 @@ static struct {
+ };
+
+ /* setup & interrupt */
+-static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);
++static irqreturn_t intr(int irq, void *dev_id);
+ static void reset_ports(struct Scsi_Host *shpnt);
+ static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
+ static void done(struct Scsi_Host *shpnt, int error);
+@@ -755,25 +757,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_
+ return ptr;
+ }
+
+-static inline struct Scsi_Host *lookup_irq(int irqno)
+-{
+- int i;
+-
+- for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
+- if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
+- return aha152x_host[i];
+-
+- return NULL;
+-}
+-
+-static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
++static irqreturn_t swintr(int irqno, void *dev_id)
+ {
+- struct Scsi_Host *shpnt = lookup_irq(irqno);
+-
+- if (!shpnt) {
+- printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
+- return IRQ_NONE;
+- }
++ struct Scsi_Host *shpnt = dev_id;
+
+ HOSTDATA(shpnt)->swint++;
+
+@@ -791,10 +777,11 @@ struct Scsi_Host *aha152x_probe_one(stru
+ return NULL;
+ }
+
+- /* need to have host registered before triggering any interrupt */
+- aha152x_host[registered_count] = shpnt;
+-
+ memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
++ INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
++
++ /* need to have host registered before triggering any interrupt */
++ list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
+
+ shpnt->io_port = setup->io_port;
+ shpnt->n_io_port = IO_RANGE;
+@@ -907,12 +894,10 @@ struct Scsi_Host *aha152x_probe_one(stru
+
+ scsi_scan_host(shpnt);
+
+- registered_count++;
+-
+ return shpnt;
+
+ out_host_put:
+- aha152x_host[registered_count]=NULL;
++ list_del(&HOSTDATA(shpnt)->host_list);
+ scsi_host_put(shpnt);
+
+ return NULL;
+@@ -937,6 +922,7 @@ void aha152x_release(struct Scsi_Host *s
+ #endif
+
+ scsi_remove_host(shpnt);
++ list_del(&HOSTDATA(shpnt)->host_list);
+ scsi_host_put(shpnt);
+ }
+
+@@ -1459,9 +1445,12 @@ static struct work_struct aha152x_tq;
+ */
+ static void run(void)
+ {
+- int i;
+- for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
+- is_complete(aha152x_host[i]);
++ struct aha152x_hostdata *hd;
++
++ list_for_each_entry(hd, &aha152x_host_list, host_list) {
++ struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
++
++ is_complete(shost);
+ }
+ }
+
+@@ -1469,9 +1458,9 @@ static void run(void)
+ * Interrupt handler
+ *
+ */
+-static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
++static irqreturn_t intr(int irqno, void *dev_id)
+ {
+- struct Scsi_Host *shpnt = lookup_irq(irqno);
++ struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
+ unsigned long flags;
+ unsigned char rev, dmacntrl0;
+
+@@ -3953,16 +3942,17 @@ static int __init aha152x_init(void)
+ #endif
+ }
+
+- return registered_count>0;
++ return 1;
+ }
+
+ static void __exit aha152x_exit(void)
+ {
+- int i;
++ struct aha152x_hostdata *hd;
++
++ list_for_each_entry(hd, &aha152x_host_list, host_list) {
++ struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
+
+- for(i=0; i<ARRAY_SIZE(setup); i++) {
+- aha152x_release(aha152x_host[i]);
+- aha152x_host[i]=NULL;
++ aha152x_release(shost);
+ }
+ }
+
+diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
+index 24f0f54..d7a61a6 100644
+--- a/drivers/scsi/aha1542.c
++++ b/drivers/scsi/aha1542.c
+@@ -174,9 +174,8 @@ static DEFINE_SPINLOCK(aha1542_lock);
+
+ static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
+ static int aha1542_restart(struct Scsi_Host *shost);
+-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs);
+-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
+- struct pt_regs *regs);
++static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id);
++static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id);
+
+ #define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
+
+@@ -416,8 +415,7 @@ fail:
+ }
+
+ /* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
+-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *shost;
+@@ -427,13 +425,13 @@ static irqreturn_t do_aha1542_intr_handl
+ panic("Splunge!");
+
+ spin_lock_irqsave(shost->host_lock, flags);
+- aha1542_intr_handle(shost, dev_id, regs);
++ aha1542_intr_handle(shost, dev_id);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ /* A "high" level interrupt handler */
+-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs)
++static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
+ {
+ void (*my_done) (Scsi_Cmnd *) = NULL;
+ int errstatus, mbi, mbo, mbistatus;
+diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
+index 0e4a7eb..c3c38a7 100644
+--- a/drivers/scsi/aha1740.c
++++ b/drivers/scsi/aha1740.c
+@@ -223,8 +223,7 @@ static int aha1740_test_port(unsigned in
+ }
+
+ /* A "high" level interrupt handler */
+-static irqreturn_t aha1740_intr_handle(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
+ {
+ struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
+ void (*my_done)(Scsi_Cmnd *);
+@@ -681,6 +680,7 @@ static struct eisa_device_id aha1740_ids
+ { "ADP0400" }, /* 1744 */
+ { "" }
+ };
++MODULE_DEVICE_TABLE(eisa, aha1740_ids);
+
+ static struct eisa_driver aha1740_driver = {
+ .id_table = aha1740_ids,
+diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
+deleted file mode 100644
+index 904c25f..0000000
+--- a/drivers/scsi/ahci.c
++++ /dev/null
+@@ -1,1473 +0,0 @@
+-/*
+- * ahci.c - AHCI SATA support
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2004-2005 Red Hat, Inc.
+- *
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * AHCI hardware documentation:
+- * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+- * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/sched.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-
+-#define DRV_NAME "ahci"
+-#define DRV_VERSION "2.0"
+-
+-
+-enum {
+- AHCI_PCI_BAR = 5,
+- AHCI_MAX_SG = 168, /* hardware max is 64K */
+- AHCI_DMA_BOUNDARY = 0xffffffff,
+- AHCI_USE_CLUSTERING = 0,
+- AHCI_MAX_CMDS = 32,
+- AHCI_CMD_SZ = 32,
+- AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
+- AHCI_RX_FIS_SZ = 256,
+- AHCI_CMD_TBL_CDB = 0x40,
+- AHCI_CMD_TBL_HDR_SZ = 0x80,
+- AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+- AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
+- AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
+- AHCI_RX_FIS_SZ,
+- AHCI_IRQ_ON_SG = (1 << 31),
+- AHCI_CMD_ATAPI = (1 << 5),
+- AHCI_CMD_WRITE = (1 << 6),
+- AHCI_CMD_PREFETCH = (1 << 7),
+- AHCI_CMD_RESET = (1 << 8),
+- AHCI_CMD_CLR_BUSY = (1 << 10),
+-
+- RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
+- RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
+-
+- board_ahci = 0,
+- board_ahci_vt8251 = 1,
+-
+- /* global controller registers */
+- HOST_CAP = 0x00, /* host capabilities */
+- HOST_CTL = 0x04, /* global host control */
+- HOST_IRQ_STAT = 0x08, /* interrupt status */
+- HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
+- HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
+-
+- /* HOST_CTL bits */
+- HOST_RESET = (1 << 0), /* reset controller; self-clear */
+- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
+- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
+-
+- /* HOST_CAP bits */
+- HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
+- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+-
+- /* registers for each SATA port */
+- PORT_LST_ADDR = 0x00, /* command list DMA addr */
+- PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
+- PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
+- PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
+- PORT_IRQ_STAT = 0x10, /* interrupt status */
+- PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
+- PORT_CMD = 0x18, /* port command */
+- PORT_TFDATA = 0x20, /* taskfile data */
+- PORT_SIG = 0x24, /* device TF signature */
+- PORT_CMD_ISSUE = 0x38, /* command issue */
+- PORT_SCR = 0x28, /* SATA phy register block */
+- PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
+- PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
+- PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
+- PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+-
+- /* PORT_IRQ_{STAT,MASK} bits */
+- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
+- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
+- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
+- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
+- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
+- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
+- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
+- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
+-
+- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
+- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
+- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
+- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
+- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
+- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
+- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
+- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
+- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
+-
+- PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
+- PORT_IRQ_IF_ERR |
+- PORT_IRQ_CONNECT |
+- PORT_IRQ_PHYRDY |
+- PORT_IRQ_UNK_FIS,
+- PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
+- PORT_IRQ_TF_ERR |
+- PORT_IRQ_HBUS_DATA_ERR,
+- DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
+- PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
+- PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
+-
+- /* PORT_CMD bits */
+- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
+- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
+- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
+- PORT_CMD_CLO = (1 << 3), /* Command list override */
+- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
+- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
+- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
+-
+- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
+- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
+- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+-
+- /* hpriv->flags bits */
+- AHCI_FLAG_MSI = (1 << 0),
+-
+- /* ap->flags bits */
+- AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
+- AHCI_FLAG_NO_NCQ = (1 << 25),
+-};
+-
+-struct ahci_cmd_hdr {
+- u32 opts;
+- u32 status;
+- u32 tbl_addr;
+- u32 tbl_addr_hi;
+- u32 reserved[4];
+-};
+-
+-struct ahci_sg {
+- u32 addr;
+- u32 addr_hi;
+- u32 reserved;
+- u32 flags_size;
+-};
+-
+-struct ahci_host_priv {
+- unsigned long flags;
+- u32 cap; /* cache of HOST_CAP register */
+- u32 port_map; /* cache of HOST_PORTS_IMPL reg */
+-};
+-
+-struct ahci_port_priv {
+- struct ahci_cmd_hdr *cmd_slot;
+- dma_addr_t cmd_slot_dma;
+- void *cmd_tbl;
+- dma_addr_t cmd_tbl_dma;
+- void *rx_fis;
+- dma_addr_t rx_fis_dma;
+-};
+-
+-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
+-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+-static void ahci_irq_clear(struct ata_port *ap);
+-static int ahci_port_start(struct ata_port *ap);
+-static void ahci_port_stop(struct ata_port *ap);
+-static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+-static void ahci_qc_prep(struct ata_queued_cmd *qc);
+-static u8 ahci_check_status(struct ata_port *ap);
+-static void ahci_freeze(struct ata_port *ap);
+-static void ahci_thaw(struct ata_port *ap);
+-static void ahci_error_handler(struct ata_port *ap);
+-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+-static void ahci_remove_one (struct pci_dev *pdev);
+-
+-static struct scsi_host_template ahci_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .change_queue_depth = ata_scsi_change_queue_depth,
+- .can_queue = AHCI_MAX_CMDS - 1,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = AHCI_MAX_SG,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = AHCI_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = AHCI_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations ahci_ops = {
+- .port_disable = ata_port_disable,
+-
+- .check_status = ahci_check_status,
+- .check_altstatus = ahci_check_status,
+- .dev_select = ata_noop_dev_select,
+-
+- .tf_read = ahci_tf_read,
+-
+- .qc_prep = ahci_qc_prep,
+- .qc_issue = ahci_qc_issue,
+-
+- .irq_handler = ahci_interrupt,
+- .irq_clear = ahci_irq_clear,
+-
+- .scr_read = ahci_scr_read,
+- .scr_write = ahci_scr_write,
+-
+- .freeze = ahci_freeze,
+- .thaw = ahci_thaw,
+-
+- .error_handler = ahci_error_handler,
+- .post_internal_cmd = ahci_post_internal_cmd,
+-
+- .port_start = ahci_port_start,
+- .port_stop = ahci_port_stop,
+-};
+-
+-static const struct ata_port_info ahci_port_info[] = {
+- /* board_ahci */
+- {
+- .sht = &ahci_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+- ATA_FLAG_SKIP_D2H_BSY,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &ahci_ops,
+- },
+- /* board_ahci_vt8251 */
+- {
+- .sht = &ahci_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+- ATA_FLAG_SKIP_D2H_BSY |
+- AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &ahci_ops,
+- },
+-};
+-
+-static const struct pci_device_id ahci_pci_tbl[] = {
+- /* Intel */
+- { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH6 */
+- { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH6M */
+- { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH7 */
+- { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH7M */
+- { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH7R */
+- { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ULi M5288 */
+- { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ESB2 */
+- { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ESB2 */
+- { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ESB2 */
+- { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH7-M DH */
+- { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH8 */
+- { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH8 */
+- { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH8 */
+- { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH8M */
+- { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ICH8M */
+-
+- /* JMicron */
+- { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* JMicron JMB360 */
+- { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* JMicron JMB361 */
+- { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* JMicron JMB363 */
+- { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* JMicron JMB365 */
+- { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* JMicron JMB366 */
+-
+- /* ATI */
+- { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ATI SB600 non-raid */
+- { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* ATI SB600 raid */
+-
+- /* VIA */
+- { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci_vt8251 }, /* VIA VT8251 */
+-
+- /* NVIDIA */
+- { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* MCP65 */
+- { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* MCP65 */
+- { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* MCP65 */
+- { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_ahci }, /* MCP65 */
+-
+- { } /* terminate list */
+-};
+-
+-
+-static struct pci_driver ahci_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = ahci_pci_tbl,
+- .probe = ahci_init_one,
+- .remove = ahci_remove_one,
+-};
+-
+-
+-static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
+-{
+- return base + 0x100 + (port * 0x80);
+-}
+-
+-static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
+-{
+- return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
+-}
+-
+-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;
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- void *mem;
+- dma_addr_t mem_dma;
+- int rc;
+-
+- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+- if (!pp)
+- return -ENOMEM;
+- memset(pp, 0, sizeof(*pp));
+-
+- rc = ata_pad_alloc(ap, dev);
+- if (rc) {
+- kfree(pp);
+- return rc;
+- }
+-
+- mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
+- if (!mem) {
+- ata_pad_free(ap, dev);
+- kfree(pp);
+- return -ENOMEM;
+- }
+- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+-
+- /*
+- * First item in chunk of DMA memory: 32-slot command table,
+- * 32 bytes each in size
+- */
+- pp->cmd_slot = mem;
+- pp->cmd_slot_dma = mem_dma;
+-
+- mem += AHCI_CMD_SLOT_SZ;
+- mem_dma += AHCI_CMD_SLOT_SZ;
+-
+- /*
+- * Second item: Received-FIS area
+- */
+- pp->rx_fis = mem;
+- pp->rx_fis_dma = mem_dma;
+-
+- mem += AHCI_RX_FIS_SZ;
+- mem_dma += AHCI_RX_FIS_SZ;
+-
+- /*
+- * Third item: data area for storing a single command
+- * and its scatter-gather table
+- */
+- pp->cmd_tbl = mem;
+- pp->cmd_tbl_dma = mem_dma;
+-
+- ap->private_data = pp;
+-
+- if (hpriv->cap & HOST_CAP_64)
+- writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
+- writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+- readl(port_mmio + PORT_LST_ADDR); /* flush */
+-
+- if (hpriv->cap & HOST_CAP_64)
+- writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
+- writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+- readl(port_mmio + PORT_FIS_ADDR); /* flush */
+-
+- writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
+- PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
+- PORT_CMD_START, port_mmio + PORT_CMD);
+- readl(port_mmio + PORT_CMD); /* flush */
+-
+- return 0;
+-}
+-
+-
+-static void ahci_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct ahci_port_priv *pp = ap->private_data;
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- u32 tmp;
+-
+- tmp = readl(port_mmio + PORT_CMD);
+- tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
+- writel(tmp, port_mmio + PORT_CMD);
+- readl(port_mmio + PORT_CMD); /* flush */
+-
+- /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
+- * this is slightly incorrect.
+- */
+- msleep(500);
+-
+- ap->private_data = NULL;
+- dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+- pp->cmd_slot, pp->cmd_slot_dma);
+- ata_pad_free(ap, dev);
+- kfree(pp);
+-}
+-
+-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+-{
+- unsigned int sc_reg;
+-
+- switch (sc_reg_in) {
+- case SCR_STATUS: sc_reg = 0; break;
+- case SCR_CONTROL: sc_reg = 1; break;
+- case SCR_ERROR: sc_reg = 2; break;
+- case SCR_ACTIVE: sc_reg = 3; break;
+- default:
+- return 0xffffffffU;
+- }
+-
+- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-
+-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
+- u32 val)
+-{
+- unsigned int sc_reg;
+-
+- switch (sc_reg_in) {
+- case SCR_STATUS: sc_reg = 0; break;
+- case SCR_CONTROL: sc_reg = 1; break;
+- case SCR_ERROR: sc_reg = 2; break;
+- case SCR_ACTIVE: sc_reg = 3; break;
+- default:
+- return;
+- }
+-
+- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-static int ahci_stop_engine(struct ata_port *ap)
+-{
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- int work;
+- u32 tmp;
+-
+- tmp = readl(port_mmio + PORT_CMD);
+- tmp &= ~PORT_CMD_START;
+- writel(tmp, port_mmio + PORT_CMD);
+-
+- /* wait for engine to stop. TODO: this could be
+- * as long as 500 msec
+- */
+- work = 1000;
+- while (work-- > 0) {
+- tmp = readl(port_mmio + PORT_CMD);
+- if ((tmp & PORT_CMD_LIST_ON) == 0)
+- return 0;
+- udelay(10);
+- }
+-
+- return -EIO;
+-}
+-
+-static void ahci_start_engine(struct ata_port *ap)
+-{
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- u32 tmp;
+-
+- tmp = readl(port_mmio + PORT_CMD);
+- tmp |= PORT_CMD_START;
+- writel(tmp, port_mmio + PORT_CMD);
+- readl(port_mmio + PORT_CMD); /* flush */
+-}
+-
+-static unsigned int ahci_dev_classify(struct ata_port *ap)
+-{
+- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+- struct ata_taskfile tf;
+- u32 tmp;
+-
+- tmp = readl(port_mmio + PORT_SIG);
+- tf.lbah = (tmp >> 24) & 0xff;
+- tf.lbam = (tmp >> 16) & 0xff;
+- tf.lbal = (tmp >> 8) & 0xff;
+- tf.nsect = (tmp) & 0xff;
+-
+- return ata_dev_classify(&tf);
+-}
+-
+-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+- u32 opts)
+-{
+- dma_addr_t cmd_tbl_dma;
+-
+- cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
+-
+- pp->cmd_slot[tag].opts = cpu_to_le32(opts);
+- pp->cmd_slot[tag].status = 0;
+- pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
+- pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
+-}
+-
+-static int ahci_clo(struct ata_port *ap)
+-{
+- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+- struct ahci_host_priv *hpriv = ap->host_set->private_data;
+- u32 tmp;
+-
+- if (!(hpriv->cap & HOST_CAP_CLO))
+- return -EOPNOTSUPP;
+-
+- tmp = readl(port_mmio + PORT_CMD);
+- tmp |= PORT_CMD_CLO;
+- writel(tmp, port_mmio + PORT_CMD);
+-
+- tmp = ata_wait_register(port_mmio + PORT_CMD,
+- PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
+- if (tmp & PORT_CMD_CLO)
+- return -EIO;
+-
+- return 0;
+-}
+-
+-static int ahci_prereset(struct ata_port *ap)
+-{
+- if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+- (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+- /* ATA_BUSY hasn't cleared, so send a CLO */
+- ahci_clo(ap);
+- }
+-
+- return ata_std_prereset(ap);
+-}
+-
+-static int ahci_softreset(struct ata_port *ap, unsigned int *class)
+-{
+- struct ahci_port_priv *pp = ap->private_data;
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- const u32 cmd_fis_len = 5; /* five dwords */
+- const char *reason = NULL;
+- struct ata_taskfile tf;
+- u32 tmp;
+- u8 *fis;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+-
+- if (ata_port_offline(ap)) {
+- DPRINTK("PHY reports no device\n");
+- *class = ATA_DEV_NONE;
+- return 0;
+- }
+-
+- /* prepare for SRST (AHCI-1.1 10.4.1) */
+- rc = ahci_stop_engine(ap);
+- if (rc) {
+- reason = "failed to stop engine";
+- goto fail_restart;
+- }
+-
+- /* check BUSY/DRQ, perform Command List Override if necessary */
+- ahci_tf_read(ap, &tf);
+- if (tf.command & (ATA_BUSY | ATA_DRQ)) {
+- rc = ahci_clo(ap);
+-
+- if (rc == -EOPNOTSUPP) {
+- reason = "port busy but CLO unavailable";
+- goto fail_restart;
+- } else if (rc) {
+- reason = "port busy but CLO failed";
+- goto fail_restart;
+- }
+- }
+-
+- /* restart engine */
+- ahci_start_engine(ap);
+-
+- ata_tf_init(ap->device, &tf);
+- fis = pp->cmd_tbl;
+-
+- /* issue the first D2H Register FIS */
+- ahci_fill_cmd_slot(pp, 0,
+- cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+-
+- tf.ctl |= ATA_SRST;
+- ata_tf_to_fis(&tf, fis, 0);
+- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+-
+- writel(1, port_mmio + PORT_CMD_ISSUE);
+-
+- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
+- if (tmp & 0x1) {
+- rc = -EIO;
+- reason = "1st FIS failed";
+- goto fail;
+- }
+-
+- /* spec says at least 5us, but be generous and sleep for 1ms */
+- msleep(1);
+-
+- /* issue the second D2H Register FIS */
+- ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
+-
+- tf.ctl &= ~ATA_SRST;
+- ata_tf_to_fis(&tf, fis, 0);
+- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+-
+- writel(1, port_mmio + PORT_CMD_ISSUE);
+- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+-
+- /* spec mandates ">= 2ms" before checking status.
+- * We wait 150ms, because that was the magic delay used for
+- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+- * between when the ATA command register is written, and then
+- * status is checked. Because waiting for "a while" before
+- * checking status is fine, post SRST, we perform this magic
+- * delay here as well.
+- */
+- msleep(150);
+-
+- *class = ATA_DEV_NONE;
+- if (ata_port_online(ap)) {
+- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+- rc = -EIO;
+- reason = "device not ready";
+- goto fail;
+- }
+- *class = ahci_dev_classify(ap);
+- }
+-
+- DPRINTK("EXIT, class=%u\n", *class);
+- return 0;
+-
+- fail_restart:
+- ahci_start_engine(ap);
+- fail:
+- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+- return rc;
+-}
+-
+-static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
+-{
+- struct ahci_port_priv *pp = ap->private_data;
+- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+- struct ata_taskfile tf;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+-
+- ahci_stop_engine(ap);
+-
+- /* clear D2H reception area to properly wait for D2H FIS */
+- ata_tf_init(ap->device, &tf);
+- tf.command = 0xff;
+- ata_tf_to_fis(&tf, d2h_fis, 0);
+-
+- rc = sata_std_hardreset(ap, class);
+-
+- ahci_start_engine(ap);
+-
+- if (rc == 0 && ata_port_online(ap))
+- *class = ahci_dev_classify(ap);
+- if (*class == ATA_DEV_UNKNOWN)
+- *class = ATA_DEV_NONE;
+-
+- DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+- return rc;
+-}
+-
+-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+-{
+- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+- u32 new_tmp, tmp;
+-
+- ata_std_postreset(ap, class);
+-
+- /* Make sure port's ATAPI bit is set appropriately */
+- new_tmp = tmp = readl(port_mmio + PORT_CMD);
+- if (*class == ATA_DEV_ATAPI)
+- new_tmp |= PORT_CMD_ATAPI;
+- else
+- new_tmp &= ~PORT_CMD_ATAPI;
+- if (new_tmp != tmp) {
+- writel(new_tmp, port_mmio + PORT_CMD);
+- readl(port_mmio + PORT_CMD); /* flush */
+- }
+-}
+-
+-static u8 ahci_check_status(struct ata_port *ap)
+-{
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+-
+- return readl(mmio + PORT_TFDATA) & 0xFF;
+-}
+-
+-static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- struct ahci_port_priv *pp = ap->private_data;
+- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+-
+- ata_tf_from_fis(d2h_fis, tf);
+-}
+-
+-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+-{
+- struct scatterlist *sg;
+- struct ahci_sg *ahci_sg;
+- unsigned int n_sg = 0;
+-
+- VPRINTK("ENTER\n");
+-
+- /*
+- * Next, the S/G list.
+- */
+- ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+- ata_for_each_sg(sg, qc) {
+- dma_addr_t addr = sg_dma_address(sg);
+- u32 sg_len = sg_dma_len(sg);
+-
+- ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
+- ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+- ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
+-
+- ahci_sg++;
+- n_sg++;
+- }
+-
+- return n_sg;
+-}
+-
+-static void ahci_qc_prep(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct ahci_port_priv *pp = ap->private_data;
+- int is_atapi = is_atapi_taskfile(&qc->tf);
+- void *cmd_tbl;
+- u32 opts;
+- const u32 cmd_fis_len = 5; /* five dwords */
+- unsigned int n_elem;
+-
+- /*
+- * Fill in command table information. First, the header,
+- * a SATA Register - Host to Device command FIS.
+- */
+- cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+-
+- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+- if (is_atapi) {
+- memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+- memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
+- }
+-
+- n_elem = 0;
+- if (qc->flags & ATA_QCFLAG_DMAMAP)
+- n_elem = ahci_fill_sg(qc, cmd_tbl);
+-
+- /*
+- * Fill in command slot information.
+- */
+- opts = cmd_fis_len | n_elem << 16;
+- if (qc->tf.flags & ATA_TFLAG_WRITE)
+- opts |= AHCI_CMD_WRITE;
+- if (is_atapi)
+- opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
+-
+- ahci_fill_cmd_slot(pp, qc->tag, opts);
+-}
+-
+-static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+-{
+- struct ahci_port_priv *pp = ap->private_data;
+- struct ata_eh_info *ehi = &ap->eh_info;
+- unsigned int err_mask = 0, action = 0;
+- struct ata_queued_cmd *qc;
+- u32 serror;
+-
+- ata_ehi_clear_desc(ehi);
+-
+- /* AHCI needs SError cleared; otherwise, it might lock up */
+- serror = ahci_scr_read(ap, SCR_ERROR);
+- ahci_scr_write(ap, SCR_ERROR, serror);
+-
+- /* analyze @irq_stat */
+- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+-
+- if (irq_stat & PORT_IRQ_TF_ERR)
+- err_mask |= AC_ERR_DEV;
+-
+- if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
+- err_mask |= AC_ERR_HOST_BUS;
+- action |= ATA_EH_SOFTRESET;
+- }
+-
+- if (irq_stat & PORT_IRQ_IF_ERR) {
+- err_mask |= AC_ERR_ATA_BUS;
+- action |= ATA_EH_SOFTRESET;
+- ata_ehi_push_desc(ehi, ", interface fatal error");
+- }
+-
+- if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
+- ata_ehi_hotplugged(ehi);
+- ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+- "connection status changed" : "PHY RDY changed");
+- }
+-
+- if (irq_stat & PORT_IRQ_UNK_FIS) {
+- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+-
+- err_mask |= AC_ERR_HSM;
+- action |= ATA_EH_SOFTRESET;
+- ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+- unk[0], unk[1], unk[2], unk[3]);
+- }
+-
+- /* okay, let's hand over to EH */
+- ehi->serror |= serror;
+- ehi->action |= action;
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc)
+- qc->err_mask |= err_mask;
+- else
+- ehi->err_mask |= err_mask;
+-
+- if (irq_stat & PORT_IRQ_FREEZE)
+- ata_port_freeze(ap);
+- else
+- ata_port_abort(ap);
+-}
+-
+-static void ahci_host_intr(struct ata_port *ap)
+-{
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- struct ata_eh_info *ehi = &ap->eh_info;
+- u32 status, qc_active;
+- int rc;
+-
+- status = readl(port_mmio + PORT_IRQ_STAT);
+- writel(status, port_mmio + PORT_IRQ_STAT);
+-
+- if (unlikely(status & PORT_IRQ_ERROR)) {
+- ahci_error_intr(ap, status);
+- return;
+- }
+-
+- if (ap->sactive)
+- qc_active = readl(port_mmio + PORT_SCR_ACT);
+- else
+- qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+-
+- rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+- if (rc > 0)
+- return;
+- if (rc < 0) {
+- ehi->err_mask |= AC_ERR_HSM;
+- ehi->action |= ATA_EH_SOFTRESET;
+- ata_port_freeze(ap);
+- return;
+- }
+-
+- /* hmmm... a spurious interupt */
+-
+- /* some devices send D2H reg with I bit set during NCQ command phase */
+- if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+- return;
+-
+- /* ignore interim PIO setup fis interrupts */
+- if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
+- return;
+-
+- if (ata_ratelimit())
+- ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+- "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
+- status, ap->active_tag, ap->sactive);
+-}
+-
+-static void ahci_irq_clear(struct ata_port *ap)
+-{
+- /* TODO */
+-}
+-
+-static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- struct ahci_host_priv *hpriv;
+- unsigned int i, handled = 0;
+- void __iomem *mmio;
+- u32 irq_stat, irq_ack = 0;
+-
+- VPRINTK("ENTER\n");
+-
+- hpriv = host_set->private_data;
+- mmio = host_set->mmio_base;
+-
+- /* sigh. 0xffffffff is a valid return from h/w */
+- irq_stat = readl(mmio + HOST_IRQ_STAT);
+- irq_stat &= hpriv->port_map;
+- if (!irq_stat)
+- return IRQ_NONE;
+-
+- spin_lock(&host_set->lock);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap;
+-
+- if (!(irq_stat & (1 << i)))
+- continue;
+-
+- ap = host_set->ports[i];
+- if (ap) {
+- ahci_host_intr(ap);
+- VPRINTK("port %u\n", i);
+- } else {
+- VPRINTK("port %u (no irq)\n", i);
+- if (ata_ratelimit())
+- dev_printk(KERN_WARNING, host_set->dev,
+- "interrupt on disabled port %u\n", i);
+- }
+-
+- irq_ack |= (1 << i);
+- }
+-
+- if (irq_ack) {
+- writel(irq_ack, mmio + HOST_IRQ_STAT);
+- handled = 1;
+- }
+-
+- spin_unlock(&host_set->lock);
+-
+- VPRINTK("EXIT\n");
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+-
+- if (qc->tf.protocol == ATA_PROT_NCQ)
+- writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+- writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
+- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+-
+- return 0;
+-}
+-
+-static void ahci_freeze(struct ata_port *ap)
+-{
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+-
+- /* turn IRQ off */
+- writel(0, port_mmio + PORT_IRQ_MASK);
+-}
+-
+-static void ahci_thaw(struct ata_port *ap)
+-{
+- void __iomem *mmio = ap->host_set->mmio_base;
+- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+- u32 tmp;
+-
+- /* clear IRQ */
+- tmp = readl(port_mmio + PORT_IRQ_STAT);
+- writel(tmp, port_mmio + PORT_IRQ_STAT);
+- writel(1 << ap->id, mmio + HOST_IRQ_STAT);
+-
+- /* turn IRQ back on */
+- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+-}
+-
+-static void ahci_error_handler(struct ata_port *ap)
+-{
+- if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+- /* restart engine */
+- ahci_stop_engine(ap);
+- ahci_start_engine(ap);
+- }
+-
+- /* perform recovery */
+- ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
+- ahci_postreset);
+-}
+-
+-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- if (qc->flags & ATA_QCFLAG_FAILED)
+- qc->err_mask |= AC_ERR_OTHER;
+-
+- if (qc->err_mask) {
+- /* make DMA engine forget about the failed command */
+- ahci_stop_engine(ap);
+- ahci_start_engine(ap);
+- }
+-}
+-
+-static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
+- unsigned int port_idx)
+-{
+- VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
+- base = ahci_port_base_ul(base, port_idx);
+- VPRINTK("base now==0x%lx\n", base);
+-
+- port->cmd_addr = base;
+- port->scr_addr = base + PORT_SCR;
+-
+- VPRINTK("EXIT\n");
+-}
+-
+-static int ahci_host_init(struct ata_probe_ent *probe_ent)
+-{
+- struct ahci_host_priv *hpriv = probe_ent->private_data;
+- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+- void __iomem *mmio = probe_ent->mmio_base;
+- u32 tmp, cap_save;
+- unsigned int i, j, using_dac;
+- int rc;
+- void __iomem *port_mmio;
+-
+- cap_save = readl(mmio + HOST_CAP);
+- cap_save &= ( (1<<28) | (1<<17) );
+- cap_save |= (1 << 27);
+-
+- /* global controller reset */
+- tmp = readl(mmio + HOST_CTL);
+- if ((tmp & HOST_RESET) == 0) {
+- writel(tmp | HOST_RESET, mmio + HOST_CTL);
+- readl(mmio + HOST_CTL); /* flush */
+- }
+-
+- /* reset must complete within 1 second, or
+- * the hardware should be considered fried.
+- */
+- ssleep(1);
+-
+- tmp = readl(mmio + HOST_CTL);
+- if (tmp & HOST_RESET) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "controller reset failed (0x%x)\n", tmp);
+- return -EIO;
+- }
+-
+- writel(HOST_AHCI_EN, mmio + HOST_CTL);
+- (void) readl(mmio + HOST_CTL); /* flush */
+- writel(cap_save, mmio + HOST_CAP);
+- writel(0xf, mmio + HOST_PORTS_IMPL);
+- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
+-
+- if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+- u16 tmp16;
+-
+- pci_read_config_word(pdev, 0x92, &tmp16);
+- tmp16 |= 0xf;
+- pci_write_config_word(pdev, 0x92, tmp16);
+- }
+-
+- hpriv->cap = readl(mmio + HOST_CAP);
+- hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
+- probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
+-
+- VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
+- hpriv->cap, hpriv->port_map, probe_ent->n_ports);
+-
+- using_dac = hpriv->cap & HOST_CAP_64;
+- if (using_dac &&
+- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+- if (rc) {
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "64-bit DMA enable failed\n");
+- return rc;
+- }
+- }
+- } else {
+- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit DMA enable failed\n");
+- return rc;
+- }
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit consistent DMA enable failed\n");
+- return rc;
+- }
+- }
+-
+- for (i = 0; i < probe_ent->n_ports; i++) {
+-#if 0 /* BIOSen initialize this incorrectly */
+- if (!(hpriv->port_map & (1 << i)))
+- continue;
+-#endif
+-
+- port_mmio = ahci_port_base(mmio, i);
+- VPRINTK("mmio %p port_mmio %p\n", mmio, port_mmio);
+-
+- ahci_setup_port(&probe_ent->port[i],
+- (unsigned long) mmio, i);
+-
+- /* make sure port is not active */
+- tmp = readl(port_mmio + PORT_CMD);
+- VPRINTK("PORT_CMD 0x%x\n", tmp);
+- if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
+- PORT_CMD_FIS_RX | PORT_CMD_START)) {
+- tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
+- PORT_CMD_FIS_RX | PORT_CMD_START);
+- writel(tmp, port_mmio + PORT_CMD);
+- readl(port_mmio + PORT_CMD); /* flush */
+-
+- /* spec says 500 msecs for each bit, so
+- * this is slightly incorrect.
+- */
+- msleep(500);
+- }
+-
+- writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
+-
+- j = 0;
+- while (j < 100) {
+- msleep(10);
+- tmp = readl(port_mmio + PORT_SCR_STAT);
+- if ((tmp & 0xf) == 0x3)
+- break;
+- j++;
+- }
+-
+- tmp = readl(port_mmio + PORT_SCR_ERR);
+- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+- writel(tmp, port_mmio + PORT_SCR_ERR);
+-
+- /* ack any pending irq events for this port */
+- tmp = readl(port_mmio + PORT_IRQ_STAT);
+- VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+- if (tmp)
+- writel(tmp, port_mmio + PORT_IRQ_STAT);
+-
+- writel(1 << i, mmio + HOST_IRQ_STAT);
+- }
+-
+- tmp = readl(mmio + HOST_CTL);
+- VPRINTK("HOST_CTL 0x%x\n", tmp);
+- writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+- tmp = readl(mmio + HOST_CTL);
+- VPRINTK("HOST_CTL 0x%x\n", tmp);
+-
+- pci_set_master(pdev);
+-
+- return 0;
+-}
+-
+-static void ahci_print_info(struct ata_probe_ent *probe_ent)
+-{
+- struct ahci_host_priv *hpriv = probe_ent->private_data;
+- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+- void __iomem *mmio = probe_ent->mmio_base;
+- u32 vers, cap, impl, speed;
+- const char *speed_s;
+- u16 cc;
+- const char *scc_s;
+-
+- vers = readl(mmio + HOST_VERSION);
+- cap = hpriv->cap;
+- impl = hpriv->port_map;
+-
+- speed = (cap >> 20) & 0xf;
+- if (speed == 1)
+- speed_s = "1.5";
+- else if (speed == 2)
+- speed_s = "3";
+- else
+- speed_s = "?";
+-
+- pci_read_config_word(pdev, 0x0a, &cc);
+- if (cc == 0x0101)
+- scc_s = "IDE";
+- else if (cc == 0x0106)
+- scc_s = "SATA";
+- else if (cc == 0x0104)
+- scc_s = "RAID";
+- else
+- scc_s = "unknown";
+-
+- dev_printk(KERN_INFO, &pdev->dev,
+- "AHCI %02x%02x.%02x%02x "
+- "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
+- ,
+-
+- (vers >> 24) & 0xff,
+- (vers >> 16) & 0xff,
+- (vers >> 8) & 0xff,
+- vers & 0xff,
+-
+- ((cap >> 8) & 0x1f) + 1,
+- (cap & 0x1f) + 1,
+- speed_s,
+- impl,
+- scc_s);
+-
+- dev_printk(KERN_INFO, &pdev->dev,
+- "flags: "
+- "%s%s%s%s%s%s"
+- "%s%s%s%s%s%s%s\n"
+- ,
+-
+- cap & (1 << 31) ? "64bit " : "",
+- cap & (1 << 30) ? "ncq " : "",
+- cap & (1 << 28) ? "ilck " : "",
+- cap & (1 << 27) ? "stag " : "",
+- cap & (1 << 26) ? "pm " : "",
+- cap & (1 << 25) ? "led " : "",
+-
+- cap & (1 << 24) ? "clo " : "",
+- cap & (1 << 19) ? "nz " : "",
+- cap & (1 << 18) ? "only " : "",
+- cap & (1 << 17) ? "pmp " : "",
+- cap & (1 << 15) ? "pio " : "",
+- cap & (1 << 14) ? "slum " : "",
+- cap & (1 << 13) ? "part " : ""
+- );
+-}
+-
+-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- struct ahci_host_priv *hpriv;
+- unsigned long base;
+- void __iomem *mmio_base;
+- unsigned int board_idx = (unsigned int) ent->driver_data;
+- int have_msi, pci_dev_busy = 0;
+- int rc;
+-
+- VPRINTK("ENTER\n");
+-
+- WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- /* JMicron-specific fixup: make sure we're in AHCI mode */
+- /* This is protected from races with ata_jmicron by the pci probe
+- locking */
+- if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
+- /* AHCI enable, AHCI on function 0 */
+- pci_write_config_byte(pdev, 0x41, 0xa1);
+- /* Function 1 is the PATA controller */
+- if (PCI_FUNC(pdev->devfn))
+- return -ENODEV;
+- }
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- if (pci_enable_msi(pdev) == 0)
+- have_msi = 1;
+- else {
+- pci_intx(pdev, 1);
+- have_msi = 0;
+- }
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_msi;
+- }
+-
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+- base = (unsigned long) mmio_base;
+-
+- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv) {
+- rc = -ENOMEM;
+- goto err_out_iounmap;
+- }
+- memset(hpriv, 0, sizeof(*hpriv));
+-
+- probe_ent->sht = ahci_port_info[board_idx].sht;
+- probe_ent->host_flags = ahci_port_info[board_idx].host_flags;
+- probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask;
+- probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask;
+- probe_ent->port_ops = ahci_port_info[board_idx].port_ops;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+- probe_ent->private_data = hpriv;
+-
+- if (have_msi)
+- hpriv->flags |= AHCI_FLAG_MSI;
+-
+- /* initialize adapter */
+- rc = ahci_host_init(probe_ent);
+- if (rc)
+- goto err_out_hpriv;
+-
+- if (!(probe_ent->host_flags & AHCI_FLAG_NO_NCQ) &&
+- (hpriv->cap & HOST_CAP_NCQ))
+- probe_ent->host_flags |= ATA_FLAG_NCQ;
+-
+- ahci_print_info(probe_ent);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_hpriv:
+- kfree(hpriv);
+-err_out_iounmap:
+- pci_iounmap(pdev, mmio_base);
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_msi:
+- if (have_msi)
+- pci_disable_msi(pdev);
+- else
+- pci_intx(pdev, 0);
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-static void ahci_remove_one (struct pci_dev *pdev)
+-{
+- struct device *dev = pci_dev_to_dev(pdev);
+- struct ata_host_set *host_set = dev_get_drvdata(dev);
+- struct ahci_host_priv *hpriv = host_set->private_data;
+- unsigned int i;
+- int have_msi;
+-
+- for (i = 0; i < host_set->n_ports; i++)
+- ata_port_detach(host_set->ports[i]);
+-
+- have_msi = hpriv->flags & AHCI_FLAG_MSI;
+- free_irq(host_set->irq, host_set);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap = host_set->ports[i];
+-
+- ata_scsi_release(ap->host);
+- scsi_host_put(ap->host);
+- }
+-
+- kfree(hpriv);
+- pci_iounmap(pdev, host_set->mmio_base);
+- kfree(host_set);
+-
+- if (have_msi)
+- pci_disable_msi(pdev);
+- else
+- pci_intx(pdev, 0);
+- pci_release_regions(pdev);
+- pci_disable_device(pdev);
+- dev_set_drvdata(dev, NULL);
+-}
+-
+-static int __init ahci_init(void)
+-{
+- return pci_module_init(&ahci_pci_driver);
+-}
+-
+-static void __exit ahci_exit(void)
+-{
+- pci_unregister_driver(&ahci_pci_driver);
+-}
+-
+-
+-MODULE_AUTHOR("Jeff Garzik");
+-MODULE_DESCRIPTION("AHCI SATA low-level driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(ahci_init);
+-module_exit(ahci_exit);
+diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
+index 7955ebe..911ea17 100644
+--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
++++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
+@@ -22,12 +22,12 @@ config AIC79XX_CMDS_PER_DEVICE
+ to be used for any device. The aic7xxx driver will automatically
+ vary this number based on device behavior. For devices with a
+ fixed maximum, the driver will eventually lock to this maximum
+- and display a console message inidicating this value.
++ and display a console message indicating this value.
+
+ Due to resource allocation issues in the Linux SCSI mid-layer, using
+ a high number of commands per device may result in memory allocation
+ failures when many devices are attached to the system. For this reason,
+- the default is set to 32. Higher values may result in higer performance
++ the default is set to 32. Higher values may result in higher performance
+ on some devices. The upper bound is 253. 0 disables tagged queueing.
+
+ Per device tag depth can be controlled via the kernel command line
+diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+index 5517da5..cd93f9a 100644
+--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
++++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+@@ -27,12 +27,12 @@ config AIC7XXX_CMDS_PER_DEVICE
+ to be used for any device. The aic7xxx driver will automatically
+ vary this number based on device behavior. For devices with a
+ fixed maximum, the driver will eventually lock to this maximum
+- and display a console message inidicating this value.
++ and display a console message indicating this value.
+
+ Due to resource allocation issues in the Linux SCSI mid-layer, using
+ a high number of commands per device may result in memory allocation
+ failures when many devices are attached to the system. For this reason,
+- the default is set to 32. Higher values may result in higer performance
++ the default is set to 32. Higher values may result in higher performance
+ on some devices. The upper bound is 253. 0 disables tagged queueing.
+
+ Per device tag depth can be controlled via the kernel command line
+diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
+index 867cbe2..1ac1197 100644
+--- a/drivers/scsi/aic7xxx/aic7770_osm.c
++++ b/drivers/scsi/aic7xxx/aic7770_osm.c
+@@ -132,7 +132,8 @@ static struct eisa_device_id aic7770_ids
+ { "ADP7770", 5 }, /* AIC7770 generic */
+ { "" }
+ };
+-
++MODULE_DEVICE_TABLE(eisa, aic7770_ids);
++
+ static struct eisa_driver aic7770_driver = {
+ .id_table = aic7770_ids,
+ .driver = {
+diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
+index df3346b..170a434 100644
+--- a/drivers/scsi/aic7xxx/aic79xx.h
++++ b/drivers/scsi/aic7xxx/aic79xx.h
+@@ -53,14 +53,6 @@ struct ahd_platform_data;
+ struct scb_platform_data;
+
+ /****************************** Useful Macros *********************************/
+-#ifndef MAX
+-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+-#endif
+-
+-#ifndef MIN
+-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+-#endif
+-
+ #ifndef TRUE
+ #define TRUE 1
+ #endif
+@@ -972,8 +964,6 @@ int ahd_read_seeprom(struct ahd_softc *
+
+ int ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
+ u_int start_addr, u_int count);
+-int ahd_wait_seeprom(struct ahd_softc *ahd);
+-int ahd_verify_vpd_cksum(struct vpd_config *vpd);
+ int ahd_verify_cksum(struct seeprom_config *sc);
+ int ahd_acquire_seeprom(struct ahd_softc *ahd);
+ void ahd_release_seeprom(struct ahd_softc *ahd);
+@@ -1320,8 +1310,6 @@ struct ahd_pci_identity {
+ char *name;
+ ahd_device_setup_t *setup;
+ };
+-extern struct ahd_pci_identity ahd_pci_ident_table [];
+-extern const u_int ahd_num_pci_devs;
+
+ /***************************** VL/EISA Declarations ***************************/
+ struct aic7770_identity {
+@@ -1339,15 +1327,6 @@ extern const int ahd_num_aic7770_devs;
+ /*************************** Function Declarations ****************************/
+ /******************************************************************************/
+ void ahd_reset_cmds_pending(struct ahd_softc *ahd);
+-u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
+-void ahd_busy_tcl(struct ahd_softc *ahd,
+- u_int tcl, u_int busyid);
+-static __inline void ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl);
+-static __inline void
+-ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
+-{
+- ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
+-}
+
+ /***************************** PCI Front End *********************************/
+ struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
+@@ -1356,7 +1335,6 @@ int ahd_pci_config(struct ahd_softc
+ int ahd_pci_test_register_access(struct ahd_softc *);
+
+ /************************** SCB and SCB queue management **********************/
+-int ahd_probe_scbs(struct ahd_softc *);
+ void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
+ struct scb *scb);
+ int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
+@@ -1374,33 +1352,20 @@ int ahd_parse_vpddata(struct ahd_soft
+ int ahd_parse_cfgdata(struct ahd_softc *ahd,
+ struct seeprom_config *sc);
+ void ahd_intr_enable(struct ahd_softc *ahd, int enable);
+-void ahd_update_coalescing_values(struct ahd_softc *ahd,
+- u_int timer,
+- u_int maxcmds,
+- u_int mincmds);
+-void ahd_enable_coalescing(struct ahd_softc *ahd,
+- int enable);
+ void ahd_pause_and_flushwork(struct ahd_softc *ahd);
+ int ahd_suspend(struct ahd_softc *ahd);
+-int ahd_resume(struct ahd_softc *ahd);
+ void ahd_set_unit(struct ahd_softc *, int);
+ void ahd_set_name(struct ahd_softc *, char *);
+ struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
+ void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb);
+-void ahd_alloc_scbs(struct ahd_softc *ahd);
+ void ahd_free(struct ahd_softc *ahd);
+ int ahd_reset(struct ahd_softc *ahd, int reinit);
+-void ahd_shutdown(void *arg);
+ int ahd_write_flexport(struct ahd_softc *ahd,
+ u_int addr, u_int value);
+ int ahd_read_flexport(struct ahd_softc *ahd, u_int addr,
+ uint8_t *value);
+-int ahd_wait_flexport(struct ahd_softc *ahd);
+
+ /*************************** Interrupt Services *******************************/
+-void ahd_pci_intr(struct ahd_softc *ahd);
+-void ahd_clear_intstat(struct ahd_softc *ahd);
+-void ahd_flush_qoutfifo(struct ahd_softc *ahd);
+ void ahd_run_qoutfifo(struct ahd_softc *ahd);
+ #ifdef AHD_TARGET_MODE
+ void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
+@@ -1409,7 +1374,6 @@ void ahd_handle_hwerrint(struct ahd_so
+ void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
+ void ahd_handle_scsiint(struct ahd_softc *ahd,
+ u_int intstat);
+-void ahd_clear_critical_section(struct ahd_softc *ahd);
+
+ /***************************** Error Recovery *********************************/
+ typedef enum {
+@@ -1426,23 +1390,9 @@ int ahd_search_disc_list(struct ahd_so
+ char channel, int lun, u_int tag,
+ int stop_on_first, int remove,
+ int save_state);
+-void ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
+ int ahd_reset_channel(struct ahd_softc *ahd, char channel,
+ int initiate_reset);
+-int ahd_abort_scbs(struct ahd_softc *ahd, int target,
+- char channel, int lun, u_int tag,
+- role_t role, uint32_t status);
+-void ahd_restart(struct ahd_softc *ahd);
+-void ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo);
+-void ahd_handle_scb_status(struct ahd_softc *ahd,
+- struct scb *scb);
+-void ahd_handle_scsi_status(struct ahd_softc *ahd,
+- struct scb *scb);
+-void ahd_calc_residual(struct ahd_softc *ahd,
+- struct scb *scb);
+ /*************************** Utility Functions ********************************/
+-struct ahd_phase_table_entry*
+- ahd_lookup_phase_entry(int phase);
+ void ahd_compile_devinfo(struct ahd_devinfo *devinfo,
+ u_int our_id, u_int target,
+ u_int lun, char channel,
+@@ -1450,14 +1400,6 @@ void ahd_compile_devinfo(struct ahd_de
+ /************************** Transfer Negotiation ******************************/
+ void ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
+ u_int *ppr_options, u_int maxsync);
+-void ahd_validate_offset(struct ahd_softc *ahd,
+- struct ahd_initiator_tinfo *tinfo,
+- u_int period, u_int *offset,
+- int wide, role_t role);
+-void ahd_validate_width(struct ahd_softc *ahd,
+- struct ahd_initiator_tinfo *tinfo,
+- u_int *bus_width,
+- role_t role);
+ /*
+ * Negotiation types. These are used to qualify if we should renegotiate
+ * even if our goal and current transport parameters are identical.
+@@ -1486,11 +1428,6 @@ typedef enum {
+ AHD_QUEUE_TAGGED
+ } ahd_queue_alg;
+
+-void ahd_set_tags(struct ahd_softc *ahd,
+- struct scsi_cmnd *cmd,
+- struct ahd_devinfo *devinfo,
+- ahd_queue_alg alg);
+-
+ /**************************** Target Mode *************************************/
+ #ifdef AHD_TARGET_MODE
+ void ahd_send_lstate_events(struct ahd_softc *,
+@@ -1528,10 +1465,8 @@ extern uint32_t ahd_debug;
+ #define AHD_SHOW_INT_COALESCING 0x10000
+ #define AHD_DEBUG_SEQUENCER 0x20000
+ #endif
+-void ahd_print_scb(struct scb *scb);
+ void ahd_print_devinfo(struct ahd_softc *ahd,
+ struct ahd_devinfo *devinfo);
+-void ahd_dump_sglist(struct scb *scb);
+ void ahd_dump_card_state(struct ahd_softc *ahd);
+ int ahd_print_register(ahd_reg_parse_entry_t *table,
+ u_int num_entries,
+@@ -1540,5 +1475,4 @@ int ahd_print_register(ahd_reg_parse_e
+ u_int value,
+ u_int *cur_column,
+ u_int wrap_point);
+-void ahd_dump_scbs(struct ahd_softc *ahd);
+ #endif /* _AIC79XX_H_ */
+diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
+index 653818d..07a86a3 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_core.c
++++ b/drivers/scsi/aic7xxx/aic79xx_core.c
+@@ -52,7 +52,7 @@
+
+
+ /***************************** Lookup Tables **********************************/
+-char *ahd_chip_names[] =
++static char *ahd_chip_names[] =
+ {
+ "NONE",
+ "aic7901",
+@@ -237,10 +237,33 @@ static int ahd_handle_target_cmd(struct
+ struct target_cmd *cmd);
+ #endif
+
++static int ahd_abort_scbs(struct ahd_softc *ahd, int target,
++ char channel, int lun, u_int tag,
++ role_t role, uint32_t status);
++static void ahd_alloc_scbs(struct ahd_softc *ahd);
++static void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl,
++ u_int scbid);
++static void ahd_calc_residual(struct ahd_softc *ahd,
++ struct scb *scb);
++static void ahd_clear_critical_section(struct ahd_softc *ahd);
++static void ahd_clear_intstat(struct ahd_softc *ahd);
++static void ahd_enable_coalescing(struct ahd_softc *ahd,
++ int enable);
++static u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
++static void ahd_freeze_devq(struct ahd_softc *ahd,
++ struct scb *scb);
++static void ahd_handle_scb_status(struct ahd_softc *ahd,
++ struct scb *scb);
++static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
++static void ahd_shutdown(void *arg);
++static void ahd_update_coalescing_values(struct ahd_softc *ahd,
++ u_int timer,
++ u_int maxcmds,
++ u_int mincmds);
++static int ahd_verify_vpd_cksum(struct vpd_config *vpd);
++static int ahd_wait_seeprom(struct ahd_softc *ahd);
++
+ /******************************** Private Inlines *****************************/
+-static __inline void ahd_assert_atn(struct ahd_softc *ahd);
+-static __inline int ahd_currently_packetized(struct ahd_softc *ahd);
+-static __inline int ahd_set_active_fifo(struct ahd_softc *ahd);
+
+ static __inline void
+ ahd_assert_atn(struct ahd_softc *ahd)
+@@ -294,11 +317,44 @@ ahd_set_active_fifo(struct ahd_softc *ah
+ }
+ }
+
++static __inline void
++ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
++{
++ ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
++}
++
++/*
++ * Determine whether the sequencer reported a residual
++ * for this SCB/transaction.
++ */
++static __inline void
++ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
++{
++ uint32_t sgptr;
++
++ sgptr = ahd_le32toh(scb->hscb->sgptr);
++ if ((sgptr & SG_STATUS_VALID) != 0)
++ ahd_calc_residual(ahd, scb);
++}
++
++static __inline void
++ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
++{
++ uint32_t sgptr;
++
++ sgptr = ahd_le32toh(scb->hscb->sgptr);
++ if ((sgptr & SG_STATUS_VALID) != 0)
++ ahd_handle_scb_status(ahd, scb);
++ else
++ ahd_done(ahd, scb);
++}
++
++
+ /************************* Sequencer Execution Control ************************/
+ /*
+ * Restart the sequencer program from address zero
+ */
+-void
++static void
+ ahd_restart(struct ahd_softc *ahd)
+ {
+
+@@ -342,7 +398,7 @@ ahd_restart(struct ahd_softc *ahd)
+ ahd_unpause(ahd);
+ }
+
+-void
++static void
+ ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
+ {
+ ahd_mode_state saved_modes;
+@@ -366,7 +422,7 @@ ahd_clear_fifo(struct ahd_softc *ahd, u_
+ * Flush and completed commands that are sitting in the command
+ * complete queues down on the chip but have yet to be dma'ed back up.
+ */
+-void
++static void
+ ahd_flush_qoutfifo(struct ahd_softc *ahd)
+ {
+ struct scb *scb;
+@@ -905,6 +961,51 @@ ahd_handle_hwerrint(struct ahd_softc *ah
+ ahd_free(ahd);
+ }
+
++#ifdef AHD_DEBUG
++static void
++ahd_dump_sglist(struct scb *scb)
++{
++ int i;
++
++ if (scb->sg_count > 0) {
++ if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
++ struct ahd_dma64_seg *sg_list;
++
++ sg_list = (struct ahd_dma64_seg*)scb->sg_list;
++ for (i = 0; i < scb->sg_count; i++) {
++ uint64_t addr;
++ uint32_t len;
++
++ addr = ahd_le64toh(sg_list[i].addr);
++ len = ahd_le32toh(sg_list[i].len);
++ printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
++ i,
++ (uint32_t)((addr >> 32) & 0xFFFFFFFF),
++ (uint32_t)(addr & 0xFFFFFFFF),
++ sg_list[i].len & AHD_SG_LEN_MASK,
++ (sg_list[i].len & AHD_DMA_LAST_SEG)
++ ? " Last" : "");
++ }
++ } else {
++ struct ahd_dma_seg *sg_list;
++
++ sg_list = (struct ahd_dma_seg*)scb->sg_list;
++ for (i = 0; i < scb->sg_count; i++) {
++ uint32_t len;
++
++ len = ahd_le32toh(sg_list[i].len);
++ printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
++ i,
++ (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
++ ahd_le32toh(sg_list[i].addr),
++ len & AHD_SG_LEN_MASK,
++ len & AHD_DMA_LAST_SEG ? " Last" : "");
++ }
++ }
++ }
++}
++#endif /* AHD_DEBUG */
++
+ void
+ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
+ {
+@@ -1053,10 +1154,12 @@ ahd_handle_seqint(struct ahd_softc *ahd,
+ * If a target takes us into the command phase
+ * assume that it has been externally reset and
+ * has thus lost our previous packetized negotiation
+- * agreement.
+- * Revert to async/narrow transfers until we
+- * can renegotiate with the device and notify
+- * the OSM about the reset.
++ * agreement. Since we have not sent an identify
++ * message and may not have fully qualified the
++ * connection, we change our command to TUR, assert
++ * ATN and ABORT the task when we go to message in
++ * phase. The OSM will see the REQUEUE_REQUEST
++ * status and retry the command.
+ */
+ scbid = ahd_get_scbptr(ahd);
+ scb = ahd_lookup_scb(ahd, scbid);
+@@ -1083,7 +1186,28 @@ ahd_handle_seqint(struct ahd_softc *ahd,
+ ahd_set_syncrate(ahd, &devinfo, /*period*/0,
+ /*offset*/0, /*ppr_options*/0,
+ AHD_TRANS_ACTIVE, /*paused*/TRUE);
+- scb->flags |= SCB_EXTERNAL_RESET;
++ /* Hand-craft TUR command */
++ ahd_outb(ahd, SCB_CDB_STORE, 0);
++ ahd_outb(ahd, SCB_CDB_STORE+1, 0);
++ ahd_outb(ahd, SCB_CDB_STORE+2, 0);
++ ahd_outb(ahd, SCB_CDB_STORE+3, 0);
++ ahd_outb(ahd, SCB_CDB_STORE+4, 0);
++ ahd_outb(ahd, SCB_CDB_STORE+5, 0);
++ ahd_outb(ahd, SCB_CDB_LEN, 6);
++ scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE);
++ scb->hscb->control |= MK_MESSAGE;
++ ahd_outb(ahd, SCB_CONTROL, scb->hscb->control);
++ ahd_outb(ahd, MSG_OUT, HOST_MSG);
++ ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid);
++ /*
++ * The lun is 0, regardless of the SCB's lun
++ * as we have not sent an identify message.
++ */
++ ahd_outb(ahd, SAVED_LUN, 0);
++ ahd_outb(ahd, SEQ_FLAGS, 0);
++ ahd_assert_atn(ahd);
++ scb->flags &= ~SCB_PACKETIZED;
++ scb->flags |= SCB_ABORT|SCB_EXTERNAL_RESET;
+ ahd_freeze_devq(ahd, scb);
+ ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
+ ahd_freeze_scb(scb);
+@@ -1519,8 +1643,10 @@ ahd_handle_scsiint(struct ahd_softc *ahd
+ /*
+ * Ignore external resets after a bus reset.
+ */
+- if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE))
++ if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) {
++ ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
+ return;
++ }
+
+ /*
+ * Clear bus reset flag
+@@ -2200,6 +2326,22 @@ ahd_handle_nonpkt_busfree(struct ahd_sof
+ if (sent_msg == MSG_ABORT_TAG)
+ tag = SCB_GET_TAG(scb);
+
++ if ((scb->flags & SCB_EXTERNAL_RESET) != 0) {
++ /*
++ * This abort is in response to an
++ * unexpected switch to command phase
++ * for a packetized connection. Since
++ * the identify message was never sent,
++ * "saved lun" is 0. We really want to
++ * abort only the SCB that encountered
++ * this error, which could have a different
++ * lun. The SCB will be retried so the OS
++ * will see the UA after renegotiating to
++ * packetized.
++ */
++ tag = SCB_GET_TAG(scb);
++ saved_lun = scb->hscb->lun;
++ }
+ found = ahd_abort_scbs(ahd, target, 'A', saved_lun,
+ tag, ROLE_INITIATOR,
+ CAM_REQ_ABORTED);
+@@ -2523,7 +2665,7 @@ ahd_force_renegotiation(struct ahd_softc
+ }
+
+ #define AHD_MAX_STEPS 2000
+-void
++static void
+ ahd_clear_critical_section(struct ahd_softc *ahd)
+ {
+ ahd_mode_state saved_modes;
+@@ -2646,7 +2788,7 @@ ahd_clear_critical_section(struct ahd_so
+ /*
+ * Clear any pending interrupt status.
+ */
+-void
++static void
+ ahd_clear_intstat(struct ahd_softc *ahd)
+ {
+ AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+@@ -2677,6 +2819,8 @@ ahd_clear_intstat(struct ahd_softc *ahd)
+ #ifdef AHD_DEBUG
+ uint32_t ahd_debug = AHD_DEBUG_OPTS;
+ #endif
++
++#if 0
+ void
+ ahd_print_scb(struct scb *scb)
+ {
+@@ -2701,49 +2845,7 @@ ahd_print_scb(struct scb *scb)
+ SCB_GET_TAG(scb));
+ ahd_dump_sglist(scb);
+ }
+-
+-void
+-ahd_dump_sglist(struct scb *scb)
+-{
+- int i;
+-
+- if (scb->sg_count > 0) {
+- if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
+- struct ahd_dma64_seg *sg_list;
+-
+- sg_list = (struct ahd_dma64_seg*)scb->sg_list;
+- for (i = 0; i < scb->sg_count; i++) {
+- uint64_t addr;
+- uint32_t len;
+-
+- addr = ahd_le64toh(sg_list[i].addr);
+- len = ahd_le32toh(sg_list[i].len);
+- printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+- i,
+- (uint32_t)((addr >> 32) & 0xFFFFFFFF),
+- (uint32_t)(addr & 0xFFFFFFFF),
+- sg_list[i].len & AHD_SG_LEN_MASK,
+- (sg_list[i].len & AHD_DMA_LAST_SEG)
+- ? " Last" : "");
+- }
+- } else {
+- struct ahd_dma_seg *sg_list;
+-
+- sg_list = (struct ahd_dma_seg*)scb->sg_list;
+- for (i = 0; i < scb->sg_count; i++) {
+- uint32_t len;
+-
+- len = ahd_le32toh(sg_list[i].len);
+- printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+- i,
+- (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
+- ahd_le32toh(sg_list[i].addr),
+- len & AHD_SG_LEN_MASK,
+- len & AHD_DMA_LAST_SEG ? " Last" : "");
+- }
+- }
+- }
+-}
++#endif /* 0 */
+
+ /************************* Transfer Negotiation *******************************/
+ /*
+@@ -2850,14 +2952,14 @@ ahd_devlimited_syncrate(struct ahd_softc
+ transinfo = &tinfo->goal;
+ *ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN);
+ if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
+- maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2);
++ maxsync = max(maxsync, (u_int)AHD_SYNCRATE_ULTRA2);
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+ }
+ if (transinfo->period == 0) {
+ *period = 0;
+ *ppr_options = 0;
+ } else {
+- *period = MAX(*period, transinfo->period);
++ *period = max(*period, (u_int)transinfo->period);
+ ahd_find_syncrate(ahd, period, ppr_options, maxsync);
+ }
+ }
+@@ -2906,7 +3008,7 @@ ahd_find_syncrate(struct ahd_softc *ahd,
+ * Truncate the given synchronous offset to a value the
+ * current adapter type and syncrate are capable of.
+ */
+-void
++static void
+ ahd_validate_offset(struct ahd_softc *ahd,
+ struct ahd_initiator_tinfo *tinfo,
+ u_int period, u_int *offset, int wide,
+@@ -2924,12 +3026,12 @@ ahd_validate_offset(struct ahd_softc *ah
+ maxoffset = MAX_OFFSET_PACED;
+ } else
+ maxoffset = MAX_OFFSET_NON_PACED;
+- *offset = MIN(*offset, maxoffset);
++ *offset = min(*offset, maxoffset);
+ if (tinfo != NULL) {
+ if (role == ROLE_TARGET)
+- *offset = MIN(*offset, tinfo->user.offset);
++ *offset = min(*offset, (u_int)tinfo->user.offset);
+ else
+- *offset = MIN(*offset, tinfo->goal.offset);
++ *offset = min(*offset, (u_int)tinfo->goal.offset);
+ }
+ }
+
+@@ -2937,7 +3039,7 @@ ahd_validate_offset(struct ahd_softc *ah
+ * Truncate the given transfer width parameter to a value the
+ * current adapter type is capable of.
+ */
+-void
++static void
+ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
+ u_int *bus_width, role_t role)
+ {
+@@ -2955,9 +3057,9 @@ ahd_validate_width(struct ahd_softc *ahd
+ }
+ if (tinfo != NULL) {
+ if (role == ROLE_TARGET)
+- *bus_width = MIN(tinfo->user.width, *bus_width);
++ *bus_width = min((u_int)tinfo->user.width, *bus_width);
+ else
+- *bus_width = MIN(tinfo->goal.width, *bus_width);
++ *bus_width = min((u_int)tinfo->goal.width, *bus_width);
+ }
+ }
+
+@@ -3210,7 +3312,7 @@ ahd_set_width(struct ahd_softc *ahd, str
+ /*
+ * Update the current state of tagged queuing for a given target.
+ */
+-void
++static void
+ ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+ struct ahd_devinfo *devinfo, ahd_queue_alg alg)
+ {
+@@ -3466,7 +3568,7 @@ ahd_print_devinfo(struct ahd_softc *ahd,
+ devinfo->target, devinfo->lun);
+ }
+
+-struct ahd_phase_table_entry*
++static struct ahd_phase_table_entry*
+ ahd_lookup_phase_entry(int phase)
+ {
+ struct ahd_phase_table_entry *entry;
+@@ -5351,7 +5453,7 @@ ahd_free(struct ahd_softc *ahd)
+ return;
+ }
+
+-void
++static void
+ ahd_shutdown(void *arg)
+ {
+ struct ahd_softc *ahd;
+@@ -5480,7 +5582,7 @@ ahd_reset(struct ahd_softc *ahd, int rei
+ /*
+ * Determine the number of SCBs available on the controller
+ */
+-int
++static int
+ ahd_probe_scbs(struct ahd_softc *ahd) {
+ int i;
+
+@@ -5929,7 +6031,7 @@ ahd_free_scb(struct ahd_softc *ahd, stru
+ ahd_platform_scb_free(ahd, scb);
+ }
+
+-void
++static void
+ ahd_alloc_scbs(struct ahd_softc *ahd)
+ {
+ struct scb_data *scb_data;
+@@ -6057,9 +6159,9 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
+ #endif
+ }
+
+- newcount = MIN(scb_data->sense_left, scb_data->scbs_left);
+- newcount = MIN(newcount, scb_data->sgs_left);
+- newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
++ newcount = min(scb_data->sense_left, scb_data->scbs_left);
++ newcount = min(newcount, scb_data->sgs_left);
++ newcount = min(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
+ for (i = 0; i < newcount; i++) {
+ struct scb_platform_data *pdata;
+ u_int col_tag;
+@@ -6982,7 +7084,7 @@ ahd_intr_enable(struct ahd_softc *ahd, i
+ ahd_outb(ahd, HCNTRL, hcntrl);
+ }
+
+-void
++static void
+ ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
+ u_int mincmds)
+ {
+@@ -7000,7 +7102,7 @@ ahd_update_coalescing_values(struct ahd_
+ ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds);
+ }
+
+-void
++static void
+ ahd_enable_coalescing(struct ahd_softc *ahd, int enable)
+ {
+
+@@ -7070,6 +7172,7 @@ ahd_pause_and_flushwork(struct ahd_softc
+ ahd->flags &= ~AHD_ALL_INTERRUPTS;
+ }
+
++#if 0
+ int
+ ahd_suspend(struct ahd_softc *ahd)
+ {
+@@ -7083,7 +7186,9 @@ ahd_suspend(struct ahd_softc *ahd)
+ ahd_shutdown(ahd);
+ return (0);
+ }
++#endif /* 0 */
+
++#if 0
+ int
+ ahd_resume(struct ahd_softc *ahd)
+ {
+@@ -7093,6 +7198,7 @@ ahd_resume(struct ahd_softc *ahd)
+ ahd_restart(ahd);
+ return (0);
+ }
++#endif /* 0 */
+
+ /************************** Busy Target Table *********************************/
+ /*
+@@ -7125,7 +7231,7 @@ ahd_index_busy_tcl(struct ahd_softc *ahd
+ /*
+ * Return the untagged transaction id for a given target/channel lun.
+ */
+-u_int
++static u_int
+ ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
+ {
+ u_int scbid;
+@@ -7138,7 +7244,7 @@ ahd_find_busy_tcl(struct ahd_softc *ahd,
+ return (scbid);
+ }
+
+-void
++static void
+ ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid)
+ {
+ u_int scb_offset;
+@@ -7186,7 +7292,7 @@ ahd_match_scb(struct ahd_softc *ahd, str
+ return match;
+ }
+
+-void
++static void
+ ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
+ {
+ int target;
+@@ -7690,7 +7796,7 @@ ahd_add_scb_to_free_list(struct ahd_soft
+ * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer
+ * is paused before it is called.
+ */
+-int
++static int
+ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
+ int lun, u_int tag, role_t role, uint32_t status)
+ {
+@@ -7920,6 +8026,11 @@ ahd_reset_channel(struct ahd_softc *ahd,
+ ahd_clear_fifo(ahd, 1);
+
+ /*
++ * Clear SCSI interrupt status
++ */
++ ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
++
++ /*
+ * Reenable selections
+ */
+ ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
+@@ -7952,10 +8063,6 @@ ahd_reset_channel(struct ahd_softc *ahd,
+ }
+ }
+ #endif
+- /* Notify the XPT that a bus reset occurred */
+- ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
+- CAM_LUN_WILDCARD, AC_BUS_RESET);
+-
+ /*
+ * Revert to async/narrow transfers until we renegotiate.
+ */
+@@ -7977,6 +8084,10 @@ ahd_reset_channel(struct ahd_softc *ahd,
+ }
+ }
+
++ /* Notify the XPT that a bus reset occurred */
++ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
++ CAM_LUN_WILDCARD, AC_BUS_RESET);
++
+ ahd_restart(ahd);
+
+ return (found);
+@@ -8019,18 +8130,8 @@ ahd_stat_timer(void *arg)
+ }
+
+ /****************************** Status Processing *****************************/
+-void
+-ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
+-{
+- if (scb->hscb->shared_data.istatus.scsi_status != 0) {
+- ahd_handle_scsi_status(ahd, scb);
+- } else {
+- ahd_calc_residual(ahd, scb);
+- ahd_done(ahd, scb);
+- }
+-}
+
+-void
++static void
+ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
+ {
+ struct hardware_scb *hscb;
+@@ -8238,10 +8339,21 @@ ahd_handle_scsi_status(struct ahd_softc
+ }
+ }
+
++static void
++ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
++{
++ if (scb->hscb->shared_data.istatus.scsi_status != 0) {
++ ahd_handle_scsi_status(ahd, scb);
++ } else {
++ ahd_calc_residual(ahd, scb);
++ ahd_done(ahd, scb);
++ }
++}
++
+ /*
+ * Calculate the residual for a just completed SCB.
+ */
+-void
++static void
+ ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
+ {
+ struct hardware_scb *hscb;
+@@ -8668,7 +8780,7 @@ ahd_resolve_seqaddr(struct ahd_softc *ah
+ if (skip_addr > i) {
+ int end_addr;
+
+- end_addr = MIN(address, skip_addr);
++ end_addr = min(address, skip_addr);
+ address_offset += end_addr - i;
+ i = skip_addr;
+ } else {
+@@ -9092,6 +9204,7 @@ ahd_dump_card_state(struct ahd_softc *ah
+ ahd_unpause(ahd);
+ }
+
++#if 0
+ void
+ ahd_dump_scbs(struct ahd_softc *ahd)
+ {
+@@ -9117,6 +9230,7 @@ ahd_dump_scbs(struct ahd_softc *ahd)
+ ahd_set_scbptr(ahd, saved_scb_index);
+ ahd_restore_modes(ahd, saved_modes);
+ }
++#endif /* 0 */
+
+ /**************************** Flexport Logic **********************************/
+ /*
+@@ -9219,7 +9333,7 @@ ahd_write_seeprom(struct ahd_softc *ahd,
+ /*
+ * Wait ~100us for the serial eeprom to satisfy our request.
+ */
+-int
++static int
+ ahd_wait_seeprom(struct ahd_softc *ahd)
+ {
+ int cnt;
+@@ -9237,7 +9351,7 @@ ahd_wait_seeprom(struct ahd_softc *ahd)
+ * Validate the two checksums in the per_channel
+ * vital product data struct.
+ */
+-int
++static int
+ ahd_verify_vpd_cksum(struct vpd_config *vpd)
+ {
+ int i;
+@@ -9316,6 +9430,24 @@ ahd_release_seeprom(struct ahd_softc *ah
+ /* Currently a no-op */
+ }
+
++/*
++ * Wait at most 2 seconds for flexport arbitration to succeed.
++ */
++static int
++ahd_wait_flexport(struct ahd_softc *ahd)
++{
++ int cnt;
++
++ AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
++ cnt = 1000000 * 2 / 5;
++ while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
++ ahd_delay(5);
++
++ if (cnt == 0)
++ return (ETIMEDOUT);
++ return (0);
++}
++
+ int
+ ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value)
+ {
+@@ -9357,24 +9489,6 @@ ahd_read_flexport(struct ahd_softc *ahd,
+ return (0);
+ }
+
+-/*
+- * Wait at most 2 seconds for flexport arbitration to succeed.
+- */
+-int
+-ahd_wait_flexport(struct ahd_softc *ahd)
+-{
+- int cnt;
+-
+- AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+- cnt = 1000000 * 2 / 5;
+- while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
+- ahd_delay(5);
+-
+- if (cnt == 0)
+- return (ETIMEDOUT);
+- return (0);
+-}
+-
+ /************************* Target Mode ****************************************/
+ #ifdef AHD_TARGET_MODE
+ cam_status
+diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
+index 8ad3ce9..2ceb67f 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
++++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
+@@ -418,10 +418,6 @@ ahd_targetcmd_offset(struct ahd_softc *a
+ }
+
+ /*********************** Miscelaneous Support Functions ***********************/
+-static __inline void ahd_complete_scb(struct ahd_softc *ahd,
+- struct scb *scb);
+-static __inline void ahd_update_residual(struct ahd_softc *ahd,
+- struct scb *scb);
+ static __inline struct ahd_initiator_tinfo *
+ ahd_fetch_transinfo(struct ahd_softc *ahd,
+ char channel, u_int our_id,
+@@ -467,32 +463,6 @@ static __inline uint32_t
+ ahd_get_sense_bufaddr(struct ahd_softc *ahd,
+ struct scb *scb);
+
+-static __inline void
+-ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
+-{
+- uint32_t sgptr;
+-
+- sgptr = ahd_le32toh(scb->hscb->sgptr);
+- if ((sgptr & SG_STATUS_VALID) != 0)
+- ahd_handle_scb_status(ahd, scb);
+- else
+- ahd_done(ahd, scb);
+-}
+-
+-/*
+- * Determine whether the sequencer reported a residual
+- * for this SCB/transaction.
+- */
+-static __inline void
+-ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
+-{
+- uint32_t sgptr;
+-
+- sgptr = ahd_le32toh(scb->hscb->sgptr);
+- if ((sgptr & SG_STATUS_VALID) != 0)
+- ahd_calc_residual(ahd, scb);
+-}
+-
+ /*
+ * Return pointers to the transfer negotiation information
+ * for the specified our_id/remote_id pair.
+@@ -527,7 +497,8 @@ ahd_inw(struct ahd_softc *ahd, u_int por
+ * or have other side effects when the low byte is
+ * read.
+ */
+- return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
++ uint16_t r = ahd_inb(ahd, port+1) << 8;
++ return r | ahd_inb(ahd, port);
+ }
+
+ static __inline void
+diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
+index 998999c..9bfcca5 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
++++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
+@@ -293,7 +293,7 @@ static uint32_t aic79xx_seltime;
+ * force all outstanding transactions to be serviced prior to a new
+ * transaction.
+ */
+-uint32_t aic79xx_periodic_otag;
++static uint32_t aic79xx_periodic_otag;
+
+ /* Some storage boxes are using an LSI chip which has a bug making it
+ * impossible to use aic79xx Rev B chip in 320 speeds. The following
+@@ -321,7 +321,7 @@ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_VERSION(AIC79XX_DRIVER_VERSION);
+ module_param(aic79xx, charp, 0444);
+ MODULE_PARM_DESC(aic79xx,
+-"period delimited, options string.\n"
++"period-delimited options string:\n"
+ " verbose Enable verbose/diagnostic logging\n"
+ " allow_memio Allow device registers to be memory mapped\n"
+ " debug Bitmask of debug values to enable\n"
+@@ -346,7 +346,7 @@ MODULE_PARM_DESC(aic79xx,
+ " Shorten the selection timeout to 128ms\n"
+ "\n"
+ " options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
+-"\n");
++);
+
+ static void ahd_linux_handle_scsi_status(struct ahd_softc *,
+ struct scsi_device *,
+@@ -646,7 +646,7 @@ ahd_linux_dev_reset(struct scsi_cmnd *cm
+ struct ahd_initiator_tinfo *tinfo;
+ struct ahd_tmode_tstate *tstate;
+ unsigned long flags;
+- DECLARE_COMPLETION(done);
++ DECLARE_COMPLETION_ONSTACK(done);
+
+ reset_scb = NULL;
+ paused = FALSE;
+@@ -773,6 +773,7 @@ struct scsi_host_template aic79xx_driver
+ #endif
+ .can_queue = AHD_MAX_QUEUE,
+ .this_id = -1,
++ .max_sectors = 8192,
+ .cmd_per_lun = 2,
+ .use_clustering = ENABLE_CLUSTERING,
+ .slave_alloc = ahd_linux_slave_alloc,
+@@ -1557,7 +1558,7 @@ ahd_linux_run_command(struct ahd_softc *
+ * SCSI controller interrupt handler.
+ */
+ irqreturn_t
+-ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
++ahd_linux_isr(int irq, void *dev_id)
+ {
+ struct ahd_softc *ahd;
+ u_long flags;
+@@ -1813,9 +1814,9 @@ ahd_linux_handle_scsi_status(struct ahd_
+ u_int sense_offset;
+
+ if (scb->flags & SCB_SENSE) {
+- sense_size = MIN(sizeof(struct scsi_sense_data)
++ sense_size = min(sizeof(struct scsi_sense_data)
+ - ahd_get_sense_residual(scb),
+- sizeof(cmd->sense_buffer));
++ (u_long)sizeof(cmd->sense_buffer));
+ sense_offset = 0;
+ } else {
+ /*
+@@ -1824,7 +1825,8 @@ ahd_linux_handle_scsi_status(struct ahd_
+ */
+ siu = (struct scsi_status_iu_header *)
+ scb->sense_data;
+- sense_size = MIN(scsi_4btoul(siu->sense_length),
++ sense_size = min_t(size_t,
++ scsi_4btoul(siu->sense_length),
+ sizeof(cmd->sense_buffer));
+ sense_offset = SIU_SENSE_OFFSET(siu);
+ }
+@@ -2251,7 +2253,7 @@ done:
+ if (paused)
+ ahd_unpause(ahd);
+ if (wait) {
+- DECLARE_COMPLETION(done);
++ DECLARE_COMPLETION_ONSTACK(done);
+
+ ahd->platform_data->eh_done = &done;
+ ahd_unlock(ahd, &flags);
+@@ -2634,8 +2636,22 @@ static void ahd_linux_set_pcomp_en(struc
+ pcomp ? "Enable" : "Disable");
+ #endif
+
+- if (pcomp)
++ if (pcomp) {
++ uint8_t precomp;
++
++ if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
++ struct ahd_linux_iocell_opts *iocell_opts;
++
++ iocell_opts = &aic79xx_iocell_info[ahd->unit];
++ precomp = iocell_opts->precomp;
++ } else {
++ precomp = AIC79XX_DEFAULT_PRECOMP;
++ }
+ ppr_options |= MSG_EXT_PPR_PCOMP_EN;
++ AHD_SET_PRECOMP(ahd, precomp);
++ } else {
++ AHD_SET_PRECOMP(ahd, 0);
++ }
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+@@ -2678,7 +2694,25 @@ static void ahd_linux_set_hold_mcs(struc
+ ahd_unlock(ahd, &flags);
+ }
+
++static void ahd_linux_get_signalling(struct Scsi_Host *shost)
++{
++ struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
++ unsigned long flags;
++ u8 mode;
++
++ ahd_lock(ahd, &flags);
++ ahd_pause(ahd);
++ mode = ahd_inb(ahd, SBLKCTL);
++ ahd_unpause(ahd);
++ ahd_unlock(ahd, &flags);
+
++ if (mode & ENAB40)
++ spi_signalling(shost) = SPI_SIGNAL_LVD;
++ else if (mode & ENAB20)
++ spi_signalling(shost) = SPI_SIGNAL_SE;
++ else
++ spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
++}
+
+ static struct spi_function_template ahd_linux_transport_functions = {
+ .set_offset = ahd_linux_set_offset,
+@@ -2703,6 +2737,7 @@ static struct spi_function_template ahd_
+ .show_pcomp_en = 1,
+ .set_hold_mcs = ahd_linux_set_hold_mcs,
+ .show_hold_mcs = 1,
++ .get_signalling = ahd_linux_get_signalling,
+ };
+
+ static int __init
+diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
+index 601340d..3a67fc5 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
++++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
+@@ -506,9 +506,6 @@ struct info_str {
+ int pos;
+ };
+
+-void ahd_format_transinfo(struct info_str *info,
+- struct ahd_transinfo *tinfo);
+-
+ /******************************** Locking *************************************/
+ static __inline void
+ ahd_lockinit(struct ahd_softc *ahd)
+@@ -582,8 +579,6 @@ ahd_unlock(struct ahd_softc *ahd, unsign
+ #define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */
+ #define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */
+
+-extern struct pci_driver aic79xx_pci_driver;
+-
+ typedef enum
+ {
+ AHD_POWER_STATE_D0,
+@@ -862,7 +857,7 @@ int ahd_platform_abort_scbs(struct ahd_s
+ char channel, int lun, u_int tag,
+ role_t role, uint32_t status);
+ irqreturn_t
+- ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
++ ahd_linux_isr(int irq, void *dev_id);
+ void ahd_done(struct ahd_softc*, struct scb*);
+ void ahd_send_async(struct ahd_softc *, char channel,
+ u_int target, u_int lun, ac_code);
+diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+index 50a41ed..2001fe8 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
++++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+@@ -82,7 +82,7 @@ static struct pci_device_id ahd_linux_pc
+
+ MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
+
+-struct pci_driver aic79xx_pci_driver = {
++static struct pci_driver aic79xx_pci_driver = {
+ .name = "aic79xx",
+ .probe = ahd_linux_pci_dev_probe,
+ .remove = ahd_linux_pci_dev_remove,
+@@ -198,7 +198,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *
+ int
+ ahd_linux_pci_init(void)
+ {
+- return (pci_module_init(&aic79xx_pci_driver));
++ return pci_register_driver(&aic79xx_pci_driver);
+ }
+
+ void
+diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
+index 14850f3..c077358 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
++++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
+@@ -97,7 +97,7 @@ static ahd_device_setup_t ahd_aic7901A_s
+ static ahd_device_setup_t ahd_aic7902_setup;
+ static ahd_device_setup_t ahd_aic790X_setup;
+
+-struct ahd_pci_identity ahd_pci_ident_table [] =
++static struct ahd_pci_identity ahd_pci_ident_table [] =
+ {
+ /* aic7901 based controllers */
+ {
+@@ -201,7 +201,7 @@ struct ahd_pci_identity ahd_pci_ident_ta
+ }
+ };
+
+-const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
++static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
+
+ #define DEVCONFIG 0x40
+ #define PCIXINITPAT 0x0000E000ul
+@@ -245,6 +245,7 @@ static int ahd_check_extport(struct ahd_
+ static void ahd_configure_termination(struct ahd_softc *ahd,
+ u_int adapter_control);
+ static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
++static void ahd_pci_intr(struct ahd_softc *ahd);
+
+ struct ahd_pci_identity *
+ ahd_find_pci_device(ahd_dev_softc_t pci)
+@@ -757,7 +758,7 @@ static const char *pci_status_strings[]
+ "%s: Address or Write Phase Parity Error Detected in %s.\n"
+ };
+
+-void
++static void
+ ahd_pci_intr(struct ahd_softc *ahd)
+ {
+ uint8_t pci_status[8];
+diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
+index c5f0ee5..6b28beb 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
++++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
+@@ -136,7 +136,7 @@ copy_info(struct info_str *info, char *f
+ return (len);
+ }
+
+-void
++static void
+ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
+ {
+ u_int speed;
+diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
+index 62ff8c3..954c7c2 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx.h
++++ b/drivers/scsi/aic7xxx/aic7xxx.h
+@@ -54,14 +54,6 @@ struct scb_platform_data;
+ struct seeprom_descriptor;
+
+ /****************************** Useful Macros *********************************/
+-#ifndef MAX
+-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+-#endif
+-
+-#ifndef MIN
+-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+-#endif
+-
+ #ifndef TRUE
+ #define TRUE 1
+ #endif
+@@ -1135,8 +1127,6 @@ struct ahc_pci_identity {
+ char *name;
+ ahc_device_setup_t *setup;
+ };
+-extern struct ahc_pci_identity ahc_pci_ident_table[];
+-extern const u_int ahc_num_pci_devs;
+
+ /***************************** VL/EISA Declarations ***************************/
+ struct aic7770_identity {
+@@ -1289,6 +1279,7 @@ typedef enum {
+ } ahc_queue_alg;
+
+ void ahc_set_tags(struct ahc_softc *ahc,
++ struct scsi_cmnd *cmd,
+ struct ahc_devinfo *devinfo,
+ ahc_queue_alg alg);
+
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
+index 93e4e40..50ef785 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
++++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
+@@ -1671,7 +1671,7 @@ ahc_devlimited_syncrate(struct ahc_softc
+ transinfo = &tinfo->goal;
+ *ppr_options &= transinfo->ppr_options;
+ if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
+- maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
++ maxsync = max(maxsync, (u_int)AHC_SYNCRATE_ULTRA2);
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+ }
+ if (transinfo->period == 0) {
+@@ -1679,7 +1679,7 @@ ahc_devlimited_syncrate(struct ahc_softc
+ *ppr_options = 0;
+ return (NULL);
+ }
+- *period = MAX(*period, transinfo->period);
++ *period = max(*period, (u_int)transinfo->period);
+ return (ahc_find_syncrate(ahc, period, ppr_options, maxsync));
+ }
+
+@@ -1804,12 +1804,12 @@ ahc_validate_offset(struct ahc_softc *ah
+ else
+ maxoffset = MAX_OFFSET_8BIT;
+ }
+- *offset = MIN(*offset, maxoffset);
++ *offset = min(*offset, maxoffset);
+ if (tinfo != NULL) {
+ if (role == ROLE_TARGET)
+- *offset = MIN(*offset, tinfo->user.offset);
++ *offset = min(*offset, (u_int)tinfo->user.offset);
+ else
+- *offset = MIN(*offset, tinfo->goal.offset);
++ *offset = min(*offset, (u_int)tinfo->goal.offset);
+ }
+ }
+
+@@ -1835,9 +1835,9 @@ ahc_validate_width(struct ahc_softc *ahc
+ }
+ if (tinfo != NULL) {
+ if (role == ROLE_TARGET)
+- *bus_width = MIN(tinfo->user.width, *bus_width);
++ *bus_width = min((u_int)tinfo->user.width, *bus_width);
+ else
+- *bus_width = MIN(tinfo->goal.width, *bus_width);
++ *bus_width = min((u_int)tinfo->goal.width, *bus_width);
+ }
+ }
+
+@@ -1986,7 +1986,7 @@ ahc_set_syncrate(struct ahc_softc *ahc,
+ tinfo->curr.ppr_options = ppr_options;
+
+ ahc_send_async(ahc, devinfo->channel, devinfo->target,
+- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
++ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
+ if (bootverbose) {
+ if (offset != 0) {
+ printf("%s: target %d synchronous at %sMHz%s, "
+@@ -2056,7 +2056,7 @@ ahc_set_width(struct ahc_softc *ahc, str
+ tinfo->curr.width = width;
+
+ ahc_send_async(ahc, devinfo->channel, devinfo->target,
+- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
++ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
+ if (bootverbose) {
+ printf("%s: target %d using %dbit transfers\n",
+ ahc_name(ahc), devinfo->target,
+@@ -2074,12 +2074,14 @@ ahc_set_width(struct ahc_softc *ahc, str
+ * Update the current state of tagged queuing for a given target.
+ */
+ void
+-ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+- ahc_queue_alg alg)
++ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
++ struct ahc_devinfo *devinfo, ahc_queue_alg alg)
+ {
+- ahc_platform_set_tags(ahc, devinfo, alg);
++ struct scsi_device *sdev = cmd->device;
++
++ ahc_platform_set_tags(ahc, sdev, devinfo, alg);
+ ahc_send_async(ahc, devinfo->channel, devinfo->target,
+- devinfo->lun, AC_TRANSFER_NEG, &alg);
++ devinfo->lun, AC_TRANSFER_NEG);
+ }
+
+ /*
+@@ -3489,7 +3491,7 @@ ahc_handle_msg_reject(struct ahc_softc *
+ printf("(%s:%c:%d:%d): refuses tagged commands. "
+ "Performing non-tagged I/O\n", ahc_name(ahc),
+ devinfo->channel, devinfo->target, devinfo->lun);
+- ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE);
++ ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE);
+ mask = ~0x23;
+ } else {
+ printf("(%s:%c:%d:%d): refuses %s tagged commands. "
+@@ -3497,7 +3499,7 @@ ahc_handle_msg_reject(struct ahc_softc *
+ ahc_name(ahc), devinfo->channel, devinfo->target,
+ devinfo->lun, tag_type == MSG_ORDERED_TASK
+ ? "ordered" : "head of queue");
+- ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC);
++ ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_BASIC);
+ mask = ~0x03;
+ }
+
+@@ -3763,7 +3765,7 @@ ahc_handle_devreset(struct ahc_softc *ah
+
+ if (status != CAM_SEL_TIMEOUT)
+ ahc_send_async(ahc, devinfo->channel, devinfo->target,
+- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
++ CAM_LUN_WILDCARD, AC_SENT_BDR);
+
+ if (message != NULL
+ && (verbose_level <= bootverbose))
+@@ -4406,7 +4408,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
+ physaddr = sg_map->sg_physaddr;
+
+ newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
+- newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
++ newcount = min(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
+ for (i = 0; i < newcount; i++) {
+ struct scb_platform_data *pdata;
+ #ifndef __linux__
+@@ -6018,7 +6020,7 @@ ahc_reset_channel(struct ahc_softc *ahc,
+ #endif
+ /* Notify the XPT that a bus reset occurred */
+ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
+- CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
++ CAM_LUN_WILDCARD, AC_BUS_RESET);
+
+ /*
+ * Revert to async/narrow transfers until we renegotiate.
+@@ -6442,7 +6444,7 @@ ahc_download_instr(struct ahc_softc *ahc
+ if (skip_addr > i) {
+ int end_addr;
+
+- end_addr = MIN(address, skip_addr);
++ end_addr = min(address, skip_addr);
+ address_offset += end_addr - i;
+ i = skip_addr;
+ } else {
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
+index 2cc8a17..8e1954c 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h
++++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
+@@ -300,7 +300,8 @@ ahc_fetch_transinfo(struct ahc_softc *ah
+ static __inline uint16_t
+ ahc_inw(struct ahc_softc *ahc, u_int port)
+ {
+- return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
++ uint16_t r = ahc_inb(ahc, port+1) << 8;
++ return r | ahc_inb(ahc, port);
+ }
+
+ static __inline void
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
+index aa4be8a..660f26e 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
++++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
+@@ -328,7 +328,7 @@ static uint32_t aic7xxx_seltime;
+ * force all outstanding transactions to be serviced prior to a new
+ * transaction.
+ */
+-uint32_t aic7xxx_periodic_otag;
++static uint32_t aic7xxx_periodic_otag;
+
+ /*
+ * Module information and settable options.
+@@ -341,7 +341,7 @@ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
+ module_param(aic7xxx, charp, 0444);
+ MODULE_PARM_DESC(aic7xxx,
+-"period delimited, options string.\n"
++"period-delimited options string:\n"
+ " verbose Enable verbose/diagnostic logging\n"
+ " allow_memio Allow device registers to be memory mapped\n"
+ " debug Bitmask of debug values to enable\n"
+@@ -512,7 +512,6 @@ ahc_linux_target_alloc(struct scsi_targe
+ struct seeprom_config *sc = ahc->seep_config;
+ unsigned long flags;
+ struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget);
+- struct ahc_linux_target *targ = scsi_transport_target_data(starget);
+ unsigned short scsirate;
+ struct ahc_devinfo devinfo;
+ struct ahc_initiator_tinfo *tinfo;
+@@ -533,7 +532,6 @@ ahc_linux_target_alloc(struct scsi_targe
+ BUG_ON(*ahc_targp != NULL);
+
+ *ahc_targp = starget;
+- memset(targ, 0, sizeof(*targ));
+
+ if (sc) {
+ int maxsync = AHC_SYNCRATE_DT;
+@@ -594,14 +592,11 @@ ahc_linux_slave_alloc(struct scsi_device
+ struct ahc_softc *ahc =
+ *((struct ahc_softc **)sdev->host->hostdata);
+ struct scsi_target *starget = sdev->sdev_target;
+- struct ahc_linux_target *targ = scsi_transport_target_data(starget);
+ struct ahc_linux_device *dev;
+
+ if (bootverbose)
+ printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
+
+- BUG_ON(targ->sdev[sdev->lun] != NULL);
+-
+ dev = scsi_transport_device_data(sdev);
+ memset(dev, 0, sizeof(*dev));
+
+@@ -618,8 +613,6 @@ ahc_linux_slave_alloc(struct scsi_device
+ */
+ dev->maxtags = 0;
+
+- targ->sdev[sdev->lun] = sdev;
+-
+ spi_period(starget) = 0;
+
+ return 0;
+@@ -644,22 +637,6 @@ ahc_linux_slave_configure(struct scsi_de
+ return 0;
+ }
+
+-static void
+-ahc_linux_slave_destroy(struct scsi_device *sdev)
+-{
+- struct ahc_softc *ahc;
+- struct ahc_linux_device *dev = scsi_transport_device_data(sdev);
+- struct ahc_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);
+-
+- ahc = *((struct ahc_softc **)sdev->host->hostdata);
+- if (bootverbose)
+- printf("%s: Slave Destroy %d\n", ahc_name(ahc), sdev->id);
+-
+- BUG_ON(dev->active);
+-
+- targ->sdev[sdev->lun] = NULL;
+-}
+-
+ #if defined(__i386__)
+ /*
+ * Return the disk geometry for the given SCSI device.
+@@ -777,11 +754,11 @@ struct scsi_host_template aic7xxx_driver
+ #endif
+ .can_queue = AHC_MAX_QUEUE,
+ .this_id = -1,
++ .max_sectors = 8192,
+ .cmd_per_lun = 2,
+ .use_clustering = ENABLE_CLUSTERING,
+ .slave_alloc = ahc_linux_slave_alloc,
+ .slave_configure = ahc_linux_slave_configure,
+- .slave_destroy = ahc_linux_slave_destroy,
+ .target_alloc = ahc_linux_target_alloc,
+ .target_destroy = ahc_linux_target_destroy,
+ };
+@@ -1203,21 +1180,13 @@ void
+ ahc_platform_free(struct ahc_softc *ahc)
+ {
+ struct scsi_target *starget;
+- int i, j;
++ int i;
+
+ if (ahc->platform_data != NULL) {
+ /* destroy all of the device and target objects */
+ for (i = 0; i < AHC_NUM_TARGETS; i++) {
+ starget = ahc->platform_data->starget[i];
+ if (starget != NULL) {
+- for (j = 0; j < AHC_NUM_LUNS; j++) {
+- struct ahc_linux_target *targ =
+- scsi_transport_target_data(starget);
+-
+- if (targ->sdev[j] == NULL)
+- continue;
+- targ->sdev[j] = NULL;
+- }
+ ahc->platform_data->starget[i] = NULL;
+ }
+ }
+@@ -1251,24 +1220,13 @@ ahc_platform_freeze_devq(struct ahc_soft
+ }
+
+ void
+-ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+- ahc_queue_alg alg)
++ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
++ struct ahc_devinfo *devinfo, ahc_queue_alg alg)
+ {
+- struct scsi_target *starget;
+- struct ahc_linux_target *targ;
+ struct ahc_linux_device *dev;
+- struct scsi_device *sdev;
+- u_int target_offset;
+ int was_queuing;
+ int now_queuing;
+
+- target_offset = devinfo->target;
+- if (devinfo->channel != 'A')
+- target_offset += 8;
+- starget = ahc->platform_data->starget[target_offset];
+- targ = scsi_transport_target_data(starget);
+- BUG_ON(targ == NULL);
+- sdev = targ->sdev[devinfo->lun];
+ if (sdev == NULL)
+ return;
+ dev = scsi_transport_device_data(sdev);
+@@ -1401,11 +1359,15 @@ ahc_linux_device_queue_depth(struct scsi
+ tags = ahc_linux_user_tagdepth(ahc, &devinfo);
+ if (tags != 0 && sdev->tagged_supported != 0) {
+
+- ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
++ ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_TAGGED);
++ ahc_send_async(ahc, devinfo.channel, devinfo.target,
++ devinfo.lun, AC_TRANSFER_NEG);
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("Tagged Queuing enabled. Depth %d\n", tags);
+ } else {
+- ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
++ ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE);
++ ahc_send_async(ahc, devinfo.channel, devinfo.target,
++ devinfo.lun, AC_TRANSFER_NEG);
+ }
+ }
+
+@@ -1608,7 +1570,7 @@ ahc_linux_run_command(struct ahc_softc *
+ * SCSI controller interrupt handler.
+ */
+ irqreturn_t
+-ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
++ahc_linux_isr(int irq, void *dev_id)
+ {
+ struct ahc_softc *ahc;
+ u_long flags;
+@@ -1629,7 +1591,7 @@ ahc_platform_flushwork(struct ahc_softc
+
+ void
+ ahc_send_async(struct ahc_softc *ahc, char channel,
+- u_int target, u_int lun, ac_code code, void *arg)
++ u_int target, u_int lun, ac_code code)
+ {
+ switch (code) {
+ case AC_TRANSFER_NEG:
+@@ -1875,9 +1837,9 @@ ahc_linux_handle_scsi_status(struct ahc_
+ if (scb->flags & SCB_SENSE) {
+ u_int sense_size;
+
+- sense_size = MIN(sizeof(struct scsi_sense_data)
++ sense_size = min(sizeof(struct scsi_sense_data)
+ - ahc_get_sense_residual(scb),
+- sizeof(cmd->sense_buffer));
++ (u_long)sizeof(cmd->sense_buffer));
+ memcpy(cmd->sense_buffer,
+ ahc_get_sense_buf(ahc, scb), sense_size);
+ if (sense_size < sizeof(cmd->sense_buffer))
+@@ -1946,7 +1908,7 @@ ahc_linux_handle_scsi_status(struct ahc_
+ }
+ ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);
+ ahc_set_scsi_status(scb, SCSI_STATUS_OK);
+- ahc_platform_set_tags(ahc, &devinfo,
++ ahc_platform_set_tags(ahc, sdev, &devinfo,
+ (dev->flags & AHC_DEV_Q_BASIC)
+ ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
+ break;
+@@ -1957,7 +1919,7 @@ ahc_linux_handle_scsi_status(struct ahc_
+ */
+ dev->openings = 1;
+ ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);
+- ahc_platform_set_tags(ahc, &devinfo,
++ ahc_platform_set_tags(ahc, sdev, &devinfo,
+ (dev->flags & AHC_DEV_Q_BASIC)
+ ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
+ break;
+@@ -2335,7 +2297,7 @@ done:
+ if (paused)
+ ahc_unpause(ahc);
+ if (wait) {
+- DECLARE_COMPLETION(done);
++ DECLARE_COMPLETION_ONSTACK(done);
+
+ ahc->platform_data->eh_done = &done;
+ ahc_unlock(ahc, &flags);
+@@ -2539,15 +2501,28 @@ static void ahc_linux_set_iu(struct scsi
+ static void ahc_linux_get_signalling(struct Scsi_Host *shost)
+ {
+ struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata;
+- u8 mode = ahc_inb(ahc, SBLKCTL);
++ unsigned long flags;
++ u8 mode;
+
+- if (mode & ENAB40)
+- spi_signalling(shost) = SPI_SIGNAL_LVD;
+- else if (mode & ENAB20)
++ if (!(ahc->features & AHC_ULTRA2)) {
++ /* non-LVD chipset, may not have SBLKCTL reg */
+ spi_signalling(shost) =
+ ahc->features & AHC_HVD ?
+ SPI_SIGNAL_HVD :
+ SPI_SIGNAL_SE;
++ return;
++ }
++
++ ahc_lock(ahc, &flags);
++ ahc_pause(ahc);
++ mode = ahc_inb(ahc, SBLKCTL);
++ ahc_unpause(ahc);
++ ahc_unlock(ahc, &flags);
++
++ if (mode & ENAB40)
++ spi_signalling(shost) = SPI_SIGNAL_LVD;
++ else if (mode & ENAB20)
++ spi_signalling(shost) = SPI_SIGNAL_SE;
+ else
+ spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
+ }
+@@ -2586,8 +2561,6 @@ ahc_linux_init(void)
+ if (!ahc_linux_transport_template)
+ return -ENODEV;
+
+- scsi_transport_reserve_target(ahc_linux_transport_template,
+- sizeof(struct ahc_linux_target));
+ scsi_transport_reserve_device(ahc_linux_transport_template,
+ sizeof(struct ahc_linux_device));
+
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
+index d42a71e..85ae5d8 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
++++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
+@@ -256,7 +256,6 @@ typedef enum {
+ AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */
+ } ahc_linux_dev_flags;
+
+-struct ahc_linux_target;
+ struct ahc_linux_device {
+ /*
+ * The number of transactions currently
+@@ -329,12 +328,6 @@ struct ahc_linux_device {
+ #define AHC_OTAG_THRESH 500
+ };
+
+-struct ahc_linux_target {
+- struct scsi_device *sdev[AHC_NUM_LUNS];
+- struct ahc_transinfo last_tinfo;
+- struct ahc_softc *ahc;
+-};
+-
+ /********************* Definitions Required by the Core ***********************/
+ /*
+ * Number of SG segments we require. So long as the S/G segments for
+@@ -533,8 +526,6 @@ ahc_unlock(struct ahc_softc *ahc, unsign
+ #define PCIR_SUBVEND_0 0x2c
+ #define PCIR_SUBDEV_0 0x2e
+
+-extern struct pci_driver aic7xxx_pci_driver;
+-
+ typedef enum
+ {
+ AHC_POWER_STATE_D0,
+@@ -824,17 +815,17 @@ ahc_freeze_scb(struct scb *scb)
+ }
+ }
+
+-void ahc_platform_set_tags(struct ahc_softc *ahc,
++void ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
+ struct ahc_devinfo *devinfo, ahc_queue_alg);
+ int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
+ char channel, int lun, u_int tag,
+ role_t role, uint32_t status);
+ irqreturn_t
+- ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
++ ahc_linux_isr(int irq, void *dev_id);
+ void ahc_platform_flushwork(struct ahc_softc *ahc);
+ void ahc_done(struct ahc_softc*, struct scb*);
+ void ahc_send_async(struct ahc_softc *, char channel,
+- u_int target, u_int lun, ac_code, void *);
++ u_int target, u_int lun, ac_code);
+ void ahc_print_path(struct ahc_softc *, struct scb *);
+ void ahc_platform_dump_card_state(struct ahc_softc *ahc);
+
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+index 7e42f07..ea5687d 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
++++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+@@ -130,7 +130,7 @@ static struct pci_device_id ahc_linux_pc
+
+ MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
+
+-struct pci_driver aic7xxx_pci_driver = {
++static struct pci_driver aic7xxx_pci_driver = {
+ .name = "aic7xxx",
+ .probe = ahc_linux_pci_dev_probe,
+ .remove = ahc_linux_pci_dev_remove,
+@@ -246,8 +246,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *
+ int
+ ahc_linux_pci_init(void)
+ {
+- /* Translate error or zero return into zero or one */
+- return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1;
++ return pci_register_driver(&aic7xxx_pci_driver);
+ }
+
+ void
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
+index 63cab2d..09c8172 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
++++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
+@@ -168,7 +168,7 @@ static ahc_device_setup_t ahc_aha394XX_s
+ static ahc_device_setup_t ahc_aha494XX_setup;
+ static ahc_device_setup_t ahc_aha398XX_setup;
+
+-struct ahc_pci_identity ahc_pci_ident_table [] =
++static struct ahc_pci_identity ahc_pci_ident_table [] =
+ {
+ /* aic7850 based controllers */
+ {
+@@ -559,7 +559,7 @@ struct ahc_pci_identity ahc_pci_ident_ta
+ }
+ };
+
+-const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table);
++static const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table);
+
+ #define AHC_394X_SLOT_CHANNEL_A 4
+ #define AHC_394X_SLOT_CHANNEL_B 5
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
+index 5914b4a..99e5443 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
++++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
+@@ -182,7 +182,6 @@ ahc_dump_target_state(struct ahc_softc *
+ u_int our_id, char channel, u_int target_id,
+ u_int target_offset)
+ {
+- struct ahc_linux_target *targ;
+ struct scsi_target *starget;
+ struct ahc_initiator_tinfo *tinfo;
+ struct ahc_tmode_tstate *tstate;
+@@ -198,7 +197,6 @@ ahc_dump_target_state(struct ahc_softc *
+ starget = ahc->platform_data->starget[target_offset];
+ if (!starget)
+ return;
+- targ = scsi_transport_target_data(starget);
+
+ copy_info(info, "\tGoal: ");
+ ahc_format_transinfo(info, &tinfo->goal);
+@@ -208,7 +206,7 @@ ahc_dump_target_state(struct ahc_softc *
+ for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+ struct scsi_device *sdev;
+
+- sdev = targ->sdev[lun];
++ sdev = scsi_device_lookup_by_target(starget, lun);
+
+ if (sdev == NULL)
+ continue;
+@@ -383,11 +381,11 @@ ahc_linux_proc_info(struct Scsi_Host *sh
+ }
+ copy_info(&info, "\n");
+
+- max_targ = 15;
++ max_targ = 16;
+ if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
+- max_targ = 7;
++ max_targ = 8;
+
+- for (i = 0; i <= max_targ; i++) {
++ for (i = 0; i < max_targ; i++) {
+ u_int our_id;
+ u_int target_id;
+ char channel;
+diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
+index 3f85b5e..46eed10 100644
+--- a/drivers/scsi/aic7xxx_old.c
++++ b/drivers/scsi/aic7xxx_old.c
+@@ -249,8 +249,6 @@
+ #include <linux/stat.h>
+ #include <linux/slab.h> /* for kmalloc() */
+
+-#include <linux/config.h> /* for CONFIG_PCI */
+-
+ #define AIC7XXX_C_VERSION "5.2.6"
+
+ #define ALL_TARGETS -1
+@@ -782,24 +780,26 @@ typedef enum {
+ } ahc_bugs;
+
+ struct aic7xxx_scb {
+- struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
+- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
+- struct aic7xxx_scb *q_next; /* next scb in queue */
+- volatile scb_flag_type flags; /* current state of scb */
+- struct hw_scatterlist *sg_list; /* SG list in adapter format */
+- unsigned char tag_action;
+- unsigned char sg_count;
+- unsigned char *sense_cmd; /*
+- * Allocate 6 characters for
+- * sense command.
+- */
+- unsigned char *cmnd;
+- unsigned int sg_length; /* We init this during buildscb so we
+- * don't have to calculate anything
+- * during underflow/overflow/stat code
+- */
+- void *kmalloc_ptr;
+- struct aic7xxx_scb_dma *scb_dma;
++ struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
++ struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */
++ struct aic7xxx_scb *q_next; /* next scb in queue */
++ volatile scb_flag_type flags; /* current state of scb */
++ struct hw_scatterlist *sg_list; /* SG list in adapter format */
++ unsigned char tag_action;
++ unsigned char sg_count;
++ unsigned char *sense_cmd; /*
++ * Allocate 6 characters for
++ * sense command.
++ */
++ unsigned char *cmnd;
++ unsigned int sg_length; /*
++ * We init this during
++ * buildscb so we don't have
++ * to calculate anything during
++ * underflow/overflow/stat code
++ */
++ void *kmalloc_ptr;
++ struct aic7xxx_scb_dma *scb_dma;
+ };
+
+ /*
+@@ -920,79 +920,77 @@ struct aic7xxx_host {
+ * We are grouping things here....first, items that get either read or
+ * written with nearly every interrupt
+ */
+- volatile long flags;
+- ahc_feature features; /* chip features */
+- unsigned long base; /* card base address */
+- volatile unsigned char __iomem *maddr; /* memory mapped address */
+- unsigned long isr_count; /* Interrupt count */
+- unsigned long spurious_int;
+- scb_data_type *scb_data;
+- struct aic7xxx_cmd_queue {
+- Scsi_Cmnd *head;
+- Scsi_Cmnd *tail;
+- } completeq;
++ volatile long flags;
++ ahc_feature features; /* chip features */
++ unsigned long base; /* card base address */
++ volatile unsigned char __iomem *maddr; /* memory mapped address */
++ unsigned long isr_count; /* Interrupt count */
++ unsigned long spurious_int;
++ scb_data_type *scb_data;
++ struct aic7xxx_cmd_queue {
++ struct scsi_cmnd *head;
++ struct scsi_cmnd *tail;
++ } completeq;
+
+- /*
+- * Things read/written on nearly every entry into aic7xxx_queue()
+- */
+- volatile scb_queue_type waiting_scbs;
+- unsigned char unpause; /* unpause value for HCNTRL */
+- unsigned char pause; /* pause value for HCNTRL */
+- volatile unsigned char qoutfifonext;
+- volatile unsigned char activescbs; /* active scbs */
+- volatile unsigned char max_activescbs;
+- volatile unsigned char qinfifonext;
+- volatile unsigned char *untagged_scbs;
+- volatile unsigned char *qoutfifo;
+- volatile unsigned char *qinfifo;
+-
+- unsigned char dev_last_queue_full[MAX_TARGETS];
+- unsigned char dev_last_queue_full_count[MAX_TARGETS];
+- unsigned short ultraenb; /* Gets downloaded to card as a
+- bitmap */
+- unsigned short discenable; /* Gets downloaded to card as a
+- bitmap */
+- transinfo_type user[MAX_TARGETS];
+-
+- unsigned char msg_buf[13]; /* The message for the target */
+- unsigned char msg_type;
++ /*
++ * Things read/written on nearly every entry into aic7xxx_queue()
++ */
++ volatile scb_queue_type waiting_scbs;
++ unsigned char unpause; /* unpause value for HCNTRL */
++ unsigned char pause; /* pause value for HCNTRL */
++ volatile unsigned char qoutfifonext;
++ volatile unsigned char activescbs; /* active scbs */
++ volatile unsigned char max_activescbs;
++ volatile unsigned char qinfifonext;
++ volatile unsigned char *untagged_scbs;
++ volatile unsigned char *qoutfifo;
++ volatile unsigned char *qinfifo;
++
++ unsigned char dev_last_queue_full[MAX_TARGETS];
++ unsigned char dev_last_queue_full_count[MAX_TARGETS];
++ unsigned short ultraenb; /* Gets downloaded to card as a bitmap */
++ unsigned short discenable; /* Gets downloaded to card as a bitmap */
++ transinfo_type user[MAX_TARGETS];
++
++ unsigned char msg_buf[13]; /* The message for the target */
++ unsigned char msg_type;
+ #define MSG_TYPE_NONE 0x00
+ #define MSG_TYPE_INITIATOR_MSGOUT 0x01
+ #define MSG_TYPE_INITIATOR_MSGIN 0x02
+- unsigned char msg_len; /* Length of message */
+- unsigned char msg_index; /* Index into msg_buf array */
+-
++ unsigned char msg_len; /* Length of message */
++ unsigned char msg_index; /* Index into msg_buf array */
+
+- /*
+- * We put the less frequently used host structure items after the more
+- * frequently used items to try and ease the burden on the cache subsystem.
+- * These entries are not *commonly* accessed, whereas the preceding entries
+- * are accessed very often.
+- */
+
+- unsigned int irq; /* IRQ for this adapter */
+- int instance; /* aic7xxx instance number */
+- int scsi_id; /* host adapter SCSI ID */
+- int scsi_id_b; /* channel B for twin adapters */
+- unsigned int bios_address;
+- int board_name_index;
+- unsigned short bios_control; /* bios control - SEEPROM */
+- unsigned short adapter_control; /* adapter control - SEEPROM */
+- struct pci_dev *pdev;
+- unsigned char pci_bus;
+- unsigned char pci_device_fn;
+- struct seeprom_config sc;
+- unsigned short sc_type;
+- unsigned short sc_size;
+- struct aic7xxx_host *next; /* allow for multiple IRQs */
+- struct Scsi_Host *host; /* pointer to scsi host */
+- struct list_head aic_devs; /* all aic_dev structs on host */
+- int host_no; /* SCSI host number */
+- unsigned long mbase; /* I/O memory address */
+- ahc_chip chip; /* chip type */
+- ahc_bugs bugs;
+- dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
++ /*
++ * We put the less frequently used host structure items
++ * after the more frequently used items to try and ease
++ * the burden on the cache subsystem.
++ * These entries are not *commonly* accessed, whereas
++ * the preceding entries are accessed very often.
++ */
+
++ unsigned int irq; /* IRQ for this adapter */
++ int instance; /* aic7xxx instance number */
++ int scsi_id; /* host adapter SCSI ID */
++ int scsi_id_b; /* channel B for twin adapters */
++ unsigned int bios_address;
++ int board_name_index;
++ unsigned short bios_control; /* bios control - SEEPROM */
++ unsigned short adapter_control; /* adapter control - SEEPROM */
++ struct pci_dev *pdev;
++ unsigned char pci_bus;
++ unsigned char pci_device_fn;
++ struct seeprom_config sc;
++ unsigned short sc_type;
++ unsigned short sc_size;
++ struct aic7xxx_host *next; /* allow for multiple IRQs */
++ struct Scsi_Host *host; /* pointer to scsi host */
++ struct list_head aic_devs; /* all aic_dev structs on host */
++ int host_no; /* SCSI host number */
++ unsigned long mbase; /* I/O memory address */
++ ahc_chip chip; /* chip type */
++ ahc_bugs bugs;
++ dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
+ };
+
+ /*
+@@ -1273,7 +1271,7 @@ static void aic7xxx_set_syncrate(struct
+ static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel,
+ int lun, unsigned int width, unsigned int type,
+ struct aic_dev_data *aic_dev);
+-static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
++static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd);
+ static void aic7xxx_print_card(struct aic7xxx_host *p);
+ static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
+ static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
+@@ -2628,7 +2626,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host
+ * we're finished. This function queues the completed commands.
+ *-F*************************************************************************/
+ static void
+-aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
++aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
+ {
+ aic7xxx_position(cmd) = SCB_LIST_NULL;
+ cmd->host_scribble = (char *)p->completeq.head;
+@@ -2642,18 +2640,16 @@ aic7xxx_queue_cmd_complete(struct aic7xx
+ * Description:
+ * Process the completed command queue.
+ *-F*************************************************************************/
+-static void
+-aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
++static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
+ {
+- Scsi_Cmnd *cmd;
+-
+- while (p->completeq.head != NULL)
+- {
+- cmd = p->completeq.head;
+- p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+- cmd->host_scribble = NULL;
+- cmd->scsi_done(cmd);
+- }
++ struct scsi_cmnd *cmd;
++
++ while (p->completeq.head != NULL) {
++ cmd = p->completeq.head;
++ p->completeq.head = (struct scsi_cmnd *) cmd->host_scribble;
++ cmd->host_scribble = NULL;
++ cmd->scsi_done(cmd);
++ }
+ }
+
+ /*+F*************************************************************************
+@@ -2689,11 +2685,11 @@ aic7xxx_free_scb(struct aic7xxx_host *p,
+ static void
+ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+ {
+- Scsi_Cmnd *cmd = scb->cmd;
+- struct aic_dev_data *aic_dev = cmd->device->hostdata;
+- int tindex = TARGET_INDEX(cmd);
+- struct aic7xxx_scb *scbp;
+- unsigned char queue_depth;
++ struct scsi_cmnd *cmd = scb->cmd;
++ struct aic_dev_data *aic_dev = cmd->device->hostdata;
++ int tindex = TARGET_INDEX(cmd);
++ struct aic7xxx_scb *scbp;
++ unsigned char queue_depth;
+
+ if (cmd->use_sg > 1)
+ {
+@@ -2864,7 +2860,7 @@ aic7xxx_done(struct aic7xxx_host *p, str
+ aic_dev->r_total++;
+ ptr = aic_dev->r_bins;
+ }
+- if(cmd->device->simple_tags && cmd->request->flags & REQ_HARDBARRIER)
++ if(cmd->device->simple_tags && cmd->request->cmd_flags & REQ_HARDBARRIER)
+ {
+ aic_dev->barrier_total++;
+ if(scb->tag_action == MSG_ORDERED_Q_TAG)
+@@ -2893,7 +2889,7 @@ aic7xxx_done(struct aic7xxx_host *p, str
+ * aic7xxx_run_done_queue
+ *
+ * Description:
+- * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
++ * Calls the aic7xxx_done() for the scsi_cmnd of each scb in the
+ * aborted list, and adds each scb to the free list. If complete
+ * is TRUE, we also process the commands complete list.
+ *-F*************************************************************************/
+@@ -3828,9 +3824,9 @@ aic7xxx_construct_wdtr(struct aic7xxx_ho
+ static void
+ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+ {
+- struct aic7xxx_hwscb *hscb;
+- Scsi_Cmnd *cmd;
+- int actual, i;
++ struct aic7xxx_hwscb *hscb;
++ struct scsi_cmnd *cmd;
++ int actual, i;
+
+ cmd = scb->cmd;
+ hscb = scb->hscb;
+@@ -4221,20 +4217,20 @@ aic7xxx_handle_seqint(struct aic7xxx_hos
+
+ case BAD_STATUS:
+ {
+- unsigned char scb_index;
+- struct aic7xxx_hwscb *hscb;
+- Scsi_Cmnd *cmd;
+-
+- /* The sequencer will notify us when a command has an error that
+- * would be of interest to the kernel. This allows us to leave
+- * the sequencer running in the common case of command completes
+- * without error. The sequencer will have DMA'd the SCB back
+- * up to us, so we can reference the drivers SCB array.
+- *
+- * Set the default return value to 0 indicating not to send
+- * sense. The sense code will change this if needed and this
+- * reduces code duplication.
+- */
++ unsigned char scb_index;
++ struct aic7xxx_hwscb *hscb;
++ struct scsi_cmnd *cmd;
++
++ /* The sequencer will notify us when a command has an error that
++ * would be of interest to the kernel. This allows us to leave
++ * the sequencer running in the common case of command completes
++ * without error. The sequencer will have DMA'd the SCB back
++ * up to us, so we can reference the drivers SCB array.
++ *
++ * Set the default return value to 0 indicating not to send
++ * sense. The sense code will change this if needed and this
++ * reduces code duplication.
++ */
+ aic_outb(p, 0, RETURN_1);
+ scb_index = aic_inb(p, SCB_TAG);
+ if (scb_index > p->scb_data->numscbs)
+@@ -5802,9 +5798,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_ho
+ }
+ else if ((status & SELTO) != 0)
+ {
+- unsigned char scbptr;
+- unsigned char nextscb;
+- Scsi_Cmnd *cmd;
++ unsigned char scbptr;
++ unsigned char nextscb;
++ struct scsi_cmnd *cmd;
+
+ scbptr = aic_inb(p, WAITING_SCBH);
+ if (scbptr > p->scb_data->maxhscbs)
+@@ -5943,11 +5939,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_ho
+ /*
+ * Determine the bus phase and queue an appropriate message.
+ */
+- char *phase;
+- Scsi_Cmnd *cmd;
+- unsigned char mesg_out = MSG_NOOP;
+- unsigned char lastphase = aic_inb(p, LASTPHASE);
+- unsigned char sstat2 = aic_inb(p, SSTAT2);
++ char *phase;
++ struct scsi_cmnd *cmd;
++ unsigned char mesg_out = MSG_NOOP;
++ unsigned char lastphase = aic_inb(p, LASTPHASE);
++ unsigned char sstat2 = aic_inb(p, SSTAT2);
+
+ cmd = scb->cmd;
+ switch (lastphase)
+@@ -6250,10 +6246,10 @@ aic7xxx_check_scbs(struct aic7xxx_host *
+ static void
+ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
+ {
+- struct aic7xxx_scb *scb = NULL;
+- struct aic_dev_data *aic_dev;
+- Scsi_Cmnd *cmd;
+- unsigned char scb_index, tindex;
++ struct aic7xxx_scb *scb = NULL;
++ struct aic_dev_data *aic_dev;
++ struct scsi_cmnd *cmd;
++ unsigned char scb_index, tindex;
+
+ #ifdef AIC7XXX_VERBOSE_DEBUGGING
+ if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
+@@ -6349,12 +6345,12 @@ aic7xxx_handle_command_completion_intr(s
+ * SCSI controller interrupt handler.
+ *-F*************************************************************************/
+ static void
+-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
++aic7xxx_isr(void *dev_id)
+ {
+ struct aic7xxx_host *p;
+ unsigned char intstat;
+
+- p = (struct aic7xxx_host *)dev_id;
++ p = dev_id;
+
+ /*
+ * Just a few sanity checks. Make sure that we have an int pending.
+@@ -6481,7 +6477,7 @@ aic7xxx_isr(int irq, void *dev_id, struc
+ * anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+ static irqreturn_t
+-do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
++do_aic7xxx_isr(int irq, void *dev_id)
+ {
+ unsigned long cpu_flags;
+ struct aic7xxx_host *p;
+@@ -6493,7 +6489,7 @@ do_aic7xxx_isr(int irq, void *dev_id, st
+ p->flags |= AHC_IN_ISR;
+ do
+ {
+- aic7xxx_isr(irq, dev_id, regs);
++ aic7xxx_isr(dev_id);
+ } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
+ aic7xxx_done_cmds_complete(p);
+ aic7xxx_run_waiting_queues(p);
+@@ -9196,7 +9192,7 @@ aic7xxx_detect(struct scsi_host_template
+ for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++)
+ {
+ pdev = NULL;
+- while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
++ while ((pdev = pci_get_device(aic_pdevs[i].vendor_id,
+ aic_pdevs[i].device_id,
+ pdev))) {
+ if (pci_enable_device(pdev))
+@@ -9653,6 +9649,9 @@ aic7xxx_detect(struct scsi_host_template
+ */
+ aic7xxx_configure_bugs(temp_p);
+
++ /* Hold a pci device reference */
++ pci_dev_get(temp_p->pdev);
++
+ if ( list_p == NULL )
+ {
+ list_p = current_p = temp_p;
+@@ -10130,9 +10129,8 @@ skip_pci_controller:
+ * Description:
+ * Build a SCB.
+ *-F*************************************************************************/
+-static void
+-aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
+- struct aic7xxx_scb *scb)
++static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
++ struct aic7xxx_scb *scb)
+ {
+ unsigned short mask;
+ struct aic7xxx_hwscb *hscb;
+@@ -10157,7 +10155,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
+ /* We always force TEST_UNIT_READY to untagged */
+ if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags)
+ {
+- if (req->flags & REQ_HARDBARRIER)
++ if (req->cmd_flags & REQ_HARDBARRIER)
+ {
+ if(sdptr->ordered_tags)
+ {
+@@ -10284,8 +10282,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
+ * Description:
+ * Queue a SCB to the controller.
+ *-F*************************************************************************/
+-static int
+-aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
++static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+ {
+ struct aic7xxx_host *p;
+ struct aic7xxx_scb *scb;
+@@ -10318,11 +10315,11 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)
+ }
+ scb->cmd = cmd;
+
+- /*
+- * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+- * is set up properly, and the parity error flag is reset, then send
+- * the SCB to the sequencer and watch the fun begin.
+- */
++ /*
++ * Make sure the scsi_cmnd pointer is saved, the struct it points to
++ * is set up properly, and the parity error flag is reset, then send
++ * the SCB to the sequencer and watch the fun begin.
++ */
+ aic7xxx_position(cmd) = scb->hscb->tag;
+ cmd->scsi_done = fn;
+ cmd->result = DID_OK;
+@@ -10355,8 +10352,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)
+ * aborted, then we will reset the channel and have all devices renegotiate.
+ * Returns an enumerated type that indicates the status of the operation.
+ *-F*************************************************************************/
+-static int
+-__aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
++static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
+ {
+ struct aic7xxx_host *p;
+ struct aic7xxx_scb *scb;
+@@ -10381,7 +10377,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cm
+
+ hscb = scb->hscb;
+
+- aic7xxx_isr(p->irq, (void *)p, NULL);
++ aic7xxx_isr(p);
+ aic7xxx_done_cmds_complete(p);
+ /* If the command was already complete or just completed, then we didn't
+ * do a reset, return FAILED */
+@@ -10549,8 +10545,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cm
+ return SUCCESS;
+ }
+
+-static int
+-aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
++static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
+ {
+ int rc;
+
+@@ -10569,8 +10564,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
+ * Description:
+ * Abort the current SCSI command(s).
+ *-F*************************************************************************/
+-static void
+-aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
++static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
+ {
+
+ printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+@@ -10594,8 +10588,7 @@ aic7xxx_panic_abort(struct aic7xxx_host
+ * Description:
+ * Abort the current SCSI command(s).
+ *-F*************************************************************************/
+-static int
+-__aic7xxx_abort(Scsi_Cmnd *cmd)
++static int __aic7xxx_abort(struct scsi_cmnd *cmd)
+ {
+ struct aic7xxx_scb *scb = NULL;
+ struct aic7xxx_host *p;
+@@ -10615,7 +10608,7 @@ __aic7xxx_abort(Scsi_Cmnd *cmd)
+ else
+ return FAILED;
+
+- aic7xxx_isr(p->irq, (void *)p, NULL);
++ aic7xxx_isr(p);
+ aic7xxx_done_cmds_complete(p);
+ /* If the command was already complete or just completed, then we didn't
+ * do a reset, return FAILED */
+@@ -10812,8 +10805,7 @@ success:
+ return SUCCESS;
+ }
+
+-static int
+-aic7xxx_abort(Scsi_Cmnd *cmd)
++static int aic7xxx_abort(struct scsi_cmnd *cmd)
+ {
+ int rc;
+
+@@ -10835,8 +10827,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
+ * DEVICE RESET message - on the offending target before pulling
+ * the SCSI bus reset line.
+ *-F*************************************************************************/
+-static int
+-aic7xxx_reset(Scsi_Cmnd *cmd)
++static int aic7xxx_reset(struct scsi_cmnd *cmd)
+ {
+ struct aic7xxx_scb *scb;
+ struct aic7xxx_host *p;
+@@ -10872,7 +10863,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd)
+
+ while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+ {
+- aic7xxx_isr(p->irq, p, (void *)NULL );
++ aic7xxx_isr(p);
+ pause_sequencer(p);
+ }
+ aic7xxx_done_cmds_complete(p);
+@@ -10989,8 +10980,10 @@ aic7xxx_release(struct Scsi_Host *host)
+ if(!p->pdev)
+ release_region(p->base, MAXREG - MINREG);
+ #ifdef CONFIG_PCI
+- else
++ else {
+ pci_release_regions(p->pdev);
++ pci_dev_put(p->pdev);
++ }
+ #endif
+ prev = NULL;
+ next = first_aic7xxx;
+diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
+new file mode 100644
+index 0000000..c83fe75
+--- /dev/null
++++ b/drivers/scsi/aic94xx/Kconfig
+@@ -0,0 +1,42 @@
++#
++# Kernel configuration file for aic94xx SAS/SATA driver.
++#
++# Copyright (c) 2005 Adaptec, Inc. All rights reserved.
++# Copyright (c) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++#
++# This file is licensed under GPLv2.
++#
++# This file is part of the aic94xx driver.
++#
++# The aic94xx driver 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 of the
++# License.
++#
++# The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++#
++#
++
++config SCSI_AIC94XX
++ tristate "Adaptec AIC94xx SAS/SATA support"
++ depends on PCI
++ select SCSI_SAS_LIBSAS
++ select FW_LOADER
++ help
++ This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
++ AIC94xx chip based host adapters.
++
++config AIC94XX_DEBUG
++ bool "Compile in debug mode"
++ default y
++ depends on SCSI_AIC94XX
++ help
++ Compiles the aic94xx driver in debug mode. In debug mode,
++ the driver prints some messages to the console.
+diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
+new file mode 100644
+index 0000000..e6b7012
+--- /dev/null
++++ b/drivers/scsi/aic94xx/Makefile
+@@ -0,0 +1,39 @@
++#
++# Makefile for Adaptec aic94xx SAS/SATA driver.
++#
++# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++# Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++#
++# This file is licensed under GPLv2.
++#
++# This file is part of the the aic94xx driver.
++#
++# The aic94xx driver 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 of the
++# License.
++#
++# The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++
++ifeq ($(CONFIG_AIC94XX_DEBUG),y)
++ EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT
++endif
++
++obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
++aic94xx-y += aic94xx_init.o \
++ aic94xx_hwi.o \
++ aic94xx_reg.o \
++ aic94xx_sds.o \
++ aic94xx_seq.o \
++ aic94xx_dump.o \
++ aic94xx_scb.o \
++ aic94xx_dev.o \
++ aic94xx_tmf.o \
++ aic94xx_task.o
+diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
+new file mode 100644
+index 0000000..71a031d
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx.h
+@@ -0,0 +1,114 @@
++/*
++ * Aic94xx SAS/SATA driver header file.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * $Id: //depot/aic94xx/aic94xx.h#31 $
++ */
++
++#ifndef _AIC94XX_H_
++#define _AIC94XX_H_
++
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <scsi/libsas.h>
++
++#define ASD_DRIVER_NAME "aic94xx"
++#define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver"
++
++#define asd_printk(fmt, ...) printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__)
++
++#ifdef ASD_ENTER_EXIT
++#define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
++ __FUNCTION__)
++#define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
++ __FUNCTION__)
++#else
++#define ENTER
++#define EXIT
++#endif
++
++#ifdef ASD_DEBUG
++#define ASD_DPRINTK asd_printk
++#else
++#define ASD_DPRINTK(fmt, ...)
++#endif
++
++/* 2*ITNL timeout + 1 second */
++#define AIC94XX_SCB_TIMEOUT (5*HZ)
++
++extern kmem_cache_t *asd_dma_token_cache;
++extern kmem_cache_t *asd_ascb_cache;
++extern char sas_addr_str[2*SAS_ADDR_SIZE + 1];
++
++static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
++{
++ int i;
++ for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2)
++ snprintf(p, 3, "%02X", sas_addr[i]);
++ *p = '\0';
++}
++
++static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p)
++{
++ int i;
++ for (i = 0; i < SAS_ADDR_SIZE; i++) {
++ u8 h, l;
++ if (!*p)
++ break;
++ h = isdigit(*p) ? *p-'0' : *p-'A'+10;
++ p++;
++ l = isdigit(*p) ? *p-'0' : *p-'A'+10;
++ p++;
++ sas_addr[i] = (h<<4) | l;
++ }
++}
++
++struct asd_ha_struct;
++struct asd_ascb;
++
++int asd_read_ocm(struct asd_ha_struct *asd_ha);
++int asd_read_flash(struct asd_ha_struct *asd_ha);
++
++int asd_dev_found(struct domain_device *dev);
++void asd_dev_gone(struct domain_device *dev);
++
++void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
++
++int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
++
++/* ---------- TMFs ---------- */
++int asd_abort_task(struct sas_task *);
++int asd_abort_task_set(struct domain_device *, u8 *lun);
++int asd_clear_aca(struct domain_device *, u8 *lun);
++int asd_clear_task_set(struct domain_device *, u8 *lun);
++int asd_lu_reset(struct domain_device *, u8 *lun);
++int asd_query_task(struct sas_task *);
++
++/* ---------- Adapter and Port management ---------- */
++int asd_clear_nexus_port(struct asd_sas_port *port);
++int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
++
++/* ---------- Phy Management ---------- */
++int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg);
++
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
+new file mode 100644
+index 0000000..6f8901b
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_dev.c
+@@ -0,0 +1,353 @@
++/*
++ * Aic94xx SAS/SATA DDB management
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * $Id: //depot/aic94xx/aic94xx_dev.c#21 $
++ */
++
++#include "aic94xx.h"
++#include "aic94xx_hwi.h"
++#include "aic94xx_reg.h"
++#include "aic94xx_sas.h"
++
++#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \
++ (_ha)->hw_prof.max_ddbs)
++#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
++#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
++
++static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
++{
++ unsigned long flags;
++ int ddb, i;
++
++ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
++ ddb = FIND_FREE_DDB(asd_ha);
++ if (ddb >= asd_ha->hw_prof.max_ddbs) {
++ ddb = -ENOMEM;
++ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
++ goto out;
++ }
++ SET_DDB(ddb, asd_ha);
++ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
++
++ for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
++ asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
++out:
++ return ddb;
++}
++
++#define INIT_CONN_TAG offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag)
++#define DEST_SAS_ADDR offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr)
++#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head)
++#define DDB_TYPE offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type)
++#define CONN_MASK offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask)
++#define DDB_TARG_FLAGS offsetof(struct asd_ddb_ssp_smp_target_port, flags)
++#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2)
++#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail)
++#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail)
++#define SISTER_DDB offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb)
++#define MAX_CCONN offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn)
++#define NUM_CTX offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts)
++#define ATA_CMD_SCBPTR offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr)
++#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask)
++#define NUM_SATA_TAGS offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags)
++#define SATA_STATUS offsetof(struct asd_ddb_stp_sata_target_port, sata_status)
++#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr)
++#define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout)
++
++static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
++{
++ unsigned long flags;
++
++ if (!ddb || ddb >= 0xFFFF)
++ return;
++ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
++ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
++ CLEAR_DDB(ddb, asd_ha);
++ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
++}
++
++static inline void asd_set_ddb_type(struct domain_device *dev)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ int ddb = (int) (unsigned long) dev->lldd_dev;
++
++ if (dev->dev_type == SATA_PM_PORT)
++ asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT);
++ else if (dev->tproto)
++ asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET);
++ else
++ asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR);
++}
++
++static int asd_init_sata_tag_ddb(struct domain_device *dev)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ int ddb, i;
++
++ ddb = asd_get_ddb(asd_ha);
++ if (ddb < 0)
++ return ddb;
++
++ for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2)
++ asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
++
++ asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
++ SISTER_DDB, ddb);
++ return 0;
++}
++
++static inline int asd_init_sata(struct domain_device *dev)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ int ddb = (int) (unsigned long) dev->lldd_dev;
++ u32 qdepth = 0;
++ int res = 0;
++
++ asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
++ if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
++ dev->sata_dev.identify_device &&
++ dev->sata_dev.identify_device[10] != 0) {
++ u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
++ u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
++
++ if (w76 & 0x100) /* NCQ? */
++ qdepth = (w75 & 0x1F) + 1;
++ asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
++ (1<<qdepth)-1);
++ asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
++ }
++ if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
++ dev->dev_type == SATA_PM_PORT) {
++ struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
++ dev->frame_rcvd;
++ asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
++ }
++ asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
++ if (qdepth > 0)
++ res = asd_init_sata_tag_ddb(dev);
++ return res;
++}
++
++static int asd_init_target_ddb(struct domain_device *dev)
++{
++ int ddb, i;
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ u8 flags = 0;
++
++ ddb = asd_get_ddb(asd_ha);
++ if (ddb < 0)
++ return ddb;
++
++ dev->lldd_dev = (void *) (unsigned long) ddb;
++
++ asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE);
++ asd_ddbsite_write_byte(asd_ha, ddb, 1, 0);
++ asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF);
++ for (i = 0; i < SAS_ADDR_SIZE; i++)
++ asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i,
++ dev->sas_addr[i]);
++ asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF);
++ asd_set_ddb_type(dev);
++ asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask);
++ if (dev->port->oob_mode != SATA_OOB_MODE) {
++ flags |= OPEN_REQUIRED;
++ if ((dev->dev_type == SATA_DEV) ||
++ (dev->tproto & SAS_PROTO_STP)) {
++ struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
++ if (rps_resp->frame_type == SMP_RESPONSE &&
++ rps_resp->function == SMP_REPORT_PHY_SATA &&
++ rps_resp->result == SMP_RESP_FUNC_ACC) {
++ if (rps_resp->rps.affil_valid)
++ flags |= STP_AFFIL_POL;
++ if (rps_resp->rps.affil_supp)
++ flags |= SUPPORTS_AFFIL;
++ }
++ } else {
++ flags |= CONCURRENT_CONN_SUPP;
++ if (!dev->parent &&
++ (dev->dev_type == EDGE_DEV ||
++ dev->dev_type == FANOUT_DEV))
++ asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
++ 4);
++ else
++ asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
++ dev->pathways);
++ asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1);
++ }
++ }
++ if (dev->dev_type == SATA_PM)
++ flags |= SATA_MULTIPORT;
++ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
++
++ flags = 0;
++ if (dev->tproto & SAS_PROTO_STP)
++ flags |= STP_CL_POL_NO_TX;
++ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
++
++ asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF);
++ asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
++ asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
++
++ if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
++ i = asd_init_sata(dev);
++ if (i < 0) {
++ asd_free_ddb(asd_ha, ddb);
++ return i;
++ }
++ }
++
++ if (dev->dev_type == SAS_END_DEV) {
++ struct sas_end_device *rdev = rphy_to_end_device(dev->rphy);
++ if (rdev->I_T_nexus_loss_timeout > 0)
++ asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
++ min(rdev->I_T_nexus_loss_timeout,
++ (u16)ITNL_TIMEOUT_CONST));
++ else
++ asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
++ (u16)ITNL_TIMEOUT_CONST);
++ }
++ return 0;
++}
++
++static int asd_init_sata_pm_table_ddb(struct domain_device *dev)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ int ddb, i;
++
++ ddb = asd_get_ddb(asd_ha);
++ if (ddb < 0)
++ return ddb;
++
++ for (i = 0; i < 32; i += 2)
++ asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
++
++ asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
++ SISTER_DDB, ddb);
++
++ return 0;
++}
++
++#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags)
++#define PARENT_DDB offsetof(struct asd_ddb_sata_pm_port, parent_ddb)
++
++/**
++ * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port
++ * dev: pointer to domain device
++ *
++ * For SATA Port Multiplier Ports we need to allocate one SATA Port
++ * Multiplier Port DDB and depending on whether the target on it
++ * supports SATA II NCQ, one SATA Tag DDB.
++ */
++static int asd_init_sata_pm_port_ddb(struct domain_device *dev)
++{
++ int ddb, i, parent_ddb, pmtable_ddb;
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ u8 flags;
++
++ ddb = asd_get_ddb(asd_ha);
++ if (ddb < 0)
++ return ddb;
++
++ asd_set_ddb_type(dev);
++ flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET;
++ asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags);
++ asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
++ asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
++ asd_init_sata(dev);
++
++ parent_ddb = (int) (unsigned long) dev->parent->lldd_dev;
++ asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb);
++ pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB);
++ asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb);
++
++ if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) {
++ i = asd_init_sata_tag_ddb(dev);
++ if (i < 0) {
++ asd_free_ddb(asd_ha, ddb);
++ return i;
++ }
++ }
++ return 0;
++}
++
++static int asd_init_initiator_ddb(struct domain_device *dev)
++{
++ return -ENODEV;
++}
++
++/**
++ * asd_init_sata_pm_ddb -- SATA Port Multiplier
++ * dev: pointer to domain device
++ *
++ * For STP and direct-attached SATA Port Multipliers we need
++ * one target port DDB entry and one SATA PM table DDB entry.
++ */
++static int asd_init_sata_pm_ddb(struct domain_device *dev)
++{
++ int res = 0;
++
++ res = asd_init_target_ddb(dev);
++ if (res)
++ goto out;
++ res = asd_init_sata_pm_table_ddb(dev);
++ if (res)
++ asd_free_ddb(dev->port->ha->lldd_ha,
++ (int) (unsigned long) dev->lldd_dev);
++out:
++ return res;
++}
++
++int asd_dev_found(struct domain_device *dev)
++{
++ int res = 0;
++
++ switch (dev->dev_type) {
++ case SATA_PM:
++ res = asd_init_sata_pm_ddb(dev);
++ break;
++ case SATA_PM_PORT:
++ res = asd_init_sata_pm_port_ddb(dev);
++ break;
++ default:
++ if (dev->tproto)
++ res = asd_init_target_ddb(dev);
++ else
++ res = asd_init_initiator_ddb(dev);
++ }
++ return res;
++}
++
++void asd_dev_gone(struct domain_device *dev)
++{
++ int ddb, sister_ddb;
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++
++ ddb = (int) (unsigned long) dev->lldd_dev;
++ sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
++
++ if (sister_ddb != 0xFFFF)
++ asd_free_ddb(asd_ha, sister_ddb);
++ asd_free_ddb(asd_ha, ddb);
++ dev->lldd_dev = NULL;
++}
+diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
+new file mode 100644
+index 0000000..e6ade59
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_dump.c
+@@ -0,0 +1,959 @@
++/*
++ * Aic94xx SAS/SATA driver dump interface.
++ *
++ * Copyright (C) 2004 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2004 David Chaw <david_chaw at adaptec.com>
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * 2005/07/14/LT Complete overhaul of this file. Update pages, register
++ * locations, names, etc. Make use of macros. Print more information.
++ * Print all cseq and lseq mip and mdp.
++ *
++ */
++
++#include "linux/pci.h"
++#include "aic94xx.h"
++#include "aic94xx_reg.h"
++#include "aic94xx_reg_def.h"
++#include "aic94xx_sas.h"
++
++#include "aic94xx_dump.h"
++
++#ifdef ASD_DEBUG
++
++#define MD(x) (1 << (x))
++#define MODE_COMMON (1 << 31)
++#define MODE_0_7 (0xFF)
++
++static const struct lseq_cio_regs {
++ char *name;
++ u32 offs;
++ u8 width;
++ u32 mode;
++} LSEQmCIOREGS[] = {
++ {"LmMnSCBPTR", 0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
++ {"LmMnDDBPTR", 0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
++ {"LmREQMBX", 0x30, 32, MODE_COMMON },
++ {"LmRSPMBX", 0x34, 32, MODE_COMMON },
++ {"LmMnINT", 0x38, 32, MODE_0_7 },
++ {"LmMnINTEN", 0x3C, 32, MODE_0_7 },
++ {"LmXMTPRIMD", 0x40, 32, MODE_COMMON },
++ {"LmXMTPRIMCS", 0x44, 8, MODE_COMMON },
++ {"LmCONSTAT", 0x45, 8, MODE_COMMON },
++ {"LmMnDMAERRS", 0x46, 8, MD(0)|MD(1) },
++ {"LmMnSGDMAERRS", 0x47, 8, MD(0)|MD(1) },
++ {"LmMnEXPHDRP", 0x48, 8, MD(0) },
++ {"LmMnSASAALIGN", 0x48, 8, MD(1) },
++ {"LmMnMSKHDRP", 0x49, 8, MD(0) },
++ {"LmMnSTPALIGN", 0x49, 8, MD(1) },
++ {"LmMnRCVHDRP", 0x4A, 8, MD(0) },
++ {"LmMnXMTHDRP", 0x4A, 8, MD(1) },
++ {"LmALIGNMODE", 0x4B, 8, MD(1) },
++ {"LmMnEXPRCVCNT", 0x4C, 32, MD(0) },
++ {"LmMnXMTCNT", 0x4C, 32, MD(1) },
++ {"LmMnCURRTAG", 0x54, 16, MD(0) },
++ {"LmMnPREVTAG", 0x56, 16, MD(0) },
++ {"LmMnACKOFS", 0x58, 8, MD(1) },
++ {"LmMnXFRLVL", 0x59, 8, MD(0)|MD(1) },
++ {"LmMnSGDMACTL", 0x5A, 8, MD(0)|MD(1) },
++ {"LmMnSGDMASTAT", 0x5B, 8, MD(0)|MD(1) },
++ {"LmMnDDMACTL", 0x5C, 8, MD(0)|MD(1) },
++ {"LmMnDDMASTAT", 0x5D, 8, MD(0)|MD(1) },
++ {"LmMnDDMAMODE", 0x5E, 16, MD(0)|MD(1) },
++ {"LmMnPIPECTL", 0x61, 8, MD(0)|MD(1) },
++ {"LmMnACTSCB", 0x62, 16, MD(0)|MD(1) },
++ {"LmMnSGBHADR", 0x64, 8, MD(0)|MD(1) },
++ {"LmMnSGBADR", 0x65, 8, MD(0)|MD(1) },
++ {"LmMnSGDCNT", 0x66, 8, MD(0)|MD(1) },
++ {"LmMnSGDMADR", 0x68, 32, MD(0)|MD(1) },
++ {"LmMnSGDMADR", 0x6C, 32, MD(0)|MD(1) },
++ {"LmMnXFRCNT", 0x70, 32, MD(0)|MD(1) },
++ {"LmMnXMTCRC", 0x74, 32, MD(1) },
++ {"LmCURRTAG", 0x74, 16, MD(0) },
++ {"LmPREVTAG", 0x76, 16, MD(0) },
++ {"LmMnDPSEL", 0x7B, 8, MD(0)|MD(1) },
++ {"LmDPTHSTAT", 0x7C, 8, MODE_COMMON },
++ {"LmMnHOLDLVL", 0x7D, 8, MD(0) },
++ {"LmMnSATAFS", 0x7E, 8, MD(1) },
++ {"LmMnCMPLTSTAT", 0x7F, 8, MD(0)|MD(1) },
++ {"LmPRMSTAT0", 0x80, 32, MODE_COMMON },
++ {"LmPRMSTAT1", 0x84, 32, MODE_COMMON },
++ {"LmGPRMINT", 0x88, 8, MODE_COMMON },
++ {"LmMnCURRSCB", 0x8A, 16, MD(0) },
++ {"LmPRMICODE", 0x8C, 32, MODE_COMMON },
++ {"LmMnRCVCNT", 0x90, 16, MD(0) },
++ {"LmMnBUFSTAT", 0x92, 16, MD(0) },
++ {"LmMnXMTHDRSIZE",0x92, 8, MD(1) },
++ {"LmMnXMTSIZE", 0x93, 8, MD(1) },
++ {"LmMnTGTXFRCNT", 0x94, 32, MD(0) },
++ {"LmMnEXPROFS", 0x98, 32, MD(0) },
++ {"LmMnXMTROFS", 0x98, 32, MD(1) },
++ {"LmMnRCVROFS", 0x9C, 32, MD(0) },
++ {"LmCONCTL", 0xA0, 16, MODE_COMMON },
++ {"LmBITLTIMER", 0xA2, 16, MODE_COMMON },
++ {"LmWWNLOW", 0xA8, 32, MODE_COMMON },
++ {"LmWWNHIGH", 0xAC, 32, MODE_COMMON },
++ {"LmMnFRMERR", 0xB0, 32, MD(0) },
++ {"LmMnFRMERREN", 0xB4, 32, MD(0) },
++ {"LmAWTIMER", 0xB8, 16, MODE_COMMON },
++ {"LmAWTCTL", 0xBA, 8, MODE_COMMON },
++ {"LmMnHDRCMPS", 0xC0, 32, MD(0) },
++ {"LmMnXMTSTAT", 0xC4, 8, MD(1) },
++ {"LmHWTSTATEN", 0xC5, 8, MODE_COMMON },
++ {"LmMnRRDYRC", 0xC6, 8, MD(0) },
++ {"LmMnRRDYTC", 0xC6, 8, MD(1) },
++ {"LmHWTSTAT", 0xC7, 8, MODE_COMMON },
++ {"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) },
++ {"LmDWSSTATUS", 0xCB, 8, MODE_COMMON },
++ {"LmMnACTSTAT", 0xCE, 16, MD(0)|MD(1) },
++ {"LmMnREQSCB", 0xD2, 16, MD(0)|MD(1) },
++ {"LmXXXPRIM", 0xD4, 32, MODE_COMMON },
++ {"LmRCVASTAT", 0xD9, 8, MODE_COMMON },
++ {"LmINTDIS1", 0xDA, 8, MODE_COMMON },
++ {"LmPSTORESEL", 0xDB, 8, MODE_COMMON },
++ {"LmPSTORE", 0xDC, 32, MODE_COMMON },
++ {"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON },
++ {"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON },
++ {"LmDONETCTL", 0xF2, 16, MODE_COMMON },
++ {NULL, 0, 0, 0 }
++};
++/*
++static struct lseq_cio_regs LSEQmOOBREGS[] = {
++ {"OOB_BFLTR" ,0x100, 8, MD(5)},
++ {"OOB_INIT_MIN" ,0x102,16, MD(5)},
++ {"OOB_INIT_MAX" ,0x104,16, MD(5)},
++ {"OOB_INIT_NEG" ,0x106,16, MD(5)},
++ {"OOB_SAS_MIN" ,0x108,16, MD(5)},
++ {"OOB_SAS_MAX" ,0x10A,16, MD(5)},
++ {"OOB_SAS_NEG" ,0x10C,16, MD(5)},
++ {"OOB_WAKE_MIN" ,0x10E,16, MD(5)},
++ {"OOB_WAKE_MAX" ,0x110,16, MD(5)},
++ {"OOB_WAKE_NEG" ,0x112,16, MD(5)},
++ {"OOB_IDLE_MAX" ,0x114,16, MD(5)},
++ {"OOB_BURST_MAX" ,0x116,16, MD(5)},
++ {"OOB_XMIT_BURST" ,0x118, 8, MD(5)},
++ {"OOB_SEND_PAIRS" ,0x119, 8, MD(5)},
++ {"OOB_INIT_IDLE" ,0x11A, 8, MD(5)},
++ {"OOB_INIT_NEGO" ,0x11C, 8, MD(5)},
++ {"OOB_SAS_IDLE" ,0x11E, 8, MD(5)},
++ {"OOB_SAS_NEGO" ,0x120, 8, MD(5)},
++ {"OOB_WAKE_IDLE" ,0x122, 8, MD(5)},
++ {"OOB_WAKE_NEGO" ,0x124, 8, MD(5)},
++ {"OOB_DATA_KBITS" ,0x126, 8, MD(5)},
++ {"OOB_BURST_DATA" ,0x128,32, MD(5)},
++ {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)},
++ {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)},
++ {"OOB_SYNC_DATA" ,0x134,32, MD(5)},
++ {"OOB_D10_2_DATA" ,0x138,32, MD(5)},
++ {"OOB_PHY_RST_CNT" ,0x13C,32, MD(5)},
++ {"OOB_SIG_GEN" ,0x140, 8, MD(5)},
++ {"OOB_XMIT" ,0x141, 8, MD(5)},
++ {"FUNCTION_MAKS" ,0x142, 8, MD(5)},
++ {"OOB_MODE" ,0x143, 8, MD(5)},
++ {"CURRENT_STATUS" ,0x144, 8, MD(5)},
++ {"SPEED_MASK" ,0x145, 8, MD(5)},
++ {"PRIM_COUNT" ,0x146, 8, MD(5)},
++ {"OOB_SIGNALS" ,0x148, 8, MD(5)},
++ {"OOB_DATA_DET" ,0x149, 8, MD(5)},
++ {"OOB_TIME_OUT" ,0x14C, 8, MD(5)},
++ {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)},
++ {"OOB_STATUS" ,0x14E, 8, MD(5)},
++ {"HOT_PLUG_DELAY" ,0x150, 8, MD(5)},
++ {"RCD_DELAY" ,0x151, 8, MD(5)},
++ {"COMSAS_TIMER" ,0x152, 8, MD(5)},
++ {"SNTT_DELAY" ,0x153, 8, MD(5)},
++ {"SPD_CHNG_DELAY" ,0x154, 8, MD(5)},
++ {"SNLT_DELAY" ,0x155, 8, MD(5)},
++ {"SNWT_DELAY" ,0x156, 8, MD(5)},
++ {"ALIGN_DELAY" ,0x157, 8, MD(5)},
++ {"INT_ENABLE_0" ,0x158, 8, MD(5)},
++ {"INT_ENABLE_1" ,0x159, 8, MD(5)},
++ {"INT_ENABLE_2" ,0x15A, 8, MD(5)},
++ {"INT_ENABLE_3" ,0x15B, 8, MD(5)},
++ {"OOB_TEST_REG" ,0x15C, 8, MD(5)},
++ {"PHY_CONTROL_0" ,0x160, 8, MD(5)},
++ {"PHY_CONTROL_1" ,0x161, 8, MD(5)},
++ {"PHY_CONTROL_2" ,0x162, 8, MD(5)},
++ {"PHY_CONTROL_3" ,0x163, 8, MD(5)},
++ {"PHY_OOB_CAL_TX" ,0x164, 8, MD(5)},
++ {"PHY_OOB_CAL_RX" ,0x165, 8, MD(5)},
++ {"OOB_PHY_CAL_TX" ,0x166, 8, MD(5)},
++ {"OOB_PHY_CAL_RX" ,0x167, 8, MD(5)},
++ {"PHY_CONTROL_4" ,0x168, 8, MD(5)},
++ {"PHY_TEST" ,0x169, 8, MD(5)},
++ {"PHY_PWR_CTL" ,0x16A, 8, MD(5)},
++ {"PHY_PWR_DELAY" ,0x16B, 8, MD(5)},
++ {"OOB_SM_CON" ,0x16C, 8, MD(5)},
++ {"ADDR_TRAP_1" ,0x16D, 8, MD(5)},
++ {"ADDR_NEXT_1" ,0x16E, 8, MD(5)},
++ {"NEXT_ST_1" ,0x16F, 8, MD(5)},
++ {"OOB_SM_STATE" ,0x170, 8, MD(5)},
++ {"ADDR_TRAP_2" ,0x171, 8, MD(5)},
++ {"ADDR_NEXT_2" ,0x172, 8, MD(5)},
++ {"NEXT_ST_2" ,0x173, 8, MD(5)},
++ {NULL, 0, 0, 0 }
++};
++*/
++#define STR_8BIT " %30s[0x%04x]:0x%02x\n"
++#define STR_16BIT " %30s[0x%04x]:0x%04x\n"
++#define STR_32BIT " %30s[0x%04x]:0x%08x\n"
++#define STR_64BIT " %30s[0x%04x]:0x%llx\n"
++
++#define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n, \
++ asd_read_reg_byte(_ha, _r))
++#define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n, \
++ asd_read_reg_word(_ha, _r))
++#define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n, \
++ asd_read_reg_dword(_ha, _r))
++
++#define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n, \
++ asd_read_reg_byte(_ha, C##_n))
++#define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n, \
++ asd_read_reg_word(_ha, C##_n))
++#define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n, \
++ asd_read_reg_dword(_ha, C##_n))
++
++#define MSTR_8BIT " Mode:%02d %30s[0x%04x]:0x%02x\n"
++#define MSTR_16BIT " Mode:%02d %30s[0x%04x]:0x%04x\n"
++#define MSTR_32BIT " Mode:%02d %30s[0x%04x]:0x%08x\n"
++
++#define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n, \
++ asd_read_reg_byte(_ha, _r))
++#define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \
++ asd_read_reg_word(_ha, _r))
++#define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \
++ asd_read_reg_dword(_ha, _r))
++
++/* can also be used for MD when the register is mode aware already */
++#define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\
++ asd_read_reg_byte(_ha, CSEQ_##_n))
++#define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
++ asd_read_reg_word(_ha, CSEQ_##_n))
++#define PRINT_MIS_dword(_ha, _n) \
++ asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
++ asd_read_reg_dword(_ha, CSEQ_##_n))
++#define PRINT_MIS_qword(_ha, _n) \
++ asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR, \
++ (unsigned long long)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n)) \
++ | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32)))
++
++#define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n)
++#define PRINT_CMDP_word(_ha, _n) \
++asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
++ #_n, \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \
++ asd_read_reg_word(_ha, CMDP_REG(_n, 7)))
++
++#define PRINT_CMDP_byte(_ha, _n) \
++asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
++ #_n, \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \
++ asd_read_reg_byte(_ha, CMDP_REG(_n, 7)))
++
++static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha)
++{
++ int mode;
++
++ asd_printk("CSEQ STATE\n");
++
++ asd_printk("ARP2 REGISTERS\n");
++
++ PRINT_CREG_32bit(asd_ha, ARP2CTL);
++ PRINT_CREG_32bit(asd_ha, ARP2INT);
++ PRINT_CREG_32bit(asd_ha, ARP2INTEN);
++ PRINT_CREG_8bit(asd_ha, MODEPTR);
++ PRINT_CREG_8bit(asd_ha, ALTMODE);
++ PRINT_CREG_8bit(asd_ha, FLAG);
++ PRINT_CREG_8bit(asd_ha, ARP2INTCTL);
++ PRINT_CREG_16bit(asd_ha, STACK);
++ PRINT_CREG_16bit(asd_ha, PRGMCNT);
++ PRINT_CREG_16bit(asd_ha, ACCUM);
++ PRINT_CREG_16bit(asd_ha, SINDEX);
++ PRINT_CREG_16bit(asd_ha, DINDEX);
++ PRINT_CREG_8bit(asd_ha, SINDIR);
++ PRINT_CREG_8bit(asd_ha, DINDIR);
++ PRINT_CREG_8bit(asd_ha, JUMLDIR);
++ PRINT_CREG_8bit(asd_ha, ARP2HALTCODE);
++ PRINT_CREG_16bit(asd_ha, CURRADDR);
++ PRINT_CREG_16bit(asd_ha, LASTADDR);
++ PRINT_CREG_16bit(asd_ha, NXTLADDR);
++
++ asd_printk("IOP REGISTERS\n");
++
++ PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL);
++ PRINT_CREG_32bit(asd_ha, MAPPEDSCR);
++
++ asd_printk("CIO REGISTERS\n");
++
++ for (mode = 0; mode < 9; mode++)
++ PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode));
++ PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15));
++
++ for (mode = 0; mode < 9; mode++)
++ PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode));
++ PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15));
++
++ for (mode = 0; mode < 8; mode++)
++ PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode));
++ for (mode = 0; mode < 8; mode++)
++ PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode));
++ for (mode = 0; mode < 8; mode++)
++ PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode));
++ for (mode = 0; mode < 8; mode++)
++ PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode));
++
++ PRINT_CREG_8bit(asd_ha, SCRATCHPAGE);
++ for (mode = 0; mode < 8; mode++)
++ PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE,
++ CMnSCRATCHPAGE(mode));
++
++ PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON);
++ PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK);
++ PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST);
++ PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE);
++ PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC);
++ PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS);
++
++ asd_printk("SCRATCH MEMORY\n");
++
++ asd_printk("MIP 4 >>>>>\n");
++ PRINT_MIS_word(asd_ha, Q_EXE_HEAD);
++ PRINT_MIS_word(asd_ha, Q_EXE_TAIL);
++ PRINT_MIS_word(asd_ha, Q_DONE_HEAD);
++ PRINT_MIS_word(asd_ha, Q_DONE_TAIL);
++ PRINT_MIS_word(asd_ha, Q_SEND_HEAD);
++ PRINT_MIS_word(asd_ha, Q_SEND_TAIL);
++ PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD);
++ PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL);
++ PRINT_MIS_word(asd_ha, Q_COPY_HEAD);
++ PRINT_MIS_word(asd_ha, Q_COPY_TAIL);
++ PRINT_MIS_word(asd_ha, REG0);
++ PRINT_MIS_word(asd_ha, REG1);
++ PRINT_MIS_dword(asd_ha, REG2);
++ PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP);
++ PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE);
++ PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT);
++
++ asd_printk("MIP 5 >>>>\n");
++ PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE);
++ PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT);
++ PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD);
++ PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL);
++ PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB);
++ PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD);
++ PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL);
++ PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET);
++
++ asd_printk("MIP 6 >>>>\n");
++ PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0);
++ PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1);
++ PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR);
++ PRINT_MIS_byte(asd_ha, INT_ROUT_MODE);
++ PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS);
++ PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX);
++ PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX);
++ PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD);
++ PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL);
++ PRINT_MIS_byte(asd_ha, FREE_SCB_MASK);
++ PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD);
++ PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL);
++ PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD);
++ PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL);
++
++ asd_printk("MIP 7 >>>>\n");
++ PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE);
++ PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT);
++ PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD);
++ PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL);
++ PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB);
++ PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD);
++ PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL);
++ PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET);
++ PRINT_MIS_word(asd_ha, PRIMITIVE_DATA);
++ PRINT_MIS_dword(asd_ha, TIMEOUT_CONST);
++
++ asd_printk("MDP 0 >>>>\n");
++ asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++ "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7");
++ PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX);
++ PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR);
++ PRINT_CMDP_word(asd_ha, Q_LINK_HEAD);
++ PRINT_CMDP_word(asd_ha, Q_LINK_TAIL);
++ PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE);
++
++ asd_printk("MDP 0 Mode 8 >>>>\n");
++ PRINT_MIS_word(asd_ha, RET_ADDR);
++ PRINT_MIS_word(asd_ha, RET_SCBPTR);
++ PRINT_MIS_word(asd_ha, SAVE_SCBPTR);
++ PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX);
++ PRINT_MIS_word(asd_ha, RESP_LEN);
++ PRINT_MIS_word(asd_ha, TMF_SCBPTR);
++ PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB);
++ PRINT_MIS_word(asd_ha, GLOBAL_HEAD);
++ PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD);
++ PRINT_MIS_byte(asd_ha, TMF_OPCODE);
++ PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS);
++ PRINT_MIS_word(asd_ha, HSB_SITE);
++ PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE);
++ PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE);
++
++ asd_printk("MDP 1 Mode 8 >>>>\n");
++ PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR);
++ PRINT_MIS_qword(asd_ha, LUN_TO_CHECK);
++
++ asd_printk("MDP 2 Mode 8 >>>>\n");
++ PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER);
++ PRINT_MIS_qword(asd_ha, HQ_DONE_BASE);
++ PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER);
++ PRINT_MIS_byte(asd_ha, HQ_DONE_PASS);
++}
++
++#define PRINT_LREG_8bit(_h, _lseq, _n) \
++ asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq)))
++#define PRINT_LREG_16bit(_h, _lseq, _n) \
++ asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq)))
++#define PRINT_LREG_32bit(_h, _lseq, _n) \
++ asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq)))
++
++#define PRINT_LMIP_byte(_h, _lseq, _n) \
++ asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
++ asd_read_reg_byte(_h, LmSEQ_##_n(_lseq)))
++#define PRINT_LMIP_word(_h, _lseq, _n) \
++ asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
++ asd_read_reg_word(_h, LmSEQ_##_n(_lseq)))
++#define PRINT_LMIP_dword(_h, _lseq, _n) \
++ asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
++ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)))
++#define PRINT_LMIP_qword(_h, _lseq, _n) \
++ asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
++ (unsigned long long)(((unsigned long long) \
++ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) \
++ | (((unsigned long long) \
++ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32)))
++
++static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha,
++ u32 lseq_cio_addr, int i)
++{
++ switch (LSEQmCIOREGS[i].width) {
++ case 8:
++ asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name,
++ LSEQmCIOREGS[i].offs,
++ asd_read_reg_byte(asd_ha, lseq_cio_addr +
++ LSEQmCIOREGS[i].offs));
++
++ break;
++ case 16:
++ asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name,
++ LSEQmCIOREGS[i].offs,
++ asd_read_reg_word(asd_ha, lseq_cio_addr +
++ LSEQmCIOREGS[i].offs));
++
++ break;
++ case 32:
++ asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name,
++ LSEQmCIOREGS[i].offs,
++ asd_read_reg_dword(asd_ha, lseq_cio_addr +
++ LSEQmCIOREGS[i].offs));
++ break;
++ }
++}
++
++static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq)
++{
++ u32 moffs;
++ int mode;
++
++ asd_printk("LSEQ %d STATE\n", lseq);
++
++ asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq);
++ PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL);
++ PRINT_LREG_32bit(asd_ha, lseq, ARP2INT);
++ PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN);
++ PRINT_LREG_8bit(asd_ha, lseq, MODEPTR);
++ PRINT_LREG_8bit(asd_ha, lseq, ALTMODE);
++ PRINT_LREG_8bit(asd_ha, lseq, FLAG);
++ PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL);
++ PRINT_LREG_16bit(asd_ha, lseq, STACK);
++ PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT);
++ PRINT_LREG_16bit(asd_ha, lseq, ACCUM);
++ PRINT_LREG_16bit(asd_ha, lseq, SINDEX);
++ PRINT_LREG_16bit(asd_ha, lseq, DINDEX);
++ PRINT_LREG_8bit(asd_ha, lseq, SINDIR);
++ PRINT_LREG_8bit(asd_ha, lseq, DINDIR);
++ PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR);
++ PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE);
++ PRINT_LREG_16bit(asd_ha, lseq, CURRADDR);
++ PRINT_LREG_16bit(asd_ha, lseq, LASTADDR);
++ PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR);
++
++ asd_printk("LSEQ%d: IOP REGISTERS\n", lseq);
++
++ PRINT_LREG_32bit(asd_ha, lseq, MODECTL);
++ PRINT_LREG_32bit(asd_ha, lseq, DBGMODE);
++ PRINT_LREG_32bit(asd_ha, lseq, CONTROL);
++ PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq));
++ PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq));
++
++ asd_printk("LSEQ%d: CIO REGISTERS\n", lseq);
++ asd_printk("Mode common:\n");
++
++ for (mode = 0; mode < 8; mode++) {
++ u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
++ int i;
++
++ for (i = 0; LSEQmCIOREGS[i].name; i++)
++ if (LSEQmCIOREGS[i].mode == MODE_COMMON)
++ asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i);
++ }
++
++ asd_printk("Mode unique:\n");
++ for (mode = 0; mode < 8; mode++) {
++ u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
++ int i;
++
++ asd_printk("Mode %d\n", mode);
++ for (i = 0; LSEQmCIOREGS[i].name; i++) {
++ if (!(LSEQmCIOREGS[i].mode & (1 << mode)))
++ continue;
++ asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i);
++ }
++ }
++
++ asd_printk("SCRATCH MEMORY\n");
++
++ asd_printk("LSEQ%d MIP 0 >>>>\n", lseq);
++ PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD);
++ PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL);
++ PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER);
++ PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS);
++ PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE);
++ PRINT_LMIP_word(asd_ha, lseq, CONCTL);
++ PRINT_LMIP_byte(asd_ha, lseq, CONSTAT);
++ PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES);
++ PRINT_LMIP_word(asd_ha, lseq, REG1_ISR);
++ PRINT_LMIP_word(asd_ha, lseq, REG2_ISR);
++ PRINT_LMIP_word(asd_ha, lseq, REG3_ISR);
++ PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR);
++
++ asd_printk("LSEQ%d MIP 1 >>>>\n", lseq);
++ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0);
++ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1);
++ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2);
++ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL);
++ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL);
++ PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST);
++ PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX);
++ PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX);
++
++ asd_printk("LSEQ%d MIP 2 >>>>\n", lseq);
++ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0);
++ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1);
++ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2);
++ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL);
++ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL);
++
++ asd_printk("LSEQ%d MIP 3 >>>>\n", lseq);
++ PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST);
++ PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT);
++ PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT);
++ PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT);
++ PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT);
++ PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT);
++ PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT);
++
++ for (mode = 0; mode < 3; mode++) {
++ asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode);
++ moffs = mode * LSEQ_MODE_SCRATCH_SIZE;
++
++ asd_printk(STR_16BIT, "RET_ADDR", 0,
++ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)
++ + moffs));
++ asd_printk(STR_16BIT, "REG0_MODE", 2,
++ asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)
++ + moffs));
++ asd_printk(STR_16BIT, "MODE_FLAGS", 4,
++ asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)
++ + moffs));
++ asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
++ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)
++ + moffs));
++ asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
++ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)
++ + moffs));
++ asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
++ asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)
++ + moffs));
++ asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
++ asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)
++ + moffs));
++ }
++
++ asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq);
++ moffs = LSEQ_MODE5_PAGE0_OFFSET;
++ asd_printk(STR_16BIT, "RET_ADDR", 0,
++ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs));
++ asd_printk(STR_16BIT, "REG0_MODE", 2,
++ asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs));
++ asd_printk(STR_16BIT, "MODE_FLAGS", 4,
++ asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs));
++ asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
++ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs));
++ asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
++ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs));
++ asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
++ asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs));
++ asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
++ asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs));
++
++ asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq);
++ PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE);
++ PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX);
++ PRINT_LMIP_word(asd_ha, lseq, RESP_LEN);
++ PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE);
++ PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE);
++ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN);
++ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL);
++ PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS);
++ PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE);
++ PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR);
++
++ asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq);
++ PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD);
++ PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX);
++ PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG);
++ PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS);
++ PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE);
++ PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS);
++ PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE);
++ PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR);
++
++ asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq);
++ PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER);
++ PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR);
++ PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE);
++ PRINT_LMIP_word(asd_ha, lseq, IP_BITL);
++ PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG);
++ PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH);
++
++ asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq);
++ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS);
++ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE);
++ PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD);
++ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR);
++ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS);
++ PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE);
++ PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT);
++ PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES);
++ PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES);
++ PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT);
++ PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT);
++
++ asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq);
++ PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0);
++ PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1);
++
++ asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq);
++ PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0);
++ PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1);
++
++ asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq);
++ PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT);
++ PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT);
++ PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT);
++
++ asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq);
++ PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK);
++ PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT);
++ PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK);
++ PRINT_LMIP_word(asd_ha, lseq, TAG_MASK);
++ PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG);
++ PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET);
++
++ asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq);
++ PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS);
++ PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS);
++ PRINT_LMIP_word(asd_ha, lseq, SDB_DDB);
++ PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS);
++ PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG);
++
++ asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq);
++ PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME);
++ PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL);
++
++ asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq);
++ PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS);
++
++ asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq);
++ PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS);
++ PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS);
++}
++
++/**
++ * asd_dump_ddb_site -- dump a CSEQ DDB site
++ * @asd_ha: pointer to host adapter structure
++ * @site_no: site number of interest
++ */
++void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no)
++{
++ if (site_no >= asd_ha->hw_prof.max_ddbs)
++ return;
++
++#define DDB_FIELDB(__name) \
++ asd_ddbsite_read_byte(asd_ha, site_no, \
++ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
++#define DDB2_FIELDB(__name) \
++ asd_ddbsite_read_byte(asd_ha, site_no, \
++ offsetof(struct asd_ddb_stp_sata_target_port, __name))
++#define DDB_FIELDW(__name) \
++ asd_ddbsite_read_word(asd_ha, site_no, \
++ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
++
++#define DDB_FIELDD(__name) \
++ asd_ddbsite_read_dword(asd_ha, site_no, \
++ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
++
++ asd_printk("DDB: 0x%02x\n", site_no);
++ asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type));
++ asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate));
++ asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag)));
++ asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head)));
++ asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended));
++ asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type));
++ asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def));
++ asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features));
++ asd_printk("Pathway Blocked Count: 0x%02x\n",
++ DDB_FIELDB(pathway_blocked_count));
++ asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time));
++ asd_printk("more_compat_features: 0x%08x\n",
++ DDB_FIELDD(more_compat_features));
++ asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask));
++ asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags));
++ asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2));
++ asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail));
++ asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail));
++ asd_printk("Active Task Count: 0x%04x\n",
++ DDB_FIELDW(active_task_count));
++ asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason));
++ asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout));
++ asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp));
++}
++
++void asd_dump_ddb_0(struct asd_ha_struct *asd_ha)
++{
++#define DDB0_FIELDB(__name) \
++ asd_ddbsite_read_byte(asd_ha, 0, \
++ offsetof(struct asd_ddb_seq_shared, __name))
++#define DDB0_FIELDW(__name) \
++ asd_ddbsite_read_word(asd_ha, 0, \
++ offsetof(struct asd_ddb_seq_shared, __name))
++
++#define DDB0_FIELDD(__name) \
++ asd_ddbsite_read_dword(asd_ha,0 , \
++ offsetof(struct asd_ddb_seq_shared, __name))
++
++#define DDB0_FIELDA(__name, _o) \
++ asd_ddbsite_read_byte(asd_ha, 0, \
++ offsetof(struct asd_ddb_seq_shared, __name)+_o)
++
++
++ asd_printk("DDB: 0\n");
++ asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head));
++ asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail));
++ asd_printk("q_free_ddb_cnt:%04x\n", DDB0_FIELDW(q_free_ddb_cnt));
++ asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head));
++ asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail));
++ asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock));
++ asd_printk("smp_conn_tag:%04x\n", DDB0_FIELDW(smp_conn_tag));
++ asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt));
++ asd_printk("est_nexus_buf_thresh:%04x\n",
++ DDB0_FIELDW(est_nexus_buf_thresh));
++ asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active));
++ asd_printk("phy_is_up:%02x\n", DDB0_FIELDB(phy_is_up));
++ asd_printk("port_map_by_links:%02x %02x %02x %02x "
++ "%02x %02x %02x %02x\n",
++ DDB0_FIELDA(port_map_by_links, 0),
++ DDB0_FIELDA(port_map_by_links, 1),
++ DDB0_FIELDA(port_map_by_links, 2),
++ DDB0_FIELDA(port_map_by_links, 3),
++ DDB0_FIELDA(port_map_by_links, 4),
++ DDB0_FIELDA(port_map_by_links, 5),
++ DDB0_FIELDA(port_map_by_links, 6),
++ DDB0_FIELDA(port_map_by_links, 7));
++}
++
++static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no)
++{
++
++#define SCB_FIELDB(__name) \
++ asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header) \
++ + offsetof(struct initiate_ssp_task, __name))
++#define SCB_FIELDW(__name) \
++ asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header) \
++ + offsetof(struct initiate_ssp_task, __name))
++#define SCB_FIELDD(__name) \
++ asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header) \
++ + offsetof(struct initiate_ssp_task, __name))
++
++ asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len));
++ asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type));
++ asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag));
++ asd_printk("Target Port Xfer Tag: 0x%04x.\n",
++ SCB_FIELDW(ssp_frame.tptt));
++ asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs));
++ asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count));
++}
++
++/**
++ * asd_dump_scb_sites -- dump currently used CSEQ SCB sites
++ * @asd_ha: pointer to host adapter struct
++ */
++void asd_dump_scb_sites(struct asd_ha_struct *asd_ha)
++{
++ u16 site_no;
++
++ for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) {
++ u8 opcode;
++
++ if (!SCB_SITE_VALID(site_no))
++ continue;
++
++ /* We are only interested in SCB sites currently used.
++ */
++ opcode = asd_scbsite_read_byte(asd_ha, site_no,
++ offsetof(struct scb_header,
++ opcode));
++ if (opcode == 0xFF)
++ continue;
++
++ asd_printk("\nSCB: 0x%x\n", site_no);
++ asd_dump_scb_site(asd_ha, site_no);
++ }
++}
++
++/**
++ * ads_dump_seq_state -- dump CSEQ and LSEQ states
++ * @asd_ha: pointer to host adapter structure
++ * @lseq_mask: mask of LSEQs of interest
++ */
++void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask)
++{
++ int lseq;
++
++ asd_dump_cseq_state(asd_ha);
++
++ if (lseq_mask != 0)
++ for_each_sequencer(lseq_mask, lseq_mask, lseq)
++ asd_dump_lseq_state(asd_ha, lseq);
++}
++
++void asd_dump_frame_rcvd(struct asd_phy *phy,
++ struct done_list_struct *dl)
++{
++ unsigned long flags;
++ int i;
++
++ switch ((dl->status_block[1] & 0x70) >> 3) {
++ case SAS_PROTO_STP:
++ ASD_DPRINTK("STP proto device-to-host FIS:\n");
++ break;
++ default:
++ case SAS_PROTO_SSP:
++ ASD_DPRINTK("SAS proto IDENTIFY:\n");
++ break;
++ }
++ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
++ for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4)
++ ASD_DPRINTK("%02x: %02x %02x %02x %02x\n",
++ i,
++ phy->frame_rcvd[i],
++ phy->frame_rcvd[i+1],
++ phy->frame_rcvd[i+2],
++ phy->frame_rcvd[i+3]);
++ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
++}
++
++static inline void asd_dump_scb(struct asd_ascb *ascb, int ind)
++{
++ asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, "
++ "index:%d, opcode:0x%02x\n",
++ ind, ascb->dma_scb.vaddr,
++ (unsigned long long)ascb->dma_scb.dma_handle,
++ (unsigned long long)
++ le64_to_cpu(ascb->scb->header.next_scb),
++ le16_to_cpu(ascb->scb->header.index),
++ ascb->scb->header.opcode);
++}
++
++void asd_dump_scb_list(struct asd_ascb *ascb, int num)
++{
++ int i = 0;
++
++ asd_printk("dumping %d scbs:\n", num);
++
++ asd_dump_scb(ascb, i++);
++ --num;
++
++ if (num > 0 && !list_empty(&ascb->list)) {
++ struct list_head *el;
++
++ list_for_each(el, &ascb->list) {
++ struct asd_ascb *s = list_entry(el, struct asd_ascb,
++ list);
++ asd_dump_scb(s, i++);
++ if (--num <= 0)
++ break;
++ }
++ }
++}
++
++#endif /* ASD_DEBUG */
+diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h
+new file mode 100644
+index 0000000..0c388e7
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_dump.h
+@@ -0,0 +1,52 @@
++/*
++ * Aic94xx SAS/SATA driver dump header file.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef _AIC94XX_DUMP_H_
++#define _AIC94XX_DUMP_H_
++
++#ifdef ASD_DEBUG
++
++void asd_dump_ddb_0(struct asd_ha_struct *asd_ha);
++void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no);
++void asd_dump_scb_sites(struct asd_ha_struct *asd_ha);
++void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask);
++void asd_dump_frame_rcvd(struct asd_phy *phy,
++ struct done_list_struct *dl);
++void asd_dump_scb_list(struct asd_ascb *ascb, int num);
++#else /* ASD_DEBUG */
++
++static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { }
++static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha,
++ u16 site_no) { }
++static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { }
++static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha,
++ u8 lseq_mask) { }
++static inline void asd_dump_frame_rcvd(struct asd_phy *phy,
++ struct done_list_struct *dl) { }
++static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { }
++#endif /* ASD_DEBUG */
++
++#endif /* _AIC94XX_DUMP_H_ */
+diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
+new file mode 100644
+index 0000000..3c2d7a3
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
+@@ -0,0 +1,1375 @@
++/*
++ * Aic94xx SAS/SATA driver hardware interface.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++
++#include "aic94xx.h"
++#include "aic94xx_reg.h"
++#include "aic94xx_hwi.h"
++#include "aic94xx_seq.h"
++#include "aic94xx_dump.h"
++
++u32 MBAR0_SWB_SIZE;
++
++/* ---------- Initialization ---------- */
++
++static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha)
++{
++ extern char sas_addr_str[];
++ /* If the user has specified a WWN it overrides other settings
++ */
++ if (sas_addr_str[0] != '\0')
++ asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr,
++ sas_addr_str);
++ else if (asd_ha->hw_prof.sas_addr[0] != 0)
++ asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr);
++}
++
++static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha)
++{
++ int i;
++
++ for (i = 0; i < ASD_MAX_PHYS; i++) {
++ if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)
++ continue;
++ /* Set a phy's address only if it has none.
++ */
++ ASD_DPRINTK("setting phy%d addr to %llx\n", i,
++ SAS_ADDR(asd_ha->hw_prof.sas_addr));
++ memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,
++ asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
++ }
++}
++
++/* ---------- PHY initialization ---------- */
++
++static void asd_init_phy_identify(struct asd_phy *phy)
++{
++ phy->identify_frame = phy->id_frm_tok->vaddr;
++
++ memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));
++
++ phy->identify_frame->dev_type = SAS_END_DEV;
++ if (phy->sas_phy.role & PHY_ROLE_INITIATOR)
++ phy->identify_frame->initiator_bits = phy->sas_phy.iproto;
++ if (phy->sas_phy.role & PHY_ROLE_TARGET)
++ phy->identify_frame->target_bits = phy->sas_phy.tproto;
++ memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,
++ SAS_ADDR_SIZE);
++ phy->identify_frame->phy_id = phy->sas_phy.id;
++}
++
++static int asd_init_phy(struct asd_phy *phy)
++{
++ struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
++ struct asd_sas_phy *sas_phy = &phy->sas_phy;
++
++ sas_phy->enabled = 1;
++ sas_phy->class = SAS;
++ sas_phy->iproto = SAS_PROTO_ALL;
++ sas_phy->tproto = 0;
++ sas_phy->type = PHY_TYPE_PHYSICAL;
++ sas_phy->role = PHY_ROLE_INITIATOR;
++ sas_phy->oob_mode = OOB_NOT_CONNECTED;
++ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
++
++ phy->id_frm_tok = asd_alloc_coherent(asd_ha,
++ sizeof(*phy->identify_frame),
++ GFP_KERNEL);
++ if (!phy->id_frm_tok) {
++ asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);
++ return -ENOMEM;
++ } else
++ asd_init_phy_identify(phy);
++
++ memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
++
++ return 0;
++}
++
++static int asd_init_phys(struct asd_ha_struct *asd_ha)
++{
++ u8 i;
++ u8 phy_mask = asd_ha->hw_prof.enabled_phys;
++
++ for (i = 0; i < ASD_MAX_PHYS; i++) {
++ struct asd_phy *phy = &asd_ha->phys[i];
++
++ phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
++
++ phy->sas_phy.enabled = 0;
++ phy->sas_phy.id = i;
++ phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];
++ phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];
++ phy->sas_phy.ha = &asd_ha->sas_ha;
++ phy->sas_phy.lldd_phy = phy;
++ }
++
++ /* Now enable and initialize only the enabled phys. */
++ for_each_phy(phy_mask, phy_mask, i) {
++ int err = asd_init_phy(&asd_ha->phys[i]);
++ if (err)
++ return err;
++ }
++
++ return 0;
++}
++
++/* ---------- Sliding windows ---------- */
++
++static int asd_init_sw(struct asd_ha_struct *asd_ha)
++{
++ struct pci_dev *pcidev = asd_ha->pcidev;
++ int err;
++ u32 v;
++
++ /* Unlock MBARs */
++ err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);
++ if (err) {
++ asd_printk("couldn't access conf. space of %s\n",
++ pci_name(pcidev));
++ goto Err;
++ }
++ if (v)
++ err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);
++ if (err) {
++ asd_printk("couldn't write to MBAR_KEY of %s\n",
++ pci_name(pcidev));
++ goto Err;
++ }
++
++ /* Set sliding windows A, B and C to point to proper internal
++ * memory regions.
++ */
++ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);
++ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,
++ REG_BASE_ADDR_CSEQCIO);
++ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);
++ asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;
++ asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;
++ asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;
++ MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;
++ if (!asd_ha->iospace) {
++ /* MBAR1 will point to OCM (On Chip Memory) */
++ pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);
++ asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;
++ }
++ spin_lock_init(&asd_ha->iolock);
++Err:
++ return err;
++}
++
++/* ---------- SCB initialization ---------- */
++
++/**
++ * asd_init_scbs - manually allocate the first SCB.
++ * @asd_ha: pointer to host adapter structure
++ *
++ * This allocates the very first SCB which would be sent to the
++ * sequencer for execution. Its bus address is written to
++ * CSEQ_Q_NEW_POINTER, mode page 2, mode 8. Since the bus address of
++ * the _next_ scb to be DMA-ed to the host adapter is read from the last
++ * SCB DMA-ed to the host adapter, we have to always stay one step
++ * ahead of the sequencer and keep one SCB already allocated.
++ */
++static int asd_init_scbs(struct asd_ha_struct *asd_ha)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int bitmap_bytes;
++
++ /* allocate the index array and bitmap */
++ asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;
++ asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*
++ sizeof(void *), GFP_KERNEL);
++ if (!asd_ha->seq.tc_index_array)
++ return -ENOMEM;
++
++ bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;
++ bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
++ asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
++ if (!asd_ha->seq.tc_index_bitmap)
++ return -ENOMEM;
++
++ spin_lock_init(&seq->tc_index_lock);
++
++ seq->next_scb.size = sizeof(struct scb);
++ seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,
++ &seq->next_scb.dma_handle);
++ if (!seq->next_scb.vaddr) {
++ kfree(asd_ha->seq.tc_index_bitmap);
++ kfree(asd_ha->seq.tc_index_array);
++ asd_ha->seq.tc_index_bitmap = NULL;
++ asd_ha->seq.tc_index_array = NULL;
++ return -ENOMEM;
++ }
++
++ seq->pending = 0;
++ spin_lock_init(&seq->pend_q_lock);
++ INIT_LIST_HEAD(&seq->pend_q);
++
++ return 0;
++}
++
++static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
++{
++ asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;
++ asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;
++ ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",
++ asd_ha->hw_prof.max_scbs,
++ asd_ha->hw_prof.max_ddbs);
++}
++
++/* ---------- Done List initialization ---------- */
++
++static void asd_dl_tasklet_handler(unsigned long);
++
++static int asd_init_dl(struct asd_ha_struct *asd_ha)
++{
++ asd_ha->seq.actual_dl
++ = asd_alloc_coherent(asd_ha,
++ ASD_DL_SIZE * sizeof(struct done_list_struct),
++ GFP_KERNEL);
++ if (!asd_ha->seq.actual_dl)
++ return -ENOMEM;
++ asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
++ asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
++ asd_ha->seq.dl_next = 0;
++ tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
++ (unsigned long) asd_ha);
++
++ return 0;
++}
++
++/* ---------- EDB and ESCB init ---------- */
++
++static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int i;
++
++ seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);
++ if (!seq->edb_arr)
++ return -ENOMEM;
++
++ for (i = 0; i < seq->num_edbs; i++) {
++ seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,
++ gfp_flags);
++ if (!seq->edb_arr[i])
++ goto Err_unroll;
++ memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);
++ }
++
++ ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);
++
++ return 0;
++
++Err_unroll:
++ for (i-- ; i >= 0; i--)
++ asd_free_coherent(asd_ha, seq->edb_arr[i]);
++ kfree(seq->edb_arr);
++ seq->edb_arr = NULL;
++
++ return -ENOMEM;
++}
++
++static int asd_alloc_escbs(struct asd_ha_struct *asd_ha,
++ gfp_t gfp_flags)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ struct asd_ascb *escb;
++ int i, escbs;
++
++ seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),
++ gfp_flags);
++ if (!seq->escb_arr)
++ return -ENOMEM;
++
++ escbs = seq->num_escbs;
++ escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);
++ if (!escb) {
++ asd_printk("couldn't allocate list of escbs\n");
++ goto Err;
++ }
++ seq->num_escbs -= escbs; /* subtract what was not allocated */
++ ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);
++
++ for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,
++ struct asd_ascb,
++ list)) {
++ seq->escb_arr[i] = escb;
++ escb->scb->header.opcode = EMPTY_SCB;
++ }
++
++ return 0;
++Err:
++ kfree(seq->escb_arr);
++ seq->escb_arr = NULL;
++ return -ENOMEM;
++
++}
++
++static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int i, k, z = 0;
++
++ for (i = 0; i < seq->num_escbs; i++) {
++ struct asd_ascb *ascb = seq->escb_arr[i];
++ struct empty_scb *escb = &ascb->scb->escb;
++
++ ascb->edb_index = z;
++
++ escb->num_valid = ASD_EDBS_PER_SCB;
++
++ for (k = 0; k < ASD_EDBS_PER_SCB; k++) {
++ struct sg_el *eb = &escb->eb[k];
++ struct asd_dma_tok *edb = seq->edb_arr[z++];
++
++ memset(eb, 0, sizeof(*eb));
++ eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));
++ eb->size = cpu_to_le32(((u32) edb->size));
++ }
++ }
++}
++
++/**
++ * asd_init_escbs -- allocate and initialize empty scbs
++ * @asd_ha: pointer to host adapter structure
++ *
++ * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers.
++ * They transport sense data, etc.
++ */
++static int asd_init_escbs(struct asd_ha_struct *asd_ha)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int err = 0;
++
++ /* Allocate two empty data buffers (edb) per sequencer. */
++ int edbs = 2*(1+asd_ha->hw_prof.num_phys);
++
++ seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;
++ seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;
++
++ err = asd_alloc_edbs(asd_ha, GFP_KERNEL);
++ if (err) {
++ asd_printk("couldn't allocate edbs\n");
++ return err;
++ }
++
++ err = asd_alloc_escbs(asd_ha, GFP_KERNEL);
++ if (err) {
++ asd_printk("couldn't allocate escbs\n");
++ return err;
++ }
++
++ asd_assign_edbs2escbs(asd_ha);
++ /* In order to insure that normal SCBs do not overfill sequencer
++ * memory and leave no space for escbs (halting condition),
++ * we increment pending here by the number of escbs. However,
++ * escbs are never pending.
++ */
++ seq->pending = seq->num_escbs;
++ seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;
++
++ return 0;
++}
++
++/* ---------- HW initialization ---------- */
++
++/**
++ * asd_chip_hardrst -- hard reset the chip
++ * @asd_ha: pointer to host adapter structure
++ *
++ * This takes 16 cycles and is synchronous to CFCLK, which runs
++ * at 200 MHz, so this should take at most 80 nanoseconds.
++ */
++int asd_chip_hardrst(struct asd_ha_struct *asd_ha)
++{
++ int i;
++ int count = 100;
++ u32 reg;
++
++ for (i = 0 ; i < 4 ; i++) {
++ asd_write_reg_dword(asd_ha, COMBIST, HARDRST);
++ }
++
++ do {
++ udelay(1);
++ reg = asd_read_reg_dword(asd_ha, CHIMINT);
++ if (reg & HARDRSTDET) {
++ asd_write_reg_dword(asd_ha, CHIMINT,
++ HARDRSTDET|PORRSTDET);
++ return 0;
++ }
++ } while (--count > 0);
++
++ return -ENODEV;
++}
++
++/**
++ * asd_init_chip -- initialize the chip
++ * @asd_ha: pointer to host adapter structure
++ *
++ * Hard resets the chip, disables HA interrupts, downloads the sequnecer
++ * microcode and starts the sequencers. The caller has to explicitly
++ * enable HA interrupts with asd_enable_ints(asd_ha).
++ */
++static int asd_init_chip(struct asd_ha_struct *asd_ha)
++{
++ int err;
++
++ err = asd_chip_hardrst(asd_ha);
++ if (err) {
++ asd_printk("couldn't hard reset %s\n",
++ pci_name(asd_ha->pcidev));
++ goto out;
++ }
++
++ asd_disable_ints(asd_ha);
++
++ err = asd_init_seqs(asd_ha);
++ if (err) {
++ asd_printk("couldn't init seqs for %s\n",
++ pci_name(asd_ha->pcidev));
++ goto out;
++ }
++
++ err = asd_start_seqs(asd_ha);
++ if (err) {
++ asd_printk("coudln't start seqs for %s\n",
++ pci_name(asd_ha->pcidev));
++ goto out;
++ }
++out:
++ return err;
++}
++
++#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))
++
++static int max_devs = 0;
++module_param_named(max_devs, max_devs, int, S_IRUGO);
++MODULE_PARM_DESC(max_devs, "\n"
++ "\tMaximum number of SAS devices to support (not LUs).\n"
++ "\tDefault: 2176, Maximum: 65663.\n");
++
++static int max_cmnds = 0;
++module_param_named(max_cmnds, max_cmnds, int, S_IRUGO);
++MODULE_PARM_DESC(max_cmnds, "\n"
++ "\tMaximum number of commands queuable.\n"
++ "\tDefault: 512, Maximum: 66047.\n");
++
++static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha)
++{
++ unsigned long dma_addr = OCM_BASE_ADDR;
++ u32 d;
++
++ dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
++ asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);
++ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
++ d |= 4;
++ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
++ asd_ha->hw_prof.max_ddbs += MAX_DEVS;
++}
++
++static int asd_extend_devctx(struct asd_ha_struct *asd_ha)
++{
++ dma_addr_t dma_handle;
++ unsigned long dma_addr;
++ u32 d;
++ int size;
++
++ asd_extend_devctx_ocm(asd_ha);
++
++ asd_ha->hw_prof.ddb_ext = NULL;
++ if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {
++ max_devs = asd_ha->hw_prof.max_ddbs;
++ return 0;
++ }
++
++ size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;
++
++ asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
++ if (!asd_ha->hw_prof.ddb_ext) {
++ asd_printk("couldn't allocate memory for %d devices\n",
++ max_devs);
++ max_devs = asd_ha->hw_prof.max_ddbs;
++ return -ENOMEM;
++ }
++ dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;
++ dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);
++ dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
++ dma_handle = (dma_addr_t) dma_addr;
++ asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);
++ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
++ d &= ~4;
++ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
++
++ asd_ha->hw_prof.max_ddbs = max_devs;
++
++ return 0;
++}
++
++static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha)
++{
++ dma_addr_t dma_handle;
++ unsigned long dma_addr;
++ u32 d;
++ int size;
++
++ asd_ha->hw_prof.scb_ext = NULL;
++ if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {
++ max_cmnds = asd_ha->hw_prof.max_scbs;
++ return 0;
++ }
++
++ size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;
++
++ asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
++ if (!asd_ha->hw_prof.scb_ext) {
++ asd_printk("couldn't allocate memory for %d commands\n",
++ max_cmnds);
++ max_cmnds = asd_ha->hw_prof.max_scbs;
++ return -ENOMEM;
++ }
++ dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;
++ dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);
++ dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;
++ dma_handle = (dma_addr_t) dma_addr;
++ asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);
++ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
++ d &= ~1;
++ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
++
++ asd_ha->hw_prof.max_scbs = max_cmnds;
++
++ return 0;
++}
++
++/**
++ * asd_init_ctxmem -- initialize context memory
++ * asd_ha: pointer to host adapter structure
++ *
++ * This function sets the maximum number of SCBs and
++ * DDBs which can be used by the sequencer. This is normally
++ * 512 and 128 respectively. If support for more SCBs or more DDBs
++ * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are
++ * initialized here to extend context memory to point to host memory,
++ * thus allowing unlimited support for SCBs and DDBs -- only limited
++ * by host memory.
++ */
++static int asd_init_ctxmem(struct asd_ha_struct *asd_ha)
++{
++ int bitmap_bytes;
++
++ asd_get_max_scb_ddb(asd_ha);
++ asd_extend_devctx(asd_ha);
++ asd_extend_cmdctx(asd_ha);
++
++ /* The kernel wants bitmaps to be unsigned long sized. */
++ bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;
++ bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
++ asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
++ if (!asd_ha->hw_prof.ddb_bitmap)
++ return -ENOMEM;
++ spin_lock_init(&asd_ha->hw_prof.ddb_lock);
++
++ return 0;
++}
++
++int asd_init_hw(struct asd_ha_struct *asd_ha)
++{
++ int err;
++ u32 v;
++
++ err = asd_init_sw(asd_ha);
++ if (err)
++ return err;
++
++ err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v);
++ if (err) {
++ asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n",
++ pci_name(asd_ha->pcidev));
++ return err;
++ }
++ pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
++ v | SC_TMR_DIS);
++ if (err) {
++ asd_printk("couldn't disable split completion timer of %s\n",
++ pci_name(asd_ha->pcidev));
++ return err;
++ }
++
++ err = asd_read_ocm(asd_ha);
++ if (err) {
++ asd_printk("couldn't read ocm(%d)\n", err);
++ /* While suspicios, it is not an error that we
++ * couldn't read the OCM. */
++ }
++
++ err = asd_read_flash(asd_ha);
++ if (err) {
++ asd_printk("couldn't read flash(%d)\n", err);
++ /* While suspicios, it is not an error that we
++ * couldn't read FLASH memory.
++ */
++ }
++
++ asd_init_ctxmem(asd_ha);
++
++ asd_get_user_sas_addr(asd_ha);
++ if (!asd_ha->hw_prof.sas_addr[0]) {
++ asd_printk("No SAS Address provided for %s\n",
++ pci_name(asd_ha->pcidev));
++ err = -ENODEV;
++ goto Out;
++ }
++
++ asd_propagate_sas_addr(asd_ha);
++
++ err = asd_init_phys(asd_ha);
++ if (err) {
++ asd_printk("couldn't initialize phys for %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Out;
++ }
++
++ err = asd_init_scbs(asd_ha);
++ if (err) {
++ asd_printk("couldn't initialize scbs for %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Out;
++ }
++
++ err = asd_init_dl(asd_ha);
++ if (err) {
++ asd_printk("couldn't initialize the done list:%d\n",
++ err);
++ goto Out;
++ }
++
++ err = asd_init_escbs(asd_ha);
++ if (err) {
++ asd_printk("couldn't initialize escbs\n");
++ goto Out;
++ }
++
++ err = asd_init_chip(asd_ha);
++ if (err) {
++ asd_printk("couldn't init the chip\n");
++ goto Out;
++ }
++Out:
++ return err;
++}
++
++/* ---------- Chip reset ---------- */
++
++/**
++ * asd_chip_reset -- reset the host adapter, etc
++ * @asd_ha: pointer to host adapter structure of interest
++ *
++ * Called from the ISR. Hard reset the chip. Let everything
++ * timeout. This should be no different than hot-unplugging the
++ * host adapter. Once everything times out we'll init the chip with
++ * a call to asd_init_chip() and enable interrupts with asd_enable_ints().
++ * XXX finish.
++ */
++static void asd_chip_reset(struct asd_ha_struct *asd_ha)
++{
++ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
++
++ ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));
++ asd_chip_hardrst(asd_ha);
++ sas_ha->notify_ha_event(sas_ha, HAE_RESET);
++}
++
++/* ---------- Done List Routines ---------- */
++
++static void asd_dl_tasklet_handler(unsigned long data)
++{
++ struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
++ struct asd_seq_data *seq = &asd_ha->seq;
++ unsigned long flags;
++
++ while (1) {
++ struct done_list_struct *dl = &seq->dl[seq->dl_next];
++ struct asd_ascb *ascb;
++
++ if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)
++ break;
++
++ /* find the aSCB */
++ spin_lock_irqsave(&seq->tc_index_lock, flags);
++ ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));
++ spin_unlock_irqrestore(&seq->tc_index_lock, flags);
++ if (unlikely(!ascb)) {
++ ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");
++ goto next_1;
++ } else if (ascb->scb->header.opcode == EMPTY_SCB) {
++ goto out;
++ } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {
++ goto next_1;
++ }
++ spin_lock_irqsave(&seq->pend_q_lock, flags);
++ list_del_init(&ascb->list);
++ seq->pending--;
++ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
++ out:
++ ascb->tasklet_complete(ascb, dl);
++
++ next_1:
++ seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
++ if (!seq->dl_next)
++ seq->dl_toggle ^= DL_TOGGLE_MASK;
++ }
++}
++
++/* ---------- Interrupt Service Routines ---------- */
++
++/**
++ * asd_process_donelist_isr -- schedule processing of done list entries
++ * @asd_ha: pointer to host adapter structure
++ */
++static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
++{
++ tasklet_schedule(&asd_ha->seq.dl_tasklet);
++}
++
++/**
++ * asd_com_sas_isr -- process device communication interrupt (COMINT)
++ * @asd_ha: pointer to host adapter structure
++ */
++static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha)
++{
++ u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);
++
++ /* clear COMSTAT int */
++ asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);
++
++ if (comstat & CSBUFPERR) {
++ asd_printk("%s: command/status buffer dma parity error\n",
++ pci_name(asd_ha->pcidev));
++ } else if (comstat & CSERR) {
++ int i;
++ u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
++ dmaerr &= 0xFF;
++ asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "
++ "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",
++ pci_name(asd_ha->pcidev),
++ dmaerr,
++ asd_read_reg_dword(asd_ha, CSDMAADR),
++ asd_read_reg_dword(asd_ha, CSDMAADR+4));
++ asd_printk("CSBUFFER:\n");
++ for (i = 0; i < 8; i++) {
++ asd_printk("%08x %08x %08x %08x\n",
++ asd_read_reg_dword(asd_ha, CSBUFFER),
++ asd_read_reg_dword(asd_ha, CSBUFFER+4),
++ asd_read_reg_dword(asd_ha, CSBUFFER+8),
++ asd_read_reg_dword(asd_ha, CSBUFFER+12));
++ }
++ asd_dump_seq_state(asd_ha, 0);
++ } else if (comstat & OVLYERR) {
++ u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
++ dmaerr = (dmaerr >> 8) & 0xFF;
++ asd_printk("%s: overlay dma error:0x%x\n",
++ pci_name(asd_ha->pcidev),
++ dmaerr);
++ }
++ asd_chip_reset(asd_ha);
++}
++
++static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus)
++{
++ static const char *halt_code[256] = {
++ "UNEXPECTED_INTERRUPT0",
++ "UNEXPECTED_INTERRUPT1",
++ "UNEXPECTED_INTERRUPT2",
++ "UNEXPECTED_INTERRUPT3",
++ "UNEXPECTED_INTERRUPT4",
++ "UNEXPECTED_INTERRUPT5",
++ "UNEXPECTED_INTERRUPT6",
++ "UNEXPECTED_INTERRUPT7",
++ "UNEXPECTED_INTERRUPT8",
++ "UNEXPECTED_INTERRUPT9",
++ "UNEXPECTED_INTERRUPT10",
++ [11 ... 19] = "unknown[11,19]",
++ "NO_FREE_SCB_AVAILABLE",
++ "INVALID_SCB_OPCODE",
++ "INVALID_MBX_OPCODE",
++ "INVALID_ATA_STATE",
++ "ATA_QUEUE_FULL",
++ "ATA_TAG_TABLE_FAULT",
++ "ATA_TAG_MASK_FAULT",
++ "BAD_LINK_QUEUE_STATE",
++ "DMA2CHIM_QUEUE_ERROR",
++ "EMPTY_SCB_LIST_FULL",
++ "unknown[30]",
++ "IN_USE_SCB_ON_FREE_LIST",
++ "BAD_OPEN_WAIT_STATE",
++ "INVALID_STP_AFFILIATION",
++ "unknown[34]",
++ "EXEC_QUEUE_ERROR",
++ "TOO_MANY_EMPTIES_NEEDED",
++ "EMPTY_REQ_QUEUE_ERROR",
++ "Q_MONIRTT_MGMT_ERROR",
++ "TARGET_MODE_FLOW_ERROR",
++ "DEVICE_QUEUE_NOT_FOUND",
++ "START_IRTT_TIMER_ERROR",
++ "ABORT_TASK_ILLEGAL_REQ",
++ [43 ... 255] = "unknown[43,255]"
++ };
++
++ if (dchstatus & CSEQINT) {
++ u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);
++
++ if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {
++ asd_printk("%s: CSEQ arp2int:0x%x\n",
++ pci_name(asd_ha->pcidev),
++ arp2int);
++ } else if (arp2int & ARP2HALTC)
++ asd_printk("%s: CSEQ halted: %s\n",
++ pci_name(asd_ha->pcidev),
++ halt_code[(arp2int>>16)&0xFF]);
++ else
++ asd_printk("%s: CARP2INT:0x%x\n",
++ pci_name(asd_ha->pcidev),
++ arp2int);
++ }
++ if (dchstatus & LSEQINT_MASK) {
++ int lseq;
++ u8 lseq_mask = dchstatus & LSEQINT_MASK;
++
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ u32 arp2int = asd_read_reg_dword(asd_ha,
++ LmARP2INT(lseq));
++ if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR
++ | ARP2CIOPERR)) {
++ asd_printk("%s: LSEQ%d arp2int:0x%x\n",
++ pci_name(asd_ha->pcidev),
++ lseq, arp2int);
++ /* XXX we should only do lseq reset */
++ } else if (arp2int & ARP2HALTC)
++ asd_printk("%s: LSEQ%d halted: %s\n",
++ pci_name(asd_ha->pcidev),
++ lseq,halt_code[(arp2int>>16)&0xFF]);
++ else
++ asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",
++ pci_name(asd_ha->pcidev), lseq,
++ arp2int);
++ }
++ }
++ asd_chip_reset(asd_ha);
++}
++
++/**
++ * asd_dch_sas_isr -- process device channel interrupt (DEVINT)
++ * @asd_ha: pointer to host adapter structure
++ */
++static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha)
++{
++ u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);
++
++ if (dchstatus & CFIFTOERR) {
++ asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));
++ asd_chip_reset(asd_ha);
++ } else
++ asd_arp2_err(asd_ha, dchstatus);
++}
++
++/**
++ * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR)
++ * @asd_ha: pointer to host adapter structure
++ */
++static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha)
++{
++ u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);
++
++ if (!(stat0r & ASIERR)) {
++ asd_printk("hmm, EXSI interrupted but no error?\n");
++ return;
++ }
++
++ if (stat0r & ASIFMTERR) {
++ asd_printk("ASI SEEPROM format error for %s\n",
++ pci_name(asd_ha->pcidev));
++ } else if (stat0r & ASISEECHKERR) {
++ u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R);
++ asd_printk("ASI SEEPROM checksum 0x%x error for %s\n",
++ stat1r & CHECKSUM_MASK,
++ pci_name(asd_ha->pcidev));
++ } else {
++ u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR);
++
++ if (!(statr & CPI2ASIMSTERR_MASK)) {
++ ASD_DPRINTK("hmm, ASIERR?\n");
++ return;
++ } else {
++ u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR);
++ u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR);
++
++ asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, "
++ "count: 0x%x, byteen: 0x%x, targerr: 0x%x "
++ "master id: 0x%x, master err: 0x%x\n",
++ pci_name(asd_ha->pcidev),
++ addr, data,
++ (statr & CPI2ASIBYTECNT_MASK) >> 16,
++ (statr & CPI2ASIBYTEEN_MASK) >> 12,
++ (statr & CPI2ASITARGERR_MASK) >> 8,
++ (statr & CPI2ASITARGMID_MASK) >> 4,
++ (statr & CPI2ASIMSTERR_MASK));
++ }
++ }
++ asd_chip_reset(asd_ha);
++}
++
++/**
++ * asd_hst_pcix_isr -- process host interface interrupts
++ * @asd_ha: pointer to host adapter structure
++ *
++ * Asserted on PCIX errors: target abort, etc.
++ */
++static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
++{
++ u16 status;
++ u32 pcix_status;
++ u32 ecc_status;
++
++ pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status);
++ pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status);
++ pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status);
++
++ if (status & PCI_STATUS_DETECTED_PARITY)
++ asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev));
++ else if (status & PCI_STATUS_REC_MASTER_ABORT)
++ asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev));
++ else if (status & PCI_STATUS_REC_TARGET_ABORT)
++ asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev));
++ else if (status & PCI_STATUS_PARITY)
++ asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev));
++ else if (pcix_status & RCV_SCE) {
++ asd_printk("received split completion error for %s\n",
++ pci_name(asd_ha->pcidev));
++ pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
++ /* XXX: Abort task? */
++ return;
++ } else if (pcix_status & UNEXP_SC) {
++ asd_printk("unexpected split completion for %s\n",
++ pci_name(asd_ha->pcidev));
++ pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
++ /* ignore */
++ return;
++ } else if (pcix_status & SC_DISCARD)
++ asd_printk("split completion discarded for %s\n",
++ pci_name(asd_ha->pcidev));
++ else if (ecc_status & UNCOR_ECCERR)
++ asd_printk("uncorrectable ECC error for %s\n",
++ pci_name(asd_ha->pcidev));
++ asd_chip_reset(asd_ha);
++}
++
++/**
++ * asd_hw_isr -- host adapter interrupt service routine
++ * @irq: ignored
++ * @dev_id: pointer to host adapter structure
++ *
++ * The ISR processes done list entries and level 3 error handling.
++ */
++irqreturn_t asd_hw_isr(int irq, void *dev_id)
++{
++ struct asd_ha_struct *asd_ha = dev_id;
++ u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
++
++ if (!chimint)
++ return IRQ_NONE;
++
++ asd_write_reg_dword(asd_ha, CHIMINT, chimint);
++ (void) asd_read_reg_dword(asd_ha, CHIMINT);
++
++ if (chimint & DLAVAIL)
++ asd_process_donelist_isr(asd_ha);
++ if (chimint & COMINT)
++ asd_com_sas_isr(asd_ha);
++ if (chimint & DEVINT)
++ asd_dch_sas_isr(asd_ha);
++ if (chimint & INITERR)
++ asd_rbi_exsi_isr(asd_ha);
++ if (chimint & HOSTERR)
++ asd_hst_pcix_isr(asd_ha);
++
++ return IRQ_HANDLED;
++}
++
++/* ---------- SCB handling ---------- */
++
++static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
++ gfp_t gfp_flags)
++{
++ extern kmem_cache_t *asd_ascb_cache;
++ struct asd_seq_data *seq = &asd_ha->seq;
++ struct asd_ascb *ascb;
++ unsigned long flags;
++
++ ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags);
++
++ if (ascb) {
++ memset(ascb, 0, sizeof(*ascb));
++ ascb->dma_scb.size = sizeof(struct scb);
++ ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
++ gfp_flags,
++ &ascb->dma_scb.dma_handle);
++ if (!ascb->dma_scb.vaddr) {
++ kmem_cache_free(asd_ascb_cache, ascb);
++ return NULL;
++ }
++ memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb));
++ asd_init_ascb(asd_ha, ascb);
++
++ spin_lock_irqsave(&seq->tc_index_lock, flags);
++ ascb->tc_index = asd_tc_index_get(seq, ascb);
++ spin_unlock_irqrestore(&seq->tc_index_lock, flags);
++ if (ascb->tc_index == -1)
++ goto undo;
++
++ ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index);
++ }
++
++ return ascb;
++undo:
++ dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
++ ascb->dma_scb.dma_handle);
++ kmem_cache_free(asd_ascb_cache, ascb);
++ ASD_DPRINTK("no index for ascb\n");
++ return NULL;
++}
++
++/**
++ * asd_ascb_alloc_list -- allocate a list of aSCBs
++ * @asd_ha: pointer to host adapter structure
++ * @num: pointer to integer number of aSCBs
++ * @gfp_flags: GFP_ flags.
++ *
++ * This is the only function which is used to allocate aSCBs.
++ * It can allocate one or many. If more than one, then they form
++ * a linked list in two ways: by their list field of the ascb struct
++ * and by the next_scb field of the scb_header.
++ *
++ * Returns NULL if no memory was available, else pointer to a list
++ * of ascbs. When this function returns, @num would be the number
++ * of SCBs which were not able to be allocated, 0 if all requested
++ * were able to be allocated.
++ */
++struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
++ *asd_ha, int *num,
++ gfp_t gfp_flags)
++{
++ struct asd_ascb *first = NULL;
++
++ for ( ; *num > 0; --*num) {
++ struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags);
++
++ if (!ascb)
++ break;
++ else if (!first)
++ first = ascb;
++ else {
++ struct asd_ascb *last = list_entry(first->list.prev,
++ struct asd_ascb,
++ list);
++ list_add_tail(&ascb->list, &first->list);
++ last->scb->header.next_scb =
++ cpu_to_le64(((u64)ascb->dma_scb.dma_handle));
++ }
++ }
++
++ return first;
++}
++
++/**
++ * asd_swap_head_scb -- swap the head scb
++ * @asd_ha: pointer to host adapter structure
++ * @ascb: pointer to the head of an ascb list
++ *
++ * The sequencer knows the DMA address of the next SCB to be DMAed to
++ * the host adapter, from initialization or from the last list DMAed.
++ * seq->next_scb keeps the address of this SCB. The sequencer will
++ * DMA to the host adapter this list of SCBs. But the head (first
++ * element) of this list is not known to the sequencer. Here we swap
++ * the head of the list with the known SCB (memcpy()).
++ * Only one memcpy() is required per list so it is in our interest
++ * to keep the list of SCB as long as possible so that the ratio
++ * of number of memcpy calls to the number of SCB DMA-ed is as small
++ * as possible.
++ *
++ * LOCKING: called with the pending list lock held.
++ */
++static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha,
++ struct asd_ascb *ascb)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ struct asd_ascb *last = list_entry(ascb->list.prev,
++ struct asd_ascb,
++ list);
++ struct asd_dma_tok t = ascb->dma_scb;
++
++ memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb));
++ ascb->dma_scb = seq->next_scb;
++ ascb->scb = ascb->dma_scb.vaddr;
++ seq->next_scb = t;
++ last->scb->header.next_scb =
++ cpu_to_le64(((u64)seq->next_scb.dma_handle));
++}
++
++/**
++ * asd_start_timers -- (add and) start timers of SCBs
++ * @list: pointer to struct list_head of the scbs
++ * @to: timeout in jiffies
++ *
++ * If an SCB in the @list has no timer function, assign the default
++ * one, then start the timer of the SCB. This function is
++ * intended to be called from asd_post_ascb_list(), just prior to
++ * posting the SCBs to the sequencer.
++ */
++static inline void asd_start_scb_timers(struct list_head *list)
++{
++ struct asd_ascb *ascb;
++ list_for_each_entry(ascb, list, list) {
++ if (!ascb->uldd_timer) {
++ ascb->timer.data = (unsigned long) ascb;
++ ascb->timer.function = asd_ascb_timedout;
++ ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
++ add_timer(&ascb->timer);
++ }
++ }
++}
++
++/**
++ * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter
++ * @asd_ha: pointer to a host adapter structure
++ * @ascb: pointer to the first aSCB in the list
++ * @num: number of aSCBs in the list (to be posted)
++ *
++ * See queueing comment in asd_post_escb_list().
++ *
++ * Additional note on queuing: In order to minimize the ratio of memcpy()
++ * to the number of ascbs sent, we try to batch-send as many ascbs as possible
++ * in one go.
++ * Two cases are possible:
++ * A) can_queue >= num,
++ * B) can_queue < num.
++ * Case A: we can send the whole batch at once. Increment "pending"
++ * in the beginning of this function, when it is checked, in order to
++ * eliminate races when this function is called by multiple processes.
++ * Case B: should never happen if the managing layer considers
++ * lldd_queue_size.
++ */
++int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
++ int num)
++{
++ unsigned long flags;
++ LIST_HEAD(list);
++ int can_queue;
++
++ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
++ can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending;
++ if (can_queue >= num)
++ asd_ha->seq.pending += num;
++ else
++ can_queue = 0;
++
++ if (!can_queue) {
++ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
++ asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev));
++ return -SAS_QUEUE_FULL;
++ }
++
++ asd_swap_head_scb(asd_ha, ascb);
++
++ __list_add(&list, ascb->list.prev, &ascb->list);
++
++ asd_start_scb_timers(&list);
++
++ asd_ha->seq.scbpro += num;
++ list_splice_init(&list, asd_ha->seq.pend_q.prev);
++ asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
++ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
++
++ return 0;
++}
++
++/**
++ * asd_post_escb_list -- post a list of 1 or more empty scb
++ * @asd_ha: pointer to a host adapter structure
++ * @ascb: pointer to the first empty SCB in the list
++ * @num: number of aSCBs in the list (to be posted)
++ *
++ * This is essentially the same as asd_post_ascb_list, but we do not
++ * increment pending, add those to the pending list or get indexes.
++ * See asd_init_escbs() and asd_init_post_escbs().
++ *
++ * Since sending a list of ascbs is a superset of sending a single
++ * ascb, this function exists to generalize this. More specifically,
++ * when sending a list of those, we want to do only a _single_
++ * memcpy() at swap head, as opposed to for each ascb sent (in the
++ * case of sending them one by one). That is, we want to minimize the
++ * ratio of memcpy() operations to the number of ascbs sent. The same
++ * logic applies to asd_post_ascb_list().
++ */
++int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
++ int num)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
++ asd_swap_head_scb(asd_ha, ascb);
++ asd_ha->seq.scbpro += num;
++ asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
++ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
++
++ return 0;
++}
++
++/* ---------- LED ---------- */
++
++/**
++ * asd_turn_led -- turn on/off an LED
++ * @asd_ha: pointer to host adapter structure
++ * @phy_id: the PHY id whose LED we want to manupulate
++ * @op: 1 to turn on, 0 to turn off
++ */
++void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
++{
++ if (phy_id < ASD_MAX_PHYS) {
++ u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id));
++ if (op)
++ v |= LEDPOL;
++ else
++ v &= ~LEDPOL;
++ asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v);
++ }
++}
++
++/**
++ * asd_control_led -- enable/disable an LED on the board
++ * @asd_ha: pointer to host adapter structure
++ * @phy_id: integer, the phy id
++ * @op: integer, 1 to enable, 0 to disable the LED
++ *
++ * First we output enable the LED, then we set the source
++ * to be an external module.
++ */
++void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
++{
++ if (phy_id < ASD_MAX_PHYS) {
++ u32 v;
++
++ v = asd_read_reg_dword(asd_ha, GPIOOER);
++ if (op)
++ v |= (1 << phy_id);
++ else
++ v &= ~(1 << phy_id);
++ asd_write_reg_dword(asd_ha, GPIOOER, v);
++
++ v = asd_read_reg_dword(asd_ha, GPIOCNFGR);
++ if (op)
++ v |= (1 << phy_id);
++ else
++ v &= ~(1 << phy_id);
++ asd_write_reg_dword(asd_ha, GPIOCNFGR, v);
++ }
++}
++
++/* ---------- PHY enable ---------- */
++
++static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id)
++{
++ struct asd_phy *phy = &asd_ha->phys[phy_id];
++
++ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY),
++ HOTPLUG_DELAY_TIMEOUT);
++
++ /* Get defaults from manuf. sector */
++ /* XXX we need defaults for those in case MS is broken. */
++ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0),
++ phy->phy_desc->phy_control_0);
++ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1),
++ phy->phy_desc->phy_control_1);
++ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2),
++ phy->phy_desc->phy_control_2);
++ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3),
++ phy->phy_desc->phy_control_3);
++
++ asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id),
++ ASD_COMINIT_TIMEOUT);
++
++ asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id),
++ phy->id_frm_tok->dma_handle);
++
++ asd_control_led(asd_ha, phy_id, 1);
++
++ return 0;
++}
++
++int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
++{
++ u8 phy_m;
++ u8 i;
++ int num = 0, k;
++ struct asd_ascb *ascb;
++ struct asd_ascb *ascb_list;
++
++ if (!phy_mask) {
++ asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
++ return 0;
++ }
++
++ for_each_phy(phy_mask, phy_m, i) {
++ num++;
++ asd_enable_phy(asd_ha, i);
++ }
++
++ k = num;
++ ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL);
++ if (!ascb_list) {
++ asd_printk("no memory for control phy ascb list\n");
++ return -ENOMEM;
++ }
++ num -= k;
++
++ ascb = ascb_list;
++ for_each_phy(phy_mask, phy_m, i) {
++ asd_build_control_phy(ascb, i, ENABLE_PHY);
++ ascb = list_entry(ascb->list.next, struct asd_ascb, list);
++ }
++ ASD_DPRINTK("posting %d control phy scbs\n", num);
++ k = asd_post_ascb_list(asd_ha, ascb_list, num);
++ if (k)
++ asd_ascb_free_list(ascb_list);
++
++ return k;
++}
+diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
+new file mode 100644
+index 0000000..7b6aca0
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
+@@ -0,0 +1,398 @@
++/*
++ * Aic94xx SAS/SATA driver hardware interface header file.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef _AIC94XX_HWI_H_
++#define _AIC94XX_HWI_H_
++
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/dma-mapping.h>
++
++#include <scsi/libsas.h>
++
++#include "aic94xx.h"
++#include "aic94xx_sas.h"
++
++/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
++#define ASD_MAX_PHYS 8
++#define ASD_PCBA_SN_SIZE 12
++
++/* Those are to be further named properly, the "RAZORx" part, and
++ * subsequently included in include/linux/pci_ids.h.
++ */
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
++#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
++
++struct asd_ha_addrspace {
++ void __iomem *addr;
++ unsigned long start; /* pci resource start */
++ unsigned long len; /* pci resource len */
++ unsigned long flags; /* pci resource flags */
++
++ /* addresses internal to the host adapter */
++ u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
++ u32 swb_base;
++ u32 swc_base;
++};
++
++struct bios_struct {
++ int present;
++ u8 maj;
++ u8 min;
++ u32 bld;
++};
++
++struct unit_element_struct {
++ u16 num;
++ u16 size;
++ void *area;
++};
++
++struct flash_struct {
++ u32 bar;
++ int present;
++ int wide;
++ u8 manuf;
++ u8 dev_id;
++ u8 sec_prot;
++
++ u32 dir_offs;
++};
++
++struct asd_phy_desc {
++ /* From CTRL-A settings, then set to what is appropriate */
++ u8 sas_addr[SAS_ADDR_SIZE];
++ u8 max_sas_lrate;
++ u8 min_sas_lrate;
++ u8 max_sata_lrate;
++ u8 min_sata_lrate;
++ u8 flags;
++#define ASD_CRC_DIS 1
++#define ASD_SATA_SPINUP_HOLD 2
++
++ u8 phy_control_0; /* mode 5 reg 0x160 */
++ u8 phy_control_1; /* mode 5 reg 0x161 */
++ u8 phy_control_2; /* mode 5 reg 0x162 */
++ u8 phy_control_3; /* mode 5 reg 0x163 */
++};
++
++struct asd_dma_tok {
++ void *vaddr;
++ dma_addr_t dma_handle;
++ size_t size;
++};
++
++struct hw_profile {
++ struct bios_struct bios;
++ struct unit_element_struct ue;
++ struct flash_struct flash;
++
++ u8 sas_addr[SAS_ADDR_SIZE];
++ char pcba_sn[ASD_PCBA_SN_SIZE+1];
++
++ u8 enabled_phys; /* mask of enabled phys */
++ struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
++ u32 max_scbs; /* absolute sequencer scb queue size */
++ struct asd_dma_tok *scb_ext;
++ u32 max_ddbs;
++ struct asd_dma_tok *ddb_ext;
++
++ spinlock_t ddb_lock;
++ void *ddb_bitmap;
++
++ int num_phys; /* ENABLEABLE */
++ int max_phys; /* REPORTED + ENABLEABLE */
++
++ unsigned addr_range; /* max # of addrs; max # of possible ports */
++ unsigned port_name_base;
++ unsigned dev_name_base;
++ unsigned sata_name_base;
++};
++
++struct asd_ascb {
++ struct list_head list;
++ struct asd_ha_struct *ha;
++
++ struct scb *scb; /* equals dma_scb->vaddr */
++ struct asd_dma_tok dma_scb;
++ struct asd_dma_tok *sg_arr;
++
++ void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
++ u8 uldd_timer:1;
++
++ /* internally generated command */
++ struct timer_list timer;
++ struct completion completion;
++ u8 tag_valid:1;
++ __be16 tag; /* error recovery only */
++
++ /* If this is an Empty SCB, index of first edb in seq->edb_arr. */
++ int edb_index;
++
++ /* Used by the timer timeout function. */
++ int tc_index;
++
++ void *uldd_task;
++};
++
++#define ASD_DL_SIZE_BITS 0x8
++#define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS))
++#define ASD_DEF_DL_TOGGLE 0x01
++
++struct asd_seq_data {
++ spinlock_t pend_q_lock;
++ u16 scbpro;
++ int pending;
++ struct list_head pend_q;
++ int can_queue; /* per adapter */
++ struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
++
++ spinlock_t tc_index_lock;
++ void **tc_index_array;
++ void *tc_index_bitmap;
++ int tc_index_bitmap_bits;
++
++ struct tasklet_struct dl_tasklet;
++ struct done_list_struct *dl; /* array of done list entries, equals */
++ struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
++ int dl_toggle;
++ int dl_next;
++
++ int num_edbs;
++ struct asd_dma_tok **edb_arr;
++ int num_escbs;
++ struct asd_ascb **escb_arr; /* array of pointers to escbs */
++};
++
++/* This is the Host Adapter structure. It describes the hardware
++ * SAS adapter.
++ */
++struct asd_ha_struct {
++ struct pci_dev *pcidev;
++ const char *name;
++
++ struct sas_ha_struct sas_ha;
++
++ u8 revision_id;
++
++ int iospace;
++ spinlock_t iolock;
++ struct asd_ha_addrspace io_handle[2];
++
++ struct hw_profile hw_prof;
++
++ struct asd_phy phys[ASD_MAX_PHYS];
++ struct asd_sas_port ports[ASD_MAX_PHYS];
++
++ struct dma_pool *scb_pool;
++
++ struct asd_seq_data seq; /* sequencer related */
++};
++
++/* ---------- Common macros ---------- */
++
++#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
++#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \
++ ? ((u32)((__dma_handle) >> 32)) \
++ : ((u32)0))
++
++#define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev))
++#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \
++ && ((__site_no) & 0xF0FF) > 0x001F)
++/* For each bit set in __lseq_mask, set __lseq to equal the bit
++ * position of the set bit and execute the statement following.
++ * __mc is the temporary mask, used as a mask "counter".
++ */
++#define for_each_sequencer(__lseq_mask, __mc, __lseq) \
++ for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
++ if (((__mc) & 1))
++#define for_each_phy(__lseq_mask, __mc, __lseq) \
++ for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
++ if (((__mc) & 1))
++
++#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
++
++/* ---------- DMA allocs ---------- */
++
++static inline struct asd_dma_tok *asd_dmatok_alloc(gfp_t flags)
++{
++ return kmem_cache_alloc(asd_dma_token_cache, flags);
++}
++
++static inline void asd_dmatok_free(struct asd_dma_tok *token)
++{
++ kmem_cache_free(asd_dma_token_cache, token);
++}
++
++static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
++ asd_ha, size_t size,
++ gfp_t flags)
++{
++ struct asd_dma_tok *token = asd_dmatok_alloc(flags);
++ if (token) {
++ token->size = size;
++ token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
++ token->size,
++ &token->dma_handle,
++ flags);
++ if (!token->vaddr) {
++ asd_dmatok_free(token);
++ token = NULL;
++ }
++ }
++ return token;
++}
++
++static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
++ struct asd_dma_tok *token)
++{
++ if (token) {
++ dma_free_coherent(&asd_ha->pcidev->dev, token->size,
++ token->vaddr, token->dma_handle);
++ asd_dmatok_free(token);
++ }
++}
++
++static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
++ struct asd_ascb *ascb)
++{
++ INIT_LIST_HEAD(&ascb->list);
++ ascb->scb = ascb->dma_scb.vaddr;
++ ascb->ha = asd_ha;
++ ascb->timer.function = NULL;
++ init_timer(&ascb->timer);
++ ascb->tc_index = -1;
++ init_completion(&ascb->completion);
++}
++
++/* Must be called with the tc_index_lock held!
++ */
++static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
++{
++ seq->tc_index_array[index] = NULL;
++ clear_bit(index, seq->tc_index_bitmap);
++}
++
++/* Must be called with the tc_index_lock held!
++ */
++static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
++{
++ int index;
++
++ index = find_first_zero_bit(seq->tc_index_bitmap,
++ seq->tc_index_bitmap_bits);
++ if (index == seq->tc_index_bitmap_bits)
++ return -1;
++
++ seq->tc_index_array[index] = ptr;
++ set_bit(index, seq->tc_index_bitmap);
++
++ return index;
++}
++
++/* Must be called with the tc_index_lock held!
++ */
++static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
++{
++ return seq->tc_index_array[index];
++}
++
++/**
++ * asd_ascb_free -- free a single aSCB after is has completed
++ * @ascb: pointer to the aSCB of interest
++ *
++ * This frees an aSCB after it has been executed/completed by
++ * the sequencer.
++ */
++static inline void asd_ascb_free(struct asd_ascb *ascb)
++{
++ if (ascb) {
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ unsigned long flags;
++
++ BUG_ON(!list_empty(&ascb->list));
++ spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
++ asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
++ spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
++ dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
++ ascb->dma_scb.dma_handle);
++ kmem_cache_free(asd_ascb_cache, ascb);
++ }
++}
++
++/**
++ * asd_ascb_list_free -- free a list of ascbs
++ * @ascb_list: a list of ascbs
++ *
++ * This function will free a list of ascbs allocated by asd_ascb_alloc_list.
++ * It is used when say the scb queueing function returned QUEUE_FULL,
++ * and we do not need the ascbs any more.
++ */
++static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
++{
++ LIST_HEAD(list);
++ struct list_head *n, *pos;
++
++ __list_add(&list, ascb_list->list.prev, &ascb_list->list);
++ list_for_each_safe(pos, n, &list) {
++ list_del_init(pos);
++ asd_ascb_free(list_entry(pos, struct asd_ascb, list));
++ }
++}
++
++/* ---------- Function declarations ---------- */
++
++int asd_init_hw(struct asd_ha_struct *asd_ha);
++irqreturn_t asd_hw_isr(int irq, void *dev_id);
++
++
++struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
++ *asd_ha, int *num,
++ gfp_t gfp_mask);
++
++int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
++ int num);
++int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
++ int num);
++
++int asd_init_post_escbs(struct asd_ha_struct *asd_ha);
++void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
++void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
++void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
++int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
++void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
++ u8 subfunc);
++
++void asd_ascb_timedout(unsigned long data);
++int asd_chip_hardrst(struct asd_ha_struct *asd_ha);
++
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
+new file mode 100644
+index 0000000..a4cc432
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_init.c
+@@ -0,0 +1,892 @@
++/*
++ * Aic94xx SAS/SATA driver initialization.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++
++#include <scsi/scsi_host.h>
++
++#include "aic94xx.h"
++#include "aic94xx_reg.h"
++#include "aic94xx_hwi.h"
++#include "aic94xx_seq.h"
++
++/* The format is "version.release.patchlevel" */
++#define ASD_DRIVER_VERSION "1.0.2"
++
++static int use_msi = 0;
++module_param_named(use_msi, use_msi, int, S_IRUGO);
++MODULE_PARM_DESC(use_msi, "\n"
++ "\tEnable(1) or disable(0) using PCI MSI.\n"
++ "\tDefault: 0");
++
++static int lldd_max_execute_num = 0;
++module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
++MODULE_PARM_DESC(collector, "\n"
++ "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
++ "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
++ "\tThe aic94xx SAS LLDD supports both modes.\n"
++ "\tDefault: 0 (Direct Mode).\n");
++
++char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
++
++static struct scsi_transport_template *aic94xx_transport_template;
++
++static struct scsi_host_template aic94xx_sht = {
++ .module = THIS_MODULE,
++ /* .name is initialized */
++ .name = "aic94xx",
++ .queuecommand = sas_queuecommand,
++ .target_alloc = sas_target_alloc,
++ .slave_configure = sas_slave_configure,
++ .slave_destroy = sas_slave_destroy,
++ .change_queue_depth = sas_change_queue_depth,
++ .change_queue_type = sas_change_queue_type,
++ .bios_param = sas_bios_param,
++ .can_queue = 1,
++ .cmd_per_lun = 1,
++ .this_id = -1,
++ .sg_tablesize = SG_ALL,
++ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
++ .use_clustering = ENABLE_CLUSTERING,
++};
++
++static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
++{
++ int err, i;
++ struct asd_ha_addrspace *io_handle;
++
++ asd_ha->iospace = 0;
++ for (i = 0; i < 3; i += 2) {
++ io_handle = &asd_ha->io_handle[i==0?0:1];
++ io_handle->start = pci_resource_start(asd_ha->pcidev, i);
++ io_handle->len = pci_resource_len(asd_ha->pcidev, i);
++ io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
++ err = -ENODEV;
++ if (!io_handle->start || !io_handle->len) {
++ asd_printk("MBAR%d start or length for %s is 0.\n",
++ i==0?0:1, pci_name(asd_ha->pcidev));
++ goto Err;
++ }
++ err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
++ if (err) {
++ asd_printk("couldn't reserve memory region for %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Err;
++ }
++ if (io_handle->flags & IORESOURCE_CACHEABLE)
++ io_handle->addr = ioremap(io_handle->start,
++ io_handle->len);
++ else
++ io_handle->addr = ioremap_nocache(io_handle->start,
++ io_handle->len);
++ if (!io_handle->addr) {
++ asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1,
++ pci_name(asd_ha->pcidev));
++ goto Err_unreq;
++ }
++ }
++
++ return 0;
++Err_unreq:
++ pci_release_region(asd_ha->pcidev, i);
++Err:
++ if (i > 0) {
++ io_handle = &asd_ha->io_handle[0];
++ iounmap(io_handle->addr);
++ pci_release_region(asd_ha->pcidev, 0);
++ }
++ return err;
++}
++
++static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
++{
++ struct asd_ha_addrspace *io_handle;
++
++ io_handle = &asd_ha->io_handle[1];
++ iounmap(io_handle->addr);
++ pci_release_region(asd_ha->pcidev, 2);
++
++ io_handle = &asd_ha->io_handle[0];
++ iounmap(io_handle->addr);
++ pci_release_region(asd_ha->pcidev, 0);
++}
++
++static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
++{
++ int i = PCI_IOBAR_OFFSET, err;
++ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];
++
++ asd_ha->iospace = 1;
++ io_handle->start = pci_resource_start(asd_ha->pcidev, i);
++ io_handle->len = pci_resource_len(asd_ha->pcidev, i);
++ io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
++ io_handle->addr = (void __iomem *) io_handle->start;
++ if (!io_handle->start || !io_handle->len) {
++ asd_printk("couldn't get IO ports for %s\n",
++ pci_name(asd_ha->pcidev));
++ return -ENODEV;
++ }
++ err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
++ if (err) {
++ asd_printk("couldn't reserve io space for %s\n",
++ pci_name(asd_ha->pcidev));
++ }
++
++ return err;
++}
++
++static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
++{
++ pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
++}
++
++static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha)
++{
++ int err;
++ u16 cmd_reg;
++
++ err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg);
++ if (err) {
++ asd_printk("couldn't read command register of %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Err;
++ }
++
++ err = -ENODEV;
++ if (cmd_reg & PCI_COMMAND_MEMORY) {
++ if ((err = asd_map_memio(asd_ha)))
++ goto Err;
++ } else if (cmd_reg & PCI_COMMAND_IO) {
++ if ((err = asd_map_ioport(asd_ha)))
++ goto Err;
++ asd_printk("%s ioport mapped -- upgrade your hardware\n",
++ pci_name(asd_ha->pcidev));
++ } else {
++ asd_printk("no proper device access to %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Err;
++ }
++
++ return 0;
++Err:
++ return err;
++}
++
++static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
++{
++ if (asd_ha->iospace)
++ asd_unmap_ioport(asd_ha);
++ else
++ asd_unmap_memio(asd_ha);
++}
++
++static const char *asd_dev_rev[30] = {
++ [0] = "A0",
++ [1] = "A1",
++ [8] = "B0",
++};
++
++static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
++{
++ int err, i;
++
++ err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
++ &asd_ha->revision_id);
++ if (err) {
++ asd_printk("couldn't read REVISION ID register of %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Err;
++ }
++ err = -ENODEV;
++ if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
++ asd_printk("%s is revision %s (%X), which is not supported\n",
++ pci_name(asd_ha->pcidev),
++ asd_dev_rev[asd_ha->revision_id],
++ asd_ha->revision_id);
++ goto Err;
++ }
++ /* Provide some sane default values. */
++ asd_ha->hw_prof.max_scbs = 512;
++ asd_ha->hw_prof.max_ddbs = 128;
++ asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
++ /* All phys are enabled, by default. */
++ asd_ha->hw_prof.enabled_phys = 0xFF;
++ for (i = 0; i < ASD_MAX_PHYS; i++) {
++ asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
++ SAS_LINK_RATE_3_0_GBPS;
++ asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
++ SAS_LINK_RATE_1_5_GBPS;
++ asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
++ SAS_LINK_RATE_1_5_GBPS;
++ asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
++ SAS_LINK_RATE_1_5_GBPS;
++ }
++
++ return 0;
++Err:
++ return err;
++}
++
++static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
++{
++ int err = asd_common_setup(asd_ha);
++
++ if (err)
++ return err;
++
++ asd_ha->hw_prof.addr_range = 8;
++ asd_ha->hw_prof.port_name_base = 0;
++ asd_ha->hw_prof.dev_name_base = 8;
++ asd_ha->hw_prof.sata_name_base = 16;
++
++ return 0;
++}
++
++static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
++{
++ int err = asd_common_setup(asd_ha);
++
++ if (err)
++ return err;
++
++ asd_ha->hw_prof.addr_range = 4;
++ asd_ha->hw_prof.port_name_base = 0;
++ asd_ha->hw_prof.dev_name_base = 4;
++ asd_ha->hw_prof.sata_name_base = 8;
++
++ return 0;
++}
++
++static ssize_t asd_show_dev_rev(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
++ return snprintf(buf, PAGE_SIZE, "%s\n",
++ asd_dev_rev[asd_ha->revision_id]);
++}
++static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL);
++
++static ssize_t asd_show_dev_bios_build(struct device *dev,
++ struct device_attribute *attr,char *buf)
++{
++ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
++ return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld);
++}
++static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL);
++
++static ssize_t asd_show_dev_pcba_sn(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
++ return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn);
++}
++static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
++
++static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
++{
++ int err;
++
++ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
++ if (err)
++ return err;
++
++ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
++ if (err)
++ goto err_rev;
++
++ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
++ if (err)
++ goto err_biosb;
++
++ return 0;
++
++err_biosb:
++ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
++err_rev:
++ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
++ return err;
++}
++
++static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
++{
++ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
++ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
++ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
++}
++
++/* The first entry, 0, is used for dynamic ids, the rest for devices
++ * we know about.
++ */
++static struct asd_pcidev_struct {
++ const char * name;
++ int (*setup)(struct asd_ha_struct *asd_ha);
++} asd_pcidev_data[] = {
++ /* Id 0 is used for dynamic ids. */
++ { .name = "Adaptec AIC-94xx SAS/SATA Host Adapter",
++ .setup = asd_aic9410_setup
++ },
++ { .name = "Adaptec AIC-9410W SAS/SATA Host Adapter",
++ .setup = asd_aic9410_setup
++ },
++ { .name = "Adaptec AIC-9405W SAS/SATA Host Adapter",
++ .setup = asd_aic9405_setup
++ },
++};
++
++static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
++{
++ asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",
++ &asd_ha->pcidev->dev,
++ sizeof(struct scb),
++ 8, 0);
++ if (!asd_ha->scb_pool) {
++ asd_printk("couldn't create scb pool\n");
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++/**
++ * asd_free_edbs -- free empty data buffers
++ * asd_ha: pointer to host adapter structure
++ */
++static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int i;
++
++ for (i = 0; i < seq->num_edbs; i++)
++ asd_free_coherent(asd_ha, seq->edb_arr[i]);
++ kfree(seq->edb_arr);
++ seq->edb_arr = NULL;
++}
++
++static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int i;
++
++ for (i = 0; i < seq->num_escbs; i++) {
++ if (!list_empty(&seq->escb_arr[i]->list))
++ list_del_init(&seq->escb_arr[i]->list);
++
++ asd_ascb_free(seq->escb_arr[i]);
++ }
++ kfree(seq->escb_arr);
++ seq->escb_arr = NULL;
++}
++
++static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
++{
++ int i;
++
++ if (asd_ha->hw_prof.ddb_ext)
++ asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext);
++ if (asd_ha->hw_prof.scb_ext)
++ asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext);
++
++ if (asd_ha->hw_prof.ddb_bitmap)
++ kfree(asd_ha->hw_prof.ddb_bitmap);
++ asd_ha->hw_prof.ddb_bitmap = NULL;
++
++ for (i = 0; i < ASD_MAX_PHYS; i++) {
++ struct asd_phy *phy = &asd_ha->phys[i];
++
++ asd_free_coherent(asd_ha, phy->id_frm_tok);
++ }
++ if (asd_ha->seq.escb_arr)
++ asd_free_escbs(asd_ha);
++ if (asd_ha->seq.edb_arr)
++ asd_free_edbs(asd_ha);
++ if (asd_ha->hw_prof.ue.area) {
++ kfree(asd_ha->hw_prof.ue.area);
++ asd_ha->hw_prof.ue.area = NULL;
++ }
++ if (asd_ha->seq.tc_index_array) {
++ kfree(asd_ha->seq.tc_index_array);
++ kfree(asd_ha->seq.tc_index_bitmap);
++ asd_ha->seq.tc_index_array = NULL;
++ asd_ha->seq.tc_index_bitmap = NULL;
++ }
++ if (asd_ha->seq.actual_dl) {
++ asd_free_coherent(asd_ha, asd_ha->seq.actual_dl);
++ asd_ha->seq.actual_dl = NULL;
++ asd_ha->seq.dl = NULL;
++ }
++ if (asd_ha->seq.next_scb.vaddr) {
++ dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr,
++ asd_ha->seq.next_scb.dma_handle);
++ asd_ha->seq.next_scb.vaddr = NULL;
++ }
++ dma_pool_destroy(asd_ha->scb_pool);
++ asd_ha->scb_pool = NULL;
++}
++
++kmem_cache_t *asd_dma_token_cache;
++kmem_cache_t *asd_ascb_cache;
++
++static int asd_create_global_caches(void)
++{
++ if (!asd_dma_token_cache) {
++ asd_dma_token_cache
++ = kmem_cache_create(ASD_DRIVER_NAME "_dma_token",
++ sizeof(struct asd_dma_tok),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!asd_dma_token_cache) {
++ asd_printk("couldn't create dma token cache\n");
++ return -ENOMEM;
++ }
++ }
++
++ if (!asd_ascb_cache) {
++ asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb",
++ sizeof(struct asd_ascb),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (!asd_ascb_cache) {
++ asd_printk("couldn't create ascb cache\n");
++ goto Err;
++ }
++ }
++
++ return 0;
++Err:
++ kmem_cache_destroy(asd_dma_token_cache);
++ asd_dma_token_cache = NULL;
++ return -ENOMEM;
++}
++
++static void asd_destroy_global_caches(void)
++{
++ if (asd_dma_token_cache)
++ kmem_cache_destroy(asd_dma_token_cache);
++ asd_dma_token_cache = NULL;
++
++ if (asd_ascb_cache)
++ kmem_cache_destroy(asd_ascb_cache);
++ asd_ascb_cache = NULL;
++}
++
++static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
++{
++ int i;
++ struct asd_sas_phy **sas_phys =
++ kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL);
++ struct asd_sas_port **sas_ports =
++ kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL);
++
++ if (!sas_phys || !sas_ports) {
++ kfree(sas_phys);
++ kfree(sas_ports);
++ return -ENOMEM;
++ }
++
++ asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name;
++ asd_ha->sas_ha.lldd_module = THIS_MODULE;
++ asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0];
++
++ for (i = 0; i < ASD_MAX_PHYS; i++) {
++ sas_phys[i] = &asd_ha->phys[i].sas_phy;
++ sas_ports[i] = &asd_ha->ports[i];
++ }
++
++ asd_ha->sas_ha.sas_phy = sas_phys;
++ asd_ha->sas_ha.sas_port= sas_ports;
++ asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
++
++ asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
++
++ return sas_register_ha(&asd_ha->sas_ha);
++}
++
++static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
++{
++ int err;
++
++ err = sas_unregister_ha(&asd_ha->sas_ha);
++
++ sas_remove_host(asd_ha->sas_ha.core.shost);
++ scsi_remove_host(asd_ha->sas_ha.core.shost);
++ scsi_host_put(asd_ha->sas_ha.core.shost);
++
++ kfree(asd_ha->sas_ha.sas_phy);
++ kfree(asd_ha->sas_ha.sas_port);
++
++ return err;
++}
++
++static int __devinit asd_pci_probe(struct pci_dev *dev,
++ const struct pci_device_id *id)
++{
++ struct asd_pcidev_struct *asd_dev;
++ unsigned asd_id = (unsigned) id->driver_data;
++ struct asd_ha_struct *asd_ha;
++ struct Scsi_Host *shost;
++ int err;
++
++ if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) {
++ asd_printk("wrong driver_data in PCI table\n");
++ return -ENODEV;
++ }
++
++ if ((err = pci_enable_device(dev))) {
++ asd_printk("couldn't enable device %s\n", pci_name(dev));
++ return err;
++ }
++
++ pci_set_master(dev);
++
++ err = -ENOMEM;
++
++ shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *));
++ if (!shost)
++ goto Err;
++
++ asd_dev = &asd_pcidev_data[asd_id];
++
++ asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
++ if (!asd_ha) {
++ asd_printk("out of memory\n");
++ goto Err;
++ }
++ asd_ha->pcidev = dev;
++ asd_ha->sas_ha.pcidev = asd_ha->pcidev;
++ asd_ha->sas_ha.lldd_ha = asd_ha;
++
++ asd_ha->name = asd_dev->name;
++ asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
++
++ SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha;
++ asd_ha->sas_ha.core.shost = shost;
++ shost->transportt = aic94xx_transport_template;
++ shost->max_id = ~0;
++ shost->max_lun = ~0;
++ shost->max_cmd_len = 16;
++
++ err = scsi_add_host(shost, &dev->dev);
++ if (err) {
++ scsi_host_put(shost);
++ goto Err_free;
++ }
++
++
++
++ err = asd_dev->setup(asd_ha);
++ if (err)
++ goto Err_free;
++
++ err = -ENODEV;
++ if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
++ && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK))
++ ;
++ else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)
++ && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK))
++ ;
++ else {
++ asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
++ goto Err_free;
++ }
++
++ pci_set_drvdata(dev, asd_ha);
++
++ err = asd_map_ha(asd_ha);
++ if (err)
++ goto Err_free;
++
++ err = asd_create_ha_caches(asd_ha);
++ if (err)
++ goto Err_unmap;
++
++ err = asd_init_hw(asd_ha);
++ if (err)
++ goto Err_free_cache;
++
++ asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled "
++ "phys, flash %s, BIOS %s%d\n",
++ pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr),
++ asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys,
++ asd_ha->hw_prof.num_phys,
++ asd_ha->hw_prof.flash.present ? "present" : "not present",
++ asd_ha->hw_prof.bios.present ? "build " : "not present",
++ asd_ha->hw_prof.bios.bld);
++
++ shost->can_queue = asd_ha->seq.can_queue;
++
++ if (use_msi)
++ pci_enable_msi(asd_ha->pcidev);
++
++ err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
++ ASD_DRIVER_NAME, asd_ha);
++ if (err) {
++ asd_printk("couldn't get irq %d for %s\n",
++ asd_ha->pcidev->irq, pci_name(asd_ha->pcidev));
++ goto Err_irq;
++ }
++ asd_enable_ints(asd_ha);
++
++ err = asd_init_post_escbs(asd_ha);
++ if (err) {
++ asd_printk("couldn't post escbs for %s\n",
++ pci_name(asd_ha->pcidev));
++ goto Err_escbs;
++ }
++ ASD_DPRINTK("escbs posted\n");
++
++ err = asd_create_dev_attrs(asd_ha);
++ if (err)
++ goto Err_dev_attrs;
++
++ err = asd_register_sas_ha(asd_ha);
++ if (err)
++ goto Err_reg_sas;
++
++ err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
++ if (err) {
++ asd_printk("coudln't enable phys, err:%d\n", err);
++ goto Err_en_phys;
++ }
++ ASD_DPRINTK("enabled phys\n");
++ /* give the phy enabling interrupt event time to come in (1s
++ * is empirically about all it takes) */
++ ssleep(1);
++ /* Wait for discovery to finish */
++ scsi_flush_work(asd_ha->sas_ha.core.shost);
++
++ return 0;
++Err_en_phys:
++ asd_unregister_sas_ha(asd_ha);
++Err_reg_sas:
++ asd_remove_dev_attrs(asd_ha);
++Err_dev_attrs:
++Err_escbs:
++ asd_disable_ints(asd_ha);
++ free_irq(dev->irq, asd_ha);
++Err_irq:
++ if (use_msi)
++ pci_disable_msi(dev);
++ asd_chip_hardrst(asd_ha);
++Err_free_cache:
++ asd_destroy_ha_caches(asd_ha);
++Err_unmap:
++ asd_unmap_ha(asd_ha);
++Err_free:
++ kfree(asd_ha);
++ scsi_remove_host(shost);
++Err:
++ pci_disable_device(dev);
++ return err;
++}
++
++static void asd_free_queues(struct asd_ha_struct *asd_ha)
++{
++ unsigned long flags;
++ LIST_HEAD(pending);
++ struct list_head *n, *pos;
++
++ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
++ asd_ha->seq.pending = 0;
++ list_splice_init(&asd_ha->seq.pend_q, &pending);
++ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
++
++ if (!list_empty(&pending))
++ ASD_DPRINTK("Uh-oh! Pending is not empty!\n");
++
++ list_for_each_safe(pos, n, &pending) {
++ struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
++ list_del_init(pos);
++ ASD_DPRINTK("freeing from pending\n");
++ asd_ascb_free(ascb);
++ }
++}
++
++static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
++{
++ u8 phy_mask = asd_ha->hw_prof.enabled_phys;
++ u8 i;
++
++ for_each_phy(phy_mask, phy_mask, i) {
++ asd_turn_led(asd_ha, i, 0);
++ asd_control_led(asd_ha, i, 0);
++ }
++}
++
++static void __devexit asd_pci_remove(struct pci_dev *dev)
++{
++ struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
++
++ if (!asd_ha)
++ return;
++
++ asd_unregister_sas_ha(asd_ha);
++
++ asd_disable_ints(asd_ha);
++
++ asd_remove_dev_attrs(asd_ha);
++
++ /* XXX more here as needed */
++
++ free_irq(dev->irq, asd_ha);
++ if (use_msi)
++ pci_disable_msi(asd_ha->pcidev);
++ asd_turn_off_leds(asd_ha);
++ asd_chip_hardrst(asd_ha);
++ asd_free_queues(asd_ha);
++ asd_destroy_ha_caches(asd_ha);
++ asd_unmap_ha(asd_ha);
++ kfree(asd_ha);
++ pci_disable_device(dev);
++ return;
++}
++
++static ssize_t asd_version_show(struct device_driver *driver, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
++}
++static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
++
++static int asd_create_driver_attrs(struct device_driver *driver)
++{
++ return driver_create_file(driver, &driver_attr_version);
++}
++
++static void asd_remove_driver_attrs(struct device_driver *driver)
++{
++ driver_remove_file(driver, &driver_attr_version);
++}
++
++static struct sas_domain_function_template aic94xx_transport_functions = {
++ .lldd_port_formed = asd_update_port_links,
++
++ .lldd_dev_found = asd_dev_found,
++ .lldd_dev_gone = asd_dev_gone,
++
++ .lldd_execute_task = asd_execute_task,
++
++ .lldd_abort_task = asd_abort_task,
++ .lldd_abort_task_set = asd_abort_task_set,
++ .lldd_clear_aca = asd_clear_aca,
++ .lldd_clear_task_set = asd_clear_task_set,
++ .lldd_I_T_nexus_reset = NULL,
++ .lldd_lu_reset = asd_lu_reset,
++ .lldd_query_task = asd_query_task,
++
++ .lldd_clear_nexus_port = asd_clear_nexus_port,
++ .lldd_clear_nexus_ha = asd_clear_nexus_ha,
++
++ .lldd_control_phy = asd_control_phy,
++};
++
++static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
++ 0, 0, 1},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
++ 0, 0, 1},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
++ 0, 0, 1},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F),
++ 0, 0, 1},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
++ 0, 0, 2},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
++ 0, 0, 2},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
++ 0, 0, 2},
++ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
++ 0, 0, 2},
++ {}
++};
++
++MODULE_DEVICE_TABLE(pci, aic94xx_pci_table);
++
++static struct pci_driver aic94xx_pci_driver = {
++ .name = ASD_DRIVER_NAME,
++ .id_table = aic94xx_pci_table,
++ .probe = asd_pci_probe,
++ .remove = __devexit_p(asd_pci_remove),
++};
++
++static int __init aic94xx_init(void)
++{
++ int err;
++
++
++ asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION,
++ ASD_DRIVER_VERSION);
++
++ err = asd_create_global_caches();
++ if (err)
++ return err;
++
++ aic94xx_transport_template =
++ sas_domain_attach_transport(&aic94xx_transport_functions);
++ if (!aic94xx_transport_template)
++ goto out_destroy_caches;
++
++ err = pci_register_driver(&aic94xx_pci_driver);
++ if (err)
++ goto out_release_transport;
++
++ err = asd_create_driver_attrs(&aic94xx_pci_driver.driver);
++ if (err)
++ goto out_unregister_pcidrv;
++
++ return err;
++
++ out_unregister_pcidrv:
++ pci_unregister_driver(&aic94xx_pci_driver);
++ out_release_transport:
++ sas_release_transport(aic94xx_transport_template);
++ out_destroy_caches:
++ asd_destroy_global_caches();
++
++ return err;
++}
++
++static void __exit aic94xx_exit(void)
++{
++ asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
++ pci_unregister_driver(&aic94xx_pci_driver);
++ sas_release_transport(aic94xx_transport_template);
++ asd_destroy_global_caches();
++ asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
++ ASD_DRIVER_VERSION);
++}
++
++module_init(aic94xx_init);
++module_exit(aic94xx_exit);
++
++MODULE_AUTHOR("Luben Tuikov <luben_tuikov at adaptec.com>");
++MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION);
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION(ASD_DRIVER_VERSION);
+diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c
+new file mode 100644
+index 0000000..f210dac
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_reg.c
+@@ -0,0 +1,332 @@
++/*
++ * Aic94xx SAS/SATA driver register access.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/pci.h>
++#include "aic94xx_reg.h"
++#include "aic94xx.h"
++
++/* Writing to device address space.
++ * Offset comes before value to remind that the operation of
++ * this function is *offs = val.
++ */
++static inline void asd_write_byte(struct asd_ha_struct *asd_ha,
++ unsigned long offs, u8 val)
++{
++ if (unlikely(asd_ha->iospace))
++ outb(val,
++ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
++ else
++ writeb(val, asd_ha->io_handle[0].addr + offs);
++ wmb();
++}
++
++static inline void asd_write_word(struct asd_ha_struct *asd_ha,
++ unsigned long offs, u16 val)
++{
++ if (unlikely(asd_ha->iospace))
++ outw(val,
++ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
++ else
++ writew(val, asd_ha->io_handle[0].addr + offs);
++ wmb();
++}
++
++static inline void asd_write_dword(struct asd_ha_struct *asd_ha,
++ unsigned long offs, u32 val)
++{
++ if (unlikely(asd_ha->iospace))
++ outl(val,
++ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
++ else
++ writel(val, asd_ha->io_handle[0].addr + offs);
++ wmb();
++}
++
++/* Reading from device address space.
++ */
++static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha,
++ unsigned long offs)
++{
++ u8 val;
++ if (unlikely(asd_ha->iospace))
++ val = inb((unsigned long) asd_ha->io_handle[0].addr
++ + (offs & 0xFF));
++ else
++ val = readb(asd_ha->io_handle[0].addr + offs);
++ rmb();
++ return val;
++}
++
++static inline u16 asd_read_word(struct asd_ha_struct *asd_ha,
++ unsigned long offs)
++{
++ u16 val;
++ if (unlikely(asd_ha->iospace))
++ val = inw((unsigned long)asd_ha->io_handle[0].addr
++ + (offs & 0xFF));
++ else
++ val = readw(asd_ha->io_handle[0].addr + offs);
++ rmb();
++ return val;
++}
++
++static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha,
++ unsigned long offs)
++{
++ u32 val;
++ if (unlikely(asd_ha->iospace))
++ val = inl((unsigned long) asd_ha->io_handle[0].addr
++ + (offs & 0xFF));
++ else
++ val = readl(asd_ha->io_handle[0].addr + offs);
++ rmb();
++ return val;
++}
++
++static inline u32 asd_mem_offs_swa(void)
++{
++ return 0;
++}
++
++static inline u32 asd_mem_offs_swc(void)
++{
++ return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
++}
++
++static inline u32 asd_mem_offs_swb(void)
++{
++ return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
++}
++
++/* We know that the register wanted is in the range
++ * of the sliding window.
++ */
++#define ASD_READ_SW(ww, type, ord) \
++static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\
++ u32 reg) \
++{ \
++ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
++ u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
++ return asd_read_##ord (asd_ha, (unsigned long) map_offs); \
++}
++
++#define ASD_WRITE_SW(ww, type, ord) \
++static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\
++ u32 reg, type val) \
++{ \
++ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
++ u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
++ asd_write_##ord (asd_ha, (unsigned long) map_offs, val); \
++}
++
++ASD_READ_SW(swa, u8, byte);
++ASD_READ_SW(swa, u16, word);
++ASD_READ_SW(swa, u32, dword);
++
++ASD_READ_SW(swb, u8, byte);
++ASD_READ_SW(swb, u16, word);
++ASD_READ_SW(swb, u32, dword);
++
++ASD_READ_SW(swc, u8, byte);
++ASD_READ_SW(swc, u16, word);
++ASD_READ_SW(swc, u32, dword);
++
++ASD_WRITE_SW(swa, u8, byte);
++ASD_WRITE_SW(swa, u16, word);
++ASD_WRITE_SW(swa, u32, dword);
++
++ASD_WRITE_SW(swb, u8, byte);
++ASD_WRITE_SW(swb, u16, word);
++ASD_WRITE_SW(swb, u32, dword);
++
++ASD_WRITE_SW(swc, u8, byte);
++ASD_WRITE_SW(swc, u16, word);
++ASD_WRITE_SW(swc, u32, dword);
++
++/*
++ * A word about sliding windows:
++ * MBAR0 is divided into sliding windows A, C and B, in that order.
++ * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
++ * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
++ * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
++ * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
++ * See asd_init_sw() in aic94xx_hwi.c
++ *
++ * We map the most common registers we'd access of the internal 4GB
++ * host adapter memory space. If a register/internal memory location
++ * is wanted which is not mapped, we slide SWB, by paging it,
++ * see asd_move_swb() in aic94xx_reg.c.
++ */
++
++/**
++ * asd_move_swb -- move sliding window B
++ * @asd_ha: pointer to host adapter structure
++ * @reg: register desired to be within range of the new window
++ */
++static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
++{
++ u32 base = reg & ~(MBAR0_SWB_SIZE-1);
++ pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
++ asd_ha->io_handle[0].swb_base = base;
++}
++
++static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
++{
++ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
++ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
++ if (io_handle->swa_base <= reg
++ && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
++ asd_write_swa_byte (asd_ha, reg,val);
++ else if (io_handle->swb_base <= reg
++ && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
++ asd_write_swb_byte (asd_ha, reg, val);
++ else if (io_handle->swc_base <= reg
++ && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
++ asd_write_swc_byte (asd_ha, reg, val);
++ else {
++ /* Ok, we have to move SWB */
++ asd_move_swb(asd_ha, reg);
++ asd_write_swb_byte (asd_ha, reg, val);
++ }
++}
++
++#define ASD_WRITE_REG(type, ord) \
++void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
++{ \
++ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
++ unsigned long flags; \
++ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
++ spin_lock_irqsave(&asd_ha->iolock, flags); \
++ if (io_handle->swa_base <= reg \
++ && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
++ asd_write_swa_##ord (asd_ha, reg,val); \
++ else if (io_handle->swb_base <= reg \
++ && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
++ asd_write_swb_##ord (asd_ha, reg, val); \
++ else if (io_handle->swc_base <= reg \
++ && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
++ asd_write_swc_##ord (asd_ha, reg, val); \
++ else { \
++ /* Ok, we have to move SWB */ \
++ asd_move_swb(asd_ha, reg); \
++ asd_write_swb_##ord (asd_ha, reg, val); \
++ } \
++ spin_unlock_irqrestore(&asd_ha->iolock, flags); \
++}
++
++ASD_WRITE_REG(u8, byte);
++ASD_WRITE_REG(u16,word);
++ASD_WRITE_REG(u32,dword);
++
++static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
++{
++ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
++ u8 val;
++ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
++ if (io_handle->swa_base <= reg
++ && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
++ val = asd_read_swa_byte (asd_ha, reg);
++ else if (io_handle->swb_base <= reg
++ && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
++ val = asd_read_swb_byte (asd_ha, reg);
++ else if (io_handle->swc_base <= reg
++ && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
++ val = asd_read_swc_byte (asd_ha, reg);
++ else {
++ /* Ok, we have to move SWB */
++ asd_move_swb(asd_ha, reg);
++ val = asd_read_swb_byte (asd_ha, reg);
++ }
++ return val;
++}
++
++#define ASD_READ_REG(type, ord) \
++type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \
++{ \
++ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
++ type val; \
++ unsigned long flags; \
++ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
++ spin_lock_irqsave(&asd_ha->iolock, flags); \
++ if (io_handle->swa_base <= reg \
++ && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
++ val = asd_read_swa_##ord (asd_ha, reg); \
++ else if (io_handle->swb_base <= reg \
++ && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
++ val = asd_read_swb_##ord (asd_ha, reg); \
++ else if (io_handle->swc_base <= reg \
++ && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
++ val = asd_read_swc_##ord (asd_ha, reg); \
++ else { \
++ /* Ok, we have to move SWB */ \
++ asd_move_swb(asd_ha, reg); \
++ val = asd_read_swb_##ord (asd_ha, reg); \
++ } \
++ spin_unlock_irqrestore(&asd_ha->iolock, flags); \
++ return val; \
++}
++
++ASD_READ_REG(u8, byte);
++ASD_READ_REG(u16,word);
++ASD_READ_REG(u32,dword);
++
++/**
++ * asd_read_reg_string -- read a string of bytes from io space memory
++ * @asd_ha: pointer to host adapter structure
++ * @dst: pointer to a destination buffer where data will be written to
++ * @offs: start offset (register) to read from
++ * @count: number of bytes to read
++ */
++void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
++ u32 offs, int count)
++{
++ u8 *p = dst;
++ unsigned long flags;
++
++ spin_lock_irqsave(&asd_ha->iolock, flags);
++ for ( ; count > 0; count--, offs++, p++)
++ *p = __asd_read_reg_byte(asd_ha, offs);
++ spin_unlock_irqrestore(&asd_ha->iolock, flags);
++}
++
++/**
++ * asd_write_reg_string -- write a string of bytes to io space memory
++ * @asd_ha: pointer to host adapter structure
++ * @src: pointer to source buffer where data will be read from
++ * @offs: start offset (register) to write to
++ * @count: number of bytes to write
++ */
++void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
++ u32 offs, int count)
++{
++ u8 *p = src;
++ unsigned long flags;
++
++ spin_lock_irqsave(&asd_ha->iolock, flags);
++ for ( ; count > 0; count--, offs++, p++)
++ __asd_write_reg_byte(asd_ha, offs, *p);
++ spin_unlock_irqrestore(&asd_ha->iolock, flags);
++}
+diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h
+new file mode 100644
+index 0000000..2279307
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_reg.h
+@@ -0,0 +1,302 @@
++/*
++ * Aic94xx SAS/SATA driver hardware registers definitions.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef _AIC94XX_REG_H_
++#define _AIC94XX_REG_H_
++
++#include <asm/io.h>
++#include "aic94xx_hwi.h"
++
++/* Values */
++#define AIC9410_DEV_REV_B0 0x8
++
++/* MBAR0, SWA, SWB, SWC, internal memory space addresses */
++#define REG_BASE_ADDR 0xB8000000
++#define REG_BASE_ADDR_CSEQCIO 0xB8002000
++#define REG_BASE_ADDR_EXSI 0xB8042800
++
++#define MBAR0_SWA_SIZE 0x58
++extern u32 MBAR0_SWB_SIZE;
++#define MBAR0_SWC_SIZE 0x8
++
++/* MBAR1, points to On Chip Memory */
++#define OCM_BASE_ADDR 0xA0000000
++#define OCM_MAX_SIZE 0x20000
++
++/* Smallest address possible to reference */
++#define ALL_BASE_ADDR OCM_BASE_ADDR
++
++/* PCI configuration space registers */
++#define PCI_IOBAR_OFFSET 4
++
++#define PCI_CONF_MBAR1 0x6C
++#define PCI_CONF_MBAR0_SWA 0x70
++#define PCI_CONF_MBAR0_SWB 0x74
++#define PCI_CONF_MBAR0_SWC 0x78
++#define PCI_CONF_MBAR_KEY 0x7C
++#define PCI_CONF_FLSH_BAR 0xB8
++
++#include "aic94xx_reg_def.h"
++
++u8 asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg);
++u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg);
++u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg);
++
++void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val);
++void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val);
++void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val);
++
++void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
++ u32 offs, int count);
++void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
++ u32 offs, int count);
++
++#define ASD_READ_OCM(type, ord, S) \
++static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha, \
++ u32 offs) \
++{ \
++ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \
++ type val = read##S (io_handle->addr + (unsigned long) offs); \
++ rmb(); \
++ return val; \
++}
++
++ASD_READ_OCM(u8, byte, b);
++ASD_READ_OCM(u16,word, w);
++ASD_READ_OCM(u32,dword,l);
++
++#define ASD_WRITE_OCM(type, ord, S) \
++static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha, \
++ u32 offs, type val) \
++{ \
++ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \
++ write##S (val, io_handle->addr + (unsigned long) offs); \
++ return; \
++}
++
++ASD_WRITE_OCM(u8, byte, b);
++ASD_WRITE_OCM(u16,word, w);
++ASD_WRITE_OCM(u32,dword,l);
++
++#define ASD_DDBSITE_READ(type, ord) \
++static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha, \
++ u16 ddb_site_no, \
++ u16 offs) \
++{ \
++ asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \
++ asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \
++ return asd_read_reg_##ord (asd_ha, CTXACCESS); \
++}
++
++ASD_DDBSITE_READ(u32, dword);
++ASD_DDBSITE_READ(u16, word);
++
++static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha,
++ u16 ddb_site_no,
++ u16 offs)
++{
++ if (offs & 1)
++ return asd_ddbsite_read_word(asd_ha, ddb_site_no,
++ offs & ~1) >> 8;
++ else
++ return asd_ddbsite_read_word(asd_ha, ddb_site_no,
++ offs) & 0xFF;
++}
++
++
++#define ASD_DDBSITE_WRITE(type, ord) \
++static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha, \
++ u16 ddb_site_no, \
++ u16 offs, type val) \
++{ \
++ asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \
++ asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \
++ asd_write_reg_##ord (asd_ha, CTXACCESS, val); \
++}
++
++ASD_DDBSITE_WRITE(u32, dword);
++ASD_DDBSITE_WRITE(u16, word);
++
++static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha,
++ u16 ddb_site_no,
++ u16 offs, u8 val)
++{
++ u16 base = offs & ~1;
++ u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
++ if (offs & 1)
++ rval = (val << 8) | (rval & 0xFF);
++ else
++ rval = (rval & 0xFF00) | val;
++ asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval);
++}
++
++
++#define ASD_SCBSITE_READ(type, ord) \
++static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha, \
++ u16 scb_site_no, \
++ u16 offs) \
++{ \
++ asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \
++ asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \
++ return asd_read_reg_##ord (asd_ha, CTXACCESS); \
++}
++
++ASD_SCBSITE_READ(u32, dword);
++ASD_SCBSITE_READ(u16, word);
++
++static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha,
++ u16 scb_site_no,
++ u16 offs)
++{
++ if (offs & 1)
++ return asd_scbsite_read_word(asd_ha, scb_site_no,
++ offs & ~1) >> 8;
++ else
++ return asd_scbsite_read_word(asd_ha, scb_site_no,
++ offs) & 0xFF;
++}
++
++
++#define ASD_SCBSITE_WRITE(type, ord) \
++static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha, \
++ u16 scb_site_no, \
++ u16 offs, type val) \
++{ \
++ asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \
++ asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \
++ asd_write_reg_##ord (asd_ha, CTXACCESS, val); \
++}
++
++ASD_SCBSITE_WRITE(u32, dword);
++ASD_SCBSITE_WRITE(u16, word);
++
++static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha,
++ u16 scb_site_no,
++ u16 offs, u8 val)
++{
++ u16 base = offs & ~1;
++ u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base);
++ if (offs & 1)
++ rval = (val << 8) | (rval & 0xFF);
++ else
++ rval = (rval & 0xFF00) | val;
++ asd_scbsite_write_word(asd_ha, scb_site_no, base, rval);
++}
++
++/**
++ * asd_ddbsite_update_word -- atomically update a word in a ddb site
++ * @asd_ha: pointer to host adapter structure
++ * @ddb_site_no: the DDB site number
++ * @offs: the offset into the DDB
++ * @oldval: old value found in that offset
++ * @newval: the new value to replace it
++ *
++ * This function is used when the sequencers are running and we need to
++ * update a DDB site atomically without expensive pausing and upausing
++ * of the sequencers and accessing the DDB site through the CIO bus.
++ *
++ * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value
++ * is different than the current value at that offset.
++ */
++static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha,
++ u16 ddb_site_no, u16 offs,
++ u16 oldval, u16 newval)
++{
++ u8 done;
++ u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs);
++ if (oval != oldval)
++ return -EAGAIN;
++ asd_write_reg_word(asd_ha, AOLDDATA, oldval);
++ asd_write_reg_word(asd_ha, ANEWDATA, newval);
++ do {
++ done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL);
++ } while (!(done & ATOMICDONE));
++ if (done & ATOMICERR)
++ return -EFAULT; /* parity error */
++ else if (done & ATOMICWIN)
++ return 0; /* success */
++ else
++ return -EAGAIN; /* oldval different than current value */
++}
++
++static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha,
++ u16 ddb_site_no, u16 offs,
++ u8 _oldval, u8 _newval)
++{
++ u16 base = offs & ~1;
++ u16 oval;
++ u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
++ if (offs & 1) {
++ if ((nval >> 8) != _oldval)
++ return -EAGAIN;
++ nval = (_newval << 8) | (nval & 0xFF);
++ oval = (_oldval << 8) | (nval & 0xFF);
++ } else {
++ if ((nval & 0xFF) != _oldval)
++ return -EAGAIN;
++ nval = (nval & 0xFF00) | _newval;
++ oval = (nval & 0xFF00) | _oldval;
++ }
++ return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval);
++}
++
++static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg,
++ dma_addr_t dma_handle)
++{
++ asd_write_reg_dword(asd_ha, reg, ASD_BUSADDR_LO(dma_handle));
++ asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle));
++}
++
++static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha)
++{
++ /* DCHREVISION returns 0, possibly broken */
++ u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
++ return ctxmemsize ? 65536 : 32768;
++}
++
++static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha)
++{
++ u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
++ return ctxmemsize ? 8192 : 4096;
++}
++
++static inline void asd_disable_ints(struct asd_ha_struct *asd_ha)
++{
++ asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
++}
++
++static inline void asd_enable_ints(struct asd_ha_struct *asd_ha)
++{
++ /* Enable COM SAS interrupt on errors, COMSTAT */
++ asd_write_reg_dword(asd_ha, COMSTATEN,
++ EN_CSBUFPERR | EN_CSERR | EN_OVLYERR);
++ /* Enable DCH SAS CFIFTOERR */
++ asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR);
++ /* Enable Host Device interrupts */
++ asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN);
++}
++
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
+new file mode 100644
+index 0000000..b79f45f
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
+@@ -0,0 +1,2398 @@
++/*
++ * Aic94xx SAS/SATA driver hardware registers defintions.
++ *
++ * Copyright (C) 2004 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2004 David Chaw <david_chaw at adaptec.com>
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * Luben Tuikov: Some register value updates to make it work with the window
++ * agnostic register r/w functions. Some register corrections, sizes,
++ * etc.
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $
++ *
++ */
++
++#ifndef _ADP94XX_REG_DEF_H_
++#define _ADP94XX_REG_DEF_H_
++
++/*
++ * Common definitions.
++ */
++#define CSEQ_MODE_PAGE_SIZE 0x200 /* CSEQ mode page size */
++#define LmSEQ_MODE_PAGE_SIZE 0x200 /* LmSEQ mode page size */
++#define LmSEQ_HOST_REG_SIZE 0x4000 /* LmSEQ Host Register size */
++
++/********************* COM_SAS registers definition *************************/
++
++/* The base is REG_BASE_ADDR, defined in aic94xx_reg.h.
++ */
++
++/*
++ * CHIM Registers, Address Range : (0x00-0xFF)
++ */
++#define COMBIST (REG_BASE_ADDR + 0x00)
++
++/* bits 31:24 */
++#define L7BLKRST 0x80000000
++#define L6BLKRST 0x40000000
++#define L5BLKRST 0x20000000
++#define L4BLKRST 0x10000000
++#define L3BLKRST 0x08000000
++#define L2BLKRST 0x04000000
++#define L1BLKRST 0x02000000
++#define L0BLKRST 0x01000000
++#define LmBLKRST 0xFF000000
++#define LmBLKRST_COMBIST(phyid) (1 << (24 + phyid))
++
++#define OCMBLKRST 0x00400000
++#define CTXMEMBLKRST 0x00200000
++#define CSEQBLKRST 0x00100000
++#define EXSIBLKRST 0x00040000
++#define DPIBLKRST 0x00020000
++#define DFIFBLKRST 0x00010000
++#define HARDRST 0x00000200
++#define COMBLKRST 0x00000100
++#define FRCDFPERR 0x00000080
++#define FRCCIOPERR 0x00000020
++#define FRCBISTERR 0x00000010
++#define COMBISTEN 0x00000004
++#define COMBISTDONE 0x00000002 /* ro */
++#define COMBISTFAIL 0x00000001 /* ro */
++
++#define COMSTAT (REG_BASE_ADDR + 0x04)
++
++#define REQMBXREAD 0x00000040
++#define RSPMBXAVAIL 0x00000020
++#define CSBUFPERR 0x00000008
++#define OVLYERR 0x00000004
++#define CSERR 0x00000002
++#define OVLYDMADONE 0x00000001
++
++#define COMSTAT_MASK (REQMBXREAD | RSPMBXAVAIL | \
++ CSBUFPERR | OVLYERR | CSERR |\
++ OVLYDMADONE)
++
++#define COMSTATEN (REG_BASE_ADDR + 0x08)
++
++#define EN_REQMBXREAD 0x00000040
++#define EN_RSPMBXAVAIL 0x00000020
++#define EN_CSBUFPERR 0x00000008
++#define EN_OVLYERR 0x00000004
++#define EN_CSERR 0x00000002
++#define EN_OVLYDONE 0x00000001
++
++#define SCBPRO (REG_BASE_ADDR + 0x0C)
++
++#define SCBCONS_MASK 0xFFFF0000
++#define SCBPRO_MASK 0x0000FFFF
++
++#define CHIMREQMBX (REG_BASE_ADDR + 0x10)
++
++#define CHIMRSPMBX (REG_BASE_ADDR + 0x14)
++
++#define CHIMINT (REG_BASE_ADDR + 0x18)
++
++#define EXT_INT0 0x00000800
++#define EXT_INT1 0x00000400
++#define PORRSTDET 0x00000200
++#define HARDRSTDET 0x00000100
++#define DLAVAILQ 0x00000080 /* ro */
++#define HOSTERR 0x00000040
++#define INITERR 0x00000020
++#define DEVINT 0x00000010
++#define COMINT 0x00000008
++#define DEVTIMER2 0x00000004
++#define DEVTIMER1 0x00000002
++#define DLAVAIL 0x00000001
++
++#define CHIMINT_MASK (HOSTERR | INITERR | DEVINT | COMINT |\
++ DEVTIMER2 | DEVTIMER1 | DLAVAIL)
++
++#define DEVEXCEPT_MASK (HOSTERR | INITERR | DEVINT | COMINT)
++
++#define CHIMINTEN (REG_BASE_ADDR + 0x1C)
++
++#define RST_EN_EXT_INT1 0x01000000
++#define RST_EN_EXT_INT0 0x00800000
++#define RST_EN_HOSTERR 0x00400000
++#define RST_EN_INITERR 0x00200000
++#define RST_EN_DEVINT 0x00100000
++#define RST_EN_COMINT 0x00080000
++#define RST_EN_DEVTIMER2 0x00040000
++#define RST_EN_DEVTIMER1 0x00020000
++#define RST_EN_DLAVAIL 0x00010000
++#define SET_EN_EXT_INT1 0x00000100
++#define SET_EN_EXT_INT0 0x00000080
++#define SET_EN_HOSTERR 0x00000040
++#define SET_EN_INITERR 0x00000020
++#define SET_EN_DEVINT 0x00000010
++#define SET_EN_COMINT 0x00000008
++#define SET_EN_DEVTIMER2 0x00000004
++#define SET_EN_DEVTIMER1 0x00000002
++#define SET_EN_DLAVAIL 0x00000001
++
++#define RST_CHIMINTEN (RST_EN_HOSTERR | RST_EN_INITERR | \
++ RST_EN_DEVINT | RST_EN_COMINT | \
++ RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\
++ RST_EN_DLAVAIL)
++
++#define SET_CHIMINTEN (SET_EN_HOSTERR | SET_EN_INITERR |\
++ SET_EN_DEVINT | SET_EN_COMINT |\
++ SET_EN_DLAVAIL)
++
++#define OVLYDMACTL (REG_BASE_ADDR + 0x20)
++
++#define OVLYADR_MASK 0x07FF0000
++#define OVLYLSEQ_MASK 0x0000FF00
++#define OVLYCSEQ 0x00000080
++#define OVLYHALTERR 0x00000040
++#define PIOCMODE 0x00000020
++#define RESETOVLYDMA 0x00000008 /* wo */
++#define STARTOVLYDMA 0x00000004
++#define STOPOVLYDMA 0x00000002 /* wo */
++#define OVLYDMAACT 0x00000001 /* ro */
++
++#define OVLYDMACNT (REG_BASE_ADDR + 0x24)
++
++#define OVLYDOMAIN1 0x20000000 /* ro */
++#define OVLYDOMAIN0 0x10000000
++#define OVLYBUFADR_MASK 0x007F0000
++#define OVLYDMACNT_MASK 0x00003FFF
++
++#define OVLYDMAADR (REG_BASE_ADDR + 0x28)
++
++#define DMAERR (REG_BASE_ADDR + 0x30)
++
++#define OVLYERRSTAT_MASK 0x0000FF00 /* ro */
++#define CSERRSTAT_MASK 0x000000FF /* ro */
++
++#define SPIODATA (REG_BASE_ADDR + 0x34)
++
++/* 0x38 - 0x3C are reserved */
++
++#define T1CNTRLR (REG_BASE_ADDR + 0x40)
++
++#define T1DONE 0x00010000 /* ro */
++#define TIMER64 0x00000400
++#define T1ENABLE 0x00000200
++#define T1RELOAD 0x00000100
++#define T1PRESCALER_MASK 0x00000003
++
++#define T1CMPR (REG_BASE_ADDR + 0x44)
++
++#define T1CNTR (REG_BASE_ADDR + 0x48)
++
++#define T2CNTRLR (REG_BASE_ADDR + 0x4C)
++
++#define T2DONE 0x00010000 /* ro */
++#define T2ENABLE 0x00000200
++#define T2RELOAD 0x00000100
++#define T2PRESCALER_MASK 0x00000003
++
++#define T2CMPR (REG_BASE_ADDR + 0x50)
++
++#define T2CNTR (REG_BASE_ADDR + 0x54)
++
++/* 0x58h - 0xFCh are reserved */
++
++/*
++ * DCH_SAS Registers, Address Range : (0x800-0xFFF)
++ */
++#define CMDCTXBASE (REG_BASE_ADDR + 0x800)
++
++#define DEVCTXBASE (REG_BASE_ADDR + 0x808)
++
++#define CTXDOMAIN (REG_BASE_ADDR + 0x810)
++
++#define DEVCTXDOMAIN1 0x00000008 /* ro */
++#define DEVCTXDOMAIN0 0x00000004
++#define CMDCTXDOMAIN1 0x00000002 /* ro */
++#define CMDCTXDOMAIN0 0x00000001
++
++#define DCHCTL (REG_BASE_ADDR + 0x814)
++
++#define OCMBISTREPAIR 0x00080000
++#define OCMBISTEN 0x00040000
++#define OCMBISTDN 0x00020000 /* ro */
++#define OCMBISTFAIL 0x00010000 /* ro */
++#define DDBBISTEN 0x00004000
++#define DDBBISTDN 0x00002000 /* ro */
++#define DDBBISTFAIL 0x00001000 /* ro */
++#define SCBBISTEN 0x00000400
++#define SCBBISTDN 0x00000200 /* ro */
++#define SCBBISTFAIL 0x00000100 /* ro */
++
++#define MEMSEL_MASK 0x000000E0
++#define MEMSEL_CCM_LSEQ 0x00000000
++#define MEMSEL_CCM_IOP 0x00000020
++#define MEMSEL_CCM_SASCTL 0x00000040
++#define MEMSEL_DCM_LSEQ 0x00000060
++#define MEMSEL_DCM_IOP 0x00000080
++#define MEMSEL_OCM 0x000000A0
++
++#define FRCERR 0x00000010
++#define AUTORLS 0x00000001
++
++#define DCHREVISION (REG_BASE_ADDR + 0x818)
++
++#define DCHREVISION_MASK 0x000000FF
++
++#define DCHSTATUS (REG_BASE_ADDR + 0x81C)
++
++#define EN_CFIFTOERR 0x00020000
++#define CFIFTOERR 0x00000200
++#define CSEQINT 0x00000100 /* ro */
++#define LSEQ7INT 0x00000080 /* ro */
++#define LSEQ6INT 0x00000040 /* ro */
++#define LSEQ5INT 0x00000020 /* ro */
++#define LSEQ4INT 0x00000010 /* ro */
++#define LSEQ3INT 0x00000008 /* ro */
++#define LSEQ2INT 0x00000004 /* ro */
++#define LSEQ1INT 0x00000002 /* ro */
++#define LSEQ0INT 0x00000001 /* ro */
++
++#define LSEQINT_MASK (LSEQ7INT | LSEQ6INT | LSEQ5INT |\
++ LSEQ4INT | LSEQ3INT | LSEQ2INT |\
++ LSEQ1INT | LSEQ0INT)
++
++#define DCHDFIFDEBUG (REG_BASE_ADDR + 0x820)
++#define ENFAIRMST 0x00FF0000
++#define DISWRMST9 0x00000200
++#define DISWRMST8 0x00000100
++#define DISRDMST 0x000000FF
++
++#define ATOMICSTATCTL (REG_BASE_ADDR + 0x824)
++/* 8 bit wide */
++#define AUTOINC 0x80
++#define ATOMICERR 0x04
++#define ATOMICWIN 0x02
++#define ATOMICDONE 0x01
++
++
++#define ALTCIOADR (REG_BASE_ADDR + 0x828)
++/* 16 bit; bits 8:0 define CIO addr space of CSEQ */
++
++#define ASCBPTR (REG_BASE_ADDR + 0x82C)
++/* 16 bit wide */
++
++#define ADDBPTR (REG_BASE_ADDR + 0x82E)
++/* 16 bit wide */
++
++#define ANEWDATA (REG_BASE_ADDR + 0x830)
++/* 16 bit */
++
++#define AOLDDATA (REG_BASE_ADDR + 0x834)
++/* 16 bit */
++
++#define CTXACCESS (REG_BASE_ADDR + 0x838)
++/* 32 bit */
++
++/* 0x83Ch - 0xFFCh are reserved */
++
++/*
++ * ARP2 External Processor Registers, Address Range : (0x00-0x1F)
++ */
++#define ARP2CTL 0x00
++
++#define FRCSCRPERR 0x00040000
++#define FRCARP2PERR 0x00020000
++#define FRCARP2ILLOPC 0x00010000
++#define ENWAITTO 0x00008000
++#define PERRORDIS 0x00004000
++#define FAILDIS 0x00002000
++#define CIOPERRDIS 0x00001000
++#define BREAKEN3 0x00000800
++#define BREAKEN2 0x00000400
++#define BREAKEN1 0x00000200
++#define BREAKEN0 0x00000100
++#define EPAUSE 0x00000008
++#define PAUSED 0x00000004 /* ro */
++#define STEP 0x00000002
++#define ARP2RESET 0x00000001 /* wo */
++
++#define ARP2INT 0x04
++
++#define HALTCODE_MASK 0x00FF0000 /* ro */
++#define ARP2WAITTO 0x00000100
++#define ARP2HALTC 0x00000080
++#define ARP2ILLOPC 0x00000040
++#define ARP2PERR 0x00000020
++#define ARP2CIOPERR 0x00000010
++#define ARP2BREAK3 0x00000008
++#define ARP2BREAK2 0x00000004
++#define ARP2BREAK1 0x00000002
++#define ARP2BREAK0 0x00000001
++
++#define ARP2INTEN 0x08
++
++#define EN_ARP2WAITTO 0x00000100
++#define EN_ARP2HALTC 0x00000080
++#define EN_ARP2ILLOPC 0x00000040
++#define EN_ARP2PERR 0x00000020
++#define EN_ARP2CIOPERR 0x00000010
++#define EN_ARP2BREAK3 0x00000008
++#define EN_ARP2BREAK2 0x00000004
++#define EN_ARP2BREAK1 0x00000002
++#define EN_ARP2BREAK0 0x00000001
++
++#define ARP2BREAKADR01 0x0C
++
++#define BREAKADR1_MASK 0x0FFF0000
++#define BREAKADR0_MASK 0x00000FFF
++
++#define ARP2BREAKADR23 0x10
++
++#define BREAKADR3_MASK 0x0FFF0000
++#define BREAKADR2_MASK 0x00000FFF
++
++/* 0x14h - 0x1Ch are reserved */
++
++/*
++ * ARP2 Registers, Address Range : (0x00-0x1F)
++ * The definitions have the same address offset for CSEQ and LmSEQ
++ * CIO Bus Registers.
++ */
++#define MODEPTR 0x00
++
++#define DSTMODE 0xF0
++#define SRCMODE 0x0F
++
++#define ALTMODE 0x01
++
++#define ALTDMODE 0xF0
++#define ALTSMODE 0x0F
++
++#define ATOMICXCHG 0x02
++
++#define FLAG 0x04
++
++#define INTCODE_MASK 0xF0
++#define ALTMODEV2 0x04
++#define CARRY_INT 0x02
++#define CARRY 0x01
++
++#define ARP2INTCTL 0x05
++
++#define PAUSEDIS 0x80
++#define RSTINTCTL 0x40
++#define POPALTMODE 0x08
++#define ALTMODEV 0x04
++#define INTMASK 0x02
++#define IRET 0x01
++
++#define STACK 0x06
++
++#define FUNCTION1 0x07
++
++#define PRGMCNT 0x08
++
++#define ACCUM 0x0A
++
++#define SINDEX 0x0C
++
++#define DINDEX 0x0E
++
++#define ALLONES 0x10
++
++#define ALLZEROS 0x11
++
++#define SINDIR 0x12
++
++#define DINDIR 0x13
++
++#define JUMLDIR 0x14
++
++#define ARP2HALTCODE 0x15
++
++#define CURRADDR 0x16
++
++#define LASTADDR 0x18
++
++#define NXTLADDR 0x1A
++
++#define DBGPORTPTR 0x1C
++
++#define DBGPORT 0x1D
++
++/*
++ * CIO Registers.
++ * The definitions have the same address offset for CSEQ and LmSEQ
++ * CIO Bus Registers.
++ */
++#define MnSCBPTR 0x20
++
++#define MnDDBPTR 0x22
++
++#define SCRATCHPAGE 0x24
++
++#define MnSCRATCHPAGE 0x25
++
++#define SCRATCHPAGESV 0x26
++
++#define MnSCRATCHPAGESV 0x27
++
++#define MnDMAERRS 0x46
++
++#define MnSGDMAERRS 0x47
++
++#define MnSGBUF 0x53
++
++#define MnSGDMASTAT 0x5b
++
++#define MnDDMACTL 0x5c /* RAZOR.rspec.fm rev 1.5 is wrong */
++
++#define MnDDMASTAT 0x5d /* RAZOR.rspec.fm rev 1.5 is wrong */
++
++#define MnDDMAMODE 0x5e /* RAZOR.rspec.fm rev 1.5 is wrong */
++
++#define MnDMAENG 0x60
++
++#define MnPIPECTL 0x61
++
++#define MnSGBADR 0x65
++
++#define MnSCB_SITE 0x100
++
++#define MnDDB_SITE 0x180
++
++/*
++ * The common definitions below have the same address offset for both
++ * CSEQ and LmSEQ.
++ */
++#define BISTCTL0 0x4C
++
++#define BISTCTL1 0x50
++
++#define MAPPEDSCR 0x800
++
++/*
++ * CSEQ Host Register, Address Range : (0x000-0xFFC)
++ */
++#define CSEQ_HOST_REG_BASE_ADR 0xB8001000
++
++#define CARP2CTL (CSEQ_HOST_REG_BASE_ADR + ARP2CTL)
++
++#define CARP2INT (CSEQ_HOST_REG_BASE_ADR + ARP2INT)
++
++#define CARP2INTEN (CSEQ_HOST_REG_BASE_ADR + ARP2INTEN)
++
++#define CARP2BREAKADR01 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01)
++
++#define CARP2BREAKADR23 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23)
++
++#define CBISTCTL (CSEQ_HOST_REG_BASE_ADR + BISTCTL1)
++
++#define CSEQRAMBISTEN 0x00000040
++#define CSEQRAMBISTDN 0x00000020 /* ro */
++#define CSEQRAMBISTFAIL 0x00000010 /* ro */
++#define CSEQSCRBISTEN 0x00000004
++#define CSEQSCRBISTDN 0x00000002 /* ro */
++#define CSEQSCRBISTFAIL 0x00000001 /* ro */
++
++#define CMAPPEDSCR (CSEQ_HOST_REG_BASE_ADR + MAPPEDSCR)
++
++/*
++ * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC)
++ * 16 modes, each mode is 512 bytes.
++ * Unless specified, the register should valid for all modes.
++ */
++#define CSEQ_CIO_REG_BASE_ADR REG_BASE_ADDR_CSEQCIO
++
++#define CSEQm_CIO_REG(Mode, Reg) \
++ (CSEQ_CIO_REG_BASE_ADR + \
++ ((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg))
++
++#define CMODEPTR (CSEQ_CIO_REG_BASE_ADR + MODEPTR)
++
++#define CALTMODE (CSEQ_CIO_REG_BASE_ADR + ALTMODE)
++
++#define CATOMICXCHG (CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG)
++
++#define CFLAG (CSEQ_CIO_REG_BASE_ADR + FLAG)
++
++#define CARP2INTCTL (CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL)
++
++#define CSTACK (CSEQ_CIO_REG_BASE_ADR + STACK)
++
++#define CFUNCTION1 (CSEQ_CIO_REG_BASE_ADR + FUNCTION1)
++
++#define CPRGMCNT (CSEQ_CIO_REG_BASE_ADR + PRGMCNT)
++
++#define CACCUM (CSEQ_CIO_REG_BASE_ADR + ACCUM)
++
++#define CSINDEX (CSEQ_CIO_REG_BASE_ADR + SINDEX)
++
++#define CDINDEX (CSEQ_CIO_REG_BASE_ADR + DINDEX)
++
++#define CALLONES (CSEQ_CIO_REG_BASE_ADR + ALLONES)
++
++#define CALLZEROS (CSEQ_CIO_REG_BASE_ADR + ALLZEROS)
++
++#define CSINDIR (CSEQ_CIO_REG_BASE_ADR + SINDIR)
++
++#define CDINDIR (CSEQ_CIO_REG_BASE_ADR + DINDIR)
++
++#define CJUMLDIR (CSEQ_CIO_REG_BASE_ADR + JUMLDIR)
++
++#define CARP2HALTCODE (CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE)
++
++#define CCURRADDR (CSEQ_CIO_REG_BASE_ADR + CURRADDR)
++
++#define CLASTADDR (CSEQ_CIO_REG_BASE_ADR + LASTADDR)
++
++#define CNXTLADDR (CSEQ_CIO_REG_BASE_ADR + NXTLADDR)
++
++#define CDBGPORTPTR (CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR)
++
++#define CDBGPORT (CSEQ_CIO_REG_BASE_ADR + DBGPORT)
++
++#define CSCRATCHPAGE (CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE)
++
++#define CMnSCBPTR(Mode) CSEQm_CIO_REG(Mode, MnSCBPTR)
++
++#define CMnDDBPTR(Mode) CSEQm_CIO_REG(Mode, MnDDBPTR)
++
++#define CMnSCRATCHPAGE(Mode) CSEQm_CIO_REG(Mode, MnSCRATCHPAGE)
++
++#define CLINKCON (CSEQ_CIO_REG_BASE_ADR + 0x28)
++
++#define CCIOAACESS (CSEQ_CIO_REG_BASE_ADR + 0x2C)
++
++/* mode 0-7 */
++#define MnREQMBX 0x30
++#define CMnREQMBX(Mode) CSEQm_CIO_REG(Mode, 0x30)
++
++/* mode 8 */
++#define CSEQCON CSEQm_CIO_REG(8, 0x30)
++
++/* mode 0-7 */
++#define MnRSPMBX 0x34
++#define CMnRSPMBX(Mode) CSEQm_CIO_REG(Mode, 0x34)
++
++/* mode 8 */
++#define CSEQCOMCTL CSEQm_CIO_REG(8, 0x34)
++
++/* mode 8 */
++#define CSEQCOMSTAT CSEQm_CIO_REG(8, 0x35)
++
++/* mode 8 */
++#define CSEQCOMINTEN CSEQm_CIO_REG(8, 0x36)
++
++/* mode 8 */
++#define CSEQCOMDMACTL CSEQm_CIO_REG(8, 0x37)
++
++#define CSHALTERR 0x10
++#define RESETCSDMA 0x08 /* wo */
++#define STARTCSDMA 0x04
++#define STOPCSDMA 0x02 /* wo */
++#define CSDMAACT 0x01 /* ro */
++
++/* mode 0-7 */
++#define MnINT 0x38
++#define CMnINT(Mode) CSEQm_CIO_REG(Mode, 0x38)
++
++#define CMnREQMBXE 0x02
++#define CMnRSPMBXF 0x01
++#define CMnINT_MASK 0x00000003
++
++/* mode 8 */
++#define CSEQREQMBX CSEQm_CIO_REG(8, 0x38)
++
++/* mode 0-7 */
++#define MnINTEN 0x3C
++#define CMnINTEN(Mode) CSEQm_CIO_REG(Mode, 0x3C)
++
++#define EN_CMnRSPMBXF 0x01
++
++/* mode 8 */
++#define CSEQRSPMBX CSEQm_CIO_REG(8, 0x3C)
++
++/* mode 8 */
++#define CSDMAADR CSEQm_CIO_REG(8, 0x40)
++
++/* mode 8 */
++#define CSDMACNT CSEQm_CIO_REG(8, 0x48)
++
++/* mode 8 */
++#define CSEQDLCTL CSEQm_CIO_REG(8, 0x4D)
++
++#define DONELISTEND 0x10
++#define DONELISTSIZE_MASK 0x0F
++#define DONELISTSIZE_8ELEM 0x01
++#define DONELISTSIZE_16ELEM 0x02
++#define DONELISTSIZE_32ELEM 0x03
++#define DONELISTSIZE_64ELEM 0x04
++#define DONELISTSIZE_128ELEM 0x05
++#define DONELISTSIZE_256ELEM 0x06
++#define DONELISTSIZE_512ELEM 0x07
++#define DONELISTSIZE_1024ELEM 0x08
++#define DONELISTSIZE_2048ELEM 0x09
++#define DONELISTSIZE_4096ELEM 0x0A
++#define DONELISTSIZE_8192ELEM 0x0B
++#define DONELISTSIZE_16384ELEM 0x0C
++
++/* mode 8 */
++#define CSEQDLOFFS CSEQm_CIO_REG(8, 0x4E)
++
++/* mode 11 */
++#define CM11INTVEC0 CSEQm_CIO_REG(11, 0x50)
++
++/* mode 11 */
++#define CM11INTVEC1 CSEQm_CIO_REG(11, 0x52)
++
++/* mode 11 */
++#define CM11INTVEC2 CSEQm_CIO_REG(11, 0x54)
++
++#define CCONMSK (CSEQ_CIO_REG_BASE_ADR + 0x60)
++
++#define CCONEXIST (CSEQ_CIO_REG_BASE_ADR + 0x61)
++
++#define CCONMODE (CSEQ_CIO_REG_BASE_ADR + 0x62)
++
++#define CTIMERCALC (CSEQ_CIO_REG_BASE_ADR + 0x64)
++
++#define CINTDIS (CSEQ_CIO_REG_BASE_ADR + 0x68)
++
++/* mode 8, 32x32 bits, 128 bytes of mapped buffer */
++#define CSBUFFER CSEQm_CIO_REG(8, 0x80)
++
++#define CSCRATCH (CSEQ_CIO_REG_BASE_ADR + 0x1C0)
++
++/* mode 0-8 */
++#define CMnSCRATCH(Mode) CSEQm_CIO_REG(Mode, 0x1E0)
++
++/*
++ * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC)
++ */
++#define CSEQ_RAM_REG_BASE_ADR 0xB8004000
++
++/*
++ * The common definitions below have the same address offset for all the Link
++ * sequencers.
++ */
++#define MODECTL 0x40
++
++#define DBGMODE 0x44
++
++#define CONTROL 0x48
++#define LEDTIMER 0x00010000
++#define LEDTIMERS_10us 0x00000000
++#define LEDTIMERS_1ms 0x00000800
++#define LEDTIMERS_100ms 0x00001000
++#define LEDMODE_TXRX 0x00000000
++#define LEDMODE_CONNECTED 0x00000200
++#define LEDPOL 0x00000100
++
++#define LSEQRAM 0x1000
++
++/*
++ * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC)
++ */
++#define LSEQ0_HOST_REG_BASE_ADR 0xB8020000
++#define LSEQ1_HOST_REG_BASE_ADR 0xB8024000
++#define LSEQ2_HOST_REG_BASE_ADR 0xB8028000
++#define LSEQ3_HOST_REG_BASE_ADR 0xB802C000
++#define LSEQ4_HOST_REG_BASE_ADR 0xB8030000
++#define LSEQ5_HOST_REG_BASE_ADR 0xB8034000
++#define LSEQ6_HOST_REG_BASE_ADR 0xB8038000
++#define LSEQ7_HOST_REG_BASE_ADR 0xB803C000
++
++#define LmARP2CTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ ARP2CTL)
++
++#define LmARP2INT(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ ARP2INT)
++
++#define LmARP2INTEN(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ ARP2INTEN)
++
++#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ DBGMODE)
++
++#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ CONTROL)
++
++#define LmARP2BREAKADR01(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ ARP2BREAKADR01)
++
++#define LmARP2BREAKADR23(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ ARP2BREAKADR23)
++
++#define LmMODECTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ MODECTL)
++
++#define LmAUTODISCI 0x08000000
++#define LmDSBLBITLT 0x04000000
++#define LmDSBLANTT 0x02000000
++#define LmDSBLCRTT 0x01000000
++#define LmDSBLCONT 0x00000100
++#define LmPRIMODE 0x00000080
++#define LmDSBLHOLD 0x00000040
++#define LmDISACK 0x00000020
++#define LmBLIND48 0x00000010
++#define LmRCVMODE_MASK 0x0000000C
++#define LmRCVMODE_PLD 0x00000000
++#define LmRCVMODE_HPC 0x00000004
++
++#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ DBGMODE)
++
++#define LmFRCPERR 0x80000000
++#define LmMEMSEL_MASK 0x30000000
++#define LmFRCRBPERR 0x00000000
++#define LmFRCTBPERR 0x10000000
++#define LmFRCSGBPERR 0x20000000
++#define LmFRCARBPERR 0x30000000
++#define LmRCVIDW 0x00080000
++#define LmINVDWERR 0x00040000
++#define LmRCVDISP 0x00004000
++#define LmDISPERR 0x00002000
++#define LmDSBLDSCR 0x00000800
++#define LmDSBLSCR 0x00000400
++#define LmFRCNAK 0x00000200
++#define LmFRCROFS 0x00000100
++#define LmFRCCRC 0x00000080
++#define LmFRMTYPE_MASK 0x00000070
++#define LmSG_DATA 0x00000000
++#define LmSG_COMMAND 0x00000010
++#define LmSG_TASK 0x00000020
++#define LmSG_TGTXFER 0x00000030
++#define LmSG_RESPONSE 0x00000040
++#define LmSG_IDENADDR 0x00000050
++#define LmSG_OPENADDR 0x00000060
++#define LmDISCRCGEN 0x00000008
++#define LmDISCRCCHK 0x00000004
++#define LmSSXMTFRM 0x00000002
++#define LmSSRCVFRM 0x00000001
++
++#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ CONTROL)
++
++#define LmSTEPXMTFRM 0x00000002
++#define LmSTEPRCVFRM 0x00000001
++
++#define LmBISTCTL0(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
++ BISTCTL0)
++
++#define ARBBISTEN 0x40000000
++#define ARBBISTDN 0x20000000 /* ro */
++#define ARBBISTFAIL 0x10000000 /* ro */
++#define TBBISTEN 0x00000400
++#define TBBISTDN 0x00000200 /* ro */
++#define TBBISTFAIL 0x00000100 /* ro */
++#define RBBISTEN 0x00000040
++#define RBBISTDN 0x00000020 /* ro */
++#define RBBISTFAIL 0x00000010 /* ro */
++#define SGBISTEN 0x00000004
++#define SGBISTDN 0x00000002 /* ro */
++#define SGBISTFAIL 0x00000001 /* ro */
++
++#define LmBISTCTL1(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum)*LmSEQ_HOST_REG_SIZE) +\
++ BISTCTL1)
++
++#define LmRAMPAGE1 0x00000200
++#define LmRAMPAGE0 0x00000100
++#define LmIMEMBISTEN 0x00000040
++#define LmIMEMBISTDN 0x00000020 /* ro */
++#define LmIMEMBISTFAIL 0x00000010 /* ro */
++#define LmSCRBISTEN 0x00000004
++#define LmSCRBISTDN 0x00000002 /* ro */
++#define LmSCRBISTFAIL 0x00000001 /* ro */
++#define LmRAMPAGE (LmRAMPAGE1 + LmRAMPAGE0)
++#define LmRAMPAGE_LSHIFT 0x8
++
++#define LmSCRATCH(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
++ MAPPEDSCR)
++
++#define LmSEQRAM(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
++ ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
++ LSEQRAM)
++
++/*
++ * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC)
++ * 8 modes, each mode is 512 bytes.
++ * Unless specified, the register should valid for all modes.
++ */
++#define LmSEQ_CIOBUS_REG_BASE 0x2000
++
++#define LmSEQ_PHY_BASE(Mode, LinkNum) \
++ (LSEQ0_HOST_REG_BASE_ADR + \
++ (LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \
++ LmSEQ_CIOBUS_REG_BASE + \
++ ((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE))
++
++#define LmSEQ_PHY_REG(Mode, LinkNum, Reg) \
++ (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg))
++
++#define LmMODEPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, MODEPTR)
++
++#define LmALTMODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALTMODE)
++
++#define LmATOMICXCHG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG)
++
++#define LmFLAG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FLAG)
++
++#define LmARP2INTCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL)
++
++#define LmSTACK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, STACK)
++
++#define LmFUNCTION1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FUNCTION1)
++
++#define LmPRGMCNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, PRGMCNT)
++
++#define LmACCUM(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ACCUM)
++
++#define LmSINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDEX)
++
++#define LmDINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDEX)
++
++#define LmALLONES(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLONES)
++
++#define LmALLZEROS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLZEROS)
++
++#define LmSINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDIR)
++
++#define LmDINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDIR)
++
++#define LmJUMLDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, JUMLDIR)
++
++#define LmARP2HALTCODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE)
++
++#define LmCURRADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, CURRADDR)
++
++#define LmLASTADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, LASTADDR)
++
++#define LmNXTLADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, NXTLADDR)
++
++#define LmDBGPORTPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR)
++
++#define LmDBGPORT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORT)
++
++#define LmSCRATCHPAGE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE)
++
++#define LmMnSCRATCHPAGE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, \
++ MnSCRATCHPAGE)
++
++#define LmTIMERCALC(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x28)
++
++#define LmREQMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x30)
++
++#define LmRSPMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x34)
++
++#define LmMnINT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x38)
++
++#define CTXMEMSIZE 0x80000000 /* ro */
++#define LmACKREQ 0x08000000
++#define LmNAKREQ 0x04000000
++#define LmMnXMTERR 0x02000000
++#define LmM5OOBSVC 0x01000000
++#define LmHWTINT 0x00800000
++#define LmMnCTXDONE 0x00100000
++#define LmM2REQMBXF 0x00080000
++#define LmM2RSPMBXE 0x00040000
++#define LmMnDMAERR 0x00020000
++#define LmRCVPRIM 0x00010000
++#define LmRCVERR 0x00008000
++#define LmADDRRCV 0x00004000
++#define LmMnHDRMISS 0x00002000
++#define LmMnWAITSCB 0x00001000
++#define LmMnRLSSCB 0x00000800
++#define LmMnSAVECTX 0x00000400
++#define LmMnFETCHSG 0x00000200
++#define LmMnLOADCTX 0x00000100
++#define LmMnCFGICL 0x00000080
++#define LmMnCFGSATA 0x00000040
++#define LmMnCFGEXPSATA 0x00000020
++#define LmMnCFGCMPLT 0x00000010
++#define LmMnCFGRBUF 0x00000008
++#define LmMnSAVETTR 0x00000004
++#define LmMnCFGRDAT 0x00000002
++#define LmMnCFGHDR 0x00000001
++
++#define LmMnINTEN(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x3C)
++
++#define EN_LmACKREQ 0x08000000
++#define EN_LmNAKREQ 0x04000000
++#define EN_LmMnXMTERR 0x02000000
++#define EN_LmM5OOBSVC 0x01000000
++#define EN_LmHWTINT 0x00800000
++#define EN_LmMnCTXDONE 0x00100000
++#define EN_LmM2REQMBXF 0x00080000
++#define EN_LmM2RSPMBXE 0x00040000
++#define EN_LmMnDMAERR 0x00020000
++#define EN_LmRCVPRIM 0x00010000
++#define EN_LmRCVERR 0x00008000
++#define EN_LmADDRRCV 0x00004000
++#define EN_LmMnHDRMISS 0x00002000
++#define EN_LmMnWAITSCB 0x00001000
++#define EN_LmMnRLSSCB 0x00000800
++#define EN_LmMnSAVECTX 0x00000400
++#define EN_LmMnFETCHSG 0x00000200
++#define EN_LmMnLOADCTX 0x00000100
++#define EN_LmMnCFGICL 0x00000080
++#define EN_LmMnCFGSATA 0x00000040
++#define EN_LmMnCFGEXPSATA 0x00000020
++#define EN_LmMnCFGCMPLT 0x00000010
++#define EN_LmMnCFGRBUF 0x00000008
++#define EN_LmMnSAVETTR 0x00000004
++#define EN_LmMnCFGRDAT 0x00000002
++#define EN_LmMnCFGHDR 0x00000001
++
++#define LmM0INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \
++ EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \
++ EN_LmMnCFGHDR | EN_LmRCVERR | \
++ EN_LmADDRRCV | EN_LmMnHDRMISS | \
++ EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
++ EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
++ EN_LmHWTINT | EN_LmMnCTXDONE | \
++ EN_LmRCVPRIM | EN_LmMnCFGSATA | \
++ EN_LmMnCFGEXPSATA | EN_LmMnDMAERR)
++
++#define LmM1INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmADDRRCV | \
++ EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
++ EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
++ EN_LmMnXMTERR | EN_LmHWTINT | \
++ EN_LmMnCTXDONE | EN_LmRCVPRIM | \
++ EN_LmRCVERR | EN_LmMnDMAERR)
++
++#define LmM2INTEN_MASK (EN_LmADDRRCV | EN_LmHWTINT | \
++ EN_LmM2REQMBXF | EN_LmRCVPRIM | \
++ EN_LmRCVERR)
++
++#define LmM5INTEN_MASK (EN_LmADDRRCV | EN_LmM5OOBSVC | \
++ EN_LmHWTINT | EN_LmRCVPRIM | \
++ EN_LmRCVERR)
++
++#define LmXMTPRIMD(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x40)
++
++#define LmXMTPRIMCS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x44)
++
++#define LmCONSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x45)
++
++#define LmMnDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x46)
++
++#define LmMnSGDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x47)
++
++#define LmM0EXPHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x48)
++
++#define LmM1SASALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x48)
++#define SAS_ALIGN_DEFAULT 0xFF
++
++#define LmM0MSKHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x49)
++
++#define LmM1STPALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x49)
++#define STP_ALIGN_DEFAULT 0x1F
++
++#define LmM0RCVHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4A)
++
++#define LmM1XMTHDRP(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4A)
++
++#define LmM0ICLADR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4B)
++
++#define LmM1ALIGNMODE(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4B)
++
++#define LmDISALIGN 0x20
++#define LmROTSTPALIGN 0x10
++#define LmSTPALIGN 0x08
++#define LmROTNOTIFY 0x04
++#define LmDUALALIGN 0x02
++#define LmROTALIGN 0x01
++
++#define LmM0EXPRCVNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4C)
++
++#define LmM1XMTCNT(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4C)
++
++#define LmMnBUFSTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x4E)
++
++#define LmMnBUFPERR 0x01
++
++/* mode 0-1 */
++#define LmMnXFRLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x59)
++
++#define LmMnXFRLVL_128 0x05
++#define LmMnXFRLVL_256 0x04
++#define LmMnXFRLVL_512 0x03
++#define LmMnXFRLVL_1024 0x02
++#define LmMnXFRLVL_1536 0x01
++#define LmMnXFRLVL_2048 0x00
++
++ /* mode 0-1 */
++#define LmMnSGDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5A)
++
++#define LmMnRESETSG 0x04
++#define LmMnSTOPSG 0x02
++#define LmMnSTARTSG 0x01
++
++/* mode 0-1 */
++#define LmMnSGDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5B)
++
++/* mode 0-1 */
++#define LmMnDDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5C)
++
++#define LmMnFLUSH 0x40 /* wo */
++#define LmMnRLSRTRY 0x20 /* wo */
++#define LmMnDISCARD 0x10 /* wo */
++#define LmMnRESETDAT 0x08 /* wo */
++#define LmMnSUSDAT 0x04 /* wo */
++#define LmMnSTOPDAT 0x02 /* wo */
++#define LmMnSTARTDAT 0x01 /* wo */
++
++/* mode 0-1 */
++#define LmMnDDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5D)
++
++#define LmMnDPEMPTY 0x80
++#define LmMnFLUSHING 0x40
++#define LmMnDDMAREQ 0x20
++#define LmMnHDMAREQ 0x10
++#define LmMnDATFREE 0x08
++#define LmMnDATSUS 0x04
++#define LmMnDATACT 0x02
++#define LmMnDATEN 0x01
++
++/* mode 0-1 */
++#define LmMnDDMAMODE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5E)
++
++#define LmMnDMATYPE_NORMAL 0x0000
++#define LmMnDMATYPE_HOST_ONLY_TX 0x0001
++#define LmMnDMATYPE_DEVICE_ONLY_TX 0x0002
++#define LmMnDMATYPE_INVALID 0x0003
++#define LmMnDMATYPE_MASK 0x0003
++
++#define LmMnDMAWRAP 0x0004
++#define LmMnBITBUCKET 0x0008
++#define LmMnDISHDR 0x0010
++#define LmMnSTPCRC 0x0020
++#define LmXTEST 0x0040
++#define LmMnDISCRC 0x0080
++#define LmMnENINTLK 0x0100
++#define LmMnADDRFRM 0x0400
++#define LmMnENXMTCRC 0x0800
++
++/* mode 0-1 */
++#define LmMnXFRCNT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x70)
++
++/* mode 0-1 */
++#define LmMnDPSEL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7B)
++#define LmMnDPSEL_MASK 0x07
++#define LmMnEOLPRE 0x40
++#define LmMnEOSPRE 0x80
++
++/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
++/* Receive Mode n = 0 */
++#define LmMnHRADDR 0x00
++#define LmMnHBYTECNT 0x01
++#define LmMnHREWIND 0x02
++#define LmMnDWADDR 0x03
++#define LmMnDSPACECNT 0x04
++#define LmMnDFRMSIZE 0x05
++
++/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
++/* Transmit Mode n = 1 */
++#define LmMnHWADDR 0x00
++#define LmMnHSPACECNT 0x01
++/* #define LmMnHREWIND 0x02 */
++#define LmMnDRADDR 0x03
++#define LmMnDBYTECNT 0x04
++/* #define LmMnDFRMSIZE 0x05 */
++
++/* mode 0-1 */
++#define LmMnDPACC(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x78)
++#define LmMnDPACC_MASK 0x00FFFFFF
++
++/* mode 0-1 */
++#define LmMnHOLDLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7D)
++
++#define LmPRMSTAT0(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x80)
++#define LmPRMSTAT0BYTE0 0x80
++#define LmPRMSTAT0BYTE1 0x81
++#define LmPRMSTAT0BYTE2 0x82
++#define LmPRMSTAT0BYTE3 0x83
++
++#define LmFRAMERCVD 0x80000000
++#define LmXFRRDYRCVD 0x40000000
++#define LmUNKNOWNP 0x20000000
++#define LmBREAK 0x10000000
++#define LmDONE 0x08000000
++#define LmOPENACPT 0x04000000
++#define LmOPENRJCT 0x02000000
++#define LmOPENRTRY 0x01000000
++#define LmCLOSERV1 0x00800000
++#define LmCLOSERV0 0x00400000
++#define LmCLOSENORM 0x00200000
++#define LmCLOSECLAF 0x00100000
++#define LmNOTIFYRV2 0x00080000
++#define LmNOTIFYRV1 0x00040000
++#define LmNOTIFYRV0 0x00020000
++#define LmNOTIFYSPIN 0x00010000
++#define LmBROADRV4 0x00008000
++#define LmBROADRV3 0x00004000
++#define LmBROADRV2 0x00002000
++#define LmBROADRV1 0x00001000
++#define LmBROADSES 0x00000800
++#define LmBROADRVCH1 0x00000400
++#define LmBROADRVCH0 0x00000200
++#define LmBROADCH 0x00000100
++#define LmAIPRVWP 0x00000080
++#define LmAIPWP 0x00000040
++#define LmAIPWD 0x00000020
++#define LmAIPWC 0x00000010
++#define LmAIPRV2 0x00000008
++#define LmAIPRV1 0x00000004
++#define LmAIPRV0 0x00000002
++#define LmAIPNRML 0x00000001
++
++#define LmBROADCAST_MASK (LmBROADCH | LmBROADRVCH0 | \
++ LmBROADRVCH1)
++
++#define LmPRMSTAT1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x84)
++#define LmPRMSTAT1BYTE0 0x84
++#define LmPRMSTAT1BYTE1 0x85
++#define LmPRMSTAT1BYTE2 0x86
++#define LmPRMSTAT1BYTE3 0x87
++
++#define LmFRMRCVDSTAT 0x80000000
++#define LmBREAK_DET 0x04000000
++#define LmCLOSE_DET 0x02000000
++#define LmDONE_DET 0x01000000
++#define LmXRDY 0x00040000
++#define LmSYNCSRST 0x00020000
++#define LmSYNC 0x00010000
++#define LmXHOLD 0x00008000
++#define LmRRDY 0x00004000
++#define LmHOLD 0x00002000
++#define LmROK 0x00001000
++#define LmRIP 0x00000800
++#define LmCRBLK 0x00000400
++#define LmACK 0x00000200
++#define LmNAK 0x00000100
++#define LmHARDRST 0x00000080
++#define LmERROR 0x00000040
++#define LmRERR 0x00000020
++#define LmPMREQP 0x00000010
++#define LmPMREQS 0x00000008
++#define LmPMACK 0x00000004
++#define LmPMNAK 0x00000002
++#define LmDMAT 0x00000001
++
++/* mode 1 */
++#define LmMnSATAFS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7E)
++#define LmMnXMTSIZE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x93)
++
++/* mode 0 */
++#define LmMnFRMERR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xB0)
++
++#define LmACRCERR 0x00000800
++#define LmPHYOVRN 0x00000400
++#define LmOBOVRN 0x00000200
++#define LmMnZERODATA 0x00000100
++#define LmSATAINTLK 0x00000080
++#define LmMnCRCERR 0x00000020
++#define LmRRDYOVRN 0x00000010
++#define LmMISSSOAF 0x00000008
++#define LmMISSSOF 0x00000004
++#define LmMISSEOAF 0x00000002
++#define LmMISSEOF 0x00000001
++
++#define LmFRMERREN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xB4)
++
++#define EN_LmACRCERR 0x00000800
++#define EN_LmPHYOVRN 0x00000400
++#define EN_LmOBOVRN 0x00000200
++#define EN_LmMnZERODATA 0x00000100
++#define EN_LmSATAINTLK 0x00000080
++#define EN_LmFRMBAD 0x00000040
++#define EN_LmMnCRCERR 0x00000020
++#define EN_LmRRDYOVRN 0x00000010
++#define EN_LmMISSSOAF 0x00000008
++#define EN_LmMISSSOF 0x00000004
++#define EN_LmMISSEOAF 0x00000002
++#define EN_LmMISSEOF 0x00000001
++
++#define LmFRMERREN_MASK (EN_LmSATAINTLK | EN_LmMnCRCERR | \
++ EN_LmRRDYOVRN | EN_LmMISSSOF | \
++ EN_LmMISSEOAF | EN_LmMISSEOF | \
++ EN_LmACRCERR | LmPHYOVRN | \
++ EN_LmOBOVRN | EN_LmMnZERODATA)
++
++#define LmHWTSTATEN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC5)
++
++#define EN_LmDONETO 0x80
++#define EN_LmINVDISP 0x40
++#define EN_LmINVDW 0x20
++#define EN_LmDWSEVENT 0x08
++#define EN_LmCRTTTO 0x04
++#define EN_LmANTTTO 0x02
++#define EN_LmBITLTTO 0x01
++
++#define LmHWTSTATEN_MASK (EN_LmINVDISP | EN_LmINVDW | \
++ EN_LmDWSEVENT | EN_LmCRTTTO | \
++ EN_LmANTTTO | EN_LmDONETO | \
++ EN_LmBITLTTO)
++
++#define LmHWTSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC7)
++
++#define LmDONETO 0x80
++#define LmINVDISP 0x40
++#define LmINVDW 0x20
++#define LmDWSEVENT 0x08
++#define LmCRTTTO 0x04
++#define LmANTTTO 0x02
++#define LmBITLTTO 0x01
++
++#define LmMnDATABUFADR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xC8)
++#define LmDATABUFADR_MASK 0x0FFF
++
++#define LmMnDATABUF(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xCA)
++
++#define LmPRIMSTAT0EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE0)
++
++#define EN_LmUNKNOWNP 0x20000000
++#define EN_LmBREAK 0x10000000
++#define EN_LmDONE 0x08000000
++#define EN_LmOPENACPT 0x04000000
++#define EN_LmOPENRJCT 0x02000000
++#define EN_LmOPENRTRY 0x01000000
++#define EN_LmCLOSERV1 0x00800000
++#define EN_LmCLOSERV0 0x00400000
++#define EN_LmCLOSENORM 0x00200000
++#define EN_LmCLOSECLAF 0x00100000
++#define EN_LmNOTIFYRV2 0x00080000
++#define EN_LmNOTIFYRV1 0x00040000
++#define EN_LmNOTIFYRV0 0x00020000
++#define EN_LmNOTIFYSPIN 0x00010000
++#define EN_LmBROADRV4 0x00008000
++#define EN_LmBROADRV3 0x00004000
++#define EN_LmBROADRV2 0x00002000
++#define EN_LmBROADRV1 0x00001000
++#define EN_LmBROADRV0 0x00000800
++#define EN_LmBROADRVCH1 0x00000400
++#define EN_LmBROADRVCH0 0x00000200
++#define EN_LmBROADCH 0x00000100
++#define EN_LmAIPRVWP 0x00000080
++#define EN_LmAIPWP 0x00000040
++#define EN_LmAIPWD 0x00000020
++#define EN_LmAIPWC 0x00000010
++#define EN_LmAIPRV2 0x00000008
++#define EN_LmAIPRV1 0x00000004
++#define EN_LmAIPRV0 0x00000002
++#define EN_LmAIPNRML 0x00000001
++
++#define LmPRIMSTAT0EN_MASK (EN_LmBREAK | \
++ EN_LmDONE | EN_LmOPENACPT | \
++ EN_LmOPENRJCT | EN_LmOPENRTRY | \
++ EN_LmCLOSERV1 | EN_LmCLOSERV0 | \
++ EN_LmCLOSENORM | EN_LmCLOSECLAF | \
++ EN_LmBROADRV4 | EN_LmBROADRV3 | \
++ EN_LmBROADRV2 | EN_LmBROADRV1 | \
++ EN_LmBROADRV0 | EN_LmBROADRVCH1 | \
++ EN_LmBROADRVCH0 | EN_LmBROADCH | \
++ EN_LmAIPRVWP | EN_LmAIPWP | \
++ EN_LmAIPWD | EN_LmAIPWC | \
++ EN_LmAIPRV2 | EN_LmAIPRV1 | \
++ EN_LmAIPRV0 | EN_LmAIPNRML)
++
++#define LmPRIMSTAT1EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE4)
++
++#define EN_LmXRDY 0x00040000
++#define EN_LmSYNCSRST 0x00020000
++#define EN_LmSYNC 0x00010000
++#define EN_LmXHOLD 0x00008000
++#define EN_LmRRDY 0x00004000
++#define EN_LmHOLD 0x00002000
++#define EN_LmROK 0x00001000
++#define EN_LmRIP 0x00000800
++#define EN_LmCRBLK 0x00000400
++#define EN_LmACK 0x00000200
++#define EN_LmNAK 0x00000100
++#define EN_LmHARDRST 0x00000080
++#define EN_LmERROR 0x00000040
++#define EN_LmRERR 0x00000020
++#define EN_LmPMREQP 0x00000010
++#define EN_LmPMREQS 0x00000008
++#define EN_LmPMACK 0x00000004
++#define EN_LmPMNAK 0x00000002
++#define EN_LmDMAT 0x00000001
++
++#define LmPRIMSTAT1EN_MASK (EN_LmHARDRST | \
++ EN_LmSYNCSRST | \
++ EN_LmPMREQP | EN_LmPMREQS | \
++ EN_LmPMACK | EN_LmPMNAK)
++
++#define LmSMSTATE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE8)
++
++#define LmSMSTATEBRK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xEC)
++
++#define LmSMDBGCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xF0)
++
++
++/*
++ * LmSEQ CIO Bus Mode 3 Register.
++ * Mode 3: Configuration and Setup, IOP Context SCB.
++ */
++#define LmM3SATATIMER(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x48)
++
++#define LmM3INTVEC0(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x90)
++
++#define LmM3INTVEC1(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x92)
++
++#define LmM3INTVEC2(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x94)
++
++#define LmM3INTVEC3(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x96)
++
++#define LmM3INTVEC4(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x98)
++
++#define LmM3INTVEC5(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9A)
++
++#define LmM3INTVEC6(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9C)
++
++#define LmM3INTVEC7(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9E)
++
++#define LmM3INTVEC8(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA4)
++
++#define LmM3INTVEC9(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA6)
++
++#define LmM3INTVEC10(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB0)
++
++#define LmM3FRMGAP(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB4)
++
++#define LmBITL_TIMER(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA2)
++
++#define LmWWN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA8)
++
++
++/*
++ * LmSEQ CIO Bus Mode 5 Registers.
++ * Mode 5: Phy/OOB Control and Status.
++ */
++#define LmSEQ_OOB_REG(phy_id, reg) LmSEQ_PHY_REG(5, (phy_id), (reg))
++
++#define OOB_BFLTR 0x100
++
++#define BFLTR_THR_MASK 0xF0
++#define BFLTR_TC_MASK 0x0F
++
++#define OOB_INIT_MIN 0x102
++
++#define OOB_INIT_MAX 0x104
++
++#define OOB_INIT_NEG 0x106
++
++#define OOB_SAS_MIN 0x108
++
++#define OOB_SAS_MAX 0x10A
++
++#define OOB_SAS_NEG 0x10C
++
++#define OOB_WAKE_MIN 0x10E
++
++#define OOB_WAKE_MAX 0x110
++
++#define OOB_WAKE_NEG 0x112
++
++#define OOB_IDLE_MAX 0x114
++
++#define OOB_BURST_MAX 0x116
++
++#define OOB_DATA_KBITS 0x126
++
++#define OOB_ALIGN_0_DATA 0x12C
++
++#define OOB_ALIGN_1_DATA 0x130
++
++#define D10_2_DATA_k 0x00
++#define SYNC_DATA_k 0x02
++#define ALIGN_1_DATA_k 0x04
++#define ALIGN_0_DATA_k 0x08
++#define BURST_DATA_k 0x10
++
++#define OOB_PHY_RESET_COUNT 0x13C
++
++#define OOB_SIG_GEN 0x140
++
++#define START_OOB 0x80
++#define START_DWS 0x40
++#define ALIGN_CNT3 0x30
++#define ALIGN_CNT2 0x20
++#define ALIGN_CNT1 0x10
++#define ALIGN_CNT4 0x00
++#define STOP_DWS 0x08
++#define SEND_COMSAS 0x04
++#define SEND_COMINIT 0x02
++#define SEND_COMWAKE 0x01
++
++#define OOB_XMIT 0x141
++
++#define TX_ENABLE 0x80
++#define XMIT_OOB_BURST 0x10
++#define XMIT_D10_2 0x08
++#define XMIT_SYNC 0x04
++#define XMIT_ALIGN_1 0x02
++#define XMIT_ALIGN_0 0x01
++
++#define FUNCTION_MASK 0x142
++
++#define SAS_MODE_DIS 0x80
++#define SATA_MODE_DIS 0x40
++#define SPINUP_HOLD_DIS 0x20
++#define HOT_PLUG_DIS 0x10
++#define SATA_PS_DIS 0x08
++#define FUNCTION_MASK_DEFAULT (SPINUP_HOLD_DIS | SATA_PS_DIS)
++
++#define OOB_MODE 0x143
++
++#define SAS_MODE 0x80
++#define SATA_MODE 0x40
++#define SLOW_CLK 0x20
++#define FORCE_XMIT_15 0x08
++#define PHY_SPEED_60 0x04
++#define PHY_SPEED_30 0x02
++#define PHY_SPEED_15 0x01
++
++#define CURRENT_STATUS 0x144
++
++#define CURRENT_OOB_DONE 0x80
++#define CURRENT_LOSS_OF_SIGNAL 0x40
++#define CURRENT_SPINUP_HOLD 0x20
++#define CURRENT_HOT_PLUG_CNCT 0x10
++#define CURRENT_GTO_TIMEOUT 0x08
++#define CURRENT_OOB_TIMEOUT 0x04
++#define CURRENT_DEVICE_PRESENT 0x02
++#define CURRENT_OOB_ERROR 0x01
++
++#define CURRENT_OOB1_ERROR (CURRENT_HOT_PLUG_CNCT | \
++ CURRENT_GTO_TIMEOUT)
++
++#define CURRENT_OOB2_ERROR (CURRENT_HOT_PLUG_CNCT | \
++ CURRENT_OOB_ERROR)
++
++#define DEVICE_ADDED_W_CNT (CURRENT_OOB_DONE | \
++ CURRENT_HOT_PLUG_CNCT | \
++ CURRENT_DEVICE_PRESENT)
++
++#define DEVICE_ADDED_WO_CNT (CURRENT_OOB_DONE | \
++ CURRENT_DEVICE_PRESENT)
++
++#define DEVICE_REMOVED CURRENT_LOSS_OF_SIGNAL
++
++#define CURRENT_PHY_MASK (CURRENT_OOB_DONE | \
++ CURRENT_LOSS_OF_SIGNAL | \
++ CURRENT_SPINUP_HOLD | \
++ CURRENT_HOT_PLUG_CNCT | \
++ CURRENT_GTO_TIMEOUT | \
++ CURRENT_DEVICE_PRESENT | \
++ CURRENT_OOB_ERROR )
++
++#define CURRENT_ERR_MASK (CURRENT_LOSS_OF_SIGNAL | \
++ CURRENT_GTO_TIMEOUT | \
++ CURRENT_OOB_TIMEOUT | \
++ CURRENT_OOB_ERROR )
++
++#define SPEED_MASK 0x145
++
++#define SATA_SPEED_30_DIS 0x10
++#define SATA_SPEED_15_DIS 0x08
++#define SAS_SPEED_60_DIS 0x04
++#define SAS_SPEED_30_DIS 0x02
++#define SAS_SPEED_15_DIS 0x01
++#define SAS_SPEED_MASK_DEFAULT 0x00
++
++#define OOB_TIMER_ENABLE 0x14D
++
++#define HOT_PLUG_EN 0x80
++#define RCD_EN 0x40
++#define COMTIMER_EN 0x20
++#define SNTT_EN 0x10
++#define SNLT_EN 0x04
++#define SNWT_EN 0x02
++#define ALIGN_EN 0x01
++
++#define OOB_STATUS 0x14E
++
++#define OOB_DONE 0x80
++#define LOSS_OF_SIGNAL 0x40 /* ro */
++#define SPINUP_HOLD 0x20
++#define HOT_PLUG_CNCT 0x10 /* ro */
++#define GTO_TIMEOUT 0x08 /* ro */
++#define OOB_TIMEOUT 0x04 /* ro */
++#define DEVICE_PRESENT 0x02 /* ro */
++#define OOB_ERROR 0x01 /* ro */
++
++#define OOB_STATUS_ERROR_MASK (LOSS_OF_SIGNAL | GTO_TIMEOUT | \
++ OOB_TIMEOUT | OOB_ERROR)
++
++#define OOB_STATUS_CLEAR 0x14F
++
++#define OOB_DONE_CLR 0x80
++#define LOSS_OF_SIGNAL_CLR 0x40
++#define SPINUP_HOLD_CLR 0x20
++#define HOT_PLUG_CNCT_CLR 0x10
++#define GTO_TIMEOUT_CLR 0x08
++#define OOB_TIMEOUT_CLR 0x04
++#define OOB_ERROR_CLR 0x01
++
++#define HOT_PLUG_DELAY 0x150
++/* In 5 ms units. 20 = 100 ms. */
++#define HOTPLUG_DELAY_TIMEOUT 20
++
++
++#define INT_ENABLE_2 0x15A
++
++#define OOB_DONE_EN 0x80
++#define LOSS_OF_SIGNAL_EN 0x40
++#define SPINUP_HOLD_EN 0x20
++#define HOT_PLUG_CNCT_EN 0x10
++#define GTO_TIMEOUT_EN 0x08
++#define OOB_TIMEOUT_EN 0x04
++#define DEVICE_PRESENT_EN 0x02
++#define OOB_ERROR_EN 0x01
++
++#define PHY_CONTROL_0 0x160
++
++#define PHY_LOWPWREN_TX 0x80
++#define PHY_LOWPWREN_RX 0x40
++#define SPARE_REG_160_B5 0x20
++#define OFFSET_CANCEL_RX 0x10
++
++/* bits 3:2 */
++#define PHY_RXCOMCENTER_60V 0x00
++#define PHY_RXCOMCENTER_70V 0x04
++#define PHY_RXCOMCENTER_80V 0x08
++#define PHY_RXCOMCENTER_90V 0x0C
++#define PHY_RXCOMCENTER_MASK 0x0C
++
++#define PHY_RESET 0x02
++#define SAS_DEFAULT_SEL 0x01
++
++#define PHY_CONTROL_1 0x161
++
++/* bits 2:0 */
++#define SATA_PHY_DETLEVEL_50mv 0x00
++#define SATA_PHY_DETLEVEL_75mv 0x01
++#define SATA_PHY_DETLEVEL_100mv 0x02
++#define SATA_PHY_DETLEVEL_125mv 0x03
++#define SATA_PHY_DETLEVEL_150mv 0x04
++#define SATA_PHY_DETLEVEL_175mv 0x05
++#define SATA_PHY_DETLEVEL_200mv 0x06
++#define SATA_PHY_DETLEVEL_225mv 0x07
++#define SATA_PHY_DETLEVEL_MASK 0x07
++
++/* bits 5:3 */
++#define SAS_PHY_DETLEVEL_50mv 0x00
++#define SAS_PHY_DETLEVEL_75mv 0x08
++#define SAS_PHY_DETLEVEL_100mv 0x10
++#define SAS_PHY_DETLEVEL_125mv 0x11
++#define SAS_PHY_DETLEVEL_150mv 0x20
++#define SAS_PHY_DETLEVEL_175mv 0x21
++#define SAS_PHY_DETLEVEL_200mv 0x30
++#define SAS_PHY_DETLEVEL_225mv 0x31
++#define SAS_PHY_DETLEVEL_MASK 0x38
++
++#define PHY_CONTROL_2 0x162
++
++/* bits 7:5 */
++#define SATA_PHY_DRV_400mv 0x00
++#define SATA_PHY_DRV_450mv 0x20
++#define SATA_PHY_DRV_500mv 0x40
++#define SATA_PHY_DRV_550mv 0x60
++#define SATA_PHY_DRV_600mv 0x80
++#define SATA_PHY_DRV_650mv 0xA0
++#define SATA_PHY_DRV_725mv 0xC0
++#define SATA_PHY_DRV_800mv 0xE0
++#define SATA_PHY_DRV_MASK 0xE0
++
++/* bits 4:3 */
++#define SATA_PREEMP_0 0x00
++#define SATA_PREEMP_1 0x08
++#define SATA_PREEMP_2 0x10
++#define SATA_PREEMP_3 0x18
++#define SATA_PREEMP_MASK 0x18
++
++#define SATA_CMSH1P5 0x04
++
++/* bits 1:0 */
++#define SATA_SLEW_0 0x00
++#define SATA_SLEW_1 0x01
++#define SATA_SLEW_2 0x02
++#define SATA_SLEW_3 0x03
++#define SATA_SLEW_MASK 0x03
++
++#define PHY_CONTROL_3 0x163
++
++/* bits 7:5 */
++#define SAS_PHY_DRV_400mv 0x00
++#define SAS_PHY_DRV_450mv 0x20
++#define SAS_PHY_DRV_500mv 0x40
++#define SAS_PHY_DRV_550mv 0x60
++#define SAS_PHY_DRV_600mv 0x80
++#define SAS_PHY_DRV_650mv 0xA0
++#define SAS_PHY_DRV_725mv 0xC0
++#define SAS_PHY_DRV_800mv 0xE0
++#define SAS_PHY_DRV_MASK 0xE0
++
++/* bits 4:3 */
++#define SAS_PREEMP_0 0x00
++#define SAS_PREEMP_1 0x08
++#define SAS_PREEMP_2 0x10
++#define SAS_PREEMP_3 0x18
++#define SAS_PREEMP_MASK 0x18
++
++#define SAS_CMSH1P5 0x04
++
++/* bits 1:0 */
++#define SAS_SLEW_0 0x00
++#define SAS_SLEW_1 0x01
++#define SAS_SLEW_2 0x02
++#define SAS_SLEW_3 0x03
++#define SAS_SLEW_MASK 0x03
++
++#define PHY_CONTROL_4 0x168
++
++#define PHY_DONE_CAL_TX 0x80
++#define PHY_DONE_CAL_RX 0x40
++#define RX_TERM_LOAD_DIS 0x20
++#define TX_TERM_LOAD_DIS 0x10
++#define AUTO_TERM_CAL_DIS 0x08
++#define PHY_SIGDET_FLTR_EN 0x04
++#define OSC_FREQ 0x02
++#define PHY_START_CAL 0x01
++
++/*
++ * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC)
++ */
++#define PCIX_REG_BASE_ADR 0xB8040000
++
++#define PCIC_VENDOR_ID 0x00
++
++#define PCIC_DEVICE_ID 0x02
++
++#define PCIC_COMMAND 0x04
++
++#define INT_DIS 0x0400
++#define FBB_EN 0x0200 /* ro */
++#define SERR_EN 0x0100
++#define STEP_EN 0x0080 /* ro */
++#define PERR_EN 0x0040
++#define VGA_EN 0x0020 /* ro */
++#define MWI_EN 0x0010
++#define SPC_EN 0x0008
++#define MST_EN 0x0004
++#define MEM_EN 0x0002
++#define IO_EN 0x0001
++
++#define PCIC_STATUS 0x06
++
++#define PERR_DET 0x8000
++#define SERR_GEN 0x4000
++#define MABT_DET 0x2000
++#define TABT_DET 0x1000
++#define TABT_GEN 0x0800
++#define DPERR_DET 0x0100
++#define CAP_LIST 0x0010
++#define INT_STAT 0x0008
++
++#define PCIC_DEVREV_ID 0x08
++
++#define PCIC_CLASS_CODE 0x09
++
++#define PCIC_CACHELINE_SIZE 0x0C
++
++#define PCIC_MBAR0 0x10
++
++#define PCIC_MBAR0_OFFSET 0
++
++#define PCIC_MBAR1 0x18
++
++#define PCIC_MBAR1_OFFSET 2
++
++#define PCIC_IOBAR 0x20
++
++#define PCIC_IOBAR_OFFSET 4
++
++#define PCIC_SUBVENDOR_ID 0x2C
++
++#define PCIC_SUBSYTEM_ID 0x2E
++
++#define PCIX_STATUS 0x44
++#define RCV_SCE 0x20000000
++#define UNEXP_SC 0x00080000
++#define SC_DISCARD 0x00040000
++
++#define ECC_CTRL_STAT 0x48
++#define UNCOR_ECCERR 0x00000008
++
++#define PCIC_PM_CSR 0x5C
++
++#define PWR_STATE_D0 0
++#define PWR_STATE_D1 1 /* not supported */
++#define PWR_STATE_D2 2 /* not supported */
++#define PWR_STATE_D3 3
++
++#define PCIC_BASE1 0x6C /* internal use only */
++
++#define BASE1_RSVD 0xFFFFFFF8
++
++#define PCIC_BASEA 0x70 /* internal use only */
++
++#define BASEA_RSVD 0xFFFFFFC0
++#define BASEA_START 0
++
++#define PCIC_BASEB 0x74 /* internal use only */
++
++#define BASEB_RSVD 0xFFFFFF80
++#define BASEB_IOMAP_MASK 0x7F
++#define BASEB_START 0x80
++
++#define PCIC_BASEC 0x78 /* internal use only */
++
++#define BASEC_RSVD 0xFFFFFFFC
++#define BASEC_MASK 0x03
++#define BASEC_START 0x58
++
++#define PCIC_MBAR_KEY 0x7C /* internal use only */
++
++#define MBAR_KEY_MASK 0xFFFFFFFF
++
++#define PCIC_HSTPCIX_CNTRL 0xA0
++
++#define REWIND_DIS 0x0800
++#define SC_TMR_DIS 0x04000000
++
++#define PCIC_MBAR0_MASK 0xA8
++#define PCIC_MBAR0_SIZE_MASK 0x1FFFE000
++#define PCIC_MBAR0_SIZE_SHIFT 13
++#define PCIC_MBAR0_SIZE(val) \
++ (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT)
++
++#define PCIC_FLASH_MBAR 0xB8
++
++#define PCIC_INTRPT_STAT 0xD4
++
++#define PCIC_TP_CTRL 0xFC
++
++/*
++ * EXSI Registers, Addresss Range: (0x00-0xFC)
++ */
++#define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI
++
++#define EXSICNFGR (EXSI_REG_BASE_ADR + 0x00)
++
++#define OCMINITIALIZED 0x80000000
++#define ASIEN 0x00400000
++#define HCMODE 0x00200000
++#define PCIDEF 0x00100000
++#define COMSTOCK 0x00080000
++#define SEEPROMEND 0x00040000
++#define MSTTIMEN 0x00020000
++#define XREGEX 0x00000200
++#define NVRAMW 0x00000100
++#define NVRAMEX 0x00000080
++#define SRAMW 0x00000040
++#define SRAMEX 0x00000020
++#define FLASHW 0x00000010
++#define FLASHEX 0x00000008
++#define SEEPROMCFG 0x00000004
++#define SEEPROMTYP 0x00000002
++#define SEEPROMEX 0x00000001
++
++
++#define EXSICNTRLR (EXSI_REG_BASE_ADR + 0x04)
++
++#define MODINT_EN 0x00000001
++
++
++#define PMSTATR (EXSI_REG_BASE_ADR + 0x10)
++
++#define FLASHRST 0x00000002
++#define FLASHRDY 0x00000001
++
++
++#define FLCNFGR (EXSI_REG_BASE_ADR + 0x14)
++
++#define FLWEH_MASK 0x30000000
++#define FLWESU_MASK 0x0C000000
++#define FLWEPW_MASK 0x03F00000
++#define FLOEH_MASK 0x000C0000
++#define FLOESU_MASK 0x00030000
++#define FLOEPW_MASK 0x0000FC00
++#define FLCSH_MASK 0x00000300
++#define FLCSSU_MASK 0x000000C0
++#define FLCSPW_MASK 0x0000003F
++
++#define SRCNFGR (EXSI_REG_BASE_ADR + 0x18)
++
++#define SRWEH_MASK 0x30000000
++#define SRWESU_MASK 0x0C000000
++#define SRWEPW_MASK 0x03F00000
++
++#define SROEH_MASK 0x000C0000
++#define SROESU_MASK 0x00030000
++#define SROEPW_MASK 0x0000FC00
++#define SRCSH_MASK 0x00000300
++#define SRCSSU_MASK 0x000000C0
++#define SRCSPW_MASK 0x0000003F
++
++#define NVCNFGR (EXSI_REG_BASE_ADR + 0x1C)
++
++#define NVWEH_MASK 0x30000000
++#define NVWESU_MASK 0x0C000000
++#define NVWEPW_MASK 0x03F00000
++#define NVOEH_MASK 0x000C0000
++#define NVOESU_MASK 0x00030000
++#define NVOEPW_MASK 0x0000FC00
++#define NVCSH_MASK 0x00000300
++#define NVCSSU_MASK 0x000000C0
++#define NVCSPW_MASK 0x0000003F
++
++#define XRCNFGR (EXSI_REG_BASE_ADR + 0x20)
++
++#define XRWEH_MASK 0x30000000
++#define XRWESU_MASK 0x0C000000
++#define XRWEPW_MASK 0x03F00000
++#define XROEH_MASK 0x000C0000
++#define XROESU_MASK 0x00030000
++#define XROEPW_MASK 0x0000FC00
++#define XRCSH_MASK 0x00000300
++#define XRCSSU_MASK 0x000000C0
++#define XRCSPW_MASK 0x0000003F
++
++#define XREGADDR (EXSI_REG_BASE_ADR + 0x24)
++
++#define XRADDRINCEN 0x80000000
++#define XREGADD_MASK 0x007FFFFF
++
++
++#define XREGDATAR (EXSI_REG_BASE_ADR + 0x28)
++
++#define XREGDATA_MASK 0x0000FFFF
++
++#define GPIOOER (EXSI_REG_BASE_ADR + 0x40)
++
++#define GPIOODENR (EXSI_REG_BASE_ADR + 0x44)
++
++#define GPIOINVR (EXSI_REG_BASE_ADR + 0x48)
++
++#define GPIODATAOR (EXSI_REG_BASE_ADR + 0x4C)
++
++#define GPIODATAIR (EXSI_REG_BASE_ADR + 0x50)
++
++#define GPIOCNFGR (EXSI_REG_BASE_ADR + 0x54)
++
++#define GPIO_EXTSRC 0x00000001
++
++#define SCNTRLR (EXSI_REG_BASE_ADR + 0xA0)
++
++#define SXFERDONE 0x00000100
++#define SXFERCNT_MASK 0x000000E0
++#define SCMDTYP_MASK 0x0000001C
++#define SXFERSTART 0x00000002
++#define SXFEREN 0x00000001
++
++#define SRATER (EXSI_REG_BASE_ADR + 0xA4)
++
++#define SADDRR (EXSI_REG_BASE_ADR + 0xA8)
++
++#define SADDR_MASK 0x0000FFFF
++
++#define SDATAOR (EXSI_REG_BASE_ADR + 0xAC)
++
++#define SDATAOR0 (EXSI_REG_BASE_ADR + 0xAC)
++#define SDATAOR1 (EXSI_REG_BASE_ADR + 0xAD)
++#define SDATAOR2 (EXSI_REG_BASE_ADR + 0xAE)
++#define SDATAOR3 (EXSI_REG_BASE_ADR + 0xAF)
++
++#define SDATAIR (EXSI_REG_BASE_ADR + 0xB0)
++
++#define SDATAIR0 (EXSI_REG_BASE_ADR + 0xB0)
++#define SDATAIR1 (EXSI_REG_BASE_ADR + 0xB1)
++#define SDATAIR2 (EXSI_REG_BASE_ADR + 0xB2)
++#define SDATAIR3 (EXSI_REG_BASE_ADR + 0xB3)
++
++#define ASISTAT0R (EXSI_REG_BASE_ADR + 0xD0)
++#define ASIFMTERR 0x00000400
++#define ASISEECHKERR 0x00000200
++#define ASIERR 0x00000100
++
++#define ASISTAT1R (EXSI_REG_BASE_ADR + 0xD4)
++#define CHECKSUM_MASK 0x0000FFFF
++
++#define ASIERRADDR (EXSI_REG_BASE_ADR + 0xD8)
++#define ASIERRDATAR (EXSI_REG_BASE_ADR + 0xDC)
++#define ASIERRSTATR (EXSI_REG_BASE_ADR + 0xE0)
++#define CPI2ASIBYTECNT_MASK 0x00070000
++#define CPI2ASIBYTEEN_MASK 0x0000F000
++#define CPI2ASITARGERR_MASK 0x00000F00
++#define CPI2ASITARGMID_MASK 0x000000F0
++#define CPI2ASIMSTERR_MASK 0x0000000F
++
++/*
++ * XSRAM, External SRAM (DWord and any BE pattern accessible)
++ */
++#define XSRAM_REG_BASE_ADDR 0xB8100000
++#define XSRAM_SIZE 0x100000
++
++/*
++ * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF).
++ */
++#define NVRAM_REG_BASE_ADR 0xBF800000
++#define NVRAM_MAX_BASE_ADR 0x003FFFFF
++
++/* OCM base address */
++#define OCM_BASE_ADDR 0xA0000000
++#define OCM_MAX_SIZE 0x20000
++
++/*
++ * Sequencers (Central and Link) Scratch RAM page definitions.
++ */
++
++/*
++ * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024
++ * byte memory. It is dword accessible and has byte parity
++ * protection. The CSEQ accesses it in 32 byte windows, either as mode
++ * dependent or mode independent memory. Each mode has 96 bytes,
++ * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of
++ * Mode Independent memory (four 32 byte pages 3-7). Note that mode
++ * dependent scratch memory, Mode 8, page 0-3 overlaps mode
++ * independent scratch memory, pages 0-3.
++ * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and
++ * 128 bytes in mode 8,
++ * - 259 bytes of mode independent scratch, common to modes 0-15.
++ *
++ * Sequencer scratch RAM is 1024 bytes. This scratch memory is
++ * divided into mode dependent and mode independent scratch with this
++ * memory further subdivided into pages of size 32 bytes. There are 5
++ * pages (160 bytes) of mode independent scratch and 3 pages of
++ * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages
++ * 0-2 dependent scratch overlap with pages 0-2 of mode independent
++ * scratch memory.
++ *
++ * The host accesses this scratch in a different manner from the
++ * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE
++ * and CMnSCRPAGE to access the scratch memory. A flat mapping of the
++ * scratch memory is avaliable for software convenience and to prevent
++ * corruption while the sequencer is running. This memory is mapped
++ * onto addresses 800h - BFFh, total of 400h bytes.
++ *
++ * These addresses are mapped as follows:
++ *
++ * 800h-83Fh Mode Dependent Scratch Mode 0 Pages 0-1
++ * 840h-87Fh Mode Dependent Scratch Mode 1 Pages 0-1
++ * 880h-8BFh Mode Dependent Scratch Mode 2 Pages 0-1
++ * 8C0h-8FFh Mode Dependent Scratch Mode 3 Pages 0-1
++ * 900h-93Fh Mode Dependent Scratch Mode 4 Pages 0-1
++ * 940h-97Fh Mode Dependent Scratch Mode 5 Pages 0-1
++ * 980h-9BFh Mode Dependent Scratch Mode 6 Pages 0-1
++ * 9C0h-9FFh Mode Dependent Scratch Mode 7 Pages 0-1
++ * A00h-A5Fh Mode Dependent Scratch Mode 8 Pages 0-2
++ * Mode Independent Scratch Pages 0-2
++ * A60h-A7Fh Mode Dependent Scratch Mode 8 Page 3
++ * Mode Independent Scratch Page 3
++ * A80h-AFFh Mode Independent Scratch Pages 4-7
++ * B00h-B1Fh Mode Dependent Scratch Mode 0 Page 2
++ * B20h-B3Fh Mode Dependent Scratch Mode 1 Page 2
++ * B40h-B5Fh Mode Dependent Scratch Mode 2 Page 2
++ * B60h-B7Fh Mode Dependent Scratch Mode 3 Page 2
++ * B80h-B9Fh Mode Dependent Scratch Mode 4 Page 2
++ * BA0h-BBFh Mode Dependent Scratch Mode 5 Page 2
++ * BC0h-BDFh Mode Dependent Scratch Mode 6 Page 2
++ * BE0h-BFFh Mode Dependent Scratch Mode 7 Page 2
++ */
++
++/* General macros */
++#define CSEQ_PAGE_SIZE 32 /* Scratch page size (in bytes) */
++
++/* All macros start with offsets from base + 0x800 (CMAPPEDSCR).
++ * Mode dependent scratch page 0, mode 0.
++ * For modes 1-7 you have to do arithmetic. */
++#define CSEQ_LRM_SAVE_SINDEX (CMAPPEDSCR + 0x0000)
++#define CSEQ_LRM_SAVE_SCBPTR (CMAPPEDSCR + 0x0002)
++#define CSEQ_Q_LINK_HEAD (CMAPPEDSCR + 0x0004)
++#define CSEQ_Q_LINK_TAIL (CMAPPEDSCR + 0x0006)
++#define CSEQ_LRM_SAVE_SCRPAGE (CMAPPEDSCR + 0x0008)
++
++/* Mode dependent scratch page 0 mode 8 macros. */
++#define CSEQ_RET_ADDR (CMAPPEDSCR + 0x0200)
++#define CSEQ_RET_SCBPTR (CMAPPEDSCR + 0x0202)
++#define CSEQ_SAVE_SCBPTR (CMAPPEDSCR + 0x0204)
++#define CSEQ_EMPTY_TRANS_CTX (CMAPPEDSCR + 0x0206)
++#define CSEQ_RESP_LEN (CMAPPEDSCR + 0x0208)
++#define CSEQ_TMF_SCBPTR (CMAPPEDSCR + 0x020A)
++#define CSEQ_GLOBAL_PREV_SCB (CMAPPEDSCR + 0x020C)
++#define CSEQ_GLOBAL_HEAD (CMAPPEDSCR + 0x020E)
++#define CSEQ_CLEAR_LU_HEAD (CMAPPEDSCR + 0x0210)
++#define CSEQ_TMF_OPCODE (CMAPPEDSCR + 0x0212)
++#define CSEQ_SCRATCH_FLAGS (CMAPPEDSCR + 0x0213)
++#define CSEQ_HSB_SITE (CMAPPEDSCR + 0x021A)
++#define CSEQ_FIRST_INV_SCB_SITE (CMAPPEDSCR + 0x021C)
++#define CSEQ_FIRST_INV_DDB_SITE (CMAPPEDSCR + 0x021E)
++
++/* Mode dependent scratch page 1 mode 8 macros. */
++#define CSEQ_LUN_TO_CLEAR (CMAPPEDSCR + 0x0220)
++#define CSEQ_LUN_TO_CHECK (CMAPPEDSCR + 0x0228)
++
++/* Mode dependent scratch page 2 mode 8 macros */
++#define CSEQ_HQ_NEW_POINTER (CMAPPEDSCR + 0x0240)
++#define CSEQ_HQ_DONE_BASE (CMAPPEDSCR + 0x0248)
++#define CSEQ_HQ_DONE_POINTER (CMAPPEDSCR + 0x0250)
++#define CSEQ_HQ_DONE_PASS (CMAPPEDSCR + 0x0254)
++
++/* Mode independent scratch page 4 macros. */
++#define CSEQ_Q_EXE_HEAD (CMAPPEDSCR + 0x0280)
++#define CSEQ_Q_EXE_TAIL (CMAPPEDSCR + 0x0282)
++#define CSEQ_Q_DONE_HEAD (CMAPPEDSCR + 0x0284)
++#define CSEQ_Q_DONE_TAIL (CMAPPEDSCR + 0x0286)
++#define CSEQ_Q_SEND_HEAD (CMAPPEDSCR + 0x0288)
++#define CSEQ_Q_SEND_TAIL (CMAPPEDSCR + 0x028A)
++#define CSEQ_Q_DMA2CHIM_HEAD (CMAPPEDSCR + 0x028C)
++#define CSEQ_Q_DMA2CHIM_TAIL (CMAPPEDSCR + 0x028E)
++#define CSEQ_Q_COPY_HEAD (CMAPPEDSCR + 0x0290)
++#define CSEQ_Q_COPY_TAIL (CMAPPEDSCR + 0x0292)
++#define CSEQ_REG0 (CMAPPEDSCR + 0x0294)
++#define CSEQ_REG1 (CMAPPEDSCR + 0x0296)
++#define CSEQ_REG2 (CMAPPEDSCR + 0x0298)
++#define CSEQ_LINK_CTL_Q_MAP (CMAPPEDSCR + 0x029C)
++#define CSEQ_MAX_CSEQ_MODE (CMAPPEDSCR + 0x029D)
++#define CSEQ_FREE_LIST_HACK_COUNT (CMAPPEDSCR + 0x029E)
++
++/* Mode independent scratch page 5 macros. */
++#define CSEQ_EST_NEXUS_REQ_QUEUE (CMAPPEDSCR + 0x02A0)
++#define CSEQ_EST_NEXUS_REQ_COUNT (CMAPPEDSCR + 0x02A8)
++#define CSEQ_Q_EST_NEXUS_HEAD (CMAPPEDSCR + 0x02B0)
++#define CSEQ_Q_EST_NEXUS_TAIL (CMAPPEDSCR + 0x02B2)
++#define CSEQ_NEED_EST_NEXUS_SCB (CMAPPEDSCR + 0x02B4)
++#define CSEQ_EST_NEXUS_REQ_HEAD (CMAPPEDSCR + 0x02B6)
++#define CSEQ_EST_NEXUS_REQ_TAIL (CMAPPEDSCR + 0x02B7)
++#define CSEQ_EST_NEXUS_SCB_OFFSET (CMAPPEDSCR + 0x02B8)
++
++/* Mode independent scratch page 6 macros. */
++#define CSEQ_INT_ROUT_RET_ADDR0 (CMAPPEDSCR + 0x02C0)
++#define CSEQ_INT_ROUT_RET_ADDR1 (CMAPPEDSCR + 0x02C2)
++#define CSEQ_INT_ROUT_SCBPTR (CMAPPEDSCR + 0x02C4)
++#define CSEQ_INT_ROUT_MODE (CMAPPEDSCR + 0x02C6)
++#define CSEQ_ISR_SCRATCH_FLAGS (CMAPPEDSCR + 0x02C7)
++#define CSEQ_ISR_SAVE_SINDEX (CMAPPEDSCR + 0x02C8)
++#define CSEQ_ISR_SAVE_DINDEX (CMAPPEDSCR + 0x02CA)
++#define CSEQ_Q_MONIRTT_HEAD (CMAPPEDSCR + 0x02D0)
++#define CSEQ_Q_MONIRTT_TAIL (CMAPPEDSCR + 0x02D2)
++#define CSEQ_FREE_SCB_MASK (CMAPPEDSCR + 0x02D5)
++#define CSEQ_BUILTIN_FREE_SCB_HEAD (CMAPPEDSCR + 0x02D6)
++#define CSEQ_BUILTIN_FREE_SCB_TAIL (CMAPPEDSCR + 0x02D8)
++#define CSEQ_EXTENDED_FREE_SCB_HEAD (CMAPPEDSCR + 0x02DA)
++#define CSEQ_EXTENDED_FREE_SCB_TAIL (CMAPPEDSCR + 0x02DC)
++
++/* Mode independent scratch page 7 macros. */
++#define CSEQ_EMPTY_REQ_QUEUE (CMAPPEDSCR + 0x02E0)
++#define CSEQ_EMPTY_REQ_COUNT (CMAPPEDSCR + 0x02E8)
++#define CSEQ_Q_EMPTY_HEAD (CMAPPEDSCR + 0x02F0)
++#define CSEQ_Q_EMPTY_TAIL (CMAPPEDSCR + 0x02F2)
++#define CSEQ_NEED_EMPTY_SCB (CMAPPEDSCR + 0x02F4)
++#define CSEQ_EMPTY_REQ_HEAD (CMAPPEDSCR + 0x02F6)
++#define CSEQ_EMPTY_REQ_TAIL (CMAPPEDSCR + 0x02F7)
++#define CSEQ_EMPTY_SCB_OFFSET (CMAPPEDSCR + 0x02F8)
++#define CSEQ_PRIMITIVE_DATA (CMAPPEDSCR + 0x02FA)
++#define CSEQ_TIMEOUT_CONST (CMAPPEDSCR + 0x02FC)
++
++/***************************************************************************
++* Link m Sequencer scratch RAM is 512 bytes.
++* This scratch memory is divided into mode dependent and mode
++* independent scratch with this memory further subdivided into
++* pages of size 32 bytes. There are 4 pages (128 bytes) of
++* mode independent scratch and 4 pages of dependent scratch
++* memory for modes 0-2 (384 bytes).
++*
++* The host accesses this scratch in a different manner from the
++* link sequencer. The sequencer has to use LSEQ registers
++* LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat
++* mapping of the scratch memory is avaliable for software
++* convenience and to prevent corruption while the sequencer is
++* running. This memory is mapped onto addresses 800h - 9FFh.
++*
++* These addresses are mapped as follows:
++*
++* 800h-85Fh Mode Dependent Scratch Mode 0 Pages 0-2
++* 860h-87Fh Mode Dependent Scratch Mode 0 Page 3
++* Mode Dependent Scratch Mode 5 Page 0
++* 880h-8DFh Mode Dependent Scratch Mode 1 Pages 0-2
++* 8E0h-8FFh Mode Dependent Scratch Mode 1 Page 3
++* Mode Dependent Scratch Mode 5 Page 1
++* 900h-95Fh Mode Dependent Scratch Mode 2 Pages 0-2
++* 960h-97Fh Mode Dependent Scratch Mode 2 Page 3
++* Mode Dependent Scratch Mode 5 Page 2
++* 980h-9DFh Mode Independent Scratch Pages 0-3
++* 9E0h-9FFh Mode Independent Scratch Page 3
++* Mode Dependent Scratch Mode 5 Page 3
++*
++****************************************************************************/
++/* General macros */
++#define LSEQ_MODE_SCRATCH_SIZE 0x80 /* Size of scratch RAM per mode */
++#define LSEQ_PAGE_SIZE 0x20 /* Scratch page size (in bytes) */
++#define LSEQ_MODE5_PAGE0_OFFSET 0x60
++
++/* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */
++/* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */
++#define LmSEQ_RET_ADDR(LinkNum) (LmSCRATCH(LinkNum) + 0x0000)
++#define LmSEQ_REG0_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0002)
++#define LmSEQ_MODE_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0004)
++
++/* Mode flag macros (byte 0) */
++#define SAS_SAVECTX_OCCURRED 0x80
++#define SAS_OOBSVC_OCCURRED 0x40
++#define SAS_OOB_DEVICE_PRESENT 0x20
++#define SAS_CFGHDR_OCCURRED 0x10
++#define SAS_RCV_INTS_ARE_DISABLED 0x08
++#define SAS_OOB_HOT_PLUG_CNCT 0x04
++#define SAS_AWAIT_OPEN_CONNECTION 0x02
++#define SAS_CFGCMPLT_OCCURRED 0x01
++
++/* Mode flag macros (byte 1) */
++#define SAS_RLSSCB_OCCURRED 0x80
++#define SAS_FORCED_HEADER_MISS 0x40
++
++#define LmSEQ_RET_ADDR2(LinkNum) (LmSCRATCH(LinkNum) + 0x0006)
++#define LmSEQ_RET_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0008)
++#define LmSEQ_OPCODE_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000B)
++#define LmSEQ_DATA_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000C)
++
++/* Mode dependent scratch page 0 macros for mode 0 (non-common) */
++/* Absolute offsets */
++#define LmSEQ_FIRST_INV_DDB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x000E)
++#define LmSEQ_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0010)
++#define LmSEQ_RESP_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x0012)
++#define LmSEQ_FIRST_INV_SCB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x0014)
++#define LmSEQ_INTEN_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0016)
++#define LmSEQ_LINK_RST_FRM_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x001A)
++#define LmSEQ_LINK_RST_PROTOCOL(LinkNum) (LmSCRATCH(LinkNum) + 0x001B)
++#define LmSEQ_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x001C)
++#define LmSEQ_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x001D)
++#define LmSEQ_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x001E)
++
++/* Mode dependent scratch page 0 macros for mode 1 (non-common) */
++/* Absolute offsets */
++#define LmSEQ_Q_XMIT_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x008E)
++#define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0090)
++#define LmSEQ_INI_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0092)
++#define LmSEQ_FAILED_OPEN_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009A)
++#define LmSEQ_XMIT_REQUEST_TYPE(LinkNum) (LmSCRATCH(LinkNum) + 0x009B)
++#define LmSEQ_M1_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009C)
++#define LmSEQ_M1_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x009D)
++#define LmSEQ_M1_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x009E)
++
++/* Mode dependent scratch page 0 macros for mode 2 (non-common) */
++#define LmSEQ_PORT_COUNTER(LinkNum) (LmSCRATCH(LinkNum) + 0x010E)
++#define LmSEQ_PM_TABLE_PTR(LinkNum) (LmSCRATCH(LinkNum) + 0x0110)
++#define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0112)
++#define LmSEQ_IP_BITL(LinkNum) (LmSCRATCH(LinkNum) + 0x0114)
++#define LmSEQ_COPY_SMP_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0116)
++#define LmSEQ_P0M2_OFFS1AH(LinkNum) (LmSCRATCH(LinkNum) + 0x011A)
++
++/* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */
++/* Absolute offsets */
++#define LmSEQ_SAVED_OOB_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x006E)
++#define LmSEQ_SAVED_OOB_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x006F)
++#define LmSEQ_Q_LINK_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0070)
++#define LmSEQ_LINK_RST_ERR(LinkNum) (LmSCRATCH(LinkNum) + 0x0072)
++#define LmSEQ_SAVED_OOB_SIGNALS(LinkNum) (LmSCRATCH(LinkNum) + 0x0073)
++#define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074)
++#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075)
++#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076)
++#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A)
++#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C)
++#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E)
++
++/* Mode dependent scratch page 1, mode 0 and mode 1 */
++#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020)
++#define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0030)
++#define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x00A0)
++#define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x00B0)
++
++/* Mode dependent scratch page 1 macros for mode 2 */
++/* Absolute offsets */
++#define LmSEQ_INVALID_DWORD_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0120)
++#define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0124)
++#define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0128)
++
++/* Mode dependent scratch page 1 macros for mode 4/5 */
++#define LmSEQ_FRAME_TYPE_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E0)
++#define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E1)
++#define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4)
++#define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E5)
++#define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00EB)
++#define LmSEQ_TAG_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00F0)
++#define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x00F2)
++#define LmSEQ_DATA_OFFSET(LinkNum) (LmSCRATCH(LinkNum) + 0x00F4)
++
++/* Mode dependent scratch page 2 macros for mode 0 */
++/* Absolute offsets */
++#define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0040)
++#define LmSEQ_DEVICE_BITS(LinkNum) (LmSCRATCH(LinkNum) + 0x005B)
++#define LmSEQ_SDB_DDB(LinkNum) (LmSCRATCH(LinkNum) + 0x005C)
++#define LmSEQ_SDB_NUM_TAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x005E)
++#define LmSEQ_SDB_CURR_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x005F)
++
++/* Mode dependent scratch page 2 macros for mode 1 */
++/* Absolute offsets */
++/* byte 0 bits 1-0 are domain select. */
++#define LmSEQ_TX_ID_ADDR_FRAME(LinkNum) (LmSCRATCH(LinkNum) + 0x00C0)
++#define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00C8)
++#define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00CC)
++#define LmSEQ_LAST_LOADED_SG_EL(LinkNum) (LmSCRATCH(LinkNum) + 0x00D4)
++
++/* Mode dependent scratch page 2 macros for mode 2 */
++/* Absolute offsets */
++#define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140)
++#define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0144)
++#define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0148)
++#define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x014C)
++#define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \
++ (LmSCRATCH(LinkNum) + 0x0150)
++#define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0154)
++
++/* Mode dependent scratch page 2 macros for mode 5 */
++#define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0160)
++#define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0164)
++#define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0168)
++#define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x016C)
++
++/* Mode dependent scratch page 3 macros for modes 0 and 1 */
++/* None defined */
++
++/* Mode dependent scratch page 3 macros for modes 2 and 5 */
++/* None defined */
++
++/* Mode Independent Scratch page 0 macros. */
++#define LmSEQ_Q_TGTXFR_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0180)
++#define LmSEQ_Q_TGTXFR_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x0182)
++#define LmSEQ_LINK_NUMBER(LinkNum) (LmSCRATCH(LinkNum) + 0x0186)
++#define LmSEQ_SCRATCH_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0187)
++/*
++ * Currently only bit 0, SAS_DWSAQD, is used.
++ */
++#define SAS_DWSAQD 0x01 /*
++ * DWSSTATUS: DWSAQD
++ * bit las read in ISR.
++ */
++#define LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188)
++/* Connection states (byte 0) */
++#define SAS_WE_OPENED_CS 0x01
++#define SAS_DEVICE_OPENED_CS 0x02
++#define SAS_WE_SENT_DONE_CS 0x04
++#define SAS_DEVICE_SENT_DONE_CS 0x08
++#define SAS_WE_SENT_CLOSE_CS 0x10
++#define SAS_DEVICE_SENT_CLOSE_CS 0x20
++#define SAS_WE_SENT_BREAK_CS 0x40
++#define SAS_DEVICE_SENT_BREAK_CS 0x80
++/* Connection states (byte 1) */
++#define SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS 0x01
++#define SAS_AIP_RECEIVED_CS 0x02
++#define SAS_CREDIT_TIMEOUT_OCCURRED_CS 0x04
++#define SAS_ACKNAK_TIMEOUT_OCCURRED_CS 0x08
++#define SAS_SMPRSP_TIMEOUT_OCCURRED_CS 0x10
++#define SAS_DONE_TIMEOUT_OCCURRED_CS 0x20
++/* Connection states (byte 2) */
++#define SAS_SMP_RESPONSE_RECEIVED_CS 0x01
++#define SAS_INTLK_TIMEOUT_OCCURRED_CS 0x02
++#define SAS_DEVICE_SENT_DMAT_CS 0x04
++#define SAS_DEVICE_SENT_SYNCSRST_CS 0x08
++#define SAS_CLEARING_AFFILIATION_CS 0x20
++#define SAS_RXTASK_ACTIVE_CS 0x40
++#define SAS_TXTASK_ACTIVE_CS 0x80
++/* Connection states (byte 3) */
++#define SAS_PHY_LOSS_OF_SIGNAL_CS 0x01
++#define SAS_DWS_TIMER_EXPIRED_CS 0x02
++#define SAS_LINK_RESET_NOT_COMPLETE_CS 0x04
++#define SAS_PHY_DISABLED_CS 0x08
++#define SAS_LINK_CTL_TASK_ACTIVE_CS 0x10
++#define SAS_PHY_EVENT_TASK_ACTIVE_CS 0x20
++#define SAS_DEVICE_SENT_ID_FRAME_CS 0x40
++#define SAS_DEVICE_SENT_REG_FIS_CS 0x40
++#define SAS_DEVICE_SENT_HARD_RESET_CS 0x80
++#define SAS_PHY_IS_DOWN_FLAGS (SAS_PHY_LOSS_OF_SIGNAL_CS|\
++ SAS_DWS_TIMER_EXPIRED_CS |\
++ SAS_LINK_RESET_NOT_COMPLETE_CS|\
++ SAS_PHY_DISABLED_CS)
++
++#define SAS_LINK_CTL_PHY_EVENT_FLAGS (SAS_LINK_CTL_TASK_ACTIVE_CS |\
++ SAS_PHY_EVENT_TASK_ACTIVE_CS |\
++ SAS_DEVICE_SENT_ID_FRAME_CS |\
++ SAS_DEVICE_SENT_HARD_RESET_CS)
++
++#define LmSEQ_CONCTL(LinkNum) (LmSCRATCH(LinkNum) + 0x018C)
++#define LmSEQ_CONSTAT(LinkNum) (LmSCRATCH(LinkNum) + 0x018E)
++#define LmSEQ_CONNECTION_MODES(LinkNum) (LmSCRATCH(LinkNum) + 0x018F)
++#define LmSEQ_REG1_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0192)
++#define LmSEQ_REG2_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0194)
++#define LmSEQ_REG3_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0196)
++#define LmSEQ_REG0_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0198)
++
++/* Mode independent scratch page 1 macros. */
++#define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A0)
++#define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A2)
++#define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01A4)
++#define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01A6)
++#define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A8)
++#define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A9)
++#define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum) (LmSCRATCH(LinkNum) + 0x01AA)
++#define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum) (LmSCRATCH(LinkNum) + 0x01AB)
++#define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01AC)
++#define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AD)
++#define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AE)
++#define LmSEQ_TIMEOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01B8)
++#define LmSEQ_ISR_SAVE_SINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BC)
++#define LmSEQ_ISR_SAVE_DINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BE)
++
++/* Mode independent scratch page 2 macros. */
++#define LmSEQ_EMPTY_SCB_PTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C0)
++#define LmSEQ_EMPTY_SCB_PTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C2)
++#define LmSEQ_EMPTY_SCB_PTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01C4)
++#define LmSEQ_EMPTY_SCB_PTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01C6)
++#define LmSEQ_EMPTY_SCB_OPCD0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C8)
++#define LmSEQ_EMPTY_SCB_OPCD1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C9)
++#define LmSEQ_EMPTY_SCB_OPCD2(LinkNum) (LmSCRATCH(LinkNum) + 0x01CA)
++#define LmSEQ_EMPTY_SCB_OPCD3(LinkNum) (LmSCRATCH(LinkNum) + 0x01CB)
++#define LmSEQ_EMPTY_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01CC)
++#define LmSEQ_EMPTY_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CD)
++#define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CE)
++#define LmSEQ_ATA_SCR_REGS(LinkNum) (LmSCRATCH(LinkNum) + 0x01D4)
++
++/* Mode independent scratch page 3 macros. */
++#define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01E0)
++#define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E4)
++#define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E8)
++#define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01EC)
++#define LmSEQ_RCV_FIS_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F0)
++#define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F4)
++#define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F8)
++#define LmSEQ_SMP_RCV_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01FC)
++
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
+new file mode 100644
+index 0000000..64d2317
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_sas.h
+@@ -0,0 +1,785 @@
++/*
++ * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef _AIC94XX_SAS_H_
++#define _AIC94XX_SAS_H_
++
++#include <scsi/libsas.h>
++
++/* ---------- DDBs ---------- */
++/* DDBs are device descriptor blocks which describe a device in the
++ * domain that this sequencer can maintain low-level connections for
++ * us. They are be 64 bytes.
++ */
++
++struct asd_ddb_ssp_smp_target_port {
++ u8 conn_type; /* byte 0 */
++#define DDB_TP_CONN_TYPE 0x81 /* Initiator port and addr frame type 0x01 */
++
++ u8 conn_rate;
++ __be16 init_conn_tag;
++ u8 dest_sas_addr[8]; /* bytes 4-11 */
++
++ __le16 send_queue_head;
++ u8 sq_suspended;
++ u8 ddb_type; /* DDB_TYPE_TARGET */
++#define DDB_TYPE_UNUSED 0xFF
++#define DDB_TYPE_TARGET 0xFE
++#define DDB_TYPE_INITIATOR 0xFD
++#define DDB_TYPE_PM_PORT 0xFC
++
++ __le16 _r_a;
++ __be16 awt_def;
++
++ u8 compat_features; /* byte 20 */
++ u8 pathway_blocked_count;
++ __be16 arb_wait_time;
++ __be32 more_compat_features; /* byte 24 */
++
++ u8 conn_mask;
++ u8 flags; /* concurrent conn:2,2 and open:0(1) */
++#define CONCURRENT_CONN_SUPP 0x04
++#define OPEN_REQUIRED 0x01
++
++ u16 _r_b;
++ __le16 exec_queue_tail;
++ __le16 send_queue_tail;
++ __le16 sister_ddb;
++
++ __le16 _r_c;
++
++ u8 max_concurrent_conn;
++ u8 num_concurrent_conn;
++ u8 num_contexts;
++
++ u8 _r_d;
++
++ __le16 active_task_count;
++
++ u8 _r_e[9];
++
++ u8 itnl_reason; /* I_T nexus loss reason */
++
++ __le16 _r_f;
++
++ __le16 itnl_timeout;
++#define ITNL_TIMEOUT_CONST 0x7D0 /* 2 seconds */
++
++ __le32 itnl_timestamp;
++} __attribute__ ((packed));
++
++struct asd_ddb_stp_sata_target_port {
++ u8 conn_type; /* byte 0 */
++ u8 conn_rate;
++ __be16 init_conn_tag;
++ u8 dest_sas_addr[8]; /* bytes 4-11 */
++
++ __le16 send_queue_head;
++ u8 sq_suspended;
++ u8 ddb_type; /* DDB_TYPE_TARGET */
++
++ __le16 _r_a;
++
++ __be16 awt_def;
++ u8 compat_features; /* byte 20 */
++ u8 pathway_blocked_count;
++ __be16 arb_wait_time;
++ __be32 more_compat_features; /* byte 24 */
++
++ u8 conn_mask;
++ u8 flags; /* concurrent conn:2,2 and open:0(1) */
++#define SATA_MULTIPORT 0x80
++#define SUPPORTS_AFFIL 0x40
++#define STP_AFFIL_POL 0x20
++
++ u8 _r_b;
++ u8 flags2; /* STP close policy:0 */
++#define STP_CL_POL_NO_TX 0x00
++#define STP_CL_POL_BTW_CMDS 0x01
++
++ __le16 exec_queue_tail;
++ __le16 send_queue_tail;
++ __le16 sister_ddb;
++ __le16 ata_cmd_scbptr;
++ __le32 sata_tag_alloc_mask;
++ __le16 active_task_count;
++ __le16 _r_c;
++ __le32 sata_sactive;
++ u8 num_sata_tags;
++ u8 sata_status;
++ u8 sata_ending_status;
++ u8 itnl_reason; /* I_T nexus loss reason */
++ __le16 ncq_data_scb_ptr;
++ __le16 itnl_timeout;
++ __le32 itnl_timestamp;
++} __attribute__ ((packed));
++
++/* This struct asd_ddb_init_port, describes the device descriptor block
++ * of an initiator port (when the sequencer is operating in target mode).
++ * Bytes [0,11] and [20,27] are from the OPEN address frame.
++ * The sequencer allocates an initiator port DDB entry.
++ */
++struct asd_ddb_init_port {
++ u8 conn_type; /* byte 0 */
++ u8 conn_rate;
++ __be16 init_conn_tag; /* BE */
++ u8 dest_sas_addr[8];
++ __le16 send_queue_head; /* LE, byte 12 */
++ u8 sq_suspended;
++ u8 ddb_type; /* DDB_TYPE_INITIATOR */
++ __le16 _r_a;
++ __be16 awt_def; /* BE */
++ u8 compat_features;
++ u8 pathway_blocked_count;
++ __be16 arb_wait_time; /* BE */
++ __be32 more_compat_features; /* BE */
++ u8 conn_mask;
++ u8 flags; /* == 5 */
++ u16 _r_b;
++ __le16 exec_queue_tail; /* execution queue tail */
++ __le16 send_queue_tail;
++ __le16 sister_ddb;
++ __le16 init_resp_timeout; /* initiator response timeout */
++ __le32 _r_c;
++ __le16 active_tasks; /* active task count */
++ __le16 init_list; /* initiator list link pointer */
++ __le32 _r_d;
++ u8 max_conn_to[3]; /* from Conn-Disc mode page, in us, LE */
++ u8 itnl_reason; /* I_T nexus loss reason */
++ __le16 bus_inact_to; /* from Conn-Disc mode page, in 100 us, LE */
++ __le16 itnl_to; /* from the Protocol Specific Port Ctrl MP */
++ __le32 itnl_timestamp;
++} __attribute__ ((packed));
++
++/* This struct asd_ddb_sata_tag, describes a look-up table to be used
++ * by the sequencers. SATA II, IDENTIFY DEVICE data, word 76, bit 8:
++ * NCQ support. This table is used by the sequencers to find the
++ * corresponding SCB, given a SATA II tag value.
++ */
++struct asd_ddb_sata_tag {
++ __le16 scb_pointer[32];
++} __attribute__ ((packed));
++
++/* This struct asd_ddb_sata_pm_table, describes a port number to
++ * connection handle look-up table. SATA targets attached to a port
++ * multiplier require a 4-bit port number value. There is one DDB
++ * entry of this type for each SATA port multiplier (sister DDB).
++ * Given a SATA PM port number, this table gives us the SATA PM Port
++ * DDB of the SATA port multiplier port (i.e. the SATA target
++ * discovered on the port).
++ */
++struct asd_ddb_sata_pm_table {
++ __le16 ddb_pointer[16];
++ __le16 _r_a[16];
++} __attribute__ ((packed));
++
++/* This struct asd_ddb_sata_pm_port, describes the SATA port multiplier
++ * port format DDB.
++ */
++struct asd_ddb_sata_pm_port {
++ u8 _r_a[15];
++ u8 ddb_type;
++ u8 _r_b[13];
++ u8 pm_port_flags;
++#define PM_PORT_MASK 0xF0
++#define PM_PORT_SET 0x02
++ u8 _r_c[6];
++ __le16 sister_ddb;
++ __le16 ata_cmd_scbptr;
++ __le32 sata_tag_alloc_mask;
++ __le16 active_task_count;
++ __le16 parent_ddb;
++ __le32 sata_sactive;
++ u8 num_sata_tags;
++ u8 sata_status;
++ u8 sata_ending_status;
++ u8 _r_d[9];
++} __attribute__ ((packed));
++
++/* This struct asd_ddb_seq_shared, describes a DDB shared by the
++ * central and link sequencers. port_map_by_links is indexed phy
++ * number [0,7]; each byte is a bit mask of all the phys that are in
++ * the same port as the indexed phy.
++ */
++struct asd_ddb_seq_shared {
++ __le16 q_free_ddb_head;
++ __le16 q_free_ddb_tail;
++ __le16 q_free_ddb_cnt;
++ __le16 q_used_ddb_head;
++ __le16 q_used_ddb_tail;
++ __le16 shared_mem_lock;
++ __le16 smp_conn_tag;
++ __le16 est_nexus_buf_cnt;
++ __le16 est_nexus_buf_thresh;
++ u32 _r_a;
++ u8 settable_max_contexts;
++ u8 _r_b[23];
++ u8 conn_not_active;
++ u8 phy_is_up;
++ u8 _r_c[8];
++ u8 port_map_by_links[8];
++} __attribute__ ((packed));
++
++/* ---------- SG Element ---------- */
++
++/* This struct sg_el, describes the hardware scatter gather buffer
++ * element. All entries are little endian. In an SCB, there are 2 of
++ * this, plus one more, called a link element of this indicating a
++ * sublist if needed.
++ *
++ * A link element has only the bus address set and the flags (DS) bit
++ * valid. The bus address points to the start of the sublist.
++ *
++ * If a sublist is needed, then that sublist should also include the 2
++ * sg_el embedded in the SCB, in which case next_sg_offset is 32,
++ * since sizeof(sg_el) = 16; EOS should be 1 and EOL 0 in this case.
++ */
++struct sg_el {
++ __le64 bus_addr;
++ __le32 size;
++ __le16 _r;
++ u8 next_sg_offs;
++ u8 flags;
++#define ASD_SG_EL_DS_MASK 0x30
++#define ASD_SG_EL_DS_OCM 0x10
++#define ASD_SG_EL_DS_HM 0x00
++#define ASD_SG_EL_LIST_MASK 0xC0
++#define ASD_SG_EL_LIST_EOL 0x40
++#define ASD_SG_EL_LIST_EOS 0x80
++} __attribute__ ((packed));
++
++/* ---------- SCBs ---------- */
++
++/* An SCB (sequencer control block) is comprised of a common header
++ * and a task part, for a total of 128 bytes. All fields are in LE
++ * order, unless otherwise noted.
++ */
++
++/* This struct scb_header, defines the SCB header format.
++ */
++struct scb_header {
++ __le64 next_scb;
++ __le16 index; /* transaction context */
++ u8 opcode;
++} __attribute__ ((packed));
++
++/* SCB opcodes: Execution queue
++ */
++#define INITIATE_SSP_TASK 0x00
++#define INITIATE_LONG_SSP_TASK 0x01
++#define INITIATE_BIDIR_SSP_TASK 0x02
++#define ABORT_TASK 0x03
++#define INITIATE_SSP_TMF 0x04
++#define SSP_TARG_GET_DATA 0x05
++#define SSP_TARG_GET_DATA_GOOD 0x06
++#define SSP_TARG_SEND_RESP 0x07
++#define QUERY_SSP_TASK 0x08
++#define INITIATE_ATA_TASK 0x09
++#define INITIATE_ATAPI_TASK 0x0a
++#define CONTROL_ATA_DEV 0x0b
++#define INITIATE_SMP_TASK 0x0c
++#define SMP_TARG_SEND_RESP 0x0f
++
++/* SCB opcodes: Send Queue
++ */
++#define SSP_TARG_SEND_DATA 0x40
++#define SSP_TARG_SEND_DATA_GOOD 0x41
++
++/* SCB opcodes: Link Queue
++ */
++#define CONTROL_PHY 0x80
++#define SEND_PRIMITIVE 0x81
++#define INITIATE_LINK_ADM_TASK 0x82
++
++/* SCB opcodes: other
++ */
++#define EMPTY_SCB 0xc0
++#define INITIATE_SEQ_ADM_TASK 0xc1
++#define EST_ICL_TARG_WINDOW 0xc2
++#define COPY_MEM 0xc3
++#define CLEAR_NEXUS 0xc4
++#define INITIATE_DDB_ADM_TASK 0xc6
++#define ESTABLISH_NEXUS_ESCB 0xd0
++
++#define LUN_SIZE 8
++
++/* See SAS spec, task IU
++ */
++struct ssp_task_iu {
++ u8 lun[LUN_SIZE]; /* BE */
++ u16 _r_a;
++ u8 tmf;
++ u8 _r_b;
++ __be16 tag; /* BE */
++ u8 _r_c[14];
++} __attribute__ ((packed));
++
++/* See SAS spec, command IU
++ */
++struct ssp_command_iu {
++ u8 lun[LUN_SIZE];
++ u8 _r_a;
++ u8 efb_prio_attr; /* enable first burst, task prio & attr */
++#define EFB_MASK 0x80
++#define TASK_PRIO_MASK 0x78
++#define TASK_ATTR_MASK 0x07
++
++ u8 _r_b;
++ u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */
++ union {
++ u8 cdb[16];
++ struct {
++ __le64 long_cdb_addr; /* bus address, LE */
++ __le32 long_cdb_size; /* LE */
++ u8 _r_c[3];
++ u8 eol_ds; /* eol:6,6, ds:5,4 */
++ } long_cdb; /* sequencer extension */
++ };
++} __attribute__ ((packed));
++
++struct xfer_rdy_iu {
++ __be32 requested_offset; /* BE */
++ __be32 write_data_len; /* BE */
++ __be32 _r_a;
++} __attribute__ ((packed));
++
++/* ---------- SCB tasks ---------- */
++
++/* This is both ssp_task and long_ssp_task
++ */
++struct initiate_ssp_task {
++ u8 proto_conn_rate; /* proto:6,4, conn_rate:3,0 */
++ __le32 total_xfer_len;
++ struct ssp_frame_hdr ssp_frame;
++ struct ssp_command_iu ssp_cmd;
++ __le16 sister_scb; /* 0xFFFF */
++ __le16 conn_handle; /* index to DDB for the intended target */
++ u8 data_dir; /* :1,0 */
++#define DATA_DIR_NONE 0x00
++#define DATA_DIR_IN 0x01
++#define DATA_DIR_OUT 0x02
++#define DATA_DIR_BYRECIPIENT 0x03
++
++ u8 _r_a;
++ u8 retry_count;
++ u8 _r_b[5];
++ struct sg_el sg_element[3]; /* 2 real and 1 link */
++} __attribute__ ((packed));
++
++/* This defines both ata_task and atapi_task.
++ * ata: C bit of FIS should be 1,
++ * atapi: C bit of FIS should be 1, and command register should be 0xA0,
++ * to indicate a packet command.
++ */
++struct initiate_ata_task {
++ u8 proto_conn_rate;
++ __le32 total_xfer_len;
++ struct host_to_dev_fis fis;
++ __le32 data_offs;
++ u8 atapi_packet[16];
++ u8 _r_a[12];
++ __le16 sister_scb;
++ __le16 conn_handle;
++ u8 ata_flags; /* CSMI:6,6, DTM:4,4, QT:3,3, data dir:1,0 */
++#define CSMI_TASK 0x40
++#define DATA_XFER_MODE_DMA 0x10
++#define ATA_Q_TYPE_MASK 0x08
++#define ATA_Q_TYPE_UNTAGGED 0x00
++#define ATA_Q_TYPE_NCQ 0x08
++
++ u8 _r_b;
++ u8 retry_count;
++ u8 _r_c;
++ u8 flags;
++#define STP_AFFIL_POLICY 0x20
++#define SET_AFFIL_POLICY 0x10
++#define RET_PARTIAL_SGLIST 0x02
++
++ u8 _r_d[3];
++ struct sg_el sg_element[3];
++} __attribute__ ((packed));
++
++struct initiate_smp_task {
++ u8 proto_conn_rate;
++ u8 _r_a[40];
++ struct sg_el smp_req;
++ __le16 sister_scb;
++ __le16 conn_handle;
++ u8 _r_c[8];
++ struct sg_el smp_resp;
++ u8 _r_d[32];
++} __attribute__ ((packed));
++
++struct control_phy {
++ u8 phy_id;
++ u8 sub_func;
++#define DISABLE_PHY 0x00
++#define ENABLE_PHY 0x01
++#define RELEASE_SPINUP_HOLD 0x02
++#define ENABLE_PHY_NO_SAS_OOB 0x03
++#define ENABLE_PHY_NO_SATA_OOB 0x04
++#define PHY_NO_OP 0x05
++#define EXECUTE_HARD_RESET 0x81
++
++ u8 func_mask;
++ u8 speed_mask;
++ u8 hot_plug_delay;
++ u8 port_type;
++ u8 flags;
++#define DEV_PRES_TIMER_OVERRIDE_ENABLE 0x01
++#define DISABLE_PHY_IF_OOB_FAILS 0x02
++
++ __le32 timeout_override;
++ u8 link_reset_retries;
++ u8 _r_a[47];
++ __le16 conn_handle;
++ u8 _r_b[56];
++} __attribute__ ((packed));
++
++struct control_ata_dev {
++ u8 proto_conn_rate;
++ __le32 _r_a;
++ struct host_to_dev_fis fis;
++ u8 _r_b[32];
++ __le16 sister_scb;
++ __le16 conn_handle;
++ u8 ata_flags; /* 0 */
++ u8 _r_c[55];
++} __attribute__ ((packed));
++
++struct empty_scb {
++ u8 num_valid;
++ __le32 _r_a;
++#define ASD_EDBS_PER_SCB 7
++/* header+data+CRC+DMA suffix data */
++#define ASD_EDB_SIZE (24+1024+4+16)
++ struct sg_el eb[ASD_EDBS_PER_SCB];
++#define ELEMENT_NOT_VALID 0xC0
++} __attribute__ ((packed));
++
++struct initiate_link_adm {
++ u8 phy_id;
++ u8 sub_func;
++#define GET_LINK_ERROR_COUNT 0x00
++#define RESET_LINK_ERROR_COUNT 0x01
++#define ENABLE_NOTIFY_SPINUP_INTS 0x02
++
++ u8 _r_a[57];
++ __le16 conn_handle;
++ u8 _r_b[56];
++} __attribute__ ((packed));
++
++struct copy_memory {
++ u8 _r_a;
++ __le16 xfer_len;
++ __le16 _r_b;
++ __le64 src_busaddr;
++ u8 src_ds; /* See definition of sg_el */
++ u8 _r_c[45];
++ __le16 conn_handle;
++ __le64 _r_d;
++ __le64 dest_busaddr;
++ u8 dest_ds; /* See definition of sg_el */
++ u8 _r_e[39];
++} __attribute__ ((packed));
++
++struct abort_task {
++ u8 proto_conn_rate;
++ __le32 _r_a;
++ struct ssp_frame_hdr ssp_frame;
++ struct ssp_task_iu ssp_task;
++ __le16 sister_scb;
++ __le16 conn_handle;
++ u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
++#define SUSPEND_DATA_TRANS 0x04
++
++ u8 _r_b;
++ u8 retry_count;
++ u8 _r_c[5];
++ __le16 index; /* Transaction context of task to be queried */
++ __le16 itnl_to;
++ u8 _r_d[44];
++} __attribute__ ((packed));
++
++struct clear_nexus {
++ u8 nexus;
++#define NEXUS_ADAPTER 0x00
++#define NEXUS_PORT 0x01
++#define NEXUS_I_T 0x02
++#define NEXUS_I_T_L 0x03
++#define NEXUS_TAG 0x04
++#define NEXUS_TRANS_CX 0x05
++#define NEXUS_SATA_TAG 0x06
++#define NEXUS_T_L 0x07
++#define NEXUS_L 0x08
++#define NEXUS_T_TAG 0x09
++
++ __le32 _r_a;
++ u8 flags;
++#define SUSPEND_TX 0x80
++#define RESUME_TX 0x40
++#define SEND_Q 0x04
++#define EXEC_Q 0x02
++#define NOTINQ 0x01
++
++ u8 _r_b[3];
++ u8 conn_mask;
++ u8 _r_c[19];
++ struct ssp_task_iu ssp_task; /* LUN and TAG */
++ __le16 _r_d;
++ __le16 conn_handle;
++ __le64 _r_e;
++ __le16 index; /* Transaction context of task to be cleared */
++ __le16 context; /* Clear nexus context */
++ u8 _r_f[44];
++} __attribute__ ((packed));
++
++struct initiate_ssp_tmf {
++ u8 proto_conn_rate;
++ __le32 _r_a;
++ struct ssp_frame_hdr ssp_frame;
++ struct ssp_task_iu ssp_task;
++ __le16 sister_scb;
++ __le16 conn_handle;
++ u8 flags; /* itnl override and suspend data tx */
++#define OVERRIDE_ITNL_TIMER 8
++
++ u8 _r_b;
++ u8 retry_count;
++ u8 _r_c[5];
++ __le16 index; /* Transaction context of task to be queried */
++ __le16 itnl_to;
++ u8 _r_d[44];
++} __attribute__ ((packed));
++
++/* Transmits an arbitrary primitive on the link.
++ * Used for NOTIFY and BROADCAST.
++ */
++struct send_prim {
++ u8 phy_id;
++ u8 wait_transmit; /* :0,0 */
++ u8 xmit_flags;
++#define XMTPSIZE_MASK 0xF0
++#define XMTPSIZE_SINGLE 0x10
++#define XMTPSIZE_REPEATED 0x20
++#define XMTPSIZE_CONT 0x20
++#define XMTPSIZE_TRIPLE 0x30
++#define XMTPSIZE_REDUNDANT 0x60
++#define XMTPSIZE_INF 0
++
++#define XMTCONTEN 0x04
++#define XMTPFRM 0x02 /* Transmit at the next frame boundary */
++#define XMTPIMM 0x01 /* Transmit immediately */
++
++ __le16 _r_a;
++ u8 prim[4]; /* K, D0, D1, D2 */
++ u8 _r_b[50];
++ __le16 conn_handle;
++ u8 _r_c[56];
++} __attribute__ ((packed));
++
++/* This describes both SSP Target Get Data and SSP Target Get Data And
++ * Send Good Response SCBs. Used when the sequencer is operating in
++ * target mode...
++ */
++struct ssp_targ_get_data {
++ u8 proto_conn_rate;
++ __le32 total_xfer_len;
++ struct ssp_frame_hdr ssp_frame;
++ struct xfer_rdy_iu xfer_rdy;
++ u8 lun[LUN_SIZE];
++ __le64 _r_a;
++ __le16 sister_scb;
++ __le16 conn_handle;
++ u8 data_dir; /* 01b */
++ u8 _r_b;
++ u8 retry_count;
++ u8 _r_c[5];
++ struct sg_el sg_element[3];
++} __attribute__ ((packed));
++
++/* ---------- The actual SCB struct ---------- */
++
++struct scb {
++ struct scb_header header;
++ union {
++ struct initiate_ssp_task ssp_task;
++ struct initiate_ata_task ata_task;
++ struct initiate_smp_task smp_task;
++ struct control_phy control_phy;
++ struct control_ata_dev control_ata_dev;
++ struct empty_scb escb;
++ struct initiate_link_adm link_adm;
++ struct copy_memory cp_mem;
++ struct abort_task abort_task;
++ struct clear_nexus clear_nexus;
++ struct initiate_ssp_tmf ssp_tmf;
++ };
++} __attribute__ ((packed));
++
++/* ---------- Done List ---------- */
++/* The done list entry opcode field is defined below.
++ * The mnemonic encoding and meaning is as follows:
++ * TC - Task Complete, status was received and acknowledged
++ * TF - Task Failed, indicates an error prior to receiving acknowledgment
++ * for the command:
++ * - no conn,
++ * - NACK or R_ERR received in response to this command,
++ * - credit blocked or not available, or in the case of SMP request,
++ * - no SMP response was received.
++ * In these four cases it is known that the target didn't receive the
++ * command.
++ * TI - Task Interrupted, error after the command was acknowledged. It is
++ * known that the command was received by the target.
++ * TU - Task Unacked, command was transmitted but neither ACK (R_OK) nor NAK
++ * (R_ERR) was received due to loss of signal, broken connection, loss of
++ * dword sync or other reason. The application client should send the
++ * appropriate task query.
++ * TA - Task Aborted, see TF.
++ * _RESP - The completion includes an empty buffer containing status.
++ * TO - Timeout.
++ */
++#define TC_NO_ERROR 0x00
++#define TC_UNDERRUN 0x01
++#define TC_OVERRUN 0x02
++#define TF_OPEN_TO 0x03
++#define TF_OPEN_REJECT 0x04
++#define TI_BREAK 0x05
++#define TI_PROTO_ERR 0x06
++#define TC_SSP_RESP 0x07
++#define TI_PHY_DOWN 0x08
++#define TF_PHY_DOWN 0x09
++#define TC_LINK_ADM_RESP 0x0a
++#define TC_CSMI 0x0b
++#define TC_ATA_RESP 0x0c
++#define TU_PHY_DOWN 0x0d
++#define TU_BREAK 0x0e
++#define TI_SATA_TO 0x0f
++#define TI_NAK 0x10
++#define TC_CONTROL_PHY 0x11
++#define TF_BREAK 0x12
++#define TC_RESUME 0x13
++#define TI_ACK_NAK_TO 0x14
++#define TF_SMPRSP_TO 0x15
++#define TF_SMP_XMIT_RCV_ERR 0x16
++#define TC_PARTIAL_SG_LIST 0x17
++#define TU_ACK_NAK_TO 0x18
++#define TU_SATA_TO 0x19
++#define TF_NAK_RECV 0x1a
++#define TA_I_T_NEXUS_LOSS 0x1b
++#define TC_ATA_R_ERR_RECV 0x1c
++#define TF_TMF_NO_CTX 0x1d
++#define TA_ON_REQ 0x1e
++#define TF_TMF_NO_TAG 0x1f
++#define TF_TMF_TAG_FREE 0x20
++#define TF_TMF_TASK_DONE 0x21
++#define TF_TMF_NO_CONN_HANDLE 0x22
++#define TC_TASK_CLEARED 0x23
++#define TI_SYNCS_RECV 0x24
++#define TU_SYNCS_RECV 0x25
++#define TF_IRTT_TO 0x26
++#define TF_NO_SMP_CONN 0x27
++#define TF_IU_SHORT 0x28
++#define TF_DATA_OFFS_ERR 0x29
++#define TF_INV_CONN_HANDLE 0x2a
++#define TF_REQUESTED_N_PENDING 0x2b
++
++/* 0xc1 - 0xc7: empty buffer received,
++ 0xd1 - 0xd7: establish nexus empty buffer received
++*/
++/* This is the ESCB mask */
++#define ESCB_RECVD 0xC0
++
++
++/* This struct done_list_struct defines the done list entry.
++ * All fields are LE.
++ */
++struct done_list_struct {
++ __le16 index; /* aka transaction context */
++ u8 opcode;
++ u8 status_block[4];
++ u8 toggle; /* bit 0 */
++#define DL_TOGGLE_MASK 0x01
++} __attribute__ ((packed));
++
++/* ---------- PHYS ---------- */
++
++struct asd_phy {
++ struct asd_sas_phy sas_phy;
++ struct asd_phy_desc *phy_desc; /* hw profile */
++
++ struct sas_identify_frame *identify_frame;
++ struct asd_dma_tok *id_frm_tok;
++
++ u8 frame_rcvd[ASD_EDB_SIZE];
++};
++
++
++#define ASD_SCB_SIZE sizeof(struct scb)
++#define ASD_DDB_SIZE sizeof(struct asd_ddb_ssp_smp_target_port)
++
++/* Define this to 0 if you do not want NOTIFY (ENABLE SPINIP) sent.
++ * Default: 0x10 (it's a mask)
++ */
++#define ASD_NOTIFY_ENABLE_SPINUP 0x10
++
++/* If enabled, set this to the interval between transmission
++ * of NOTIFY (ENABLE SPINUP). In units of 200 us.
++ */
++#define ASD_NOTIFY_TIMEOUT 2500
++
++/* Initial delay after OOB, before we transmit NOTIFY (ENABLE SPINUP).
++ * If 0, transmit immediately. In milliseconds.
++ */
++#define ASD_NOTIFY_DOWN_COUNT 0
++
++/* Device present timer timeout constant, 10 ms. */
++#define ASD_DEV_PRESENT_TIMEOUT 0x2710
++
++#define ASD_SATA_INTERLOCK_TIMEOUT 0
++
++/* How long to wait before shutting down an STP connection, unless
++ * an STP target sent frame(s). 50 usec.
++ * IGNORED by the sequencer (i.e. value 0 always).
++ */
++#define ASD_STP_SHUTDOWN_TIMEOUT 0x0
++
++/* ATA soft reset timer timeout. 5 usec. */
++#define ASD_SRST_ASSERT_TIMEOUT 0x05
++
++/* 31 sec */
++#define ASD_RCV_FIS_TIMEOUT 0x01D905C0
++
++#define ASD_ONE_MILLISEC_TIMEOUT 0x03e8
++
++/* COMINIT timer */
++#define ASD_TEN_MILLISEC_TIMEOUT 0x2710
++#define ASD_COMINIT_TIMEOUT ASD_TEN_MILLISEC_TIMEOUT
++
++/* 1 sec */
++#define ASD_SMP_RCV_TIMEOUT 0x000F4240
++
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
+new file mode 100644
+index 0000000..7ee49b5
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_scb.c
+@@ -0,0 +1,758 @@
++/*
++ * Aic94xx SAS/SATA driver SCB management.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/pci.h>
++
++#include "aic94xx.h"
++#include "aic94xx_reg.h"
++#include "aic94xx_hwi.h"
++#include "aic94xx_seq.h"
++
++#include "aic94xx_dump.h"
++
++/* ---------- EMPTY SCB ---------- */
++
++#define DL_PHY_MASK 7
++#define BYTES_DMAED 0
++#define PRIMITIVE_RECVD 0x08
++#define PHY_EVENT 0x10
++#define LINK_RESET_ERROR 0x18
++#define TIMER_EVENT 0x20
++#define REQ_TASK_ABORT 0xF0
++#define REQ_DEVICE_RESET 0xF1
++#define SIGNAL_NCQ_ERROR 0xF2
++#define CLEAR_NCQ_ERROR 0xF3
++
++#define PHY_EVENTS_STATUS (CURRENT_LOSS_OF_SIGNAL | CURRENT_OOB_DONE \
++ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
++ | CURRENT_OOB_ERROR)
++
++static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
++{
++ struct sas_phy *sas_phy = phy->sas_phy.phy;
++
++ switch (oob_mode & 7) {
++ case PHY_SPEED_60:
++ /* FIXME: sas transport class doesn't have this */
++ phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
++ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
++ break;
++ case PHY_SPEED_30:
++ phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
++ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
++ break;
++ case PHY_SPEED_15:
++ phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
++ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
++ break;
++ }
++ sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
++ sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
++ sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
++ sas_phy->maximum_linkrate = phy->phy_desc->max_sas_lrate;
++ sas_phy->minimum_linkrate = phy->phy_desc->min_sas_lrate;
++
++ if (oob_mode & SAS_MODE)
++ phy->sas_phy.oob_mode = SAS_OOB_MODE;
++ else if (oob_mode & SATA_MODE)
++ phy->sas_phy.oob_mode = SATA_OOB_MODE;
++}
++
++static inline void asd_phy_event_tasklet(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
++ int phy_id = dl->status_block[0] & DL_PHY_MASK;
++ struct asd_phy *phy = &asd_ha->phys[phy_id];
++
++ u8 oob_status = dl->status_block[1] & PHY_EVENTS_STATUS;
++ u8 oob_mode = dl->status_block[2];
++
++ switch (oob_status) {
++ case CURRENT_LOSS_OF_SIGNAL:
++ /* directly attached device was removed */
++ ASD_DPRINTK("phy%d: device unplugged\n", phy_id);
++ asd_turn_led(asd_ha, phy_id, 0);
++ sas_phy_disconnected(&phy->sas_phy);
++ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL);
++ break;
++ case CURRENT_OOB_DONE:
++ /* hot plugged device */
++ asd_turn_led(asd_ha, phy_id, 1);
++ get_lrate_mode(phy, oob_mode);
++ ASD_DPRINTK("phy%d device plugged: lrate:0x%x, proto:0x%x\n",
++ phy_id, phy->sas_phy.linkrate, phy->sas_phy.iproto);
++ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
++ break;
++ case CURRENT_SPINUP_HOLD:
++ /* hot plug SATA, no COMWAKE sent */
++ asd_turn_led(asd_ha, phy_id, 1);
++ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD);
++ break;
++ case CURRENT_GTO_TIMEOUT:
++ case CURRENT_OOB_ERROR:
++ ASD_DPRINTK("phy%d error while OOB: oob status:0x%x\n", phy_id,
++ dl->status_block[1]);
++ asd_turn_led(asd_ha, phy_id, 0);
++ sas_phy_disconnected(&phy->sas_phy);
++ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR);
++ break;
++ }
++}
++
++/* If phys are enabled sparsely, this will do the right thing. */
++static inline unsigned ord_phy(struct asd_ha_struct *asd_ha,
++ struct asd_phy *phy)
++{
++ u8 enabled_mask = asd_ha->hw_prof.enabled_phys;
++ int i, k = 0;
++
++ for_each_phy(enabled_mask, enabled_mask, i) {
++ if (&asd_ha->phys[i] == phy)
++ return k;
++ k++;
++ }
++ return 0;
++}
++
++/**
++ * asd_get_attached_sas_addr -- extract/generate attached SAS address
++ * phy: pointer to asd_phy
++ * sas_addr: pointer to buffer where the SAS address is to be written
++ *
++ * This function extracts the SAS address from an IDENTIFY frame
++ * received. If OOB is SATA, then a SAS address is generated from the
++ * HA tables.
++ *
++ * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
++ * buffer.
++ */
++static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
++{
++ if (phy->sas_phy.frame_rcvd[0] == 0x34
++ && phy->sas_phy.oob_mode == SATA_OOB_MODE) {
++ struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
++ /* FIS device-to-host */
++ u64 addr = be64_to_cpu(*(__be64 *)phy->phy_desc->sas_addr);
++
++ addr += asd_ha->hw_prof.sata_name_base + ord_phy(asd_ha, phy);
++ *(__be64 *)sas_addr = cpu_to_be64(addr);
++ } else {
++ struct sas_identify_frame *idframe =
++ (void *) phy->sas_phy.frame_rcvd;
++ memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
++ }
++}
++
++static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
++ struct done_list_struct *dl,
++ int edb_id, int phy_id)
++{
++ unsigned long flags;
++ int edb_el = edb_id + ascb->edb_index;
++ struct asd_dma_tok *edb = ascb->ha->seq.edb_arr[edb_el];
++ struct asd_phy *phy = &ascb->ha->phys[phy_id];
++ struct sas_ha_struct *sas_ha = phy->sas_phy.ha;
++ u16 size = ((dl->status_block[3] & 7) << 8) | dl->status_block[2];
++
++ size = min(size, (u16) sizeof(phy->frame_rcvd));
++
++ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
++ memcpy(phy->sas_phy.frame_rcvd, edb->vaddr, size);
++ phy->sas_phy.frame_rcvd_size = size;
++ asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
++ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
++ asd_dump_frame_rcvd(phy, dl);
++ sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
++}
++
++static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
++ struct done_list_struct *dl,
++ int phy_id)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
++ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
++ u8 lr_error = dl->status_block[1];
++ u8 retries_left = dl->status_block[2];
++
++ switch (lr_error) {
++ case 0:
++ ASD_DPRINTK("phy%d: Receive ID timer expired\n", phy_id);
++ break;
++ case 1:
++ ASD_DPRINTK("phy%d: Loss of signal\n", phy_id);
++ break;
++ case 2:
++ ASD_DPRINTK("phy%d: Loss of dword sync\n", phy_id);
++ break;
++ case 3:
++ ASD_DPRINTK("phy%d: Receive FIS timeout\n", phy_id);
++ break;
++ default:
++ ASD_DPRINTK("phy%d: unknown link reset error code: 0x%x\n",
++ phy_id, lr_error);
++ break;
++ }
++
++ asd_turn_led(asd_ha, phy_id, 0);
++ sas_phy_disconnected(sas_phy);
++ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
++
++ if (retries_left == 0) {
++ int num = 1;
++ struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
++ GFP_ATOMIC);
++ if (!cp) {
++ asd_printk("%s: out of memory\n", __FUNCTION__);
++ goto out;
++ }
++ ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
++ phy_id);
++ asd_build_control_phy(cp, phy_id, ENABLE_PHY);
++ if (asd_post_ascb_list(ascb->ha, cp, 1) != 0)
++ asd_ascb_free(cp);
++ }
++out:
++ ;
++}
++
++static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
++ struct done_list_struct *dl,
++ int phy_id)
++{
++ unsigned long flags;
++ struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
++ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
++ u8 reg = dl->status_block[1];
++ u32 cont = dl->status_block[2] << ((reg & 3)*8);
++
++ reg &= ~3;
++ switch (reg) {
++ case LmPRMSTAT0BYTE0:
++ switch (cont) {
++ case LmBROADCH:
++ case LmBROADRVCH0:
++ case LmBROADRVCH1:
++ case LmBROADSES:
++ ASD_DPRINTK("phy%d: BROADCAST change received:%d\n",
++ phy_id, cont);
++ spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
++ sas_phy->sas_prim = ffs(cont);
++ spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
++ sas_ha->notify_port_event(sas_phy,PORTE_BROADCAST_RCVD);
++ break;
++
++ case LmUNKNOWNP:
++ ASD_DPRINTK("phy%d: unknown BREAK\n", phy_id);
++ break;
++
++ default:
++ ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
++ phy_id, reg, cont);
++ break;
++ }
++ break;
++ case LmPRMSTAT1BYTE0:
++ switch (cont) {
++ case LmHARDRST:
++ ASD_DPRINTK("phy%d: HARD_RESET primitive rcvd\n",
++ phy_id);
++ /* The sequencer disables all phys on that port.
++ * We have to re-enable the phys ourselves. */
++ sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
++ break;
++
++ default:
++ ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
++ phy_id, reg, cont);
++ break;
++ }
++ break;
++ default:
++ ASD_DPRINTK("unknown primitive register:0x%x\n",
++ dl->status_block[1]);
++ break;
++ }
++}
++
++/**
++ * asd_invalidate_edb -- invalidate an EDB and if necessary post the ESCB
++ * @ascb: pointer to Empty SCB
++ * @edb_id: index [0,6] to the empty data buffer which is to be invalidated
++ *
++ * After an EDB has been invalidated, if all EDBs in this ESCB have been
++ * invalidated, the ESCB is posted back to the sequencer.
++ * Context is tasklet/IRQ.
++ */
++void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
++{
++ struct asd_seq_data *seq = &ascb->ha->seq;
++ struct empty_scb *escb = &ascb->scb->escb;
++ struct sg_el *eb = &escb->eb[edb_id];
++ struct asd_dma_tok *edb = seq->edb_arr[ascb->edb_index + edb_id];
++
++ memset(edb->vaddr, 0, ASD_EDB_SIZE);
++ eb->flags |= ELEMENT_NOT_VALID;
++ escb->num_valid--;
++
++ if (escb->num_valid == 0) {
++ int i;
++ /* ASD_DPRINTK("reposting escb: vaddr: 0x%p, "
++ "dma_handle: 0x%08llx, next: 0x%08llx, "
++ "index:%d, opcode:0x%02x\n",
++ ascb->dma_scb.vaddr,
++ (u64)ascb->dma_scb.dma_handle,
++ le64_to_cpu(ascb->scb->header.next_scb),
++ le16_to_cpu(ascb->scb->header.index),
++ ascb->scb->header.opcode);
++ */
++ escb->num_valid = ASD_EDBS_PER_SCB;
++ for (i = 0; i < ASD_EDBS_PER_SCB; i++)
++ escb->eb[i].flags = 0;
++ if (!list_empty(&ascb->list))
++ list_del_init(&ascb->list);
++ i = asd_post_escb_list(ascb->ha, ascb, 1);
++ if (i)
++ asd_printk("couldn't post escb, err:%d\n", i);
++ }
++}
++
++static void escb_tasklet_complete(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
++ int edb = (dl->opcode & DL_PHY_MASK) - 1; /* [0xc1,0xc7] -> [0,6] */
++ u8 sb_opcode = dl->status_block[0];
++ int phy_id = sb_opcode & DL_PHY_MASK;
++ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
++
++ if (edb > 6 || edb < 0) {
++ ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
++ edb, dl->opcode);
++ ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
++ sb_opcode, phy_id);
++ ASD_DPRINTK("escb: vaddr: 0x%p, "
++ "dma_handle: 0x%llx, next: 0x%llx, "
++ "index:%d, opcode:0x%02x\n",
++ ascb->dma_scb.vaddr,
++ (unsigned long long)ascb->dma_scb.dma_handle,
++ (unsigned long long)
++ le64_to_cpu(ascb->scb->header.next_scb),
++ le16_to_cpu(ascb->scb->header.index),
++ ascb->scb->header.opcode);
++ }
++
++ sb_opcode &= ~DL_PHY_MASK;
++
++ switch (sb_opcode) {
++ case BYTES_DMAED:
++ ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
++ asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
++ break;
++ case PRIMITIVE_RECVD:
++ ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
++ phy_id);
++ asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
++ break;
++ case PHY_EVENT:
++ ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
++ asd_phy_event_tasklet(ascb, dl);
++ break;
++ case LINK_RESET_ERROR:
++ ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
++ phy_id);
++ asd_link_reset_err_tasklet(ascb, dl, phy_id);
++ break;
++ case TIMER_EVENT:
++ ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
++ __FUNCTION__, phy_id);
++ asd_turn_led(asd_ha, phy_id, 0);
++ /* the device is gone */
++ sas_phy_disconnected(sas_phy);
++ sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
++ break;
++ case REQ_TASK_ABORT:
++ ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
++ phy_id);
++ break;
++ case REQ_DEVICE_RESET:
++ ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
++ phy_id);
++ break;
++ case SIGNAL_NCQ_ERROR:
++ ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
++ phy_id);
++ break;
++ case CLEAR_NCQ_ERROR:
++ ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
++ phy_id);
++ break;
++ default:
++ ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
++ phy_id, sb_opcode);
++ ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
++ edb, dl->opcode);
++ ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
++ sb_opcode, phy_id);
++ ASD_DPRINTK("escb: vaddr: 0x%p, "
++ "dma_handle: 0x%llx, next: 0x%llx, "
++ "index:%d, opcode:0x%02x\n",
++ ascb->dma_scb.vaddr,
++ (unsigned long long)ascb->dma_scb.dma_handle,
++ (unsigned long long)
++ le64_to_cpu(ascb->scb->header.next_scb),
++ le16_to_cpu(ascb->scb->header.index),
++ ascb->scb->header.opcode);
++
++ break;
++ }
++
++ asd_invalidate_edb(ascb, edb);
++}
++
++int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
++{
++ struct asd_seq_data *seq = &asd_ha->seq;
++ int i;
++
++ for (i = 0; i < seq->num_escbs; i++)
++ seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete;
++
++ ASD_DPRINTK("posting %d escbs\n", i);
++ return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs);
++}
++
++/* ---------- CONTROL PHY ---------- */
++
++#define CONTROL_PHY_STATUS (CURRENT_DEVICE_PRESENT | CURRENT_OOB_DONE \
++ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
++ | CURRENT_OOB_ERROR)
++
++/**
++ * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb
++ * @ascb: pointer to an ascb
++ * @dl: pointer to the done list entry
++ *
++ * This function completes a CONTROL PHY scb and frees the ascb.
++ * A note on LEDs:
++ * - an LED blinks if there is IO though it,
++ * - if a device is connected to the LED, it is lit,
++ * - if no device is connected to the LED, is is dimmed (off).
++ */
++static void control_phy_tasklet_complete(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct scb *scb = ascb->scb;
++ struct control_phy *control_phy = &scb->control_phy;
++ u8 phy_id = control_phy->phy_id;
++ struct asd_phy *phy = &ascb->ha->phys[phy_id];
++
++ u8 status = dl->status_block[0];
++ u8 oob_status = dl->status_block[1];
++ u8 oob_mode = dl->status_block[2];
++ /* u8 oob_signals= dl->status_block[3]; */
++
++ if (status != 0) {
++ ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
++ __FUNCTION__, phy_id, status);
++ goto out;
++ }
++
++ switch (control_phy->sub_func) {
++ case DISABLE_PHY:
++ asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
++ asd_turn_led(asd_ha, phy_id, 0);
++ asd_control_led(asd_ha, phy_id, 0);
++ ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
++ break;
++
++ case ENABLE_PHY:
++ asd_control_led(asd_ha, phy_id, 1);
++ if (oob_status & CURRENT_OOB_DONE) {
++ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
++ get_lrate_mode(phy, oob_mode);
++ asd_turn_led(asd_ha, phy_id, 1);
++ ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
++ __FUNCTION__, phy_id,phy->sas_phy.linkrate,
++ phy->sas_phy.iproto);
++ } else if (oob_status & CURRENT_SPINUP_HOLD) {
++ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
++ asd_turn_led(asd_ha, phy_id, 1);
++ ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
++ phy_id);
++ } else if (oob_status & CURRENT_ERR_MASK) {
++ asd_turn_led(asd_ha, phy_id, 0);
++ ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
++ __FUNCTION__, phy_id, oob_status);
++ } else if (oob_status & (CURRENT_HOT_PLUG_CNCT
++ | CURRENT_DEVICE_PRESENT)) {
++ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
++ asd_turn_led(asd_ha, phy_id, 1);
++ ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
++ __FUNCTION__, phy_id);
++ } else {
++ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
++ asd_turn_led(asd_ha, phy_id, 0);
++ ASD_DPRINTK("%s: phy%d: no device present: "
++ "oob_status:0x%x\n",
++ __FUNCTION__, phy_id, oob_status);
++ }
++ break;
++ case RELEASE_SPINUP_HOLD:
++ case PHY_NO_OP:
++ case EXECUTE_HARD_RESET:
++ ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
++ phy_id, control_phy->sub_func);
++ /* XXX finish */
++ break;
++ default:
++ ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
++ phy_id, control_phy->sub_func);
++ break;
++ }
++out:
++ asd_ascb_free(ascb);
++}
++
++static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
++{
++ /* disable all speeds, then enable defaults */
++ *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS
++ | SATA_SPEED_30_DIS | SATA_SPEED_15_DIS;
++
++ switch (pd->max_sas_lrate) {
++ case SAS_LINK_RATE_6_0_GBPS:
++ *speed_mask &= ~SAS_SPEED_60_DIS;
++ default:
++ case SAS_LINK_RATE_3_0_GBPS:
++ *speed_mask &= ~SAS_SPEED_30_DIS;
++ case SAS_LINK_RATE_1_5_GBPS:
++ *speed_mask &= ~SAS_SPEED_15_DIS;
++ }
++
++ switch (pd->min_sas_lrate) {
++ case SAS_LINK_RATE_6_0_GBPS:
++ *speed_mask |= SAS_SPEED_30_DIS;
++ case SAS_LINK_RATE_3_0_GBPS:
++ *speed_mask |= SAS_SPEED_15_DIS;
++ default:
++ case SAS_LINK_RATE_1_5_GBPS:
++ /* nothing to do */
++ ;
++ }
++
++ switch (pd->max_sata_lrate) {
++ case SAS_LINK_RATE_3_0_GBPS:
++ *speed_mask &= ~SATA_SPEED_30_DIS;
++ default:
++ case SAS_LINK_RATE_1_5_GBPS:
++ *speed_mask &= ~SATA_SPEED_15_DIS;
++ }
++
++ switch (pd->min_sata_lrate) {
++ case SAS_LINK_RATE_3_0_GBPS:
++ *speed_mask |= SATA_SPEED_15_DIS;
++ default:
++ case SAS_LINK_RATE_1_5_GBPS:
++ /* nothing to do */
++ ;
++ }
++}
++
++/**
++ * asd_build_control_phy -- build a CONTROL PHY SCB
++ * @ascb: pointer to an ascb
++ * @phy_id: phy id to control, integer
++ * @subfunc: subfunction, what to actually to do the phy
++ *
++ * This function builds a CONTROL PHY scb. No allocation of any kind
++ * is performed. @ascb is allocated with the list function.
++ * The caller can override the ascb->tasklet_complete to point
++ * to its own callback function. It must call asd_ascb_free()
++ * at its tasklet complete function.
++ * See the default implementation.
++ */
++void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
++{
++ struct asd_phy *phy = &ascb->ha->phys[phy_id];
++ struct scb *scb = ascb->scb;
++ struct control_phy *control_phy = &scb->control_phy;
++
++ scb->header.opcode = CONTROL_PHY;
++ control_phy->phy_id = (u8) phy_id;
++ control_phy->sub_func = subfunc;
++
++ switch (subfunc) {
++ case EXECUTE_HARD_RESET: /* 0x81 */
++ case ENABLE_PHY: /* 0x01 */
++ /* decide hot plug delay */
++ control_phy->hot_plug_delay = HOTPLUG_DELAY_TIMEOUT;
++
++ /* decide speed mask */
++ set_speed_mask(&control_phy->speed_mask, phy->phy_desc);
++
++ /* initiator port settings are in the hi nibble */
++ if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
++ control_phy->port_type = SAS_PROTO_ALL << 4;
++ else if (phy->sas_phy.role == PHY_ROLE_TARGET)
++ control_phy->port_type = SAS_PROTO_ALL;
++ else
++ control_phy->port_type =
++ (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
++
++ /* link reset retries, this should be nominal */
++ control_phy->link_reset_retries = 10;
++
++ case RELEASE_SPINUP_HOLD: /* 0x02 */
++ /* decide the func_mask */
++ control_phy->func_mask = FUNCTION_MASK_DEFAULT;
++ if (phy->phy_desc->flags & ASD_SATA_SPINUP_HOLD)
++ control_phy->func_mask &= ~SPINUP_HOLD_DIS;
++ else
++ control_phy->func_mask |= SPINUP_HOLD_DIS;
++ }
++
++ control_phy->conn_handle = cpu_to_le16(0xFFFF);
++
++ ascb->tasklet_complete = control_phy_tasklet_complete;
++}
++
++/* ---------- INITIATE LINK ADM TASK ---------- */
++
++static void link_adm_tasklet_complete(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ u8 opcode = dl->opcode;
++ struct initiate_link_adm *link_adm = &ascb->scb->link_adm;
++ u8 phy_id = link_adm->phy_id;
++
++ if (opcode != TC_NO_ERROR) {
++ asd_printk("phy%d: link adm task 0x%x completed with error "
++ "0x%x\n", phy_id, link_adm->sub_func, opcode);
++ }
++ ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n",
++ phy_id, link_adm->sub_func, opcode);
++
++ asd_ascb_free(ascb);
++}
++
++void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
++ u8 subfunc)
++{
++ struct scb *scb = ascb->scb;
++ struct initiate_link_adm *link_adm = &scb->link_adm;
++
++ scb->header.opcode = INITIATE_LINK_ADM_TASK;
++
++ link_adm->phy_id = phy_id;
++ link_adm->sub_func = subfunc;
++ link_adm->conn_handle = cpu_to_le16(0xFFFF);
++
++ ascb->tasklet_complete = link_adm_tasklet_complete;
++}
++
++/* ---------- SCB timer ---------- */
++
++/**
++ * asd_ascb_timedout -- called when a pending SCB's timer has expired
++ * @data: unsigned long, a pointer to the ascb in question
++ *
++ * This is the default timeout function which does the most necessary.
++ * Upper layers can implement their own timeout function, say to free
++ * resources they have with this SCB, and then call this one at the
++ * end of their timeout function. To do this, one should initialize
++ * the ascb->timer.{function, data, expires} prior to calling the post
++ * funcion. The timer is started by the post function.
++ */
++void asd_ascb_timedout(unsigned long data)
++{
++ struct asd_ascb *ascb = (void *) data;
++ struct asd_seq_data *seq = &ascb->ha->seq;
++ unsigned long flags;
++
++ ASD_DPRINTK("scb:0x%x timed out\n", ascb->scb->header.opcode);
++
++ spin_lock_irqsave(&seq->pend_q_lock, flags);
++ seq->pending--;
++ list_del_init(&ascb->list);
++ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
++
++ asd_ascb_free(ascb);
++}
++
++/* ---------- CONTROL PHY ---------- */
++
++/* Given the spec value, return a driver value. */
++static const int phy_func_table[] = {
++ [PHY_FUNC_NOP] = PHY_NO_OP,
++ [PHY_FUNC_LINK_RESET] = ENABLE_PHY,
++ [PHY_FUNC_HARD_RESET] = EXECUTE_HARD_RESET,
++ [PHY_FUNC_DISABLE] = DISABLE_PHY,
++ [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD,
++};
++
++int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg)
++{
++ struct asd_ha_struct *asd_ha = phy->ha->lldd_ha;
++ struct asd_phy_desc *pd = asd_ha->phys[phy->id].phy_desc;
++ struct asd_ascb *ascb;
++ struct sas_phy_linkrates *rates;
++ int res = 1;
++
++ switch (func) {
++ case PHY_FUNC_CLEAR_ERROR_LOG:
++ return -ENOSYS;
++ case PHY_FUNC_SET_LINK_RATE:
++ rates = arg;
++ if (rates->minimum_linkrate) {
++ pd->min_sas_lrate = rates->minimum_linkrate;
++ pd->min_sata_lrate = rates->minimum_linkrate;
++ }
++ if (rates->maximum_linkrate) {
++ pd->max_sas_lrate = rates->maximum_linkrate;
++ pd->max_sata_lrate = rates->maximum_linkrate;
++ }
++ func = PHY_FUNC_LINK_RESET;
++ break;
++ default:
++ break;
++ }
++
++ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
++ if (!ascb)
++ return -ENOMEM;
++
++ asd_build_control_phy(ascb, phy->id, phy_func_table[func]);
++ res = asd_post_ascb_list(asd_ha, ascb , 1);
++ if (res)
++ asd_ascb_free(ascb);
++
++ return res;
++}
+diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
+new file mode 100644
+index 0000000..de7c04d
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_sds.c
+@@ -0,0 +1,1085 @@
++/*
++ * Aic94xx SAS/SATA driver access to shared data structures and memory
++ * maps.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/pci.h>
++#include <linux/delay.h>
++
++#include "aic94xx.h"
++#include "aic94xx_reg.h"
++
++/* ---------- OCM stuff ---------- */
++
++struct asd_ocm_dir_ent {
++ u8 type;
++ u8 offs[3];
++ u8 _r1;
++ u8 size[3];
++} __attribute__ ((packed));
++
++struct asd_ocm_dir {
++ char sig[2];
++ u8 _r1[2];
++ u8 major; /* 0 */
++ u8 minor; /* 0 */
++ u8 _r2;
++ u8 num_de;
++ struct asd_ocm_dir_ent entry[15];
++} __attribute__ ((packed));
++
++#define OCM_DE_OCM_DIR 0x00
++#define OCM_DE_WIN_DRVR 0x01
++#define OCM_DE_BIOS_CHIM 0x02
++#define OCM_DE_RAID_ENGN 0x03
++#define OCM_DE_BIOS_INTL 0x04
++#define OCM_DE_BIOS_CHIM_OSM 0x05
++#define OCM_DE_BIOS_CHIM_DYNAMIC 0x06
++#define OCM_DE_ADDC2C_RES0 0x07
++#define OCM_DE_ADDC2C_RES1 0x08
++#define OCM_DE_ADDC2C_RES2 0x09
++#define OCM_DE_ADDC2C_RES3 0x0A
++
++#define OCM_INIT_DIR_ENTRIES 5
++/***************************************************************************
++* OCM dircetory default
++***************************************************************************/
++static struct asd_ocm_dir OCMDirInit =
++{
++ .sig = {0x4D, 0x4F}, /* signature */
++ .num_de = OCM_INIT_DIR_ENTRIES, /* no. of directory entries */
++};
++
++/***************************************************************************
++* OCM dircetory Entries default
++***************************************************************************/
++static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
++{
++ {
++ .type = (OCM_DE_ADDC2C_RES0), /* Entry type */
++ .offs = {128}, /* Offset */
++ .size = {0, 4}, /* size */
++ },
++ {
++ .type = (OCM_DE_ADDC2C_RES1), /* Entry type */
++ .offs = {128, 4}, /* Offset */
++ .size = {0, 4}, /* size */
++ },
++ {
++ .type = (OCM_DE_ADDC2C_RES2), /* Entry type */
++ .offs = {128, 8}, /* Offset */
++ .size = {0, 4}, /* size */
++ },
++ {
++ .type = (OCM_DE_ADDC2C_RES3), /* Entry type */
++ .offs = {128, 12}, /* Offset */
++ .size = {0, 4}, /* size */
++ },
++ {
++ .type = (OCM_DE_WIN_DRVR), /* Entry type */
++ .offs = {128, 16}, /* Offset */
++ .size = {128, 235, 1}, /* size */
++ },
++};
++
++struct asd_bios_chim_struct {
++ char sig[4];
++ u8 major; /* 1 */
++ u8 minor; /* 0 */
++ u8 bios_major;
++ u8 bios_minor;
++ __le32 bios_build;
++ u8 flags;
++ u8 pci_slot;
++ __le16 ue_num;
++ __le16 ue_size;
++ u8 _r[14];
++ /* The unit element array is right here.
++ */
++} __attribute__ ((packed));
++
++/**
++ * asd_read_ocm_seg - read an on chip memory (OCM) segment
++ * @asd_ha: pointer to the host adapter structure
++ * @buffer: where to write the read data
++ * @offs: offset into OCM where to read from
++ * @size: how many bytes to read
++ *
++ * Return the number of bytes not read. Return 0 on success.
++ */
++static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
++ u32 offs, int size)
++{
++ u8 *p = buffer;
++ if (unlikely(asd_ha->iospace))
++ asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
++ else {
++ for ( ; size > 0; size--, offs++, p++)
++ *p = asd_read_ocm_byte(asd_ha, offs);
++ }
++ return size;
++}
++
++static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,
++ struct asd_ocm_dir *dir, u32 offs)
++{
++ int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));
++ if (err) {
++ ASD_DPRINTK("couldn't read ocm segment\n");
++ return err;
++ }
++
++ if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {
++ ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",
++ dir->sig[0], dir->sig[1]);
++ return -ENOENT;
++ }
++ if (dir->major != 0) {
++ asd_printk("unsupported major version of ocm dir:0x%x\n",
++ dir->major);
++ return -ENOENT;
++ }
++ dir->num_de &= 0xf;
++ return 0;
++}
++
++/**
++ * asd_write_ocm_seg - write an on chip memory (OCM) segment
++ * @asd_ha: pointer to the host adapter structure
++ * @buffer: where to read the write data
++ * @offs: offset into OCM to write to
++ * @size: how many bytes to write
++ *
++ * Return the number of bytes not written. Return 0 on success.
++ */
++static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
++ u32 offs, int size)
++{
++ u8 *p = buffer;
++ if (unlikely(asd_ha->iospace))
++ asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
++ else {
++ for ( ; size > 0; size--, offs++, p++)
++ asd_write_ocm_byte(asd_ha, offs, *p);
++ }
++ return;
++}
++
++#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))
++
++static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,
++ u32 *offs, u32 *size)
++{
++ int i;
++ struct asd_ocm_dir_ent *ent;
++
++ for (i = 0; i < dir->num_de; i++) {
++ if (dir->entry[i].type == type)
++ break;
++ }
++ if (i >= dir->num_de)
++ return -ENOENT;
++ ent = &dir->entry[i];
++ *offs = (u32) THREE_TO_NUM(ent->offs);
++ *size = (u32) THREE_TO_NUM(ent->size);
++ return 0;
++}
++
++#define OCM_BIOS_CHIM_DE 2
++#define BC_BIOS_PRESENT 1
++
++static int asd_get_bios_chim(struct asd_ha_struct *asd_ha,
++ struct asd_ocm_dir *dir)
++{
++ int err;
++ struct asd_bios_chim_struct *bc_struct;
++ u32 offs, size;
++
++ err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);
++ if (err) {
++ ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");
++ goto out;
++ }
++ err = -ENOMEM;
++ bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);
++ if (!bc_struct) {
++ asd_printk("no memory for bios_chim struct\n");
++ goto out;
++ }
++ err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,
++ sizeof(*bc_struct));
++ if (err) {
++ ASD_DPRINTK("couldn't read ocm segment\n");
++ goto out2;
++ }
++ if (strncmp(bc_struct->sig, "SOIB", 4)
++ && strncmp(bc_struct->sig, "IPSA", 4)) {
++ ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",
++ bc_struct->sig[0], bc_struct->sig[1],
++ bc_struct->sig[2], bc_struct->sig[3]);
++ err = -ENOENT;
++ goto out2;
++ }
++ if (bc_struct->major != 1) {
++ asd_printk("BIOS_CHIM unsupported major version:0x%x\n",
++ bc_struct->major);
++ err = -ENOENT;
++ goto out2;
++ }
++ if (bc_struct->flags & BC_BIOS_PRESENT) {
++ asd_ha->hw_prof.bios.present = 1;
++ asd_ha->hw_prof.bios.maj = bc_struct->bios_major;
++ asd_ha->hw_prof.bios.min = bc_struct->bios_minor;
++ asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);
++ ASD_DPRINTK("BIOS present (%d,%d), %d\n",
++ asd_ha->hw_prof.bios.maj,
++ asd_ha->hw_prof.bios.min,
++ asd_ha->hw_prof.bios.bld);
++ }
++ asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);
++ asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);
++ ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,
++ asd_ha->hw_prof.ue.size);
++ size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;
++ if (size > 0) {
++ err = -ENOMEM;
++ asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);
++ if (!asd_ha->hw_prof.ue.area)
++ goto out2;
++ err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,
++ offs + sizeof(*bc_struct), size);
++ if (err) {
++ kfree(asd_ha->hw_prof.ue.area);
++ asd_ha->hw_prof.ue.area = NULL;
++ asd_ha->hw_prof.ue.num = 0;
++ asd_ha->hw_prof.ue.size = 0;
++ ASD_DPRINTK("couldn't read ue entries(%d)\n", err);
++ }
++ }
++out2:
++ kfree(bc_struct);
++out:
++ return err;
++}
++
++static void
++asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha)
++{
++ int i;
++
++ /* Zero OCM */
++ for (i = 0; i < OCM_MAX_SIZE; i += 4)
++ asd_write_ocm_dword(asd_ha, i, 0);
++
++ /* Write Dir */
++ asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,
++ sizeof(struct asd_ocm_dir));
++
++ /* Write Dir Entries */
++ for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)
++ asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],
++ sizeof(struct asd_ocm_dir) +
++ (i * sizeof(struct asd_ocm_dir_ent))
++ , sizeof(struct asd_ocm_dir_ent));
++
++}
++
++static int
++asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha)
++{
++ struct pci_dev *pcidev = asd_ha->pcidev;
++ u32 reg;
++ int err = 0;
++ u32 v;
++
++ /* check if OCM has been initialized by BIOS */
++ reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
++
++ if (!(reg & OCMINITIALIZED)) {
++ err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);
++ if (err) {
++ asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",
++ pci_name(pcidev));
++ goto out;
++ }
++
++ printk(KERN_INFO "OCM is not initialized by BIOS,"
++ "reinitialize it and ignore it, current IntrptStatus"
++ "is 0x%x\n", v);
++
++ if (v)
++ err = pci_write_config_dword(pcidev,
++ PCIC_INTRPT_STAT, v);
++ if (err) {
++ asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",
++ pci_name(pcidev));
++ goto out;
++ }
++
++ asd_hwi_initialize_ocm_dir(asd_ha);
++
++ }
++out:
++ return err;
++}
++
++/**
++ * asd_read_ocm - read on chip memory (OCM)
++ * @asd_ha: pointer to the host adapter structure
++ */
++int asd_read_ocm(struct asd_ha_struct *asd_ha)
++{
++ int err;
++ struct asd_ocm_dir *dir;
++
++ if (asd_hwi_check_ocm_access(asd_ha))
++ return -1;
++
++ dir = kmalloc(sizeof(*dir), GFP_KERNEL);
++ if (!dir) {
++ asd_printk("no memory for ocm dir\n");
++ return -ENOMEM;
++ }
++
++ err = asd_read_ocm_dir(asd_ha, dir, 0);
++ if (err)
++ goto out;
++
++ err = asd_get_bios_chim(asd_ha, dir);
++out:
++ kfree(dir);
++ return err;
++}
++
++/* ---------- FLASH stuff ---------- */
++
++#define FLASH_RESET 0xF0
++
++#define FLASH_SIZE 0x200000
++#define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** "
++#define FLASH_NEXT_ENTRY_OFFS 0x2000
++#define FLASH_MAX_DIR_ENTRIES 32
++
++#define FLASH_DE_TYPE_MASK 0x3FFFFFFF
++#define FLASH_DE_MS 0x120
++#define FLASH_DE_CTRL_A_USER 0xE0
++
++struct asd_flash_de {
++ __le32 type;
++ __le32 offs;
++ __le32 pad_size;
++ __le32 image_size;
++ __le32 chksum;
++ u8 _r[12];
++ u8 version[32];
++} __attribute__ ((packed));
++
++struct asd_flash_dir {
++ u8 cookie[32];
++ __le32 rev; /* 2 */
++ __le32 chksum;
++ __le32 chksum_antidote;
++ __le32 bld;
++ u8 bld_id[32]; /* build id data */
++ u8 ver_data[32]; /* date and time of build */
++ __le32 ae_mask;
++ __le32 v_mask;
++ __le32 oc_mask;
++ u8 _r[20];
++ struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];
++} __attribute__ ((packed));
++
++struct asd_manuf_sec {
++ char sig[2]; /* 'S', 'M' */
++ u16 offs_next;
++ u8 maj; /* 0 */
++ u8 min; /* 0 */
++ u16 chksum;
++ u16 size;
++ u8 _r[6];
++ u8 sas_addr[SAS_ADDR_SIZE];
++ u8 pcba_sn[ASD_PCBA_SN_SIZE];
++ /* Here start the other segments */
++ u8 linked_list[0];
++} __attribute__ ((packed));
++
++struct asd_manuf_phy_desc {
++ u8 state; /* low 4 bits */
++#define MS_PHY_STATE_ENABLEABLE 0
++#define MS_PHY_STATE_REPORTED 1
++#define MS_PHY_STATE_HIDDEN 2
++ u8 phy_id;
++ u16 _r;
++ u8 phy_control_0; /* mode 5 reg 0x160 */
++ u8 phy_control_1; /* mode 5 reg 0x161 */
++ u8 phy_control_2; /* mode 5 reg 0x162 */
++ u8 phy_control_3; /* mode 5 reg 0x163 */
++} __attribute__ ((packed));
++
++struct asd_manuf_phy_param {
++ char sig[2]; /* 'P', 'M' */
++ u16 next;
++ u8 maj; /* 0 */
++ u8 min; /* 2 */
++ u8 num_phy_desc; /* 8 */
++ u8 phy_desc_size; /* 8 */
++ u8 _r[3];
++ u8 usage_model_id;
++ u32 _r2;
++ struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];
++} __attribute__ ((packed));
++
++#if 0
++static const char *asd_sb_type[] = {
++ "unknown",
++ "SGPIO",
++ [2 ... 0x7F] = "unknown",
++ [0x80] = "ADPT_I2C",
++ [0x81 ... 0xFF] = "VENDOR_UNIQUExx"
++};
++#endif
++
++struct asd_ms_sb_desc {
++ u8 type;
++ u8 node_desc_index;
++ u8 conn_desc_index;
++ u8 _recvd[0];
++} __attribute__ ((packed));
++
++#if 0
++static const char *asd_conn_type[] = {
++ [0 ... 7] = "unknown",
++ "SFF8470",
++ "SFF8482",
++ "SFF8484",
++ [0x80] = "PCIX_DAUGHTER0",
++ [0x81] = "SAS_DAUGHTER0",
++ [0x82 ... 0xFF] = "VENDOR_UNIQUExx"
++};
++
++static const char *asd_conn_location[] = {
++ "unknown",
++ "internal",
++ "external",
++ "board_to_board",
++};
++#endif
++
++struct asd_ms_conn_desc {
++ u8 type;
++ u8 location;
++ u8 num_sideband_desc;
++ u8 size_sideband_desc;
++ u32 _resvd;
++ u8 name[16];
++ struct asd_ms_sb_desc sb_desc[0];
++} __attribute__ ((packed));
++
++struct asd_nd_phy_desc {
++ u8 vp_attch_type;
++ u8 attch_specific[0];
++} __attribute__ ((packed));
++
++#if 0
++static const char *asd_node_type[] = {
++ "IOP",
++ "IO_CONTROLLER",
++ "EXPANDER",
++ "PORT_MULTIPLIER",
++ "PORT_MULTIPLEXER",
++ "MULTI_DROP_I2C_BUS",
++};
++#endif
++
++struct asd_ms_node_desc {
++ u8 type;
++ u8 num_phy_desc;
++ u8 size_phy_desc;
++ u8 _resvd;
++ u8 name[16];
++ struct asd_nd_phy_desc phy_desc[0];
++} __attribute__ ((packed));
++
++struct asd_ms_conn_map {
++ char sig[2]; /* 'M', 'C' */
++ __le16 next;
++ u8 maj; /* 0 */
++ u8 min; /* 0 */
++ __le16 cm_size; /* size of this struct */
++ u8 num_conn;
++ u8 conn_size;
++ u8 num_nodes;
++ u8 usage_model_id;
++ u32 _resvd;
++ struct asd_ms_conn_desc conn_desc[0];
++ struct asd_ms_node_desc node_desc[0];
++} __attribute__ ((packed));
++
++struct asd_ctrla_phy_entry {
++ u8 sas_addr[SAS_ADDR_SIZE];
++ u8 sas_link_rates; /* max in hi bits, min in low bits */
++ u8 flags;
++ u8 sata_link_rates;
++ u8 _r[5];
++} __attribute__ ((packed));
++
++struct asd_ctrla_phy_settings {
++ u8 id0; /* P'h'y */
++ u8 _r;
++ u16 next;
++ u8 num_phys; /* number of PHYs in the PCI function */
++ u8 _r2[3];
++ struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS];
++} __attribute__ ((packed));
++
++struct asd_ll_el {
++ u8 id0;
++ u8 id1;
++ __le16 next;
++ u8 something_here[0];
++} __attribute__ ((packed));
++
++static int asd_poll_flash(struct asd_ha_struct *asd_ha)
++{
++ int c;
++ u8 d;
++
++ for (c = 5000; c > 0; c--) {
++ d = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
++ d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
++ if (!d)
++ return 0;
++ udelay(5);
++ }
++ return -ENOENT;
++}
++
++static int asd_reset_flash(struct asd_ha_struct *asd_ha)
++{
++ int err;
++
++ err = asd_poll_flash(asd_ha);
++ if (err)
++ return err;
++ asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET);
++ err = asd_poll_flash(asd_ha);
++
++ return err;
++}
++
++static inline int asd_read_flash_seg(struct asd_ha_struct *asd_ha,
++ void *buffer, u32 offs, int size)
++{
++ asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs,
++ size);
++ return 0;
++}
++
++/**
++ * asd_find_flash_dir - finds and reads the flash directory
++ * @asd_ha: pointer to the host adapter structure
++ * @flash_dir: pointer to flash directory structure
++ *
++ * If found, the flash directory segment will be copied to
++ * @flash_dir. Return 1 if found, 0 if not.
++ */
++static int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
++ struct asd_flash_dir *flash_dir)
++{
++ u32 v;
++ for (v = 0; v < FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
++ asd_read_flash_seg(asd_ha, flash_dir, v,
++ sizeof(FLASH_DIR_COOKIE)-1);
++ if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
++ sizeof(FLASH_DIR_COOKIE)-1) == 0) {
++ asd_ha->hw_prof.flash.dir_offs = v;
++ asd_read_flash_seg(asd_ha, flash_dir, v,
++ sizeof(*flash_dir));
++ return 1;
++ }
++ }
++ return 0;
++}
++
++static int asd_flash_getid(struct asd_ha_struct *asd_ha)
++{
++ int err = 0;
++ u32 reg;
++
++ reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
++
++ if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR,
++ &asd_ha->hw_prof.flash.bar)) {
++ asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n",
++ pci_name(asd_ha->pcidev));
++ return -ENOENT;
++ }
++ asd_ha->hw_prof.flash.present = 1;
++ asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0;
++ err = asd_reset_flash(asd_ha);
++ if (err) {
++ ASD_DPRINTK("couldn't reset flash(%d)\n", err);
++ return err;
++ }
++ return 0;
++}
++
++static u16 asd_calc_flash_chksum(u16 *p, int size)
++{
++ u16 chksum = 0;
++
++ while (size-- > 0)
++ chksum += *p++;
++
++ return chksum;
++}
++
++
++static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type,
++ u32 *offs, u32 *size)
++{
++ int i;
++ struct asd_flash_de *de;
++
++ for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) {
++ u32 type = le32_to_cpu(flash_dir->dir_entry[i].type);
++
++ type &= FLASH_DE_TYPE_MASK;
++ if (type == entry_type)
++ break;
++ }
++ if (i >= FLASH_MAX_DIR_ENTRIES)
++ return -ENOENT;
++ de = &flash_dir->dir_entry[i];
++ *offs = le32_to_cpu(de->offs);
++ *size = le32_to_cpu(de->pad_size);
++ return 0;
++}
++
++static int asd_validate_ms(struct asd_manuf_sec *ms)
++{
++ if (ms->sig[0] != 'S' || ms->sig[1] != 'M') {
++ ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n",
++ ms->sig[0], ms->sig[1]);
++ return -ENOENT;
++ }
++ if (ms->maj != 0) {
++ asd_printk("unsupported manuf. sector. major version:%x\n",
++ ms->maj);
++ return -ENOENT;
++ }
++ ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next);
++ ms->chksum = le16_to_cpu((__force __le16) ms->chksum);
++ ms->size = le16_to_cpu((__force __le16) ms->size);
++
++ if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) {
++ asd_printk("failed manuf sector checksum\n");
++ }
++
++ return 0;
++}
++
++static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha,
++ struct asd_manuf_sec *ms)
++{
++ memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE);
++ return 0;
++}
++
++static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha,
++ struct asd_manuf_sec *ms)
++{
++ memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE);
++ asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0';
++ return 0;
++}
++
++/**
++ * asd_find_ll_by_id - find a linked list entry by its id
++ * @start: void pointer to the first element in the linked list
++ * @id0: the first byte of the id (offs 0)
++ * @id1: the second byte of the id (offs 1)
++ *
++ * @start has to be the _base_ element start, since the
++ * linked list entries's offset is from this pointer.
++ * Some linked list entries use only the first id, in which case
++ * you can pass 0xFF for the second.
++ */
++static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
++{
++ struct asd_ll_el *el = start;
++
++ do {
++ switch (id1) {
++ default:
++ if (el->id1 == id1)
++ case 0xFF:
++ if (el->id0 == id0)
++ return el;
++ }
++ el = start + le16_to_cpu(el->next);
++ } while (el != start);
++
++ return NULL;
++}
++
++/**
++ * asd_ms_get_phy_params - get phy parameters from the manufacturing sector
++ * @asd_ha: pointer to the host adapter structure
++ * @manuf_sec: pointer to the manufacturing sector
++ *
++ * The manufacturing sector contans also the linked list of sub-segments,
++ * since when it was read, its size was taken from the flash directory,
++ * not from the structure size.
++ *
++ * HIDDEN phys do not count in the total count. REPORTED phys cannot
++ * be enabled but are reported and counted towards the total.
++ * ENEBLEABLE phys are enabled by default and count towards the total.
++ * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys
++ * merely specifies the number of phys the host adapter decided to
++ * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
++ * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE.
++ * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
++ * are actually enabled (enabled by default, max number of phys
++ * enableable in this case).
++ */
++static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
++ struct asd_manuf_sec *manuf_sec)
++{
++ int i;
++ int en_phys = 0;
++ int rep_phys = 0;
++ struct asd_manuf_phy_param *phy_param;
++ struct asd_manuf_phy_param dflt_phy_param;
++
++ phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M');
++ if (!phy_param) {
++ ASD_DPRINTK("ms: no phy parameters found\n");
++ ASD_DPRINTK("ms: Creating default phy parameters\n");
++ dflt_phy_param.sig[0] = 'P';
++ dflt_phy_param.sig[1] = 'M';
++ dflt_phy_param.maj = 0;
++ dflt_phy_param.min = 2;
++ dflt_phy_param.num_phy_desc = 8;
++ dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc);
++ for (i =0; i < ASD_MAX_PHYS; i++) {
++ dflt_phy_param.phy_desc[i].state = 0;
++ dflt_phy_param.phy_desc[i].phy_id = i;
++ dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6;
++ dflt_phy_param.phy_desc[i].phy_control_1 = 0x10;
++ dflt_phy_param.phy_desc[i].phy_control_2 = 0x43;
++ dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb;
++ }
++
++ phy_param = &dflt_phy_param;
++
++ }
++
++ if (phy_param->maj != 0) {
++ asd_printk("unsupported manuf. phy param major version:0x%x\n",
++ phy_param->maj);
++ return -ENOENT;
++ }
++
++ ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc);
++ asd_ha->hw_prof.enabled_phys = 0;
++ for (i = 0; i < phy_param->num_phy_desc; i++) {
++ struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i];
++ switch (pd->state & 0xF) {
++ case MS_PHY_STATE_HIDDEN:
++ ASD_DPRINTK("ms: phy%d: HIDDEN\n", i);
++ continue;
++ case MS_PHY_STATE_REPORTED:
++ ASD_DPRINTK("ms: phy%d: REPORTED\n", i);
++ asd_ha->hw_prof.enabled_phys &= ~(1 << i);
++ rep_phys++;
++ continue;
++ case MS_PHY_STATE_ENABLEABLE:
++ ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i);
++ asd_ha->hw_prof.enabled_phys |= (1 << i);
++ en_phys++;
++ break;
++ }
++ asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0;
++ asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1;
++ asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2;
++ asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3;
++ }
++ asd_ha->hw_prof.max_phys = rep_phys + en_phys;
++ asd_ha->hw_prof.num_phys = en_phys;
++ ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n",
++ asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys);
++ ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys);
++ return 0;
++}
++
++static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha,
++ struct asd_manuf_sec *manuf_sec)
++{
++ struct asd_ms_conn_map *cm;
++
++ cm = asd_find_ll_by_id(manuf_sec, 'M', 'C');
++ if (!cm) {
++ ASD_DPRINTK("ms: no connector map found\n");
++ return 0;
++ }
++
++ if (cm->maj != 0) {
++ ASD_DPRINTK("ms: unsupported: connector map major version 0x%x"
++ "\n", cm->maj);
++ return -ENOENT;
++ }
++
++ /* XXX */
++
++ return 0;
++}
++
++
++/**
++ * asd_process_ms - find and extract information from the manufacturing sector
++ * @asd_ha: pointer to the host adapter structure
++ * @flash_dir: pointer to the flash directory
++ */
++static int asd_process_ms(struct asd_ha_struct *asd_ha,
++ struct asd_flash_dir *flash_dir)
++{
++ int err;
++ struct asd_manuf_sec *manuf_sec;
++ u32 offs, size;
++
++ err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size);
++ if (err) {
++ ASD_DPRINTK("Couldn't find the manuf. sector\n");
++ goto out;
++ }
++
++ if (size == 0)
++ goto out;
++
++ err = -ENOMEM;
++ manuf_sec = kmalloc(size, GFP_KERNEL);
++ if (!manuf_sec) {
++ ASD_DPRINTK("no mem for manuf sector\n");
++ goto out;
++ }
++
++ err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size);
++ if (err) {
++ ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n",
++ offs, size);
++ goto out2;
++ }
++
++ err = asd_validate_ms(manuf_sec);
++ if (err) {
++ ASD_DPRINTK("couldn't validate manuf sector\n");
++ goto out2;
++ }
++
++ err = asd_ms_get_sas_addr(asd_ha, manuf_sec);
++ if (err) {
++ ASD_DPRINTK("couldn't read the SAS_ADDR\n");
++ goto out2;
++ }
++ ASD_DPRINTK("manuf sect SAS_ADDR %llx\n",
++ SAS_ADDR(asd_ha->hw_prof.sas_addr));
++
++ err = asd_ms_get_pcba_sn(asd_ha, manuf_sec);
++ if (err) {
++ ASD_DPRINTK("couldn't read the PCBA SN\n");
++ goto out2;
++ }
++ ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn);
++
++ err = asd_ms_get_phy_params(asd_ha, manuf_sec);
++ if (err) {
++ ASD_DPRINTK("ms: couldn't get phy parameters\n");
++ goto out2;
++ }
++
++ err = asd_ms_get_connector_map(asd_ha, manuf_sec);
++ if (err) {
++ ASD_DPRINTK("ms: couldn't get connector map\n");
++ goto out2;
++ }
++
++out2:
++ kfree(manuf_sec);
++out:
++ return err;
++}
++
++static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha,
++ struct asd_ctrla_phy_settings *ps)
++{
++ int i;
++ for (i = 0; i < ps->num_phys; i++) {
++ struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i];
++
++ if (!PHY_ENABLED(asd_ha, i))
++ continue;
++ if (*(u64 *)pe->sas_addr == 0) {
++ asd_ha->hw_prof.enabled_phys &= ~(1 << i);
++ continue;
++ }
++ /* This is the SAS address which should be sent in IDENTIFY. */
++ memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr,
++ SAS_ADDR_SIZE);
++ asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
++ (pe->sas_link_rates & 0xF0) >> 4;
++ asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
++ (pe->sas_link_rates & 0x0F);
++ asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
++ (pe->sata_link_rates & 0xF0) >> 4;
++ asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
++ (pe->sata_link_rates & 0x0F);
++ asd_ha->hw_prof.phy_desc[i].flags = pe->flags;
++ ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x,"
++ " sata rate:0x%x-0x%x, flags:0x%x\n",
++ i,
++ SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr),
++ asd_ha->hw_prof.phy_desc[i].max_sas_lrate,
++ asd_ha->hw_prof.phy_desc[i].min_sas_lrate,
++ asd_ha->hw_prof.phy_desc[i].max_sata_lrate,
++ asd_ha->hw_prof.phy_desc[i].min_sata_lrate,
++ asd_ha->hw_prof.phy_desc[i].flags);
++ }
++
++ return 0;
++}
++
++/**
++ * asd_process_ctrl_a_user - process CTRL-A user settings
++ * @asd_ha: pointer to the host adapter structure
++ * @flash_dir: pointer to the flash directory
++ */
++static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
++ struct asd_flash_dir *flash_dir)
++{
++ int err, i;
++ u32 offs, size;
++ struct asd_ll_el *el;
++ struct asd_ctrla_phy_settings *ps;
++ struct asd_ctrla_phy_settings dflt_ps;
++
++ err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size);
++ if (err) {
++ ASD_DPRINTK("couldn't find CTRL-A user settings section\n");
++ ASD_DPRINTK("Creating default CTRL-A user settings section\n");
++
++ dflt_ps.id0 = 'h';
++ dflt_ps.num_phys = 8;
++ for (i =0; i < ASD_MAX_PHYS; i++) {
++ memcpy(dflt_ps.phy_ent[i].sas_addr,
++ asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
++ dflt_ps.phy_ent[i].sas_link_rates = 0x98;
++ dflt_ps.phy_ent[i].flags = 0x0;
++ dflt_ps.phy_ent[i].sata_link_rates = 0x0;
++ }
++
++ size = sizeof(struct asd_ctrla_phy_settings);
++ ps = &dflt_ps;
++ }
++
++ if (size == 0)
++ goto out;
++
++ err = -ENOMEM;
++ el = kmalloc(size, GFP_KERNEL);
++ if (!el) {
++ ASD_DPRINTK("no mem for ctrla user settings section\n");
++ goto out;
++ }
++
++ err = asd_read_flash_seg(asd_ha, (void *)el, offs, size);
++ if (err) {
++ ASD_DPRINTK("couldn't read ctrla phy settings section\n");
++ goto out2;
++ }
++
++ err = -ENOENT;
++ ps = asd_find_ll_by_id(el, 'h', 0xFF);
++ if (!ps) {
++ ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
++ goto out2;
++ }
++
++ err = asd_process_ctrla_phy_settings(asd_ha, ps);
++ if (err) {
++ ASD_DPRINTK("couldn't process ctrla phy settings\n");
++ goto out2;
++ }
++out2:
++ kfree(el);
++out:
++ return err;
++}
++
++/**
++ * asd_read_flash - read flash memory
++ * @asd_ha: pointer to the host adapter structure
++ */
++int asd_read_flash(struct asd_ha_struct *asd_ha)
++{
++ int err;
++ struct asd_flash_dir *flash_dir;
++
++ err = asd_flash_getid(asd_ha);
++ if (err)
++ return err;
++
++ flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL);
++ if (!flash_dir)
++ return -ENOMEM;
++
++ err = -ENOENT;
++ if (!asd_find_flash_dir(asd_ha, flash_dir)) {
++ ASD_DPRINTK("couldn't find flash directory\n");
++ goto out;
++ }
++
++ if (le32_to_cpu(flash_dir->rev) != 2) {
++ asd_printk("unsupported flash dir version:0x%x\n",
++ le32_to_cpu(flash_dir->rev));
++ goto out;
++ }
++
++ err = asd_process_ms(asd_ha, flash_dir);
++ if (err) {
++ ASD_DPRINTK("couldn't process manuf sector settings\n");
++ goto out;
++ }
++
++ err = asd_process_ctrl_a_user(asd_ha, flash_dir);
++ if (err) {
++ ASD_DPRINTK("couldn't process CTRL-A user settings\n");
++ goto out;
++ }
++
++out:
++ kfree(flash_dir);
++ return err;
++}
+diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
+new file mode 100644
+index 0000000..56e4b3b
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_seq.c
+@@ -0,0 +1,1404 @@
++/*
++ * Aic94xx SAS/SATA driver sequencer interface.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * Parts of this code adapted from David Chaw's adp94xx_seq.c.
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/module.h>
++#include <linux/firmware.h>
++#include "aic94xx_reg.h"
++#include "aic94xx_hwi.h"
++
++#include "aic94xx_seq.h"
++#include "aic94xx_dump.h"
++
++/* It takes no more than 0.05 us for an instruction
++ * to complete. So waiting for 1 us should be more than
++ * plenty.
++ */
++#define PAUSE_DELAY 1
++#define PAUSE_TRIES 1000
++
++static const struct firmware *sequencer_fw;
++static const char *sequencer_version;
++static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task,
++ cseq_idle_loop, lseq_idle_loop;
++static u8 *cseq_code, *lseq_code;
++static u32 cseq_code_size, lseq_code_size;
++
++static u16 first_scb_site_no = 0xFFFF;
++static u16 last_scb_site_no;
++
++/* ---------- Pause/Unpause CSEQ/LSEQ ---------- */
++
++/**
++ * asd_pause_cseq - pause the central sequencer
++ * @asd_ha: pointer to host adapter structure
++ *
++ * Return 0 on success, negative on failure.
++ */
++int asd_pause_cseq(struct asd_ha_struct *asd_ha)
++{
++ int count = PAUSE_TRIES;
++ u32 arp2ctl;
++
++ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
++ if (arp2ctl & PAUSED)
++ return 0;
++
++ asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE);
++ do {
++ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
++ if (arp2ctl & PAUSED)
++ return 0;
++ udelay(PAUSE_DELAY);
++ } while (--count > 0);
++
++ ASD_DPRINTK("couldn't pause CSEQ\n");
++ return -1;
++}
++
++/**
++ * asd_unpause_cseq - unpause the central sequencer.
++ * @asd_ha: pointer to host adapter structure.
++ *
++ * Return 0 on success, negative on error.
++ */
++int asd_unpause_cseq(struct asd_ha_struct *asd_ha)
++{
++ u32 arp2ctl;
++ int count = PAUSE_TRIES;
++
++ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
++ if (!(arp2ctl & PAUSED))
++ return 0;
++
++ asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE);
++ do {
++ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
++ if (!(arp2ctl & PAUSED))
++ return 0;
++ udelay(PAUSE_DELAY);
++ } while (--count > 0);
++
++ ASD_DPRINTK("couldn't unpause the CSEQ\n");
++ return -1;
++}
++
++/**
++ * asd_seq_pause_lseq - pause a link sequencer
++ * @asd_ha: pointer to a host adapter structure
++ * @lseq: link sequencer of interest
++ *
++ * Return 0 on success, negative on error.
++ */
++static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq)
++{
++ u32 arp2ctl;
++ int count = PAUSE_TRIES;
++
++ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
++ if (arp2ctl & PAUSED)
++ return 0;
++
++ asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE);
++ do {
++ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
++ if (arp2ctl & PAUSED)
++ return 0;
++ udelay(PAUSE_DELAY);
++ } while (--count > 0);
++
++ ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq);
++ return -1;
++}
++
++/**
++ * asd_pause_lseq - pause the link sequencer(s)
++ * @asd_ha: pointer to host adapter structure
++ * @lseq_mask: mask of link sequencers of interest
++ *
++ * Return 0 on success, negative on failure.
++ */
++int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
++{
++ int lseq;
++ int err = 0;
++
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ err = asd_seq_pause_lseq(asd_ha, lseq);
++ if (err)
++ return err;
++ }
++
++ return err;
++}
++
++/**
++ * asd_seq_unpause_lseq - unpause a link sequencer
++ * @asd_ha: pointer to host adapter structure
++ * @lseq: link sequencer of interest
++ *
++ * Return 0 on success, negative on error.
++ */
++static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq)
++{
++ u32 arp2ctl;
++ int count = PAUSE_TRIES;
++
++ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
++ if (!(arp2ctl & PAUSED))
++ return 0;
++
++ asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE);
++ do {
++ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
++ if (!(arp2ctl & PAUSED))
++ return 0;
++ udelay(PAUSE_DELAY);
++ } while (--count > 0);
++
++ ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq);
++ return 0;
++}
++
++
++/**
++ * asd_unpause_lseq - unpause the link sequencer(s)
++ * @asd_ha: pointer to host adapter structure
++ * @lseq_mask: mask of link sequencers of interest
++ *
++ * Return 0 on success, negative on failure.
++ */
++int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
++{
++ int lseq;
++ int err = 0;
++
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ err = asd_seq_unpause_lseq(asd_ha, lseq);
++ if (err)
++ return err;
++ }
++
++ return err;
++}
++
++/* ---------- Downloading CSEQ/LSEQ microcode ---------- */
++
++static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
++ u32 size)
++{
++ u32 addr = CSEQ_RAM_REG_BASE_ADR;
++ const u32 *prog = (u32 *) _prog;
++ u32 i;
++
++ for (i = 0; i < size; i += 4, prog++, addr += 4) {
++ u32 val = asd_read_reg_dword(asd_ha, addr);
++
++ if (le32_to_cpu(*prog) != val) {
++ asd_printk("%s: cseq verify failed at %u "
++ "read:0x%x, wanted:0x%x\n",
++ pci_name(asd_ha->pcidev),
++ i, val, le32_to_cpu(*prog));
++ return -1;
++ }
++ }
++ ASD_DPRINTK("verified %d bytes, passed\n", size);
++ return 0;
++}
++
++/**
++ * asd_verify_lseq - verify the microcode of a link sequencer
++ * @asd_ha: pointer to host adapter structure
++ * @_prog: pointer to the microcode
++ * @size: size of the microcode in bytes
++ * @lseq: link sequencer of interest
++ *
++ * The link sequencer code is accessed in 4 KB pages, which are selected
++ * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register.
++ * The 10 KB LSEQm instruction code is mapped, page at a time, at
++ * LmSEQRAM address.
++ */
++static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
++ u32 size, int lseq)
++{
++#define LSEQ_CODEPAGE_SIZE 4096
++ int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE;
++ u32 page;
++ const u32 *prog = (u32 *) _prog;
++
++ for (page = 0; page < pages; page++) {
++ u32 i;
++
++ asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq),
++ page << LmRAMPAGE_LSHIFT);
++ for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE;
++ i += 4, prog++, size-=4) {
++
++ u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i);
++
++ if (le32_to_cpu(*prog) != val) {
++ asd_printk("%s: LSEQ%d verify failed "
++ "page:%d, offs:%d\n",
++ pci_name(asd_ha->pcidev),
++ lseq, page, i);
++ return -1;
++ }
++ }
++ }
++ ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq,
++ (int)((u8 *)prog-_prog));
++ return 0;
++}
++
++/**
++ * asd_verify_seq -- verify CSEQ/LSEQ microcode
++ * @asd_ha: pointer to host adapter structure
++ * @prog: pointer to microcode
++ * @size: size of the microcode
++ * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest
++ *
++ * Return 0 if microcode is correct, negative on mismatch.
++ */
++static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog,
++ u32 size, u8 lseq_mask)
++{
++ if (lseq_mask == 0)
++ return asd_verify_cseq(asd_ha, prog, size);
++ else {
++ int lseq, err;
++
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ err = asd_verify_lseq(asd_ha, prog, size, lseq);
++ if (err)
++ return err;
++ }
++ }
++
++ return 0;
++}
++#define ASD_DMA_MODE_DOWNLOAD
++#ifdef ASD_DMA_MODE_DOWNLOAD
++/* This is the size of the CSEQ Mapped instruction page */
++#define MAX_DMA_OVLY_COUNT ((1U << 14)-1)
++static int asd_download_seq(struct asd_ha_struct *asd_ha,
++ const u8 * const prog, u32 size, u8 lseq_mask)
++{
++ u32 comstaten;
++ u32 reg;
++ int page;
++ const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT;
++ struct asd_dma_tok *token;
++ int err = 0;
++
++ if (size % 4) {
++ asd_printk("sequencer program not multiple of 4\n");
++ return -1;
++ }
++
++ asd_pause_cseq(asd_ha);
++ asd_pause_lseq(asd_ha, 0xFF);
++
++ /* save, disable and clear interrupts */
++ comstaten = asd_read_reg_dword(asd_ha, COMSTATEN);
++ asd_write_reg_dword(asd_ha, COMSTATEN, 0);
++ asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK);
++
++ asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
++ asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK);
++
++ token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL);
++ if (!token) {
++ asd_printk("out of memory for dma SEQ download\n");
++ err = -ENOMEM;
++ goto out;
++ }
++ ASD_DPRINTK("dma-ing %d bytes\n", size);
++
++ for (page = 0; page < pages; page++) {
++ int i;
++ u32 left = min(size-page*MAX_DMA_OVLY_COUNT,
++ (u32)MAX_DMA_OVLY_COUNT);
++
++ memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left);
++ asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle);
++ asd_write_reg_dword(asd_ha, OVLYDMACNT, left);
++ reg = !page ? RESETOVLYDMA : 0;
++ reg |= (STARTOVLYDMA | OVLYHALTERR);
++ reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
++ /* Start DMA. */
++ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
++
++ for (i = PAUSE_TRIES*100; i > 0; i--) {
++ u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL);
++ if (!(dmadone & OVLYDMAACT))
++ break;
++ udelay(PAUSE_DELAY);
++ }
++ }
++
++ reg = asd_read_reg_dword(asd_ha, COMSTAT);
++ if (!(reg & OVLYDMADONE) || (reg & OVLYERR)
++ || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){
++ asd_printk("%s: error DMA-ing sequencer code\n",
++ pci_name(asd_ha->pcidev));
++ err = -ENODEV;
++ }
++
++ asd_free_coherent(asd_ha, token);
++ out:
++ asd_write_reg_dword(asd_ha, COMSTATEN, comstaten);
++
++ return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask);
++}
++#else /* ASD_DMA_MODE_DOWNLOAD */
++static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog,
++ u32 size, u8 lseq_mask)
++{
++ int i;
++ u32 reg = 0;
++ const u32 *prog = (u32 *) _prog;
++
++ if (size % 4) {
++ asd_printk("sequencer program not multiple of 4\n");
++ return -1;
++ }
++
++ asd_pause_cseq(asd_ha);
++ asd_pause_lseq(asd_ha, 0xFF);
++
++ reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
++ reg |= PIOCMODE;
++
++ asd_write_reg_dword(asd_ha, OVLYDMACNT, size);
++ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
++
++ ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n",
++ lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : "");
++
++ for (i = 0; i < size; i += 4, prog++)
++ asd_write_reg_dword(asd_ha, SPIODATA, *prog);
++
++ reg = (reg & ~PIOCMODE) | OVLYHALTERR;
++ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
++
++ return asd_verify_seq(asd_ha, _prog, size, lseq_mask);
++}
++#endif /* ASD_DMA_MODE_DOWNLOAD */
++
++/**
++ * asd_seq_download_seqs - download the sequencer microcode
++ * @asd_ha: pointer to host adapter structure
++ *
++ * Download the central and link sequencer microcode.
++ */
++static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha)
++{
++ int err;
++
++ if (!asd_ha->hw_prof.enabled_phys) {
++ asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev));
++ return -ENODEV;
++ }
++
++ /* Download the CSEQ */
++ ASD_DPRINTK("downloading CSEQ...\n");
++ err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0);
++ if (err) {
++ asd_printk("CSEQ download failed:%d\n", err);
++ return err;
++ }
++
++ /* Download the Link Sequencers code. All of the Link Sequencers
++ * microcode can be downloaded at the same time.
++ */
++ ASD_DPRINTK("downloading LSEQs...\n");
++ err = asd_download_seq(asd_ha, lseq_code, lseq_code_size,
++ asd_ha->hw_prof.enabled_phys);
++ if (err) {
++ /* Try it one at a time */
++ u8 lseq;
++ u8 lseq_mask = asd_ha->hw_prof.enabled_phys;
++
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ err = asd_download_seq(asd_ha, lseq_code,
++ lseq_code_size, 1<<lseq);
++ if (err)
++ break;
++ }
++ }
++ if (err)
++ asd_printk("LSEQs download failed:%d\n", err);
++
++ return err;
++}
++
++/* ---------- Initializing the chip, chip memory, etc. ---------- */
++
++/**
++ * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha)
++{
++ /* CSEQ Mode Independent, page 4 setup. */
++ asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_REG0, 0);
++ asd_write_reg_word(asd_ha, CSEQ_REG1, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_REG2, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0);
++ {
++ u8 con = asd_read_reg_byte(asd_ha, CCONEXIST);
++ u8 val = hweight8(con);
++ asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val);
++ }
++ asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0);
++
++ /* CSEQ Mode independent, page 5 setup. */
++ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0);
++ asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0);
++
++ /* CSEQ Mode independent, page 6 setup. */
++ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0);
++ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0);
++ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0);
++ asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0);
++ asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0);
++ asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF);
++ /* Calculate the free scb mask. */
++ {
++ u16 cmdctx = asd_get_cmdctx_size(asd_ha);
++ cmdctx = (~((cmdctx/128)-1)) >> 8;
++ asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx);
++ }
++ asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD,
++ first_scb_site_no);
++ asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL,
++ last_scb_site_no);
++ asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF);
++
++ /* CSEQ Mode independent, page 7 setup. */
++ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0);
++ asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0);
++ asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0);
++}
++
++/**
++ * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha)
++{
++ int i;
++ int moffs;
++
++ moffs = CSEQ_PAGE_SIZE * 2;
++
++ /* CSEQ Mode dependent, modes 0-7, page 0 setup. */
++ for (i = 0; i < 8; i++) {
++ asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0);
++ asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0);
++ asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF);
++ asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF);
++ asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0);
++ }
++
++ /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */
++
++ /* CSEQ Mode dependent, mode 8, page 0 setup. */
++ asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF);
++ asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0);
++ asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0);
++ asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0);
++ asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0);
++ asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0);
++ asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0);
++ asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0);
++ asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0);
++ asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0);
++ asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0);
++ asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE,
++ (u16)last_scb_site_no+1);
++ asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE,
++ (u16)asd_ha->hw_prof.max_ddbs);
++
++ /* CSEQ Mode dependent, mode 8, page 1 setup. */
++ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0);
++ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0);
++
++ /* CSEQ Mode dependent, mode 8, page 2 setup. */
++ /* Tell the sequencer the bus address of the first SCB. */
++ asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER,
++ asd_ha->seq.next_scb.dma_handle);
++ ASD_DPRINTK("First SCB dma_handle: 0x%llx\n",
++ (unsigned long long)asd_ha->seq.next_scb.dma_handle);
++
++ /* Tell the sequencer the first Done List entry address. */
++ asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE,
++ asd_ha->seq.actual_dl->dma_handle);
++
++ /* Initialize the Q_DONE_POINTER with the least significant
++ * 4 bytes of the first Done List address. */
++ asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER,
++ ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle));
++
++ asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE);
++
++ /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */
++}
++
++/**
++ * asd_init_cseq_scratch -- setup and init CSEQ
++ * @asd_ha: pointer to host adapter structure
++ *
++ * Setup and initialize Central sequencers. Initialiaze the mode
++ * independent and dependent scratch page to the default settings.
++ */
++static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha)
++{
++ asd_init_cseq_mip(asd_ha);
++ asd_init_cseq_mdp(asd_ha);
++}
++
++/**
++ * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq)
++{
++ int i;
++
++ /* LSEQ Mode independent page 0 setup. */
++ asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq);
++ asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq),
++ ASD_NOTIFY_ENABLE_SPINUP);
++ asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000);
++ asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0);
++
++ /* LSEQ Mode independent page 1 setup. */
++ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0);
++
++ /* LSEQ Mode Independent page 2 setup. */
++ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0);
++ for (i = 0; i < 12; i += 4)
++ asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0);
++
++ /* LSEQ Mode Independent page 3 setup. */
++
++ /* Device present timer timeout */
++ asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq),
++ ASD_DEV_PRESENT_TIMEOUT);
++
++ /* SATA interlock timer disabled */
++ asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq),
++ ASD_SATA_INTERLOCK_TIMEOUT);
++
++ /* STP shutdown timer timeout constant, IGNORED by the sequencer,
++ * always 0. */
++ asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq),
++ ASD_STP_SHUTDOWN_TIMEOUT);
++
++ asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq),
++ ASD_SRST_ASSERT_TIMEOUT);
++
++ asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq),
++ ASD_RCV_FIS_TIMEOUT);
++
++ asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq),
++ ASD_ONE_MILLISEC_TIMEOUT);
++
++ /* COM_INIT timer */
++ asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq),
++ ASD_TEN_MILLISEC_TIMEOUT);
++
++ asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq),
++ ASD_SMP_RCV_TIMEOUT);
++}
++
++/**
++ * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages.
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq)
++{
++ int i;
++ u32 moffs;
++ u16 ret_addr[] = {
++ 0xFFFF, /* mode 0 */
++ 0xFFFF, /* mode 1 */
++ mode2_task, /* mode 2 */
++ 0,
++ 0xFFFF, /* mode 4/5 */
++ 0xFFFF, /* mode 4/5 */
++ };
++
++ /*
++ * Mode 0,1,2 and 4/5 have common field on page 0 for the first
++ * 14 bytes.
++ */
++ for (i = 0; i < 3; i++) {
++ moffs = i * LSEQ_MODE_SCRATCH_SIZE;
++ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs,
++ ret_addr[i]);
++ asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0);
++ asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0);
++ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0);
++ asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0);
++ }
++ /*
++ * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3.
++ */
++ asd_write_reg_word(asd_ha,
++ LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET,
++ ret_addr[5]);
++ asd_write_reg_word(asd_ha,
++ LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
++ asd_write_reg_word(asd_ha,
++ LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
++ asd_write_reg_word(asd_ha,
++ LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
++ asd_write_reg_word(asd_ha,
++ LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
++ asd_write_reg_byte(asd_ha,
++ LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
++ asd_write_reg_word(asd_ha,
++ LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
++
++ /* LSEQ Mode dependent 0, page 0 setup. */
++ asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq),
++ (u16)asd_ha->hw_prof.max_ddbs);
++ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq),
++ (u16)last_scb_site_no+1);
++ asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq),
++ (u16) ((LmM0INTEN_MASK & 0xFFFF0000) >> 16));
++ asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2,
++ (u16) LmM0INTEN_MASK & 0xFFFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0);
++
++ /* LSEQ mode dependent, mode 1, page 0 setup. */
++ asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF);
++ asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0);
++
++ /* LSEQ Mode dependent mode 2, page 0 setup */
++ asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0);
++
++ /* LSEQ Mode dependent, mode 4/5, page 0 setup. */
++ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0);
++ /*
++ * Set the desired interval between transmissions of the NOTIFY
++ * (ENABLE SPINUP) primitive. Must be initilized to val - 1.
++ */
++ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq),
++ ASD_NOTIFY_TIMEOUT - 1);
++ /* No delay for the first NOTIFY to be sent to the attached target. */
++ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq),
++ ASD_NOTIFY_DOWN_COUNT);
++
++ /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */
++ for (i = 0; i < 2; i++) {
++ int j;
++ /* Start from Page 1 of Mode 0 and 1. */
++ moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE;
++ /* All the fields of page 1 can be intialized to 0. */
++ for (j = 0; j < LSEQ_PAGE_SIZE; j += 4)
++ asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0);
++ }
++
++ /* LSEQ Mode dependent, mode 2, page 1 setup. */
++ asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0);
++
++ /* LSEQ Mode dependent, mode 4/5, page 1. */
++ for (i = 0; i < LSEQ_PAGE_SIZE; i+=4)
++ asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF);
++ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF);
++ asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF);
++
++ /* LSEQ Mode dependent, mode 0, page 2 setup. */
++ asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0);
++ asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0);
++ asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0);
++
++ /* LSEQ Mode Dependent 1, page 2 setup. */
++ asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0);
++
++ /* LSEQ Mode Dependent 2, page 2 setup. */
++ /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer,
++ * i.e. always 0. */
++ asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0);
++ asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0);
++ asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0);
++
++ /* LSEQ Mode Dependent 4/5, page 2 setup. */
++ asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0);
++ asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0);
++}
++
++/**
++ * asd_init_lseq_scratch -- setup and init link sequencers
++ * @asd_ha: pointer to host adapter struct
++ */
++static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha)
++{
++ u8 lseq;
++ u8 lseq_mask;
++
++ lseq_mask = asd_ha->hw_prof.enabled_phys;
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ asd_init_lseq_mip(asd_ha, lseq);
++ asd_init_lseq_mdp(asd_ha, lseq);
++ }
++}
++
++/**
++ * asd_init_scb_sites -- initialize sequencer SCB sites (memory).
++ * @asd_ha: pointer to host adapter structure
++ *
++ * This should be done before initializing common CSEQ and LSEQ
++ * scratch since those areas depend on some computed values here,
++ * last_scb_site_no, etc.
++ */
++static void asd_init_scb_sites(struct asd_ha_struct *asd_ha)
++{
++ u16 site_no;
++ u16 max_scbs = 0;
++
++ for (site_no = asd_ha->hw_prof.max_scbs-1;
++ site_no != (u16) -1;
++ site_no--) {
++ u16 i;
++
++ /* Initialize all fields in the SCB site to 0. */
++ for (i = 0; i < ASD_SCB_SIZE; i += 4)
++ asd_scbsite_write_dword(asd_ha, site_no, i, 0);
++
++ /* Workaround needed by SEQ to fix a SATA issue is to exclude
++ * certain SCB sites from the free list. */
++ if (!SCB_SITE_VALID(site_no))
++ continue;
++
++ if (last_scb_site_no == 0)
++ last_scb_site_no = site_no;
++
++ /* For every SCB site, we need to initialize the
++ * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS,
++ * and SG Element Flag. */
++
++ /* Q_NEXT field of the last SCB is invalidated. */
++ asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no);
++
++ /* Initialize SCB Site Opcode field to invalid. */
++ asd_scbsite_write_byte(asd_ha, site_no,
++ offsetof(struct scb_header, opcode),
++ 0xFF);
++
++ /* Initialize SCB Site Flags field to mean a response
++ * frame has been received. This means inadvertent
++ * frames received to be dropped. */
++ asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01);
++
++ first_scb_site_no = site_no;
++ max_scbs++;
++ }
++ asd_ha->hw_prof.max_scbs = max_scbs;
++ ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs);
++ ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no);
++ ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no);
++}
++
++/**
++ * asd_init_cseq_cio - initialize CSEQ CIO registers
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha)
++{
++ int i;
++
++ asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0);
++ asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS);
++ asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0);
++ asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0);
++ asd_ha->seq.scbpro = 0;
++ asd_write_reg_dword(asd_ha, SCBPRO, 0);
++ asd_write_reg_dword(asd_ha, CSEQCON, 0);
++
++ /* Intialize CSEQ Mode 11 Interrupt Vectors.
++ * The addresses are 16 bit wide and in dword units.
++ * The values of their macros are in byte units.
++ * Thus we have to divide by 4. */
++ asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]);
++ asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]);
++ asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]);
++
++ /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
++ asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC);
++
++ /* Initialize CSEQ Scratch Page to 0x04. */
++ asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04);
++
++ /* Initialize CSEQ Mode[0-8] Dependent registers. */
++ /* Initialize Scratch Page to 0. */
++ for (i = 0; i < 9; i++)
++ asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0);
++
++ /* Reset the ARP2 Program Count. */
++ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
++
++ for (i = 0; i < 8; i++) {
++ /* Intialize Mode n Link m Interrupt Enable. */
++ asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF);
++ /* Initialize Mode n Request Mailbox. */
++ asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0);
++ }
++}
++
++/**
++ * asd_init_lseq_cio -- initialize LmSEQ CIO registers
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq)
++{
++ u8 *sas_addr;
++ int i;
++
++ /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
++ asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC);
++
++ asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0);
++
++ /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */
++ for (i = 0; i < 3; i++)
++ asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0);
++
++ /* Initialize Mode 5 SCRATCHPAGE to 0. */
++ asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0);
++
++ asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0);
++ /* Initialize Mode 0,1,2 and 5 Interrupt Enable and
++ * Interrupt registers. */
++ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK);
++ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF);
++ /* Mode 1 */
++ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK);
++ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF);
++ /* Mode 2 */
++ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK);
++ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF);
++ /* Mode 5 */
++ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK);
++ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF);
++
++ /* Enable HW Timer status. */
++ asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK);
++
++ /* Enable Primitive Status 0 and 1. */
++ asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK);
++ asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK);
++
++ /* Enable Frame Error. */
++ asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK);
++ asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50);
++
++ /* Initialize Mode 0 Transfer Level to 512. */
++ asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512);
++ /* Initialize Mode 1 Transfer Level to 256. */
++ asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256);
++
++ /* Initialize Program Count. */
++ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop);
++
++ /* Enable Blind SG Move. */
++ asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48);
++ asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq),
++ ASD_SATA_INTERLOCK_TIMEOUT);
++
++ (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq));
++
++ /* Clear Primitive Status 0 and 1. */
++ asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF);
++ asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF);
++
++ /* Clear HW Timer status. */
++ asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF);
++
++ /* Clear DMA Errors for Mode 0 and 1. */
++ asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF);
++ asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF);
++
++ /* Clear SG DMA Errors for Mode 0 and 1. */
++ asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF);
++ asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF);
++
++ /* Clear Mode 0 Buffer Parity Error. */
++ asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR);
++
++ /* Clear Mode 0 Frame Error register. */
++ asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF);
++
++ /* Reset LSEQ external interrupt arbiter. */
++ asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL);
++
++ /* Set the Phy SAS for the LmSEQ WWN. */
++ sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr;
++ for (i = 0; i < SAS_ADDR_SIZE; i++)
++ asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]);
++
++ /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */
++ asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0);
++
++ /* Set the Bus Inactivity Time Limit Timer. */
++ asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9);
++
++ /* Enable SATA Port Multiplier. */
++ asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80);
++
++ /* Initialize Interrupt Vector[0-10] address in Mode 3.
++ * See the comment on CSEQ_INT_* */
++ asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]);
++ asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]);
++ /*
++ * Program the Link LED control, applicable only for
++ * Chip Rev. B or later.
++ */
++ asd_write_reg_dword(asd_ha, LmCONTROL(lseq),
++ (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms));
++
++ /* Set the Align Rate for SAS and STP mode. */
++ asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT);
++ asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT);
++}
++
++
++/**
++ * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox
++ * @asd_ha: pointer to host adapter struct
++ */
++static void asd_post_init_cseq(struct asd_ha_struct *asd_ha)
++{
++ int i;
++
++ for (i = 0; i < 8; i++)
++ asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF);
++ for (i = 0; i < 8; i++)
++ asd_read_reg_dword(asd_ha, CMnRSPMBX(i));
++ /* Reset the external interrupt arbiter. */
++ asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL);
++}
++
++/**
++ * asd_init_ddb_0 -- initialize DDB 0
++ * @asd_ha: pointer to host adapter structure
++ *
++ * Initialize DDB site 0 which is used internally by the sequencer.
++ */
++static void asd_init_ddb_0(struct asd_ha_struct *asd_ha)
++{
++ int i;
++
++ /* Zero out the DDB explicitly */
++ for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4)
++ asd_ddbsite_write_dword(asd_ha, 0, i, 0);
++
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail),
++ asd_ha->hw_prof.max_ddbs-1);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0);
++ asd_ddbsite_write_word(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh),
++ asd_ha->hw_prof.num_phys * 2);
++ asd_ddbsite_write_byte(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0);
++ asd_ddbsite_write_byte(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF);
++ asd_ddbsite_write_byte(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00);
++ /* DDB 0 is reserved */
++ set_bit(0, asd_ha->hw_prof.ddb_bitmap);
++}
++
++/**
++ * asd_seq_setup_seqs -- setup and initialize central and link sequencers
++ * @asd_ha: pointer to host adapter structure
++ */
++static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha)
++{
++ int lseq;
++ u8 lseq_mask;
++
++ /* Initialize SCB sites. Done first to compute some values which
++ * the rest of the init code depends on. */
++ asd_init_scb_sites(asd_ha);
++
++ /* Initialize CSEQ Scratch RAM registers. */
++ asd_init_cseq_scratch(asd_ha);
++
++ /* Initialize LmSEQ Scratch RAM registers. */
++ asd_init_lseq_scratch(asd_ha);
++
++ /* Initialize CSEQ CIO registers. */
++ asd_init_cseq_cio(asd_ha);
++
++ asd_init_ddb_0(asd_ha);
++
++ /* Initialize LmSEQ CIO registers. */
++ lseq_mask = asd_ha->hw_prof.enabled_phys;
++ for_each_sequencer(lseq_mask, lseq_mask, lseq)
++ asd_init_lseq_cio(asd_ha, lseq);
++ asd_post_init_cseq(asd_ha);
++}
++
++
++/**
++ * asd_seq_start_cseq -- start the central sequencer, CSEQ
++ * @asd_ha: pointer to host adapter structure
++ */
++static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha)
++{
++ /* Reset the ARP2 instruction to location zero. */
++ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
++
++ /* Unpause the CSEQ */
++ return asd_unpause_cseq(asd_ha);
++}
++
++/**
++ * asd_seq_start_lseq -- start a link sequencer
++ * @asd_ha: pointer to host adapter structure
++ * @lseq: the link sequencer of interest
++ */
++static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
++{
++ /* Reset the ARP2 instruction to location zero. */
++ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop);
++
++ /* Unpause the LmSEQ */
++ return asd_seq_unpause_lseq(asd_ha, lseq);
++}
++
++static int asd_request_firmware(struct asd_ha_struct *asd_ha)
++{
++ int err, i;
++ struct sequencer_file_header header, *hdr_ptr;
++ u32 csum = 0;
++ u16 *ptr_cseq_vecs, *ptr_lseq_vecs;
++
++ if (sequencer_fw)
++ /* already loaded */
++ return 0;
++
++ err = request_firmware(&sequencer_fw,
++ SAS_RAZOR_SEQUENCER_FW_FILE,
++ &asd_ha->pcidev->dev);
++ if (err)
++ return err;
++
++ hdr_ptr = (struct sequencer_file_header *)sequencer_fw->data;
++
++ header.csum = le32_to_cpu(hdr_ptr->csum);
++ header.major = le32_to_cpu(hdr_ptr->major);
++ header.minor = le32_to_cpu(hdr_ptr->minor);
++ sequencer_version = hdr_ptr->version;
++ header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset);
++ header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size);
++ header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset);
++ header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size);
++ header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset);
++ header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size);
++ header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset);
++ header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size);
++ header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task);
++ header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop);
++ header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop);
++
++ for (i = sizeof(header.csum); i < sequencer_fw->size; i++)
++ csum += sequencer_fw->data[i];
++
++ if (csum != header.csum) {
++ asd_printk("Firmware file checksum mismatch\n");
++ return -EINVAL;
++ }
++
++ if (header.cseq_table_size != CSEQ_NUM_VECS ||
++ header.lseq_table_size != LSEQ_NUM_VECS) {
++ asd_printk("Firmware file table size mismatch\n");
++ return -EINVAL;
++ }
++
++ ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset];
++ ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset];
++ mode2_task = header.mode2_task;
++ cseq_idle_loop = header.cseq_idle_loop;
++ lseq_idle_loop = header.lseq_idle_loop;
++
++ for (i = 0; i < CSEQ_NUM_VECS; i++)
++ cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]);
++
++ for (i = 0; i < LSEQ_NUM_VECS; i++)
++ lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]);
++
++ cseq_code = &sequencer_fw->data[header.cseq_code_offset];
++ cseq_code_size = header.cseq_code_size;
++ lseq_code = &sequencer_fw->data[header.lseq_code_offset];
++ lseq_code_size = header.lseq_code_size;
++
++ return 0;
++}
++
++int asd_init_seqs(struct asd_ha_struct *asd_ha)
++{
++ int err;
++
++ err = asd_request_firmware(asd_ha);
++
++ if (err) {
++ asd_printk("Failed to load sequencer firmware file %s, error %d\n",
++ SAS_RAZOR_SEQUENCER_FW_FILE, err);
++ return err;
++ }
++
++ asd_printk("using sequencer %s\n", sequencer_version);
++ err = asd_seq_download_seqs(asd_ha);
++ if (err) {
++ asd_printk("couldn't download sequencers for %s\n",
++ pci_name(asd_ha->pcidev));
++ return err;
++ }
++
++ asd_seq_setup_seqs(asd_ha);
++
++ return 0;
++}
++
++int asd_start_seqs(struct asd_ha_struct *asd_ha)
++{
++ int err;
++ u8 lseq_mask;
++ int lseq;
++
++ err = asd_seq_start_cseq(asd_ha);
++ if (err) {
++ asd_printk("couldn't start CSEQ for %s\n",
++ pci_name(asd_ha->pcidev));
++ return err;
++ }
++
++ lseq_mask = asd_ha->hw_prof.enabled_phys;
++ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
++ err = asd_seq_start_lseq(asd_ha, lseq);
++ if (err) {
++ asd_printk("coudln't start LSEQ %d for %s\n", lseq,
++ pci_name(asd_ha->pcidev));
++ return err;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * asd_update_port_links -- update port_map_by_links and phy_is_up
++ * @sas_phy: pointer to the phy which has been added to a port
++ *
++ * 1) When a link reset has completed and we got BYTES DMAED with a
++ * valid frame we call this function for that phy, to indicate that
++ * the phy is up, i.e. we update the phy_is_up in DDB 0. The
++ * sequencer checks phy_is_up when pending SCBs are to be sent, and
++ * when an open address frame has been received.
++ *
++ * 2) When we know of ports, we call this function to update the map
++ * of phys participaing in that port, i.e. we update the
++ * port_map_by_links in DDB 0. When a HARD_RESET primitive has been
++ * received, the sequencer disables all phys in that port.
++ * port_map_by_links is also used as the conn_mask byte in the
++ * initiator/target port DDB.
++ */
++void asd_update_port_links(struct asd_sas_phy *sas_phy)
++{
++ struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha;
++ const u8 phy_mask = (u8) sas_phy->port->phy_mask;
++ u8 phy_is_up;
++ u8 mask;
++ int i, err;
++
++ for_each_phy(phy_mask, mask, i)
++ asd_ddbsite_write_byte(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared,
++ port_map_by_links)+i,phy_mask);
++
++ for (i = 0; i < 12; i++) {
++ phy_is_up = asd_ddbsite_read_byte(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, phy_is_up));
++ err = asd_ddbsite_update_byte(asd_ha, 0,
++ offsetof(struct asd_ddb_seq_shared, phy_is_up),
++ phy_is_up,
++ phy_is_up | phy_mask);
++ if (!err)
++ break;
++ else if (err == -EFAULT) {
++ asd_printk("phy_is_up: parity error in DDB 0\n");
++ break;
++ }
++ }
++
++ if (err)
++ asd_printk("couldn't update DDB 0:error:%d\n", err);
++}
++
++MODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE);
+diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h
+new file mode 100644
+index 0000000..42281c3
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_seq.h
+@@ -0,0 +1,70 @@
++/*
++ * Aic94xx SAS/SATA driver sequencer interface header file.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef _AIC94XX_SEQ_H_
++#define _AIC94XX_SEQ_H_
++
++#define CSEQ_NUM_VECS 3
++#define LSEQ_NUM_VECS 11
++
++#define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw"
++
++/* Note: All quantites in the sequencer file are little endian */
++struct sequencer_file_header {
++ /* Checksum of the entire contents of the sequencer excluding
++ * these four bytes */
++ u32 csum;
++ /* numeric major version */
++ u32 major;
++ /* numeric minor version */
++ u32 minor;
++ /* version string printed by driver */
++ char version[16];
++ u32 cseq_table_offset;
++ u32 cseq_table_size;
++ u32 lseq_table_offset;
++ u32 lseq_table_size;
++ u32 cseq_code_offset;
++ u32 cseq_code_size;
++ u32 lseq_code_offset;
++ u32 lseq_code_size;
++ u16 mode2_task;
++ u16 cseq_idle_loop;
++ u16 lseq_idle_loop;
++} __attribute__((packed));
++
++#ifdef __KERNEL__
++int asd_pause_cseq(struct asd_ha_struct *asd_ha);
++int asd_unpause_cseq(struct asd_ha_struct *asd_ha);
++int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
++int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
++int asd_init_seqs(struct asd_ha_struct *asd_ha);
++int asd_start_seqs(struct asd_ha_struct *asd_ha);
++
++void asd_update_port_links(struct asd_sas_phy *phy);
++#endif
++
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
+new file mode 100644
+index 0000000..d202ed5
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_task.c
+@@ -0,0 +1,642 @@
++/*
++ * Aic94xx SAS/SATA Tasks
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/spinlock.h>
++#include "aic94xx.h"
++#include "aic94xx_sas.h"
++#include "aic94xx_hwi.h"
++
++static void asd_unbuild_ata_ascb(struct asd_ascb *a);
++static void asd_unbuild_smp_ascb(struct asd_ascb *a);
++static void asd_unbuild_ssp_ascb(struct asd_ascb *a);
++
++static inline void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
++ asd_ha->seq.can_queue += num;
++ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
++}
++
++/* PCI_DMA_... to our direction translation.
++ */
++static const u8 data_dir_flags[] = {
++ [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
++ [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */
++ [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */
++ [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
++};
++
++static inline int asd_map_scatterlist(struct sas_task *task,
++ struct sg_el *sg_arr,
++ gfp_t gfp_flags)
++{
++ struct asd_ascb *ascb = task->lldd_task;
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct scatterlist *sc;
++ int num_sg, res;
++
++ if (task->data_dir == PCI_DMA_NONE)
++ return 0;
++
++ if (task->num_scatter == 0) {
++ void *p = task->scatter;
++ dma_addr_t dma = pci_map_single(asd_ha->pcidev, p,
++ task->total_xfer_len,
++ task->data_dir);
++ sg_arr[0].bus_addr = cpu_to_le64((u64)dma);
++ sg_arr[0].size = cpu_to_le32(task->total_xfer_len);
++ sg_arr[0].flags |= ASD_SG_EL_LIST_EOL;
++ return 0;
++ }
++
++ num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
++ task->data_dir);
++ if (num_sg == 0)
++ return -ENOMEM;
++
++ if (num_sg > 3) {
++ int i;
++
++ ascb->sg_arr = asd_alloc_coherent(asd_ha,
++ num_sg*sizeof(struct sg_el),
++ gfp_flags);
++ if (!ascb->sg_arr) {
++ res = -ENOMEM;
++ goto err_unmap;
++ }
++ for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
++ struct sg_el *sg =
++ &((struct sg_el *)ascb->sg_arr->vaddr)[i];
++ sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc));
++ sg->size = cpu_to_le32((u32)sg_dma_len(sc));
++ if (i == num_sg-1)
++ sg->flags |= ASD_SG_EL_LIST_EOL;
++ }
++
++ for (sc = task->scatter, i = 0; i < 2; i++, sc++) {
++ sg_arr[i].bus_addr =
++ cpu_to_le64((u64)sg_dma_address(sc));
++ sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
++ }
++ sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr);
++ sg_arr[1].flags |= ASD_SG_EL_LIST_EOS;
++
++ memset(&sg_arr[2], 0, sizeof(*sg_arr));
++ sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle);
++ } else {
++ int i;
++ for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
++ sg_arr[i].bus_addr =
++ cpu_to_le64((u64)sg_dma_address(sc));
++ sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
++ }
++ sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL;
++ }
++
++ return 0;
++err_unmap:
++ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
++ task->data_dir);
++ return res;
++}
++
++static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct sas_task *task = ascb->uldd_task;
++
++ if (task->data_dir == PCI_DMA_NONE)
++ return;
++
++ if (task->num_scatter == 0) {
++ dma_addr_t dma = (dma_addr_t)
++ le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr);
++ pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len,
++ task->data_dir);
++ return;
++ }
++
++ asd_free_coherent(asd_ha, ascb->sg_arr);
++ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
++ task->data_dir);
++}
++
++/* ---------- Task complete tasklet ---------- */
++
++static void asd_get_response_tasklet(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct sas_task *task = ascb->uldd_task;
++ struct task_status_struct *ts = &task->task_status;
++ unsigned long flags;
++ struct tc_resp_sb_struct {
++ __le16 index_escb;
++ u8 len_lsb;
++ u8 flags;
++ } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
++
++/* int size = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */
++ int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
++ struct asd_ascb *escb;
++ struct asd_dma_tok *edb;
++ void *r;
++
++ spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
++ escb = asd_tc_index_find(&asd_ha->seq,
++ (int)le16_to_cpu(resp_sb->index_escb));
++ spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
++
++ if (!escb) {
++ ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
++ return;
++ }
++
++ ts->buf_valid_size = 0;
++ edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
++ r = edb->vaddr;
++ if (task->task_proto == SAS_PROTO_SSP) {
++ struct ssp_response_iu *iu =
++ r + 16 + sizeof(struct ssp_frame_hdr);
++
++ ts->residual = le32_to_cpu(*(__le32 *)r);
++ ts->resp = SAS_TASK_COMPLETE;
++ if (iu->datapres == 0)
++ ts->stat = iu->status;
++ else if (iu->datapres == 1)
++ ts->stat = iu->resp_data[3];
++ else if (iu->datapres == 2) {
++ ts->stat = SAM_CHECK_COND;
++ ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
++ be32_to_cpu(iu->sense_data_len));
++ memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
++ if (iu->status != SAM_CHECK_COND) {
++ ASD_DPRINTK("device %llx sent sense data, but "
++ "stat(0x%x) is not CHECK_CONDITION"
++ "\n",
++ SAS_ADDR(task->dev->sas_addr),
++ ts->stat);
++ }
++ }
++ } else {
++ struct ata_task_resp *resp = (void *) &ts->buf[0];
++
++ ts->residual = le32_to_cpu(*(__le32 *)r);
++
++ if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
++ resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
++ memcpy(&resp->ending_fis[0], r+16, 24);
++ ts->buf_valid_size = sizeof(*resp);
++ }
++ }
++
++ asd_invalidate_edb(escb, edb_id);
++}
++
++static void asd_task_tasklet_complete(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ struct sas_task *task = ascb->uldd_task;
++ struct task_status_struct *ts = &task->task_status;
++ unsigned long flags;
++ u8 opcode = dl->opcode;
++
++ asd_can_dequeue(ascb->ha, 1);
++
++Again:
++ switch (opcode) {
++ case TC_NO_ERROR:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAM_GOOD;
++ break;
++ case TC_UNDERRUN:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_DATA_UNDERRUN;
++ ts->residual = le32_to_cpu(*(__le32 *)dl->status_block);
++ break;
++ case TC_OVERRUN:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_DATA_OVERRUN;
++ ts->residual = 0;
++ break;
++ case TC_SSP_RESP:
++ case TC_ATA_RESP:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_PROTO_RESPONSE;
++ asd_get_response_tasklet(ascb, dl);
++ break;
++ case TF_OPEN_REJECT:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_OPEN_REJECT;
++ if (dl->status_block[1] & 2)
++ ts->open_rej_reason = 1 + dl->status_block[2];
++ else if (dl->status_block[1] & 1)
++ ts->open_rej_reason = (dl->status_block[2] >> 4)+10;
++ else
++ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
++ break;
++ case TF_OPEN_TO:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_OPEN_TO;
++ break;
++ case TF_PHY_DOWN:
++ case TU_PHY_DOWN:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_PHY_DOWN;
++ break;
++ case TI_PHY_DOWN:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_PHY_DOWN;
++ break;
++ case TI_BREAK:
++ case TI_PROTO_ERR:
++ case TI_NAK:
++ case TI_ACK_NAK_TO:
++ case TF_SMP_XMIT_RCV_ERR:
++ case TC_ATA_R_ERR_RECV:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_INTERRUPTED;
++ break;
++ case TF_BREAK:
++ case TU_BREAK:
++ case TU_ACK_NAK_TO:
++ case TF_SMPRSP_TO:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_DEV_NO_RESPONSE;
++ break;
++ case TF_NAK_RECV:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_NAK_R_ERR;
++ break;
++ case TA_I_T_NEXUS_LOSS:
++ opcode = dl->status_block[0];
++ goto Again;
++ break;
++ case TF_INV_CONN_HANDLE:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_DEVICE_UNKNOWN;
++ break;
++ case TF_REQUESTED_N_PENDING:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_PENDING;
++ break;
++ case TC_TASK_CLEARED:
++ case TA_ON_REQ:
++ ts->resp = SAS_TASK_COMPLETE;
++ ts->stat = SAS_ABORTED_TASK;
++ break;
++
++ case TF_NO_SMP_CONN:
++ case TF_TMF_NO_CTX:
++ case TF_TMF_NO_TAG:
++ case TF_TMF_TAG_FREE:
++ case TF_TMF_TASK_DONE:
++ case TF_TMF_NO_CONN_HANDLE:
++ case TF_IRTT_TO:
++ case TF_IU_SHORT:
++ case TF_DATA_OFFS_ERR:
++ ts->resp = SAS_TASK_UNDELIVERED;
++ ts->stat = SAS_DEV_NO_RESPONSE;
++ break;
++
++ case TC_LINK_ADM_RESP:
++ case TC_CONTROL_PHY:
++ case TC_RESUME:
++ case TC_PARTIAL_SG_LIST:
++ default:
++ ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
++ break;
++ }
++
++ switch (task->task_proto) {
++ case SATA_PROTO:
++ case SAS_PROTO_STP:
++ asd_unbuild_ata_ascb(ascb);
++ break;
++ case SAS_PROTO_SMP:
++ asd_unbuild_smp_ascb(ascb);
++ break;
++ case SAS_PROTO_SSP:
++ asd_unbuild_ssp_ascb(ascb);
++ default:
++ break;
++ }
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
++ task->task_state_flags |= SAS_TASK_STATE_DONE;
++ if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
++ "stat 0x%x but aborted by upper layer!\n",
++ task, opcode, ts->resp, ts->stat);
++ complete(&ascb->completion);
++ } else {
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ task->lldd_task = NULL;
++ asd_ascb_free(ascb);
++ mb();
++ task->task_done(task);
++ }
++}
++
++/* ---------- ATA ---------- */
++
++static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
++ gfp_t gfp_flags)
++{
++ struct domain_device *dev = task->dev;
++ struct scb *scb;
++ u8 flags;
++ int res = 0;
++
++ scb = ascb->scb;
++
++ if (unlikely(task->ata_task.device_control_reg_update))
++ scb->header.opcode = CONTROL_ATA_DEV;
++ else if (dev->sata_dev.command_set == ATA_COMMAND_SET)
++ scb->header.opcode = INITIATE_ATA_TASK;
++ else
++ scb->header.opcode = INITIATE_ATAPI_TASK;
++
++ scb->ata_task.proto_conn_rate = (1 << 5); /* STP */
++ if (dev->port->oob_mode == SAS_OOB_MODE)
++ scb->ata_task.proto_conn_rate |= dev->linkrate;
++
++ scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
++ scb->ata_task.fis = task->ata_task.fis;
++ scb->ata_task.fis.fis_type = 0x27;
++ if (likely(!task->ata_task.device_control_reg_update))
++ scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
++ scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
++ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
++ memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet,
++ 16);
++ scb->ata_task.sister_scb = cpu_to_le16(0xFFFF);
++ scb->ata_task.conn_handle = cpu_to_le16(
++ (u16)(unsigned long)dev->lldd_dev);
++
++ if (likely(!task->ata_task.device_control_reg_update)) {
++ flags = 0;
++ if (task->ata_task.dma_xfer)
++ flags |= DATA_XFER_MODE_DMA;
++ if (task->ata_task.use_ncq &&
++ dev->sata_dev.command_set != ATAPI_COMMAND_SET)
++ flags |= ATA_Q_TYPE_NCQ;
++ flags |= data_dir_flags[task->data_dir];
++ scb->ata_task.ata_flags = flags;
++
++ scb->ata_task.retry_count = task->ata_task.retry_count;
++
++ flags = 0;
++ if (task->ata_task.set_affil_pol)
++ flags |= SET_AFFIL_POLICY;
++ if (task->ata_task.stp_affil_pol)
++ flags |= STP_AFFIL_POLICY;
++ scb->ata_task.flags = flags;
++ }
++ ascb->tasklet_complete = asd_task_tasklet_complete;
++
++ if (likely(!task->ata_task.device_control_reg_update))
++ res = asd_map_scatterlist(task, scb->ata_task.sg_element,
++ gfp_flags);
++
++ return res;
++}
++
++static void asd_unbuild_ata_ascb(struct asd_ascb *a)
++{
++ asd_unmap_scatterlist(a);
++}
++
++/* ---------- SMP ---------- */
++
++static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
++ gfp_t gfp_flags)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ struct domain_device *dev = task->dev;
++ struct scb *scb;
++
++ pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
++ PCI_DMA_FROMDEVICE);
++ pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
++ PCI_DMA_FROMDEVICE);
++
++ scb = ascb->scb;
++
++ scb->header.opcode = INITIATE_SMP_TASK;
++
++ scb->smp_task.proto_conn_rate = dev->linkrate;
++
++ scb->smp_task.smp_req.bus_addr =
++ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
++ scb->smp_task.smp_req.size =
++ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
++
++ scb->smp_task.smp_resp.bus_addr =
++ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
++ scb->smp_task.smp_resp.size =
++ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
++
++ scb->smp_task.sister_scb = cpu_to_le16(0xFFFF);
++ scb->smp_task.conn_handle = cpu_to_le16((u16)
++ (unsigned long)dev->lldd_dev);
++
++ ascb->tasklet_complete = asd_task_tasklet_complete;
++
++ return 0;
++}
++
++static void asd_unbuild_smp_ascb(struct asd_ascb *a)
++{
++ struct sas_task *task = a->uldd_task;
++
++ BUG_ON(!task);
++ pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
++ PCI_DMA_FROMDEVICE);
++ pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
++ PCI_DMA_FROMDEVICE);
++}
++
++/* ---------- SSP ---------- */
++
++static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,
++ gfp_t gfp_flags)
++{
++ struct domain_device *dev = task->dev;
++ struct scb *scb;
++ int res = 0;
++
++ scb = ascb->scb;
++
++ scb->header.opcode = INITIATE_SSP_TASK;
++
++ scb->ssp_task.proto_conn_rate = (1 << 4); /* SSP */
++ scb->ssp_task.proto_conn_rate |= dev->linkrate;
++ scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
++ scb->ssp_task.ssp_frame.frame_type = SSP_DATA;
++ memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr,
++ HASHED_SAS_ADDR_SIZE);
++ memcpy(scb->ssp_task.ssp_frame.hashed_src_addr,
++ dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
++ scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
++
++ memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8);
++ if (task->ssp_task.enable_first_burst)
++ scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK;
++ scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3);
++ scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7);
++ memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16);
++
++ scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF);
++ scb->ssp_task.conn_handle = cpu_to_le16(
++ (u16)(unsigned long)dev->lldd_dev);
++ scb->ssp_task.data_dir = data_dir_flags[task->data_dir];
++ scb->ssp_task.retry_count = scb->ssp_task.retry_count;
++
++ ascb->tasklet_complete = asd_task_tasklet_complete;
++
++ res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);
++
++ return res;
++}
++
++static void asd_unbuild_ssp_ascb(struct asd_ascb *a)
++{
++ asd_unmap_scatterlist(a);
++}
++
++/* ---------- Execute Task ---------- */
++
++static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
++{
++ int res = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
++ if ((asd_ha->seq.can_queue - num) < 0)
++ res = -SAS_QUEUE_FULL;
++ else
++ asd_ha->seq.can_queue -= num;
++ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
++
++ return res;
++}
++
++int asd_execute_task(struct sas_task *task, const int num,
++ gfp_t gfp_flags)
++{
++ int res = 0;
++ LIST_HEAD(alist);
++ struct sas_task *t = task;
++ struct asd_ascb *ascb = NULL, *a;
++ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
++
++ res = asd_can_queue(asd_ha, num);
++ if (res)
++ return res;
++
++ res = num;
++ ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);
++ if (res) {
++ res = -ENOMEM;
++ goto out_err;
++ }
++
++ __list_add(&alist, ascb->list.prev, &ascb->list);
++ list_for_each_entry(a, &alist, list) {
++ a->uldd_task = t;
++ t->lldd_task = a;
++ t = list_entry(t->list.next, struct sas_task, list);
++ }
++ list_for_each_entry(a, &alist, list) {
++ t = a->uldd_task;
++ a->uldd_timer = 1;
++ if (t->task_proto & SAS_PROTO_STP)
++ t->task_proto = SAS_PROTO_STP;
++ switch (t->task_proto) {
++ case SATA_PROTO:
++ case SAS_PROTO_STP:
++ res = asd_build_ata_ascb(a, t, gfp_flags);
++ break;
++ case SAS_PROTO_SMP:
++ res = asd_build_smp_ascb(a, t, gfp_flags);
++ break;
++ case SAS_PROTO_SSP:
++ res = asd_build_ssp_ascb(a, t, gfp_flags);
++ break;
++ default:
++ asd_printk("unknown sas_task proto: 0x%x\n",
++ t->task_proto);
++ res = -ENOMEM;
++ break;
++ }
++ if (res)
++ goto out_err_unmap;
++ }
++ list_del_init(&alist);
++
++ res = asd_post_ascb_list(asd_ha, ascb, num);
++ if (unlikely(res)) {
++ a = NULL;
++ __list_add(&alist, ascb->list.prev, &ascb->list);
++ goto out_err_unmap;
++ }
++
++ return 0;
++out_err_unmap:
++ {
++ struct asd_ascb *b = a;
++ list_for_each_entry(a, &alist, list) {
++ if (a == b)
++ break;
++ t = a->uldd_task;
++ switch (t->task_proto) {
++ case SATA_PROTO:
++ case SAS_PROTO_STP:
++ asd_unbuild_ata_ascb(a);
++ break;
++ case SAS_PROTO_SMP:
++ asd_unbuild_smp_ascb(a);
++ break;
++ case SAS_PROTO_SSP:
++ asd_unbuild_ssp_ascb(a);
++ default:
++ break;
++ }
++ t->lldd_task = NULL;
++ }
++ }
++ list_del_init(&alist);
++out_err:
++ if (ascb)
++ asd_ascb_free_list(ascb);
++ asd_can_dequeue(asd_ha, num);
++ return res;
++}
+diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
+new file mode 100644
+index 0000000..6123438
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
+@@ -0,0 +1,636 @@
++/*
++ * Aic94xx Task Management Functions
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx driver 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 of the
++ * License.
++ *
++ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/spinlock.h>
++#include "aic94xx.h"
++#include "aic94xx_sas.h"
++#include "aic94xx_hwi.h"
++
++/* ---------- Internal enqueue ---------- */
++
++static int asd_enqueue_internal(struct asd_ascb *ascb,
++ void (*tasklet_complete)(struct asd_ascb *,
++ struct done_list_struct *),
++ void (*timed_out)(unsigned long))
++{
++ int res;
++
++ ascb->tasklet_complete = tasklet_complete;
++ ascb->uldd_timer = 1;
++
++ ascb->timer.data = (unsigned long) ascb;
++ ascb->timer.function = timed_out;
++ ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
++
++ add_timer(&ascb->timer);
++
++ res = asd_post_ascb_list(ascb->ha, ascb, 1);
++ if (unlikely(res))
++ del_timer(&ascb->timer);
++ return res;
++}
++
++static inline void asd_timedout_common(unsigned long data)
++{
++ struct asd_ascb *ascb = (void *) data;
++ struct asd_seq_data *seq = &ascb->ha->seq;
++ unsigned long flags;
++
++ spin_lock_irqsave(&seq->pend_q_lock, flags);
++ seq->pending--;
++ list_del_init(&ascb->list);
++ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
++}
++
++/* ---------- CLEAR NEXUS ---------- */
++
++static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ ASD_DPRINTK("%s: here\n", __FUNCTION__);
++ if (!del_timer(&ascb->timer)) {
++ ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
++ return;
++ }
++ ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
++ ascb->uldd_task = (void *) (unsigned long) dl->opcode;
++ complete(&ascb->completion);
++}
++
++static void asd_clear_nexus_timedout(unsigned long data)
++{
++ struct asd_ascb *ascb = (void *) data;
++
++ ASD_DPRINTK("%s: here\n", __FUNCTION__);
++ asd_timedout_common(data);
++ ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
++ complete(&ascb->completion);
++}
++
++#define CLEAR_NEXUS_PRE \
++ ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
++ res = 1; \
++ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
++ if (!ascb) \
++ return -ENOMEM; \
++ \
++ scb = ascb->scb; \
++ scb->header.opcode = CLEAR_NEXUS
++
++#define CLEAR_NEXUS_POST \
++ ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
++ res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
++ asd_clear_nexus_timedout); \
++ if (res) \
++ goto out_err; \
++ ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
++ wait_for_completion(&ascb->completion); \
++ res = (int) (unsigned long) ascb->uldd_task; \
++ if (res == TC_NO_ERROR) \
++ res = TMF_RESP_FUNC_COMPLETE; \
++out_err: \
++ asd_ascb_free(ascb); \
++ return res
++
++int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
++{
++ struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
++ struct asd_ascb *ascb;
++ struct scb *scb;
++ int res;
++
++ CLEAR_NEXUS_PRE;
++ scb->clear_nexus.nexus = NEXUS_ADAPTER;
++ CLEAR_NEXUS_POST;
++}
++
++int asd_clear_nexus_port(struct asd_sas_port *port)
++{
++ struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
++ struct asd_ascb *ascb;
++ struct scb *scb;
++ int res;
++
++ CLEAR_NEXUS_PRE;
++ scb->clear_nexus.nexus = NEXUS_PORT;
++ scb->clear_nexus.conn_mask = port->phy_mask;
++ CLEAR_NEXUS_POST;
++}
++
++#if 0
++static int asd_clear_nexus_I_T(struct domain_device *dev)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ struct asd_ascb *ascb;
++ struct scb *scb;
++ int res;
++
++ CLEAR_NEXUS_PRE;
++ scb->clear_nexus.nexus = NEXUS_I_T;
++ scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
++ if (dev->tproto)
++ scb->clear_nexus.flags |= SUSPEND_TX;
++ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
++ dev->lldd_dev);
++ CLEAR_NEXUS_POST;
++}
++#endif
++
++static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ struct asd_ascb *ascb;
++ struct scb *scb;
++ int res;
++
++ CLEAR_NEXUS_PRE;
++ scb->clear_nexus.nexus = NEXUS_I_T_L;
++ scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
++ if (dev->tproto)
++ scb->clear_nexus.flags |= SUSPEND_TX;
++ memcpy(scb->clear_nexus.ssp_task.lun, lun, 8);
++ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
++ dev->lldd_dev);
++ CLEAR_NEXUS_POST;
++}
++
++static int asd_clear_nexus_tag(struct sas_task *task)
++{
++ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
++ struct asd_ascb *tascb = task->lldd_task;
++ struct asd_ascb *ascb;
++ struct scb *scb;
++ int res;
++
++ CLEAR_NEXUS_PRE;
++ scb->clear_nexus.nexus = NEXUS_TAG;
++ memcpy(scb->clear_nexus.ssp_task.lun, task->ssp_task.LUN, 8);
++ scb->clear_nexus.ssp_task.tag = tascb->tag;
++ if (task->dev->tproto)
++ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
++ task->dev->lldd_dev);
++ CLEAR_NEXUS_POST;
++}
++
++static int asd_clear_nexus_index(struct sas_task *task)
++{
++ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
++ struct asd_ascb *tascb = task->lldd_task;
++ struct asd_ascb *ascb;
++ struct scb *scb;
++ int res;
++
++ CLEAR_NEXUS_PRE;
++ scb->clear_nexus.nexus = NEXUS_TRANS_CX;
++ if (task->dev->tproto)
++ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
++ task->dev->lldd_dev);
++ scb->clear_nexus.index = cpu_to_le16(tascb->tc_index);
++ CLEAR_NEXUS_POST;
++}
++
++/* ---------- TMFs ---------- */
++
++static void asd_tmf_timedout(unsigned long data)
++{
++ struct asd_ascb *ascb = (void *) data;
++
++ ASD_DPRINTK("tmf timed out\n");
++ asd_timedout_common(data);
++ ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
++ complete(&ascb->completion);
++}
++
++static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ struct asd_ha_struct *asd_ha = ascb->ha;
++ unsigned long flags;
++ struct tc_resp_sb_struct {
++ __le16 index_escb;
++ u8 len_lsb;
++ u8 flags;
++ } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
++
++ int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
++ struct asd_ascb *escb;
++ struct asd_dma_tok *edb;
++ struct ssp_frame_hdr *fh;
++ struct ssp_response_iu *ru;
++ int res = TMF_RESP_FUNC_FAILED;
++
++ ASD_DPRINTK("tmf resp tasklet\n");
++
++ spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
++ escb = asd_tc_index_find(&asd_ha->seq,
++ (int)le16_to_cpu(resp_sb->index_escb));
++ spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
++
++ if (!escb) {
++ ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
++ return res;
++ }
++
++ edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
++ ascb->tag = *(__be16 *)(edb->vaddr+4);
++ fh = edb->vaddr + 16;
++ ru = edb->vaddr + 16 + sizeof(*fh);
++ res = ru->status;
++ if (ru->datapres == 1) /* Response data present */
++ res = ru->resp_data[3];
++#if 0
++ ascb->tag = fh->tag;
++#endif
++ ascb->tag_valid = 1;
++
++ asd_invalidate_edb(escb, edb_id);
++ return res;
++}
++
++static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
++ struct done_list_struct *dl)
++{
++ if (!del_timer(&ascb->timer))
++ return;
++
++ ASD_DPRINTK("tmf tasklet complete\n");
++
++ if (dl->opcode == TC_SSP_RESP)
++ ascb->uldd_task = (void *) (unsigned long)
++ asd_get_tmf_resp_tasklet(ascb, dl);
++ else
++ ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode;
++
++ complete(&ascb->completion);
++}
++
++static inline int asd_clear_nexus(struct sas_task *task)
++{
++ int res = TMF_RESP_FUNC_FAILED;
++ struct asd_ascb *tascb = task->lldd_task;
++ unsigned long flags;
++
++ ASD_DPRINTK("task not done, clearing nexus\n");
++ if (tascb->tag_valid)
++ res = asd_clear_nexus_tag(task);
++ else
++ res = asd_clear_nexus_index(task);
++ wait_for_completion_timeout(&tascb->completion,
++ AIC94XX_SCB_TIMEOUT);
++ ASD_DPRINTK("came back from clear nexus\n");
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (task->task_state_flags & SAS_TASK_STATE_DONE)
++ res = TMF_RESP_FUNC_COMPLETE;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ return res;
++}
++
++/**
++ * asd_abort_task -- ABORT TASK TMF
++ * @task: the task to be aborted
++ *
++ * Before calling ABORT TASK the task state flags should be ORed with
++ * SAS_TASK_STATE_ABORTED (unless SAS_TASK_STATE_DONE is set) under
++ * the task_state_lock IRQ spinlock, then ABORT TASK *must* be called.
++ *
++ * Implements the ABORT TASK TMF, I_T_L_Q nexus.
++ * Returns: SAS TMF responses (see sas_task.h),
++ * -ENOMEM,
++ * -SAS_QUEUE_FULL.
++ *
++ * When ABORT TASK returns, the caller of ABORT TASK checks first the
++ * task->task_state_flags, and then the return value of ABORT TASK.
++ *
++ * If the task has task state bit SAS_TASK_STATE_DONE set, then the
++ * task was completed successfully prior to it being aborted. The
++ * caller of ABORT TASK has responsibility to call task->task_done()
++ * xor free the task, depending on their framework. The return code
++ * is TMF_RESP_FUNC_FAILED in this case.
++ *
++ * Else the SAS_TASK_STATE_DONE bit is not set,
++ * If the return code is TMF_RESP_FUNC_COMPLETE, then
++ * the task was aborted successfully. The caller of
++ * ABORT TASK has responsibility to call task->task_done()
++ * to finish the task, xor free the task depending on their
++ * framework.
++ * else
++ * the ABORT TASK returned some kind of error. The task
++ * was _not_ cancelled. Nothing can be assumed.
++ * The caller of ABORT TASK may wish to retry.
++ */
++int asd_abort_task(struct sas_task *task)
++{
++ struct asd_ascb *tascb = task->lldd_task;
++ struct asd_ha_struct *asd_ha = tascb->ha;
++ int res = 1;
++ unsigned long flags;
++ struct asd_ascb *ascb = NULL;
++ struct scb *scb;
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ res = TMF_RESP_FUNC_COMPLETE;
++ ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
++ goto out_done;
++ }
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
++ if (!ascb)
++ return -ENOMEM;
++ scb = ascb->scb;
++
++ scb->header.opcode = ABORT_TASK;
++
++ switch (task->task_proto) {
++ case SATA_PROTO:
++ case SAS_PROTO_STP:
++ scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
++ break;
++ case SAS_PROTO_SSP:
++ scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */
++ scb->abort_task.proto_conn_rate |= task->dev->linkrate;
++ break;
++ case SAS_PROTO_SMP:
++ break;
++ default:
++ break;
++ }
++
++ if (task->task_proto == SAS_PROTO_SSP) {
++ scb->abort_task.ssp_frame.frame_type = SSP_TASK;
++ memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
++ task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
++ memcpy(scb->abort_task.ssp_frame.hashed_src_addr,
++ task->dev->port->ha->hashed_sas_addr,
++ HASHED_SAS_ADDR_SIZE);
++ scb->abort_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
++
++ memcpy(scb->abort_task.ssp_task.lun, task->ssp_task.LUN, 8);
++ scb->abort_task.ssp_task.tmf = TMF_ABORT_TASK;
++ scb->abort_task.ssp_task.tag = cpu_to_be16(0xFFFF);
++ }
++
++ scb->abort_task.sister_scb = cpu_to_le16(0xFFFF);
++ scb->abort_task.conn_handle = cpu_to_le16(
++ (u16)(unsigned long)task->dev->lldd_dev);
++ scb->abort_task.retry_count = 1;
++ scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index);
++ scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
++
++ res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
++ asd_tmf_timedout);
++ if (res)
++ goto out;
++ wait_for_completion(&ascb->completion);
++ ASD_DPRINTK("tmf came back\n");
++
++ res = (int) (unsigned long) ascb->uldd_task;
++ tascb->tag = ascb->tag;
++ tascb->tag_valid = ascb->tag_valid;
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ res = TMF_RESP_FUNC_COMPLETE;
++ ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
++ goto out_done;
++ }
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ switch (res) {
++ /* The task to be aborted has been sent to the device.
++ * We got a Response IU for the ABORT TASK TMF. */
++ case TC_NO_ERROR + 0xFF00:
++ case TMF_RESP_FUNC_COMPLETE:
++ case TMF_RESP_FUNC_FAILED:
++ res = asd_clear_nexus(task);
++ break;
++ case TMF_RESP_INVALID_FRAME:
++ case TMF_RESP_OVERLAPPED_TAG:
++ case TMF_RESP_FUNC_ESUPP:
++ case TMF_RESP_NO_LUN:
++ goto out_done; break;
++ }
++ /* In the following we assume that the managing layer
++ * will _never_ make a mistake, when issuing ABORT TASK.
++ */
++ switch (res) {
++ default:
++ res = asd_clear_nexus(task);
++ /* fallthrough */
++ case TC_NO_ERROR + 0xFF00:
++ case TMF_RESP_FUNC_COMPLETE:
++ break;
++ /* The task hasn't been sent to the device xor we never got
++ * a (sane) Response IU for the ABORT TASK TMF.
++ */
++ case TF_NAK_RECV + 0xFF00:
++ res = TMF_RESP_INVALID_FRAME;
++ break;
++ case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */
++ res = TMF_RESP_FUNC_FAILED;
++ wait_for_completion_timeout(&tascb->completion,
++ AIC94XX_SCB_TIMEOUT);
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (task->task_state_flags & SAS_TASK_STATE_DONE)
++ res = TMF_RESP_FUNC_COMPLETE;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ goto out_done;
++ case TF_TMF_NO_TAG + 0xFF00:
++ case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
++ case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
++ res = TMF_RESP_FUNC_COMPLETE;
++ goto out_done;
++ case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
++ res = TMF_RESP_FUNC_ESUPP;
++ goto out;
++ }
++out_done:
++ if (res == TMF_RESP_FUNC_COMPLETE) {
++ task->lldd_task = NULL;
++ mb();
++ asd_ascb_free(tascb);
++ }
++out:
++ asd_ascb_free(ascb);
++ ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
++ return res;
++}
++
++/**
++ * asd_initiate_ssp_tmf -- send a TMF to an I_T_L or I_T_L_Q nexus
++ * @dev: pointer to struct domain_device of interest
++ * @lun: pointer to u8[8] which is the LUN
++ * @tmf: the TMF to be performed (see sas_task.h or the SAS spec)
++ * @index: the transaction context of the task to be queried if QT TMF
++ *
++ * This function is used to send ABORT TASK SET, CLEAR ACA,
++ * CLEAR TASK SET, LU RESET and QUERY TASK TMFs.
++ *
++ * No SCBs should be queued to the I_T_L nexus when this SCB is
++ * pending.
++ *
++ * Returns: TMF response code (see sas_task.h or the SAS spec)
++ */
++static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
++ int tmf, int index)
++{
++ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
++ struct asd_ascb *ascb;
++ int res = 1;
++ struct scb *scb;
++
++ if (!(dev->tproto & SAS_PROTO_SSP))
++ return TMF_RESP_FUNC_ESUPP;
++
++ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
++ if (!ascb)
++ return -ENOMEM;
++ scb = ascb->scb;
++
++ if (tmf == TMF_QUERY_TASK)
++ scb->header.opcode = QUERY_SSP_TASK;
++ else
++ scb->header.opcode = INITIATE_SSP_TMF;
++
++ scb->ssp_tmf.proto_conn_rate = (1 << 4); /* SSP */
++ scb->ssp_tmf.proto_conn_rate |= dev->linkrate;
++ /* SSP frame header */
++ scb->ssp_tmf.ssp_frame.frame_type = SSP_TASK;
++ memcpy(scb->ssp_tmf.ssp_frame.hashed_dest_addr,
++ dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
++ memcpy(scb->ssp_tmf.ssp_frame.hashed_src_addr,
++ dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
++ scb->ssp_tmf.ssp_frame.tptt = cpu_to_be16(0xFFFF);
++ /* SSP Task IU */
++ memcpy(scb->ssp_tmf.ssp_task.lun, lun, 8);
++ scb->ssp_tmf.ssp_task.tmf = tmf;
++
++ scb->ssp_tmf.sister_scb = cpu_to_le16(0xFFFF);
++ scb->ssp_tmf.conn_handle= cpu_to_le16((u16)(unsigned long)
++ dev->lldd_dev);
++ scb->ssp_tmf.retry_count = 1;
++ scb->ssp_tmf.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
++ if (tmf == TMF_QUERY_TASK)
++ scb->ssp_tmf.index = cpu_to_le16(index);
++
++ res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
++ asd_tmf_timedout);
++ if (res)
++ goto out_err;
++ wait_for_completion(&ascb->completion);
++ res = (int) (unsigned long) ascb->uldd_task;
++
++ switch (res) {
++ case TC_NO_ERROR + 0xFF00:
++ res = TMF_RESP_FUNC_COMPLETE;
++ break;
++ case TF_NAK_RECV + 0xFF00:
++ res = TMF_RESP_INVALID_FRAME;
++ break;
++ case TF_TMF_TASK_DONE + 0xFF00:
++ res = TMF_RESP_FUNC_FAILED;
++ break;
++ case TF_TMF_NO_TAG + 0xFF00:
++ case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
++ case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
++ res = TMF_RESP_FUNC_COMPLETE;
++ break;
++ case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
++ res = TMF_RESP_FUNC_ESUPP;
++ break;
++ default:
++ ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n",
++ __FUNCTION__, res);
++ res = TMF_RESP_FUNC_FAILED;
++ break;
++ }
++out_err:
++ asd_ascb_free(ascb);
++ return res;
++}
++
++int asd_abort_task_set(struct domain_device *dev, u8 *lun)
++{
++ int res = asd_initiate_ssp_tmf(dev, lun, TMF_ABORT_TASK_SET, 0);
++
++ if (res == TMF_RESP_FUNC_COMPLETE)
++ asd_clear_nexus_I_T_L(dev, lun);
++ return res;
++}
++
++int asd_clear_aca(struct domain_device *dev, u8 *lun)
++{
++ int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0);
++
++ if (res == TMF_RESP_FUNC_COMPLETE)
++ asd_clear_nexus_I_T_L(dev, lun);
++ return res;
++}
++
++int asd_clear_task_set(struct domain_device *dev, u8 *lun)
++{
++ int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0);
++
++ if (res == TMF_RESP_FUNC_COMPLETE)
++ asd_clear_nexus_I_T_L(dev, lun);
++ return res;
++}
++
++int asd_lu_reset(struct domain_device *dev, u8 *lun)
++{
++ int res = asd_initiate_ssp_tmf(dev, lun, TMF_LU_RESET, 0);
++
++ if (res == TMF_RESP_FUNC_COMPLETE)
++ asd_clear_nexus_I_T_L(dev, lun);
++ return res;
++}
++
++/**
++ * asd_query_task -- send a QUERY TASK TMF to an I_T_L_Q nexus
++ * task: pointer to sas_task struct of interest
++ *
++ * Returns: TMF_RESP_FUNC_COMPLETE if the task is not in the task set,
++ * or TMF_RESP_FUNC_SUCC if the task is in the task set.
++ *
++ * Normally the management layer sets the task to aborted state,
++ * and then calls query task and then abort task.
++ */
++int asd_query_task(struct sas_task *task)
++{
++ struct asd_ascb *ascb = task->lldd_task;
++ int index;
++
++ if (ascb) {
++ index = ascb->tc_index;
++ return asd_initiate_ssp_tmf(task->dev, task->ssp_task.LUN,
++ TMF_QUERY_TASK, index);
++ }
++ return TMF_RESP_FUNC_COMPLETE;
++}
+diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
+index 1b63759..7cd63a9 100644
+--- a/drivers/scsi/amiga7xx.h
++++ b/drivers/scsi/amiga7xx.h
+@@ -8,7 +8,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *,
+ int NCR53c7xx_abort(Scsi_Cmnd *);
+ int NCR53c7x0_release (struct Scsi_Host *);
+ int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
++void NCR53c7x0_intr(int irq, void *dev_id);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 3
+diff --git a/drivers/scsi/arcmsr/Makefile b/drivers/scsi/arcmsr/Makefile
+new file mode 100644
+index 0000000..721aced
+--- /dev/null
++++ b/drivers/scsi/arcmsr/Makefile
+@@ -0,0 +1,6 @@
++# File: drivers/arcmsr/Makefile
++# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
++
++arcmsr-objs := arcmsr_attr.o arcmsr_hba.o
++
++obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o
+diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
+new file mode 100644
+index 0000000..aff96db
+--- /dev/null
++++ b/drivers/scsi/arcmsr/arcmsr.h
+@@ -0,0 +1,472 @@
++/*
++*******************************************************************************
++** O.S : Linux
++** FILE NAME : arcmsr.h
++** BY : Erich Chen
++** Description: SCSI RAID Device Driver for
++** ARECA RAID Host adapter
++*******************************************************************************
++** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
++**
++** Web site: www.areca.com.tw
++** E-mail: erich at areca.com.tw
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License version 2 as
++** published by the Free Software Foundation.
++** This 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.
++*******************************************************************************
++** 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. The name of the author may not be used to endorse or promote products
++** derived from this software without specific prior written permission.
++**
++** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
++*******************************************************************************
++*/
++#include <linux/interrupt.h>
++
++struct class_device_attribute;
++
++#define ARCMSR_MAX_OUTSTANDING_CMD 256
++#define ARCMSR_MAX_FREECCB_NUM 288
++#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13"
++#define ARCMSR_SCSI_INITIATOR_ID 255
++#define ARCMSR_MAX_XFER_SECTORS 512
++#define ARCMSR_MAX_TARGETID 17
++#define ARCMSR_MAX_TARGETLUN 8
++#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
++#define ARCMSR_MAX_QBUFFER 4096
++#define ARCMSR_MAX_SG_ENTRIES 38
++
++/*
++*******************************************************************************
++** split 64bits dma addressing
++*******************************************************************************
++*/
++#define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16)
++#define dma_addr_lo32(addr) (uint32_t) (addr & 0xffffffff)
++/*
++*******************************************************************************
++** MESSAGE CONTROL CODE
++*******************************************************************************
++*/
++struct CMD_MESSAGE
++{
++ uint32_t HeaderLength;
++ uint8_t Signature[8];
++ uint32_t Timeout;
++ uint32_t ControlCode;
++ uint32_t ReturnCode;
++ uint32_t Length;
++};
++/*
++*******************************************************************************
++** IOP Message Transfer Data for user space
++*******************************************************************************
++*/
++struct CMD_MESSAGE_FIELD
++{
++ struct CMD_MESSAGE cmdmessage;
++ uint8_t messagedatabuffer[1032];
++};
++/* IOP message transfer */
++#define ARCMSR_MESSAGE_FAIL 0x0001
++/* DeviceType */
++#define ARECA_SATA_RAID 0x90000000
++/* FunctionCode */
++#define FUNCTION_READ_RQBUFFER 0x0801
++#define FUNCTION_WRITE_WQBUFFER 0x0802
++#define FUNCTION_CLEAR_RQBUFFER 0x0803
++#define FUNCTION_CLEAR_WQBUFFER 0x0804
++#define FUNCTION_CLEAR_ALLQBUFFER 0x0805
++#define FUNCTION_RETURN_CODE_3F 0x0806
++#define FUNCTION_SAY_HELLO 0x0807
++#define FUNCTION_SAY_GOODBYE 0x0808
++#define FUNCTION_FLUSH_ADAPTER_CACHE 0x0809
++/* ARECA IO CONTROL CODE*/
++#define ARCMSR_MESSAGE_READ_RQBUFFER \
++ ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
++#define ARCMSR_MESSAGE_WRITE_WQBUFFER \
++ ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
++#define ARCMSR_MESSAGE_CLEAR_RQBUFFER \
++ ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
++#define ARCMSR_MESSAGE_CLEAR_WQBUFFER \
++ ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
++#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER \
++ ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
++#define ARCMSR_MESSAGE_RETURN_CODE_3F \
++ ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
++#define ARCMSR_MESSAGE_SAY_HELLO \
++ ARECA_SATA_RAID | FUNCTION_SAY_HELLO
++#define ARCMSR_MESSAGE_SAY_GOODBYE \
++ ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
++#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
++ ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
++/* ARECA IOCTL ReturnCode */
++#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001
++#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006
++#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F
++/*
++*************************************************************
++** structure for holding DMA address data
++*************************************************************
++*/
++#define IS_SG64_ADDR 0x01000000 /* bit24 */
++struct SG32ENTRY
++{
++ uint32_t length;
++ uint32_t address;
++};
++struct SG64ENTRY
++{
++ uint32_t length;
++ uint32_t address;
++ uint32_t addresshigh;
++};
++struct SGENTRY_UNION
++{
++ union
++ {
++ struct SG32ENTRY sg32entry;
++ struct SG64ENTRY sg64entry;
++ }u;
++};
++/*
++********************************************************************
++** Q Buffer of IOP Message Transfer
++********************************************************************
++*/
++struct QBUFFER
++{
++ uint32_t data_len;
++ uint8_t data[124];
++};
++/*
++*******************************************************************************
++** FIRMWARE INFO
++*******************************************************************************
++*/
++struct FIRMWARE_INFO
++{
++ uint32_t signature; /*0, 00-03*/
++ uint32_t request_len; /*1, 04-07*/
++ uint32_t numbers_queue; /*2, 08-11*/
++ uint32_t sdram_size; /*3, 12-15*/
++ uint32_t ide_channels; /*4, 16-19*/
++ char vendor[40]; /*5, 20-59*/
++ char model[8]; /*15, 60-67*/
++ char firmware_ver[16]; /*17, 68-83*/
++ char device_map[16]; /*21, 84-99*/
++};
++/* signature of set and get firmware config */
++#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
++#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
++/* message code of inbound message register */
++#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
++#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
++#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002
++#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003
++#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004
++#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE 0x00000005
++#define ARCMSR_INBOUND_MESG0_START_BGRB 0x00000006
++#define ARCMSR_INBOUND_MESG0_CHK331PENDING 0x00000007
++#define ARCMSR_INBOUND_MESG0_SYNC_TIMER 0x00000008
++/* doorbell interrupt generator */
++#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK 0x00000001
++#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK 0x00000002
++#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK 0x00000001
++#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK 0x00000002
++/* ccb areca cdb flag */
++#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000
++#define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000
++#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000
++#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
++/* outbound firmware ok */
++#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
++/*
++*******************************************************************************
++** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
++*******************************************************************************
++*/
++struct ARCMSR_CDB
++{
++ uint8_t Bus;
++ uint8_t TargetID;
++ uint8_t LUN;
++ uint8_t Function;
++
++ uint8_t CdbLength;
++ uint8_t sgcount;
++ uint8_t Flags;
++#define ARCMSR_CDB_FLAG_SGL_BSIZE 0x01
++#define ARCMSR_CDB_FLAG_BIOS 0x02
++#define ARCMSR_CDB_FLAG_WRITE 0x04
++#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00
++#define ARCMSR_CDB_FLAG_HEADQ 0x08
++#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
++ uint8_t Reserved1;
++
++ uint32_t Context;
++ uint32_t DataLength;
++
++ uint8_t Cdb[16];
++
++ uint8_t DeviceStatus;
++#define ARCMSR_DEV_CHECK_CONDITION 0x02
++#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
++#define ARCMSR_DEV_ABORTED 0xF1
++#define ARCMSR_DEV_INIT_FAIL 0xF2
++ uint8_t SenseData[15];
++
++ union
++ {
++ struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
++ struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES];
++ } u;
++};
++/*
++*******************************************************************************
++** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
++*******************************************************************************
++*/
++struct MessageUnit
++{
++ uint32_t resrved0[4]; /*0000 000F*/
++ uint32_t inbound_msgaddr0; /*0010 0013*/
++ uint32_t inbound_msgaddr1; /*0014 0017*/
++ uint32_t outbound_msgaddr0; /*0018 001B*/
++ uint32_t outbound_msgaddr1; /*001C 001F*/
++ uint32_t inbound_doorbell; /*0020 0023*/
++ uint32_t inbound_intstatus; /*0024 0027*/
++ uint32_t inbound_intmask; /*0028 002B*/
++ uint32_t outbound_doorbell; /*002C 002F*/
++ uint32_t outbound_intstatus; /*0030 0033*/
++ uint32_t outbound_intmask; /*0034 0037*/
++ uint32_t reserved1[2]; /*0038 003F*/
++ uint32_t inbound_queueport; /*0040 0043*/
++ uint32_t outbound_queueport; /*0044 0047*/
++ uint32_t reserved2[2]; /*0048 004F*/
++ uint32_t reserved3[492]; /*0050 07FF 492*/
++ uint32_t reserved4[128]; /*0800 09FF 128*/
++ uint32_t message_rwbuffer[256]; /*0a00 0DFF 256*/
++ uint32_t message_wbuffer[32]; /*0E00 0E7F 32*/
++ uint32_t reserved5[32]; /*0E80 0EFF 32*/
++ uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/
++ uint32_t reserved6[32]; /*0F80 0FFF 32*/
++};
++/*
++*******************************************************************************
++** Adapter Control Block
++*******************************************************************************
++*/
++struct AdapterControlBlock
++{
++ struct pci_dev * pdev;
++ struct Scsi_Host * host;
++ unsigned long vir2phy_offset;
++ /* Offset is used in making arc cdb physical to virtual calculations */
++ uint32_t outbound_int_enable;
++
++ struct MessageUnit __iomem * pmu;
++ /* message unit ATU inbound base address0 */
++
++ uint32_t acb_flags;
++#define ACB_F_SCSISTOPADAPTER 0x0001
++#define ACB_F_MSG_STOP_BGRB 0x0002
++ /* stop RAID background rebuild */
++#define ACB_F_MSG_START_BGRB 0x0004
++ /* stop RAID background rebuild */
++#define ACB_F_IOPDATA_OVERFLOW 0x0008
++ /* iop message data rqbuffer overflow */
++#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
++ /* message clear wqbuffer */
++#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
++ /* message clear rqbuffer */
++#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
++#define ACB_F_BUS_RESET 0x0080
++#define ACB_F_IOP_INITED 0x0100
++ /* iop init */
++
++ struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
++ /* used for memory free */
++ struct list_head ccb_free_list;
++ /* head of free ccb list */
++ atomic_t ccboutstandingcount;
++
++ void * dma_coherent;
++ /* dma_coherent used for memory free */
++ dma_addr_t dma_coherent_handle;
++ /* dma_coherent_handle used for memory free */
++
++ uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
++ /* data collection buffer for read from 80331 */
++ int32_t rqbuf_firstindex;
++ /* first of read buffer */
++ int32_t rqbuf_lastindex;
++ /* last of read buffer */
++ uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
++ /* data collection buffer for write to 80331 */
++ int32_t wqbuf_firstindex;
++ /* first of write buffer */
++ int32_t wqbuf_lastindex;
++ /* last of write buffer */
++ uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
++ /* id0 ..... id15, lun0...lun7 */
++#define ARECA_RAID_GONE 0x55
++#define ARECA_RAID_GOOD 0xaa
++ uint32_t num_resets;
++ uint32_t num_aborts;
++ uint32_t firm_request_len;
++ uint32_t firm_numbers_queue;
++ uint32_t firm_sdram_size;
++ uint32_t firm_hd_channels;
++ char firm_model[12];
++ char firm_version[20];
++};/* HW_DEVICE_EXTENSION */
++/*
++*******************************************************************************
++** Command Control Block
++** this CCB length must be 32 bytes boundary
++*******************************************************************************
++*/
++struct CommandControlBlock
++{
++ struct ARCMSR_CDB arcmsr_cdb;
++ /*
++ ** 0-503 (size of CDB=504):
++ ** arcmsr messenger scsi command descriptor size 504 bytes
++ */
++ uint32_t cdb_shifted_phyaddr;
++ /* 504-507 */
++ uint32_t reserved1;
++ /* 508-511 */
++#if BITS_PER_LONG == 64
++ /* ======================512+64 bytes======================== */
++ struct list_head list;
++ /* 512-527 16 bytes next/prev ptrs for ccb lists */
++ struct scsi_cmnd * pcmd;
++ /* 528-535 8 bytes pointer of linux scsi command */
++ struct AdapterControlBlock * acb;
++ /* 536-543 8 bytes pointer of acb */
++
++ uint16_t ccb_flags;
++ /* 544-545 */
++ #define CCB_FLAG_READ 0x0000
++ #define CCB_FLAG_WRITE 0x0001
++ #define CCB_FLAG_ERROR 0x0002
++ #define CCB_FLAG_FLUSHCACHE 0x0004
++ #define CCB_FLAG_MASTER_ABORTED 0x0008
++ uint16_t startdone;
++ /* 546-547 */
++ #define ARCMSR_CCB_DONE 0x0000
++ #define ARCMSR_CCB_START 0x55AA
++ #define ARCMSR_CCB_ABORTED 0xAA55
++ #define ARCMSR_CCB_ILLEGAL 0xFFFF
++ uint32_t reserved2[7];
++ /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
++#else
++ /* ======================512+32 bytes======================== */
++ struct list_head list;
++ /* 512-519 8 bytes next/prev ptrs for ccb lists */
++ struct scsi_cmnd * pcmd;
++ /* 520-523 4 bytes pointer of linux scsi command */
++ struct AdapterControlBlock * acb;
++ /* 524-527 4 bytes pointer of acb */
++
++ uint16_t ccb_flags;
++ /* 528-529 */
++ #define CCB_FLAG_READ 0x0000
++ #define CCB_FLAG_WRITE 0x0001
++ #define CCB_FLAG_ERROR 0x0002
++ #define CCB_FLAG_FLUSHCACHE 0x0004
++ #define CCB_FLAG_MASTER_ABORTED 0x0008
++ uint16_t startdone;
++ /* 530-531 */
++ #define ARCMSR_CCB_DONE 0x0000
++ #define ARCMSR_CCB_START 0x55AA
++ #define ARCMSR_CCB_ABORTED 0xAA55
++ #define ARCMSR_CCB_ILLEGAL 0xFFFF
++ uint32_t reserved2[3];
++ /* 532-535 536-539 540-543 */
++#endif
++ /* ========================================================== */
++};
++/*
++*******************************************************************************
++** ARECA SCSI sense data
++*******************************************************************************
++*/
++struct SENSE_DATA
++{
++ uint8_t ErrorCode:7;
++#define SCSI_SENSE_CURRENT_ERRORS 0x70
++#define SCSI_SENSE_DEFERRED_ERRORS 0x71
++ uint8_t Valid:1;
++ uint8_t SegmentNumber;
++ uint8_t SenseKey:4;
++ uint8_t Reserved:1;
++ uint8_t IncorrectLength:1;
++ uint8_t EndOfMedia:1;
++ uint8_t FileMark:1;
++ uint8_t Information[4];
++ uint8_t AdditionalSenseLength;
++ uint8_t CommandSpecificInformation[4];
++ uint8_t AdditionalSenseCode;
++ uint8_t AdditionalSenseCodeQualifier;
++ uint8_t FieldReplaceableUnitCode;
++ uint8_t SenseKeySpecific[3];
++};
++/*
++*******************************************************************************
++** Outbound Interrupt Status Register - OISR
++*******************************************************************************
++*/
++#define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG 0x30
++#define ARCMSR_MU_OUTBOUND_PCI_INT 0x10
++#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT 0x08
++#define ARCMSR_MU_OUTBOUND_DOORBELL_INT 0x04
++#define ARCMSR_MU_OUTBOUND_MESSAGE1_INT 0x02
++#define ARCMSR_MU_OUTBOUND_MESSAGE0_INT 0x01
++#define ARCMSR_MU_OUTBOUND_HANDLE_INT \
++ (ARCMSR_MU_OUTBOUND_MESSAGE0_INT \
++ |ARCMSR_MU_OUTBOUND_MESSAGE1_INT \
++ |ARCMSR_MU_OUTBOUND_DOORBELL_INT \
++ |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT \
++ |ARCMSR_MU_OUTBOUND_PCI_INT)
++/*
++*******************************************************************************
++** Outbound Interrupt Mask Register - OIMR
++*******************************************************************************
++*/
++#define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG 0x34
++#define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE 0x10
++#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE 0x08
++#define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE 0x04
++#define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE 0x02
++#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
++#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
++
++extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
++extern struct class_device_attribute *arcmsr_host_attrs[];
++extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
++void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
++
+diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
+new file mode 100644
+index 0000000..12497da
+--- /dev/null
++++ b/drivers/scsi/arcmsr/arcmsr_attr.c
+@@ -0,0 +1,381 @@
++/*
++*******************************************************************************
++** O.S : Linux
++** FILE NAME : arcmsr_attr.c
++** BY : Erich Chen
++** Description: attributes exported to sysfs and device host
++*******************************************************************************
++** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
++**
++** Web site: www.areca.com.tw
++** E-mail: erich at areca.com.tw
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License version 2 as
++** published by the Free Software Foundation.
++** This 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.
++*******************************************************************************
++** 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. The name of the author may not be used to endorse or promote products
++** derived from this software without specific prior written permission.
++**
++** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
++*******************************************************************************
++** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
++** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
++*******************************************************************************
++*/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_transport.h>
++#include "arcmsr.h"
++
++struct class_device_attribute *arcmsr_host_attrs[];
++
++static ssize_t
++arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
++ size_t count)
++{
++ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ struct MessageUnit __iomem *reg = acb->pmu;
++ uint8_t *pQbuffer,*ptmpQbuffer;
++ int32_t allxfer_len = 0;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ /* do message unit read. */
++ ptmpQbuffer = (uint8_t *)buf;
++ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
++ && (allxfer_len < 1031)) {
++ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
++ memcpy(ptmpQbuffer, pQbuffer, 1);
++ acb->rqbuf_firstindex++;
++ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
++ ptmpQbuffer++;
++ allxfer_len++;
++ }
++ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
++ struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
++ ®->message_rbuffer;
++ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
++ int32_t iop_len;
++
++ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
++ iop_len = readl(&prbuffer->data_len);
++ while (iop_len > 0) {
++ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
++ acb->rqbuf_lastindex++;
++ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
++ iop_data++;
++ iop_len--;
++ }
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
++ ®->inbound_doorbell);
++ }
++ return (allxfer_len);
++}
++
++static ssize_t
++arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
++ size_t count)
++{
++ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
++ uint8_t *pQbuffer, *ptmpuserbuffer;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++ if (count > 1032)
++ return -EINVAL;
++ /* do message unit write. */
++ ptmpuserbuffer = (uint8_t *)buf;
++ user_len = (int32_t)count;
++ wqbuf_lastindex = acb->wqbuf_lastindex;
++ wqbuf_firstindex = acb->wqbuf_firstindex;
++ if (wqbuf_lastindex != wqbuf_firstindex) {
++ arcmsr_post_Qbuffer(acb);
++ return 0; /*need retry*/
++ } else {
++ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
++ &(ARCMSR_MAX_QBUFFER - 1);
++ if (my_empty_len >= user_len) {
++ while (user_len > 0) {
++ pQbuffer =
++ &acb->wqbuffer[acb->wqbuf_lastindex];
++ memcpy(pQbuffer, ptmpuserbuffer, 1);
++ acb->wqbuf_lastindex++;
++ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
++ ptmpuserbuffer++;
++ user_len--;
++ }
++ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
++ acb->acb_flags &=
++ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
++ arcmsr_post_Qbuffer(acb);
++ }
++ return count;
++ } else {
++ return 0; /*need retry*/
++ }
++ }
++}
++
++static ssize_t
++arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off,
++ size_t count)
++{
++ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ struct MessageUnit __iomem *reg = acb->pmu;
++ uint8_t *pQbuffer;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
++ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
++ , ®->inbound_doorbell);
++ }
++ acb->acb_flags |=
++ (ACB_F_MESSAGE_WQBUFFER_CLEARED
++ | ACB_F_MESSAGE_RQBUFFER_CLEARED
++ | ACB_F_MESSAGE_WQBUFFER_READED);
++ acb->rqbuf_firstindex = 0;
++ acb->rqbuf_lastindex = 0;
++ acb->wqbuf_firstindex = 0;
++ acb->wqbuf_lastindex = 0;
++ pQbuffer = acb->rqbuffer;
++ memset(pQbuffer, 0, sizeof (struct QBUFFER));
++ pQbuffer = acb->wqbuffer;
++ memset(pQbuffer, 0, sizeof (struct QBUFFER));
++ return 1;
++}
++
++static struct bin_attribute arcmsr_sysfs_message_read_attr = {
++ .attr = {
++ .name = "mu_read",
++ .mode = S_IRUSR ,
++ .owner = THIS_MODULE,
++ },
++ .size = 1032,
++ .read = arcmsr_sysfs_iop_message_read,
++};
++
++static struct bin_attribute arcmsr_sysfs_message_write_attr = {
++ .attr = {
++ .name = "mu_write",
++ .mode = S_IWUSR,
++ .owner = THIS_MODULE,
++ },
++ .size = 1032,
++ .write = arcmsr_sysfs_iop_message_write,
++};
++
++static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
++ .attr = {
++ .name = "mu_clear",
++ .mode = S_IWUSR,
++ .owner = THIS_MODULE,
++ },
++ .size = 1,
++ .write = arcmsr_sysfs_iop_message_clear,
++};
++
++int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
++{
++ struct Scsi_Host *host = acb->host;
++ int error;
++
++ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_read_attr);
++ if (error) {
++ printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
++ goto error_bin_file_message_read;
++ }
++ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_write_attr);
++ if (error) {
++ printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
++ goto error_bin_file_message_write;
++ }
++ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_clear_attr);
++ if (error) {
++ printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
++ goto error_bin_file_message_clear;
++ }
++ return 0;
++error_bin_file_message_clear:
++ sysfs_remove_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_write_attr);
++error_bin_file_message_write:
++ sysfs_remove_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_read_attr);
++error_bin_file_message_read:
++ return error;
++}
++
++void
++arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
++ struct Scsi_Host *host = acb->host;
++
++ sysfs_remove_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_clear_attr);
++ sysfs_remove_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_write_attr);
++ sysfs_remove_bin_file(&host->shost_classdev.kobj,
++ &arcmsr_sysfs_message_read_attr);
++}
++
++
++static ssize_t
++arcmsr_attr_host_driver_version(struct class_device *cdev, char *buf) {
++ return snprintf(buf, PAGE_SIZE,
++ "%s\n",
++ ARCMSR_DRIVER_VERSION);
++}
++
++static ssize_t
++arcmsr_attr_host_driver_posted_cmd(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ atomic_read(&acb->ccboutstandingcount));
++}
++
++static ssize_t
++arcmsr_attr_host_driver_reset(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ acb->num_resets);
++}
++
++static ssize_t
++arcmsr_attr_host_driver_abort(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ acb->num_aborts);
++}
++
++static ssize_t
++arcmsr_attr_host_fw_model(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++ return snprintf(buf, PAGE_SIZE,
++ "%s\n",
++ acb->firm_model);
++}
++
++static ssize_t
++arcmsr_attr_host_fw_version(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++
++ return snprintf(buf, PAGE_SIZE,
++ "%s\n",
++ acb->firm_version);
++}
++
++static ssize_t
++arcmsr_attr_host_fw_request_len(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ acb->firm_request_len);
++}
++
++static ssize_t
++arcmsr_attr_host_fw_numbers_queue(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ acb->firm_numbers_queue);
++}
++
++static ssize_t
++arcmsr_attr_host_fw_sdram_size(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ acb->firm_sdram_size);
++}
++
++static ssize_t
++arcmsr_attr_host_fw_hd_channels(struct class_device *cdev, char *buf) {
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
++
++ return snprintf(buf, PAGE_SIZE,
++ "%4d\n",
++ acb->firm_hd_channels);
++}
++
++static CLASS_DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
++static CLASS_DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL);
++static CLASS_DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL);
++static CLASS_DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL);
++static CLASS_DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
++static CLASS_DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
++static CLASS_DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
++static CLASS_DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
++static CLASS_DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
++static CLASS_DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
++
++struct class_device_attribute *arcmsr_host_attrs[] = {
++ &class_device_attr_host_driver_version,
++ &class_device_attr_host_driver_posted_cmd,
++ &class_device_attr_host_driver_reset,
++ &class_device_attr_host_driver_abort,
++ &class_device_attr_host_fw_model,
++ &class_device_attr_host_fw_version,
++ &class_device_attr_host_fw_request_len,
++ &class_device_attr_host_fw_numbers_queue,
++ &class_device_attr_host_fw_sdram_size,
++ &class_device_attr_host_fw_hd_channels,
++ NULL,
++};
+diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
+new file mode 100644
+index 0000000..086cc97
+--- /dev/null
++++ b/drivers/scsi/arcmsr/arcmsr_hba.c
+@@ -0,0 +1,1495 @@
++/*
++*******************************************************************************
++** O.S : Linux
++** FILE NAME : arcmsr_hba.c
++** BY : Erich Chen
++** Description: SCSI RAID Device Driver for
++** ARECA RAID Host adapter
++*******************************************************************************
++** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
++**
++** Web site: www.areca.com.tw
++** E-mail: erich at areca.com.tw
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License version 2 as
++** published by the Free Software Foundation.
++** This 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.
++*******************************************************************************
++** 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. The name of the author may not be used to endorse or promote products
++** derived from this software without specific prior written permission.
++**
++** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
++*******************************************************************************
++** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
++** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
++*******************************************************************************
++*/
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/spinlock.h>
++#include <linux/pci_ids.h>
++#include <linux/interrupt.h>
++#include <linux/moduleparam.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/timer.h>
++#include <linux/pci.h>
++#include <asm/dma.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_tcq.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsicam.h>
++#include "arcmsr.h"
++
++MODULE_AUTHOR("Erich Chen <erich at areca.com.tw>");
++MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_VERSION(ARCMSR_DRIVER_VERSION);
++
++static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
++static int arcmsr_abort(struct scsi_cmnd *);
++static int arcmsr_bus_reset(struct scsi_cmnd *);
++static int arcmsr_bios_param(struct scsi_device *sdev,
++ struct block_device *bdev, sector_t capacity, int *info);
++static int arcmsr_queue_command(struct scsi_cmnd * cmd,
++ void (*done) (struct scsi_cmnd *));
++static int arcmsr_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id);
++static void arcmsr_remove(struct pci_dev *pdev);
++static void arcmsr_shutdown(struct pci_dev *pdev);
++static void arcmsr_iop_init(struct AdapterControlBlock *acb);
++static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
++static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
++static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
++static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
++static const char *arcmsr_info(struct Scsi_Host *);
++static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
++
++static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
++{
++ if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
++ queue_depth = ARCMSR_MAX_CMD_PERLUN;
++ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
++ return queue_depth;
++}
++
++static struct scsi_host_template arcmsr_scsi_host_template = {
++ .module = THIS_MODULE,
++ .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
++ .info = arcmsr_info,
++ .queuecommand = arcmsr_queue_command,
++ .eh_abort_handler = arcmsr_abort,
++ .eh_bus_reset_handler = arcmsr_bus_reset,
++ .bios_param = arcmsr_bios_param,
++ .change_queue_depth = arcmsr_adjust_disk_queue_depth,
++ .can_queue = ARCMSR_MAX_OUTSTANDING_CMD,
++ .this_id = ARCMSR_SCSI_INITIATOR_ID,
++ .sg_tablesize = ARCMSR_MAX_SG_ENTRIES,
++ .max_sectors = ARCMSR_MAX_XFER_SECTORS,
++ .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
++ .use_clustering = ENABLE_CLUSTERING,
++ .shost_attrs = arcmsr_host_attrs,
++};
++
++static struct pci_device_id arcmsr_device_id_table[] = {
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
++ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
++ {0, 0}, /* Terminating entry */
++};
++MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
++static struct pci_driver arcmsr_pci_driver = {
++ .name = "arcmsr",
++ .id_table = arcmsr_device_id_table,
++ .probe = arcmsr_probe,
++ .remove = arcmsr_remove,
++ .shutdown = arcmsr_shutdown
++};
++
++static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
++{
++ irqreturn_t handle_state;
++ struct AdapterControlBlock *acb;
++ unsigned long flags;
++
++ acb = (struct AdapterControlBlock *)dev_id;
++
++ spin_lock_irqsave(acb->host->host_lock, flags);
++ handle_state = arcmsr_interrupt(acb);
++ spin_unlock_irqrestore(acb->host->host_lock, flags);
++ return handle_state;
++}
++
++static int arcmsr_bios_param(struct scsi_device *sdev,
++ struct block_device *bdev, sector_t capacity, int *geom)
++{
++ int ret, heads, sectors, cylinders, total_capacity;
++ unsigned char *buffer;/* return copy of block device's partition table */
++
++ buffer = scsi_bios_ptable(bdev);
++ if (buffer) {
++ ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
++ kfree(buffer);
++ if (ret != -1)
++ return ret;
++ }
++ total_capacity = capacity;
++ heads = 64;
++ sectors = 32;
++ cylinders = total_capacity / (heads * sectors);
++ if (cylinders > 1024) {
++ heads = 255;
++ sectors = 63;
++ cylinders = total_capacity / (heads * sectors);
++ }
++ geom[0] = heads;
++ geom[1] = sectors;
++ geom[2] = cylinders;
++ return 0;
++}
++
++static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
++{
++ struct pci_dev *pdev = acb->pdev;
++ struct MessageUnit __iomem *reg = acb->pmu;
++ u32 ccb_phyaddr_hi32;
++ void *dma_coherent;
++ dma_addr_t dma_coherent_handle, dma_addr;
++ struct CommandControlBlock *ccb_tmp;
++ int i, j;
++
++ dma_coherent = dma_alloc_coherent(&pdev->dev,
++ ARCMSR_MAX_FREECCB_NUM *
++ sizeof (struct CommandControlBlock) + 0x20,
++ &dma_coherent_handle, GFP_KERNEL);
++ if (!dma_coherent)
++ return -ENOMEM;
++
++ acb->dma_coherent = dma_coherent;
++ acb->dma_coherent_handle = dma_coherent_handle;
++
++ if (((unsigned long)dma_coherent & 0x1F)) {
++ dma_coherent = dma_coherent +
++ (0x20 - ((unsigned long)dma_coherent & 0x1F));
++ dma_coherent_handle = dma_coherent_handle +
++ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
++ }
++
++ dma_addr = dma_coherent_handle;
++ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
++ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
++ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
++ ccb_tmp->acb = acb;
++ acb->pccb_pool[i] = ccb_tmp;
++ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
++ dma_addr = dma_addr + sizeof (struct CommandControlBlock);
++ ccb_tmp++;
++ }
++
++ acb->vir2phy_offset = (unsigned long)ccb_tmp -
++ (unsigned long)dma_addr;
++ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
++ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
++ acb->devstate[i][j] = ARECA_RAID_GOOD;
++
++ /*
++ ** here we need to tell iop 331 our ccb_tmp.HighPart
++ ** if ccb_tmp.HighPart is not zero
++ */
++ ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
++ if (ccb_phyaddr_hi32 != 0) {
++ writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->message_rwbuffer[0]);
++ writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]);
++ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0);
++ if (arcmsr_wait_msgint_ready(acb))
++ printk(KERN_NOTICE "arcmsr%d: "
++ "'set ccb high part physical address' timeout\n",
++ acb->host->host_no);
++ }
++
++ writel(readl(®->outbound_intmask) |
++ ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
++ ®->outbound_intmask);
++ return 0;
++}
++
++static int arcmsr_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct Scsi_Host *host;
++ struct AdapterControlBlock *acb;
++ uint8_t bus, dev_fun;
++ int error;
++
++ error = pci_enable_device(pdev);
++ if (error)
++ goto out;
++ pci_set_master(pdev);
++
++ host = scsi_host_alloc(&arcmsr_scsi_host_template,
++ sizeof(struct AdapterControlBlock));
++ if (!host) {
++ error = -ENOMEM;
++ goto out_disable_device;
++ }
++ acb = (struct AdapterControlBlock *)host->hostdata;
++ memset(acb, 0, sizeof (struct AdapterControlBlock));
++
++ error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
++ if (error) {
++ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (error) {
++ printk(KERN_WARNING
++ "scsi%d: No suitable DMA mask available\n",
++ host->host_no);
++ goto out_host_put;
++ }
++ }
++ bus = pdev->bus->number;
++ dev_fun = pdev->devfn;
++ acb->host = host;
++ acb->pdev = pdev;
++ host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
++ host->max_lun = ARCMSR_MAX_TARGETLUN;
++ host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
++ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
++ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
++ host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
++ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
++ host->this_id = ARCMSR_SCSI_INITIATOR_ID;
++ host->unique_id = (bus << 8) | dev_fun;
++ host->irq = pdev->irq;
++ error = pci_request_regions(pdev, "arcmsr");
++ if (error)
++ goto out_host_put;
++
++ acb->pmu = ioremap(pci_resource_start(pdev, 0),
++ pci_resource_len(pdev, 0));
++ if (!acb->pmu) {
++ printk(KERN_NOTICE "arcmsr%d: memory"
++ " mapping region fail \n", acb->host->host_no);
++ goto out_release_regions;
++ }
++ acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
++ ACB_F_MESSAGE_RQBUFFER_CLEARED |
++ ACB_F_MESSAGE_WQBUFFER_READED);
++ acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
++ INIT_LIST_HEAD(&acb->ccb_free_list);
++
++ error = arcmsr_alloc_ccb_pool(acb);
++ if (error)
++ goto out_iounmap;
++
++ error = request_irq(pdev->irq, arcmsr_do_interrupt,
++ SA_INTERRUPT | SA_SHIRQ, "arcmsr", acb);
++ if (error)
++ goto out_free_ccb_pool;
++
++ arcmsr_iop_init(acb);
++ pci_set_drvdata(pdev, host);
++
++ error = scsi_add_host(host, &pdev->dev);
++ if (error)
++ goto out_free_irq;
++
++ error = arcmsr_alloc_sysfs_attr(acb);
++ if (error)
++ goto out_free_sysfs;
++
++ scsi_scan_host(host);
++ return 0;
++ out_free_sysfs:
++ out_free_irq:
++ free_irq(pdev->irq, acb);
++ out_free_ccb_pool:
++ arcmsr_free_ccb_pool(acb);
++ out_iounmap:
++ iounmap(acb->pmu);
++ out_release_regions:
++ pci_release_regions(pdev);
++ out_host_put:
++ scsi_host_put(host);
++ out_disable_device:
++ pci_disable_device(pdev);
++ out:
++ return error;
++}
++
++static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++
++ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0);
++ if (arcmsr_wait_msgint_ready(acb))
++ printk(KERN_NOTICE
++ "arcmsr%d: wait 'abort all outstanding command' timeout \n"
++ , acb->host->host_no);
++}
++
++static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
++{
++ struct AdapterControlBlock *acb = ccb->acb;
++ struct scsi_cmnd *pcmd = ccb->pcmd;
++
++ if (pcmd->use_sg != 0) {
++ struct scatterlist *sl;
++
++ sl = (struct scatterlist *)pcmd->request_buffer;
++ pci_unmap_sg(acb->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction);
++ }
++ else if (pcmd->request_bufflen != 0)
++ pci_unmap_single(acb->pdev,
++ pcmd->SCp.dma_handle,
++ pcmd->request_bufflen, pcmd->sc_data_direction);
++}
++
++static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
++{
++ struct AdapterControlBlock *acb = ccb->acb;
++ struct scsi_cmnd *pcmd = ccb->pcmd;
++
++ arcmsr_pci_unmap_dma(ccb);
++ if (stand_flag == 1)
++ atomic_dec(&acb->ccboutstandingcount);
++ ccb->startdone = ARCMSR_CCB_DONE;
++ ccb->ccb_flags = 0;
++ list_add_tail(&ccb->list, &acb->ccb_free_list);
++ pcmd->scsi_done(pcmd);
++}
++
++static void arcmsr_remove(struct pci_dev *pdev)
++{
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ struct AdapterControlBlock *acb =
++ (struct AdapterControlBlock *) host->hostdata;
++ struct MessageUnit __iomem *reg = acb->pmu;
++ int poll_count = 0;
++
++ arcmsr_free_sysfs_attr(acb);
++ scsi_remove_host(host);
++ arcmsr_stop_adapter_bgrb(acb);
++ arcmsr_flush_adapter_cache(acb);
++ writel(readl(®->outbound_intmask) |
++ ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
++ ®->outbound_intmask);
++ acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
++ acb->acb_flags &= ~ACB_F_IOP_INITED;
++
++ for (poll_count = 0; poll_count < 256; poll_count++) {
++ if (!atomic_read(&acb->ccboutstandingcount))
++ break;
++ arcmsr_interrupt(acb);
++ msleep(25);
++ }
++
++ if (atomic_read(&acb->ccboutstandingcount)) {
++ int i;
++
++ arcmsr_abort_allcmd(acb);
++ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
++ readl(®->outbound_queueport);
++ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
++ struct CommandControlBlock *ccb = acb->pccb_pool[i];
++ if (ccb->startdone == ARCMSR_CCB_START) {
++ ccb->startdone = ARCMSR_CCB_ABORTED;
++ ccb->pcmd->result = DID_ABORT << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ }
++ }
++
++ free_irq(pdev->irq, acb);
++ iounmap(acb->pmu);
++ arcmsr_free_ccb_pool(acb);
++ pci_release_regions(pdev);
++
++ scsi_host_put(host);
++
++ pci_disable_device(pdev);
++ pci_set_drvdata(pdev, NULL);
++}
++
++static void arcmsr_shutdown(struct pci_dev *pdev)
++{
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ struct AdapterControlBlock *acb =
++ (struct AdapterControlBlock *)host->hostdata;
++
++ arcmsr_stop_adapter_bgrb(acb);
++ arcmsr_flush_adapter_cache(acb);
++}
++
++static int arcmsr_module_init(void)
++{
++ int error = 0;
++
++ error = pci_register_driver(&arcmsr_pci_driver);
++ return error;
++}
++
++static void arcmsr_module_exit(void)
++{
++ pci_unregister_driver(&arcmsr_pci_driver);
++}
++module_init(arcmsr_module_init);
++module_exit(arcmsr_module_exit);
++
++static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ u32 orig_mask = readl(®->outbound_intmask);
++
++ writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
++ ®->outbound_intmask);
++ return orig_mask;
++}
++
++static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
++ u32 orig_mask)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ u32 mask;
++
++ mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
++ ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
++ writel(mask, ®->outbound_intmask);
++}
++
++static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg=acb->pmu;
++
++ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0);
++ if (arcmsr_wait_msgint_ready(acb))
++ printk(KERN_NOTICE
++ "arcmsr%d: wait 'flush adapter cache' timeout \n"
++ , acb->host->host_no);
++}
++
++static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
++{
++ struct scsi_cmnd *pcmd = ccb->pcmd;
++ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
++
++ pcmd->result = DID_OK << 16;
++ if (sensebuffer) {
++ int sense_data_length =
++ sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
++ ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
++ memset(sensebuffer, 0, sizeof (pcmd->sense_buffer));
++ memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
++ sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
++ sensebuffer->Valid = 1;
++ }
++}
++
++static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ uint32_t Index;
++ uint8_t Retries = 0x00;
++
++ do {
++ for (Index = 0; Index < 100; Index++) {
++ if (readl(®->outbound_intstatus)
++ & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
++ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
++ , ®->outbound_intstatus);
++ return 0x00;
++ }
++ msleep_interruptible(10);
++ }/*max 1 seconds*/
++ } while (Retries++ < 20);/*max 20 sec*/
++ return 0xff;
++}
++
++static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
++ struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
++{
++ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
++ int8_t *psge = (int8_t *)&arcmsr_cdb->u;
++ uint32_t address_lo, address_hi;
++ int arccdbsize = 0x30;
++
++ ccb->pcmd = pcmd;
++ memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
++ arcmsr_cdb->Bus = 0;
++ arcmsr_cdb->TargetID = pcmd->device->id;
++ arcmsr_cdb->LUN = pcmd->device->lun;
++ arcmsr_cdb->Function = 1;
++ arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
++ arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
++ memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
++ if (pcmd->use_sg) {
++ int length, sgcount, i, cdb_sgcount = 0;
++ struct scatterlist *sl;
++
++ /* Get Scatter Gather List from scsiport. */
++ sl = (struct scatterlist *) pcmd->request_buffer;
++ sgcount = pci_map_sg(acb->pdev, sl, pcmd->use_sg,
++ pcmd->sc_data_direction);
++ /* map stor port SG list to our iop SG List. */
++ for (i = 0; i < sgcount; i++) {
++ /* Get the physical address of the current data pointer */
++ length = cpu_to_le32(sg_dma_len(sl));
++ address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl)));
++ address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl)));
++ if (address_hi == 0) {
++ struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
++
++ pdma_sg->address = address_lo;
++ pdma_sg->length = length;
++ psge += sizeof (struct SG32ENTRY);
++ arccdbsize += sizeof (struct SG32ENTRY);
++ } else {
++ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
++
++ pdma_sg->addresshigh = address_hi;
++ pdma_sg->address = address_lo;
++ pdma_sg->length = length|IS_SG64_ADDR;
++ psge += sizeof (struct SG64ENTRY);
++ arccdbsize += sizeof (struct SG64ENTRY);
++ }
++ sl++;
++ cdb_sgcount++;
++ }
++ arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
++ arcmsr_cdb->DataLength = pcmd->request_bufflen;
++ if ( arccdbsize > 256)
++ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
++ } else if (pcmd->request_bufflen) {
++ dma_addr_t dma_addr;
++ dma_addr = pci_map_single(acb->pdev, pcmd->request_buffer,
++ pcmd->request_bufflen, pcmd->sc_data_direction);
++ pcmd->SCp.dma_handle = dma_addr;
++ address_lo = cpu_to_le32(dma_addr_lo32(dma_addr));
++ address_hi = cpu_to_le32(dma_addr_hi32(dma_addr));
++ if (address_hi == 0) {
++ struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
++ pdma_sg->address = address_lo;
++ pdma_sg->length = pcmd->request_bufflen;
++ } else {
++ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
++ pdma_sg->addresshigh = address_hi;
++ pdma_sg->address = address_lo;
++ pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR;
++ }
++ arcmsr_cdb->sgcount = 1;
++ arcmsr_cdb->DataLength = pcmd->request_bufflen;
++ }
++ if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
++ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
++ ccb->ccb_flags |= CCB_FLAG_WRITE;
++ }
++}
++
++static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
++ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
++
++ atomic_inc(&acb->ccboutstandingcount);
++ ccb->startdone = ARCMSR_CCB_START;
++ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
++ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
++ ®->inbound_queueport);
++ else
++ writel(cdb_shifted_phyaddr, ®->inbound_queueport);
++}
++
++void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer;
++ uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
++ int32_t allxfer_len = 0;
++
++ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
++ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
++ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
++ && (allxfer_len < 124)) {
++ writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
++ acb->wqbuf_firstindex++;
++ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
++ iop_data++;
++ allxfer_len++;
++ }
++ writel(allxfer_len, &pwbuffer->data_len);
++ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
++ , ®->inbound_doorbell);
++ }
++}
++
++static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++
++ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
++ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0);
++ if (arcmsr_wait_msgint_ready(acb))
++ printk(KERN_NOTICE
++ "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
++ , acb->host->host_no);
++}
++
++static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
++{
++ dma_free_coherent(&acb->pdev->dev,
++ ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
++ acb->dma_coherent,
++ acb->dma_coherent_handle);
++}
++
++static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ struct CommandControlBlock *ccb;
++ uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
++
++ outbound_intstatus = readl(®->outbound_intstatus)
++ & acb->outbound_int_enable;
++ writel(outbound_intstatus, ®->outbound_intstatus);
++ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
++ outbound_doorbell = readl(®->outbound_doorbell);
++ writel(outbound_doorbell, ®->outbound_doorbell);
++ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
++ struct QBUFFER __iomem * prbuffer =
++ (struct QBUFFER __iomem *) ®->message_rbuffer;
++ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
++ int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
++
++ rqbuf_lastindex = acb->rqbuf_lastindex;
++ rqbuf_firstindex = acb->rqbuf_firstindex;
++ iop_len = readl(&prbuffer->data_len);
++ my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
++ &(ARCMSR_MAX_QBUFFER - 1);
++ if (my_empty_len >= iop_len) {
++ while (iop_len > 0) {
++ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
++ acb->rqbuf_lastindex++;
++ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
++ iop_data++;
++ iop_len--;
++ }
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
++ ®->inbound_doorbell);
++ } else
++ acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
++ }
++ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
++ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
++ if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
++ struct QBUFFER __iomem * pwbuffer =
++ (struct QBUFFER __iomem *) ®->message_wbuffer;
++ uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
++ int32_t allxfer_len = 0;
++
++ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
++ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
++ && (allxfer_len < 124)) {
++ writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
++ acb->wqbuf_firstindex++;
++ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
++ iop_data++;
++ allxfer_len++;
++ }
++ writel(allxfer_len, &pwbuffer->data_len);
++ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
++ ®->inbound_doorbell);
++ }
++ if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
++ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
++ }
++ }
++ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
++ int id, lun;
++ /*
++ ****************************************************************
++ ** areca cdb command done
++ ****************************************************************
++ */
++ while (1) {
++ if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF)
++ break;/*chip FIFO no ccb for completion already*/
++ /* check if command done with no error*/
++ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
++ (flag_ccb << 5));
++ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
++ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
++ struct scsi_cmnd *abortcmd=ccb->pcmd;
++ if (abortcmd) {
++ abortcmd->result |= DID_ABORT >> 16;
++ arcmsr_ccb_complete(ccb, 1);
++ printk(KERN_NOTICE
++ "arcmsr%d: ccb='0x%p' isr got aborted command \n"
++ , acb->host->host_no, ccb);
++ }
++ continue;
++ }
++ printk(KERN_NOTICE
++ "arcmsr%d: isr get an illegal ccb command done acb='0x%p'"
++ "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x"
++ " ccboutstandingcount=%d \n"
++ , acb->host->host_no
++ , acb
++ , ccb
++ , ccb->acb
++ , ccb->startdone
++ , atomic_read(&acb->ccboutstandingcount));
++ continue;
++ }
++ id = ccb->pcmd->device->id;
++ lun = ccb->pcmd->device->lun;
++ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
++ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
++ acb->devstate[id][lun] = ARECA_RAID_GOOD;
++ ccb->pcmd->result = DID_OK << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ } else {
++ switch(ccb->arcmsr_cdb.DeviceStatus) {
++ case ARCMSR_DEV_SELECT_TIMEOUT: {
++ acb->devstate[id][lun] = ARECA_RAID_GONE;
++ ccb->pcmd->result = DID_TIME_OUT << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ break;
++ case ARCMSR_DEV_ABORTED:
++ case ARCMSR_DEV_INIT_FAIL: {
++ acb->devstate[id][lun] = ARECA_RAID_GONE;
++ ccb->pcmd->result = DID_BAD_TARGET << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ break;
++ case ARCMSR_DEV_CHECK_CONDITION: {
++ acb->devstate[id][lun] = ARECA_RAID_GOOD;
++ arcmsr_report_sense_info(ccb);
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ break;
++ default:
++ printk(KERN_NOTICE
++ "arcmsr%d: scsi id=%d lun=%d"
++ " isr get command error done,"
++ "but got unknown DeviceStatus = 0x%x \n"
++ , acb->host->host_no
++ , id
++ , lun
++ , ccb->arcmsr_cdb.DeviceStatus);
++ acb->devstate[id][lun] = ARECA_RAID_GONE;
++ ccb->pcmd->result = DID_NO_CONNECT << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ break;
++ }
++ }
++ }/*drain reply FIFO*/
++ }
++ if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
++ return IRQ_NONE;
++ return IRQ_HANDLED;
++}
++
++static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
++{
++ if (acb) {
++ /* stop adapter background rebuild */
++ if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
++ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
++ arcmsr_stop_adapter_bgrb(acb);
++ arcmsr_flush_adapter_cache(acb);
++ }
++ }
++}
++
++static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ struct CMD_MESSAGE_FIELD *pcmdmessagefld;
++ int retvalue = 0, transfer_len = 0;
++ char *buffer;
++ uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
++ (uint32_t ) cmd->cmnd[6] << 16 |
++ (uint32_t ) cmd->cmnd[7] << 8 |
++ (uint32_t ) cmd->cmnd[8];
++ /* 4 bytes: Areca io control code */
++ if (cmd->use_sg) {
++ struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
++
++ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
++ if (cmd->use_sg > 1) {
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ goto message_out;
++ }
++ transfer_len += sg->length;
++ } else {
++ buffer = cmd->request_buffer;
++ transfer_len = cmd->request_bufflen;
++ }
++ if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ goto message_out;
++ }
++ pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
++ switch(controlcode) {
++ case ARCMSR_MESSAGE_READ_RQBUFFER: {
++ unsigned long *ver_addr;
++ dma_addr_t buf_handle;
++ uint8_t *pQbuffer, *ptmpQbuffer;
++ int32_t allxfer_len = 0;
++
++ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
++ if (!ver_addr) {
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ goto message_out;
++ }
++ ptmpQbuffer = (uint8_t *) ver_addr;
++ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
++ && (allxfer_len < 1031)) {
++ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
++ memcpy(ptmpQbuffer, pQbuffer, 1);
++ acb->rqbuf_firstindex++;
++ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
++ ptmpQbuffer++;
++ allxfer_len++;
++ }
++ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
++ struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
++ ®->message_rbuffer;
++ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
++ int32_t iop_len;
++
++ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
++ iop_len = readl(&prbuffer->data_len);
++ while (iop_len > 0) {
++ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
++ acb->rqbuf_lastindex++;
++ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
++ iop_data++;
++ iop_len--;
++ }
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
++ ®->inbound_doorbell);
++ }
++ memcpy(pcmdmessagefld->messagedatabuffer,
++ (uint8_t *)ver_addr, allxfer_len);
++ pcmdmessagefld->cmdmessage.Length = allxfer_len;
++ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
++ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
++ }
++ break;
++ case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
++ unsigned long *ver_addr;
++ dma_addr_t buf_handle;
++ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
++ uint8_t *pQbuffer, *ptmpuserbuffer;
++
++ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
++ if (!ver_addr) {
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ goto message_out;
++ }
++ ptmpuserbuffer = (uint8_t *)ver_addr;
++ user_len = pcmdmessagefld->cmdmessage.Length;
++ memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
++ wqbuf_lastindex = acb->wqbuf_lastindex;
++ wqbuf_firstindex = acb->wqbuf_firstindex;
++ if (wqbuf_lastindex != wqbuf_firstindex) {
++ struct SENSE_DATA *sensebuffer =
++ (struct SENSE_DATA *)cmd->sense_buffer;
++ arcmsr_post_Qbuffer(acb);
++ /* has error report sensedata */
++ sensebuffer->ErrorCode = 0x70;
++ sensebuffer->SenseKey = ILLEGAL_REQUEST;
++ sensebuffer->AdditionalSenseLength = 0x0A;
++ sensebuffer->AdditionalSenseCode = 0x20;
++ sensebuffer->Valid = 1;
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ } else {
++ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
++ &(ARCMSR_MAX_QBUFFER - 1);
++ if (my_empty_len >= user_len) {
++ while (user_len > 0) {
++ pQbuffer =
++ &acb->wqbuffer[acb->wqbuf_lastindex];
++ memcpy(pQbuffer, ptmpuserbuffer, 1);
++ acb->wqbuf_lastindex++;
++ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
++ ptmpuserbuffer++;
++ user_len--;
++ }
++ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
++ acb->acb_flags &=
++ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
++ arcmsr_post_Qbuffer(acb);
++ }
++ } else {
++ /* has error report sensedata */
++ struct SENSE_DATA *sensebuffer =
++ (struct SENSE_DATA *)cmd->sense_buffer;
++ sensebuffer->ErrorCode = 0x70;
++ sensebuffer->SenseKey = ILLEGAL_REQUEST;
++ sensebuffer->AdditionalSenseLength = 0x0A;
++ sensebuffer->AdditionalSenseCode = 0x20;
++ sensebuffer->Valid = 1;
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ }
++ }
++ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
++ }
++ break;
++ case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
++ uint8_t *pQbuffer = acb->rqbuffer;
++
++ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
++ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
++ ®->inbound_doorbell);
++ }
++ acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
++ acb->rqbuf_firstindex = 0;
++ acb->rqbuf_lastindex = 0;
++ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
++ pcmdmessagefld->cmdmessage.ReturnCode =
++ ARCMSR_MESSAGE_RETURNCODE_OK;
++ }
++ break;
++ case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
++ uint8_t *pQbuffer = acb->wqbuffer;
++
++ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
++ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
++ , ®->inbound_doorbell);
++ }
++ acb->acb_flags |=
++ (ACB_F_MESSAGE_WQBUFFER_CLEARED |
++ ACB_F_MESSAGE_WQBUFFER_READED);
++ acb->wqbuf_firstindex = 0;
++ acb->wqbuf_lastindex = 0;
++ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
++ pcmdmessagefld->cmdmessage.ReturnCode =
++ ARCMSR_MESSAGE_RETURNCODE_OK;
++ }
++ break;
++ case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
++ uint8_t *pQbuffer;
++
++ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
++ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
++ , ®->inbound_doorbell);
++ }
++ acb->acb_flags |=
++ (ACB_F_MESSAGE_WQBUFFER_CLEARED
++ | ACB_F_MESSAGE_RQBUFFER_CLEARED
++ | ACB_F_MESSAGE_WQBUFFER_READED);
++ acb->rqbuf_firstindex = 0;
++ acb->rqbuf_lastindex = 0;
++ acb->wqbuf_firstindex = 0;
++ acb->wqbuf_lastindex = 0;
++ pQbuffer = acb->rqbuffer;
++ memset(pQbuffer, 0, sizeof (struct QBUFFER));
++ pQbuffer = acb->wqbuffer;
++ memset(pQbuffer, 0, sizeof (struct QBUFFER));
++ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
++ }
++ break;
++ case ARCMSR_MESSAGE_RETURN_CODE_3F: {
++ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
++ }
++ break;
++ case ARCMSR_MESSAGE_SAY_HELLO: {
++ int8_t * hello_string = "Hello! I am ARCMSR";
++
++ memcpy(pcmdmessagefld->messagedatabuffer, hello_string
++ , (int16_t)strlen(hello_string));
++ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
++ }
++ break;
++ case ARCMSR_MESSAGE_SAY_GOODBYE:
++ arcmsr_iop_parking(acb);
++ break;
++ case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
++ arcmsr_flush_adapter_cache(acb);
++ break;
++ default:
++ retvalue = ARCMSR_MESSAGE_FAIL;
++ }
++ message_out:
++ if (cmd->use_sg) {
++ struct scatterlist *sg;
++
++ sg = (struct scatterlist *) cmd->request_buffer;
++ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
++ }
++ return retvalue;
++}
++
++static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb)
++{
++ struct list_head *head = &acb->ccb_free_list;
++ struct CommandControlBlock *ccb = NULL;
++
++ if (!list_empty(head)) {
++ ccb = list_entry(head->next, struct CommandControlBlock, list);
++ list_del(head->next);
++ }
++ return ccb;
++}
++
++static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
++ struct scsi_cmnd *cmd)
++{
++ switch (cmd->cmnd[0]) {
++ case INQUIRY: {
++ unsigned char inqdata[36];
++ char *buffer;
++
++ if (cmd->device->lun) {
++ cmd->result = (DID_TIME_OUT << 16);
++ cmd->scsi_done(cmd);
++ return;
++ }
++ inqdata[0] = TYPE_PROCESSOR;
++ /* Periph Qualifier & Periph Dev Type */
++ inqdata[1] = 0;
++ /* rem media bit & Dev Type Modifier */
++ inqdata[2] = 0;
++ /* ISO,ECMA,& ANSI versions */
++ inqdata[4] = 31;
++ /* length of additional data */
++ strncpy(&inqdata[8], "Areca ", 8);
++ /* Vendor Identification */
++ strncpy(&inqdata[16], "RAID controller ", 16);
++ /* Product Identification */
++ strncpy(&inqdata[32], "R001", 4); /* Product Revision */
++ if (cmd->use_sg) {
++ struct scatterlist *sg;
++
++ sg = (struct scatterlist *) cmd->request_buffer;
++ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
++ } else {
++ buffer = cmd->request_buffer;
++ }
++ memcpy(buffer, inqdata, sizeof(inqdata));
++ if (cmd->use_sg) {
++ struct scatterlist *sg;
++
++ sg = (struct scatterlist *) cmd->request_buffer;
++ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
++ }
++ cmd->scsi_done(cmd);
++ }
++ break;
++ case WRITE_BUFFER:
++ case READ_BUFFER: {
++ if (arcmsr_iop_message_xfer(acb, cmd))
++ cmd->result = (DID_ERROR << 16);
++ cmd->scsi_done(cmd);
++ }
++ break;
++ default:
++ cmd->scsi_done(cmd);
++ }
++}
++
++static int arcmsr_queue_command(struct scsi_cmnd *cmd,
++ void (* done)(struct scsi_cmnd *))
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct AdapterControlBlock *acb =
++ (struct AdapterControlBlock *) host->hostdata;
++ struct CommandControlBlock *ccb;
++ int target = cmd->device->id;
++ int lun = cmd->device->lun;
++
++ cmd->scsi_done = done;
++ cmd->host_scribble = NULL;
++ cmd->result = 0;
++ if (acb->acb_flags & ACB_F_BUS_RESET) {
++ printk(KERN_NOTICE "arcmsr%d: bus reset"
++ " and return busy \n"
++ , acb->host->host_no);
++ return SCSI_MLQUEUE_HOST_BUSY;
++ }
++ if(target == 16) {
++ /* virtual device for iop message transfer */
++ arcmsr_handle_virtual_command(acb, cmd);
++ return 0;
++ }
++ if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
++ uint8_t block_cmd;
++
++ block_cmd = cmd->cmnd[0] & 0x0f;
++ if (block_cmd == 0x08 || block_cmd == 0x0a) {
++ printk(KERN_NOTICE
++ "arcmsr%d: block 'read/write'"
++ "command with gone raid volume"
++ " Cmd=%2x, TargetId=%d, Lun=%d \n"
++ , acb->host->host_no
++ , cmd->cmnd[0]
++ , target, lun);
++ cmd->result = (DID_NO_CONNECT << 16);
++ cmd->scsi_done(cmd);
++ return 0;
++ }
++ }
++ if (atomic_read(&acb->ccboutstandingcount) >=
++ ARCMSR_MAX_OUTSTANDING_CMD)
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++ ccb = arcmsr_get_freeccb(acb);
++ if (!ccb)
++ return SCSI_MLQUEUE_HOST_BUSY;
++ arcmsr_build_ccb(acb, ccb, cmd);
++ arcmsr_post_ccb(acb, ccb);
++ return 0;
++}
++
++static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ char *acb_firm_model = acb->firm_model;
++ char *acb_firm_version = acb->firm_version;
++ char __iomem *iop_firm_model = (char __iomem *) ®->message_rwbuffer[15];
++ char __iomem *iop_firm_version = (char __iomem *) ®->message_rwbuffer[17];
++ int count;
++
++ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
++ if (arcmsr_wait_msgint_ready(acb))
++ printk(KERN_NOTICE
++ "arcmsr%d: wait "
++ "'get adapter firmware miscellaneous data' timeout \n"
++ , acb->host->host_no);
++ count = 8;
++ while (count) {
++ *acb_firm_model = readb(iop_firm_model);
++ acb_firm_model++;
++ iop_firm_model++;
++ count--;
++ }
++ count = 16;
++ while (count) {
++ *acb_firm_version = readb(iop_firm_version);
++ acb_firm_version++;
++ iop_firm_version++;
++ count--;
++ }
++ printk(KERN_INFO
++ "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
++ , acb->host->host_no
++ , acb->firm_version);
++ acb->firm_request_len = readl(®->message_rwbuffer[1]);
++ acb->firm_numbers_queue = readl(®->message_rwbuffer[2]);
++ acb->firm_sdram_size = readl(®->message_rwbuffer[3]);
++ acb->firm_hd_channels = readl(®->message_rwbuffer[4]);
++}
++
++static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
++ struct CommandControlBlock *poll_ccb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ struct CommandControlBlock *ccb;
++ uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
++ int id, lun;
++
++ polling_ccb_retry:
++ poll_count++;
++ outbound_intstatus = readl(®->outbound_intstatus)
++ & acb->outbound_int_enable;
++ writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/
++ while (1) {
++ if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) {
++ if (poll_ccb_done)
++ break;
++ else {
++ msleep(25);
++ if (poll_count > 100)
++ break;
++ goto polling_ccb_retry;
++ }
++ }
++ ccb = (struct CommandControlBlock *)
++ (acb->vir2phy_offset + (flag_ccb << 5));
++ if ((ccb->acb != acb) ||
++ (ccb->startdone != ARCMSR_CCB_START)) {
++ if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
++ (ccb == poll_ccb)) {
++ printk(KERN_NOTICE
++ "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'"
++ " poll command abort successfully \n"
++ , acb->host->host_no
++ , ccb->pcmd->device->id
++ , ccb->pcmd->device->lun
++ , ccb);
++ ccb->pcmd->result = DID_ABORT << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ poll_ccb_done = 1;
++ continue;
++ }
++ printk(KERN_NOTICE
++ "arcmsr%d: polling get an illegal ccb"
++ " command done ccb='0x%p'"
++ "ccboutstandingcount=%d \n"
++ , acb->host->host_no
++ , ccb
++ , atomic_read(&acb->ccboutstandingcount));
++ continue;
++ }
++ id = ccb->pcmd->device->id;
++ lun = ccb->pcmd->device->lun;
++ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
++ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
++ acb->devstate[id][lun] = ARECA_RAID_GOOD;
++ ccb->pcmd->result = DID_OK << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ } else {
++ switch(ccb->arcmsr_cdb.DeviceStatus) {
++ case ARCMSR_DEV_SELECT_TIMEOUT: {
++ acb->devstate[id][lun] = ARECA_RAID_GONE;
++ ccb->pcmd->result = DID_TIME_OUT << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ break;
++ case ARCMSR_DEV_ABORTED:
++ case ARCMSR_DEV_INIT_FAIL: {
++ acb->devstate[id][lun] = ARECA_RAID_GONE;
++ ccb->pcmd->result = DID_BAD_TARGET << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ break;
++ case ARCMSR_DEV_CHECK_CONDITION: {
++ acb->devstate[id][lun] = ARECA_RAID_GOOD;
++ arcmsr_report_sense_info(ccb);
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ break;
++ default:
++ printk(KERN_NOTICE
++ "arcmsr%d: scsi id=%d lun=%d"
++ " polling and getting command error done"
++ "but got unknown DeviceStatus = 0x%x \n"
++ , acb->host->host_no
++ , id
++ , lun
++ , ccb->arcmsr_cdb.DeviceStatus);
++ acb->devstate[id][lun] = ARECA_RAID_GONE;
++ ccb->pcmd->result = DID_BAD_TARGET << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ break;
++ }
++ }
++ }
++}
++
++static void arcmsr_iop_init(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
++
++ do {
++ firmware_state = readl(®->outbound_msgaddr1);
++ } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
++ intmask_org = readl(®->outbound_intmask)
++ | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
++ arcmsr_get_firmware_spec(acb);
++
++ acb->acb_flags |= ACB_F_MSG_START_BGRB;
++ writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0);
++ if (arcmsr_wait_msgint_ready(acb)) {
++ printk(KERN_NOTICE "arcmsr%d: "
++ "wait 'start adapter background rebulid' timeout\n",
++ acb->host->host_no);
++ }
++
++ outbound_doorbell = readl(®->outbound_doorbell);
++ writel(outbound_doorbell, ®->outbound_doorbell);
++ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell);
++ mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
++ | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
++ writel(intmask_org & mask, ®->outbound_intmask);
++ acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
++ acb->acb_flags |= ACB_F_IOP_INITED;
++}
++
++static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
++{
++ struct MessageUnit __iomem *reg = acb->pmu;
++ struct CommandControlBlock *ccb;
++ uint32_t intmask_org;
++ int i = 0;
++
++ if (atomic_read(&acb->ccboutstandingcount) != 0) {
++ /* talk to iop 331 outstanding command aborted */
++ arcmsr_abort_allcmd(acb);
++ /* wait for 3 sec for all command aborted*/
++ msleep_interruptible(3000);
++ /* disable all outbound interrupt */
++ intmask_org = arcmsr_disable_outbound_ints(acb);
++ /* clear all outbound posted Q */
++ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
++ readl(®->outbound_queueport);
++ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
++ ccb = acb->pccb_pool[i];
++ if ((ccb->startdone == ARCMSR_CCB_START) ||
++ (ccb->startdone == ARCMSR_CCB_ABORTED)) {
++ ccb->startdone = ARCMSR_CCB_ABORTED;
++ ccb->pcmd->result = DID_ABORT << 16;
++ arcmsr_ccb_complete(ccb, 1);
++ }
++ }
++ /* enable all outbound interrupt */
++ arcmsr_enable_outbound_ints(acb, intmask_org);
++ }
++ atomic_set(&acb->ccboutstandingcount, 0);
++}
++
++static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
++{
++ struct AdapterControlBlock *acb =
++ (struct AdapterControlBlock *)cmd->device->host->hostdata;
++ int i;
++
++ acb->num_resets++;
++ acb->acb_flags |= ACB_F_BUS_RESET;
++ for (i = 0; i < 400; i++) {
++ if (!atomic_read(&acb->ccboutstandingcount))
++ break;
++ arcmsr_interrupt(acb);
++ msleep(25);
++ }
++ arcmsr_iop_reset(acb);
++ acb->acb_flags &= ~ACB_F_BUS_RESET;
++ return SUCCESS;
++}
++
++static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
++ struct CommandControlBlock *ccb)
++{
++ u32 intmask;
++
++ ccb->startdone = ARCMSR_CCB_ABORTED;
++
++ /*
++ ** Wait for 3 sec for all command done.
++ */
++ msleep_interruptible(3000);
++
++ intmask = arcmsr_disable_outbound_ints(acb);
++ arcmsr_polling_ccbdone(acb, ccb);
++ arcmsr_enable_outbound_ints(acb, intmask);
++}
++
++static int arcmsr_abort(struct scsi_cmnd *cmd)
++{
++ struct AdapterControlBlock *acb =
++ (struct AdapterControlBlock *)cmd->device->host->hostdata;
++ int i = 0;
++
++ printk(KERN_NOTICE
++ "arcmsr%d: abort device command of scsi id=%d lun=%d \n",
++ acb->host->host_no, cmd->device->id, cmd->device->lun);
++ acb->num_aborts++;
++
++ /*
++ ************************************************
++ ** the all interrupt service routine is locked
++ ** we need to handle it as soon as possible and exit
++ ************************************************
++ */
++ if (!atomic_read(&acb->ccboutstandingcount))
++ return SUCCESS;
++
++ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
++ struct CommandControlBlock *ccb = acb->pccb_pool[i];
++ if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
++ arcmsr_abort_one_cmd(acb, ccb);
++ break;
++ }
++ }
++
++ return SUCCESS;
++}
++
++static const char *arcmsr_info(struct Scsi_Host *host)
++{
++ struct AdapterControlBlock *acb =
++ (struct AdapterControlBlock *) host->hostdata;
++ static char buf[256];
++ char *type;
++ int raid6 = 1;
++
++ switch (acb->pdev->device) {
++ case PCI_DEVICE_ID_ARECA_1110:
++ case PCI_DEVICE_ID_ARECA_1210:
++ raid6 = 0;
++ /*FALLTHRU*/
++ case PCI_DEVICE_ID_ARECA_1120:
++ case PCI_DEVICE_ID_ARECA_1130:
++ case PCI_DEVICE_ID_ARECA_1160:
++ case PCI_DEVICE_ID_ARECA_1170:
++ case PCI_DEVICE_ID_ARECA_1220:
++ case PCI_DEVICE_ID_ARECA_1230:
++ case PCI_DEVICE_ID_ARECA_1260:
++ case PCI_DEVICE_ID_ARECA_1270:
++ case PCI_DEVICE_ID_ARECA_1280:
++ type = "SATA";
++ break;
++ case PCI_DEVICE_ID_ARECA_1380:
++ case PCI_DEVICE_ID_ARECA_1381:
++ case PCI_DEVICE_ID_ARECA_1680:
++ case PCI_DEVICE_ID_ARECA_1681:
++ type = "SAS";
++ break;
++ default:
++ type = "X-TYPE";
++ break;
++ }
++ sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
++ type, raid6 ? "( RAID6 capable)" : "",
++ ARCMSR_DRIVER_VERSION);
++ return buf;
++}
++
++
+diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
+index 7621e3f..9cf902b 100644
+--- a/drivers/scsi/arm/acornscsi.c
++++ b/drivers/scsi/arm/acornscsi.c
+@@ -194,7 +194,8 @@
+ unsigned int sdtr_period = SDTR_PERIOD;
+ unsigned int sdtr_size = SDTR_SIZE;
+
+-static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
++static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
++ unsigned int result);
+ static int acornscsi_reconnect_finish(AS_Host *host);
+ static void acornscsi_dma_cleanup(AS_Host *host);
+ static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
+@@ -712,7 +713,7 @@ static
+ intr_ret_t acornscsi_kick(AS_Host *host)
+ {
+ int from_queue = 0;
+- Scsi_Cmnd *SCpnt;
++ struct scsi_cmnd *SCpnt;
+
+ /* first check to see if a command is waiting to be executed */
+ SCpnt = host->origSCpnt;
+@@ -796,15 +797,15 @@ intr_ret_t acornscsi_kick(AS_Host *host)
+ }
+
+ /*
+- * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
++ * Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result)
+ * Purpose : complete processing for command
+ * Params : host - interface that completed
+ * result - driver byte of result
+ */
+-static
+-void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
++static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
++ unsigned int result)
+ {
+- Scsi_Cmnd *SCpnt = *SCpntp;
++ struct scsi_cmnd *SCpnt = *SCpntp;
+
+ /* clean up */
+ sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+@@ -1318,7 +1319,7 @@ acornscsi_write_pio(AS_Host *host, char
+ static void
+ acornscsi_sendcommand(AS_Host *host)
+ {
+- Scsi_Cmnd *SCpnt = host->SCpnt;
++ struct scsi_cmnd *SCpnt = host->SCpnt;
+
+ sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);
+ sbic_arm_writenext(host->scsi.io_port, 0);
+@@ -1693,7 +1694,7 @@ void acornscsi_message(AS_Host *host)
+ acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+ msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
+ } else {
+- Scsi_Cmnd *SCpnt = host->SCpnt;
++ struct scsi_cmnd *SCpnt = host->SCpnt;
+
+ acornscsi_dma_cleanup(host);
+
+@@ -2460,14 +2461,13 @@ intr_ret_t acornscsi_sbicintr(AS_Host *h
+ }
+
+ /*
+- * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
++ * Prototype: void acornscsi_intr(int irq, void *dev_id)
+ * Purpose : handle interrupts from Acorn SCSI card
+ * Params : irq - interrupt number
+ * dev_id - device specific data (AS_Host structure)
+- * regs - processor registers when interrupt occurred
+ */
+ static irqreturn_t
+-acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
++acornscsi_intr(int irq, void *dev_id)
+ {
+ AS_Host *host = (AS_Host *)dev_id;
+ intr_ret_t ret;
+@@ -2509,13 +2509,14 @@ acornscsi_intr(int irq, void *dev_id, st
+ */
+
+ /*
+- * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
++ * Function : acornscsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+ * Purpose : queues a SCSI command
+ * Params : cmd - SCSI command
+ * done - function called on completion, with pointer to command descriptor
+ * Returns : 0, or < 0 on error.
+ */
+-int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
++ void (*done)(struct scsi_cmnd *))
+ {
+ AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+
+@@ -2565,17 +2566,18 @@ int acornscsi_queuecmd(Scsi_Cmnd *SCpnt,
+ }
+
+ /*
+- * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
++ * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
+ * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
+ * Params : SCpntp1 - pointer to command to return
+ * SCpntp2 - pointer to command to check
+ * result - result to pass back to mid-level done function
+ * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
+ */
+-static inline
+-void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
++static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1,
++ struct scsi_cmnd **SCpntp2,
++ int result)
+ {
+- Scsi_Cmnd *SCpnt = *SCpntp1;
++ struct scsi_cmnd *SCpnt = *SCpntp1;
+
+ if (SCpnt) {
+ *SCpntp1 = NULL;
+@@ -2591,13 +2593,12 @@ void acornscsi_reportstatus(Scsi_Cmnd **
+ enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
+ /*
+- * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
++ * Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt)
+ * Purpose : abort a command on this host
+ * Params : SCpnt - command to abort
+ * Returns : our abort status
+ */
+-static enum res_abort
+-acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
++static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt)
+ {
+ enum res_abort res = res_not_running;
+
+@@ -2684,12 +2685,12 @@ acornscsi_do_abort(AS_Host *host, Scsi_C
+ }
+
+ /*
+- * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
++ * Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt)
+ * Purpose : abort a command on this host
+ * Params : SCpnt - command to abort
+ * Returns : one of SCSI_ABORT_ macros
+ */
+-int acornscsi_abort(Scsi_Cmnd *SCpnt)
++int acornscsi_abort(struct scsi_cmnd *SCpnt)
+ {
+ AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
+ int result;
+@@ -2770,16 +2771,16 @@ int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ }
+
+ /*
+- * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
++ * Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
+ * Purpose : reset a command on this host/reset this host
+ * Params : SCpnt - command causing reset
+ * result - what type of reset to perform
+ * Returns : one of SCSI_RESET_ macros
+ */
+-int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
++int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
+ {
+- AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+- Scsi_Cmnd *SCptr;
++ AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
++ struct scsi_cmnd *SCptr;
+
+ host->stats.resets += 1;
+
+diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
+index 2142290..d11424b 100644
+--- a/drivers/scsi/arm/acornscsi.h
++++ b/drivers/scsi/arm/acornscsi.h
+@@ -277,8 +277,8 @@ struct status_entry {
+ typedef struct acornscsi_hostdata {
+ /* miscellaneous */
+ struct Scsi_Host *host; /* host */
+- Scsi_Cmnd *SCpnt; /* currently processing command */
+- Scsi_Cmnd *origSCpnt; /* original connecting command */
++ struct scsi_cmnd *SCpnt; /* currently processing command */
++ struct scsi_cmnd *origSCpnt; /* original connecting command */
+
+ /* driver information */
+ struct {
+diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
+index a289401..4385e9e 100644
+--- a/drivers/scsi/arm/arxescsi.c
++++ b/drivers/scsi/arm/arxescsi.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/drivers/scsi/arxescsi.c
++ * linux/drivers/scsi/arm/arxescsi.c
+ *
+ * Copyright (C) 1997-2000 Russell King, Stefan Hanske
+ *
+diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
+index 719af0d..19edd9c 100644
+--- a/drivers/scsi/arm/cumana_2.c
++++ b/drivers/scsi/arm/cumana_2.c
+@@ -137,10 +137,9 @@ cumanascsi_2_terminator_ctl(struct Scsi_
+ * Purpose : handle interrupts from Cumana SCSI 2 card
+ * Params : irq - interrupt number
+ * dev_id - user-defined (Scsi_Host structure)
+- * regs - processor registers at interrupt
+ */
+ static irqreturn_t
+-cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
++cumanascsi_2_intr(int irq, void *dev_id)
+ {
+ struct cumanascsi2_info *info = dev_id;
+
+diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
+index dcbb4b2..3f876fb 100644
+--- a/drivers/scsi/arm/eesox.c
++++ b/drivers/scsi/arm/eesox.c
+@@ -138,10 +138,9 @@ eesoxscsi_terminator_ctl(struct Scsi_Hos
+ * Purpose : handle interrupts from EESOX SCSI card
+ * Params : irq - interrupt number
+ * dev_id - user-defined (Scsi_Host structure)
+- * regs - processor registers at interrupt
+ */
+ static irqreturn_t
+-eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
++eesoxscsi_intr(int irq, void *dev_id)
+ {
+ struct eesoxscsi_info *info = dev_id;
+
+diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
+index 4cf7afc..e05f0c2 100644
+--- a/drivers/scsi/arm/fas216.c
++++ b/drivers/scsi/arm/fas216.c
+@@ -297,8 +297,8 @@ fas216_do_log(FAS216_Info *info, char ta
+ printk("scsi%d.%c: %s", info->host->host_no, target, buf);
+ }
+
+-static void
+-fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
++static void fas216_log_command(FAS216_Info *info, int level,
++ struct scsi_cmnd *SCpnt, char *fmt, ...)
+ {
+ va_list args;
+
+@@ -1662,7 +1662,7 @@ irqreturn_t fas216_intr(FAS216_Info *inf
+ return handled;
+ }
+
+-static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
++static void __fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
+ {
+ int tot_msglen;
+
+@@ -1754,7 +1754,7 @@ static int parity_test(FAS216_Info *info
+ return info->device[target].parity_check;
+ }
+
+-static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
++static void fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
+ {
+ int disconnect_ok;
+
+@@ -1808,7 +1808,7 @@ static void fas216_start_command(FAS216_
+ __fas216_start_command(info, SCpnt);
+ }
+
+-static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
++static void fas216_allocate_tag(FAS216_Info *info, struct scsi_cmnd *SCpnt)
+ {
+ #ifdef SCSI2_TAG
+ /*
+@@ -1842,7 +1842,8 @@ static void fas216_allocate_tag(FAS216_I
+ }
+ }
+
+-static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
++static void fas216_do_bus_device_reset(FAS216_Info *info,
++ struct scsi_cmnd *SCpnt)
+ {
+ struct message *msg;
+
+@@ -1890,7 +1891,7 @@ static void fas216_do_bus_device_reset(F
+ */
+ static void fas216_kick(FAS216_Info *info)
+ {
+- Scsi_Cmnd *SCpnt = NULL;
++ struct scsi_cmnd *SCpnt = NULL;
+ #define TYPE_OTHER 0
+ #define TYPE_RESET 1
+ #define TYPE_QUEUE 2
+@@ -1978,8 +1979,8 @@ static void fas216_kick(FAS216_Info *inf
+ /*
+ * Clean up from issuing a BUS DEVICE RESET message to a device.
+ */
+-static void
+-fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
++static void fas216_devicereset_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
++ unsigned int result)
+ {
+ fas216_log(info, LOG_ERROR, "fas216 device reset complete");
+
+@@ -1996,8 +1997,8 @@ fas216_devicereset_done(FAS216_Info *inf
+ *
+ * Finish processing automatic request sense command
+ */
+-static void
+-fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
++static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
++ unsigned int result)
+ {
+ fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
+ "request sense complete, result=0x%04x%02x%02x",
+@@ -2030,7 +2031,7 @@ fas216_rq_sns_done(FAS216_Info *info, Sc
+ * Finish processing of standard command
+ */
+ static void
+-fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
++fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
+ {
+ info->stats.fins += 1;
+
+@@ -2142,8 +2143,8 @@ request_sense:
+ */
+ static void fas216_done(FAS216_Info *info, unsigned int result)
+ {
+- void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
+- Scsi_Cmnd *SCpnt;
++ void (*fn)(FAS216_Info *, struct scsi_cmnd *, unsigned int);
++ struct scsi_cmnd *SCpnt;
+ unsigned long flags;
+
+ fas216_checkmagic(info);
+@@ -2182,7 +2183,7 @@ static void fas216_done(FAS216_Info *inf
+ info->device[SCpnt->device->id].parity_check = 0;
+ clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+
+- fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
++ fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble;
+ fn(info, SCpnt, result);
+
+ if (info->scsi.irq != NO_IRQ) {
+@@ -2207,7 +2208,8 @@ no_command:
+ * Returns: 0 on success, else error.
+ * Notes: io_request_lock is held, interrupts are disabled.
+ */
+-int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++int fas216_queue_command(struct scsi_cmnd *SCpnt,
++ void (*done)(struct scsi_cmnd *))
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+ int result;
+@@ -2254,7 +2256,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpn
+ *
+ * Trigger restart of a waiting thread in fas216_command
+ */
+-static void fas216_internal_done(Scsi_Cmnd *SCpnt)
++static void fas216_internal_done(struct scsi_cmnd *SCpnt)
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+@@ -2271,7 +2273,8 @@ static void fas216_internal_done(Scsi_Cm
+ * Returns: scsi result code.
+ * Notes: io_request_lock is held, interrupts are disabled.
+ */
+-int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
++ void (*done)(struct scsi_cmnd *))
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+@@ -2350,7 +2353,8 @@ enum res_find {
+ * Decide how to abort a command.
+ * Returns: abort status
+ */
+-static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
++static enum res_find fas216_find_command(FAS216_Info *info,
++ struct scsi_cmnd *SCpnt)
+ {
+ enum res_find res = res_failed;
+
+@@ -2417,7 +2421,7 @@ static enum res_find fas216_find_command
+ * Returns: FAILED if unable to abort
+ * Notes: io_request_lock is taken, and irqs are disabled
+ */
+-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
++int fas216_eh_abort(struct scsi_cmnd *SCpnt)
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+ int result = FAILED;
+@@ -2474,7 +2478,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Notes: We won't be re-entered, so we'll only have one device
+ * reset on the go at one time.
+ */
+-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
++int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+ unsigned long flags;
+@@ -2555,7 +2559,7 @@ int fas216_eh_device_reset(Scsi_Cmnd *SC
+ * Returns: FAILED if unable to reset.
+ * Notes: Further commands are blocked.
+ */
+-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
++int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+ unsigned long flags;
+@@ -2655,7 +2659,7 @@ static void fas216_init_chip(FAS216_Info
+ * Returns: FAILED if unable to reset.
+ * Notes: io_request_lock is taken, and irqs are disabled
+ */
+-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
++int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
+ {
+ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
+index 540914d..00e5f05 100644
+--- a/drivers/scsi/arm/fas216.h
++++ b/drivers/scsi/arm/fas216.h
+@@ -218,11 +218,11 @@ typedef struct {
+ unsigned long magic_start;
+ spinlock_t host_lock;
+ struct Scsi_Host *host; /* host */
+- Scsi_Cmnd *SCpnt; /* currently processing command */
+- Scsi_Cmnd *origSCpnt; /* original connecting command */
+- Scsi_Cmnd *reqSCpnt; /* request sense command */
+- Scsi_Cmnd *rstSCpnt; /* reset command */
+- Scsi_Cmnd *pending_SCpnt[8]; /* per-device pending commands */
++ struct scsi_cmnd *SCpnt; /* currently processing command */
++ struct scsi_cmnd *origSCpnt; /* original connecting command */
++ struct scsi_cmnd *reqSCpnt; /* request sense command */
++ struct scsi_cmnd *rstSCpnt; /* reset command */
++ struct scsi_cmnd *pending_SCpnt[8]; /* per-device pending commands */
+ int next_pending; /* next pending device */
+
+ /*
+@@ -328,21 +328,23 @@ extern int fas216_init (struct Scsi_Host
+ */
+ extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
+
+-/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+ * Purpose : queue a command for adapter to process.
+ * Params : SCpnt - Command to queue
+ * done - done function to call once command is complete
+ * Returns : 0 - success, else error
+ */
+-extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
++extern int fas216_queue_command(struct scsi_cmnd *,
++ void (*done)(struct scsi_cmnd *));
+
+-/* Function: int fas216_noqueue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+ * Purpose : queue a command for adapter to process, and process it to completion.
+ * Params : SCpnt - Command to queue
+ * done - done function to call once command is complete
+ * Returns : 0 - success, else error
+ */
+-extern int fas216_noqueue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
++extern int fas216_noqueue_command(struct scsi_cmnd *,
++ void (*done)(struct scsi_cmnd *));
+
+ /* Function: irqreturn_t fas216_intr (FAS216_Info *info)
+ * Purpose : handle interrupts from the interface to progress a command
+@@ -363,32 +365,32 @@ extern int fas216_print_host(FAS216_Info
+ extern int fas216_print_stats(FAS216_Info *info, char *buffer);
+ extern int fas216_print_devices(FAS216_Info *info, char *buffer);
+
+-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
++/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ */
+-extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
++extern int fas216_eh_abort(struct scsi_cmnd *SCpnt);
+
+-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
++/* Function: int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+-extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
++extern int fas216_eh_device_reset(struct scsi_cmnd *SCpnt);
+
+-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
++/* Function: int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
+ * Purpose : Reset the complete bus associated with this command
+ * Params : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ */
+-extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
++extern int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt);
+
+-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
++/* Function: int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ */
+-extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
++extern int fas216_eh_host_reset(struct scsi_cmnd *SCpnt);
+
+ #endif /* FAS216_H */
+diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
+index b2c346a..ce159c1 100644
+--- a/drivers/scsi/arm/powertec.c
++++ b/drivers/scsi/arm/powertec.c
+@@ -112,10 +112,8 @@ powertecscsi_terminator_ctl(struct Scsi_
+ * Purpose : handle interrupts from Powertec SCSI card
+ * Params : irq - interrupt number
+ * dev_id - user-defined (Scsi_Host structure)
+- * regs - processor registers at interrupt
+ */
+-static irqreturn_t
+-powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t powertecscsi_intr(int irq, void *dev_id)
+ {
+ struct powertec_info *info = dev_id;
+
+diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
+index 8caa590..cb11cce 100644
+--- a/drivers/scsi/arm/queue.c
++++ b/drivers/scsi/arm/queue.c
+@@ -29,7 +29,7 @@
+
+ typedef struct queue_entry {
+ struct list_head list;
+- Scsi_Cmnd *SCpnt;
++ struct scsi_cmnd *SCpnt;
+ #ifdef DEBUG
+ unsigned long magic;
+ #endif
+@@ -96,14 +96,14 @@ void queue_free (Queue_t *queue)
+
+
+ /*
+- * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
++ * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
+ * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
+ * Params : queue - destination queue
+ * SCpnt - command to add
+ * head - add command to head of queue
+ * Returns : 0 on error, !0 on success
+ */
+-int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
++int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
+ {
+ unsigned long flags;
+ struct list_head *l;
+@@ -134,7 +134,7 @@ empty:
+ return ret;
+ }
+
+-static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
++static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
+ {
+ QE_t *q;
+
+@@ -152,17 +152,17 @@ static Scsi_Cmnd *__queue_remove(Queue_t
+ }
+
+ /*
+- * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
++ * Function: struct scsi_cmnd *queue_remove_exclude (queue, exclude)
+ * Purpose : remove a SCSI command from a queue
+ * Params : queue - queue to remove command from
+ * exclude - bit array of target&lun which is busy
+- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
++ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
+ */
+-Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
++struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
+ {
+ unsigned long flags;
+ struct list_head *l;
+- Scsi_Cmnd *SCpnt = NULL;
++ struct scsi_cmnd *SCpnt = NULL;
+
+ spin_lock_irqsave(&queue->queue_lock, flags);
+ list_for_each(l, &queue->head) {
+@@ -178,15 +178,15 @@ Scsi_Cmnd *queue_remove_exclude(Queue_t
+ }
+
+ /*
+- * Function: Scsi_Cmnd *queue_remove (queue)
++ * Function: struct scsi_cmnd *queue_remove (queue)
+ * Purpose : removes first SCSI command from a queue
+ * Params : queue - queue to remove command from
+- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
++ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
+ */
+-Scsi_Cmnd *queue_remove(Queue_t *queue)
++struct scsi_cmnd *queue_remove(Queue_t *queue)
+ {
+ unsigned long flags;
+- Scsi_Cmnd *SCpnt = NULL;
++ struct scsi_cmnd *SCpnt = NULL;
+
+ spin_lock_irqsave(&queue->queue_lock, flags);
+ if (!list_empty(&queue->head))
+@@ -197,19 +197,20 @@ Scsi_Cmnd *queue_remove(Queue_t *queue)
+ }
+
+ /*
+- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
++ * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
+ * Params : queue - queue to remove command from
+ * target - target that we want
+ * lun - lun on device
+ * tag - tag on device
+- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
++ * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
+ */
+-Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
++struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun,
++ int tag)
+ {
+ unsigned long flags;
+ struct list_head *l;
+- Scsi_Cmnd *SCpnt = NULL;
++ struct scsi_cmnd *SCpnt = NULL;
+
+ spin_lock_irqsave(&queue->queue_lock, flags);
+ list_for_each(l, &queue->head) {
+@@ -275,13 +276,13 @@ int queue_probetgtlun (Queue_t *queue, i
+ }
+
+ /*
+- * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
++ * Function: int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
+ * Purpose : remove a specific command from the queues
+ * Params : queue - queue to look in
+ * SCpnt - command to find
+ * Returns : 0 if not found
+ */
+-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
++int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
+ {
+ unsigned long flags;
+ struct list_head *l;
+diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
+index 0c9dec4..3c519c9 100644
+--- a/drivers/scsi/arm/queue.h
++++ b/drivers/scsi/arm/queue.h
+@@ -32,46 +32,48 @@ extern int queue_initialise (Queue_t *qu
+ extern void queue_free (Queue_t *queue);
+
+ /*
+- * Function: Scsi_Cmnd *queue_remove (queue)
++ * Function: struct scsi_cmnd *queue_remove (queue)
+ * Purpose : removes first SCSI command from a queue
+ * Params : queue - queue to remove command from
+- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
++ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
+ */
+-extern Scsi_Cmnd *queue_remove (Queue_t *queue);
++extern struct scsi_cmnd *queue_remove (Queue_t *queue);
+
+ /*
+- * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
++ * Function: struct scsi_cmnd *queue_remove_exclude_ref (queue, exclude)
+ * Purpose : remove a SCSI command from a queue
+ * Params : queue - queue to remove command from
+ * exclude - array of busy LUNs
+- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
++ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
+ */
+-extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
++extern struct scsi_cmnd *queue_remove_exclude(Queue_t *queue,
++ unsigned long *exclude);
+
+ #define queue_add_cmd_ordered(queue,SCpnt) \
+ __queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
+ #define queue_add_cmd_tail(queue,SCpnt) \
+ __queue_add(queue,SCpnt,0)
+ /*
+- * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
++ * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
+ * Purpose : Add a new command onto a queue
+ * Params : queue - destination queue
+ * SCpnt - command to add
+ * head - add command to head of queue
+ * Returns : 0 on error, !0 on success
+ */
+-extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
++extern int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head);
+
+ /*
+- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
++ * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
+ * Params : queue - queue to remove command from
+ * target - target that we want
+ * lun - lun on device
+ * tag - tag on device
+- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
++ * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
+ */
+-extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
++extern struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target,
++ int lun, int tag);
+
+ /*
+ * Function: queue_remove_all_target(queue, target)
+@@ -94,12 +96,12 @@ extern void queue_remove_all_target(Queu
+ extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
+
+ /*
+- * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
++ * Function: int queue_remove_cmd (Queue_t *queue, struct scsi_cmnd *SCpnt)
+ * Purpose : remove a specific command from the queues
+ * Params : queue - queue to look in
+ * SCpnt - command to find
+ * Returns : 0 if not found
+ */
+-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
++int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt);
+
+ #endif /* QUEUE_H */
+diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
+index 8c2600f..3a39579 100644
+--- a/drivers/scsi/arm/scsi.h
++++ b/drivers/scsi/arm/scsi.h
+@@ -66,7 +66,7 @@ static inline void put_next_SCp_byte(str
+ SCp->this_residual -= 1;
+ }
+
+-static inline void init_SCp(Scsi_Cmnd *SCpnt)
++static inline void init_SCp(struct scsi_cmnd *SCpnt)
+ {
+ memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
+
+diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
+deleted file mode 100644
+index a9bb3cb..0000000
+--- a/drivers/scsi/ata_piix.c
++++ /dev/null
+@@ -1,1040 +0,0 @@
+-/*
+- * ata_piix.c - Intel PATA/SATA controllers
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- *
+- * Copyright 2003-2005 Red Hat Inc
+- * Copyright 2003-2005 Jeff Garzik
+- *
+- *
+- * Copyright header from piix.c:
+- *
+- * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+- * Copyright (C) 1998-2000 Andre Hedrick <andre at linux-ide.org>
+- * Copyright (C) 2003 Red Hat Inc <alan at 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, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available at http://developer.intel.com/
+- *
+- * Documentation
+- * Publically available from Intel web site. Errata documentation
+- * is also publically available. As an aide to anyone hacking on this
+- * driver the list of errata that are relevant is below.going back to
+- * PIIX4. Older device documentation is now a bit tricky to find.
+- *
+- * The chipsets all follow very much the same design. The orginal Triton
+- * series chipsets do _not_ support independant device timings, but this
+- * is fixed in Triton II. With the odd mobile exception the chips then
+- * change little except in gaining more modes until SATA arrives. This
+- * driver supports only the chips with independant timing (that is those
+- * with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix
+- * for the early chip drivers.
+- *
+- * Errata of note:
+- *
+- * Unfixable
+- * PIIX4 errata #9 - Only on ultra obscure hw
+- * ICH3 errata #13 - Not observed to affect real hw
+- * by Intel
+- *
+- * Things we must deal with
+- * PIIX4 errata #10 - BM IDE hang with non UDMA
+- * (must stop/start dma to recover)
+- * 440MX errata #15 - As PIIX4 errata #10
+- * PIIX4 errata #15 - Must not read control registers
+- * during a PIO transfer
+- * 440MX errata #13 - As PIIX4 errata #15
+- * ICH2 errata #21 - DMA mode 0 doesn't work right
+- * ICH0/1 errata #55 - As ICH2 errata #21
+- * ICH2 spec c #9 - Extra operations needed to handle
+- * drive hotswap [NOT YET SUPPORTED]
+- * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
+- * and must be dword aligned
+- * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
+- *
+- * Should have been BIOS fixed:
+- * 450NX: errata #19 - DMA hangs on old 450NX
+- * 450NX: errata #20 - DMA hangs on old 450NX
+- * 450NX: errata #25 - Corruption with DMA on old 450NX
+- * ICH3 errata #15 - IDE deadlock under high load
+- * (BIOS must set dev 31 fn 0 bit 23)
+- * ICH3 errata #18 - Don't use native mode
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "ata_piix"
+-#define DRV_VERSION "2.00"
+-
+-enum {
+- PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
+- ICH5_PMR = 0x90, /* port mapping register */
+- ICH5_PCS = 0x92, /* port control and status */
+- PIIX_SCC = 0x0A, /* sub-class code register */
+-
+- PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */
+- PIIX_FLAG_SCR = (1 << 26), /* SCR available */
+- PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
+- PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
+-
+- /* combined mode. if set, PATA is channel 0.
+- * if clear, PATA is channel 1.
+- */
+- PIIX_PORT_ENABLED = (1 << 0),
+- PIIX_PORT_PRESENT = (1 << 4),
+-
+- PIIX_80C_PRI = (1 << 5) | (1 << 4),
+- PIIX_80C_SEC = (1 << 7) | (1 << 6),
+-
+- /* controller IDs */
+- piix4_pata = 0,
+- ich5_pata = 1,
+- ich5_sata = 2,
+- esb_sata = 3,
+- ich6_sata = 4,
+- ich6_sata_ahci = 5,
+- ich6m_sata_ahci = 6,
+- ich7m_sata_ahci = 7,
+- ich8_sata_ahci = 8,
+-
+- /* constants for mapping table */
+- P0 = 0, /* port 0 */
+- P1 = 1, /* port 1 */
+- P2 = 2, /* port 2 */
+- P3 = 3, /* port 3 */
+- IDE = -1, /* IDE */
+- NA = -2, /* not avaliable */
+- RV = -3, /* reserved */
+-
+- PIIX_AHCI_DEVICE = 6,
+-};
+-
+-struct piix_map_db {
+- const u32 mask;
+- const u16 port_enable;
+- const int present_shift;
+- const int map[][4];
+-};
+-
+-struct piix_host_priv {
+- const int *map;
+- const struct piix_map_db *map_db;
+-};
+-
+-static int piix_init_one (struct pci_dev *pdev,
+- const struct pci_device_id *ent);
+-static void piix_host_stop(struct ata_host_set *host_set);
+-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
+-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+-static void piix_pata_error_handler(struct ata_port *ap);
+-static void piix_sata_error_handler(struct ata_port *ap);
+-
+-static unsigned int in_module_init = 1;
+-
+-static const struct pci_device_id piix_pci_tbl[] = {
+-#ifdef ATA_ENABLE_PATA
+- { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
+- { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+- { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+- { 0x8086, 0x27df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+-#endif
+-
+- /* NOTE: The following PCI ids must be kept in sync with the
+- * list in drivers/pci/quirks.c.
+- */
+-
+- /* 82801EB (ICH5) */
+- { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+- /* 82801EB (ICH5) */
+- { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+- /* 6300ESB (ICH5 variant with broken PCS present bits) */
+- { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+- /* 6300ESB pretending RAID */
+- { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+- /* 82801FB/FW (ICH6/ICH6W) */
+- { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+- /* 82801FR/FRW (ICH6R/ICH6RW) */
+- { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+- /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
+- { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+- /* 82801GB/GR/GH (ICH7, identical to ICH6) */
+- { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+- /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
+- { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7m_sata_ahci },
+- /* Enterprise Southbridge 2 (where's the datasheet?) */
+- { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+- /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
+- { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+- /* SATA Controller 2 IDE (ICH8, ditto) */
+- { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+- /* Mobile SATA Controller IDE (ICH8M, ditto) */
+- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+-
+- { } /* terminate list */
+-};
+-
+-static struct pci_driver piix_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = piix_pci_tbl,
+- .probe = piix_init_one,
+- .remove = ata_pci_remove_one,
+- .suspend = ata_pci_device_suspend,
+- .resume = ata_pci_device_resume,
+-};
+-
+-static struct scsi_host_template piix_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+- .resume = ata_scsi_device_resume,
+- .suspend = ata_scsi_device_suspend,
+-};
+-
+-static const struct ata_port_operations piix_pata_ops = {
+- .port_disable = ata_port_disable,
+- .set_piomode = piix_set_piomode,
+- .set_dmamode = piix_set_dmamode,
+- .mode_filter = ata_pci_default_filter,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_pio_data_xfer,
+-
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = piix_pata_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+-
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+-
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = piix_host_stop,
+-};
+-
+-static const struct ata_port_operations piix_sata_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_pio_data_xfer,
+-
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = piix_sata_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+-
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+-
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = piix_host_stop,
+-};
+-
+-static const struct piix_map_db ich5_map_db = {
+- .mask = 0x7,
+- .port_enable = 0x3,
+- .present_shift = 4,
+- .map = {
+- /* PM PS SM SS MAP */
+- { P0, NA, P1, NA }, /* 000b */
+- { P1, NA, P0, NA }, /* 001b */
+- { RV, RV, RV, RV },
+- { RV, RV, RV, RV },
+- { P0, P1, IDE, IDE }, /* 100b */
+- { P1, P0, IDE, IDE }, /* 101b */
+- { IDE, IDE, P0, P1 }, /* 110b */
+- { IDE, IDE, P1, P0 }, /* 111b */
+- },
+-};
+-
+-static const struct piix_map_db ich6_map_db = {
+- .mask = 0x3,
+- .port_enable = 0xf,
+- .present_shift = 4,
+- .map = {
+- /* PM PS SM SS MAP */
+- { P0, P2, P1, P3 }, /* 00b */
+- { IDE, IDE, P1, P3 }, /* 01b */
+- { P0, P2, IDE, IDE }, /* 10b */
+- { RV, RV, RV, RV },
+- },
+-};
+-
+-static const struct piix_map_db ich6m_map_db = {
+- .mask = 0x3,
+- .port_enable = 0x5,
+- .present_shift = 4,
+- .map = {
+- /* PM PS SM SS MAP */
+- { P0, P2, RV, RV }, /* 00b */
+- { RV, RV, RV, RV },
+- { P0, P2, IDE, IDE }, /* 10b */
+- { RV, RV, RV, RV },
+- },
+-};
+-
+-static const struct piix_map_db ich7m_map_db = {
+- .mask = 0x3,
+- .port_enable = 0x5,
+- .present_shift = 4,
+-
+- /* Map 01b isn't specified in the doc but some notebooks use
+- * it anyway. ATM, the only case spotted carries subsystem ID
+- * 1025:0107. This is the only difference from ich6m.
+- */
+- .map = {
+- /* PM PS SM SS MAP */
+- { P0, P2, RV, RV }, /* 00b */
+- { IDE, IDE, P1, P3 }, /* 01b */
+- { P0, P2, IDE, IDE }, /* 10b */
+- { RV, RV, RV, RV },
+- },
+-};
+-
+-static const struct piix_map_db ich8_map_db = {
+- .mask = 0x3,
+- .port_enable = 0x3,
+- .present_shift = 8,
+- .map = {
+- /* PM PS SM SS MAP */
+- { P0, NA, P1, NA }, /* 00b (hardwired) */
+- { RV, RV, RV, RV },
+- { RV, RV, RV, RV }, /* 10b (never) */
+- { RV, RV, RV, RV },
+- },
+-};
+-
+-static const struct piix_map_db *piix_map_db_table[] = {
+- [ich5_sata] = &ich5_map_db,
+- [esb_sata] = &ich5_map_db,
+- [ich6_sata] = &ich6_map_db,
+- [ich6_sata_ahci] = &ich6_map_db,
+- [ich6m_sata_ahci] = &ich6m_map_db,
+- [ich7m_sata_ahci] = &ich7m_map_db,
+- [ich8_sata_ahci] = &ich8_map_db,
+-};
+-
+-static struct ata_port_info piix_port_info[] = {
+- /* piix4_pata */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SLAVE_POSS,
+- .pio_mask = 0x1f, /* pio0-4 */
+-#if 0
+- .mwdma_mask = 0x06, /* mwdma1-2 */
+-#else
+- .mwdma_mask = 0x00, /* mwdma broken */
+-#endif
+- .udma_mask = ATA_UDMA_MASK_40C,
+- .port_ops = &piix_pata_ops,
+- },
+-
+- /* ich5_pata */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
+- .pio_mask = 0x1f, /* pio0-4 */
+-#if 0
+- .mwdma_mask = 0x06, /* mwdma1-2 */
+-#else
+- .mwdma_mask = 0x00, /* mwdma broken */
+-#endif
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &piix_pata_ops,
+- },
+-
+- /* ich5_sata */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR |
+- PIIX_FLAG_IGNORE_PCS,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-
+- /* i6300esb_sata */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA |
+- PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-
+- /* ich6_sata */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA |
+- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-
+- /* ich6_sata_ahci */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA |
+- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+- PIIX_FLAG_AHCI,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-
+- /* ich6m_sata_ahci */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA |
+- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+- PIIX_FLAG_AHCI,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-
+- /* ich7m_sata_ahci */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA |
+- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+- PIIX_FLAG_AHCI,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-
+- /* ich8_sata_ahci */
+- {
+- .sht = &piix_sht,
+- .host_flags = ATA_FLAG_SATA |
+- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+- PIIX_FLAG_AHCI,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &piix_sata_ops,
+- },
+-};
+-
+-static struct pci_bits piix_enable_bits[] = {
+- { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+- { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+-};
+-
+-MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
+-MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-static int force_pcs = 0;
+-module_param(force_pcs, int, 0444);
+-MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around "
+- "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)");
+-
+-/**
+- * piix_pata_cbl_detect - Probe host controller cable detect info
+- * @ap: Port for which cable detect info is desired
+- *
+- * Read 80c cable indicator from ATA PCI device's PCI config
+- * register. This register is normally set by firmware (BIOS).
+- *
+- * LOCKING:
+- * None (inherited from caller).
+- */
+-static void piix_pata_cbl_detect(struct ata_port *ap)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- u8 tmp, mask;
+-
+- /* no 80c support in host controller? */
+- if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
+- goto cbl40;
+-
+- /* check BIOS cable detect results */
+- mask = ap->hard_port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
+- pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
+- if ((tmp & mask) == 0)
+- goto cbl40;
+-
+- ap->cbl = ATA_CBL_PATA80;
+- return;
+-
+-cbl40:
+- ap->cbl = ATA_CBL_PATA40;
+- ap->udma_mask &= ATA_UDMA_MASK_40C;
+-}
+-
+-/**
+- * piix_pata_prereset - prereset for PATA host controller
+- * @ap: Target port
+- *
+- * Prereset including cable detection.
+- *
+- * LOCKING:
+- * None (inherited from caller).
+- */
+-static int piix_pata_prereset(struct ata_port *ap)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+-
+- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
+- ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
+- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+- return 0;
+- }
+-
+- piix_pata_cbl_detect(ap);
+-
+- return ata_std_prereset(ap);
+-}
+-
+-static void piix_pata_error_handler(struct ata_port *ap)
+-{
+- ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
+- ata_std_postreset);
+-}
+-
+-/**
+- * piix_sata_present_mask - determine present mask for SATA host controller
+- * @ap: Target port
+- *
+- * Reads SATA PCI device's PCI config register Port Configuration
+- * and Status (PCS) to determine port and device availability.
+- *
+- * LOCKING:
+- * None (inherited from caller).
+- *
+- * RETURNS:
+- * determined present_mask
+- */
+-static unsigned int piix_sata_present_mask(struct ata_port *ap)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- struct piix_host_priv *hpriv = ap->host_set->private_data;
+- const unsigned int *map = hpriv->map;
+- int base = 2 * ap->hard_port_no;
+- unsigned int present_mask = 0;
+- int port, i;
+- u16 pcs;
+-
+- pci_read_config_word(pdev, ICH5_PCS, &pcs);
+- DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
+-
+- for (i = 0; i < 2; i++) {
+- port = map[base + i];
+- if (port < 0)
+- continue;
+- if ((ap->flags & PIIX_FLAG_IGNORE_PCS) ||
+- (pcs & 1 << (hpriv->map_db->present_shift + port)))
+- present_mask |= 1 << i;
+- }
+-
+- DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
+- ap->id, pcs, present_mask);
+-
+- return present_mask;
+-}
+-
+-/**
+- * piix_sata_softreset - reset SATA host port via ATA SRST
+- * @ap: port to reset
+- * @classes: resulting classes of attached devices
+- *
+- * Reset SATA host port via ATA SRST. On controllers with
+- * reliable PCS present bits, the bits are used to determine
+- * device presence.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes)
+-{
+- unsigned int present_mask;
+- int i, rc;
+-
+- present_mask = piix_sata_present_mask(ap);
+-
+- rc = ata_std_softreset(ap, classes);
+- if (rc)
+- return rc;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- if (!(present_mask & (1 << i)))
+- classes[i] = ATA_DEV_NONE;
+- }
+-
+- return 0;
+-}
+-
+-static void piix_sata_error_handler(struct ata_port *ap)
+-{
+- ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL,
+- ata_std_postreset);
+-}
+-
+-/**
+- * piix_set_piomode - Initialize host controller PATA PIO timings
+- * @ap: Port whose timings we are configuring
+- * @adev: um
+- *
+- * Set PIO mode for device, in host controller PCI config space.
+- *
+- * LOCKING:
+- * None (inherited from caller).
+- */
+-
+-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+-{
+- unsigned int pio = adev->pio_mode - XFER_PIO_0;
+- struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
+- unsigned int is_slave = (adev->devno != 0);
+- unsigned int master_port= ap->hard_port_no ? 0x42 : 0x40;
+- unsigned int slave_port = 0x44;
+- u16 master_data;
+- u8 slave_data;
+-
+- static const /* ISP RTC */
+- u8 timings[][2] = { { 0, 0 },
+- { 0, 0 },
+- { 1, 0 },
+- { 2, 1 },
+- { 2, 3 }, };
+-
+- pci_read_config_word(dev, master_port, &master_data);
+- if (is_slave) {
+- master_data |= 0x4000;
+- /* enable PPE, IE and TIME */
+- master_data |= 0x0070;
+- pci_read_config_byte(dev, slave_port, &slave_data);
+- slave_data &= (ap->hard_port_no ? 0x0f : 0xf0);
+- slave_data |=
+- (timings[pio][0] << 2) |
+- (timings[pio][1] << (ap->hard_port_no ? 4 : 0));
+- } else {
+- master_data &= 0xccf8;
+- /* enable PPE, IE and TIME */
+- master_data |= 0x0007;
+- master_data |=
+- (timings[pio][0] << 12) |
+- (timings[pio][1] << 8);
+- }
+- pci_write_config_word(dev, master_port, master_data);
+- if (is_slave)
+- pci_write_config_byte(dev, slave_port, slave_data);
+-}
+-
+-/**
+- * piix_set_dmamode - Initialize host controller PATA PIO timings
+- * @ap: Port whose timings we are configuring
+- * @adev: um
+- * @udma: udma mode, 0 - 6
+- *
+- * Set UDMA mode for device, in host controller PCI config space.
+- *
+- * LOCKING:
+- * None (inherited from caller).
+- */
+-
+-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+-{
+- unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */
+- struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
+- u8 maslave = ap->hard_port_no ? 0x42 : 0x40;
+- u8 speed = udma;
+- unsigned int drive_dn = (ap->hard_port_no ? 2 : 0) + adev->devno;
+- int a_speed = 3 << (drive_dn * 4);
+- int u_flag = 1 << drive_dn;
+- int v_flag = 0x01 << drive_dn;
+- int w_flag = 0x10 << drive_dn;
+- int u_speed = 0;
+- int sitre;
+- u16 reg4042, reg4a;
+- u8 reg48, reg54, reg55;
+-
+- pci_read_config_word(dev, maslave, ®4042);
+- DPRINTK("reg4042 = 0x%04x\n", reg4042);
+- sitre = (reg4042 & 0x4000) ? 1 : 0;
+- pci_read_config_byte(dev, 0x48, ®48);
+- pci_read_config_word(dev, 0x4a, ®4a);
+- pci_read_config_byte(dev, 0x54, ®54);
+- pci_read_config_byte(dev, 0x55, ®55);
+-
+- switch(speed) {
+- case XFER_UDMA_4:
+- case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break;
+- case XFER_UDMA_6:
+- case XFER_UDMA_5:
+- case XFER_UDMA_3:
+- case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break;
+- case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break;
+- case XFER_MW_DMA_2:
+- case XFER_MW_DMA_1: break;
+- default:
+- BUG();
+- return;
+- }
+-
+- if (speed >= XFER_UDMA_0) {
+- if (!(reg48 & u_flag))
+- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+- if (speed == XFER_UDMA_5) {
+- pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+- } else {
+- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+- }
+- if ((reg4a & a_speed) != u_speed)
+- pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+- if (speed > XFER_UDMA_2) {
+- if (!(reg54 & v_flag))
+- pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+- } else
+- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+- } else {
+- if (reg48 & u_flag)
+- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+- if (reg4a & a_speed)
+- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+- if (reg54 & v_flag)
+- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+- if (reg55 & w_flag)
+- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+- }
+-}
+-
+-#define AHCI_PCI_BAR 5
+-#define AHCI_GLOBAL_CTL 0x04
+-#define AHCI_ENABLE (1 << 31)
+-static int piix_disable_ahci(struct pci_dev *pdev)
+-{
+- void __iomem *mmio;
+- u32 tmp;
+- int rc = 0;
+-
+- /* BUG: pci_enable_device has not yet been called. This
+- * works because this device is usually set up by BIOS.
+- */
+-
+- if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
+- !pci_resource_len(pdev, AHCI_PCI_BAR))
+- return 0;
+-
+- mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
+- if (!mmio)
+- return -ENOMEM;
+-
+- tmp = readl(mmio + AHCI_GLOBAL_CTL);
+- if (tmp & AHCI_ENABLE) {
+- tmp &= ~AHCI_ENABLE;
+- writel(tmp, mmio + AHCI_GLOBAL_CTL);
+-
+- tmp = readl(mmio + AHCI_GLOBAL_CTL);
+- if (tmp & AHCI_ENABLE)
+- rc = -EIO;
+- }
+-
+- pci_iounmap(pdev, mmio);
+- return rc;
+-}
+-
+-/**
+- * piix_check_450nx_errata - Check for problem 450NX setup
+- * @ata_dev: the PCI device to check
+- *
+- * Check for the present of 450NX errata #19 and errata #25. If
+- * they are found return an error code so we can turn off DMA
+- */
+-
+-static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
+-{
+- struct pci_dev *pdev = NULL;
+- u16 cfg;
+- u8 rev;
+- int no_piix_dma = 0;
+-
+- while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL)
+- {
+- /* Look for 450NX PXB. Check for problem configurations
+- A PCI quirk checks bit 6 already */
+- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+- pci_read_config_word(pdev, 0x41, &cfg);
+- /* Only on the original revision: IDE DMA can hang */
+- if (rev == 0x00)
+- no_piix_dma = 1;
+- /* On all revisions below 5 PXB bus lock must be disabled for IDE */
+- else if (cfg & (1<<14) && rev < 5)
+- no_piix_dma = 2;
+- }
+- if (no_piix_dma)
+- dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");
+- if (no_piix_dma == 2)
+- dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");
+- return no_piix_dma;
+-}
+-
+-static void __devinit piix_init_pcs(struct pci_dev *pdev,
+- struct ata_port_info *pinfo,
+- const struct piix_map_db *map_db)
+-{
+- u16 pcs, new_pcs;
+-
+- pci_read_config_word(pdev, ICH5_PCS, &pcs);
+-
+- new_pcs = pcs | map_db->port_enable;
+-
+- if (new_pcs != pcs) {
+- DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs);
+- pci_write_config_word(pdev, ICH5_PCS, new_pcs);
+- msleep(150);
+- }
+-
+- if (force_pcs == 1) {
+- dev_printk(KERN_INFO, &pdev->dev,
+- "force ignoring PCS (0x%x)\n", new_pcs);
+- pinfo[0].host_flags |= PIIX_FLAG_IGNORE_PCS;
+- pinfo[1].host_flags |= PIIX_FLAG_IGNORE_PCS;
+- } else if (force_pcs == 2) {
+- dev_printk(KERN_INFO, &pdev->dev,
+- "force honoring PCS (0x%x)\n", new_pcs);
+- pinfo[0].host_flags &= ~PIIX_FLAG_IGNORE_PCS;
+- pinfo[1].host_flags &= ~PIIX_FLAG_IGNORE_PCS;
+- }
+-}
+-
+-static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+- struct ata_port_info *pinfo,
+- const struct piix_map_db *map_db)
+-{
+- struct piix_host_priv *hpriv = pinfo[0].private_data;
+- const unsigned int *map;
+- int i, invalid_map = 0;
+- u8 map_value;
+-
+- pci_read_config_byte(pdev, ICH5_PMR, &map_value);
+-
+- map = map_db->map[map_value & map_db->mask];
+-
+- dev_printk(KERN_INFO, &pdev->dev, "MAP [");
+- for (i = 0; i < 4; i++) {
+- switch (map[i]) {
+- case RV:
+- invalid_map = 1;
+- printk(" XX");
+- break;
+-
+- case NA:
+- printk(" --");
+- break;
+-
+- case IDE:
+- WARN_ON((i & 1) || map[i + 1] != IDE);
+- pinfo[i / 2] = piix_port_info[ich5_pata];
+- pinfo[i / 2].private_data = hpriv;
+- i++;
+- printk(" IDE IDE");
+- break;
+-
+- default:
+- printk(" P%d", map[i]);
+- if (i & 1)
+- pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS;
+- break;
+- }
+- }
+- printk(" ]\n");
+-
+- if (invalid_map)
+- dev_printk(KERN_ERR, &pdev->dev,
+- "invalid MAP value %u\n", map_value);
+-
+- hpriv->map = map;
+- hpriv->map_db = map_db;
+-}
+-
+-/**
+- * piix_init_one - Register PIIX ATA PCI device with kernel services
+- * @pdev: PCI device to register
+- * @ent: Entry in piix_pci_tbl matching with @pdev
+- *
+- * Called from kernel PCI layer. We probe for combined mode (sigh),
+- * and then hand over control to libata, for it to do the rest.
+- *
+- * LOCKING:
+- * Inherited from PCI layer (may sleep).
+- *
+- * RETURNS:
+- * Zero on success, or -ERRNO value.
+- */
+-
+-static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_port_info port_info[2];
+- struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
+- struct piix_host_priv *hpriv;
+- unsigned long host_flags;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev,
+- "version " DRV_VERSION "\n");
+-
+- /* no hotplugging support (FIXME) */
+- if (!in_module_init)
+- return -ENODEV;
+-
+- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv)
+- return -ENOMEM;
+-
+- port_info[0] = piix_port_info[ent->driver_data];
+- port_info[1] = piix_port_info[ent->driver_data];
+- port_info[0].private_data = hpriv;
+- port_info[1].private_data = hpriv;
+-
+- host_flags = port_info[0].host_flags;
+-
+- if (host_flags & PIIX_FLAG_AHCI) {
+- u8 tmp;
+- pci_read_config_byte(pdev, PIIX_SCC, &tmp);
+- if (tmp == PIIX_AHCI_DEVICE) {
+- int rc = piix_disable_ahci(pdev);
+- if (rc)
+- return rc;
+- }
+- }
+-
+- /* Initialize SATA map */
+- if (host_flags & ATA_FLAG_SATA) {
+- piix_init_sata_map(pdev, port_info,
+- piix_map_db_table[ent->driver_data]);
+- piix_init_pcs(pdev, port_info,
+- piix_map_db_table[ent->driver_data]);
+- }
+-
+- /* On ICH5, some BIOSen disable the interrupt using the
+- * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
+- * On ICH6, this bit has the same effect, but only when
+- * MSI is disabled (and it is disabled, as we don't use
+- * message-signalled interrupts currently).
+- */
+- if (host_flags & PIIX_FLAG_CHECKINTR)
+- pci_intx(pdev, 1);
+-
+- if (piix_check_450nx_errata(pdev)) {
+- /* This writes into the master table but it does not
+- really matter for this errata as we will apply it to
+- all the PIIX devices on the board */
+- port_info[0].mwdma_mask = 0;
+- port_info[0].udma_mask = 0;
+- port_info[1].mwdma_mask = 0;
+- port_info[1].udma_mask = 0;
+- }
+- return ata_pci_init_one(pdev, ppinfo, 2);
+-}
+-
+-static void piix_host_stop(struct ata_host_set *host_set)
+-{
+- if (host_set->next == NULL)
+- kfree(host_set->private_data);
+- ata_host_stop(host_set);
+-}
+-
+-static int __init piix_init(void)
+-{
+- int rc;
+-
+- DPRINTK("pci_module_init\n");
+- rc = pci_module_init(&piix_pci_driver);
+- if (rc)
+- return rc;
+-
+- in_module_init = 0;
+-
+- DPRINTK("done\n");
+- return 0;
+-}
+-
+-static void __exit piix_exit(void)
+-{
+- pci_unregister_driver(&piix_pci_driver);
+-}
+-
+-module_init(piix_init);
+-module_exit(piix_exit);
+-
+diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
+index e397129..0f920c8 100644
+--- a/drivers/scsi/atari_NCR5380.c
++++ b/drivers/scsi/atari_NCR5380.c
+@@ -1262,7 +1262,7 @@ static void NCR5380_dma_complete( struct
+ *
+ */
+
+-static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t NCR5380_intr (int irq, void *dev_id)
+ {
+ struct Scsi_Host *instance = first_instance;
+ int done = 1, handled = 0;
+diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
+index 8d5d2a5..cdc710e 100644
+--- a/drivers/scsi/atari_dma_emul.c
++++ b/drivers/scsi/atari_dma_emul.c
+@@ -110,7 +110,7 @@ static inline void set_restdata_reg(unsi
+ }
+
+ /*
+- * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
++ * void hades_dma_emulator(int irq, void *dummy)
+ *
+ * This code emulates TT SCSI DMA on the Hades.
+ *
+@@ -140,7 +140,7 @@ static inline void set_restdata_reg(unsi
+ * increased with one.
+ */
+
+-static irqreturn_t hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t hades_dma_emulator(int irq, void *dummy)
+ {
+ unsigned long dma_base;
+ register unsigned long dma_cnt asm ("d3");
+diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
+index e1be4a4..dfb1bcf 100644
+--- a/drivers/scsi/atari_scsi.c
++++ b/drivers/scsi/atari_scsi.c
+@@ -194,8 +194,8 @@ static int falcon_classify_cmd( Scsi_Cmn
+ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+ Scsi_Cmnd *cmd, int write_flag );
+ #endif
+-static irqreturn_t scsi_tt_intr( int irq, void *dummy, struct pt_regs *fp);
+-static irqreturn_t scsi_falcon_intr( int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t scsi_tt_intr( int irq, void *dummy);
++static irqreturn_t scsi_falcon_intr( int irq, void *dummy);
+ static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
+ hostdata );
+ static void falcon_get_lock( void );
+@@ -285,7 +285,7 @@ static int scsi_dma_is_ignored_buserr( u
+ * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
+ * to clear the DMA int pending bit before it allows other level 6 interrupts.
+ */
+-static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
++static void scsi_dma_buserr (int irq, void *dummy)
+ {
+ unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
+
+@@ -314,7 +314,7 @@ static void scsi_dma_buserr (int irq, vo
+ #endif
+
+
+-static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t scsi_tt_intr (int irq, void *dummy)
+ {
+ #ifdef REAL_DMA
+ int dma_stat;
+@@ -406,7 +406,7 @@ static irqreturn_t scsi_tt_intr (int irq
+ }
+
+
+-static irqreturn_t scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
+ {
+ #ifdef REAL_DMA
+ int dma_stat;
+diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
+index 0ec41f3..fec58cc 100644
+--- a/drivers/scsi/atp870u.c
++++ b/drivers/scsi/atp870u.c
+@@ -44,7 +44,7 @@ static void send_s870(struct atp_unit *d
+ static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
+ static void tscam_885(void);
+
+-static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ unsigned short int tmpcip, id;
+diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
+index 7c9c036..ea3e4b2 100644
+--- a/drivers/scsi/bvme6000.h
++++ b/drivers/scsi/bvme6000.h
+@@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *,
+ int NCR53c7xx_abort(Scsi_Cmnd *);
+ int NCR53c7x0_release (struct Scsi_Host *);
+ int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
++void NCR53c7x0_intr(int irq, void *dev_id);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 3
+diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
+index ff2b179..e95b367 100644
+--- a/drivers/scsi/dc395x.c
++++ b/drivers/scsi/dc395x.c
+@@ -1219,7 +1219,7 @@ static void dump_register_info(struct Ad
+ srb, srb->cmd, srb->cmd->pid,
+ srb->cmd->cmnd[0], srb->cmd->device->id,
+ srb->cmd->device->lun);
+- printk(" sglist=%p cnt=%i idx=%i len=%i\n",
++ printk(" sglist=%p cnt=%i idx=%i len=%zu\n",
+ srb->segment_x, srb->sg_count, srb->sg_index,
+ srb->total_xfer_length);
+ printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
+@@ -1813,10 +1813,9 @@ static void dc395x_handle_interrupt(stru
+ }
+
+
+-static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
+ {
+- struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id;
++ struct AdapterCtlBlk *acb = dev_id;
+ u16 scsi_status;
+ u8 dma_status;
+ irqreturn_t handled = IRQ_NONE;
+@@ -4949,7 +4948,7 @@ static struct pci_driver dc395x_driver =
+ **/
+ static int __init dc395x_module_init(void)
+ {
+- return pci_module_init(&dc395x_driver);
++ return pci_register_driver(&dc395x_driver);
+ }
+
+
+diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
+index eb32062..c29ccbc 100644
+--- a/drivers/scsi/dec_esp.c
++++ b/drivers/scsi/dec_esp.c
+@@ -94,9 +94,9 @@ volatile unsigned char pmaz_cmd_buffer[1
+ * via PIO.
+ */
+
+-static irqreturn_t scsi_dma_merr_int(int, void *, struct pt_regs *);
+-static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *);
+-static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *);
++static irqreturn_t scsi_dma_merr_int(int, void *);
++static irqreturn_t scsi_dma_err_int(int, void *);
++static irqreturn_t scsi_dma_int(int, void *);
+
+ static int dec_esp_detect(struct scsi_host_template * tpnt);
+
+@@ -307,7 +307,7 @@ err_dealloc:
+ }
+
+ /************************************************************* DMA Functions */
+-static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
+ {
+ printk("Got unexpected SCSI DMA Interrupt! < ");
+ printk("SCSI_DMA_MEMRDERR ");
+@@ -316,14 +316,14 @@ static irqreturn_t scsi_dma_merr_int(int
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t scsi_dma_err_int(int irq, void *dev_id)
+ {
+ /* empty */
+
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t scsi_dma_int(int irq, void *dev_id)
+ {
+ u32 scsi_next_ptr;
+
+diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
+index 879a266..fa738ec 100644
+--- a/drivers/scsi/dmx3191d.c
++++ b/drivers/scsi/dmx3191d.c
+@@ -155,7 +155,7 @@ static struct pci_driver dmx3191d_pci_dr
+
+ static int __init dmx3191d_init(void)
+ {
+- return pci_module_init(&dmx3191d_pci_driver);
++ return pci_register_driver(&dmx3191d_pci_driver);
+ }
+
+ static void __exit dmx3191d_exit(void)
+diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
+index d84a281..5a49216 100644
+--- a/drivers/scsi/dpt/dpti_i2o.h
++++ b/drivers/scsi/dpt/dpti_i2o.h
+@@ -47,21 +47,11 @@
+ * I2O Interface Objects
+ */
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+-
+-#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
+-
+-typedef struct wait_queue *adpt_wait_queue_head_t;
+-#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) adpt_wait_queue_head_t wait = NULL
+-typedef struct wait_queue adpt_wait_queue_t;
+-#else
+-
+ #include <linux/wait.h>
+ typedef wait_queue_head_t adpt_wait_queue_head_t;
+-#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait)
++#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait)
+ typedef wait_queue_t adpt_wait_queue_t;
+
+-#endif
+ /*
+ * message structures
+ */
+diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
+index e133733..60b1b43 100644
+--- a/drivers/scsi/dpt_i2o.c
++++ b/drivers/scsi/dpt_i2o.c
+@@ -46,7 +46,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Dri
+
+ #include <linux/stat.h>
+ #include <linux/slab.h> /* for kmalloc() */
+-#include <linux/config.h> /* for CONFIG_PCI */
+ #include <linux/pci.h> /* for PCI support */
+ #include <linux/proc_fs.h>
+ #include <linux/blkdev.h>
+@@ -185,7 +184,7 @@ static int adpt_detect(struct scsi_host_
+ PINFO("Detecting Adaptec I2O RAID controllers...\n");
+
+ /* search for all Adatpec I2O RAID cards */
+- while ((pDev = pci_find_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
++ while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
+ if(pDev->device == PCI_DPT_DEVICE_ID ||
+ pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
+ if(adpt_install_hba(sht, pDev) ){
+@@ -193,8 +192,11 @@ static int adpt_detect(struct scsi_host_
+ PERROR("Will not try to detect others.\n");
+ return hba_count-1;
+ }
++ pci_dev_get(pDev);
+ }
+ }
++ if (pDev)
++ pci_dev_put(pDev);
+
+ /* In INIT state, Activate IOPs */
+ for (pHba = hba_chain; pHba; pHba = pHba->next) {
+@@ -1076,6 +1078,7 @@ static void adpt_i2o_delete_hba(adpt_hba
+ }
+ }
+ }
++ pci_dev_put(pHba->pDev);
+ kfree(pHba);
+
+ if(hba_count <= 0){
+@@ -1986,7 +1989,7 @@ static int adpt_ioctl(struct inode *inod
+ }
+
+
+-static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t adpt_isr(int irq, void *dev_id)
+ {
+ struct scsi_cmnd* cmd;
+ adpt_hba* pHba = dev_id;
+@@ -2209,7 +2212,7 @@ static s32 adpt_scsi_register(adpt_hba*
+ */
+ host->io_port = 0;
+ host->n_io_port = 0;
+- /* see comments in hosts.h */
++ /* see comments in scsi_host.h */
+ host->max_id = 16;
+ host->max_lun = 256;
+ host->max_channel = pHba->top_scsi_channel + 1;
+diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
+index 2ad2a89..fd79068 100644
+--- a/drivers/scsi/dpti.h
++++ b/drivers/scsi/dpti.h
+@@ -44,7 +44,7 @@ static int adpt_device_reset(struct scsi
+
+
+ /*
+- * struct scsi_host_template (see hosts.h)
++ * struct scsi_host_template (see scsi/scsi_host.h)
+ */
+
+ #define DPT_DRIVER_NAME "Adaptec I2O RAID"
+@@ -263,7 +263,7 @@ struct sg_simple_element {
+ static void adpt_i2o_sys_shutdown(void);
+ static int adpt_init(void);
+ static int adpt_i2o_build_sys_table(void);
+-static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t adpt_isr(int irq, void *dev_id);
+ #ifdef REBOOT_NOTIFIER
+ static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
+ #endif
+diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
+index 0d5713d..5475672 100644
+--- a/drivers/scsi/dtc.c
++++ b/drivers/scsi/dtc.c
+@@ -82,7 +82,7 @@
+ #include <linux/string.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include "scsi.h"
+ #include <scsi/scsi_host.h>
+ #include "dtc.h"
+diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
+index a5ff43b..2d38025 100644
+--- a/drivers/scsi/eata.c
++++ b/drivers/scsi/eata.c
+@@ -875,7 +875,7 @@ static unsigned long io_port[] = {
+ /* But transfer orientation from the 16 bit data register is Little Endian */
+ #define REG2H(x) le16_to_cpu(x)
+
+-static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
++static irqreturn_t do_interrupt_handler(int, void *);
+ static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *,
+ unsigned int);
+ static int do_trace = 0;
+@@ -2555,8 +2555,7 @@ static irqreturn_t ihdlr(int irq, struct
+ return IRQ_NONE;
+ }
+
+-static irqreturn_t do_interrupt_handler(int irq, void *shap,
+- struct pt_regs *regs)
++static irqreturn_t do_interrupt_handler(int irq, void *shap)
+ {
+ struct Scsi_Host *shost;
+ unsigned int j;
+diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
+index 34bce2c..635c148 100644
+--- a/drivers/scsi/eata_generic.h
++++ b/drivers/scsi/eata_generic.h
+@@ -364,6 +364,7 @@ typedef struct hstd {
+ __u8 moresupport; /* HBA supports MORE flag */
+ struct Scsi_Host *next;
+ struct Scsi_Host *prev;
++ struct pci_dev *pdev; /* PCI device or NULL for non PCI */
+ struct eata_sp sp; /* status packet */
+ struct eata_ccb ccb[0]; /* ccb array begins here */
+ }hostdata;
+diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
+index 771b019..2dbb66d 100644
+--- a/drivers/scsi/eata_pio.c
++++ b/drivers/scsi/eata_pio.c
+@@ -71,11 +71,11 @@
+ #include "eata_pio.h"
+
+
+-static uint ISAbases[MAXISA] = {
++static unsigned int ISAbases[MAXISA] = {
+ 0x1F0, 0x170, 0x330, 0x230
+ };
+
+-static uint ISAirqs[MAXISA] = {
++static unsigned int ISAirqs[MAXISA] = {
+ 14, 12, 15, 11
+ };
+
+@@ -84,7 +84,7 @@ static unsigned char EISAbases[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+-static uint registered_HBAs;
++static unsigned int registered_HBAs;
+ static struct Scsi_Host *last_HBA;
+ static struct Scsi_Host *first_HBA;
+ static unsigned char reg_IRQ[16];
+@@ -165,6 +165,7 @@ static int eata_pio_proc_info(struct Scs
+
+ static int eata_pio_release(struct Scsi_Host *sh)
+ {
++ hostdata *hd = SD(sh);
+ if (sh->irq && reg_IRQ[sh->irq] == 1)
+ free_irq(sh->irq, NULL);
+ else
+@@ -173,10 +174,13 @@ static int eata_pio_release(struct Scsi_
+ if (sh->io_port && sh->n_io_port)
+ release_region(sh->io_port, sh->n_io_port);
+ }
++ /* At this point the PCI reference can go */
++ if (hd->pdev)
++ pci_dev_put(hd->pdev);
+ return 1;
+ }
+
+-static void IncStat(struct scsi_pointer *SCp, uint Increment)
++static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
+ {
+ SCp->ptr += Increment;
+ if ((SCp->this_residual -= Increment) == 0) {
+@@ -190,46 +194,48 @@ static void IncStat(struct scsi_pointer
+ }
+ }
+
+-static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t eata_pio_int_handler(int irq, void *dev_id);
+
+-static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
++ irqreturn_t ret;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+- eata_pio_int_handler(irq, dev_id, regs);
++ ret = eata_pio_int_handler(irq, dev_id);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+- return IRQ_HANDLED;
++ return ret;
+ }
+
+-static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t eata_pio_int_handler(int irq, void *dev_id)
+ {
+- uint eata_stat = 0xfffff;
++ unsigned int eata_stat = 0xfffff;
+ struct scsi_cmnd *cmd;
+ hostdata *hd;
+ struct eata_ccb *cp;
+- uint base;
+- uint x, z;
++ unsigned long base;
++ unsigned int x, z;
+ struct Scsi_Host *sh;
+ unsigned short zwickel = 0;
+ unsigned char stat, odd;
++ irqreturn_t ret = IRQ_NONE;
+
+ for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev)
+ {
+ if (sh->irq != irq)
+ continue;
+- if (inb((uint) sh->base + HA_RSTATUS) & HA_SBUSY)
++ if (inb(sh->base + HA_RSTATUS) & HA_SBUSY)
+ continue;
+
+ int_counter++;
++ ret = IRQ_HANDLED;
+
+ hd = SD(sh);
+
+ cp = &hd->ccb[0];
+ cmd = cp->cmd;
+- base = (uint) cmd->device->host->base;
++ base = cmd->device->host->base;
+
+ do {
+ stat = inb(base + HA_RSTATUS);
+@@ -304,7 +310,7 @@ static void eata_pio_int_handler(int irq
+ if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {
+ cmd->result = (DID_OK << 16);
+ hd->devflags |= (1 << cp->cp_id);
+- } else if (hd->devflags & 1 << cp->cp_id)
++ } else if (hd->devflags & (1 << cp->cp_id))
+ cmd->result = (DID_OK << 16) + 0x02;
+ else
+ cmd->result = (DID_NO_CONNECT << 16);
+@@ -313,7 +319,7 @@ static void eata_pio_int_handler(int irq
+ cp->status = FREE;
+ eata_stat = inb(base + HA_RSTATUS);
+ printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n");
+- return;
++ return ret;
+ }
+ #if DBG_INTR2
+ if (stat != 0x50)
+@@ -325,12 +331,12 @@ static void eata_pio_int_handler(int irq
+ cmd->scsi_done(cmd);
+ }
+
+- return;
++ return ret;
+ }
+
+-static inline uint eata_pio_send_command(uint base, unsigned char command)
++static inline unsigned int eata_pio_send_command(unsigned long base, unsigned char command)
+ {
+- uint loop = HZ / 2;
++ unsigned int loop = 50;
+
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
+ if (--loop == 0)
+@@ -349,8 +355,8 @@ static inline uint eata_pio_send_command
+ static int eata_pio_queue(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+ {
+- uint x, y;
+- uint base;
++ unsigned int x, y;
++ unsigned long base;
+
+ hostdata *hd;
+ struct Scsi_Host *sh;
+@@ -360,7 +366,7 @@ static int eata_pio_queue(struct scsi_cm
+
+ hd = HD(cmd);
+ sh = cmd->device->host;
+- base = (uint) sh->base;
++ base = sh->base;
+
+ /* use only slot 0, as 2001 can handle only one cmd at a time */
+
+@@ -395,9 +401,9 @@ static int eata_pio_queue(struct scsi_cm
+ cp->DataIn = 0; /* Input mode */
+
+ cp->Interpret = (cmd->device->id == hd->hostid);
+- cp->cp_datalen = htonl((unsigned long) cmd->request_bufflen);
++ cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
+ cp->Auto_Req_Sen = 0;
+- cp->cp_reqDMA = htonl(0);
++ cp->cp_reqDMA = 0;
+ cp->reqlen = 0;
+
+ cp->cp_id = cmd->device->id;
+@@ -406,7 +412,7 @@ static int eata_pio_queue(struct scsi_cm
+ cp->cp_identify = 1;
+ memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+- cp->cp_statDMA = htonl(0);
++ cp->cp_statDMA = 0;
+
+ cp->cp_viraddr = cp;
+ cp->cmd = cmd;
+@@ -445,14 +451,14 @@ static int eata_pio_queue(struct scsi_cm
+
+ DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
+ "Queued base %#.4lx pid: %ld "
+- "slot %d irq %d\n", (long) sh->base, cmd->pid, y, sh->irq));
++ "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq));
+
+ return (0);
+ }
+
+ static int eata_pio_abort(struct scsi_cmnd *cmd)
+ {
+- uint loop = HZ;
++ unsigned int loop = 100;
+
+ DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
+ "eata_pio_abort called pid: %ld\n",
+@@ -485,7 +491,7 @@ static int eata_pio_abort(struct scsi_cm
+
+ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
+ {
+- uint x, limit = 0;
++ unsigned int x, limit = 0;
+ unsigned char success = 0;
+ struct scsi_cmnd *sp;
+ struct Scsi_Host *host = cmd->device->host;
+@@ -518,7 +524,7 @@ static int eata_pio_host_reset(struct sc
+ }
+
+ /* hard reset the HBA */
+- outb(EATA_CMD_RESET, (uint) cmd->device->host->base + HA_WCOMMAND);
++ outb(EATA_CMD_RESET, cmd->device->host->base + HA_WCOMMAND);
+
+ DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
+ HD(cmd)->state = RESET;
+@@ -558,7 +564,7 @@ static int eata_pio_host_reset(struct sc
+ }
+ }
+
+-static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned long cplen, unsigned short cppadlen)
++static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned int id, unsigned long cplen, unsigned short cppadlen)
+ {
+ struct eata_ccb cp;
+ static char buff[256];
+@@ -570,8 +576,8 @@ static char *get_pio_board_data(unsigned
+ cp.DataIn = 1;
+ cp.Interpret = 1; /* Interpret command */
+
+- cp.cp_datalen = htonl(254);
+- cp.cp_dataDMA = htonl(0);
++ cp.cp_datalen = cpu_to_be32(254);
++ cp.cp_dataDMA = cpu_to_be32(0);
+
+ cp.cp_id = id;
+ cp.cp_lun = 0;
+@@ -583,7 +589,7 @@ static char *get_pio_board_data(unsigned
+ cp.cp_cdb[4] = 254;
+ cp.cp_cdb[5] = 0;
+
+- if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP))
++ if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
+ return (NULL);
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+ outsw(base + HA_RDATA, &cp, cplen);
+@@ -604,7 +610,7 @@ static char *get_pio_board_data(unsigned
+ }
+ }
+
+-static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
++static int get_pio_conf_PIO(unsigned long base, struct get_conf *buf)
+ {
+ unsigned long loop = HZ / 2;
+ int z;
+@@ -619,30 +625,30 @@ static int get_pio_conf_PIO(u32 base, st
+ if (--loop == 0)
+ goto fail;
+
+- DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
++ DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#lx\n", base));
+ eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
+
+- loop = HZ / 2;
++ loop = 50;
+ for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+ if (--loop == 0)
+ goto fail;
+
+- loop = HZ / 2;
++ loop = 50;
+ *p = inw(base + HA_RDATA);
+ }
+ if (inb(base + HA_RSTATUS) & HA_SERROR) {
+ DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during "
+- "transfer for HBA at %x\n", base));
++ "transfer for HBA at %lx\n", base));
+ goto fail;
+ }
+
+- if (htonl(EATA_SIGNATURE) != buf->signature)
++ if (cpu_to_be32(EATA_SIGNATURE) != buf->signature)
+ goto fail;
+
+ DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
+- "at %#4x EATA Level: %x\n",
+- base, (uint) (buf->version)));
++ "at %#4lx EATA Level: %x\n",
++ base, (unsigned int) (buf->version)));
+
+ while (inb(base + HA_RSTATUS) & HA_SDRQ)
+ inw(base + HA_RDATA);
+@@ -665,12 +671,12 @@ static int get_pio_conf_PIO(u32 base, st
+ static void print_pio_config(struct get_conf *gc)
+ {
+ printk("Please check values: (read config data)\n");
+- printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", (uint) ntohl(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+- printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
++ printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", be32_to_cpu(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
++ printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], be16_to_cpu(gc->queuesiz), be16_to_cpu(gc->SGsiz), gc->SECOND);
+ printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest);
+ }
+
+-static uint print_selftest(uint base)
++static unsigned int print_selftest(unsigned int base)
+ {
+ unsigned char buffer[512];
+ #ifdef VERBOSE_SETUP
+@@ -697,7 +703,7 @@ static uint print_selftest(uint base)
+ return (!(inb(base + HA_RSTATUS) & HA_SERROR));
+ }
+
+-static int register_pio_HBA(long base, struct get_conf *gc)
++static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev)
+ {
+ unsigned long size = 0;
+ char *buff;
+@@ -714,17 +720,17 @@ static int register_pio_HBA(long base, s
+ return 0;
+ }
+
+- if ((buff = get_pio_board_data((uint) base, gc->IRQ, gc->scsi_id[3], cplen = (htonl(gc->cplen) + 1) / 2, cppadlen = (htons(gc->cppadlen) + 1) / 2)) == NULL) {
+- printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (unsigned long) base);
++ if ((buff = get_pio_board_data(base, gc->IRQ, gc->scsi_id[3], cplen = (cpu_to_be32(gc->cplen) + 1) / 2, cppadlen = (cpu_to_be16(gc->cppadlen) + 1) / 2)) == NULL) {
++ printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", base);
+ return 0;
+ }
+
+ if (!print_selftest(base) && !ALLOW_DMA_BOARDS) {
+- printk("HBA at %#lx failed while performing self test & setup.\n", (unsigned long) base);
++ printk("HBA at %#lx failed while performing self test & setup.\n", base);
+ return 0;
+ }
+
+- size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
++ size = sizeof(hostdata) + (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz));
+
+ sh = scsi_register(&driver_template, size);
+ if (sh == NULL)
+@@ -749,8 +755,8 @@ static int register_pio_HBA(long base, s
+
+ hd = SD(sh);
+
+- memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
+- memset(hd->reads, 0, sizeof(unsigned long) * 26);
++ memset(hd->ccb, 0, (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz)));
++ memset(hd->reads, 0, sizeof(hd->reads));
+
+ strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor));
+ strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name));
+@@ -761,7 +767,7 @@ static int register_pio_HBA(long base, s
+ SD(sh)->revision[4] = buff[35];
+ SD(sh)->revision[5] = 0;
+
+- switch (ntohl(gc->len)) {
++ switch (be32_to_cpu(gc->len)) {
+ case 0x1c:
+ SD(sh)->EATA_revision = 'a';
+ break;
+@@ -777,7 +783,7 @@ static int register_pio_HBA(long base, s
+ SD(sh)->EATA_revision = '?';
+ }
+
+- if (ntohl(gc->len) >= 0x22) {
++ if (be32_to_cpu(gc->len) >= 0x22) {
+ if (gc->is_PCI)
+ hd->bustype = IS_PCI;
+ else if (gc->is_EISA)
+@@ -811,6 +817,8 @@ static int register_pio_HBA(long base, s
+
+ hd->channel = 0;
+
++ hd->pdev = pci_dev_get(pdev); /* Keep a PCI reference */
++
+ sh->max_id = 8;
+ sh->max_lun = 8;
+
+@@ -841,7 +849,7 @@ static void find_pio_ISA(struct get_conf
+ continue;
+ if (!get_pio_conf_PIO(ISAbases[i], buf))
+ continue;
+- if (!register_pio_HBA(ISAbases[i], buf))
++ if (!register_pio_HBA(ISAbases[i], buf, NULL))
+ release_region(ISAbases[i], 9);
+ else
+ ISAbases[i] = 0;
+@@ -873,7 +881,7 @@ static void find_pio_EISA(struct get_con
+ if (get_pio_conf_PIO(base, buf)) {
+ DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
+ if (buf->IRQ) {
+- if (!register_pio_HBA(base, buf))
++ if (!register_pio_HBA(base, buf, NULL))
+ release_region(base, 9);
+ } else {
+ printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
+@@ -896,9 +904,9 @@ static void find_pio_PCI(struct get_conf
+ printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
+ #else
+ struct pci_dev *dev = NULL;
+- u32 base, x;
++ unsigned long base, x;
+
+- while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
++ while ((dev = pci_get_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
+ DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev)));
+ if (pci_enable_device(dev))
+ continue;
+@@ -926,7 +934,7 @@ static void find_pio_PCI(struct get_conf
+ * eventually remove it from the EISA and ISA list
+ */
+
+- if (!register_pio_HBA(base, buf)) {
++ if (!register_pio_HBA(base, buf, dev)) {
+ release_region(base, 9);
+ continue;
+ }
+@@ -976,12 +984,12 @@ static int eata_pio_detect(struct scsi_h
+ printk("Registered HBAs:\n");
+ printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n");
+ for (i = 1; i <= registered_HBAs; i++) {
+- printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %d %d %c"
++ printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d %d %d %c"
+ " %2d %2d %2d\n",
+ HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+ SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ?
+ "PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ",
+- (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
++ HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
+ SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue,
+ HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+ HBA_ptr = SD(HBA_ptr)->next;
+diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
+index 5630868..2c2fe80 100644
+--- a/drivers/scsi/esp.c
++++ b/drivers/scsi/esp.c
+@@ -184,7 +184,7 @@ enum {
+ };
+
+ /* Forward declarations. */
+-static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
++static irqreturn_t esp_intr(int irq, void *dev_id);
+
+ /* Debugging routines */
+ struct esp_cmdstrings {
+@@ -4282,7 +4282,7 @@ state_machine:
+ }
+
+ /* Service only the ESP described by dev_id. */
+-static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
++static irqreturn_t esp_intr(int irq, void *dev_id)
+ {
+ struct esp *esp = dev_id;
+ unsigned long flags;
+diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
+index 7f89102..c4e16c0 100644
+--- a/drivers/scsi/fcal.c
++++ b/drivers/scsi/fcal.c
+@@ -248,8 +248,7 @@ int fcal_proc_info (struct Scsi_Host *ho
+ if (scd->id == target) {
+ SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ",
+ alpa, target, u1[0], u1[1], u2[0], u2[1]);
+- SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
+- scsi_device_types[(short) scd->type] : "Unknown device");
++ SPRINTF ("%s ", scsi_device_type(scd->type));
+
+ for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
+ SPRINTF ("%c", scd->vendor[j]);
+diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
+index dde3edf..ef8285c 100644
+--- a/drivers/scsi/fd_mcs.c
++++ b/drivers/scsi/fd_mcs.c
+@@ -281,7 +281,7 @@ static struct fd_mcs_adapters_struct fd_
+
+ #define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
+
+-static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t fd_mcs_intr(int irq, void *dev_id);
+
+ static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
+ static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+@@ -617,7 +617,7 @@ static void my_done(struct Scsi_Host *sh
+ }
+
+ /* only my_done needs to be protected */
+-static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ int status;
+diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
+index b0694dc..5d4ea6f 100644
+--- a/drivers/scsi/fdomain.c
++++ b/drivers/scsi/fdomain.c
+@@ -278,9 +278,9 @@
+ #include <linux/pci.h>
+ #include <linux/stat.h>
+ #include <linux/delay.h>
++#include <linux/io.h>
+ #include <scsi/scsicam.h>
+
+-#include <asm/io.h>
+ #include <asm/system.h>
+
+ #include <scsi/scsi.h>
+@@ -387,6 +387,7 @@ static void __iomem * bios_mem;
+ static int bios_major;
+ static int bios_minor;
+ static int PCI_bus;
++static struct pci_dev *PCI_dev;
+ static int Quantum; /* Quantum board variant */
+ static int interrupt_level;
+ static volatile int in_command;
+@@ -403,8 +404,7 @@ static volatile int in_interrupt_fl
+ static int FIFO_Size = 0x2000; /* 8k FIFO for
+ pre-tmc18c30 chips */
+
+-static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id,
+- struct pt_regs * regs );
++static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id );
+ /* Allow insmod parameters to be like LILO parameters. For example:
+ insmod fdomain fdomain=0x140,11 */
+ static char * fdomain = NULL;
+@@ -813,9 +813,10 @@ static int fdomain_pci_bios_detect( int
+ PCI_DEVICE_ID_FD_36C70 );
+ #endif
+
+- if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
++ if ((pdev = pci_get_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
+ return 0;
+- if (pci_enable_device(pdev)) return 0;
++ if (pci_enable_device(pdev))
++ goto fail;
+
+ #if DEBUG_DETECT
+ printk( "scsi: <fdomain> TMC-3260 detect:"
+@@ -832,7 +833,7 @@ static int fdomain_pci_bios_detect( int
+ pci_irq = pdev->irq;
+
+ if (!request_region( pci_base, 0x10, "fdomain" ))
+- return 0;
++ goto fail;
+
+ /* Now we have the I/O base address and interrupt from the PCI
+ configuration registers. */
+@@ -849,17 +850,22 @@ static int fdomain_pci_bios_detect( int
+ if (!fdomain_is_valid_port(pci_base)) {
+ printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" );
+ release_region(pci_base, 0x10);
+- return 0;
++ goto fail;
+ }
+
+ /* Fill in a few global variables. Ugh. */
+ bios_major = bios_minor = -1;
+ PCI_bus = 1;
++ PCI_dev = pdev;
+ Quantum = 0;
+ bios_base = 0;
+
+ return 1;
++fail:
++ pci_dev_put(pdev);
++ return 0;
+ }
++
+ #endif
+
+ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
+@@ -910,8 +916,7 @@ struct Scsi_Host *__fdomain_16x0_detect(
+ if (setup_called) {
+ printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
+ }
+- release_region(port_base, 0x10);
+- return NULL;
++ goto fail;
+ }
+
+ if (this_id) {
+@@ -943,8 +948,7 @@ struct Scsi_Host *__fdomain_16x0_detect(
+ /* Log IRQ with kernel */
+ if (!interrupt_level) {
+ printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" );
+- release_region(port_base, 0x10);
+- return NULL;
++ goto fail;
+ } else {
+ /* Register the IRQ with the kernel */
+
+@@ -965,11 +969,14 @@ struct Scsi_Host *__fdomain_16x0_detect(
+ printk(KERN_ERR " Send mail to faith at acm.org\n" );
+ }
+ printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
+- release_region(port_base, 0x10);
+- return NULL;
++ goto fail;
+ }
+ }
+ return shpnt;
++fail:
++ pci_dev_put(pdev);
++ release_region(port_base, 0x10);
++ return NULL;
+ }
+
+ static int fdomain_16x0_detect(struct scsi_host_template *tpnt)
+@@ -1094,8 +1101,7 @@ static void my_done(int error)
+ #endif
+ }
+
+-static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id,
+- struct pt_regs * regs )
++static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ int status;
+@@ -1716,6 +1722,8 @@ static int fdomain_16x0_release(struct S
+ free_irq(shpnt->irq, shpnt);
+ if (shpnt->io_port && shpnt->n_io_port)
+ release_region(shpnt->io_port, shpnt->n_io_port);
++ if (PCI_bus)
++ pci_dev_put(PCI_dev);
+ return 0;
+ }
+
+@@ -1738,6 +1746,15 @@ struct scsi_host_template fdomain_driver
+ };
+
+ #ifndef PCMCIA
++
++static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
++ { }
++};
++MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
++
+ #define driver_template fdomain_driver_template
+ #include "scsi_module.c"
++
+ #endif
+diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
+index 67f1100..cdd893b 100644
+--- a/drivers/scsi/g_NCR5380.c
++++ b/drivers/scsi/g_NCR5380.c
+@@ -811,7 +811,6 @@ static int generic_NCR5380_proc_info(str
+ struct NCR5380_hostdata *hostdata;
+ #ifdef NCR5380_STATS
+ struct scsi_device *dev;
+- extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+ #endif
+
+ NCR5380_setup(scsi_ptr);
+@@ -851,7 +850,7 @@ static int generic_NCR5380_proc_info(str
+ long tr = hostdata->time_read[dev->id] / HZ;
+ long tw = hostdata->time_write[dev->id] / HZ;
+
+- PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
++ PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
+ for (i = 0; i < 8; i++)
+ if (dev->vendor[i] >= 0x20)
+ *(buffer + (len++)) = dev->vendor[i];
+diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
+index 43afd47..4bc14ad 100644
+--- a/drivers/scsi/gdth.c
++++ b/drivers/scsi/gdth.c
+@@ -424,7 +424,7 @@
+
+ static void gdth_delay(int milliseconds);
+ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
+-static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t gdth_interrupt(int irq, void *dev_id);
+ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
+ static int gdth_async_event(int hanum);
+ static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
+@@ -724,7 +724,7 @@ int __gdth_execute(struct scsi_device *s
+ int timeout, u32 *info)
+ {
+ Scsi_Cmnd *scp;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ int rval;
+
+ scp = kmalloc(sizeof(*scp), GFP_KERNEL);
+@@ -764,7 +764,7 @@ int __gdth_execute(struct scsi_device *s
+ {
+ Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE);
+ unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ int rval;
+
+ if (!scp)
+@@ -1804,7 +1804,7 @@ static int gdth_wait(int hanum,int index
+
+ gdth_from_wait = TRUE;
+ do {
+- gdth_interrupt((int)ha->irq,ha,NULL);
++ gdth_interrupt((int)ha->irq,ha);
+ if (wait_hanum==hanum && wait_index==index) {
+ answer_found = TRUE;
+ break;
+@@ -3406,7 +3406,7 @@ static void gdth_clear_events(void)
+
+ /* SCSI interface functions */
+
+-static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
++static irqreturn_t gdth_interrupt(int irq,void *dev_id)
+ {
+ gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
+ register gdth_ha_str *ha;
+diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
+index 47eae02..8c29eaf 100644
+--- a/drivers/scsi/gdth.h
++++ b/drivers/scsi/gdth.h
+@@ -936,18 +936,12 @@ typedef struct {
+ gdth_binfo_str binfo; /* controller info */
+ gdth_evt_data dvr; /* event structure */
+ spinlock_t smp_lock;
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ struct pci_dev *pdev;
+-#endif
+ char oem_name[8];
+ #ifdef GDTH_DMA_STATISTICS
+ ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */
+ #endif
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ struct scsi_device *sdev;
+-#else
+- struct scsi_device sdev;
+-#endif
+ } gdth_ha_str;
+
+ /* structure for scsi_register(), SCSI bus != 0 */
+@@ -1029,10 +1023,6 @@ typedef struct {
+
+ /* function prototyping */
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
+-#else
+-int gdth_proc_info(char *,char **,off_t,int,int,int);
+-#endif
+
+ #endif
+diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
+index a0d831b..2f6c113 100644
+--- a/drivers/scsi/gvp11.c
++++ b/drivers/scsi/gvp11.c
+@@ -24,7 +24,7 @@
+ #define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
+ #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+-static irqreturn_t gvp11_intr (int irq, void *_instance, struct pt_regs *fp)
++static irqreturn_t gvp11_intr (int irq, void *_instance)
+ {
+ unsigned long flags;
+ unsigned int status;
+@@ -47,7 +47,7 @@ void gvp11_setup (char *str, int *ints)
+ gvp11_xfer_mask = ints[1];
+ }
+
+-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
++static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
+ {
+ unsigned short cntr = GVP11_DMAC_INT_ENABLE;
+ unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+@@ -142,8 +142,8 @@ static int dma_setup (Scsi_Cmnd *cmd, in
+ return 0;
+ }
+
+-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+- int status)
++static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
++ int status)
+ {
+ /* stop DMA */
+ DMA(instance)->SP_DMA = 1;
+@@ -341,7 +341,7 @@ release:
+ return num_gvp11;
+ }
+
+-static int gvp11_bus_reset(Scsi_Cmnd *cmd)
++static int gvp11_bus_reset(struct scsi_cmnd *cmd)
+ {
+ /* FIXME perform bus-specific reset */
+
+diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
+index 575d219..bf22859 100644
+--- a/drivers/scsi/gvp11.h
++++ b/drivers/scsi/gvp11.h
+@@ -13,10 +13,6 @@
+
+ int gvp11_detect(struct scsi_host_template *);
+ int gvp11_release(struct Scsi_Host *);
+-const char *wd33c93_info(void);
+-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int wd33c93_abort(Scsi_Cmnd *);
+-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 2
+diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
+index dfcb96f..68ef163 100644
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -265,6 +265,9 @@ static void scsi_host_dev_release(struct
+ destroy_workqueue(shost->work_q);
+
+ scsi_destroy_command_freelist(shost);
++ if (shost->bqt)
++ blk_free_tags(shost->bqt);
++
+ kfree(shost->shost_data);
+
+ if (parent)
+@@ -487,7 +490,9 @@ EXPORT_SYMBOL(scsi_is_host_device);
+ * @work: Work to queue for execution.
+ *
+ * Return value:
+- * 0 on success / != 0 for error
++ * 1 - work queued for execution
++ * 0 - work is already queued
++ * -EINVAL - work queue doesn't exist
+ **/
+ int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
+ {
+diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
+deleted file mode 100644
+index c27264b..0000000
+--- a/drivers/scsi/hosts.h
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#warning "This file is obsolete, please use <scsi/scsi_host.h> instead"
+-#include <scsi/scsi_host.h>
+diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
+index bcb3444..bec83cb 100644
+--- a/drivers/scsi/hptiop.c
++++ b/drivers/scsi/hptiop.c
+@@ -15,7 +15,6 @@
+ *
+ * For more information, visit http://www.highpoint-tech.com
+ */
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/string.h>
+@@ -432,7 +431,7 @@ void hptiop_iop_request_callback(struct
+ writel(tag, &hba->iop->outbound_queue);
+ }
+
+-static irqreturn_t hptiop_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hptiop_intr(int irq, void *dev_id)
+ {
+ struct hptiop_hba *hba = dev_id;
+ int handled;
+diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
+index 2be1dc5..0e57fb6 100644
+--- a/drivers/scsi/ibmmca.c
++++ b/drivers/scsi/ibmmca.c
+@@ -497,8 +497,7 @@ static int option_setup(char *);
+ static int ldn_access_load(int, int);
+ static int ldn_access_total_read_write(int);
+
+-static irqreturn_t interrupt_handler(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t interrupt_handler(int irq, void *dev_id)
+ {
+ int host_index, ihost_index;
+ unsigned int intr_reg;
+diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
+index 669ea4f..fbc1d5c 100644
+--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
+@@ -1213,7 +1213,7 @@ void ibmvscsi_handle_crq(struct viosrp_c
+ "ibmvscsi: Re-enabling adapter!\n");
+ purge_requests(hostdata, DID_REQUEUE);
+ if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
+- hostdata) == 0) ||
++ hostdata)) ||
+ (ibmvscsi_send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
+ atomic_set(&hostdata->request_limit,
+diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
+index ed22b96..227c0f2 100644
+--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
++++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
+@@ -45,14 +45,11 @@ static unsigned int partition_number = -
+ * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * @irq: number of irq to handle, not used
+ * @dev_instance: ibmvscsi_host_data of host that received interrupt
+- * @regs: pt_regs with registers
+ *
+ * Disables interrupts and schedules srp_task
+ * Always returns IRQ_HANDLED
+ */
+-static irqreturn_t ibmvscsi_handle_event(int irq,
+- void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
+ {
+ struct ibmvscsi_host_data *hostdata =
+ (struct ibmvscsi_host_data *)dev_instance;
+@@ -156,8 +153,8 @@ static void gather_partition_info(void)
+ {
+ struct device_node *rootdn;
+
+- char *ppartition_name;
+- unsigned int *p_number_ptr;
++ const char *ppartition_name;
++ const unsigned int *p_number_ptr;
+
+ /* Retrieve information about this partition */
+ rootdn = find_path_device("/");
+@@ -165,14 +162,11 @@ static void gather_partition_info(void)
+ return;
+ }
+
+- ppartition_name =
+- get_property(rootdn, "ibm,partition-name", NULL);
++ ppartition_name = get_property(rootdn, "ibm,partition-name", NULL);
+ if (ppartition_name)
+ strncpy(partition_name, ppartition_name,
+ sizeof(partition_name));
+- p_number_ptr =
+- (unsigned int *)get_property(rootdn, "ibm,partition-no",
+- NULL);
++ p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+ if (p_number_ptr)
+ partition_number = *p_number_ptr;
+ }
+diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
+index 94d1de5..1427a41 100644
+--- a/drivers/scsi/ide-scsi.c
++++ b/drivers/scsi/ide-scsi.c
+@@ -344,7 +344,7 @@ static int idescsi_check_condition(ide_d
+ pc->buffer = buf;
+ pc->c[0] = REQUEST_SENSE;
+ pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE;
+- rq->flags = REQ_SENSE;
++ rq->cmd_type = REQ_TYPE_SENSE;
+ pc->timeout = jiffies + WAIT_READY;
+ /* NOTE! Save the failed packet command in "rq->buffer" */
+ rq->buffer = (void *) failed_command->special;
+@@ -398,12 +398,12 @@ static int idescsi_end_request (ide_driv
+ int errors = rq->errors;
+ unsigned long flags;
+
+- if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) {
++ if (!blk_special_request(rq) && !blk_sense_request(rq)) {
+ ide_end_request(drive, uptodate, nrsecs);
+ return 0;
+ }
+ ide_end_drive_cmd (drive, 0, 0);
+- if (rq->flags & REQ_SENSE) {
++ if (blk_sense_request(rq)) {
+ idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer;
+ if (log) {
+ printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number);
+@@ -708,11 +708,11 @@ static ide_startstop_t idescsi_issue_pc
+ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
+ {
+ #if IDESCSI_DEBUG_LOG
+- printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
++ printk (KERN_INFO "dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
+ printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+ #endif /* IDESCSI_DEBUG_LOG */
+
+- if (rq->flags & (REQ_SPECIAL|REQ_SENSE)) {
++ if (blk_sense_request(rq) || blk_special_request(rq)) {
+ return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
+ }
+ blk_dump_rq_flags(rq, "ide-scsi: unsup command");
+@@ -938,7 +938,7 @@ static int idescsi_queue (struct scsi_cm
+
+ ide_init_drive_cmd (rq);
+ rq->special = (char *) pc;
+- rq->flags = REQ_SPECIAL;
++ rq->cmd_type = REQ_TYPE_SPECIAL;
+ spin_unlock_irq(host->host_lock);
+ rq->rq_disk = scsi->disk;
+ (void) ide_do_drive_cmd (drive, rq, ide_end);
+@@ -992,7 +992,7 @@ static int idescsi_eh_abort (struct scsi
+ */
+ printk (KERN_ERR "ide-scsi: cmd aborted!\n");
+
+- if (scsi->pc->rq->flags & REQ_SENSE)
++ if (blk_sense_request(scsi->pc->rq))
+ kfree(scsi->pc->buffer);
+ kfree(scsi->pc->rq);
+ kfree(scsi->pc);
+@@ -1042,7 +1042,7 @@ static int idescsi_eh_reset (struct scsi
+ /* kill current request */
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, 0);
+- if (req->flags & REQ_SENSE)
++ if (blk_sense_request(req))
+ kfree(scsi->pc->buffer);
+ kfree(scsi->pc);
+ scsi->pc = NULL;
+diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
+index 2d95ac9..e31f612 100644
+--- a/drivers/scsi/imm.c
++++ b/drivers/scsi/imm.c
+@@ -1153,7 +1153,7 @@ static int __imm_attach(struct parport *
+ {
+ struct Scsi_Host *host;
+ imm_struct *dev;
+- DECLARE_WAIT_QUEUE_HEAD(waiting);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
+ DEFINE_WAIT(wait);
+ int ports;
+ int modes, ppb;
+diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
+index ece936a..8f6f32f 100644
+--- a/drivers/scsi/imm.h
++++ b/drivers/scsi/imm.h
+@@ -66,7 +66,6 @@
+ */
+ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+-#include <linux/config.h>
+ #include <linux/stddef.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
+index 59a4097..312190a 100644
+--- a/drivers/scsi/in2000.c
++++ b/drivers/scsi/in2000.c
+@@ -829,7 +829,7 @@ static void transfer_bytes(Scsi_Cmnd * c
+ * but it _does_ need to be able to compile and run in an SMP kernel.)
+ */
+
+-static irqreturn_t in2000_intr(int irqnum, void *dev_id, struct pt_regs *ptregs)
++static irqreturn_t in2000_intr(int irqnum, void *dev_id)
+ {
+ struct Scsi_Host *instance = dev_id;
+ struct IN2000_hostdata *hostdata;
+diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
+index 9e10dac..afed293 100644
+--- a/drivers/scsi/initio.c
++++ b/drivers/scsi/initio.c
+@@ -142,8 +142,6 @@
+ #define i91u_MAXQUEUE 2
+ #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
+
+-#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */
+-#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */
+ #define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
+ #define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
+ #define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
+@@ -171,13 +169,16 @@ static int setup_debug = 0;
+
+ static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+
+-static const PCI_ID i91u_pci_devices[] = {
+- { INI_VENDOR_ID, I950_DEVICE_ID },
+- { INI_VENDOR_ID, I940_DEVICE_ID },
+- { INI_VENDOR_ID, I935_DEVICE_ID },
+- { INI_VENDOR_ID, I920_DEVICE_ID },
+- { DMX_VENDOR_ID, I920_DEVICE_ID },
++/* PCI Devices supported by this driver */
++static struct pci_device_id i91u_pci_devices[] __devinitdata = {
++ { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
+ };
++MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
+
+ #define DEBUG_INTERRUPT 0
+ #define DEBUG_QUEUE 0
+@@ -2748,7 +2749,7 @@ int tul_wait_done_disc(HCS * pCurHcb)
+ return (tul_bad_seq(pCurHcb));
+ }
+
+-static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i91u_intr(int irqno, void *dev_id)
+ {
+ struct Scsi_Host *dev = dev_id;
+ unsigned long flags;
+@@ -2771,7 +2772,7 @@ static int tul_NewReturnNumberOfAdapters
+
+ for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++)
+ {
+- while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
++ while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) {
+ if (pci_enable_device(pDev))
+ continue;
+ pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
+index 01080b3..2dde821 100644
+--- a/drivers/scsi/ipr.c
++++ b/drivers/scsi/ipr.c
+@@ -70,6 +70,7 @@
+ #include <linux/firmware.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
++#include <linux/libata.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/processor.h>
+@@ -78,6 +79,7 @@
+ #include <scsi/scsi_tcq.h>
+ #include <scsi/scsi_eh.h>
+ #include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_transport.h>
+ #include "ipr.h"
+
+ /*
+@@ -175,6 +177,8 @@ struct ipr_error_table_t ipr_error_table
+ "Qualified success"},
+ {0x01080000, 1, 1,
+ "FFFE: Soft device bus error recovered by the IOA"},
++ {0x01088100, 0, 1,
++ "4101: Soft device bus fabric error"},
+ {0x01170600, 0, 1,
+ "FFF9: Device sector reassign successful"},
+ {0x01170900, 0, 1,
+@@ -197,6 +201,8 @@ struct ipr_error_table_t ipr_error_table
+ "FFFA: Undefined device response recovered by the IOA"},
+ {0x014A0000, 1, 1,
+ "FFF6: Device bus error, message or command phase"},
++ {0x014A8000, 0, 1,
++ "FFFE: Task Management Function failed"},
+ {0x015D0000, 0, 1,
+ "FFF6: Failure prediction threshold exceeded"},
+ {0x015D9200, 0, 1,
+@@ -225,6 +231,8 @@ struct ipr_error_table_t ipr_error_table
+ "3109: IOA timed out a device command"},
+ {0x04088000, 0, 0,
+ "3120: SCSI bus is not operational"},
++ {0x04088100, 0, 1,
++ "4100: Hard device bus fabric error"},
+ {0x04118000, 0, 1,
+ "9000: IOA reserved area data check"},
+ {0x04118100, 0, 1,
+@@ -257,6 +265,8 @@ struct ipr_error_table_t ipr_error_table
+ "Device bus status error"},
+ {0x04448600, 0, 1,
+ "8157: IOA error requiring IOA reset to recover"},
++ {0x04448700, 0, 0,
++ "ATA device status error"},
+ {0x04490000, 0, 0,
+ "Message reject received from the device"},
+ {0x04449200, 0, 1,
+@@ -269,10 +279,20 @@ struct ipr_error_table_t ipr_error_table
+ "9082: IOA detected device error"},
+ {0x044A0000, 1, 1,
+ "3110: Device bus error, message or command phase"},
++ {0x044A8000, 1, 1,
++ "3110: SAS Command / Task Management Function failed"},
+ {0x04670400, 0, 1,
+ "9091: Incorrect hardware configuration change has been detected"},
+ {0x04678000, 0, 1,
+ "9073: Invalid multi-adapter configuration"},
++ {0x04678100, 0, 1,
++ "4010: Incorrect connection between cascaded expanders"},
++ {0x04678200, 0, 1,
++ "4020: Connections exceed IOA design limits"},
++ {0x04678300, 0, 1,
++ "4030: Incorrect multipath connection"},
++ {0x04679000, 0, 1,
++ "4110: Unsupported enclosure function"},
+ {0x046E0000, 0, 1,
+ "FFF4: Command to logical unit failed"},
+ {0x05240000, 1, 0,
+@@ -297,6 +317,8 @@ struct ipr_error_table_t ipr_error_table
+ "9031: Array protection temporarily suspended, protection resuming"},
+ {0x06040600, 0, 1,
+ "9040: Array protection temporarily suspended, protection resuming"},
++ {0x06288000, 0, 1,
++ "3140: Device bus not ready to ready transition"},
+ {0x06290000, 0, 1,
+ "FFFB: SCSI bus was reset"},
+ {0x06290500, 0, 0,
+@@ -319,6 +341,16 @@ struct ipr_error_table_t ipr_error_table
+ "3150: SCSI bus configuration error"},
+ {0x06678100, 0, 1,
+ "9074: Asymmetric advanced function disk configuration"},
++ {0x06678300, 0, 1,
++ "4040: Incomplete multipath connection between IOA and enclosure"},
++ {0x06678400, 0, 1,
++ "4041: Incomplete multipath connection between enclosure and device"},
++ {0x06678500, 0, 1,
++ "9075: Incomplete multipath connection between IOA and remote IOA"},
++ {0x06678600, 0, 1,
++ "9076: Configuration error, missing remote IOA"},
++ {0x06679100, 0, 1,
++ "4050: Enclosure does not support a required multipath function"},
+ {0x06690200, 0, 1,
+ "9041: Array protection temporarily suspended"},
+ {0x06698200, 0, 1,
+@@ -331,6 +363,10 @@ struct ipr_error_table_t ipr_error_table
+ "9072: Link not operational transition"},
+ {0x066B8200, 0, 1,
+ "9032: Array exposed but still protected"},
++ {0x066B9100, 0, 1,
++ "4061: Multipath redundancy level got better"},
++ {0x066B9200, 0, 1,
++ "4060: Multipath redundancy level got worse"},
+ {0x07270000, 0, 0,
+ "Failure due to other device"},
+ {0x07278000, 0, 1,
+@@ -425,7 +461,8 @@ static void ipr_trc_hook(struct ipr_cmnd
+ trace_entry->time = jiffies;
+ trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
+ trace_entry->type = type;
+- trace_entry->cmd_index = ipr_cmd->cmd_index;
++ trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command;
++ trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff;
+ trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
+ trace_entry->u.add_data = add_data;
+ }
+@@ -452,8 +489,10 @@ static void ipr_reinit_ipr_cmnd(struct i
+ ioarcb->read_ioadl_len = 0;
+ ioasa->ioasc = 0;
+ ioasa->residual_data_len = 0;
++ ioasa->u.gata.status = 0;
+
+ ipr_cmd->scsi_cmd = NULL;
++ ipr_cmd->qc = NULL;
+ ipr_cmd->sense_buffer[0] = 0;
+ ipr_cmd->dma_use_sg = 0;
+ }
+@@ -598,6 +637,28 @@ static int ipr_set_pcix_cmd_reg(struct i
+ }
+
+ /**
++ * ipr_sata_eh_done - done function for aborted SATA commands
++ * @ipr_cmd: ipr command struct
++ *
++ * This function is invoked for ops generated to SATA
++ * devices which are being aborted.
++ *
++ * Return value:
++ * none
++ **/
++static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
++{
++ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
++ struct ata_queued_cmd *qc = ipr_cmd->qc;
++ struct ipr_sata_port *sata_port = qc->ap->private_data;
++
++ qc->err_mask |= AC_ERR_OTHER;
++ sata_port->ioasa.status |= ATA_BUSY;
++ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
++ ata_qc_complete(qc);
++}
++
++/**
+ * ipr_scsi_eh_done - mid-layer done function for aborted ops
+ * @ipr_cmd: ipr command struct
+ *
+@@ -641,6 +702,8 @@ static void ipr_fail_all_ops(struct ipr_
+
+ if (ipr_cmd->scsi_cmd)
+ ipr_cmd->done = ipr_scsi_eh_done;
++ else if (ipr_cmd->qc)
++ ipr_cmd->done = ipr_sata_eh_done;
+
+ ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);
+ del_timer(&ipr_cmd->timer);
+@@ -797,6 +860,7 @@ static void ipr_init_res_entry(struct ip
+ res->del_from_ml = 0;
+ res->resetting_device = 0;
+ res->sdev = NULL;
++ res->sata_port = NULL;
+ }
+
+ /**
+@@ -1288,7 +1352,7 @@ static u32 ipr_get_error(u32 ioasc)
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++)
+- if (ipr_error_table[i].ioasc == ioasc)
++ if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK))
+ return i;
+
+ return 0;
+@@ -3023,6 +3087,17 @@ static int ipr_free_dump(struct ipr_ioa_
+ **/
+ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
+ {
++ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
++ struct ipr_resource_entry *res;
++ unsigned long lock_flags = 0;
++
++ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
++ res = (struct ipr_resource_entry *)sdev->hostdata;
++
++ if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN)
++ qdepth = IPR_MAX_CMD_PER_ATA_LUN;
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
++
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ return sdev->queue_depth;
+ }
+@@ -3138,6 +3213,122 @@ static int ipr_biosparam(struct scsi_dev
+ }
+
+ /**
++ * ipr_find_starget - Find target based on bus/target.
++ * @starget: scsi target struct
++ *
++ * Return value:
++ * resource entry pointer if found / NULL if not found
++ **/
++static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget)
++{
++ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
++ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
++ struct ipr_resource_entry *res;
++
++ list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
++ if ((res->cfgte.res_addr.bus == starget->channel) &&
++ (res->cfgte.res_addr.target == starget->id) &&
++ (res->cfgte.res_addr.lun == 0)) {
++ return res;
++ }
++ }
++
++ return NULL;
++}
++
++static struct ata_port_info sata_port_info;
++
++/**
++ * ipr_target_alloc - Prepare for commands to a SCSI target
++ * @starget: scsi target struct
++ *
++ * If the device is a SATA device, this function allocates an
++ * ATA port with libata, else it does nothing.
++ *
++ * Return value:
++ * 0 on success / non-0 on failure
++ **/
++static int ipr_target_alloc(struct scsi_target *starget)
++{
++ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
++ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
++ struct ipr_sata_port *sata_port;
++ struct ata_port *ap;
++ struct ipr_resource_entry *res;
++ unsigned long lock_flags;
++
++ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
++ res = ipr_find_starget(starget);
++ starget->hostdata = NULL;
++
++ if (res && ipr_is_gata(res)) {
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
++ sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL);
++ if (!sata_port)
++ return -ENOMEM;
++
++ ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost);
++ if (ap) {
++ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
++ sata_port->ioa_cfg = ioa_cfg;
++ sata_port->ap = ap;
++ sata_port->res = res;
++
++ res->sata_port = sata_port;
++ ap->private_data = sata_port;
++ starget->hostdata = sata_port;
++ } else {
++ kfree(sata_port);
++ return -ENOMEM;
++ }
++ }
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
++
++ return 0;
++}
++
++/**
++ * ipr_target_destroy - Destroy a SCSI target
++ * @starget: scsi target struct
++ *
++ * If the device was a SATA device, this function frees the libata
++ * ATA port, else it does nothing.
++ *
++ **/
++static void ipr_target_destroy(struct scsi_target *starget)
++{
++ struct ipr_sata_port *sata_port = starget->hostdata;
++
++ if (sata_port) {
++ starget->hostdata = NULL;
++ ata_sas_port_destroy(sata_port->ap);
++ kfree(sata_port);
++ }
++}
++
++/**
++ * ipr_find_sdev - Find device based on bus/target/lun.
++ * @sdev: scsi device struct
++ *
++ * Return value:
++ * resource entry pointer if found / NULL if not found
++ **/
++static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev)
++{
++ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
++ struct ipr_resource_entry *res;
++
++ list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
++ if ((res->cfgte.res_addr.bus == sdev->channel) &&
++ (res->cfgte.res_addr.target == sdev->id) &&
++ (res->cfgte.res_addr.lun == sdev->lun))
++ return res;
++ }
++
++ return NULL;
++}
++
++/**
+ * ipr_slave_destroy - Unconfigure a SCSI device
+ * @sdev: scsi device struct
+ *
+@@ -3155,8 +3346,11 @@ static void ipr_slave_destroy(struct scs
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = (struct ipr_resource_entry *) sdev->hostdata;
+ if (res) {
++ if (res->sata_port)
++ ata_port_disable(res->sata_port->ap);
+ sdev->hostdata = NULL;
+ res->sdev = NULL;
++ res->sata_port = NULL;
+ }
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ }
+@@ -3191,13 +3385,45 @@ static int ipr_slave_configure(struct sc
+ }
+ if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
+ sdev->allow_restart = 1;
+- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
++ if (ipr_is_gata(res) && res->sata_port) {
++ scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN);
++ ata_sas_slave_configure(sdev, res->sata_port->ap);
++ } else {
++ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
++ }
+ }
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return 0;
+ }
+
+ /**
++ * ipr_ata_slave_alloc - Prepare for commands to a SATA device
++ * @sdev: scsi device struct
++ *
++ * This function initializes an ATA port so that future commands
++ * sent through queuecommand will work.
++ *
++ * Return value:
++ * 0 on success
++ **/
++static int ipr_ata_slave_alloc(struct scsi_device *sdev)
++{
++ struct ipr_sata_port *sata_port = NULL;
++ int rc = -ENXIO;
++
++ ENTER;
++ if (sdev->sdev_target)
++ sata_port = sdev->sdev_target->hostdata;
++ if (sata_port)
++ rc = ata_sas_port_init(sata_port->ap);
++ if (rc)
++ ipr_slave_destroy(sdev);
++
++ LEAVE;
++ return rc;
++}
++
++/**
+ * ipr_slave_alloc - Prepare for commands to a device.
+ * @sdev: scsi device struct
+ *
+@@ -3220,18 +3446,18 @@ static int ipr_slave_alloc(struct scsi_d
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+- list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+- if ((res->cfgte.res_addr.bus == sdev->channel) &&
+- (res->cfgte.res_addr.target == sdev->id) &&
+- (res->cfgte.res_addr.lun == sdev->lun)) {
+- res->sdev = sdev;
+- res->add_to_ml = 0;
+- res->in_erp = 0;
+- sdev->hostdata = res;
+- if (!ipr_is_naca_model(res))
+- res->needs_sync_complete = 1;
+- rc = 0;
+- break;
++ res = ipr_find_sdev(sdev);
++ if (res) {
++ res->sdev = sdev;
++ res->add_to_ml = 0;
++ res->in_erp = 0;
++ sdev->hostdata = res;
++ if (!ipr_is_naca_model(res))
++ res->needs_sync_complete = 1;
++ rc = 0;
++ if (ipr_is_gata(res)) {
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
++ return ipr_ata_slave_alloc(sdev);
+ }
+ }
+
+@@ -3286,7 +3512,8 @@ static int ipr_eh_host_reset(struct scsi
+ * This function issues a device reset to the affected device.
+ * If the device is a SCSI device, a LUN reset will be sent
+ * to the device first. If that does not work, a target reset
+- * will be sent.
++ * will be sent. If the device is a SATA device, a PHY reset will
++ * be sent.
+ *
+ * Return value:
+ * 0 on success / non-zero on failure
+@@ -3297,26 +3524,79 @@ static int ipr_device_reset(struct ipr_i
+ struct ipr_cmnd *ipr_cmd;
+ struct ipr_ioarcb *ioarcb;
+ struct ipr_cmd_pkt *cmd_pkt;
++ struct ipr_ioarcb_ata_regs *regs;
+ u32 ioasc;
+
+ ENTER;
+ ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+ ioarcb = &ipr_cmd->ioarcb;
+ cmd_pkt = &ioarcb->cmd_pkt;
++ regs = &ioarcb->add_data.u.regs;
+
+ ioarcb->res_handle = res->cfgte.res_handle;
+ cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
+ cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
++ if (ipr_is_gata(res)) {
++ cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET;
++ ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags));
++ regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
++ }
+
+ ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
+ ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
++ if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET)
++ memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
++ sizeof(struct ipr_ioasa_gata));
+
+ LEAVE;
+ return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
+ }
+
+ /**
++ * ipr_sata_reset - Reset the SATA port
++ * @ap: SATA port to reset
++ * @classes: class of the attached device
++ *
++ * This function issues a SATA phy reset to the affected ATA port.
++ *
++ * Return value:
++ * 0 on success / non-zero on failure
++ **/
++static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
++{
++ struct ipr_sata_port *sata_port = ap->private_data;
++ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
++ struct ipr_resource_entry *res;
++ unsigned long lock_flags = 0;
++ int rc = -ENXIO;
++
++ ENTER;
++ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
++ res = sata_port->res;
++ if (res) {
++ rc = ipr_device_reset(ioa_cfg, res);
++ switch(res->cfgte.proto) {
++ case IPR_PROTO_SATA:
++ case IPR_PROTO_SAS_STP:
++ *classes = ATA_DEV_ATA;
++ break;
++ case IPR_PROTO_SATA_ATAPI:
++ case IPR_PROTO_SAS_STP_ATAPI:
++ *classes = ATA_DEV_ATAPI;
++ break;
++ default:
++ *classes = ATA_DEV_UNKNOWN;
++ break;
++ };
++ }
++
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
++ LEAVE;
++ return rc;
++}
++
++/**
+ * ipr_eh_dev_reset - Reset the device
+ * @scsi_cmd: scsi command struct
+ *
+@@ -3332,7 +3612,8 @@ static int __ipr_eh_dev_reset(struct scs
+ struct ipr_cmnd *ipr_cmd;
+ struct ipr_ioa_cfg *ioa_cfg;
+ struct ipr_resource_entry *res;
+- int rc;
++ struct ata_port *ap;
++ int rc = 0;
+
+ ENTER;
+ ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
+@@ -3360,7 +3641,14 @@ static int __ipr_eh_dev_reset(struct scs
+
+ res->resetting_device = 1;
+ scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
+- rc = ipr_device_reset(ioa_cfg, res);
++
++ if (ipr_is_gata(res) && res->sata_port) {
++ ap = res->sata_port->ap;
++ spin_unlock_irq(scsi_cmd->device->host->host_lock);
++ ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL);
++ spin_lock_irq(scsi_cmd->device->host->host_lock);
++ } else
++ rc = ipr_device_reset(ioa_cfg, res);
+ res->resetting_device = 0;
+
+ LEAVE;
+@@ -3592,12 +3880,11 @@ static irqreturn_t ipr_handle_other_inte
+ * ipr_isr - Interrupt service routine
+ * @irq: irq number
+ * @devp: pointer to ioa config struct
+- * @regs: pt_regs struct
+ *
+ * Return value:
+ * IRQ_NONE / IRQ_HANDLED
+ **/
+-static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs)
++static irqreturn_t ipr_isr(int irq, void *devp)
+ {
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
+ unsigned long lock_flags = 0;
+@@ -4099,8 +4386,7 @@ static int ipr_get_autosense(struct ipr_
+ {
+ struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+
+- if ((be32_to_cpu(ioasa->ioasc_specific) &
+- (IPR_ADDITIONAL_STATUS_FMT | IPR_AUTOSENSE_VALID)) == 0)
++ if ((be32_to_cpu(ioasa->ioasc_specific) & IPR_AUTOSENSE_VALID) == 0)
+ return 0;
+
+ memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
+@@ -4190,7 +4476,8 @@ static void ipr_erp_start(struct ipr_ioa
+ case IPR_IOASC_NR_INIT_CMD_REQUIRED:
+ break;
+ default:
+- scsi_cmd->result |= (DID_ERROR << 16);
++ if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
++ scsi_cmd->result |= (DID_ERROR << 16);
+ if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res))
+ res->needs_sync_complete = 1;
+ break;
+@@ -4272,6 +4559,9 @@ static int ipr_queuecommand(struct scsi_
+ return 0;
+ }
+
++ if (ipr_is_gata(res) && res->sata_port)
++ return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
++
+ ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+ ioarcb = &ipr_cmd->ioarcb;
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+@@ -4317,6 +4607,26 @@ static int ipr_queuecommand(struct scsi_
+ }
+
+ /**
++ * ipr_ioctl - IOCTL handler
++ * @sdev: scsi device struct
++ * @cmd: IOCTL cmd
++ * @arg: IOCTL arg
++ *
++ * Return value:
++ * 0 on success / other on failure
++ **/
++int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
++{
++ struct ipr_resource_entry *res;
++
++ res = (struct ipr_resource_entry *)sdev->hostdata;
++ if (res && ipr_is_gata(res))
++ return ata_scsi_ioctl(sdev, cmd, arg);
++
++ return -EINVAL;
++}
++
++/**
+ * ipr_info - Get information about the card/driver
+ * @scsi_host: scsi host struct
+ *
+@@ -4338,10 +4648,45 @@ static const char * ipr_ioa_info(struct
+ return buffer;
+ }
+
++/**
++ * ipr_scsi_timed_out - Handle scsi command timeout
++ * @scsi_cmd: scsi command struct
++ *
++ * Return value:
++ * EH_NOT_HANDLED
++ **/
++enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd)
++{
++ struct ipr_ioa_cfg *ioa_cfg;
++ struct ipr_cmnd *ipr_cmd;
++ unsigned long flags;
++
++ ENTER;
++ spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
++ ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
++
++ list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
++ if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) {
++ ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
++ ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
++ LEAVE;
++ return EH_NOT_HANDLED;
++}
++
++static struct scsi_transport_template ipr_transport_template = {
++ .eh_timed_out = ipr_scsi_timed_out
++};
++
+ static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
+ .name = "IPR",
+ .info = ipr_ioa_info,
++ .ioctl = ipr_ioctl,
+ .queuecommand = ipr_queuecommand,
+ .eh_abort_handler = ipr_eh_abort,
+ .eh_device_reset_handler = ipr_eh_dev_reset,
+@@ -4349,6 +4694,8 @@ static struct scsi_host_template driver_
+ .slave_alloc = ipr_slave_alloc,
+ .slave_configure = ipr_slave_configure,
+ .slave_destroy = ipr_slave_destroy,
++ .target_alloc = ipr_target_alloc,
++ .target_destroy = ipr_target_destroy,
+ .change_queue_depth = ipr_change_queue_depth,
+ .change_queue_type = ipr_change_queue_type,
+ .bios_param = ipr_biosparam,
+@@ -4363,6 +4710,330 @@ static struct scsi_host_template driver_
+ .proc_name = IPR_NAME
+ };
+
++/**
++ * ipr_ata_phy_reset - libata phy_reset handler
++ * @ap: ata port to reset
++ *
++ **/
++static void ipr_ata_phy_reset(struct ata_port *ap)
++{
++ unsigned long flags;
++ struct ipr_sata_port *sata_port = ap->private_data;
++ struct ipr_resource_entry *res = sata_port->res;
++ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
++ int rc;
++
++ ENTER;
++ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
++ while(ioa_cfg->in_reset_reload) {
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
++ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
++ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
++ }
++
++ if (!ioa_cfg->allow_cmds)
++ goto out_unlock;
++
++ rc = ipr_device_reset(ioa_cfg, res);
++
++ if (rc) {
++ ap->ops->port_disable(ap);
++ goto out_unlock;
++ }
++
++ switch(res->cfgte.proto) {
++ case IPR_PROTO_SATA:
++ case IPR_PROTO_SAS_STP:
++ ap->device[0].class = ATA_DEV_ATA;
++ break;
++ case IPR_PROTO_SATA_ATAPI:
++ case IPR_PROTO_SAS_STP_ATAPI:
++ ap->device[0].class = ATA_DEV_ATAPI;
++ break;
++ default:
++ ap->device[0].class = ATA_DEV_UNKNOWN;
++ ap->ops->port_disable(ap);
++ break;
++ };
++
++out_unlock:
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
++ LEAVE;
++}
++
++/**
++ * ipr_ata_post_internal - Cleanup after an internal command
++ * @qc: ATA queued command
++ *
++ * Return value:
++ * none
++ **/
++static void ipr_ata_post_internal(struct ata_queued_cmd *qc)
++{
++ struct ipr_sata_port *sata_port = qc->ap->private_data;
++ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
++ struct ipr_cmnd *ipr_cmd;
++ unsigned long flags;
++
++ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
++ list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
++ if (ipr_cmd->qc == qc) {
++ ipr_device_reset(ioa_cfg, sata_port->res);
++ break;
++ }
++ }
++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
++}
++
++/**
++ * ipr_tf_read - Read the current ATA taskfile for the ATA port
++ * @ap: ATA port
++ * @tf: destination ATA taskfile
++ *
++ * Return value:
++ * none
++ **/
++static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ struct ipr_sata_port *sata_port = ap->private_data;
++ struct ipr_ioasa_gata *g = &sata_port->ioasa;
++
++ tf->feature = g->error;
++ tf->nsect = g->nsect;
++ tf->lbal = g->lbal;
++ tf->lbam = g->lbam;
++ tf->lbah = g->lbah;
++ tf->device = g->device;
++ tf->command = g->status;
++ tf->hob_nsect = g->hob_nsect;
++ tf->hob_lbal = g->hob_lbal;
++ tf->hob_lbam = g->hob_lbam;
++ tf->hob_lbah = g->hob_lbah;
++ tf->ctl = g->alt_status;
++}
++
++/**
++ * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure
++ * @regs: destination
++ * @tf: source ATA taskfile
++ *
++ * Return value:
++ * none
++ **/
++static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs,
++ struct ata_taskfile *tf)
++{
++ regs->feature = tf->feature;
++ regs->nsect = tf->nsect;
++ regs->lbal = tf->lbal;
++ regs->lbam = tf->lbam;
++ regs->lbah = tf->lbah;
++ regs->device = tf->device;
++ regs->command = tf->command;
++ regs->hob_feature = tf->hob_feature;
++ regs->hob_nsect = tf->hob_nsect;
++ regs->hob_lbal = tf->hob_lbal;
++ regs->hob_lbam = tf->hob_lbam;
++ regs->hob_lbah = tf->hob_lbah;
++ regs->ctl = tf->ctl;
++}
++
++/**
++ * ipr_sata_done - done function for SATA commands
++ * @ipr_cmd: ipr command struct
++ *
++ * This function is invoked by the interrupt handler for
++ * ops generated by the SCSI mid-layer to SATA devices
++ *
++ * Return value:
++ * none
++ **/
++static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
++{
++ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
++ struct ata_queued_cmd *qc = ipr_cmd->qc;
++ struct ipr_sata_port *sata_port = qc->ap->private_data;
++ struct ipr_resource_entry *res = sata_port->res;
++ u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
++
++ memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
++ sizeof(struct ipr_ioasa_gata));
++ ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
++
++ if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
++ scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus,
++ res->cfgte.res_addr.target);
++
++ if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
++ qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
++ else
++ qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status);
++ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
++ ata_qc_complete(qc);
++}
++
++/**
++ * ipr_build_ata_ioadl - Build an ATA scatter/gather list
++ * @ipr_cmd: ipr command struct
++ * @qc: ATA queued command
++ *
++ **/
++static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
++ struct ata_queued_cmd *qc)
++{
++ u32 ioadl_flags = 0;
++ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
++ struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
++ int len = qc->nbytes + qc->pad_len;
++ struct scatterlist *sg;
++
++ if (len == 0)
++ return;
++
++ if (qc->dma_dir == DMA_TO_DEVICE) {
++ ioadl_flags = IPR_IOADL_FLAGS_WRITE;
++ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
++ ioarcb->write_data_transfer_length = cpu_to_be32(len);
++ ioarcb->write_ioadl_len =
++ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
++ } else if (qc->dma_dir == DMA_FROM_DEVICE) {
++ ioadl_flags = IPR_IOADL_FLAGS_READ;
++ ioarcb->read_data_transfer_length = cpu_to_be32(len);
++ ioarcb->read_ioadl_len =
++ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
++ }
++
++ ata_for_each_sg(sg, qc) {
++ ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
++ ioadl->address = cpu_to_be32(sg_dma_address(sg));
++ if (ata_sg_is_last(sg, qc))
++ ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
++ else
++ ioadl++;
++ }
++}
++
++/**
++ * ipr_qc_issue - Issue a SATA qc to a device
++ * @qc: queued command
++ *
++ * Return value:
++ * 0 if success
++ **/
++static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct ipr_sata_port *sata_port = ap->private_data;
++ struct ipr_resource_entry *res = sata_port->res;
++ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
++ struct ipr_cmnd *ipr_cmd;
++ struct ipr_ioarcb *ioarcb;
++ struct ipr_ioarcb_ata_regs *regs;
++
++ if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
++ return -EIO;
++
++ ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
++ ioarcb = &ipr_cmd->ioarcb;
++ regs = &ioarcb->add_data.u.regs;
++
++ memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data));
++ ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs));
++
++ list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
++ ipr_cmd->qc = qc;
++ ipr_cmd->done = ipr_sata_done;
++ ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
++ ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU;
++ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
++ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
++ ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
++
++ ipr_build_ata_ioadl(ipr_cmd, qc);
++ regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
++ ipr_copy_sata_tf(regs, &qc->tf);
++ memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN);
++ ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
++
++ switch (qc->tf.protocol) {
++ case ATA_PROT_NODATA:
++ case ATA_PROT_PIO:
++ break;
++
++ case ATA_PROT_DMA:
++ regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
++ break;
++
++ case ATA_PROT_ATAPI:
++ case ATA_PROT_ATAPI_NODATA:
++ regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
++ break;
++
++ case ATA_PROT_ATAPI_DMA:
++ regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
++ regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
++ break;
++
++ default:
++ WARN_ON(1);
++ return -1;
++ }
++
++ mb();
++ writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
++ ioa_cfg->regs.ioarrin_reg);
++ return 0;
++}
++
++/**
++ * ipr_ata_check_status - Return last ATA status
++ * @ap: ATA port
++ *
++ * Return value:
++ * ATA status
++ **/
++static u8 ipr_ata_check_status(struct ata_port *ap)
++{
++ struct ipr_sata_port *sata_port = ap->private_data;
++ return sata_port->ioasa.status;
++}
++
++/**
++ * ipr_ata_check_altstatus - Return last ATA altstatus
++ * @ap: ATA port
++ *
++ * Return value:
++ * Alt ATA status
++ **/
++static u8 ipr_ata_check_altstatus(struct ata_port *ap)
++{
++ struct ipr_sata_port *sata_port = ap->private_data;
++ return sata_port->ioasa.alt_status;
++}
++
++static struct ata_port_operations ipr_sata_ops = {
++ .port_disable = ata_port_disable,
++ .check_status = ipr_ata_check_status,
++ .check_altstatus = ipr_ata_check_altstatus,
++ .dev_select = ata_noop_dev_select,
++ .phy_reset = ipr_ata_phy_reset,
++ .post_internal_cmd = ipr_ata_post_internal,
++ .tf_read = ipr_tf_read,
++ .qc_prep = ata_noop_qc_prep,
++ .qc_issue = ipr_qc_issue,
++ .port_start = ata_sas_port_start,
++ .port_stop = ata_sas_port_stop
++};
++
++static struct ata_port_info sata_port_info = {
++ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
++ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
++ .pio_mask = 0x10, /* pio4 */
++ .mwdma_mask = 0x07,
++ .udma_mask = 0x7f, /* udma0-6 */
++ .port_ops = &ipr_sata_ops
++};
++
+ #ifdef CONFIG_PPC_PSERIES
+ static const u16 ipr_blocked_processors[] = {
+ PV_NORTHSTAR,
+@@ -6324,7 +6995,7 @@ static int __devinit ipr_probe_ioa(struc
+ struct Scsi_Host *host;
+ unsigned long ipr_regs_pci;
+ void __iomem *ipr_regs;
+- u32 rc = PCIBIOS_SUCCESSFUL;
++ int rc = PCIBIOS_SUCCESSFUL;
+ volatile u32 mask, uproc;
+
+ ENTER;
+@@ -6346,6 +7017,9 @@ static int __devinit ipr_probe_ioa(struc
+
+ ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
+ memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
++ host->transportt = &ipr_transport_template;
++ ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
++ sata_port_info.flags, &ipr_sata_ops);
+
+ ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
+
+@@ -6721,7 +7395,7 @@ static int __init ipr_init(void)
+ ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n",
+ IPR_DRIVER_VERSION, IPR_DRIVER_DATE);
+
+- return pci_module_init(&ipr_driver);
++ return pci_register_driver(&ipr_driver);
+ }
+
+ /**
+diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
+index 1ad24df..6d03528 100644
+--- a/drivers/scsi/ipr.h
++++ b/drivers/scsi/ipr.h
+@@ -28,6 +28,7 @@
+
+ #include <linux/types.h>
+ #include <linux/completion.h>
++#include <linux/libata.h>
+ #include <linux/list.h>
+ #include <linux/kref.h>
+ #include <scsi/scsi.h>
+@@ -36,8 +37,8 @@
+ /*
+ * Literals
+ */
+-#define IPR_DRIVER_VERSION "2.1.3"
+-#define IPR_DRIVER_DATE "(March 29, 2006)"
++#define IPR_DRIVER_VERSION "2.2.0"
++#define IPR_DRIVER_DATE "(September 25, 2006)"
+
+ /*
+ * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
+@@ -45,6 +46,7 @@
+ * This can be adjusted at runtime through sysfs device attributes.
+ */
+ #define IPR_MAX_CMD_PER_LUN 6
++#define IPR_MAX_CMD_PER_ATA_LUN 1
+
+ /*
+ * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of
+@@ -106,7 +108,7 @@
+ #define IPR_IOA_BUS 0xff
+ #define IPR_IOA_TARGET 0xff
+ #define IPR_IOA_LUN 0xff
+-#define IPR_MAX_NUM_BUSES 8
++#define IPR_MAX_NUM_BUSES 16
+ #define IPR_MAX_BUS_TO_SCAN IPR_MAX_NUM_BUSES
+
+ #define IPR_NUM_RESET_RELOAD_RETRIES 3
+@@ -145,6 +147,7 @@
+ #define IPR_LUN_RESET 0x40
+ #define IPR_TARGET_RESET 0x20
+ #define IPR_BUS_RESET 0x10
++#define IPR_ATA_PHY_RESET 0x80
+ #define IPR_ID_HOST_RR_Q 0xC4
+ #define IPR_QUERY_IOA_CONFIG 0xC5
+ #define IPR_CANCEL_ALL_REQUESTS 0xCE
+@@ -295,7 +298,11 @@ struct ipr_std_inq_data {
+ }__attribute__ ((packed));
+
+ struct ipr_config_table_entry {
+- u8 service_level;
++ u8 proto;
++#define IPR_PROTO_SATA 0x02
++#define IPR_PROTO_SATA_ATAPI 0x03
++#define IPR_PROTO_SAS_STP 0x06
++#define IPR_PROTO_SAS_STP_ATAPI 0x07
+ u8 array_id;
+ u8 flags;
+ #define IPR_IS_IOA_RESOURCE 0x80
+@@ -307,6 +314,7 @@ struct ipr_config_table_entry {
+ #define IPR_SUBTYPE_AF_DASD 0
+ #define IPR_SUBTYPE_GENERIC_SCSI 1
+ #define IPR_SUBTYPE_VOLUME_SET 2
++#define IPR_SUBTYPE_GENERIC_ATA 4
+
+ #define IPR_QUEUEING_MODEL(res) ((((res)->cfgte.flags) & 0x70) >> 4)
+ #define IPR_QUEUE_FROZEN_MODEL 0
+@@ -350,6 +358,7 @@ struct ipr_cmd_pkt {
+ #define IPR_RQTYPE_SCSICDB 0x00
+ #define IPR_RQTYPE_IOACMD 0x01
+ #define IPR_RQTYPE_HCAM 0x02
++#define IPR_RQTYPE_ATA_PASSTHRU 0x04
+
+ u8 luntar_luntrn;
+
+@@ -373,6 +382,37 @@ struct ipr_cmd_pkt {
+ __be16 timeout;
+ }__attribute__ ((packed, aligned(4)));
+
++struct ipr_ioarcb_ata_regs {
++ u8 flags;
++#define IPR_ATA_FLAG_PACKET_CMD 0x80
++#define IPR_ATA_FLAG_XFER_TYPE_DMA 0x40
++#define IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION 0x20
++ u8 reserved[3];
++
++ __be16 data;
++ u8 feature;
++ u8 nsect;
++ u8 lbal;
++ u8 lbam;
++ u8 lbah;
++ u8 device;
++ u8 command;
++ u8 reserved2[3];
++ u8 hob_feature;
++ u8 hob_nsect;
++ u8 hob_lbal;
++ u8 hob_lbam;
++ u8 hob_lbah;
++ u8 ctl;
++}__attribute__ ((packed, aligned(4)));
++
++struct ipr_ioarcb_add_data {
++ union {
++ struct ipr_ioarcb_ata_regs regs;
++ __be32 add_cmd_parms[10];
++ }u;
++}__attribute__ ((packed, aligned(4)));
++
+ /* IOA Request Control Block 128 bytes */
+ struct ipr_ioarcb {
+ __be32 ioarcb_host_pci_addr;
+@@ -397,7 +437,7 @@ struct ipr_ioarcb {
+ struct ipr_cmd_pkt cmd_pkt;
+
+ __be32 add_cmd_parms_len;
+- __be32 add_cmd_parms[10];
++ struct ipr_ioarcb_add_data add_data;
+ }__attribute__((packed, aligned (4)));
+
+ struct ipr_ioadl_desc {
+@@ -433,6 +473,21 @@ struct ipr_ioasa_gpdd {
+ __be32 ioa_data[2];
+ }__attribute__((packed, aligned (4)));
+
++struct ipr_ioasa_gata {
++ u8 error;
++ u8 nsect; /* Interrupt reason */
++ u8 lbal;
++ u8 lbam;
++ u8 lbah;
++ u8 device;
++ u8 status;
++ u8 alt_status; /* ATA CTL */
++ u8 hob_nsect;
++ u8 hob_lbal;
++ u8 hob_lbam;
++ u8 hob_lbah;
++}__attribute__((packed, aligned (4)));
++
+ struct ipr_auto_sense {
+ __be16 auto_sense_len;
+ __be16 ioa_data_len;
+@@ -466,6 +521,7 @@ struct ipr_ioasa {
+ __be32 ioasc_specific; /* status code specific field */
+ #define IPR_ADDITIONAL_STATUS_FMT 0x80000000
+ #define IPR_AUTOSENSE_VALID 0x40000000
++#define IPR_ATA_DEVICE_WAS_RESET 0x20000000
+ #define IPR_IOASC_SPECIFIC_MASK 0x00ffffff
+ #define IPR_FIELD_POINTER_VALID (0x80000000 >> 8)
+ #define IPR_FIELD_POINTER_MASK 0x0000ffff
+@@ -474,6 +530,7 @@ struct ipr_ioasa {
+ struct ipr_ioasa_vset vset;
+ struct ipr_ioasa_af_dasd dasd;
+ struct ipr_ioasa_gpdd gpdd;
++ struct ipr_ioasa_gata gata;
+ } u;
+
+ struct ipr_auto_sense auto_sense;
+@@ -793,6 +850,13 @@ struct ipr_bus_attributes {
+ u32 max_xfer_rate;
+ };
+
++struct ipr_sata_port {
++ struct ipr_ioa_cfg *ioa_cfg;
++ struct ata_port *ap;
++ struct ipr_resource_entry *res;
++ struct ipr_ioasa_gata ioasa;
++};
++
+ struct ipr_resource_entry {
+ struct ipr_config_table_entry cfgte;
+ u8 needs_sync_complete:1;
+@@ -802,6 +866,7 @@ struct ipr_resource_entry {
+ u8 resetting_device:1;
+
+ struct scsi_device *sdev;
++ struct ipr_sata_port *sata_port;
+ struct list_head queue;
+ };
+
+@@ -872,10 +937,11 @@ struct ipr_trace_entry {
+ u32 time;
+
+ u8 op_code;
++ u8 ata_op_code;
+ u8 type;
+ #define IPR_TRACE_START 0x00
+ #define IPR_TRACE_FINISH 0xff
+- u16 cmd_index;
++ u8 cmd_index;
+
+ __be32 res_handle;
+ union {
+@@ -1017,6 +1083,7 @@ struct ipr_ioa_cfg {
+
+ struct ipr_cmnd *reset_cmd;
+
++ struct ata_host ata_host;
+ char ipr_cmd_label[8];
+ #define IPR_CMD_LABEL "ipr_cmnd"
+ struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
+@@ -1029,6 +1096,7 @@ struct ipr_cmnd {
+ struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
+ struct list_head queue;
+ struct scsi_cmnd *scsi_cmd;
++ struct ata_queued_cmd *qc;
+ struct completion completion;
+ struct timer_list timer;
+ void (*done) (struct ipr_cmnd *);
+@@ -1308,6 +1376,22 @@ static inline int ipr_is_scsi_disk(struc
+ }
+
+ /**
++ * ipr_is_gata - Determine if a resource is a generic ATA resource
++ * @res: resource entry struct
++ *
++ * Return value:
++ * 1 if GATA / 0 if not GATA
++ **/
++static inline int ipr_is_gata(struct ipr_resource_entry *res)
++{
++ if (!ipr_is_ioa_resource(res) &&
++ IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_ATA)
++ return 1;
++ else
++ return 0;
++}
++
++/**
+ * ipr_is_naca_model - Determine if a resource is using NACA queueing model
+ * @res: resource entry struct
+ *
+diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
+index 3c63928..f06a06a 100644
+--- a/drivers/scsi/ips.c
++++ b/drivers/scsi/ips.c
+@@ -182,14 +182,8 @@
+ #include <linux/dma-mapping.h>
+
+ #include <scsi/sg.h>
+-
+ #include "scsi.h"
+-
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+-#include "hosts.h"
+-#else
+ #include <scsi/scsi_host.h>
+-#endif
+
+ #include "ips.h"
+
+@@ -250,11 +244,11 @@ module_param(ips, charp, 0);
+ */
+ static int ips_detect(struct scsi_host_template *);
+ static int ips_release(struct Scsi_Host *);
+-static int ips_eh_abort(Scsi_Cmnd *);
+-static int ips_eh_reset(Scsi_Cmnd *);
+-static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
++static int ips_eh_abort(struct scsi_cmnd *);
++static int ips_eh_reset(struct scsi_cmnd *);
++static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
+ static const char *ips_info(struct Scsi_Host *);
+-static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
++static irqreturn_t do_ipsintr(int, void *);
+ static int ips_hainit(ips_ha_t *);
+ static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
+ static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
+@@ -325,24 +319,26 @@ static uint32_t ips_statupd_copperhead_m
+ static uint32_t ips_statupd_morpheus(ips_ha_t *);
+ static ips_scb_t *ips_getscb(ips_ha_t *);
+ static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
+-static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
++static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *);
+ static void ips_putq_copp_tail(ips_copp_queue_t *,
+ ips_copp_wait_item_t *);
+ static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
+ static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
+-static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
+-static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
++static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
++static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *,
++ struct scsi_cmnd *);
+ static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
+ ips_copp_wait_item_t *);
+ static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
+
+-static int ips_is_passthru(Scsi_Cmnd *);
+-static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
++static int ips_is_passthru(struct scsi_cmnd *);
++static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int);
+ static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
+ static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
+-static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
++static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
+ unsigned int count);
+-static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
++static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data,
++ unsigned int count);
+
+ static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+ static int ips_host_info(ips_ha_t *, char *, off_t, int);
+@@ -812,8 +808,7 @@ ips_halt(struct notifier_block *nb, ulon
+ /* Abort a command (using the new error code stuff) */
+ /* Note: this routine is called under the io_request_lock */
+ /****************************************************************************/
+-int
+-ips_eh_abort(Scsi_Cmnd * SC)
++int ips_eh_abort(struct scsi_cmnd *SC)
+ {
+ ips_ha_t *ha;
+ ips_copp_wait_item_t *item;
+@@ -871,8 +866,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
+ /* NOTE: this routine is called under the io_request_lock spinlock */
+ /* */
+ /****************************************************************************/
+-static int
+-__ips_eh_reset(Scsi_Cmnd * SC)
++static int __ips_eh_reset(struct scsi_cmnd *SC)
+ {
+ int ret;
+ int i;
+@@ -968,7 +962,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
+ ret = (*ha->func.reset) (ha);
+
+ if (!ret) {
+- Scsi_Cmnd *scsi_cmd;
++ struct scsi_cmnd *scsi_cmd;
+
+ IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+ "Controller reset failed - controller now offline.\n");
+@@ -997,7 +991,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
+ }
+
+ if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
+- Scsi_Cmnd *scsi_cmd;
++ struct scsi_cmnd *scsi_cmd;
+
+ IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+ "Controller reset failed - controller now offline.\n");
+@@ -1059,8 +1053,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
+
+ }
+
+-static int
+-ips_eh_reset(Scsi_Cmnd * SC)
++static int ips_eh_reset(struct scsi_cmnd *SC)
+ {
+ int rc;
+
+@@ -1083,8 +1076,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
+ /* Linux obtains io_request_lock before calling this function */
+ /* */
+ /****************************************************************************/
+-static int
+-ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
++static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
+ {
+ ips_ha_t *ha;
+ ips_passthru_t *pt;
+@@ -1336,7 +1328,7 @@ ips_slave_configure(struct scsi_device *
+ /* */
+ /****************************************************************************/
+ static irqreturn_t
+-do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
++do_ipsintr(int irq, void *dev_id)
+ {
+ ips_ha_t *ha;
+ unsigned long cpu_flags;
+@@ -1602,8 +1594,7 @@ ips_proc_info(struct Scsi_Host *host, ch
+ /* Determine if the specified SCSI command is really a passthru command */
+ /* */
+ /****************************************************************************/
+-static int
+-ips_is_passthru(Scsi_Cmnd * SC)
++static int ips_is_passthru(struct scsi_cmnd *SC)
+ {
+ unsigned long flags;
+
+@@ -1685,7 +1676,7 @@ ips_alloc_passthru_buffer(ips_ha_t * ha,
+ /* */
+ /****************************************************************************/
+ static int
+-ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
++ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
+ {
+ ips_passthru_t *pt;
+ int length = 0;
+@@ -2734,9 +2725,9 @@ static void
+ ips_next(ips_ha_t * ha, int intr)
+ {
+ ips_scb_t *scb;
+- Scsi_Cmnd *SC;
+- Scsi_Cmnd *p;
+- Scsi_Cmnd *q;
++ struct scsi_cmnd *SC;
++ struct scsi_cmnd *p;
++ struct scsi_cmnd *q;
+ ips_copp_wait_item_t *item;
+ int ret;
+ unsigned long cpu_flags = 0;
+@@ -2847,7 +2838,7 @@ ips_next(ips_ha_t * ha, int intr)
+ dcdb_active[scmd_channel(p) -
+ 1] & (1 << scmd_id(p)))) {
+ ips_freescb(ha, scb);
+- p = (Scsi_Cmnd *) p->host_scribble;
++ p = (struct scsi_cmnd *) p->host_scribble;
+ continue;
+ }
+
+@@ -2962,7 +2953,7 @@ ips_next(ips_ha_t * ha, int intr)
+ break;
+ } /* end case */
+
+- p = (Scsi_Cmnd *) p->host_scribble;
++ p = (struct scsi_cmnd *) p->host_scribble;
+
+ } /* end while */
+
+@@ -3090,8 +3081,7 @@ ips_removeq_scb(ips_scb_queue_t * queue,
+ /* ASSUMED to be called from within the HA lock */
+ /* */
+ /****************************************************************************/
+-static void
+-ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
++static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item)
+ {
+ METHOD_TRACE("ips_putq_wait_tail", 1);
+
+@@ -3122,10 +3112,9 @@ ips_putq_wait_tail(ips_wait_queue_t * qu
+ /* ASSUMED to be called from within the HA lock */
+ /* */
+ /****************************************************************************/
+-static Scsi_Cmnd *
+-ips_removeq_wait_head(ips_wait_queue_t * queue)
++static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue)
+ {
+- Scsi_Cmnd *item;
++ struct scsi_cmnd *item;
+
+ METHOD_TRACE("ips_removeq_wait_head", 1);
+
+@@ -3135,7 +3124,7 @@ ips_removeq_wait_head(ips_wait_queue_t *
+ return (NULL);
+ }
+
+- queue->head = (Scsi_Cmnd *) item->host_scribble;
++ queue->head = (struct scsi_cmnd *) item->host_scribble;
+ item->host_scribble = NULL;
+
+ if (queue->tail == item)
+@@ -3157,10 +3146,10 @@ ips_removeq_wait_head(ips_wait_queue_t *
+ /* ASSUMED to be called from within the HA lock */
+ /* */
+ /****************************************************************************/
+-static Scsi_Cmnd *
+-ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
++static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue,
++ struct scsi_cmnd *item)
+ {
+- Scsi_Cmnd *p;
++ struct scsi_cmnd *p;
+
+ METHOD_TRACE("ips_removeq_wait", 1);
+
+@@ -3173,8 +3162,8 @@ ips_removeq_wait(ips_wait_queue_t * queu
+
+ p = queue->head;
+
+- while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
+- p = (Scsi_Cmnd *) p->host_scribble;
++ while ((p) && (item != (struct scsi_cmnd *) p->host_scribble))
++ p = (struct scsi_cmnd *) p->host_scribble;
+
+ if (p) {
+ /* found a match */
+@@ -3659,11 +3648,10 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t *
+ /* Routine Name: ips_scmd_buf_write */
+ /* */
+ /* Routine Description: */
+-/* Write data to Scsi_Cmnd request_buffer at proper offsets */
++/* Write data to struct scsi_cmnd request_buffer at proper offsets */
+ /****************************************************************************/
+ static void
+-ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
+- int count)
++ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
+ {
+ if (scmd->use_sg) {
+ int i;
+@@ -3698,11 +3686,10 @@ ips_scmd_buf_write(Scsi_Cmnd * scmd, voi
+ /* Routine Name: ips_scmd_buf_read */
+ /* */
+ /* Routine Description: */
+-/* Copy data from a Scsi_Cmnd to a new, linear buffer */
++/* Copy data from a struct scsi_cmnd to a new, linear buffer */
+ /****************************************************************************/
+ static void
+-ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
+- int count)
++ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
+ {
+ if (scmd->use_sg) {
+ int i;
+@@ -7078,7 +7065,7 @@ ips_remove_device(struct pci_dev *pci_de
+ static int __init
+ ips_module_init(void)
+ {
+- if (pci_module_init(&ips_pci_driver) < 0)
++ if (pci_register_driver(&ips_pci_driver) < 0)
+ return -ENODEV;
+ ips_driver_template.module = THIS_MODULE;
+ ips_order_controllers();
+diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
+index f46c382..34680f3 100644
+--- a/drivers/scsi/ips.h
++++ b/drivers/scsi/ips.h
+@@ -6,7 +6,7 @@
+ /* David Jeffery, Adaptec, Inc. */
+ /* */
+ /* Copyright (C) 1999 IBM Corporation */
+-/* Copyright (C) 2003 Adaptec, Inc. */
++/* Copyright (C) 2003 Adaptec, 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 */
+@@ -1033,14 +1033,14 @@ typedef struct ips_scb_queue {
+ * Wait queue_format
+ */
+ typedef struct ips_wait_queue {
+- Scsi_Cmnd *head;
+- Scsi_Cmnd *tail;
+- int count;
++ struct scsi_cmnd *head;
++ struct scsi_cmnd *tail;
++ int count;
+ } ips_wait_queue_t;
+
+ typedef struct ips_copp_wait_item {
+- Scsi_Cmnd *scsi_cmd;
+- struct ips_copp_wait_item *next;
++ struct scsi_cmnd *scsi_cmd;
++ struct ips_copp_wait_item *next;
+ } ips_copp_wait_item_t;
+
+ typedef struct ips_copp_queue {
+@@ -1149,7 +1149,7 @@ typedef struct ips_scb {
+ uint32_t flags;
+ uint32_t op_code;
+ IPS_SG_LIST sg_list;
+- Scsi_Cmnd *scsi_cmd;
++ struct scsi_cmnd *scsi_cmd;
+ struct ips_scb *q_next;
+ ips_scb_callback callback;
+ uint32_t sg_busaddr;
+@@ -1175,7 +1175,7 @@ typedef struct ips_scb_pt {
+ uint32_t flags;
+ uint32_t op_code;
+ IPS_SG_LIST *sg_list;
+- Scsi_Cmnd *scsi_cmd;
++ struct scsi_cmnd *scsi_cmd;
+ struct ips_scb *q_next;
+ ips_scb_callback callback;
+ } ips_scb_pt_t;
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 058f094..0a9dbc5 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -108,8 +108,8 @@ iscsi_hdr_digest(struct iscsi_conn *conn
+ {
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+- crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
+- buf->sg.length += sizeof(uint32_t);
++ crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
++ buf->sg.length = tcp_conn->hdr_size;
+ }
+
+ static inline int
+@@ -281,7 +281,6 @@ iscsi_solicit_data_init(struct iscsi_con
+ {
+ struct iscsi_data *hdr;
+ struct scsi_cmnd *sc = ctask->sc;
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+
+ hdr = &r2t->dtask.hdr;
+ memset(hdr, 0, sizeof(struct iscsi_data));
+@@ -336,10 +335,12 @@ iscsi_solicit_data_init(struct iscsi_con
+ sg_count += sg->length;
+ }
+ BUG_ON(r2t->sg == NULL);
+- } else
+- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
++ } else {
++ iscsi_buf_init_iov(&r2t->sendbuf,
+ (char*)sc->request_buffer + r2t->data_offset,
+ r2t->data_count);
++ r2t->sg = NULL;
++ }
+ }
+
+ /**
+@@ -358,8 +359,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
+ int r2tsn = be32_to_cpu(rhdr->r2tsn);
+ int rc;
+
+- if (tcp_conn->in.datalen)
++ if (tcp_conn->in.datalen) {
++ printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n",
++ tcp_conn->in.datalen);
+ return ISCSI_ERR_DATALEN;
++ }
+
+ if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
+ return ISCSI_ERR_R2TSN;
+@@ -385,15 +389,23 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
+
+ r2t->exp_statsn = rhdr->statsn;
+ r2t->data_length = be32_to_cpu(rhdr->data_length);
+- if (r2t->data_length == 0 ||
+- r2t->data_length > session->max_burst) {
++ if (r2t->data_length == 0) {
++ printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
+ spin_unlock(&session->lock);
+ return ISCSI_ERR_DATALEN;
+ }
+
++ if (r2t->data_length > session->max_burst)
++ debug_scsi("invalid R2T with data len %u and max burst %u."
++ "Attempting to execute request.\n",
++ r2t->data_length, session->max_burst);
++
+ r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+ if (r2t->data_offset + r2t->data_length > ctask->total_length) {
+ spin_unlock(&session->lock);
++ printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
++ "offset %u and total length %d\n", r2t->data_length,
++ r2t->data_offset, ctask->total_length);
+ return ISCSI_ERR_DATALEN;
+ }
+
+@@ -456,7 +468,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
+
+ sg_init_one(&sg, (u8 *)hdr,
+ sizeof(struct iscsi_hdr) + ahslen);
+- crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
++ crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
++ (u8 *)&cdgst);
+ rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
+ ahslen);
+ if (cdgst != rdgst) {
+@@ -492,7 +505,6 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
+ goto copy_hdr;
+
+ spin_lock(&session->lock);
+- iscsi_tcp_cleanup_ctask(conn, tcp_conn->in.ctask);
+ rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
+ spin_unlock(&session->lock);
+ break;
+@@ -637,10 +649,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *
+ * byte counters.
+ **/
+ static inline int
+-iscsi_tcp_copy(struct iscsi_conn *conn)
++iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
+ {
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+- int buf_size = tcp_conn->in.datalen;
+ int buf_left = buf_size - tcp_conn->data_copied;
+ int size = min(tcp_conn->in.copy, buf_left);
+ int rc;
+@@ -665,15 +676,15 @@ iscsi_tcp_copy(struct iscsi_conn *conn)
+ }
+
+ static inline void
+-partial_sg_digest_update(struct iscsi_tcp_conn *tcp_conn,
+- struct scatterlist *sg, int offset, int length)
++partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
++ int offset, int length)
+ {
+ struct scatterlist temp;
+
+ memcpy(&temp, sg, sizeof(struct scatterlist));
+ temp.offset = offset;
+ temp.length = length;
+- crypto_digest_update(tcp_conn->data_rx_tfm, &temp, 1);
++ crypto_hash_update(desc, &temp, length);
+ }
+
+ static void
+@@ -682,7 +693,7 @@ iscsi_recv_digest_update(struct iscsi_tc
+ struct scatterlist tmp;
+
+ sg_init_one(&tmp, buf, len);
+- crypto_digest_update(tcp_conn->data_rx_tfm, &tmp, 1);
++ crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
+ }
+
+ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
+@@ -736,11 +747,12 @@ static int iscsi_scsi_data_in(struct isc
+ if (!rc) {
+ if (conn->datadgst_en) {
+ if (!offset)
+- crypto_digest_update(
+- tcp_conn->data_rx_tfm,
++ crypto_hash_update(
++ &tcp_conn->rx_hash,
+ &sg[i], 1);
+ else
+- partial_sg_digest_update(tcp_conn,
++ partial_sg_digest_update(
++ &tcp_conn->rx_hash,
+ &sg[i],
+ sg[i].offset + offset,
+ sg[i].length - offset);
+@@ -754,8 +766,10 @@ static int iscsi_scsi_data_in(struct isc
+ /*
+ * data-in is complete, but buffer not...
+ */
+- partial_sg_digest_update(tcp_conn, &sg[i],
+- sg[i].offset, sg[i].length-rc);
++ partial_sg_digest_update(&tcp_conn->rx_hash,
++ &sg[i],
++ sg[i].offset,
++ sg[i].length-rc);
+ rc = 0;
+ break;
+ }
+@@ -772,7 +786,6 @@ done:
+ (long)sc, sc->result, ctask->itt,
+ tcp_conn->in.hdr->flags);
+ spin_lock(&conn->session->lock);
+- iscsi_tcp_cleanup_ctask(conn, ctask);
+ __iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
+ spin_unlock(&conn->session->lock);
+ }
+@@ -792,9 +805,6 @@ iscsi_data_recv(struct iscsi_conn *conn)
+ rc = iscsi_scsi_data_in(conn);
+ break;
+ case ISCSI_OP_SCSI_CMD_RSP:
+- spin_lock(&conn->session->lock);
+- iscsi_tcp_cleanup_ctask(conn, tcp_conn->in.ctask);
+- spin_unlock(&conn->session->lock);
+ case ISCSI_OP_TEXT_RSP:
+ case ISCSI_OP_LOGIN_RSP:
+ case ISCSI_OP_ASYNC_EVENT:
+@@ -803,7 +813,7 @@ iscsi_data_recv(struct iscsi_conn *conn)
+ * Collect data segment to the connection's data
+ * placeholder
+ */
+- if (iscsi_tcp_copy(conn)) {
++ if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
+ rc = -EAGAIN;
+ goto exit;
+ }
+@@ -876,10 +886,8 @@ more:
+ */
+ rc = iscsi_tcp_hdr_recv(conn);
+ if (!rc && tcp_conn->in.datalen) {
+- if (conn->datadgst_en) {
+- BUG_ON(!tcp_conn->data_rx_tfm);
+- crypto_digest_init(tcp_conn->data_rx_tfm);
+- }
++ if (conn->datadgst_en)
++ crypto_hash_init(&tcp_conn->rx_hash);
+ tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
+ } else if (rc) {
+ iscsi_conn_failure(conn, rc);
+@@ -892,10 +900,15 @@ more:
+
+ debug_tcp("extra data_recv offset %d copy %d\n",
+ tcp_conn->in.offset, tcp_conn->in.copy);
+- skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
+- &recv_digest, 4);
+- tcp_conn->in.offset += 4;
+- tcp_conn->in.copy -= 4;
++ rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
++ if (rc) {
++ if (rc == -EAGAIN)
++ goto again;
++ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++ return 0;
++ }
++
++ memcpy(&recv_digest, conn->data, sizeof(uint32_t));
+ if (recv_digest != tcp_conn->in.datadgst) {
+ debug_tcp("iscsi_tcp: data digest error!"
+ "0x%x != 0x%x\n", recv_digest,
+@@ -931,13 +944,14 @@ more:
+ tcp_conn->in.padding);
+ memset(pad, 0, tcp_conn->in.padding);
+ sg_init_one(&sg, pad, tcp_conn->in.padding);
+- crypto_digest_update(tcp_conn->data_rx_tfm,
+- &sg, 1);
++ crypto_hash_update(&tcp_conn->rx_hash,
++ &sg, sg.length);
+ }
+- crypto_digest_final(tcp_conn->data_rx_tfm,
+- (u8 *) & tcp_conn->in.datadgst);
++ crypto_hash_final(&tcp_conn->rx_hash,
++ (u8 *) &tcp_conn->in.datadgst);
+ debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+ tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
++ tcp_conn->data_copied = 0;
+ } else
+ tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+ }
+@@ -1177,37 +1191,12 @@ iscsi_sendpage(struct iscsi_conn *conn,
+
+ static inline void
+ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
+- struct iscsi_cmd_task *ctask)
++ struct iscsi_tcp_cmd_task *tcp_ctask)
+ {
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-
+- BUG_ON(!tcp_conn->data_tx_tfm);
+- crypto_digest_init(tcp_conn->data_tx_tfm);
++ crypto_hash_init(&tcp_conn->tx_hash);
+ tcp_ctask->digest_count = 4;
+ }
+
+-static int
+-iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+- struct iscsi_buf *buf, uint32_t *digest, int final)
+-{
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+- int rc = 0;
+- int sent = 0;
+-
+- if (final)
+- crypto_digest_final(tcp_conn->data_tx_tfm, (u8*)digest);
+-
+- iscsi_buf_init_iov(buf, (char*)digest, 4);
+- rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
+- if (rc) {
+- tcp_ctask->datadigest = *digest;
+- tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
+- } else
+- tcp_ctask->digest_count = 4;
+- return rc;
+-}
+-
+ /**
+ * iscsi_solicit_data_cont - initialize next Data-Out
+ * @conn: iscsi connection
+@@ -1225,7 +1214,6 @@ static void
+ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ struct iscsi_r2t_info *r2t, int left)
+ {
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ struct iscsi_data *hdr;
+ struct scsi_cmnd *sc = ctask->sc;
+ int new_offset;
+@@ -1254,27 +1242,30 @@ iscsi_solicit_data_cont(struct iscsi_con
+ iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
+ sizeof(struct iscsi_hdr));
+
+- if (sc->use_sg && !iscsi_buf_left(&r2t->sendbuf)) {
+- BUG_ON(tcp_ctask->bad_sg == r2t->sg);
++ if (iscsi_buf_left(&r2t->sendbuf))
++ return;
++
++ if (sc->use_sg) {
+ iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
+ r2t->sg += 1;
+- } else
+- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
++ } else {
++ iscsi_buf_init_iov(&r2t->sendbuf,
+ (char*)sc->request_buffer + new_offset,
+ r2t->data_count);
++ r2t->sg = NULL;
++ }
+ }
+
+-static void
+-iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
++static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
++ unsigned long len)
+ {
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- struct iscsi_data_task *dtask;
++ tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
++ if (!tcp_ctask->pad_count)
++ return;
+
+- dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
+- iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr,
+- tcp_ctask->r2t_data_count);
+- iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
+- sizeof(struct iscsi_hdr));
++ tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
++ debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
++ tcp_ctask->xmstate |= XMSTATE_W_PAD;
+ }
+
+ /**
+@@ -1302,38 +1293,20 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task
+ if (sc->use_sg) {
+ struct scatterlist *sg = sc->request_buffer;
+
+- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
+- &sg[tcp_ctask->sg_count++]);
+- tcp_ctask->sg = sg;
++ iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
++ tcp_ctask->sg = sg + 1;
+ tcp_ctask->bad_sg = sg + sc->use_sg;
+- } else
++ } else {
+ iscsi_buf_init_iov(&tcp_ctask->sendbuf,
+ sc->request_buffer,
+ sc->request_bufflen);
+-
+- if (ctask->imm_count)
+- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
+-
+- tcp_ctask->pad_count = ctask->total_length & (ISCSI_PAD_LEN-1);
+- if (tcp_ctask->pad_count) {
+- tcp_ctask->pad_count = ISCSI_PAD_LEN -
+- tcp_ctask->pad_count;
+- debug_scsi("write padding %d bytes\n",
+- tcp_ctask->pad_count);
+- tcp_ctask->xmstate |= XMSTATE_W_PAD;
++ tcp_ctask->sg = NULL;
++ tcp_ctask->bad_sg = NULL;
+ }
+-
+- if (ctask->unsol_count)
+- tcp_ctask->xmstate |= XMSTATE_UNS_HDR |
+- XMSTATE_UNS_INIT;
+- tcp_ctask->r2t_data_count = ctask->total_length -
+- ctask->imm_count -
+- ctask->unsol_count;
+-
+- debug_scsi("cmd [itt 0x%x total %d imm %d imm_data %d "
+- "r2t_data %d]\n",
++ debug_scsi("cmd [itt 0x%x total %d imm_data %d "
++ "unsol count %d, unsol offset %d]\n",
+ ctask->itt, ctask->total_length, ctask->imm_count,
+- ctask->unsol_count, tcp_ctask->r2t_data_count);
++ ctask->unsol_count, ctask->unsol_offset);
+ } else
+ tcp_ctask->xmstate = XMSTATE_R_HDR;
+
+@@ -1415,8 +1388,8 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *
+ }
+
+ static inline int
+-handle_xmstate_r_hdr(struct iscsi_conn *conn,
+- struct iscsi_tcp_cmd_task *tcp_ctask)
++iscsi_send_read_hdr(struct iscsi_conn *conn,
++ struct iscsi_tcp_cmd_task *tcp_ctask)
+ {
+ int rc;
+
+@@ -1434,7 +1407,7 @@ handle_xmstate_r_hdr(struct iscsi_conn *
+ }
+
+ static inline int
+-handle_xmstate_w_hdr(struct iscsi_conn *conn,
++iscsi_send_write_hdr(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask)
+ {
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+@@ -1445,85 +1418,126 @@ handle_xmstate_w_hdr(struct iscsi_conn *
+ iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
+ (u8*)tcp_ctask->hdrext);
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
+- if (rc)
++ if (rc) {
+ tcp_ctask->xmstate |= XMSTATE_W_HDR;
+- return rc;
++ return rc;
++ }
++
++ if (ctask->imm_count) {
++ tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
++ iscsi_set_padding(tcp_ctask, ctask->imm_count);
++
++ if (ctask->conn->datadgst_en) {
++ iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
++ tcp_ctask->immdigest = 0;
++ }
++ }
++
++ if (ctask->unsol_count)
++ tcp_ctask->xmstate |= XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
++ return 0;
+ }
+
+-static inline int
+-handle_xmstate_data_digest(struct iscsi_conn *conn,
+- struct iscsi_cmd_task *ctask)
++static int
++iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- int rc;
++ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
++ int sent = 0, rc;
+
+- tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST;
+- debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest);
+- rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
+- &tcp_ctask->datadigest, 0);
++ if (tcp_ctask->xmstate & XMSTATE_W_PAD) {
++ iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
++ tcp_ctask->pad_count);
++ if (conn->datadgst_en)
++ crypto_hash_update(&tcp_conn->tx_hash,
++ &tcp_ctask->sendbuf.sg,
++ tcp_ctask->sendbuf.sg.length);
++ } else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD))
++ return 0;
++
++ tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
++ tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_PAD;
++ debug_scsi("sending %d pad bytes for itt 0x%x\n",
++ tcp_ctask->pad_count, ctask->itt);
++ rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
++ &sent);
+ if (rc) {
+- tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
+- debug_tcp("resent data digest 0x%x fail!\n",
+- tcp_ctask->datadigest);
++ debug_scsi("padding send failed %d\n", rc);
++ tcp_ctask->xmstate |= XMSTATE_W_RESEND_PAD;
+ }
+-
+ return rc;
+ }
+
+-static inline int
+-handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
++static int
++iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
++ struct iscsi_buf *buf, uint32_t *digest)
+ {
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+- int rc;
++ struct iscsi_tcp_cmd_task *tcp_ctask;
++ struct iscsi_tcp_conn *tcp_conn;
++ int rc, sent = 0;
+
+- BUG_ON(!ctask->imm_count);
+- tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
++ if (!conn->datadgst_en)
++ return 0;
+
+- if (conn->datadgst_en) {
+- iscsi_data_digest_init(tcp_conn, ctask);
+- tcp_ctask->immdigest = 0;
+- }
++ tcp_ctask = ctask->dd_data;
++ tcp_conn = conn->dd_data;
+
+- for (;;) {
+- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
+- &ctask->imm_count, &tcp_ctask->sent);
+- if (rc) {
+- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
+- if (conn->datadgst_en) {
+- crypto_digest_final(tcp_conn->data_tx_tfm,
+- (u8*)&tcp_ctask->immdigest);
+- debug_tcp("tx imm sendpage fail 0x%x\n",
+- tcp_ctask->datadigest);
+- }
+- return rc;
+- }
+- if (conn->datadgst_en)
+- crypto_digest_update(tcp_conn->data_tx_tfm,
+- &tcp_ctask->sendbuf.sg, 1);
++ if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) {
++ crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
++ iscsi_buf_init_iov(buf, (char*)digest, 4);
++ }
++ tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST;
+
+- if (!ctask->imm_count)
+- break;
+- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
+- &tcp_ctask->sg[tcp_ctask->sg_count++]);
++ rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
++ if (!rc)
++ debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
++ ctask->itt);
++ else {
++ debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
++ *digest, ctask->itt);
++ tcp_ctask->xmstate |= XMSTATE_W_RESEND_DATA_DIGEST;
+ }
++ return rc;
++}
+
+- if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
+- rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
+- &tcp_ctask->immdigest, 1);
+- if (rc) {
+- debug_tcp("sending imm digest 0x%x fail!\n",
+- tcp_ctask->immdigest);
+- return rc;
++static int
++iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
++ struct scatterlist **sg, int *sent, int *count,
++ struct iscsi_buf *digestbuf, uint32_t *digest)
++{
++ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
++ struct iscsi_conn *conn = ctask->conn;
++ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
++ int rc, buf_sent, offset;
++
++ while (*count) {
++ buf_sent = 0;
++ offset = sendbuf->sent;
++
++ rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
++ *sent = *sent + buf_sent;
++ if (buf_sent && conn->datadgst_en)
++ partial_sg_digest_update(&tcp_conn->tx_hash,
++ &sendbuf->sg, sendbuf->sg.offset + offset,
++ buf_sent);
++ if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
++ iscsi_buf_init_sg(sendbuf, *sg);
++ *sg = *sg + 1;
+ }
+- debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest);
++
++ if (rc)
++ return rc;
+ }
+
+- return 0;
++ rc = iscsi_send_padding(conn, ctask);
++ if (rc)
++ return rc;
++
++ return iscsi_send_digest(conn, ctask, digestbuf, digest);
+ }
+
+-static inline int
+-handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
++static int
++iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ struct iscsi_data_task *dtask;
+@@ -1531,12 +1545,17 @@ handle_xmstate_uns_hdr(struct iscsi_conn
+
+ tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
+ if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
+- iscsi_unsolicit_data_init(conn, ctask);
+- dtask = tcp_ctask->dtask;
++ dtask = &tcp_ctask->unsol_dtask;
++
++ iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
++ iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
++ sizeof(struct iscsi_hdr));
+ if (conn->hdrdgst_en)
+ iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
+ (u8*)dtask->hdrext);
++
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT;
++ iscsi_set_padding(tcp_ctask, ctask->data_count);
+ }
+
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
+@@ -1546,254 +1565,138 @@ handle_xmstate_uns_hdr(struct iscsi_conn
+ return rc;
+ }
+
++ if (conn->datadgst_en) {
++ dtask = &tcp_ctask->unsol_dtask;
++ iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
++ dtask->digest = 0;
++ }
++
+ debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
+ ctask->itt, ctask->unsol_count, tcp_ctask->sent);
+ return 0;
+ }
+
+-static inline int
+-handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
++static int
++iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- struct iscsi_data_task *dtask = tcp_ctask->dtask;
+- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int rc;
+
+- BUG_ON(!ctask->data_count);
+- tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
+-
+- if (conn->datadgst_en) {
+- iscsi_data_digest_init(tcp_conn, ctask);
+- dtask->digest = 0;
++ if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
++ BUG_ON(!ctask->unsol_count);
++ tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
++send_hdr:
++ rc = iscsi_send_unsol_hdr(conn, ctask);
++ if (rc)
++ return rc;
+ }
+
+- for (;;) {
++ if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
++ struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
+ int start = tcp_ctask->sent;
+
+- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
+- &ctask->data_count, &tcp_ctask->sent);
+- if (rc) {
+- ctask->unsol_count -= tcp_ctask->sent - start;
+- tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
+- /* will continue with this ctask later.. */
+- if (conn->datadgst_en) {
+- crypto_digest_final(tcp_conn->data_tx_tfm,
+- (u8 *)&dtask->digest);
+- debug_tcp("tx uns data fail 0x%x\n",
+- dtask->digest);
+- }
+- return rc;
+- }
+-
+- BUG_ON(tcp_ctask->sent > ctask->total_length);
++ rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
++ &tcp_ctask->sent, &ctask->data_count,
++ &dtask->digestbuf, &dtask->digest);
+ ctask->unsol_count -= tcp_ctask->sent - start;
+-
++ if (rc)
++ return rc;
++ tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
+ /*
+- * XXX:we may run here with un-initial sendbuf.
+- * so pass it
++ * Done with the Data-Out. Next, check if we need
++ * to send another unsolicited Data-Out.
+ */
+- if (conn->datadgst_en && tcp_ctask->sent - start > 0)
+- crypto_digest_update(tcp_conn->data_tx_tfm,
+- &tcp_ctask->sendbuf.sg, 1);
+-
+- if (!ctask->data_count)
+- break;
+- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
+- &tcp_ctask->sg[tcp_ctask->sg_count++]);
+- }
+- BUG_ON(ctask->unsol_count < 0);
+-
+- /*
+- * Done with the Data-Out. Next, check if we need
+- * to send another unsolicited Data-Out.
+- */
+- if (ctask->unsol_count) {
+- if (conn->datadgst_en) {
+- rc = iscsi_digest_final_send(conn, ctask,
+- &dtask->digestbuf,
+- &dtask->digest, 1);
+- if (rc) {
+- debug_tcp("send uns digest 0x%x fail\n",
+- dtask->digest);
+- return rc;
+- }
+- debug_tcp("sending uns digest 0x%x, more uns\n",
+- dtask->digest);
++ if (ctask->unsol_count) {
++ debug_scsi("sending more uns\n");
++ tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
++ goto send_hdr;
+ }
+- tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
+- return 1;
+ }
+-
+- if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
+- rc = iscsi_digest_final_send(conn, ctask,
+- &dtask->digestbuf,
+- &dtask->digest, 1);
+- if (rc) {
+- debug_tcp("send last uns digest 0x%x fail\n",
+- dtask->digest);
+- return rc;
+- }
+- debug_tcp("sending uns digest 0x%x\n",dtask->digest);
+- }
+-
+ return 0;
+ }
+
+-static inline int
+-handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
++static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
++ struct iscsi_cmd_task *ctask)
+ {
+- struct iscsi_session *session = conn->session;
+- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- struct iscsi_r2t_info *r2t = tcp_ctask->r2t;
+- struct iscsi_data_task *dtask = &r2t->dtask;
++ struct iscsi_session *session = conn->session;
++ struct iscsi_r2t_info *r2t;
++ struct iscsi_data_task *dtask;
+ int left, rc;
+
+- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
+- tcp_ctask->dtask = dtask;
+-
+- if (conn->datadgst_en) {
+- iscsi_data_digest_init(tcp_conn, ctask);
+- dtask->digest = 0;
+- }
+-solicit_again:
+- /*
+- * send Data-Out within this R2T sequence.
+- */
+- if (!r2t->data_count)
+- goto data_out_done;
+-
+- rc = iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent);
+- if (rc) {
++ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
++ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+- /* will continue with this ctask later.. */
+- if (conn->datadgst_en) {
+- crypto_digest_final(tcp_conn->data_tx_tfm,
+- (u8 *)&dtask->digest);
+- debug_tcp("r2t data send fail 0x%x\n", dtask->digest);
+- }
+- return rc;
+- }
++ if (!tcp_ctask->r2t)
++ __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
++ sizeof(void*));
++send_hdr:
++ r2t = tcp_ctask->r2t;
++ dtask = &r2t->dtask;
+
+- BUG_ON(r2t->data_count < 0);
+- if (conn->datadgst_en)
+- crypto_digest_update(tcp_conn->data_tx_tfm, &r2t->sendbuf.sg,
+- 1);
+-
+- if (r2t->data_count) {
+- BUG_ON(ctask->sc->use_sg == 0);
+- if (!iscsi_buf_left(&r2t->sendbuf)) {
+- BUG_ON(tcp_ctask->bad_sg == r2t->sg);
+- iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
+- r2t->sg += 1;
++ if (conn->hdrdgst_en)
++ iscsi_hdr_digest(conn, &r2t->headbuf,
++ (u8*)dtask->hdrext);
++ rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
++ if (rc) {
++ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
++ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
++ return rc;
+ }
+- goto solicit_again;
+- }
+
+-data_out_done:
+- /*
+- * Done with this Data-Out. Next, check if we have
+- * to send another Data-Out for this R2T.
+- */
+- BUG_ON(r2t->data_length - r2t->sent < 0);
+- left = r2t->data_length - r2t->sent;
+- if (left) {
+ if (conn->datadgst_en) {
+- rc = iscsi_digest_final_send(conn, ctask,
+- &dtask->digestbuf,
+- &dtask->digest, 1);
+- if (rc) {
+- debug_tcp("send r2t data digest 0x%x"
+- "fail\n", dtask->digest);
+- return rc;
+- }
+- debug_tcp("r2t data send digest 0x%x\n",
+- dtask->digest);
++ iscsi_data_digest_init(conn->dd_data, tcp_ctask);
++ dtask->digest = 0;
+ }
+- iscsi_solicit_data_cont(conn, ctask, r2t, left);
+- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+- return 1;
+- }
+
+- /*
+- * Done with this R2T. Check if there are more
+- * outstanding R2Ts ready to be processed.
+- */
+- BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0);
+- if (conn->datadgst_en) {
+- rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
+- &dtask->digest, 1);
+- if (rc) {
+- debug_tcp("send last r2t data digest 0x%x"
+- "fail\n", dtask->digest);
+- return rc;
+- }
+- debug_tcp("r2t done dout digest 0x%x\n", dtask->digest);
+- }
+-
+- tcp_ctask->r2t_data_count -= r2t->data_length;
+- tcp_ctask->r2t = NULL;
+- spin_lock_bh(&session->lock);
+- __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
+- spin_unlock_bh(&session->lock);
+- if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
+- tcp_ctask->r2t = r2t;
+- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+- return 1;
++ iscsi_set_padding(tcp_ctask, r2t->data_count);
++ debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
++ r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
++ r2t->sent);
+ }
+
+- return 0;
+-}
++ if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
++ r2t = tcp_ctask->r2t;
++ dtask = &r2t->dtask;
+
+-static inline int
+-handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+-{
+- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+- struct iscsi_data_task *dtask = tcp_ctask->dtask;
+- int sent = 0, rc;
++ rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
++ &r2t->sent, &r2t->data_count,
++ &dtask->digestbuf, &dtask->digest);
++ if (rc)
++ return rc;
++ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
+
+- tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
+- iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
+- tcp_ctask->pad_count);
+- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
+- &sent);
+- if (rc) {
+- tcp_ctask->xmstate |= XMSTATE_W_PAD;
+- return rc;
+- }
++ /*
++ * Done with this Data-Out. Next, check if we have
++ * to send another Data-Out for this R2T.
++ */
++ BUG_ON(r2t->data_length - r2t->sent < 0);
++ left = r2t->data_length - r2t->sent;
++ if (left) {
++ iscsi_solicit_data_cont(conn, ctask, r2t, left);
++ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
++ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
++ goto send_hdr;
++ }
+
+- if (conn->datadgst_en) {
+- crypto_digest_update(tcp_conn->data_tx_tfm,
+- &tcp_ctask->sendbuf.sg, 1);
+- /* imm data? */
+- if (!dtask) {
+- rc = iscsi_digest_final_send(conn, ctask,
+- &tcp_ctask->immbuf,
+- &tcp_ctask->immdigest, 1);
+- if (rc) {
+- debug_tcp("send padding digest 0x%x"
+- "fail!\n", tcp_ctask->immdigest);
+- return rc;
+- }
+- debug_tcp("done with padding, digest 0x%x\n",
+- tcp_ctask->datadigest);
+- } else {
+- rc = iscsi_digest_final_send(conn, ctask,
+- &dtask->digestbuf,
+- &dtask->digest, 1);
+- if (rc) {
+- debug_tcp("send padding digest 0x%x"
+- "fail\n", dtask->digest);
+- return rc;
+- }
+- debug_tcp("done with padding, digest 0x%x\n",
+- dtask->digest);
++ /*
++ * Done with this R2T. Check if there are more
++ * outstanding R2Ts ready to be processed.
++ */
++ spin_lock_bh(&session->lock);
++ tcp_ctask->r2t = NULL;
++ __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
++ sizeof(void*));
++ if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
++ sizeof(void*))) {
++ tcp_ctask->r2t = r2t;
++ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
++ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
++ spin_unlock_bh(&session->lock);
++ goto send_hdr;
+ }
++ spin_unlock_bh(&session->lock);
+ }
+-
+ return 0;
+ }
+
+@@ -1813,85 +1716,30 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *
+ return rc;
+
+ if (tcp_ctask->xmstate & XMSTATE_R_HDR)
+- return handle_xmstate_r_hdr(conn, tcp_ctask);
++ return iscsi_send_read_hdr(conn, tcp_ctask);
+
+ if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
+- rc = handle_xmstate_w_hdr(conn, ctask);
+- if (rc)
+- return rc;
+- }
+-
+- /* XXX: for data digest xmit recover */
+- if (tcp_ctask->xmstate & XMSTATE_DATA_DIGEST) {
+- rc = handle_xmstate_data_digest(conn, ctask);
++ rc = iscsi_send_write_hdr(conn, ctask);
+ if (rc)
+ return rc;
+ }
+
+ if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
+- rc = handle_xmstate_imm_data(conn, ctask);
++ rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
++ &tcp_ctask->sent, &ctask->imm_count,
++ &tcp_ctask->immbuf, &tcp_ctask->immdigest);
+ if (rc)
+ return rc;
++ tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
+ }
+
+- if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
+- BUG_ON(!ctask->unsol_count);
+- tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
+-unsolicit_head_again:
+- rc = handle_xmstate_uns_hdr(conn, ctask);
+- if (rc)
+- return rc;
+- }
+-
+- if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
+- rc = handle_xmstate_uns_data(conn, ctask);
+- if (rc == 1)
+- goto unsolicit_head_again;
+- else if (rc)
+- return rc;
+- goto done;
+- }
+-
+- if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
+- struct iscsi_r2t_info *r2t;
+-
+- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+- if (!tcp_ctask->r2t)
+- __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
+- sizeof(void*));
+-solicit_head_again:
+- r2t = tcp_ctask->r2t;
+- if (conn->hdrdgst_en)
+- iscsi_hdr_digest(conn, &r2t->headbuf,
+- (u8*)r2t->dtask.hdrext);
+- rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
+- if (rc) {
+- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
+- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+- return rc;
+- }
+-
+- debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
+- r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
+- r2t->sent);
+- }
+-
+- if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
+- rc = handle_xmstate_sol_data(conn, ctask);
+- if (rc == 1)
+- goto solicit_head_again;
+- if (rc)
+- return rc;
+- }
++ rc = iscsi_send_unsol_pdu(conn, ctask);
++ if (rc)
++ return rc;
+
+-done:
+- /*
+- * Last thing to check is whether we need to send write
+- * padding. Note that we check for xmstate equality, not just the bit.
+- */
+- if (tcp_ctask->xmstate == XMSTATE_W_PAD)
+- rc = handle_xmstate_w_pad(conn, ctask);
++ rc = iscsi_send_sol_pdu(conn, ctask);
++ if (rc)
++ return rc;
+
+ return rc;
+ }
+@@ -1923,8 +1771,24 @@ iscsi_tcp_conn_create(struct iscsi_cls_s
+ /* initial operational parameters */
+ tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+
++ tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
++ CRYPTO_ALG_ASYNC);
++ tcp_conn->tx_hash.flags = 0;
++ if (!tcp_conn->tx_hash.tfm)
++ goto free_tcp_conn;
++
++ tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
++ CRYPTO_ALG_ASYNC);
++ tcp_conn->rx_hash.flags = 0;
++ if (!tcp_conn->rx_hash.tfm)
++ goto free_tx_tfm;
++
+ return cls_conn;
+
++free_tx_tfm:
++ crypto_free_hash(tcp_conn->tx_hash.tfm);
++free_tcp_conn:
++ kfree(tcp_conn);
+ tcp_conn_alloc_fail:
+ iscsi_conn_teardown(cls_conn);
+ return NULL;
+@@ -1962,14 +1826,10 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_
+
+ /* now free tcp_conn */
+ if (digest) {
+- if (tcp_conn->tx_tfm)
+- crypto_free_tfm(tcp_conn->tx_tfm);
+- if (tcp_conn->rx_tfm)
+- crypto_free_tfm(tcp_conn->rx_tfm);
+- if (tcp_conn->data_tx_tfm)
+- crypto_free_tfm(tcp_conn->data_tx_tfm);
+- if (tcp_conn->data_rx_tfm)
+- crypto_free_tfm(tcp_conn->data_rx_tfm);
++ if (tcp_conn->tx_hash.tfm)
++ crypto_free_hash(tcp_conn->tx_hash.tfm);
++ if (tcp_conn->rx_hash.tfm)
++ crypto_free_hash(tcp_conn->rx_hash.tfm);
+ }
+
+ kfree(tcp_conn);
+@@ -1979,9 +1839,11 @@ static void
+ iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+ {
+ struct iscsi_conn *conn = cls_conn->dd_data;
++ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+ iscsi_conn_stop(cls_conn, flag);
+ iscsi_tcp_release_conn(conn);
++ tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+ }
+
+ static int
+@@ -2127,48 +1989,11 @@ iscsi_conn_set_param(struct iscsi_cls_co
+ case ISCSI_PARAM_HDRDGST_EN:
+ iscsi_set_param(cls_conn, param, buf, buflen);
+ tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+- if (conn->hdrdgst_en) {
++ if (conn->hdrdgst_en)
+ tcp_conn->hdr_size += sizeof(__u32);
+- if (!tcp_conn->tx_tfm)
+- tcp_conn->tx_tfm = crypto_alloc_tfm("crc32c",
+- 0);
+- if (!tcp_conn->tx_tfm)
+- return -ENOMEM;
+- if (!tcp_conn->rx_tfm)
+- tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c",
+- 0);
+- if (!tcp_conn->rx_tfm) {
+- crypto_free_tfm(tcp_conn->tx_tfm);
+- return -ENOMEM;
+- }
+- } else {
+- if (tcp_conn->tx_tfm)
+- crypto_free_tfm(tcp_conn->tx_tfm);
+- if (tcp_conn->rx_tfm)
+- crypto_free_tfm(tcp_conn->rx_tfm);
+- }
+ break;
+ case ISCSI_PARAM_DATADGST_EN:
+ iscsi_set_param(cls_conn, param, buf, buflen);
+- if (conn->datadgst_en) {
+- if (!tcp_conn->data_tx_tfm)
+- tcp_conn->data_tx_tfm =
+- crypto_alloc_tfm("crc32c", 0);
+- if (!tcp_conn->data_tx_tfm)
+- return -ENOMEM;
+- if (!tcp_conn->data_rx_tfm)
+- tcp_conn->data_rx_tfm =
+- crypto_alloc_tfm("crc32c", 0);
+- if (!tcp_conn->data_rx_tfm) {
+- crypto_free_tfm(tcp_conn->data_tx_tfm);
+- return -ENOMEM;
+- }
+- } else {
+- if (tcp_conn->data_tx_tfm)
+- crypto_free_tfm(tcp_conn->data_tx_tfm);
+- if (tcp_conn->data_rx_tfm)
+- crypto_free_tfm(tcp_conn->data_rx_tfm);
+- }
+ tcp_conn->sendpage = conn->datadgst_en ?
+ sock_no_sendpage : tcp_conn->sock->ops->sendpage;
+ break;
+diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
+index 6a4ee70..3273683 100644
+--- a/drivers/scsi/iscsi_tcp.h
++++ b/drivers/scsi/iscsi_tcp.h
+@@ -31,26 +31,25 @@
+ #define IN_PROGRESS_DDIGEST_RECV 0x3
+
+ /* xmit state machine */
+-#define XMSTATE_IDLE 0x0
+-#define XMSTATE_R_HDR 0x1
+-#define XMSTATE_W_HDR 0x2
+-#define XMSTATE_IMM_HDR 0x4
+-#define XMSTATE_IMM_DATA 0x8
+-#define XMSTATE_UNS_INIT 0x10
+-#define XMSTATE_UNS_HDR 0x20
+-#define XMSTATE_UNS_DATA 0x40
+-#define XMSTATE_SOL_HDR 0x80
+-#define XMSTATE_SOL_DATA 0x100
+-#define XMSTATE_W_PAD 0x200
+-#define XMSTATE_DATA_DIGEST 0x400
+-
+-#define ISCSI_CONN_RCVBUF_MIN 262144
+-#define ISCSI_CONN_SNDBUF_MIN 262144
++#define XMSTATE_IDLE 0x0
++#define XMSTATE_R_HDR 0x1
++#define XMSTATE_W_HDR 0x2
++#define XMSTATE_IMM_HDR 0x4
++#define XMSTATE_IMM_DATA 0x8
++#define XMSTATE_UNS_INIT 0x10
++#define XMSTATE_UNS_HDR 0x20
++#define XMSTATE_UNS_DATA 0x40
++#define XMSTATE_SOL_HDR 0x80
++#define XMSTATE_SOL_DATA 0x100
++#define XMSTATE_W_PAD 0x200
++#define XMSTATE_W_RESEND_PAD 0x400
++#define XMSTATE_W_RESEND_DATA_DIGEST 0x800
++
+ #define ISCSI_PAD_LEN 4
+-#define ISCSI_R2T_MAX 16
+ #define ISCSI_SG_TABLESIZE SG_ALL
+ #define ISCSI_TCP_MAX_CMD_LEN 16
+
++struct crypto_hash;
+ struct socket;
+
+ /* Socket connection recieve helper */
+@@ -84,9 +83,6 @@ struct iscsi_tcp_conn {
+ /* iSCSI connection-wide sequencing */
+ int hdr_size; /* PDU header size */
+
+- struct crypto_tfm *rx_tfm; /* CRC32C (Rx) */
+- struct crypto_tfm *data_rx_tfm; /* CRC32C (Rx) for data */
+-
+ /* control data */
+ struct iscsi_tcp_recv in; /* TCP receive context */
+ int in_progress; /* connection state machine */
+@@ -96,9 +92,9 @@ struct iscsi_tcp_conn {
+ void (*old_state_change)(struct sock *);
+ void (*old_write_space)(struct sock *);
+
+- /* xmit */
+- struct crypto_tfm *tx_tfm; /* CRC32C (Tx) */
+- struct crypto_tfm *data_tx_tfm; /* CRC32C (Tx) for data */
++ /* data and header digests */
++ struct hash_desc tx_hash; /* CRC32C (Tx) */
++ struct hash_desc rx_hash; /* CRC32C (Rx) */
+
+ /* MIB custom statistics */
+ uint32_t sendpage_failures_cnt;
+@@ -157,19 +153,15 @@ struct iscsi_tcp_cmd_task {
+ struct scatterlist *bad_sg; /* assert statement */
+ int sg_count; /* SG's to process */
+ uint32_t exp_r2tsn;
+- int r2t_data_count; /* R2T Data-Out bytes */
+ int data_offset;
+ struct iscsi_r2t_info *r2t; /* in progress R2T */
+ struct iscsi_queue r2tpool;
+ struct kfifo *r2tqueue;
+ struct iscsi_r2t_info **r2ts;
+- uint32_t datadigest; /* for recover digest */
+ int digest_count;
+ uint32_t immdigest; /* for imm data */
+ struct iscsi_buf immbuf; /* for imm data digest */
+- struct iscsi_data_task *dtask; /* data task in progress*/
+ struct iscsi_data_task unsol_dtask; /* unsol data task */
+- int digest_offset; /* for partial buff digest */
+ };
+
+ #endif /* ISCSI_H */
+diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
+deleted file mode 100644
+index 9ce221f..0000000
+--- a/drivers/scsi/libata-bmdma.c
++++ /dev/null
+@@ -1,1149 +0,0 @@
+-/*
+- * libata-bmdma.c - helper library for PCI IDE BMDMA
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003-2006 Red Hat, Inc. All rights reserved.
+- * Copyright 2003-2006 Jeff Garzik
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available from http://www.t13.org/ and
+- * http://www.sata-io.org/
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/pci.h>
+-#include <linux/libata.h>
+-
+-#include "libata.h"
+-
+-/**
+- * ata_tf_load_pio - send taskfile registers to host controller
+- * @ap: Port to which output is sent
+- * @tf: ATA taskfile register set
+- *
+- * Outputs ATA taskfile to standard ATA host controller.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+-
+- if (tf->ctl != ap->last_ctl) {
+- outb(tf->ctl, ioaddr->ctl_addr);
+- ap->last_ctl = tf->ctl;
+- ata_wait_idle(ap);
+- }
+-
+- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+- outb(tf->hob_feature, ioaddr->feature_addr);
+- outb(tf->hob_nsect, ioaddr->nsect_addr);
+- outb(tf->hob_lbal, ioaddr->lbal_addr);
+- outb(tf->hob_lbam, ioaddr->lbam_addr);
+- outb(tf->hob_lbah, ioaddr->lbah_addr);
+- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+- tf->hob_feature,
+- tf->hob_nsect,
+- tf->hob_lbal,
+- tf->hob_lbam,
+- tf->hob_lbah);
+- }
+-
+- if (is_addr) {
+- outb(tf->feature, ioaddr->feature_addr);
+- outb(tf->nsect, ioaddr->nsect_addr);
+- outb(tf->lbal, ioaddr->lbal_addr);
+- outb(tf->lbam, ioaddr->lbam_addr);
+- outb(tf->lbah, ioaddr->lbah_addr);
+- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+- tf->feature,
+- tf->nsect,
+- tf->lbal,
+- tf->lbam,
+- tf->lbah);
+- }
+-
+- if (tf->flags & ATA_TFLAG_DEVICE) {
+- outb(tf->device, ioaddr->device_addr);
+- VPRINTK("device 0x%X\n", tf->device);
+- }
+-
+- ata_wait_idle(ap);
+-}
+-
+-/**
+- * ata_tf_load_mmio - send taskfile registers to host controller
+- * @ap: Port to which output is sent
+- * @tf: ATA taskfile register set
+- *
+- * Outputs ATA taskfile to standard ATA host controller using MMIO.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+-
+- if (tf->ctl != ap->last_ctl) {
+- writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+- ap->last_ctl = tf->ctl;
+- ata_wait_idle(ap);
+- }
+-
+- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+- writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+- writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+- writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+- writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+- writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+- tf->hob_feature,
+- tf->hob_nsect,
+- tf->hob_lbal,
+- tf->hob_lbam,
+- tf->hob_lbah);
+- }
+-
+- if (is_addr) {
+- writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+- writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+- writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+- writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+- writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+- tf->feature,
+- tf->nsect,
+- tf->lbal,
+- tf->lbam,
+- tf->lbah);
+- }
+-
+- if (tf->flags & ATA_TFLAG_DEVICE) {
+- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+- VPRINTK("device 0x%X\n", tf->device);
+- }
+-
+- ata_wait_idle(ap);
+-}
+-
+-
+-/**
+- * ata_tf_load - send taskfile registers to host controller
+- * @ap: Port to which output is sent
+- * @tf: ATA taskfile register set
+- *
+- * Outputs ATA taskfile to standard ATA host controller using MMIO
+- * or PIO as indicated by the ATA_FLAG_MMIO flag.
+- * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+- * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+- * hob_lbal, hob_lbam, and hob_lbah.
+- *
+- * This function waits for idle (!BUSY and !DRQ) after writing
+- * registers. If the control register has a new value, this
+- * function also waits for idle after writing control and before
+- * writing the remaining registers.
+- *
+- * May be used as the tf_load() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- if (ap->flags & ATA_FLAG_MMIO)
+- ata_tf_load_mmio(ap, tf);
+- else
+- ata_tf_load_pio(ap, tf);
+-}
+-
+-/**
+- * ata_exec_command_pio - issue ATA command to host controller
+- * @ap: port to which command is being issued
+- * @tf: ATA taskfile register set
+- *
+- * Issues PIO write to ATA command register, with proper
+- * synchronization with interrupt handler / other threads.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+-
+- outb(tf->command, ap->ioaddr.command_addr);
+- ata_pause(ap);
+-}
+-
+-
+-/**
+- * ata_exec_command_mmio - issue ATA command to host controller
+- * @ap: port to which command is being issued
+- * @tf: ATA taskfile register set
+- *
+- * Issues MMIO write to ATA command register, with proper
+- * synchronization with interrupt handler / other threads.
+- *
+- * FIXME: missing write posting for 400nS delay enforcement
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+-
+- writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+- ata_pause(ap);
+-}
+-
+-
+-/**
+- * ata_exec_command - issue ATA command to host controller
+- * @ap: port to which command is being issued
+- * @tf: ATA taskfile register set
+- *
+- * Issues PIO/MMIO write to ATA command register, with proper
+- * synchronization with interrupt handler / other threads.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- if (ap->flags & ATA_FLAG_MMIO)
+- ata_exec_command_mmio(ap, tf);
+- else
+- ata_exec_command_pio(ap, tf);
+-}
+-
+-/**
+- * ata_tf_read_pio - input device's ATA taskfile shadow registers
+- * @ap: Port from which input is read
+- * @tf: ATA taskfile register set for storing input
+- *
+- * Reads ATA taskfile registers for currently-selected device
+- * into @tf.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+-
+- tf->command = ata_check_status(ap);
+- tf->feature = inb(ioaddr->error_addr);
+- tf->nsect = inb(ioaddr->nsect_addr);
+- tf->lbal = inb(ioaddr->lbal_addr);
+- tf->lbam = inb(ioaddr->lbam_addr);
+- tf->lbah = inb(ioaddr->lbah_addr);
+- tf->device = inb(ioaddr->device_addr);
+-
+- if (tf->flags & ATA_TFLAG_LBA48) {
+- outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+- tf->hob_feature = inb(ioaddr->error_addr);
+- tf->hob_nsect = inb(ioaddr->nsect_addr);
+- tf->hob_lbal = inb(ioaddr->lbal_addr);
+- tf->hob_lbam = inb(ioaddr->lbam_addr);
+- tf->hob_lbah = inb(ioaddr->lbah_addr);
+- }
+-}
+-
+-/**
+- * ata_tf_read_mmio - input device's ATA taskfile shadow registers
+- * @ap: Port from which input is read
+- * @tf: ATA taskfile register set for storing input
+- *
+- * Reads ATA taskfile registers for currently-selected device
+- * into @tf via MMIO.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+-
+- tf->command = ata_check_status(ap);
+- tf->feature = readb((void __iomem *)ioaddr->error_addr);
+- tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+- tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+- tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+- tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+- tf->device = readb((void __iomem *)ioaddr->device_addr);
+-
+- if (tf->flags & ATA_TFLAG_LBA48) {
+- writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+- tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+- tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+- tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+- tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+- tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+- }
+-}
+-
+-
+-/**
+- * ata_tf_read - input device's ATA taskfile shadow registers
+- * @ap: Port from which input is read
+- * @tf: ATA taskfile register set for storing input
+- *
+- * Reads ATA taskfile registers for currently-selected device
+- * into @tf.
+- *
+- * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
+- * is set, also reads the hob registers.
+- *
+- * May be used as the tf_read() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- if (ap->flags & ATA_FLAG_MMIO)
+- ata_tf_read_mmio(ap, tf);
+- else
+- ata_tf_read_pio(ap, tf);
+-}
+-
+-/**
+- * ata_check_status_pio - Read device status reg & clear interrupt
+- * @ap: port where the device is
+- *
+- * Reads ATA taskfile status register for currently-selected device
+- * and return its value. This also clears pending interrupts
+- * from this device
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static u8 ata_check_status_pio(struct ata_port *ap)
+-{
+- return inb(ap->ioaddr.status_addr);
+-}
+-
+-/**
+- * ata_check_status_mmio - Read device status reg & clear interrupt
+- * @ap: port where the device is
+- *
+- * Reads ATA taskfile status register for currently-selected device
+- * via MMIO and return its value. This also clears pending interrupts
+- * from this device
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static u8 ata_check_status_mmio(struct ata_port *ap)
+-{
+- return readb((void __iomem *) ap->ioaddr.status_addr);
+-}
+-
+-
+-/**
+- * ata_check_status - Read device status reg & clear interrupt
+- * @ap: port where the device is
+- *
+- * Reads ATA taskfile status register for currently-selected device
+- * and return its value. This also clears pending interrupts
+- * from this device
+- *
+- * May be used as the check_status() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-u8 ata_check_status(struct ata_port *ap)
+-{
+- if (ap->flags & ATA_FLAG_MMIO)
+- return ata_check_status_mmio(ap);
+- return ata_check_status_pio(ap);
+-}
+-
+-
+-/**
+- * ata_altstatus - Read device alternate status reg
+- * @ap: port where the device is
+- *
+- * Reads ATA taskfile alternate status register for
+- * currently-selected device and return its value.
+- *
+- * Note: may NOT be used as the check_altstatus() entry in
+- * ata_port_operations.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-u8 ata_altstatus(struct ata_port *ap)
+-{
+- if (ap->ops->check_altstatus)
+- return ap->ops->check_altstatus(ap);
+-
+- if (ap->flags & ATA_FLAG_MMIO)
+- return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+- return inb(ap->ioaddr.altstatus_addr);
+-}
+-
+-/**
+- * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
+- * @qc: Info associated with this ATA transaction.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+- u8 dmactl;
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+-
+- /* load PRD table addr. */
+- mb(); /* make sure PRD table writes are visible to controller */
+- writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+-
+- /* specify data direction, triple-check start bit is clear */
+- dmactl = readb(mmio + ATA_DMA_CMD);
+- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+- if (!rw)
+- dmactl |= ATA_DMA_WR;
+- writeb(dmactl, mmio + ATA_DMA_CMD);
+-
+- /* issue r/w command */
+- ap->ops->exec_command(ap, &qc->tf);
+-}
+-
+-/**
+- * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
+- * @qc: Info associated with this ATA transaction.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+- u8 dmactl;
+-
+- /* start host DMA transaction */
+- dmactl = readb(mmio + ATA_DMA_CMD);
+- writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+-
+- /* Strictly, one may wish to issue a readb() here, to
+- * flush the mmio write. However, control also passes
+- * to the hardware at this point, and it will interrupt
+- * us when we are to resume control. So, in effect,
+- * we don't care when the mmio write flushes.
+- * Further, a read of the DMA status register _immediately_
+- * following the write may not be what certain flaky hardware
+- * is expected, so I think it is best to not add a readb()
+- * without first all the MMIO ATA cards/mobos.
+- * Or maybe I'm just being paranoid.
+- */
+-}
+-
+-/**
+- * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
+- * @qc: Info associated with this ATA transaction.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+- u8 dmactl;
+-
+- /* load PRD table addr. */
+- outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+-
+- /* specify data direction, triple-check start bit is clear */
+- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+- if (!rw)
+- dmactl |= ATA_DMA_WR;
+- outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+-
+- /* issue r/w command */
+- ap->ops->exec_command(ap, &qc->tf);
+-}
+-
+-/**
+- * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
+- * @qc: Info associated with this ATA transaction.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- u8 dmactl;
+-
+- /* start host DMA transaction */
+- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+- outb(dmactl | ATA_DMA_START,
+- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+-}
+-
+-
+-/**
+- * ata_bmdma_start - Start a PCI IDE BMDMA transaction
+- * @qc: Info associated with this ATA transaction.
+- *
+- * Writes the ATA_DMA_START flag to the DMA command register.
+- *
+- * May be used as the bmdma_start() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_bmdma_start(struct ata_queued_cmd *qc)
+-{
+- if (qc->ap->flags & ATA_FLAG_MMIO)
+- ata_bmdma_start_mmio(qc);
+- else
+- ata_bmdma_start_pio(qc);
+-}
+-
+-
+-/**
+- * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+- * @qc: Info associated with this ATA transaction.
+- *
+- * Writes address of PRD table to device's PRD Table Address
+- * register, sets the DMA control register, and calls
+- * ops->exec_command() to start the transfer.
+- *
+- * May be used as the bmdma_setup() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_bmdma_setup(struct ata_queued_cmd *qc)
+-{
+- if (qc->ap->flags & ATA_FLAG_MMIO)
+- ata_bmdma_setup_mmio(qc);
+- else
+- ata_bmdma_setup_pio(qc);
+-}
+-
+-
+-/**
+- * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+- * @ap: Port associated with this ATA transaction.
+- *
+- * Clear interrupt and error flags in DMA status register.
+- *
+- * May be used as the irq_clear() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_bmdma_irq_clear(struct ata_port *ap)
+-{
+- if (!ap->ioaddr.bmdma_addr)
+- return;
+-
+- if (ap->flags & ATA_FLAG_MMIO) {
+- void __iomem *mmio =
+- ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
+- writeb(readb(mmio), mmio);
+- } else {
+- unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+- outb(inb(addr), addr);
+- }
+-}
+-
+-
+-/**
+- * ata_bmdma_status - Read PCI IDE BMDMA status
+- * @ap: Port associated with this ATA transaction.
+- *
+- * Read and return BMDMA status register.
+- *
+- * May be used as the bmdma_status() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-u8 ata_bmdma_status(struct ata_port *ap)
+-{
+- u8 host_stat;
+- if (ap->flags & ATA_FLAG_MMIO) {
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+- host_stat = readb(mmio + ATA_DMA_STATUS);
+- } else
+- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+- return host_stat;
+-}
+-
+-
+-/**
+- * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
+- * @qc: Command we are ending DMA for
+- *
+- * Clears the ATA_DMA_START flag in the dma control register
+- *
+- * May be used as the bmdma_stop() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_bmdma_stop(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- if (ap->flags & ATA_FLAG_MMIO) {
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+-
+- /* clear start/stop bit */
+- writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+- mmio + ATA_DMA_CMD);
+- } else {
+- /* clear start/stop bit */
+- outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+- }
+-
+- /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+- ata_altstatus(ap); /* dummy read */
+-}
+-
+-/**
+- * ata_bmdma_freeze - Freeze BMDMA controller port
+- * @ap: port to freeze
+- *
+- * Freeze BMDMA controller port.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void ata_bmdma_freeze(struct ata_port *ap)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+-
+- ap->ctl |= ATA_NIEN;
+- ap->last_ctl = ap->ctl;
+-
+- if (ap->flags & ATA_FLAG_MMIO)
+- writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
+- else
+- outb(ap->ctl, ioaddr->ctl_addr);
+-}
+-
+-/**
+- * ata_bmdma_thaw - Thaw BMDMA controller port
+- * @ap: port to thaw
+- *
+- * Thaw BMDMA controller port.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void ata_bmdma_thaw(struct ata_port *ap)
+-{
+- /* clear & re-enable interrupts */
+- ata_chk_status(ap);
+- ap->ops->irq_clear(ap);
+- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+- ata_irq_on(ap);
+-}
+-
+-/**
+- * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
+- * @ap: port to handle error for
+- * @prereset: prereset method (can be NULL)
+- * @softreset: softreset method (can be NULL)
+- * @hardreset: hardreset method (can be NULL)
+- * @postreset: postreset method (can be NULL)
+- *
+- * Handle error for ATA BMDMA controller. It can handle both
+- * PATA and SATA controllers. Many controllers should be able to
+- * use this EH as-is or with some added handling before and
+- * after.
+- *
+- * This function is intended to be used for constructing
+- * ->error_handler callback by low level drivers.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- */
+-void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+- ata_postreset_fn_t postreset)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- struct ata_queued_cmd *qc;
+- unsigned long flags;
+- int thaw = 0;
+-
+- qc = __ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+- qc = NULL;
+-
+- /* reset PIO HSM and stop DMA engine */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- ap->hsm_task_state = HSM_ST_IDLE;
+-
+- if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
+- qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+- u8 host_stat;
+-
+- host_stat = ata_bmdma_status(ap);
+-
+- ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);
+-
+- /* BMDMA controllers indicate host bus error by
+- * setting DMA_ERR bit and timing out. As it wasn't
+- * really a timeout event, adjust error mask and
+- * cancel frozen state.
+- */
+- if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
+- qc->err_mask = AC_ERR_HOST_BUS;
+- thaw = 1;
+- }
+-
+- ap->ops->bmdma_stop(qc);
+- }
+-
+- ata_altstatus(ap);
+- ata_chk_status(ap);
+- ap->ops->irq_clear(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- if (thaw)
+- ata_eh_thaw_port(ap);
+-
+- /* PIO and DMA engines have been stopped, perform recovery */
+- ata_do_eh(ap, prereset, softreset, hardreset, postreset);
+-}
+-
+-/**
+- * ata_bmdma_error_handler - Stock error handler for BMDMA controller
+- * @ap: port to handle error for
+- *
+- * Stock error handler for BMDMA controller.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- */
+-void ata_bmdma_error_handler(struct ata_port *ap)
+-{
+- ata_reset_fn_t hardreset;
+-
+- hardreset = NULL;
+- if (sata_scr_valid(ap))
+- hardreset = sata_std_hardreset;
+-
+- ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
+- ata_std_postreset);
+-}
+-
+-/**
+- * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
+- * BMDMA controller
+- * @qc: internal command to clean up
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- */
+-void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
+-{
+- ata_bmdma_stop(qc);
+-}
+-
+-#ifdef CONFIG_PCI
+-static struct ata_probe_ent *
+-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+-{
+- struct ata_probe_ent *probe_ent;
+-
+- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (!probe_ent) {
+- printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+- kobject_name(&(dev->kobj)));
+- return NULL;
+- }
+-
+- INIT_LIST_HEAD(&probe_ent->node);
+- probe_ent->dev = dev;
+-
+- probe_ent->sht = port->sht;
+- probe_ent->host_flags = port->host_flags;
+- probe_ent->pio_mask = port->pio_mask;
+- probe_ent->mwdma_mask = port->mwdma_mask;
+- probe_ent->udma_mask = port->udma_mask;
+- probe_ent->port_ops = port->port_ops;
+-
+- return probe_ent;
+-}
+-
+-
+-/**
+- * ata_pci_init_native_mode - Initialize native-mode driver
+- * @pdev: pci device to be initialized
+- * @port: array[2] of pointers to port info structures.
+- * @ports: bitmap of ports present
+- *
+- * Utility function which allocates and initializes an
+- * ata_probe_ent structure for a standard dual-port
+- * PIO-based IDE controller. The returned ata_probe_ent
+- * structure can be passed to ata_device_add(). The returned
+- * ata_probe_ent structure should then be freed with kfree().
+- *
+- * The caller need only pass the address of the primary port, the
+- * secondary will be deduced automatically. If the device has non
+- * standard secondary port mappings this function can be called twice,
+- * once for each interface.
+- */
+-
+-struct ata_probe_ent *
+-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+-{
+- struct ata_probe_ent *probe_ent =
+- ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+- int p = 0;
+- unsigned long bmdma;
+-
+- if (!probe_ent)
+- return NULL;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->private_data = port[0]->private_data;
+-
+- if (ports & ATA_PORT_PRIMARY) {
+- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+- probe_ent->port[p].altstatus_addr =
+- probe_ent->port[p].ctl_addr =
+- pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+- bmdma = pci_resource_start(pdev, 4);
+- if (bmdma) {
+- if (inb(bmdma + 2) & 0x80)
+- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+- probe_ent->port[p].bmdma_addr = bmdma;
+- }
+- ata_std_ports(&probe_ent->port[p]);
+- p++;
+- }
+-
+- if (ports & ATA_PORT_SECONDARY) {
+- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+- probe_ent->port[p].altstatus_addr =
+- probe_ent->port[p].ctl_addr =
+- pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+- bmdma = pci_resource_start(pdev, 4);
+- if (bmdma) {
+- bmdma += 8;
+- if(inb(bmdma + 2) & 0x80)
+- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+- probe_ent->port[p].bmdma_addr = bmdma;
+- }
+- ata_std_ports(&probe_ent->port[p]);
+- p++;
+- }
+-
+- probe_ent->n_ports = p;
+- return probe_ent;
+-}
+-
+-
+-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
+- struct ata_port_info *port, int port_num)
+-{
+- struct ata_probe_ent *probe_ent;
+- unsigned long bmdma;
+-
+- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
+- if (!probe_ent)
+- return NULL;
+-
+- probe_ent->legacy_mode = 1;
+- probe_ent->n_ports = 1;
+- probe_ent->hard_port_no = port_num;
+- probe_ent->private_data = port->private_data;
+-
+- switch(port_num)
+- {
+- case 0:
+- probe_ent->irq = 14;
+- probe_ent->port[0].cmd_addr = 0x1f0;
+- probe_ent->port[0].altstatus_addr =
+- probe_ent->port[0].ctl_addr = 0x3f6;
+- break;
+- case 1:
+- probe_ent->irq = 15;
+- probe_ent->port[0].cmd_addr = 0x170;
+- probe_ent->port[0].altstatus_addr =
+- probe_ent->port[0].ctl_addr = 0x376;
+- break;
+- }
+-
+- bmdma = pci_resource_start(pdev, 4);
+- if (bmdma != 0) {
+- bmdma += 8 * port_num;
+- probe_ent->port[0].bmdma_addr = bmdma;
+- if (inb(bmdma + 2) & 0x80)
+- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+- }
+- ata_std_ports(&probe_ent->port[0]);
+-
+- return probe_ent;
+-}
+-
+-
+-/**
+- * ata_pci_init_one - Initialize/register PCI IDE host controller
+- * @pdev: Controller to be initialized
+- * @port_info: Information from low-level host driver
+- * @n_ports: Number of ports attached to host controller
+- *
+- * This is a helper function which can be called from a driver's
+- * xxx_init_one() probe function if the hardware uses traditional
+- * IDE taskfile registers.
+- *
+- * This function calls pci_enable_device(), reserves its register
+- * regions, sets the dma mask, enables bus master mode, and calls
+- * ata_device_add()
+- *
+- * LOCKING:
+- * Inherited from PCI layer (may sleep).
+- *
+- * RETURNS:
+- * Zero on success, negative on errno-based value on error.
+- */
+-
+-int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+- unsigned int n_ports)
+-{
+- struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
+- struct ata_port_info *port[2];
+- u8 tmp8, mask;
+- unsigned int legacy_mode = 0;
+- int disable_dev_on_err = 1;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+-
+- port[0] = port_info[0];
+- if (n_ports > 1)
+- port[1] = port_info[1];
+- else
+- port[1] = port[0];
+-
+- if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
+- && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+- /* TODO: What if one channel is in native mode ... */
+- pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+- mask = (1 << 2) | (1 << 0);
+- if ((tmp8 & mask) != mask)
+- legacy_mode = (1 << 3);
+- }
+-
+- /* FIXME... */
+- if ((!legacy_mode) && (n_ports > 2)) {
+- printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+- n_ports = 2;
+- /* For now */
+- }
+-
+- /* FIXME: Really for ATA it isn't safe because the device may be
+- multi-purpose and we want to leave it alone if it was already
+- enabled. Secondly for shared use as Arjan says we want refcounting
+-
+- Checking dev->is_enabled is insufficient as this is not set at
+- boot for the primary video which is BIOS enabled
+- */
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- disable_dev_on_err = 0;
+- goto err_out;
+- }
+-
+- /* FIXME: Should use platform specific mappers for legacy port ranges */
+- if (legacy_mode) {
+- if (!request_region(0x1f0, 8, "libata")) {
+- struct resource *conflict, res;
+- res.start = 0x1f0;
+- res.end = 0x1f0 + 8 - 1;
+- conflict = ____request_resource(&ioport_resource, &res);
+- if (!strcmp(conflict->name, "libata"))
+- legacy_mode |= (1 << 0);
+- else {
+- disable_dev_on_err = 0;
+- printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+- }
+- } else
+- legacy_mode |= (1 << 0);
+-
+- if (!request_region(0x170, 8, "libata")) {
+- struct resource *conflict, res;
+- res.start = 0x170;
+- res.end = 0x170 + 8 - 1;
+- conflict = ____request_resource(&ioport_resource, &res);
+- if (!strcmp(conflict->name, "libata"))
+- legacy_mode |= (1 << 1);
+- else {
+- disable_dev_on_err = 0;
+- printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+- }
+- } else
+- legacy_mode |= (1 << 1);
+- }
+-
+- /* we have legacy mode, but all ports are unavailable */
+- if (legacy_mode == (1 << 3)) {
+- rc = -EBUSY;
+- goto err_out_regions;
+- }
+-
+- /* FIXME: If we get no DMA mask we should fall back to PIO */
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- if (legacy_mode) {
+- if (legacy_mode & (1 << 0))
+- probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
+- if (legacy_mode & (1 << 1))
+- probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
+- } else {
+- if (n_ports == 2)
+- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+- else
+- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+- }
+- if (!probe_ent && !probe_ent2) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- pci_set_master(pdev);
+-
+- /* FIXME: check ata_device_add return */
+- if (legacy_mode) {
+- struct device *dev = &pdev->dev;
+- struct ata_host_set *host_set = NULL;
+-
+- if (legacy_mode & (1 << 0)) {
+- ata_device_add(probe_ent);
+- host_set = dev_get_drvdata(dev);
+- }
+-
+- if (legacy_mode & (1 << 1)) {
+- ata_device_add(probe_ent2);
+- if (host_set) {
+- host_set->next = dev_get_drvdata(dev);
+- dev_set_drvdata(dev, host_set);
+- }
+- }
+- } else
+- ata_device_add(probe_ent);
+-
+- kfree(probe_ent);
+- kfree(probe_ent2);
+-
+- return 0;
+-
+-err_out_regions:
+- if (legacy_mode & (1 << 0))
+- release_region(0x1f0, 8);
+- if (legacy_mode & (1 << 1))
+- release_region(0x170, 8);
+- pci_release_regions(pdev);
+-err_out:
+- if (disable_dev_on_err)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-/**
+- * ata_pci_clear_simplex - attempt to kick device out of simplex
+- * @pdev: PCI device
+- *
+- * Some PCI ATA devices report simplex mode but in fact can be told to
+- * enter non simplex mode. This implements the neccessary logic to
+- * perform the task on such devices. Calling it on other devices will
+- * have -undefined- behaviour.
+- */
+-
+-int ata_pci_clear_simplex(struct pci_dev *pdev)
+-{
+- unsigned long bmdma = pci_resource_start(pdev, 4);
+- u8 simplex;
+-
+- if (bmdma == 0)
+- return -ENOENT;
+-
+- simplex = inb(bmdma + 0x02);
+- outb(simplex & 0x60, bmdma + 0x02);
+- simplex = inb(bmdma + 0x02);
+- if (simplex & 0x80)
+- return -EOPNOTSUPP;
+- return 0;
+-}
+-
+-unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
+-{
+- /* Filter out DMA modes if the device has been configured by
+- the BIOS as PIO only */
+-
+- if (ap->ioaddr.bmdma_addr == 0)
+- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+- return xfer_mask;
+-}
+-
+-#endif /* CONFIG_PCI */
+-
+diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
+deleted file mode 100644
+index 427b73a..0000000
+--- a/drivers/scsi/libata-core.c
++++ /dev/null
+@@ -1,6020 +0,0 @@
+-/*
+- * libata-core.c - helper library for ATA
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+- * Copyright 2003-2004 Jeff Garzik
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available from http://www.t13.org/ and
+- * http://www.sata-io.org/
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/list.h>
+-#include <linux/mm.h>
+-#include <linux/highmem.h>
+-#include <linux/spinlock.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/timer.h>
+-#include <linux/interrupt.h>
+-#include <linux/completion.h>
+-#include <linux/suspend.h>
+-#include <linux/workqueue.h>
+-#include <linux/jiffies.h>
+-#include <linux/scatterlist.h>
+-#include <scsi/scsi.h>
+-#include "scsi_priv.h"
+-#include <scsi/scsi_cmnd.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-#include <asm/semaphore.h>
+-#include <asm/byteorder.h>
+-
+-#include "libata.h"
+-
+-/* debounce timing parameters in msecs { interval, duration, timeout } */
+-const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
+-const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
+-const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
+-
+-static unsigned int ata_dev_init_params(struct ata_device *dev,
+- u16 heads, u16 sectors);
+-static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+-static void ata_dev_xfermask(struct ata_device *dev);
+-
+-static unsigned int ata_unique_id = 1;
+-static struct workqueue_struct *ata_wq;
+-
+-struct workqueue_struct *ata_aux_wq;
+-
+-int atapi_enabled = 1;
+-module_param(atapi_enabled, int, 0444);
+-MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+-
+-int atapi_dmadir = 0;
+-module_param(atapi_dmadir, int, 0444);
+-MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+-
+-int libata_fua = 0;
+-module_param_named(fua, libata_fua, int, 0444);
+-MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+-
+-static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
+-module_param(ata_probe_timeout, int, 0444);
+-MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
+-
+-MODULE_AUTHOR("Jeff Garzik");
+-MODULE_DESCRIPTION("Library module for ATA devices");
+-MODULE_LICENSE("GPL");
+-MODULE_VERSION(DRV_VERSION);
+-
+-
+-/**
+- * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+- * @tf: Taskfile to convert
+- * @fis: Buffer into which data will output
+- * @pmp: Port multiplier port
+- *
+- * Converts a standard ATA taskfile to a Serial ATA
+- * FIS structure (Register - Host to Device).
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+-{
+- fis[0] = 0x27; /* Register - Host to Device FIS */
+- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
+- bit 7 indicates Command FIS */
+- fis[2] = tf->command;
+- fis[3] = tf->feature;
+-
+- fis[4] = tf->lbal;
+- fis[5] = tf->lbam;
+- fis[6] = tf->lbah;
+- fis[7] = tf->device;
+-
+- fis[8] = tf->hob_lbal;
+- fis[9] = tf->hob_lbam;
+- fis[10] = tf->hob_lbah;
+- fis[11] = tf->hob_feature;
+-
+- fis[12] = tf->nsect;
+- fis[13] = tf->hob_nsect;
+- fis[14] = 0;
+- fis[15] = tf->ctl;
+-
+- fis[16] = 0;
+- fis[17] = 0;
+- fis[18] = 0;
+- fis[19] = 0;
+-}
+-
+-/**
+- * ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+- * @fis: Buffer from which data will be input
+- * @tf: Taskfile to output
+- *
+- * Converts a serial ATA FIS structure to a standard ATA taskfile.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
+-{
+- tf->command = fis[2]; /* status */
+- tf->feature = fis[3]; /* error */
+-
+- tf->lbal = fis[4];
+- tf->lbam = fis[5];
+- tf->lbah = fis[6];
+- tf->device = fis[7];
+-
+- tf->hob_lbal = fis[8];
+- tf->hob_lbam = fis[9];
+- tf->hob_lbah = fis[10];
+-
+- tf->nsect = fis[12];
+- tf->hob_nsect = fis[13];
+-}
+-
+-static const u8 ata_rw_cmds[] = {
+- /* pio multi */
+- ATA_CMD_READ_MULTI,
+- ATA_CMD_WRITE_MULTI,
+- ATA_CMD_READ_MULTI_EXT,
+- ATA_CMD_WRITE_MULTI_EXT,
+- 0,
+- 0,
+- 0,
+- ATA_CMD_WRITE_MULTI_FUA_EXT,
+- /* pio */
+- ATA_CMD_PIO_READ,
+- ATA_CMD_PIO_WRITE,
+- ATA_CMD_PIO_READ_EXT,
+- ATA_CMD_PIO_WRITE_EXT,
+- 0,
+- 0,
+- 0,
+- 0,
+- /* dma */
+- ATA_CMD_READ,
+- ATA_CMD_WRITE,
+- ATA_CMD_READ_EXT,
+- ATA_CMD_WRITE_EXT,
+- 0,
+- 0,
+- 0,
+- ATA_CMD_WRITE_FUA_EXT
+-};
+-
+-/**
+- * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+- * @qc: command to examine and configure
+- *
+- * Examine the device configuration and tf->flags to calculate
+- * the proper read/write commands and protocol to use.
+- *
+- * LOCKING:
+- * caller.
+- */
+-int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
+-{
+- struct ata_taskfile *tf = &qc->tf;
+- struct ata_device *dev = qc->dev;
+- u8 cmd;
+-
+- int index, fua, lba48, write;
+-
+- fua = (tf->flags & ATA_TFLAG_FUA) ? 4 : 0;
+- lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+- write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+-
+- if (dev->flags & ATA_DFLAG_PIO) {
+- tf->protocol = ATA_PROT_PIO;
+- index = dev->multi_count ? 0 : 8;
+- } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) {
+- /* Unable to use DMA due to host limitation */
+- tf->protocol = ATA_PROT_PIO;
+- index = dev->multi_count ? 0 : 8;
+- } else {
+- tf->protocol = ATA_PROT_DMA;
+- index = 16;
+- }
+-
+- cmd = ata_rw_cmds[index + fua + lba48 + write];
+- if (cmd) {
+- tf->command = cmd;
+- return 0;
+- }
+- return -1;
+-}
+-
+-/**
+- * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
+- * @pio_mask: pio_mask
+- * @mwdma_mask: mwdma_mask
+- * @udma_mask: udma_mask
+- *
+- * Pack @pio_mask, @mwdma_mask and @udma_mask into a single
+- * unsigned int xfer_mask.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Packed xfer_mask.
+- */
+-static unsigned int ata_pack_xfermask(unsigned int pio_mask,
+- unsigned int mwdma_mask,
+- unsigned int udma_mask)
+-{
+- return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+- ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+- ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+-}
+-
+-/**
+- * ata_unpack_xfermask - Unpack xfer_mask into pio, mwdma and udma masks
+- * @xfer_mask: xfer_mask to unpack
+- * @pio_mask: resulting pio_mask
+- * @mwdma_mask: resulting mwdma_mask
+- * @udma_mask: resulting udma_mask
+- *
+- * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
+- * Any NULL distination masks will be ignored.
+- */
+-static void ata_unpack_xfermask(unsigned int xfer_mask,
+- unsigned int *pio_mask,
+- unsigned int *mwdma_mask,
+- unsigned int *udma_mask)
+-{
+- if (pio_mask)
+- *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO;
+- if (mwdma_mask)
+- *mwdma_mask = (xfer_mask & ATA_MASK_MWDMA) >> ATA_SHIFT_MWDMA;
+- if (udma_mask)
+- *udma_mask = (xfer_mask & ATA_MASK_UDMA) >> ATA_SHIFT_UDMA;
+-}
+-
+-static const struct ata_xfer_ent {
+- int shift, bits;
+- u8 base;
+-} ata_xfer_tbl[] = {
+- { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
+- { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
+- { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+- { -1, },
+-};
+-
+-/**
+- * ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
+- * @xfer_mask: xfer_mask of interest
+- *
+- * Return matching XFER_* value for @xfer_mask. Only the highest
+- * bit of @xfer_mask is considered.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Matching XFER_* value, 0 if no match found.
+- */
+-static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+-{
+- int highbit = fls(xfer_mask) - 1;
+- const struct ata_xfer_ent *ent;
+-
+- for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+- if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
+- return ent->base + highbit - ent->shift;
+- return 0;
+-}
+-
+-/**
+- * ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
+- * @xfer_mode: XFER_* of interest
+- *
+- * Return matching xfer_mask for @xfer_mode.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Matching xfer_mask, 0 if no match found.
+- */
+-static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+-{
+- const struct ata_xfer_ent *ent;
+-
+- for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+- if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+- return 1 << (ent->shift + xfer_mode - ent->base);
+- return 0;
+-}
+-
+-/**
+- * ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
+- * @xfer_mode: XFER_* of interest
+- *
+- * Return matching xfer_shift for @xfer_mode.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Matching xfer_shift, -1 if no match found.
+- */
+-static int ata_xfer_mode2shift(unsigned int xfer_mode)
+-{
+- const struct ata_xfer_ent *ent;
+-
+- for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+- if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+- return ent->shift;
+- return -1;
+-}
+-
+-/**
+- * ata_mode_string - convert xfer_mask to string
+- * @xfer_mask: mask of bits supported; only highest bit counts.
+- *
+- * Determine string which represents the highest speed
+- * (highest bit in @modemask).
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Constant C string representing highest speed listed in
+- * @mode_mask, or the constant C string "<n/a>".
+- */
+-static const char *ata_mode_string(unsigned int xfer_mask)
+-{
+- static const char * const xfer_mode_str[] = {
+- "PIO0",
+- "PIO1",
+- "PIO2",
+- "PIO3",
+- "PIO4",
+- "MWDMA0",
+- "MWDMA1",
+- "MWDMA2",
+- "UDMA/16",
+- "UDMA/25",
+- "UDMA/33",
+- "UDMA/44",
+- "UDMA/66",
+- "UDMA/100",
+- "UDMA/133",
+- "UDMA7",
+- };
+- int highbit;
+-
+- highbit = fls(xfer_mask) - 1;
+- if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
+- return xfer_mode_str[highbit];
+- return "<n/a>";
+-}
+-
+-static const char *sata_spd_string(unsigned int spd)
+-{
+- static const char * const spd_str[] = {
+- "1.5 Gbps",
+- "3.0 Gbps",
+- };
+-
+- if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
+- return "<unknown>";
+- return spd_str[spd - 1];
+-}
+-
+-void ata_dev_disable(struct ata_device *dev)
+-{
+- if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
+- ata_dev_printk(dev, KERN_WARNING, "disabled\n");
+- dev->class++;
+- }
+-}
+-
+-/**
+- * ata_pio_devchk - PATA device presence detection
+- * @ap: ATA channel to examine
+- * @device: Device to examine (starting at zero)
+- *
+- * This technique was originally described in
+- * Hale Landis's ATADRVR (www.ata-atapi.com), and
+- * later found its way into the ATA/ATAPI spec.
+- *
+- * Write a pattern to the ATA shadow registers,
+- * and if a device is present, it will respond by
+- * correctly storing and echoing back the
+- * ATA shadow register contents.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-static unsigned int ata_pio_devchk(struct ata_port *ap,
+- unsigned int device)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- u8 nsect, lbal;
+-
+- ap->ops->dev_select(ap, device);
+-
+- outb(0x55, ioaddr->nsect_addr);
+- outb(0xaa, ioaddr->lbal_addr);
+-
+- outb(0xaa, ioaddr->nsect_addr);
+- outb(0x55, ioaddr->lbal_addr);
+-
+- outb(0x55, ioaddr->nsect_addr);
+- outb(0xaa, ioaddr->lbal_addr);
+-
+- nsect = inb(ioaddr->nsect_addr);
+- lbal = inb(ioaddr->lbal_addr);
+-
+- if ((nsect == 0x55) && (lbal == 0xaa))
+- return 1; /* we found a device */
+-
+- return 0; /* nothing found */
+-}
+-
+-/**
+- * ata_mmio_devchk - PATA device presence detection
+- * @ap: ATA channel to examine
+- * @device: Device to examine (starting at zero)
+- *
+- * This technique was originally described in
+- * Hale Landis's ATADRVR (www.ata-atapi.com), and
+- * later found its way into the ATA/ATAPI spec.
+- *
+- * Write a pattern to the ATA shadow registers,
+- * and if a device is present, it will respond by
+- * correctly storing and echoing back the
+- * ATA shadow register contents.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-static unsigned int ata_mmio_devchk(struct ata_port *ap,
+- unsigned int device)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- u8 nsect, lbal;
+-
+- ap->ops->dev_select(ap, device);
+-
+- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+-
+- writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
+- writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
+-
+- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+-
+- nsect = readb((void __iomem *) ioaddr->nsect_addr);
+- lbal = readb((void __iomem *) ioaddr->lbal_addr);
+-
+- if ((nsect == 0x55) && (lbal == 0xaa))
+- return 1; /* we found a device */
+-
+- return 0; /* nothing found */
+-}
+-
+-/**
+- * ata_devchk - PATA device presence detection
+- * @ap: ATA channel to examine
+- * @device: Device to examine (starting at zero)
+- *
+- * Dispatch ATA device presence detection, depending
+- * on whether we are using PIO or MMIO to talk to the
+- * ATA shadow registers.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-static unsigned int ata_devchk(struct ata_port *ap,
+- unsigned int device)
+-{
+- if (ap->flags & ATA_FLAG_MMIO)
+- return ata_mmio_devchk(ap, device);
+- return ata_pio_devchk(ap, device);
+-}
+-
+-/**
+- * ata_dev_classify - determine device type based on ATA-spec signature
+- * @tf: ATA taskfile register set for device to be identified
+- *
+- * Determine from taskfile register contents whether a device is
+- * ATA or ATAPI, as per "Signature and persistence" section
+- * of ATA/PI spec (volume 1, sect 5.14).
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
+- * the event of failure.
+- */
+-
+-unsigned int ata_dev_classify(const struct ata_taskfile *tf)
+-{
+- /* Apple's open source Darwin code hints that some devices only
+- * put a proper signature into the LBA mid/high registers,
+- * So, we only check those. It's sufficient for uniqueness.
+- */
+-
+- if (((tf->lbam == 0) && (tf->lbah == 0)) ||
+- ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+- DPRINTK("found ATA device by sig\n");
+- return ATA_DEV_ATA;
+- }
+-
+- if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
+- ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+- DPRINTK("found ATAPI device by sig\n");
+- return ATA_DEV_ATAPI;
+- }
+-
+- DPRINTK("unknown device\n");
+- return ATA_DEV_UNKNOWN;
+-}
+-
+-/**
+- * ata_dev_try_classify - Parse returned ATA device signature
+- * @ap: ATA channel to examine
+- * @device: Device to examine (starting at zero)
+- * @r_err: Value of error register on completion
+- *
+- * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
+- * an ATA/ATAPI-defined set of values is placed in the ATA
+- * shadow registers, indicating the results of device detection
+- * and diagnostics.
+- *
+- * Select the ATA device, and read the values from the ATA shadow
+- * registers. Then parse according to the Error register value,
+- * and the spec-defined values examined by ata_dev_classify().
+- *
+- * LOCKING:
+- * caller.
+- *
+- * RETURNS:
+- * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
+- */
+-
+-static unsigned int
+-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+-{
+- struct ata_taskfile tf;
+- unsigned int class;
+- u8 err;
+-
+- ap->ops->dev_select(ap, device);
+-
+- memset(&tf, 0, sizeof(tf));
+-
+- ap->ops->tf_read(ap, &tf);
+- err = tf.feature;
+- if (r_err)
+- *r_err = err;
+-
+- /* see if device passed diags */
+- if (err == 1)
+- /* do nothing */ ;
+- else if ((device == 0) && (err == 0x81))
+- /* do nothing */ ;
+- else
+- return ATA_DEV_NONE;
+-
+- /* determine if device is ATA or ATAPI */
+- class = ata_dev_classify(&tf);
+-
+- if (class == ATA_DEV_UNKNOWN)
+- return ATA_DEV_NONE;
+- if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+- return ATA_DEV_NONE;
+- return class;
+-}
+-
+-/**
+- * ata_id_string - Convert IDENTIFY DEVICE page into string
+- * @id: IDENTIFY DEVICE results we will examine
+- * @s: string into which data is output
+- * @ofs: offset into identify device page
+- * @len: length of string to return. must be an even number.
+- *
+- * The strings in the IDENTIFY DEVICE page are broken up into
+- * 16-bit chunks. Run through the string, and output each
+- * 8-bit chunk linearly, regardless of platform.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-void ata_id_string(const u16 *id, unsigned char *s,
+- unsigned int ofs, unsigned int len)
+-{
+- unsigned int c;
+-
+- while (len > 0) {
+- c = id[ofs] >> 8;
+- *s = c;
+- s++;
+-
+- c = id[ofs] & 0xff;
+- *s = c;
+- s++;
+-
+- ofs++;
+- len -= 2;
+- }
+-}
+-
+-/**
+- * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+- * @id: IDENTIFY DEVICE results we will examine
+- * @s: string into which data is output
+- * @ofs: offset into identify device page
+- * @len: length of string to return. must be an odd number.
+- *
+- * This function is identical to ata_id_string except that it
+- * trims trailing spaces and terminates the resulting string with
+- * null. @len must be actual maximum length (even number) + 1.
+- *
+- * LOCKING:
+- * caller.
+- */
+-void ata_id_c_string(const u16 *id, unsigned char *s,
+- unsigned int ofs, unsigned int len)
+-{
+- unsigned char *p;
+-
+- WARN_ON(!(len & 1));
+-
+- ata_id_string(id, s, ofs, len - 1);
+-
+- p = s + strnlen(s, len - 1);
+- while (p > s && p[-1] == ' ')
+- p--;
+- *p = '\0';
+-}
+-
+-static u64 ata_id_n_sectors(const u16 *id)
+-{
+- if (ata_id_has_lba(id)) {
+- if (ata_id_has_lba48(id))
+- return ata_id_u64(id, 100);
+- else
+- return ata_id_u32(id, 60);
+- } else {
+- if (ata_id_current_chs_valid(id))
+- return ata_id_u32(id, 57);
+- else
+- return id[1] * id[3] * id[6];
+- }
+-}
+-
+-/**
+- * ata_noop_dev_select - Select device 0/1 on ATA bus
+- * @ap: ATA channel to manipulate
+- * @device: ATA device (numbered from zero) to select
+- *
+- * This function performs no actual function.
+- *
+- * May be used as the dev_select() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * caller.
+- */
+-void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
+-{
+-}
+-
+-
+-/**
+- * ata_std_dev_select - Select device 0/1 on ATA bus
+- * @ap: ATA channel to manipulate
+- * @device: ATA device (numbered from zero) to select
+- *
+- * Use the method defined in the ATA specification to
+- * make either device 0, or device 1, active on the
+- * ATA channel. Works with both PIO and MMIO.
+- *
+- * May be used as the dev_select() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-void ata_std_dev_select (struct ata_port *ap, unsigned int device)
+-{
+- u8 tmp;
+-
+- if (device == 0)
+- tmp = ATA_DEVICE_OBS;
+- else
+- tmp = ATA_DEVICE_OBS | ATA_DEV1;
+-
+- if (ap->flags & ATA_FLAG_MMIO) {
+- writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
+- } else {
+- outb(tmp, ap->ioaddr.device_addr);
+- }
+- ata_pause(ap); /* needed; also flushes, for mmio */
+-}
+-
+-/**
+- * ata_dev_select - Select device 0/1 on ATA bus
+- * @ap: ATA channel to manipulate
+- * @device: ATA device (numbered from zero) to select
+- * @wait: non-zero to wait for Status register BSY bit to clear
+- * @can_sleep: non-zero if context allows sleeping
+- *
+- * Use the method defined in the ATA specification to
+- * make either device 0, or device 1, active on the
+- * ATA channel.
+- *
+- * This is a high-level version of ata_std_dev_select(),
+- * which additionally provides the services of inserting
+- * the proper pauses and status polling, where needed.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-void ata_dev_select(struct ata_port *ap, unsigned int device,
+- unsigned int wait, unsigned int can_sleep)
+-{
+- if (ata_msg_probe(ap))
+- ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
+- "device %u, wait %u\n", ap->id, device, wait);
+-
+- if (wait)
+- ata_wait_idle(ap);
+-
+- ap->ops->dev_select(ap, device);
+-
+- if (wait) {
+- if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+- msleep(150);
+- ata_wait_idle(ap);
+- }
+-}
+-
+-/**
+- * ata_dump_id - IDENTIFY DEVICE info debugging output
+- * @id: IDENTIFY DEVICE page to dump
+- *
+- * Dump selected 16-bit words from the given IDENTIFY DEVICE
+- * page.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-static inline void ata_dump_id(const u16 *id)
+-{
+- DPRINTK("49==0x%04x "
+- "53==0x%04x "
+- "63==0x%04x "
+- "64==0x%04x "
+- "75==0x%04x \n",
+- id[49],
+- id[53],
+- id[63],
+- id[64],
+- id[75]);
+- DPRINTK("80==0x%04x "
+- "81==0x%04x "
+- "82==0x%04x "
+- "83==0x%04x "
+- "84==0x%04x \n",
+- id[80],
+- id[81],
+- id[82],
+- id[83],
+- id[84]);
+- DPRINTK("88==0x%04x "
+- "93==0x%04x\n",
+- id[88],
+- id[93]);
+-}
+-
+-/**
+- * ata_id_xfermask - Compute xfermask from the given IDENTIFY data
+- * @id: IDENTIFY data to compute xfer mask from
+- *
+- * Compute the xfermask for this device. This is not as trivial
+- * as it seems if we must consider early devices correctly.
+- *
+- * FIXME: pre IDE drive timing (do we care ?).
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Computed xfermask
+- */
+-static unsigned int ata_id_xfermask(const u16 *id)
+-{
+- unsigned int pio_mask, mwdma_mask, udma_mask;
+-
+- /* Usual case. Word 53 indicates word 64 is valid */
+- if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+- pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+- pio_mask <<= 3;
+- pio_mask |= 0x7;
+- } else {
+- /* If word 64 isn't valid then Word 51 high byte holds
+- * the PIO timing number for the maximum. Turn it into
+- * a mask.
+- */
+- pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+-
+- /* But wait.. there's more. Design your standards by
+- * committee and you too can get a free iordy field to
+- * process. However its the speeds not the modes that
+- * are supported... Note drivers using the timing API
+- * will get this right anyway
+- */
+- }
+-
+- mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+-
+- udma_mask = 0;
+- if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+- udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+-
+- return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
+-}
+-
+-/**
+- * ata_port_queue_task - Queue port_task
+- * @ap: The ata_port to queue port_task for
+- * @fn: workqueue function to be scheduled
+- * @data: data value to pass to workqueue function
+- * @delay: delay time for workqueue function
+- *
+- * Schedule @fn(@data) for execution after @delay jiffies using
+- * port_task. There is one port_task per port and it's the
+- * user(low level driver)'s responsibility to make sure that only
+- * one task is active at any given time.
+- *
+- * libata core layer takes care of synchronization between
+- * port_task and EH. ata_port_queue_task() may be ignored for EH
+- * synchronization.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
+- unsigned long delay)
+-{
+- int rc;
+-
+- if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
+- return;
+-
+- PREPARE_WORK(&ap->port_task, fn, data);
+-
+- if (!delay)
+- rc = queue_work(ata_wq, &ap->port_task);
+- else
+- rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
+-
+- /* rc == 0 means that another user is using port task */
+- WARN_ON(rc == 0);
+-}
+-
+-/**
+- * ata_port_flush_task - Flush port_task
+- * @ap: The ata_port to flush port_task for
+- *
+- * After this function completes, port_task is guranteed not to
+- * be running or scheduled.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- */
+-void ata_port_flush_task(struct ata_port *ap)
+-{
+- unsigned long flags;
+-
+- DPRINTK("ENTER\n");
+-
+- spin_lock_irqsave(ap->lock, flags);
+- ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- DPRINTK("flush #1\n");
+- flush_workqueue(ata_wq);
+-
+- /*
+- * At this point, if a task is running, it's guaranteed to see
+- * the FLUSH flag; thus, it will never queue pio tasks again.
+- * Cancel and flush.
+- */
+- if (!cancel_delayed_work(&ap->port_task)) {
+- if (ata_msg_ctl(ap))
+- ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
+- __FUNCTION__);
+- flush_workqueue(ata_wq);
+- }
+-
+- spin_lock_irqsave(ap->lock, flags);
+- ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- if (ata_msg_ctl(ap))
+- ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
+-}
+-
+-void ata_qc_complete_internal(struct ata_queued_cmd *qc)
+-{
+- struct completion *waiting = qc->private_data;
+-
+- complete(waiting);
+-}
+-
+-/**
+- * ata_exec_internal - execute libata internal command
+- * @dev: Device to which the command is sent
+- * @tf: Taskfile registers for the command and the result
+- * @cdb: CDB for packet command
+- * @dma_dir: Data tranfer direction of the command
+- * @buf: Data buffer of the command
+- * @buflen: Length of data buffer
+- *
+- * Executes libata internal command with timeout. @tf contains
+- * command on entry and result on return. Timeout and error
+- * conditions are reported via return value. No recovery action
+- * is taken after a command times out. It's caller's duty to
+- * clean up after timeout.
+- *
+- * LOCKING:
+- * None. Should be called with kernel context, might sleep.
+- *
+- * RETURNS:
+- * Zero on success, AC_ERR_* mask on failure
+- */
+-unsigned ata_exec_internal(struct ata_device *dev,
+- struct ata_taskfile *tf, const u8 *cdb,
+- int dma_dir, void *buf, unsigned int buflen)
+-{
+- struct ata_port *ap = dev->ap;
+- u8 command = tf->command;
+- struct ata_queued_cmd *qc;
+- unsigned int tag, preempted_tag;
+- u32 preempted_sactive, preempted_qc_active;
+- DECLARE_COMPLETION_ONSTACK(wait);
+- unsigned long flags;
+- unsigned int err_mask;
+- int rc;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* no internal command while frozen */
+- if (ap->pflags & ATA_PFLAG_FROZEN) {
+- spin_unlock_irqrestore(ap->lock, flags);
+- return AC_ERR_SYSTEM;
+- }
+-
+- /* initialize internal qc */
+-
+- /* XXX: Tag 0 is used for drivers with legacy EH as some
+- * drivers choke if any other tag is given. This breaks
+- * ata_tag_internal() test for those drivers. Don't use new
+- * EH stuff without converting to it.
+- */
+- if (ap->ops->error_handler)
+- tag = ATA_TAG_INTERNAL;
+- else
+- tag = 0;
+-
+- if (test_and_set_bit(tag, &ap->qc_allocated))
+- BUG();
+- qc = __ata_qc_from_tag(ap, tag);
+-
+- qc->tag = tag;
+- qc->scsicmd = NULL;
+- qc->ap = ap;
+- qc->dev = dev;
+- ata_qc_reinit(qc);
+-
+- preempted_tag = ap->active_tag;
+- preempted_sactive = ap->sactive;
+- preempted_qc_active = ap->qc_active;
+- ap->active_tag = ATA_TAG_POISON;
+- ap->sactive = 0;
+- ap->qc_active = 0;
+-
+- /* prepare & issue qc */
+- qc->tf = *tf;
+- if (cdb)
+- memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+- qc->flags |= ATA_QCFLAG_RESULT_TF;
+- qc->dma_dir = dma_dir;
+- if (dma_dir != DMA_NONE) {
+- ata_sg_init_one(qc, buf, buflen);
+- qc->nsect = buflen / ATA_SECT_SIZE;
+- }
+-
+- qc->private_data = &wait;
+- qc->complete_fn = ata_qc_complete_internal;
+-
+- ata_qc_issue(qc);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+-
+- ata_port_flush_task(ap);
+-
+- if (!rc) {
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* We're racing with irq here. If we lose, the
+- * following test prevents us from completing the qc
+- * twice. If we win, the port is frozen and will be
+- * cleaned up by ->post_internal_cmd().
+- */
+- if (qc->flags & ATA_QCFLAG_ACTIVE) {
+- qc->err_mask |= AC_ERR_TIMEOUT;
+-
+- if (ap->ops->error_handler)
+- ata_port_freeze(ap);
+- else
+- ata_qc_complete(qc);
+-
+- if (ata_msg_warn(ap))
+- ata_dev_printk(dev, KERN_WARNING,
+- "qc timeout (cmd 0x%x)\n", command);
+- }
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+- }
+-
+- /* do post_internal_cmd */
+- if (ap->ops->post_internal_cmd)
+- ap->ops->post_internal_cmd(qc);
+-
+- if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
+- if (ata_msg_warn(ap))
+- ata_dev_printk(dev, KERN_WARNING,
+- "zero err_mask for failed "
+- "internal command, assuming AC_ERR_OTHER\n");
+- qc->err_mask |= AC_ERR_OTHER;
+- }
+-
+- /* finish up */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- *tf = qc->result_tf;
+- err_mask = qc->err_mask;
+-
+- ata_qc_free(qc);
+- ap->active_tag = preempted_tag;
+- ap->sactive = preempted_sactive;
+- ap->qc_active = preempted_qc_active;
+-
+- /* XXX - Some LLDDs (sata_mv) disable port on command failure.
+- * Until those drivers are fixed, we detect the condition
+- * here, fail the command with AC_ERR_SYSTEM and reenable the
+- * port.
+- *
+- * Note that this doesn't change any behavior as internal
+- * command failure results in disabling the device in the
+- * higher layer for LLDDs without new reset/EH callbacks.
+- *
+- * Kill the following code as soon as those drivers are fixed.
+- */
+- if (ap->flags & ATA_FLAG_DISABLED) {
+- err_mask |= AC_ERR_SYSTEM;
+- ata_port_probe(ap);
+- }
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- return err_mask;
+-}
+-
+-/**
+- * ata_do_simple_cmd - execute simple internal command
+- * @dev: Device to which the command is sent
+- * @cmd: Opcode to execute
+- *
+- * Execute a 'simple' command, that only consists of the opcode
+- * 'cmd' itself, without filling any other registers
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * Zero on success, AC_ERR_* mask on failure
+- */
+-unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+-{
+- struct ata_taskfile tf;
+-
+- ata_tf_init(dev, &tf);
+-
+- tf.command = cmd;
+- tf.flags |= ATA_TFLAG_DEVICE;
+- tf.protocol = ATA_PROT_NODATA;
+-
+- return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+-}
+-
+-/**
+- * ata_pio_need_iordy - check if iordy needed
+- * @adev: ATA device
+- *
+- * Check if the current speed of the device requires IORDY. Used
+- * by various controllers for chip configuration.
+- */
+-
+-unsigned int ata_pio_need_iordy(const struct ata_device *adev)
+-{
+- int pio;
+- int speed = adev->pio_mode - XFER_PIO_0;
+-
+- if (speed < 2)
+- return 0;
+- if (speed > 2)
+- return 1;
+-
+- /* If we have no drive specific rule, then PIO 2 is non IORDY */
+-
+- if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
+- pio = adev->id[ATA_ID_EIDE_PIO];
+- /* Is the speed faster than the drive allows non IORDY ? */
+- if (pio) {
+- /* This is cycle times not frequency - watch the logic! */
+- if (pio > 240) /* PIO2 is 240nS per cycle */
+- return 1;
+- return 0;
+- }
+- }
+- return 0;
+-}
+-
+-/**
+- * ata_dev_read_id - Read ID data from the specified device
+- * @dev: target device
+- * @p_class: pointer to class of the target device (may be changed)
+- * @post_reset: is this read ID post-reset?
+- * @id: buffer to read IDENTIFY data into
+- *
+- * Read ID data from the specified device. ATA_CMD_ID_ATA is
+- * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
+- * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
+- * for pre-ATA4 drives.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+- int post_reset, u16 *id)
+-{
+- struct ata_port *ap = dev->ap;
+- unsigned int class = *p_class;
+- struct ata_taskfile tf;
+- unsigned int err_mask = 0;
+- const char *reason;
+- int rc;
+-
+- if (ata_msg_ctl(ap))
+- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+- __FUNCTION__, ap->id, dev->devno);
+-
+- ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
+-
+- retry:
+- ata_tf_init(dev, &tf);
+-
+- switch (class) {
+- case ATA_DEV_ATA:
+- tf.command = ATA_CMD_ID_ATA;
+- break;
+- case ATA_DEV_ATAPI:
+- tf.command = ATA_CMD_ID_ATAPI;
+- break;
+- default:
+- rc = -ENODEV;
+- reason = "unsupported class";
+- goto err_out;
+- }
+-
+- tf.protocol = ATA_PROT_PIO;
+-
+- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+- id, sizeof(id[0]) * ATA_ID_WORDS);
+- if (err_mask) {
+- rc = -EIO;
+- reason = "I/O error";
+- goto err_out;
+- }
+-
+- swap_buf_le16(id, ATA_ID_WORDS);
+-
+- /* sanity check */
+- rc = -EINVAL;
+- reason = "device reports illegal type";
+-
+- if (class == ATA_DEV_ATA) {
+- if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
+- goto err_out;
+- } else {
+- if (ata_id_is_ata(id))
+- goto err_out;
+- }
+-
+- if (post_reset && class == ATA_DEV_ATA) {
+- /*
+- * The exact sequence expected by certain pre-ATA4 drives is:
+- * SRST RESET
+- * IDENTIFY
+- * INITIALIZE DEVICE PARAMETERS
+- * anything else..
+- * Some drives were very specific about that exact sequence.
+- */
+- if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
+- err_mask = ata_dev_init_params(dev, id[3], id[6]);
+- if (err_mask) {
+- rc = -EIO;
+- reason = "INIT_DEV_PARAMS failed";
+- goto err_out;
+- }
+-
+- /* current CHS translation info (id[53-58]) might be
+- * changed. reread the identify device info.
+- */
+- post_reset = 0;
+- goto retry;
+- }
+- }
+-
+- *p_class = class;
+-
+- return 0;
+-
+- err_out:
+- if (ata_msg_warn(ap))
+- ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
+- "(%s, err_mask=0x%x)\n", reason, err_mask);
+- return rc;
+-}
+-
+-static inline u8 ata_dev_knobble(struct ata_device *dev)
+-{
+- return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+-}
+-
+-static void ata_dev_config_ncq(struct ata_device *dev,
+- char *desc, size_t desc_sz)
+-{
+- struct ata_port *ap = dev->ap;
+- int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+-
+- if (!ata_id_has_ncq(dev->id)) {
+- desc[0] = '\0';
+- return;
+- }
+-
+- if (ap->flags & ATA_FLAG_NCQ) {
+- hdepth = min(ap->host->can_queue, ATA_MAX_QUEUE - 1);
+- dev->flags |= ATA_DFLAG_NCQ;
+- }
+-
+- if (hdepth >= ddepth)
+- snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+- else
+- snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
+-}
+-
+-static void ata_set_port_max_cmd_len(struct ata_port *ap)
+-{
+- int i;
+-
+- if (ap->host) {
+- ap->host->max_cmd_len = 0;
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ap->host->max_cmd_len = max_t(unsigned int,
+- ap->host->max_cmd_len,
+- ap->device[i].cdb_len);
+- }
+-}
+-
+-/**
+- * ata_dev_configure - Configure the specified ATA/ATAPI device
+- * @dev: Target device to configure
+- * @print_info: Enable device info printout
+- *
+- * Configure @dev according to @dev->id. Generic and low-level
+- * driver specific fixups are also applied.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise
+- */
+-int ata_dev_configure(struct ata_device *dev, int print_info)
+-{
+- struct ata_port *ap = dev->ap;
+- const u16 *id = dev->id;
+- unsigned int xfer_mask;
+- int rc;
+-
+- if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
+- ata_dev_printk(dev, KERN_INFO,
+- "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+- __FUNCTION__, ap->id, dev->devno);
+- return 0;
+- }
+-
+- if (ata_msg_probe(ap))
+- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+- __FUNCTION__, ap->id, dev->devno);
+-
+- /* print device capabilities */
+- if (ata_msg_probe(ap))
+- ata_dev_printk(dev, KERN_DEBUG,
+- "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
+- "85:%04x 86:%04x 87:%04x 88:%04x\n",
+- __FUNCTION__,
+- id[49], id[82], id[83], id[84],
+- id[85], id[86], id[87], id[88]);
+-
+- /* initialize to-be-configured parameters */
+- dev->flags &= ~ATA_DFLAG_CFG_MASK;
+- dev->max_sectors = 0;
+- dev->cdb_len = 0;
+- dev->n_sectors = 0;
+- dev->cylinders = 0;
+- dev->heads = 0;
+- dev->sectors = 0;
+-
+- /*
+- * common ATA, ATAPI feature tests
+- */
+-
+- /* find max transfer mode; for printk only */
+- xfer_mask = ata_id_xfermask(id);
+-
+- if (ata_msg_probe(ap))
+- ata_dump_id(id);
+-
+- /* ATA-specific feature tests */
+- if (dev->class == ATA_DEV_ATA) {
+- dev->n_sectors = ata_id_n_sectors(id);
+-
+- if (ata_id_has_lba(id)) {
+- const char *lba_desc;
+- char ncq_desc[20];
+-
+- lba_desc = "LBA";
+- dev->flags |= ATA_DFLAG_LBA;
+- if (ata_id_has_lba48(id)) {
+- dev->flags |= ATA_DFLAG_LBA48;
+- lba_desc = "LBA48";
+- }
+-
+- /* config NCQ */
+- ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+-
+- /* print device info to dmesg */
+- if (ata_msg_drv(ap) && print_info)
+- ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
+- "max %s, %Lu sectors: %s %s\n",
+- ata_id_major_version(id),
+- ata_mode_string(xfer_mask),
+- (unsigned long long)dev->n_sectors,
+- lba_desc, ncq_desc);
+- } else {
+- /* CHS */
+-
+- /* Default translation */
+- dev->cylinders = id[1];
+- dev->heads = id[3];
+- dev->sectors = id[6];
+-
+- if (ata_id_current_chs_valid(id)) {
+- /* Current CHS translation is valid. */
+- dev->cylinders = id[54];
+- dev->heads = id[55];
+- dev->sectors = id[56];
+- }
+-
+- /* print device info to dmesg */
+- if (ata_msg_drv(ap) && print_info)
+- ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
+- "max %s, %Lu sectors: CHS %u/%u/%u\n",
+- ata_id_major_version(id),
+- ata_mode_string(xfer_mask),
+- (unsigned long long)dev->n_sectors,
+- dev->cylinders, dev->heads,
+- dev->sectors);
+- }
+-
+- if (dev->id[59] & 0x100) {
+- dev->multi_count = dev->id[59] & 0xff;
+- if (ata_msg_drv(ap) && print_info)
+- ata_dev_printk(dev, KERN_INFO,
+- "ata%u: dev %u multi count %u\n",
+- ap->id, dev->devno, dev->multi_count);
+- }
+-
+- dev->cdb_len = 16;
+- }
+-
+- /* ATAPI-specific feature tests */
+- else if (dev->class == ATA_DEV_ATAPI) {
+- char *cdb_intr_string = "";
+-
+- rc = atapi_cdb_len(id);
+- if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
+- if (ata_msg_warn(ap))
+- ata_dev_printk(dev, KERN_WARNING,
+- "unsupported CDB len\n");
+- rc = -EINVAL;
+- goto err_out_nosup;
+- }
+- dev->cdb_len = (unsigned int) rc;
+-
+- if (ata_id_cdb_intr(dev->id)) {
+- dev->flags |= ATA_DFLAG_CDB_INTR;
+- cdb_intr_string = ", CDB intr";
+- }
+-
+- /* print device info to dmesg */
+- if (ata_msg_drv(ap) && print_info)
+- ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
+- ata_mode_string(xfer_mask),
+- cdb_intr_string);
+- }
+-
+- ata_set_port_max_cmd_len(ap);
+-
+- /* limit bridge transfers to udma5, 200 sectors */
+- if (ata_dev_knobble(dev)) {
+- if (ata_msg_drv(ap) && print_info)
+- ata_dev_printk(dev, KERN_INFO,
+- "applying bridge limits\n");
+- dev->udma_mask &= ATA_UDMA5;
+- dev->max_sectors = ATA_MAX_SECTORS;
+- }
+-
+- if (ap->ops->dev_config)
+- ap->ops->dev_config(ap, dev);
+-
+- if (ata_msg_probe(ap))
+- ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
+- __FUNCTION__, ata_chk_status(ap));
+- return 0;
+-
+-err_out_nosup:
+- if (ata_msg_probe(ap))
+- ata_dev_printk(dev, KERN_DEBUG,
+- "%s: EXIT, err\n", __FUNCTION__);
+- return rc;
+-}
+-
+-/**
+- * ata_bus_probe - Reset and probe ATA bus
+- * @ap: Bus to probe
+- *
+- * Master ATA bus probing function. Initiates a hardware-dependent
+- * bus reset, then attempts to identify any devices found on
+- * the bus.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- * RETURNS:
+- * Zero on success, negative errno otherwise.
+- */
+-
+-static int ata_bus_probe(struct ata_port *ap)
+-{
+- unsigned int classes[ATA_MAX_DEVICES];
+- int tries[ATA_MAX_DEVICES];
+- int i, rc, down_xfermask;
+- struct ata_device *dev;
+-
+- ata_port_probe(ap);
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- tries[i] = ATA_PROBE_MAX_TRIES;
+-
+- retry:
+- down_xfermask = 0;
+-
+- /* reset and determine device classes */
+- ap->ops->phy_reset(ap);
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+-
+- if (!(ap->flags & ATA_FLAG_DISABLED) &&
+- dev->class != ATA_DEV_UNKNOWN)
+- classes[dev->devno] = dev->class;
+- else
+- classes[dev->devno] = ATA_DEV_NONE;
+-
+- dev->class = ATA_DEV_UNKNOWN;
+- }
+-
+- ata_port_probe(ap);
+-
+- /* after the reset the device state is PIO 0 and the controller
+- state is undefined. Record the mode */
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ap->device[i].pio_mode = XFER_PIO_0;
+-
+- /* read IDENTIFY page and configure devices */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+-
+- if (tries[i])
+- dev->class = classes[i];
+-
+- if (!ata_dev_enabled(dev))
+- continue;
+-
+- rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+- if (rc)
+- goto fail;
+-
+- rc = ata_dev_configure(dev, 1);
+- if (rc)
+- goto fail;
+- }
+-
+- /* configure transfer mode */
+- rc = ata_set_mode(ap, &dev);
+- if (rc) {
+- down_xfermask = 1;
+- goto fail;
+- }
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- if (ata_dev_enabled(&ap->device[i]))
+- return 0;
+-
+- /* no device present, disable port */
+- ata_port_disable(ap);
+- ap->ops->port_disable(ap);
+- return -ENODEV;
+-
+- fail:
+- switch (rc) {
+- case -EINVAL:
+- case -ENODEV:
+- tries[dev->devno] = 0;
+- break;
+- case -EIO:
+- sata_down_spd_limit(ap);
+- /* fall through */
+- default:
+- tries[dev->devno]--;
+- if (down_xfermask &&
+- ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
+- tries[dev->devno] = 0;
+- }
+-
+- if (!tries[dev->devno]) {
+- ata_down_xfermask_limit(dev, 1);
+- ata_dev_disable(dev);
+- }
+-
+- goto retry;
+-}
+-
+-/**
+- * ata_port_probe - Mark port as enabled
+- * @ap: Port for which we indicate enablement
+- *
+- * Modify @ap data structure such that the system
+- * thinks that the entire port is enabled.
+- *
+- * LOCKING: host_set lock, or some other form of
+- * serialization.
+- */
+-
+-void ata_port_probe(struct ata_port *ap)
+-{
+- ap->flags &= ~ATA_FLAG_DISABLED;
+-}
+-
+-/**
+- * sata_print_link_status - Print SATA link status
+- * @ap: SATA port to printk link status about
+- *
+- * This function prints link speed and status of a SATA link.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void sata_print_link_status(struct ata_port *ap)
+-{
+- u32 sstatus, scontrol, tmp;
+-
+- if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+- return;
+- sata_scr_read(ap, SCR_CONTROL, &scontrol);
+-
+- if (ata_port_online(ap)) {
+- tmp = (sstatus >> 4) & 0xf;
+- ata_port_printk(ap, KERN_INFO,
+- "SATA link up %s (SStatus %X SControl %X)\n",
+- sata_spd_string(tmp), sstatus, scontrol);
+- } else {
+- ata_port_printk(ap, KERN_INFO,
+- "SATA link down (SStatus %X SControl %X)\n",
+- sstatus, scontrol);
+- }
+-}
+-
+-/**
+- * __sata_phy_reset - Wake/reset a low-level SATA PHY
+- * @ap: SATA port associated with target SATA PHY.
+- *
+- * This function issues commands to standard SATA Sxxx
+- * PHY registers, to wake up the phy (and device), and
+- * clear any reset condition.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- */
+-void __sata_phy_reset(struct ata_port *ap)
+-{
+- u32 sstatus;
+- unsigned long timeout = jiffies + (HZ * 5);
+-
+- if (ap->flags & ATA_FLAG_SATA_RESET) {
+- /* issue phy wake/reset */
+- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+- /* Couldn't find anything in SATA I/II specs, but
+- * AHCI-1.1 10.4.2 says at least 1 ms. */
+- mdelay(1);
+- }
+- /* phy wake/clear reset */
+- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+-
+- /* wait for phy to become ready, if necessary */
+- do {
+- msleep(200);
+- sata_scr_read(ap, SCR_STATUS, &sstatus);
+- if ((sstatus & 0xf) != 1)
+- break;
+- } while (time_before(jiffies, timeout));
+-
+- /* print link status */
+- sata_print_link_status(ap);
+-
+- /* TODO: phy layer with polling, timeouts, etc. */
+- if (!ata_port_offline(ap))
+- ata_port_probe(ap);
+- else
+- ata_port_disable(ap);
+-
+- if (ap->flags & ATA_FLAG_DISABLED)
+- return;
+-
+- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+- ata_port_disable(ap);
+- return;
+- }
+-
+- ap->cbl = ATA_CBL_SATA;
+-}
+-
+-/**
+- * sata_phy_reset - Reset SATA bus.
+- * @ap: SATA port associated with target SATA PHY.
+- *
+- * This function resets the SATA bus, and then probes
+- * the bus for devices.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- */
+-void sata_phy_reset(struct ata_port *ap)
+-{
+- __sata_phy_reset(ap);
+- if (ap->flags & ATA_FLAG_DISABLED)
+- return;
+- ata_bus_reset(ap);
+-}
+-
+-/**
+- * ata_dev_pair - return other device on cable
+- * @adev: device
+- *
+- * Obtain the other device on the same cable, or if none is
+- * present NULL is returned
+- */
+-
+-struct ata_device *ata_dev_pair(struct ata_device *adev)
+-{
+- struct ata_port *ap = adev->ap;
+- struct ata_device *pair = &ap->device[1 - adev->devno];
+- if (!ata_dev_enabled(pair))
+- return NULL;
+- return pair;
+-}
+-
+-/**
+- * ata_port_disable - Disable port.
+- * @ap: Port to be disabled.
+- *
+- * Modify @ap data structure such that the system
+- * thinks that the entire port is disabled, and should
+- * never attempt to probe or communicate with devices
+- * on this port.
+- *
+- * LOCKING: host_set lock, or some other form of
+- * serialization.
+- */
+-
+-void ata_port_disable(struct ata_port *ap)
+-{
+- ap->device[0].class = ATA_DEV_NONE;
+- ap->device[1].class = ATA_DEV_NONE;
+- ap->flags |= ATA_FLAG_DISABLED;
+-}
+-
+-/**
+- * sata_down_spd_limit - adjust SATA spd limit downward
+- * @ap: Port to adjust SATA spd limit for
+- *
+- * Adjust SATA spd limit of @ap downward. Note that this
+- * function only adjusts the limit. The change must be applied
+- * using sata_set_spd().
+- *
+- * LOCKING:
+- * Inherited from caller.
+- *
+- * RETURNS:
+- * 0 on success, negative errno on failure
+- */
+-int sata_down_spd_limit(struct ata_port *ap)
+-{
+- u32 sstatus, spd, mask;
+- int rc, highbit;
+-
+- rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+- if (rc)
+- return rc;
+-
+- mask = ap->sata_spd_limit;
+- if (mask <= 1)
+- return -EINVAL;
+- highbit = fls(mask) - 1;
+- mask &= ~(1 << highbit);
+-
+- spd = (sstatus >> 4) & 0xf;
+- if (spd <= 1)
+- return -EINVAL;
+- spd--;
+- mask &= (1 << spd) - 1;
+- if (!mask)
+- return -EINVAL;
+-
+- ap->sata_spd_limit = mask;
+-
+- ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+- sata_spd_string(fls(mask)));
+-
+- return 0;
+-}
+-
+-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+-{
+- u32 spd, limit;
+-
+- if (ap->sata_spd_limit == UINT_MAX)
+- limit = 0;
+- else
+- limit = fls(ap->sata_spd_limit);
+-
+- spd = (*scontrol >> 4) & 0xf;
+- *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
+-
+- return spd != limit;
+-}
+-
+-/**
+- * sata_set_spd_needed - is SATA spd configuration needed
+- * @ap: Port in question
+- *
+- * Test whether the spd limit in SControl matches
+- * @ap->sata_spd_limit. This function is used to determine
+- * whether hardreset is necessary to apply SATA spd
+- * configuration.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- *
+- * RETURNS:
+- * 1 if SATA spd configuration is needed, 0 otherwise.
+- */
+-int sata_set_spd_needed(struct ata_port *ap)
+-{
+- u32 scontrol;
+-
+- if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+- return 0;
+-
+- return __sata_set_spd_needed(ap, &scontrol);
+-}
+-
+-/**
+- * sata_set_spd - set SATA spd according to spd limit
+- * @ap: Port to set SATA spd for
+- *
+- * Set SATA spd of @ap according to sata_spd_limit.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- *
+- * RETURNS:
+- * 0 if spd doesn't need to be changed, 1 if spd has been
+- * changed. Negative errno if SCR registers are inaccessible.
+- */
+-int sata_set_spd(struct ata_port *ap)
+-{
+- u32 scontrol;
+- int rc;
+-
+- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+- return rc;
+-
+- if (!__sata_set_spd_needed(ap, &scontrol))
+- return 0;
+-
+- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+- return rc;
+-
+- return 1;
+-}
+-
+-/*
+- * This mode timing computation functionality is ported over from
+- * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
+- */
+-/*
+- * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+- * These were taken from ATA/ATAPI-6 standard, rev 0a, except
+- * for PIO 5, which is a nonstandard extension and UDMA6, which
+- * is currently supported only by Maxtor drives.
+- */
+-
+-static const struct ata_timing ata_timing[] = {
+-
+- { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
+- { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
+- { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
+- { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
+-
+- { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
+- { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
+- { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
+-
+-/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */
+-
+- { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
+- { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
+- { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
+-
+- { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
+- { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
+- { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
+-
+-/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */
+- { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
+- { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
+-
+- { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
+- { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
+- { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
+-
+-/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */
+-
+- { 0xFF }
+-};
+-
+-#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
+-#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)
+-
+-static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
+-{
+- q->setup = EZ(t->setup * 1000, T);
+- q->act8b = EZ(t->act8b * 1000, T);
+- q->rec8b = EZ(t->rec8b * 1000, T);
+- q->cyc8b = EZ(t->cyc8b * 1000, T);
+- q->active = EZ(t->active * 1000, T);
+- q->recover = EZ(t->recover * 1000, T);
+- q->cycle = EZ(t->cycle * 1000, T);
+- q->udma = EZ(t->udma * 1000, UT);
+-}
+-
+-void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
+- struct ata_timing *m, unsigned int what)
+-{
+- if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup);
+- if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b);
+- if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b);
+- if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
+- if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
+- if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
+- if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
+- if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
+-}
+-
+-static const struct ata_timing* ata_timing_find_mode(unsigned short speed)
+-{
+- const struct ata_timing *t;
+-
+- for (t = ata_timing; t->mode != speed; t++)
+- if (t->mode == 0xFF)
+- return NULL;
+- return t;
+-}
+-
+-int ata_timing_compute(struct ata_device *adev, unsigned short speed,
+- struct ata_timing *t, int T, int UT)
+-{
+- const struct ata_timing *s;
+- struct ata_timing p;
+-
+- /*
+- * Find the mode.
+- */
+-
+- if (!(s = ata_timing_find_mode(speed)))
+- return -EINVAL;
+-
+- memcpy(t, s, sizeof(*s));
+-
+- /*
+- * If the drive is an EIDE drive, it can tell us it needs extended
+- * PIO/MW_DMA cycle timing.
+- */
+-
+- if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
+- memset(&p, 0, sizeof(p));
+- if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
+- if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
+- else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
+- } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
+- p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
+- }
+- ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
+- }
+-
+- /*
+- * Convert the timing to bus clock counts.
+- */
+-
+- ata_timing_quantize(t, t, T, UT);
+-
+- /*
+- * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+- * S.M.A.R.T * and some other commands. We have to ensure that the
+- * DMA cycle timing is slower/equal than the fastest PIO timing.
+- */
+-
+- if (speed > XFER_PIO_4) {
+- ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
+- ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
+- }
+-
+- /*
+- * Lengthen active & recovery time so that cycle time is correct.
+- */
+-
+- if (t->act8b + t->rec8b < t->cyc8b) {
+- t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
+- t->rec8b = t->cyc8b - t->act8b;
+- }
+-
+- if (t->active + t->recover < t->cycle) {
+- t->active += (t->cycle - (t->active + t->recover)) / 2;
+- t->recover = t->cycle - t->active;
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * ata_down_xfermask_limit - adjust dev xfer masks downward
+- * @dev: Device to adjust xfer masks
+- * @force_pio0: Force PIO0
+- *
+- * Adjust xfer masks of @dev downward. Note that this function
+- * does not apply the change. Invoking ata_set_mode() afterwards
+- * will apply the limit.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- *
+- * RETURNS:
+- * 0 on success, negative errno on failure
+- */
+-int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
+-{
+- unsigned long xfer_mask;
+- int highbit;
+-
+- xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
+- dev->udma_mask);
+-
+- if (!xfer_mask)
+- goto fail;
+- /* don't gear down to MWDMA from UDMA, go directly to PIO */
+- if (xfer_mask & ATA_MASK_UDMA)
+- xfer_mask &= ~ATA_MASK_MWDMA;
+-
+- highbit = fls(xfer_mask) - 1;
+- xfer_mask &= ~(1 << highbit);
+- if (force_pio0)
+- xfer_mask &= 1 << ATA_SHIFT_PIO;
+- if (!xfer_mask)
+- goto fail;
+-
+- ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
+- &dev->udma_mask);
+-
+- ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
+- ata_mode_string(xfer_mask));
+-
+- return 0;
+-
+- fail:
+- return -EINVAL;
+-}
+-
+-static int ata_dev_set_mode(struct ata_device *dev)
+-{
+- unsigned int err_mask;
+- int rc;
+-
+- dev->flags &= ~ATA_DFLAG_PIO;
+- if (dev->xfer_shift == ATA_SHIFT_PIO)
+- dev->flags |= ATA_DFLAG_PIO;
+-
+- err_mask = ata_dev_set_xfermode(dev);
+- if (err_mask) {
+- ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
+- "(err_mask=0x%x)\n", err_mask);
+- return -EIO;
+- }
+-
+- rc = ata_dev_revalidate(dev, 0);
+- if (rc)
+- return rc;
+-
+- DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
+- dev->xfer_shift, (int)dev->xfer_mode);
+-
+- ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
+- ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
+- return 0;
+-}
+-
+-/**
+- * ata_set_mode - Program timings and issue SET FEATURES - XFER
+- * @ap: port on which timings will be programmed
+- * @r_failed_dev: out paramter for failed device
+- *
+- * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+- * ata_set_mode() fails, pointer to the failing device is
+- * returned in @r_failed_dev.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- * RETURNS:
+- * 0 on success, negative errno otherwise
+- */
+-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+-{
+- struct ata_device *dev;
+- int i, rc = 0, used_dma = 0, found = 0;
+-
+- /* has private set_mode? */
+- if (ap->ops->set_mode) {
+- /* FIXME: make ->set_mode handle no device case and
+- * return error code and failing device on failure.
+- */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- if (ata_dev_ready(&ap->device[i])) {
+- ap->ops->set_mode(ap);
+- break;
+- }
+- }
+- return 0;
+- }
+-
+- /* step 1: calculate xfer_mask */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- unsigned int pio_mask, dma_mask;
+-
+- dev = &ap->device[i];
+-
+- if (!ata_dev_enabled(dev))
+- continue;
+-
+- ata_dev_xfermask(dev);
+-
+- pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
+- dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+- dev->pio_mode = ata_xfer_mask2mode(pio_mask);
+- dev->dma_mode = ata_xfer_mask2mode(dma_mask);
+-
+- found = 1;
+- if (dev->dma_mode)
+- used_dma = 1;
+- }
+- if (!found)
+- goto out;
+-
+- /* step 2: always set host PIO timings */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+- if (!ata_dev_enabled(dev))
+- continue;
+-
+- if (!dev->pio_mode) {
+- ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
+- rc = -EINVAL;
+- goto out;
+- }
+-
+- dev->xfer_mode = dev->pio_mode;
+- dev->xfer_shift = ATA_SHIFT_PIO;
+- if (ap->ops->set_piomode)
+- ap->ops->set_piomode(ap, dev);
+- }
+-
+- /* step 3: set host DMA timings */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+-
+- if (!ata_dev_enabled(dev) || !dev->dma_mode)
+- continue;
+-
+- dev->xfer_mode = dev->dma_mode;
+- dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+- if (ap->ops->set_dmamode)
+- ap->ops->set_dmamode(ap, dev);
+- }
+-
+- /* step 4: update devices' xfer mode */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+-
+- /* don't udpate suspended devices' xfer mode */
+- if (!ata_dev_ready(dev))
+- continue;
+-
+- rc = ata_dev_set_mode(dev);
+- if (rc)
+- goto out;
+- }
+-
+- /* Record simplex status. If we selected DMA then the other
+- * host channels are not permitted to do so.
+- */
+- if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX))
+- ap->host_set->simplex_claimed = 1;
+-
+- /* step5: chip specific finalisation */
+- if (ap->ops->post_set_mode)
+- ap->ops->post_set_mode(ap);
+-
+- out:
+- if (rc)
+- *r_failed_dev = dev;
+- return rc;
+-}
+-
+-/**
+- * ata_tf_to_host - issue ATA taskfile to host controller
+- * @ap: port to which command is being issued
+- * @tf: ATA taskfile register set
+- *
+- * Issues ATA taskfile register set to ATA host controller,
+- * with proper synchronization with interrupt handler and
+- * other threads.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static inline void ata_tf_to_host(struct ata_port *ap,
+- const struct ata_taskfile *tf)
+-{
+- ap->ops->tf_load(ap, tf);
+- ap->ops->exec_command(ap, tf);
+-}
+-
+-/**
+- * ata_busy_sleep - sleep until BSY clears, or timeout
+- * @ap: port containing status register to be polled
+- * @tmout_pat: impatience timeout
+- * @tmout: overall timeout
+- *
+- * Sleep until ATA Status register bit BSY clears,
+- * or a timeout occurs.
+- *
+- * LOCKING: None.
+- */
+-
+-unsigned int ata_busy_sleep (struct ata_port *ap,
+- unsigned long tmout_pat, unsigned long tmout)
+-{
+- unsigned long timer_start, timeout;
+- u8 status;
+-
+- status = ata_busy_wait(ap, ATA_BUSY, 300);
+- timer_start = jiffies;
+- timeout = timer_start + tmout_pat;
+- while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+- msleep(50);
+- status = ata_busy_wait(ap, ATA_BUSY, 3);
+- }
+-
+- if (status & ATA_BUSY)
+- ata_port_printk(ap, KERN_WARNING,
+- "port is slow to respond, please be patient\n");
+-
+- timeout = timer_start + tmout;
+- while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+- msleep(50);
+- status = ata_chk_status(ap);
+- }
+-
+- if (status & ATA_BUSY) {
+- ata_port_printk(ap, KERN_ERR, "port failed to respond "
+- "(%lu secs)\n", tmout / HZ);
+- return 1;
+- }
+-
+- return 0;
+-}
+-
+-static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- unsigned int dev0 = devmask & (1 << 0);
+- unsigned int dev1 = devmask & (1 << 1);
+- unsigned long timeout;
+-
+- /* if device 0 was found in ata_devchk, wait for its
+- * BSY bit to clear
+- */
+- if (dev0)
+- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+-
+- /* if device 1 was found in ata_devchk, wait for
+- * register access, then wait for BSY to clear
+- */
+- timeout = jiffies + ATA_TMOUT_BOOT;
+- while (dev1) {
+- u8 nsect, lbal;
+-
+- ap->ops->dev_select(ap, 1);
+- if (ap->flags & ATA_FLAG_MMIO) {
+- nsect = readb((void __iomem *) ioaddr->nsect_addr);
+- lbal = readb((void __iomem *) ioaddr->lbal_addr);
+- } else {
+- nsect = inb(ioaddr->nsect_addr);
+- lbal = inb(ioaddr->lbal_addr);
+- }
+- if ((nsect == 1) && (lbal == 1))
+- break;
+- if (time_after(jiffies, timeout)) {
+- dev1 = 0;
+- break;
+- }
+- msleep(50); /* give drive a breather */
+- }
+- if (dev1)
+- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+-
+- /* is all this really necessary? */
+- ap->ops->dev_select(ap, 0);
+- if (dev1)
+- ap->ops->dev_select(ap, 1);
+- if (dev0)
+- ap->ops->dev_select(ap, 0);
+-}
+-
+-static unsigned int ata_bus_softreset(struct ata_port *ap,
+- unsigned int devmask)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+-
+- DPRINTK("ata%u: bus reset via SRST\n", ap->id);
+-
+- /* software reset. causes dev0 to be selected */
+- if (ap->flags & ATA_FLAG_MMIO) {
+- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+- udelay(20); /* FIXME: flush */
+- writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
+- udelay(20); /* FIXME: flush */
+- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+- } else {
+- outb(ap->ctl, ioaddr->ctl_addr);
+- udelay(10);
+- outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+- udelay(10);
+- outb(ap->ctl, ioaddr->ctl_addr);
+- }
+-
+- /* spec mandates ">= 2ms" before checking status.
+- * We wait 150ms, because that was the magic delay used for
+- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+- * between when the ATA command register is written, and then
+- * status is checked. Because waiting for "a while" before
+- * checking status is fine, post SRST, we perform this magic
+- * delay here as well.
+- *
+- * Old drivers/ide uses the 2mS rule and then waits for ready
+- */
+- msleep(150);
+-
+- /* Before we perform post reset processing we want to see if
+- * the bus shows 0xFF because the odd clown forgets the D7
+- * pulldown resistor.
+- */
+- if (ata_check_status(ap) == 0xFF) {
+- ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n");
+- return AC_ERR_OTHER;
+- }
+-
+- ata_bus_post_reset(ap, devmask);
+-
+- return 0;
+-}
+-
+-/**
+- * ata_bus_reset - reset host port and associated ATA channel
+- * @ap: port to reset
+- *
+- * This is typically the first time we actually start issuing
+- * commands to the ATA channel. We wait for BSY to clear, then
+- * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
+- * result. Determine what devices, if any, are on the channel
+- * by looking at the device 0/1 error register. Look at the signature
+- * stored in each device's taskfile registers, to determine if
+- * the device is ATA or ATAPI.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- * Obtains host_set lock.
+- *
+- * SIDE EFFECTS:
+- * Sets ATA_FLAG_DISABLED if bus reset fails.
+- */
+-
+-void ata_bus_reset(struct ata_port *ap)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+- u8 err;
+- unsigned int dev0, dev1 = 0, devmask = 0;
+-
+- DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+-
+- /* determine if device 0/1 are present */
+- if (ap->flags & ATA_FLAG_SATA_RESET)
+- dev0 = 1;
+- else {
+- dev0 = ata_devchk(ap, 0);
+- if (slave_possible)
+- dev1 = ata_devchk(ap, 1);
+- }
+-
+- if (dev0)
+- devmask |= (1 << 0);
+- if (dev1)
+- devmask |= (1 << 1);
+-
+- /* select device 0 again */
+- ap->ops->dev_select(ap, 0);
+-
+- /* issue bus reset */
+- if (ap->flags & ATA_FLAG_SRST)
+- if (ata_bus_softreset(ap, devmask))
+- goto err_out;
+-
+- /*
+- * determine by signature whether we have ATA or ATAPI devices
+- */
+- ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+- if ((slave_possible) && (err != 0x81))
+- ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+-
+- /* re-enable interrupts */
+- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+- ata_irq_on(ap);
+-
+- /* is double-select really necessary? */
+- if (ap->device[1].class != ATA_DEV_NONE)
+- ap->ops->dev_select(ap, 1);
+- if (ap->device[0].class != ATA_DEV_NONE)
+- ap->ops->dev_select(ap, 0);
+-
+- /* if no devices were detected, disable this port */
+- if ((ap->device[0].class == ATA_DEV_NONE) &&
+- (ap->device[1].class == ATA_DEV_NONE))
+- goto err_out;
+-
+- if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
+- /* set up device control for ATA_FLAG_SATA_RESET */
+- if (ap->flags & ATA_FLAG_MMIO)
+- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+- else
+- outb(ap->ctl, ioaddr->ctl_addr);
+- }
+-
+- DPRINTK("EXIT\n");
+- return;
+-
+-err_out:
+- ata_port_printk(ap, KERN_ERR, "disabling port\n");
+- ap->ops->port_disable(ap);
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * sata_phy_debounce - debounce SATA phy status
+- * @ap: ATA port to debounce SATA phy status for
+- * @params: timing parameters { interval, duratinon, timeout } in msec
+- *
+- * Make sure SStatus of @ap reaches stable state, determined by
+- * holding the same value where DET is not 1 for @duration polled
+- * every @interval, before @timeout. Timeout constraints the
+- * beginning of the stable state. Because, after hot unplugging,
+- * DET gets stuck at 1 on some controllers, this functions waits
+- * until timeout then returns 0 if DET is stable at 1.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno on failure.
+- */
+-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
+-{
+- unsigned long interval_msec = params[0];
+- unsigned long duration = params[1] * HZ / 1000;
+- unsigned long timeout = jiffies + params[2] * HZ / 1000;
+- unsigned long last_jiffies;
+- u32 last, cur;
+- int rc;
+-
+- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+- return rc;
+- cur &= 0xf;
+-
+- last = cur;
+- last_jiffies = jiffies;
+-
+- while (1) {
+- msleep(interval_msec);
+- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+- return rc;
+- cur &= 0xf;
+-
+- /* DET stable? */
+- if (cur == last) {
+- if (cur == 1 && time_before(jiffies, timeout))
+- continue;
+- if (time_after(jiffies, last_jiffies + duration))
+- return 0;
+- continue;
+- }
+-
+- /* unstable, start over */
+- last = cur;
+- last_jiffies = jiffies;
+-
+- /* check timeout */
+- if (time_after(jiffies, timeout))
+- return -EBUSY;
+- }
+-}
+-
+-/**
+- * sata_phy_resume - resume SATA phy
+- * @ap: ATA port to resume SATA phy for
+- * @params: timing parameters { interval, duratinon, timeout } in msec
+- *
+- * Resume SATA phy of @ap and debounce it.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno on failure.
+- */
+-int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
+-{
+- u32 scontrol;
+- int rc;
+-
+- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+- return rc;
+-
+- scontrol = (scontrol & 0x0f0) | 0x300;
+-
+- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+- return rc;
+-
+- /* Some PHYs react badly if SStatus is pounded immediately
+- * after resuming. Delay 200ms before debouncing.
+- */
+- msleep(200);
+-
+- return sata_phy_debounce(ap, params);
+-}
+-
+-static void ata_wait_spinup(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- unsigned long end, secs;
+- int rc;
+-
+- /* first, debounce phy if SATA */
+- if (ap->cbl == ATA_CBL_SATA) {
+- rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
+-
+- /* if debounced successfully and offline, no need to wait */
+- if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
+- return;
+- }
+-
+- /* okay, let's give the drive time to spin up */
+- end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
+- secs = ((end - jiffies) + HZ - 1) / HZ;
+-
+- if (time_after(jiffies, end))
+- return;
+-
+- if (secs > 5)
+- ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
+- "(%lu secs)\n", secs);
+-
+- schedule_timeout_uninterruptible(end - jiffies);
+-}
+-
+-/**
+- * ata_std_prereset - prepare for reset
+- * @ap: ATA port to be reset
+- *
+- * @ap is about to be reset. Initialize it.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-int ata_std_prereset(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- const unsigned long *timing = sata_ehc_deb_timing(ehc);
+- int rc;
+-
+- /* handle link resume & hotplug spinup */
+- if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+- (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+- ehc->i.action |= ATA_EH_HARDRESET;
+-
+- if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+- (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+- ata_wait_spinup(ap);
+-
+- /* if we're about to do hardreset, nothing more to do */
+- if (ehc->i.action & ATA_EH_HARDRESET)
+- return 0;
+-
+- /* if SATA, resume phy */
+- if (ap->cbl == ATA_CBL_SATA) {
+- rc = sata_phy_resume(ap, timing);
+- if (rc && rc != -EOPNOTSUPP) {
+- /* phy resume failed */
+- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+- "link for reset (errno=%d)\n", rc);
+- return rc;
+- }
+- }
+-
+- /* Wait for !BSY if the controller can wait for the first D2H
+- * Reg FIS and we don't know that no device is attached.
+- */
+- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
+- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+-
+- return 0;
+-}
+-
+-/**
+- * ata_std_softreset - reset host port via ATA SRST
+- * @ap: port to reset
+- * @classes: resulting classes of attached devices
+- *
+- * Reset host port using ATA SRST.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
+-{
+- unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+- unsigned int devmask = 0, err_mask;
+- u8 err;
+-
+- DPRINTK("ENTER\n");
+-
+- if (ata_port_offline(ap)) {
+- classes[0] = ATA_DEV_NONE;
+- goto out;
+- }
+-
+- /* determine if device 0/1 are present */
+- if (ata_devchk(ap, 0))
+- devmask |= (1 << 0);
+- if (slave_possible && ata_devchk(ap, 1))
+- devmask |= (1 << 1);
+-
+- /* select device 0 again */
+- ap->ops->dev_select(ap, 0);
+-
+- /* issue bus reset */
+- DPRINTK("about to softreset, devmask=%x\n", devmask);
+- err_mask = ata_bus_softreset(ap, devmask);
+- if (err_mask) {
+- ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+- err_mask);
+- return -EIO;
+- }
+-
+- /* determine by signature whether we have ATA or ATAPI devices */
+- classes[0] = ata_dev_try_classify(ap, 0, &err);
+- if (slave_possible && err != 0x81)
+- classes[1] = ata_dev_try_classify(ap, 1, &err);
+-
+- out:
+- DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+- return 0;
+-}
+-
+-/**
+- * sata_std_hardreset - reset host port via SATA phy reset
+- * @ap: port to reset
+- * @class: resulting class of attached device
+- *
+- * SATA phy-reset host port using DET bits of SControl register.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- const unsigned long *timing = sata_ehc_deb_timing(ehc);
+- u32 scontrol;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+-
+- if (sata_set_spd_needed(ap)) {
+- /* SATA spec says nothing about how to reconfigure
+- * spd. To be on the safe side, turn off phy during
+- * reconfiguration. This works for at least ICH7 AHCI
+- * and Sil3124.
+- */
+- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+- return rc;
+-
+- scontrol = (scontrol & 0x0f0) | 0x304;
+-
+- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+- return rc;
+-
+- sata_set_spd(ap);
+- }
+-
+- /* issue phy wake/reset */
+- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+- return rc;
+-
+- scontrol = (scontrol & 0x0f0) | 0x301;
+-
+- if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+- return rc;
+-
+- /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
+- * 10.4.2 says at least 1 ms.
+- */
+- msleep(1);
+-
+- /* bring phy back */
+- sata_phy_resume(ap, timing);
+-
+- /* TODO: phy layer with polling, timeouts, etc. */
+- if (ata_port_offline(ap)) {
+- *class = ATA_DEV_NONE;
+- DPRINTK("EXIT, link offline\n");
+- return 0;
+- }
+-
+- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+- ata_port_printk(ap, KERN_ERR,
+- "COMRESET failed (device not ready)\n");
+- return -EIO;
+- }
+-
+- ap->ops->dev_select(ap, 0); /* probably unnecessary */
+-
+- *class = ata_dev_try_classify(ap, 0, NULL);
+-
+- DPRINTK("EXIT, class=%u\n", *class);
+- return 0;
+-}
+-
+-/**
+- * ata_std_postreset - standard postreset callback
+- * @ap: the target ata_port
+- * @classes: classes of attached devices
+- *
+- * This function is invoked after a successful reset. Note that
+- * the device might have been reset more than once using
+- * different reset methods before postreset is invoked.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- */
+-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+-{
+- u32 serror;
+-
+- DPRINTK("ENTER\n");
+-
+- /* print link status */
+- sata_print_link_status(ap);
+-
+- /* clear SError */
+- if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
+- sata_scr_write(ap, SCR_ERROR, serror);
+-
+- /* re-enable interrupts */
+- if (!ap->ops->error_handler) {
+- /* FIXME: hack. create a hook instead */
+- if (ap->ioaddr.ctl_addr)
+- ata_irq_on(ap);
+- }
+-
+- /* is double-select really necessary? */
+- if (classes[0] != ATA_DEV_NONE)
+- ap->ops->dev_select(ap, 1);
+- if (classes[1] != ATA_DEV_NONE)
+- ap->ops->dev_select(ap, 0);
+-
+- /* bail out if no device is present */
+- if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+- DPRINTK("EXIT, no device\n");
+- return;
+- }
+-
+- /* set up device control */
+- if (ap->ioaddr.ctl_addr) {
+- if (ap->flags & ATA_FLAG_MMIO)
+- writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+- else
+- outb(ap->ctl, ap->ioaddr.ctl_addr);
+- }
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_dev_same_device - Determine whether new ID matches configured device
+- * @dev: device to compare against
+- * @new_class: class of the new device
+- * @new_id: IDENTIFY page of the new device
+- *
+- * Compare @new_class and @new_id against @dev and determine
+- * whether @dev is the device indicated by @new_class and
+- * @new_id.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 1 if @dev matches @new_class and @new_id, 0 otherwise.
+- */
+-static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
+- const u16 *new_id)
+-{
+- const u16 *old_id = dev->id;
+- unsigned char model[2][41], serial[2][21];
+- u64 new_n_sectors;
+-
+- if (dev->class != new_class) {
+- ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
+- dev->class, new_class);
+- return 0;
+- }
+-
+- ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
+- ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
+- ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
+- ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+- new_n_sectors = ata_id_n_sectors(new_id);
+-
+- if (strcmp(model[0], model[1])) {
+- ata_dev_printk(dev, KERN_INFO, "model number mismatch "
+- "'%s' != '%s'\n", model[0], model[1]);
+- return 0;
+- }
+-
+- if (strcmp(serial[0], serial[1])) {
+- ata_dev_printk(dev, KERN_INFO, "serial number mismatch "
+- "'%s' != '%s'\n", serial[0], serial[1]);
+- return 0;
+- }
+-
+- if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
+- ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
+- "%llu != %llu\n",
+- (unsigned long long)dev->n_sectors,
+- (unsigned long long)new_n_sectors);
+- return 0;
+- }
+-
+- return 1;
+-}
+-
+-/**
+- * ata_dev_revalidate - Revalidate ATA device
+- * @dev: device to revalidate
+- * @post_reset: is this revalidation after reset?
+- *
+- * Re-read IDENTIFY page and make sure @dev is still attached to
+- * the port.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, negative errno otherwise
+- */
+-int ata_dev_revalidate(struct ata_device *dev, int post_reset)
+-{
+- unsigned int class = dev->class;
+- u16 *id = (void *)dev->ap->sector_buf;
+- int rc;
+-
+- if (!ata_dev_enabled(dev)) {
+- rc = -ENODEV;
+- goto fail;
+- }
+-
+- /* read ID data */
+- rc = ata_dev_read_id(dev, &class, post_reset, id);
+- if (rc)
+- goto fail;
+-
+- /* is the device still there? */
+- if (!ata_dev_same_device(dev, class, id)) {
+- rc = -ENODEV;
+- goto fail;
+- }
+-
+- memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS);
+-
+- /* configure device according to the new ID */
+- rc = ata_dev_configure(dev, 0);
+- if (rc == 0)
+- return 0;
+-
+- fail:
+- ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
+- return rc;
+-}
+-
+-static const char * const ata_dma_blacklist [] = {
+- "WDC AC11000H", NULL,
+- "WDC AC22100H", NULL,
+- "WDC AC32500H", NULL,
+- "WDC AC33100H", NULL,
+- "WDC AC31600H", NULL,
+- "WDC AC32100H", "24.09P07",
+- "WDC AC23200L", "21.10N21",
+- "Compaq CRD-8241B", NULL,
+- "CRD-8400B", NULL,
+- "CRD-8480B", NULL,
+- "CRD-8482B", NULL,
+- "CRD-84", NULL,
+- "SanDisk SDP3B", NULL,
+- "SanDisk SDP3B-64", NULL,
+- "SANYO CD-ROM CRD", NULL,
+- "HITACHI CDR-8", NULL,
+- "HITACHI CDR-8335", NULL,
+- "HITACHI CDR-8435", NULL,
+- "Toshiba CD-ROM XM-6202B", NULL,
+- "TOSHIBA CD-ROM XM-1702BC", NULL,
+- "CD-532E-A", NULL,
+- "E-IDE CD-ROM CR-840", NULL,
+- "CD-ROM Drive/F5A", NULL,
+- "WPI CDD-820", NULL,
+- "SAMSUNG CD-ROM SC-148C", NULL,
+- "SAMSUNG CD-ROM SC", NULL,
+- "SanDisk SDP3B-64", NULL,
+- "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,
+- "_NEC DV5800A", NULL,
+- "SAMSUNG CD-ROM SN-124", "N001"
+-};
+-
+-static int ata_strim(char *s, size_t len)
+-{
+- len = strnlen(s, len);
+-
+- /* ATAPI specifies that empty space is blank-filled; remove blanks */
+- while ((len > 0) && (s[len - 1] == ' ')) {
+- len--;
+- s[len] = 0;
+- }
+- return len;
+-}
+-
+-static int ata_dma_blacklisted(const struct ata_device *dev)
+-{
+- unsigned char model_num[40];
+- unsigned char model_rev[16];
+- unsigned int nlen, rlen;
+- int i;
+-
+- /* We don't support polling DMA.
+- * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
+- * if the LLDD handles only interrupts in the HSM_ST_LAST state.
+- */
+- if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+- (dev->flags & ATA_DFLAG_CDB_INTR))
+- return 1;
+-
+- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
+- sizeof(model_num));
+- ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
+- sizeof(model_rev));
+- nlen = ata_strim(model_num, sizeof(model_num));
+- rlen = ata_strim(model_rev, sizeof(model_rev));
+-
+- for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) {
+- if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) {
+- if (ata_dma_blacklist[i+1] == NULL)
+- return 1;
+- if (!strncmp(ata_dma_blacklist[i], model_rev, rlen))
+- return 1;
+- }
+- }
+- return 0;
+-}
+-
+-/**
+- * ata_dev_xfermask - Compute supported xfermask of the given device
+- * @dev: Device to compute xfermask for
+- *
+- * Compute supported xfermask of @dev and store it in
+- * dev->*_mask. This function is responsible for applying all
+- * known limits including host controller limits, device
+- * blacklist, etc...
+- *
+- * FIXME: The current implementation limits all transfer modes to
+- * the fastest of the lowested device on the port. This is not
+- * required on most controllers.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_dev_xfermask(struct ata_device *dev)
+-{
+- struct ata_port *ap = dev->ap;
+- struct ata_host_set *hs = ap->host_set;
+- unsigned long xfer_mask;
+- int i;
+-
+- xfer_mask = ata_pack_xfermask(ap->pio_mask,
+- ap->mwdma_mask, ap->udma_mask);
+-
+- /* Apply cable rule here. Don't apply it early because when
+- * we handle hot plug the cable type can itself change.
+- */
+- if (ap->cbl == ATA_CBL_PATA40)
+- xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
+-
+- /* FIXME: Use port-wide xfermask for now */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *d = &ap->device[i];
+-
+- if (ata_dev_absent(d))
+- continue;
+-
+- if (ata_dev_disabled(d)) {
+- /* to avoid violating device selection timing */
+- xfer_mask &= ata_pack_xfermask(d->pio_mask,
+- UINT_MAX, UINT_MAX);
+- continue;
+- }
+-
+- xfer_mask &= ata_pack_xfermask(d->pio_mask,
+- d->mwdma_mask, d->udma_mask);
+- xfer_mask &= ata_id_xfermask(d->id);
+- if (ata_dma_blacklisted(d))
+- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+- }
+-
+- if (ata_dma_blacklisted(dev))
+- ata_dev_printk(dev, KERN_WARNING,
+- "device is on DMA blacklist, disabling DMA\n");
+-
+- if (hs->flags & ATA_HOST_SIMPLEX) {
+- if (hs->simplex_claimed)
+- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+- }
+-
+- if (ap->ops->mode_filter)
+- xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
+-
+- ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
+- &dev->mwdma_mask, &dev->udma_mask);
+-}
+-
+-/**
+- * ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command
+- * @dev: Device to which command will be sent
+- *
+- * Issue SET FEATURES - XFER MODE command to device @dev
+- * on port @ap.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- * RETURNS:
+- * 0 on success, AC_ERR_* mask otherwise.
+- */
+-
+-static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
+-{
+- struct ata_taskfile tf;
+- unsigned int err_mask;
+-
+- /* set up set-features taskfile */
+- DPRINTK("set features - xfer mode\n");
+-
+- ata_tf_init(dev, &tf);
+- tf.command = ATA_CMD_SET_FEATURES;
+- tf.feature = SETFEATURES_XFER;
+- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+- tf.protocol = ATA_PROT_NODATA;
+- tf.nsect = dev->xfer_mode;
+-
+- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+-
+- DPRINTK("EXIT, err_mask=%x\n", err_mask);
+- return err_mask;
+-}
+-
+-/**
+- * ata_dev_init_params - Issue INIT DEV PARAMS command
+- * @dev: Device to which command will be sent
+- * @heads: Number of heads (taskfile parameter)
+- * @sectors: Number of sectors (taskfile parameter)
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, AC_ERR_* mask otherwise.
+- */
+-static unsigned int ata_dev_init_params(struct ata_device *dev,
+- u16 heads, u16 sectors)
+-{
+- struct ata_taskfile tf;
+- unsigned int err_mask;
+-
+- /* Number of sectors per track 1-255. Number of heads 1-16 */
+- if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
+- return AC_ERR_INVALID;
+-
+- /* set up init dev params taskfile */
+- DPRINTK("init dev params \n");
+-
+- ata_tf_init(dev, &tf);
+- tf.command = ATA_CMD_INIT_DEV_PARAMS;
+- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+- tf.protocol = ATA_PROT_NODATA;
+- tf.nsect = sectors;
+- tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
+-
+- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+-
+- DPRINTK("EXIT, err_mask=%x\n", err_mask);
+- return err_mask;
+-}
+-
+-/**
+- * ata_sg_clean - Unmap DMA memory associated with command
+- * @qc: Command containing DMA memory to be released
+- *
+- * Unmap all mapped DMA memory associated with this command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void ata_sg_clean(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct scatterlist *sg = qc->__sg;
+- int dir = qc->dma_dir;
+- void *pad_buf = NULL;
+-
+- WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+- WARN_ON(sg == NULL);
+-
+- if (qc->flags & ATA_QCFLAG_SINGLE)
+- WARN_ON(qc->n_elem > 1);
+-
+- VPRINTK("unmapping %u sg elements\n", qc->n_elem);
+-
+- /* if we padded the buffer out to 32-bit bound, and data
+- * xfer direction is from-device, we must copy from the
+- * pad buffer back into the supplied buffer
+- */
+- if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
+- pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+-
+- if (qc->flags & ATA_QCFLAG_SG) {
+- if (qc->n_elem)
+- dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
+- /* restore last sg */
+- sg[qc->orig_n_elem - 1].length += qc->pad_len;
+- if (pad_buf) {
+- struct scatterlist *psg = &qc->pad_sgent;
+- void *addr = kmap_atomic(psg->page, KM_IRQ0);
+- memcpy(addr + psg->offset, pad_buf, qc->pad_len);
+- kunmap_atomic(addr, KM_IRQ0);
+- }
+- } else {
+- if (qc->n_elem)
+- dma_unmap_single(ap->dev,
+- sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
+- dir);
+- /* restore sg */
+- sg->length += qc->pad_len;
+- if (pad_buf)
+- memcpy(qc->buf_virt + sg->length - qc->pad_len,
+- pad_buf, qc->pad_len);
+- }
+-
+- qc->flags &= ~ATA_QCFLAG_DMAMAP;
+- qc->__sg = NULL;
+-}
+-
+-/**
+- * ata_fill_sg - Fill PCI IDE PRD table
+- * @qc: Metadata associated with taskfile to be transferred
+- *
+- * Fill PCI IDE PRD (scatter-gather) table with segments
+- * associated with the current disk command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- */
+-static void ata_fill_sg(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct scatterlist *sg;
+- unsigned int idx;
+-
+- WARN_ON(qc->__sg == NULL);
+- WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+-
+- idx = 0;
+- ata_for_each_sg(sg, qc) {
+- u32 addr, offset;
+- u32 sg_len, len;
+-
+- /* determine if physical DMA addr spans 64K boundary.
+- * Note h/w doesn't support 64-bit, so we unconditionally
+- * truncate dma_addr_t to u32.
+- */
+- addr = (u32) sg_dma_address(sg);
+- sg_len = sg_dma_len(sg);
+-
+- while (sg_len) {
+- offset = addr & 0xffff;
+- len = sg_len;
+- if ((offset + sg_len) > 0x10000)
+- len = 0x10000 - offset;
+-
+- ap->prd[idx].addr = cpu_to_le32(addr);
+- ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+-
+- idx++;
+- sg_len -= len;
+- addr += len;
+- }
+- }
+-
+- if (idx)
+- ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+-}
+-/**
+- * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+- * @qc: Metadata associated with taskfile to check
+- *
+- * 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.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS: 0 when ATAPI DMA can be used
+- * nonzero otherwise
+- */
+-int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- int rc = 0; /* Assume ATAPI DMA is OK by default */
+-
+- if (ap->ops->check_atapi_dma)
+- rc = ap->ops->check_atapi_dma(qc);
+-
+- return rc;
+-}
+-/**
+- * ata_qc_prep - Prepare taskfile for submission
+- * @qc: Metadata associated with taskfile to be prepared
+- *
+- * Prepare ATA taskfile for submission.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_qc_prep(struct ata_queued_cmd *qc)
+-{
+- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+- return;
+-
+- ata_fill_sg(qc);
+-}
+-
+-void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
+-
+-/**
+- * ata_sg_init_one - Associate command with memory buffer
+- * @qc: Command to be associated
+- * @buf: Memory buffer
+- * @buflen: Length of memory buffer, in bytes.
+- *
+- * Initialize the data-related elements of queued_cmd @qc
+- * to point to a single memory buffer, @buf of byte length @buflen.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
+-{
+- struct scatterlist *sg;
+-
+- qc->flags |= ATA_QCFLAG_SINGLE;
+-
+- memset(&qc->sgent, 0, sizeof(qc->sgent));
+- qc->__sg = &qc->sgent;
+- qc->n_elem = 1;
+- qc->orig_n_elem = 1;
+- qc->buf_virt = buf;
+- qc->nbytes = buflen;
+-
+- sg = qc->__sg;
+- sg_init_one(sg, buf, buflen);
+-}
+-
+-/**
+- * ata_sg_init - Associate command with scatter-gather table.
+- * @qc: Command to be associated
+- * @sg: Scatter-gather table.
+- * @n_elem: Number of elements in s/g table.
+- *
+- * Initialize the data-related elements of queued_cmd @qc
+- * to point to a scatter-gather table @sg, containing @n_elem
+- * elements.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
+- unsigned int n_elem)
+-{
+- qc->flags |= ATA_QCFLAG_SG;
+- qc->__sg = sg;
+- qc->n_elem = n_elem;
+- qc->orig_n_elem = n_elem;
+-}
+-
+-/**
+- * ata_sg_setup_one - DMA-map the memory buffer associated with a command.
+- * @qc: Command with memory buffer to be mapped.
+- *
+- * DMA-map the memory buffer associated with queued_cmd @qc.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, negative on error.
+- */
+-
+-static int ata_sg_setup_one(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- int dir = qc->dma_dir;
+- struct scatterlist *sg = qc->__sg;
+- dma_addr_t dma_address;
+- int trim_sg = 0;
+-
+- /* we must lengthen transfers to end on a 32-bit boundary */
+- qc->pad_len = sg->length & 3;
+- if (qc->pad_len) {
+- void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+- struct scatterlist *psg = &qc->pad_sgent;
+-
+- WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
+-
+- memset(pad_buf, 0, ATA_DMA_PAD_SZ);
+-
+- if (qc->tf.flags & ATA_TFLAG_WRITE)
+- memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
+- qc->pad_len);
+-
+- sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
+- sg_dma_len(psg) = ATA_DMA_PAD_SZ;
+- /* trim sg */
+- sg->length -= qc->pad_len;
+- if (sg->length == 0)
+- trim_sg = 1;
+-
+- DPRINTK("padding done, sg->length=%u pad_len=%u\n",
+- sg->length, qc->pad_len);
+- }
+-
+- if (trim_sg) {
+- qc->n_elem--;
+- goto skip_map;
+- }
+-
+- dma_address = dma_map_single(ap->dev, qc->buf_virt,
+- sg->length, dir);
+- if (dma_mapping_error(dma_address)) {
+- /* restore sg */
+- sg->length += qc->pad_len;
+- return -1;
+- }
+-
+- sg_dma_address(sg) = dma_address;
+- sg_dma_len(sg) = sg->length;
+-
+-skip_map:
+- DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
+- qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+-
+- return 0;
+-}
+-
+-/**
+- * ata_sg_setup - DMA-map the scatter-gather table associated with a command.
+- * @qc: Command with scatter-gather table to be mapped.
+- *
+- * DMA-map the scatter-gather table associated with queued_cmd @qc.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, negative on error.
+- *
+- */
+-
+-static int ata_sg_setup(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct scatterlist *sg = qc->__sg;
+- struct scatterlist *lsg = &sg[qc->n_elem - 1];
+- int n_elem, pre_n_elem, dir, trim_sg = 0;
+-
+- VPRINTK("ENTER, ata%u\n", ap->id);
+- WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
+-
+- /* we must lengthen transfers to end on a 32-bit boundary */
+- qc->pad_len = lsg->length & 3;
+- if (qc->pad_len) {
+- void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+- struct scatterlist *psg = &qc->pad_sgent;
+- unsigned int offset;
+-
+- WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
+-
+- memset(pad_buf, 0, ATA_DMA_PAD_SZ);
+-
+- /*
+- * psg->page/offset are used to copy to-be-written
+- * data in this function or read data in ata_sg_clean.
+- */
+- offset = lsg->offset + lsg->length - qc->pad_len;
+- psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
+- psg->offset = offset_in_page(offset);
+-
+- if (qc->tf.flags & ATA_TFLAG_WRITE) {
+- void *addr = kmap_atomic(psg->page, KM_IRQ0);
+- memcpy(pad_buf, addr + psg->offset, qc->pad_len);
+- kunmap_atomic(addr, KM_IRQ0);
+- }
+-
+- sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
+- sg_dma_len(psg) = ATA_DMA_PAD_SZ;
+- /* trim last sg */
+- lsg->length -= qc->pad_len;
+- if (lsg->length == 0)
+- trim_sg = 1;
+-
+- DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
+- qc->n_elem - 1, lsg->length, qc->pad_len);
+- }
+-
+- pre_n_elem = qc->n_elem;
+- if (trim_sg && pre_n_elem)
+- pre_n_elem--;
+-
+- if (!pre_n_elem) {
+- n_elem = 0;
+- goto skip_map;
+- }
+-
+- dir = qc->dma_dir;
+- n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir);
+- if (n_elem < 1) {
+- /* restore last sg */
+- lsg->length += qc->pad_len;
+- return -1;
+- }
+-
+- DPRINTK("%d sg elements mapped\n", n_elem);
+-
+-skip_map:
+- qc->n_elem = n_elem;
+-
+- return 0;
+-}
+-
+-/**
+- * swap_buf_le16 - swap halves of 16-bit words in place
+- * @buf: Buffer to swap
+- * @buf_words: Number of 16-bit words in buffer.
+- *
+- * Swap halves of 16-bit words if needed to convert from
+- * little-endian byte order to native cpu byte order, or
+- * vice-versa.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void swap_buf_le16(u16 *buf, unsigned int buf_words)
+-{
+-#ifdef __BIG_ENDIAN
+- unsigned int i;
+-
+- for (i = 0; i < buf_words; i++)
+- buf[i] = le16_to_cpu(buf[i]);
+-#endif /* __BIG_ENDIAN */
+-}
+-
+-/**
+- * ata_mmio_data_xfer - Transfer data by MMIO
+- * @adev: device for this I/O
+- * @buf: data buffer
+- * @buflen: buffer length
+- * @write_data: read/write
+- *
+- * Transfer data from/to the device data register by MMIO.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
+- unsigned int buflen, int write_data)
+-{
+- struct ata_port *ap = adev->ap;
+- unsigned int i;
+- unsigned int words = buflen >> 1;
+- u16 *buf16 = (u16 *) buf;
+- void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
+-
+- /* Transfer multiple of 2 bytes */
+- if (write_data) {
+- for (i = 0; i < words; i++)
+- writew(le16_to_cpu(buf16[i]), mmio);
+- } else {
+- for (i = 0; i < words; i++)
+- buf16[i] = cpu_to_le16(readw(mmio));
+- }
+-
+- /* Transfer trailing 1 byte, if any. */
+- if (unlikely(buflen & 0x01)) {
+- u16 align_buf[1] = { 0 };
+- unsigned char *trailing_buf = buf + buflen - 1;
+-
+- if (write_data) {
+- memcpy(align_buf, trailing_buf, 1);
+- writew(le16_to_cpu(align_buf[0]), mmio);
+- } else {
+- align_buf[0] = cpu_to_le16(readw(mmio));
+- memcpy(trailing_buf, align_buf, 1);
+- }
+- }
+-}
+-
+-/**
+- * ata_pio_data_xfer - Transfer data by PIO
+- * @adev: device to target
+- * @buf: data buffer
+- * @buflen: buffer length
+- * @write_data: read/write
+- *
+- * Transfer data from/to the device data register by PIO.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
+- unsigned int buflen, int write_data)
+-{
+- struct ata_port *ap = adev->ap;
+- unsigned int words = buflen >> 1;
+-
+- /* Transfer multiple of 2 bytes */
+- if (write_data)
+- outsw(ap->ioaddr.data_addr, buf, words);
+- else
+- insw(ap->ioaddr.data_addr, buf, words);
+-
+- /* Transfer trailing 1 byte, if any. */
+- if (unlikely(buflen & 0x01)) {
+- u16 align_buf[1] = { 0 };
+- unsigned char *trailing_buf = buf + buflen - 1;
+-
+- if (write_data) {
+- memcpy(align_buf, trailing_buf, 1);
+- outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
+- } else {
+- align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
+- memcpy(trailing_buf, align_buf, 1);
+- }
+- }
+-}
+-
+-/**
+- * ata_pio_data_xfer_noirq - Transfer data by PIO
+- * @adev: device to target
+- * @buf: data buffer
+- * @buflen: buffer length
+- * @write_data: read/write
+- *
+- * Transfer data from/to the device data register by PIO. Do the
+- * transfer with interrupts disabled.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+- unsigned int buflen, int write_data)
+-{
+- unsigned long flags;
+- local_irq_save(flags);
+- ata_pio_data_xfer(adev, buf, buflen, write_data);
+- local_irq_restore(flags);
+-}
+-
+-
+-/**
+- * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
+- * @qc: Command on going
+- *
+- * Transfer ATA_SECT_SIZE of data from/to the ATA device.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void ata_pio_sector(struct ata_queued_cmd *qc)
+-{
+- int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+- struct scatterlist *sg = qc->__sg;
+- struct ata_port *ap = qc->ap;
+- struct page *page;
+- unsigned int offset;
+- unsigned char *buf;
+-
+- if (qc->cursect == (qc->nsect - 1))
+- ap->hsm_task_state = HSM_ST_LAST;
+-
+- page = sg[qc->cursg].page;
+- offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
+-
+- /* get the current page and offset */
+- page = nth_page(page, (offset >> PAGE_SHIFT));
+- offset %= PAGE_SIZE;
+-
+- DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+-
+- if (PageHighMem(page)) {
+- unsigned long flags;
+-
+- /* FIXME: use a bounce buffer */
+- local_irq_save(flags);
+- buf = kmap_atomic(page, KM_IRQ0);
+-
+- /* do the actual data transfer */
+- ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+-
+- kunmap_atomic(buf, KM_IRQ0);
+- local_irq_restore(flags);
+- } else {
+- buf = page_address(page);
+- ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+- }
+-
+- qc->cursect++;
+- qc->cursg_ofs++;
+-
+- if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
+- qc->cursg++;
+- qc->cursg_ofs = 0;
+- }
+-}
+-
+-/**
+- * ata_pio_sectors - Transfer one or many 512-byte sectors.
+- * @qc: Command on going
+- *
+- * Transfer one or many ATA_SECT_SIZE of data from/to the
+- * ATA device for the DRQ request.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void ata_pio_sectors(struct ata_queued_cmd *qc)
+-{
+- if (is_multi_taskfile(&qc->tf)) {
+- /* READ/WRITE MULTIPLE */
+- unsigned int nsect;
+-
+- WARN_ON(qc->dev->multi_count == 0);
+-
+- nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
+- while (nsect--)
+- ata_pio_sector(qc);
+- } else
+- ata_pio_sector(qc);
+-}
+-
+-/**
+- * atapi_send_cdb - Write CDB bytes to hardware
+- * @ap: Port to which ATAPI device is attached.
+- * @qc: Taskfile currently active
+- *
+- * When device has indicated its readiness to accept
+- * a CDB, this function is called. Send the CDB.
+- *
+- * LOCKING:
+- * caller.
+- */
+-
+-static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+-{
+- /* send SCSI cdb */
+- DPRINTK("send cdb\n");
+- WARN_ON(qc->dev->cdb_len < 12);
+-
+- ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
+- ata_altstatus(ap); /* flush */
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_ATAPI:
+- ap->hsm_task_state = HSM_ST;
+- break;
+- case ATA_PROT_ATAPI_NODATA:
+- ap->hsm_task_state = HSM_ST_LAST;
+- break;
+- case ATA_PROT_ATAPI_DMA:
+- ap->hsm_task_state = HSM_ST_LAST;
+- /* initiate bmdma */
+- ap->ops->bmdma_start(qc);
+- break;
+- }
+-}
+-
+-/**
+- * __atapi_pio_bytes - Transfer data from/to the ATAPI device.
+- * @qc: Command on going
+- * @bytes: number of bytes
+- *
+- * Transfer Transfer data from/to the ATAPI device.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- *
+- */
+-
+-static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
+-{
+- int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+- struct scatterlist *sg = qc->__sg;
+- struct ata_port *ap = qc->ap;
+- struct page *page;
+- unsigned char *buf;
+- unsigned int offset, count;
+-
+- if (qc->curbytes + bytes >= qc->nbytes)
+- ap->hsm_task_state = HSM_ST_LAST;
+-
+-next_sg:
+- if (unlikely(qc->cursg >= qc->n_elem)) {
+- /*
+- * The end of qc->sg is reached and the device expects
+- * more data to transfer. In order not to overrun qc->sg
+- * and fulfill length specified in the byte count register,
+- * - for read case, discard trailing data from the device
+- * - for write case, padding zero data to the device
+- */
+- u16 pad_buf[1] = { 0 };
+- unsigned int words = bytes >> 1;
+- unsigned int i;
+-
+- if (words) /* warning if bytes > 1 */
+- ata_dev_printk(qc->dev, KERN_WARNING,
+- "%u bytes trailing data\n", bytes);
+-
+- for (i = 0; i < words; i++)
+- ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write);
+-
+- ap->hsm_task_state = HSM_ST_LAST;
+- return;
+- }
+-
+- sg = &qc->__sg[qc->cursg];
+-
+- page = sg->page;
+- offset = sg->offset + qc->cursg_ofs;
+-
+- /* get the current page and offset */
+- page = nth_page(page, (offset >> PAGE_SHIFT));
+- offset %= PAGE_SIZE;
+-
+- /* don't overrun current sg */
+- count = min(sg->length - qc->cursg_ofs, bytes);
+-
+- /* don't cross page boundaries */
+- count = min(count, (unsigned int)PAGE_SIZE - offset);
+-
+- DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+-
+- if (PageHighMem(page)) {
+- unsigned long flags;
+-
+- /* FIXME: use bounce buffer */
+- local_irq_save(flags);
+- buf = kmap_atomic(page, KM_IRQ0);
+-
+- /* do the actual data transfer */
+- ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+-
+- kunmap_atomic(buf, KM_IRQ0);
+- local_irq_restore(flags);
+- } else {
+- buf = page_address(page);
+- ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+- }
+-
+- bytes -= count;
+- qc->curbytes += count;
+- qc->cursg_ofs += count;
+-
+- if (qc->cursg_ofs == sg->length) {
+- qc->cursg++;
+- qc->cursg_ofs = 0;
+- }
+-
+- if (bytes)
+- goto next_sg;
+-}
+-
+-/**
+- * atapi_pio_bytes - Transfer data from/to the ATAPI device.
+- * @qc: Command on going
+- *
+- * Transfer Transfer data from/to the ATAPI device.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-static void atapi_pio_bytes(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct ata_device *dev = qc->dev;
+- unsigned int ireason, bc_lo, bc_hi, bytes;
+- int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
+-
+- /* Abuse qc->result_tf for temp storage of intermediate TF
+- * here to save some kernel stack usage.
+- * For normal completion, qc->result_tf is not relevant. For
+- * error, qc->result_tf is later overwritten by ata_qc_complete().
+- * So, the correctness of qc->result_tf is not affected.
+- */
+- ap->ops->tf_read(ap, &qc->result_tf);
+- ireason = qc->result_tf.nsect;
+- bc_lo = qc->result_tf.lbam;
+- bc_hi = qc->result_tf.lbah;
+- bytes = (bc_hi << 8) | bc_lo;
+-
+- /* shall be cleared to zero, indicating xfer of data */
+- if (ireason & (1 << 0))
+- goto err_out;
+-
+- /* make sure transfer direction matches expected */
+- i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
+- if (do_write != i_write)
+- goto err_out;
+-
+- VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+-
+- __atapi_pio_bytes(qc, bytes);
+-
+- return;
+-
+-err_out:
+- ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n");
+- qc->err_mask |= AC_ERR_HSM;
+- ap->hsm_task_state = HSM_ST_ERR;
+-}
+-
+-/**
+- * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue.
+- * @ap: the target ata_port
+- * @qc: qc on going
+- *
+- * RETURNS:
+- * 1 if ok in workqueue, 0 otherwise.
+- */
+-
+-static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
+-{
+- if (qc->tf.flags & ATA_TFLAG_POLLING)
+- return 1;
+-
+- if (ap->hsm_task_state == HSM_ST_FIRST) {
+- if (qc->tf.protocol == ATA_PROT_PIO &&
+- (qc->tf.flags & ATA_TFLAG_WRITE))
+- return 1;
+-
+- if (is_atapi_taskfile(&qc->tf) &&
+- !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+- return 1;
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * ata_hsm_qc_complete - finish a qc running on standard HSM
+- * @qc: Command to complete
+- * @in_wq: 1 if called from workqueue, 0 otherwise
+- *
+- * Finish @qc which is running on standard HSM.
+- *
+- * LOCKING:
+- * If @in_wq is zero, spin_lock_irqsave(host_set lock).
+- * Otherwise, none on entry and grabs host lock.
+- */
+-static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
+-{
+- struct ata_port *ap = qc->ap;
+- unsigned long flags;
+-
+- if (ap->ops->error_handler) {
+- if (in_wq) {
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* EH might have kicked in while host_set lock
+- * is released.
+- */
+- qc = ata_qc_from_tag(ap, qc->tag);
+- if (qc) {
+- if (likely(!(qc->err_mask & AC_ERR_HSM))) {
+- ata_irq_on(ap);
+- ata_qc_complete(qc);
+- } else
+- ata_port_freeze(ap);
+- }
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+- } else {
+- if (likely(!(qc->err_mask & AC_ERR_HSM)))
+- ata_qc_complete(qc);
+- else
+- ata_port_freeze(ap);
+- }
+- } else {
+- if (in_wq) {
+- spin_lock_irqsave(ap->lock, flags);
+- ata_irq_on(ap);
+- ata_qc_complete(qc);
+- spin_unlock_irqrestore(ap->lock, flags);
+- } else
+- ata_qc_complete(qc);
+- }
+-
+- ata_altstatus(ap); /* flush */
+-}
+-
+-/**
+- * ata_hsm_move - move the HSM to the next state.
+- * @ap: the target ata_port
+- * @qc: qc on going
+- * @status: current device status
+- * @in_wq: 1 if called from workqueue, 0 otherwise
+- *
+- * RETURNS:
+- * 1 when poll next status needed, 0 otherwise.
+- */
+-int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+- u8 status, int in_wq)
+-{
+- unsigned long flags = 0;
+- int poll_next;
+-
+- WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
+-
+- /* Make sure ata_qc_issue_prot() does not throw things
+- * like DMA polling into the workqueue. Notice that
+- * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
+- */
+- WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
+-
+-fsm_start:
+- DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
+- ap->id, qc->tf.protocol, ap->hsm_task_state, status);
+-
+- switch (ap->hsm_task_state) {
+- case HSM_ST_FIRST:
+- /* Send first data block or PACKET CDB */
+-
+- /* If polling, we will stay in the work queue after
+- * sending the data. Otherwise, interrupt handler
+- * takes over after sending the data.
+- */
+- poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
+-
+- /* check device status */
+- if (unlikely((status & ATA_DRQ) == 0)) {
+- /* handle BSY=0, DRQ=0 as error */
+- if (likely(status & (ATA_ERR | ATA_DF)))
+- /* device stops HSM for abort/error */
+- qc->err_mask |= AC_ERR_DEV;
+- else
+- /* HSM violation. Let EH handle this */
+- qc->err_mask |= AC_ERR_HSM;
+-
+- ap->hsm_task_state = HSM_ST_ERR;
+- goto fsm_start;
+- }
+-
+- /* Device should not ask for data transfer (DRQ=1)
+- * when it finds something wrong.
+- * We ignore DRQ here and stop the HSM by
+- * changing hsm_task_state to HSM_ST_ERR and
+- * let the EH abort the command or reset the device.
+- */
+- if (unlikely(status & (ATA_ERR | ATA_DF))) {
+- printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
+- ap->id, status);
+- qc->err_mask |= AC_ERR_HSM;
+- ap->hsm_task_state = HSM_ST_ERR;
+- goto fsm_start;
+- }
+-
+- /* Send the CDB (atapi) or the first data block (ata pio out).
+- * During the state transition, interrupt handler shouldn't
+- * be invoked before the data transfer is complete and
+- * hsm_task_state is changed. Hence, the following locking.
+- */
+- if (in_wq)
+- spin_lock_irqsave(ap->lock, flags);
+-
+- if (qc->tf.protocol == ATA_PROT_PIO) {
+- /* PIO data out protocol.
+- * send first data block.
+- */
+-
+- /* ata_pio_sectors() might change the state
+- * to HSM_ST_LAST. so, the state is changed here
+- * before ata_pio_sectors().
+- */
+- ap->hsm_task_state = HSM_ST;
+- ata_pio_sectors(qc);
+- ata_altstatus(ap); /* flush */
+- } else
+- /* send CDB */
+- atapi_send_cdb(ap, qc);
+-
+- if (in_wq)
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* if polling, ata_pio_task() handles the rest.
+- * otherwise, interrupt handler takes over from here.
+- */
+- break;
+-
+- case HSM_ST:
+- /* complete command or read/write the data register */
+- if (qc->tf.protocol == ATA_PROT_ATAPI) {
+- /* ATAPI PIO protocol */
+- if ((status & ATA_DRQ) == 0) {
+- /* No more data to transfer or device error.
+- * Device error will be tagged in HSM_ST_LAST.
+- */
+- ap->hsm_task_state = HSM_ST_LAST;
+- goto fsm_start;
+- }
+-
+- /* Device should not ask for data transfer (DRQ=1)
+- * when it finds something wrong.
+- * We ignore DRQ here and stop the HSM by
+- * changing hsm_task_state to HSM_ST_ERR and
+- * let the EH abort the command or reset the device.
+- */
+- if (unlikely(status & (ATA_ERR | ATA_DF))) {
+- printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
+- ap->id, status);
+- qc->err_mask |= AC_ERR_HSM;
+- ap->hsm_task_state = HSM_ST_ERR;
+- goto fsm_start;
+- }
+-
+- atapi_pio_bytes(qc);
+-
+- if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
+- /* bad ireason reported by device */
+- goto fsm_start;
+-
+- } else {
+- /* ATA PIO protocol */
+- if (unlikely((status & ATA_DRQ) == 0)) {
+- /* handle BSY=0, DRQ=0 as error */
+- if (likely(status & (ATA_ERR | ATA_DF)))
+- /* device stops HSM for abort/error */
+- qc->err_mask |= AC_ERR_DEV;
+- else
+- /* HSM violation. Let EH handle this */
+- qc->err_mask |= AC_ERR_HSM;
+-
+- ap->hsm_task_state = HSM_ST_ERR;
+- goto fsm_start;
+- }
+-
+- /* For PIO reads, some devices may ask for
+- * data transfer (DRQ=1) alone with ERR=1.
+- * We respect DRQ here and transfer one
+- * block of junk data before changing the
+- * hsm_task_state to HSM_ST_ERR.
+- *
+- * For PIO writes, ERR=1 DRQ=1 doesn't make
+- * sense since the data block has been
+- * transferred to the device.
+- */
+- if (unlikely(status & (ATA_ERR | ATA_DF))) {
+- /* data might be corrputed */
+- qc->err_mask |= AC_ERR_DEV;
+-
+- if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+- ata_pio_sectors(qc);
+- ata_altstatus(ap);
+- status = ata_wait_idle(ap);
+- }
+-
+- if (status & (ATA_BUSY | ATA_DRQ))
+- qc->err_mask |= AC_ERR_HSM;
+-
+- /* ata_pio_sectors() might change the
+- * state to HSM_ST_LAST. so, the state
+- * is changed after ata_pio_sectors().
+- */
+- ap->hsm_task_state = HSM_ST_ERR;
+- goto fsm_start;
+- }
+-
+- ata_pio_sectors(qc);
+-
+- if (ap->hsm_task_state == HSM_ST_LAST &&
+- (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+- /* all data read */
+- ata_altstatus(ap);
+- status = ata_wait_idle(ap);
+- goto fsm_start;
+- }
+- }
+-
+- ata_altstatus(ap); /* flush */
+- poll_next = 1;
+- break;
+-
+- case HSM_ST_LAST:
+- if (unlikely(!ata_ok(status))) {
+- qc->err_mask |= __ac_err_mask(status);
+- ap->hsm_task_state = HSM_ST_ERR;
+- goto fsm_start;
+- }
+-
+- /* no more data to transfer */
+- DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
+- ap->id, qc->dev->devno, status);
+-
+- WARN_ON(qc->err_mask);
+-
+- ap->hsm_task_state = HSM_ST_IDLE;
+-
+- /* complete taskfile transaction */
+- ata_hsm_qc_complete(qc, in_wq);
+-
+- poll_next = 0;
+- break;
+-
+- case HSM_ST_ERR:
+- /* make sure qc->err_mask is available to
+- * know what's wrong and recover
+- */
+- WARN_ON(qc->err_mask == 0);
+-
+- ap->hsm_task_state = HSM_ST_IDLE;
+-
+- /* complete taskfile transaction */
+- ata_hsm_qc_complete(qc, in_wq);
+-
+- poll_next = 0;
+- break;
+- default:
+- poll_next = 0;
+- BUG();
+- }
+-
+- return poll_next;
+-}
+-
+-static void ata_pio_task(void *_data)
+-{
+- struct ata_queued_cmd *qc = _data;
+- struct ata_port *ap = qc->ap;
+- u8 status;
+- int poll_next;
+-
+-fsm_start:
+- WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
+-
+- /*
+- * This is purely heuristic. This is a fast path.
+- * Sometimes when we enter, BSY will be cleared in
+- * a chk-status or two. If not, the drive is probably seeking
+- * or something. Snooze for a couple msecs, then
+- * chk-status again. If still busy, queue delayed work.
+- */
+- status = ata_busy_wait(ap, ATA_BUSY, 5);
+- if (status & ATA_BUSY) {
+- msleep(2);
+- status = ata_busy_wait(ap, ATA_BUSY, 10);
+- if (status & ATA_BUSY) {
+- ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
+- return;
+- }
+- }
+-
+- /* move the HSM */
+- poll_next = ata_hsm_move(ap, qc, status, 1);
+-
+- /* another command or interrupt handler
+- * may be running at this point.
+- */
+- if (poll_next)
+- goto fsm_start;
+-}
+-
+-/**
+- * ata_qc_new - Request an available ATA command, for queueing
+- * @ap: Port associated with device @dev
+- * @dev: Device from whom we request an available command structure
+- *
+- * LOCKING:
+- * None.
+- */
+-
+-static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+-{
+- struct ata_queued_cmd *qc = NULL;
+- unsigned int i;
+-
+- /* no command while frozen */
+- if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
+- return NULL;
+-
+- /* the last tag is reserved for internal command. */
+- for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
+- if (!test_and_set_bit(i, &ap->qc_allocated)) {
+- qc = __ata_qc_from_tag(ap, i);
+- break;
+- }
+-
+- if (qc)
+- qc->tag = i;
+-
+- return qc;
+-}
+-
+-/**
+- * ata_qc_new_init - Request an available ATA command, and initialize it
+- * @dev: Device from whom we request an available command structure
+- *
+- * LOCKING:
+- * None.
+- */
+-
+-struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
+-{
+- struct ata_port *ap = dev->ap;
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_new(ap);
+- if (qc) {
+- qc->scsicmd = NULL;
+- qc->ap = ap;
+- qc->dev = dev;
+-
+- ata_qc_reinit(qc);
+- }
+-
+- return qc;
+-}
+-
+-/**
+- * ata_qc_free - free unused ata_queued_cmd
+- * @qc: Command to complete
+- *
+- * Designed to free unused ata_queued_cmd object
+- * in case something prevents using it.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_qc_free(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- unsigned int tag;
+-
+- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+-
+- qc->flags = 0;
+- tag = qc->tag;
+- if (likely(ata_tag_valid(tag))) {
+- qc->tag = ATA_TAG_POISON;
+- clear_bit(tag, &ap->qc_allocated);
+- }
+-}
+-
+-void __ata_qc_complete(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+-
+- if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
+- ata_sg_clean(qc);
+-
+- /* command should be marked inactive atomically with qc completion */
+- if (qc->tf.protocol == ATA_PROT_NCQ)
+- ap->sactive &= ~(1 << qc->tag);
+- else
+- ap->active_tag = ATA_TAG_POISON;
+-
+- /* atapi: mark qc as inactive to prevent the interrupt handler
+- * from completing the command twice later, before the error handler
+- * is called. (when rc != 0 and atapi request sense is needed)
+- */
+- qc->flags &= ~ATA_QCFLAG_ACTIVE;
+- ap->qc_active &= ~(1 << qc->tag);
+-
+- /* call completion callback */
+- qc->complete_fn(qc);
+-}
+-
+-/**
+- * ata_qc_complete - Complete an active ATA command
+- * @qc: Command to complete
+- * @err_mask: ATA Status register contents
+- *
+- * Indicate to the mid and upper layers that an ATA
+- * command has completed, with either an ok or not-ok status.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_qc_complete(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- /* XXX: New EH and old EH use different mechanisms to
+- * synchronize EH with regular execution path.
+- *
+- * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
+- * Normal execution path is responsible for not accessing a
+- * failed qc. libata core enforces the rule by returning NULL
+- * from ata_qc_from_tag() for failed qcs.
+- *
+- * Old EH depends on ata_qc_complete() nullifying completion
+- * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
+- * not synchronize with interrupt handler. Only PIO task is
+- * taken care of.
+- */
+- if (ap->ops->error_handler) {
+- WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
+-
+- if (unlikely(qc->err_mask))
+- qc->flags |= ATA_QCFLAG_FAILED;
+-
+- if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+- if (!ata_tag_internal(qc->tag)) {
+- /* always fill result TF for failed qc */
+- ap->ops->tf_read(ap, &qc->result_tf);
+- ata_qc_schedule_eh(qc);
+- return;
+- }
+- }
+-
+- /* read result TF if requested */
+- if (qc->flags & ATA_QCFLAG_RESULT_TF)
+- ap->ops->tf_read(ap, &qc->result_tf);
+-
+- __ata_qc_complete(qc);
+- } else {
+- if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
+- return;
+-
+- /* read result TF if failed or requested */
+- if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
+- ap->ops->tf_read(ap, &qc->result_tf);
+-
+- __ata_qc_complete(qc);
+- }
+-}
+-
+-/**
+- * ata_qc_complete_multiple - Complete multiple qcs successfully
+- * @ap: port in question
+- * @qc_active: new qc_active mask
+- * @finish_qc: LLDD callback invoked before completing a qc
+- *
+- * Complete in-flight commands. This functions is meant to be
+- * called from low-level driver's interrupt routine to complete
+- * requests normally. ap->qc_active and @qc_active is compared
+- * and commands are completed accordingly.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Number of completed commands on success, -errno otherwise.
+- */
+-int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
+- void (*finish_qc)(struct ata_queued_cmd *))
+-{
+- int nr_done = 0;
+- u32 done_mask;
+- int i;
+-
+- done_mask = ap->qc_active ^ qc_active;
+-
+- if (unlikely(done_mask & qc_active)) {
+- ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
+- "(%08x->%08x)\n", ap->qc_active, qc_active);
+- return -EINVAL;
+- }
+-
+- for (i = 0; i < ATA_MAX_QUEUE; i++) {
+- struct ata_queued_cmd *qc;
+-
+- if (!(done_mask & (1 << i)))
+- continue;
+-
+- if ((qc = ata_qc_from_tag(ap, i))) {
+- if (finish_qc)
+- finish_qc(qc);
+- ata_qc_complete(qc);
+- nr_done++;
+- }
+- }
+-
+- return nr_done;
+-}
+-
+-static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_NCQ:
+- case ATA_PROT_DMA:
+- case ATA_PROT_ATAPI_DMA:
+- return 1;
+-
+- case ATA_PROT_ATAPI:
+- case ATA_PROT_PIO:
+- if (ap->flags & ATA_FLAG_PIO_DMA)
+- return 1;
+-
+- /* fall through */
+-
+- default:
+- return 0;
+- }
+-
+- /* never reached */
+-}
+-
+-/**
+- * ata_qc_issue - issue taskfile to device
+- * @qc: command to issue to device
+- *
+- * Prepare an ATA command to submission to device.
+- * This includes mapping the data into a DMA-able
+- * area, filling in the S/G table, and finally
+- * writing the taskfile to hardware, starting the command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_qc_issue(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- /* Make sure only one non-NCQ command is outstanding. The
+- * check is skipped for old EH because it reuses active qc to
+- * request ATAPI sense.
+- */
+- WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+-
+- if (qc->tf.protocol == ATA_PROT_NCQ) {
+- WARN_ON(ap->sactive & (1 << qc->tag));
+- ap->sactive |= 1 << qc->tag;
+- } else {
+- WARN_ON(ap->sactive);
+- ap->active_tag = qc->tag;
+- }
+-
+- qc->flags |= ATA_QCFLAG_ACTIVE;
+- ap->qc_active |= 1 << qc->tag;
+-
+- if (ata_should_dma_map(qc)) {
+- if (qc->flags & ATA_QCFLAG_SG) {
+- if (ata_sg_setup(qc))
+- goto sg_err;
+- } else if (qc->flags & ATA_QCFLAG_SINGLE) {
+- if (ata_sg_setup_one(qc))
+- goto sg_err;
+- }
+- } else {
+- qc->flags &= ~ATA_QCFLAG_DMAMAP;
+- }
+-
+- ap->ops->qc_prep(qc);
+-
+- qc->err_mask |= ap->ops->qc_issue(qc);
+- if (unlikely(qc->err_mask))
+- goto err;
+- return;
+-
+-sg_err:
+- qc->flags &= ~ATA_QCFLAG_DMAMAP;
+- qc->err_mask |= AC_ERR_SYSTEM;
+-err:
+- ata_qc_complete(qc);
+-}
+-
+-/**
+- * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+- * @qc: command to issue to device
+- *
+- * Using various libata functions and hooks, this function
+- * starts an ATA command. ATA commands are grouped into
+- * classes called "protocols", and issuing each type of protocol
+- * is slightly different.
+- *
+- * May be used as the qc_issue() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, AC_ERR_* mask on failure
+- */
+-
+-unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- /* Use polling pio if the LLD doesn't handle
+- * interrupt driven pio and atapi CDB interrupt.
+- */
+- if (ap->flags & ATA_FLAG_PIO_POLLING) {
+- switch (qc->tf.protocol) {
+- case ATA_PROT_PIO:
+- case ATA_PROT_ATAPI:
+- case ATA_PROT_ATAPI_NODATA:
+- qc->tf.flags |= ATA_TFLAG_POLLING;
+- break;
+- case ATA_PROT_ATAPI_DMA:
+- if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
+- /* see ata_dma_blacklisted() */
+- BUG();
+- break;
+- default:
+- break;
+- }
+- }
+-
+- /* select the device */
+- ata_dev_select(ap, qc->dev->devno, 1, 0);
+-
+- /* start the command */
+- switch (qc->tf.protocol) {
+- case ATA_PROT_NODATA:
+- if (qc->tf.flags & ATA_TFLAG_POLLING)
+- ata_qc_set_polling(qc);
+-
+- ata_tf_to_host(ap, &qc->tf);
+- ap->hsm_task_state = HSM_ST_LAST;
+-
+- if (qc->tf.flags & ATA_TFLAG_POLLING)
+- ata_port_queue_task(ap, ata_pio_task, qc, 0);
+-
+- break;
+-
+- case ATA_PROT_DMA:
+- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+-
+- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+- ap->ops->bmdma_setup(qc); /* set up bmdma */
+- ap->ops->bmdma_start(qc); /* initiate bmdma */
+- ap->hsm_task_state = HSM_ST_LAST;
+- break;
+-
+- case ATA_PROT_PIO:
+- if (qc->tf.flags & ATA_TFLAG_POLLING)
+- ata_qc_set_polling(qc);
+-
+- ata_tf_to_host(ap, &qc->tf);
+-
+- if (qc->tf.flags & ATA_TFLAG_WRITE) {
+- /* PIO data out protocol */
+- ap->hsm_task_state = HSM_ST_FIRST;
+- ata_port_queue_task(ap, ata_pio_task, qc, 0);
+-
+- /* always send first data block using
+- * the ata_pio_task() codepath.
+- */
+- } else {
+- /* PIO data in protocol */
+- ap->hsm_task_state = HSM_ST;
+-
+- if (qc->tf.flags & ATA_TFLAG_POLLING)
+- ata_port_queue_task(ap, ata_pio_task, qc, 0);
+-
+- /* if polling, ata_pio_task() handles the rest.
+- * otherwise, interrupt handler takes over from here.
+- */
+- }
+-
+- break;
+-
+- case ATA_PROT_ATAPI:
+- case ATA_PROT_ATAPI_NODATA:
+- if (qc->tf.flags & ATA_TFLAG_POLLING)
+- ata_qc_set_polling(qc);
+-
+- ata_tf_to_host(ap, &qc->tf);
+-
+- ap->hsm_task_state = HSM_ST_FIRST;
+-
+- /* send cdb by polling if no cdb interrupt */
+- if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+- (qc->tf.flags & ATA_TFLAG_POLLING))
+- ata_port_queue_task(ap, ata_pio_task, qc, 0);
+- break;
+-
+- case ATA_PROT_ATAPI_DMA:
+- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+-
+- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+- ap->ops->bmdma_setup(qc); /* set up bmdma */
+- ap->hsm_task_state = HSM_ST_FIRST;
+-
+- /* send cdb by polling if no cdb interrupt */
+- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+- ata_port_queue_task(ap, ata_pio_task, qc, 0);
+- break;
+-
+- default:
+- WARN_ON(1);
+- return AC_ERR_SYSTEM;
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * ata_host_intr - Handle host interrupt for given (port, task)
+- * @ap: Port on which interrupt arrived (possibly...)
+- * @qc: Taskfile currently active in engine
+- *
+- * Handle host interrupt for given queued command. Currently,
+- * only DMA interrupts are handled. All other commands are
+- * handled via polling with interrupts disabled (nIEN bit).
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * One if interrupt was handled, zero if not (shared irq).
+- */
+-
+-inline unsigned int ata_host_intr (struct ata_port *ap,
+- struct ata_queued_cmd *qc)
+-{
+- u8 status, host_stat = 0;
+-
+- VPRINTK("ata%u: protocol %d task_state %d\n",
+- ap->id, qc->tf.protocol, ap->hsm_task_state);
+-
+- /* Check whether we are expecting interrupt in this state */
+- switch (ap->hsm_task_state) {
+- case HSM_ST_FIRST:
+- /* Some pre-ATAPI-4 devices assert INTRQ
+- * at this state when ready to receive CDB.
+- */
+-
+- /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+- * The flag was turned on only for atapi devices.
+- * No need to check is_atapi_taskfile(&qc->tf) again.
+- */
+- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+- goto idle_irq;
+- break;
+- case HSM_ST_LAST:
+- if (qc->tf.protocol == ATA_PROT_DMA ||
+- qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+- /* check status of DMA engine */
+- host_stat = ap->ops->bmdma_status(ap);
+- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+-
+- /* if it's not our irq... */
+- if (!(host_stat & ATA_DMA_INTR))
+- goto idle_irq;
+-
+- /* before we do anything else, clear DMA-Start bit */
+- ap->ops->bmdma_stop(qc);
+-
+- if (unlikely(host_stat & ATA_DMA_ERR)) {
+- /* error when transfering data to/from memory */
+- qc->err_mask |= AC_ERR_HOST_BUS;
+- ap->hsm_task_state = HSM_ST_ERR;
+- }
+- }
+- break;
+- case HSM_ST:
+- break;
+- default:
+- goto idle_irq;
+- }
+-
+- /* check altstatus */
+- status = ata_altstatus(ap);
+- if (status & ATA_BUSY)
+- goto idle_irq;
+-
+- /* check main status, clearing INTRQ */
+- status = ata_chk_status(ap);
+- if (unlikely(status & ATA_BUSY))
+- goto idle_irq;
+-
+- /* ack bmdma irq events */
+- ap->ops->irq_clear(ap);
+-
+- ata_hsm_move(ap, qc, status, 0);
+- return 1; /* irq handled */
+-
+-idle_irq:
+- ap->stats.idle_irq++;
+-
+-#ifdef ATA_IRQ_TRAP
+- if ((ap->stats.idle_irq % 1000) == 0) {
+- ata_irq_ack(ap, 0); /* debug trap */
+- ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+- return 1;
+- }
+-#endif
+- return 0; /* irq not handled */
+-}
+-
+-/**
+- * ata_interrupt - Default ATA host interrupt handler
+- * @irq: irq line (unused)
+- * @dev_instance: pointer to our ata_host_set information structure
+- * @regs: unused
+- *
+- * Default interrupt handler for PCI IDE devices. Calls
+- * ata_host_intr() for each port that is not disabled.
+- *
+- * LOCKING:
+- * Obtains host_set lock during operation.
+- *
+- * RETURNS:
+- * IRQ_NONE or IRQ_HANDLED.
+- */
+-
+-irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- unsigned int i;
+- unsigned int handled = 0;
+- unsigned long flags;
+-
+- /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+- spin_lock_irqsave(&host_set->lock, flags);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap;
+-
+- ap = host_set->ports[i];
+- if (ap &&
+- !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+- (qc->flags & ATA_QCFLAG_ACTIVE))
+- handled |= ata_host_intr(ap, qc);
+- }
+- }
+-
+- spin_unlock_irqrestore(&host_set->lock, flags);
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-/**
+- * sata_scr_valid - test whether SCRs are accessible
+- * @ap: ATA port to test SCR accessibility for
+- *
+- * Test whether SCRs are accessible for @ap.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 1 if SCRs are accessible, 0 otherwise.
+- */
+-int sata_scr_valid(struct ata_port *ap)
+-{
+- return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
+-}
+-
+-/**
+- * sata_scr_read - read SCR register of the specified port
+- * @ap: ATA port to read SCR for
+- * @reg: SCR to read
+- * @val: Place to store read value
+- *
+- * Read SCR register @reg of @ap into *@val. This function is
+- * guaranteed to succeed if the cable type of the port is SATA
+- * and the port implements ->scr_read.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 0 on success, negative errno on failure.
+- */
+-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+-{
+- if (sata_scr_valid(ap)) {
+- *val = ap->ops->scr_read(ap, reg);
+- return 0;
+- }
+- return -EOPNOTSUPP;
+-}
+-
+-/**
+- * sata_scr_write - write SCR register of the specified port
+- * @ap: ATA port to write SCR for
+- * @reg: SCR to write
+- * @val: value to write
+- *
+- * Write @val to SCR register @reg of @ap. This function is
+- * guaranteed to succeed if the cable type of the port is SATA
+- * and the port implements ->scr_read.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 0 on success, negative errno on failure.
+- */
+-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+-{
+- if (sata_scr_valid(ap)) {
+- ap->ops->scr_write(ap, reg, val);
+- return 0;
+- }
+- return -EOPNOTSUPP;
+-}
+-
+-/**
+- * sata_scr_write_flush - write SCR register of the specified port and flush
+- * @ap: ATA port to write SCR for
+- * @reg: SCR to write
+- * @val: value to write
+- *
+- * This function is identical to sata_scr_write() except that this
+- * function performs flush after writing to the register.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 0 on success, negative errno on failure.
+- */
+-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+-{
+- if (sata_scr_valid(ap)) {
+- ap->ops->scr_write(ap, reg, val);
+- ap->ops->scr_read(ap, reg);
+- return 0;
+- }
+- return -EOPNOTSUPP;
+-}
+-
+-/**
+- * ata_port_online - test whether the given port is online
+- * @ap: ATA port to test
+- *
+- * Test whether @ap is online. Note that this function returns 0
+- * if online status of @ap cannot be obtained, so
+- * ata_port_online(ap) != !ata_port_offline(ap).
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 1 if the port online status is available and online.
+- */
+-int ata_port_online(struct ata_port *ap)
+-{
+- u32 sstatus;
+-
+- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+- return 1;
+- return 0;
+-}
+-
+-/**
+- * ata_port_offline - test whether the given port is offline
+- * @ap: ATA port to test
+- *
+- * Test whether @ap is offline. Note that this function returns
+- * 0 if offline status of @ap cannot be obtained, so
+- * ata_port_online(ap) != !ata_port_offline(ap).
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * 1 if the port offline status is available and offline.
+- */
+-int ata_port_offline(struct ata_port *ap)
+-{
+- u32 sstatus;
+-
+- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+- return 1;
+- return 0;
+-}
+-
+-int ata_flush_cache(struct ata_device *dev)
+-{
+- unsigned int err_mask;
+- u8 cmd;
+-
+- if (!ata_try_flush_cache(dev))
+- return 0;
+-
+- if (ata_id_has_flush_ext(dev->id))
+- cmd = ATA_CMD_FLUSH_EXT;
+- else
+- cmd = ATA_CMD_FLUSH;
+-
+- err_mask = ata_do_simple_cmd(dev, cmd);
+- if (err_mask) {
+- ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+- return -EIO;
+- }
+-
+- return 0;
+-}
+-
+-static int ata_host_set_request_pm(struct ata_host_set *host_set,
+- pm_message_t mesg, unsigned int action,
+- unsigned int ehi_flags, int wait)
+-{
+- unsigned long flags;
+- int i, rc;
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap = host_set->ports[i];
+-
+- /* Previous resume operation might still be in
+- * progress. Wait for PM_PENDING to clear.
+- */
+- if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+- ata_port_wait_eh(ap);
+- WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+- }
+-
+- /* request PM ops to EH */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- ap->pm_mesg = mesg;
+- if (wait) {
+- rc = 0;
+- ap->pm_result = &rc;
+- }
+-
+- ap->pflags |= ATA_PFLAG_PM_PENDING;
+- ap->eh_info.action |= action;
+- ap->eh_info.flags |= ehi_flags;
+-
+- ata_port_schedule_eh(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* wait and check result */
+- if (wait) {
+- ata_port_wait_eh(ap);
+- WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+- if (rc)
+- return rc;
+- }
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * ata_host_set_suspend - suspend host_set
+- * @host_set: host_set to suspend
+- * @mesg: PM message
+- *
+- * Suspend @host_set. Actual operation is performed by EH. This
+- * function requests EH to perform PM operations and waits for EH
+- * to finish.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno on failure.
+- */
+-int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
+-{
+- int i, j, rc;
+-
+- rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
+- if (rc)
+- goto fail;
+-
+- /* EH is quiescent now. Fail if we have any ready device.
+- * This happens if hotplug occurs between completion of device
+- * suspension and here.
+- */
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap = host_set->ports[i];
+-
+- for (j = 0; j < ATA_MAX_DEVICES; j++) {
+- struct ata_device *dev = &ap->device[j];
+-
+- if (ata_dev_ready(dev)) {
+- ata_port_printk(ap, KERN_WARNING,
+- "suspend failed, device %d "
+- "still active\n", dev->devno);
+- rc = -EBUSY;
+- goto fail;
+- }
+- }
+- }
+-
+- host_set->dev->power.power_state = mesg;
+- return 0;
+-
+- fail:
+- ata_host_set_resume(host_set);
+- return rc;
+-}
+-
+-/**
+- * ata_host_set_resume - resume host_set
+- * @host_set: host_set to resume
+- *
+- * Resume @host_set. Actual operation is performed by EH. This
+- * function requests EH to perform PM operations and returns.
+- * Note that all resume operations are performed parallely.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-void ata_host_set_resume(struct ata_host_set *host_set)
+-{
+- ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
+- ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+- host_set->dev->power.power_state = PMSG_ON;
+-}
+-
+-/**
+- * ata_port_start - Set port up for dma.
+- * @ap: Port to initialize
+- *
+- * Called just after data structures for each port are
+- * initialized. Allocates space for PRD table.
+- *
+- * May be used as the port_start() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-int ata_port_start (struct ata_port *ap)
+-{
+- struct device *dev = ap->dev;
+- int rc;
+-
+- ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+- if (!ap->prd)
+- return -ENOMEM;
+-
+- rc = ata_pad_alloc(ap, dev);
+- if (rc) {
+- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+- return rc;
+- }
+-
+- DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
+-
+- return 0;
+-}
+-
+-
+-/**
+- * ata_port_stop - Undo ata_port_start()
+- * @ap: Port to shut down
+- *
+- * Frees the PRD table.
+- *
+- * May be used as the port_stop() entry in ata_port_operations.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-
+-void ata_port_stop (struct ata_port *ap)
+-{
+- struct device *dev = ap->dev;
+-
+- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+- ata_pad_free(ap, dev);
+-}
+-
+-void ata_host_stop (struct ata_host_set *host_set)
+-{
+- if (host_set->mmio_base)
+- iounmap(host_set->mmio_base);
+-}
+-
+-/**
+- * ata_dev_init - Initialize an ata_device structure
+- * @dev: Device structure to initialize
+- *
+- * Initialize @dev in preparation for probing.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-void ata_dev_init(struct ata_device *dev)
+-{
+- struct ata_port *ap = dev->ap;
+- unsigned long flags;
+-
+- /* SATA spd limit is bound to the first device */
+- ap->sata_spd_limit = ap->hw_sata_spd_limit;
+-
+- /* High bits of dev->flags are used to record warm plug
+- * requests which occur asynchronously. Synchronize using
+- * host_set lock.
+- */
+- spin_lock_irqsave(ap->lock, flags);
+- dev->flags &= ~ATA_DFLAG_INIT_MASK;
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
+- sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
+- dev->pio_mask = UINT_MAX;
+- dev->mwdma_mask = UINT_MAX;
+- dev->udma_mask = UINT_MAX;
+-}
+-
+-/**
+- * ata_host_init - Initialize an ata_port structure
+- * @ap: Structure to initialize
+- * @host: associated SCSI mid-layer structure
+- * @host_set: Collection of hosts to which @ap belongs
+- * @ent: Probe information provided by low-level driver
+- * @port_no: Port number associated with this ata_port
+- *
+- * Initialize a new ata_port structure, and its associated
+- * scsi_host.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
+- struct ata_host_set *host_set,
+- const struct ata_probe_ent *ent, unsigned int port_no)
+-{
+- unsigned int i;
+-
+- host->max_id = 16;
+- host->max_lun = 1;
+- host->max_channel = 1;
+- host->unique_id = ata_unique_id++;
+- host->max_cmd_len = 12;
+-
+- ap->lock = &host_set->lock;
+- ap->flags = ATA_FLAG_DISABLED;
+- ap->id = host->unique_id;
+- ap->host = host;
+- ap->ctl = ATA_DEVCTL_OBS;
+- ap->host_set = host_set;
+- ap->dev = ent->dev;
+- ap->port_no = port_no;
+- ap->hard_port_no =
+- ent->legacy_mode ? ent->hard_port_no : port_no;
+- ap->pio_mask = ent->pio_mask;
+- ap->mwdma_mask = ent->mwdma_mask;
+- ap->udma_mask = ent->udma_mask;
+- ap->flags |= ent->host_flags;
+- ap->ops = ent->port_ops;
+- ap->hw_sata_spd_limit = UINT_MAX;
+- ap->active_tag = ATA_TAG_POISON;
+- ap->last_ctl = 0xFF;
+-
+-#if defined(ATA_VERBOSE_DEBUG)
+- /* turn on all debugging levels */
+- ap->msg_enable = 0x00FF;
+-#elif defined(ATA_DEBUG)
+- ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
+-#else
+- ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
+-#endif
+-
+- INIT_WORK(&ap->port_task, NULL, NULL);
+- INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
+- INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
+- INIT_LIST_HEAD(&ap->eh_done_q);
+- init_waitqueue_head(&ap->eh_wait_q);
+-
+- /* set cable type */
+- ap->cbl = ATA_CBL_NONE;
+- if (ap->flags & ATA_FLAG_SATA)
+- ap->cbl = ATA_CBL_SATA;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *dev = &ap->device[i];
+- dev->ap = ap;
+- dev->devno = i;
+- ata_dev_init(dev);
+- }
+-
+-#ifdef ATA_IRQ_TRAP
+- ap->stats.unhandled_irq = 1;
+- ap->stats.idle_irq = 1;
+-#endif
+-
+- memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+-}
+-
+-/**
+- * ata_host_add - Attach low-level ATA driver to system
+- * @ent: Information provided by low-level driver
+- * @host_set: Collections of ports to which we add
+- * @port_no: Port number associated with this host
+- *
+- * Attach low-level ATA driver to system.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- * RETURNS:
+- * New ata_port on success, for NULL on error.
+- */
+-
+-static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
+- struct ata_host_set *host_set,
+- unsigned int port_no)
+-{
+- struct Scsi_Host *host;
+- struct ata_port *ap;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+-
+- if (!ent->port_ops->error_handler &&
+- !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
+- printk(KERN_ERR "ata%u: no reset mechanism available\n",
+- port_no);
+- return NULL;
+- }
+-
+- host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+- if (!host)
+- return NULL;
+-
+- host->transportt = &ata_scsi_transport_template;
+-
+- ap = ata_shost_to_port(host);
+-
+- ata_host_init(ap, host, host_set, ent, port_no);
+-
+- rc = ap->ops->port_start(ap);
+- if (rc)
+- goto err_out;
+-
+- return ap;
+-
+-err_out:
+- scsi_host_put(host);
+- return NULL;
+-}
+-
+-/**
+- * ata_device_add - Register hardware device with ATA and SCSI layers
+- * @ent: Probe information describing hardware device to be registered
+- *
+- * This function processes the information provided in the probe
+- * information struct @ent, allocates the necessary ATA and SCSI
+- * host information structures, initializes them, and registers
+- * everything with requisite kernel subsystems.
+- *
+- * This function requests irqs, probes the ATA bus, and probes
+- * the SCSI bus.
+- *
+- * LOCKING:
+- * PCI/etc. bus probe sem.
+- *
+- * RETURNS:
+- * Number of ports registered. Zero on error (no ports registered).
+- */
+-int ata_device_add(const struct ata_probe_ent *ent)
+-{
+- unsigned int count = 0, i;
+- struct device *dev = ent->dev;
+- struct ata_host_set *host_set;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+- /* alloc a container for our list of ATA ports (buses) */
+- host_set = kzalloc(sizeof(struct ata_host_set) +
+- (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+- if (!host_set)
+- return 0;
+- spin_lock_init(&host_set->lock);
+-
+- host_set->dev = dev;
+- host_set->n_ports = ent->n_ports;
+- host_set->irq = ent->irq;
+- host_set->mmio_base = ent->mmio_base;
+- host_set->private_data = ent->private_data;
+- host_set->ops = ent->port_ops;
+- host_set->flags = ent->host_set_flags;
+-
+- /* register each port bound to this device */
+- for (i = 0; i < ent->n_ports; i++) {
+- struct ata_port *ap;
+- unsigned long xfer_mode_mask;
+-
+- ap = ata_host_add(ent, host_set, i);
+- if (!ap)
+- goto err_out;
+-
+- host_set->ports[i] = ap;
+- xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
+- (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
+- (ap->pio_mask << ATA_SHIFT_PIO);
+-
+- /* print per-port info to dmesg */
+- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
+- "ctl 0x%lX bmdma 0x%lX irq %lu\n",
+- ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
+- ata_mode_string(xfer_mode_mask),
+- ap->ioaddr.cmd_addr,
+- ap->ioaddr.ctl_addr,
+- ap->ioaddr.bmdma_addr,
+- ent->irq);
+-
+- ata_chk_status(ap);
+- host_set->ops->irq_clear(ap);
+- ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
+- count++;
+- }
+-
+- if (!count)
+- goto err_free_ret;
+-
+- /* obtain irq, that is shared between channels */
+- rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
+- DRV_NAME, host_set);
+- if (rc) {
+- dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+- ent->irq, rc);
+- goto err_out;
+- }
+-
+- /* perform each probe synchronously */
+- DPRINTK("probe begin\n");
+- for (i = 0; i < count; i++) {
+- struct ata_port *ap;
+- u32 scontrol;
+- int rc;
+-
+- ap = host_set->ports[i];
+-
+- /* init sata_spd_limit to the current value */
+- if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+- int spd = (scontrol >> 4) & 0xf;
+- ap->hw_sata_spd_limit &= (1 << spd) - 1;
+- }
+- ap->sata_spd_limit = ap->hw_sata_spd_limit;
+-
+- rc = scsi_add_host(ap->host, dev);
+- if (rc) {
+- ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
+- /* FIXME: do something useful here */
+- /* FIXME: handle unconditional calls to
+- * scsi_scan_host and ata_host_remove, below,
+- * at the very least
+- */
+- }
+-
+- if (ap->ops->error_handler) {
+- struct ata_eh_info *ehi = &ap->eh_info;
+- unsigned long flags;
+-
+- ata_port_probe(ap);
+-
+- /* kick EH for boot probing */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+- ehi->action |= ATA_EH_SOFTRESET;
+- ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+-
+- ap->pflags |= ATA_PFLAG_LOADING;
+- ata_port_schedule_eh(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* wait for EH to finish */
+- ata_port_wait_eh(ap);
+- } else {
+- DPRINTK("ata%u: bus probe begin\n", ap->id);
+- rc = ata_bus_probe(ap);
+- DPRINTK("ata%u: bus probe end\n", ap->id);
+-
+- if (rc) {
+- /* FIXME: do something useful here?
+- * Current libata behavior will
+- * tear down everything when
+- * the module is removed
+- * or the h/w is unplugged.
+- */
+- }
+- }
+- }
+-
+- /* probes are done, now scan each port's disk(s) */
+- DPRINTK("host probe begin\n");
+- for (i = 0; i < count; i++) {
+- struct ata_port *ap = host_set->ports[i];
+-
+- ata_scsi_scan_host(ap);
+- }
+-
+- dev_set_drvdata(dev, host_set);
+-
+- VPRINTK("EXIT, returning %u\n", ent->n_ports);
+- return ent->n_ports; /* success */
+-
+-err_out:
+- for (i = 0; i < count; i++) {
+- struct ata_port *ap = host_set->ports[i];
+- if (ap) {
+- ap->ops->port_stop(ap);
+- scsi_host_put(ap->host);
+- }
+- }
+-err_free_ret:
+- kfree(host_set);
+- VPRINTK("EXIT, returning 0\n");
+- return 0;
+-}
+-
+-/**
+- * ata_port_detach - Detach ATA port in prepration of device removal
+- * @ap: ATA port to be detached
+- *
+- * Detach all ATA devices and the associated SCSI devices of @ap;
+- * then, remove the associated SCSI host. @ap is guaranteed to
+- * be quiescent on return from this function.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-void ata_port_detach(struct ata_port *ap)
+-{
+- unsigned long flags;
+- int i;
+-
+- if (!ap->ops->error_handler)
+- goto skip_eh;
+-
+- /* tell EH we're leaving & flush EH */
+- spin_lock_irqsave(ap->lock, flags);
+- ap->pflags |= ATA_PFLAG_UNLOADING;
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- ata_port_wait_eh(ap);
+-
+- /* EH is now guaranteed to see UNLOADING, so no new device
+- * will be attached. Disable all existing devices.
+- */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ata_dev_disable(&ap->device[i]);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* Final freeze & EH. All in-flight commands are aborted. EH
+- * will be skipped and retrials will be terminated with bad
+- * target.
+- */
+- spin_lock_irqsave(ap->lock, flags);
+- ata_port_freeze(ap); /* won't be thawed */
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- ata_port_wait_eh(ap);
+-
+- /* Flush hotplug task. The sequence is similar to
+- * ata_port_flush_task().
+- */
+- flush_workqueue(ata_aux_wq);
+- cancel_delayed_work(&ap->hotplug_task);
+- flush_workqueue(ata_aux_wq);
+-
+- skip_eh:
+- /* remove the associated SCSI host */
+- scsi_remove_host(ap->host);
+-}
+-
+-/**
+- * ata_host_set_remove - PCI layer callback for device removal
+- * @host_set: ATA host set that was removed
+- *
+- * Unregister all objects associated with this host set. Free those
+- * objects.
+- *
+- * LOCKING:
+- * Inherited from calling layer (may sleep).
+- */
+-
+-void ata_host_set_remove(struct ata_host_set *host_set)
+-{
+- unsigned int i;
+-
+- for (i = 0; i < host_set->n_ports; i++)
+- ata_port_detach(host_set->ports[i]);
+-
+- free_irq(host_set->irq, host_set);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap = host_set->ports[i];
+-
+- ata_scsi_release(ap->host);
+-
+- if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+-
+- if (ioaddr->cmd_addr == 0x1f0)
+- release_region(0x1f0, 8);
+- else if (ioaddr->cmd_addr == 0x170)
+- release_region(0x170, 8);
+- }
+-
+- scsi_host_put(ap->host);
+- }
+-
+- if (host_set->ops->host_stop)
+- host_set->ops->host_stop(host_set);
+-
+- kfree(host_set);
+-}
+-
+-/**
+- * ata_scsi_release - SCSI layer callback hook for host unload
+- * @host: libata host to be unloaded
+- *
+- * Performs all duties necessary to shut down a libata port...
+- * Kill port kthread, disable port, and release resources.
+- *
+- * LOCKING:
+- * Inherited from SCSI layer.
+- *
+- * RETURNS:
+- * One.
+- */
+-
+-int ata_scsi_release(struct Scsi_Host *host)
+-{
+- struct ata_port *ap = ata_shost_to_port(host);
+-
+- DPRINTK("ENTER\n");
+-
+- ap->ops->port_disable(ap);
+- ap->ops->port_stop(ap);
+-
+- DPRINTK("EXIT\n");
+- return 1;
+-}
+-
+-/**
+- * ata_std_ports - initialize ioaddr with standard port offsets.
+- * @ioaddr: IO address structure to be initialized
+- *
+- * Utility function which initializes data_addr, error_addr,
+- * feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
+- * device_addr, status_addr, and command_addr to standard offsets
+- * relative to cmd_addr.
+- *
+- * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
+- */
+-
+-void ata_std_ports(struct ata_ioports *ioaddr)
+-{
+- ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
+- ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
+- ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
+- ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
+- ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
+- ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
+- ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
+- ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
+- ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
+- ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
+-}
+-
+-
+-#ifdef CONFIG_PCI
+-
+-void ata_pci_host_stop (struct ata_host_set *host_set)
+-{
+- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+-
+- pci_iounmap(pdev, host_set->mmio_base);
+-}
+-
+-/**
+- * ata_pci_remove_one - PCI layer callback for device removal
+- * @pdev: PCI device that was removed
+- *
+- * PCI layer indicates to libata via this hook that
+- * hot-unplug or module unload event has occurred.
+- * Handle this by unregistering all objects associated
+- * with this PCI device. Free those objects. Then finally
+- * release PCI resources and disable device.
+- *
+- * LOCKING:
+- * Inherited from PCI layer (may sleep).
+- */
+-
+-void ata_pci_remove_one (struct pci_dev *pdev)
+-{
+- struct device *dev = pci_dev_to_dev(pdev);
+- struct ata_host_set *host_set = dev_get_drvdata(dev);
+- struct ata_host_set *host_set2 = host_set->next;
+-
+- ata_host_set_remove(host_set);
+- if (host_set2)
+- ata_host_set_remove(host_set2);
+-
+- pci_release_regions(pdev);
+- pci_disable_device(pdev);
+- dev_set_drvdata(dev, NULL);
+-}
+-
+-/* move to PCI subsystem */
+-int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
+-{
+- unsigned long tmp = 0;
+-
+- switch (bits->width) {
+- case 1: {
+- u8 tmp8 = 0;
+- pci_read_config_byte(pdev, bits->reg, &tmp8);
+- tmp = tmp8;
+- break;
+- }
+- case 2: {
+- u16 tmp16 = 0;
+- pci_read_config_word(pdev, bits->reg, &tmp16);
+- tmp = tmp16;
+- break;
+- }
+- case 4: {
+- u32 tmp32 = 0;
+- pci_read_config_dword(pdev, bits->reg, &tmp32);
+- tmp = tmp32;
+- break;
+- }
+-
+- default:
+- return -EINVAL;
+- }
+-
+- tmp &= bits->mask;
+-
+- return (tmp == bits->val) ? 1 : 0;
+-}
+-
+-void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state)
+-{
+- pci_save_state(pdev);
+-
+- if (state.event == PM_EVENT_SUSPEND) {
+- pci_disable_device(pdev);
+- pci_set_power_state(pdev, PCI_D3hot);
+- }
+-}
+-
+-void ata_pci_device_do_resume(struct pci_dev *pdev)
+-{
+- pci_set_power_state(pdev, PCI_D0);
+- pci_restore_state(pdev);
+- pci_enable_device(pdev);
+- pci_set_master(pdev);
+-}
+-
+-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+-{
+- struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+- int rc = 0;
+-
+- rc = ata_host_set_suspend(host_set, state);
+- if (rc)
+- return rc;
+-
+- if (host_set->next) {
+- rc = ata_host_set_suspend(host_set->next, state);
+- if (rc) {
+- ata_host_set_resume(host_set);
+- return rc;
+- }
+- }
+-
+- ata_pci_device_do_suspend(pdev, state);
+-
+- return 0;
+-}
+-
+-int ata_pci_device_resume(struct pci_dev *pdev)
+-{
+- struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+-
+- ata_pci_device_do_resume(pdev);
+- ata_host_set_resume(host_set);
+- if (host_set->next)
+- ata_host_set_resume(host_set->next);
+-
+- return 0;
+-}
+-#endif /* CONFIG_PCI */
+-
+-
+-static int __init ata_init(void)
+-{
+- ata_probe_timeout *= HZ;
+- ata_wq = create_workqueue("ata");
+- if (!ata_wq)
+- return -ENOMEM;
+-
+- ata_aux_wq = create_singlethread_workqueue("ata_aux");
+- if (!ata_aux_wq) {
+- destroy_workqueue(ata_wq);
+- return -ENOMEM;
+- }
+-
+- printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
+- return 0;
+-}
+-
+-static void __exit ata_exit(void)
+-{
+- destroy_workqueue(ata_wq);
+- destroy_workqueue(ata_aux_wq);
+-}
+-
+-module_init(ata_init);
+-module_exit(ata_exit);
+-
+-static unsigned long ratelimit_time;
+-static DEFINE_SPINLOCK(ata_ratelimit_lock);
+-
+-int ata_ratelimit(void)
+-{
+- int rc;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&ata_ratelimit_lock, flags);
+-
+- if (time_after(jiffies, ratelimit_time)) {
+- rc = 1;
+- ratelimit_time = jiffies + (HZ/5);
+- } else
+- rc = 0;
+-
+- spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
+-
+- return rc;
+-}
+-
+-/**
+- * ata_wait_register - wait until register value changes
+- * @reg: IO-mapped register
+- * @mask: Mask to apply to read register value
+- * @val: Wait condition
+- * @interval_msec: polling interval in milliseconds
+- * @timeout_msec: timeout in milliseconds
+- *
+- * Waiting for some bits of register to change is a common
+- * operation for ATA controllers. This function reads 32bit LE
+- * IO-mapped register @reg and tests for the following condition.
+- *
+- * (*@reg & mask) != val
+- *
+- * If the condition is met, it returns; otherwise, the process is
+- * repeated after @interval_msec until timeout.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * The final register value.
+- */
+-u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
+- unsigned long interval_msec,
+- unsigned long timeout_msec)
+-{
+- unsigned long timeout;
+- u32 tmp;
+-
+- tmp = ioread32(reg);
+-
+- /* Calculate timeout _after_ the first read to make sure
+- * preceding writes reach the controller before starting to
+- * eat away the timeout.
+- */
+- timeout = jiffies + (timeout_msec * HZ) / 1000;
+-
+- while ((tmp & mask) == val && time_before(jiffies, timeout)) {
+- msleep(interval_msec);
+- tmp = ioread32(reg);
+- }
+-
+- return tmp;
+-}
+-
+-/*
+- * libata is essentially a library of internal helper functions for
+- * low-level ATA host controller drivers. As such, the API/ABI is
+- * likely to change as new drivers are added and updated.
+- * Do not depend on ABI/API stability.
+- */
+-
+-EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+-EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+-EXPORT_SYMBOL_GPL(sata_deb_timing_long);
+-EXPORT_SYMBOL_GPL(ata_std_bios_param);
+-EXPORT_SYMBOL_GPL(ata_std_ports);
+-EXPORT_SYMBOL_GPL(ata_device_add);
+-EXPORT_SYMBOL_GPL(ata_port_detach);
+-EXPORT_SYMBOL_GPL(ata_host_set_remove);
+-EXPORT_SYMBOL_GPL(ata_sg_init);
+-EXPORT_SYMBOL_GPL(ata_sg_init_one);
+-EXPORT_SYMBOL_GPL(ata_hsm_move);
+-EXPORT_SYMBOL_GPL(ata_qc_complete);
+-EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
+-EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
+-EXPORT_SYMBOL_GPL(ata_tf_load);
+-EXPORT_SYMBOL_GPL(ata_tf_read);
+-EXPORT_SYMBOL_GPL(ata_noop_dev_select);
+-EXPORT_SYMBOL_GPL(ata_std_dev_select);
+-EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+-EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+-EXPORT_SYMBOL_GPL(ata_check_status);
+-EXPORT_SYMBOL_GPL(ata_altstatus);
+-EXPORT_SYMBOL_GPL(ata_exec_command);
+-EXPORT_SYMBOL_GPL(ata_port_start);
+-EXPORT_SYMBOL_GPL(ata_port_stop);
+-EXPORT_SYMBOL_GPL(ata_host_stop);
+-EXPORT_SYMBOL_GPL(ata_interrupt);
+-EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
+-EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
+-EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
+-EXPORT_SYMBOL_GPL(ata_qc_prep);
+-EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
+-EXPORT_SYMBOL_GPL(ata_bmdma_setup);
+-EXPORT_SYMBOL_GPL(ata_bmdma_start);
+-EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
+-EXPORT_SYMBOL_GPL(ata_bmdma_status);
+-EXPORT_SYMBOL_GPL(ata_bmdma_stop);
+-EXPORT_SYMBOL_GPL(ata_bmdma_freeze);
+-EXPORT_SYMBOL_GPL(ata_bmdma_thaw);
+-EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh);
+-EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
+-EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
+-EXPORT_SYMBOL_GPL(ata_port_probe);
+-EXPORT_SYMBOL_GPL(sata_set_spd);
+-EXPORT_SYMBOL_GPL(sata_phy_debounce);
+-EXPORT_SYMBOL_GPL(sata_phy_resume);
+-EXPORT_SYMBOL_GPL(sata_phy_reset);
+-EXPORT_SYMBOL_GPL(__sata_phy_reset);
+-EXPORT_SYMBOL_GPL(ata_bus_reset);
+-EXPORT_SYMBOL_GPL(ata_std_prereset);
+-EXPORT_SYMBOL_GPL(ata_std_softreset);
+-EXPORT_SYMBOL_GPL(sata_std_hardreset);
+-EXPORT_SYMBOL_GPL(ata_std_postreset);
+-EXPORT_SYMBOL_GPL(ata_dev_revalidate);
+-EXPORT_SYMBOL_GPL(ata_dev_classify);
+-EXPORT_SYMBOL_GPL(ata_dev_pair);
+-EXPORT_SYMBOL_GPL(ata_port_disable);
+-EXPORT_SYMBOL_GPL(ata_ratelimit);
+-EXPORT_SYMBOL_GPL(ata_wait_register);
+-EXPORT_SYMBOL_GPL(ata_busy_sleep);
+-EXPORT_SYMBOL_GPL(ata_port_queue_task);
+-EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
+-EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+-EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+-EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
+-EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
+-EXPORT_SYMBOL_GPL(ata_scsi_release);
+-EXPORT_SYMBOL_GPL(ata_host_intr);
+-EXPORT_SYMBOL_GPL(sata_scr_valid);
+-EXPORT_SYMBOL_GPL(sata_scr_read);
+-EXPORT_SYMBOL_GPL(sata_scr_write);
+-EXPORT_SYMBOL_GPL(sata_scr_write_flush);
+-EXPORT_SYMBOL_GPL(ata_port_online);
+-EXPORT_SYMBOL_GPL(ata_port_offline);
+-EXPORT_SYMBOL_GPL(ata_host_set_suspend);
+-EXPORT_SYMBOL_GPL(ata_host_set_resume);
+-EXPORT_SYMBOL_GPL(ata_id_string);
+-EXPORT_SYMBOL_GPL(ata_id_c_string);
+-EXPORT_SYMBOL_GPL(ata_scsi_simulate);
+-
+-EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
+-EXPORT_SYMBOL_GPL(ata_timing_compute);
+-EXPORT_SYMBOL_GPL(ata_timing_merge);
+-
+-#ifdef CONFIG_PCI
+-EXPORT_SYMBOL_GPL(pci_test_config_bits);
+-EXPORT_SYMBOL_GPL(ata_pci_host_stop);
+-EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+-EXPORT_SYMBOL_GPL(ata_pci_init_one);
+-EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+-EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+-EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
+-EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
+-EXPORT_SYMBOL_GPL(ata_pci_device_resume);
+-EXPORT_SYMBOL_GPL(ata_pci_default_filter);
+-EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
+-#endif /* CONFIG_PCI */
+-
+-EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
+-EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
+-
+-EXPORT_SYMBOL_GPL(ata_eng_timeout);
+-EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+-EXPORT_SYMBOL_GPL(ata_port_abort);
+-EXPORT_SYMBOL_GPL(ata_port_freeze);
+-EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
+-EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
+-EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
+-EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
+-EXPORT_SYMBOL_GPL(ata_do_eh);
+diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
+deleted file mode 100644
+index 29f5934..0000000
+--- a/drivers/scsi/libata-eh.c
++++ /dev/null
+@@ -1,2246 +0,0 @@
+-/*
+- * libata-eh.c - libata error handling
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2006 Tejun Heo <htejun at gmail.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, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+- * USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available from http://www.t13.org/ and
+- * http://www.sata-io.org/
+- *
+- */
+-
+-#include <linux/config.h>
+-#include <linux/kernel.h>
+-#include <scsi/scsi.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_eh.h>
+-#include <scsi/scsi_device.h>
+-#include <scsi/scsi_cmnd.h>
+-#include "scsi_transport_api.h"
+-
+-#include <linux/libata.h>
+-
+-#include "libata.h"
+-
+-static void __ata_port_freeze(struct ata_port *ap);
+-static void ata_eh_finish(struct ata_port *ap);
+-static void ata_eh_handle_port_suspend(struct ata_port *ap);
+-static void ata_eh_handle_port_resume(struct ata_port *ap);
+-
+-static void ata_ering_record(struct ata_ering *ering, int is_io,
+- unsigned int err_mask)
+-{
+- struct ata_ering_entry *ent;
+-
+- WARN_ON(!err_mask);
+-
+- ering->cursor++;
+- ering->cursor %= ATA_ERING_SIZE;
+-
+- ent = &ering->ring[ering->cursor];
+- ent->is_io = is_io;
+- ent->err_mask = err_mask;
+- ent->timestamp = get_jiffies_64();
+-}
+-
+-static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering)
+-{
+- struct ata_ering_entry *ent = &ering->ring[ering->cursor];
+- if (!ent->err_mask)
+- return NULL;
+- return ent;
+-}
+-
+-static int ata_ering_map(struct ata_ering *ering,
+- int (*map_fn)(struct ata_ering_entry *, void *),
+- void *arg)
+-{
+- int idx, rc = 0;
+- struct ata_ering_entry *ent;
+-
+- idx = ering->cursor;
+- do {
+- ent = &ering->ring[idx];
+- if (!ent->err_mask)
+- break;
+- rc = map_fn(ent, arg);
+- if (rc)
+- break;
+- idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE;
+- } while (idx != ering->cursor);
+-
+- return rc;
+-}
+-
+-static unsigned int ata_eh_dev_action(struct ata_device *dev)
+-{
+- struct ata_eh_context *ehc = &dev->ap->eh_context;
+-
+- return ehc->i.action | ehc->i.dev_action[dev->devno];
+-}
+-
+-static void ata_eh_clear_action(struct ata_device *dev,
+- struct ata_eh_info *ehi, unsigned int action)
+-{
+- int i;
+-
+- if (!dev) {
+- ehi->action &= ~action;
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ehi->dev_action[i] &= ~action;
+- } else {
+- /* doesn't make sense for port-wide EH actions */
+- WARN_ON(!(action & ATA_EH_PERDEV_MASK));
+-
+- /* break ehi->action into ehi->dev_action */
+- if (ehi->action & action) {
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ehi->dev_action[i] |= ehi->action & action;
+- ehi->action &= ~action;
+- }
+-
+- /* turn off the specified per-dev action */
+- ehi->dev_action[dev->devno] &= ~action;
+- }
+-}
+-
+-/**
+- * ata_scsi_timed_out - SCSI layer time out callback
+- * @cmd: timed out SCSI command
+- *
+- * Handles SCSI layer timeout. We race with normal completion of
+- * the qc for @cmd. If the qc is already gone, we lose and let
+- * the scsi command finish (EH_HANDLED). Otherwise, the qc has
+- * timed out and EH should be invoked. Prevent ata_qc_complete()
+- * from finishing it by setting EH_SCHEDULED and return
+- * EH_NOT_HANDLED.
+- *
+- * TODO: kill this function once old EH is gone.
+- *
+- * LOCKING:
+- * Called from timer context
+- *
+- * RETURNS:
+- * EH_HANDLED or EH_NOT_HANDLED
+- */
+-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+-{
+- struct Scsi_Host *host = cmd->device->host;
+- struct ata_port *ap = ata_shost_to_port(host);
+- unsigned long flags;
+- struct ata_queued_cmd *qc;
+- enum scsi_eh_timer_return ret;
+-
+- DPRINTK("ENTER\n");
+-
+- if (ap->ops->error_handler) {
+- ret = EH_NOT_HANDLED;
+- goto out;
+- }
+-
+- ret = EH_HANDLED;
+- spin_lock_irqsave(ap->lock, flags);
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc) {
+- WARN_ON(qc->scsicmd != cmd);
+- qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+- qc->err_mask |= AC_ERR_TIMEOUT;
+- ret = EH_NOT_HANDLED;
+- }
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- out:
+- DPRINTK("EXIT, ret=%d\n", ret);
+- return ret;
+-}
+-
+-/**
+- * ata_scsi_error - SCSI layer error handler callback
+- * @host: SCSI host on which error occurred
+- *
+- * Handles SCSI-layer-thrown error events.
+- *
+- * LOCKING:
+- * Inherited from SCSI layer (none, can sleep)
+- *
+- * RETURNS:
+- * Zero.
+- */
+-void ata_scsi_error(struct Scsi_Host *host)
+-{
+- struct ata_port *ap = ata_shost_to_port(host);
+- int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+- unsigned long flags;
+-
+- DPRINTK("ENTER\n");
+-
+- /* synchronize with port task */
+- ata_port_flush_task(ap);
+-
+- /* synchronize with host_set lock and sort out timeouts */
+-
+- /* For new EH, all qcs are finished in one of three ways -
+- * normal completion, error completion, and SCSI timeout.
+- * Both cmpletions can race against SCSI timeout. When normal
+- * completion wins, the qc never reaches EH. When error
+- * completion wins, the qc has ATA_QCFLAG_FAILED set.
+- *
+- * When SCSI timeout wins, things are a bit more complex.
+- * Normal or error completion can occur after the timeout but
+- * before this point. In such cases, both types of
+- * completions are honored. A scmd is determined to have
+- * timed out iff its associated qc is active and not failed.
+- */
+- if (ap->ops->error_handler) {
+- struct scsi_cmnd *scmd, *tmp;
+- int nr_timedout = 0;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
+- struct ata_queued_cmd *qc;
+-
+- for (i = 0; i < ATA_MAX_QUEUE; i++) {
+- qc = __ata_qc_from_tag(ap, i);
+- if (qc->flags & ATA_QCFLAG_ACTIVE &&
+- qc->scsicmd == scmd)
+- break;
+- }
+-
+- if (i < ATA_MAX_QUEUE) {
+- /* the scmd has an associated qc */
+- if (!(qc->flags & ATA_QCFLAG_FAILED)) {
+- /* which hasn't failed yet, timeout */
+- qc->err_mask |= AC_ERR_TIMEOUT;
+- qc->flags |= ATA_QCFLAG_FAILED;
+- nr_timedout++;
+- }
+- } else {
+- /* Normal completion occurred after
+- * SCSI timeout but before this point.
+- * Successfully complete it.
+- */
+- scmd->retries = scmd->allowed;
+- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+- }
+- }
+-
+- /* If we have timed out qcs. They belong to EH from
+- * this point but the state of the controller is
+- * unknown. Freeze the port to make sure the IRQ
+- * handler doesn't diddle with those qcs. This must
+- * be done atomically w.r.t. setting QCFLAG_FAILED.
+- */
+- if (nr_timedout)
+- __ata_port_freeze(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+- } else
+- spin_unlock_wait(ap->lock);
+-
+- repeat:
+- /* invoke error handler */
+- if (ap->ops->error_handler) {
+- /* process port resume request */
+- ata_eh_handle_port_resume(ap);
+-
+- /* fetch & clear EH info */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- memset(&ap->eh_context, 0, sizeof(ap->eh_context));
+- ap->eh_context.i = ap->eh_info;
+- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+-
+- ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
+- ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* invoke EH, skip if unloading or suspended */
+- if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
+- ap->ops->error_handler(ap);
+- else
+- ata_eh_finish(ap);
+-
+- /* process port suspend request */
+- ata_eh_handle_port_suspend(ap);
+-
+- /* Exception might have happend after ->error_handler
+- * recovered the port but before this point. Repeat
+- * EH in such case.
+- */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- if (ap->pflags & ATA_PFLAG_EH_PENDING) {
+- if (--repeat_cnt) {
+- ata_port_printk(ap, KERN_INFO,
+- "EH pending after completion, "
+- "repeating EH (cnt=%d)\n", repeat_cnt);
+- spin_unlock_irqrestore(ap->lock, flags);
+- goto repeat;
+- }
+- ata_port_printk(ap, KERN_ERR, "EH pending after %d "
+- "tries, giving up\n", ATA_EH_MAX_REPEAT);
+- }
+-
+- /* this run is complete, make sure EH info is clear */
+- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+-
+- /* Clear host_eh_scheduled while holding ap->lock such
+- * that if exception occurs after this point but
+- * before EH completion, SCSI midlayer will
+- * re-initiate EH.
+- */
+- host->host_eh_scheduled = 0;
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+- } else {
+- WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+- ap->ops->eng_timeout(ap);
+- }
+-
+- /* finish or retry handled scmd's and clean up */
+- WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
+-
+- scsi_eh_flush_done_q(&ap->eh_done_q);
+-
+- /* clean up */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- if (ap->pflags & ATA_PFLAG_LOADING)
+- ap->pflags &= ~ATA_PFLAG_LOADING;
+- else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+- queue_work(ata_aux_wq, &ap->hotplug_task);
+-
+- if (ap->pflags & ATA_PFLAG_RECOVERED)
+- ata_port_printk(ap, KERN_INFO, "EH complete\n");
+-
+- ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
+-
+- /* tell wait_eh that we're done */
+- ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
+- wake_up_all(&ap->eh_wait_q);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_port_wait_eh - Wait for the currently pending EH to complete
+- * @ap: Port to wait EH for
+- *
+- * Wait until the currently pending EH is complete.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-void ata_port_wait_eh(struct ata_port *ap)
+-{
+- unsigned long flags;
+- DEFINE_WAIT(wait);
+-
+- retry:
+- spin_lock_irqsave(ap->lock, flags);
+-
+- while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
+- prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
+- spin_unlock_irqrestore(ap->lock, flags);
+- schedule();
+- spin_lock_irqsave(ap->lock, flags);
+- }
+- finish_wait(&ap->eh_wait_q, &wait);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* make sure SCSI EH is complete */
+- if (scsi_host_in_recovery(ap->host)) {
+- msleep(10);
+- goto retry;
+- }
+-}
+-
+-/**
+- * ata_qc_timeout - Handle timeout of queued command
+- * @qc: Command that timed out
+- *
+- * Some part of the kernel (currently, only the SCSI layer)
+- * has noticed that the active command on port @ap has not
+- * completed after a specified length of time. Handle this
+- * condition by disabling DMA (if necessary) and completing
+- * transactions, with error if necessary.
+- *
+- * This also handles the case of the "lost interrupt", where
+- * for some reason (possibly hardware bug, possibly driver bug)
+- * an interrupt was not delivered to the driver, even though the
+- * transaction completed successfully.
+- *
+- * TODO: kill this function once old EH is gone.
+- *
+- * LOCKING:
+- * Inherited from SCSI layer (none, can sleep)
+- */
+-static void ata_qc_timeout(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- u8 host_stat = 0, drv_stat;
+- unsigned long flags;
+-
+- DPRINTK("ENTER\n");
+-
+- ap->hsm_task_state = HSM_ST_IDLE;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- switch (qc->tf.protocol) {
+-
+- case ATA_PROT_DMA:
+- case ATA_PROT_ATAPI_DMA:
+- host_stat = ap->ops->bmdma_status(ap);
+-
+- /* before we do anything else, clear DMA-Start bit */
+- ap->ops->bmdma_stop(qc);
+-
+- /* fall through */
+-
+- default:
+- ata_altstatus(ap);
+- drv_stat = ata_chk_status(ap);
+-
+- /* ack bmdma irq events */
+- ap->ops->irq_clear(ap);
+-
+- ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, "
+- "stat 0x%x host_stat 0x%x\n",
+- qc->tf.command, drv_stat, host_stat);
+-
+- /* complete taskfile transaction */
+- qc->err_mask |= AC_ERR_TIMEOUT;
+- break;
+- }
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- ata_eh_qc_complete(qc);
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_eng_timeout - Handle timeout of queued command
+- * @ap: Port on which timed-out command is active
+- *
+- * Some part of the kernel (currently, only the SCSI layer)
+- * has noticed that the active command on port @ap has not
+- * completed after a specified length of time. Handle this
+- * condition by disabling DMA (if necessary) and completing
+- * transactions, with error if necessary.
+- *
+- * This also handles the case of the "lost interrupt", where
+- * for some reason (possibly hardware bug, possibly driver bug)
+- * an interrupt was not delivered to the driver, even though the
+- * transaction completed successfully.
+- *
+- * TODO: kill this function once old EH is gone.
+- *
+- * LOCKING:
+- * Inherited from SCSI layer (none, can sleep)
+- */
+-void ata_eng_timeout(struct ata_port *ap)
+-{
+- DPRINTK("ENTER\n");
+-
+- ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_qc_schedule_eh - schedule qc for error handling
+- * @qc: command to schedule error handling for
+- *
+- * Schedule error handling for @qc. EH will kick in as soon as
+- * other commands are drained.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- WARN_ON(!ap->ops->error_handler);
+-
+- qc->flags |= ATA_QCFLAG_FAILED;
+- qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+-
+- /* The following will fail if timeout has already expired.
+- * ata_scsi_error() takes care of such scmds on EH entry.
+- * Note that ATA_QCFLAG_FAILED is unconditionally set after
+- * this function completes.
+- */
+- scsi_req_abort_cmd(qc->scsicmd);
+-}
+-
+-/**
+- * ata_port_schedule_eh - schedule error handling without a qc
+- * @ap: ATA port to schedule EH for
+- *
+- * Schedule error handling for @ap. EH will kick in as soon as
+- * all commands are drained.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_port_schedule_eh(struct ata_port *ap)
+-{
+- WARN_ON(!ap->ops->error_handler);
+-
+- ap->pflags |= ATA_PFLAG_EH_PENDING;
+- scsi_schedule_eh(ap->host);
+-
+- DPRINTK("port EH scheduled\n");
+-}
+-
+-/**
+- * ata_port_abort - abort all qc's on the port
+- * @ap: ATA port to abort qc's for
+- *
+- * Abort all active qc's of @ap and schedule EH.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Number of aborted qc's.
+- */
+-int ata_port_abort(struct ata_port *ap)
+-{
+- int tag, nr_aborted = 0;
+-
+- WARN_ON(!ap->ops->error_handler);
+-
+- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+-
+- if (qc) {
+- qc->flags |= ATA_QCFLAG_FAILED;
+- ata_qc_complete(qc);
+- nr_aborted++;
+- }
+- }
+-
+- if (!nr_aborted)
+- ata_port_schedule_eh(ap);
+-
+- return nr_aborted;
+-}
+-
+-/**
+- * __ata_port_freeze - freeze port
+- * @ap: ATA port to freeze
+- *
+- * This function is called when HSM violation or some other
+- * condition disrupts normal operation of the port. Frozen port
+- * is not allowed to perform any operation until the port is
+- * thawed, which usually follows a successful reset.
+- *
+- * ap->ops->freeze() callback can be used for freezing the port
+- * hardware-wise (e.g. mask interrupt and stop DMA engine). If a
+- * port cannot be frozen hardware-wise, the interrupt handler
+- * must ack and clear interrupts unconditionally while the port
+- * is frozen.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-static void __ata_port_freeze(struct ata_port *ap)
+-{
+- WARN_ON(!ap->ops->error_handler);
+-
+- if (ap->ops->freeze)
+- ap->ops->freeze(ap);
+-
+- ap->pflags |= ATA_PFLAG_FROZEN;
+-
+- DPRINTK("ata%u port frozen\n", ap->id);
+-}
+-
+-/**
+- * ata_port_freeze - abort & freeze port
+- * @ap: ATA port to freeze
+- *
+- * Abort and freeze @ap.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Number of aborted commands.
+- */
+-int ata_port_freeze(struct ata_port *ap)
+-{
+- int nr_aborted;
+-
+- WARN_ON(!ap->ops->error_handler);
+-
+- nr_aborted = ata_port_abort(ap);
+- __ata_port_freeze(ap);
+-
+- return nr_aborted;
+-}
+-
+-/**
+- * ata_eh_freeze_port - EH helper to freeze port
+- * @ap: ATA port to freeze
+- *
+- * Freeze @ap.
+- *
+- * LOCKING:
+- * None.
+- */
+-void ata_eh_freeze_port(struct ata_port *ap)
+-{
+- unsigned long flags;
+-
+- if (!ap->ops->error_handler)
+- return;
+-
+- spin_lock_irqsave(ap->lock, flags);
+- __ata_port_freeze(ap);
+- spin_unlock_irqrestore(ap->lock, flags);
+-}
+-
+-/**
+- * ata_port_thaw_port - EH helper to thaw port
+- * @ap: ATA port to thaw
+- *
+- * Thaw frozen port @ap.
+- *
+- * LOCKING:
+- * None.
+- */
+-void ata_eh_thaw_port(struct ata_port *ap)
+-{
+- unsigned long flags;
+-
+- if (!ap->ops->error_handler)
+- return;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- ap->pflags &= ~ATA_PFLAG_FROZEN;
+-
+- if (ap->ops->thaw)
+- ap->ops->thaw(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- DPRINTK("ata%u port thawed\n", ap->id);
+-}
+-
+-static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+-{
+- /* nada */
+-}
+-
+-static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct scsi_cmnd *scmd = qc->scsicmd;
+- unsigned long flags;
+-
+- spin_lock_irqsave(ap->lock, flags);
+- qc->scsidone = ata_eh_scsidone;
+- __ata_qc_complete(qc);
+- WARN_ON(ata_tag_valid(qc->tag));
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+-}
+-
+-/**
+- * ata_eh_qc_complete - Complete an active ATA command from EH
+- * @qc: Command to complete
+- *
+- * Indicate to the mid and upper layers that an ATA command has
+- * completed. To be used from EH.
+- */
+-void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+-{
+- struct scsi_cmnd *scmd = qc->scsicmd;
+- scmd->retries = scmd->allowed;
+- __ata_eh_qc_complete(qc);
+-}
+-
+-/**
+- * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+- * @qc: Command to retry
+- *
+- * Indicate to the mid and upper layers that an ATA command
+- * should be retried. To be used from EH.
+- *
+- * SCSI midlayer limits the number of retries to scmd->allowed.
+- * scmd->retries is decremented for commands which get retried
+- * due to unrelated failures (qc->err_mask is zero).
+- */
+-void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+-{
+- struct scsi_cmnd *scmd = qc->scsicmd;
+- if (!qc->err_mask && scmd->retries)
+- scmd->retries--;
+- __ata_eh_qc_complete(qc);
+-}
+-
+-/**
+- * ata_eh_detach_dev - detach ATA device
+- * @dev: ATA device to detach
+- *
+- * Detach @dev.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_eh_detach_dev(struct ata_device *dev)
+-{
+- struct ata_port *ap = dev->ap;
+- unsigned long flags;
+-
+- ata_dev_disable(dev);
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- dev->flags &= ~ATA_DFLAG_DETACH;
+-
+- if (ata_scsi_offline_dev(dev)) {
+- dev->flags |= ATA_DFLAG_DETACHED;
+- ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
+- }
+-
+- /* clear per-dev EH actions */
+- ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
+- ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-}
+-
+-/**
+- * ata_eh_about_to_do - about to perform eh_action
+- * @ap: target ATA port
+- * @dev: target ATA dev for per-dev action (can be NULL)
+- * @action: action about to be performed
+- *
+- * Called just before performing EH actions to clear related bits
+- * in @ap->eh_info such that eh actions are not unnecessarily
+- * repeated.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
+- unsigned int action)
+-{
+- unsigned long flags;
+- struct ata_eh_info *ehi = &ap->eh_info;
+- struct ata_eh_context *ehc = &ap->eh_context;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* Reset is represented by combination of actions and EHI
+- * flags. Suck in all related bits before clearing eh_info to
+- * avoid losing requested action.
+- */
+- if (action & ATA_EH_RESET_MASK) {
+- ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
+- ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
+-
+- /* make sure all reset actions are cleared & clear EHI flags */
+- action |= ATA_EH_RESET_MASK;
+- ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+- }
+-
+- ata_eh_clear_action(dev, ehi, action);
+-
+- if (!(ehc->i.flags & ATA_EHI_QUIET))
+- ap->pflags |= ATA_PFLAG_RECOVERED;
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-}
+-
+-/**
+- * ata_eh_done - EH action complete
+- * @ap: target ATA port
+- * @dev: target ATA dev for per-dev action (can be NULL)
+- * @action: action just completed
+- *
+- * Called right after performing EH actions to clear related bits
+- * in @ap->eh_context.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
+- unsigned int action)
+-{
+- /* if reset is complete, clear all reset actions & reset modifier */
+- if (action & ATA_EH_RESET_MASK) {
+- action |= ATA_EH_RESET_MASK;
+- ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+- }
+-
+- ata_eh_clear_action(dev, &ap->eh_context.i, action);
+-}
+-
+-/**
+- * ata_err_string - convert err_mask to descriptive string
+- * @err_mask: error mask to convert to string
+- *
+- * Convert @err_mask to descriptive string. Errors are
+- * prioritized according to severity and only the most severe
+- * error is reported.
+- *
+- * LOCKING:
+- * None.
+- *
+- * RETURNS:
+- * Descriptive string for @err_mask
+- */
+-static const char * ata_err_string(unsigned int err_mask)
+-{
+- if (err_mask & AC_ERR_HOST_BUS)
+- return "host bus error";
+- if (err_mask & AC_ERR_ATA_BUS)
+- return "ATA bus error";
+- if (err_mask & AC_ERR_TIMEOUT)
+- return "timeout";
+- if (err_mask & AC_ERR_HSM)
+- return "HSM violation";
+- if (err_mask & AC_ERR_SYSTEM)
+- return "internal error";
+- if (err_mask & AC_ERR_MEDIA)
+- return "media error";
+- if (err_mask & AC_ERR_INVALID)
+- return "invalid argument";
+- if (err_mask & AC_ERR_DEV)
+- return "device error";
+- return "unknown error";
+-}
+-
+-/**
+- * ata_read_log_page - read a specific log page
+- * @dev: target device
+- * @page: page to read
+- * @buf: buffer to store read page
+- * @sectors: number of sectors to read
+- *
+- * Read log page using READ_LOG_EXT command.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, AC_ERR_* mask otherwise.
+- */
+-static unsigned int ata_read_log_page(struct ata_device *dev,
+- u8 page, void *buf, unsigned int sectors)
+-{
+- struct ata_taskfile tf;
+- unsigned int err_mask;
+-
+- DPRINTK("read log page - page %d\n", page);
+-
+- ata_tf_init(dev, &tf);
+- tf.command = ATA_CMD_READ_LOG_EXT;
+- tf.lbal = page;
+- tf.nsect = sectors;
+- tf.hob_nsect = sectors >> 8;
+- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+- tf.protocol = ATA_PROT_PIO;
+-
+- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+- buf, sectors * ATA_SECT_SIZE);
+-
+- DPRINTK("EXIT, err_mask=%x\n", err_mask);
+- return err_mask;
+-}
+-
+-/**
+- * ata_eh_read_log_10h - Read log page 10h for NCQ error details
+- * @dev: Device to read log page 10h from
+- * @tag: Resulting tag of the failed command
+- * @tf: Resulting taskfile registers of the failed command
+- *
+- * Read log page 10h to obtain NCQ error details and clear error
+- * condition.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-static int ata_eh_read_log_10h(struct ata_device *dev,
+- int *tag, struct ata_taskfile *tf)
+-{
+- u8 *buf = dev->ap->sector_buf;
+- unsigned int err_mask;
+- u8 csum;
+- int i;
+-
+- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
+- if (err_mask)
+- return -EIO;
+-
+- csum = 0;
+- for (i = 0; i < ATA_SECT_SIZE; i++)
+- csum += buf[i];
+- if (csum)
+- ata_dev_printk(dev, KERN_WARNING,
+- "invalid checksum 0x%x on log page 10h\n", csum);
+-
+- if (buf[0] & 0x80)
+- return -ENOENT;
+-
+- *tag = buf[0] & 0x1f;
+-
+- tf->command = buf[2];
+- tf->feature = buf[3];
+- tf->lbal = buf[4];
+- tf->lbam = buf[5];
+- tf->lbah = buf[6];
+- tf->device = buf[7];
+- tf->hob_lbal = buf[8];
+- tf->hob_lbam = buf[9];
+- tf->hob_lbah = buf[10];
+- tf->nsect = buf[12];
+- tf->hob_nsect = buf[13];
+-
+- return 0;
+-}
+-
+-/**
+- * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
+- * @dev: device to perform REQUEST_SENSE to
+- * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
+- *
+- * Perform ATAPI REQUEST_SENSE after the device reported CHECK
+- * SENSE. This function is EH helper.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, AC_ERR_* mask on failure
+- */
+-static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+- unsigned char *sense_buf)
+-{
+- struct ata_port *ap = dev->ap;
+- struct ata_taskfile tf;
+- u8 cdb[ATAPI_CDB_LEN];
+-
+- DPRINTK("ATAPI request sense\n");
+-
+- ata_tf_init(dev, &tf);
+-
+- /* FIXME: is this needed? */
+- memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
+-
+- /* XXX: why tf_read here? */
+- ap->ops->tf_read(ap, &tf);
+-
+- /* fill these in, for the case where they are -not- overwritten */
+- sense_buf[0] = 0x70;
+- sense_buf[2] = tf.feature >> 4;
+-
+- memset(cdb, 0, ATAPI_CDB_LEN);
+- cdb[0] = REQUEST_SENSE;
+- cdb[4] = SCSI_SENSE_BUFFERSIZE;
+-
+- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+- tf.command = ATA_CMD_PACKET;
+-
+- /* is it pointless to prefer PIO for "safety reasons"? */
+- if (ap->flags & ATA_FLAG_PIO_DMA) {
+- tf.protocol = ATA_PROT_ATAPI_DMA;
+- tf.feature |= ATAPI_PKT_DMA;
+- } else {
+- tf.protocol = ATA_PROT_ATAPI;
+- tf.lbam = (8 * 1024) & 0xff;
+- tf.lbah = (8 * 1024) >> 8;
+- }
+-
+- return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
+- sense_buf, SCSI_SENSE_BUFFERSIZE);
+-}
+-
+-/**
+- * ata_eh_analyze_serror - analyze SError for a failed port
+- * @ap: ATA port to analyze SError for
+- *
+- * Analyze SError if available and further determine cause of
+- * failure.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_eh_analyze_serror(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- u32 serror = ehc->i.serror;
+- unsigned int err_mask = 0, action = 0;
+-
+- if (serror & SERR_PERSISTENT) {
+- err_mask |= AC_ERR_ATA_BUS;
+- action |= ATA_EH_HARDRESET;
+- }
+- if (serror &
+- (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
+- err_mask |= AC_ERR_ATA_BUS;
+- action |= ATA_EH_SOFTRESET;
+- }
+- if (serror & SERR_PROTOCOL) {
+- err_mask |= AC_ERR_HSM;
+- action |= ATA_EH_SOFTRESET;
+- }
+- if (serror & SERR_INTERNAL) {
+- err_mask |= AC_ERR_SYSTEM;
+- action |= ATA_EH_SOFTRESET;
+- }
+- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+- ata_ehi_hotplugged(&ehc->i);
+-
+- ehc->i.err_mask |= err_mask;
+- ehc->i.action |= action;
+-}
+-
+-/**
+- * ata_eh_analyze_ncq_error - analyze NCQ error
+- * @ap: ATA port to analyze NCQ error for
+- *
+- * Read log page 10h, determine the offending qc and acquire
+- * error status TF. For NCQ device errors, all LLDDs have to do
+- * is setting AC_ERR_DEV in ehi->err_mask. This function takes
+- * care of the rest.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- struct ata_device *dev = ap->device;
+- struct ata_queued_cmd *qc;
+- struct ata_taskfile tf;
+- int tag, rc;
+-
+- /* if frozen, we can't do much */
+- if (ap->pflags & ATA_PFLAG_FROZEN)
+- return;
+-
+- /* is it NCQ device error? */
+- if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+- return;
+-
+- /* has LLDD analyzed already? */
+- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+- qc = __ata_qc_from_tag(ap, tag);
+-
+- if (!(qc->flags & ATA_QCFLAG_FAILED))
+- continue;
+-
+- if (qc->err_mask)
+- return;
+- }
+-
+- /* okay, this error is ours */
+- rc = ata_eh_read_log_10h(dev, &tag, &tf);
+- if (rc) {
+- ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+- "(errno=%d)\n", rc);
+- return;
+- }
+-
+- if (!(ap->sactive & (1 << tag))) {
+- ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+- "inactive tag %d\n", tag);
+- return;
+- }
+-
+- /* we've got the perpetrator, condemn it */
+- qc = __ata_qc_from_tag(ap, tag);
+- memcpy(&qc->result_tf, &tf, sizeof(tf));
+- qc->err_mask |= AC_ERR_DEV;
+- ehc->i.err_mask &= ~AC_ERR_DEV;
+-}
+-
+-/**
+- * ata_eh_analyze_tf - analyze taskfile of a failed qc
+- * @qc: qc to analyze
+- * @tf: Taskfile registers to analyze
+- *
+- * Analyze taskfile of @qc and further determine cause of
+- * failure. This function also requests ATAPI sense data if
+- * avaliable.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * Determined recovery action
+- */
+-static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
+- const struct ata_taskfile *tf)
+-{
+- unsigned int tmp, action = 0;
+- u8 stat = tf->command, err = tf->feature;
+-
+- if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) {
+- qc->err_mask |= AC_ERR_HSM;
+- return ATA_EH_SOFTRESET;
+- }
+-
+- if (!(qc->err_mask & AC_ERR_DEV))
+- return 0;
+-
+- switch (qc->dev->class) {
+- case ATA_DEV_ATA:
+- if (err & ATA_ICRC)
+- qc->err_mask |= AC_ERR_ATA_BUS;
+- if (err & ATA_UNC)
+- qc->err_mask |= AC_ERR_MEDIA;
+- if (err & ATA_IDNF)
+- qc->err_mask |= AC_ERR_INVALID;
+- break;
+-
+- case ATA_DEV_ATAPI:
+- tmp = atapi_eh_request_sense(qc->dev,
+- qc->scsicmd->sense_buffer);
+- if (!tmp) {
+- /* ATA_QCFLAG_SENSE_VALID is used to tell
+- * atapi_qc_complete() that sense data is
+- * already valid.
+- *
+- * TODO: interpret sense data and set
+- * appropriate err_mask.
+- */
+- qc->flags |= ATA_QCFLAG_SENSE_VALID;
+- } else
+- qc->err_mask |= tmp;
+- }
+-
+- if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
+- action |= ATA_EH_SOFTRESET;
+-
+- return action;
+-}
+-
+-static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent)
+-{
+- if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT))
+- return 1;
+-
+- if (ent->is_io) {
+- if (ent->err_mask & AC_ERR_HSM)
+- return 1;
+- if ((ent->err_mask &
+- (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
+- return 2;
+- }
+-
+- return 0;
+-}
+-
+-struct speed_down_needed_arg {
+- u64 since;
+- int nr_errors[3];
+-};
+-
+-static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg)
+-{
+- struct speed_down_needed_arg *arg = void_arg;
+-
+- if (ent->timestamp < arg->since)
+- return -1;
+-
+- arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++;
+- return 0;
+-}
+-
+-/**
+- * ata_eh_speed_down_needed - Determine wheter speed down is necessary
+- * @dev: Device of interest
+- *
+- * This function examines error ring of @dev and determines
+- * whether speed down is necessary. Speed down is necessary if
+- * there have been more than 3 of Cat-1 errors or 10 of Cat-2
+- * errors during last 15 minutes.
+- *
+- * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM
+- * violation for known supported commands.
+- *
+- * Cat-2 errors are unclassified DEV error for known supported
+- * command.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- *
+- * RETURNS:
+- * 1 if speed down is necessary, 0 otherwise
+- */
+-static int ata_eh_speed_down_needed(struct ata_device *dev)
+-{
+- const u64 interval = 15LLU * 60 * HZ;
+- static const int err_limits[3] = { -1, 3, 10 };
+- struct speed_down_needed_arg arg;
+- struct ata_ering_entry *ent;
+- int err_cat;
+- u64 j64;
+-
+- ent = ata_ering_top(&dev->ering);
+- if (!ent)
+- return 0;
+-
+- err_cat = ata_eh_categorize_ering_entry(ent);
+- if (err_cat == 0)
+- return 0;
+-
+- memset(&arg, 0, sizeof(arg));
+-
+- j64 = get_jiffies_64();
+- if (j64 >= interval)
+- arg.since = j64 - interval;
+- else
+- arg.since = 0;
+-
+- ata_ering_map(&dev->ering, speed_down_needed_cb, &arg);
+-
+- return arg.nr_errors[err_cat] > err_limits[err_cat];
+-}
+-
+-/**
+- * ata_eh_speed_down - record error and speed down if necessary
+- * @dev: Failed device
+- * @is_io: Did the device fail during normal IO?
+- * @err_mask: err_mask of the error
+- *
+- * Record error and examine error history to determine whether
+- * adjusting transmission speed is necessary. It also sets
+- * transmission limits appropriately if such adjustment is
+- * necessary.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise
+- */
+-static int ata_eh_speed_down(struct ata_device *dev, int is_io,
+- unsigned int err_mask)
+-{
+- if (!err_mask)
+- return 0;
+-
+- /* record error and determine whether speed down is necessary */
+- ata_ering_record(&dev->ering, is_io, err_mask);
+-
+- if (!ata_eh_speed_down_needed(dev))
+- return 0;
+-
+- /* speed down SATA link speed if possible */
+- if (sata_down_spd_limit(dev->ap) == 0)
+- return ATA_EH_HARDRESET;
+-
+- /* lower transfer mode */
+- if (ata_down_xfermask_limit(dev, 0) == 0)
+- return ATA_EH_SOFTRESET;
+-
+- ata_dev_printk(dev, KERN_ERR,
+- "speed down requested but no transfer mode left\n");
+- return 0;
+-}
+-
+-/**
+- * ata_eh_autopsy - analyze error and determine recovery action
+- * @ap: ATA port to perform autopsy on
+- *
+- * Analyze why @ap failed and determine which recovery action is
+- * needed. This function also sets more detailed AC_ERR_* values
+- * and fills sense data for ATAPI CHECK SENSE.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-static void ata_eh_autopsy(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- unsigned int all_err_mask = 0;
+- int tag, is_io = 0;
+- u32 serror;
+- int rc;
+-
+- DPRINTK("ENTER\n");
+-
+- if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+- return;
+-
+- /* obtain and analyze SError */
+- rc = sata_scr_read(ap, SCR_ERROR, &serror);
+- if (rc == 0) {
+- ehc->i.serror |= serror;
+- ata_eh_analyze_serror(ap);
+- } else if (rc != -EOPNOTSUPP)
+- ehc->i.action |= ATA_EH_HARDRESET;
+-
+- /* analyze NCQ failure */
+- ata_eh_analyze_ncq_error(ap);
+-
+- /* any real error trumps AC_ERR_OTHER */
+- if (ehc->i.err_mask & ~AC_ERR_OTHER)
+- ehc->i.err_mask &= ~AC_ERR_OTHER;
+-
+- all_err_mask |= ehc->i.err_mask;
+-
+- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+-
+- if (!(qc->flags & ATA_QCFLAG_FAILED))
+- continue;
+-
+- /* inherit upper level err_mask */
+- qc->err_mask |= ehc->i.err_mask;
+-
+- /* analyze TF */
+- ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
+-
+- /* DEV errors are probably spurious in case of ATA_BUS error */
+- if (qc->err_mask & AC_ERR_ATA_BUS)
+- qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA |
+- AC_ERR_INVALID);
+-
+- /* any real error trumps unknown error */
+- if (qc->err_mask & ~AC_ERR_OTHER)
+- qc->err_mask &= ~AC_ERR_OTHER;
+-
+- /* SENSE_VALID trumps dev/unknown error and revalidation */
+- if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+- qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
+- ehc->i.action &= ~ATA_EH_REVALIDATE;
+- }
+-
+- /* accumulate error info */
+- ehc->i.dev = qc->dev;
+- all_err_mask |= qc->err_mask;
+- if (qc->flags & ATA_QCFLAG_IO)
+- is_io = 1;
+- }
+-
+- /* enforce default EH actions */
+- if (ap->pflags & ATA_PFLAG_FROZEN ||
+- all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
+- ehc->i.action |= ATA_EH_SOFTRESET;
+- else if (all_err_mask)
+- ehc->i.action |= ATA_EH_REVALIDATE;
+-
+- /* if we have offending qcs and the associated failed device */
+- if (ehc->i.dev) {
+- /* speed down */
+- ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
+- all_err_mask);
+-
+- /* perform per-dev EH action only on the offending device */
+- ehc->i.dev_action[ehc->i.dev->devno] |=
+- ehc->i.action & ATA_EH_PERDEV_MASK;
+- ehc->i.action &= ~ATA_EH_PERDEV_MASK;
+- }
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_eh_report - report error handling to user
+- * @ap: ATA port EH is going on
+- *
+- * Report EH to user.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_eh_report(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- const char *frozen, *desc;
+- int tag, nr_failed = 0;
+-
+- desc = NULL;
+- if (ehc->i.desc[0] != '\0')
+- desc = ehc->i.desc;
+-
+- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+-
+- if (!(qc->flags & ATA_QCFLAG_FAILED))
+- continue;
+- if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
+- continue;
+-
+- nr_failed++;
+- }
+-
+- if (!nr_failed && !ehc->i.err_mask)
+- return;
+-
+- frozen = "";
+- if (ap->pflags & ATA_PFLAG_FROZEN)
+- frozen = " frozen";
+-
+- if (ehc->i.dev) {
+- ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
+- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+- ehc->i.err_mask, ap->sactive, ehc->i.serror,
+- ehc->i.action, frozen);
+- if (desc)
+- ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+- } else {
+- ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
+- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+- ehc->i.err_mask, ap->sactive, ehc->i.serror,
+- ehc->i.action, frozen);
+- if (desc)
+- ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+- }
+-
+- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+-
+- if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+- continue;
+-
+- ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
+- "Emask 0x%x stat 0x%x err 0x%x (%s)\n",
+- qc->tag, qc->tf.command, qc->err_mask,
+- qc->result_tf.command, qc->result_tf.feature,
+- ata_err_string(qc->err_mask));
+- }
+-}
+-
+-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+- unsigned int *classes)
+-{
+- int i, rc;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- classes[i] = ATA_DEV_UNKNOWN;
+-
+- rc = reset(ap, classes);
+- if (rc)
+- return rc;
+-
+- /* If any class isn't ATA_DEV_UNKNOWN, consider classification
+- * is complete and convert all ATA_DEV_UNKNOWN to
+- * ATA_DEV_NONE.
+- */
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- if (classes[i] != ATA_DEV_UNKNOWN)
+- break;
+-
+- if (i < ATA_MAX_DEVICES)
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- if (classes[i] == ATA_DEV_UNKNOWN)
+- classes[i] = ATA_DEV_NONE;
+-
+- return 0;
+-}
+-
+-static int ata_eh_followup_srst_needed(int rc, int classify,
+- const unsigned int *classes)
+-{
+- if (rc == -EAGAIN)
+- return 1;
+- if (rc != 0)
+- return 0;
+- if (classify && classes[0] == ATA_DEV_UNKNOWN)
+- return 1;
+- return 0;
+-}
+-
+-static int ata_eh_reset(struct ata_port *ap, int classify,
+- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- unsigned int *classes = ehc->classes;
+- int tries = ATA_EH_RESET_TRIES;
+- int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
+- unsigned int action;
+- ata_reset_fn_t reset;
+- int i, did_followup_srst, rc;
+-
+- /* about to reset */
+- ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+-
+- /* Determine which reset to use and record in ehc->i.action.
+- * prereset() may examine and modify it.
+- */
+- action = ehc->i.action;
+- ehc->i.action &= ~ATA_EH_RESET_MASK;
+- if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+- !(action & ATA_EH_HARDRESET))))
+- ehc->i.action |= ATA_EH_SOFTRESET;
+- else
+- ehc->i.action |= ATA_EH_HARDRESET;
+-
+- if (prereset) {
+- rc = prereset(ap);
+- if (rc) {
+- ata_port_printk(ap, KERN_ERR,
+- "prereset failed (errno=%d)\n", rc);
+- return rc;
+- }
+- }
+-
+- /* prereset() might have modified ehc->i.action */
+- if (ehc->i.action & ATA_EH_HARDRESET)
+- reset = hardreset;
+- else if (ehc->i.action & ATA_EH_SOFTRESET)
+- reset = softreset;
+- else {
+- /* prereset told us not to reset, bang classes and return */
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- classes[i] = ATA_DEV_NONE;
+- return 0;
+- }
+-
+- /* did prereset() screw up? if so, fix up to avoid oopsing */
+- if (!reset) {
+- ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
+- "invalid reset type\n");
+- if (softreset)
+- reset = softreset;
+- else
+- reset = hardreset;
+- }
+-
+- retry:
+- /* shut up during boot probing */
+- if (verbose)
+- ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+- reset == softreset ? "soft" : "hard");
+-
+- /* mark that this EH session started with reset */
+- ehc->i.flags |= ATA_EHI_DID_RESET;
+-
+- rc = ata_do_reset(ap, reset, classes);
+-
+- did_followup_srst = 0;
+- if (reset == hardreset &&
+- ata_eh_followup_srst_needed(rc, classify, classes)) {
+- /* okay, let's do follow-up softreset */
+- did_followup_srst = 1;
+- reset = softreset;
+-
+- if (!reset) {
+- ata_port_printk(ap, KERN_ERR,
+- "follow-up softreset required "
+- "but no softreset avaliable\n");
+- return -EINVAL;
+- }
+-
+- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+- rc = ata_do_reset(ap, reset, classes);
+-
+- if (rc == 0 && classify &&
+- classes[0] == ATA_DEV_UNKNOWN) {
+- ata_port_printk(ap, KERN_ERR,
+- "classification failed\n");
+- return -EINVAL;
+- }
+- }
+-
+- if (rc && --tries) {
+- const char *type;
+-
+- if (reset == softreset) {
+- if (did_followup_srst)
+- type = "follow-up soft";
+- else
+- type = "soft";
+- } else
+- type = "hard";
+-
+- ata_port_printk(ap, KERN_WARNING,
+- "%sreset failed, retrying in 5 secs\n", type);
+- ssleep(5);
+-
+- if (reset == hardreset)
+- sata_down_spd_limit(ap);
+- if (hardreset)
+- reset = hardreset;
+- goto retry;
+- }
+-
+- if (rc == 0) {
+- /* After the reset, the device state is PIO 0 and the
+- * controller state is undefined. Record the mode.
+- */
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ap->device[i].pio_mode = XFER_PIO_0;
+-
+- if (postreset)
+- postreset(ap, classes);
+-
+- /* reset successful, schedule revalidation */
+- ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+- ehc->i.action |= ATA_EH_REVALIDATE;
+- }
+-
+- return rc;
+-}
+-
+-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+- struct ata_device **r_failed_dev)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- struct ata_device *dev;
+- unsigned long flags;
+- int i, rc = 0;
+-
+- DPRINTK("ENTER\n");
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- unsigned int action;
+-
+- dev = &ap->device[i];
+- action = ata_eh_dev_action(dev);
+-
+- if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
+- if (ata_port_offline(ap)) {
+- rc = -EIO;
+- break;
+- }
+-
+- ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
+- rc = ata_dev_revalidate(dev,
+- ehc->i.flags & ATA_EHI_DID_RESET);
+- if (rc)
+- break;
+-
+- ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+-
+- /* schedule the scsi_rescan_device() here */
+- queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
+- } else if (dev->class == ATA_DEV_UNKNOWN &&
+- ehc->tries[dev->devno] &&
+- ata_class_enabled(ehc->classes[dev->devno])) {
+- dev->class = ehc->classes[dev->devno];
+-
+- rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+- if (rc == 0)
+- rc = ata_dev_configure(dev, 1);
+-
+- if (rc) {
+- dev->class = ATA_DEV_UNKNOWN;
+- break;
+- }
+-
+- spin_lock_irqsave(ap->lock, flags);
+- ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
+- spin_unlock_irqrestore(ap->lock, flags);
+- }
+- }
+-
+- if (rc)
+- *r_failed_dev = dev;
+-
+- DPRINTK("EXIT\n");
+- return rc;
+-}
+-
+-/**
+- * ata_eh_suspend - handle suspend EH action
+- * @ap: target host port
+- * @r_failed_dev: result parameter to indicate failing device
+- *
+- * Handle suspend EH action. Disk devices are spinned down and
+- * other types of devices are just marked suspended. Once
+- * suspended, no EH action to the device is allowed until it is
+- * resumed.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise
+- */
+-static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+-{
+- struct ata_device *dev;
+- int i, rc = 0;
+-
+- DPRINTK("ENTER\n");
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- unsigned long flags;
+- unsigned int action, err_mask;
+-
+- dev = &ap->device[i];
+- action = ata_eh_dev_action(dev);
+-
+- if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
+- continue;
+-
+- WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
+-
+- ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+-
+- if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+- /* flush cache */
+- rc = ata_flush_cache(dev);
+- if (rc)
+- break;
+-
+- /* spin down */
+- err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+- if (err_mask) {
+- ata_dev_printk(dev, KERN_ERR, "failed to "
+- "spin down (err_mask=0x%x)\n",
+- err_mask);
+- rc = -EIO;
+- break;
+- }
+- }
+-
+- spin_lock_irqsave(ap->lock, flags);
+- dev->flags |= ATA_DFLAG_SUSPENDED;
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+- }
+-
+- if (rc)
+- *r_failed_dev = dev;
+-
+- DPRINTK("EXIT\n");
+- return 0;
+-}
+-
+-/**
+- * ata_eh_prep_resume - prep for resume EH action
+- * @ap: target host port
+- *
+- * Clear SUSPENDED in preparation for scheduled resume actions.
+- * This allows other parts of EH to access the devices being
+- * resumed.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-static void ata_eh_prep_resume(struct ata_port *ap)
+-{
+- struct ata_device *dev;
+- unsigned long flags;
+- int i;
+-
+- DPRINTK("ENTER\n");
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- unsigned int action;
+-
+- dev = &ap->device[i];
+- action = ata_eh_dev_action(dev);
+-
+- if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+- continue;
+-
+- spin_lock_irqsave(ap->lock, flags);
+- dev->flags &= ~ATA_DFLAG_SUSPENDED;
+- spin_unlock_irqrestore(ap->lock, flags);
+- }
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_eh_resume - handle resume EH action
+- * @ap: target host port
+- * @r_failed_dev: result parameter to indicate failing device
+- *
+- * Handle resume EH action. Target devices are already reset and
+- * revalidated. Spinning up is the only operation left.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise
+- */
+-static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+-{
+- struct ata_device *dev;
+- int i, rc = 0;
+-
+- DPRINTK("ENTER\n");
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- unsigned int action, err_mask;
+-
+- dev = &ap->device[i];
+- action = ata_eh_dev_action(dev);
+-
+- if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+- continue;
+-
+- ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+-
+- if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+- err_mask = ata_do_simple_cmd(dev,
+- ATA_CMD_IDLEIMMEDIATE);
+- if (err_mask) {
+- ata_dev_printk(dev, KERN_ERR, "failed to "
+- "spin up (err_mask=0x%x)\n",
+- err_mask);
+- rc = -EIO;
+- break;
+- }
+- }
+-
+- ata_eh_done(ap, dev, ATA_EH_RESUME);
+- }
+-
+- if (rc)
+- *r_failed_dev = dev;
+-
+- DPRINTK("EXIT\n");
+- return 0;
+-}
+-
+-static int ata_port_nr_enabled(struct ata_port *ap)
+-{
+- int i, cnt = 0;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- if (ata_dev_enabled(&ap->device[i]))
+- cnt++;
+- return cnt;
+-}
+-
+-static int ata_port_nr_vacant(struct ata_port *ap)
+-{
+- int i, cnt = 0;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- if (ap->device[i].class == ATA_DEV_UNKNOWN)
+- cnt++;
+- return cnt;
+-}
+-
+-static int ata_eh_skip_recovery(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- int i;
+-
+- /* skip if all possible devices are suspended */
+- for (i = 0; i < ata_port_max_devices(ap); i++) {
+- struct ata_device *dev = &ap->device[i];
+-
+- if (!(dev->flags & ATA_DFLAG_SUSPENDED))
+- break;
+- }
+-
+- if (i == ata_port_max_devices(ap))
+- return 1;
+-
+- /* thaw frozen port, resume link and recover failed devices */
+- if ((ap->pflags & ATA_PFLAG_FROZEN) ||
+- (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+- return 0;
+-
+- /* skip if class codes for all vacant slots are ATA_DEV_NONE */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *dev = &ap->device[i];
+-
+- if (dev->class == ATA_DEV_UNKNOWN &&
+- ehc->classes[dev->devno] != ATA_DEV_NONE)
+- return 0;
+- }
+-
+- return 1;
+-}
+-
+-/**
+- * ata_eh_recover - recover host port after error
+- * @ap: host port to recover
+- * @prereset: prereset method (can be NULL)
+- * @softreset: softreset method (can be NULL)
+- * @hardreset: hardreset method (can be NULL)
+- * @postreset: postreset method (can be NULL)
+- *
+- * This is the alpha and omega, eum and yang, heart and soul of
+- * libata exception handling. On entry, actions required to
+- * recover the port and hotplug requests are recorded in
+- * eh_context. This function executes all the operations with
+- * appropriate retrials and fallbacks to resurrect failed
+- * devices, detach goners and greet newcomers.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno on failure.
+- */
+-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+- ata_postreset_fn_t postreset)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- struct ata_device *dev;
+- int down_xfermask, i, rc;
+-
+- DPRINTK("ENTER\n");
+-
+- /* prep for recovery */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+-
+- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+-
+- /* process hotplug request */
+- if (dev->flags & ATA_DFLAG_DETACH)
+- ata_eh_detach_dev(dev);
+-
+- if (!ata_dev_enabled(dev) &&
+- ((ehc->i.probe_mask & (1 << dev->devno)) &&
+- !(ehc->did_probe_mask & (1 << dev->devno)))) {
+- ata_eh_detach_dev(dev);
+- ata_dev_init(dev);
+- ehc->did_probe_mask |= (1 << dev->devno);
+- ehc->i.action |= ATA_EH_SOFTRESET;
+- }
+- }
+-
+- retry:
+- down_xfermask = 0;
+- rc = 0;
+-
+- /* if UNLOADING, finish immediately */
+- if (ap->pflags & ATA_PFLAG_UNLOADING)
+- goto out;
+-
+- /* prep for resume */
+- ata_eh_prep_resume(ap);
+-
+- /* skip EH if possible. */
+- if (ata_eh_skip_recovery(ap))
+- ehc->i.action = 0;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ehc->classes[i] = ATA_DEV_UNKNOWN;
+-
+- /* reset */
+- if (ehc->i.action & ATA_EH_RESET_MASK) {
+- ata_eh_freeze_port(ap);
+-
+- rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
+- softreset, hardreset, postreset);
+- if (rc) {
+- ata_port_printk(ap, KERN_ERR,
+- "reset failed, giving up\n");
+- goto out;
+- }
+-
+- ata_eh_thaw_port(ap);
+- }
+-
+- /* revalidate existing devices and attach new ones */
+- rc = ata_eh_revalidate_and_attach(ap, &dev);
+- if (rc)
+- goto dev_fail;
+-
+- /* resume devices */
+- rc = ata_eh_resume(ap, &dev);
+- if (rc)
+- goto dev_fail;
+-
+- /* configure transfer mode if the port has been reset */
+- if (ehc->i.flags & ATA_EHI_DID_RESET) {
+- rc = ata_set_mode(ap, &dev);
+- if (rc) {
+- down_xfermask = 1;
+- goto dev_fail;
+- }
+- }
+-
+- /* suspend devices */
+- rc = ata_eh_suspend(ap, &dev);
+- if (rc)
+- goto dev_fail;
+-
+- goto out;
+-
+- dev_fail:
+- switch (rc) {
+- case -ENODEV:
+- /* device missing, schedule probing */
+- ehc->i.probe_mask |= (1 << dev->devno);
+- case -EINVAL:
+- ehc->tries[dev->devno] = 0;
+- break;
+- case -EIO:
+- sata_down_spd_limit(ap);
+- default:
+- ehc->tries[dev->devno]--;
+- if (down_xfermask &&
+- ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
+- ehc->tries[dev->devno] = 0;
+- }
+-
+- if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
+- /* disable device if it has used up all its chances */
+- ata_dev_disable(dev);
+-
+- /* detach if offline */
+- if (ata_port_offline(ap))
+- ata_eh_detach_dev(dev);
+-
+- /* probe if requested */
+- if ((ehc->i.probe_mask & (1 << dev->devno)) &&
+- !(ehc->did_probe_mask & (1 << dev->devno))) {
+- ata_eh_detach_dev(dev);
+- ata_dev_init(dev);
+-
+- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+- ehc->did_probe_mask |= (1 << dev->devno);
+- ehc->i.action |= ATA_EH_SOFTRESET;
+- }
+- } else {
+- /* soft didn't work? be haaaaard */
+- if (ehc->i.flags & ATA_EHI_DID_RESET)
+- ehc->i.action |= ATA_EH_HARDRESET;
+- else
+- ehc->i.action |= ATA_EH_SOFTRESET;
+- }
+-
+- if (ata_port_nr_enabled(ap)) {
+- ata_port_printk(ap, KERN_WARNING, "failed to recover some "
+- "devices, retrying in 5 secs\n");
+- ssleep(5);
+- } else {
+- /* no device left, repeat fast */
+- msleep(500);
+- }
+-
+- goto retry;
+-
+- out:
+- if (rc) {
+- for (i = 0; i < ATA_MAX_DEVICES; i++)
+- ata_dev_disable(&ap->device[i]);
+- }
+-
+- DPRINTK("EXIT, rc=%d\n", rc);
+- return rc;
+-}
+-
+-/**
+- * ata_eh_finish - finish up EH
+- * @ap: host port to finish EH for
+- *
+- * Recovery is complete. Clean up EH states and retry or finish
+- * failed qcs.
+- *
+- * LOCKING:
+- * None.
+- */
+-static void ata_eh_finish(struct ata_port *ap)
+-{
+- int tag;
+-
+- /* retry or finish qcs */
+- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+-
+- if (!(qc->flags & ATA_QCFLAG_FAILED))
+- continue;
+-
+- if (qc->err_mask) {
+- /* FIXME: Once EH migration is complete,
+- * generate sense data in this function,
+- * considering both err_mask and tf.
+- */
+- if (qc->err_mask & AC_ERR_INVALID)
+- ata_eh_qc_complete(qc);
+- else
+- ata_eh_qc_retry(qc);
+- } else {
+- if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+- ata_eh_qc_complete(qc);
+- } else {
+- /* feed zero TF to sense generation */
+- memset(&qc->result_tf, 0, sizeof(qc->result_tf));
+- ata_eh_qc_retry(qc);
+- }
+- }
+- }
+-}
+-
+-/**
+- * ata_do_eh - do standard error handling
+- * @ap: host port to handle error for
+- * @prereset: prereset method (can be NULL)
+- * @softreset: softreset method (can be NULL)
+- * @hardreset: hardreset method (can be NULL)
+- * @postreset: postreset method (can be NULL)
+- *
+- * Perform standard error handling sequence.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+- ata_postreset_fn_t postreset)
+-{
+- ata_eh_autopsy(ap);
+- ata_eh_report(ap);
+- ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+- ata_eh_finish(ap);
+-}
+-
+-/**
+- * ata_eh_handle_port_suspend - perform port suspend operation
+- * @ap: port to suspend
+- *
+- * Suspend @ap.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-static void ata_eh_handle_port_suspend(struct ata_port *ap)
+-{
+- unsigned long flags;
+- int rc = 0;
+-
+- /* are we suspending? */
+- spin_lock_irqsave(ap->lock, flags);
+- if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+- ap->pm_mesg.event == PM_EVENT_ON) {
+- spin_unlock_irqrestore(ap->lock, flags);
+- return;
+- }
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+-
+- /* suspend */
+- ata_eh_freeze_port(ap);
+-
+- if (ap->ops->port_suspend)
+- rc = ap->ops->port_suspend(ap, ap->pm_mesg);
+-
+- /* report result */
+- spin_lock_irqsave(ap->lock, flags);
+-
+- ap->pflags &= ~ATA_PFLAG_PM_PENDING;
+- if (rc == 0)
+- ap->pflags |= ATA_PFLAG_SUSPENDED;
+- else
+- ata_port_schedule_eh(ap);
+-
+- if (ap->pm_result) {
+- *ap->pm_result = rc;
+- ap->pm_result = NULL;
+- }
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- return;
+-}
+-
+-/**
+- * ata_eh_handle_port_resume - perform port resume operation
+- * @ap: port to resume
+- *
+- * Resume @ap.
+- *
+- * This function also waits upto one second until all devices
+- * hanging off this port requests resume EH action. This is to
+- * prevent invoking EH and thus reset multiple times on resume.
+- *
+- * On DPM resume, where some of devices might not be resumed
+- * together, this may delay port resume upto one second, but such
+- * DPM resumes are rare and 1 sec delay isn't too bad.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-static void ata_eh_handle_port_resume(struct ata_port *ap)
+-{
+- unsigned long timeout;
+- unsigned long flags;
+- int i, rc = 0;
+-
+- /* are we resuming? */
+- spin_lock_irqsave(ap->lock, flags);
+- if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+- ap->pm_mesg.event != PM_EVENT_ON) {
+- spin_unlock_irqrestore(ap->lock, flags);
+- return;
+- }
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* spurious? */
+- if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
+- goto done;
+-
+- if (ap->ops->port_resume)
+- rc = ap->ops->port_resume(ap);
+-
+- /* give devices time to request EH */
+- timeout = jiffies + HZ; /* 1s max */
+- while (1) {
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *dev = &ap->device[i];
+- unsigned int action = ata_eh_dev_action(dev);
+-
+- if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+- !(action & ATA_EH_RESUME))
+- break;
+- }
+-
+- if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+- break;
+- msleep(10);
+- }
+-
+- done:
+- spin_lock_irqsave(ap->lock, flags);
+- ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+- if (ap->pm_result) {
+- *ap->pm_result = rc;
+- ap->pm_result = NULL;
+- }
+- spin_unlock_irqrestore(ap->lock, flags);
+-}
+diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
+deleted file mode 100644
+index e92c31d..0000000
+--- a/drivers/scsi/libata-scsi.c
++++ /dev/null
+@@ -1,3173 +0,0 @@
+-/*
+- * libata-scsi.c - helper library for ATA
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+- * Copyright 2003-2004 Jeff Garzik
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available from
+- * - http://www.t10.org/
+- * - http://www.t13.org/
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/blkdev.h>
+-#include <linux/spinlock.h>
+-#include <scsi/scsi.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <scsi/scsi_eh.h>
+-#include <scsi/scsi_device.h>
+-#include <scsi/scsi_tcq.h>
+-#include <scsi/scsi_transport.h>
+-#include <linux/libata.h>
+-#include <linux/hdreg.h>
+-#include <asm/uaccess.h>
+-
+-#include "libata.h"
+-
+-#define SECTOR_SIZE 512
+-
+-typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
+-
+-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+- const struct scsi_device *scsidev);
+-static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
+- const struct scsi_device *scsidev);
+-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+- unsigned int id, unsigned int lun);
+-
+-
+-#define RW_RECOVERY_MPAGE 0x1
+-#define RW_RECOVERY_MPAGE_LEN 12
+-#define CACHE_MPAGE 0x8
+-#define CACHE_MPAGE_LEN 20
+-#define CONTROL_MPAGE 0xa
+-#define CONTROL_MPAGE_LEN 12
+-#define ALL_MPAGES 0x3f
+-#define ALL_SUB_MPAGES 0xff
+-
+-
+-static const u8 def_rw_recovery_mpage[] = {
+- RW_RECOVERY_MPAGE,
+- RW_RECOVERY_MPAGE_LEN - 2,
+- (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
+- (1 << 6), /* ARRE (auto read reallocation) */
+- 0, /* read retry count */
+- 0, 0, 0, 0,
+- 0, /* write retry count */
+- 0, 0, 0
+-};
+-
+-static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = {
+- CACHE_MPAGE,
+- CACHE_MPAGE_LEN - 2,
+- 0, /* contains WCE, needs to be 0 for logic */
+- 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, /* contains DRA, needs to be 0 for logic */
+- 0, 0, 0, 0, 0, 0, 0
+-};
+-
+-static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
+- CONTROL_MPAGE,
+- CONTROL_MPAGE_LEN - 2,
+- 2, /* DSENSE=0, GLTSD=1 */
+- 0, /* [QAM+QERR may be 1, see 05-359r1] */
+- 0, 0, 0, 0, 0xff, 0xff,
+- 0, 30 /* extended self test time, see 05-359r1 */
+-};
+-
+-/*
+- * libata transport template. libata doesn't do real transport stuff.
+- * It just needs the eh_timed_out hook.
+- */
+-struct scsi_transport_template ata_scsi_transport_template = {
+- .eh_strategy_handler = ata_scsi_error,
+- .eh_timed_out = ata_scsi_timed_out,
+- .user_scan = ata_scsi_user_scan,
+-};
+-
+-
+-static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
+- void (*done)(struct scsi_cmnd *))
+-{
+- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+- /* "Invalid field in cbd" */
+- done(cmd);
+-}
+-
+-/**
+- * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
+- * @sdev: SCSI device for which BIOS geometry is to be determined
+- * @bdev: block device associated with @sdev
+- * @capacity: capacity of SCSI device
+- * @geom: location to which geometry will be output
+- *
+- * Generic bios head/sector/cylinder calculator
+- * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS)
+- * mapping. Some situations may arise where the disk is not
+- * bootable if this is not used.
+- *
+- * LOCKING:
+- * Defined by the SCSI layer. We don't really care.
+- *
+- * RETURNS:
+- * Zero.
+- */
+-int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+- sector_t capacity, int geom[])
+-{
+- geom[0] = 255;
+- geom[1] = 63;
+- sector_div(capacity, 255*63);
+- geom[2] = capacity;
+-
+- return 0;
+-}
+-
+-/**
+- * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
+- * @scsidev: Device to which we are issuing command
+- * @arg: User provided data for issuing command
+- *
+- * LOCKING:
+- * Defined by the SCSI layer. We don't really care.
+- *
+- * RETURNS:
+- * Zero on success, negative errno on error.
+- */
+-
+-int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
+-{
+- int rc = 0;
+- u8 scsi_cmd[MAX_COMMAND_SIZE];
+- u8 args[4], *argbuf = NULL;
+- int argsize = 0;
+- struct scsi_sense_hdr sshdr;
+- enum dma_data_direction data_dir;
+-
+- if (arg == NULL)
+- return -EINVAL;
+-
+- if (copy_from_user(args, arg, sizeof(args)))
+- return -EFAULT;
+-
+- memset(scsi_cmd, 0, sizeof(scsi_cmd));
+-
+- if (args[3]) {
+- argsize = SECTOR_SIZE * args[3];
+- argbuf = kmalloc(argsize, GFP_KERNEL);
+- if (argbuf == NULL) {
+- rc = -ENOMEM;
+- goto error;
+- }
+-
+- scsi_cmd[1] = (4 << 1); /* PIO Data-in */
+- scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
+- block count in sector count field */
+- data_dir = DMA_FROM_DEVICE;
+- } else {
+- scsi_cmd[1] = (3 << 1); /* Non-data */
+- /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
+- data_dir = DMA_NONE;
+- }
+-
+- scsi_cmd[0] = ATA_16;
+-
+- scsi_cmd[4] = args[2];
+- if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
+- scsi_cmd[6] = args[3];
+- scsi_cmd[8] = args[1];
+- scsi_cmd[10] = 0x4f;
+- scsi_cmd[12] = 0xc2;
+- } else {
+- scsi_cmd[6] = args[1];
+- }
+- scsi_cmd[14] = args[0];
+-
+- /* Good values for timeout and retries? Values below
+- from scsi_ioctl_send_command() for default case... */
+- if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize,
+- &sshdr, (10*HZ), 5)) {
+- rc = -EIO;
+- goto error;
+- }
+-
+- /* Need code to retrieve data from check condition? */
+-
+- if ((argbuf)
+- && copy_to_user(arg + sizeof(args), argbuf, argsize))
+- rc = -EFAULT;
+-error:
+- kfree(argbuf);
+- return rc;
+-}
+-
+-/**
+- * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
+- * @scsidev: Device to which we are issuing command
+- * @arg: User provided data for issuing command
+- *
+- * LOCKING:
+- * Defined by the SCSI layer. We don't really care.
+- *
+- * RETURNS:
+- * Zero on success, negative errno on error.
+- */
+-int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
+-{
+- int rc = 0;
+- u8 scsi_cmd[MAX_COMMAND_SIZE];
+- u8 args[7];
+- struct scsi_sense_hdr sshdr;
+-
+- if (arg == NULL)
+- return -EINVAL;
+-
+- if (copy_from_user(args, arg, sizeof(args)))
+- return -EFAULT;
+-
+- memset(scsi_cmd, 0, sizeof(scsi_cmd));
+- scsi_cmd[0] = ATA_16;
+- scsi_cmd[1] = (3 << 1); /* Non-data */
+- /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
+- scsi_cmd[4] = args[1];
+- scsi_cmd[6] = args[2];
+- scsi_cmd[8] = args[3];
+- scsi_cmd[10] = args[4];
+- scsi_cmd[12] = args[5];
+- scsi_cmd[14] = args[0];
+-
+- /* Good values for timeout and retries? Values below
+- from scsi_ioctl_send_command() for default case... */
+- if (scsi_execute_req(scsidev, scsi_cmd, DMA_NONE, NULL, 0, &sshdr,
+- (10*HZ), 5))
+- rc = -EIO;
+-
+- /* Need code to retrieve data from check condition? */
+- return rc;
+-}
+-
+-int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+-{
+- int val = -EINVAL, rc = -EINVAL;
+-
+- switch (cmd) {
+- case ATA_IOC_GET_IO32:
+- val = 0;
+- if (copy_to_user(arg, &val, 1))
+- return -EFAULT;
+- return 0;
+-
+- case ATA_IOC_SET_IO32:
+- val = (unsigned long) arg;
+- if (val != 0)
+- return -EINVAL;
+- return 0;
+-
+- case HDIO_DRIVE_CMD:
+- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+- return -EACCES;
+- return ata_cmd_ioctl(scsidev, arg);
+-
+- case HDIO_DRIVE_TASK:
+- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+- return -EACCES;
+- return ata_task_ioctl(scsidev, arg);
+-
+- default:
+- rc = -ENOTTY;
+- break;
+- }
+-
+- return rc;
+-}
+-
+-/**
+- * ata_scsi_qc_new - acquire new ata_queued_cmd reference
+- * @dev: ATA device to which the new command is attached
+- * @cmd: SCSI command that originated this ATA command
+- * @done: SCSI command completion function
+- *
+- * Obtain a reference to an unused ata_queued_cmd structure,
+- * which is the basic libata structure representing a single
+- * ATA command sent to the hardware.
+- *
+- * If a command was available, fill in the SCSI-specific
+- * portions of the structure with information on the
+- * current command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Command allocated, or %NULL if none available.
+- */
+-struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
+- struct scsi_cmnd *cmd,
+- void (*done)(struct scsi_cmnd *))
+-{
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_new_init(dev);
+- if (qc) {
+- qc->scsicmd = cmd;
+- qc->scsidone = done;
+-
+- if (cmd->use_sg) {
+- qc->__sg = (struct scatterlist *) cmd->request_buffer;
+- qc->n_elem = cmd->use_sg;
+- } else {
+- qc->__sg = &qc->sgent;
+- qc->n_elem = 1;
+- }
+- } else {
+- cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
+- done(cmd);
+- }
+-
+- return qc;
+-}
+-
+-/**
+- * ata_dump_status - user friendly display of error info
+- * @id: id of the port in question
+- * @tf: ptr to filled out taskfile
+- *
+- * Decode and dump the ATA error/status registers for the user so
+- * that they have some idea what really happened at the non
+- * make-believe layer.
+- *
+- * LOCKING:
+- * inherited from caller
+- */
+-void ata_dump_status(unsigned id, struct ata_taskfile *tf)
+-{
+- u8 stat = tf->command, err = tf->feature;
+-
+- printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat);
+- if (stat & ATA_BUSY) {
+- printk("Busy }\n"); /* Data is not valid in this case */
+- } else {
+- if (stat & 0x40) printk("DriveReady ");
+- if (stat & 0x20) printk("DeviceFault ");
+- if (stat & 0x10) printk("SeekComplete ");
+- if (stat & 0x08) printk("DataRequest ");
+- if (stat & 0x04) printk("CorrectedError ");
+- if (stat & 0x02) printk("Index ");
+- if (stat & 0x01) printk("Error ");
+- printk("}\n");
+-
+- if (err) {
+- printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err);
+- if (err & 0x04) printk("DriveStatusError ");
+- if (err & 0x80) {
+- if (err & 0x04) printk("BadCRC ");
+- else printk("Sector ");
+- }
+- if (err & 0x40) printk("UncorrectableError ");
+- if (err & 0x10) printk("SectorIdNotFound ");
+- if (err & 0x02) printk("TrackZeroNotFound ");
+- if (err & 0x01) printk("AddrMarkNotFound ");
+- printk("}\n");
+- }
+- }
+-}
+-
+-/**
+- * ata_scsi_device_suspend - suspend ATA device associated with sdev
+- * @sdev: the SCSI device to suspend
+- * @state: target power management state
+- *
+- * Request suspend EH action on the ATA device associated with
+- * @sdev and wait for the operation to complete.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
+-{
+- struct ata_port *ap = ata_shost_to_port(sdev->host);
+- struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+- unsigned long flags;
+- unsigned int action;
+- int rc = 0;
+-
+- if (!dev)
+- goto out;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* wait for the previous resume to complete */
+- while (dev->flags & ATA_DFLAG_SUSPENDED) {
+- spin_unlock_irqrestore(ap->lock, flags);
+- ata_port_wait_eh(ap);
+- spin_lock_irqsave(ap->lock, flags);
+- }
+-
+- /* if @sdev is already detached, nothing to do */
+- if (sdev->sdev_state == SDEV_OFFLINE ||
+- sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+- goto out_unlock;
+-
+- /* request suspend */
+- action = ATA_EH_SUSPEND;
+- if (state.event != PM_EVENT_SUSPEND)
+- action |= ATA_EH_PM_FREEZE;
+- ap->eh_info.dev_action[dev->devno] |= action;
+- ap->eh_info.flags |= ATA_EHI_QUIET;
+- ata_port_schedule_eh(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- /* wait for EH to do the job */
+- ata_port_wait_eh(ap);
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* If @sdev is still attached but the associated ATA device
+- * isn't suspended, the operation failed.
+- */
+- if (sdev->sdev_state != SDEV_OFFLINE &&
+- sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
+- !(dev->flags & ATA_DFLAG_SUSPENDED))
+- rc = -EIO;
+-
+- out_unlock:
+- spin_unlock_irqrestore(ap->lock, flags);
+- out:
+- if (rc == 0)
+- sdev->sdev_gendev.power.power_state = state;
+- return rc;
+-}
+-
+-/**
+- * ata_scsi_device_resume - resume ATA device associated with sdev
+- * @sdev: the SCSI device to resume
+- *
+- * Request resume EH action on the ATA device associated with
+- * @sdev and return immediately. This enables parallel
+- * wakeup/spinup of devices.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- *
+- * RETURNS:
+- * 0.
+- */
+-int ata_scsi_device_resume(struct scsi_device *sdev)
+-{
+- struct ata_port *ap = ata_shost_to_port(sdev->host);
+- struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+- struct ata_eh_info *ehi = &ap->eh_info;
+- unsigned long flags;
+- unsigned int action;
+-
+- if (!dev)
+- goto out;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* if @sdev is already detached, nothing to do */
+- if (sdev->sdev_state == SDEV_OFFLINE ||
+- sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+- goto out_unlock;
+-
+- /* request resume */
+- action = ATA_EH_RESUME;
+- if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
+- __ata_ehi_hotplugged(ehi);
+- else
+- action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
+- ehi->dev_action[dev->devno] |= action;
+-
+- /* We don't want autopsy and verbose EH messages. Disable
+- * those if we're the only device on this link.
+- */
+- if (ata_port_max_devices(ap) == 1)
+- ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+-
+- ata_port_schedule_eh(ap);
+-
+- out_unlock:
+- spin_unlock_irqrestore(ap->lock, flags);
+- out:
+- sdev->sdev_gendev.power.power_state = PMSG_ON;
+- return 0;
+-}
+-
+-/**
+- * ata_to_sense_error - convert ATA error to SCSI error
+- * @id: ATA device number
+- * @drv_stat: value contained in ATA status register
+- * @drv_err: value contained in ATA error register
+- * @sk: the sense key we'll fill out
+- * @asc: the additional sense code we'll fill out
+- * @ascq: the additional sense code qualifier we'll fill out
+- * @verbose: be verbose
+- *
+- * Converts an ATA error into a SCSI error. Fill out pointers to
+- * SK, ASC, and ASCQ bytes for later use in fixed or descriptor
+- * format sense blocks.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
+- u8 *ascq, int verbose)
+-{
+- int i;
+-
+- /* Based on the 3ware driver translation table */
+- static const unsigned char sense_table[][4] = {
+- /* BBD|ECC|ID|MAR */
+- {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
+- /* BBD|ECC|ID */
+- {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
+- /* ECC|MC|MARK */
+- {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error
+- /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */
+- {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error
+- /* MC|ID|ABRT|TRK0|MARK */
+- {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready
+- /* MCR|MARK */
+- {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready
+- /* Bad address mark */
+- {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field
+- /* TRK0 */
+- {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
+- /* Abort & !ICRC */
+- {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command
+- /* Media change request */
+- {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline
+- /* SRV */
+- {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found
+- /* Media change */
+- {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline
+- /* ECC */
+- {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error
+- /* BBD - block marked bad */
+- {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
+- {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+- };
+- static const unsigned char stat_table[][4] = {
+- /* Must be first because BUSY means no other bits valid */
+- {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now
+- {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault
+- {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now
+- {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered
+- {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+- };
+-
+- /*
+- * Is this an error we can process/parse
+- */
+- if (drv_stat & ATA_BUSY) {
+- drv_err = 0; /* Ignore the err bits, they're invalid */
+- }
+-
+- if (drv_err) {
+- /* Look for drv_err */
+- for (i = 0; sense_table[i][0] != 0xFF; i++) {
+- /* Look for best matches first */
+- if ((sense_table[i][0] & drv_err) ==
+- sense_table[i][0]) {
+- *sk = sense_table[i][1];
+- *asc = sense_table[i][2];
+- *ascq = sense_table[i][3];
+- goto translate_done;
+- }
+- }
+- /* No immediate match */
+- if (verbose)
+- printk(KERN_WARNING "ata%u: no sense translation for "
+- "error 0x%02x\n", id, drv_err);
+- }
+-
+- /* Fall back to interpreting status bits */
+- for (i = 0; stat_table[i][0] != 0xFF; i++) {
+- if (stat_table[i][0] & drv_stat) {
+- *sk = stat_table[i][1];
+- *asc = stat_table[i][2];
+- *ascq = stat_table[i][3];
+- goto translate_done;
+- }
+- }
+- /* No error? Undecoded? */
+- if (verbose)
+- printk(KERN_WARNING "ata%u: no sense translation for "
+- "status: 0x%02x\n", id, drv_stat);
+-
+- /* We need a sensible error return here, which is tricky, and one
+- that won't cause people to do things like return a disk wrongly */
+- *sk = ABORTED_COMMAND;
+- *asc = 0x00;
+- *ascq = 0x00;
+-
+- translate_done:
+- if (verbose)
+- printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
+- "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
+- id, drv_stat, drv_err, *sk, *asc, *ascq);
+- return;
+-}
+-
+-/*
+- * ata_gen_ata_desc_sense - Generate check condition sense block.
+- * @qc: Command that completed.
+- *
+- * This function is specific to the ATA descriptor format sense
+- * block specified for the ATA pass through commands. Regardless
+- * of whether the command errored or not, return a sense
+- * block. Copy all controller registers into the sense
+- * block. Clear sense key, ASC & ASCQ if there is no error.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
+-{
+- struct scsi_cmnd *cmd = qc->scsicmd;
+- struct ata_taskfile *tf = &qc->result_tf;
+- unsigned char *sb = cmd->sense_buffer;
+- unsigned char *desc = sb + 8;
+- int verbose = qc->ap->ops->error_handler == NULL;
+-
+- memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+-
+- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+-
+- /*
+- * Use ata_to_sense_error() to map status register bits
+- * onto sense key, asc & ascq.
+- */
+- if (qc->err_mask ||
+- tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
+- ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
+- &sb[1], &sb[2], &sb[3], verbose);
+- sb[1] &= 0x0f;
+- }
+-
+- /*
+- * Sense data is current and format is descriptor.
+- */
+- sb[0] = 0x72;
+-
+- desc[0] = 0x09;
+-
+- /*
+- * Set length of additional sense data.
+- * Since we only populate descriptor 0, the total
+- * length is the same (fixed) length as descriptor 0.
+- */
+- desc[1] = sb[7] = 14;
+-
+- /*
+- * Copy registers into sense buffer.
+- */
+- desc[2] = 0x00;
+- desc[3] = tf->feature; /* == error reg */
+- desc[5] = tf->nsect;
+- desc[7] = tf->lbal;
+- desc[9] = tf->lbam;
+- desc[11] = tf->lbah;
+- desc[12] = tf->device;
+- desc[13] = tf->command; /* == status reg */
+-
+- /*
+- * Fill in Extend bit, and the high order bytes
+- * if applicable.
+- */
+- if (tf->flags & ATA_TFLAG_LBA48) {
+- desc[2] |= 0x01;
+- desc[4] = tf->hob_nsect;
+- desc[6] = tf->hob_lbal;
+- desc[8] = tf->hob_lbam;
+- desc[10] = tf->hob_lbah;
+- }
+-}
+-
+-/**
+- * ata_gen_fixed_sense - generate a SCSI fixed sense block
+- * @qc: Command that we are erroring out
+- *
+- * Leverage ata_to_sense_error() to give us the codes. Fit our
+- * LBA in here if there's room.
+- *
+- * LOCKING:
+- * inherited from caller
+- */
+-void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
+-{
+- struct scsi_cmnd *cmd = qc->scsicmd;
+- struct ata_taskfile *tf = &qc->result_tf;
+- unsigned char *sb = cmd->sense_buffer;
+- int verbose = qc->ap->ops->error_handler == NULL;
+-
+- memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+-
+- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+-
+- /*
+- * Use ata_to_sense_error() to map status register bits
+- * onto sense key, asc & ascq.
+- */
+- if (qc->err_mask ||
+- tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
+- ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
+- &sb[2], &sb[12], &sb[13], verbose);
+- sb[2] &= 0x0f;
+- }
+-
+- sb[0] = 0x70;
+- sb[7] = 0x0a;
+-
+- if (tf->flags & ATA_TFLAG_LBA48) {
+- /* TODO: find solution for LBA48 descriptors */
+- }
+-
+- else if (tf->flags & ATA_TFLAG_LBA) {
+- /* A small (28b) LBA will fit in the 32b info field */
+- sb[0] |= 0x80; /* set valid bit */
+- sb[3] = tf->device & 0x0f;
+- sb[4] = tf->lbah;
+- sb[5] = tf->lbam;
+- sb[6] = tf->lbal;
+- }
+-
+- else {
+- /* TODO: C/H/S */
+- }
+-}
+-
+-static void ata_scsi_sdev_config(struct scsi_device *sdev)
+-{
+- sdev->use_10_for_rw = 1;
+- sdev->use_10_for_ms = 1;
+-}
+-
+-static void ata_scsi_dev_config(struct scsi_device *sdev,
+- struct ata_device *dev)
+-{
+- unsigned int max_sectors;
+-
+- /* TODO: 2048 is an arbitrary number, not the
+- * hardware maximum. This should be increased to
+- * 65534 when Jens Axboe's patch for dynamically
+- * determining max_sectors is merged.
+- */
+- max_sectors = ATA_MAX_SECTORS;
+- if (dev->flags & ATA_DFLAG_LBA48)
+- max_sectors = ATA_MAX_SECTORS_LBA48;
+- if (dev->max_sectors)
+- max_sectors = dev->max_sectors;
+-
+- blk_queue_max_sectors(sdev->request_queue, max_sectors);
+-
+- /*
+- * SATA DMA transfers must be multiples of 4 byte, so
+- * we need to pad ATAPI transfers using an extra sg.
+- * Decrement max hw segments accordingly.
+- */
+- if (dev->class == ATA_DEV_ATAPI) {
+- request_queue_t *q = sdev->request_queue;
+- blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
+- }
+-
+- if (dev->flags & ATA_DFLAG_NCQ) {
+- int depth;
+-
+- depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+- depth = min(ATA_MAX_QUEUE - 1, depth);
+- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
+- }
+-}
+-
+-/**
+- * ata_scsi_slave_config - Set SCSI device attributes
+- * @sdev: SCSI device to examine
+- *
+- * This is called before we actually start reading
+- * and writing to the device, to configure certain
+- * SCSI mid-layer behaviors.
+- *
+- * LOCKING:
+- * Defined by SCSI layer. We don't really care.
+- */
+-
+-int ata_scsi_slave_config(struct scsi_device *sdev)
+-{
+- struct ata_port *ap = ata_shost_to_port(sdev->host);
+- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+-
+- ata_scsi_sdev_config(sdev);
+-
+- blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
+-
+- if (dev)
+- ata_scsi_dev_config(sdev, dev);
+-
+- return 0; /* scsi layer doesn't check return value, sigh */
+-}
+-
+-/**
+- * ata_scsi_slave_destroy - SCSI device is about to be destroyed
+- * @sdev: SCSI device to be destroyed
+- *
+- * @sdev is about to be destroyed for hot/warm unplugging. If
+- * this unplugging was initiated by libata as indicated by NULL
+- * dev->sdev, this function doesn't have to do anything.
+- * Otherwise, SCSI layer initiated warm-unplug is in progress.
+- * Clear dev->sdev, schedule the device for ATA detach and invoke
+- * EH.
+- *
+- * LOCKING:
+- * Defined by SCSI layer. We don't really care.
+- */
+-void ata_scsi_slave_destroy(struct scsi_device *sdev)
+-{
+- struct ata_port *ap = ata_shost_to_port(sdev->host);
+- unsigned long flags;
+- struct ata_device *dev;
+-
+- if (!ap->ops->error_handler)
+- return;
+-
+- spin_lock_irqsave(ap->lock, flags);
+- dev = __ata_scsi_find_dev(ap, sdev);
+- if (dev && dev->sdev) {
+- /* SCSI device already in CANCEL state, no need to offline it */
+- dev->sdev = NULL;
+- dev->flags |= ATA_DFLAG_DETACH;
+- ata_port_schedule_eh(ap);
+- }
+- spin_unlock_irqrestore(ap->lock, flags);
+-}
+-
+-/**
+- * ata_scsi_change_queue_depth - SCSI callback for queue depth config
+- * @sdev: SCSI device to configure queue depth for
+- * @queue_depth: new queue depth
+- *
+- * This is libata standard hostt->change_queue_depth callback.
+- * SCSI will call into this callback when user tries to set queue
+- * depth via sysfs.
+- *
+- * LOCKING:
+- * SCSI layer (we don't care)
+- *
+- * RETURNS:
+- * Newly configured queue depth.
+- */
+-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+-{
+- struct ata_port *ap = ata_shost_to_port(sdev->host);
+- struct ata_device *dev;
+- int max_depth;
+-
+- if (queue_depth < 1)
+- return sdev->queue_depth;
+-
+- dev = ata_scsi_find_dev(ap, sdev);
+- if (!dev || !ata_dev_enabled(dev))
+- return sdev->queue_depth;
+-
+- max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+- max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
+- if (queue_depth > max_depth)
+- queue_depth = max_depth;
+-
+- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+- return queue_depth;
+-}
+-
+-/**
+- * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
+- * @qc: Storage for translated ATA taskfile
+- * @scsicmd: SCSI command to translate
+- *
+- * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
+- * (to start). Perhaps these commands should be preceded by
+- * CHECK POWER MODE to see what power mode the device is already in.
+- * [See SAT revision 5 at www.t10.org]
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, non-zero on error.
+- */
+-
+-static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
+- const u8 *scsicmd)
+-{
+- struct ata_taskfile *tf = &qc->tf;
+-
+- tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+- tf->protocol = ATA_PROT_NODATA;
+- if (scsicmd[1] & 0x1) {
+- ; /* ignore IMMED bit, violates sat-r05 */
+- }
+- if (scsicmd[4] & 0x2)
+- goto invalid_fld; /* LOEJ bit set not supported */
+- if (((scsicmd[4] >> 4) & 0xf) != 0)
+- goto invalid_fld; /* power conditions not supported */
+- if (scsicmd[4] & 0x1) {
+- tf->nsect = 1; /* 1 sector, lba=0 */
+-
+- if (qc->dev->flags & ATA_DFLAG_LBA) {
+- tf->flags |= ATA_TFLAG_LBA;
+-
+- tf->lbah = 0x0;
+- tf->lbam = 0x0;
+- tf->lbal = 0x0;
+- tf->device |= ATA_LBA;
+- } else {
+- /* CHS */
+- tf->lbal = 0x1; /* sect */
+- tf->lbam = 0x0; /* cyl low */
+- tf->lbah = 0x0; /* cyl high */
+- }
+-
+- tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
+- } else {
+- tf->nsect = 0; /* time period value (0 implies now) */
+- tf->command = ATA_CMD_STANDBY;
+- /* Consider: ATA STANDBY IMMEDIATE command */
+- }
+- /*
+- * Standby and Idle condition timers could be implemented but that
+- * would require libata to implement the Power condition mode page
+- * and allow the user to change it. Changing mode pages requires
+- * MODE SELECT to be implemented.
+- */
+-
+- return 0;
+-
+-invalid_fld:
+- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+- /* "Invalid field in cbd" */
+- return 1;
+-}
+-
+-
+-/**
+- * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
+- * @qc: Storage for translated ATA taskfile
+- * @scsicmd: SCSI command to translate (ignored)
+- *
+- * Sets up an ATA taskfile to issue FLUSH CACHE or
+- * FLUSH CACHE EXT.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, non-zero on error.
+- */
+-
+-static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+-{
+- struct ata_taskfile *tf = &qc->tf;
+-
+- tf->flags |= ATA_TFLAG_DEVICE;
+- tf->protocol = ATA_PROT_NODATA;
+-
+- if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
+- (ata_id_has_flush_ext(qc->dev->id)))
+- tf->command = ATA_CMD_FLUSH_EXT;
+- else
+- tf->command = ATA_CMD_FLUSH;
+-
+- return 0;
+-}
+-
+-/**
+- * scsi_6_lba_len - Get LBA and transfer length
+- * @scsicmd: SCSI command to translate
+- *
+- * Calculate LBA and transfer length for 6-byte commands.
+- *
+- * RETURNS:
+- * @plba: the LBA
+- * @plen: the transfer length
+- */
+-
+-static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+-{
+- u64 lba = 0;
+- u32 len = 0;
+-
+- VPRINTK("six-byte command\n");
+-
+- lba |= ((u64)scsicmd[2]) << 8;
+- lba |= ((u64)scsicmd[3]);
+-
+- len |= ((u32)scsicmd[4]);
+-
+- *plba = lba;
+- *plen = len;
+-}
+-
+-/**
+- * scsi_10_lba_len - Get LBA and transfer length
+- * @scsicmd: SCSI command to translate
+- *
+- * Calculate LBA and transfer length for 10-byte commands.
+- *
+- * RETURNS:
+- * @plba: the LBA
+- * @plen: the transfer length
+- */
+-
+-static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+-{
+- u64 lba = 0;
+- u32 len = 0;
+-
+- VPRINTK("ten-byte command\n");
+-
+- lba |= ((u64)scsicmd[2]) << 24;
+- lba |= ((u64)scsicmd[3]) << 16;
+- lba |= ((u64)scsicmd[4]) << 8;
+- lba |= ((u64)scsicmd[5]);
+-
+- len |= ((u32)scsicmd[7]) << 8;
+- len |= ((u32)scsicmd[8]);
+-
+- *plba = lba;
+- *plen = len;
+-}
+-
+-/**
+- * scsi_16_lba_len - Get LBA and transfer length
+- * @scsicmd: SCSI command to translate
+- *
+- * Calculate LBA and transfer length for 16-byte commands.
+- *
+- * RETURNS:
+- * @plba: the LBA
+- * @plen: the transfer length
+- */
+-
+-static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+-{
+- u64 lba = 0;
+- u32 len = 0;
+-
+- VPRINTK("sixteen-byte command\n");
+-
+- lba |= ((u64)scsicmd[2]) << 56;
+- lba |= ((u64)scsicmd[3]) << 48;
+- lba |= ((u64)scsicmd[4]) << 40;
+- lba |= ((u64)scsicmd[5]) << 32;
+- lba |= ((u64)scsicmd[6]) << 24;
+- lba |= ((u64)scsicmd[7]) << 16;
+- lba |= ((u64)scsicmd[8]) << 8;
+- lba |= ((u64)scsicmd[9]);
+-
+- len |= ((u32)scsicmd[10]) << 24;
+- len |= ((u32)scsicmd[11]) << 16;
+- len |= ((u32)scsicmd[12]) << 8;
+- len |= ((u32)scsicmd[13]);
+-
+- *plba = lba;
+- *plen = len;
+-}
+-
+-/**
+- * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
+- * @qc: Storage for translated ATA taskfile
+- * @scsicmd: SCSI command to translate
+- *
+- * Converts SCSI VERIFY command to an ATA READ VERIFY command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, non-zero on error.
+- */
+-
+-static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+-{
+- struct ata_taskfile *tf = &qc->tf;
+- struct ata_device *dev = qc->dev;
+- u64 dev_sectors = qc->dev->n_sectors;
+- u64 block;
+- u32 n_block;
+-
+- tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+- tf->protocol = ATA_PROT_NODATA;
+-
+- if (scsicmd[0] == VERIFY)
+- scsi_10_lba_len(scsicmd, &block, &n_block);
+- else if (scsicmd[0] == VERIFY_16)
+- scsi_16_lba_len(scsicmd, &block, &n_block);
+- else
+- goto invalid_fld;
+-
+- if (!n_block)
+- goto nothing_to_do;
+- if (block >= dev_sectors)
+- goto out_of_range;
+- if ((block + n_block) > dev_sectors)
+- goto out_of_range;
+-
+- if (dev->flags & ATA_DFLAG_LBA) {
+- tf->flags |= ATA_TFLAG_LBA;
+-
+- if (lba_28_ok(block, n_block)) {
+- /* use LBA28 */
+- tf->command = ATA_CMD_VERIFY;
+- tf->device |= (block >> 24) & 0xf;
+- } else if (lba_48_ok(block, n_block)) {
+- if (!(dev->flags & ATA_DFLAG_LBA48))
+- goto out_of_range;
+-
+- /* use LBA48 */
+- tf->flags |= ATA_TFLAG_LBA48;
+- tf->command = ATA_CMD_VERIFY_EXT;
+-
+- tf->hob_nsect = (n_block >> 8) & 0xff;
+-
+- tf->hob_lbah = (block >> 40) & 0xff;
+- tf->hob_lbam = (block >> 32) & 0xff;
+- tf->hob_lbal = (block >> 24) & 0xff;
+- } else
+- /* request too large even for LBA48 */
+- goto out_of_range;
+-
+- tf->nsect = n_block & 0xff;
+-
+- tf->lbah = (block >> 16) & 0xff;
+- tf->lbam = (block >> 8) & 0xff;
+- tf->lbal = block & 0xff;
+-
+- tf->device |= ATA_LBA;
+- } else {
+- /* CHS */
+- u32 sect, head, cyl, track;
+-
+- if (!lba_28_ok(block, n_block))
+- goto out_of_range;
+-
+- /* Convert LBA to CHS */
+- track = (u32)block / dev->sectors;
+- cyl = track / dev->heads;
+- head = track % dev->heads;
+- sect = (u32)block % dev->sectors + 1;
+-
+- DPRINTK("block %u track %u cyl %u head %u sect %u\n",
+- (u32)block, track, cyl, head, sect);
+-
+- /* Check whether the converted CHS can fit.
+- Cylinder: 0-65535
+- Head: 0-15
+- Sector: 1-255*/
+- if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
+- goto out_of_range;
+-
+- tf->command = ATA_CMD_VERIFY;
+- tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+- tf->lbal = sect;
+- tf->lbam = cyl;
+- tf->lbah = cyl >> 8;
+- tf->device |= head;
+- }
+-
+- return 0;
+-
+-invalid_fld:
+- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+- /* "Invalid field in cbd" */
+- return 1;
+-
+-out_of_range:
+- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+- /* "Logical Block Address out of range" */
+- return 1;
+-
+-nothing_to_do:
+- qc->scsicmd->result = SAM_STAT_GOOD;
+- return 1;
+-}
+-
+-/**
+- * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
+- * @qc: Storage for translated ATA taskfile
+- * @scsicmd: SCSI command to translate
+- *
+- * Converts any of six SCSI read/write commands into the
+- * ATA counterpart, including starting sector (LBA),
+- * sector count, and taking into account the device's LBA48
+- * support.
+- *
+- * Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
+- * %WRITE_16 are currently supported.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, non-zero on error.
+- */
+-
+-static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+-{
+- struct ata_taskfile *tf = &qc->tf;
+- struct ata_device *dev = qc->dev;
+- u64 block;
+- u32 n_block;
+-
+- qc->flags |= ATA_QCFLAG_IO;
+- tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+-
+- if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+- scsicmd[0] == WRITE_16)
+- tf->flags |= ATA_TFLAG_WRITE;
+-
+- /* Calculate the SCSI LBA, transfer length and FUA. */
+- switch (scsicmd[0]) {
+- case READ_10:
+- case WRITE_10:
+- scsi_10_lba_len(scsicmd, &block, &n_block);
+- if (unlikely(scsicmd[1] & (1 << 3)))
+- tf->flags |= ATA_TFLAG_FUA;
+- break;
+- case READ_6:
+- case WRITE_6:
+- scsi_6_lba_len(scsicmd, &block, &n_block);
+-
+- /* for 6-byte r/w commands, transfer length 0
+- * means 256 blocks of data, not 0 block.
+- */
+- if (!n_block)
+- n_block = 256;
+- break;
+- case READ_16:
+- case WRITE_16:
+- scsi_16_lba_len(scsicmd, &block, &n_block);
+- if (unlikely(scsicmd[1] & (1 << 3)))
+- tf->flags |= ATA_TFLAG_FUA;
+- break;
+- default:
+- DPRINTK("no-byte command\n");
+- goto invalid_fld;
+- }
+-
+- /* Check and compose ATA command */
+- if (!n_block)
+- /* For 10-byte and 16-byte SCSI R/W commands, transfer
+- * length 0 means transfer 0 block of data.
+- * However, for ATA R/W commands, sector count 0 means
+- * 256 or 65536 sectors, not 0 sectors as in SCSI.
+- *
+- * WARNING: one or two older ATA drives treat 0 as 0...
+- */
+- goto nothing_to_do;
+-
+- if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+- /* yay, NCQ */
+- if (!lba_48_ok(block, n_block))
+- goto out_of_range;
+-
+- tf->protocol = ATA_PROT_NCQ;
+- tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+-
+- if (tf->flags & ATA_TFLAG_WRITE)
+- tf->command = ATA_CMD_FPDMA_WRITE;
+- else
+- tf->command = ATA_CMD_FPDMA_READ;
+-
+- qc->nsect = n_block;
+-
+- tf->nsect = qc->tag << 3;
+- tf->hob_feature = (n_block >> 8) & 0xff;
+- tf->feature = n_block & 0xff;
+-
+- tf->hob_lbah = (block >> 40) & 0xff;
+- tf->hob_lbam = (block >> 32) & 0xff;
+- tf->hob_lbal = (block >> 24) & 0xff;
+- tf->lbah = (block >> 16) & 0xff;
+- tf->lbam = (block >> 8) & 0xff;
+- tf->lbal = block & 0xff;
+-
+- tf->device = 1 << 6;
+- if (tf->flags & ATA_TFLAG_FUA)
+- tf->device |= 1 << 7;
+- } else if (dev->flags & ATA_DFLAG_LBA) {
+- tf->flags |= ATA_TFLAG_LBA;
+-
+- if (lba_28_ok(block, n_block)) {
+- /* use LBA28 */
+- tf->device |= (block >> 24) & 0xf;
+- } else if (lba_48_ok(block, n_block)) {
+- if (!(dev->flags & ATA_DFLAG_LBA48))
+- goto out_of_range;
+-
+- /* use LBA48 */
+- tf->flags |= ATA_TFLAG_LBA48;
+-
+- tf->hob_nsect = (n_block >> 8) & 0xff;
+-
+- tf->hob_lbah = (block >> 40) & 0xff;
+- tf->hob_lbam = (block >> 32) & 0xff;
+- tf->hob_lbal = (block >> 24) & 0xff;
+- } else
+- /* request too large even for LBA48 */
+- goto out_of_range;
+-
+- if (unlikely(ata_rwcmd_protocol(qc) < 0))
+- goto invalid_fld;
+-
+- qc->nsect = n_block;
+- tf->nsect = n_block & 0xff;
+-
+- tf->lbah = (block >> 16) & 0xff;
+- tf->lbam = (block >> 8) & 0xff;
+- tf->lbal = block & 0xff;
+-
+- tf->device |= ATA_LBA;
+- } else {
+- /* CHS */
+- u32 sect, head, cyl, track;
+-
+- /* The request -may- be too large for CHS addressing. */
+- if (!lba_28_ok(block, n_block))
+- goto out_of_range;
+-
+- if (unlikely(ata_rwcmd_protocol(qc) < 0))
+- goto invalid_fld;
+-
+- /* Convert LBA to CHS */
+- track = (u32)block / dev->sectors;
+- cyl = track / dev->heads;
+- head = track % dev->heads;
+- sect = (u32)block % dev->sectors + 1;
+-
+- DPRINTK("block %u track %u cyl %u head %u sect %u\n",
+- (u32)block, track, cyl, head, sect);
+-
+- /* Check whether the converted CHS can fit.
+- Cylinder: 0-65535
+- Head: 0-15
+- Sector: 1-255*/
+- if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
+- goto out_of_range;
+-
+- qc->nsect = n_block;
+- tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+- tf->lbal = sect;
+- tf->lbam = cyl;
+- tf->lbah = cyl >> 8;
+- tf->device |= head;
+- }
+-
+- return 0;
+-
+-invalid_fld:
+- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+- /* "Invalid field in cbd" */
+- return 1;
+-
+-out_of_range:
+- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+- /* "Logical Block Address out of range" */
+- return 1;
+-
+-nothing_to_do:
+- qc->scsicmd->result = SAM_STAT_GOOD;
+- return 1;
+-}
+-
+-static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
+-{
+- struct scsi_cmnd *cmd = qc->scsicmd;
+- u8 *cdb = cmd->cmnd;
+- int need_sense = (qc->err_mask != 0);
+-
+- /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
+- * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
+- * cache
+- */
+- if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
+- ((qc->tf.feature == SETFEATURES_WC_ON) ||
+- (qc->tf.feature == SETFEATURES_WC_OFF))) {
+- qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
+- ata_port_schedule_eh(qc->ap);
+- }
+-
+- /* For ATA pass thru (SAT) commands, generate a sense block if
+- * user mandated it or if there's an error. Note that if we
+- * generate because the user forced us to, a check condition
+- * is generated and the ATA register values are returned
+- * whether the command completed successfully or not. If there
+- * was no error, SK, ASC and ASCQ will all be zero.
+- */
+- if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
+- ((cdb[2] & 0x20) || need_sense)) {
+- ata_gen_ata_desc_sense(qc);
+- } else {
+- if (!need_sense) {
+- cmd->result = SAM_STAT_GOOD;
+- } else {
+- /* TODO: decide which descriptor format to use
+- * for 48b LBA devices and call that here
+- * instead of the fixed desc, which is only
+- * good for smaller LBA (and maybe CHS?)
+- * devices.
+- */
+- ata_gen_fixed_sense(qc);
+- }
+- }
+-
+- if (need_sense && !qc->ap->ops->error_handler)
+- ata_dump_status(qc->ap->id, &qc->result_tf);
+-
+- qc->scsidone(cmd);
+-
+- ata_qc_free(qc);
+-}
+-
+-/**
+- * ata_scmd_need_defer - Check whether we need to defer scmd
+- * @dev: ATA device to which the command is addressed
+- * @is_io: Is the command IO (and thus possibly NCQ)?
+- *
+- * NCQ and non-NCQ commands cannot run together. As upper layer
+- * only knows the queue depth, we are responsible for maintaining
+- * exclusion. This function checks whether a new command can be
+- * issued to @dev.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * 1 if deferring is needed, 0 otherwise.
+- */
+-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
+-{
+- struct ata_port *ap = dev->ap;
+-
+- if (!(dev->flags & ATA_DFLAG_NCQ))
+- return 0;
+-
+- if (is_io) {
+- if (!ata_tag_valid(ap->active_tag))
+- return 0;
+- } else {
+- if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
+- return 0;
+- }
+- return 1;
+-}
+-
+-/**
+- * ata_scsi_translate - Translate then issue SCSI command to ATA device
+- * @dev: ATA device to which the command is addressed
+- * @cmd: SCSI command to execute
+- * @done: SCSI command completion function
+- * @xlat_func: Actor which translates @cmd to an ATA taskfile
+- *
+- * Our ->queuecommand() function has decided that the SCSI
+- * command issued can be directly translated into an ATA
+- * command, rather than handled internally.
+- *
+- * This function sets up an ata_queued_cmd structure for the
+- * SCSI command, and sends that ata_queued_cmd to the hardware.
+- *
+- * The xlat_func argument (actor) returns 0 if ready to execute
+- * ATA command, else 1 to finish translation. If 1 is returned
+- * then cmd->result (and possibly cmd->sense_buffer) are assumed
+- * to be set reflecting an error condition or clean (early)
+- * termination.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
+- * needs to be deferred.
+- */
+-static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
+- void (*done)(struct scsi_cmnd *),
+- ata_xlat_func_t xlat_func)
+-{
+- struct ata_queued_cmd *qc;
+- u8 *scsicmd = cmd->cmnd;
+- int is_io = xlat_func == ata_scsi_rw_xlat;
+-
+- VPRINTK("ENTER\n");
+-
+- if (unlikely(ata_scmd_need_defer(dev, is_io)))
+- goto defer;
+-
+- qc = ata_scsi_qc_new(dev, cmd, done);
+- if (!qc)
+- goto err_mem;
+-
+- /* data is present; dma-map it */
+- if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
+- cmd->sc_data_direction == DMA_TO_DEVICE) {
+- if (unlikely(cmd->request_bufflen < 1)) {
+- ata_dev_printk(dev, KERN_WARNING,
+- "WARNING: zero len r/w req\n");
+- goto err_did;
+- }
+-
+- if (cmd->use_sg)
+- ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
+- else
+- ata_sg_init_one(qc, cmd->request_buffer,
+- cmd->request_bufflen);
+-
+- qc->dma_dir = cmd->sc_data_direction;
+- }
+-
+- qc->complete_fn = ata_scsi_qc_complete;
+-
+- if (xlat_func(qc, scsicmd))
+- goto early_finish;
+-
+- /* select device, send command to hardware */
+- ata_qc_issue(qc);
+-
+- VPRINTK("EXIT\n");
+- return 0;
+-
+-early_finish:
+- ata_qc_free(qc);
+- done(cmd);
+- DPRINTK("EXIT - early finish (good or error)\n");
+- return 0;
+-
+-err_did:
+- ata_qc_free(qc);
+-err_mem:
+- cmd->result = (DID_ERROR << 16);
+- done(cmd);
+- DPRINTK("EXIT - internal\n");
+- return 0;
+-
+-defer:
+- DPRINTK("EXIT - defer\n");
+- return SCSI_MLQUEUE_DEVICE_BUSY;
+-}
+-
+-/**
+- * ata_scsi_rbuf_get - Map response buffer.
+- * @cmd: SCSI command containing buffer to be mapped.
+- * @buf_out: Pointer to mapped area.
+- *
+- * Maps buffer contained within SCSI command @cmd.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Length of response buffer.
+- */
+-
+-static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+-{
+- u8 *buf;
+- unsigned int buflen;
+-
+- if (cmd->use_sg) {
+- struct scatterlist *sg;
+-
+- sg = (struct scatterlist *) cmd->request_buffer;
+- buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
+- buflen = sg->length;
+- } else {
+- buf = cmd->request_buffer;
+- buflen = cmd->request_bufflen;
+- }
+-
+- *buf_out = buf;
+- return buflen;
+-}
+-
+-/**
+- * ata_scsi_rbuf_put - Unmap response buffer.
+- * @cmd: SCSI command containing buffer to be unmapped.
+- * @buf: buffer to unmap
+- *
+- * Unmaps response buffer contained within @cmd.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
+-{
+- if (cmd->use_sg) {
+- struct scatterlist *sg;
+-
+- sg = (struct scatterlist *) cmd->request_buffer;
+- kunmap_atomic(buf - sg->offset, KM_USER0);
+- }
+-}
+-
+-/**
+- * ata_scsi_rbuf_fill - wrapper for SCSI command simulators
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @actor: Callback hook for desired SCSI command simulator
+- *
+- * Takes care of the hard work of simulating a SCSI command...
+- * Mapping the response buffer, calling the command's handler,
+- * and handling the handler's return value. This return value
+- * indicates whether the handler wishes the SCSI command to be
+- * completed successfully (0), or not (in which case cmd->result
+- * and sense buffer are assumed to be set).
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+- unsigned int (*actor) (struct ata_scsi_args *args,
+- u8 *rbuf, unsigned int buflen))
+-{
+- u8 *rbuf;
+- unsigned int buflen, rc;
+- struct scsi_cmnd *cmd = args->cmd;
+-
+- buflen = ata_scsi_rbuf_get(cmd, &rbuf);
+- memset(rbuf, 0, buflen);
+- rc = actor(args, rbuf, buflen);
+- ata_scsi_rbuf_put(cmd, rbuf);
+-
+- if (rc == 0)
+- cmd->result = SAM_STAT_GOOD;
+- args->done(cmd);
+-}
+-
+-/**
+- * ata_scsiop_inq_std - Simulate INQUIRY command
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Returns standard device identification data associated
+- * with non-VPD INQUIRY command output.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- u8 hdr[] = {
+- TYPE_DISK,
+- 0,
+- 0x5, /* claim SPC-3 version compatibility */
+- 2,
+- 95 - 4
+- };
+-
+- /* set scsi removeable (RMB) bit per ata bit */
+- if (ata_id_removeable(args->id))
+- hdr[1] |= (1 << 7);
+-
+- VPRINTK("ENTER\n");
+-
+- memcpy(rbuf, hdr, sizeof(hdr));
+-
+- if (buflen > 35) {
+- memcpy(&rbuf[8], "ATA ", 8);
+- ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
+- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+- if (rbuf[32] == 0 || rbuf[32] == ' ')
+- memcpy(&rbuf[32], "n/a ", 4);
+- }
+-
+- if (buflen > 63) {
+- const u8 versions[] = {
+- 0x60, /* SAM-3 (no version claimed) */
+-
+- 0x03,
+- 0x20, /* SBC-2 (no version claimed) */
+-
+- 0x02,
+- 0x60 /* SPC-3 (no version claimed) */
+- };
+-
+- memcpy(rbuf + 59, versions, sizeof(versions));
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Returns list of inquiry VPD pages available.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- const u8 pages[] = {
+- 0x00, /* page 0x00, this page */
+- 0x80, /* page 0x80, unit serial no page */
+- 0x83 /* page 0x83, device ident page */
+- };
+- rbuf[3] = sizeof(pages); /* number of supported VPD pages */
+-
+- if (buflen > 6)
+- memcpy(rbuf + 4, pages, sizeof(pages));
+-
+- return 0;
+-}
+-
+-/**
+- * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Returns ATA device serial number.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- const u8 hdr[] = {
+- 0,
+- 0x80, /* this page code */
+- 0,
+- ATA_SERNO_LEN, /* page len */
+- };
+- memcpy(rbuf, hdr, sizeof(hdr));
+-
+- if (buflen > (ATA_SERNO_LEN + 4 - 1))
+- ata_id_string(args->id, (unsigned char *) &rbuf[4],
+- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+-
+- return 0;
+-}
+-
+-/**
+- * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Yields two logical unit device identification designators:
+- * - vendor specific ASCII containing the ATA serial number
+- * - SAT defined "t10 vendor id based" containing ASCII vendor
+- * name ("ATA "), model and serial numbers.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- int num;
+- const int sat_model_serial_desc_len = 68;
+- const int ata_model_byte_len = 40;
+-
+- rbuf[1] = 0x83; /* this page code */
+- num = 4;
+-
+- if (buflen > (ATA_SERNO_LEN + num + 3)) {
+- /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
+- rbuf[num + 0] = 2;
+- rbuf[num + 3] = ATA_SERNO_LEN;
+- num += 4;
+- ata_id_string(args->id, (unsigned char *) rbuf + num,
+- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+- num += ATA_SERNO_LEN;
+- }
+- if (buflen > (sat_model_serial_desc_len + num + 3)) {
+- /* SAT defined lu model and serial numbers descriptor */
+- /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
+- rbuf[num + 0] = 2;
+- rbuf[num + 1] = 1;
+- rbuf[num + 3] = sat_model_serial_desc_len;
+- num += 4;
+- memcpy(rbuf + num, "ATA ", 8);
+- num += 8;
+- ata_id_string(args->id, (unsigned char *) rbuf + num,
+- ATA_ID_PROD_OFS, ata_model_byte_len);
+- num += ata_model_byte_len;
+- ata_id_string(args->id, (unsigned char *) rbuf + num,
+- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+- num += ATA_SERNO_LEN;
+- }
+- rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
+- return 0;
+-}
+-
+-/**
+- * ata_scsiop_noop - Command handler that simply returns success.
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * No operation. Simply returns success to caller, to indicate
+- * that the caller should successfully complete this SCSI command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- VPRINTK("ENTER\n");
+- return 0;
+-}
+-
+-/**
+- * ata_msense_push - Push data onto MODE SENSE data output buffer
+- * @ptr_io: (input/output) Location to store more output data
+- * @last: End of output data buffer
+- * @buf: Pointer to BLOB being added to output buffer
+- * @buflen: Length of BLOB
+- *
+- * Store MODE SENSE data on an output buffer.
+- *
+- * LOCKING:
+- * None.
+- */
+-
+-static void ata_msense_push(u8 **ptr_io, const u8 *last,
+- const u8 *buf, unsigned int buflen)
+-{
+- u8 *ptr = *ptr_io;
+-
+- if ((ptr + buflen - 1) > last)
+- return;
+-
+- memcpy(ptr, buf, buflen);
+-
+- ptr += buflen;
+-
+- *ptr_io = ptr;
+-}
+-
+-/**
+- * ata_msense_caching - Simulate MODE SENSE caching info page
+- * @id: device IDENTIFY data
+- * @ptr_io: (input/output) Location to store more output data
+- * @last: End of output data buffer
+- *
+- * Generate a caching info page, which conditionally indicates
+- * write caching to the SCSI layer, depending on device
+- * capabilities.
+- *
+- * LOCKING:
+- * None.
+- */
+-
+-static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
+- const u8 *last)
+-{
+- u8 page[CACHE_MPAGE_LEN];
+-
+- memcpy(page, def_cache_mpage, sizeof(page));
+- if (ata_id_wcache_enabled(id))
+- page[2] |= (1 << 2); /* write cache enable */
+- if (!ata_id_rahead_enabled(id))
+- page[12] |= (1 << 5); /* disable read ahead */
+-
+- ata_msense_push(ptr_io, last, page, sizeof(page));
+- return sizeof(page);
+-}
+-
+-/**
+- * ata_msense_ctl_mode - Simulate MODE SENSE control mode page
+- * @dev: Device associated with this MODE SENSE command
+- * @ptr_io: (input/output) Location to store more output data
+- * @last: End of output data buffer
+- *
+- * Generate a generic MODE SENSE control mode page.
+- *
+- * LOCKING:
+- * None.
+- */
+-
+-static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+-{
+- ata_msense_push(ptr_io, last, def_control_mpage,
+- sizeof(def_control_mpage));
+- return sizeof(def_control_mpage);
+-}
+-
+-/**
+- * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
+- * @dev: Device associated with this MODE SENSE command
+- * @ptr_io: (input/output) Location to store more output data
+- * @last: End of output data buffer
+- *
+- * Generate a generic MODE SENSE r/w error recovery page.
+- *
+- * LOCKING:
+- * None.
+- */
+-
+-static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
+-{
+-
+- ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
+- sizeof(def_rw_recovery_mpage));
+- return sizeof(def_rw_recovery_mpage);
+-}
+-
+-/*
+- * We can turn this into a real blacklist if it's needed, for now just
+- * blacklist any Maxtor BANC1G10 revision firmware
+- */
+-static int ata_dev_supports_fua(u16 *id)
+-{
+- unsigned char model[41], fw[9];
+-
+- if (!libata_fua)
+- return 0;
+- if (!ata_id_has_fua(id))
+- return 0;
+-
+- ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
+- ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
+-
+- if (strcmp(model, "Maxtor"))
+- return 1;
+- if (strcmp(fw, "BANC1G10"))
+- return 1;
+-
+- return 0; /* blacklisted */
+-}
+-
+-/**
+- * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Simulate MODE SENSE commands. Assume this is invoked for direct
+- * access devices (e.g. disks) only. There should be no block
+- * descriptor for other device types.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- struct ata_device *dev = args->dev;
+- u8 *scsicmd = args->cmd->cmnd, *p, *last;
+- const u8 sat_blk_desc[] = {
+- 0, 0, 0, 0, /* number of blocks: sat unspecified */
+- 0,
+- 0, 0x2, 0x0 /* block length: 512 bytes */
+- };
+- u8 pg, spg;
+- unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
+- u8 dpofua;
+-
+- VPRINTK("ENTER\n");
+-
+- six_byte = (scsicmd[0] == MODE_SENSE);
+- ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */
+- /*
+- * LLBA bit in msense(10) ignored (compliant)
+- */
+-
+- page_control = scsicmd[2] >> 6;
+- switch (page_control) {
+- case 0: /* current */
+- break; /* supported */
+- case 3: /* saved */
+- goto saving_not_supp;
+- case 1: /* changeable */
+- case 2: /* defaults */
+- default:
+- goto invalid_fld;
+- }
+-
+- if (six_byte) {
+- output_len = 4 + (ebd ? 8 : 0);
+- alloc_len = scsicmd[4];
+- } else {
+- output_len = 8 + (ebd ? 8 : 0);
+- alloc_len = (scsicmd[7] << 8) + scsicmd[8];
+- }
+- minlen = (alloc_len < buflen) ? alloc_len : buflen;
+-
+- p = rbuf + output_len;
+- last = rbuf + minlen - 1;
+-
+- pg = scsicmd[2] & 0x3f;
+- spg = scsicmd[3];
+- /*
+- * No mode subpages supported (yet) but asking for _all_
+- * subpages may be valid
+- */
+- if (spg && (spg != ALL_SUB_MPAGES))
+- goto invalid_fld;
+-
+- switch(pg) {
+- case RW_RECOVERY_MPAGE:
+- output_len += ata_msense_rw_recovery(&p, last);
+- break;
+-
+- case CACHE_MPAGE:
+- output_len += ata_msense_caching(args->id, &p, last);
+- break;
+-
+- case CONTROL_MPAGE: {
+- output_len += ata_msense_ctl_mode(&p, last);
+- break;
+- }
+-
+- case ALL_MPAGES:
+- output_len += ata_msense_rw_recovery(&p, last);
+- output_len += ata_msense_caching(args->id, &p, last);
+- output_len += ata_msense_ctl_mode(&p, last);
+- break;
+-
+- default: /* invalid page code */
+- goto invalid_fld;
+- }
+-
+- if (minlen < 1)
+- return 0;
+-
+- dpofua = 0;
+- if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
+- (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
+- dpofua = 1 << 4;
+-
+- if (six_byte) {
+- output_len--;
+- rbuf[0] = output_len;
+- if (minlen > 2)
+- rbuf[2] |= dpofua;
+- if (ebd) {
+- if (minlen > 3)
+- rbuf[3] = sizeof(sat_blk_desc);
+- if (minlen > 11)
+- memcpy(rbuf + 4, sat_blk_desc,
+- sizeof(sat_blk_desc));
+- }
+- } else {
+- output_len -= 2;
+- rbuf[0] = output_len >> 8;
+- if (minlen > 1)
+- rbuf[1] = output_len;
+- if (minlen > 3)
+- rbuf[3] |= dpofua;
+- if (ebd) {
+- if (minlen > 7)
+- rbuf[7] = sizeof(sat_blk_desc);
+- if (minlen > 15)
+- memcpy(rbuf + 8, sat_blk_desc,
+- sizeof(sat_blk_desc));
+- }
+- }
+- return 0;
+-
+-invalid_fld:
+- ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+- /* "Invalid field in cbd" */
+- return 1;
+-
+-saving_not_supp:
+- ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
+- /* "Saving parameters not supported" */
+- return 1;
+-}
+-
+-/**
+- * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Simulate READ CAPACITY commands.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- u64 n_sectors;
+- u32 tmp;
+-
+- VPRINTK("ENTER\n");
+-
+- if (ata_id_has_lba(args->id)) {
+- if (ata_id_has_lba48(args->id))
+- n_sectors = ata_id_u64(args->id, 100);
+- else
+- n_sectors = ata_id_u32(args->id, 60);
+- } else {
+- /* CHS default translation */
+- n_sectors = args->id[1] * args->id[3] * args->id[6];
+-
+- if (ata_id_current_chs_valid(args->id))
+- /* CHS current translation */
+- n_sectors = ata_id_u32(args->id, 57);
+- }
+-
+- n_sectors--; /* ATA TotalUserSectors - 1 */
+-
+- 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);
+- rbuf[2] = tmp >> (8 * 1);
+- rbuf[3] = tmp;
+-
+- /* sector size */
+- tmp = ATA_SECT_SIZE;
+- rbuf[6] = tmp >> 8;
+- rbuf[7] = tmp;
+-
+- } else {
+- /* sector count, 64-bit */
+- 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);
+- rbuf[9] = tmp;
+-
+- /* sector size */
+- tmp = ATA_SECT_SIZE;
+- rbuf[12] = tmp >> 8;
+- rbuf[13] = tmp;
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * ata_scsiop_report_luns - Simulate REPORT LUNS command
+- * @args: device IDENTIFY data / SCSI command of interest.
+- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+- * @buflen: Response buffer length.
+- *
+- * Simulate REPORT LUNS command.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen)
+-{
+- VPRINTK("ENTER\n");
+- rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
+-
+- return 0;
+-}
+-
+-/**
+- * ata_scsi_set_sense - Set SCSI sense data and status
+- * @cmd: SCSI request to be handled
+- * @sk: SCSI-defined sense key
+- * @asc: SCSI-defined additional sense code
+- * @ascq: SCSI-defined additional sense code qualifier
+- *
+- * Helper function that builds a valid fixed format, current
+- * response code and the given sense key (sk), additional sense
+- * code (asc) and additional sense code qualifier (ascq) with
+- * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
+- * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
+- *
+- * LOCKING:
+- * Not required
+- */
+-
+-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+-{
+- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+-
+- cmd->sense_buffer[0] = 0x70; /* fixed format, current */
+- cmd->sense_buffer[2] = sk;
+- cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
+- cmd->sense_buffer[12] = asc;
+- cmd->sense_buffer[13] = ascq;
+-}
+-
+-/**
+- * ata_scsi_badcmd - End a SCSI request with an error
+- * @cmd: SCSI request to be handled
+- * @done: SCSI command completion function
+- * @asc: SCSI-defined additional sense code
+- * @ascq: SCSI-defined additional sense code qualifier
+- *
+- * Helper function that completes a SCSI command with
+- * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
+- * and the specified additional sense codes.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
+-{
+- DPRINTK("ENTER\n");
+- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
+-
+- done(cmd);
+-}
+-
+-static void atapi_sense_complete(struct ata_queued_cmd *qc)
+-{
+- if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
+- /* FIXME: not quite right; we don't want the
+- * translation of taskfile registers into
+- * a sense descriptors, since that's only
+- * correct for ATA, not ATAPI
+- */
+- ata_gen_ata_desc_sense(qc);
+- }
+-
+- qc->scsidone(qc->scsicmd);
+- ata_qc_free(qc);
+-}
+-
+-/* is it pointless to prefer PIO for "safety reasons"? */
+-static inline int ata_pio_use_silly(struct ata_port *ap)
+-{
+- return (ap->flags & ATA_FLAG_PIO_DMA);
+-}
+-
+-static void atapi_request_sense(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct scsi_cmnd *cmd = qc->scsicmd;
+-
+- DPRINTK("ATAPI request sense\n");
+-
+- /* FIXME: is this needed? */
+- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+-
+- ap->ops->tf_read(ap, &qc->tf);
+-
+- /* fill these in, for the case where they are -not- overwritten */
+- cmd->sense_buffer[0] = 0x70;
+- cmd->sense_buffer[2] = qc->tf.feature >> 4;
+-
+- ata_qc_reinit(qc);
+-
+- ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+- qc->dma_dir = DMA_FROM_DEVICE;
+-
+- memset(&qc->cdb, 0, qc->dev->cdb_len);
+- qc->cdb[0] = REQUEST_SENSE;
+- qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
+-
+- qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+- qc->tf.command = ATA_CMD_PACKET;
+-
+- if (ata_pio_use_silly(ap)) {
+- qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+- qc->tf.feature |= ATAPI_PKT_DMA;
+- } else {
+- qc->tf.protocol = ATA_PROT_ATAPI;
+- qc->tf.lbam = (8 * 1024) & 0xff;
+- qc->tf.lbah = (8 * 1024) >> 8;
+- }
+- qc->nbytes = SCSI_SENSE_BUFFERSIZE;
+-
+- qc->complete_fn = atapi_sense_complete;
+-
+- ata_qc_issue(qc);
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-static void atapi_qc_complete(struct ata_queued_cmd *qc)
+-{
+- struct scsi_cmnd *cmd = qc->scsicmd;
+- unsigned int err_mask = qc->err_mask;
+-
+- VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
+-
+- /* handle completion from new EH */
+- if (unlikely(qc->ap->ops->error_handler &&
+- (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
+-
+- if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
+- /* FIXME: not quite right; we don't want the
+- * translation of taskfile registers into a
+- * sense descriptors, since that's only
+- * correct for ATA, not ATAPI
+- */
+- ata_gen_ata_desc_sense(qc);
+- }
+-
+- /* SCSI EH automatically locks door if sdev->locked is
+- * set. Sometimes door lock request continues to
+- * fail, for example, when no media is present. This
+- * creates a loop - SCSI EH issues door lock which
+- * fails and gets invoked again to acquire sense data
+- * for the failed command.
+- *
+- * If door lock fails, always clear sdev->locked to
+- * avoid this infinite loop.
+- */
+- if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+- qc->dev->sdev->locked = 0;
+-
+- qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
+- qc->scsidone(cmd);
+- ata_qc_free(qc);
+- return;
+- }
+-
+- /* successful completion or old EH failure path */
+- if (unlikely(err_mask & AC_ERR_DEV)) {
+- cmd->result = SAM_STAT_CHECK_CONDITION;
+- atapi_request_sense(qc);
+- return;
+- } else if (unlikely(err_mask)) {
+- /* FIXME: not quite right; we don't want the
+- * translation of taskfile registers into
+- * a sense descriptors, since that's only
+- * correct for ATA, not ATAPI
+- */
+- ata_gen_ata_desc_sense(qc);
+- } else {
+- u8 *scsicmd = cmd->cmnd;
+-
+- if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
+- u8 *buf = NULL;
+- unsigned int buflen;
+-
+- buflen = ata_scsi_rbuf_get(cmd, &buf);
+-
+- /* ATAPI devices typically report zero for their SCSI version,
+- * and sometimes deviate from the spec WRT response data
+- * format. If SCSI version is reported as zero like normal,
+- * then we make the following fixups: 1) Fake MMC-5 version,
+- * to indicate to the Linux scsi midlayer this is a modern
+- * device. 2) Ensure response data format / ATAPI information
+- * are always correct.
+- */
+- if (buf[2] == 0) {
+- buf[2] = 0x5;
+- buf[3] = 0x32;
+- }
+-
+- ata_scsi_rbuf_put(cmd, buf);
+- }
+-
+- cmd->result = SAM_STAT_GOOD;
+- }
+-
+- qc->scsidone(cmd);
+- ata_qc_free(qc);
+-}
+-/**
+- * atapi_xlat - Initialize PACKET taskfile
+- * @qc: command structure to be initialized
+- * @scsicmd: SCSI CDB associated with this PACKET command
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Zero on success, non-zero on failure.
+- */
+-
+-static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+-{
+- struct scsi_cmnd *cmd = qc->scsicmd;
+- struct ata_device *dev = qc->dev;
+- int using_pio = (dev->flags & ATA_DFLAG_PIO);
+- int nodata = (cmd->sc_data_direction == DMA_NONE);
+-
+- if (!using_pio)
+- /* Check whether ATAPI DMA is safe */
+- if (ata_check_atapi_dma(qc))
+- using_pio = 1;
+-
+- memcpy(&qc->cdb, scsicmd, dev->cdb_len);
+-
+- qc->complete_fn = atapi_qc_complete;
+-
+- qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+- if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+- qc->tf.flags |= ATA_TFLAG_WRITE;
+- DPRINTK("direction: write\n");
+- }
+-
+- qc->tf.command = ATA_CMD_PACKET;
+-
+- /* no data, or PIO data xfer */
+- if (using_pio || nodata) {
+- if (nodata)
+- qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+- else
+- qc->tf.protocol = ATA_PROT_ATAPI;
+- qc->tf.lbam = (8 * 1024) & 0xff;
+- qc->tf.lbah = (8 * 1024) >> 8;
+- }
+-
+- /* DMA data xfer */
+- else {
+- qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+- qc->tf.feature |= ATAPI_PKT_DMA;
+-
+- if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE))
+- /* some SATA bridges need us to indicate data xfer direction */
+- qc->tf.feature |= ATAPI_DMADIR;
+- }
+-
+- qc->nbytes = cmd->request_bufflen;
+-
+- return 0;
+-}
+-
+-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+-{
+- if (likely(id < ATA_MAX_DEVICES))
+- return &ap->device[id];
+- return NULL;
+-}
+-
+-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+- const struct scsi_device *scsidev)
+-{
+- /* skip commands not addressed to targets we simulate */
+- if (unlikely(scsidev->channel || scsidev->lun))
+- return NULL;
+-
+- return ata_find_dev(ap, scsidev->id);
+-}
+-
+-/**
+- * ata_scsi_dev_enabled - determine if device is enabled
+- * @dev: ATA device
+- *
+- * Determine if commands should be sent to the specified device.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * 0 if commands are not allowed / 1 if commands are allowed
+- */
+-
+-static int ata_scsi_dev_enabled(struct ata_device *dev)
+-{
+- if (unlikely(!ata_dev_enabled(dev)))
+- return 0;
+-
+- if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+- if (unlikely(dev->class == ATA_DEV_ATAPI)) {
+- ata_dev_printk(dev, KERN_WARNING,
+- "WARNING: ATAPI is %s, device ignored.\n",
+- atapi_enabled ? "not supported with this driver" : "disabled");
+- return 0;
+- }
+- }
+-
+- return 1;
+-}
+-
+-/**
+- * ata_scsi_find_dev - lookup ata_device from scsi_cmnd
+- * @ap: ATA port to which the device is attached
+- * @scsidev: SCSI device from which we derive the ATA device
+- *
+- * Given various information provided in struct scsi_cmnd,
+- * map that onto an ATA bus, and using that mapping
+- * determine which ata_device is associated with the
+- * SCSI command to be sent.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * Associated ATA device, or %NULL if not found.
+- */
+-static struct ata_device *
+-ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
+-{
+- struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
+-
+- if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
+- return NULL;
+-
+- return dev;
+-}
+-
+-/*
+- * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value.
+- * @byte1: Byte 1 from pass-thru CDB.
+- *
+- * RETURNS:
+- * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise.
+- */
+-static u8
+-ata_scsi_map_proto(u8 byte1)
+-{
+- switch((byte1 & 0x1e) >> 1) {
+- case 3: /* Non-data */
+- return ATA_PROT_NODATA;
+-
+- case 6: /* DMA */
+- return ATA_PROT_DMA;
+-
+- case 4: /* PIO Data-in */
+- case 5: /* PIO Data-out */
+- return ATA_PROT_PIO;
+-
+- case 10: /* Device Reset */
+- case 0: /* Hard Reset */
+- case 1: /* SRST */
+- case 2: /* Bus Idle */
+- case 7: /* Packet */
+- case 8: /* DMA Queued */
+- case 9: /* Device Diagnostic */
+- case 11: /* UDMA Data-in */
+- case 12: /* UDMA Data-Out */
+- case 13: /* FPDMA */
+- default: /* Reserved */
+- break;
+- }
+-
+- return ATA_PROT_UNKNOWN;
+-}
+-
+-/**
+- * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
+- * @qc: command structure to be initialized
+- * @scsicmd: SCSI command to convert
+- *
+- * Handles either 12 or 16-byte versions of the CDB.
+- *
+- * RETURNS:
+- * Zero on success, non-zero on failure.
+- */
+-static unsigned int
+-ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
+-{
+- struct ata_taskfile *tf = &(qc->tf);
+- struct scsi_cmnd *cmd = qc->scsicmd;
+- struct ata_device *dev = qc->dev;
+-
+- if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN)
+- goto invalid_fld;
+-
+- /* We may not issue DMA commands if no DMA mode is set */
+- if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
+- goto invalid_fld;
+-
+- if (scsicmd[1] & 0xe0)
+- /* PIO multi not supported yet */
+- goto invalid_fld;
+-
+- /*
+- * 12 and 16 byte CDBs use different offsets to
+- * provide the various register values.
+- */
+- if (scsicmd[0] == ATA_16) {
+- /*
+- * 16-byte CDB - may contain extended commands.
+- *
+- * If that is the case, copy the upper byte register values.
+- */
+- if (scsicmd[1] & 0x01) {
+- tf->hob_feature = scsicmd[3];
+- tf->hob_nsect = scsicmd[5];
+- tf->hob_lbal = scsicmd[7];
+- tf->hob_lbam = scsicmd[9];
+- tf->hob_lbah = scsicmd[11];
+- tf->flags |= ATA_TFLAG_LBA48;
+- } else
+- tf->flags &= ~ATA_TFLAG_LBA48;
+-
+- /*
+- * Always copy low byte, device and command registers.
+- */
+- tf->feature = scsicmd[4];
+- tf->nsect = scsicmd[6];
+- tf->lbal = scsicmd[8];
+- tf->lbam = scsicmd[10];
+- tf->lbah = scsicmd[12];
+- tf->device = scsicmd[13];
+- tf->command = scsicmd[14];
+- } else {
+- /*
+- * 12-byte CDB - incapable of extended commands.
+- */
+- tf->flags &= ~ATA_TFLAG_LBA48;
+-
+- tf->feature = scsicmd[3];
+- tf->nsect = scsicmd[4];
+- tf->lbal = scsicmd[5];
+- tf->lbam = scsicmd[6];
+- tf->lbah = scsicmd[7];
+- tf->device = scsicmd[8];
+- tf->command = scsicmd[9];
+- }
+- /*
+- * If slave is possible, enforce correct master/slave bit
+- */
+- if (qc->ap->flags & ATA_FLAG_SLAVE_POSS)
+- tf->device = qc->dev->devno ?
+- tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+-
+- /*
+- * Filter SET_FEATURES - XFER MODE command -- otherwise,
+- * SET_FEATURES - XFER MODE must be preceded/succeeded
+- * by an update to hardware-specific registers for each
+- * controller (i.e. the reason for ->set_piomode(),
+- * ->set_dmamode(), and ->post_set_mode() hooks).
+- */
+- if ((tf->command == ATA_CMD_SET_FEATURES)
+- && (tf->feature == SETFEATURES_XFER))
+- goto invalid_fld;
+-
+- /*
+- * Set flags so that all registers will be written,
+- * and pass on write indication (used for PIO/DMA
+- * setup.)
+- */
+- tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE);
+-
+- if (cmd->sc_data_direction == DMA_TO_DEVICE)
+- tf->flags |= ATA_TFLAG_WRITE;
+-
+- /*
+- * Set transfer length.
+- *
+- * TODO: find out if we need to do more here to
+- * cover scatter/gather case.
+- */
+- qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE;
+-
+- /* request result TF */
+- qc->flags |= ATA_QCFLAG_RESULT_TF;
+-
+- return 0;
+-
+- invalid_fld:
+- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00);
+- /* "Invalid field in cdb" */
+- return 1;
+-}
+-
+-/**
+- * ata_get_xlat_func - check if SCSI to ATA translation is possible
+- * @dev: ATA device
+- * @cmd: SCSI command opcode to consider
+- *
+- * Look up the SCSI command given, and determine whether the
+- * SCSI command is to be translated or simulated.
+- *
+- * RETURNS:
+- * Pointer to translation function if possible, %NULL if not.
+- */
+-
+-static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
+-{
+- switch (cmd) {
+- case READ_6:
+- case READ_10:
+- case READ_16:
+-
+- case WRITE_6:
+- case WRITE_10:
+- case WRITE_16:
+- return ata_scsi_rw_xlat;
+-
+- case SYNCHRONIZE_CACHE:
+- if (ata_try_flush_cache(dev))
+- return ata_scsi_flush_xlat;
+- break;
+-
+- case VERIFY:
+- case VERIFY_16:
+- return ata_scsi_verify_xlat;
+-
+- case ATA_12:
+- case ATA_16:
+- return ata_scsi_pass_thru;
+-
+- case START_STOP:
+- return ata_scsi_start_stop_xlat;
+- }
+-
+- return NULL;
+-}
+-
+-/**
+- * ata_scsi_dump_cdb - dump SCSI command contents to dmesg
+- * @ap: ATA port to which the command was being sent
+- * @cmd: SCSI command to dump
+- *
+- * Prints the contents of a SCSI command via printk().
+- */
+-
+-static inline void ata_scsi_dump_cdb(struct ata_port *ap,
+- struct scsi_cmnd *cmd)
+-{
+-#ifdef ATA_DEBUG
+- struct scsi_device *scsidev = cmd->device;
+- u8 *scsicmd = cmd->cmnd;
+-
+- DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+- ap->id,
+- scsidev->channel, scsidev->id, scsidev->lun,
+- scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
+- scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
+- scsicmd[8]);
+-#endif
+-}
+-
+-static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
+- void (*done)(struct scsi_cmnd *),
+- struct ata_device *dev)
+-{
+- int rc = 0;
+-
+- if (dev->class == ATA_DEV_ATA) {
+- ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
+- cmd->cmnd[0]);
+-
+- if (xlat_func)
+- rc = ata_scsi_translate(dev, cmd, done, xlat_func);
+- else
+- ata_scsi_simulate(dev, cmd, done);
+- } else
+- rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
+-
+- return rc;
+-}
+-
+-/**
+- * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+- * @cmd: SCSI command to be sent
+- * @done: Completion function, called when command is complete
+- *
+- * In some cases, this function translates SCSI commands into
+- * ATA taskfiles, and queues the taskfiles to be sent to
+- * hardware. In other cases, this function simulates a
+- * SCSI device by evaluating and responding to certain
+- * SCSI commands. This creates the overall effect of
+- * ATA and ATAPI devices appearing as SCSI devices.
+- *
+- * LOCKING:
+- * Releases scsi-layer-held lock, and obtains host_set lock.
+- *
+- * RETURNS:
+- * Return value from __ata_scsi_queuecmd() if @cmd can be queued,
+- * 0 otherwise.
+- */
+-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+-{
+- struct ata_port *ap;
+- struct ata_device *dev;
+- struct scsi_device *scsidev = cmd->device;
+- struct Scsi_Host *shost = scsidev->host;
+- int rc = 0;
+-
+- ap = ata_shost_to_port(shost);
+-
+- spin_unlock(shost->host_lock);
+- spin_lock(ap->lock);
+-
+- ata_scsi_dump_cdb(ap, cmd);
+-
+- dev = ata_scsi_find_dev(ap, scsidev);
+- if (likely(dev))
+- rc = __ata_scsi_queuecmd(cmd, done, dev);
+- else {
+- cmd->result = (DID_BAD_TARGET << 16);
+- done(cmd);
+- }
+-
+- spin_unlock(ap->lock);
+- spin_lock(shost->host_lock);
+- return rc;
+-}
+-
+-/**
+- * ata_scsi_simulate - simulate SCSI command on ATA device
+- * @dev: the target device
+- * @cmd: SCSI command being sent to device.
+- * @done: SCSI command completion function.
+- *
+- * Interprets and directly executes a select list of SCSI commands
+- * that can be handled internally.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
+- void (*done)(struct scsi_cmnd *))
+-{
+- struct ata_scsi_args args;
+- const u8 *scsicmd = cmd->cmnd;
+-
+- args.dev = dev;
+- args.id = dev->id;
+- args.cmd = cmd;
+- args.done = done;
+-
+- switch(scsicmd[0]) {
+- /* no-op's, complete with success */
+- case SYNCHRONIZE_CACHE:
+- case REZERO_UNIT:
+- case SEEK_6:
+- case SEEK_10:
+- case TEST_UNIT_READY:
+- case FORMAT_UNIT: /* FIXME: correct? */
+- case SEND_DIAGNOSTIC: /* FIXME: correct? */
+- ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+- break;
+-
+- case INQUIRY:
+- if (scsicmd[1] & 2) /* is CmdDt set? */
+- ata_scsi_invalid_field(cmd, done);
+- else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
+- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+- else if (scsicmd[2] == 0x00)
+- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
+- else if (scsicmd[2] == 0x80)
+- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
+- else if (scsicmd[2] == 0x83)
+- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+- else
+- ata_scsi_invalid_field(cmd, done);
+- break;
+-
+- case MODE_SENSE:
+- case MODE_SENSE_10:
+- ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+- break;
+-
+- case MODE_SELECT: /* unconditionally return */
+- case MODE_SELECT_10: /* bad-field-in-cdb */
+- ata_scsi_invalid_field(cmd, done);
+- break;
+-
+- case READ_CAPACITY:
+- ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+- break;
+-
+- case SERVICE_ACTION_IN:
+- if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
+- ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+- else
+- ata_scsi_invalid_field(cmd, done);
+- break;
+-
+- case REPORT_LUNS:
+- ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+- break;
+-
+- /* mandatory commands we haven't implemented yet */
+- case REQUEST_SENSE:
+-
+- /* all other commands */
+- default:
+- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
+- /* "Invalid command operation code" */
+- done(cmd);
+- break;
+- }
+-}
+-
+-void ata_scsi_scan_host(struct ata_port *ap)
+-{
+- unsigned int i;
+-
+- if (ap->flags & ATA_FLAG_DISABLED)
+- return;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *dev = &ap->device[i];
+- struct scsi_device *sdev;
+-
+- if (!ata_dev_enabled(dev) || dev->sdev)
+- continue;
+-
+- sdev = __scsi_add_device(ap->host, 0, i, 0, NULL);
+- if (!IS_ERR(sdev)) {
+- dev->sdev = sdev;
+- scsi_device_put(sdev);
+- }
+- }
+-}
+-
+-/**
+- * ata_scsi_offline_dev - offline attached SCSI device
+- * @dev: ATA device to offline attached SCSI device for
+- *
+- * This function is called from ata_eh_hotplug() and responsible
+- * for taking the SCSI device attached to @dev offline. This
+- * function is called with host_set lock which protects dev->sdev
+- * against clearing.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- *
+- * RETURNS:
+- * 1 if attached SCSI device exists, 0 otherwise.
+- */
+-int ata_scsi_offline_dev(struct ata_device *dev)
+-{
+- if (dev->sdev) {
+- scsi_device_set_state(dev->sdev, SDEV_OFFLINE);
+- return 1;
+- }
+- return 0;
+-}
+-
+-/**
+- * ata_scsi_remove_dev - remove attached SCSI device
+- * @dev: ATA device to remove attached SCSI device for
+- *
+- * This function is called from ata_eh_scsi_hotplug() and
+- * responsible for removing the SCSI device attached to @dev.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-static void ata_scsi_remove_dev(struct ata_device *dev)
+-{
+- struct ata_port *ap = dev->ap;
+- struct scsi_device *sdev;
+- unsigned long flags;
+-
+- /* Alas, we need to grab scan_mutex to ensure SCSI device
+- * state doesn't change underneath us and thus
+- * scsi_device_get() always succeeds. The mutex locking can
+- * be removed if there is __scsi_device_get() interface which
+- * increments reference counts regardless of device state.
+- */
+- mutex_lock(&ap->host->scan_mutex);
+- spin_lock_irqsave(ap->lock, flags);
+-
+- /* clearing dev->sdev is protected by host_set lock */
+- sdev = dev->sdev;
+- dev->sdev = NULL;
+-
+- if (sdev) {
+- /* If user initiated unplug races with us, sdev can go
+- * away underneath us after the host_set lock and
+- * scan_mutex are released. Hold onto it.
+- */
+- if (scsi_device_get(sdev) == 0) {
+- /* The following ensures the attached sdev is
+- * offline on return from ata_scsi_offline_dev()
+- * regardless it wins or loses the race
+- * against this function.
+- */
+- scsi_device_set_state(sdev, SDEV_OFFLINE);
+- } else {
+- WARN_ON(1);
+- sdev = NULL;
+- }
+- }
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+- mutex_unlock(&ap->host->scan_mutex);
+-
+- if (sdev) {
+- ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
+- sdev->sdev_gendev.bus_id);
+-
+- scsi_remove_device(sdev);
+- scsi_device_put(sdev);
+- }
+-}
+-
+-/**
+- * ata_scsi_hotplug - SCSI part of hotplug
+- * @data: Pointer to ATA port to perform SCSI hotplug on
+- *
+- * Perform SCSI part of hotplug. It's executed from a separate
+- * workqueue after EH completes. This is necessary because SCSI
+- * hot plugging requires working EH and hot unplugging is
+- * synchronized with hot plugging with a mutex.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-void ata_scsi_hotplug(void *data)
+-{
+- struct ata_port *ap = data;
+- int i;
+-
+- if (ap->pflags & ATA_PFLAG_UNLOADING) {
+- DPRINTK("ENTER/EXIT - unloading\n");
+- return;
+- }
+-
+- DPRINTK("ENTER\n");
+-
+- /* unplug detached devices */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *dev = &ap->device[i];
+- unsigned long flags;
+-
+- if (!(dev->flags & ATA_DFLAG_DETACHED))
+- continue;
+-
+- spin_lock_irqsave(ap->lock, flags);
+- dev->flags &= ~ATA_DFLAG_DETACHED;
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- ata_scsi_remove_dev(dev);
+- }
+-
+- /* scan for new ones */
+- ata_scsi_scan_host(ap);
+-
+- /* If we scanned while EH was in progress, scan would have
+- * failed silently. Requeue if there are enabled but
+- * unattached devices.
+- */
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- struct ata_device *dev = &ap->device[i];
+- if (ata_dev_enabled(dev) && !dev->sdev) {
+- queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
+- break;
+- }
+- }
+-
+- DPRINTK("EXIT\n");
+-}
+-
+-/**
+- * ata_scsi_user_scan - indication for user-initiated bus scan
+- * @shost: SCSI host to scan
+- * @channel: Channel to scan
+- * @id: ID to scan
+- * @lun: LUN to scan
+- *
+- * This function is called when user explicitly requests bus
+- * scan. Set probe pending flag and invoke EH.
+- *
+- * LOCKING:
+- * SCSI layer (we don't care)
+- *
+- * RETURNS:
+- * Zero.
+- */
+-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+- unsigned int id, unsigned int lun)
+-{
+- struct ata_port *ap = ata_shost_to_port(shost);
+- unsigned long flags;
+- int rc = 0;
+-
+- if (!ap->ops->error_handler)
+- return -EOPNOTSUPP;
+-
+- if ((channel != SCAN_WILD_CARD && channel != 0) ||
+- (lun != SCAN_WILD_CARD && lun != 0))
+- return -EINVAL;
+-
+- spin_lock_irqsave(ap->lock, flags);
+-
+- if (id == SCAN_WILD_CARD) {
+- ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+- ap->eh_info.action |= ATA_EH_SOFTRESET;
+- } else {
+- struct ata_device *dev = ata_find_dev(ap, id);
+-
+- if (dev) {
+- ap->eh_info.probe_mask |= 1 << dev->devno;
+- ap->eh_info.action |= ATA_EH_SOFTRESET;
+- ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+- } else
+- rc = -EINVAL;
+- }
+-
+- if (rc == 0)
+- ata_port_schedule_eh(ap);
+-
+- spin_unlock_irqrestore(ap->lock, flags);
+-
+- return rc;
+-}
+-
+-/**
+- * ata_scsi_dev_rescan - initiate scsi_rescan_device()
+- * @data: Pointer to ATA port to perform scsi_rescan_device()
+- *
+- * After ATA pass thru (SAT) commands are executed successfully,
+- * libata need to propagate the changes to SCSI layer. This
+- * function must be executed from ata_aux_wq such that sdev
+- * attach/detach don't race with rescan.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep).
+- */
+-void ata_scsi_dev_rescan(void *data)
+-{
+- struct ata_port *ap = data;
+- struct ata_device *dev;
+- unsigned int i;
+-
+- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+- dev = &ap->device[i];
+-
+- if (ata_dev_enabled(dev) && dev->sdev)
+- scsi_rescan_device(&(dev->sdev->sdev_gendev));
+- }
+-}
+diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
+deleted file mode 100644
+index c325679..0000000
+--- a/drivers/scsi/libata.h
++++ /dev/null
+@@ -1,117 +0,0 @@
+-/*
+- * libata.h - helper library for ATA
+- *
+- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+- * Copyright 2003-2004 Jeff Garzik
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- */
+-
+-#ifndef __LIBATA_H__
+-#define __LIBATA_H__
+-
+-#define DRV_NAME "libata"
+-#define DRV_VERSION "2.00" /* must be exactly four chars */
+-
+-struct ata_scsi_args {
+- struct ata_device *dev;
+- u16 *id;
+- struct scsi_cmnd *cmd;
+- void (*done)(struct scsi_cmnd *);
+-};
+-
+-/* libata-core.c */
+-extern struct workqueue_struct *ata_aux_wq;
+-extern int atapi_enabled;
+-extern int atapi_dmadir;
+-extern int libata_fua;
+-extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
+-extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+-extern void ata_dev_disable(struct ata_device *dev);
+-extern void ata_port_flush_task(struct ata_port *ap);
+-extern unsigned ata_exec_internal(struct ata_device *dev,
+- struct ata_taskfile *tf, const u8 *cdb,
+- int dma_dir, void *buf, unsigned int buflen);
+-extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
+-extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+- int post_reset, u16 *id);
+-extern int ata_dev_configure(struct ata_device *dev, int print_info);
+-extern int sata_down_spd_limit(struct ata_port *ap);
+-extern int sata_set_spd_needed(struct ata_port *ap);
+-extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
+-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+-extern void ata_qc_free(struct ata_queued_cmd *qc);
+-extern void ata_qc_issue(struct ata_queued_cmd *qc);
+-extern void __ata_qc_complete(struct ata_queued_cmd *qc);
+-extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+-extern void ata_dev_select(struct ata_port *ap, unsigned int device,
+- unsigned int wait, unsigned int can_sleep);
+-extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+-extern int ata_flush_cache(struct ata_device *dev);
+-extern void ata_dev_init(struct ata_device *dev);
+-extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
+-extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
+-
+-
+-/* libata-scsi.c */
+-extern struct scsi_transport_template ata_scsi_transport_template;
+-
+-extern void ata_scsi_scan_host(struct ata_port *ap);
+-extern int ata_scsi_offline_dev(struct ata_device *dev);
+-extern void ata_scsi_hotplug(void *data);
+-extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-
+-extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-
+-extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+- unsigned int buflen);
+-extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
+- void (*done)(struct scsi_cmnd *),
+- u8 asc, u8 ascq);
+-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
+- u8 sk, u8 asc, u8 ascq);
+-extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+- unsigned int (*actor) (struct ata_scsi_args *args,
+- u8 *rbuf, unsigned int buflen));
+-extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
+-extern void ata_scsi_dev_rescan(void *data);
+-
+-/* libata-eh.c */
+-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+-extern void ata_scsi_error(struct Scsi_Host *host);
+-extern void ata_port_wait_eh(struct ata_port *ap);
+-extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+-
+-#endif /* __LIBATA_H__ */
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index 5884cd2..2865ebd 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_se
+ EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
+
+ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
+- struct iscsi_data *hdr,
+- int transport_data_cnt)
++ struct iscsi_data *hdr)
+ {
+ struct iscsi_conn *conn = ctask->conn;
+
+@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struc
+
+ hdr->itt = ctask->hdr->itt;
+ hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-
+- hdr->offset = cpu_to_be32(ctask->total_length -
+- transport_data_cnt -
+- ctask->unsol_count);
++ hdr->offset = cpu_to_be32(ctask->unsol_offset);
+
+ if (ctask->unsol_count > conn->max_xmit_dlength) {
+ hton24(hdr->dlength, conn->max_xmit_dlength);
+ ctask->data_count = conn->max_xmit_dlength;
++ ctask->unsol_offset += ctask->data_count;
+ hdr->flags = 0;
+ } else {
+ hton24(hdr->dlength, ctask->unsol_count);
+@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(stru
+ memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
+ memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+
++ ctask->data_count = 0;
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ /*
+@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(stru
+ */
+ ctask->imm_count = 0;
+ ctask->unsol_count = 0;
++ ctask->unsol_offset = 0;
+ ctask->unsol_datasn = 0;
+
+ if (session->imm_data_en) {
+@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(stru
+ } else
+ zero_data(ctask->hdr->dlength);
+
+- if (!session->initial_r2t_en)
++ if (!session->initial_r2t_en) {
+ ctask->unsol_count = min(session->first_burst,
+ ctask->total_length) - ctask->imm_count;
++ ctask->unsol_offset = ctask->imm_count;
++ }
++
+ if (!ctask->unsol_count)
+ /* No unsolicit Data-Out's */
+ ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+@@ -177,25 +179,51 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pd
+
+ /**
+ * iscsi_complete_command - return command back to scsi-ml
+- * @session: iscsi session
+ * @ctask: iscsi cmd task
+ *
+ * Must be called with session lock.
+ * This function returns the scsi command to scsi-ml and returns
+ * the cmd task to the pool of available cmd tasks.
+ */
+-static void iscsi_complete_command(struct iscsi_session *session,
+- struct iscsi_cmd_task *ctask)
++static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
+ {
++ struct iscsi_session *session = ctask->conn->session;
+ struct scsi_cmnd *sc = ctask->sc;
+
+ ctask->state = ISCSI_TASK_COMPLETED;
+ ctask->sc = NULL;
++ /* SCSI eh reuses commands to verify us */
++ sc->SCp.ptr = NULL;
+ list_del_init(&ctask->running);
+ __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
+ sc->scsi_done(sc);
+ }
+
++static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
++{
++ atomic_inc(&ctask->refcount);
++}
++
++static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
++{
++ spin_lock_bh(&ctask->conn->session->lock);
++ __iscsi_get_ctask(ctask);
++ spin_unlock_bh(&ctask->conn->session->lock);
++}
++
++static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
++{
++ if (atomic_dec_and_test(&ctask->refcount))
++ iscsi_complete_command(ctask);
++}
++
++static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
++{
++ spin_lock_bh(&ctask->conn->session->lock);
++ __iscsi_put_ctask(ctask);
++ spin_unlock_bh(&ctask->conn->session->lock);
++}
++
+ /**
+ * iscsi_cmd_rsp - SCSI Command Response processing
+ * @conn: iscsi connection
+@@ -272,7 +300,7 @@ out:
+ (long)sc, sc->result, ctask->itt);
+ conn->scsirsp_pdus_cnt++;
+
+- iscsi_complete_command(conn->session, ctask);
++ __iscsi_put_ctask(ctask);
+ return rc;
+ }
+
+@@ -295,6 +323,30 @@ static void iscsi_tmf_rsp(struct iscsi_c
+ wake_up(&conn->ehwait);
+ }
+
++static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
++ char *data, int datalen)
++{
++ struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
++ struct iscsi_hdr rejected_pdu;
++ uint32_t itt;
++
++ conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
++
++ if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
++ if (ntoh24(reject->dlength) > datalen)
++ return ISCSI_ERR_PROTO;
++
++ if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
++ memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
++ itt = rejected_pdu.itt & ISCSI_ITT_MASK;
++ printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
++ "due to DataDigest error.\n", itt,
++ rejected_pdu.opcode);
++ }
++ }
++ return 0;
++}
++
+ /**
+ * __iscsi_complete_pdu - complete pdu
+ * @conn: iscsi conn
+@@ -336,7 +388,7 @@ int __iscsi_complete_pdu(struct iscsi_co
+ BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
+ if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+ conn->scsirsp_pdus_cnt++;
+- iscsi_complete_command(session, ctask);
++ __iscsi_put_ctask(ctask);
+ }
+ break;
+ case ISCSI_OP_R2T:
+@@ -406,6 +458,11 @@ int __iscsi_complete_pdu(struct iscsi_co
+ break;
+ }
+ } else if (itt == ISCSI_RESERVED_TAG) {
++ rc = iscsi_check_assign_cmdsn(session,
++ (struct iscsi_nopin*)hdr);
++ if (rc)
++ goto done;
++
+ switch(opcode) {
+ case ISCSI_OP_NOOP_IN:
+ if (datalen) {
+@@ -413,11 +470,6 @@ int __iscsi_complete_pdu(struct iscsi_co
+ break;
+ }
+
+- rc = iscsi_check_assign_cmdsn(session,
+- (struct iscsi_nopin*)hdr);
+- if (rc)
+- break;
+-
+ if (hdr->ttt == ISCSI_RESERVED_TAG)
+ break;
+
+@@ -425,11 +477,12 @@ int __iscsi_complete_pdu(struct iscsi_co
+ rc = ISCSI_ERR_CONN_FAILED;
+ break;
+ case ISCSI_OP_REJECT:
+- /* we need sth like iscsi_reject_rsp()*/
++ rc = iscsi_handle_reject(conn, hdr, data, datalen);
++ break;
+ case ISCSI_OP_ASYNC_EVENT:
+ conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+- /* we need sth like iscsi_async_event_rsp() */
+- rc = ISCSI_ERR_BAD_OPCODE;
++ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
++ rc = ISCSI_ERR_CONN_FAILED;
+ break;
+ default:
+ rc = ISCSI_ERR_BAD_OPCODE;
+@@ -525,6 +578,27 @@ void iscsi_conn_failure(struct iscsi_con
+ }
+ EXPORT_SYMBOL_GPL(iscsi_conn_failure);
+
++static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
++{
++ struct iscsi_hdr *hdr = conn->mtask->hdr;
++ int rc, was_logout = 0;
++
++ if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
++ conn->session->state = ISCSI_STATE_IN_RECOVERY;
++ iscsi_block_session(session_to_cls(conn->session));
++ was_logout = 1;
++ }
++ rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
++ if (rc)
++ return rc;
++
++ if (was_logout) {
++ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
++ return -ENODATA;
++ }
++ return 0;
++}
++
+ /**
+ * iscsi_data_xmit - xmit any command into the scheduled connection
+ * @conn: iscsi connection
+@@ -561,14 +635,16 @@ static int iscsi_data_xmit(struct iscsi_
+ BUG_ON(conn->ctask && conn->mtask);
+
+ if (conn->ctask) {
++ iscsi_get_ctask(conn->ctask);
+ rc = tt->xmit_cmd_task(conn, conn->ctask);
++ iscsi_put_ctask(conn->ctask);
+ if (rc)
+ goto again;
+ /* done with this in-progress ctask */
+ conn->ctask = NULL;
+ }
+ if (conn->mtask) {
+- rc = tt->xmit_mgmt_task(conn, conn->mtask);
++ rc = iscsi_xmit_imm_task(conn);
+ if (rc)
+ goto again;
+ /* done with this in-progress mtask */
+@@ -583,7 +659,7 @@ static int iscsi_data_xmit(struct iscsi_
+ list_add_tail(&conn->mtask->running,
+ &conn->mgmt_run_list);
+ spin_unlock_bh(&conn->session->lock);
+- rc = tt->xmit_mgmt_task(conn, conn->mtask);
++ rc = iscsi_xmit_imm_task(conn);
+ if (rc)
+ goto again;
+ }
+@@ -602,12 +678,17 @@ static int iscsi_data_xmit(struct iscsi_
+ struct iscsi_cmd_task, running);
+ conn->ctask->state = ISCSI_TASK_RUNNING;
+ list_move_tail(conn->xmitqueue.next, &conn->run_list);
++ __iscsi_get_ctask(conn->ctask);
+ spin_unlock_bh(&conn->session->lock);
+
+ rc = tt->xmit_cmd_task(conn, conn->ctask);
+- if (rc)
+- goto again;
++
+ spin_lock_bh(&conn->session->lock);
++ __iscsi_put_ctask(conn->ctask);
++ if (rc) {
++ spin_unlock_bh(&conn->session->lock);
++ goto again;
++ }
+ }
+ spin_unlock_bh(&conn->session->lock);
+ /* done with this ctask */
+@@ -657,6 +738,7 @@ enum {
+ FAILURE_SESSION_FAILED,
+ FAILURE_SESSION_FREED,
+ FAILURE_WINDOW_CLOSED,
++ FAILURE_OOM,
+ FAILURE_SESSION_TERMINATE,
+ FAILURE_SESSION_IN_RECOVERY,
+ FAILURE_SESSION_RECOVERY_TIMEOUT,
+@@ -672,6 +754,7 @@ int iscsi_queuecommand(struct scsi_cmnd
+
+ sc->scsi_done = done;
+ sc->result = 0;
++ sc->SCp.ptr = NULL;
+
+ host = sc->device->host;
+ session = iscsi_hostdata(host->hostdata);
+@@ -714,11 +797,20 @@ int iscsi_queuecommand(struct scsi_cmnd
+ }
+
+ conn = session->leadconn;
++ if (!conn) {
++ reason = FAILURE_SESSION_FREED;
++ goto fault;
++ }
+
+- __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
++ if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
++ sizeof(void*))) {
++ reason = FAILURE_OOM;
++ goto reject;
++ }
+ sc->SCp.phase = session->age;
+ sc->SCp.ptr = (char *)ctask;
+
++ atomic_set(&ctask->refcount, 1);
+ ctask->state = ISCSI_TASK_PENDING;
+ ctask->mtask = NULL;
+ ctask->conn = conn;
+@@ -731,9 +823,10 @@ int iscsi_queuecommand(struct scsi_cmnd
+
+ list_add_tail(&ctask->running, &conn->xmitqueue);
+ debug_scsi(
+- "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n",
++ "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
++ "win %d]\n",
+ sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+- conn->id, (long)sc, ctask->itt, sc->request_bufflen,
++ conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
+ session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ spin_unlock(&session->lock);
+
+@@ -1061,16 +1154,30 @@ static void fail_command(struct iscsi_co
+
+ sc->result = err;
+ sc->resid = sc->request_bufflen;
+- iscsi_complete_command(conn->session, ctask);
++ /* release ref from queuecommand */
++ __iscsi_put_ctask(ctask);
+ }
+
+ int iscsi_eh_abort(struct scsi_cmnd *sc)
+ {
+- struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+- struct iscsi_conn *conn = ctask->conn;
+- struct iscsi_session *session = conn->session;
++ struct iscsi_cmd_task *ctask;
++ struct iscsi_conn *conn;
++ struct iscsi_session *session;
+ int rc;
+
++ /*
++ * if session was ISCSI_STATE_IN_RECOVERY then we may not have
++ * got the command.
++ */
++ if (!sc->SCp.ptr) {
++ debug_scsi("sc never reached iscsi layer or it completed.\n");
++ return SUCCESS;
++ }
++
++ ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
++ conn = ctask->conn;
++ session = conn->session;
++
+ conn->eh_abort_cnt++;
+ debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
+
+@@ -1293,7 +1400,6 @@ iscsi_session_setup(struct iscsi_transpo
+ }
+
+ spin_lock_init(&session->lock);
+- INIT_LIST_HEAD(&session->connections);
+
+ /* initialize immediate command pool */
+ if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max,
+@@ -1496,16 +1602,11 @@ void iscsi_conn_teardown(struct iscsi_cl
+ kfree(conn->persistent_address);
+ __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
+ sizeof(void*));
+- list_del(&conn->item);
+- if (list_empty(&session->connections))
++ if (session->leadconn == conn) {
+ session->leadconn = NULL;
+- if (session->leadconn && session->leadconn == conn)
+- session->leadconn = container_of(session->connections.next,
+- struct iscsi_conn, item);
+-
+- if (session->leadconn == NULL)
+ /* no connections exits.. reset sequencing */
+ session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
++ }
+ spin_unlock_bh(&session->lock);
+
+ kfifo_free(conn->immqueue);
+@@ -1520,11 +1621,19 @@ int iscsi_conn_start(struct iscsi_cls_co
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
+
+- if (session == NULL) {
++ if (!session) {
+ printk(KERN_ERR "iscsi: can't start unbound connection\n");
+ return -EPERM;
+ }
+
++ if ((session->imm_data_en || !session->initial_r2t_en) &&
++ session->first_burst > session->max_burst) {
++ printk("iscsi: invalid burst lengths: "
++ "first_burst %d max_burst %d\n",
++ session->first_burst, session->max_burst);
++ return -EINVAL;
++ }
++
+ spin_lock_bh(&session->lock);
+ conn->c_stage = ISCSI_CONN_STARTED;
+ session->state = ISCSI_STATE_LOGGED_IN;
+@@ -1685,32 +1794,12 @@ int iscsi_conn_bind(struct iscsi_cls_ses
+ struct iscsi_cls_conn *cls_conn, int is_leading)
+ {
+ struct iscsi_session *session = class_to_transport_session(cls_session);
+- struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data;
++ struct iscsi_conn *conn = cls_conn->dd_data;
+
+- /* lookup for existing connection */
+ spin_lock_bh(&session->lock);
+- list_for_each_entry(tmp, &session->connections, item) {
+- if (tmp == conn) {
+- if (conn->c_stage != ISCSI_CONN_STOPPED ||
+- conn->stop_stage == STOP_CONN_TERM) {
+- printk(KERN_ERR "iscsi: can't bind "
+- "non-stopped connection (%d:%d)\n",
+- conn->c_stage, conn->stop_stage);
+- spin_unlock_bh(&session->lock);
+- return -EIO;
+- }
+- break;
+- }
+- }
+- if (tmp != conn) {
+- /* bind new iSCSI connection to session */
+- conn->session = session;
+- list_add(&conn->item, &session->connections);
+- }
+- spin_unlock_bh(&session->lock);
+-
+ if (is_leading)
+ session->leadconn = conn;
++ spin_unlock_bh(&session->lock);
+
+ /*
+ * Unblock xmitworker(), Login Phase will pass through.
+diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
+new file mode 100644
+index 0000000..aafdc92
+--- /dev/null
++++ b/drivers/scsi/libsas/Kconfig
+@@ -0,0 +1,39 @@
++#
++# Kernel configuration file for the SAS Class
++#
++# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++# Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++#
++# This file is licensed under GPLv2.
++#
++# 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 of the
++# License.
++#
++# 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
++#
++
++config SCSI_SAS_LIBSAS
++ tristate "SAS Domain Transport Attributes"
++ depends on SCSI
++ select SCSI_SAS_ATTRS
++ help
++ This provides transport specific helpers for SAS drivers which
++ use the domain device construct (like the aic94xxx).
++
++config SCSI_SAS_LIBSAS_DEBUG
++ bool "Compile the SAS Domain Transport Attributes in debug mode"
++ default y
++ depends on SCSI_SAS_LIBSAS
++ help
++ Compiles the SAS Layer in debug mode. In debug mode, the
++ SAS Layer prints diagnostic and debug messages.
+diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
+new file mode 100644
+index 0000000..44d972a
+--- /dev/null
++++ b/drivers/scsi/libsas/Makefile
+@@ -0,0 +1,36 @@
++#
++# Kernel Makefile for the libsas helpers
++#
++# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++# Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++#
++# This file is licensed under GPLv2.
++#
++# 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 of the
++# License.
++#
++# 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
++
++ifeq ($(CONFIG_SCSI_SAS_LIBSAS_DEBUG),y)
++ EXTRA_CFLAGS += -DSAS_DEBUG
++endif
++
++obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o
++libsas-y += sas_init.o \
++ sas_phy.o \
++ sas_port.o \
++ sas_event.o \
++ sas_dump.o \
++ sas_discover.o \
++ sas_expander.o \
++ sas_scsi_host.o
+diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
+new file mode 100644
+index 0000000..d977bd4
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_discover.c
+@@ -0,0 +1,749 @@
++/*
++ * Serial Attached SCSI (SAS) Discover process
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/pci.h>
++#include <linux/scatterlist.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_eh.h>
++#include "sas_internal.h"
++
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++#include "../scsi_sas_internal.h"
++
++/* ---------- Basic task processing for discovery purposes ---------- */
++
++void sas_init_dev(struct domain_device *dev)
++{
++ INIT_LIST_HEAD(&dev->siblings);
++ INIT_LIST_HEAD(&dev->dev_list_node);
++ switch (dev->dev_type) {
++ case SAS_END_DEV:
++ break;
++ case EDGE_DEV:
++ case FANOUT_DEV:
++ INIT_LIST_HEAD(&dev->ex_dev.children);
++ break;
++ case SATA_DEV:
++ case SATA_PM:
++ case SATA_PM_PORT:
++ INIT_LIST_HEAD(&dev->sata_dev.children);
++ break;
++ default:
++ break;
++ }
++}
++
++static void sas_task_timedout(unsigned long _task)
++{
++ struct sas_task *task = (void *) _task;
++ unsigned long flags;
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
++ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ complete(&task->completion);
++}
++
++static void sas_disc_task_done(struct sas_task *task)
++{
++ if (!del_timer(&task->timer))
++ return;
++ complete(&task->completion);
++}
++
++#define SAS_DEV_TIMEOUT 10
++
++/**
++ * sas_execute_task -- Basic task processing for discovery
++ * @task: the task to be executed
++ * @buffer: pointer to buffer to do I/O
++ * @size: size of @buffer
++ * @pci_dma_dir: PCI_DMA_...
++ */
++static int sas_execute_task(struct sas_task *task, void *buffer, int size,
++ int pci_dma_dir)
++{
++ int res = 0;
++ struct scatterlist *scatter = NULL;
++ struct task_status_struct *ts = &task->task_status;
++ int num_scatter = 0;
++ int retries = 0;
++ struct sas_internal *i =
++ to_sas_internal(task->dev->port->ha->core.shost->transportt);
++
++ if (pci_dma_dir != PCI_DMA_NONE) {
++ scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
++ if (!scatter)
++ goto out;
++
++ sg_init_one(scatter, buffer, size);
++ num_scatter = 1;
++ }
++
++ task->task_proto = task->dev->tproto;
++ task->scatter = scatter;
++ task->num_scatter = num_scatter;
++ task->total_xfer_len = size;
++ task->data_dir = pci_dma_dir;
++ task->task_done = sas_disc_task_done;
++
++ for (retries = 0; retries < 5; retries++) {
++ task->task_state_flags = SAS_TASK_STATE_PENDING;
++ init_completion(&task->completion);
++
++ task->timer.data = (unsigned long) task;
++ task->timer.function = sas_task_timedout;
++ task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
++ add_timer(&task->timer);
++
++ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
++ if (res) {
++ del_timer(&task->timer);
++ SAS_DPRINTK("executing SAS discovery task failed:%d\n",
++ res);
++ goto ex_err;
++ }
++ wait_for_completion(&task->completion);
++ res = -ETASK;
++ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
++ int res2;
++ SAS_DPRINTK("task aborted, flags:0x%x\n",
++ task->task_state_flags);
++ res2 = i->dft->lldd_abort_task(task);
++ SAS_DPRINTK("came back from abort task\n");
++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
++ if (res2 == TMF_RESP_FUNC_COMPLETE)
++ continue; /* Retry the task */
++ else
++ goto ex_err;
++ }
++ }
++ if (task->task_status.stat == SAM_BUSY ||
++ task->task_status.stat == SAM_TASK_SET_FULL ||
++ task->task_status.stat == SAS_QUEUE_FULL) {
++ SAS_DPRINTK("task: q busy, sleeping...\n");
++ schedule_timeout_interruptible(HZ);
++ } else if (task->task_status.stat == SAM_CHECK_COND) {
++ struct scsi_sense_hdr shdr;
++
++ if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
++ &shdr)) {
++ SAS_DPRINTK("couldn't normalize sense\n");
++ continue;
++ }
++ if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
++ (shdr.sense_key == 2 && shdr.asc == 4 &&
++ shdr.ascq == 1)) {
++ SAS_DPRINTK("device %016llx LUN: %016llx "
++ "powering up or not ready yet, "
++ "sleeping...\n",
++ SAS_ADDR(task->dev->sas_addr),
++ SAS_ADDR(task->ssp_task.LUN));
++
++ schedule_timeout_interruptible(5*HZ);
++ } else if (shdr.sense_key == 1) {
++ res = 0;
++ break;
++ } else if (shdr.sense_key == 5) {
++ break;
++ } else {
++ SAS_DPRINTK("dev %016llx LUN: %016llx "
++ "sense key:0x%x ASC:0x%x ASCQ:0x%x"
++ "\n",
++ SAS_ADDR(task->dev->sas_addr),
++ SAS_ADDR(task->ssp_task.LUN),
++ shdr.sense_key,
++ shdr.asc, shdr.ascq);
++ }
++ } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
++ task->task_status.stat != SAM_GOOD) {
++ SAS_DPRINTK("task finished with resp:0x%x, "
++ "stat:0x%x\n",
++ task->task_status.resp,
++ task->task_status.stat);
++ goto ex_err;
++ } else {
++ res = 0;
++ break;
++ }
++ }
++ex_err:
++ if (pci_dma_dir != PCI_DMA_NONE)
++ kfree(scatter);
++out:
++ return res;
++}
++
++/* ---------- Domain device discovery ---------- */
++
++/**
++ * sas_get_port_device -- Discover devices which caused port creation
++ * @port: pointer to struct sas_port of interest
++ *
++ * Devices directly attached to a HA port, have no parent. This is
++ * how we know they are (domain) "root" devices. All other devices
++ * do, and should have their "parent" pointer set appropriately as
++ * soon as a child device is discovered.
++ */
++static int sas_get_port_device(struct asd_sas_port *port)
++{
++ unsigned long flags;
++ struct asd_sas_phy *phy;
++ struct sas_rphy *rphy;
++ struct domain_device *dev;
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ spin_lock_irqsave(&port->phy_list_lock, flags);
++ if (list_empty(&port->phy_list)) {
++ spin_unlock_irqrestore(&port->phy_list_lock, flags);
++ kfree(dev);
++ return -ENODEV;
++ }
++ phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
++ spin_lock(&phy->frame_rcvd_lock);
++ memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
++ (size_t)phy->frame_rcvd_size));
++ spin_unlock(&phy->frame_rcvd_lock);
++ spin_unlock_irqrestore(&port->phy_list_lock, flags);
++
++ if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
++ struct dev_to_host_fis *fis =
++ (struct dev_to_host_fis *) dev->frame_rcvd;
++ if (fis->interrupt_reason == 1 && fis->lbal == 1 &&
++ fis->byte_count_low==0x69 && fis->byte_count_high == 0x96
++ && (fis->device & ~0x10) == 0)
++ dev->dev_type = SATA_PM;
++ else
++ dev->dev_type = SATA_DEV;
++ dev->tproto = SATA_PROTO;
++ } else {
++ struct sas_identify_frame *id =
++ (struct sas_identify_frame *) dev->frame_rcvd;
++ dev->dev_type = id->dev_type;
++ dev->iproto = id->initiator_bits;
++ dev->tproto = id->target_bits;
++ }
++
++ sas_init_dev(dev);
++
++ switch (dev->dev_type) {
++ case SAS_END_DEV:
++ rphy = sas_end_device_alloc(port->port);
++ break;
++ case EDGE_DEV:
++ rphy = sas_expander_alloc(port->port,
++ SAS_EDGE_EXPANDER_DEVICE);
++ break;
++ case FANOUT_DEV:
++ rphy = sas_expander_alloc(port->port,
++ SAS_FANOUT_EXPANDER_DEVICE);
++ break;
++ case SATA_DEV:
++ default:
++ printk("ERROR: Unidentified device type %d\n", dev->dev_type);
++ rphy = NULL;
++ break;
++ }
++
++ if (!rphy) {
++ kfree(dev);
++ return -ENODEV;
++ }
++ rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
++ memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
++ sas_fill_in_rphy(dev, rphy);
++ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
++ port->port_dev = dev;
++ dev->port = port;
++ dev->linkrate = port->linkrate;
++ dev->min_linkrate = port->linkrate;
++ dev->max_linkrate = port->linkrate;
++ dev->pathways = port->num_phys;
++ memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE);
++ memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
++ memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
++ port->disc.max_level = 0;
++
++ dev->rphy = rphy;
++ spin_lock(&port->dev_list_lock);
++ list_add_tail(&dev->dev_list_node, &port->dev_list);
++ spin_unlock(&port->dev_list_lock);
++
++ return 0;
++}
++
++/* ---------- Discover and Revalidate ---------- */
++
++/* ---------- SATA ---------- */
++
++static void sas_get_ata_command_set(struct domain_device *dev)
++{
++ struct dev_to_host_fis *fis =
++ (struct dev_to_host_fis *) dev->frame_rcvd;
++
++ if ((fis->sector_count == 1 && /* ATA */
++ fis->lbal == 1 &&
++ fis->lbam == 0 &&
++ fis->lbah == 0 &&
++ fis->device == 0)
++ ||
++ (fis->sector_count == 0 && /* CE-ATA (mATA) */
++ fis->lbal == 0 &&
++ fis->lbam == 0xCE &&
++ fis->lbah == 0xAA &&
++ (fis->device & ~0x10) == 0))
++
++ dev->sata_dev.command_set = ATA_COMMAND_SET;
++
++ else if ((fis->interrupt_reason == 1 && /* ATAPI */
++ fis->lbal == 1 &&
++ fis->byte_count_low == 0x14 &&
++ fis->byte_count_high == 0xEB &&
++ (fis->device & ~0x10) == 0))
++
++ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
++
++ else if ((fis->sector_count == 1 && /* SEMB */
++ fis->lbal == 1 &&
++ fis->lbam == 0x3C &&
++ fis->lbah == 0xC3 &&
++ fis->device == 0)
++ ||
++ (fis->interrupt_reason == 1 && /* SATA PM */
++ fis->lbal == 1 &&
++ fis->byte_count_low == 0x69 &&
++ fis->byte_count_high == 0x96 &&
++ (fis->device & ~0x10) == 0))
++
++ /* Treat it as a superset? */
++ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
++}
++
++/**
++ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
++ * @dev: the device to send the command to
++ * @command: the command register
++ * @features: the features register
++ * @buffer: pointer to buffer to do I/O
++ * @size: size of @buffer
++ * @pci_dma_dir: PCI_DMA_...
++ */
++static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
++ u8 features, void *buffer, int size,
++ int pci_dma_dir)
++{
++ int res = 0;
++ struct sas_task *task;
++ struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
++ &dev->frame_rcvd[0];
++
++ res = -ENOMEM;
++ task = sas_alloc_task(GFP_KERNEL);
++ if (!task)
++ goto out;
++
++ task->dev = dev;
++
++ task->ata_task.fis.command = command;
++ task->ata_task.fis.features = features;
++ task->ata_task.fis.device = d2h_fis->device;
++ task->ata_task.retry_count = 1;
++
++ res = sas_execute_task(task, buffer, size, pci_dma_dir);
++
++ sas_free_task(task);
++out:
++ return res;
++}
++
++static void sas_sata_propagate_sas_addr(struct domain_device *dev)
++{
++ unsigned long flags;
++ struct asd_sas_port *port = dev->port;
++ struct asd_sas_phy *phy;
++
++ BUG_ON(dev->parent);
++
++ memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
++ spin_lock_irqsave(&port->phy_list_lock, flags);
++ list_for_each_entry(phy, &port->phy_list, port_phy_el)
++ memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
++ spin_unlock_irqrestore(&port->phy_list_lock, flags);
++}
++
++#define ATA_IDENTIFY_DEV 0xEC
++#define ATA_IDENTIFY_PACKET_DEV 0xA1
++#define ATA_SET_FEATURES 0xEF
++#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
++
++/**
++ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
++ * @dev: STP/SATA device of interest (ATA/ATAPI)
++ *
++ * The LLDD has already been notified of this device, so that we can
++ * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
++ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
++ * performance for this device.
++ */
++static int sas_discover_sata_dev(struct domain_device *dev)
++{
++ int res;
++ __le16 *identify_x;
++ u8 command;
++
++ identify_x = kzalloc(512, GFP_KERNEL);
++ if (!identify_x)
++ return -ENOMEM;
++
++ if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
++ dev->sata_dev.identify_device = identify_x;
++ command = ATA_IDENTIFY_DEV;
++ } else {
++ dev->sata_dev.identify_packet_device = identify_x;
++ command = ATA_IDENTIFY_PACKET_DEV;
++ }
++
++ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
++ PCI_DMA_FROMDEVICE);
++ if (res)
++ goto out_err;
++
++ /* lives on the media? */
++ if (le16_to_cpu(identify_x[0]) & 4) {
++ /* incomplete response */
++ SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
++ "dev %llx\n", SAS_ADDR(dev->sas_addr));
++ if (!le16_to_cpu(identify_x[83] & (1<<6)))
++ goto cont1;
++ res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
++ ATA_FEATURE_PUP_STBY_SPIN_UP,
++ NULL, 0, PCI_DMA_NONE);
++ if (res)
++ goto cont1;
++
++ schedule_timeout_interruptible(5*HZ); /* More time? */
++ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
++ PCI_DMA_FROMDEVICE);
++ if (res)
++ goto out_err;
++ }
++cont1:
++ /* Get WWN */
++ if (dev->port->oob_mode != SATA_OOB_MODE) {
++ memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
++ SAS_ADDR_SIZE);
++ } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
++ (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
++ == 0x5000) {
++ int i;
++
++ for (i = 0; i < 4; i++) {
++ dev->sas_addr[2*i] =
++ (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
++ dev->sas_addr[2*i+1] =
++ le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
++ }
++ }
++ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
++ if (!dev->parent)
++ sas_sata_propagate_sas_addr(dev);
++
++ /* XXX Hint: register this SATA device with SATL.
++ When this returns, dev->sata_dev->lu is alive and
++ present.
++ sas_satl_register_dev(dev);
++ */
++ return 0;
++out_err:
++ dev->sata_dev.identify_packet_device = NULL;
++ dev->sata_dev.identify_device = NULL;
++ kfree(identify_x);
++ return res;
++}
++
++static int sas_discover_sata_pm(struct domain_device *dev)
++{
++ return -ENODEV;
++}
++
++int sas_notify_lldd_dev_found(struct domain_device *dev)
++{
++ int res = 0;
++ struct sas_ha_struct *sas_ha = dev->port->ha;
++ struct Scsi_Host *shost = sas_ha->core.shost;
++ struct sas_internal *i = to_sas_internal(shost->transportt);
++
++ if (i->dft->lldd_dev_found) {
++ res = i->dft->lldd_dev_found(dev);
++ if (res) {
++ printk("sas: driver on pcidev %s cannot handle "
++ "device %llx, error:%d\n",
++ pci_name(sas_ha->pcidev),
++ SAS_ADDR(dev->sas_addr), res);
++ }
++ }
++ return res;
++}
++
++
++void sas_notify_lldd_dev_gone(struct domain_device *dev)
++{
++ struct sas_ha_struct *sas_ha = dev->port->ha;
++ struct Scsi_Host *shost = sas_ha->core.shost;
++ struct sas_internal *i = to_sas_internal(shost->transportt);
++
++ if (i->dft->lldd_dev_gone)
++ i->dft->lldd_dev_gone(dev);
++}
++
++/* ---------- Common/dispatchers ---------- */
++
++/**
++ * sas_discover_sata -- discover an STP/SATA domain device
++ * @dev: pointer to struct domain_device of interest
++ *
++ * First we notify the LLDD of this device, so we can send frames to
++ * it. Then depending on the type of device we call the appropriate
++ * discover functions. Once device discover is done, we notify the
++ * LLDD so that it can fine-tune its parameters for the device, by
++ * removing it and then adding it. That is, the second time around,
++ * the driver would have certain fields, that it is looking at, set.
++ * Finally we initialize the kobj so that the device can be added to
++ * the system at registration time. Devices directly attached to a HA
++ * port, have no parents. All other devices do, and should have their
++ * "parent" pointer set appropriately before calling this function.
++ */
++int sas_discover_sata(struct domain_device *dev)
++{
++ int res;
++
++ sas_get_ata_command_set(dev);
++
++ res = sas_notify_lldd_dev_found(dev);
++ if (res)
++ return res;
++
++ switch (dev->dev_type) {
++ case SATA_DEV:
++ res = sas_discover_sata_dev(dev);
++ break;
++ case SATA_PM:
++ res = sas_discover_sata_pm(dev);
++ break;
++ default:
++ break;
++ }
++
++ sas_notify_lldd_dev_gone(dev);
++ if (!res) {
++ sas_notify_lldd_dev_found(dev);
++ }
++ return res;
++}
++
++/**
++ * sas_discover_end_dev -- discover an end device (SSP, etc)
++ * @end: pointer to domain device of interest
++ *
++ * See comment in sas_discover_sata().
++ */
++int sas_discover_end_dev(struct domain_device *dev)
++{
++ int res;
++
++ res = sas_notify_lldd_dev_found(dev);
++ if (res)
++ return res;
++
++ res = sas_rphy_add(dev->rphy);
++ if (res)
++ goto out_err;
++
++ /* do this to get the end device port attributes which will have
++ * been scanned in sas_rphy_add */
++ sas_notify_lldd_dev_gone(dev);
++ sas_notify_lldd_dev_found(dev);
++
++ return 0;
++
++out_err:
++ sas_notify_lldd_dev_gone(dev);
++ return res;
++}
++
++/* ---------- Device registration and unregistration ---------- */
++
++static inline void sas_unregister_common_dev(struct domain_device *dev)
++{
++ sas_notify_lldd_dev_gone(dev);
++ if (!dev->parent)
++ dev->port->port_dev = NULL;
++ else
++ list_del_init(&dev->siblings);
++ list_del_init(&dev->dev_list_node);
++}
++
++void sas_unregister_dev(struct domain_device *dev)
++{
++ if (dev->rphy) {
++ sas_remove_children(&dev->rphy->dev);
++ sas_rphy_delete(dev->rphy);
++ dev->rphy = NULL;
++ }
++ if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
++ /* remove the phys and ports, everything else should be gone */
++ kfree(dev->ex_dev.ex_phy);
++ dev->ex_dev.ex_phy = NULL;
++ }
++ sas_unregister_common_dev(dev);
++}
++
++void sas_unregister_domain_devices(struct asd_sas_port *port)
++{
++ struct domain_device *dev, *n;
++
++ list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node)
++ sas_unregister_dev(dev);
++
++ port->port->rphy = NULL;
++
++}
++
++/* ---------- Discovery and Revalidation ---------- */
++
++/**
++ * sas_discover_domain -- discover the domain
++ * @port: port to the domain of interest
++ *
++ * NOTE: this process _must_ quit (return) as soon as any connection
++ * errors are encountered. Connection recovery is done elsewhere.
++ * Discover process only interrogates devices in order to discover the
++ * domain.
++ */
++static void sas_discover_domain(void *data)
++{
++ int error = 0;
++ struct asd_sas_port *port = data;
++
++ sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
++ &port->disc.pending);
++
++ if (port->port_dev)
++ return ;
++ else {
++ error = sas_get_port_device(port);
++ if (error)
++ return;
++ }
++
++ SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
++ current->pid);
++
++ switch (port->port_dev->dev_type) {
++ case SAS_END_DEV:
++ error = sas_discover_end_dev(port->port_dev);
++ break;
++ case EDGE_DEV:
++ case FANOUT_DEV:
++ error = sas_discover_root_expander(port->port_dev);
++ break;
++ case SATA_DEV:
++ case SATA_PM:
++ error = sas_discover_sata(port->port_dev);
++ break;
++ default:
++ SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type);
++ break;
++ }
++
++ if (error) {
++ kfree(port->port_dev); /* not kobject_register-ed yet */
++ port->port_dev = NULL;
++ }
++
++ SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
++ current->pid, error);
++}
++
++static void sas_revalidate_domain(void *data)
++{
++ int res = 0;
++ struct asd_sas_port *port = data;
++
++ sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
++ &port->disc.pending);
++
++ SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
++ current->pid);
++ if (port->port_dev)
++ res = sas_ex_revalidate_domain(port->port_dev);
++
++ SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
++ port->id, current->pid, res);
++}
++
++/* ---------- Events ---------- */
++
++int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
++{
++ struct sas_discovery *disc;
++
++ if (!port)
++ return 0;
++ disc = &port->disc;
++
++ BUG_ON(ev >= DISC_NUM_EVENTS);
++
++ sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
++ &disc->disc_work[ev], port->ha->core.shost);
++
++ return 0;
++}
++
++/**
++ * sas_init_disc -- initialize the discovery struct in the port
++ * @port: pointer to struct port
++ *
++ * Called when the ports are being initialized.
++ */
++void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
++{
++ int i;
++
++ static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = {
++ [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
++ [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
++ };
++
++ spin_lock_init(&disc->disc_event_lock);
++ disc->pending = 0;
++ for (i = 0; i < DISC_NUM_EVENTS; i++)
++ INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port);
++}
+diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
+new file mode 100644
+index 0000000..f1246d2
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_dump.c
+@@ -0,0 +1,76 @@
++/*
++ * Serial Attached SCSI (SAS) Dump/Debugging routines
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include "sas_dump.h"
++
++#ifdef SAS_DEBUG
++
++static const char *sas_hae_str[] = {
++ [0] = "HAE_RESET",
++};
++
++static const char *sas_porte_str[] = {
++ [0] = "PORTE_BYTES_DMAED",
++ [1] = "PORTE_BROADCAST_RCVD",
++ [2] = "PORTE_LINK_RESET_ERR",
++ [3] = "PORTE_TIMER_EVENT",
++ [4] = "PORTE_HARD_RESET",
++};
++
++static const char *sas_phye_str[] = {
++ [0] = "PHYE_LOSS_OF_SIGNAL",
++ [1] = "PHYE_OOB_DONE",
++ [2] = "PHYE_OOB_ERROR",
++ [3] = "PHYE_SPINUP_HOLD",
++};
++
++void sas_dprint_porte(int phyid, enum port_event pe)
++{
++ SAS_DPRINTK("phy%d: port event: %s\n", phyid, sas_porte_str[pe]);
++}
++void sas_dprint_phye(int phyid, enum phy_event pe)
++{
++ SAS_DPRINTK("phy%d: phy event: %s\n", phyid, sas_phye_str[pe]);
++}
++
++void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
++{
++ SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev),
++ sas_hae_str[he]);
++}
++
++void sas_dump_port(struct asd_sas_port *port)
++{
++ SAS_DPRINTK("port%d: class:0x%x\n", port->id, port->class);
++ SAS_DPRINTK("port%d: sas_addr:%llx\n", port->id,
++ SAS_ADDR(port->sas_addr));
++ SAS_DPRINTK("port%d: attached_sas_addr:%llx\n", port->id,
++ SAS_ADDR(port->attached_sas_addr));
++ SAS_DPRINTK("port%d: iproto:0x%x\n", port->id, port->iproto);
++ SAS_DPRINTK("port%d: tproto:0x%x\n", port->id, port->tproto);
++ SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode);
++ SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys);
++}
++
++#endif /* SAS_DEBUG */
+diff --git a/drivers/scsi/libsas/sas_dump.h b/drivers/scsi/libsas/sas_dump.h
+new file mode 100644
+index 0000000..47b45d4
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_dump.h
+@@ -0,0 +1,42 @@
++/*
++ * Serial Attached SCSI (SAS) Dump/Debugging routines header file
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include "sas_internal.h"
++
++#ifdef SAS_DEBUG
++
++void sas_dprint_porte(int phyid, enum port_event pe);
++void sas_dprint_phye(int phyid, enum phy_event pe);
++void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he);
++void sas_dump_port(struct asd_sas_port *port);
++
++#else /* SAS_DEBUG */
++
++static inline void sas_dprint_porte(int phyid, enum port_event pe) { }
++static inline void sas_dprint_phye(int phyid, enum phy_event pe) { }
++static inline void sas_dprint_hae(struct sas_ha_struct *sas_ha,
++ enum ha_event he) { }
++static inline void sas_dump_port(struct asd_sas_port *port) { }
++
++#endif /* SAS_DEBUG */
+diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
+new file mode 100644
+index 0000000..19110ed
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_event.c
+@@ -0,0 +1,75 @@
++/*
++ * Serial Attached SCSI (SAS) Event processing
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <scsi/scsi_host.h>
++#include "sas_internal.h"
++#include "sas_dump.h"
++
++static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
++{
++ BUG_ON(event >= HA_NUM_EVENTS);
++
++ sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
++ &sas_ha->ha_events[event], sas_ha->core.shost);
++}
++
++static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
++{
++ struct sas_ha_struct *ha = phy->ha;
++
++ BUG_ON(event >= PORT_NUM_EVENTS);
++
++ sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
++ &phy->port_events[event], ha->core.shost);
++}
++
++static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
++{
++ struct sas_ha_struct *ha = phy->ha;
++
++ BUG_ON(event >= PHY_NUM_EVENTS);
++
++ sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
++ &phy->phy_events[event], ha->core.shost);
++}
++
++int sas_init_events(struct sas_ha_struct *sas_ha)
++{
++ static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = {
++ [HAE_RESET] = sas_hae_reset,
++ };
++
++ int i;
++
++ spin_lock_init(&sas_ha->event_lock);
++
++ for (i = 0; i < HA_NUM_EVENTS; i++)
++ INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha);
++
++ sas_ha->notify_ha_event = notify_ha_event;
++ sas_ha->notify_port_event = notify_port_event;
++ sas_ha->notify_phy_event = notify_phy_event;
++
++ return 0;
++}
+diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
+new file mode 100644
+index 0000000..30b8014
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_expander.c
+@@ -0,0 +1,1855 @@
++/*
++ * Serial Attached SCSI (SAS) Expander discovery and configuration
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/pci.h>
++#include <linux/scatterlist.h>
++
++#include "sas_internal.h"
++
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++#include "../scsi_sas_internal.h"
++
++static int sas_discover_expander(struct domain_device *dev);
++static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr);
++static int sas_configure_phy(struct domain_device *dev, int phy_id,
++ u8 *sas_addr, int include);
++static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);
++
++#if 0
++/* FIXME: smp needs to migrate into the sas class */
++static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
++static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
++#endif
++
++/* ---------- SMP task management ---------- */
++
++static void smp_task_timedout(unsigned long _task)
++{
++ struct sas_task *task = (void *) _task;
++ unsigned long flags;
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
++ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ complete(&task->completion);
++}
++
++static void smp_task_done(struct sas_task *task)
++{
++ if (!del_timer(&task->timer))
++ return;
++ complete(&task->completion);
++}
++
++/* Give it some long enough timeout. In seconds. */
++#define SMP_TIMEOUT 10
++
++static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
++ void *resp, int resp_size)
++{
++ int res;
++ struct sas_task *task = sas_alloc_task(GFP_KERNEL);
++ struct sas_internal *i =
++ to_sas_internal(dev->port->ha->core.shost->transportt);
++
++ if (!task)
++ return -ENOMEM;
++
++ task->dev = dev;
++ task->task_proto = dev->tproto;
++ sg_init_one(&task->smp_task.smp_req, req, req_size);
++ sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
++
++ task->task_done = smp_task_done;
++
++ task->timer.data = (unsigned long) task;
++ task->timer.function = smp_task_timedout;
++ task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
++ add_timer(&task->timer);
++
++ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
++
++ if (res) {
++ del_timer(&task->timer);
++ SAS_DPRINTK("executing SMP task failed:%d\n", res);
++ goto ex_err;
++ }
++
++ wait_for_completion(&task->completion);
++ res = -ETASK;
++ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
++ SAS_DPRINTK("smp task timed out or aborted\n");
++ i->dft->lldd_abort_task(task);
++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
++ SAS_DPRINTK("SMP task aborted and not done\n");
++ goto ex_err;
++ }
++ }
++ if (task->task_status.resp == SAS_TASK_COMPLETE &&
++ task->task_status.stat == SAM_GOOD)
++ res = 0;
++ else
++ SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
++ "status 0x%x\n", __FUNCTION__,
++ SAS_ADDR(dev->sas_addr),
++ task->task_status.resp,
++ task->task_status.stat);
++ex_err:
++ sas_free_task(task);
++ return res;
++}
++
++/* ---------- Allocations ---------- */
++
++static inline void *alloc_smp_req(int size)
++{
++ u8 *p = kzalloc(size, GFP_KERNEL);
++ if (p)
++ p[0] = SMP_REQUEST;
++ return p;
++}
++
++static inline void *alloc_smp_resp(int size)
++{
++ return kzalloc(size, GFP_KERNEL);
++}
++
++/* ---------- Expander configuration ---------- */
++
++static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
++ void *disc_resp)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *phy = &ex->ex_phy[phy_id];
++ struct smp_resp *resp = disc_resp;
++ struct discover_resp *dr = &resp->disc;
++ struct sas_rphy *rphy = dev->rphy;
++ int rediscover = (phy->phy != NULL);
++
++ if (!rediscover) {
++ phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
++
++ /* FIXME: error_handling */
++ BUG_ON(!phy->phy);
++ }
++
++ switch (resp->result) {
++ case SMP_RESP_PHY_VACANT:
++ phy->phy_state = PHY_VACANT;
++ return;
++ default:
++ phy->phy_state = PHY_NOT_PRESENT;
++ return;
++ case SMP_RESP_FUNC_ACC:
++ phy->phy_state = PHY_EMPTY; /* do not know yet */
++ break;
++ }
++
++ phy->phy_id = phy_id;
++ phy->attached_dev_type = dr->attached_dev_type;
++ phy->linkrate = dr->linkrate;
++ phy->attached_sata_host = dr->attached_sata_host;
++ phy->attached_sata_dev = dr->attached_sata_dev;
++ phy->attached_sata_ps = dr->attached_sata_ps;
++ phy->attached_iproto = dr->iproto << 1;
++ phy->attached_tproto = dr->tproto << 1;
++ memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);
++ phy->attached_phy_id = dr->attached_phy_id;
++ phy->phy_change_count = dr->change_count;
++ phy->routing_attr = dr->routing_attr;
++ phy->virtual = dr->virtual;
++ phy->last_da_index = -1;
++
++ phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
++ phy->phy->identify.target_port_protocols = phy->attached_tproto;
++ phy->phy->identify.phy_identifier = phy_id;
++ phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
++ phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
++ phy->phy->minimum_linkrate = dr->pmin_linkrate;
++ phy->phy->maximum_linkrate = dr->pmax_linkrate;
++ phy->phy->negotiated_linkrate = phy->linkrate;
++
++ if (!rediscover)
++ sas_phy_add(phy->phy);
++
++ SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
++ SAS_ADDR(dev->sas_addr), phy->phy_id,
++ phy->routing_attr == TABLE_ROUTING ? 'T' :
++ phy->routing_attr == DIRECT_ROUTING ? 'D' :
++ phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
++ SAS_ADDR(phy->attached_sas_addr));
++
++ return;
++}
++
++#define DISCOVER_REQ_SIZE 16
++#define DISCOVER_RESP_SIZE 56
++
++static int sas_ex_phy_discover(struct domain_device *dev, int single)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int res = 0;
++ u8 *disc_req;
++ u8 *disc_resp;
++
++ disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
++ if (!disc_req)
++ return -ENOMEM;
++
++ disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
++ if (!disc_resp) {
++ kfree(disc_req);
++ return -ENOMEM;
++ }
++
++ disc_req[1] = SMP_DISCOVER;
++
++ if (0 <= single && single < ex->num_phys) {
++ disc_req[9] = single;
++ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
++ disc_resp, DISCOVER_RESP_SIZE);
++ if (res)
++ goto out_err;
++ sas_set_ex_phy(dev, single, disc_resp);
++ } else {
++ int i;
++
++ for (i = 0; i < ex->num_phys; i++) {
++ disc_req[9] = i;
++ res = smp_execute_task(dev, disc_req,
++ DISCOVER_REQ_SIZE, disc_resp,
++ DISCOVER_RESP_SIZE);
++ if (res)
++ goto out_err;
++ sas_set_ex_phy(dev, i, disc_resp);
++ }
++ }
++out_err:
++ kfree(disc_resp);
++ kfree(disc_req);
++ return res;
++}
++
++static int sas_expander_discover(struct domain_device *dev)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int res = -ENOMEM;
++
++ ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL);
++ if (!ex->ex_phy)
++ return -ENOMEM;
++
++ res = sas_ex_phy_discover(dev, -1);
++ if (res)
++ goto out_err;
++
++ return 0;
++ out_err:
++ kfree(ex->ex_phy);
++ ex->ex_phy = NULL;
++ return res;
++}
++
++#define MAX_EXPANDER_PHYS 128
++
++static void ex_assign_report_general(struct domain_device *dev,
++ struct smp_resp *resp)
++{
++ struct report_general_resp *rg = &resp->rg;
++
++ dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count);
++ dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes);
++ dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS);
++ dev->ex_dev.conf_route_table = rg->conf_route_table;
++ dev->ex_dev.configuring = rg->configuring;
++ memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8);
++}
++
++#define RG_REQ_SIZE 8
++#define RG_RESP_SIZE 32
++
++static int sas_ex_general(struct domain_device *dev)
++{
++ u8 *rg_req;
++ struct smp_resp *rg_resp;
++ int res;
++ int i;
++
++ rg_req = alloc_smp_req(RG_REQ_SIZE);
++ if (!rg_req)
++ return -ENOMEM;
++
++ rg_resp = alloc_smp_resp(RG_RESP_SIZE);
++ if (!rg_resp) {
++ kfree(rg_req);
++ return -ENOMEM;
++ }
++
++ rg_req[1] = SMP_REPORT_GENERAL;
++
++ for (i = 0; i < 5; i++) {
++ res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
++ RG_RESP_SIZE);
++
++ if (res) {
++ SAS_DPRINTK("RG to ex %016llx failed:0x%x\n",
++ SAS_ADDR(dev->sas_addr), res);
++ goto out;
++ } else if (rg_resp->result != SMP_RESP_FUNC_ACC) {
++ SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n",
++ SAS_ADDR(dev->sas_addr), rg_resp->result);
++ res = rg_resp->result;
++ goto out;
++ }
++
++ ex_assign_report_general(dev, rg_resp);
++
++ if (dev->ex_dev.configuring) {
++ SAS_DPRINTK("RG: ex %llx self-configuring...\n",
++ SAS_ADDR(dev->sas_addr));
++ schedule_timeout_interruptible(5*HZ);
++ } else
++ break;
++ }
++out:
++ kfree(rg_req);
++ kfree(rg_resp);
++ return res;
++}
++
++static void ex_assign_manuf_info(struct domain_device *dev, void
++ *_mi_resp)
++{
++ u8 *mi_resp = _mi_resp;
++ struct sas_rphy *rphy = dev->rphy;
++ struct sas_expander_device *edev = rphy_to_expander_device(rphy);
++
++ memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN);
++ memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN);
++ memcpy(edev->product_rev, mi_resp + 36,
++ SAS_EXPANDER_PRODUCT_REV_LEN);
++
++ if (mi_resp[8] & 1) {
++ memcpy(edev->component_vendor_id, mi_resp + 40,
++ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
++ edev->component_id = mi_resp[48] << 8 | mi_resp[49];
++ edev->component_revision_id = mi_resp[50];
++ }
++}
++
++#define MI_REQ_SIZE 8
++#define MI_RESP_SIZE 64
++
++static int sas_ex_manuf_info(struct domain_device *dev)
++{
++ u8 *mi_req;
++ u8 *mi_resp;
++ int res;
++
++ mi_req = alloc_smp_req(MI_REQ_SIZE);
++ if (!mi_req)
++ return -ENOMEM;
++
++ mi_resp = alloc_smp_resp(MI_RESP_SIZE);
++ if (!mi_resp) {
++ kfree(mi_req);
++ return -ENOMEM;
++ }
++
++ mi_req[1] = SMP_REPORT_MANUF_INFO;
++
++ res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE);
++ if (res) {
++ SAS_DPRINTK("MI: ex %016llx failed:0x%x\n",
++ SAS_ADDR(dev->sas_addr), res);
++ goto out;
++ } else if (mi_resp[2] != SMP_RESP_FUNC_ACC) {
++ SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n",
++ SAS_ADDR(dev->sas_addr), mi_resp[2]);
++ goto out;
++ }
++
++ ex_assign_manuf_info(dev, mi_resp);
++out:
++ kfree(mi_req);
++ kfree(mi_resp);
++ return res;
++}
++
++#define PC_REQ_SIZE 44
++#define PC_RESP_SIZE 8
++
++int sas_smp_phy_control(struct domain_device *dev, int phy_id,
++ enum phy_func phy_func,
++ struct sas_phy_linkrates *rates)
++{
++ u8 *pc_req;
++ u8 *pc_resp;
++ int res;
++
++ pc_req = alloc_smp_req(PC_REQ_SIZE);
++ if (!pc_req)
++ return -ENOMEM;
++
++ pc_resp = alloc_smp_resp(PC_RESP_SIZE);
++ if (!pc_resp) {
++ kfree(pc_req);
++ return -ENOMEM;
++ }
++
++ pc_req[1] = SMP_PHY_CONTROL;
++ pc_req[9] = phy_id;
++ pc_req[10]= phy_func;
++ if (rates) {
++ pc_req[32] = rates->minimum_linkrate << 4;
++ pc_req[33] = rates->maximum_linkrate << 4;
++ }
++
++ res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
++
++ kfree(pc_resp);
++ kfree(pc_req);
++ return res;
++}
++
++static void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *phy = &ex->ex_phy[phy_id];
++
++ sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL);
++ phy->linkrate = SAS_PHY_DISABLED;
++}
++
++static void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int i;
++
++ for (i = 0; i < ex->num_phys; i++) {
++ struct ex_phy *phy = &ex->ex_phy[i];
++
++ if (phy->phy_state == PHY_VACANT ||
++ phy->phy_state == PHY_NOT_PRESENT)
++ continue;
++
++ if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr))
++ sas_ex_disable_phy(dev, i);
++ }
++}
++
++static int sas_dev_present_in_domain(struct asd_sas_port *port,
++ u8 *sas_addr)
++{
++ struct domain_device *dev;
++
++ if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr))
++ return 1;
++ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
++ if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr))
++ return 1;
++ }
++ return 0;
++}
++
++#define RPEL_REQ_SIZE 16
++#define RPEL_RESP_SIZE 32
++int sas_smp_get_phy_events(struct sas_phy *phy)
++{
++ int res;
++ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
++ struct domain_device *dev = sas_find_dev_by_rphy(rphy);
++ u8 *req = alloc_smp_req(RPEL_REQ_SIZE);
++ u8 *resp = kzalloc(RPEL_RESP_SIZE, GFP_KERNEL);
++
++ if (!resp)
++ return -ENOMEM;
++
++ req[1] = SMP_REPORT_PHY_ERR_LOG;
++ req[9] = phy->number;
++
++ res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
++ resp, RPEL_RESP_SIZE);
++
++ if (!res)
++ goto out;
++
++ phy->invalid_dword_count = scsi_to_u32(&resp[12]);
++ phy->running_disparity_error_count = scsi_to_u32(&resp[16]);
++ phy->loss_of_dword_sync_count = scsi_to_u32(&resp[20]);
++ phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
++
++ out:
++ kfree(resp);
++ return res;
++
++}
++
++#define RPS_REQ_SIZE 16
++#define RPS_RESP_SIZE 60
++
++static int sas_get_report_phy_sata(struct domain_device *dev,
++ int phy_id,
++ struct smp_resp *rps_resp)
++{
++ int res;
++ u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
++
++ if (!rps_req)
++ return -ENOMEM;
++
++ rps_req[1] = SMP_REPORT_PHY_SATA;
++ rps_req[9] = phy_id;
++
++ res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
++ rps_resp, RPS_RESP_SIZE);
++
++ kfree(rps_req);
++ return 0;
++}
++
++static void sas_ex_get_linkrate(struct domain_device *parent,
++ struct domain_device *child,
++ struct ex_phy *parent_phy)
++{
++ struct expander_device *parent_ex = &parent->ex_dev;
++ struct sas_port *port;
++ int i;
++
++ child->pathways = 0;
++
++ port = parent_phy->port;
++
++ for (i = 0; i < parent_ex->num_phys; i++) {
++ struct ex_phy *phy = &parent_ex->ex_phy[i];
++
++ if (phy->phy_state == PHY_VACANT ||
++ phy->phy_state == PHY_NOT_PRESENT)
++ continue;
++
++ if (SAS_ADDR(phy->attached_sas_addr) ==
++ SAS_ADDR(child->sas_addr)) {
++
++ child->min_linkrate = min(parent->min_linkrate,
++ phy->linkrate);
++ child->max_linkrate = max(parent->max_linkrate,
++ phy->linkrate);
++ child->pathways++;
++ sas_port_add_phy(port, phy->phy);
++ }
++ }
++ child->linkrate = min(parent_phy->linkrate, child->max_linkrate);
++ child->pathways = min(child->pathways, parent->pathways);
++}
++
++static struct domain_device *sas_ex_discover_end_dev(
++ struct domain_device *parent, int phy_id)
++{
++ struct expander_device *parent_ex = &parent->ex_dev;
++ struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
++ struct domain_device *child = NULL;
++ struct sas_rphy *rphy;
++ int res;
++
++ if (phy->attached_sata_host || phy->attached_sata_ps)
++ return NULL;
++
++ child = kzalloc(sizeof(*child), GFP_KERNEL);
++ if (!child)
++ return NULL;
++
++ child->parent = parent;
++ child->port = parent->port;
++ child->iproto = phy->attached_iproto;
++ memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
++ sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
++ phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
++ BUG_ON(!phy->port);
++ /* FIXME: better error handling*/
++ BUG_ON(sas_port_add(phy->port) != 0);
++ sas_ex_get_linkrate(parent, child, phy);
++
++ if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
++ child->dev_type = SATA_DEV;
++ if (phy->attached_tproto & SAS_PROTO_STP)
++ child->tproto = phy->attached_tproto;
++ if (phy->attached_sata_dev)
++ child->tproto |= SATA_DEV;
++ res = sas_get_report_phy_sata(parent, phy_id,
++ &child->sata_dev.rps_resp);
++ if (res) {
++ SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
++ "0x%x\n", SAS_ADDR(parent->sas_addr),
++ phy_id, res);
++ kfree(child);
++ return NULL;
++ }
++ memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
++ sizeof(struct dev_to_host_fis));
++ sas_init_dev(child);
++ res = sas_discover_sata(child);
++ if (res) {
++ SAS_DPRINTK("sas_discover_sata() for device %16llx at "
++ "%016llx:0x%x returned 0x%x\n",
++ SAS_ADDR(child->sas_addr),
++ SAS_ADDR(parent->sas_addr), phy_id, res);
++ kfree(child);
++ return NULL;
++ }
++ } else if (phy->attached_tproto & SAS_PROTO_SSP) {
++ child->dev_type = SAS_END_DEV;
++ rphy = sas_end_device_alloc(phy->port);
++ /* FIXME: error handling */
++ BUG_ON(!rphy);
++ child->tproto = phy->attached_tproto;
++ sas_init_dev(child);
++
++ child->rphy = rphy;
++ sas_fill_in_rphy(child, rphy);
++
++ spin_lock(&parent->port->dev_list_lock);
++ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
++ spin_unlock(&parent->port->dev_list_lock);
++
++ res = sas_discover_end_dev(child);
++ if (res) {
++ SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
++ "at %016llx:0x%x returned 0x%x\n",
++ SAS_ADDR(child->sas_addr),
++ SAS_ADDR(parent->sas_addr), phy_id, res);
++ /* FIXME: this kfrees list elements without removing them */
++ //kfree(child);
++ return NULL;
++ }
++ } else {
++ SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
++ phy->attached_tproto, SAS_ADDR(parent->sas_addr),
++ phy_id);
++ }
++
++ list_add_tail(&child->siblings, &parent_ex->children);
++ return child;
++}
++
++static struct domain_device *sas_ex_discover_expander(
++ struct domain_device *parent, int phy_id)
++{
++ struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy);
++ struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
++ struct domain_device *child = NULL;
++ struct sas_rphy *rphy;
++ struct sas_expander_device *edev;
++ struct asd_sas_port *port;
++ int res;
++
++ if (phy->routing_attr == DIRECT_ROUTING) {
++ SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not "
++ "allowed\n",
++ SAS_ADDR(parent->sas_addr), phy_id,
++ SAS_ADDR(phy->attached_sas_addr),
++ phy->attached_phy_id);
++ return NULL;
++ }
++ child = kzalloc(sizeof(*child), GFP_KERNEL);
++ if (!child)
++ return NULL;
++
++ phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
++ /* FIXME: better error handling */
++ BUG_ON(sas_port_add(phy->port) != 0);
++
++
++ switch (phy->attached_dev_type) {
++ case EDGE_DEV:
++ rphy = sas_expander_alloc(phy->port,
++ SAS_EDGE_EXPANDER_DEVICE);
++ break;
++ case FANOUT_DEV:
++ rphy = sas_expander_alloc(phy->port,
++ SAS_FANOUT_EXPANDER_DEVICE);
++ break;
++ default:
++ rphy = NULL; /* shut gcc up */
++ BUG();
++ }
++ port = parent->port;
++ child->rphy = rphy;
++ edev = rphy_to_expander_device(rphy);
++ child->dev_type = phy->attached_dev_type;
++ child->parent = parent;
++ child->port = port;
++ child->iproto = phy->attached_iproto;
++ child->tproto = phy->attached_tproto;
++ memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
++ sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
++ sas_ex_get_linkrate(parent, child, phy);
++ edev->level = parent_ex->level + 1;
++ parent->port->disc.max_level = max(parent->port->disc.max_level,
++ edev->level);
++ sas_init_dev(child);
++ sas_fill_in_rphy(child, rphy);
++ sas_rphy_add(rphy);
++
++ spin_lock(&parent->port->dev_list_lock);
++ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
++ spin_unlock(&parent->port->dev_list_lock);
++
++ res = sas_discover_expander(child);
++ if (res) {
++ kfree(child);
++ return NULL;
++ }
++ list_add_tail(&child->siblings, &parent->ex_dev.children);
++ return child;
++}
++
++static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
++ struct domain_device *child = NULL;
++ int res = 0;
++
++ /* Phy state */
++ if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) {
++ if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL))
++ res = sas_ex_phy_discover(dev, phy_id);
++ if (res)
++ return res;
++ }
++
++ /* Parent and domain coherency */
++ if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
++ SAS_ADDR(dev->port->sas_addr))) {
++ sas_add_parent_port(dev, phy_id);
++ return 0;
++ }
++ if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
++ SAS_ADDR(dev->parent->sas_addr))) {
++ sas_add_parent_port(dev, phy_id);
++ if (ex_phy->routing_attr == TABLE_ROUTING)
++ sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1);
++ return 0;
++ }
++
++ if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr))
++ sas_ex_disable_port(dev, ex_phy->attached_sas_addr);
++
++ if (ex_phy->attached_dev_type == NO_DEVICE) {
++ if (ex_phy->routing_attr == DIRECT_ROUTING) {
++ memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
++ sas_configure_routing(dev, ex_phy->attached_sas_addr);
++ }
++ return 0;
++ } else if (ex_phy->linkrate == SAS_LINK_RATE_UNKNOWN)
++ return 0;
++
++ if (ex_phy->attached_dev_type != SAS_END_DEV &&
++ ex_phy->attached_dev_type != FANOUT_DEV &&
++ ex_phy->attached_dev_type != EDGE_DEV) {
++ SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
++ "phy 0x%x\n", ex_phy->attached_dev_type,
++ SAS_ADDR(dev->sas_addr),
++ phy_id);
++ return 0;
++ }
++
++ res = sas_configure_routing(dev, ex_phy->attached_sas_addr);
++ if (res) {
++ SAS_DPRINTK("configure routing for dev %016llx "
++ "reported 0x%x. Forgotten\n",
++ SAS_ADDR(ex_phy->attached_sas_addr), res);
++ sas_disable_routing(dev, ex_phy->attached_sas_addr);
++ return res;
++ }
++
++ switch (ex_phy->attached_dev_type) {
++ case SAS_END_DEV:
++ child = sas_ex_discover_end_dev(dev, phy_id);
++ break;
++ case FANOUT_DEV:
++ if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
++ SAS_DPRINTK("second fanout expander %016llx phy 0x%x "
++ "attached to ex %016llx phy 0x%x\n",
++ SAS_ADDR(ex_phy->attached_sas_addr),
++ ex_phy->attached_phy_id,
++ SAS_ADDR(dev->sas_addr),
++ phy_id);
++ sas_ex_disable_phy(dev, phy_id);
++ break;
++ } else
++ memcpy(dev->port->disc.fanout_sas_addr,
++ ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
++ /* fallthrough */
++ case EDGE_DEV:
++ child = sas_ex_discover_expander(dev, phy_id);
++ break;
++ default:
++ break;
++ }
++
++ if (child) {
++ int i;
++
++ for (i = 0; i < ex->num_phys; i++) {
++ if (ex->ex_phy[i].phy_state == PHY_VACANT ||
++ ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
++ continue;
++
++ if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
++ SAS_ADDR(child->sas_addr))
++ ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
++ }
++ }
++
++ return res;
++}
++
++static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int i;
++
++ for (i = 0; i < ex->num_phys; i++) {
++ struct ex_phy *phy = &ex->ex_phy[i];
++
++ if (phy->phy_state == PHY_VACANT ||
++ phy->phy_state == PHY_NOT_PRESENT)
++ continue;
++
++ if ((phy->attached_dev_type == EDGE_DEV ||
++ phy->attached_dev_type == FANOUT_DEV) &&
++ phy->routing_attr == SUBTRACTIVE_ROUTING) {
++
++ memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE);
++
++ return 1;
++ }
++ }
++ return 0;
++}
++
++static int sas_check_level_subtractive_boundary(struct domain_device *dev)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct domain_device *child;
++ u8 sub_addr[8] = {0, };
++
++ list_for_each_entry(child, &ex->children, siblings) {
++ if (child->dev_type != EDGE_DEV &&
++ child->dev_type != FANOUT_DEV)
++ continue;
++ if (sub_addr[0] == 0) {
++ sas_find_sub_addr(child, sub_addr);
++ continue;
++ } else {
++ u8 s2[8];
++
++ if (sas_find_sub_addr(child, s2) &&
++ (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
++
++ SAS_DPRINTK("ex %016llx->%016llx-?->%016llx "
++ "diverges from subtractive "
++ "boundary %016llx\n",
++ SAS_ADDR(dev->sas_addr),
++ SAS_ADDR(child->sas_addr),
++ SAS_ADDR(s2),
++ SAS_ADDR(sub_addr));
++
++ sas_ex_disable_port(child, s2);
++ }
++ }
++ }
++ return 0;
++}
++/**
++ * sas_ex_discover_devices -- discover devices attached to this expander
++ * dev: pointer to the expander domain device
++ * single: if you want to do a single phy, else set to -1;
++ *
++ * Configure this expander for use with its devices and register the
++ * devices of this expander.
++ */
++static int sas_ex_discover_devices(struct domain_device *dev, int single)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int i = 0, end = ex->num_phys;
++ int res = 0;
++
++ if (0 <= single && single < end) {
++ i = single;
++ end = i+1;
++ }
++
++ for ( ; i < end; i++) {
++ struct ex_phy *ex_phy = &ex->ex_phy[i];
++
++ if (ex_phy->phy_state == PHY_VACANT ||
++ ex_phy->phy_state == PHY_NOT_PRESENT ||
++ ex_phy->phy_state == PHY_DEVICE_DISCOVERED)
++ continue;
++
++ switch (ex_phy->linkrate) {
++ case SAS_PHY_DISABLED:
++ case SAS_PHY_RESET_PROBLEM:
++ case SAS_SATA_PORT_SELECTOR:
++ continue;
++ default:
++ res = sas_ex_discover_dev(dev, i);
++ if (res)
++ break;
++ continue;
++ }
++ }
++
++ if (!res)
++ sas_check_level_subtractive_boundary(dev);
++
++ return res;
++}
++
++static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int i;
++ u8 *sub_sas_addr = NULL;
++
++ if (dev->dev_type != EDGE_DEV)
++ return 0;
++
++ for (i = 0; i < ex->num_phys; i++) {
++ struct ex_phy *phy = &ex->ex_phy[i];
++
++ if (phy->phy_state == PHY_VACANT ||
++ phy->phy_state == PHY_NOT_PRESENT)
++ continue;
++
++ if ((phy->attached_dev_type == FANOUT_DEV ||
++ phy->attached_dev_type == EDGE_DEV) &&
++ phy->routing_attr == SUBTRACTIVE_ROUTING) {
++
++ if (!sub_sas_addr)
++ sub_sas_addr = &phy->attached_sas_addr[0];
++ else if (SAS_ADDR(sub_sas_addr) !=
++ SAS_ADDR(phy->attached_sas_addr)) {
++
++ SAS_DPRINTK("ex %016llx phy 0x%x "
++ "diverges(%016llx) on subtractive "
++ "boundary(%016llx). Disabled\n",
++ SAS_ADDR(dev->sas_addr), i,
++ SAS_ADDR(phy->attached_sas_addr),
++ SAS_ADDR(sub_sas_addr));
++ sas_ex_disable_phy(dev, i);
++ }
++ }
++ }
++ return 0;
++}
++
++static void sas_print_parent_topology_bug(struct domain_device *child,
++ struct ex_phy *parent_phy,
++ struct ex_phy *child_phy)
++{
++ static const char ra_char[] = {
++ [DIRECT_ROUTING] = 'D',
++ [SUBTRACTIVE_ROUTING] = 'S',
++ [TABLE_ROUTING] = 'T',
++ };
++ static const char *ex_type[] = {
++ [EDGE_DEV] = "edge",
++ [FANOUT_DEV] = "fanout",
++ };
++ struct domain_device *parent = child->parent;
++
++ sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x "
++ "has %c:%c routing link!\n",
++
++ ex_type[parent->dev_type],
++ SAS_ADDR(parent->sas_addr),
++ parent_phy->phy_id,
++
++ ex_type[child->dev_type],
++ SAS_ADDR(child->sas_addr),
++ child_phy->phy_id,
++
++ ra_char[parent_phy->routing_attr],
++ ra_char[child_phy->routing_attr]);
++}
++
++static int sas_check_eeds(struct domain_device *child,
++ struct ex_phy *parent_phy,
++ struct ex_phy *child_phy)
++{
++ int res = 0;
++ struct domain_device *parent = child->parent;
++
++ if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
++ res = -ENODEV;
++ SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx "
++ "phy S:0x%x, while there is a fanout ex %016llx\n",
++ SAS_ADDR(parent->sas_addr),
++ parent_phy->phy_id,
++ SAS_ADDR(child->sas_addr),
++ child_phy->phy_id,
++ SAS_ADDR(parent->port->disc.fanout_sas_addr));
++ } else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
++ memcpy(parent->port->disc.eeds_a, parent->sas_addr,
++ SAS_ADDR_SIZE);
++ memcpy(parent->port->disc.eeds_b, child->sas_addr,
++ SAS_ADDR_SIZE);
++ } else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
++ SAS_ADDR(parent->sas_addr)) ||
++ (SAS_ADDR(parent->port->disc.eeds_a) ==
++ SAS_ADDR(child->sas_addr)))
++ &&
++ ((SAS_ADDR(parent->port->disc.eeds_b) ==
++ SAS_ADDR(parent->sas_addr)) ||
++ (SAS_ADDR(parent->port->disc.eeds_b) ==
++ SAS_ADDR(child->sas_addr))))
++ ;
++ else {
++ res = -ENODEV;
++ SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx "
++ "phy 0x%x link forms a third EEDS!\n",
++ SAS_ADDR(parent->sas_addr),
++ parent_phy->phy_id,
++ SAS_ADDR(child->sas_addr),
++ child_phy->phy_id);
++ }
++
++ return res;
++}
++
++/* Here we spill over 80 columns. It is intentional.
++ */
++static int sas_check_parent_topology(struct domain_device *child)
++{
++ struct expander_device *child_ex = &child->ex_dev;
++ struct expander_device *parent_ex;
++ int i;
++ int res = 0;
++
++ if (!child->parent)
++ return 0;
++
++ if (child->parent->dev_type != EDGE_DEV &&
++ child->parent->dev_type != FANOUT_DEV)
++ return 0;
++
++ parent_ex = &child->parent->ex_dev;
++
++ for (i = 0; i < parent_ex->num_phys; i++) {
++ struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
++ struct ex_phy *child_phy;
++
++ if (parent_phy->phy_state == PHY_VACANT ||
++ parent_phy->phy_state == PHY_NOT_PRESENT)
++ continue;
++
++ if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr))
++ continue;
++
++ child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
++
++ switch (child->parent->dev_type) {
++ case EDGE_DEV:
++ if (child->dev_type == FANOUT_DEV) {
++ if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
++ child_phy->routing_attr != TABLE_ROUTING) {
++ sas_print_parent_topology_bug(child, parent_phy, child_phy);
++ res = -ENODEV;
++ }
++ } else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
++ if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
++ res = sas_check_eeds(child, parent_phy, child_phy);
++ } else if (child_phy->routing_attr != TABLE_ROUTING) {
++ sas_print_parent_topology_bug(child, parent_phy, child_phy);
++ res = -ENODEV;
++ }
++ } else if (parent_phy->routing_attr == TABLE_ROUTING &&
++ child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
++ sas_print_parent_topology_bug(child, parent_phy, child_phy);
++ res = -ENODEV;
++ }
++ break;
++ case FANOUT_DEV:
++ if (parent_phy->routing_attr != TABLE_ROUTING ||
++ child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
++ sas_print_parent_topology_bug(child, parent_phy, child_phy);
++ res = -ENODEV;
++ }
++ break;
++ default:
++ break;
++ }
++ }
++
++ return res;
++}
++
++#define RRI_REQ_SIZE 16
++#define RRI_RESP_SIZE 44
++
++static int sas_configure_present(struct domain_device *dev, int phy_id,
++ u8 *sas_addr, int *index, int *present)
++{
++ int i, res = 0;
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *phy = &ex->ex_phy[phy_id];
++ u8 *rri_req;
++ u8 *rri_resp;
++
++ *present = 0;
++ *index = 0;
++
++ rri_req = alloc_smp_req(RRI_REQ_SIZE);
++ if (!rri_req)
++ return -ENOMEM;
++
++ rri_resp = alloc_smp_resp(RRI_RESP_SIZE);
++ if (!rri_resp) {
++ kfree(rri_req);
++ return -ENOMEM;
++ }
++
++ rri_req[1] = SMP_REPORT_ROUTE_INFO;
++ rri_req[9] = phy_id;
++
++ for (i = 0; i < ex->max_route_indexes ; i++) {
++ *(__be16 *)(rri_req+6) = cpu_to_be16(i);
++ res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp,
++ RRI_RESP_SIZE);
++ if (res)
++ goto out;
++ res = rri_resp[2];
++ if (res == SMP_RESP_NO_INDEX) {
++ SAS_DPRINTK("overflow of indexes: dev %016llx "
++ "phy 0x%x index 0x%x\n",
++ SAS_ADDR(dev->sas_addr), phy_id, i);
++ goto out;
++ } else if (res != SMP_RESP_FUNC_ACC) {
++ SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
++ "result 0x%x\n", __FUNCTION__,
++ SAS_ADDR(dev->sas_addr), phy_id, i, res);
++ goto out;
++ }
++ if (SAS_ADDR(sas_addr) != 0) {
++ if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) {
++ *index = i;
++ if ((rri_resp[12] & 0x80) == 0x80)
++ *present = 0;
++ else
++ *present = 1;
++ goto out;
++ } else if (SAS_ADDR(rri_resp+16) == 0) {
++ *index = i;
++ *present = 0;
++ goto out;
++ }
++ } else if (SAS_ADDR(rri_resp+16) == 0 &&
++ phy->last_da_index < i) {
++ phy->last_da_index = i;
++ *index = i;
++ *present = 0;
++ goto out;
++ }
++ }
++ res = -1;
++out:
++ kfree(rri_req);
++ kfree(rri_resp);
++ return res;
++}
++
++#define CRI_REQ_SIZE 44
++#define CRI_RESP_SIZE 8
++
++static int sas_configure_set(struct domain_device *dev, int phy_id,
++ u8 *sas_addr, int index, int include)
++{
++ int res;
++ u8 *cri_req;
++ u8 *cri_resp;
++
++ cri_req = alloc_smp_req(CRI_REQ_SIZE);
++ if (!cri_req)
++ return -ENOMEM;
++
++ cri_resp = alloc_smp_resp(CRI_RESP_SIZE);
++ if (!cri_resp) {
++ kfree(cri_req);
++ return -ENOMEM;
++ }
++
++ cri_req[1] = SMP_CONF_ROUTE_INFO;
++ *(__be16 *)(cri_req+6) = cpu_to_be16(index);
++ cri_req[9] = phy_id;
++ if (SAS_ADDR(sas_addr) == 0 || !include)
++ cri_req[12] |= 0x80;
++ memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE);
++
++ res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp,
++ CRI_RESP_SIZE);
++ if (res)
++ goto out;
++ res = cri_resp[2];
++ if (res == SMP_RESP_NO_INDEX) {
++ SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x "
++ "index 0x%x\n",
++ SAS_ADDR(dev->sas_addr), phy_id, index);
++ }
++out:
++ kfree(cri_req);
++ kfree(cri_resp);
++ return res;
++}
++
++static int sas_configure_phy(struct domain_device *dev, int phy_id,
++ u8 *sas_addr, int include)
++{
++ int index;
++ int present;
++ int res;
++
++ res = sas_configure_present(dev, phy_id, sas_addr, &index, &present);
++ if (res)
++ return res;
++ if (include ^ present)
++ return sas_configure_set(dev, phy_id, sas_addr, index,include);
++
++ return res;
++}
++
++/**
++ * sas_configure_parent -- configure routing table of parent
++ * parent: parent expander
++ * child: child expander
++ * sas_addr: SAS port identifier of device directly attached to child
++ */
++static int sas_configure_parent(struct domain_device *parent,
++ struct domain_device *child,
++ u8 *sas_addr, int include)
++{
++ struct expander_device *ex_parent = &parent->ex_dev;
++ int res = 0;
++ int i;
++
++ if (parent->parent) {
++ res = sas_configure_parent(parent->parent, parent, sas_addr,
++ include);
++ if (res)
++ return res;
++ }
++
++ if (ex_parent->conf_route_table == 0) {
++ SAS_DPRINTK("ex %016llx has self-configuring routing table\n",
++ SAS_ADDR(parent->sas_addr));
++ return 0;
++ }
++
++ for (i = 0; i < ex_parent->num_phys; i++) {
++ struct ex_phy *phy = &ex_parent->ex_phy[i];
++
++ if ((phy->routing_attr == TABLE_ROUTING) &&
++ (SAS_ADDR(phy->attached_sas_addr) ==
++ SAS_ADDR(child->sas_addr))) {
++ res = sas_configure_phy(parent, i, sas_addr, include);
++ if (res)
++ return res;
++ }
++ }
++
++ return res;
++}
++
++/**
++ * sas_configure_routing -- configure routing
++ * dev: expander device
++ * sas_addr: port identifier of device directly attached to the expander device
++ */
++static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
++{
++ if (dev->parent)
++ return sas_configure_parent(dev->parent, dev, sas_addr, 1);
++ return 0;
++}
++
++static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr)
++{
++ if (dev->parent)
++ return sas_configure_parent(dev->parent, dev, sas_addr, 0);
++ return 0;
++}
++
++#if 0
++#define SMP_BIN_ATTR_NAME "smp_portal"
++
++static void sas_ex_smp_hook(struct domain_device *dev)
++{
++ struct expander_device *ex_dev = &dev->ex_dev;
++ struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
++
++ memset(bin_attr, 0, sizeof(*bin_attr));
++
++ bin_attr->attr.name = SMP_BIN_ATTR_NAME;
++ bin_attr->attr.owner = THIS_MODULE;
++ bin_attr->attr.mode = 0600;
++
++ bin_attr->size = 0;
++ bin_attr->private = NULL;
++ bin_attr->read = smp_portal_read;
++ bin_attr->write= smp_portal_write;
++ bin_attr->mmap = NULL;
++
++ ex_dev->smp_portal_pid = -1;
++ init_MUTEX(&ex_dev->smp_sema);
++}
++#endif
++
++/**
++ * sas_discover_expander -- expander discovery
++ * @ex: pointer to expander domain device
++ *
++ * See comment in sas_discover_sata().
++ */
++static int sas_discover_expander(struct domain_device *dev)
++{
++ int res;
++
++ res = sas_notify_lldd_dev_found(dev);
++ if (res)
++ return res;
++
++ res = sas_ex_general(dev);
++ if (res)
++ goto out_err;
++ res = sas_ex_manuf_info(dev);
++ if (res)
++ goto out_err;
++
++ res = sas_expander_discover(dev);
++ if (res) {
++ SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n",
++ SAS_ADDR(dev->sas_addr), res);
++ goto out_err;
++ }
++
++ sas_check_ex_subtractive_boundary(dev);
++ res = sas_check_parent_topology(dev);
++ if (res)
++ goto out_err;
++ return 0;
++out_err:
++ sas_notify_lldd_dev_gone(dev);
++ return res;
++}
++
++static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
++{
++ int res = 0;
++ struct domain_device *dev;
++
++ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
++ if (dev->dev_type == EDGE_DEV ||
++ dev->dev_type == FANOUT_DEV) {
++ struct sas_expander_device *ex =
++ rphy_to_expander_device(dev->rphy);
++
++ if (level == ex->level)
++ res = sas_ex_discover_devices(dev, -1);
++ else if (level > 0)
++ res = sas_ex_discover_devices(port->port_dev, -1);
++
++ }
++ }
++
++ return res;
++}
++
++static int sas_ex_bfs_disc(struct asd_sas_port *port)
++{
++ int res;
++ int level;
++
++ do {
++ level = port->disc.max_level;
++ res = sas_ex_level_discovery(port, level);
++ mb();
++ } while (level < port->disc.max_level);
++
++ return res;
++}
++
++int sas_discover_root_expander(struct domain_device *dev)
++{
++ int res;
++ struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
++
++ sas_rphy_add(dev->rphy);
++
++ ex->level = dev->port->disc.max_level; /* 0 */
++ res = sas_discover_expander(dev);
++ if (!res)
++ sas_ex_bfs_disc(dev->port);
++
++ return res;
++}
++
++/* ---------- Domain revalidation ---------- */
++
++static int sas_get_phy_discover(struct domain_device *dev,
++ int phy_id, struct smp_resp *disc_resp)
++{
++ int res;
++ u8 *disc_req;
++
++ disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
++ if (!disc_req)
++ return -ENOMEM;
++
++ disc_req[1] = SMP_DISCOVER;
++ disc_req[9] = phy_id;
++
++ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
++ disc_resp, DISCOVER_RESP_SIZE);
++ if (res)
++ goto out;
++ else if (disc_resp->result != SMP_RESP_FUNC_ACC) {
++ res = disc_resp->result;
++ goto out;
++ }
++out:
++ kfree(disc_req);
++ return res;
++}
++
++static int sas_get_phy_change_count(struct domain_device *dev,
++ int phy_id, int *pcc)
++{
++ int res;
++ struct smp_resp *disc_resp;
++
++ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
++ if (!disc_resp)
++ return -ENOMEM;
++
++ res = sas_get_phy_discover(dev, phy_id, disc_resp);
++ if (!res)
++ *pcc = disc_resp->disc.change_count;
++
++ kfree(disc_resp);
++ return res;
++}
++
++static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
++ int phy_id, u8 *attached_sas_addr)
++{
++ int res;
++ struct smp_resp *disc_resp;
++ struct discover_resp *dr;
++
++ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
++ if (!disc_resp)
++ return -ENOMEM;
++ dr = &disc_resp->disc;
++
++ res = sas_get_phy_discover(dev, phy_id, disc_resp);
++ if (!res) {
++ memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
++ if (dr->attached_dev_type == 0)
++ memset(attached_sas_addr, 0, 8);
++ }
++ kfree(disc_resp);
++ return res;
++}
++
++static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
++ int from_phy)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int res = 0;
++ int i;
++
++ for (i = from_phy; i < ex->num_phys; i++) {
++ int phy_change_count = 0;
++
++ res = sas_get_phy_change_count(dev, i, &phy_change_count);
++ if (res)
++ goto out;
++ else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
++ ex->ex_phy[i].phy_change_count = phy_change_count;
++ *phy_id = i;
++ return 0;
++ }
++ }
++out:
++ return res;
++}
++
++static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
++{
++ int res;
++ u8 *rg_req;
++ struct smp_resp *rg_resp;
++
++ rg_req = alloc_smp_req(RG_REQ_SIZE);
++ if (!rg_req)
++ return -ENOMEM;
++
++ rg_resp = alloc_smp_resp(RG_RESP_SIZE);
++ if (!rg_resp) {
++ kfree(rg_req);
++ return -ENOMEM;
++ }
++
++ rg_req[1] = SMP_REPORT_GENERAL;
++
++ res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
++ RG_RESP_SIZE);
++ if (res)
++ goto out;
++ if (rg_resp->result != SMP_RESP_FUNC_ACC) {
++ res = rg_resp->result;
++ goto out;
++ }
++
++ *ecc = be16_to_cpu(rg_resp->rg.change_count);
++out:
++ kfree(rg_resp);
++ kfree(rg_req);
++ return res;
++}
++
++static int sas_find_bcast_dev(struct domain_device *dev,
++ struct domain_device **src_dev)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ int ex_change_count = -1;
++ int res;
++
++ res = sas_get_ex_change_count(dev, &ex_change_count);
++ if (res)
++ goto out;
++ if (ex_change_count != -1 &&
++ ex_change_count != ex->ex_change_count) {
++ *src_dev = dev;
++ ex->ex_change_count = ex_change_count;
++ } else {
++ struct domain_device *ch;
++
++ list_for_each_entry(ch, &ex->children, siblings) {
++ if (ch->dev_type == EDGE_DEV ||
++ ch->dev_type == FANOUT_DEV) {
++ res = sas_find_bcast_dev(ch, src_dev);
++ if (src_dev)
++ return res;
++ }
++ }
++ }
++out:
++ return res;
++}
++
++static void sas_unregister_ex_tree(struct domain_device *dev)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct domain_device *child, *n;
++
++ list_for_each_entry_safe(child, n, &ex->children, siblings) {
++ if (child->dev_type == EDGE_DEV ||
++ child->dev_type == FANOUT_DEV)
++ sas_unregister_ex_tree(child);
++ else
++ sas_unregister_dev(child);
++ }
++ sas_unregister_dev(dev);
++}
++
++static void sas_unregister_devs_sas_addr(struct domain_device *parent,
++ int phy_id)
++{
++ struct expander_device *ex_dev = &parent->ex_dev;
++ struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
++ struct domain_device *child, *n;
++
++ list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
++ if (SAS_ADDR(child->sas_addr) ==
++ SAS_ADDR(phy->attached_sas_addr)) {
++ if (child->dev_type == EDGE_DEV ||
++ child->dev_type == FANOUT_DEV)
++ sas_unregister_ex_tree(child);
++ else
++ sas_unregister_dev(child);
++ break;
++ }
++ }
++ sas_disable_routing(parent, phy->attached_sas_addr);
++ memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
++ sas_port_delete_phy(phy->port, phy->phy);
++ if (phy->port->num_phys == 0)
++ sas_port_delete(phy->port);
++ phy->port = NULL;
++}
++
++static int sas_discover_bfs_by_root_level(struct domain_device *root,
++ const int level)
++{
++ struct expander_device *ex_root = &root->ex_dev;
++ struct domain_device *child;
++ int res = 0;
++
++ list_for_each_entry(child, &ex_root->children, siblings) {
++ if (child->dev_type == EDGE_DEV ||
++ child->dev_type == FANOUT_DEV) {
++ struct sas_expander_device *ex =
++ rphy_to_expander_device(child->rphy);
++
++ if (level > ex->level)
++ res = sas_discover_bfs_by_root_level(child,
++ level);
++ else if (level == ex->level)
++ res = sas_ex_discover_devices(child, -1);
++ }
++ }
++ return res;
++}
++
++static int sas_discover_bfs_by_root(struct domain_device *dev)
++{
++ int res;
++ struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
++ int level = ex->level+1;
++
++ res = sas_ex_discover_devices(dev, -1);
++ if (res)
++ goto out;
++ do {
++ res = sas_discover_bfs_by_root_level(dev, level);
++ mb();
++ level += 1;
++ } while (level <= dev->port->disc.max_level);
++out:
++ return res;
++}
++
++static int sas_discover_new(struct domain_device *dev, int phy_id)
++{
++ struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
++ struct domain_device *child;
++ int res;
++
++ SAS_DPRINTK("ex %016llx phy%d new device attached\n",
++ SAS_ADDR(dev->sas_addr), phy_id);
++ res = sas_ex_phy_discover(dev, phy_id);
++ if (res)
++ goto out;
++ res = sas_ex_discover_devices(dev, phy_id);
++ if (res)
++ goto out;
++ list_for_each_entry(child, &dev->ex_dev.children, siblings) {
++ if (SAS_ADDR(child->sas_addr) ==
++ SAS_ADDR(ex_phy->attached_sas_addr)) {
++ if (child->dev_type == EDGE_DEV ||
++ child->dev_type == FANOUT_DEV)
++ res = sas_discover_bfs_by_root(child);
++ break;
++ }
++ }
++out:
++ return res;
++}
++
++static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *phy = &ex->ex_phy[phy_id];
++ u8 attached_sas_addr[8];
++ int res;
++
++ res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
++ switch (res) {
++ case SMP_RESP_NO_PHY:
++ phy->phy_state = PHY_NOT_PRESENT;
++ sas_unregister_devs_sas_addr(dev, phy_id);
++ goto out; break;
++ case SMP_RESP_PHY_VACANT:
++ phy->phy_state = PHY_VACANT;
++ sas_unregister_devs_sas_addr(dev, phy_id);
++ goto out; break;
++ case SMP_RESP_FUNC_ACC:
++ break;
++ }
++
++ if (SAS_ADDR(attached_sas_addr) == 0) {
++ phy->phy_state = PHY_EMPTY;
++ sas_unregister_devs_sas_addr(dev, phy_id);
++ } else if (SAS_ADDR(attached_sas_addr) ==
++ SAS_ADDR(phy->attached_sas_addr)) {
++ SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
++ SAS_ADDR(dev->sas_addr), phy_id);
++ sas_ex_phy_discover(dev, phy_id);
++ } else
++ res = sas_discover_new(dev, phy_id);
++out:
++ return res;
++}
++
++static int sas_rediscover(struct domain_device *dev, const int phy_id)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
++ int res = 0;
++ int i;
++
++ SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
++ SAS_ADDR(dev->sas_addr), phy_id);
++
++ if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
++ for (i = 0; i < ex->num_phys; i++) {
++ struct ex_phy *phy = &ex->ex_phy[i];
++
++ if (i == phy_id)
++ continue;
++ if (SAS_ADDR(phy->attached_sas_addr) ==
++ SAS_ADDR(changed_phy->attached_sas_addr)) {
++ SAS_DPRINTK("phy%d part of wide port with "
++ "phy%d\n", phy_id, i);
++ goto out;
++ }
++ }
++ res = sas_rediscover_dev(dev, phy_id);
++ } else
++ res = sas_discover_new(dev, phy_id);
++out:
++ return res;
++}
++
++/**
++ * sas_revalidate_domain -- revalidate the domain
++ * @port: port to the domain of interest
++ *
++ * NOTE: this process _must_ quit (return) as soon as any connection
++ * errors are encountered. Connection recovery is done elsewhere.
++ * Discover process only interrogates devices in order to discover the
++ * domain.
++ */
++int sas_ex_revalidate_domain(struct domain_device *port_dev)
++{
++ int res;
++ struct domain_device *dev = NULL;
++
++ res = sas_find_bcast_dev(port_dev, &dev);
++ if (res)
++ goto out;
++ if (dev) {
++ struct expander_device *ex = &dev->ex_dev;
++ int i = 0, phy_id;
++
++ do {
++ phy_id = -1;
++ res = sas_find_bcast_phy(dev, &phy_id, i);
++ if (phy_id == -1)
++ break;
++ res = sas_rediscover(dev, phy_id);
++ i = phy_id + 1;
++ } while (i < ex->num_phys);
++ }
++out:
++ return res;
++}
++
++#if 0
++/* ---------- SMP portal ---------- */
++
++static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
++ size_t size)
++{
++ struct domain_device *dev = to_dom_device(kobj);
++ struct expander_device *ex = &dev->ex_dev;
++
++ if (offs != 0)
++ return -EFBIG;
++ else if (size == 0)
++ return 0;
++
++ down_interruptible(&ex->smp_sema);
++ if (ex->smp_req)
++ kfree(ex->smp_req);
++ ex->smp_req = kzalloc(size, GFP_USER);
++ if (!ex->smp_req) {
++ up(&ex->smp_sema);
++ return -ENOMEM;
++ }
++ memcpy(ex->smp_req, buf, size);
++ ex->smp_req_size = size;
++ ex->smp_portal_pid = current->pid;
++ up(&ex->smp_sema);
++
++ return size;
++}
++
++static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
++ size_t size)
++{
++ struct domain_device *dev = to_dom_device(kobj);
++ struct expander_device *ex = &dev->ex_dev;
++ u8 *smp_resp;
++ int res = -EINVAL;
++
++ /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
++ * it should be 0.
++ */
++
++ down_interruptible(&ex->smp_sema);
++ if (!ex->smp_req || ex->smp_portal_pid != current->pid)
++ goto out;
++
++ res = 0;
++ if (size == 0)
++ goto out;
++
++ res = -ENOMEM;
++ smp_resp = alloc_smp_resp(size);
++ if (!smp_resp)
++ goto out;
++ res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
++ smp_resp, size);
++ if (!res) {
++ memcpy(buf, smp_resp, size);
++ res = size;
++ }
++
++ kfree(smp_resp);
++out:
++ kfree(ex->smp_req);
++ ex->smp_req = NULL;
++ ex->smp_req_size = 0;
++ ex->smp_portal_pid = -1;
++ up(&ex->smp_sema);
++ return res;
++}
++#endif
+diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
+new file mode 100644
+index 0000000..c836a23
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_init.c
+@@ -0,0 +1,267 @@
++/*
++ * Serial Attached SCSI (SAS) Transport Layer initialization
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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/init.h>
++#include <linux/device.h>
++#include <linux/spinlock.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++
++#include "sas_internal.h"
++
++#include "../scsi_sas_internal.h"
++
++kmem_cache_t *sas_task_cache;
++
++/*------------ SAS addr hash -----------*/
++void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
++{
++ const u32 poly = 0x00DB2777;
++ u32 r = 0;
++ int i;
++
++ for (i = 0; i < 8; i++) {
++ int b;
++ for (b = 7; b >= 0; b--) {
++ r <<= 1;
++ if ((1 << b) & sas_addr[i]) {
++ if (!(r & 0x01000000))
++ r ^= poly;
++ } else if (r & 0x01000000)
++ r ^= poly;
++ }
++ }
++
++ hashed[0] = (r >> 16) & 0xFF;
++ hashed[1] = (r >> 8) & 0xFF ;
++ hashed[2] = r & 0xFF;
++}
++
++
++/* ---------- HA events ---------- */
++
++void sas_hae_reset(void *data)
++{
++ struct sas_ha_struct *ha = data;
++
++ sas_begin_event(HAE_RESET, &ha->event_lock,
++ &ha->pending);
++}
++
++int sas_register_ha(struct sas_ha_struct *sas_ha)
++{
++ int error = 0;
++
++ spin_lock_init(&sas_ha->phy_port_lock);
++ sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
++
++ if (sas_ha->lldd_queue_size == 0)
++ sas_ha->lldd_queue_size = 1;
++ else if (sas_ha->lldd_queue_size == -1)
++ sas_ha->lldd_queue_size = 128; /* Sanity */
++
++ error = sas_register_phys(sas_ha);
++ if (error) {
++ printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
++ return error;
++ }
++
++ error = sas_register_ports(sas_ha);
++ if (error) {
++ printk(KERN_NOTICE "couldn't register sas ports:%d\n", error);
++ goto Undo_phys;
++ }
++
++ error = sas_init_events(sas_ha);
++ if (error) {
++ printk(KERN_NOTICE "couldn't start event thread:%d\n", error);
++ goto Undo_ports;
++ }
++
++ if (sas_ha->lldd_max_execute_num > 1) {
++ error = sas_init_queue(sas_ha);
++ if (error) {
++ printk(KERN_NOTICE "couldn't start queue thread:%d, "
++ "running in direct mode\n", error);
++ sas_ha->lldd_max_execute_num = 1;
++ }
++ }
++
++ return 0;
++
++Undo_ports:
++ sas_unregister_ports(sas_ha);
++Undo_phys:
++
++ return error;
++}
++
++int sas_unregister_ha(struct sas_ha_struct *sas_ha)
++{
++ if (sas_ha->lldd_max_execute_num > 1) {
++ sas_shutdown_queue(sas_ha);
++ }
++
++ sas_unregister_ports(sas_ha);
++
++ return 0;
++}
++
++static int sas_get_linkerrors(struct sas_phy *phy)
++{
++ if (scsi_is_sas_phy_local(phy))
++ /* FIXME: we have no local phy stats
++ * gathering at this time */
++ return -EINVAL;
++
++ return sas_smp_get_phy_events(phy);
++}
++
++static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
++{
++ int ret;
++ enum phy_func reset_type;
++
++ if (hard_reset)
++ reset_type = PHY_FUNC_HARD_RESET;
++ else
++ reset_type = PHY_FUNC_LINK_RESET;
++
++ if (scsi_is_sas_phy_local(phy)) {
++ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
++ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
++ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
++ struct sas_internal *i =
++ to_sas_internal(sas_ha->core.shost->transportt);
++
++ ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
++ } else {
++ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
++ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
++ ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
++ }
++ return ret;
++}
++
++static int sas_set_phy_speed(struct sas_phy *phy,
++ struct sas_phy_linkrates *rates)
++{
++ int ret;
++
++ if ((rates->minimum_linkrate &&
++ rates->minimum_linkrate > phy->maximum_linkrate) ||
++ (rates->maximum_linkrate &&
++ rates->maximum_linkrate < phy->minimum_linkrate))
++ return -EINVAL;
++
++ if (rates->minimum_linkrate &&
++ rates->minimum_linkrate < phy->minimum_linkrate_hw)
++ rates->minimum_linkrate = phy->minimum_linkrate_hw;
++
++ if (rates->maximum_linkrate &&
++ rates->maximum_linkrate > phy->maximum_linkrate_hw)
++ rates->maximum_linkrate = phy->maximum_linkrate_hw;
++
++ if (scsi_is_sas_phy_local(phy)) {
++ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
++ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
++ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
++ struct sas_internal *i =
++ to_sas_internal(sas_ha->core.shost->transportt);
++
++ ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE,
++ rates);
++ } else {
++ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
++ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
++ ret = sas_smp_phy_control(ddev, phy->number,
++ PHY_FUNC_LINK_RESET, rates);
++
++ }
++
++ return ret;
++}
++
++static struct sas_function_template sft = {
++ .phy_reset = sas_phy_reset,
++ .set_phy_speed = sas_set_phy_speed,
++ .get_linkerrors = sas_get_linkerrors,
++};
++
++struct scsi_transport_template *
++sas_domain_attach_transport(struct sas_domain_function_template *dft)
++{
++ struct scsi_transport_template *stt = sas_attach_transport(&sft);
++ struct sas_internal *i;
++
++ if (!stt)
++ return stt;
++
++ i = to_sas_internal(stt);
++ i->dft = dft;
++ stt->create_work_queue = 1;
++ stt->eh_timed_out = sas_scsi_timed_out;
++ stt->eh_strategy_handler = sas_scsi_recover_host;
++
++ return stt;
++}
++EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
++
++
++void sas_domain_release_transport(struct scsi_transport_template *stt)
++{
++ sas_release_transport(stt);
++}
++EXPORT_SYMBOL_GPL(sas_domain_release_transport);
++
++/* ---------- SAS Class register/unregister ---------- */
++
++static int __init sas_class_init(void)
++{
++ sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
++ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (!sas_task_cache)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void __exit sas_class_exit(void)
++{
++ kmem_cache_destroy(sas_task_cache);
++}
++
++MODULE_AUTHOR("Luben Tuikov <luben_tuikov at adaptec.com>");
++MODULE_DESCRIPTION("SAS Transport Layer");
++MODULE_LICENSE("GPL v2");
++
++module_init(sas_class_init);
++module_exit(sas_class_exit);
++
++EXPORT_SYMBOL_GPL(sas_register_ha);
++EXPORT_SYMBOL_GPL(sas_unregister_ha);
+diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
+new file mode 100644
+index 0000000..bffcee4
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_internal.h
+@@ -0,0 +1,146 @@
++/*
++ * Serial Attached SCSI (SAS) class internal header file
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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 _SAS_INTERNAL_H_
++#define _SAS_INTERNAL_H_
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_transport_sas.h>
++#include <scsi/libsas.h>
++
++#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
++
++#ifdef SAS_DEBUG
++#define SAS_DPRINTK(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
++#else
++#define SAS_DPRINTK(fmt, ...)
++#endif
++
++void sas_scsi_recover_host(struct Scsi_Host *shost);
++
++int sas_show_class(enum sas_class class, char *buf);
++int sas_show_proto(enum sas_proto proto, char *buf);
++int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
++int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
++
++int sas_register_phys(struct sas_ha_struct *sas_ha);
++void sas_unregister_phys(struct sas_ha_struct *sas_ha);
++
++int sas_register_ports(struct sas_ha_struct *sas_ha);
++void sas_unregister_ports(struct sas_ha_struct *sas_ha);
++
++enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
++
++int sas_init_queue(struct sas_ha_struct *sas_ha);
++int sas_init_events(struct sas_ha_struct *sas_ha);
++void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
++
++void sas_deform_port(struct asd_sas_phy *phy);
++
++void sas_porte_bytes_dmaed(void *);
++void sas_porte_broadcast_rcvd(void *);
++void sas_porte_link_reset_err(void *);
++void sas_porte_timer_event(void *);
++void sas_porte_hard_reset(void *);
++
++int sas_notify_lldd_dev_found(struct domain_device *);
++void sas_notify_lldd_dev_gone(struct domain_device *);
++
++int sas_smp_phy_control(struct domain_device *dev, int phy_id,
++ enum phy_func phy_func, struct sas_phy_linkrates *);
++int sas_smp_get_phy_events(struct sas_phy *phy);
++
++struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
++
++void sas_hae_reset(void *);
++
++static inline void sas_queue_event(int event, spinlock_t *lock,
++ unsigned long *pending,
++ struct work_struct *work,
++ struct Scsi_Host *shost)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(lock, flags);
++ if (test_bit(event, pending)) {
++ spin_unlock_irqrestore(lock, flags);
++ return;
++ }
++ __set_bit(event, pending);
++ spin_unlock_irqrestore(lock, flags);
++ scsi_queue_work(shost, work);
++}
++
++static inline void sas_begin_event(int event, spinlock_t *lock,
++ unsigned long *pending)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(lock, flags);
++ __clear_bit(event, pending);
++ spin_unlock_irqrestore(lock, flags);
++}
++
++static inline void sas_fill_in_rphy(struct domain_device *dev,
++ struct sas_rphy *rphy)
++{
++ rphy->identify.sas_address = SAS_ADDR(dev->sas_addr);
++ rphy->identify.initiator_port_protocols = dev->iproto;
++ rphy->identify.target_port_protocols = dev->tproto;
++ switch (dev->dev_type) {
++ case SATA_DEV:
++ /* FIXME: need sata device type */
++ case SAS_END_DEV:
++ rphy->identify.device_type = SAS_END_DEVICE;
++ break;
++ case EDGE_DEV:
++ rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE;
++ break;
++ case FANOUT_DEV:
++ rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE;
++ break;
++ default:
++ rphy->identify.device_type = SAS_PHY_UNUSED;
++ break;
++ }
++}
++
++static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
++{
++ struct expander_device *ex = &dev->ex_dev;
++ struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
++
++ if (!ex->parent_port) {
++ ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id);
++ /* FIXME: error handling */
++ BUG_ON(!ex->parent_port);
++ BUG_ON(sas_port_add(ex->parent_port));
++ sas_port_mark_backlink(ex->parent_port);
++ }
++ sas_port_add_phy(ex->parent_port, ex_phy->phy);
++}
++
++#endif /* _SAS_INTERNAL_H_ */
+diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
+new file mode 100644
+index 0000000..9340cdb
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_phy.c
+@@ -0,0 +1,158 @@
++/*
++ * Serial Attached SCSI (SAS) Phy class
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include "sas_internal.h"
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++#include "../scsi_sas_internal.h"
++
++/* ---------- Phy events ---------- */
++
++static void sas_phye_loss_of_signal(void *data)
++{
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
++ &phy->phy_events_pending);
++ phy->error = 0;
++ sas_deform_port(phy);
++}
++
++static void sas_phye_oob_done(void *data)
++{
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock,
++ &phy->phy_events_pending);
++ phy->error = 0;
++}
++
++static void sas_phye_oob_error(void *data)
++{
++ struct asd_sas_phy *phy = data;
++ struct sas_ha_struct *sas_ha = phy->ha;
++ struct asd_sas_port *port = phy->port;
++ struct sas_internal *i =
++ to_sas_internal(sas_ha->core.shost->transportt);
++
++ sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
++ &phy->phy_events_pending);
++
++ sas_deform_port(phy);
++
++ if (!port && phy->enabled && i->dft->lldd_control_phy) {
++ phy->error++;
++ switch (phy->error) {
++ case 1:
++ case 2:
++ i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
++ NULL);
++ break;
++ case 3:
++ default:
++ phy->error = 0;
++ phy->enabled = 0;
++ i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
++ break;
++ }
++ }
++}
++
++static void sas_phye_spinup_hold(void *data)
++{
++ struct asd_sas_phy *phy = data;
++ struct sas_ha_struct *sas_ha = phy->ha;
++ struct sas_internal *i =
++ to_sas_internal(sas_ha->core.shost->transportt);
++
++ sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock,
++ &phy->phy_events_pending);
++
++ phy->error = 0;
++ i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
++}
++
++/* ---------- Phy class registration ---------- */
++
++int sas_register_phys(struct sas_ha_struct *sas_ha)
++{
++ int i;
++
++ static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = {
++ [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
++ [PHYE_OOB_DONE] = sas_phye_oob_done,
++ [PHYE_OOB_ERROR] = sas_phye_oob_error,
++ [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
++ };
++
++ static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = {
++ [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
++ [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
++ [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
++ [PORTE_TIMER_EVENT] = sas_porte_timer_event,
++ [PORTE_HARD_RESET] = sas_porte_hard_reset,
++ };
++
++ /* Now register the phys. */
++ for (i = 0; i < sas_ha->num_phys; i++) {
++ int k;
++ struct asd_sas_phy *phy = sas_ha->sas_phy[i];
++
++ phy->error = 0;
++ INIT_LIST_HEAD(&phy->port_phy_el);
++ for (k = 0; k < PORT_NUM_EVENTS; k++)
++ INIT_WORK(&phy->port_events[k], sas_port_event_fns[k],
++ phy);
++
++ for (k = 0; k < PHY_NUM_EVENTS; k++)
++ INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k],
++ phy);
++ phy->port = NULL;
++ phy->ha = sas_ha;
++ spin_lock_init(&phy->frame_rcvd_lock);
++ spin_lock_init(&phy->sas_prim_lock);
++ phy->frame_rcvd_size = 0;
++
++ phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev,
++ i);
++ if (!phy->phy)
++ return -ENOMEM;
++
++ phy->phy->identify.initiator_port_protocols =
++ phy->iproto;
++ phy->phy->identify.target_port_protocols = phy->tproto;
++ phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
++ phy->phy->identify.phy_identifier = i;
++ phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
++ phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
++ phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
++ phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
++ phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
++
++ sas_phy_add(phy->phy);
++ }
++
++ return 0;
++}
+diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
+new file mode 100644
+index 0000000..253cdcf
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_port.c
+@@ -0,0 +1,279 @@
++/*
++ * Serial Attached SCSI (SAS) Port class
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include "sas_internal.h"
++
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++#include "../scsi_sas_internal.h"
++
++/**
++ * sas_form_port -- add this phy to a port
++ * @phy: the phy of interest
++ *
++ * This function adds this phy to an existing port, thus creating a wide
++ * port, or it creates a port and adds the phy to the port.
++ */
++static void sas_form_port(struct asd_sas_phy *phy)
++{
++ int i;
++ struct sas_ha_struct *sas_ha = phy->ha;
++ struct asd_sas_port *port = phy->port;
++ struct sas_internal *si =
++ to_sas_internal(sas_ha->core.shost->transportt);
++
++ if (port) {
++ if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
++ SAS_ADDR_SIZE) == 0)
++ sas_deform_port(phy);
++ else {
++ SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
++ __FUNCTION__, phy->id, phy->port->id,
++ phy->port->num_phys);
++ return;
++ }
++ }
++
++ /* find a port */
++ spin_lock(&sas_ha->phy_port_lock);
++ for (i = 0; i < sas_ha->num_phys; i++) {
++ port = sas_ha->sas_port[i];
++ spin_lock(&port->phy_list_lock);
++ if (*(u64 *) port->sas_addr &&
++ memcmp(port->attached_sas_addr,
++ phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&
++ port->num_phys > 0) {
++ /* wide port */
++ SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
++ port->id);
++ break;
++ } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
++ memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
++ break;
++ }
++ spin_unlock(&port->phy_list_lock);
++ }
++
++ if (i >= sas_ha->num_phys) {
++ printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
++ __FUNCTION__);
++ spin_unlock(&sas_ha->phy_port_lock);
++ return;
++ }
++
++ /* add the phy to the port */
++ list_add_tail(&phy->port_phy_el, &port->phy_list);
++ phy->port = port;
++ port->num_phys++;
++ port->phy_mask |= (1U << phy->id);
++
++ if (!port->phy)
++ port->phy = phy->phy;
++
++ SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id,
++ port->id, port->phy_mask);
++
++ if (*(u64 *)port->attached_sas_addr == 0) {
++ port->class = phy->class;
++ memcpy(port->attached_sas_addr, phy->attached_sas_addr,
++ SAS_ADDR_SIZE);
++ port->iproto = phy->iproto;
++ port->tproto = phy->tproto;
++ port->oob_mode = phy->oob_mode;
++ port->linkrate = phy->linkrate;
++ } else
++ port->linkrate = max(port->linkrate, phy->linkrate);
++ spin_unlock(&port->phy_list_lock);
++ spin_unlock(&sas_ha->phy_port_lock);
++
++ if (!port->port) {
++ port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
++ BUG_ON(!port->port);
++ sas_port_add(port->port);
++ }
++ sas_port_add_phy(port->port, phy->phy);
++
++ if (port->port_dev)
++ port->port_dev->pathways = port->num_phys;
++
++ /* Tell the LLDD about this port formation. */
++ if (si->dft->lldd_port_formed)
++ si->dft->lldd_port_formed(phy);
++
++ sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
++}
++
++/**
++ * sas_deform_port -- remove this phy from the port it belongs to
++ * @phy: the phy of interest
++ *
++ * This is called when the physical link to the other phy has been
++ * lost (on this phy), in Event thread context. We cannot delay here.
++ */
++void sas_deform_port(struct asd_sas_phy *phy)
++{
++ struct sas_ha_struct *sas_ha = phy->ha;
++ struct asd_sas_port *port = phy->port;
++ struct sas_internal *si =
++ to_sas_internal(sas_ha->core.shost->transportt);
++
++ if (!port)
++ return; /* done by a phy event */
++
++ if (port->port_dev)
++ port->port_dev->pathways--;
++
++ if (port->num_phys == 1) {
++ sas_unregister_domain_devices(port);
++ sas_port_delete(port->port);
++ port->port = NULL;
++ } else
++ sas_port_delete_phy(port->port, phy->phy);
++
++
++ if (si->dft->lldd_port_deformed)
++ si->dft->lldd_port_deformed(phy);
++
++ spin_lock(&sas_ha->phy_port_lock);
++ spin_lock(&port->phy_list_lock);
++
++ list_del_init(&phy->port_phy_el);
++ phy->port = NULL;
++ port->num_phys--;
++ port->phy_mask &= ~(1U << phy->id);
++
++ if (port->num_phys == 0) {
++ INIT_LIST_HEAD(&port->phy_list);
++ memset(port->sas_addr, 0, SAS_ADDR_SIZE);
++ memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE);
++ port->class = 0;
++ port->iproto = 0;
++ port->tproto = 0;
++ port->oob_mode = 0;
++ port->phy_mask = 0;
++ }
++ spin_unlock(&port->phy_list_lock);
++ spin_unlock(&sas_ha->phy_port_lock);
++
++ return;
++}
++
++/* ---------- SAS port events ---------- */
++
++void sas_porte_bytes_dmaed(void *data)
++{
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
++ &phy->port_events_pending);
++
++ sas_form_port(phy);
++}
++
++void sas_porte_broadcast_rcvd(void *data)
++{
++ unsigned long flags;
++ u32 prim;
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,
++ &phy->port_events_pending);
++
++ spin_lock_irqsave(&phy->sas_prim_lock, flags);
++ prim = phy->sas_prim;
++ spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
++
++ SAS_DPRINTK("broadcast received: %d\n", prim);
++ sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
++}
++
++void sas_porte_link_reset_err(void *data)
++{
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
++ &phy->port_events_pending);
++
++ sas_deform_port(phy);
++}
++
++void sas_porte_timer_event(void *data)
++{
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
++ &phy->port_events_pending);
++
++ sas_deform_port(phy);
++}
++
++void sas_porte_hard_reset(void *data)
++{
++ struct asd_sas_phy *phy = data;
++
++ sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
++ &phy->port_events_pending);
++
++ sas_deform_port(phy);
++}
++
++/* ---------- SAS port registration ---------- */
++
++static void sas_init_port(struct asd_sas_port *port,
++ struct sas_ha_struct *sas_ha, int i)
++{
++ port->id = i;
++ INIT_LIST_HEAD(&port->dev_list);
++ spin_lock_init(&port->phy_list_lock);
++ INIT_LIST_HEAD(&port->phy_list);
++ port->num_phys = 0;
++ port->phy_mask = 0;
++ port->ha = sas_ha;
++
++ spin_lock_init(&port->dev_list_lock);
++}
++
++int sas_register_ports(struct sas_ha_struct *sas_ha)
++{
++ int i;
++
++ /* initialize the ports and discovery */
++ for (i = 0; i < sas_ha->num_phys; i++) {
++ struct asd_sas_port *port = sas_ha->sas_port[i];
++
++ sas_init_port(port, sas_ha, i);
++ sas_init_disc(&port->disc, port);
++ }
++ return 0;
++}
++
++void sas_unregister_ports(struct sas_ha_struct *sas_ha)
++{
++ int i;
++
++ for (i = 0; i < sas_ha->num_phys; i++)
++ if (sas_ha->sas_phy[i]->port)
++ sas_deform_port(sas_ha->sas_phy[i]);
++
++}
+diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
+new file mode 100644
+index 0000000..e46e793
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_scsi_host.c
+@@ -0,0 +1,786 @@
++/*
++ * Serial Attached SCSI (SAS) class SCSI Host glue.
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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 "sas_internal.h"
++
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_tcq.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++#include "../scsi_sas_internal.h"
++
++#include <linux/err.h>
++#include <linux/blkdev.h>
++#include <linux/scatterlist.h>
++
++/* ---------- SCSI Host glue ---------- */
++
++#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
++#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
++
++static void sas_scsi_task_done(struct sas_task *task)
++{
++ struct task_status_struct *ts = &task->task_status;
++ struct scsi_cmnd *sc = task->uldd_task;
++ unsigned ts_flags = task->task_state_flags;
++ int hs = 0, stat = 0;
++
++ if (unlikely(!sc)) {
++ SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
++ list_del_init(&task->list);
++ sas_free_task(task);
++ return;
++ }
++
++ if (ts->resp == SAS_TASK_UNDELIVERED) {
++ /* transport error */
++ hs = DID_NO_CONNECT;
++ } else { /* ts->resp == SAS_TASK_COMPLETE */
++ /* task delivered, what happened afterwards? */
++ switch (ts->stat) {
++ case SAS_DEV_NO_RESPONSE:
++ case SAS_INTERRUPTED:
++ case SAS_PHY_DOWN:
++ case SAS_NAK_R_ERR:
++ case SAS_OPEN_TO:
++ hs = DID_NO_CONNECT;
++ break;
++ case SAS_DATA_UNDERRUN:
++ sc->resid = ts->residual;
++ if (sc->request_bufflen - sc->resid < sc->underflow)
++ hs = DID_ERROR;
++ break;
++ case SAS_DATA_OVERRUN:
++ hs = DID_ERROR;
++ break;
++ case SAS_QUEUE_FULL:
++ hs = DID_SOFT_ERROR; /* retry */
++ break;
++ case SAS_DEVICE_UNKNOWN:
++ hs = DID_BAD_TARGET;
++ break;
++ case SAS_SG_ERR:
++ hs = DID_PARITY;
++ break;
++ case SAS_OPEN_REJECT:
++ if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY)
++ hs = DID_SOFT_ERROR; /* retry */
++ else
++ hs = DID_ERROR;
++ break;
++ case SAS_PROTO_RESPONSE:
++ SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP "
++ "task; please report this\n",
++ task->dev->port->ha->sas_ha_name);
++ break;
++ case SAS_ABORTED_TASK:
++ hs = DID_ABORT;
++ break;
++ case SAM_CHECK_COND:
++ memcpy(sc->sense_buffer, ts->buf,
++ max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
++ stat = SAM_CHECK_COND;
++ break;
++ default:
++ stat = ts->stat;
++ break;
++ }
++ }
++ ASSIGN_SAS_TASK(sc, NULL);
++ sc->result = (hs << 16) | stat;
++ list_del_init(&task->list);
++ sas_free_task(task);
++ /* This is very ugly but this is how SCSI Core works. */
++ if (ts_flags & SAS_TASK_STATE_ABORTED)
++ scsi_finish_command(sc);
++ else
++ sc->scsi_done(sc);
++}
++
++static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
++{
++ enum task_attribute ta = TASK_ATTR_SIMPLE;
++ if (cmd->request && blk_rq_tagged(cmd->request)) {
++ if (cmd->device->ordered_tags &&
++ (cmd->request->cmd_flags & REQ_HARDBARRIER))
++ ta = TASK_ATTR_HOQ;
++ }
++ return ta;
++}
++
++static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
++ struct domain_device *dev,
++ gfp_t gfp_flags)
++{
++ struct sas_task *task = sas_alloc_task(gfp_flags);
++ struct scsi_lun lun;
++
++ if (!task)
++ return NULL;
++
++ *(u32 *)cmd->sense_buffer = 0;
++ task->uldd_task = cmd;
++ ASSIGN_SAS_TASK(cmd, task);
++
++ task->dev = dev;
++ task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */
++
++ task->ssp_task.retry_count = 1;
++ int_to_scsilun(cmd->device->lun, &lun);
++ memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8);
++ task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
++ memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
++
++ task->scatter = cmd->request_buffer;
++ task->num_scatter = cmd->use_sg;
++ task->total_xfer_len = cmd->request_bufflen;
++ task->data_dir = cmd->sc_data_direction;
++
++ task->task_done = sas_scsi_task_done;
++
++ return task;
++}
++
++static int sas_queue_up(struct sas_task *task)
++{
++ struct sas_ha_struct *sas_ha = task->dev->port->ha;
++ struct scsi_core *core = &sas_ha->core;
++ unsigned long flags;
++ LIST_HEAD(list);
++
++ spin_lock_irqsave(&core->task_queue_lock, flags);
++ if (sas_ha->lldd_queue_size < core->task_queue_size + 1) {
++ spin_unlock_irqrestore(&core->task_queue_lock, flags);
++ return -SAS_QUEUE_FULL;
++ }
++ list_add_tail(&task->list, &core->task_queue);
++ core->task_queue_size += 1;
++ spin_unlock_irqrestore(&core->task_queue_lock, flags);
++ up(&core->queue_thread_sema);
++
++ return 0;
++}
++
++/**
++ * sas_queuecommand -- Enqueue a command for processing
++ * @parameters: See SCSI Core documentation
++ *
++ * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
++ * call us without holding an IRQ spinlock...
++ */
++int sas_queuecommand(struct scsi_cmnd *cmd,
++ void (*scsi_done)(struct scsi_cmnd *))
++{
++ int res = 0;
++ struct domain_device *dev = cmd_to_domain_dev(cmd);
++ struct Scsi_Host *host = cmd->device->host;
++ struct sas_internal *i = to_sas_internal(host->transportt);
++
++ spin_unlock_irq(host->host_lock);
++
++ {
++ struct sas_ha_struct *sas_ha = dev->port->ha;
++ struct sas_task *task;
++
++ res = -ENOMEM;
++ task = sas_create_task(cmd, dev, GFP_ATOMIC);
++ if (!task)
++ goto out;
++
++ cmd->scsi_done = scsi_done;
++ /* Queue up, Direct Mode or Task Collector Mode. */
++ if (sas_ha->lldd_max_execute_num < 2)
++ res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
++ else
++ res = sas_queue_up(task);
++
++ /* Examine */
++ if (res) {
++ SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
++ ASSIGN_SAS_TASK(cmd, NULL);
++ sas_free_task(task);
++ if (res == -SAS_QUEUE_FULL) {
++ cmd->result = DID_SOFT_ERROR << 16; /* retry */
++ res = 0;
++ scsi_done(cmd);
++ }
++ goto out;
++ }
++ }
++out:
++ spin_lock_irq(host->host_lock);
++ return res;
++}
++
++static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
++{
++ struct scsi_cmnd *cmd, *n;
++
++ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
++ if (cmd == my_cmd)
++ list_del_init(&cmd->eh_entry);
++ }
++}
++
++static void sas_scsi_clear_queue_I_T(struct list_head *error_q,
++ struct domain_device *dev)
++{
++ struct scsi_cmnd *cmd, *n;
++
++ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
++ struct domain_device *x = cmd_to_domain_dev(cmd);
++
++ if (x == dev)
++ list_del_init(&cmd->eh_entry);
++ }
++}
++
++static void sas_scsi_clear_queue_port(struct list_head *error_q,
++ struct asd_sas_port *port)
++{
++ struct scsi_cmnd *cmd, *n;
++
++ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
++ struct domain_device *dev = cmd_to_domain_dev(cmd);
++ struct asd_sas_port *x = dev->port;
++
++ if (x == port)
++ list_del_init(&cmd->eh_entry);
++ }
++}
++
++enum task_disposition {
++ TASK_IS_DONE,
++ TASK_IS_ABORTED,
++ TASK_IS_AT_LU,
++ TASK_IS_NOT_AT_LU,
++};
++
++static enum task_disposition sas_scsi_find_task(struct sas_task *task)
++{
++ struct sas_ha_struct *ha = task->dev->port->ha;
++ unsigned long flags;
++ int i, res;
++ struct sas_internal *si =
++ to_sas_internal(task->dev->port->ha->core.shost->transportt);
++
++ if (ha->lldd_max_execute_num > 1) {
++ struct scsi_core *core = &ha->core;
++ struct sas_task *t, *n;
++
++ spin_lock_irqsave(&core->task_queue_lock, flags);
++ list_for_each_entry_safe(t, n, &core->task_queue, list) {
++ if (task == t) {
++ list_del_init(&t->list);
++ spin_unlock_irqrestore(&core->task_queue_lock,
++ flags);
++ SAS_DPRINTK("%s: task 0x%p aborted from "
++ "task_queue\n",
++ __FUNCTION__, task);
++ return TASK_IS_ABORTED;
++ }
++ }
++ spin_unlock_irqrestore(&core->task_queue_lock, flags);
++ }
++
++ for (i = 0; i < 5; i++) {
++ SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
++ res = si->dft->lldd_abort_task(task);
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
++ task);
++ return TASK_IS_DONE;
++ }
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ if (res == TMF_RESP_FUNC_COMPLETE) {
++ SAS_DPRINTK("%s: task 0x%p is aborted\n",
++ __FUNCTION__, task);
++ return TASK_IS_ABORTED;
++ } else if (si->dft->lldd_query_task) {
++ SAS_DPRINTK("%s: querying task 0x%p\n",
++ __FUNCTION__, task);
++ res = si->dft->lldd_query_task(task);
++ if (res == TMF_RESP_FUNC_SUCC) {
++ SAS_DPRINTK("%s: task 0x%p at LU\n",
++ __FUNCTION__, task);
++ return TASK_IS_AT_LU;
++ } else if (res == TMF_RESP_FUNC_COMPLETE) {
++ SAS_DPRINTK("%s: task 0x%p not at LU\n",
++ __FUNCTION__, task);
++ return TASK_IS_NOT_AT_LU;
++ }
++ }
++ }
++ return res;
++}
++
++static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd)
++{
++ int res = TMF_RESP_FUNC_FAILED;
++ struct scsi_lun lun;
++ struct sas_internal *i =
++ to_sas_internal(dev->port->ha->core.shost->transportt);
++
++ int_to_scsilun(cmd->device->lun, &lun);
++
++ SAS_DPRINTK("eh: device %llx LUN %x has the task\n",
++ SAS_ADDR(dev->sas_addr),
++ cmd->device->lun);
++
++ if (i->dft->lldd_abort_task_set)
++ res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun);
++
++ if (res == TMF_RESP_FUNC_FAILED) {
++ if (i->dft->lldd_clear_task_set)
++ res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun);
++ }
++
++ if (res == TMF_RESP_FUNC_FAILED) {
++ if (i->dft->lldd_lu_reset)
++ res = i->dft->lldd_lu_reset(dev, lun.scsi_lun);
++ }
++
++ return res;
++}
++
++static int sas_recover_I_T(struct domain_device *dev)
++{
++ int res = TMF_RESP_FUNC_FAILED;
++ struct sas_internal *i =
++ to_sas_internal(dev->port->ha->core.shost->transportt);
++
++ SAS_DPRINTK("I_T nexus reset for dev %016llx\n",
++ SAS_ADDR(dev->sas_addr));
++
++ if (i->dft->lldd_I_T_nexus_reset)
++ res = i->dft->lldd_I_T_nexus_reset(dev);
++
++ return res;
++}
++
++void sas_scsi_recover_host(struct Scsi_Host *shost)
++{
++ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
++ unsigned long flags;
++ LIST_HEAD(error_q);
++ struct scsi_cmnd *cmd, *n;
++ enum task_disposition res = TASK_IS_DONE;
++ int tmf_resp;
++ struct sas_internal *i = to_sas_internal(shost->transportt);
++
++ spin_lock_irqsave(shost->host_lock, flags);
++ list_splice_init(&shost->eh_cmd_q, &error_q);
++ spin_unlock_irqrestore(shost->host_lock, flags);
++
++ SAS_DPRINTK("Enter %s\n", __FUNCTION__);
++
++ /* All tasks on this list were marked SAS_TASK_STATE_ABORTED
++ * by sas_scsi_timed_out() callback.
++ */
++Again:
++ SAS_DPRINTK("going over list...\n");
++ list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
++ struct sas_task *task = TO_SAS_TASK(cmd);
++
++ SAS_DPRINTK("trying to find task 0x%p\n", task);
++ list_del_init(&cmd->eh_entry);
++ res = sas_scsi_find_task(task);
++
++ cmd->eh_eflags = 0;
++ shost->host_failed--;
++
++ switch (res) {
++ case TASK_IS_DONE:
++ SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
++ task);
++ task->task_done(task);
++ continue;
++ case TASK_IS_ABORTED:
++ SAS_DPRINTK("%s: task 0x%p is aborted\n",
++ __FUNCTION__, task);
++ task->task_done(task);
++ continue;
++ case TASK_IS_AT_LU:
++ SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
++ tmf_resp = sas_recover_lu(task->dev, cmd);
++ if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
++ SAS_DPRINTK("dev %016llx LU %x is "
++ "recovered\n",
++ SAS_ADDR(task->dev),
++ cmd->device->lun);
++ task->task_done(task);
++ sas_scsi_clear_queue_lu(&error_q, cmd);
++ goto Again;
++ }
++ /* fallthrough */
++ case TASK_IS_NOT_AT_LU:
++ SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
++ task);
++ tmf_resp = sas_recover_I_T(task->dev);
++ if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
++ SAS_DPRINTK("I_T %016llx recovered\n",
++ SAS_ADDR(task->dev->sas_addr));
++ task->task_done(task);
++ sas_scsi_clear_queue_I_T(&error_q, task->dev);
++ goto Again;
++ }
++ /* Hammer time :-) */
++ if (i->dft->lldd_clear_nexus_port) {
++ struct asd_sas_port *port = task->dev->port;
++ SAS_DPRINTK("clearing nexus for port:%d\n",
++ port->id);
++ res = i->dft->lldd_clear_nexus_port(port);
++ if (res == TMF_RESP_FUNC_COMPLETE) {
++ SAS_DPRINTK("clear nexus port:%d "
++ "succeeded\n", port->id);
++ task->task_done(task);
++ sas_scsi_clear_queue_port(&error_q,
++ port);
++ goto Again;
++ }
++ }
++ if (i->dft->lldd_clear_nexus_ha) {
++ SAS_DPRINTK("clear nexus ha\n");
++ res = i->dft->lldd_clear_nexus_ha(ha);
++ if (res == TMF_RESP_FUNC_COMPLETE) {
++ SAS_DPRINTK("clear nexus ha "
++ "succeeded\n");
++ task->task_done(task);
++ goto out;
++ }
++ }
++ /* If we are here -- this means that no amount
++ * of effort could recover from errors. Quite
++ * possibly the HA just disappeared.
++ */
++ SAS_DPRINTK("error from device %llx, LUN %x "
++ "couldn't be recovered in any way\n",
++ SAS_ADDR(task->dev->sas_addr),
++ cmd->device->lun);
++
++ task->task_done(task);
++ goto clear_q;
++ }
++ }
++out:
++ SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
++ return;
++clear_q:
++ SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
++ list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
++ struct sas_task *task = TO_SAS_TASK(cmd);
++ list_del_init(&cmd->eh_entry);
++ task->task_done(task);
++ }
++}
++
++enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
++{
++ struct sas_task *task = TO_SAS_TASK(cmd);
++ unsigned long flags;
++
++ if (!task) {
++ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
++ cmd, task);
++ return EH_HANDLED;
++ }
++
++ spin_lock_irqsave(&task->task_state_lock, flags);
++ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
++ cmd, task);
++ return EH_HANDLED;
++ }
++ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
++ spin_unlock_irqrestore(&task->task_state_lock, flags);
++
++ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
++ cmd, task);
++
++ return EH_NOT_HANDLED;
++}
++
++struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
++{
++ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
++ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
++ struct domain_device *found_dev = NULL;
++ int i;
++
++ spin_lock(&ha->phy_port_lock);
++ for (i = 0; i < ha->num_phys; i++) {
++ struct asd_sas_port *port = ha->sas_port[i];
++ struct domain_device *dev;
++
++ spin_lock(&port->dev_list_lock);
++ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
++ if (rphy == dev->rphy) {
++ found_dev = dev;
++ spin_unlock(&port->dev_list_lock);
++ goto found;
++ }
++ }
++ spin_unlock(&port->dev_list_lock);
++ }
++ found:
++ spin_unlock(&ha->phy_port_lock);
++
++ return found_dev;
++}
++
++static inline struct domain_device *sas_find_target(struct scsi_target *starget)
++{
++ struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
++
++ return sas_find_dev_by_rphy(rphy);
++}
++
++int sas_target_alloc(struct scsi_target *starget)
++{
++ struct domain_device *found_dev = sas_find_target(starget);
++
++ if (!found_dev)
++ return -ENODEV;
++
++ starget->hostdata = found_dev;
++ return 0;
++}
++
++#define SAS_DEF_QD 32
++#define SAS_MAX_QD 64
++
++int sas_slave_configure(struct scsi_device *scsi_dev)
++{
++ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
++ struct sas_ha_struct *sas_ha;
++
++ BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
++
++ sas_ha = dev->port->ha;
++
++ sas_read_port_mode_page(scsi_dev);
++
++ if (scsi_dev->tagged_supported) {
++ scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG);
++ scsi_activate_tcq(scsi_dev, SAS_DEF_QD);
++ } else {
++ SAS_DPRINTK("device %llx, LUN %x doesn't support "
++ "TCQ\n", SAS_ADDR(dev->sas_addr),
++ scsi_dev->lun);
++ scsi_dev->tagged_supported = 0;
++ scsi_set_tag_type(scsi_dev, 0);
++ scsi_deactivate_tcq(scsi_dev, 1);
++ }
++
++ return 0;
++}
++
++void sas_slave_destroy(struct scsi_device *scsi_dev)
++{
++}
++
++int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
++{
++ int res = min(new_depth, SAS_MAX_QD);
++
++ if (scsi_dev->tagged_supported)
++ scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
++ res);
++ else {
++ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
++ sas_printk("device %llx LUN %x queue depth changed to 1\n",
++ SAS_ADDR(dev->sas_addr),
++ scsi_dev->lun);
++ scsi_adjust_queue_depth(scsi_dev, 0, 1);
++ res = 1;
++ }
++
++ return res;
++}
++
++int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
++{
++ if (!scsi_dev->tagged_supported)
++ return 0;
++
++ scsi_deactivate_tcq(scsi_dev, 1);
++
++ scsi_set_tag_type(scsi_dev, qt);
++ scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
++
++ return qt;
++}
++
++int sas_bios_param(struct scsi_device *scsi_dev,
++ struct block_device *bdev,
++ sector_t capacity, int *hsc)
++{
++ hsc[0] = 255;
++ hsc[1] = 63;
++ sector_div(capacity, 255*63);
++ hsc[2] = capacity;
++
++ return 0;
++}
++
++/* ---------- Task Collector Thread implementation ---------- */
++
++static void sas_queue(struct sas_ha_struct *sas_ha)
++{
++ struct scsi_core *core = &sas_ha->core;
++ unsigned long flags;
++ LIST_HEAD(q);
++ int can_queue;
++ int res;
++ struct sas_internal *i = to_sas_internal(core->shost->transportt);
++
++ spin_lock_irqsave(&core->task_queue_lock, flags);
++ while (!core->queue_thread_kill &&
++ !list_empty(&core->task_queue)) {
++
++ can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
++ if (can_queue >= 0) {
++ can_queue = core->task_queue_size;
++ list_splice_init(&core->task_queue, &q);
++ } else {
++ struct list_head *a, *n;
++
++ can_queue = sas_ha->lldd_queue_size;
++ list_for_each_safe(a, n, &core->task_queue) {
++ list_move_tail(a, &q);
++ if (--can_queue == 0)
++ break;
++ }
++ can_queue = sas_ha->lldd_queue_size;
++ }
++ core->task_queue_size -= can_queue;
++ spin_unlock_irqrestore(&core->task_queue_lock, flags);
++ {
++ struct sas_task *task = list_entry(q.next,
++ struct sas_task,
++ list);
++ list_del_init(&q);
++ res = i->dft->lldd_execute_task(task, can_queue,
++ GFP_KERNEL);
++ if (unlikely(res))
++ __list_add(&q, task->list.prev, &task->list);
++ }
++ spin_lock_irqsave(&core->task_queue_lock, flags);
++ if (res) {
++ list_splice_init(&q, &core->task_queue); /*at head*/
++ core->task_queue_size += can_queue;
++ }
++ }
++ spin_unlock_irqrestore(&core->task_queue_lock, flags);
++}
++
++static DECLARE_COMPLETION(queue_th_comp);
++
++/**
++ * sas_queue_thread -- The Task Collector thread
++ * @_sas_ha: pointer to struct sas_ha
++ */
++static int sas_queue_thread(void *_sas_ha)
++{
++ struct sas_ha_struct *sas_ha = _sas_ha;
++ struct scsi_core *core = &sas_ha->core;
++
++ daemonize("sas_queue_%d", core->shost->host_no);
++ current->flags |= PF_NOFREEZE;
++
++ complete(&queue_th_comp);
++
++ while (1) {
++ down_interruptible(&core->queue_thread_sema);
++ sas_queue(sas_ha);
++ if (core->queue_thread_kill)
++ break;
++ }
++
++ complete(&queue_th_comp);
++
++ return 0;
++}
++
++int sas_init_queue(struct sas_ha_struct *sas_ha)
++{
++ int res;
++ struct scsi_core *core = &sas_ha->core;
++
++ spin_lock_init(&core->task_queue_lock);
++ core->task_queue_size = 0;
++ INIT_LIST_HEAD(&core->task_queue);
++ init_MUTEX_LOCKED(&core->queue_thread_sema);
++
++ res = kernel_thread(sas_queue_thread, sas_ha, 0);
++ if (res >= 0)
++ wait_for_completion(&queue_th_comp);
++
++ return res < 0 ? res : 0;
++}
++
++void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
++{
++ unsigned long flags;
++ struct scsi_core *core = &sas_ha->core;
++ struct sas_task *task, *n;
++
++ init_completion(&queue_th_comp);
++ core->queue_thread_kill = 1;
++ up(&core->queue_thread_sema);
++ wait_for_completion(&queue_th_comp);
++
++ if (!list_empty(&core->task_queue))
++ SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
++ SAS_ADDR(sas_ha->sas_addr));
++
++ spin_lock_irqsave(&core->task_queue_lock, flags);
++ list_for_each_entry_safe(task, n, &core->task_queue, list) {
++ struct scsi_cmnd *cmd = task->uldd_task;
++
++ list_del_init(&task->list);
++
++ ASSIGN_SAS_TASK(cmd, NULL);
++ sas_free_task(task);
++ cmd->result = DID_ABORT << 16;
++ cmd->scsi_done(cmd);
++ }
++ spin_unlock_irqrestore(&core->task_queue_lock, flags);
++}
++
++EXPORT_SYMBOL_GPL(sas_queuecommand);
++EXPORT_SYMBOL_GPL(sas_target_alloc);
++EXPORT_SYMBOL_GPL(sas_slave_configure);
++EXPORT_SYMBOL_GPL(sas_slave_destroy);
++EXPORT_SYMBOL_GPL(sas_change_queue_depth);
++EXPORT_SYMBOL_GPL(sas_change_queue_type);
++EXPORT_SYMBOL_GPL(sas_bios_param);
+diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
+index d44f9aa..3f7f5f8 100644
+--- a/drivers/scsi/lpfc/lpfc.h
++++ b/drivers/scsi/lpfc/lpfc.h
+@@ -285,6 +285,7 @@ struct lpfc_hba {
+ uint32_t cfg_log_verbose;
+ uint32_t cfg_lun_queue_depth;
+ uint32_t cfg_nodev_tmo;
++ uint32_t cfg_devloss_tmo;
+ uint32_t cfg_hba_queue_depth;
+ uint32_t cfg_fcp_class;
+ uint32_t cfg_use_adisc;
+@@ -302,6 +303,9 @@ struct lpfc_hba {
+ uint32_t cfg_poll_tmo;
+ uint32_t cfg_sg_seg_cnt;
+ uint32_t cfg_sg_dma_buf_size;
++ uint64_t cfg_soft_wwpn;
++
++ uint32_t dev_loss_tmo_changed;
+
+ lpfc_vpd_t vpd; /* vital product data */
+
+@@ -351,6 +355,8 @@ struct lpfc_hba {
+ #define VPD_PORT 0x8 /* valid vpd port data */
+ #define VPD_MASK 0xf /* mask for any vpd data */
+
++ uint8_t soft_wwpn_enable;
++
+ struct timer_list fcp_poll_timer;
+ struct timer_list els_tmofunc;
+
+@@ -391,3 +397,5 @@ struct rnidrsp {
+ struct list_head list;
+ uint32_t data;
+ };
++
++#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
+diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
+index d384c16..2a4e02e 100644
+--- a/drivers/scsi/lpfc/lpfc_attr.c
++++ b/drivers/scsi/lpfc/lpfc_attr.c
+@@ -39,6 +39,9 @@
+ #include "lpfc_compat.h"
+ #include "lpfc_crtn.h"
+
++#define LPFC_DEF_DEVLOSS_TMO 30
++#define LPFC_MIN_DEVLOSS_TMO 1
++#define LPFC_MAX_DEVLOSS_TMO 255
+
+ static void
+ lpfc_jedec_to_ascii(int incr, char hdw[])
+@@ -548,6 +551,120 @@ static CLASS_DEVICE_ATTR(board_mode, S_I
+ lpfc_board_mode_show, lpfc_board_mode_store);
+ static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
+
++
++static char *lpfc_soft_wwpn_key = "C99G71SL8032A";
++
++static ssize_t
++lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
++ size_t count)
++{
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
++ unsigned int cnt = count;
++
++ /*
++ * We're doing a simple sanity check for soft_wwpn setting.
++ * We require that the user write a specific key to enable
++ * the soft_wwpn attribute to be settable. Once the attribute
++ * is written, the enable key resets. If further updates are
++ * desired, the key must be written again to re-enable the
++ * attribute.
++ *
++ * The "key" is not secret - it is a hardcoded string shown
++ * here. The intent is to protect against the random user or
++ * application that is just writing attributes.
++ */
++
++ /* count may include a LF at end of string */
++ if (buf[cnt-1] == '\n')
++ cnt--;
++
++ if ((cnt != strlen(lpfc_soft_wwpn_key)) ||
++ (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0))
++ return -EINVAL;
++
++ phba->soft_wwpn_enable = 1;
++ return count;
++}
++static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL,
++ lpfc_soft_wwpn_enable_store);
++
++static ssize_t
++lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
++{
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
++ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
++ (unsigned long long)phba->cfg_soft_wwpn);
++}
++
++
++static ssize_t
++lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
++{
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
++ struct completion online_compl;
++ int stat1=0, stat2=0;
++ unsigned int i, j, cnt=count;
++ u8 wwpn[8];
++
++ /* count may include a LF at end of string */
++ if (buf[cnt-1] == '\n')
++ cnt--;
++
++ if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) ||
++ ((cnt == 17) && (*buf++ != 'x')) ||
++ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
++ return -EINVAL;
++
++ phba->soft_wwpn_enable = 0;
++
++ memset(wwpn, 0, sizeof(wwpn));
++
++ /* Validate and store the new name */
++ for (i=0, j=0; i < 16; i++) {
++ if ((*buf >= 'a') && (*buf <= 'f'))
++ j = ((j << 4) | ((*buf++ -'a') + 10));
++ else if ((*buf >= 'A') && (*buf <= 'F'))
++ j = ((j << 4) | ((*buf++ -'A') + 10));
++ else if ((*buf >= '0') && (*buf <= '9'))
++ j = ((j << 4) | (*buf++ -'0'));
++ else
++ return -EINVAL;
++ if (i % 2) {
++ wwpn[i/2] = j & 0xff;
++ j = 0;
++ }
++ }
++ phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
++ fc_host_port_name(host) = phba->cfg_soft_wwpn;
++
++ dev_printk(KERN_NOTICE, &phba->pcidev->dev,
++ "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
++
++ init_completion(&online_compl);
++ lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
++ wait_for_completion(&online_compl);
++ if (stat1)
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
++ "adapter - %d\n", phba->brd_no, stat1);
++
++ init_completion(&online_compl);
++ lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
++ wait_for_completion(&online_compl);
++ if (stat2)
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0464 lpfc_soft_wwpn attribute set failed to reinit "
++ "adapter - %d\n", phba->brd_no, stat2);
++
++ return (stat1 || stat2) ? -EIO : count;
++}
++static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
++ lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
++
++
+ static int lpfc_poll = 0;
+ module_param(lpfc_poll, int, 0);
+ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:"
+@@ -559,6 +676,123 @@ static CLASS_DEVICE_ATTR(lpfc_poll, S_IR
+ lpfc_poll_show, lpfc_poll_store);
+
+ /*
++# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
++# until the timer expires. Value range is [0,255]. Default value is 30.
++*/
++static int lpfc_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
++static int lpfc_devloss_tmo = LPFC_DEF_DEVLOSS_TMO;
++module_param(lpfc_nodev_tmo, int, 0);
++MODULE_PARM_DESC(lpfc_nodev_tmo,
++ "Seconds driver will hold I/O waiting "
++ "for a device to come back");
++static ssize_t
++lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
++{
++ struct Scsi_Host *host = class_to_shost(cdev);
++ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
++ int val = 0;
++ val = phba->cfg_devloss_tmo;
++ return snprintf(buf, PAGE_SIZE, "%d\n",
++ phba->cfg_devloss_tmo);
++}
++
++static int
++lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
++{
++ static int warned;
++ if (phba->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
++ phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
++ if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
++ warned = 1;
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0402 Ignoring nodev_tmo module "
++ "parameter because devloss_tmo is"
++ " set.\n",
++ phba->brd_no);
++ }
++ return 0;
++ }
++
++ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
++ phba->cfg_nodev_tmo = val;
++ phba->cfg_devloss_tmo = val;
++ return 0;
++ }
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
++ "allowed range is [%d, %d]\n",
++ phba->brd_no, val,
++ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
++ phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
++ return -EINVAL;
++}
++
++static int
++lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
++{
++ if (phba->dev_loss_tmo_changed ||
++ (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0401 Ignoring change to nodev_tmo "
++ "because devloss_tmo is set.\n",
++ phba->brd_no);
++ return 0;
++ }
++
++ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
++ phba->cfg_nodev_tmo = val;
++ phba->cfg_devloss_tmo = val;
++ return 0;
++ }
++
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
++ "allowed range is [%d, %d]\n",
++ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
++ LPFC_MAX_DEVLOSS_TMO);
++ return -EINVAL;
++}
++
++lpfc_param_store(nodev_tmo)
++
++static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
++ lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
++
++/*
++# lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that
++# disappear until the timer expires. Value range is [0,255]. Default
++# value is 30.
++*/
++module_param(lpfc_devloss_tmo, int, 0);
++MODULE_PARM_DESC(lpfc_devloss_tmo,
++ "Seconds driver will hold I/O waiting "
++ "for a device to come back");
++lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
++ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
++lpfc_param_show(devloss_tmo)
++static int
++lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
++{
++ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
++ phba->cfg_nodev_tmo = val;
++ phba->cfg_devloss_tmo = val;
++ phba->dev_loss_tmo_changed = 1;
++ return 0;
++ }
++
++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++ "%d:0404 lpfc_devloss_tmo attribute cannot be set to"
++ " %d, allowed range is [%d, %d]\n",
++ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
++ LPFC_MAX_DEVLOSS_TMO);
++ return -EINVAL;
++}
++
++lpfc_param_store(devloss_tmo)
++static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
++ lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
++
++/*
+ # lpfc_log_verbose: Only turn this flag on if you are willing to risk being
+ # deluged with LOTS of information.
+ # You can set a bit mask to record specific types of verbose messages:
+@@ -617,14 +851,6 @@ LPFC_ATTR_R(scan_down, 1, 0, 1,
+ "Start scanning for devices from highest ALPA to lowest");
+
+ /*
+-# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+-# until the timer expires. Value range is [0,255]. Default value is 30.
+-# NOTE: this MUST be less then the SCSI Layer command timeout - 1.
+-*/
+-LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
+- "Seconds driver will hold I/O waiting for a device to come back");
+-
+-/*
+ # lpfc_topology: link topology for init link
+ # 0x0 = attempt loop mode then point-to-point
+ # 0x01 = internal loopback mode
+@@ -720,6 +946,7 @@ LPFC_ATTR_R(max_luns, 255, 0, 65535,
+ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
+ "Milliseconds driver will wait between polling FCP ring");
+
++
+ struct class_device_attribute *lpfc_host_attrs[] = {
+ &class_device_attr_info,
+ &class_device_attr_serialnum,
+@@ -737,6 +964,7 @@ struct class_device_attribute *lpfc_host
+ &class_device_attr_lpfc_lun_queue_depth,
+ &class_device_attr_lpfc_hba_queue_depth,
+ &class_device_attr_lpfc_nodev_tmo,
++ &class_device_attr_lpfc_devloss_tmo,
+ &class_device_attr_lpfc_fcp_class,
+ &class_device_attr_lpfc_use_adisc,
+ &class_device_attr_lpfc_ack0,
+@@ -754,6 +982,8 @@ struct class_device_attribute *lpfc_host
+ &class_device_attr_issue_reset,
+ &class_device_attr_lpfc_poll,
+ &class_device_attr_lpfc_poll_tmo,
++ &class_device_attr_lpfc_soft_wwpn,
++ &class_device_attr_lpfc_soft_wwpn_enable,
+ NULL,
+ };
+
+@@ -1204,6 +1434,15 @@ lpfc_get_host_fabric_name (struct Scsi_H
+ fc_host_fabric_name(shost) = node_name;
+ }
+
++static void
++lpfc_get_host_symbolic_name (struct Scsi_Host *shost)
++{
++ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
++
++ spin_lock_irq(shost->host_lock);
++ lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
++ spin_unlock_irq(shost->host_lock);
++}
+
+ static struct fc_host_statistics *
+ lpfc_get_stats(struct Scsi_Host *shost)
+@@ -1441,27 +1680,12 @@ lpfc_get_starget_port_name(struct scsi_t
+ }
+
+ static void
+-lpfc_get_rport_loss_tmo(struct fc_rport *rport)
+-{
+- /*
+- * Return the driver's global value for device loss timeout plus
+- * five seconds to allow the driver's nodev timer to run.
+- */
+- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
+-}
+-
+-static void
+ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+ {
+- /*
+- * The driver doesn't have a per-target timeout setting. Set
+- * this value globally. lpfc_nodev_tmo should be greater then 0.
+- */
+ if (timeout)
+- lpfc_nodev_tmo = timeout;
++ rport->dev_loss_tmo = timeout;
+ else
+- lpfc_nodev_tmo = 1;
+- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
++ rport->dev_loss_tmo = 1;
+ }
+
+
+@@ -1486,7 +1710,6 @@ struct fc_function_template lpfc_transpo
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+- .show_host_symbolic_name = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+@@ -1509,6 +1732,9 @@ struct fc_function_template lpfc_transpo
+ .get_host_fabric_name = lpfc_get_host_fabric_name,
+ .show_host_fabric_name = 1,
+
++ .get_host_symbolic_name = lpfc_get_host_symbolic_name,
++ .show_host_symbolic_name = 1,
++
+ /*
+ * The LPFC driver treats linkdown handling as target loss events
+ * so there are no sysfs handlers for link_down_tmo.
+@@ -1521,7 +1747,6 @@ struct fc_function_template lpfc_transpo
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+
+- .get_rport_dev_loss_tmo = lpfc_get_rport_loss_tmo,
+ .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+
+@@ -1535,6 +1760,8 @@ struct fc_function_template lpfc_transpo
+ .show_starget_port_name = 1,
+
+ .issue_fc_host_lip = lpfc_issue_lip,
++ .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
++ .terminate_rport_io = lpfc_terminate_rport_io,
+ };
+
+ void
+@@ -1550,14 +1777,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
+ lpfc_ack0_init(phba, lpfc_ack0);
+ lpfc_topology_init(phba, lpfc_topology);
+ lpfc_scan_down_init(phba, lpfc_scan_down);
+- lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
+ lpfc_link_speed_init(phba, lpfc_link_speed);
+ lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
+ lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
+ lpfc_max_luns_init(phba, lpfc_max_luns);
+ lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+-
++ lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
++ lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
+ phba->cfg_poll = lpfc_poll;
++ phba->cfg_soft_wwpn = 0L;
+
+ /*
+ * The total number of segments is the configuration value plus 2
+diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
+index 2a17646..1251788 100644
+--- a/drivers/scsi/lpfc/lpfc_crtn.h
++++ b/drivers/scsi/lpfc/lpfc_crtn.h
+@@ -18,6 +18,7 @@
+ * included with this package. *
+ *******************************************************************/
+
++struct fc_rport;
+ void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+ void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
+@@ -119,7 +120,7 @@ int lpfc_sli_queue_setup(struct lpfc_hba
+
+ void lpfc_handle_eratt(struct lpfc_hba *);
+ void lpfc_handle_latt(struct lpfc_hba *);
+-irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
++irqreturn_t lpfc_intr_handler(int, void *);
+
+ void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
+@@ -200,6 +201,8 @@ extern struct scsi_host_template lpfc_te
+ extern struct fc_function_template lpfc_transport_functions;
+
+ void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
++void lpfc_terminate_rport_io(struct fc_rport *);
++void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
+
+ #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
+ #define HBA_EVENT_RSCN 5
+diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
+index bbb7310..3add7c2 100644
+--- a/drivers/scsi/lpfc/lpfc_ct.c
++++ b/drivers/scsi/lpfc/lpfc_ct.c
+@@ -188,7 +188,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba * phba
+
+ if (!mp->virt) {
+ kfree(mp);
+- lpfc_free_ct_rsp(phba, mlist);
++ if (mlist)
++ lpfc_free_ct_rsp(phba, mlist);
+ return NULL;
+ }
+
+@@ -324,7 +325,6 @@ lpfc_ns_rsp(struct lpfc_hba * phba, stru
+ struct lpfc_sli_ct_request *Response =
+ (struct lpfc_sli_ct_request *) mp->virt;
+ struct lpfc_nodelist *ndlp = NULL;
+- struct lpfc_nodelist *next_ndlp;
+ struct lpfc_dmabuf *mlast, *next_mp;
+ uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
+ uint32_t Did;
+@@ -399,30 +399,6 @@ nsout1:
+ * current driver state.
+ */
+ if (phba->hba_state == LPFC_HBA_READY) {
+-
+- /*
+- * Switch ports that connect a loop of multiple targets need
+- * special consideration. The driver wants to unregister the
+- * rpi only on the target that was pulled from the loop. On
+- * RSCN, the driver wants to rediscover an NPort only if the
+- * driver flagged it as NLP_NPR_2B_DISC. Provided adisc is
+- * not enabled and the NPort is not capable of retransmissions
+- * (FC Tape) prevent timing races with the scsi error handler by
+- * unregistering the Nport's RPI. This action causes all
+- * outstanding IO to flush back to the midlayer.
+- */
+- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+- nlp_listp) {
+- if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+- (lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) {
+- if ((phba->cfg_use_adisc == 0) &&
+- !(ndlp->nlp_fcp_info &
+- NLP_FCP_2_DEVICE)) {
+- lpfc_unreg_rpi(phba, ndlp);
+- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+- }
+- }
+- }
+ lpfc_els_flush_rscn(phba);
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
+@@ -958,8 +934,8 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, st
+ ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
+ ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION);
+ sprintf(ae->un.OsNameVersion, "%s %s %s",
+- system_utsname.sysname, system_utsname.release,
+- system_utsname.version);
++ init_utsname()->sysname, init_utsname()->release,
++ init_utsname()->version);
+ len = strlen(ae->un.OsNameVersion);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
+@@ -1077,7 +1053,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, st
+ size);
+ ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME);
+ sprintf(ae->un.HostName, "%s",
+- system_utsname.nodename);
++ init_utsname()->nodename);
+ len = strlen(ae->un.HostName);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ ae->ad.bits.AttrLen =
+@@ -1165,7 +1141,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *p
+
+ ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+ if (ndlp) {
+- if (system_utsname.nodename[0] != '\0') {
++ if (init_utsname()->nodename[0] != '\0') {
+ lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
+ } else {
+ mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
+diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
+index 41cf5d3..9766f90 100644
+--- a/drivers/scsi/lpfc/lpfc_disc.h
++++ b/drivers/scsi/lpfc/lpfc_disc.h
+@@ -30,7 +30,6 @@
+
+ /* worker thread events */
+ enum lpfc_work_type {
+- LPFC_EVT_NODEV_TMO,
+ LPFC_EVT_ONLINE,
+ LPFC_EVT_OFFLINE,
+ LPFC_EVT_WARM_START,
+@@ -74,11 +73,9 @@ struct lpfc_nodelist {
+ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
+
+ struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
+- struct timer_list nlp_tmofunc; /* Used for nodev tmo */
+ struct fc_rport *rport; /* Corresponding FC transport
+ port structure */
+ struct lpfc_hba *nlp_phba;
+- struct lpfc_work_evt nodev_timeout_evt;
+ struct lpfc_work_evt els_retry_evt;
+ unsigned long last_ramp_up_time; /* jiffy of last ramp up */
+ unsigned long last_q_full_time; /* jiffy of last queue full */
+@@ -102,7 +99,6 @@ struct lpfc_nodelist {
+ #define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */
+ #define NLP_RNID_SND 0x400 /* sent RNID request for this entry */
+ #define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */
+-#define NLP_NODEV_TMO 0x10000 /* nodev timeout is running for node */
+ #define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */
+ #define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */
+ #define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */
+@@ -169,7 +165,7 @@ struct lpfc_nodelist {
+ */
+ /*
+ * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
+- * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
++ * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
+ * expire, all effected nodes will receive a DEVICE_RM event.
+ */
+ /*
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 3567de6..71864cd 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -2506,6 +2506,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba
+ uint32_t *lp;
+ IOCB_t *icmd;
+ uint32_t payload_len, cmd;
++ int i;
+
+ icmd = &cmdiocb->iocb;
+ pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+@@ -2524,6 +2525,10 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba
+ phba->brd_no,
+ phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
+
++ for (i = 0; i < payload_len/sizeof(uint32_t); i++)
++ fc_host_post_event(phba->host, fc_get_event_number(),
++ FCH_EVT_RSCN, lp[i]);
++
+ /* If we are about to begin discovery, just ACC the RSCN.
+ * Discovery processing will satisfy it.
+ */
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index b2f1552..19c79a0 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -56,28 +56,63 @@ static uint8_t lpfcAlpaArray[] = {
+
+ static void lpfc_disc_timeout_handler(struct lpfc_hba *);
+
+-static void
+-lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
++void
++lpfc_terminate_rport_io(struct fc_rport *rport)
+ {
+- uint8_t *name = (uint8_t *)&ndlp->nlp_portname;
+- int warn_on = 0;
++ struct lpfc_rport_data *rdata;
++ struct lpfc_nodelist * ndlp;
++ struct lpfc_hba *phba;
+
+- spin_lock_irq(phba->host->host_lock);
+- if (!(ndlp->nlp_flag & NLP_NODEV_TMO)) {
+- spin_unlock_irq(phba->host->host_lock);
++ rdata = rport->dd_data;
++ ndlp = rdata->pnode;
++
++ if (!ndlp) {
++ if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
++ printk(KERN_ERR "Cannot find remote node"
++ " to terminate I/O Data x%x\n",
++ rport->port_id);
+ return;
+ }
+
+- /*
+- * If a discovery event readded nodev_timer after timer
+- * firing and before processing the timer, cancel the
+- * nlp_tmofunc.
+- */
+- spin_unlock_irq(phba->host->host_lock);
+- del_timer_sync(&ndlp->nlp_tmofunc);
++ phba = ndlp->nlp_phba;
++
+ spin_lock_irq(phba->host->host_lock);
++ if (ndlp->nlp_sid != NLP_NO_SID) {
++ lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
++ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
++ }
++ spin_unlock_irq(phba->host->host_lock);
+
+- ndlp->nlp_flag &= ~NLP_NODEV_TMO;
++ return;
++}
++
++/*
++ * This function will be called when dev_loss_tmo fire.
++ */
++void
++lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
++{
++ struct lpfc_rport_data *rdata;
++ struct lpfc_nodelist * ndlp;
++ uint8_t *name;
++ int warn_on = 0;
++ struct lpfc_hba *phba;
++
++ rdata = rport->dd_data;
++ ndlp = rdata->pnode;
++
++ if (!ndlp) {
++ if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
++ printk(KERN_ERR "Cannot find remote node"
++ " for rport in dev_loss_tmo_callbk x%x\n",
++ rport->port_id);
++ return;
++ }
++
++ name = (uint8_t *)&ndlp->nlp_portname;
++ phba = ndlp->nlp_phba;
++
++ spin_lock_irq(phba->host->host_lock);
+
+ if (ndlp->nlp_sid != NLP_NO_SID) {
+ warn_on = 1;
+@@ -85,11 +120,14 @@ lpfc_process_nodev_timeout(struct lpfc_h
+ lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ }
++ if (phba->fc_flag & FC_UNLOADING)
++ warn_on = 0;
++
+ spin_unlock_irq(phba->host->host_lock);
+
+ if (warn_on) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+- "%d:0203 Nodev timeout on "
++ "%d:0203 Devloss timeout on "
+ "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
+ "NPort x%x Data: x%x x%x x%x\n",
+ phba->brd_no,
+@@ -99,7 +137,7 @@ lpfc_process_nodev_timeout(struct lpfc_h
+ ndlp->nlp_state, ndlp->nlp_rpi);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+- "%d:0204 Nodev timeout on "
++ "%d:0204 Devloss timeout on "
+ "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
+ "NPort x%x Data: x%x x%x x%x\n",
+ phba->brd_no,
+@@ -109,7 +147,12 @@ lpfc_process_nodev_timeout(struct lpfc_h
+ ndlp->nlp_state, ndlp->nlp_rpi);
+ }
+
+- lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
++ ndlp->rport = NULL;
++ rdata->pnode = NULL;
++
++ if (!(phba->fc_flag & FC_UNLOADING))
++ lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
++
+ return;
+ }
+
+@@ -127,11 +170,6 @@ lpfc_work_list_done(struct lpfc_hba * ph
+ spin_unlock_irq(phba->host->host_lock);
+ free_evt = 1;
+ switch (evtp->evt) {
+- case LPFC_EVT_NODEV_TMO:
+- ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+- lpfc_process_nodev_timeout(phba, ndlp);
+- free_evt = 0;
+- break;
+ case LPFC_EVT_ELS_RETRY:
+ ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+ lpfc_els_retry_delay_handler(ndlp);
+@@ -267,7 +305,7 @@ lpfc_do_work(void *p)
+ {
+ struct lpfc_hba *phba = p;
+ int rc;
+- DECLARE_WAIT_QUEUE_HEAD(work_waitq);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq);
+
+ set_user_nice(current, -20);
+ phba->work_wait = &work_waitq;
+@@ -340,6 +378,9 @@ lpfc_linkdown(struct lpfc_hba * phba)
+ spin_unlock_irq(phba->host->host_lock);
+ }
+
++ fc_host_post_event(phba->host, fc_get_event_number(),
++ FCH_EVT_LINKDOWN, 0);
++
+ /* Clean up any firmware default rpi's */
+ if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+ lpfc_unreg_did(phba, 0xffffffff, mb);
+@@ -374,16 +415,6 @@ lpfc_linkdown(struct lpfc_hba * phba)
+ rc = lpfc_disc_state_machine(phba, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
+
+- /* Check config parameter use-adisc or FCP-2 */
+- if ((rc != NLP_STE_FREED_NODE) &&
+- (phba->cfg_use_adisc == 0) &&
+- !(ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE)) {
+- /* We know we will have to relogin, so
+- * unreglogin the rpi right now to fail
+- * any outstanding I/Os quickly.
+- */
+- lpfc_unreg_rpi(phba, ndlp);
+- }
+ }
+ }
+
+@@ -427,6 +458,9 @@ lpfc_linkup(struct lpfc_hba * phba)
+ struct list_head *listp, *node_list[7];
+ int i;
+
++ fc_host_post_event(phba->host, fc_get_event_number(),
++ FCH_EVT_LINKUP, 0);
++
+ spin_lock_irq(phba->host->host_lock);
+ phba->hba_state = LPFC_LINK_UP;
+ phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
+@@ -638,6 +672,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hb
+
+ memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
+ sizeof (struct serv_parm));
++ if (phba->cfg_soft_wwpn)
++ u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
+ memcpy((uint8_t *) & phba->fc_nodename,
+ (uint8_t *) & phba->fc_sparam.nodeName,
+ sizeof (struct lpfc_name));
+@@ -1098,8 +1134,11 @@ lpfc_unregister_remote_port(struct lpfc_
+ struct fc_rport *rport = ndlp->rport;
+ struct lpfc_rport_data *rdata = rport->dd_data;
+
+- ndlp->rport = NULL;
+- rdata->pnode = NULL;
++ if (rport->scsi_target_id == -1) {
++ ndlp->rport = NULL;
++ rdata->pnode = NULL;
++ }
++
+ fc_remote_port_delete(rport);
+
+ return;
+@@ -1227,17 +1266,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, st
+ list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
+ phba->fc_unmap_cnt++;
+ phba->nport_event_cnt++;
+- /* stop nodev tmo if running */
+- if (nlp->nlp_flag & NLP_NODEV_TMO) {
+- nlp->nlp_flag &= ~NLP_NODEV_TMO;
+- spin_unlock_irq(phba->host->host_lock);
+- del_timer_sync(&nlp->nlp_tmofunc);
+- spin_lock_irq(phba->host->host_lock);
+- if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
+- list_del_init(&nlp->nodev_timeout_evt.
+- evt_listp);
+-
+- }
+ nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+ nlp->nlp_type |= NLP_FC_NODE;
+ break;
+@@ -1248,17 +1276,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, st
+ list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
+ phba->fc_map_cnt++;
+ phba->nport_event_cnt++;
+- /* stop nodev tmo if running */
+- if (nlp->nlp_flag & NLP_NODEV_TMO) {
+- nlp->nlp_flag &= ~NLP_NODEV_TMO;
+- spin_unlock_irq(phba->host->host_lock);
+- del_timer_sync(&nlp->nlp_tmofunc);
+- spin_lock_irq(phba->host->host_lock);
+- if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
+- list_del_init(&nlp->nodev_timeout_evt.
+- evt_listp);
+-
+- }
+ nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+ break;
+ case NLP_NPR_LIST:
+@@ -1267,11 +1284,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, st
+ list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
+ phba->fc_npr_cnt++;
+
+- if (!(nlp->nlp_flag & NLP_NODEV_TMO))
+- mod_timer(&nlp->nlp_tmofunc,
+- jiffies + HZ * phba->cfg_nodev_tmo);
+-
+- nlp->nlp_flag |= NLP_NODEV_TMO;
+ nlp->nlp_flag &= ~NLP_RCV_PLOGI;
+ break;
+ case NLP_JUST_DQ:
+@@ -1301,7 +1313,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, st
+ * already. If we have, and it's a scsi entity, be
+ * sure to unblock any attached scsi devices
+ */
+- if (!nlp->rport)
++ if ((!nlp->rport) || (nlp->rport->port_state ==
++ FC_PORTSTATE_BLOCKED))
+ lpfc_register_remote_port(phba, nlp);
+
+ /*
+@@ -1575,15 +1588,12 @@ lpfc_freenode(struct lpfc_hba * phba, st
+
+ lpfc_els_abort(phba,ndlp,0);
+ spin_lock_irq(phba->host->host_lock);
+- ndlp->nlp_flag &= ~(NLP_NODEV_TMO|NLP_DELAY_TMO);
++ ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+ spin_unlock_irq(phba->host->host_lock);
+- del_timer_sync(&ndlp->nlp_tmofunc);
+
+ ndlp->nlp_last_elscmd = 0;
+ del_timer_sync(&ndlp->nlp_delayfunc);
+
+- if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
+- list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
+ if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+ list_del_init(&ndlp->els_retry_evt.evt_listp);
+
+@@ -1600,16 +1610,6 @@ lpfc_freenode(struct lpfc_hba * phba, st
+ int
+ lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+ {
+- if (ndlp->nlp_flag & NLP_NODEV_TMO) {
+- spin_lock_irq(phba->host->host_lock);
+- ndlp->nlp_flag &= ~NLP_NODEV_TMO;
+- spin_unlock_irq(phba->host->host_lock);
+- del_timer_sync(&ndlp->nlp_tmofunc);
+- if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
+- list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
+-
+- }
+-
+
+ if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+ lpfc_cancel_retry_delay_tmo(phba, ndlp);
+@@ -2424,34 +2424,6 @@ lpfc_disc_timeout_handler(struct lpfc_hb
+ return;
+ }
+
+-static void
+-lpfc_nodev_timeout(unsigned long ptr)
+-{
+- struct lpfc_hba *phba;
+- struct lpfc_nodelist *ndlp;
+- unsigned long iflag;
+- struct lpfc_work_evt *evtp;
+-
+- ndlp = (struct lpfc_nodelist *)ptr;
+- phba = ndlp->nlp_phba;
+- evtp = &ndlp->nodev_timeout_evt;
+- spin_lock_irqsave(phba->host->host_lock, iflag);
+-
+- if (!list_empty(&evtp->evt_listp)) {
+- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+- return;
+- }
+- evtp->evt_arg1 = ndlp;
+- evtp->evt = LPFC_EVT_NODEV_TMO;
+- list_add_tail(&evtp->evt_listp, &phba->work_list);
+- if (phba->work_wait)
+- wake_up(phba->work_wait);
+-
+- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+- return;
+-}
+-
+-
+ /*
+ * This routine handles processing a NameServer REG_LOGIN mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+@@ -2575,11 +2547,7 @@ lpfc_nlp_init(struct lpfc_hba * phba, st
+ uint32_t did)
+ {
+ memset(ndlp, 0, sizeof (struct lpfc_nodelist));
+- INIT_LIST_HEAD(&ndlp->nodev_timeout_evt.evt_listp);
+ INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
+- init_timer(&ndlp->nlp_tmofunc);
+- ndlp->nlp_tmofunc.function = lpfc_nodev_timeout;
+- ndlp->nlp_tmofunc.data = (unsigned long)ndlp;
+ init_timer(&ndlp->nlp_delayfunc);
+ ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
+ ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
+diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
+index f6948ff..a5723ad 100644
+--- a/drivers/scsi/lpfc/lpfc_init.c
++++ b/drivers/scsi/lpfc/lpfc_init.c
+@@ -268,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba *
+ kfree(mp);
+ pmb->context1 = NULL;
+
++ if (phba->cfg_soft_wwpn)
++ u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
+ memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
+ sizeof (struct lpfc_name));
+ memcpy(&phba->fc_portname, &phba->fc_sparam.portName,
+@@ -387,7 +389,8 @@ lpfc_config_port_post(struct lpfc_hba *
+
+ lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+- if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) {
++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
++ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba,
+ KERN_ERR,
+ LOG_INIT,
+@@ -404,7 +407,8 @@ lpfc_config_port_post(struct lpfc_hba *
+ readl(phba->HAregaddr); /* flush */
+
+ phba->hba_state = LPFC_HBA_ERROR;
+- mempool_free(pmb, phba->mbox_mem_pool);
++ if (rc != MBX_BUSY)
++ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
+ /* MBOX buffer will be freed in mbox compl */
+@@ -511,6 +515,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba
+ {
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
++ uint32_t event_data;
+
+ if (phba->work_hs & HS_FFER6) {
+ /* Re-establishing Link */
+@@ -555,6 +560,11 @@ lpfc_handle_eratt(struct lpfc_hba * phba
+ phba->brd_no, phba->work_hs,
+ phba->work_status[0], phba->work_status[1]);
+
++ event_data = FC_REG_DUMP_EVENT;
++ fc_host_post_vendor_event(phba->host, fc_get_event_number(),
++ sizeof(event_data), (char *) &event_data,
++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
++
+ psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ lpfc_offline(phba);
+ phba->hba_state = LPFC_HBA_ERROR;
+diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
+index 20449a8..d5f4150 100644
+--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
+@@ -1813,7 +1813,7 @@ lpfc_device_recov_npr_node(struct lpfc_h
+ */
+ /*
+ * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
+- * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
++ * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
+ * expire, all effected nodes will receive a DEVICE_RM event.
+ */
+ /*
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
+index a8816a8..97ae98d 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.c
++++ b/drivers/scsi/lpfc/lpfc_scsi.c
+@@ -935,7 +935,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmn
+ schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ);
+ spin_lock_irq(phba->host->host_lock);
+ if (++loop_count
+- > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT)
++ > (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
+ break;
+ }
+
+@@ -978,7 +978,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd
+ spin_lock_irq(shost->host_lock);
+ /*
+ * If target is not in a MAPPED state, delay the reset until
+- * target is rediscovered or nodev timeout expires.
++ * target is rediscovered or devloss timeout expires.
+ */
+ while ( 1 ) {
+ if (!pnode)
+@@ -1050,7 +1050,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd
+ spin_lock_irq(phba->host->host_lock);
+
+ if (++loopcnt
+- > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
++ > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
+ break;
+
+ cnt = lpfc_sli_sum_iocb(phba,
+@@ -1151,7 +1151,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd
+ spin_lock_irq(phba->host->host_lock);
+
+ if (++loopcnt
+- > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
++ > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
+ break;
+
+ cnt = lpfc_sli_sum_iocb(phba,
+@@ -1249,7 +1249,7 @@ lpfc_slave_configure(struct scsi_device
+ * target pointer is stored in the starget_data for the
+ * driver's sysfs entry point functions.
+ */
+- rport->dev_loss_tmo = phba->cfg_nodev_tmo + 5;
++ rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+
+ if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+ lpfc_sli_poll_fcp_ring(phba);
+diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
+index 70f4d5a..582f5ea 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.c
++++ b/drivers/scsi/lpfc/lpfc_sli.c
+@@ -2983,7 +2983,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba
+ struct lpfc_iocbq * prspiocbq,
+ uint32_t timeout)
+ {
+- DECLARE_WAIT_QUEUE_HEAD(done_q);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
+ long timeleft, timeout_req = 0;
+ int retval = IOCB_SUCCESS;
+ uint32_t creg_val;
+@@ -3061,7 +3061,7 @@ int
+ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
+ uint32_t timeout)
+ {
+- DECLARE_WAIT_QUEUE_HEAD(done_q);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
+ DECLARE_WAITQUEUE(wq_entry, current);
+ uint32_t timeleft = 0;
+ int retval;
+@@ -3119,7 +3119,7 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hb
+ }
+
+ irqreturn_t
+-lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
++lpfc_intr_handler(int irq, void *dev_id)
+ {
+ struct lpfc_hba *phba;
+ uint32_t ha_copy;
+diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
+index c7091ea..ac41790 100644
+--- a/drivers/scsi/lpfc/lpfc_version.h
++++ b/drivers/scsi/lpfc/lpfc_version.h
+@@ -18,7 +18,7 @@
+ * included with this package. *
+ *******************************************************************/
+
+-#define LPFC_DRIVER_VERSION "8.1.9"
++#define LPFC_DRIVER_VERSION "8.1.10"
+
+ #define LPFC_DRIVER_NAME "lpfc"
+
+diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
+index 89ef34d..753d883 100644
+--- a/drivers/scsi/mac53c94.c
++++ b/drivers/scsi/mac53c94.c
+@@ -60,8 +60,8 @@ struct fsc_state {
+
+ static void mac53c94_init(struct fsc_state *);
+ static void mac53c94_start(struct fsc_state *);
+-static void mac53c94_interrupt(int, void *, struct pt_regs *);
+-static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
++static void mac53c94_interrupt(int, void *);
++static irqreturn_t do_mac53c94_interrupt(int, void *);
+ static void cmd_done(struct fsc_state *, int result);
+ static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
+
+@@ -177,18 +177,18 @@ static void mac53c94_start(struct fsc_st
+ set_dma_cmds(state, cmd);
+ }
+
+-static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+- mac53c94_interrupt(irq, dev_id, ptregs);
++ mac53c94_interrupt(irq, dev_id);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+-static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++static void mac53c94_interrupt(int irq, void *dev_id)
+ {
+ struct fsc_state *state = (struct fsc_state *) dev_id;
+ struct mac53c94_regs __iomem *regs = state->regs;
+@@ -431,7 +431,7 @@ static int mac53c94_probe(struct macio_d
+ struct fsc_state *state;
+ struct Scsi_Host *host;
+ void *dma_cmd_space;
+- unsigned char *clkprop;
++ const unsigned char *clkprop;
+ int proplen, rc = -ENODEV;
+
+ if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
+diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
+index 118206d..3586fac 100644
+--- a/drivers/scsi/mac_esp.c
++++ b/drivers/scsi/mac_esp.c
+@@ -44,7 +44,7 @@
+ /* #define DEBUG_MAC_ESP */
+
+ extern void esp_handle(struct NCR_ESP *esp);
+-extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
++extern void mac_esp_intr(int irq, void *dev_id);
+
+ static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
+ static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
+@@ -88,7 +88,7 @@ static int setup_hostid = -1;
+ * set up properly!
+ */
+
+-void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
++void mac_esp_intr(int irq, void *dev_id)
+ {
+ struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
+ int irq_p = 0;
+@@ -122,24 +122,24 @@ void mac_esp_intr(int irq, void *dev_id,
+ * acknowledge on the various machines
+ */
+
+-void scsi_esp_polled(int irq, void *dev_id, struct pt_regs *pregs)
++void scsi_esp_polled(int irq, void *dev_id)
+ {
+ if (esp_initialized == 0)
+ return;
+
+- mac_esp_intr(irq, dev_id, pregs);
++ mac_esp_intr(irq, dev_id);
+ }
+
+-void fake_intr(int irq, void *dev_id, struct pt_regs *pregs)
++void fake_intr(int irq, void *dev_id)
+ {
+ #ifdef DEBUG_MAC_ESP
+ printk("mac_esp: got irq\n");
+ #endif
+
+- mac_esp_intr(irq, dev_id, pregs);
++ mac_esp_intr(irq, dev_id);
+ }
+
+-irqreturn_t fake_drq(int irq, void *dev_id, struct pt_regs *pregs)
++irqreturn_t fake_drq(int irq, void *dev_id)
+ {
+ printk("mac_esp: got drq\n");
+ return IRQ_HANDLED;
+diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
+index 76edbb6..86099fd 100644
+--- a/drivers/scsi/megaraid.c
++++ b/drivers/scsi/megaraid.c
+@@ -1256,14 +1256,13 @@ bug_blocked_mailbox:
+ * megaraid_isr_iomapped()
+ * @irq - irq
+ * @devp - pointer to our soft state
+- * @regs - unused
+ *
+ * Interrupt service routine for io-mapped controllers.
+ * Find out if our device is interrupting. If yes, acknowledge the interrupt
+ * and service the completed commands.
+ */
+ static irqreturn_t
+-megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
++megaraid_isr_iomapped(int irq, void *devp)
+ {
+ adapter_t *adapter = devp;
+ unsigned long flags;
+@@ -1333,14 +1332,13 @@ megaraid_isr_iomapped(int irq, void *dev
+ * megaraid_isr_memmapped()
+ * @irq - irq
+ * @devp - pointer to our soft state
+- * @regs - unused
+ *
+ * Interrupt service routine for memory-mapped controllers.
+ * Find out if our device is interrupting. If yes, acknowledge the interrupt
+ * and service the completed commands.
+ */
+ static irqreturn_t
+-megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
++megaraid_isr_memmapped(int irq, void *devp)
+ {
+ adapter_t *adapter = devp;
+ unsigned long flags;
+@@ -2822,9 +2820,7 @@ mega_print_inquiry(char *page, char *scs
+
+ i = scsi_inq[0] & 0x1f;
+
+- len += sprintf(page+len, " Type: %s ",
+- i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
+- "Unknown ");
++ len += sprintf(page+len, " Type: %s ", scsi_device_type(i));
+
+ len += sprintf(page+len,
+ " ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
+@@ -3658,8 +3654,9 @@ megadev_ioctl(struct inode *inode, struc
+ * Send the request sense data also, irrespective of
+ * whether the user has asked for it or not.
+ */
+- copy_to_user(upthru->reqsensearea,
+- pthru->reqsensearea, 14);
++ if (copy_to_user(upthru->reqsensearea,
++ pthru->reqsensearea, 14))
++ rval = -EFAULT;
+
+ freemem_and_return:
+ if( pthru->dataxferlen ) {
+diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
+index 4b75fe6..66529f1 100644
+--- a/drivers/scsi/megaraid.h
++++ b/drivers/scsi/megaraid.h
+@@ -991,8 +991,8 @@ static scb_t * mega_build_cmd(adapter_t
+ static void __mega_runpendq(adapter_t *);
+ static int issue_scb_block(adapter_t *, u_char *);
+
+-static irqreturn_t megaraid_isr_memmapped(int, void *, struct pt_regs *);
+-static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *);
++static irqreturn_t megaraid_isr_memmapped(int, void *);
++static irqreturn_t megaraid_isr_iomapped(int, void *);
+
+ static void mega_free_scb(adapter_t *, scb_t *);
+
+diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
+index 8cd0bd1..b50e27e 100644
+--- a/drivers/scsi/megaraid/mega_common.h
++++ b/drivers/scsi/megaraid/mega_common.h
+@@ -175,7 +175,7 @@ typedef struct {
+ uint8_t max_lun;
+
+ uint32_t unique_id;
+- uint8_t irq;
++ int irq;
+ uint8_t ito;
+ caddr_t ibuf;
+ dma_addr_t ibuf_dma_h;
+diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
+index cd982c8..7bac86d 100644
+--- a/drivers/scsi/megaraid/megaraid_mbox.c
++++ b/drivers/scsi/megaraid/megaraid_mbox.c
+@@ -120,7 +120,7 @@ static void megaraid_mbox_prepare_pthru(
+ static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
+ struct scsi_cmnd *);
+
+-static irqreturn_t megaraid_isr(int, void *, struct pt_regs *);
++static irqreturn_t megaraid_isr(int, void *);
+
+ static void megaraid_mbox_dpc(unsigned long);
+
+@@ -330,6 +330,21 @@ static struct device_attribute *megaraid
+ NULL,
+ };
+
++/**
++ * megaraid_change_queue_depth - Change the device's queue depth
++ * @sdev: scsi device struct
++ * @qdepth: depth to set
++ *
++ * Return value:
++ * actual depth set
++ **/
++static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
++{
++ if (qdepth > MBOX_MAX_SCSI_CMDS)
++ qdepth = MBOX_MAX_SCSI_CMDS;
++ scsi_adjust_queue_depth(sdev, 0, qdepth);
++ return sdev->queue_depth;
++}
+
+ /*
+ * Scsi host template for megaraid unified driver
+@@ -343,6 +358,7 @@ static struct scsi_host_template megarai
+ .eh_device_reset_handler = megaraid_reset_handler,
+ .eh_bus_reset_handler = megaraid_reset_handler,
+ .eh_host_reset_handler = megaraid_reset_handler,
++ .change_queue_depth = megaraid_change_queue_depth,
+ .use_clustering = ENABLE_CLUSTERING,
+ .sdev_attrs = megaraid_sdev_attrs,
+ .shost_attrs = megaraid_shost_attrs,
+@@ -868,7 +884,7 @@ megaraid_init_mbox(adapter_t *adapter)
+
+ if (((magic64 == HBA_SIGNATURE_64_BIT) &&
+ ((adapter->pdev->subsystem_device !=
+- PCI_SUBSYS_ID_MEGARAID_SATA_150_6) ||
++ PCI_SUBSYS_ID_MEGARAID_SATA_150_6) &&
+ (adapter->pdev->subsystem_device !=
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+@@ -2215,7 +2231,7 @@ megaraid_ack_sequence(adapter_t *adapter
+ * Interrupt service routine for memory-mapped mailbox controllers.
+ */
+ static irqreturn_t
+-megaraid_isr(int irq, void *devp, struct pt_regs *regs)
++megaraid_isr(int irq, void *devp)
+ {
+ adapter_t *adapter = devp;
+ int handled;
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index a8c9627..7e4262f 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -10,7 +10,7 @@
+ * 2 of the License, or (at your option) any later version.
+ *
+ * FILE : megaraid_sas.c
+- * Version : v00.00.03.01
++ * Version : v00.00.03.05
+ *
+ * Authors:
+ * Sreenivas Bagalkote <Sreenivas.Bagalkote at lsil.com>
+@@ -53,31 +53,15 @@ MODULE_DESCRIPTION("LSI Logic MegaRAID S
+ */
+ static struct pci_device_id megasas_pci_table[] = {
+
+- {
+- PCI_VENDOR_ID_LSI_LOGIC,
+- PCI_DEVICE_ID_LSI_SAS1064R, /* xscale IOP */
+- PCI_ANY_ID,
+- PCI_ANY_ID,
+- },
+- {
+- PCI_VENDOR_ID_LSI_LOGIC,
+- PCI_DEVICE_ID_LSI_SAS1078R, /* ppc IOP */
+- PCI_ANY_ID,
+- PCI_ANY_ID,
+- },
+- {
+- PCI_VENDOR_ID_LSI_LOGIC,
+- PCI_DEVICE_ID_LSI_VERDE_ZCR, /* xscale IOP, vega */
+- PCI_ANY_ID,
+- PCI_ANY_ID,
+- },
+- {
+- PCI_VENDOR_ID_DELL,
+- PCI_DEVICE_ID_DELL_PERC5, /* xscale IOP */
+- PCI_ANY_ID,
+- PCI_ANY_ID,
+- },
+- {0} /* Terminating entry */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
++ /* xscale IOP */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
++ /* ppc IOP */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
++ /* xscale IOP, vega */
++ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
++ /* xscale IOP */
++ {}
+ };
+
+ MODULE_DEVICE_TABLE(pci, megasas_pci_table);
+@@ -87,6 +71,8 @@ static struct megasas_mgmt_info megasas_
+ static struct fasync_struct *megasas_async_queue;
+ static DEFINE_MUTEX(megasas_async_queue_mutex);
+
++static u32 megasas_dbg_lvl;
++
+ /**
+ * megasas_get_cmd - Get a command from the free pool
+ * @instance: Adapter soft state
+@@ -151,6 +137,19 @@ megasas_enable_intr_xscale(struct megasa
+ }
+
+ /**
++ * megasas_disable_intr_xscale -Disables interrupt
++ * @regs: MFI register set
++ */
++static inline void
++megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
++{
++ u32 mask = 0x1f;
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
+ * megasas_read_fw_status_reg_xscale - returns the current FW status value
+ * @regs: MFI register set
+ */
+@@ -201,6 +200,7 @@ static struct megasas_instance_template
+
+ .fire_cmd = megasas_fire_cmd_xscale,
+ .enable_intr = megasas_enable_intr_xscale,
++ .disable_intr = megasas_disable_intr_xscale,
+ .clear_intr = megasas_clear_intr_xscale,
+ .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
+ };
+@@ -231,6 +231,19 @@ megasas_enable_intr_ppc(struct megasas_r
+ }
+
+ /**
++ * megasas_disable_intr_ppc - Disable interrupt
++ * @regs: MFI register set
++ */
++static inline void
++megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
++{
++ u32 mask = 0xFFFFFFFF;
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
+ * megasas_read_fw_status_reg_ppc - returns the current FW status value
+ * @regs: MFI register set
+ */
+@@ -281,6 +294,7 @@ static struct megasas_instance_template
+
+ .fire_cmd = megasas_fire_cmd_ppc,
+ .enable_intr = megasas_enable_intr_ppc,
++ .disable_intr = megasas_disable_intr_ppc,
+ .clear_intr = megasas_clear_intr_ppc,
+ .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
+ };
+@@ -291,25 +305,6 @@ static struct megasas_instance_template
+ */
+
+ /**
+- * megasas_disable_intr - Disables interrupts
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_disable_intr(struct megasas_instance *instance)
+-{
+- u32 mask = 0x1f;
+- struct megasas_register_set __iomem *regs = instance->reg_set;
+-
+- if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
+- mask = 0xffffffff;
+-
+- writel(mask, ®s->outbound_intr_mask);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+ * megasas_issue_polled - Issues a polling command
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be issued
+@@ -352,6 +347,7 @@ megasas_issue_polled(struct megasas_inst
+ * @cmd: Command to be issued
+ *
+ * This function waits on an event for the command to be returned from ISR.
++ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
+ * Used to issue ioctl commands.
+ */
+ static int
+@@ -362,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas
+
+ instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+
+- wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
++ wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
++ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
+
+ return 0;
+ }
+@@ -374,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas
+ *
+ * MFI firmware can abort previously issued AEN comamnd (automatic event
+ * notification). The megasas_issue_blocked_abort_cmd() issues such abort
+- * cmd and blocks till it is completed.
++ * cmd and waits for return status.
++ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
+ */
+ static int
+ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
+@@ -408,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct m
+ /*
+ * Wait for this cmd to complete
+ */
+- wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
++ wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
++ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
+
+ megasas_return_cmd(instance, cmd);
+ return 0;
+@@ -511,6 +510,46 @@ megasas_make_sgl64(struct megasas_instan
+ return sge_count;
+ }
+
++ /**
++ * megasas_get_frame_count - Computes the number of frames
++ * @sge_count : number of sg elements
++ *
++ * Returns the number of frames required for numnber of sge's (sge_count)
++ */
++
++u32 megasas_get_frame_count(u8 sge_count)
++{
++ int num_cnt;
++ int sge_bytes;
++ u32 sge_sz;
++ u32 frame_count=0;
++
++ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
++ sizeof(struct megasas_sge32);
++
++ /*
++ * Main frame can contain 2 SGEs for 64-bit SGLs and
++ * 3 SGEs for 32-bit SGLs
++ */
++ if (IS_DMA64)
++ num_cnt = sge_count - 2;
++ else
++ num_cnt = sge_count - 3;
++
++ if(num_cnt>0){
++ sge_bytes = sge_sz * num_cnt;
++
++ frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
++ ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
++ }
++ /* Main frame */
++ frame_count +=1;
++
++ if (frame_count > 7)
++ frame_count = 8;
++ return frame_count;
++}
++
+ /**
+ * megasas_build_dcdb - Prepares a direct cdb (DCDB) command
+ * @instance: Adapter soft state
+@@ -524,8 +563,6 @@ static int
+ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ struct megasas_cmd *cmd)
+ {
+- u32 sge_sz;
+- int sge_bytes;
+ u32 is_logical;
+ u32 device_id;
+ u16 flags = 0;
+@@ -560,9 +597,6 @@ megasas_build_dcdb(struct megasas_instan
+ /*
+ * Construct SGL
+ */
+- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+- sizeof(struct megasas_sge32);
+-
+ if (IS_DMA64) {
+ pthru->flags |= MFI_FRAME_SGL64;
+ pthru->sge_count = megasas_make_sgl64(instance, scp,
+@@ -578,17 +612,11 @@ megasas_build_dcdb(struct megasas_instan
+ pthru->sense_buf_phys_addr_hi = 0;
+ pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
+
+- sge_bytes = sge_sz * pthru->sge_count;
+-
+ /*
+ * Compute the total number of frames this command consumes. FW uses
+ * this number to pull sufficient number of frames from host memory.
+ */
+- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
+-
+- if (cmd->frame_count > 7)
+- cmd->frame_count = 8;
++ cmd->frame_count = megasas_get_frame_count(pthru->sge_count);
+
+ return cmd->frame_count;
+ }
+@@ -605,8 +633,6 @@ static int
+ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ struct megasas_cmd *cmd)
+ {
+- u32 sge_sz;
+- int sge_bytes;
+ u32 device_id;
+ u8 sc = scp->cmnd[0];
+ u16 flags = 0;
+@@ -621,7 +647,7 @@ megasas_build_ldio(struct megasas_instan
+ flags = MFI_FRAME_DIR_READ;
+
+ /*
+- * Preare the Logical IO frame: 2nd bit is zero for all read cmds
++ * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
+ */
+ ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
+ ldio->cmd_status = 0x0;
+@@ -690,9 +716,6 @@ megasas_build_ldio(struct megasas_instan
+ /*
+ * Construct SGL
+ */
+- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+- sizeof(struct megasas_sge32);
+-
+ if (IS_DMA64) {
+ ldio->flags |= MFI_FRAME_SGL64;
+ ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
+@@ -706,13 +729,11 @@ megasas_build_ldio(struct megasas_instan
+ ldio->sense_buf_phys_addr_hi = 0;
+ ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
+
+- sge_bytes = sge_sz * ldio->sge_count;
+-
+- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
+-
+- if (cmd->frame_count > 7)
+- cmd->frame_count = 8;
++ /*
++ * Compute the total number of frames this command consumes. FW uses
++ * this number to pull sufficient number of frames from host memory.
++ */
++ cmd->frame_count = megasas_get_frame_count(ldio->sge_count);
+
+ return cmd->frame_count;
+ }
+@@ -743,6 +764,69 @@ static inline int megasas_is_ldio(struct
+ }
+ }
+
++ /**
++ * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
++ * in FW
++ * @instance: Adapter soft state
++ */
++static inline void
++megasas_dump_pending_frames(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ int i,n;
++ union megasas_sgl *mfi_sgl;
++ struct megasas_io_frame *ldio;
++ struct megasas_pthru_frame *pthru;
++ u32 sgcount;
++ u32 max_cmd = instance->max_fw_cmds;
++
++ printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
++ printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
++ if (IS_DMA64)
++ printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
++ else
++ printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
++
++ printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
++ for (i = 0; i < max_cmd; i++) {
++ cmd = instance->cmd_list[i];
++ if(!cmd->scmd)
++ continue;
++ printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
++ if (megasas_is_ldio(cmd->scmd)){
++ ldio = (struct megasas_io_frame *)cmd->frame;
++ mfi_sgl = &ldio->sgl;
++ sgcount = ldio->sge_count;
++ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
++ }
++ else {
++ pthru = (struct megasas_pthru_frame *) cmd->frame;
++ mfi_sgl = &pthru->sgl;
++ sgcount = pthru->sge_count;
++ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
++ }
++ if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
++ for (n = 0; n < sgcount; n++){
++ if (IS_DMA64)
++ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
++ else
++ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
++ }
++ }
++ printk(KERN_ERR "\n");
++ } /*for max_cmd*/
++ printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
++ for (i = 0; i < max_cmd; i++) {
++
++ cmd = instance->cmd_list[i];
++
++ if(cmd->sync_cmd == 1){
++ printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
++ }
++ }
++ printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
++}
++
+ /**
+ * megasas_queue_command - Queue entry point
+ * @scmd: SCSI command to be queued
+@@ -848,6 +932,13 @@ static int megasas_wait_for_outstanding(
+ }
+
+ if (atomic_read(&instance->fw_outstanding)) {
++ /*
++ * Send signal to FW to stop processing any pending cmds.
++ * The controller will be taken offline by the OS now.
++ */
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->inbound_doorbell);
++ megasas_dump_pending_frames(instance);
+ instance->hw_crit_error = 1;
+ return FAILED;
+ }
+@@ -1184,11 +1275,6 @@ megasas_complete_cmd(struct megasas_inst
+ static int
+ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
+ {
+- u32 producer;
+- u32 consumer;
+- u32 context;
+- struct megasas_cmd *cmd;
+-
+ /*
+ * Check if it is our interrupt
+ * Clear the interrupt
+@@ -1196,23 +1282,10 @@ megasas_deplete_reply_queue(struct megas
+ if(instance->instancet->clear_intr(instance->reg_set))
+ return IRQ_NONE;
+
+- producer = *instance->producer;
+- consumer = *instance->consumer;
+-
+- while (consumer != producer) {
+- context = instance->reply_queue[consumer];
+-
+- cmd = instance->cmd_list[context];
+-
+- megasas_complete_cmd(instance, cmd, alt_status);
+-
+- consumer++;
+- if (consumer == (instance->max_fw_cmds + 1)) {
+- consumer = 0;
+- }
+- }
+-
+- *instance->consumer = producer;
++ /*
++ * Schedule the tasklet for cmd completion
++ */
++ tasklet_schedule(&instance->isr_tasklet);
+
+ return IRQ_HANDLED;
+ }
+@@ -1220,7 +1293,7 @@ megasas_deplete_reply_queue(struct megas
+ /**
+ * megasas_isr - isr entry point
+ */
+-static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
++static irqreturn_t megasas_isr(int irq, void *devp)
+ {
+ return megasas_deplete_reply_queue((struct megasas_instance *)devp,
+ DID_OK);
+@@ -1245,10 +1318,12 @@ megasas_transition_to_ready(struct megas
+
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
++ if (fw_state != MFI_STATE_READY)
++ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
++ " state\n");
++
+ while (fw_state != MFI_STATE_READY) {
+
+- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+- " state\n");
+ switch (fw_state) {
+
+ case MFI_STATE_FAULT:
+@@ -1260,19 +1335,27 @@ megasas_transition_to_ready(struct megas
+ /*
+ * Set the CLR bit in inbound doorbell
+ */
+- writel(MFI_INIT_CLEAR_HANDSHAKE,
++ writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+
+ max_wait = 2;
+ cur_state = MFI_STATE_WAIT_HANDSHAKE;
+ break;
+
++ case MFI_STATE_BOOT_MESSAGE_PENDING:
++ writel(MFI_INIT_HOTPLUG,
++ &instance->reg_set->inbound_doorbell);
++
++ max_wait = 10;
++ cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
++ break;
++
+ case MFI_STATE_OPERATIONAL:
+ /*
+- * Bring it to READY state; assuming max wait 2 secs
++ * Bring it to READY state; assuming max wait 10 secs
+ */
+- megasas_disable_intr(instance);
+- writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
++ instance->instancet->disable_intr(instance->reg_set);
++ writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
+
+ max_wait = 10;
+ cur_state = MFI_STATE_OPERATIONAL;
+@@ -1339,6 +1422,7 @@ megasas_transition_to_ready(struct megas
+ return -ENODEV;
+ }
+ };
++ printk(KERN_INFO "megasas: FW now in Ready state\n");
+
+ return 0;
+ }
+@@ -1368,7 +1452,7 @@ static void megasas_teardown_frame_pool(
+ cmd->frame_phys_addr);
+
+ if (cmd->sense)
+- pci_pool_free(instance->sense_dma_pool, cmd->frame,
++ pci_pool_free(instance->sense_dma_pool, cmd->sense,
+ cmd->sense_phys_addr);
+ }
+
+@@ -1644,6 +1728,39 @@ megasas_get_ctrl_info(struct megasas_ins
+ }
+
+ /**
++ * megasas_complete_cmd_dpc - Returns FW's controller structure
++ * @instance_addr: Address of adapter soft state
++ *
++ * Tasklet to complete cmds
++ */
++void megasas_complete_cmd_dpc(unsigned long instance_addr)
++{
++ u32 producer;
++ u32 consumer;
++ u32 context;
++ struct megasas_cmd *cmd;
++ struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
++
++ producer = *instance->producer;
++ consumer = *instance->consumer;
++
++ while (consumer != producer) {
++ context = instance->reply_queue[consumer];
++
++ cmd = instance->cmd_list[context];
++
++ megasas_complete_cmd(instance, cmd, DID_OK);
++
++ consumer++;
++ if (consumer == (instance->max_fw_cmds + 1)) {
++ consumer = 0;
++ }
++ }
++
++ *instance->consumer = producer;
++}
++
++/**
+ * megasas_init_mfi - Initializes the FW
+ * @instance: Adapter soft state
+ *
+@@ -1706,6 +1823,12 @@ static int megasas_init_mfi(struct megas
+ * Get various operational parameters from status register
+ */
+ instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
++ /*
++ * Reduce the max supported cmds by 1. This is to ensure that the
++ * reply_q_sz (1 more than the max cmd that driver may send)
++ * does not exceed max cmds that the FW can support
++ */
++ instance->max_fw_cmds = instance->max_fw_cmds-1;
+ instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
+ 0x10;
+ /*
+@@ -1770,7 +1893,7 @@ static int megasas_init_mfi(struct megas
+ /*
+ * disable the intr before firing the init frame to FW
+ */
+- megasas_disable_intr(instance);
++ instance->instancet->disable_intr(instance->reg_set);
+
+ /*
+ * Issue the init frame in polled mode
+@@ -1807,6 +1930,12 @@ static int megasas_init_mfi(struct megas
+
+ kfree(ctrl_info);
+
++ /*
++ * Setup tasklet for cmd completion
++ */
++
++ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
++ (unsigned long)instance);
+ return 0;
+
+ fail_fw_init:
+@@ -2198,6 +2327,8 @@ megasas_probe_one(struct pci_dev *pdev,
+ instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
+ instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+
++ megasas_dbg_lvl = 0;
++
+ /*
+ * Initialize MFI Firmware
+ */
+@@ -2250,7 +2381,7 @@ megasas_probe_one(struct pci_dev *pdev,
+ megasas_mgmt_info.max_index--;
+
+ pci_set_drvdata(pdev, NULL);
+- megasas_disable_intr(instance);
++ instance->instancet->disable_intr(instance->reg_set);
+ free_irq(instance->pdev->irq, instance);
+
+ megasas_release_mfi(instance);
+@@ -2364,6 +2495,7 @@ static void megasas_detach_one(struct pc
+ scsi_remove_host(instance->host);
+ megasas_flush_cache(instance);
+ megasas_shutdown_controller(instance);
++ tasklet_kill(&instance->isr_tasklet);
+
+ /*
+ * Take the instance off the instance array. Note that we will not
+@@ -2380,7 +2512,7 @@ static void megasas_detach_one(struct pc
+
+ pci_set_drvdata(instance->pdev, NULL);
+
+- megasas_disable_intr(instance);
++ instance->instancet->disable_intr(instance->reg_set);
+
+ free_irq(instance->pdev->irq, instance);
+
+@@ -2732,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(
+ int i;
+ int error = 0;
+
+- clear_user(ioc, sizeof(*ioc));
++ if (clear_user(ioc, sizeof(*ioc)))
++ return -EFAULT;
+
+ if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
+ copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
+@@ -2824,6 +2957,26 @@ megasas_sysfs_show_release_date(struct d
+ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
+ NULL);
+
++static ssize_t
++megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
++{
++ return sprintf(buf,"%u",megasas_dbg_lvl);
++}
++
++static ssize_t
++megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
++{
++ int retval = count;
++ if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
++ printk(KERN_ERR "megasas: could not set dbg_lvl\n");
++ retval = -EINVAL;
++ }
++ return retval;
++}
++
++static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
++ megasas_sysfs_set_dbg_lvl);
++
+ /**
+ * megasas_init - Driver load entry point
+ */
+@@ -2854,18 +3007,37 @@ static int __init megasas_init(void)
+ /*
+ * Register ourselves as PCI hotplug module
+ */
+- rval = pci_module_init(&megasas_pci_driver);
++ rval = pci_register_driver(&megasas_pci_driver);
+
+ if (rval) {
+ printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
+- unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+- }
+-
+- driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
+- driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_release_date);
++ goto err_pcidrv;
++ }
++
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_version);
++ if (rval)
++ goto err_dcf_attr_ver;
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_release_date);
++ if (rval)
++ goto err_dcf_rel_date;
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_dbg_lvl);
++ if (rval)
++ goto err_dcf_dbg_lvl;
+
+ return rval;
++err_dcf_dbg_lvl:
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_release_date);
++err_dcf_rel_date:
++ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
++err_dcf_attr_ver:
++ pci_unregister_driver(&megasas_pci_driver);
++err_pcidrv:
++ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
++ return rval;
+ }
+
+ /**
+@@ -2873,9 +3045,11 @@ static int __init megasas_init(void)
+ */
+ static void __exit megasas_exit(void)
+ {
+- driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_dbg_lvl);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
++ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+
+ pci_unregister_driver(&megasas_pci_driver);
+ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 3531a14..55eddcf 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -18,9 +18,9 @@
+ /**
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.03.01"
+-#define MEGASAS_RELDATE "May 14, 2006"
+-#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006"
++#define MEGASAS_VERSION "00.00.03.05"
++#define MEGASAS_RELDATE "Oct 02, 2006"
++#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006"
+
+ /*
+ * Device IDs
+@@ -50,6 +50,7 @@
+ #define MFI_STATE_WAIT_HANDSHAKE 0x60000000
+ #define MFI_STATE_FW_INIT_2 0x70000000
+ #define MFI_STATE_DEVICE_SCAN 0x80000000
++#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000
+ #define MFI_STATE_FLUSH_CACHE 0xA0000000
+ #define MFI_STATE_READY 0xB0000000
+ #define MFI_STATE_OPERATIONAL 0xC0000000
+@@ -64,12 +65,18 @@
+ * READY : Move from OPERATIONAL to READY state; discard queue info
+ * MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??)
+ * CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver
++ * HOTPLUG : Resume from Hotplug
++ * MFI_STOP_ADP : Send signal to FW to stop processing
+ */
+-#define MFI_INIT_ABORT 0x00000000
++#define MFI_INIT_ABORT 0x00000001
+ #define MFI_INIT_READY 0x00000002
+ #define MFI_INIT_MFIMODE 0x00000004
+ #define MFI_INIT_CLEAR_HANDSHAKE 0x00000008
+-#define MFI_RESET_FLAGS MFI_INIT_READY|MFI_INIT_MFIMODE
++#define MFI_INIT_HOTPLUG 0x00000010
++#define MFI_STOP_ADP 0x00000020
++#define MFI_RESET_FLAGS MFI_INIT_READY| \
++ MFI_INIT_MFIMODE| \
++ MFI_INIT_ABORT
+
+ /**
+ * MFI frame flags
+@@ -530,6 +537,8 @@ struct megasas_ctrl_info {
+ #define MEGASAS_MAX_LUN 8
+ #define MEGASAS_MAX_LD 64
+
++#define MEGASAS_DBG_LVL 1
++
+ /*
+ * When SCSI mid-layer calls driver's reset routine, driver waits for
+ * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
+@@ -538,6 +547,7 @@ struct megasas_ctrl_info {
+ * every MEGASAS_RESET_NOTICE_INTERVAL seconds
+ */
+ #define MEGASAS_RESET_WAIT_TIME 180
++#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180
+ #define MEGASAS_RESET_NOTICE_INTERVAL 5
+
+ #define MEGASAS_IOCTL_CMD 0
+@@ -1042,6 +1052,7 @@ struct megasas_evt_detail {
+ void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
+
+ void (*enable_intr)(struct megasas_register_set __iomem *) ;
++ void (*disable_intr)(struct megasas_register_set __iomem *);
+
+ int (*clear_intr)(struct megasas_register_set __iomem *);
+
+@@ -1092,6 +1103,7 @@ struct megasas_instance {
+ u32 hw_crit_error;
+
+ struct megasas_instance_template *instancet;
++ struct tasklet_struct isr_tasklet;
+ };
+
+ #define MEGASAS_IS_LOGICAL(scp) \
+diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
+index 5572981..1fd3c75 100644
+--- a/drivers/scsi/mesh.c
++++ b/drivers/scsi/mesh.c
+@@ -185,7 +185,7 @@ struct mesh_state {
+ * Driver is too messy, we need a few prototypes...
+ */
+ static void mesh_done(struct mesh_state *ms, int start_next);
+-static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
++static void mesh_interrupt(int irq, void *dev_id);
+ static void cmd_complete(struct mesh_state *ms);
+ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
+ static void halt_dma(struct mesh_state *ms);
+@@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_s
+ dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
+ MKWORD(mr->interrupt, mr->exception,
+ mr->error, mr->fifo_count));
+- mesh_interrupt(0, (void *)ms, NULL);
++ mesh_interrupt(0, (void *)ms);
+ if (ms->phase != arbitrating)
+ return;
+ }
+@@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_s
+ dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
+ MKWORD(mr->interrupt, mr->exception,
+ mr->error, mr->fifo_count));
+- mesh_interrupt(0, (void *)ms, NULL);
++ mesh_interrupt(0, (void *)ms);
+ if (ms->phase != arbitrating)
+ return;
+ dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
+@@ -1015,13 +1015,13 @@ static void handle_reset(struct mesh_sta
+ out_8(&mr->sequence, SEQ_ENBRESEL);
+ }
+
+-static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+- mesh_interrupt(irq, dev_id, ptregs);
++ mesh_interrupt(irq, dev_id);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+@@ -1661,7 +1661,7 @@ static int mesh_queue(struct scsi_cmnd *
+ * handler (do_mesh_interrupt) or by other functions in
+ * exceptional circumstances
+ */
+-static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++static void mesh_interrupt(int irq, void *dev_id)
+ {
+ struct mesh_state *ms = (struct mesh_state *) dev_id;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
+@@ -1756,16 +1756,23 @@ static void set_mesh_power(struct mesh_s
+ pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
+ msleep(10);
+ }
+-}
++}
+
+
+ #ifdef CONFIG_PM
+-static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
++static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg)
+ {
+ struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+ unsigned long flags;
+
+- if (state.event == mdev->ofdev.dev.power.power_state.event || state.event < 2)
++ switch (mesg.event) {
++ case PM_EVENT_SUSPEND:
++ case PM_EVENT_FREEZE:
++ break;
++ default:
++ return 0;
++ }
++ if (mesg.event == mdev->ofdev.dev.power.power_state.event)
+ return 0;
+
+ scsi_block_requests(ms->host);
+@@ -1780,7 +1787,7 @@ static int mesh_suspend(struct macio_dev
+ disable_irq(ms->meshintr);
+ set_mesh_power(ms, 0);
+
+- mdev->ofdev.dev.power.power_state = state;
++ mdev->ofdev.dev.power.power_state = mesg;
+
+ return 0;
+ }
+@@ -1850,7 +1857,8 @@ static int mesh_probe(struct macio_dev *
+ {
+ struct device_node *mesh = macio_get_of_node(mdev);
+ struct pci_dev* pdev = macio_get_pci_dev(mdev);
+- int tgt, *cfp, minper;
++ int tgt, minper;
++ const int *cfp;
+ struct mesh_state *ms;
+ struct Scsi_Host *mesh_host;
+ void *dma_cmd_space;
+@@ -1939,7 +1947,7 @@ static int mesh_probe(struct macio_dev *
+ ms->tgts[tgt].current_req = NULL;
+ }
+
+- if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
++ if ((cfp = get_property(mesh, "clock-frequency", NULL)))
+ ms->clk_freq = *cfp;
+ else {
+ printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
+diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
+index cb367c2..1ddd7a1 100644
+--- a/drivers/scsi/mvme147.c
++++ b/drivers/scsi/mvme147.c
+@@ -20,7 +20,7 @@
+
+ static struct Scsi_Host *mvme147_host = NULL;
+
+-static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t mvme147_intr (int irq, void *dummy)
+ {
+ if (irq == MVME147_IRQ_SCSI_PORT)
+ wd33c93_intr (mvme147_host);
+@@ -29,7 +29,7 @@ static irqreturn_t mvme147_intr (int irq
+ return IRQ_HANDLED;
+ }
+
+-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
++static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
+ {
+ unsigned char flags = 0x01;
+ unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+@@ -57,7 +57,7 @@ static int dma_setup (Scsi_Cmnd *cmd, in
+ return 0;
+ }
+
+-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
++static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
+ {
+ m147_pcc->dma_cntrl = 0;
+@@ -112,7 +112,7 @@ int mvme147_detect(struct scsi_host_temp
+ return 0;
+ }
+
+-static int mvme147_bus_reset(Scsi_Cmnd *cmd)
++static int mvme147_bus_reset(struct scsi_cmnd *cmd)
+ {
+ /* FIXME perform bus-specific reset */
+
+diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h
+index 2f56d69..32aee85 100644
+--- a/drivers/scsi/mvme147.h
++++ b/drivers/scsi/mvme147.h
+@@ -12,10 +12,6 @@
+
+ int mvme147_detect(struct scsi_host_template *);
+ int mvme147_release(struct Scsi_Host *);
+-const char *wd33c93_info(void);
+-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int wd33c93_abort(Scsi_Cmnd *);
+-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 2
+diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
+index c7a1253..73e33b3 100644
+--- a/drivers/scsi/mvme16x.h
++++ b/drivers/scsi/mvme16x.h
+@@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *,
+ int NCR53c7xx_abort(Scsi_Cmnd *);
+ int NCR53c7x0_release (struct Scsi_Host *);
+ int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
++void NCR53c7x0_intr(int irq, void *dev_id);
+
+ #ifndef CMD_PER_LUN
+ #define CMD_PER_LUN 3
+diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
+index b28712d..6cc2bc2 100644
+--- a/drivers/scsi/ncr53c8xx.c
++++ b/drivers/scsi/ncr53c8xx.c
+@@ -8111,7 +8111,7 @@ printk("ncr53c8xx : command successfully
+ return sts;
+ }
+
+-irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
++irqreturn_t ncr53c8xx_intr(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *shost = (struct Scsi_Host *)dev_id;
+diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
+index 78818b6..cb8b770 100644
+--- a/drivers/scsi/ncr53c8xx.h
++++ b/drivers/scsi/ncr53c8xx.h
+@@ -1322,7 +1322,7 @@ struct ncr_device {
+
+ extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
+ extern int ncr53c8xx_release(struct Scsi_Host *host);
+-irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
++irqreturn_t ncr53c8xx_intr(int irq, void *dev_id);
+ extern int ncr53c8xx_init(void);
+ extern void ncr53c8xx_exit(void);
+
+diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
+index bfb4f49..7c13f6f 100644
+--- a/drivers/scsi/nsp32.c
++++ b/drivers/scsi/nsp32.c
+@@ -256,7 +256,7 @@ static void nsp32_sack_negate (nsp32_hw_
+ static void nsp32_do_bus_reset(nsp32_hw_data *);
+
+ /* hardware interrupt handler */
+-static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *);
++static irqreturn_t do_nsp32_isr(int, void *);
+
+ /* initialize hardware */
+ static int nsp32hw_init(nsp32_hw_data *);
+@@ -1201,7 +1201,7 @@ static int nsp32hw_init(nsp32_hw_data *d
+
+
+ /* interrupt routine */
+-static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
+ {
+ nsp32_hw_data *data = dev_id;
+ unsigned int base = data->BaseAddress;
+@@ -3581,7 +3581,7 @@ static struct pci_driver nsp32_driver =
+ */
+ static int __init init_nsp32(void) {
+ nsp32_msg(KERN_INFO, "loading...");
+- return pci_module_init(&nsp32_driver);
++ return pci_register_driver(&nsp32_driver);
+ }
+
+ static void __exit exit_nsp32(void) {
+diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
+index 5addf9f..a976e81 100644
+--- a/drivers/scsi/nsp32.h
++++ b/drivers/scsi/nsp32.h
+@@ -619,47 +619,5 @@ typedef struct _nsp32_hw_data {
+ #define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion
+ or negation, 10000us == 10ms */
+
+-/**************************************************************************
+- * Compatibility functions
+- */
+-
+-/* for Kernel 2.4 */
+-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+-# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template)
+-# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
+-# define scsi_host_put(host) scsi_unregister(host)
+-# define pci_name(pci_dev) ((pci_dev)->slot_name)
+-
+-typedef void irqreturn_t;
+-# define IRQ_NONE /* */
+-# define IRQ_HANDLED /* */
+-# define IRQ_RETVAL(x) /* */
+-
+-/* This is ad-hoc version of scsi_host_get_next() */
+-static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
+-{
+- if (host == NULL) {
+- return scsi_hostlist;
+- } else {
+- return host->next;
+- }
+-}
+-
+-/* This is ad-hoc version of scsi_host_hn_get() */
+-static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
+-{
+- struct Scsi_Host *host;
+-
+- for (host = scsi_host_get_next(NULL); host != NULL;
+- host = scsi_host_get_next(host)) {
+- if (host->host_no == hostno) {
+- break;
+- }
+- }
+-
+- return host;
+-}
+-#endif
+-
+ #endif /* _NSP32_H */
+ /* end */
+diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
+index 4a2fed3..824fe08 100644
+--- a/drivers/scsi/osst.c
++++ b/drivers/scsi/osst.c
+@@ -4843,8 +4843,7 @@ static int os_scsi_tape_close(struct ino
+ static int osst_ioctl(struct inode * inode,struct file * file,
+ unsigned int cmd_in, unsigned long arg)
+ {
+- int i, cmd_nr, cmd_type, retval = 0;
+- unsigned int blk;
++ int i, cmd_nr, cmd_type, blk, retval = 0;
+ struct st_modedef * STm;
+ struct st_partstat * STps;
+ struct osst_request * SRpnt = NULL;
+@@ -5207,12 +5206,12 @@ static struct osst_buffer * new_tape_buf
+ priority = GFP_KERNEL;
+
+ i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
+- tb = (struct osst_buffer *)kmalloc(i, priority);
++ tb = kzalloc(i, priority);
+ if (!tb) {
+ printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
+ return NULL;
+ }
+- memset(tb, 0, i);
++
+ tb->sg_segs = tb->orig_sg_segs = 0;
+ tb->use_sg = max_sg;
+ tb->in_use = 1;
+@@ -5575,9 +5574,9 @@ static ssize_t osst_version_show(struct
+
+ static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
+
+-static void osst_create_driverfs_files(struct device_driver *driverfs)
++static int osst_create_driverfs_files(struct device_driver *driverfs)
+ {
+- driver_create_file(driverfs, &driver_attr_version);
++ return driver_create_file(driverfs, &driver_attr_version);
+ }
+
+ static void osst_remove_driverfs_files(struct device_driver *driverfs)
+@@ -5663,50 +5662,70 @@ CLASS_DEVICE_ATTR(file_count, S_IRUGO, o
+
+ static struct class *osst_sysfs_class;
+
+-static int osst_sysfs_valid = 0;
+-
+-static void osst_sysfs_init(void)
++static int osst_sysfs_init(void)
+ {
+ osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
+- if ( IS_ERR(osst_sysfs_class) )
+- printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
+- else
+- osst_sysfs_valid = 1;
++ if (IS_ERR(osst_sysfs_class)) {
++ printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
++ return PTR_ERR(osst_sysfs_class);
++ }
++
++ return 0;
+ }
+
+-static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
++static void osst_sysfs_destroy(dev_t dev)
+ {
+- struct class_device *osst_class_member;
++ class_device_destroy(osst_sysfs_class, dev);
++}
+
+- if (!osst_sysfs_valid) return;
++static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
++{
++ struct class_device *osst_class_member;
++ int err;
+
+- osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name);
++ osst_class_member = class_device_create(osst_sysfs_class, NULL, dev,
++ device, "%s", name);
+ if (IS_ERR(osst_class_member)) {
+ printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
+- return;
++ return PTR_ERR(osst_class_member);
+ }
++
+ class_set_devdata(osst_class_member, STp);
+- class_device_create_file(osst_class_member, &class_device_attr_ADR_rev);
+- class_device_create_file(osst_class_member, &class_device_attr_media_version);
+- class_device_create_file(osst_class_member, &class_device_attr_capacity);
+- class_device_create_file(osst_class_member, &class_device_attr_BOT_frame);
+- class_device_create_file(osst_class_member, &class_device_attr_EOD_frame);
+- class_device_create_file(osst_class_member, &class_device_attr_file_count);
+-}
++ err = class_device_create_file(osst_class_member,
++ &class_device_attr_ADR_rev);
++ if (err)
++ goto err_out;
++ err = class_device_create_file(osst_class_member,
++ &class_device_attr_media_version);
++ if (err)
++ goto err_out;
++ err = class_device_create_file(osst_class_member,
++ &class_device_attr_capacity);
++ if (err)
++ goto err_out;
++ err = class_device_create_file(osst_class_member,
++ &class_device_attr_BOT_frame);
++ if (err)
++ goto err_out;
++ err = class_device_create_file(osst_class_member,
++ &class_device_attr_EOD_frame);
++ if (err)
++ goto err_out;
++ err = class_device_create_file(osst_class_member,
++ &class_device_attr_file_count);
++ if (err)
++ goto err_out;
+
+-static void osst_sysfs_destroy(dev_t dev)
+-{
+- if (!osst_sysfs_valid) return;
++ return 0;
+
+- class_device_destroy(osst_sysfs_class, dev);
++err_out:
++ osst_sysfs_destroy(dev);
++ return err;
+ }
+
+ static void osst_sysfs_cleanup(void)
+ {
+- if (osst_sysfs_valid) {
+- class_destroy(osst_sysfs_class);
+- osst_sysfs_valid = 0;
+- }
++ class_destroy(osst_sysfs_class);
+ }
+
+ /*
+@@ -5721,7 +5740,7 @@ static int osst_probe(struct device *dev
+ struct st_partstat * STps;
+ struct osst_buffer * buffer;
+ struct gendisk * drive;
+- int i, dev_num;
++ int i, dev_num, err = -ENODEV;
+
+ if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
+ return -ENODEV;
+@@ -5849,13 +5868,20 @@ static int osst_probe(struct device *dev
+ init_MUTEX(&tpnt->lock);
+ osst_nr_dev++;
+ write_unlock(&os_scsi_tapes_lock);
++
+ {
+ char name[8];
++
+ /* Rewind entry */
+- osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
++ err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
++ if (err)
++ goto out_free_buffer;
++
+ /* No-rewind entry */
+ snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
+- osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
++ err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
++ if (err)
++ goto out_free_sysfs1;
+ }
+
+ sdev_printk(KERN_INFO, SDp,
+@@ -5864,9 +5890,13 @@ static int osst_probe(struct device *dev
+
+ return 0;
+
++out_free_sysfs1:
++ osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
++out_free_buffer:
++ kfree(buffer);
+ out_put_disk:
+ put_disk(drive);
+- return -ENODEV;
++ return err;
+ };
+
+ static int osst_remove(struct device *dev)
+@@ -5903,19 +5933,39 @@ static int osst_remove(struct device *de
+
+ static int __init init_osst(void)
+ {
++ int err;
++
+ printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
+
+ validate_options();
+- osst_sysfs_init();
+
+- if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
++ err = osst_sysfs_init();
++ if (err)
++ return err;
++
++ err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
++ if (err < 0) {
+ printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
+- osst_sysfs_cleanup();
+- return 1;
++ goto err_out;
+ }
+- osst_create_driverfs_files(&osst_template.gendrv);
++
++ err = scsi_register_driver(&osst_template.gendrv);
++ if (err)
++ goto err_out_chrdev;
++
++ err = osst_create_driverfs_files(&osst_template.gendrv);
++ if (err)
++ goto err_out_scsidrv;
+
+ return 0;
++
++err_out_scsidrv:
++ scsi_unregister_driver(&osst_template.gendrv);
++err_out_chrdev:
++ unregister_chrdev(OSST_MAJOR, "osst");
++err_out:
++ osst_sysfs_cleanup();
++ return err;
+ }
+
+ static void __exit exit_osst (void)
+diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
+index 0d4c04e..f2d79c3 100644
+--- a/drivers/scsi/pcmcia/nsp_cs.c
++++ b/drivers/scsi/pcmcia/nsp_cs.c
+@@ -80,7 +80,6 @@ static int free_ports = 0;
+ module_param(free_ports, bool, 0);
+ MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
+
+-/* /usr/src/linux/drivers/scsi/hosts.h */
+ static struct scsi_host_template nsp_driver_template = {
+ .proc_name = "nsp_cs",
+ .proc_info = nsp_proc_info,
+@@ -184,7 +183,7 @@ static void nsp_cs_dmessage(const char *
+ * Clenaup parameters and call done() functions.
+ * You must be set SCpnt->result before call this function.
+ */
+-static void nsp_scsi_done(Scsi_Cmnd *SCpnt)
++static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
+ {
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+@@ -193,7 +192,8 @@ static void nsp_scsi_done(Scsi_Cmnd *SCp
+ SCpnt->scsi_done(SCpnt);
+ }
+
+-static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
++ void (*done)(struct scsi_cmnd *))
+ {
+ #ifdef NSP_DEBUG
+ /*unsigned int host_id = SCpnt->device->host->this_id;*/
+@@ -366,7 +366,7 @@ static int nsphw_init(nsp_hw_data *data)
+ /*
+ * Start selection phase
+ */
+-static int nsphw_start_selection(Scsi_Cmnd *SCpnt)
++static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int host_id = SCpnt->device->host->this_id;
+ unsigned int base = SCpnt->device->host->io_port;
+@@ -447,7 +447,7 @@ static struct nsp_sync_table nsp_sync_ta
+ /*
+ * setup synchronous data transfer mode
+ */
+-static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt)
++static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
+ {
+ unsigned char target = scmd_id(SCpnt);
+ // unsigned char lun = SCpnt->device->lun;
+@@ -505,7 +505,7 @@ static int nsp_analyze_sdtr(Scsi_Cmnd *S
+ /*
+ * start ninja hardware timer
+ */
+-static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
++static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+@@ -518,7 +518,8 @@ static void nsp_start_timer(Scsi_Cmnd *S
+ /*
+ * wait for bus phase change
+ */
+-static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str)
++static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
++ char *str)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned char reg;
+@@ -545,9 +546,9 @@ static int nsp_negate_signal(Scsi_Cmnd *
+ /*
+ * expect Ninja Irq
+ */
+-static int nsp_expect_signal(Scsi_Cmnd *SCpnt,
+- unsigned char current_phase,
+- unsigned char mask)
++static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
++ unsigned char current_phase,
++ unsigned char mask)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ int time_out;
+@@ -580,7 +581,7 @@ static int nsp_expect_signal(Scsi_Cmnd
+ /*
+ * transfer SCSI message
+ */
+-static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
++static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+@@ -620,7 +621,7 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, in
+ /*
+ * get extra SCSI data from fifo
+ */
+-static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
++static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
+ {
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ unsigned int count;
+@@ -652,7 +653,7 @@ static int nsp_dataphase_bypass(Scsi_Cmn
+ /*
+ * accept reselection
+ */
+-static int nsp_reselected(Scsi_Cmnd *SCpnt)
++static int nsp_reselected(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned int host_id = SCpnt->device->host->this_id;
+@@ -691,7 +692,7 @@ static int nsp_reselected(Scsi_Cmnd *SCp
+ /*
+ * count how many data transferd
+ */
+-static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
++static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned int count;
+@@ -718,7 +719,7 @@ static int nsp_fifo_count(Scsi_Cmnd *SCp
+ /*
+ * read data in DATA IN phase
+ */
+-static void nsp_pio_read(Scsi_Cmnd *SCpnt)
++static void nsp_pio_read(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned long mmio_base = SCpnt->device->host->base;
+@@ -813,7 +814,7 @@ static void nsp_pio_read(Scsi_Cmnd *SCpn
+ /*
+ * write data in DATA OUT phase
+ */
+-static void nsp_pio_write(Scsi_Cmnd *SCpnt)
++static void nsp_pio_write(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned long mmio_base = SCpnt->device->host->base;
+@@ -906,7 +907,7 @@ static void nsp_pio_write(Scsi_Cmnd *SCp
+ /*
+ * setup synchronous/asynchronous data transfer mode
+ */
+-static int nsp_nexus(Scsi_Cmnd *SCpnt)
++static int nsp_nexus(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned char target = scmd_id(SCpnt);
+@@ -949,11 +950,11 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt)
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t nspintr(int irq, void *dev_id)
+ {
+ unsigned int base;
+ unsigned char irq_status, irq_phase, phase;
+- Scsi_Cmnd *tmpSC;
++ struct scsi_cmnd *tmpSC;
+ unsigned char target, lun;
+ unsigned int *sync_neg;
+ int i, tmp;
+@@ -1531,7 +1532,7 @@ nsp_proc_info(
+ /*---------------------------------------------------------------*/
+
+ /*
+-static int nsp_eh_abort(Scsi_Cmnd *SCpnt)
++static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
+ {
+ nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
+
+@@ -1559,7 +1560,7 @@ static int nsp_bus_reset(nsp_hw_data *da
+ return SUCCESS;
+ }
+
+-static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
++static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
+ {
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+@@ -1568,7 +1569,7 @@ static int nsp_eh_bus_reset(Scsi_Cmnd *S
+ return nsp_bus_reset(data);
+ }
+
+-static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt)
++static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
+ {
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
+index 8908b8e..625ca97 100644
+--- a/drivers/scsi/pcmcia/nsp_cs.h
++++ b/drivers/scsi/pcmcia/nsp_cs.h
+@@ -266,7 +266,7 @@ typedef struct _nsp_hw_data {
+
+ int TimerCount;
+ int SelectionTimeOut;
+- Scsi_Cmnd *CurrentSC;
++ struct scsi_cmnd *CurrentSC;
+ //int CurrnetTarget;
+
+ int FifoCount;
+@@ -319,34 +319,38 @@ static int nsp_proc_info
+ int hostno,
+ #endif
+ int inout);
+-static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *SCpnt));
++static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
++ void (* done)(struct scsi_cmnd *SCpnt));
+
+ /* Error handler */
+-/*static int nsp_eh_abort (Scsi_Cmnd *SCpnt);*/
+-/*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/
+-static int nsp_eh_bus_reset (Scsi_Cmnd *SCpnt);
+-static int nsp_eh_host_reset (Scsi_Cmnd *SCpnt);
++/*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/
++/*static int nsp_eh_device_reset(struct scsi_cmnd *SCpnt);*/
++static int nsp_eh_bus_reset (struct scsi_cmnd *SCpnt);
++static int nsp_eh_host_reset (struct scsi_cmnd *SCpnt);
+ static int nsp_bus_reset (nsp_hw_data *data);
+
+ /* */
+ static int nsphw_init (nsp_hw_data *data);
+-static int nsphw_start_selection(Scsi_Cmnd *SCpnt);
+-static void nsp_start_timer (Scsi_Cmnd *SCpnt, int time);
+-static int nsp_fifo_count (Scsi_Cmnd *SCpnt);
+-static void nsp_pio_read (Scsi_Cmnd *SCpnt);
+-static void nsp_pio_write (Scsi_Cmnd *SCpnt);
+-static int nsp_nexus (Scsi_Cmnd *SCpnt);
+-static void nsp_scsi_done (Scsi_Cmnd *SCpnt);
+-static int nsp_analyze_sdtr (Scsi_Cmnd *SCpnt);
+-static int nsp_negate_signal (Scsi_Cmnd *SCpnt, unsigned char mask, char *str);
+-static int nsp_expect_signal (Scsi_Cmnd *SCpnt, unsigned char current_phase, unsigned char mask);
+-static int nsp_xfer (Scsi_Cmnd *SCpnt, int phase);
+-static int nsp_dataphase_bypass (Scsi_Cmnd *SCpnt);
+-static int nsp_reselected (Scsi_Cmnd *SCpnt);
++static int nsphw_start_selection(struct scsi_cmnd *SCpnt);
++static void nsp_start_timer (struct scsi_cmnd *SCpnt, int time);
++static int nsp_fifo_count (struct scsi_cmnd *SCpnt);
++static void nsp_pio_read (struct scsi_cmnd *SCpnt);
++static void nsp_pio_write (struct scsi_cmnd *SCpnt);
++static int nsp_nexus (struct scsi_cmnd *SCpnt);
++static void nsp_scsi_done (struct scsi_cmnd *SCpnt);
++static int nsp_analyze_sdtr (struct scsi_cmnd *SCpnt);
++static int nsp_negate_signal (struct scsi_cmnd *SCpnt,
++ unsigned char mask, char *str);
++static int nsp_expect_signal (struct scsi_cmnd *SCpnt,
++ unsigned char current_phase,
++ unsigned char mask);
++static int nsp_xfer (struct scsi_cmnd *SCpnt, int phase);
++static int nsp_dataphase_bypass (struct scsi_cmnd *SCpnt);
++static int nsp_reselected (struct scsi_cmnd *SCpnt);
+ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht);
+
+ /* Interrupt handler */
+-//static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs);
++//static irqreturn_t nspintr(int irq, void *dev_id);
+
+ /* Module entry point*/
+ static int __init nsp_cs_init(void);
+@@ -355,8 +359,8 @@ static void __exit nsp_cs_exit(void);
+
+ /* Debug */
+ #ifdef NSP_DEBUG
+-static void show_command (Scsi_Cmnd *SCpnt);
+-static void show_phase (Scsi_Cmnd *SCpnt);
++static void show_command (struct scsi_cmnd *SCpnt);
++static void show_phase (struct scsi_cmnd *SCpnt);
+ static void show_busphase(unsigned char stat);
+ static void show_message (nsp_hw_data *data);
+ #else
+diff --git a/drivers/scsi/pcmcia/nsp_debug.c b/drivers/scsi/pcmcia/nsp_debug.c
+index 62e5c60..2f75fe6 100644
+--- a/drivers/scsi/pcmcia/nsp_debug.c
++++ b/drivers/scsi/pcmcia/nsp_debug.c
+@@ -138,12 +138,12 @@ static void print_commandk (unsigned cha
+ printk("\n");
+ }
+
+-static void show_command(Scsi_Cmnd *SCpnt)
++static void show_command(struct scsi_cmnd *SCpnt)
+ {
+ print_commandk(SCpnt->cmnd);
+ }
+
+-static void show_phase(Scsi_Cmnd *SCpnt)
++static void show_phase(struct scsi_cmnd *SCpnt)
+ {
+ int i = SCpnt->SCp.phase;
+
+diff --git a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c
+index d705773..ef593b7 100644
+--- a/drivers/scsi/pcmcia/nsp_message.c
++++ b/drivers/scsi/pcmcia/nsp_message.c
+@@ -8,7 +8,7 @@
+
+ /* $Id: nsp_message.c,v 1.6 2003/07/26 14:21:09 elca Exp $ */
+
+-static void nsp_message_in(Scsi_Cmnd *SCpnt)
++static void nsp_message_in(struct scsi_cmnd *SCpnt)
+ {
+ unsigned int base = SCpnt->device->host->io_port;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+@@ -50,7 +50,7 @@ static void nsp_message_in(Scsi_Cmnd *SC
+
+ }
+
+-static void nsp_message_out(Scsi_Cmnd *SCpnt)
++static void nsp_message_out(struct scsi_cmnd *SCpnt)
+ {
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ int ret = 1;
+diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
+index 0b65099..72fe5d0 100644
+--- a/drivers/scsi/pcmcia/sym53c500_cs.c
++++ b/drivers/scsi/pcmcia/sym53c500_cs.c
+@@ -363,7 +363,7 @@ SYM53C500_pio_write(int fast_pio, int ba
+ }
+
+ static irqreturn_t
+-SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs)
++SYM53C500_intr(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
+deleted file mode 100644
+index efc8fff..0000000
+--- a/drivers/scsi/pdc_adma.c
++++ /dev/null
+@@ -1,740 +0,0 @@
+-/*
+- * pdc_adma.c - Pacific Digital Corporation ADMA
+- *
+- * Maintained by: Mark Lord <mlord at pobox.com>
+- *
+- * Copyright 2005 Mark Lord
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- *
+- * Supports ATA disks in single-packet ADMA mode.
+- * Uses PIO for everything else.
+- *
+- * TODO: Use ADMA transfers for ATAPI devices, when possible.
+- * This requires careful attention to a number of quirks of the chip.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/sched.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <asm/io.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "pdc_adma"
+-#define DRV_VERSION "0.04"
+-
+-/* macro to calculate base address for ATA regs */
+-#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
+-
+-/* macro to calculate base address for ADMA regs */
+-#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+-
+-enum {
+- ADMA_PORTS = 2,
+- ADMA_CPB_BYTES = 40,
+- ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16,
+- ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES,
+-
+- ADMA_DMA_BOUNDARY = 0xffffffff,
+-
+- /* global register offsets */
+- ADMA_MODE_LOCK = 0x00c7,
+-
+- /* per-channel register offsets */
+- ADMA_CONTROL = 0x0000, /* ADMA control */
+- ADMA_STATUS = 0x0002, /* ADMA status */
+- ADMA_CPB_COUNT = 0x0004, /* CPB count */
+- ADMA_CPB_CURRENT = 0x000c, /* current CPB address */
+- ADMA_CPB_NEXT = 0x000c, /* next CPB address */
+- ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */
+- ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */
+- ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */
+-
+- /* ADMA_CONTROL register bits */
+- aNIEN = (1 << 8), /* irq mask: 1==masked */
+- aGO = (1 << 7), /* packet trigger ("Go!") */
+- aRSTADM = (1 << 5), /* ADMA logic reset */
+- aPIOMD4 = 0x0003, /* PIO mode 4 */
+-
+- /* ADMA_STATUS register bits */
+- aPSD = (1 << 6),
+- aUIRQ = (1 << 4),
+- aPERR = (1 << 0),
+-
+- /* CPB bits */
+- cDONE = (1 << 0),
+- cVLD = (1 << 0),
+- cDAT = (1 << 2),
+- cIEN = (1 << 3),
+-
+- /* PRD bits */
+- pORD = (1 << 4),
+- pDIRO = (1 << 5),
+- pEND = (1 << 7),
+-
+- /* ATA register flags */
+- rIGN = (1 << 5),
+- rEND = (1 << 7),
+-
+- /* ATA register addresses */
+- ADMA_REGS_CONTROL = 0x0e,
+- ADMA_REGS_SECTOR_COUNT = 0x12,
+- ADMA_REGS_LBA_LOW = 0x13,
+- ADMA_REGS_LBA_MID = 0x14,
+- ADMA_REGS_LBA_HIGH = 0x15,
+- ADMA_REGS_DEVICE = 0x16,
+- ADMA_REGS_COMMAND = 0x17,
+-
+- /* PCI device IDs */
+- board_1841_idx = 0, /* ADMA 2-port controller */
+-};
+-
+-typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t;
+-
+-struct adma_port_priv {
+- u8 *pkt;
+- dma_addr_t pkt_dma;
+- adma_state_t state;
+-};
+-
+-static int adma_ata_init_one (struct pci_dev *pdev,
+- const struct pci_device_id *ent);
+-static irqreturn_t adma_intr (int irq, void *dev_instance,
+- struct pt_regs *regs);
+-static int adma_port_start(struct ata_port *ap);
+-static void adma_host_stop(struct ata_host_set *host_set);
+-static void adma_port_stop(struct ata_port *ap);
+-static void adma_phy_reset(struct ata_port *ap);
+-static void adma_qc_prep(struct ata_queued_cmd *qc);
+-static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
+-static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
+-static void adma_bmdma_stop(struct ata_queued_cmd *qc);
+-static u8 adma_bmdma_status(struct ata_port *ap);
+-static void adma_irq_clear(struct ata_port *ap);
+-static void adma_eng_timeout(struct ata_port *ap);
+-
+-static struct scsi_host_template adma_ata_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ENABLE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ADMA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations adma_ata_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .check_atapi_dma = adma_check_atapi_dma,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+- .phy_reset = adma_phy_reset,
+- .qc_prep = adma_qc_prep,
+- .qc_issue = adma_qc_issue,
+- .eng_timeout = adma_eng_timeout,
+- .data_xfer = ata_mmio_data_xfer,
+- .irq_handler = adma_intr,
+- .irq_clear = adma_irq_clear,
+- .port_start = adma_port_start,
+- .port_stop = adma_port_stop,
+- .host_stop = adma_host_stop,
+- .bmdma_stop = adma_bmdma_stop,
+- .bmdma_status = adma_bmdma_status,
+-};
+-
+-static struct ata_port_info adma_port_info[] = {
+- /* board_1841_idx */
+- {
+- .sht = &adma_ata_sht,
+- .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+- ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
+- ATA_FLAG_PIO_POLLING,
+- .pio_mask = 0x10, /* pio4 */
+- .udma_mask = 0x1f, /* udma0-4 */
+- .port_ops = &adma_ata_ops,
+- },
+-};
+-
+-static const struct pci_device_id adma_ata_pci_tbl[] = {
+- { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_1841_idx },
+-
+- { } /* terminate list */
+-};
+-
+-static struct pci_driver adma_ata_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = adma_ata_pci_tbl,
+- .probe = adma_ata_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static int adma_check_atapi_dma(struct ata_queued_cmd *qc)
+-{
+- return 1; /* ATAPI DMA not yet supported */
+-}
+-
+-static void adma_bmdma_stop(struct ata_queued_cmd *qc)
+-{
+- /* nothing */
+-}
+-
+-static u8 adma_bmdma_status(struct ata_port *ap)
+-{
+- return 0;
+-}
+-
+-static void adma_irq_clear(struct ata_port *ap)
+-{
+- /* nothing */
+-}
+-
+-static void adma_reset_engine(void __iomem *chan)
+-{
+- /* reset ADMA to idle state */
+- writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+- udelay(2);
+- writew(aPIOMD4, chan + ADMA_CONTROL);
+- udelay(2);
+-}
+-
+-static void adma_reinit_engine(struct ata_port *ap)
+-{
+- struct adma_port_priv *pp = ap->private_data;
+- void __iomem *mmio_base = ap->host_set->mmio_base;
+- void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
+-
+- /* mask/clear ATA interrupts */
+- writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr);
+- ata_check_status(ap);
+-
+- /* reset the ADMA engine */
+- adma_reset_engine(chan);
+-
+- /* set in-FIFO threshold to 0x100 */
+- writew(0x100, chan + ADMA_FIFO_IN);
+-
+- /* set CPB pointer */
+- writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT);
+-
+- /* set out-FIFO threshold to 0x100 */
+- writew(0x100, chan + ADMA_FIFO_OUT);
+-
+- /* set CPB count */
+- writew(1, chan + ADMA_CPB_COUNT);
+-
+- /* read/discard ADMA status */
+- readb(chan + ADMA_STATUS);
+-}
+-
+-static inline void adma_enter_reg_mode(struct ata_port *ap)
+-{
+- void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no);
+-
+- writew(aPIOMD4, chan + ADMA_CONTROL);
+- readb(chan + ADMA_STATUS); /* flush */
+-}
+-
+-static void adma_phy_reset(struct ata_port *ap)
+-{
+- struct adma_port_priv *pp = ap->private_data;
+-
+- pp->state = adma_state_idle;
+- adma_reinit_engine(ap);
+- ata_port_probe(ap);
+- ata_bus_reset(ap);
+-}
+-
+-static void adma_eng_timeout(struct ata_port *ap)
+-{
+- struct adma_port_priv *pp = ap->private_data;
+-
+- if (pp->state != adma_state_idle) /* healthy paranoia */
+- pp->state = adma_state_mmio;
+- adma_reinit_engine(ap);
+- ata_eng_timeout(ap);
+-}
+-
+-static int adma_fill_sg(struct ata_queued_cmd *qc)
+-{
+- struct scatterlist *sg;
+- struct ata_port *ap = qc->ap;
+- struct adma_port_priv *pp = ap->private_data;
+- u8 *buf = pp->pkt;
+- int i = (2 + buf[3]) * 8;
+- u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
+-
+- ata_for_each_sg(sg, qc) {
+- u32 addr;
+- u32 len;
+-
+- addr = (u32)sg_dma_address(sg);
+- *(__le32 *)(buf + i) = cpu_to_le32(addr);
+- i += 4;
+-
+- len = sg_dma_len(sg) >> 3;
+- *(__le32 *)(buf + i) = cpu_to_le32(len);
+- i += 4;
+-
+- if (ata_sg_is_last(sg, qc))
+- pFLAGS |= pEND;
+- buf[i++] = pFLAGS;
+- buf[i++] = qc->dev->dma_mode & 0xf;
+- buf[i++] = 0; /* pPKLW */
+- buf[i++] = 0; /* reserved */
+-
+- *(__le32 *)(buf + i)
+- = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
+- i += 4;
+-
+- VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4,
+- (unsigned long)addr, len);
+- }
+- return i;
+-}
+-
+-static void adma_qc_prep(struct ata_queued_cmd *qc)
+-{
+- struct adma_port_priv *pp = qc->ap->private_data;
+- u8 *buf = pp->pkt;
+- u32 pkt_dma = (u32)pp->pkt_dma;
+- int i = 0;
+-
+- VPRINTK("ENTER\n");
+-
+- adma_enter_reg_mode(qc->ap);
+- if (qc->tf.protocol != ATA_PROT_DMA) {
+- ata_qc_prep(qc);
+- return;
+- }
+-
+- buf[i++] = 0; /* Response flags */
+- buf[i++] = 0; /* reserved */
+- buf[i++] = cVLD | cDAT | cIEN;
+- i++; /* cLEN, gets filled in below */
+-
+- *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */
+- i += 4; /* cNCPB */
+- i += 4; /* cPRD, gets filled in below */
+-
+- buf[i++] = 0; /* reserved */
+- buf[i++] = 0; /* reserved */
+- buf[i++] = 0; /* reserved */
+- buf[i++] = 0; /* reserved */
+-
+- /* ATA registers; must be a multiple of 4 */
+- buf[i++] = qc->tf.device;
+- buf[i++] = ADMA_REGS_DEVICE;
+- if ((qc->tf.flags & ATA_TFLAG_LBA48)) {
+- buf[i++] = qc->tf.hob_nsect;
+- buf[i++] = ADMA_REGS_SECTOR_COUNT;
+- buf[i++] = qc->tf.hob_lbal;
+- buf[i++] = ADMA_REGS_LBA_LOW;
+- buf[i++] = qc->tf.hob_lbam;
+- buf[i++] = ADMA_REGS_LBA_MID;
+- buf[i++] = qc->tf.hob_lbah;
+- buf[i++] = ADMA_REGS_LBA_HIGH;
+- }
+- buf[i++] = qc->tf.nsect;
+- buf[i++] = ADMA_REGS_SECTOR_COUNT;
+- buf[i++] = qc->tf.lbal;
+- buf[i++] = ADMA_REGS_LBA_LOW;
+- buf[i++] = qc->tf.lbam;
+- buf[i++] = ADMA_REGS_LBA_MID;
+- buf[i++] = qc->tf.lbah;
+- buf[i++] = ADMA_REGS_LBA_HIGH;
+- buf[i++] = 0;
+- buf[i++] = ADMA_REGS_CONTROL;
+- buf[i++] = rIGN;
+- buf[i++] = 0;
+- buf[i++] = qc->tf.command;
+- buf[i++] = ADMA_REGS_COMMAND | rEND;
+-
+- buf[3] = (i >> 3) - 2; /* cLEN */
+- *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */
+-
+- i = adma_fill_sg(qc);
+- wmb(); /* flush PRDs and pkt to memory */
+-#if 0
+- /* dump out CPB + PRDs for debug */
+- {
+- int j, len = 0;
+- static char obuf[2048];
+- for (j = 0; j < i; ++j) {
+- len += sprintf(obuf+len, "%02x ", buf[j]);
+- if ((j & 7) == 7) {
+- printk("%s\n", obuf);
+- len = 0;
+- }
+- }
+- if (len)
+- printk("%s\n", obuf);
+- }
+-#endif
+-}
+-
+-static inline void adma_packet_start(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no);
+-
+- VPRINTK("ENTER, ap %p\n", ap);
+-
+- /* fire up the ADMA engine */
+- writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
+-}
+-
+-static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
+-{
+- struct adma_port_priv *pp = qc->ap->private_data;
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- pp->state = adma_state_pkt;
+- adma_packet_start(qc);
+- return 0;
+-
+- case ATA_PROT_ATAPI_DMA:
+- BUG();
+- break;
+-
+- default:
+- break;
+- }
+-
+- pp->state = adma_state_mmio;
+- return ata_qc_issue_prot(qc);
+-}
+-
+-static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
+-{
+- unsigned int handled = 0, port_no;
+- u8 __iomem *mmio_base = host_set->mmio_base;
+-
+- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
+- struct ata_port *ap = host_set->ports[port_no];
+- struct adma_port_priv *pp;
+- struct ata_queued_cmd *qc;
+- void __iomem *chan = ADMA_REGS(mmio_base, port_no);
+- u8 status = readb(chan + ADMA_STATUS);
+-
+- if (status == 0)
+- continue;
+- handled = 1;
+- adma_enter_reg_mode(ap);
+- if (ap->flags & ATA_FLAG_DISABLED)
+- continue;
+- pp = ap->private_data;
+- if (!pp || pp->state != adma_state_pkt)
+- continue;
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+- if ((status & (aPERR | aPSD | aUIRQ)))
+- qc->err_mask |= AC_ERR_OTHER;
+- else if (pp->pkt[0] != cDONE)
+- qc->err_mask |= AC_ERR_OTHER;
+-
+- ata_qc_complete(qc);
+- }
+- }
+- return handled;
+-}
+-
+-static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
+-{
+- unsigned int handled = 0, port_no;
+-
+- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
+- struct ata_port *ap;
+- ap = host_set->ports[port_no];
+- if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
+- struct ata_queued_cmd *qc;
+- struct adma_port_priv *pp = ap->private_data;
+- if (!pp || pp->state != adma_state_mmio)
+- continue;
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+-
+- /* check main status, clearing INTRQ */
+- u8 status = ata_check_status(ap);
+- if ((status & ATA_BUSY))
+- continue;
+- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+- ap->id, qc->tf.protocol, status);
+-
+- /* complete taskfile transaction */
+- pp->state = adma_state_idle;
+- qc->err_mask |= ac_err_mask(status);
+- ata_qc_complete(qc);
+- handled = 1;
+- }
+- }
+- }
+- return handled;
+-}
+-
+-static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- unsigned int handled = 0;
+-
+- VPRINTK("ENTER\n");
+-
+- spin_lock(&host_set->lock);
+- handled = adma_intr_pkt(host_set) | adma_intr_mmio(host_set);
+- spin_unlock(&host_set->lock);
+-
+- VPRINTK("EXIT\n");
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
+-{
+- port->cmd_addr =
+- port->data_addr = base + 0x000;
+- port->error_addr =
+- port->feature_addr = base + 0x004;
+- port->nsect_addr = base + 0x008;
+- port->lbal_addr = base + 0x00c;
+- port->lbam_addr = base + 0x010;
+- port->lbah_addr = base + 0x014;
+- port->device_addr = base + 0x018;
+- port->status_addr =
+- port->command_addr = base + 0x01c;
+- port->altstatus_addr =
+- port->ctl_addr = base + 0x038;
+-}
+-
+-static int adma_port_start(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct adma_port_priv *pp;
+- int rc;
+-
+- rc = ata_port_start(ap);
+- if (rc)
+- return rc;
+- adma_enter_reg_mode(ap);
+- rc = -ENOMEM;
+- pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+- if (!pp)
+- goto err_out;
+- pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
+- GFP_KERNEL);
+- if (!pp->pkt)
+- goto err_out_kfree;
+- /* paranoia? */
+- if ((pp->pkt_dma & 7) != 0) {
+- printk("bad alignment for pp->pkt_dma: %08x\n",
+- (u32)pp->pkt_dma);
+- dma_free_coherent(dev, ADMA_PKT_BYTES,
+- pp->pkt, pp->pkt_dma);
+- goto err_out_kfree;
+- }
+- memset(pp->pkt, 0, ADMA_PKT_BYTES);
+- ap->private_data = pp;
+- adma_reinit_engine(ap);
+- return 0;
+-
+-err_out_kfree:
+- kfree(pp);
+-err_out:
+- ata_port_stop(ap);
+- return rc;
+-}
+-
+-static void adma_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct adma_port_priv *pp = ap->private_data;
+-
+- adma_reset_engine(ADMA_REGS(ap->host_set->mmio_base, ap->port_no));
+- if (pp != NULL) {
+- ap->private_data = NULL;
+- if (pp->pkt != NULL)
+- dma_free_coherent(dev, ADMA_PKT_BYTES,
+- pp->pkt, pp->pkt_dma);
+- kfree(pp);
+- }
+- ata_port_stop(ap);
+-}
+-
+-static void adma_host_stop(struct ata_host_set *host_set)
+-{
+- unsigned int port_no;
+-
+- for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+- adma_reset_engine(ADMA_REGS(host_set->mmio_base, port_no));
+-
+- ata_pci_host_stop(host_set);
+-}
+-
+-static void adma_host_init(unsigned int chip_id,
+- struct ata_probe_ent *probe_ent)
+-{
+- unsigned int port_no;
+- void __iomem *mmio_base = probe_ent->mmio_base;
+-
+- /* enable/lock aGO operation */
+- writeb(7, mmio_base + ADMA_MODE_LOCK);
+-
+- /* reset the ADMA logic */
+- for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+- adma_reset_engine(ADMA_REGS(mmio_base, port_no));
+-}
+-
+-static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
+-{
+- int rc;
+-
+- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit DMA enable failed\n");
+- return rc;
+- }
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit consistent DMA enable failed\n");
+- return rc;
+- }
+- return 0;
+-}
+-
+-static int adma_ata_init_one(struct pci_dev *pdev,
+- const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- void __iomem *mmio_base;
+- unsigned int board_idx = (unsigned int) ent->driver_data;
+- int rc, port_no;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc)
+- goto err_out;
+-
+- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
+- rc = -ENODEV;
+- goto err_out_regions;
+- }
+-
+- mmio_base = pci_iomap(pdev, 4, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- rc = adma_set_dma_masks(pdev, mmio_base);
+- if (rc)
+- goto err_out_iounmap;
+-
+- probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_iounmap;
+- }
+-
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- probe_ent->sht = adma_port_info[board_idx].sht;
+- probe_ent->host_flags = adma_port_info[board_idx].host_flags;
+- probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
+- probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
+- probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
+- probe_ent->port_ops = adma_port_info[board_idx].port_ops;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+- probe_ent->n_ports = ADMA_PORTS;
+-
+- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+- adma_ata_setup_port(&probe_ent->port[port_no],
+- ADMA_ATA_REGS((unsigned long)mmio_base, port_no));
+- }
+-
+- pci_set_master(pdev);
+-
+- /* initialize adapter */
+- adma_host_init(board_idx, probe_ent);
+-
+- rc = ata_device_add(probe_ent);
+- kfree(probe_ent);
+- if (rc != ADMA_PORTS)
+- goto err_out_iounmap;
+- return 0;
+-
+-err_out_iounmap:
+- pci_iounmap(pdev, mmio_base);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-static int __init adma_ata_init(void)
+-{
+- return pci_module_init(&adma_ata_pci_driver);
+-}
+-
+-static void __exit adma_ata_exit(void)
+-{
+- pci_unregister_driver(&adma_ata_pci_driver);
+-}
+-
+-MODULE_AUTHOR("Mark Lord");
+-MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(adma_ata_init);
+-module_exit(adma_ata_exit);
+diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
+index 0bd9c60..aa60a5f 100644
+--- a/drivers/scsi/pluto.c
++++ b/drivers/scsi/pluto.c
+@@ -67,7 +67,6 @@ static void __init pluto_detect_done(Scs
+
+ static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
+ {
+- SCpnt->request->rq_status = RQ_SCSI_DONE;
+ PLND(("Detect done %08lx\n", (long)SCpnt))
+ if (atomic_dec_and_test (&fcss))
+ up(&fc_sem);
+@@ -166,7 +165,7 @@ int __init pluto_detect(struct scsi_host
+
+ SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
+
+- SCpnt->request->rq_status = RQ_SCSI_BUSY;
++ SCpnt->request->cmd_flags &= ~REQ_STARTED;
+
+ SCpnt->done = pluto_detect_done;
+ SCpnt->request_bufflen = 256;
+@@ -178,7 +177,8 @@ int __init pluto_detect(struct scsi_host
+ for (retry = 0; retry < 5; retry++) {
+ for (i = 0; i < fcscount; i++) {
+ if (!fcs[i].fc) break;
+- if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) {
++ if (!(fcs[i].cmd.request->cmd_flags & REQ_STARTED)) {
++ fcs[i].cmd.request->cmd_flags |= REQ_STARTED;
+ disable_irq(fcs[i].fc->irq);
+ PLND(("queuecommand %d %d\n", retry, i))
+ fcp_scsi_queuecommand (&(fcs[i].cmd),
+diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
+index b0eba39..89a2a9f 100644
+--- a/drivers/scsi/ppa.c
++++ b/drivers/scsi/ppa.c
+@@ -1012,7 +1012,7 @@ static LIST_HEAD(ppa_hosts);
+ static int __ppa_attach(struct parport *pb)
+ {
+ struct Scsi_Host *host;
+- DECLARE_WAIT_QUEUE_HEAD(waiting);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
+ DEFINE_WAIT(wait);
+ ppa_struct *dev;
+ int ports;
+diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
+index 7511df3..ba80214 100644
+--- a/drivers/scsi/ppa.h
++++ b/drivers/scsi/ppa.h
+@@ -73,7 +73,6 @@
+ */
+ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+-#include <linux/config.h>
+ #include <linux/stddef.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
+index 5c2cdf5..ac0419e 100644
+--- a/drivers/scsi/psi240i.c
++++ b/drivers/scsi/psi240i.c
+@@ -87,11 +87,11 @@ typedef struct
+ {
+ USHORT ports[13];
+ OUR_DEVICE device[8];
+- Scsi_Cmnd *pSCmnd;
++ struct scsi_cmnd *pSCmnd;
+ IDE_STRUCT ide;
+ ULONG startSector;
+ USHORT sectorCount;
+- Scsi_Cmnd *SCpnt;
++ struct scsi_cmnd *SCpnt;
+ VOID *buffer;
+ USHORT expectingIRQ;
+ } ADAPTER240I, *PADAPTER240I;
+@@ -247,19 +247,18 @@ static ULONG DecodeError (struct Scsi_Ho
+ *
+ * Parameters: irq - Hardware IRQ number.
+ * dev_id -
+- * regs -
+ *
+ * Returns: TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+-static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
++static void Irq_Handler (int irq, void *dev_id)
+ {
+- struct Scsi_Host *shost; // Pointer to host data block
+- PADAPTER240I padapter; // Pointer to adapter control structure
+- USHORT *pports; // I/O port array
+- Scsi_Cmnd *SCpnt;
+- UCHAR status;
+- int z;
++ struct Scsi_Host *shost; // Pointer to host data block
++ PADAPTER240I padapter; // Pointer to adapter control structure
++ USHORT *pports; // I/O port array
++ struct scsi_cmnd *SCpnt;
++ UCHAR status;
++ int z;
+
+ DEB(printk ("\npsi240i received interrupt\n"));
+
+@@ -368,13 +367,13 @@ irqerror:;
+ SCpnt->scsi_done (SCpnt);
+ }
+
+-static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+- Irq_Handler(irq, dev_id, regs);
++ Irq_Handler(irq, dev_id);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+@@ -390,12 +389,17 @@ static irqreturn_t do_Irq_Handler (int i
+ * Returns: Status code.
+ *
+ ****************************************************************/
+-static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
++ void (*done)(struct scsi_cmnd *))
+ {
+- UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB
+- PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); // Pointer to adapter control structure
+- POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];// Pointer to device information
+- UCHAR rc; // command return code
++ UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
++ // Pointer to SCSI CDB
++ PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
++ // Pointer to adapter control structure
++ POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
++ // Pointer to device information
++ UCHAR rc;
++ // command return code
+
+ SCpnt->scsi_done = done;
+ padapter->ide.ide.ides.spigot = pdev->spigot;
+diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
+index 6a59876..21ebb92 100644
+--- a/drivers/scsi/psi240i.h
++++ b/drivers/scsi/psi240i.h
+@@ -309,7 +309,7 @@ typedef struct _IDENTIFY_DATA2 {
+ #endif // PSI_EIDE_SCSIOP
+
+ // function prototypes
+-int Psi240i_Command (Scsi_Cmnd *SCpnt);
+-int Psi240i_Abort (Scsi_Cmnd *SCpnt);
+-int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
++int Psi240i_Command(struct scsi_cmnd *SCpnt);
++int Psi240i_Abort(struct scsi_cmnd *SCpnt);
++int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags);
+ #endif
+diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
+index 8953991..16af5b7 100644
+--- a/drivers/scsi/qla1280.c
++++ b/drivers/scsi/qla1280.c
+@@ -813,7 +813,7 @@ qla1280_error_action(struct scsi_cmnd *c
+ uint16_t data;
+ unsigned char *handle;
+ int result, i;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ struct timer_list timer;
+
+ ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata);
+@@ -931,11 +931,10 @@ qla1280_error_action(struct scsi_cmnd *c
+
+ case BUS_RESET:
+ if (qla1280_verbose)
+- printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS "
+- "DEVICE RESET\n", ha->host_no, bus);
+- if (qla1280_bus_reset(ha, bus == 0))
++ printk(KERN_INFO "qla1280(%ld:%d): Issued bus "
++ "reset.\n", ha->host_no, bus);
++ if (qla1280_bus_reset(ha, bus) == 0)
+ result = SUCCESS;
+-
+ break;
+
+ case ADAPTER_RESET:
+@@ -1113,7 +1112,7 @@ qla1280_enable_intrs(struct scsi_qla_hos
+ * Handles the H/W interrupt
+ **************************************************************************/
+ static irqreturn_t
+-qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
++qla1280_intr_handler(int irq, void *dev_id)
+ {
+ struct scsi_qla_host *ha;
+ struct device_reg __iomem *reg;
+@@ -2406,7 +2405,7 @@ qla1280_mailbox_command(struct scsi_qla_
+ uint16_t *optr, *iptr;
+ uint16_t __iomem *mptr;
+ uint16_t data;
+- DECLARE_COMPLETION(wait);
++ DECLARE_COMPLETION_ONSTACK(wait);
+ struct timer_list timer;
+
+ ENTER("qla1280_mailbox_command");
+@@ -2862,7 +2861,7 @@ qla1280_64bit_start_scsi(struct scsi_qla
+ memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
+
+ /* Set ISP command timeout. */
+- pkt->timeout = cpu_to_le16(30);
++ pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+
+ /* Set device target ID and LUN */
+ pkt->lun = SCSI_LUN_32(cmd);
+@@ -3161,7 +3160,7 @@ qla1280_32bit_start_scsi(struct scsi_qla
+ memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
+
+ /* Set ISP command timeout. */
+- pkt->timeout = cpu_to_le16(30);
++ pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+
+ /* Set device target ID and LUN */
+ pkt->lun = SCSI_LUN_32(cmd);
+@@ -4484,7 +4483,7 @@ qla1280_init(void)
+ qla1280_setup(qla1280);
+ #endif
+
+- return pci_module_init(&qla1280_pci_driver);
++ return pci_register_driver(&qla1280_pci_driver);
+ }
+
+ static void __exit
+diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
+index 87f90c4..285c8e8 100644
+--- a/drivers/scsi/qla2xxx/qla_attr.c
++++ b/drivers/scsi/qla2xxx/qla_attr.c
+@@ -379,21 +379,37 @@ static struct bin_attribute sysfs_sfp_at
+ .read = qla2x00_sysfs_read_sfp,
+ };
+
++static struct sysfs_entry {
++ char *name;
++ struct bin_attribute *attr;
++ int is4GBp_only;
++} bin_file_entries[] = {
++ { "fw_dump", &sysfs_fw_dump_attr, },
++ { "nvram", &sysfs_nvram_attr, },
++ { "optrom", &sysfs_optrom_attr, },
++ { "optrom_ctl", &sysfs_optrom_ctl_attr, },
++ { "vpd", &sysfs_vpd_attr, 1 },
++ { "sfp", &sysfs_sfp_attr, 1 },
++ { 0 },
++};
++
+ void
+ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
+ {
+ struct Scsi_Host *host = ha->host;
++ struct sysfs_entry *iter;
++ int ret;
+
+- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
+- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
+- sysfs_create_bin_file(&host->shost_gendev.kobj,
+- &sysfs_optrom_ctl_attr);
+- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+- sysfs_create_bin_file(&host->shost_gendev.kobj,
+- &sysfs_vpd_attr);
+- sysfs_create_bin_file(&host->shost_gendev.kobj,
+- &sysfs_sfp_attr);
++ for (iter = bin_file_entries; iter->name; iter++) {
++ if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
++ continue;
++
++ ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
++ iter->attr);
++ if (ret)
++ qla_printk(KERN_INFO, ha,
++ "Unable to create sysfs %s binary attribute "
++ "(%d).\n", iter->name, ret);
+ }
+ }
+
+@@ -401,17 +417,14 @@ void
+ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
+ {
+ struct Scsi_Host *host = ha->host;
++ struct sysfs_entry *iter;
++
++ for (iter = bin_file_entries; iter->name; iter++) {
++ if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
++ continue;
+
+- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
+- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
+- sysfs_remove_bin_file(&host->shost_gendev.kobj,
+- &sysfs_optrom_ctl_attr);
+- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+- sysfs_remove_bin_file(&host->shost_gendev.kobj,
+- &sysfs_vpd_attr);
+ sysfs_remove_bin_file(&host->shost_gendev.kobj,
+- &sysfs_sfp_attr);
++ iter->attr);
+ }
+
+ if (ha->beacon_blink_led == 1)
+@@ -691,13 +704,13 @@ qla2x00_get_host_speed(struct Scsi_Host
+ uint32_t speed = 0;
+
+ switch (ha->link_data_rate) {
+- case LDR_1GB:
++ case PORT_SPEED_1GB:
+ speed = 1;
+ break;
+- case LDR_2GB:
++ case PORT_SPEED_2GB:
+ speed = 2;
+ break;
+- case LDR_4GB:
++ case PORT_SPEED_4GB:
+ speed = 4;
+ break;
+ }
+@@ -849,6 +862,49 @@ qla2x00_get_fc_host_stats(struct Scsi_Ho
+ return pfc_host_stat;
+ }
+
++static void
++qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
++{
++ scsi_qla_host_t *ha = to_qla_host(shost);
++
++ qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
++}
++
++static void
++qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
++{
++ scsi_qla_host_t *ha = to_qla_host(shost);
++
++ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
++}
++
++static void
++qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
++{
++ scsi_qla_host_t *ha = to_qla_host(shost);
++ u64 node_name;
++
++ if (ha->device_flags & SWITCH_FOUND)
++ node_name = wwn_to_u64(ha->fabric_node_name);
++ else
++ node_name = wwn_to_u64(ha->node_name);
++
++ fc_host_fabric_name(shost) = node_name;
++}
++
++static void
++qla2x00_get_host_port_state(struct Scsi_Host *shost)
++{
++ scsi_qla_host_t *ha = to_qla_host(shost);
++
++ if (!ha->flags.online)
++ fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
++ else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT)
++ fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
++ else
++ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
++}
++
+ struct fc_function_template qla2xxx_transport_functions = {
+
+ .show_host_node_name = 1,
+@@ -861,6 +917,14 @@ struct fc_function_template qla2xxx_tran
+ .show_host_speed = 1,
+ .get_host_port_type = qla2x00_get_host_port_type,
+ .show_host_port_type = 1,
++ .get_host_symbolic_name = qla2x00_get_host_symbolic_name,
++ .show_host_symbolic_name = 1,
++ .set_host_system_hostname = qla2x00_set_host_system_hostname,
++ .show_host_system_hostname = 1,
++ .get_host_fabric_name = qla2x00_get_host_fabric_name,
++ .show_host_fabric_name = 1,
++ .get_host_port_state = qla2x00_get_host_port_state,
++ .show_host_port_state = 1,
+
+ .dd_fcrport_size = sizeof(struct fc_port *),
+ .show_rport_supported_classes = 1,
+diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
+index 5334253..5b12278 100644
+--- a/drivers/scsi/qla2xxx/qla_dbg.h
++++ b/drivers/scsi/qla2xxx/qla_dbg.h
+@@ -38,7 +38,7 @@
+ * Macros use for debugging the driver.
+ */
+
+-#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0)
++#define DEBUG(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+
+ #if defined(QL_DEBUG_LEVEL_1)
+ #define DEBUG1(x) do {x;} while (0)
+@@ -46,12 +46,12 @@
+ #define DEBUG1(x) do {} while (0)
+ #endif
+
+-#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0)
+-#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0)
+-#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0)
+-#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0)
+-#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0)
+-#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0)
++#define DEBUG2(x) do { if (ql2xextended_error_logging) { x; } } while (0)
++#define DEBUG2_3(x) do { if (ql2xextended_error_logging) { x; } } while (0)
++#define DEBUG2_3_11(x) do { if (ql2xextended_error_logging) { x; } } while (0)
++#define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0)
++#define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0)
++#define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+
+ #if defined(QL_DEBUG_LEVEL_3)
+ #define DEBUG3(x) do {x;} while (0)
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 0930260..c4fc40f 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -608,6 +608,7 @@ typedef struct {
+ */
+ #define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
+ #define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
++#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
+ #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */
+ #define MBC_TRACE_CONTROL 0x27 /* Trace control command. */
+ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */
+@@ -1497,6 +1498,9 @@ typedef struct {
+ port_id_t d_id;
+ uint8_t node_name[WWN_SIZE];
+ uint8_t port_name[WWN_SIZE];
++ uint8_t fabric_port_name[WWN_SIZE];
++ uint16_t fp_speeds;
++ uint16_t fp_speed;
+ } sw_info_t;
+
+ /*
+@@ -1524,6 +1528,9 @@ typedef struct fc_port {
+ uint16_t loop_id;
+ uint16_t old_loop_id;
+
++ uint8_t fabric_port_name[WWN_SIZE];
++ uint16_t fp_speed;
++
+ fc_port_type_t port_type;
+
+ atomic_t state;
+@@ -1538,6 +1545,9 @@ typedef struct fc_port {
+ spinlock_t rport_lock;
+ struct fc_rport *rport, *drport;
+ u32 supported_classes;
++
++ unsigned long last_queue_full;
++ unsigned long last_ramp_up;
+ } fc_port_t;
+
+ /*
+@@ -1635,6 +1645,15 @@ typedef struct fc_port {
+ #define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
+ #define RSNN_NN_RSP_SIZE 16
+
++#define GFPN_ID_CMD 0x11C
++#define GFPN_ID_REQ_SIZE (16 + 4)
++#define GFPN_ID_RSP_SIZE (16 + 8)
++
++#define GPSC_CMD 0x127
++#define GPSC_REQ_SIZE (16 + 8)
++#define GPSC_RSP_SIZE (16 + 2 + 2)
++
++
+ /*
+ * HBA attribute types.
+ */
+@@ -1748,7 +1767,7 @@ struct ct_sns_req {
+ uint8_t reserved[3];
+
+ union {
+- /* GA_NXT, GPN_ID, GNN_ID, GFT_ID */
++ /* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */
+ struct {
+ uint8_t reserved;
+ uint8_t port_id[3];
+@@ -1823,6 +1842,10 @@ struct ct_sns_req {
+ struct {
+ uint8_t port_name[8];
+ } dpa;
++
++ struct {
++ uint8_t port_name[8];
++ } gpsc;
+ } req;
+ };
+
+@@ -1886,6 +1909,15 @@ struct ct_sns_rsp {
+ uint8_t port_name[8];
+ struct ct_fdmi_hba_attributes attrs;
+ } ghat;
++
++ struct {
++ uint8_t port_name[8];
++ } gfpn_id;
++
++ struct {
++ uint16_t speeds;
++ uint16_t speed;
++ } gpsc;
+ } rsp;
+ };
+
+@@ -1980,7 +2012,7 @@ struct isp_operations {
+ char * (*pci_info_str) (struct scsi_qla_host *, char *);
+ char * (*fw_version_str) (struct scsi_qla_host *, char *);
+
+- irqreturn_t (*intr_handler) (int, void *, struct pt_regs *);
++ irq_handler_t intr_handler;
+ void (*enable_intrs) (struct scsi_qla_host *);
+ void (*disable_intrs) (struct scsi_qla_host *);
+
+@@ -2182,11 +2214,11 @@ typedef struct scsi_qla_host {
+ uint16_t max_public_loop_ids;
+ uint16_t min_external_loopid; /* First external loop Id */
+
++#define PORT_SPEED_UNKNOWN 0xFFFF
++#define PORT_SPEED_1GB 0x00
++#define PORT_SPEED_2GB 0x01
++#define PORT_SPEED_4GB 0x03
+ uint16_t link_data_rate; /* F/W operating speed */
+-#define LDR_1GB 0
+-#define LDR_2GB 1
+-#define LDR_4GB 3
+-#define LDR_UNKNOWN 0xFFFF
+
+ uint8_t current_topology;
+ uint8_t prev_topology;
+@@ -2226,6 +2258,7 @@ typedef struct scsi_qla_host {
+ uint16_t mgmt_svr_loop_id;
+
+ uint32_t login_retry_count;
++ int max_q_depth;
+
+ /* Fibre Channel Device List. */
+ struct list_head fcports;
+@@ -2333,6 +2366,7 @@ typedef struct scsi_qla_host {
+
+ uint8_t *node_name;
+ uint8_t *port_name;
++ uint8_t fabric_node_name[WWN_SIZE];
+ uint32_t isp_abort_cnt;
+
+ /* Option ROM information. */
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index 8311ac2..32ebeec 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -48,6 +48,7 @@ extern void qla2x00_update_fcport(scsi_q
+ extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
+
+ extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
++extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
+
+ /*
+ * Global Data in qla_os.c source file.
+@@ -60,7 +61,8 @@ extern int ql2xplogiabsentdevice;
+ extern int ql2xloginretrycount;
+ extern int ql2xfdmienable;
+ extern int ql2xallocfwdump;
+-extern int extended_error_logging;
++extern int ql2xextended_error_logging;
++extern int ql2xqfullrampup;
+
+ extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
+
+@@ -208,12 +210,18 @@ qla2x00_trace_control(scsi_qla_host_t *,
+ extern int
+ qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+
++extern int
++qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
++
++extern int
++qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
++
+ /*
+ * Global Function Prototypes in qla_isr.c source file.
+ */
+-extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *);
+-extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *);
+-extern irqreturn_t qla24xx_intr_handler(int, void *, struct pt_regs *);
++extern irqreturn_t qla2100_intr_handler(int, void *);
++extern irqreturn_t qla2300_intr_handler(int, void *);
++extern irqreturn_t qla24xx_intr_handler(int, void *);
+ extern void qla2x00_process_response_queue(struct scsi_qla_host *);
+ extern void qla24xx_process_response_queue(struct scsi_qla_host *);
+
+@@ -279,6 +287,9 @@ extern int qla2x00_rsnn_nn(scsi_qla_host
+ extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
+ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
+ extern int qla2x00_fdmi_register(scsi_qla_host_t *);
++extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *);
++extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *);
++extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *);
+
+ /*
+ * Global Function Prototypes in qla_attr.c source file.
+diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
+index 2ebf259..97fbc62 100644
+--- a/drivers/scsi/qla2xxx/qla_gs.c
++++ b/drivers/scsi/qla2xxx/qla_gs.c
+@@ -612,6 +612,14 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
+ return (rval);
+ }
+
++void
++qla2x00_get_sym_node_name(scsi_qla_host_t *ha, uint8_t *snn)
++{
++ sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
++ ha->fw_major_version, ha->fw_minor_version,
++ ha->fw_subminor_version, qla2x00_version_str);
++}
++
+ /**
+ * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
+ * @ha: HA context
+@@ -622,9 +630,6 @@ int
+ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
+ {
+ int rval;
+- uint8_t *snn;
+- uint8_t version[20];
+-
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+@@ -649,20 +654,11 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
+ memcpy(ct_req->req.rsnn_nn.node_name, ha->node_name, WWN_SIZE);
+
+ /* Prepare the Symbolic Node Name */
+- /* Board type */
+- snn = ct_req->req.rsnn_nn.sym_node_name;
+- strcpy(snn, ha->model_number);
+- /* Firmware version */
+- strcat(snn, " FW:v");
+- sprintf(version, "%d.%02d.%02d", ha->fw_major_version,
+- ha->fw_minor_version, ha->fw_subminor_version);
+- strcat(snn, version);
+- /* Driver version */
+- strcat(snn, " DVR:v");
+- strcat(snn, qla2x00_version_str);
++ qla2x00_get_sym_node_name(ha, ct_req->req.rsnn_nn.sym_node_name);
+
+ /* Calculate SNN length */
+- ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn);
++ ct_req->req.rsnn_nn.name_len =
++ (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name);
+
+ /* Update MS IOCB request */
+ ms_pkt->req_bytecount =
+@@ -687,7 +683,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
+ return (rval);
+ }
+
+-
+ /**
+ * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
+ * @ha: HA context
+@@ -1585,6 +1580,21 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
+ DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
+ eiter->a.os_dev_name));
+
++ /* Hostname. */
++ if (strlen(fc_host_system_hostname(ha->host))) {
++ eiter = (struct ct_fdmi_port_attr *) (entries + size);
++ eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
++ snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
++ "%s", fc_host_system_hostname(ha->host));
++ alen = strlen(eiter->a.host_name);
++ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
++ eiter->len = cpu_to_be16(4 + alen);
++ size += 4 + alen;
++
++ DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
++ ha->host_no, eiter->a.host_name));
++ }
++
+ /* Update MS request size. */
+ qla2x00_update_ms_fdmi_iocb(ha, size + 16);
+
+@@ -1647,3 +1657,189 @@ qla2x00_fdmi_register(scsi_qla_host_t *h
+
+ return rval;
+ }
++
++/**
++ * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
++ * @ha: HA context
++ * @list: switch info entries to populate
++ *
++ * Returns 0 on success.
++ */
++int
++qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
++{
++ int rval;
++ uint16_t i;
++
++ ms_iocb_entry_t *ms_pkt;
++ struct ct_sns_req *ct_req;
++ struct ct_sns_rsp *ct_rsp;
++
++ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
++ return QLA_FUNCTION_FAILED;
++
++ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
++ /* Issue GFPN_ID */
++ memset(list[i].fabric_port_name, 0, WWN_SIZE);
++
++ /* Prepare common MS IOCB */
++ ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
++ GFPN_ID_RSP_SIZE);
++
++ /* Prepare CT request */
++ ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
++ GFPN_ID_RSP_SIZE);
++ ct_rsp = &ha->ct_sns->p.rsp;
++
++ /* Prepare CT arguments -- port_id */
++ ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
++ ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
++ ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
++
++ /* Execute MS IOCB */
++ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
++ sizeof(ms_iocb_entry_t));
++ if (rval != QLA_SUCCESS) {
++ /*EMPTY*/
++ DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
++ "failed (%d).\n", ha->host_no, rval));
++ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
++ "GFPN_ID") != QLA_SUCCESS) {
++ rval = QLA_FUNCTION_FAILED;
++ } else {
++ /* Save fabric portname */
++ memcpy(list[i].fabric_port_name,
++ ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE);
++ }
++
++ /* Last device exit. */
++ if (list[i].d_id.b.rsvd_1 != 0)
++ break;
++ }
++
++ return (rval);
++}
++
++static inline void *
++qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
++ uint32_t rsp_size)
++{
++ struct ct_entry_24xx *ct_pkt;
++
++ ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
++ memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
++
++ ct_pkt->entry_type = CT_IOCB_TYPE;
++ ct_pkt->entry_count = 1;
++ ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
++ ct_pkt->timeout = __constant_cpu_to_le16(59);
++ ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
++ ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
++ ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
++ ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
++
++ ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
++ ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
++ ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
++
++ ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
++ ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
++ ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
++
++ return ct_pkt;
++}
++
++
++static inline struct ct_sns_req *
++qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
++ uint16_t rsp_size)
++{
++ memset(ct_req, 0, sizeof(struct ct_sns_pkt));
++
++ ct_req->header.revision = 0x01;
++ ct_req->header.gs_type = 0xFA;
++ ct_req->header.gs_subtype = 0x01;
++ ct_req->command = cpu_to_be16(cmd);
++ ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
++
++ return ct_req;
++}
++
++/**
++ * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
++ * @ha: HA context
++ * @list: switch info entries to populate
++ *
++ * Returns 0 on success.
++ */
++int
++qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
++{
++ int rval;
++ uint16_t i;
++
++ ms_iocb_entry_t *ms_pkt;
++ struct ct_sns_req *ct_req;
++ struct ct_sns_rsp *ct_rsp;
++
++ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
++ return QLA_FUNCTION_FAILED;
++
++ rval = qla2x00_mgmt_svr_login(ha);
++ if (rval)
++ return rval;
++
++ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
++ /* Issue GFPN_ID */
++ list[i].fp_speeds = list[i].fp_speed = 0;
++
++ /* Prepare common MS IOCB */
++ ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
++ GPSC_RSP_SIZE);
++
++ /* Prepare CT request */
++ ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
++ GPSC_CMD, GPSC_RSP_SIZE);
++ ct_rsp = &ha->ct_sns->p.rsp;
++
++ /* Prepare CT arguments -- port_name */
++ memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name,
++ WWN_SIZE);
++
++ /* Execute MS IOCB */
++ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
++ sizeof(ms_iocb_entry_t));
++ if (rval != QLA_SUCCESS) {
++ /*EMPTY*/
++ DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
++ "failed (%d).\n", ha->host_no, rval));
++ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
++ "GPSC") != QLA_SUCCESS) {
++ rval = QLA_FUNCTION_FAILED;
++ } else {
++ /* Save portname */
++ list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
++ list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
++
++ DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
++ "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
++ "speed=%04x.\n", ha->host_no,
++ list[i].fabric_port_name[0],
++ list[i].fabric_port_name[1],
++ list[i].fabric_port_name[2],
++ list[i].fabric_port_name[3],
++ list[i].fabric_port_name[4],
++ list[i].fabric_port_name[5],
++ list[i].fabric_port_name[6],
++ list[i].fabric_port_name[7],
++ be16_to_cpu(list[i].fp_speeds),
++ be16_to_cpu(list[i].fp_speed)));
++ }
++
++ /* Last device exit. */
++ if (list[i].d_id.b.rsvd_1 != 0)
++ break;
++ }
++
++ return (rval);
++}
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 8596491..08cb5e3 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -1644,7 +1644,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha
+ * Set host adapter parameters.
+ */
+ if (nv->host_p[0] & BIT_7)
+- extended_error_logging = 1;
++ ql2xextended_error_logging = 1;
+ ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
+ /* Always load RISC code on non ISP2[12]00 chips. */
+ if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
+@@ -2074,6 +2074,19 @@ qla2x00_configure_local_loop(scsi_qla_ho
+ new_fcport->flags &= ~FCF_FABRIC_DEVICE;
+ }
+
++ /* Base iIDMA settings on HBA port speed. */
++ switch (ha->link_data_rate) {
++ case PORT_SPEED_1GB:
++ fcport->fp_speed = cpu_to_be16(BIT_15);
++ break;
++ case PORT_SPEED_2GB:
++ fcport->fp_speed = cpu_to_be16(BIT_14);
++ break;
++ case PORT_SPEED_4GB:
++ fcport->fp_speed = cpu_to_be16(BIT_13);
++ break;
++ }
++
+ qla2x00_update_fcport(ha, fcport);
+
+ found_devs++;
+@@ -2109,6 +2122,62 @@ qla2x00_probe_for_all_luns(scsi_qla_host
+ }
+ }
+
++static void
++qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
++{
++#define LS_UNKNOWN 2
++ static char *link_speeds[5] = { "1", "2", "?", "4" };
++ int rval;
++ uint16_t port_speed, mb[6];
++
++ if (!IS_QLA24XX(ha))
++ return;
++
++ switch (be16_to_cpu(fcport->fp_speed)) {
++ case BIT_15:
++ port_speed = PORT_SPEED_1GB;
++ break;
++ case BIT_14:
++ port_speed = PORT_SPEED_2GB;
++ break;
++ case BIT_13:
++ port_speed = PORT_SPEED_4GB;
++ break;
++ default:
++ DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
++ "unsupported FM port operating speed (%04x).\n",
++ ha->host_no, fcport->port_name[0], fcport->port_name[1],
++ fcport->port_name[2], fcport->port_name[3],
++ fcport->port_name[4], fcport->port_name[5],
++ fcport->port_name[6], fcport->port_name[7],
++ be16_to_cpu(fcport->fp_speed)));
++ port_speed = PORT_SPEED_UNKNOWN;
++ break;
++ }
++ if (port_speed == PORT_SPEED_UNKNOWN)
++ return;
++
++ rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
++ if (rval != QLA_SUCCESS) {
++ DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
++ "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
++ ha->host_no, fcport->port_name[0], fcport->port_name[1],
++ fcport->port_name[2], fcport->port_name[3],
++ fcport->port_name[4], fcport->port_name[5],
++ fcport->port_name[6], fcport->port_name[7], rval,
++ port_speed, mb[0], mb[1]));
++ } else {
++ DEBUG2(qla_printk(KERN_INFO, ha,
++ "iIDMA adjusted to %s GB/s on "
++ "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
++ link_speeds[port_speed], fcport->port_name[0],
++ fcport->port_name[1], fcport->port_name[2],
++ fcport->port_name[3], fcport->port_name[4],
++ fcport->port_name[5], fcport->port_name[6],
++ fcport->port_name[7]));
++ }
++}
++
+ /*
+ * qla2x00_update_fcport
+ * Updates device on list.
+@@ -2135,6 +2204,8 @@ qla2x00_update_fcport(scsi_qla_host_t *h
+ PORT_RETRY_TIME);
+ fcport->flags &= ~FCF_LOGIN_NEEDED;
+
++ qla2x00_iidma_fcport(ha, fcport);
++
+ atomic_set(&fcport->state, FCS_ONLINE);
+
+ if (ha->flags.init_done)
+@@ -2209,7 +2280,7 @@ qla2x00_configure_fabric(scsi_qla_host_t
+ loop_id = NPH_F_PORT;
+ else
+ loop_id = SNS_FL_PORT;
+- rval = qla2x00_get_port_name(ha, loop_id, NULL, 0);
++ rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
+ "Port\n", ha->host_no));
+@@ -2217,6 +2288,7 @@ qla2x00_configure_fabric(scsi_qla_host_t
+ ha->device_flags &= ~SWITCH_FOUND;
+ return (QLA_SUCCESS);
+ }
++ ha->device_flags |= SWITCH_FOUND;
+
+ /* Mark devices that need re-synchronization. */
+ rval2 = qla2x00_device_resync(ha);
+@@ -2416,6 +2488,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_ho
+ } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
+ kfree(swl);
+ swl = NULL;
++ } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
++ qla2x00_gpsc(ha, swl);
+ }
+ }
+ swl_idx = 0;
+@@ -2450,6 +2524,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_ho
+ swl[swl_idx].node_name, WWN_SIZE);
+ memcpy(new_fcport->port_name,
+ swl[swl_idx].port_name, WWN_SIZE);
++ memcpy(new_fcport->fabric_port_name,
++ swl[swl_idx].fabric_port_name, WWN_SIZE);
++ new_fcport->fp_speed = swl[swl_idx].fp_speed;
+
+ if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
+ last_dev = 1;
+@@ -2507,6 +2584,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_ho
+
+ found++;
+
++ /* Update port state. */
++ memcpy(fcport->fabric_port_name,
++ new_fcport->fabric_port_name, WWN_SIZE);
++ fcport->fp_speed = new_fcport->fp_speed;
++
+ /*
+ * If address the same and state FCS_ONLINE, nothing
+ * changed.
+@@ -3866,3 +3948,24 @@ qla24xx_load_risc(scsi_qla_host_t *ha, u
+ fail_fw_integrity:
+ return QLA_FUNCTION_FAILED;
+ }
++
++void
++qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
++{
++ int ret, retries;
++
++ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
++ return;
++
++ ret = qla2x00_stop_firmware(ha);
++ for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
++ qla2x00_reset_chip(ha);
++ if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
++ continue;
++ if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
++ continue;
++ qla_printk(KERN_INFO, ha,
++ "Attempting retry of stop-firmware command...\n");
++ ret = qla2x00_stop_firmware(ha);
++ }
++}
+diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
+index 45007ee..d302333 100644
+--- a/drivers/scsi/qla2xxx/qla_inline.h
++++ b/drivers/scsi/qla2xxx/qla_inline.h
+@@ -104,7 +104,7 @@ static __inline__ void qla2x00_poll(scsi
+ static inline void
+ qla2x00_poll(scsi_qla_host_t *ha)
+ {
+- ha->isp_ops.intr_handler(0, ha, NULL);
++ ha->isp_ops.intr_handler(0, ha);
+ }
+
+ static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
+diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
+index de06131..d3b6df4 100644
+--- a/drivers/scsi/qla2xxx/qla_isr.c
++++ b/drivers/scsi/qla2xxx/qla_isr.c
+@@ -6,6 +6,8 @@
+ */
+ #include "qla_def.h"
+
++#include <scsi/scsi_tcq.h>
++
+ static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
+ static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
+ static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
+@@ -20,14 +22,13 @@ static void qla24xx_ms_entry(scsi_qla_ho
+ * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+- * @regs:
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+ irqreturn_t
+-qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
++qla2100_intr_handler(int irq, void *dev_id)
+ {
+ scsi_qla_host_t *ha;
+ struct device_reg_2xxx __iomem *reg;
+@@ -100,14 +101,13 @@ qla2100_intr_handler(int irq, void *dev_
+ * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+- * @regs:
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+ irqreturn_t
+-qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
++qla2300_intr_handler(int irq, void *dev_id)
+ {
+ scsi_qla_host_t *ha;
+ struct device_reg_2xxx __iomem *reg;
+@@ -400,7 +400,7 @@ qla2x00_async_event(scsi_qla_host_t *ha,
+ case MBA_LOOP_UP: /* Loop Up Event */
+ if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+ link_speed = link_speeds[0];
+- ha->link_data_rate = LDR_1GB;
++ ha->link_data_rate = PORT_SPEED_1GB;
+ } else {
+ link_speed = link_speeds[LS_UNKNOWN];
+ if (mb[1] < 5)
+@@ -429,7 +429,7 @@ qla2x00_async_event(scsi_qla_host_t *ha,
+ }
+
+ ha->flags.management_server_logged_in = 0;
+- ha->link_data_rate = LDR_UNKNOWN;
++ ha->link_data_rate = PORT_SPEED_UNKNOWN;
+ if (ql2xfdmienable)
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
+ break;
+@@ -595,6 +595,67 @@ qla2x00_async_event(scsi_qla_host_t *ha,
+ }
+ }
+
++static void
++qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
++{
++ fc_port_t *fcport = data;
++
++ if (fcport->ha->max_q_depth <= sdev->queue_depth)
++ return;
++
++ if (sdev->ordered_tags)
++ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
++ sdev->queue_depth + 1);
++ else
++ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
++ sdev->queue_depth + 1);
++
++ fcport->last_ramp_up = jiffies;
++
++ DEBUG2(qla_printk(KERN_INFO, fcport->ha,
++ "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
++ fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
++ sdev->queue_depth));
++}
++
++static void
++qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
++{
++ fc_port_t *fcport = data;
++
++ if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
++ return;
++
++ DEBUG2(qla_printk(KERN_INFO, fcport->ha,
++ "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
++ fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
++ sdev->queue_depth));
++}
++
++static inline void
++qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
++{
++ fc_port_t *fcport;
++ struct scsi_device *sdev;
++
++ sdev = sp->cmd->device;
++ if (sdev->queue_depth >= ha->max_q_depth)
++ return;
++
++ fcport = sp->fcport;
++ if (time_before(jiffies,
++ fcport->last_ramp_up + ql2xqfullrampup * HZ))
++ return;
++ if (time_before(jiffies,
++ fcport->last_queue_full + ql2xqfullrampup * HZ))
++ return;
++
++ spin_unlock_irq(&ha->hardware_lock);
++ starget_for_each_device(sdev->sdev_target, fcport,
++ qla2x00_adjust_sdev_qdepth_up);
++ spin_lock_irq(&ha->hardware_lock);
++}
++
+ /**
+ * qla2x00_process_completed_request() - Process a Fast Post response.
+ * @ha: SCSI driver HA context
+@@ -626,6 +687,8 @@ qla2x00_process_completed_request(struct
+
+ /* Save ISP completion status */
+ sp->cmd->result = DID_OK << 16;
++
++ qla2x00_ramp_up_queue_depth(ha, sp);
+ qla2x00_sp_compl(ha, sp);
+ } else {
+ DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
+@@ -825,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha
+ */
+ switch (comp_status) {
+ case CS_COMPLETE:
++ case CS_QUEUE_FULL:
+ if (scsi_status == 0) {
+ cp->result = DID_OK << 16;
+ break;
+@@ -851,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha
+ }
+ cp->result = DID_OK << 16 | lscsi_status;
+
++ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
++ DEBUG2(printk(KERN_INFO
++ "scsi(%ld): QUEUE FULL status detected "
++ "0x%x-0x%x.\n", ha->host_no, comp_status,
++ scsi_status));
++
++ /* Adjust queue depth for all luns on the port. */
++ fcport->last_queue_full = jiffies;
++ spin_unlock_irq(&ha->hardware_lock);
++ starget_for_each_device(cp->device->sdev_target,
++ fcport, qla2x00_adjust_sdev_qdepth_down);
++ spin_lock_irq(&ha->hardware_lock);
++ break;
++ }
+ if (lscsi_status != SS_CHECK_CONDITION)
+ break;
+
+@@ -1068,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha
+ qla2x00_mark_device_lost(ha, fcport, 1, 1);
+ break;
+
+- case CS_QUEUE_FULL:
+- DEBUG2(printk(KERN_INFO
+- "scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n",
+- ha->host_no, comp_status, scsi_status));
+-
+- /* SCSI Mid-Layer handles device queue full */
+-
+- cp->result = DID_OK << 16 | lscsi_status;
+-
+- break;
+-
+ default:
+ DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
+ "0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status));
+@@ -1338,14 +1405,13 @@ qla24xx_process_response_queue(struct sc
+ * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+- * @regs:
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+ irqreturn_t
+-qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
++qla24xx_intr_handler(int irq, void *dev_id)
+ {
+ scsi_qla_host_t *ha;
+ struct device_reg_24xx __iomem *reg;
+diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
+index 879f281..4cde76c 100644
+--- a/drivers/scsi/qla2xxx/qla_mbx.c
++++ b/drivers/scsi/qla2xxx/qla_mbx.c
+@@ -2540,3 +2540,89 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dm
+
+ return rval;
+ }
++
++int
++qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
++ uint16_t *port_speed, uint16_t *mb)
++{
++ int rval;
++ mbx_cmd_t mc;
++ mbx_cmd_t *mcp = &mc;
++
++ if (!IS_QLA24XX(ha))
++ return QLA_FUNCTION_FAILED;
++
++ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
++
++ mcp->mb[0] = MBC_PORT_PARAMS;
++ mcp->mb[1] = loop_id;
++ mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
++ mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
++ mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
++ mcp->tov = 30;
++ mcp->flags = 0;
++ rval = qla2x00_mailbox_command(ha, mcp);
++
++ /* Return mailbox statuses. */
++ if (mb != NULL) {
++ mb[0] = mcp->mb[0];
++ mb[1] = mcp->mb[1];
++ mb[3] = mcp->mb[3];
++ mb[4] = mcp->mb[4];
++ mb[5] = mcp->mb[5];
++ }
++
++ if (rval != QLA_SUCCESS) {
++ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
++ ha->host_no, rval));
++ } else {
++ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
++ if (port_speed)
++ *port_speed = mcp->mb[3];
++ }
++
++ return rval;
++}
++
++int
++qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
++ uint16_t port_speed, uint16_t *mb)
++{
++ int rval;
++ mbx_cmd_t mc;
++ mbx_cmd_t *mcp = &mc;
++
++ if (!IS_QLA24XX(ha))
++ return QLA_FUNCTION_FAILED;
++
++ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
++
++ mcp->mb[0] = MBC_PORT_PARAMS;
++ mcp->mb[1] = loop_id;
++ mcp->mb[2] = BIT_0;
++ mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
++ mcp->mb[4] = mcp->mb[5] = 0;
++ mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
++ mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
++ mcp->tov = 30;
++ mcp->flags = 0;
++ rval = qla2x00_mailbox_command(ha, mcp);
++
++ /* Return mailbox statuses. */
++ if (mb != NULL) {
++ mb[0] = mcp->mb[0];
++ mb[1] = mcp->mb[1];
++ mb[3] = mcp->mb[3];
++ mb[4] = mcp->mb[4];
++ mb[5] = mcp->mb[5];
++ }
++
++ if (rval != QLA_SUCCESS) {
++ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
++ ha->host_no, rval));
++ } else {
++ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
++ }
++
++ return rval;
++}
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index 65cbe2f..208607b 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -61,9 +61,9 @@ MODULE_PARM_DESC(ql2xallocfwdump,
+ "during HBA initialization. Memory allocation requirements "
+ "vary by ISP type. Default is 1 - allocate memory.");
+
+-int extended_error_logging;
+-module_param(extended_error_logging, int, S_IRUGO|S_IRUSR);
+-MODULE_PARM_DESC(extended_error_logging,
++int ql2xextended_error_logging;
++module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR);
++MODULE_PARM_DESC(ql2xextended_error_logging,
+ "Option to enable extended error logging, "
+ "Default is 0 - no logging. 1 - log errors.");
+
+@@ -77,6 +77,19 @@ MODULE_PARM_DESC(ql2xfdmienable,
+ "Enables FDMI registratons "
+ "Default is 0 - no FDMI. 1 - perfom FDMI.");
+
++#define MAX_Q_DEPTH 32
++static int ql2xmaxqdepth = MAX_Q_DEPTH;
++module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(ql2xmaxqdepth,
++ "Maximum queue depth to report for target devices.");
++
++int ql2xqfullrampup = 120;
++module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(ql2xqfullrampup,
++ "Number of seconds to wait to begin to ramp-up the queue "
++ "depth for a device after a queue-full condition has been "
++ "detected. Default is 120 seconds.");
++
+ /*
+ * SCSI host template entry points
+ */
+@@ -589,6 +602,23 @@ qla2x00_wait_for_loop_ready(scsi_qla_hos
+ return (return_status);
+ }
+
++static void
++qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
++{
++ struct Scsi_Host *shost = cmnd->device->host;
++ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
++ unsigned long flags;
++
++ spin_lock_irqsave(shost->host_lock, flags);
++ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
++ spin_unlock_irqrestore(shost->host_lock, flags);
++ msleep(1000);
++ spin_lock_irqsave(shost->host_lock, flags);
++ }
++ spin_unlock_irqrestore(shost->host_lock, flags);
++ return;
++}
++
+ /**************************************************************************
+ * qla2xxx_eh_abort
+ *
+@@ -615,6 +645,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
+ unsigned long flags;
+ int wait = 0;
+
++ qla2x00_block_error_handler(cmd);
++
+ if (!CMD_SP(cmd))
+ return SUCCESS;
+
+@@ -748,6 +780,8 @@ qla2xxx_eh_device_reset(struct scsi_cmnd
+ unsigned int id, lun;
+ unsigned long serial;
+
++ qla2x00_block_error_handler(cmd);
++
+ ret = FAILED;
+
+ id = cmd->device->id;
+@@ -877,6 +911,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *c
+ unsigned int id, lun;
+ unsigned long serial;
+
++ qla2x00_block_error_handler(cmd);
++
+ ret = FAILED;
+
+ id = cmd->device->id;
+@@ -936,6 +972,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *
+ unsigned int id, lun;
+ unsigned long serial;
+
++ qla2x00_block_error_handler(cmd);
++
+ ret = FAILED;
+
+ id = cmd->device->id;
+@@ -1079,9 +1117,9 @@ qla2xxx_slave_configure(struct scsi_devi
+ struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
+
+ if (sdev->tagged_supported)
+- scsi_activate_tcq(sdev, 32);
++ scsi_activate_tcq(sdev, ha->max_q_depth);
+ else
+- scsi_deactivate_tcq(sdev, 32);
++ scsi_deactivate_tcq(sdev, ha->max_q_depth);
+
+ rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+
+@@ -1385,9 +1423,13 @@ qla2x00_probe_one(struct pci_dev *pdev,
+ ha->prev_topology = 0;
+ ha->init_cb_size = sizeof(init_cb_t);
+ ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+- ha->link_data_rate = LDR_UNKNOWN;
++ ha->link_data_rate = PORT_SPEED_UNKNOWN;
+ ha->optrom_size = OPTROM_SIZE_2300;
+
++ ha->max_q_depth = MAX_Q_DEPTH;
++ if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
++ ha->max_q_depth = ql2xmaxqdepth;
++
+ /* Assign ISP specific operations. */
+ ha->isp_ops.pci_config = qla2100_pci_config;
+ ha->isp_ops.reset_chip = qla2x00_reset_chip;
+@@ -1687,8 +1729,10 @@ qla2x00_free_device(scsi_qla_host_t *ha)
+ if (ha->eft)
+ qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
+
++ ha->flags.online = 0;
++
+ /* Stop currently executing firmware. */
+- qla2x00_stop_firmware(ha);
++ qla2x00_try_to_stop_firmware(ha);
+
+ /* turn-off interrupts on the card */
+ if (ha->interrupts_on)
+@@ -1696,8 +1740,6 @@ qla2x00_free_device(scsi_qla_host_t *ha)
+
+ qla2x00_mem_free(ha);
+
+- ha->flags.online = 0;
+-
+ /* Detach interrupts */
+ if (ha->host->irq)
+ free_irq(ha->host->irq, ha);
+@@ -2564,14 +2606,20 @@ qla2x00_down_timeout(struct semaphore *s
+ #define FW_ISP2322 3
+ #define FW_ISP24XX 4
+
++#define FW_FILE_ISP21XX "ql2100_fw.bin"
++#define FW_FILE_ISP22XX "ql2200_fw.bin"
++#define FW_FILE_ISP2300 "ql2300_fw.bin"
++#define FW_FILE_ISP2322 "ql2322_fw.bin"
++#define FW_FILE_ISP24XX "ql2400_fw.bin"
++
+ static DECLARE_MUTEX(qla_fw_lock);
+
+ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
+- { .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, },
+- { .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, },
+- { .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, },
+- { .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
+- { .name = "ql2400_fw.bin", },
++ { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
++ { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
++ { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
++ { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
++ { .name = FW_FILE_ISP24XX, },
+ };
+
+ struct fw_blob *
+@@ -2666,7 +2714,7 @@ qla2x00_module_init(void)
+
+ /* Derive version string. */
+ strcpy(qla2x00_version_str, QLA2XXX_VERSION);
+- if (extended_error_logging)
++ if (ql2xextended_error_logging)
+ strcat(qla2x00_version_str, "-debug");
+
+ qla2xxx_transport_template =
+@@ -2702,3 +2750,8 @@ MODULE_AUTHOR("QLogic Corporation");
+ MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(QLA2XXX_VERSION);
++MODULE_FIRMWARE(FW_FILE_ISP21XX);
++MODULE_FIRMWARE(FW_FILE_ISP22XX);
++MODULE_FIRMWARE(FW_FILE_ISP2300);
++MODULE_FIRMWARE(FW_FILE_ISP2322);
++MODULE_FIRMWARE(FW_FILE_ISP24XX);
+diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
+index 9712590..1fa0bce 100644
+--- a/drivers/scsi/qla2xxx/qla_version.h
++++ b/drivers/scsi/qla2xxx/qla_version.h
+@@ -7,7 +7,7 @@
+ /*
+ * Driver version
+ */
+-#define QLA2XXX_VERSION "8.01.07-k1"
++#define QLA2XXX_VERSION "8.01.07-k3"
+
+ #define QLA_DRIVER_MAJOR_VER 8
+ #define QLA_DRIVER_MINOR_VER 1
+diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
+new file mode 100644
+index 0000000..69cbff3
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/Kconfig
+@@ -0,0 +1,7 @@
++config SCSI_QLA_ISCSI
++ tristate "QLogic ISP4XXX host adapter family support"
++ depends on PCI && SCSI && NET
++ select SCSI_ISCSI_ATTRS
++ ---help---
++ This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
++ adapter family.
+diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
+new file mode 100644
+index 0000000..86ea37b
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/Makefile
+@@ -0,0 +1,5 @@
++qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
++ ql4_nvram.o ql4_dbg.o
++
++obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
++
+diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
+new file mode 100644
+index 0000000..752031f
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_dbg.c
+@@ -0,0 +1,197 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#include "ql4_def.h"
++#include <scsi/scsi_dbg.h>
++
++static void qla4xxx_print_srb_info(struct srb * srb)
++{
++ printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
++ printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
++ __func__, srb->cmd, (unsigned long) srb->dma_handle);
++ printk("%s: fw_ddb_index = %d, lun = %d\n",
++ __func__, srb->fw_ddb_index, srb->cmd->device->lun);
++ printk("%s: iocb_tov = %d\n",
++ __func__, srb->iocb_tov);
++ printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n",
++ __func__, srb->cc_stat, srb->r_start, srb->u_start);
++}
++
++void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
++{
++ printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
++ printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
++ cmd->device->channel, cmd->device->id, cmd->device->lun,
++ cmd->cmd_len);
++ scsi_print_command(cmd);
++ printk(" seg_cnt = %d\n", cmd->use_sg);
++ printk(" request buffer = 0x%p, request buffer len = 0x%x\n",
++ cmd->request_buffer, cmd->request_bufflen);
++ if (cmd->use_sg) {
++ struct scatterlist *sg;
++ sg = (struct scatterlist *)cmd->request_buffer;
++ printk(" SG buffer: \n");
++ qla4xxx_dump_buffer((caddr_t) sg,
++ (cmd->use_sg * sizeof(*sg)));
++ }
++ printk(" tag = %d, transfersize = 0x%x \n", cmd->tag,
++ cmd->transfersize);
++ printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr);
++ printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow,
++ cmd->sc_data_direction);
++ printk(" Current time (jiffies) = 0x%lx, "
++ "timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires);
++ qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
++}
++
++void __dump_registers(struct scsi_qla_host *ha)
++{
++ uint8_t i;
++ for (i = 0; i < MBOX_REG_COUNT; i++) {
++ printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
++ readw(&ha->reg->mailbox[i]));
++ }
++ printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, flash_address),
++ readw(&ha->reg->flash_address));
++ printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, flash_data),
++ readw(&ha->reg->flash_data));
++ printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, ctrl_status),
++ readw(&ha->reg->ctrl_status));
++ if (is_qla4010(ha)) {
++ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
++ readw(&ha->reg->u1.isp4010.nvram));
++ }
++
++ else if (is_qla4022(ha)) {
++ printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u1.isp4022.intr_mask),
++ readw(&ha->reg->u1.isp4022.intr_mask));
++ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
++ readw(&ha->reg->u1.isp4022.nvram));
++ printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u1.isp4022.semaphore),
++ readw(&ha->reg->u1.isp4022.semaphore));
++ }
++ printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, req_q_in),
++ readw(&ha->reg->req_q_in));
++ printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, rsp_q_out),
++ readw(&ha->reg->rsp_q_out));
++ if (is_qla4010(ha)) {
++ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4010.ext_hw_conf),
++ readw(&ha->reg->u2.isp4010.ext_hw_conf));
++ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4010.port_ctrl),
++ readw(&ha->reg->u2.isp4010.port_ctrl));
++ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4010.port_status),
++ readw(&ha->reg->u2.isp4010.port_status));
++ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4010.req_q_out),
++ readw(&ha->reg->u2.isp4010.req_q_out));
++ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
++ readw(&ha->reg->u2.isp4010.gp_out));
++ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
++ readw(&ha->reg->u2.isp4010.gp_in));
++ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4010.port_err_status),
++ readw(&ha->reg->u2.isp4010.port_err_status));
++ }
++
++ else if (is_qla4022(ha)) {
++ printk(KERN_INFO "Page 0 Registers:\n");
++ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4022.p0.ext_hw_conf),
++ readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
++ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4022.p0.port_ctrl),
++ readw(&ha->reg->u2.isp4022.p0.port_ctrl));
++ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4022.p0.port_status),
++ readw(&ha->reg->u2.isp4022.p0.port_status));
++ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4022.p0.gp_out),
++ readw(&ha->reg->u2.isp4022.p0.gp_out));
++ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
++ readw(&ha->reg->u2.isp4022.p0.gp_in));
++ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4022.p0.port_err_status),
++ readw(&ha->reg->u2.isp4022.p0.port_err_status));
++ printk(KERN_INFO "Page 1 Registers:\n");
++ writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
++ &ha->reg->ctrl_status);
++ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
++ (uint8_t) offsetof(struct isp_reg,
++ u2.isp4022.p1.req_q_out),
++ readw(&ha->reg->u2.isp4022.p1.req_q_out));
++ writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
++ &ha->reg->ctrl_status);
++ }
++}
++
++void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
++{
++ unsigned long flags = 0;
++ int i = 0;
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ for (i = 1; i < MBOX_REG_COUNT; i++)
++ printk(KERN_INFO " Mailbox[%d] = %08x\n", i,
++ readw(&ha->reg->mailbox[i]));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++}
++
++void qla4xxx_dump_registers(struct scsi_qla_host *ha)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ __dump_registers(ha);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++}
++
++void qla4xxx_dump_buffer(void *b, uint32_t size)
++{
++ uint32_t cnt;
++ uint8_t *c = b;
++
++ printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
++ "Fh\n");
++ printk("------------------------------------------------------------"
++ "--\n");
++ for (cnt = 0; cnt < size; cnt++, c++) {
++ printk(KERN_DEBUG "%02x", *c);
++ if (!(cnt % 16))
++ printk(KERN_DEBUG "\n");
++
++ else
++ printk(KERN_DEBUG " ");
++ }
++ if (cnt % 16)
++ printk(KERN_DEBUG "\n");
++}
+diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
+new file mode 100644
+index 0000000..d861c3b
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_dbg.h
+@@ -0,0 +1,55 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++/*
++ * Driver debug definitions.
++ */
++/* #define QL_DEBUG */ /* DEBUG messages */
++/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */
++/* #define QL_DEBUG_LEVEL_4 */
++/* #define QL_DEBUG_LEVEL_5 */
++/* #define QL_DEBUG_LEVEL_9 */
++
++#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */
++#if defined(QL_DEBUG)
++#define DEBUG(x) do {x;} while (0);
++#else
++#define DEBUG(x) do {} while (0);
++#endif
++
++#if defined(QL_DEBUG_LEVEL_2)
++#define DEBUG2(x) do {if(ql4xextended_error_logging == 2) x;} while (0);
++#define DEBUG2_3(x) do {x;} while (0);
++#else /* */
++#define DEBUG2(x) do {} while (0);
++#endif /* */
++
++#if defined(QL_DEBUG_LEVEL_3)
++#define DEBUG3(x) do {if(ql4xextended_error_logging == 3) x;} while (0);
++#else /* */
++#define DEBUG3(x) do {} while (0);
++#if !defined(QL_DEBUG_LEVEL_2)
++#define DEBUG2_3(x) do {} while (0);
++#endif /* */
++#endif /* */
++#if defined(QL_DEBUG_LEVEL_4)
++#define DEBUG4(x) do {x;} while (0);
++#else /* */
++#define DEBUG4(x) do {} while (0);
++#endif /* */
++
++#if defined(QL_DEBUG_LEVEL_5)
++#define DEBUG5(x) do {x;} while (0);
++#else /* */
++#define DEBUG5(x) do {} while (0);
++#endif /* */
++
++#if defined(QL_DEBUG_LEVEL_9)
++#define DEBUG9(x) do {x;} while (0);
++#else /* */
++#define DEBUG9(x) do {} while (0);
++#endif /* */
+diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
+new file mode 100644
+index 0000000..a7f6c7b
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_def.h
+@@ -0,0 +1,586 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#ifndef __QL4_DEF_H
++#define __QL4_DEF_H
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/dma-mapping.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/dmapool.h>
++#include <linux/mempool.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/mutex.h>
++
++#include <net/tcp.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_iscsi.h>
++
++
++#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
++#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
++#endif
++
++#ifndef PCI_DEVICE_ID_QLOGIC_ISP4022
++#define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022
++#endif /* */
++
++#define QLA_SUCCESS 0
++#define QLA_ERROR 1
++
++/*
++ * Data bit definitions
++ */
++#define BIT_0 0x1
++#define BIT_1 0x2
++#define BIT_2 0x4
++#define BIT_3 0x8
++#define BIT_4 0x10
++#define BIT_5 0x20
++#define BIT_6 0x40
++#define BIT_7 0x80
++#define BIT_8 0x100
++#define BIT_9 0x200
++#define BIT_10 0x400
++#define BIT_11 0x800
++#define BIT_12 0x1000
++#define BIT_13 0x2000
++#define BIT_14 0x4000
++#define BIT_15 0x8000
++#define BIT_16 0x10000
++#define BIT_17 0x20000
++#define BIT_18 0x40000
++#define BIT_19 0x80000
++#define BIT_20 0x100000
++#define BIT_21 0x200000
++#define BIT_22 0x400000
++#define BIT_23 0x800000
++#define BIT_24 0x1000000
++#define BIT_25 0x2000000
++#define BIT_26 0x4000000
++#define BIT_27 0x8000000
++#define BIT_28 0x10000000
++#define BIT_29 0x20000000
++#define BIT_30 0x40000000
++#define BIT_31 0x80000000
++
++/*
++ * Host adapter default definitions
++ ***********************************/
++#define MAX_HBAS 16
++#define MAX_BUSES 1
++#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
++#define MAX_LUNS 0xffff
++#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
++#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
++#define MAX_PDU_ENTRIES 32
++#define INVALID_ENTRY 0xFFFF
++#define MAX_CMDS_TO_RISC 1024
++#define MAX_SRBS MAX_CMDS_TO_RISC
++#define MBOX_AEN_REG_COUNT 5
++#define MAX_INIT_RETRIES 5
++#define IOCB_HIWAT_CUSHION 16
++
++/*
++ * Buffer sizes
++ */
++#define REQUEST_QUEUE_DEPTH MAX_CMDS_TO_RISC
++#define RESPONSE_QUEUE_DEPTH 64
++#define QUEUE_SIZE 64
++#define DMA_BUFFER_SIZE 512
++
++/*
++ * Misc
++ */
++#define MAC_ADDR_LEN 6 /* in bytes */
++#define IP_ADDR_LEN 4 /* in bytes */
++#define DRIVER_NAME "qla4xxx"
++
++#define MAX_LINKED_CMDS_PER_LUN 3
++#define MAX_REQS_SERVICED_PER_INTR 16
++
++#define ISCSI_IPADDR_SIZE 4 /* IP address size */
++#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
++#define ISCSI_NAME_SIZE 255 /* ISCSI Name size -
++ * usually a string */
++
++#define LSDW(x) ((u32)((u64)(x)))
++#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
++
++/*
++ * Retry & Timeout Values
++ */
++#define MBOX_TOV 60
++#define SOFT_RESET_TOV 30
++#define RESET_INTR_TOV 3
++#define SEMAPHORE_TOV 10
++#define ADAPTER_INIT_TOV 120
++#define ADAPTER_RESET_TOV 180
++#define EXTEND_CMD_TOV 60
++#define WAIT_CMD_TOV 30
++#define EH_WAIT_CMD_TOV 120
++#define FIRMWARE_UP_TOV 60
++#define RESET_FIRMWARE_TOV 30
++#define LOGOUT_TOV 10
++#define IOCB_TOV_MARGIN 10
++#define RELOGIN_TOV 18
++#define ISNS_DEREG_TOV 5
++
++#define MAX_RESET_HA_RETRIES 2
++
++/*
++ * SCSI Request Block structure (srb) that is placed
++ * on cmd->SCp location of every I/O [We have 22 bytes available]
++ */
++struct srb {
++ struct list_head list; /* (8) */
++ struct scsi_qla_host *ha; /* HA the SP is queued on */
++ struct ddb_entry *ddb;
++ uint16_t flags; /* (1) Status flags. */
++
++#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */
++#define SRB_GOT_SENSE BIT_4 /* sense data recieved. */
++ uint8_t state; /* (1) Status flags. */
++
++#define SRB_NO_QUEUE_STATE 0 /* Request is in between states */
++#define SRB_FREE_STATE 1
++#define SRB_ACTIVE_STATE 3
++#define SRB_ACTIVE_TIMEOUT_STATE 4
++#define SRB_SUSPENDED_STATE 7 /* Request in suspended state */
++
++ struct scsi_cmnd *cmd; /* (4) SCSI command block */
++ dma_addr_t dma_handle; /* (4) for unmap of single transfers */
++ atomic_t ref_count; /* reference count for this srb */
++ uint32_t fw_ddb_index;
++ uint8_t err_id; /* error id */
++#define SRB_ERR_PORT 1 /* Request failed because "port down" */
++#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */
++#define SRB_ERR_DEVICE 3 /* Request failed because "device error" */
++#define SRB_ERR_OTHER 4
++
++ uint16_t reserved;
++ uint16_t iocb_tov;
++ uint16_t iocb_cnt; /* Number of used iocbs */
++ uint16_t cc_stat;
++ u_long r_start; /* Time we recieve a cmd from OS */
++ u_long u_start; /* Time when we handed the cmd to F/W */
++};
++
++ /*
++ * Device Database (DDB) structure
++ */
++struct ddb_entry {
++ struct list_head list; /* ddb list */
++ struct scsi_qla_host *ha;
++ struct iscsi_cls_session *sess;
++ struct iscsi_cls_conn *conn;
++
++ atomic_t state; /* DDB State */
++
++ unsigned long flags; /* DDB Flags */
++
++ unsigned long dev_scan_wait_to_start_relogin;
++ unsigned long dev_scan_wait_to_complete_relogin;
++
++ uint16_t os_target_id; /* Target ID */
++ uint16_t fw_ddb_index; /* DDB firmware index */
++ uint8_t reserved[2];
++ uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */
++
++ uint32_t CmdSn;
++ uint16_t target_session_id;
++ uint16_t connection_id;
++ uint16_t exe_throttle; /* Max mumber of cmds outstanding
++ * simultaneously */
++ uint16_t task_mgmt_timeout; /* Min time for task mgmt cmds to
++ * complete */
++ uint16_t default_relogin_timeout; /* Max time to wait for
++ * relogin to complete */
++ uint16_t tcp_source_port_num;
++ uint32_t default_time2wait; /* Default Min time between
++ * relogins (+aens) */
++
++ atomic_t port_down_timer; /* Device connection timer */
++ atomic_t retry_relogin_timer; /* Min Time between relogins
++ * (4000 only) */
++ atomic_t relogin_timer; /* Max Time to wait for relogin to complete */
++ atomic_t relogin_retry_count; /* Num of times relogin has been
++ * retried */
++
++ uint16_t port;
++ uint32_t tpgt;
++ uint8_t ip_addr[ISCSI_IPADDR_SIZE];
++ uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */
++ uint8_t iscsi_alias[0x20];
++};
++
++/*
++ * DDB states.
++ */
++#define DDB_STATE_DEAD 0 /* We can no longer talk to
++ * this device */
++#define DDB_STATE_ONLINE 1 /* Device ready to accept
++ * commands */
++#define DDB_STATE_MISSING 2 /* Device logged off, trying
++ * to re-login */
++
++/*
++ * DDB flags.
++ */
++#define DF_RELOGIN 0 /* Relogin to device */
++#define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL
++ * logged it out */
++#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
++#define DF_FO_MASKED 3
++
++/*
++ * Asynchronous Event Queue structure
++ */
++struct aen {
++ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
++};
++
++
++#include "ql4_fw.h"
++#include "ql4_nvram.h"
++
++/*
++ * Linux Host Adapter structure
++ */
++struct scsi_qla_host {
++ /* Linux adapter configuration data */
++ struct Scsi_Host *host; /* pointer to host data */
++ uint32_t tot_ddbs;
++ unsigned long flags;
++
++#define AF_ONLINE 0 /* 0x00000001 */
++#define AF_INIT_DONE 1 /* 0x00000002 */
++#define AF_MBOX_COMMAND 2 /* 0x00000004 */
++#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
++#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */
++#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
++#define AF_LINK_UP 8 /* 0x00000100 */
++#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */
++#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
++#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */
++#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */
++
++ unsigned long dpc_flags;
++
++#define DPC_RESET_HA 1 /* 0x00000002 */
++#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
++#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
++#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
++#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
++#define DPC_ISNS_RESTART 7 /* 0x00000080 */
++#define DPC_AEN 9 /* 0x00000200 */
++#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
++
++ uint16_t iocb_cnt;
++ uint16_t iocb_hiwat;
++
++ /* SRB cache. */
++#define SRB_MIN_REQ 128
++ mempool_t *srb_mempool;
++
++ /* pci information */
++ struct pci_dev *pdev;
++
++ struct isp_reg __iomem *reg; /* Base I/O address */
++ unsigned long pio_address;
++ unsigned long pio_length;
++#define MIN_IOBASE_LEN 0x100
++
++ uint16_t req_q_count;
++ uint8_t marker_needed;
++ uint8_t rsvd1;
++
++ unsigned long host_no;
++
++ /* NVRAM registers */
++ struct eeprom_data *nvram;
++ spinlock_t hardware_lock ____cacheline_aligned;
++ spinlock_t list_lock;
++ uint32_t eeprom_cmd_data;
++
++ /* Counters for general statistics */
++ uint64_t adapter_error_count;
++ uint64_t device_error_count;
++ uint64_t total_io_count;
++ uint64_t total_mbytes_xferred;
++ uint64_t link_failure_count;
++ uint64_t invalid_crc_count;
++ uint32_t spurious_int_count;
++ uint32_t aborted_io_count;
++ uint32_t io_timeout_count;
++ uint32_t mailbox_timeout_count;
++ uint32_t seconds_since_last_intr;
++ uint32_t seconds_since_last_heartbeat;
++ uint32_t mac_index;
++
++ /* Info Needed for Management App */
++ /* --- From GetFwVersion --- */
++ uint32_t firmware_version[2];
++ uint32_t patch_number;
++ uint32_t build_number;
++
++ /* --- From Init_FW --- */
++ /* init_cb_t *init_cb; */
++ uint16_t firmware_options;
++ uint16_t tcp_options;
++ uint8_t ip_address[IP_ADDR_LEN];
++ uint8_t subnet_mask[IP_ADDR_LEN];
++ uint8_t gateway[IP_ADDR_LEN];
++ uint8_t alias[32];
++ uint8_t name_string[256];
++ uint8_t heartbeat_interval;
++ uint8_t rsvd;
++
++ /* --- From FlashSysInfo --- */
++ uint8_t my_mac[MAC_ADDR_LEN];
++ uint8_t serial_number[16];
++
++ /* --- From GetFwState --- */
++ uint32_t firmware_state;
++ uint32_t board_id;
++ uint32_t addl_fw_state;
++
++ /* Linux kernel thread */
++ struct workqueue_struct *dpc_thread;
++ struct work_struct dpc_work;
++
++ /* Linux timer thread */
++ struct timer_list timer;
++ uint32_t timer_active;
++
++ /* Recovery Timers */
++ uint32_t port_down_retry_count;
++ uint32_t discovery_wait;
++ atomic_t check_relogin_timeouts;
++ uint32_t retry_reset_ha_cnt;
++ uint32_t isp_reset_timer; /* reset test timer */
++ uint32_t nic_reset_timer; /* simulated nic reset test timer */
++ int eh_start;
++ struct list_head free_srb_q;
++ uint16_t free_srb_q_count;
++ uint16_t num_srbs_allocated;
++
++ /* DMA Memory Block */
++ void *queues;
++ dma_addr_t queues_dma;
++ unsigned long queues_len;
++
++#define MEM_ALIGN_VALUE \
++ ((max(REQUEST_QUEUE_DEPTH, RESPONSE_QUEUE_DEPTH)) * \
++ sizeof(struct queue_entry))
++ /* request and response queue variables */
++ dma_addr_t request_dma;
++ struct queue_entry *request_ring;
++ struct queue_entry *request_ptr;
++ dma_addr_t response_dma;
++ struct queue_entry *response_ring;
++ struct queue_entry *response_ptr;
++ dma_addr_t shadow_regs_dma;
++ struct shadow_regs *shadow_regs;
++ uint16_t request_in; /* Current indexes. */
++ uint16_t request_out;
++ uint16_t response_in;
++ uint16_t response_out;
++
++ /* aen queue variables */
++ uint16_t aen_q_count; /* Number of available aen_q entries */
++ uint16_t aen_in; /* Current indexes */
++ uint16_t aen_out;
++ struct aen aen_q[MAX_AEN_ENTRIES];
++
++ /* This mutex protects several threads to do mailbox commands
++ * concurrently.
++ */
++ struct mutex mbox_sem;
++ wait_queue_head_t mailbox_wait_queue;
++
++ /* temporary mailbox status registers */
++ volatile uint8_t mbox_status_count;
++ volatile uint32_t mbox_status[MBOX_REG_COUNT];
++
++ /* local device database list (contains internal ddb entries) */
++ struct list_head ddb_list;
++
++ /* Map ddb_list entry by FW ddb index */
++ struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
++
++};
++
++static inline int is_qla4010(struct scsi_qla_host *ha)
++{
++ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010;
++}
++
++static inline int is_qla4022(struct scsi_qla_host *ha)
++{
++ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022;
++}
++
++static inline int adapter_up(struct scsi_qla_host *ha)
++{
++ return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
++ (test_bit(AF_LINK_UP, &ha->flags) != 0);
++}
++
++static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost)
++{
++ return (struct scsi_qla_host *)shost->hostdata;
++}
++
++static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u1.isp4022.semaphore :
++ &ha->reg->u1.isp4010.nvram);
++}
++
++static inline void __iomem* isp_nvram(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u1.isp4022.nvram :
++ &ha->reg->u1.isp4010.nvram);
++}
++
++static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u2.isp4022.p0.ext_hw_conf :
++ &ha->reg->u2.isp4010.ext_hw_conf);
++}
++
++static inline void __iomem* isp_port_status(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u2.isp4022.p0.port_status :
++ &ha->reg->u2.isp4010.port_status);
++}
++
++static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u2.isp4022.p0.port_ctrl :
++ &ha->reg->u2.isp4010.port_ctrl);
++}
++
++static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u2.isp4022.p0.port_err_status :
++ &ha->reg->u2.isp4010.port_err_status);
++}
++
++static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ &ha->reg->u2.isp4022.p0.gp_out :
++ &ha->reg->u2.isp4010.gp_out);
++}
++
++static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha)
++{
++ return (is_qla4022(ha) ?
++ offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2 :
++ offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2);
++}
++
++int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
++void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask);
++int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
++
++static inline int ql4xxx_lock_flash(struct scsi_qla_host *a)
++{
++ if (is_qla4022(a))
++ return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK,
++ (QL4022_RESOURCE_BITS_BASE_CODE |
++ (a->mac_index)) << 13);
++ else
++ return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK,
++ QL4010_FLASH_SEM_BITS);
++}
++
++static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a)
++{
++ if (is_qla4022(a))
++ ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK);
++ else
++ ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK);
++}
++
++static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a)
++{
++ if (is_qla4022(a))
++ return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK,
++ (QL4022_RESOURCE_BITS_BASE_CODE |
++ (a->mac_index)) << 10);
++ else
++ return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK,
++ QL4010_NVRAM_SEM_BITS);
++}
++
++static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a)
++{
++ if (is_qla4022(a))
++ ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK);
++ else
++ ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK);
++}
++
++static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a)
++{
++ if (is_qla4022(a))
++ return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK,
++ (QL4022_RESOURCE_BITS_BASE_CODE |
++ (a->mac_index)) << 1);
++ else
++ return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK,
++ QL4010_DRVR_SEM_BITS);
++}
++
++static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
++{
++ if (is_qla4022(a))
++ ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK);
++ else
++ ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK);
++}
++
++/*---------------------------------------------------------------------------*/
++
++/* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */
++#define PRESERVE_DDB_LIST 0
++#define REBUILD_DDB_LIST 1
++
++/* Defines for process_aen() */
++#define PROCESS_ALL_AENS 0
++#define FLUSH_DDB_CHANGED_AENS 1
++#define RELOGIN_DDB_CHANGED_AENS 2
++
++#include "ql4_version.h"
++#include "ql4_glbl.h"
++#include "ql4_dbg.h"
++#include "ql4_inline.h"
++
++
++#endif /*_QLA4XXX_H */
+diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
+new file mode 100644
+index 0000000..427489d
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_fw.h
+@@ -0,0 +1,843 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#ifndef _QLA4X_FW_H
++#define _QLA4X_FW_H
++
++
++#define MAX_PRST_DEV_DB_ENTRIES 64
++#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES
++#define MAX_DEV_DB_ENTRIES 512
++
++/*************************************************************************
++ *
++ * ISP 4010 I/O Register Set Structure and Definitions
++ *
++ *************************************************************************/
++
++struct port_ctrl_stat_regs {
++ __le32 ext_hw_conf; /* 80 x50 R/W */
++ __le32 intChipConfiguration; /* 84 x54 */
++ __le32 port_ctrl; /* 88 x58 */
++ __le32 port_status; /* 92 x5c */
++ __le32 HostPrimMACHi; /* 96 x60 */
++ __le32 HostPrimMACLow; /* 100 x64 */
++ __le32 HostSecMACHi; /* 104 x68 */
++ __le32 HostSecMACLow; /* 108 x6c */
++ __le32 EPPrimMACHi; /* 112 x70 */
++ __le32 EPPrimMACLow; /* 116 x74 */
++ __le32 EPSecMACHi; /* 120 x78 */
++ __le32 EPSecMACLow; /* 124 x7c */
++ __le32 HostPrimIPHi; /* 128 x80 */
++ __le32 HostPrimIPMidHi; /* 132 x84 */
++ __le32 HostPrimIPMidLow; /* 136 x88 */
++ __le32 HostPrimIPLow; /* 140 x8c */
++ __le32 HostSecIPHi; /* 144 x90 */
++ __le32 HostSecIPMidHi; /* 148 x94 */
++ __le32 HostSecIPMidLow; /* 152 x98 */
++ __le32 HostSecIPLow; /* 156 x9c */
++ __le32 EPPrimIPHi; /* 160 xa0 */
++ __le32 EPPrimIPMidHi; /* 164 xa4 */
++ __le32 EPPrimIPMidLow; /* 168 xa8 */
++ __le32 EPPrimIPLow; /* 172 xac */
++ __le32 EPSecIPHi; /* 176 xb0 */
++ __le32 EPSecIPMidHi; /* 180 xb4 */
++ __le32 EPSecIPMidLow; /* 184 xb8 */
++ __le32 EPSecIPLow; /* 188 xbc */
++ __le32 IPReassemblyTimeout; /* 192 xc0 */
++ __le32 EthMaxFramePayload; /* 196 xc4 */
++ __le32 TCPMaxWindowSize; /* 200 xc8 */
++ __le32 TCPCurrentTimestampHi; /* 204 xcc */
++ __le32 TCPCurrentTimestampLow; /* 208 xd0 */
++ __le32 LocalRAMAddress; /* 212 xd4 */
++ __le32 LocalRAMData; /* 216 xd8 */
++ __le32 PCSReserved1; /* 220 xdc */
++ __le32 gp_out; /* 224 xe0 */
++ __le32 gp_in; /* 228 xe4 */
++ __le32 ProbeMuxAddr; /* 232 xe8 */
++ __le32 ProbeMuxData; /* 236 xec */
++ __le32 ERMQueueBaseAddr0; /* 240 xf0 */
++ __le32 ERMQueueBaseAddr1; /* 244 xf4 */
++ __le32 MACConfiguration; /* 248 xf8 */
++ __le32 port_err_status; /* 252 xfc COR */
++};
++
++struct host_mem_cfg_regs {
++ __le32 NetRequestQueueOut; /* 80 x50 */
++ __le32 NetRequestQueueOutAddrHi; /* 84 x54 */
++ __le32 NetRequestQueueOutAddrLow; /* 88 x58 */
++ __le32 NetRequestQueueBaseAddrHi; /* 92 x5c */
++ __le32 NetRequestQueueBaseAddrLow; /* 96 x60 */
++ __le32 NetRequestQueueLength; /* 100 x64 */
++ __le32 NetResponseQueueIn; /* 104 x68 */
++ __le32 NetResponseQueueInAddrHi; /* 108 x6c */
++ __le32 NetResponseQueueInAddrLow; /* 112 x70 */
++ __le32 NetResponseQueueBaseAddrHi; /* 116 x74 */
++ __le32 NetResponseQueueBaseAddrLow; /* 120 x78 */
++ __le32 NetResponseQueueLength; /* 124 x7c */
++ __le32 req_q_out; /* 128 x80 */
++ __le32 RequestQueueOutAddrHi; /* 132 x84 */
++ __le32 RequestQueueOutAddrLow; /* 136 x88 */
++ __le32 RequestQueueBaseAddrHi; /* 140 x8c */
++ __le32 RequestQueueBaseAddrLow; /* 144 x90 */
++ __le32 RequestQueueLength; /* 148 x94 */
++ __le32 ResponseQueueIn; /* 152 x98 */
++ __le32 ResponseQueueInAddrHi; /* 156 x9c */
++ __le32 ResponseQueueInAddrLow; /* 160 xa0 */
++ __le32 ResponseQueueBaseAddrHi; /* 164 xa4 */
++ __le32 ResponseQueueBaseAddrLow; /* 168 xa8 */
++ __le32 ResponseQueueLength; /* 172 xac */
++ __le32 NetRxLargeBufferQueueOut; /* 176 xb0 */
++ __le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */
++ __le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */
++ __le32 NetRxLargeBufferQueueLength; /* 188 xbc */
++ __le32 NetRxLargeBufferLength; /* 192 xc0 */
++ __le32 NetRxSmallBufferQueueOut; /* 196 xc4 */
++ __le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */
++ __le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */
++ __le32 NetRxSmallBufferQueueLength; /* 208 xd0 */
++ __le32 NetRxSmallBufferLength; /* 212 xd4 */
++ __le32 HMCReserved0[10]; /* 216 xd8 */
++};
++
++struct local_ram_cfg_regs {
++ __le32 BufletSize; /* 80 x50 */
++ __le32 BufletMaxCount; /* 84 x54 */
++ __le32 BufletCurrCount; /* 88 x58 */
++ __le32 BufletPauseThresholdCount; /* 92 x5c */
++ __le32 BufletTCPWinThresholdHi; /* 96 x60 */
++ __le32 BufletTCPWinThresholdLow; /* 100 x64 */
++ __le32 IPHashTableBaseAddr; /* 104 x68 */
++ __le32 IPHashTableSize; /* 108 x6c */
++ __le32 TCPHashTableBaseAddr; /* 112 x70 */
++ __le32 TCPHashTableSize; /* 116 x74 */
++ __le32 NCBAreaBaseAddr; /* 120 x78 */
++ __le32 NCBMaxCount; /* 124 x7c */
++ __le32 NCBCurrCount; /* 128 x80 */
++ __le32 DRBAreaBaseAddr; /* 132 x84 */
++ __le32 DRBMaxCount; /* 136 x88 */
++ __le32 DRBCurrCount; /* 140 x8c */
++ __le32 LRCReserved[28]; /* 144 x90 */
++};
++
++struct prot_stat_regs {
++ __le32 MACTxFrameCount; /* 80 x50 R */
++ __le32 MACTxByteCount; /* 84 x54 R */
++ __le32 MACRxFrameCount; /* 88 x58 R */
++ __le32 MACRxByteCount; /* 92 x5c R */
++ __le32 MACCRCErrCount; /* 96 x60 R */
++ __le32 MACEncErrCount; /* 100 x64 R */
++ __le32 MACRxLengthErrCount; /* 104 x68 R */
++ __le32 IPTxPacketCount; /* 108 x6c R */
++ __le32 IPTxByteCount; /* 112 x70 R */
++ __le32 IPTxFragmentCount; /* 116 x74 R */
++ __le32 IPRxPacketCount; /* 120 x78 R */
++ __le32 IPRxByteCount; /* 124 x7c R */
++ __le32 IPRxFragmentCount; /* 128 x80 R */
++ __le32 IPDatagramReassemblyCount; /* 132 x84 R */
++ __le32 IPV6RxPacketCount; /* 136 x88 R */
++ __le32 IPErrPacketCount; /* 140 x8c R */
++ __le32 IPReassemblyErrCount; /* 144 x90 R */
++ __le32 TCPTxSegmentCount; /* 148 x94 R */
++ __le32 TCPTxByteCount; /* 152 x98 R */
++ __le32 TCPRxSegmentCount; /* 156 x9c R */
++ __le32 TCPRxByteCount; /* 160 xa0 R */
++ __le32 TCPTimerExpCount; /* 164 xa4 R */
++ __le32 TCPRxAckCount; /* 168 xa8 R */
++ __le32 TCPTxAckCount; /* 172 xac R */
++ __le32 TCPRxErrOOOCount; /* 176 xb0 R */
++ __le32 PSReserved0; /* 180 xb4 */
++ __le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */
++ __le32 ECCErrCorrectionCount; /* 188 xbc R */
++ __le32 PSReserved1[16]; /* 192 xc0 */
++};
++
++
++/* remote register set (access via PCI memory read/write) */
++struct isp_reg {
++#define MBOX_REG_COUNT 8
++ __le32 mailbox[MBOX_REG_COUNT];
++
++ __le32 flash_address; /* 0x20 */
++ __le32 flash_data;
++ __le32 ctrl_status;
++
++ union {
++ struct {
++ __le32 nvram;
++ __le32 reserved1[2]; /* 0x30 */
++ } __attribute__ ((packed)) isp4010;
++ struct {
++ __le32 intr_mask;
++ __le32 nvram; /* 0x30 */
++ __le32 semaphore;
++ } __attribute__ ((packed)) isp4022;
++ } u1;
++
++ __le32 req_q_in; /* SCSI Request Queue Producer Index */
++ __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */
++
++ __le32 reserved2[4]; /* 0x40 */
++
++ union {
++ struct {
++ __le32 ext_hw_conf; /* 0x50 */
++ __le32 flow_ctrl;
++ __le32 port_ctrl;
++ __le32 port_status;
++
++ __le32 reserved3[8]; /* 0x60 */
++
++ __le32 req_q_out; /* 0x80 */
++
++ __le32 reserved4[23]; /* 0x84 */
++
++ __le32 gp_out; /* 0xe0 */
++ __le32 gp_in;
++
++ __le32 reserved5[5];
++
++ __le32 port_err_status; /* 0xfc */
++ } __attribute__ ((packed)) isp4010;
++ struct {
++ union {
++ struct port_ctrl_stat_regs p0;
++ struct host_mem_cfg_regs p1;
++ struct local_ram_cfg_regs p2;
++ struct prot_stat_regs p3;
++ __le32 r_union[44];
++ };
++
++ } __attribute__ ((packed)) isp4022;
++ } u2;
++}; /* 256 x100 */
++
++
++/* Semaphore Defines for 4010 */
++#define QL4010_DRVR_SEM_BITS 0x00000030
++#define QL4010_GPIO_SEM_BITS 0x000000c0
++#define QL4010_SDRAM_SEM_BITS 0x00000300
++#define QL4010_PHY_SEM_BITS 0x00000c00
++#define QL4010_NVRAM_SEM_BITS 0x00003000
++#define QL4010_FLASH_SEM_BITS 0x0000c000
++
++#define QL4010_DRVR_SEM_MASK 0x00300000
++#define QL4010_GPIO_SEM_MASK 0x00c00000
++#define QL4010_SDRAM_SEM_MASK 0x03000000
++#define QL4010_PHY_SEM_MASK 0x0c000000
++#define QL4010_NVRAM_SEM_MASK 0x30000000
++#define QL4010_FLASH_SEM_MASK 0xc0000000
++
++/* Semaphore Defines for 4022 */
++#define QL4022_RESOURCE_MASK_BASE_CODE 0x7
++#define QL4022_RESOURCE_BITS_BASE_CODE 0x4
++
++
++#define QL4022_DRVR_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (1+16))
++#define QL4022_DDR_RAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (4+16))
++#define QL4022_PHY_GIO_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (7+16))
++#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16))
++#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16))
++
++
++
++/* Page # defines for 4022 */
++#define PORT_CTRL_STAT_PAGE 0 /* 4022 */
++#define HOST_MEM_CFG_PAGE 1 /* 4022 */
++#define LOCAL_RAM_CFG_PAGE 2 /* 4022 */
++#define PROT_STAT_PAGE 3 /* 4022 */
++
++/* Register Mask - sets corresponding mask bits in the upper word */
++static inline uint32_t set_rmask(uint32_t val)
++{
++ return (val & 0xffff) | (val << 16);
++}
++
++
++static inline uint32_t clr_rmask(uint32_t val)
++{
++ return 0 | (val << 16);
++}
++
++/* ctrl_status definitions */
++#define CSR_SCSI_PAGE_SELECT 0x00000003
++#define CSR_SCSI_INTR_ENABLE 0x00000004 /* 4010 */
++#define CSR_SCSI_RESET_INTR 0x00000008
++#define CSR_SCSI_COMPLETION_INTR 0x00000010
++#define CSR_SCSI_PROCESSOR_INTR 0x00000020
++#define CSR_INTR_RISC 0x00000040
++#define CSR_BOOT_ENABLE 0x00000080
++#define CSR_NET_PAGE_SELECT 0x00000300 /* 4010 */
++#define CSR_FUNC_NUM 0x00000700 /* 4022 */
++#define CSR_NET_RESET_INTR 0x00000800 /* 4010 */
++#define CSR_FORCE_SOFT_RESET 0x00002000 /* 4022 */
++#define CSR_FATAL_ERROR 0x00004000
++#define CSR_SOFT_RESET 0x00008000
++#define ISP_CONTROL_FN_MASK CSR_FUNC_NUM
++#define ISP_CONTROL_FN0_SCSI 0x0500
++#define ISP_CONTROL_FN1_SCSI 0x0700
++
++#define INTR_PENDING (CSR_SCSI_COMPLETION_INTR |\
++ CSR_SCSI_PROCESSOR_INTR |\
++ CSR_SCSI_RESET_INTR)
++
++/* ISP InterruptMask definitions */
++#define IMR_SCSI_INTR_ENABLE 0x00000004 /* 4022 */
++
++/* ISP 4022 nvram definitions */
++#define NVR_WRITE_ENABLE 0x00000010 /* 4022 */
++
++/* ISP port_status definitions */
++
++/* ISP Semaphore definitions */
++
++/* ISP General Purpose Output definitions */
++#define GPOR_TOPCAT_RESET 0x00000004
++
++/* shadow registers (DMA'd from HA to system memory. read only) */
++struct shadow_regs {
++ /* SCSI Request Queue Consumer Index */
++ __le32 req_q_out; /* 0 x0 R */
++
++ /* SCSI Completion Queue Producer Index */
++ __le32 rsp_q_in; /* 4 x4 R */
++}; /* 8 x8 */
++
++
++/* External hardware configuration register */
++union external_hw_config_reg {
++ struct {
++ /* FIXME: Do we even need this? All values are
++ * referred to by 16 bit quantities. Platform and
++ * endianess issues. */
++ __le32 bReserved0:1;
++ __le32 bSDRAMProtectionMethod:2;
++ __le32 bSDRAMBanks:1;
++ __le32 bSDRAMChipWidth:1;
++ __le32 bSDRAMChipSize:2;
++ __le32 bParityDisable:1;
++ __le32 bExternalMemoryType:1;
++ __le32 bFlashBIOSWriteEnable:1;
++ __le32 bFlashUpperBankSelect:1;
++ __le32 bWriteBurst:2;
++ __le32 bReserved1:3;
++ __le32 bMask:16;
++ };
++ uint32_t Asuint32_t;
++};
++
++/*************************************************************************
++ *
++ * Mailbox Commands Structures and Definitions
++ *
++ *************************************************************************/
++
++/* Mailbox command definitions */
++#define MBOX_CMD_ABOUT_FW 0x0009
++#define MBOX_CMD_LUN_RESET 0x0016
++#define MBOX_CMD_GET_FW_STATUS 0x001F
++#define MBOX_CMD_SET_ISNS_SERVICE 0x0021
++#define ISNS_DISABLE 0
++#define ISNS_ENABLE 1
++#define MBOX_CMD_READ_FLASH 0x0026
++#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
++#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
++#define LOGOUT_OPTION_CLOSE_SESSION 0x01
++#define LOGOUT_OPTION_RELOGIN 0x02
++#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A
++#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060
++#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061
++#define MBOX_CMD_REQUEST_DATABASE_ENTRY 0x0062
++#define MBOX_CMD_SET_DATABASE_ENTRY 0x0063
++#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064
++#define DDB_DS_UNASSIGNED 0x00
++#define DDB_DS_NO_CONNECTION_ACTIVE 0x01
++#define DDB_DS_SESSION_ACTIVE 0x04
++#define DDB_DS_SESSION_FAILED 0x06
++#define DDB_DS_LOGIN_IN_PROCESS 0x07
++#define MBOX_CMD_GET_FW_STATE 0x0069
++
++/* Mailbox 1 */
++#define FW_STATE_READY 0x0000
++#define FW_STATE_CONFIG_WAIT 0x0001
++#define FW_STATE_ERROR 0x0004
++#define FW_STATE_DHCP_IN_PROGRESS 0x0008
++
++/* Mailbox 3 */
++#define FW_ADDSTATE_OPTICAL_MEDIA 0x0001
++#define FW_ADDSTATE_DHCP_ENABLED 0x0002
++#define FW_ADDSTATE_LINK_UP 0x0010
++#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020
++#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B
++#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074
++#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */
++#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077
++
++/* Mailbox status definitions */
++#define MBOX_COMPLETION_STATUS 4
++#define MBOX_STS_BUSY 0x0007
++#define MBOX_STS_INTERMEDIATE_COMPLETION 0x1000
++#define MBOX_STS_COMMAND_COMPLETE 0x4000
++#define MBOX_STS_COMMAND_ERROR 0x4005
++
++#define MBOX_ASYNC_EVENT_STATUS 8
++#define MBOX_ASTS_SYSTEM_ERROR 0x8002
++#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003
++#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004
++#define MBOX_ASTS_PROTOCOL_STATISTIC_ALARM 0x8005
++#define MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED 0x8006
++#define MBOX_ASTS_LINK_UP 0x8010
++#define MBOX_ASTS_LINK_DOWN 0x8011
++#define MBOX_ASTS_DATABASE_CHANGED 0x8014
++#define MBOX_ASTS_UNSOLICITED_PDU_RECEIVED 0x8015
++#define MBOX_ASTS_SELF_TEST_FAILED 0x8016
++#define MBOX_ASTS_LOGIN_FAILED 0x8017
++#define MBOX_ASTS_DNS 0x8018
++#define MBOX_ASTS_HEARTBEAT 0x8019
++#define MBOX_ASTS_NVRAM_INVALID 0x801A
++#define MBOX_ASTS_MAC_ADDRESS_CHANGED 0x801B
++#define MBOX_ASTS_IP_ADDRESS_CHANGED 0x801C
++#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D
++#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F
++#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021
++#define ISNS_EVENT_DATA_RECEIVED 0x0000
++#define ISNS_EVENT_CONNECTION_OPENED 0x0001
++#define ISNS_EVENT_CONNECTION_FAILED 0x0002
++#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022
++#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
++
++/*************************************************************************/
++
++/* Host Adapter Initialization Control Block (from host) */
++struct init_fw_ctrl_blk {
++ uint8_t Version; /* 00 */
++ uint8_t Control; /* 01 */
++
++ uint16_t FwOptions; /* 02-03 */
++#define FWOPT_HEARTBEAT_ENABLE 0x1000
++#define FWOPT_SESSION_MODE 0x0040
++#define FWOPT_INITIATOR_MODE 0x0020
++#define FWOPT_TARGET_MODE 0x0010
++
++ uint16_t ExecThrottle; /* 04-05 */
++ uint8_t RetryCount; /* 06 */
++ uint8_t RetryDelay; /* 07 */
++ uint16_t MaxEthFrPayloadSize; /* 08-09 */
++ uint16_t AddFwOptions; /* 0A-0B */
++
++ uint8_t HeartbeatInterval; /* 0C */
++ uint8_t InstanceNumber; /* 0D */
++ uint16_t RES2; /* 0E-0F */
++ uint16_t ReqQConsumerIndex; /* 10-11 */
++ uint16_t ComplQProducerIndex; /* 12-13 */
++ uint16_t ReqQLen; /* 14-15 */
++ uint16_t ComplQLen; /* 16-17 */
++ uint32_t ReqQAddrLo; /* 18-1B */
++ uint32_t ReqQAddrHi; /* 1C-1F */
++ uint32_t ComplQAddrLo; /* 20-23 */
++ uint32_t ComplQAddrHi; /* 24-27 */
++ uint32_t ShadowRegBufAddrLo; /* 28-2B */
++ uint32_t ShadowRegBufAddrHi; /* 2C-2F */
++
++ uint16_t iSCSIOptions; /* 30-31 */
++
++ uint16_t TCPOptions; /* 32-33 */
++
++ uint16_t IPOptions; /* 34-35 */
++
++ uint16_t MaxPDUSize; /* 36-37 */
++ uint16_t RcvMarkerInt; /* 38-39 */
++ uint16_t SndMarkerInt; /* 3A-3B */
++ uint16_t InitMarkerlessInt; /* 3C-3D */
++ uint16_t FirstBurstSize; /* 3E-3F */
++ uint16_t DefaultTime2Wait; /* 40-41 */
++ uint16_t DefaultTime2Retain; /* 42-43 */
++ uint16_t MaxOutStndngR2T; /* 44-45 */
++ uint16_t KeepAliveTimeout; /* 46-47 */
++ uint16_t PortNumber; /* 48-49 */
++ uint16_t MaxBurstSize; /* 4A-4B */
++ uint32_t RES4; /* 4C-4F */
++ uint8_t IPAddr[4]; /* 50-53 */
++ uint8_t RES5[12]; /* 54-5F */
++ uint8_t SubnetMask[4]; /* 60-63 */
++ uint8_t RES6[12]; /* 64-6F */
++ uint8_t GatewayIPAddr[4]; /* 70-73 */
++ uint8_t RES7[12]; /* 74-7F */
++ uint8_t PriDNSIPAddr[4]; /* 80-83 */
++ uint8_t SecDNSIPAddr[4]; /* 84-87 */
++ uint8_t RES8[8]; /* 88-8F */
++ uint8_t Alias[32]; /* 90-AF */
++ uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */
++ uint8_t CHAPNameSecretsTable[8]; /* B8-BF */
++ uint8_t EthernetMACAddr[6]; /* C0-C5 */
++ uint16_t TargetPortalGroup; /* C6-C7 */
++ uint8_t SendScale; /* C8 */
++ uint8_t RecvScale; /* C9 */
++ uint8_t TypeOfService; /* CA */
++ uint8_t Time2Live; /* CB */
++ uint16_t VLANPriority; /* CC-CD */
++ uint16_t Reserved8; /* CE-CF */
++ uint8_t SecIPAddr[4]; /* D0-D3 */
++ uint8_t Reserved9[12]; /* D4-DF */
++ uint8_t iSNSIPAddr[4]; /* E0-E3 */
++ uint16_t iSNSServerPortNumber; /* E4-E5 */
++ uint8_t Reserved10[10]; /* E6-EF */
++ uint8_t SLPDAIPAddr[4]; /* F0-F3 */
++ uint8_t Reserved11[12]; /* F4-FF */
++ uint8_t iSCSINameString[256]; /* 100-1FF */
++};
++
++/*************************************************************************/
++
++struct dev_db_entry {
++ uint8_t options; /* 00 */
++#define DDB_OPT_DISC_SESSION 0x10
++#define DDB_OPT_TARGET 0x02 /* device is a target */
++
++ uint8_t control; /* 01 */
++
++ uint16_t exeThrottle; /* 02-03 */
++ uint16_t exeCount; /* 04-05 */
++ uint8_t retryCount; /* 06 */
++ uint8_t retryDelay; /* 07 */
++ uint16_t iSCSIOptions; /* 08-09 */
++
++ uint16_t TCPOptions; /* 0A-0B */
++
++ uint16_t IPOptions; /* 0C-0D */
++
++ uint16_t maxPDUSize; /* 0E-0F */
++ uint16_t rcvMarkerInt; /* 10-11 */
++ uint16_t sndMarkerInt; /* 12-13 */
++ uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */
++ uint16_t firstBurstSize; /* 16-17 */
++ uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */
++ uint16_t maxTime2Retain; /* 1A-1B */
++ uint16_t maxOutstndngR2T; /* 1C-1D */
++ uint16_t keepAliveTimeout; /* 1E-1F */
++ uint8_t ISID[6]; /* 20-25 big-endian, must be converted
++ * to little-endian */
++ uint16_t TSID; /* 26-27 */
++ uint16_t portNumber; /* 28-29 */
++ uint16_t maxBurstSize; /* 2A-2B */
++ uint16_t taskMngmntTimeout; /* 2C-2D */
++ uint16_t reserved1; /* 2E-2F */
++ uint8_t ipAddr[0x10]; /* 30-3F */
++ uint8_t iSCSIAlias[0x20]; /* 40-5F */
++ uint8_t targetAddr[0x20]; /* 60-7F */
++ uint8_t userID[0x20]; /* 80-9F */
++ uint8_t password[0x20]; /* A0-BF */
++ uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a
++ * pointer to a string so we
++ * don't have to reserve soooo
++ * much RAM */
++ uint16_t ddbLink; /* 1C0-1C1 */
++ uint16_t CHAPTableIndex; /* 1C2-1C3 */
++ uint16_t TargetPortalGroup; /* 1C4-1C5 */
++ uint16_t reserved2[2]; /* 1C6-1C7 */
++ uint32_t statSN; /* 1C8-1CB */
++ uint32_t expStatSN; /* 1CC-1CF */
++ uint16_t reserved3[0x2C]; /* 1D0-1FB */
++ uint16_t ddbValidCookie; /* 1FC-1FD */
++ uint16_t ddbValidSize; /* 1FE-1FF */
++};
++
++/*************************************************************************/
++
++/* Flash definitions */
++
++#define FLASH_OFFSET_SYS_INFO 0x02000000
++#define FLASH_DEFAULTBLOCKSIZE 0x20000
++#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes
++ * for EOF
++ * signature */
++
++struct sys_info_phys_addr {
++ uint8_t address[6]; /* 00-05 */
++ uint8_t filler[2]; /* 06-07 */
++};
++
++struct flash_sys_info {
++ uint32_t cookie; /* 00-03 */
++ uint32_t physAddrCount; /* 04-07 */
++ struct sys_info_phys_addr physAddr[4]; /* 08-27 */
++ uint8_t vendorId[128]; /* 28-A7 */
++ uint8_t productId[128]; /* A8-127 */
++ uint32_t serialNumber; /* 128-12B */
++
++ /* PCI Configuration values */
++ uint32_t pciDeviceVendor; /* 12C-12F */
++ uint32_t pciDeviceId; /* 130-133 */
++ uint32_t pciSubsysVendor; /* 134-137 */
++ uint32_t pciSubsysId; /* 138-13B */
++
++ /* This validates version 1. */
++ uint32_t crumbs; /* 13C-13F */
++
++ uint32_t enterpriseNumber; /* 140-143 */
++
++ uint32_t mtu; /* 144-147 */
++ uint32_t reserved0; /* 148-14b */
++ uint32_t crumbs2; /* 14c-14f */
++ uint8_t acSerialNumber[16]; /* 150-15f */
++ uint32_t crumbs3; /* 160-16f */
++
++ /* Leave this last in the struct so it is declared invalid if
++ * any new items are added.
++ */
++ uint32_t reserved1[39]; /* 170-1ff */
++}; /* 200 */
++
++struct crash_record {
++ uint16_t fw_major_version; /* 00 - 01 */
++ uint16_t fw_minor_version; /* 02 - 03 */
++ uint16_t fw_patch_version; /* 04 - 05 */
++ uint16_t fw_build_version; /* 06 - 07 */
++
++ uint8_t build_date[16]; /* 08 - 17 */
++ uint8_t build_time[16]; /* 18 - 27 */
++ uint8_t build_user[16]; /* 28 - 37 */
++ uint8_t card_serial_num[16]; /* 38 - 47 */
++
++ uint32_t time_of_crash_in_secs; /* 48 - 4B */
++ uint32_t time_of_crash_in_ms; /* 4C - 4F */
++
++ uint16_t out_RISC_sd_num_frames; /* 50 - 51 */
++ uint16_t OAP_sd_num_words; /* 52 - 53 */
++ uint16_t IAP_sd_num_frames; /* 54 - 55 */
++ uint16_t in_RISC_sd_num_words; /* 56 - 57 */
++
++ uint8_t reserved1[28]; /* 58 - 7F */
++
++ uint8_t out_RISC_reg_dump[256]; /* 80 -17F */
++ uint8_t in_RISC_reg_dump[256]; /*180 -27F */
++ uint8_t in_out_RISC_stack_dump[0]; /*280 - ??? */
++};
++
++struct conn_event_log_entry {
++#define MAX_CONN_EVENT_LOG_ENTRIES 100
++ uint32_t timestamp_sec; /* 00 - 03 seconds since boot */
++ uint32_t timestamp_ms; /* 04 - 07 milliseconds since boot */
++ uint16_t device_index; /* 08 - 09 */
++ uint16_t fw_conn_state; /* 0A - 0B */
++ uint8_t event_type; /* 0C - 0C */
++ uint8_t error_code; /* 0D - 0D */
++ uint16_t error_code_detail; /* 0E - 0F */
++ uint8_t num_consecutive_events; /* 10 - 10 */
++ uint8_t rsvd[3]; /* 11 - 13 */
++};
++
++/*************************************************************************
++ *
++ * IOCB Commands Structures and Definitions
++ *
++ *************************************************************************/
++#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */
++#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */
++
++/* IOCB header structure */
++struct qla4_header {
++ uint8_t entryType;
++#define ET_STATUS 0x03
++#define ET_MARKER 0x04
++#define ET_CONT_T1 0x0A
++#define ET_STATUS_CONTINUATION 0x10
++#define ET_CMND_T3 0x19
++#define ET_PASSTHRU0 0x3A
++#define ET_PASSTHRU_STATUS 0x3C
++
++ uint8_t entryStatus;
++ uint8_t systemDefined;
++ uint8_t entryCount;
++
++ /* SyetemDefined definition */
++};
++
++/* Generic queue entry structure*/
++struct queue_entry {
++ uint8_t data[60];
++ uint32_t signature;
++
++};
++
++/* 64 bit addressing segment counts*/
++
++#define COMMAND_SEG_A64 1
++#define CONTINUE_SEG_A64 5
++
++/* 64 bit addressing segment definition*/
++
++struct data_seg_a64 {
++ struct {
++ uint32_t addrLow;
++ uint32_t addrHigh;
++
++ } base;
++
++ uint32_t count;
++
++};
++
++/* Command Type 3 entry structure*/
++
++struct command_t3_entry {
++ struct qla4_header hdr; /* 00-03 */
++
++ uint32_t handle; /* 04-07 */
++ uint16_t target; /* 08-09 */
++ uint16_t connection_id; /* 0A-0B */
++
++ uint8_t control_flags; /* 0C */
++
++ /* data direction (bits 5-6) */
++#define CF_WRITE 0x20
++#define CF_READ 0x40
++#define CF_NO_DATA 0x00
++
++ /* task attributes (bits 2-0) */
++#define CF_HEAD_TAG 0x03
++#define CF_ORDERED_TAG 0x02
++#define CF_SIMPLE_TAG 0x01
++
++ /* STATE FLAGS FIELD IS A PLACE HOLDER. THE FW WILL SET BITS
++ * IN THIS FIELD AS THE COMMAND IS PROCESSED. WHEN THE IOCB IS
++ * CHANGED TO AN IOSB THIS FIELD WILL HAVE THE STATE FLAGS SET
++ * PROPERLY.
++ */
++ uint8_t state_flags; /* 0D */
++ uint8_t cmdRefNum; /* 0E */
++ uint8_t reserved1; /* 0F */
++ uint8_t cdb[IOCB_MAX_CDB_LEN]; /* 10-1F */
++ struct scsi_lun lun; /* FCP LUN (BE). */
++ uint32_t cmdSeqNum; /* 28-2B */
++ uint16_t timeout; /* 2C-2D */
++ uint16_t dataSegCnt; /* 2E-2F */
++ uint32_t ttlByteCnt; /* 30-33 */
++ struct data_seg_a64 dataseg[COMMAND_SEG_A64]; /* 34-3F */
++
++};
++
++
++/* Continuation Type 1 entry structure*/
++struct continuation_t1_entry {
++ struct qla4_header hdr;
++
++ struct data_seg_a64 dataseg[CONTINUE_SEG_A64];
++
++};
++
++/* Parameterize for 64 or 32 bits */
++#define COMMAND_SEG COMMAND_SEG_A64
++#define CONTINUE_SEG CONTINUE_SEG_A64
++
++#define ET_COMMAND ET_CMND_T3
++#define ET_CONTINUE ET_CONT_T1
++
++/* Marker entry structure*/
++struct marker_entry {
++ struct qla4_header hdr; /* 00-03 */
++
++ uint32_t system_defined; /* 04-07 */
++ uint16_t target; /* 08-09 */
++ uint16_t modifier; /* 0A-0B */
++#define MM_LUN_RESET 0
++
++ uint16_t flags; /* 0C-0D */
++ uint16_t reserved1; /* 0E-0F */
++ struct scsi_lun lun; /* FCP LUN (BE). */
++ uint64_t reserved2; /* 18-1F */
++ uint64_t reserved3; /* 20-27 */
++ uint64_t reserved4; /* 28-2F */
++ uint64_t reserved5; /* 30-37 */
++ uint64_t reserved6; /* 38-3F */
++};
++
++/* Status entry structure*/
++struct status_entry {
++ struct qla4_header hdr; /* 00-03 */
++
++ uint32_t handle; /* 04-07 */
++
++ uint8_t scsiStatus; /* 08 */
++#define SCSI_CHECK_CONDITION 0x02
++
++ uint8_t iscsiFlags; /* 09 */
++#define ISCSI_FLAG_RESIDUAL_UNDER 0x02
++#define ISCSI_FLAG_RESIDUAL_OVER 0x04
++
++ uint8_t iscsiResponse; /* 0A */
++
++ uint8_t completionStatus; /* 0B */
++#define SCS_COMPLETE 0x00
++#define SCS_INCOMPLETE 0x01
++#define SCS_RESET_OCCURRED 0x04
++#define SCS_ABORTED 0x05
++#define SCS_TIMEOUT 0x06
++#define SCS_DATA_OVERRUN 0x07
++#define SCS_DATA_UNDERRUN 0x15
++#define SCS_QUEUE_FULL 0x1C
++#define SCS_DEVICE_UNAVAILABLE 0x28
++#define SCS_DEVICE_LOGGED_OUT 0x29
++
++ uint8_t reserved1; /* 0C */
++
++ /* state_flags MUST be at the same location as state_flags in
++ * the Command_T3/4_Entry */
++ uint8_t state_flags; /* 0D */
++
++ uint16_t senseDataByteCnt; /* 0E-0F */
++ uint32_t residualByteCnt; /* 10-13 */
++ uint32_t bidiResidualByteCnt; /* 14-17 */
++ uint32_t expSeqNum; /* 18-1B */
++ uint32_t maxCmdSeqNum; /* 1C-1F */
++ uint8_t senseData[IOCB_MAX_SENSEDATA_LEN]; /* 20-3F */
++
++};
++
++struct passthru0 {
++ struct qla4_header hdr; /* 00-03 */
++ uint32_t handle; /* 04-07 */
++ uint16_t target; /* 08-09 */
++ uint16_t connectionID; /* 0A-0B */
++#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000)
++
++ uint16_t controlFlags; /* 0C-0D */
++#define PT_FLAG_ETHERNET_FRAME 0x8000
++#define PT_FLAG_ISNS_PDU 0x8000
++#define PT_FLAG_SEND_BUFFER 0x0200
++#define PT_FLAG_WAIT_4_RESPONSE 0x0100
++
++ uint16_t timeout; /* 0E-0F */
++#define PT_DEFAULT_TIMEOUT 30 /* seconds */
++
++ struct data_seg_a64 outDataSeg64; /* 10-1B */
++ uint32_t res1; /* 1C-1F */
++ struct data_seg_a64 inDataSeg64; /* 20-2B */
++ uint8_t res2[20]; /* 2C-3F */
++};
++
++struct passthru_status {
++ struct qla4_header hdr; /* 00-03 */
++ uint32_t handle; /* 04-07 */
++ uint16_t target; /* 08-09 */
++ uint16_t connectionID; /* 0A-0B */
++
++ uint8_t completionStatus; /* 0C */
++#define PASSTHRU_STATUS_COMPLETE 0x01
++
++ uint8_t residualFlags; /* 0D */
++
++ uint16_t timeout; /* 0E-0F */
++ uint16_t portNumber; /* 10-11 */
++ uint8_t res1[10]; /* 12-1B */
++ uint32_t outResidual; /* 1C-1F */
++ uint8_t res2[12]; /* 20-2B */
++ uint32_t inResidual; /* 2C-2F */
++ uint8_t res4[16]; /* 30-3F */
++};
++
++#endif /* _QLA4X_FW_H */
+diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
+new file mode 100644
+index 0000000..1b221ff
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_glbl.h
+@@ -0,0 +1,78 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#ifndef __QLA4x_GBL_H
++#define __QLA4x_GBL_H
++
++int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
++int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
++int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
++ uint8_t renew_ddb_list);
++int qla4xxx_soft_reset(struct scsi_qla_host *ha);
++irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
++
++void qla4xxx_free_ddb_list(struct scsi_qla_host * ha);
++void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
++
++int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
++int qla4xxx_relogin_device(struct scsi_qla_host * ha,
++ struct ddb_entry * ddb_entry);
++int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
++ int lun);
++int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
++ uint32_t offset, uint32_t len);
++int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
++int qla4xxx_get_firmware_state(struct scsi_qla_host * ha);
++int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha);
++
++/* FIXME: Goodness! this really wants a small struct to hold the
++ * parameters. On x86 the args will get passed on the stack! */
++int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
++ uint16_t fw_ddb_index,
++ struct dev_db_entry *fw_ddb_entry,
++ dma_addr_t fw_ddb_entry_dma,
++ uint32_t *num_valid_ddb_entries,
++ uint32_t *next_ddb_index,
++ uint32_t *fw_ddb_device_state,
++ uint32_t *conn_err_detail,
++ uint16_t *tcp_source_port_num,
++ uint16_t *connection_id);
++
++struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
++ uint32_t fw_ddb_index);
++int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
++ dma_addr_t fw_ddb_entry_dma);
++
++void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
++ struct ddb_entry *ddb_entry);
++u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
++void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
++struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
++int qla4xxx_add_sess(struct ddb_entry *);
++void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
++int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
++ uint16_t fw_ddb_index,
++ uint16_t connection_id,
++ uint16_t option);
++int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
++ uint16_t fw_ddb_index);
++int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
++int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
++void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
++ uint32_t intr_status);
++int qla4xxx_init_rings(struct scsi_qla_host * ha);
++void qla4xxx_dump_buffer(void *b, uint32_t size);
++struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
++void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
++int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
++int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
++ uint32_t fw_ddb_index, uint32_t state);
++
++extern int ql4xextended_error_logging;
++extern int ql4xdiscoverywait;
++extern int ql4xdontresethba;
++#endif /* _QLA4x_GBL_H */
+diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
+new file mode 100644
+index 0000000..bb3a1c1
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_init.c
+@@ -0,0 +1,1340 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#include "ql4_def.h"
++
++/*
++ * QLogic ISP4xxx Hardware Support Function Prototypes.
++ */
++
++static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
++{
++ uint32_t value;
++ uint8_t func_number;
++ unsigned long flags;
++
++ /* Get the function number */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ value = readw(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ func_number = (uint8_t) ((value >> 4) & 0x30);
++ switch (value & ISP_CONTROL_FN_MASK) {
++ case ISP_CONTROL_FN0_SCSI:
++ ha->mac_index = 1;
++ break;
++ case ISP_CONTROL_FN1_SCSI:
++ ha->mac_index = 3;
++ break;
++ default:
++ DEBUG2(printk("scsi%ld: %s: Invalid function number, "
++ "ispControlStatus = 0x%x\n", ha->host_no,
++ __func__, value));
++ break;
++ }
++ DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__,
++ ha->mac_index));
++}
++
++/**
++ * qla4xxx_free_ddb - deallocate ddb
++ * @ha: pointer to host adapter structure.
++ * @ddb_entry: pointer to device database entry
++ *
++ * This routine deallocates and unlinks the specified ddb_entry from the
++ * adapter's
++ **/
++void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry)
++{
++ /* Remove device entry from list */
++ list_del_init(&ddb_entry->list);
++
++ /* Remove device pointer from index mapping arrays */
++ ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] =
++ (struct ddb_entry *) INVALID_ENTRY;
++ ha->tot_ddbs--;
++
++ /* Free memory and scsi-ml struct for device entry */
++ qla4xxx_destroy_sess(ddb_entry);
++}
++
++/**
++ * qla4xxx_free_ddb_list - deallocate all ddbs
++ * @ha: pointer to host adapter structure.
++ *
++ * This routine deallocates and removes all devices on the sppecified adapter.
++ **/
++void qla4xxx_free_ddb_list(struct scsi_qla_host *ha)
++{
++ struct list_head *ptr;
++ struct ddb_entry *ddb_entry;
++
++ while (!list_empty(&ha->ddb_list)) {
++ ptr = ha->ddb_list.next;
++ /* Free memory for device entry and remove */
++ ddb_entry = list_entry(ptr, struct ddb_entry, list);
++ qla4xxx_free_ddb(ha, ddb_entry);
++ }
++}
++
++/**
++ * qla4xxx_init_rings - initialize hw queues
++ * @ha: pointer to host adapter structure.
++ *
++ * This routine initializes the internal queues for the specified adapter.
++ * The QLA4010 requires us to restart the queues at index 0.
++ * The QLA4000 doesn't care, so just default to QLA4010's requirement.
++ **/
++int qla4xxx_init_rings(struct scsi_qla_host *ha)
++{
++ unsigned long flags = 0;
++
++ /* Initialize request queue. */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ ha->request_out = 0;
++ ha->request_in = 0;
++ ha->request_ptr = &ha->request_ring[ha->request_in];
++ ha->req_q_count = REQUEST_QUEUE_DEPTH;
++
++ /* Initialize response queue. */
++ ha->response_in = 0;
++ ha->response_out = 0;
++ ha->response_ptr = &ha->response_ring[ha->response_out];
++
++ /*
++ * Initialize DMA Shadow registers. The firmware is really supposed to
++ * take care of this, but on some uniprocessor systems, the shadow
++ * registers aren't cleared-- causing the interrupt_handler to think
++ * there are responses to be processed when there aren't.
++ */
++ ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
++ ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
++ wmb();
++
++ writel(0, &ha->reg->req_q_in);
++ writel(0, &ha->reg->rsp_q_out);
++ readl(&ha->reg->rsp_q_out);
++
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_validate_mac_address - validate adapter MAC address(es)
++ * @ha: pointer to host adapter structure.
++ *
++ **/
++static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
++{
++ struct flash_sys_info *sys_info;
++ dma_addr_t sys_info_dma;
++ int status = QLA_ERROR;
++
++ sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),
++ &sys_info_dma, GFP_KERNEL);
++ if (sys_info == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
++ ha->host_no, __func__));
++
++ goto exit_validate_mac_no_free;
++ }
++ memset(sys_info, 0, sizeof(*sys_info));
++
++ /* Get flash sys info */
++ if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO,
++ sizeof(*sys_info)) != QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "
++ "failed\n", ha->host_no, __func__));
++
++ goto exit_validate_mac;
++ }
++
++ /* Save M.A.C. address & serial_number */
++ memcpy(ha->my_mac, &sys_info->physAddr[0].address[0],
++ min(sizeof(ha->my_mac),
++ sizeof(sys_info->physAddr[0].address)));
++ memcpy(ha->serial_number, &sys_info->acSerialNumber,
++ min(sizeof(ha->serial_number),
++ sizeof(sys_info->acSerialNumber)));
++
++ status = QLA_SUCCESS;
++
++ exit_validate_mac:
++ dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
++ sys_info_dma);
++
++ exit_validate_mac_no_free:
++ return status;
++}
++
++/**
++ * qla4xxx_init_local_data - initialize adapter specific local data
++ * @ha: pointer to host adapter structure.
++ *
++ **/
++static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
++{
++ /* Initilize aen queue */
++ ha->aen_q_count = MAX_AEN_ENTRIES;
++
++ return qla4xxx_get_firmware_status(ha);
++}
++
++static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
++{
++ uint32_t timeout_count;
++ int ready = 0;
++
++ DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n"));
++ for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0;
++ timeout_count--) {
++ if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
++ qla4xxx_get_dhcp_ip_address(ha);
++
++ /* Get firmware state. */
++ if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: unable to get firmware "
++ "state\n", ha->host_no, __func__));
++ break;
++
++ }
++
++ if (ha->firmware_state & FW_STATE_ERROR) {
++ DEBUG2(printk("scsi%ld: %s: an unrecoverable error has"
++ " occurred\n", ha->host_no, __func__));
++ break;
++
++ }
++ if (ha->firmware_state & FW_STATE_CONFIG_WAIT) {
++ /*
++ * The firmware has not yet been issued an Initialize
++ * Firmware command, so issue it now.
++ */
++ if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR)
++ break;
++
++ /* Go back and test for ready state - no wait. */
++ continue;
++ }
++
++ if (ha->firmware_state == FW_STATE_READY) {
++ DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n"));
++ /* The firmware is ready to process SCSI commands. */
++ DEBUG2(dev_info(&ha->pdev->dev,
++ "scsi%ld: %s: MEDIA TYPE - %s\n",
++ ha->host_no,
++ __func__, (ha->addl_fw_state &
++ FW_ADDSTATE_OPTICAL_MEDIA)
++ != 0 ? "OPTICAL" : "COPPER"));
++ DEBUG2(dev_info(&ha->pdev->dev,
++ "scsi%ld: %s: DHCP STATE Enabled "
++ "%s\n",
++ ha->host_no, __func__,
++ (ha->addl_fw_state &
++ FW_ADDSTATE_DHCP_ENABLED) != 0 ?
++ "YES" : "NO"));
++ DEBUG2(dev_info(&ha->pdev->dev,
++ "scsi%ld: %s: LINK %s\n",
++ ha->host_no, __func__,
++ (ha->addl_fw_state &
++ FW_ADDSTATE_LINK_UP) != 0 ?
++ "UP" : "DOWN"));
++ DEBUG2(dev_info(&ha->pdev->dev,
++ "scsi%ld: %s: iSNS Service "
++ "Started %s\n",
++ ha->host_no, __func__,
++ (ha->addl_fw_state &
++ FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ?
++ "YES" : "NO"));
++
++ ready = 1;
++ break;
++ }
++ DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - "
++ "seconds expired= %d\n", ha->host_no, __func__,
++ ha->firmware_state, ha->addl_fw_state,
++ timeout_count));
++ msleep(1000);
++ } /* end of for */
++
++ if (timeout_count <= 0)
++ DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",
++ ha->host_no, __func__));
++
++ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) {
++ DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to"
++ " grab an IP address from DHCP server\n",
++ ha->host_no, __func__));
++ ready = 1;
++ }
++
++ return ready;
++}
++
++/**
++ * qla4xxx_init_firmware - initializes the firmware.
++ * @ha: pointer to host adapter structure.
++ *
++ **/
++static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
++{
++ int status = QLA_ERROR;
++
++ dev_info(&ha->pdev->dev, "Initializing firmware..\n");
++ if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) {
++ DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware "
++ "control block\n", ha->host_no, __func__));
++ return status;
++ }
++ if (!qla4xxx_fw_ready(ha))
++ return status;
++
++ set_bit(AF_ONLINE, &ha->flags);
++ return qla4xxx_get_firmware_status(ha);
++}
++
++static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
++ uint32_t fw_ddb_index)
++{
++ struct dev_db_entry *fw_ddb_entry = NULL;
++ dma_addr_t fw_ddb_entry_dma;
++ struct ddb_entry *ddb_entry = NULL;
++ int found = 0;
++ uint32_t device_state;
++
++ /* Make sure the dma buffer is valid */
++ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
++ sizeof(*fw_ddb_entry),
++ &fw_ddb_entry_dma, GFP_KERNEL);
++ if (fw_ddb_entry == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
++ ha->host_no, __func__));
++ return NULL;
++ }
++
++ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
++ fw_ddb_entry_dma, NULL, NULL,
++ &device_state, NULL, NULL, NULL) ==
++ QLA_ERROR) {
++ DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
++ "fw_ddb_index %d\n", ha->host_no, __func__,
++ fw_ddb_index));
++ return NULL;
++ }
++
++ /* Allocate DDB if not already allocated. */
++ DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,
++ __func__, fw_ddb_index));
++ list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
++ if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsiName,
++ ISCSI_NAME_SIZE) == 0) {
++ found++;
++ break;
++ }
++ }
++
++ if (!found) {
++ DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
++ "new ddb\n", ha->host_no, __func__,
++ fw_ddb_index));
++ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
++ }
++
++ /* if not found allocate new ddb */
++ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
++ fw_ddb_entry_dma);
++
++ return ddb_entry;
++}
++
++/**
++ * qla4xxx_update_ddb_entry - update driver's internal ddb
++ * @ha: pointer to host adapter structure.
++ * @ddb_entry: pointer to device database structure to be filled
++ * @fw_ddb_index: index of the ddb entry in fw ddb table
++ *
++ * This routine updates the driver's internal device database entry
++ * with information retrieved from the firmware's device database
++ * entry for the specified device. The ddb_entry->fw_ddb_index field
++ * must be initialized prior to calling this routine
++ *
++ **/
++int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
++ struct ddb_entry *ddb_entry,
++ uint32_t fw_ddb_index)
++{
++ struct dev_db_entry *fw_ddb_entry = NULL;
++ dma_addr_t fw_ddb_entry_dma;
++ int status = QLA_ERROR;
++
++ if (ddb_entry == NULL) {
++ DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
++ __func__));
++ goto exit_update_ddb;
++ }
++
++ /* Make sure the dma buffer is valid */
++ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
++ sizeof(*fw_ddb_entry),
++ &fw_ddb_entry_dma, GFP_KERNEL);
++ if (fw_ddb_entry == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
++ ha->host_no, __func__));
++
++ goto exit_update_ddb;
++ }
++
++ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
++ fw_ddb_entry_dma, NULL, NULL,
++ &ddb_entry->fw_ddb_device_state, NULL,
++ &ddb_entry->tcp_source_port_num,
++ &ddb_entry->connection_id) ==
++ QLA_ERROR) {
++ DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
++ "fw_ddb_index %d\n", ha->host_no, __func__,
++ fw_ddb_index));
++
++ goto exit_update_ddb;
++ }
++
++ status = QLA_SUCCESS;
++ ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->TSID);
++ ddb_entry->task_mgmt_timeout =
++ le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
++ ddb_entry->CmdSn = 0;
++ ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exeThrottle);
++ ddb_entry->default_relogin_timeout =
++ le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
++ ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->minTime2Wait);
++
++ /* Update index in case it changed */
++ ddb_entry->fw_ddb_index = fw_ddb_index;
++ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
++
++ ddb_entry->port = le16_to_cpu(fw_ddb_entry->portNumber);
++ ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->TargetPortalGroup);
++ memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsiName[0],
++ min(sizeof(ddb_entry->iscsi_name),
++ sizeof(fw_ddb_entry->iscsiName)));
++ memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ipAddr[0],
++ min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ipAddr)));
++
++ DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
++ ha->host_no, __func__, fw_ddb_index,
++ ddb_entry->fw_ddb_device_state, status));
++
++ exit_update_ddb:
++ if (fw_ddb_entry)
++ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
++ fw_ddb_entry, fw_ddb_entry_dma);
++
++ return status;
++}
++
++/**
++ * qla4xxx_alloc_ddb - allocate device database entry
++ * @ha: Pointer to host adapter structure.
++ * @fw_ddb_index: Firmware's device database index
++ *
++ * This routine allocates a ddb_entry, ititializes some values, and
++ * inserts it into the ddb list.
++ **/
++struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
++ uint32_t fw_ddb_index)
++{
++ struct ddb_entry *ddb_entry;
++
++ DEBUG2(printk("scsi%ld: %s: fw_ddb_index [%d]\n", ha->host_no,
++ __func__, fw_ddb_index));
++
++ ddb_entry = qla4xxx_alloc_sess(ha);
++ if (ddb_entry == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
++ "to add fw_ddb_index [%d]\n",
++ ha->host_no, __func__, fw_ddb_index));
++ return ddb_entry;
++ }
++
++ ddb_entry->fw_ddb_index = fw_ddb_index;
++ atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count);
++ atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
++ atomic_set(&ddb_entry->relogin_timer, 0);
++ atomic_set(&ddb_entry->relogin_retry_count, 0);
++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
++ list_add_tail(&ddb_entry->list, &ha->ddb_list);
++ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
++ ha->tot_ddbs++;
++
++ return ddb_entry;
++}
++
++/**
++ * qla4xxx_configure_ddbs - builds driver ddb list
++ * @ha: Pointer to host adapter structure.
++ *
++ * This routine searches for all valid firmware ddb entries and builds
++ * an internal ddb list. Ddbs that are considered valid are those with
++ * a device state of SESSION_ACTIVE.
++ **/
++static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
++{
++ int status = QLA_SUCCESS;
++ uint32_t fw_ddb_index = 0;
++ uint32_t next_fw_ddb_index = 0;
++ uint32_t ddb_state;
++ uint32_t conn_err, err_code;
++ struct ddb_entry *ddb_entry;
++
++ dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
++ for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
++ fw_ddb_index = next_fw_ddb_index) {
++ /* First, let's see if a device exists here */
++ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL,
++ &next_fw_ddb_index, &ddb_state,
++ &conn_err, NULL, NULL) ==
++ QLA_ERROR) {
++ DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
++ "fw_ddb_index %d failed", ha->host_no,
++ __func__, fw_ddb_index));
++ return QLA_ERROR;
++ }
++
++ DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
++ "next_fw_ddb_index=%d.\n", ha->host_no, __func__,
++ fw_ddb_index, ddb_state, next_fw_ddb_index));
++
++ /* Issue relogin, if necessary. */
++ if (ddb_state == DDB_DS_SESSION_FAILED ||
++ ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) {
++ /* Try and login to device */
++ DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",
++ ha->host_no, __func__, fw_ddb_index));
++ err_code = ((conn_err & 0x00ff0000) >> 16);
++ if (err_code == 0x1c || err_code == 0x06) {
++ DEBUG2(printk("scsi%ld: %s send target "
++ "completed "
++ "or access denied failure\n",
++ ha->host_no, __func__));
++ } else
++ qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
++ }
++
++ if (ddb_state != DDB_DS_SESSION_ACTIVE)
++ goto next_one;
++ /*
++ * if fw_ddb with session active state found,
++ * add to ddb_list
++ */
++ DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n",
++ ha->host_no, __func__, fw_ddb_index));
++
++ /* Add DDB to internal our ddb list. */
++ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
++ if (ddb_entry == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
++ "for device at fw_ddb_index %d\n",
++ ha->host_no, __func__, fw_ddb_index));
++ return QLA_ERROR;
++ }
++ /* Fill in the device structure */
++ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
++ QLA_ERROR) {
++ ha->fw_ddb_index_map[fw_ddb_index] =
++ (struct ddb_entry *)INVALID_ENTRY;
++
++
++ DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed "
++ "for fw_ddb_index %d.\n",
++ ha->host_no, __func__, fw_ddb_index));
++ return QLA_ERROR;
++ }
++
++next_one:
++ /* We know we've reached the last device when
++ * next_fw_ddb_index is 0 */
++ if (next_fw_ddb_index == 0)
++ break;
++ }
++
++ dev_info(&ha->pdev->dev, "DDB list done..\n");
++
++ return status;
++}
++
++struct qla4_relog_scan {
++ int halt_wait;
++ uint32_t conn_err;
++ uint32_t err_code;
++ uint32_t fw_ddb_index;
++ uint32_t next_fw_ddb_index;
++ uint32_t fw_ddb_device_state;
++};
++
++static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs)
++{
++ struct ddb_entry *ddb_entry;
++
++ /*
++ * Don't want to do a relogin if connection
++ * error is 0x1c.
++ */
++ rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16);
++ if (rs->err_code == 0x1c || rs->err_code == 0x06) {
++ DEBUG2(printk(
++ "scsi%ld: %s send target"
++ " completed or "
++ "access denied failure\n",
++ ha->host_no, __func__));
++ } else {
++ /* We either have a device that is in
++ * the process of relogging in or a
++ * device that is waiting to be
++ * relogged in */
++ rs->halt_wait = 0;
++
++ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
++ rs->fw_ddb_index);
++ if (ddb_entry == NULL)
++ return QLA_ERROR;
++
++ if (ddb_entry->dev_scan_wait_to_start_relogin != 0
++ && time_after_eq(jiffies,
++ ddb_entry->
++ dev_scan_wait_to_start_relogin))
++ {
++ ddb_entry->dev_scan_wait_to_start_relogin = 0;
++ qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0);
++ }
++ }
++ return QLA_SUCCESS;
++}
++
++static int qla4_scan_for_relogin(struct scsi_qla_host *ha,
++ struct qla4_relog_scan *rs)
++{
++ int error;
++
++ /* scan for relogins
++ * ----------------- */
++ for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES;
++ rs->fw_ddb_index = rs->next_fw_ddb_index) {
++ if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0,
++ NULL, &rs->next_fw_ddb_index,
++ &rs->fw_ddb_device_state,
++ &rs->conn_err, NULL, NULL)
++ == QLA_ERROR)
++ return QLA_ERROR;
++
++ if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS)
++ rs->halt_wait = 0;
++
++ if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED ||
++ rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) {
++ error = qla4_test_rdy(ha, rs);
++ if (error)
++ return error;
++ }
++
++ /* We know we've reached the last device when
++ * next_fw_ddb_index is 0 */
++ if (rs->next_fw_ddb_index == 0)
++ break;
++ }
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_devices_ready - wait for target devices to be logged in
++ * @ha: pointer to adapter structure
++ *
++ * This routine waits up to ql4xdiscoverywait seconds
++ * F/W database during driver load time.
++ **/
++static int qla4xxx_devices_ready(struct scsi_qla_host *ha)
++{
++ int error;
++ unsigned long discovery_wtime;
++ struct qla4_relog_scan rs;
++
++ discovery_wtime = jiffies + (ql4xdiscoverywait * HZ);
++
++ DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait));
++ do {
++ /* poll for AEN. */
++ qla4xxx_get_firmware_state(ha);
++ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) {
++ /* Set time-between-relogin timer */
++ qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS);
++ }
++
++ /* if no relogins active or needed, halt discvery wait */
++ rs.halt_wait = 1;
++
++ error = qla4_scan_for_relogin(ha, &rs);
++
++ if (rs.halt_wait) {
++ DEBUG2(printk("scsi%ld: %s: Delay halted. Devices "
++ "Ready.\n", ha->host_no, __func__));
++ return QLA_SUCCESS;
++ }
++
++ msleep(2000);
++ } while (!time_after_eq(jiffies, discovery_wtime));
++
++ DEBUG3(qla4xxx_get_conn_event_log(ha));
++
++ return QLA_SUCCESS;
++}
++
++static void qla4xxx_flush_AENS(struct scsi_qla_host *ha)
++{
++ unsigned long wtime;
++
++ /* Flush the 0x8014 AEN from the firmware as a result of
++ * Auto connect. We are basically doing get_firmware_ddb()
++ * to determine whether we need to log back in or not.
++ * Trying to do a set ddb before we have processed 0x8014
++ * will result in another set_ddb() for the same ddb. In other
++ * words there will be stale entries in the aen_q.
++ */
++ wtime = jiffies + (2 * HZ);
++ do {
++ if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS)
++ if (ha->firmware_state & (BIT_2 | BIT_0))
++ return;
++
++ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
++ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
++
++ msleep(1000);
++ } while (!time_after_eq(jiffies, wtime));
++
++}
++
++static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
++{
++ uint16_t fw_ddb_index;
++ int status = QLA_SUCCESS;
++
++ /* free the ddb list if is not empty */
++ if (!list_empty(&ha->ddb_list))
++ qla4xxx_free_ddb_list(ha);
++
++ for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++)
++ ha->fw_ddb_index_map[fw_ddb_index] =
++ (struct ddb_entry *)INVALID_ENTRY;
++
++ ha->tot_ddbs = 0;
++
++ qla4xxx_flush_AENS(ha);
++
++ /*
++ * First perform device discovery for active
++ * fw ddb indexes and build
++ * ddb list.
++ */
++ if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR)
++ return status;
++
++ /* Wait for an AEN */
++ qla4xxx_devices_ready(ha);
++
++ /*
++ * Targets can come online after the inital discovery, so processing
++ * the aens here will catch them.
++ */
++ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
++ qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
++
++ return status;
++}
++
++/**
++ * qla4xxx_update_ddb_list - update the driver ddb list
++ * @ha: pointer to host adapter structure.
++ *
++ * This routine obtains device information from the F/W database after
++ * firmware or adapter resets. The device table is preserved.
++ **/
++int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
++{
++ int status = QLA_SUCCESS;
++ struct ddb_entry *ddb_entry, *detemp;
++
++ /* Update the device information for all devices. */
++ list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) {
++ qla4xxx_update_ddb_entry(ha, ddb_entry,
++ ddb_entry->fw_ddb_index);
++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
++ DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
++ "ONLINE\n", ha->host_no, __func__,
++ ddb_entry->fw_ddb_index));
++ } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
++ qla4xxx_mark_device_missing(ha, ddb_entry);
++ }
++ return status;
++}
++
++/**
++ * qla4xxx_relogin_device - re-establish session
++ * @ha: Pointer to host adapter structure.
++ * @ddb_entry: Pointer to device database entry
++ *
++ * This routine does a session relogin with the specified device.
++ * The ddb entry must be assigned prior to making this call.
++ **/
++int qla4xxx_relogin_device(struct scsi_qla_host *ha,
++ struct ddb_entry * ddb_entry)
++{
++ uint16_t relogin_timer;
++
++ relogin_timer = max(ddb_entry->default_relogin_timeout,
++ (uint16_t)RELOGIN_TOV);
++ atomic_set(&ddb_entry->relogin_timer, relogin_timer);
++
++ DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
++ ddb_entry->fw_ddb_index, relogin_timer));
++
++ qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0);
++
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4010_get_topcat_presence - check if it is QLA4040 TopCat Chip
++ * @ha: Pointer to host adapter structure.
++ *
++ **/
++static int qla4010_get_topcat_presence(struct scsi_qla_host *ha)
++{
++ unsigned long flags;
++ uint16_t topcat;
++
++ if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS)
++ return QLA_ERROR;
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ topcat = rd_nvram_word(ha, offsetof(struct eeprom_data,
++ isp4010.topcat));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if ((topcat & TOPCAT_MASK) == TOPCAT_PRESENT)
++ set_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags);
++ else
++ clear_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags);
++ ql4xxx_unlock_nvram(ha);
++ return QLA_SUCCESS;
++}
++
++
++static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
++{
++ unsigned long flags;
++ union external_hw_config_reg extHwConfig;
++
++ DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no,
++ __func__));
++ if (ql4xxx_lock_flash(ha) != QLA_SUCCESS)
++ return (QLA_ERROR);
++ if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) {
++ ql4xxx_unlock_flash(ha);
++ return (QLA_ERROR);
++ }
++
++ /* Get EEPRom Parameters from NVRAM and validate */
++ dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n");
++ if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) {
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ extHwConfig.Asuint32_t =
++ rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ } else {
++ /*
++ * QLogic adapters should always have a valid NVRAM.
++ * If not valid, do not load.
++ */
++ dev_warn(&ha->pdev->dev,
++ "scsi%ld: %s: EEProm checksum invalid. "
++ "Please update your EEPROM\n", ha->host_no,
++ __func__);
++
++ /* set defaults */
++ if (is_qla4010(ha))
++ extHwConfig.Asuint32_t = 0x1912;
++ else if (is_qla4022(ha))
++ extHwConfig.Asuint32_t = 0x0023;
++ }
++ DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n",
++ ha->host_no, __func__, extHwConfig.Asuint32_t));
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha));
++ readl(isp_ext_hw_conf(ha));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ ql4xxx_unlock_nvram(ha);
++ ql4xxx_unlock_flash(ha);
++
++ return (QLA_SUCCESS);
++}
++
++static void qla4x00_pci_config(struct scsi_qla_host *ha)
++{
++ uint16_t w, mwi;
++
++ dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
++
++ pci_set_master(ha->pdev);
++ mwi = 0;
++ if (pci_set_mwi(ha->pdev))
++ mwi = PCI_COMMAND_INVALIDATE;
++ /*
++ * We want to respect framework's setting of PCI configuration space
++ * command register and also want to make sure that all bits of
++ * interest to us are properly set in command register.
++ */
++ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
++ w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
++ w &= ~PCI_COMMAND_INTX_DISABLE;
++ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
++}
++
++static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
++{
++ int status = QLA_ERROR;
++ uint32_t max_wait_time;
++ unsigned long flags;
++ uint32_t mbox_status;
++
++ dev_info(&ha->pdev->dev, "Starting firmware ...\n");
++
++ /*
++ * Start firmware from flash ROM
++ *
++ * WORKAROUND: Stuff a non-constant value that the firmware can
++ * use as a seed for a random number generator in MB7 prior to
++ * setting BOOT_ENABLE. Fixes problem where the TCP
++ * connections use the same TCP ports after each reboot,
++ * causing some connections to not get re-established.
++ */
++ DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n",
++ ha->host_no, __func__));
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel(jiffies, &ha->reg->mailbox[7]);
++ if (is_qla4022(ha))
++ writel(set_rmask(NVR_WRITE_ENABLE),
++ &ha->reg->u1.isp4022.nvram);
++
++ writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ /* Wait for firmware to come UP. */
++ max_wait_time = FIRMWARE_UP_TOV * 4;
++ do {
++ uint32_t ctrl_status;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ ctrl_status = readw(&ha->reg->ctrl_status);
++ mbox_status = readw(&ha->reg->mailbox[0]);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR))
++ break;
++ if (mbox_status == MBOX_STS_COMMAND_COMPLETE)
++ break;
++
++ DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to "
++ "complete... ctrl_sts=0x%x, remaining=%d\n",
++ ha->host_no, __func__, ctrl_status,
++ max_wait_time));
++
++ msleep(250);
++ } while ((max_wait_time--));
++
++ if (mbox_status == MBOX_STS_COMMAND_COMPLETE) {
++ DEBUG(printk("scsi%ld: %s: Firmware has started\n",
++ ha->host_no, __func__));
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
++ &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ status = QLA_SUCCESS;
++ } else {
++ printk(KERN_INFO "scsi%ld: %s: Boot firmware failed "
++ "- mbox status 0x%x\n", ha->host_no, __func__,
++ mbox_status);
++ status = QLA_ERROR;
++ }
++ return status;
++}
++
++static int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
++{
++#define QL4_LOCK_DRVR_WAIT 300
++#define QL4_LOCK_DRVR_SLEEP 100
++
++ int drvr_wait = QL4_LOCK_DRVR_WAIT;
++ while (drvr_wait) {
++ if (ql4xxx_lock_drvr(a) == 0) {
++ msleep(QL4_LOCK_DRVR_SLEEP);
++ if (drvr_wait) {
++ DEBUG2(printk("scsi%ld: %s: Waiting for "
++ "Global Init Semaphore...n",
++ a->host_no,
++ __func__));
++ }
++ drvr_wait -= QL4_LOCK_DRVR_SLEEP;
++ } else {
++ DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
++ "acquired.n", a->host_no, __func__));
++ return QLA_SUCCESS;
++ }
++ }
++ return QLA_ERROR;
++}
++
++/**
++ * qla4xxx_start_firmware - starts qla4xxx firmware
++ * @ha: Pointer to host adapter structure.
++ *
++ * This routine performs the neccessary steps to start the firmware for
++ * the QLA4010 adapter.
++ **/
++static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
++{
++ unsigned long flags = 0;
++ uint32_t mbox_status;
++ int status = QLA_ERROR;
++ int soft_reset = 1;
++ int config_chip = 0;
++
++ if (is_qla4010(ha)){
++ if (qla4010_get_topcat_presence(ha) != QLA_SUCCESS)
++ return QLA_ERROR;
++ }
++
++ if (is_qla4022(ha))
++ ql4xxx_set_mac_number(ha);
++
++ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
++ return QLA_ERROR;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++
++ DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no,
++ __func__, readw(isp_port_ctrl(ha))));
++ DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no,
++ __func__, readw(isp_port_status(ha))));
++
++ /* Is Hardware already initialized? */
++ if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) {
++ DEBUG(printk("scsi%ld: %s: Hardware has already been "
++ "initialized\n", ha->host_no, __func__));
++
++ /* Receive firmware boot acknowledgement */
++ mbox_status = readw(&ha->reg->mailbox[0]);
++
++ DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= "
++ "0x%x\n", ha->host_no, __func__, mbox_status));
++
++ /* Is firmware already booted? */
++ if (mbox_status == 0) {
++ /* F/W not running, must be config by net driver */
++ config_chip = 1;
++ soft_reset = 0;
++ } else {
++ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
++ &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: Get firmware "
++ "state -- state = 0x%x\n",
++ ha->host_no,
++ __func__, ha->firmware_state));
++ /* F/W is running */
++ if (ha->firmware_state &
++ FW_STATE_CONFIG_WAIT) {
++ DEBUG2(printk("scsi%ld: %s: Firmware "
++ "in known state -- "
++ "config and "
++ "boot, state = 0x%x\n",
++ ha->host_no, __func__,
++ ha->firmware_state));
++ config_chip = 1;
++ soft_reset = 0;
++ }
++ } else {
++ DEBUG2(printk("scsi%ld: %s: Firmware in "
++ "unknown state -- resetting,"
++ " state = "
++ "0x%x\n", ha->host_no, __func__,
++ ha->firmware_state));
++ }
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ }
++ } else {
++ DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been "
++ "started - resetting\n", ha->host_no, __func__));
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ",
++ ha->host_no, __func__, soft_reset, config_chip));
++ if (soft_reset) {
++ DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no,
++ __func__));
++ status = qla4xxx_soft_reset(ha);
++ if (status == QLA_ERROR) {
++ DEBUG(printk("scsi%d: %s: Soft Reset failed!\n",
++ ha->host_no, __func__));
++ ql4xxx_unlock_drvr(ha);
++ return QLA_ERROR;
++ }
++ config_chip = 1;
++
++ /* Reset clears the semaphore, so aquire again */
++ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
++ return QLA_ERROR;
++ }
++
++ if (config_chip) {
++ if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS)
++ status = qla4xxx_start_firmware_from_flash(ha);
++ }
++
++ ql4xxx_unlock_drvr(ha);
++ if (status == QLA_SUCCESS) {
++ qla4xxx_get_fw_version(ha);
++ if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags))
++ qla4xxx_get_crash_record(ha);
++ } else {
++ DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n",
++ ha->host_no, __func__));
++ }
++ return status;
++}
++
++
++/**
++ * qla4xxx_initialize_adapter - initiailizes hba
++ * @ha: Pointer to host adapter structure.
++ * @renew_ddb_list: Indicates what to do with the adapter's ddb list
++ * after adapter recovery has completed.
++ * 0=preserve ddb list, 1=destroy and rebuild ddb list
++ *
++ * This routine parforms all of the steps necessary to initialize the adapter.
++ *
++ **/
++int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
++ uint8_t renew_ddb_list)
++{
++ int status = QLA_ERROR;
++ int8_t ip_address[IP_ADDR_LEN] = {0} ;
++
++ ha->eeprom_cmd_data = 0;
++
++ qla4x00_pci_config(ha);
++
++ qla4xxx_disable_intrs(ha);
++
++ /* Initialize the Host adapter request/response queues and firmware */
++ if (qla4xxx_start_firmware(ha) == QLA_ERROR)
++ return status;
++
++ if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
++ return status;
++
++ if (qla4xxx_init_local_data(ha) == QLA_ERROR)
++ return status;
++
++ status = qla4xxx_init_firmware(ha);
++ if (status == QLA_ERROR)
++ return status;
++
++ /*
++ * FW is waiting to get an IP address from DHCP server: Skip building
++ * the ddb_list and wait for DHCP lease acquired aen to come in
++ * followed by 0x8014 aen" to trigger the tgt discovery process.
++ */
++ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)
++ return status;
++
++ /* Skip device discovery if ip and subnet is zero */
++ if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 ||
++ memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0)
++ return status;
++
++ if (renew_ddb_list == PRESERVE_DDB_LIST) {
++ /*
++ * We want to preserve lun states (i.e. suspended, etc.)
++ * for recovery initiated by the driver. So just update
++ * the device states for the existing ddb_list.
++ */
++ qla4xxx_reinitialize_ddb_list(ha);
++ } else if (renew_ddb_list == REBUILD_DDB_LIST) {
++ /*
++ * We want to build the ddb_list from scratch during
++ * driver initialization and recovery initiated by the
++ * INT_HBA_RESET IOCTL.
++ */
++ status = qla4xxx_initialize_ddb_list(ha);
++ if (status == QLA_ERROR) {
++ DEBUG2(printk("%s(%ld) Error occurred during build"
++ "ddb list\n", __func__, ha->host_no));
++ goto exit_init_hba;
++ }
++
++ }
++ if (!ha->tot_ddbs) {
++ DEBUG2(printk("scsi%ld: Failed to initialize devices or none "
++ "present in Firmware device database\n",
++ ha->host_no));
++ }
++
++ exit_init_hba:
++ return status;
++
++}
++
++/**
++ * qla4xxx_add_device_dynamically - ddb addition due to an AEN
++ * @ha: Pointer to host adapter structure.
++ * @fw_ddb_index: Firmware's device database index
++ *
++ * This routine processes adds a device as a result of an 8014h AEN.
++ **/
++static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
++ uint32_t fw_ddb_index)
++{
++ struct ddb_entry * ddb_entry;
++
++ /* First allocate a device structure */
++ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
++ if (ddb_entry == NULL) {
++ DEBUG2(printk(KERN_WARNING
++ "scsi%ld: Unable to allocate memory to add "
++ "fw_ddb_index %d\n", ha->host_no, fw_ddb_index));
++ return;
++ }
++
++ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
++ QLA_ERROR) {
++ ha->fw_ddb_index_map[fw_ddb_index] =
++ (struct ddb_entry *)INVALID_ENTRY;
++ DEBUG2(printk(KERN_WARNING
++ "scsi%ld: failed to add new device at index "
++ "[%d]\n Unable to retrieve fw ddb entry\n",
++ ha->host_no, fw_ddb_index));
++ qla4xxx_free_ddb(ha, ddb_entry);
++ return;
++ }
++
++ if (qla4xxx_add_sess(ddb_entry)) {
++ DEBUG2(printk(KERN_WARNING
++ "scsi%ld: failed to add new device at index "
++ "[%d]\n Unable to add connection and session\n",
++ ha->host_no, fw_ddb_index));
++ qla4xxx_free_ddb(ha, ddb_entry);
++ }
++}
++
++/**
++ * qla4xxx_process_ddb_changed - process ddb state change
++ * @ha - Pointer to host adapter structure.
++ * @fw_ddb_index - Firmware's device database index
++ * @state - Device state
++ *
++ * This routine processes a Decive Database Changed AEN Event.
++ **/
++int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
++ uint32_t fw_ddb_index, uint32_t state)
++{
++ struct ddb_entry * ddb_entry;
++ uint32_t old_fw_ddb_device_state;
++
++ /* check for out of range index */
++ if (fw_ddb_index >= MAX_DDB_ENTRIES)
++ return QLA_ERROR;
++
++ /* Get the corresponging ddb entry */
++ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index);
++ /* Device does not currently exist in our database. */
++ if (ddb_entry == NULL) {
++ if (state == DDB_DS_SESSION_ACTIVE)
++ qla4xxx_add_device_dynamically(ha, fw_ddb_index);
++ return QLA_SUCCESS;
++ }
++
++ /* Device already exists in our database. */
++ old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state;
++ DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for "
++ "index [%d]\n", ha->host_no, __func__,
++ ddb_entry->fw_ddb_device_state, state, fw_ddb_index));
++ if (old_fw_ddb_device_state == state &&
++ state == DDB_DS_SESSION_ACTIVE) {
++ /* Do nothing, state not changed. */
++ return QLA_SUCCESS;
++ }
++
++ ddb_entry->fw_ddb_device_state = state;
++ /* Device is back online. */
++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
++ atomic_set(&ddb_entry->port_down_timer,
++ ha->port_down_retry_count);
++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
++ atomic_set(&ddb_entry->relogin_retry_count, 0);
++ atomic_set(&ddb_entry->relogin_timer, 0);
++ clear_bit(DF_RELOGIN, &ddb_entry->flags);
++ clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
++ iscsi_if_create_session_done(ddb_entry->conn);
++ /*
++ * Change the lun state to READY in case the lun TIMEOUT before
++ * the device came back.
++ */
++ } else {
++ /* Device went away, try to relogin. */
++ /* Mark device missing */
++ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
++ qla4xxx_mark_device_missing(ha, ddb_entry);
++ /*
++ * Relogin if device state changed to a not active state.
++ * However, do not relogin if this aen is a result of an IOCTL
++ * logout (DF_NO_RELOGIN) or if this is a discovered device.
++ */
++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
++ !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
++ !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) &&
++ !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) {
++ /*
++ * This triggers a relogin. After the relogin_timer
++ * expires, the relogin gets scheduled. We must wait a
++ * minimum amount of time since receiving an 0x8014 AEN
++ * with failed device_state or a logout response before
++ * we can issue another relogin.
++ */
++ /* Firmware padds this timeout: (time2wait +1).
++ * Driver retry to login should be longer than F/W.
++ * Otherwise F/W will fail
++ * set_ddb() mbx cmd with 0x4005 since it still
++ * counting down its time2wait.
++ */
++ atomic_set(&ddb_entry->relogin_timer, 0);
++ atomic_set(&ddb_entry->retry_relogin_timer,
++ ddb_entry->default_time2wait + 4);
++ }
++ }
++
++ return QLA_SUCCESS;
++}
++
+diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
+new file mode 100644
+index 0000000..0d61797
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_inline.h
+@@ -0,0 +1,84 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++/*
++ *
++ * qla4xxx_lookup_ddb_by_fw_index
++ * This routine locates a device handle given the firmware device
++ * database index. If device doesn't exist, returns NULL.
++ *
++ * Input:
++ * ha - Pointer to host adapter structure.
++ * fw_ddb_index - Firmware's device database index
++ *
++ * Returns:
++ * Pointer to the corresponding internal device database structure
++ */
++static inline struct ddb_entry *
++qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
++{
++ struct ddb_entry *ddb_entry = NULL;
++
++ if ((fw_ddb_index < MAX_DDB_ENTRIES) &&
++ (ha->fw_ddb_index_map[fw_ddb_index] !=
++ (struct ddb_entry *) INVALID_ENTRY)) {
++ ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
++ }
++
++ DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n",
++ ha->host_no, __func__, fw_ddb_index, ddb_entry));
++
++ return ddb_entry;
++}
++
++static inline void
++__qla4xxx_enable_intrs(struct scsi_qla_host *ha)
++{
++ if (is_qla4022(ha)) {
++ writel(set_rmask(IMR_SCSI_INTR_ENABLE),
++ &ha->reg->u1.isp4022.intr_mask);
++ readl(&ha->reg->u1.isp4022.intr_mask);
++ } else {
++ writel(set_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ }
++ set_bit(AF_INTERRUPTS_ON, &ha->flags);
++}
++
++static inline void
++__qla4xxx_disable_intrs(struct scsi_qla_host *ha)
++{
++ if (is_qla4022(ha)) {
++ writel(clr_rmask(IMR_SCSI_INTR_ENABLE),
++ &ha->reg->u1.isp4022.intr_mask);
++ readl(&ha->reg->u1.isp4022.intr_mask);
++ } else {
++ writel(clr_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ }
++ clear_bit(AF_INTERRUPTS_ON, &ha->flags);
++}
++
++static inline void
++qla4xxx_enable_intrs(struct scsi_qla_host *ha)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ __qla4xxx_enable_intrs(ha);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++}
++
++static inline void
++qla4xxx_disable_intrs(struct scsi_qla_host *ha)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ __qla4xxx_disable_intrs(ha);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++}
+diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
+new file mode 100644
+index 0000000..c0a254b
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_iocb.c
+@@ -0,0 +1,368 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#include "ql4_def.h"
++
++#include <scsi/scsi_tcq.h>
++
++/**
++ * qla4xxx_get_req_pkt - returns a valid entry in request queue.
++ * @ha: Pointer to host adapter structure.
++ * @queue_entry: Pointer to pointer to queue entry structure
++ *
++ * This routine performs the following tasks:
++ * - returns the current request_in pointer (if queue not full)
++ * - advances the request_in pointer
++ * - checks for queue full
++ **/
++int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
++ struct queue_entry **queue_entry)
++{
++ uint16_t request_in;
++ uint8_t status = QLA_SUCCESS;
++
++ *queue_entry = ha->request_ptr;
++
++ /* get the latest request_in and request_out index */
++ request_in = ha->request_in;
++ ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
++
++ /* Advance request queue pointer and check for queue full */
++ if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
++ request_in = 0;
++ ha->request_ptr = ha->request_ring;
++ } else {
++ request_in++;
++ ha->request_ptr++;
++ }
++
++ /* request queue is full, try again later */
++ if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
++ /* restore request pointer */
++ ha->request_ptr = *queue_entry;
++ status = QLA_ERROR;
++ } else {
++ ha->request_in = request_in;
++ memset(*queue_entry, 0, sizeof(**queue_entry));
++ }
++
++ return status;
++}
++
++/**
++ * qla4xxx_send_marker_iocb - issues marker iocb to HBA
++ * @ha: Pointer to host adapter structure.
++ * @ddb_entry: Pointer to device database entry
++ * @lun: SCSI LUN
++ * @marker_type: marker identifier
++ *
++ * This routine issues a marker IOCB.
++ **/
++int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
++ struct ddb_entry *ddb_entry, int lun)
++{
++ struct marker_entry *marker_entry;
++ unsigned long flags = 0;
++ uint8_t status = QLA_SUCCESS;
++
++ /* Acquire hardware specific lock */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++
++ /* Get pointer to the queue entry for the marker */
++ if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) !=
++ QLA_SUCCESS) {
++ status = QLA_ERROR;
++ goto exit_send_marker;
++ }
++
++ /* Put the marker in the request queue */
++ marker_entry->hdr.entryType = ET_MARKER;
++ marker_entry->hdr.entryCount = 1;
++ marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
++ marker_entry->modifier = cpu_to_le16(MM_LUN_RESET);
++ int_to_scsilun(lun, &marker_entry->lun);
++ wmb();
++
++ /* Tell ISP it's got a new I/O request */
++ writel(ha->request_in, &ha->reg->req_q_in);
++ readl(&ha->reg->req_q_in);
++
++exit_send_marker:
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ return status;
++}
++
++struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
++ struct scsi_qla_host *ha)
++{
++ struct continuation_t1_entry *cont_entry;
++
++ cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
++
++ /* Advance request queue pointer */
++ if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
++ ha->request_in = 0;
++ ha->request_ptr = ha->request_ring;
++ } else {
++ ha->request_in++;
++ ha->request_ptr++;
++ }
++
++ /* Load packet defaults */
++ cont_entry->hdr.entryType = ET_CONTINUE;
++ cont_entry->hdr.entryCount = 1;
++ cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in);
++
++ return cont_entry;
++}
++
++uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
++{
++ uint16_t iocbs;
++
++ iocbs = 1;
++ if (dsds > COMMAND_SEG) {
++ iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG;
++ if ((dsds - COMMAND_SEG) % CONTINUE_SEG)
++ iocbs++;
++ }
++ return iocbs;
++}
++
++void qla4xxx_build_scsi_iocbs(struct srb *srb,
++ struct command_t3_entry *cmd_entry,
++ uint16_t tot_dsds)
++{
++ struct scsi_qla_host *ha;
++ uint16_t avail_dsds;
++ struct data_seg_a64 *cur_dsd;
++ struct scsi_cmnd *cmd;
++
++ cmd = srb->cmd;
++ ha = srb->ha;
++
++ if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
++ /* No data being transferred */
++ cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0);
++ return;
++ }
++
++ avail_dsds = COMMAND_SEG;
++ cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
++
++ /* Load data segments */
++ if (cmd->use_sg) {
++ struct scatterlist *cur_seg;
++ struct scatterlist *end_seg;
++
++ cur_seg = (struct scatterlist *)cmd->request_buffer;
++ end_seg = cur_seg + tot_dsds;
++ while (cur_seg < end_seg) {
++ dma_addr_t sle_dma;
++
++ /* Allocate additional continuation packets? */
++ if (avail_dsds == 0) {
++ struct continuation_t1_entry *cont_entry;
++
++ cont_entry = qla4xxx_alloc_cont_entry(ha);
++ cur_dsd =
++ (struct data_seg_a64 *)
++ &cont_entry->dataseg[0];
++ avail_dsds = CONTINUE_SEG;
++ }
++
++ sle_dma = sg_dma_address(cur_seg);
++ cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
++ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
++ cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg));
++ avail_dsds--;
++
++ cur_dsd++;
++ cur_seg++;
++ }
++ } else {
++ cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
++ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
++ cur_dsd->count = cpu_to_le32(cmd->request_bufflen);
++ }
++}
++
++/**
++ * qla4xxx_send_command_to_isp - issues command to HBA
++ * @ha: pointer to host adapter structure.
++ * @srb: pointer to SCSI Request Block to be sent to ISP
++ *
++ * This routine is called by qla4xxx_queuecommand to build an ISP
++ * command and pass it to the ISP for execution.
++ **/
++int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
++{
++ struct scsi_cmnd *cmd = srb->cmd;
++ struct ddb_entry *ddb_entry;
++ struct command_t3_entry *cmd_entry;
++ struct scatterlist *sg = NULL;
++
++ uint16_t tot_dsds;
++ uint16_t req_cnt;
++
++ unsigned long flags;
++ uint16_t cnt;
++ uint32_t index;
++ char tag[2];
++
++ /* Get real lun and adapter */
++ ddb_entry = srb->ddb;
++
++ /* Send marker(s) if needed. */
++ if (ha->marker_needed == 1) {
++ if (qla4xxx_send_marker_iocb(ha, ddb_entry,
++ cmd->device->lun) != QLA_SUCCESS)
++ return QLA_ERROR;
++
++ ha->marker_needed = 0;
++ }
++ tot_dsds = 0;
++
++ /* Acquire hardware specific lock */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++
++ index = (uint32_t)cmd->request->tag;
++
++ /* Calculate the number of request entries needed. */
++ if (cmd->use_sg) {
++ sg = (struct scatterlist *)cmd->request_buffer;
++ tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
++ cmd->sc_data_direction);
++ if (tot_dsds == 0)
++ goto queuing_error;
++ } else if (cmd->request_bufflen) {
++ dma_addr_t req_dma;
++
++ req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
++ cmd->request_bufflen,
++ cmd->sc_data_direction);
++ if (dma_mapping_error(req_dma))
++ goto queuing_error;
++
++ srb->dma_handle = req_dma;
++ tot_dsds = 1;
++ }
++ req_cnt = qla4xxx_calc_request_entries(tot_dsds);
++
++ if (ha->req_q_count < (req_cnt + 2)) {
++ cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
++ if (ha->request_in < cnt)
++ ha->req_q_count = cnt - ha->request_in;
++ else
++ ha->req_q_count = REQUEST_QUEUE_DEPTH -
++ (ha->request_in - cnt);
++ }
++
++ if (ha->req_q_count < (req_cnt + 2))
++ goto queuing_error;
++
++ /* total iocbs active */
++ if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH)
++ goto queuing_error;
++
++ /* Build command packet */
++ cmd_entry = (struct command_t3_entry *) ha->request_ptr;
++ memset(cmd_entry, 0, sizeof(struct command_t3_entry));
++ cmd_entry->hdr.entryType = ET_COMMAND;
++ cmd_entry->handle = cpu_to_le32(index);
++ cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
++ cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id);
++
++ int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
++ cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn);
++ cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen);
++ memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
++ cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
++ cmd_entry->hdr.entryCount = req_cnt;
++
++ /* Set data transfer direction control flags
++ * NOTE: Look at data_direction bits iff there is data to be
++ * transferred, as the data direction bit is sometimed filled
++ * in when there is no data to be transferred */
++ cmd_entry->control_flags = CF_NO_DATA;
++ if (cmd->request_bufflen) {
++ if (cmd->sc_data_direction == DMA_TO_DEVICE)
++ cmd_entry->control_flags = CF_WRITE;
++ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
++ cmd_entry->control_flags = CF_READ;
++ }
++
++ /* Set tagged queueing control flags */
++ cmd_entry->control_flags |= CF_SIMPLE_TAG;
++ if (scsi_populate_tag_msg(cmd, tag))
++ switch (tag[0]) {
++ case MSG_HEAD_TAG:
++ cmd_entry->control_flags |= CF_HEAD_TAG;
++ break;
++ case MSG_ORDERED_TAG:
++ cmd_entry->control_flags |= CF_ORDERED_TAG;
++ break;
++ }
++
++
++ /* Advance request queue pointer */
++ ha->request_in++;
++ if (ha->request_in == REQUEST_QUEUE_DEPTH) {
++ ha->request_in = 0;
++ ha->request_ptr = ha->request_ring;
++ } else
++ ha->request_ptr++;
++
++
++ qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
++ wmb();
++
++ /*
++ * Check to see if adapter is online before placing request on
++ * request queue. If a reset occurs and a request is in the queue,
++ * the firmware will still attempt to process the request, retrieving
++ * garbage for pointers.
++ */
++ if (!test_bit(AF_ONLINE, &ha->flags)) {
++ DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
++ "Do not issue command.\n",
++ ha->host_no, __func__));
++ goto queuing_error;
++ }
++
++ srb->cmd->host_scribble = (unsigned char *)srb;
++
++ /* update counters */
++ srb->state = SRB_ACTIVE_STATE;
++ srb->flags |= SRB_DMA_VALID;
++
++ /* Track IOCB used */
++ ha->iocb_cnt += req_cnt;
++ srb->iocb_cnt = req_cnt;
++ ha->req_q_count -= req_cnt;
++
++ /* Debug print statements */
++ writel(ha->request_in, &ha->reg->req_q_in);
++ readl(&ha->reg->req_q_in);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ return QLA_SUCCESS;
++
++queuing_error:
++
++ if (cmd->use_sg && tot_dsds) {
++ sg = (struct scatterlist *) cmd->request_buffer;
++ pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
++ cmd->sc_data_direction);
++ } else if (tot_dsds)
++ pci_unmap_single(ha->pdev, srb->dma_handle,
++ cmd->request_bufflen, cmd->sc_data_direction);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ return QLA_ERROR;
++}
++
+diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
+new file mode 100644
+index 0000000..1e28332
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_isr.c
+@@ -0,0 +1,796 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#include "ql4_def.h"
++
++/**
++ * qla2x00_process_completed_request() - Process a Fast Post response.
++ * @ha: SCSI driver HA context
++ * @index: SRB index
++ **/
++static void qla4xxx_process_completed_request(struct scsi_qla_host *ha,
++ uint32_t index)
++{
++ struct srb *srb;
++
++ srb = qla4xxx_del_from_active_array(ha, index);
++ if (srb) {
++ /* Save ISP completion status */
++ srb->cmd->result = DID_OK << 16;
++ qla4xxx_srb_compl(ha, srb);
++ } else {
++ DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = "
++ "%d\n", ha->host_no, index));
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++ }
++}
++
++/**
++ * qla4xxx_status_entry - processes status IOCBs
++ * @ha: Pointer to host adapter structure.
++ * @sts_entry: Pointer to status entry structure.
++ **/
++static void qla4xxx_status_entry(struct scsi_qla_host *ha,
++ struct status_entry *sts_entry)
++{
++ uint8_t scsi_status;
++ struct scsi_cmnd *cmd;
++ struct srb *srb;
++ struct ddb_entry *ddb_entry;
++ uint32_t residual;
++ uint16_t sensebytecnt;
++
++ if (sts_entry->completionStatus == SCS_COMPLETE &&
++ sts_entry->scsiStatus == 0) {
++ qla4xxx_process_completed_request(ha,
++ le32_to_cpu(sts_entry->
++ handle));
++ return;
++ }
++
++ srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
++ if (!srb) {
++ /* FIXMEdg: Don't we need to reset ISP in this case??? */
++ DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
++ "handle 0x%x, sp=%p. This cmd may have already "
++ "been completed.\n", ha->host_no, __func__,
++ le32_to_cpu(sts_entry->handle), srb));
++ return;
++ }
++
++ cmd = srb->cmd;
++ if (cmd == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Command already returned back to "
++ "OS pkt->handle=%d srb=%p srb->state:%d\n",
++ ha->host_no, __func__, sts_entry->handle,
++ srb, srb->state));
++ dev_warn(&ha->pdev->dev, "Command is NULL:"
++ " already returned to OS (srb=%p)\n", srb);
++ return;
++ }
++
++ ddb_entry = srb->ddb;
++ if (ddb_entry == NULL) {
++ cmd->result = DID_NO_CONNECT << 16;
++ goto status_entry_exit;
++ }
++
++ residual = le32_to_cpu(sts_entry->residualByteCnt);
++
++ /* Translate ISP error to a Linux SCSI error. */
++ scsi_status = sts_entry->scsiStatus;
++ switch (sts_entry->completionStatus) {
++ case SCS_COMPLETE:
++ if (scsi_status == 0) {
++ cmd->result = DID_OK << 16;
++ break;
++ }
++
++ if (sts_entry->iscsiFlags &
++ (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
++ cmd->resid = residual;
++
++ cmd->result = DID_OK << 16 | scsi_status;
++
++ if (scsi_status != SCSI_CHECK_CONDITION)
++ break;
++
++ /* Copy Sense Data into sense buffer. */
++ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++
++ sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
++ if (sensebytecnt == 0)
++ break;
++
++ memcpy(cmd->sense_buffer, sts_entry->senseData,
++ min(sensebytecnt,
++ (uint16_t) sizeof(cmd->sense_buffer)));
++
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
++ "ASC/ASCQ = %02x/%02x\n", ha->host_no,
++ cmd->device->channel, cmd->device->id,
++ cmd->device->lun, __func__,
++ sts_entry->senseData[2] & 0x0f,
++ sts_entry->senseData[12],
++ sts_entry->senseData[13]));
++
++ srb->flags |= SRB_GOT_SENSE;
++ break;
++
++ case SCS_INCOMPLETE:
++ /* Always set the status to DID_ERROR, since
++ * all conditions result in that status anyway */
++ cmd->result = DID_ERROR << 16;
++ break;
++
++ case SCS_RESET_OCCURRED:
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n",
++ ha->host_no, cmd->device->channel,
++ cmd->device->id, cmd->device->lun, __func__));
++
++ cmd->result = DID_RESET << 16;
++ break;
++
++ case SCS_ABORTED:
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n",
++ ha->host_no, cmd->device->channel,
++ cmd->device->id, cmd->device->lun, __func__));
++
++ cmd->result = DID_RESET << 16;
++ break;
++
++ case SCS_TIMEOUT:
++ DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n",
++ ha->host_no, cmd->device->channel,
++ cmd->device->id, cmd->device->lun));
++
++ cmd->result = DID_BUS_BUSY << 16;
++
++ /*
++ * Mark device missing so that we won't continue to send
++ * I/O to this device. We should get a ddb state change
++ * AEN soon.
++ */
++ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
++ qla4xxx_mark_device_missing(ha, ddb_entry);
++ break;
++
++ case SCS_DATA_UNDERRUN:
++ case SCS_DATA_OVERRUN:
++ if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
++ "residual = 0x%x\n", ha->host_no,
++ cmd->device->channel, cmd->device->id,
++ cmd->device->lun, __func__, residual));
++
++ cmd->result = DID_ERROR << 16;
++ break;
++ }
++
++ if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
++ /*
++ * Firmware detected a SCSI transport underrun
++ * condition
++ */
++ cmd->resid = residual;
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
++ "detected, xferlen = 0x%x, residual = "
++ "0x%x\n",
++ ha->host_no, cmd->device->channel,
++ cmd->device->id,
++ cmd->device->lun, __func__,
++ cmd->request_bufflen,
++ residual));
++ }
++
++ /*
++ * If there is scsi_status, it takes precedense over
++ * underflow condition.
++ */
++ if (scsi_status != 0) {
++ cmd->result = DID_OK << 16 | scsi_status;
++
++ if (scsi_status != SCSI_CHECK_CONDITION)
++ break;
++
++ /* Copy Sense Data into sense buffer. */
++ memset(cmd->sense_buffer, 0,
++ sizeof(cmd->sense_buffer));
++
++ sensebytecnt =
++ le16_to_cpu(sts_entry->senseDataByteCnt);
++ if (sensebytecnt == 0)
++ break;
++
++ memcpy(cmd->sense_buffer, sts_entry->senseData,
++ min(sensebytecnt,
++ (uint16_t) sizeof(cmd->sense_buffer)));
++
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
++ "ASC/ASCQ = %02x/%02x\n", ha->host_no,
++ cmd->device->channel, cmd->device->id,
++ cmd->device->lun, __func__,
++ sts_entry->senseData[2] & 0x0f,
++ sts_entry->senseData[12],
++ sts_entry->senseData[13]));
++ } else {
++ /*
++ * If RISC reports underrun and target does not
++ * report it then we must have a lost frame, so
++ * tell upper layer to retry it by reporting a
++ * bus busy.
++ */
++ if ((sts_entry->iscsiFlags &
++ ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
++ cmd->result = DID_BUS_BUSY << 16;
++ } else if ((cmd->request_bufflen - residual) <
++ cmd->underflow) {
++ /*
++ * Handle mid-layer underflow???
++ *
++ * For kernels less than 2.4, the driver must
++ * return an error if an underflow is detected.
++ * For kernels equal-to and above 2.4, the
++ * mid-layer will appearantly handle the
++ * underflow by detecting the residual count --
++ * unfortunately, we do not see where this is
++ * actually being done. In the interim, we
++ * will return DID_ERROR.
++ */
++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
++ "Mid-layer Data underrun, "
++ "xferlen = 0x%x, "
++ "residual = 0x%x\n", ha->host_no,
++ cmd->device->channel,
++ cmd->device->id,
++ cmd->device->lun, __func__,
++ cmd->request_bufflen, residual));
++
++ cmd->result = DID_ERROR << 16;
++ } else {
++ cmd->result = DID_OK << 16;
++ }
++ }
++ break;
++
++ case SCS_DEVICE_LOGGED_OUT:
++ case SCS_DEVICE_UNAVAILABLE:
++ /*
++ * Mark device missing so that we won't continue to
++ * send I/O to this device. We should get a ddb
++ * state change AEN soon.
++ */
++ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
++ qla4xxx_mark_device_missing(ha, ddb_entry);
++
++ cmd->result = DID_BUS_BUSY << 16;
++ break;
++
++ case SCS_QUEUE_FULL:
++ /*
++ * SCSI Mid-Layer handles device queue full
++ */
++ cmd->result = DID_OK << 16 | sts_entry->scsiStatus;
++ DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected "
++ "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x,"
++ " iResp=%02x\n", ha->host_no, cmd->device->id,
++ cmd->device->lun, __func__,
++ sts_entry->completionStatus,
++ sts_entry->scsiStatus, sts_entry->state_flags,
++ sts_entry->iscsiFlags,
++ sts_entry->iscsiResponse));
++ break;
++
++ default:
++ cmd->result = DID_ERROR << 16;
++ break;
++ }
++
++status_entry_exit:
++
++ /* complete the request */
++ srb->cc_stat = sts_entry->completionStatus;
++ qla4xxx_srb_compl(ha, srb);
++}
++
++/**
++ * qla4xxx_process_response_queue - process response queue completions
++ * @ha: Pointer to host adapter structure.
++ *
++ * This routine process response queue completions in interrupt context.
++ * Hardware_lock locked upon entry
++ **/
++static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
++{
++ uint32_t count = 0;
++ struct srb *srb = NULL;
++ struct status_entry *sts_entry;
++
++ /* Process all responses from response queue */
++ while ((ha->response_in =
++ (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=
++ ha->response_out) {
++ sts_entry = (struct status_entry *) ha->response_ptr;
++ count++;
++
++ /* Advance pointers for next entry */
++ if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) {
++ ha->response_out = 0;
++ ha->response_ptr = ha->response_ring;
++ } else {
++ ha->response_out++;
++ ha->response_ptr++;
++ }
++
++ /* process entry */
++ switch (sts_entry->hdr.entryType) {
++ case ET_STATUS:
++ /*
++ * Common status - Single completion posted in single
++ * IOSB.
++ */
++ qla4xxx_status_entry(ha, sts_entry);
++ break;
++
++ case ET_PASSTHRU_STATUS:
++ break;
++
++ case ET_STATUS_CONTINUATION:
++ /* Just throw away the status continuation entries */
++ DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
++ "- ignoring\n", ha->host_no, __func__));
++ break;
++
++ case ET_COMMAND:
++ /* ISP device queue is full. Command not
++ * accepted by ISP. Queue command for
++ * later */
++
++ srb = qla4xxx_del_from_active_array(ha,
++ le32_to_cpu(sts_entry->
++ handle));
++ if (srb == NULL)
++ goto exit_prq_invalid_handle;
++
++ DEBUG2(printk("scsi%ld: %s: FW device queue full, "
++ "srb %p\n", ha->host_no, __func__, srb));
++
++ /* ETRY normally by sending it back with
++ * DID_BUS_BUSY */
++ srb->cmd->result = DID_BUS_BUSY << 16;
++ qla4xxx_srb_compl(ha, srb);
++ break;
++
++ case ET_CONTINUE:
++ /* Just throw away the continuation entries */
++ DEBUG2(printk("scsi%ld: %s: Continuation entry - "
++ "ignoring\n", ha->host_no, __func__));
++ break;
++
++ default:
++ /*
++ * Invalid entry in response queue, reset RISC
++ * firmware.
++ */
++ DEBUG2(printk("scsi%ld: %s: Invalid entry %x in "
++ "response queue \n", ha->host_no,
++ __func__,
++ sts_entry->hdr.entryType));
++ goto exit_prq_error;
++ }
++ }
++
++ /*
++ * Done with responses, update the ISP For QLA4010, this also clears
++ * the interrupt.
++ */
++ writel(ha->response_out, &ha->reg->rsp_q_out);
++ readl(&ha->reg->rsp_q_out);
++
++ return;
++
++exit_prq_invalid_handle:
++ DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n",
++ ha->host_no, __func__, srb, sts_entry->hdr.entryType,
++ sts_entry->completionStatus));
++
++exit_prq_error:
++ writel(ha->response_out, &ha->reg->rsp_q_out);
++ readl(&ha->reg->rsp_q_out);
++
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++}
++
++/**
++ * qla4xxx_isr_decode_mailbox - decodes mailbox status
++ * @ha: Pointer to host adapter structure.
++ * @mailbox_status: Mailbox status.
++ *
++ * This routine decodes the mailbox status during the ISR.
++ * Hardware_lock locked upon entry. runs in interrupt context.
++ **/
++static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
++ uint32_t mbox_status)
++{
++ int i;
++
++ if ((mbox_status == MBOX_STS_BUSY) ||
++ (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
++ (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) {
++ ha->mbox_status[0] = mbox_status;
++
++ if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {
++ /*
++ * Copy all mailbox registers to a temporary
++ * location and set mailbox command done flag
++ */
++ for (i = 1; i < ha->mbox_status_count; i++)
++ ha->mbox_status[i] =
++ readl(&ha->reg->mailbox[i]);
++
++ set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
++ wake_up(&ha->mailbox_wait_queue);
++ }
++ } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
++ /* Immediately process the AENs that don't require much work.
++ * Only queue the database_changed AENs */
++ switch (mbox_status) {
++ case MBOX_ASTS_SYSTEM_ERROR:
++ /* Log Mailbox registers */
++ if (ql4xdontresethba) {
++ DEBUG2(printk("%s:Dont Reset HBA\n",
++ __func__));
++ } else {
++ set_bit(AF_GET_CRASH_RECORD, &ha->flags);
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++ }
++ break;
++
++ case MBOX_ASTS_REQUEST_TRANSFER_ERROR:
++ case MBOX_ASTS_RESPONSE_TRANSFER_ERROR:
++ case MBOX_ASTS_NVRAM_INVALID:
++ case MBOX_ASTS_IP_ADDRESS_CHANGED:
++ case MBOX_ASTS_DHCP_LEASE_EXPIRED:
++ DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "
++ "Reset HA\n", ha->host_no, mbox_status));
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++ break;
++
++ case MBOX_ASTS_LINK_UP:
++ DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n",
++ ha->host_no, mbox_status));
++ set_bit(AF_LINK_UP, &ha->flags);
++ break;
++
++ case MBOX_ASTS_LINK_DOWN:
++ DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n",
++ ha->host_no, mbox_status));
++ clear_bit(AF_LINK_UP, &ha->flags);
++ break;
++
++ case MBOX_ASTS_HEARTBEAT:
++ ha->seconds_since_last_heartbeat = 0;
++ break;
++
++ case MBOX_ASTS_DHCP_LEASE_ACQUIRED:
++ DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE "
++ "ACQUIRED\n", ha->host_no, mbox_status));
++ set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
++ break;
++
++ case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM:
++ case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target
++ * mode
++ * only */
++ case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */
++ case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:
++ case MBOX_ASTS_SUBNET_STATE_CHANGE:
++ /* No action */
++ DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,
++ mbox_status));
++ break;
++
++ case MBOX_ASTS_MAC_ADDRESS_CHANGED:
++ case MBOX_ASTS_DNS:
++ /* No action */
++ DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
++ "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
++ ha->host_no, mbox_status,
++ readl(&ha->reg->mailbox[1]),
++ readl(&ha->reg->mailbox[2])));
++ break;
++
++ case MBOX_ASTS_SELF_TEST_FAILED:
++ case MBOX_ASTS_LOGIN_FAILED:
++ /* No action */
++ DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
++ "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
++ ha->host_no, mbox_status,
++ readl(&ha->reg->mailbox[1]),
++ readl(&ha->reg->mailbox[2]),
++ readl(&ha->reg->mailbox[3])));
++ break;
++
++ case MBOX_ASTS_DATABASE_CHANGED:
++ /* Queue AEN information and process it in the DPC
++ * routine */
++ if (ha->aen_q_count > 0) {
++ /* advance pointer */
++ if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
++ ha->aen_in = 0;
++ else
++ ha->aen_in++;
++
++ /* decrement available counter */
++ ha->aen_q_count--;
++
++ for (i = 1; i < MBOX_AEN_REG_COUNT; i++)
++ ha->aen_q[ha->aen_in].mbox_sts[i] =
++ readl(&ha->reg->mailbox[i]);
++
++ ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status;
++
++ /* print debug message */
++ DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
++ " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
++ ha->host_no, ha->aen_in,
++ mbox_status,
++ ha->aen_q[ha->aen_in].mbox_sts[1],
++ ha->aen_q[ha->aen_in].mbox_sts[2],
++ ha->aen_q[ha->aen_in].mbox_sts[3],
++ ha->aen_q[ha->aen_in]. mbox_sts[4]));
++
++ /* The DPC routine will process the aen */
++ set_bit(DPC_AEN, &ha->dpc_flags);
++ } else {
++ DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
++ "overflowed! AEN LOST!!\n",
++ ha->host_no, __func__,
++ mbox_status));
++
++ DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
++ ha->host_no));
++
++ for (i = 0; i < MAX_AEN_ENTRIES; i++) {
++ DEBUG2(printk("AEN[%d] %04x %04x %04x "
++ "%04x\n", i,
++ ha->aen_q[i].mbox_sts[0],
++ ha->aen_q[i].mbox_sts[1],
++ ha->aen_q[i].mbox_sts[2],
++ ha->aen_q[i].mbox_sts[3]));
++ }
++ }
++ break;
++
++ default:
++ DEBUG2(printk(KERN_WARNING
++ "scsi%ld: AEN %04x UNKNOWN\n",
++ ha->host_no, mbox_status));
++ break;
++ }
++ } else {
++ DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n",
++ ha->host_no, mbox_status));
++
++ ha->mbox_status[0] = mbox_status;
++ }
++}
++
++/**
++ * qla4xxx_interrupt_service_routine - isr
++ * @ha: pointer to host adapter structure.
++ *
++ * This is the main interrupt service routine.
++ * hardware_lock locked upon entry. runs in interrupt context.
++ **/
++void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
++ uint32_t intr_status)
++{
++ /* Process response queue interrupt. */
++ if (intr_status & CSR_SCSI_COMPLETION_INTR)
++ qla4xxx_process_response_queue(ha);
++
++ /* Process mailbox/asynch event interrupt.*/
++ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
++ qla4xxx_isr_decode_mailbox(ha,
++ readl(&ha->reg->mailbox[0]));
++
++ /* Clear Mailbox Interrupt */
++ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
++ &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ }
++}
++
++/**
++ * qla4xxx_intr_handler - hardware interrupt handler.
++ * @irq: Unused
++ * @dev_id: Pointer to host adapter structure
++ **/
++irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
++{
++ struct scsi_qla_host *ha;
++ uint32_t intr_status;
++ unsigned long flags = 0;
++ uint8_t reqs_count = 0;
++
++ ha = (struct scsi_qla_host *) dev_id;
++ if (!ha) {
++ DEBUG2(printk(KERN_INFO
++ "qla4xxx: Interrupt with NULL host ptr\n"));
++ return IRQ_NONE;
++ }
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++
++ /*
++ * Repeatedly service interrupts up to a maximum of
++ * MAX_REQS_SERVICED_PER_INTR
++ */
++ while (1) {
++ /*
++ * Read interrupt status
++ */
++ if (le32_to_cpu(ha->shadow_regs->rsp_q_in) !=
++ ha->response_out)
++ intr_status = CSR_SCSI_COMPLETION_INTR;
++ else
++ intr_status = readl(&ha->reg->ctrl_status);
++
++ if ((intr_status &
++ (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) ==
++ 0) {
++ if (reqs_count == 0)
++ ha->spurious_int_count++;
++ break;
++ }
++
++ if (intr_status & CSR_FATAL_ERROR) {
++ DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, "
++ "Status 0x%04x\n", ha->host_no,
++ readl(isp_port_error_status (ha))));
++
++ /* Issue Soft Reset to clear this error condition.
++ * This will prevent the RISC from repeatedly
++ * interrupting the driver; thus, allowing the DPC to
++ * get scheduled to continue error recovery.
++ * NOTE: Disabling RISC interrupts does not work in
++ * this case, as CSR_FATAL_ERROR overrides
++ * CSR_SCSI_INTR_ENABLE */
++ if ((readl(&ha->reg->ctrl_status) &
++ CSR_SCSI_RESET_INTR) == 0) {
++ writel(set_rmask(CSR_SOFT_RESET),
++ &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ }
++
++ writel(set_rmask(CSR_FATAL_ERROR),
++ &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++
++ __qla4xxx_disable_intrs(ha);
++
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++
++ break;
++ } else if (intr_status & CSR_SCSI_RESET_INTR) {
++ clear_bit(AF_ONLINE, &ha->flags);
++ __qla4xxx_disable_intrs(ha);
++
++ writel(set_rmask(CSR_SCSI_RESET_INTR),
++ &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++
++ set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
++
++ break;
++ } else if (intr_status & INTR_PENDING) {
++ qla4xxx_interrupt_service_routine(ha, intr_status);
++ ha->total_io_count++;
++ if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
++ break;
++
++ intr_status = 0;
++ }
++ }
++
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * qla4xxx_process_aen - processes AENs generated by firmware
++ * @ha: pointer to host adapter structure.
++ * @process_aen: type of AENs to process
++ *
++ * Processes specific types of Asynchronous Events generated by firmware.
++ * The type of AENs to process is specified by process_aen and can be
++ * PROCESS_ALL_AENS 0
++ * FLUSH_DDB_CHANGED_AENS 1
++ * RELOGIN_DDB_CHANGED_AENS 2
++ **/
++void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
++{
++ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
++ struct aen *aen;
++ int i;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ while (ha->aen_out != ha->aen_in) {
++ /* Advance pointers for next entry */
++ if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
++ ha->aen_out = 0;
++ else
++ ha->aen_out++;
++
++ ha->aen_q_count++;
++ aen = &ha->aen_q[ha->aen_out];
++
++ /* copy aen information to local structure */
++ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
++ mbox_sts[i] = aen->mbox_sts[i];
++
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
++ "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
++ mbox_sts[0], mbox_sts[2], mbox_sts[3],
++ mbox_sts[1], mbox_sts[4]));
++
++ switch (mbox_sts[0]) {
++ case MBOX_ASTS_DATABASE_CHANGED:
++ if (process_aen == FLUSH_DDB_CHANGED_AENS) {
++ DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "
++ "[%d] state=%04x FLUSHED!\n",
++ ha->host_no, ha->aen_out,
++ mbox_sts[0], mbox_sts[2],
++ mbox_sts[3]));
++ break;
++ } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) {
++ /* for use during init time, we only want to
++ * relogin non-active ddbs */
++ struct ddb_entry *ddb_entry;
++
++ ddb_entry =
++ /* FIXME: name length? */
++ qla4xxx_lookup_ddb_by_fw_index(ha,
++ mbox_sts[2]);
++ if (!ddb_entry)
++ break;
++
++ ddb_entry->dev_scan_wait_to_complete_relogin =
++ 0;
++ ddb_entry->dev_scan_wait_to_start_relogin =
++ jiffies +
++ ((ddb_entry->default_time2wait +
++ 4) * HZ);
++
++ DEBUG2(printk("scsi%ld: ddb index [%d] initate"
++ " RELOGIN after %d seconds\n",
++ ha->host_no,
++ ddb_entry->fw_ddb_index,
++ ddb_entry->default_time2wait +
++ 4));
++ break;
++ }
++
++ if (mbox_sts[1] == 0) { /* Global DB change. */
++ qla4xxx_reinitialize_ddb_list(ha);
++ } else if (mbox_sts[1] == 1) { /* Specific device. */
++ qla4xxx_process_ddb_changed(ha, mbox_sts[2],
++ mbox_sts[3]);
++ }
++ break;
++ }
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++}
++
+diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
+new file mode 100644
+index 0000000..b721dc5
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_mbx.c
+@@ -0,0 +1,930 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#include "ql4_def.h"
++
++
++/**
++ * qla4xxx_mailbox_command - issues mailbox commands
++ * @ha: Pointer to host adapter structure.
++ * @inCount: number of mailbox registers to load.
++ * @outCount: number of mailbox registers to return.
++ * @mbx_cmd: data pointer for mailbox in registers.
++ * @mbx_sts: data pointer for mailbox out registers.
++ *
++ * This routine sssue mailbox commands and waits for completion.
++ * If outCount is 0, this routine completes successfully WITHOUT waiting
++ * for the mailbox command to complete.
++ **/
++int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
++ uint8_t outCount, uint32_t *mbx_cmd,
++ uint32_t *mbx_sts)
++{
++ int status = QLA_ERROR;
++ uint8_t i;
++ u_long wait_count;
++ uint32_t intr_status;
++ unsigned long flags = 0;
++ DECLARE_WAITQUEUE(wait, current);
++
++ mutex_lock(&ha->mbox_sem);
++
++ /* Mailbox code active */
++ set_bit(AF_MBOX_COMMAND, &ha->flags);
++
++ /* Make sure that pointers are valid */
++ if (!mbx_cmd || !mbx_sts) {
++ DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts "
++ "pointer\n", ha->host_no, __func__));
++ goto mbox_exit;
++ }
++
++ /* To prevent overwriting mailbox registers for a command that has
++ * not yet been serviced, check to see if a previously issued
++ * mailbox command is interrupting.
++ * -----------------------------------------------------------------
++ */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ intr_status = readl(&ha->reg->ctrl_status);
++ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
++ /* Service existing interrupt */
++ qla4xxx_interrupt_service_routine(ha, intr_status);
++ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
++ }
++
++ /* Send the mailbox command to the firmware */
++ ha->mbox_status_count = outCount;
++ for (i = 0; i < outCount; i++)
++ ha->mbox_status[i] = 0;
++
++ /* Load all mailbox registers, except mailbox 0. */
++ for (i = 1; i < inCount; i++)
++ writel(mbx_cmd[i], &ha->reg->mailbox[i]);
++
++ /* Wakeup firmware */
++ writel(mbx_cmd[0], &ha->reg->mailbox[0]);
++ readl(&ha->reg->mailbox[0]);
++ writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ /* Wait for completion */
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ add_wait_queue(&ha->mailbox_wait_queue, &wait);
++
++ /*
++ * If we don't want status, don't wait for the mailbox command to
++ * complete. For example, MBOX_CMD_RESET_FW doesn't return status,
++ * you must poll the inbound Interrupt Mask for completion.
++ */
++ if (outCount == 0) {
++ status = QLA_SUCCESS;
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&ha->mailbox_wait_queue, &wait);
++ goto mbox_exit;
++ }
++ /* Wait for command to complete */
++ wait_count = jiffies + MBOX_TOV * HZ;
++ while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
++ if (time_after_eq(jiffies, wait_count))
++ break;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ intr_status = readl(&ha->reg->ctrl_status);
++ if (intr_status & INTR_PENDING) {
++ /*
++ * Service the interrupt.
++ * The ISR will save the mailbox status registers
++ * to a temporary storage location in the adapter
++ * structure.
++ */
++ ha->mbox_status_count = outCount;
++ qla4xxx_interrupt_service_routine(ha, intr_status);
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ msleep(10);
++ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&ha->mailbox_wait_queue, &wait);
++
++ /* Check for mailbox timeout. */
++ if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
++ DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
++ " Scheduling Adapter Reset\n", ha->host_no,
++ mbx_cmd[0]));
++ ha->mailbox_timeout_count++;
++ mbx_sts[0] = (-1);
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++ goto mbox_exit;
++ }
++
++ /*
++ * Copy the mailbox out registers to the caller's mailbox in/out
++ * structure.
++ */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ for (i = 0; i < outCount; i++)
++ mbx_sts[i] = ha->mbox_status[i];
++
++ /* Set return status and error flags (if applicable). */
++ switch (ha->mbox_status[0]) {
++ case MBOX_STS_COMMAND_COMPLETE:
++ status = QLA_SUCCESS;
++ break;
++
++ case MBOX_STS_INTERMEDIATE_COMPLETION:
++ status = QLA_SUCCESS;
++ break;
++
++ case MBOX_STS_BUSY:
++ DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
++ ha->host_no, __func__, mbx_cmd[0]));
++ ha->mailbox_timeout_count++;
++ break;
++
++ default:
++ DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
++ "sts = %08X ****\n", ha->host_no, __func__,
++ mbx_cmd[0], mbx_sts[0]));
++ break;
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++mbox_exit:
++ clear_bit(AF_MBOX_COMMAND, &ha->flags);
++ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
++ mutex_unlock(&ha->mbox_sem);
++
++ return status;
++}
++
++
++/**
++ * qla4xxx_issue_iocb - issue mailbox iocb command
++ * @ha: adapter state pointer.
++ * @buffer: buffer pointer.
++ * @phys_addr: physical address of buffer.
++ * @size: size of buffer.
++ *
++ * Issues iocbs via mailbox commands.
++ * TARGET_QUEUE_LOCK must be released.
++ * ADAPTER_STATE_LOCK must be released.
++ **/
++int
++qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
++ dma_addr_t phys_addr, size_t size)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++ int status;
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
++ mbox_cmd[1] = 0;
++ mbox_cmd[2] = LSDW(phys_addr);
++ mbox_cmd[3] = MSDW(phys_addr);
++ status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
++ return status;
++}
++
++int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
++ uint16_t fw_ddb_index,
++ uint16_t connection_id,
++ uint16_t option)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
++ mbox_cmd[1] = fw_ddb_index;
++ mbox_cmd[2] = connection_id;
++ mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
++ if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
++ "option %04x failed sts %04X %04X",
++ ha->host_no, __func__,
++ option, mbox_sts[0], mbox_sts[1]));
++ if (mbox_sts[0] == 0x4005)
++ DEBUG2(printk("%s reason %04X\n", __func__,
++ mbox_sts[1]));
++ }
++ return QLA_SUCCESS;
++}
++
++int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
++ uint16_t fw_ddb_index)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
++ mbox_cmd[1] = fw_ddb_index;
++ if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS)
++ return QLA_ERROR;
++
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_initialize_fw_cb - initializes firmware control block.
++ * @ha: Pointer to host adapter structure.
++ **/
++int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
++{
++ struct init_fw_ctrl_blk *init_fw_cb;
++ dma_addr_t init_fw_cb_dma;
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++ int status = QLA_ERROR;
++
++ init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
++ sizeof(struct init_fw_ctrl_blk),
++ &init_fw_cb_dma, GFP_KERNEL);
++ if (init_fw_cb == NULL) {
++ DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
++ ha->host_no, __func__));
++ return 10;
++ }
++ memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
++
++ /* Get Initialize Firmware Control Block. */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
++ mbox_cmd[2] = LSDW(init_fw_cb_dma);
++ mbox_cmd[3] = MSDW(init_fw_cb_dma);
++ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ dma_free_coherent(&ha->pdev->dev,
++ sizeof(struct init_fw_ctrl_blk),
++ init_fw_cb, init_fw_cb_dma);
++ return status;
++ }
++
++ /* Initialize request and response queues. */
++ qla4xxx_init_rings(ha);
++
++ /* Fill in the request and response queue information. */
++ init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out);
++ init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in);
++ init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
++ init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
++ init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma));
++ init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma));
++ init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma));
++ init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma));
++ init_fw_cb->ShadowRegBufAddrLo =
++ cpu_to_le32(LSDW(ha->shadow_regs_dma));
++ init_fw_cb->ShadowRegBufAddrHi =
++ cpu_to_le32(MSDW(ha->shadow_regs_dma));
++
++ /* Set up required options. */
++ init_fw_cb->FwOptions |=
++ __constant_cpu_to_le16(FWOPT_SESSION_MODE |
++ FWOPT_INITIATOR_MODE);
++ init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
++
++ /* Save some info in adapter structure. */
++ ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions);
++ ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions);
++ ha->heartbeat_interval = init_fw_cb->HeartbeatInterval;
++ memcpy(ha->ip_address, init_fw_cb->IPAddr,
++ min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
++ memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
++ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
++ memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
++ min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
++ memcpy(ha->name_string, init_fw_cb->iSCSINameString,
++ min(sizeof(ha->name_string),
++ sizeof(init_fw_cb->iSCSINameString)));
++ memcpy(ha->alias, init_fw_cb->Alias,
++ min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));
++
++ /* Save Command Line Paramater info */
++ ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout);
++ ha->discovery_wait = ql4xdiscoverywait;
++
++ /* Send Initialize Firmware Control Block. */
++ mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
++ mbox_cmd[1] = 0;
++ mbox_cmd[2] = LSDW(init_fw_cb_dma);
++ mbox_cmd[3] = MSDW(init_fw_cb_dma);
++ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) ==
++ QLA_SUCCESS)
++ status = QLA_SUCCESS;
++ else {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE "
++ "failed w/ status %04X\n", ha->host_no, __func__,
++ mbox_sts[0]));
++ }
++ dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
++ init_fw_cb, init_fw_cb_dma);
++
++ return status;
++}
++
++/**
++ * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP
++ * @ha: Pointer to host adapter structure.
++ **/
++int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
++{
++ struct init_fw_ctrl_blk *init_fw_cb;
++ dma_addr_t init_fw_cb_dma;
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
++ sizeof(struct init_fw_ctrl_blk),
++ &init_fw_cb_dma, GFP_KERNEL);
++ if (init_fw_cb == NULL) {
++ printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
++ __func__);
++ return 10;
++ }
++
++ /* Get Initialize Firmware Control Block. */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
++ mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
++ mbox_cmd[2] = LSDW(init_fw_cb_dma);
++ mbox_cmd[3] = MSDW(init_fw_cb_dma);
++
++ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
++ ha->host_no, __func__));
++ dma_free_coherent(&ha->pdev->dev,
++ sizeof(struct init_fw_ctrl_blk),
++ init_fw_cb, init_fw_cb_dma);
++ return QLA_ERROR;
++ }
++
++ /* Save IP Address. */
++ memcpy(ha->ip_address, init_fw_cb->IPAddr,
++ min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
++ memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
++ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
++ memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
++ min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
++
++ dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
++ init_fw_cb, init_fw_cb_dma);
++
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_get_firmware_state - gets firmware state of HBA
++ * @ha: Pointer to host adapter structure.
++ **/
++int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ /* Get firmware version */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
++ if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
++ "status %04X\n", ha->host_no, __func__,
++ mbox_sts[0]));
++ return QLA_ERROR;
++ }
++ ha->firmware_state = mbox_sts[1];
++ ha->board_id = mbox_sts[2];
++ ha->addl_fw_state = mbox_sts[3];
++ DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
++ ha->host_no, __func__, ha->firmware_state);)
++
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_get_firmware_status - retrieves firmware status
++ * @ha: Pointer to host adapter structure.
++ **/
++int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ /* Get firmware version */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
++ if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
++ "status %04X\n", ha->host_no, __func__,
++ mbox_sts[0]));
++ return QLA_ERROR;
++ }
++
++ /* High-water mark of IOCBs */
++ ha->iocb_hiwat = mbox_sts[2];
++ if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
++ ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
++ else
++ dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
++ "firmare IOCBs available (%d).\n",
++ IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
++
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry
++ * @ha: Pointer to host adapter structure.
++ * @fw_ddb_index: Firmware's device database index
++ * @fw_ddb_entry: Pointer to firmware's device database entry structure
++ * @num_valid_ddb_entries: Pointer to number of valid ddb entries
++ * @next_ddb_index: Pointer to next valid device database index
++ * @fw_ddb_device_state: Pointer to device state
++ **/
++int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
++ uint16_t fw_ddb_index,
++ struct dev_db_entry *fw_ddb_entry,
++ dma_addr_t fw_ddb_entry_dma,
++ uint32_t *num_valid_ddb_entries,
++ uint32_t *next_ddb_index,
++ uint32_t *fw_ddb_device_state,
++ uint32_t *conn_err_detail,
++ uint16_t *tcp_source_port_num,
++ uint16_t *connection_id)
++{
++ int status = QLA_ERROR;
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ /* Make sure the device index is valid */
++ if (fw_ddb_index >= MAX_DDB_ENTRIES) {
++ DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
++ ha->host_no, __func__, fw_ddb_index));
++ goto exit_get_fwddb;
++ }
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
++ mbox_cmd[1] = (uint32_t) fw_ddb_index;
++ mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
++ mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
++ if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) ==
++ QLA_ERROR) {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
++ " with status 0x%04X\n", ha->host_no, __func__,
++ mbox_sts[0]));
++ goto exit_get_fwddb;
++ }
++ if (fw_ddb_index != mbox_sts[1]) {
++ DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
++ ha->host_no, __func__, fw_ddb_index,
++ mbox_sts[1]));
++ goto exit_get_fwddb;
++ }
++ if (fw_ddb_entry) {
++ dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
++ "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
++ fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
++ mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0],
++ fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2],
++ fw_ddb_entry->ipAddr[3],
++ le16_to_cpu(fw_ddb_entry->portNumber),
++ fw_ddb_entry->iscsiName);
++ }
++ if (num_valid_ddb_entries)
++ *num_valid_ddb_entries = mbox_sts[2];
++ if (next_ddb_index)
++ *next_ddb_index = mbox_sts[3];
++ if (fw_ddb_device_state)
++ *fw_ddb_device_state = mbox_sts[4];
++
++ /*
++ * RA: This mailbox has been changed to pass connection error and
++ * details. Its true for ISP4010 as per Version E - Not sure when it
++ * was changed. Get the time2wait from the fw_dd_entry field :
++ * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY
++ * struct.
++ */
++ if (conn_err_detail)
++ *conn_err_detail = mbox_sts[5];
++ if (tcp_source_port_num)
++ *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16;
++ if (connection_id)
++ *connection_id = (uint16_t) mbox_sts[6] & 0x00FF;
++ status = QLA_SUCCESS;
++
++exit_get_fwddb:
++ return status;
++}
++
++/**
++ * qla4xxx_set_fwddb_entry - sets a ddb entry.
++ * @ha: Pointer to host adapter structure.
++ * @fw_ddb_index: Firmware's device database index
++ * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL.
++ *
++ * This routine initializes or updates the adapter's device database
++ * entry for the specified device. It also triggers a login for the
++ * specified device. Therefore, it may also be used as a secondary
++ * login routine when a NULL pointer is specified for the fw_ddb_entry.
++ **/
++int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
++ dma_addr_t fw_ddb_entry_dma)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ /* Do not wait for completion. The firmware will send us an
++ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
++ */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++ mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY;
++ mbox_cmd[1] = (uint32_t) fw_ddb_index;
++ mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
++ mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
++ return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
++}
++
++int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
++ uint16_t fw_ddb_index)
++{
++ int status = QLA_ERROR;
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ /* Do not wait for completion. The firmware will send us an
++ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
++ */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
++ mbox_cmd[1] = (uint32_t) fw_ddb_index;
++ mbox_cmd[2] = 0;
++ mbox_cmd[3] = 0;
++ mbox_cmd[4] = 0;
++ status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]);
++ DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
++ __func__, fw_ddb_index, status, mbox_sts[0],
++ mbox_sts[1]);)
++
++ return status;
++}
++
++/**
++ * qla4xxx_get_crash_record - retrieves crash record.
++ * @ha: Pointer to host adapter structure.
++ *
++ * This routine retrieves a crash record from the QLA4010 after an 8002h aen.
++ **/
++void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++ struct crash_record *crash_record = NULL;
++ dma_addr_t crash_record_dma = 0;
++ uint32_t crash_record_size = 0;
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_cmd));
++
++ /* Get size of crash record. */
++ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
++ if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
++ ha->host_no, __func__));
++ goto exit_get_crash_record;
++ }
++ crash_record_size = mbox_sts[4];
++ if (crash_record_size == 0) {
++ DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n",
++ ha->host_no, __func__));
++ goto exit_get_crash_record;
++ }
++
++ /* Alloc Memory for Crash Record. */
++ crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size,
++ &crash_record_dma, GFP_KERNEL);
++ if (crash_record == NULL)
++ goto exit_get_crash_record;
++
++ /* Get Crash Record. */
++ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
++ mbox_cmd[2] = LSDW(crash_record_dma);
++ mbox_cmd[3] = MSDW(crash_record_dma);
++ mbox_cmd[4] = crash_record_size;
++ if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS)
++ goto exit_get_crash_record;
++
++ /* Dump Crash Record. */
++
++exit_get_crash_record:
++ if (crash_record)
++ dma_free_coherent(&ha->pdev->dev, crash_record_size,
++ crash_record, crash_record_dma);
++}
++
++/**
++ * qla4xxx_get_conn_event_log - retrieves connection event log
++ * @ha: Pointer to host adapter structure.
++ **/
++void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++ struct conn_event_log_entry *event_log = NULL;
++ dma_addr_t event_log_dma = 0;
++ uint32_t event_log_size = 0;
++ uint32_t num_valid_entries;
++ uint32_t oldest_entry = 0;
++ uint32_t max_event_log_entries;
++ uint8_t i;
++
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_cmd));
++
++ /* Get size of crash record. */
++ mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
++ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS)
++ goto exit_get_event_log;
++
++ event_log_size = mbox_sts[4];
++ if (event_log_size == 0)
++ goto exit_get_event_log;
++
++ /* Alloc Memory for Crash Record. */
++ event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size,
++ &event_log_dma, GFP_KERNEL);
++ if (event_log == NULL)
++ goto exit_get_event_log;
++
++ /* Get Crash Record. */
++ mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
++ mbox_cmd[2] = LSDW(event_log_dma);
++ mbox_cmd[3] = MSDW(event_log_dma);
++ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
++ "log!\n", ha->host_no, __func__));
++ goto exit_get_event_log;
++ }
++
++ /* Dump Event Log. */
++ num_valid_entries = mbox_sts[1];
++
++ max_event_log_entries = event_log_size /
++ sizeof(struct conn_event_log_entry);
++
++ if (num_valid_entries > max_event_log_entries)
++ oldest_entry = num_valid_entries % max_event_log_entries;
++
++ DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n",
++ ha->host_no, num_valid_entries));
++
++ if (ql4xextended_error_logging == 3) {
++ if (oldest_entry == 0) {
++ /* Circular Buffer has not wrapped around */
++ for (i=0; i < num_valid_entries; i++) {
++ qla4xxx_dump_buffer((uint8_t *)event_log+
++ (i*sizeof(*event_log)),
++ sizeof(*event_log));
++ }
++ }
++ else {
++ /* Circular Buffer has wrapped around -
++ * display accordingly*/
++ for (i=oldest_entry; i < max_event_log_entries; i++) {
++ qla4xxx_dump_buffer((uint8_t *)event_log+
++ (i*sizeof(*event_log)),
++ sizeof(*event_log));
++ }
++ for (i=0; i < oldest_entry; i++) {
++ qla4xxx_dump_buffer((uint8_t *)event_log+
++ (i*sizeof(*event_log)),
++ sizeof(*event_log));
++ }
++ }
++ }
++
++exit_get_event_log:
++ if (event_log)
++ dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
++ event_log_dma);
++}
++
++/**
++ * qla4xxx_reset_lun - issues LUN Reset
++ * @ha: Pointer to host adapter structure.
++ * @db_entry: Pointer to device database entry
++ * @un_entry: Pointer to lun entry structure
++ *
++ * This routine performs a LUN RESET on the specified target/lun.
++ * The caller must ensure that the ddb_entry and lun_entry pointers
++ * are valid before calling this routine.
++ **/
++int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
++ int lun)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++ int status = QLA_SUCCESS;
++
++ DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
++ ddb_entry->os_target_id, lun));
++
++ /*
++ * Send lun reset command to ISP, so that the ISP will return all
++ * outstanding requests with RESET status
++ */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_LUN_RESET;
++ mbox_cmd[1] = ddb_entry->fw_ddb_index;
++ mbox_cmd[2] = lun << 8;
++ mbox_cmd[5] = 0x01; /* Immediate Command Enable */
++ qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]);
++ if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
++ mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
++ status = QLA_ERROR;
++
++ return status;
++}
++
++
++int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
++ uint32_t offset, uint32_t len)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_READ_FLASH;
++ mbox_cmd[1] = LSDW(dma_addr);
++ mbox_cmd[2] = MSDW(dma_addr);
++ mbox_cmd[3] = offset;
++ mbox_cmd[4] = len;
++ if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
++ "status %04X %04X, offset %08x, len %08x\n", ha->host_no,
++ __func__, mbox_sts[0], mbox_sts[1], offset, len));
++ return QLA_ERROR;
++ }
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_get_fw_version - gets firmware version
++ * @ha: Pointer to host adapter structure.
++ *
++ * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may
++ * hold an address for data. Make sure that we write 0 to those mailboxes,
++ * if unused.
++ **/
++int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ /* Get firmware version. */
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++ mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
++ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
++ "status %04X\n", ha->host_no, __func__, mbox_sts[0]));
++ return QLA_ERROR;
++ }
++
++ /* Save firmware version information. */
++ ha->firmware_version[0] = mbox_sts[1];
++ ha->firmware_version[1] = mbox_sts[2];
++ ha->patch_number = mbox_sts[3];
++ ha->build_number = mbox_sts[4];
++
++ return QLA_SUCCESS;
++}
++
++int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++ mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS;
++ mbox_cmd[2] = LSDW(dma_addr);
++ mbox_cmd[3] = MSDW(dma_addr);
++
++ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
++ ha->host_no, __func__, mbox_sts[0]));
++ return QLA_ERROR;
++ }
++ return QLA_SUCCESS;
++}
++
++int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
++{
++ uint32_t mbox_cmd[MBOX_REG_COUNT];
++ uint32_t mbox_sts[MBOX_REG_COUNT];
++
++ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++ memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++ mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
++ mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES;
++
++ if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) !=
++ QLA_SUCCESS) {
++ if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) {
++ *ddb_index = mbox_sts[2];
++ } else {
++ DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
++ ha->host_no, __func__, mbox_sts[0]));
++ return QLA_ERROR;
++ }
++ } else {
++ *ddb_index = MAX_PRST_DEV_DB_ENTRIES;
++ }
++
++ return QLA_SUCCESS;
++}
++
++
++int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
++{
++ struct dev_db_entry *fw_ddb_entry;
++ dma_addr_t fw_ddb_entry_dma;
++ uint32_t ddb_index;
++ int ret_val = QLA_SUCCESS;
++
++
++ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
++ sizeof(*fw_ddb_entry),
++ &fw_ddb_entry_dma, GFP_KERNEL);
++ if (!fw_ddb_entry) {
++ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
++ ha->host_no, __func__));
++ ret_val = QLA_ERROR;
++ goto qla4xxx_send_tgts_exit;
++ }
++
++ ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma);
++ if (ret_val != QLA_SUCCESS)
++ goto qla4xxx_send_tgts_exit;
++
++ ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index);
++ if (ret_val != QLA_SUCCESS)
++ goto qla4xxx_send_tgts_exit;
++
++ memset((void *)fw_ddb_entry->iSCSIAlias, 0,
++ sizeof(fw_ddb_entry->iSCSIAlias));
++
++ memset((void *)fw_ddb_entry->iscsiName, 0,
++ sizeof(fw_ddb_entry->iscsiName));
++
++ memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr));
++ memset((void *)fw_ddb_entry->targetAddr, 0,
++ sizeof(fw_ddb_entry->targetAddr));
++
++ fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
++ fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port));
++
++ fw_ddb_entry->ipAddr[0] = *ip;
++ fw_ddb_entry->ipAddr[1] = *(ip + 1);
++ fw_ddb_entry->ipAddr[2] = *(ip + 2);
++ fw_ddb_entry->ipAddr[3] = *(ip + 3);
++
++ ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
++
++qla4xxx_send_tgts_exit:
++ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
++ fw_ddb_entry, fw_ddb_entry_dma);
++ return ret_val;
++}
++
+diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
+new file mode 100644
+index 0000000..e3957ca
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_nvram.c
+@@ -0,0 +1,224 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#include "ql4_def.h"
++
++static inline int eeprom_size(struct scsi_qla_host *ha)
++{
++ return is_qla4022(ha) ? FM93C86A_SIZE_16 : FM93C66A_SIZE_16;
++}
++
++static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha)
++{
++ return is_qla4022(ha) ? FM93C86A_NO_ADDR_BITS_16 :
++ FM93C56A_NO_ADDR_BITS_16;
++}
++
++static inline int eeprom_no_data_bits(struct scsi_qla_host *ha)
++{
++ return FM93C56A_DATA_BITS_16;
++}
++
++static int fm93c56a_select(struct scsi_qla_host * ha)
++{
++ DEBUG5(printk(KERN_ERR "fm93c56a_select:\n"));
++
++ ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000;
++ writel(ha->eeprom_cmd_data, isp_nvram(ha));
++ readl(isp_nvram(ha));
++ return 1;
++}
++
++static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
++{
++ int i;
++ int mask;
++ int dataBit;
++ int previousBit;
++
++ /* Clock in a zero, then do the start bit. */
++ writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, isp_nvram(ha));
++ writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
++ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
++ writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
++ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
++ readl(isp_nvram(ha));
++ mask = 1 << (FM93C56A_CMD_BITS - 1);
++
++ /* Force the previous data bit to be different. */
++ previousBit = 0xffff;
++ for (i = 0; i < FM93C56A_CMD_BITS; i++) {
++ dataBit =
++ (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
++ if (previousBit != dataBit) {
++
++ /*
++ * If the bit changed, then change the DO state to
++ * match.
++ */
++ writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
++ previousBit = dataBit;
++ }
++ writel(ha->eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
++ writel(ha->eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
++ readl(isp_nvram(ha));
++ cmd = cmd << 1;
++ }
++ mask = 1 << (eeprom_no_addr_bits(ha) - 1);
++
++ /* Force the previous data bit to be different. */
++ previousBit = 0xffff;
++ for (i = 0; i < eeprom_no_addr_bits(ha); i++) {
++ dataBit = addr & mask ? AUBURN_EEPROM_DO_1 :
++ AUBURN_EEPROM_DO_0;
++ if (previousBit != dataBit) {
++ /*
++ * If the bit changed, then change the DO state to
++ * match.
++ */
++ writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
++ previousBit = dataBit;
++ }
++ writel(ha->eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
++ writel(ha->eeprom_cmd_data | dataBit |
++ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
++ readl(isp_nvram(ha));
++ addr = addr << 1;
++ }
++ return 1;
++}
++
++static int fm93c56a_deselect(struct scsi_qla_host * ha)
++{
++ ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000;
++ writel(ha->eeprom_cmd_data, isp_nvram(ha));
++ readl(isp_nvram(ha));
++ return 1;
++}
++
++static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value)
++{
++ int i;
++ int data = 0;
++ int dataBit;
++
++ /* Read the data bits
++ * The first bit is a dummy. Clock right over it. */
++ for (i = 0; i < eeprom_no_data_bits(ha); i++) {
++ writel(ha->eeprom_cmd_data |
++ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
++ writel(ha->eeprom_cmd_data |
++ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
++ dataBit =
++ (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0;
++ data = (data << 1) | dataBit;
++ }
++
++ *value = data;
++ return 1;
++}
++
++static int eeprom_readword(int eepromAddr, u16 * value,
++ struct scsi_qla_host * ha)
++{
++ fm93c56a_select(ha);
++ fm93c56a_cmd(ha, FM93C56A_READ, eepromAddr);
++ fm93c56a_datain(ha, value);
++ fm93c56a_deselect(ha);
++ return 1;
++}
++
++/* Hardware_lock must be set before calling */
++u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
++{
++ u16 val;
++
++ /* NOTE: NVRAM uses half-word addresses */
++ eeprom_readword(offset, &val, ha);
++ return val;
++}
++
++int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha)
++{
++ int status = QLA_ERROR;
++ uint16_t checksum = 0;
++ uint32_t index;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ for (index = 0; index < eeprom_size(ha); index++)
++ checksum += rd_nvram_word(ha, index);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if (checksum == 0)
++ status = QLA_SUCCESS;
++
++ return status;
++}
++
++/*************************************************************************
++ *
++ * Hardware Semaphore routines
++ *
++ *************************************************************************/
++int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
++{
++ uint32_t value;
++ unsigned long flags;
++ unsigned int seconds = 30;
++
++ DEBUG2(printk("scsi%ld : Trying to get SEM lock - mask= 0x%x, code = "
++ "0x%x\n", ha->host_no, sem_mask, sem_bits));
++ do {
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel((sem_mask | sem_bits), isp_semaphore(ha));
++ value = readw(isp_semaphore(ha));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ if ((value & (sem_mask >> 16)) == sem_bits) {
++ DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, "
++ "code = 0x%x\n", ha->host_no,
++ sem_mask, sem_bits));
++ return QLA_SUCCESS;
++ }
++ ssleep(1);
++ } while (--seconds);
++ return QLA_ERROR;
++}
++
++void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel(sem_mask, isp_semaphore(ha));
++ readl(isp_semaphore(ha));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ DEBUG2(printk("scsi%ld : UNLOCK SEM - mask= 0x%x\n", ha->host_no,
++ sem_mask));
++}
++
++int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
++{
++ uint32_t value;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel((sem_mask | sem_bits), isp_semaphore(ha));
++ value = readw(isp_semaphore(ha));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ if ((value & (sem_mask >> 16)) == sem_bits) {
++ DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, code = "
++ "0x%x, sema code=0x%x\n", ha->host_no,
++ sem_mask, sem_bits, value));
++ return 1;
++ }
++ return 0;
++}
+diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
+new file mode 100644
+index 0000000..08e2aed
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_nvram.h
+@@ -0,0 +1,256 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#ifndef _QL4XNVRM_H_
++#define _QL4XNVRM_H_
++
++/*
++ * AM29LV Flash definitions
++ */
++#define FM93C56A_SIZE_8 0x100
++#define FM93C56A_SIZE_16 0x80
++#define FM93C66A_SIZE_8 0x200
++#define FM93C66A_SIZE_16 0x100/* 4010 */
++#define FM93C86A_SIZE_16 0x400/* 4022 */
++
++#define FM93C56A_START 0x1
++
++// Commands
++#define FM93C56A_READ 0x2
++#define FM93C56A_WEN 0x0
++#define FM93C56A_WRITE 0x1
++#define FM93C56A_WRITE_ALL 0x0
++#define FM93C56A_WDS 0x0
++#define FM93C56A_ERASE 0x3
++#define FM93C56A_ERASE_ALL 0x0
++
++/* Command Extentions */
++#define FM93C56A_WEN_EXT 0x3
++#define FM93C56A_WRITE_ALL_EXT 0x1
++#define FM93C56A_WDS_EXT 0x0
++#define FM93C56A_ERASE_ALL_EXT 0x2
++
++/* Address Bits */
++#define FM93C56A_NO_ADDR_BITS_16 8 /* 4010 */
++#define FM93C56A_NO_ADDR_BITS_8 9 /* 4010 */
++#define FM93C86A_NO_ADDR_BITS_16 10 /* 4022 */
++
++/* Data Bits */
++#define FM93C56A_DATA_BITS_16 16
++#define FM93C56A_DATA_BITS_8 8
++
++/* Special Bits */
++#define FM93C56A_READ_DUMMY_BITS 1
++#define FM93C56A_READY 0
++#define FM93C56A_BUSY 1
++#define FM93C56A_CMD_BITS 2
++
++/* Auburn Bits */
++#define AUBURN_EEPROM_DI 0x8
++#define AUBURN_EEPROM_DI_0 0x0
++#define AUBURN_EEPROM_DI_1 0x8
++#define AUBURN_EEPROM_DO 0x4
++#define AUBURN_EEPROM_DO_0 0x0
++#define AUBURN_EEPROM_DO_1 0x4
++#define AUBURN_EEPROM_CS 0x2
++#define AUBURN_EEPROM_CS_0 0x0
++#define AUBURN_EEPROM_CS_1 0x2
++#define AUBURN_EEPROM_CLK_RISE 0x1
++#define AUBURN_EEPROM_CLK_FALL 0x0
++
++/* */
++/* EEPROM format */
++/* */
++struct bios_params {
++ uint16_t SpinUpDelay:1;
++ uint16_t BIOSDisable:1;
++ uint16_t MMAPEnable:1;
++ uint16_t BootEnable:1;
++ uint16_t Reserved0:12;
++ uint8_t bootID0:7;
++ uint8_t bootID0Valid:1;
++ uint8_t bootLUN0[8];
++ uint8_t bootID1:7;
++ uint8_t bootID1Valid:1;
++ uint8_t bootLUN1[8];
++ uint16_t MaxLunsPerTarget;
++ uint8_t Reserved1[10];
++};
++
++struct eeprom_port_cfg {
++
++ /* MTU MAC 0 */
++ u16 etherMtu_mac;
++
++ /* Flow Control MAC 0 */
++ u16 pauseThreshold_mac;
++ u16 resumeThreshold_mac;
++ u16 reserved[13];
++};
++
++struct eeprom_function_cfg {
++ u8 reserved[30];
++
++ /* MAC ADDR */
++ u8 macAddress[6];
++ u8 macAddressSecondary[6];
++ u16 subsysVendorId;
++ u16 subsysDeviceId;
++};
++
++struct eeprom_data {
++ union {
++ struct { /* isp4010 */
++ u8 asic_id[4]; /* x00 */
++ u8 version; /* x04 */
++ u8 reserved; /* x05 */
++ u16 board_id; /* x06 */
++#define EEPROM_BOARDID_ELDORADO 1
++#define EEPROM_BOARDID_PLACER 2
++
++#define EEPROM_SERIAL_NUM_SIZE 16
++ u8 serial_number[EEPROM_SERIAL_NUM_SIZE]; /* x08 */
++
++ /* ExtHwConfig: */
++ /* Offset = 24bytes
++ *
++ * | SSRAM Size| |ST|PD|SDRAM SZ| W| B| SP | |
++ * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
++ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
++ */
++ u16 ext_hw_conf; /* x18 */
++ u8 mac0[6]; /* x1A */
++ u8 mac1[6]; /* x20 */
++ u8 mac2[6]; /* x26 */
++ u8 mac3[6]; /* x2C */
++ u16 etherMtu; /* x32 */
++ u16 macConfig; /* x34 */
++#define MAC_CONFIG_ENABLE_ANEG 0x0001
++#define MAC_CONFIG_ENABLE_PAUSE 0x0002
++ u16 phyConfig; /* x36 */
++#define PHY_CONFIG_PHY_ADDR_MASK 0x1f
++#define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20
++ u16 topcat; /* x38 */
++#define TOPCAT_PRESENT 0x0100
++#define TOPCAT_MASK 0xFF00
++
++#define EEPROM_UNUSED_1_SIZE 2
++ u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */
++ u16 bufletSize; /* x3C */
++ u16 bufletCount; /* x3E */
++ u16 bufletPauseThreshold; /* x40 */
++ u16 tcpWindowThreshold50; /* x42 */
++ u16 tcpWindowThreshold25; /* x44 */
++ u16 tcpWindowThreshold0; /* x46 */
++ u16 ipHashTableBaseHi; /* x48 */
++ u16 ipHashTableBaseLo; /* x4A */
++ u16 ipHashTableSize; /* x4C */
++ u16 tcpHashTableBaseHi; /* x4E */
++ u16 tcpHashTableBaseLo; /* x50 */
++ u16 tcpHashTableSize; /* x52 */
++ u16 ncbTableBaseHi; /* x54 */
++ u16 ncbTableBaseLo; /* x56 */
++ u16 ncbTableSize; /* x58 */
++ u16 drbTableBaseHi; /* x5A */
++ u16 drbTableBaseLo; /* x5C */
++ u16 drbTableSize; /* x5E */
++
++#define EEPROM_UNUSED_2_SIZE 4
++ u8 unused_2[EEPROM_UNUSED_2_SIZE]; /* x60 */
++ u16 ipReassemblyTimeout; /* x64 */
++ u16 tcpMaxWindowSizeHi; /* x66 */
++ u16 tcpMaxWindowSizeLo; /* x68 */
++ u32 net_ip_addr0; /* x6A Added for TOE
++ * functionality. */
++ u32 net_ip_addr1; /* x6E */
++ u32 scsi_ip_addr0; /* x72 */
++ u32 scsi_ip_addr1; /* x76 */
++#define EEPROM_UNUSED_3_SIZE 128 /* changed from 144 to account
++ * for ip addresses */
++ u8 unused_3[EEPROM_UNUSED_3_SIZE]; /* x7A */
++ u16 subsysVendorId_f0; /* xFA */
++ u16 subsysDeviceId_f0; /* xFC */
++
++ /* Address = 0x7F */
++#define FM93C56A_SIGNATURE 0x9356
++#define FM93C66A_SIGNATURE 0x9366
++ u16 signature; /* xFE */
++
++#define EEPROM_UNUSED_4_SIZE 250
++ u8 unused_4[EEPROM_UNUSED_4_SIZE]; /* x100 */
++ u16 subsysVendorId_f1; /* x1FA */
++ u16 subsysDeviceId_f1; /* x1FC */
++ u16 checksum; /* x1FE */
++ } __attribute__ ((packed)) isp4010;
++ struct { /* isp4022 */
++ u8 asicId[4]; /* x00 */
++ u8 version; /* x04 */
++ u8 reserved_5; /* x05 */
++ u16 boardId; /* x06 */
++ u8 boardIdStr[16]; /* x08 */
++ u8 serialNumber[16]; /* x18 */
++
++ /* External Hardware Configuration */
++ u16 ext_hw_conf; /* x28 */
++
++ /* MAC 0 CONFIGURATION */
++ struct eeprom_port_cfg macCfg_port0; /* x2A */
++
++ /* MAC 1 CONFIGURATION */
++ struct eeprom_port_cfg macCfg_port1; /* x4A */
++
++ /* DDR SDRAM Configuration */
++ u16 bufletSize; /* x6A */
++ u16 bufletCount; /* x6C */
++ u16 tcpWindowThreshold50; /* x6E */
++ u16 tcpWindowThreshold25; /* x70 */
++ u16 tcpWindowThreshold0; /* x72 */
++ u16 ipHashTableBaseHi; /* x74 */
++ u16 ipHashTableBaseLo; /* x76 */
++ u16 ipHashTableSize; /* x78 */
++ u16 tcpHashTableBaseHi; /* x7A */
++ u16 tcpHashTableBaseLo; /* x7C */
++ u16 tcpHashTableSize; /* x7E */
++ u16 ncbTableBaseHi; /* x80 */
++ u16 ncbTableBaseLo; /* x82 */
++ u16 ncbTableSize; /* x84 */
++ u16 drbTableBaseHi; /* x86 */
++ u16 drbTableBaseLo; /* x88 */
++ u16 drbTableSize; /* x8A */
++ u16 reserved_142[4]; /* x8C */
++
++ /* TCP/IP Parameters */
++ u16 ipReassemblyTimeout; /* x94 */
++ u16 tcpMaxWindowSize; /* x96 */
++ u16 ipSecurity; /* x98 */
++ u8 reserved_156[294]; /* x9A */
++ u16 qDebug[8]; /* QLOGIC USE ONLY x1C0 */
++ struct eeprom_function_cfg funcCfg_fn0; /* x1D0 */
++ u16 reserved_510; /* x1FE */
++
++ /* Address = 512 */
++ u8 oemSpace[432]; /* x200 */
++ struct bios_params sBIOSParams_fn1; /* x3B0 */
++ struct eeprom_function_cfg funcCfg_fn1; /* x3D0 */
++ u16 reserved_1022; /* x3FE */
++
++ /* Address = 1024 */
++ u8 reserved_1024[464]; /* x400 */
++ struct eeprom_function_cfg funcCfg_fn2; /* x5D0 */
++ u16 reserved_1534; /* x5FE */
++
++ /* Address = 1536 */
++ u8 reserved_1536[432]; /* x600 */
++ struct bios_params sBIOSParams_fn3; /* x7B0 */
++ struct eeprom_function_cfg funcCfg_fn3; /* x7D0 */
++ u16 checksum; /* x7FE */
++ } __attribute__ ((packed)) isp4022;
++ };
++};
++
++
++#endif /* _QL4XNVRM_H_ */
+diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
+new file mode 100644
+index 0000000..5b8db61
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_os.c
+@@ -0,0 +1,1755 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++#include <linux/moduleparam.h>
++
++#include <scsi/scsi_tcq.h>
++#include <scsi/scsicam.h>
++
++#include "ql4_def.h"
++
++/*
++ * Driver version
++ */
++char qla4xxx_version_str[40];
++
++/*
++ * SRB allocation cache
++ */
++static kmem_cache_t *srb_cachep;
++
++/*
++ * Module parameter information and variables
++ */
++int ql4xdiscoverywait = 60;
++module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR);
++MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time");
++int ql4xdontresethba = 0;
++module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR);
++MODULE_PARM_DESC(ql4xdontresethba,
++ "Dont reset the HBA when the driver gets 0x8002 AEN "
++ " default it will reset hba :0"
++ " set to 1 to avoid resetting HBA");
++
++int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */
++module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR);
++MODULE_PARM_DESC(ql4xextended_error_logging,
++ "Option to enable extended error logging, "
++ "Default is 0 - no logging, 1 - debug logging");
++
++/*
++ * SCSI host template entry points
++ */
++
++void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
++
++/*
++ * iSCSI template entry points
++ */
++static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
++ uint32_t enable, struct sockaddr *dst_addr);
++static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
++ enum iscsi_param param, char *buf);
++static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
++ enum iscsi_param param, char *buf);
++static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag);
++static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
++static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
++
++/*
++ * SCSI host template entry points
++ */
++static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
++ void (*done) (struct scsi_cmnd *));
++static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
++static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
++static int qla4xxx_slave_alloc(struct scsi_device *device);
++static int qla4xxx_slave_configure(struct scsi_device *device);
++static void qla4xxx_slave_destroy(struct scsi_device *sdev);
++
++static struct scsi_host_template qla4xxx_driver_template = {
++ .module = THIS_MODULE,
++ .name = DRIVER_NAME,
++ .proc_name = DRIVER_NAME,
++ .queuecommand = qla4xxx_queuecommand,
++
++ .eh_device_reset_handler = qla4xxx_eh_device_reset,
++ .eh_host_reset_handler = qla4xxx_eh_host_reset,
++
++ .slave_configure = qla4xxx_slave_configure,
++ .slave_alloc = qla4xxx_slave_alloc,
++ .slave_destroy = qla4xxx_slave_destroy,
++
++ .this_id = -1,
++ .cmd_per_lun = 3,
++ .use_clustering = ENABLE_CLUSTERING,
++ .sg_tablesize = SG_ALL,
++
++ .max_sectors = 0xFFFF,
++};
++
++static struct iscsi_transport qla4xxx_iscsi_transport = {
++ .owner = THIS_MODULE,
++ .name = DRIVER_NAME,
++ .param_mask = ISCSI_CONN_PORT |
++ ISCSI_CONN_ADDRESS |
++ ISCSI_TARGET_NAME |
++ ISCSI_TPGT,
++ .sessiondata_size = sizeof(struct ddb_entry),
++ .host_template = &qla4xxx_driver_template,
++
++ .tgt_dscvr = qla4xxx_tgt_dscvr,
++ .get_conn_param = qla4xxx_conn_get_param,
++ .get_session_param = qla4xxx_sess_get_param,
++ .start_conn = qla4xxx_conn_start,
++ .stop_conn = qla4xxx_conn_stop,
++ .session_recovery_timedout = qla4xxx_recovery_timedout,
++};
++
++static struct scsi_transport_template *qla4xxx_scsi_transport;
++
++static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
++{
++ struct ddb_entry *ddb_entry = session->dd_data;
++ struct scsi_qla_host *ha = ddb_entry->ha;
++
++ DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) "
++ "secs exhausted, marking device DEAD.\n", ha->host_no,
++ __func__, ddb_entry->fw_ddb_index,
++ ha->port_down_retry_count));
++
++ atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
++
++ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = "
++ "0x%lx\n", ha->host_no, __func__, ha->dpc_flags));
++ queue_work(ha->dpc_thread, &ha->dpc_work);
++}
++
++static int qla4xxx_conn_start(struct iscsi_cls_conn *conn)
++{
++ struct iscsi_cls_session *session;
++ struct ddb_entry *ddb_entry;
++
++ session = iscsi_dev_to_session(conn->dev.parent);
++ ddb_entry = session->dd_data;
++
++ DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n",
++ ddb_entry->ha->host_no, __func__,
++ ddb_entry->fw_ddb_index));
++ iscsi_unblock_session(session);
++ return 0;
++}
++
++static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
++{
++ struct iscsi_cls_session *session;
++ struct ddb_entry *ddb_entry;
++
++ session = iscsi_dev_to_session(conn->dev.parent);
++ ddb_entry = session->dd_data;
++
++ DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n",
++ ddb_entry->ha->host_no, __func__,
++ ddb_entry->fw_ddb_index));
++ if (flag == STOP_CONN_RECOVER)
++ iscsi_block_session(session);
++ else
++ printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
++}
++
++static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
++ enum iscsi_param param, char *buf)
++{
++ struct ddb_entry *ddb_entry = sess->dd_data;
++ int len;
++
++ switch (param) {
++ case ISCSI_PARAM_TARGET_NAME:
++ len = snprintf(buf, PAGE_SIZE - 1, "%s\n",
++ ddb_entry->iscsi_name);
++ break;
++ case ISCSI_PARAM_TPGT:
++ len = sprintf(buf, "%u\n", ddb_entry->tpgt);
++ break;
++ default:
++ return -ENOSYS;
++ }
++
++ return len;
++}
++
++static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
++ enum iscsi_param param, char *buf)
++{
++ struct iscsi_cls_session *session;
++ struct ddb_entry *ddb_entry;
++ int len;
++
++ session = iscsi_dev_to_session(conn->dev.parent);
++ ddb_entry = session->dd_data;
++
++ switch (param) {
++ case ISCSI_PARAM_CONN_PORT:
++ len = sprintf(buf, "%hu\n", ddb_entry->port);
++ break;
++ case ISCSI_PARAM_CONN_ADDRESS:
++ /* TODO: what are the ipv6 bits */
++ len = sprintf(buf, "%u.%u.%u.%u\n",
++ NIPQUAD(ddb_entry->ip_addr));
++ break;
++ default:
++ return -ENOSYS;
++ }
++
++ return len;
++}
++
++static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
++ uint32_t enable, struct sockaddr *dst_addr)
++{
++ struct scsi_qla_host *ha;
++ struct Scsi_Host *shost;
++ struct sockaddr_in *addr;
++ struct sockaddr_in6 *addr6;
++ int ret = 0;
++
++ shost = scsi_host_lookup(host_no);
++ if (IS_ERR(shost)) {
++ printk(KERN_ERR "Could not find host no %u\n", host_no);
++ return -ENODEV;
++ }
++
++ ha = (struct scsi_qla_host *) shost->hostdata;
++
++ switch (type) {
++ case ISCSI_TGT_DSCVR_SEND_TARGETS:
++ if (dst_addr->sa_family == AF_INET) {
++ addr = (struct sockaddr_in *)dst_addr;
++ if (qla4xxx_send_tgts(ha, (char *)&addr->sin_addr,
++ addr->sin_port) != QLA_SUCCESS)
++ ret = -EIO;
++ } else if (dst_addr->sa_family == AF_INET6) {
++ /*
++ * TODO: fix qla4xxx_send_tgts
++ */
++ addr6 = (struct sockaddr_in6 *)dst_addr;
++ if (qla4xxx_send_tgts(ha, (char *)&addr6->sin6_addr,
++ addr6->sin6_port) != QLA_SUCCESS)
++ ret = -EIO;
++ } else
++ ret = -ENOSYS;
++ break;
++ default:
++ ret = -ENOSYS;
++ }
++
++ scsi_host_put(shost);
++ return ret;
++}
++
++void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
++{
++ if (!ddb_entry->sess)
++ return;
++
++ if (ddb_entry->conn) {
++ iscsi_if_destroy_session_done(ddb_entry->conn);
++ iscsi_destroy_conn(ddb_entry->conn);
++ iscsi_remove_session(ddb_entry->sess);
++ }
++ iscsi_free_session(ddb_entry->sess);
++}
++
++int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
++{
++ int err;
++
++ err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
++ if (err) {
++ DEBUG2(printk(KERN_ERR "Could not add session.\n"));
++ return err;
++ }
++
++ ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0);
++ if (!ddb_entry->conn) {
++ iscsi_remove_session(ddb_entry->sess);
++ DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
++ return -ENOMEM;
++ }
++
++ ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
++ iscsi_if_create_session_done(ddb_entry->conn);
++ return 0;
++}
++
++struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
++{
++ struct ddb_entry *ddb_entry;
++ struct iscsi_cls_session *sess;
++
++ sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport);
++ if (!sess)
++ return NULL;
++
++ ddb_entry = sess->dd_data;
++ memset(ddb_entry, 0, sizeof(*ddb_entry));
++ ddb_entry->ha = ha;
++ ddb_entry->sess = sess;
++ return ddb_entry;
++}
++
++/*
++ * Timer routines
++ */
++
++static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
++ unsigned long interval)
++{
++ DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
++ __func__, ha->host->host_no));
++ init_timer(&ha->timer);
++ ha->timer.expires = jiffies + interval * HZ;
++ ha->timer.data = (unsigned long)ha;
++ ha->timer.function = (void (*)(unsigned long))func;
++ add_timer(&ha->timer);
++ ha->timer_active = 1;
++}
++
++static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
++{
++ del_timer_sync(&ha->timer);
++ ha->timer_active = 0;
++}
++
++/***
++ * qla4xxx_mark_device_missing - mark a device as missing.
++ * @ha: Pointer to host adapter structure.
++ * @ddb_entry: Pointer to device database entry
++ *
++ * This routine marks a device missing and resets the relogin retry count.
++ **/
++void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
++ struct ddb_entry *ddb_entry)
++{
++ atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
++ DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n",
++ ha->host_no, ddb_entry->bus, ddb_entry->target,
++ ddb_entry->fw_ddb_index));
++ iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
++}
++
++static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
++ struct ddb_entry *ddb_entry,
++ struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
++{
++ struct srb *srb;
++
++ srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
++ if (!srb)
++ return srb;
++
++ atomic_set(&srb->ref_count, 1);
++ srb->ha = ha;
++ srb->ddb = ddb_entry;
++ srb->cmd = cmd;
++ srb->flags = 0;
++ cmd->SCp.ptr = (void *)srb;
++ cmd->scsi_done = done;
++
++ return srb;
++}
++
++static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
++{
++ struct scsi_cmnd *cmd = srb->cmd;
++
++ if (srb->flags & SRB_DMA_VALID) {
++ if (cmd->use_sg) {
++ pci_unmap_sg(ha->pdev, cmd->request_buffer,
++ cmd->use_sg, cmd->sc_data_direction);
++ } else if (cmd->request_bufflen) {
++ pci_unmap_single(ha->pdev, srb->dma_handle,
++ cmd->request_bufflen,
++ cmd->sc_data_direction);
++ }
++ srb->flags &= ~SRB_DMA_VALID;
++ }
++ cmd->SCp.ptr = NULL;
++}
++
++void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
++{
++ struct scsi_cmnd *cmd = srb->cmd;
++
++ qla4xxx_srb_free_dma(ha, srb);
++
++ mempool_free(srb, ha->srb_mempool);
++
++ cmd->scsi_done(cmd);
++}
++
++/**
++ * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
++ * @cmd: Pointer to Linux's SCSI command structure
++ * @done_fn: Function that the driver calls to notify the SCSI mid-layer
++ * that the command has been processed.
++ *
++ * Remarks:
++ * This routine is invoked by Linux to send a SCSI command to the driver.
++ * The mid-level driver tries to ensure that queuecommand never gets
++ * invoked concurrently with itself or the interrupt handler (although
++ * the interrupt handler may call this routine as part of request-
++ * completion handling). Unfortunely, it sometimes calls the scheduler
++ * in interrupt context which is a big NO! NO!.
++ **/
++static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
++{
++ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
++ struct ddb_entry *ddb_entry = cmd->device->hostdata;
++ struct srb *srb;
++ int rval;
++
++ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
++ if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) {
++ cmd->result = DID_NO_CONNECT << 16;
++ goto qc_fail_command;
++ }
++ goto qc_host_busy;
++ }
++
++ spin_unlock_irq(ha->host->host_lock);
++
++ srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done);
++ if (!srb)
++ goto qc_host_busy_lock;
++
++ rval = qla4xxx_send_command_to_isp(ha, srb);
++ if (rval != QLA_SUCCESS)
++ goto qc_host_busy_free_sp;
++
++ spin_lock_irq(ha->host->host_lock);
++ return 0;
++
++qc_host_busy_free_sp:
++ qla4xxx_srb_free_dma(ha, srb);
++ mempool_free(srb, ha->srb_mempool);
++
++qc_host_busy_lock:
++ spin_lock_irq(ha->host->host_lock);
++
++qc_host_busy:
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++qc_fail_command:
++ done(cmd);
++
++ return 0;
++}
++
++/**
++ * qla4xxx_mem_free - frees memory allocated to adapter
++ * @ha: Pointer to host adapter structure.
++ *
++ * Frees memory previously allocated by qla4xxx_mem_alloc
++ **/
++static void qla4xxx_mem_free(struct scsi_qla_host *ha)
++{
++ if (ha->queues)
++ dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
++ ha->queues_dma);
++
++ ha->queues_len = 0;
++ ha->queues = NULL;
++ ha->queues_dma = 0;
++ ha->request_ring = NULL;
++ ha->request_dma = 0;
++ ha->response_ring = NULL;
++ ha->response_dma = 0;
++ ha->shadow_regs = NULL;
++ ha->shadow_regs_dma = 0;
++
++ /* Free srb pool. */
++ if (ha->srb_mempool)
++ mempool_destroy(ha->srb_mempool);
++
++ ha->srb_mempool = NULL;
++
++ /* release io space registers */
++ if (ha->reg)
++ iounmap(ha->reg);
++ pci_release_regions(ha->pdev);
++}
++
++/**
++ * qla4xxx_mem_alloc - allocates memory for use by adapter.
++ * @ha: Pointer to host adapter structure
++ *
++ * Allocates DMA memory for request and response queues. Also allocates memory
++ * for srbs.
++ **/
++static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
++{
++ unsigned long align;
++
++ /* Allocate contiguous block of DMA memory for queues. */
++ ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
++ (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
++ sizeof(struct shadow_regs) +
++ MEM_ALIGN_VALUE +
++ (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
++ ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
++ &ha->queues_dma, GFP_KERNEL);
++ if (ha->queues == NULL) {
++ dev_warn(&ha->pdev->dev,
++ "Memory Allocation failed - queues.\n");
++
++ goto mem_alloc_error_exit;
++ }
++ memset(ha->queues, 0, ha->queues_len);
++
++ /*
++ * As per RISC alignment requirements -- the bus-address must be a
++ * multiple of the request-ring size (in bytes).
++ */
++ align = 0;
++ if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
++ align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
++ (MEM_ALIGN_VALUE - 1));
++
++ /* Update request and response queue pointers. */
++ ha->request_dma = ha->queues_dma + align;
++ ha->request_ring = (struct queue_entry *) (ha->queues + align);
++ ha->response_dma = ha->queues_dma + align +
++ (REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
++ ha->response_ring = (struct queue_entry *) (ha->queues + align +
++ (REQUEST_QUEUE_DEPTH *
++ QUEUE_SIZE));
++ ha->shadow_regs_dma = ha->queues_dma + align +
++ (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
++ (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
++ ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
++ (REQUEST_QUEUE_DEPTH *
++ QUEUE_SIZE) +
++ (RESPONSE_QUEUE_DEPTH *
++ QUEUE_SIZE));
++
++ /* Allocate memory for srb pool. */
++ ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
++ mempool_free_slab, srb_cachep);
++ if (ha->srb_mempool == NULL) {
++ dev_warn(&ha->pdev->dev,
++ "Memory Allocation failed - SRB Pool.\n");
++
++ goto mem_alloc_error_exit;
++ }
++
++ return QLA_SUCCESS;
++
++mem_alloc_error_exit:
++ qla4xxx_mem_free(ha);
++ return QLA_ERROR;
++}
++
++/**
++ * qla4xxx_timer - checks every second for work to do.
++ * @ha: Pointer to host adapter structure.
++ **/
++static void qla4xxx_timer(struct scsi_qla_host *ha)
++{
++ struct ddb_entry *ddb_entry, *dtemp;
++ int start_dpc = 0;
++
++ /* Search for relogin's to time-out and port down retry. */
++ list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
++ /* Count down time between sending relogins */
++ if (adapter_up(ha) &&
++ !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
++ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
++ if (atomic_read(&ddb_entry->retry_relogin_timer) !=
++ INVALID_ENTRY) {
++ if (atomic_read(&ddb_entry->retry_relogin_timer)
++ == 0) {
++ atomic_set(&ddb_entry->
++ retry_relogin_timer,
++ INVALID_ENTRY);
++ set_bit(DPC_RELOGIN_DEVICE,
++ &ha->dpc_flags);
++ set_bit(DF_RELOGIN, &ddb_entry->flags);
++ DEBUG2(printk("scsi%ld: %s: index [%d]"
++ " login device\n",
++ ha->host_no, __func__,
++ ddb_entry->fw_ddb_index));
++ } else
++ atomic_dec(&ddb_entry->
++ retry_relogin_timer);
++ }
++ }
++
++ /* Wait for relogin to timeout */
++ if (atomic_read(&ddb_entry->relogin_timer) &&
++ (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
++ /*
++ * If the relogin times out and the device is
++ * still NOT ONLINE then try and relogin again.
++ */
++ if (atomic_read(&ddb_entry->state) !=
++ DDB_STATE_ONLINE &&
++ ddb_entry->fw_ddb_device_state ==
++ DDB_DS_SESSION_FAILED) {
++ /* Reset retry relogin timer */
++ atomic_inc(&ddb_entry->relogin_retry_count);
++ DEBUG2(printk("scsi%ld: index[%d] relogin"
++ " timed out-retrying"
++ " relogin (%d)\n",
++ ha->host_no,
++ ddb_entry->fw_ddb_index,
++ atomic_read(&ddb_entry->
++ relogin_retry_count))
++ );
++ start_dpc++;
++ DEBUG(printk("scsi%ld:%d:%d: index [%d] "
++ "initate relogin after"
++ " %d seconds\n",
++ ha->host_no, ddb_entry->bus,
++ ddb_entry->target,
++ ddb_entry->fw_ddb_index,
++ ddb_entry->default_time2wait + 4)
++ );
++
++ atomic_set(&ddb_entry->retry_relogin_timer,
++ ddb_entry->default_time2wait + 4);
++ }
++ }
++ }
++
++ /* Check for heartbeat interval. */
++ if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
++ ha->heartbeat_interval != 0) {
++ ha->seconds_since_last_heartbeat++;
++ if (ha->seconds_since_last_heartbeat >
++ ha->heartbeat_interval + 2)
++ set_bit(DPC_RESET_HA, &ha->dpc_flags);
++ }
++
++
++ /* Wakeup the dpc routine for this adapter, if needed. */
++ if ((start_dpc ||
++ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
++ test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
++ test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
++ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
++ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
++ test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
++ test_bit(DPC_AEN, &ha->dpc_flags)) &&
++ ha->dpc_thread) {
++ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
++ " - dpc flags = 0x%lx\n",
++ ha->host_no, __func__, ha->dpc_flags));
++ queue_work(ha->dpc_thread, &ha->dpc_work);
++ }
++
++ /* Reschedule timer thread to call us back in one second */
++ mod_timer(&ha->timer, jiffies + HZ);
++
++ DEBUG2(ha->seconds_since_last_intr++);
++}
++
++/**
++ * qla4xxx_cmd_wait - waits for all outstanding commands to complete
++ * @ha: Pointer to host adapter structure.
++ *
++ * This routine stalls the driver until all outstanding commands are returned.
++ * Caller must release the Hardware Lock prior to calling this routine.
++ **/
++static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
++{
++ uint32_t index = 0;
++ int stat = QLA_SUCCESS;
++ unsigned long flags;
++ struct scsi_cmnd *cmd;
++ int wait_cnt = WAIT_CMD_TOV; /*
++ * Initialized for 30 seconds as we
++ * expect all commands to retuned
++ * ASAP.
++ */
++
++ while (wait_cnt) {
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ /* Find a command that hasn't completed. */
++ for (index = 0; index < ha->host->can_queue; index++) {
++ cmd = scsi_host_find_tag(ha->host, index);
++ if (cmd != NULL)
++ break;
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ /* If No Commands are pending, wait is complete */
++ if (index == ha->host->can_queue) {
++ break;
++ }
++
++ /* If we timed out on waiting for commands to come back
++ * return ERROR.
++ */
++ wait_cnt--;
++ if (wait_cnt == 0)
++ stat = QLA_ERROR;
++ else {
++ msleep(1000);
++ }
++ } /* End of While (wait_cnt) */
++
++ return stat;
++}
++
++/**
++ * qla4010_soft_reset - performs soft reset.
++ * @ha: Pointer to host adapter structure.
++ **/
++static int qla4010_soft_reset(struct scsi_qla_host *ha)
++{
++ uint32_t max_wait_time;
++ unsigned long flags = 0;
++ int status = QLA_ERROR;
++ uint32_t ctrl_status;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++
++ /*
++ * If the SCSI Reset Interrupt bit is set, clear it.
++ * Otherwise, the Soft Reset won't work.
++ */
++ ctrl_status = readw(&ha->reg->ctrl_status);
++ if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
++ writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
++
++ /* Issue Soft Reset */
++ writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ /* Wait until the Network Reset Intr bit is cleared */
++ max_wait_time = RESET_INTR_TOV;
++ do {
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ ctrl_status = readw(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
++ break;
++
++ msleep(1000);
++ } while ((--max_wait_time));
++
++ if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
++ DEBUG2(printk(KERN_WARNING
++ "scsi%ld: Network Reset Intr not cleared by "
++ "Network function, clearing it now!\n",
++ ha->host_no));
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ }
++
++ /* Wait until the firmware tells us the Soft Reset is done */
++ max_wait_time = SOFT_RESET_TOV;
++ do {
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ ctrl_status = readw(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if ((ctrl_status & CSR_SOFT_RESET) == 0) {
++ status = QLA_SUCCESS;
++ break;
++ }
++
++ msleep(1000);
++ } while ((--max_wait_time));
++
++ /*
++ * Also, make sure that the SCSI Reset Interrupt bit has been cleared
++ * after the soft reset has taken place.
++ */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ ctrl_status = readw(&ha->reg->ctrl_status);
++ if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
++ writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ /* If soft reset fails then most probably the bios on other
++ * function is also enabled.
++ * Since the initialization is sequential the other fn
++ * wont be able to acknowledge the soft reset.
++ * Issue a force soft reset to workaround this scenario.
++ */
++ if (max_wait_time == 0) {
++ /* Issue Force Soft Reset */
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
++ readl(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ /* Wait until the firmware tells us the Soft Reset is done */
++ max_wait_time = SOFT_RESET_TOV;
++ do {
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ ctrl_status = readw(&ha->reg->ctrl_status);
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
++ status = QLA_SUCCESS;
++ break;
++ }
++
++ msleep(1000);
++ } while ((--max_wait_time));
++ }
++
++ return status;
++}
++
++/**
++ * qla4xxx_topcat_reset - performs hard reset of TopCat Chip.
++ * @ha: Pointer to host adapter structure.
++ **/
++static int qla4xxx_topcat_reset(struct scsi_qla_host *ha)
++{
++ unsigned long flags;
++
++ ql4xxx_lock_nvram(ha);
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ writel(set_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
++ readl(isp_gp_out(ha));
++ mdelay(1);
++
++ writel(clr_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
++ readl(isp_gp_out(ha));
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++ mdelay(2523);
++
++ ql4xxx_unlock_nvram(ha);
++ return QLA_SUCCESS;
++}
++
++/**
++ * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
++ * @ha: Pointer to host adapter structure.
++ *
++ * This routine is called just prior to a HARD RESET to return all
++ * outstanding commands back to the Operating System.
++ * Caller should make sure that the following locks are released
++ * before this calling routine: Hardware lock, and io_request_lock.
++ **/
++static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
++{
++ struct srb *srb;
++ int i;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ for (i = 0; i < ha->host->can_queue; i++) {
++ srb = qla4xxx_del_from_active_array(ha, i);
++ if (srb != NULL) {
++ srb->cmd->result = DID_RESET << 16;
++ qla4xxx_srb_compl(ha, srb);
++ }
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++}
++
++/**
++ * qla4xxx_hard_reset - performs HBA Hard Reset
++ * @ha: Pointer to host adapter structure.
++ **/
++static int qla4xxx_hard_reset(struct scsi_qla_host *ha)
++{
++ /* The QLA4010 really doesn't have an equivalent to a hard reset */
++ qla4xxx_flush_active_srbs(ha);
++ if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
++ int status = QLA_ERROR;
++
++ if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
++ (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
++ (qla4010_soft_reset(ha) == QLA_SUCCESS))
++ status = QLA_SUCCESS;
++ return status;
++ } else
++ return qla4010_soft_reset(ha);
++}
++
++/**
++ * qla4xxx_recover_adapter - recovers adapter after a fatal error
++ * @ha: Pointer to host adapter structure.
++ * @renew_ddb_list: Indicates what to do with the adapter's ddb list
++ * after adapter recovery has completed.
++ * 0=preserve ddb list, 1=destroy and rebuild ddb list
++ **/
++static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
++ uint8_t renew_ddb_list)
++{
++ int status;
++
++ /* Stall incoming I/O until we are done */
++ clear_bit(AF_ONLINE, &ha->flags);
++ DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
++ __func__));
++
++ /* Wait for outstanding commands to complete.
++ * Stalls the driver for max 30 secs
++ */
++ status = qla4xxx_cmd_wait(ha);
++
++ qla4xxx_disable_intrs(ha);
++
++ /* Flush any pending ddb changed AENs */
++ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
++
++ /* Reset the firmware. If successful, function
++ * returns with ISP interrupts enabled.
++ */
++ if (status == QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
++ ha->host_no, __func__));
++ status = qla4xxx_soft_reset(ha);
++ }
++ /* FIXMEkaren: Do we want to keep interrupts enabled and process
++ AENs after soft reset */
++
++ /* If firmware (SOFT) reset failed, or if all outstanding
++ * commands have not returned, then do a HARD reset.
++ */
++ if (status == QLA_ERROR) {
++ DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n",
++ ha->host_no, __func__));
++ status = qla4xxx_hard_reset(ha);
++ }
++
++ /* Flush any pending ddb changed AENs */
++ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
++
++ /* Re-initialize firmware. If successful, function returns
++ * with ISP interrupts enabled */
++ if (status == QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n",
++ ha->host_no, __func__));
++
++ /* If successful, AF_ONLINE flag set in
++ * qla4xxx_initialize_adapter */
++ status = qla4xxx_initialize_adapter(ha, renew_ddb_list);
++ }
++
++ /* Failed adapter initialization?
++ * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */
++ if ((test_bit(AF_ONLINE, &ha->flags) == 0) &&
++ (test_bit(DPC_RESET_HA, &ha->dpc_flags))) {
++ /* Adapter initialization failed, see if we can retry
++ * resetting the ha */
++ if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
++ ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
++ DEBUG2(printk("scsi%ld: recover adapter - retrying "
++ "(%d) more times\n", ha->host_no,
++ ha->retry_reset_ha_cnt));
++ set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
++ status = QLA_ERROR;
++ } else {
++ if (ha->retry_reset_ha_cnt > 0) {
++ /* Schedule another Reset HA--DPC will retry */
++ ha->retry_reset_ha_cnt--;
++ DEBUG2(printk("scsi%ld: recover adapter - "
++ "retry remaining %d\n",
++ ha->host_no,
++ ha->retry_reset_ha_cnt));
++ status = QLA_ERROR;
++ }
++
++ if (ha->retry_reset_ha_cnt == 0) {
++ /* Recover adapter retries have been exhausted.
++ * Adapter DEAD */
++ DEBUG2(printk("scsi%ld: recover adapter "
++ "failed - board disabled\n",
++ ha->host_no));
++ qla4xxx_flush_active_srbs(ha);
++ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
++ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
++ clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST,
++ &ha->dpc_flags);
++ status = QLA_ERROR;
++ }
++ }
++ } else {
++ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
++ clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags);
++ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
++ }
++
++ ha->adapter_error_count++;
++
++ if (status == QLA_SUCCESS)
++ qla4xxx_enable_intrs(ha);
++
++ DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no));
++ return status;
++}
++
++/**
++ * qla4xxx_do_dpc - dpc routine
++ * @data: in our case pointer to adapter structure
++ *
++ * This routine is a task that is schedule by the interrupt handler
++ * to perform the background processing for interrupts. We put it
++ * on a task queue that is consumed whenever the scheduler runs; that's
++ * so you can do anything (i.e. put the process to sleep etc). In fact,
++ * the mid-level tries to sleep when it reaches the driver threshold
++ * "host->can_queue". This can cause a panic if we were in our interrupt code.
++ **/
++static void qla4xxx_do_dpc(void *data)
++{
++ struct scsi_qla_host *ha = (struct scsi_qla_host *) data;
++ struct ddb_entry *ddb_entry, *dtemp;
++
++ DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n",
++ ha->host_no, __func__));
++
++ DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n",
++ ha->host_no, __func__, ha->flags));
++ DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n",
++ ha->host_no, __func__, ha->dpc_flags));
++
++ /* Initialization not yet finished. Don't do anything yet. */
++ if (!test_bit(AF_INIT_DONE, &ha->flags))
++ return;
++
++ if (adapter_up(ha) ||
++ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
++ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
++ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
++ if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags))
++ /*
++ * dg 09/23 Never initialize ddb list
++ * once we up and running
++ * qla4xxx_recover_adapter(ha,
++ * REBUILD_DDB_LIST);
++ */
++ qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
++
++ if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
++ qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
++
++ if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
++ uint8_t wait_time = RESET_INTR_TOV;
++ unsigned long flags = 0;
++
++ qla4xxx_flush_active_srbs(ha);
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ while ((readw(&ha->reg->ctrl_status) &
++ (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
++ if (--wait_time == 0)
++ break;
++
++ spin_unlock_irqrestore(&ha->hardware_lock,
++ flags);
++
++ msleep(1000);
++
++ spin_lock_irqsave(&ha->hardware_lock, flags);
++ }
++ spin_unlock_irqrestore(&ha->hardware_lock, flags);
++
++ if (wait_time == 0)
++ DEBUG2(printk("scsi%ld: %s: SR|FSR "
++ "bit not cleared-- resetting\n",
++ ha->host_no, __func__));
++ }
++ }
++
++ /* ---- process AEN? --- */
++ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
++ qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
++
++ /* ---- Get DHCP IP Address? --- */
++ if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
++ qla4xxx_get_dhcp_ip_address(ha);
++
++ /* ---- relogin device? --- */
++ if (adapter_up(ha) &&
++ test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
++ list_for_each_entry_safe(ddb_entry, dtemp,
++ &ha->ddb_list, list) {
++ if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
++ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
++ qla4xxx_relogin_device(ha, ddb_entry);
++
++ /*
++ * If mbx cmd times out there is no point
++ * in continuing further.
++ * With large no of targets this can hang
++ * the system.
++ */
++ if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
++ printk(KERN_WARNING "scsi%ld: %s: "
++ "need to reset hba\n",
++ ha->host_no, __func__);
++ break;
++ }
++ }
++ }
++}
++
++/**
++ * qla4xxx_free_adapter - release the adapter
++ * @ha: pointer to adapter structure
++ **/
++static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
++{
++
++ if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) {
++ /* Turn-off interrupts on the card. */
++ qla4xxx_disable_intrs(ha);
++ }
++
++ /* Kill the kernel thread for this host */
++ if (ha->dpc_thread)
++ destroy_workqueue(ha->dpc_thread);
++
++ /* Issue Soft Reset to put firmware in unknown state */
++ qla4xxx_soft_reset(ha);
++
++ /* Remove timer thread, if present */
++ if (ha->timer_active)
++ qla4xxx_stop_timer(ha);
++
++ /* free extra memory */
++ qla4xxx_mem_free(ha);
++
++ /* Detach interrupts */
++ if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
++ free_irq(ha->pdev->irq, ha);
++
++ pci_disable_device(ha->pdev);
++
++}
++
++/***
++ * qla4xxx_iospace_config - maps registers
++ * @ha: pointer to adapter structure
++ *
++ * This routines maps HBA's registers from the pci address space
++ * into the kernel virtual address space for memory mapped i/o.
++ **/
++static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
++{
++ unsigned long pio, pio_len, pio_flags;
++ unsigned long mmio, mmio_len, mmio_flags;
++
++ pio = pci_resource_start(ha->pdev, 0);
++ pio_len = pci_resource_len(ha->pdev, 0);
++ pio_flags = pci_resource_flags(ha->pdev, 0);
++ if (pio_flags & IORESOURCE_IO) {
++ if (pio_len < MIN_IOBASE_LEN) {
++ dev_warn(&ha->pdev->dev,
++ "Invalid PCI I/O region size\n");
++ pio = 0;
++ }
++ } else {
++ dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n");
++ pio = 0;
++ }
++
++ /* Use MMIO operations for all accesses. */
++ mmio = pci_resource_start(ha->pdev, 1);
++ mmio_len = pci_resource_len(ha->pdev, 1);
++ mmio_flags = pci_resource_flags(ha->pdev, 1);
++
++ if (!(mmio_flags & IORESOURCE_MEM)) {
++ dev_err(&ha->pdev->dev,
++ "region #0 not an MMIO resource, aborting\n");
++
++ goto iospace_error_exit;
++ }
++ if (mmio_len < MIN_IOBASE_LEN) {
++ dev_err(&ha->pdev->dev,
++ "Invalid PCI mem region size, aborting\n");
++ goto iospace_error_exit;
++ }
++
++ if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
++ dev_warn(&ha->pdev->dev,
++ "Failed to reserve PIO/MMIO regions\n");
++
++ goto iospace_error_exit;
++ }
++
++ ha->pio_address = pio;
++ ha->pio_length = pio_len;
++ ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
++ if (!ha->reg) {
++ dev_err(&ha->pdev->dev,
++ "cannot remap MMIO, aborting\n");
++
++ goto iospace_error_exit;
++ }
++
++ return 0;
++
++iospace_error_exit:
++ return -ENOMEM;
++}
++
++/**
++ * qla4xxx_probe_adapter - callback function to probe HBA
++ * @pdev: pointer to pci_dev structure
++ * @pci_device_id: pointer to pci_device entry
++ *
++ * This routine will probe for Qlogic 4xxx iSCSI host adapters.
++ * It returns zero if successful. It also initializes all data necessary for
++ * the driver.
++ **/
++static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
++{
++ int ret = -ENODEV, status;
++ struct Scsi_Host *host;
++ struct scsi_qla_host *ha;
++ struct ddb_entry *ddb_entry, *ddbtemp;
++ uint8_t init_retry_count = 0;
++ char buf[34];
++
++ if (pci_enable_device(pdev))
++ return -1;
++
++ host = scsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha));
++ if (host == NULL) {
++ printk(KERN_WARNING
++ "qla4xxx: Couldn't allocate host from scsi layer!\n");
++ goto probe_disable_device;
++ }
++
++ /* Clear our data area */
++ ha = (struct scsi_qla_host *) host->hostdata;
++ memset(ha, 0, sizeof(*ha));
++
++ /* Save the information from PCI BIOS. */
++ ha->pdev = pdev;
++ ha->host = host;
++ ha->host_no = host->host_no;
++
++ /* Configure PCI I/O space. */
++ ret = qla4xxx_iospace_config(ha);
++ if (ret)
++ goto probe_failed;
++
++ dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n",
++ pdev->device, pdev->irq, ha->reg);
++
++ qla4xxx_config_dma_addressing(ha);
++
++ /* Initialize lists and spinlocks. */
++ INIT_LIST_HEAD(&ha->ddb_list);
++ INIT_LIST_HEAD(&ha->free_srb_q);
++
++ mutex_init(&ha->mbox_sem);
++ init_waitqueue_head(&ha->mailbox_wait_queue);
++
++ spin_lock_init(&ha->hardware_lock);
++ spin_lock_init(&ha->list_lock);
++
++ /* Allocate dma buffers */
++ if (qla4xxx_mem_alloc(ha)) {
++ dev_warn(&ha->pdev->dev,
++ "[ERROR] Failed to allocate memory for adapter\n");
++
++ ret = -ENOMEM;
++ goto probe_failed;
++ }
++
++ /*
++ * Initialize the Host adapter request/response queues and
++ * firmware
++ * NOTE: interrupts enabled upon successful completion
++ */
++ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
++ while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) {
++ DEBUG2(printk("scsi: %s: retrying adapter initialization "
++ "(%d)\n", __func__, init_retry_count));
++ qla4xxx_soft_reset(ha);
++ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
++ }
++ if (status == QLA_ERROR) {
++ dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n");
++
++ ret = -ENODEV;
++ goto probe_failed;
++ }
++
++ host->cmd_per_lun = 3;
++ host->max_channel = 0;
++ host->max_lun = MAX_LUNS - 1;
++ host->max_id = MAX_TARGETS;
++ host->max_cmd_len = IOCB_MAX_CDB_LEN;
++ host->can_queue = MAX_SRBS ;
++ host->transportt = qla4xxx_scsi_transport;
++
++ ret = scsi_init_shared_tag_map(host, MAX_SRBS);
++ if (ret) {
++ dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed");
++ goto probe_failed;
++ }
++
++ /* Startup the kernel thread for this host adapter. */
++ DEBUG2(printk("scsi: %s: Starting kernel thread for "
++ "qla4xxx_dpc\n", __func__));
++ sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
++ ha->dpc_thread = create_singlethread_workqueue(buf);
++ if (!ha->dpc_thread) {
++ dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n");
++ ret = -ENODEV;
++ goto probe_failed;
++ }
++ INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc, ha);
++
++ ret = request_irq(pdev->irq, qla4xxx_intr_handler,
++ SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha);
++ if (ret) {
++ dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
++ " already in use.\n", pdev->irq);
++ goto probe_failed;
++ }
++ set_bit(AF_IRQ_ATTACHED, &ha->flags);
++ host->irq = pdev->irq;
++ DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq));
++
++ qla4xxx_enable_intrs(ha);
++
++ /* Start timer thread. */
++ qla4xxx_start_timer(ha, qla4xxx_timer, 1);
++
++ set_bit(AF_INIT_DONE, &ha->flags);
++
++ pci_set_drvdata(pdev, ha);
++
++ ret = scsi_add_host(host, &pdev->dev);
++ if (ret)
++ goto probe_failed;
++
++ /* Update transport device information for all devices. */
++ list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
++ if (qla4xxx_add_sess(ddb_entry))
++ goto remove_host;
++ }
++
++ printk(KERN_INFO
++ " QLogic iSCSI HBA Driver version: %s\n"
++ " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
++ qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
++ ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
++ ha->patch_number, ha->build_number);
++
++ return 0;
++
++remove_host:
++ qla4xxx_free_ddb_list(ha);
++ scsi_remove_host(host);
++
++probe_failed:
++ qla4xxx_free_adapter(ha);
++ scsi_host_put(ha->host);
++
++probe_disable_device:
++ pci_disable_device(pdev);
++
++ return ret;
++}
++
++/**
++ * qla4xxx_remove_adapter - calback function to remove adapter.
++ * @pci_dev: PCI device pointer
++ **/
++static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
++{
++ struct scsi_qla_host *ha;
++
++ ha = pci_get_drvdata(pdev);
++
++ /* remove devs from iscsi_sessions to scsi_devices */
++ qla4xxx_free_ddb_list(ha);
++
++ scsi_remove_host(ha->host);
++
++ qla4xxx_free_adapter(ha);
++
++ scsi_host_put(ha->host);
++
++ pci_set_drvdata(pdev, NULL);
++}
++
++/**
++ * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
++ * @ha: HA context
++ *
++ * At exit, the @ha's flags.enable_64bit_addressing set to indicated
++ * supported addressing method.
++ */
++void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
++{
++ int retval;
++
++ /* Update our PCI device dma_mask for full 64 bit mask */
++ if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {
++ if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
++ dev_dbg(&ha->pdev->dev,
++ "Failed to set 64 bit PCI consistent mask; "
++ "using 32 bit.\n");
++ retval = pci_set_consistent_dma_mask(ha->pdev,
++ DMA_32BIT_MASK);
++ }
++ } else
++ retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
++}
++
++static int qla4xxx_slave_alloc(struct scsi_device *sdev)
++{
++ struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target);
++ struct ddb_entry *ddb = sess->dd_data;
++
++ sdev->hostdata = ddb;
++ sdev->tagged_supported = 1;
++ scsi_activate_tcq(sdev, sdev->host->can_queue);
++ return 0;
++}
++
++static int qla4xxx_slave_configure(struct scsi_device *sdev)
++{
++ sdev->tagged_supported = 1;
++ return 0;
++}
++
++static void qla4xxx_slave_destroy(struct scsi_device *sdev)
++{
++ scsi_deactivate_tcq(sdev, 1);
++}
++
++/**
++ * qla4xxx_del_from_active_array - returns an active srb
++ * @ha: Pointer to host adapter structure.
++ * @index: index into to the active_array
++ *
++ * This routine removes and returns the srb at the specified index
++ **/
++struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
++{
++ struct srb *srb = NULL;
++ struct scsi_cmnd *cmd;
++
++ if (!(cmd = scsi_host_find_tag(ha->host, index)))
++ return srb;
++
++ if (!(srb = (struct srb *)cmd->host_scribble))
++ return srb;
++
++ /* update counters */
++ if (srb->flags & SRB_DMA_VALID) {
++ ha->req_q_count += srb->iocb_cnt;
++ ha->iocb_cnt -= srb->iocb_cnt;
++ if (srb->cmd)
++ srb->cmd->host_scribble = NULL;
++ }
++ return srb;
++}
++
++/**
++ * qla4xxx_soft_reset - performs a SOFT RESET of hba.
++ * @ha: Pointer to host adapter structure.
++ **/
++int qla4xxx_soft_reset(struct scsi_qla_host *ha)
++{
++
++ DEBUG2(printk(KERN_WARNING "scsi%ld: %s: chip reset!\n", ha->host_no,
++ __func__));
++ if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
++ int status = QLA_ERROR;
++
++ if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
++ (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
++ (qla4010_soft_reset(ha) == QLA_SUCCESS) )
++ status = QLA_SUCCESS;
++ return status;
++ } else
++ return qla4010_soft_reset(ha);
++}
++
++/**
++ * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
++ * @ha: actual ha whose done queue will contain the comd returned by firmware.
++ * @cmd: Scsi Command to wait on.
++ *
++ * This routine waits for the command to be returned by the Firmware
++ * for some max time.
++ **/
++static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
++ struct scsi_cmnd *cmd)
++{
++ int done = 0;
++ struct srb *rp;
++ uint32_t max_wait_time = EH_WAIT_CMD_TOV;
++
++ do {
++ /* Checking to see if its returned to OS */
++ rp = (struct srb *) cmd->SCp.ptr;
++ if (rp == NULL) {
++ done++;
++ break;
++ }
++
++ msleep(2000);
++ } while (max_wait_time--);
++
++ return done;
++}
++
++/**
++ * qla4xxx_wait_for_hba_online - waits for HBA to come online
++ * @ha: Pointer to host adapter structure
++ **/
++static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
++{
++ unsigned long wait_online;
++
++ wait_online = jiffies + (30 * HZ);
++ while (time_before(jiffies, wait_online)) {
++
++ if (adapter_up(ha))
++ return QLA_SUCCESS;
++ else if (ha->retry_reset_ha_cnt == 0)
++ return QLA_ERROR;
++
++ msleep(2000);
++ }
++
++ return QLA_ERROR;
++}
++
++/**
++ * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish.
++ * @ha: pointer to to HBA
++ * @t: target id
++ * @l: lun id
++ *
++ * This function waits for all outstanding commands to a lun to complete. It
++ * returns 0 if all pending commands are returned and 1 otherwise.
++ **/
++static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha,
++ int t, int l)
++{
++ int cnt;
++ int status = 0;
++ struct scsi_cmnd *cmd;
++
++ /*
++ * Waiting for all commands for the designated target in the active
++ * array
++ */
++ for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
++ cmd = scsi_host_find_tag(ha->host, cnt);
++ if (cmd && cmd->device->id == t && cmd->device->lun == l) {
++ if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
++ status++;
++ break;
++ }
++ }
++ }
++ return status;
++}
++
++/**
++ * qla4xxx_eh_device_reset - callback for target reset.
++ * @cmd: Pointer to Linux's SCSI command structure
++ *
++ * This routine is called by the Linux OS to reset all luns on the
++ * specified target.
++ **/
++static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
++{
++ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
++ struct ddb_entry *ddb_entry = cmd->device->hostdata;
++ struct srb *sp;
++ int ret = FAILED, stat;
++
++ sp = (struct srb *) cmd->SCp.ptr;
++ if (!sp || !ddb_entry)
++ return ret;
++
++ dev_info(&ha->pdev->dev,
++ "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
++ cmd->device->channel, cmd->device->id, cmd->device->lun);
++
++ DEBUG2(printk(KERN_INFO
++ "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
++ "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
++ cmd, jiffies, cmd->timeout_per_command / HZ,
++ ha->dpc_flags, cmd->result, cmd->allowed));
++
++ /* FIXME: wait for hba to go online */
++ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
++ if (stat != QLA_SUCCESS) {
++ dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
++ goto eh_dev_reset_done;
++ }
++
++ /* Send marker. */
++ ha->marker_needed = 1;
++
++ /*
++ * If we are coming down the EH path, wait for all commands to complete
++ * for the device.
++ */
++ if (cmd->device->host->shost_state == SHOST_RECOVERY) {
++ if (qla4xxx_eh_wait_for_active_target_commands(ha,
++ cmd->device->id,
++ cmd->device->lun)){
++ dev_info(&ha->pdev->dev,
++ "DEVICE RESET FAILED - waiting for "
++ "commands.\n");
++ goto eh_dev_reset_done;
++ }
++ }
++
++ dev_info(&ha->pdev->dev,
++ "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
++ ha->host_no, cmd->device->channel, cmd->device->id,
++ cmd->device->lun);
++
++ ret = SUCCESS;
++
++eh_dev_reset_done:
++
++ return ret;
++}
++
++/**
++ * qla4xxx_eh_host_reset - kernel callback
++ * @cmd: Pointer to Linux's SCSI command structure
++ *
++ * This routine is invoked by the Linux kernel to perform fatal error
++ * recovery on the specified adapter.
++ **/
++static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
++{
++ int return_status = FAILED;
++ struct scsi_qla_host *ha;
++
++ ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
++
++ dev_info(&ha->pdev->dev,
++ "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
++ cmd->device->channel, cmd->device->id, cmd->device->lun);
++
++ if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
++ DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter "
++ "DEAD.\n", ha->host_no, cmd->device->channel,
++ __func__));
++
++ return FAILED;
++ }
++
++ if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) {
++ return_status = SUCCESS;
++ }
++
++ dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
++ return_status == FAILED ? "FAILED" : "SUCCEDED");
++
++ return return_status;
++}
++
++
++static struct pci_device_id qla4xxx_pci_tbl[] = {
++ {
++ .vendor = PCI_VENDOR_ID_QLOGIC,
++ .device = PCI_DEVICE_ID_QLOGIC_ISP4010,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ },
++ {
++ .vendor = PCI_VENDOR_ID_QLOGIC,
++ .device = PCI_DEVICE_ID_QLOGIC_ISP4022,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ },
++ {0, 0},
++};
++MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
++
++struct pci_driver qla4xxx_pci_driver = {
++ .name = DRIVER_NAME,
++ .id_table = qla4xxx_pci_tbl,
++ .probe = qla4xxx_probe_adapter,
++ .remove = qla4xxx_remove_adapter,
++};
++
++static int __init qla4xxx_module_init(void)
++{
++ int ret;
++
++ /* Allocate cache for SRBs. */
++ srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (srb_cachep == NULL) {
++ printk(KERN_ERR
++ "%s: Unable to allocate SRB cache..."
++ "Failing load!\n", DRIVER_NAME);
++ ret = -ENOMEM;
++ goto no_srp_cache;
++ }
++
++ /* Derive version string. */
++ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
++ if (ql4xextended_error_logging)
++ strcat(qla4xxx_version_str, "-debug");
++
++ qla4xxx_scsi_transport =
++ iscsi_register_transport(&qla4xxx_iscsi_transport);
++ if (!qla4xxx_scsi_transport){
++ ret = -ENODEV;
++ goto release_srb_cache;
++ }
++
++ ret = pci_register_driver(&qla4xxx_pci_driver);
++ if (ret)
++ goto unregister_transport;
++
++ printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
++ return 0;
++
++unregister_transport:
++ iscsi_unregister_transport(&qla4xxx_iscsi_transport);
++release_srb_cache:
++ kmem_cache_destroy(srb_cachep);
++no_srp_cache:
++ return ret;
++}
++
++static void __exit qla4xxx_module_exit(void)
++{
++ pci_unregister_driver(&qla4xxx_pci_driver);
++ iscsi_unregister_transport(&qla4xxx_iscsi_transport);
++ kmem_cache_destroy(srb_cachep);
++}
++
++module_init(qla4xxx_module_init);
++module_exit(qla4xxx_module_exit);
++
++MODULE_AUTHOR("QLogic Corporation");
++MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(QLA4XXX_DRIVER_VERSION);
+diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
+new file mode 100644
+index 0000000..b3fe7e6
+--- /dev/null
++++ b/drivers/scsi/qla4xxx/ql4_version.h
+@@ -0,0 +1,13 @@
++/*
++ * QLogic iSCSI HBA Driver
++ * Copyright (c) 2003-2006 QLogic Corporation
++ *
++ * See LICENSE.qla4xxx for copyright and licensing details.
++ */
++
++#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k"
++
++#define QL4_DRIVER_MAJOR_VER 5
++#define QL4_DRIVER_MINOR_VER 0
++#define QL4_DRIVER_PATCH_VER 5
++#define QL4_DRIVER_BETA_VER 9
+diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
+index 52fb2ec..2e7db18 100644
+--- a/drivers/scsi/qlogicfas408.c
++++ b/drivers/scsi/qlogicfas408.c
+@@ -209,7 +209,7 @@ static int ql_wai(struct qlogicfas408_pr
+ * caller must hold host lock
+ */
+
+-static void ql_icmd(Scsi_Cmnd * cmd)
++static void ql_icmd(struct scsi_cmnd *cmd)
+ {
+ struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+ int qbase = priv->qbase;
+@@ -256,7 +256,7 @@ static void ql_icmd(Scsi_Cmnd * cmd)
+ * Process scsi command - usually after interrupt
+ */
+
+-static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
++static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
+ {
+ unsigned int i, j;
+ unsigned long k;
+@@ -405,10 +405,10 @@ static unsigned int ql_pcmd(Scsi_Cmnd *
+ * Interrupt handler
+ */
+
+-static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
++static void ql_ihandl(void *dev_id)
+ {
+- Scsi_Cmnd *icmd;
+- struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
++ struct scsi_cmnd *icmd;
++ struct Scsi_Host *host = dev_id;
+ struct qlogicfas408_priv *priv = get_priv_by_host(host);
+ int qbase = priv->qbase;
+ REG0;
+@@ -432,13 +432,13 @@ static void ql_ihandl(int irq, void *dev
+ (icmd->scsi_done) (icmd);
+ }
+
+-irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *host = dev_id;
+
+ spin_lock_irqsave(host->host_lock, flags);
+- ql_ihandl(irq, dev_id, regs);
++ ql_ihandl(dev_id);
+ spin_unlock_irqrestore(host->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+@@ -447,7 +447,8 @@ irqreturn_t qlogicfas408_ihandl(int irq,
+ * Queued command
+ */
+
+-int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
++int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
++ void (*done) (struct scsi_cmnd *))
+ {
+ struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+ if (scmd_id(cmd) == priv->qinitid) {
+@@ -470,9 +471,8 @@ int qlogicfas408_queuecommand(Scsi_Cmnd
+ * Return bios parameters
+ */
+
+-int qlogicfas408_biosparam(struct scsi_device * disk,
+- struct block_device *dev,
+- sector_t capacity, int ip[])
++int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
++ sector_t capacity, int ip[])
+ {
+ /* This should mimic the DOS Qlogic driver's behavior exactly */
+ ip[0] = 0x40;
+@@ -494,7 +494,7 @@ int qlogicfas408_biosparam(struct scsi_d
+ * Abort a command in progress
+ */
+
+-int qlogicfas408_abort(Scsi_Cmnd * cmd)
++int qlogicfas408_abort(struct scsi_cmnd *cmd)
+ {
+ struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+ priv->qabort = 1;
+@@ -508,7 +508,7 @@ int qlogicfas408_abort(Scsi_Cmnd * cmd)
+ * the PCMCIA qlogic_stub code. This wants fixing
+ */
+
+-int qlogicfas408_bus_reset(Scsi_Cmnd * cmd)
++int qlogicfas408_bus_reset(struct scsi_cmnd *cmd)
+ {
+ struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+ unsigned long flags;
+diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h
+index 4b3df20..2606264 100644
+--- a/drivers/scsi/qlogicfas408.h
++++ b/drivers/scsi/qlogicfas408.h
+@@ -75,15 +75,15 @@
+ /*----------------------------------------------------------------*/
+
+ struct qlogicfas408_priv {
+- int qbase; /* Port */
+- int qinitid; /* initiator ID */
+- int qabort; /* Flag to cause an abort */
+- int qlirq; /* IRQ being used */
+- int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */
+- char qinfo[80]; /* description */
+- Scsi_Cmnd *qlcmd; /* current command being processed */
+- struct Scsi_Host *shost; /* pointer back to host */
+- struct qlogicfas408_priv *next; /* next private struct */
++ int qbase; /* Port */
++ int qinitid; /* initiator ID */
++ int qabort; /* Flag to cause an abort */
++ int qlirq; /* IRQ being used */
++ int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */
++ char qinfo[80]; /* description */
++ struct scsi_cmnd *qlcmd; /* current command being processed */
++ struct Scsi_Host *shost; /* pointer back to host */
++ struct qlogicfas408_priv *next; /* next private struct */
+ };
+
+ /* The qlogic card uses two register maps - These macros select which one */
+@@ -102,13 +102,14 @@ struct qlogicfas408_priv {
+ #define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0])
+ #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
+
+-irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs);
+-int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
++irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id);
++int qlogicfas408_queuecommand(struct scsi_cmnd * cmd,
++ void (*done) (struct scsi_cmnd *));
+ int qlogicfas408_biosparam(struct scsi_device * disk,
+- struct block_device *dev,
+- sector_t capacity, int ip[]);
+-int qlogicfas408_abort(Scsi_Cmnd * cmd);
+-int qlogicfas408_bus_reset(Scsi_Cmnd * cmd);
++ struct block_device *dev,
++ sector_t capacity, int ip[]);
++int qlogicfas408_abort(struct scsi_cmnd * cmd);
++int qlogicfas408_bus_reset(struct scsi_cmnd * cmd);
+ const char *qlogicfas408_info(struct Scsi_Host *host);
+ int qlogicfas408_get_chip_type(int qbase, int int_type);
+ void qlogicfas408_setup(int qbase, int id, int int_type);
+diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
+index 5b2f074..9b827ce 100644
+--- a/drivers/scsi/qlogicpti.c
++++ b/drivers/scsi/qlogicpti.c
+@@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(stru
+
+ #define PTI_RESET_LIMIT 400
+
+-static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
++static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti)
+ {
+ struct Scsi_Host *host = qpti->qhost;
+ unsigned short csum = 0;
+@@ -649,7 +649,7 @@ static int qlogicpti_verify_tmon(struct
+ return 0;
+ }
+
+-static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t qpti_intr(int irq, void *dev_id);
+
+ static void __init qpti_chain_add(struct qlogicpti *qpti)
+ {
+@@ -1297,7 +1297,7 @@ static struct scsi_cmnd *qlogicpti_intr_
+ return done_queue;
+ }
+
+-static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t qpti_intr(int irq, void *dev_id)
+ {
+ struct qlogicpti *qpti = dev_id;
+ unsigned long flags;
+diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c
+index 1545b30..19aa84f 100644
+--- a/drivers/scsi/qlogicpti_asm.c
++++ b/drivers/scsi/qlogicpti_asm.c
+@@ -1,5 +1,5 @@
+ /* Version 1.31.00 ISP1000 Initiator RISC firmware */
+-unsigned short sbus_risc_code01[] __initdata = {
++unsigned short sbus_risc_code01[] __devinitdata = {
+ 0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50,
+ 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932,
+ 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749,
+@@ -1157,4 +1157,4 @@ unsigned short sbus_risc_code01[] __init
+ 0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c,
+ 0x92a7
+ };
+-unsigned short sbus_risc_code_length01 = 0x2419;
++unsigned short __devinitdata sbus_risc_code_length01 = 0x2419;
+diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
+index 327b33a..86e1318 100644
+--- a/drivers/scsi/raid_class.c
++++ b/drivers/scsi/raid_class.c
+@@ -215,18 +215,19 @@ static void raid_component_release(struc
+ kfree(rc);
+ }
+
+-void raid_component_add(struct raid_template *r,struct device *raid_dev,
+- struct device *component_dev)
++int raid_component_add(struct raid_template *r,struct device *raid_dev,
++ struct device *component_dev)
+ {
+ struct class_device *cdev =
+ attribute_container_find_class_device(&r->raid_attrs.ac,
+ raid_dev);
+ struct raid_component *rc;
+ struct raid_data *rd = class_get_devdata(cdev);
++ int err;
+
+ rc = kzalloc(sizeof(*rc), GFP_KERNEL);
+ if (!rc)
+- return;
++ return -ENOMEM;
+
+ INIT_LIST_HEAD(&rc->node);
+ class_device_initialize(&rc->cdev);
+@@ -239,7 +240,18 @@ void raid_component_add(struct raid_temp
+ list_add_tail(&rc->node, &rd->component_list);
+ rc->cdev.parent = cdev;
+ rc->cdev.class = &raid_class.class;
+- class_device_add(&rc->cdev);
++ err = class_device_add(&rc->cdev);
++ if (err)
++ goto err_out;
++
++ return 0;
++
++err_out:
++ list_del(&rc->node);
++ rd->component_count--;
++ put_device(component_dev);
++ kfree(rc);
++ return err;
+ }
+ EXPORT_SYMBOL(raid_component_add);
+
+diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
+deleted file mode 100644
+index fa38a41..0000000
+--- a/drivers/scsi/sata_mv.c
++++ /dev/null
+@@ -1,2467 +0,0 @@
+-/*
+- * sata_mv.c - Marvell SATA support
+- *
+- * Copyright 2005: EMC Corporation, all rights reserved.
+- * Copyright 2005 Red Hat, Inc. All rights reserved.
+- *
+- * Please ALWAYS copy linux-ide at vger.kernel.org on emails.
+- *
+- * 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 of the License.
+- *
+- * 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/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/sched.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-
+-#define DRV_NAME "sata_mv"
+-#define DRV_VERSION "0.7"
+-
+-enum {
+- /* BAR's are enumerated in terms of pci_resource_start() terms */
+- MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */
+- MV_IO_BAR = 2, /* offset 0x18: IO space */
+- MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */
+-
+- MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
+- MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
+-
+- MV_PCI_REG_BASE = 0,
+- MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
+- MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
+- MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
+- MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
+- MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
+- MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
+-
+- MV_SATAHC0_REG_BASE = 0x20000,
+- MV_FLASH_CTL = 0x1046c,
+- MV_GPIO_PORT_CTL = 0x104f0,
+- MV_RESET_CFG = 0x180d8,
+-
+- MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
+- MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
+- MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
+- MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
+-
+- MV_USE_Q_DEPTH = ATA_DEF_QUEUE,
+-
+- MV_MAX_Q_DEPTH = 32,
+- MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1,
+-
+- /* CRQB needs alignment on a 1KB boundary. Size == 1KB
+- * CRPB needs alignment on a 256B boundary. Size == 256B
+- * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
+- * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
+- */
+- MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH),
+- MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH),
+- MV_MAX_SG_CT = 176,
+- MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
+- MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
+-
+- MV_PORTS_PER_HC = 4,
+- /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+- MV_PORT_HC_SHIFT = 2,
+- /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
+- MV_PORT_MASK = 3,
+-
+- /* Host Flags */
+- MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
+- MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
+- MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
+- MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
+-
+- CRQB_FLAG_READ = (1 << 0),
+- CRQB_TAG_SHIFT = 1,
+- CRQB_CMD_ADDR_SHIFT = 8,
+- CRQB_CMD_CS = (0x2 << 11),
+- CRQB_CMD_LAST = (1 << 15),
+-
+- CRPB_FLAG_STATUS_SHIFT = 8,
+-
+- EPRD_FLAG_END_OF_TBL = (1 << 31),
+-
+- /* PCI interface registers */
+-
+- PCI_COMMAND_OFS = 0xc00,
+-
+- PCI_MAIN_CMD_STS_OFS = 0xd30,
+- STOP_PCI_MASTER = (1 << 2),
+- PCI_MASTER_EMPTY = (1 << 3),
+- GLOB_SFT_RST = (1 << 4),
+-
+- MV_PCI_MODE = 0xd00,
+- MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
+- MV_PCI_DISC_TIMER = 0xd04,
+- MV_PCI_MSI_TRIGGER = 0xc38,
+- MV_PCI_SERR_MASK = 0xc28,
+- MV_PCI_XBAR_TMOUT = 0x1d04,
+- MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
+- MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
+- MV_PCI_ERR_ATTRIBUTE = 0x1d48,
+- MV_PCI_ERR_COMMAND = 0x1d50,
+-
+- PCI_IRQ_CAUSE_OFS = 0x1d58,
+- PCI_IRQ_MASK_OFS = 0x1d5c,
+- PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
+-
+- HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
+- HC_MAIN_IRQ_MASK_OFS = 0x1d64,
+- PORT0_ERR = (1 << 0), /* shift by port # */
+- PORT0_DONE = (1 << 1), /* shift by port # */
+- HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
+- HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
+- PCI_ERR = (1 << 18),
+- TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
+- TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
+- PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
+- GPIO_INT = (1 << 22),
+- SELF_INT = (1 << 23),
+- TWSI_INT = (1 << 24),
+- HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
+- HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
+- PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
+- HC_MAIN_RSVD),
+-
+- /* SATAHC registers */
+- HC_CFG_OFS = 0,
+-
+- HC_IRQ_CAUSE_OFS = 0x14,
+- CRPB_DMA_DONE = (1 << 0), /* shift by port # */
+- HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
+- DEV_IRQ = (1 << 8), /* shift by port # */
+-
+- /* Shadow block registers */
+- SHD_BLK_OFS = 0x100,
+- SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
+-
+- /* SATA registers */
+- SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
+- SATA_ACTIVE_OFS = 0x350,
+- PHY_MODE3 = 0x310,
+- PHY_MODE4 = 0x314,
+- PHY_MODE2 = 0x330,
+- MV5_PHY_MODE = 0x74,
+- MV5_LT_MODE = 0x30,
+- MV5_PHY_CTL = 0x0C,
+- SATA_INTERFACE_CTL = 0x050,
+-
+- MV_M2_PREAMP_MASK = 0x7e0,
+-
+- /* Port registers */
+- EDMA_CFG_OFS = 0,
+- EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */
+- EDMA_CFG_NCQ = (1 << 5),
+- EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
+- EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
+- EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
+-
+- EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
+- EDMA_ERR_IRQ_MASK_OFS = 0xc,
+- EDMA_ERR_D_PAR = (1 << 0),
+- EDMA_ERR_PRD_PAR = (1 << 1),
+- EDMA_ERR_DEV = (1 << 2),
+- EDMA_ERR_DEV_DCON = (1 << 3),
+- EDMA_ERR_DEV_CON = (1 << 4),
+- EDMA_ERR_SERR = (1 << 5),
+- EDMA_ERR_SELF_DIS = (1 << 7),
+- EDMA_ERR_BIST_ASYNC = (1 << 8),
+- EDMA_ERR_CRBQ_PAR = (1 << 9),
+- EDMA_ERR_CRPB_PAR = (1 << 10),
+- EDMA_ERR_INTRL_PAR = (1 << 11),
+- EDMA_ERR_IORDY = (1 << 12),
+- EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
+- EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
+- EDMA_ERR_LNK_DATA_RX = (0xf << 17),
+- EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
+- EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
+- EDMA_ERR_TRANS_PROTO = (1 << 31),
+- EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
+- EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
+- EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
+- EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
+- EDMA_ERR_LNK_DATA_RX |
+- EDMA_ERR_LNK_DATA_TX |
+- EDMA_ERR_TRANS_PROTO),
+-
+- EDMA_REQ_Q_BASE_HI_OFS = 0x10,
+- EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
+-
+- EDMA_REQ_Q_OUT_PTR_OFS = 0x18,
+- EDMA_REQ_Q_PTR_SHIFT = 5,
+-
+- EDMA_RSP_Q_BASE_HI_OFS = 0x1c,
+- EDMA_RSP_Q_IN_PTR_OFS = 0x20,
+- EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
+- EDMA_RSP_Q_PTR_SHIFT = 3,
+-
+- EDMA_CMD_OFS = 0x28,
+- EDMA_EN = (1 << 0),
+- EDMA_DS = (1 << 1),
+- ATA_RST = (1 << 2),
+-
+- EDMA_IORDY_TMOUT = 0x34,
+- EDMA_ARB_CFG = 0x38,
+-
+- /* Host private flags (hp_flags) */
+- MV_HP_FLAG_MSI = (1 << 0),
+- MV_HP_ERRATA_50XXB0 = (1 << 1),
+- MV_HP_ERRATA_50XXB2 = (1 << 2),
+- MV_HP_ERRATA_60X1B2 = (1 << 3),
+- MV_HP_ERRATA_60X1C0 = (1 << 4),
+- MV_HP_ERRATA_XX42A0 = (1 << 5),
+- MV_HP_50XX = (1 << 6),
+- MV_HP_GEN_IIE = (1 << 7),
+-
+- /* Port private flags (pp_flags) */
+- MV_PP_FLAG_EDMA_EN = (1 << 0),
+- MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
+-};
+-
+-#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
+-#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
+-#define IS_GEN_I(hpriv) IS_50XX(hpriv)
+-#define IS_GEN_II(hpriv) IS_60XX(hpriv)
+-#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
+-
+-enum {
+- /* Our DMA boundary is determined by an ePRD being unable to handle
+- * anything larger than 64KB
+- */
+- MV_DMA_BOUNDARY = 0xffffU,
+-
+- EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
+-
+- EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
+-};
+-
+-enum chip_type {
+- chip_504x,
+- chip_508x,
+- chip_5080,
+- chip_604x,
+- chip_608x,
+- chip_6042,
+- chip_7042,
+-};
+-
+-/* Command ReQuest Block: 32B */
+-struct mv_crqb {
+- __le32 sg_addr;
+- __le32 sg_addr_hi;
+- __le16 ctrl_flags;
+- __le16 ata_cmd[11];
+-};
+-
+-struct mv_crqb_iie {
+- __le32 addr;
+- __le32 addr_hi;
+- __le32 flags;
+- __le32 len;
+- __le32 ata_cmd[4];
+-};
+-
+-/* Command ResPonse Block: 8B */
+-struct mv_crpb {
+- __le16 id;
+- __le16 flags;
+- __le32 tmstmp;
+-};
+-
+-/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
+-struct mv_sg {
+- __le32 addr;
+- __le32 flags_size;
+- __le32 addr_hi;
+- __le32 reserved;
+-};
+-
+-struct mv_port_priv {
+- struct mv_crqb *crqb;
+- dma_addr_t crqb_dma;
+- struct mv_crpb *crpb;
+- dma_addr_t crpb_dma;
+- struct mv_sg *sg_tbl;
+- dma_addr_t sg_tbl_dma;
+- u32 pp_flags;
+-};
+-
+-struct mv_port_signal {
+- u32 amps;
+- u32 pre;
+-};
+-
+-struct mv_host_priv;
+-struct mv_hw_ops {
+- void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port);
+- void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
+- void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
+- void __iomem *mmio);
+- int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int n_hc);
+- void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
+- void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
+-};
+-
+-struct mv_host_priv {
+- u32 hp_flags;
+- struct mv_port_signal signal[8];
+- const struct mv_hw_ops *ops;
+-};
+-
+-static void mv_irq_clear(struct ata_port *ap);
+-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
+-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
+-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+-static void mv_phy_reset(struct ata_port *ap);
+-static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
+-static void mv_host_stop(struct ata_host_set *host_set);
+-static int mv_port_start(struct ata_port *ap);
+-static void mv_port_stop(struct ata_port *ap);
+-static void mv_qc_prep(struct ata_queued_cmd *qc);
+-static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+-static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
+-static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
+-static void mv_eng_timeout(struct ata_port *ap);
+-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+-
+-static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port);
+-static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
+-static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
+- void __iomem *mmio);
+-static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int n_hc);
+-static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
+-
+-static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port);
+-static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
+-static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
+- void __iomem *mmio);
+-static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int n_hc);
+-static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
+-static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port_no);
+-static void mv_stop_and_reset(struct ata_port *ap);
+-
+-static struct scsi_host_template mv_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = MV_USE_Q_DEPTH,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = MV_MAX_SG_CT / 2,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = MV_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations mv5_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .phy_reset = mv_phy_reset,
+-
+- .qc_prep = mv_qc_prep,
+- .qc_issue = mv_qc_issue,
+- .data_xfer = ata_mmio_data_xfer,
+-
+- .eng_timeout = mv_eng_timeout,
+-
+- .irq_handler = mv_interrupt,
+- .irq_clear = mv_irq_clear,
+-
+- .scr_read = mv5_scr_read,
+- .scr_write = mv5_scr_write,
+-
+- .port_start = mv_port_start,
+- .port_stop = mv_port_stop,
+- .host_stop = mv_host_stop,
+-};
+-
+-static const struct ata_port_operations mv6_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .phy_reset = mv_phy_reset,
+-
+- .qc_prep = mv_qc_prep,
+- .qc_issue = mv_qc_issue,
+- .data_xfer = ata_mmio_data_xfer,
+-
+- .eng_timeout = mv_eng_timeout,
+-
+- .irq_handler = mv_interrupt,
+- .irq_clear = mv_irq_clear,
+-
+- .scr_read = mv_scr_read,
+- .scr_write = mv_scr_write,
+-
+- .port_start = mv_port_start,
+- .port_stop = mv_port_stop,
+- .host_stop = mv_host_stop,
+-};
+-
+-static const struct ata_port_operations mv_iie_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .phy_reset = mv_phy_reset,
+-
+- .qc_prep = mv_qc_prep_iie,
+- .qc_issue = mv_qc_issue,
+-
+- .eng_timeout = mv_eng_timeout,
+-
+- .irq_handler = mv_interrupt,
+- .irq_clear = mv_irq_clear,
+-
+- .scr_read = mv_scr_read,
+- .scr_write = mv_scr_write,
+-
+- .port_start = mv_port_start,
+- .port_stop = mv_port_stop,
+- .host_stop = mv_host_stop,
+-};
+-
+-static const struct ata_port_info mv_port_info[] = {
+- { /* chip_504x */
+- .sht = &mv_sht,
+- .host_flags = MV_COMMON_FLAGS,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv5_ops,
+- },
+- { /* chip_508x */
+- .sht = &mv_sht,
+- .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv5_ops,
+- },
+- { /* chip_5080 */
+- .sht = &mv_sht,
+- .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv5_ops,
+- },
+- { /* chip_604x */
+- .sht = &mv_sht,
+- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv6_ops,
+- },
+- { /* chip_608x */
+- .sht = &mv_sht,
+- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+- MV_FLAG_DUAL_HC),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv6_ops,
+- },
+- { /* chip_6042 */
+- .sht = &mv_sht,
+- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv_iie_ops,
+- },
+- { /* chip_7042 */
+- .sht = &mv_sht,
+- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+- MV_FLAG_DUAL_HC),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &mv_iie_ops,
+- },
+-};
+-
+-static const struct pci_device_id mv_pci_tbl[] = {
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
+-
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
+- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+-
+- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
+- {} /* terminate list */
+-};
+-
+-static struct pci_driver mv_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = mv_pci_tbl,
+- .probe = mv_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static const struct mv_hw_ops mv5xxx_ops = {
+- .phy_errata = mv5_phy_errata,
+- .enable_leds = mv5_enable_leds,
+- .read_preamp = mv5_read_preamp,
+- .reset_hc = mv5_reset_hc,
+- .reset_flash = mv5_reset_flash,
+- .reset_bus = mv5_reset_bus,
+-};
+-
+-static const struct mv_hw_ops mv6xxx_ops = {
+- .phy_errata = mv6_phy_errata,
+- .enable_leds = mv6_enable_leds,
+- .read_preamp = mv6_read_preamp,
+- .reset_hc = mv6_reset_hc,
+- .reset_flash = mv6_reset_flash,
+- .reset_bus = mv_reset_pci_bus,
+-};
+-
+-/*
+- * module options
+- */
+-static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
+-
+-
+-/*
+- * Functions
+- */
+-
+-static inline void writelfl(unsigned long data, void __iomem *addr)
+-{
+- writel(data, addr);
+- (void) readl(addr); /* flush to avoid PCI posted write */
+-}
+-
+-static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
+-{
+- return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
+-}
+-
+-static inline unsigned int mv_hc_from_port(unsigned int port)
+-{
+- return port >> MV_PORT_HC_SHIFT;
+-}
+-
+-static inline unsigned int mv_hardport_from_port(unsigned int port)
+-{
+- return port & MV_PORT_MASK;
+-}
+-
+-static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
+- unsigned int port)
+-{
+- return mv_hc_base(base, mv_hc_from_port(port));
+-}
+-
+-static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
+-{
+- return mv_hc_base_from_port(base, port) +
+- MV_SATAHC_ARBTR_REG_SZ +
+- (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
+-}
+-
+-static inline void __iomem *mv_ap_base(struct ata_port *ap)
+-{
+- return mv_port_base(ap->host_set->mmio_base, ap->port_no);
+-}
+-
+-static inline int mv_get_hc_count(unsigned long host_flags)
+-{
+- return ((host_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
+-}
+-
+-static void mv_irq_clear(struct ata_port *ap)
+-{
+-}
+-
+-/**
+- * mv_start_dma - Enable eDMA engine
+- * @base: port base address
+- * @pp: port private data
+- *
+- * Verify the local cache of the eDMA state is accurate with a
+- * WARN_ON.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
+-{
+- if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
+- writelfl(EDMA_EN, base + EDMA_CMD_OFS);
+- pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
+- }
+- WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
+-}
+-
+-/**
+- * mv_stop_dma - Disable eDMA engine
+- * @ap: ATA channel to manipulate
+- *
+- * Verify the local cache of the eDMA state is accurate with a
+- * WARN_ON.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_stop_dma(struct ata_port *ap)
+-{
+- void __iomem *port_mmio = mv_ap_base(ap);
+- struct mv_port_priv *pp = ap->private_data;
+- u32 reg;
+- int i;
+-
+- if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
+- /* Disable EDMA if active. The disable bit auto clears.
+- */
+- writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+- } else {
+- WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
+- }
+-
+- /* now properly wait for the eDMA to stop */
+- for (i = 1000; i > 0; i--) {
+- reg = readl(port_mmio + EDMA_CMD_OFS);
+- if (!(EDMA_EN & reg)) {
+- break;
+- }
+- udelay(100);
+- }
+-
+- if (EDMA_EN & reg) {
+- ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
+- /* FIXME: Consider doing a reset here to recover */
+- }
+-}
+-
+-#ifdef ATA_DEBUG
+-static void mv_dump_mem(void __iomem *start, unsigned bytes)
+-{
+- int b, w;
+- for (b = 0; b < bytes; ) {
+- DPRINTK("%p: ", start + b);
+- for (w = 0; b < bytes && w < 4; w++) {
+- printk("%08x ",readl(start + b));
+- b += sizeof(u32);
+- }
+- printk("\n");
+- }
+-}
+-#endif
+-
+-static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
+-{
+-#ifdef ATA_DEBUG
+- int b, w;
+- u32 dw;
+- for (b = 0; b < bytes; ) {
+- DPRINTK("%02x: ", b);
+- for (w = 0; b < bytes && w < 4; w++) {
+- (void) pci_read_config_dword(pdev,b,&dw);
+- printk("%08x ",dw);
+- b += sizeof(u32);
+- }
+- printk("\n");
+- }
+-#endif
+-}
+-static void mv_dump_all_regs(void __iomem *mmio_base, int port,
+- struct pci_dev *pdev)
+-{
+-#ifdef ATA_DEBUG
+- void __iomem *hc_base = mv_hc_base(mmio_base,
+- port >> MV_PORT_HC_SHIFT);
+- void __iomem *port_base;
+- int start_port, num_ports, p, start_hc, num_hcs, hc;
+-
+- if (0 > port) {
+- start_hc = start_port = 0;
+- num_ports = 8; /* shld be benign for 4 port devs */
+- num_hcs = 2;
+- } else {
+- start_hc = port >> MV_PORT_HC_SHIFT;
+- start_port = port;
+- num_ports = num_hcs = 1;
+- }
+- DPRINTK("All registers for port(s) %u-%u:\n", start_port,
+- num_ports > 1 ? num_ports - 1 : start_port);
+-
+- if (NULL != pdev) {
+- DPRINTK("PCI config space regs:\n");
+- mv_dump_pci_cfg(pdev, 0x68);
+- }
+- DPRINTK("PCI regs:\n");
+- mv_dump_mem(mmio_base+0xc00, 0x3c);
+- mv_dump_mem(mmio_base+0xd00, 0x34);
+- mv_dump_mem(mmio_base+0xf00, 0x4);
+- mv_dump_mem(mmio_base+0x1d00, 0x6c);
+- for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
+- hc_base = mv_hc_base(mmio_base, hc);
+- DPRINTK("HC regs (HC %i):\n", hc);
+- mv_dump_mem(hc_base, 0x1c);
+- }
+- for (p = start_port; p < start_port + num_ports; p++) {
+- port_base = mv_port_base(mmio_base, p);
+- DPRINTK("EDMA regs (port %i):\n",p);
+- mv_dump_mem(port_base, 0x54);
+- DPRINTK("SATA regs (port %i):\n",p);
+- mv_dump_mem(port_base+0x300, 0x60);
+- }
+-#endif
+-}
+-
+-static unsigned int mv_scr_offset(unsigned int sc_reg_in)
+-{
+- unsigned int ofs;
+-
+- switch (sc_reg_in) {
+- case SCR_STATUS:
+- case SCR_CONTROL:
+- case SCR_ERROR:
+- ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
+- break;
+- case SCR_ACTIVE:
+- ofs = SATA_ACTIVE_OFS; /* active is not with the others */
+- break;
+- default:
+- ofs = 0xffffffffU;
+- break;
+- }
+- return ofs;
+-}
+-
+-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+-{
+- unsigned int ofs = mv_scr_offset(sc_reg_in);
+-
+- if (0xffffffffU != ofs) {
+- return readl(mv_ap_base(ap) + ofs);
+- } else {
+- return (u32) ofs;
+- }
+-}
+-
+-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+-{
+- unsigned int ofs = mv_scr_offset(sc_reg_in);
+-
+- if (0xffffffffU != ofs) {
+- writelfl(val, mv_ap_base(ap) + ofs);
+- }
+-}
+-
+-/**
+- * mv_host_stop - Host specific cleanup/stop routine.
+- * @host_set: host data structure
+- *
+- * Disable ints, cleanup host memory, call general purpose
+- * host_stop.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_host_stop(struct ata_host_set *host_set)
+-{
+- struct mv_host_priv *hpriv = host_set->private_data;
+- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+-
+- if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
+- pci_disable_msi(pdev);
+- } else {
+- pci_intx(pdev, 0);
+- }
+- kfree(hpriv);
+- ata_host_stop(host_set);
+-}
+-
+-static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
+-{
+- dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
+-}
+-
+-static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
+-{
+- u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+-
+- /* set up non-NCQ EDMA configuration */
+- cfg &= ~0x1f; /* clear queue depth */
+- cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */
+- cfg &= ~(1 << 9); /* disable equeue */
+-
+- if (IS_GEN_I(hpriv))
+- cfg |= (1 << 8); /* enab config burst size mask */
+-
+- else if (IS_GEN_II(hpriv))
+- cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+-
+- else if (IS_GEN_IIE(hpriv)) {
+- cfg |= (1 << 23); /* dis RX PM port mask */
+- cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
+- cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
+- cfg |= (1 << 18); /* enab early completion */
+- cfg |= (1 << 17); /* enab host q cache */
+- cfg |= (1 << 22); /* enab cutthrough */
+- }
+-
+- writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+-}
+-
+-/**
+- * mv_port_start - Port specific init/start routine.
+- * @ap: ATA channel to manipulate
+- *
+- * Allocate and point to DMA memory, init port private memory,
+- * zero indices.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static int mv_port_start(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct mv_host_priv *hpriv = ap->host_set->private_data;
+- struct mv_port_priv *pp;
+- void __iomem *port_mmio = mv_ap_base(ap);
+- void *mem;
+- dma_addr_t mem_dma;
+- int rc = -ENOMEM;
+-
+- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+- if (!pp)
+- goto err_out;
+- memset(pp, 0, sizeof(*pp));
+-
+- mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
+- GFP_KERNEL);
+- if (!mem)
+- goto err_out_pp;
+- memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
+-
+- rc = ata_pad_alloc(ap, dev);
+- if (rc)
+- goto err_out_priv;
+-
+- /* First item in chunk of DMA memory:
+- * 32-slot command request table (CRQB), 32 bytes each in size
+- */
+- pp->crqb = mem;
+- pp->crqb_dma = mem_dma;
+- mem += MV_CRQB_Q_SZ;
+- mem_dma += MV_CRQB_Q_SZ;
+-
+- /* Second item:
+- * 32-slot command response table (CRPB), 8 bytes each in size
+- */
+- pp->crpb = mem;
+- pp->crpb_dma = mem_dma;
+- mem += MV_CRPB_Q_SZ;
+- mem_dma += MV_CRPB_Q_SZ;
+-
+- /* Third item:
+- * Table of scatter-gather descriptors (ePRD), 16 bytes each
+- */
+- pp->sg_tbl = mem;
+- pp->sg_tbl_dma = mem_dma;
+-
+- mv_edma_cfg(hpriv, port_mmio);
+-
+- writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
+- writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
+- port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+-
+- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+- writelfl(pp->crqb_dma & 0xffffffff,
+- port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+- else
+- writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+-
+- writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+-
+- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+- writelfl(pp->crpb_dma & 0xffffffff,
+- port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+- else
+- writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+-
+- writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
+- port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+-
+- /* Don't turn on EDMA here...do it before DMA commands only. Else
+- * we'll be unable to send non-data, PIO, etc due to restricted access
+- * to shadow regs.
+- */
+- ap->private_data = pp;
+- return 0;
+-
+-err_out_priv:
+- mv_priv_free(pp, dev);
+-err_out_pp:
+- kfree(pp);
+-err_out:
+- return rc;
+-}
+-
+-/**
+- * mv_port_stop - Port specific cleanup/stop routine.
+- * @ap: ATA channel to manipulate
+- *
+- * Stop DMA, cleanup port memory.
+- *
+- * LOCKING:
+- * This routine uses the host_set lock to protect the DMA stop.
+- */
+-static void mv_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct mv_port_priv *pp = ap->private_data;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&ap->host_set->lock, flags);
+- mv_stop_dma(ap);
+- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+-
+- ap->private_data = NULL;
+- ata_pad_free(ap, dev);
+- mv_priv_free(pp, dev);
+- kfree(pp);
+-}
+-
+-/**
+- * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
+- * @qc: queued command whose SG list to source from
+- *
+- * Populate the SG list and mark the last entry.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_fill_sg(struct ata_queued_cmd *qc)
+-{
+- struct mv_port_priv *pp = qc->ap->private_data;
+- unsigned int i = 0;
+- struct scatterlist *sg;
+-
+- ata_for_each_sg(sg, qc) {
+- dma_addr_t addr;
+- u32 sg_len, len, offset;
+-
+- addr = sg_dma_address(sg);
+- sg_len = sg_dma_len(sg);
+-
+- while (sg_len) {
+- offset = addr & MV_DMA_BOUNDARY;
+- len = sg_len;
+- if ((offset + sg_len) > 0x10000)
+- len = 0x10000 - offset;
+-
+- pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
+- pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+- pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
+-
+- sg_len -= len;
+- addr += len;
+-
+- if (!sg_len && ata_sg_is_last(sg, qc))
+- pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+-
+- i++;
+- }
+- }
+-}
+-
+-static inline unsigned mv_inc_q_index(unsigned index)
+-{
+- return (index + 1) & MV_MAX_Q_DEPTH_MASK;
+-}
+-
+-static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
+-{
+- u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
+- (last ? CRQB_CMD_LAST : 0);
+- *cmdw = cpu_to_le16(tmp);
+-}
+-
+-/**
+- * mv_qc_prep - Host specific command preparation.
+- * @qc: queued command to prepare
+- *
+- * This routine simply redirects to the general purpose routine
+- * if command is not DMA. Else, it handles prep of the CRQB
+- * (command request block), does some sanity checking, and calls
+- * the SG load routine.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_qc_prep(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct mv_port_priv *pp = ap->private_data;
+- __le16 *cw;
+- struct ata_taskfile *tf;
+- u16 flags = 0;
+- unsigned in_index;
+-
+- if (ATA_PROT_DMA != qc->tf.protocol)
+- return;
+-
+- /* Fill in command request block
+- */
+- if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+- flags |= CRQB_FLAG_READ;
+- WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+- flags |= qc->tag << CRQB_TAG_SHIFT;
+-
+- /* get current queue index from hardware */
+- in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+-
+- pp->crqb[in_index].sg_addr =
+- cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+- pp->crqb[in_index].sg_addr_hi =
+- cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+- pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
+-
+- cw = &pp->crqb[in_index].ata_cmd[0];
+- tf = &qc->tf;
+-
+- /* Sadly, the CRQB cannot accomodate all registers--there are
+- * only 11 bytes...so we must pick and choose required
+- * registers based on the command. So, we drop feature and
+- * hob_feature for [RW] DMA commands, but they are needed for
+- * NCQ. NCQ will drop hob_nsect.
+- */
+- switch (tf->command) {
+- case ATA_CMD_READ:
+- case ATA_CMD_READ_EXT:
+- case ATA_CMD_WRITE:
+- case ATA_CMD_WRITE_EXT:
+- case ATA_CMD_WRITE_FUA_EXT:
+- mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
+- break;
+-#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */
+- case ATA_CMD_FPDMA_READ:
+- case ATA_CMD_FPDMA_WRITE:
+- mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
+- mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
+- break;
+-#endif /* FIXME: remove this line when NCQ added */
+- default:
+- /* The only other commands EDMA supports in non-queued and
+- * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
+- * of which are defined/used by Linux. If we get here, this
+- * driver needs work.
+- *
+- * FIXME: modify libata to give qc_prep a return value and
+- * return error here.
+- */
+- BUG_ON(tf->command);
+- break;
+- }
+- mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
+- mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
+- mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
+- mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
+- mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
+- mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
+- mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
+- mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
+- mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */
+-
+- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+- return;
+- mv_fill_sg(qc);
+-}
+-
+-/**
+- * mv_qc_prep_iie - Host specific command preparation.
+- * @qc: queued command to prepare
+- *
+- * This routine simply redirects to the general purpose routine
+- * if command is not DMA. Else, it handles prep of the CRQB
+- * (command request block), does some sanity checking, and calls
+- * the SG load routine.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct mv_port_priv *pp = ap->private_data;
+- struct mv_crqb_iie *crqb;
+- struct ata_taskfile *tf;
+- unsigned in_index;
+- u32 flags = 0;
+-
+- if (ATA_PROT_DMA != qc->tf.protocol)
+- return;
+-
+- /* Fill in Gen IIE command request block
+- */
+- if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+- flags |= CRQB_FLAG_READ;
+-
+- WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+- flags |= qc->tag << CRQB_TAG_SHIFT;
+-
+- /* get current queue index from hardware */
+- in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+-
+- crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
+- crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+- crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+- crqb->flags = cpu_to_le32(flags);
+-
+- tf = &qc->tf;
+- crqb->ata_cmd[0] = cpu_to_le32(
+- (tf->command << 16) |
+- (tf->feature << 24)
+- );
+- crqb->ata_cmd[1] = cpu_to_le32(
+- (tf->lbal << 0) |
+- (tf->lbam << 8) |
+- (tf->lbah << 16) |
+- (tf->device << 24)
+- );
+- crqb->ata_cmd[2] = cpu_to_le32(
+- (tf->hob_lbal << 0) |
+- (tf->hob_lbam << 8) |
+- (tf->hob_lbah << 16) |
+- (tf->hob_feature << 24)
+- );
+- crqb->ata_cmd[3] = cpu_to_le32(
+- (tf->nsect << 0) |
+- (tf->hob_nsect << 8)
+- );
+-
+- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+- return;
+- mv_fill_sg(qc);
+-}
+-
+-/**
+- * mv_qc_issue - Initiate a command to the host
+- * @qc: queued command to start
+- *
+- * This routine simply redirects to the general purpose routine
+- * if command is not DMA. Else, it sanity checks our local
+- * caches of the request producer/consumer indices then enables
+- * DMA and bumps the request producer index.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
+-{
+- void __iomem *port_mmio = mv_ap_base(qc->ap);
+- struct mv_port_priv *pp = qc->ap->private_data;
+- unsigned in_index;
+- u32 in_ptr;
+-
+- if (ATA_PROT_DMA != qc->tf.protocol) {
+- /* We're about to send a non-EDMA capable command to the
+- * port. Turn off EDMA so there won't be problems accessing
+- * shadow block, etc registers.
+- */
+- mv_stop_dma(qc->ap);
+- return ata_qc_issue_prot(qc);
+- }
+-
+- in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+- in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+-
+- /* until we do queuing, the queue should be empty at this point */
+- WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+-
+- in_index = mv_inc_q_index(in_index); /* now incr producer index */
+-
+- mv_start_dma(port_mmio, pp);
+-
+- /* and write the request in pointer to kick the EDMA to life */
+- in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
+- in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
+- writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+-
+- return 0;
+-}
+-
+-/**
+- * mv_get_crpb_status - get status from most recently completed cmd
+- * @ap: ATA channel to manipulate
+- *
+- * This routine is for use when the port is in DMA mode, when it
+- * will be using the CRPB (command response block) method of
+- * returning command completion information. We check indices
+- * are good, grab status, and bump the response consumer index to
+- * prove that we're up to date.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static u8 mv_get_crpb_status(struct ata_port *ap)
+-{
+- void __iomem *port_mmio = mv_ap_base(ap);
+- struct mv_port_priv *pp = ap->private_data;
+- unsigned out_index;
+- u32 out_ptr;
+- u8 ata_status;
+-
+- out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+- out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+-
+- ata_status = le16_to_cpu(pp->crpb[out_index].flags)
+- >> CRPB_FLAG_STATUS_SHIFT;
+-
+- /* increment our consumer index... */
+- out_index = mv_inc_q_index(out_index);
+-
+- /* and, until we do NCQ, there should only be 1 CRPB waiting */
+- WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
+- >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+-
+- /* write out our inc'd consumer index so EDMA knows we're caught up */
+- out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
+- out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
+- writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+-
+- /* Return ATA status register for completed CRPB */
+- return ata_status;
+-}
+-
+-/**
+- * mv_err_intr - Handle error interrupts on the port
+- * @ap: ATA channel to manipulate
+- * @reset_allowed: bool: 0 == don't trigger from reset here
+- *
+- * In most cases, just clear the interrupt and move on. However,
+- * some cases require an eDMA reset, which is done right before
+- * the COMRESET in mv_phy_reset(). The SERR case requires a
+- * clear of pending errors in the SATA SERROR register. Finally,
+- * if the port disabled DMA, update our cached copy to match.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_err_intr(struct ata_port *ap, int reset_allowed)
+-{
+- void __iomem *port_mmio = mv_ap_base(ap);
+- u32 edma_err_cause, serr = 0;
+-
+- edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+-
+- if (EDMA_ERR_SERR & edma_err_cause) {
+- sata_scr_read(ap, SCR_ERROR, &serr);
+- sata_scr_write_flush(ap, SCR_ERROR, serr);
+- }
+- if (EDMA_ERR_SELF_DIS & edma_err_cause) {
+- struct mv_port_priv *pp = ap->private_data;
+- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+- }
+- DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
+- "SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
+-
+- /* Clear EDMA now that SERR cleanup done */
+- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+-
+- /* check for fatal here and recover if needed */
+- if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
+- mv_stop_and_reset(ap);
+-}
+-
+-/**
+- * mv_host_intr - Handle all interrupts on the given host controller
+- * @host_set: host specific structure
+- * @relevant: port error bits relevant to this host controller
+- * @hc: which host controller we're to look at
+- *
+- * Read then write clear the HC interrupt status then walk each
+- * port connected to the HC and see if it needs servicing. Port
+- * success ints are reported in the HC interrupt status reg, the
+- * port error ints are reported in the higher level main
+- * interrupt status register and thus are passed in via the
+- * 'relevant' argument.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
+- unsigned int hc)
+-{
+- void __iomem *mmio = host_set->mmio_base;
+- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+- struct ata_queued_cmd *qc;
+- u32 hc_irq_cause;
+- int shift, port, port0, hard_port, handled;
+- unsigned int err_mask;
+-
+- if (hc == 0) {
+- port0 = 0;
+- } else {
+- port0 = MV_PORTS_PER_HC;
+- }
+-
+- /* we'll need the HC success int register in most cases */
+- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+- if (hc_irq_cause) {
+- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+- }
+-
+- VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
+- hc,relevant,hc_irq_cause);
+-
+- for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+- u8 ata_status = 0;
+- struct ata_port *ap = host_set->ports[port];
+- struct mv_port_priv *pp = ap->private_data;
+-
+- hard_port = mv_hardport_from_port(port); /* range 0..3 */
+- handled = 0; /* ensure ata_status is set if handled++ */
+-
+- /* Note that DEV_IRQ might happen spuriously during EDMA,
+- * and should be ignored in such cases.
+- * The cause of this is still under investigation.
+- */
+- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+- /* EDMA: check for response queue interrupt */
+- if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
+- ata_status = mv_get_crpb_status(ap);
+- handled = 1;
+- }
+- } else {
+- /* PIO: check for device (drive) interrupt */
+- if ((DEV_IRQ << hard_port) & hc_irq_cause) {
+- ata_status = readb((void __iomem *)
+- ap->ioaddr.status_addr);
+- handled = 1;
+- /* ignore spurious intr if drive still BUSY */
+- if (ata_status & ATA_BUSY) {
+- ata_status = 0;
+- handled = 0;
+- }
+- }
+- }
+-
+- if (ap && (ap->flags & ATA_FLAG_DISABLED))
+- continue;
+-
+- err_mask = ac_err_mask(ata_status);
+-
+- shift = port << 1; /* (port * 2) */
+- if (port >= MV_PORTS_PER_HC) {
+- shift++; /* skip bit 8 in the HC Main IRQ reg */
+- }
+- if ((PORT0_ERR << shift) & relevant) {
+- mv_err_intr(ap, 1);
+- err_mask |= AC_ERR_OTHER;
+- handled = 1;
+- }
+-
+- if (handled) {
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
+- VPRINTK("port %u IRQ found for qc, "
+- "ata_status 0x%x\n", port,ata_status);
+- /* mark qc status appropriately */
+- if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
+- qc->err_mask |= err_mask;
+- ata_qc_complete(qc);
+- }
+- }
+- }
+- }
+- VPRINTK("EXIT\n");
+-}
+-
+-/**
+- * mv_interrupt -
+- * @irq: unused
+- * @dev_instance: private data; in this case the host structure
+- * @regs: unused
+- *
+- * Read the read only register to determine if any host
+- * controllers have pending interrupts. If so, call lower level
+- * routine to handle. Also check for PCI errors which are only
+- * reported here.
+- *
+- * LOCKING:
+- * This routine holds the host_set lock while processing pending
+- * interrupts.
+- */
+-static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- unsigned int hc, handled = 0, n_hcs;
+- void __iomem *mmio = host_set->mmio_base;
+- struct mv_host_priv *hpriv;
+- u32 irq_stat;
+-
+- irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
+-
+- /* check the cases where we either have nothing pending or have read
+- * a bogus register value which can indicate HW removal or PCI fault
+- */
+- if (!irq_stat || (0xffffffffU == irq_stat)) {
+- return IRQ_NONE;
+- }
+-
+- n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
+- spin_lock(&host_set->lock);
+-
+- for (hc = 0; hc < n_hcs; hc++) {
+- u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
+- if (relevant) {
+- mv_host_intr(host_set, relevant, hc);
+- handled++;
+- }
+- }
+-
+- hpriv = host_set->private_data;
+- if (IS_60XX(hpriv)) {
+- /* deal with the interrupt coalescing bits */
+- if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
+- writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
+- writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
+- writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
+- }
+- }
+-
+- if (PCI_ERR & irq_stat) {
+- printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
+- readl(mmio + PCI_IRQ_CAUSE_OFS));
+-
+- DPRINTK("All regs @ PCI error\n");
+- mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev));
+-
+- writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+- handled++;
+- }
+- spin_unlock(&host_set->lock);
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
+-{
+- void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
+- unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
+-
+- return hc_mmio + ofs;
+-}
+-
+-static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
+-{
+- unsigned int ofs;
+-
+- switch (sc_reg_in) {
+- case SCR_STATUS:
+- case SCR_ERROR:
+- case SCR_CONTROL:
+- ofs = sc_reg_in * sizeof(u32);
+- break;
+- default:
+- ofs = 0xffffffffU;
+- break;
+- }
+- return ofs;
+-}
+-
+-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+-{
+- void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
+- unsigned int ofs = mv5_scr_offset(sc_reg_in);
+-
+- if (ofs != 0xffffffffU)
+- return readl(mmio + ofs);
+- else
+- return (u32) ofs;
+-}
+-
+-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+-{
+- void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
+- unsigned int ofs = mv5_scr_offset(sc_reg_in);
+-
+- if (ofs != 0xffffffffU)
+- writelfl(val, mmio + ofs);
+-}
+-
+-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
+-{
+- u8 rev_id;
+- int early_5080;
+-
+- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+-
+- early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
+-
+- if (!early_5080) {
+- u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
+- tmp |= (1 << 0);
+- writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
+- }
+-
+- mv_reset_pci_bus(pdev, mmio);
+-}
+-
+-static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
+-{
+- writel(0x0fcfffff, mmio + MV_FLASH_CTL);
+-}
+-
+-static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
+- void __iomem *mmio)
+-{
+- void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
+- u32 tmp;
+-
+- tmp = readl(phy_mmio + MV5_PHY_MODE);
+-
+- hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */
+- hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */
+-}
+-
+-static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
+-{
+- u32 tmp;
+-
+- writel(0, mmio + MV_GPIO_PORT_CTL);
+-
+- /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
+-
+- tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
+- tmp |= ~(1 << 0);
+- writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
+-}
+-
+-static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port)
+-{
+- void __iomem *phy_mmio = mv5_phy_base(mmio, port);
+- const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
+- u32 tmp;
+- int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
+-
+- if (fix_apm_sq) {
+- tmp = readl(phy_mmio + MV5_LT_MODE);
+- tmp |= (1 << 19);
+- writel(tmp, phy_mmio + MV5_LT_MODE);
+-
+- tmp = readl(phy_mmio + MV5_PHY_CTL);
+- tmp &= ~0x3;
+- tmp |= 0x1;
+- writel(tmp, phy_mmio + MV5_PHY_CTL);
+- }
+-
+- tmp = readl(phy_mmio + MV5_PHY_MODE);
+- tmp &= ~mask;
+- tmp |= hpriv->signal[port].pre;
+- tmp |= hpriv->signal[port].amps;
+- writel(tmp, phy_mmio + MV5_PHY_MODE);
+-}
+-
+-
+-#undef ZERO
+-#define ZERO(reg) writel(0, port_mmio + (reg))
+-static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port)
+-{
+- void __iomem *port_mmio = mv_port_base(mmio, port);
+-
+- writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+-
+- mv_channel_reset(hpriv, mmio, port);
+-
+- ZERO(0x028); /* command */
+- writel(0x11f, port_mmio + EDMA_CFG_OFS);
+- ZERO(0x004); /* timer */
+- ZERO(0x008); /* irq err cause */
+- ZERO(0x00c); /* irq err mask */
+- ZERO(0x010); /* rq bah */
+- ZERO(0x014); /* rq inp */
+- ZERO(0x018); /* rq outp */
+- ZERO(0x01c); /* respq bah */
+- ZERO(0x024); /* respq outp */
+- ZERO(0x020); /* respq inp */
+- ZERO(0x02c); /* test control */
+- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+-}
+-#undef ZERO
+-
+-#define ZERO(reg) writel(0, hc_mmio + (reg))
+-static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int hc)
+-{
+- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+- u32 tmp;
+-
+- ZERO(0x00c);
+- ZERO(0x010);
+- ZERO(0x014);
+- ZERO(0x018);
+-
+- tmp = readl(hc_mmio + 0x20);
+- tmp &= 0x1c1c1c1c;
+- tmp |= 0x03030303;
+- writel(tmp, hc_mmio + 0x20);
+-}
+-#undef ZERO
+-
+-static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int n_hc)
+-{
+- unsigned int hc, port;
+-
+- for (hc = 0; hc < n_hc; hc++) {
+- for (port = 0; port < MV_PORTS_PER_HC; port++)
+- mv5_reset_hc_port(hpriv, mmio,
+- (hc * MV_PORTS_PER_HC) + port);
+-
+- mv5_reset_one_hc(hpriv, mmio, hc);
+- }
+-
+- return 0;
+-}
+-
+-#undef ZERO
+-#define ZERO(reg) writel(0, mmio + (reg))
+-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
+-{
+- u32 tmp;
+-
+- tmp = readl(mmio + MV_PCI_MODE);
+- tmp &= 0xff00ffff;
+- writel(tmp, mmio + MV_PCI_MODE);
+-
+- ZERO(MV_PCI_DISC_TIMER);
+- ZERO(MV_PCI_MSI_TRIGGER);
+- writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
+- ZERO(HC_MAIN_IRQ_MASK_OFS);
+- ZERO(MV_PCI_SERR_MASK);
+- ZERO(PCI_IRQ_CAUSE_OFS);
+- ZERO(PCI_IRQ_MASK_OFS);
+- ZERO(MV_PCI_ERR_LOW_ADDRESS);
+- ZERO(MV_PCI_ERR_HIGH_ADDRESS);
+- ZERO(MV_PCI_ERR_ATTRIBUTE);
+- ZERO(MV_PCI_ERR_COMMAND);
+-}
+-#undef ZERO
+-
+-static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
+-{
+- u32 tmp;
+-
+- mv5_reset_flash(hpriv, mmio);
+-
+- tmp = readl(mmio + MV_GPIO_PORT_CTL);
+- tmp &= 0x3;
+- tmp |= (1 << 5) | (1 << 6);
+- writel(tmp, mmio + MV_GPIO_PORT_CTL);
+-}
+-
+-/**
+- * mv6_reset_hc - Perform the 6xxx global soft reset
+- * @mmio: base address of the HBA
+- *
+- * This routine only applies to 6xxx parts.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int n_hc)
+-{
+- void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
+- int i, rc = 0;
+- u32 t;
+-
+- /* Following procedure defined in PCI "main command and status
+- * register" table.
+- */
+- t = readl(reg);
+- writel(t | STOP_PCI_MASTER, reg);
+-
+- for (i = 0; i < 1000; i++) {
+- udelay(1);
+- t = readl(reg);
+- if (PCI_MASTER_EMPTY & t) {
+- break;
+- }
+- }
+- if (!(PCI_MASTER_EMPTY & t)) {
+- printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
+- rc = 1;
+- goto done;
+- }
+-
+- /* set reset */
+- i = 5;
+- do {
+- writel(t | GLOB_SFT_RST, reg);
+- t = readl(reg);
+- udelay(1);
+- } while (!(GLOB_SFT_RST & t) && (i-- > 0));
+-
+- if (!(GLOB_SFT_RST & t)) {
+- printk(KERN_ERR DRV_NAME ": can't set global reset\n");
+- rc = 1;
+- goto done;
+- }
+-
+- /* clear reset and *reenable the PCI master* (not mentioned in spec) */
+- i = 5;
+- do {
+- writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
+- t = readl(reg);
+- udelay(1);
+- } while ((GLOB_SFT_RST & t) && (i-- > 0));
+-
+- if (GLOB_SFT_RST & t) {
+- printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
+- rc = 1;
+- }
+-done:
+- return rc;
+-}
+-
+-static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
+- void __iomem *mmio)
+-{
+- void __iomem *port_mmio;
+- u32 tmp;
+-
+- tmp = readl(mmio + MV_RESET_CFG);
+- if ((tmp & (1 << 0)) == 0) {
+- hpriv->signal[idx].amps = 0x7 << 8;
+- hpriv->signal[idx].pre = 0x1 << 5;
+- return;
+- }
+-
+- port_mmio = mv_port_base(mmio, idx);
+- tmp = readl(port_mmio + PHY_MODE2);
+-
+- hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */
+- hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */
+-}
+-
+-static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
+-{
+- writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
+-}
+-
+-static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port)
+-{
+- void __iomem *port_mmio = mv_port_base(mmio, port);
+-
+- u32 hp_flags = hpriv->hp_flags;
+- int fix_phy_mode2 =
+- hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
+- int fix_phy_mode4 =
+- hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
+- u32 m2, tmp;
+-
+- if (fix_phy_mode2) {
+- m2 = readl(port_mmio + PHY_MODE2);
+- m2 &= ~(1 << 16);
+- m2 |= (1 << 31);
+- writel(m2, port_mmio + PHY_MODE2);
+-
+- udelay(200);
+-
+- m2 = readl(port_mmio + PHY_MODE2);
+- m2 &= ~((1 << 16) | (1 << 31));
+- writel(m2, port_mmio + PHY_MODE2);
+-
+- udelay(200);
+- }
+-
+- /* who knows what this magic does */
+- tmp = readl(port_mmio + PHY_MODE3);
+- tmp &= ~0x7F800000;
+- tmp |= 0x2A800000;
+- writel(tmp, port_mmio + PHY_MODE3);
+-
+- if (fix_phy_mode4) {
+- u32 m4;
+-
+- m4 = readl(port_mmio + PHY_MODE4);
+-
+- if (hp_flags & MV_HP_ERRATA_60X1B2)
+- tmp = readl(port_mmio + 0x310);
+-
+- m4 = (m4 & ~(1 << 1)) | (1 << 0);
+-
+- writel(m4, port_mmio + PHY_MODE4);
+-
+- if (hp_flags & MV_HP_ERRATA_60X1B2)
+- writel(tmp, port_mmio + 0x310);
+- }
+-
+- /* Revert values of pre-emphasis and signal amps to the saved ones */
+- m2 = readl(port_mmio + PHY_MODE2);
+-
+- m2 &= ~MV_M2_PREAMP_MASK;
+- m2 |= hpriv->signal[port].amps;
+- m2 |= hpriv->signal[port].pre;
+- m2 &= ~(1 << 16);
+-
+- /* according to mvSata 3.6.1, some IIE values are fixed */
+- if (IS_GEN_IIE(hpriv)) {
+- m2 &= ~0xC30FF01F;
+- m2 |= 0x0000900F;
+- }
+-
+- writel(m2, port_mmio + PHY_MODE2);
+-}
+-
+-static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
+- unsigned int port_no)
+-{
+- void __iomem *port_mmio = mv_port_base(mmio, port_no);
+-
+- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+-
+- if (IS_60XX(hpriv)) {
+- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
+- ifctl |= (1 << 7); /* enable gen2i speed */
+- ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
+- writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
+- }
+-
+- udelay(25); /* allow reset propagation */
+-
+- /* Spec never mentions clearing the bit. Marvell's driver does
+- * clear the bit, however.
+- */
+- writelfl(0, port_mmio + EDMA_CMD_OFS);
+-
+- hpriv->ops->phy_errata(hpriv, mmio, port_no);
+-
+- if (IS_50XX(hpriv))
+- mdelay(1);
+-}
+-
+-static void mv_stop_and_reset(struct ata_port *ap)
+-{
+- struct mv_host_priv *hpriv = ap->host_set->private_data;
+- void __iomem *mmio = ap->host_set->mmio_base;
+-
+- mv_stop_dma(ap);
+-
+- mv_channel_reset(hpriv, mmio, ap->port_no);
+-
+- __mv_phy_reset(ap, 0);
+-}
+-
+-static inline void __msleep(unsigned int msec, int can_sleep)
+-{
+- if (can_sleep)
+- msleep(msec);
+- else
+- mdelay(msec);
+-}
+-
+-/**
+- * __mv_phy_reset - Perform eDMA reset followed by COMRESET
+- * @ap: ATA channel to manipulate
+- *
+- * Part of this is taken from __sata_phy_reset and modified to
+- * not sleep since this routine gets called from interrupt level.
+- *
+- * LOCKING:
+- * Inherited from caller. This is coded to safe to call at
+- * interrupt level, i.e. it does not sleep.
+- */
+-static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
+-{
+- struct mv_port_priv *pp = ap->private_data;
+- struct mv_host_priv *hpriv = ap->host_set->private_data;
+- void __iomem *port_mmio = mv_ap_base(ap);
+- struct ata_taskfile tf;
+- struct ata_device *dev = &ap->device[0];
+- unsigned long timeout;
+- int retry = 5;
+- u32 sstatus;
+-
+- VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
+-
+- DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
+- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+-
+- /* Issue COMRESET via SControl */
+-comreset_retry:
+- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+- __msleep(1, can_sleep);
+-
+- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+- __msleep(20, can_sleep);
+-
+- timeout = jiffies + msecs_to_jiffies(200);
+- do {
+- sata_scr_read(ap, SCR_STATUS, &sstatus);
+- if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
+- break;
+-
+- __msleep(1, can_sleep);
+- } while (time_before(jiffies, timeout));
+-
+- /* work around errata */
+- if (IS_60XX(hpriv) &&
+- (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
+- (retry-- > 0))
+- goto comreset_retry;
+-
+- DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
+- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+-
+- if (ata_port_online(ap)) {
+- ata_port_probe(ap);
+- } else {
+- sata_scr_read(ap, SCR_STATUS, &sstatus);
+- ata_port_printk(ap, KERN_INFO,
+- "no device found (phy stat %08x)\n", sstatus);
+- ata_port_disable(ap);
+- return;
+- }
+- ap->cbl = ATA_CBL_SATA;
+-
+- /* even after SStatus reflects that device is ready,
+- * it seems to take a while for link to be fully
+- * established (and thus Status no longer 0x80/0x7F),
+- * so we poll a bit for that, here.
+- */
+- retry = 20;
+- while (1) {
+- u8 drv_stat = ata_check_status(ap);
+- if ((drv_stat != 0x80) && (drv_stat != 0x7f))
+- break;
+- __msleep(500, can_sleep);
+- if (retry-- <= 0)
+- break;
+- }
+-
+- tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
+- tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
+- tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
+- tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
+-
+- dev->class = ata_dev_classify(&tf);
+- if (!ata_dev_enabled(dev)) {
+- VPRINTK("Port disabled post-sig: No device present.\n");
+- ata_port_disable(ap);
+- }
+-
+- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+-
+- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+-
+- VPRINTK("EXIT\n");
+-}
+-
+-static void mv_phy_reset(struct ata_port *ap)
+-{
+- __mv_phy_reset(ap, 1);
+-}
+-
+-/**
+- * mv_eng_timeout - Routine called by libata when SCSI times out I/O
+- * @ap: ATA channel to manipulate
+- *
+- * Intent is to clear all pending error conditions, reset the
+- * chip/bus, fail the command, and move on.
+- *
+- * LOCKING:
+- * This routine holds the host_set lock while failing the command.
+- */
+-static void mv_eng_timeout(struct ata_port *ap)
+-{
+- struct ata_queued_cmd *qc;
+- unsigned long flags;
+-
+- ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
+- DPRINTK("All regs @ start of eng_timeout\n");
+- mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no,
+- to_pci_dev(ap->host_set->dev));
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
+- ap->host_set->mmio_base, ap, qc, qc->scsicmd,
+- &qc->scsicmd->cmnd);
+-
+- spin_lock_irqsave(&ap->host_set->lock, flags);
+- mv_err_intr(ap, 0);
+- mv_stop_and_reset(ap);
+- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+-
+- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+- if (qc->flags & ATA_QCFLAG_ACTIVE) {
+- qc->err_mask |= AC_ERR_TIMEOUT;
+- ata_eh_qc_complete(qc);
+- }
+-}
+-
+-/**
+- * mv_port_init - Perform some early initialization on a single port.
+- * @port: libata data structure storing shadow register addresses
+- * @port_mmio: base address of the port
+- *
+- * Initialize shadow register mmio addresses, clear outstanding
+- * interrupts on the port, and unmask interrupts for the future
+- * start of the port.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
+-{
+- unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
+- unsigned serr_ofs;
+-
+- /* PIO related setup
+- */
+- port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
+- port->error_addr =
+- port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
+- port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
+- port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
+- port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
+- port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
+- port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
+- port->status_addr =
+- port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
+- /* special case: control/altstatus doesn't have ATA_REG_ address */
+- port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
+-
+- /* unused: */
+- port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+-
+- /* Clear any currently outstanding port interrupt conditions */
+- serr_ofs = mv_scr_offset(SCR_ERROR);
+- writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
+- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+-
+- /* unmask all EDMA error interrupts */
+- writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+-
+- VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
+- readl(port_mmio + EDMA_CFG_OFS),
+- readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
+- readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
+-}
+-
+-static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
+- unsigned int board_idx)
+-{
+- u8 rev_id;
+- u32 hp_flags = hpriv->hp_flags;
+-
+- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+-
+- switch(board_idx) {
+- case chip_5080:
+- hpriv->ops = &mv5xxx_ops;
+- hp_flags |= MV_HP_50XX;
+-
+- switch (rev_id) {
+- case 0x1:
+- hp_flags |= MV_HP_ERRATA_50XXB0;
+- break;
+- case 0x3:
+- hp_flags |= MV_HP_ERRATA_50XXB2;
+- break;
+- default:
+- dev_printk(KERN_WARNING, &pdev->dev,
+- "Applying 50XXB2 workarounds to unknown rev\n");
+- hp_flags |= MV_HP_ERRATA_50XXB2;
+- break;
+- }
+- break;
+-
+- case chip_504x:
+- case chip_508x:
+- hpriv->ops = &mv5xxx_ops;
+- hp_flags |= MV_HP_50XX;
+-
+- switch (rev_id) {
+- case 0x0:
+- hp_flags |= MV_HP_ERRATA_50XXB0;
+- break;
+- case 0x3:
+- hp_flags |= MV_HP_ERRATA_50XXB2;
+- break;
+- default:
+- dev_printk(KERN_WARNING, &pdev->dev,
+- "Applying B2 workarounds to unknown rev\n");
+- hp_flags |= MV_HP_ERRATA_50XXB2;
+- break;
+- }
+- break;
+-
+- case chip_604x:
+- case chip_608x:
+- hpriv->ops = &mv6xxx_ops;
+-
+- switch (rev_id) {
+- case 0x7:
+- hp_flags |= MV_HP_ERRATA_60X1B2;
+- break;
+- case 0x9:
+- hp_flags |= MV_HP_ERRATA_60X1C0;
+- break;
+- default:
+- dev_printk(KERN_WARNING, &pdev->dev,
+- "Applying B2 workarounds to unknown rev\n");
+- hp_flags |= MV_HP_ERRATA_60X1B2;
+- break;
+- }
+- break;
+-
+- case chip_7042:
+- case chip_6042:
+- hpriv->ops = &mv6xxx_ops;
+-
+- hp_flags |= MV_HP_GEN_IIE;
+-
+- switch (rev_id) {
+- case 0x0:
+- hp_flags |= MV_HP_ERRATA_XX42A0;
+- break;
+- case 0x1:
+- hp_flags |= MV_HP_ERRATA_60X1C0;
+- break;
+- default:
+- dev_printk(KERN_WARNING, &pdev->dev,
+- "Applying 60X1C0 workarounds to unknown rev\n");
+- hp_flags |= MV_HP_ERRATA_60X1C0;
+- break;
+- }
+- break;
+-
+- default:
+- printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
+- return 1;
+- }
+-
+- hpriv->hp_flags = hp_flags;
+-
+- return 0;
+-}
+-
+-/**
+- * mv_init_host - Perform some early initialization of the host.
+- * @pdev: host PCI device
+- * @probe_ent: early data struct representing the host
+- *
+- * If possible, do an early global reset of the host. Then do
+- * our port init and clear/unmask all/relevant host interrupts.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
+- unsigned int board_idx)
+-{
+- int rc = 0, n_hc, port, hc;
+- void __iomem *mmio = probe_ent->mmio_base;
+- struct mv_host_priv *hpriv = probe_ent->private_data;
+-
+- /* global interrupt mask */
+- writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
+-
+- rc = mv_chip_id(pdev, hpriv, board_idx);
+- if (rc)
+- goto done;
+-
+- n_hc = mv_get_hc_count(probe_ent->host_flags);
+- probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+-
+- for (port = 0; port < probe_ent->n_ports; port++)
+- hpriv->ops->read_preamp(hpriv, port, mmio);
+-
+- rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
+- if (rc)
+- goto done;
+-
+- hpriv->ops->reset_flash(hpriv, mmio);
+- hpriv->ops->reset_bus(pdev, mmio);
+- hpriv->ops->enable_leds(hpriv, mmio);
+-
+- for (port = 0; port < probe_ent->n_ports; port++) {
+- if (IS_60XX(hpriv)) {
+- void __iomem *port_mmio = mv_port_base(mmio, port);
+-
+- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
+- ifctl |= (1 << 7); /* enable gen2i speed */
+- ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
+- writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
+- }
+-
+- hpriv->ops->phy_errata(hpriv, mmio, port);
+- }
+-
+- for (port = 0; port < probe_ent->n_ports; port++) {
+- void __iomem *port_mmio = mv_port_base(mmio, port);
+- mv_port_init(&probe_ent->port[port], port_mmio);
+- }
+-
+- for (hc = 0; hc < n_hc; hc++) {
+- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+-
+- VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
+- "(before clear)=0x%08x\n", hc,
+- readl(hc_mmio + HC_CFG_OFS),
+- readl(hc_mmio + HC_IRQ_CAUSE_OFS));
+-
+- /* Clear any currently outstanding hc interrupt conditions */
+- writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
+- }
+-
+- /* Clear any currently outstanding host interrupt conditions */
+- writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+-
+- /* and unmask interrupt generation for host regs */
+- writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
+- writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+-
+- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+- "PCI int cause/mask=0x%08x/0x%08x\n",
+- readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
+- readl(mmio + HC_MAIN_IRQ_MASK_OFS),
+- readl(mmio + PCI_IRQ_CAUSE_OFS),
+- readl(mmio + PCI_IRQ_MASK_OFS));
+-
+-done:
+- return rc;
+-}
+-
+-/**
+- * mv_print_info - Dump key info to kernel log for perusal.
+- * @probe_ent: early data struct representing the host
+- *
+- * FIXME: complete this.
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static void mv_print_info(struct ata_probe_ent *probe_ent)
+-{
+- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+- struct mv_host_priv *hpriv = probe_ent->private_data;
+- u8 rev_id, scc;
+- const char *scc_s;
+-
+- /* Use this to determine the HW stepping of the chip so we know
+- * what errata to workaround
+- */
+- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+-
+- pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
+- if (scc == 0)
+- scc_s = "SCSI";
+- else if (scc == 0x01)
+- scc_s = "RAID";
+- else
+- scc_s = "unknown";
+-
+- dev_printk(KERN_INFO, &pdev->dev,
+- "%u slots %u ports %s mode IRQ via %s\n",
+- (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
+- scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
+-}
+-
+-/**
+- * mv_init_one - handle a positive probe of a Marvell host
+- * @pdev: PCI device found
+- * @ent: PCI device ID entry for the matched host
+- *
+- * LOCKING:
+- * Inherited from caller.
+- */
+-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version = 0;
+- struct ata_probe_ent *probe_ent = NULL;
+- struct mv_host_priv *hpriv;
+- unsigned int board_idx = (unsigned int)ent->driver_data;
+- void __iomem *mmio_base;
+- int pci_dev_busy = 0, rc;
+-
+- if (!printed_version++)
+- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc) {
+- return rc;
+- }
+- pci_set_master(pdev);
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+-
+- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv) {
+- rc = -ENOMEM;
+- goto err_out_iounmap;
+- }
+- memset(hpriv, 0, sizeof(*hpriv));
+-
+- probe_ent->sht = mv_port_info[board_idx].sht;
+- probe_ent->host_flags = mv_port_info[board_idx].host_flags;
+- probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
+- probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
+- probe_ent->port_ops = mv_port_info[board_idx].port_ops;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+- probe_ent->private_data = hpriv;
+-
+- /* initialize adapter */
+- rc = mv_init_host(pdev, probe_ent, board_idx);
+- if (rc) {
+- goto err_out_hpriv;
+- }
+-
+- /* Enable interrupts */
+- if (msi && pci_enable_msi(pdev) == 0) {
+- hpriv->hp_flags |= MV_HP_FLAG_MSI;
+- } else {
+- pci_intx(pdev, 1);
+- }
+-
+- mv_dump_pci_cfg(pdev, 0x68);
+- mv_print_info(probe_ent);
+-
+- if (ata_device_add(probe_ent) == 0) {
+- rc = -ENODEV; /* No devices discovered */
+- goto err_out_dev_add;
+- }
+-
+- kfree(probe_ent);
+- return 0;
+-
+-err_out_dev_add:
+- if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
+- pci_disable_msi(pdev);
+- } else {
+- pci_intx(pdev, 0);
+- }
+-err_out_hpriv:
+- kfree(hpriv);
+-err_out_iounmap:
+- pci_iounmap(pdev, mmio_base);
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy) {
+- pci_disable_device(pdev);
+- }
+-
+- return rc;
+-}
+-
+-static int __init mv_init(void)
+-{
+- return pci_module_init(&mv_pci_driver);
+-}
+-
+-static void __exit mv_exit(void)
+-{
+- pci_unregister_driver(&mv_pci_driver);
+-}
+-
+-MODULE_AUTHOR("Brett Russ");
+-MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_param(msi, int, 0444);
+-MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+-
+-module_init(mv_init);
+-module_exit(mv_exit);
+diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
+deleted file mode 100644
+index 56da255..0000000
+--- a/drivers/scsi/sata_nv.c
++++ /dev/null
+@@ -1,595 +0,0 @@
+-/*
+- * sata_nv.c - NVIDIA nForce SATA
+- *
+- * Copyright 2004 NVIDIA Corp. All rights reserved.
+- * Copyright 2004 Andrew Chew
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * No hardware documentation available outside of NVIDIA.
+- * This driver programs the NVIDIA SATA controller in a similar
+- * fashion as with other PCI IDE BMDMA controllers, with a few
+- * NV-specific details such as register offsets, SATA phy location,
+- * hotplug info, etc.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "sata_nv"
+-#define DRV_VERSION "2.0"
+-
+-enum {
+- NV_PORTS = 2,
+- NV_PIO_MASK = 0x1f,
+- NV_MWDMA_MASK = 0x07,
+- NV_UDMA_MASK = 0x7f,
+- NV_PORT0_SCR_REG_OFFSET = 0x00,
+- NV_PORT1_SCR_REG_OFFSET = 0x40,
+-
+- /* INT_STATUS/ENABLE */
+- NV_INT_STATUS = 0x10,
+- NV_INT_ENABLE = 0x11,
+- NV_INT_STATUS_CK804 = 0x440,
+- NV_INT_ENABLE_CK804 = 0x441,
+-
+- /* INT_STATUS/ENABLE bits */
+- NV_INT_DEV = 0x01,
+- NV_INT_PM = 0x02,
+- NV_INT_ADDED = 0x04,
+- NV_INT_REMOVED = 0x08,
+-
+- NV_INT_PORT_SHIFT = 4, /* each port occupies 4 bits */
+-
+- NV_INT_ALL = 0x0f,
+- NV_INT_MASK = NV_INT_DEV |
+- NV_INT_ADDED | NV_INT_REMOVED,
+-
+- /* INT_CONFIG */
+- NV_INT_CONFIG = 0x12,
+- NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI
+-
+- // For PCI config register 20
+- NV_MCP_SATA_CFG_20 = 0x50,
+- NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04,
+-};
+-
+-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static void nv_ck804_host_stop(struct ata_host_set *host_set);
+-static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
+-static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
+-static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
+-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-
+-static void nv_nf2_freeze(struct ata_port *ap);
+-static void nv_nf2_thaw(struct ata_port *ap);
+-static void nv_ck804_freeze(struct ata_port *ap);
+-static void nv_ck804_thaw(struct ata_port *ap);
+-static void nv_error_handler(struct ata_port *ap);
+-
+-enum nv_host_type
+-{
+- GENERIC,
+- NFORCE2,
+- NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
+- CK804
+-};
+-
+-static const struct pci_device_id nv_pci_tbl[] = {
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+- PCI_ANY_ID, PCI_ANY_ID,
+- PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
+- { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+- PCI_ANY_ID, PCI_ANY_ID,
+- PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
+- { 0, } /* terminate list */
+-};
+-
+-static struct pci_driver nv_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = nv_pci_tbl,
+- .probe = nv_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static struct scsi_host_template nv_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations nv_generic_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .exec_command = ata_exec_command,
+- .check_status = ata_check_status,
+- .dev_select = ata_std_dev_select,
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = nv_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .data_xfer = ata_pio_data_xfer,
+- .irq_handler = nv_generic_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = nv_scr_read,
+- .scr_write = nv_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_pci_host_stop,
+-};
+-
+-static const struct ata_port_operations nv_nf2_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .exec_command = ata_exec_command,
+- .check_status = ata_check_status,
+- .dev_select = ata_std_dev_select,
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .freeze = nv_nf2_freeze,
+- .thaw = nv_nf2_thaw,
+- .error_handler = nv_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .data_xfer = ata_pio_data_xfer,
+- .irq_handler = nv_nf2_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = nv_scr_read,
+- .scr_write = nv_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_pci_host_stop,
+-};
+-
+-static const struct ata_port_operations nv_ck804_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .exec_command = ata_exec_command,
+- .check_status = ata_check_status,
+- .dev_select = ata_std_dev_select,
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .freeze = nv_ck804_freeze,
+- .thaw = nv_ck804_thaw,
+- .error_handler = nv_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .data_xfer = ata_pio_data_xfer,
+- .irq_handler = nv_ck804_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = nv_scr_read,
+- .scr_write = nv_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = nv_ck804_host_stop,
+-};
+-
+-static struct ata_port_info nv_port_info[] = {
+- /* generic */
+- {
+- .sht = &nv_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+- .pio_mask = NV_PIO_MASK,
+- .mwdma_mask = NV_MWDMA_MASK,
+- .udma_mask = NV_UDMA_MASK,
+- .port_ops = &nv_generic_ops,
+- },
+- /* nforce2/3 */
+- {
+- .sht = &nv_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+- .pio_mask = NV_PIO_MASK,
+- .mwdma_mask = NV_MWDMA_MASK,
+- .udma_mask = NV_UDMA_MASK,
+- .port_ops = &nv_nf2_ops,
+- },
+- /* ck804 */
+- {
+- .sht = &nv_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+- .pio_mask = NV_PIO_MASK,
+- .mwdma_mask = NV_MWDMA_MASK,
+- .udma_mask = NV_UDMA_MASK,
+- .port_ops = &nv_ck804_ops,
+- },
+-};
+-
+-MODULE_AUTHOR("NVIDIA");
+-MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- unsigned int i;
+- unsigned int handled = 0;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&host_set->lock, flags);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap;
+-
+- ap = host_set->ports[i];
+- if (ap &&
+- !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+- handled += ata_host_intr(ap, qc);
+- else
+- // No request pending? Clear interrupt status
+- // anyway, in case there's one pending.
+- ap->ops->check_status(ap);
+- }
+-
+- }
+-
+- spin_unlock_irqrestore(&host_set->lock, flags);
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
+-{
+- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+- int handled;
+-
+- /* freeze if hotplugged */
+- if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
+- ata_port_freeze(ap);
+- return 1;
+- }
+-
+- /* bail out if not our interrupt */
+- if (!(irq_stat & NV_INT_DEV))
+- return 0;
+-
+- /* DEV interrupt w/ no active qc? */
+- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+- ata_check_status(ap);
+- return 1;
+- }
+-
+- /* handle interrupt */
+- handled = ata_host_intr(ap, qc);
+- if (unlikely(!handled)) {
+- /* spurious, clear it */
+- ata_check_status(ap);
+- }
+-
+- return 1;
+-}
+-
+-static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
+-{
+- int i, handled = 0;
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap = host_set->ports[i];
+-
+- if (ap && !(ap->flags & ATA_FLAG_DISABLED))
+- handled += nv_host_intr(ap, irq_stat);
+-
+- irq_stat >>= NV_INT_PORT_SHIFT;
+- }
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- u8 irq_stat;
+- irqreturn_t ret;
+-
+- spin_lock(&host_set->lock);
+- irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+- ret = nv_do_interrupt(host_set, irq_stat);
+- spin_unlock(&host_set->lock);
+-
+- return ret;
+-}
+-
+-static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- u8 irq_stat;
+- irqreturn_t ret;
+-
+- spin_lock(&host_set->lock);
+- irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
+- ret = nv_do_interrupt(host_set, irq_stat);
+- spin_unlock(&host_set->lock);
+-
+- return ret;
+-}
+-
+-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+-
+- return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return;
+-
+- iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-static void nv_nf2_freeze(struct ata_port *ap)
+-{
+- unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
+- int shift = ap->port_no * NV_INT_PORT_SHIFT;
+- u8 mask;
+-
+- mask = inb(scr_addr + NV_INT_ENABLE);
+- mask &= ~(NV_INT_ALL << shift);
+- outb(mask, scr_addr + NV_INT_ENABLE);
+-}
+-
+-static void nv_nf2_thaw(struct ata_port *ap)
+-{
+- unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
+- int shift = ap->port_no * NV_INT_PORT_SHIFT;
+- u8 mask;
+-
+- outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
+-
+- mask = inb(scr_addr + NV_INT_ENABLE);
+- mask |= (NV_INT_MASK << shift);
+- outb(mask, scr_addr + NV_INT_ENABLE);
+-}
+-
+-static void nv_ck804_freeze(struct ata_port *ap)
+-{
+- void __iomem *mmio_base = ap->host_set->mmio_base;
+- int shift = ap->port_no * NV_INT_PORT_SHIFT;
+- u8 mask;
+-
+- mask = readb(mmio_base + NV_INT_ENABLE_CK804);
+- mask &= ~(NV_INT_ALL << shift);
+- writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
+-}
+-
+-static void nv_ck804_thaw(struct ata_port *ap)
+-{
+- void __iomem *mmio_base = ap->host_set->mmio_base;
+- int shift = ap->port_no * NV_INT_PORT_SHIFT;
+- u8 mask;
+-
+- writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804);
+-
+- mask = readb(mmio_base + NV_INT_ENABLE_CK804);
+- mask |= (NV_INT_MASK << shift);
+- writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
+-}
+-
+-static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+-{
+- unsigned int dummy;
+-
+- /* SATA hardreset fails to retrieve proper device signature on
+- * some controllers. Don't classify on hardreset. For more
+- * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
+- */
+- return sata_std_hardreset(ap, &dummy);
+-}
+-
+-static void nv_error_handler(struct ata_port *ap)
+-{
+- ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+- nv_hardreset, ata_std_postreset);
+-}
+-
+-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version = 0;
+- struct ata_port_info *ppi;
+- struct ata_probe_ent *probe_ent;
+- int pci_dev_busy = 0;
+- int rc;
+- u32 bar;
+- unsigned long base;
+-
+- // Make sure this is a SATA controller by counting the number of bars
+- // (NVIDIA SATA controllers will always have six bars). Otherwise,
+- // it's an IDE controller and we ignore it.
+- for (bar=0; bar<6; bar++)
+- if (pci_resource_start(pdev, bar) == 0)
+- return -ENODEV;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- goto err_out;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out_disable;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- rc = -ENOMEM;
+-
+- ppi = &nv_port_info[ent->driver_data];
+- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+- if (!probe_ent)
+- goto err_out_regions;
+-
+- probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
+- if (!probe_ent->mmio_base) {
+- rc = -EIO;
+- goto err_out_free_ent;
+- }
+-
+- base = (unsigned long)probe_ent->mmio_base;
+-
+- probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+- probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+-
+- /* enable SATA space for CK804 */
+- if (ent->driver_data == CK804) {
+- u8 regval;
+-
+- pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val);
+- regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+- pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+- }
+-
+- pci_set_master(pdev);
+-
+- rc = ata_device_add(probe_ent);
+- if (rc != NV_PORTS)
+- goto err_out_iounmap;
+-
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_iounmap:
+- pci_iounmap(pdev, probe_ent->mmio_base);
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out_disable:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+-err_out:
+- return rc;
+-}
+-
+-static void nv_ck804_host_stop(struct ata_host_set *host_set)
+-{
+- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+- u8 regval;
+-
+- /* disable SATA space for CK804 */
+- pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val);
+- regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+- pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+-
+- ata_pci_host_stop(host_set);
+-}
+-
+-static int __init nv_init(void)
+-{
+- return pci_module_init(&nv_pci_driver);
+-}
+-
+-static void __exit nv_exit(void)
+-{
+- pci_unregister_driver(&nv_pci_driver);
+-}
+-
+-module_init(nv_init);
+-module_exit(nv_exit);
+diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
+deleted file mode 100644
+index 4776f4e..0000000
+--- a/drivers/scsi/sata_promise.c
++++ /dev/null
+@@ -1,844 +0,0 @@
+-/*
+- * sata_promise.c - Promise SATA
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003-2004 Red Hat, Inc.
+- *
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware information only available under NDA.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/sched.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-#include "sata_promise.h"
+-
+-#define DRV_NAME "sata_promise"
+-#define DRV_VERSION "1.04"
+-
+-
+-enum {
+- PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
+- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+- PDC_TBG_MODE = 0x41, /* TBG mode */
+- PDC_FLASH_CTL = 0x44, /* Flash control register */
+- PDC_PCI_CTL = 0x48, /* PCI control and status register */
+- PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
+- PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
+- PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
+- PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
+- PDC_SLEW_CTL = 0x470, /* slew rate control reg */
+-
+- PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+- (1<<8) | (1<<9) | (1<<10),
+-
+- board_2037x = 0, /* FastTrak S150 TX2plus */
+- board_20319 = 1, /* FastTrak S150 TX4 */
+- board_20619 = 2, /* FastTrak TX4000 */
+- board_20771 = 3, /* FastTrak TX2300 */
+- board_2057x = 4, /* SATAII150 Tx2plus */
+- board_40518 = 5, /* SATAII150 Tx4 */
+-
+- PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
+-
+- PDC_RESET = (1 << 11), /* HDMA reset */
+-
+- PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
+- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+- ATA_FLAG_PIO_POLLING,
+-};
+-
+-
+-struct pdc_port_priv {
+- u8 *pkt;
+- dma_addr_t pkt_dma;
+-};
+-
+-struct pdc_host_priv {
+- int hotplug_offset;
+-};
+-
+-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+-static void pdc_eng_timeout(struct ata_port *ap);
+-static int pdc_port_start(struct ata_port *ap);
+-static void pdc_port_stop(struct ata_port *ap);
+-static void pdc_pata_phy_reset(struct ata_port *ap);
+-static void pdc_sata_phy_reset(struct ata_port *ap);
+-static void pdc_qc_prep(struct ata_queued_cmd *qc);
+-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+-static void pdc_irq_clear(struct ata_port *ap);
+-static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+-static void pdc_host_stop(struct ata_host_set *host_set);
+-
+-
+-static struct scsi_host_template pdc_ata_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations pdc_sata_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = pdc_tf_load_mmio,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = pdc_exec_command_mmio,
+- .dev_select = ata_std_dev_select,
+-
+- .phy_reset = pdc_sata_phy_reset,
+-
+- .qc_prep = pdc_qc_prep,
+- .qc_issue = pdc_qc_issue_prot,
+- .eng_timeout = pdc_eng_timeout,
+- .data_xfer = ata_mmio_data_xfer,
+- .irq_handler = pdc_interrupt,
+- .irq_clear = pdc_irq_clear,
+-
+- .scr_read = pdc_sata_scr_read,
+- .scr_write = pdc_sata_scr_write,
+- .port_start = pdc_port_start,
+- .port_stop = pdc_port_stop,
+- .host_stop = pdc_host_stop,
+-};
+-
+-static const struct ata_port_operations pdc_pata_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = pdc_tf_load_mmio,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = pdc_exec_command_mmio,
+- .dev_select = ata_std_dev_select,
+-
+- .phy_reset = pdc_pata_phy_reset,
+-
+- .qc_prep = pdc_qc_prep,
+- .qc_issue = pdc_qc_issue_prot,
+- .data_xfer = ata_mmio_data_xfer,
+- .eng_timeout = pdc_eng_timeout,
+- .irq_handler = pdc_interrupt,
+- .irq_clear = pdc_irq_clear,
+-
+- .port_start = pdc_port_start,
+- .port_stop = pdc_port_stop,
+- .host_stop = pdc_host_stop,
+-};
+-
+-static const struct ata_port_info pdc_port_info[] = {
+- /* board_2037x */
+- {
+- .sht = &pdc_ata_sht,
+- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_sata_ops,
+- },
+-
+- /* board_20319 */
+- {
+- .sht = &pdc_ata_sht,
+- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_sata_ops,
+- },
+-
+- /* board_20619 */
+- {
+- .sht = &pdc_ata_sht,
+- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_pata_ops,
+- },
+-
+- /* board_20771 */
+- {
+- .sht = &pdc_ata_sht,
+- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_sata_ops,
+- },
+-
+- /* board_2057x */
+- {
+- .sht = &pdc_ata_sht,
+- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_sata_ops,
+- },
+-
+- /* board_40518 */
+- {
+- .sht = &pdc_ata_sht,
+- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_sata_ops,
+- },
+-};
+-
+-static const struct pci_device_id pdc_ata_pci_tbl[] = {
+- { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+- { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+- { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+- { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+- { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+- { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2057x },
+- { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2057x },
+- { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2037x },
+-
+- { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20319 },
+- { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20319 },
+- { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20319 },
+- { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20319 },
+- { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20319 },
+- { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_40518 },
+-
+- { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20619 },
+-
+-/* TODO: remove all associated board_20771 code, as it completely
+- * duplicates board_2037x code, unless reason for separation can be
+- * divined.
+- */
+-#if 0
+- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20771 },
+-#endif
+-
+- { } /* terminate list */
+-};
+-
+-
+-static struct pci_driver pdc_ata_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = pdc_ata_pci_tbl,
+- .probe = pdc_ata_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-
+-static int pdc_port_start(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct pdc_port_priv *pp;
+- int rc;
+-
+- rc = ata_port_start(ap);
+- if (rc)
+- return rc;
+-
+- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+- if (!pp) {
+- rc = -ENOMEM;
+- goto err_out;
+- }
+-
+- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+- if (!pp->pkt) {
+- rc = -ENOMEM;
+- goto err_out_kfree;
+- }
+-
+- ap->private_data = pp;
+-
+- return 0;
+-
+-err_out_kfree:
+- kfree(pp);
+-err_out:
+- ata_port_stop(ap);
+- return rc;
+-}
+-
+-
+-static void pdc_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct pdc_port_priv *pp = ap->private_data;
+-
+- ap->private_data = NULL;
+- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
+- kfree(pp);
+- ata_port_stop(ap);
+-}
+-
+-
+-static void pdc_host_stop(struct ata_host_set *host_set)
+-{
+- struct pdc_host_priv *hp = host_set->private_data;
+-
+- ata_pci_host_stop(host_set);
+-
+- kfree(hp);
+-}
+-
+-
+-static void pdc_reset_port(struct ata_port *ap)
+-{
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+- unsigned int i;
+- u32 tmp;
+-
+- for (i = 11; i > 0; i--) {
+- tmp = readl(mmio);
+- if (tmp & PDC_RESET)
+- break;
+-
+- udelay(100);
+-
+- tmp |= PDC_RESET;
+- writel(tmp, mmio);
+- }
+-
+- tmp &= ~PDC_RESET;
+- writel(tmp, mmio);
+- readl(mmio); /* flush */
+-}
+-
+-static void pdc_sata_phy_reset(struct ata_port *ap)
+-{
+- pdc_reset_port(ap);
+- sata_phy_reset(ap);
+-}
+-
+-static void pdc_pata_cbl_detect(struct ata_port *ap)
+-{
+- u8 tmp;
+- void __iomem *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+-
+- tmp = readb(mmio);
+-
+- if (tmp & 0x01) {
+- ap->cbl = ATA_CBL_PATA40;
+- ap->udma_mask &= ATA_UDMA_MASK_40C;
+- } else
+- ap->cbl = ATA_CBL_PATA80;
+-}
+-
+-static void pdc_pata_phy_reset(struct ata_port *ap)
+-{
+- pdc_pata_cbl_detect(ap);
+- pdc_reset_port(ap);
+- ata_port_probe(ap);
+- ata_bus_reset(ap);
+-}
+-
+-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-
+-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+- u32 val)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return;
+- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-static void pdc_qc_prep(struct ata_queued_cmd *qc)
+-{
+- struct pdc_port_priv *pp = qc->ap->private_data;
+- unsigned int i;
+-
+- VPRINTK("ENTER\n");
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- ata_qc_prep(qc);
+- /* fall through */
+-
+- case ATA_PROT_NODATA:
+- i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
+- qc->dev->devno, pp->pkt);
+-
+- if (qc->tf.flags & ATA_TFLAG_LBA48)
+- i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
+- else
+- i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
+-
+- pdc_pkt_footer(&qc->tf, pp->pkt, i);
+- break;
+-
+- default:
+- break;
+- }
+-}
+-
+-static void pdc_eng_timeout(struct ata_port *ap)
+-{
+- struct ata_host_set *host_set = ap->host_set;
+- u8 drv_stat;
+- struct ata_queued_cmd *qc;
+- unsigned long flags;
+-
+- DPRINTK("ENTER\n");
+-
+- spin_lock_irqsave(&host_set->lock, flags);
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- case ATA_PROT_NODATA:
+- ata_port_printk(ap, KERN_ERR, "command timeout\n");
+- drv_stat = ata_wait_idle(ap);
+- qc->err_mask |= __ac_err_mask(drv_stat);
+- break;
+-
+- default:
+- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+-
+- ata_port_printk(ap, KERN_ERR,
+- "unknown timeout, cmd 0x%x stat 0x%x\n",
+- qc->tf.command, drv_stat);
+-
+- qc->err_mask |= ac_err_mask(drv_stat);
+- break;
+- }
+-
+- spin_unlock_irqrestore(&host_set->lock, flags);
+- ata_eh_qc_complete(qc);
+- DPRINTK("EXIT\n");
+-}
+-
+-static inline unsigned int pdc_host_intr( struct ata_port *ap,
+- struct ata_queued_cmd *qc)
+-{
+- unsigned int handled = 0;
+- u32 tmp;
+- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+-
+- tmp = readl(mmio);
+- if (tmp & PDC_ERR_MASK) {
+- qc->err_mask |= AC_ERR_DEV;
+- pdc_reset_port(ap);
+- }
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- case ATA_PROT_NODATA:
+- qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
+- ata_qc_complete(qc);
+- handled = 1;
+- break;
+-
+- default:
+- ap->stats.idle_irq++;
+- break;
+- }
+-
+- return handled;
+-}
+-
+-static void pdc_irq_clear(struct ata_port *ap)
+-{
+- struct ata_host_set *host_set = ap->host_set;
+- void __iomem *mmio = host_set->mmio_base;
+-
+- readl(mmio + PDC_INT_SEQMASK);
+-}
+-
+-static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- struct ata_port *ap;
+- u32 mask = 0;
+- unsigned int i, tmp;
+- unsigned int handled = 0;
+- void __iomem *mmio_base;
+-
+- VPRINTK("ENTER\n");
+-
+- if (!host_set || !host_set->mmio_base) {
+- VPRINTK("QUICK EXIT\n");
+- return IRQ_NONE;
+- }
+-
+- mmio_base = host_set->mmio_base;
+-
+- /* reading should also clear interrupts */
+- mask = readl(mmio_base + PDC_INT_SEQMASK);
+-
+- if (mask == 0xffffffff) {
+- VPRINTK("QUICK EXIT 2\n");
+- return IRQ_NONE;
+- }
+-
+- spin_lock(&host_set->lock);
+-
+- mask &= 0xffff; /* only 16 tags possible */
+- if (!mask) {
+- VPRINTK("QUICK EXIT 3\n");
+- goto done_irq;
+- }
+-
+- writel(mask, mmio_base + PDC_INT_SEQMASK);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- VPRINTK("port %u\n", i);
+- ap = host_set->ports[i];
+- tmp = mask & (1 << (i + 1));
+- if (tmp && ap &&
+- !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+- handled += pdc_host_intr(ap, qc);
+- }
+- }
+-
+- VPRINTK("EXIT\n");
+-
+-done_irq:
+- spin_unlock(&host_set->lock);
+- return IRQ_RETVAL(handled);
+-}
+-
+-static inline void pdc_packet_start(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct pdc_port_priv *pp = ap->private_data;
+- unsigned int port_no = ap->port_no;
+- u8 seq = (u8) (port_no + 1);
+-
+- VPRINTK("ENTER, ap %p\n", ap);
+-
+- writel(0x00000001, ap->host_set->mmio_base + (seq * 4));
+- readl(ap->host_set->mmio_base + (seq * 4)); /* flush */
+-
+- pp->pkt[2] = seq;
+- wmb(); /* flush PRD, pkt writes */
+- writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+-}
+-
+-static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+-{
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- case ATA_PROT_NODATA:
+- pdc_packet_start(qc);
+- return 0;
+-
+- case ATA_PROT_ATAPI_DMA:
+- BUG();
+- break;
+-
+- default:
+- break;
+- }
+-
+- return ata_qc_issue_prot(qc);
+-}
+-
+-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- WARN_ON (tf->protocol == ATA_PROT_DMA ||
+- tf->protocol == ATA_PROT_NODATA);
+- ata_tf_load(ap, tf);
+-}
+-
+-
+-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- WARN_ON (tf->protocol == ATA_PROT_DMA ||
+- tf->protocol == ATA_PROT_NODATA);
+- ata_exec_command(ap, tf);
+-}
+-
+-
+-static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+-{
+- port->cmd_addr = base;
+- port->data_addr = base;
+- port->feature_addr =
+- port->error_addr = base + 0x4;
+- port->nsect_addr = base + 0x8;
+- port->lbal_addr = base + 0xc;
+- port->lbam_addr = base + 0x10;
+- port->lbah_addr = base + 0x14;
+- port->device_addr = base + 0x18;
+- port->command_addr =
+- port->status_addr = base + 0x1c;
+- port->altstatus_addr =
+- port->ctl_addr = base + 0x38;
+-}
+-
+-
+-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+-{
+- void __iomem *mmio = pe->mmio_base;
+- struct pdc_host_priv *hp = pe->private_data;
+- int hotplug_offset = hp->hotplug_offset;
+- u32 tmp;
+-
+- /*
+- * Except for the hotplug stuff, this is voodoo from the
+- * Promise driver. Label this entire section
+- * "TODO: figure out why we do this"
+- */
+-
+- /* change FIFO_SHD to 8 dwords, enable BMR_BURST */
+- tmp = readl(mmio + PDC_FLASH_CTL);
+- tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
+- writel(tmp, mmio + PDC_FLASH_CTL);
+-
+- /* clear plug/unplug flags for all ports */
+- tmp = readl(mmio + hotplug_offset);
+- writel(tmp | 0xff, mmio + hotplug_offset);
+-
+- /* mask plug/unplug ints */
+- tmp = readl(mmio + hotplug_offset);
+- writel(tmp | 0xff0000, mmio + hotplug_offset);
+-
+- /* reduce TBG clock to 133 Mhz. */
+- tmp = readl(mmio + PDC_TBG_MODE);
+- tmp &= ~0x30000; /* clear bit 17, 16*/
+- tmp |= 0x10000; /* set bit 17:16 = 0:1 */
+- writel(tmp, mmio + PDC_TBG_MODE);
+-
+- readl(mmio + PDC_TBG_MODE); /* flush */
+- msleep(10);
+-
+- /* adjust slew rate control register. */
+- tmp = readl(mmio + PDC_SLEW_CTL);
+- tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
+- tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
+- writel(tmp, mmio + PDC_SLEW_CTL);
+-}
+-
+-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- struct pdc_host_priv *hp;
+- unsigned long base;
+- void __iomem *mmio_base;
+- unsigned int board_idx = (unsigned int) ent->driver_data;
+- int pci_dev_busy = 0;
+- int rc;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- mmio_base = pci_iomap(pdev, 3, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+- base = (unsigned long) mmio_base;
+-
+- hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+- if (hp == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+-
+- /* Set default hotplug offset */
+- hp->hotplug_offset = PDC_SATA_PLUG_CSR;
+- probe_ent->private_data = hp;
+-
+- probe_ent->sht = pdc_port_info[board_idx].sht;
+- probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
+- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
+- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
+- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
+- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+-
+- pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
+- pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
+-
+- probe_ent->port[0].scr_addr = base + 0x400;
+- probe_ent->port[1].scr_addr = base + 0x500;
+-
+- /* notice 4-port boards */
+- switch (board_idx) {
+- case board_40518:
+- /* Override hotplug offset for SATAII150 */
+- hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+- /* Fall through */
+- case board_20319:
+- probe_ent->n_ports = 4;
+-
+- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
+-
+- probe_ent->port[2].scr_addr = base + 0x600;
+- probe_ent->port[3].scr_addr = base + 0x700;
+- break;
+- case board_2057x:
+- /* Override hotplug offset for SATAII150 */
+- hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+- /* Fall through */
+- case board_2037x:
+- probe_ent->n_ports = 2;
+- break;
+- case board_20771:
+- probe_ent->n_ports = 2;
+- break;
+- case board_20619:
+- probe_ent->n_ports = 4;
+-
+- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
+-
+- probe_ent->port[2].scr_addr = base + 0x600;
+- probe_ent->port[3].scr_addr = base + 0x700;
+- break;
+- default:
+- BUG();
+- break;
+- }
+-
+- pci_set_master(pdev);
+-
+- /* initialize adapter */
+- pdc_host_init(board_idx, probe_ent);
+-
+- /* FIXME: Need any other frees than hp? */
+- if (!ata_device_add(probe_ent))
+- kfree(hp);
+-
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-
+-static int __init pdc_ata_init(void)
+-{
+- return pci_module_init(&pdc_ata_pci_driver);
+-}
+-
+-
+-static void __exit pdc_ata_exit(void)
+-{
+- pci_unregister_driver(&pdc_ata_pci_driver);
+-}
+-
+-
+-MODULE_AUTHOR("Jeff Garzik");
+-MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(pdc_ata_init);
+-module_exit(pdc_ata_exit);
+diff --git a/drivers/scsi/sata_promise.h b/drivers/scsi/sata_promise.h
+deleted file mode 100644
+index 6ee5e19..0000000
+--- a/drivers/scsi/sata_promise.h
++++ /dev/null
+@@ -1,157 +0,0 @@
+-/*
+- * sata_promise.h - Promise SATA common definitions and inline funcs
+- *
+- * Copyright 2003-2004 Red Hat, Inc.
+- *
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- */
+-
+-#ifndef __SATA_PROMISE_H__
+-#define __SATA_PROMISE_H__
+-
+-#include <linux/ata.h>
+-
+-enum pdc_packet_bits {
+- PDC_PKT_READ = (1 << 2),
+- PDC_PKT_NODATA = (1 << 3),
+-
+- PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
+- PDC_PKT_CLEAR_BSY = (1 << 4),
+- PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
+- PDC_LAST_REG = (1 << 3),
+-
+- PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
+-};
+-
+-static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
+- dma_addr_t sg_table,
+- unsigned int devno, u8 *buf)
+-{
+- u8 dev_reg;
+- u32 *buf32 = (u32 *) buf;
+-
+- /* set control bits (byte 0), zero delay seq id (byte 3),
+- * and seq id (byte 2)
+- */
+- switch (tf->protocol) {
+- case ATA_PROT_DMA:
+- if (!(tf->flags & ATA_TFLAG_WRITE))
+- buf32[0] = cpu_to_le32(PDC_PKT_READ);
+- else
+- buf32[0] = 0;
+- break;
+-
+- case ATA_PROT_NODATA:
+- buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+- break;
+-
+- default:
+- BUG();
+- break;
+- }
+-
+- buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
+- buf32[2] = 0; /* no next-packet */
+-
+- if (devno == 0)
+- dev_reg = ATA_DEVICE_OBS;
+- else
+- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+-
+- /* select device */
+- buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+- buf[13] = dev_reg;
+-
+- /* device control register */
+- buf[14] = (1 << 5) | PDC_REG_DEVCTL;
+- buf[15] = tf->ctl;
+-
+- return 16; /* offset of next byte */
+-}
+-
+-static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
+- unsigned int i)
+-{
+- if (tf->flags & ATA_TFLAG_DEVICE) {
+- buf[i++] = (1 << 5) | ATA_REG_DEVICE;
+- buf[i++] = tf->device;
+- }
+-
+- /* and finally the command itself; also includes end-of-pkt marker */
+- buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
+- buf[i++] = tf->command;
+-
+- return i;
+-}
+-
+-static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+-{
+- /* the "(1 << 5)" should be read "(count << 5)" */
+-
+- /* ATA command block registers */
+- buf[i++] = (1 << 5) | ATA_REG_FEATURE;
+- buf[i++] = tf->feature;
+-
+- buf[i++] = (1 << 5) | ATA_REG_NSECT;
+- buf[i++] = tf->nsect;
+-
+- buf[i++] = (1 << 5) | ATA_REG_LBAL;
+- buf[i++] = tf->lbal;
+-
+- buf[i++] = (1 << 5) | ATA_REG_LBAM;
+- buf[i++] = tf->lbam;
+-
+- buf[i++] = (1 << 5) | ATA_REG_LBAH;
+- buf[i++] = tf->lbah;
+-
+- return i;
+-}
+-
+-static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+-{
+- /* the "(2 << 5)" should be read "(count << 5)" */
+-
+- /* ATA command block registers */
+- buf[i++] = (2 << 5) | ATA_REG_FEATURE;
+- buf[i++] = tf->hob_feature;
+- buf[i++] = tf->feature;
+-
+- buf[i++] = (2 << 5) | ATA_REG_NSECT;
+- buf[i++] = tf->hob_nsect;
+- buf[i++] = tf->nsect;
+-
+- buf[i++] = (2 << 5) | ATA_REG_LBAL;
+- buf[i++] = tf->hob_lbal;
+- buf[i++] = tf->lbal;
+-
+- buf[i++] = (2 << 5) | ATA_REG_LBAM;
+- buf[i++] = tf->hob_lbam;
+- buf[i++] = tf->lbam;
+-
+- buf[i++] = (2 << 5) | ATA_REG_LBAH;
+- buf[i++] = tf->hob_lbah;
+- buf[i++] = tf->lbah;
+-
+- return i;
+-}
+-
+-
+-#endif /* __SATA_PROMISE_H__ */
+diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
+deleted file mode 100644
+index d374c1d..0000000
+--- a/drivers/scsi/sata_qstor.c
++++ /dev/null
+@@ -1,730 +0,0 @@
+-/*
+- * sata_qstor.c - Pacific Digital Corporation QStor SATA
+- *
+- * Maintained by: Mark Lord <mlord at pobox.com>
+- *
+- * Copyright 2005 Pacific Digital Corporation.
+- * (OSL/GPL code release authorized by Jalil Fadavi).
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/sched.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <asm/io.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "sata_qstor"
+-#define DRV_VERSION "0.06"
+-
+-enum {
+- QS_PORTS = 4,
+- QS_MAX_PRD = LIBATA_MAX_PRD,
+- QS_CPB_ORDER = 6,
+- QS_CPB_BYTES = (1 << QS_CPB_ORDER),
+- QS_PRD_BYTES = QS_MAX_PRD * 16,
+- QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES,
+-
+- /* global register offsets */
+- QS_HCF_CNFG3 = 0x0003, /* host configuration offset */
+- QS_HID_HPHY = 0x0004, /* host physical interface info */
+- QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */
+- QS_HST_SFF = 0x0100, /* host status fifo offset */
+- QS_HVS_SERD3 = 0x0393, /* PHY enable offset */
+-
+- /* global control bits */
+- QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */
+- QS_CNFG3_GSRST = 0x01, /* global chip reset */
+- QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/
+-
+- /* per-channel register offsets */
+- QS_CCF_CPBA = 0x0710, /* chan CPB base address */
+- QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */
+- QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */
+- QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */
+- QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */
+- QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */
+- QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */
+- QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */
+- QS_CCT_CFF = 0x0a00, /* chan command fifo offset */
+-
+- /* channel control bits */
+- QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */
+- QS_CTR0_CLER = (1 << 2), /* clear channel errors */
+- QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */
+- QS_CTR1_RCHN = (1 << 4), /* reset channel logic */
+- QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */
+-
+- /* pkt sub-field headers */
+- QS_HCB_HDR = 0x01, /* Host Control Block header */
+- QS_DCB_HDR = 0x02, /* Device Control Block header */
+-
+- /* pkt HCB flag bits */
+- QS_HF_DIRO = (1 << 0), /* data DIRection Out */
+- QS_HF_DAT = (1 << 3), /* DATa pkt */
+- QS_HF_IEN = (1 << 4), /* Interrupt ENable */
+- QS_HF_VLD = (1 << 5), /* VaLiD pkt */
+-
+- /* pkt DCB flag bits */
+- QS_DF_PORD = (1 << 2), /* Pio OR Dma */
+- QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */
+-
+- /* PCI device IDs */
+- board_2068_idx = 0, /* QStor 4-port SATA/RAID */
+-};
+-
+-enum {
+- QS_DMA_BOUNDARY = ~0UL
+-};
+-
+-typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
+-
+-struct qs_port_priv {
+- u8 *pkt;
+- dma_addr_t pkt_dma;
+- qs_state_t state;
+-};
+-
+-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
+-static int qs_port_start(struct ata_port *ap);
+-static void qs_host_stop(struct ata_host_set *host_set);
+-static void qs_port_stop(struct ata_port *ap);
+-static void qs_phy_reset(struct ata_port *ap);
+-static void qs_qc_prep(struct ata_queued_cmd *qc);
+-static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
+-static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
+-static void qs_bmdma_stop(struct ata_queued_cmd *qc);
+-static u8 qs_bmdma_status(struct ata_port *ap);
+-static void qs_irq_clear(struct ata_port *ap);
+-static void qs_eng_timeout(struct ata_port *ap);
+-
+-static struct scsi_host_template qs_ata_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = QS_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .use_clustering = ENABLE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = QS_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations qs_ata_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .check_atapi_dma = qs_check_atapi_dma,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+- .phy_reset = qs_phy_reset,
+- .qc_prep = qs_qc_prep,
+- .qc_issue = qs_qc_issue,
+- .data_xfer = ata_mmio_data_xfer,
+- .eng_timeout = qs_eng_timeout,
+- .irq_handler = qs_intr,
+- .irq_clear = qs_irq_clear,
+- .scr_read = qs_scr_read,
+- .scr_write = qs_scr_write,
+- .port_start = qs_port_start,
+- .port_stop = qs_port_stop,
+- .host_stop = qs_host_stop,
+- .bmdma_stop = qs_bmdma_stop,
+- .bmdma_status = qs_bmdma_status,
+-};
+-
+-static const struct ata_port_info qs_port_info[] = {
+- /* board_2068_idx */
+- {
+- .sht = &qs_ata_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_SATA_RESET |
+- //FIXME ATA_FLAG_SRST |
+- ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
+- .pio_mask = 0x10, /* pio4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &qs_ata_ops,
+- },
+-};
+-
+-static const struct pci_device_id qs_ata_pci_tbl[] = {
+- { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_2068_idx },
+-
+- { } /* terminate list */
+-};
+-
+-static struct pci_driver qs_ata_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = qs_ata_pci_tbl,
+- .probe = qs_ata_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
+-{
+- return 1; /* ATAPI DMA not supported */
+-}
+-
+-static void qs_bmdma_stop(struct ata_queued_cmd *qc)
+-{
+- /* nothing */
+-}
+-
+-static u8 qs_bmdma_status(struct ata_port *ap)
+-{
+- return 0;
+-}
+-
+-static void qs_irq_clear(struct ata_port *ap)
+-{
+- /* nothing */
+-}
+-
+-static inline void qs_enter_reg_mode(struct ata_port *ap)
+-{
+- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+-
+- writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
+- readb(chan + QS_CCT_CTR0); /* flush */
+-}
+-
+-static inline void qs_reset_channel_logic(struct ata_port *ap)
+-{
+- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+-
+- writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+- readb(chan + QS_CCT_CTR0); /* flush */
+- qs_enter_reg_mode(ap);
+-}
+-
+-static void qs_phy_reset(struct ata_port *ap)
+-{
+- struct qs_port_priv *pp = ap->private_data;
+-
+- pp->state = qs_state_idle;
+- qs_reset_channel_logic(ap);
+- sata_phy_reset(ap);
+-}
+-
+-static void qs_eng_timeout(struct ata_port *ap)
+-{
+- struct qs_port_priv *pp = ap->private_data;
+-
+- if (pp->state != qs_state_idle) /* healthy paranoia */
+- pp->state = qs_state_mmio;
+- qs_reset_channel_logic(ap);
+- ata_eng_timeout(ap);
+-}
+-
+-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return ~0U;
+- return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+-}
+-
+-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return;
+- writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+-}
+-
+-static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
+-{
+- struct scatterlist *sg;
+- struct ata_port *ap = qc->ap;
+- struct qs_port_priv *pp = ap->private_data;
+- unsigned int nelem;
+- u8 *prd = pp->pkt + QS_CPB_BYTES;
+-
+- WARN_ON(qc->__sg == NULL);
+- WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+-
+- nelem = 0;
+- ata_for_each_sg(sg, qc) {
+- u64 addr;
+- u32 len;
+-
+- addr = sg_dma_address(sg);
+- *(__le64 *)prd = cpu_to_le64(addr);
+- prd += sizeof(u64);
+-
+- len = sg_dma_len(sg);
+- *(__le32 *)prd = cpu_to_le32(len);
+- prd += sizeof(u64);
+-
+- VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
+- (unsigned long long)addr, len);
+- nelem++;
+- }
+-
+- return nelem;
+-}
+-
+-static void qs_qc_prep(struct ata_queued_cmd *qc)
+-{
+- struct qs_port_priv *pp = qc->ap->private_data;
+- u8 dflags = QS_DF_PORD, *buf = pp->pkt;
+- u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
+- u64 addr;
+- unsigned int nelem;
+-
+- VPRINTK("ENTER\n");
+-
+- qs_enter_reg_mode(qc->ap);
+- if (qc->tf.protocol != ATA_PROT_DMA) {
+- ata_qc_prep(qc);
+- return;
+- }
+-
+- nelem = qs_fill_sg(qc);
+-
+- if ((qc->tf.flags & ATA_TFLAG_WRITE))
+- hflags |= QS_HF_DIRO;
+- if ((qc->tf.flags & ATA_TFLAG_LBA48))
+- dflags |= QS_DF_ELBA;
+-
+- /* host control block (HCB) */
+- buf[ 0] = QS_HCB_HDR;
+- buf[ 1] = hflags;
+- *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
+- *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem);
+- addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
+- *(__le64 *)(&buf[16]) = cpu_to_le64(addr);
+-
+- /* device control block (DCB) */
+- buf[24] = QS_DCB_HDR;
+- buf[28] = dflags;
+-
+- /* frame information structure (FIS) */
+- ata_tf_to_fis(&qc->tf, &buf[32], 0);
+-}
+-
+-static inline void qs_packet_start(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+-
+- VPRINTK("ENTER, ap %p\n", ap);
+-
+- writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
+- wmb(); /* flush PRDs and pkt to memory */
+- writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
+- readl(chan + QS_CCT_CFF); /* flush */
+-}
+-
+-static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
+-{
+- struct qs_port_priv *pp = qc->ap->private_data;
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+-
+- pp->state = qs_state_pkt;
+- qs_packet_start(qc);
+- return 0;
+-
+- case ATA_PROT_ATAPI_DMA:
+- BUG();
+- break;
+-
+- default:
+- break;
+- }
+-
+- pp->state = qs_state_mmio;
+- return ata_qc_issue_prot(qc);
+-}
+-
+-static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
+-{
+- unsigned int handled = 0;
+- u8 sFFE;
+- u8 __iomem *mmio_base = host_set->mmio_base;
+-
+- do {
+- u32 sff0 = readl(mmio_base + QS_HST_SFF);
+- u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
+- u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */
+- sFFE = sff1 >> 31; /* empty flag */
+-
+- if (sEVLD) {
+- u8 sDST = sff0 >> 16; /* dev status */
+- u8 sHST = sff1 & 0x3f; /* host status */
+- unsigned int port_no = (sff1 >> 8) & 0x03;
+- struct ata_port *ap = host_set->ports[port_no];
+-
+- DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
+- sff1, sff0, port_no, sHST, sDST);
+- handled = 1;
+- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+- struct qs_port_priv *pp = ap->private_data;
+- if (!pp || pp->state != qs_state_pkt)
+- continue;
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+- switch (sHST) {
+- case 0: /* successful CPB */
+- case 3: /* device error */
+- pp->state = qs_state_idle;
+- qs_enter_reg_mode(qc->ap);
+- qc->err_mask |= ac_err_mask(sDST);
+- ata_qc_complete(qc);
+- break;
+- default:
+- break;
+- }
+- }
+- }
+- }
+- } while (!sFFE);
+- return handled;
+-}
+-
+-static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
+-{
+- unsigned int handled = 0, port_no;
+-
+- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
+- struct ata_port *ap;
+- ap = host_set->ports[port_no];
+- if (ap &&
+- !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+- struct qs_port_priv *pp = ap->private_data;
+- if (!pp || pp->state != qs_state_mmio)
+- continue;
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+-
+- /* check main status, clearing INTRQ */
+- u8 status = ata_check_status(ap);
+- if ((status & ATA_BUSY))
+- continue;
+- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+- ap->id, qc->tf.protocol, status);
+-
+- /* complete taskfile transaction */
+- pp->state = qs_state_idle;
+- qc->err_mask |= ac_err_mask(status);
+- ata_qc_complete(qc);
+- handled = 1;
+- }
+- }
+- }
+- return handled;
+-}
+-
+-static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- unsigned int handled = 0;
+-
+- VPRINTK("ENTER\n");
+-
+- spin_lock(&host_set->lock);
+- handled = qs_intr_pkt(host_set) | qs_intr_mmio(host_set);
+- spin_unlock(&host_set->lock);
+-
+- VPRINTK("EXIT\n");
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
+-{
+- port->cmd_addr =
+- port->data_addr = base + 0x400;
+- port->error_addr =
+- port->feature_addr = base + 0x408; /* hob_feature = 0x409 */
+- port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */
+- port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */
+- port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */
+- port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */
+- port->device_addr = base + 0x430;
+- port->status_addr =
+- port->command_addr = base + 0x438;
+- port->altstatus_addr =
+- port->ctl_addr = base + 0x440;
+- port->scr_addr = base + 0xc00;
+-}
+-
+-static int qs_port_start(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct qs_port_priv *pp;
+- void __iomem *mmio_base = ap->host_set->mmio_base;
+- void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
+- u64 addr;
+- int rc;
+-
+- rc = ata_port_start(ap);
+- if (rc)
+- return rc;
+- qs_enter_reg_mode(ap);
+- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+- if (!pp) {
+- rc = -ENOMEM;
+- goto err_out;
+- }
+- pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
+- GFP_KERNEL);
+- if (!pp->pkt) {
+- rc = -ENOMEM;
+- goto err_out_kfree;
+- }
+- memset(pp->pkt, 0, QS_PKT_BYTES);
+- ap->private_data = pp;
+-
+- addr = (u64)pp->pkt_dma;
+- writel((u32) addr, chan + QS_CCF_CPBA);
+- writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
+- return 0;
+-
+-err_out_kfree:
+- kfree(pp);
+-err_out:
+- ata_port_stop(ap);
+- return rc;
+-}
+-
+-static void qs_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct qs_port_priv *pp = ap->private_data;
+-
+- if (pp != NULL) {
+- ap->private_data = NULL;
+- if (pp->pkt != NULL)
+- dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
+- pp->pkt_dma);
+- kfree(pp);
+- }
+- ata_port_stop(ap);
+-}
+-
+-static void qs_host_stop(struct ata_host_set *host_set)
+-{
+- void __iomem *mmio_base = host_set->mmio_base;
+- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+-
+- writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+- writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+-
+- pci_iounmap(pdev, mmio_base);
+-}
+-
+-static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+-{
+- void __iomem *mmio_base = pe->mmio_base;
+- unsigned int port_no;
+-
+- writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+- writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+-
+- /* reset each channel in turn */
+- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+- u8 __iomem *chan = mmio_base + (port_no * 0x4000);
+- writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+- writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
+- readb(chan + QS_CCT_CTR0); /* flush */
+- }
+- writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
+-
+- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+- u8 __iomem *chan = mmio_base + (port_no * 0x4000);
+- /* set FIFO depths to same settings as Windows driver */
+- writew(32, chan + QS_CFC_HUFT);
+- writew(32, chan + QS_CFC_HDFT);
+- writew(10, chan + QS_CFC_DUFT);
+- writew( 8, chan + QS_CFC_DDFT);
+- /* set CPB size in bytes, as a power of two */
+- writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP);
+- }
+- writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
+-}
+-
+-/*
+- * The QStor understands 64-bit buses, and uses 64-bit fields
+- * for DMA pointers regardless of bus width. We just have to
+- * make sure our DMA masks are set appropriately for whatever
+- * bridge lies between us and the QStor, and then the DMA mapping
+- * code will ensure we only ever "see" appropriate buffer addresses.
+- * If we're 32-bit limited somewhere, then our 64-bit fields will
+- * just end up with zeros in the upper 32-bits, without any special
+- * logic required outside of this routine (below).
+- */
+-static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
+-{
+- u32 bus_info = readl(mmio_base + QS_HID_HPHY);
+- int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
+-
+- if (have_64bit_bus &&
+- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+- if (rc) {
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "64-bit DMA enable failed\n");
+- return rc;
+- }
+- }
+- } else {
+- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit DMA enable failed\n");
+- return rc;
+- }
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit consistent DMA enable failed\n");
+- return rc;
+- }
+- }
+- return 0;
+-}
+-
+-static int qs_ata_init_one(struct pci_dev *pdev,
+- const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- void __iomem *mmio_base;
+- unsigned int board_idx = (unsigned int) ent->driver_data;
+- int rc, port_no;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc)
+- goto err_out;
+-
+- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
+- rc = -ENODEV;
+- goto err_out_regions;
+- }
+-
+- mmio_base = pci_iomap(pdev, 4, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- rc = qs_set_dma_masks(pdev, mmio_base);
+- if (rc)
+- goto err_out_iounmap;
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_iounmap;
+- }
+-
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- probe_ent->sht = qs_port_info[board_idx].sht;
+- probe_ent->host_flags = qs_port_info[board_idx].host_flags;
+- probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
+- probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
+- probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
+- probe_ent->port_ops = qs_port_info[board_idx].port_ops;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+- probe_ent->n_ports = QS_PORTS;
+-
+- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+- unsigned long chan = (unsigned long)mmio_base +
+- (port_no * 0x4000);
+- qs_ata_setup_port(&probe_ent->port[port_no], chan);
+- }
+-
+- pci_set_master(pdev);
+-
+- /* initialize adapter */
+- qs_host_init(board_idx, probe_ent);
+-
+- rc = ata_device_add(probe_ent);
+- kfree(probe_ent);
+- if (rc != QS_PORTS)
+- goto err_out_iounmap;
+- return 0;
+-
+-err_out_iounmap:
+- pci_iounmap(pdev, mmio_base);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-static int __init qs_ata_init(void)
+-{
+- return pci_module_init(&qs_ata_pci_driver);
+-}
+-
+-static void __exit qs_ata_exit(void)
+-{
+- pci_unregister_driver(&qs_ata_pci_driver);
+-}
+-
+-MODULE_AUTHOR("Mark Lord");
+-MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(qs_ata_init);
+-module_exit(qs_ata_exit);
+diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
+deleted file mode 100644
+index d0a8507..0000000
+--- a/drivers/scsi/sata_sil.c
++++ /dev/null
+@@ -1,727 +0,0 @@
+-/*
+- * sata_sil.c - Silicon Image SATA
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003-2005 Red Hat, Inc.
+- * Copyright 2003 Benjamin Herrenschmidt
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Documentation for SiI 3112:
+- * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
+- *
+- * Other errata and documentation available under NDA.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "sata_sil"
+-#define DRV_VERSION "2.0"
+-
+-enum {
+- /*
+- * host flags
+- */
+- SIL_FLAG_NO_SATA_IRQ = (1 << 28),
+- SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
+- SIL_FLAG_MOD15WRITE = (1 << 30),
+-
+- SIL_DFL_HOST_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+-
+- /*
+- * Controller IDs
+- */
+- sil_3112 = 0,
+- sil_3112_no_sata_irq = 1,
+- sil_3512 = 2,
+- sil_3114 = 3,
+-
+- /*
+- * Register offsets
+- */
+- SIL_SYSCFG = 0x48,
+-
+- /*
+- * Register bits
+- */
+- /* SYSCFG */
+- SIL_MASK_IDE0_INT = (1 << 22),
+- SIL_MASK_IDE1_INT = (1 << 23),
+- SIL_MASK_IDE2_INT = (1 << 24),
+- SIL_MASK_IDE3_INT = (1 << 25),
+- SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
+- SIL_MASK_4PORT = SIL_MASK_2PORT |
+- SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
+-
+- /* BMDMA/BMDMA2 */
+- SIL_INTR_STEERING = (1 << 1),
+-
+- SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */
+- SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */
+- SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */
+- SIL_DMA_ACTIVE = (1 << 16), /* DMA running */
+- SIL_DMA_ERROR = (1 << 17), /* PCI bus error */
+- SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */
+- SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */
+- SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */
+- SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */
+- SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */
+-
+- /* SIEN */
+- SIL_SIEN_N = (1 << 16), /* triggered by SError.N */
+-
+- /*
+- * Others
+- */
+- SIL_QUIRK_MOD15WRITE = (1 << 0),
+- SIL_QUIRK_UDMA5MAX = (1 << 1),
+-};
+-
+-static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static int sil_pci_device_resume(struct pci_dev *pdev);
+-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-static void sil_post_set_mode (struct ata_port *ap);
+-static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs);
+-static void sil_freeze(struct ata_port *ap);
+-static void sil_thaw(struct ata_port *ap);
+-
+-
+-static const struct pci_device_id sil_pci_tbl[] = {
+- { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+- { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+- { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
+- { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
+- { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+- { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+- { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+- { } /* terminate list */
+-};
+-
+-
+-/* TODO firmware versions should be added - eric */
+-static const struct sil_drivelist {
+- const char * product;
+- unsigned int quirk;
+-} sil_blacklist [] = {
+- { "ST320012AS", SIL_QUIRK_MOD15WRITE },
+- { "ST330013AS", SIL_QUIRK_MOD15WRITE },
+- { "ST340017AS", SIL_QUIRK_MOD15WRITE },
+- { "ST360015AS", SIL_QUIRK_MOD15WRITE },
+- { "ST380013AS", SIL_QUIRK_MOD15WRITE },
+- { "ST380023AS", SIL_QUIRK_MOD15WRITE },
+- { "ST3120023AS", SIL_QUIRK_MOD15WRITE },
+- { "ST3160023AS", SIL_QUIRK_MOD15WRITE },
+- { "ST3120026AS", SIL_QUIRK_MOD15WRITE },
+- { "ST3200822AS", SIL_QUIRK_MOD15WRITE },
+- { "ST340014ASL", SIL_QUIRK_MOD15WRITE },
+- { "ST360014ASL", SIL_QUIRK_MOD15WRITE },
+- { "ST380011ASL", SIL_QUIRK_MOD15WRITE },
+- { "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
+- { "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
+- { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
+- { }
+-};
+-
+-static struct pci_driver sil_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = sil_pci_tbl,
+- .probe = sil_init_one,
+- .remove = ata_pci_remove_one,
+- .suspend = ata_pci_device_suspend,
+- .resume = sil_pci_device_resume,
+-};
+-
+-static struct scsi_host_template sil_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+- .suspend = ata_scsi_device_suspend,
+- .resume = ata_scsi_device_resume,
+-};
+-
+-static const struct ata_port_operations sil_ops = {
+- .port_disable = ata_port_disable,
+- .dev_config = sil_dev_config,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+- .post_set_mode = sil_post_set_mode,
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_mmio_data_xfer,
+- .freeze = sil_freeze,
+- .thaw = sil_thaw,
+- .error_handler = ata_bmdma_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .irq_handler = sil_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = sil_scr_read,
+- .scr_write = sil_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_pci_host_stop,
+-};
+-
+-static const struct ata_port_info sil_port_info[] = {
+- /* sil_3112 */
+- {
+- .sht = &sil_sht,
+- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil_ops,
+- },
+- /* sil_3112_no_sata_irq */
+- {
+- .sht = &sil_sht,
+- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE |
+- SIL_FLAG_NO_SATA_IRQ,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil_ops,
+- },
+- /* sil_3512 */
+- {
+- .sht = &sil_sht,
+- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil_ops,
+- },
+- /* sil_3114 */
+- {
+- .sht = &sil_sht,
+- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil_ops,
+- },
+-};
+-
+-/* per-port register offsets */
+-/* TODO: we can probably calculate rather than use a table */
+-static const struct {
+- unsigned long tf; /* ATA taskfile register block */
+- unsigned long ctl; /* ATA control/altstatus register block */
+- unsigned long bmdma; /* DMA register block */
+- unsigned long bmdma2; /* DMA register block #2 */
+- unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
+- unsigned long scr; /* SATA control register block */
+- unsigned long sien; /* SATA Interrupt Enable register */
+- unsigned long xfer_mode;/* data transfer mode register */
+- unsigned long sfis_cfg; /* SATA FIS reception config register */
+-} sil_port[] = {
+- /* port 0 ... */
+- { 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+- { 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+- { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+- { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
+- /* ... port 3 */
+-};
+-
+-MODULE_AUTHOR("Jeff Garzik");
+-MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-static int slow_down = 0;
+-module_param(slow_down, int, 0444);
+-MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
+-
+-
+-static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
+-{
+- u8 cache_line = 0;
+- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
+- return cache_line;
+-}
+-
+-static void sil_post_set_mode (struct ata_port *ap)
+-{
+- struct ata_host_set *host_set = ap->host_set;
+- struct ata_device *dev;
+- void __iomem *addr =
+- host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+- u32 tmp, dev_mode[2];
+- unsigned int i;
+-
+- for (i = 0; i < 2; i++) {
+- dev = &ap->device[i];
+- if (!ata_dev_enabled(dev))
+- dev_mode[i] = 0; /* PIO0/1/2 */
+- else if (dev->flags & ATA_DFLAG_PIO)
+- dev_mode[i] = 1; /* PIO3/4 */
+- else
+- dev_mode[i] = 3; /* UDMA */
+- /* value 2 indicates MDMA */
+- }
+-
+- tmp = readl(addr);
+- tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
+- tmp |= dev_mode[0];
+- tmp |= (dev_mode[1] << 4);
+- writel(tmp, addr);
+- readl(addr); /* flush */
+-}
+-
+-static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+-{
+- unsigned long offset = ap->ioaddr.scr_addr;
+-
+- switch (sc_reg) {
+- case SCR_STATUS:
+- return offset + 4;
+- case SCR_ERROR:
+- return offset + 8;
+- case SCR_CONTROL:
+- return offset;
+- default:
+- /* do nothing */
+- break;
+- }
+-
+- return 0;
+-}
+-
+-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+- if (mmio)
+- return readl(mmio);
+- return 0xffffffffU;
+-}
+-
+-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+-{
+- void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+- if (mmio)
+- writel(val, mmio);
+-}
+-
+-static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
+-{
+- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+- u8 status;
+-
+- if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
+- u32 serror;
+-
+- /* SIEN doesn't mask SATA IRQs on some 3112s. Those
+- * controllers continue to assert IRQ as long as
+- * SError bits are pending. Clear SError immediately.
+- */
+- serror = sil_scr_read(ap, SCR_ERROR);
+- sil_scr_write(ap, SCR_ERROR, serror);
+-
+- /* Trigger hotplug and accumulate SError only if the
+- * port isn't already frozen. Otherwise, PHY events
+- * during hardreset makes controllers with broken SIEN
+- * repeat probing needlessly.
+- */
+- if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+- ata_ehi_hotplugged(&ap->eh_info);
+- ap->eh_info.serror |= serror;
+- }
+-
+- goto freeze;
+- }
+-
+- if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
+- goto freeze;
+-
+- /* Check whether we are expecting interrupt in this state */
+- switch (ap->hsm_task_state) {
+- case HSM_ST_FIRST:
+- /* Some pre-ATAPI-4 devices assert INTRQ
+- * at this state when ready to receive CDB.
+- */
+-
+- /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+- * The flag was turned on only for atapi devices.
+- * No need to check is_atapi_taskfile(&qc->tf) again.
+- */
+- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+- goto err_hsm;
+- break;
+- case HSM_ST_LAST:
+- if (qc->tf.protocol == ATA_PROT_DMA ||
+- qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+- /* clear DMA-Start bit */
+- ap->ops->bmdma_stop(qc);
+-
+- if (bmdma2 & SIL_DMA_ERROR) {
+- qc->err_mask |= AC_ERR_HOST_BUS;
+- ap->hsm_task_state = HSM_ST_ERR;
+- }
+- }
+- break;
+- case HSM_ST:
+- break;
+- default:
+- goto err_hsm;
+- }
+-
+- /* check main status, clearing INTRQ */
+- status = ata_chk_status(ap);
+- if (unlikely(status & ATA_BUSY))
+- goto err_hsm;
+-
+- /* ack bmdma irq events */
+- ata_bmdma_irq_clear(ap);
+-
+- /* kick HSM in the ass */
+- ata_hsm_move(ap, qc, status, 0);
+-
+- return;
+-
+- err_hsm:
+- qc->err_mask |= AC_ERR_HSM;
+- freeze:
+- ata_port_freeze(ap);
+-}
+-
+-static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+- struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- void __iomem *mmio_base = host_set->mmio_base;
+- int handled = 0;
+- int i;
+-
+- spin_lock(&host_set->lock);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- struct ata_port *ap = host_set->ports[i];
+- u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
+-
+- if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+- continue;
+-
+- /* turn off SATA_IRQ if not supported */
+- if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+- bmdma2 &= ~SIL_DMA_SATA_IRQ;
+-
+- if (bmdma2 == 0xffffffff ||
+- !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
+- continue;
+-
+- sil_host_intr(ap, bmdma2);
+- handled = 1;
+- }
+-
+- spin_unlock(&host_set->lock);
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static void sil_freeze(struct ata_port *ap)
+-{
+- void __iomem *mmio_base = ap->host_set->mmio_base;
+- u32 tmp;
+-
+- /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
+- writel(0, mmio_base + sil_port[ap->port_no].sien);
+-
+- /* plug IRQ */
+- tmp = readl(mmio_base + SIL_SYSCFG);
+- tmp |= SIL_MASK_IDE0_INT << ap->port_no;
+- writel(tmp, mmio_base + SIL_SYSCFG);
+- readl(mmio_base + SIL_SYSCFG); /* flush */
+-}
+-
+-static void sil_thaw(struct ata_port *ap)
+-{
+- void __iomem *mmio_base = ap->host_set->mmio_base;
+- u32 tmp;
+-
+- /* clear IRQ */
+- ata_chk_status(ap);
+- ata_bmdma_irq_clear(ap);
+-
+- /* turn on SATA IRQ if supported */
+- if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+- writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+-
+- /* turn on IRQ */
+- tmp = readl(mmio_base + SIL_SYSCFG);
+- tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
+- writel(tmp, mmio_base + SIL_SYSCFG);
+-}
+-
+-/**
+- * sil_dev_config - Apply device/host-specific errata fixups
+- * @ap: Port containing device to be examined
+- * @dev: Device to be examined
+- *
+- * After the IDENTIFY [PACKET] DEVICE step is complete, and a
+- * device is known to be present, this function is called.
+- * We apply two errata fixups which are specific to Silicon Image,
+- * a Seagate and a Maxtor fixup.
+- *
+- * For certain Seagate devices, we must limit the maximum sectors
+- * to under 8K.
+- *
+- * For certain Maxtor devices, we must not program the drive
+- * beyond udma5.
+- *
+- * Both fixups are unfairly pessimistic. As soon as I get more
+- * information on these errata, I will create a more exhaustive
+- * list, and apply the fixups to only the specific
+- * devices/hosts/firmwares that need it.
+- *
+- * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
+- * The Maxtor quirk is in the blacklist, but I'm keeping the original
+- * pessimistic fix for the following reasons...
+- * - There seems to be less info on it, only one device gleaned off the
+- * Windows driver, maybe only one is affected. More info would be greatly
+- * appreciated.
+- * - But then again UDMA5 is hardly anything to complain about
+- */
+-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+-{
+- unsigned int n, quirks = 0;
+- unsigned char model_num[41];
+-
+- ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+-
+- for (n = 0; sil_blacklist[n].product; n++)
+- if (!strcmp(sil_blacklist[n].product, model_num)) {
+- quirks = sil_blacklist[n].quirk;
+- break;
+- }
+-
+- /* limit requests to 15 sectors */
+- if (slow_down ||
+- ((ap->flags & SIL_FLAG_MOD15WRITE) &&
+- (quirks & SIL_QUIRK_MOD15WRITE))) {
+- ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix "
+- "(mod15write workaround)\n");
+- dev->max_sectors = 15;
+- return;
+- }
+-
+- /* limit to udma5 */
+- if (quirks & SIL_QUIRK_UDMA5MAX) {
+- ata_dev_printk(dev, KERN_INFO,
+- "applying Maxtor errata fix %s\n", model_num);
+- dev->udma_mask &= ATA_UDMA5;
+- return;
+- }
+-}
+-
+-static void sil_init_controller(struct pci_dev *pdev,
+- int n_ports, unsigned long host_flags,
+- void __iomem *mmio_base)
+-{
+- u8 cls;
+- u32 tmp;
+- int i;
+-
+- /* Initialize FIFO PCI bus arbitration */
+- cls = sil_get_device_cache_line(pdev);
+- if (cls) {
+- cls >>= 3;
+- cls++; /* cls = (line_size/8)+1 */
+- for (i = 0; i < n_ports; i++)
+- writew(cls << 8 | cls,
+- mmio_base + sil_port[i].fifo_cfg);
+- } else
+- dev_printk(KERN_WARNING, &pdev->dev,
+- "cache line size not set. Driver may not function\n");
+-
+- /* Apply R_ERR on DMA activate FIS errata workaround */
+- if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+- int cnt;
+-
+- for (i = 0, cnt = 0; i < n_ports; i++) {
+- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+- if ((tmp & 0x3) != 0x01)
+- continue;
+- if (!cnt)
+- dev_printk(KERN_INFO, &pdev->dev,
+- "Applying R_ERR on DMA activate "
+- "FIS errata fix\n");
+- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+- cnt++;
+- }
+- }
+-
+- if (n_ports == 4) {
+- /* flip the magic "make 4 ports work" bit */
+- tmp = readl(mmio_base + sil_port[2].bmdma);
+- if ((tmp & SIL_INTR_STEERING) == 0)
+- writel(tmp | SIL_INTR_STEERING,
+- mmio_base + sil_port[2].bmdma);
+- }
+-}
+-
+-static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- unsigned long base;
+- void __iomem *mmio_base;
+- int rc;
+- unsigned int i;
+- int pci_dev_busy = 0;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- INIT_LIST_HEAD(&probe_ent->node);
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
+- probe_ent->sht = sil_port_info[ent->driver_data].sht;
+- probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
+- probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
+- probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
+- probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
+-
+- mmio_base = pci_iomap(pdev, 5, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+-
+- probe_ent->mmio_base = mmio_base;
+-
+- base = (unsigned long) mmio_base;
+-
+- for (i = 0; i < probe_ent->n_ports; i++) {
+- probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+- probe_ent->port[i].altstatus_addr =
+- probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
+- probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
+- probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+- ata_std_ports(&probe_ent->port[i]);
+- }
+-
+- sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+- mmio_base);
+-
+- pci_set_master(pdev);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-static int sil_pci_device_resume(struct pci_dev *pdev)
+-{
+- struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+-
+- ata_pci_device_do_resume(pdev);
+- sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
+- host_set->mmio_base);
+- ata_host_set_resume(host_set);
+-
+- return 0;
+-}
+-
+-static int __init sil_init(void)
+-{
+- return pci_module_init(&sil_pci_driver);
+-}
+-
+-static void __exit sil_exit(void)
+-{
+- pci_unregister_driver(&sil_pci_driver);
+-}
+-
+-
+-module_init(sil_init);
+-module_exit(sil_exit);
+diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
+deleted file mode 100644
+index 3f368c7..0000000
+--- a/drivers/scsi/sata_sil24.c
++++ /dev/null
+@@ -1,1222 +0,0 @@
+-/*
+- * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers
+- *
+- * Copyright 2005 Tejun Heo
+- *
+- * Based on preview driver from Silicon Image.
+- *
+- * 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/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-
+-#define DRV_NAME "sata_sil24"
+-#define DRV_VERSION "0.3"
+-
+-/*
+- * Port request block (PRB) 32 bytes
+- */
+-struct sil24_prb {
+- __le16 ctrl;
+- __le16 prot;
+- __le32 rx_cnt;
+- u8 fis[6 * 4];
+-};
+-
+-/*
+- * Scatter gather entry (SGE) 16 bytes
+- */
+-struct sil24_sge {
+- __le64 addr;
+- __le32 cnt;
+- __le32 flags;
+-};
+-
+-/*
+- * Port multiplier
+- */
+-struct sil24_port_multiplier {
+- __le32 diag;
+- __le32 sactive;
+-};
+-
+-enum {
+- /*
+- * Global controller registers (128 bytes @ BAR0)
+- */
+- /* 32 bit regs */
+- HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */
+- HOST_CTRL = 0x40,
+- HOST_IRQ_STAT = 0x44,
+- HOST_PHY_CFG = 0x48,
+- HOST_BIST_CTRL = 0x50,
+- HOST_BIST_PTRN = 0x54,
+- HOST_BIST_STAT = 0x58,
+- HOST_MEM_BIST_STAT = 0x5c,
+- HOST_FLASH_CMD = 0x70,
+- /* 8 bit regs */
+- HOST_FLASH_DATA = 0x74,
+- HOST_TRANSITION_DETECT = 0x75,
+- HOST_GPIO_CTRL = 0x76,
+- HOST_I2C_ADDR = 0x78, /* 32 bit */
+- HOST_I2C_DATA = 0x7c,
+- HOST_I2C_XFER_CNT = 0x7e,
+- HOST_I2C_CTRL = 0x7f,
+-
+- /* HOST_SLOT_STAT bits */
+- HOST_SSTAT_ATTN = (1 << 31),
+-
+- /* HOST_CTRL bits */
+- HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */
+- HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */
+- HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
+- HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
+- HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+- HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
+-
+- /*
+- * Port registers
+- * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
+- */
+- PORT_REGS_SIZE = 0x2000,
+-
+- PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */
+- PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
+-
+- PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
+- /* 32 bit regs */
+- PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */
+- PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */
+- PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */
+- PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */
+- PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */
+- PORT_ACTIVATE_UPPER_ADDR= 0x101c,
+- PORT_EXEC_FIFO = 0x1020, /* command execution fifo */
+- PORT_CMD_ERR = 0x1024, /* command error number */
+- PORT_FIS_CFG = 0x1028,
+- PORT_FIFO_THRES = 0x102c,
+- /* 16 bit regs */
+- PORT_DECODE_ERR_CNT = 0x1040,
+- PORT_DECODE_ERR_THRESH = 0x1042,
+- PORT_CRC_ERR_CNT = 0x1044,
+- PORT_CRC_ERR_THRESH = 0x1046,
+- PORT_HSHK_ERR_CNT = 0x1048,
+- PORT_HSHK_ERR_THRESH = 0x104a,
+- /* 32 bit regs */
+- PORT_PHY_CFG = 0x1050,
+- PORT_SLOT_STAT = 0x1800,
+- PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */
+- PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */
+- PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */
+- PORT_SCONTROL = 0x1f00,
+- PORT_SSTATUS = 0x1f04,
+- PORT_SERROR = 0x1f08,
+- PORT_SACTIVE = 0x1f0c,
+-
+- /* PORT_CTRL_STAT bits */
+- PORT_CS_PORT_RST = (1 << 0), /* port reset */
+- PORT_CS_DEV_RST = (1 << 1), /* device reset */
+- PORT_CS_INIT = (1 << 2), /* port initialize */
+- PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */
+- PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */
+- PORT_CS_RESUME = (1 << 6), /* port resume */
+- PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */
+- PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */
+- PORT_CS_RDY = (1 << 31), /* port ready to accept commands */
+-
+- /* PORT_IRQ_STAT/ENABLE_SET/CLR */
+- /* bits[11:0] are masked */
+- PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */
+- PORT_IRQ_ERROR = (1 << 1), /* command execution error */
+- PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */
+- PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */
+- PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */
+- PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */
+- PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */
+- PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */
+- PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */
+- PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */
+- PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */
+- PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
+-
+- DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
+- PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
+- PORT_IRQ_UNK_FIS,
+-
+- /* bits[27:16] are unmasked (raw) */
+- PORT_IRQ_RAW_SHIFT = 16,
+- PORT_IRQ_MASKED_MASK = 0x7ff,
+- PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT),
+-
+- /* ENABLE_SET/CLR specific, intr steering - 2 bit field */
+- PORT_IRQ_STEER_SHIFT = 30,
+- PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT),
+-
+- /* PORT_CMD_ERR constants */
+- PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */
+- PORT_CERR_SDB = 2, /* Error bit in SDB FIS */
+- PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */
+- PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */
+- PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */
+- PORT_CERR_DIRECTION = 6, /* Data direction mismatch */
+- PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */
+- PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */
+- PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */
+- PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */
+- PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */
+- PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */
+- PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */
+- PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */
+- PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */
+- PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */
+- PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */
+- PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */
+- PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */
+- PORT_CERR_XFR_MSTABRT = 34, /* PSD ecode 10 - master abort */
+- PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */
+- PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */
+-
+- /* bits of PRB control field */
+- PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */
+- PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */
+- PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */
+- PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */
+- PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */
+-
+- /* PRB protocol field */
+- PRB_PROT_PACKET = (1 << 0),
+- PRB_PROT_TCQ = (1 << 1),
+- PRB_PROT_NCQ = (1 << 2),
+- PRB_PROT_READ = (1 << 3),
+- PRB_PROT_WRITE = (1 << 4),
+- PRB_PROT_TRANSPARENT = (1 << 5),
+-
+- /*
+- * Other constants
+- */
+- SGE_TRM = (1 << 31), /* Last SGE in chain */
+- SGE_LNK = (1 << 30), /* linked list
+- Points to SGT, not SGE */
+- SGE_DRD = (1 << 29), /* discard data read (/dev/null)
+- data address ignored */
+-
+- SIL24_MAX_CMDS = 31,
+-
+- /* board id */
+- BID_SIL3124 = 0,
+- BID_SIL3132 = 1,
+- BID_SIL3131 = 2,
+-
+- /* host flags */
+- SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+- ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY,
+- SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
+-
+- IRQ_STAT_4PORTS = 0xf,
+-};
+-
+-struct sil24_ata_block {
+- struct sil24_prb prb;
+- struct sil24_sge sge[LIBATA_MAX_PRD];
+-};
+-
+-struct sil24_atapi_block {
+- struct sil24_prb prb;
+- u8 cdb[16];
+- struct sil24_sge sge[LIBATA_MAX_PRD - 1];
+-};
+-
+-union sil24_cmd_block {
+- struct sil24_ata_block ata;
+- struct sil24_atapi_block atapi;
+-};
+-
+-static struct sil24_cerr_info {
+- unsigned int err_mask, action;
+- const char *desc;
+-} sil24_cerr_db[] = {
+- [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+- "device error" },
+- [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+- "device error via D2H FIS" },
+- [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+- "device error via SDB FIS" },
+- [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
+- "error in data FIS" },
+- [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
+- "failed to transmit command FIS" },
+- [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+- "protocol mismatch" },
+- [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+- "data directon mismatch" },
+- [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+- "ran out of SGEs while writing" },
+- [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+- "ran out of SGEs while reading" },
+- [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+- "invalid data directon for ATAPI CDB" },
+- [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
+- "SGT no on qword boundary" },
+- [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI target abort while fetching SGT" },
+- [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI master abort while fetching SGT" },
+- [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI parity error while fetching SGT" },
+- [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
+- "PRB not on qword boundary" },
+- [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI target abort while fetching PRB" },
+- [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI master abort while fetching PRB" },
+- [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI parity error while fetching PRB" },
+- [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "undefined error while transferring data" },
+- [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI target abort while transferring data" },
+- [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI master abort while transferring data" },
+- [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+- "PCI parity error while transferring data" },
+- [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+- "FIS received while sending service FIS" },
+-};
+-
+-/*
+- * ap->private_data
+- *
+- * The preview driver always returned 0 for status. We emulate it
+- * here from the previous interrupt.
+- */
+-struct sil24_port_priv {
+- union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
+- dma_addr_t cmd_block_dma; /* DMA base addr for them */
+- struct ata_taskfile tf; /* Cached taskfile registers */
+-};
+-
+-/* ap->host_set->private_data */
+-struct sil24_host_priv {
+- void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
+- void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
+-};
+-
+-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
+-static u8 sil24_check_status(struct ata_port *ap);
+-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
+-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+-static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+-static void sil24_qc_prep(struct ata_queued_cmd *qc);
+-static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
+-static void sil24_irq_clear(struct ata_port *ap);
+-static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+-static void sil24_freeze(struct ata_port *ap);
+-static void sil24_thaw(struct ata_port *ap);
+-static void sil24_error_handler(struct ata_port *ap);
+-static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
+-static int sil24_port_start(struct ata_port *ap);
+-static void sil24_port_stop(struct ata_port *ap);
+-static void sil24_host_stop(struct ata_host_set *host_set);
+-static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+-static int sil24_pci_device_resume(struct pci_dev *pdev);
+-
+-static const struct pci_device_id sil24_pci_tbl[] = {
+- { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+- { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+- { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
+- { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+- { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+- { } /* terminate list */
+-};
+-
+-static struct pci_driver sil24_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = sil24_pci_tbl,
+- .probe = sil24_init_one,
+- .remove = ata_pci_remove_one, /* safe? */
+- .suspend = ata_pci_device_suspend,
+- .resume = sil24_pci_device_resume,
+-};
+-
+-static struct scsi_host_template sil24_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .change_queue_depth = ata_scsi_change_queue_depth,
+- .can_queue = SIL24_MAX_CMDS,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+- .suspend = ata_scsi_device_suspend,
+- .resume = ata_scsi_device_resume,
+-};
+-
+-static const struct ata_port_operations sil24_ops = {
+- .port_disable = ata_port_disable,
+-
+- .dev_config = sil24_dev_config,
+-
+- .check_status = sil24_check_status,
+- .check_altstatus = sil24_check_status,
+- .dev_select = ata_noop_dev_select,
+-
+- .tf_read = sil24_tf_read,
+-
+- .qc_prep = sil24_qc_prep,
+- .qc_issue = sil24_qc_issue,
+-
+- .irq_handler = sil24_interrupt,
+- .irq_clear = sil24_irq_clear,
+-
+- .scr_read = sil24_scr_read,
+- .scr_write = sil24_scr_write,
+-
+- .freeze = sil24_freeze,
+- .thaw = sil24_thaw,
+- .error_handler = sil24_error_handler,
+- .post_internal_cmd = sil24_post_internal_cmd,
+-
+- .port_start = sil24_port_start,
+- .port_stop = sil24_port_stop,
+- .host_stop = sil24_host_stop,
+-};
+-
+-/*
+- * Use bits 30-31 of host_flags to encode available port numbers.
+- * Current maxium is 4.
+- */
+-#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
+-#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
+-
+-static struct ata_port_info sil24_port_info[] = {
+- /* sil_3124 */
+- {
+- .sht = &sil24_sht,
+- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
+- SIL24_FLAG_PCIX_IRQ_WOC,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil24_ops,
+- },
+- /* sil_3132 */
+- {
+- .sht = &sil24_sht,
+- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil24_ops,
+- },
+- /* sil_3131/sil_3531 */
+- {
+- .sht = &sil24_sht,
+- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x3f, /* udma0-5 */
+- .port_ops = &sil24_ops,
+- },
+-};
+-
+-static int sil24_tag(int tag)
+-{
+- if (unlikely(ata_tag_internal(tag)))
+- return 0;
+- return tag;
+-}
+-
+-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+-
+- if (dev->cdb_len == 16)
+- writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
+- else
+- writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
+-}
+-
+-static inline void sil24_update_tf(struct ata_port *ap)
+-{
+- struct sil24_port_priv *pp = ap->private_data;
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- struct sil24_prb __iomem *prb = port;
+- u8 fis[6 * 4];
+-
+- memcpy_fromio(fis, prb->fis, 6 * 4);
+- ata_tf_from_fis(fis, &pp->tf);
+-}
+-
+-static u8 sil24_check_status(struct ata_port *ap)
+-{
+- struct sil24_port_priv *pp = ap->private_data;
+- return pp->tf.command;
+-}
+-
+-static int sil24_scr_map[] = {
+- [SCR_CONTROL] = 0,
+- [SCR_STATUS] = 1,
+- [SCR_ERROR] = 2,
+- [SCR_ACTIVE] = 3,
+-};
+-
+-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+-{
+- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+- if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
+- void __iomem *addr;
+- addr = scr_addr + sil24_scr_map[sc_reg] * 4;
+- return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+- }
+- return 0xffffffffU;
+-}
+-
+-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+-{
+- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+- if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
+- void __iomem *addr;
+- addr = scr_addr + sil24_scr_map[sc_reg] * 4;
+- writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+- }
+-}
+-
+-static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- struct sil24_port_priv *pp = ap->private_data;
+- *tf = pp->tf;
+-}
+-
+-static int sil24_init_port(struct ata_port *ap)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- u32 tmp;
+-
+- writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
+- ata_wait_register(port + PORT_CTRL_STAT,
+- PORT_CS_INIT, PORT_CS_INIT, 10, 100);
+- tmp = ata_wait_register(port + PORT_CTRL_STAT,
+- PORT_CS_RDY, 0, 10, 100);
+-
+- if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+- return -EIO;
+- return 0;
+-}
+-
+-static int sil24_softreset(struct ata_port *ap, unsigned int *class)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- struct sil24_port_priv *pp = ap->private_data;
+- struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
+- dma_addr_t paddr = pp->cmd_block_dma;
+- u32 mask, irq_stat;
+- const char *reason;
+-
+- DPRINTK("ENTER\n");
+-
+- if (ata_port_offline(ap)) {
+- DPRINTK("PHY reports no device\n");
+- *class = ATA_DEV_NONE;
+- goto out;
+- }
+-
+- /* put the port into known state */
+- if (sil24_init_port(ap)) {
+- reason ="port not ready";
+- goto err;
+- }
+-
+- /* do SRST */
+- prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
+- prb->fis[1] = 0; /* no PM yet */
+-
+- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+-
+- mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
+- 100, ATA_TMOUT_BOOT / HZ * 1000);
+-
+- writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
+- irq_stat >>= PORT_IRQ_RAW_SHIFT;
+-
+- if (!(irq_stat & PORT_IRQ_COMPLETE)) {
+- if (irq_stat & PORT_IRQ_ERROR)
+- reason = "SRST command error";
+- else
+- reason = "timeout";
+- goto err;
+- }
+-
+- sil24_update_tf(ap);
+- *class = ata_dev_classify(&pp->tf);
+-
+- if (*class == ATA_DEV_UNKNOWN)
+- *class = ATA_DEV_NONE;
+-
+- out:
+- DPRINTK("EXIT, class=%u\n", *class);
+- return 0;
+-
+- err:
+- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+- return -EIO;
+-}
+-
+-static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- const char *reason;
+- int tout_msec, rc;
+- u32 tmp;
+-
+- /* sil24 does the right thing(tm) without any protection */
+- sata_set_spd(ap);
+-
+- tout_msec = 100;
+- if (ata_port_online(ap))
+- tout_msec = 5000;
+-
+- writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
+- tmp = ata_wait_register(port + PORT_CTRL_STAT,
+- PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
+-
+- /* SStatus oscillates between zero and valid status after
+- * DEV_RST, debounce it.
+- */
+- rc = sata_phy_debounce(ap, sata_deb_timing_long);
+- if (rc) {
+- reason = "PHY debouncing failed";
+- goto err;
+- }
+-
+- if (tmp & PORT_CS_DEV_RST) {
+- if (ata_port_offline(ap))
+- return 0;
+- reason = "link not ready";
+- goto err;
+- }
+-
+- /* Sil24 doesn't store signature FIS after hardreset, so we
+- * can't wait for BSY to clear. Some devices take a long time
+- * to get ready and those devices will choke if we don't wait
+- * for BSY clearance here. Tell libata to perform follow-up
+- * softreset.
+- */
+- return -EAGAIN;
+-
+- err:
+- ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+- return -EIO;
+-}
+-
+-static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
+- struct sil24_sge *sge)
+-{
+- struct scatterlist *sg;
+- unsigned int idx = 0;
+-
+- ata_for_each_sg(sg, qc) {
+- sge->addr = cpu_to_le64(sg_dma_address(sg));
+- sge->cnt = cpu_to_le32(sg_dma_len(sg));
+- if (ata_sg_is_last(sg, qc))
+- sge->flags = cpu_to_le32(SGE_TRM);
+- else
+- sge->flags = 0;
+-
+- sge++;
+- idx++;
+- }
+-}
+-
+-static void sil24_qc_prep(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct sil24_port_priv *pp = ap->private_data;
+- union sil24_cmd_block *cb;
+- struct sil24_prb *prb;
+- struct sil24_sge *sge;
+- u16 ctrl = 0;
+-
+- cb = &pp->cmd_block[sil24_tag(qc->tag)];
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_PIO:
+- case ATA_PROT_DMA:
+- case ATA_PROT_NCQ:
+- case ATA_PROT_NODATA:
+- prb = &cb->ata.prb;
+- sge = cb->ata.sge;
+- break;
+-
+- case ATA_PROT_ATAPI:
+- case ATA_PROT_ATAPI_DMA:
+- case ATA_PROT_ATAPI_NODATA:
+- prb = &cb->atapi.prb;
+- sge = cb->atapi.sge;
+- memset(cb->atapi.cdb, 0, 32);
+- memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
+-
+- if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
+- if (qc->tf.flags & ATA_TFLAG_WRITE)
+- ctrl = PRB_CTRL_PACKET_WRITE;
+- else
+- ctrl = PRB_CTRL_PACKET_READ;
+- }
+- break;
+-
+- default:
+- prb = NULL; /* shut up, gcc */
+- sge = NULL;
+- BUG();
+- }
+-
+- prb->ctrl = cpu_to_le16(ctrl);
+- ata_tf_to_fis(&qc->tf, prb->fis, 0);
+-
+- if (qc->flags & ATA_QCFLAG_DMAMAP)
+- sil24_fill_sg(qc, sge);
+-}
+-
+-static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct sil24_port_priv *pp = ap->private_data;
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- unsigned int tag = sil24_tag(qc->tag);
+- dma_addr_t paddr;
+- void __iomem *activate;
+-
+- paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
+- activate = port + PORT_CMD_ACTIVATE + tag * 8;
+-
+- writel((u32)paddr, activate);
+- writel((u64)paddr >> 32, activate + 4);
+-
+- return 0;
+-}
+-
+-static void sil24_irq_clear(struct ata_port *ap)
+-{
+- /* unused */
+-}
+-
+-static void sil24_freeze(struct ata_port *ap)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+-
+- /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
+- * PORT_IRQ_ENABLE instead.
+- */
+- writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
+-}
+-
+-static void sil24_thaw(struct ata_port *ap)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- u32 tmp;
+-
+- /* clear IRQ */
+- tmp = readl(port + PORT_IRQ_STAT);
+- writel(tmp, port + PORT_IRQ_STAT);
+-
+- /* turn IRQ back on */
+- writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET);
+-}
+-
+-static void sil24_error_intr(struct ata_port *ap)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- struct ata_eh_info *ehi = &ap->eh_info;
+- int freeze = 0;
+- u32 irq_stat;
+-
+- /* on error, we need to clear IRQ explicitly */
+- irq_stat = readl(port + PORT_IRQ_STAT);
+- writel(irq_stat, port + PORT_IRQ_STAT);
+-
+- /* first, analyze and record host port events */
+- ata_ehi_clear_desc(ehi);
+-
+- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+-
+- if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
+- ata_ehi_hotplugged(ehi);
+- ata_ehi_push_desc(ehi, ", %s",
+- irq_stat & PORT_IRQ_PHYRDY_CHG ?
+- "PHY RDY changed" : "device exchanged");
+- freeze = 1;
+- }
+-
+- if (irq_stat & PORT_IRQ_UNK_FIS) {
+- ehi->err_mask |= AC_ERR_HSM;
+- ehi->action |= ATA_EH_SOFTRESET;
+- ata_ehi_push_desc(ehi , ", unknown FIS");
+- freeze = 1;
+- }
+-
+- /* deal with command error */
+- if (irq_stat & PORT_IRQ_ERROR) {
+- struct sil24_cerr_info *ci = NULL;
+- unsigned int err_mask = 0, action = 0;
+- struct ata_queued_cmd *qc;
+- u32 cerr;
+-
+- /* analyze CMD_ERR */
+- cerr = readl(port + PORT_CMD_ERR);
+- if (cerr < ARRAY_SIZE(sil24_cerr_db))
+- ci = &sil24_cerr_db[cerr];
+-
+- if (ci && ci->desc) {
+- err_mask |= ci->err_mask;
+- action |= ci->action;
+- ata_ehi_push_desc(ehi, ", %s", ci->desc);
+- } else {
+- err_mask |= AC_ERR_OTHER;
+- action |= ATA_EH_SOFTRESET;
+- ata_ehi_push_desc(ehi, ", unknown command error %d",
+- cerr);
+- }
+-
+- /* record error info */
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc) {
+- sil24_update_tf(ap);
+- qc->err_mask |= err_mask;
+- } else
+- ehi->err_mask |= err_mask;
+-
+- ehi->action |= action;
+- }
+-
+- /* freeze or abort */
+- if (freeze)
+- ata_port_freeze(ap);
+- else
+- ata_port_abort(ap);
+-}
+-
+-static void sil24_finish_qc(struct ata_queued_cmd *qc)
+-{
+- if (qc->flags & ATA_QCFLAG_RESULT_TF)
+- sil24_update_tf(qc->ap);
+-}
+-
+-static inline void sil24_host_intr(struct ata_port *ap)
+-{
+- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+- u32 slot_stat, qc_active;
+- int rc;
+-
+- slot_stat = readl(port + PORT_SLOT_STAT);
+-
+- if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
+- sil24_error_intr(ap);
+- return;
+- }
+-
+- if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+- writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
+-
+- qc_active = slot_stat & ~HOST_SSTAT_ATTN;
+- rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
+- if (rc > 0)
+- return;
+- if (rc < 0) {
+- struct ata_eh_info *ehi = &ap->eh_info;
+- ehi->err_mask |= AC_ERR_HSM;
+- ehi->action |= ATA_EH_SOFTRESET;
+- ata_port_freeze(ap);
+- return;
+- }
+-
+- if (ata_ratelimit())
+- ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+- "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+- slot_stat, ap->active_tag, ap->sactive);
+-}
+-
+-static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- struct sil24_host_priv *hpriv = host_set->private_data;
+- unsigned handled = 0;
+- u32 status;
+- int i;
+-
+- status = readl(hpriv->host_base + HOST_IRQ_STAT);
+-
+- if (status == 0xffffffff) {
+- printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, "
+- "PCI fault or device removal?\n");
+- goto out;
+- }
+-
+- if (!(status & IRQ_STAT_4PORTS))
+- goto out;
+-
+- spin_lock(&host_set->lock);
+-
+- for (i = 0; i < host_set->n_ports; i++)
+- if (status & (1 << i)) {
+- struct ata_port *ap = host_set->ports[i];
+- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+- sil24_host_intr(host_set->ports[i]);
+- handled++;
+- } else
+- printk(KERN_ERR DRV_NAME
+- ": interrupt from disabled port %d\n", i);
+- }
+-
+- spin_unlock(&host_set->lock);
+- out:
+- return IRQ_RETVAL(handled);
+-}
+-
+-static void sil24_error_handler(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+-
+- if (sil24_init_port(ap)) {
+- ata_eh_freeze_port(ap);
+- ehc->i.action |= ATA_EH_HARDRESET;
+- }
+-
+- /* perform recovery */
+- ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+- ata_std_postreset);
+-}
+-
+-static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+-
+- if (qc->flags & ATA_QCFLAG_FAILED)
+- qc->err_mask |= AC_ERR_OTHER;
+-
+- /* make DMA engine forget about the failed command */
+- if (qc->err_mask)
+- sil24_init_port(ap);
+-}
+-
+-static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
+-{
+- const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
+-
+- dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
+-}
+-
+-static int sil24_port_start(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct sil24_port_priv *pp;
+- union sil24_cmd_block *cb;
+- size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
+- dma_addr_t cb_dma;
+- int rc = -ENOMEM;
+-
+- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+- if (!pp)
+- goto err_out;
+-
+- pp->tf.command = ATA_DRDY;
+-
+- cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
+- if (!cb)
+- goto err_out_pp;
+- memset(cb, 0, cb_size);
+-
+- rc = ata_pad_alloc(ap, dev);
+- if (rc)
+- goto err_out_pad;
+-
+- pp->cmd_block = cb;
+- pp->cmd_block_dma = cb_dma;
+-
+- ap->private_data = pp;
+-
+- return 0;
+-
+-err_out_pad:
+- sil24_cblk_free(pp, dev);
+-err_out_pp:
+- kfree(pp);
+-err_out:
+- return rc;
+-}
+-
+-static void sil24_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct sil24_port_priv *pp = ap->private_data;
+-
+- sil24_cblk_free(pp, dev);
+- ata_pad_free(ap, dev);
+- kfree(pp);
+-}
+-
+-static void sil24_host_stop(struct ata_host_set *host_set)
+-{
+- struct sil24_host_priv *hpriv = host_set->private_data;
+- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+-
+- pci_iounmap(pdev, hpriv->host_base);
+- pci_iounmap(pdev, hpriv->port_base);
+- kfree(hpriv);
+-}
+-
+-static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+- unsigned long host_flags,
+- void __iomem *host_base,
+- void __iomem *port_base)
+-{
+- u32 tmp;
+- int i;
+-
+- /* GPIO off */
+- writel(0, host_base + HOST_FLASH_CMD);
+-
+- /* clear global reset & mask interrupts during initialization */
+- writel(0, host_base + HOST_CTRL);
+-
+- /* init ports */
+- for (i = 0; i < n_ports; i++) {
+- void __iomem *port = port_base + i * PORT_REGS_SIZE;
+-
+- /* Initial PHY setting */
+- writel(0x20c, port + PORT_PHY_CFG);
+-
+- /* Clear port RST */
+- tmp = readl(port + PORT_CTRL_STAT);
+- if (tmp & PORT_CS_PORT_RST) {
+- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+- tmp = ata_wait_register(port + PORT_CTRL_STAT,
+- PORT_CS_PORT_RST,
+- PORT_CS_PORT_RST, 10, 100);
+- if (tmp & PORT_CS_PORT_RST)
+- dev_printk(KERN_ERR, &pdev->dev,
+- "failed to clear port RST\n");
+- }
+-
+- /* Configure IRQ WoC */
+- if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+- else
+- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+-
+- /* Zero error counters. */
+- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+- writel(0x8000, port + PORT_CRC_ERR_THRESH);
+- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+- writel(0x0000, port + PORT_DECODE_ERR_CNT);
+- writel(0x0000, port + PORT_CRC_ERR_CNT);
+- writel(0x0000, port + PORT_HSHK_ERR_CNT);
+-
+- /* Always use 64bit activation */
+- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+-
+- /* Clear port multiplier enable and resume bits */
+- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+- }
+-
+- /* Turn on interrupts */
+- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+-}
+-
+-static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version = 0;
+- unsigned int board_id = (unsigned int)ent->driver_data;
+- struct ata_port_info *pinfo = &sil24_port_info[board_id];
+- struct ata_probe_ent *probe_ent = NULL;
+- struct sil24_host_priv *hpriv = NULL;
+- void __iomem *host_base = NULL;
+- void __iomem *port_base = NULL;
+- int i, rc;
+- u32 tmp;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc)
+- goto out_disable;
+-
+- rc = -ENOMEM;
+- /* map mmio registers */
+- host_base = pci_iomap(pdev, 0, 0);
+- if (!host_base)
+- goto out_free;
+- port_base = pci_iomap(pdev, 2, 0);
+- if (!port_base)
+- goto out_free;
+-
+- /* allocate & init probe_ent and hpriv */
+- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (!probe_ent)
+- goto out_free;
+-
+- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv)
+- goto out_free;
+-
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- probe_ent->sht = pinfo->sht;
+- probe_ent->host_flags = pinfo->host_flags;
+- probe_ent->pio_mask = pinfo->pio_mask;
+- probe_ent->mwdma_mask = pinfo->mwdma_mask;
+- probe_ent->udma_mask = pinfo->udma_mask;
+- probe_ent->port_ops = pinfo->port_ops;
+- probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags);
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->private_data = hpriv;
+-
+- hpriv->host_base = host_base;
+- hpriv->port_base = port_base;
+-
+- /*
+- * Configure the device
+- */
+- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+- if (rc) {
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "64-bit DMA enable failed\n");
+- goto out_free;
+- }
+- }
+- } else {
+- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit DMA enable failed\n");
+- goto out_free;
+- }
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "32-bit consistent DMA enable failed\n");
+- goto out_free;
+- }
+- }
+-
+- /* Apply workaround for completion IRQ loss on PCI-X errata */
+- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+- tmp = readl(host_base + HOST_CTRL);
+- if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
+- dev_printk(KERN_INFO, &pdev->dev,
+- "Applying completion IRQ loss on PCI-X "
+- "errata fix\n");
+- else
+- probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+- }
+-
+- for (i = 0; i < probe_ent->n_ports; i++) {
+- unsigned long portu =
+- (unsigned long)port_base + i * PORT_REGS_SIZE;
+-
+- probe_ent->port[i].cmd_addr = portu;
+- probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
+-
+- ata_std_ports(&probe_ent->port[i]);
+- }
+-
+- sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+- host_base, port_base);
+-
+- pci_set_master(pdev);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+-
+- kfree(probe_ent);
+- return 0;
+-
+- out_free:
+- if (host_base)
+- pci_iounmap(pdev, host_base);
+- if (port_base)
+- pci_iounmap(pdev, port_base);
+- kfree(probe_ent);
+- kfree(hpriv);
+- pci_release_regions(pdev);
+- out_disable:
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-static int sil24_pci_device_resume(struct pci_dev *pdev)
+-{
+- struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+- struct sil24_host_priv *hpriv = host_set->private_data;
+-
+- ata_pci_device_do_resume(pdev);
+-
+- if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+- writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+-
+- sil24_init_controller(pdev, host_set->n_ports,
+- host_set->ports[0]->flags,
+- hpriv->host_base, hpriv->port_base);
+-
+- ata_host_set_resume(host_set);
+-
+- return 0;
+-}
+-
+-static int __init sil24_init(void)
+-{
+- return pci_module_init(&sil24_pci_driver);
+-}
+-
+-static void __exit sil24_exit(void)
+-{
+- pci_unregister_driver(&sil24_pci_driver);
+-}
+-
+-MODULE_AUTHOR("Tejun Heo");
+-MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, sil24_pci_tbl);
+-
+-module_init(sil24_init);
+-module_exit(sil24_exit);
+diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
+deleted file mode 100644
+index ee6b5df..0000000
+--- a/drivers/scsi/sata_sis.c
++++ /dev/null
+@@ -1,347 +0,0 @@
+-/*
+- * sata_sis.c - Silicon Integrated Systems SATA
+- *
+- * Maintained by: Uwe Koziolek
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2004 Uwe Koziolek
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available under NDA.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "sata_sis"
+-#define DRV_VERSION "0.6"
+-
+-enum {
+- sis_180 = 0,
+- SIS_SCR_PCI_BAR = 5,
+-
+- /* PCI configuration registers */
+- SIS_GENCTL = 0x54, /* IDE General Control register */
+- SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */
+- SIS180_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */
+- SIS182_SATA1_OFS = 0x20, /* offset from sata0->sata1 phy regs */
+- SIS_PMR = 0x90, /* port mapping register */
+- SIS_PMR_COMBINED = 0x30,
+-
+- /* random bits */
+- SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */
+-
+- GENCTL_IOMAPPED_SCR = (1 << 26), /* if set, SCRs are in IO space */
+-};
+-
+-static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-
+-static const struct pci_device_id sis_pci_tbl[] = {
+- { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+- { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+- { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+- { } /* terminate list */
+-};
+-
+-
+-static struct pci_driver sis_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = sis_pci_tbl,
+- .probe = sis_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static struct scsi_host_template sis_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = ATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations sis_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_pio_data_xfer,
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = ata_bmdma_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = sis_scr_read,
+- .scr_write = sis_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_host_stop,
+-};
+-
+-static struct ata_port_info sis_port_info = {
+- .sht = &sis_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+- .pio_mask = 0x1f,
+- .mwdma_mask = 0x7,
+- .udma_mask = 0x7f,
+- .port_ops = &sis_ops,
+-};
+-
+-
+-MODULE_AUTHOR("Uwe Koziolek");
+-MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
+-{
+- unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+-
+- if (port_no) {
+- if (device == 0x182)
+- addr += SIS182_SATA1_OFS;
+- else
+- addr += SIS180_SATA1_OFS;
+- }
+-
+- return addr;
+-}
+-
+-static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
+- u32 val, val2 = 0;
+- u8 pmr;
+-
+- if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
+- return 0xffffffff;
+-
+- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+-
+- pci_read_config_dword(pdev, cfg_addr, &val);
+-
+- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+- pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
+-
+- return val|val2;
+-}
+-
+-static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
+- u8 pmr;
+-
+- if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+- return;
+-
+- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+-
+- pci_write_config_dword(pdev, cfg_addr, val);
+-
+- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+- pci_write_config_dword(pdev, cfg_addr+0x10, val);
+-}
+-
+-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- u32 val, val2 = 0;
+- u8 pmr;
+-
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+-
+- if (ap->flags & SIS_FLAG_CFGSCR)
+- return sis_scr_cfg_read(ap, sc_reg);
+-
+- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+-
+- val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+-
+- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+- val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+-
+- return val | val2;
+-}
+-
+-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- u8 pmr;
+-
+- if (sc_reg > SCR_CONTROL)
+- return;
+-
+- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+-
+- if (ap->flags & SIS_FLAG_CFGSCR)
+- sis_scr_cfg_write(ap, sc_reg, val);
+- else {
+- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+- }
+-}
+-
+-static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- int rc;
+- u32 genctl;
+- struct ata_port_info *ppi;
+- int pci_dev_busy = 0;
+- u8 pmr;
+- u8 port2_start;
+-
+- if (!printed_version++)
+- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- ppi = &sis_port_info;
+- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+- if (!probe_ent) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- /* check and see if the SCRs are in IO space or PCI cfg space */
+- pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
+- if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
+- probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+-
+- /* if hardware thinks SCRs are in IO space, but there are
+- * no IO resources assigned, change to PCI cfg space.
+- */
+- if ((!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) &&
+- ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
+- (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
+- genctl &= ~GENCTL_IOMAPPED_SCR;
+- pci_write_config_dword(pdev, SIS_GENCTL, genctl);
+- probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+- }
+-
+- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+- if (ent->device != 0x182) {
+- if ((pmr & SIS_PMR_COMBINED) == 0) {
+- dev_printk(KERN_INFO, &pdev->dev,
+- "Detected SiS 180/181 chipset in SATA mode\n");
+- port2_start = 64;
+- }
+- else {
+- dev_printk(KERN_INFO, &pdev->dev,
+- "Detected SiS 180/181 chipset in combined mode\n");
+- port2_start=0;
+- }
+- }
+- else {
+- dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n");
+- port2_start = 0x20;
+- }
+-
+- if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
+- probe_ent->port[0].scr_addr =
+- pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+- probe_ent->port[1].scr_addr =
+- pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
+- }
+-
+- pci_set_master(pdev);
+- pci_intx(pdev, 1);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_regions:
+- pci_release_regions(pdev);
+-
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-
+-}
+-
+-static int __init sis_init(void)
+-{
+- return pci_module_init(&sis_pci_driver);
+-}
+-
+-static void __exit sis_exit(void)
+-{
+- pci_unregister_driver(&sis_pci_driver);
+-}
+-
+-module_init(sis_init);
+-module_exit(sis_exit);
+-
+diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
+deleted file mode 100644
+index 7d08580..0000000
+--- a/drivers/scsi/sata_svw.c
++++ /dev/null
+@@ -1,508 +0,0 @@
+-/*
+- * sata_svw.c - ServerWorks / Apple K2 SATA
+- *
+- * Maintained by: Benjamin Herrenschmidt <benh at kernel.crashing.org> and
+- * Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003 Benjamin Herrenschmidt <benh at kernel.crashing.org>
+- *
+- * Bits from Jeff Garzik, Copyright RedHat, Inc.
+- *
+- * This driver probably works with non-Apple versions of the
+- * Broadcom chipset...
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available under NDA.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#ifdef CONFIG_PPC_OF
+-#include <asm/prom.h>
+-#include <asm/pci-bridge.h>
+-#endif /* CONFIG_PPC_OF */
+-
+-#define DRV_NAME "sata_svw"
+-#define DRV_VERSION "2.0"
+-
+-enum {
+- /* Taskfile registers offsets */
+- K2_SATA_TF_CMD_OFFSET = 0x00,
+- K2_SATA_TF_DATA_OFFSET = 0x00,
+- K2_SATA_TF_ERROR_OFFSET = 0x04,
+- K2_SATA_TF_NSECT_OFFSET = 0x08,
+- K2_SATA_TF_LBAL_OFFSET = 0x0c,
+- K2_SATA_TF_LBAM_OFFSET = 0x10,
+- K2_SATA_TF_LBAH_OFFSET = 0x14,
+- K2_SATA_TF_DEVICE_OFFSET = 0x18,
+- K2_SATA_TF_CMDSTAT_OFFSET = 0x1c,
+- K2_SATA_TF_CTL_OFFSET = 0x20,
+-
+- /* DMA base */
+- K2_SATA_DMA_CMD_OFFSET = 0x30,
+-
+- /* SCRs base */
+- K2_SATA_SCR_STATUS_OFFSET = 0x40,
+- K2_SATA_SCR_ERROR_OFFSET = 0x44,
+- K2_SATA_SCR_CONTROL_OFFSET = 0x48,
+-
+- /* Others */
+- K2_SATA_SICR1_OFFSET = 0x80,
+- K2_SATA_SICR2_OFFSET = 0x84,
+- K2_SATA_SIM_OFFSET = 0x88,
+-
+- /* Port stride */
+- K2_SATA_PORT_OFFSET = 0x100,
+-};
+-
+-static u8 k2_stat_check_status(struct ata_port *ap);
+-
+-
+-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+- return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-
+-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+- u32 val)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return;
+- writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-
+-static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+-
+- if (tf->ctl != ap->last_ctl) {
+- writeb(tf->ctl, ioaddr->ctl_addr);
+- ap->last_ctl = tf->ctl;
+- ata_wait_idle(ap);
+- }
+- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+- writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+- writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+- writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+- writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+- writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+- } else if (is_addr) {
+- writew(tf->feature, ioaddr->feature_addr);
+- writew(tf->nsect, ioaddr->nsect_addr);
+- writew(tf->lbal, ioaddr->lbal_addr);
+- writew(tf->lbam, ioaddr->lbam_addr);
+- writew(tf->lbah, ioaddr->lbah_addr);
+- }
+-
+- if (tf->flags & ATA_TFLAG_DEVICE)
+- writeb(tf->device, ioaddr->device_addr);
+-
+- ata_wait_idle(ap);
+-}
+-
+-
+-static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- u16 nsect, lbal, lbam, lbah, feature;
+-
+- tf->command = k2_stat_check_status(ap);
+- tf->device = readw(ioaddr->device_addr);
+- feature = readw(ioaddr->error_addr);
+- nsect = readw(ioaddr->nsect_addr);
+- lbal = readw(ioaddr->lbal_addr);
+- lbam = readw(ioaddr->lbam_addr);
+- lbah = readw(ioaddr->lbah_addr);
+-
+- tf->feature = feature;
+- tf->nsect = nsect;
+- tf->lbal = lbal;
+- tf->lbam = lbam;
+- tf->lbah = lbah;
+-
+- if (tf->flags & ATA_TFLAG_LBA48) {
+- tf->hob_feature = feature >> 8;
+- tf->hob_nsect = nsect >> 8;
+- tf->hob_lbal = lbal >> 8;
+- tf->hob_lbam = lbam >> 8;
+- tf->hob_lbah = lbah >> 8;
+- }
+-}
+-
+-/**
+- * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
+- * @qc: Info associated with this ATA transaction.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+- u8 dmactl;
+- void *mmio = (void *) ap->ioaddr.bmdma_addr;
+- /* load PRD table addr. */
+- mb(); /* make sure PRD table writes are visible to controller */
+- writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+-
+- /* specify data direction, triple-check start bit is clear */
+- dmactl = readb(mmio + ATA_DMA_CMD);
+- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+- if (!rw)
+- dmactl |= ATA_DMA_WR;
+- writeb(dmactl, mmio + ATA_DMA_CMD);
+-
+- /* issue r/w command if this is not a ATA DMA command*/
+- if (qc->tf.protocol != ATA_PROT_DMA)
+- ap->ops->exec_command(ap, &qc->tf);
+-}
+-
+-/**
+- * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
+- * @qc: Info associated with this ATA transaction.
+- *
+- * LOCKING:
+- * spin_lock_irqsave(host_set lock)
+- */
+-
+-static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- void *mmio = (void *) ap->ioaddr.bmdma_addr;
+- u8 dmactl;
+-
+- /* start host DMA transaction */
+- dmactl = readb(mmio + ATA_DMA_CMD);
+- writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+- /* There is a race condition in certain SATA controllers that can
+- be seen when the r/w command is given to the controller before the
+- host DMA is started. On a Read command, the controller would initiate
+- the command to the drive even before it sees the DMA start. When there
+- are very fast drives connected to the controller, or when the data request
+- hits in the drive cache, there is the possibility that the drive returns a part
+- or all of the requested data to the controller before the DMA start is issued.
+- In this case, the controller would become confused as to what to do with the data.
+- In the worst case when all the data is returned back to the controller, the
+- controller could hang. In other cases it could return partial data returning
+- in data corruption. This problem has been seen in PPC systems and can also appear
+- on an system with very fast disks, where the SATA controller is sitting behind a
+- number of bridges, and hence there is significant latency between the r/w command
+- and the start command. */
+- /* issue r/w command if the access is to ATA*/
+- if (qc->tf.protocol == ATA_PROT_DMA)
+- ap->ops->exec_command(ap, &qc->tf);
+-}
+-
+-
+-static u8 k2_stat_check_status(struct ata_port *ap)
+-{
+- return readl((void *) ap->ioaddr.status_addr);
+-}
+-
+-#ifdef CONFIG_PPC_OF
+-/*
+- * k2_sata_proc_info
+- * inout : decides on the direction of the dataflow and the meaning of the
+- * variables
+- * buffer: If inout==FALSE data is being written to it else read from it
+- * *start: If inout==FALSE start of the valid data in the buffer
+- * offset: If inout==FALSE offset from the beginning of the imaginary file
+- * from which we start writing into the buffer
+- * length: If inout==FALSE max number of bytes to be written into the buffer
+- * else number of bytes in the buffer
+- */
+-static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
+- off_t offset, int count, int inout)
+-{
+- struct ata_port *ap;
+- struct device_node *np;
+- int len, index;
+-
+- /* Find the ata_port */
+- ap = ata_shost_to_port(shost);
+- if (ap == NULL)
+- return 0;
+-
+- /* Find the OF node for the PCI device proper */
+- np = pci_device_to_OF_node(to_pci_dev(ap->host_set->dev));
+- if (np == NULL)
+- return 0;
+-
+- /* Match it to a port node */
+- index = (ap == ap->host_set->ports[0]) ? 0 : 1;
+- for (np = np->child; np != NULL; np = np->sibling) {
+- u32 *reg = (u32 *)get_property(np, "reg", NULL);
+- if (!reg)
+- continue;
+- if (index == *reg)
+- break;
+- }
+- if (np == NULL)
+- return 0;
+-
+- len = sprintf(page, "devspec: %s\n", np->full_name);
+-
+- return len;
+-}
+-#endif /* CONFIG_PPC_OF */
+-
+-
+-static struct scsi_host_template k2_sata_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+-#ifdef CONFIG_PPC_OF
+- .proc_info = k2_sata_proc_info,
+-#endif
+- .bios_param = ata_std_bios_param,
+-};
+-
+-
+-static const struct ata_port_operations k2_sata_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = k2_sata_tf_load,
+- .tf_read = k2_sata_tf_read,
+- .check_status = k2_stat_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+- .bmdma_setup = k2_bmdma_setup_mmio,
+- .bmdma_start = k2_bmdma_start_mmio,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_mmio_data_xfer,
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = ata_bmdma_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = k2_sata_scr_read,
+- .scr_write = k2_sata_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_pci_host_stop,
+-};
+-
+-static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
+-{
+- port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
+- port->data_addr = base + K2_SATA_TF_DATA_OFFSET;
+- port->feature_addr =
+- port->error_addr = base + K2_SATA_TF_ERROR_OFFSET;
+- port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET;
+- port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET;
+- port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET;
+- port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET;
+- port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET;
+- port->command_addr =
+- port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET;
+- port->altstatus_addr =
+- port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET;
+- port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET;
+- port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET;
+-}
+-
+-
+-static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- unsigned long base;
+- void __iomem *mmio_base;
+- int pci_dev_busy = 0;
+- int rc;
+- int i;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- /*
+- * If this driver happens to only be useful on Apple's K2, then
+- * we should check that here as it has a normal Serverworks ID
+- */
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+- /*
+- * Check if we have resources mapped at all (second function may
+- * have been disabled by firmware)
+- */
+- if (pci_resource_len(pdev, 5) == 0)
+- return -ENODEV;
+-
+- /* Request PCI regions */
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- mmio_base = pci_iomap(pdev, 5, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+- base = (unsigned long) mmio_base;
+-
+- /* Clear a magic bit in SCR1 according to Darwin, those help
+- * some funky seagate drives (though so far, those were already
+- * set by the firmware on the machines I had access to)
+- */
+- writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
+- mmio_base + K2_SATA_SICR1_OFFSET);
+-
+- /* Clear SATA error & interrupts we don't use */
+- writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
+- writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
+-
+- probe_ent->sht = &k2_sata_sht;
+- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_MMIO;
+- probe_ent->port_ops = &k2_sata_ops;
+- probe_ent->n_ports = 4;
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+-
+- /* We don't care much about the PIO/UDMA masks, but the core won't like us
+- * if we don't fill these
+- */
+- probe_ent->pio_mask = 0x1f;
+- probe_ent->mwdma_mask = 0x7;
+- probe_ent->udma_mask = 0x7f;
+-
+- /* different controllers have different number of ports - currently 4 or 8 */
+- /* All ports are on the same function. Multi-function device is no
+- * longer available. This should not be seen in any system. */
+- for (i = 0; i < ent->driver_data; i++)
+- k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
+-
+- pci_set_master(pdev);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-/* 0x240 is device ID for Apple K2 device
+- * 0x241 is device ID for Serverworks Frodo4
+- * 0x242 is device ID for Serverworks Frodo8
+- * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA
+- * controller
+- * */
+-static const struct pci_device_id k2_sata_pci_tbl[] = {
+- { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+- { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+- { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+- { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+- { 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+- { }
+-};
+-
+-
+-static struct pci_driver k2_sata_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = k2_sata_pci_tbl,
+- .probe = k2_sata_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-
+-static int __init k2_sata_init(void)
+-{
+- return pci_module_init(&k2_sata_pci_driver);
+-}
+-
+-
+-static void __exit k2_sata_exit(void)
+-{
+- pci_unregister_driver(&k2_sata_pci_driver);
+-}
+-
+-
+-MODULE_AUTHOR("Benjamin Herrenschmidt");
+-MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(k2_sata_init);
+-module_exit(k2_sata_exit);
+diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
+deleted file mode 100644
+index ccc8cad..0000000
+--- a/drivers/scsi/sata_sx4.c
++++ /dev/null
+@@ -1,1502 +0,0 @@
+-/*
+- * sata_sx4.c - Promise SATA
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2003-2004 Red Hat, Inc.
+- *
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available under NDA.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/sched.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-#include "sata_promise.h"
+-
+-#define DRV_NAME "sata_sx4"
+-#define DRV_VERSION "0.9"
+-
+-
+-enum {
+- PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
+-
+- PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
+- PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
+- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+- PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
+-
+- PDC_20621_SEQCTL = 0x400,
+- PDC_20621_SEQMASK = 0x480,
+- PDC_20621_GENERAL_CTL = 0x484,
+- PDC_20621_PAGE_SIZE = (32 * 1024),
+-
+- /* chosen, not constant, values; we design our own DIMM mem map */
+- PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
+- PDC_20621_DIMM_BASE = 0x00200000,
+- PDC_20621_DIMM_DATA = (64 * 1024),
+- PDC_DIMM_DATA_STEP = (256 * 1024),
+- PDC_DIMM_WINDOW_STEP = (8 * 1024),
+- PDC_DIMM_HOST_PRD = (6 * 1024),
+- PDC_DIMM_HOST_PKT = (128 * 0),
+- PDC_DIMM_HPKT_PRD = (128 * 1),
+- PDC_DIMM_ATA_PKT = (128 * 2),
+- PDC_DIMM_APKT_PRD = (128 * 3),
+- PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
+- PDC_PAGE_WINDOW = 0x40,
+- PDC_PAGE_DATA = PDC_PAGE_WINDOW +
+- (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
+- PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
+-
+- PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
+-
+- PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+- (1<<23),
+-
+- board_20621 = 0, /* FastTrak S150 SX4 */
+-
+- PDC_RESET = (1 << 11), /* HDMA reset */
+-
+- PDC_MAX_HDMA = 32,
+- PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
+-
+- PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
+- PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
+- PDC_MAX_DIMM_MODULE = 0x02,
+- PDC_I2C_CONTROL_OFFSET = 0x48,
+- PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
+- PDC_DIMM0_CONTROL_OFFSET = 0x80,
+- PDC_DIMM1_CONTROL_OFFSET = 0x84,
+- PDC_SDRAM_CONTROL_OFFSET = 0x88,
+- PDC_I2C_WRITE = 0x00000000,
+- PDC_I2C_READ = 0x00000040,
+- PDC_I2C_START = 0x00000080,
+- PDC_I2C_MASK_INT = 0x00000020,
+- PDC_I2C_COMPLETE = 0x00010000,
+- PDC_I2C_NO_ACK = 0x00100000,
+- PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
+- PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
+- PDC_DIMM_SPD_ROW_NUM = 3,
+- PDC_DIMM_SPD_COLUMN_NUM = 4,
+- PDC_DIMM_SPD_MODULE_ROW = 5,
+- PDC_DIMM_SPD_TYPE = 11,
+- PDC_DIMM_SPD_FRESH_RATE = 12,
+- PDC_DIMM_SPD_BANK_NUM = 17,
+- PDC_DIMM_SPD_CAS_LATENCY = 18,
+- PDC_DIMM_SPD_ATTRIBUTE = 21,
+- PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
+- PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
+- PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
+- PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
+- PDC_DIMM_SPD_SYSTEM_FREQ = 126,
+- PDC_CTL_STATUS = 0x08,
+- PDC_DIMM_WINDOW_CTLR = 0x0C,
+- PDC_TIME_CONTROL = 0x3C,
+- PDC_TIME_PERIOD = 0x40,
+- PDC_TIME_COUNTER = 0x44,
+- PDC_GENERAL_CTLR = 0x484,
+- PCI_PLL_INIT = 0x8A531824,
+- PCI_X_TCOUNT = 0xEE1E5CFF
+-};
+-
+-
+-struct pdc_port_priv {
+- u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
+- u8 *pkt;
+- dma_addr_t pkt_dma;
+-};
+-
+-struct pdc_host_priv {
+- void __iomem *dimm_mmio;
+-
+- unsigned int doing_hdma;
+- unsigned int hdma_prod;
+- unsigned int hdma_cons;
+- struct {
+- struct ata_queued_cmd *qc;
+- unsigned int seq;
+- unsigned long pkt_ofs;
+- } hdma[32];
+-};
+-
+-
+-static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+-static void pdc_eng_timeout(struct ata_port *ap);
+-static void pdc_20621_phy_reset (struct ata_port *ap);
+-static int pdc_port_start(struct ata_port *ap);
+-static void pdc_port_stop(struct ata_port *ap);
+-static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
+-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+-static void pdc20621_host_stop(struct ata_host_set *host_set);
+-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
+-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
+-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
+- u32 device, u32 subaddr, u32 *pdata);
+-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
+-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+-#ifdef ATA_VERBOSE_DEBUG
+-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+- void *psource, u32 offset, u32 size);
+-#endif
+-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+- void *psource, u32 offset, u32 size);
+-static void pdc20621_irq_clear(struct ata_port *ap);
+-static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
+-
+-
+-static struct scsi_host_template pdc_sata_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations pdc_20621_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = pdc_tf_load_mmio,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = pdc_exec_command_mmio,
+- .dev_select = ata_std_dev_select,
+- .phy_reset = pdc_20621_phy_reset,
+- .qc_prep = pdc20621_qc_prep,
+- .qc_issue = pdc20621_qc_issue_prot,
+- .data_xfer = ata_mmio_data_xfer,
+- .eng_timeout = pdc_eng_timeout,
+- .irq_handler = pdc20621_interrupt,
+- .irq_clear = pdc20621_irq_clear,
+- .port_start = pdc_port_start,
+- .port_stop = pdc_port_stop,
+- .host_stop = pdc20621_host_stop,
+-};
+-
+-static const struct ata_port_info pdc_port_info[] = {
+- /* board_20621 */
+- {
+- .sht = &pdc_sata_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_SRST | ATA_FLAG_MMIO |
+- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .mwdma_mask = 0x07, /* mwdma0-2 */
+- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+- .port_ops = &pdc_20621_ops,
+- },
+-
+-};
+-
+-static const struct pci_device_id pdc_sata_pci_tbl[] = {
+- { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- board_20621 },
+- { } /* terminate list */
+-};
+-
+-
+-static struct pci_driver pdc_sata_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = pdc_sata_pci_tbl,
+- .probe = pdc_sata_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-
+-static void pdc20621_host_stop(struct ata_host_set *host_set)
+-{
+- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+- struct pdc_host_priv *hpriv = host_set->private_data;
+- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+-
+- pci_iounmap(pdev, dimm_mmio);
+- kfree(hpriv);
+-
+- pci_iounmap(pdev, host_set->mmio_base);
+-}
+-
+-static int pdc_port_start(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct pdc_port_priv *pp;
+- int rc;
+-
+- rc = ata_port_start(ap);
+- if (rc)
+- return rc;
+-
+- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+- if (!pp) {
+- rc = -ENOMEM;
+- goto err_out;
+- }
+- memset(pp, 0, sizeof(*pp));
+-
+- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+- if (!pp->pkt) {
+- rc = -ENOMEM;
+- goto err_out_kfree;
+- }
+-
+- ap->private_data = pp;
+-
+- return 0;
+-
+-err_out_kfree:
+- kfree(pp);
+-err_out:
+- ata_port_stop(ap);
+- return rc;
+-}
+-
+-
+-static void pdc_port_stop(struct ata_port *ap)
+-{
+- struct device *dev = ap->host_set->dev;
+- struct pdc_port_priv *pp = ap->private_data;
+-
+- ap->private_data = NULL;
+- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
+- kfree(pp);
+- ata_port_stop(ap);
+-}
+-
+-
+-static void pdc_20621_phy_reset (struct ata_port *ap)
+-{
+- VPRINTK("ENTER\n");
+- ap->cbl = ATA_CBL_SATA;
+- ata_port_probe(ap);
+- ata_bus_reset(ap);
+-}
+-
+-static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
+- unsigned int portno,
+- unsigned int total_len)
+-{
+- u32 addr;
+- unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
+- u32 *buf32 = (u32 *) buf;
+-
+- /* output ATA packet S/G table */
+- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+- (PDC_DIMM_DATA_STEP * portno);
+- VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
+- buf32[dw] = cpu_to_le32(addr);
+- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+-
+- VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
+- PDC_20621_DIMM_BASE +
+- (PDC_DIMM_WINDOW_STEP * portno) +
+- PDC_DIMM_APKT_PRD,
+- buf32[dw], buf32[dw + 1]);
+-}
+-
+-static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
+- unsigned int portno,
+- unsigned int total_len)
+-{
+- u32 addr;
+- unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
+- u32 *buf32 = (u32 *) buf;
+-
+- /* output Host DMA packet S/G table */
+- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+- (PDC_DIMM_DATA_STEP * portno);
+-
+- buf32[dw] = cpu_to_le32(addr);
+- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+-
+- VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
+- PDC_20621_DIMM_BASE +
+- (PDC_DIMM_WINDOW_STEP * portno) +
+- PDC_DIMM_HPKT_PRD,
+- buf32[dw], buf32[dw + 1]);
+-}
+-
+-static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
+- unsigned int devno, u8 *buf,
+- unsigned int portno)
+-{
+- unsigned int i, dw;
+- u32 *buf32 = (u32 *) buf;
+- u8 dev_reg;
+-
+- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+- (PDC_DIMM_WINDOW_STEP * portno) +
+- PDC_DIMM_APKT_PRD;
+- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+-
+- i = PDC_DIMM_ATA_PKT;
+-
+- /*
+- * Set up ATA packet
+- */
+- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+- buf[i++] = PDC_PKT_READ;
+- else if (tf->protocol == ATA_PROT_NODATA)
+- buf[i++] = PDC_PKT_NODATA;
+- else
+- buf[i++] = 0;
+- buf[i++] = 0; /* reserved */
+- buf[i++] = portno + 1; /* seq. id */
+- buf[i++] = 0xff; /* delay seq. id */
+-
+- /* dimm dma S/G, and next-pkt */
+- dw = i >> 2;
+- if (tf->protocol == ATA_PROT_NODATA)
+- buf32[dw] = 0;
+- else
+- buf32[dw] = cpu_to_le32(dimm_sg);
+- buf32[dw + 1] = 0;
+- i += 8;
+-
+- if (devno == 0)
+- dev_reg = ATA_DEVICE_OBS;
+- else
+- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+-
+- /* select device */
+- buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+- buf[i++] = dev_reg;
+-
+- /* device control register */
+- buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
+- buf[i++] = tf->ctl;
+-
+- return i;
+-}
+-
+-static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
+- unsigned int portno)
+-{
+- unsigned int dw;
+- u32 tmp, *buf32 = (u32 *) buf;
+-
+- unsigned int host_sg = PDC_20621_DIMM_BASE +
+- (PDC_DIMM_WINDOW_STEP * portno) +
+- PDC_DIMM_HOST_PRD;
+- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+- (PDC_DIMM_WINDOW_STEP * portno) +
+- PDC_DIMM_HPKT_PRD;
+- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+- VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
+-
+- dw = PDC_DIMM_HOST_PKT >> 2;
+-
+- /*
+- * Set up Host DMA packet
+- */
+- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+- tmp = PDC_PKT_READ;
+- else
+- tmp = 0;
+- tmp |= ((portno + 1 + 4) << 16); /* seq. id */
+- tmp |= (0xff << 24); /* delay seq. id */
+- buf32[dw + 0] = cpu_to_le32(tmp);
+- buf32[dw + 1] = cpu_to_le32(host_sg);
+- buf32[dw + 2] = cpu_to_le32(dimm_sg);
+- buf32[dw + 3] = 0;
+-
+- VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
+- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
+- PDC_DIMM_HOST_PKT,
+- buf32[dw + 0],
+- buf32[dw + 1],
+- buf32[dw + 2],
+- buf32[dw + 3]);
+-}
+-
+-static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
+-{
+- struct scatterlist *sg;
+- struct ata_port *ap = qc->ap;
+- struct pdc_port_priv *pp = ap->private_data;
+- void __iomem *mmio = ap->host_set->mmio_base;
+- struct pdc_host_priv *hpriv = ap->host_set->private_data;
+- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+- unsigned int portno = ap->port_no;
+- unsigned int i, idx, total_len = 0, sgt_len;
+- u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
+-
+- WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+-
+- VPRINTK("ata%u: ENTER\n", ap->id);
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- /*
+- * Build S/G table
+- */
+- idx = 0;
+- ata_for_each_sg(sg, qc) {
+- buf[idx++] = cpu_to_le32(sg_dma_address(sg));
+- buf[idx++] = cpu_to_le32(sg_dma_len(sg));
+- total_len += sg_dma_len(sg);
+- }
+- buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
+- sgt_len = idx * 4;
+-
+- /*
+- * Build ATA, host DMA packets
+- */
+- pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+- pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
+-
+- pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+- i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+-
+- if (qc->tf.flags & ATA_TFLAG_LBA48)
+- i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+- else
+- i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+-
+- pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+-
+- /* copy three S/G tables and two packets to DIMM MMIO window */
+- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+- &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
+- PDC_DIMM_HOST_PRD,
+- &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
+-
+- /* force host FIFO dump */
+- writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+-
+- readl(dimm_mmio); /* MMIO PCI posting flush */
+-
+- VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+-}
+-
+-static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct pdc_port_priv *pp = ap->private_data;
+- void __iomem *mmio = ap->host_set->mmio_base;
+- struct pdc_host_priv *hpriv = ap->host_set->private_data;
+- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+- unsigned int portno = ap->port_no;
+- unsigned int i;
+-
+- VPRINTK("ata%u: ENTER\n", ap->id);
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+-
+- if (qc->tf.flags & ATA_TFLAG_LBA48)
+- i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+- else
+- i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+-
+- pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+-
+- /* copy three S/G tables and two packets to DIMM MMIO window */
+- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+- &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+-
+- /* force host FIFO dump */
+- writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+-
+- readl(dimm_mmio); /* MMIO PCI posting flush */
+-
+- VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
+-}
+-
+-static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
+-{
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- pdc20621_dma_prep(qc);
+- break;
+- case ATA_PROT_NODATA:
+- pdc20621_nodata_prep(qc);
+- break;
+- default:
+- break;
+- }
+-}
+-
+-static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
+- unsigned int seq,
+- u32 pkt_ofs)
+-{
+- struct ata_port *ap = qc->ap;
+- struct ata_host_set *host_set = ap->host_set;
+- void __iomem *mmio = host_set->mmio_base;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
+-
+- writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
+- readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
+-}
+-
+-static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
+- unsigned int seq,
+- u32 pkt_ofs)
+-{
+- struct ata_port *ap = qc->ap;
+- struct pdc_host_priv *pp = ap->host_set->private_data;
+- unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
+-
+- if (!pp->doing_hdma) {
+- __pdc20621_push_hdma(qc, seq, pkt_ofs);
+- pp->doing_hdma = 1;
+- return;
+- }
+-
+- pp->hdma[idx].qc = qc;
+- pp->hdma[idx].seq = seq;
+- pp->hdma[idx].pkt_ofs = pkt_ofs;
+- pp->hdma_prod++;
+-}
+-
+-static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct pdc_host_priv *pp = ap->host_set->private_data;
+- unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
+-
+- /* if nothing on queue, we're done */
+- if (pp->hdma_prod == pp->hdma_cons) {
+- pp->doing_hdma = 0;
+- return;
+- }
+-
+- __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
+- pp->hdma[idx].pkt_ofs);
+- pp->hdma_cons++;
+-}
+-
+-#ifdef ATA_VERBOSE_DEBUG
+-static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- unsigned int port_no = ap->port_no;
+- struct pdc_host_priv *hpriv = ap->host_set->private_data;
+- void *dimm_mmio = hpriv->dimm_mmio;
+-
+- dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
+- dimm_mmio += PDC_DIMM_HOST_PKT;
+-
+- printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
+- printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
+- printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
+- printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
+-}
+-#else
+-static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
+-#endif /* ATA_VERBOSE_DEBUG */
+-
+-static void pdc20621_packet_start(struct ata_queued_cmd *qc)
+-{
+- struct ata_port *ap = qc->ap;
+- struct ata_host_set *host_set = ap->host_set;
+- unsigned int port_no = ap->port_no;
+- void __iomem *mmio = host_set->mmio_base;
+- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+- u8 seq = (u8) (port_no + 1);
+- unsigned int port_ofs;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- VPRINTK("ata%u: ENTER\n", ap->id);
+-
+- wmb(); /* flush PRD, pkt writes */
+-
+- port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+-
+- /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
+- if (rw && qc->tf.protocol == ATA_PROT_DMA) {
+- seq += 4;
+-
+- pdc20621_dump_hdma(qc);
+- pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
+- VPRINTK("queued ofs 0x%x (%u), seq %u\n",
+- port_ofs + PDC_DIMM_HOST_PKT,
+- port_ofs + PDC_DIMM_HOST_PKT,
+- seq);
+- } else {
+- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
+-
+- writel(port_ofs + PDC_DIMM_ATA_PKT,
+- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+- VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
+- port_ofs + PDC_DIMM_ATA_PKT,
+- port_ofs + PDC_DIMM_ATA_PKT,
+- seq);
+- }
+-}
+-
+-static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+-{
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- case ATA_PROT_NODATA:
+- pdc20621_packet_start(qc);
+- return 0;
+-
+- case ATA_PROT_ATAPI_DMA:
+- BUG();
+- break;
+-
+- default:
+- break;
+- }
+-
+- return ata_qc_issue_prot(qc);
+-}
+-
+-static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
+- struct ata_queued_cmd *qc,
+- unsigned int doing_hdma,
+- void __iomem *mmio)
+-{
+- unsigned int port_no = ap->port_no;
+- unsigned int port_ofs =
+- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+- u8 status;
+- unsigned int handled = 0;
+-
+- VPRINTK("ENTER\n");
+-
+- if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
+- (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+-
+- /* step two - DMA from DIMM to host */
+- if (doing_hdma) {
+- VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+- /* get drive status; clear intr; complete txn */
+- qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
+- ata_qc_complete(qc);
+- pdc20621_pop_hdma(qc);
+- }
+-
+- /* step one - exec ATA command */
+- else {
+- u8 seq = (u8) (port_no + 1 + 4);
+- VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+-
+- /* submit hdma pkt */
+- pdc20621_dump_hdma(qc);
+- pdc20621_push_hdma(qc, seq,
+- port_ofs + PDC_DIMM_HOST_PKT);
+- }
+- handled = 1;
+-
+- } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
+-
+- /* step one - DMA from host to DIMM */
+- if (doing_hdma) {
+- u8 seq = (u8) (port_no + 1);
+- VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+-
+- /* submit ata pkt */
+- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+- readl(mmio + PDC_20621_SEQCTL + (seq * 4));
+- writel(port_ofs + PDC_DIMM_ATA_PKT,
+- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+- }
+-
+- /* step two - execute ATA command */
+- else {
+- VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+- /* get drive status; clear intr; complete txn */
+- qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
+- ata_qc_complete(qc);
+- pdc20621_pop_hdma(qc);
+- }
+- handled = 1;
+-
+- /* command completion, but no data xfer */
+- } else if (qc->tf.protocol == ATA_PROT_NODATA) {
+-
+- status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+- DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+- qc->err_mask |= ac_err_mask(status);
+- ata_qc_complete(qc);
+- handled = 1;
+-
+- } else {
+- ap->stats.idle_irq++;
+- }
+-
+- return handled;
+-}
+-
+-static void pdc20621_irq_clear(struct ata_port *ap)
+-{
+- struct ata_host_set *host_set = ap->host_set;
+- void __iomem *mmio = host_set->mmio_base;
+-
+- mmio += PDC_CHIP0_OFS;
+-
+- readl(mmio + PDC_20621_SEQMASK);
+-}
+-
+-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- struct ata_port *ap;
+- u32 mask = 0;
+- unsigned int i, tmp, port_no;
+- unsigned int handled = 0;
+- void __iomem *mmio_base;
+-
+- VPRINTK("ENTER\n");
+-
+- if (!host_set || !host_set->mmio_base) {
+- VPRINTK("QUICK EXIT\n");
+- return IRQ_NONE;
+- }
+-
+- mmio_base = host_set->mmio_base;
+-
+- /* reading should also clear interrupts */
+- mmio_base += PDC_CHIP0_OFS;
+- mask = readl(mmio_base + PDC_20621_SEQMASK);
+- VPRINTK("mask == 0x%x\n", mask);
+-
+- if (mask == 0xffffffff) {
+- VPRINTK("QUICK EXIT 2\n");
+- return IRQ_NONE;
+- }
+- mask &= 0xffff; /* only 16 tags possible */
+- if (!mask) {
+- VPRINTK("QUICK EXIT 3\n");
+- return IRQ_NONE;
+- }
+-
+- spin_lock(&host_set->lock);
+-
+- for (i = 1; i < 9; i++) {
+- port_no = i - 1;
+- if (port_no > 3)
+- port_no -= 4;
+- if (port_no >= host_set->n_ports)
+- ap = NULL;
+- else
+- ap = host_set->ports[port_no];
+- tmp = mask & (1 << i);
+- VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
+- if (tmp && ap &&
+- !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+- handled += pdc20621_host_intr(ap, qc, (i > 4),
+- mmio_base);
+- }
+- }
+-
+- spin_unlock(&host_set->lock);
+-
+- VPRINTK("mask == 0x%x\n", mask);
+-
+- VPRINTK("EXIT\n");
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-static void pdc_eng_timeout(struct ata_port *ap)
+-{
+- u8 drv_stat;
+- struct ata_host_set *host_set = ap->host_set;
+- struct ata_queued_cmd *qc;
+- unsigned long flags;
+-
+- DPRINTK("ENTER\n");
+-
+- spin_lock_irqsave(&host_set->lock, flags);
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+-
+- switch (qc->tf.protocol) {
+- case ATA_PROT_DMA:
+- case ATA_PROT_NODATA:
+- ata_port_printk(ap, KERN_ERR, "command timeout\n");
+- qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
+- break;
+-
+- default:
+- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+-
+- ata_port_printk(ap, KERN_ERR,
+- "unknown timeout, cmd 0x%x stat 0x%x\n",
+- qc->tf.command, drv_stat);
+-
+- qc->err_mask |= ac_err_mask(drv_stat);
+- break;
+- }
+-
+- spin_unlock_irqrestore(&host_set->lock, flags);
+- ata_eh_qc_complete(qc);
+- DPRINTK("EXIT\n");
+-}
+-
+-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- WARN_ON (tf->protocol == ATA_PROT_DMA ||
+- tf->protocol == ATA_PROT_NODATA);
+- ata_tf_load(ap, tf);
+-}
+-
+-
+-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- WARN_ON (tf->protocol == ATA_PROT_DMA ||
+- tf->protocol == ATA_PROT_NODATA);
+- ata_exec_command(ap, tf);
+-}
+-
+-
+-static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+-{
+- port->cmd_addr = base;
+- port->data_addr = base;
+- port->feature_addr =
+- port->error_addr = base + 0x4;
+- port->nsect_addr = base + 0x8;
+- port->lbal_addr = base + 0xc;
+- port->lbam_addr = base + 0x10;
+- port->lbah_addr = base + 0x14;
+- port->device_addr = base + 0x18;
+- port->command_addr =
+- port->status_addr = base + 0x1c;
+- port->altstatus_addr =
+- port->ctl_addr = base + 0x38;
+-}
+-
+-
+-#ifdef ATA_VERBOSE_DEBUG
+-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+- u32 offset, u32 size)
+-{
+- u32 window_size;
+- u16 idx;
+- u8 page_mask;
+- long dist;
+- void __iomem *mmio = pe->mmio_base;
+- struct pdc_host_priv *hpriv = pe->private_data;
+- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- page_mask = 0x00;
+- window_size = 0x2000 * 4; /* 32K byte uchar size */
+- idx = (u16) (offset / window_size);
+-
+- writel(0x01, mmio + PDC_GENERAL_CTLR);
+- readl(mmio + PDC_GENERAL_CTLR);
+- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+- readl(mmio + PDC_DIMM_WINDOW_CTLR);
+-
+- offset -= (idx * window_size);
+- idx++;
+- dist = ((long) (window_size - (offset + size))) >= 0 ? size :
+- (long) (window_size - offset);
+- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
+- dist);
+-
+- psource += dist;
+- size -= dist;
+- for (; (long) size >= (long) window_size ;) {
+- writel(0x01, mmio + PDC_GENERAL_CTLR);
+- readl(mmio + PDC_GENERAL_CTLR);
+- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+- readl(mmio + PDC_DIMM_WINDOW_CTLR);
+- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
+- window_size / 4);
+- psource += window_size;
+- size -= window_size;
+- idx ++;
+- }
+-
+- if (size) {
+- writel(0x01, mmio + PDC_GENERAL_CTLR);
+- readl(mmio + PDC_GENERAL_CTLR);
+- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+- readl(mmio + PDC_DIMM_WINDOW_CTLR);
+- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
+- size / 4);
+- }
+-}
+-#endif
+-
+-
+-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+- u32 offset, u32 size)
+-{
+- u32 window_size;
+- u16 idx;
+- u8 page_mask;
+- long dist;
+- void __iomem *mmio = pe->mmio_base;
+- struct pdc_host_priv *hpriv = pe->private_data;
+- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- page_mask = 0x00;
+- window_size = 0x2000 * 4; /* 32K byte uchar size */
+- idx = (u16) (offset / window_size);
+-
+- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+- readl(mmio + PDC_DIMM_WINDOW_CTLR);
+- offset -= (idx * window_size);
+- idx++;
+- dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
+- (long) (window_size - offset);
+- memcpy_toio(dimm_mmio + offset / 4, psource, dist);
+- writel(0x01, mmio + PDC_GENERAL_CTLR);
+- readl(mmio + PDC_GENERAL_CTLR);
+-
+- psource += dist;
+- size -= dist;
+- for (; (long) size >= (long) window_size ;) {
+- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+- readl(mmio + PDC_DIMM_WINDOW_CTLR);
+- memcpy_toio(dimm_mmio, psource, window_size / 4);
+- writel(0x01, mmio + PDC_GENERAL_CTLR);
+- readl(mmio + PDC_GENERAL_CTLR);
+- psource += window_size;
+- size -= window_size;
+- idx ++;
+- }
+-
+- if (size) {
+- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+- readl(mmio + PDC_DIMM_WINDOW_CTLR);
+- memcpy_toio(dimm_mmio, psource, size / 4);
+- writel(0x01, mmio + PDC_GENERAL_CTLR);
+- readl(mmio + PDC_GENERAL_CTLR);
+- }
+-}
+-
+-
+-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+- u32 subaddr, u32 *pdata)
+-{
+- void __iomem *mmio = pe->mmio_base;
+- u32 i2creg = 0;
+- u32 status;
+- u32 count =0;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- i2creg |= device << 24;
+- i2creg |= subaddr << 16;
+-
+- /* Set the device and subaddress */
+- writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
+- readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+-
+- /* Write Control to perform read operation, mask int */
+- writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
+- mmio + PDC_I2C_CONTROL_OFFSET);
+-
+- for (count = 0; count <= 1000; count ++) {
+- status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
+- if (status & PDC_I2C_COMPLETE) {
+- status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+- break;
+- } else if (count == 1000)
+- return 0;
+- }
+-
+- *pdata = (status >> 8) & 0x000000ff;
+- return 1;
+-}
+-
+-
+-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+-{
+- u32 data=0 ;
+- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+- PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
+- if (data == 100)
+- return 100;
+- } else
+- return 0;
+-
+- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+- if(data <= 0x75)
+- return 133;
+- } else
+- return 0;
+-
+- return 0;
+-}
+-
+-
+-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+-{
+- u32 spd0[50];
+- u32 data = 0;
+- int size, i;
+- u8 bdimmsize;
+- void __iomem *mmio = pe->mmio_base;
+- static const struct {
+- unsigned int reg;
+- unsigned int ofs;
+- } pdc_i2c_read_data [] = {
+- { PDC_DIMM_SPD_TYPE, 11 },
+- { PDC_DIMM_SPD_FRESH_RATE, 12 },
+- { PDC_DIMM_SPD_COLUMN_NUM, 4 },
+- { PDC_DIMM_SPD_ATTRIBUTE, 21 },
+- { PDC_DIMM_SPD_ROW_NUM, 3 },
+- { PDC_DIMM_SPD_BANK_NUM, 17 },
+- { PDC_DIMM_SPD_MODULE_ROW, 5 },
+- { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
+- { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
+- { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
+- { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
+- { PDC_DIMM_SPD_CAS_LATENCY, 18 },
+- };
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
+- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+- pdc_i2c_read_data[i].reg,
+- &spd0[pdc_i2c_read_data[i].ofs]);
+-
+- data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
+- data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
+- ((((spd0[27] + 9) / 10) - 1) << 8) ;
+- data |= (((((spd0[29] > spd0[28])
+- ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
+- data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+-
+- if (spd0[18] & 0x08)
+- data |= ((0x03) << 14);
+- else if (spd0[18] & 0x04)
+- data |= ((0x02) << 14);
+- else if (spd0[18] & 0x01)
+- data |= ((0x01) << 14);
+- else
+- data |= (0 << 14);
+-
+- /*
+- Calculate the size of bDIMMSize (power of 2) and
+- merge the DIMM size by program start/end address.
+- */
+-
+- bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+- size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
+- data |= (((size / 16) - 1) << 16);
+- data |= (0 << 23);
+- data |= 8;
+- writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
+- readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
+- return size;
+-}
+-
+-
+-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+-{
+- u32 data, spd0;
+- int error, i;
+- void __iomem *mmio = pe->mmio_base;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- /*
+- Set To Default : DIMM Module Global Control Register (0x022259F1)
+- DIMM Arbitration Disable (bit 20)
+- DIMM Data/Control Output Driving Selection (bit12 - bit15)
+- Refresh Enable (bit 17)
+- */
+-
+- data = 0x022259F1;
+- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+- readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+-
+- /* Turn on for ECC */
+- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+- PDC_DIMM_SPD_TYPE, &spd0);
+- if (spd0 == 0x02) {
+- data |= (0x01 << 16);
+- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+- readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+- printk(KERN_ERR "Local DIMM ECC Enabled\n");
+- }
+-
+- /* DIMM Initialization Select/Enable (bit 18/19) */
+- data &= (~(1<<18));
+- data |= (1<<19);
+- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+-
+- error = 1;
+- for (i = 1; i <= 10; i++) { /* polling ~5 secs */
+- data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+- if (!(data & (1<<19))) {
+- error = 0;
+- break;
+- }
+- msleep(i*100);
+- }
+- return error;
+-}
+-
+-
+-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+-{
+- int speed, size, length;
+- u32 addr,spd0,pci_status;
+- u32 tmp=0;
+- u32 time_period=0;
+- u32 tcount=0;
+- u32 ticks=0;
+- u32 clock=0;
+- u32 fparam=0;
+- void __iomem *mmio = pe->mmio_base;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- /* Initialize PLL based upon PCI Bus Frequency */
+-
+- /* Initialize Time Period Register */
+- writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+- time_period = readl(mmio + PDC_TIME_PERIOD);
+- VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+-
+- /* Enable timer */
+- writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+- readl(mmio + PDC_TIME_CONTROL);
+-
+- /* Wait 3 seconds */
+- msleep(3000);
+-
+- /*
+- When timer is enabled, counter is decreased every internal
+- clock cycle.
+- */
+-
+- tcount = readl(mmio + PDC_TIME_COUNTER);
+- VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+-
+- /*
+- If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+- register should be >= (0xffffffff - 3x10^8).
+- */
+- if(tcount >= PCI_X_TCOUNT) {
+- ticks = (time_period - tcount);
+- VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+-
+- clock = (ticks / 300000);
+- VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+-
+- clock = (clock * 33);
+- VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+-
+- /* PLL F Param (bit 22:16) */
+- fparam = (1400000 / clock) - 2;
+- VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+-
+- /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+- pci_status = (0x8a001824 | (fparam << 16));
+- } else
+- pci_status = PCI_PLL_INIT;
+-
+- /* Initialize PLL. */
+- VPRINTK("pci_status: 0x%x\n", pci_status);
+- writel(pci_status, mmio + PDC_CTL_STATUS);
+- readl(mmio + PDC_CTL_STATUS);
+-
+- /*
+- Read SPD of DIMM by I2C interface,
+- and program the DIMM Module Controller.
+- */
+- if (!(speed = pdc20621_detect_dimm(pe))) {
+- printk(KERN_ERR "Detect Local DIMM Fail\n");
+- return 1; /* DIMM error */
+- }
+- VPRINTK("Local DIMM Speed = %d\n", speed);
+-
+- /* Programming DIMM0 Module Control Register (index_CID0:80h) */
+- size = pdc20621_prog_dimm0(pe);
+- VPRINTK("Local DIMM Size = %dMB\n",size);
+-
+- /* Programming DIMM Module Global Control Register (index_CID0:88h) */
+- if (pdc20621_prog_dimm_global(pe)) {
+- printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
+- return 1;
+- }
+-
+-#ifdef ATA_VERBOSE_DEBUG
+- {
+- u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+- 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
+- '1','.','1','0',
+- '9','8','0','3','1','6','1','2',0,0};
+- u8 test_parttern2[40] = {0};
+-
+- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
+- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+-
+- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
+- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+- test_parttern2[1], &(test_parttern2[2]));
+- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
+- 40);
+- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+- test_parttern2[1], &(test_parttern2[2]));
+-
+- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
+- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+- test_parttern2[1], &(test_parttern2[2]));
+- }
+-#endif
+-
+- /* ECC initiliazation. */
+-
+- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+- PDC_DIMM_SPD_TYPE, &spd0);
+- if (spd0 == 0x02) {
+- VPRINTK("Start ECC initialization\n");
+- addr = 0;
+- length = size * 1024 * 1024;
+- while (addr < length) {
+- pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
+- sizeof(u32));
+- addr += sizeof(u32);
+- }
+- VPRINTK("Finish ECC initialization\n");
+- }
+- return 0;
+-}
+-
+-
+-static void pdc_20621_init(struct ata_probe_ent *pe)
+-{
+- u32 tmp;
+- void __iomem *mmio = pe->mmio_base;
+-
+- /* hard-code chip #0 */
+- mmio += PDC_CHIP0_OFS;
+-
+- /*
+- * Select page 0x40 for our 32k DIMM window
+- */
+- tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
+- tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
+- writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
+-
+- /*
+- * Reset Host DMA
+- */
+- tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+- tmp |= PDC_RESET;
+- writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+- readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
+-
+- udelay(10);
+-
+- tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+- tmp &= ~PDC_RESET;
+- writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+- readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
+-}
+-
+-static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- unsigned long base;
+- void __iomem *mmio_base;
+- void __iomem *dimm_mmio = NULL;
+- struct pdc_host_priv *hpriv = NULL;
+- unsigned int board_idx = (unsigned int) ent->driver_data;
+- int pci_dev_busy = 0;
+- int rc;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- mmio_base = pci_iomap(pdev, 3, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+- base = (unsigned long) mmio_base;
+-
+- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv) {
+- rc = -ENOMEM;
+- goto err_out_iounmap;
+- }
+- memset(hpriv, 0, sizeof(*hpriv));
+-
+- dimm_mmio = pci_iomap(pdev, 4, 0);
+- if (!dimm_mmio) {
+- kfree(hpriv);
+- rc = -ENOMEM;
+- goto err_out_iounmap;
+- }
+-
+- hpriv->dimm_mmio = dimm_mmio;
+-
+- probe_ent->sht = pdc_port_info[board_idx].sht;
+- probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
+- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
+- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
+- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
+- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
+-
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+-
+- probe_ent->private_data = hpriv;
+- base += PDC_CHIP0_OFS;
+-
+- probe_ent->n_ports = 4;
+- pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+- pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+- pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+- pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+-
+- pci_set_master(pdev);
+-
+- /* initialize adapter */
+- /* initialize local dimm */
+- if (pdc20621_dimm_init(probe_ent)) {
+- rc = -ENOMEM;
+- goto err_out_iounmap_dimm;
+- }
+- pdc_20621_init(probe_ent);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_iounmap_dimm: /* only get to this label if 20621 */
+- kfree(hpriv);
+- pci_iounmap(pdev, dimm_mmio);
+-err_out_iounmap:
+- pci_iounmap(pdev, mmio_base);
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-
+-static int __init pdc_sata_init(void)
+-{
+- return pci_module_init(&pdc_sata_pci_driver);
+-}
+-
+-
+-static void __exit pdc_sata_exit(void)
+-{
+- pci_unregister_driver(&pdc_sata_pci_driver);
+-}
+-
+-
+-MODULE_AUTHOR("Jeff Garzik");
+-MODULE_DESCRIPTION("Promise SATA low-level driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(pdc_sata_init);
+-module_exit(pdc_sata_exit);
+diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
+deleted file mode 100644
+index 33cdb48..0000000
+--- a/drivers/scsi/sata_uli.c
++++ /dev/null
+@@ -1,300 +0,0 @@
+-/*
+- * sata_uli.c - ULi Electronics SATA
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available under NDA.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "sata_uli"
+-#define DRV_VERSION "1.0"
+-
+-enum {
+- uli_5289 = 0,
+- uli_5287 = 1,
+- uli_5281 = 2,
+-
+- uli_max_ports = 4,
+-
+- /* PCI configuration registers */
+- ULI5287_BASE = 0x90, /* sata0 phy SCR registers */
+- ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */
+- ULI5281_BASE = 0x60, /* sata0 phy SCR registers */
+- ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */
+-};
+-
+-struct uli_priv {
+- unsigned int scr_cfg_addr[uli_max_ports];
+-};
+-
+-static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-
+-static const struct pci_device_id uli_pci_tbl[] = {
+- { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
+- { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+- { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+- { } /* terminate list */
+-};
+-
+-
+-static struct pci_driver uli_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = uli_pci_tbl,
+- .probe = uli_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static struct scsi_host_template uli_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations uli_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_pio_data_xfer,
+-
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = ata_bmdma_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+-
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+-
+- .scr_read = uli_scr_read,
+- .scr_write = uli_scr_write,
+-
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_host_stop,
+-};
+-
+-static struct ata_port_info uli_port_info = {
+- .sht = &uli_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+- .pio_mask = 0x1f, /* pio0-4 */
+- .udma_mask = 0x7f, /* udma0-6 */
+- .port_ops = &uli_ops,
+-};
+-
+-
+-MODULE_AUTHOR("Peer Chen");
+-MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
+-{
+- struct uli_priv *hpriv = ap->host_set->private_data;
+- return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
+-}
+-
+-static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+- u32 val;
+-
+- pci_read_config_dword(pdev, cfg_addr, &val);
+- return val;
+-}
+-
+-static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+-{
+- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+- unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
+-
+- pci_write_config_dword(pdev, cfg_addr, val);
+-}
+-
+-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+-
+- return uli_scr_cfg_read(ap, sc_reg);
+-}
+-
+-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+-{
+- if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
+- return;
+-
+- uli_scr_cfg_write(ap, sc_reg, val);
+-}
+-
+-static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent;
+- struct ata_port_info *ppi;
+- int rc;
+- unsigned int board_idx = (unsigned int) ent->driver_data;
+- int pci_dev_busy = 0;
+- struct uli_priv *hpriv;
+-
+- if (!printed_version++)
+- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- ppi = &uli_port_info;
+- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+- if (!probe_ent) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv) {
+- rc = -ENOMEM;
+- goto err_out_probe_ent;
+- }
+-
+- probe_ent->private_data = hpriv;
+-
+- switch (board_idx) {
+- case uli_5287:
+- hpriv->scr_cfg_addr[0] = ULI5287_BASE;
+- hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
+- probe_ent->n_ports = 4;
+-
+- probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
+- probe_ent->port[2].altstatus_addr =
+- probe_ent->port[2].ctl_addr =
+- (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
+- probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+- hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
+-
+- probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
+- probe_ent->port[3].altstatus_addr =
+- probe_ent->port[3].ctl_addr =
+- (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
+- probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+- hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
+-
+- ata_std_ports(&probe_ent->port[2]);
+- ata_std_ports(&probe_ent->port[3]);
+- break;
+-
+- case uli_5289:
+- hpriv->scr_cfg_addr[0] = ULI5287_BASE;
+- hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
+- break;
+-
+- case uli_5281:
+- hpriv->scr_cfg_addr[0] = ULI5281_BASE;
+- hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS;
+- break;
+-
+- default:
+- BUG();
+- break;
+- }
+-
+- pci_set_master(pdev);
+- pci_intx(pdev, 1);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_probe_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-
+-}
+-
+-static int __init uli_init(void)
+-{
+- return pci_module_init(&uli_pci_driver);
+-}
+-
+-static void __exit uli_exit(void)
+-{
+- pci_unregister_driver(&uli_pci_driver);
+-}
+-
+-
+-module_init(uli_init);
+-module_exit(uli_exit);
+diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
+deleted file mode 100644
+index a3727af..0000000
+--- a/drivers/scsi/sata_via.c
++++ /dev/null
+@@ -1,502 +0,0 @@
+-/*
+- * sata_via.c - VIA Serial ATA controllers
+- *
+- * Maintained by: Jeff Garzik <jgarzik at pobox.com>
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- on emails.
+- *
+- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+- * Copyright 2003-2004 Jeff Garzik
+- *
+- *
+- * 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Hardware documentation available under NDA.
+- *
+- *
+- * To-do list:
+- * - VT6421 PATA support
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-#include <asm/io.h>
+-
+-#define DRV_NAME "sata_via"
+-#define DRV_VERSION "2.0"
+-
+-enum board_ids_enum {
+- vt6420,
+- vt6421,
+-};
+-
+-enum {
+- SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
+- SATA_INT_GATE = 0x41, /* SATA interrupt gating */
+- SATA_NATIVE_MODE = 0x42, /* Native mode enable */
+- SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
+-
+- PORT0 = (1 << 1),
+- PORT1 = (1 << 0),
+- ALL_PORTS = PORT0 | PORT1,
+- N_PORTS = 2,
+-
+- NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
+-
+- SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
+- SATA_2DEV = (1 << 5), /* SATA is master/slave */
+-};
+-
+-static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
+-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+-static void vt6420_error_handler(struct ata_port *ap);
+-
+-static const struct pci_device_id svia_pci_tbl[] = {
+- { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
+- { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
+- { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+-
+- { } /* terminate list */
+-};
+-
+-static struct pci_driver svia_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = svia_pci_tbl,
+- .probe = svia_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-static struct scsi_host_template svia_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-static const struct ata_port_operations vt6420_sata_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+-
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_pio_data_xfer,
+-
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = vt6420_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+-
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+-
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_host_stop,
+-};
+-
+-static const struct ata_port_operations vt6421_sata_ops = {
+- .port_disable = ata_port_disable,
+-
+- .tf_load = ata_tf_load,
+- .tf_read = ata_tf_read,
+- .check_status = ata_check_status,
+- .exec_command = ata_exec_command,
+- .dev_select = ata_std_dev_select,
+-
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+-
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_pio_data_xfer,
+-
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = ata_bmdma_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+-
+- .irq_handler = ata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+-
+- .scr_read = svia_scr_read,
+- .scr_write = svia_scr_write,
+-
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_host_stop,
+-};
+-
+-static struct ata_port_info vt6420_port_info = {
+- .sht = &svia_sht,
+- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+- .pio_mask = 0x1f,
+- .mwdma_mask = 0x07,
+- .udma_mask = 0x7f,
+- .port_ops = &vt6420_sata_ops,
+-};
+-
+-MODULE_AUTHOR("Jeff Garzik");
+-MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+- return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
+-}
+-
+-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return;
+- outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+-}
+-
+-/**
+- * vt6420_prereset - prereset for vt6420
+- * @ap: target ATA port
+- *
+- * SCR registers on vt6420 are pieces of shit and may hang the
+- * whole machine completely if accessed with the wrong timing.
+- * To avoid such catastrophe, vt6420 doesn't provide generic SCR
+- * access operations, but uses SStatus and SControl only during
+- * boot probing in controlled way.
+- *
+- * As the old (pre EH update) probing code is proven to work, we
+- * strictly follow the access pattern.
+- *
+- * LOCKING:
+- * Kernel thread context (may sleep)
+- *
+- * RETURNS:
+- * 0 on success, -errno otherwise.
+- */
+-static int vt6420_prereset(struct ata_port *ap)
+-{
+- struct ata_eh_context *ehc = &ap->eh_context;
+- unsigned long timeout = jiffies + (HZ * 5);
+- u32 sstatus, scontrol;
+- int online;
+-
+- /* don't do any SCR stuff if we're not loading */
+- if (!ATA_PFLAG_LOADING)
+- goto skip_scr;
+-
+- /* Resume phy. This is the old resume sequence from
+- * __sata_phy_reset().
+- */
+- svia_scr_write(ap, SCR_CONTROL, 0x300);
+- svia_scr_read(ap, SCR_CONTROL); /* flush */
+-
+- /* wait for phy to become ready, if necessary */
+- do {
+- msleep(200);
+- if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+- break;
+- } while (time_before(jiffies, timeout));
+-
+- /* open code sata_print_link_status() */
+- sstatus = svia_scr_read(ap, SCR_STATUS);
+- scontrol = svia_scr_read(ap, SCR_CONTROL);
+-
+- online = (sstatus & 0xf) == 0x3;
+-
+- ata_port_printk(ap, KERN_INFO,
+- "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
+- online ? "up" : "down", sstatus, scontrol);
+-
+- /* SStatus is read one more time */
+- svia_scr_read(ap, SCR_STATUS);
+-
+- if (!online) {
+- /* tell EH to bail */
+- ehc->i.action &= ~ATA_EH_RESET_MASK;
+- return 0;
+- }
+-
+- skip_scr:
+- /* wait for !BSY */
+- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+-
+- return 0;
+-}
+-
+-static void vt6420_error_handler(struct ata_port *ap)
+-{
+- return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset,
+- NULL, ata_std_postreset);
+-}
+-
+-static const unsigned int svia_bar_sizes[] = {
+- 8, 4, 8, 4, 16, 256
+-};
+-
+-static const unsigned int vt6421_bar_sizes[] = {
+- 16, 16, 16, 16, 32, 128
+-};
+-
+-static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+-{
+- return addr + (port * 128);
+-}
+-
+-static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
+-{
+- return addr + (port * 64);
+-}
+-
+-static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
+- struct pci_dev *pdev,
+- unsigned int port)
+-{
+- unsigned long reg_addr = pci_resource_start(pdev, port);
+- unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
+- unsigned long scr_addr;
+-
+- probe_ent->port[port].cmd_addr = reg_addr;
+- probe_ent->port[port].altstatus_addr =
+- probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
+- probe_ent->port[port].bmdma_addr = bmdma_addr;
+-
+- scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
+- probe_ent->port[port].scr_addr = scr_addr;
+-
+- ata_std_ports(&probe_ent->port[port]);
+-}
+-
+-static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
+-{
+- struct ata_probe_ent *probe_ent;
+- struct ata_port_info *ppi = &vt6420_port_info;
+-
+- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+- if (!probe_ent)
+- return NULL;
+-
+- probe_ent->port[0].scr_addr =
+- svia_scr_addr(pci_resource_start(pdev, 5), 0);
+- probe_ent->port[1].scr_addr =
+- svia_scr_addr(pci_resource_start(pdev, 5), 1);
+-
+- return probe_ent;
+-}
+-
+-static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
+-{
+- struct ata_probe_ent *probe_ent;
+- unsigned int i;
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (!probe_ent)
+- return NULL;
+-
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- probe_ent->sht = &svia_sht;
+- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
+- probe_ent->port_ops = &vt6421_sata_ops;
+- probe_ent->n_ports = N_PORTS;
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->pio_mask = 0x1f;
+- probe_ent->mwdma_mask = 0x07;
+- probe_ent->udma_mask = 0x7f;
+-
+- for (i = 0; i < N_PORTS; i++)
+- vt6421_init_addrs(probe_ent, pdev, i);
+-
+- return probe_ent;
+-}
+-
+-static void svia_configure(struct pci_dev *pdev)
+-{
+- u8 tmp8;
+-
+- pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
+- dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n",
+- (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+-
+- /* make sure SATA channels are enabled */
+- pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
+- if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
+- dev_printk(KERN_DEBUG, &pdev->dev,
+- "enabling SATA channels (0x%x)\n",
+- (int) tmp8);
+- tmp8 |= ALL_PORTS;
+- pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
+- }
+-
+- /* make sure interrupts for each channel sent to us */
+- pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
+- if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
+- dev_printk(KERN_DEBUG, &pdev->dev,
+- "enabling SATA channel interrupts (0x%x)\n",
+- (int) tmp8);
+- tmp8 |= ALL_PORTS;
+- pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
+- }
+-
+- /* make sure native mode is enabled */
+- pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
+- if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
+- dev_printk(KERN_DEBUG, &pdev->dev,
+- "enabling SATA channel native mode (0x%x)\n",
+- (int) tmp8);
+- tmp8 |= NATIVE_MODE_ALL;
+- pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
+- }
+-}
+-
+-static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- unsigned int i;
+- int rc;
+- struct ata_probe_ent *probe_ent;
+- int board_id = (int) ent->driver_data;
+- const int *bar_sizes;
+- int pci_dev_busy = 0;
+- u8 tmp8;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- if (board_id == vt6420) {
+- pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
+- if (tmp8 & SATA_2DEV) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "SATA master/slave not supported (0x%x)\n",
+- (int) tmp8);
+- rc = -EIO;
+- goto err_out_regions;
+- }
+-
+- bar_sizes = &svia_bar_sizes[0];
+- } else {
+- bar_sizes = &vt6421_bar_sizes[0];
+- }
+-
+- for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
+- if ((pci_resource_start(pdev, i) == 0) ||
+- (pci_resource_len(pdev, i) < bar_sizes[i])) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
+- i,
+- (unsigned long long)pci_resource_start(pdev, i),
+- (unsigned long long)pci_resource_len(pdev, i));
+- rc = -ENODEV;
+- goto err_out_regions;
+- }
+-
+- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- if (board_id == vt6420)
+- probe_ent = vt6420_init_probe_ent(pdev);
+- else
+- probe_ent = vt6421_init_probe_ent(pdev);
+-
+- if (!probe_ent) {
+- dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+-
+- svia_configure(pdev);
+-
+- pci_set_master(pdev);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-static int __init svia_init(void)
+-{
+- return pci_module_init(&svia_pci_driver);
+-}
+-
+-static void __exit svia_exit(void)
+-{
+- pci_unregister_driver(&svia_pci_driver);
+-}
+-
+-module_init(svia_init);
+-module_exit(svia_exit);
+-
+diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
+deleted file mode 100644
+index ad37871..0000000
+--- a/drivers/scsi/sata_vsc.c
++++ /dev/null
+@@ -1,482 +0,0 @@
+-/*
+- * sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
+- *
+- * Maintained by: Jeremy Higdon @ SGI
+- * Please ALWAYS copy linux-ide at vger.kernel.org
+- * on emails.
+- *
+- * Copyright 2004 SGI
+- *
+- * Bits from Jeff Garzik, Copyright RedHat, 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, 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; see the file COPYING. If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- * libata documentation is available via 'make {ps|pdf}docs',
+- * as Documentation/DocBook/libata.*
+- *
+- * Vitesse hardware documentation presumably available under NDA.
+- * Intel 31244 (same hardware interface) documentation presumably
+- * available from http://developer.intel.com/
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/device.h>
+-#include <scsi/scsi_host.h>
+-#include <linux/libata.h>
+-
+-#define DRV_NAME "sata_vsc"
+-#define DRV_VERSION "2.0"
+-
+-enum {
+- /* Interrupt register offsets (from chip base address) */
+- VSC_SATA_INT_STAT_OFFSET = 0x00,
+- VSC_SATA_INT_MASK_OFFSET = 0x04,
+-
+- /* Taskfile registers offsets */
+- VSC_SATA_TF_CMD_OFFSET = 0x00,
+- VSC_SATA_TF_DATA_OFFSET = 0x00,
+- VSC_SATA_TF_ERROR_OFFSET = 0x04,
+- VSC_SATA_TF_FEATURE_OFFSET = 0x06,
+- VSC_SATA_TF_NSECT_OFFSET = 0x08,
+- VSC_SATA_TF_LBAL_OFFSET = 0x0c,
+- VSC_SATA_TF_LBAM_OFFSET = 0x10,
+- VSC_SATA_TF_LBAH_OFFSET = 0x14,
+- VSC_SATA_TF_DEVICE_OFFSET = 0x18,
+- VSC_SATA_TF_STATUS_OFFSET = 0x1c,
+- VSC_SATA_TF_COMMAND_OFFSET = 0x1d,
+- VSC_SATA_TF_ALTSTATUS_OFFSET = 0x28,
+- VSC_SATA_TF_CTL_OFFSET = 0x29,
+-
+- /* DMA base */
+- VSC_SATA_UP_DESCRIPTOR_OFFSET = 0x64,
+- VSC_SATA_UP_DATA_BUFFER_OFFSET = 0x6C,
+- VSC_SATA_DMA_CMD_OFFSET = 0x70,
+-
+- /* SCRs base */
+- VSC_SATA_SCR_STATUS_OFFSET = 0x100,
+- VSC_SATA_SCR_ERROR_OFFSET = 0x104,
+- VSC_SATA_SCR_CONTROL_OFFSET = 0x108,
+-
+- /* Port stride */
+- VSC_SATA_PORT_OFFSET = 0x200,
+-
+- /* Error interrupt status bit offsets */
+- VSC_SATA_INT_ERROR_CRC = 0x40,
+- VSC_SATA_INT_ERROR_T = 0x20,
+- VSC_SATA_INT_ERROR_P = 0x10,
+- VSC_SATA_INT_ERROR_R = 0x8,
+- VSC_SATA_INT_ERROR_E = 0x4,
+- VSC_SATA_INT_ERROR_M = 0x2,
+- VSC_SATA_INT_PHY_CHANGE = 0x1,
+- VSC_SATA_INT_ERROR = (VSC_SATA_INT_ERROR_CRC | VSC_SATA_INT_ERROR_T | \
+- VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \
+- VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \
+- VSC_SATA_INT_PHY_CHANGE),
+-};
+-
+-
+-#define is_vsc_sata_int_err(port_idx, int_status) \
+- (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
+-
+-
+-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return 0xffffffffU;
+- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-
+-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+- u32 val)
+-{
+- if (sc_reg > SCR_CONTROL)
+- return;
+- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+-}
+-
+-
+-static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
+-{
+- void __iomem *mask_addr;
+- u8 mask;
+-
+- mask_addr = ap->host_set->mmio_base +
+- VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+- mask = readb(mask_addr);
+- if (ctl & ATA_NIEN)
+- mask |= 0x80;
+- else
+- mask &= 0x7F;
+- writeb(mask, mask_addr);
+-}
+-
+-
+-static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+-
+- /*
+- * The only thing the ctl register is used for is SRST.
+- * That is not enabled or disabled via tf_load.
+- * However, if ATA_NIEN is changed, then we need to change the interrupt register.
+- */
+- if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
+- ap->last_ctl = tf->ctl;
+- vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
+- }
+- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+- writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+- writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+- writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+- writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+- writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+- } else if (is_addr) {
+- writew(tf->feature, ioaddr->feature_addr);
+- writew(tf->nsect, ioaddr->nsect_addr);
+- writew(tf->lbal, ioaddr->lbal_addr);
+- writew(tf->lbam, ioaddr->lbam_addr);
+- writew(tf->lbah, ioaddr->lbah_addr);
+- }
+-
+- if (tf->flags & ATA_TFLAG_DEVICE)
+- writeb(tf->device, ioaddr->device_addr);
+-
+- ata_wait_idle(ap);
+-}
+-
+-
+-static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+-{
+- struct ata_ioports *ioaddr = &ap->ioaddr;
+- u16 nsect, lbal, lbam, lbah, feature;
+-
+- tf->command = ata_check_status(ap);
+- tf->device = readw(ioaddr->device_addr);
+- feature = readw(ioaddr->error_addr);
+- nsect = readw(ioaddr->nsect_addr);
+- lbal = readw(ioaddr->lbal_addr);
+- lbam = readw(ioaddr->lbam_addr);
+- lbah = readw(ioaddr->lbah_addr);
+-
+- tf->feature = feature;
+- tf->nsect = nsect;
+- tf->lbal = lbal;
+- tf->lbam = lbam;
+- tf->lbah = lbah;
+-
+- if (tf->flags & ATA_TFLAG_LBA48) {
+- tf->hob_feature = feature >> 8;
+- tf->hob_nsect = nsect >> 8;
+- tf->hob_lbal = lbal >> 8;
+- tf->hob_lbam = lbam >> 8;
+- tf->hob_lbah = lbah >> 8;
+- }
+-}
+-
+-
+-/*
+- * vsc_sata_interrupt
+- *
+- * Read the interrupt register and process for the devices that have them pending.
+- */
+-static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
+- struct pt_regs *regs)
+-{
+- struct ata_host_set *host_set = dev_instance;
+- unsigned int i;
+- unsigned int handled = 0;
+- u32 int_status;
+-
+- spin_lock(&host_set->lock);
+-
+- int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+-
+- for (i = 0; i < host_set->n_ports; i++) {
+- if (int_status & ((u32) 0xFF << (8 * i))) {
+- struct ata_port *ap;
+-
+- ap = host_set->ports[i];
+-
+- if (is_vsc_sata_int_err(i, int_status)) {
+- u32 err_status;
+- printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
+- err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
+- vsc_sata_scr_write(ap, SCR_ERROR, err_status);
+- handled++;
+- }
+-
+- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+- struct ata_queued_cmd *qc;
+-
+- qc = ata_qc_from_tag(ap, ap->active_tag);
+- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+- handled += ata_host_intr(ap, qc);
+- else if (is_vsc_sata_int_err(i, int_status)) {
+- /*
+- * On some chips (i.e. Intel 31244), an error
+- * interrupt will sneak in at initialization
+- * time (phy state changes). Clearing the SCR
+- * error register is not required, but it prevents
+- * the phy state change interrupts from recurring
+- * later.
+- */
+- u32 err_status;
+- err_status = vsc_sata_scr_read(ap, SCR_ERROR);
+- printk(KERN_DEBUG "%s: clearing interrupt, "
+- "status %x; sata err status %x\n",
+- __FUNCTION__,
+- int_status, err_status);
+- vsc_sata_scr_write(ap, SCR_ERROR, err_status);
+- /* Clear interrupt status */
+- ata_chk_status(ap);
+- handled++;
+- }
+- }
+- }
+- }
+-
+- spin_unlock(&host_set->lock);
+-
+- return IRQ_RETVAL(handled);
+-}
+-
+-
+-static struct scsi_host_template vsc_sata_sht = {
+- .module = THIS_MODULE,
+- .name = DRV_NAME,
+- .ioctl = ata_scsi_ioctl,
+- .queuecommand = ata_scsi_queuecmd,
+- .can_queue = ATA_DEF_QUEUE,
+- .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
+- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+- .emulated = ATA_SHT_EMULATED,
+- .use_clustering = ATA_SHT_USE_CLUSTERING,
+- .proc_name = DRV_NAME,
+- .dma_boundary = ATA_DMA_BOUNDARY,
+- .slave_configure = ata_scsi_slave_config,
+- .slave_destroy = ata_scsi_slave_destroy,
+- .bios_param = ata_std_bios_param,
+-};
+-
+-
+-static const struct ata_port_operations vsc_sata_ops = {
+- .port_disable = ata_port_disable,
+- .tf_load = vsc_sata_tf_load,
+- .tf_read = vsc_sata_tf_read,
+- .exec_command = ata_exec_command,
+- .check_status = ata_check_status,
+- .dev_select = ata_std_dev_select,
+- .bmdma_setup = ata_bmdma_setup,
+- .bmdma_start = ata_bmdma_start,
+- .bmdma_stop = ata_bmdma_stop,
+- .bmdma_status = ata_bmdma_status,
+- .qc_prep = ata_qc_prep,
+- .qc_issue = ata_qc_issue_prot,
+- .data_xfer = ata_mmio_data_xfer,
+- .freeze = ata_bmdma_freeze,
+- .thaw = ata_bmdma_thaw,
+- .error_handler = ata_bmdma_error_handler,
+- .post_internal_cmd = ata_bmdma_post_internal_cmd,
+- .irq_handler = vsc_sata_interrupt,
+- .irq_clear = ata_bmdma_irq_clear,
+- .scr_read = vsc_sata_scr_read,
+- .scr_write = vsc_sata_scr_write,
+- .port_start = ata_port_start,
+- .port_stop = ata_port_stop,
+- .host_stop = ata_pci_host_stop,
+-};
+-
+-static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+-{
+- port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
+- port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
+- port->error_addr = base + VSC_SATA_TF_ERROR_OFFSET;
+- port->feature_addr = base + VSC_SATA_TF_FEATURE_OFFSET;
+- port->nsect_addr = base + VSC_SATA_TF_NSECT_OFFSET;
+- port->lbal_addr = base + VSC_SATA_TF_LBAL_OFFSET;
+- port->lbam_addr = base + VSC_SATA_TF_LBAM_OFFSET;
+- port->lbah_addr = base + VSC_SATA_TF_LBAH_OFFSET;
+- port->device_addr = base + VSC_SATA_TF_DEVICE_OFFSET;
+- port->status_addr = base + VSC_SATA_TF_STATUS_OFFSET;
+- port->command_addr = base + VSC_SATA_TF_COMMAND_OFFSET;
+- port->altstatus_addr = base + VSC_SATA_TF_ALTSTATUS_OFFSET;
+- port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET;
+- port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET;
+- port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET;
+- writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+- writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
+-}
+-
+-
+-static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+-{
+- static int printed_version;
+- struct ata_probe_ent *probe_ent = NULL;
+- unsigned long base;
+- int pci_dev_busy = 0;
+- void __iomem *mmio_base;
+- int rc;
+-
+- if (!printed_version++)
+- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+-
+- rc = pci_enable_device(pdev);
+- if (rc)
+- return rc;
+-
+- /*
+- * Check if we have needed resource mapped.
+- */
+- if (pci_resource_len(pdev, 0) == 0) {
+- rc = -ENODEV;
+- goto err_out;
+- }
+-
+- rc = pci_request_regions(pdev, DRV_NAME);
+- if (rc) {
+- pci_dev_busy = 1;
+- goto err_out;
+- }
+-
+- /*
+- * Use 32 bit DMA mask, because 64 bit address support is poor.
+- */
+- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc)
+- goto err_out_regions;
+- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+- if (rc)
+- goto err_out_regions;
+-
+- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+- if (probe_ent == NULL) {
+- rc = -ENOMEM;
+- goto err_out_regions;
+- }
+- memset(probe_ent, 0, sizeof(*probe_ent));
+- probe_ent->dev = pci_dev_to_dev(pdev);
+- INIT_LIST_HEAD(&probe_ent->node);
+-
+- mmio_base = pci_iomap(pdev, 0, 0);
+- if (mmio_base == NULL) {
+- rc = -ENOMEM;
+- goto err_out_free_ent;
+- }
+- base = (unsigned long) mmio_base;
+-
+- /*
+- * Due to a bug in the chip, the default cache line size can't be used
+- */
+- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+-
+- probe_ent->sht = &vsc_sata_sht;
+- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+- ATA_FLAG_MMIO;
+- probe_ent->port_ops = &vsc_sata_ops;
+- probe_ent->n_ports = 4;
+- probe_ent->irq = pdev->irq;
+- probe_ent->irq_flags = IRQF_SHARED;
+- probe_ent->mmio_base = mmio_base;
+-
+- /* We don't care much about the PIO/UDMA masks, but the core won't like us
+- * if we don't fill these
+- */
+- probe_ent->pio_mask = 0x1f;
+- probe_ent->mwdma_mask = 0x07;
+- probe_ent->udma_mask = 0x7f;
+-
+- /* We have 4 ports per PCI function */
+- vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
+- vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
+- vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
+- vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+-
+- pci_set_master(pdev);
+-
+- /*
+- * Config offset 0x98 is "Extended Control and Status Register 0"
+- * Default value is (1 << 28). All bits except bit 28 are reserved in
+- * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity.
+- * If bit 28 is clear, each port has its own LED.
+- */
+- pci_write_config_dword(pdev, 0x98, 0);
+-
+- /* FIXME: check ata_device_add return value */
+- ata_device_add(probe_ent);
+- kfree(probe_ent);
+-
+- return 0;
+-
+-err_out_free_ent:
+- kfree(probe_ent);
+-err_out_regions:
+- pci_release_regions(pdev);
+-err_out:
+- if (!pci_dev_busy)
+- pci_disable_device(pdev);
+- return rc;
+-}
+-
+-
+-static const struct pci_device_id vsc_sata_pci_tbl[] = {
+- { PCI_VENDOR_ID_VITESSE, 0x7174,
+- PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+- { PCI_VENDOR_ID_INTEL, 0x3200,
+- PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+- { } /* terminate list */
+-};
+-
+-
+-static struct pci_driver vsc_sata_pci_driver = {
+- .name = DRV_NAME,
+- .id_table = vsc_sata_pci_tbl,
+- .probe = vsc_sata_init_one,
+- .remove = ata_pci_remove_one,
+-};
+-
+-
+-static int __init vsc_sata_init(void)
+-{
+- return pci_module_init(&vsc_sata_pci_driver);
+-}
+-
+-
+-static void __exit vsc_sata_exit(void)
+-{
+- pci_unregister_driver(&vsc_sata_pci_driver);
+-}
+-
+-
+-MODULE_AUTHOR("Jeremy Higdon");
+-MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
+-MODULE_VERSION(DRV_VERSION);
+-
+-module_init(vsc_sata_init);
+-module_exit(vsc_sata_exit);
+diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
+index b332cad..c59f315 100644
+--- a/drivers/scsi/scsi.c
++++ b/drivers/scsi/scsi.c
+@@ -96,7 +96,11 @@ unsigned int scsi_logging_level;
+ EXPORT_SYMBOL(scsi_logging_level);
+ #endif
+
+-const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
++/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
++ * You may not alter any existing entry (although adding new ones is
++ * encouraged once assigned by ANSI/INCITS T10
++ */
++static const char *const scsi_device_types[] = {
+ "Direct-Access ",
+ "Sequential-Access",
+ "Printer ",
+@@ -107,13 +111,29 @@ const char *const scsi_device_types[MAX_
+ "Optical Device ",
+ "Medium Changer ",
+ "Communications ",
+- "Unknown ",
+- "Unknown ",
++ "ASC IT8 ",
++ "ASC IT8 ",
+ "RAID ",
+ "Enclosure ",
+ "Direct-Access-RBC",
++ "Optical card ",
++ "Bridge controller",
++ "Object storage ",
++ "Automation/Drive ",
+ };
+-EXPORT_SYMBOL(scsi_device_types);
++
++const char * scsi_device_type(unsigned type)
++{
++ if (type == 0x1e)
++ return "Well-known LUN ";
++ if (type == 0x1f)
++ return "No Device ";
++ if (type >= ARRAY_SIZE(scsi_device_types))
++ return "Unknown ";
++ return scsi_device_types[type];
++}
++
++EXPORT_SYMBOL(scsi_device_type);
+
+ struct scsi_host_cmd_pool {
+ kmem_cache_t *slab;
+@@ -572,12 +592,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
+ return rtn;
+ }
+
+-
+-/*
+- * Per-CPU I/O completion queue.
+- */
+-static DEFINE_PER_CPU(struct list_head, scsi_done_q);
+-
+ /**
+ * scsi_req_abort_cmd -- Request command recovery for the specified command
+ * cmd: pointer to the SCSI command of interest
+@@ -835,14 +849,14 @@ EXPORT_SYMBOL(scsi_track_queue_full);
+ */
+ int scsi_device_get(struct scsi_device *sdev)
+ {
+- if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
++ if (sdev->sdev_state == SDEV_DEL)
+ return -ENXIO;
+ if (!get_device(&sdev->sdev_gendev))
+ return -ENXIO;
+- if (!try_module_get(sdev->host->hostt->module)) {
+- put_device(&sdev->sdev_gendev);
+- return -ENXIO;
+- }
++ /* We can fail this if we're doing SCSI operations
++ * from module exit (like cache flush) */
++ try_module_get(sdev->host->hostt->module);
++
+ return 0;
+ }
+ EXPORT_SYMBOL(scsi_device_get);
+@@ -857,7 +871,14 @@ EXPORT_SYMBOL(scsi_device_get);
+ */
+ void scsi_device_put(struct scsi_device *sdev)
+ {
+- module_put(sdev->host->hostt->module);
++ struct module *module = sdev->host->hostt->module;
++
++#ifdef CONFIG_MODULE_UNLOAD
++ /* The module refcount will be zero if scsi_device_get()
++ * was called from a module removal routine */
++ if (module && module_refcount(module) != 0)
++ module_put(module);
++#endif
+ put_device(&sdev->sdev_gendev);
+ }
+ EXPORT_SYMBOL(scsi_device_put);
+@@ -1038,7 +1059,7 @@ int scsi_device_cancel(struct scsi_devic
+
+ spin_lock_irqsave(&sdev->list_lock, flags);
+ list_for_each_entry(scmd, &sdev->cmd_list, list) {
+- if (scmd->request && scmd->request->rq_status != RQ_INACTIVE) {
++ if (scmd->request) {
+ /*
+ * If we are unable to remove the timer, it means
+ * that the command has already timed out or
+@@ -1075,7 +1096,7 @@ MODULE_PARM_DESC(scsi_logging_level, "a
+
+ static int __init init_scsi(void)
+ {
+- int error, i;
++ int error;
+
+ error = scsi_init_queue();
+ if (error)
+@@ -1096,8 +1117,7 @@ static int __init init_scsi(void)
+ if (error)
+ goto cleanup_sysctl;
+
+- for_each_possible_cpu(i)
+- INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
++ scsi_netlink_init();
+
+ printk(KERN_NOTICE "SCSI subsystem initialized\n");
+ return 0;
+@@ -1119,6 +1139,7 @@ cleanup_queue:
+
+ static void __exit exit_scsi(void)
+ {
++ scsi_netlink_exit();
+ scsi_sysfs_unregister();
+ scsi_exit_sysctl();
+ scsi_exit_hosts();
+diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
+index f51e466..d5a55fa 100644
+--- a/drivers/scsi/scsi.h
++++ b/drivers/scsi/scsi.h
+@@ -20,8 +20,6 @@
+ #ifndef _SCSI_H
+ #define _SCSI_H
+
+-#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
+-
+ #include <scsi/scsi_cmnd.h>
+ #include <scsi/scsi_device.h>
+ #include <scsi/scsi_eh.h>
+diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
+index a80303c..30ee3d7 100644
+--- a/drivers/scsi/scsi_debug.c
++++ b/drivers/scsi/scsi_debug.c
+@@ -1,5 +1,4 @@
+ /*
+- * linux/kernel/scsi_debug.c
+ * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Copyright (C) 1992 Eric Youngdale
+ * Simulate a host adapter with 2 disks attached. Do a lot of checking
+@@ -8,7 +7,9 @@
+ * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * This version is more generic, simulating a variable number of disk
+- * (or disk like devices) sharing a common amount of RAM
++ * (or disk like devices) sharing a common amount of RAM. To be more
++ * realistic, the simulated devices have the transport attributes of
++ * SAS disks.
+ *
+ *
+ * For documentation see http://www.torque.net/sg/sdebug26.html
+@@ -50,8 +51,8 @@
+ #include "scsi_logging.h"
+ #include "scsi_debug.h"
+
+-#define SCSI_DEBUG_VERSION "1.79"
+-static const char * scsi_debug_version_date = "20060604";
++#define SCSI_DEBUG_VERSION "1.80"
++static const char * scsi_debug_version_date = "20061018";
+
+ /* Additional Sense Code (ASC) used */
+ #define NO_ADDITIONAL_SENSE 0x0
+@@ -86,6 +87,8 @@ static const char * scsi_debug_version_d
+ #define DEF_D_SENSE 0
+ #define DEF_NO_LUN_0 0
+ #define DEF_VIRTUAL_GB 0
++#define DEF_FAKE_RW 0
++#define DEF_VPD_USE_HOSTNO 1
+
+ /* bit mask values for scsi_debug_opts */
+ #define SCSI_DEBUG_OPT_NOISE 1
+@@ -127,6 +130,8 @@ static int scsi_debug_ptype = DEF_PTYPE;
+ static int scsi_debug_dsense = DEF_D_SENSE;
+ static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
+ static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
++static int scsi_debug_fake_rw = DEF_FAKE_RW;
++static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
+
+ static int scsi_debug_cmnd_count = 0;
+
+@@ -249,6 +254,8 @@ static int resp_requests(struct scsi_cmn
+ struct sdebug_dev_info * devip);
+ static int resp_start_stop(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip);
++static int resp_report_tgtpgs(struct scsi_cmnd * scp,
++ struct sdebug_dev_info * devip);
+ static int resp_readcap(struct scsi_cmnd * SCpnt,
+ struct sdebug_dev_info * devip);
+ static int resp_readcap16(struct scsi_cmnd * SCpnt,
+@@ -282,9 +289,9 @@ static void __init sdebug_build_parts(un
+ static void __init init_all_queued(void);
+ static void stop_all_queued(void);
+ static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
+-static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
+- int dev_id_num, const char * dev_id_str,
+- int dev_id_str_len);
++static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
++ int target_dev_id, int dev_id_num,
++ const char * dev_id_str, int dev_id_str_len);
+ static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
+ static int do_create_driverfs_files(void);
+ static void do_remove_driverfs_files(void);
+@@ -417,12 +424,23 @@ int scsi_debug_queuecommand(struct scsi_
+ }
+ errsts = resp_readcap16(SCpnt, devip);
+ break;
++ case MAINTENANCE_IN:
++ if (MI_REPORT_TARGET_PGS != cmd[1]) {
++ mk_sense_buffer(devip, ILLEGAL_REQUEST,
++ INVALID_OPCODE, 0);
++ errsts = check_condition_result;
++ break;
++ }
++ errsts = resp_report_tgtpgs(SCpnt, devip);
++ break;
+ case READ_16:
+ case READ_12:
+ case READ_10:
+ case READ_6:
+ if ((errsts = check_readiness(SCpnt, 0, devip)))
+ break;
++ if (scsi_debug_fake_rw)
++ break;
+ if ((*cmd) == READ_16) {
+ for (lba = 0, j = 0; j < 8; ++j) {
+ if (j > 0)
+@@ -465,6 +483,8 @@ int scsi_debug_queuecommand(struct scsi_
+ case WRITE_6:
+ if ((errsts = check_readiness(SCpnt, 0, devip)))
+ break;
++ if (scsi_debug_fake_rw)
++ break;
+ if ((*cmd) == WRITE_16) {
+ for (lba = 0, j = 0; j < 8; ++j) {
+ if (j > 0)
+@@ -656,8 +676,9 @@ static const char * inq_vendor_id = "Lin
+ static const char * inq_product_id = "scsi_debug ";
+ static const char * inq_product_rev = "0004";
+
+-static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
+- int dev_id_num, const char * dev_id_str,
++static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
++ int target_dev_id, int dev_id_num,
++ const char * dev_id_str,
+ int dev_id_str_len)
+ {
+ int num, port_a;
+@@ -711,6 +732,15 @@ static int inquiry_evpd_83(unsigned char
+ arr[num++] = (port_a >> 16) & 0xff;
+ arr[num++] = (port_a >> 8) & 0xff;
+ arr[num++] = port_a & 0xff;
++ /* NAA-5, Target port group identifier */
++ arr[num++] = 0x61; /* proto=sas, binary */
++ arr[num++] = 0x95; /* piv=1, target port group id */
++ arr[num++] = 0x0;
++ arr[num++] = 0x4;
++ arr[num++] = 0;
++ arr[num++] = 0;
++ arr[num++] = (port_group_id >> 8) & 0xff;
++ arr[num++] = port_group_id & 0xff;
+ /* NAA-5, Target device identifier */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0xa3; /* piv=1, target device, naa */
+@@ -919,12 +949,12 @@ static int resp_inquiry(struct scsi_cmnd
+ struct sdebug_dev_info * devip)
+ {
+ unsigned char pq_pdt;
+- unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
++ unsigned char * arr;
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+- int alloc_len, n;
++ int alloc_len, n, ret;
+
+ alloc_len = (cmd[3] << 8) + cmd[4];
+- memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
++ arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL);
+ if (devip->wlun)
+ pq_pdt = 0x1e; /* present, wlun */
+ else if (scsi_debug_no_lun_0 && (0 == devip->lun))
+@@ -935,12 +965,17 @@ static int resp_inquiry(struct scsi_cmnd
+ if (0x2 & cmd[1]) { /* CMDDT bit set */
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
++ kfree(arr);
+ return check_condition_result;
+ } else if (0x1 & cmd[1]) { /* EVPD bit set */
+- int lu_id_num, target_dev_id, len;
++ int lu_id_num, port_group_id, target_dev_id, len;
+ char lu_id_str[6];
+ int host_no = devip->sdbg_host->shost->host_no;
+
++ port_group_id = (((host_no + 1) & 0x7f) << 8) +
++ (devip->channel & 0x7f);
++ if (0 == scsi_debug_vpd_use_hostno)
++ host_no = 0;
+ lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
+ (devip->target * 1000) + devip->lun);
+ target_dev_id = ((host_no + 1) * 2000) +
+@@ -966,8 +1001,9 @@ static int resp_inquiry(struct scsi_cmnd
+ memcpy(&arr[4], lu_id_str, len);
+ } else if (0x83 == cmd[2]) { /* device identification */
+ arr[1] = cmd[2]; /*sanity */
+- arr[3] = inquiry_evpd_83(&arr[4], target_dev_id,
+- lu_id_num, lu_id_str, len);
++ arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
++ target_dev_id, lu_id_num,
++ lu_id_str, len);
+ } else if (0x84 == cmd[2]) { /* Software interface ident. */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_84(&arr[4]);
+@@ -1001,17 +1037,22 @@ static int resp_inquiry(struct scsi_cmnd
+ /* Illegal request, invalid field in cdb */
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
++ kfree(arr);
+ return check_condition_result;
+ }
+ len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
+- return fill_from_dev_buffer(scp, arr,
++ ret = fill_from_dev_buffer(scp, arr,
+ min(len, SDEBUG_MAX_INQ_ARR_SZ));
++ kfree(arr);
++ return ret;
+ }
+ /* drops through here for a standard inquiry */
+ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
+ arr[2] = scsi_debug_scsi_level;
+ arr[3] = 2; /* response_data_format==2 */
+ arr[4] = SDEBUG_LONG_INQ_SZ - 5;
++ if (0 == scsi_debug_vpd_use_hostno)
++ arr[5] = 0x10; /* claim: implicit TGPS */
+ arr[6] = 0x10; /* claim: MultiP */
+ /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
+ arr[7] = 0xa; /* claim: LINKED + CMDQUE */
+@@ -1028,8 +1069,10 @@ static int resp_inquiry(struct scsi_cmnd
+ arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
+ }
+ arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
+- return fill_from_dev_buffer(scp, arr,
++ ret = fill_from_dev_buffer(scp, arr,
+ min(alloc_len, SDEBUG_LONG_INQ_SZ));
++ kfree(arr);
++ return ret;
+ }
+
+ static int resp_requests(struct scsi_cmnd * scp,
+@@ -1059,19 +1102,6 @@ static int resp_requests(struct scsi_cmn
+ arr[12] = THRESHOLD_EXCEEDED;
+ arr[13] = 0xff; /* TEST set and MRIE==6 */
+ }
+- } else if (devip->stopped) {
+- if (want_dsense) {
+- arr[0] = 0x72;
+- arr[1] = 0x0; /* NO_SENSE in sense_key */
+- arr[2] = LOW_POWER_COND_ON;
+- arr[3] = 0x0; /* TEST set and MRIE==6 */
+- } else {
+- arr[0] = 0x70;
+- arr[2] = 0x0; /* NO_SENSE in sense_key */
+- arr[7] = 0xa; /* 18 byte sense buffer */
+- arr[12] = LOW_POWER_COND_ON;
+- arr[13] = 0x0; /* TEST set and MRIE==6 */
+- }
+ } else {
+ memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
+ if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
+@@ -1173,6 +1203,87 @@ static int resp_readcap16(struct scsi_cm
+ min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
+ }
+
++#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
++
++static int resp_report_tgtpgs(struct scsi_cmnd * scp,
++ struct sdebug_dev_info * devip)
++{
++ unsigned char *cmd = (unsigned char *)scp->cmnd;
++ unsigned char * arr;
++ int host_no = devip->sdbg_host->shost->host_no;
++ int n, ret, alen, rlen;
++ int port_group_a, port_group_b, port_a, port_b;
++
++ alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
++ + cmd[9]);
++
++ arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL);
++ /*
++ * EVPD page 0x88 states we have two ports, one
++ * real and a fake port with no device connected.
++ * So we create two port groups with one port each
++ * and set the group with port B to unavailable.
++ */
++ port_a = 0x1; /* relative port A */
++ port_b = 0x2; /* relative port B */
++ port_group_a = (((host_no + 1) & 0x7f) << 8) +
++ (devip->channel & 0x7f);
++ port_group_b = (((host_no + 1) & 0x7f) << 8) +
++ (devip->channel & 0x7f) + 0x80;
++
++ /*
++ * The asymmetric access state is cycled according to the host_id.
++ */
++ n = 4;
++ if (0 == scsi_debug_vpd_use_hostno) {
++ arr[n++] = host_no % 3; /* Asymm access state */
++ arr[n++] = 0x0F; /* claim: all states are supported */
++ } else {
++ arr[n++] = 0x0; /* Active/Optimized path */
++ arr[n++] = 0x01; /* claim: only support active/optimized paths */
++ }
++ arr[n++] = (port_group_a >> 8) & 0xff;
++ arr[n++] = port_group_a & 0xff;
++ arr[n++] = 0; /* Reserved */
++ arr[n++] = 0; /* Status code */
++ arr[n++] = 0; /* Vendor unique */
++ arr[n++] = 0x1; /* One port per group */
++ arr[n++] = 0; /* Reserved */
++ arr[n++] = 0; /* Reserved */
++ arr[n++] = (port_a >> 8) & 0xff;
++ arr[n++] = port_a & 0xff;
++ arr[n++] = 3; /* Port unavailable */
++ arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
++ arr[n++] = (port_group_b >> 8) & 0xff;
++ arr[n++] = port_group_b & 0xff;
++ arr[n++] = 0; /* Reserved */
++ arr[n++] = 0; /* Status code */
++ arr[n++] = 0; /* Vendor unique */
++ arr[n++] = 0x1; /* One port per group */
++ arr[n++] = 0; /* Reserved */
++ arr[n++] = 0; /* Reserved */
++ arr[n++] = (port_b >> 8) & 0xff;
++ arr[n++] = port_b & 0xff;
++
++ rlen = n - 4;
++ arr[0] = (rlen >> 24) & 0xff;
++ arr[1] = (rlen >> 16) & 0xff;
++ arr[2] = (rlen >> 8) & 0xff;
++ arr[3] = rlen & 0xff;
++
++ /*
++ * Return the smallest value of either
++ * - The allocated length
++ * - The constructed command length
++ * - The maximum array size
++ */
++ rlen = min(alen,n);
++ ret = fill_from_dev_buffer(scp, arr,
++ min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
++ kfree(arr);
++ return ret;
++}
++
+ /* <<Following mode page info copied from ST318451LW>> */
+
+ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
+@@ -1325,21 +1436,26 @@ static int resp_sas_sha_m_spg(unsigned c
+ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
+ struct sdebug_dev_info * devip)
+ {
+- unsigned char dbd;
+- int pcontrol, pcode, subpcode;
++ unsigned char dbd, llbaa;
++ int pcontrol, pcode, subpcode, bd_len;
+ unsigned char dev_spec;
+- int alloc_len, msense_6, offset, len, errsts, target_dev_id;
++ int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
+ unsigned char * ap;
+ unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+- dbd = cmd[1] & 0x8;
++ dbd = !!(cmd[1] & 0x8);
+ pcontrol = (cmd[2] & 0xc0) >> 6;
+ pcode = cmd[2] & 0x3f;
+ subpcode = cmd[3];
+ msense_6 = (MODE_SENSE == cmd[0]);
++ llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
++ if ((0 == scsi_debug_ptype) && (0 == dbd))
++ bd_len = llbaa ? 16 : 8;
++ else
++ bd_len = 0;
+ alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
+ memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
+ if (0x3 == pcontrol) { /* Saving values not supported */
+@@ -1349,15 +1465,58 @@ static int resp_mode_sense(struct scsi_c
+ }
+ target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
+ (devip->target * 1000) - 3;
+- dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
++ /* set DPOFUA bit for disks */
++ if (0 == scsi_debug_ptype)
++ dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
++ else
++ dev_spec = 0x0;
+ if (msense_6) {
+ arr[2] = dev_spec;
++ arr[3] = bd_len;
+ offset = 4;
+ } else {
+ arr[3] = dev_spec;
++ if (16 == bd_len)
++ arr[4] = 0x1; /* set LONGLBA bit */
++ arr[7] = bd_len; /* assume 255 or less */
+ offset = 8;
+ }
+ ap = arr + offset;
++ if ((bd_len > 0) && (0 == sdebug_capacity)) {
++ if (scsi_debug_virtual_gb > 0) {
++ sdebug_capacity = 2048 * 1024;
++ sdebug_capacity *= scsi_debug_virtual_gb;
++ } else
++ sdebug_capacity = sdebug_store_sectors;
++ }
++ if (8 == bd_len) {
++ if (sdebug_capacity > 0xfffffffe) {
++ ap[0] = 0xff;
++ ap[1] = 0xff;
++ ap[2] = 0xff;
++ ap[3] = 0xff;
++ } else {
++ ap[0] = (sdebug_capacity >> 24) & 0xff;
++ ap[1] = (sdebug_capacity >> 16) & 0xff;
++ ap[2] = (sdebug_capacity >> 8) & 0xff;
++ ap[3] = sdebug_capacity & 0xff;
++ }
++ ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
++ ap[7] = SECT_SIZE_PER(target) & 0xff;
++ offset += bd_len;
++ ap = arr + offset;
++ } else if (16 == bd_len) {
++ unsigned long long capac = sdebug_capacity;
++
++ for (k = 0; k < 8; ++k, capac >>= 8)
++ ap[7 - k] = capac & 0xff;
++ ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
++ ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
++ ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
++ ap[15] = SECT_SIZE_PER(target) & 0xff;
++ offset += bd_len;
++ ap = arr + offset;
++ }
+
+ if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
+ /* TODO: Control Extension page */
+@@ -1471,7 +1630,7 @@ static int resp_mode_select(struct scsi_
+ " IO sent=%d bytes\n", param_len, res);
+ md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
+ bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
+- if ((md_len > 2) || (0 != bd_len)) {
++ if (md_len > 2) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+@@ -1544,7 +1703,7 @@ static int resp_ie_l_pg(unsigned char *
+ static int resp_log_sense(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+ {
+- int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n;
++ int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
+ unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+@@ -1560,23 +1719,63 @@ static int resp_log_sense(struct scsi_cm
+ }
+ pcontrol = (cmd[2] & 0xc0) >> 6;
+ pcode = cmd[2] & 0x3f;
++ subpcode = cmd[3] & 0xff;
+ alloc_len = (cmd[7] << 8) + cmd[8];
+ arr[0] = pcode;
+- switch (pcode) {
+- case 0x0: /* Supported log pages log page */
+- n = 4;
+- arr[n++] = 0x0; /* this page */
+- arr[n++] = 0xd; /* Temperature */
+- arr[n++] = 0x2f; /* Informational exceptions */
+- arr[3] = n - 4;
+- break;
+- case 0xd: /* Temperature log page */
+- arr[3] = resp_temp_l_pg(arr + 4);
+- break;
+- case 0x2f: /* Informational exceptions log page */
+- arr[3] = resp_ie_l_pg(arr + 4);
+- break;
+- default:
++ if (0 == subpcode) {
++ switch (pcode) {
++ case 0x0: /* Supported log pages log page */
++ n = 4;
++ arr[n++] = 0x0; /* this page */
++ arr[n++] = 0xd; /* Temperature */
++ arr[n++] = 0x2f; /* Informational exceptions */
++ arr[3] = n - 4;
++ break;
++ case 0xd: /* Temperature log page */
++ arr[3] = resp_temp_l_pg(arr + 4);
++ break;
++ case 0x2f: /* Informational exceptions log page */
++ arr[3] = resp_ie_l_pg(arr + 4);
++ break;
++ default:
++ mk_sense_buffer(devip, ILLEGAL_REQUEST,
++ INVALID_FIELD_IN_CDB, 0);
++ return check_condition_result;
++ }
++ } else if (0xff == subpcode) {
++ arr[0] |= 0x40;
++ arr[1] = subpcode;
++ switch (pcode) {
++ case 0x0: /* Supported log pages and subpages log page */
++ n = 4;
++ arr[n++] = 0x0;
++ arr[n++] = 0x0; /* 0,0 page */
++ arr[n++] = 0x0;
++ arr[n++] = 0xff; /* this page */
++ arr[n++] = 0xd;
++ arr[n++] = 0x0; /* Temperature */
++ arr[n++] = 0x2f;
++ arr[n++] = 0x0; /* Informational exceptions */
++ arr[3] = n - 4;
++ break;
++ case 0xd: /* Temperature subpages */
++ n = 4;
++ arr[n++] = 0xd;
++ arr[n++] = 0x0; /* Temperature */
++ arr[3] = n - 4;
++ break;
++ case 0x2f: /* Informational exceptions subpages */
++ n = 4;
++ arr[n++] = 0x2f;
++ arr[n++] = 0x0; /* Informational exceptions */
++ arr[3] = n - 4;
++ break;
++ default:
++ mk_sense_buffer(devip, ILLEGAL_REQUEST,
++ INVALID_FIELD_IN_CDB, 0);
++ return check_condition_result;
++ }
++ } else {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+@@ -2151,11 +2350,18 @@ static int schedule_resp(struct scsi_cmn
+ }
+ }
+
++/* Note: The following macros create attribute files in the
++ /sys/module/scsi_debug/parameters directory. Unfortunately this
++ driver is unaware of a change and cannot trigger auxiliary actions
++ as it can when the corresponding attribute in the
++ /sys/bus/pseudo/drivers/scsi_debug directory is changed.
++ */
+ module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
+ module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
+ module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
+ module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
+ module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
++module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
+ module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
+ module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
+ module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
+@@ -2164,6 +2370,8 @@ module_param_named(opts, scsi_debug_opts
+ module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
+ module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
+ module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
++module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
++ S_IRUGO | S_IWUSR);
+
+ MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+ MODULE_DESCRIPTION("SCSI debug adapter driver");
+@@ -2175,6 +2383,7 @@ MODULE_PARM_DESC(delay, "# of jiffies to
+ MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
+ MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
+ MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
++MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
+ MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
+ MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
+ MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
+@@ -2183,6 +2392,7 @@ MODULE_PARM_DESC(opts, "1->noise, 2->med
+ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
+ MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
+ MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
++MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
+
+
+ static char sdebug_info[256];
+@@ -2334,6 +2544,24 @@ static ssize_t sdebug_dsense_store(struc
+ DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
+ sdebug_dsense_store);
+
++static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
++{
++ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
++}
++static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
++ const char * buf, size_t count)
++{
++ int n;
++
++ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
++ scsi_debug_fake_rw = n;
++ return count;
++ }
++ return -EINVAL;
++}
++DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
++ sdebug_fake_rw_store);
++
+ static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
+ {
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
+@@ -2487,6 +2715,31 @@ static ssize_t sdebug_add_host_store(str
+ DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
+ sdebug_add_host_store);
+
++static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
++ char * buf)
++{
++ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
++}
++static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
++ const char * buf, size_t count)
++{
++ int n;
++
++ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
++ scsi_debug_vpd_use_hostno = n;
++ return count;
++ }
++ return -EINVAL;
++}
++DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
++ sdebug_vpd_use_hostno_store);
++
++/* Note: The following function creates attribute files in the
++ /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
++ files (over those found in the /sys/module/scsi_debug/parameters
++ directory) is that auxiliary actions can be triggered when an attribute
++ is changed. For example see: sdebug_add_host_store() above.
++ */
+ static int do_create_driverfs_files(void)
+ {
+ int ret;
+@@ -2496,23 +2749,31 @@ static int do_create_driverfs_files(void
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
++ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+- ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
++ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
++ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
++ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
++ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
+ return ret;
+ }
+
+ static void do_remove_driverfs_files(void)
+ {
++ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
++ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+- driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
++ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
++ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
++ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
+index 3d0429b..ce63044 100644
+--- a/drivers/scsi/scsi_devinfo.c
++++ b/drivers/scsi/scsi_devinfo.c
+@@ -150,6 +150,7 @@ static struct {
+ {"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
+ {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */
+ {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */
++ {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+ {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN},
+ {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+@@ -161,6 +162,11 @@ static struct {
+ {"HITACHI", "DF600", "*", BLIST_SPARSELUN},
+ {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
+ {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
+ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
+@@ -168,6 +174,14 @@ static struct {
+ {"HP", "C1557A", NULL, BLIST_FORCELUN},
+ {"HP", "C3323-300", "4269", BLIST_NOTQ},
+ {"HP", "C5713A", NULL, BLIST_NOREPORTLUN},
++ {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
+ {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
+@@ -188,6 +202,7 @@ static struct {
+ {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+ {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+ {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
++ {"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
+ {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+ {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+ {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+@@ -210,6 +225,7 @@ static struct {
+ {"SUN", "T300", "*", BLIST_SPARSELUN},
+ {"SUN", "T4", "*", BLIST_SPARSELUN},
+ {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
++ {"Tornado-", "F4", "*", BLIST_NOREPORTLUN},
+ {"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
+ {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
+ {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
+diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
+index 3d355d0..aff1b0c 100644
+--- a/drivers/scsi/scsi_error.c
++++ b/drivers/scsi/scsi_error.c
+@@ -495,7 +495,7 @@ static int scsi_send_eh_cmnd(struct scsi
+ memcpy(scmd->cmnd, cmnd, cmnd_size);
+
+ if (copy_sense) {
+- int gfp_mask = GFP_ATOMIC;
++ gfp_t gfp_mask = GFP_ATOMIC;
+
+ if (shost->hostt->unchecked_isa_dma)
+ gfp_mask |= __GFP_DMA;
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index 077c1c6..d2c02df 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -82,7 +82,7 @@ static void scsi_unprep_request(struct r
+ {
+ struct scsi_cmnd *cmd = req->special;
+
+- req->flags &= ~REQ_DONTPREP;
++ req->cmd_flags &= ~REQ_DONTPREP;
+ req->special = NULL;
+
+ scsi_put_command(cmd);
+@@ -196,7 +196,8 @@ int scsi_execute(struct scsi_device *sde
+ req->sense_len = 0;
+ req->retries = retries;
+ req->timeout = timeout;
+- req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET;
++ req->cmd_type = REQ_TYPE_BLOCK_PC;
++ req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT;
+
+ /*
+ * head injection *required* here otherwise quiesce won't work
+@@ -397,7 +398,8 @@ int scsi_execute_async(struct scsi_devic
+ req = blk_get_request(sdev->request_queue, write, gfp);
+ if (!req)
+ goto free_sense;
+- req->flags |= REQ_BLOCK_PC | REQ_QUIET;
++ req->cmd_type = REQ_TYPE_BLOCK_PC;
++ req->cmd_flags |= REQ_QUIET;
+
+ if (use_sg)
+ err = scsi_req_map_sg(req, buffer, use_sg, bufflen, gfp);
+@@ -424,7 +426,7 @@ int scsi_execute_async(struct scsi_devic
+ free_req:
+ blk_put_request(req);
+ free_sense:
+- kfree(sioc);
++ kmem_cache_free(scsi_io_context_cache, sioc);
+ return DRIVER_ERROR << 24;
+ }
+ EXPORT_SYMBOL_GPL(scsi_execute_async);
+@@ -551,7 +553,15 @@ static void scsi_run_queue(struct reques
+ list_del_init(&sdev->starved_entry);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+- blk_run_queue(sdev->request_queue);
++
++ if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
++ !test_and_set_bit(QUEUE_FLAG_REENTER,
++ &sdev->request_queue->queue_flags)) {
++ blk_run_queue(sdev->request_queue);
++ clear_bit(QUEUE_FLAG_REENTER,
++ &sdev->request_queue->queue_flags);
++ } else
++ blk_run_queue(sdev->request_queue);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (unlikely(!list_empty(&sdev->starved_entry)))
+@@ -925,7 +935,7 @@ void scsi_io_completion(struct scsi_cmnd
+ break;
+ }
+ }
+- if (!(req->flags & REQ_QUIET)) {
++ if (!(req->cmd_flags & REQ_QUIET)) {
+ scmd_printk(KERN_INFO, cmd,
+ "Device not ready: ");
+ scsi_print_sense_hdr("", &sshdr);
+@@ -933,7 +943,7 @@ void scsi_io_completion(struct scsi_cmnd
+ scsi_end_request(cmd, 0, this_count, 1);
+ return;
+ case VOLUME_OVERFLOW:
+- if (!(req->flags & REQ_QUIET)) {
++ if (!(req->cmd_flags & REQ_QUIET)) {
+ scmd_printk(KERN_INFO, cmd,
+ "Volume overflow, CDB: ");
+ __scsi_print_command(cmd->cmnd);
+@@ -955,7 +965,7 @@ void scsi_io_completion(struct scsi_cmnd
+ return;
+ }
+ if (result) {
+- if (!(req->flags & REQ_QUIET)) {
++ if (!(req->cmd_flags & REQ_QUIET)) {
+ scmd_printk(KERN_INFO, cmd,
+ "SCSI error: return code = 0x%08x\n",
+ result);
+@@ -987,7 +997,7 @@ static int scsi_init_io(struct scsi_cmnd
+ /*
+ * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
+ */
+- if ((req->flags & REQ_BLOCK_PC) && !req->bio) {
++ if (blk_pc_request(req) && !req->bio) {
+ cmd->request_bufflen = req->data_len;
+ cmd->request_buffer = req->data;
+ req->buffer = req->data;
+@@ -1074,7 +1084,7 @@ static void scsi_setup_blk_pc_cmnd(struc
+ {
+ struct request *req = cmd->request;
+
+- BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
++ BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
+ memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
+ cmd->cmd_len = req->cmd_len;
+ if (!req->data_len)
+@@ -1131,13 +1141,12 @@ static int scsi_prep_fn(struct request_q
+ * these two cases differently. We differentiate by looking
+ * at request->cmd, as this tells us the real story.
+ */
+- if (req->flags & REQ_SPECIAL && req->special) {
++ if (blk_special_request(req) && req->special)
+ cmd = req->special;
+- } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+-
+- if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) {
+- if(specials_only == SDEV_QUIESCE ||
+- specials_only == SDEV_BLOCK)
++ else if (blk_pc_request(req) || blk_fs_request(req)) {
++ if (unlikely(specials_only) && !(req->cmd_flags & REQ_PREEMPT)){
++ if (specials_only == SDEV_QUIESCE ||
++ specials_only == SDEV_BLOCK)
+ goto defer;
+
+ sdev_printk(KERN_ERR, sdev,
+@@ -1145,7 +1154,6 @@ static int scsi_prep_fn(struct request_q
+ goto kill;
+ }
+
+-
+ /*
+ * Now try and find a command block that we can use.
+ */
+@@ -1176,7 +1184,7 @@ static int scsi_prep_fn(struct request_q
+ * lock. We hope REQ_STARTED prevents anything untoward from
+ * happening now.
+ */
+- if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
++ if (blk_fs_request(req) || blk_pc_request(req)) {
+ int ret;
+
+ /*
+@@ -1208,7 +1216,7 @@ static int scsi_prep_fn(struct request_q
+ /*
+ * Initialize the actual SCSI command for this request.
+ */
+- if (req->flags & REQ_BLOCK_PC) {
++ if (blk_pc_request(req)) {
+ scsi_setup_blk_pc_cmnd(cmd);
+ } else if (req->rq_disk) {
+ struct scsi_driver *drv;
+@@ -1225,7 +1233,7 @@ static int scsi_prep_fn(struct request_q
+ /*
+ * The request is now prepped, no need to come back here
+ */
+- req->flags |= REQ_DONTPREP;
++ req->cmd_flags |= REQ_DONTPREP;
+ return BLKPREP_OK;
+
+ defer:
+@@ -1446,8 +1454,9 @@ static void scsi_request_fn(struct reque
+ if (unlikely(cmd == NULL)) {
+ printk(KERN_CRIT "impossible request in %s.\n"
+ "please mail a stack trace to "
+- "linux-scsi at vger.kernel.org",
++ "linux-scsi at vger.kernel.org\n",
+ __FUNCTION__);
++ blk_dump_rq_flags(req, "foo");
+ BUG();
+ }
+ spin_lock(shost->host_lock);
+diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
+new file mode 100644
+index 0000000..1b59b27
+--- /dev/null
++++ b/drivers/scsi/scsi_netlink.c
+@@ -0,0 +1,199 @@
++/*
++ * scsi_netlink.c - SCSI Transport Netlink Interface
++ *
++ * Copyright (C) 2006 James Smart, Emulex Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#include <linux/time.h>
++#include <linux/jiffies.h>
++#include <linux/security.h>
++#include <net/sock.h>
++#include <net/netlink.h>
++
++#include <scsi/scsi_netlink.h>
++#include "scsi_priv.h"
++
++struct sock *scsi_nl_sock = NULL;
++EXPORT_SYMBOL_GPL(scsi_nl_sock);
++
++
++/**
++ * scsi_nl_rcv_msg -
++ * Receive message handler. Extracts message from a receive buffer.
++ * Validates message header and calls appropriate transport message handler
++ *
++ * @skb: socket receive buffer
++ *
++ **/
++static void
++scsi_nl_rcv_msg(struct sk_buff *skb)
++{
++ struct nlmsghdr *nlh;
++ struct scsi_nl_hdr *hdr;
++ uint32_t rlen;
++ int err;
++
++ while (skb->len >= NLMSG_SPACE(0)) {
++ err = 0;
++
++ nlh = (struct nlmsghdr *) skb->data;
++ if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
++ (skb->len < nlh->nlmsg_len)) {
++ printk(KERN_WARNING "%s: discarding partial skb\n",
++ __FUNCTION__);
++ return;
++ }
++
++ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
++ if (rlen > skb->len)
++ rlen = skb->len;
++
++ if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
++ err = -EBADMSG;
++ goto next_msg;
++ }
++
++ hdr = NLMSG_DATA(nlh);
++ if ((hdr->version != SCSI_NL_VERSION) ||
++ (hdr->magic != SCSI_NL_MAGIC)) {
++ err = -EPROTOTYPE;
++ goto next_msg;
++ }
++
++ if (security_netlink_recv(skb, CAP_SYS_ADMIN)) {
++ err = -EPERM;
++ goto next_msg;
++ }
++
++ if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
++ printk(KERN_WARNING "%s: discarding partial message\n",
++ __FUNCTION__);
++ return;
++ }
++
++ /*
++ * We currently don't support anyone sending us a message
++ */
++
++next_msg:
++ if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
++ netlink_ack(skb, nlh, err);
++
++ skb_pull(skb, rlen);
++ }
++}
++
++
++/**
++ * scsi_nl_rcv_msg -
++ * Receive handler for a socket. Extracts a received message buffer from
++ * the socket, and starts message processing.
++ *
++ * @sk: socket
++ * @len: unused
++ *
++ **/
++static void
++scsi_nl_rcv(struct sock *sk, int len)
++{
++ struct sk_buff *skb;
++
++ while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
++ scsi_nl_rcv_msg(skb);
++ kfree_skb(skb);
++ }
++}
++
++
++/**
++ * scsi_nl_rcv_event -
++ * Event handler for a netlink socket.
++ *
++ * @this: event notifier block
++ * @event: event type
++ * @ptr: event payload
++ *
++ **/
++static int
++scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
++{
++ struct netlink_notify *n = ptr;
++
++ if (n->protocol != NETLINK_SCSITRANSPORT)
++ return NOTIFY_DONE;
++
++ /*
++ * Currently, we are not tracking PID's, etc. There is nothing
++ * to handle.
++ */
++
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block scsi_netlink_notifier = {
++ .notifier_call = scsi_nl_rcv_event,
++};
++
++
++/**
++ * scsi_netlink_init -
++ * Called by SCSI subsystem to intialize the SCSI transport netlink
++ * interface
++ *
++ **/
++void
++scsi_netlink_init(void)
++{
++ int error;
++
++ error = netlink_register_notifier(&scsi_netlink_notifier);
++ if (error) {
++ printk(KERN_ERR "%s: register of event handler failed - %d\n",
++ __FUNCTION__, error);
++ return;
++ }
++
++ scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
++ SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE);
++ if (!scsi_nl_sock) {
++ printk(KERN_ERR "%s: register of recieve handler failed\n",
++ __FUNCTION__);
++ netlink_unregister_notifier(&scsi_netlink_notifier);
++ }
++
++ return;
++}
++
++
++/**
++ * scsi_netlink_exit -
++ * Called by SCSI subsystem to disable the SCSI transport netlink
++ * interface
++ *
++ **/
++void
++scsi_netlink_exit(void)
++{
++ if (scsi_nl_sock) {
++ sock_release(scsi_nl_sock->sk_socket);
++ netlink_unregister_notifier(&scsi_netlink_notifier);
++ }
++
++ return;
++}
++
++
+diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
+index ae24c85..5d023d4 100644
+--- a/drivers/scsi/scsi_priv.h
++++ b/drivers/scsi/scsi_priv.h
+@@ -8,6 +8,7 @@ struct scsi_cmnd;
+ struct scsi_device;
+ struct scsi_host_template;
+ struct Scsi_Host;
++struct scsi_nl_hdr;
+
+
+ /*
+@@ -110,6 +111,16 @@ extern void __scsi_remove_device(struct
+
+ extern struct bus_type scsi_bus_type;
+
++/* scsi_netlink.c */
++#ifdef CONFIG_SCSI_NETLINK
++extern void scsi_netlink_init(void);
++extern void scsi_netlink_exit(void);
++extern struct sock *scsi_nl_sock;
++#else
++static inline void scsi_netlink_init(void) {}
++static inline void scsi_netlink_exit(void) {}
++#endif
++
+ /*
+ * internal scsi timeout functions: for use by mid-layer and transport
+ * classes.
+diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
+index 55200e4..524a5f7 100644
+--- a/drivers/scsi/scsi_proc.c
++++ b/drivers/scsi/scsi_proc.c
+@@ -178,9 +178,7 @@ static int proc_print_scsidevice(struct
+
+ seq_printf(s, "\n");
+
+- seq_printf(s, " Type: %s ",
+- sdev->type < MAX_SCSI_DEVICE_CODE ?
+- scsi_device_types[(int) sdev->type] : "Unknown ");
++ seq_printf(s, " Type: %s ", scsi_device_type(sdev->type));
+ seq_printf(s, " ANSI"
+ " SCSI revision: %02x", (sdev->scsi_level - 1) ?
+ sdev->scsi_level - 1 : 1);
+diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
+index 1bd92b9..fd9e281 100644
+--- a/drivers/scsi/scsi_scan.c
++++ b/drivers/scsi/scsi_scan.c
+@@ -134,59 +134,6 @@ static void scsi_unlock_floptical(struct
+ }
+
+ /**
+- * print_inquiry - printk the inquiry information
+- * @inq_result: printk this SCSI INQUIRY
+- *
+- * Description:
+- * printk the vendor, model, and other information found in the
+- * INQUIRY data in @inq_result.
+- *
+- * Notes:
+- * Remove this, and replace with a hotplug event that logs any
+- * relevant information.
+- **/
+-static void print_inquiry(unsigned char *inq_result)
+-{
+- int i;
+-
+- printk(KERN_NOTICE " Vendor: ");
+- for (i = 8; i < 16; i++)
+- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+- printk("%c", inq_result[i]);
+- else
+- printk(" ");
+-
+- printk(" Model: ");
+- for (i = 16; i < 32; i++)
+- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+- printk("%c", inq_result[i]);
+- else
+- printk(" ");
+-
+- printk(" Rev: ");
+- for (i = 32; i < 36; i++)
+- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+- printk("%c", inq_result[i]);
+- else
+- printk(" ");
+-
+- printk("\n");
+-
+- i = inq_result[0] & 0x1f;
+-
+- printk(KERN_NOTICE " Type: %s ",
+- i <
+- MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
+- "Unknown ");
+- printk(" ANSI SCSI revision: %02x",
+- inq_result[2] & 0x07);
+- if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)
+- printk(" CCS\n");
+- else
+- printk("\n");
+-}
+-
+-/**
+ * scsi_alloc_sdev - allocate and setup a scsi_Device
+ *
+ * Description:
+@@ -319,6 +266,18 @@ static struct scsi_target *__scsi_find_t
+ return found_starget;
+ }
+
++/**
++ * scsi_alloc_target - allocate a new or find an existing target
++ * @parent: parent of the target (need not be a scsi host)
++ * @channel: target channel number (zero if no channels)
++ * @id: target id number
++ *
++ * Return an existing target if one exists, provided it hasn't already
++ * gone into STARGET_DEL state, otherwise allocate a new target.
++ *
++ * The target is returned with an incremented reference, so the caller
++ * is responsible for both reaping and doing a last put
++ */
+ static struct scsi_target *scsi_alloc_target(struct device *parent,
+ int channel, uint id)
+ {
+@@ -384,14 +343,15 @@ static struct scsi_target *scsi_alloc_ta
+ return NULL;
+ }
+ }
++ get_device(dev);
+
+ return starget;
+
+ found:
+ found_target->reap_ref++;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+- put_device(parent);
+ if (found_target->state != STARGET_DEL) {
++ put_device(parent);
+ kfree(starget);
+ return found_target;
+ }
+@@ -450,6 +410,32 @@ void scsi_target_reap(struct scsi_target
+ }
+
+ /**
++ * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string
++ * @s: INQUIRY result string to sanitize
++ * @len: length of the string
++ *
++ * Description:
++ * The SCSI spec says that INQUIRY vendor, product, and revision
++ * strings must consist entirely of graphic ASCII characters,
++ * padded on the right with spaces. Since not all devices obey
++ * this rule, we will replace non-graphic or non-ASCII characters
++ * with spaces. Exception: a NUL character is interpreted as a
++ * string terminator, so all the following characters are set to
++ * spaces.
++ **/
++static void sanitize_inquiry_string(unsigned char *s, int len)
++{
++ int terminated = 0;
++
++ for (; len > 0; (--len, ++s)) {
++ if (*s == 0)
++ terminated = 1;
++ if (terminated || *s < 0x20 || *s > 0x7e)
++ *s = ' ';
++ }
++}
++
++/**
+ * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
+ * @sdev: scsi_device to probe
+ * @inq_result: area to store the INQUIRY result
+@@ -463,7 +449,7 @@ void scsi_target_reap(struct scsi_target
+ * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
+ * are copied to the scsi_device any flags value is stored in *@bflags.
+ **/
+-static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
++static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
+ int result_len, int *bflags)
+ {
+ unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+@@ -522,7 +508,11 @@ static int scsi_probe_lun(struct scsi_de
+ }
+
+ if (result == 0) {
+- response_len = (unsigned char) inq_result[4] + 5;
++ sanitize_inquiry_string(&inq_result[8], 8);
++ sanitize_inquiry_string(&inq_result[16], 16);
++ sanitize_inquiry_string(&inq_result[32], 4);
++
++ response_len = inq_result[4] + 5;
+ if (response_len > 255)
+ response_len = first_inquiry_len; /* sanity */
+
+@@ -628,7 +618,8 @@ static int scsi_probe_lun(struct scsi_de
+ * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
+ * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
+ **/
+-static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
++static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
++ int *bflags)
+ {
+ /*
+ * XXX do not save the inquiry, since it can change underneath us,
+@@ -653,9 +644,8 @@ static int scsi_add_lun(struct scsi_devi
+ if (*bflags & BLIST_ISROM) {
+ /*
+ * It would be better to modify sdev->type, and set
+- * sdev->removable, but then the print_inquiry() output
+- * would not show TYPE_ROM; if print_inquiry() is removed
+- * the issue goes away.
++ * sdev->removable; this can now be done since
++ * print_inquiry has gone away.
+ */
+ inq_result[0] = TYPE_ROM;
+ inq_result[1] |= 0x80; /* removable */
+@@ -684,8 +674,6 @@ static int scsi_add_lun(struct scsi_devi
+ printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
+ }
+
+- print_inquiry(inq_result);
+-
+ /*
+ * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
+ * spec says: The device server is capable of supporting the
+@@ -715,6 +703,12 @@ static int scsi_add_lun(struct scsi_devi
+ if (inq_result[7] & 0x10)
+ sdev->sdtr = 1;
+
++ sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d "
++ "ANSI: %d%s\n", scsi_device_type(sdev->type),
++ sdev->vendor, sdev->model, sdev->rev,
++ sdev->inq_periph_qual, inq_result[2] & 0x07,
++ (inq_result[3] & 0x0f) == 1 ? " CCS" : "");
++
+ /*
+ * End sysfs code.
+ */
+@@ -943,11 +937,26 @@ static int scsi_probe_and_add_lun(struct
+ }
+
+ /*
+- * Non-standard SCSI targets may set the PDT to 0x1f (unknown or
+- * no device type) instead of using the Peripheral Qualifier to
+- * indicate that no LUN is present. For example, USB UFI does this.
++ * Some targets may set slight variations of PQ and PDT to signal
++ * that no LUN is present, so don't add sdev in these cases.
++ * Two specific examples are:
++ * 1) NetApp targets: return PQ=1, PDT=0x1f
++ * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
++ * in the UFI 1.0 spec (we cannot rely on reserved bits).
++ *
++ * References:
++ * 1) SCSI SPC-3, pp. 145-146
++ * PQ=1: "A peripheral device having the specified peripheral
++ * device type is not connected to this logical unit. However, the
++ * device server is capable of supporting the specified peripheral
++ * device type on this logical unit."
++ * PDT=0x1f: "Unknown or no device type"
++ * 2) USB UFI 1.0, p. 20
++ * PDT=00h Direct-access device (floppy)
++ * PDT=1Fh none (no FDD connected to the requested logical unit)
+ */
+- if (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f) {
++ if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
++ (result[0] & 0x1f) == 0x1f) {
+ SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
+ "scsi scan: peripheral device type"
+ " of 31, no device added\n"));
+@@ -1345,7 +1354,6 @@ struct scsi_device *__scsi_add_device(st
+ if (!starget)
+ return ERR_PTR(-ENOMEM);
+
+- get_device(&starget->dev);
+ mutex_lock(&shost->scan_mutex);
+ if (scsi_host_scan_allowed(shost))
+ scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+@@ -1404,7 +1412,6 @@ static void __scsi_scan_target(struct de
+ if (!starget)
+ return;
+
+- get_device(&starget->dev);
+ if (lun != SCAN_WILD_CARD) {
+ /*
+ * Scan for a specific host/chan/id/lun.
+@@ -1586,7 +1593,8 @@ struct scsi_device *scsi_get_host_dev(st
+ if (sdev) {
+ sdev->sdev_gendev.parent = get_device(&starget->dev);
+ sdev->borken = 0;
+- }
++ } else
++ scsi_target_reap(starget);
+ put_device(&starget->dev);
+ out:
+ mutex_unlock(&shost->scan_mutex);
+diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
+index e7fe565..e1a9166 100644
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -192,6 +192,7 @@ static CLASS_DEVICE_ATTR(state, S_IRUGO
+ shost_rd_attr(unique_id, "%u\n");
+ shost_rd_attr(host_busy, "%hu\n");
+ shost_rd_attr(cmd_per_lun, "%hd\n");
++shost_rd_attr(can_queue, "%hd\n");
+ shost_rd_attr(sg_tablesize, "%hu\n");
+ shost_rd_attr(unchecked_isa_dma, "%d\n");
+ shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
+@@ -200,6 +201,7 @@ static struct class_device_attribute *sc
+ &class_device_attr_unique_id,
+ &class_device_attr_host_busy,
+ &class_device_attr_cmd_per_lun,
++ &class_device_attr_can_queue,
+ &class_device_attr_sg_tablesize,
+ &class_device_attr_unchecked_isa_dma,
+ &class_device_attr_proc_name,
+diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
+index b03aa85..38c215a 100644
+--- a/drivers/scsi/scsi_transport_fc.c
++++ b/drivers/scsi/scsi_transport_fc.c
+@@ -32,6 +32,9 @@
+ #include <scsi/scsi_transport.h>
+ #include <scsi/scsi_transport_fc.h>
+ #include <scsi/scsi_cmnd.h>
++#include <linux/netlink.h>
++#include <net/netlink.h>
++#include <scsi/scsi_netlink_fc.h>
+ #include "scsi_priv.h"
+
+ static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
+@@ -93,6 +96,29 @@ fc_enum_name_search(port_type, fc_port_t
+ #define FC_PORTTYPE_MAX_NAMELEN 50
+
+
++/* Convert fc_host_event_code values to ascii string name */
++static const struct {
++ enum fc_host_event_code value;
++ char *name;
++} fc_host_event_code_names[] = {
++ { FCH_EVT_LIP, "lip" },
++ { FCH_EVT_LINKUP, "link_up" },
++ { FCH_EVT_LINKDOWN, "link_down" },
++ { FCH_EVT_LIPRESET, "lip_reset" },
++ { FCH_EVT_RSCN, "rscn" },
++ { FCH_EVT_ADAPTER_CHANGE, "adapter_chg" },
++ { FCH_EVT_PORT_UNKNOWN, "port_unknown" },
++ { FCH_EVT_PORT_ONLINE, "port_online" },
++ { FCH_EVT_PORT_OFFLINE, "port_offline" },
++ { FCH_EVT_PORT_FABRIC, "port_fabric" },
++ { FCH_EVT_LINK_UNKNOWN, "link_unknown" },
++ { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" },
++};
++fc_enum_name_search(host_event_code, fc_host_event_code,
++ fc_host_event_code_names)
++#define FC_HOST_EVENT_CODE_MAX_NAMELEN 30
++
++
+ /* Convert fc_port_state values to ascii string name */
+ static struct {
+ enum fc_port_state value;
+@@ -216,6 +242,7 @@ fc_bitfield_name_search(remote_port_role
+
+
+ static void fc_timeout_deleted_rport(void *data);
++static void fc_timeout_fail_rport_io(void *data);
+ static void fc_scsi_scan_rport(void *data);
+
+ /*
+@@ -223,7 +250,7 @@ static void fc_scsi_scan_rport(void *dat
+ * Increase these values if you add attributes
+ */
+ #define FC_STARGET_NUM_ATTRS 3
+-#define FC_RPORT_NUM_ATTRS 9
++#define FC_RPORT_NUM_ATTRS 10
+ #define FC_HOST_NUM_ATTRS 17
+
+ struct fc_internal {
+@@ -301,8 +328,6 @@ static int fc_host_setup(struct transpor
+ fc_host->supported_classes = FC_COS_UNSPECIFIED;
+ memset(fc_host->supported_fc4s, 0,
+ sizeof(fc_host->supported_fc4s));
+- memset(fc_host->symbolic_name, 0,
+- sizeof(fc_host->symbolic_name));
+ fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
+ fc_host->maxframe_size = -1;
+ memset(fc_host->serial_number, 0,
+@@ -315,6 +340,8 @@ static int fc_host_setup(struct transpor
+ sizeof(fc_host->active_fc4s));
+ fc_host->speed = FC_PORTSPEED_UNKNOWN;
+ fc_host->fabric_name = -1;
++ memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name));
++ memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname));
+
+ fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN;
+
+@@ -377,10 +404,184 @@ MODULE_PARM_DESC(dev_loss_tmo,
+ " exceeded, the scsi target is removed. Value should be"
+ " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+
++/**
++ * Netlink Infrastructure
++ **/
++
++static atomic_t fc_event_seq;
++
++/**
++ * fc_get_event_number - Obtain the next sequential FC event number
++ *
++ * Notes:
++ * We could have inline'd this, but it would have required fc_event_seq to
++ * be exposed. For now, live with the subroutine call.
++ * Atomic used to avoid lock/unlock...
++ **/
++u32
++fc_get_event_number(void)
++{
++ return atomic_add_return(1, &fc_event_seq);
++}
++EXPORT_SYMBOL(fc_get_event_number);
++
++
++/**
++ * fc_host_post_event - called to post an even on an fc_host.
++ *
++ * @shost: host the event occurred on
++ * @event_number: fc event number obtained from get_fc_event_number()
++ * @event_code: fc_host event being posted
++ * @event_data: 32bits of data for the event being posted
++ *
++ * Notes:
++ * This routine assumes no locks are held on entry.
++ **/
++void
++fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
++ enum fc_host_event_code event_code, u32 event_data)
++{
++ struct sk_buff *skb;
++ struct nlmsghdr *nlh;
++ struct fc_nl_event *event;
++ const char *name;
++ u32 len, skblen;
++ int err;
++
++ if (!scsi_nl_sock) {
++ err = -ENOENT;
++ goto send_fail;
++ }
++
++ len = FC_NL_MSGALIGN(sizeof(*event));
++ skblen = NLMSG_SPACE(len);
++
++ skb = alloc_skb(skblen, GFP_KERNEL);
++ if (!skb) {
++ err = -ENOBUFS;
++ goto send_fail;
++ }
++
++ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
++ skblen - sizeof(*nlh), 0);
++ if (!nlh) {
++ err = -ENOBUFS;
++ goto send_fail_skb;
++ }
++ event = NLMSG_DATA(nlh);
++
++ INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
++ FC_NL_ASYNC_EVENT, len);
++ event->seconds = get_seconds();
++ event->vendor_id = 0;
++ event->host_no = shost->host_no;
++ event->event_datalen = sizeof(u32); /* bytes */
++ event->event_num = event_number;
++ event->event_code = event_code;
++ event->event_data = event_data;
++
++ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
++ GFP_KERNEL);
++ if (err && (err != -ESRCH)) /* filter no recipient errors */
++ /* nlmsg_multicast already kfree_skb'd */
++ goto send_fail;
++
++ return;
++
++send_fail_skb:
++ kfree_skb(skb);
++send_fail:
++ name = get_fc_host_event_code_name(event_code);
++ printk(KERN_WARNING
++ "%s: Dropped Event : host %d %s data 0x%08x - err %d\n",
++ __FUNCTION__, shost->host_no,
++ (name) ? name : "<unknown>", event_data, err);
++ return;
++}
++EXPORT_SYMBOL(fc_host_post_event);
++
++
++/**
++ * fc_host_post_vendor_event - called to post a vendor unique event on
++ * a fc_host
++ *
++ * @shost: host the event occurred on
++ * @event_number: fc event number obtained from get_fc_event_number()
++ * @data_len: amount, in bytes, of vendor unique data
++ * @data_buf: pointer to vendor unique data
++ *
++ * Notes:
++ * This routine assumes no locks are held on entry.
++ **/
++void
++fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
++ u32 data_len, char * data_buf, u64 vendor_id)
++{
++ struct sk_buff *skb;
++ struct nlmsghdr *nlh;
++ struct fc_nl_event *event;
++ u32 len, skblen;
++ int err;
++
++ if (!scsi_nl_sock) {
++ err = -ENOENT;
++ goto send_vendor_fail;
++ }
++
++ len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
++ skblen = NLMSG_SPACE(len);
++
++ skb = alloc_skb(skblen, GFP_KERNEL);
++ if (!skb) {
++ err = -ENOBUFS;
++ goto send_vendor_fail;
++ }
++
++ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
++ skblen - sizeof(*nlh), 0);
++ if (!nlh) {
++ err = -ENOBUFS;
++ goto send_vendor_fail_skb;
++ }
++ event = NLMSG_DATA(nlh);
++
++ INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
++ FC_NL_ASYNC_EVENT, len);
++ event->seconds = get_seconds();
++ event->vendor_id = vendor_id;
++ event->host_no = shost->host_no;
++ event->event_datalen = data_len; /* bytes */
++ event->event_num = event_number;
++ event->event_code = FCH_EVT_VENDOR_UNIQUE;
++ memcpy(&event->event_data, data_buf, data_len);
++
++ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
++ GFP_KERNEL);
++ if (err && (err != -ESRCH)) /* filter no recipient errors */
++ /* nlmsg_multicast already kfree_skb'd */
++ goto send_vendor_fail;
++
++ return;
++
++send_vendor_fail_skb:
++ kfree_skb(skb);
++send_vendor_fail:
++ printk(KERN_WARNING
++ "%s: Dropped Event : host %d vendor_unique - err %d\n",
++ __FUNCTION__, shost->host_no, err);
++ return;
++}
++EXPORT_SYMBOL(fc_host_post_vendor_event);
++
++
+
+ static __init int fc_transport_init(void)
+ {
+- int error = transport_class_register(&fc_host_class);
++ int error;
++
++ atomic_set(&fc_event_seq, 0);
++
++ error = transport_class_register(&fc_host_class);
+ if (error)
+ return error;
+ error = transport_class_register(&fc_rport_class);
+@@ -424,11 +625,14 @@ store_fc_rport_##field(struct class_devi
+ struct fc_rport *rport = transport_class_to_rport(cdev); \
+ struct Scsi_Host *shost = rport_to_shost(rport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
++ char *cp; \
+ if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
+ (rport->port_state == FC_PORTSTATE_DELETED) || \
+ (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
+ return -EBUSY; \
+- val = simple_strtoul(buf, NULL, 0); \
++ val = simple_strtoul(buf, &cp, 0); \
++ if (*cp && (*cp != '\n')) \
++ return -EINVAL; \
+ i->f->set_rport_##field(rport, val); \
+ return count; \
+ }
+@@ -510,6 +714,13 @@ static FC_CLASS_DEVICE_ATTR(rport, title
+ if (i->f->show_rport_##field) \
+ count++
+
++#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \
++{ \
++ i->private_rport_attrs[count] = class_device_attr_rport_##field; \
++ i->rport_attrs[count] = &i->private_rport_attrs[count]; \
++ count++; \
++}
++
+
+ /* The FC Transport Remote Port Attributes: */
+
+@@ -542,12 +753,14 @@ store_fc_rport_dev_loss_tmo(struct class
+ struct fc_rport *rport = transport_class_to_rport(cdev);
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
++ char *cp;
+ if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
+ (rport->port_state == FC_PORTSTATE_DELETED) ||
+ (rport->port_state == FC_PORTSTATE_NOTPRESENT))
+ return -EBUSY;
+- val = simple_strtoul(buf, NULL, 0);
+- if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
++ val = simple_strtoul(buf, &cp, 0);
++ if ((*cp && (*cp != '\n')) ||
++ (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
+ return -EINVAL;
+ i->f->set_rport_dev_loss_tmo(rport, val);
+ return count;
+@@ -597,6 +810,44 @@ static FC_CLASS_DEVICE_ATTR(rport, roles
+ fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
+ fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20);
+
++/*
++ * fast_io_fail_tmo attribute
++ */
++static ssize_t
++show_fc_rport_fast_io_fail_tmo (struct class_device *cdev, char *buf)
++{
++ struct fc_rport *rport = transport_class_to_rport(cdev);
++
++ if (rport->fast_io_fail_tmo == -1)
++ return snprintf(buf, 5, "off\n");
++ return snprintf(buf, 20, "%d\n", rport->fast_io_fail_tmo);
++}
++
++static ssize_t
++store_fc_rport_fast_io_fail_tmo(struct class_device *cdev, const char *buf,
++ size_t count)
++{
++ int val;
++ char *cp;
++ struct fc_rport *rport = transport_class_to_rport(cdev);
++
++ if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
++ (rport->port_state == FC_PORTSTATE_DELETED) ||
++ (rport->port_state == FC_PORTSTATE_NOTPRESENT))
++ return -EBUSY;
++ if (strncmp(buf, "off", 3) == 0)
++ rport->fast_io_fail_tmo = -1;
++ else {
++ val = simple_strtoul(buf, &cp, 0);
++ if ((*cp && (*cp != '\n')) ||
++ (val < 0) || (val >= rport->dev_loss_tmo))
++ return -EINVAL;
++ rport->fast_io_fail_tmo = val;
++ }
++ return count;
++}
++static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
++ show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo);
+
+
+ /*
+@@ -682,12 +933,34 @@ store_fc_host_##field(struct class_devic
+ int val; \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
++ char *cp; \
+ \
+- val = simple_strtoul(buf, NULL, 0); \
++ val = simple_strtoul(buf, &cp, 0); \
++ if (*cp && (*cp != '\n')) \
++ return -EINVAL; \
+ i->f->set_host_##field(shost, val); \
+ return count; \
+ }
+
++#define fc_host_store_str_function(field, slen) \
++static ssize_t \
++store_fc_host_##field(struct class_device *cdev, const char *buf, \
++ size_t count) \
++{ \
++ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
++ struct fc_internal *i = to_fc_internal(shost->transportt); \
++ unsigned int cnt=count; \
++ \
++ /* count may include a LF at end of string */ \
++ if (buf[cnt-1] == '\n') \
++ cnt--; \
++ if (cnt > ((slen) - 1)) \
++ return -EINVAL; \
++ memcpy(fc_host_##field(shost), buf, cnt); \
++ i->f->set_host_##field(shost); \
++ return count; \
++}
++
+ #define fc_host_rd_attr(field, format_string, sz) \
+ fc_host_show_function(field, format_string, sz, ) \
+ static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO, \
+@@ -815,7 +1088,6 @@ fc_private_host_rd_attr_cast(node_name,
+ fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+ fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
+ unsigned long long);
+-fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
+ fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
+ fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
+
+@@ -858,6 +1130,13 @@ fc_host_rd_attr(port_id, "0x%06x\n", 20)
+ fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN);
+ fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
+ fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
++fc_host_rd_attr(symbolic_name, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1);
++
++fc_private_host_show_function(system_hostname, "%s\n",
++ FC_SYMBOLIC_NAME_SIZE + 1, )
++fc_host_store_str_function(system_hostname, FC_SYMBOLIC_NAME_SIZE)
++static FC_CLASS_DEVICE_ATTR(host, system_hostname, S_IRUGO | S_IWUSR,
++ show_fc_host_system_hostname, store_fc_host_system_hostname);
+
+
+ /* Private Host Attributes */
+@@ -1223,7 +1502,6 @@ fc_attach_transport(struct fc_function_t
+ SETUP_HOST_ATTRIBUTE_RD(permanent_port_name);
+ SETUP_HOST_ATTRIBUTE_RD(supported_classes);
+ SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
+- SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
+ SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
+ SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
+ SETUP_HOST_ATTRIBUTE_RD(serial_number);
+@@ -1234,6 +1512,8 @@ fc_attach_transport(struct fc_function_t
+ SETUP_HOST_ATTRIBUTE_RD(active_fc4s);
+ SETUP_HOST_ATTRIBUTE_RD(speed);
+ SETUP_HOST_ATTRIBUTE_RD(fabric_name);
++ SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
++ SETUP_HOST_ATTRIBUTE_RW(system_hostname);
+
+ /* Transport-managed attributes */
+ SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
+@@ -1257,6 +1537,8 @@ fc_attach_transport(struct fc_function_t
+ SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
+ SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
+ SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
++ if (ft->terminate_rport_io)
++ SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo);
+
+ BUG_ON(count > FC_RPORT_NUM_ATTRS);
+
+@@ -1328,7 +1610,7 @@ fc_flush_work(struct Scsi_Host *shost)
+ * @delay: jiffies to delay the work queuing
+ *
+ * Return value:
+- * 0 on success / != 0 for error
++ * 1 on success / 0 already queued / < 0 for error
+ **/
+ static int
+ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
+@@ -1343,6 +1625,9 @@ fc_queue_devloss_work(struct Scsi_Host *
+ return -EINVAL;
+ }
+
++ if (delay == 0)
++ return queue_work(fc_host_devloss_work_q(shost), work);
++
+ return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay);
+ }
+
+@@ -1435,10 +1720,23 @@ fc_starget_delete(void *data)
+ struct fc_rport *rport = (struct fc_rport *)data;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ unsigned long flags;
++ struct fc_internal *i = to_fc_internal(shost->transportt);
++
++ /*
++ * Involve the LLDD if possible. All io on the rport is to
++ * be terminated, either as part of the dev_loss_tmo callback
++ * processing, or via the terminate_rport_io function.
++ */
++ if (i->f->dev_loss_tmo_callbk)
++ i->f->dev_loss_tmo_callbk(rport);
++ else if (i->f->terminate_rport_io)
++ i->f->terminate_rport_io(rport);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
++ if (!cancel_delayed_work(&rport->fail_io_work))
++ fc_flush_devloss(shost);
+ if (!cancel_delayed_work(&rport->dev_loss_work))
+ fc_flush_devloss(shost);
+ spin_lock_irqsave(shost->host_lock, flags);
+@@ -1461,10 +1759,7 @@ fc_rport_final_delete(void *data)
+ struct fc_rport *rport = (struct fc_rport *)data;
+ struct device *dev = &rport->dev;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+-
+- /* Delete SCSI target and sdevs */
+- if (rport->scsi_target_id != -1)
+- fc_starget_delete(data);
++ struct fc_internal *i = to_fc_internal(shost->transportt);
+
+ /*
+ * if a scan is pending, flush the SCSI Host work_q so that
+@@ -1473,6 +1768,14 @@ fc_rport_final_delete(void *data)
+ if (rport->flags & FC_RPORT_SCAN_PENDING)
+ scsi_flush_work(shost);
+
++ /* Delete SCSI target and sdevs */
++ if (rport->scsi_target_id != -1)
++ fc_starget_delete(data);
++ else if (i->f->dev_loss_tmo_callbk)
++ i->f->dev_loss_tmo_callbk(rport);
++ else if (i->f->terminate_rport_io)
++ i->f->terminate_rport_io(rport);
++
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+@@ -1524,8 +1827,10 @@ fc_rport_create(struct Scsi_Host *shost,
+ if (fci->f->dd_fcrport_size)
+ rport->dd_data = &rport[1];
+ rport->channel = channel;
++ rport->fast_io_fail_tmo = -1;
+
+ INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport);
++ INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport);
+ INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
+ INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport);
+ INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport);
+@@ -1689,11 +1994,13 @@ fc_remote_port_add(struct Scsi_Host *sho
+ /* restart the target */
+
+ /*
+- * Stop the target timer first. Take no action
++ * Stop the target timers first. Take no action
+ * on the del_timer failure as the state
+ * machine state change will validate the
+ * transaction.
+ */
++ if (!cancel_delayed_work(&rport->fail_io_work))
++ fc_flush_devloss(shost);
+ if (!cancel_delayed_work(work))
+ fc_flush_devloss(shost);
+
+@@ -1837,6 +2144,7 @@ void
+ fc_remote_port_delete(struct fc_rport *rport)
+ {
+ struct Scsi_Host *shost = rport_to_shost(rport);
++ struct fc_internal *i = to_fc_internal(shost->transportt);
+ int timeout = rport->dev_loss_tmo;
+ unsigned long flags;
+
+@@ -1867,6 +2175,12 @@ fc_remote_port_delete(struct fc_rport *
+
+ scsi_target_block(&rport->dev);
+
++ /* see if we need to kill io faster than waiting for device loss */
++ if ((rport->fast_io_fail_tmo != -1) &&
++ (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io))
++ fc_queue_devloss_work(shost, &rport->fail_io_work,
++ rport->fast_io_fail_tmo * HZ);
++
+ /* cap the length the devices can be blocked until they are deleted */
+ fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ);
+ }
+@@ -1926,6 +2240,8 @@ fc_remote_port_rolechg(struct fc_rport
+ * machine state change will validate the
+ * transaction.
+ */
++ if (!cancel_delayed_work(&rport->fail_io_work))
++ fc_flush_devloss(shost);
+ if (!cancel_delayed_work(&rport->dev_loss_work))
+ fc_flush_devloss(shost);
+
+@@ -2047,6 +2363,28 @@ fc_timeout_deleted_rport(void *data)
+ }
+
+ /**
++ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
++ * disconnected SCSI target.
++ *
++ * @data: rport to terminate io on.
++ *
++ * Notes: Only requests the failure of the io, not that all are flushed
++ * prior to returning.
++ **/
++static void
++fc_timeout_fail_rport_io(void *data)
++{
++ struct fc_rport *rport = (struct fc_rport *)data;
++ struct Scsi_Host *shost = rport_to_shost(rport);
++ struct fc_internal *i = to_fc_internal(shost->transportt);
++
++ if (rport->port_state != FC_PORTSTATE_BLOCKED)
++ return;
++
++ i->f->terminate_rport_io(rport);
++}
++
++/**
+ * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
+ *
+ * @data: remote port to be scanned.
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 2ecd141..2d3baa9 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -21,7 +21,6 @@
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ #include <linux/module.h>
+-#include <linux/mempool.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+ #include <scsi/scsi.h>
+@@ -34,7 +33,7 @@
+ #define ISCSI_SESSION_ATTRS 11
+ #define ISCSI_CONN_ATTRS 11
+ #define ISCSI_HOST_ATTRS 0
+-#define ISCSI_TRANSPORT_VERSION "1.1-646"
++#define ISCSI_TRANSPORT_VERSION "2.0-685"
+
+ struct iscsi_internal {
+ int daemon_pid;
+@@ -149,30 +148,6 @@ static DECLARE_TRANSPORT_CLASS(iscsi_con
+ static struct sock *nls;
+ static DEFINE_MUTEX(rx_queue_mutex);
+
+-struct mempool_zone {
+- mempool_t *pool;
+- atomic_t allocated;
+- int size;
+- int hiwat;
+- struct list_head freequeue;
+- spinlock_t freelock;
+-};
+-
+-static struct mempool_zone *z_reply;
+-
+-/*
+- * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time
+- * Z_HIWAT_* - zone's high watermark when if_error bit will be set to -ENOMEM
+- * so daemon will notice OOM on NETLINK tranposrt level and will
+- * be able to predict or change operational behavior
+- */
+-#define Z_MAX_REPLY 8
+-#define Z_HIWAT_REPLY 6
+-#define Z_MAX_PDU 8
+-#define Z_HIWAT_PDU 6
+-#define Z_MAX_ERROR 16
+-#define Z_HIWAT_ERROR 12
+-
+ static LIST_HEAD(sesslist);
+ static DEFINE_SPINLOCK(sesslock);
+ static LIST_HEAD(connlist);
+@@ -414,59 +389,11 @@ int iscsi_destroy_session(struct iscsi_c
+ }
+ EXPORT_SYMBOL_GPL(iscsi_destroy_session);
+
+-static void mempool_zone_destroy(struct mempool_zone *zp)
+-{
+- mempool_destroy(zp->pool);
+- kfree(zp);
+-}
+-
+-static void*
+-mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
+-{
+- struct mempool_zone *zone = pool_data;
+-
+- return alloc_skb(zone->size, gfp_mask);
+-}
+-
+-static void
+-mempool_zone_free_skb(void *element, void *pool_data)
+-{
+- kfree_skb(element);
+-}
+-
+-static struct mempool_zone *
+-mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
+-{
+- struct mempool_zone *zp;
+-
+- zp = kzalloc(sizeof(*zp), GFP_KERNEL);
+- if (!zp)
+- return NULL;
+-
+- zp->size = size;
+- zp->hiwat = hiwat;
+- INIT_LIST_HEAD(&zp->freequeue);
+- spin_lock_init(&zp->freelock);
+- atomic_set(&zp->allocated, 0);
+-
+- zp->pool = mempool_create(max, mempool_zone_alloc_skb,
+- mempool_zone_free_skb, zp);
+- if (!zp->pool) {
+- kfree(zp);
+- return NULL;
+- }
+-
+- return zp;
+-}
+-
+ static void iscsi_conn_release(struct device *dev)
+ {
+ struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+ struct device *parent = conn->dev.parent;
+
+- mempool_zone_destroy(conn->z_pdu);
+- mempool_zone_destroy(conn->z_error);
+-
+ kfree(conn);
+ put_device(parent);
+ }
+@@ -476,31 +403,6 @@ static int iscsi_is_conn_dev(const struc
+ return dev->release == iscsi_conn_release;
+ }
+
+-static int iscsi_create_event_pools(struct iscsi_cls_conn *conn)
+-{
+- conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
+- NLMSG_SPACE(sizeof(struct iscsi_uevent) +
+- sizeof(struct iscsi_hdr) +
+- DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
+- Z_HIWAT_PDU);
+- if (!conn->z_pdu) {
+- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+- "pdu zone for new conn\n");
+- return -ENOMEM;
+- }
+-
+- conn->z_error = mempool_zone_init(Z_MAX_ERROR,
+- NLMSG_SPACE(sizeof(struct iscsi_uevent)),
+- Z_HIWAT_ERROR);
+- if (!conn->z_error) {
+- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+- "error zone for new conn\n");
+- mempool_zone_destroy(conn->z_pdu);
+- return -ENOMEM;
+- }
+- return 0;
+-}
+-
+ /**
+ * iscsi_create_conn - create iscsi class connection
+ * @session: iscsi cls session
+@@ -533,12 +435,9 @@ iscsi_create_conn(struct iscsi_cls_sessi
+ conn->transport = transport;
+ conn->cid = cid;
+
+- if (iscsi_create_event_pools(conn))
+- goto free_conn;
+-
+ /* this is released in the dev's release function */
+ if (!get_device(&session->dev))
+- goto free_conn_pools;
++ goto free_conn;
+
+ snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
+ session->sid, cid);
+@@ -555,8 +454,6 @@ iscsi_create_conn(struct iscsi_cls_sessi
+
+ release_parent_ref:
+ put_device(&session->dev);
+-free_conn_pools:
+-
+ free_conn:
+ kfree(conn);
+ return NULL;
+@@ -599,81 +496,31 @@ iscsi_if_transport_lookup(struct iscsi_t
+ return NULL;
+ }
+
+-static inline struct list_head *skb_to_lh(struct sk_buff *skb)
+-{
+- return (struct list_head *)&skb->cb;
+-}
+-
+-static void
+-mempool_zone_complete(struct mempool_zone *zone)
+-{
+- unsigned long flags;
+- struct list_head *lh, *n;
+-
+- spin_lock_irqsave(&zone->freelock, flags);
+- list_for_each_safe(lh, n, &zone->freequeue) {
+- struct sk_buff *skb = (struct sk_buff *)((char *)lh -
+- offsetof(struct sk_buff, cb));
+- if (!skb_shared(skb)) {
+- list_del(skb_to_lh(skb));
+- mempool_free(skb, zone->pool);
+- atomic_dec(&zone->allocated);
+- }
+- }
+- spin_unlock_irqrestore(&zone->freelock, flags);
+-}
+-
+-static struct sk_buff*
+-mempool_zone_get_skb(struct mempool_zone *zone)
+-{
+- struct sk_buff *skb;
+-
+- skb = mempool_alloc(zone->pool, GFP_ATOMIC);
+- if (skb)
+- atomic_inc(&zone->allocated);
+- return skb;
+-}
+-
+ static int
+-iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb, gfp_t gfp)
++iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp)
+ {
+- unsigned long flags;
+ int rc;
+
+- skb_get(skb);
+ rc = netlink_broadcast(nls, skb, 0, 1, gfp);
+ if (rc < 0) {
+- mempool_free(skb, zone->pool);
+ printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc);
+ return rc;
+ }
+
+- spin_lock_irqsave(&zone->freelock, flags);
+- INIT_LIST_HEAD(skb_to_lh(skb));
+- list_add(skb_to_lh(skb), &zone->freequeue);
+- spin_unlock_irqrestore(&zone->freelock, flags);
+ return 0;
+ }
+
+ static int
+-iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid)
++iscsi_unicast_skb(struct sk_buff *skb, int pid)
+ {
+- unsigned long flags;
+ int rc;
+
+- skb_get(skb);
+ rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);
+ if (rc < 0) {
+- mempool_free(skb, zone->pool);
+ printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc);
+ return rc;
+ }
+
+- spin_lock_irqsave(&zone->freelock, flags);
+- INIT_LIST_HEAD(skb_to_lh(skb));
+- list_add(skb_to_lh(skb), &zone->freequeue);
+- spin_unlock_irqrestore(&zone->freelock, flags);
+-
+ return 0;
+ }
+
+@@ -692,9 +539,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn
+ if (!priv)
+ return -EINVAL;
+
+- mempool_zone_complete(conn->z_pdu);
+-
+- skb = mempool_zone_get_skb(conn->z_pdu);
++ skb = alloc_skb(len, GFP_ATOMIC);
+ if (!skb) {
+ iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED);
+ dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
+@@ -707,15 +552,13 @@ int iscsi_recv_pdu(struct iscsi_cls_conn
+ memset(ev, 0, sizeof(*ev));
+ ev->transport_handle = iscsi_handle(conn->transport);
+ ev->type = ISCSI_KEVENT_RECV_PDU;
+- if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
+- ev->iferror = -ENOMEM;
+ ev->r.recv_req.cid = conn->cid;
+ ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
+ pdu = (char*)ev + sizeof(*ev);
+ memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
+ memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
+
+- return iscsi_unicast_skb(conn->z_pdu, skb, priv->daemon_pid);
++ return iscsi_unicast_skb(skb, priv->daemon_pid);
+ }
+ EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
+
+@@ -731,9 +574,7 @@ void iscsi_conn_error(struct iscsi_cls_c
+ if (!priv)
+ return;
+
+- mempool_zone_complete(conn->z_error);
+-
+- skb = mempool_zone_get_skb(conn->z_error);
++ skb = alloc_skb(len, GFP_ATOMIC);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
+ "conn error (%d)\n", error);
+@@ -744,13 +585,11 @@ void iscsi_conn_error(struct iscsi_cls_c
+ ev = NLMSG_DATA(nlh);
+ ev->transport_handle = iscsi_handle(conn->transport);
+ ev->type = ISCSI_KEVENT_CONN_ERROR;
+- if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat)
+- ev->iferror = -ENOMEM;
+ ev->r.connerror.error = error;
+ ev->r.connerror.cid = conn->cid;
+ ev->r.connerror.sid = iscsi_conn_get_sid(conn);
+
+- iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC);
++ iscsi_broadcast_skb(skb, GFP_ATOMIC);
+
+ dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
+ error);
+@@ -767,9 +606,7 @@ iscsi_if_send_reply(int pid, int seq, in
+ int flags = multi ? NLM_F_MULTI : 0;
+ int t = done ? NLMSG_DONE : type;
+
+- mempool_zone_complete(z_reply);
+-
+- skb = mempool_zone_get_skb(z_reply);
++ skb = alloc_skb(len, GFP_ATOMIC);
+ /*
+ * FIXME:
+ * user is supposed to react on iferror == -ENOMEM;
+@@ -780,7 +617,7 @@ iscsi_if_send_reply(int pid, int seq, in
+ nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
+ nlh->nlmsg_flags = flags;
+ memcpy(NLMSG_DATA(nlh), payload, size);
+- return iscsi_unicast_skb(z_reply, skb, pid);
++ return iscsi_unicast_skb(skb, pid);
+ }
+
+ static int
+@@ -810,9 +647,7 @@ iscsi_if_get_stats(struct iscsi_transpor
+ do {
+ int actual_size;
+
+- mempool_zone_complete(conn->z_pdu);
+-
+- skbstat = mempool_zone_get_skb(conn->z_pdu);
++ skbstat = alloc_skb(len, GFP_ATOMIC);
+ if (!skbstat) {
+ dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
+ "deliver stats: OOM\n");
+@@ -825,8 +660,6 @@ iscsi_if_get_stats(struct iscsi_transpor
+ memset(evstat, 0, sizeof(*evstat));
+ evstat->transport_handle = iscsi_handle(conn->transport);
+ evstat->type = nlh->nlmsg_type;
+- if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
+- evstat->iferror = -ENOMEM;
+ evstat->u.get_stats.cid =
+ ev->u.get_stats.cid;
+ evstat->u.get_stats.sid =
+@@ -845,7 +678,7 @@ iscsi_if_get_stats(struct iscsi_transpor
+ skb_trim(skbstat, NLMSG_ALIGN(actual_size));
+ nlhstat->nlmsg_len = actual_size;
+
+- err = iscsi_unicast_skb(conn->z_pdu, skbstat, priv->daemon_pid);
++ err = iscsi_unicast_skb(skbstat, priv->daemon_pid);
+ } while (err < 0 && err != -ECONNREFUSED);
+
+ return err;
+@@ -876,9 +709,7 @@ int iscsi_if_destroy_session_done(struct
+ session = iscsi_dev_to_session(conn->dev.parent);
+ shost = iscsi_session_to_shost(session);
+
+- mempool_zone_complete(conn->z_pdu);
+-
+- skb = mempool_zone_get_skb(conn->z_pdu);
++ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event\n");
+@@ -896,7 +727,7 @@ int iscsi_if_destroy_session_done(struct
+ * this will occur if the daemon is not up, so we just warn
+ * the user and when the daemon is restarted it will handle it
+ */
+- rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL);
++ rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
+ if (rc < 0)
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session destruction event. Check iscsi daemon\n");
+@@ -939,9 +770,7 @@ int iscsi_if_create_session_done(struct
+ session = iscsi_dev_to_session(conn->dev.parent);
+ shost = iscsi_session_to_shost(session);
+
+- mempool_zone_complete(conn->z_pdu);
+-
+- skb = mempool_zone_get_skb(conn->z_pdu);
++ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event\n");
+@@ -959,7 +788,7 @@ int iscsi_if_create_session_done(struct
+ * this will occur if the daemon is not up, so we just warn
+ * the user and when the daemon is restarted it will handle it
+ */
+- rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL);
++ rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
+ if (rc < 0)
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event. Check iscsi daemon\n");
+@@ -1278,9 +1107,6 @@ iscsi_if_rx(struct sock *sk, int len)
+ err = iscsi_if_send_reply(
+ NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+- if (atomic_read(&z_reply->allocated) >=
+- z_reply->hiwat)
+- ev->iferror = -ENOMEM;
+ } while (err < 0 && err != -ECONNREFUSED);
+ skb_pull(skb, rlen);
+ }
+@@ -1584,32 +1410,6 @@ int iscsi_unregister_transport(struct is
+ }
+ EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
+
+-static int
+-iscsi_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr)
+-{
+- struct netlink_notify *n = ptr;
+-
+- if (event == NETLINK_URELEASE &&
+- n->protocol == NETLINK_ISCSI && n->pid) {
+- struct iscsi_cls_conn *conn;
+- unsigned long flags;
+-
+- mempool_zone_complete(z_reply);
+- spin_lock_irqsave(&connlock, flags);
+- list_for_each_entry(conn, &connlist, conn_list) {
+- mempool_zone_complete(conn->z_error);
+- mempool_zone_complete(conn->z_pdu);
+- }
+- spin_unlock_irqrestore(&connlock, flags);
+- }
+-
+- return NOTIFY_DONE;
+-}
+-
+-static struct notifier_block iscsi_nl_notifier = {
+- .notifier_call = iscsi_rcv_nl_event,
+-};
+-
+ static __init int iscsi_transport_init(void)
+ {
+ int err;
+@@ -1633,25 +1433,15 @@ static __init int iscsi_transport_init(v
+ if (err)
+ goto unregister_conn_class;
+
+- err = netlink_register_notifier(&iscsi_nl_notifier);
+- if (err)
+- goto unregister_session_class;
+-
+ nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
+ THIS_MODULE);
+ if (!nls) {
+ err = -ENOBUFS;
+- goto unregister_notifier;
++ goto unregister_session_class;
+ }
+
+- z_reply = mempool_zone_init(Z_MAX_REPLY,
+- NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY);
+- if (z_reply)
+- return 0;
++ return 0;
+
+- sock_release(nls->sk_socket);
+-unregister_notifier:
+- netlink_unregister_notifier(&iscsi_nl_notifier);
+ unregister_session_class:
+ transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1665,9 +1455,7 @@ unregister_transport_class:
+
+ static void __exit iscsi_transport_exit(void)
+ {
+- mempool_zone_destroy(z_reply);
+ sock_release(nls->sk_socket);
+- netlink_unregister_notifier(&iscsi_nl_notifier);
+ transport_class_unregister(&iscsi_connection_class);
+ transport_class_unregister(&iscsi_session_class);
+ transport_class_unregister(&iscsi_host_class);
+diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
+index 5a625c3..b5b0c2c 100644
+--- a/drivers/scsi/scsi_transport_sas.c
++++ b/drivers/scsi/scsi_transport_sas.c
+@@ -77,6 +77,24 @@ get_sas_##title##_names(u32 table_key, c
+ return len; \
+ }
+
++#define sas_bitfield_name_set(title, table) \
++static ssize_t \
++set_sas_##title##_names(u32 *table_key, const char *buf) \
++{ \
++ ssize_t len = 0; \
++ int i; \
++ \
++ for (i = 0; i < ARRAY_SIZE(table); i++) { \
++ len = strlen(table[i].name); \
++ if (strncmp(buf, table[i].name, len) == 0 && \
++ (buf[len] == '\n' || buf[len] == '\0')) { \
++ *table_key = table[i].value; \
++ return 0; \
++ } \
++ } \
++ return -EINVAL; \
++}
++
+ #define sas_bitfield_name_search(title, table) \
+ static ssize_t \
+ get_sas_##title##_names(u32 table_key, char *buf) \
+@@ -131,7 +149,7 @@ static struct {
+ { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
+ };
+ sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
+-
++sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
+
+ /*
+ * SAS host attributes
+@@ -253,10 +271,39 @@ show_sas_phy_##field(struct class_device
+ return get_sas_linkspeed_names(phy->field, buf); \
+ }
+
++/* Fudge to tell if we're minimum or maximum */
++#define sas_phy_store_linkspeed(field) \
++static ssize_t \
++store_sas_phy_##field(struct class_device *cdev, const char *buf, \
++ size_t count) \
++{ \
++ struct sas_phy *phy = transport_class_to_phy(cdev); \
++ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
++ struct sas_internal *i = to_sas_internal(shost->transportt); \
++ u32 value; \
++ struct sas_phy_linkrates rates = {0}; \
++ int error; \
++ \
++ error = set_sas_linkspeed_names(&value, buf); \
++ if (error) \
++ return error; \
++ rates.field = value; \
++ error = i->f->set_phy_speed(phy, &rates); \
++ \
++ return error ? error : count; \
++}
++
++#define sas_phy_linkspeed_rw_attr(field) \
++ sas_phy_show_linkspeed(field) \
++ sas_phy_store_linkspeed(field) \
++static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \
++ store_sas_phy_##field)
++
+ #define sas_phy_linkspeed_attr(field) \
+ sas_phy_show_linkspeed(field) \
+ static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
+
++
+ #define sas_phy_show_linkerror(field) \
+ static ssize_t \
+ show_sas_phy_##field(struct class_device *cdev, char *buf) \
+@@ -266,9 +313,6 @@ show_sas_phy_##field(struct class_device
+ struct sas_internal *i = to_sas_internal(shost->transportt); \
+ int error; \
+ \
+- if (!phy->local_attached) \
+- return -EINVAL; \
+- \
+ error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \
+ if (error) \
+ return error; \
+@@ -299,9 +343,6 @@ static ssize_t do_sas_phy_reset(struct c
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+ int error;
+
+- if (!phy->local_attached)
+- return -EINVAL;
+-
+ error = i->f->phy_reset(phy, hard_reset);
+ if (error)
+ return error;
+@@ -332,9 +373,9 @@ sas_phy_simple_attr(identify.phy_identif
+ //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
+ sas_phy_linkspeed_attr(negotiated_linkrate);
+ sas_phy_linkspeed_attr(minimum_linkrate_hw);
+-sas_phy_linkspeed_attr(minimum_linkrate);
++sas_phy_linkspeed_rw_attr(minimum_linkrate);
+ sas_phy_linkspeed_attr(maximum_linkrate_hw);
+-sas_phy_linkspeed_attr(maximum_linkrate);
++sas_phy_linkspeed_rw_attr(maximum_linkrate);
+ sas_phy_linkerror_attr(invalid_dword_count);
+ sas_phy_linkerror_attr(running_disparity_error_count);
+ sas_phy_linkerror_attr(loss_of_dword_sync_count);
+@@ -849,7 +890,7 @@ show_sas_rphy_enclosure_identifier(struc
+ * Only devices behind an expander are supported, because the
+ * enclosure identifier is a SMP feature.
+ */
+- if (phy->local_attached)
++ if (scsi_is_sas_phy_local(phy))
+ return -EINVAL;
+
+ error = i->f->get_enclosure_identifier(rphy, &identifier);
+@@ -870,7 +911,7 @@ show_sas_rphy_bay_identifier(struct clas
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+ int val;
+
+- if (phy->local_attached)
++ if (scsi_is_sas_phy_local(phy))
+ return -EINVAL;
+
+ val = i->f->get_bay_identifier(rphy);
+@@ -1316,13 +1357,23 @@ static int sas_user_scan(struct Scsi_Hos
+ * Setup / Teardown code
+ */
+
+-#define SETUP_TEMPLATE(attrb, field, perm, test) \
++#define SETUP_TEMPLATE(attrb, field, perm, test) \
+ i->private_##attrb[count] = class_device_attr_##field; \
+ i->private_##attrb[count].attr.mode = perm; \
+ i->attrb[count] = &i->private_##attrb[count]; \
+ if (test) \
+ count++
+
++#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \
++ i->private_##attrb[count] = class_device_attr_##field; \
++ i->private_##attrb[count].attr.mode = perm; \
++ if (ro_test) { \
++ i->private_##attrb[count].attr.mode = ro_perm; \
++ i->private_##attrb[count].store = NULL; \
++ } \
++ i->attrb[count] = &i->private_##attrb[count]; \
++ if (test) \
++ count++
+
+ #define SETUP_RPORT_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
+@@ -1333,6 +1384,10 @@ static int sas_user_scan(struct Scsi_Hos
+ #define SETUP_PHY_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
+
++#define SETUP_PHY_ATTRIBUTE_RW(field) \
++ SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
++ !i->f->set_phy_speed, S_IRUGO)
++
+ #define SETUP_PORT_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+
+@@ -1413,9 +1468,9 @@ sas_attach_transport(struct sas_function
+ //SETUP_PHY_ATTRIBUTE(port_identifier);
+ SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
+ SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
+- SETUP_PHY_ATTRIBUTE(minimum_linkrate);
++ SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
+ SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
+- SETUP_PHY_ATTRIBUTE(maximum_linkrate);
++ SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
+
+ SETUP_PHY_ATTRIBUTE(invalid_dword_count);
+ SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
+diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
+index 29a9a53..9f070f0 100644
+--- a/drivers/scsi/scsi_transport_spi.c
++++ b/drivers/scsi/scsi_transport_spi.c
+@@ -47,6 +47,7 @@
+
+ /* Private data accessors (keep these out of the header file) */
+ #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
++#define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
+ #define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
+
+ struct spi_internal {
+@@ -240,6 +241,7 @@ static int spi_setup_transport_attrs(str
+ spi_pcomp_en(starget) = 0;
+ spi_hold_mcs(starget) = 0;
+ spi_dv_pending(starget) = 0;
++ spi_dv_in_progress(starget) = 0;
+ spi_initial_dv(starget) = 0;
+ mutex_init(&spi_dv_mutex(starget));
+
+@@ -830,28 +832,37 @@ spi_dv_device_internal(struct scsi_devic
+ DV_SET(period, spi_min_period(starget));
+ /* try QAS requests; this should be harmless to set if the
+ * target supports it */
+- if (scsi_device_qas(sdev))
++ if (scsi_device_qas(sdev)) {
+ DV_SET(qas, 1);
+- /* Also try IU transfers */
+- if (scsi_device_ius(sdev))
++ } else {
++ DV_SET(qas, 0);
++ }
++
++ if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
++ /* This u320 (or u640). Set IU transfers */
+ DV_SET(iu, 1);
+- if (spi_min_period(starget) < 9) {
+- /* This u320 (or u640). Ignore the coupled parameters
+- * like DT and IU, but set the optional ones */
++ /* Then set the optional parameters */
+ DV_SET(rd_strm, 1);
+ DV_SET(wr_flow, 1);
+ DV_SET(rti, 1);
+ if (spi_min_period(starget) == 8)
+ DV_SET(pcomp_en, 1);
++ } else {
++ DV_SET(iu, 0);
+ }
++
+ /* now that we've done all this, actually check the bus
+ * signal type (if known). Some devices are stupid on
+ * a SE bus and still claim they can try LVD only settings */
+ if (i->f->get_signalling)
+ i->f->get_signalling(shost);
+ if (spi_signalling(shost) == SPI_SIGNAL_SE ||
+- spi_signalling(shost) == SPI_SIGNAL_HVD)
++ spi_signalling(shost) == SPI_SIGNAL_HVD ||
++ !scsi_device_dt(sdev)) {
+ DV_SET(dt, 0);
++ } else {
++ DV_SET(dt, 1);
++ }
+ /* Do the read only INQUIRY tests */
+ spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
+ spi_dv_device_compare_inquiry);
+@@ -907,6 +918,10 @@ spi_dv_device(struct scsi_device *sdev)
+ if (unlikely(scsi_device_get(sdev)))
+ return;
+
++ if (unlikely(spi_dv_in_progress(starget)))
++ return;
++ spi_dv_in_progress(starget) = 1;
++
+ buffer = kzalloc(len, GFP_KERNEL);
+
+ if (unlikely(!buffer))
+@@ -938,6 +953,7 @@ spi_dv_device(struct scsi_device *sdev)
+ out_free:
+ kfree(buffer);
+ out_put:
++ spi_dv_in_progress(starget) = 0;
+ scsi_device_put(sdev);
+ }
+ EXPORT_SYMBOL(spi_dv_device);
+diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
+index 98bd3aa..84ff203 100644
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -443,8 +443,7 @@ static int sd_init_command(struct scsi_c
+ SCpnt->cmnd[0] = READ_6;
+ SCpnt->sc_data_direction = DMA_FROM_DEVICE;
+ } else {
+- printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags);
+-/* overkill panic("Unknown sd command %lx\n", rq->flags); */
++ printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags);
+ return 0;
+ }
+
+@@ -840,7 +839,7 @@ static int sd_issue_flush(struct device
+ static void sd_prepare_flush(request_queue_t *q, struct request *rq)
+ {
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+- rq->flags |= REQ_BLOCK_PC;
++ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->timeout = SD_TIMEOUT;
+ rq->cmd[0] = SYNCHRONIZE_CACHE;
+ rq->cmd_len = 10;
+@@ -1215,7 +1214,7 @@ repeat:
+ /* Either no media are present but the drive didn't tell us,
+ or they are present but the read capacity command fails */
+ /* sdkp->media_present = 0; -- not always correct */
+- sdkp->capacity = 0x200000; /* 1 GB - random */
++ sdkp->capacity = 0; /* unknown mapped to zero - as usual */
+
+ return;
+ } else if (the_result && longrc) {
+@@ -1795,7 +1794,7 @@ static void sd_shutdown(struct device *d
+ **/
+ static int __init init_sd(void)
+ {
+- int majors = 0, i;
++ int majors = 0, i, err;
+
+ SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
+
+@@ -1806,9 +1805,22 @@ static int __init init_sd(void)
+ if (!majors)
+ return -ENODEV;
+
+- class_register(&sd_disk_class);
++ err = class_register(&sd_disk_class);
++ if (err)
++ goto err_out;
+
+- return scsi_register_driver(&sd_template.gendrv);
++ err = scsi_register_driver(&sd_template.gendrv);
++ if (err)
++ goto err_out_class;
++
++ return 0;
++
++err_out_class:
++ class_unregister(&sd_disk_class);
++err_out:
++ for (i = 0; i < SD_MAJORS; i++)
++ unregister_blkdev(sd_major(i), "sd");
++ return err;
+ }
+
+ /**
+@@ -1823,10 +1835,10 @@ static void __exit exit_sd(void)
+ SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
+
+ scsi_unregister_driver(&sd_template.gendrv);
++ class_unregister(&sd_disk_class);
++
+ for (i = 0; i < SD_MAJORS; i++)
+ unregister_blkdev(sd_major(i), "sd");
+-
+- class_unregister(&sd_disk_class);
+ }
+
+ module_init(init_sd);
+diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
+index 2679ea8..5ffec27 100644
+--- a/drivers/scsi/seagate.c
++++ b/drivers/scsi/seagate.c
+@@ -94,21 +94,21 @@
+ #include <linux/string.h>
+ #include <linux/proc_fs.h>
+ #include <linux/init.h>
+-#include <linux/delay.h>
+ #include <linux/blkdev.h>
+ #include <linux/stat.h>
+ #include <linux/delay.h>
++#include <linux/io.h>
+
+-#include <asm/io.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+
+-#include "scsi.h"
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi.h>
++
+ #include <scsi/scsi_dbg.h>
+ #include <scsi/scsi_host.h>
+-#include "seagate.h"
+
+-#include <scsi/scsi_ioctl.h>
+
+ #ifdef DEBUG
+ #define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
+@@ -320,8 +320,9 @@ static Signature __initdata signatures[]
+ */
+
+ static int hostno = -1;
+-static void seagate_reconnect_intr (int, void *, struct pt_regs *);
+-static irqreturn_t do_seagate_reconnect_intr (int, void *, struct pt_regs *);
++static void seagate_reconnect_intr (int, void *);
++static irqreturn_t do_seagate_reconnect_intr (int, void *);
++static int seagate_st0x_bus_reset(struct scsi_cmnd *);
+
+ #ifdef FAST
+ static int fast = 1;
+@@ -585,8 +586,8 @@ static int linked_connected = 0;
+ static unsigned char linked_target, linked_lun;
+ #endif
+
+-static void (*done_fn) (Scsi_Cmnd *) = NULL;
+-static Scsi_Cmnd *SCint = NULL;
++static void (*done_fn) (struct scsi_cmnd *) = NULL;
++static struct scsi_cmnd *SCint = NULL;
+
+ /*
+ * These control whether or not disconnect / reconnect will be attempted,
+@@ -618,22 +619,21 @@ static int should_reconnect = 0;
+ * asserting SEL.
+ */
+
+-static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+
+ spin_lock_irqsave (dev->host_lock, flags);
+- seagate_reconnect_intr (irq, dev_id, regs);
++ seagate_reconnect_intr (irq, dev_id);
+ spin_unlock_irqrestore (dev->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+-static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
++static void seagate_reconnect_intr (int irq, void *dev_id)
+ {
+ int temp;
+- Scsi_Cmnd *SCtmp;
++ struct scsi_cmnd *SCtmp;
+
+ DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
+
+@@ -675,10 +675,11 @@ static void seagate_reconnect_intr (int
+
+ static int recursion_depth = 0;
+
+-static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
++static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
++ void (*done) (struct scsi_cmnd *))
+ {
+ int result, reconnect;
+- Scsi_Cmnd *SCtmp;
++ struct scsi_cmnd *SCtmp;
+
+ DANY ("seagate: que_command");
+ done_fn = done;
+@@ -1609,7 +1610,7 @@ connect_loop:
+ return retcode (st0x_aborted);
+ } /* end of internal_command */
+
+-static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
++static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
+ {
+ st0x_aborted = DID_ABORT;
+ return SUCCESS;
+@@ -1624,7 +1625,7 @@ static int seagate_st0x_abort (Scsi_Cmnd
+ * May be called with SCpnt = NULL
+ */
+
+-static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt)
++static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
+ {
+ /* No timeouts - this command is going to fail because it was reset. */
+ DANY ("scsi%d: Reseting bus... ", hostno);
+diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
+deleted file mode 100644
+index fb5f380..0000000
+--- a/drivers/scsi/seagate.h
++++ /dev/null
+@@ -1,19 +0,0 @@
+-/*
+- * seagate.h Copyright (C) 1992 Drew Eckhardt
+- * low level scsi driver header for ST01/ST02 by
+- * Drew Eckhardt
+- *
+- * <drew at colorado.edu>
+- */
+-
+-#ifndef _SEAGATE_H
+-#define SEAGATE_H
+-
+-static int seagate_st0x_detect(struct scsi_host_template *);
+-static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-
+-static int seagate_st0x_abort(Scsi_Cmnd *);
+-static const char *seagate_st0x_info(struct Scsi_Host *);
+-static int seagate_st0x_bus_reset(Scsi_Cmnd *);
+-
+-#endif /* _SEAGATE_H */
+diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
+index 34f9343..3f8b931 100644
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2
+
+ #ifdef CONFIG_SCSI_PROC_FS
+ #include <linux/proc_fs.h>
+-static char *sg_version_date = "20060818";
++static char *sg_version_date = "20060920";
+
+ static int sg_proc_init(void);
+ static void sg_proc_cleanup(void);
+@@ -94,6 +94,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE;
+ static int def_reserved_size = -1; /* picks up init parameter */
+ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
+
++static int scatter_elem_sz = SG_SCATTER_SZ;
++static int scatter_elem_sz_prev = SG_SCATTER_SZ;
++
+ #define SG_SECTOR_SZ 512
+ #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
+
+@@ -1537,11 +1540,9 @@ sg_remove(struct class_device *cl_dev, s
+ msleep(10); /* dirty detach so delay device destruction */
+ }
+
+-/* Set 'perm' (4th argument) to 0 to disable module_param's definition
+- * of sysfs parameters (which module_param doesn't yet support).
+- * Sysfs parameters defined explicitly below.
+- */
+-module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO);
++module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
++module_param_named(def_reserved_size, def_reserved_size, int,
++ S_IRUGO | S_IWUSR);
+ module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
+
+ MODULE_AUTHOR("Douglas Gilbert");
+@@ -1550,6 +1551,8 @@ MODULE_LICENSE("GPL");
+ MODULE_VERSION(SG_VERSION_STR);
+ MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
+
++MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element "
++ "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))");
+ MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
+ MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
+
+@@ -1558,8 +1561,14 @@ init_sg(void)
+ {
+ int rc;
+
++ if (scatter_elem_sz < PAGE_SIZE) {
++ scatter_elem_sz = PAGE_SIZE;
++ scatter_elem_sz_prev = scatter_elem_sz;
++ }
+ if (def_reserved_size >= 0)
+ sg_big_buff = def_reserved_size;
++ else
++ def_reserved_size = sg_big_buff;
+
+ rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
+ SG_MAX_DEVS, "sg");
+@@ -1842,15 +1851,30 @@ sg_build_indirect(Sg_scatter_hold * schp
+ if (mx_sc_elems < 0)
+ return mx_sc_elems; /* most likely -ENOMEM */
+
++ num = scatter_elem_sz;
++ if (unlikely(num != scatter_elem_sz_prev)) {
++ if (num < PAGE_SIZE) {
++ scatter_elem_sz = PAGE_SIZE;
++ scatter_elem_sz_prev = PAGE_SIZE;
++ } else
++ scatter_elem_sz_prev = num;
++ }
+ for (k = 0, sg = schp->buffer, rem_sz = blk_size;
+ (rem_sz > 0) && (k < mx_sc_elems);
+ ++k, rem_sz -= ret_sz, ++sg) {
+
+- num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
++ num = (rem_sz > scatter_elem_sz_prev) ?
++ scatter_elem_sz_prev : rem_sz;
+ p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
+ if (!p)
+ return -ENOMEM;
+
++ if (num == scatter_elem_sz_prev) {
++ if (unlikely(ret_sz > scatter_elem_sz_prev)) {
++ scatter_elem_sz = ret_sz;
++ scatter_elem_sz_prev = ret_sz;
++ }
++ }
+ sg->page = p;
+ sg->length = ret_sz;
+
+@@ -2341,6 +2365,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ }
+ write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
++ if (unlikely(sg_big_buff != def_reserved_size))
++ sg_big_buff = def_reserved_size;
++
+ sg_build_reserve(sfp, sg_big_buff);
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
+ sfp->reserve.bufflen, sfp->reserve.k_use_sg));
+@@ -2437,16 +2464,16 @@ sg_res_in_use(Sg_fd * sfp)
+ return srp ? 1 : 0;
+ }
+
+-/* If retSzp==NULL want exact size or fail */
++/* The size fetched (value output via retSzp) set when non-NULL return */
+ static struct page *
+ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
+ {
+ struct page *resp = NULL;
+ gfp_t page_mask;
+ int order, a_size;
+- int resSz = rqSz;
++ int resSz;
+
+- if (rqSz <= 0)
++ if ((rqSz <= 0) || (NULL == retSzp))
+ return resp;
+
+ if (lowDma)
+@@ -2456,8 +2483,9 @@ sg_page_malloc(int rqSz, int lowDma, int
+
+ for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
+ order++, a_size <<= 1) ;
++ resSz = a_size; /* rounded up if necessary */
+ resp = alloc_pages(page_mask, order);
+- while ((!resp) && order && retSzp) {
++ while ((!resp) && order) {
+ --order;
+ a_size >>= 1; /* divide by 2, until PAGE_SIZE */
+ resp = alloc_pages(page_mask, order); /* try half */
+@@ -2466,8 +2494,7 @@ sg_page_malloc(int rqSz, int lowDma, int
+ if (resp) {
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ memset(page_address(resp), 0, resSz);
+- if (retSzp)
+- *retSzp = resSz;
++ *retSzp = resSz;
+ }
+ return resp;
+ }
+diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
+index 7cd366f..e81f97a 100644
+--- a/drivers/scsi/sgiwd93.c
++++ b/drivers/scsi/sgiwd93.c
+@@ -84,7 +84,7 @@ static inline unsigned long read_wd33c93
+ return value;
+ }
+
+-static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
+ {
+ struct Scsi_Host * host = (struct Scsi_Host *) dev_id;
+ unsigned long flags;
+@@ -97,7 +97,7 @@ static irqreturn_t sgiwd93_intr(int irq,
+ }
+
+ static inline
+-void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp)
++void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
+ {
+ unsigned long len = cmd->SCp.this_residual;
+ void *addr = cmd->SCp.ptr;
+@@ -129,7 +129,7 @@ void fill_hpc_entries(struct hpc_chunk *
+ hcp->desc.cntinfo = HPCDMA_EOX;
+ }
+
+-static int dma_setup(Scsi_Cmnd *cmd, int datainp)
++static int dma_setup(struct scsi_cmnd *cmd, int datainp)
+ {
+ struct ip22_hostdata *hdata = HDATA(cmd->device->host);
+ struct hpc3_scsiregs *hregs =
+@@ -163,7 +163,7 @@ static int dma_setup(Scsi_Cmnd *cmd, int
+ return 0;
+ }
+
+-static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
++static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
+ {
+ struct ip22_hostdata *hdata = HDATA(instance);
+@@ -305,7 +305,7 @@ static int sgiwd93_release(struct Scsi_H
+ return 1;
+ }
+
+-static int sgiwd93_bus_reset(Scsi_Cmnd *cmd)
++static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
+ {
+ /* FIXME perform bus-specific reset */
+
+diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
+index b27e854..551bacc 100644
+--- a/drivers/scsi/sim710.c
++++ b/drivers/scsi/sim710.c
+@@ -282,6 +282,7 @@ static struct eisa_device_id sim710_eisa
+ { "HWP0C80" },
+ { "" }
+ };
++MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
+
+ static __init int
+ sim710_eisa_probe(struct device *dev)
+diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
+index 7f669b6..e1a52c5 100644
+--- a/drivers/scsi/st.c
++++ b/drivers/scsi/st.c
+@@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct s
+ static int st_probe(struct device *);
+ static int st_remove(struct device *);
+
+-static void do_create_driverfs_files(void);
++static int do_create_driverfs_files(void);
+ static void do_remove_driverfs_files(void);
+-static void do_create_class_files(struct scsi_tape *, int, int);
++static int do_create_class_files(struct scsi_tape *, int, int);
+
+ static struct scsi_driver st_template = {
+ .owner = THIS_MODULE,
+@@ -1177,7 +1177,10 @@ static int st_open(struct inode *inode,
+ goto err_out;
+ if ((filp->f_flags & O_NONBLOCK) == 0 &&
+ retval != CHKRES_READY) {
+- retval = (-EIO);
++ if (STp->ready == NO_TAPE)
++ retval = (-ENOMEDIUM);
++ else
++ retval = (-EIO);
+ goto err_out;
+ }
+ return 0;
+@@ -4048,7 +4051,9 @@ static int st_probe(struct device *dev)
+ STm->cdevs[j] = cdev;
+
+ }
+- do_create_class_files(tpnt, dev_num, mode);
++ error = do_create_class_files(tpnt, dev_num, mode);
++ if (error)
++ goto out_free_tape;
+ }
+
+ sdev_printk(KERN_WARNING, SDp,
+@@ -4157,32 +4162,45 @@ static void scsi_tape_release(struct kre
+
+ static int __init init_st(void)
+ {
++ int err;
++
+ validate_options();
+
+- printk(KERN_INFO
+- "st: Version %s, fixed bufsize %d, s/g segs %d\n",
++ printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
+ verstr, st_fixed_buffer_size, st_max_sg_segs);
+
+ st_sysfs_class = class_create(THIS_MODULE, "scsi_tape");
+ if (IS_ERR(st_sysfs_class)) {
+- st_sysfs_class = NULL;
+ printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
+- return 1;
++ return PTR_ERR(st_sysfs_class);
+ }
+
+- if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+- ST_MAX_TAPE_ENTRIES, "st")) {
+- if (scsi_register_driver(&st_template.gendrv) == 0) {
+- do_create_driverfs_files();
+- return 0;
+- }
+- unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+- ST_MAX_TAPE_ENTRIES);
++ err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
++ ST_MAX_TAPE_ENTRIES, "st");
++ if (err) {
++ printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
++ SCSI_TAPE_MAJOR);
++ goto err_class;
+ }
+- class_destroy(st_sysfs_class);
+
+- printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
+- return 1;
++ err = scsi_register_driver(&st_template.gendrv);
++ if (err)
++ goto err_chrdev;
++
++ err = do_create_driverfs_files();
++ if (err)
++ goto err_scsidrv;
++
++ return 0;
++
++err_scsidrv:
++ scsi_unregister_driver(&st_template.gendrv);
++err_chrdev:
++ unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
++ ST_MAX_TAPE_ENTRIES);
++err_class:
++ class_destroy(st_sysfs_class);
++ return err;
+ }
+
+ static void __exit exit_st(void)
+@@ -4225,14 +4243,33 @@ static ssize_t st_version_show(struct de
+ }
+ static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
+
+-static void do_create_driverfs_files(void)
++static int do_create_driverfs_files(void)
+ {
+ struct device_driver *driverfs = &st_template.gendrv;
++ int err;
++
++ err = driver_create_file(driverfs, &driver_attr_try_direct_io);
++ if (err)
++ return err;
++ err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
++ if (err)
++ goto err_try_direct_io;
++ err = driver_create_file(driverfs, &driver_attr_max_sg_segs);
++ if (err)
++ goto err_attr_fixed_buf;
++ err = driver_create_file(driverfs, &driver_attr_version);
++ if (err)
++ goto err_attr_max_sg;
++
++ return 0;
+
+- driver_create_file(driverfs, &driver_attr_try_direct_io);
+- driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
+- driver_create_file(driverfs, &driver_attr_max_sg_segs);
+- driver_create_file(driverfs, &driver_attr_version);
++err_attr_max_sg:
++ driver_remove_file(driverfs, &driver_attr_max_sg_segs);
++err_attr_fixed_buf:
++ driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
++err_try_direct_io:
++ driver_remove_file(driverfs, &driver_attr_try_direct_io);
++ return err;
+ }
+
+ static void do_remove_driverfs_files(void)
+@@ -4293,15 +4330,12 @@ static ssize_t st_defcompression_show(st
+
+ CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
+
+-static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
++static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
+ {
+ int i, rew, error;
+ char name[10];
+ struct class_device *st_class_member;
+
+- if (!st_sysfs_class)
+- return;
+-
+ for (rew=0; rew < 2; rew++) {
+ /* Make sure that the minor numbers corresponding to the four
+ first modes always get the same names */
+@@ -4316,18 +4350,24 @@ static void do_create_class_files(struct
+ if (IS_ERR(st_class_member)) {
+ printk(KERN_WARNING "st%d: class_device_create failed\n",
+ dev_num);
++ error = PTR_ERR(st_class_member);
+ goto out;
+ }
+ class_set_devdata(st_class_member, &STp->modes[mode]);
+
+- class_device_create_file(st_class_member,
+- &class_device_attr_defined);
+- class_device_create_file(st_class_member,
+- &class_device_attr_default_blksize);
+- class_device_create_file(st_class_member,
+- &class_device_attr_default_density);
+- class_device_create_file(st_class_member,
+- &class_device_attr_default_compression);
++ error = class_device_create_file(st_class_member,
++ &class_device_attr_defined);
++ if (error) goto out;
++ error = class_device_create_file(st_class_member,
++ &class_device_attr_default_blksize);
++ if (error) goto out;
++ error = class_device_create_file(st_class_member,
++ &class_device_attr_default_density);
++ if (error) goto out;
++ error = class_device_create_file(st_class_member,
++ &class_device_attr_default_compression);
++ if (error) goto out;
++
+ if (mode == 0 && rew == 0) {
+ error = sysfs_create_link(&STp->device->sdev_gendev.kobj,
+ &st_class_member->kobj,
+@@ -4336,11 +4376,15 @@ static void do_create_class_files(struct
+ printk(KERN_ERR
+ "st%d: Can't create sysfs link from SCSI device.\n",
+ dev_num);
++ goto out;
+ }
+ }
+ }
+- out:
+- return;
++
++ return 0;
++
++out:
++ return error;
+ }
+
+ /* The following functions may be useful for a larger audience. */
+diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
+new file mode 100644
+index 0000000..185c270
+--- /dev/null
++++ b/drivers/scsi/stex.c
+@@ -0,0 +1,1385 @@
++/*
++ * SuperTrak EX Series Storage Controller driver for Linux
++ *
++ * Copyright (C) 2005, 2006 Promise Technology 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.
++ *
++ * Written By:
++ * Ed Lin <promise_linux at promise.com>
++ *
++ * Version: 3.0.0.1
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/time.h>
++#include <linux/pci.h>
++#include <linux/blkdev.h>
++#include <linux/interrupt.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/byteorder.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_tcq.h>
++
++#define DRV_NAME "stex"
++#define ST_DRIVER_VERSION "3.0.0.1"
++#define ST_VER_MAJOR 3
++#define ST_VER_MINOR 0
++#define ST_OEM 0
++#define ST_BUILD_VER 1
++
++enum {
++ /* MU register offset */
++ IMR0 = 0x10, /* MU_INBOUND_MESSAGE_REG0 */
++ IMR1 = 0x14, /* MU_INBOUND_MESSAGE_REG1 */
++ OMR0 = 0x18, /* MU_OUTBOUND_MESSAGE_REG0 */
++ OMR1 = 0x1c, /* MU_OUTBOUND_MESSAGE_REG1 */
++ IDBL = 0x20, /* MU_INBOUND_DOORBELL */
++ IIS = 0x24, /* MU_INBOUND_INTERRUPT_STATUS */
++ IIM = 0x28, /* MU_INBOUND_INTERRUPT_MASK */
++ ODBL = 0x2c, /* MU_OUTBOUND_DOORBELL */
++ OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */
++ OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */
++
++ /* MU register value */
++ MU_INBOUND_DOORBELL_HANDSHAKE = 1,
++ MU_INBOUND_DOORBELL_REQHEADCHANGED = 2,
++ MU_INBOUND_DOORBELL_STATUSTAILCHANGED = 4,
++ MU_INBOUND_DOORBELL_HMUSTOPPED = 8,
++ MU_INBOUND_DOORBELL_RESET = 16,
++
++ MU_OUTBOUND_DOORBELL_HANDSHAKE = 1,
++ MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = 2,
++ MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = 4,
++ MU_OUTBOUND_DOORBELL_BUSCHANGE = 8,
++ MU_OUTBOUND_DOORBELL_HASEVENT = 16,
++
++ /* MU status code */
++ MU_STATE_STARTING = 1,
++ MU_STATE_FMU_READY_FOR_HANDSHAKE = 2,
++ MU_STATE_SEND_HANDSHAKE_FRAME = 3,
++ MU_STATE_STARTED = 4,
++ MU_STATE_RESETTING = 5,
++
++ MU_MAX_DELAY_TIME = 240000,
++ MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
++ HMU_PARTNER_TYPE = 2,
++
++ /* firmware returned values */
++ SRB_STATUS_SUCCESS = 0x01,
++ SRB_STATUS_ERROR = 0x04,
++ SRB_STATUS_BUSY = 0x05,
++ SRB_STATUS_INVALID_REQUEST = 0x06,
++ SRB_STATUS_SELECTION_TIMEOUT = 0x0A,
++ SRB_SEE_SENSE = 0x80,
++
++ /* task attribute */
++ TASK_ATTRIBUTE_SIMPLE = 0x0,
++ TASK_ATTRIBUTE_HEADOFQUEUE = 0x1,
++ TASK_ATTRIBUTE_ORDERED = 0x2,
++ TASK_ATTRIBUTE_ACA = 0x4,
++
++ /* request count, etc. */
++ MU_MAX_REQUEST = 32,
++
++ /* one message wasted, use MU_MAX_REQUEST+1
++ to handle MU_MAX_REQUEST messages */
++ MU_REQ_COUNT = (MU_MAX_REQUEST + 1),
++ MU_STATUS_COUNT = (MU_MAX_REQUEST + 1),
++
++ STEX_CDB_LENGTH = MAX_COMMAND_SIZE,
++ REQ_VARIABLE_LEN = 1024,
++ STATUS_VAR_LEN = 128,
++ ST_CAN_QUEUE = MU_MAX_REQUEST,
++ ST_CMD_PER_LUN = MU_MAX_REQUEST,
++ ST_MAX_SG = 32,
++
++ /* sg flags */
++ SG_CF_EOT = 0x80, /* end of table */
++ SG_CF_64B = 0x40, /* 64 bit item */
++ SG_CF_HOST = 0x20, /* sg in host memory */
++
++ ST_MAX_ARRAY_SUPPORTED = 16,
++ ST_MAX_TARGET_NUM = (ST_MAX_ARRAY_SUPPORTED+1),
++ ST_MAX_LUN_PER_TARGET = 16,
++
++ st_shasta = 0,
++ st_vsc = 1,
++ st_yosemite = 2,
++
++ PASSTHRU_REQ_TYPE = 0x00000001,
++ PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
++ ST_INTERNAL_TIMEOUT = 30,
++
++ ST_TO_CMD = 0,
++ ST_FROM_CMD = 1,
++
++ /* vendor specific commands of Promise */
++ MGT_CMD = 0xd8,
++ SINBAND_MGT_CMD = 0xd9,
++ ARRAY_CMD = 0xe0,
++ CONTROLLER_CMD = 0xe1,
++ DEBUGGING_CMD = 0xe2,
++ PASSTHRU_CMD = 0xe3,
++
++ PASSTHRU_GET_ADAPTER = 0x05,
++ PASSTHRU_GET_DRVVER = 0x10,
++
++ CTLR_CONFIG_CMD = 0x03,
++ CTLR_SHUTDOWN = 0x0d,
++
++ CTLR_POWER_STATE_CHANGE = 0x0e,
++ CTLR_POWER_SAVING = 0x01,
++
++ PASSTHRU_SIGNATURE = 0x4e415041,
++ MGT_CMD_SIGNATURE = 0xba,
++
++ INQUIRY_EVPD = 0x01,
++};
++
++/* SCSI inquiry data */
++typedef struct st_inq {
++ u8 DeviceType :5;
++ u8 DeviceTypeQualifier :3;
++ u8 DeviceTypeModifier :7;
++ u8 RemovableMedia :1;
++ u8 Versions;
++ u8 ResponseDataFormat :4;
++ u8 HiSupport :1;
++ u8 NormACA :1;
++ u8 ReservedBit :1;
++ u8 AERC :1;
++ u8 AdditionalLength;
++ u8 Reserved[2];
++ u8 SoftReset :1;
++ u8 CommandQueue :1;
++ u8 Reserved2 :1;
++ u8 LinkedCommands :1;
++ u8 Synchronous :1;
++ u8 Wide16Bit :1;
++ u8 Wide32Bit :1;
++ u8 RelativeAddressing :1;
++ u8 VendorId[8];
++ u8 ProductId[16];
++ u8 ProductRevisionLevel[4];
++ u8 VendorSpecific[20];
++ u8 Reserved3[40];
++} ST_INQ;
++
++struct st_sgitem {
++ u8 ctrl; /* SG_CF_xxx */
++ u8 reserved[3];
++ __le32 count;
++ __le32 addr;
++ __le32 addr_hi;
++};
++
++struct st_sgtable {
++ __le16 sg_count;
++ __le16 max_sg_count;
++ __le32 sz_in_byte;
++ struct st_sgitem table[ST_MAX_SG];
++};
++
++struct handshake_frame {
++ __le32 rb_phy; /* request payload queue physical address */
++ __le32 rb_phy_hi;
++ __le16 req_sz; /* size of each request payload */
++ __le16 req_cnt; /* count of reqs the buffer can hold */
++ __le16 status_sz; /* size of each status payload */
++ __le16 status_cnt; /* count of status the buffer can hold */
++ __le32 hosttime; /* seconds from Jan 1, 1970 (GMT) */
++ __le32 hosttime_hi;
++ u8 partner_type; /* who sends this frame */
++ u8 reserved0[7];
++ __le32 partner_ver_major;
++ __le32 partner_ver_minor;
++ __le32 partner_ver_oem;
++ __le32 partner_ver_build;
++ u32 reserved1[4];
++};
++
++struct req_msg {
++ __le16 tag;
++ u8 lun;
++ u8 target;
++ u8 task_attr;
++ u8 task_manage;
++ u8 prd_entry;
++ u8 payload_sz; /* payload size in 4-byte, not used */
++ u8 cdb[STEX_CDB_LENGTH];
++ u8 variable[REQ_VARIABLE_LEN];
++};
++
++struct status_msg {
++ __le16 tag;
++ u8 lun;
++ u8 target;
++ u8 srb_status;
++ u8 scsi_status;
++ u8 reserved;
++ u8 payload_sz; /* payload size in 4-byte */
++ u8 variable[STATUS_VAR_LEN];
++};
++
++struct ver_info {
++ u32 major;
++ u32 minor;
++ u32 oem;
++ u32 build;
++ u32 reserved[2];
++};
++
++struct st_frame {
++ u32 base[6];
++ u32 rom_addr;
++
++ struct ver_info drv_ver;
++ struct ver_info bios_ver;
++
++ u32 bus;
++ u32 slot;
++ u32 irq_level;
++ u32 irq_vec;
++ u32 id;
++ u32 subid;
++
++ u32 dimm_size;
++ u8 dimm_type;
++ u8 reserved[3];
++
++ u32 channel;
++ u32 reserved1;
++};
++
++struct st_drvver {
++ u32 major;
++ u32 minor;
++ u32 oem;
++ u32 build;
++ u32 signature[2];
++ u8 console_id;
++ u8 host_no;
++ u8 reserved0[2];
++ u32 reserved[3];
++};
++
++#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg))
++#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg))
++#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
++#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ))
++#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE)
++
++struct st_ccb {
++ struct req_msg *req;
++ struct scsi_cmnd *cmd;
++
++ void *sense_buffer;
++ unsigned int sense_bufflen;
++ int sg_count;
++
++ u32 req_type;
++ u8 srb_status;
++ u8 scsi_status;
++};
++
++struct st_hba {
++ void __iomem *mmio_base; /* iomapped PCI memory space */
++ void *dma_mem;
++ dma_addr_t dma_handle;
++
++ struct Scsi_Host *host;
++ struct pci_dev *pdev;
++
++ u32 req_head;
++ u32 req_tail;
++ u32 status_head;
++ u32 status_tail;
++
++ struct status_msg *status_buffer;
++ void *copy_buffer; /* temp buffer for driver-handled commands */
++ struct st_ccb ccb[MU_MAX_REQUEST];
++ struct st_ccb *wait_ccb;
++ wait_queue_head_t waitq;
++
++ unsigned int mu_status;
++ int out_req_cnt;
++
++ unsigned int cardtype;
++};
++
++static const char console_inq_page[] =
++{
++ 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30,
++ 0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20, /* "Promise " */
++ 0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E, /* "RAID Con" */
++ 0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20, /* "sole " */
++ 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20, /* "1.00 " */
++ 0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D, /* "SX/RSAF-" */
++ 0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20, /* "TE1.00 " */
++ 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20
++};
++
++MODULE_AUTHOR("Ed Lin");
++MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(ST_DRIVER_VERSION);
++
++static void stex_gettime(__le32 *time)
++{
++ struct timeval tv;
++ do_gettimeofday(&tv);
++
++ *time = cpu_to_le32(tv.tv_sec & 0xffffffff);
++ *(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
++}
++
++static struct status_msg *stex_get_status(struct st_hba *hba)
++{
++ struct status_msg *status =
++ hba->status_buffer + hba->status_tail;
++
++ ++hba->status_tail;
++ hba->status_tail %= MU_STATUS_COUNT;
++
++ return status;
++}
++
++static void stex_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
++{
++ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
++
++ cmd->sense_buffer[0] = 0x70; /* fixed format, current */
++ cmd->sense_buffer[2] = sk;
++ cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
++ cmd->sense_buffer[12] = asc;
++ cmd->sense_buffer[13] = ascq;
++}
++
++static void stex_invalid_field(struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
++{
++ /* "Invalid field in cbd" */
++ stex_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
++ done(cmd);
++}
++
++static struct req_msg *stex_alloc_req(struct st_hba *hba)
++{
++ struct req_msg *req = ((struct req_msg *)hba->dma_mem) +
++ hba->req_head;
++
++ ++hba->req_head;
++ hba->req_head %= MU_REQ_COUNT;
++
++ return req;
++}
++
++static int stex_map_sg(struct st_hba *hba,
++ struct req_msg *req, struct st_ccb *ccb)
++{
++ struct pci_dev *pdev = hba->pdev;
++ struct scsi_cmnd *cmd;
++ dma_addr_t dma_handle;
++ struct scatterlist *src;
++ struct st_sgtable *dst;
++ int i;
++
++ cmd = ccb->cmd;
++ dst = (struct st_sgtable *)req->variable;
++ dst->max_sg_count = cpu_to_le16(ST_MAX_SG);
++ dst->sz_in_byte = cpu_to_le32(cmd->request_bufflen);
++
++ if (cmd->use_sg) {
++ int n_elem;
++
++ src = (struct scatterlist *) cmd->request_buffer;
++ n_elem = pci_map_sg(pdev, src,
++ cmd->use_sg, cmd->sc_data_direction);
++ if (n_elem <= 0)
++ return -EIO;
++
++ ccb->sg_count = n_elem;
++ dst->sg_count = cpu_to_le16((u16)n_elem);
++
++ for (i = 0; i < n_elem; i++, src++) {
++ dst->table[i].count = cpu_to_le32((u32)sg_dma_len(src));
++ dst->table[i].addr =
++ cpu_to_le32(sg_dma_address(src) & 0xffffffff);
++ dst->table[i].addr_hi =
++ cpu_to_le32((sg_dma_address(src) >> 16) >> 16);
++ dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;
++ }
++ dst->table[--i].ctrl |= SG_CF_EOT;
++ return 0;
++ }
++
++ dma_handle = pci_map_single(pdev, cmd->request_buffer,
++ cmd->request_bufflen, cmd->sc_data_direction);
++ cmd->SCp.dma_handle = dma_handle;
++
++ ccb->sg_count = 1;
++ dst->sg_count = cpu_to_le16(1);
++ dst->table[0].addr = cpu_to_le32(dma_handle & 0xffffffff);
++ dst->table[0].addr_hi = cpu_to_le32((dma_handle >> 16) >> 16);
++ dst->table[0].count = cpu_to_le32((u32)cmd->request_bufflen);
++ dst->table[0].ctrl = SG_CF_EOT | SG_CF_64B | SG_CF_HOST;
++
++ return 0;
++}
++
++static void stex_internal_copy(struct scsi_cmnd *cmd,
++ const void *src, size_t *count, int sg_count, int direction)
++{
++ size_t lcount;
++ size_t len;
++ void *s, *d, *base = NULL;
++ if (*count > cmd->request_bufflen)
++ *count = cmd->request_bufflen;
++ lcount = *count;
++ while (lcount) {
++ len = lcount;
++ s = (void *)src;
++ if (cmd->use_sg) {
++ size_t offset = *count - lcount;
++ s += offset;
++ base = scsi_kmap_atomic_sg(cmd->request_buffer,
++ sg_count, &offset, &len);
++ if (base == NULL) {
++ *count -= lcount;
++ return;
++ }
++ d = base + offset;
++ } else
++ d = cmd->request_buffer;
++
++ if (direction == ST_TO_CMD)
++ memcpy(d, s, len);
++ else
++ memcpy(s, d, len);
++
++ lcount -= len;
++ if (cmd->use_sg)
++ scsi_kunmap_atomic_sg(base);
++ }
++}
++
++static int stex_direct_copy(struct scsi_cmnd *cmd,
++ const void *src, size_t count)
++{
++ struct st_hba *hba = (struct st_hba *) &cmd->device->host->hostdata[0];
++ size_t cp_len = count;
++ int n_elem = 0;
++
++ if (cmd->use_sg) {
++ n_elem = pci_map_sg(hba->pdev, cmd->request_buffer,
++ cmd->use_sg, cmd->sc_data_direction);
++ if (n_elem <= 0)
++ return 0;
++ }
++
++ stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
++
++ if (cmd->use_sg)
++ pci_unmap_sg(hba->pdev, cmd->request_buffer,
++ cmd->use_sg, cmd->sc_data_direction);
++ return cp_len == count;
++}
++
++static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
++{
++ struct st_frame *p;
++ size_t count = sizeof(struct st_frame);
++
++ p = hba->copy_buffer;
++ memset(p->base, 0, sizeof(u32)*6);
++ *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
++ p->rom_addr = 0;
++
++ p->drv_ver.major = ST_VER_MAJOR;
++ p->drv_ver.minor = ST_VER_MINOR;
++ p->drv_ver.oem = ST_OEM;
++ p->drv_ver.build = ST_BUILD_VER;
++
++ p->bus = hba->pdev->bus->number;
++ p->slot = hba->pdev->devfn;
++ p->irq_level = 0;
++ p->irq_vec = hba->pdev->irq;
++ p->id = hba->pdev->vendor << 16 | hba->pdev->device;
++ p->subid =
++ hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
++
++ stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
++}
++
++static void
++stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
++{
++ req->tag = cpu_to_le16(tag);
++ req->task_attr = TASK_ATTRIBUTE_SIMPLE;
++ req->task_manage = 0; /* not supported yet */
++
++ hba->ccb[tag].req = req;
++ hba->out_req_cnt++;
++
++ writel(hba->req_head, hba->mmio_base + IMR0);
++ writel(MU_INBOUND_DOORBELL_REQHEADCHANGED, hba->mmio_base + IDBL);
++ readl(hba->mmio_base + IDBL); /* flush */
++}
++
++static int
++stex_slave_alloc(struct scsi_device *sdev)
++{
++ /* Cheat: usually extracted from Inquiry data */
++ sdev->tagged_supported = 1;
++
++ scsi_activate_tcq(sdev, sdev->host->can_queue);
++
++ return 0;
++}
++
++static int
++stex_slave_config(struct scsi_device *sdev)
++{
++ sdev->use_10_for_rw = 1;
++ sdev->use_10_for_ms = 1;
++ sdev->timeout = 60 * HZ;
++ sdev->tagged_supported = 1;
++
++ return 0;
++}
++
++static void
++stex_slave_destroy(struct scsi_device *sdev)
++{
++ scsi_deactivate_tcq(sdev, 1);
++}
++
++static int
++stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
++{
++ struct st_hba *hba;
++ struct Scsi_Host *host;
++ unsigned int id,lun;
++ struct req_msg *req;
++ u16 tag;
++ host = cmd->device->host;
++ id = cmd->device->id;
++ lun = cmd->device->channel; /* firmware lun issue work around */
++ hba = (struct st_hba *) &host->hostdata[0];
++
++ switch (cmd->cmnd[0]) {
++ case MODE_SENSE_10:
++ {
++ static char ms10_caching_page[12] =
++ { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 };
++ unsigned char page;
++ page = cmd->cmnd[2] & 0x3f;
++ if (page == 0x8 || page == 0x3f) {
++ stex_direct_copy(cmd, ms10_caching_page,
++ sizeof(ms10_caching_page));
++ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
++ done(cmd);
++ } else
++ stex_invalid_field(cmd, done);
++ return 0;
++ }
++ case INQUIRY:
++ if (id != ST_MAX_ARRAY_SUPPORTED)
++ break;
++ if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) {
++ stex_direct_copy(cmd, console_inq_page,
++ sizeof(console_inq_page));
++ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
++ done(cmd);
++ } else
++ stex_invalid_field(cmd, done);
++ return 0;
++ case PASSTHRU_CMD:
++ if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
++ struct st_drvver ver;
++ ver.major = ST_VER_MAJOR;
++ ver.minor = ST_VER_MINOR;
++ ver.oem = ST_OEM;
++ ver.build = ST_BUILD_VER;
++ ver.signature[0] = PASSTHRU_SIGNATURE;
++ ver.console_id = ST_MAX_ARRAY_SUPPORTED;
++ ver.host_no = hba->host->host_no;
++ cmd->result = stex_direct_copy(cmd, &ver, sizeof(ver)) ?
++ DID_OK << 16 | COMMAND_COMPLETE << 8 :
++ DID_ERROR << 16 | COMMAND_COMPLETE << 8;
++ done(cmd);
++ return 0;
++ }
++ default:
++ break;
++ }
++
++ cmd->scsi_done = done;
++
++ tag = cmd->request->tag;
++
++ if (unlikely(tag >= host->can_queue))
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++ req = stex_alloc_req(hba);
++
++ if (hba->cardtype == st_yosemite) {
++ req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id;
++ req->target = 0;
++ } else {
++ req->lun = lun;
++ req->target = id;
++ }
++
++ /* cdb */
++ memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
++
++ hba->ccb[tag].cmd = cmd;
++ hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE;
++ hba->ccb[tag].sense_buffer = cmd->sense_buffer;
++ hba->ccb[tag].req_type = 0;
++
++ if (cmd->sc_data_direction != DMA_NONE)
++ stex_map_sg(hba, req, &hba->ccb[tag]);
++
++ stex_send_cmd(hba, req, tag);
++ return 0;
++}
++
++static void stex_unmap_sg(struct st_hba *hba, struct scsi_cmnd *cmd)
++{
++ if (cmd->sc_data_direction != DMA_NONE) {
++ if (cmd->use_sg)
++ pci_unmap_sg(hba->pdev, cmd->request_buffer,
++ cmd->use_sg, cmd->sc_data_direction);
++ else
++ pci_unmap_single(hba->pdev, cmd->SCp.dma_handle,
++ cmd->request_bufflen, cmd->sc_data_direction);
++ }
++}
++
++static void stex_scsi_done(struct st_ccb *ccb)
++{
++ struct scsi_cmnd *cmd = ccb->cmd;
++ int result;
++
++ if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) {
++ result = ccb->scsi_status;
++ switch (ccb->scsi_status) {
++ case SAM_STAT_GOOD:
++ result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
++ break;
++ case SAM_STAT_CHECK_CONDITION:
++ result |= DRIVER_SENSE << 24;
++ break;
++ case SAM_STAT_BUSY:
++ result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
++ break;
++ default:
++ result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8;
++ break;
++ }
++ }
++ else if (ccb->srb_status & SRB_SEE_SENSE)
++ result = DRIVER_SENSE << 24 | SAM_STAT_CHECK_CONDITION;
++ else switch (ccb->srb_status) {
++ case SRB_STATUS_SELECTION_TIMEOUT:
++ result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
++ break;
++ case SRB_STATUS_BUSY:
++ result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
++ break;
++ case SRB_STATUS_INVALID_REQUEST:
++ case SRB_STATUS_ERROR:
++ default:
++ result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
++ break;
++ }
++
++ cmd->result = result;
++ cmd->scsi_done(cmd);
++}
++
++static void stex_copy_data(struct st_ccb *ccb,
++ struct status_msg *resp, unsigned int variable)
++{
++ size_t count = variable;
++ if (resp->scsi_status != SAM_STAT_GOOD) {
++ if (ccb->sense_buffer != NULL)
++ memcpy(ccb->sense_buffer, resp->variable,
++ min(variable, ccb->sense_bufflen));
++ return;
++ }
++
++ if (ccb->cmd == NULL)
++ return;
++ stex_internal_copy(ccb->cmd,
++ resp->variable, &count, ccb->sg_count, ST_TO_CMD);
++}
++
++static void stex_ys_commands(struct st_hba *hba,
++ struct st_ccb *ccb, struct status_msg *resp)
++{
++ size_t count;
++
++ if (ccb->cmd->cmnd[0] == MGT_CMD &&
++ resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
++ ccb->cmd->request_bufflen =
++ le32_to_cpu(*(__le32 *)&resp->variable[0]);
++ return;
++ }
++
++ if (resp->srb_status != 0)
++ return;
++
++ /* determine inquiry command status by DeviceTypeQualifier */
++ if (ccb->cmd->cmnd[0] == INQUIRY &&
++ resp->scsi_status == SAM_STAT_GOOD) {
++ ST_INQ *inq_data;
++
++ count = STEX_EXTRA_SIZE;
++ stex_internal_copy(ccb->cmd, hba->copy_buffer,
++ &count, ccb->sg_count, ST_FROM_CMD);
++ inq_data = (ST_INQ *)hba->copy_buffer;
++ if (inq_data->DeviceTypeQualifier != 0)
++ ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
++ else
++ ccb->srb_status = SRB_STATUS_SUCCESS;
++ } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) {
++ u8 *report_lun_data = (u8 *)hba->copy_buffer;
++
++ count = STEX_EXTRA_SIZE;
++ stex_internal_copy(ccb->cmd, report_lun_data,
++ &count, ccb->sg_count, ST_FROM_CMD);
++ if (report_lun_data[2] || report_lun_data[3]) {
++ report_lun_data[2] = 0x00;
++ report_lun_data[3] = 0x08;
++ stex_internal_copy(ccb->cmd, report_lun_data,
++ &count, ccb->sg_count, ST_TO_CMD);
++ }
++ }
++}
++
++static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
++{
++ void __iomem *base = hba->mmio_base;
++ struct status_msg *resp;
++ struct st_ccb *ccb;
++ unsigned int size;
++ u16 tag;
++
++ if (!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))
++ return;
++
++ /* status payloads */
++ hba->status_head = readl(base + OMR1);
++ if (unlikely(hba->status_head >= MU_STATUS_COUNT)) {
++ printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n",
++ pci_name(hba->pdev));
++ return;
++ }
++
++ /*
++ * it's not a valid status payload if:
++ * 1. there are no pending requests(e.g. during init stage)
++ * 2. there are some pending requests, but the controller is in
++ * reset status, and its type is not st_yosemite
++ * firmware of st_yosemite in reset status will return pending requests
++ * to driver, so we allow it to pass
++ */
++ if (unlikely(hba->out_req_cnt <= 0 ||
++ (hba->mu_status == MU_STATE_RESETTING &&
++ hba->cardtype != st_yosemite))) {
++ hba->status_tail = hba->status_head;
++ goto update_status;
++ }
++
++ while (hba->status_tail != hba->status_head) {
++ resp = stex_get_status(hba);
++ tag = le16_to_cpu(resp->tag);
++ if (unlikely(tag >= hba->host->can_queue)) {
++ printk(KERN_WARNING DRV_NAME
++ "(%s): invalid tag\n", pci_name(hba->pdev));
++ continue;
++ }
++
++ ccb = &hba->ccb[tag];
++ if (hba->wait_ccb == ccb)
++ hba->wait_ccb = NULL;
++ if (unlikely(ccb->req == NULL)) {
++ printk(KERN_WARNING DRV_NAME
++ "(%s): lagging req\n", pci_name(hba->pdev));
++ hba->out_req_cnt--;
++ continue;
++ }
++
++ size = resp->payload_sz * sizeof(u32); /* payload size */
++ if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN ||
++ size > sizeof(*resp))) {
++ printk(KERN_WARNING DRV_NAME "(%s): bad status size\n",
++ pci_name(hba->pdev));
++ } else {
++ size -= sizeof(*resp) - STATUS_VAR_LEN; /* copy size */
++ if (size)
++ stex_copy_data(ccb, resp, size);
++ }
++
++ ccb->srb_status = resp->srb_status;
++ ccb->scsi_status = resp->scsi_status;
++
++ if (likely(ccb->cmd != NULL)) {
++ if (hba->cardtype == st_yosemite)
++ stex_ys_commands(hba, ccb, resp);
++
++ if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
++ ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
++ stex_controller_info(hba, ccb);
++
++ stex_unmap_sg(hba, ccb->cmd);
++ stex_scsi_done(ccb);
++ hba->out_req_cnt--;
++ } else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
++ hba->out_req_cnt--;
++ if (ccb->req_type & PASSTHRU_REQ_NO_WAKEUP) {
++ ccb->req_type = 0;
++ continue;
++ }
++ ccb->req_type = 0;
++ if (waitqueue_active(&hba->waitq))
++ wake_up(&hba->waitq);
++ }
++ }
++
++update_status:
++ writel(hba->status_head, base + IMR1);
++ readl(base + IMR1); /* flush */
++}
++
++static irqreturn_t stex_intr(int irq, void *__hba)
++{
++ struct st_hba *hba = __hba;
++ void __iomem *base = hba->mmio_base;
++ u32 data;
++ unsigned long flags;
++ int handled = 0;
++
++ spin_lock_irqsave(hba->host->host_lock, flags);
++
++ data = readl(base + ODBL);
++
++ if (data && data != 0xffffffff) {
++ /* clear the interrupt */
++ writel(data, base + ODBL);
++ readl(base + ODBL); /* flush */
++ stex_mu_intr(hba, data);
++ handled = 1;
++ }
++
++ spin_unlock_irqrestore(hba->host->host_lock, flags);
++
++ return IRQ_RETVAL(handled);
++}
++
++static int stex_handshake(struct st_hba *hba)
++{
++ void __iomem *base = hba->mmio_base;
++ struct handshake_frame *h;
++ dma_addr_t status_phys;
++ int i;
++
++ if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
++ writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
++ readl(base + IDBL);
++ for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
++ && i < MU_MAX_DELAY_TIME; i++) {
++ rmb();
++ msleep(1);
++ }
++
++ if (i == MU_MAX_DELAY_TIME) {
++ printk(KERN_ERR DRV_NAME
++ "(%s): no handshake signature\n",
++ pci_name(hba->pdev));
++ return -1;
++ }
++ }
++
++ udelay(10);
++
++ h = (struct handshake_frame *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
++ h->rb_phy = cpu_to_le32(hba->dma_handle);
++ h->rb_phy_hi = cpu_to_le32((hba->dma_handle >> 16) >> 16);
++ h->req_sz = cpu_to_le16(sizeof(struct req_msg));
++ h->req_cnt = cpu_to_le16(MU_REQ_COUNT);
++ h->status_sz = cpu_to_le16(sizeof(struct status_msg));
++ h->status_cnt = cpu_to_le16(MU_STATUS_COUNT);
++ stex_gettime(&h->hosttime);
++ h->partner_type = HMU_PARTNER_TYPE;
++
++ status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE;
++ writel(status_phys, base + IMR0);
++ readl(base + IMR0);
++ writel((status_phys >> 16) >> 16, base + IMR1);
++ readl(base + IMR1);
++
++ writel((status_phys >> 16) >> 16, base + OMR0); /* old fw compatible */
++ readl(base + OMR0);
++ writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
++ readl(base + IDBL); /* flush */
++
++ udelay(10);
++ for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
++ && i < MU_MAX_DELAY_TIME; i++) {
++ rmb();
++ msleep(1);
++ }
++
++ if (i == MU_MAX_DELAY_TIME) {
++ printk(KERN_ERR DRV_NAME
++ "(%s): no signature after handshake frame\n",
++ pci_name(hba->pdev));
++ return -1;
++ }
++
++ writel(0, base + IMR0);
++ readl(base + IMR0);
++ writel(0, base + OMR0);
++ readl(base + OMR0);
++ writel(0, base + IMR1);
++ readl(base + IMR1);
++ writel(0, base + OMR1);
++ readl(base + OMR1); /* flush */
++ hba->mu_status = MU_STATE_STARTED;
++ return 0;
++}
++
++static int stex_abort(struct scsi_cmnd *cmd)
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct st_hba *hba = (struct st_hba *)host->hostdata;
++ u16 tag = cmd->request->tag;
++ void __iomem *base;
++ u32 data;
++ int result = SUCCESS;
++ unsigned long flags;
++ base = hba->mmio_base;
++ spin_lock_irqsave(host->host_lock, flags);
++ if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
++ hba->wait_ccb = &hba->ccb[tag];
++ else {
++ for (tag = 0; tag < host->can_queue; tag++)
++ if (hba->ccb[tag].cmd == cmd) {
++ hba->wait_ccb = &hba->ccb[tag];
++ break;
++ }
++ if (tag >= host->can_queue)
++ goto out;
++ }
++
++ data = readl(base + ODBL);
++ if (data == 0 || data == 0xffffffff)
++ goto fail_out;
++
++ writel(data, base + ODBL);
++ readl(base + ODBL); /* flush */
++
++ stex_mu_intr(hba, data);
++
++ if (hba->wait_ccb == NULL) {
++ printk(KERN_WARNING DRV_NAME
++ "(%s): lost interrupt\n", pci_name(hba->pdev));
++ goto out;
++ }
++
++fail_out:
++ stex_unmap_sg(hba, cmd);
++ hba->wait_ccb->req = NULL; /* nullify the req's future return */
++ hba->wait_ccb = NULL;
++ result = FAILED;
++out:
++ spin_unlock_irqrestore(host->host_lock, flags);
++ return result;
++}
++
++static void stex_hard_reset(struct st_hba *hba)
++{
++ struct pci_bus *bus;
++ int i;
++ u16 pci_cmd;
++ u8 pci_bctl;
++
++ for (i = 0; i < 16; i++)
++ pci_read_config_dword(hba->pdev, i * 4,
++ &hba->pdev->saved_config_space[i]);
++
++ /* Reset secondary bus. Our controller(MU/ATU) is the only device on
++ secondary bus. Consult Intel 80331/3 developer's manual for detail */
++ bus = hba->pdev->bus;
++ pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);
++ pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;
++ pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
++ msleep(1);
++ pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
++ pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
++
++ for (i = 0; i < MU_MAX_DELAY_TIME; i++) {
++ pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);
++ if (pci_cmd & PCI_COMMAND_MASTER)
++ break;
++ msleep(1);
++ }
++
++ ssleep(5);
++ for (i = 0; i < 16; i++)
++ pci_write_config_dword(hba->pdev, i * 4,
++ hba->pdev->saved_config_space[i]);
++}
++
++static int stex_reset(struct scsi_cmnd *cmd)
++{
++ struct st_hba *hba;
++ unsigned long flags;
++ unsigned long before;
++ hba = (struct st_hba *) &cmd->device->host->hostdata[0];
++
++ hba->mu_status = MU_STATE_RESETTING;
++
++ if (hba->cardtype == st_shasta)
++ stex_hard_reset(hba);
++
++ if (hba->cardtype != st_yosemite) {
++ if (stex_handshake(hba)) {
++ printk(KERN_WARNING DRV_NAME
++ "(%s): resetting: handshake failed\n",
++ pci_name(hba->pdev));
++ return FAILED;
++ }
++ spin_lock_irqsave(hba->host->host_lock, flags);
++ hba->req_head = 0;
++ hba->req_tail = 0;
++ hba->status_head = 0;
++ hba->status_tail = 0;
++ hba->out_req_cnt = 0;
++ spin_unlock_irqrestore(hba->host->host_lock, flags);
++ return SUCCESS;
++ }
++
++ /* st_yosemite */
++ writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
++ readl(hba->mmio_base + IDBL); /* flush */
++ before = jiffies;
++ while (hba->out_req_cnt > 0) {
++ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
++ printk(KERN_WARNING DRV_NAME
++ "(%s): reset timeout\n", pci_name(hba->pdev));
++ return FAILED;
++ }
++ msleep(1);
++ }
++
++ hba->mu_status = MU_STATE_STARTED;
++ return SUCCESS;
++}
++
++static int stex_biosparam(struct scsi_device *sdev,
++ struct block_device *bdev, sector_t capacity, int geom[])
++{
++ int heads = 255, sectors = 63, cylinders;
++
++ if (capacity < 0x200000) {
++ heads = 64;
++ sectors = 32;
++ }
++
++ cylinders = sector_div(capacity, heads * sectors);
++
++ geom[0] = heads;
++ geom[1] = sectors;
++ geom[2] = cylinders;
++
++ return 0;
++}
++
++static struct scsi_host_template driver_template = {
++ .module = THIS_MODULE,
++ .name = DRV_NAME,
++ .proc_name = DRV_NAME,
++ .bios_param = stex_biosparam,
++ .queuecommand = stex_queuecommand,
++ .slave_alloc = stex_slave_alloc,
++ .slave_configure = stex_slave_config,
++ .slave_destroy = stex_slave_destroy,
++ .eh_abort_handler = stex_abort,
++ .eh_host_reset_handler = stex_reset,
++ .can_queue = ST_CAN_QUEUE,
++ .this_id = -1,
++ .sg_tablesize = ST_MAX_SG,
++ .cmd_per_lun = ST_CMD_PER_LUN,
++};
++
++static int stex_set_dma_mask(struct pci_dev * pdev)
++{
++ int ret;
++ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
++ && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
++ return 0;
++ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (!ret)
++ ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++ return ret;
++}
++
++static int __devinit
++stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ struct st_hba *hba;
++ struct Scsi_Host *host;
++ int err;
++
++ err = pci_enable_device(pdev);
++ if (err)
++ return err;
++
++ pci_set_master(pdev);
++
++ host = scsi_host_alloc(&driver_template, sizeof(struct st_hba));
++
++ if (!host) {
++ printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n",
++ pci_name(pdev));
++ err = -ENOMEM;
++ goto out_disable;
++ }
++
++ hba = (struct st_hba *)host->hostdata;
++ memset(hba, 0, sizeof(struct st_hba));
++
++ err = pci_request_regions(pdev, DRV_NAME);
++ if (err < 0) {
++ printk(KERN_ERR DRV_NAME "(%s): request regions failed\n",
++ pci_name(pdev));
++ goto out_scsi_host_put;
++ }
++
++ hba->mmio_base = ioremap(pci_resource_start(pdev, 0),
++ pci_resource_len(pdev, 0));
++ if ( !hba->mmio_base) {
++ printk(KERN_ERR DRV_NAME "(%s): memory map failed\n",
++ pci_name(pdev));
++ err = -ENOMEM;
++ goto out_release_regions;
++ }
++
++ err = stex_set_dma_mask(pdev);
++ if (err) {
++ printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n",
++ pci_name(pdev));
++ goto out_iounmap;
++ }
++
++ hba->dma_mem = dma_alloc_coherent(&pdev->dev,
++ STEX_BUFFER_SIZE, &hba->dma_handle, GFP_KERNEL);
++ if (!hba->dma_mem) {
++ err = -ENOMEM;
++ printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
++ pci_name(pdev));
++ goto out_iounmap;
++ }
++
++ hba->status_buffer =
++ (struct status_msg *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
++ hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE;
++ hba->mu_status = MU_STATE_STARTING;
++
++ hba->cardtype = (unsigned int) id->driver_data;
++
++ /* firmware uses id/lun pair for a logical drive, but lun would be
++ always 0 if CONFIG_SCSI_MULTI_LUN not configured, so we use
++ channel to map lun here */
++ host->max_channel = ST_MAX_LUN_PER_TARGET - 1;
++ host->max_id = ST_MAX_TARGET_NUM;
++ host->max_lun = 1;
++ host->unique_id = host->host_no;
++ host->max_cmd_len = STEX_CDB_LENGTH;
++
++ hba->host = host;
++ hba->pdev = pdev;
++ init_waitqueue_head(&hba->waitq);
++
++ err = request_irq(pdev->irq, stex_intr, IRQF_SHARED, DRV_NAME, hba);
++ if (err) {
++ printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",
++ pci_name(pdev));
++ goto out_pci_free;
++ }
++
++ err = stex_handshake(hba);
++ if (err)
++ goto out_free_irq;
++
++ err = scsi_init_shared_tag_map(host, ST_CAN_QUEUE);
++ if (err) {
++ printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
++ pci_name(pdev));
++ goto out_free_irq;
++ }
++
++ pci_set_drvdata(pdev, hba);
++
++ err = scsi_add_host(host, &pdev->dev);
++ if (err) {
++ printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n",
++ pci_name(pdev));
++ goto out_free_irq;
++ }
++
++ scsi_scan_host(host);
++
++ return 0;
++
++out_free_irq:
++ free_irq(pdev->irq, hba);
++out_pci_free:
++ dma_free_coherent(&pdev->dev, STEX_BUFFER_SIZE,
++ hba->dma_mem, hba->dma_handle);
++out_iounmap:
++ iounmap(hba->mmio_base);
++out_release_regions:
++ pci_release_regions(pdev);
++out_scsi_host_put:
++ scsi_host_put(host);
++out_disable:
++ pci_disable_device(pdev);
++
++ return err;
++}
++
++static void stex_hba_stop(struct st_hba *hba)
++{
++ struct req_msg *req;
++ unsigned long flags;
++ unsigned long before;
++ u16 tag = 0;
++
++ spin_lock_irqsave(hba->host->host_lock, flags);
++ req = stex_alloc_req(hba);
++ memset(req->cdb, 0, STEX_CDB_LENGTH);
++
++ if (hba->cardtype == st_yosemite) {
++ req->cdb[0] = MGT_CMD;
++ req->cdb[1] = MGT_CMD_SIGNATURE;
++ req->cdb[2] = CTLR_CONFIG_CMD;
++ req->cdb[3] = CTLR_SHUTDOWN;
++ } else {
++ req->cdb[0] = CONTROLLER_CMD;
++ req->cdb[1] = CTLR_POWER_STATE_CHANGE;
++ req->cdb[2] = CTLR_POWER_SAVING;
++ }
++
++ hba->ccb[tag].cmd = NULL;
++ hba->ccb[tag].sg_count = 0;
++ hba->ccb[tag].sense_bufflen = 0;
++ hba->ccb[tag].sense_buffer = NULL;
++ hba->ccb[tag].req_type |= PASSTHRU_REQ_TYPE;
++
++ stex_send_cmd(hba, req, tag);
++ spin_unlock_irqrestore(hba->host->host_lock, flags);
++
++ before = jiffies;
++ while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
++ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
++ return;
++ msleep(10);
++ }
++}
++
++static void stex_hba_free(struct st_hba *hba)
++{
++ free_irq(hba->pdev->irq, hba);
++
++ iounmap(hba->mmio_base);
++
++ pci_release_regions(hba->pdev);
++
++ dma_free_coherent(&hba->pdev->dev, STEX_BUFFER_SIZE,
++ hba->dma_mem, hba->dma_handle);
++}
++
++static void stex_remove(struct pci_dev *pdev)
++{
++ struct st_hba *hba = pci_get_drvdata(pdev);
++
++ scsi_remove_host(hba->host);
++
++ pci_set_drvdata(pdev, NULL);
++
++ stex_hba_stop(hba);
++
++ stex_hba_free(hba);
++
++ scsi_host_put(hba->host);
++
++ pci_disable_device(pdev);
++}
++
++static void stex_shutdown(struct pci_dev *pdev)
++{
++ struct st_hba *hba = pci_get_drvdata(pdev);
++
++ stex_hba_stop(hba);
++}
++
++static struct pci_device_id stex_pci_tbl[] = {
++ { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x105a, 0xf350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x105a, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
++ { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
++ { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite },
++ { } /* terminate list */
++};
++MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
++
++static struct pci_driver stex_pci_driver = {
++ .name = DRV_NAME,
++ .id_table = stex_pci_tbl,
++ .probe = stex_probe,
++ .remove = __devexit_p(stex_remove),
++ .shutdown = stex_shutdown,
++};
++
++static int __init stex_init(void)
++{
++ printk(KERN_INFO DRV_NAME
++ ": Promise SuperTrak EX Driver version: %s\n",
++ ST_DRIVER_VERSION);
++
++ return pci_register_driver(&stex_pci_driver);
++}
++
++static void __exit stex_exit(void)
++{
++ pci_unregister_driver(&stex_pci_driver);
++}
++
++module_init(stex_init);
++module_exit(stex_exit);
+diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
+index 2f8073b..3b3f305 100644
+--- a/drivers/scsi/sun3_NCR5380.c
++++ b/drivers/scsi/sun3_NCR5380.c
+@@ -266,8 +266,8 @@ static struct scsi_host_template *the_te
+ (struct NCR5380_hostdata *)(in)->hostdata
+ #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+-#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
+-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
++#define NEXT(cmd) ((struct scsi_cmnd *)((cmd)->host_scribble))
++#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble))
+
+ #define HOSTNO instance->host_no
+ #define H_NO(cmd) (cmd)->device->host->host_no
+@@ -360,7 +360,7 @@ static void __init init_tags( void )
+ * conditions.
+ */
+
+-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
++static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
+ {
+ SETUP_HOSTDATA(cmd->device->host);
+
+@@ -384,7 +384,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd,
+ * untagged.
+ */
+
+-static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
++static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
+ {
+ SETUP_HOSTDATA(cmd->device->host);
+
+@@ -416,7 +416,7 @@ static void cmd_get_tag( Scsi_Cmnd *cmd,
+ * unlock the LUN.
+ */
+
+-static void cmd_free_tag( Scsi_Cmnd *cmd )
++static void cmd_free_tag(struct scsi_cmnd *cmd)
+ {
+ SETUP_HOSTDATA(cmd->device->host);
+
+@@ -460,18 +460,18 @@ static void free_all_tags( void )
+
+
+ /*
+- * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
++ * Function: void merge_contiguous_buffers(struct scsi_cmnd *cmd)
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ * transfer. This is possible if the scatter buffers lie on
+ * physical contiguous addresses.
+ *
+- * Parameters: Scsi_Cmnd *cmd
++ * Parameters: struct scsi_cmnd *cmd
+ * The command to work on. The first scatter buffer's data are
+ * assumed to be already transfered into ptr/this_residual.
+ */
+
+-static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
++static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
+ {
+ unsigned long endaddr;
+ #if (NDEBUG & NDEBUG_MERGING)
+@@ -501,15 +501,15 @@ static void merge_contiguous_buffers( Sc
+ }
+
+ /*
+- * Function : void initialize_SCp(Scsi_Cmnd *cmd)
++ * Function : void initialize_SCp(struct scsi_cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the
+ * start of the buffer.
+ *
+- * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
++ * Inputs : cmd - struct scsi_cmnd structure to have pointers reset.
+ */
+
+-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
++static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
+ {
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
+@@ -753,14 +753,15 @@ static void NCR5380_print_status (struct
+ do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+ pos += sprintf(pos, fmt , ## args); } while(0)
+ static
+-char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
++char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer,
++ int length);
+
+-static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start,
+- off_t offset, int length, int inout)
++static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
++ char **start, off_t offset, int length, int inout)
+ {
+ char *pos = buffer;
+ struct NCR5380_hostdata *hostdata;
+- Scsi_Cmnd *ptr;
++ struct scsi_cmnd *ptr;
+ unsigned long flags;
+ off_t begin = 0;
+ #define check_offset() \
+@@ -784,18 +785,19 @@ static int NCR5380_proc_info (struct Scs
+ if (!hostdata->connected)
+ SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+ else
+- pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
++ pos = lprint_Scsi_Cmnd ((struct scsi_cmnd *) hostdata->connected,
+ pos, buffer, length);
+ SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+ check_offset();
+- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
++ for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr))
++ {
+ pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ check_offset();
+ }
+
+ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+ check_offset();
+- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
++ for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ check_offset();
+@@ -810,8 +812,8 @@ static int NCR5380_proc_info (struct Scs
+ return length;
+ }
+
+-static char *
+-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
++static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer,
++ int length)
+ {
+ int i, s;
+ unsigned char *command;
+@@ -888,8 +890,8 @@ static int NCR5380_init (struct Scsi_Hos
+ }
+
+ /*
+- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+- * void (*done)(Scsi_Cmnd *))
++ * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd,
++ * void (*done)(struct scsi_cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+@@ -906,10 +908,11 @@ static int NCR5380_init (struct Scsi_Hos
+ */
+
+ /* Only make static if a wrapper function is used */
+-static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
++static int NCR5380_queue_command(struct scsi_cmnd *cmd,
++ void (*done)(struct scsi_cmnd *))
+ {
+ SETUP_HOSTDATA(cmd->device->host);
+- Scsi_Cmnd *tmp;
++ struct scsi_cmnd *tmp;
+ unsigned long flags;
+
+ #if (NDEBUG & NDEBUG_NO_WRITE)
+@@ -990,7 +993,7 @@ static int NCR5380_queue_command (Scsi_C
+ NEXT(cmd) = hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
++ for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
+ NEXT(tmp); tmp = NEXT(tmp))
+ ;
+ LIST(cmd, tmp);
+@@ -1030,7 +1033,7 @@ static int NCR5380_queue_command (Scsi_C
+
+ static void NCR5380_main (void *bl)
+ {
+- Scsi_Cmnd *tmp, *prev;
++ struct scsi_cmnd *tmp, *prev;
+ struct Scsi_Host *instance = first_instance;
+ struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+ int done;
+@@ -1073,12 +1076,12 @@ static void NCR5380_main (void *bl)
+ * for a target that's not busy.
+ */
+ #if (NDEBUG & NDEBUG_LISTS)
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
++ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
+ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+ ;
+ if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+ #endif
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
++ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+ #if (NDEBUG & NDEBUG_LISTS)
+@@ -1252,7 +1255,7 @@ static void NCR5380_dma_complete( struct
+ *
+ */
+
+-static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t NCR5380_intr (int irq, void *dev_id)
+ {
+ struct Scsi_Host *instance = first_instance;
+ int done = 1, handled = 0;
+@@ -1339,7 +1342,8 @@ static irqreturn_t NCR5380_intr (int irq
+ }
+
+ #ifdef NCR5380_STATS
+-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
++static void collect_stats(struct NCR5380_hostdata *hostdata,
++ struct scsi_cmnd *cmd)
+ {
+ # ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+@@ -1365,8 +1369,8 @@ static void collect_stats(struct NCR5380
+ #endif
+
+ /*
+- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+- * int tag);
++ * Function : int NCR5380_select(struct Scsi_Host *instance,
++ * struct scsi_cmnd *cmd, int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ * including ARBITRATION, SELECTION, and initial message out for
+@@ -1395,7 +1399,8 @@ static void collect_stats(struct NCR5380
+ * cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
++static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd,
++ int tag)
+ {
+ SETUP_HOSTDATA(instance);
+ unsigned char tmp[3], phase;
+@@ -1985,7 +1990,7 @@ static void NCR5380_information_transfer
+ #endif
+ unsigned char *data;
+ unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
++ struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
+
+ #ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_INTR;
+@@ -2017,7 +2022,7 @@ static void NCR5380_information_transfer
+ if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+ != cmd))
+ {
+- if(cmd->request->flags & REQ_CMD) {
++ if(blk_fs_request(cmd->request)) {
+ sun3scsi_dma_setup(d, count,
+ rq_data_dir(cmd->request));
+ sun3_dma_setup_done = cmd;
+@@ -2272,7 +2277,7 @@ static void NCR5380_information_transfer
+ local_irq_save(flags);
+ LIST(cmd,hostdata->issue_queue);
+ NEXT(cmd) = hostdata->issue_queue;
+- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
++ hostdata->issue_queue = (struct scsi_cmnd *) cmd;
+ local_irq_restore(flags);
+ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+ "issue queue\n", H_NO(cmd));
+@@ -2502,7 +2507,7 @@ static void NCR5380_information_transfer
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected
+- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
++ * field to point to the struct scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
+ *
+ * Inputs : instance - this instance of the NCR5380.
+@@ -2521,7 +2526,7 @@ static void NCR5380_reselect (struct Scs
+ unsigned char tag;
+ #endif
+ unsigned char msg[3];
+- Scsi_Cmnd *tmp = NULL, *prev;
++ struct scsi_cmnd *tmp = NULL, *prev;
+ /* unsigned long flags; */
+
+ /*
+@@ -2577,7 +2582,7 @@ static void NCR5380_reselect (struct Scs
+ * just reestablished, and remove it from the disconnected queue.
+ */
+
+- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
++ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
+ tmp; prev = tmp, tmp = NEXT(tmp) ) {
+ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+ #ifdef SUPPORT_TAGS
+@@ -2668,11 +2673,11 @@ static void NCR5380_reselect (struct Scs
+
+
+ /*
+- * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
++ * Function : int NCR5380_abort(struct scsi_cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
++ * Inputs : cmd - the struct scsi_cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
+ * used.
+ *
+@@ -2684,11 +2689,11 @@ static void NCR5380_reselect (struct Scs
+ * called where the loop started in NCR5380_main().
+ */
+
+-static int NCR5380_abort (Scsi_Cmnd *cmd)
++static int NCR5380_abort(struct scsi_cmnd *cmd)
+ {
+ struct Scsi_Host *instance = cmd->device->host;
+ SETUP_HOSTDATA(instance);
+- Scsi_Cmnd *tmp, **prev;
++ struct scsi_cmnd *tmp, **prev;
+ unsigned long flags;
+
+ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+@@ -2753,9 +2758,9 @@ static int NCR5380_abort (Scsi_Cmnd *cmd
+ * Case 2 : If the command hasn't been issued yet, we simply remove it
+ * from the issue queue.
+ */
+- for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
+- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
++ for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue),
++ tmp = (struct scsi_cmnd *) hostdata->issue_queue;
++ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp))
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ (*prev) = NEXT(tmp);
+@@ -2812,7 +2817,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd
+ * it from the disconnected queue.
+ */
+
+- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
++ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
+ tmp = NEXT(tmp))
+ if (cmd == tmp) {
+ local_irq_restore(flags);
+@@ -2826,8 +2831,8 @@ static int NCR5380_abort (Scsi_Cmnd *cmd
+ do_abort (instance);
+
+ local_irq_save(flags);
+- for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
+- tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
++ for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue),
++ tmp = (struct scsi_cmnd *) hostdata->disconnected_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+@@ -2868,7 +2873,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd
+
+
+ /*
+- * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
++ * Function : int NCR5380_bus_reset(struct scsi_cmnd *cmd)
+ *
+ * Purpose : reset the SCSI bus.
+ *
+@@ -2876,13 +2881,13 @@ static int NCR5380_abort (Scsi_Cmnd *cmd
+ *
+ */
+
+-static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
++static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
+ {
+ SETUP_HOSTDATA(cmd->device->host);
+ int i;
+ unsigned long flags;
+ #if 1
+- Scsi_Cmnd *connected, *disconnected_queue;
++ struct scsi_cmnd *connected, *disconnected_queue;
+ #endif
+
+
+@@ -2914,9 +2919,9 @@ static int NCR5380_bus_reset( Scsi_Cmnd
+ * remembered in local variables first.
+ */
+ local_irq_save(flags);
+- connected = (Scsi_Cmnd *)hostdata->connected;
++ connected = (struct scsi_cmnd *)hostdata->connected;
+ hostdata->connected = NULL;
+- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
++ disconnected_queue = (struct scsi_cmnd *)hostdata->disconnected_queue;
+ hostdata->disconnected_queue = NULL;
+ #ifdef SUPPORT_TAGS
+ free_all_tags();
+diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
+index 8371734..d56d85d 100644
+--- a/drivers/scsi/sun3_scsi.c
++++ b/drivers/scsi/sun3_scsi.c
+@@ -102,7 +102,7 @@ static void NCR5380_print(struct Scsi_Ho
+ #define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
+
+
+-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
+ static inline unsigned char sun3scsi_read(int reg);
+ static inline void sun3scsi_write(int reg, int value);
+
+@@ -119,7 +119,7 @@ module_param(setup_use_tagged_queuing, i
+ static int setup_hostid = -1;
+ module_param(setup_hostid, int, 0);
+
+-static Scsi_Cmnd *sun3_dma_setup_done = NULL;
++static struct scsi_cmnd *sun3_dma_setup_done = NULL;
+
+ #define AFTER_RESET_DELAY (HZ/2)
+
+@@ -371,7 +371,7 @@ const char * sun3scsi_info (struct Scsi_
+ // safe bits for the CSR
+ #define CSR_GOOD 0x060f
+
+-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
+ {
+ unsigned short csr = dregs->csr;
+ int handled = 0;
+@@ -388,7 +388,7 @@ static irqreturn_t scsi_sun3_intr(int ir
+ }
+
+ if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
+- NCR5380_intr(irq, dummy, fp);
++ NCR5380_intr(irq, dummy);
+ handled = 1;
+ }
+
+@@ -521,10 +521,11 @@ static inline unsigned long sun3scsi_dma
+ return last_residual;
+ }
+
+-static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+- int write_flag)
++static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
++ struct scsi_cmnd *cmd,
++ int write_flag)
+ {
+- if(cmd->request->flags & REQ_CMD)
++ if(blk_fs_request(cmd->request))
+ return wanted;
+ else
+ return 0;
+diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
+index 834dab4..a1103b3 100644
+--- a/drivers/scsi/sun3_scsi.h
++++ b/drivers/scsi/sun3_scsi.h
+@@ -47,11 +47,12 @@
+
+ #define IOBASE_SUN3_VMESCSI 0xff200000
+
+-static int sun3scsi_abort (Scsi_Cmnd *);
++static int sun3scsi_abort(struct scsi_cmnd *);
+ static int sun3scsi_detect (struct scsi_host_template *);
+ static const char *sun3scsi_info (struct Scsi_Host *);
+-static int sun3scsi_bus_reset(Scsi_Cmnd *);
+-static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
++static int sun3scsi_bus_reset(struct scsi_cmnd *);
++static int sun3scsi_queue_command(struct scsi_cmnd *,
++ void (*done)(struct scsi_cmnd *));
+ static int sun3scsi_release (struct Scsi_Host *);
+
+ #ifndef CMD_PER_LUN
+diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
+index 008a82a..92def31 100644
+--- a/drivers/scsi/sun3_scsi_vme.c
++++ b/drivers/scsi/sun3_scsi_vme.c
+@@ -67,7 +67,7 @@ extern int sun3_map_test(unsigned long,
+ #define ENABLE_IRQ()
+
+
+-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
+ static inline unsigned char sun3scsi_read(int reg);
+ static inline void sun3scsi_write(int reg, int value);
+
+@@ -84,7 +84,7 @@ module_param(setup_use_tagged_queuing, i
+ static int setup_hostid = -1;
+ module_param(setup_hostid, int, 0);
+
+-static Scsi_Cmnd *sun3_dma_setup_done = NULL;
++static struct scsi_cmnd *sun3_dma_setup_done = NULL;
+
+ #define AFTER_RESET_DELAY (HZ/2)
+
+@@ -340,7 +340,7 @@ static const char * sun3scsi_info (struc
+ // safe bits for the CSR
+ #define CSR_GOOD 0x060f
+
+-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
+ {
+ unsigned short csr = dregs->csr;
+ int handled = 0;
+@@ -371,7 +371,7 @@ static irqreturn_t scsi_sun3_intr(int ir
+ }
+
+ if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
+- NCR5380_intr(irq, dummy, fp);
++ NCR5380_intr(irq, dummy);
+ handled = 1;
+ }
+
+@@ -455,10 +455,11 @@ static inline unsigned long sun3scsi_dma
+ return last_residual;
+ }
+
+-static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+- int write_flag)
++static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
++ struct scsi_cmnd *cmd,
++ int write_flag)
+ {
+- if(cmd->request->flags & REQ_CMD)
++ if(blk_fs_request(cmd->request))
+ return wanted;
+ else
+ return 0;
+diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
+index 8640253..32c883f 100644
+--- a/drivers/scsi/sym53c416.c
++++ b/drivers/scsi/sym53c416.c
+@@ -326,8 +326,7 @@ static __inline__ unsigned int sym53c416
+ return orig_len - len;
+ }
+
+-static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
+ {
+ struct Scsi_Host *dev = dev_id;
+ int base = 0;
+diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
+index 739d3ef..4d78c7e 100644
+--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
++++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
+@@ -652,7 +652,7 @@ static int sym53c8xx_queue_command(struc
+ /*
+ * Linux entry point of the interrupt handler.
+ */
+-static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t sym53c8xx_intr(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct sym_hcb *np = (struct sym_hcb *)dev_id;
+diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
+index 2df6747..0b7a70f 100644
+--- a/drivers/scsi/t128.c
++++ b/drivers/scsi/t128.c
+@@ -109,7 +109,7 @@
+ #include <asm/system.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+-#include <asm/io.h>
++#include <linux/io.h>
+ #include <linux/blkdev.h>
+ #include <linux/interrupt.h>
+ #include <linux/stat.h>
+diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
+index 9404ff3..fa5382e 100644
+--- a/drivers/scsi/tmscsim.c
++++ b/drivers/scsi/tmscsim.c
+@@ -279,6 +279,10 @@ static void dc390_ResetDevParam(struct d
+ static u32 dc390_laststatus = 0;
+ static u8 dc390_adapterCnt = 0;
+
++static int disable_clustering;
++module_param(disable_clustering, int, S_IRUGO);
++MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1");
++
+ /* Startup values, to be overriden on the commandline */
+ static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
+
+@@ -696,9 +700,9 @@ dc390_InvalidCmd(struct dc390_acb* pACB)
+
+
+ static irqreturn_t __inline__
+-DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
++DC390_Interrupt(void *dev_id)
+ {
+- struct dc390_acb *pACB = (struct dc390_acb*)dev_id;
++ struct dc390_acb *pACB = dev_id;
+ struct dc390_dcb *pDCB;
+ struct dc390_srb *pSRB;
+ u8 sstatus=0;
+@@ -807,12 +811,12 @@ DC390_Interrupt(int irq, void *dev_id, s
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
+ {
+ irqreturn_t ret;
+ DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));
+ /* Locking is done in DC390_Interrupt */
+- ret = DC390_Interrupt(irq, dev_id, regs);
++ ret = DC390_Interrupt(dev_id);
+ DEBUG1(printk (".. IRQ returned\n"));
+ return ret;
+ }
+@@ -2299,7 +2303,8 @@ static struct scsi_host_template driver_
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+- .use_clustering = DISABLE_CLUSTERING,
++ .use_clustering = ENABLE_CLUSTERING,
++ .max_sectors = 0x4000, /* 8MiB = 16 * 1024 * 512 */
+ };
+
+ /***********************************************************************
+@@ -2525,6 +2530,8 @@ static int __devinit dc390_probe_one(str
+ pci_set_master(pdev);
+
+ error = -ENOMEM;
++ if (disable_clustering)
++ driver_template.use_clustering = DISABLE_CLUSTERING;
+ shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb));
+ if (!shost)
+ goto out_disable_device;
+@@ -2660,6 +2667,10 @@ static struct pci_driver dc390_driver =
+
+ static int __init dc390_module_init(void)
+ {
++ if (!disable_clustering)
++ printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"
++ "\twith \"disable_clustering=1\" and report to maintainers\n");
++
+ if (tmscsim[0] == -1 || tmscsim[0] > 15) {
+ tmscsim[0] = 7;
+ tmscsim[1] = 4;
+diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
+index 5744961..3de08a1 100644
+--- a/drivers/scsi/u14-34f.c
++++ b/drivers/scsi/u14-34f.c
+@@ -634,7 +634,7 @@ static unsigned long io_port[] = {
+ #define H2DEV(x) cpu_to_le32(x)
+ #define DEV2H(x) le32_to_cpu(x)
+
+-static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
++static irqreturn_t do_interrupt_handler(int, void *);
+ static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int);
+ static int do_trace = FALSE;
+ static int setup_done = FALSE;
+@@ -1932,8 +1932,7 @@ none:
+ return IRQ_NONE;
+ }
+
+-static irqreturn_t do_interrupt_handler(int irq, void *shap,
+- struct pt_regs *regs) {
++static irqreturn_t do_interrupt_handler(int irq, void *shap) {
+ unsigned int j;
+ unsigned long spin_flags;
+ irqreturn_t ret;
+diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
+index e681681..56906ab 100644
+--- a/drivers/scsi/ultrastor.c
++++ b/drivers/scsi/ultrastor.c
+@@ -196,8 +196,8 @@ struct mscp {
+ u32 sense_data PACKED;
+ /* The following fields are for software only. They are included in
+ the MSCP structure because they are associated with SCSI requests. */
+- void (*done)(Scsi_Cmnd *);
+- Scsi_Cmnd *SCint;
++ void (*done) (struct scsi_cmnd *);
++ struct scsi_cmnd *SCint;
+ ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */
+ };
+
+@@ -287,9 +287,9 @@ static const unsigned short ultrastor_po
+ };
+ #endif
+
+-static void ultrastor_interrupt(int, void *, struct pt_regs *);
+-static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *);
+-static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
++static void ultrastor_interrupt(void *);
++static irqreturn_t do_ultrastor_interrupt(int, void *);
++static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt);
+
+
+ /* Always called with host lock held */
+@@ -673,7 +673,7 @@ static const char *ultrastor_info(struct
+ return buf;
+ }
+
+-static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
++static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
+ {
+ struct scatterlist *sl;
+ long transfer_length = 0;
+@@ -694,7 +694,8 @@ static inline void build_sg_list(struct
+ mscp->transfer_data_length = transfer_length;
+ }
+
+-static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
++static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
++ void (*done) (struct scsi_cmnd *))
+ {
+ struct mscp *my_mscp;
+ #if ULTRASTOR_MAX_CMDS > 1
+@@ -833,7 +834,7 @@ retry:
+
+ */
+
+-static int ultrastor_abort(Scsi_Cmnd *SCpnt)
++static int ultrastor_abort(struct scsi_cmnd *SCpnt)
+ {
+ #if ULTRASTOR_DEBUG & UD_ABORT
+ char out[108];
+@@ -843,7 +844,7 @@ static int ultrastor_abort(Scsi_Cmnd *SC
+ unsigned int mscp_index;
+ unsigned char old_aborted;
+ unsigned long flags;
+- void (*done)(Scsi_Cmnd *);
++ void (*done)(struct scsi_cmnd *);
+ struct Scsi_Host *host = SCpnt->device->host;
+
+ if(config.slot)
+@@ -892,7 +893,7 @@ static int ultrastor_abort(Scsi_Cmnd *SC
+
+ spin_lock_irqsave(host->host_lock, flags);
+ /* FIXME: Ewww... need to think about passing host around properly */
+- ultrastor_interrupt(0, NULL, NULL);
++ ultrastor_interrupt(NULL);
+ spin_unlock_irqrestore(host->host_lock, flags);
+ return SUCCESS;
+ }
+@@ -960,7 +961,7 @@ static int ultrastor_abort(Scsi_Cmnd *SC
+ return SUCCESS;
+ }
+
+-static int ultrastor_host_reset(Scsi_Cmnd * SCpnt)
++static int ultrastor_host_reset(struct scsi_cmnd * SCpnt)
+ {
+ unsigned long flags;
+ int i;
+@@ -1038,15 +1039,15 @@ int ultrastor_biosparam(struct scsi_devi
+ return 0;
+ }
+
+-static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void ultrastor_interrupt(void *dev_id)
+ {
+ unsigned int status;
+ #if ULTRASTOR_MAX_CMDS > 1
+ unsigned int mscp_index;
+ #endif
+ struct mscp *mscp;
+- void (*done)(Scsi_Cmnd *);
+- Scsi_Cmnd *SCtmp;
++ void (*done) (struct scsi_cmnd *);
++ struct scsi_cmnd *SCtmp;
+
+ #if ULTRASTOR_MAX_CMDS == 1
+ mscp = &config.mscp[0];
+@@ -1079,7 +1080,7 @@ static void ultrastor_interrupt(int irq,
+ return;
+ }
+ if (icm_status == 3) {
+- void (*done)(Scsi_Cmnd *) = mscp->done;
++ void (*done)(struct scsi_cmnd *) = mscp->done;
+ if (done) {
+ mscp->done = NULL;
+ mscp->SCint->result = DID_ABORT << 16;
+@@ -1170,14 +1171,13 @@ static void ultrastor_interrupt(int irq,
+ #endif
+ }
+
+-static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+- ultrastor_interrupt(irq, dev_id, regs);
++ ultrastor_interrupt(dev_id);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
+index da759a1..a692905 100644
+--- a/drivers/scsi/ultrastor.h
++++ b/drivers/scsi/ultrastor.h
+@@ -14,11 +14,13 @@
+ #define _ULTRASTOR_H
+
+ static int ultrastor_detect(struct scsi_host_template *);
+-static const char *ultrastor_info(struct Scsi_Host * shpnt);
+-static int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-static int ultrastor_abort(Scsi_Cmnd *);
+-static int ultrastor_host_reset(Scsi_Cmnd *);
+-static int ultrastor_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
++static const char *ultrastor_info(struct Scsi_Host *shpnt);
++static int ultrastor_queuecommand(struct scsi_cmnd *,
++ void (*done)(struct scsi_cmnd *));
++static int ultrastor_abort(struct scsi_cmnd *);
++static int ultrastor_host_reset(struct scsi_cmnd *);
++static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
++ sector_t, int *);
+
+
+ #define ULTRASTOR_14F_MAX_SG 16
+diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
+index a0b61af..30be765 100644
+--- a/drivers/scsi/wd7000.c
++++ b/drivers/scsi/wd7000.c
+@@ -178,10 +178,10 @@
+ #include <linux/blkdev.h>
+ #include <linux/init.h>
+ #include <linux/stat.h>
++#include <linux/io.h>
+
+ #include <asm/system.h>
+ #include <asm/dma.h>
+-#include <asm/io.h>
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -998,7 +998,7 @@ static int make_code(unsigned hosterr, u
+ #define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
+
+
+-static irqreturn_t wd7000_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t wd7000_intr(int irq, void *dev_id)
+ {
+ Adapter *host = (Adapter *) dev_id;
+ int flag, icmb, errstatus, icmb_status;
+diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
+index 5743832..6a1a568 100644
+--- a/drivers/serial/21285.c
++++ b/drivers/serial/21285.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/char/21285.c
++ * linux/drivers/serial/21285.c
+ *
+ * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
+ *
+@@ -85,7 +85,7 @@ static void serial21285_enable_ms(struct
+ {
+ }
+
+-static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
+ {
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = port->info->tty;
+@@ -123,7 +123,7 @@ static irqreturn_t serial21285_rx_chars(
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
+ {
+ struct uart_port *port = dev_id;
+ struct circ_buf *xmit = &port->info->xmit;
+diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
+index 993a702..9b8b585 100644
+--- a/drivers/serial/68328serial.c
++++ b/drivers/serial/68328serial.c
+@@ -275,8 +275,7 @@ static void status_handle(struct m68k_se
+ return;
+ }
+
+-static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
+- unsigned short rx)
++static void receive_chars(struct m68k_serial *info, unsigned short rx)
+ {
+ struct tty_struct *tty = info->tty;
+ m68328_uart *uart = &uart_addr[info->line];
+@@ -377,7 +376,7 @@ clear_and_return:
+ /*
+ * This is the serial driver's generic interrupt routine
+ */
+-irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++irqreturn_t rs_interrupt(int irq, void *dev_id)
+ {
+ struct m68k_serial * info;
+ m68328_uart *uart;
+@@ -394,10 +393,10 @@ irqreturn_t rs_interrupt(int irq, void *
+ #ifdef USE_INTS
+ tx = uart->utx.w;
+
+- if (rx & URX_DATA_READY) receive_chars(info, regs, rx);
++ if (rx & URX_DATA_READY) receive_chars(info, rx);
+ if (tx & UTX_TX_AVAIL) transmit_chars(info);
+ #else
+- receive_chars(info, regs, rx);
++ receive_chars(info, rx);
+ #endif
+ return IRQ_HANDLED;
+ }
+@@ -1378,7 +1377,7 @@ void startup_console(void)
+ #endif /* CONFIG_PM_LEGACY */
+
+
+-static struct tty_operations rs_ops = {
++static const struct tty_operations rs_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
+index e80e70e..634ecca 100644
+--- a/drivers/serial/68360serial.c
++++ b/drivers/serial/68360serial.c
+@@ -612,7 +612,7 @@ static _INLINE_ void check_modem_status(
+ * This is the serial driver's interrupt routine for a single port
+ */
+ /* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
+-static void rs_360_interrupt(int vec, void *dev_id, struct pt_regs *fp)
++static void rs_360_interrupt(int vec, void *dev_id)
+ {
+ u_char events;
+ int idx;
+@@ -620,7 +620,7 @@ static void rs_360_interrupt(int vec, vo
+ volatile struct smc_regs *smcp;
+ volatile struct scc_regs *sccp;
+
+- info = (ser_info_t *)dev_id;
++ info = dev_id;
+
+ idx = PORT_NUM(info->state->smc_scc_num);
+ if (info->state->smc_scc_num & NUM_IS_SCC) {
+@@ -2424,7 +2424,7 @@ long console_360_init(long kmem_start, l
+ */
+ static int baud_idx;
+
+-static struct tty_operations rs_360_ops = {
++static const struct tty_operations rs_360_ops = {
+ .owner = THIS_MODULE,
+ .open = rs_360_open,
+ .close = rs_360_close,
+diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
+index 0ae9ced..e34bd03 100644
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -320,8 +320,8 @@ static unsigned int serial_in(struct uar
+
+ case UPIO_TSI:
+ if (offset == UART_IIR) {
+- tmp = readl((u32 *)(up->port.membase + UART_RX));
+- return (cpu_to_le32(tmp) >> 8) & 0xff;
++ tmp = readl(up->port.membase + (UART_IIR & ~3));
++ return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+ } else
+ return readb(up->port.membase + offset);
+
+@@ -1175,7 +1175,7 @@ static void serial8250_enable_ms(struct
+ }
+
+ static void
+-receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
++receive_chars(struct uart_8250_port *up, int *status)
+ {
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned char ch, lsr = *status;
+@@ -1233,7 +1233,7 @@ receive_chars(struct uart_8250_port *up,
+ else if (lsr & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ goto ignore_char;
+
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+@@ -1309,7 +1309,7 @@ static unsigned int check_modem_status(s
+ * This handles the interrupt from one port.
+ */
+ static inline void
+-serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
++serial8250_handle_port(struct uart_8250_port *up)
+ {
+ unsigned int status;
+
+@@ -1320,7 +1320,7 @@ serial8250_handle_port(struct uart_8250_
+ DEBUG_INTR("status = %x...", status);
+
+ if (status & UART_LSR_DR)
+- receive_chars(up, &status, regs);
++ receive_chars(up, &status);
+ check_modem_status(up);
+ if (status & UART_LSR_THRE)
+ transmit_chars(up);
+@@ -1342,7 +1342,7 @@ serial8250_handle_port(struct uart_8250_
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+-static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
+ {
+ struct irq_info *i = dev_id;
+ struct list_head *l, *end = NULL;
+@@ -1361,7 +1361,7 @@ static irqreturn_t serial8250_interrupt(
+
+ iir = serial_in(up, UART_IIR);
+ if (!(iir & UART_IIR_NO_INT)) {
+- serial8250_handle_port(up, regs);
++ serial8250_handle_port(up);
+
+ handled = 1;
+
+@@ -1461,7 +1461,7 @@ static void serial8250_timeout(unsigned
+
+ iir = serial_in(up, UART_IIR);
+ if (!(iir & UART_IIR_NO_INT))
+- serial8250_handle_port(up, NULL);
++ serial8250_handle_port(up);
+
+ timeout = up->port.timeout;
+ timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+@@ -1896,6 +1896,17 @@ serial8250_set_termios(struct uart_port
+ serial_outp(up, UART_EFR, efr);
+ }
+
++#ifdef CONFIG_ARCH_OMAP15XX
++ /* Workaround to enable 115200 baud on OMAP1510 internal ports */
++ if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
++ if (baud == 115200) {
++ quot = 1;
++ serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
++ } else
++ serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
++ }
++#endif
++
+ if (up->capabilities & UART_NATSEMI) {
+ /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
+ serial_outp(up, UART_LCR, 0xe0);
+@@ -1949,6 +1960,8 @@ static int serial8250_request_std_resour
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
++ case UPIO_TSI:
++ case UPIO_MEM32:
+ case UPIO_MEM:
+ if (!up->port.mapbase)
+ break;
+@@ -1984,6 +1997,8 @@ static void serial8250_release_std_resou
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
++ case UPIO_TSI:
++ case UPIO_MEM32:
+ case UPIO_MEM:
+ if (!up->port.mapbase)
+ break;
+@@ -2007,17 +2022,15 @@ static int serial8250_request_rsa_resour
+ {
+ unsigned long start = UART_RSA_BASE << up->port.regshift;
+ unsigned int size = 8 << up->port.regshift;
+- int ret = 0;
++ int ret = -EINVAL;
+
+ switch (up->port.iotype) {
+- case UPIO_MEM:
+- ret = -EINVAL;
+- break;
+-
+ case UPIO_HUB6:
+ case UPIO_PORT:
+ start += up->port.iobase;
+- if (!request_region(start, size, "serial-rsa"))
++ if (request_region(start, size, "serial-rsa"))
++ ret = 0;
++ else
+ ret = -EBUSY;
+ break;
+ }
+@@ -2031,9 +2044,6 @@ static void serial8250_release_rsa_resou
+ unsigned int size = 8 << up->port.regshift;
+
+ switch (up->port.iotype) {
+- case UPIO_MEM:
+- break;
+-
+ case UPIO_HUB6:
+ case UPIO_PORT:
+ release_region(up->port.iobase + offset, size);
+@@ -2222,9 +2232,10 @@ static inline void wait_for_xmitr(struct
+ /* Wait up to 1s for flow control if necessary */
+ if (up->port.flags & UPF_CONS_FLOW) {
+ tmout = 1000000;
+- while (--tmout &&
+- ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
++ while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
+ udelay(1);
++ touch_nmi_watchdog();
++ }
+ }
+ }
+
+@@ -2397,7 +2408,6 @@ int __init early_serial_setup(struct uar
+ /**
+ * serial8250_suspend_port - suspend one serial port
+ * @line: serial line number
+- * @level: the level of port suspension, as per uart_suspend_port
+ *
+ * Suspend one serial port.
+ */
+@@ -2409,7 +2419,6 @@ void serial8250_suspend_port(int line)
+ /**
+ * serial8250_resume_port - resume one serial port
+ * @line: serial line number
+- * @level: the level of port resumption, as per uart_resume_port
+ *
+ * Resume one serial port.
+ */
+diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
+index 32af365..ef8cc8a 100644
+--- a/drivers/serial/8250_acorn.c
++++ b/drivers/serial/8250_acorn.c
+@@ -35,6 +35,7 @@ struct serial_card_type {
+ struct serial_card_info {
+ unsigned int num_ports;
+ int ports[MAX_PORTS];
++ void __iomem *vaddr;
+ };
+
+ static int __devinit
+@@ -44,7 +45,6 @@ serial_card_probe(struct expansion_card
+ struct serial_card_type *type = id->data;
+ struct uart_port port;
+ unsigned long bus_addr;
+- unsigned char __iomem *virt_addr;
+ unsigned int i;
+
+ info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL);
+@@ -55,8 +55,8 @@ serial_card_probe(struct expansion_card
+ info->num_ports = type->num_ports;
+
+ bus_addr = ecard_resource_start(ec, type->type);
+- virt_addr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
+- if (!virt_addr) {
++ info->vaddr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
++ if (!info->vaddr) {
+ kfree(info);
+ return -ENOMEM;
+ }
+@@ -72,7 +72,7 @@ serial_card_probe(struct expansion_card
+ port.dev = &ec->dev;
+
+ for (i = 0; i < info->num_ports; i ++) {
+- port.membase = virt_addr + type->offset[i];
++ port.membase = info->vaddr + type->offset[i];
+ port.mapbase = bus_addr + type->offset[i];
+
+ info->ports[i] = serial8250_register_port(&port);
+@@ -92,6 +92,7 @@ static void __devexit serial_card_remove
+ if (info->ports[i] > 0)
+ serial8250_unregister_port(info->ports[i]);
+
++ iounmap(info->vaddr);
+ kfree(info);
+ }
+
+diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
+index 913c71c..c5d0add 100644
+--- a/drivers/serial/8250_gsc.c
++++ b/drivers/serial/8250_gsc.c
+@@ -22,7 +22,6 @@
+ #include <asm/hardware.h>
+ #include <asm/parisc-device.h>
+ #include <asm/io.h>
+-#include <asm/serial.h> /* for LASI_BASE_BAUD */
+
+ #include "8250.h"
+
+@@ -54,7 +53,8 @@ serial_init_chip(struct parisc_device *d
+
+ memset(&port, 0, sizeof(port));
+ port.iotype = UPIO_MEM;
+- port.uartclk = LASI_BASE_BAUD * 16;
++ /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
++ port.uartclk = 7272727;
+ port.mapbase = address;
+ port.membase = ioremap_nocache(address, 16);
+ port.irq = dev->irq;
+@@ -64,6 +64,7 @@ serial_init_chip(struct parisc_device *d
+ err = serial8250_register_port(&port);
+ if (err < 0) {
+ printk(KERN_WARNING "serial8250_register_port returned error %d\n", err);
++ iounmap(port.membase);
+ return err;
+ }
+
+diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
+index 851e483..4d0ff8f 100644
+--- a/drivers/serial/8250_pci.c
++++ b/drivers/serial/8250_pci.c
+@@ -1789,6 +1789,7 @@ static void __devexit pciserial_remove_o
+ pci_disable_device(dev);
+ }
+
++#ifdef CONFIG_PM
+ static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
+ {
+ struct serial_private *priv = pci_get_drvdata(dev);
+@@ -1818,6 +1819,7 @@ static int pciserial_resume_one(struct p
+ }
+ return 0;
+ }
++#endif
+
+ static struct pci_device_id serial_pci_tbl[] = {
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+@@ -2375,8 +2377,10 @@ static struct pci_driver serial_pci_driv
+ .name = "serial",
+ .probe = pciserial_init_one,
+ .remove = __devexit_p(pciserial_remove_one),
++#ifdef CONFIG_PM
+ .suspend = pciserial_suspend_one,
+ .resume = pciserial_resume_one,
++#endif
+ .id_table = serial_pci_tbl,
+ };
+
+diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
+index 632f62d..71d907c 100644
+--- a/drivers/serial/8250_pnp.c
++++ b/drivers/serial/8250_pnp.c
+@@ -327,6 +327,19 @@ static const struct pnp_device_id pnp_de
+ { "WACF004", 0 },
+ { "WACF005", 0 },
+ { "WACF006", 0 },
++ /* Compaq touchscreen */
++ { "FPI2002", 0 },
++ /* Fujitsu Stylistic touchscreens */
++ { "FUJ02B2", 0 },
++ { "FUJ02B3", 0 },
++ /* Fujitsu Stylistic LT touchscreens */
++ { "FUJ02B4", 0 },
++ /* Passive Fujitsu Stylistic touchscreens */
++ { "FUJ02B6", 0 },
++ { "FUJ02B7", 0 },
++ { "FUJ02B8", 0 },
++ { "FUJ02B9", 0 },
++ { "FUJ02BC", 0 },
+ /* Rockwell's (PORALiNK) 33600 INT PNP */
+ { "WCI0003", 0 },
+ /* Unkown PnP modems */
+diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
+index 5b48ac2..0b71e7d 100644
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -121,7 +121,7 @@ config SERIAL_8250_RUNTIME_UARTS
+ default "4"
+ help
+ Set this to the maximum number of serial ports you want
+- the kernel to register at boot time. This can be overriden
++ the kernel to register at boot time. This can be overridden
+ with the module parameter "nr_uarts", or boot-time parameter
+ 8250.nr_uarts
+
+@@ -205,7 +205,7 @@ config SERIAL_8250_BOCA
+ 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>
++ mini-HOWTO, available 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.
+@@ -295,37 +295,37 @@ config SERIAL_AMBA_PL011_CONSOLE
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+- "console=ttyAM0". (Try "man bootparam" or see the documentation of
++ "console=ttyAMA0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+-config SERIAL_AT91
+- bool "AT91RM9200 / AT91SAM9261 serial port support"
+- depends on ARM && (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
++config SERIAL_ATMEL
++ bool "AT91 / AT32 on-chip serial port support"
++ depends on (ARM && ARCH_AT91) || AVR32
+ select SERIAL_CORE
+ help
+ This enables the driver for the on-chip UARTs of the Atmel
+- AT91RM9200 and AT91SAM926 processor.
++ AT91 and AT32 processors.
+
+-config SERIAL_AT91_CONSOLE
+- bool "Support for console on AT91RM9200 / AT91SAM9261 serial port"
+- depends on SERIAL_AT91=y
++config SERIAL_ATMEL_CONSOLE
++ bool "Support for console on AT91 / AT32 serial port"
++ depends on SERIAL_ATMEL=y
+ select SERIAL_CORE_CONSOLE
+ help
+- Say Y here if you wish to use a UART on the Atmel AT91RM9200 or
+- AT91SAM9261 as the system console (the system console is the device
+- which receives all kernel messages and warnings and which allows
+- logins in single user mode).
++ Say Y here if you wish to use an on-chip UART on a Atmel
++ AT91 or AT32 processor as the system console (the system
++ console is the device which receives all kernel messages and
++ warnings and which allows logins in single user mode).
+
+-config SERIAL_AT91_TTYAT
+- bool "Install as device ttyAT0-4 instead of ttyS0-4"
+- depends on SERIAL_AT91=y
++config SERIAL_ATMEL_TTYAT
++ bool "Install as device ttyATn instead of ttySn"
++ depends on SERIAL_ATMEL=y
+ help
+- Say Y here if you wish to have the five internal AT91RM9200 UARTs
+- appear as /dev/ttyAT0-4 (major 204, minor 154-158) instead of the
+- normal /dev/ttyS0-4 (major 4, minor 64-68). This is necessary if
+- you also want other UARTs, such as external 8250/16C550 compatible
+- UARTs.
++ Say Y here if you wish to have the internal AT91 / AT32 UARTs
++ appear as /dev/ttyATn (major 204, minor starting at 154)
++ instead of the normal /dev/ttySn (major 4, minor starting at
++ 64). This is necessary if you also want other UARTs, such as
++ external 8250/16C550 compatible UARTs.
+ The ttySn nodes are legally reserved for the 8250 serial driver
+ but are often misused by other serial drivers.
+
+@@ -556,10 +556,11 @@ config SERIAL_MUX
+ default y
+ ---help---
+ Saying Y here will enable the hardware MUX serial driver for
+- the Nova and K class systems. The hardware MUX is not 8250/16550
+- compatible therefore the /dev/ttyB0 device is shared between the
+- Serial MUX and the PDC software console. The following steps
+- need to be completed to use the Serial MUX:
++ the Nova, K class systems and D class with a 'remote control card'.
++ The hardware MUX is not 8250/16550 compatible therefore the
++ /dev/ttyB0 device is shared between the Serial MUX and the PDC
++ software console. The following steps need to be completed to use
++ the Serial MUX:
+
+ 1. create the device entry (mknod /dev/ttyB0 c 11 0)
+ 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+@@ -642,12 +643,17 @@ config V850E_UART_CONSOLE
+ select SERIAL_CORE_CONSOLE
+
+ config SERIAL_SH_SCI
+- tristate "SH SCI(F) serial port support"
++ tristate "SuperH SCI(F) serial port support"
+ depends on SUPERH || H8300
+ select SERIAL_CORE
+
++config SERIAL_SH_SCI_NR_UARTS
++ int "Maximum number of SCI(F) serial ports"
++ depends on SERIAL_SH_SCI
++ default "2"
++
+ config SERIAL_SH_SCI_CONSOLE
+- bool "Support for console on SH SCI(F)"
++ bool "Support for console on SuperH SCI(F)"
+ depends on SERIAL_SH_SCI=y
+ select SERIAL_CORE_CONSOLE
+
+@@ -662,7 +668,7 @@ config SERIAL_68328
+ depends on M68328 || M68EZ328 || M68VZ328
+ help
+ This driver supports the built-in serial port of the Motorola 68328
+- (standard, EZ and VZ varities).
++ (standard, EZ and VZ varieties).
+
+ config SERIAL_68328_RTS_CTS
+ bool "Support RTS/CTS on 68328 serial port"
+@@ -761,37 +767,37 @@ config SERIAL_CPM_SCC1
+ bool "Support for SCC1 serial port"
+ depends on SERIAL_CPM=y
+ help
+- Select the is option to use SCC1 as a serial port
++ Select this option to use SCC1 as a serial port
+
+ config SERIAL_CPM_SCC2
+ bool "Support for SCC2 serial port"
+ depends on SERIAL_CPM=y
+ help
+- Select the is option to use SCC2 as a serial port
++ Select this option to use SCC2 as a serial port
+
+ config SERIAL_CPM_SCC3
+ bool "Support for SCC3 serial port"
+ depends on SERIAL_CPM=y
+ help
+- Select the is option to use SCC3 as a serial port
++ Select this option to use SCC3 as a serial port
+
+ config SERIAL_CPM_SCC4
+ bool "Support for SCC4 serial port"
+ depends on SERIAL_CPM=y
+ help
+- Select the is option to use SCC4 as a serial port
++ Select this option to use SCC4 as a serial port
+
+ config SERIAL_CPM_SMC1
+ bool "Support for SMC1 serial port"
+ depends on SERIAL_CPM=y
+ help
+- Select the is option to use SMC1 as a serial port
++ Select this option to use SMC1 as a serial port
+
+ config SERIAL_CPM_SMC2
+ bool "Support for SMC2 serial port"
+ depends on SERIAL_CPM=y
+ help
+- Select the is option to use SMC2 as a serial port
++ Select this option to use SMC2 as a serial port
+
+ config SERIAL_SGI_L1_CONSOLE
+ bool "SGI Altix L1 serial console support"
+diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
+index 927faee..b4d8a7c 100644
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -54,5 +54,5 @@ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9
+ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
+ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
+-obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
++obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
+ obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
+index 7311d84..4213fab 100644
+--- a/drivers/serial/amba-pl010.c
++++ b/drivers/serial/amba-pl010.c
+@@ -111,12 +111,7 @@ static void pl010_enable_ms(struct uart_
+ writel(cr, port->membase + UART010_CR);
+ }
+
+-static void
+-#ifdef SUPPORT_SYSRQ
+-pl010_rx_chars(struct uart_port *port, struct pt_regs *regs)
+-#else
+-pl010_rx_chars(struct uart_port *port)
+-#endif
++static void pl010_rx_chars(struct uart_port *port)
+ {
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, flag, rsr, max_count = 256;
+@@ -156,7 +151,7 @@ pl010_rx_chars(struct uart_port *port)
+ flag = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char(port, ch, regs))
++ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
+@@ -227,7 +222,7 @@ static void pl010_modem_status(struct ua
+ wake_up_interruptible(&uap->port.info->delta_msr_wait);
+ }
+
+-static irqreturn_t pl010_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pl010_int(int irq, void *dev_id)
+ {
+ struct uart_port *port = dev_id;
+ unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+@@ -239,11 +234,7 @@ static irqreturn_t pl010_int(int irq, vo
+ if (status) {
+ do {
+ if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
+-#ifdef SUPPORT_SYSRQ
+- pl010_rx_chars(port, regs);
+-#else
+ pl010_rx_chars(port);
+-#endif
+ if (status & UART010_IIR_MIS)
+ pl010_modem_status(port);
+ if (status & UART010_IIR_TIS)
+diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
+index a8d7124..d503625 100644
+--- a/drivers/serial/amba-pl011.c
++++ b/drivers/serial/amba-pl011.c
+@@ -107,12 +107,7 @@ static void pl011_enable_ms(struct uart_
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
+
+-static void
+-#ifdef SUPPORT_SYSRQ
+-pl011_rx_chars(struct uart_amba_port *uap, struct pt_regs *regs)
+-#else
+-pl011_rx_chars(struct uart_amba_port *uap)
+-#endif
++static void pl011_rx_chars(struct uart_amba_port *uap)
+ {
+ struct tty_struct *tty = uap->port.info->tty;
+ unsigned int status, ch, flag, max_count = 256;
+@@ -150,7 +145,7 @@ pl011_rx_chars(struct uart_amba_port *ua
+ flag = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char(&uap->port, ch & 255, regs))
++ if (uart_handle_sysrq_char(&uap->port, ch & 255))
+ goto ignore_char;
+
+ uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+@@ -218,7 +213,7 @@ static void pl011_modem_status(struct ua
+ wake_up_interruptible(&uap->port.info->delta_msr_wait);
+ }
+
+-static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pl011_int(int irq, void *dev_id)
+ {
+ struct uart_amba_port *uap = dev_id;
+ unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+@@ -234,11 +229,7 @@ static irqreturn_t pl011_int(int irq, vo
+ uap->port.membase + UART011_ICR);
+
+ if (status & (UART011_RTIS|UART011_RXIS))
+-#ifdef SUPPORT_SYSRQ
+- pl011_rx_chars(uap, regs);
+-#else
+ pl011_rx_chars(uap);
+-#endif
+ if (status & (UART011_DSRMIS|UART011_DCDMIS|
+ UART011_CTSMIS|UART011_RIMIS))
+ pl011_modem_status(uap);
+diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c
+deleted file mode 100644
+index 54c6b2a..0000000
+--- a/drivers/serial/at91_serial.c
++++ /dev/null
+@@ -1,980 +0,0 @@
+-/*
+- * linux/drivers/char/at91_serial.c
+- *
+- * Driver for Atmel AT91RM9200 Serial ports
+- * Copyright (C) 2003 Rick Bronson
+- *
+- * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
+- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+- *
+- * 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/tty.h>
+-#include <linux/ioport.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/serial.h>
+-#include <linux/clk.h>
+-#include <linux/console.h>
+-#include <linux/sysrq.h>
+-#include <linux/tty_flip.h>
+-#include <linux/platform_device.h>
+-
+-#include <asm/io.h>
+-
+-#include <asm/arch/at91rm9200_usart.h>
+-#include <asm/arch/at91rm9200_pdc.h>
+-#include <asm/mach/serial_at91.h>
+-#include <asm/arch/board.h>
+-#include <asm/arch/system.h>
+-#include <asm/arch/gpio.h>
+-
+-#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+-#define SUPPORT_SYSRQ
+-#endif
+-
+-#include <linux/serial_core.h>
+-
+-#ifdef CONFIG_SERIAL_AT91_TTYAT
+-
+-/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
+- * should coexist with the 8250 driver, such as if we have an external 16C550
+- * UART. */
+-#define SERIAL_AT91_MAJOR 204
+-#define MINOR_START 154
+-#define AT91_DEVICENAME "ttyAT"
+-
+-#else
+-
+-/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port
+- * name, but it is legally reserved for the 8250 driver. */
+-#define SERIAL_AT91_MAJOR TTY_MAJOR
+-#define MINOR_START 64
+-#define AT91_DEVICENAME "ttyS"
+-
+-#endif
+-
+-#define AT91_ISR_PASS_LIMIT 256
+-
+-#define UART_PUT_CR(port,v) writel(v, (port)->membase + AT91_US_CR)
+-#define UART_GET_MR(port) readl((port)->membase + AT91_US_MR)
+-#define UART_PUT_MR(port,v) writel(v, (port)->membase + AT91_US_MR)
+-#define UART_PUT_IER(port,v) writel(v, (port)->membase + AT91_US_IER)
+-#define UART_PUT_IDR(port,v) writel(v, (port)->membase + AT91_US_IDR)
+-#define UART_GET_IMR(port) readl((port)->membase + AT91_US_IMR)
+-#define UART_GET_CSR(port) readl((port)->membase + AT91_US_CSR)
+-#define UART_GET_CHAR(port) readl((port)->membase + AT91_US_RHR)
+-#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + AT91_US_THR)
+-#define UART_GET_BRGR(port) readl((port)->membase + AT91_US_BRGR)
+-#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + AT91_US_BRGR)
+-#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + AT91_US_RTOR)
+-
+-// #define UART_GET_CR(port) readl((port)->membase + AT91_US_CR) // is write-only
+-
+- /* PDC registers */
+-#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + AT91_PDC_PTCR)
+-#define UART_GET_PTSR(port) readl((port)->membase + AT91_PDC_PTSR)
+-
+-#define UART_PUT_RPR(port,v) writel(v, (port)->membase + AT91_PDC_RPR)
+-#define UART_GET_RPR(port) readl((port)->membase + AT91_PDC_RPR)
+-#define UART_PUT_RCR(port,v) writel(v, (port)->membase + AT91_PDC_RCR)
+-#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + AT91_PDC_RNPR)
+-#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + AT91_PDC_RNCR)
+-
+-#define UART_PUT_TPR(port,v) writel(v, (port)->membase + AT91_PDC_TPR)
+-#define UART_PUT_TCR(port,v) writel(v, (port)->membase + AT91_PDC_TCR)
+-//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + AT91_PDC_TNPR)
+-//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + AT91_PDC_TNCR)
+-
+-static int (*at91_open)(struct uart_port *);
+-static void (*at91_close)(struct uart_port *);
+-
+-/*
+- * We wrap our port structure around the generic uart_port.
+- */
+-struct at91_uart_port {
+- struct uart_port uart; /* uart */
+- struct clk *clk; /* uart clock */
+- unsigned short suspended; /* is port suspended? */
+-};
+-
+-static struct at91_uart_port at91_ports[AT91_NR_UART];
+-
+-#ifdef SUPPORT_SYSRQ
+-static struct console at91_console;
+-#endif
+-
+-/*
+- * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
+- */
+-static u_int at91_tx_empty(struct uart_port *port)
+-{
+- return (UART_GET_CSR(port) & AT91_US_TXEMPTY) ? TIOCSER_TEMT : 0;
+-}
+-
+-/*
+- * Set state of the modem control output lines
+- */
+-static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
+-{
+- unsigned int control = 0;
+- unsigned int mode;
+-
+- if (arch_identify() == ARCH_ID_AT91RM9200) {
+- /*
+- * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
+- * We need to drive the pin manually.
+- */
+- if (port->mapbase == AT91_BASE_US0) {
+- if (mctrl & TIOCM_RTS)
+- at91_set_gpio_value(AT91_PIN_PA21, 0);
+- else
+- at91_set_gpio_value(AT91_PIN_PA21, 1);
+- }
+- }
+-
+- if (mctrl & TIOCM_RTS)
+- control |= AT91_US_RTSEN;
+- else
+- control |= AT91_US_RTSDIS;
+-
+- if (mctrl & TIOCM_DTR)
+- control |= AT91_US_DTREN;
+- else
+- control |= AT91_US_DTRDIS;
+-
+- UART_PUT_CR(port, control);
+-
+- /* Local loopback mode? */
+- mode = UART_GET_MR(port) & ~AT91_US_CHMODE;
+- if (mctrl & TIOCM_LOOP)
+- mode |= AT91_US_CHMODE_LOC_LOOP;
+- else
+- mode |= AT91_US_CHMODE_NORMAL;
+- UART_PUT_MR(port, mode);
+-}
+-
+-/*
+- * Get state of the modem control input lines
+- */
+-static u_int at91_get_mctrl(struct uart_port *port)
+-{
+- unsigned int status, ret = 0;
+-
+- status = UART_GET_CSR(port);
+-
+- /*
+- * The control signals are active low.
+- */
+- if (!(status & AT91_US_DCD))
+- ret |= TIOCM_CD;
+- if (!(status & AT91_US_CTS))
+- ret |= TIOCM_CTS;
+- if (!(status & AT91_US_DSR))
+- ret |= TIOCM_DSR;
+- if (!(status & AT91_US_RI))
+- ret |= TIOCM_RI;
+-
+- return ret;
+-}
+-
+-/*
+- * Stop transmitting.
+- */
+-static void at91_stop_tx(struct uart_port *port)
+-{
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- UART_PUT_IDR(port, AT91_US_TXRDY);
+-}
+-
+-/*
+- * Start transmitting.
+- */
+-static void at91_start_tx(struct uart_port *port)
+-{
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- UART_PUT_IER(port, AT91_US_TXRDY);
+-}
+-
+-/*
+- * Stop receiving - port is in process of being closed.
+- */
+-static void at91_stop_rx(struct uart_port *port)
+-{
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- UART_PUT_IDR(port, AT91_US_RXRDY);
+-}
+-
+-/*
+- * Enable modem status interrupts
+- */
+-static void at91_enable_ms(struct uart_port *port)
+-{
+- UART_PUT_IER(port, AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC);
+-}
+-
+-/*
+- * Control the transmission of a break signal
+- */
+-static void at91_break_ctl(struct uart_port *port, int break_state)
+-{
+- if (break_state != 0)
+- UART_PUT_CR(port, AT91_US_STTBRK); /* start break */
+- else
+- UART_PUT_CR(port, AT91_US_STPBRK); /* stop break */
+-}
+-
+-/*
+- * Characters received (called from interrupt handler)
+- */
+-static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs)
+-{
+- struct tty_struct *tty = port->info->tty;
+- unsigned int status, ch, flg;
+-
+- status = UART_GET_CSR(port);
+- while (status & AT91_US_RXRDY) {
+- ch = UART_GET_CHAR(port);
+-
+- port->icount.rx++;
+-
+- flg = TTY_NORMAL;
+-
+- /*
+- * note that the error handling code is
+- * out of the main execution path
+- */
+- if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE | AT91_US_RXBRK))) {
+- UART_PUT_CR(port, AT91_US_RSTSTA); /* clear error */
+- if (status & AT91_US_RXBRK) {
+- status &= ~(AT91_US_PARE | AT91_US_FRAME); /* ignore side-effect */
+- port->icount.brk++;
+- if (uart_handle_break(port))
+- goto ignore_char;
+- }
+- if (status & AT91_US_PARE)
+- port->icount.parity++;
+- if (status & AT91_US_FRAME)
+- port->icount.frame++;
+- if (status & AT91_US_OVRE)
+- port->icount.overrun++;
+-
+- status &= port->read_status_mask;
+-
+- if (status & AT91_US_RXBRK)
+- flg = TTY_BREAK;
+- else if (status & AT91_US_PARE)
+- flg = TTY_PARITY;
+- else if (status & AT91_US_FRAME)
+- flg = TTY_FRAME;
+- }
+-
+- if (uart_handle_sysrq_char(port, ch, regs))
+- goto ignore_char;
+-
+- uart_insert_char(port, status, AT91_US_OVRE, ch, flg);
+-
+- ignore_char:
+- status = UART_GET_CSR(port);
+- }
+-
+- tty_flip_buffer_push(tty);
+-}
+-
+-/*
+- * Transmit characters (called from interrupt handler)
+- */
+-static void at91_tx_chars(struct uart_port *port)
+-{
+- struct circ_buf *xmit = &port->info->xmit;
+-
+- if (port->x_char) {
+- UART_PUT_CHAR(port, port->x_char);
+- port->icount.tx++;
+- port->x_char = 0;
+- return;
+- }
+- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+- at91_stop_tx(port);
+- return;
+- }
+-
+- while (UART_GET_CSR(port) & AT91_US_TXRDY) {
+- UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+- port->icount.tx++;
+- if (uart_circ_empty(xmit))
+- break;
+- }
+-
+- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+- uart_write_wakeup(port);
+-
+- if (uart_circ_empty(xmit))
+- at91_stop_tx(port);
+-}
+-
+-/*
+- * Interrupt handler
+- */
+-static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct uart_port *port = dev_id;
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+- unsigned int status, pending, pass_counter = 0;
+-
+- status = UART_GET_CSR(port);
+- pending = status & UART_GET_IMR(port);
+- while (pending) {
+- /* Interrupt receive */
+- if (pending & AT91_US_RXRDY)
+- at91_rx_chars(port, regs);
+-
+- // TODO: All reads to CSR will clear these interrupts!
+- if (pending & AT91_US_RIIC) port->icount.rng++;
+- if (pending & AT91_US_DSRIC) port->icount.dsr++;
+- if (pending & AT91_US_DCDIC)
+- uart_handle_dcd_change(port, !(status & AT91_US_DCD));
+- if (pending & AT91_US_CTSIC)
+- uart_handle_cts_change(port, !(status & AT91_US_CTS));
+- if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC))
+- wake_up_interruptible(&port->info->delta_msr_wait);
+-
+- /* Interrupt transmit */
+- if (pending & AT91_US_TXRDY)
+- at91_tx_chars(port);
+-
+- if (pass_counter++ > AT91_ISR_PASS_LIMIT)
+- break;
+-
+- status = UART_GET_CSR(port);
+- pending = status & UART_GET_IMR(port);
+- }
+- return IRQ_HANDLED;
+-}
+-
+-/*
+- * Perform initialization and enable port for reception
+- */
+-static int at91_startup(struct uart_port *port)
+-{
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+- int retval;
+-
+- /*
+- * Ensure that no interrupts are enabled otherwise when
+- * request_irq() is called we could get stuck trying to
+- * handle an unexpected interrupt
+- */
+- UART_PUT_IDR(port, -1);
+-
+- /*
+- * Allocate the IRQ
+- */
+- retval = request_irq(port->irq, at91_interrupt, IRQF_SHARED, "at91_serial", port);
+- if (retval) {
+- printk("at91_serial: at91_startup - Can't get irq\n");
+- return retval;
+- }
+-
+- /*
+- * If there is a specific "open" function (to register
+- * control line interrupts)
+- */
+- if (at91_open) {
+- retval = at91_open(port);
+- if (retval) {
+- free_irq(port->irq, port);
+- return retval;
+- }
+- }
+-
+- /*
+- * Finally, enable the serial port
+- */
+- UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
+- UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); /* enable xmit & rcvr */
+-
+- UART_PUT_IER(port, AT91_US_RXRDY); /* enable receive only */
+-
+- return 0;
+-}
+-
+-/*
+- * Disable the port
+- */
+-static void at91_shutdown(struct uart_port *port)
+-{
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- /*
+- * Disable all interrupts, port and break condition.
+- */
+- UART_PUT_CR(port, AT91_US_RSTSTA);
+- UART_PUT_IDR(port, -1);
+-
+- /*
+- * Free the interrupt
+- */
+- free_irq(port->irq, port);
+-
+- /*
+- * If there is a specific "close" function (to unregister
+- * control line interrupts)
+- */
+- if (at91_close)
+- at91_close(port);
+-}
+-
+-/*
+- * Power / Clock management.
+- */
+-static void at91_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+-{
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- switch (state) {
+- case 0:
+- /*
+- * Enable the peripheral clock for this serial port.
+- * This is called on uart_open() or a resume event.
+- */
+- clk_enable(at91_port->clk);
+- break;
+- case 3:
+- /*
+- * Disable the peripheral clock for this serial port.
+- * This is called on uart_close() or a suspend event.
+- */
+- clk_disable(at91_port->clk);
+- break;
+- default:
+- printk(KERN_ERR "at91_serial: unknown pm %d\n", state);
+- }
+-}
+-
+-/*
+- * Change the port parameters
+- */
+-static void at91_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
+-{
+- unsigned long flags;
+- unsigned int mode, imr, quot, baud;
+-
+- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+- quot = uart_get_divisor(port, baud);
+-
+- /* Get current mode register */
+- mode = UART_GET_MR(port) & ~(AT91_US_CHRL | AT91_US_NBSTOP | AT91_US_PAR);
+-
+- /* byte size */
+- switch (termios->c_cflag & CSIZE) {
+- case CS5:
+- mode |= AT91_US_CHRL_5;
+- break;
+- case CS6:
+- mode |= AT91_US_CHRL_6;
+- break;
+- case CS7:
+- mode |= AT91_US_CHRL_7;
+- break;
+- default:
+- mode |= AT91_US_CHRL_8;
+- break;
+- }
+-
+- /* stop bits */
+- if (termios->c_cflag & CSTOPB)
+- mode |= AT91_US_NBSTOP_2;
+-
+- /* parity */
+- if (termios->c_cflag & PARENB) {
+- if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
+- if (termios->c_cflag & PARODD)
+- mode |= AT91_US_PAR_MARK;
+- else
+- mode |= AT91_US_PAR_SPACE;
+- }
+- else if (termios->c_cflag & PARODD)
+- mode |= AT91_US_PAR_ODD;
+- else
+- mode |= AT91_US_PAR_EVEN;
+- }
+- else
+- mode |= AT91_US_PAR_NONE;
+-
+- spin_lock_irqsave(&port->lock, flags);
+-
+- port->read_status_mask = AT91_US_OVRE;
+- if (termios->c_iflag & INPCK)
+- port->read_status_mask |= (AT91_US_FRAME | AT91_US_PARE);
+- if (termios->c_iflag & (BRKINT | PARMRK))
+- port->read_status_mask |= AT91_US_RXBRK;
+-
+- /*
+- * Characters to ignore
+- */
+- port->ignore_status_mask = 0;
+- if (termios->c_iflag & IGNPAR)
+- port->ignore_status_mask |= (AT91_US_FRAME | AT91_US_PARE);
+- if (termios->c_iflag & IGNBRK) {
+- port->ignore_status_mask |= AT91_US_RXBRK;
+- /*
+- * If we're ignoring parity and break indicators,
+- * ignore overruns too (for real raw support).
+- */
+- if (termios->c_iflag & IGNPAR)
+- port->ignore_status_mask |= AT91_US_OVRE;
+- }
+-
+- // TODO: Ignore all characters if CREAD is set.
+-
+- /* update the per-port timeout */
+- uart_update_timeout(port, termios->c_cflag, baud);
+-
+- /* disable interrupts and drain transmitter */
+- imr = UART_GET_IMR(port); /* get interrupt mask */
+- UART_PUT_IDR(port, -1); /* disable all interrupts */
+- while (!(UART_GET_CSR(port) & AT91_US_TXEMPTY)) { barrier(); }
+-
+- /* disable receiver and transmitter */
+- UART_PUT_CR(port, AT91_US_TXDIS | AT91_US_RXDIS);
+-
+- /* set the parity, stop bits and data size */
+- UART_PUT_MR(port, mode);
+-
+- /* set the baud rate */
+- UART_PUT_BRGR(port, quot);
+- UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
+- UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);
+-
+- /* restore interrupts */
+- UART_PUT_IER(port, imr);
+-
+- /* CTS flow-control and modem-status interrupts */
+- if (UART_ENABLE_MS(port, termios->c_cflag))
+- port->ops->enable_ms(port);
+-
+- spin_unlock_irqrestore(&port->lock, flags);
+-}
+-
+-/*
+- * Return string describing the specified port
+- */
+-static const char *at91_type(struct uart_port *port)
+-{
+- return (port->type == PORT_AT91) ? "AT91_SERIAL" : NULL;
+-}
+-
+-/*
+- * Release the memory region(s) being used by 'port'.
+- */
+-static void at91_release_port(struct uart_port *port)
+-{
+- struct platform_device *pdev = to_platform_device(port->dev);
+- int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+-
+- release_mem_region(port->mapbase, size);
+-
+- if (port->flags & UPF_IOREMAP) {
+- iounmap(port->membase);
+- port->membase = NULL;
+- }
+-}
+-
+-/*
+- * Request the memory region(s) being used by 'port'.
+- */
+-static int at91_request_port(struct uart_port *port)
+-{
+- struct platform_device *pdev = to_platform_device(port->dev);
+- int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+-
+- if (!request_mem_region(port->mapbase, size, "at91_serial"))
+- return -EBUSY;
+-
+- if (port->flags & UPF_IOREMAP) {
+- port->membase = ioremap(port->mapbase, size);
+- if (port->membase == NULL) {
+- release_mem_region(port->mapbase, size);
+- return -ENOMEM;
+- }
+- }
+-
+- return 0;
+-}
+-
+-/*
+- * Configure/autoconfigure the port.
+- */
+-static void at91_config_port(struct uart_port *port, int flags)
+-{
+- if (flags & UART_CONFIG_TYPE) {
+- port->type = PORT_AT91;
+- at91_request_port(port);
+- }
+-}
+-
+-/*
+- * Verify the new serial_struct (for TIOCSSERIAL).
+- */
+-static int at91_verify_port(struct uart_port *port, struct serial_struct *ser)
+-{
+- int ret = 0;
+- if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91)
+- ret = -EINVAL;
+- if (port->irq != ser->irq)
+- ret = -EINVAL;
+- if (ser->io_type != SERIAL_IO_MEM)
+- ret = -EINVAL;
+- if (port->uartclk / 16 != ser->baud_base)
+- ret = -EINVAL;
+- if ((void *)port->mapbase != ser->iomem_base)
+- ret = -EINVAL;
+- if (port->iobase != ser->port)
+- ret = -EINVAL;
+- if (ser->hub6 != 0)
+- ret = -EINVAL;
+- return ret;
+-}
+-
+-static struct uart_ops at91_pops = {
+- .tx_empty = at91_tx_empty,
+- .set_mctrl = at91_set_mctrl,
+- .get_mctrl = at91_get_mctrl,
+- .stop_tx = at91_stop_tx,
+- .start_tx = at91_start_tx,
+- .stop_rx = at91_stop_rx,
+- .enable_ms = at91_enable_ms,
+- .break_ctl = at91_break_ctl,
+- .startup = at91_startup,
+- .shutdown = at91_shutdown,
+- .set_termios = at91_set_termios,
+- .type = at91_type,
+- .release_port = at91_release_port,
+- .request_port = at91_request_port,
+- .config_port = at91_config_port,
+- .verify_port = at91_verify_port,
+- .pm = at91_serial_pm,
+-};
+-
+-/*
+- * Configure the port from the platform device resource info.
+- */
+-static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct platform_device *pdev)
+-{
+- struct uart_port *port = &at91_port->uart;
+- struct at91_uart_data *data = pdev->dev.platform_data;
+-
+- port->iotype = UPIO_MEM;
+- port->flags = UPF_BOOT_AUTOCONF;
+- port->ops = &at91_pops;
+- port->fifosize = 1;
+- port->line = pdev->id;
+- port->dev = &pdev->dev;
+-
+- port->mapbase = pdev->resource[0].start;
+- port->irq = pdev->resource[1].start;
+-
+- if (port->mapbase == AT91_VA_BASE_SYS + AT91_DBGU) /* Part of system perpherals - already mapped */
+- port->membase = (void __iomem *) port->mapbase;
+- else {
+- port->flags |= UPF_IOREMAP;
+- port->membase = NULL;
+- }
+-
+- if (!at91_port->clk) { /* for console, the clock could already be configured */
+- at91_port->clk = clk_get(&pdev->dev, "usart");
+- clk_enable(at91_port->clk);
+- port->uartclk = clk_get_rate(at91_port->clk);
+- }
+-}
+-
+-/*
+- * Register board-specific modem-control line handlers.
+- */
+-void __init at91_register_uart_fns(struct at91_port_fns *fns)
+-{
+- if (fns->enable_ms)
+- at91_pops.enable_ms = fns->enable_ms;
+- if (fns->get_mctrl)
+- at91_pops.get_mctrl = fns->get_mctrl;
+- if (fns->set_mctrl)
+- at91_pops.set_mctrl = fns->set_mctrl;
+- at91_open = fns->open;
+- at91_close = fns->close;
+- at91_pops.pm = fns->pm;
+- at91_pops.set_wake = fns->set_wake;
+-}
+-
+-
+-#ifdef CONFIG_SERIAL_AT91_CONSOLE
+-static void at91_console_putchar(struct uart_port *port, int ch)
+-{
+- while (!(UART_GET_CSR(port) & AT91_US_TXRDY))
+- barrier();
+- UART_PUT_CHAR(port, ch);
+-}
+-
+-/*
+- * Interrupts are disabled on entering
+- */
+-static void at91_console_write(struct console *co, const char *s, u_int count)
+-{
+- struct uart_port *port = &at91_ports[co->index].uart;
+- unsigned int status, imr;
+-
+- /*
+- * First, save IMR and then disable interrupts
+- */
+- imr = UART_GET_IMR(port); /* get interrupt mask */
+- UART_PUT_IDR(port, AT91_US_RXRDY | AT91_US_TXRDY);
+-
+- uart_console_write(port, s, count, at91_console_putchar);
+-
+- /*
+- * Finally, wait for transmitter to become empty
+- * and restore IMR
+- */
+- do {
+- status = UART_GET_CSR(port);
+- } while (!(status & AT91_US_TXRDY));
+- UART_PUT_IER(port, imr); /* set interrupts back the way they were */
+-}
+-
+-/*
+- * If the port was already initialised (eg, by a boot loader), try to determine
+- * the current setup.
+- */
+-static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+-{
+- unsigned int mr, quot;
+-
+-// TODO: CR is a write-only register
+-// unsigned int cr;
+-//
+-// cr = UART_GET_CR(port) & (AT91_US_RXEN | AT91_US_TXEN);
+-// if (cr == (AT91_US_RXEN | AT91_US_TXEN)) {
+-// /* ok, the port was enabled */
+-// }
+-
+- mr = UART_GET_MR(port) & AT91_US_CHRL;
+- if (mr == AT91_US_CHRL_8)
+- *bits = 8;
+- else
+- *bits = 7;
+-
+- mr = UART_GET_MR(port) & AT91_US_PAR;
+- if (mr == AT91_US_PAR_EVEN)
+- *parity = 'e';
+- else if (mr == AT91_US_PAR_ODD)
+- *parity = 'o';
+-
+- quot = UART_GET_BRGR(port);
+- *baud = port->uartclk / (16 * (quot));
+-}
+-
+-static int __init at91_console_setup(struct console *co, char *options)
+-{
+- struct uart_port *port = &at91_ports[co->index].uart;
+- int baud = 115200;
+- int bits = 8;
+- int parity = 'n';
+- int flow = 'n';
+-
+- if (port->membase == 0) /* Port not initialized yet - delay setup */
+- return -ENODEV;
+-
+- UART_PUT_IDR(port, -1); /* disable interrupts */
+- UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
+- UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);
+-
+- if (options)
+- uart_parse_options(options, &baud, &parity, &bits, &flow);
+- else
+- at91_console_get_options(port, &baud, &parity, &bits);
+-
+- return uart_set_options(port, co, baud, parity, bits, flow);
+-}
+-
+-static struct uart_driver at91_uart;
+-
+-static struct console at91_console = {
+- .name = AT91_DEVICENAME,
+- .write = at91_console_write,
+- .device = uart_console_device,
+- .setup = at91_console_setup,
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
+- .data = &at91_uart,
+-};
+-
+-#define AT91_CONSOLE_DEVICE &at91_console
+-
+-/*
+- * Early console initialization (before VM subsystem initialized).
+- */
+-static int __init at91_console_init(void)
+-{
+- if (at91_default_console_device) {
+- add_preferred_console(AT91_DEVICENAME, at91_default_console_device->id, NULL);
+- at91_init_port(&(at91_ports[at91_default_console_device->id]), at91_default_console_device);
+- register_console(&at91_console);
+- }
+-
+- return 0;
+-}
+-console_initcall(at91_console_init);
+-
+-/*
+- * Late console initialization.
+- */
+-static int __init at91_late_console_init(void)
+-{
+- if (at91_default_console_device && !(at91_console.flags & CON_ENABLED))
+- register_console(&at91_console);
+-
+- return 0;
+-}
+-core_initcall(at91_late_console_init);
+-
+-#else
+-#define AT91_CONSOLE_DEVICE NULL
+-#endif
+-
+-static struct uart_driver at91_uart = {
+- .owner = THIS_MODULE,
+- .driver_name = "at91_serial",
+- .dev_name = AT91_DEVICENAME,
+- .major = SERIAL_AT91_MAJOR,
+- .minor = MINOR_START,
+- .nr = AT91_NR_UART,
+- .cons = AT91_CONSOLE_DEVICE,
+-};
+-
+-#ifdef CONFIG_PM
+-static int at91_serial_suspend(struct platform_device *pdev, pm_message_t state)
+-{
+- struct uart_port *port = platform_get_drvdata(pdev);
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
+- enable_irq_wake(port->irq);
+- else {
+- disable_irq_wake(port->irq);
+- uart_suspend_port(&at91_uart, port);
+- at91_port->suspended = 1;
+- }
+-
+- return 0;
+-}
+-
+-static int at91_serial_resume(struct platform_device *pdev)
+-{
+- struct uart_port *port = platform_get_drvdata(pdev);
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+-
+- if (at91_port->suspended) {
+- uart_resume_port(&at91_uart, port);
+- at91_port->suspended = 0;
+- }
+-
+- return 0;
+-}
+-#else
+-#define at91_serial_suspend NULL
+-#define at91_serial_resume NULL
+-#endif
+-
+-static int __devinit at91_serial_probe(struct platform_device *pdev)
+-{
+- struct at91_uart_port *port;
+- int ret;
+-
+- port = &at91_ports[pdev->id];
+- at91_init_port(port, pdev);
+-
+- ret = uart_add_one_port(&at91_uart, &port->uart);
+- if (!ret) {
+- device_init_wakeup(&pdev->dev, 1);
+- platform_set_drvdata(pdev, port);
+- }
+-
+- return ret;
+-}
+-
+-static int __devexit at91_serial_remove(struct platform_device *pdev)
+-{
+- struct uart_port *port = platform_get_drvdata(pdev);
+- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
+- int ret = 0;
+-
+- clk_disable(at91_port->clk);
+- clk_put(at91_port->clk);
+-
+- device_init_wakeup(&pdev->dev, 0);
+- platform_set_drvdata(pdev, NULL);
+-
+- if (port) {
+- ret = uart_remove_one_port(&at91_uart, port);
+- kfree(port);
+- }
+-
+- return ret;
+-}
+-
+-static struct platform_driver at91_serial_driver = {
+- .probe = at91_serial_probe,
+- .remove = __devexit_p(at91_serial_remove),
+- .suspend = at91_serial_suspend,
+- .resume = at91_serial_resume,
+- .driver = {
+- .name = "at91_usart",
+- .owner = THIS_MODULE,
+- },
+-};
+-
+-static int __init at91_serial_init(void)
+-{
+- int ret;
+-
+- ret = uart_register_driver(&at91_uart);
+- if (ret)
+- return ret;
+-
+- ret = platform_driver_register(&at91_serial_driver);
+- if (ret)
+- uart_unregister_driver(&at91_uart);
+-
+- return ret;
+-}
+-
+-static void __exit at91_serial_exit(void)
+-{
+- platform_driver_unregister(&at91_serial_driver);
+- uart_unregister_driver(&at91_uart);
+-}
+-
+-module_init(at91_serial_init);
+-module_exit(at91_serial_exit);
+-
+-MODULE_AUTHOR("Rick Bronson");
+-MODULE_DESCRIPTION("AT91 generic serial port driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
+new file mode 100644
+index 0000000..391a1f4
+--- /dev/null
++++ b/drivers/serial/atmel_serial.c
+@@ -0,0 +1,992 @@
++/*
++ * linux/drivers/char/at91_serial.c
++ *
++ * Driver for Atmel AT91 / AT32 Serial ports
++ * Copyright (C) 2003 Rick Bronson
++ *
++ * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
++ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ * 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/tty.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <linux/clk.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/tty_flip.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++
++#include <asm/arch/at91rm9200_pdc.h>
++#include <asm/mach/serial_at91.h>
++#include <asm/arch/board.h>
++#ifdef CONFIG_ARM
++#include <asm/arch/system.h>
++#include <asm/arch/gpio.h>
++#endif
++
++#include "atmel_serial.h"
++
++#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++
++#ifdef CONFIG_SERIAL_ATMEL_TTYAT
++
++/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
++ * should coexist with the 8250 driver, such as if we have an external 16C550
++ * UART. */
++#define SERIAL_ATMEL_MAJOR 204
++#define MINOR_START 154
++#define ATMEL_DEVICENAME "ttyAT"
++
++#else
++
++/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port
++ * name, but it is legally reserved for the 8250 driver. */
++#define SERIAL_ATMEL_MAJOR TTY_MAJOR
++#define MINOR_START 64
++#define ATMEL_DEVICENAME "ttyS"
++
++#endif
++
++#define ATMEL_ISR_PASS_LIMIT 256
++
++#define UART_PUT_CR(port,v) writel(v, (port)->membase + ATMEL_US_CR)
++#define UART_GET_MR(port) readl((port)->membase + ATMEL_US_MR)
++#define UART_PUT_MR(port,v) writel(v, (port)->membase + ATMEL_US_MR)
++#define UART_PUT_IER(port,v) writel(v, (port)->membase + ATMEL_US_IER)
++#define UART_PUT_IDR(port,v) writel(v, (port)->membase + ATMEL_US_IDR)
++#define UART_GET_IMR(port) readl((port)->membase + ATMEL_US_IMR)
++#define UART_GET_CSR(port) readl((port)->membase + ATMEL_US_CSR)
++#define UART_GET_CHAR(port) readl((port)->membase + ATMEL_US_RHR)
++#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + ATMEL_US_THR)
++#define UART_GET_BRGR(port) readl((port)->membase + ATMEL_US_BRGR)
++#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + ATMEL_US_BRGR)
++#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + ATMEL_US_RTOR)
++
++// #define UART_GET_CR(port) readl((port)->membase + ATMEL_US_CR) // is write-only
++
++ /* PDC registers */
++#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + ATMEL_PDC_PTCR)
++#define UART_GET_PTSR(port) readl((port)->membase + ATMEL_PDC_PTSR)
++
++#define UART_PUT_RPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RPR)
++#define UART_GET_RPR(port) readl((port)->membase + ATMEL_PDC_RPR)
++#define UART_PUT_RCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RCR)
++#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNPR)
++#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNCR)
++
++#define UART_PUT_TPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TPR)
++#define UART_PUT_TCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TCR)
++//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNPR)
++//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNCR)
++
++static int (*atmel_open_hook)(struct uart_port *);
++static void (*atmel_close_hook)(struct uart_port *);
++
++/*
++ * We wrap our port structure around the generic uart_port.
++ */
++struct atmel_uart_port {
++ struct uart_port uart; /* uart */
++ struct clk *clk; /* uart clock */
++ unsigned short suspended; /* is port suspended? */
++};
++
++static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
++
++#ifdef SUPPORT_SYSRQ
++static struct console atmel_console;
++#endif
++
++/*
++ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
++ */
++static u_int atmel_tx_empty(struct uart_port *port)
++{
++ return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
++}
++
++/*
++ * Set state of the modem control output lines
++ */
++static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
++{
++ unsigned int control = 0;
++ unsigned int mode;
++
++#ifdef CONFIG_ARM
++ if (arch_identify() == ARCH_ID_AT91RM9200) {
++ /*
++ * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
++ * We need to drive the pin manually.
++ */
++ if (port->mapbase == AT91RM9200_BASE_US0) {
++ if (mctrl & TIOCM_RTS)
++ at91_set_gpio_value(AT91_PIN_PA21, 0);
++ else
++ at91_set_gpio_value(AT91_PIN_PA21, 1);
++ }
++ }
++#endif
++
++ if (mctrl & TIOCM_RTS)
++ control |= ATMEL_US_RTSEN;
++ else
++ control |= ATMEL_US_RTSDIS;
++
++ if (mctrl & TIOCM_DTR)
++ control |= ATMEL_US_DTREN;
++ else
++ control |= ATMEL_US_DTRDIS;
++
++ UART_PUT_CR(port, control);
++
++ /* Local loopback mode? */
++ mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
++ if (mctrl & TIOCM_LOOP)
++ mode |= ATMEL_US_CHMODE_LOC_LOOP;
++ else
++ mode |= ATMEL_US_CHMODE_NORMAL;
++ UART_PUT_MR(port, mode);
++}
++
++/*
++ * Get state of the modem control input lines
++ */
++static u_int atmel_get_mctrl(struct uart_port *port)
++{
++ unsigned int status, ret = 0;
++
++ status = UART_GET_CSR(port);
++
++ /*
++ * The control signals are active low.
++ */
++ if (!(status & ATMEL_US_DCD))
++ ret |= TIOCM_CD;
++ if (!(status & ATMEL_US_CTS))
++ ret |= TIOCM_CTS;
++ if (!(status & ATMEL_US_DSR))
++ ret |= TIOCM_DSR;
++ if (!(status & ATMEL_US_RI))
++ ret |= TIOCM_RI;
++
++ return ret;
++}
++
++/*
++ * Stop transmitting.
++ */
++static void atmel_stop_tx(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ UART_PUT_IDR(port, ATMEL_US_TXRDY);
++}
++
++/*
++ * Start transmitting.
++ */
++static void atmel_start_tx(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ UART_PUT_IER(port, ATMEL_US_TXRDY);
++}
++
++/*
++ * Stop receiving - port is in process of being closed.
++ */
++static void atmel_stop_rx(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ UART_PUT_IDR(port, ATMEL_US_RXRDY);
++}
++
++/*
++ * Enable modem status interrupts
++ */
++static void atmel_enable_ms(struct uart_port *port)
++{
++ UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
++}
++
++/*
++ * Control the transmission of a break signal
++ */
++static void atmel_break_ctl(struct uart_port *port, int break_state)
++{
++ if (break_state != 0)
++ UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */
++ else
++ UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */
++}
++
++/*
++ * Characters received (called from interrupt handler)
++ */
++static void atmel_rx_chars(struct uart_port *port)
++{
++ struct tty_struct *tty = port->info->tty;
++ unsigned int status, ch, flg;
++
++ status = UART_GET_CSR(port);
++ while (status & ATMEL_US_RXRDY) {
++ ch = UART_GET_CHAR(port);
++
++ port->icount.rx++;
++
++ flg = TTY_NORMAL;
++
++ /*
++ * note that the error handling code is
++ * out of the main execution path
++ */
++ if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
++ UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */
++ if (status & ATMEL_US_RXBRK) {
++ status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */
++ port->icount.brk++;
++ if (uart_handle_break(port))
++ goto ignore_char;
++ }
++ if (status & ATMEL_US_PARE)
++ port->icount.parity++;
++ if (status & ATMEL_US_FRAME)
++ port->icount.frame++;
++ if (status & ATMEL_US_OVRE)
++ port->icount.overrun++;
++
++ status &= port->read_status_mask;
++
++ if (status & ATMEL_US_RXBRK)
++ flg = TTY_BREAK;
++ else if (status & ATMEL_US_PARE)
++ flg = TTY_PARITY;
++ else if (status & ATMEL_US_FRAME)
++ flg = TTY_FRAME;
++ }
++
++ if (uart_handle_sysrq_char(port, ch))
++ goto ignore_char;
++
++ uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg);
++
++ ignore_char:
++ status = UART_GET_CSR(port);
++ }
++
++ tty_flip_buffer_push(tty);
++}
++
++/*
++ * Transmit characters (called from interrupt handler)
++ */
++static void atmel_tx_chars(struct uart_port *port)
++{
++ struct circ_buf *xmit = &port->info->xmit;
++
++ if (port->x_char) {
++ UART_PUT_CHAR(port, port->x_char);
++ port->icount.tx++;
++ port->x_char = 0;
++ return;
++ }
++ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++ atmel_stop_tx(port);
++ return;
++ }
++
++ while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
++ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ port->icount.tx++;
++ if (uart_circ_empty(xmit))
++ break;
++ }
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++
++ if (uart_circ_empty(xmit))
++ atmel_stop_tx(port);
++}
++
++/*
++ * Interrupt handler
++ */
++static irqreturn_t atmel_interrupt(int irq, void *dev_id)
++{
++ struct uart_port *port = dev_id;
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++ unsigned int status, pending, pass_counter = 0;
++
++ status = UART_GET_CSR(port);
++ pending = status & UART_GET_IMR(port);
++ while (pending) {
++ /* Interrupt receive */
++ if (pending & ATMEL_US_RXRDY)
++ atmel_rx_chars(port);
++
++ // TODO: All reads to CSR will clear these interrupts!
++ if (pending & ATMEL_US_RIIC) port->icount.rng++;
++ if (pending & ATMEL_US_DSRIC) port->icount.dsr++;
++ if (pending & ATMEL_US_DCDIC)
++ uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
++ if (pending & ATMEL_US_CTSIC)
++ uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
++ if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC))
++ wake_up_interruptible(&port->info->delta_msr_wait);
++
++ /* Interrupt transmit */
++ if (pending & ATMEL_US_TXRDY)
++ atmel_tx_chars(port);
++
++ if (pass_counter++ > ATMEL_ISR_PASS_LIMIT)
++ break;
++
++ status = UART_GET_CSR(port);
++ pending = status & UART_GET_IMR(port);
++ }
++ return IRQ_HANDLED;
++}
++
++/*
++ * Perform initialization and enable port for reception
++ */
++static int atmel_startup(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++ int retval;
++
++ /*
++ * Ensure that no interrupts are enabled otherwise when
++ * request_irq() is called we could get stuck trying to
++ * handle an unexpected interrupt
++ */
++ UART_PUT_IDR(port, -1);
++
++ /*
++ * Allocate the IRQ
++ */
++ retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port);
++ if (retval) {
++ printk("atmel_serial: atmel_startup - Can't get irq\n");
++ return retval;
++ }
++
++ /*
++ * If there is a specific "open" function (to register
++ * control line interrupts)
++ */
++ if (atmel_open_hook) {
++ retval = atmel_open_hook(port);
++ if (retval) {
++ free_irq(port->irq, port);
++ return retval;
++ }
++ }
++
++ /*
++ * Finally, enable the serial port
++ */
++ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
++ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */
++
++ UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */
++
++ return 0;
++}
++
++/*
++ * Disable the port
++ */
++static void atmel_shutdown(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ /*
++ * Disable all interrupts, port and break condition.
++ */
++ UART_PUT_CR(port, ATMEL_US_RSTSTA);
++ UART_PUT_IDR(port, -1);
++
++ /*
++ * Free the interrupt
++ */
++ free_irq(port->irq, port);
++
++ /*
++ * If there is a specific "close" function (to unregister
++ * control line interrupts)
++ */
++ if (atmel_close_hook)
++ atmel_close_hook(port);
++}
++
++/*
++ * Power / Clock management.
++ */
++static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
++{
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ switch (state) {
++ case 0:
++ /*
++ * Enable the peripheral clock for this serial port.
++ * This is called on uart_open() or a resume event.
++ */
++ clk_enable(atmel_port->clk);
++ break;
++ case 3:
++ /*
++ * Disable the peripheral clock for this serial port.
++ * This is called on uart_close() or a suspend event.
++ */
++ clk_disable(atmel_port->clk);
++ break;
++ default:
++ printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
++ }
++}
++
++/*
++ * Change the port parameters
++ */
++static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
++{
++ unsigned long flags;
++ unsigned int mode, imr, quot, baud;
++
++ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
++ quot = uart_get_divisor(port, baud);
++
++ /* Get current mode register */
++ mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
++
++ /* byte size */
++ switch (termios->c_cflag & CSIZE) {
++ case CS5:
++ mode |= ATMEL_US_CHRL_5;
++ break;
++ case CS6:
++ mode |= ATMEL_US_CHRL_6;
++ break;
++ case CS7:
++ mode |= ATMEL_US_CHRL_7;
++ break;
++ default:
++ mode |= ATMEL_US_CHRL_8;
++ break;
++ }
++
++ /* stop bits */
++ if (termios->c_cflag & CSTOPB)
++ mode |= ATMEL_US_NBSTOP_2;
++
++ /* parity */
++ if (termios->c_cflag & PARENB) {
++ if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
++ if (termios->c_cflag & PARODD)
++ mode |= ATMEL_US_PAR_MARK;
++ else
++ mode |= ATMEL_US_PAR_SPACE;
++ }
++ else if (termios->c_cflag & PARODD)
++ mode |= ATMEL_US_PAR_ODD;
++ else
++ mode |= ATMEL_US_PAR_EVEN;
++ }
++ else
++ mode |= ATMEL_US_PAR_NONE;
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ port->read_status_mask = ATMEL_US_OVRE;
++ if (termios->c_iflag & INPCK)
++ port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
++ if (termios->c_iflag & (BRKINT | PARMRK))
++ port->read_status_mask |= ATMEL_US_RXBRK;
++
++ /*
++ * Characters to ignore
++ */
++ port->ignore_status_mask = 0;
++ if (termios->c_iflag & IGNPAR)
++ port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
++ if (termios->c_iflag & IGNBRK) {
++ port->ignore_status_mask |= ATMEL_US_RXBRK;
++ /*
++ * If we're ignoring parity and break indicators,
++ * ignore overruns too (for real raw support).
++ */
++ if (termios->c_iflag & IGNPAR)
++ port->ignore_status_mask |= ATMEL_US_OVRE;
++ }
++
++ // TODO: Ignore all characters if CREAD is set.
++
++ /* update the per-port timeout */
++ uart_update_timeout(port, termios->c_cflag, baud);
++
++ /* disable interrupts and drain transmitter */
++ imr = UART_GET_IMR(port); /* get interrupt mask */
++ UART_PUT_IDR(port, -1); /* disable all interrupts */
++ while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); }
++
++ /* disable receiver and transmitter */
++ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
++
++ /* set the parity, stop bits and data size */
++ UART_PUT_MR(port, mode);
++
++ /* set the baud rate */
++ UART_PUT_BRGR(port, quot);
++ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
++ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
++
++ /* restore interrupts */
++ UART_PUT_IER(port, imr);
++
++ /* CTS flow-control and modem-status interrupts */
++ if (UART_ENABLE_MS(port, termios->c_cflag))
++ port->ops->enable_ms(port);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++/*
++ * Return string describing the specified port
++ */
++static const char *atmel_type(struct uart_port *port)
++{
++ return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'.
++ */
++static void atmel_release_port(struct uart_port *port)
++{
++ struct platform_device *pdev = to_platform_device(port->dev);
++ int size = pdev->resource[0].end - pdev->resource[0].start + 1;
++
++ release_mem_region(port->mapbase, size);
++
++ if (port->flags & UPF_IOREMAP) {
++ iounmap(port->membase);
++ port->membase = NULL;
++ }
++}
++
++/*
++ * Request the memory region(s) being used by 'port'.
++ */
++static int atmel_request_port(struct uart_port *port)
++{
++ struct platform_device *pdev = to_platform_device(port->dev);
++ int size = pdev->resource[0].end - pdev->resource[0].start + 1;
++
++ if (!request_mem_region(port->mapbase, size, "atmel_serial"))
++ return -EBUSY;
++
++ if (port->flags & UPF_IOREMAP) {
++ port->membase = ioremap(port->mapbase, size);
++ if (port->membase == NULL) {
++ release_mem_region(port->mapbase, size);
++ return -ENOMEM;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void atmel_config_port(struct uart_port *port, int flags)
++{
++ if (flags & UART_CONFIG_TYPE) {
++ port->type = PORT_ATMEL;
++ atmel_request_port(port);
++ }
++}
++
++/*
++ * Verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++ int ret = 0;
++ if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
++ ret = -EINVAL;
++ if (port->irq != ser->irq)
++ ret = -EINVAL;
++ if (ser->io_type != SERIAL_IO_MEM)
++ ret = -EINVAL;
++ if (port->uartclk / 16 != ser->baud_base)
++ ret = -EINVAL;
++ if ((void *)port->mapbase != ser->iomem_base)
++ ret = -EINVAL;
++ if (port->iobase != ser->port)
++ ret = -EINVAL;
++ if (ser->hub6 != 0)
++ ret = -EINVAL;
++ return ret;
++}
++
++static struct uart_ops atmel_pops = {
++ .tx_empty = atmel_tx_empty,
++ .set_mctrl = atmel_set_mctrl,
++ .get_mctrl = atmel_get_mctrl,
++ .stop_tx = atmel_stop_tx,
++ .start_tx = atmel_start_tx,
++ .stop_rx = atmel_stop_rx,
++ .enable_ms = atmel_enable_ms,
++ .break_ctl = atmel_break_ctl,
++ .startup = atmel_startup,
++ .shutdown = atmel_shutdown,
++ .set_termios = atmel_set_termios,
++ .type = atmel_type,
++ .release_port = atmel_release_port,
++ .request_port = atmel_request_port,
++ .config_port = atmel_config_port,
++ .verify_port = atmel_verify_port,
++ .pm = atmel_serial_pm,
++};
++
++/*
++ * Configure the port from the platform device resource info.
++ */
++static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev)
++{
++ struct uart_port *port = &atmel_port->uart;
++ struct atmel_uart_data *data = pdev->dev.platform_data;
++
++ port->iotype = UPIO_MEM;
++ port->flags = UPF_BOOT_AUTOCONF;
++ port->ops = &atmel_pops;
++ port->fifosize = 1;
++ port->line = pdev->id;
++ port->dev = &pdev->dev;
++
++ port->mapbase = pdev->resource[0].start;
++ port->irq = pdev->resource[1].start;
++
++ if (data->regs)
++ /* Already mapped by setup code */
++ port->membase = data->regs;
++ else {
++ port->flags |= UPF_IOREMAP;
++ port->membase = NULL;
++ }
++
++ if (!atmel_port->clk) { /* for console, the clock could already be configured */
++ atmel_port->clk = clk_get(&pdev->dev, "usart");
++ clk_enable(atmel_port->clk);
++ port->uartclk = clk_get_rate(atmel_port->clk);
++ }
++}
++
++/*
++ * Register board-specific modem-control line handlers.
++ */
++void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
++{
++ if (fns->enable_ms)
++ atmel_pops.enable_ms = fns->enable_ms;
++ if (fns->get_mctrl)
++ atmel_pops.get_mctrl = fns->get_mctrl;
++ if (fns->set_mctrl)
++ atmel_pops.set_mctrl = fns->set_mctrl;
++ atmel_open_hook = fns->open;
++ atmel_close_hook = fns->close;
++ atmel_pops.pm = fns->pm;
++ atmel_pops.set_wake = fns->set_wake;
++}
++
++
++#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
++static void atmel_console_putchar(struct uart_port *port, int ch)
++{
++ while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
++ barrier();
++ UART_PUT_CHAR(port, ch);
++}
++
++/*
++ * Interrupts are disabled on entering
++ */
++static void atmel_console_write(struct console *co, const char *s, u_int count)
++{
++ struct uart_port *port = &atmel_ports[co->index].uart;
++ unsigned int status, imr;
++
++ /*
++ * First, save IMR and then disable interrupts
++ */
++ imr = UART_GET_IMR(port); /* get interrupt mask */
++ UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
++
++ uart_console_write(port, s, count, atmel_console_putchar);
++
++ /*
++ * Finally, wait for transmitter to become empty
++ * and restore IMR
++ */
++ do {
++ status = UART_GET_CSR(port);
++ } while (!(status & ATMEL_US_TXRDY));
++ UART_PUT_IER(port, imr); /* set interrupts back the way they were */
++}
++
++/*
++ * If the port was already initialised (eg, by a boot loader), try to determine
++ * the current setup.
++ */
++static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++ unsigned int mr, quot;
++
++// TODO: CR is a write-only register
++// unsigned int cr;
++//
++// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN);
++// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) {
++// /* ok, the port was enabled */
++// }
++
++ mr = UART_GET_MR(port) & ATMEL_US_CHRL;
++ if (mr == ATMEL_US_CHRL_8)
++ *bits = 8;
++ else
++ *bits = 7;
++
++ mr = UART_GET_MR(port) & ATMEL_US_PAR;
++ if (mr == ATMEL_US_PAR_EVEN)
++ *parity = 'e';
++ else if (mr == ATMEL_US_PAR_ODD)
++ *parity = 'o';
++
++ /*
++ * The serial core only rounds down when matching this to a
++ * supported baud rate. Make sure we don't end up slightly
++ * lower than one of those, as it would make us fall through
++ * to a much lower baud rate than we really want.
++ */
++ quot = UART_GET_BRGR(port);
++ *baud = port->uartclk / (16 * (quot - 1));
++}
++
++static int __init atmel_console_setup(struct console *co, char *options)
++{
++ struct uart_port *port = &atmel_ports[co->index].uart;
++ int baud = 115200;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ if (port->membase == 0) /* Port not initialized yet - delay setup */
++ return -ENODEV;
++
++ UART_PUT_IDR(port, -1); /* disable interrupts */
++ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
++ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++ else
++ atmel_console_get_options(port, &baud, &parity, &bits);
++
++ return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct uart_driver atmel_uart;
++
++static struct console atmel_console = {
++ .name = ATMEL_DEVICENAME,
++ .write = atmel_console_write,
++ .device = uart_console_device,
++ .setup = atmel_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &atmel_uart,
++};
++
++#define ATMEL_CONSOLE_DEVICE &atmel_console
++
++/*
++ * Early console initialization (before VM subsystem initialized).
++ */
++static int __init atmel_console_init(void)
++{
++ if (atmel_default_console_device) {
++ add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL);
++ atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device);
++ register_console(&atmel_console);
++ }
++
++ return 0;
++}
++console_initcall(atmel_console_init);
++
++/*
++ * Late console initialization.
++ */
++static int __init atmel_late_console_init(void)
++{
++ if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED))
++ register_console(&atmel_console);
++
++ return 0;
++}
++core_initcall(atmel_late_console_init);
++
++#else
++#define ATMEL_CONSOLE_DEVICE NULL
++#endif
++
++static struct uart_driver atmel_uart = {
++ .owner = THIS_MODULE,
++ .driver_name = "atmel_serial",
++ .dev_name = ATMEL_DEVICENAME,
++ .major = SERIAL_ATMEL_MAJOR,
++ .minor = MINOR_START,
++ .nr = ATMEL_MAX_UART,
++ .cons = ATMEL_CONSOLE_DEVICE,
++};
++
++#ifdef CONFIG_PM
++static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct uart_port *port = platform_get_drvdata(pdev);
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
++ enable_irq_wake(port->irq);
++ else {
++ disable_irq_wake(port->irq);
++ uart_suspend_port(&atmel_uart, port);
++ atmel_port->suspended = 1;
++ }
++
++ return 0;
++}
++
++static int atmel_serial_resume(struct platform_device *pdev)
++{
++ struct uart_port *port = platform_get_drvdata(pdev);
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++
++ if (atmel_port->suspended) {
++ uart_resume_port(&atmel_uart, port);
++ atmel_port->suspended = 0;
++ }
++
++ return 0;
++}
++#else
++#define atmel_serial_suspend NULL
++#define atmel_serial_resume NULL
++#endif
++
++static int __devinit atmel_serial_probe(struct platform_device *pdev)
++{
++ struct atmel_uart_port *port;
++ int ret;
++
++ port = &atmel_ports[pdev->id];
++ atmel_init_port(port, pdev);
++
++ ret = uart_add_one_port(&atmel_uart, &port->uart);
++ if (!ret) {
++ device_init_wakeup(&pdev->dev, 1);
++ platform_set_drvdata(pdev, port);
++ }
++
++ return ret;
++}
++
++static int __devexit atmel_serial_remove(struct platform_device *pdev)
++{
++ struct uart_port *port = platform_get_drvdata(pdev);
++ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
++ int ret = 0;
++
++ clk_disable(atmel_port->clk);
++ clk_put(atmel_port->clk);
++
++ device_init_wakeup(&pdev->dev, 0);
++ platform_set_drvdata(pdev, NULL);
++
++ if (port) {
++ ret = uart_remove_one_port(&atmel_uart, port);
++ kfree(port);
++ }
++
++ return ret;
++}
++
++static struct platform_driver atmel_serial_driver = {
++ .probe = atmel_serial_probe,
++ .remove = __devexit_p(atmel_serial_remove),
++ .suspend = atmel_serial_suspend,
++ .resume = atmel_serial_resume,
++ .driver = {
++ .name = "atmel_usart",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init atmel_serial_init(void)
++{
++ int ret;
++
++ ret = uart_register_driver(&atmel_uart);
++ if (ret)
++ return ret;
++
++ ret = platform_driver_register(&atmel_serial_driver);
++ if (ret)
++ uart_unregister_driver(&atmel_uart);
++
++ return ret;
++}
++
++static void __exit atmel_serial_exit(void)
++{
++ platform_driver_unregister(&atmel_serial_driver);
++ uart_unregister_driver(&atmel_uart);
++}
++
++module_init(atmel_serial_init);
++module_exit(atmel_serial_exit);
++
++MODULE_AUTHOR("Rick Bronson");
++MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
+new file mode 100644
+index 0000000..eced2ad
+--- /dev/null
++++ b/drivers/serial/atmel_serial.h
+@@ -0,0 +1,123 @@
++/*
++ * drivers/serial/atmel_serial.h
++ *
++ * Copyright (C) 2005 Ivan Kokshaysky
++ * Copyright (C) SAN People
++ *
++ * USART registers.
++ * Based on AT91RM9200 datasheet revision E.
++ *
++ * 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.
++ */
++
++#ifndef ATMEL_SERIAL_H
++#define ATMEL_SERIAL_H
++
++#define ATMEL_US_CR 0x00 /* Control Register */
++#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */
++#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */
++#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */
++#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */
++#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */
++#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */
++#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */
++#define ATMEL_US_STTBRK (1 << 9) /* Start Break */
++#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */
++#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */
++#define ATMEL_US_SENDA (1 << 12) /* Send Address */
++#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */
++#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */
++#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */
++#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable */
++#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */
++#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */
++#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */
++
++#define ATMEL_US_MR 0x04 /* Mode Register */
++#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */
++#define ATMEL_US_USMODE_NORMAL 0
++#define ATMEL_US_USMODE_RS485 1
++#define ATMEL_US_USMODE_HWHS 2
++#define ATMEL_US_USMODE_MODEM 3
++#define ATMEL_US_USMODE_ISO7816_T0 4
++#define ATMEL_US_USMODE_ISO7816_T1 6
++#define ATMEL_US_USMODE_IRDA 8
++#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */
++#define ATMEL_US_CHRL (3 << 6) /* Character Length */
++#define ATMEL_US_CHRL_5 (0 << 6)
++#define ATMEL_US_CHRL_6 (1 << 6)
++#define ATMEL_US_CHRL_7 (2 << 6)
++#define ATMEL_US_CHRL_8 (3 << 6)
++#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */
++#define ATMEL_US_PAR (7 << 9) /* Parity Type */
++#define ATMEL_US_PAR_EVEN (0 << 9)
++#define ATMEL_US_PAR_ODD (1 << 9)
++#define ATMEL_US_PAR_SPACE (2 << 9)
++#define ATMEL_US_PAR_MARK (3 << 9)
++#define ATMEL_US_PAR_NONE (4 << 9)
++#define ATMEL_US_PAR_MULTI_DROP (6 << 9)
++#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */
++#define ATMEL_US_NBSTOP_1 (0 << 12)
++#define ATMEL_US_NBSTOP_1_5 (1 << 12)
++#define ATMEL_US_NBSTOP_2 (2 << 12)
++#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */
++#define ATMEL_US_CHMODE_NORMAL (0 << 14)
++#define ATMEL_US_CHMODE_ECHO (1 << 14)
++#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14)
++#define ATMEL_US_CHMODE_REM_LOOP (3 << 14)
++#define ATMEL_US_MSBF (1 << 16) /* Bit Order */
++#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */
++#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */
++#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */
++#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */
++#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */
++#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */
++#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */
++
++#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */
++#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */
++#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */
++#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */
++#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */
++#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */
++#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */
++#define ATMEL_US_FRAME (1 << 6) /* Framing Error */
++#define ATMEL_US_PARE (1 << 7) /* Parity Error */
++#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */
++#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */
++#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */
++#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */
++#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */
++#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */
++#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change */
++#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change */
++#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */
++#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */
++#define ATMEL_US_RI (1 << 20) /* RI */
++#define ATMEL_US_DSR (1 << 21) /* DSR */
++#define ATMEL_US_DCD (1 << 22) /* DCD */
++#define ATMEL_US_CTS (1 << 23) /* CTS */
++
++#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */
++#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */
++#define ATMEL_US_CSR 0x14 /* Channel Status Register */
++#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */
++#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */
++
++#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */
++#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */
++
++#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */
++#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */
++
++#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */
++#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */
++
++#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */
++#define ATMEL_US_NER 0x44 /* Number of Errors Register */
++#define ATMEL_US_IF 0x4c /* IrDA Filter Register */
++
++#endif
+diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
+index f27d852..5980127 100644
+--- a/drivers/serial/clps711x.c
++++ b/drivers/serial/clps711x.c
+@@ -93,7 +93,7 @@ static void clps711xuart_enable_ms(struc
+ {
+ }
+
+-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
+ {
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = port->info->tty;
+@@ -131,7 +131,7 @@ static irqreturn_t clps711xuart_int_rx(i
+ #endif
+ }
+
+- if (uart_handle_sysrq_char(port, ch, regs))
++ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ /*
+@@ -147,7 +147,7 @@ static irqreturn_t clps711xuart_int_rx(i
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
+ {
+ struct uart_port *port = dev_id;
+ struct circ_buf *xmit = &port->info->xmit;
+diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
+index 3b35cb7..a8f894c 100644
+--- a/drivers/serial/cpm_uart/cpm_uart.h
++++ b/drivers/serial/cpm_uart/cpm_uart.h
+@@ -16,7 +16,6 @@
+ #ifndef CPM_UART_H
+ #define CPM_UART_H
+
+-#include <linux/config.h>
+ #include <linux/platform_device.h>
+ #include <linux/fs_uart_pd.h>
+
+diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
+index 90ff96e..0abb544 100644
+--- a/drivers/serial/cpm_uart/cpm_uart_core.c
++++ b/drivers/serial/cpm_uart/cpm_uart_core.c
+@@ -46,6 +46,7 @@
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/delay.h>
++#include <asm/fs_pd.h>
+
+ #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+@@ -247,7 +248,7 @@ static void cpm_uart_break_ctl(struct ua
+ /*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+-static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs)
++static void cpm_uart_int_tx(struct uart_port *port)
+ {
+ pr_debug("CPM uart[%d]:TX INT\n", port->line);
+
+@@ -257,7 +258,7 @@ static void cpm_uart_int_tx(struct uart_
+ /*
+ * Receive characters
+ */
+-static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
++static void cpm_uart_int_rx(struct uart_port *port)
+ {
+ int i;
+ unsigned char ch, *cp;
+@@ -303,7 +304,7 @@ static void cpm_uart_int_rx(struct uart_
+ if (status &
+ (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+ goto handle_error;
+- if (uart_handle_sysrq_char(port, ch, regs))
++ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ error_return:
+@@ -372,7 +373,7 @@ static void cpm_uart_int_rx(struct uart_
+ /*
+ * Asynchron mode interrupt handler
+ */
+-static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t cpm_uart_int(int irq, void *data)
+ {
+ u8 events;
+ struct uart_port *port = (struct uart_port *)data;
+@@ -388,18 +389,18 @@ static irqreturn_t cpm_uart_int(int irq,
+ if (events & SMCM_BRKE)
+ uart_handle_break(port);
+ if (events & SMCM_RX)
+- cpm_uart_int_rx(port, regs);
++ cpm_uart_int_rx(port);
+ if (events & SMCM_TX)
+- cpm_uart_int_tx(port, regs);
++ cpm_uart_int_tx(port);
+ } else {
+ events = sccp->scc_scce;
+ sccp->scc_scce = events;
+ if (events & UART_SCCM_BRKE)
+ uart_handle_break(port);
+ if (events & UART_SCCM_RX)
+- cpm_uart_int_rx(port, regs);
++ cpm_uart_int_rx(port);
+ if (events & UART_SCCM_TX)
+- cpm_uart_int_tx(port, regs);
++ cpm_uart_int_tx(port);
+ }
+ return (events) ? IRQ_HANDLED : IRQ_NONE;
+ }
+@@ -1022,15 +1023,17 @@ int cpm_uart_drv_get_platform_data(struc
+ {
+ struct resource *r;
+ struct fs_uart_platform_info *pdata = pdev->dev.platform_data;
+- int idx = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */
++ int idx; /* It is UART_SMCx or UART_SCCx index */
+ struct uart_cpm_port *pinfo;
+ int line;
+ u32 mem, pram;
+
++ idx = pdata->fs_no = fs_uart_get_id(pdata);
++
+ line = cpm_uart_id2nr(idx);
+ if(line < 0) {
+ printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
+- return -1;
++ return -EINVAL;
+ }
+
+ pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx];
+@@ -1044,11 +1047,11 @@ int cpm_uart_drv_get_platform_data(struc
+
+ if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs")))
+ return -EINVAL;
+- mem = r->start;
++ mem = (u32)ioremap(r->start, r->end - r->start + 1);
+
+ if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram")))
+ return -EINVAL;
+- pram = r->start;
++ pram = (u32)ioremap(r->start, r->end - r->start + 1);
+
+ if(idx > fsid_smc2_uart) {
+ pinfo->sccp = (scc_t *)mem;
+@@ -1179,7 +1182,7 @@ static int __init cpm_uart_console_setup
+ pdata = pdev->dev.platform_data;
+ if (pdata)
+ if (pdata->init_ioports)
+- pdata->init_ioports();
++ pdata->init_ioports(pdata);
+
+ cpm_uart_drv_get_platform_data(pdev, 1);
+ }
+@@ -1189,11 +1192,7 @@ static int __init cpm_uart_console_setup
+ if (options) {
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ } else {
+- bd_t *bd = (bd_t *) __res;
+-
+- if (bd->bi_baudrate)
+- baud = bd->bi_baudrate;
+- else
++ if ((baud = uart_baudrate()) == -1)
+ baud = 9600;
+ }
+
+@@ -1266,13 +1265,14 @@ static int cpm_uart_drv_probe(struct dev
+ }
+
+ pdata = pdev->dev.platform_data;
+- pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no));
+
+ if ((ret = cpm_uart_drv_get_platform_data(pdev, 0)))
+ return ret;
+
++ pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no));
++
+ if (pdata->init_ioports)
+- pdata->init_ioports();
++ pdata->init_ioports(pdata);
+
+ ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port);
+
+diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+index 5d867ab..5eb49ea 100644
+--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
++++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/serial/cpm_uart_cpm1.h
++ * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ *
+diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+index ef3bb47..b691d3e 100644
+--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
++++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+@@ -40,6 +40,7 @@
+
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/fs_pd.h>
+
+ #include <linux/serial_core.h>
+ #include <linux/kernel.h>
+@@ -50,8 +51,9 @@
+
+ void cpm_line_cr_cmd(int line, int cmd)
+ {
+- volatile cpm_cpm2_t *cp = cpmp;
+ ulong val;
++ volatile cpm_cpm2_t *cp = cpm2_map(im_cpm);
++
+
+ switch (line) {
+ case UART_SMC1:
+@@ -84,11 +86,14 @@ void cpm_line_cr_cmd(int line, int cmd)
+ }
+ cp->cp_cpcr = val;
+ while (cp->cp_cpcr & CPM_CR_FLG) ;
++
++ cpm2_unmap(cp);
+ }
+
+ void smc1_lineif(struct uart_cpm_port *pinfo)
+ {
+- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
++ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
++ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
+
+ /* SMC1 is only on port D */
+ io->iop_ppard |= 0x00c00000;
+@@ -97,13 +102,17 @@ void smc1_lineif(struct uart_cpm_port *p
+ io->iop_psord &= ~0x00c00000;
+
+ /* Wire BRG1 to SMC1 */
+- cpm2_immr->im_cpmux.cmx_smr &= 0x0f;
++ cpmux->cmx_smr &= 0x0f;
+ pinfo->brg = 1;
++
++ cpm2_unmap(cpmux);
++ cpm2_unmap(io);
+ }
+
+ void smc2_lineif(struct uart_cpm_port *pinfo)
+ {
+- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
++ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
++ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
+
+ /* SMC2 is only on port A */
+ io->iop_ppara |= 0x00c00000;
+@@ -112,13 +121,17 @@ void smc2_lineif(struct uart_cpm_port *p
+ io->iop_psora &= ~0x00c00000;
+
+ /* Wire BRG2 to SMC2 */
+- cpm2_immr->im_cpmux.cmx_smr &= 0xf0;
++ cpmux->cmx_smr &= 0xf0;
+ pinfo->brg = 2;
++
++ cpm2_unmap(cpmux);
++ cpm2_unmap(io);
+ }
+
+ void scc1_lineif(struct uart_cpm_port *pinfo)
+ {
+- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
++ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
++ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
+
+ /* Use Port D for SCC1 instead of other functions. */
+ io->iop_ppard |= 0x00000003;
+@@ -128,9 +141,12 @@ void scc1_lineif(struct uart_cpm_port *p
+ io->iop_pdird |= 0x00000002; /* Tx */
+
+ /* Wire BRG1 to SCC1 */
+- cpm2_immr->im_cpmux.cmx_scr &= 0x00ffffff;
+- cpm2_immr->im_cpmux.cmx_scr |= 0x00000000;
++ cpmux->cmx_scr &= 0x00ffffff;
++ cpmux->cmx_scr |= 0x00000000;
+ pinfo->brg = 1;
++
++ cpm2_unmap(cpmux);
++ cpm2_unmap(io);
+ }
+
+ void scc2_lineif(struct uart_cpm_port *pinfo)
+@@ -143,43 +159,57 @@ void scc2_lineif(struct uart_cpm_port *p
+ * be supported in a sane fashion.
+ */
+ #ifndef CONFIG_STX_GP3
+- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
++ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
++ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
++
+ io->iop_pparb |= 0x008b0000;
+ io->iop_pdirb |= 0x00880000;
+ io->iop_psorb |= 0x00880000;
+ io->iop_pdirb &= ~0x00030000;
+ io->iop_psorb &= ~0x00030000;
+ #endif
+- cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
+- cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
++ cpmux->cmx_scr &= 0xff00ffff;
++ cpmux->cmx_scr |= 0x00090000;
+ pinfo->brg = 2;
++
++ cpm2_unmap(cpmux);
++ cpm2_unmap(io);
+ }
+
+ void scc3_lineif(struct uart_cpm_port *pinfo)
+ {
+- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
++ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
++ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
++
+ io->iop_pparb |= 0x008b0000;
+ io->iop_pdirb |= 0x00880000;
+ io->iop_psorb |= 0x00880000;
+ io->iop_pdirb &= ~0x00030000;
+ io->iop_psorb &= ~0x00030000;
+- cpm2_immr->im_cpmux.cmx_scr &= 0xffff00ff;
+- cpm2_immr->im_cpmux.cmx_scr |= 0x00001200;
++ cpmux->cmx_scr &= 0xffff00ff;
++ cpmux->cmx_scr |= 0x00001200;
+ pinfo->brg = 3;
++
++ cpm2_unmap(cpmux);
++ cpm2_unmap(io);
+ }
+
+ void scc4_lineif(struct uart_cpm_port *pinfo)
+ {
+- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
++ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
++ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
+
+ io->iop_ppard |= 0x00000600;
+ io->iop_psord &= ~0x00000600; /* Tx/Rx */
+ io->iop_pdird &= ~0x00000200; /* Rx */
+ io->iop_pdird |= 0x00000400; /* Tx */
+
+- cpm2_immr->im_cpmux.cmx_scr &= 0xffffff00;
+- cpm2_immr->im_cpmux.cmx_scr |= 0x0000001b;
++ cpmux->cmx_scr &= 0xffffff00;
++ cpmux->cmx_scr |= 0x0000001b;
+ pinfo->brg = 4;
++
++ cpm2_unmap(cpmux);
++ cpm2_unmap(io);
+ }
+
+ /*
+@@ -254,88 +284,103 @@ void cpm_uart_freebuf(struct uart_cpm_po
+ /* Setup any dynamic params in the uart desc */
+ int cpm_uart_init_portdesc(void)
+ {
++#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
++ u32 addr;
++#endif
+ pr_debug("CPM uart[-]:init portdesc\n");
+
+ cpm_uart_nr = 0;
+ #ifdef CONFIG_SERIAL_CPM_SMC1
+- cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
+- cpm_uart_ports[UART_SMC1].smcup =
+- (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
+- *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
++ cpm_uart_ports[UART_SMC1].smcp = (smc_t *) cpm2_map(im_smc[0]);
+ cpm_uart_ports[UART_SMC1].port.mapbase =
+- (unsigned long)&cpm2_immr->im_smc[0];
++ (unsigned long)cpm_uart_ports[UART_SMC1].smcp;
++
++ cpm_uart_ports[UART_SMC1].smcup =
++ (smc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SMC1], PROFF_SMC_SIZE);
++ addr = (u16 *)cpm2_map_size(im_dprambase[PROFF_SMC1_BASE], 2);
++ *addr = PROFF_SMC1;
++ cpm2_unmap(addr);
++
+ cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+ cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+- cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
++ cpm_uart_ports[UART_SMC1].port.uartclk = uart_clock();
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
+ #endif
+
+ #ifdef CONFIG_SERIAL_CPM_SMC2
+- cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
+- cpm_uart_ports[UART_SMC2].smcup =
+- (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
+- *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
++ cpm_uart_ports[UART_SMC2].smcp = (smc_t *) cpm2_map(im_smc[1]);
+ cpm_uart_ports[UART_SMC2].port.mapbase =
+- (unsigned long)&cpm2_immr->im_smc[1];
++ (unsigned long)cpm_uart_ports[UART_SMC2].smcp;
++
++ cpm_uart_ports[UART_SMC2].smcup =
++ (smc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SMC2], PROFF_SMC_SIZE);
++ addr = (u16 *)cpm2_map_size(im_dprambase[PROFF_SMC2_BASE], 2);
++ *addr = PROFF_SMC2;
++ cpm2_unmap(addr);
++
+ cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+ cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+- cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
++ cpm_uart_ports[UART_SMC2].port.uartclk = uart_clock();
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
+ #endif
+
+ #ifdef CONFIG_SERIAL_CPM_SCC1
+- cpm_uart_ports[UART_SCC1].sccp = (scc_t *) & cpm2_immr->im_scc[0];
+- cpm_uart_ports[UART_SCC1].sccup =
+- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC1];
++ cpm_uart_ports[UART_SCC1].sccp = (scc_t *) cpm2_map(im_scc[0]);
+ cpm_uart_ports[UART_SCC1].port.mapbase =
+- (unsigned long)&cpm2_immr->im_scc[0];
++ (unsigned long)cpm_uart_ports[UART_SCC1].sccp;
++ cpm_uart_ports[UART_SCC1].sccup =
++ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC1], PROFF_SCC_SIZE);
++
+ cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
+ ~(UART_SCCM_TX | UART_SCCM_RX);
+ cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+- cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
++ cpm_uart_ports[UART_SCC1].port.uartclk = uart_clock();
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
+ #endif
+
+ #ifdef CONFIG_SERIAL_CPM_SCC2
+- cpm_uart_ports[UART_SCC2].sccp = (scc_t *) & cpm2_immr->im_scc[1];
+- cpm_uart_ports[UART_SCC2].sccup =
+- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC2];
++ cpm_uart_ports[UART_SCC2].sccp = (scc_t *) cpm2_map(im_scc[1]);
+ cpm_uart_ports[UART_SCC2].port.mapbase =
+- (unsigned long)&cpm2_immr->im_scc[1];
++ (unsigned long)cpm_uart_ports[UART_SCC2].sccp;
++ cpm_uart_ports[UART_SCC2].sccup =
++ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC2], PROFF_SCC_SIZE);
++
+ cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
+ ~(UART_SCCM_TX | UART_SCCM_RX);
+ cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+- cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
++ cpm_uart_ports[UART_SCC2].port.uartclk = uart_clock();
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
+ #endif
+
+ #ifdef CONFIG_SERIAL_CPM_SCC3
+- cpm_uart_ports[UART_SCC3].sccp = (scc_t *) & cpm2_immr->im_scc[2];
+- cpm_uart_ports[UART_SCC3].sccup =
+- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC3];
++ cpm_uart_ports[UART_SCC3].sccp = (scc_t *) cpm2_map(im_scc[2]);
+ cpm_uart_ports[UART_SCC3].port.mapbase =
+- (unsigned long)&cpm2_immr->im_scc[2];
++ (unsigned long)cpm_uart_ports[UART_SCC3].sccp;
++ cpm_uart_ports[UART_SCC3].sccup =
++ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC3], PROFF_SCC_SIZE);
++
+ cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
+ ~(UART_SCCM_TX | UART_SCCM_RX);
+ cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+- cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
++ cpm_uart_ports[UART_SCC3].port.uartclk = uart_clock();
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
+ #endif
+
+ #ifdef CONFIG_SERIAL_CPM_SCC4
+- cpm_uart_ports[UART_SCC4].sccp = (scc_t *) & cpm2_immr->im_scc[3];
+- cpm_uart_ports[UART_SCC4].sccup =
+- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC4];
++ cpm_uart_ports[UART_SCC4].sccp = (scc_t *) cpm2_map(im_scc[3]);
+ cpm_uart_ports[UART_SCC4].port.mapbase =
+- (unsigned long)&cpm2_immr->im_scc[3];
++ (unsigned long)cpm_uart_ports[UART_SCC4].sccp;
++ cpm_uart_ports[UART_SCC4].sccup =
++ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC4], PROFF_SCC_SIZE);
++
+ cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
+ ~(UART_SCCM_TX | UART_SCCM_RX);
+ cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+- cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
++ cpm_uart_ports[UART_SCC4].port.uartclk = uart_clock();
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
+ #endif
+
+diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+index 4793fec..4b77911 100644
+--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
++++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/serial/cpm_uart_cpm2.h
++ * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ *
+@@ -40,6 +40,6 @@ static inline void cpm_set_smc_fcr(volat
+ up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+ }
+
+-#define DPRAM_BASE ((unsigned char *)&cpm2_immr->im_dprambase[0])
++#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0))
+
+ #endif
+diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
+index cabd048..7a24e53 100644
+--- a/drivers/serial/crisv10.c
++++ b/drivers/serial/crisv10.c
+@@ -2346,7 +2346,7 @@ start_receive(struct e100_serial *info)
+ */
+
+ static irqreturn_t
+-tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++tr_interrupt(int irq, void *dev_id)
+ {
+ struct e100_serial *info;
+ unsigned long ireg;
+@@ -2395,7 +2395,7 @@ tr_interrupt(int irq, void *dev_id, stru
+ /* dma input channel interrupt handler */
+
+ static irqreturn_t
+-rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++rec_interrupt(int irq, void *dev_id)
+ {
+ struct e100_serial *info;
+ unsigned long ireg;
+@@ -3054,7 +3054,7 @@ static void handle_ser_tx_interrupt(stru
+ * ser_int duration: just sending: 8-15 us normally, up to 73 us
+ */
+ static irqreturn_t
+-ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++ser_interrupt(int irq, void *dev_id)
+ {
+ static volatile int tx_started = 0;
+ struct e100_serial *info;
+@@ -4825,7 +4825,7 @@ show_serial_version(void)
+
+ /* rs_init inits the driver at boot (using the module_init chain) */
+
+-static struct tty_operations rs_ops = {
++static const struct tty_operations rs_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
+index 8a98aae..53662b3 100644
+--- a/drivers/serial/dz.c
++++ b/drivers/serial/dz.c
+@@ -339,7 +339,7 @@ static inline void check_modem_status(st
+ * It deals with the multiple ports.
+ * ------------------------------------------------------------
+ */
+-static irqreturn_t dz_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t dz_interrupt(int irq, void *dev)
+ {
+ struct dz_port *dport;
+ unsigned short status;
+diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
+index a3c00a2..8aa0f64 100644
+--- a/drivers/serial/icom.c
++++ b/drivers/serial/icom.c
+@@ -844,8 +844,7 @@ static void process_interrupt(u16 port_i
+ spin_unlock(&icom_port->uart_port.lock);
+ }
+
+-static irqreturn_t icom_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t icom_interrupt(int irq, void *dev_id)
+ {
+ void __iomem * int_reg;
+ u32 adapter_interrupts;
+diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
+index 4a142d6..ee5c782 100644
+--- a/drivers/serial/imx.c
++++ b/drivers/serial/imx.c
+@@ -182,7 +182,7 @@ static void imx_start_tx(struct uart_por
+ imx_transmit_buffer(sport);
+ }
+
+-static irqreturn_t imx_rtsint(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t imx_rtsint(int irq, void *dev_id)
+ {
+ struct imx_port *sport = (struct imx_port *)dev_id;
+ unsigned int val = USR1((u32)sport->port.membase)&USR1_RTSS;
+@@ -198,7 +198,7 @@ static irqreturn_t imx_rtsint(int irq, v
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t imx_txint(int irq, void *dev_id)
+ {
+ struct imx_port *sport = (struct imx_port *)dev_id;
+ struct circ_buf *xmit = &sport->port.info->xmit;
+@@ -227,7 +227,7 @@ out:
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t imx_rxint(int irq, void *dev_id)
+ {
+ struct imx_port *sport = dev_id;
+ unsigned int rx,flg,ignored = 0;
+@@ -248,7 +248,7 @@ static irqreturn_t imx_rxint(int irq, vo
+ }
+
+ if (uart_handle_sysrq_char
+- (&sport->port, (unsigned char)rx, regs))
++ (&sport->port, (unsigned char)rx))
+ goto ignore_char;
+
+ if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) )
+diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
+index 8097cd9..2308d26 100644
+--- a/drivers/serial/ioc3_serial.c
++++ b/drivers/serial/ioc3_serial.c
+@@ -1428,13 +1428,12 @@ static int receive_chars(struct uart_por
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+- * @regs: pt_regs
+ */
+
+ static int inline
+ ioc3uart_intr_one(struct ioc3_submodule *is,
+ struct ioc3_driver_data *idd,
+- unsigned int pending, struct pt_regs *regs)
++ unsigned int pending)
+ {
+ int port_num = GET_PORT_FROM_SIO_IR(pending);
+ struct port_hooks *hooks;
+@@ -1628,13 +1627,12 @@ ioc3uart_intr_one(struct ioc3_submodule
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+- * @regs: pt_regs
+ *
+ */
+
+ static int ioc3uart_intr(struct ioc3_submodule *is,
+ struct ioc3_driver_data *idd,
+- unsigned int pending, struct pt_regs *regs)
++ unsigned int pending)
+ {
+ int ret = 0;
+
+@@ -1644,9 +1642,9 @@ static int ioc3uart_intr(struct ioc3_sub
+ */
+
+ if (pending & SIO_IR_SA)
+- ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA, regs);
++ ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
+ if (pending & SIO_IR_SB)
+- ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB, regs);
++ ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
+
+ return ret;
+ }
+diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
+index 576ca1e..711bd15 100644
+--- a/drivers/serial/ioc4_serial.c
++++ b/drivers/serial/ioc4_serial.c
+@@ -921,7 +921,7 @@ static void handle_dma_error_intr(void *
+ {
+ struct ioc4_port *port = (struct ioc4_port *)arg;
+ struct hooks *hooks = port->ip_hooks;
+- unsigned int flags;
++ unsigned long flags;
+
+ spin_lock_irqsave(&port->ip_lock, flags);
+
+@@ -987,10 +987,9 @@ intr_connect(struct ioc4_soft *soft, int
+ * ioc4_intr - Top level IOC4 interrupt handler.
+ * @irq: irq value
+ * @arg: handler arg
+- * @regs: registers
+ */
+
+-static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t ioc4_intr(int irq, void *arg)
+ {
+ struct ioc4_soft *soft;
+ uint32_t this_ir, this_mir;
+@@ -1835,7 +1834,7 @@ static void handle_intr(void *arg, uint3
+ struct ioc4_port *port = (struct ioc4_port *)arg;
+ struct hooks *hooks = port->ip_hooks;
+ unsigned int rx_high_rd_aborted = 0;
+- unsigned int flags;
++ unsigned long flags;
+ struct uart_port *the_port;
+ int loop_counter;
+
+@@ -2685,6 +2684,7 @@ static int ioc4_serial_remove_one(struct
+ if (soft) {
+ free_irq(control->ic_irq, soft);
+ if (soft->is_ioc4_serial_addr) {
++ iounmap(soft->is_ioc4_serial_addr);
+ release_region((unsigned long)
+ soft->is_ioc4_serial_addr,
+ sizeof(struct ioc4_serial));
+@@ -2887,6 +2887,8 @@ out4:
+ out3:
+ kfree(control);
+ out2:
++ if (serial)
++ iounmap(serial);
+ release_region(tmp_addr1, sizeof(struct ioc4_serial));
+ out1:
+
+@@ -2933,7 +2935,7 @@ static void __devexit ioc4_serial_exit(v
+ uart_unregister_driver(&ioc4_uart_rs422);
+ }
+
+-module_init(ioc4_serial_init);
++late_initcall(ioc4_serial_init); /* Call only after tty init is done */
+ module_exit(ioc4_serial_exit);
+
+ MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg at sgi.com>");
+diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
+index 5ff269f..dca6c1b 100644
+--- a/drivers/serial/ip22zilog.c
++++ b/drivers/serial/ip22zilog.c
+@@ -252,8 +252,7 @@ static void ip22zilog_maybe_update_regs(
+ }
+
+ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
+- struct zilog_channel *channel,
+- struct pt_regs *regs)
++ struct zilog_channel *channel)
+ {
+ struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */
+
+@@ -319,7 +318,7 @@ static void ip22zilog_receive_chars(stru
+ else if (r1 & CRC_ERR)
+ flag = TTY_FRAME;
+ }
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ goto next_char;
+
+ if (up->port.ignore_status_mask == 0xff ||
+@@ -339,8 +338,7 @@ static void ip22zilog_receive_chars(stru
+ }
+
+ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
+- struct zilog_channel *channel,
+- struct pt_regs *regs)
++ struct zilog_channel *channel)
+ {
+ unsigned char status;
+
+@@ -443,7 +441,7 @@ ack_tx_int:
+ ZS_WSYNC(channel);
+ }
+
+-static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
+ {
+ struct uart_ip22zilog_port *up = dev_id;
+
+@@ -462,9 +460,9 @@ static irqreturn_t ip22zilog_interrupt(i
+ ZS_WSYNC(channel);
+
+ if (r3 & CHARxIP)
+- ip22zilog_receive_chars(up, channel, regs);
++ ip22zilog_receive_chars(up, channel);
+ if (r3 & CHAEXT)
+- ip22zilog_status_handle(up, channel, regs);
++ ip22zilog_status_handle(up, channel);
+ if (r3 & CHATxIP)
+ ip22zilog_transmit_chars(up, channel);
+ }
+@@ -481,9 +479,9 @@ static irqreturn_t ip22zilog_interrupt(i
+ ZS_WSYNC(channel);
+
+ if (r3 & CHBRxIP)
+- ip22zilog_receive_chars(up, channel, regs);
++ ip22zilog_receive_chars(up, channel);
+ if (r3 & CHBEXT)
+- ip22zilog_status_handle(up, channel, regs);
++ ip22zilog_status_handle(up, channel);
+ if (r3 & CHBTxIP)
+ ip22zilog_transmit_chars(up, channel);
+ }
+@@ -1229,13 +1227,27 @@ static int __init ip22zilog_init(void)
+ static void __exit ip22zilog_exit(void)
+ {
+ int i;
++ struct uart_ip22zilog_port *up;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+- struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
++ up = &ip22zilog_port_table[i];
+
+ uart_remove_one_port(&ip22zilog_reg, &up->port);
+ }
+
++ /* Free IO mem */
++ up = &ip22zilog_port_table[0];
++ for (i = 0; i < NUM_IP22ZILOG; i++) {
++ if (up[(i * 2) + 0].port.mapbase) {
++ iounmap((void*)up[(i * 2) + 0].port.mapbase);
++ up[(i * 2) + 0].port.mapbase = 0;
++ }
++ if (up[(i * 2) + 1].port.mapbase) {
++ iounmap((void*)up[(i * 2) + 1].port.mapbase);
++ up[(i * 2) + 1].port.mapbase = 0;
++ }
++ }
++
+ uart_unregister_driver(&ip22zilog_reg);
+ }
+
+diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
+index 043f50b..12c934a 100644
+--- a/drivers/serial/jsm/jsm.h
++++ b/drivers/serial/jsm/jsm.h
+@@ -99,7 +99,7 @@ struct jsm_channel;
+ * Per board operations structure *
+ ************************************************************************/
+ struct board_ops {
+- irqreturn_t (*intr) (int irq, void *voidbrd, struct pt_regs *regs);
++ irq_handler_t intr;
+ void (*uart_init) (struct jsm_channel *ch);
+ void (*uart_off) (struct jsm_channel *ch);
+ void (*param) (struct jsm_channel *ch);
+diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
+index a5fc589..8be8da3 100644
+--- a/drivers/serial/jsm/jsm_neo.c
++++ b/drivers/serial/jsm/jsm_neo.c
+@@ -1114,9 +1114,9 @@ static void neo_param(struct jsm_channel
+ *
+ * Neo specific interrupt handler.
+ */
+-static irqreturn_t neo_intr(int irq, void *voidbrd, struct pt_regs *regs)
++static irqreturn_t neo_intr(int irq, void *voidbrd)
+ {
+- struct jsm_board *brd = (struct jsm_board *) voidbrd;
++ struct jsm_board *brd = voidbrd;
+ struct jsm_channel *ch;
+ int port = 0;
+ int type = 0;
+diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
+index e7fe4bb..7656a35 100644
+--- a/drivers/serial/m32r_sio.c
++++ b/drivers/serial/m32r_sio.c
+@@ -76,7 +76,7 @@
+ */
+ #define is_real_interrupt(irq) ((irq) != 0)
+
+-#include <asm/serial.h>
++#define BASE_BAUD 115200
+
+ /* Standard COM flags */
+ #define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+@@ -86,7 +86,6 @@
+ * standard enumeration mechanism. Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
+ */
+-#undef SERIAL_PORT_DFNS
+ #if defined(CONFIG_PLAT_USRV)
+
+ #define SERIAL_PORT_DFNS \
+@@ -109,7 +108,7 @@
+ #endif /* !CONFIG_PLAT_USRV */
+
+ static struct old_serial_port old_serial_port[] = {
+- SERIAL_PORT_DFNS /* defined in asm/serial.h */
++ SERIAL_PORT_DFNS
+ };
+
+ #define UART_NR ARRAY_SIZE(old_serial_port)
+@@ -324,8 +323,7 @@ static void m32r_sio_enable_ms(struct ua
+ serial_out(up, UART_IER, up->ier);
+ }
+
+-static void receive_chars(struct uart_sio_port *up, int *status,
+- struct pt_regs *regs)
++static void receive_chars(struct uart_sio_port *up, int *status)
+ {
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned char ch;
+@@ -379,7 +377,7 @@ static void receive_chars(struct uart_si
+ else if (*status & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ goto ignore_char;
+ if ((*status & up->port.ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+@@ -440,12 +438,12 @@ static void transmit_chars(struct uart_s
+ * This handles the interrupt from one port.
+ */
+ static inline void m32r_sio_handle_port(struct uart_sio_port *up,
+- unsigned int status, struct pt_regs *regs)
++ unsigned int status)
+ {
+ DEBUG_INTR("status = %x...", status);
+
+ if (status & 0x04)
+- receive_chars(up, &status, regs);
++ receive_chars(up, &status);
+ if (status & 0x01)
+ transmit_chars(up);
+ }
+@@ -464,8 +462,7 @@ static inline void m32r_sio_handle_port(
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+-static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
+ {
+ struct irq_info *i = dev_id;
+ struct list_head *l, *end = NULL;
+@@ -493,7 +490,7 @@ static irqreturn_t m32r_sio_interrupt(in
+ sts = sio_in(up, SIOSTS);
+ if (sts & 0x5) {
+ spin_lock(&up->port.lock);
+- m32r_sio_handle_port(up, sts, regs);
++ m32r_sio_handle_port(up, sts);
+ spin_unlock(&up->port.lock);
+
+ end = NULL;
+@@ -593,7 +590,7 @@ static void m32r_sio_timeout(unsigned lo
+ sts = sio_in(up, SIOSTS);
+ if (sts & 0x5) {
+ spin_lock(&up->port.lock);
+- m32r_sio_handle_port(up, sts, NULL);
++ m32r_sio_handle_port(up, sts);
+ spin_unlock(&up->port.lock);
+ }
+
+diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
+index 832abd3..aee1b31 100644
+--- a/drivers/serial/mcfserial.c
++++ b/drivers/serial/mcfserial.c
+@@ -385,7 +385,7 @@ static inline void transmit_chars(struct
+ /*
+ * This is the serial driver's generic interrupt routine
+ */
+-irqreturn_t mcfrs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
+ {
+ struct mcf_serial *info;
+ unsigned char isr;
+@@ -1666,7 +1666,7 @@ static void show_serial_version(void)
+ printk(mcfrs_drivername);
+ }
+
+-static struct tty_operations mcfrs_ops = {
++static const struct tty_operations mcfrs_ops = {
+ .open = mcfrs_open,
+ .close = mcfrs_close,
+ .write = mcfrs_write,
+diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
+index 7708e5d..4f80c5b 100644
+--- a/drivers/serial/mpc52xx_uart.c
++++ b/drivers/serial/mpc52xx_uart.c
+@@ -85,7 +85,7 @@ static struct uart_port mpc52xx_uart_por
+
+
+ /* Forward declaration of the interruption handling routine */
+-static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs);
++static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
+
+
+ /* Simple macro to test if a port is console or not. This one is taken
+@@ -338,14 +338,23 @@ mpc52xx_uart_release_port(struct uart_po
+ static int
+ mpc52xx_uart_request_port(struct uart_port *port)
+ {
++ int err;
++
+ if (port->flags & UPF_IOREMAP) /* Need to remap ? */
+ port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
+
+ if (!port->membase)
+ return -EINVAL;
+
+- return request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
++ err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
+ "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
++
++ if (err && (port->flags & UPF_IOREMAP)) {
++ iounmap(port->membase);
++ port->membase = NULL;
++ }
++
++ return err;
+ }
+
+ static void
+@@ -401,7 +410,7 @@ static struct uart_ops mpc52xx_uart_ops
+ /* ======================================================================== */
+
+ static inline int
+-mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
++mpc52xx_uart_int_rx_chars(struct uart_port *port)
+ {
+ struct tty_struct *tty = port->info->tty;
+ unsigned char ch, flag;
+@@ -416,7 +425,7 @@ mpc52xx_uart_int_rx_chars(struct uart_po
+
+ /* Handle sysreq char */
+ #ifdef SUPPORT_SYSRQ
+- if (uart_handle_sysrq_char(port, ch, regs)) {
++ if (uart_handle_sysrq_char(port, ch)) {
+ port->sysrq = 0;
+ continue;
+ }
+@@ -501,21 +510,13 @@ mpc52xx_uart_int_tx_chars(struct uart_po
+ }
+
+ static irqreturn_t
+-mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs)
++mpc52xx_uart_int(int irq, void *dev_id)
+ {
+- struct uart_port *port = (struct uart_port *) dev_id;
++ struct uart_port *port = dev_id;
+ unsigned long pass = ISR_PASS_LIMIT;
+ unsigned int keepgoing;
+ unsigned short status;
+
+- if ( irq != port->irq ) {
+- printk( KERN_WARNING
+- "mpc52xx_uart_int : " \
+- "Received wrong int %d. Waiting for %d\n",
+- irq, port->irq);
+- return IRQ_NONE;
+- }
+-
+ spin_lock(&port->lock);
+
+ /* While we have stuff to do, we continue */
+@@ -530,7 +531,7 @@ mpc52xx_uart_int(int irq, void *dev_id,
+ /* Do we need to receive chars ? */
+ /* For this RX interrupts must be on and some chars waiting */
+ if ( status & MPC52xx_PSC_IMR_RXRDY )
+- keepgoing |= mpc52xx_uart_int_rx_chars(port, regs);
++ keepgoing |= mpc52xx_uart_int_rx_chars(port);
+
+ /* Do we need to send chars ? */
+ /* For this, TX must be ready and TX interrupt enabled */
+diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
+index 63d2a66..8eea69f 100644
+--- a/drivers/serial/mpsc.c
++++ b/drivers/serial/mpsc.c
+@@ -992,7 +992,7 @@ mpsc_make_ready(struct mpsc_port_info *p
+ */
+
+ static inline int
+-mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs)
++mpsc_rx_intr(struct mpsc_port_info *pi)
+ {
+ struct mpsc_rx_desc *rxre;
+ struct tty_struct *tty = pi->port.info->tty;
+@@ -1072,7 +1072,7 @@ mpsc_rx_intr(struct mpsc_port_info *pi,
+ flag = TTY_PARITY;
+ }
+
+- if (uart_handle_sysrq_char(&pi->port, *bp, regs)) {
++ if (uart_handle_sysrq_char(&pi->port, *bp)) {
+ bp++;
+ bytes_in--;
+ goto next_frame;
+@@ -1257,7 +1257,7 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
+ * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
+ */
+ static irqreturn_t
+-mpsc_sdma_intr(int irq, void *dev_id, struct pt_regs *regs)
++mpsc_sdma_intr(int irq, void *dev_id)
+ {
+ struct mpsc_port_info *pi = dev_id;
+ ulong iflags;
+@@ -1267,7 +1267,7 @@ mpsc_sdma_intr(int irq, void *dev_id, st
+
+ spin_lock_irqsave(&pi->port.lock, iflags);
+ mpsc_sdma_intr_ack(pi);
+- if (mpsc_rx_intr(pi, regs))
++ if (mpsc_rx_intr(pi))
+ rc = IRQ_HANDLED;
+ if (mpsc_tx_intr(pi))
+ rc = IRQ_HANDLED;
+@@ -1893,6 +1893,10 @@ mpsc_drv_map_regs(struct mpsc_port_info
+ }
+ else {
+ mpsc_resource_err("SDMA base");
++ if (pi->mpsc_base) {
++ iounmap(pi->mpsc_base);
++ pi->mpsc_base = NULL;
++ }
+ return -ENOMEM;
+ }
+
+@@ -1905,6 +1909,14 @@ mpsc_drv_map_regs(struct mpsc_port_info
+ }
+ else {
+ mpsc_resource_err("BRG base");
++ if (pi->mpsc_base) {
++ iounmap(pi->mpsc_base);
++ pi->mpsc_base = NULL;
++ }
++ if (pi->sdma_base) {
++ iounmap(pi->sdma_base);
++ pi->sdma_base = NULL;
++ }
+ return -ENOMEM;
+ }
+
+diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
+index 4a1c998..8ad1b8c 100644
+--- a/drivers/serial/mux.c
++++ b/drivers/serial/mux.c
+@@ -230,7 +230,7 @@ static void mux_read(struct uart_port *p
+ continue;
+ }
+
+- if (uart_handle_sysrq_char(port, data & 0xffu, NULL))
++ if (uart_handle_sysrq_char(port, data & 0xffu))
+ continue;
+
+ tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+@@ -521,6 +521,8 @@ static void __exit mux_exit(void)
+
+ for (i = 0; i < port_cnt; i++) {
+ uart_remove_one_port(&mux_driver, &mux_ports[i]);
++ if (mux_ports[i].membase)
++ iounmap(mux_ports[i].membase);
+ }
+
+ uart_unregister_driver(&mux_driver);
+diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
+index c1adc9e..062bad4 100644
+--- a/drivers/serial/netx-serial.c
++++ b/drivers/serial/netx-serial.c
+@@ -17,8 +17,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/config.h>
+-
+ #if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+@@ -202,7 +200,7 @@ static void netx_txint(struct uart_port
+ uart_write_wakeup(port);
+ }
+
+-static void netx_rxint(struct uart_port *port, struct pt_regs *regs)
++static void netx_rxint(struct uart_port *port)
+ {
+ unsigned char rx, flg, status;
+ struct tty_struct *tty = port->info->tty;
+@@ -237,7 +235,7 @@ static void netx_rxint(struct uart_port
+ flg = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char(port, rx, regs))
++ if (uart_handle_sysrq_char(port, rx))
+ continue;
+
+ uart_insert_char(port, status, SR_OE, rx, flg);
+@@ -247,9 +245,9 @@ static void netx_rxint(struct uart_port
+ return;
+ }
+
+-static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t netx_int(int irq, void *dev_id)
+ {
+- struct uart_port *port = (struct uart_port *)dev_id;
++ struct uart_port *port = dev_id;
+ unsigned long flags;
+ unsigned char status;
+
+@@ -258,7 +256,7 @@ static irqreturn_t netx_int(int irq, voi
+ status = readl(port->membase + UART_IIR) & IIR_MASK;
+ while (status) {
+ if (status & IIR_RIS)
+- netx_rxint(port, regs);
++ netx_rxint(port);
+ if (status & IIR_TIS)
+ netx_txint(port);
+ if (status & IIR_MIS) {
+diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
+index bfd2a22..bf9809e 100644
+--- a/drivers/serial/pmac_zilog.c
++++ b/drivers/serial/pmac_zilog.c
+@@ -204,8 +204,7 @@ static void pmz_maybe_update_regs(struct
+ }
+ }
+
+-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
+- struct pt_regs *regs)
++static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
+ {
+ struct tty_struct *tty = NULL;
+ unsigned char ch, r1, drop, error, flag;
+@@ -267,7 +266,7 @@ static struct tty_struct *pmz_receive_ch
+ if (uap->port.sysrq) {
+ int swallow;
+ spin_unlock(&uap->port.lock);
+- swallow = uart_handle_sysrq_char(&uap->port, ch, regs);
++ swallow = uart_handle_sysrq_char(&uap->port, ch);
+ spin_lock(&uap->port.lock);
+ if (swallow)
+ goto next_char;
+@@ -335,7 +334,7 @@ static struct tty_struct *pmz_receive_ch
+ return tty;
+ }
+
+-static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs)
++static void pmz_status_handle(struct uart_pmac_port *uap)
+ {
+ unsigned char status;
+
+@@ -438,7 +437,7 @@ ack_tx_int:
+ }
+
+ /* Hrm... we register that twice, fixme later.... */
+-static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pmz_interrupt(int irq, void *dev_id)
+ {
+ struct uart_pmac_port *uap = dev_id;
+ struct uart_pmac_port *uap_a;
+@@ -462,9 +461,9 @@ static irqreturn_t pmz_interrupt(int irq
+ write_zsreg(uap_a, R0, RES_H_IUS);
+ zssync(uap_a);
+ if (r3 & CHAEXT)
+- pmz_status_handle(uap_a, regs);
++ pmz_status_handle(uap_a);
+ if (r3 & CHARxIP)
+- tty = pmz_receive_chars(uap_a, regs);
++ tty = pmz_receive_chars(uap_a);
+ if (r3 & CHATxIP)
+ pmz_transmit_chars(uap_a);
+ rc = IRQ_HANDLED;
+@@ -482,9 +481,9 @@ static irqreturn_t pmz_interrupt(int irq
+ write_zsreg(uap_b, R0, RES_H_IUS);
+ zssync(uap_b);
+ if (r3 & CHBEXT)
+- pmz_status_handle(uap_b, regs);
++ pmz_status_handle(uap_b);
+ if (r3 & CHBRxIP)
+- tty = pmz_receive_chars(uap_b, regs);
++ tty = pmz_receive_chars(uap_b);
+ if (r3 & CHBTxIP)
+ pmz_transmit_chars(uap_b);
+ rc = IRQ_HANDLED;
+@@ -1400,8 +1399,8 @@ static struct uart_ops pmz_pops = {
+ static int __init pmz_init_port(struct uart_pmac_port *uap)
+ {
+ struct device_node *np = uap->node;
+- char *conn;
+- struct slot_names_prop {
++ const char *conn;
++ const struct slot_names_prop {
+ int count;
+ char name[1];
+ } *slots;
+@@ -1458,7 +1457,7 @@ no_dma:
+ uap->flags |= PMACZILOG_FLAG_IS_IRDA;
+ uap->port_type = PMAC_SCC_ASYNC;
+ /* 1999 Powerbook G3 has slot-names property instead */
+- slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
++ slots = get_property(np, "slot-names", &len);
+ if (slots && slots->count > 0) {
+ if (strcmp(slots->name, "IrDA") == 0)
+ uap->flags |= PMACZILOG_FLAG_IS_IRDA;
+@@ -1470,7 +1469,8 @@ no_dma:
+ if (ZS_IS_INTMODEM(uap)) {
+ struct device_node* i2c_modem = find_devices("i2c-modem");
+ if (i2c_modem) {
+- char* mid = get_property(i2c_modem, "modem-id", NULL);
++ const char* mid =
++ get_property(i2c_modem, "modem-id", NULL);
+ if (mid) switch(*mid) {
+ case 0x04 :
+ case 0x05 :
+diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
+index a720953..415fe96 100644
+--- a/drivers/serial/pxa.c
++++ b/drivers/serial/pxa.c
+@@ -98,8 +98,7 @@ static void serial_pxa_stop_rx(struct ua
+ serial_out(up, UART_IER, up->ier);
+ }
+
+-static inline void
+-receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
++static inline void receive_chars(struct uart_pxa_port *up, int *status)
+ {
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int ch, flag;
+@@ -153,7 +152,7 @@ receive_chars(struct uart_pxa_port *up,
+ flag = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ goto ignore_char;
+
+ uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+@@ -231,10 +230,9 @@ static inline void check_modem_status(st
+ /*
+ * This handles the interrupt from one port.
+ */
+-static inline irqreturn_t
+-serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs)
++static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
+ {
+- struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id;
++ struct uart_pxa_port *up = dev_id;
+ unsigned int iir, lsr;
+
+ iir = serial_in(up, UART_IIR);
+@@ -242,7 +240,7 @@ serial_pxa_irq(int irq, void *dev_id, st
+ return IRQ_NONE;
+ lsr = serial_in(up, UART_LSR);
+ if (lsr & UART_LSR_DR)
+- receive_chars(up, &lsr, regs);
++ receive_chars(up, &lsr);
+ check_modem_status(up);
+ if (lsr & UART_LSR_THRE)
+ transmit_chars(up);
+diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
+index 95738a1..8dfc2dd 100644
+--- a/drivers/serial/s3c2410.c
++++ b/drivers/serial/s3c2410.c
+@@ -310,7 +310,7 @@ static int s3c24xx_serial_rx_fifocnt(str
+ #define S3C2410_UERSTAT_PARITY (0x1000)
+
+ static irqreturn_t
+-s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
++s3c24xx_serial_rx_chars(int irq, void *dev_id)
+ {
+ struct s3c24xx_uart_port *ourport = dev_id;
+ struct uart_port *port = &ourport->port;
+@@ -379,7 +379,7 @@ s3c24xx_serial_rx_chars(int irq, void *d
+ flag = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char(port, ch, regs))
++ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
+@@ -393,7 +393,7 @@ s3c24xx_serial_rx_chars(int irq, void *d
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *regs)
++static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
+ {
+ struct s3c24xx_uart_port *ourport = id;
+ struct uart_port *port = &ourport->port;
+diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
+index db3486d..d406526 100644
+--- a/drivers/serial/sa1100.c
++++ b/drivers/serial/sa1100.c
+@@ -190,7 +190,7 @@ static void sa1100_enable_ms(struct uart
+ }
+
+ static void
+-sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
++sa1100_rx_chars(struct sa1100_port *sport)
+ {
+ struct tty_struct *tty = sport->port.info->tty;
+ unsigned int status, ch, flg;
+@@ -228,7 +228,7 @@ sa1100_rx_chars(struct sa1100_port *spor
+ #endif
+ }
+
+- if (uart_handle_sysrq_char(&sport->port, ch, regs))
++ if (uart_handle_sysrq_char(&sport->port, ch))
+ goto ignore_char;
+
+ uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
+@@ -281,7 +281,7 @@ static void sa1100_tx_chars(struct sa110
+ sa1100_stop_tx(&sport->port);
+ }
+
+-static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sa1100_int(int irq, void *dev_id)
+ {
+ struct sa1100_port *sport = dev_id;
+ unsigned int status, pass_counter = 0;
+@@ -294,7 +294,7 @@ static irqreturn_t sa1100_int(int irq, v
+ /* Clear the receiver idle bit, if set */
+ if (status & UTSR0_RID)
+ UART_PUT_UTSR0(sport, UTSR0_RID);
+- sa1100_rx_chars(sport, regs);
++ sa1100_rx_chars(sport);
+ }
+
+ /* Clear the relevant break bits */
+diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
+index 372e47f..c67b05e 100644
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -792,6 +792,7 @@ static int uart_set_info(struct uart_sta
+ * We failed anyway.
+ */
+ retval = -EBUSY;
++ goto exit; // Added to return the correct error -Ram Gupta
+ }
+ }
+
+@@ -1662,16 +1663,16 @@ static int uart_line_info(char *buf, str
+ struct uart_port *port = state->port;
+ char stat_buf[32];
+ unsigned int status;
+- int ret;
++ int mmio, ret;
+
+ if (!port)
+ return 0;
+
++ mmio = port->iotype >= UPIO_MEM;
+ ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d",
+ port->line, uart_type(port),
+- port->iotype == UPIO_MEM ? "mmio:0x" : "port:",
+- port->iotype == UPIO_MEM ? port->mapbase :
+- (unsigned long) port->iobase,
++ mmio ? "mmio:0x" : "port:",
++ mmio ? port->mapbase : (unsigned long) port->iobase,
+ port->irq);
+
+ if (port->type == PORT_UNKNOWN) {
+@@ -1929,9 +1930,19 @@ int uart_suspend_port(struct uart_driver
+
+ mutex_lock(&state->mutex);
+
++#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
++ if (uart_console(port)) {
++ mutex_unlock(&state->mutex);
++ return 0;
++ }
++#endif
++
+ if (state->info && state->info->flags & UIF_INITIALIZED) {
+ const struct uart_ops *ops = port->ops;
+
++ state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
++ | UIF_SUSPENDED;
++
+ spin_lock_irq(&port->lock);
+ ops->stop_tx(port);
+ ops->set_mctrl(port, 0);
+@@ -1967,6 +1978,13 @@ int uart_resume_port(struct uart_driver
+
+ mutex_lock(&state->mutex);
+
++#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
++ if (uart_console(port)) {
++ mutex_unlock(&state->mutex);
++ return 0;
++ }
++#endif
++
+ uart_change_pm(state, 0);
+
+ /*
+@@ -1991,7 +2009,7 @@ int uart_resume_port(struct uart_driver
+ console_start(port->cons);
+ }
+
+- if (state->info && state->info->flags & UIF_INITIALIZED) {
++ if (state->info && state->info->flags & UIF_SUSPENDED) {
+ const struct uart_ops *ops = port->ops;
+ int ret;
+
+@@ -2003,15 +2021,17 @@ int uart_resume_port(struct uart_driver
+ ops->set_mctrl(port, port->mctrl);
+ ops->start_tx(port);
+ spin_unlock_irq(&port->lock);
++ state->info->flags |= UIF_INITIALIZED;
+ } else {
+ /*
+ * Failed to resume - maybe hardware went away?
+ * Clear the "initialized" flag so we won't try
+ * to call the low level drivers shutdown method.
+ */
+- state->info->flags &= ~UIF_INITIALIZED;
+ uart_shutdown(state);
+ }
++
++ state->info->flags &= ~UIF_SUSPENDED;
+ }
+
+ mutex_unlock(&state->mutex);
+@@ -2097,7 +2117,7 @@ uart_configure_port(struct uart_driver *
+ }
+ }
+
+-static struct tty_operations uart_ops = {
++static const struct tty_operations uart_ops = {
+ .open = uart_open,
+ .close = uart_close,
+ .write = uart_write,
+diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
+index cbf260b..00f9ffd 100644
+--- a/drivers/serial/serial_cs.c
++++ b/drivers/serial/serial_cs.c
+@@ -80,23 +80,16 @@ module_param(buggy_uart, int, 0444);
+
+ /* Table of multi-port card ID's */
+
+-struct multi_id {
+- u_short manfid;
+- u_short prodid;
++struct serial_quirk {
++ unsigned int manfid;
++ unsigned int prodid;
+ int multi; /* 1 = multifunction, > 1 = # ports */
++ void (*config)(struct pcmcia_device *);
++ void (*setup)(struct pcmcia_device *, struct uart_port *);
++ void (*wakeup)(struct pcmcia_device *);
++ int (*post)(struct pcmcia_device *);
+ };
+
+-static const struct multi_id multi_id[] = {
+- { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
+- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
+- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+- { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
+- { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
+- { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
+-};
+-#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
+-
+ struct serial_info {
+ struct pcmcia_device *p_dev;
+ int ndev;
+@@ -107,6 +100,7 @@ struct serial_info {
+ int c950ctrl;
+ dev_node_t node[4];
+ int line[4];
++ const struct serial_quirk *quirk;
+ };
+
+ struct serial_cfg_mem {
+@@ -115,37 +109,165 @@ struct serial_cfg_mem {
+ u_char buf[256];
+ };
+
++/*
++ * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
++ * manfid 0x0160, 0x0104
++ * This card appears to have a 14.7456MHz clock.
++ */
++static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
++{
++ port->uartclk = 14745600;
++}
+
+-static int serial_config(struct pcmcia_device * link);
++static int quirk_post_ibm(struct pcmcia_device *link)
++{
++ conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
++ int last_ret, last_fn;
+
++ last_ret = pcmcia_access_configuration_register(link, ®);
++ if (last_ret) {
++ last_fn = AccessConfigurationRegister;
++ goto cs_failed;
++ }
++ reg.Action = CS_WRITE;
++ reg.Value = reg.Value | 1;
++ last_ret = pcmcia_access_configuration_register(link, ®);
++ if (last_ret) {
++ last_fn = AccessConfigurationRegister;
++ goto cs_failed;
++ }
++ return 0;
+
+-static void wakeup_card(struct serial_info *info)
++ cs_failed:
++ cs_error(link, last_fn, last_ret);
++ return -ENODEV;
++}
++
++/*
++ * Nokia cards are not really multiport cards. Shouldn't this
++ * be handled by setting the quirk entry .multi = 0 | 1 ?
++ */
++static void quirk_config_nokia(struct pcmcia_device *link)
+ {
+- int ctrl = info->c950ctrl;
+-
+- if (info->manfid == MANFID_OXSEMI) {
+- outb(12, ctrl + 1);
+- } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
+- /* request_region? oxsemi branch does no request_region too... */
+- /* This sequence is needed to properly initialize MC45 attached to OXCF950.
+- * I tried decreasing these msleep()s, but it worked properly (survived
+- * 1000 stop/start operations) with these timeouts (or bigger). */
+- outb(0xA, ctrl + 1);
+- msleep(100);
+- outb(0xE, ctrl + 1);
+- msleep(300);
+- outb(0xC, ctrl + 1);
+- msleep(100);
+- outb(0xE, ctrl + 1);
+- msleep(200);
+- outb(0xF, ctrl + 1);
+- msleep(100);
+- outb(0xE, ctrl + 1);
+- msleep(100);
+- outb(0xC, ctrl + 1);
++ struct serial_info *info = link->priv;
++
++ if (info->multi > 1)
++ info->multi = 1;
++}
++
++static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
++{
++ struct serial_info *info = link->priv;
++
++ outb(12, info->c950ctrl + 1);
++}
++
++/* request_region? oxsemi branch does no request_region too... */
++/*
++ * This sequence is needed to properly initialize MC45 attached to OXCF950.
++ * I tried decreasing these msleep()s, but it worked properly (survived
++ * 1000 stop/start operations) with these timeouts (or bigger).
++ */
++static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
++{
++ struct serial_info *info = link->priv;
++ unsigned int ctrl = info->c950ctrl;
++
++ outb(0xA, ctrl + 1);
++ msleep(100);
++ outb(0xE, ctrl + 1);
++ msleep(300);
++ outb(0xC, ctrl + 1);
++ msleep(100);
++ outb(0xE, ctrl + 1);
++ msleep(200);
++ outb(0xF, ctrl + 1);
++ msleep(100);
++ outb(0xE, ctrl + 1);
++ msleep(100);
++ outb(0xC, ctrl + 1);
++}
++
++/*
++ * Socket Dual IO: this enables irq's for second port
++ */
++static void quirk_config_socket(struct pcmcia_device *link)
++{
++ struct serial_info *info = link->priv;
++
++ if (info->multi) {
++ link->conf.Present |= PRESENT_EXT_STATUS;
++ link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
+ }
+ }
+
++static const struct serial_quirk quirks[] = {
++ {
++ .manfid = 0x0160,
++ .prodid = 0x0104,
++ .multi = -1,
++ .setup = quirk_setup_brainboxes_0104,
++ }, {
++ .manfid = MANFID_IBM,
++ .prodid = ~0,
++ .multi = -1,
++ .post = quirk_post_ibm,
++ }, {
++ .manfid = MANFID_INTEL,
++ .prodid = PRODID_INTEL_DUAL_RS232,
++ .multi = 2,
++ }, {
++ .manfid = MANFID_NATINST,
++ .prodid = PRODID_NATINST_QUAD_RS232,
++ .multi = 4,
++ }, {
++ .manfid = MANFID_NOKIA,
++ .prodid = ~0,
++ .multi = -1,
++ .config = quirk_config_nokia,
++ }, {
++ .manfid = MANFID_OMEGA,
++ .prodid = PRODID_OMEGA_QSP_100,
++ .multi = 4,
++ }, {
++ .manfid = MANFID_OXSEMI,
++ .prodid = ~0,
++ .multi = -1,
++ .wakeup = quirk_wakeup_oxsemi,
++ }, {
++ .manfid = MANFID_POSSIO,
++ .prodid = PRODID_POSSIO_GCC,
++ .multi = -1,
++ .wakeup = quirk_wakeup_possio_gcc,
++ }, {
++ .manfid = MANFID_QUATECH,
++ .prodid = PRODID_QUATECH_DUAL_RS232,
++ .multi = 2,
++ }, {
++ .manfid = MANFID_QUATECH,
++ .prodid = PRODID_QUATECH_DUAL_RS232_D1,
++ .multi = 2,
++ }, {
++ .manfid = MANFID_QUATECH,
++ .prodid = PRODID_QUATECH_QUAD_RS232,
++ .multi = 4,
++ }, {
++ .manfid = MANFID_SOCKET,
++ .prodid = PRODID_SOCKET_DUAL_RS232,
++ .multi = 2,
++ .config = quirk_config_socket,
++ }, {
++ .manfid = MANFID_SOCKET,
++ .prodid = ~0,
++ .multi = -1,
++ .config = quirk_config_socket,
++ }
++};
++
++
++static int serial_config(struct pcmcia_device * link);
++
++
+ /*======================================================================
+
+ After a card is removed, serial_remove() will unregister
+@@ -185,14 +307,14 @@ static int serial_suspend(struct pcmcia_
+
+ static int serial_resume(struct pcmcia_device *link)
+ {
+- if (pcmcia_dev_present(link)) {
+- struct serial_info *info = link->priv;
+- int i;
++ struct serial_info *info = link->priv;
++ int i;
+
+- for (i = 0; i < info->ndev; i++)
+- serial8250_resume_port(info->line[i]);
+- wakeup_card(info);
+- }
++ for (i = 0; i < info->ndev; i++)
++ serial8250_resume_port(info->line[i]);
++
++ if (info->quirk && info->quirk->wakeup)
++ info->quirk->wakeup(link);
+
+ return 0;
+ }
+@@ -278,6 +400,10 @@ static int setup_serial(struct pcmcia_de
+ port.dev = &handle_to_dev(handle);
+ if (buggy_uart)
+ port.flags |= UPF_BUGGY_UART;
++
++ if (info->quirk && info->quirk->setup)
++ info->quirk->setup(handle, &port);
++
+ line = serial8250_register_port(&port);
+ if (line < 0) {
+ printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
+@@ -433,6 +559,13 @@ next_entry:
+ }
+ if (info->multi && (info->manfid == MANFID_3COM))
+ link->conf.ConfigIndex &= ~(0x08);
++
++ /*
++ * Apply any configuration quirks.
++ */
++ if (info->quirk && info->quirk->config)
++ info->quirk->config(link);
++
+ i = pcmcia_request_configuration(link, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(link, RequestConfiguration, i);
+@@ -521,11 +654,13 @@ static int multi_config(struct pcmcia_de
+ cs_error(link, RequestIRQ, i);
+ link->irq.AssignedIRQ = 0;
+ }
+- /* Socket Dual IO: this enables irq's for second port */
+- if (info->multi && (info->manfid == MANFID_SOCKET)) {
+- link->conf.Present |= PRESENT_EXT_STATUS;
+- link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
+- }
++
++ /*
++ * Apply any configuration quirks.
++ */
++ if (info->quirk && info->quirk->config)
++ info->quirk->config(link);
++
+ i = pcmcia_request_configuration(link, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(link, RequestConfiguration, i);
+@@ -550,17 +685,19 @@ static int multi_config(struct pcmcia_de
+ link->irq.AssignedIRQ);
+ }
+ info->c950ctrl = base2;
+- wakeup_card(info);
++
++ /*
++ * FIXME: We really should wake up the port prior to
++ * handing it over to the serial layer.
++ */
++ if (info->quirk && info->quirk->wakeup)
++ info->quirk->wakeup(link);
++
+ rc = 0;
+ goto free_cfg_mem;
+ }
+
+ setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
+- /* The Nokia cards are not really multiport cards */
+- if (info->manfid == MANFID_NOKIA) {
+- rc = 0;
+- goto free_cfg_mem;
+- }
+ for (i = 0; i < info->multi - 1; i++)
+ setup_serial(link, info, base2 + (8 * i),
+ link->irq.AssignedIRQ);
+@@ -622,13 +759,16 @@ static int serial_config(struct pcmcia_d
+ tuple->DesiredTuple = CISTPL_MANFID;
+ if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
+ info->manfid = parse->manfid.manf;
+- info->prodid = le16_to_cpu(buf[1]);
+- for (i = 0; i < MULTI_COUNT; i++)
+- if ((info->manfid == multi_id[i].manfid) &&
+- (parse->manfid.card == multi_id[i].prodid))
++ info->prodid = parse->manfid.card;
++
++ for (i = 0; i < ARRAY_SIZE(quirks); i++)
++ if ((quirks[i].manfid == ~0 ||
++ quirks[i].manfid == info->manfid) &&
++ (quirks[i].prodid == ~0 ||
++ quirks[i].prodid == info->prodid)) {
++ info->quirk = &quirks[i];
+ break;
+- if (i < MULTI_COUNT)
+- info->multi = multi_id[i].multi;
++ }
+ }
+
+ /* Another check for dual-serial cards: look for either serial or
+@@ -648,6 +788,12 @@ static int serial_config(struct pcmcia_d
+ }
+ }
+
++ /*
++ * Apply any multi-port quirk.
++ */
++ if (info->quirk && info->quirk->multi != -1)
++ info->multi = info->quirk->multi;
++
+ if (info->multi > 1)
+ multi_config(link);
+ else
+@@ -656,21 +802,13 @@ static int serial_config(struct pcmcia_d
+ if (info->ndev == 0)
+ goto failed;
+
+- if (info->manfid == MANFID_IBM) {
+- conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+- last_ret = pcmcia_access_configuration_register(link, ®);
+- if (last_ret) {
+- last_fn = AccessConfigurationRegister;
+- goto cs_failed;
+- }
+- reg.Action = CS_WRITE;
+- reg.Value = reg.Value | 1;
+- last_ret = pcmcia_access_configuration_register(link, ®);
+- if (last_ret) {
+- last_fn = AccessConfigurationRegister;
+- goto cs_failed;
+- }
+- }
++ /*
++ * Apply any post-init quirk. FIXME: This should really happen
++ * before we register the port, since it might already be in use.
++ */
++ if (info->quirk && info->quirk->post)
++ if (info->quirk->post(link))
++ goto failed;
+
+ link->dev_node = &info->node[0];
+ kfree(cfg_mem);
+diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
+index 23ddedb..5e1ac35 100644
+--- a/drivers/serial/serial_lh7a40x.c
++++ b/drivers/serial/serial_lh7a40x.c
+@@ -135,12 +135,7 @@ static void lh7a40xuart_enable_ms (struc
+ BIT_SET (port, UART_R_INTEN, ModemInt);
+ }
+
+-static void
+-#ifdef SUPPORT_SYSRQ
+-lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
+-#else
+-lh7a40xuart_rx_chars (struct uart_port* port)
+-#endif
++static void lh7a40xuart_rx_chars (struct uart_port* port)
+ {
+ struct tty_struct* tty = port->info->tty;
+ int cbRxMax = 256; /* (Gross) limit on receive */
+@@ -177,7 +172,7 @@ lh7a40xuart_rx_chars (struct uart_port*
+ flag = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
++ if (uart_handle_sysrq_char (port, (unsigned char) data))
+ continue;
+
+ uart_insert_char(port, data, RxOverrunError, data, flag);
+@@ -248,8 +243,7 @@ static void lh7a40xuart_modem_status (st
+ wake_up_interruptible (&port->info->delta_msr_wait);
+ }
+
+-static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
+- struct pt_regs* regs)
++static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
+ {
+ struct uart_port* port = dev_id;
+ unsigned int cLoopLimit = ISR_LOOP_LIMIT;
+@@ -258,11 +252,7 @@ static irqreturn_t lh7a40xuart_int (int
+
+ do {
+ if (isr & (RxInt | RxTimeoutInt))
+-#ifdef SUPPORT_SYSRQ
+- lh7a40xuart_rx_chars(port, regs);
+-#else
+ lh7a40xuart_rx_chars(port);
+-#endif
+ if (isr & ModemInt)
+ lh7a40xuart_modem_status (port);
+ if (isr & TxInt)
+diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
+index b361669..2a48289 100644
+--- a/drivers/serial/serial_txx9.c
++++ b/drivers/serial/serial_txx9.c
+@@ -283,7 +283,7 @@ static void serial_txx9_enable_ms(struct
+ }
+
+ static inline void
+-receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *regs)
++receive_chars(struct uart_txx9_port *up, unsigned int *status)
+ {
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned char ch;
+@@ -344,7 +344,7 @@ receive_chars(struct uart_txx9_port *up,
+ else if (disr & TXX9_SIDISR_UFER)
+ flag = TTY_FRAME;
+ }
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ goto ignore_char;
+
+ uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
+@@ -391,7 +391,7 @@ static inline void transmit_chars(struct
+ serial_txx9_stop_tx(&up->port);
+ }
+
+-static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
+ {
+ int pass_counter = 0;
+ struct uart_txx9_port *up = dev_id;
+@@ -409,7 +409,7 @@ static irqreturn_t serial_txx9_interrupt
+ }
+
+ if (status & TXX9_SIDISR_RDIS)
+- receive_chars(up, &status, regs);
++ receive_chars(up, &status);
+ if (status & TXX9_SIDISR_TDIS)
+ transmit_chars(up);
+ /* Clear TX/RX Int. Status */
+@@ -990,7 +990,6 @@ int __init early_serial_txx9_setup(struc
+ /**
+ * serial_txx9_suspend_port - suspend one serial port
+ * @line: serial line number
+- * @level: the level of port suspension, as per uart_suspend_port
+ *
+ * Suspend one serial port.
+ */
+@@ -1002,7 +1001,6 @@ static void serial_txx9_suspend_port(int
+ /**
+ * serial_txx9_resume_port - resume one serial port
+ * @line: serial line number
+- * @level: the level of port resumption, as per uart_resume_port
+ *
+ * Resume one serial port.
+ */
+diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
+index cbede06..cfcc3ca 100644
+--- a/drivers/serial/sh-sci.c
++++ b/drivers/serial/sh-sci.c
+@@ -3,7 +3,7 @@
+ *
+ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
+ *
+- * Copyright (C) 2002, 2003, 2004 Paul Mundt
++ * Copyright (C) 2002 - 2006 Paul Mundt
+ *
+ * based off of the old drivers/char/sh-sci.c by:
+ *
+@@ -22,8 +22,6 @@
+
+ #include <linux/module.h>
+ #include <linux/errno.h>
+-#include <linux/signal.h>
+-#include <linux/sched.h>
+ #include <linux/timer.h>
+ #include <linux/interrupt.h>
+ #include <linux/tty.h>
+@@ -32,71 +30,77 @@
+ #include <linux/major.h>
+ #include <linux/string.h>
+ #include <linux/sysrq.h>
+-#include <linux/fcntl.h>
+-#include <linux/ptrace.h>
+ #include <linux/ioport.h>
+ #include <linux/mm.h>
+-#include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/console.h>
+-#include <linux/bitops.h>
+-#include <linux/generic_serial.h>
++#include <linux/platform_device.h>
+
+ #ifdef CONFIG_CPU_FREQ
+ #include <linux/notifier.h>
+ #include <linux/cpufreq.h>
+ #endif
+
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-
+ #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ #include <asm/clock.h>
+-#endif
+-
+-#ifdef CONFIG_SH_STANDARD_BIOS
+ #include <asm/sh_bios.h>
++#include <asm/kgdb.h>
+ #endif
+
++#include <asm/sci.h>
++
+ #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+
+ #include "sh-sci.h"
+
+-#ifdef CONFIG_SH_KGDB
+-#include <asm/kgdb.h>
++struct sci_port {
++ struct uart_port port;
++
++ /* Port type */
++ unsigned int type;
++
++ /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
++ unsigned int irqs[SCIx_NR_IRQS];
++
++ /* Port pin configuration */
++ void (*init_pins)(struct uart_port *port,
++ unsigned int cflag);
+
+-static int kgdb_get_char(struct sci_port *port);
+-static void kgdb_put_char(struct sci_port *port, char c);
+-static void kgdb_handle_error(struct sci_port *port);
++ /* Port enable callback */
++ void (*enable)(struct uart_port *port);
++
++ /* Port disable callback */
++ void (*disable)(struct uart_port *port);
++
++ /* Break timer */
++ struct timer_list break_timer;
++ int break_flag;
++};
++
++#ifdef CONFIG_SH_KGDB
+ static struct sci_port *kgdb_sci_port;
+-#endif /* CONFIG_SH_KGDB */
++#endif
+
+ #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+-static struct sci_port *serial_console_port = 0;
+-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
++static struct sci_port *serial_console_port;
++#endif
+
+ /* Function prototypes */
+ static void sci_stop_tx(struct uart_port *port);
+-static void sci_start_tx(struct uart_port *port);
+-static void sci_start_rx(struct uart_port *port, unsigned int tty_start);
+-static void sci_stop_rx(struct uart_port *port);
+-static int sci_request_irq(struct sci_port *port);
+-static void sci_free_irq(struct sci_port *port);
+-
+-static struct sci_port sci_ports[];
+-static struct uart_driver sci_uart_driver;
+
+-#define SCI_NPORTS sci_uart_driver.nr
++#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+
+-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
++static struct sci_port sci_ports[SCI_NPORTS];
++static struct uart_driver sci_uart_driver;
+
+-static void handle_error(struct uart_port *port)
+-{ /* Clear error flags */
++#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \
++ defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
++static inline void handle_error(struct uart_port *port)
++{
++ /* Clear error flags */
+ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+ }
+
+@@ -106,8 +110,8 @@ static int get_char(struct uart_port *po
+ unsigned short status;
+ int c;
+
+- local_irq_save(flags);
+- do {
++ spin_lock_irqsave(&port->lock, flags);
++ do {
+ status = sci_in(port, SCxSR);
+ if (status & SCxSR_ERRORS(port)) {
+ handle_error(port);
+@@ -117,38 +121,19 @@ static int get_char(struct uart_port *po
+ c = sci_in(port, SCxRDR);
+ sci_in(port, SCxSR); /* Dummy read */
+ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(&port->lock, flags);
+
+ return c;
+ }
+-
+-/* Taken from sh-stub.c of GDB 4.18 */
+-static const char hexchars[] = "0123456789abcdef";
+-
+-static __inline__ char highhex(int x)
+-{
+- return hexchars[(x >> 4) & 0xf];
+-}
+-
+-static __inline__ char lowhex(int x)
+-{
+- return hexchars[x & 0xf];
+-}
+-
+ #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+
+-/*
+- * Send the packet in buffer. The host gets one chance to read it.
+- * This routine does not wait for a positive acknowledge.
+- */
+-
+-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
++#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB)
+ static void put_char(struct uart_port *port, char c)
+ {
+ unsigned long flags;
+ unsigned short status;
+
+- local_irq_save(flags);
++ spin_lock_irqsave(&port->lock, flags);
+
+ do {
+ status = sci_in(port, SCxSR);
+@@ -158,9 +143,11 @@ static void put_char(struct uart_port *p
+ sci_in(port, SCxSR); /* Dummy read */
+ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(&port->lock, flags);
+ }
++#endif
+
++#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
+ {
+ struct uart_port *port = &sci_port->port;
+@@ -213,96 +200,28 @@ static void put_string(struct sci_port *
+ }
+ #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+-
+ #ifdef CONFIG_SH_KGDB
+-
+-/* Is the SCI ready, ie is there a char waiting? */
+-static int kgdb_is_char_ready(struct sci_port *port)
+-{
+- unsigned short status = sci_in(port, SCxSR);
+-
+- if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
+- kgdb_handle_error(port);
+-
+- return (status & SCxSR_RDxF(port));
+-}
+-
+-/* Write a char */
+-static void kgdb_put_char(struct sci_port *port, char c)
+-{
+- unsigned short status;
+-
+- do
+- status = sci_in(port, SCxSR);
+- while (!(status & SCxSR_TDxE(port)));
+-
+- sci_out(port, SCxTDR, c);
+- sci_in(port, SCxSR); /* Dummy read */
+- sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+-}
+-
+-/* Get a char if there is one, else ret -1 */
+-static int kgdb_get_char(struct sci_port *port)
+-{
+- int c;
+-
+- if (kgdb_is_char_ready(port) == 0)
+- c = -1;
+- else {
+- c = sci_in(port, SCxRDR);
+- sci_in(port, SCxSR); /* Dummy read */
+- sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+- }
+-
+- return c;
+-}
+-
+-/* Called from kgdbstub.c to get a character, i.e. is blocking */
+ static int kgdb_sci_getchar(void)
+ {
+- volatile int c;
++ int c;
+
+ /* Keep trying to read a character, this could be neater */
+- while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
++ while ((c = get_char(kgdb_sci_port)) < 0)
++ cpu_relax();
+
+ return c;
+ }
+
+-/* Called from kgdbstub.c to put a character, just a wrapper */
+-static void kgdb_sci_putchar(int c)
+-{
+-
+- kgdb_put_char(kgdb_sci_port, c);
+-}
+-
+-/* Clear any errors on the SCI */
+-static void kgdb_handle_error(struct sci_port *port)
++static inline void kgdb_sci_putchar(int c)
+ {
+- sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Clear error flags */
++ put_char(kgdb_sci_port, c);
+ }
+-
+-/* Breakpoint if there's a break sent on the serial port */
+-static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
+-{
+- struct sci_port *port = ptr;
+- unsigned short status = sci_in(port, SCxSR);
+-
+- if (status & SCxSR_BRK(port)) {
+-
+- /* Break into the debugger if a break is detected */
+- BREAKPOINT();
+-
+- /* Clear */
+- sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+- }
+-}
+-
+ #endif /* CONFIG_SH_KGDB */
+
+ #if defined(__H8300S__)
+ enum { sci_disable, sci_enable };
+
+-static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl)
++static void h8300_sci_config(struct uart_port* port, unsigned int ctrl)
+ {
+ volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
+ int ch = (port->mapbase - SMR0) >> 3;
+@@ -314,32 +233,66 @@ static void h8300_sci_enable(struct uart
+ *mstpcrl &= ~mask;
+ }
+ }
++
++static inline void h8300_sci_enable(struct uart_port *port)
++{
++ h8300_sci_config(port, sci_enable);
++}
++
++static inline void h8300_sci_disable(struct uart_port *port)
++{
++ h8300_sci_config(port, sci_disable);
++}
+ #endif
+
+-#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
+-#if defined(__H8300H__) || defined(__H8300S__)
++#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) && \
++ defined(__H8300H__) || defined(__H8300S__)
+ static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag)
+ {
+ int ch = (port->mapbase - SMR0) >> 3;
+
+ /* set DDR regs */
+- H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT);
+- H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT);
++ H8300_GPIO_DDR(h8300_sci_pins[ch].port,
++ h8300_sci_pins[ch].rx,
++ H8300_GPIO_INPUT);
++ H8300_GPIO_DDR(h8300_sci_pins[ch].port,
++ h8300_sci_pins[ch].tx,
++ H8300_GPIO_OUTPUT);
++
+ /* tx mark output*/
+ H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
+ }
++#else
++#define sci_init_pins_sci NULL
++#endif
++
++#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
++static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
++{
++ unsigned int fcr_val = 0;
++
++ if (cflag & CRTSCTS)
++ fcr_val |= SCFCR_MCE;
++
++ sci_out(port, SCFCR, fcr_val);
++}
++#else
++#define sci_init_pins_irda NULL
+ #endif
++
++#ifdef SCI_ONLY
++#define sci_init_pins_scif NULL
+ #endif
+
+ #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
+-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
++#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+ /* SH7300 doesn't use RTS/CTS */
+ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+ {
+ sci_out(port, SCFCR, 0);
+ }
+ #elif defined(CONFIG_CPU_SH3)
+-/* For SH7705, SH7707, SH7709, SH7709A, SH7729 */
++/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
+ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+ {
+ unsigned int fcr_val = 0;
+@@ -366,20 +319,7 @@ static void sci_init_pins_scif(struct ua
+
+ sci_out(port, SCFCR, fcr_val);
+ }
+-
+-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+-static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
+-{
+- unsigned int fcr_val = 0;
+-
+- if (cflag & CRTSCTS)
+- fcr_val |= SCFCR_MCE;
+-
+- sci_out(port, SCFCR, fcr_val);
+-}
+-#endif
+ #else
+-
+ /* For SH7750 */
+ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+ {
+@@ -388,7 +328,9 @@ static void sci_init_pins_scif(struct ua
+ if (cflag & CRTSCTS) {
+ fcr_val |= SCFCR_MCE;
+ } else {
+-#ifdef CONFIG_CPU_SUBTYPE_SH7780
++#ifdef CONFIG_CPU_SUBTYPE_SH7343
++ /* Nothing */
++#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
+ #else
+ ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
+@@ -396,10 +338,41 @@ static void sci_init_pins_scif(struct ua
+ }
+ sci_out(port, SCFCR, fcr_val);
+ }
++#endif
++
++#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
++static inline int scif_txroom(struct uart_port *port)
++{
++ return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
++}
++
++static inline int scif_rxroom(struct uart_port *port)
++{
++ return sci_in(port, SCRFDR) & 0x7f;
++}
++#else
++static inline int scif_txroom(struct uart_port *port)
++{
++ return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8);
++}
+
++static inline int scif_rxroom(struct uart_port *port)
++{
++ return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
++}
+ #endif
+ #endif /* SCIF_ONLY || SCI_AND_SCIF */
+
++static inline int sci_txroom(struct uart_port *port)
++{
++ return ((sci_in(port, SCxSR) & SCI_TDRE) != 0);
++}
++
++static inline int sci_rxroom(struct uart_port *port)
++{
++ return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0);
++}
++
+ /* ********************************************************************** *
+ * the interrupt related routines *
+ * ********************************************************************** */
+@@ -408,14 +381,12 @@ static void sci_transmit_chars(struct ua
+ {
+ struct circ_buf *xmit = &port->info->xmit;
+ unsigned int stopped = uart_tx_stopped(port);
+- unsigned long flags;
+ unsigned short status;
+ unsigned short ctrl;
+- int count, txroom;
++ int count;
+
+ status = sci_in(port, SCxSR);
+ if (!(status & SCxSR_TDxE(port))) {
+- local_irq_save(flags);
+ ctrl = sci_in(port, SCSCR);
+ if (uart_circ_empty(xmit)) {
+ ctrl &= ~SCI_CTRL_FLAGS_TIE;
+@@ -423,25 +394,15 @@ static void sci_transmit_chars(struct ua
+ ctrl |= SCI_CTRL_FLAGS_TIE;
+ }
+ sci_out(port, SCSCR, ctrl);
+- local_irq_restore(flags);
+ return;
+ }
+
+-#if !defined(SCI_ONLY)
+- if (port->type == PORT_SCIF) {
+-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+- txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
+-#else
+- txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8);
+-#endif
+- } else {
+- txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
+- }
+-#else
+- txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
++#ifndef SCI_ONLY
++ if (port->type == PORT_SCIF)
++ count = scif_txroom(port);
++ else
+ #endif
+-
+- count = txroom;
++ count = sci_txroom(port);
+
+ do {
+ unsigned char c;
+@@ -468,7 +429,6 @@ static void sci_transmit_chars(struct ua
+ if (uart_circ_empty(xmit)) {
+ sci_stop_tx(port);
+ } else {
+- local_irq_save(flags);
+ ctrl = sci_in(port, SCSCR);
+
+ #if !defined(SCI_ONLY)
+@@ -480,16 +440,15 @@ static void sci_transmit_chars(struct ua
+
+ ctrl |= SCI_CTRL_FLAGS_TIE;
+ sci_out(port, SCSCR, ctrl);
+- local_irq_restore(flags);
+ }
+ }
+
+ /* On SH3, SCIF may read end-of-break as a space->mark char */
+ #define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); })
+
+-static inline void sci_receive_chars(struct uart_port *port,
+- struct pt_regs *regs)
++static inline void sci_receive_chars(struct uart_port *port)
+ {
++ struct sci_port *sci_port = (struct sci_port *)port;
+ struct tty_struct *tty = port->info->tty;
+ int i, count, copied = 0;
+ unsigned short status;
+@@ -501,18 +460,11 @@ static inline void sci_receive_chars(str
+
+ while (1) {
+ #if !defined(SCI_ONLY)
+- if (port->type == PORT_SCIF) {
+-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+- count = sci_in(port, SCRFDR) & 0x7f;
+-#else
+- count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ;
+-#endif
+- } else {
+- count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
+- }
+-#else
+- count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
++ if (port->type == PORT_SCIF)
++ count = scif_rxroom(port);
++ else
+ #endif
++ count = sci_rxroom(port);
+
+ /* Don't copy more bytes than there is room for in the buffer */
+ count = tty_buffer_request_room(tty, count);
+@@ -523,11 +475,10 @@ static inline void sci_receive_chars(str
+
+ if (port->type == PORT_SCI) {
+ char c = sci_in(port, SCxRDR);
+- if(((struct sci_port *)port)->break_flag
+- || uart_handle_sysrq_char(port, c, regs)) {
++ if (uart_handle_sysrq_char(port, c) || sci_port->break_flag)
+ count = 0;
+- } else {
+- tty_insert_flip_char(tty, c, TTY_NORMAL);
++ else {
++ tty_insert_flip_char(tty, c, TTY_NORMAL);
+ }
+ } else {
+ for (i=0; i<count; i++) {
+@@ -535,22 +486,24 @@ static inline void sci_receive_chars(str
+ status = sci_in(port, SCxSR);
+ #if defined(CONFIG_CPU_SH3)
+ /* Skip "chars" during break */
+- if (((struct sci_port *)port)->break_flag) {
++ if (sci_port->break_flag) {
+ if ((c == 0) &&
+ (status & SCxSR_FER(port))) {
+ count--; i--;
+ continue;
+ }
++
+ /* Nonzero => end-of-break */
+ pr_debug("scif: debounce<%02x>\n", c);
+- ((struct sci_port *)port)->break_flag = 0;
++ sci_port->break_flag = 0;
++
+ if (STEPFN(c)) {
+ count--; i--;
+ continue;
+ }
+ }
+ #endif /* CONFIG_CPU_SH3 */
+- if (uart_handle_sysrq_char(port, c, regs)) {
++ if (uart_handle_sysrq_char(port, c)) {
+ count--; i--;
+ continue;
+ }
+@@ -600,15 +553,17 @@ static void sci_schedule_break_timer(str
+ /* Ensure that two consecutive samples find the break over. */
+ static void sci_break_timer(unsigned long data)
+ {
+- struct sci_port * port = (struct sci_port *)data;
+- if(sci_rxd_in(&port->port) == 0) {
++ struct sci_port *port = (struct sci_port *)data;
++
++ if (sci_rxd_in(&port->port) == 0) {
+ port->break_flag = 1;
+- sci_schedule_break_timer(port);
+- } else if(port->break_flag == 1){
++ sci_schedule_break_timer(port);
++ } else if (port->break_flag == 1) {
+ /* break is over. */
+ port->break_flag = 2;
+- sci_schedule_break_timer(port);
+- } else port->break_flag = 0;
++ sci_schedule_break_timer(port);
++ } else
++ port->break_flag = 0;
+ }
+
+ static inline int sci_handle_errors(struct uart_port *port)
+@@ -617,40 +572,41 @@ static inline int sci_handle_errors(stru
+ unsigned short status = sci_in(port, SCxSR);
+ struct tty_struct *tty = port->info->tty;
+
+- if (status&SCxSR_ORER(port)) {
++ if (status & SCxSR_ORER(port)) {
+ /* overrun error */
+- if(tty_insert_flip_char(tty, 0, TTY_OVERRUN))
++ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+ copied++;
+ pr_debug("sci: overrun error\n");
+ }
+
+- if (status&SCxSR_FER(port)) {
++ if (status & SCxSR_FER(port)) {
+ if (sci_rxd_in(port) == 0) {
+ /* Notify of BREAK */
+- struct sci_port * sci_port = (struct sci_port *)port;
+- if(!sci_port->break_flag) {
+- sci_port->break_flag = 1;
+- sci_schedule_break_timer((struct sci_port *)port);
++ struct sci_port *sci_port = (struct sci_port *)port;
++
++ if (!sci_port->break_flag) {
++ sci_port->break_flag = 1;
++ sci_schedule_break_timer(sci_port);
++
+ /* Do sysrq handling. */
+- if(uart_handle_break(port))
++ if (uart_handle_break(port))
+ return 0;
+ pr_debug("sci: BREAK detected\n");
+- if(tty_insert_flip_char(tty, 0, TTY_BREAK))
++ if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+ copied++;
+ }
+- }
+- else {
++ } else {
+ /* frame error */
+- if(tty_insert_flip_char(tty, 0, TTY_FRAME))
++ if (tty_insert_flip_char(tty, 0, TTY_FRAME))
+ copied++;
+ pr_debug("sci: frame error\n");
+ }
+ }
+
+- if (status&SCxSR_PER(port)) {
+- if(tty_insert_flip_char(tty, 0, TTY_PARITY))
+- copied++;
++ if (status & SCxSR_PER(port)) {
+ /* parity error */
++ if (tty_insert_flip_char(tty, 0, TTY_PARITY))
++ copied++;
+ pr_debug("sci: parity error\n");
+ }
+
+@@ -673,7 +629,7 @@ static inline int sci_handle_breaks(stru
+ s->break_flag = 1;
+ #endif
+ /* Notify of BREAK */
+- if(tty_insert_flip_char(tty, 0, TTY_BREAK))
++ if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+ copied++;
+ pr_debug("sci: BREAK detected\n");
+ }
+@@ -682,7 +638,7 @@ static inline int sci_handle_breaks(stru
+ /* XXX: Handle SCIF overrun error */
+ if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+ sci_out(port, SCLSR, 0);
+- if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
++ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
+ copied++;
+ pr_debug("sci: overrun error\n");
+ }
+@@ -691,32 +647,33 @@ static inline int sci_handle_breaks(stru
+
+ if (copied)
+ tty_flip_buffer_push(tty);
++
+ return copied;
+ }
+
+-static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t sci_rx_interrupt(int irq, void *port)
+ {
+- struct uart_port *port = ptr;
+-
+ /* I think sci_receive_chars has to be called irrespective
+ * of whether the I_IXOFF is set, otherwise, how is the interrupt
+ * to be disabled?
+ */
+- sci_receive_chars(port, regs);
++ sci_receive_chars(port);
+
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
+ {
+ struct uart_port *port = ptr;
+
++ spin_lock_irq(&port->lock);
+ sci_transmit_chars(port);
++ spin_unlock_irq(&port->lock);
+
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+ {
+ struct uart_port *port = ptr;
+
+@@ -738,29 +695,35 @@ static irqreturn_t sci_er_interrupt(int
+ pr_debug("scif: overrun error\n");
+ }
+ #endif
+- sci_rx_interrupt(irq, ptr, regs);
++ sci_rx_interrupt(irq, ptr);
+ }
+
+ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+
+ /* Kick the transmission */
+- sci_tx_interrupt(irq, ptr, regs);
++ sci_tx_interrupt(irq, ptr);
+
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t sci_br_interrupt(int irq, void *ptr)
+ {
+ struct uart_port *port = ptr;
+
+ /* Handle BREAKs */
+ sci_handle_breaks(port);
++
++#ifdef CONFIG_SH_KGDB
++ /* Break into the debugger if a break is detected */
++ BREAKPOINT();
++#endif
++
+ sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
++static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
+ {
+ unsigned short ssr_status, scr_status;
+ struct uart_port *port = ptr;
+@@ -769,17 +732,17 @@ static irqreturn_t sci_mpxed_interrupt(i
+ scr_status = sci_in(port,SCSCR);
+
+ /* Tx Interrupt */
+- if ((ssr_status&0x0020) && (scr_status&0x0080))
+- sci_tx_interrupt(irq, ptr, regs);
++ if ((ssr_status & 0x0020) && (scr_status & 0x0080))
++ sci_tx_interrupt(irq, ptr);
+ /* Rx Interrupt */
+- if ((ssr_status&0x0002) && (scr_status&0x0040))
+- sci_rx_interrupt(irq, ptr, regs);
++ if ((ssr_status & 0x0002) && (scr_status & 0x0040))
++ sci_rx_interrupt(irq, ptr);
+ /* Error Interrupt */
+- if ((ssr_status&0x0080) && (scr_status&0x0400))
+- sci_er_interrupt(irq, ptr, regs);
++ if ((ssr_status & 0x0080) && (scr_status & 0x0400))
++ sci_er_interrupt(irq, ptr);
+ /* Break Interrupt */
+- if ((ssr_status&0x0010) && (scr_status&0x0200))
+- sci_br_interrupt(irq, ptr, regs);
++ if ((ssr_status & 0x0010) && (scr_status & 0x0200))
++ sci_br_interrupt(irq, ptr);
+
+ return IRQ_HANDLED;
+ }
+@@ -789,7 +752,8 @@ static irqreturn_t sci_mpxed_interrupt(i
+ * Here we define a transistion notifier so that we can update all of our
+ * ports' baud rate when the peripheral clock changes.
+ */
+-static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p)
++static int sci_notifier(struct notifier_block *self,
++ unsigned long phase, void *p)
+ {
+ struct cpufreq_freqs *freqs = p;
+ int i;
+@@ -816,8 +780,9 @@ static int sci_notifier(struct notifier_
+ clk_put(clk);
+ }
+
+- printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n",
+- __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
++ printk(KERN_INFO "%s: got a postchange notification "
++ "for cpu %d (old %d, new %d)\n",
++ __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+ }
+
+ return NOTIFY_OK;
+@@ -829,7 +794,7 @@ static struct notifier_block sci_nb = {
+ static int sci_request_irq(struct sci_port *port)
+ {
+ int i;
+- irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = {
++ irqreturn_t (*handlers[4])(int irq, void *ptr) = {
+ sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+ sci_br_interrupt,
+ };
+@@ -841,8 +806,9 @@ static int sci_request_irq(struct sci_po
+ printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n");
+ return -ENODEV;
+ }
+- if (request_irq(port->irqs[0], sci_mpxed_interrupt, IRQF_DISABLED,
+- "sci", port)) {
++
++ if (request_irq(port->irqs[0], sci_mpxed_interrupt,
++ IRQF_DISABLED, "sci", port)) {
+ printk(KERN_ERR "sci: Cannot allocate irq.\n");
+ return -ENODEV;
+ }
+@@ -850,8 +816,8 @@ static int sci_request_irq(struct sci_po
+ for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+ if (!port->irqs[i])
+ continue;
+- if (request_irq(port->irqs[i], handlers[i], IRQF_DISABLED,
+- desc[i], port)) {
++ if (request_irq(port->irqs[i], handlers[i],
++ IRQF_DISABLED, desc[i], port)) {
+ printk(KERN_ERR "sci: Cannot allocate irq.\n");
+ return -ENODEV;
+ }
+@@ -903,50 +869,42 @@ static unsigned int sci_get_mctrl(struct
+
+ static void sci_start_tx(struct uart_port *port)
+ {
+- struct sci_port *s = &sci_ports[port->line];
++ unsigned short ctrl;
+
+- disable_irq(s->irqs[SCIx_TXI_IRQ]);
+- sci_transmit_chars(port);
+- enable_irq(s->irqs[SCIx_TXI_IRQ]);
++ /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
++ ctrl = sci_in(port, SCSCR);
++ ctrl |= SCI_CTRL_FLAGS_TIE;
++ sci_out(port, SCSCR, ctrl);
+ }
+
+ static void sci_stop_tx(struct uart_port *port)
+ {
+- unsigned long flags;
+ unsigned short ctrl;
+
+ /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+- local_irq_save(flags);
+ ctrl = sci_in(port, SCSCR);
+ ctrl &= ~SCI_CTRL_FLAGS_TIE;
+ sci_out(port, SCSCR, ctrl);
+- local_irq_restore(flags);
+ }
+
+ static void sci_start_rx(struct uart_port *port, unsigned int tty_start)
+ {
+- unsigned long flags;
+ unsigned short ctrl;
+
+ /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
+- local_irq_save(flags);
+ ctrl = sci_in(port, SCSCR);
+ ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
+ sci_out(port, SCSCR, ctrl);
+- local_irq_restore(flags);
+ }
+
+ static void sci_stop_rx(struct uart_port *port)
+ {
+- unsigned long flags;
+ unsigned short ctrl;
+
+ /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
+- local_irq_save(flags);
+ ctrl = sci_in(port, SCSCR);
+ ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
+ sci_out(port, SCSCR, ctrl);
+- local_irq_restore(flags);
+ }
+
+ static void sci_enable_ms(struct uart_port *port)
+@@ -963,9 +921,8 @@ static int sci_startup(struct uart_port
+ {
+ struct sci_port *s = &sci_ports[port->line];
+
+-#if defined(__H8300S__)
+- h8300_sci_enable(port, sci_enable);
+-#endif
++ if (s->enable)
++ s->enable(port);
+
+ sci_request_irq(s);
+ sci_start_tx(port);
+@@ -982,9 +939,8 @@ static void sci_shutdown(struct uart_por
+ sci_stop_tx(port);
+ sci_free_irq(s);
+
+-#if defined(__H8300S__)
+- h8300_sci_enable(port, sci_disable);
+-#endif
++ if (s->disable)
++ s->disable(port);
+ }
+
+ static void sci_set_termios(struct uart_port *port, struct termios *termios,
+@@ -997,6 +953,23 @@ static void sci_set_termios(struct uart_
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+
++ switch (baud) {
++ case 0:
++ t = -1;
++ break;
++ default:
++ {
++#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
++ struct clk *clk = clk_get("module_clk");
++ t = SCBRR_VALUE(baud, clk_get_rate(clk));
++ clk_put(clk);
++#else
++ t = SCBRR_VALUE(baud);
++#endif
++ }
++ break;
++ }
++
+ spin_lock_irqsave(&port->lock, flags);
+
+ do {
+@@ -1006,9 +979,8 @@ static void sci_set_termios(struct uart_
+ sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
+
+ #if !defined(SCI_ONLY)
+- if (port->type == PORT_SCIF) {
++ if (port->type == PORT_SCIF)
+ sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+- }
+ #endif
+
+ smr_val = sci_in(port, SCSMR) & 3;
+@@ -1025,23 +997,6 @@ static void sci_set_termios(struct uart_
+
+ sci_out(port, SCSMR, smr_val);
+
+- switch (baud) {
+- case 0:
+- t = -1;
+- break;
+- default:
+- {
+-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+- struct clk *clk = clk_get("module_clk");
+- t = SCBRR_VALUE(baud, clk_get_rate(clk));
+- clk_put(clk);
+-#else
+- t = SCBRR_VALUE(baud);
+-#endif
+- }
+- break;
+- }
+-
+ if (t > 0) {
+ if(t >= 256) {
+ sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
+@@ -1092,11 +1047,23 @@ static void sci_config_port(struct uart_
+
+ port->type = s->type;
+
++ switch (port->type) {
++ case PORT_SCI:
++ s->init_pins = sci_init_pins_sci;
++ break;
++ case PORT_SCIF:
++ s->init_pins = sci_init_pins_scif;
++ break;
++ case PORT_IRDA:
++ s->init_pins = sci_init_pins_irda;
++ break;
++ }
++
+ #if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+ if (port->mapbase == 0)
+ port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
+
+- port->membase = (void *)port->mapbase;
++ port->membase = (void __iomem *)port->mapbase;
+ #endif
+ }
+
+@@ -1132,412 +1099,61 @@ static struct uart_ops sci_uart_ops = {
+ .verify_port = sci_verify_port,
+ };
+
+-static struct sci_port sci_ports[] = {
+-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
+- {
+- .port = {
+- .membase = (void *)0xfffffe80,
+- .mapbase = 0xfffffe80,
+- .iotype = UPIO_MEM,
+- .irq = 25,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCI,
+- .irqs = SCI_IRQS,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+- {
+- .port = {
+- .membase = (void *)SCIF0,
+- .mapbase = SCIF0,
+- .iotype = UPIO_MEM,
+- .irq = 55,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH3_IRDA_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)SCIF2,
+- .mapbase = SCIF2,
+- .iotype = UPIO_MEM,
+- .irq = 59,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH3_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- }
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+- {
+- .port = {
+- .membase = (void *)0xfffffe80,
+- .mapbase = 0xfffffe80,
+- .iotype = UPIO_MEM,
+- .irq = 25,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCI,
+- .irqs = SCI_IRQS,
+- },
+- {
+- .port = {
+- .membase = (void *)0xa4000150,
+- .mapbase = 0xa4000150,
+- .iotype = UPIO_MEM,
+- .irq = 59,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH3_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xa4000140,
+- .mapbase = 0xa4000140,
+- .iotype = UPIO_MEM,
+- .irq = 55,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 2,
+- },
+- .type = PORT_IRDA,
+- .irqs = SH3_IRDA_IRQS,
+- .init_pins = sci_init_pins_irda,
+- }
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
+- {
+- .port = {
+- .membase = (void *)0xA4430000,
+- .mapbase = 0xA4430000,
+- .iotype = UPIO_MEM,
+- .irq = 25,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7300_SCIF0_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
+- {
+- .port = {
+- .membase = (void *)0xffe00000,
+- .mapbase = 0xffe00000,
+- .iotype = UPIO_MEM,
+- .irq = 25,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH73180_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
+- {
+- .port = {
+- .membase = (void *)0xffe80000,
+- .mapbase = 0xffe80000,
+- .iotype = UPIO_MEM,
+- .irq = 43,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH4_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
+- {
+- .port = {
+- .membase = (void *)0xffe00000,
+- .mapbase = 0xffe00000,
+- .iotype = UPIO_MEM,
+- .irq = 25,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCI,
+- .irqs = SCI_IRQS,
+- },
+- {
+- .port = {
+- .membase = (void *)0xffe80000,
+- .mapbase = 0xffe80000,
+- .iotype = UPIO_MEM,
+- .irq = 43,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH4_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+- {
+- .port = {
+- .membase = (void *)0xfe600000,
+- .mapbase = 0xfe600000,
+- .iotype = UPIO_MEM,
+- .irq = 55,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7760_SCIF0_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xfe610000,
+- .mapbase = 0xfe610000,
+- .iotype = UPIO_MEM,
+- .irq = 75,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7760_SCIF1_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xfe620000,
+- .mapbase = 0xfe620000,
+- .iotype = UPIO_MEM,
+- .irq = 79,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 2,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7760_SCIF2_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+- {
+- .port = {
+- .membase = (void *)0xffe00000,
+- .mapbase = 0xffe00000,
+- .iotype = UPIO_MEM,
+- .irq = 26,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = STB1_SCIF1_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xffe80000,
+- .mapbase = 0xffe80000,
+- .iotype = UPIO_MEM,
+- .irq = 43,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH4_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+- {
+- .port = {
+- .iotype = UPIO_MEM,
+- .irq = 42,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH5_SCIF_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
+- {
+- .port = {
+- .membase = (void *)0x00ffffb0,
+- .mapbase = 0x00ffffb0,
+- .iotype = UPIO_MEM,
+- .irq = 54,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCI,
+- .irqs = H8300H_SCI_IRQS0,
+- .init_pins = sci_init_pins_sci,
+- },
+- {
+- .port = {
+- .membase = (void *)0x00ffffb8,
+- .mapbase = 0x00ffffb8,
+- .iotype = UPIO_MEM,
+- .irq = 58,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCI,
+- .irqs = H8300H_SCI_IRQS1,
+- .init_pins = sci_init_pins_sci,
+- },
+- {
+- .port = {
+- .membase = (void *)0x00ffffc0,
+- .mapbase = 0x00ffffc0,
+- .iotype = UPIO_MEM,
+- .irq = 62,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 2,
+- },
+- .type = PORT_SCI,
+- .irqs = H8300H_SCI_IRQS2,
+- .init_pins = sci_init_pins_sci,
+- },
+-#elif defined(CONFIG_H8S2678)
+- {
+- .port = {
+- .membase = (void *)0x00ffff78,
+- .mapbase = 0x00ffff78,
+- .iotype = UPIO_MEM,
+- .irq = 90,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCI,
+- .irqs = H8S_SCI_IRQS0,
+- .init_pins = sci_init_pins_sci,
+- },
+- {
+- .port = {
+- .membase = (void *)0x00ffff80,
+- .mapbase = 0x00ffff80,
+- .iotype = UPIO_MEM,
+- .irq = 94,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCI,
+- .irqs = H8S_SCI_IRQS1,
+- .init_pins = sci_init_pins_sci,
+- },
+- {
+- .port = {
+- .membase = (void *)0x00ffff88,
+- .mapbase = 0x00ffff88,
+- .iotype = UPIO_MEM,
+- .irq = 98,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 2,
+- },
+- .type = PORT_SCI,
+- .irqs = H8S_SCI_IRQS2,
+- .init_pins = sci_init_pins_sci,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+- {
+- .port = {
+- .membase = (void *)0xff923000,
+- .mapbase = 0xff923000,
+- .iotype = UPIO_MEM,
+- .irq = 61,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7770_SCIF0_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xff924000,
+- .mapbase = 0xff924000,
+- .iotype = UPIO_MEM,
+- .irq = 62,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7770_SCIF1_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xff925000,
+- .mapbase = 0xff925000,
+- .iotype = UPIO_MEM,
+- .irq = 63,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 2,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7770_SCIF2_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+- {
+- .port = {
+- .membase = (void *)0xffe00000,
+- .mapbase = 0xffe00000,
+- .iotype = UPIO_MEM,
+- .irq = 43,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 0,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7780_SCIF0_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
+- {
+- .port = {
+- .membase = (void *)0xffe10000,
+- .mapbase = 0xffe10000,
+- .iotype = UPIO_MEM,
+- .irq = 79,
+- .ops = &sci_uart_ops,
+- .flags = UPF_BOOT_AUTOCONF,
+- .line = 1,
+- },
+- .type = PORT_SCIF,
+- .irqs = SH7780_SCIF1_IRQS,
+- .init_pins = sci_init_pins_scif,
+- },
++static void __init sci_init_ports(void)
++{
++ static int first = 1;
++ int i;
++
++ if (!first)
++ return;
++
++ first = 0;
++
++ for (i = 0; i < SCI_NPORTS; i++) {
++ sci_ports[i].port.ops = &sci_uart_ops;
++ sci_ports[i].port.iotype = UPIO_MEM;
++ sci_ports[i].port.line = i;
++ sci_ports[i].port.fifosize = 1;
++
++#if defined(__H8300H__) || defined(__H8300S__)
++#ifdef __H8300S__
++ sci_ports[i].enable = h8300_sci_enable;
++ sci_ports[i].disable = h8300_sci_disable;
++#endif
++ sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK;
++#elif defined(CONFIG_SUPERH64)
++ sci_ports[i].port.uartclk = current_cpu_data.module_clock * 16;
+ #else
+-#error "CPU subtype not defined"
++ /*
++ * XXX: We should use a proper SCI/SCIF clock
++ */
++ {
++ struct clk *clk = clk_get("module_clk");
++ sci_ports[i].port.uartclk = clk_get_rate(clk) * 16;
++ clk_put(clk);
++ }
+ #endif
+-};
++
++ sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i];
++ sci_ports[i].break_timer.function = sci_break_timer;
++
++ init_timer(&sci_ports[i].break_timer);
++ }
++}
++
++int __init early_sci_setup(struct uart_port *port)
++{
++ if (unlikely(port->line > SCI_NPORTS))
++ return -ENODEV;
++
++ sci_init_ports();
++
++ sci_ports[port->line].port.membase = port->membase;
++ sci_ports[port->line].port.mapbase = port->mapbase;
++ sci_ports[port->line].port.type = port->type;
++
++ return 0;
++}
+
+ #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+ /*
+@@ -1559,34 +1175,38 @@ static int __init serial_console_setup(s
+ int flow = 'n';
+ int ret;
+
++ /*
++ * Check whether an invalid uart number has been specified, and
++ * if so, search for the first available port that does have
++ * console support.
++ */
++ if (co->index >= SCI_NPORTS)
++ co->index = 0;
++
+ serial_console_port = &sci_ports[co->index];
+ port = &serial_console_port->port;
+- port->type = serial_console_port->type;
+-
+-#ifdef CONFIG_SUPERH64
+- /* This is especially needed on sh64 to remap the SCIF */
+- sci_config_port(port, 0);
+-#endif
+
+ /*
+- * We need to set the initial uartclk here, since otherwise it will
+- * only ever be setup at sci_init() time.
++ * Also need to check port->type, we don't actually have any
++ * UPIO_PORT ports, but uart_report_port() handily misreports
++ * it anyways if we don't have a port available by the time this is
++ * called.
+ */
+-#if defined(__H8300H__) || defined(__H8300S__)
+- port->uartclk = CONFIG_CPU_CLOCK;
++ if (!port->type)
++ return -ENODEV;
++ if (!port->membase || !port->mapbase)
++ return -ENODEV;
++
++ spin_lock_init(&port->lock);
++
++ port->type = serial_console_port->type;
++
++ if (port->flags & UPF_IOREMAP)
++ sci_config_port(port, 0);
++
++ if (serial_console_port->enable)
++ serial_console_port->enable(port);
+
+-#if defined(__H8300S__)
+- h8300_sci_enable(port, sci_enable);
+-#endif
+-#elif defined(CONFIG_SUPERH64)
+- port->uartclk = current_cpu_data.module_clock * 16;
+-#else
+- {
+- struct clk *clk = clk_get("module_clk");
+- port->uartclk = clk_get_rate(clk) * 16;
+- clk_put(clk);
+- }
+-#endif
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+@@ -1604,17 +1224,17 @@ static struct console serial_console = {
+ .device = uart_console_device,
+ .write = serial_console_write,
+ .setup = serial_console_setup,
+- .flags = CON_PRINTBUFFER,
++ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &sci_uart_driver,
+ };
+
+ static int __init sci_console_init(void)
+ {
++ sci_init_ports();
+ register_console(&serial_console);
+ return 0;
+ }
+-
+ console_initcall(sci_console_init);
+ #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+@@ -1649,6 +1269,8 @@ int __init kgdb_console_setup(struct con
+ int parity = 'n';
+ int flow = 'n';
+
++ spin_lock_init(&port->lock);
++
+ if (co->index != kgdb_portnum)
+ co->index = kgdb_portnum;
+
+@@ -1677,10 +1299,10 @@ static struct console kgdb_console = {
+ /* Register the KGDB console so we get messages (d'oh!) */
+ static int __init kgdb_console_init(void)
+ {
++ sci_init_ports();
+ register_console(&kgdb_console);
+ return 0;
+ }
+-
+ console_initcall(kgdb_console_init);
+ #endif /* CONFIG_SH_KGDB_CONSOLE */
+
+@@ -1701,60 +1323,132 @@ static struct uart_driver sci_uart_drive
+ .dev_name = "ttySC",
+ .major = SCI_MAJOR,
+ .minor = SCI_MINOR_START,
++ .nr = SCI_NPORTS,
+ .cons = SCI_CONSOLE,
+ };
+
+-static int __init sci_init(void)
++/*
++ * Register a set of serial devices attached to a platform device. The
++ * list is terminated with a zero flags entry, which means we expect
++ * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
++ * remapping (such as sh64) should also set UPF_IOREMAP.
++ */
++static int __devinit sci_probe(struct platform_device *dev)
+ {
+- int chan, ret;
++ struct plat_sci_port *p = dev->dev.platform_data;
++ int i;
+
+- printk("%s", banner);
++ for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) {
++ struct sci_port *sciport = &sci_ports[i];
+
+- sci_uart_driver.nr = ARRAY_SIZE(sci_ports);
++ sciport->port.mapbase = p->mapbase;
+
+- ret = uart_register_driver(&sci_uart_driver);
+- if (ret == 0) {
+- for (chan = 0; chan < SCI_NPORTS; chan++) {
+- struct sci_port *sciport = &sci_ports[chan];
++ /*
++ * For the simple (and majority of) cases where we don't need
++ * to do any remapping, just cast the cookie directly.
++ */
++ if (p->mapbase && !p->membase && !(p->flags & UPF_IOREMAP))
++ p->membase = (void __iomem *)p->mapbase;
+
+-#if defined(__H8300H__) || defined(__H8300S__)
+- sciport->port.uartclk = CONFIG_CPU_CLOCK;
+-#elif defined(CONFIG_SUPERH64)
+- sciport->port.uartclk = current_cpu_data.module_clock * 16;
+-#else
+- struct clk *clk = clk_get("module_clk");
+- sciport->port.uartclk = clk_get_rate(clk) * 16;
+- clk_put(clk);
+-#endif
+- uart_add_one_port(&sci_uart_driver, &sciport->port);
+- sciport->break_timer.data = (unsigned long)sciport;
+- sciport->break_timer.function = sci_break_timer;
+- init_timer(&sciport->break_timer);
+- }
++ sciport->port.membase = p->membase;
++
++ sciport->port.irq = p->irqs[SCIx_TXI_IRQ];
++ sciport->port.flags = p->flags;
++ sciport->port.dev = &dev->dev;
++
++ sciport->type = sciport->port.type = p->type;
++
++ memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs));
++
++ uart_add_one_port(&sci_uart_driver, &sciport->port);
+ }
+
+ #ifdef CONFIG_CPU_FREQ
+ cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
+- printk("sci: CPU frequency notifier registered\n");
++ dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
+ #endif
+
+ #ifdef CONFIG_SH_STANDARD_BIOS
+ sh_bios_gdb_detach();
+ #endif
+
+- return ret;
++ return 0;
+ }
+
+-static void __exit sci_exit(void)
++static int __devexit sci_remove(struct platform_device *dev)
++{
++ int i;
++
++ for (i = 0; i < SCI_NPORTS; i++)
++ uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
++
++ return 0;
++}
++
++static int sci_suspend(struct platform_device *dev, pm_message_t state)
+ {
+- int chan;
++ int i;
++
++ for (i = 0; i < SCI_NPORTS; i++) {
++ struct sci_port *p = &sci_ports[i];
++
++ if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
++ uart_suspend_port(&sci_uart_driver, &p->port);
++ }
+
+- for (chan = 0; chan < SCI_NPORTS; chan++)
+- uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port);
++ return 0;
++}
+
++static int sci_resume(struct platform_device *dev)
++{
++ int i;
++
++ for (i = 0; i < SCI_NPORTS; i++) {
++ struct sci_port *p = &sci_ports[i];
++
++ if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
++ uart_resume_port(&sci_uart_driver, &p->port);
++ }
++
++ return 0;
++}
++
++static struct platform_driver sci_driver = {
++ .probe = sci_probe,
++ .remove = __devexit_p(sci_remove),
++ .suspend = sci_suspend,
++ .resume = sci_resume,
++ .driver = {
++ .name = "sh-sci",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init sci_init(void)
++{
++ int ret;
++
++ printk(banner);
++
++ sci_init_ports();
++
++ ret = uart_register_driver(&sci_uart_driver);
++ if (likely(ret == 0)) {
++ ret = platform_driver_register(&sci_driver);
++ if (unlikely(ret))
++ uart_unregister_driver(&sci_uart_driver);
++ }
++
++ return ret;
++}
++
++static void __exit sci_exit(void)
++{
++ platform_driver_unregister(&sci_driver);
+ uart_unregister_driver(&sci_uart_driver);
+ }
+
+ module_init(sci_init);
+ module_exit(sci_exit);
+
++MODULE_LICENSE("GPL");
+diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
+index ab320fa..7ee9921 100644
+--- a/drivers/serial/sh-sci.h
++++ b/drivers/serial/sh-sci.h
+@@ -11,6 +11,7 @@
+ * Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
+ */
+ #include <linux/serial_core.h>
++#include <asm/io.h>
+
+ #if defined(__H8300H__) || defined(__H8300S__)
+ #include <asm/gpio.h>
+@@ -22,40 +23,13 @@
+ #endif
+ #endif
+
+-/* Offsets into the sci_port->irqs array */
+-#define SCIx_ERI_IRQ 0
+-#define SCIx_RXI_IRQ 1
+-#define SCIx_TXI_IRQ 2
+-
+-/* ERI, RXI, TXI, BRI */
+-#define SCI_IRQS { 23, 24, 25, 0 }
+-#define SH3_SCIF_IRQS { 56, 57, 59, 58 }
+-#define SH3_IRDA_IRQS { 52, 53, 55, 54 }
+-#define SH4_SCIF_IRQS { 40, 41, 43, 42 }
+-#define STB1_SCIF1_IRQS {23, 24, 26, 25 }
+-#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
+-#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
+-#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
+-#define SH7300_SCIF0_IRQS {80, 80, 80, 80 }
+-#define SH73180_SCIF_IRQS {80, 81, 83, 82 }
+-#define H8300H_SCI_IRQS0 {52, 53, 54, 0 }
+-#define H8300H_SCI_IRQS1 {56, 57, 58, 0 }
+-#define H8300H_SCI_IRQS2 {60, 61, 62, 0 }
+-#define H8S_SCI_IRQS0 {88, 89, 90, 0 }
+-#define H8S_SCI_IRQS1 {92, 93, 94, 0 }
+-#define H8S_SCI_IRQS2 {96, 97, 98, 0 }
+-#define SH5_SCIF_IRQS {39, 40, 42, 0 }
+-#define SH7770_SCIF0_IRQS {61, 61, 61, 61 }
+-#define SH7770_SCIF1_IRQS {62, 62, 62, 62 }
+-#define SH7770_SCIF2_IRQS {63, 63, 63, 63 }
+-#define SH7780_SCIF0_IRQS {40, 41, 43, 42 }
+-#define SH7780_SCIF1_IRQS {76, 77, 79, 78 }
+-
+ #if defined(CONFIG_CPU_SUBTYPE_SH7708)
+ # define SCSPTR 0xffffff7c /* 8 bit */
+ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define SCI_ONLY
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706)
+ # define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
+ # define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
+ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+@@ -99,12 +73,23 @@
+ # define SCPDR 0xA4050136 /* 16 bit SCIF */
+ # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define SCIF_ONLY
++#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
++# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
++# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
++# define SCIF_ONLY
+ #elif defined(CONFIG_CPU_SUBTYPE_SH73180)
+ # define SCPDR 0xA4050138 /* 16 bit SCIF */
+ # define SCSPTR2 SCPDR
+ # define SCIF_ORER 0x0001 /* overrun error bit */
+ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define SCIF_ONLY
++#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
++# define SCSPTR0 0xffe00010 /* 16 bit SCIF */
++# define SCSPTR1 0xffe10010 /* 16 bit SCIF */
++# define SCSPTR2 0xffe20010 /* 16 bit SCIF */
++# define SCSPTR3 0xffe30010 /* 16 bit SCIF */
++# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
++# define SCIF_ONLY
+ #elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
+ # define SCSPTR2 0xffe80020 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001 /* overrun error bit */
+@@ -145,7 +130,7 @@
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ # define SCSPTR0 0xffe00024 /* 16 bit SCIF */
+ # define SCSPTR1 0xffe10024 /* 16 bit SCIF */
+-# define SCIF_OPER 0x0001 /* Overrun error bit */
++# define SCIF_ORER 0x0001 /* Overrun error bit */
+ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ # define SCIF_ONLY
+ #else
+@@ -273,15 +258,6 @@
+ */
+ #define SCI_EVENT_WRITE_WAKEUP 0
+
+-struct sci_port {
+- struct uart_port port;
+- int type;
+- unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */
+- void (*init_pins)(struct uart_port *port, unsigned int cflag);
+- int break_flag;
+- struct timer_list break_timer;
+-};
+-
+ #define SCI_IN(size, offset) \
+ unsigned int addr = port->mapbase + (offset); \
+ if ((size) == 8) { \
+@@ -336,7 +312,9 @@ struct sci_port {
+ }
+
+ #ifdef CONFIG_CPU_SH3
+-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
++#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7710)
+ #define SCIF_FNS(name, scif_offset, scif_size) \
+ CPU_SCIF_FNS(name, scif_offset, scif_size)
+ #else
+@@ -362,7 +340,9 @@ struct sci_port {
+ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+ #endif
+
+-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
++#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7710)
+ SCIF_FNS(SCSMR, 0x00, 16)
+ SCIF_FNS(SCBRR, 0x04, 8)
+ SCIF_FNS(SCSCR, 0x08, 16)
+@@ -447,7 +427,9 @@ static inline int sci_rxd_in(struct uart
+ return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
+ return 1;
+ }
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+ if (port->mapbase == 0xfffffe80)
+@@ -467,6 +449,13 @@ static inline int sci_rxd_in(struct uart
+ return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
+ return 1;
+ }
++#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
++static inline int sci_rxd_in(struct uart_port *port)
++{
++ if (port->mapbase == SCSPTR0)
++ return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0;
++ return 1;
++}
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH4_202)
+@@ -504,6 +493,19 @@ static inline int sci_rxd_in(struct uart
+ {
+ return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
+ }
++#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
++static inline int sci_rxd_in(struct uart_port *port)
++{
++ if (port->mapbase == 0xffe00000)
++ return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
++ if (port->mapbase == 0xffe10000)
++ return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
++ if (port->mapbase == 0xffe20000)
++ return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
++ if (port->mapbase == 0xffe30000)
++ return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
++ return 1;
++}
+ #elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+@@ -587,4 +589,3 @@ static inline int sci_rxd_in(struct uart
+ #else /* Generic SH */
+ #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
+ #endif
+-
+diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
+index 2f148e5..956b2cf 100644
+--- a/drivers/serial/sn_console.c
++++ b/drivers/serial/sn_console.c
+@@ -447,7 +447,6 @@ static int sn_debug_printf(const char *f
+ /**
+ * sn_receive_chars - Grab characters, pass them to tty layer
+ * @port: Port to operate on
+- * @regs: Saved registers (needed by uart_handle_sysrq_char)
+ * @flags: irq flags
+ *
+ * Note: If we're not registered with the serial core infrastructure yet,
+@@ -455,8 +454,7 @@ static int sn_debug_printf(const char *f
+ *
+ */
+ static void
+-sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs,
+- unsigned long flags)
++sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
+ {
+ int ch;
+ struct tty_struct *tty;
+@@ -494,7 +492,7 @@ sn_receive_chars(struct sn_cons_port *po
+ sysrq_requested = 0;
+ if (ch && time_before(jiffies, sysrq_timeout)) {
+ spin_unlock_irqrestore(&port->sc_port.lock, flags);
+- handle_sysrq(ch, regs, NULL);
++ handle_sysrq(ch, NULL);
+ spin_lock_irqsave(&port->sc_port.lock, flags);
+ /* ignore actual sysrq command char */
+ continue;
+@@ -615,10 +613,9 @@ static void sn_transmit_chars(struct sn_
+ * sn_sal_interrupt - Handle console interrupts
+ * @irq: irq #, useful for debug statements
+ * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
+- * @regs: Saved registers, used by sn_receive_chars for uart_handle_sysrq_char
+ *
+ */
+-static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
+ {
+ struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
+ unsigned long flags;
+@@ -629,7 +626,7 @@ static irqreturn_t sn_sal_interrupt(int
+
+ spin_lock_irqsave(&port->sc_port.lock, flags);
+ if (status & SAL_CONSOLE_INTR_RECV) {
+- sn_receive_chars(port, regs, flags);
++ sn_receive_chars(port, flags);
+ }
+ if (status & SAL_CONSOLE_INTR_XMIT) {
+ sn_transmit_chars(port, TRANSMIT_BUFFERED);
+@@ -677,7 +674,7 @@ static void sn_sal_timer_poll(unsigned l
+ if (!port->sc_port.irq) {
+ spin_lock_irqsave(&port->sc_port.lock, flags);
+ if (sn_process_input)
+- sn_receive_chars(port, NULL, flags);
++ sn_receive_chars(port, flags);
+ sn_transmit_chars(port, TRANSMIT_RAW);
+ spin_unlock_irqrestore(&port->sc_port.lock, flags);
+ mod_timer(&port->sc_timer,
+diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
+index f851f0f..03941d2 100644
+--- a/drivers/serial/sunhv.c
++++ b/drivers/serial/sunhv.c
+@@ -73,7 +73,7 @@ static inline long hypervisor_con_putcha
+
+ static int hung_up = 0;
+
+-static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs)
++static struct tty_struct *receive_chars(struct uart_port *port)
+ {
+ struct tty_struct *tty = NULL;
+ int saw_console_brk = 0;
+@@ -106,7 +106,7 @@ static struct tty_struct *receive_chars(
+ }
+
+ if (tty == NULL) {
+- uart_handle_sysrq_char(port, c, regs);
++ uart_handle_sysrq_char(port, c);
+ continue;
+ }
+
+@@ -119,7 +119,7 @@ static struct tty_struct *receive_chars(
+ flag = TTY_BREAK;
+ }
+
+- if (uart_handle_sysrq_char(port, c, regs))
++ if (uart_handle_sysrq_char(port, c))
+ continue;
+
+ if ((port->ignore_status_mask & IGNORE_ALL) ||
+@@ -161,14 +161,14 @@ static void transmit_chars(struct uart_p
+ uart_write_wakeup(port);
+ }
+
+-static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
+ {
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+- tty = receive_chars(port, regs);
++ tty = receive_chars(port);
+ transmit_chars(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
+index cfe20f7..08a7cd6 100644
+--- a/drivers/serial/sunsab.c
++++ b/drivers/serial/sunsab.c
+@@ -108,8 +108,7 @@ static __inline__ void sunsab_cec_wait(s
+
+ static struct tty_struct *
+ receive_chars(struct uart_sunsab_port *up,
+- union sab82532_irq_status *stat,
+- struct pt_regs *regs)
++ union sab82532_irq_status *stat)
+ {
+ struct tty_struct *tty = NULL;
+ unsigned char buf[32];
+@@ -161,7 +160,7 @@ receive_chars(struct uart_sunsab_port *u
+ unsigned char ch = buf[i], flag;
+
+ if (tty == NULL) {
+- uart_handle_sysrq_char(&up->port, ch, regs);
++ uart_handle_sysrq_char(&up->port, ch);
+ continue;
+ }
+
+@@ -208,7 +207,7 @@ receive_chars(struct uart_sunsab_port *u
+ flag = TTY_FRAME;
+ }
+
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ continue;
+
+ if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
+@@ -301,7 +300,7 @@ static void check_status(struct uart_sun
+ wake_up_interruptible(&up->port.info->delta_msr_wait);
+ }
+
+-static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
+ {
+ struct uart_sunsab_port *up = dev_id;
+ struct tty_struct *tty;
+@@ -321,7 +320,7 @@ static irqreturn_t sunsab_interrupt(int
+ if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
+ SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
+ (status.sreg.isr1 & SAB82532_ISR1_BRK))
+- tty = receive_chars(up, &status, regs);
++ tty = receive_chars(up, &status);
+ if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
+ (status.sreg.isr1 & SAB82532_ISR1_CSC))
+ check_status(up, &status);
+@@ -350,7 +349,7 @@ static irqreturn_t sunsab_interrupt(int
+ SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
+ (status.sreg.isr1 & SAB82532_ISR1_BRK))
+
+- tty = receive_chars(up, &status, regs);
++ tty = receive_chars(up, &status);
+ if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
+ (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
+ check_status(up, &status);
+diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
+index d3a5aee..c577fae 100644
+--- a/drivers/serial/sunsu.c
++++ b/drivers/serial/sunsu.c
+@@ -310,7 +310,7 @@ static void sunsu_enable_ms(struct uart_
+ }
+
+ static struct tty_struct *
+-receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs *regs)
++receive_chars(struct uart_sunsu_port *up, unsigned char *status)
+ {
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned char ch, flag;
+@@ -367,7 +367,7 @@ receive_chars(struct uart_sunsu_port *up
+ else if (*status & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ goto ignore_char;
+ if ((*status & up->port.ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+@@ -445,7 +445,7 @@ static void check_modem_status(struct ua
+ wake_up_interruptible(&up->port.info->delta_msr_wait);
+ }
+
+-static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
+ {
+ struct uart_sunsu_port *up = dev_id;
+ unsigned long flags;
+@@ -459,7 +459,7 @@ static irqreturn_t sunsu_serial_interrup
+ status = serial_inp(up, UART_LSR);
+ tty = NULL;
+ if (status & UART_LSR_DR)
+- tty = receive_chars(up, &status, regs);
++ tty = receive_chars(up, &status);
+ check_modem_status(up);
+ if (status & UART_LSR_THRE)
+ transmit_chars(up);
+@@ -497,7 +497,7 @@ static void sunsu_change_mouse_baud(stru
+ sunsu_change_speed(&up->port, up->cflag, 0, quot);
+ }
+
+-static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *regs, int is_break)
++static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
+ {
+ do {
+ unsigned char ch = serial_inp(up, UART_RX);
+@@ -505,7 +505,7 @@ static void receive_kbd_ms_chars(struct
+ /* Stop-A is handled by drivers/char/keyboard.c now. */
+ if (up->su_type == SU_PORT_KBD) {
+ #ifdef CONFIG_SERIO
+- serio_interrupt(&up->serio, ch, 0, regs);
++ serio_interrupt(&up->serio, ch, 0);
+ #endif
+ } else if (up->su_type == SU_PORT_MS) {
+ int ret = suncore_mouse_baud_detection(ch, is_break);
+@@ -519,7 +519,7 @@ static void receive_kbd_ms_chars(struct
+
+ case 0:
+ #ifdef CONFIG_SERIO
+- serio_interrupt(&up->serio, ch, 0, regs);
++ serio_interrupt(&up->serio, ch, 0);
+ #endif
+ break;
+ };
+@@ -527,7 +527,7 @@ static void receive_kbd_ms_chars(struct
+ } while (serial_in(up, UART_LSR) & UART_LSR_DR);
+ }
+
+-static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
+ {
+ struct uart_sunsu_port *up = dev_id;
+
+@@ -535,8 +535,7 @@ static irqreturn_t sunsu_kbd_ms_interrup
+ unsigned char status = serial_inp(up, UART_LSR);
+
+ if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
+- receive_kbd_ms_chars(up, regs,
+- (status & UART_LSR_BI) != 0);
++ receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
+ }
+
+ return IRQ_HANDLED;
+@@ -1499,6 +1498,9 @@ static int __devexit su_remove(struct of
+ uart_remove_one_port(&sunsu_reg, &up->port);
+ }
+
++ if (up->port.membase)
++ of_iounmap(up->port.membase, up->reg_size);
++
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
+diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
+index d34f336..b2cc703 100644
+--- a/drivers/serial/sunzilog.c
++++ b/drivers/serial/sunzilog.c
+@@ -277,14 +277,13 @@ static void sunzilog_change_mouse_baud(s
+ }
+
+ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
+- unsigned char ch, int is_break,
+- struct pt_regs *regs)
++ unsigned char ch, int is_break)
+ {
+ if (ZS_IS_KEYB(up)) {
+ /* Stop-A is handled by drivers/char/keyboard.c now. */
+ #ifdef CONFIG_SERIO
+ if (up->serio_open)
+- serio_interrupt(&up->serio, ch, 0, regs);
++ serio_interrupt(&up->serio, ch, 0);
+ #endif
+ } else if (ZS_IS_MOUSE(up)) {
+ int ret = suncore_mouse_baud_detection(ch, is_break);
+@@ -299,7 +298,7 @@ static void sunzilog_kbdms_receive_chars
+ case 0:
+ #ifdef CONFIG_SERIO
+ if (up->serio_open)
+- serio_interrupt(&up->serio, ch, 0, regs);
++ serio_interrupt(&up->serio, ch, 0);
+ #endif
+ break;
+ };
+@@ -308,8 +307,7 @@ static void sunzilog_kbdms_receive_chars
+
+ static struct tty_struct *
+ sunzilog_receive_chars(struct uart_sunzilog_port *up,
+- struct zilog_channel __iomem *channel,
+- struct pt_regs *regs)
++ struct zilog_channel __iomem *channel)
+ {
+ struct tty_struct *tty;
+ unsigned char ch, r1, flag;
+@@ -346,12 +344,12 @@ sunzilog_receive_chars(struct uart_sunzi
+ ch &= up->parity_mask;
+
+ if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
+- sunzilog_kbdms_receive_chars(up, ch, 0, regs);
++ sunzilog_kbdms_receive_chars(up, ch, 0);
+ continue;
+ }
+
+ if (tty == NULL) {
+- uart_handle_sysrq_char(&up->port, ch, regs);
++ uart_handle_sysrq_char(&up->port, ch);
+ continue;
+ }
+
+@@ -379,7 +377,7 @@ sunzilog_receive_chars(struct uart_sunzi
+ else if (r1 & CRC_ERR)
+ flag = TTY_FRAME;
+ }
+- if (uart_handle_sysrq_char(&up->port, ch, regs))
++ if (uart_handle_sysrq_char(&up->port, ch))
+ continue;
+
+ if (up->port.ignore_status_mask == 0xff ||
+@@ -394,8 +392,7 @@ sunzilog_receive_chars(struct uart_sunzi
+ }
+
+ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
+- struct zilog_channel __iomem *channel,
+- struct pt_regs *regs)
++ struct zilog_channel __iomem *channel)
+ {
+ unsigned char status;
+
+@@ -408,7 +405,7 @@ static void sunzilog_status_handle(struc
+
+ if (status & BRK_ABRT) {
+ if (ZS_IS_MOUSE(up))
+- sunzilog_kbdms_receive_chars(up, 0, 1, regs);
++ sunzilog_kbdms_receive_chars(up, 0, 1);
+ if (ZS_IS_CONS(up)) {
+ /* Wait for BREAK to deassert to avoid potentially
+ * confusing the PROM.
+@@ -517,7 +514,7 @@ ack_tx_int:
+ ZS_WSYNC(channel);
+ }
+
+-static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
+ {
+ struct uart_sunzilog_port *up = dev_id;
+
+@@ -538,9 +535,9 @@ static irqreturn_t sunzilog_interrupt(in
+ ZS_WSYNC(channel);
+
+ if (r3 & CHARxIP)
+- tty = sunzilog_receive_chars(up, channel, regs);
++ tty = sunzilog_receive_chars(up, channel);
+ if (r3 & CHAEXT)
+- sunzilog_status_handle(up, channel, regs);
++ sunzilog_status_handle(up, channel);
+ if (r3 & CHATxIP)
+ sunzilog_transmit_chars(up, channel);
+ }
+@@ -561,9 +558,9 @@ static irqreturn_t sunzilog_interrupt(in
+ ZS_WSYNC(channel);
+
+ if (r3 & CHBRxIP)
+- tty = sunzilog_receive_chars(up, channel, regs);
++ tty = sunzilog_receive_chars(up, channel);
+ if (r3 & CHBEXT)
+- sunzilog_status_handle(up, channel, regs);
++ sunzilog_status_handle(up, channel);
+ if (r3 & CHBTxIP)
+ sunzilog_transmit_chars(up, channel);
+ }
+@@ -1060,7 +1057,7 @@ static void sunzilog_free_tables(void)
+
+ static void sunzilog_putchar(struct uart_port *port, int ch)
+ {
+- struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
++ struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+ int loops = ZS_PUT_CHAR_MAX_DELAY;
+
+ /* This is a timed polling loop so do not switch the explicit
+@@ -1185,7 +1182,7 @@ static int __init sunzilog_console_setup
+ return 0;
+ }
+
+-static struct console sunzilog_console = {
++static struct console sunzilog_console_ops = {
+ .name = "ttyS",
+ .write = sunzilog_console_write,
+ .device = uart_console_device,
+@@ -1211,10 +1208,10 @@ static inline struct console *SUNZILOG_C
+ if (i == NUM_CHANNELS)
+ return NULL;
+
+- sunzilog_console.index = i;
++ sunzilog_console_ops.index = i;
+ sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
+
+- return &sunzilog_console;
++ return &sunzilog_console_ops;
+ }
+
+ #else
+@@ -1270,7 +1267,7 @@ static void __init sunzilog_register_ser
+ }
+ #endif
+
+-static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
++static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
+ {
+ struct zilog_channel __iomem *channel;
+ unsigned long flags;
+diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
+index f802867..28f3bbf 100644
+--- a/drivers/serial/v850e_uart.c
++++ b/drivers/serial/v850e_uart.c
+@@ -271,14 +271,14 @@ void v850e_uart_tx (struct uart_port *po
+ v850e_uart_stop_tx (port, stopped);
+ }
+
+-static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t v850e_uart_tx_irq(int irq, void *data)
+ {
+ struct uart_port *port = data;
+ v850e_uart_tx (port);
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t v850e_uart_rx_irq(int irq, void *data)
+ {
+ struct uart_port *port = data;
+ unsigned ch_stat = TTY_NORMAL;
+diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
+index 6c8b0ea..fd51f81 100644
+--- a/drivers/serial/vr41xx_siu.c
++++ b/drivers/serial/vr41xx_siu.c
+@@ -359,8 +359,7 @@ static void siu_break_ctl(struct uart_po
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+
+-static inline void receive_chars(struct uart_port *port, uint8_t *status,
+- struct pt_regs *regs)
++static inline void receive_chars(struct uart_port *port, uint8_t *status)
+ {
+ struct tty_struct *tty;
+ uint8_t lsr, ch;
+@@ -405,7 +404,7 @@ static inline void receive_chars(struct
+ flag = TTY_PARITY;
+ }
+
+- if (uart_handle_sysrq_char(port, ch, regs))
++ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+@@ -472,7 +471,7 @@ static inline void transmit_chars(struct
+ siu_stop_tx(port);
+ }
+
+-static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t siu_interrupt(int irq, void *dev_id)
+ {
+ struct uart_port *port;
+ uint8_t iir, lsr;
+@@ -485,7 +484,7 @@ static irqreturn_t siu_interrupt(int irq
+
+ lsr = siu_read(port, UART_LSR);
+ if (lsr & UART_LSR_DR)
+- receive_chars(port, &lsr, regs);
++ receive_chars(port, &lsr);
+
+ check_modem_status(port);
+
+diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig
+index a347316..c66ba9a 100644
+--- a/drivers/sn/Kconfig
++++ b/drivers/sn/Kconfig
+@@ -5,19 +5,6 @@
+ menu "SN Devices"
+ depends on SGI_SN
+
+-config SGI_IOC4
+- tristate "SGI IOC4 Base IO support"
+- depends on MMTIMER
+- default m
+- ---help---
+- This option enables basic support for the SGI IOC4-based Base IO
+- controller card. This option does not enable any specific
+- functions on such a card, but provides necessary infrastructure
+- for other drivers to utilize.
+-
+- If you have an SGI Altix with an IOC4-based
+- I/O controller say Y. Otherwise say N.
+-
+ config SGI_IOC3
+ tristate "SGI IOC3 Base IO support"
+ default m
+diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile
+index 2cda011..693db8b 100644
+--- a/drivers/sn/Makefile
++++ b/drivers/sn/Makefile
+@@ -3,5 +3,4 @@
+ #
+ #
+
+-obj-$(CONFIG_SGI_IOC4) += ioc4.o
+ obj-$(CONFIG_SGI_IOC3) += ioc3.o
+diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
+index 6c7e035..cd6b653 100644
+--- a/drivers/sn/ioc3.c
++++ b/drivers/sn/ioc3.c
+@@ -398,10 +398,10 @@ static inline uint32_t get_pending_intrs
+ return intrs;
+ }
+
+-static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t ioc3_intr_io(int irq, void *arg)
+ {
+ unsigned long flags;
+- struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
++ struct ioc3_driver_data *idd = arg;
+ int handled = 1, id;
+ unsigned int pending;
+
+@@ -412,7 +412,7 @@ static irqreturn_t ioc3_intr_io(int irq,
+ if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
+ ioc3_ethernet->intr) {
+ handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
+- idd, 0, regs);
++ idd, 0);
+ }
+ }
+ pending = get_pending_intrs(idd); /* look at the IO IRQs */
+@@ -424,8 +424,7 @@ static irqreturn_t ioc3_intr_io(int irq,
+ write_ireg(idd, ioc3_submodules[id]->irq_mask,
+ IOC3_W_IEC);
+ if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
+- idd, pending & ioc3_submodules[id]->irq_mask,
+- regs))
++ idd, pending & ioc3_submodules[id]->irq_mask))
+ pending &= ~ioc3_submodules[id]->irq_mask;
+ if (ioc3_submodules[id]->reset_mask)
+ write_ireg(idd, ioc3_submodules[id]->irq_mask,
+@@ -442,7 +441,7 @@ static irqreturn_t ioc3_intr_io(int irq,
+ return handled?IRQ_HANDLED:IRQ_NONE;
+ }
+
+-static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs)
++static irqreturn_t ioc3_intr_eth(int irq, void *arg)
+ {
+ unsigned long flags;
+ struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
+@@ -453,8 +452,7 @@ static irqreturn_t ioc3_intr_eth(int irq
+ read_lock_irqsave(&ioc3_submodules_lock, flags);
+ if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
+ && ioc3_ethernet->intr)
+- handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0,
+- regs);
++ handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0);
+ read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+ return handled?IRQ_HANDLED:IRQ_NONE;
+ }
+diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c
+deleted file mode 100644
+index 8562821..0000000
+--- a/drivers/sn/ioc4.c
++++ /dev/null
+@@ -1,476 +0,0 @@
+-/*
+- * 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 file contains the master driver module for use by SGI IOC4 subdrivers.
+- *
+- * It allocates any resources shared between multiple subdevices, and
+- * provides accessor functions (where needed) and the like for those
+- * resources. It also provides a mechanism for the subdevice modules
+- * to support loading and unloading.
+- *
+- * Non-shared resources (e.g. external interrupt A_INT_OUT register page
+- * alias, serial port and UART registers) are handled by the subdevice
+- * modules themselves.
+- *
+- * This is all necessary because IOC4 is not implemented as a multi-function
+- * PCI device, but an amalgamation of disparate registers for several
+- * types of device (ATA, serial, external interrupts). The normal
+- * resource management in the kernel doesn't have quite the right interfaces
+- * to handle this situation (e.g. multiple modules can't claim the same
+- * PCI ID), thus this IOC4 master module.
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/ioc4.h>
+-#include <linux/mmtimer.h>
+-#include <linux/rtc.h>
+-#include <linux/mutex.h>
+-#include <asm/sn/addrs.h>
+-#include <asm/sn/clksupport.h>
+-#include <asm/sn/shub_mmr.h>
+-
+-/***************
+- * Definitions *
+- ***************/
+-
+-/* Tweakable values */
+-
+-/* PCI bus speed detection/calibration */
+-#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
+-#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */
+-#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */
+-#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */
+-#define IOC4_CALIBRATE_HIGH_MHZ 75 /* Upper bound on bus speed sanity */
+-#define IOC4_CALIBRATE_DEFAULT_MHZ 66 /* Assumed if sanity check fails */
+-
+-/************************
+- * Submodule management *
+- ************************/
+-
+-static DEFINE_MUTEX(ioc4_mutex);
+-
+-static LIST_HEAD(ioc4_devices);
+-static LIST_HEAD(ioc4_submodules);
+-
+-/* Register an IOC4 submodule */
+-int
+-ioc4_register_submodule(struct ioc4_submodule *is)
+-{
+- struct ioc4_driver_data *idd;
+-
+- mutex_lock(&ioc4_mutex);
+- list_add(&is->is_list, &ioc4_submodules);
+-
+- /* Initialize submodule for each IOC4 */
+- if (!is->is_probe)
+- goto out;
+-
+- list_for_each_entry(idd, &ioc4_devices, idd_list) {
+- if (is->is_probe(idd)) {
+- printk(KERN_WARNING
+- "%s: IOC4 submodule %s probe failed "
+- "for pci_dev %s",
+- __FUNCTION__, module_name(is->is_owner),
+- pci_name(idd->idd_pdev));
+- }
+- }
+- out:
+- mutex_unlock(&ioc4_mutex);
+- return 0;
+-}
+-
+-/* Unregister an IOC4 submodule */
+-void
+-ioc4_unregister_submodule(struct ioc4_submodule *is)
+-{
+- struct ioc4_driver_data *idd;
+-
+- mutex_lock(&ioc4_mutex);
+- list_del(&is->is_list);
+-
+- /* Remove submodule for each IOC4 */
+- if (!is->is_remove)
+- goto out;
+-
+- list_for_each_entry(idd, &ioc4_devices, idd_list) {
+- if (is->is_remove(idd)) {
+- printk(KERN_WARNING
+- "%s: IOC4 submodule %s remove failed "
+- "for pci_dev %s.\n",
+- __FUNCTION__, module_name(is->is_owner),
+- pci_name(idd->idd_pdev));
+- }
+- }
+- out:
+- mutex_unlock(&ioc4_mutex);
+-}
+-
+-/*********************
+- * Device management *
+- *********************/
+-
+-#define IOC4_CALIBRATE_LOW_LIMIT \
+- (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
+-#define IOC4_CALIBRATE_HIGH_LIMIT \
+- (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
+-#define IOC4_CALIBRATE_DEFAULT \
+- (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
+-
+-#define IOC4_CALIBRATE_END \
+- (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
+-
+-#define IOC4_INT_OUT_MODE_TOGGLE 0x7 /* Toggle INT_OUT every COUNT+1 ticks */
+-
+-/* Determines external interrupt output clock period of the PCI bus an
+- * IOC4 is attached to. This value can be used to determine the PCI
+- * bus speed.
+- *
+- * IOC4 has a design feature that various internal timers are derived from
+- * the PCI bus clock. This causes IOC4 device drivers to need to take the
+- * bus speed into account when setting various register values (e.g. INT_OUT
+- * register COUNT field, UART divisors, etc). Since this information is
+- * needed by several subdrivers, it is determined by the main IOC4 driver,
+- * even though the following code utilizes external interrupt registers
+- * to perform the speed calculation.
+- */
+-static void
+-ioc4_clock_calibrate(struct ioc4_driver_data *idd)
+-{
+- extern unsigned long sn_rtc_cycles_per_second;
+- union ioc4_int_out int_out;
+- union ioc4_gpcr gpcr;
+- unsigned int state, last_state = 1;
+- uint64_t start = 0, end, period;
+- unsigned int count = 0;
+-
+- /* Enable output */
+- gpcr.raw = 0;
+- gpcr.fields.dir = IOC4_GPCR_DIR_0;
+- gpcr.fields.int_out_en = 1;
+- writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
+-
+- /* Reset to power-on state */
+- writel(0, &idd->idd_misc_regs->int_out.raw);
+- mmiowb();
+-
+- /* Set up square wave */
+- int_out.raw = 0;
+- int_out.fields.count = IOC4_CALIBRATE_COUNT;
+- int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
+- int_out.fields.diag = 0;
+- writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
+- mmiowb();
+-
+- /* Check square wave period averaged over some number of cycles */
+- do {
+- int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
+- state = int_out.fields.int_out;
+- if (!last_state && state) {
+- count++;
+- if (count == IOC4_CALIBRATE_END) {
+- end = rtc_time();
+- break;
+- } else if (count == IOC4_CALIBRATE_DISCARD)
+- start = rtc_time();
+- }
+- last_state = state;
+- } while (1);
+-
+- /* Calculation rearranged to preserve intermediate precision.
+- * Logically:
+- * 1. "end - start" gives us number of RTC cycles over all the
+- * square wave cycles measured.
+- * 2. Divide by number of square wave cycles to get number of
+- * RTC cycles per square wave cycle.
+- * 3. Divide by 2*(int_out.fields.count+1), which is the formula
+- * by which the IOC4 generates the square wave, to get the
+- * number of RTC cycles per IOC4 INT_OUT count.
+- * 4. Divide by sn_rtc_cycles_per_second to get seconds per
+- * count.
+- * 5. Multiply by 1E9 to get nanoseconds per count.
+- */
+- period = ((end - start) * 1000000000) /
+- (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)
+- * sn_rtc_cycles_per_second);
+-
+- /* Bounds check the result. */
+- if (period > IOC4_CALIBRATE_LOW_LIMIT ||
+- period < IOC4_CALIBRATE_HIGH_LIMIT) {
+- printk(KERN_INFO
+- "IOC4 %s: Clock calibration failed. Assuming"
+- "PCI clock is %d ns.\n",
+- pci_name(idd->idd_pdev),
+- IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
+- period = IOC4_CALIBRATE_DEFAULT;
+- } else {
+- printk(KERN_DEBUG
+- "IOC4 %s: PCI clock is %ld ns.\n",
+- pci_name(idd->idd_pdev),
+- period / IOC4_EXTINT_COUNT_DIVISOR);
+- }
+-
+- /* Remember results. We store the extint clock period rather
+- * than the PCI clock period so that greater precision is
+- * retained. Divide by IOC4_EXTINT_COUNT_DIVISOR to get
+- * PCI clock period.
+- */
+- idd->count_period = period;
+-}
+-
+-/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT.
+- * Each brings out different combinations of IOC4 signals, thus.
+- * the IOC4 subdrivers need to know to which we're attached.
+- *
+- * We look for the presence of a SCSI (IO9) or SATA (IO10) controller
+- * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
+- * If neither is present, it's a PCI-RT.
+- */
+-static unsigned int
+-ioc4_variant(struct ioc4_driver_data *idd)
+-{
+- struct pci_dev *pdev = NULL;
+- int found = 0;
+-
+- /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */
+- do {
+- pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC,
+- PCI_DEVICE_ID_QLOGIC_ISP12160, pdev);
+- if (pdev &&
+- idd->idd_pdev->bus->number == pdev->bus->number &&
+- 3 == PCI_SLOT(pdev->devfn))
+- found = 1;
+- pci_dev_put(pdev);
+- } while (pdev && !found);
+- if (NULL != pdev)
+- return IOC4_VARIANT_IO9;
+-
+- /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
+- pdev = NULL;
+- do {
+- pdev = pci_get_device(PCI_VENDOR_ID_VITESSE,
+- PCI_DEVICE_ID_VITESSE_VSC7174, pdev);
+- if (pdev &&
+- idd->idd_pdev->bus->number == pdev->bus->number &&
+- 3 == PCI_SLOT(pdev->devfn))
+- found = 1;
+- pci_dev_put(pdev);
+- } while (pdev && !found);
+- if (NULL != pdev)
+- return IOC4_VARIANT_IO10;
+-
+- /* PCI-RT: No SCSI/SATA controller will be present */
+- return IOC4_VARIANT_PCI_RT;
+-}
+-
+-/* Adds a new instance of an IOC4 card */
+-static int
+-ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+-{
+- struct ioc4_driver_data *idd;
+- struct ioc4_submodule *is;
+- uint32_t pcmd;
+- int ret;
+-
+- /* Enable IOC4 and take ownership of it */
+- if ((ret = pci_enable_device(pdev))) {
+- printk(KERN_WARNING
+- "%s: Failed to enable IOC4 device for pci_dev %s.\n",
+- __FUNCTION__, pci_name(pdev));
+- goto out;
+- }
+- pci_set_master(pdev);
+-
+- /* Set up per-IOC4 data */
+- idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
+- if (!idd) {
+- printk(KERN_WARNING
+- "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
+- __FUNCTION__, pci_name(pdev));
+- ret = -ENODEV;
+- goto out_idd;
+- }
+- idd->idd_pdev = pdev;
+- idd->idd_pci_id = pci_id;
+-
+- /* Map IOC4 misc registers. These are shared between subdevices
+- * so the main IOC4 module manages them.
+- */
+- idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
+- if (!idd->idd_bar0) {
+- printk(KERN_WARNING
+- "%s: Unable to find IOC4 misc resource "
+- "for pci_dev %s.\n",
+- __FUNCTION__, pci_name(idd->idd_pdev));
+- ret = -ENODEV;
+- goto out_pci;
+- }
+- if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
+- "ioc4_misc")) {
+- printk(KERN_WARNING
+- "%s: Unable to request IOC4 misc region "
+- "for pci_dev %s.\n",
+- __FUNCTION__, pci_name(idd->idd_pdev));
+- ret = -ENODEV;
+- goto out_pci;
+- }
+- idd->idd_misc_regs = ioremap(idd->idd_bar0,
+- sizeof(struct ioc4_misc_regs));
+- if (!idd->idd_misc_regs) {
+- printk(KERN_WARNING
+- "%s: Unable to remap IOC4 misc region "
+- "for pci_dev %s.\n",
+- __FUNCTION__, pci_name(idd->idd_pdev));
+- ret = -ENODEV;
+- goto out_misc_region;
+- }
+-
+- /* Failsafe portion of per-IOC4 initialization */
+-
+- /* Detect card variant */
+- idd->idd_variant = ioc4_variant(idd);
+- printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev),
+- idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" :
+- idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" :
+- idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown");
+-
+- /* Initialize IOC4 */
+- pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
+- pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
+- pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+-
+- /* Determine PCI clock */
+- ioc4_clock_calibrate(idd);
+-
+- /* Disable/clear all interrupts. Need to do this here lest
+- * one submodule request the shared IOC4 IRQ, but interrupt
+- * is generated by a different subdevice.
+- */
+- /* Disable */
+- writel(~0, &idd->idd_misc_regs->other_iec.raw);
+- writel(~0, &idd->idd_misc_regs->sio_iec);
+- /* Clear (i.e. acknowledge) */
+- writel(~0, &idd->idd_misc_regs->other_ir.raw);
+- writel(~0, &idd->idd_misc_regs->sio_ir);
+-
+- /* Track PCI-device specific data */
+- idd->idd_serial_data = NULL;
+- pci_set_drvdata(idd->idd_pdev, idd);
+-
+- mutex_lock(&ioc4_mutex);
+- list_add_tail(&idd->idd_list, &ioc4_devices);
+-
+- /* Add this IOC4 to all submodules */
+- list_for_each_entry(is, &ioc4_submodules, is_list) {
+- if (is->is_probe && is->is_probe(idd)) {
+- printk(KERN_WARNING
+- "%s: IOC4 submodule 0x%s probe failed "
+- "for pci_dev %s.\n",
+- __FUNCTION__, module_name(is->is_owner),
+- pci_name(idd->idd_pdev));
+- }
+- }
+- mutex_unlock(&ioc4_mutex);
+-
+- return 0;
+-
+-out_misc_region:
+- release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
+-out_pci:
+- kfree(idd);
+-out_idd:
+- pci_disable_device(pdev);
+-out:
+- return ret;
+-}
+-
+-/* Removes a particular instance of an IOC4 card. */
+-static void
+-ioc4_remove(struct pci_dev *pdev)
+-{
+- struct ioc4_submodule *is;
+- struct ioc4_driver_data *idd;
+-
+- idd = pci_get_drvdata(pdev);
+-
+- /* Remove this IOC4 from all submodules */
+- mutex_lock(&ioc4_mutex);
+- list_for_each_entry(is, &ioc4_submodules, is_list) {
+- if (is->is_remove && is->is_remove(idd)) {
+- printk(KERN_WARNING
+- "%s: IOC4 submodule 0x%s remove failed "
+- "for pci_dev %s.\n",
+- __FUNCTION__, module_name(is->is_owner),
+- pci_name(idd->idd_pdev));
+- }
+- }
+- mutex_unlock(&ioc4_mutex);
+-
+- /* Release resources */
+- iounmap(idd->idd_misc_regs);
+- if (!idd->idd_bar0) {
+- printk(KERN_WARNING
+- "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
+- "Device removal may be incomplete.\n",
+- __FUNCTION__, pci_name(idd->idd_pdev));
+- }
+- release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
+-
+- /* Disable IOC4 and relinquish */
+- pci_disable_device(pdev);
+-
+- /* Remove and free driver data */
+- mutex_lock(&ioc4_mutex);
+- list_del(&idd->idd_list);
+- mutex_unlock(&ioc4_mutex);
+- kfree(idd);
+-}
+-
+-static struct pci_device_id ioc4_id_table[] = {
+- {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
+- PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
+- {0}
+-};
+-
+-static struct pci_driver ioc4_driver = {
+- .name = "IOC4",
+- .id_table = ioc4_id_table,
+- .probe = ioc4_probe,
+- .remove = ioc4_remove,
+-};
+-
+-MODULE_DEVICE_TABLE(pci, ioc4_id_table);
+-
+-/*********************
+- * Module management *
+- *********************/
+-
+-/* Module load */
+-static int __devinit
+-ioc4_init(void)
+-{
+- return pci_register_driver(&ioc4_driver);
+-}
+-
+-/* Module unload */
+-static void __devexit
+-ioc4_exit(void)
+-{
+- pci_unregister_driver(&ioc4_driver);
+-}
+-
+-module_init(ioc4_init);
+-module_exit(ioc4_exit);
+-
+-MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan at sgi.com>");
+-MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
+-MODULE_LICENSE("GPL");
+-
+-EXPORT_SYMBOL(ioc4_register_submodule);
+-EXPORT_SYMBOL(ioc4_unregister_submodule);
+diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
+index 29aec77..72025df 100644
+--- a/drivers/spi/pxa2xx_spi.c
++++ b/drivers/spi/pxa2xx_spi.c
+@@ -409,7 +409,7 @@ static int wait_dma_channel_stop(int cha
+ return limit;
+ }
+
+-static void dma_handler(int channel, void *data, struct pt_regs *regs)
++static void dma_handler(int channel, void *data)
+ {
+ struct driver_data *drv_data = data;
+ struct spi_message *msg = drv_data->cur_msg;
+@@ -667,9 +667,9 @@ static irqreturn_t interrupt_transfer(st
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ssp_int(int irq, void *dev_id)
+ {
+- struct driver_data *drv_data = (struct driver_data *)dev_id;
++ struct driver_data *drv_data = dev_id;
+ void *reg = drv_data->ioaddr;
+
+ if (!drv_data->cur_msg) {
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 146298a..c3c0626 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -281,7 +281,6 @@ spi_register_board_info(struct spi_board
+ up(&board_lock);
+ return 0;
+ }
+-EXPORT_SYMBOL_GPL(spi_register_board_info);
+
+ /* FIXME someone should add support for a __setup("spi", ...) that
+ * creates board info from kernel command lines
+diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
+index 5d92a7e..ff0b048 100644
+--- a/drivers/spi/spi_mpc83xx.c
++++ b/drivers/spi/spi_mpc83xx.c
+@@ -296,8 +296,7 @@ static int mpc83xx_spi_bufs(struct spi_d
+ return t->len - mpc83xx_spi->count;
+ }
+
+-irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data,
+- struct pt_regs * ptregs)
++irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
+ {
+ struct mpc83xx_spi *mpc83xx_spi = context_data;
+ u32 event;
+diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
+index 5fc1456..2ebe1fc 100644
+--- a/drivers/spi/spi_s3c24xx.c
++++ b/drivers/spi/spi_s3c24xx.c
+@@ -13,7 +13,6 @@
+
+ //#define DEBUG
+
+-#include <linux/config.h>
+ #include <linux/init.h>
+ #include <linux/spinlock.h>
+ #include <linux/workqueue.h>
+@@ -197,7 +196,7 @@ static int s3c24xx_spi_txrx(struct spi_d
+ return hw->count;
+ }
+
+-static irqreturn_t s3c24xx_spi_irq(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
+ {
+ struct s3c24xx_spi *hw = dev;
+ unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
+diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
+index aacdceb..a5d2cdf 100644
+--- a/drivers/spi/spi_s3c24xx_gpio.c
++++ b/drivers/spi/spi_s3c24xx_gpio.c
+@@ -11,7 +11,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
+index 5e8a276..792becd 100644
+--- a/drivers/tc/zs.c
++++ b/drivers/tc/zs.c
+@@ -347,7 +347,7 @@ static void rs_sched_event(struct dec_se
+ tasklet_schedule(&info->tlet);
+ }
+
+-static void receive_chars(struct dec_serial *info, struct pt_regs *regs)
++static void receive_chars(struct dec_serial *info)
+ {
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, stat, flag;
+@@ -389,7 +389,7 @@ static void receive_chars(struct dec_ser
+ if (ch == 0)
+ continue;
+ if (time_before(jiffies, break_pressed + HZ * 5)) {
+- handle_sysrq(ch, regs, NULL);
++ handle_sysrq(ch, NULL);
+ break_pressed = 0;
+ continue;
+ }
+@@ -490,7 +490,7 @@ static void status_handle(struct dec_ser
+ /*
+ * This is the serial driver's generic interrupt routine
+ */
+-static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t rs_interrupt(int irq, void *dev_id)
+ {
+ struct dec_serial *info = (struct dec_serial *) dev_id;
+ irqreturn_t status = IRQ_NONE;
+@@ -518,7 +518,7 @@ static irqreturn_t rs_interrupt(int irq,
+ status = IRQ_HANDLED;
+
+ if (zs_intreg & CHBRxIP) {
+- receive_chars(info, regs);
++ receive_chars(info);
+ }
+ if (zs_intreg & CHBTxIP) {
+ transmit_chars(info);
+@@ -1701,7 +1701,7 @@ static void __init probe_sccs(void)
+ spin_unlock_irqrestore(&zs_lock, flags);
+ }
+
+-static struct tty_operations serial_ops = {
++static const struct tty_operations serial_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
+index f6b2948..1b601b6 100644
+--- a/drivers/telephony/ixj.c
++++ b/drivers/telephony/ixj.c
+@@ -284,6 +284,14 @@ static int samplerate = 100;
+
+ module_param(ixjdebug, int, 0);
+
++static struct pci_device_id ixj_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
++};
++
++MODULE_DEVICE_TABLE(pci, ixj_pci_tbl);
++
+ /************************************************************************
+ *
+ * ixjdebug meanings are now bit mapped instead of level based
+@@ -7683,7 +7691,8 @@ static int __init ixj_probe_pci(int *cnt
+ IXJ *j = NULL;
+
+ for (i = 0; i < IXJMAX - *cnt; i++) {
+- pci = pci_find_device(0x15E2, 0x0500, pci);
++ pci = pci_find_device(PCI_VENDOR_ID_QUICKNET,
++ PCI_DEVICE_ID_QUICKNET_XJ, pci);
+ if (!pci)
+ break;
+
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 0050431..f9b1719 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -25,6 +25,7 @@ config USB_ARCH_HAS_OHCI
+ default y if PXA27x
+ default y if ARCH_EP93XX
+ default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
++ default y if ARCH_PNX4008
+ # PPC:
+ default y if STB03xxx
+ default y if PPC_MPC52xx
+diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
+index 4710eb0..825bf88 100644
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/
+ obj-$(CONFIG_USB_OHCI_HCD) += host/
+ obj-$(CONFIG_USB_UHCI_HCD) += host/
+ obj-$(CONFIG_USB_SL811_HCD) += host/
++obj-$(CONFIG_USB_U132_HCD) += host/
+ obj-$(CONFIG_ETRAX_USB_HOST) += host/
+ obj-$(CONFIG_USB_OHCI_AT91) += host/
+
+@@ -23,6 +24,7 @@ obj-$(CONFIG_USB_PRINTER) += class/
+ obj-$(CONFIG_USB_STORAGE) += storage/
+ obj-$(CONFIG_USB) += storage/
+
++obj-$(CONFIG_USB_ACECAD) += input/
+ obj-$(CONFIG_USB_AIPTEK) += input/
+ obj-$(CONFIG_USB_ATI_REMOTE) += input/
+ obj-$(CONFIG_USB_HID) += input/
+@@ -32,7 +34,6 @@ 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_CATC) += net/
+@@ -47,22 +48,25 @@ obj-$(CONFIG_USB_MICROTEK) += image/
+
+ obj-$(CONFIG_USB_SERIAL) += serial/
+
++obj-$(CONFIG_USB_ADUTUX) += misc/
++obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
+ obj-$(CONFIG_USB_AUERSWALD) += misc/
+ obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
+ obj-$(CONFIG_USB_CYTHERM) += misc/
+ obj-$(CONFIG_USB_EMI26) += misc/
+ obj-$(CONFIG_USB_EMI62) += misc/
++obj-$(CONFIG_USB_FTDI_ELAN) += 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_PHIDGETSERVO) += misc/
+ obj-$(CONFIG_USB_RIO500) += misc/
++obj-$(CONFIG_USB_SISUSBVGA) += misc/
+ obj-$(CONFIG_USB_TEST) += misc/
++obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
+ obj-$(CONFIG_USB_USS720) += misc/
+-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
+-obj-$(CONFIG_USB_SISUSBVGA) += misc/
+-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
+
+ obj-$(CONFIG_USB_ATM) += atm/
+ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
+diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
+index 550ddfa..b450cba 100644
+--- a/drivers/usb/atm/Kconfig
++++ b/drivers/usb/atm/Kconfig
+@@ -64,7 +64,7 @@ config USB_XUSBATM
+ 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
++ and reception as module parameters. You may need to initialize
+ the modem using a user space utility (a firmware loader for example).
+
+ To compile this driver as a module, choose M here: the
+diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
+index 04631dc..e656563 100644
+--- a/drivers/usb/atm/cxacru.c
++++ b/drivers/usb/atm/cxacru.c
+@@ -171,7 +171,7 @@ struct cxacru_data {
+ };
+
+ /* the following three functions are stolen from drivers/usb/core/message.c */
+-static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs)
++static void cxacru_blocking_completion(struct urb *urb)
+ {
+ complete((struct completion *)urb->context);
+ }
+@@ -793,6 +793,9 @@ static const struct usb_device_id cxacru
+ { /* V = Conexant P = ADSL modem */
+ USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00
+ },
++ { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */
++ USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00
++ },
+ { /* V = Olitec P = ADSL modem version 2 */
+ USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe
+ },
+diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
+index 956b7a1..c870c80 100644
+--- a/drivers/usb/atm/speedtch.c
++++ b/drivers/usb/atm/speedtch.c
+@@ -55,7 +55,6 @@ static const char speedtch_driver_name[]
+ #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
+@@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512
+ static int enable_isoc = DEFAULT_ENABLE_ISOC;
+ static int sw_buffering = DEFAULT_SW_BUFFERING;
+
++#define DEFAULT_B_MAX_DSL 8128
++#define DEFAULT_MODEM_MODE 11
++#define MODEM_OPTION_LENGTH 16
++static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
++ 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
++static unsigned char ModemMode = DEFAULT_MODEM_MODE;
++static unsigned char ModemOption[MODEM_OPTION_LENGTH];
++static int num_ModemOption;
++
+ module_param(altsetting, uint, S_IRUGO | S_IWUSR);
+ MODULE_PARM_DESC(altsetting,
+ "Alternative setting for data interface (bulk_default: "
+@@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering,
+ "Enable software buffering (default: "
+ __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
+
++module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(BMaxDSL,
++ "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL));
++
++module_param(ModemMode, byte, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(ModemMode,
++ "default: " __MODULE_STRING(DEFAULT_MODEM_MODE));
++
++module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO);
++MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20");
++
+ #define INTERFACE_DATA 1
+ #define ENDPOINT_INT 0x81
+ #define ENDPOINT_BULK_DATA 0x07
+@@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering,
+
+ #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
+
++struct speedtch_params {
++ unsigned int altsetting;
++ unsigned int BMaxDSL;
++ unsigned char ModemMode;
++ unsigned char ModemOption[MODEM_OPTION_LENGTH];
++};
++
+ struct speedtch_instance_data {
+ struct usbatm_data *usbatm;
+
+- unsigned int altsetting;
++ struct speedtch_params params; /* set in probe, constant afterwards */
+
+ struct work_struct status_checker;
+
+@@ -123,7 +152,7 @@ struct speedtch_instance_data {
+ struct urb *int_urb;
+ unsigned char int_data[16];
+
+- unsigned char scratch_buffer[TOTAL];
++ unsigned char scratch_buffer[16];
+ };
+
+ /***************
+@@ -186,6 +215,34 @@ static void speedtch_test_sequence(struc
+ 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
+ if (ret < 0)
+ usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
++
++ /* Extra initialisation in recent drivers - gives higher speeds */
++
++ /* URBext1 */
++ buf[0] = instance->params.ModemMode;
++ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
++ 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT);
++ if (ret < 0)
++ usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret);
++
++ /* URBext2 */
++ /* This seems to be the one which actually triggers the higher sync
++ rate -- it does require the new firmware too, although it works OK
++ with older firmware */
++ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
++ 0x01, 0x40, 0x14, 0x00,
++ instance->params.ModemOption,
++ MODEM_OPTION_LENGTH, CTRL_TIMEOUT);
++ if (ret < 0)
++ usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret);
++
++ /* URBext3 */
++ buf[0] = instance->params.BMaxDSL & 0xff;
++ buf[1] = instance->params.BMaxDSL >> 8;
++ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
++ 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT);
++ if (ret < 0)
++ usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret);
+ }
+
+ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
+@@ -285,8 +342,8 @@ static int speedtch_upload_firmware(stru
+ because we're in our own kernel thread anyway. */
+ msleep_interruptible(1000);
+
+- if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
+- usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret);
++ if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
++ usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret);
+ goto out_free;
+ }
+
+@@ -372,7 +429,7 @@ static int speedtch_read_status(struct s
+ unsigned char *buf = instance->scratch_buffer;
+ int ret;
+
+- memset(buf, 0, TOTAL);
++ memset(buf, 0, 16);
+
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
+@@ -547,7 +604,7 @@ static void speedtch_resubmit_int(unsign
+ }
+ }
+
+-static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs)
++static void speedtch_handle_int(struct urb *int_urb)
+ {
+ struct speedtch_instance_data *instance = int_urb->context;
+ struct usbatm_data *usbatm = instance->usbatm;
+@@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_d
+
+ instance->usbatm = usbatm;
+
+- /* altsetting and enable_isoc may change at any moment, so take a snapshot */
+- instance->altsetting = altsetting;
++ /* module parameters may change at any moment, so take a snapshot */
++ instance->params.altsetting = altsetting;
++ instance->params.BMaxDSL = BMaxDSL;
++ instance->params.ModemMode = ModemMode;
++ memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH);
++ memcpy(instance->params.ModemOption, ModemOption, num_ModemOption);
+ use_isoc = enable_isoc;
+
+- if (instance->altsetting)
+- if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
+- usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret);
+- instance->altsetting = 0; /* fall back to default */
++ if (instance->params.altsetting)
++ if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
++ usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret);
++ instance->params.altsetting = 0; /* fall back to default */
+ }
+
+- if (!instance->altsetting && use_isoc)
++ if (!instance->params.altsetting && use_isoc)
+ if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) {
+ usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret);
+ use_isoc = 0; /* fall back to bulk */
+@@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_d
+ usb_info(usbatm, "isochronous transfer not supported - using bulk\n");
+ }
+
+- if (!use_isoc && !instance->altsetting)
++ if (!use_isoc && !instance->params.altsetting)
+ if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) {
+ usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret);
+ goto fail_free;
+ }
+
+- if (!instance->altsetting)
+- instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
++ if (!instance->params.altsetting)
++ instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
+
+ usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
+
+diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
+index b38990a..f6b9f7e 100644
+--- a/drivers/usb/atm/ueagle-atm.c
++++ b/drivers/usb/atm/ueagle-atm.c
+@@ -68,7 +68,7 @@
+
+ #include "usbatm.h"
+
+-#define EAGLEUSBVERSION "ueagle 1.3"
++#define EAGLEUSBVERSION "ueagle 1.4"
+
+
+ /*
+@@ -80,14 +80,14 @@
+ dev_dbg(&(usb_dev)->dev, \
+ "[ueagle-atm dbg] %s: " format, \
+ __FUNCTION__, ##args); \
+- } while (0)
++ } while (0)
+
+ #define uea_vdbg(usb_dev, format, args...) \
+ do { \
+ if (debug >= 2) \
+ dev_dbg(&(usb_dev)->dev, \
+ "[ueagle-atm vdbg] " format, ##args); \
+- } while (0)
++ } while (0)
+
+ #define uea_enters(usb_dev) \
+ uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
+@@ -218,8 +218,8 @@ enum {
+ #define UEA_CHIP_VERSION(x) \
+ ((x)->driver_info & 0xf)
+
+-#define IS_ISDN(sc) \
+- (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)
++#define IS_ISDN(usb_dev) \
++ (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+
+ #define INS_TO_USBDEV(ins) ins->usb_dev
+
+@@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc
+ char *dsp_name;
+
+ if (UEA_CHIP_VERSION(sc) == ADI930) {
+- if (IS_ISDN(sc))
++ if (IS_ISDN(sc->usb_dev))
+ dsp_name = FW_DIR "DSP9i.bin";
+ else
+ dsp_name = FW_DIR "DSP9p.bin";
+ } else {
+- if (IS_ISDN(sc))
++ if (IS_ISDN(sc->usb_dev))
+ dsp_name = FW_DIR "DSPei.bin";
+ else
+ dsp_name = FW_DIR "DSPep.bin";
+@@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struc
+
+ static inline int wait_cmv_ack(struct uea_softc *sc)
+ {
+- int ret = wait_event_timeout(sc->cmv_ack_wait,
++ int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
+ sc->cmv_ack, ACK_TIMEOUT);
+ sc->cmv_ack = 0;
+
+@@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc
+ break;
+
+ case 3: /* fail ... */
+- uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n");
++ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
++ " (may be try other cmv/dsp)\n");
+ return -EAGAIN;
+
+ case 4 ... 6: /* test state */
+@@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+-
+- ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+- if (ret < 0)
+- return ret;
+- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+- sc->stats.phy.firmid);
+ }
+
+ /* always update it as atm layer could not be init when we switch to
+@@ -1033,9 +1028,9 @@ static int request_cmvs(struct uea_softc
+
+ if (cmv_file[sc->modem_index] == NULL) {
+ if (UEA_CHIP_VERSION(sc) == ADI930)
+- file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin";
++ file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+ else
+- file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin";
++ file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+ } else
+ file = cmv_file[sc->modem_index];
+
+@@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_so
+ if (ret < 0)
+ return ret;
+
++ /* Dump firmware version */
++ ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
++ if (ret < 0)
++ return ret;
++ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
++ sc->stats.phy.firmid);
++
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
+ if (ret < 0)
+@@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_so
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
++ uea_info(INS_TO_USBDEV(sc), "Modem started, "
++ "waiting synchronization\n");
+ out:
+ release_firmware(cmvs_fw);
+ sc->reset = 0;
+@@ -1172,7 +1176,10 @@ static int uea_kthread(void *data)
+ if (!ret)
+ ret = uea_stat(sc);
+ if (ret != -EAGAIN)
+- msleep(1000);
++ msleep_interruptible(1000);
++ if (try_to_freeze())
++ uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
++ "please unplug/replug your modem\n");
+ }
+ uea_leaves(INS_TO_USBDEV(sc));
+ return ret;
+@@ -1297,7 +1304,7 @@ bad1:
+ /*
+ * interrupt handler
+ */
+-static void uea_intr(struct urb *urb, struct pt_regs *regs)
++static void uea_intr(struct urb *urb)
+ {
+ struct uea_softc *sc = urb->context;
+ struct intr_pkt *intr = urb->transfer_buffer;
+@@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0);
+ UEA_ATTR(dscorr, 0);
+ UEA_ATTR(usunc, 0);
+ UEA_ATTR(dsunc, 0);
++UEA_ATTR(firmid, 0);
+
+ /* Retrieve the device End System Identifier (MAC) */
+
+@@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data
+ {
+ struct uea_softc *sc = usbatm->driver_data;
+
+- wait_event(sc->sync_q, IS_OPERATIONAL(sc));
++ wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc));
+
+ return 0;
+
+@@ -1621,27 +1629,30 @@ static int claim_interface(struct usb_de
+ return ret;
+ }
+
+-static void create_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
+-{
+- /* sysfs interface */
+- device_create_file(&intf->dev, &dev_attr_stat_status);
+- device_create_file(&intf->dev, &dev_attr_stat_mflags);
+- device_create_file(&intf->dev, &dev_attr_stat_human_status);
+- device_create_file(&intf->dev, &dev_attr_stat_delin);
+- device_create_file(&intf->dev, &dev_attr_stat_vidcpe);
+- device_create_file(&intf->dev, &dev_attr_stat_usrate);
+- device_create_file(&intf->dev, &dev_attr_stat_dsrate);
+- device_create_file(&intf->dev, &dev_attr_stat_usattenuation);
+- device_create_file(&intf->dev, &dev_attr_stat_dsattenuation);
+- device_create_file(&intf->dev, &dev_attr_stat_usmargin);
+- device_create_file(&intf->dev, &dev_attr_stat_dsmargin);
+- device_create_file(&intf->dev, &dev_attr_stat_txflow);
+- device_create_file(&intf->dev, &dev_attr_stat_rxflow);
+- device_create_file(&intf->dev, &dev_attr_stat_uscorr);
+- device_create_file(&intf->dev, &dev_attr_stat_dscorr);
+- device_create_file(&intf->dev, &dev_attr_stat_usunc);
+- device_create_file(&intf->dev, &dev_attr_stat_dsunc);
+-}
++static struct attribute *attrs[] = {
++ &dev_attr_stat_status.attr,
++ &dev_attr_stat_mflags.attr,
++ &dev_attr_stat_human_status.attr,
++ &dev_attr_stat_delin.attr,
++ &dev_attr_stat_vidcpe.attr,
++ &dev_attr_stat_usrate.attr,
++ &dev_attr_stat_dsrate.attr,
++ &dev_attr_stat_usattenuation.attr,
++ &dev_attr_stat_dsattenuation.attr,
++ &dev_attr_stat_usmargin.attr,
++ &dev_attr_stat_dsmargin.attr,
++ &dev_attr_stat_txflow.attr,
++ &dev_attr_stat_rxflow.attr,
++ &dev_attr_stat_uscorr.attr,
++ &dev_attr_stat_dscorr.attr,
++ &dev_attr_stat_usunc.attr,
++ &dev_attr_stat_dsunc.attr,
++ &dev_attr_stat_firmid.attr,
++ NULL,
++};
++static struct attribute_group attr_grp = {
++ .attrs = attrs,
++};
+
+ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
+ const struct usb_device_id *id)
+@@ -1702,43 +1713,25 @@ static int uea_bind(struct usbatm_data *
+ }
+ }
+
++ ret = sysfs_create_group(&intf->dev.kobj, &attr_grp);
++ if (ret < 0)
++ goto error;
++
+ ret = uea_boot(sc);
+- if (ret < 0) {
+- kfree(sc);
+- return ret;
+- }
++ if (ret < 0)
++ goto error;
+
+- create_fs_entries(sc, intf);
+ return 0;
+-}
+-
+-static void destroy_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
+-{
+- /* sysfs interface */
+- device_remove_file(&intf->dev, &dev_attr_stat_status);
+- device_remove_file(&intf->dev, &dev_attr_stat_mflags);
+- device_remove_file(&intf->dev, &dev_attr_stat_human_status);
+- device_remove_file(&intf->dev, &dev_attr_stat_delin);
+- device_remove_file(&intf->dev, &dev_attr_stat_vidcpe);
+- device_remove_file(&intf->dev, &dev_attr_stat_usrate);
+- device_remove_file(&intf->dev, &dev_attr_stat_dsrate);
+- device_remove_file(&intf->dev, &dev_attr_stat_usattenuation);
+- device_remove_file(&intf->dev, &dev_attr_stat_dsattenuation);
+- device_remove_file(&intf->dev, &dev_attr_stat_usmargin);
+- device_remove_file(&intf->dev, &dev_attr_stat_dsmargin);
+- device_remove_file(&intf->dev, &dev_attr_stat_txflow);
+- device_remove_file(&intf->dev, &dev_attr_stat_rxflow);
+- device_remove_file(&intf->dev, &dev_attr_stat_uscorr);
+- device_remove_file(&intf->dev, &dev_attr_stat_dscorr);
+- device_remove_file(&intf->dev, &dev_attr_stat_usunc);
+- device_remove_file(&intf->dev, &dev_attr_stat_dsunc);
++error:
++ kfree(sc);
++ return ret;
+ }
+
+ static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
+ {
+ struct uea_softc *sc = usbatm->driver_data;
+
+- destroy_fs_entries(sc, intf);
++ sysfs_remove_group(&intf->dev.kobj, &attr_grp);
+ uea_stop(sc);
+ kfree(sc);
+ }
+@@ -1759,10 +1752,10 @@ static int uea_probe(struct usb_interfac
+ struct usb_device *usb = interface_to_usbdev(intf);
+
+ uea_enters(usb);
+- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n",
++ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
+ le16_to_cpu(usb->descriptor.idVendor),
+ le16_to_cpu(usb->descriptor.idProduct),
+- chip_name[UEA_CHIP_VERSION(id)]);
++ chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+
+ usb_reset_device(usb);
+
+diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
+index a38701c..ec63b0e 100644
+--- a/drivers/usb/atm/usbatm.c
++++ b/drivers/usb/atm/usbatm.c
+@@ -254,7 +254,7 @@ static int usbatm_submit_urb(struct urb
+ return ret;
+ }
+
+-static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
++static void usbatm_complete(struct urb *urb)
+ {
+ struct usbatm_channel *channel = urb->context;
+ unsigned long flags;
+@@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *ar
+
+ daemonize(instance->driver->driver_name);
+ allow_signal(SIGTERM);
++ instance->thread_pid = current->pid;
+
+ complete(&instance->thread_started);
+
+@@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usba
+ return ret;
+ }
+
+- mutex_lock(&instance->serialize);
+- instance->thread_pid = ret;
+- mutex_unlock(&instance->serialize);
+-
+ wait_for_completion(&instance->thread_started);
+
+ return 0;
+diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
+index ca90326..9a9012f 100644
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -218,7 +218,7 @@ static int acm_write_start(struct acm *a
+ */
+
+ /* control interface reports status changes with "interrupt" transfers */
+-static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
++static void acm_ctrl_irq(struct urb *urb)
+ {
+ struct acm *acm = urb->context;
+ struct usb_cdc_notification *dr = urb->transfer_buffer;
+@@ -285,7 +285,7 @@ exit:
+ }
+
+ /* data interface returns incoming bytes, or we got unthrottled */
+-static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
++static void acm_read_bulk(struct urb *urb)
+ {
+ struct acm_rb *buf;
+ struct acm_ru *rcv = urb->context;
+@@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long
+ struct acm_rb *buf;
+ struct tty_struct *tty = acm->tty;
+ struct acm_ru *rcv;
+- //unsigned long flags;
++ unsigned long flags;
+ int i = 0;
+ dbg("Entering acm_rx_tasklet");
+
+@@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long
+ return;
+
+ next_buffer:
+- spin_lock(&acm->read_lock);
++ spin_lock_irqsave(&acm->read_lock, flags);
+ if (list_empty(&acm->filled_read_bufs)) {
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+ goto urbs;
+ }
+ buf = list_entry(acm->filled_read_bufs.next,
+ struct acm_rb, list);
+ list_del(&buf->list);
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+
+ dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
+
+@@ -356,29 +356,29 @@ next_buffer:
+ memmove(buf->base, buf->base + i, buf->size - i);
+ buf->size -= i;
+ spin_unlock(&acm->throttle_lock);
+- spin_lock(&acm->read_lock);
++ spin_lock_irqsave(&acm->read_lock, flags);
+ list_add(&buf->list, &acm->filled_read_bufs);
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+ return;
+ }
+ spin_unlock(&acm->throttle_lock);
+
+- spin_lock(&acm->read_lock);
++ spin_lock_irqsave(&acm->read_lock, flags);
+ list_add(&buf->list, &acm->spare_read_bufs);
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+ goto next_buffer;
+
+ urbs:
+ while (!list_empty(&acm->spare_read_bufs)) {
+- spin_lock(&acm->read_lock);
++ spin_lock_irqsave(&acm->read_lock, flags);
+ if (list_empty(&acm->spare_read_urbs)) {
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+ return;
+ }
+ rcv = list_entry(acm->spare_read_urbs.next,
+ struct acm_ru, list);
+ list_del(&rcv->list);
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+
+ buf = list_entry(acm->spare_read_bufs.next,
+ struct acm_rb, list);
+@@ -400,16 +400,16 @@ urbs:
+ free-urbs-pool and resubmited ASAP */
+ if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
+ list_add(&buf->list, &acm->spare_read_bufs);
+- spin_lock(&acm->read_lock);
++ spin_lock_irqsave(&acm->read_lock, flags);
+ list_add(&rcv->list, &acm->spare_read_urbs);
+- spin_unlock(&acm->read_lock);
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+ return;
+ }
+ }
+ }
+
+ /* data interface wrote those outgoing bytes */
+-static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
++static void acm_write_bulk(struct urb *urb)
+ {
+ struct acm *acm = (struct acm *)urb->context;
+
+@@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] =
+ { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
+ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+ },
++ { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
++ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
++ },
+ { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
+ .driver_info = SINGLE_RX_URB, /* firmware bug */
+ },
+@@ -1120,7 +1123,7 @@ static struct usb_driver acm_driver = {
+ * TTY driver structures.
+ */
+
+-static struct tty_operations acm_ops = {
++static const struct tty_operations acm_ops = {
+ .open = acm_tty_open,
+ .close = acm_tty_close,
+ .write = acm_tty_write,
+diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
+index 48dee4b..6303970 100644
+--- a/drivers/usb/class/usblp.c
++++ b/drivers/usb/class/usblp.c
+@@ -154,6 +154,7 @@ struct usblp {
+ unsigned char used; /* True if open */
+ unsigned char present; /* True if not disconnected */
+ unsigned char bidir; /* interface is bidirectional */
++ unsigned char sleeping; /* interface is suspended */
+ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
+ /* first 2 bytes are (big-endian) length */
+ };
+@@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usb
+ dbg("quirks=%d", usblp->quirks);
+ dbg("used=%d", usblp->used);
+ dbg("bidir=%d", usblp->bidir);
++ dbg("sleeping=%d", usblp->sleeping);
+ dbg("device_id_string=\"%s\"",
+ usblp->device_id_string ?
+ usblp->device_id_string + 2 :
+@@ -271,7 +273,7 @@ static int proto_bias = -1;
+ * URB callback.
+ */
+
+-static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs)
++static void usblp_bulk_read(struct urb *urb)
+ {
+ struct usblp *usblp = urb->context;
+
+@@ -288,7 +290,7 @@ unplug:
+ wake_up_interruptible(&usblp->wait);
+ }
+
+-static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs)
++static void usblp_bulk_write(struct urb *urb)
+ {
+ struct usblp *usblp = urb->context;
+
+@@ -338,6 +340,20 @@ static int usblp_check_status(struct usb
+ return newerr;
+ }
+
++static int handle_bidir (struct usblp *usblp)
++{
++ if (usblp->bidir && usblp->used && !usblp->sleeping) {
++ usblp->readcount = 0;
++ usblp->readurb->dev = usblp->dev;
++ if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
++ usblp->used = 0;
++ return -EIO;
++ }
++ }
++
++ return 0;
++}
++
+ /*
+ * File op functions.
+ */
+@@ -390,14 +406,9 @@ static int usblp_open(struct inode *inod
+ usblp->writeurb->status = 0;
+ usblp->readurb->status = 0;
+
+- if (usblp->bidir) {
+- usblp->readcount = 0;
+- usblp->readurb->dev = usblp->dev;
+- if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
+- retval = -EIO;
+- usblp->used = 0;
+- file->private_data = NULL;
+- }
++ if (handle_bidir(usblp) < 0) {
++ file->private_data = NULL;
++ retval = -EIO;
+ }
+ out:
+ mutex_unlock (&usblp_mutex);
+@@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *fil
+ goto done;
+ }
+
++ if (usblp->sleeping) {
++ retval = -ENODEV;
++ goto done;
++ }
++
+ dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
+ _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
+
+@@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *
+ return -ENODEV;
+ }
+
++ if (usblp->sleeping) {
++ up (&usblp->sem);
++ return writecount ? writecount : -ENODEV;
++ }
++
+ if (usblp->writeurb->status != 0) {
+ if (usblp->quirks & USBLP_QUIRK_BIDIR) {
+ if (!usblp->wcomplete)
+@@ -701,6 +722,7 @@ static ssize_t usblp_write(struct file *
+ usblp->wcomplete = 0;
+ err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
+ if (err) {
++ usblp->wcomplete = 1;
+ if (err != -ENOMEM)
+ count = -EIO;
+ else
+@@ -749,6 +771,11 @@ static ssize_t usblp_read(struct file *f
+ goto done;
+ }
+
++ if (usblp->sleeping) {
++ count = -ENODEV;
++ goto done;
++ }
++
+ if (usblp->readurb->status) {
+ err("usblp%d: error %d reading from printer",
+ usblp->minor, usblp->readurb->status);
+@@ -813,7 +840,7 @@ static unsigned int usblp_quirks (__u16
+ return 0;
+ }
+
+-static struct file_operations usblp_fops = {
++static const struct file_operations usblp_fops = {
+ .owner = THIS_MODULE,
+ .read = usblp_read,
+ .write = usblp_write,
+@@ -927,7 +954,9 @@ static int usblp_probe(struct usb_interf
+
+ /* Retrieve and store the device ID string. */
+ usblp_cache_device_id_string(usblp);
+- device_create_file(&intf->dev, &dev_attr_ieee1284_id);
++ retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id);
++ if (retval)
++ goto abort_intfdata;
+
+ #ifdef DEBUG
+ usblp_check_status(usblp, 0);
+@@ -1021,18 +1050,13 @@ static int usblp_select_alts(struct usbl
+ for (e = 0; e < ifd->desc.bNumEndpoints; e++) {
+ epd = &ifd->endpoint[e].desc;
+
+- if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
+- USB_ENDPOINT_XFER_BULK)
+- continue;
+-
+- if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
++ if (usb_endpoint_is_bulk_out(epd))
+ if (!epwrite)
+ epwrite = epd;
+
+- } else {
++ if (usb_endpoint_is_bulk_in(epd))
+ if (!epread)
+ epread = epd;
+- }
+ }
+
+ /* Ignore buggy hardware without the right endpoints. */
+@@ -1170,6 +1194,39 @@ static void usblp_disconnect(struct usb_
+ mutex_unlock (&usblp_mutex);
+ }
+
++static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
++{
++ struct usblp *usblp = usb_get_intfdata (intf);
++
++ /* this races against normal access and open */
++ mutex_lock (&usblp_mutex);
++ down (&usblp->sem);
++ /* we take no more IO */
++ usblp->sleeping = 1;
++ usblp_unlink_urbs(usblp);
++ up (&usblp->sem);
++ mutex_unlock (&usblp_mutex);
++
++ return 0;
++}
++
++static int usblp_resume (struct usb_interface *intf)
++{
++ struct usblp *usblp = usb_get_intfdata (intf);
++ int r;
++
++ mutex_lock (&usblp_mutex);
++ down (&usblp->sem);
++
++ usblp->sleeping = 0;
++ r = handle_bidir (usblp);
++
++ up (&usblp->sem);
++ mutex_unlock (&usblp_mutex);
++
++ return r;
++}
++
+ static struct usb_device_id usblp_ids [] = {
+ { USB_DEVICE_INFO(7, 1, 1) },
+ { USB_DEVICE_INFO(7, 1, 2) },
+@@ -1186,6 +1243,8 @@ static struct usb_driver usblp_driver =
+ .name = "usblp",
+ .probe = usblp_probe,
+ .disconnect = usblp_disconnect,
++ .suspend = usblp_suspend,
++ .resume = usblp_resume,
+ .id_table = usblp_ids,
+ };
+
+diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
+index ec51092..34e9bac 100644
+--- a/drivers/usb/core/Makefile
++++ b/drivers/usb/core/Makefile
+@@ -4,7 +4,7 @@
+
+ usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
+ config.o file.o buffer.o sysfs.o endpoint.o \
+- devio.o notify.o
++ devio.o notify.o generic.o
+
+ ifeq ($(CONFIG_PCI),y)
+ usbcore-objs += hcd-pci.o
+diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
+index f4f4ef0..840442a 100644
+--- a/drivers/usb/core/buffer.c
++++ b/drivers/usb/core/buffer.c
+@@ -104,7 +104,7 @@ void *hcd_buffer_alloc (
+ dma_addr_t *dma
+ )
+ {
+- struct usb_hcd *hcd = bus->hcpriv;
++ struct usb_hcd *hcd = bus_to_hcd(bus);
+ int i;
+
+ /* some USB hosts just use PIO */
+@@ -127,7 +127,7 @@ void hcd_buffer_free (
+ dma_addr_t dma
+ )
+ {
+- struct usb_hcd *hcd = bus->hcpriv;
++ struct usb_hcd *hcd = bus_to_hcd(bus);
+ int i;
+
+ if (!addr)
+diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
+index 4c9e63e..bfb3731 100644
+--- a/drivers/usb/core/config.c
++++ b/drivers/usb/core/config.c
+@@ -475,7 +475,9 @@ int usb_get_configuration(struct usb_dev
+ if (result < 0) {
+ dev_err(ddev, "unable to read config index %d "
+ "descriptor/%s\n", cfgno, "start");
+- goto err;
++ dev_err(ddev, "chopping to %d config(s)\n", cfgno);
++ dev->descriptor.bNumConfigurations = cfgno;
++ break;
+ } else if (result < 4) {
+ dev_err(ddev, "config index %d descriptor too short "
+ "(expected %i, got %i)\n", cfgno,
+diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
+index c0f3734..3538c2f 100644
+--- a/drivers/usb/core/devices.c
++++ b/drivers/usb/core/devices.c
+@@ -593,7 +593,7 @@ static ssize_t usb_device_read(struct fi
+ /* Kernel lock for "lastev" protection */
+ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+ {
+- struct usb_device_status *st = (struct usb_device_status *)file->private_data;
++ struct usb_device_status *st = file->private_data;
+ unsigned int mask = 0;
+
+ lock_kernel();
+@@ -603,7 +603,7 @@ static unsigned int usb_device_poll(stru
+ unlock_kernel();
+ return POLLIN;
+ }
+-
++
+ /* we may have dropped BKL - need to check for having lost the race */
+ if (file->private_data) {
+ kfree(st);
+@@ -667,7 +667,7 @@ static loff_t usb_device_lseek(struct fi
+ return ret;
+ }
+
+-struct file_operations usbfs_devices_fops = {
++const struct file_operations usbfs_devices_fops = {
+ .llseek = usb_device_lseek,
+ .read = usb_device_read,
+ .poll = usb_device_poll,
+diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
+index 218621b..fed92be 100644
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -59,10 +59,13 @@
+ #define USB_DEVICE_MAX USB_MAXBUS * 128
+ static struct class *usb_device_class;
+
++/* Mutual exclusion for removal, open, and release */
++DEFINE_MUTEX(usbfs_mutex);
++
+ struct async {
+ struct list_head asynclist;
+ struct dev_state *ps;
+- pid_t pid;
++ struct pid *pid;
+ uid_t uid, euid;
+ unsigned int signr;
+ unsigned int ifnum;
+@@ -87,9 +90,10 @@ MODULE_PARM_DESC (usbfs_snoop, "true to
+
+ #define MAX_USBFS_BUFFER_SIZE 16384
+
+-static inline int connected (struct usb_device *dev)
++static inline int connected (struct dev_state *ps)
+ {
+- return dev->state != USB_STATE_NOTATTACHED;
++ return (!list_empty(&ps->list) &&
++ ps->dev->state != USB_STATE_NOTATTACHED);
+ }
+
+ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
+@@ -118,7 +122,7 @@ static loff_t usbdev_lseek(struct file *
+
+ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+ {
+- struct dev_state *ps = (struct dev_state *)file->private_data;
++ struct dev_state *ps = file->private_data;
+ struct usb_device *dev = ps->dev;
+ ssize_t ret = 0;
+ unsigned len;
+@@ -127,7 +131,7 @@ static ssize_t usbdev_read(struct file *
+
+ pos = *ppos;
+ usb_lock_device(dev);
+- if (!connected(dev)) {
++ if (!connected(ps)) {
+ ret = -ENODEV;
+ goto err;
+ } else if (pos < 0) {
+@@ -221,6 +225,7 @@ static struct async *alloc_async(unsigne
+
+ static void free_async(struct async *as)
+ {
++ put_pid(as->pid);
+ kfree(as->urb->transfer_buffer);
+ kfree(as->urb->setup_packet);
+ usb_free_urb(as->urb);
+@@ -299,9 +304,9 @@ static void snoop_urb(struct urb *urb, v
+ printk("\n");
+ }
+
+-static void async_completed(struct urb *urb, struct pt_regs *regs)
++static void async_completed(struct urb *urb)
+ {
+- struct async *as = (struct async *)urb->context;
++ struct async *as = urb->context;
+ struct dev_state *ps = as->ps;
+ struct siginfo sinfo;
+
+@@ -313,7 +318,7 @@ static void async_completed(struct urb *
+ sinfo.si_errno = as->urb->status;
+ sinfo.si_code = SI_ASYNCIO;
+ sinfo.si_addr = as->userurb;
+- kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
++ kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
+ as->euid, as->secid);
+ }
+ snoop(&urb->dev->dev, "urb complete\n");
+@@ -541,25 +546,25 @@ static int usbdev_open(struct inode *ino
+ struct dev_state *ps;
+ int ret;
+
+- /*
+- * no locking necessary here, as chrdev_open has the kernel lock
+- * (still acquire the kernel lock for safety)
+- */
++ /* Protect against simultaneous removal or release */
++ mutex_lock(&usbfs_mutex);
++
+ ret = -ENOMEM;
+ if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
+- goto out_nolock;
++ goto out;
+
+- lock_kernel();
+ ret = -ENOENT;
+ /* check if we are called from a real node or usbfs */
+ if (imajor(inode) == USB_DEVICE_MAJOR)
+ dev = usbdev_lookup_minor(iminor(inode));
+ if (!dev)
+- dev = inode->u.generic_ip;
+- if (!dev) {
+- kfree(ps);
++ dev = inode->i_private;
++ if (!dev)
+ goto out;
+- }
++ ret = usb_autoresume_device(dev, 1);
++ if (ret)
++ goto out;
++
+ usb_get_dev(dev);
+ ret = 0;
+ ps->dev = dev;
+@@ -569,7 +574,7 @@ static int usbdev_open(struct inode *ino
+ INIT_LIST_HEAD(&ps->async_completed);
+ init_waitqueue_head(&ps->wait);
+ ps->discsignr = 0;
+- ps->disc_pid = current->pid;
++ ps->disc_pid = get_pid(task_pid(current));
+ ps->disc_uid = current->uid;
+ ps->disc_euid = current->euid;
+ ps->disccontext = NULL;
+@@ -579,30 +584,37 @@ static int usbdev_open(struct inode *ino
+ list_add_tail(&ps->list, &dev->filelist);
+ file->private_data = ps;
+ out:
+- unlock_kernel();
+- out_nolock:
+- return ret;
++ if (ret)
++ kfree(ps);
++ mutex_unlock(&usbfs_mutex);
++ return ret;
+ }
+
+ static int usbdev_release(struct inode *inode, struct file *file)
+ {
+- struct dev_state *ps = (struct dev_state *)file->private_data;
++ struct dev_state *ps = file->private_data;
+ struct usb_device *dev = ps->dev;
+ unsigned int ifnum;
+
+ usb_lock_device(dev);
++
++ /* Protect against simultaneous open */
++ mutex_lock(&usbfs_mutex);
+ list_del_init(&ps->list);
++ mutex_unlock(&usbfs_mutex);
++
+ for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
+ ifnum++) {
+ if (test_bit(ifnum, &ps->ifclaimed))
+ releaseintf(ps, ifnum);
+ }
+ destroy_all_async(ps);
++ usb_autosuspend_device(dev, 1);
+ usb_unlock_device(dev);
+ usb_put_dev(dev);
+- ps->dev = NULL;
++ put_pid(ps->disc_pid);
+ kfree(ps);
+- return 0;
++ return 0;
+ }
+
+ static int proc_control(struct dev_state *ps, void __user *arg)
+@@ -1053,7 +1065,7 @@ static int proc_do_submiturb(struct dev_
+ as->userbuffer = NULL;
+ as->signr = uurb->signr;
+ as->ifnum = ifnum;
+- as->pid = current->pid;
++ as->pid = get_pid(task_pid(current));
+ as->uid = current->uid;
+ as->euid = current->euid;
+ security_task_getsecid(current, &as->secid);
+@@ -1204,7 +1216,7 @@ static int proc_submiturb_compat(struct
+ {
+ struct usbdevfs_urb uurb;
+
+- if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
++ if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg))
+ return -EFAULT;
+
+ return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
+@@ -1239,7 +1251,7 @@ static int processcompl_compat(struct as
+ }
+
+ free_async(as);
+- if (put_user((u32)(u64)addr, (u32 __user *)arg))
++ if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
+ return -EFAULT;
+ return 0;
+ }
+@@ -1322,7 +1334,7 @@ static int proc_ioctl(struct dev_state *
+ }
+ }
+
+- if (!connected(ps->dev)) {
++ if (!connected(ps)) {
+ kfree(buf);
+ return -ENODEV;
+ }
+@@ -1349,7 +1361,7 @@ static int proc_ioctl(struct dev_state *
+ /* let kernel drivers try to (re)bind to the interface */
+ case USBDEVFS_CONNECT:
+ usb_unlock_device(ps->dev);
+- bus_rescan_devices(intf->dev.bus);
++ retval = bus_rescan_devices(intf->dev.bus);
+ usb_lock_device(ps->dev);
+ break;
+
+@@ -1413,7 +1425,7 @@ static int proc_ioctl_compat(struct dev_
+ */
+ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ {
+- struct dev_state *ps = (struct dev_state *)file->private_data;
++ struct dev_state *ps = file->private_data;
+ struct usb_device *dev = ps->dev;
+ void __user *p = (void __user *)arg;
+ int ret = -ENOTTY;
+@@ -1421,7 +1433,7 @@ static int usbdev_ioctl(struct inode *in
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EPERM;
+ usb_lock_device(dev);
+- if (!connected(dev)) {
++ if (!connected(ps)) {
+ usb_unlock_device(dev);
+ return -ENODEV;
+ }
+@@ -1508,7 +1520,7 @@ static int usbdev_ioctl(struct inode *in
+
+ case USBDEVFS_IOCTL32:
+ snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
+- ret = proc_ioctl_compat(ps, (compat_uptr_t)(long)p);
++ ret = proc_ioctl_compat(ps, ptr_to_compat(p));
+ break;
+ #endif
+
+@@ -1556,18 +1568,18 @@ static int usbdev_ioctl(struct inode *in
+ /* No kernel lock - fine */
+ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
+ {
+- struct dev_state *ps = (struct dev_state *)file->private_data;
+- unsigned int mask = 0;
++ struct dev_state *ps = file->private_data;
++ unsigned int mask = 0;
+
+ poll_wait(file, &ps->wait, wait);
+ if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
+ mask |= POLLOUT | POLLWRNORM;
+- if (!connected(ps->dev))
++ if (!connected(ps))
+ mask |= POLLERR | POLLHUP;
+ return mask;
+ }
+
+-struct file_operations usbfs_device_file_operations = {
++const struct file_operations usbfs_device_file_operations = {
+ .llseek = usbdev_lseek,
+ .read = usbdev_read,
+ .poll = usbdev_poll,
+@@ -1576,15 +1588,18 @@ struct file_operations usbfs_device_file
+ .release = usbdev_release,
+ };
+
+-static void usbdev_add(struct usb_device *dev)
++static int usbdev_add(struct usb_device *dev)
+ {
+ int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
+
+ dev->class_dev = class_device_create(usb_device_class, NULL,
+ MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+ "usbdev%d.%d", dev->bus->busnum, dev->devnum);
++ if (IS_ERR(dev->class_dev))
++ return PTR_ERR(dev->class_dev);
+
+ dev->class_dev->class_data = dev;
++ return 0;
+ }
+
+ static void usbdev_remove(struct usb_device *dev)
+@@ -1597,7 +1612,8 @@ static int usbdev_notify(struct notifier
+ {
+ switch (action) {
+ case USB_DEVICE_ADD:
+- usbdev_add(dev);
++ if (usbdev_add(dev))
++ return NOTIFY_BAD;
+ break;
+ case USB_DEVICE_REMOVE:
+ usbdev_remove(dev);
+diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
+index ec89065..113e484 100644
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -17,12 +17,14 @@
+ *
+ * NOTE! This is not actually a driver at all, rather this is
+ * just a collection of helper routines that implement the
+- * generic USB things that the real drivers can use..
++ * matching, probing, releasing, suspending and resuming for
++ * real drivers.
+ *
+ */
+
+ #include <linux/device.h>
+ #include <linux/usb.h>
++#include <linux/workqueue.h>
+ #include "hcd.h"
+ #include "usb.h"
+
+@@ -34,38 +36,6 @@ struct usb_dynid {
+ struct usb_device_id id;
+ };
+
+-
+-static int generic_probe(struct device *dev)
+-{
+- return 0;
+-}
+-static int generic_remove(struct device *dev)
+-{
+- struct usb_device *udev = to_usb_device(dev);
+-
+- /* if this is only an unbind, not a physical disconnect, then
+- * unconfigure the device */
+- if (udev->state == USB_STATE_CONFIGURED)
+- usb_set_configuration(udev, 0);
+-
+- /* in case the call failed or the device was suspended */
+- if (udev->state >= USB_STATE_CONFIGURED)
+- usb_disable_device(udev, 0);
+- return 0;
+-}
+-
+-struct device_driver usb_generic_driver = {
+- .owner = THIS_MODULE,
+- .name = "usb",
+- .bus = &usb_bus_type,
+- .probe = generic_probe,
+- .remove = generic_remove,
+-};
+-
+-/* Fun hack to determine if the struct device is a
+- * usb device or a usb interface. */
+-int usb_generic_driver_data;
+-
+ #ifdef CONFIG_HOTPLUG
+
+ /*
+@@ -80,6 +50,7 @@ static ssize_t store_new_id(struct devic
+ u32 idVendor = 0;
+ u32 idProduct = 0;
+ int fields = 0;
++ int retval = 0;
+
+ fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
+ if (fields < 2)
+@@ -99,10 +70,12 @@ static ssize_t store_new_id(struct devic
+ spin_unlock(&usb_drv->dynids.lock);
+
+ if (get_driver(driver)) {
+- driver_attach(driver);
++ retval = driver_attach(driver);
+ put_driver(driver);
+ }
+
++ if (retval)
++ return retval;
+ return count;
+ }
+ static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+@@ -115,7 +88,7 @@ static int usb_create_newid_file(struct
+ goto exit;
+
+ if (usb_drv->probe != NULL)
+- error = sysfs_create_file(&usb_drv->driver.kobj,
++ error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
+ &driver_attr_new_id.attr);
+ exit:
+ return error;
+@@ -127,7 +100,7 @@ static void usb_remove_newid_file(struct
+ return;
+
+ if (usb_drv->probe != NULL)
+- sysfs_remove_file(&usb_drv->driver.kobj,
++ sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
+ &driver_attr_new_id.attr);
+ }
+
+@@ -174,21 +147,57 @@ static const struct usb_device_id *usb_m
+ }
+
+
+-/* called from driver core with usb_bus_type.subsys writelock */
++/* called from driver core with dev locked */
++static int usb_probe_device(struct device *dev)
++{
++ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
++ struct usb_device *udev;
++ int error = -ENODEV;
++
++ dev_dbg(dev, "%s\n", __FUNCTION__);
++
++ if (!is_usb_device(dev)) /* Sanity check */
++ return error;
++
++ udev = to_usb_device(dev);
++
++ /* TODO: Add real matching code */
++
++ /* The device should always appear to be in use
++ * unless the driver suports autosuspend.
++ */
++ udev->pm_usage_cnt = !(udriver->supports_autosuspend);
++
++ error = udriver->probe(udev);
++ return error;
++}
++
++/* called from driver core with dev locked */
++static int usb_unbind_device(struct device *dev)
++{
++ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
++
++ udriver->disconnect(to_usb_device(dev));
++ return 0;
++}
++
++
++/* called from driver core with dev locked */
+ static int usb_probe_interface(struct device *dev)
+ {
+- struct usb_interface * intf = to_usb_interface(dev);
+- struct usb_driver * driver = to_usb_driver(dev->driver);
++ struct usb_driver *driver = to_usb_driver(dev->driver);
++ struct usb_interface *intf;
++ struct usb_device *udev;
+ const struct usb_device_id *id;
+ int error = -ENODEV;
+
+ dev_dbg(dev, "%s\n", __FUNCTION__);
+
+- if (!driver->probe)
++ if (is_usb_device(dev)) /* Sanity check */
+ return error;
+- /* FIXME we'd much prefer to just resume it ... */
+- if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
+- return -EHOSTUNREACH;
++
++ intf = to_usb_interface(dev);
++ udev = interface_to_usbdev(intf);
+
+ id = usb_match_id(intf, driver->id_table);
+ if (!id)
+@@ -196,48 +205,165 @@ static int usb_probe_interface(struct de
+ if (id) {
+ dev_dbg(dev, "%s - got id\n", __FUNCTION__);
+
++ error = usb_autoresume_device(udev, 1);
++ if (error)
++ return error;
++
+ /* Interface "power state" doesn't correspond to any hardware
+ * state whatsoever. We use it to record when it's bound to
+ * a driver that may start I/0: it's not frozen/quiesced.
+ */
+ mark_active(intf);
+ intf->condition = USB_INTERFACE_BINDING;
++
++ /* The interface should always appear to be in use
++ * unless the driver suports autosuspend.
++ */
++ intf->pm_usage_cnt = !(driver->supports_autosuspend);
++
+ error = driver->probe(intf, id);
+ if (error) {
+ mark_quiesced(intf);
++ intf->needs_remote_wakeup = 0;
+ intf->condition = USB_INTERFACE_UNBOUND;
+ } else
+ intf->condition = USB_INTERFACE_BOUND;
++
++ usb_autosuspend_device(udev, 1);
+ }
+
+ return error;
+ }
+
+-/* called from driver core with usb_bus_type.subsys writelock */
++/* called from driver core with dev locked */
+ static int usb_unbind_interface(struct device *dev)
+ {
++ struct usb_driver *driver = to_usb_driver(dev->driver);
+ struct usb_interface *intf = to_usb_interface(dev);
+- struct usb_driver *driver = to_usb_driver(intf->dev.driver);
++ struct usb_device *udev;
++ int error;
+
+ intf->condition = USB_INTERFACE_UNBINDING;
+
++ /* Autoresume for set_interface call below */
++ udev = interface_to_usbdev(intf);
++ error = usb_autoresume_device(udev, 1);
++
+ /* release all urbs for this interface */
+ usb_disable_interface(interface_to_usbdev(intf), intf);
+
+- if (driver && driver->disconnect)
+- driver->disconnect(intf);
++ driver->disconnect(intf);
+
+ /* reset other interface state */
+ usb_set_interface(interface_to_usbdev(intf),
+ intf->altsetting[0].desc.bInterfaceNumber,
+ 0);
+ usb_set_intfdata(intf, NULL);
++
+ intf->condition = USB_INTERFACE_UNBOUND;
+ mark_quiesced(intf);
++ intf->needs_remote_wakeup = 0;
++
++ if (!error)
++ usb_autosuspend_device(udev, 1);
+
+ return 0;
+ }
+
++/**
++ * usb_driver_claim_interface - bind a driver to an interface
++ * @driver: the driver to be bound
++ * @iface: the interface to which it will be bound; must be in the
++ * usb device's active configuration
++ * @priv: driver data associated with that interface
++ *
++ * This is used by usb device drivers that need to claim more than one
++ * interface on a device when probing (audio and acm are current examples).
++ * No device driver should directly modify internal usb_interface or
++ * usb_device structure members.
++ *
++ * Few drivers should need to use this routine, since the most natural
++ * way to bind to an interface is to return the private data from
++ * the driver's probe() method.
++ *
++ * Callers must own the device lock and the driver model's usb_bus_type.subsys
++ * writelock. So driver probe() entries don't need extra locking,
++ * but other call contexts may need to explicitly claim those locks.
++ */
++int usb_driver_claim_interface(struct usb_driver *driver,
++ struct usb_interface *iface, void* priv)
++{
++ struct device *dev = &iface->dev;
++ struct usb_device *udev = interface_to_usbdev(iface);
++ int retval = 0;
++
++ if (dev->driver)
++ return -EBUSY;
++
++ dev->driver = &driver->drvwrap.driver;
++ usb_set_intfdata(iface, priv);
++
++ usb_pm_lock(udev);
++ iface->condition = USB_INTERFACE_BOUND;
++ mark_active(iface);
++ iface->pm_usage_cnt = !(driver->supports_autosuspend);
++ usb_pm_unlock(udev);
++
++ /* if interface was already added, bind now; else let
++ * the future device_add() bind it, bypassing probe()
++ */
++ if (device_is_registered(dev))
++ retval = device_bind_driver(dev);
++
++ return retval;
++}
++EXPORT_SYMBOL(usb_driver_claim_interface);
++
++/**
++ * usb_driver_release_interface - unbind a driver from an interface
++ * @driver: the driver to be unbound
++ * @iface: the interface from which it will be unbound
++ *
++ * This can be used by drivers to release an interface without waiting
++ * for their disconnect() methods to be called. In typical cases this
++ * also causes the driver disconnect() method to be called.
++ *
++ * This call is synchronous, and may not be used in an interrupt context.
++ * Callers must own the device lock and the driver model's usb_bus_type.subsys
++ * writelock. So driver disconnect() entries don't need extra locking,
++ * but other call contexts may need to explicitly claim those locks.
++ */
++void usb_driver_release_interface(struct usb_driver *driver,
++ struct usb_interface *iface)
++{
++ struct device *dev = &iface->dev;
++ struct usb_device *udev = interface_to_usbdev(iface);
++
++ /* this should never happen, don't release something that's not ours */
++ if (!dev->driver || dev->driver != &driver->drvwrap.driver)
++ return;
++
++ /* don't release from within disconnect() */
++ if (iface->condition != USB_INTERFACE_BOUND)
++ return;
++
++ /* don't release if the interface hasn't been added yet */
++ if (device_is_registered(dev)) {
++ iface->condition = USB_INTERFACE_UNBINDING;
++ device_release_driver(dev);
++ }
++
++ dev->driver = NULL;
++ usb_set_intfdata(iface, NULL);
++
++ usb_pm_lock(udev);
++ iface->condition = USB_INTERFACE_UNBOUND;
++ mark_quiesced(iface);
++ iface->needs_remote_wakeup = 0;
++ usb_pm_unlock(udev);
++}
++EXPORT_SYMBOL(usb_driver_release_interface);
++
+ /* returns 0 if no match, 1 if match */
+ static int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
+@@ -381,35 +507,223 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
+
+ int usb_device_match(struct device *dev, struct device_driver *drv)
+ {
++ /* devices and interfaces are handled separately */
++ if (is_usb_device(dev)) {
++
++ /* interface drivers never match devices */
++ if (!is_usb_device_driver(drv))
++ return 0;
++
++ /* TODO: Add real matching code */
++ return 1;
++
++ } else {
++ struct usb_interface *intf;
++ struct usb_driver *usb_drv;
++ const struct usb_device_id *id;
++
++ /* device drivers never match interfaces */
++ if (is_usb_device_driver(drv))
++ return 0;
++
++ intf = to_usb_interface(dev);
++ usb_drv = to_usb_driver(drv);
++
++ id = usb_match_id(intf, usb_drv->id_table);
++ if (id)
++ return 1;
++
++ id = usb_match_dynamic_id(intf, usb_drv);
++ if (id)
++ return 1;
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_HOTPLUG
++
++/*
++ * This sends an uevent to userspace, typically helping to load driver
++ * or other modules, configure the device, and more. Drivers can provide
++ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
++ *
++ * We're called either from khubd (the typical case) or from root hub
++ * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
++ * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
++ * device (and this configuration!) are still present.
++ */
++static int usb_uevent(struct device *dev, char **envp, int num_envp,
++ char *buffer, int buffer_size)
++{
+ struct usb_interface *intf;
+- struct usb_driver *usb_drv;
+- const struct usb_device_id *id;
++ struct usb_device *usb_dev;
++ struct usb_host_interface *alt;
++ int i = 0;
++ int length = 0;
+
+- /* check for generic driver, which we don't match any device with */
+- if (drv == &usb_generic_driver)
+- return 0;
++ if (!dev)
++ return -ENODEV;
+
+- intf = to_usb_interface(dev);
+- usb_drv = to_usb_driver(drv);
++ /* driver is often null here; dev_dbg() would oops */
++ pr_debug ("usb %s: uevent\n", dev->bus_id);
+
+- id = usb_match_id(intf, usb_drv->id_table);
+- if (id)
+- return 1;
++ if (is_usb_device(dev)) {
++ usb_dev = to_usb_device(dev);
++ alt = NULL;
++ } else {
++ intf = to_usb_interface(dev);
++ usb_dev = interface_to_usbdev(intf);
++ alt = intf->cur_altsetting;
++ }
++
++ if (usb_dev->devnum < 0) {
++ pr_debug ("usb %s: already deleted?\n", dev->bus_id);
++ return -ENODEV;
++ }
++ if (!usb_dev->bus) {
++ pr_debug ("usb %s: bus removed?\n", dev->bus_id);
++ return -ENODEV;
++ }
++
++#ifdef CONFIG_USB_DEVICEFS
++ /* If this is available, userspace programs can directly read
++ * all the device descriptors we don't tell them about. Or
++ * even act as usermode drivers.
++ *
++ * FIXME reduce hardwired intelligence here
++ */
++ if (add_uevent_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "DEVICE=/proc/bus/usb/%03d/%03d",
++ usb_dev->bus->busnum, usb_dev->devnum))
++ return -ENOMEM;
++#endif
++
++ /* per-device configurations are common */
++ if (add_uevent_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "PRODUCT=%x/%x/%x",
++ le16_to_cpu(usb_dev->descriptor.idVendor),
++ le16_to_cpu(usb_dev->descriptor.idProduct),
++ le16_to_cpu(usb_dev->descriptor.bcdDevice)))
++ return -ENOMEM;
++
++ /* class-based driver binding models */
++ if (add_uevent_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "TYPE=%d/%d/%d",
++ usb_dev->descriptor.bDeviceClass,
++ usb_dev->descriptor.bDeviceSubClass,
++ usb_dev->descriptor.bDeviceProtocol))
++ return -ENOMEM;
++
++ if (!is_usb_device(dev)) {
++
++ if (add_uevent_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "INTERFACE=%d/%d/%d",
++ alt->desc.bInterfaceClass,
++ alt->desc.bInterfaceSubClass,
++ alt->desc.bInterfaceProtocol))
++ return -ENOMEM;
++
++ if (add_uevent_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
++ le16_to_cpu(usb_dev->descriptor.idVendor),
++ le16_to_cpu(usb_dev->descriptor.idProduct),
++ le16_to_cpu(usb_dev->descriptor.bcdDevice),
++ usb_dev->descriptor.bDeviceClass,
++ usb_dev->descriptor.bDeviceSubClass,
++ usb_dev->descriptor.bDeviceProtocol,
++ alt->desc.bInterfaceClass,
++ alt->desc.bInterfaceSubClass,
++ alt->desc.bInterfaceProtocol))
++ return -ENOMEM;
++ }
++
++ envp[i] = NULL;
+
+- id = usb_match_dynamic_id(intf, usb_drv);
+- if (id)
+- return 1;
+ return 0;
+ }
+
++#else
++
++static int usb_uevent(struct device *dev, char **envp,
++ int num_envp, char *buffer, int buffer_size)
++{
++ return -ENODEV;
++}
++
++#endif /* CONFIG_HOTPLUG */
++
++/**
++ * usb_register_device_driver - register a USB device (not interface) driver
++ * @new_udriver: USB operations for the device driver
++ * @owner: module owner of this driver.
++ *
++ * Registers a USB device driver with the USB core. The list of
++ * unattached devices will be rescanned whenever a new driver is
++ * added, allowing the new driver to attach to any recognized devices.
++ * Returns a negative error code on failure and 0 on success.
++ */
++int usb_register_device_driver(struct usb_device_driver *new_udriver,
++ struct module *owner)
++{
++ int retval = 0;
++
++ if (usb_disabled())
++ return -ENODEV;
++
++ new_udriver->drvwrap.for_devices = 1;
++ new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
++ new_udriver->drvwrap.driver.bus = &usb_bus_type;
++ new_udriver->drvwrap.driver.probe = usb_probe_device;
++ new_udriver->drvwrap.driver.remove = usb_unbind_device;
++ new_udriver->drvwrap.driver.owner = owner;
++
++ retval = driver_register(&new_udriver->drvwrap.driver);
++
++ if (!retval) {
++ pr_info("%s: registered new device driver %s\n",
++ usbcore_name, new_udriver->name);
++ usbfs_update_special();
++ } else {
++ printk(KERN_ERR "%s: error %d registering device "
++ " driver %s\n",
++ usbcore_name, retval, new_udriver->name);
++ }
++
++ return retval;
++}
++EXPORT_SYMBOL_GPL(usb_register_device_driver);
++
++/**
++ * usb_deregister_device_driver - unregister a USB device (not interface) driver
++ * @udriver: USB operations of the device driver to unregister
++ * Context: must be able to sleep
++ *
++ * Unlinks the specified driver from the internal USB driver list.
++ */
++void usb_deregister_device_driver(struct usb_device_driver *udriver)
++{
++ pr_info("%s: deregistering device driver %s\n",
++ usbcore_name, udriver->name);
++
++ driver_unregister(&udriver->drvwrap.driver);
++ usbfs_update_special();
++}
++EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
++
+ /**
+- * usb_register_driver - register a USB driver
+- * @new_driver: USB operations for the driver
++ * usb_register_driver - register a USB interface driver
++ * @new_driver: USB operations for the interface driver
+ * @owner: module owner of this driver.
+ *
+- * Registers a USB driver with the USB core. The list of unattached
+- * interfaces will be rescanned whenever a new driver is added, allowing
+- * the new driver to attach to any recognized devices.
++ * Registers a USB interface driver with the USB core. The list of
++ * unattached interfaces will be rescanned whenever a new driver is
++ * added, allowing the new driver to attach to any recognized interfaces.
+ * Returns a negative error code on failure and 0 on success.
+ *
+ * NOTE: if you want your driver to use the USB major number, you must call
+@@ -423,23 +737,25 @@ int usb_register_driver(struct usb_drive
+ if (usb_disabled())
+ return -ENODEV;
+
+- new_driver->driver.name = (char *)new_driver->name;
+- new_driver->driver.bus = &usb_bus_type;
+- new_driver->driver.probe = usb_probe_interface;
+- new_driver->driver.remove = usb_unbind_interface;
+- new_driver->driver.owner = owner;
++ new_driver->drvwrap.for_devices = 0;
++ new_driver->drvwrap.driver.name = (char *) new_driver->name;
++ new_driver->drvwrap.driver.bus = &usb_bus_type;
++ new_driver->drvwrap.driver.probe = usb_probe_interface;
++ new_driver->drvwrap.driver.remove = usb_unbind_interface;
++ new_driver->drvwrap.driver.owner = owner;
+ spin_lock_init(&new_driver->dynids.lock);
+ INIT_LIST_HEAD(&new_driver->dynids.list);
+
+- retval = driver_register(&new_driver->driver);
++ retval = driver_register(&new_driver->drvwrap.driver);
+
+ if (!retval) {
+- pr_info("%s: registered new driver %s\n",
++ pr_info("%s: registered new interface driver %s\n",
+ usbcore_name, new_driver->name);
+ usbfs_update_special();
+ usb_create_newid_file(new_driver);
+ } else {
+- printk(KERN_ERR "%s: error %d registering driver %s\n",
++ printk(KERN_ERR "%s: error %d registering interface "
++ " driver %s\n",
+ usbcore_name, retval, new_driver->name);
+ }
+
+@@ -448,8 +764,8 @@ int usb_register_driver(struct usb_drive
+ EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
+
+ /**
+- * usb_deregister - unregister a USB driver
+- * @driver: USB operations of the driver to unregister
++ * usb_deregister - unregister a USB interface driver
++ * @driver: USB operations of the interface driver to unregister
+ * Context: must be able to sleep
+ *
+ * Unlinks the specified driver from the internal USB driver list.
+@@ -460,12 +776,554 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_register_dr
+ */
+ void usb_deregister(struct usb_driver *driver)
+ {
+- pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
++ pr_info("%s: deregistering interface driver %s\n",
++ usbcore_name, driver->name);
+
+ usb_remove_newid_file(driver);
+ usb_free_dynids(driver);
+- driver_unregister(&driver->driver);
++ driver_unregister(&driver->drvwrap.driver);
+
+ usbfs_update_special();
+ }
+ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
++
++#ifdef CONFIG_PM
++
++/* Caller has locked udev's pm_mutex */
++static int suspend_device(struct usb_device *udev, pm_message_t msg)
++{
++ struct usb_device_driver *udriver;
++ int status = 0;
++
++ if (udev->state == USB_STATE_NOTATTACHED ||
++ udev->state == USB_STATE_SUSPENDED)
++ goto done;
++
++ /* For devices that don't have a driver, we do a standard suspend. */
++ if (udev->dev.driver == NULL) {
++ udev->do_remote_wakeup = 0;
++ status = usb_port_suspend(udev);
++ goto done;
++ }
++
++ udriver = to_usb_device_driver(udev->dev.driver);
++ status = udriver->suspend(udev, msg);
++
++done:
++ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
++ if (status == 0)
++ udev->dev.power.power_state.event = msg.event;
++ return status;
++}
++
++/* Caller has locked udev's pm_mutex */
++static int resume_device(struct usb_device *udev)
++{
++ struct usb_device_driver *udriver;
++ int status = 0;
++
++ if (udev->state == USB_STATE_NOTATTACHED ||
++ udev->state != USB_STATE_SUSPENDED)
++ goto done;
++
++ /* Can't resume it if it doesn't have a driver. */
++ if (udev->dev.driver == NULL) {
++ status = -ENOTCONN;
++ goto done;
++ }
++
++ udriver = to_usb_device_driver(udev->dev.driver);
++ status = udriver->resume(udev);
++
++done:
++ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
++ if (status == 0)
++ udev->dev.power.power_state.event = PM_EVENT_ON;
++ return status;
++}
++
++/* Caller has locked intf's usb_device's pm mutex */
++static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
++{
++ struct usb_driver *driver;
++ int status = 0;
++
++ /* with no hardware, USB interfaces only use FREEZE and ON states */
++ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
++ !is_active(intf))
++ goto done;
++
++ if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */
++ goto done;
++ driver = to_usb_driver(intf->dev.driver);
++
++ if (driver->suspend && driver->resume) {
++ status = driver->suspend(intf, msg);
++ if (status == 0)
++ mark_quiesced(intf);
++ else if (!interface_to_usbdev(intf)->auto_pm)
++ dev_err(&intf->dev, "%s error %d\n",
++ "suspend", status);
++ } else {
++ // FIXME else if there's no suspend method, disconnect...
++ // Not possible if auto_pm is set...
++ dev_warn(&intf->dev, "no suspend for driver %s?\n",
++ driver->name);
++ mark_quiesced(intf);
++ }
++
++done:
++ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
++ if (status == 0)
++ intf->dev.power.power_state.event = msg.event;
++ return status;
++}
++
++/* Caller has locked intf's usb_device's pm_mutex */
++static int resume_interface(struct usb_interface *intf)
++{
++ struct usb_driver *driver;
++ int status = 0;
++
++ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
++ is_active(intf))
++ goto done;
++
++ /* Don't let autoresume interfere with unbinding */
++ if (intf->condition == USB_INTERFACE_UNBINDING)
++ goto done;
++
++ /* Can't resume it if it doesn't have a driver. */
++ if (intf->condition == USB_INTERFACE_UNBOUND) {
++ status = -ENOTCONN;
++ goto done;
++ }
++ driver = to_usb_driver(intf->dev.driver);
++
++ if (driver->resume) {
++ status = driver->resume(intf);
++ if (status)
++ dev_err(&intf->dev, "%s error %d\n",
++ "resume", status);
++ else
++ mark_active(intf);
++ } else {
++ dev_warn(&intf->dev, "no resume for driver %s?\n",
++ driver->name);
++ mark_active(intf);
++ }
++
++done:
++ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
++ if (status == 0)
++ intf->dev.power.power_state.event = PM_EVENT_ON;
++ return status;
++}
++
++/**
++ * usb_suspend_both - suspend a USB device and its interfaces
++ * @udev: the usb_device to suspend
++ * @msg: Power Management message describing this state transition
++ *
++ * This is the central routine for suspending USB devices. It calls the
++ * suspend methods for all the interface drivers in @udev and then calls
++ * the suspend method for @udev itself. If an error occurs at any stage,
++ * all the interfaces which were suspended are resumed so that they remain
++ * in the same state as the device.
++ *
++ * If an autosuspend is in progress (@udev->auto_pm is set), the routine
++ * checks first to make sure that neither the device itself or any of its
++ * active interfaces is in use (pm_usage_cnt is greater than 0). If they
++ * are, the autosuspend fails.
++ *
++ * If the suspend succeeds, the routine recursively queues an autosuspend
++ * request for @udev's parent device, thereby propagating the change up
++ * the device tree. If all of the parent's children are now suspended,
++ * the parent will autosuspend in turn.
++ *
++ * The suspend method calls are subject to mutual exclusion under control
++ * of @udev's pm_mutex. Many of these calls are also under the protection
++ * of @udev's device lock (including all requests originating outside the
++ * USB subsystem), but autosuspend requests generated by a child device or
++ * interface driver may not be. Usbcore will insure that the method calls
++ * do not arrive during bind, unbind, or reset operations. However, drivers
++ * must be prepared to handle suspend calls arriving at unpredictable times.
++ * The only way to block such calls is to do an autoresume (preventing
++ * autosuspends) while holding @udev's device lock (preventing outside
++ * suspends).
++ *
++ * The caller must hold @udev->pm_mutex.
++ *
++ * This routine can run only in process context.
++ */
++int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
++{
++ int status = 0;
++ int i = 0;
++ struct usb_interface *intf;
++ struct usb_device *parent = udev->parent;
++
++ cancel_delayed_work(&udev->autosuspend);
++ if (udev->state == USB_STATE_NOTATTACHED)
++ return 0;
++ if (udev->state == USB_STATE_SUSPENDED)
++ return 0;
++
++ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
++
++ /* For autosuspend, fail fast if anything is in use.
++ * Also fail if any interfaces require remote wakeup but it
++ * isn't available. */
++ if (udev->auto_pm) {
++ if (udev->pm_usage_cnt > 0)
++ return -EBUSY;
++ if (udev->actconfig) {
++ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
++ intf = udev->actconfig->interface[i];
++ if (!is_active(intf))
++ continue;
++ if (intf->pm_usage_cnt > 0)
++ return -EBUSY;
++ if (intf->needs_remote_wakeup &&
++ !udev->do_remote_wakeup) {
++ dev_dbg(&udev->dev,
++ "remote wakeup needed for autosuspend\n");
++ return -EOPNOTSUPP;
++ }
++ }
++ i = 0;
++ }
++ }
++
++ /* Suspend all the interfaces and then udev itself */
++ if (udev->actconfig) {
++ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
++ intf = udev->actconfig->interface[i];
++ status = suspend_interface(intf, msg);
++ if (status != 0)
++ break;
++ }
++ }
++ if (status == 0)
++ status = suspend_device(udev, msg);
++
++ /* If the suspend failed, resume interfaces that did get suspended */
++ if (status != 0) {
++ while (--i >= 0) {
++ intf = udev->actconfig->interface[i];
++ resume_interface(intf);
++ }
++
++ /* If the suspend succeeded, propagate it up the tree */
++ } else if (parent)
++ usb_autosuspend_device(parent, 0);
++
++ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
++ return status;
++}
++
++/**
++ * usb_resume_both - resume a USB device and its interfaces
++ * @udev: the usb_device to resume
++ *
++ * This is the central routine for resuming USB devices. It calls the
++ * the resume method for @udev and then calls the resume methods for all
++ * the interface drivers in @udev.
++ *
++ * Before starting the resume, the routine calls itself recursively for
++ * the parent device of @udev, thereby propagating the change up the device
++ * tree and assuring that @udev will be able to resume. If the parent is
++ * unable to resume successfully, the routine fails.
++ *
++ * The resume method calls are subject to mutual exclusion under control
++ * of @udev's pm_mutex. Many of these calls are also under the protection
++ * of @udev's device lock (including all requests originating outside the
++ * USB subsystem), but autoresume requests generated by a child device or
++ * interface driver may not be. Usbcore will insure that the method calls
++ * do not arrive during bind, unbind, or reset operations. However, drivers
++ * must be prepared to handle resume calls arriving at unpredictable times.
++ * The only way to block such calls is to do an autoresume (preventing
++ * other autoresumes) while holding @udev's device lock (preventing outside
++ * resumes).
++ *
++ * The caller must hold @udev->pm_mutex.
++ *
++ * This routine can run only in process context.
++ */
++int usb_resume_both(struct usb_device *udev)
++{
++ int status = 0;
++ int i;
++ struct usb_interface *intf;
++ struct usb_device *parent = udev->parent;
++
++ cancel_delayed_work(&udev->autosuspend);
++ if (udev->state == USB_STATE_NOTATTACHED)
++ return -ENODEV;
++
++ /* Propagate the resume up the tree, if necessary */
++ if (udev->state == USB_STATE_SUSPENDED) {
++ if (parent) {
++ usb_pm_lock(parent);
++ parent->auto_pm = 1;
++ status = usb_resume_both(parent);
++ } else {
++
++ /* We can't progagate beyond the USB subsystem,
++ * so if a root hub's controller is suspended
++ * then we're stuck. */
++ if (udev->dev.parent->power.power_state.event !=
++ PM_EVENT_ON)
++ status = -EHOSTUNREACH;
++ }
++ if (status == 0)
++ status = resume_device(udev);
++ if (parent)
++ usb_pm_unlock(parent);
++ } else {
++
++ /* Needed only for setting udev->dev.power.power_state.event
++ * and for possible debugging message. */
++ status = resume_device(udev);
++ }
++
++ /* Now the parent won't suspend until we are finished */
++
++ if (status == 0 && udev->actconfig) {
++ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
++ intf = udev->actconfig->interface[i];
++ resume_interface(intf);
++ }
++ }
++
++ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
++ return status;
++}
++
++#ifdef CONFIG_USB_SUSPEND
++
++/**
++ * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
++ * @udev: the usb_device to autosuspend
++ * @dec_usage_cnt: flag to decrement @udev's PM-usage counter
++ *
++ * This routine should be called when a core subsystem is finished using
++ * @udev and wants to allow it to autosuspend. Examples would be when
++ * @udev's device file in usbfs is closed or after a configuration change.
++ *
++ * @dec_usage_cnt should be 1 if the subsystem previously incremented
++ * @udev's usage counter (such as by passing 1 to usb_autoresume_device);
++ * otherwise it should be 0.
++ *
++ * If the usage counter for @udev or any of its active interfaces is greater
++ * than 0, the autosuspend request will not be queued. (If an interface
++ * driver does not support autosuspend then its usage counter is permanently
++ * positive.) Likewise, if an interface driver requires remote-wakeup
++ * capability during autosuspend but remote wakeup is disabled, the
++ * autosuspend will fail.
++ *
++ * Often the caller will hold @udev's device lock, but this is not
++ * necessary.
++ *
++ * This routine can run only in process context.
++ */
++void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt)
++{
++ usb_pm_lock(udev);
++ udev->pm_usage_cnt -= dec_usage_cnt;
++ if (udev->pm_usage_cnt <= 0)
++ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
++ USB_AUTOSUSPEND_DELAY);
++ usb_pm_unlock(udev);
++ // dev_dbg(&udev->dev, "%s: cnt %d\n",
++ // __FUNCTION__, udev->pm_usage_cnt);
++}
++
++/**
++ * usb_autoresume_device - immediately autoresume a USB device and its interfaces
++ * @udev: the usb_device to autoresume
++ * @inc_usage_cnt: flag to increment @udev's PM-usage counter
++ *
++ * This routine should be called when a core subsystem wants to use @udev
++ * and needs to guarantee that it is not suspended. In addition, the
++ * caller can prevent @udev from being autosuspended subsequently. (Note
++ * that this will not prevent suspend events originating in the PM core.)
++ * Examples would be when @udev's device file in usbfs is opened (autosuspend
++ * should be prevented until the file is closed) or when a remote-wakeup
++ * request is received (later autosuspends should not be prevented).
++ *
++ * @inc_usage_cnt should be 1 to increment @udev's usage counter and prevent
++ * autosuspends. This prevention will persist until the usage counter is
++ * decremented again (such as by passing 1 to usb_autosuspend_device).
++ * Otherwise @inc_usage_cnt should be 0 to leave the usage counter unchanged.
++ * Regardless, if the autoresume fails then the usage counter is not
++ * incremented.
++ *
++ * Often the caller will hold @udev's device lock, but this is not
++ * necessary (and attempting it might cause deadlock).
++ *
++ * This routine can run only in process context.
++ */
++int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt)
++{
++ int status;
++
++ usb_pm_lock(udev);
++ udev->pm_usage_cnt += inc_usage_cnt;
++ udev->auto_pm = 1;
++ status = usb_resume_both(udev);
++ if (status != 0)
++ udev->pm_usage_cnt -= inc_usage_cnt;
++ usb_pm_unlock(udev);
++ // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
++ // __FUNCTION__, status, udev->pm_usage_cnt);
++ return status;
++}
++
++/**
++ * usb_autopm_put_interface - decrement a USB interface's PM-usage counter
++ * @intf: the usb_interface whose counter should be decremented
++ *
++ * This routine should be called by an interface driver when it is
++ * finished using @intf and wants to allow it to autosuspend. A typical
++ * example would be a character-device driver when its device file is
++ * closed.
++ *
++ * The routine decrements @intf's usage counter. When the counter reaches
++ * 0, a delayed autosuspend request for @intf's device is queued. When
++ * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all
++ * the other usage counters for the sibling interfaces and @intf's
++ * usb_device, the device and all its interfaces will be autosuspended.
++ *
++ * Note that @intf->pm_usage_cnt is owned by the interface driver. The
++ * core will not change its value other than the increment and decrement
++ * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
++ * may use this simple counter-oriented discipline or may set the value
++ * any way it likes.
++ *
++ * If the driver has set @intf->needs_remote_wakeup then autosuspend will
++ * take place only if the device's remote-wakeup facility is enabled.
++ *
++ * Suspend method calls queued by this routine can arrive at any time
++ * while @intf is resumed and its usage counter is equal to 0. They are
++ * not protected by the usb_device's lock but only by its pm_mutex.
++ * Drivers must provide their own synchronization.
++ *
++ * This routine can run only in process context.
++ */
++void usb_autopm_put_interface(struct usb_interface *intf)
++{
++ struct usb_device *udev = interface_to_usbdev(intf);
++
++ usb_pm_lock(udev);
++ if (intf->condition != USB_INTERFACE_UNBOUND &&
++ --intf->pm_usage_cnt <= 0) {
++ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
++ USB_AUTOSUSPEND_DELAY);
++ }
++ usb_pm_unlock(udev);
++ // dev_dbg(&intf->dev, "%s: cnt %d\n",
++ // __FUNCTION__, intf->pm_usage_cnt);
++}
++EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
++
++/**
++ * usb_autopm_get_interface - increment a USB interface's PM-usage counter
++ * @intf: the usb_interface whose counter should be incremented
++ *
++ * This routine should be called by an interface driver when it wants to
++ * use @intf and needs to guarantee that it is not suspended. In addition,
++ * the routine prevents @intf from being autosuspended subsequently. (Note
++ * that this will not prevent suspend events originating in the PM core.)
++ * This prevention will persist until usb_autopm_put_interface() is called
++ * or @intf is unbound. A typical example would be a character-device
++ * driver when its device file is opened.
++ *
++ * The routine increments @intf's usage counter. So long as the counter
++ * is greater than 0, autosuspend will not be allowed for @intf or its
++ * usb_device. When the driver is finished using @intf it should call
++ * usb_autopm_put_interface() to decrement the usage counter and queue
++ * a delayed autosuspend request (if the counter is <= 0).
++ *
++ * Note that @intf->pm_usage_cnt is owned by the interface driver. The
++ * core will not change its value other than the increment and decrement
++ * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
++ * may use this simple counter-oriented discipline or may set the value
++ * any way it likes.
++ *
++ * Resume method calls generated by this routine can arrive at any time
++ * while @intf is suspended. They are not protected by the usb_device's
++ * lock but only by its pm_mutex. Drivers must provide their own
++ * synchronization.
++ *
++ * This routine can run only in process context.
++ */
++int usb_autopm_get_interface(struct usb_interface *intf)
++{
++ struct usb_device *udev = interface_to_usbdev(intf);
++ int status;
++
++ usb_pm_lock(udev);
++ if (intf->condition == USB_INTERFACE_UNBOUND)
++ status = -ENODEV;
++ else {
++ ++intf->pm_usage_cnt;
++ udev->auto_pm = 1;
++ status = usb_resume_both(udev);
++ if (status != 0)
++ --intf->pm_usage_cnt;
++ }
++ usb_pm_unlock(udev);
++ // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
++ // __FUNCTION__, status, intf->pm_usage_cnt);
++ return status;
++}
++EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
++
++#endif /* CONFIG_USB_SUSPEND */
++
++static int usb_suspend(struct device *dev, pm_message_t message)
++{
++ int status;
++
++ if (is_usb_device(dev)) {
++ struct usb_device *udev = to_usb_device(dev);
++
++ usb_pm_lock(udev);
++ udev->auto_pm = 0;
++ status = usb_suspend_both(udev, message);
++ usb_pm_unlock(udev);
++ } else
++ status = 0;
++ return status;
++}
++
++static int usb_resume(struct device *dev)
++{
++ int status;
++
++ if (is_usb_device(dev)) {
++ struct usb_device *udev = to_usb_device(dev);
++
++ usb_pm_lock(udev);
++ udev->auto_pm = 0;
++ status = usb_resume_both(udev);
++ usb_pm_unlock(udev);
++
++ /* Rebind drivers that had no suspend method? */
++ } else
++ status = 0;
++ return status;
++}
++
++#endif /* CONFIG_PM */
++
++struct bus_type usb_bus_type = {
++ .name = "usb",
++ .match = usb_device_match,
++ .uevent = usb_uevent,
++#ifdef CONFIG_PM
++ .suspend = usb_suspend,
++ .resume = usb_resume,
++#endif
++};
+diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
+index 247b5a4..3b2d137 100644
+--- a/drivers/usb/core/endpoint.c
++++ b/drivers/usb/core/endpoint.c
+@@ -207,9 +207,9 @@ static void ep_device_release(struct dev
+ kfree(ep_dev);
+ }
+
+-void usb_create_ep_files(struct device *parent,
+- struct usb_host_endpoint *endpoint,
+- struct usb_device *udev)
++int usb_create_ep_files(struct device *parent,
++ struct usb_host_endpoint *endpoint,
++ struct usb_device *udev)
+ {
+ char name[8];
+ struct ep_device *ep_dev;
+@@ -223,7 +223,7 @@ void usb_create_ep_files(struct device *
+ ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
+ if (!ep_dev) {
+ retval = -ENOMEM;
+- goto exit;
++ goto error_alloc;
+ }
+
+ /* fun calculation to determine the minor of this endpoint */
+@@ -241,20 +241,32 @@ void usb_create_ep_files(struct device *
+
+ retval = device_register(&ep_dev->dev);
+ if (retval)
+- goto error;
+- sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+-
+- endpoint->ep_dev = ep_dev;
++ goto error_register;
++ retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
++ if (retval)
++ goto error_group;
+
+ /* create the symlink to the old-style "ep_XX" directory */
+ sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
+- sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name);
++ retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
++ if (retval)
++ goto error_link;
++ endpoint->ep_dev = ep_dev;
++ return retval;
+
+-exit:
+- return;
+-error:
++error_link:
++ sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
++error_group:
++ device_unregister(&ep_dev->dev);
++ destroy_endpoint_class();
++ return retval;
++
++error_register:
+ kfree(ep_dev);
+- return;
++error_alloc:
++ destroy_endpoint_class();
++exit:
++ return retval;
+ }
+
+ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
+@@ -268,8 +280,6 @@ void usb_remove_ep_files(struct usb_host
+ sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
+ device_unregister(&endpoint->ep_dev->dev);
+ endpoint->ep_dev = NULL;
++ destroy_endpoint_class();
+ }
+- destroy_endpoint_class();
+ }
+-
+-
+diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
+index 8de4f8c..f794f07 100644
+--- a/drivers/usb/core/file.c
++++ b/drivers/usb/core/file.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/usb/file.c
++ * drivers/usb/core/file.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+@@ -55,7 +55,7 @@ static int usb_open(struct inode * inode
+ return err;
+ }
+
+-static struct file_operations usb_fops = {
++static const struct file_operations usb_fops = {
+ .owner = THIS_MODULE,
+ .open = usb_open,
+ };
+diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
+new file mode 100644
+index 0000000..ebb20ff
+--- /dev/null
++++ b/drivers/usb/core/generic.c
+@@ -0,0 +1,207 @@
++/*
++ * drivers/usb/generic.c - generic driver for USB devices (not interfaces)
++ *
++ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh at suse.de>
++ *
++ * based on drivers/usb/usb.c which had the following copyrights:
++ * (C) Copyright Linus Torvalds 1999
++ * (C) Copyright Johannes Erdfelt 1999-2001
++ * (C) Copyright Andreas Gal 1999
++ * (C) Copyright Gregory P. Smith 1999
++ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
++ * (C) Copyright Randy Dunlap 2000
++ * (C) Copyright David Brownell 2000-2004
++ * (C) Copyright Yggdrasil Computing, Inc. 2000
++ * (usb_device_id matching changes by Adam J. Richter)
++ * (C) Copyright Greg Kroah-Hartman 2002-2003
++ *
++ */
++
++#include <linux/usb.h>
++#include "usb.h"
++
++static inline const char *plural(int n)
++{
++ return (n == 1 ? "" : "s");
++}
++
++static int choose_configuration(struct usb_device *udev)
++{
++ int i;
++ int num_configs;
++ int insufficient_power = 0;
++ struct usb_host_config *c, *best;
++
++ best = NULL;
++ c = udev->config;
++ num_configs = udev->descriptor.bNumConfigurations;
++ for (i = 0; i < num_configs; (i++, c++)) {
++ struct usb_interface_descriptor *desc = NULL;
++
++ /* It's possible that a config has no interfaces! */
++ if (c->desc.bNumInterfaces > 0)
++ desc = &c->intf_cache[0]->altsetting->desc;
++
++ /*
++ * HP's USB bus-powered keyboard has only one configuration
++ * and it claims to be self-powered; other devices may have
++ * similar errors in their descriptors. If the next test
++ * were allowed to execute, such configurations would always
++ * be rejected and the devices would not work as expected.
++ * In the meantime, we run the risk of selecting a config
++ * that requires external power at a time when that power
++ * isn't available. It seems to be the lesser of two evils.
++ *
++ * Bugzilla #6448 reports a device that appears to crash
++ * when it receives a GET_DEVICE_STATUS request! We don't
++ * have any other way to tell whether a device is self-powered,
++ * but since we don't use that information anywhere but here,
++ * the call has been removed.
++ *
++ * Maybe the GET_DEVICE_STATUS call and the test below can
++ * be reinstated when device firmwares become more reliable.
++ * Don't hold your breath.
++ */
++#if 0
++ /* Rule out self-powered configs for a bus-powered device */
++ if (bus_powered && (c->desc.bmAttributes &
++ USB_CONFIG_ATT_SELFPOWER))
++ continue;
++#endif
++
++ /*
++ * The next test may not be as effective as it should be.
++ * Some hubs have errors in their descriptor, claiming
++ * to be self-powered when they are really bus-powered.
++ * We will overestimate the amount of current such hubs
++ * make available for each port.
++ *
++ * This is a fairly benign sort of failure. It won't
++ * cause us to reject configurations that we should have
++ * accepted.
++ */
++
++ /* Rule out configs that draw too much bus current */
++ if (c->desc.bMaxPower * 2 > udev->bus_mA) {
++ insufficient_power++;
++ continue;
++ }
++
++ /* If the first config's first interface is COMM/2/0xff
++ * (MSFT RNDIS), rule it out unless Linux has host-side
++ * RNDIS support. */
++ if (i == 0 && desc
++ && desc->bInterfaceClass == USB_CLASS_COMM
++ && desc->bInterfaceSubClass == 2
++ && desc->bInterfaceProtocol == 0xff) {
++#ifndef CONFIG_USB_NET_RNDIS_HOST
++ continue;
++#else
++ best = c;
++#endif
++ }
++
++ /* From the remaining configs, choose the first one whose
++ * first interface is for a non-vendor-specific class.
++ * Reason: Linux is more likely to have a class driver
++ * than a vendor-specific driver. */
++ else if (udev->descriptor.bDeviceClass !=
++ USB_CLASS_VENDOR_SPEC &&
++ (!desc || desc->bInterfaceClass !=
++ USB_CLASS_VENDOR_SPEC)) {
++ best = c;
++ break;
++ }
++
++ /* If all the remaining configs are vendor-specific,
++ * choose the first one. */
++ else if (!best)
++ best = c;
++ }
++
++ if (insufficient_power > 0)
++ dev_info(&udev->dev, "rejected %d configuration%s "
++ "due to insufficient available bus power\n",
++ insufficient_power, plural(insufficient_power));
++
++ if (best) {
++ i = best->desc.bConfigurationValue;
++ dev_info(&udev->dev,
++ "configuration #%d chosen from %d choice%s\n",
++ i, num_configs, plural(num_configs));
++ } else {
++ i = -1;
++ dev_warn(&udev->dev,
++ "no configuration chosen from %d choice%s\n",
++ num_configs, plural(num_configs));
++ }
++ return i;
++}
++
++static int generic_probe(struct usb_device *udev)
++{
++ int err, c;
++
++ /* put device-specific files into sysfs */
++ usb_create_sysfs_dev_files(udev);
++
++ /* Choose and set the configuration. This registers the interfaces
++ * with the driver core and lets interface drivers bind to them.
++ */
++ c = choose_configuration(udev);
++ if (c >= 0) {
++ err = usb_set_configuration(udev, c);
++ if (err) {
++ dev_err(&udev->dev, "can't set config #%d, error %d\n",
++ c, err);
++ /* This need not be fatal. The user can try to
++ * set other configurations. */
++ }
++ }
++
++ /* USB device state == configured ... usable */
++ usb_notify_add_device(udev);
++
++ return 0;
++}
++
++static void generic_disconnect(struct usb_device *udev)
++{
++ usb_notify_remove_device(udev);
++
++ /* if this is only an unbind, not a physical disconnect, then
++ * unconfigure the device */
++ if (udev->actconfig)
++ usb_set_configuration(udev, 0);
++
++ usb_remove_sysfs_dev_files(udev);
++}
++
++#ifdef CONFIG_PM
++
++static int generic_suspend(struct usb_device *udev, pm_message_t msg)
++{
++ /* USB devices enter SUSPEND state through their hubs, but can be
++ * marked for FREEZE as soon as their children are already idled.
++ * But those semantics are useless, so we equate the two (sigh).
++ */
++ return usb_port_suspend(udev);
++}
++
++static int generic_resume(struct usb_device *udev)
++{
++ return usb_port_resume(udev);
++}
++
++#endif /* CONFIG_PM */
++
++struct usb_device_driver usb_generic_driver = {
++ .name = "usb",
++ .probe = generic_probe,
++ .disconnect = generic_disconnect,
++#ifdef CONFIG_PM
++ .suspend = generic_suspend,
++ .resume = generic_resume,
++#endif
++ .supports_autosuspend = 1,
++};
+diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
+index 5078fb3..edf4300 100644
+--- a/drivers/usb/core/hcd-pci.c
++++ b/drivers/usb/core/hcd-pci.c
+@@ -281,7 +281,7 @@ int usb_hcd_pci_suspend (struct pci_dev
+ (void) usb_hcd_pci_resume (dev);
+ }
+
+- } else {
++ } else if (hcd->state != HC_STATE_HALT) {
+ dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
+ hcd->state);
+ WARN_ON(1);
+@@ -413,4 +413,20 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+ #endif /* CONFIG_PM */
+
++/**
++ * usb_hcd_pci_shutdown - shutdown host controller
++ * @dev: USB Host Controller being shutdown
++ */
++void usb_hcd_pci_shutdown (struct pci_dev *dev)
++{
++ struct usb_hcd *hcd;
++
++ hcd = pci_get_drvdata(dev);
++ if (!hcd)
++ return;
++
++ if (hcd->driver->shutdown)
++ hcd->driver->shutdown(hcd);
++}
++EXPORT_SYMBOL (usb_hcd_pci_shutdown);
+
+diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
+index fb4d058..afa2dd2 100644
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -36,6 +36,7 @@
+ #include <linux/mutex.h>
+ #include <asm/irq.h>
+ #include <asm/byteorder.h>
++#include <linux/platform_device.h>
+
+ #include <linux/usb.h>
+
+@@ -317,8 +318,8 @@ static int rh_string (
+
+ // id 3 == vendor description
+ } else if (id == 3) {
+- snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname,
+- system_utsname.release, hcd->driver->description);
++ snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
++ init_utsname()->release, hcd->driver->description);
+
+ // unsupported IDs --> "protocol stall"
+ } else
+@@ -344,7 +345,8 @@ static int rh_call_control (struct usb_h
+ struct usb_ctrlrequest *cmd;
+ u16 typeReq, wValue, wIndex, wLength;
+ u8 *ubuf = urb->transfer_buffer;
+- u8 tbuf [sizeof (struct usb_hub_descriptor)];
++ u8 tbuf [sizeof (struct usb_hub_descriptor)]
++ __attribute__((aligned(4)));
+ const u8 *bufp = tbuf;
+ int len = 0;
+ int patch_wakeup = 0;
+@@ -520,7 +522,7 @@ error:
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ spin_unlock (&urb->lock);
+- usb_hcd_giveback_urb (hcd, urb, NULL);
++ usb_hcd_giveback_urb (hcd, urb);
+ local_irq_restore (flags);
+ return 0;
+ }
+@@ -570,7 +572,7 @@ void usb_hcd_poll_rh_status(struct usb_h
+
+ /* local irqs are always blocked in completions */
+ if (length > 0)
+- usb_hcd_giveback_urb (hcd, urb, NULL);
++ usb_hcd_giveback_urb (hcd, urb);
+ else
+ hcd->poll_pending = 1;
+ local_irq_restore (flags);
+@@ -632,31 +634,20 @@ static int rh_urb_enqueue (struct usb_hc
+
+ /*-------------------------------------------------------------------------*/
+
+-/* 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.
++/* Unlinks of root-hub control URBs are legal, but they don't do anything
++ * since these URBs always execute synchronously.
+ */
+ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+ {
+- if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+- if (in_interrupt())
+- return 0; /* nothing to do */
+-
+- spin_lock_irq(&urb->lock); /* from usb_kill_urb */
+- ++urb->reject;
+- spin_unlock_irq(&urb->lock);
+-
+- wait_event(usb_kill_urb_queue,
+- atomic_read(&urb->use_count) == 0);
++ unsigned long flags;
+
+- spin_lock_irq(&urb->lock);
+- --urb->reject;
+- spin_unlock_irq(&urb->lock);
++ if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
++ ; /* Do nothing */
+
+ } else { /* Status URB */
+ if (!hcd->uses_new_polling)
+- del_timer_sync (&hcd->rh_timer);
+- local_irq_disable ();
++ del_timer (&hcd->rh_timer);
++ local_irq_save (flags);
+ spin_lock (&hcd_root_hub_lock);
+ if (urb == hcd->status_urb) {
+ hcd->status_urb = NULL;
+@@ -665,8 +656,8 @@ static int usb_rh_urb_dequeue (struct us
+ urb = NULL; /* wasn't fully queued */
+ spin_unlock (&hcd_root_hub_lock);
+ if (urb)
+- usb_hcd_giveback_urb (hcd, urb, NULL);
+- local_irq_enable ();
++ usb_hcd_giveback_urb (hcd, urb);
++ local_irq_restore (flags);
+ }
+
+ return 0;
+@@ -674,31 +665,6 @@ static int usb_rh_urb_dequeue (struct us
+
+ /*-------------------------------------------------------------------------*/
+
+-/* exported only within usbcore */
+-struct usb_bus *usb_bus_get(struct usb_bus *bus)
+-{
+- if (bus)
+- kref_get(&bus->kref);
+- return bus;
+-}
+-
+-static void usb_host_release(struct kref *kref)
+-{
+- struct usb_bus *bus = container_of(kref, struct usb_bus, kref);
+-
+- if (bus->release)
+- bus->release(bus);
+-}
+-
+-/* exported only within usbcore */
+-void usb_bus_put(struct usb_bus *bus)
+-{
+- if (bus)
+- kref_put(&bus->kref, usb_host_release);
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+ static struct class *usb_host_class;
+
+ int usb_host_init(void)
+@@ -730,39 +696,12 @@ static void usb_bus_init (struct usb_bus
+ bus->devnum_next = 1;
+
+ bus->root_hub = NULL;
+- bus->hcpriv = NULL;
+ bus->busnum = -1;
+ bus->bandwidth_allocated = 0;
+ bus->bandwidth_int_reqs = 0;
+ bus->bandwidth_isoc_reqs = 0;
+
+ INIT_LIST_HEAD (&bus->bus_list);
+-
+- kref_init(&bus->kref);
+-}
+-
+-/**
+- * usb_alloc_bus - creates a new USB host controller structure
+- * @op: pointer to a struct usb_operations that this bus structure should use
+- * Context: !in_interrupt()
+- *
+- * Creates a USB host controller bus structure with the specified
+- * usb_operations and initializes all the necessary internal objects.
+- *
+- * If no memory is available, NULL is returned.
+- *
+- * The caller should call usb_put_bus() when it is finished with the structure.
+- */
+-struct usb_bus *usb_alloc_bus (struct usb_operations *op)
+-{
+- struct usb_bus *bus;
+-
+- bus = kzalloc (sizeof *bus, GFP_KERNEL);
+- if (!bus)
+- return NULL;
+- usb_bus_init (bus);
+- bus->op = op;
+- return bus;
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -897,8 +836,7 @@ void usb_enable_root_hub_irq (struct usb
+ 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)
++ if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
+ hcd->driver->hub_irq_enable (hcd);
+ }
+
+@@ -1112,10 +1050,10 @@ 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, gfp_t mem_flags)
++int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+ {
+ int status;
+- struct usb_hcd *hcd = urb->dev->bus->hcpriv;
++ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+ struct usb_host_endpoint *ep;
+ unsigned long flags;
+
+@@ -1186,7 +1124,7 @@ doit:
+ /* lower level hcd code should use *_dma exclusively,
+ * unless it uses pio or talks to another transport.
+ */
+- if (hcd->self.controller->dma_mask) {
++ if (hcd->self.uses_dma) {
+ if (usb_pipecontrol (urb->pipe)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ urb->setup_dma = dma_map_single (
+@@ -1221,9 +1159,10 @@ done:
+ /*-------------------------------------------------------------------------*/
+
+ /* called in any context */
+-static int hcd_get_frame_number (struct usb_device *udev)
++int usb_hcd_get_frame_number (struct usb_device *udev)
+ {
+- struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv;
++ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
++
+ if (!HC_IS_RUNNING (hcd->state))
+ return -ESHUTDOWN;
+ return hcd->driver->get_frame_number (hcd);
+@@ -1263,7 +1202,7 @@ unlink1 (struct usb_hcd *hcd, struct urb
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+-static int hcd_unlink_urb (struct urb *urb, int status)
++int usb_hcd_unlink_urb (struct urb *urb, int status)
+ {
+ struct usb_host_endpoint *ep;
+ struct usb_hcd *hcd = NULL;
+@@ -1296,7 +1235,7 @@ static int hcd_unlink_urb (struct urb *u
+ spin_lock (&hcd_data_lock);
+
+ sys = &urb->dev->dev;
+- hcd = urb->dev->bus->hcpriv;
++ hcd = bus_to_hcd(urb->dev->bus);
+ if (hcd == NULL) {
+ retval = -ENODEV;
+ goto done;
+@@ -1354,41 +1293,33 @@ done:
+ /*-------------------------------------------------------------------------*/
+
+ /* disables the endpoint: cancels any pending urbs, then synchronizes with
+- * the hcd to make sure all endpoint state is gone from hardware. use for
++ * the hcd to make sure all endpoint state is gone from hardware, and then
++ * waits until the endpoint's queue is completely drained. use for
+ * set_configuration, set_interface, driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+-static void
+-hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
++void usb_hcd_endpoint_disable (struct usb_device *udev,
++ struct usb_host_endpoint *ep)
+ {
+ struct usb_hcd *hcd;
+ struct urb *urb;
+
+- hcd = udev->bus->hcpriv;
++ hcd = bus_to_hcd(udev->bus);
+
+ WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
+ udev->state != USB_STATE_NOTATTACHED);
+
+ local_irq_disable ();
+
+- /* FIXME move most of this into message.c as part of its
+- * endpoint disable logic
+- */
+-
+ /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+ rescan:
+ spin_lock (&hcd_data_lock);
+ list_for_each_entry (urb, &ep->urb_list, urb_list) {
+ int tmp;
+
+- /* another cpu may be in hcd, spinning on hcd_data_lock
+- * to giveback() this urb. the races here should be
+- * small, but a full fix needs a new "can't submit"
+- * urb state.
+- * FIXME urb->reject should allow that...
+- */
++ /* the urb may already have been unlinked */
+ if (urb->status != -EINPROGRESS)
+ continue;
+ usb_get_urb (urb);
+@@ -1430,6 +1361,30 @@ rescan:
+ might_sleep ();
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable (hcd, ep);
++
++ /* Wait until the endpoint queue is completely empty. Most HCDs
++ * will have done this already in their endpoint_disable method,
++ * but some might not. And there could be root-hub control URBs
++ * still pending since they aren't affected by the HCDs'
++ * endpoint_disable methods.
++ */
++ while (!list_empty (&ep->urb_list)) {
++ spin_lock_irq (&hcd_data_lock);
++
++ /* The list may have changed while we acquired the spinlock */
++ urb = NULL;
++ if (!list_empty (&ep->urb_list)) {
++ urb = list_entry (ep->urb_list.prev, struct urb,
++ urb_list);
++ usb_get_urb (urb);
++ }
++ spin_unlock_irq (&hcd_data_lock);
++
++ if (urb) {
++ usb_kill_urb (urb);
++ usb_put_urb (urb);
++ }
++ }
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -1476,50 +1431,6 @@ int hcd_bus_resume (struct usb_bus *bus)
+ return status;
+ }
+
+-/*
+- * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
+- * @hcd: host controller for this root hub
+- *
+- * This call arranges that usb_hcd_resume_root_hub() is safe to call later;
+- * that the HCD's root hub polling is deactivated; and that the root's hub
+- * driver is suspended. HCDs may call this to autosuspend when their root
+- * hub's downstream ports are all inactive: unpowered, disconnected,
+- * disabled, or suspended.
+- *
+- * The HCD will autoresume on device connect change detection (using SRP
+- * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
+- * from any ports that are suspended (if that is enabled). In most cases,
+- * overcurrent signaling (on powered ports) will also start autoresume.
+- *
+- * Always called with IRQs blocked.
+- */
+-void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
+-{
+- struct urb *urb;
+-
+- spin_lock (&hcd_root_hub_lock);
+- usb_suspend_root_hub (hcd->self.root_hub);
+-
+- /* force status urb to complete/unlink while suspended */
+- if (hcd->status_urb) {
+- urb = hcd->status_urb;
+- urb->status = -ECONNRESET;
+- urb->hcpriv = NULL;
+- urb->actual_length = 0;
+-
+- del_timer (&hcd->rh_timer);
+- hcd->poll_pending = 0;
+- hcd->status_urb = NULL;
+- } else
+- urb = NULL;
+- spin_unlock (&hcd_root_hub_lock);
+- hcd->state = HC_STATE_SUSPENDED;
+-
+- if (urb)
+- usb_hcd_giveback_urb (hcd, urb, NULL);
+-}
+-EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
+-
+ /**
+ * usb_hcd_resume_root_hub - called by HCD to resume its root hub
+ * @hcd: host controller for this root hub
+@@ -1583,25 +1494,10 @@ EXPORT_SYMBOL (usb_bus_start_enum);
+
+ /*-------------------------------------------------------------------------*/
+
+-/*
+- * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
+- */
+-static struct usb_operations usb_hcd_operations = {
+- .get_frame_number = hcd_get_frame_number,
+- .submit_urb = hcd_submit_urb,
+- .unlink_urb = hcd_unlink_urb,
+- .buffer_alloc = hcd_buffer_alloc,
+- .buffer_free = hcd_buffer_free,
+- .disable = hcd_endpoint_disable,
+-};
+-
+-/*-------------------------------------------------------------------------*/
+-
+ /**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+- * @regs: pt_regs, passed down to the URB completion handler
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+@@ -1610,15 +1506,16 @@ static struct usb_operations usb_hcd_ope
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
++void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+ {
+ int at_root_hub;
+
+ at_root_hub = (urb->dev == hcd->self.root_hub);
+ urb_unlink (urb);
+
+- /* lower level hcd code should use *_dma exclusively */
+- if (hcd->self.controller->dma_mask && !at_root_hub) {
++ /* lower level hcd code should use *_dma exclusively if the
++ * host controller does DMA */
++ if (hcd->self.uses_dma && !at_root_hub) {
+ if (usb_pipecontrol (urb->pipe)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ dma_unmap_single (hcd->self.controller, urb->setup_dma,
+@@ -1636,7 +1533,7 @@ void usb_hcd_giveback_urb (struct usb_hc
+
+ usbmon_urb_complete (&hcd->self, urb);
+ /* pass ownership to the completion handler */
+- urb->complete (urb, regs);
++ urb->complete (urb);
+ atomic_dec (&urb->use_count);
+ if (unlikely (urb->reject))
+ wake_up (&usb_kill_urb_queue);
+@@ -1655,7 +1552,7 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
+ * If the controller isn't HALTed, calls the driver's irq handler.
+ * Checks whether the controller is now dead.
+ */
+-irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
++irqreturn_t usb_hcd_irq (int irq, void *__hcd)
+ {
+ struct usb_hcd *hcd = __hcd;
+ int start = hcd->state;
+@@ -1663,7 +1560,7 @@ irqreturn_t usb_hcd_irq (int irq, void *
+ if (unlikely(start == HC_STATE_HALT ||
+ !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+ return IRQ_NONE;
+- if (hcd->driver->irq (hcd, r) == IRQ_NONE)
++ if (hcd->driver->irq (hcd) == IRQ_NONE)
+ return IRQ_NONE;
+
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+@@ -1704,14 +1601,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
+
+ /*-------------------------------------------------------------------------*/
+
+-static void hcd_release (struct usb_bus *bus)
+-{
+- struct usb_hcd *hcd;
+-
+- hcd = container_of(bus, struct usb_hcd, self);
+- kfree(hcd);
+-}
+-
+ /**
+ * usb_create_hcd - create and initialize an HCD structure
+ * @driver: HC driver that will use this hcd
+@@ -1736,13 +1625,12 @@ struct usb_hcd *usb_create_hcd (const st
+ return NULL;
+ }
+ dev_set_drvdata(dev, hcd);
++ kref_init(&hcd->kref);
+
+ usb_bus_init(&hcd->self);
+- hcd->self.op = &usb_hcd_operations;
+- hcd->self.hcpriv = hcd;
+- hcd->self.release = &hcd_release;
+ hcd->self.controller = dev;
+ hcd->self.bus_name = bus_name;
++ hcd->self.uses_dma = (dev->dma_mask != NULL);
+
+ init_timer(&hcd->rh_timer);
+ hcd->rh_timer.function = rh_timer_func;
+@@ -1756,10 +1644,25 @@ struct usb_hcd *usb_create_hcd (const st
+ }
+ EXPORT_SYMBOL (usb_create_hcd);
+
++static void hcd_release (struct kref *kref)
++{
++ struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
++
++ kfree(hcd);
++}
++
++struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
++{
++ if (hcd)
++ kref_get (&hcd->kref);
++ return hcd;
++}
++EXPORT_SYMBOL (usb_get_hcd);
++
+ void usb_put_hcd (struct usb_hcd *hcd)
+ {
+- dev_set_drvdata(hcd->self.controller, NULL);
+- usb_bus_put(&hcd->self);
++ if (hcd)
++ kref_put (&hcd->kref, hcd_release);
+ }
+ EXPORT_SYMBOL (usb_put_hcd);
+
+@@ -1915,6 +1818,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
+ }
+ EXPORT_SYMBOL (usb_remove_hcd);
+
++void
++usb_hcd_platform_shutdown(struct platform_device* dev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(dev);
++
++ if (hcd->driver->shutdown)
++ hcd->driver->shutdown(hcd);
++}
++EXPORT_SYMBOL (usb_hcd_platform_shutdown);
++
+ /*-------------------------------------------------------------------------*/
+
+ #if defined(CONFIG_USB_MON)
+diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
+index 7022aaf..8f8df0d 100644
+--- a/drivers/usb/core/hcd.h
++++ b/drivers/usb/core/hcd.h
+@@ -55,12 +55,13 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-struct usb_hcd { /* usb_bus.hcpriv points to this */
++struct usb_hcd {
+
+ /*
+ * housekeeping
+ */
+ struct usb_bus self; /* hcd is-a bus */
++ struct kref kref; /* reference counter */
+
+ const char *product_desc; /* product/vendor string */
+ char irq_descr[24]; /* driver + bus # */
+@@ -85,6 +86,7 @@ struct usb_hcd { /* usb_bus.hcpriv point
+ unsigned uses_new_polling:1;
+ unsigned poll_rh:1; /* poll for rh status? */
+ unsigned poll_pending:1; /* status has changed? */
++ unsigned wireless:1; /* Wireless USB HCD */
+
+ int irq; /* irq allocated */
+ void __iomem *regs; /* device memory/io */
+@@ -128,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus
+ return &hcd->self;
+ }
+
+-
+-// urb.hcpriv is really hardware-specific
++static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
++{
++ return container_of(bus, struct usb_hcd, self);
++}
+
+ struct hcd_timeout { /* timeouts we allocate */
+ struct list_head timeout_list;
+@@ -138,30 +142,6 @@ struct hcd_timeout { /* timeouts we allo
+
+ /*-------------------------------------------------------------------------*/
+
+-/*
+- * FIXME usb_operations should vanish or become hc_driver,
+- * when usb_bus and usb_hcd become the same thing.
+- */
+-
+-struct usb_operations {
+- int (*get_frame_number) (struct usb_device *usb_dev);
+- int (*submit_urb) (struct urb *urb, gfp_t 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,
+- gfp_t mem_flags,
+- dma_addr_t *dma);
+- void (*buffer_free)(struct usb_bus *bus, size_t size,
+- void *addr, dma_addr_t dma);
+-
+- void (*disable)(struct usb_device *udev,
+- struct usb_host_endpoint *ep);
+-};
+-
+-/* each driver provides one of these, and hardware init support */
+-
+-struct pt_regs;
+
+ struct hc_driver {
+ const char *description; /* "ehci-hcd" etc */
+@@ -169,7 +149,7 @@ struct hc_driver {
+ size_t hcd_priv_size; /* size of private data */
+
+ /* irq handler */
+- irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);
++ irqreturn_t (*irq) (struct usb_hcd *hcd);
+
+ int flags;
+ #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
+@@ -192,6 +172,9 @@ struct hc_driver {
+ /* cleanly make HCD stop writing memory and doing I/O */
+ void (*stop) (struct usb_hcd *hcd);
+
++ /* shutdown HCD */
++ void (*shutdown) (struct usb_hcd *hcd);
++
+ /* return current frame number */
+ int (*get_frame_number) (struct usb_hcd *hcd);
+
+@@ -218,15 +201,24 @@ struct hc_driver {
+ /* 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);
++extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
++extern int usb_hcd_unlink_urb (struct urb *urb, int status);
++extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
++extern void usb_hcd_endpoint_disable (struct usb_device *udev,
++ struct usb_host_endpoint *ep);
++extern int usb_hcd_get_frame_number (struct usb_device *udev);
+
+ extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+ struct device *dev, char *bus_name);
++extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
+ extern void usb_put_hcd (struct usb_hcd *hcd);
+ extern int usb_add_hcd(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags);
+ extern void usb_remove_hcd(struct usb_hcd *hcd);
+
++struct platform_device;
++extern void usb_hcd_platform_shutdown(struct platform_device* dev);
++
+ #ifdef CONFIG_PCI
+ struct pci_dev;
+ struct pci_device_id;
+@@ -239,6 +231,8 @@ extern int usb_hcd_pci_suspend (struct p
+ extern int usb_hcd_pci_resume (struct pci_dev *dev);
+ #endif /* CONFIG_PM */
+
++extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
++
+ #endif /* CONFIG_PCI */
+
+ /* pci-ish (pdev null is ok) buffer alloc/mapping support */
+@@ -251,7 +245,7 @@ void hcd_buffer_free (struct usb_bus *bu
+ 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 irqreturn_t usb_hcd_irq (int irq, void *__hcd);
+
+ extern void usb_hc_died (struct usb_hcd *hcd);
+ extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
+@@ -352,8 +346,6 @@ extern long usb_calc_bus_time (int speed
+
+ /*-------------------------------------------------------------------------*/
+
+-extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
+-
+ extern void usb_set_device_state(struct usb_device *udev,
+ enum usb_device_state new_state);
+
+@@ -365,9 +357,6 @@ extern struct list_head usb_bus_list;
+ extern struct mutex usb_bus_list_lock;
+ 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,
+@@ -376,17 +365,11 @@ extern int usb_find_interface_driver (st
+ #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
+
+ #ifdef CONFIG_PM
+-extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
+ extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
+ extern void usb_root_hub_lost_power (struct usb_device *rhdev);
+ extern int hcd_bus_suspend (struct usb_bus *bus);
+ extern int hcd_bus_resume (struct usb_bus *bus);
+ #else
+-static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd)
+-{
+- return;
+-}
+-
+ static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
+ {
+ return;
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 26c8cb5..ba165af 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -291,9 +291,9 @@ void usb_kick_khubd(struct usb_device *h
+
+
+ /* completion function, fires on port status changes and various faults */
+-static void hub_irq(struct urb *urb, struct pt_regs *regs)
++static void hub_irq(struct urb *urb)
+ {
+- struct usb_hub *hub = (struct usb_hub *)urb->context;
++ struct usb_hub *hub = urb->context;
+ int status;
+ int i;
+ unsigned long bits;
+@@ -311,7 +311,7 @@ static void hub_irq(struct urb *urb, str
+ goto resubmit;
+ hub->error = urb->status;
+ /* FALL THROUGH */
+-
++
+ /* let khubd handle things */
+ case 0: /* we got data: port status changed */
+ bits = 0;
+@@ -452,18 +452,14 @@ static void hub_power_on(struct usb_hub
+ msleep(max(pgood_delay, (unsigned) 100));
+ }
+
+-static inline void __hub_quiesce(struct usb_hub *hub)
++static void hub_quiesce(struct usb_hub *hub)
+ {
+ /* (nonblocking) khubd and related activity won't re-trigger */
+ hub->quiescing = 1;
+ hub->activating = 0;
+ hub->resume_root_hub = 0;
+-}
+
+-static void hub_quiesce(struct usb_hub *hub)
+-{
+ /* (blocking) stop khubd and related activity */
+- __hub_quiesce(hub);
+ usb_kill_urb(hub->urb);
+ if (hub->has_indicators)
+ cancel_delayed_work(&hub->leds);
+@@ -868,13 +864,8 @@ descriptor_error:
+
+ endpoint = &desc->endpoint[0].desc;
+
+- /* Output endpoint? Curiouser and curiouser.. */
+- if (!(endpoint->bEndpointAddress & USB_DIR_IN))
+- goto descriptor_error;
+-
+- /* If it's not an interrupt endpoint, we'd better punt! */
+- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+- != USB_ENDPOINT_XFER_INT)
++ /* If it's not an interrupt in endpoint, we'd better punt! */
++ if (!usb_endpoint_is_int_in(endpoint))
+ goto descriptor_error;
+
+ /* We found a hub */
+@@ -1022,26 +1013,29 @@ void usb_set_device_state(struct usb_dev
+ if (udev->state == USB_STATE_NOTATTACHED)
+ ; /* do nothing */
+ else if (new_state != USB_STATE_NOTATTACHED) {
+- udev->state = new_state;
+
+ /* root hub wakeup capabilities are managed out-of-band
+ * and may involve silicon errata ... ignore them here.
+ */
+ if (udev->parent) {
+- if (new_state == USB_STATE_CONFIGURED)
++ if (udev->state == USB_STATE_SUSPENDED
++ || new_state == USB_STATE_SUSPENDED)
++ ; /* No change to wakeup settings */
++ else if (new_state == USB_STATE_CONFIGURED)
+ device_init_wakeup(&udev->dev,
+ (udev->actconfig->desc.bmAttributes
+ & USB_CONFIG_ATT_WAKEUP));
+- else if (new_state != USB_STATE_SUSPENDED)
++ else
+ device_init_wakeup(&udev->dev, 0);
+ }
++ udev->state = new_state;
+ } else
+ recursively_mark_NOTATTACHED(udev);
+ spin_unlock_irqrestore(&device_state_lock, flags);
+ }
+
+
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PM
+
+ /**
+ * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
+@@ -1059,6 +1053,12 @@ void usb_root_hub_lost_power(struct usb_
+ unsigned long flags;
+
+ dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
++
++ /* Make sure no potential wakeup events get lost,
++ * by forcing the root hub to be resumed.
++ */
++ rhdev->dev.power.prev_state.event = PM_EVENT_ON;
++
+ spin_lock_irqsave(&device_state_lock, flags);
+ hub = hdev_to_hub(rhdev);
+ for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
+@@ -1072,7 +1072,7 @@ void usb_root_hub_lost_power(struct usb_
+ }
+ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+
+-#endif
++#endif /* CONFIG_PM */
+
+ static void choose_address(struct usb_device *udev)
+ {
+@@ -1148,144 +1148,28 @@ void usb_disconnect(struct usb_device **
+ * cleaning up all state associated with the current configuration
+ * so that the hardware is now fully quiesced.
+ */
++ dev_dbg (&udev->dev, "unregistering device\n");
+ usb_disable_device(udev, 0);
+
+- usb_notify_remove_device(udev);
++ usb_unlock_device(udev);
+
+- /* Free the device number, remove the /proc/bus/usb entry and
+- * the sysfs attributes, and delete the parent's children[]
++ /* Unregister the device. The device driver is responsible
++ * for removing the device files from usbfs and sysfs and for
++ * de-configuring the device.
++ */
++ device_del(&udev->dev);
++
++ /* Free the device number and delete the parent's children[]
+ * (or root_hub) pointer.
+ */
+- dev_dbg (&udev->dev, "unregistering device\n");
+ release_address(udev);
+- usb_remove_sysfs_dev_files(udev);
+
+ /* Avoid races with recursively_mark_NOTATTACHED() */
+ spin_lock_irq(&device_state_lock);
+ *pdev = NULL;
+ spin_unlock_irq(&device_state_lock);
+
+- usb_unlock_device(udev);
+-
+- device_unregister(&udev->dev);
+-}
+-
+-static inline const char *plural(int n)
+-{
+- return (n == 1 ? "" : "s");
+-}
+-
+-static int choose_configuration(struct usb_device *udev)
+-{
+- int i;
+- int num_configs;
+- int insufficient_power = 0;
+- struct usb_host_config *c, *best;
+-
+- best = NULL;
+- c = udev->config;
+- num_configs = udev->descriptor.bNumConfigurations;
+- for (i = 0; i < num_configs; (i++, c++)) {
+- struct usb_interface_descriptor *desc = NULL;
+-
+- /* It's possible that a config has no interfaces! */
+- if (c->desc.bNumInterfaces > 0)
+- desc = &c->intf_cache[0]->altsetting->desc;
+-
+- /*
+- * HP's USB bus-powered keyboard has only one configuration
+- * and it claims to be self-powered; other devices may have
+- * similar errors in their descriptors. If the next test
+- * were allowed to execute, such configurations would always
+- * be rejected and the devices would not work as expected.
+- * In the meantime, we run the risk of selecting a config
+- * that requires external power at a time when that power
+- * isn't available. It seems to be the lesser of two evils.
+- *
+- * Bugzilla #6448 reports a device that appears to crash
+- * when it receives a GET_DEVICE_STATUS request! We don't
+- * have any other way to tell whether a device is self-powered,
+- * but since we don't use that information anywhere but here,
+- * the call has been removed.
+- *
+- * Maybe the GET_DEVICE_STATUS call and the test below can
+- * be reinstated when device firmwares become more reliable.
+- * Don't hold your breath.
+- */
+-#if 0
+- /* Rule out self-powered configs for a bus-powered device */
+- if (bus_powered && (c->desc.bmAttributes &
+- USB_CONFIG_ATT_SELFPOWER))
+- continue;
+-#endif
+-
+- /*
+- * The next test may not be as effective as it should be.
+- * Some hubs have errors in their descriptor, claiming
+- * to be self-powered when they are really bus-powered.
+- * We will overestimate the amount of current such hubs
+- * make available for each port.
+- *
+- * This is a fairly benign sort of failure. It won't
+- * cause us to reject configurations that we should have
+- * accepted.
+- */
+-
+- /* Rule out configs that draw too much bus current */
+- if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+- insufficient_power++;
+- continue;
+- }
+-
+- /* If the first config's first interface is COMM/2/0xff
+- * (MSFT RNDIS), rule it out unless Linux has host-side
+- * RNDIS support. */
+- if (i == 0 && desc
+- && desc->bInterfaceClass == USB_CLASS_COMM
+- && desc->bInterfaceSubClass == 2
+- && desc->bInterfaceProtocol == 0xff) {
+-#ifndef CONFIG_USB_NET_RNDIS_HOST
+- continue;
+-#else
+- best = c;
+-#endif
+- }
+-
+- /* From the remaining configs, choose the first one whose
+- * first interface is for a non-vendor-specific class.
+- * Reason: Linux is more likely to have a class driver
+- * than a vendor-specific driver. */
+- else if (udev->descriptor.bDeviceClass !=
+- USB_CLASS_VENDOR_SPEC &&
+- (!desc || desc->bInterfaceClass !=
+- USB_CLASS_VENDOR_SPEC)) {
+- best = c;
+- break;
+- }
+-
+- /* If all the remaining configs are vendor-specific,
+- * choose the first one. */
+- else if (!best)
+- best = c;
+- }
+-
+- if (insufficient_power > 0)
+- dev_info(&udev->dev, "rejected %d configuration%s "
+- "due to insufficient available bus power\n",
+- insufficient_power, plural(insufficient_power));
+-
+- if (best) {
+- i = best->desc.bConfigurationValue;
+- dev_info(&udev->dev,
+- "configuration #%d chosen from %d choice%s\n",
+- i, num_configs, plural(num_configs));
+- } else {
+- i = -1;
+- dev_warn(&udev->dev,
+- "no configuration chosen from %d choice%s\n",
+- num_configs, plural(num_configs));
+- }
+- return i;
++ put_device(&udev->dev);
+ }
+
+ #ifdef DEBUG
+@@ -1304,6 +1188,7 @@ static inline void show_string(struct us
+
+ #ifdef CONFIG_USB_OTG
+ #include "otg_whitelist.h"
++static int __usb_port_suspend(struct usb_device *, int port1);
+ #endif
+
+ /**
+@@ -1328,7 +1213,6 @@ static inline void show_string(struct us
+ int usb_new_device(struct usb_device *udev)
+ {
+ int err;
+- int c;
+
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+@@ -1371,8 +1255,7 @@ int usb_new_device(struct usb_device *ud
+ USB_DT_OTG, (void **) &desc) == 0) {
+ if (desc->bmAttributes & USB_OTG_HNP) {
+ unsigned port1 = udev->portnum;
+- struct usb_device *root = udev->parent;
+-
++
+ dev_info(&udev->dev,
+ "Dual-Role OTG device on %sHNP port\n",
+ (port1 == bus->otg_port)
+@@ -1407,9 +1290,7 @@ int usb_new_device(struct usb_device *ud
+ * (Includes HNP test device.)
+ */
+ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
+- static int __usb_suspend_device(struct usb_device *,
+- int port1);
+- err = __usb_suspend_device(udev, udev->bus->otg_port);
++ err = __usb_port_suspend(udev, udev->bus->otg_port);
+ if (err < 0)
+ dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ }
+@@ -1418,34 +1299,15 @@ int usb_new_device(struct usb_device *ud
+ }
+ #endif
+
+- /* put device-specific files into sysfs */
++ /* Register the device. The device driver is responsible
++ * for adding the device files to usbfs and sysfs and for
++ * configuring the device.
++ */
+ err = device_add (&udev->dev);
+ if (err) {
+ dev_err(&udev->dev, "can't device_add, error %d\n", err);
+ goto fail;
+ }
+- usb_create_sysfs_dev_files (udev);
+-
+- usb_lock_device(udev);
+-
+- /* choose and set the configuration. that registers the interfaces
+- * with the driver core, and lets usb device drivers bind to them.
+- */
+- c = choose_configuration(udev);
+- if (c >= 0) {
+- err = usb_set_configuration(udev, c);
+- if (err) {
+- dev_err(&udev->dev, "can't set config #%d, error %d\n",
+- c, err);
+- /* This need not be fatal. The user can try to
+- * set other configurations. */
+- }
+- }
+-
+- /* USB device state == configured ... usable */
+- usb_notify_add_device(udev);
+-
+- usb_unlock_device(udev);
+
+ return 0;
+
+@@ -1472,6 +1334,18 @@ static int hub_port_status(struct usb_hu
+ return ret;
+ }
+
++
++/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
++static unsigned hub_is_wusb(struct usb_hub *hub)
++{
++ struct usb_hcd *hcd;
++ if (hub->hdev->parent != NULL) /* not a root hub? */
++ return 0;
++ hcd = container_of(hub->hdev->bus, struct usb_hcd, self);
++ return hcd->wireless;
++}
++
++
+ #define PORT_RESET_TRIES 5
+ #define SET_ADDRESS_TRIES 2
+ #define GET_DESCRIPTOR_TRIES 2
+@@ -1512,7 +1386,9 @@ static int hub_port_wait_reset(struct us
+ /* if we`ve finished resetting, then break out of the loop */
+ if (!(portstatus & USB_PORT_STAT_RESET) &&
+ (portstatus & USB_PORT_STAT_ENABLE)) {
+- if (portstatus & USB_PORT_STAT_HIGH_SPEED)
++ if (hub_is_wusb(hub))
++ udev->speed = USB_SPEED_VARIABLE;
++ else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ udev->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ udev->speed = USB_SPEED_LOW;
+@@ -1607,6 +1483,7 @@ static void hub_port_logical_disconnect(
+ kick_khubd(hub);
+ }
+
++#ifdef CONFIG_PM
+
+ #ifdef CONFIG_USB_SUSPEND
+
+@@ -1633,7 +1510,7 @@ static int hub_port_suspend(struct usb_h
+ * NOTE: OTG devices may issue remote wakeup (or SRP) even when
+ * we don't explicitly enable it here.
+ */
+- if (device_may_wakeup(&udev->dev)) {
++ if (udev->do_remote_wakeup) {
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0,
+@@ -1659,7 +1536,8 @@ static int hub_port_suspend(struct usb_h
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ /* device has up to 10 msec to fully suspend */
+- dev_dbg(&udev->dev, "usb suspend\n");
++ dev_dbg(&udev->dev, "usb %ssuspend\n",
++ udev->auto_pm ? "auto-" : "");
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
+ msleep(10);
+ }
+@@ -1684,7 +1562,7 @@ static int hub_port_suspend(struct usb_h
+ * the root hub for their bus goes into global suspend ... so we don't
+ * (falsely) update the device power state to say it suspended.
+ */
+-static int __usb_suspend_device (struct usb_device *udev, int port1)
++static int __usb_port_suspend (struct usb_device *udev, int port1)
+ {
+ int status = 0;
+
+@@ -1692,49 +1570,29 @@ static int __usb_suspend_device (struct
+ if (port1 < 0)
+ return port1;
+
+- if (udev->state == USB_STATE_SUSPENDED
+- || udev->state == USB_STATE_NOTATTACHED) {
+- return 0;
+- }
+-
+- /* all interfaces must already be suspended */
+- if (udev->actconfig) {
+- int i;
+-
+- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+- struct usb_interface *intf;
+-
+- intf = udev->actconfig->interface[i];
+- if (is_active(intf)) {
+- dev_dbg(&intf->dev, "nyet suspended\n");
+- return -EBUSY;
+- }
+- }
+- }
+-
+- /* we only change a device's upstream USB link.
+- * root hubs have no upstream USB link.
++ /* we change the device's upstream USB link,
++ * but root hubs have no upstream USB link.
+ */
+ if (udev->parent)
+ status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
+ udev);
+-
+- if (status == 0)
+- udev->dev.power.power_state = PMSG_SUSPEND;
++ else {
++ dev_dbg(&udev->dev, "usb %ssuspend\n",
++ udev->auto_pm ? "auto-" : "");
++ usb_set_device_state(udev, USB_STATE_SUSPENDED);
++ }
+ return status;
+ }
+
+-#endif
+-
+ /*
+- * usb_suspend_device - suspend a usb device
++ * usb_port_suspend - suspend a usb device's upstream port
+ * @udev: device that's no longer in active use
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * Suspends a USB device that isn't in active use, conserving power.
+ * Devices may wake out of a suspend, if anything important happens,
+ * using the remote wakeup mechanism. They may also be taken out of
+- * suspend by the host, using usb_resume_device(). It's also routine
++ * suspend by the host, using usb_port_resume(). It's also routine
+ * to disconnect devices while they are suspended.
+ *
+ * This only affects the USB hardware for a device; its interfaces
+@@ -1746,17 +1604,9 @@ static int __usb_suspend_device (struct
+ *
+ * Returns 0 on success, else negative errno.
+ */
+-int usb_suspend_device(struct usb_device *udev)
++int usb_port_suspend(struct usb_device *udev)
+ {
+-#ifdef CONFIG_USB_SUSPEND
+- if (udev->state == USB_STATE_NOTATTACHED)
+- return -ENODEV;
+- return __usb_suspend_device(udev, udev->portnum);
+-#else
+- /* NOTE: udev->state unchanged, it's not lying ... */
+- udev->dev.power.power_state = PMSG_SUSPEND;
+- return 0;
+-#endif
++ return __usb_port_suspend(udev, udev->portnum);
+ }
+
+ /*
+@@ -1767,7 +1617,7 @@ int usb_suspend_device(struct usb_device
+ * resume (by host) or remote wakeup (by device) ... now see what changed
+ * in the tree that's rooted at this device.
+ */
+-static int finish_device_resume(struct usb_device *udev)
++static int finish_port_resume(struct usb_device *udev)
+ {
+ int status;
+ u16 devstatus;
+@@ -1783,7 +1633,6 @@ static int finish_device_resume(struct u
+ usb_set_device_state(udev, udev->actconfig
+ ? USB_STATE_CONFIGURED
+ : USB_STATE_ADDRESS);
+- udev->dev.power.power_state = PMSG_ON;
+
+ /* 10.5.4.5 says be sure devices in the tree are still there.
+ * For now let's assume the device didn't go crazy on resume,
+@@ -1798,9 +1647,6 @@ static int finish_device_resume(struct u
+ "gone after usb resume? status %d\n",
+ status);
+ else if (udev->actconfig) {
+- unsigned i;
+- int (*resume)(struct device *);
+-
+ le16_to_cpus(&devstatus);
+ if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
+ && udev->parent) {
+@@ -1811,24 +1657,9 @@ static int finish_device_resume(struct u
+ USB_DEVICE_REMOTE_WAKEUP, 0,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+- if (status) {
++ if (status)
+ dev_dbg(&udev->dev, "disable remote "
+ "wakeup, status %d\n", status);
+- status = 0;
+- }
+- }
+-
+- /* resume interface drivers; if this is a hub, it
+- * may have a child resume event to deal with soon
+- */
+- resume = udev->dev.bus->resume;
+- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+- struct device *dev =
+- &udev->actconfig->interface[i]->dev;
+-
+- down(&dev->sem);
+- (void) resume(dev);
+- up(&dev->sem);
+ }
+ status = 0;
+
+@@ -1839,8 +1670,6 @@ static int finish_device_resume(struct u
+ return status;
+ }
+
+-#ifdef CONFIG_USB_SUSPEND
+-
+ static int
+ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
+ {
+@@ -1848,6 +1677,8 @@ hub_port_resume(struct usb_hub *hub, int
+
+ // dev_dbg(hub->intfdev, "resume port %d\n", port1);
+
++ set_bit(port1, hub->busy_bits);
++
+ /* see 7.1.7.7; affects power usage, but not budgeting */
+ status = clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_SUSPEND);
+@@ -1861,7 +1692,8 @@ hub_port_resume(struct usb_hub *hub, int
+
+ /* drive resume for at least 20 msec */
+ if (udev)
+- dev_dbg(&udev->dev, "RESUME\n");
++ dev_dbg(&udev->dev, "usb %sresume\n",
++ udev->auto_pm ? "auto-" : "");
+ msleep(25);
+
+ #define LIVE_FLAGS ( USB_PORT_STAT_POWER \
+@@ -1891,19 +1723,21 @@ hub_port_resume(struct usb_hub *hub, int
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ if (udev)
+- status = finish_device_resume(udev);
++ status = finish_port_resume(udev);
+ }
+ }
+ if (status < 0)
+ hub_port_logical_disconnect(hub, port1);
+
++ clear_bit(port1, hub->busy_bits);
++ if (!hub->hdev->parent && !hub->busy_bits[0])
++ usb_enable_root_hub_irq(hub->hdev->bus);
++
+ return status;
+ }
+
+-#endif
+-
+ /*
+- * usb_resume_device - re-activate a suspended usb device
++ * usb_port_resume - re-activate a suspended usb device's upstream port
+ * @udev: device to re-activate
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+@@ -1915,36 +1749,24 @@ hub_port_resume(struct usb_hub *hub, int
+ *
+ * Returns 0 on success, else negative errno.
+ */
+-int usb_resume_device(struct usb_device *udev)
++int usb_port_resume(struct usb_device *udev)
+ {
+ int status;
+
+- if (udev->state == USB_STATE_NOTATTACHED)
+- return -ENODEV;
+-
+- /* selective resume of one downstream hub-to-device port */
++ /* we change the device's upstream USB link,
++ * but root hubs have no upstream USB link.
++ */
+ if (udev->parent) {
+-#ifdef CONFIG_USB_SUSPEND
+- if (udev->state == USB_STATE_SUSPENDED) {
+- // NOTE swsusp may bork us, device state being wrong...
+- // NOTE this fails if parent is also suspended...
+- status = hub_port_resume(hdev_to_hub(udev->parent),
+- udev->portnum, udev);
+- } else
+-#endif
+- status = 0;
+- } else
+- status = finish_device_resume(udev);
+- if (status < 0)
+- dev_dbg(&udev->dev, "can't resume, status %d\n",
+- status);
+-
+- /* rebind drivers that had no suspend() */
+- if (status == 0) {
+- usb_unlock_device(udev);
+- bus_rescan_devices(&usb_bus_type);
+- usb_lock_device(udev);
++ // NOTE this fails if parent is also suspended...
++ status = hub_port_resume(hdev_to_hub(udev->parent),
++ udev->portnum, udev);
++ } else {
++ dev_dbg(&udev->dev, "usb %sresume\n",
++ udev->auto_pm ? "auto-" : "");
++ status = finish_port_resume(udev);
+ }
++ if (status < 0)
++ dev_dbg(&udev->dev, "can't resume, status %d\n", status);
+ return status;
+ }
+
+@@ -1952,23 +1774,60 @@ static int remote_wakeup(struct usb_devi
+ {
+ int status = 0;
+
+-#ifdef CONFIG_USB_SUSPEND
++ /* All this just to avoid sending a port-resume message
++ * to the parent hub! */
+
+- /* don't repeat RESUME sequence if this device
+- * was already woken up by some other task
+- */
+ usb_lock_device(udev);
++ usb_pm_lock(udev);
+ if (udev->state == USB_STATE_SUSPENDED) {
+- dev_dbg(&udev->dev, "RESUME (wakeup)\n");
++ dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+- status = finish_device_resume(udev);
++ status = finish_port_resume(udev);
++ if (status == 0)
++ udev->dev.power.power_state.event = PM_EVENT_ON;
+ }
++ usb_pm_unlock(udev);
++
++ if (status == 0)
++ usb_autoresume_device(udev, 0);
+ usb_unlock_device(udev);
+-#endif
+ return status;
+ }
+
++#else /* CONFIG_USB_SUSPEND */
++
++/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
++
++int usb_port_suspend(struct usb_device *udev)
++{
++ return 0;
++}
++
++static inline int
++finish_port_resume(struct usb_device *udev)
++{
++ return 0;
++}
++
++static inline int
++hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
++{
++ return 0;
++}
++
++int usb_port_resume(struct usb_device *udev)
++{
++ return 0;
++}
++
++static inline int remote_wakeup(struct usb_device *udev)
++{
++ return 0;
++}
++
++#endif
++
+ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
+ {
+ struct usb_hub *hub = usb_get_intfdata (intf);
+@@ -1980,13 +1839,17 @@ static int hub_suspend(struct usb_interf
+ struct usb_device *udev;
+
+ udev = hdev->children [port1-1];
+- if (udev && (udev->dev.power.power_state.event
+- == PM_EVENT_ON
++ if (udev && msg.event == PM_EVENT_SUSPEND &&
+ #ifdef CONFIG_USB_SUSPEND
+- || udev->state != USB_STATE_SUSPENDED
++ udev->state != USB_STATE_SUSPENDED
++#else
++ udev->dev.power.power_state.event
++ == PM_EVENT_ON
+ #endif
+- )) {
+- dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
++ ) {
++ if (!hdev->auto_pm)
++ dev_dbg(&intf->dev, "port %d nyet suspended\n",
++ port1);
+ return -EBUSY;
+ }
+ }
+@@ -2035,66 +1898,22 @@ static int hub_resume(struct usb_interfa
+ }
+ }
+
++ /* tell khubd to look for changes on this hub */
+ hub_activate(hub);
+-
+- /* REVISIT: this recursion probably shouldn't exist. Remove
+- * this code sometime, after retesting with different root and
+- * external hubs.
+- */
+-#ifdef CONFIG_USB_SUSPEND
+- {
+- unsigned port1;
+-
+- for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+- struct usb_device *udev;
+- u16 portstat, portchange;
+-
+- udev = hdev->children [port1-1];
+- status = hub_port_status(hub, port1, &portstat, &portchange);
+- if (status == 0) {
+- if (portchange & USB_PORT_STAT_C_SUSPEND) {
+- clear_port_feature(hdev, port1,
+- USB_PORT_FEAT_C_SUSPEND);
+- portchange &= ~USB_PORT_STAT_C_SUSPEND;
+- }
+-
+- /* let khubd handle disconnects etc */
+- if (portchange)
+- continue;
+- }
+-
+- if (!udev || status < 0)
+- continue;
+- usb_lock_device(udev);
+- if (portstat & USB_PORT_STAT_SUSPEND)
+- status = hub_port_resume(hub, port1, udev);
+- else {
+- status = finish_device_resume(udev);
+- if (status < 0) {
+- dev_dbg(&intf->dev, "resume port %d --> %d\n",
+- port1, status);
+- hub_port_logical_disconnect(hub, port1);
+- }
+- }
+- usb_unlock_device(udev);
+- }
+- }
+-#endif
+ return 0;
+ }
+
+-void usb_suspend_root_hub(struct usb_device *hdev)
+-{
+- struct usb_hub *hub = hdev_to_hub(hdev);
++#else /* CONFIG_PM */
+
+- /* This also makes any led blinker stop retriggering. We're called
+- * from irq, so the blinker might still be scheduled. Caller promises
+- * that the root hub status URB will be canceled.
+- */
+- __hub_quiesce(hub);
+- mark_quiesced(to_usb_interface(hub->intfdev));
++static inline int remote_wakeup(struct usb_device *udev)
++{
++ return 0;
+ }
+
++#define hub_suspend NULL
++#define hub_resume NULL
++#endif
++
+ void usb_resume_root_hub(struct usb_device *hdev)
+ {
+ struct usb_hub *hub = hdev_to_hub(hdev);
+@@ -2214,6 +2033,7 @@ hub_port_init (struct usb_hub *hub, stru
+ int i, j, retval;
+ unsigned delay = HUB_SHORT_RESET_TIME;
+ enum usb_device_speed oldspeed = udev->speed;
++ char *speed, *type;
+
+ /* root hub ports have a slightly longer reset period
+ * (from USB 2.0 spec, section 7.1.7.5)
+@@ -2246,8 +2066,13 @@ hub_port_init (struct usb_hub *hub, stru
+
+ /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
+ * it's fixed size except for full speed devices.
++ * For Wireless USB devices, ep0 max packet is always 512 (tho
++ * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
+ */
+ switch (udev->speed) {
++ case USB_SPEED_VARIABLE: /* fixed at 512 */
++ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
++ break;
+ case USB_SPEED_HIGH: /* fixed at 64 */
+ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
+ break;
+@@ -2265,17 +2090,21 @@ hub_port_init (struct usb_hub *hub, stru
+ goto fail;
+ }
+
++ type = "";
++ switch (udev->speed) {
++ case USB_SPEED_LOW: speed = "low"; break;
++ case USB_SPEED_FULL: speed = "full"; break;
++ case USB_SPEED_HIGH: speed = "high"; break;
++ case USB_SPEED_VARIABLE:
++ speed = "variable";
++ type = "Wireless ";
++ break;
++ default: speed = "?"; break;
++ }
+ dev_info (&udev->dev,
+- "%s %s speed USB device using %s and address %d\n",
+- (udev->config) ? "reset" : "new",
+- ({ char *speed; switch (udev->speed) {
+- case USB_SPEED_LOW: speed = "low"; break;
+- case USB_SPEED_FULL: speed = "full"; break;
+- case USB_SPEED_HIGH: speed = "high"; break;
+- default: speed = "?"; break;
+- }; speed;}),
+- udev->bus->controller->driver->name,
+- udev->devnum);
++ "%s %s speed %sUSB device using %s and address %d\n",
++ (udev->config) ? "reset" : "new", speed, type,
++ udev->bus->controller->driver->name, udev->devnum);
+
+ /* Set up TT records, if needed */
+ if (hdev->tt) {
+@@ -2317,6 +2146,8 @@ hub_port_init (struct usb_hub *hub, stru
+ * down tremendously by NAKing the unexpectedly
+ * early status stage. Also, retry on all errors;
+ * some devices are flakey.
++ * 255 is for WUSB devices, we actually need to use 512.
++ * WUSB1.0[4.8.1].
+ */
+ for (j = 0; j < 3; ++j) {
+ buf->bMaxPacketSize0 = 0;
+@@ -2326,7 +2157,7 @@ hub_port_init (struct usb_hub *hub, stru
+ buf, GET_DESCRIPTOR_BUFSIZE,
+ (i ? USB_CTRL_GET_TIMEOUT : 1000));
+ switch (buf->bMaxPacketSize0) {
+- case 8: case 16: case 32: case 64:
++ case 8: case 16: case 32: case 64: case 255:
+ if (buf->bDescriptorType ==
+ USB_DT_DEVICE) {
+ r = 0;
+@@ -2400,7 +2231,8 @@ hub_port_init (struct usb_hub *hub, stru
+ if (retval)
+ goto fail;
+
+- i = udev->descriptor.bMaxPacketSize0;
++ i = udev->descriptor.bMaxPacketSize0 == 0xff?
++ 512 : udev->descriptor.bMaxPacketSize0;
+ if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
+ if (udev->speed != USB_SPEED_FULL ||
+ !(i == 8 || i == 16 || i == 32 || i == 64)) {
+@@ -2585,6 +2417,7 @@ static void hub_port_connect_change(stru
+ usb_set_device_state(udev, USB_STATE_POWERED);
+ udev->speed = USB_SPEED_UNKNOWN;
+ udev->bus_mA = hub->mA_per_port;
++ udev->level = hdev->level + 1;
+
+ /* set the address */
+ choose_address(udev);
+@@ -2736,17 +2569,6 @@ static void hub_events(void)
+ usb_get_intf(intf);
+ spin_unlock_irq(&hub_event_lock);
+
+- /* Is this is a root hub wanting to reactivate the downstream
+- * ports? If so, be sure the interface resumes even if its
+- * stub "device" node was never suspended.
+- */
+- if (i) {
+- dpm_runtime_resume(&hdev->dev);
+- dpm_runtime_resume(&intf->dev);
+- usb_put_intf(intf);
+- continue;
+- }
+-
+ /* Lock the device, then check to see if we were
+ * disconnected while waiting for the lock to succeed. */
+ if (locktree(hdev) < 0) {
+@@ -2763,6 +2585,13 @@ static void hub_events(void)
+ goto loop;
+ }
+
++ /* Is this is a root hub wanting to reactivate the downstream
++ * ports? If so, be sure the interface resumes even if its
++ * stub "device" node was never suspended.
++ */
++ if (i)
++ usb_autoresume_device(hdev, 0);
++
+ /* If this is an inactive or suspended hub, do nothing */
+ if (hub->quiescing)
+ goto loop;
+@@ -2900,7 +2729,7 @@ static void hub_events(void)
+
+ /* If this is a root hub, tell the HCD it's okay to
+ * re-enable port-change interrupts now. */
+- if (!hdev->parent)
++ if (!hdev->parent && !hub->busy_bits[0])
+ usb_enable_root_hub_irq(hdev->bus);
+
+ loop:
+@@ -3075,6 +2904,9 @@ int usb_reset_device(struct usb_device *
+ break;
+ }
+ clear_bit(port1, parent_hub->busy_bits);
++ if (!parent_hdev->parent && !parent_hub->busy_bits[0])
++ usb_enable_root_hub_irq(parent_hdev->bus);
++
+ if (ret < 0)
+ goto re_enumerate;
+
+@@ -3128,6 +2960,7 @@ re_enumerate:
+ hub_port_logical_disconnect(parent_hub, port1);
+ return -ENODEV;
+ }
++EXPORT_SYMBOL(usb_reset_device);
+
+ /**
+ * usb_reset_composite_device - warn interface drivers and perform a USB port reset
+@@ -3163,6 +2996,9 @@ int usb_reset_composite_device(struct us
+ return -EINVAL;
+ }
+
++ /* Prevent autosuspend during the reset */
++ usb_autoresume_device(udev, 1);
++
+ if (iface && iface->condition != USB_INTERFACE_BINDING)
+ iface = NULL;
+
+@@ -3204,5 +3040,7 @@ int usb_reset_composite_device(struct us
+ }
+ }
+
++ usb_autosuspend_device(udev, 1);
+ return ret;
+ }
++EXPORT_SYMBOL(usb_reset_composite_device);
+diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
+index 29d5f45..0f8e82a 100644
+--- a/drivers/usb/core/hub.h
++++ b/drivers/usb/core/hub.h
+@@ -212,7 +212,8 @@ struct usb_hub {
+ unsigned long event_bits[1]; /* status change bitmask */
+ unsigned long change_bits[1]; /* ports with logical connect
+ status change */
+- unsigned long busy_bits[1]; /* ports being reset */
++ unsigned long busy_bits[1]; /* ports being reset or
++ resumed */
+ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
+ #error event_bits[] is too short!
+ #endif
+diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
+index 3182c22..b5d6a79 100644
+--- a/drivers/usb/core/inode.c
++++ b/drivers/usb/core/inode.c
+@@ -44,7 +44,7 @@
+ #include "hcd.h"
+
+ static struct super_operations usbfs_ops;
+-static struct file_operations default_file_operations;
++static const struct file_operations default_file_operations;
+ static struct vfsmount *usbfs_mount;
+ static int usbfs_mount_count; /* = 0 */
+ static int ignore_mount = 0;
+@@ -249,7 +249,6 @@ static struct inode *usbfs_get_inode (st
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+@@ -264,7 +263,7 @@ static struct inode *usbfs_get_inode (st
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ break;
+ }
+ }
+@@ -296,7 +295,7 @@ static int usbfs_mkdir (struct inode *di
+ mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+ res = usbfs_mknod (dir, dentry, mode, 0);
+ if (!res)
+- dir->i_nlink++;
++ inc_nlink(dir);
+ return res;
+ }
+
+@@ -333,7 +332,7 @@ static int usbfs_unlink (struct inode *d
+ {
+ struct inode *inode = dentry->d_inode;
+ mutex_lock(&inode->i_mutex);
+- dentry->d_inode->i_nlink--;
++ drop_nlink(dentry->d_inode);
+ dput(dentry);
+ mutex_unlock(&inode->i_mutex);
+ d_delete(dentry);
+@@ -348,10 +347,11 @@ static int usbfs_rmdir(struct inode *dir
+ mutex_lock(&inode->i_mutex);
+ dentry_unhash(dentry);
+ if (usbfs_empty(dentry)) {
+- dentry->d_inode->i_nlink -= 2;
++ drop_nlink(dentry->d_inode);
++ drop_nlink(dentry->d_inode);
+ dput(dentry);
+ inode->i_flags |= S_DEAD;
+- dir->i_nlink--;
++ drop_nlink(dir);
+ error = 0;
+ }
+ mutex_unlock(&inode->i_mutex);
+@@ -402,13 +402,13 @@ static loff_t default_file_lseek (struct
+
+ static int default_open (struct inode *inode, struct file *file)
+ {
+- if (inode->u.generic_ip)
+- file->private_data = inode->u.generic_ip;
++ if (inode->i_private)
++ file->private_data = inode->i_private;
+
+ return 0;
+ }
+
+-static struct file_operations default_file_operations = {
++static const struct file_operations default_file_operations = {
+ .read = default_read_file,
+ .write = default_write_file,
+ .open = default_open,
+@@ -495,7 +495,7 @@ static int fs_create_by_name (const char
+
+ static struct dentry *fs_create_file (const char *name, mode_t mode,
+ struct dentry *parent, void *data,
+- struct file_operations *fops,
++ const struct file_operations *fops,
+ uid_t uid, gid_t gid)
+ {
+ struct dentry *dentry;
+@@ -509,7 +509,7 @@ static struct dentry *fs_create_file (co
+ } else {
+ if (dentry->d_inode) {
+ if (data)
+- dentry->d_inode->u.generic_ip = data;
++ dentry->d_inode->i_private = data;
+ if (fops)
+ dentry->d_inode->i_fop = fops;
+ dentry->d_inode->i_uid = uid;
+@@ -699,7 +699,7 @@ static void usbfs_remove_device(struct u
+ sinfo.si_errno = EPIPE;
+ sinfo.si_code = SI_ASYNCIO;
+ sinfo.si_addr = ds->disccontext;
+- kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
++ kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
+ }
+ }
+ }
+diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
+index 4cc8d3e..fccd195 100644
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -17,65 +17,50 @@
+ #include "hcd.h" /* for usbcore internals */
+ #include "usb.h"
+
+-static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
++static void usb_api_blocking_completion(struct urb *urb)
+ {
+ complete((struct completion *)urb->context);
+ }
+
+
+-static void timeout_kill(unsigned long data)
+-{
+- struct urb *urb = (struct urb *) data;
+-
+- usb_unlink_urb(urb);
+-}
+-
+-// Starts urb and waits for completion or timeout
+-// note that this call is NOT interruptible, while
+-// many device driver i/o requests should be interruptible
+-static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
++/*
++ * Starts urb and waits for completion or timeout. Note that this call
++ * is NOT interruptible. Many device driver i/o requests should be
++ * interruptible and therefore these drivers should implement their
++ * own interruptible routines.
++ */
++static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
+ {
+- struct completion done;
+- struct timer_list timer;
+- int status;
++ struct completion done;
++ unsigned long expire;
++ int status;
+
+ init_completion(&done);
+ urb->context = &done;
+ urb->actual_length = 0;
+ status = usb_submit_urb(urb, GFP_NOIO);
+-
+- if (status == 0) {
+- if (timeout > 0) {
+- init_timer(&timer);
+- timer.expires = jiffies + msecs_to_jiffies(timeout);
+- timer.data = (unsigned long)urb;
+- timer.function = timeout_kill;
+- /* grr. timeout _should_ include submit delays. */
+- add_timer(&timer);
+- }
+- wait_for_completion(&done);
++ if (unlikely(status))
++ goto out;
++
++ expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
++ if (!wait_for_completion_timeout(&done, expire)) {
++
++ dev_dbg(&urb->dev->dev,
++ "%s timed out on ep%d%s len=%d/%d\n",
++ current->comm,
++ usb_pipeendpoint(urb->pipe),
++ usb_pipein(urb->pipe) ? "in" : "out",
++ urb->actual_length,
++ urb->transfer_buffer_length);
++
++ usb_kill_urb(urb);
++ status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
++ } else
+ status = urb->status;
+- /* note: HCDs return ETIMEDOUT for other reasons too */
+- if (status == -ECONNRESET) {
+- dev_dbg(&urb->dev->dev,
+- "%s timed out on ep%d%s len=%d/%d\n",
+- current->comm,
+- usb_pipeendpoint(urb->pipe),
+- usb_pipein(urb->pipe) ? "in" : "out",
+- urb->actual_length,
+- urb->transfer_buffer_length
+- );
+- if (urb->actual_length > 0)
+- status = 0;
+- else
+- status = -ETIMEDOUT;
+- }
+- if (timeout > 0)
+- del_timer_sync(&timer);
+- }
+-
++out:
+ if (actual_length)
+ *actual_length = urb->actual_length;
++
+ usb_free_urb(urb);
+ return status;
+ }
+@@ -261,9 +246,9 @@ static void sg_clean (struct usb_sg_requ
+ io->dev = NULL;
+ }
+
+-static void sg_complete (struct urb *urb, struct pt_regs *regs)
++static void sg_complete (struct urb *urb)
+ {
+- struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
++ struct usb_sg_request *io = urb->context;
+
+ spin_lock (&io->lock);
+
+@@ -999,8 +984,8 @@ void usb_disable_endpoint(struct usb_dev
+ ep = dev->ep_in[epnum];
+ dev->ep_in[epnum] = NULL;
+ }
+- if (ep && dev->bus && dev->bus->op && dev->bus->op->disable)
+- dev->bus->op->disable(dev, ep);
++ if (ep && dev->bus)
++ usb_hcd_endpoint_disable(dev, ep);
+ }
+
+ /**
+@@ -1381,9 +1366,6 @@ int usb_set_configuration(struct usb_dev
+ if (cp && configuration == 0)
+ dev_warn(&dev->dev, "config 0 descriptor??\n");
+
+- if (dev->state == USB_STATE_SUSPENDED)
+- return -EHOSTUNREACH;
+-
+ /* Allocate memory for new interfaces before doing anything else,
+ * so that if we run out then nothing will have changed. */
+ n = nintf = 0;
+@@ -1418,6 +1400,11 @@ free_interfaces:
+ configuration, -i);
+ }
+
++ /* Wake up the device so we can send it the Set-Config request */
++ ret = usb_autoresume_device(dev, 1);
++ if (ret)
++ goto free_interfaces;
++
+ /* if it's already configured, clear out old state first.
+ * getting rid of old interfaces means unbinding their drivers.
+ */
+@@ -1437,6 +1424,7 @@ free_interfaces:
+ dev->actconfig = cp;
+ if (!cp) {
+ usb_set_device_state(dev, USB_STATE_ADDRESS);
++ usb_autosuspend_device(dev, 1);
+ goto free_interfaces;
+ }
+ usb_set_device_state(dev, USB_STATE_CONFIGURED);
+@@ -1505,8 +1493,68 @@ free_interfaces:
+ usb_create_sysfs_intf_files (intf);
+ }
+
++ usb_autosuspend_device(dev, 1);
++ return 0;
++}
++
++struct set_config_request {
++ struct usb_device *udev;
++ int config;
++ struct work_struct work;
++};
++
++/* Worker routine for usb_driver_set_configuration() */
++static void driver_set_config_work(void *_req)
++{
++ struct set_config_request *req = _req;
++
++ usb_lock_device(req->udev);
++ usb_set_configuration(req->udev, req->config);
++ usb_unlock_device(req->udev);
++ usb_put_dev(req->udev);
++ kfree(req);
++}
++
++/**
++ * usb_driver_set_configuration - Provide a way for drivers to change device configurations
++ * @udev: the device whose configuration is being updated
++ * @config: the configuration being chosen.
++ * Context: In process context, must be able to sleep
++ *
++ * Device interface drivers are not allowed to change device configurations.
++ * This is because changing configurations will destroy the interface the
++ * driver is bound to and create new ones; it would be like a floppy-disk
++ * driver telling the computer to replace the floppy-disk drive with a
++ * tape drive!
++ *
++ * Still, in certain specialized circumstances the need may arise. This
++ * routine gets around the normal restrictions by using a work thread to
++ * submit the change-config request.
++ *
++ * Returns 0 if the request was succesfully queued, error code otherwise.
++ * The caller has no way to know whether the queued request will eventually
++ * succeed.
++ */
++int usb_driver_set_configuration(struct usb_device *udev, int config)
++{
++ struct set_config_request *req;
++
++ req = kmalloc(sizeof(*req), GFP_KERNEL);
++ if (!req)
++ return -ENOMEM;
++ req->udev = udev;
++ req->config = config;
++ INIT_WORK(&req->work, driver_set_config_work, req);
++
++ usb_get_dev(udev);
++ if (!schedule_work(&req->work)) {
++ usb_put_dev(udev);
++ kfree(req);
++ return -EINVAL;
++ }
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
+
+ // synchronous request completion model
+ EXPORT_SYMBOL(usb_control_msg);
+diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
+index b042676..6b36897 100644
+--- a/drivers/usb/core/notify.c
++++ b/drivers/usb/core/notify.c
+@@ -50,8 +50,11 @@ void usb_notify_add_device(struct usb_de
+
+ void usb_notify_remove_device(struct usb_device *udev)
+ {
++ /* Protect against simultaneous usbfs open */
++ mutex_lock(&usbfs_mutex);
+ blocking_notifier_call_chain(&usb_notifier_list,
+ USB_DEVICE_REMOVE, udev);
++ mutex_unlock(&usbfs_mutex);
+ }
+
+ void usb_notify_add_bus(struct usb_bus *ubus)
+diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
+index dec973a..55d8f57 100644
+--- a/drivers/usb/core/sysfs.c
++++ b/drivers/usb/core/sysfs.c
+@@ -60,7 +60,7 @@ static ssize_t
+ set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+- struct usb_device *udev = udev = to_usb_device (dev);
++ struct usb_device *udev = to_usb_device (dev);
+ int config, value;
+
+ if (sscanf (buf, "%u", &config) != 1 || config > 255)
+@@ -186,6 +186,7 @@ usb_descriptor_attr (bMaxPacketSize0, "%
+
+ static struct attribute *dev_attrs[] = {
+ /* current configuration's attributes */
++ &dev_attr_configuration.attr,
+ &dev_attr_bNumInterfaces.attr,
+ &dev_attr_bConfigurationValue.attr,
+ &dev_attr_bmAttributes.attr,
+@@ -209,20 +210,40 @@ static struct attribute_group dev_attr_g
+ .attrs = dev_attrs,
+ };
+
+-void usb_create_sysfs_dev_files (struct usb_device *udev)
++int usb_create_sysfs_dev_files(struct usb_device *udev)
+ {
+ struct device *dev = &udev->dev;
++ int retval;
+
+- sysfs_create_group(&dev->kobj, &dev_attr_grp);
++ retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
++ if (retval)
++ return retval;
+
+- if (udev->manufacturer)
+- device_create_file (dev, &dev_attr_manufacturer);
+- if (udev->product)
+- device_create_file (dev, &dev_attr_product);
+- if (udev->serial)
+- device_create_file (dev, &dev_attr_serial);
+- device_create_file (dev, &dev_attr_configuration);
+- usb_create_ep_files(dev, &udev->ep0, udev);
++ if (udev->manufacturer) {
++ retval = device_create_file (dev, &dev_attr_manufacturer);
++ if (retval)
++ goto error;
++ }
++ if (udev->product) {
++ retval = device_create_file (dev, &dev_attr_product);
++ if (retval)
++ goto error;
++ }
++ if (udev->serial) {
++ retval = device_create_file (dev, &dev_attr_serial);
++ if (retval)
++ goto error;
++ }
++ retval = usb_create_ep_files(dev, &udev->ep0, udev);
++ if (retval)
++ goto error;
++ return 0;
++error:
++ usb_remove_ep_files(&udev->ep0);
++ device_remove_file(dev, &dev_attr_manufacturer);
++ device_remove_file(dev, &dev_attr_product);
++ device_remove_file(dev, &dev_attr_serial);
++ return retval;
+ }
+
+ void usb_remove_sysfs_dev_files (struct usb_device *udev)
+@@ -238,7 +259,6 @@ void usb_remove_sysfs_dev_files (struct
+ device_remove_file(dev, &dev_attr_product);
+ if (udev->serial)
+ device_remove_file(dev, &dev_attr_serial);
+- device_remove_file (dev, &dev_attr_configuration);
+ }
+
+ /* Interface fields */
+@@ -340,18 +360,28 @@ static inline void usb_remove_intf_ep_fi
+ usb_remove_ep_files(&iface_desc->endpoint[i]);
+ }
+
+-void usb_create_sysfs_intf_files (struct usb_interface *intf)
++int usb_create_sysfs_intf_files(struct usb_interface *intf)
+ {
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
++ int retval;
+
+- sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
++ retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
++ if (retval)
++ goto error;
+
+ if (alt->string == NULL)
+ alt->string = usb_cache_string(udev, alt->desc.iInterface);
+ if (alt->string)
+- device_create_file(&intf->dev, &dev_attr_interface);
++ retval = device_create_file(&intf->dev, &dev_attr_interface);
+ usb_create_intf_ep_files(intf, udev);
++ return 0;
++error:
++ if (alt->string)
++ device_remove_file(&intf->dev, &dev_attr_interface);
++ sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
++ usb_remove_intf_ep_files(intf);
++ return retval;
+ }
+
+ void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
+index 9864988..9801d08 100644
+--- a/drivers/usb/core/urb.c
++++ b/drivers/usb/core/urb.c
+@@ -57,7 +57,7 @@ struct urb *usb_alloc_urb(int iso_packet
+ {
+ struct urb *urb;
+
+- urb = (struct urb *)kmalloc(sizeof(struct urb) +
++ urb = kmalloc(sizeof(struct urb) +
+ iso_packets * sizeof(struct usb_iso_packet_descriptor),
+ mem_flags);
+ if (!urb) {
+@@ -221,7 +221,6 @@ int usb_submit_urb(struct urb *urb, gfp_
+ {
+ int pipe, temp, max;
+ struct usb_device *dev;
+- struct usb_operations *op;
+ int is_out;
+
+ if (!urb || urb->hcpriv || !urb->complete)
+@@ -233,8 +232,6 @@ int usb_submit_urb(struct urb *urb, gfp_
+ if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
+ || dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+- if (!(op = dev->bus->op) || !op->submit_urb)
+- return -ENODEV;
+
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+@@ -376,7 +373,7 @@ int usb_submit_urb(struct urb *urb, gfp_
+ urb->interval = temp;
+ }
+
+- return op->submit_urb (urb, mem_flags);
++ return usb_hcd_submit_urb (urb, mem_flags);
+ }
+
+ /*-------------------------------------------------------------------*/
+@@ -440,9 +437,9 @@ int usb_unlink_urb(struct urb *urb)
+ {
+ if (!urb)
+ return -EINVAL;
+- if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
++ if (!(urb->dev && urb->dev->bus))
+ return -ENODEV;
+- return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);
++ return usb_hcd_unlink_urb(urb, -ECONNRESET);
+ }
+
+ /**
+@@ -468,13 +465,13 @@ int usb_unlink_urb(struct urb *urb)
+ void usb_kill_urb(struct urb *urb)
+ {
+ might_sleep();
+- if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op))
++ if (!(urb && urb->dev && urb->dev->bus))
+ return;
+ spin_lock_irq(&urb->lock);
+ ++urb->reject;
+ spin_unlock_irq(&urb->lock);
+
+- urb->dev->bus->op->unlink_urb(urb, -ENOENT);
++ usb_hcd_unlink_urb(urb, -ENOENT);
+ wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
+
+ spin_lock_irq(&urb->lock);
+diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
+index 184c246..467cb02 100644
+--- a/drivers/usb/core/usb.c
++++ b/drivers/usb/core/usb.c
+@@ -1,5 +1,5 @@
+ /*
+- * drivers/usb/usb.c
++ * drivers/usb/core/usb.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+@@ -33,6 +33,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/usb.h>
+ #include <linux/mutex.h>
++#include <linux/workqueue.h>
+
+ #include <asm/io.h>
+ #include <asm/scatterlist.h>
+@@ -47,6 +48,8 @@ const char *usbcore_name = "usbcore";
+
+ static int nousb; /* Disable USB when built into kernel image */
+
++struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
++
+
+ /**
+ * usb_ifnum_to_if - get the interface object with a given interface number
+@@ -67,7 +70,8 @@ static int nousb; /* Disable USB when bu
+ * Don't call this function unless you are bound to one of the interfaces
+ * on this device or you have locked the device!
+ */
+-struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
++struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
++ unsigned ifnum)
+ {
+ struct usb_host_config *config = dev->actconfig;
+ int i;
+@@ -100,8 +104,8 @@ struct usb_interface *usb_ifnum_to_if(st
+ * Don't call this function unless you are bound to the intf interface
+ * or you have locked the device!
+ */
+-struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
+- unsigned int altnum)
++struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
++ unsigned int altnum)
+ {
+ int i;
+
+@@ -112,87 +116,6 @@ struct usb_host_interface *usb_altnum_to
+ return NULL;
+ }
+
+-/**
+- * usb_driver_claim_interface - bind a driver to an interface
+- * @driver: the driver to be bound
+- * @iface: the interface to which it will be bound; must be in the
+- * usb device's active configuration
+- * @priv: driver data associated with that interface
+- *
+- * This is used by usb device drivers that need to claim more than one
+- * interface on a device when probing (audio and acm are current examples).
+- * No device driver should directly modify internal usb_interface or
+- * usb_device structure members.
+- *
+- * Few drivers should need to use this routine, since the most natural
+- * way to bind to an interface is to return the private data from
+- * the driver's probe() method.
+- *
+- * Callers must own the device lock and the driver model's usb_bus_type.subsys
+- * writelock. So driver probe() entries don't need extra locking,
+- * but other call contexts may need to explicitly claim those locks.
+- */
+-int usb_driver_claim_interface(struct usb_driver *driver,
+- struct usb_interface *iface, void* priv)
+-{
+- struct device *dev = &iface->dev;
+-
+- if (dev->driver)
+- return -EBUSY;
+-
+- dev->driver = &driver->driver;
+- usb_set_intfdata(iface, priv);
+- iface->condition = USB_INTERFACE_BOUND;
+- mark_active(iface);
+-
+- /* if interface was already added, bind now; else let
+- * the future device_add() bind it, bypassing probe()
+- */
+- if (device_is_registered(dev))
+- device_bind_driver(dev);
+-
+- return 0;
+-}
+-
+-/**
+- * usb_driver_release_interface - unbind a driver from an interface
+- * @driver: the driver to be unbound
+- * @iface: the interface from which it will be unbound
+- *
+- * This can be used by drivers to release an interface without waiting
+- * for their disconnect() methods to be called. In typical cases this
+- * also causes the driver disconnect() method to be called.
+- *
+- * This call is synchronous, and may not be used in an interrupt context.
+- * Callers must own the device lock and the driver model's usb_bus_type.subsys
+- * writelock. So driver disconnect() entries don't need extra locking,
+- * but other call contexts may need to explicitly claim those locks.
+- */
+-void usb_driver_release_interface(struct usb_driver *driver,
+- struct usb_interface *iface)
+-{
+- struct device *dev = &iface->dev;
+-
+- /* this should never happen, don't release something that's not ours */
+- if (!dev->driver || dev->driver != &driver->driver)
+- return;
+-
+- /* don't release from within disconnect() */
+- if (iface->condition != USB_INTERFACE_BOUND)
+- return;
+-
+- /* don't release if the interface hasn't been added yet */
+- if (device_is_registered(dev)) {
+- iface->condition = USB_INTERFACE_UNBINDING;
+- device_release_driver(dev);
+- }
+-
+- dev->driver = NULL;
+- usb_set_intfdata(iface, NULL);
+- iface->condition = USB_INTERFACE_UNBOUND;
+- mark_quiesced(iface);
+-}
+-
+ struct find_interface_arg {
+ int minor;
+ struct usb_interface *interface;
+@@ -204,7 +127,7 @@ static int __find_interface(struct devic
+ struct usb_interface *intf;
+
+ /* can't look at usb devices, only interfaces */
+- if (dev->driver == &usb_generic_driver)
++ if (is_usb_device(dev))
+ return 0;
+
+ intf = to_usb_interface(dev);
+@@ -227,147 +150,82 @@ static int __find_interface(struct devic
+ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
+ {
+ struct find_interface_arg argb;
++ int retval;
+
+ argb.minor = minor;
+ argb.interface = NULL;
+- driver_for_each_device(&drv->driver, NULL, &argb, __find_interface);
++ /* eat the error, it will be in argb.interface */
++ retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb,
++ __find_interface);
+ return argb.interface;
+ }
+
+-#ifdef CONFIG_HOTPLUG
+-
+-/*
+- * This sends an uevent to userspace, typically helping to load driver
+- * or other modules, configure the device, and more. Drivers can provide
+- * a MODULE_DEVICE_TABLE to help with module loading subtasks.
++/**
++ * usb_release_dev - free a usb device structure when all users of it are finished.
++ * @dev: device that's been disconnected
+ *
+- * We're called either from khubd (the typical case) or from root hub
+- * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
+- * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
+- * device (and this configuration!) are still present.
++ * Will be called only by the device core when all users of this usb device are
++ * done.
+ */
+-static int usb_uevent(struct device *dev, char **envp, int num_envp,
+- char *buffer, int buffer_size)
++static void usb_release_dev(struct device *dev)
+ {
+- struct usb_interface *intf;
+- struct usb_device *usb_dev;
+- struct usb_host_interface *alt;
+- int i = 0;
+- int length = 0;
+-
+- if (!dev)
+- return -ENODEV;
+-
+- /* driver is often null here; dev_dbg() would oops */
+- pr_debug ("usb %s: uevent\n", dev->bus_id);
+-
+- /* Must check driver_data here, as on remove driver is always NULL */
+- if ((dev->driver == &usb_generic_driver) ||
+- (dev->driver_data == &usb_generic_driver_data))
+- return 0;
+-
+- intf = to_usb_interface(dev);
+- usb_dev = interface_to_usbdev (intf);
+- alt = intf->cur_altsetting;
++ struct usb_device *udev;
+
+- if (usb_dev->devnum < 0) {
+- pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+- return -ENODEV;
+- }
+- if (!usb_dev->bus) {
+- pr_debug ("usb %s: bus removed?\n", dev->bus_id);
+- return -ENODEV;
+- }
++ udev = to_usb_device(dev);
+
+-#ifdef CONFIG_USB_DEVICEFS
+- /* If this is available, userspace programs can directly read
+- * all the device descriptors we don't tell them about. Or
+- * even act as usermode drivers.
+- *
+- * FIXME reduce hardwired intelligence here
+- */
+- if (add_uevent_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "DEVICE=/proc/bus/usb/%03d/%03d",
+- usb_dev->bus->busnum, usb_dev->devnum))
+- return -ENOMEM;
++#ifdef CONFIG_USB_SUSPEND
++ cancel_delayed_work(&udev->autosuspend);
++ flush_workqueue(ksuspend_usb_wq);
+ #endif
++ usb_destroy_configuration(udev);
++ usb_put_hcd(bus_to_hcd(udev->bus));
++ kfree(udev->product);
++ kfree(udev->manufacturer);
++ kfree(udev->serial);
++ kfree(udev);
++}
+
+- /* per-device configurations are common */
+- if (add_uevent_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "PRODUCT=%x/%x/%x",
+- le16_to_cpu(usb_dev->descriptor.idVendor),
+- le16_to_cpu(usb_dev->descriptor.idProduct),
+- le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+- return -ENOMEM;
++#ifdef CONFIG_PM
+
+- /* class-based driver binding models */
+- if (add_uevent_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "TYPE=%d/%d/%d",
+- usb_dev->descriptor.bDeviceClass,
+- usb_dev->descriptor.bDeviceSubClass,
+- usb_dev->descriptor.bDeviceProtocol))
++static int ksuspend_usb_init(void)
++{
++ ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
++ if (!ksuspend_usb_wq)
+ return -ENOMEM;
++ return 0;
++}
+
+- if (add_uevent_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "INTERFACE=%d/%d/%d",
+- alt->desc.bInterfaceClass,
+- alt->desc.bInterfaceSubClass,
+- alt->desc.bInterfaceProtocol))
+- return -ENOMEM;
++static void ksuspend_usb_cleanup(void)
++{
++ destroy_workqueue(ksuspend_usb_wq);
++}
+
+- if (add_uevent_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+- le16_to_cpu(usb_dev->descriptor.idVendor),
+- le16_to_cpu(usb_dev->descriptor.idProduct),
+- le16_to_cpu(usb_dev->descriptor.bcdDevice),
+- usb_dev->descriptor.bDeviceClass,
+- usb_dev->descriptor.bDeviceSubClass,
+- usb_dev->descriptor.bDeviceProtocol,
+- alt->desc.bInterfaceClass,
+- alt->desc.bInterfaceSubClass,
+- alt->desc.bInterfaceProtocol))
+- return -ENOMEM;
++#else
+
+- envp[i] = NULL;
++#define ksuspend_usb_init() 0
++#define ksuspend_usb_cleanup() do {} while (0)
+
+- return 0;
+-}
++#endif
+
+-#else
++#ifdef CONFIG_USB_SUSPEND
+
+-static int usb_uevent(struct device *dev, char **envp,
+- int num_envp, char *buffer, int buffer_size)
++/* usb_autosuspend_work - callback routine to autosuspend a USB device */
++static void usb_autosuspend_work(void *_udev)
+ {
+- return -ENODEV;
+-}
++ struct usb_device *udev = _udev;
+
+-#endif /* CONFIG_HOTPLUG */
++ usb_pm_lock(udev);
++ udev->auto_pm = 1;
++ usb_suspend_both(udev, PMSG_SUSPEND);
++ usb_pm_unlock(udev);
++}
+
+-/**
+- * usb_release_dev - free a usb device structure when all users of it are finished.
+- * @dev: device that's been disconnected
+- *
+- * Will be called only by the device core when all users of this usb device are
+- * done.
+- */
+-static void usb_release_dev(struct device *dev)
+-{
+- struct usb_device *udev;
++#else
+
+- udev = to_usb_device(dev);
++static void usb_autosuspend_work(void *_udev)
++{}
+
+- usb_destroy_configuration(udev);
+- usb_bus_put(udev->bus);
+- kfree(udev->product);
+- kfree(udev->manufacturer);
+- kfree(udev->serial);
+- kfree(udev);
+-}
++#endif
+
+ /**
+ * usb_alloc_dev - usb device constructor (usbcore-internal)
+@@ -390,8 +248,7 @@ usb_alloc_dev(struct usb_device *parent,
+ if (!dev)
+ return NULL;
+
+- bus = usb_bus_get(bus);
+- if (!bus) {
++ if (!usb_get_hcd(bus_to_hcd(bus))) {
+ kfree(dev);
+ return NULL;
+ }
+@@ -399,11 +256,12 @@ usb_alloc_dev(struct usb_device *parent,
+ device_initialize(&dev->dev);
+ dev->dev.bus = &usb_bus_type;
+ dev->dev.dma_mask = bus->controller->dma_mask;
+- dev->dev.driver_data = &usb_generic_driver_data;
+- dev->dev.driver = &usb_generic_driver;
+ dev->dev.release = usb_release_dev;
+ dev->state = USB_STATE_ATTACHED;
+
++ /* This magic assignment distinguishes devices from interfaces */
++ dev->dev.platform_data = &usb_generic_driver;
++
+ INIT_LIST_HEAD(&dev->ep0.urb_list);
+ dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
+ dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
+@@ -444,6 +302,10 @@ usb_alloc_dev(struct usb_device *parent,
+ dev->parent = parent;
+ INIT_LIST_HEAD(&dev->filelist);
+
++#ifdef CONFIG_PM
++ mutex_init(&dev->pm_mutex);
++ INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev);
++#endif
+ return dev;
+ }
+
+@@ -549,7 +411,7 @@ void usb_put_intf(struct usb_interface *
+ * case the driver already owns the device lock.)
+ */
+ int usb_lock_device_for_reset(struct usb_device *udev,
+- struct usb_interface *iface)
++ const struct usb_interface *iface)
+ {
+ unsigned long jiffies_expire = jiffies + HZ;
+
+@@ -672,7 +534,139 @@ exit:
+ */
+ int usb_get_current_frame_number(struct usb_device *dev)
+ {
+- return dev->bus->op->get_frame_number (dev);
++ return usb_hcd_get_frame_number (dev);
++}
++
++/**
++ * usb_endpoint_dir_in - check if the endpoint has IN direction
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint is of type IN, otherwise it returns false.
++ */
++int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
++{
++ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
++}
++
++/**
++ * usb_endpoint_dir_out - check if the endpoint has OUT direction
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint is of type OUT, otherwise it returns false.
++ */
++int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
++{
++ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
++}
++
++/**
++ * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint is of type bulk, otherwise it returns false.
++ */
++int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
++{
++ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ USB_ENDPOINT_XFER_BULK);
++}
++
++/**
++ * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint is of type interrupt, otherwise it returns
++ * false.
++ */
++int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
++{
++ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ USB_ENDPOINT_XFER_INT);
++}
++
++/**
++ * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint is of type isochronous, otherwise it returns
++ * false.
++ */
++int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
++{
++ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ USB_ENDPOINT_XFER_ISOC);
++}
++
++/**
++ * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint has bulk transfer type and IN direction,
++ * otherwise it returns false.
++ */
++int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
++{
++ return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
++}
++
++/**
++ * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint has bulk transfer type and OUT direction,
++ * otherwise it returns false.
++ */
++int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
++{
++ return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
++}
++
++/**
++ * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint has interrupt transfer type and IN direction,
++ * otherwise it returns false.
++ */
++int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
++{
++ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
++}
++
++/**
++ * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint has interrupt transfer type and OUT direction,
++ * otherwise it returns false.
++ */
++int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
++{
++ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
++}
++
++/**
++ * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint has isochronous transfer type and IN direction,
++ * otherwise it returns false.
++ */
++int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
++{
++ return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
++}
++
++/**
++ * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
++ * @epd: endpoint to be checked
++ *
++ * Returns true if the endpoint has isochronous transfer type and OUT direction,
++ * otherwise it returns false.
++ */
++int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
++{
++ return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
+ }
+
+ /*-------------------------------------------------------------------*/
+@@ -737,9 +731,9 @@ void *usb_buffer_alloc (
+ dma_addr_t *dma
+ )
+ {
+- if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
++ if (!dev || !dev->bus)
+ return NULL;
+- return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
++ return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+ }
+
+ /**
+@@ -760,9 +754,11 @@ void usb_buffer_free (
+ dma_addr_t dma
+ )
+ {
+- if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
+- return;
+- dev->bus->op->buffer_free (dev->bus, size, addr, dma);
++ if (!dev || !dev->bus)
++ return;
++ if (!addr)
++ return;
++ hcd_buffer_free (dev->bus, size, addr, dma);
+ }
+
+ /**
+@@ -911,8 +907,8 @@ void usb_buffer_unmap (struct urb *urb)
+ *
+ * Reverse the effect of this call with usb_buffer_unmap_sg().
+ */
+-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
+- struct scatterlist *sg, int nents)
++int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int nents)
+ {
+ struct usb_bus *bus;
+ struct device *controller;
+@@ -946,8 +942,8 @@ int usb_buffer_map_sg (struct usb_device
+ * Use this when you are re-using a scatterlist's data buffers for
+ * another USB request.
+ */
+-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
+- struct scatterlist *sg, int n_hw_ents)
++void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int n_hw_ents)
+ {
+ struct usb_bus *bus;
+ struct device *controller;
+@@ -972,8 +968,8 @@ void usb_buffer_dmasync_sg (struct usb_d
+ *
+ * Reverses the effect of usb_buffer_map_sg().
+ */
+-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
+- struct scatterlist *sg, int n_hw_ents)
++void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int n_hw_ents)
+ {
+ struct usb_bus *bus;
+ struct device *controller;
+@@ -988,116 +984,6 @@ void usb_buffer_unmap_sg (struct usb_dev
+ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
+
+-static int verify_suspended(struct device *dev, void *unused)
+-{
+- if (dev->driver == NULL)
+- return 0;
+- return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
+-}
+-
+-static int usb_generic_suspend(struct device *dev, pm_message_t message)
+-{
+- struct usb_interface *intf;
+- struct usb_driver *driver;
+- int status;
+-
+- /* USB devices enter SUSPEND state through their hubs, but can be
+- * marked for FREEZE as soon as their children are already idled.
+- * But those semantics are useless, so we equate the two (sigh).
+- */
+- if (dev->driver == &usb_generic_driver) {
+- if (dev->power.power_state.event == message.event)
+- return 0;
+- /* we need to rule out bogus requests through sysfs */
+- status = device_for_each_child(dev, NULL, verify_suspended);
+- if (status)
+- return status;
+- return usb_suspend_device (to_usb_device(dev));
+- }
+-
+- if ((dev->driver == NULL) ||
+- (dev->driver_data == &usb_generic_driver_data))
+- return 0;
+-
+- intf = to_usb_interface(dev);
+- driver = to_usb_driver(dev->driver);
+-
+- /* with no hardware, USB interfaces only use FREEZE and ON states */
+- if (!is_active(intf))
+- return 0;
+-
+- if (driver->suspend && driver->resume) {
+- status = driver->suspend(intf, message);
+- if (status)
+- dev_err(dev, "%s error %d\n", "suspend", status);
+- else
+- mark_quiesced(intf);
+- } else {
+- // FIXME else if there's no suspend method, disconnect...
+- dev_warn(dev, "no suspend for driver %s?\n", driver->name);
+- mark_quiesced(intf);
+- status = 0;
+- }
+- return status;
+-}
+-
+-static int usb_generic_resume(struct device *dev)
+-{
+- struct usb_interface *intf;
+- struct usb_driver *driver;
+- struct usb_device *udev;
+- int status;
+-
+- if (dev->power.power_state.event == PM_EVENT_ON)
+- return 0;
+-
+- /* mark things as "on" immediately, no matter what errors crop up */
+- dev->power.power_state.event = PM_EVENT_ON;
+-
+- /* devices resume through their hubs */
+- if (dev->driver == &usb_generic_driver) {
+- udev = to_usb_device(dev);
+- if (udev->state == USB_STATE_NOTATTACHED)
+- return 0;
+- return usb_resume_device (to_usb_device(dev));
+- }
+-
+- if ((dev->driver == NULL) ||
+- (dev->driver_data == &usb_generic_driver_data)) {
+- dev->power.power_state.event = PM_EVENT_FREEZE;
+- return 0;
+- }
+-
+- intf = to_usb_interface(dev);
+- driver = to_usb_driver(dev->driver);
+-
+- udev = interface_to_usbdev(intf);
+- if (udev->state == USB_STATE_NOTATTACHED)
+- return 0;
+-
+- /* if driver was suspended, it has a resume method;
+- * however, sysfs can wrongly mark things as suspended
+- * (on the "no suspend method" FIXME path above)
+- */
+- if (driver->resume) {
+- status = driver->resume(intf);
+- if (status) {
+- dev_err(dev, "%s error %d\n", "resume", status);
+- mark_quiesced(intf);
+- }
+- } else
+- dev_warn(dev, "no resume for driver %s?\n", driver->name);
+- return 0;
+-}
+-
+-struct bus_type usb_bus_type = {
+- .name = "usb",
+- .match = usb_device_match,
+- .uevent = usb_uevent,
+- .suspend = usb_generic_suspend,
+- .resume = usb_generic_resume,
+-};
+-
+ /* format to disable USB on kernel command line is: nousb */
+ __module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
+
+@@ -1120,9 +1006,12 @@ static int __init usb_init(void)
+ return 0;
+ }
+
++ retval = ksuspend_usb_init();
++ if (retval)
++ goto out;
+ retval = bus_register(&usb_bus_type);
+ if (retval)
+- goto out;
++ goto bus_register_failed;
+ retval = usb_host_init();
+ if (retval)
+ goto host_init_failed;
+@@ -1141,7 +1030,7 @@ static int __init usb_init(void)
+ retval = usb_hub_init();
+ if (retval)
+ goto hub_init_failed;
+- retval = driver_register(&usb_generic_driver);
++ retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
+ if (!retval)
+ goto out;
+
+@@ -1158,6 +1047,8 @@ major_init_failed:
+ usb_host_cleanup();
+ host_init_failed:
+ bus_unregister(&usb_bus_type);
++bus_register_failed:
++ ksuspend_usb_cleanup();
+ out:
+ return retval;
+ }
+@@ -1171,7 +1062,7 @@ static void __exit usb_exit(void)
+ if (nousb)
+ return;
+
+- driver_unregister(&usb_generic_driver);
++ usb_deregister_device_driver(&usb_generic_driver);
+ usb_major_cleanup();
+ usbfs_cleanup();
+ usb_deregister(&usbfs_driver);
+@@ -1179,6 +1070,7 @@ static void __exit usb_exit(void)
+ usb_hub_cleanup();
+ usb_host_cleanup();
+ bus_unregister(&usb_bus_type);
++ ksuspend_usb_cleanup();
+ }
+
+ subsys_initcall(usb_init);
+@@ -1201,20 +1093,27 @@ EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
+
+ EXPORT_SYMBOL(usb_lock_device_for_reset);
+
+-EXPORT_SYMBOL(usb_driver_claim_interface);
+-EXPORT_SYMBOL(usb_driver_release_interface);
+ EXPORT_SYMBOL(usb_find_interface);
+ EXPORT_SYMBOL(usb_ifnum_to_if);
+ EXPORT_SYMBOL(usb_altnum_to_altsetting);
+
+-EXPORT_SYMBOL(usb_reset_device);
+-EXPORT_SYMBOL(usb_reset_composite_device);
+-
+ EXPORT_SYMBOL(__usb_get_extra_descriptor);
+
+ EXPORT_SYMBOL(usb_find_device);
+ EXPORT_SYMBOL(usb_get_current_frame_number);
+
++EXPORT_SYMBOL_GPL(usb_endpoint_dir_in);
++EXPORT_SYMBOL_GPL(usb_endpoint_dir_out);
++EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk);
++EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int);
++EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc);
++EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in);
++EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out);
++EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in);
++EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out);
++EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in);
++EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out);
++
+ EXPORT_SYMBOL (usb_buffer_alloc);
+ EXPORT_SYMBOL (usb_buffer_free);
+
+diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
+index 49f6923..13322e3 100644
+--- a/drivers/usb/core/usb.h
++++ b/drivers/usb/core/usb.h
+@@ -1,10 +1,10 @@
+ /* Functions local to drivers/usb/core/ */
+
+-extern void usb_create_sysfs_dev_files (struct usb_device *dev);
++extern int usb_create_sysfs_dev_files (struct usb_device *dev);
+ extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
+-extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
++extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
+ extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
+-extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
++extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
+ struct usb_device *udev);
+ extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
+
+@@ -20,7 +20,6 @@ extern char *usb_cache_string(struct usb
+ extern int usb_set_configuration(struct usb_device *dev, int configuration);
+
+ extern void usb_kick_khubd(struct usb_device *dev);
+-extern void usb_suspend_root_hub(struct usb_device *hdev);
+ extern void usb_resume_root_hub(struct usb_device *dev);
+
+ extern int usb_hub_init(void);
+@@ -30,28 +29,91 @@ extern void usb_major_cleanup(void);
+ extern int usb_host_init(void);
+ extern void usb_host_cleanup(void);
+
+-extern int usb_suspend_device(struct usb_device *dev);
+-extern int usb_resume_device(struct usb_device *dev);
++#ifdef CONFIG_PM
+
+-extern struct device_driver usb_generic_driver;
+-extern int usb_generic_driver_data;
+-extern int usb_device_match(struct device *dev, struct device_driver *drv);
++extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
++extern int usb_resume_both(struct usb_device *udev);
++extern int usb_port_suspend(struct usb_device *dev);
++extern int usb_port_resume(struct usb_device *dev);
++
++static inline void usb_pm_lock(struct usb_device *udev)
++{
++ mutex_lock_nested(&udev->pm_mutex, udev->level);
++}
++
++static inline void usb_pm_unlock(struct usb_device *udev)
++{
++ mutex_unlock(&udev->pm_mutex);
++}
++
++#else
++
++#define usb_suspend_both(udev, msg) 0
++static inline int usb_resume_both(struct usb_device *udev)
++{
++ return 0;
++}
++#define usb_port_suspend(dev) 0
++#define usb_port_resume(dev) 0
++static inline void usb_pm_lock(struct usb_device *udev) {}
++static inline void usb_pm_unlock(struct usb_device *udev) {}
++
++#endif
++
++#ifdef CONFIG_USB_SUSPEND
++
++#define USB_AUTOSUSPEND_DELAY (HZ*2)
++
++extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt);
++extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt);
++
++#else
++
++#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0)
++static inline int usb_autoresume_device(struct usb_device *udev,
++ int inc_busy_cnt)
++{
++ return 0;
++}
++
++#endif
++
++extern struct workqueue_struct *ksuspend_usb_wq;
++extern struct bus_type usb_bus_type;
++extern struct usb_device_driver usb_generic_driver;
++
++/* Here's how we tell apart devices and interfaces. Luckily there's
++ * no such thing as a platform USB device, so we can steal the use
++ * of the platform_data field. */
++
++static inline int is_usb_device(const struct device *dev)
++{
++ return dev->platform_data == &usb_generic_driver;
++}
++
++/* Do the same for device drivers and interface drivers. */
++
++static inline int is_usb_device_driver(struct device_driver *drv)
++{
++ return container_of(drv, struct usbdrv_wrap, driver)->
++ for_devices;
++}
+
+ /* Interfaces and their "power state" are owned by usbcore */
+
+ static inline void mark_active(struct usb_interface *f)
+ {
+- f->dev.power.power_state.event = PM_EVENT_ON;
++ f->is_active = 1;
+ }
+
+ static inline void mark_quiesced(struct usb_interface *f)
+ {
+- f->dev.power.power_state.event = PM_EVENT_FREEZE;
++ f->is_active = 0;
+ }
+
+-static inline int is_active(struct usb_interface *f)
++static inline int is_active(const struct usb_interface *f)
+ {
+- return f->dev.power.power_state.event == PM_EVENT_ON;
++ return f->is_active;
+ }
+
+
+@@ -59,9 +121,10 @@ static inline int is_active(struct usb_i
+ extern const char *usbcore_name;
+
+ /* usbfs stuff */
++extern struct mutex usbfs_mutex;
+ extern struct usb_driver usbfs_driver;
+-extern struct file_operations usbfs_devices_fops;
+-extern struct file_operations usbfs_device_file_operations;
++extern const struct file_operations usbfs_devices_fops;
++extern const struct file_operations usbfs_device_file_operations;
+ extern void usbfs_conn_disc_event(void);
+
+ extern int usbdev_init(void);
+@@ -76,7 +139,7 @@ struct dev_state {
+ struct list_head async_completed;
+ wait_queue_head_t wait; /* wake up if a request completed */
+ unsigned int discsignr;
+- pid_t disc_pid;
++ struct pid *disc_pid;
+ uid_t disc_uid, disc_euid;
+ void __user *disccontext;
+ unsigned long ifclaimed;
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 1a32d96..bbbc82a 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -7,7 +7,7 @@
+ #
+ # - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
+ # - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
+-# - Some systems have both kinds of of controller.
++# - Some systems have both kinds of controllers.
+ #
+ # With help from a special transceiver and a "Mini-AB" jack, systems with
+ # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
+@@ -26,7 +26,7 @@ config USB_GADGET
+ you need a low level bus controller driver, and some software
+ talking to it. Peripheral controllers are often discrete silicon,
+ or are integrated with the CPU in a microcontroller. The more
+- familiar host side controllers have names like like "EHCI", "OHCI",
++ familiar host side controllers have names like "EHCI", "OHCI",
+ or "UHCI", and are usually integrated into southbridges on PC
+ motherboards.
+
+@@ -404,6 +404,20 @@ config USB_G_SERIAL
+ which includes instructions and a "driver info file" needed to
+ make MS-Windows work with this driver.
+
++config USB_MIDI_GADGET
++ tristate "MIDI Gadget (EXPERIMENTAL)"
++ depends on SND && EXPERIMENTAL
++ select SND_RAWMIDI
++ help
++ The MIDI Gadget acts as a USB Audio device, with one MIDI
++ input and one MIDI output. These MIDI jacks appear as
++ a sound "card" in the ALSA sound system. Other MIDI
++ connections can then be made on the gadget system, using
++ ALSA's aconnect utility etc.
++
++ Say "y" to link the driver statically, or "m" to build a
++ dynamically linked module called "g_midi".
++
+
+ # put drivers that need isochronous transfer support (for audio
+ # or video class gadget drivers), or specific hardware, here.
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index 5a28e61..e71e086 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o
+ g_zero-objs := zero.o usbstring.o config.o epautoconf.o
+ g_ether-objs := ether.o usbstring.o config.o epautoconf.o
+ g_serial-objs := serial.o usbstring.o config.o epautoconf.o
++g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
+ gadgetfs-objs := inode.o
+ g_file_storage-objs := file_storage.o usbstring.o config.o \
+ epautoconf.o
+@@ -28,4 +29,5 @@ obj-$(CONFIG_USB_ETH) += g_ether.o
+ obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
+ obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
+ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
++obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
+
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index cfebca0..72f3db9 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -247,7 +247,7 @@ static int proc_udc_open(struct inode *i
+ return single_open(file, proc_udc_show, PDE(inode)->data);
+ }
+
+-static struct file_operations proc_ops = {
++static const struct file_operations proc_ops = {
+ .open = proc_udc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -1366,7 +1366,7 @@ static void handle_ep0(struct at91_udc *
+ }
+ }
+
+-static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
++static irqreturn_t at91_udc_irq (int irq, void *_udc)
+ {
+ struct at91_udc *udc = _udc;
+ u32 rescans = 5;
+@@ -1552,7 +1552,7 @@ static struct at91_udc controller = {
+ /* ep6 and ep7 are also reserved (custom silicon might use them) */
+ };
+
+-static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
++static irqreturn_t at91_vbus_irq(int irq, void *_udc)
+ {
+ struct at91_udc *udc = _udc;
+ unsigned value;
+@@ -1658,7 +1658,7 @@ static int __devinit at91udc_probe(struc
+ return -ENODEV;
+ }
+
+- if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
++ if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
+ DBG("someone's using UDC memory\n");
+ return -EBUSY;
+ }
+@@ -1720,7 +1720,7 @@ static int __devinit at91udc_probe(struc
+ fail1:
+ device_unregister(&udc->gadget.dev);
+ fail0:
+- release_mem_region(AT91_BASE_UDP, SZ_16K);
++ release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
+ DBG("%s probe failed, %d\n", driver_name, retval);
+ return retval;
+ }
+@@ -1742,7 +1742,7 @@ static int __devexit at91udc_remove(stru
+ free_irq(udc->board.vbus_pin, udc);
+ free_irq(udc->udp_irq, udc);
+ device_unregister(&udc->gadget.dev);
+- release_mem_region(AT91_BASE_UDP, SZ_16K);
++ release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
+
+ clk_put(udc->iclk);
+ clk_put(udc->fclk);
+diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
+index 7d1c22c..f1f32d7 100644
+--- a/drivers/usb/gadget/dummy_hcd.c
++++ b/drivers/usb/gadget/dummy_hcd.c
+@@ -816,15 +816,14 @@ usb_gadget_register_driver (struct usb_g
+ dum->gadget.dev.driver = &driver->driver;
+ dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
+ driver->driver.name);
+- if ((retval = driver->bind (&dum->gadget)) != 0) {
+- dum->driver = NULL;
+- dum->gadget.dev.driver = NULL;
+- return retval;
+- }
++ if ((retval = driver->bind (&dum->gadget)) != 0)
++ goto err_bind_gadget;
+
+ driver->driver.bus = dum->gadget.dev.parent->bus;
+- driver_register (&driver->driver);
+- device_bind_driver (&dum->gadget.dev);
++ if ((retval = driver_register (&driver->driver)) != 0)
++ goto err_register;
++ if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
++ goto err_bind_driver;
+
+ /* khubd will enumerate this in a while */
+ spin_lock_irq (&dum->lock);
+@@ -834,6 +833,19 @@ usb_gadget_register_driver (struct usb_g
+
+ usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+ return 0;
++
++err_bind_driver:
++ driver_unregister (&driver->driver);
++err_register:
++ driver->unbind (&dum->gadget);
++ spin_lock_irq (&dum->lock);
++ dum->pullup = 0;
++ set_link_state (dum);
++ spin_unlock_irq (&dum->lock);
++err_bind_gadget:
++ dum->driver = NULL;
++ dum->gadget.dev.driver = NULL;
++ return retval;
+ }
+ EXPORT_SYMBOL (usb_gadget_register_driver);
+
+@@ -889,11 +901,9 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
+ 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
++ usb_put_hcd (dummy_to_hcd (dum));
+ }
+
+ static int dummy_udc_probe (struct platform_device *pdev)
+@@ -915,12 +925,12 @@ static int dummy_udc_probe (struct platf
+ if (rc < 0)
+ return rc;
+
+-#if 0 /* usb_bus_get isn't EXPORTed! */
+- usb_bus_get (&dummy_to_hcd (dum)->self);
+-#endif
++ usb_get_hcd (dummy_to_hcd (dum));
+
+ platform_set_drvdata (pdev, dum);
+- device_create_file (&dum->gadget.dev, &dev_attr_function);
++ rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
++ if (rc < 0)
++ device_unregister (&dum->gadget.dev);
+ return rc;
+ }
+
+@@ -1541,7 +1551,7 @@ return_urb:
+ ep->already_seen = ep->setup_stage = 0;
+
+ spin_unlock (&dum->lock);
+- usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL);
++ usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+ spin_lock (&dum->lock);
+
+ goto restart;
+@@ -1868,8 +1878,7 @@ static int dummy_start (struct usb_hcd *
+ #endif
+
+ /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
+- device_create_file (dummy_dev(dum), &dev_attr_urbs);
+- return 0;
++ return device_create_file (dummy_dev(dum), &dev_attr_urbs);
+ }
+
+ static void dummy_stop (struct usb_hcd *hcd)
+diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
+index 30299c6..1c17d26 100644
+--- a/drivers/usb/gadget/ether.c
++++ b/drivers/usb/gadget/ether.c
+@@ -262,7 +262,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethern
+ #define DEV_CONFIG_CDC
+ #endif
+
+-#ifdef CONFIG_USB_GADGET_MUSBHDRC
++#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ #define DEV_CONFIG_CDC
+ #endif
+
+@@ -2014,7 +2014,7 @@ rndis_control_ack_complete (struct usb_e
+ static int rndis_control_ack (struct net_device *net)
+ {
+ struct eth_dev *dev = netdev_priv(net);
+- u32 length;
++ int length;
+ struct usb_request *resp = dev->stat_req;
+
+ /* in case RNDIS calls this after disconnect */
+@@ -2230,6 +2230,9 @@ eth_bind (struct usb_gadget *gadget)
+ if (gadget_is_pxa (gadget)) {
+ /* pxa doesn't support altsettings */
+ cdc = 0;
++ } else if (gadget_is_musbhdrc(gadget)) {
++ /* reduce tx dma overhead by avoiding special cases */
++ zlp = 0;
+ } else if (gadget_is_sh(gadget)) {
+ /* sh doesn't support multiple interfaces or configs */
+ cdc = 0;
+@@ -2257,7 +2260,7 @@ eth_bind (struct usb_gadget *gadget)
+ return -ENODEV;
+ }
+ snprintf (manufacturer, sizeof manufacturer, "%s %s/%s",
+- system_utsname.sysname, system_utsname.release,
++ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+ /* If there's an RNDIS configuration, that's what Windows wants to
+@@ -2564,7 +2567,7 @@ static struct usb_gadget_driver eth_driv
+
+ .function = (char *) driver_desc,
+ .bind = eth_bind,
+- .unbind = __exit_p(eth_unbind),
++ .unbind = eth_unbind,
+
+ .setup = eth_setup,
+ .disconnect = eth_disconnect,
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+index 8d7f1e8..8b975d1 100644
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -567,6 +567,7 @@ struct lun {
+ unsigned int ro : 1;
+ unsigned int prevent_medium_removal : 1;
+ unsigned int registered : 1;
++ unsigned int info_valid : 1;
+
+ u32 sense_data;
+ u32 sense_data_info;
+@@ -1656,6 +1657,7 @@ static int do_read(struct fsg_dev *fsg)
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = file_offset >> 9;
++ curlun->info_valid = 1;
+ bh->inreq->length = 0;
+ bh->state = BUF_STATE_FULL;
+ break;
+@@ -1691,6 +1693,7 @@ static int do_read(struct fsg_dev *fsg)
+ if (nread < amount) {
+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+ curlun->sense_data_info = file_offset >> 9;
++ curlun->info_valid = 1;
+ break;
+ }
+
+@@ -1785,6 +1788,7 @@ static int do_write(struct fsg_dev *fsg)
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = usb_offset >> 9;
++ curlun->info_valid = 1;
+ continue;
+ }
+ amount -= (amount & 511);
+@@ -1827,6 +1831,7 @@ static int do_write(struct fsg_dev *fsg)
+ if (bh->outreq->status != 0) {
+ curlun->sense_data = SS_COMMUNICATION_FAILURE;
+ curlun->sense_data_info = file_offset >> 9;
++ curlun->info_valid = 1;
+ break;
+ }
+
+@@ -1868,6 +1873,7 @@ static int do_write(struct fsg_dev *fsg)
+ if (nwritten < amount) {
+ curlun->sense_data = SS_WRITE_ERROR;
+ curlun->sense_data_info = file_offset >> 9;
++ curlun->info_valid = 1;
+ break;
+ }
+
+@@ -2010,6 +2016,7 @@ static int do_verify(struct fsg_dev *fsg
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = file_offset >> 9;
++ curlun->info_valid = 1;
+ break;
+ }
+
+@@ -2036,6 +2043,7 @@ static int do_verify(struct fsg_dev *fsg
+ if (nread == 0) {
+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+ curlun->sense_data_info = file_offset >> 9;
++ curlun->info_valid = 1;
+ break;
+ }
+ file_offset += nread;
+@@ -2079,6 +2087,7 @@ static int do_request_sense(struct fsg_d
+ struct lun *curlun = fsg->curlun;
+ u8 *buf = (u8 *) bh->buf;
+ u32 sd, sdinfo;
++ int valid;
+
+ /*
+ * From the SCSI-2 spec., section 7.9 (Unit attention condition):
+@@ -2106,15 +2115,18 @@ static int do_request_sense(struct fsg_d
+ fsg->bad_lun_okay = 1;
+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+ sdinfo = 0;
++ valid = 0;
+ } else {
+ sd = curlun->sense_data;
+ sdinfo = curlun->sense_data_info;
++ valid = curlun->info_valid << 7;
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
+ }
+
+ memset(buf, 0, 18);
+- buf[0] = 0x80 | 0x70; // Valid, current error
++ buf[0] = valid | 0x70; // Valid, current error
+ buf[2] = SK(sd);
+ put_be32(&buf[3], sdinfo); // Sense information
+ buf[7] = 18 - 8; // Additional sense length
+@@ -2703,6 +2715,7 @@ static int check_command(struct fsg_dev
+ if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
+ }
+ } else {
+ fsg->curlun = curlun = NULL;
+@@ -3332,6 +3345,7 @@ static void handle_exception(struct fsg_
+ curlun->sense_data = curlun->unit_attention_data =
+ SS_NO_SENSE;
+ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
+ }
+ fsg->state = FSG_STATE_IDLE;
+ }
+@@ -3873,21 +3887,26 @@ static int __init fsg_bind(struct usb_ga
+ for (i = 0; i < fsg->nluns; ++i) {
+ curlun = &fsg->luns[i];
+ curlun->ro = mod_data.ro[i];
++ curlun->dev.release = lun_release;
+ curlun->dev.parent = &gadget->dev;
+ curlun->dev.driver = &fsg_driver.driver;
+ dev_set_drvdata(&curlun->dev, fsg);
+ snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
+ "%s-lun%d", gadget->dev.bus_id, i);
+
+- if ((rc = device_register(&curlun->dev)) != 0)
++ if ((rc = device_register(&curlun->dev)) != 0) {
+ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
+- else {
+- curlun->registered = 1;
+- curlun->dev.release = lun_release;
+- device_create_file(&curlun->dev, &dev_attr_ro);
+- device_create_file(&curlun->dev, &dev_attr_file);
+- kref_get(&fsg->ref);
++ goto out;
++ }
++ if ((rc = device_create_file(&curlun->dev,
++ &dev_attr_ro)) != 0 ||
++ (rc = device_create_file(&curlun->dev,
++ &dev_attr_file)) != 0) {
++ device_unregister(&curlun->dev);
++ goto out;
+ }
++ curlun->registered = 1;
++ kref_get(&fsg->ref);
+
+ if (mod_data.file[i] && *mod_data.file[i]) {
+ if ((rc = open_backing_file(curlun,
+@@ -3982,7 +4001,7 @@ static int __init fsg_bind(struct usb_ga
+ usb_gadget_set_selfpowered(gadget);
+
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+- system_utsname.sysname, system_utsname.release,
++ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+ /* On a real device, serial[] would be loaded from permanent
+diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
+new file mode 100644
+index 0000000..64554ac
+--- /dev/null
++++ b/drivers/usb/gadget/gmidi.c
+@@ -0,0 +1,1336 @@
++/*
++ * gmidi.c -- USB MIDI Gadget Driver
++ *
++ * Copyright (C) 2006 Thumtronics Pty Ltd.
++ * Developed for Thumtronics by Grey Innovation
++ * Ben Williamson <ben.williamson at greyinnovation.com>
++ *
++ * This software is distributed under the terms of the GNU General Public
++ * License ("GPL") version 2, as published by the Free Software Foundation.
++ *
++ * This code is based in part on:
++ *
++ * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell.
++ * USB Audio driver, Copyright (C) 2002 by Takashi Iwai.
++ * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch.
++ *
++ * Refer to the USB Device Class Definition for MIDI Devices:
++ * http://www.usb.org/developers/devclass_docs/midi10.pdf
++ */
++
++#define DEBUG 1
++// #define VERBOSE
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/rawmidi.h>
++
++#include <linux/usb_ch9.h>
++#include <linux/usb_gadget.h>
++#include <linux/usb/audio.h>
++#include <linux/usb/midi.h>
++
++#include "gadget_chips.h"
++
++MODULE_AUTHOR("Ben Williamson");
++MODULE_LICENSE("GPL v2");
++
++#define DRIVER_VERSION "25 Jul 2006"
++
++static const char shortname[] = "g_midi";
++static const char longname[] = "MIDI Gadget";
++
++static int index = SNDRV_DEFAULT_IDX1;
++static char *id = SNDRV_DEFAULT_STR1;
++
++module_param(index, int, 0444);
++MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
++module_param(id, charp, 0444);
++MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
++
++/* Some systems will want different product identifers published in the
++ * device descriptor, either numbers or strings or both. These string
++ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
++ */
++
++static ushort idVendor;
++module_param(idVendor, ushort, S_IRUGO);
++MODULE_PARM_DESC(idVendor, "USB Vendor ID");
++
++static ushort idProduct;
++module_param(idProduct, ushort, S_IRUGO);
++MODULE_PARM_DESC(idProduct, "USB Product ID");
++
++static ushort bcdDevice;
++module_param(bcdDevice, ushort, S_IRUGO);
++MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
++
++static char *iManufacturer;
++module_param(iManufacturer, charp, S_IRUGO);
++MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
++
++static char *iProduct;
++module_param(iProduct, charp, S_IRUGO);
++MODULE_PARM_DESC(iProduct, "USB Product string");
++
++static char *iSerialNumber;
++module_param(iSerialNumber, charp, S_IRUGO);
++MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
++
++/*
++ * this version autoconfigures as much as possible,
++ * which is reasonable for most "bulk-only" drivers.
++ */
++static const char *EP_IN_NAME;
++static const char *EP_OUT_NAME;
++
++
++/* big enough to hold our biggest descriptor */
++#define USB_BUFSIZ 256
++
++
++/* This is a gadget, and the IN/OUT naming is from the host's perspective.
++ USB -> OUT endpoint -> rawmidi
++ USB <- IN endpoint <- rawmidi */
++struct gmidi_in_port {
++ struct gmidi_device* dev;
++ int active;
++ uint8_t cable; /* cable number << 4 */
++ uint8_t state;
++#define STATE_UNKNOWN 0
++#define STATE_1PARAM 1
++#define STATE_2PARAM_1 2
++#define STATE_2PARAM_2 3
++#define STATE_SYSEX_0 4
++#define STATE_SYSEX_1 5
++#define STATE_SYSEX_2 6
++ uint8_t data[2];
++};
++
++struct gmidi_device {
++ spinlock_t lock;
++ struct usb_gadget *gadget;
++ struct usb_request *req; /* for control responses */
++ u8 config;
++ struct usb_ep *in_ep, *out_ep;
++ struct snd_card *card;
++ struct snd_rawmidi *rmidi;
++ struct snd_rawmidi_substream *in_substream;
++ struct snd_rawmidi_substream *out_substream;
++
++ /* For the moment we only support one port in
++ each direction, but in_port is kept as a
++ separate struct so we can have more later. */
++ struct gmidi_in_port in_port;
++ unsigned long out_triggered;
++ struct tasklet_struct tasklet;
++};
++
++static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
++
++
++#define xprintk(d,level,fmt,args...) \
++ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
++
++#ifdef DEBUG
++#define DBG(dev,fmt,args...) \
++ xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define DBG(dev,fmt,args...) \
++ do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE
++#define VDBG DBG
++#else
++#define VDBG(dev,fmt,args...) \
++ do { } while (0)
++#endif /* VERBOSE */
++
++#define ERROR(dev,fmt,args...) \
++ xprintk(dev , KERN_ERR , fmt , ## args)
++#define WARN(dev,fmt,args...) \
++ xprintk(dev , KERN_WARNING , fmt , ## args)
++#define INFO(dev,fmt,args...) \
++ xprintk(dev , KERN_INFO , fmt , ## args)
++
++
++static unsigned buflen = 256;
++static unsigned qlen = 32;
++
++module_param(buflen, uint, S_IRUGO);
++module_param(qlen, uint, S_IRUGO);
++
++
++/* Thanks to Grey Innovation for donating this product ID.
++ *
++ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
++ * Instead: allocate your own, using normal USB-IF procedures.
++ */
++#define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */
++#define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */
++
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full)
++ * configuration descriptors are built on demand.
++ */
++
++#define STRING_MANUFACTURER 25
++#define STRING_PRODUCT 42
++#define STRING_SERIAL 101
++#define STRING_MIDI_GADGET 250
++
++/* We only have the one configuration, it's number 1. */
++#define GMIDI_CONFIG 1
++
++/* We have two interfaces- AudioControl and MIDIStreaming */
++#define GMIDI_AC_INTERFACE 0
++#define GMIDI_MS_INTERFACE 1
++#define GMIDI_NUM_INTERFACES 2
++
++DECLARE_USB_AC_HEADER_DESCRIPTOR(1);
++DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
++DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
++
++/* B.1 Device Descriptor */
++static struct usb_device_descriptor device_desc = {
++ .bLength = USB_DT_DEVICE_SIZE,
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = __constant_cpu_to_le16(0x0200),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
++ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
++ .iManufacturer = STRING_MANUFACTURER,
++ .iProduct = STRING_PRODUCT,
++ .bNumConfigurations = 1,
++};
++
++/* B.2 Configuration Descriptor */
++static struct usb_config_descriptor config_desc = {
++ .bLength = USB_DT_CONFIG_SIZE,
++ .bDescriptorType = USB_DT_CONFIG,
++ /* compute wTotalLength on the fly */
++ .bNumInterfaces = GMIDI_NUM_INTERFACES,
++ .bConfigurationValue = GMIDI_CONFIG,
++ .iConfiguration = STRING_MIDI_GADGET,
++ /*
++ * FIXME: When embedding this driver in a device,
++ * these need to be set to reflect the actual
++ * power properties of the device. Is it selfpowered?
++ */
++ .bmAttributes = USB_CONFIG_ATT_ONE,
++ .bMaxPower = 1,
++};
++
++/* B.3.1 Standard AC Interface Descriptor */
++static const struct usb_interface_descriptor ac_interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = GMIDI_AC_INTERFACE,
++ .bNumEndpoints = 0,
++ .bInterfaceClass = USB_CLASS_AUDIO,
++ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
++ .iInterface = STRING_MIDI_GADGET,
++};
++
++/* B.3.2 Class-Specific AC Interface Descriptor */
++static const struct usb_ac_header_descriptor_1 ac_header_desc = {
++ .bLength = USB_DT_AC_HEADER_SIZE(1),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = USB_MS_HEADER,
++ .bcdADC = __constant_cpu_to_le16(0x0100),
++ .wTotalLength = USB_DT_AC_HEADER_SIZE(1),
++ .bInCollection = 1,
++ .baInterfaceNr = {
++ [0] = GMIDI_MS_INTERFACE,
++ }
++};
++
++/* B.4.1 Standard MS Interface Descriptor */
++static const struct usb_interface_descriptor ms_interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = GMIDI_MS_INTERFACE,
++ .bNumEndpoints = 2,
++ .bInterfaceClass = USB_CLASS_AUDIO,
++ .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
++ .iInterface = STRING_MIDI_GADGET,
++};
++
++/* B.4.2 Class-Specific MS Interface Descriptor */
++static const struct usb_ms_header_descriptor ms_header_desc = {
++ .bLength = USB_DT_MS_HEADER_SIZE,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = USB_MS_HEADER,
++ .bcdMSC = __constant_cpu_to_le16(0x0100),
++ .wTotalLength = USB_DT_MS_HEADER_SIZE
++ + 2*USB_DT_MIDI_IN_SIZE
++ + 2*USB_DT_MIDI_OUT_SIZE(1),
++};
++
++#define JACK_IN_EMB 1
++#define JACK_IN_EXT 2
++#define JACK_OUT_EMB 3
++#define JACK_OUT_EXT 4
++
++/* B.4.3 MIDI IN Jack Descriptors */
++static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
++ .bLength = USB_DT_MIDI_IN_SIZE,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
++ .bJackType = USB_MS_EMBEDDED,
++ .bJackID = JACK_IN_EMB,
++};
++
++static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = {
++ .bLength = USB_DT_MIDI_IN_SIZE,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
++ .bJackType = USB_MS_EXTERNAL,
++ .bJackID = JACK_IN_EXT,
++};
++
++/* B.4.4 MIDI OUT Jack Descriptors */
++static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = {
++ .bLength = USB_DT_MIDI_OUT_SIZE(1),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
++ .bJackType = USB_MS_EMBEDDED,
++ .bJackID = JACK_OUT_EMB,
++ .bNrInputPins = 1,
++ .pins = {
++ [0] = {
++ .baSourceID = JACK_IN_EXT,
++ .baSourcePin = 1,
++ }
++ }
++};
++
++static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = {
++ .bLength = USB_DT_MIDI_OUT_SIZE(1),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
++ .bJackType = USB_MS_EXTERNAL,
++ .bJackID = JACK_OUT_EXT,
++ .bNrInputPins = 1,
++ .pins = {
++ [0] = {
++ .baSourceID = JACK_IN_EMB,
++ .baSourcePin = 1,
++ }
++ }
++};
++
++/* B.5.1 Standard Bulk OUT Endpoint Descriptor */
++static struct usb_endpoint_descriptor bulk_out_desc = {
++ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
++static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = {
++ .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
++ .bDescriptorType = USB_DT_CS_ENDPOINT,
++ .bDescriptorSubtype = USB_MS_GENERAL,
++ .bNumEmbMIDIJack = 1,
++ .baAssocJackID = {
++ [0] = JACK_IN_EMB,
++ }
++};
++
++/* B.6.1 Standard Bulk IN Endpoint Descriptor */
++static struct usb_endpoint_descriptor bulk_in_desc = {
++ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
++static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = {
++ .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
++ .bDescriptorType = USB_DT_CS_ENDPOINT,
++ .bDescriptorSubtype = USB_MS_GENERAL,
++ .bNumEmbMIDIJack = 1,
++ .baAssocJackID = {
++ [0] = JACK_OUT_EMB,
++ }
++};
++
++static const struct usb_descriptor_header *gmidi_function [] = {
++ (struct usb_descriptor_header *)&ac_interface_desc,
++ (struct usb_descriptor_header *)&ac_header_desc,
++ (struct usb_descriptor_header *)&ms_interface_desc,
++
++ (struct usb_descriptor_header *)&ms_header_desc,
++ (struct usb_descriptor_header *)&jack_in_emb_desc,
++ (struct usb_descriptor_header *)&jack_in_ext_desc,
++ (struct usb_descriptor_header *)&jack_out_emb_desc,
++ (struct usb_descriptor_header *)&jack_out_ext_desc,
++ /* If you add more jacks, update ms_header_desc.wTotalLength */
++
++ (struct usb_descriptor_header *)&bulk_out_desc,
++ (struct usb_descriptor_header *)&ms_out_desc,
++ (struct usb_descriptor_header *)&bulk_in_desc,
++ (struct usb_descriptor_header *)&ms_in_desc,
++ NULL,
++};
++
++static char manufacturer[50];
++static char product_desc[40] = "MIDI Gadget";
++static char serial_number[20];
++
++/* static strings, in UTF-8 */
++static struct usb_string strings [] = {
++ { STRING_MANUFACTURER, manufacturer, },
++ { STRING_PRODUCT, product_desc, },
++ { STRING_SERIAL, serial_number, },
++ { STRING_MIDI_GADGET, longname, },
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab = {
++ .language = 0x0409, /* en-us */
++ .strings = strings,
++};
++
++static int config_buf(struct usb_gadget *gadget,
++ u8 *buf, u8 type, unsigned index)
++{
++ int len;
++
++ /* only one configuration */
++ if (index != 0) {
++ return -EINVAL;
++ }
++ len = usb_gadget_config_buf(&config_desc,
++ buf, USB_BUFSIZ, gmidi_function);
++ if (len < 0) {
++ return len;
++ }
++ ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
++ return len;
++}
++
++static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
++{
++ struct usb_request *req;
++
++ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
++ if (req) {
++ req->length = length;
++ req->buf = kmalloc(length, GFP_ATOMIC);
++ if (!req->buf) {
++ usb_ep_free_request(ep, req);
++ req = NULL;
++ }
++ }
++ return req;
++}
++
++static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
++{
++ kfree(req->buf);
++ usb_ep_free_request(ep, req);
++}
++
++static const uint8_t gmidi_cin_length[] = {
++ 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
++};
++
++/*
++ * Receives a chunk of MIDI data.
++ */
++static void gmidi_read_data(struct usb_ep *ep, int cable,
++ uint8_t* data, int length)
++{
++ struct gmidi_device *dev = ep->driver_data;
++ /* cable is ignored, because for now we only have one. */
++
++ if (!dev->out_substream) {
++ /* Nobody is listening - throw it on the floor. */
++ return;
++ }
++ if (!test_bit(dev->out_substream->number, &dev->out_triggered)) {
++ return;
++ }
++ snd_rawmidi_receive(dev->out_substream, data, length);
++}
++
++static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
++{
++ unsigned i;
++ u8 *buf = req->buf;
++
++ for (i = 0; i + 3 < req->actual; i += 4) {
++ if (buf[i] != 0) {
++ int cable = buf[i] >> 4;
++ int length = gmidi_cin_length[buf[i] & 0x0f];
++ gmidi_read_data(ep, cable, &buf[i + 1], length);
++ }
++ }
++}
++
++static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct gmidi_device *dev = ep->driver_data;
++ int status = req->status;
++
++ switch (status) {
++ case 0: /* normal completion */
++ if (ep == dev->out_ep) {
++ /* we received stuff.
++ req is queued again, below */
++ gmidi_handle_out_data(ep, req);
++ } else if (ep == dev->in_ep) {
++ /* our transmit completed.
++ see if there's more to go.
++ gmidi_transmit eats req, don't queue it again. */
++ gmidi_transmit(dev, req);
++ return;
++ }
++ break;
++
++ /* this endpoint is normally active while we're configured */
++ case -ECONNABORTED: /* hardware forced ep reset */
++ case -ECONNRESET: /* request dequeued */
++ case -ESHUTDOWN: /* disconnect from host */
++ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
++ req->actual, req->length);
++ if (ep == dev->out_ep) {
++ gmidi_handle_out_data(ep, req);
++ }
++ free_ep_req(ep, req);
++ return;
++
++ case -EOVERFLOW: /* buffer overrun on read means that
++ * we didn't provide a big enough
++ * buffer.
++ */
++ default:
++ DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
++ status, req->actual, req->length);
++ break;
++ case -EREMOTEIO: /* short read */
++ break;
++ }
++
++ status = usb_ep_queue(ep, req, GFP_ATOMIC);
++ if (status) {
++ ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
++ ep->name, req->length, status);
++ usb_ep_set_halt(ep);
++ /* FIXME recover later ... somehow */
++ }
++}
++
++static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
++{
++ int err = 0;
++ struct usb_request *req;
++ struct usb_ep* ep;
++ unsigned i;
++
++ err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
++ if (err) {
++ ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
++ goto fail;
++ }
++ dev->in_ep->driver_data = dev;
++
++ err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
++ if (err) {
++ ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
++ goto fail;
++ }
++ dev->out_ep->driver_data = dev;
++
++ /* allocate a bunch of read buffers and queue them all at once. */
++ ep = dev->out_ep;
++ for (i = 0; i < qlen && err == 0; i++) {
++ req = alloc_ep_req(ep, buflen);
++ if (req) {
++ req->complete = gmidi_complete;
++ err = usb_ep_queue(ep, req, GFP_ATOMIC);
++ if (err) {
++ DBG(dev, "%s queue req: %d\n", ep->name, err);
++ }
++ } else {
++ err = -ENOMEM;
++ }
++ }
++fail:
++ /* caller is responsible for cleanup on error */
++ return err;
++}
++
++
++static void gmidi_reset_config(struct gmidi_device *dev)
++{
++ if (dev->config == 0) {
++ return;
++ }
++
++ DBG(dev, "reset config\n");
++
++ /* just disable endpoints, forcing completion of pending i/o.
++ * all our completion handlers free their requests in this case.
++ */
++ usb_ep_disable(dev->in_ep);
++ usb_ep_disable(dev->out_ep);
++ dev->config = 0;
++}
++
++/* change our operational config. this code must agree with the code
++ * that returns config descriptors, and altsetting code.
++ *
++ * it's also responsible for power management interactions. some
++ * configurations might not work with our current power sources.
++ *
++ * note that some device controller hardware will constrain what this
++ * code can do, perhaps by disallowing more than one configuration or
++ * by limiting configuration choices (like the pxa2xx).
++ */
++static int
++gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
++{
++ int result = 0;
++ struct usb_gadget *gadget = dev->gadget;
++
++#if 0
++ /* FIXME */
++ /* Hacking this bit out fixes a bug where on receipt of two
++ USB_REQ_SET_CONFIGURATION messages, we end up with no
++ buffered OUT requests waiting for data. This is clearly
++ hiding a bug elsewhere, because if the config didn't
++ change then we really shouldn't do anything. */
++ /* Having said that, when we do "change" from config 1
++ to config 1, we at least gmidi_reset_config() which
++ clears out any requests on endpoints, so it's not like
++ we leak or anything. */
++ if (number == dev->config) {
++ return 0;
++ }
++#endif
++
++ if (gadget_is_sa1100(gadget) && dev->config) {
++ /* tx fifo is full, but we can't clear it...*/
++ INFO(dev, "can't change configurations\n");
++ return -ESPIPE;
++ }
++ gmidi_reset_config(dev);
++
++ switch (number) {
++ case GMIDI_CONFIG:
++ result = set_gmidi_config(dev, gfp_flags);
++ break;
++ default:
++ result = -EINVAL;
++ /* FALL THROUGH */
++ case 0:
++ return result;
++ }
++
++ if (!result && (!dev->in_ep || !dev->out_ep)) {
++ result = -ENODEV;
++ }
++ if (result) {
++ gmidi_reset_config(dev);
++ } else {
++ char *speed;
++
++ switch (gadget->speed) {
++ case USB_SPEED_LOW: speed = "low"; break;
++ case USB_SPEED_FULL: speed = "full"; break;
++ case USB_SPEED_HIGH: speed = "high"; break;
++ default: speed = "?"; break;
++ }
++
++ dev->config = number;
++ INFO(dev, "%s speed\n", speed);
++ }
++ return result;
++}
++
++
++static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ if (req->status || req->actual != req->length) {
++ DBG((struct gmidi_device *) ep->driver_data,
++ "setup complete --> %d, %d/%d\n",
++ req->status, req->actual, req->length);
++ }
++}
++
++/*
++ * The setup() callback implements all the ep0 functionality that's
++ * not handled lower down, in hardware or the hardware driver (like
++ * device and endpoint feature flags, and their status). It's all
++ * housekeeping for the gadget function we're implementing. Most of
++ * the work is in config-specific setup.
++ */
++static int gmidi_setup(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct gmidi_device *dev = get_gadget_data(gadget);
++ struct usb_request *req = dev->req;
++ int value = -EOPNOTSUPP;
++ 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.
++ */
++ req->zero = 0;
++ switch (ctrl->bRequest) {
++
++ case USB_REQ_GET_DESCRIPTOR:
++ if (ctrl->bRequestType != USB_DIR_IN) {
++ goto unknown;
++ }
++ switch (w_value >> 8) {
++
++ case USB_DT_DEVICE:
++ value = min(w_length, (u16) sizeof(device_desc));
++ memcpy(req->buf, &device_desc, value);
++ break;
++ case USB_DT_CONFIG:
++ value = config_buf(gadget, req->buf,
++ w_value >> 8,
++ w_value & 0xff);
++ if (value >= 0) {
++ value = min(w_length, (u16)value);
++ }
++ break;
++
++ case USB_DT_STRING:
++ /* wIndex == language code.
++ * this driver only handles one language, you can
++ * add string tables for other languages, using
++ * any UTF-8 characters
++ */
++ value = usb_gadget_get_string(&stringtab,
++ w_value & 0xff, req->buf);
++ if (value >= 0) {
++ value = min(w_length, (u16)value);
++ }
++ break;
++ }
++ break;
++
++ /* currently two configs, two speeds */
++ case USB_REQ_SET_CONFIGURATION:
++ if (ctrl->bRequestType != 0) {
++ goto unknown;
++ }
++ if (gadget->a_hnp_support) {
++ DBG(dev, "HNP available\n");
++ } else if (gadget->a_alt_hnp_support) {
++ DBG(dev, "HNP needs a different root port\n");
++ } else {
++ VDBG(dev, "HNP inactive\n");
++ }
++ spin_lock(&dev->lock);
++ value = gmidi_set_config(dev, w_value, GFP_ATOMIC);
++ spin_unlock(&dev->lock);
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ if (ctrl->bRequestType != USB_DIR_IN) {
++ goto unknown;
++ }
++ *(u8 *)req->buf = dev->config;
++ value = min(w_length, (u16)1);
++ break;
++
++ /* until we add altsetting support, or other interfaces,
++ * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
++ * and already killed pending endpoint I/O.
++ */
++ case USB_REQ_SET_INTERFACE:
++ if (ctrl->bRequestType != USB_RECIP_INTERFACE) {
++ goto unknown;
++ }
++ spin_lock(&dev->lock);
++ if (dev->config && w_index < GMIDI_NUM_INTERFACES
++ && w_value == 0)
++ {
++ u8 config = dev->config;
++
++ /* resets interface configuration, forgets about
++ * previous transaction state (queued bufs, etc)
++ * and re-inits endpoint state (toggle etc)
++ * no response queued, just zero status == success.
++ * if we had more than one interface we couldn't
++ * use this "reset the config" shortcut.
++ */
++ gmidi_reset_config(dev);
++ gmidi_set_config(dev, config, GFP_ATOMIC);
++ value = 0;
++ }
++ spin_unlock(&dev->lock);
++ break;
++ case USB_REQ_GET_INTERFACE:
++ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
++ goto unknown;
++ }
++ if (!dev->config) {
++ break;
++ }
++ if (w_index >= GMIDI_NUM_INTERFACES) {
++ value = -EDOM;
++ break;
++ }
++ *(u8 *)req->buf = 0;
++ value = min(w_length, (u16)1);
++ break;
++
++ default:
++unknown:
++ VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ }
++
++ /* respond with data transfer before status phase? */
++ if (value >= 0) {
++ req->length = value;
++ req->zero = value < w_length;
++ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
++ if (value < 0) {
++ DBG(dev, "ep_queue --> %d\n", value);
++ req->status = 0;
++ gmidi_setup_complete(gadget->ep0, req);
++ }
++ }
++
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static void gmidi_disconnect(struct usb_gadget *gadget)
++{
++ struct gmidi_device *dev = get_gadget_data(gadget);
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev->lock, flags);
++ gmidi_reset_config(dev);
++
++ /* a more significant application might have some non-usb
++ * activities to quiesce here, saving resources like power
++ * or pushing the notification up a network stack.
++ */
++ spin_unlock_irqrestore(&dev->lock, flags);
++
++ /* next we may get setup() calls to enumerate new connections;
++ * or an unbind() during shutdown (including removing module).
++ */
++}
++
++static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
++{
++ struct gmidi_device *dev = get_gadget_data(gadget);
++ struct snd_card* card;
++
++ DBG(dev, "unbind\n");
++
++ card = dev->card;
++ dev->card = NULL;
++ if (card) {
++ snd_card_free(card);
++ }
++
++ /* we've already been disconnected ... no i/o is active */
++ if (dev->req) {
++ dev->req->length = USB_BUFSIZ;
++ free_ep_req(gadget->ep0, dev->req);
++ }
++ kfree(dev);
++ set_gadget_data(gadget, NULL);
++}
++
++static int gmidi_snd_free(struct snd_device *device)
++{
++ return 0;
++}
++
++static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
++ uint8_t p1, uint8_t p2, uint8_t p3)
++{
++ unsigned length = req->length;
++
++ uint8_t* buf = (uint8_t*)req->buf + length;
++ buf[0] = p0;
++ buf[1] = p1;
++ buf[2] = p2;
++ buf[3] = p3;
++ req->length = length + 4;
++}
++
++/*
++ * Converts MIDI commands to USB MIDI packets.
++ */
++static void gmidi_transmit_byte(struct usb_request* req,
++ struct gmidi_in_port* port, uint8_t b)
++{
++ uint8_t p0 = port->cable;
++
++ if (b >= 0xf8) {
++ gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
++ } else if (b >= 0xf0) {
++ switch (b) {
++ case 0xf0:
++ port->data[0] = b;
++ port->state = STATE_SYSEX_1;
++ break;
++ case 0xf1:
++ case 0xf3:
++ port->data[0] = b;
++ port->state = STATE_1PARAM;
++ break;
++ case 0xf2:
++ port->data[0] = b;
++ port->state = STATE_2PARAM_1;
++ break;
++ case 0xf4:
++ case 0xf5:
++ port->state = STATE_UNKNOWN;
++ break;
++ case 0xf6:
++ gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
++ port->state = STATE_UNKNOWN;
++ break;
++ case 0xf7:
++ switch (port->state) {
++ case STATE_SYSEX_0:
++ gmidi_transmit_packet(req,
++ p0 | 0x05, 0xf7, 0, 0);
++ break;
++ case STATE_SYSEX_1:
++ gmidi_transmit_packet(req,
++ p0 | 0x06, port->data[0], 0xf7, 0);
++ break;
++ case STATE_SYSEX_2:
++ gmidi_transmit_packet(req,
++ p0 | 0x07, port->data[0],
++ port->data[1], 0xf7);
++ break;
++ }
++ port->state = STATE_UNKNOWN;
++ break;
++ }
++ } else if (b >= 0x80) {
++ port->data[0] = b;
++ if (b >= 0xc0 && b <= 0xdf)
++ port->state = STATE_1PARAM;
++ else
++ port->state = STATE_2PARAM_1;
++ } else { /* b < 0x80 */
++ switch (port->state) {
++ case STATE_1PARAM:
++ if (port->data[0] < 0xf0) {
++ p0 |= port->data[0] >> 4;
++ } else {
++ p0 |= 0x02;
++ port->state = STATE_UNKNOWN;
++ }
++ gmidi_transmit_packet(req, p0, port->data[0], b, 0);
++ break;
++ case STATE_2PARAM_1:
++ port->data[1] = b;
++ port->state = STATE_2PARAM_2;
++ break;
++ case STATE_2PARAM_2:
++ if (port->data[0] < 0xf0) {
++ p0 |= port->data[0] >> 4;
++ port->state = STATE_2PARAM_1;
++ } else {
++ p0 |= 0x03;
++ port->state = STATE_UNKNOWN;
++ }
++ gmidi_transmit_packet(req,
++ p0, port->data[0], port->data[1], b);
++ break;
++ case STATE_SYSEX_0:
++ port->data[0] = b;
++ port->state = STATE_SYSEX_1;
++ break;
++ case STATE_SYSEX_1:
++ port->data[1] = b;
++ port->state = STATE_SYSEX_2;
++ break;
++ case STATE_SYSEX_2:
++ gmidi_transmit_packet(req,
++ p0 | 0x04, port->data[0], port->data[1], b);
++ port->state = STATE_SYSEX_0;
++ break;
++ }
++ }
++}
++
++static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
++{
++ struct usb_ep* ep = dev->in_ep;
++ struct gmidi_in_port* port = &dev->in_port;
++
++ if (!ep) {
++ return;
++ }
++ if (!req) {
++ req = alloc_ep_req(ep, buflen);
++ }
++ if (!req) {
++ ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n");
++ return;
++ }
++ req->length = 0;
++ req->complete = gmidi_complete;
++
++ if (port->active) {
++ while (req->length + 3 < buflen) {
++ uint8_t b;
++ if (snd_rawmidi_transmit(dev->in_substream, &b, 1)
++ != 1)
++ {
++ port->active = 0;
++ break;
++ }
++ gmidi_transmit_byte(req, port, b);
++ }
++ }
++ if (req->length > 0) {
++ usb_ep_queue(ep, req, GFP_ATOMIC);
++ } else {
++ free_ep_req(ep, req);
++ }
++}
++
++static void gmidi_in_tasklet(unsigned long data)
++{
++ struct gmidi_device* dev = (struct gmidi_device*)data;
++
++ gmidi_transmit(dev, NULL);
++}
++
++static int gmidi_in_open(struct snd_rawmidi_substream *substream)
++{
++ struct gmidi_device* dev = substream->rmidi->private_data;
++
++ VDBG(dev, "gmidi_in_open\n");
++ dev->in_substream = substream;
++ dev->in_port.state = STATE_UNKNOWN;
++ return 0;
++}
++
++static int gmidi_in_close(struct snd_rawmidi_substream *substream)
++{
++ VDBG(dev, "gmidi_in_close\n");
++ return 0;
++}
++
++static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
++{
++ struct gmidi_device* dev = substream->rmidi->private_data;
++
++ VDBG(dev, "gmidi_in_trigger %d\n", up);
++ dev->in_port.active = up;
++ if (up) {
++ tasklet_hi_schedule(&dev->tasklet);
++ }
++}
++
++static int gmidi_out_open(struct snd_rawmidi_substream *substream)
++{
++ struct gmidi_device* dev = substream->rmidi->private_data;
++
++ VDBG(dev, "gmidi_out_open\n");
++ dev->out_substream = substream;
++ return 0;
++}
++
++static int gmidi_out_close(struct snd_rawmidi_substream *substream)
++{
++ VDBG(dev, "gmidi_out_close\n");
++ return 0;
++}
++
++static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
++{
++ struct gmidi_device* dev = substream->rmidi->private_data;
++
++ VDBG(dev, "gmidi_out_trigger %d\n", up);
++ if (up) {
++ set_bit(substream->number, &dev->out_triggered);
++ } else {
++ clear_bit(substream->number, &dev->out_triggered);
++ }
++}
++
++static struct snd_rawmidi_ops gmidi_in_ops = {
++ .open = gmidi_in_open,
++ .close = gmidi_in_close,
++ .trigger = gmidi_in_trigger,
++};
++
++static struct snd_rawmidi_ops gmidi_out_ops = {
++ .open = gmidi_out_open,
++ .close = gmidi_out_close,
++ .trigger = gmidi_out_trigger
++};
++
++/* register as a sound "card" */
++static int gmidi_register_card(struct gmidi_device *dev)
++{
++ struct snd_card *card;
++ struct snd_rawmidi *rmidi;
++ int err;
++ int out_ports = 1;
++ int in_ports = 1;
++ static struct snd_device_ops ops = {
++ .dev_free = gmidi_snd_free,
++ };
++
++ card = snd_card_new(index, id, THIS_MODULE, 0);
++ if (!card) {
++ ERROR(dev, "snd_card_new failed\n");
++ err = -ENOMEM;
++ goto fail;
++ }
++ dev->card = card;
++
++ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops);
++ if (err < 0) {
++ ERROR(dev, "snd_device_new failed: error %d\n", err);
++ goto fail;
++ }
++
++ strcpy(card->driver, longname);
++ strcpy(card->longname, longname);
++ strcpy(card->shortname, shortname);
++
++ /* Set up rawmidi */
++ dev->in_port.dev = dev;
++ dev->in_port.active = 0;
++ snd_component_add(card, "MIDI");
++ err = snd_rawmidi_new(card, "USB MIDI Gadget", 0,
++ out_ports, in_ports, &rmidi);
++ if (err < 0) {
++ ERROR(dev, "snd_rawmidi_new failed: error %d\n", err);
++ goto fail;
++ }
++ dev->rmidi = rmidi;
++ strcpy(rmidi->name, card->shortname);
++ rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
++ SNDRV_RAWMIDI_INFO_INPUT |
++ SNDRV_RAWMIDI_INFO_DUPLEX;
++ rmidi->private_data = dev;
++
++ /* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
++ It's an upside-down world being a gadget. */
++ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
++ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
++
++ snd_card_set_dev(card, &dev->gadget->dev);
++
++ /* register it - we're ready to go */
++ err = snd_card_register(card);
++ if (err < 0) {
++ ERROR(dev, "snd_card_register failed\n");
++ goto fail;
++ }
++
++ VDBG(dev, "gmidi_register_card finished ok\n");
++ return 0;
++
++fail:
++ if (dev->card) {
++ snd_card_free(dev->card);
++ dev->card = NULL;
++ }
++ return err;
++}
++
++/*
++ * Creates an output endpoint, and initializes output ports.
++ */
++static int __devinit gmidi_bind(struct usb_gadget *gadget)
++{
++ struct gmidi_device *dev;
++ struct usb_ep *in_ep, *out_ep;
++ int gcnum, err = 0;
++
++ /* support optional vendor/distro customization */
++ if (idVendor) {
++ if (!idProduct) {
++ printk(KERN_ERR "idVendor needs idProduct!\n");
++ return -ENODEV;
++ }
++ device_desc.idVendor = cpu_to_le16(idVendor);
++ device_desc.idProduct = cpu_to_le16(idProduct);
++ if (bcdDevice) {
++ device_desc.bcdDevice = cpu_to_le16(bcdDevice);
++ }
++ }
++ if (iManufacturer) {
++ strlcpy(manufacturer, iManufacturer, sizeof(manufacturer));
++ } else {
++ snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
++ init_utsname()->sysname, init_utsname()->release,
++ gadget->name);
++ }
++ if (iProduct) {
++ strlcpy(product_desc, iProduct, sizeof(product_desc));
++ }
++ if (iSerialNumber) {
++ device_desc.iSerialNumber = STRING_SERIAL,
++ strlcpy(serial_number, iSerialNumber, sizeof(serial_number));
++ }
++
++ /* Bulk-only drivers like this one SHOULD be able to
++ * autoconfigure on any sane usb controller driver,
++ * but there may also be important quirks to address.
++ */
++ usb_ep_autoconfig_reset(gadget);
++ in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
++ if (!in_ep) {
++autoconf_fail:
++ printk(KERN_ERR "%s: can't autoconfigure on %s\n",
++ shortname, gadget->name);
++ return -ENODEV;
++ }
++ EP_IN_NAME = in_ep->name;
++ in_ep->driver_data = in_ep; /* claim */
++
++ out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc);
++ if (!out_ep) {
++ goto autoconf_fail;
++ }
++ EP_OUT_NAME = out_ep->name;
++ out_ep->driver_data = out_ep; /* claim */
++
++ gcnum = usb_gadget_controller_number(gadget);
++ if (gcnum >= 0) {
++ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
++ } else {
++ /* gmidi is so simple (no altsettings) that
++ * it SHOULD NOT have problems with bulk-capable hardware.
++ * so warn about unrecognized controllers, don't panic.
++ */
++ printk(KERN_WARNING "%s: controller '%s' not recognized\n",
++ shortname, gadget->name);
++ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
++ }
++
++
++ /* ok, we made sense of the hardware ... */
++ dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
++ if (!dev) {
++ return -ENOMEM;
++ }
++ spin_lock_init(&dev->lock);
++ dev->gadget = gadget;
++ dev->in_ep = in_ep;
++ dev->out_ep = out_ep;
++ set_gadget_data(gadget, dev);
++ tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
++
++ /* preallocate control response and buffer */
++ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
++ if (!dev->req) {
++ err = -ENOMEM;
++ goto fail;
++ }
++ dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
++ &dev->req->dma, GFP_KERNEL);
++ if (!dev->req->buf) {
++ err = -ENOMEM;
++ goto fail;
++ }
++
++ dev->req->complete = gmidi_setup_complete;
++
++ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
++
++ gadget->ep0->driver_data = dev;
++
++ INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
++ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
++ EP_OUT_NAME, EP_IN_NAME);
++
++ /* register as an ALSA sound card */
++ err = gmidi_register_card(dev);
++ if (err < 0) {
++ goto fail;
++ }
++
++ VDBG(dev, "gmidi_bind finished ok\n");
++ return 0;
++
++fail:
++ gmidi_unbind(gadget);
++ return err;
++}
++
++
++static void gmidi_suspend(struct usb_gadget *gadget)
++{
++ struct gmidi_device *dev = get_gadget_data(gadget);
++
++ if (gadget->speed == USB_SPEED_UNKNOWN) {
++ return;
++ }
++
++ DBG(dev, "suspend\n");
++}
++
++static void gmidi_resume(struct usb_gadget *gadget)
++{
++ struct gmidi_device *dev = get_gadget_data(gadget);
++
++ DBG(dev, "resume\n");
++}
++
++
++static struct usb_gadget_driver gmidi_driver = {
++ .speed = USB_SPEED_FULL,
++ .function = (char *)longname,
++ .bind = gmidi_bind,
++ .unbind = __exit_p(gmidi_unbind),
++
++ .setup = gmidi_setup,
++ .disconnect = gmidi_disconnect,
++
++ .suspend = gmidi_suspend,
++ .resume = gmidi_resume,
++
++ .driver = {
++ .name = (char *)shortname,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init gmidi_init(void)
++{
++ return usb_gadget_register_driver(&gmidi_driver);
++}
++module_init(gmidi_init);
++
++static void __exit gmidi_cleanup(void)
++{
++ usb_gadget_unregister_driver(&gmidi_driver);
++}
++module_exit(gmidi_cleanup);
++
+diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
+index 7cf2999..a3076da 100644
+--- a/drivers/usb/gadget/goku_udc.c
++++ b/drivers/usb/gadget/goku_udc.c
+@@ -1628,7 +1628,7 @@ stall:
+ handled = 1; \
+ }
+
+-static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r)
++static irqreturn_t goku_irq(int irq, void *_dev)
+ {
+ struct goku_udc *dev = _dev;
+ struct goku_udc_regs __iomem *regs = dev->regs;
+diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
+index 3bdc5e3..86924f9 100644
+--- a/drivers/usb/gadget/inode.c
++++ b/drivers/usb/gadget/inode.c
+@@ -32,6 +32,7 @@
+ #include <linux/compiler.h>
+ #include <asm/uaccess.h>
+ #include <linux/slab.h>
++#include <linux/poll.h>
+
+ #include <linux/device.h>
+ #include <linux/moduleparam.h>
+@@ -222,7 +223,6 @@ static void put_ep (struct ep_data *data
+ /* needs no more cleanup */
+ BUG_ON (!list_empty (&data->epfiles));
+ BUG_ON (waitqueue_active (&data->wait));
+- BUG_ON (down_trylock (&data->lock) != 0);
+ kfree (data);
+ }
+
+@@ -342,7 +342,7 @@ fail:
+ static ssize_t
+ ep_io (struct ep_data *epdata, void *buf, unsigned len)
+ {
+- DECLARE_COMPLETION (done);
++ DECLARE_COMPLETION_ONSTACK (done);
+ int value;
+
+ spin_lock_irq (&epdata->dev->lock);
+@@ -477,6 +477,10 @@ static int
+ ep_release (struct inode *inode, struct file *fd)
+ {
+ struct ep_data *data = fd->private_data;
++ int value;
++
++ if ((value = down_interruptible(&data->lock)) < 0)
++ return value;
+
+ /* clean up if this can be reopened */
+ if (data->state != STATE_EP_UNBOUND) {
+@@ -485,6 +489,7 @@ ep_release (struct inode *inode, struct
+ data->hs_desc.bDescriptorType = 0;
+ usb_ep_disable(data->ep);
+ }
++ up (&data->lock);
+ put_ep (data);
+ return 0;
+ }
+@@ -528,7 +533,8 @@ struct kiocb_priv {
+ struct usb_request *req;
+ struct ep_data *epdata;
+ void *buf;
+- char __user *ubuf; /* NULL for writes */
++ const struct iovec *iv;
++ unsigned long nr_segs;
+ unsigned actual;
+ };
+
+@@ -556,17 +562,32 @@ static int ep_aio_cancel(struct kiocb *i
+ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
+ {
+ struct kiocb_priv *priv = iocb->private;
+- ssize_t status = priv->actual;
+-
+- /* we "retry" to get the right mm context for this: */
+- status = copy_to_user(priv->ubuf, priv->buf, priv->actual);
+- if (unlikely(0 != status))
+- status = -EFAULT;
+- else
+- status = priv->actual;
+- kfree(priv->buf);
+- kfree(priv);
+- return status;
++ ssize_t len, total;
++ int i;
++
++ /* we "retry" to get the right mm context for this: */
++
++ /* copy stuff into user buffers */
++ total = priv->actual;
++ len = 0;
++ for (i=0; i < priv->nr_segs; i++) {
++ ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
++
++ if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
++ if (len == 0)
++ len = -EFAULT;
++ break;
++ }
++
++ total -= this;
++ len += this;
++ if (total == 0)
++ break;
++ }
++ kfree(priv->buf);
++ kfree(priv);
++ aio_put_req(iocb);
++ return len;
+ }
+
+ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
+@@ -579,7 +600,7 @@ static void ep_aio_complete(struct usb_e
+ spin_lock(&epdata->dev->lock);
+ priv->req = NULL;
+ priv->epdata = NULL;
+- if (priv->ubuf == NULL
++ if (priv->iv == NULL
+ || unlikely(req->actual == 0)
+ || unlikely(kiocbIsCancelled(iocb))) {
+ kfree(req->buf);
+@@ -614,7 +635,8 @@ ep_aio_rwtail(
+ char *buf,
+ size_t len,
+ struct ep_data *epdata,
+- char __user *ubuf
++ const struct iovec *iv,
++ unsigned long nr_segs
+ )
+ {
+ struct kiocb_priv *priv;
+@@ -629,7 +651,8 @@ fail:
+ return value;
+ }
+ iocb->private = priv;
+- priv->ubuf = ubuf;
++ priv->iv = iv;
++ priv->nr_segs = nr_segs;
+
+ value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
+ if (unlikely(value < 0)) {
+@@ -669,47 +692,59 @@ fail:
+ kfree(priv);
+ put_ep(epdata);
+ } else
+- value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED);
++ value = (iv ? -EIOCBRETRY : -EIOCBQUEUED);
+ return value;
+ }
+
+ static ssize_t
+-ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o)
++ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t o)
+ {
+ struct ep_data *epdata = iocb->ki_filp->private_data;
+ char *buf;
+
+ if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
+ return -EINVAL;
+- buf = kmalloc(len, GFP_KERNEL);
++
++ buf = kmalloc(iocb->ki_left, GFP_KERNEL);
+ if (unlikely(!buf))
+ return -ENOMEM;
++
+ iocb->ki_retry = ep_aio_read_retry;
+- return ep_aio_rwtail(iocb, buf, len, epdata, ubuf);
++ return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
+ }
+
+ static ssize_t
+-ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
++ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t o)
+ {
+ struct ep_data *epdata = iocb->ki_filp->private_data;
+ char *buf;
++ size_t len = 0;
++ int i = 0;
+
+ if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
+ return -EINVAL;
+- buf = kmalloc(len, GFP_KERNEL);
++
++ buf = kmalloc(iocb->ki_left, GFP_KERNEL);
+ if (unlikely(!buf))
+ return -ENOMEM;
+- if (unlikely(copy_from_user(buf, ubuf, len) != 0)) {
+- kfree(buf);
+- return -EFAULT;
++
++ for (i=0; i < nr_segs; i++) {
++ if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
++ iov[i].iov_len) != 0)) {
++ kfree(buf);
++ return -EFAULT;
++ }
++ len += iov[i].iov_len;
+ }
+- return ep_aio_rwtail(iocb, buf, len, epdata, NULL);
++ return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
+ }
+
+ /*----------------------------------------------------------------------*/
+
+ /* used after endpoint configuration */
+-static struct file_operations ep_io_operations = {
++static const struct file_operations ep_io_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+
+@@ -741,7 +776,7 @@ ep_config (struct file *fd, const char _
+ struct ep_data *data = fd->private_data;
+ struct usb_ep *ep;
+ u32 tag;
+- int value;
++ int value, length = len;
+
+ if ((value = down_interruptible (&data->lock)) < 0)
+ return value;
+@@ -792,7 +827,6 @@ ep_config (struct file *fd, const char _
+ goto fail0;
+ }
+ }
+- value = len;
+
+ spin_lock_irq (&data->dev->lock);
+ if (data->dev->state == STATE_DEV_UNBOUND) {
+@@ -822,8 +856,10 @@ ep_config (struct file *fd, const char _
+ data->name);
+ data->state = STATE_EP_DEFER_ENABLE;
+ }
+- if (value == 0)
++ if (value == 0) {
+ fd->f_op = &ep_io_operations;
++ value = length;
++ }
+ gone:
+ spin_unlock_irq (&data->dev->lock);
+ if (value < 0) {
+@@ -844,7 +880,7 @@ fail1:
+ static int
+ ep_open (struct inode *inode, struct file *fd)
+ {
+- struct ep_data *data = inode->u.generic_ip;
++ struct ep_data *data = inode->i_private;
+ int value = -EBUSY;
+
+ if (down_interruptible (&data->lock) != 0)
+@@ -867,7 +903,7 @@ ep_open (struct inode *inode, struct fil
+ }
+
+ /* used before endpoint configuration */
+-static struct file_operations ep_config_operations = {
++static const struct file_operations ep_config_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+
+@@ -1009,7 +1045,7 @@ ep0_read (struct file *fd, char __user *
+ else {
+ len = min (len, (size_t)dev->req->actual);
+ // FIXME don't call this with the spinlock held ...
+- if (copy_to_user (buf, &dev->req->buf, len))
++ if (copy_to_user (buf, dev->req->buf, len))
+ retval = -EFAULT;
+ clean_req (dev->gadget->ep0, dev->req);
+ /* NOTE userspace can't yet choose to stall */
+@@ -1229,6 +1265,35 @@ dev_release (struct inode *inode, struct
+ return 0;
+ }
+
++static unsigned int
++ep0_poll (struct file *fd, poll_table *wait)
++{
++ struct dev_data *dev = fd->private_data;
++ int mask = 0;
++
++ poll_wait(fd, &dev->wait, wait);
++
++ spin_lock_irq (&dev->lock);
++
++ /* report fd mode change before acting on it */
++ if (dev->setup_abort) {
++ dev->setup_abort = 0;
++ mask = POLLHUP;
++ goto out;
++ }
++
++ if (dev->state == STATE_SETUP) {
++ if (dev->setup_in || dev->setup_can_stall)
++ mask = POLLOUT;
++ } else {
++ if (dev->ev_next != 0)
++ mask = POLLIN;
++ }
++out:
++ spin_unlock_irq(&dev->lock);
++ return mask;
++}
++
+ static int dev_ioctl (struct inode *inode, struct file *fd,
+ unsigned code, unsigned long value)
+ {
+@@ -1241,14 +1306,14 @@ static int dev_ioctl (struct inode *inod
+ }
+
+ /* used after device configuration */
+-static struct file_operations ep0_io_operations = {
++static const struct file_operations ep0_io_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+
+ .read = ep0_read,
+ .write = ep0_write,
+ .fasync = ep0_fasync,
+- // .poll = ep0_poll,
++ .poll = ep0_poll,
+ .ioctl = dev_ioctl,
+ .release = dev_release,
+ };
+@@ -1696,16 +1761,17 @@ gadgetfs_disconnect (struct usb_gadget *
+ {
+ struct dev_data *dev = get_gadget_data (gadget);
+
++ spin_lock (&dev->lock);
+ if (dev->state == STATE_UNCONNECTED) {
+ DBG (dev, "already unconnected\n");
+- return;
++ goto exit;
+ }
+ dev->state = STATE_UNCONNECTED;
+
+ INFO (dev, "disconnected\n");
+- spin_lock (&dev->lock);
+ next_event (dev, GADGETFS_DISCONNECT);
+ ep0_readable (dev);
++exit:
+ spin_unlock (&dev->lock);
+ }
+
+@@ -1909,7 +1975,7 @@ fail:
+ static int
+ dev_open (struct inode *inode, struct file *fd)
+ {
+- struct dev_data *dev = inode->u.generic_ip;
++ struct dev_data *dev = inode->i_private;
+ int value = -EBUSY;
+
+ if (dev->state == STATE_DEV_DISABLED) {
+@@ -1922,7 +1988,7 @@ dev_open (struct inode *inode, struct fi
+ return value;
+ }
+
+-static struct file_operations dev_init_operations = {
++static const struct file_operations dev_init_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+
+@@ -1966,11 +2032,10 @@ gadgetfs_make_inode (struct super_block
+ inode->i_mode = mode;
+ inode->i_uid = default_uid;
+ inode->i_gid = default_gid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime
+ = CURRENT_TIME;
+- inode->u.generic_ip = data;
++ inode->i_private = data;
+ inode->i_fop = fops;
+ }
+ return inode;
+diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
+index 36db725..1792596 100644
+--- a/drivers/usb/gadget/lh7a40x_udc.c
++++ b/drivers/usb/gadget/lh7a40x_udc.c
+@@ -922,7 +922,7 @@ static void lh7a40x_reset_intr(struct lh
+ /*
+ * lh7a40x usb client interrupt handler.
+ */
+-static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev, struct pt_regs *r)
++static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev)
+ {
+ struct lh7a40x_udc *dev = _dev;
+
+diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
+index 0924323..3acc896 100644
+--- a/drivers/usb/gadget/net2280.c
++++ b/drivers/usb/gadget/net2280.c
+@@ -2,7 +2,7 @@
+ * Driver for the PLX NET2280 USB device controller.
+ * Specs and errata are available from <http://www.plxtech.com>.
+ *
+- * PLX Technology Inc. (formerly NetChip Technology) supported the
++ * PLX Technology Inc. (formerly NetChip Technology) supported the
+ * development of this driver.
+ *
+ *
+@@ -26,7 +26,8 @@
+ * Copyright (C) 2003 David Brownell
+ * Copyright (C) 2003-2005 PLX Technology, Inc.
+ *
+- * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
++ * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility
++ * with 2282 chip
+ *
+ * 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
+@@ -85,7 +86,7 @@ static const char driver_name [] = "net2
+ static const char driver_desc [] = DRIVER_DESC;
+
+ static const char ep0name [] = "ep0";
+-static const char *ep_name [] = {
++static const char *const ep_name [] = {
+ ep0name,
+ "ep-a", "ep-b", "ep-c", "ep-d",
+ "ep-e", "ep-f",
+@@ -225,7 +226,9 @@ net2280_enable (struct usb_ep *_ep, cons
+ if (!ep->is_in)
+ writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+ else if (dev->pdev->device != 0x2280) {
+- /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
++ /* Added for 2282, Don't use nak packets on an in endpoint,
++ * this was ignored on 2280
++ */
+ writel ((1 << CLEAR_NAK_OUT_PACKETS)
+ | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
+ }
+@@ -288,7 +291,7 @@ static int handshake (u32 __iomem *ptr,
+ return -ETIMEDOUT;
+ }
+
+-static struct usb_ep_ops net2280_ep_ops;
++static const struct usb_ep_ops net2280_ep_ops;
+
+ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
+ {
+@@ -449,34 +452,15 @@ net2280_free_request (struct usb_ep *_ep
+
+ /*-------------------------------------------------------------------------*/
+
+-#undef USE_KMALLOC
+-
+-/* many common platforms have dma-coherent caches, which means that it's
+- * safe to use kmalloc() memory for all i/o buffers without using any
+- * cache flushing calls. (unless you're trying to share cache lines
+- * between dma and non-dma activities, which is a slow idea in any case.)
++/*
++ * dma-coherent memory allocation (for dma-capable endpoints)
+ *
+- * other platforms need more care, with 2.5 having a moderately general
+- * solution (which falls down for allocations smaller than one page)
+- * that improves significantly on the 2.4 PCI allocators by removing
+- * the restriction that memory never be freed in_interrupt().
++ * NOTE: the dma_*_coherent() API calls suck. Most implementations are
++ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
++ * respect to calls with irqs disabled: alloc is safe, free is not.
++ * We currently work around (b), but not (a).
+ */
+-#if defined(CONFIG_X86)
+-#define USE_KMALLOC
+-
+-#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+-#define USE_KMALLOC
+-
+-#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
+-#define USE_KMALLOC
+
+-/* FIXME there are other cases, including an x86-64 one ... */
+-#endif
+-
+-/* allocating buffers this way eliminates dma mapping overhead, which
+- * on some platforms will mean eliminating a per-io buffer copy. with
+- * some kinds of system caches, further tweaks may still be needed.
+- */
+ static void *
+ net2280_alloc_buffer (
+ struct usb_ep *_ep,
+@@ -493,43 +477,71 @@ net2280_alloc_buffer (
+ return NULL;
+ *dma = DMA_ADDR_INVALID;
+
+-#if defined(USE_KMALLOC)
+- retval = kmalloc(bytes, gfp_flags);
+- if (retval)
+- *dma = virt_to_phys(retval);
+-#else
+- if (ep->dma) {
+- /* the main problem with this call is that it wastes memory
+- * on typical 1/N page allocations: it allocates 1-N pages.
+- */
+-#warning Using dma_alloc_coherent even with buffers smaller than a page.
++ if (ep->dma)
+ retval = dma_alloc_coherent(&ep->dev->pdev->dev,
+ bytes, dma, gfp_flags);
+- } else
++ else
+ retval = kmalloc(bytes, gfp_flags);
+-#endif
+ return retval;
+ }
+
++static DEFINE_SPINLOCK(buflock);
++static LIST_HEAD(buffers);
++
++struct free_record {
++ struct list_head list;
++ struct device *dev;
++ unsigned bytes;
++ dma_addr_t dma;
++};
++
++static void do_free(unsigned long ignored)
++{
++ spin_lock_irq(&buflock);
++ while (!list_empty(&buffers)) {
++ struct free_record *buf;
++
++ buf = list_entry(buffers.next, struct free_record, list);
++ list_del(&buf->list);
++ spin_unlock_irq(&buflock);
++
++ dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
++
++ spin_lock_irq(&buflock);
++ }
++ spin_unlock_irq(&buflock);
++}
++
++static DECLARE_TASKLET(deferred_free, do_free, 0);
++
+ static void
+ net2280_free_buffer (
+ struct usb_ep *_ep,
+- void *buf,
++ void *address,
+ dma_addr_t dma,
+ unsigned bytes
+ ) {
+ /* free memory into the right allocator */
+-#ifndef USE_KMALLOC
+ if (dma != DMA_ADDR_INVALID) {
+ struct net2280_ep *ep;
++ struct free_record *buf = address;
++ unsigned long flags;
+
+ ep = container_of(_ep, struct net2280_ep, ep);
+ if (!_ep)
+ return;
+- dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
++
++ ep = container_of (_ep, struct net2280_ep, ep);
++ buf->dev = &ep->dev->pdev->dev;
++ buf->bytes = bytes;
++ buf->dma = dma;
++
++ spin_lock_irqsave(&buflock, flags);
++ list_add_tail(&buf->list, &buffers);
++ tasklet_schedule(&deferred_free);
++ spin_unlock_irqrestore(&buflock, flags);
+ } else
+-#endif
+- kfree (buf);
++ kfree (address);
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -737,7 +749,8 @@ fill_dma_desc (struct net2280_ep *ep, st
+ */
+ if (ep->is_in)
+ dmacount |= (1 << DMA_DIRECTION);
+- if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
++ if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0)
++ || ep->dev->pdev->device != 0x2280)
+ dmacount |= (1 << END_OF_CHAIN);
+
+ req->valid = valid;
+@@ -812,7 +825,7 @@ static void start_dma (struct net2280_ep
+
+ /* previous OUT packet might have been short */
+ if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
+- & (1 << NAK_OUT_PACKETS)) != 0) {
++ & (1 << NAK_OUT_PACKETS)) != 0) {
+ writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
+ &ep->regs->ep_stat);
+
+@@ -1373,7 +1386,7 @@ net2280_fifo_flush (struct usb_ep *_ep)
+ (void) readl (&ep->regs->ep_rsp);
+ }
+
+-static struct usb_ep_ops net2280_ep_ops = {
++static const struct usb_ep_ops net2280_ep_ops = {
+ .enable = net2280_enable,
+ .disable = net2280_disable,
+
+@@ -1631,7 +1644,7 @@ show_registers (struct device *_dev, str
+ }
+
+ /* Indexed Registers */
+- // none yet
++ // none yet
+
+ /* Statistics */
+ t = scnprintf (next, size, "\nirqs: ");
+@@ -1691,11 +1704,11 @@ show_queues (struct device *_dev, struct
+ ({ char *val;
+ switch (d->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+- val = "bulk"; break;
++ val = "bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+- val = "intr"; break;
++ val = "intr"; break;
+ default:
+- val = "iso"; break;
++ val = "iso"; break;
+ }; val; }),
+ le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
+ ep->dma ? "dma" : "pio", ep->fifo_size
+@@ -1761,8 +1774,8 @@ static DEVICE_ATTR (queues, S_IRUGO, sho
+
+ #else
+
+-#define device_create_file(a,b) do {} while (0)
+-#define device_remove_file device_create_file
++#define device_create_file(a,b) (0)
++#define device_remove_file(a,b) do { } while (0)
+
+ #endif
+
+@@ -1808,8 +1821,8 @@ extern int net2280_set_fifo_mode (struct
+ * net2280_set_fifo_mode - change allocation of fifo buffers
+ * @gadget: access to the net2280 device that will be updated
+ * @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
+- * 1 for two 2kB buffers (ep-a and ep-b only);
+- * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
++ * 1 for two 2kB buffers (ep-a and ep-b only);
++ * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
+ *
+ * returns zero on success, else negative errno. when this succeeds,
+ * the contents of gadget->ep_list may have changed.
+@@ -2031,8 +2044,10 @@ int usb_gadget_register_driver (struct u
+ return retval;
+ }
+
+- device_create_file (&dev->pdev->dev, &dev_attr_function);
+- device_create_file (&dev->pdev->dev, &dev_attr_queues);
++ retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
++ if (retval) goto err_unbind;
++ retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
++ if (retval) goto err_func;
+
+ /* ... then enable host detection and ep0; and we're ready
+ * for set_configuration as well as eventual disconnect.
+@@ -2047,6 +2062,14 @@ int usb_gadget_register_driver (struct u
+
+ /* pci writes may still be posted */
+ return 0;
++
++err_func:
++ device_remove_file (&dev->pdev->dev, &dev_attr_function);
++err_unbind:
++ driver->unbind (&dev->gadget);
++ dev->gadget.dev.driver = NULL;
++ dev->driver = NULL;
++ return retval;
+ }
+ EXPORT_SYMBOL (usb_gadget_register_driver);
+
+@@ -2241,7 +2264,8 @@ static void handle_ep_small (struct net2
+ req->td->dmacount = 0;
+ t = readl (&ep->regs->ep_avail);
+ dma_done (ep, req, count,
+- (ep->out_overflow || t) ? -EOVERFLOW : 0);
++ (ep->out_overflow || t)
++ ? -EOVERFLOW : 0);
+ }
+
+ /* also flush to prevent erratum 0106 trouble */
+@@ -2411,7 +2435,7 @@ static void handle_stat0_irqs (struct ne
+ , &ep->regs->ep_stat);
+ u.raw [0] = readl (&dev->usb->setup0123);
+ u.raw [1] = readl (&dev->usb->setup4567);
+-
++
+ cpu_to_le32s (&u.raw [0]);
+ cpu_to_le32s (&u.raw [1]);
+
+@@ -2578,14 +2602,16 @@ static void handle_stat1_irqs (struct ne
+
+ /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
+ * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
+- * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
++ * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
+ * only indicates a change in the reset state).
+ */
+ if (stat & tmp) {
+ writel (tmp, &dev->regs->irqstat1);
+- if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
+- ((readl (&dev->usb->usbstat) & mask) == 0))
+- || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0)
++ if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
++ && ((readl (&dev->usb->usbstat) & mask)
++ == 0))
++ || ((readl (&dev->usb->usbctl)
++ & (1 << VBUS_PIN)) == 0)
+ ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
+ DEBUG (dev, "disconnect %s\n",
+ dev->driver->driver.name);
+@@ -2737,7 +2763,7 @@ static void handle_stat1_irqs (struct ne
+ DEBUG (dev, "unhandled irqstat1 %08x\n", stat);
+ }
+
+-static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r)
++static irqreturn_t net2280_irq (int irq, void *_dev)
+ {
+ struct net2280 *dev = _dev;
+
+@@ -2852,7 +2878,7 @@ static int net2280_probe (struct pci_dev
+
+ /* now all the pci goodies ... */
+ if (pci_enable_device (pdev) < 0) {
+- retval = -ENODEV;
++ retval = -ENODEV;
+ goto done;
+ }
+ dev->enabled = 1;
+@@ -2870,6 +2896,10 @@ static int net2280_probe (struct pci_dev
+ }
+ dev->region = 1;
+
++ /* FIXME provide firmware download interface to put
++ * 8051 code into the chip, e.g. to turn on PCI PM.
++ */
++
+ base = ioremap_nocache (resource, len);
+ if (base == NULL) {
+ DEBUG (dev, "can't map memory\n");
+@@ -2954,8 +2984,10 @@ static int net2280_probe (struct pci_dev
+ : "disabled");
+ the_controller = dev;
+
+- device_register (&dev->gadget.dev);
+- device_create_file (&pdev->dev, &dev_attr_registers);
++ retval = device_register (&dev->gadget.dev);
++ if (retval) goto done;
++ retval = device_create_file (&pdev->dev, &dev_attr_registers);
++ if (retval) goto done;
+
+ return 0;
+
+@@ -2984,16 +3016,16 @@ static void net2280_shutdown (struct pci
+
+ /*-------------------------------------------------------------------------*/
+
+-static struct pci_device_id pci_ids [] = { {
+- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+- .class_mask = ~0,
++static const struct pci_device_id pci_ids [] = { {
++ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
++ .class_mask = ~0,
+ .vendor = 0x17cc,
+ .device = 0x2280,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ }, {
+- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+- .class_mask = ~0,
++ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
++ .class_mask = ~0,
+ .vendor = 0x17cc,
+ .device = 0x2282,
+ .subvendor = PCI_ANY_ID,
+diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
+index 2de9748..48a09fd 100644
+--- a/drivers/usb/gadget/omap_udc.c
++++ b/drivers/usb/gadget/omap_udc.c
+@@ -40,7 +40,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/usb_ch9.h>
+ #include <linux/usb_gadget.h>
+-#include <linux/usb_otg.h>
++#include <linux/usb/otg.h>
+ #include <linux/dma-mapping.h>
+
+ #include <asm/byteorder.h>
+@@ -1815,8 +1815,7 @@ static void devstate_irq(struct omap_udc
+ UDC_IRQ_SRC_REG = UDC_DS_CHG;
+ }
+
+-static irqreturn_t
+-omap_udc_irq(int irq, void *_udc, struct pt_regs *r)
++static irqreturn_t omap_udc_irq(int irq, void *_udc)
+ {
+ struct omap_udc *udc = _udc;
+ u16 irq_src;
+@@ -1888,8 +1887,7 @@ static void pio_out_timer(unsigned long
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ }
+
+-static irqreturn_t
+-omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
++static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
+ {
+ u16 epn_stat, irq_src;
+ irqreturn_t status = IRQ_NONE;
+@@ -1968,8 +1966,7 @@ omap_udc_pio_irq(int irq, void *_dev, st
+ }
+
+ #ifdef USE_ISO
+-static irqreturn_t
+-omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
++static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
+ {
+ struct omap_udc *udc = _dev;
+ struct omap_ep *ep;
+@@ -2437,7 +2434,7 @@ static int proc_udc_open(struct inode *i
+ return single_open(file, proc_udc_show, NULL);
+ }
+
+-static struct file_operations proc_ops = {
++static const struct file_operations proc_ops = {
+ .open = proc_udc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -2869,7 +2866,7 @@ cleanup0:
+
+ static int __exit omap_udc_remove(struct platform_device *pdev)
+ {
+- DECLARE_COMPLETION(done);
++ DECLARE_COMPLETION_ONSTACK(done);
+
+ if (!udc)
+ return -ENODEV;
+diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
+index fff027d..671c24b 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.c
++++ b/drivers/usb/gadget/pxa2xx_udc.c
+@@ -43,11 +43,11 @@
+ #include <linux/mm.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
++#include <linux/irq.h>
+
+ #include <asm/byteorder.h>
+ #include <asm/dma.h>
+ #include <asm/io.h>
+-#include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/mach-types.h>
+ #include <asm/unaligned.h>
+@@ -110,7 +110,7 @@ static int use_dma = 1;
+ module_param(use_dma, bool, 0);
+ MODULE_PARM_DESC (use_dma, "true to use dma");
+
+-static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r);
++static void dma_nodesc_handler (int dmach, void *_ep);
+ static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
+
+ #ifdef USE_OUT_DMA
+@@ -150,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc
+ static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
+ static void nuke (struct pxa2xx_ep *, int status);
+
++/* one GPIO should be used to detect VBUS from the host */
++static int is_vbus_present(void)
++{
++ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
++
++ if (mach->gpio_vbus)
++ return pxa_gpio_get(mach->gpio_vbus);
++ if (mach->udc_is_connected)
++ return mach->udc_is_connected();
++ return 1;
++}
++
++/* one GPIO should control a D+ pullup, so host sees this device (or not) */
++static void pullup_off(void)
++{
++ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
++
++ if (mach->gpio_pullup)
++ pxa_gpio_set(mach->gpio_pullup, 0);
++ else if (mach->udc_command)
++ mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
++}
++
++static void pullup_on(void)
++{
++ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
++
++ if (mach->gpio_pullup)
++ pxa_gpio_set(mach->gpio_pullup, 1);
++ else if (mach->udc_command)
++ mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
++}
++
+ static void pio_irq_enable(int bEndpointAddress)
+ {
+ bEndpointAddress &= 0xf;
+@@ -795,7 +828,7 @@ static void cancel_dma(struct pxa2xx_ep
+ }
+
+ /* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
+-static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r)
++static void dma_nodesc_handler(int dmach, void *_ep)
+ {
+ struct pxa2xx_ep *ep = _ep;
+ struct pxa2xx_request *req;
+@@ -1691,7 +1724,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driv
+ */
+
+ static irqreturn_t
+-lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
++lubbock_vbus_irq(int irq, void *_dev)
+ {
+ struct pxa2xx_udc *dev = _dev;
+ int vbus;
+@@ -1721,6 +1754,15 @@ lubbock_vbus_irq(int irq, void *_dev, st
+
+ #endif
+
++static irqreturn_t udc_vbus_irq(int irq, void *_dev)
++{
++ struct pxa2xx_udc *dev = _dev;
++ int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
++
++ pxa2xx_udc_vbus_session(&dev->gadget, vbus);
++ return IRQ_HANDLED;
++}
++
+
+ /*-------------------------------------------------------------------------*/
+
+@@ -2041,7 +2083,7 @@ static void handle_ep(struct pxa2xx_ep *
+ * could cause usb protocol errors.
+ */
+ static irqreturn_t
+-pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
++pxa2xx_udc_irq(int irq, void *_dev)
+ {
+ struct pxa2xx_udc *dev = _dev;
+ int handled;
+@@ -2438,7 +2480,7 @@ static struct pxa2xx_udc memory = {
+ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
+ {
+ struct pxa2xx_udc *dev = &memory;
+- int retval, out_dma = 1;
++ int retval, out_dma = 1, vbus_irq;
+ u32 chiprev;
+
+ /* insist on Intel/ARM/XScale */
+@@ -2502,6 +2544,16 @@ static int __init pxa2xx_udc_probe(struc
+ /* other non-static parts of init */
+ dev->dev = &pdev->dev;
+ dev->mach = pdev->dev.platform_data;
++ if (dev->mach->gpio_vbus) {
++ vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
++ pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
++ | GPIO_IN);
++ set_irq_type(vbus_irq, IRQT_BOTHEDGE);
++ } else
++ vbus_irq = 0;
++ if (dev->mach->gpio_pullup)
++ pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
++ | GPIO_OUT | GPIO_DFLT_LOW);
+
+ init_timer(&dev->timer);
+ dev->timer.function = udc_watchdog;
+@@ -2557,8 +2609,19 @@ lubbock_fail0:
+ HEX_DISPLAY(dev->stats.irqs);
+ LUB_DISC_BLNK_LED &= 0xff;
+ #endif
+- }
++ } else
+ #endif
++ if (vbus_irq) {
++ retval = request_irq(vbus_irq, udc_vbus_irq,
++ SA_INTERRUPT | SA_SAMPLE_RANDOM,
++ driver_name, dev);
++ if (retval != 0) {
++ printk(KERN_ERR "%s: can't get irq %i, err %d\n",
++ driver_name, vbus_irq, retval);
++ free_irq(IRQ_USB, dev);
++ return -EBUSY;
++ }
++ }
+ create_proc_files();
+
+ return 0;
+@@ -2587,6 +2650,8 @@ static int __exit pxa2xx_udc_remove(stru
+ free_irq(LUBBOCK_USB_IRQ, dev);
+ }
+ #endif
++ if (dev->mach->gpio_vbus)
++ free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
+ platform_set_drvdata(pdev, NULL);
+ the_controller = NULL;
+ return 0;
+diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
+index 19a883f..8e598c8 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.h
++++ b/drivers/usb/gadget/pxa2xx_udc.h
+@@ -177,27 +177,19 @@ struct pxa2xx_udc {
+
+ static struct pxa2xx_udc *the_controller;
+
+-/* one GPIO should be used to detect VBUS from the host */
+-static inline int is_vbus_present(void)
++static inline int pxa_gpio_get(unsigned gpio)
+ {
+- if (!the_controller->mach->udc_is_connected)
+- return 1;
+- return the_controller->mach->udc_is_connected();
++ return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
+ }
+
+-/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+-static inline void pullup_off(void)
++static inline void pxa_gpio_set(unsigned gpio, int is_on)
+ {
+- if (!the_controller->mach->udc_command)
+- return;
+- the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+-}
++ int mask = GPIO_bit(gpio);
+
+-static inline void pullup_on(void)
+-{
+- if (!the_controller->mach->udc_command)
+- return;
+- the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
++ if (is_on)
++ GPSR(gpio) = mask;
++ else
++ GPCR(gpio) = mask;
+ }
+
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
+index e762aa1..208e55a 100644
+--- a/drivers/usb/gadget/serial.c
++++ b/drivers/usb/gadget/serial.c
+@@ -271,7 +271,7 @@ static unsigned int use_acm = GS_DEFAULT
+
+
+ /* tty driver struct */
+-static struct tty_operations gs_tty_ops = {
++static const struct tty_operations gs_tty_ops = {
+ .open = gs_open,
+ .close = gs_close,
+ .write = gs_write,
+@@ -1120,12 +1120,15 @@ static int gs_send(struct gs_dev *dev)
+ gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+ list_del(&req_entry->re_entry);
+ req->length = len;
++ spin_unlock_irqrestore(&dev->dev_lock, flags);
+ if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+ printk(KERN_ERR
+ "gs_send: cannot queue read request, ret=%d\n",
+ ret);
++ spin_lock_irqsave(&dev->dev_lock, flags);
+ break;
+ }
++ spin_lock_irqsave(&dev->dev_lock, flags);
+ } else {
+ break;
+ }
+@@ -1431,7 +1434,7 @@ static int __init gs_bind(struct usb_gad
+ return -ENOMEM;
+
+ snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+- system_utsname.sysname, system_utsname.release,
++ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+ memset(dev, 0, sizeof(struct gs_dev));
+diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
+index b7018ee..0f809dd 100644
+--- a/drivers/usb/gadget/zero.c
++++ b/drivers/usb/gadget/zero.c
+@@ -1242,7 +1242,7 @@ autoconf_fail:
+ EP_OUT_NAME, EP_IN_NAME);
+
+ snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
+- system_utsname.sysname, system_utsname.release,
++ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+ return 0;
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index b93d71d..cf10cbc 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -83,6 +83,7 @@ config USB_OHCI_HCD
+ tristate "OHCI HCD support"
+ depends on USB && USB_ARCH_HAS_OHCI
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
++ select I2C if ARCH_PNX4008
+ ---help---
+ The Open Host Controller Interface (OHCI) is a standard for accessing
+ USB 1.1 host controller hardware. It does more in hardware than Intel's
+@@ -141,6 +142,34 @@ config USB_UHCI_HCD
+ To compile this driver as a module, choose M here: the
+ module will be called uhci-hcd.
+
++config USB_U132_HCD
++ tristate "Elan U132 Adapter Host Controller"
++ depends on USB && USB_FTDI_ELAN
++ default M
++ help
++ The U132 adapter is a USB to CardBus adapter specifically designed
++ for PC cards that contain an OHCI host controller. Typical PC cards
++ are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132
++ adapter will *NOT* work with PC cards that do not contain an OHCI
++ controller.
++
++ For those PC cards that contain multiple OHCI controllers only ther
++ first one is used.
++
++ The driver consists of two modules, the "ftdi-elan" module is a
++ USB client driver that interfaces to the FTDI chip within ELAN's
++ USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host
++ controller driver that talks to the OHCI controller within the
++ CardBus cards that are inserted in the U132 adapter.
++
++ This driver has been tested with a CardBus OHCI USB adapter, and
++ worked with a USB PEN Drive inserted into the first USB port of
++ the PCCARD. A rather pointless thing to do, but useful for testing.
++
++ It is safe to say M here.
++
++ See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php>
++
+ config USB_SL811_HCD
+ tristate "SL811HS HCD support"
+ depends on USB
+diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
+index e3020f4..a2e58c8 100644
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -14,4 +14,5 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
+ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
+ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
+ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
++obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
+ obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o
+diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
+index 26ed757..5d1b12a 100644
+--- a/drivers/usb/host/ehci-au1xxx.c
++++ b/drivers/usb/host/ehci-au1xxx.c
+@@ -200,6 +200,7 @@ static const struct hc_driver ehci_au1xx
+ .reset = ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -268,6 +269,7 @@ MODULE_ALIAS("au1xxx-ehci");
+ static struct platform_driver ehci_hcd_au1xxx_driver = {
+ .probe = ehci_hcd_au1xxx_drv_probe,
+ .remove = ehci_hcd_au1xxx_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ehci_hcd_au1xxx_drv_suspend, */
+ /*.resume = ehci_hcd_au1xxx_drv_resume, */
+ .driver = {
+diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
+index 65ac9fe..34b7a31 100644
+--- a/drivers/usb/host/ehci-dbg.c
++++ b/drivers/usb/host/ehci-dbg.c
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (c) 2001-2002 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+@@ -65,7 +65,7 @@ static void dbg_hcs_params (struct ehci_
+ for (i = 0; i < HCS_N_PORTS (params); i++) {
+ // FIXME MIPS won't readb() ...
+ byte = readb (&ehci->caps->portroute[(i>>1)]);
+- sprintf(tmp, "%d ",
++ sprintf(tmp, "%d ",
+ ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+ strcat(buf, tmp);
+ }
+@@ -141,12 +141,12 @@ dbg_qh (const char *label, struct ehci_h
+ }
+
+ static void __attribute__((__unused__))
+-dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
++dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
+ {
+ ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
+ label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
+ ehci_dbg (ehci,
+- " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
++ " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ le32_to_cpu(itd->hw_transaction[0]),
+ le32_to_cpu(itd->hw_transaction[1]),
+ le32_to_cpu(itd->hw_transaction[2]),
+@@ -156,7 +156,7 @@ dbg_itd (const char *label, struct ehci_
+ le32_to_cpu(itd->hw_transaction[6]),
+ le32_to_cpu(itd->hw_transaction[7]));
+ ehci_dbg (ehci,
+- " buf: %08x %08x %08x %08x %08x %08x %08x\n",
++ " buf: %08x %08x %08x %08x %08x %08x %08x\n",
+ le32_to_cpu(itd->hw_bufp[0]),
+ le32_to_cpu(itd->hw_bufp[1]),
+ le32_to_cpu(itd->hw_bufp[2]),
+@@ -171,12 +171,12 @@ dbg_itd (const char *label, struct ehci_
+ }
+
+ static void __attribute__((__unused__))
+-dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
++dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+ {
+ ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
+ label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
+ ehci_dbg (ehci,
+- " addr %08x sched %04x result %08x buf %08x %08x\n",
++ " addr %08x sched %04x result %08x buf %08x %08x\n",
+ le32_to_cpu(sitd->hw_fullspeed_ep),
+ le32_to_cpu(sitd->hw_uframe),
+ le32_to_cpu(sitd->hw_results),
+@@ -451,7 +451,7 @@ show_async (struct class_device *class_d
+ *buf = 0;
+
+ bus = class_get_devdata(class_dev);
+- hcd = bus->hcpriv;
++ hcd = bus_to_hcd(bus);
+ ehci = hcd_to_ehci (hcd);
+ next = buf;
+ size = PAGE_SIZE;
+@@ -497,7 +497,7 @@ show_periodic (struct class_device *clas
+ seen_count = 0;
+
+ bus = class_get_devdata(class_dev);
+- hcd = bus->hcpriv;
++ hcd = bus_to_hcd(bus);
+ ehci = hcd_to_ehci (hcd);
+ next = buf;
+ size = PAGE_SIZE;
+@@ -634,7 +634,7 @@ show_registers (struct class_device *cla
+ static char label [] = "";
+
+ bus = class_get_devdata(class_dev);
+- hcd = bus->hcpriv;
++ hcd = bus_to_hcd(bus);
+ ehci = hcd_to_ehci (hcd);
+ next = buf;
+ size = PAGE_SIZE;
+@@ -785,10 +785,11 @@ static CLASS_DEVICE_ATTR (registers, S_I
+ static inline void create_debug_files (struct ehci_hcd *ehci)
+ {
+ struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
++ int retval;
+
+- class_device_create_file(cldev, &class_device_attr_async);
+- class_device_create_file(cldev, &class_device_attr_periodic);
+- class_device_create_file(cldev, &class_device_attr_registers);
++ retval = class_device_create_file(cldev, &class_device_attr_async);
++ retval = class_device_create_file(cldev, &class_device_attr_periodic);
++ retval = class_device_create_file(cldev, &class_device_attr_registers);
+ }
+
+ static inline void remove_debug_files (struct ehci_hcd *ehci)
+diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
+index d030516..1a915e9 100644
+--- a/drivers/usb/host/ehci-fsl.c
++++ b/drivers/usb/host/ehci-fsl.c
+@@ -285,6 +285,7 @@ static const struct hc_driver ehci_fsl_h
+ .resume = ehci_bus_resume,
+ #endif
+ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -329,6 +330,7 @@ MODULE_ALIAS("fsl-ehci");
+ static struct platform_driver ehci_fsl_driver = {
+ .probe = ehci_fsl_drv_probe,
+ .remove = ehci_fsl_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "fsl-ehci",
+ },
+diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
+index d63177a..9030994 100644
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (c) 2000-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
+ * Free Software Foundation; either version 2 of the License, or (at your
+@@ -70,7 +70,7 @@
+ * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared;
+ * only scheduling is different, no arbitrary limitations.
+ * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support,
+- * clean up HC run state handshaking.
++ * clean up HC run state handshaking.
+ * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts
+ * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other
+ * missing pieces: enabling 64bit dma, handoff from BIOS/SMM.
+@@ -254,7 +254,7 @@ static void ehci_quiesce (struct ehci_hc
+
+ /*-------------------------------------------------------------------------*/
+
+-static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
++static void ehci_work(struct ehci_hcd *ehci);
+
+ #include "ehci-hub.c"
+ #include "ehci-mem.c"
+@@ -273,7 +273,6 @@ static void ehci_watchdog (unsigned long
+ /* lost IAA irqs wedge things badly; seen with a vt8235 */
+ if (ehci->reclaim) {
+ u32 status = readl (&ehci->regs->status);
+-
+ if (status & STS_IAA) {
+ ehci_vdbg (ehci, "lost IAA\n");
+ COUNT (ehci->stats.lost_iaa);
+@@ -284,29 +283,28 @@ static void ehci_watchdog (unsigned long
+
+ /* stop async processing after it's idled a bit */
+ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
+- start_unlink_async (ehci, ehci->async);
++ start_unlink_async (ehci, ehci->async);
+
+ /* ehci could run by timer, without IRQs ... */
+- ehci_work (ehci, NULL);
++ ehci_work (ehci);
+
+ spin_unlock_irqrestore (&ehci->lock, flags);
+ }
+
+-/* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
++/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
+ */
+-static int
+-ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
++static void
++ehci_shutdown (struct usb_hcd *hcd)
+ {
+- struct ehci_hcd *ehci;
++ struct ehci_hcd *ehci;
+
+- ehci = container_of (self, struct ehci_hcd, reboot_notifier);
++ ehci = hcd_to_ehci (hcd);
+ (void) ehci_halt (ehci);
+
+ /* make BIOS/etc use companion controller during reboot */
+ writel (0, &ehci->regs->configured_flag);
+- return 0;
+ }
+
+ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+@@ -331,11 +329,11 @@ static void ehci_port_power (struct ehci
+ * ehci_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping ehci->lock.
+ */
+-static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
++static void ehci_work (struct ehci_hcd *ehci)
+ {
+ timer_action_done (ehci, TIMER_IO_WATCHDOG);
+ if (ehci->reclaim_ready)
+- end_unlink_async (ehci, regs);
++ end_unlink_async (ehci);
+
+ /* another CPU may drop ehci->lock during a schedule scan while
+ * it reports urb completions. this flag guards against bogus
+@@ -344,9 +342,9 @@ static void ehci_work (struct ehci_hcd *
+ if (ehci->scanning)
+ return;
+ ehci->scanning = 1;
+- scan_async (ehci, regs);
++ scan_async (ehci);
+ if (ehci->next_uframe != -1)
+- scan_periodic (ehci, regs);
++ scan_periodic (ehci);
+ ehci->scanning = 0;
+
+ /* the IO watchdog guards against hardware or driver bugs that
+@@ -381,14 +379,13 @@ static void ehci_stop (struct usb_hcd *h
+
+ /* let companion controllers work when we aren't */
+ writel (0, &ehci->regs->configured_flag);
+- unregister_reboot_notifier (&ehci->reboot_notifier);
+
+ remove_debug_files (ehci);
+
+ /* root hub is shut down separately (first, when possible) */
+ spin_lock_irq (&ehci->lock);
+ if (ehci->async)
+- ehci_work (ehci, NULL);
++ ehci_work (ehci);
+ spin_unlock_irq (&ehci->lock);
+ ehci_mem_cleanup (ehci);
+
+@@ -427,7 +424,7 @@ static int ehci_init(struct usb_hcd *hcd
+
+ /* controllers may cache some of the periodic schedule ... */
+ hcc_params = readl(&ehci->caps->hcc_params);
+- if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
++ if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
+ ehci->i_thresh = 8;
+ else // N microframes cached
+ ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+@@ -483,9 +480,6 @@ static int ehci_init(struct usb_hcd *hcd
+ }
+ ehci->command = temp;
+
+- ehci->reboot_notifier.notifier_call = ehci_reboot;
+- register_reboot_notifier(&ehci->reboot_notifier);
+-
+ return 0;
+ }
+
+@@ -499,7 +493,6 @@ static int ehci_run (struct usb_hcd *hcd
+
+ /* EHCI spec section 4.1 */
+ if ((retval = ehci_reset(ehci)) != 0) {
+- unregister_reboot_notifier(&ehci->reboot_notifier);
+ ehci_mem_cleanup(ehci);
+ return retval;
+ }
+@@ -565,7 +558,7 @@ static int ehci_run (struct usb_hcd *hcd
+
+ /*-------------------------------------------------------------------------*/
+
+-static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
++static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ {
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ u32 status;
+@@ -662,7 +655,7 @@ dead:
+ }
+
+ if (bh)
+- ehci_work (ehci, regs);
++ ehci_work (ehci);
+ spin_unlock (&ehci->lock);
+ return IRQ_HANDLED;
+ }
+@@ -730,7 +723,7 @@ static void unlink_async (struct ehci_hc
+
+ /* bypass IAA if the hc can't care */
+ } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
+- end_unlink_async (ehci, NULL);
++ end_unlink_async (ehci);
+
+ /* something else might have unlinked the qh by now */
+ if (qh->qh_state == QH_STATE_LINKED)
+@@ -767,7 +760,7 @@ static int ehci_urb_dequeue (struct usb_
+ intr_deschedule (ehci, qh);
+ /* FALL THROUGH */
+ case QH_STATE_IDLE:
+- qh_completions (ehci, qh, NULL);
++ qh_completions (ehci, qh);
+ break;
+ default:
+ ehci_dbg (ehci, "bogus qh %p state %d\n",
+diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
+index d03e3ca..1b20722 100644
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -1,6 +1,6 @@
+ /*
+ * 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+@@ -49,7 +49,7 @@ static int ehci_bus_suspend (struct usb_
+ ehci->command = readl (&ehci->regs->command);
+ if (ehci->reclaim)
+ ehci->reclaim_ready = 1;
+- ehci_work(ehci, NULL);
++ ehci_work(ehci);
+
+ /* suspend any active/unsuspended ports, maybe allow wakeup */
+ while (port--) {
+@@ -103,10 +103,10 @@ static int ehci_bus_resume (struct usb_h
+
+ /* re-init operational registers in case we lost power */
+ if (readl (&ehci->regs->intr_enable) == 0) {
+- /* at least some APM implementations will try to deliver
++ /* at least some APM implementations will try to deliver
+ * IRQs right away, so delay them until we're ready.
+- */
+- intr_enable = 1;
++ */
++ intr_enable = 1;
+ writel (0, &ehci->regs->segment);
+ writel (ehci->periodic_dma, &ehci->regs->frame_list);
+ writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+@@ -232,7 +232,7 @@ ehci_hub_status_data (struct usb_hcd *hc
+ buf [1] = 0;
+ retval++;
+ }
+-
++
+ /* no hub change reports (bit 0) for now (power, ...) */
+
+ /* port N changes (bit N)? */
+@@ -304,7 +304,7 @@ ehci_hub_descriptor (
+
+ /*-------------------------------------------------------------------------*/
+
+-#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
++#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+ static int ehci_hub_control (
+ struct usb_hcd *hcd,
+diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
+index 766061e..a8ba2e1 100644
+--- a/drivers/usb/host/ehci-mem.c
++++ b/drivers/usb/host/ehci-mem.c
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (c) 2001 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+@@ -25,7 +25,7 @@
+ * - data used only by the HCD ... kmalloc is fine
+ * - async and periodic schedules, shared by HC and HCD ... these
+ * need to use dma_pool or dma_alloc_coherent
+- * - driver buffers, read/written by HC ... single shot DMA mapped
++ * - driver buffers, read/written by HC ... single shot DMA mapped
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pageable.
+@@ -119,7 +119,7 @@ static inline void qh_put (struct ehci_q
+
+ /*-------------------------------------------------------------------------*/
+
+-/* The queue heads and transfer descriptors are managed from pools tied
++/* The queue heads and transfer descriptors are managed from pools tied
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+@@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hc
+ int i;
+
+ /* QTDs for control/bulk/intr transfers */
+- ehci->qtd_pool = dma_pool_create ("ehci_qtd",
++ ehci->qtd_pool = dma_pool_create ("ehci_qtd",
+ ehci_to_hcd(ehci)->self.controller,
+ sizeof (struct ehci_qtd),
+ 32 /* byte alignment (for hw parts) */,
+@@ -175,7 +175,7 @@ static int ehci_mem_init (struct ehci_hc
+ }
+
+ /* QHs for control/bulk/intr transfers */
+- ehci->qh_pool = dma_pool_create ("ehci_qh",
++ ehci->qh_pool = dma_pool_create ("ehci_qh",
+ ehci_to_hcd(ehci)->self.controller,
+ sizeof (struct ehci_qh),
+ 32 /* byte alignment (for hw parts) */,
+@@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hc
+ }
+
+ /* ITD for high speed ISO transfers */
+- ehci->itd_pool = dma_pool_create ("ehci_itd",
++ ehci->itd_pool = dma_pool_create ("ehci_itd",
+ ehci_to_hcd(ehci)->self.controller,
+ sizeof (struct ehci_itd),
+ 32 /* byte alignment (for hw parts) */,
+@@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hc
+ }
+
+ /* SITD for full/low speed split ISO transfers */
+- ehci->sitd_pool = dma_pool_create ("ehci_sitd",
++ ehci->sitd_pool = dma_pool_create ("ehci_sitd",
+ ehci_to_hcd(ehci)->self.controller,
+ sizeof (struct ehci_sitd),
+ 32 /* byte alignment (for hw parts) */,
+diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
+index cadffac..e51c1ed 100644
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -238,6 +238,12 @@ static int ehci_pci_suspend(struct usb_h
+ writel (0, &ehci->regs->intr_enable);
+ (void)readl(&ehci->regs->intr_enable);
+
++ /* make sure snapshot being resumed re-enumerates everything */
++ if (message.event == PM_EVENT_PRETHAW) {
++ ehci_halt(ehci);
++ ehci_reset(ehci);
++ }
++
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+ spin_unlock_irqrestore (&ehci->lock, flags);
+@@ -298,7 +304,7 @@ restart:
+ spin_lock_irq(&ehci->lock);
+ if (ehci->reclaim)
+ ehci->reclaim_ready = 1;
+- ehci_work(ehci, NULL);
++ ehci_work(ehci);
+ spin_unlock_irq(&ehci->lock);
+
+ /* restart; khubd will disconnect devices */
+@@ -332,6 +338,7 @@ static const struct hc_driver ehci_pci_h
+ .resume = ehci_pci_resume,
+ #endif
+ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -378,4 +385,5 @@ static struct pci_driver ehci_pci_driver
+ .suspend = usb_hcd_pci_suspend,
+ .resume = usb_hcd_pci_resume,
+ #endif
++ .shutdown = usb_hcd_pci_shutdown,
+ };
+diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
+index e469221..62e46dc 100644
+--- a/drivers/usb/host/ehci-q.c
++++ b/drivers/usb/host/ehci-q.c
+@@ -1,6 +1,6 @@
+ /*
+ * 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+@@ -31,7 +31,7 @@
+ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
+ * interrupts) needs careful scheduling. Performance improvements can be
+ * an ongoing challenge. That's in "ehci-sched.c".
+- *
++ *
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries. TTs will
+@@ -199,7 +199,7 @@ static void qtd_copy_status (
+ && ((token & QTD_STS_MMF) != 0
+ || QTD_CERR(token) == 0)
+ && (!ehci_is_TDI(ehci)
+- || urb->dev->tt->hub !=
++ || urb->dev->tt->hub !=
+ ehci_to_hcd(ehci)->self.root_hub)) {
+ #ifdef DEBUG
+ struct usb_device *tt = urb->dev->tt->hub;
+@@ -214,7 +214,7 @@ static void qtd_copy_status (
+ }
+
+ static void
+-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
++ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ __releases(ehci->lock)
+ __acquires(ehci->lock)
+ {
+@@ -262,7 +262,7 @@ __acquires(ehci->lock)
+
+ /* complete() can reenter this HCD */
+ spin_unlock (&ehci->lock);
+- usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb, regs);
++ usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+ spin_lock (&ehci->lock);
+ }
+
+@@ -279,7 +279,7 @@ static int qh_schedule (struct ehci_hcd
+ */
+ #define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
+ static unsigned
+-qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
++qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
+ struct ehci_qtd *last = NULL, *end = qh->dummy;
+ struct list_head *entry, *tmp;
+@@ -317,7 +317,7 @@ qh_completions (struct ehci_hcd *ehci, s
+ /* clean up any state from previous QTD ...*/
+ if (last) {
+ if (likely (last->urb != urb)) {
+- ehci_urb_done (ehci, last->urb, regs);
++ ehci_urb_done (ehci, last->urb);
+ count++;
+ }
+ ehci_qtd_free (ehci, last);
+@@ -364,7 +364,7 @@ qh_completions (struct ehci_hcd *ehci, s
+ */
+ if (likely (urb->status == -EINPROGRESS))
+ continue;
+-
++
+ /* issue status after short control reads */
+ if (unlikely (do_status != 0)
+ && QTD_PID (token) == 0 /* OUT */) {
+@@ -388,7 +388,7 @@ halt:
+ wmb ();
+ }
+ }
+-
++
+ /* remove it from the queue */
+ spin_lock (&urb->lock);
+ qtd_copy_status (ehci, urb, qtd->length, token);
+@@ -407,7 +407,7 @@ halt:
+
+ /* last urb's completion might still need calling */
+ if (likely (last != NULL)) {
+- ehci_urb_done (ehci, last->urb, regs);
++ ehci_urb_done (ehci, last->urb);
+ count++;
+ ehci_qtd_free (ehci, last);
+ }
+@@ -518,7 +518,7 @@ qh_urb_transaction (
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= (1 /* "in" */ << 8);
+- }
++ }
+
+ /*
+ * data transfer stage: buffer setup
+@@ -759,7 +759,7 @@ qh_make (
+ }
+ break;
+ default:
+- dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
++ dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ done:
+ qh_put (qh);
+ return NULL;
+@@ -962,7 +962,7 @@ submit_async (
+
+ /* the async qh for the qtds being reclaimed are now unlinked from the HC */
+
+-static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
++static void end_unlink_async (struct ehci_hcd *ehci)
+ {
+ struct ehci_qh *qh = ehci->reclaim;
+ struct ehci_qh *next;
+@@ -972,7 +972,7 @@ static void end_unlink_async (struct ehc
+ // qh->hw_next = cpu_to_le32 (qh->qh_dma);
+ qh->qh_state = QH_STATE_IDLE;
+ qh->qh_next.qh = NULL;
+- qh_put (qh); // refcount from reclaim
++ qh_put (qh); // refcount from reclaim
+
+ /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
+ next = qh->reclaim;
+@@ -980,7 +980,7 @@ static void end_unlink_async (struct ehc
+ ehci->reclaim_ready = 0;
+ qh->reclaim = NULL;
+
+- qh_completions (ehci, qh, regs);
++ qh_completions (ehci, qh);
+
+ if (!list_empty (&qh->qtd_list)
+ && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+@@ -1031,7 +1031,7 @@ static void start_unlink_async (struct e
+ timer_action_done (ehci, TIMER_ASYNC_OFF);
+ }
+ return;
+- }
++ }
+
+ qh->qh_state = QH_STATE_UNLINK;
+ ehci->reclaim = qh = qh_get (qh);
+@@ -1046,9 +1046,9 @@ static void start_unlink_async (struct e
+
+ if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
+ /* if (unlikely (qh->reclaim != 0))
+- * this will recurse, probably not much
++ * this will recurse, probably not much
+ */
+- end_unlink_async (ehci, NULL);
++ end_unlink_async (ehci);
+ return;
+ }
+
+@@ -1061,8 +1061,7 @@ static void start_unlink_async (struct e
+
+ /*-------------------------------------------------------------------------*/
+
+-static void
+-scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
++static void scan_async (struct ehci_hcd *ehci)
+ {
+ struct ehci_qh *qh;
+ enum ehci_timer_action action = TIMER_IO_WATCHDOG;
+@@ -1086,7 +1085,7 @@ rescan:
+ */
+ qh = qh_get (qh);
+ qh->stamp = ehci->stamp;
+- temp = qh_completions (ehci, qh, regs);
++ temp = qh_completions (ehci, qh);
+ qh_put (qh);
+ if (temp != 0) {
+ goto rescan;
+diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
+index 4859900..65c402a 100644
+--- a/drivers/usb/host/ehci-sched.c
++++ b/drivers/usb/host/ehci-sched.c
+@@ -1,7 +1,7 @@
+ /*
+ * Copyright (c) 2001-2004 by David Brownell
+ * Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
+- *
++ *
+ * 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
+@@ -613,7 +613,7 @@ static void intr_deschedule (struct ehci
+ /*-------------------------------------------------------------------------*/
+
+ static int check_period (
+- struct ehci_hcd *ehci,
++ struct ehci_hcd *ehci,
+ unsigned frame,
+ unsigned uframe,
+ unsigned period,
+@@ -629,7 +629,7 @@ static int check_period (
+
+ /*
+ * 80% periodic == 100 usec/uframe available
+- * convert "usecs we need" to "max already claimed"
++ * convert "usecs we need" to "max already claimed"
+ */
+ usecs = 100 - usecs;
+
+@@ -659,14 +659,14 @@ static int check_period (
+ }
+
+ static int check_intr_schedule (
+- struct ehci_hcd *ehci,
++ struct ehci_hcd *ehci,
+ unsigned frame,
+ unsigned uframe,
+ const struct ehci_qh *qh,
+ __le32 *c_maskp
+ )
+ {
+- int retval = -ENOSPC;
++ int retval = -ENOSPC;
+ u8 mask = 0;
+
+ if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
+@@ -701,7 +701,7 @@ static int check_intr_schedule (
+ /* Make sure this tt's buffer is also available for CSPLITs.
+ * We pessimize a bit; probably the typical full speed case
+ * doesn't need the second CSPLIT.
+- *
++ *
+ * NOTE: both SPLIT and CSPLIT could be checked in just
+ * one smart pass...
+ */
+@@ -728,7 +728,7 @@ done:
+ */
+ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
+- int status;
++ int status;
+ unsigned uframe;
+ __le32 c_mask;
+ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
+@@ -784,7 +784,7 @@ static int qh_schedule (struct ehci_hcd
+ ehci_dbg (ehci, "reused qh %p schedule\n", qh);
+
+ /* stuff into the periodic schedule */
+- status = qh_link_periodic (ehci, qh);
++ status = qh_link_periodic (ehci, qh);
+ done:
+ return status;
+ }
+@@ -1553,8 +1553,7 @@ itd_link_urb (
+ static unsigned
+ itd_complete (
+ struct ehci_hcd *ehci,
+- struct ehci_itd *itd,
+- struct pt_regs *regs
++ struct ehci_itd *itd
+ ) {
+ struct urb *urb = itd->urb;
+ struct usb_iso_packet_descriptor *desc;
+@@ -1613,7 +1612,7 @@ itd_complete (
+
+ /* give urb back to the driver ... can be out-of-order */
+ dev = urb->dev;
+- ehci_urb_done (ehci, urb, regs);
++ ehci_urb_done (ehci, urb);
+ urb = NULL;
+
+ /* defer stopping schedule; completion can submit */
+@@ -1681,7 +1680,7 @@ static int itd_submit (struct ehci_hcd *
+ status = -ESHUTDOWN;
+ else
+ status = iso_stream_schedule (ehci, urb, stream);
+- if (likely (status == 0))
++ if (likely (status == 0))
+ itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ spin_unlock_irqrestore (&ehci->lock, flags);
+
+@@ -1738,7 +1737,7 @@ sitd_sched_init (
+ if (packet->buf1 != (buf & ~(u64)0x0fff))
+ packet->cross = 1;
+
+- /* OUT uses multiple start-splits */
++ /* OUT uses multiple start-splits */
+ if (stream->bEndpointAddress & USB_DIR_IN)
+ continue;
+ length = (length + 187) / 188;
+@@ -1925,13 +1924,12 @@ sitd_link_urb (
+ /*-------------------------------------------------------------------------*/
+
+ #define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
+- | SITD_STS_XACT | SITD_STS_MMF)
++ | SITD_STS_XACT | SITD_STS_MMF)
+
+ static unsigned
+ sitd_complete (
+ struct ehci_hcd *ehci,
+- struct ehci_sitd *sitd,
+- struct pt_regs *regs
++ struct ehci_sitd *sitd
+ ) {
+ struct urb *urb = sitd->urb;
+ struct usb_iso_packet_descriptor *desc;
+@@ -1978,7 +1976,7 @@ sitd_complete (
+
+ /* give urb back to the driver */
+ dev = urb->dev;
+- ehci_urb_done (ehci, urb, regs);
++ ehci_urb_done (ehci, urb);
+ urb = NULL;
+
+ /* defer stopping schedule; completion can submit */
+@@ -2043,7 +2041,7 @@ static int sitd_submit (struct ehci_hcd
+ status = -ESHUTDOWN;
+ else
+ status = iso_stream_schedule (ehci, urb, stream);
+- if (status == 0)
++ if (status == 0)
+ sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ spin_unlock_irqrestore (&ehci->lock, flags);
+
+@@ -2065,8 +2063,7 @@ sitd_submit (struct ehci_hcd *ehci, stru
+ static inline unsigned
+ sitd_complete (
+ struct ehci_hcd *ehci,
+- struct ehci_sitd *sitd,
+- struct pt_regs *regs
++ struct ehci_sitd *sitd
+ ) {
+ ehci_err (ehci, "sitd_complete %p?\n", sitd);
+ return 0;
+@@ -2077,7 +2074,7 @@ sitd_complete (
+ /*-------------------------------------------------------------------------*/
+
+ static void
+-scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
++scan_periodic (struct ehci_hcd *ehci)
+ {
+ unsigned frame, clock, now_uframe, mod;
+ unsigned modified;
+@@ -2131,7 +2128,7 @@ restart:
+ temp.qh = qh_get (q.qh);
+ type = Q_NEXT_TYPE (q.qh->hw_next);
+ q = q.qh->qh_next;
+- modified = qh_completions (ehci, temp.qh, regs);
++ modified = qh_completions (ehci, temp.qh);
+ if (unlikely (list_empty (&temp.qh->qtd_list)))
+ intr_deschedule (ehci, temp.qh);
+ qh_put (temp.qh);
+@@ -2169,7 +2166,7 @@ restart:
+ *hw_p = q.itd->hw_next;
+ type = Q_NEXT_TYPE (q.itd->hw_next);
+ wmb();
+- modified = itd_complete (ehci, q.itd, regs);
++ modified = itd_complete (ehci, q.itd);
+ q = *q_p;
+ break;
+ case Q_TYPE_SITD:
+@@ -2185,7 +2182,7 @@ restart:
+ *hw_p = q.sitd->hw_next;
+ type = Q_NEXT_TYPE (q.sitd->hw_next);
+ wmb();
+- modified = sitd_complete (ehci, q.sitd, regs);
++ modified = sitd_complete (ehci, q.sitd);
+ q = *q_p;
+ break;
+ default:
+@@ -2226,5 +2223,5 @@ restart:
+ now_uframe++;
+ now_uframe %= mod;
+ }
+- }
++ }
+ }
+diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
+index 679c1cd..bbc3082 100644
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -1,6 +1,6 @@
+ /*
+ * Copyright (c) 2001-2002 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+@@ -82,7 +82,6 @@ struct ehci_hcd { /* one per controlle
+ struct dma_pool *sitd_pool; /* sitd per split iso urb */
+
+ struct timer_list watchdog;
+- struct notifier_block reboot_notifier;
+ unsigned long actions;
+ unsigned stamp;
+ unsigned long next_statechange;
+@@ -104,7 +103,7 @@ struct ehci_hcd { /* one per controlle
+ #endif
+ };
+
+-/* convert between an HCD pointer and the corresponding EHCI_HCD */
++/* convert between an HCD pointer and the corresponding EHCI_HCD */
+ static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
+ {
+ return (struct ehci_hcd *) (hcd->hcd_priv);
+@@ -179,8 +178,8 @@ struct ehci_caps {
+ #define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+ #define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+ #define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
+-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
++#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
++#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+ #define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
+@@ -205,7 +204,7 @@ struct ehci_regs {
+ #define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+ #define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
+ #define CMD_ASE (1<<5) /* async schedule enable */
+-#define CMD_PSE (1<<4) /* periodic schedule enable */
++#define CMD_PSE (1<<4) /* periodic schedule enable */
+ /* 3:2 is periodic frame list size */
+ #define CMD_RESET (1<<1) /* reset HC not bus */
+ #define CMD_RUN (1<<0) /* start/stop HC */
+@@ -231,9 +230,9 @@ struct ehci_regs {
+ /* FRINDEX: offset 0x0C */
+ u32 frame_index; /* current microframe number */
+ /* CTRLDSSEGMENT: offset 0x10 */
+- u32 segment; /* address bits 63:32 if needed */
++ u32 segment; /* address bits 63:32 if needed */
+ /* PERIODICLISTBASE: offset 0x14 */
+- u32 frame_list; /* points to periodic list */
++ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
+@@ -302,7 +301,7 @@ struct ehci_dbg_port {
+
+ /*
+ * EHCI Specification 0.95 Section 3.5
+- * QTD: describe data transfer components (buffer, direction, ...)
++ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+@@ -312,7 +311,7 @@ struct ehci_qtd {
+ /* first part defined by EHCI spec */
+ __le32 hw_next; /* see EHCI 3.5.1 */
+ __le32 hw_alt_next; /* see EHCI 3.5.2 */
+- __le32 hw_token; /* see EHCI 3.5.3 */
++ __le32 hw_token; /* see EHCI 3.5.3 */
+ #define QTD_TOGGLE (1 << 31) /* data toggle */
+ #define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+ #define QTD_IOC (1 << 15) /* interrupt on complete */
+@@ -349,8 +348,8 @@ struct ehci_qtd {
+ /* values for that type tag */
+ #define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
+ #define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
+-#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
+-#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
++#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
++#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
+
+ /* next async queue entry, or pointer to interrupt/periodic QH */
+ #define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+@@ -367,7 +366,7 @@ struct ehci_qtd {
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+ union ehci_shadow {
+- struct ehci_qh *qh; /* Q_TYPE_QH */
++ struct ehci_qh *qh; /* Q_TYPE_QH */
+ struct ehci_itd *itd; /* Q_TYPE_ITD */
+ struct ehci_sitd *sitd; /* Q_TYPE_SITD */
+ struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
+@@ -397,7 +396,7 @@ struct ehci_qh {
+ #define QH_HUBPORT 0x3f800000
+ #define QH_MULT 0xc0000000
+ __le32 hw_current; /* qtd list - see EHCI 3.6.4 */
+-
++
+ /* qtd overlay (hardware parts of a struct ehci_qtd) */
+ __le32 hw_qtd_next;
+ __le32 hw_alt_next;
+@@ -472,7 +471,7 @@ struct ehci_iso_stream {
+ struct list_head td_list; /* queued itds/sitds */
+ struct list_head free_list; /* list of unused itds/sitds */
+ struct usb_device *udev;
+- struct usb_host_endpoint *ep;
++ struct usb_host_endpoint *ep;
+
+ /* output of (re)scheduling */
+ unsigned long start; /* jiffies */
+@@ -492,8 +491,8 @@ struct ehci_iso_stream {
+ unsigned bandwidth;
+
+ /* This is used to initialize iTD's hw_bufp fields */
+- __le32 buf0;
+- __le32 buf1;
++ __le32 buf0;
++ __le32 buf1;
+ __le32 buf2;
+
+ /* this is used to initialize sITD's tt info */
+@@ -521,7 +520,7 @@ struct ehci_itd {
+
+ #define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
+
+- __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
++ __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
+ __le32 hw_bufp_hi [7]; /* Appendix B */
+
+ /* the rest is HCD-private */
+@@ -542,7 +541,7 @@ struct ehci_itd {
+ /*-------------------------------------------------------------------------*/
+
+ /*
+- * EHCI Specification 0.95 Section 3.4
++ * EHCI Specification 0.95 Section 3.4
+ * siTD, aka split-transaction isochronous Transfer Descriptor
+ * ... describe full speed iso xfers through TT in hubs
+ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
+diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
+index 61e5717..87eca6a 100644
+--- a/drivers/usb/host/hc_crisv10.c
++++ b/drivers/usb/host/hc_crisv10.c
+@@ -478,9 +478,9 @@ static int etrax_usb_submit_urb(struct u
+ static int etrax_usb_unlink_urb(struct urb *urb, int status);
+ static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
+
+-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
++static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc);
++static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc);
++static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc);
+ static void etrax_usb_hc_interrupt_bottom_half(void *data);
+
+ static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
+@@ -1573,7 +1573,7 @@ static int etrax_usb_get_frame_number(st
+ return (*R_USB_FM_NUMBER & 0x7ff);
+ }
+
+-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
++static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc)
+ {
+ DBFENTER;
+
+@@ -1839,7 +1839,7 @@ static void etrax_usb_isoc_descr_interru
+
+
+
+-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
++static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc)
+ {
+ struct urb *urb;
+ etrax_urb_priv_t *urb_priv;
+@@ -3280,7 +3280,7 @@ static void etrax_usb_complete_urb(struc
+
+
+
+-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs)
++static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc)
+ {
+ usb_interrupt_registers_t *reg;
+ unsigned long flags;
+diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
+index 5147ed4..2718b5d 100644
+--- a/drivers/usb/host/isp116x-hcd.c
++++ b/drivers/usb/host/isp116x-hcd.c
+@@ -418,7 +418,7 @@ static void postproc_atl_queue(struct is
+ processed urbs.
+ */
+ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+- struct urb *urb, struct pt_regs *regs)
++ struct urb *urb)
+ __releases(isp116x->lock) __acquires(isp116x->lock)
+ {
+ unsigned i;
+@@ -432,7 +432,7 @@ __releases(isp116x->lock) __acquires(isp
+ urb_dbg(urb, "Finish");
+
+ spin_unlock(&isp116x->lock);
+- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs);
++ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+ spin_lock(&isp116x->lock);
+
+ /* take idle endpoints out of the schedule */
+@@ -568,7 +568,7 @@ static void start_atl_transfers(struct i
+ /*
+ Finish the processed transfers
+ */
+-static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs)
++static void finish_atl_transfers(struct isp116x *isp116x)
+ {
+ struct isp116x_ep *ep;
+ struct urb *urb;
+@@ -590,12 +590,12 @@ static void finish_atl_transfers(struct
+ occured, while URB_SHORT_NOT_OK was set */
+ if (urb && urb->status != -EINPROGRESS
+ && ep->nextpid != USB_PID_ACK)
+- finish_request(isp116x, ep, urb, regs);
++ finish_request(isp116x, ep, urb);
+ }
+ atomic_dec(&isp116x->atl_finishing);
+ }
+
+-static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
++static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
+ {
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ u16 irqstat;
+@@ -608,7 +608,7 @@ static irqreturn_t isp116x_irq(struct us
+
+ if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+ ret = IRQ_HANDLED;
+- finish_atl_transfers(isp116x, regs);
++ finish_atl_transfers(isp116x);
+ }
+
+ if (irqstat & HCuPINT_OPR) {
+@@ -824,7 +824,7 @@ static int isp116x_urb_enqueue(struct us
+ spin_lock(&urb->lock);
+ if (urb->status != -EINPROGRESS) {
+ spin_unlock(&urb->lock);
+- finish_request(isp116x, ep, urb, NULL);
++ finish_request(isp116x, ep, urb);
+ ret = 0;
+ goto fail;
+ }
+@@ -870,7 +870,7 @@ static int isp116x_urb_dequeue(struct us
+ }
+
+ if (urb)
+- finish_request(isp116x, ep, urb, NULL);
++ finish_request(isp116x, ep, urb);
+
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return 0;
+@@ -1204,10 +1204,10 @@ static int isp116x_show_dbg(struct seq_f
+
+ static int isp116x_open_seq(struct inode *inode, struct file *file)
+ {
+- return single_open(file, isp116x_show_dbg, inode->u.generic_ip);
++ return single_open(file, isp116x_show_dbg, inode->i_private);
+ }
+
+-static struct file_operations isp116x_debug_fops = {
++static const struct file_operations isp116x_debug_fops = {
+ .open = isp116x_open_seq,
+ .read = seq_read,
+ .llseek = seq_lseek,
+diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
+index a1b7c38..b91e2ed 100644
+--- a/drivers/usb/host/isp116x.h
++++ b/drivers/usb/host/isp116x.h
+@@ -233,7 +233,7 @@ static const int cc_to_error[16] = {
+ /* Bit Stuff */ -EPROTO,
+ /* Data Togg */ -EILSEQ,
+ /* Stall */ -EPIPE,
+- /* DevNotResp */ -ETIMEDOUT,
++ /* DevNotResp */ -ETIME,
+ /* PIDCheck */ -EPROTO,
+ /* UnExpPID */ -EPROTO,
+ /* DataOver */ -EOVERFLOW,
+diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
+index 85cc059..b466581 100644
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -193,7 +193,7 @@ ohci_at91_start (struct usb_hcd *hcd)
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+- root->maxchild = board->ports;
++ ohci->num_ports = board->ports;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ err("can't start %s", hcd->self.bus_name);
+@@ -221,6 +221,7 @@ static const struct hc_driver ohci_at91_
+ */
+ .start = ohci_at91_start,
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -239,7 +240,7 @@ static const struct hc_driver ohci_at91_
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+-
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -296,6 +297,7 @@ static int ohci_hcd_at91_drv_resume(stru
+ if (!clocked) {
+ clk_enable(iclk);
+ clk_enable(fclk);
++ clocked = 1;
+ }
+
+ return 0;
+@@ -310,6 +312,7 @@ MODULE_ALIAS("at91_ohci");
+ static struct platform_driver ohci_hcd_at91_driver = {
+ .probe = ohci_hcd_at91_drv_probe,
+ .remove = ohci_hcd_at91_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ .suspend = ohci_hcd_at91_drv_suspend,
+ .resume = ohci_hcd_at91_drv_resume,
+ .driver = {
+diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
+index f7a975d..24e23c5 100644
+--- a/drivers/usb/host/ohci-au1xxx.c
++++ b/drivers/usb/host/ohci-au1xxx.c
+@@ -268,11 +268,8 @@ static const struct hc_driver ohci_au1xx
+ * basic lifecycle operations
+ */
+ .start = ohci_au1xxx_start,
+-#ifdef CONFIG_PM
+- /* suspend: ohci_au1xxx_suspend, -- tbd */
+- /* resume: ohci_au1xxx_resume, -- tbd */
+-#endif /*CONFIG_PM*/
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -291,6 +288,7 @@ static const struct hc_driver ohci_au1xx
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -338,6 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(st
+ static struct platform_driver ohci_hcd_au1xxx_driver = {
+ .probe = ohci_hcd_au1xxx_drv_probe,
+ .remove = ohci_hcd_au1xxx_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ohci_hcd_au1xxx_drv_suspend, */
+ /*.resume = ohci_hcd_au1xxx_drv_resume, */
+ .driver = {
+diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
+index 7bfffcb..8293c1d 100644
+--- a/drivers/usb/host/ohci-dbg.c
++++ b/drivers/usb/host/ohci-dbg.c
+@@ -477,7 +477,7 @@ show_async (struct class_device *class_d
+ unsigned long flags;
+
+ bus = class_get_devdata(class_dev);
+- hcd = bus->hcpriv;
++ hcd = bus_to_hcd(bus);
+ ohci = hcd_to_ohci(hcd);
+
+ /* display control and bulk lists together, for simplicity */
+@@ -510,7 +510,7 @@ show_periodic (struct class_device *clas
+ seen_count = 0;
+
+ bus = class_get_devdata(class_dev);
+- hcd = bus->hcpriv;
++ hcd = bus_to_hcd(bus);
+ ohci = hcd_to_ohci(hcd);
+ next = buf;
+ size = PAGE_SIZE;
+@@ -607,7 +607,7 @@ show_registers (struct class_device *cla
+ u32 rdata;
+
+ bus = class_get_devdata(class_dev);
+- hcd = bus->hcpriv;
++ hcd = bus_to_hcd(bus);
+ ohci = hcd_to_ohci(hcd);
+ regs = ohci->regs;
+ next = buf;
+@@ -667,6 +667,11 @@ show_registers (struct class_device *cla
+ size -= temp;
+ next += temp;
+
++ temp = scnprintf (next, size, "hub poll timer %s\n",
++ ohci_to_hcd(ohci)->poll_rh ? "ON" : "off");
++ size -= temp;
++ next += temp;
++
+ /* roothub */
+ ohci_dump_roothub (ohci, 1, &next, &size);
+
+@@ -680,10 +685,11 @@ static CLASS_DEVICE_ATTR (registers, S_I
+ static inline void create_debug_files (struct ohci_hcd *ohci)
+ {
+ struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
++ int retval;
+
+- class_device_create_file(cldev, &class_device_attr_async);
+- class_device_create_file(cldev, &class_device_attr_periodic);
+- class_device_create_file(cldev, &class_device_attr_registers);
++ retval = class_device_create_file(cldev, &class_device_attr_async);
++ retval = class_device_create_file(cldev, &class_device_attr_periodic);
++ retval = class_device_create_file(cldev, &class_device_attr_registers);
+ ohci_dbg (ohci, "created debug files\n");
+ }
+
+diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
+index 6531c4d..1bf5e7a 100644
+--- a/drivers/usb/host/ohci-ep93xx.c
++++ b/drivers/usb/host/ohci-ep93xx.c
+@@ -128,12 +128,14 @@ static struct hc_driver ohci_ep93xx_hc_d
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .start = ohci_ep93xx_start,
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -202,6 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(st
+ static struct platform_driver ohci_hcd_ep93xx_driver = {
+ .probe = ohci_hcd_ep93xx_drv_probe,
+ .remove = ohci_hcd_ep93xx_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ #ifdef CONFIG_PM
+ .suspend = ohci_hcd_ep93xx_drv_suspend,
+ .resume = ohci_hcd_ep93xx_drv_resume,
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index 94d8cf4..9be6b30 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -88,7 +88,7 @@
+ #include <linux/timer.h>
+ #include <linux/list.h>
+ #include <linux/usb.h>
+-#include <linux/usb_otg.h>
++#include <linux/usb/otg.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmapool.h>
+ #include <linux/reboot.h>
+@@ -101,7 +101,7 @@
+
+ #include "../core/hcd.h"
+
+-#define DRIVER_VERSION "2005 April 22"
++#define DRIVER_VERSION "2006 August 04"
+ #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
+ #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
+
+@@ -110,9 +110,10 @@
+ #undef OHCI_VERBOSE_DEBUG /* not always helpful */
+
+ /* For initializing controller (mask in an HCFS mode too) */
+-#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
++#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
+ #define OHCI_INTR_INIT \
+- (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
++ (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \
++ | OHCI_INTR_RD | OHCI_INTR_WDH)
+
+ #ifdef __hppa__
+ /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
+@@ -128,12 +129,13 @@
+
+ static const char hcd_name [] = "ohci_hcd";
+
++#define STATECHANGE_DELAY msecs_to_jiffies(300)
++
+ #include "ohci.h"
+
+ 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"
+@@ -259,7 +261,7 @@ static int ohci_urb_enqueue (
+ if (urb->status != -EINPROGRESS) {
+ spin_unlock (&urb->lock);
+ urb->hcpriv = urb_priv;
+- finish_urb (ohci, urb, NULL);
++ finish_urb (ohci, urb);
+ retval = 0;
+ goto fail;
+ }
+@@ -335,7 +337,7 @@ static int ohci_urb_dequeue (struct usb_
+ * any more ... just clean up every urb's memory.
+ */
+ if (urb->hcpriv)
+- finish_urb (ohci, urb, NULL);
++ finish_urb (ohci, urb);
+ }
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return 0;
+@@ -367,7 +369,7 @@ rescan:
+ if (!HC_IS_RUNNING (hcd->state)) {
+ sanitize:
+ ed->state = ED_IDLE;
+- finish_unlinks (ohci, 0, NULL);
++ finish_unlinks (ohci, 0);
+ }
+
+ switch (ed->state) {
+@@ -416,21 +418,20 @@ static void ohci_usb_reset (struct ohci_
+ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ }
+
+-/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
++/* ohci_shutdown 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)
++static void
++ohci_shutdown (struct usb_hcd *hcd)
+ {
+ struct ohci_hcd *ohci;
+
+- ohci = container_of (block, struct ohci_hcd, reboot_notifier);
++ ohci = hcd_to_ohci (hcd);
+ 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;
+ }
+
+ /*-------------------------------------------------------------------------*
+@@ -446,7 +447,6 @@ static int ohci_init (struct ohci_hcd *o
+
+ disable (ohci);
+ ohci->regs = hcd->regs;
+- ohci->next_statechange = jiffies;
+
+ /* REVISIT this BIOS handshake is now moved into PCI "quirks", and
+ * was never needed for most non-PCI systems ... remove the code?
+@@ -502,7 +502,6 @@ static int ohci_init (struct ohci_hcd *o
+ if ((ret = ohci_mem_init (ohci)) < 0)
+ ohci_stop (hcd);
+ else {
+- register_reboot_notifier (&ohci->reboot_notifier);
+ create_debug_files (ohci);
+ }
+
+@@ -637,10 +636,14 @@ retry:
+ return -EOVERFLOW;
+ }
+
+- /* start controller operations */
++ /* use rhsc irqs after khubd is fully initialized */
++ hcd->poll_rh = 1;
++ hcd->uses_new_polling = 1;
++
++ /* start controller operations */
+ ohci->hc_control &= OHCI_CTRL_RWC;
+- ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+- ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
++ ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
++ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ hcd->state = HC_STATE_RUNNING;
+
+ /* wake on ConnectStatusChange, matching external hubs */
+@@ -648,7 +651,7 @@ retry:
+
+ /* Choose the interrupts we care about now, others later on demand */
+ mask = OHCI_INTR_INIT;
+- ohci_writel (ohci, mask, &ohci->regs->intrstatus);
++ ohci_writel (ohci, ~0, &ohci->regs->intrstatus);
+ ohci_writel (ohci, mask, &ohci->regs->intrenable);
+
+ /* handle root hub init quirks ... */
+@@ -672,6 +675,7 @@ retry:
+ // flush those writes
+ (void) ohci_readl (ohci, &ohci->regs->control);
+
++ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
+ spin_unlock_irq (&ohci->lock);
+
+ // POTPGT delay is bits 24-31, in 2 ms units.
+@@ -687,7 +691,7 @@ retry:
+
+ /* an interrupt happens */
+
+-static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
++static irqreturn_t ohci_irq (struct usb_hcd *hcd)
+ {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct ohci_regs __iomem *regs = ohci->regs;
+@@ -709,7 +713,14 @@ static irqreturn_t ohci_irq (struct usb_
+ /* interrupt for some other device? */
+ } else if ((ints &= ohci_readl (ohci, ®s->intrenable)) == 0) {
+ return IRQ_NOTMINE;
+- }
++ }
++
++ if (ints & OHCI_INTR_RHSC) {
++ ohci_vdbg (ohci, "rhsc\n");
++ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
++ ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus);
++ usb_hcd_poll_rh_status(hcd);
++ }
+
+ if (ints & OHCI_INTR_UE) {
+ disable (ohci);
+@@ -723,15 +734,20 @@ static irqreturn_t ohci_irq (struct usb_
+ if (ints & OHCI_INTR_RD) {
+ ohci_vdbg (ohci, "resume detect\n");
+ ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus);
+- if (hcd->state != HC_STATE_QUIESCING)
++ hcd->poll_rh = 1;
++ if (ohci->autostop) {
++ spin_lock (&ohci->lock);
++ ohci_rh_resume (ohci);
++ spin_unlock (&ohci->lock);
++ } else
+ usb_hcd_resume_root_hub(hcd);
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ if (HC_IS_RUNNING(hcd->state))
+- ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable);
++ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable);
+ spin_lock (&ohci->lock);
+- dl_done_list (ohci, ptregs);
++ dl_done_list (ohci);
+ spin_unlock (&ohci->lock);
+ if (HC_IS_RUNNING(hcd->state))
+ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable);
+@@ -744,7 +760,7 @@ static irqreturn_t ohci_irq (struct usb_
+ */
+ spin_lock (&ohci->lock);
+ if (ohci->ed_rm_list)
+- finish_unlinks (ohci, ohci_frame_no(ohci), ptregs);
++ finish_unlinks (ohci, ohci_frame_no(ohci));
+ if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+ && HC_IS_RUNNING(hcd->state))
+ ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable);
+@@ -775,9 +791,10 @@ static void ohci_stop (struct usb_hcd *h
+
+ ohci_usb_reset (ohci);
+ ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+-
++ free_irq(hcd->irq, hcd);
++ hcd->irq = -1;
++
+ remove_debug_files (ohci);
+- unregister_reboot_notifier (&ohci->reboot_notifier);
+ ohci_mem_cleanup (ohci);
+ if (ohci->hcca) {
+ dma_free_coherent (hcd->self.controller,
+@@ -835,7 +852,7 @@ static int ohci_restart (struct ohci_hcd
+ urb->status = -ESHUTDOWN;
+ spin_unlock (&urb->lock);
+ }
+- finish_unlinks (ohci, 0, NULL);
++ finish_unlinks (ohci, 0);
+ spin_unlock_irq(&ohci->lock);
+
+ /* paranoia, in case that didn't work: */
+@@ -917,6 +934,10 @@ MODULE_LICENSE ("GPL");
+ #include "ohci-at91.c"
+ #endif
+
++#ifdef CONFIG_ARCH_PNX4008
++#include "ohci-pnx4008.c"
++#endif
++
+ #if !(defined(CONFIG_PCI) \
+ || defined(CONFIG_SA1111) \
+ || defined(CONFIG_ARCH_S3C2410) \
+@@ -928,6 +949,7 @@ MODULE_LICENSE ("GPL");
+ || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+ || defined (CONFIG_ARCH_AT91RM9200) \
+ || defined (CONFIG_ARCH_AT91SAM9261) \
++ || defined (CONFIG_ARCH_PNX4008) \
+ )
+ #error "missing bus glue for ohci-hcd"
+ #endif
+diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
+index 5b0a23f..6f11359 100644
+--- a/drivers/usb/host/ohci-hub.c
++++ b/drivers/usb/host/ohci-hub.c
+@@ -36,27 +36,25 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-#ifdef CONFIG_PM
++/* hcd->hub_irq_enable() */
++static void ohci_rhsc_enable (struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
++
++ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
++}
+
+ #define OHCI_SCHED_ENABLES \
+ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
+
+-static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
+-static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
+-static int ohci_restart (struct ohci_hcd *ohci);
++static void dl_done_list (struct ohci_hcd *);
++static void finish_unlinks (struct ohci_hcd *, u16);
+
+-static int ohci_bus_suspend (struct usb_hcd *hcd)
++static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
++__releases(ohci->lock)
++__acquires(ohci->lock)
+ {
+- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int status = 0;
+- unsigned long flags;
+-
+- spin_lock_irqsave (&ohci->lock, flags);
+-
+- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+- spin_unlock_irqrestore (&ohci->lock, flags);
+- return -ESHUTDOWN;
+- }
+
+ ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+@@ -72,15 +70,16 @@ static int ohci_bus_suspend (struct usb_
+ ohci_dbg (ohci, "needs reinit!\n");
+ goto done;
+ case OHCI_USB_SUSPEND:
+- ohci_dbg (ohci, "already suspended\n");
+- goto done;
++ if (!ohci->autostop) {
++ ohci_dbg (ohci, "already suspended\n");
++ goto done;
++ }
+ }
+- ohci_dbg (ohci, "suspend root hub\n");
++ ohci_dbg (ohci, "%s root hub\n",
++ autostop ? "auto-stop" : "suspend");
+
+ /* First stop any processing */
+- if (ohci->hc_control & OHCI_SCHED_ENABLES) {
+- int limit;
+-
++ if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) {
+ ohci->hc_control &= ~OHCI_SCHED_ENABLES;
+ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+@@ -90,27 +89,22 @@ static int ohci_bus_suspend (struct usb_
+ * then the last WDH could take 6+ msec
+ */
+ ohci_dbg (ohci, "stopping schedules ...\n");
+- limit = 2000;
+- while (limit > 0) {
+- udelay (250);
+- limit =- 250;
+- if (ohci_readl (ohci, &ohci->regs->intrstatus)
+- & OHCI_INTR_SF)
+- break;
+- }
+- dl_done_list (ohci, NULL);
+- mdelay (7);
++ ohci->autostop = 0;
++ spin_unlock_irq (&ohci->lock);
++ msleep (8);
++ spin_lock_irq (&ohci->lock);
+ }
+- dl_done_list (ohci, NULL);
+- finish_unlinks (ohci, ohci_frame_no(ohci), NULL);
+- ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
+- &ohci->regs->intrstatus);
++ dl_done_list (ohci);
++ finish_unlinks (ohci, ohci_frame_no(ohci));
+
+ /* maybe resume can wake root hub */
+- if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
++ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) ||
++ autostop)
+ ohci->hc_control |= OHCI_CTRL_RWE;
+- else
++ else {
++ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
+ ohci->hc_control &= ~OHCI_CTRL_RWE;
++ }
+
+ /* Suspend hub ... this is the "global (to this bus) suspend" mode,
+ * which doesn't imply ports will first be individually suspended.
+@@ -121,13 +115,12 @@ static int ohci_bus_suspend (struct usb_
+ (void) ohci_readl (ohci, &ohci->regs->control);
+
+ /* no resumes until devices finish suspending */
+- ohci->next_statechange = jiffies + msecs_to_jiffies (5);
++ if (!autostop) {
++ ohci->next_statechange = jiffies + msecs_to_jiffies (5);
++ ohci->autostop = 0;
++ }
+
+ done:
+- /* external suspend vs self autosuspend ... same effect */
+- if (status == 0)
+- usb_hcd_suspend_root_hub(hcd);
+- spin_unlock_irqrestore (&ohci->lock, flags);
+ return status;
+ }
+
+@@ -139,25 +132,19 @@ static inline struct ed *find_head (stru
+ return ed;
+ }
+
++static int ohci_restart (struct ohci_hcd *ohci);
++
+ /* caller has locked the root hub */
+-static int ohci_bus_resume (struct usb_hcd *hcd)
++static int ohci_rh_resume (struct ohci_hcd *ohci)
++__releases(ohci->lock)
++__acquires(ohci->lock)
+ {
+- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
++ struct usb_hcd *hcd = ohci_to_hcd (ohci);
+ u32 temp, enables;
+ int status = -EINPROGRESS;
+- unsigned long flags;
+-
+- if (time_before (jiffies, ohci->next_statechange))
+- msleep(5);
+-
+- spin_lock_irqsave (&ohci->lock, flags);
+-
+- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+- spin_unlock_irqrestore (&ohci->lock, flags);
+- return -ESHUTDOWN;
+- }
+-
++ int autostopped = ohci->autostop;
+
++ ohci->autostop = 0;
+ ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+
+ if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
+@@ -177,7 +164,8 @@ static int ohci_bus_resume (struct usb_h
+ ohci->hc_control |= OHCI_USB_RESUME;
+ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ (void) ohci_readl (ohci, &ohci->regs->control);
+- ohci_dbg (ohci, "resume root hub\n");
++ ohci_dbg (ohci, "%s root hub\n",
++ autostopped ? "auto-start" : "resume");
+ break;
+ case OHCI_USB_RESUME:
+ /* HCFS changes sometime after INTR_RD */
+@@ -192,16 +180,24 @@ static int ohci_bus_resume (struct usb_h
+ ohci_dbg (ohci, "lost power\n");
+ status = -EBUSY;
+ }
+- spin_unlock_irqrestore (&ohci->lock, flags);
++#ifdef CONFIG_PM
+ if (status == -EBUSY) {
+- (void) ohci_init (ohci);
+- return ohci_restart (ohci);
++ if (!autostopped) {
++ spin_unlock_irq (&ohci->lock);
++ (void) ohci_init (ohci);
++ status = ohci_restart (ohci);
++ spin_lock_irq (&ohci->lock);
++ }
++ return status;
+ }
++#endif
+ if (status != -EINPROGRESS)
+ return status;
++ if (autostopped)
++ goto skip_resume;
++ spin_unlock_irq (&ohci->lock);
+
+ temp = ohci->num_ports;
+- enables = 0;
+ while (temp--) {
+ u32 stat = ohci_readl (ohci,
+ &ohci->regs->roothub.portstatus [temp]);
+@@ -234,17 +230,21 @@ static int ohci_bus_resume (struct usb_h
+ /* Sometimes PCI D3 suspend trashes frame timings ... */
+ periodic_reinit (ohci);
+
++ /* the following code is executed with ohci->lock held and
++ * irqs disabled if and only if autostopped is true
++ */
++
++skip_resume:
+ /* interrupts might have been disabled */
+ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable);
+ if (ohci->ed_rm_list)
+ ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable);
+- ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
+- &ohci->regs->intrstatus);
+
+ /* Then re-enable operations */
+ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control);
+ (void) ohci_readl (ohci, &ohci->regs->control);
+- msleep (3);
++ if (!autostopped)
++ msleep (3);
+
+ temp = ohci->hc_control;
+ temp &= OHCI_CTRL_RWC;
+@@ -254,10 +254,14 @@ static int ohci_bus_resume (struct usb_h
+ (void) ohci_readl (ohci, &ohci->regs->control);
+
+ /* TRSMRCY */
+- msleep (10);
++ if (!autostopped) {
++ msleep (10);
++ spin_lock_irq (&ohci->lock);
++ }
++ /* now ohci->lock is always held and irqs are always disabled */
+
+- /* keep it alive for ~5x suspend + resume costs */
+- ohci->next_statechange = jiffies + msecs_to_jiffies (250);
++ /* keep it alive for more than ~5x suspend + resume costs */
++ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
+
+ /* maybe turn schedules back on */
+ enables = 0;
+@@ -291,6 +295,45 @@ static int ohci_bus_resume (struct usb_h
+ return 0;
+ }
+
++#ifdef CONFIG_PM
++
++static int ohci_bus_suspend (struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
++ int rc;
++
++ spin_lock_irq (&ohci->lock);
++
++ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
++ rc = -ESHUTDOWN;
++ else
++ rc = ohci_rh_suspend (ohci, 0);
++ spin_unlock_irq (&ohci->lock);
++ return rc;
++}
++
++static int ohci_bus_resume (struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
++ int rc;
++
++ if (time_before (jiffies, ohci->next_statechange))
++ msleep(5);
++
++ spin_lock_irq (&ohci->lock);
++
++ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
++ rc = -ESHUTDOWN;
++ else
++ rc = ohci_rh_resume (ohci);
++ spin_unlock_irq (&ohci->lock);
++
++ /* poll until we know a device is connected or we autostop */
++ if (rc == 0)
++ usb_hcd_poll_rh_status(hcd);
++ return rc;
++}
++
+ #endif /* CONFIG_PM */
+
+ /*-------------------------------------------------------------------------*/
+@@ -302,20 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hc
+ {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int i, changed = 0, length = 1;
+- int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
++ int any_connected = 0, rhsc_enabled = 1;
+ unsigned long flags;
+
+ spin_lock_irqsave (&ohci->lock, flags);
+
+- /* handle autosuspended root: finish resuming before
+- * letting khubd or root hub timer see state changes.
+- */
+- if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
+- || !HC_IS_RUNNING(hcd->state))) {
+- can_suspend = 0;
+- goto done;
+- }
+-
+ /* undocumented erratum seen on at least rev D */
+ if ((ohci->flags & OHCI_QUIRK_AMD756)
+ && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
+@@ -339,6 +373,9 @@ ohci_hub_status_data (struct usb_hcd *hc
+ for (i = 0; i < ohci->num_ports; i++) {
+ u32 status = roothub_portstatus (ohci, i);
+
++ /* can't autostop if ports are connected */
++ any_connected |= (status & RH_PS_CCS);
++
+ if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+ | RH_PS_OCIC | RH_PS_PRSC)) {
+ changed = 1;
+@@ -346,39 +383,72 @@ ohci_hub_status_data (struct usb_hcd *hc
+ buf [0] |= 1 << (i + 1);
+ else
+ buf [1] |= 1 << (i - 7);
+- continue;
+ }
+-
+- /* can suspend if no ports are enabled; or if all all
+- * enabled ports are suspended AND remote wakeup is on.
+- */
+- if (!(status & RH_PS_CCS))
+- continue;
+- if ((status & RH_PS_PSS) && can_suspend)
+- continue;
+- can_suspend = 0;
+ }
+-done:
+- spin_unlock_irqrestore (&ohci->lock, flags);
+
+-#ifdef CONFIG_PM
+- /* save power by suspending idle root hubs;
+- * INTR_RD wakes us when there's work
++ /* NOTE: vendors didn't always make the same implementation
++ * choices for RHSC. Sometimes it triggers on an edge (like
++ * setting and maybe clearing a port status change bit); and
++ * it's level-triggered on other silicon, active until khubd
++ * clears all active port status change bits. If it's still
++ * set (level-triggered) we must disable it and rely on
++ * polling until khubd re-enables it.
+ */
+- if (can_suspend
+- && !changed
+- && !ohci->ed_rm_list
+- && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
+- & ohci->hc_control)
+- == OHCI_USB_OPER
+- && time_after (jiffies, ohci->next_statechange)
+- && usb_trylock_device (hcd->self.root_hub) == 0
+- ) {
+- ohci_vdbg (ohci, "autosuspend\n");
+- (void) ohci_bus_suspend (hcd);
+- usb_unlock_device (hcd->self.root_hub);
++ if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) {
++ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
++ (void) ohci_readl (ohci, &ohci->regs->intrdisable);
++ rhsc_enabled = 0;
+ }
+-#endif
++ hcd->poll_rh = 1;
++
++ /* carry out appropriate state changes */
++ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
++
++ case OHCI_USB_OPER:
++ /* keep on polling until we know a device is connected
++ * and RHSC is enabled */
++ if (!ohci->autostop) {
++ if (any_connected) {
++ if (rhsc_enabled)
++ hcd->poll_rh = 0;
++ } else {
++ ohci->autostop = 1;
++ ohci->next_statechange = jiffies + HZ;
++ }
++
++ /* if no devices have been attached for one second, autostop */
++ } else {
++ if (changed || any_connected) {
++ ohci->autostop = 0;
++ ohci->next_statechange = jiffies +
++ STATECHANGE_DELAY;
++ } else if (time_after_eq (jiffies,
++ ohci->next_statechange)
++ && !ohci->ed_rm_list
++ && !(ohci->hc_control &
++ OHCI_SCHED_ENABLES)) {
++ ohci_rh_suspend (ohci, 1);
++ }
++ }
++ break;
++
++ /* if there is a port change, autostart or ask to be resumed */
++ case OHCI_USB_SUSPEND:
++ case OHCI_USB_RESUME:
++ if (changed) {
++ if (ohci->autostop)
++ ohci_rh_resume (ohci);
++ else
++ usb_hcd_resume_root_hub (hcd);
++ } else {
++ /* everything is idle, no need for polling */
++ hcd->poll_rh = 0;
++ }
++ break;
++ }
++
++done:
++ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ return changed ? length : 0;
+ }
+@@ -550,9 +620,6 @@ static int ohci_hub_control (
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ temp = RH_PS_POCI;
+- if ((ohci->hc_control & OHCI_CTRL_HCFS)
+- != OHCI_USB_OPER)
+- usb_hcd_resume_root_hub(hcd);
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ temp = RH_PS_PSSC;
+diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
+index 5602da9..e121d97 100644
+--- a/drivers/usb/host/ohci-lh7a404.c
++++ b/drivers/usb/host/ohci-lh7a404.c
+@@ -173,11 +173,8 @@ static const struct hc_driver ohci_lh7a4
+ * basic lifecycle operations
+ */
+ .start = ohci_lh7a404_start,
+-#ifdef CONFIG_PM
+- /* suspend: ohci_lh7a404_suspend, -- tbd */
+- /* resume: ohci_lh7a404_resume, -- tbd */
+-#endif /*CONFIG_PM*/
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -196,6 +193,7 @@ static const struct hc_driver ohci_lh7a4
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -244,6 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(s
+ static struct platform_driver ohci_hcd_lh7a404_driver = {
+ .probe = ohci_hcd_lh7a404_drv_probe,
+ .remove = ohci_hcd_lh7a404_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ohci_hcd_lh7a404_drv_suspend, */
+ /*.resume = ohci_hcd_lh7a404_drv_resume, */
+ .driver = {
+diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
+index bfbe328..d976614 100644
+--- a/drivers/usb/host/ohci-mem.c
++++ b/drivers/usb/host/ohci-mem.c
+@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_h
+ ohci->next_statechange = jiffies;
+ spin_lock_init (&ohci->lock);
+ INIT_LIST_HEAD (&ohci->pending);
+- ohci->reboot_notifier.notifier_call = ohci_reboot;
+ }
+
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
+index c4c4bab..9c02177 100644
+--- a/drivers/usb/host/ohci-omap.c
++++ b/drivers/usb/host/ohci-omap.c
+@@ -4,7 +4,7 @@
+ * (C) Copyright 1999 Roman Weissgaerber <weissg at vienna.at>
+ * (C) Copyright 2000-2005 David Brownell
+ * (C) Copyright 2002 Hewlett-Packard Company
+- *
++ *
+ * OMAP Bus Glue
+ *
+ * Modified for OMAP by Tony Lindgren <tony at atomide.com>
+@@ -66,15 +66,20 @@ extern int usb_disabled(void);
+ extern int ocpi_enable(void);
+
+ static struct clk *usb_host_ck;
++static struct clk *usb_dc_ck;
++static int host_enabled;
++static int host_initialized;
+
+ static void omap_ohci_clock_power(int on)
+ {
+ if (on) {
++ clk_enable(usb_dc_ck);
+ clk_enable(usb_host_ck);
+ /* guesstimate for T5 == 1x 32K clock + APLL lock time */
+ udelay(100);
+ } else {
+ clk_disable(usb_host_ck);
++ clk_disable(usb_dc_ck);
+ }
+ }
+
+@@ -87,14 +92,14 @@ static int omap_ohci_transceiver_power(i
+ if (on) {
+ if (machine_is_omap_innovator() && cpu_is_omap1510())
+ fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
+- | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
++ | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
+ INNOVATOR_FPGA_CAM_USB_CONTROL);
+ else if (machine_is_omap_osk())
+ tps65010_set_gpio_out_value(GPIO1, LOW);
+ } else {
+ if (machine_is_omap_innovator() && cpu_is_omap1510())
+ fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
+- & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
++ & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
+ INNOVATOR_FPGA_CAM_USB_CONTROL);
+ else if (machine_is_omap_osk())
+ tps65010_set_gpio_out_value(GPIO1, HIGH);
+@@ -103,6 +108,7 @@ static int omap_ohci_transceiver_power(i
+ return 0;
+ }
+
++#ifdef CONFIG_ARCH_OMAP15XX
+ /*
+ * OMAP-1510 specific Local Bus clock on/off
+ */
+@@ -121,8 +127,8 @@ static int omap_1510_local_bus_power(int
+ /*
+ * OMAP-1510 specific Local Bus initialization
+ * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
+- * See also arch/mach-omap/memory.h for __virt_to_dma() and
+- * __dma_to_virt() which need to match with the physical
++ * See also arch/mach-omap/memory.h for __virt_to_dma() and
++ * __dma_to_virt() which need to match with the physical
+ * Local Bus address below.
+ */
+ static int omap_1510_local_bus_init(void)
+@@ -130,7 +136,7 @@ static int omap_1510_local_bus_init(void
+ unsigned int tlb;
+ unsigned long lbaddr, physaddr;
+
+- omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
++ omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
+ OMAP1510_LB_CLOCK_DIV);
+
+ /* Configure the Local Bus MMU table */
+@@ -138,7 +144,7 @@ static int omap_1510_local_bus_init(void
+ lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
+ physaddr = tlb * 0x00100000 + PHYS_OFFSET;
+ omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
+- omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
++ omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
+ OMAP1510_LB_MMU_CAM_L);
+ omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
+ omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
+@@ -152,6 +158,10 @@ static int omap_1510_local_bus_init(void
+
+ return 0;
+ }
++#else
++#define omap_1510_local_bus_power(x) {}
++#define omap_1510_local_bus_init() {}
++#endif
+
+ #ifdef CONFIG_USB_OTG
+
+@@ -173,13 +183,14 @@ static void start_hnp(struct ohci_hcd *o
+
+ /*-------------------------------------------------------------------------*/
+
+-static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
++static int ohci_omap_init(struct usb_hcd *hcd)
+ {
+- struct omap_usb_config *config = pdev->dev.platform_data;
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ struct omap_usb_config *config = hcd->self.controller->platform_data;
+ int need_transceiver = (config->otg != 0);
+ int ret;
+
+- dev_dbg(&pdev->dev, "starting USB Controller\n");
++ dev_dbg(hcd->self.controller, "starting USB Controller\n");
+
+ if (config->otg) {
+ ohci_to_hcd(ohci)->self.otg_port = config->otg;
+@@ -200,7 +211,7 @@ static int omap_start_hc(struct ohci_hcd
+ if (ohci->transceiver) {
+ int status = otg_set_host(ohci->transceiver,
+ &ohci_to_hcd(ohci)->self);
+- dev_dbg(&pdev->dev, "init %s transceiver, status %d\n",
++ dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
+ ohci->transceiver->label, status);
+ if (status) {
+ if (ohci->transceiver)
+@@ -208,7 +219,7 @@ static int omap_start_hc(struct ohci_hcd
+ return status;
+ }
+ } else {
+- dev_err(&pdev->dev, "can't find transceiver\n");
++ dev_err(hcd->self.controller, "can't find transceiver\n");
+ return -ENODEV;
+ }
+ }
+@@ -247,6 +258,10 @@ static int omap_start_hc(struct ohci_hcd
+ }
+ ohci_writel(ohci, rh, &ohci->regs->roothub.a);
+ distrust_firmware = 0;
++ } else if (machine_is_nokia770()) {
++ /* We require a self-powered hub, which should have
++ * plenty of power. */
++ ohci_to_hcd(ohci)->power_budget = 0;
+ }
+
+ /* FIXME khubd hub requests should manage power switching */
+@@ -260,21 +275,15 @@ static int omap_start_hc(struct ohci_hcd
+ return 0;
+ }
+
+-static void omap_stop_hc(struct platform_device *pdev)
++static void ohci_omap_stop(struct usb_hcd *hcd)
+ {
+- dev_dbg(&pdev->dev, "stopping USB Controller\n");
++ dev_dbg(hcd->self.controller, "stopping USB Controller\n");
+ omap_ohci_clock_power(0);
+ }
+
+
+ /*-------------------------------------------------------------------------*/
+
+-void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
+-
+-/* configure so an HC device and id are always provided */
+-/* always called with process context; sleeping is OK */
+-
+-
+ /**
+ * usb_hcd_omap_probe - initialize OMAP-based HCDs
+ * Context: !in_interrupt()
+@@ -283,7 +292,7 @@ void usb_hcd_omap_remove (struct usb_hcd
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+-int usb_hcd_omap_probe (const struct hc_driver *driver,
++static int usb_hcd_omap_probe (const struct hc_driver *driver,
+ struct platform_device *pdev)
+ {
+ int retval, irq;
+@@ -291,12 +300,12 @@ int usb_hcd_omap_probe (const struct hc_
+ struct ohci_hcd *ohci;
+
+ if (pdev->num_resources != 2) {
+- printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
++ printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+- if (pdev->resource[0].flags != IORESOURCE_MEM
++ if (pdev->resource[0].flags != IORESOURCE_MEM
+ || pdev->resource[1].flags != IORESOURCE_IRQ) {
+ printk(KERN_ERR "hcd probe: invalid resource type\n");
+ return -ENODEV;
+@@ -306,6 +315,17 @@ int usb_hcd_omap_probe (const struct hc_
+ if (IS_ERR(usb_host_ck))
+ return PTR_ERR(usb_host_ck);
+
++ if (!cpu_is_omap1510())
++ usb_dc_ck = clk_get(0, "usb_dc_ck");
++ else
++ usb_dc_ck = clk_get(0, "lb_ck");
++
++ if (IS_ERR(usb_dc_ck)) {
++ clk_put(usb_host_ck);
++ return PTR_ERR(usb_dc_ck);
++ }
++
++
+ hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ retval = -ENOMEM;
+@@ -325,9 +345,8 @@ int usb_hcd_omap_probe (const struct hc_
+ ohci = hcd_to_ohci(hcd);
+ ohci_hcd_init(ohci);
+
+- retval = omap_start_hc(ohci, pdev);
+- if (retval < 0)
+- goto err2;
++ host_initialized = 0;
++ host_enabled = 1;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+@@ -335,15 +354,21 @@ int usb_hcd_omap_probe (const struct hc_
+ goto err2;
+ }
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+- if (retval == 0)
+- return retval;
++ if (retval)
++ goto err2;
++
++ host_initialized = 1;
++
++ if (!host_enabled)
++ omap_ohci_clock_power(0);
+
+- omap_stop_hc(pdev);
++ return 0;
+ err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ usb_put_hcd(hcd);
+ err0:
++ clk_put(usb_dc_ck);
+ clk_put(usb_host_ck);
+ return retval;
+ }
+@@ -359,31 +384,41 @@ err0:
+ * Reverses the effect of usb_hcd_omap_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+- *
+ */
+-void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
++static inline void
++usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+ {
++ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
++
+ usb_remove_hcd(hcd);
++ if (ohci->transceiver) {
++ (void) otg_set_host(ohci->transceiver, 0);
++ put_device(ohci->transceiver->dev);
++ }
+ if (machine_is_omap_osk())
+ omap_free_gpio(9);
+- omap_stop_hc(pdev);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
++ clk_put(usb_dc_ck);
+ clk_put(usb_host_ck);
+ }
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __devinit
++static int
+ ohci_omap_start (struct usb_hcd *hcd)
+ {
+ struct omap_usb_config *config;
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
+
++ if (!host_enabled)
++ return 0;
+ config = hcd->self.controller->platform_data;
+- if (config->otg || config->rwc)
++ if (config->otg || config->rwc) {
++ ohci->hc_control = OHCI_CTRL_RWC;
+ writel(OHCI_CTRL_RWC, &ohci->regs->control);
++ }
+
+ if ((ret = ohci_run (ohci)) < 0) {
+ dev_err(hcd->self.controller, "can't start\n");
+@@ -409,8 +444,10 @@ static const struct hc_driver ohci_omap_
+ /*
+ * basic lifecycle operations
+ */
++ .reset = ohci_omap_init,
+ .start = ohci_omap_start,
+- .stop = ohci_stop,
++ .stop = ohci_omap_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -429,6 +466,7 @@ static const struct hc_driver ohci_omap_
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -446,13 +484,8 @@ static int ohci_hcd_omap_drv_probe(struc
+ static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
+ {
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ usb_hcd_omap_remove(hcd, dev);
+- if (ohci->transceiver) {
+- (void) otg_set_host(ohci->transceiver, 0);
+- put_device(ohci->transceiver->dev);
+- }
+ platform_set_drvdata(dev, NULL);
+
+ return 0;
+@@ -472,7 +505,7 @@ static int ohci_omap_suspend(struct plat
+
+ omap_ohci_clock_power(0);
+ ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+- dev->power.power_state = PMSG_SUSPEND;
++ dev->dev.power.power_state = PMSG_SUSPEND;
+ return 0;
+ }
+
+@@ -485,8 +518,8 @@ static int ohci_omap_resume(struct platf
+ ohci->next_statechange = jiffies;
+
+ omap_ohci_clock_power(1);
+- dev->power.power_state = PMSG_ON;
+- usb_hcd_resume_root_hub(dev_get_drvdata(dev));
++ dev->dev.power.power_state = PMSG_ON;
++ usb_hcd_resume_root_hub(platform_get_drvdata(dev));
+ return 0;
+ }
+
+@@ -500,6 +533,7 @@ static int ohci_omap_resume(struct platf
+ static struct platform_driver ohci_hcd_omap_driver = {
+ .probe = ohci_hcd_omap_drv_probe,
+ .remove = ohci_hcd_omap_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ #ifdef CONFIG_PM
+ .suspend = ohci_omap_suspend,
+ .resume = ohci_omap_resume,
+diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
+index b268537..8744185 100644
+--- a/drivers/usb/host/ohci-pci.c
++++ b/drivers/usb/host/ohci-pci.c
+@@ -73,13 +73,14 @@ ohci_pci_start (struct usb_hcd *hcd)
+ else if (pdev->vendor == PCI_VENDOR_ID_NS) {
+ struct pci_dev *b;
+
+- b = pci_find_slot (pdev->bus->number,
++ b = pci_get_slot (pdev->bus,
+ PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+ if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+ && b->vendor == PCI_VENDOR_ID_NS) {
+ ohci->flags |= OHCI_QUIRK_SUPERIO;
+ ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+ }
++ pci_dev_put(b);
+ }
+
+ /* Check for Compaq's ZFMicro chipset, which needs short
+@@ -135,6 +136,11 @@ static int ohci_pci_suspend (struct usb_
+ }
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ (void)ohci_readl(ohci, &ohci->regs->intrdisable);
++
++ /* make sure snapshot being resumed re-enumerates everything */
++ if (message.event == PM_EVENT_PRETHAW)
++ ohci_usb_reset(ohci);
++
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+ spin_unlock_irqrestore (&ohci->lock, flags);
+@@ -171,11 +177,14 @@ static const struct hc_driver ohci_pci_h
+ */
+ .reset = ohci_pci_reset,
+ .start = ohci_pci_start,
++ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
++
+ #ifdef CONFIG_PM
++ /* these suspend/resume entries are for upstream PCI glue ONLY */
+ .suspend = ohci_pci_suspend,
+ .resume = ohci_pci_resume,
+ #endif
+- .stop = ohci_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -194,6 +203,7 @@ static const struct hc_driver ohci_pci_h
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -224,6 +234,8 @@ static struct pci_driver ohci_pci_driver
+ .suspend = usb_hcd_pci_suspend,
+ .resume = usb_hcd_pci_resume,
+ #endif
++
++ .shutdown = usb_hcd_pci_shutdown,
+ };
+
+
+diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
+new file mode 100644
+index 0000000..2dbb774
+--- /dev/null
++++ b/drivers/usb/host/ohci-pnx4008.c
+@@ -0,0 +1,479 @@
++/*
++ * drivers/usb/host/ohci-pnx4008.c
++ *
++ * driver for Philips PNX4008 USB Host
++ *
++ * Authors: Dmitry Chigirev <source at mvista.com>
++ * Vitaly Wool <vitalywool at gmail.com>
++ *
++ * register initialization is based on code examples provided by Philips
++ * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
++ *
++ * NOTE: This driver does not have suspend/resume functionality
++ * This driver is intended for engineering development purposes only
++ *
++ * 2005-2006 (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/clk.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/mach-types.h>
++
++#include <asm/arch/platform.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/gpio.h>
++
++#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
++
++/* USB_CTRL bit defines */
++#define USB_SLAVE_HCLK_EN (1 << 24)
++#define USB_HOST_NEED_CLK_EN (1 << 21)
++
++#define USB_OTG_CLK_CTRL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4)
++#define USB_OTG_CLK_STAT IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8)
++
++/* USB_OTG_CLK_CTRL bit defines */
++#define AHB_M_CLOCK_ON (1 << 4)
++#define OTG_CLOCK_ON (1 << 3)
++#define I2C_CLOCK_ON (1 << 2)
++#define DEV_CLOCK_ON (1 << 1)
++#define HOST_CLOCK_ON (1 << 0)
++
++#define USB_OTG_STAT_CONTROL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110)
++
++/* USB_OTG_STAT_CONTROL bit defines */
++#define TRANSPARENT_I2C_EN (1 << 7)
++#define HOST_EN (1 << 0)
++
++/* ISP1301 USB transceiver I2C registers */
++#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
++
++#define MC1_SPEED_REG (1 << 0)
++#define MC1_SUSPEND_REG (1 << 1)
++#define MC1_DAT_SE0 (1 << 2)
++#define MC1_TRANSPARENT (1 << 3)
++#define MC1_BDIS_ACON_EN (1 << 4)
++#define MC1_OE_INT_EN (1 << 5)
++#define MC1_UART_EN (1 << 6)
++#define MC1_MASK 0x7f
++
++#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
++
++#define MC2_GLOBAL_PWR_DN (1 << 0)
++#define MC2_SPD_SUSP_CTRL (1 << 1)
++#define MC2_BI_DI (1 << 2)
++#define MC2_TRANSP_BDIR0 (1 << 3)
++#define MC2_TRANSP_BDIR1 (1 << 4)
++#define MC2_AUDIO_EN (1 << 5)
++#define MC2_PSW_EN (1 << 6)
++#define MC2_EN2V7 (1 << 7)
++
++#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
++# define OTG1_DP_PULLUP (1 << 0)
++# define OTG1_DM_PULLUP (1 << 1)
++# define OTG1_DP_PULLDOWN (1 << 2)
++# define OTG1_DM_PULLDOWN (1 << 3)
++# define OTG1_ID_PULLDOWN (1 << 4)
++# define OTG1_VBUS_DRV (1 << 5)
++# define OTG1_VBUS_DISCHRG (1 << 6)
++# define OTG1_VBUS_CHRG (1 << 7)
++#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */
++# define OTG_B_SESS_END (1 << 6)
++# define OTG_B_SESS_VLD (1 << 7)
++
++#define ISP1301_I2C_ADDR 0x2C
++
++#define ISP1301_I2C_MODE_CONTROL_1 0x4
++#define ISP1301_I2C_MODE_CONTROL_2 0x12
++#define ISP1301_I2C_OTG_CONTROL_1 0x6
++#define ISP1301_I2C_OTG_CONTROL_2 0x10
++#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
++#define ISP1301_I2C_INTERRUPT_LATCH 0xA
++#define ISP1301_I2C_INTERRUPT_FALLING 0xC
++#define ISP1301_I2C_INTERRUPT_RISING 0xE
++#define ISP1301_I2C_REG_CLEAR_ADDR 1
++
++struct i2c_driver isp1301_driver;
++struct i2c_client *isp1301_i2c_client;
++
++extern int usb_disabled(void);
++extern int ocpi_enable(void);
++
++static struct clk *usb_clk;
++
++static int isp1301_probe(struct i2c_adapter *adap);
++static int isp1301_detach(struct i2c_client *client);
++static int isp1301_command(struct i2c_client *client, unsigned int cmd,
++ void *arg);
++
++static unsigned short normal_i2c[] =
++ { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
++static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
++
++static struct i2c_client_address_data addr_data = {
++ .normal_i2c = normal_i2c,
++ .probe = dummy_i2c_addrlist,
++ .ignore = dummy_i2c_addrlist,
++};
++
++struct i2c_driver isp1301_driver = {
++ .id = I2C_DRIVERID_I2CDEV, /* Fake Id */
++ .class = I2C_CLASS_HWMON,
++ .attach_adapter = isp1301_probe,
++ .detach_client = isp1301_detach,
++ .command = isp1301_command
++};
++
++static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
++{
++ struct i2c_client *c;
++
++ c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL);
++
++ if (!c)
++ return -ENOMEM;
++
++ strcpy(c->name, "isp1301");
++ c->flags = 0;
++ c->addr = addr;
++ c->adapter = adap;
++ c->driver = &isp1301_driver;
++
++ isp1301_i2c_client = c;
++
++ return i2c_attach_client(c);
++}
++
++static int isp1301_probe(struct i2c_adapter *adap)
++{
++ return i2c_probe(adap, &addr_data, isp1301_attach);
++}
++
++static int isp1301_detach(struct i2c_client *client)
++{
++ i2c_detach_client(client);
++ kfree(isp1301_i2c_client);
++ return 0;
++}
++
++/* No commands defined */
++static int isp1301_command(struct i2c_client *client, unsigned int cmd,
++ void *arg)
++{
++ return 0;
++}
++
++static void i2c_write(u8 buf, u8 subaddr)
++{
++ char tmpbuf[2];
++
++ tmpbuf[0] = subaddr; /*register number */
++ tmpbuf[1] = buf; /*register data */
++ i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2);
++}
++
++static void isp1301_configure(void)
++{
++ /* PNX4008 only supports DAT_SE0 USB mode */
++ /* PNX4008 R2A requires setting the MAX603 to output 3.6V */
++ /* Power up externel charge-pump */
++
++ i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1);
++ i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG),
++ ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
++ i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL,
++ ISP1301_I2C_MODE_CONTROL_2);
++ i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL),
++ ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
++ i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN,
++ ISP1301_I2C_OTG_CONTROL_1);
++ i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN),
++ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
++ i2c_write(0xFF,
++ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
++ i2c_write(0xFF,
++ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
++ i2c_write(0xFF,
++ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
++
++}
++
++static inline void isp1301_vbus_on(void)
++{
++ i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1);
++}
++
++static inline void isp1301_vbus_off(void)
++{
++ i2c_write(OTG1_VBUS_DRV,
++ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
++}
++
++static void pnx4008_start_hc(void)
++{
++ unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
++ __raw_writel(tmp, USB_OTG_STAT_CONTROL);
++ isp1301_vbus_on();
++}
++
++static void pnx4008_stop_hc(void)
++{
++ unsigned long tmp;
++ isp1301_vbus_off();
++ tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
++ __raw_writel(tmp, USB_OTG_STAT_CONTROL);
++}
++
++static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ int ret;
++
++ if ((ret = ohci_init(ohci)) < 0)
++ return ret;
++
++ if ((ret = ohci_run(ohci)) < 0) {
++ dev_err(hcd->self.controller, "can't start\n");
++ ohci_stop(hcd);
++ return ret;
++ }
++ return 0;
++}
++
++static const struct hc_driver ohci_pnx4008_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "pnx4008 OHCI",
++
++ /*
++ * generic hardware linkage
++ */
++ .irq = ohci_irq,
++ .flags = HCD_USB11 | HCD_MEMORY,
++
++ .hcd_priv_size = sizeof(struct ohci_hcd),
++ /*
++ * basic lifecycle operations
++ */
++ .start = ohci_pnx4008_start,
++ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
++
++ /*
++ * managing i/o requests and associated device resources
++ */
++ .urb_enqueue = ohci_urb_enqueue,
++ .urb_dequeue = ohci_urb_dequeue,
++ .endpoint_disable = ohci_endpoint_disable,
++
++ /*
++ * scheduling support
++ */
++ .get_frame_number = ohci_get_frame,
++
++ /*
++ * root hub support
++ */
++ .hub_status_data = ohci_hub_status_data,
++ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
++#ifdef CONFIG_PM
++ .bus_suspend = ohci_bus_suspend,
++ .bus_resume = ohci_bus_resume,
++#endif
++ .start_port_reset = ohci_start_port_reset,
++};
++
++#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
++
++static void pnx4008_set_usb_bits(void)
++{
++ start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
++ start_int_ack(SE_USB_OTG_ATX_INT_N);
++ start_int_umask(SE_USB_OTG_ATX_INT_N);
++
++ start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
++ start_int_ack(SE_USB_OTG_TIMER_INT);
++ start_int_umask(SE_USB_OTG_TIMER_INT);
++
++ start_int_set_rising_edge(SE_USB_I2C_INT);
++ start_int_ack(SE_USB_I2C_INT);
++ start_int_umask(SE_USB_I2C_INT);
++
++ start_int_set_rising_edge(SE_USB_INT);
++ start_int_ack(SE_USB_INT);
++ start_int_umask(SE_USB_INT);
++
++ start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
++ start_int_ack(SE_USB_NEED_CLK_INT);
++ start_int_umask(SE_USB_NEED_CLK_INT);
++
++ start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
++ start_int_ack(SE_USB_AHB_NEED_CLK_INT);
++ start_int_umask(SE_USB_AHB_NEED_CLK_INT);
++}
++
++static void pnx4008_unset_usb_bits(void)
++{
++ start_int_mask(SE_USB_OTG_ATX_INT_N);
++ start_int_mask(SE_USB_OTG_TIMER_INT);
++ start_int_mask(SE_USB_I2C_INT);
++ start_int_mask(SE_USB_INT);
++ start_int_mask(SE_USB_NEED_CLK_INT);
++ start_int_mask(SE_USB_AHB_NEED_CLK_INT);
++}
++
++static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = 0;
++ struct ohci_hcd *ohci;
++ const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
++
++ int ret = 0, irq;
++
++ dev_dbg(&pdev->dev, "%s: " DRIVER_INFO " (pnx4008)\n", hcd_name);
++ if (usb_disabled()) {
++ err("USB is disabled");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ if (pdev->num_resources != 2
++ || pdev->resource[0].flags != IORESOURCE_MEM
++ || pdev->resource[1].flags != IORESOURCE_IRQ) {
++ err("Invalid resource configuration");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ /* Enable AHB slave USB clock, needed for further USB clock control */
++ __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
++
++ ret = i2c_add_driver(&isp1301_driver);
++ if (ret < 0) {
++ err("failed to connect I2C to ISP1301 USB Transceiver");
++ goto out;
++ }
++
++ isp1301_configure();
++
++ /* Enable USB PLL */
++ usb_clk = clk_get(&pdev->dev, "ck_pll5");
++ if (IS_ERR(usb_clk)) {
++ err("failed to acquire USB PLL");
++ ret = PTR_ERR(usb_clk);
++ goto out1;
++ }
++
++ ret = clk_enable(usb_clk);
++ if (ret < 0) {
++ err("failed to start USB PLL");
++ goto out2;
++ }
++
++ ret = clk_set_rate(usb_clk, 48000);
++ if (ret < 0) {
++ err("failed to set USB clock rate");
++ goto out3;
++ }
++
++ __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
++
++ /* Set to enable all needed USB clocks */
++ __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
++
++ while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
++ USB_CLOCK_MASK) ;
++
++ hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
++ if (!hcd) {
++ err("Failed to allocate HC buffer");
++ ret = -ENOMEM;
++ goto out3;
++ }
++
++ /* Set all USB bits in the Start Enable register */
++ pnx4008_set_usb_bits();
++
++ hcd->rsrc_start = pdev->resource[0].start;
++ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++ dev_dbg(&pdev->dev, "request_mem_region failed\n");
++ ret = -ENOMEM;
++ goto out4;
++ }
++ hcd->regs = (void __iomem *)pdev->resource[0].start;
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ ret = -ENXIO;
++ goto out4;
++ }
++
++ pnx4008_start_hc();
++ platform_set_drvdata(pdev, hcd);
++ ohci = hcd_to_ohci(hcd);
++ ohci_hcd_init(ohci);
++
++ dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
++ ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
++ if (ret == 0)
++ return ret;
++
++ pnx4008_stop_hc();
++out4:
++ pnx4008_unset_usb_bits();
++ usb_put_hcd(hcd);
++out3:
++ clk_disable(usb_clk);
++out2:
++ clk_put(usb_clk);
++out1:
++ i2c_del_driver(&isp1301_driver);
++out:
++ return ret;
++}
++
++static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ usb_remove_hcd(hcd);
++ pnx4008_stop_hc();
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
++ pnx4008_unset_usb_bits();
++ clk_disable(usb_clk);
++ clk_put(usb_clk);
++ i2c_del_driver(&isp1301_driver);
++
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++static struct platform_driver usb_hcd_pnx4008_driver = {
++ .driver = {
++ .name = "usb-ohci",
++ },
++ .probe = usb_hcd_pnx4008_probe,
++ .remove = usb_hcd_pnx4008_remove,
++};
++
++static int __init usb_hcd_pnx4008_init(void)
++{
++ return platform_driver_register(&usb_hcd_pnx4008_driver);
++}
++
++static void __exit usb_hcd_pnx4008_cleanup(void)
++{
++ return platform_driver_unregister(&usb_hcd_pnx4008_driver);
++}
++
++module_init(usb_hcd_pnx4008_init);
++module_exit(usb_hcd_pnx4008_cleanup);
+diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
+index 9fe56ff..d9d1ae2 100644
+--- a/drivers/usb/host/ohci-ppc-soc.c
++++ b/drivers/usb/host/ohci-ppc-soc.c
+@@ -148,6 +148,7 @@ static const struct hc_driver ohci_ppc_s
+ */
+ .start = ohci_ppc_soc_start,
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -166,6 +167,7 @@ static const struct hc_driver ohci_ppc_s
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -195,6 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(s
+ static struct platform_driver ohci_hcd_ppc_soc_driver = {
+ .probe = ohci_hcd_ppc_soc_drv_probe,
+ .remove = ohci_hcd_ppc_soc_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ #ifdef CONFIG_PM
+ /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
+ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
+diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
+index 6f559e1..e176b04 100644
+--- a/drivers/usb/host/ohci-pxa27x.c
++++ b/drivers/usb/host/ohci-pxa27x.c
+@@ -270,6 +270,7 @@ static const struct hc_driver ohci_pxa27
+ */
+ .start = ohci_pxa27x_start,
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -288,6 +289,7 @@ static const struct hc_driver ohci_pxa27
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -357,6 +359,7 @@ static int ohci_hcd_pxa27x_drv_resume(st
+ static struct platform_driver ohci_hcd_pxa27x_driver = {
+ .probe = ohci_hcd_pxa27x_drv_probe,
+ .remove = ohci_hcd_pxa27x_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ #ifdef CONFIG_PM
+ .suspend = ohci_hcd_pxa27x_drv_suspend,
+ .resume = ohci_hcd_pxa27x_drv_resume,
+diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
+index e372306..fe1fe2f 100644
+--- a/drivers/usb/host/ohci-q.c
++++ b/drivers/usb/host/ohci-q.c
+@@ -7,6 +7,8 @@
+ * This file is licenced under the GPL.
+ */
+
++#include <linux/irq.h>
++
+ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
+ {
+ int last = urb_priv->length - 1;
+@@ -34,7 +36,7 @@ static void urb_free_priv (struct ohci_h
+ * PRECONDITION: ohci lock held, irqs blocked.
+ */
+ static void
+-finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
++finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+ __releases(ohci->lock)
+ __acquires(ohci->lock)
+ {
+@@ -73,7 +75,7 @@ __acquires(ohci->lock)
+
+ /* urb->complete() can reenter this HCD */
+ spin_unlock (&ohci->lock);
+- usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb, regs);
++ usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+ spin_lock (&ohci->lock);
+
+ /* stop periodic dma if it's not needed */
+@@ -910,7 +912,7 @@ static struct td *dl_reverse_done_list (
+
+ /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
+ static void
+-finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
++finish_unlinks (struct ohci_hcd *ohci, u16 tick)
+ {
+ struct ed *ed, **last;
+
+@@ -923,7 +925,7 @@ rescan_all:
+ /* only take off EDs that the HC isn't using, accounting for
+ * frame counter wraps and EDs with partially retired TDs
+ */
+- if (likely (regs && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
++ if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+ if (tick_before (tick, ed->tick)) {
+ skip_ed:
+ last = &ed->ed_next;
+@@ -990,7 +992,7 @@ rescan_this:
+ /* if URB is done, clean up */
+ if (urb_priv->td_cnt == urb_priv->length) {
+ modified = completed = 1;
+- finish_urb (ohci, urb, regs);
++ finish_urb (ohci, urb);
+ }
+ }
+ if (completed && !list_empty (&ed->td_list))
+@@ -1068,7 +1070,7 @@ rescan_this:
+ * scanning the (re-reversed) donelist as this does.
+ */
+ static void
+-dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs)
++dl_done_list (struct ohci_hcd *ohci)
+ {
+ struct td *td = dl_reverse_done_list (ohci);
+
+@@ -1084,7 +1086,7 @@ dl_done_list (struct ohci_hcd *ohci, str
+
+ /* If all this urb's TDs are done, call complete() */
+ if (urb_priv->td_cnt == urb_priv->length)
+- finish_urb (ohci, urb, regs);
++ finish_urb (ohci, urb);
+
+ /* clean schedule: unlink EDs that are no longer busy */
+ if (list_empty (&ed->td_list)) {
+diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
+index d2fc696..59e4364 100644
+--- a/drivers/usb/host/ohci-s3c2410.c
++++ b/drivers/usb/host/ohci-s3c2410.c
+@@ -370,7 +370,7 @@ static int usb_hcd_s3c2410_probe (const
+ goto err_mem;
+ }
+
+- usb_clk = clk_get(&dev->dev, "upll");
++ usb_clk = clk_get(&dev->dev, "usb-bus-host");
+ if (IS_ERR(usb_clk)) {
+ dev_err(&dev->dev, "cannot get usb-host clock\n");
+ retval = -ENOENT;
+@@ -447,6 +447,7 @@ static const struct hc_driver ohci_s3c24
+ */
+ .start = ohci_s3c2410_start,
+ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+@@ -465,6 +466,7 @@ static const struct hc_driver ohci_s3c24
+ */
+ .hub_status_data = ohci_s3c2410_hub_status_data,
+ .hub_control = ohci_s3c2410_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+@@ -490,6 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(s
+ static struct platform_driver ohci_hcd_s3c2410_driver = {
+ .probe = ohci_hcd_s3c2410_drv_probe,
+ .remove = ohci_hcd_s3c2410_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ohci_hcd_s3c2410_drv_suspend, */
+ /*.resume = ohci_hcd_s3c2410_drv_resume, */
+ .driver = {
+diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
+index ce3de10..71371de 100644
+--- a/drivers/usb/host/ohci-sa1111.c
++++ b/drivers/usb/host/ohci-sa1111.c
+@@ -212,10 +212,6 @@ static const struct hc_driver ohci_sa111
+ * basic lifecycle operations
+ */
+ .start = ohci_sa1111_start,
+-#ifdef CONFIG_PM
+- /* suspend: ohci_sa1111_suspend, -- tbd */
+- /* resume: ohci_sa1111_resume, -- tbd */
+-#endif
+ .stop = ohci_stop,
+
+ /*
+@@ -235,6 +231,7 @@ static const struct hc_driver ohci_sa111
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
++ .hub_irq_enable = ohci_rhsc_enable,
+ #ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
+index caacf14..a2f42a2 100644
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -159,7 +159,7 @@ static const int cc_to_error [16] = {
+ /* Bit Stuff */ -EPROTO,
+ /* Data Togg */ -EILSEQ,
+ /* Stall */ -EPIPE,
+- /* DevNotResp */ -ETIMEDOUT,
++ /* DevNotResp */ -ETIME,
+ /* PIDCheck */ -EPROTO,
+ /* UnExpPID */ -EPROTO,
+ /* DataOver */ -EOVERFLOW,
+@@ -388,8 +388,7 @@ struct ohci_hcd {
+ u32 hc_control; /* copy of hc control reg */
+ unsigned long next_statechange; /* suspend/resume */
+ u32 fminterval; /* saved register */
+-
+- struct notifier_block reboot_notifier;
++ unsigned autostop:1; /* rh auto stopping/stopped */
+
+ 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 fa34092..5fa5647 100644
+--- a/drivers/usb/host/sl811-hcd.c
++++ b/drivers/usb/host/sl811-hcd.c
+@@ -428,7 +428,6 @@ static void finish_request(
+ struct sl811 *sl811,
+ struct sl811h_ep *ep,
+ struct urb *urb,
+- struct pt_regs *regs,
+ int status
+ ) __releases(sl811->lock) __acquires(sl811->lock)
+ {
+@@ -444,7 +443,7 @@ static void finish_request(
+ spin_unlock(&urb->lock);
+
+ spin_unlock(&sl811->lock);
+- usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, regs);
++ usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+ spin_lock(&sl811->lock);
+
+ /* leave active endpoints in the schedule */
+@@ -484,7 +483,7 @@ static void finish_request(
+ }
+
+ static void
+-done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
++done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
+ {
+ u8 status;
+ struct urb *urb;
+@@ -597,7 +596,7 @@ done(struct sl811 *sl811, struct sl811h_
+ /* error? retry, until "3 strikes" */
+ } else if (++ep->error_count >= 3) {
+ if (status & SL11H_STATMASK_TMOUT)
+- urbstat = -ETIMEDOUT;
++ urbstat = -ETIME;
+ else if (status & SL11H_STATMASK_OVF)
+ urbstat = -EOVERFLOW;
+ else
+@@ -608,7 +607,7 @@ done(struct sl811 *sl811, struct sl811h_
+ }
+
+ if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+- finish_request(sl811, ep, urb, regs, urbstat);
++ finish_request(sl811, ep, urb, urbstat);
+ }
+
+ static inline u8 checkdone(struct sl811 *sl811)
+@@ -641,7 +640,7 @@ static inline u8 checkdone(struct sl811
+ return irqstat;
+ }
+
+-static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
++static irqreturn_t sl811h_irq(struct usb_hcd *hcd)
+ {
+ struct sl811 *sl811 = hcd_to_sl811(hcd);
+ u8 irqstat;
+@@ -670,13 +669,13 @@ retry:
+ * issued ... that's fine if they're different endpoints.
+ */
+ if (irqstat & SL11H_INTMASK_DONE_A) {
+- done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs);
++ done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF));
+ sl811->active_a = NULL;
+ sl811->stat_a++;
+ }
+ #ifdef USE_B
+ if (irqstat & SL11H_INTMASK_DONE_B) {
+- done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs);
++ done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF));
+ sl811->active_b = NULL;
+ sl811->stat_b++;
+ }
+@@ -723,7 +722,7 @@ retry:
+ container_of(sl811->active_a
+ ->hep->urb_list.next,
+ struct urb, urb_list),
+- NULL, -ESHUTDOWN);
++ -ESHUTDOWN);
+ sl811->active_a = NULL;
+ }
+ #ifdef USE_B
+@@ -957,7 +956,7 @@ static int sl811h_urb_enqueue(
+ spin_lock(&urb->lock);
+ if (urb->status != -EINPROGRESS) {
+ spin_unlock(&urb->lock);
+- finish_request(sl811, ep, urb, NULL, 0);
++ finish_request(sl811, ep, urb, 0);
+ retval = 0;
+ goto fail;
+ }
+@@ -1026,7 +1025,7 @@ static int sl811h_urb_dequeue(struct usb
+ }
+
+ if (urb)
+- finish_request(sl811, ep, urb, NULL, 0);
++ finish_request(sl811, ep, urb, 0);
+ else
+ VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
+ (sl811->active_a == ep) ? "A" : "B");
+@@ -1083,7 +1082,7 @@ sl811h_hub_status_data(struct usb_hcd *h
+ */
+ local_irq_save(flags);
+ if (!timer_pending(&sl811->timer)) {
+- if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)
++ if (sl811h_irq( /* ~0, */ hcd) != IRQ_NONE)
+ sl811->stat_lost++;
+ }
+ local_irq_restore(flags);
+@@ -1517,7 +1516,7 @@ static int proc_sl811h_open(struct inode
+ return single_open(file, proc_sl811h_show, PDE(inode)->data);
+ }
+
+-static struct file_operations proc_ops = {
++static const struct file_operations proc_ops = {
+ .open = proc_sl811h_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -1783,10 +1782,15 @@ sl811h_suspend(struct platform_device *d
+ struct sl811 *sl811 = hcd_to_sl811(hcd);
+ int retval = 0;
+
+- if (state.event == PM_EVENT_FREEZE)
++ switch (state.event) {
++ case PM_EVENT_FREEZE:
+ retval = sl811h_bus_suspend(hcd);
+- else if (state.event == PM_EVENT_SUSPEND)
++ break;
++ case PM_EVENT_SUSPEND:
++ case PM_EVENT_PRETHAW: /* explicitly discard hw state */
+ port_power(sl811, 0);
++ break;
++ }
+ if (retval == 0)
+ dev->dev.power.power_state = state;
+ return retval;
+diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
+new file mode 100644
+index 0000000..32c635e
+--- /dev/null
++++ b/drivers/usb/host/u132-hcd.c
+@@ -0,0 +1,3294 @@
++/*
++* Host Controller Driver for the Elan Digital Systems U132 adapter
++*
++* Copyright(C) 2006 Elan Digital Systems Limited
++* http://www.elandigitalsystems.com
++*
++* Author and Maintainer - Tony Olech - Elan Digital Systems
++* tony.olech at elandigitalsystems.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 was written by Tony Olech(tony.olech at elandigitalsystems.com)
++* based on various USB host drivers in the 2.6.15 linux kernel
++* with constant reference to the 3rd Edition of Linux Device Drivers
++* published by O'Reilly
++*
++* The U132 adapter is a USB to CardBus adapter specifically designed
++* for PC cards that contain an OHCI host controller. Typical PC cards
++* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
++*
++* The U132 adapter will *NOT *work with PC cards that do not contain
++* an OHCI controller. A simple way to test whether a PC card has an
++* OHCI controller as an interface is to insert the PC card directly
++* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
++* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
++* then there is a good chance that the U132 adapter will support the
++* PC card.(you also need the specific client driver for the PC card)
++*
++* Please inform the Author and Maintainer about any PC cards that
++* contain OHCI Host Controller and work when directly connected to
++* an embedded CardBus slot but do not work when they are connected
++* via an ELAN U132 adapter.
++*
++*/
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.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/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/usb.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/pci_ids.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/byteorder.h>
++#include "../core/hcd.h"
++#include "ohci.h"
++#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
++#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
++ OHCI_INTR_WDH)
++MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
++MODULE_DESCRIPTION("U132 USB Host Controller Driver");
++MODULE_LICENSE("GPL");
++#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
++INT_MODULE_PARM(testing, 0);
++/* Some boards misreport power switching/overcurrent*/
++static int distrust_firmware = 1;
++module_param(distrust_firmware, bool, 0);
++MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
++ "t setup");
++DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
++/*
++* u132_module_lock exists to protect access to global variables
++*
++*/
++static struct semaphore u132_module_lock;
++static int u132_exiting = 0;
++static int u132_instances = 0;
++static struct list_head u132_static_list;
++/*
++* end of the global variables protected by u132_module_lock
++*/
++static struct workqueue_struct *workqueue;
++#define MAX_U132_PORTS 7
++#define MAX_U132_ADDRS 128
++#define MAX_U132_UDEVS 4
++#define MAX_U132_ENDPS 100
++#define MAX_U132_RINGS 4
++static const char *cc_to_text[16] = {
++ "No Error ",
++ "CRC Error ",
++ "Bit Stuff ",
++ "Data Togg ",
++ "Stall ",
++ "DevNotResp ",
++ "PIDCheck ",
++ "UnExpPID ",
++ "DataOver ",
++ "DataUnder ",
++ "(for hw) ",
++ "(for hw) ",
++ "BufferOver ",
++ "BuffUnder ",
++ "(for HCD) ",
++ "(for HCD) "
++};
++struct u132_port {
++ struct u132 *u132;
++ int reset;
++ int enable;
++ int power;
++ int Status;
++};
++struct u132_addr {
++ u8 address;
++};
++struct u132_udev {
++ struct kref kref;
++ struct usb_device *usb_device;
++ u8 enumeration;
++ u8 udev_number;
++ u8 usb_addr;
++ u8 portnumber;
++ u8 endp_number_in[16];
++ u8 endp_number_out[16];
++};
++#define ENDP_QUEUE_SHIFT 3
++#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
++#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
++struct u132_urbq {
++ struct list_head urb_more;
++ struct urb *urb;
++};
++struct u132_spin {
++ spinlock_t slock;
++};
++struct u132_endp {
++ struct kref kref;
++ u8 udev_number;
++ u8 endp_number;
++ u8 usb_addr;
++ u8 usb_endp;
++ struct u132 *u132;
++ struct list_head endp_ring;
++ struct u132_ring *ring;
++ unsigned toggle_bits:2;
++ unsigned active:1;
++ unsigned delayed:1;
++ unsigned input:1;
++ unsigned output:1;
++ unsigned pipetype:2;
++ unsigned dequeueing:1;
++ unsigned edset_flush:1;
++ unsigned spare_bits:14;
++ unsigned long jiffies;
++ struct usb_host_endpoint *hep;
++ struct u132_spin queue_lock;
++ u16 queue_size;
++ u16 queue_last;
++ u16 queue_next;
++ struct urb *urb_list[ENDP_QUEUE_SIZE];
++ struct list_head urb_more;
++ struct work_struct scheduler;
++};
++struct u132_ring {
++ unsigned in_use:1;
++ unsigned length:7;
++ u8 number;
++ struct u132 *u132;
++ struct u132_endp *curr_endp;
++ struct work_struct scheduler;
++};
++#define OHCI_QUIRK_AMD756 0x01
++#define OHCI_QUIRK_SUPERIO 0x02
++#define OHCI_QUIRK_INITRESET 0x04
++#define OHCI_BIG_ENDIAN 0x08
++#define OHCI_QUIRK_ZFMICRO 0x10
++struct u132 {
++ struct kref kref;
++ struct list_head u132_list;
++ struct semaphore sw_lock;
++ struct semaphore scheduler_lock;
++ struct u132_platform_data *board;
++ struct platform_device *platform_dev;
++ struct u132_ring ring[MAX_U132_RINGS];
++ int sequence_num;
++ int going;
++ int power;
++ int reset;
++ int num_ports;
++ u32 hc_control;
++ u32 hc_fminterval;
++ u32 hc_roothub_status;
++ u32 hc_roothub_a;
++ u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
++ int flags;
++ unsigned long next_statechange;
++ struct work_struct monitor;
++ int num_endpoints;
++ struct u132_addr addr[MAX_U132_ADDRS];
++ struct u132_udev udev[MAX_U132_UDEVS];
++ struct u132_port port[MAX_U132_PORTS];
++ struct u132_endp *endp[MAX_U132_ENDPS];
++};
++int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data);
++int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs,
++ u8 width, u32 *data);
++int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs,
++ u8 width, u32 data);
++/*
++* these can not be inlines because we need the structure offset!!
++* Does anyone have a better way?????
++*/
++#define u132_read_pcimem(u132, member, data) \
++ usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
++ ohci_regs, member), 0, data);
++#define u132_write_pcimem(u132, member, data) \
++ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
++ ohci_regs, member), 0, data);
++#define u132_write_pcimem_byte(u132, member, data) \
++ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
++ ohci_regs, member), 0x0e, data);
++static inline struct u132 *udev_to_u132(struct u132_udev *udev)
++{
++ u8 udev_number = udev->udev_number;
++ return container_of(udev, struct u132, udev[udev_number]);
++}
++
++static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
++{
++ return (struct u132 *)(hcd->hcd_priv);
++}
++
++static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
++{
++ return container_of((void *)u132, struct usb_hcd, hcd_priv);
++}
++
++static inline void u132_disable(struct u132 *u132)
++{
++ u132_to_hcd(u132)->state = HC_STATE_HALT;
++}
++
++
++#define kref_to_u132(d) container_of(d, struct u132, kref)
++#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref)
++#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref)
++#include "../misc/usb_u132.h"
++static const char hcd_name[] = "u132_hcd";
++#define PORT_C_MASK ((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 void u132_hcd_delete(struct kref *kref)
++{
++ struct u132 *u132 = kref_to_u132(kref);
++ struct platform_device *pdev = u132->platform_dev;
++ struct usb_hcd *hcd = u132_to_hcd(u132);
++ u132->going += 1;
++ down(&u132_module_lock);
++ list_del_init(&u132->u132_list);
++ u132_instances -= 1;
++ up(&u132_module_lock);
++ dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
++ "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
++ usb_put_hcd(hcd);
++}
++
++static inline void u132_u132_put_kref(struct u132 *u132)
++{
++ kref_put(&u132->kref, u132_hcd_delete);
++}
++
++static inline void u132_u132_init_kref(struct u132 *u132)
++{
++ kref_init(&u132->kref);
++}
++
++static void u132_udev_delete(struct kref *kref)
++{
++ struct u132_udev *udev = kref_to_u132_udev(kref);
++ udev->udev_number = 0;
++ udev->usb_device = NULL;
++ udev->usb_addr = 0;
++ udev->enumeration = 0;
++}
++
++static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
++{
++ kref_put(&udev->kref, u132_udev_delete);
++}
++
++static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
++{
++ kref_get(&udev->kref);
++}
++
++static inline void u132_udev_init_kref(struct u132 *u132,
++ struct u132_udev *udev)
++{
++ kref_init(&udev->kref);
++}
++
++static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
++{
++ kref_put(&u132->kref, u132_hcd_delete);
++}
++
++static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
++ unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(workqueue, &ring->scheduler, delta))
++ return;
++ } else if (queue_work(workqueue, &ring->scheduler))
++ return;
++ kref_put(&u132->kref, u132_hcd_delete);
++ return;
++}
++
++static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
++ unsigned int delta)
++{
++ kref_get(&u132->kref);
++ u132_ring_requeue_work(u132, ring, delta);
++ return;
++}
++
++static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
++{
++ if (cancel_delayed_work(&ring->scheduler)) {
++ kref_put(&u132->kref, u132_hcd_delete);
++ }
++}
++
++static void u132_endp_delete(struct kref *kref)
++{
++ struct u132_endp *endp = kref_to_u132_endp(kref);
++ struct u132 *u132 = endp->u132;
++ u8 usb_addr = endp->usb_addr;
++ u8 usb_endp = endp->usb_endp;
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ u8 endp_number = endp->endp_number;
++ struct usb_host_endpoint *hep = endp->hep;
++ struct u132_ring *ring = endp->ring;
++ struct list_head *head = &endp->endp_ring;
++ ring->length -= 1;
++ if (endp == ring->curr_endp) {
++ if (list_empty(head)) {
++ ring->curr_endp = NULL;
++ list_del(head);
++ } else {
++ struct u132_endp *next_endp = list_entry(head->next,
++ struct u132_endp, endp_ring);
++ ring->curr_endp = next_endp;
++ list_del(head);
++ }} else
++ list_del(head);
++ if (endp->input) {
++ udev->endp_number_in[usb_endp] = 0;
++ u132_udev_put_kref(u132, udev);
++ }
++ if (endp->output) {
++ udev->endp_number_out[usb_endp] = 0;
++ u132_udev_put_kref(u132, udev);
++ }
++ u132->endp[endp_number - 1] = NULL;
++ hep->hcpriv = NULL;
++ kfree(endp);
++ u132_u132_put_kref(u132);
++}
++
++static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
++{
++ kref_put(&endp->kref, u132_endp_delete);
++}
++
++static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
++{
++ kref_get(&endp->kref);
++}
++
++static inline void u132_endp_init_kref(struct u132 *u132,
++ struct u132_endp *endp)
++{
++ kref_init(&endp->kref);
++ kref_get(&u132->kref);
++}
++
++static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
++ unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(workqueue, &endp->scheduler, delta))
++ kref_get(&endp->kref);
++ } else if (queue_work(workqueue, &endp->scheduler))
++ kref_get(&endp->kref);
++ return;
++}
++
++static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
++{
++ if (cancel_delayed_work(&endp->scheduler))
++ kref_put(&endp->kref, u132_endp_delete);
++}
++
++static inline void u132_monitor_put_kref(struct u132 *u132)
++{
++ kref_put(&u132->kref, u132_hcd_delete);
++}
++
++static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(workqueue, &u132->monitor, delta)) {
++ kref_get(&u132->kref);
++ }
++ } else if (queue_work(workqueue, &u132->monitor))
++ kref_get(&u132->kref);
++ return;
++}
++
++static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(workqueue, &u132->monitor, delta))
++ return;
++ } else if (queue_work(workqueue, &u132->monitor))
++ return;
++ kref_put(&u132->kref, u132_hcd_delete);
++ return;
++}
++
++static void u132_monitor_cancel_work(struct u132 *u132)
++{
++ if (cancel_delayed_work(&u132->monitor))
++ kref_put(&u132->kref, u132_hcd_delete);
++}
++
++static int read_roothub_info(struct u132 *u132)
++{
++ u32 revision;
++ int retval;
++ retval = u132_read_pcimem(u132, revision, &revision);
++ if (retval) {
++ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
++ "ntrol\n", retval);
++ return retval;
++ } else if ((revision & 0xFF) == 0x10) {
++ } else if ((revision & 0xFF) == 0x11) {
++ } else {
++ dev_err(&u132->platform_dev->dev, "device revision is not valid"
++ " %08X\n", revision);
++ return -ENODEV;
++ }
++ retval = u132_read_pcimem(u132, control, &u132->hc_control);
++ if (retval) {
++ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
++ "ntrol\n", retval);
++ return retval;
++ }
++ retval = u132_read_pcimem(u132, roothub.status,
++ &u132->hc_roothub_status);
++ if (retval) {
++ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
++ "g roothub.status\n", retval);
++ return retval;
++ }
++ retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
++ if (retval) {
++ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
++ "g roothub.a\n", retval);
++ return retval;
++ }
++ {
++ int I = u132->num_ports;
++ int i = 0;
++ while (I-- > 0) {
++ retval = u132_read_pcimem(u132, roothub.portstatus[i],
++ &u132->hc_roothub_portstatus[i]);
++ if (retval) {
++ dev_err(&u132->platform_dev->dev, "error %d acc"
++ "essing device roothub.portstatus[%d]\n"
++ , retval, i);
++ return retval;
++ } else
++ i += 1;
++ }
++ }
++ return 0;
++}
++
++static void u132_hcd_monitor_work(void *data)
++{
++ struct u132 *u132 = data;
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ u132_monitor_put_kref(u132);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ u132_monitor_put_kref(u132);
++ return;
++ } else {
++ int retval;
++ down(&u132->sw_lock);
++ retval = read_roothub_info(u132);
++ if (retval) {
++ struct usb_hcd *hcd = u132_to_hcd(u132);
++ u132_disable(u132);
++ u132->going = 1;
++ up(&u132->sw_lock);
++ usb_hc_died(hcd);
++ ftdi_elan_gone_away(u132->platform_dev);
++ u132_monitor_put_kref(u132);
++ return;
++ } else {
++ u132_monitor_requeue_work(u132, 500);
++ up(&u132->sw_lock);
++ return;
++ }
++ }
++}
++
++static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
++ struct urb *urb, int status)
++{
++ struct u132_ring *ring;
++ unsigned long irqs;
++ struct usb_hcd *hcd = u132_to_hcd(u132);
++ urb->error_count = 0;
++ urb->status = status;
++ urb->hcpriv = NULL;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ endp->queue_next += 1;
++ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
++ endp->active = 0;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ } else {
++ struct list_head *next = endp->urb_more.next;
++ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
++ urb_more);
++ list_del(next);
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
++ urbq->urb;
++ endp->active = 0;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ kfree(urbq);
++ } down(&u132->scheduler_lock);
++ ring = endp->ring;
++ ring->in_use = 0;
++ u132_ring_cancel_work(u132, ring);
++ u132_ring_queue_work(u132, ring, 0);
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ usb_hcd_giveback_urb(hcd, urb);
++ return;
++}
++
++static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
++ struct urb *urb, int status)
++{
++ u132_endp_put_kref(u132, endp);
++}
++
++static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
++ struct urb *urb, int status)
++{
++ unsigned long irqs;
++ struct usb_hcd *hcd = u132_to_hcd(u132);
++ urb->error_count = 0;
++ urb->status = status;
++ urb->hcpriv = NULL;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ endp->queue_next += 1;
++ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
++ endp->active = 0;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ } else {
++ struct list_head *next = endp->urb_more.next;
++ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
++ urb_more);
++ list_del(next);
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
++ urbq->urb;
++ endp->active = 0;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ kfree(urbq);
++ } usb_hcd_giveback_urb(hcd, urb);
++ return;
++}
++
++static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
++ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
++ urb, address, endp->usb_endp, toggle_bits, callback);
++}
++
++static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
++ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
++ urb, address, endp->usb_endp, toggle_bits, callback);
++}
++
++static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
++ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
++ endp, urb, address, endp->usb_endp, toggle_bits, callback);
++}
++
++static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
++ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
++ endp, urb, address, endp->usb_endp, toggle_bits, callback);
++}
++
++
++/*
++* must not LOCK sw_lock
++*
++*/
++static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ struct u132_ring *ring = endp->ring;
++ u8 *u = urb->transfer_buffer + urb->actual_length;
++ u8 *b = buf;
++ int L = len;
++ while (L-- > 0) {
++ *u++ = *b++;
++ }
++ urb->actual_length += len;
++ if ((condition_code == TD_CC_NOERROR) &&
++ (urb->transfer_buffer_length > urb->actual_length)) {
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
++ 1 & toggle_bits);
++ if (urb->actual_length > 0) {
++ int retval;
++ up(&u132->scheduler_lock);
++ retval = edset_single(u132, ring, endp, urb,
++ address, endp->toggle_bits,
++ u132_hcd_interrupt_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb,
++ retval);
++ } else {
++ ring->in_use = 0;
++ endp->active = 0;
++ endp->jiffies = jiffies +
++ msecs_to_jiffies(urb->interval);
++ u132_ring_cancel_work(u132, ring);
++ u132_ring_queue_work(u132, ring, 0);
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ }
++ return;
++ } else if ((condition_code == TD_DATAUNDERRUN) &&
++ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
++ 1 & toggle_bits);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else {
++ if (condition_code == TD_CC_NOERROR) {
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp,
++ 0, 1 & toggle_bits);
++ } else if (condition_code == TD_CC_STALL) {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, endp->usb_endp,
++ 0, 0);
++ } else {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, endp->usb_endp,
++ 0, 0);
++ dev_err(&u132->platform_dev->dev, "urb=%p givin"
++ "g back INTERRUPT %s\n", urb,
++ cc_to_text[condition_code]);
++ }
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb,
++ cc_to_error[condition_code]);
++ return;
++ }
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ struct u132_ring *ring = endp->ring;
++ urb->actual_length += len;
++ endp->toggle_bits = toggle_bits;
++ if (urb->transfer_buffer_length > urb->actual_length) {
++ int retval;
++ up(&u132->scheduler_lock);
++ retval = edset_output(u132, ring, endp, urb, address,
++ endp->toggle_bits, u132_hcd_bulk_output_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else {
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ }
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ struct u132_ring *ring = endp->ring;
++ u8 *u = urb->transfer_buffer + urb->actual_length;
++ u8 *b = buf;
++ int L = len;
++ while (L-- > 0) {
++ *u++ = *b++;
++ }
++ urb->actual_length += len;
++ if ((condition_code == TD_CC_NOERROR) &&
++ (urb->transfer_buffer_length > urb->actual_length)) {
++ int retval;
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
++ 1 & toggle_bits);
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
++ ring->number, endp, urb, address,
++ endp->usb_endp, endp->toggle_bits,
++ u132_hcd_bulk_input_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else if (condition_code == TD_CC_NOERROR) {
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
++ 1 & toggle_bits);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb,
++ cc_to_error[condition_code]);
++ return;
++ } else if ((condition_code == TD_DATAUNDERRUN) &&
++ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
++ 1 & toggle_bits);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else if (condition_code == TD_DATAUNDERRUN) {
++ endp->toggle_bits = toggle_bits;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
++ 1 & toggle_bits);
++ dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
++ ") giving back BULK IN %s\n", urb,
++ cc_to_text[condition_code]);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else if (condition_code == TD_CC_STALL) {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb,
++ cc_to_error[condition_code]);
++ return;
++ } else {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
++ dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
++ "ULK IN code=%d %s\n", urb, condition_code,
++ cc_to_text[condition_code]);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb,
++ cc_to_error[condition_code]);
++ return;
++ }
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ struct u132_ring *ring = endp->ring;
++ u8 *u = urb->transfer_buffer;
++ u8 *b = buf;
++ int L = len;
++ while (L-- > 0) {
++ *u++ = *b++;
++ }
++ urb->actual_length = len;
++ if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
++ TD_DATAUNDERRUN) && ((urb->transfer_flags &
++ URB_SHORT_NOT_OK) == 0))) {
++ int retval;
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
++ ring->number, endp, urb, address,
++ endp->usb_endp, 0x3,
++ u132_hcd_configure_empty_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else if (condition_code == TD_CC_STALL) {
++ up(&u132->scheduler_lock);
++ dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
++ "NPUT STALL urb %p\n", urb);
++ u132_hcd_giveback_urb(u132, endp, urb,
++ cc_to_error[condition_code]);
++ return;
++ } else {
++ up(&u132->scheduler_lock);
++ dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
++ "PUT %s urb %p\n", cc_to_text[condition_code],
++ urb);
++ u132_hcd_giveback_urb(u132, endp, urb,
++ cc_to_error[condition_code]);
++ return;
++ }
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ if (usb_pipein(urb->pipe)) {
++ int retval;
++ struct u132_ring *ring = endp->ring;
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
++ ring->number, endp, urb, address,
++ endp->usb_endp, 0,
++ u132_hcd_configure_input_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else {
++ int retval;
++ struct u132_ring *ring = endp->ring;
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
++ ring->number, endp, urb, address,
++ endp->usb_endp, 0,
++ u132_hcd_configure_empty_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ }
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
++ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ u132->addr[0].address = 0;
++ endp->usb_addr = udev->usb_addr;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
++ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ int retval;
++ struct u132_ring *ring = endp->ring;
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
++ ring->number, endp, urb, 0, endp->usb_endp, 0,
++ u132_hcd_enumeration_empty_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, 0);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ int retval;
++ struct u132_ring *ring = endp->ring;
++ u8 *u = urb->transfer_buffer;
++ u8 *b = buf;
++ int L = len;
++ while (L-- > 0) {
++ *u++ = *b++;
++ }
++ urb->actual_length = len;
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
++ ring->number, endp, urb, address, endp->usb_endp, 0x3,
++ u132_hcd_initial_empty_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
++ int len, int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual, int non_null)
++{
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ u8 address = u132->addr[endp->usb_addr].address;
++ down(&u132->scheduler_lock);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ up(&u132->scheduler_lock);
++ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (endp->dequeueing) {
++ endp->dequeueing = 0;
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
++ return;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
++ return;
++ } else if (urb->status == -EINPROGRESS) {
++ int retval;
++ struct u132_ring *ring = endp->ring;
++ up(&u132->scheduler_lock);
++ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
++ ring->number, endp, urb, address, endp->usb_endp, 0,
++ u132_hcd_initial_input_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else {
++ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
++ "s=%d\n", urb, urb->status);
++ up(&u132->scheduler_lock);
++ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
++ return;
++ }
++}
++
++static void u132_hcd_ring_work_scheduler(void *data);
++static void u132_hcd_endp_work_scheduler(void *data);
++/*
++* this work function is only executed from the work queue
++*
++*/
++static void u132_hcd_ring_work_scheduler(void *data)
++{
++ struct u132_ring *ring = data;
++ struct u132 *u132 = ring->u132;
++ down(&u132->scheduler_lock);
++ if (ring->in_use) {
++ up(&u132->scheduler_lock);
++ u132_ring_put_kref(u132, ring);
++ return;
++ } else if (ring->curr_endp) {
++ struct u132_endp *last_endp = ring->curr_endp;
++ struct list_head *scan;
++ struct list_head *head = &last_endp->endp_ring;
++ unsigned long wakeup = 0;
++ list_for_each(scan, head) {
++ struct u132_endp *endp = list_entry(scan,
++ struct u132_endp, endp_ring);
++ if (endp->queue_next == endp->queue_last) {
++ } else if ((endp->delayed == 0)
++ || time_after_eq(jiffies, endp->jiffies)) {
++ ring->curr_endp = endp;
++ u132_endp_cancel_work(u132, last_endp);
++ u132_endp_queue_work(u132, last_endp, 0);
++ up(&u132->scheduler_lock);
++ u132_ring_put_kref(u132, ring);
++ return;
++ } else {
++ unsigned long delta = endp->jiffies - jiffies;
++ if (delta > wakeup)
++ wakeup = delta;
++ }
++ }
++ if (last_endp->queue_next == last_endp->queue_last) {
++ } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
++ last_endp->jiffies)) {
++ u132_endp_cancel_work(u132, last_endp);
++ u132_endp_queue_work(u132, last_endp, 0);
++ up(&u132->scheduler_lock);
++ u132_ring_put_kref(u132, ring);
++ return;
++ } else {
++ unsigned long delta = last_endp->jiffies - jiffies;
++ if (delta > wakeup)
++ wakeup = delta;
++ }
++ if (wakeup > 0) {
++ u132_ring_requeue_work(u132, ring, wakeup);
++ up(&u132->scheduler_lock);
++ return;
++ } else {
++ up(&u132->scheduler_lock);
++ u132_ring_put_kref(u132, ring);
++ return;
++ }
++ } else {
++ up(&u132->scheduler_lock);
++ u132_ring_put_kref(u132, ring);
++ return;
++ }
++}
++
++static void u132_hcd_endp_work_scheduler(void *data)
++{
++ struct u132_ring *ring;
++ struct u132_endp *endp = data;
++ struct u132 *u132 = endp->u132;
++ down(&u132->scheduler_lock);
++ ring = endp->ring;
++ if (endp->edset_flush) {
++ endp->edset_flush = 0;
++ if (endp->dequeueing)
++ usb_ftdi_elan_edset_flush(u132->platform_dev,
++ ring->number, endp);
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else if (endp->active) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else if (ring->in_use) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else if (endp->queue_next == endp->queue_last) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else if (endp->pipetype == PIPE_INTERRUPT) {
++ u8 address = u132->addr[endp->usb_addr].address;
++ if (ring->in_use) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else {
++ int retval;
++ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
++ endp->queue_next];
++ endp->active = 1;
++ ring->curr_endp = endp;
++ ring->in_use = 1;
++ up(&u132->scheduler_lock);
++ retval = edset_single(u132, ring, endp, urb, address,
++ endp->toggle_bits, u132_hcd_interrupt_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ }
++ } else if (endp->pipetype == PIPE_CONTROL) {
++ u8 address = u132->addr[endp->usb_addr].address;
++ if (ring->in_use) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else if (address == 0) {
++ int retval;
++ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
++ endp->queue_next];
++ endp->active = 1;
++ ring->curr_endp = endp;
++ ring->in_use = 1;
++ up(&u132->scheduler_lock);
++ retval = edset_setup(u132, ring, endp, urb, address,
++ 0x2, u132_hcd_initial_setup_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else if (endp->usb_addr == 0) {
++ int retval;
++ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
++ endp->queue_next];
++ endp->active = 1;
++ ring->curr_endp = endp;
++ ring->in_use = 1;
++ up(&u132->scheduler_lock);
++ retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
++ u132_hcd_enumeration_address_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ } else {
++ int retval;
++ u8 address = u132->addr[endp->usb_addr].address;
++ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
++ endp->queue_next];
++ endp->active = 1;
++ ring->curr_endp = endp;
++ ring->in_use = 1;
++ up(&u132->scheduler_lock);
++ retval = edset_setup(u132, ring, endp, urb, address,
++ 0x2, u132_hcd_configure_setup_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb, retval);
++ return;
++ }
++ } else {
++ if (endp->input) {
++ u8 address = u132->addr[endp->usb_addr].address;
++ if (ring->in_use) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else {
++ int retval;
++ struct urb *urb = endp->urb_list[
++ ENDP_QUEUE_MASK & endp->queue_next];
++ endp->active = 1;
++ ring->curr_endp = endp;
++ ring->in_use = 1;
++ up(&u132->scheduler_lock);
++ retval = edset_input(u132, ring, endp, urb,
++ address, endp->toggle_bits,
++ u132_hcd_bulk_input_recv);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb,
++ retval);
++ return;
++ }
++ } else { /* output pipe */
++ u8 address = u132->addr[endp->usb_addr].address;
++ if (ring->in_use) {
++ up(&u132->scheduler_lock);
++ u132_endp_put_kref(u132, endp);
++ return;
++ } else {
++ int retval;
++ struct urb *urb = endp->urb_list[
++ ENDP_QUEUE_MASK & endp->queue_next];
++ endp->active = 1;
++ ring->curr_endp = endp;
++ ring->in_use = 1;
++ up(&u132->scheduler_lock);
++ retval = edset_output(u132, ring, endp, urb,
++ address, endp->toggle_bits,
++ u132_hcd_bulk_output_sent);
++ if (retval == 0) {
++ } else
++ u132_hcd_giveback_urb(u132, endp, urb,
++ retval);
++ return;
++ }
++ }
++ }
++}
++
++static void port_power(struct u132 *u132, int pn, int is_on)
++{
++ u132->port[pn].power = is_on;
++}
++
++static void u132_power(struct u132 *u132, int is_on)
++{
++ struct usb_hcd *hcd = u132_to_hcd(u132)
++ ; /* hub is inactive unless the port is powered */
++ if (is_on) {
++ if (u132->power)
++ return;
++ u132->power = 1;
++ hcd->self.controller->power.power_state = PMSG_ON;
++ } else {
++ u132->power = 0;
++ hcd->state = HC_STATE_HALT;
++ hcd->self.controller->power.power_state = PMSG_SUSPEND;
++ }
++}
++
++static int u132_periodic_reinit(struct u132 *u132)
++{
++ int retval;
++ u32 fi = u132->hc_fminterval & 0x03fff;
++ u32 fit;
++ u32 fminterval;
++ retval = u132_read_pcimem(u132, fminterval, &fminterval);
++ if (retval)
++ return retval;
++ fit = fminterval & FIT;
++ retval = u132_write_pcimem(u132, fminterval,
++ (fit ^ FIT) | u132->hc_fminterval);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem(u132, periodicstart,
++ ((9 *fi) / 10) & 0x3fff);
++ if (retval)
++ return retval;
++ return 0;
++}
++
++static char *hcfs2string(int state)
++{
++ switch (state) {
++ case OHCI_USB_RESET:
++ return "reset";
++ case OHCI_USB_RESUME:
++ return "resume";
++ case OHCI_USB_OPER:
++ return "operational";
++ case OHCI_USB_SUSPEND:
++ return "suspend";
++ }
++ return "?";
++}
++
++static int u132_usb_reset(struct u132 *u132)
++{
++ int retval;
++ retval = u132_read_pcimem(u132, control, &u132->hc_control);
++ if (retval)
++ return retval;
++ u132->hc_control &= OHCI_CTRL_RWC;
++ retval = u132_write_pcimem(u132, control, u132->hc_control);
++ if (retval)
++ return retval;
++ return 0;
++}
++
++static int u132_init(struct u132 *u132)
++{
++ int retval;
++ u32 control;
++ u132_disable(u132);
++ u132->next_statechange =
++ jiffies; /* SMM owns the HC? not for long! */ {
++ u32 control;
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ if (control & OHCI_CTRL_IR) {
++ u32 temp = 50;
++ retval = u132_write_pcimem(u132, intrenable,
++ OHCI_INTR_OC);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem_byte(u132, cmdstatus,
++ OHCI_OCR);
++ if (retval)
++ return retval;
++ check:{
++ retval = u132_read_pcimem(u132, control,
++ &control);
++ if (retval)
++ return retval;
++ }
++ if (control & OHCI_CTRL_IR) {
++ msleep(10);
++ if (--temp == 0) {
++ dev_err(&u132->platform_dev->dev, "USB "
++ "HC takeover failed!(BIOS/SMM b"
++ "ug) control=%08X\n", control);
++ return -EBUSY;
++ }
++ goto check;
++ }
++ u132_usb_reset(u132);
++ }
++ }
++ retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ if (u132->num_ports == 0) {
++ u32 rh_a = -1;
++ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
++ if (retval)
++ return retval;
++ u132->num_ports = rh_a & RH_A_NDP;
++ retval = read_roothub_info(u132);
++ if (retval)
++ return retval;
++ }
++ if (u132->num_ports > MAX_U132_PORTS) {
++ return -EINVAL;
++ }
++ return 0;
++}
++
++
++/* Start an OHCI controller, set the BUS operational
++* resets USB and controller
++* enable interrupts
++*/
++static int u132_run(struct u132 *u132)
++{
++ int retval;
++ u32 control;
++ u32 status;
++ u32 fminterval;
++ u32 periodicstart;
++ u32 cmdstatus;
++ u32 roothub_a;
++ int mask = OHCI_INTR_INIT;
++ int first = u132->hc_fminterval == 0;
++ int sleep_time = 0;
++ int reset_timeout = 30; /* ... allow extra time */
++ u132_disable(u132);
++ if (first) {
++ u32 temp;
++ retval = u132_read_pcimem(u132, fminterval, &temp);
++ if (retval)
++ return retval;
++ u132->hc_fminterval = temp & 0x3fff;
++ if (u132->hc_fminterval != FI) {
++ }
++ u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
++ }
++ retval = u132_read_pcimem(u132, control, &u132->hc_control);
++ if (retval)
++ return retval;
++ dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
++ "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
++ u132->hc_control);
++ switch (u132->hc_control & OHCI_CTRL_HCFS) {
++ case OHCI_USB_OPER:
++ sleep_time = 0;
++ break;
++ case OHCI_USB_SUSPEND:
++ case OHCI_USB_RESUME:
++ u132->hc_control &= OHCI_CTRL_RWC;
++ u132->hc_control |= OHCI_USB_RESUME;
++ sleep_time = 10;
++ break;
++ default:
++ u132->hc_control &= OHCI_CTRL_RWC;
++ u132->hc_control |= OHCI_USB_RESET;
++ sleep_time = 50;
++ break;
++ }
++ retval = u132_write_pcimem(u132, control, u132->hc_control);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ msleep(sleep_time);
++ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
++ if (retval)
++ return retval;
++ if (!(roothub_a & RH_A_NPS)) {
++ int temp; /* power down each port */
++ for (temp = 0; temp < u132->num_ports; temp++) {
++ retval = u132_write_pcimem(u132,
++ roothub.portstatus[temp], RH_PS_LSDA);
++ if (retval)
++ return retval;
++ }
++ }
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ retry:retval = u132_read_pcimem(u132, cmdstatus, &status);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR);
++ if (retval)
++ return retval;
++ extra:{
++ retval = u132_read_pcimem(u132, cmdstatus, &status);
++ if (retval)
++ return retval;
++ if (0 != (status & OHCI_HCR)) {
++ if (--reset_timeout == 0) {
++ dev_err(&u132->platform_dev->dev, "USB HC reset"
++ " timed out!\n");
++ return -ENODEV;
++ } else {
++ msleep(5);
++ goto extra;
++ }
++ }
++ }
++ if (u132->flags & OHCI_QUIRK_INITRESET) {
++ retval = u132_write_pcimem(u132, control, u132->hc_control);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ }
++ retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem(u132, hcca, 0x00000000);
++ if (retval)
++ return retval;
++ retval = u132_periodic_reinit(u132);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, fminterval, &fminterval);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
++ if (retval)
++ return retval;
++ if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
++ if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
++ u132->flags |= OHCI_QUIRK_INITRESET;
++ goto retry;
++ } else
++ dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
++ "\n", fminterval, periodicstart);
++ } /* start controller operations */
++ u132->hc_control &= OHCI_CTRL_RWC;
++ u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
++ retval = u132_write_pcimem(u132, control, u132->hc_control);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
++ retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem(u132, intrstatus, mask);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem(u132, intrdisable,
++ OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
++ OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
++ OHCI_INTR_SO);
++ if (retval)
++ return retval; /* handle root hub init quirks ... */
++ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
++ if (retval)
++ return retval;
++ roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
++ if (u132->flags & OHCI_QUIRK_SUPERIO) {
++ roothub_a |= RH_A_NOCP;
++ roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
++ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
++ if (retval)
++ return retval;
++ } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
++ roothub_a |= RH_A_NPS;
++ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
++ if (retval)
++ return retval;
++ }
++ retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
++ if (retval)
++ return retval;
++ retval = u132_write_pcimem(u132, roothub.b,
++ (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
++ if (retval)
++ return retval;
++ retval = u132_read_pcimem(u132, control, &control);
++ if (retval)
++ return retval;
++ mdelay((roothub_a >> 23) & 0x1fe);
++ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
++ return 0;
++}
++
++static void u132_hcd_stop(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
++ "ed\n", hcd);
++ } else {
++ down(&u132->sw_lock);
++ msleep(100);
++ u132_power(u132, 0);
++ up(&u132->sw_lock);
++ }
++}
++
++static int u132_hcd_start(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else if (hcd->self.controller) {
++ int retval;
++ struct platform_device *pdev =
++ to_platform_device(hcd->self.controller);
++ u16 vendor = ((struct u132_platform_data *)
++ (pdev->dev.platform_data))->vendor;
++ u16 device = ((struct u132_platform_data *)
++ (pdev->dev.platform_data))->device;
++ down(&u132->sw_lock);
++ msleep(10);
++ if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
++ u132->flags = OHCI_QUIRK_AMD756;
++ } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
++ dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
++ "ounds unavailable\n");
++ } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
++ u132->flags |= OHCI_QUIRK_ZFMICRO;
++ retval = u132_run(u132);
++ if (retval) {
++ u132_disable(u132);
++ u132->going = 1;
++ }
++ msleep(100);
++ up(&u132->sw_lock);
++ return retval;
++ } else {
++ dev_err(&u132->platform_dev->dev, "platform_device missing\n");
++ return -ENODEV;
++ }
++}
++
++static int u132_hcd_reset(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else {
++ int retval;
++ down(&u132->sw_lock);
++ retval = u132_init(u132);
++ if (retval) {
++ u132_disable(u132);
++ u132->going = 1;
++ }
++ up(&u132->sw_lock);
++ return retval;
++ }
++}
++
++static int create_endpoint_and_queue_int(struct u132 *u132,
++ struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
++ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
++ gfp_t mem_flags)
++{
++ struct u132_ring *ring;
++ unsigned long irqs;
++ u8 endp_number = ++u132->num_endpoints;
++ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
++ kmalloc(sizeof(struct u132_endp), mem_flags);
++ if (!endp) {
++ return -ENOMEM;
++ }
++ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
++ spin_lock_init(&endp->queue_lock.slock);
++ INIT_LIST_HEAD(&endp->urb_more);
++ ring = endp->ring = &u132->ring[0];
++ if (ring->curr_endp) {
++ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
++ } else {
++ INIT_LIST_HEAD(&endp->endp_ring);
++ ring->curr_endp = endp;
++ }
++ ring->length += 1;
++ endp->dequeueing = 0;
++ endp->edset_flush = 0;
++ endp->active = 0;
++ endp->delayed = 0;
++ endp->endp_number = endp_number;
++ endp->u132 = u132;
++ endp->hep = hep;
++ endp->pipetype = usb_pipetype(urb->pipe);
++ u132_endp_init_kref(u132, endp);
++ if (usb_pipein(urb->pipe)) {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
++ endp->input = 1;
++ endp->output = 0;
++ udev->endp_number_in[usb_endp] = endp_number;
++ u132_udev_get_kref(u132, udev);
++ } else {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
++ endp->input = 0;
++ endp->output = 1;
++ udev->endp_number_out[usb_endp] = endp_number;
++ u132_udev_get_kref(u132, udev);
++ }
++ urb->hcpriv = u132;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ endp->delayed = 1;
++ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
++ endp->udev_number = address;
++ endp->usb_addr = usb_addr;
++ endp->usb_endp = usb_endp;
++ endp->queue_size = 1;
++ endp->queue_last = 0;
++ endp->queue_next = 0;
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
++ return 0;
++}
++
++static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
++ struct usb_host_endpoint *hep, struct urb *urb,
++ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
++ u8 usb_endp, u8 address)
++{
++ urb->hcpriv = u132;
++ endp->delayed = 1;
++ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
++ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
++ } else {
++ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
++ GFP_ATOMIC);
++ if (urbq == NULL) {
++ endp->queue_size -= 1;
++ return -ENOMEM;
++ } else {
++ list_add_tail(&urbq->urb_more, &endp->urb_more);
++ urbq->urb = urb;
++ }
++ }
++ return 0;
++}
++
++static int create_endpoint_and_queue_bulk(struct u132 *u132,
++ struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
++ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
++ gfp_t mem_flags)
++{
++ int ring_number;
++ struct u132_ring *ring;
++ unsigned long irqs;
++ u8 endp_number = ++u132->num_endpoints;
++ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
++ kmalloc(sizeof(struct u132_endp), mem_flags);
++ if (!endp) {
++ return -ENOMEM;
++ }
++ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
++ spin_lock_init(&endp->queue_lock.slock);
++ INIT_LIST_HEAD(&endp->urb_more);
++ endp->dequeueing = 0;
++ endp->edset_flush = 0;
++ endp->active = 0;
++ endp->delayed = 0;
++ endp->endp_number = endp_number;
++ endp->u132 = u132;
++ endp->hep = hep;
++ endp->pipetype = usb_pipetype(urb->pipe);
++ u132_endp_init_kref(u132, endp);
++ if (usb_pipein(urb->pipe)) {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
++ ring_number = 3;
++ endp->input = 1;
++ endp->output = 0;
++ udev->endp_number_in[usb_endp] = endp_number;
++ u132_udev_get_kref(u132, udev);
++ } else {
++ endp->toggle_bits = 0x2;
++ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
++ ring_number = 2;
++ endp->input = 0;
++ endp->output = 1;
++ udev->endp_number_out[usb_endp] = endp_number;
++ u132_udev_get_kref(u132, udev);
++ }
++ ring = endp->ring = &u132->ring[ring_number - 1];
++ if (ring->curr_endp) {
++ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
++ } else {
++ INIT_LIST_HEAD(&endp->endp_ring);
++ ring->curr_endp = endp;
++ }
++ ring->length += 1;
++ urb->hcpriv = u132;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ endp->udev_number = address;
++ endp->usb_addr = usb_addr;
++ endp->usb_endp = usb_endp;
++ endp->queue_size = 1;
++ endp->queue_last = 0;
++ endp->queue_next = 0;
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ u132_endp_queue_work(u132, endp, 0);
++ return 0;
++}
++
++static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
++ struct usb_host_endpoint *hep, struct urb *urb,
++ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
++ u8 usb_endp, u8 address)
++{
++ urb->hcpriv = u132;
++ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
++ } else {
++ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
++ GFP_ATOMIC);
++ if (urbq == NULL) {
++ endp->queue_size -= 1;
++ return -ENOMEM;
++ } else {
++ list_add_tail(&urbq->urb_more, &endp->urb_more);
++ urbq->urb = urb;
++ }
++ }
++ return 0;
++}
++
++static int create_endpoint_and_queue_control(struct u132 *u132,
++ struct usb_host_endpoint *hep, struct urb *urb,
++ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
++ gfp_t mem_flags)
++{
++ struct u132_ring *ring;
++ u8 endp_number = ++u132->num_endpoints;
++ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
++ kmalloc(sizeof(struct u132_endp), mem_flags);
++ if (!endp) {
++ return -ENOMEM;
++ }
++ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
++ spin_lock_init(&endp->queue_lock.slock);
++ INIT_LIST_HEAD(&endp->urb_more);
++ ring = endp->ring = &u132->ring[0];
++ if (ring->curr_endp) {
++ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
++ } else {
++ INIT_LIST_HEAD(&endp->endp_ring);
++ ring->curr_endp = endp;
++ }
++ ring->length += 1;
++ endp->dequeueing = 0;
++ endp->edset_flush = 0;
++ endp->active = 0;
++ endp->delayed = 0;
++ endp->endp_number = endp_number;
++ endp->u132 = u132;
++ endp->hep = hep;
++ u132_endp_init_kref(u132, endp);
++ u132_endp_get_kref(u132, endp);
++ if (usb_addr == 0) {
++ unsigned long irqs;
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ endp->udev_number = address;
++ endp->usb_addr = usb_addr;
++ endp->usb_endp = usb_endp;
++ endp->input = 1;
++ endp->output = 1;
++ endp->pipetype = usb_pipetype(urb->pipe);
++ u132_udev_init_kref(u132, udev);
++ u132_udev_get_kref(u132, udev);
++ udev->endp_number_in[usb_endp] = endp_number;
++ udev->endp_number_out[usb_endp] = endp_number;
++ urb->hcpriv = u132;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ endp->queue_size = 1;
++ endp->queue_last = 0;
++ endp->queue_next = 0;
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ u132_endp_queue_work(u132, endp, 0);
++ return 0;
++ } else { /*(usb_addr > 0) */
++ unsigned long irqs;
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ endp->udev_number = address;
++ endp->usb_addr = usb_addr;
++ endp->usb_endp = usb_endp;
++ endp->input = 1;
++ endp->output = 1;
++ endp->pipetype = usb_pipetype(urb->pipe);
++ u132_udev_get_kref(u132, udev);
++ udev->enumeration = 2;
++ udev->endp_number_in[usb_endp] = endp_number;
++ udev->endp_number_out[usb_endp] = endp_number;
++ urb->hcpriv = u132;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ endp->queue_size = 1;
++ endp->queue_last = 0;
++ endp->queue_next = 0;
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ u132_endp_queue_work(u132, endp, 0);
++ return 0;
++ }
++}
++
++static int queue_control_on_old_endpoint(struct u132 *u132,
++ struct usb_host_endpoint *hep, struct urb *urb,
++ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
++ u8 usb_endp)
++{
++ if (usb_addr == 0) {
++ if (usb_pipein(urb->pipe)) {
++ urb->hcpriv = u132;
++ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
++ endp->urb_list[ENDP_QUEUE_MASK &
++ endp->queue_last++] = urb;
++ } else {
++ struct u132_urbq *urbq =
++ kmalloc(sizeof(struct u132_urbq),
++ GFP_ATOMIC);
++ if (urbq == NULL) {
++ endp->queue_size -= 1;
++ return -ENOMEM;
++ } else {
++ list_add_tail(&urbq->urb_more,
++ &endp->urb_more);
++ urbq->urb = urb;
++ }
++ }
++ return 0;
++ } else { /* usb_pipeout(urb->pipe) */
++ struct u132_addr *addr = &u132->addr[usb_dev->devnum];
++ int I = MAX_U132_UDEVS;
++ int i = 0;
++ while (--I > 0) {
++ struct u132_udev *udev = &u132->udev[++i];
++ if (udev->usb_device) {
++ continue;
++ } else {
++ udev->enumeration = 1;
++ u132->addr[0].address = i;
++ endp->udev_number = i;
++ udev->udev_number = i;
++ udev->usb_addr = usb_dev->devnum;
++ u132_udev_init_kref(u132, udev);
++ udev->endp_number_in[usb_endp] =
++ endp->endp_number;
++ u132_udev_get_kref(u132, udev);
++ udev->endp_number_out[usb_endp] =
++ endp->endp_number;
++ udev->usb_device = usb_dev;
++ ((u8 *) (urb->setup_packet))[2] =
++ addr->address = i;
++ u132_udev_get_kref(u132, udev);
++ break;
++ }
++ }
++ if (I == 0) {
++ dev_err(&u132->platform_dev->dev, "run out of d"
++ "evice space\n");
++ return -EINVAL;
++ }
++ urb->hcpriv = u132;
++ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
++ endp->urb_list[ENDP_QUEUE_MASK &
++ endp->queue_last++] = urb;
++ } else {
++ struct u132_urbq *urbq =
++ kmalloc(sizeof(struct u132_urbq),
++ GFP_ATOMIC);
++ if (urbq == NULL) {
++ endp->queue_size -= 1;
++ return -ENOMEM;
++ } else {
++ list_add_tail(&urbq->urb_more,
++ &endp->urb_more);
++ urbq->urb = urb;
++ }
++ }
++ return 0;
++ }
++ } else { /*(usb_addr > 0) */
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ urb->hcpriv = u132;
++ if (udev->enumeration == 2) {
++ } else
++ udev->enumeration = 2;
++ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
++ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
++ urb;
++ } else {
++ struct u132_urbq *urbq =
++ kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
++ if (urbq == NULL) {
++ endp->queue_size -= 1;
++ return -ENOMEM;
++ } else {
++ list_add_tail(&urbq->urb_more, &endp->urb_more);
++ urbq->urb = urb;
++ }
++ }
++ return 0;
++ }
++}
++
++static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
++ struct urb *urb, gfp_t mem_flags)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (irqs_disabled()) {
++ if (__GFP_WAIT & mem_flags) {
++ printk(KERN_ERR "invalid context for function that migh"
++ "t sleep\n");
++ return -EINVAL;
++ }
++ }
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed urb="
++ "%p status=%d\n", urb, urb->status);
++ return -ESHUTDOWN;
++ } else {
++ u8 usb_addr = usb_pipedevice(urb->pipe);
++ u8 usb_endp = usb_pipeendpoint(urb->pipe);
++ struct usb_device *usb_dev = urb->dev;
++ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ struct u132_endp *endp = hep->hcpriv;
++ urb->actual_length = 0;
++ if (endp) {
++ unsigned long irqs;
++ int retval;
++ spin_lock_irqsave(&endp->queue_lock.slock,
++ irqs);
++ retval = queue_int_on_old_endpoint(u132, udev,
++ hep, urb, usb_dev, endp, usb_addr,
++ usb_endp, address);
++ spin_unlock_irqrestore(&endp->queue_lock.slock,
++ irqs);
++ if (retval) {
++ return retval;
++ } else {
++ u132_endp_queue_work(u132, endp,
++ msecs_to_jiffies(urb->interval))
++ ;
++ return 0;
++ }
++ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
++ return -EINVAL;
++ } else { /*(endp == NULL) */
++ return create_endpoint_and_queue_int(u132, udev,
++ hep, urb, usb_dev, usb_addr, usb_endp,
++ address, mem_flags);
++ }
++ } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ dev_err(&u132->platform_dev->dev, "the hardware does no"
++ "t support PIPE_ISOCHRONOUS\n");
++ return -EINVAL;
++ } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ struct u132_endp *endp = hep->hcpriv;
++ urb->actual_length = 0;
++ if (endp) {
++ unsigned long irqs;
++ int retval;
++ spin_lock_irqsave(&endp->queue_lock.slock,
++ irqs);
++ retval = queue_bulk_on_old_endpoint(u132, udev,
++ hep, urb, usb_dev, endp, usb_addr,
++ usb_endp, address);
++ spin_unlock_irqrestore(&endp->queue_lock.slock,
++ irqs);
++ if (retval) {
++ return retval;
++ } else {
++ u132_endp_queue_work(u132, endp, 0);
++ return 0;
++ }
++ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
++ return -EINVAL;
++ } else
++ return create_endpoint_and_queue_bulk(u132,
++ udev, hep, urb, usb_dev, usb_addr,
++ usb_endp, address, mem_flags);
++ } else {
++ struct u132_endp *endp = hep->hcpriv;
++ u16 urb_size = 8;
++ u8 *b = urb->setup_packet;
++ int i = 0;
++ char data[30 *3 + 4];
++ char *d = data;
++ int m = (sizeof(data) - 1) / 3;
++ int l = 0;
++ data[0] = 0;
++ while (urb_size-- > 0) {
++ if (i > m) {
++ } else if (i++ < m) {
++ int w = sprintf(d, " %02X", *b++);
++ d += w;
++ l += w;
++ } else
++ d += sprintf(d, " ..");
++ }
++ if (endp) {
++ unsigned long irqs;
++ int retval;
++ spin_lock_irqsave(&endp->queue_lock.slock,
++ irqs);
++ retval = queue_control_on_old_endpoint(u132,
++ hep, urb, usb_dev, endp, usb_addr,
++ usb_endp);
++ spin_unlock_irqrestore(&endp->queue_lock.slock,
++ irqs);
++ if (retval) {
++ return retval;
++ } else {
++ u132_endp_queue_work(u132, endp, 0);
++ return 0;
++ }
++ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
++ return -EINVAL;
++ } else
++ return create_endpoint_and_queue_control(u132,
++ hep, urb, usb_dev, usb_addr, usb_endp,
++ mem_flags);
++ }
++ }
++}
++
++static int dequeue_from_overflow_chain(struct u132 *u132,
++ struct u132_endp *endp, struct urb *urb)
++{
++ struct list_head *scan;
++ struct list_head *head = &endp->urb_more;
++ list_for_each(scan, head) {
++ struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
++ urb_more);
++ if (urbq->urb == urb) {
++ struct usb_hcd *hcd = u132_to_hcd(u132);
++ list_del(scan);
++ endp->queue_size -= 1;
++ urb->error_count = 0;
++ urb->hcpriv = NULL;
++ usb_hcd_giveback_urb(hcd, urb);
++ return 0;
++ } else
++ continue;
++ }
++ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
++ "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
++ "\n", urb, endp->endp_number, endp, endp->ring->number,
++ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
++ endp->usb_endp, endp->usb_addr, endp->queue_size,
++ endp->queue_next, endp->queue_last);
++ return -EINVAL;
++}
++
++static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
++ struct urb *urb)
++{
++ unsigned long irqs;
++ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
++ if (endp->queue_size == 0) {
++ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
++ "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
++ endp->endp_number, endp, endp->ring->number,
++ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
++ endp->usb_endp, endp->usb_addr);
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ return -EINVAL;
++ }
++ if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
++ if (endp->active) {
++ endp->dequeueing = 1;
++ endp->edset_flush = 1;
++ u132_endp_queue_work(u132, endp, 0);
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ urb->hcpriv = NULL;
++ return 0;
++ } else {
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ u132_hcd_abandon_urb(u132, endp, urb, urb->status);
++ return 0;
++ }
++ } else {
++ u16 queue_list = 0;
++ u16 queue_size = endp->queue_size;
++ u16 queue_scan = endp->queue_next;
++ struct urb **urb_slot = NULL;
++ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
++ if (urb == endp->urb_list[ENDP_QUEUE_MASK &
++ ++queue_scan]) {
++ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
++ queue_scan];
++ break;
++ } else
++ continue;
++ }
++ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
++ *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
++ ++queue_scan];
++ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
++ queue_scan];
++ }
++ if (urb_slot) {
++ struct usb_hcd *hcd = u132_to_hcd(u132);
++ endp->queue_size -= 1;
++ if (list_empty(&endp->urb_more)) {
++ spin_unlock_irqrestore(&endp->queue_lock.slock,
++ irqs);
++ } else {
++ struct list_head *next = endp->urb_more.next;
++ struct u132_urbq *urbq = list_entry(next,
++ struct u132_urbq, urb_more);
++ list_del(next);
++ *urb_slot = urbq->urb;
++ spin_unlock_irqrestore(&endp->queue_lock.slock,
++ irqs);
++ kfree(urbq);
++ } urb->error_count = 0;
++ urb->hcpriv = NULL;
++ usb_hcd_giveback_urb(hcd, urb);
++ return 0;
++ } else if (list_empty(&endp->urb_more)) {
++ dev_err(&u132->platform_dev->dev, "urb=%p not found in "
++ "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
++ "=%d size=%d next=%04X last=%04X\n", urb,
++ endp->endp_number, endp, endp->ring->number,
++ endp->input ? 'I' : ' ',
++ endp->output ? 'O' : ' ', endp->usb_endp,
++ endp->usb_addr, endp->queue_size,
++ endp->queue_next, endp->queue_last);
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ return -EINVAL;
++ } else {
++ int retval = dequeue_from_overflow_chain(u132, endp,
++ urb);
++ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
++ return retval;
++ }
++ }
++}
++
++static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 2) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else {
++ u8 usb_addr = usb_pipedevice(urb->pipe);
++ u8 usb_endp = usb_pipeendpoint(urb->pipe);
++ u8 address = u132->addr[usb_addr].address;
++ struct u132_udev *udev = &u132->udev[address];
++ if (usb_pipein(urb->pipe)) {
++ u8 endp_number = udev->endp_number_in[usb_endp];
++ struct u132_endp *endp = u132->endp[endp_number - 1];
++ return u132_endp_urb_dequeue(u132, endp, urb);
++ } else {
++ u8 endp_number = udev->endp_number_out[usb_endp];
++ struct u132_endp *endp = u132->endp[endp_number - 1];
++ return u132_endp_urb_dequeue(u132, endp, urb);
++ }
++ }
++}
++
++static void u132_endpoint_disable(struct usb_hcd *hcd,
++ struct usb_host_endpoint *hep)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 2) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ } else {
++ struct u132_endp *endp = hep->hcpriv;
++ if (endp)
++ u132_endp_put_kref(u132, endp);
++ }
++}
++
++static int u132_get_frame(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else {
++ int frame = 0;
++ dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
++ msleep(100);
++ return frame;
++ }
++}
++
++static int u132_roothub_descriptor(struct u132 *u132,
++ struct usb_hub_descriptor *desc)
++{
++ int retval;
++ u16 temp;
++ u32 rh_a = -1;
++ u32 rh_b = -1;
++ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
++ if (retval)
++ return retval;
++ desc->bDescriptorType = 0x29;
++ desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
++ desc->bHubContrCurrent = 0;
++ desc->bNbrPorts = u132->num_ports;
++ temp = 1 + (u132->num_ports / 8);
++ desc->bDescLength = 7 + 2 *temp;
++ temp = 0;
++ if (rh_a & RH_A_NPS)
++ temp |= 0x0002;
++ if (rh_a & RH_A_PSM)
++ temp |= 0x0001;
++ if (rh_a & RH_A_NOCP) {
++ temp |= 0x0010;
++ } else if (rh_a & RH_A_OCPM)
++ temp |= 0x0008;
++ desc->wHubCharacteristics = cpu_to_le16(temp);
++ retval = u132_read_pcimem(u132, roothub.b, &rh_b);
++ if (retval)
++ return retval;
++ memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
++ desc->bitmap[0] = rh_b & RH_B_DR;
++ if (u132->num_ports > 7) {
++ desc->bitmap[1] = (rh_b & RH_B_DR) >> 8;
++ desc->bitmap[2] = 0xff;
++ } else
++ desc->bitmap[1] = 0xff;
++ return 0;
++}
++
++static int u132_roothub_status(struct u132 *u132, __le32 *desc)
++{
++ u32 rh_status = -1;
++ int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
++ *desc = cpu_to_le32(rh_status);
++ return ret_status;
++}
++
++static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
++{
++ if (wIndex == 0 || wIndex > u132->num_ports) {
++ return -EINVAL;
++ } else {
++ int port = wIndex - 1;
++ u32 rh_portstatus = -1;
++ int ret_portstatus = u132_read_pcimem(u132,
++ roothub.portstatus[port], &rh_portstatus);
++ *desc = cpu_to_le32(rh_portstatus);
++ if (*(u16 *) (desc + 2)) {
++ dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
++ "ge = %08X\n", port, *desc);
++ }
++ return ret_portstatus;
++ }
++}
++
++
++/* this timer value might be vendor-specific ... */
++#define PORT_RESET_HW_MSEC 10
++#define PORT_RESET_MSEC 10
++/* wrap-aware logic morphed from <linux/jiffies.h> */
++#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
++static int u132_roothub_portreset(struct u132 *u132, int port_index)
++{
++ int retval;
++ u32 fmnumber;
++ u16 now;
++ u16 reset_done;
++ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
++ if (retval)
++ return retval;
++ now = fmnumber;
++ reset_done = now + PORT_RESET_MSEC;
++ do {
++ u32 portstat;
++ do {
++ retval = u132_read_pcimem(u132,
++ roothub.portstatus[port_index], &portstat);
++ if (retval)
++ return retval;
++ if (RH_PS_PRS & portstat) {
++ continue;
++ } else
++ break;
++ } while (tick_before(now, reset_done));
++ if (RH_PS_PRS & portstat)
++ return -ENODEV;
++ if (RH_PS_CCS & portstat) {
++ if (RH_PS_PRSC & portstat) {
++ retval = u132_write_pcimem(u132,
++ roothub.portstatus[port_index],
++ RH_PS_PRSC);
++ if (retval)
++ return retval;
++ }
++ } else
++ break; /* start the next reset,
++ sleep till it's probably done */
++ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
++ RH_PS_PRS);
++ if (retval)
++ return retval;
++ msleep(PORT_RESET_HW_MSEC);
++ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
++ if (retval)
++ return retval;
++ now = fmnumber;
++ } while (tick_before(now, reset_done));
++ return 0;
++}
++
++static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
++ u16 wIndex)
++{
++ if (wIndex == 0 || wIndex > u132->num_ports) {
++ return -EINVAL;
++ } else {
++ int retval;
++ int port_index = wIndex - 1;
++ struct u132_port *port = &u132->port[port_index];
++ port->Status &= ~(1 << wValue);
++ switch (wValue) {
++ case USB_PORT_FEAT_SUSPEND:
++ retval = u132_write_pcimem(u132,
++ roothub.portstatus[port_index], RH_PS_PSS);
++ if (retval)
++ return retval;
++ return 0;
++ case USB_PORT_FEAT_POWER:
++ retval = u132_write_pcimem(u132,
++ roothub.portstatus[port_index], RH_PS_PPS);
++ if (retval)
++ return retval;
++ return 0;
++ case USB_PORT_FEAT_RESET:
++ retval = u132_roothub_portreset(u132, port_index);
++ if (retval)
++ return retval;
++ return 0;
++ default:
++ return -EPIPE;
++ }
++ }
++}
++
++static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
++ u16 wIndex)
++{
++ if (wIndex == 0 || wIndex > u132->num_ports) {
++ return -EINVAL;
++ } else {
++ int port_index = wIndex - 1;
++ u32 temp;
++ int retval;
++ struct u132_port *port = &u132->port[port_index];
++ port->Status &= ~(1 << wValue);
++ switch (wValue) {
++ case USB_PORT_FEAT_ENABLE:
++ temp = RH_PS_CCS;
++ break;
++ case USB_PORT_FEAT_C_ENABLE:
++ temp = RH_PS_PESC;
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ temp = RH_PS_POCI;
++ if ((u132->hc_control & OHCI_CTRL_HCFS)
++ != OHCI_USB_OPER) {
++ dev_err(&u132->platform_dev->dev, "TODO resume_"
++ "root_hub\n");
++ }
++ break;
++ case USB_PORT_FEAT_C_SUSPEND:
++ temp = RH_PS_PSSC;
++ break;
++ case USB_PORT_FEAT_POWER:
++ temp = RH_PS_LSDA;
++ break;
++ case USB_PORT_FEAT_C_CONNECTION:
++ temp = RH_PS_CSC;
++ break;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ temp = RH_PS_OCIC;
++ break;
++ case USB_PORT_FEAT_C_RESET:
++ temp = RH_PS_PRSC;
++ break;
++ default:
++ return -EPIPE;
++ }
++ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
++ temp);
++ if (retval)
++ return retval;
++ return 0;
++ }
++}
++
++
++/* the virtual root hub timer IRQ checks for hub status*/
++static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
++ "ed %d\n", hcd, u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
++ "ed\n", hcd);
++ dump_stack();
++ return -ESHUTDOWN;
++ } else {
++ int i, changed = 0, length = 1;
++ if (u132->flags & OHCI_QUIRK_AMD756) {
++ if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
++ dev_err(&u132->platform_dev->dev, "bogus NDP, r"
++ "ereads as NDP=%d\n",
++ u132->hc_roothub_a & RH_A_NDP);
++ goto done;
++ }
++ }
++ if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) {
++ buf[0] = changed = 1;
++ } else
++ buf[0] = 0;
++ if (u132->num_ports > 7) {
++ buf[1] = 0;
++ length++;
++ }
++ for (i = 0; i < u132->num_ports; i++) {
++ if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
++ RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
++ RH_PS_PRSC)) {
++ changed = 1;
++ if (i < 7) {
++ buf[0] |= 1 << (i + 1);
++ } else
++ buf[1] |= 1 << (i - 7);
++ continue;
++ }
++ if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) {
++ continue;
++ }
++ if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) {
++ continue;
++ }
++ }
++ done:return changed ? length : 0;
++ }
++}
++
++static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
++ u16 wIndex, char *buf, u16 wLength)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else {
++ int retval = 0;
++ down(&u132->sw_lock);
++ switch (typeReq) {
++ case ClearHubFeature:
++ switch (wValue) {
++ case C_HUB_OVER_CURRENT:
++ case C_HUB_LOCAL_POWER:
++ break;
++ default:
++ goto stall;
++ }
++ break;
++ case SetHubFeature:
++ switch (wValue) {
++ case C_HUB_OVER_CURRENT:
++ case C_HUB_LOCAL_POWER:
++ break;
++ default:
++ goto stall;
++ }
++ break;
++ case ClearPortFeature:{
++ retval = u132_roothub_clearportfeature(u132,
++ wValue, wIndex);
++ if (retval)
++ goto error;
++ break;
++ }
++ case GetHubDescriptor:{
++ retval = u132_roothub_descriptor(u132,
++ (struct usb_hub_descriptor *)buf);
++ if (retval)
++ goto error;
++ break;
++ }
++ case GetHubStatus:{
++ retval = u132_roothub_status(u132,
++ (__le32 *) buf);
++ if (retval)
++ goto error;
++ break;
++ }
++ case GetPortStatus:{
++ retval = u132_roothub_portstatus(u132,
++ (__le32 *) buf, wIndex);
++ if (retval)
++ goto error;
++ break;
++ }
++ case SetPortFeature:{
++ retval = u132_roothub_setportfeature(u132,
++ wValue, wIndex);
++ if (retval)
++ goto error;
++ break;
++ }
++ default:
++ goto stall;
++ error:u132_disable(u132);
++ u132->going = 1;
++ break;
++ stall:retval = -EPIPE;
++ break;
++ }
++ up(&u132->sw_lock);
++ return retval;
++ }
++}
++
++static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else
++ return 0;
++}
++
++static void u132_hub_irq_enable(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ } else if (u132->going > 0)
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++}
++
++
++#ifdef CONFIG_PM
++static int u132_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else
++ return 0;
++}
++
++static int u132_hcd_resume(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else
++ return 0;
++}
++
++static int u132_bus_suspend(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else
++ return 0;
++}
++
++static int u132_bus_resume(struct usb_hcd *hcd)
++{
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else
++ return 0;
++}
++
++#else
++#define u132_hcd_suspend NULL
++#define u132_hcd_resume NULL
++#define u132_bus_suspend NULL
++#define u132_bus_resume NULL
++#endif
++static struct hc_driver u132_hc_driver = {
++ .description = hcd_name,
++ .hcd_priv_size = sizeof(struct u132),
++ .irq = NULL,
++ .flags = HCD_USB11 | HCD_MEMORY,
++ .reset = u132_hcd_reset,
++ .start = u132_hcd_start,
++ .suspend = u132_hcd_suspend,
++ .resume = u132_hcd_resume,
++ .stop = u132_hcd_stop,
++ .urb_enqueue = u132_urb_enqueue,
++ .urb_dequeue = u132_urb_dequeue,
++ .endpoint_disable = u132_endpoint_disable,
++ .get_frame_number = u132_get_frame,
++ .hub_status_data = u132_hub_status_data,
++ .hub_control = u132_hub_control,
++ .bus_suspend = u132_bus_suspend,
++ .bus_resume = u132_bus_resume,
++ .start_port_reset = u132_start_port_reset,
++ .hub_irq_enable = u132_hub_irq_enable,
++};
++
++/*
++* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
++* is held for writing, thus this module must not call usb_remove_hcd()
++* synchronously - but instead should immediately stop activity to the
++* device and ansynchronously call usb_remove_hcd()
++*/
++static int __devexit u132_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ if (hcd) {
++ struct u132 *u132 = hcd_to_u132(hcd);
++ dump_stack();
++ if (u132->going++ > 1) {
++ return -ENODEV;
++ } else {
++ int rings = MAX_U132_RINGS;
++ int endps = MAX_U132_ENDPS;
++ msleep(100);
++ down(&u132->sw_lock);
++ u132_monitor_cancel_work(u132);
++ while (rings-- > 0) {
++ struct u132_ring *ring = &u132->ring[rings];
++ u132_ring_cancel_work(u132, ring);
++ } while (endps-- > 0) {
++ struct u132_endp *endp = u132->endp[endps];
++ if (endp)
++ u132_endp_cancel_work(u132, endp);
++ }
++ u132->going += 1;
++ printk(KERN_INFO "removing device u132.%d\n",
++ u132->sequence_num);
++ up(&u132->sw_lock);
++ usb_remove_hcd(hcd);
++ u132_u132_put_kref(u132);
++ return 0;
++ }
++ } else
++ return 0;
++}
++
++static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
++{
++ int rings = MAX_U132_RINGS;
++ int ports = MAX_U132_PORTS;
++ int addrs = MAX_U132_ADDRS;
++ int udevs = MAX_U132_UDEVS;
++ int endps = MAX_U132_ENDPS;
++ u132->board = pdev->dev.platform_data;
++ u132->platform_dev = pdev;
++ u132->power = 0;
++ u132->reset = 0;
++ init_MUTEX(&u132->sw_lock);
++ init_MUTEX(&u132->scheduler_lock);
++ while (rings-- > 0) {
++ struct u132_ring *ring = &u132->ring[rings];
++ ring->u132 = u132;
++ ring->number = rings + 1;
++ ring->length = 0;
++ ring->curr_endp = NULL;
++ INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler,
++ (void *)ring);
++ } down(&u132->sw_lock);
++ INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132);
++ while (ports-- > 0) {
++ struct u132_port *port = &u132->port[ports];
++ port->u132 = u132;
++ port->reset = 0;
++ port->enable = 0;
++ port->power = 0;
++ port->Status = 0;
++ } while (addrs-- > 0) {
++ struct u132_addr *addr = &u132->addr[addrs];
++ addr->address = 0;
++ } while (udevs-- > 0) {
++ struct u132_udev *udev = &u132->udev[udevs];
++ int i = ARRAY_SIZE(udev->endp_number_in);
++ int o = ARRAY_SIZE(udev->endp_number_out);
++ udev->usb_device = NULL;
++ udev->udev_number = 0;
++ udev->usb_addr = 0;
++ udev->portnumber = 0;
++ while (i-- > 0) {
++ udev->endp_number_in[i] = 0;
++ }
++ while (o-- > 0) {
++ udev->endp_number_out[o] = 0;
++ }
++ }
++ while (endps-- > 0) {
++ u132->endp[endps] = NULL;
++ }
++ up(&u132->sw_lock);
++ return;
++}
++
++static int __devinit u132_probe(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd;
++ msleep(100);
++ if (u132_exiting > 0) {
++ return -ENODEV;
++ } /* refuse to confuse usbcore */
++ if (pdev->dev.dma_mask) {
++ return -EINVAL;
++ }
++ hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id);
++ if (!hcd) {
++ printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
++ );
++ ftdi_elan_gone_away(pdev);
++ return -ENOMEM;
++ } else {
++ int retval = 0;
++ struct u132 *u132 = hcd_to_u132(hcd);
++ hcd->rsrc_start = 0;
++ down(&u132_module_lock);
++ list_add_tail(&u132->u132_list, &u132_static_list);
++ u132->sequence_num = ++u132_instances;
++ up(&u132_module_lock);
++ u132_u132_init_kref(u132);
++ u132_initialise(u132, pdev);
++ hcd->product_desc = "ELAN U132 Host Controller";
++ retval = usb_add_hcd(hcd, 0, 0);
++ if (retval != 0) {
++ dev_err(&u132->platform_dev->dev, "init error %d\n",
++ retval);
++ u132_u132_put_kref(u132);
++ return retval;
++ } else {
++ u132_monitor_queue_work(u132, 100);
++ return 0;
++ }
++ }
++}
++
++
++#ifdef CONFIG_PM
++/* for this device there's no useful distinction between the controller
++* and its root hub, except that the root hub only gets direct PM calls
++* when CONFIG_USB_SUSPEND is enabled.
++*/
++static int u132_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else {
++ int retval = 0;
++ if (state.event == PM_EVENT_FREEZE) {
++ retval = u132_bus_suspend(hcd);
++ } else if (state.event == PM_EVENT_SUSPEND) {
++ int ports = MAX_U132_PORTS;
++ while (ports-- > 0) {
++ port_power(u132, ports, 0);
++ }
++ }
++ if (retval == 0)
++ pdev->dev.power.power_state = state;
++ return retval;
++ }
++}
++
++static int u132_resume(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct u132 *u132 = hcd_to_u132(hcd);
++ if (u132->going > 1) {
++ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
++ , u132->going);
++ return -ENODEV;
++ } else if (u132->going > 0) {
++ dev_err(&u132->platform_dev->dev, "device is being removed\n");
++ return -ESHUTDOWN;
++ } else {
++ int retval = 0;
++ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
++ int ports = MAX_U132_PORTS;
++ while (ports-- > 0) {
++ port_power(u132, ports, 1);
++ }
++ retval = 0;
++ } else {
++ pdev->dev.power.power_state = PMSG_ON;
++ retval = u132_bus_resume(hcd);
++ }
++ return retval;
++ }
++}
++
++#else
++#define u132_suspend NULL
++#define u132_resume NULL
++#endif
++/*
++* this driver is loaded explicitely by ftdi_u132
++*
++* the platform_driver struct is static because it is per type of module
++*/
++static struct platform_driver u132_platform_driver = {
++ .probe = u132_probe,
++ .remove = __devexit_p(u132_remove),
++ .suspend = u132_suspend,
++ .resume = u132_resume,
++ .driver = {
++ .name = (char *)hcd_name,
++ .owner = THIS_MODULE,
++ },
++};
++static int __init u132_hcd_init(void)
++{
++ int retval;
++ INIT_LIST_HEAD(&u132_static_list);
++ u132_instances = 0;
++ u132_exiting = 0;
++ init_MUTEX(&u132_module_lock);
++ if (usb_disabled())
++ return -ENODEV;
++ printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
++ __DATE__);
++ workqueue = create_singlethread_workqueue("u132");
++ retval = platform_driver_register(&u132_platform_driver);
++ return retval;
++}
++
++
++module_init(u132_hcd_init);
++static void __exit u132_hcd_exit(void)
++{
++ struct u132 *u132;
++ struct u132 *temp;
++ down(&u132_module_lock);
++ u132_exiting += 1;
++ up(&u132_module_lock);
++ list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
++ platform_device_unregister(u132->platform_dev);
++ } platform_driver_unregister(&u132_platform_driver);
++ printk(KERN_INFO "u132-hcd driver deregistered\n");
++ wait_event(u132_hcd_wait, u132_instances == 0);
++ flush_workqueue(workqueue);
++ destroy_workqueue(workqueue);
++}
++
++
++module_exit(u132_hcd_exit);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
+index dc286a4..e345f15 100644
+--- a/drivers/usb/host/uhci-debug.c
++++ b/drivers/usb/host/uhci-debug.c
+@@ -16,7 +16,7 @@
+
+ #include "uhci-hcd.h"
+
+-#define uhci_debug_operations (* (struct file_operations *) NULL)
++#define uhci_debug_operations (* (const struct file_operations *) NULL)
+ static struct dentry *uhci_debugfs_root;
+
+ #ifdef DEBUG
+@@ -428,7 +428,7 @@ struct uhci_debug {
+
+ static int uhci_debug_open(struct inode *inode, struct file *file)
+ {
+- struct uhci_hcd *uhci = inode->u.generic_ip;
++ struct uhci_hcd *uhci = inode->i_private;
+ struct uhci_debug *up;
+ int ret = -ENOMEM;
+ unsigned long flags;
+@@ -500,7 +500,7 @@ static int uhci_debug_release(struct ino
+ }
+
+ #undef uhci_debug_operations
+-static struct file_operations uhci_debug_operations = {
++static const struct file_operations uhci_debug_operations = {
+ .owner = THIS_MODULE,
+ .open = uhci_debug_open,
+ .llseek = uhci_debug_lseek,
+diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
+index 4151f61..226bf3d 100644
+--- a/drivers/usb/host/uhci-hcd.c
++++ b/drivers/usb/host/uhci-hcd.c
+@@ -40,6 +40,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/usb.h>
+ #include <linux/bitops.h>
++#include <linux/dmi.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_
+ return 0;
+ }
+
++static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
++{
++ static struct dmi_system_id broken_wakeup_table[] = {
++ {
++ .ident = "Asus A7V8X",
++ .matches = {
++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"),
++ DMI_MATCH(DMI_BOARD_NAME, "A7V8X"),
++ DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"),
++ }
++ },
++ { }
++ };
++ int port;
++
++ /* One of Asus's motherboards has a bug which causes it to
++ * wake up immediately from suspend-to-RAM if any of the ports
++ * are connected. In such cases we will not set EGSM.
++ */
++ if (dmi_check_system(broken_wakeup_table)) {
++ for (port = 0; port < uhci->rh_numports; ++port) {
++ if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
++ USBPORTSC_CCS)
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
+ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
+ __releases(uhci->lock)
+ __acquires(uhci->lock)
+ {
+ int auto_stop;
+- int int_enable;
++ int int_enable, egsm_enable;
+
+ auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
+ dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
+@@ -217,15 +248,18 @@ __acquires(uhci->lock)
+ }
+
+ /* Enable resume-detect interrupts if they work.
+- * Then enter Global Suspend mode, still configured.
++ * Then enter Global Suspend mode if _it_ works, still configured.
+ */
++ egsm_enable = USBCMD_EGSM;
+ uhci->working_RD = 1;
+ int_enable = USBINTR_RESUME;
+- if (resume_detect_interrupts_are_broken(uhci)) {
++ if (remote_wakeup_is_broken(uhci))
++ egsm_enable = 0;
++ if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable)
+ uhci->working_RD = int_enable = 0;
+- }
++
+ outw(int_enable, uhci->io_addr + USBINTR);
+- outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
++ outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
+ mb();
+ udelay(5);
+
+@@ -252,7 +286,7 @@ __acquires(uhci->lock)
+ uhci->is_stopped = UHCI_IS_STOPPED;
+ uhci_to_hcd(uhci)->poll_rh = !int_enable;
+
+- uhci_scan_schedule(uhci, NULL);
++ uhci_scan_schedule(uhci);
+ uhci_fsbr_off(uhci);
+ }
+
+@@ -309,7 +343,7 @@ __acquires(uhci->lock)
+ mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
+ }
+
+-static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
++static irqreturn_t uhci_irq(struct usb_hcd *hcd)
+ {
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned short status;
+@@ -358,7 +392,7 @@ static irqreturn_t uhci_irq(struct usb_h
+ usb_hcd_poll_rh_status(hcd);
+ else {
+ spin_lock_irqsave(&uhci->lock, flags);
+- uhci_scan_schedule(uhci, regs);
++ uhci_scan_schedule(uhci);
+ spin_unlock_irqrestore(&uhci->lock, flags);
+ }
+
+@@ -671,7 +705,7 @@ static void uhci_stop(struct usb_hcd *hc
+ spin_lock_irq(&uhci->lock);
+ if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead)
+ uhci_hc_died(uhci);
+- uhci_scan_schedule(uhci, NULL);
++ uhci_scan_schedule(uhci);
+ spin_unlock_irq(&uhci->lock);
+
+ del_timer_sync(&uhci->fsbr_timer);
+@@ -734,6 +768,10 @@ static int uhci_suspend(struct usb_hcd *
+
+ /* FIXME: Enable non-PME# remote wakeup? */
+
++ /* make sure snapshot being resumed re-enumerates everything */
++ if (message.event == PM_EVENT_PRETHAW)
++ uhci_hc_died(uhci);
++
+ done_okay:
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ done:
+@@ -909,8 +947,7 @@ static int __init uhci_hcd_init(void)
+ return 0;
+
+ init_failed:
+- if (kmem_cache_destroy(uhci_up_cachep))
+- warn("not all urb_privs were freed!");
++ kmem_cache_destroy(uhci_up_cachep);
+
+ up_failed:
+ debugfs_remove(uhci_debugfs_root);
+@@ -926,10 +963,7 @@ errbuf_failed:
+ static void __exit uhci_hcd_cleanup(void)
+ {
+ pci_unregister_driver(&uhci_pci_driver);
+-
+- if (kmem_cache_destroy(uhci_up_cachep))
+- warn("not all urb_privs were freed!");
+-
++ kmem_cache_destroy(uhci_up_cachep);
+ debugfs_remove(uhci_debugfs_root);
+ kfree(errbuf);
+ }
+diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
+index c545ef9..f8347f1 100644
+--- a/drivers/usb/host/uhci-hub.c
++++ b/drivers/usb/host/uhci-hub.c
+@@ -84,6 +84,7 @@ static void uhci_finish_suspend(struct u
+ unsigned long port_addr)
+ {
+ int status;
++ int i;
+
+ if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) {
+ CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
+@@ -92,9 +93,14 @@ static void uhci_finish_suspend(struct u
+
+ /* The controller won't actually turn off the RD bit until
+ * it has had a chance to send a low-speed EOP sequence,
+- * which takes 3 bit times (= 2 microseconds). We'll delay
+- * slightly longer for good luck. */
+- udelay(4);
++ * which is supposed to take 3 bit times (= 2 microseconds).
++ * Experiments show that some controllers take longer, so
++ * we'll poll for completion. */
++ for (i = 0; i < 10; ++i) {
++ if (!(inw(port_addr) & USBPORTSC_RD))
++ break;
++ udelay(1);
++ }
+ }
+ clear_bit(port, &uhci->resuming_ports);
+ }
+@@ -170,7 +176,7 @@ static int uhci_hub_status_data(struct u
+
+ spin_lock_irqsave(&uhci->lock, flags);
+
+- uhci_scan_schedule(uhci, NULL);
++ uhci_scan_schedule(uhci);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
+ goto done;
+ uhci_check_ports(uhci);
+diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
+index 431e8f3..06115f2 100644
+--- a/drivers/usb/host/uhci-q.c
++++ b/drivers/usb/host/uhci-q.c
+@@ -1244,7 +1244,7 @@ done:
+ * Finish unlinking an URB and give it back
+ */
+ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
+- struct urb *urb, struct pt_regs *regs)
++ struct urb *urb)
+ __releases(uhci->lock)
+ __acquires(uhci->lock)
+ {
+@@ -1293,7 +1293,7 @@ __acquires(uhci->lock)
+ }
+
+ spin_unlock(&uhci->lock);
+- usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs);
++ usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+ spin_lock(&uhci->lock);
+
+ /* If the queue is now empty, we can unlink the QH and give up its
+@@ -1313,8 +1313,7 @@ __acquires(uhci->lock)
+ (qh->state == QH_STATE_UNLINKING && \
+ uhci->frame_number + uhci->is_stopped != qh->unlink_frame)
+
+-static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
+- struct pt_regs *regs)
++static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+ {
+ struct urb_priv *urbp;
+ struct urb *urb;
+@@ -1347,7 +1346,7 @@ static void uhci_scan_qh(struct uhci_hcd
+ return;
+ }
+
+- uhci_giveback_urb(uhci, qh, urb, regs);
++ uhci_giveback_urb(uhci, qh, urb);
+ if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+ break;
+ }
+@@ -1372,7 +1371,7 @@ restart:
+ qh->is_stopped = 0;
+ return;
+ }
+- uhci_giveback_urb(uhci, qh, urb, regs);
++ uhci_giveback_urb(uhci, qh, urb);
+ goto restart;
+ }
+ }
+@@ -1487,7 +1486,7 @@ done:
+ /*
+ * Process events in the schedule, but only in one thread at a time
+ */
+-static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
++static void uhci_scan_schedule(struct uhci_hcd *uhci)
+ {
+ int i;
+ struct uhci_qh *qh;
+@@ -1515,7 +1514,7 @@ rescan:
+ struct uhci_qh, node);
+
+ if (uhci_advance_check(uhci, qh)) {
+- uhci_scan_qh(uhci, qh, regs);
++ uhci_scan_qh(uhci, qh);
+ if (qh->state == QH_STATE_ACTIVE) {
+ uhci_urbp_wants_fsbr(uhci,
+ list_entry(qh->queue.next, struct urb_priv, node));
+diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
+index 08daf40..63a84bb 100644
+--- a/drivers/usb/image/mdc800.c
++++ b/drivers/usb/image/mdc800.c
+@@ -280,7 +280,7 @@ static int mdc800_isReady (char *ch)
+ /*
+ * USB IRQ Handler for InputLine
+ */
+-static void mdc800_usb_irq (struct urb *urb, struct pt_regs *res)
++static void mdc800_usb_irq (struct urb *urb)
+ {
+ int data_received=0, wake_up;
+ unsigned char* b=urb->transfer_buffer;
+@@ -374,7 +374,7 @@ static int mdc800_usb_waitForIRQ (int mo
+ /*
+ * The write_urb callback function
+ */
+-static void mdc800_usb_write_notify (struct urb *urb, struct pt_regs *res)
++static void mdc800_usb_write_notify (struct urb *urb)
+ {
+ struct mdc800_data* mdc800=urb->context;
+
+@@ -394,7 +394,7 @@ static void mdc800_usb_write_notify (str
+ /*
+ * The download_urb callback function
+ */
+-static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
++static void mdc800_usb_download_notify (struct urb *urb)
+ {
+ struct mdc800_data* mdc800=urb->context;
+
+@@ -424,7 +424,7 @@ static void mdc800_usb_download_notify (
+ ***************************************************************************/
+
+ static struct usb_driver mdc800_usb_driver;
+-static struct file_operations mdc800_device_ops;
++static const struct file_operations mdc800_device_ops;
+ static struct usb_class_driver mdc800_class = {
+ .name = "mdc800%d",
+ .fops = &mdc800_device_ops,
+@@ -941,7 +941,7 @@ static ssize_t mdc800_device_write (stru
+ ****************************************************************************/
+
+ /* File Operations of this drivers */
+-static struct file_operations mdc800_device_ops =
++static const struct file_operations mdc800_device_ops =
+ {
+ .owner = THIS_MODULE,
+ .read = mdc800_device_read,
+diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
+index b2bafc3..3038ed0 100644
+--- a/drivers/usb/image/microtek.c
++++ b/drivers/usb/image/microtek.c
+@@ -225,7 +225,7 @@ static inline void mts_debug_dump(struct
+ }
+
+
+-static inline void mts_show_command(Scsi_Cmnd *srb)
++static inline void mts_show_command(struct scsi_cmnd *srb)
+ {
+ char *what = NULL;
+
+@@ -309,7 +309,7 @@ static inline void mts_show_command(Scsi
+
+ #else
+
+-static inline void mts_show_command(Scsi_Cmnd * dummy)
++static inline void mts_show_command(struct scsi_cmnd * dummy)
+ {
+ }
+
+@@ -338,7 +338,7 @@ static int mts_slave_configure (struct s
+ return 0;
+ }
+
+-static int mts_scsi_abort (Scsi_Cmnd *srb)
++static int mts_scsi_abort(struct scsi_cmnd *srb)
+ {
+ struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
+
+@@ -349,7 +349,7 @@ static int mts_scsi_abort (Scsi_Cmnd *sr
+ return FAILED;
+ }
+
+-static int mts_scsi_host_reset (Scsi_Cmnd *srb)
++static int mts_scsi_host_reset(struct scsi_cmnd *srb)
+ {
+ struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
+ int result, rc;
+@@ -366,11 +366,11 @@ static int mts_scsi_host_reset (Scsi_Cmn
+ return result ? FAILED : SUCCESS;
+ }
+
+-static
+-int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
++static int
++mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
+
+ static void mts_transfer_cleanup( struct urb *transfer );
+-static void mts_do_sg(struct urb * transfer, struct pt_regs *regs);
++static void mts_do_sg(struct urb * transfer);
+
+ static inline
+ void mts_int_submit_urb (struct urb* transfer,
+@@ -417,7 +417,7 @@ static void mts_transfer_cleanup( struct
+
+ }
+
+-static void mts_transfer_done( struct urb *transfer, struct pt_regs *regs )
++static void mts_transfer_done( struct urb *transfer )
+ {
+ MTS_INT_INIT();
+
+@@ -443,7 +443,7 @@ static void mts_get_status( struct urb *
+ mts_transfer_done );
+ }
+
+-static void mts_data_done( struct urb* transfer, struct pt_regs *regs )
++static void mts_data_done( struct urb* transfer )
+ /* Interrupt context! */
+ {
+ MTS_INT_INIT();
+@@ -460,7 +460,7 @@ static void mts_data_done( struct urb* t
+ }
+
+
+-static void mts_command_done( struct urb *transfer, struct pt_regs *regs )
++static void mts_command_done( struct urb *transfer )
+ /* Interrupt context! */
+ {
+ MTS_INT_INIT();
+@@ -501,7 +501,7 @@ static void mts_command_done( struct urb
+ return;
+ }
+
+-static void mts_do_sg (struct urb* transfer, struct pt_regs *regs)
++static void mts_do_sg (struct urb* transfer)
+ {
+ struct scatterlist * sg;
+ MTS_INT_INIT();
+@@ -537,7 +537,7 @@ static const unsigned char mts_direction
+ #define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
+
+ static void
+-mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
++mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
+ {
+ int pipe;
+ struct scatterlist * sg;
+@@ -588,8 +588,8 @@ mts_build_transfer_context( Scsi_Cmnd *s
+ }
+
+
+-static
+-int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
++static int
++mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
+ {
+ struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
+ int err = 0;
+diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
+index 926d4bd..d5d62a9 100644
+--- a/drivers/usb/image/microtek.h
++++ b/drivers/usb/image/microtek.h
+@@ -8,14 +8,14 @@
+ *
+ */
+
+-typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *);
++typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *);
+
+
+ struct mts_transfer_context
+ {
+ struct mts_desc* instance;
+ mts_scsi_cmnd_callback final_callback;
+- Scsi_Cmnd *srb;
++ struct scsi_cmnd *srb;
+
+ void* data;
+ unsigned data_length;
+diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
+index 650103b..20db364 100644
+--- a/drivers/usb/input/Kconfig
++++ b/drivers/usb/input/Kconfig
+@@ -60,16 +60,17 @@ config HID_FF
+ If unsure, say N.
+
+ config HID_PID
+- bool "PID Devices (Microsoft Sidewinder Force Feedback 2)"
++ bool "PID device support"
+ depends on HID_FF
+ help
+- Say Y here if you have a PID-compliant joystick and wish to enable force
+- feedback for it. The Microsoft Sidewinder Force Feedback 2 is one such
+- device.
++ Say Y here if you have a PID-compliant device and wish to enable force
++ feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
++ devices.
+
+ config LOGITECH_FF
+ bool "Logitech WingMan *3D support"
+ depends on HID_FF
++ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have one of these devices:
+ - Logitech WingMan Cordless RumblePad
+@@ -81,12 +82,21 @@ config LOGITECH_FF
+ config THRUSTMASTER_FF
+ bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+ depends on HID_FF && EXPERIMENTAL
++ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+ and want to enable force feedback support for it.
+ Note: if you say N here, this device will still be supported, but without
+ force feedback.
+
++config ZEROPLUS_FF
++ bool "Zeroplus based game controller support"
++ depends on HID_FF
++ select INPUT_FF_MEMLESS if USB_HID
++ help
++ Say Y here if you have a Zeroplus based game controller and want to
++ enable force feedback for it.
++
+ config USB_HIDDEV
+ bool "/dev/hiddev raw HID device support"
+ depends on USB_HID
+@@ -205,10 +215,12 @@ config USB_TOUCHSCREEN
+ depends on USB && INPUT
+ ---help---
+ USB Touchscreen driver for:
+- - eGalax Touchkit USB
++ - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
+ - PanJit TouchSet USB
+- - 3M MicroTouch USB
++ - 3M MicroTouch USB (EX II series)
+ - ITM
++ - some other eTurboTouch
++ - Gunze AHL61
+
+ Have a look at <http://linux.chapter7.ch/touchkit/> for
+ a usage description and the required user-space stuff.
+@@ -218,7 +230,7 @@ config USB_TOUCHSCREEN
+
+ config USB_TOUCHSCREEN_EGALAX
+ default y
+- bool "eGalax device support" if EMBEDDED
++ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
+ config USB_TOUCHSCREEN_PANJIT
+@@ -228,7 +240,7 @@ config USB_TOUCHSCREEN_PANJIT
+
+ config USB_TOUCHSCREEN_3M
+ default y
+- bool "3M/Microtouch device support" if EMBEDDED
++ bool "3M/Microtouch EX II series device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
+ config USB_TOUCHSCREEN_ITM
+@@ -236,6 +248,16 @@ config USB_TOUCHSCREEN_ITM
+ bool "ITM device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
++config USB_TOUCHSCREEN_ETURBO
++ default y
++ bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
++ depends on USB_TOUCHSCREEN
++
++config USB_TOUCHSCREEN_GUNZE
++ default y
++ bool "Gunze AHL61 device support" if EMBEDDED
++ depends on USB_TOUCHSCREEN
++
+ config USB_YEALINK
+ tristate "Yealink usb-p1k voip phone"
+ depends on USB && INPUT && EXPERIMENTAL
+diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
+index 7641145..d946d52 100644
+--- a/drivers/usb/input/Makefile
++++ b/drivers/usb/input/Makefile
+@@ -3,6 +3,7 @@
+ #
+
+ # Multipart objects.
++wacom-objs := wacom_wac.o wacom_sys.o
+ usbhid-objs := hid-core.o
+
+ # Optional parts of multipart objects.
+@@ -14,7 +15,7 @@ ifeq ($(CONFIG_USB_HIDINPUT),y)
+ usbhid-objs += hid-input.o
+ endif
+ ifeq ($(CONFIG_HID_PID),y)
+- usbhid-objs += pid.o
++ usbhid-objs += hid-pidff.o
+ endif
+ ifeq ($(CONFIG_LOGITECH_FF),y)
+ usbhid-objs += hid-lgff.o
+@@ -22,6 +23,9 @@ endif
+ ifeq ($(CONFIG_THRUSTMASTER_FF),y)
+ usbhid-objs += hid-tmff.o
+ endif
++ifeq ($(CONFIG_ZEROPLUS_FF),y)
++ usbhid-objs += hid-zpff.o
++endif
+ ifeq ($(CONFIG_HID_FF),y)
+ usbhid-objs += hid-ff.o
+ endif
+diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
+index 18c10e1..0096373 100644
+--- a/drivers/usb/input/acecad.c
++++ b/drivers/usb/input/acecad.c
+@@ -58,7 +58,7 @@ struct usb_acecad {
+ dma_addr_t data_dma;
+ };
+
+-static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs)
++static void usb_acecad_irq(struct urb *urb)
+ {
+ struct usb_acecad *acecad = urb->context;
+ unsigned char *data = acecad->data;
+@@ -141,10 +141,7 @@ static int usb_acecad_probe(struct usb_i
+
+ endpoint = &interface->endpoint[0].desc;
+
+- if (!(endpoint->bEndpointAddress & 0x80))
+- return -ENODEV;
+-
+- if ((endpoint->bmAttributes & 3) != 3)
++ if (!usb_endpoint_is_int_in(endpoint))
+ return -ENODEV;
+
+ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
+index b138dae..bf42818 100644
+--- a/drivers/usb/input/aiptek.c
++++ b/drivers/usb/input/aiptek.c
+@@ -396,7 +396,7 @@ static int aiptek_convert_from_2s_comple
+ * replaced with the input_sync() method (which emits EV_SYN.)
+ */
+
+-static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
++static void aiptek_irq(struct urb *urb)
+ {
+ struct aiptek *aiptek = urb->context;
+ unsigned char *data = aiptek->data;
+@@ -442,8 +442,6 @@ static void aiptek_irq(struct urb *urb,
+ aiptek->diagnostic =
+ AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
+ } else {
+- input_regs(inputdev, regs);
+-
+ x = aiptek_convert_from_2s_complement(data[2]);
+ y = aiptek_convert_from_2s_complement(data[3]);
+
+@@ -488,8 +486,6 @@ static void aiptek_irq(struct urb *urb,
+ (aiptek->curSetting.pointerMode)) {
+ aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
+ } else {
+- input_regs(inputdev, regs);
+-
+ x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+ y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+ z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
+@@ -568,7 +564,6 @@ static void aiptek_irq(struct urb *urb,
+ (aiptek->curSetting.pointerMode)) {
+ aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
+ } else {
+- input_regs(inputdev, regs);
+ x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+ y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+
+@@ -631,8 +626,6 @@ static void aiptek_irq(struct urb *urb,
+ z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
+
+ if (dv != 0) {
+- input_regs(inputdev, regs);
+-
+ /* If we've not already sent a tool_button_?? code, do
+ * so now. Then set FIRED_BIT so it won't be resent unless
+ * the user forces FIRED_BIT off.
+@@ -681,8 +674,6 @@ static void aiptek_irq(struct urb *urb,
+ macro = data[3];
+
+ if (dv != 0) {
+- input_regs(inputdev, regs);
+-
+ /* If we've not already sent a tool_button_?? code, do
+ * so now. Then set FIRED_BIT so it won't be resent unless
+ * the user forces FIRED_BIT off.
+@@ -726,8 +717,6 @@ static void aiptek_irq(struct urb *urb,
+ */
+ else if (data[0] == 6) {
+ macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+- input_regs(inputdev, regs);
+-
+ if (macro > 0) {
+ input_report_key(inputdev, macroKeyEvents[macro - 1],
+ 0);
+diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
+index 044faa0..4c21351 100644
+--- a/drivers/usb/input/appletouch.c
++++ b/drivers/usb/input/appletouch.c
+@@ -210,7 +210,7 @@ static inline void atp_report_fingers(st
+ input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
+ }
+
+-static void atp_complete(struct urb* urb, struct pt_regs* regs)
++static void atp_complete(struct urb* urb)
+ {
+ int x, y, x_z, y_z, x_f, y_f;
+ int retval, i, j;
+@@ -436,10 +436,7 @@ static int atp_probe(struct usb_interfac
+ iface_desc = iface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+- if (!int_in_endpointAddr &&
+- (endpoint->bEndpointAddress & USB_DIR_IN) &&
+- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+- == USB_ENDPOINT_XFER_INT)) {
++ if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
+ /* we found an interrupt in endpoint */
+ int_in_endpointAddr = endpoint->bEndpointAddress;
+ break;
+diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
+index 3719fcb..f659f30 100644
+--- a/drivers/usb/input/ati_remote.c
++++ b/drivers/usb/input/ati_remote.c
+@@ -283,9 +283,9 @@ static void ati_remote_dump (unsigned c
+ static int ati_remote_open (struct input_dev *inputdev);
+ static void ati_remote_close (struct input_dev *inputdev);
+ static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
+-static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs);
+-static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs);
+-static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs);
++static void ati_remote_irq_out (struct urb *urb);
++static void ati_remote_irq_in (struct urb *urb);
++static void ati_remote_input_report (struct urb *urb);
+ static int ati_remote_initialize (struct ati_remote *ati_remote);
+ static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id);
+ static void ati_remote_disconnect (struct usb_interface *interface);
+@@ -344,7 +344,7 @@ static void ati_remote_close(struct inpu
+ /*
+ * ati_remote_irq_out
+ */
+-static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
++static void ati_remote_irq_out(struct urb *urb)
+ {
+ struct ati_remote *ati_remote = urb->context;
+
+@@ -453,7 +453,7 @@ static int ati_remote_compute_accel(stru
+ /*
+ * 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 ati_remote *ati_remote = urb->context;
+ unsigned char *data= ati_remote->inbuf;
+@@ -491,7 +491,6 @@ static void ati_remote_input_report(stru
+ 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);
+@@ -520,7 +519,6 @@ static void ati_remote_input_report(stru
+ return;
+
+
+- input_regs(dev, regs);
+ input_event(dev, ati_remote_tbl[index].type,
+ ati_remote_tbl[index].code, 1);
+ input_sync(dev);
+@@ -537,7 +535,6 @@ static void ati_remote_input_report(stru
+ */
+ acc = ati_remote_compute_accel(ati_remote);
+
+- input_regs(dev, regs);
+ switch (ati_remote_tbl[index].kind) {
+ case KIND_ACCEL:
+ input_event(dev, ati_remote_tbl[index].type,
+@@ -575,14 +572,14 @@ static void ati_remote_input_report(stru
+ /*
+ * ati_remote_irq_in
+ */
+-static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
++static void ati_remote_irq_in(struct urb *urb)
+ {
+ struct ati_remote *ati_remote = urb->context;
+ int retval;
+
+ switch (urb->status) {
+ case 0: /* success */
+- ati_remote_input_report(urb, regs);
++ ati_remote_input_report(urb);
+ break;
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+@@ -732,12 +729,8 @@ static int ati_remote_probe(struct usb_i
+ endpoint_in = &iface_host->endpoint[0].desc;
+ endpoint_out = &iface_host->endpoint[1].desc;
+
+- if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) {
+- err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
+- return -ENODEV;
+- }
+- if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
+- err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
++ if (!usb_endpoint_is_int_in(endpoint_in)) {
++ err("%s: Unexpected endpoint_in\n", __FUNCTION__);
+ return -ENODEV;
+ }
+ if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
+diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c
+index ea71de8..f982a2b 100644
+--- a/drivers/usb/input/ati_remote2.c
++++ b/drivers/usb/input/ati_remote2.c
+@@ -142,7 +142,7 @@ static void ati_remote2_close(struct inp
+ usb_kill_urb(ar2->urb[1]);
+ }
+
+-static void ati_remote2_input_mouse(struct ati_remote2 *ar2, struct pt_regs *regs)
++static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
+ {
+ struct input_dev *idev = ar2->idev;
+ u8 *data = ar2->buf[0];
+@@ -157,7 +157,6 @@ static void ati_remote2_input_mouse(stru
+ if (!((1 << data[0]) & mode_mask))
+ return;
+
+- input_regs(idev, regs);
+ input_event(idev, EV_REL, REL_X, (s8) data[1]);
+ input_event(idev, EV_REL, REL_Y, (s8) data[2]);
+ input_sync(idev);
+@@ -174,7 +173,7 @@ static int ati_remote2_lookup(unsigned i
+ return -1;
+ }
+
+-static void ati_remote2_input_key(struct ati_remote2 *ar2, struct pt_regs *regs)
++static void ati_remote2_input_key(struct ati_remote2 *ar2)
+ {
+ struct input_dev *idev = ar2->idev;
+ u8 *data = ar2->buf[1];
+@@ -245,19 +244,18 @@ static void ati_remote2_input_key(struct
+ return;
+ }
+
+- input_regs(idev, regs);
+ input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
+ input_sync(idev);
+ }
+
+-static void ati_remote2_complete_mouse(struct urb *urb, struct pt_regs *regs)
++static void ati_remote2_complete_mouse(struct urb *urb)
+ {
+ struct ati_remote2 *ar2 = urb->context;
+ int r;
+
+ switch (urb->status) {
+ case 0:
+- ati_remote2_input_mouse(ar2, regs);
++ ati_remote2_input_mouse(ar2);
+ break;
+ case -ENOENT:
+ case -EILSEQ:
+@@ -277,14 +275,14 @@ static void ati_remote2_complete_mouse(s
+ "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
+ }
+
+-static void ati_remote2_complete_key(struct urb *urb, struct pt_regs *regs)
++static void ati_remote2_complete_key(struct urb *urb)
+ {
+ struct ati_remote2 *ar2 = urb->context;
+ int r;
+
+ switch (urb->status) {
+ case 0:
+- ati_remote2_input_key(ar2, regs);
++ ati_remote2_input_key(ar2);
+ break;
+ case -ENOENT:
+ case -EILSEQ:
+diff --git a/drivers/usb/input/fixp-arith.h b/drivers/usb/input/fixp-arith.h
+deleted file mode 100644
+index ed3d2da..0000000
+--- a/drivers/usb/input/fixp-arith.h
++++ /dev/null
+@@ -1,87 +0,0 @@
+-#ifndef _FIXP_ARITH_H
+-#define _FIXP_ARITH_H
+-
+-/*
+- * Simplistic fixed-point arithmetics.
+- * Hmm, I'm probably duplicating some code :(
+- *
+- * Copyright (c) 2002 Johann Deneux
+- */
+-
+-/*
+- * 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 by
+- * e-mail - mail your message to <deneux at ifrance.com>
+- */
+-
+-#include <linux/types.h>
+-
+-/* The type representing fixed-point values */
+-typedef s16 fixp_t;
+-
+-#define FRAC_N 8
+-#define FRAC_MASK ((1<<FRAC_N)-1)
+-
+-/* Not to be used directly. Use fixp_{cos,sin} */
+-static const fixp_t cos_table[46] = {
+- 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8,
+- 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD,
+- 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1,
+- 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078,
+- 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035,
+- 0x002C, 0x0023, 0x001A, 0x0011, 0x0008, 0x0000
+-};
+-
+-
+-/* a: 123 -> 123.0 */
+-static inline fixp_t fixp_new(s16 a)
+-{
+- return a<<FRAC_N;
+-}
+-
+-/* a: 0xFFFF -> -1.0
+- 0x8000 -> 1.0
+- 0x0000 -> 0.0
+-*/
+-static inline fixp_t fixp_new16(s16 a)
+-{
+- return ((s32)a)>>(16-FRAC_N);
+-}
+-
+-static inline fixp_t fixp_cos(unsigned int degrees)
+-{
+- int quadrant = (degrees / 90) & 3;
+- unsigned int i = degrees % 90;
+-
+- if (quadrant == 1 || quadrant == 3)
+- i = 90 - i;
+-
+- i >>= 1;
+-
+- return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i];
+-}
+-
+-static inline fixp_t fixp_sin(unsigned int degrees)
+-{
+- return -fixp_cos(degrees + 90);
+-}
+-
+-static inline fixp_t fixp_mult(fixp_t a, fixp_t b)
+-{
+- return ((s32)(a*b))>>FRAC_N;
+-}
+-
+-#endif
+diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
+index a2c56b2..6daf85c 100644
+--- a/drivers/usb/input/hid-core.c
++++ b/drivers/usb/input/hid-core.c
+@@ -270,7 +270,7 @@ static int hid_add_field(struct hid_pars
+ * Read data value from item.
+ */
+
+-static __inline__ __u32 item_udata(struct hid_item *item)
++static u32 item_udata(struct hid_item *item)
+ {
+ switch (item->size) {
+ case 1: return item->data.u8;
+@@ -280,7 +280,7 @@ static __inline__ __u32 item_udata(struc
+ return 0;
+ }
+
+-static __inline__ __s32 item_sdata(struct hid_item *item)
++static s32 item_sdata(struct hid_item *item)
+ {
+ switch (item->size) {
+ case 1: return item->data.s8;
+@@ -543,8 +543,6 @@ static void hid_free_device(struct hid_d
+ {
+ unsigned i,j;
+
+- hid_ff_exit(device);
+-
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ struct hid_report_enum *report_enum = device->report_enum + i;
+
+@@ -729,7 +727,7 @@ static struct hid_device *hid_parse_repo
+ * done by hand.
+ */
+
+-static __inline__ __s32 snto32(__u32 value, unsigned n)
++static s32 snto32(__u32 value, unsigned n)
+ {
+ switch (n) {
+ case 8: return ((__s8)value);
+@@ -743,30 +741,65 @@ static __inline__ __s32 snto32(__u32 val
+ * Convert a signed 32-bit integer to a signed n-bit integer.
+ */
+
+-static __inline__ __u32 s32ton(__s32 value, unsigned n)
++static u32 s32ton(__s32 value, unsigned n)
+ {
+- __s32 a = value >> (n - 1);
++ s32 a = value >> (n - 1);
+ if (a && a != -1)
+ return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+ return value & ((1 << n) - 1);
+ }
+
+ /*
+- * Extract/implement a data field from/to a report.
++ * Extract/implement a data field from/to a little endian report (bit array).
++ *
++ * Code sort-of follows HID spec:
++ * http://www.usb.org/developers/devclass_docs/HID1_11.pdf
++ *
++ * While the USB HID spec allows unlimited length bit fields in "report
++ * descriptors", most devices never use more than 16 bits.
++ * One model of UPS is claimed to report "LINEV" as a 32-bit field.
++ * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
+ */
+
+ 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) & ((1ULL << n) - 1);
++ u64 x;
++
++ WARN_ON(n > 32);
++
++ report += offset >> 3; /* adjust byte index */
++ offset &= 7; /* now only need bit offset into one byte */
++ x = get_unaligned((u64 *) report);
++ x = le64_to_cpu(x);
++ x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
++ return (u32) x;
+ }
+
++/*
++ * "implement" : set bits in a little endian bit stream.
++ * Same concepts as "extract" (see comments above).
++ * The data mangled in the bit stream remains in little endian
++ * order the whole time. It make more sense to talk about
++ * endianness of register values by considering a register
++ * a "cached" copy of the little endiad bit stream.
++ */
+ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+ {
+- report += (offset >> 5) << 2; offset &= 31;
+- put_unaligned((get_unaligned((__le64*)report)
+- & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))
+- | cpu_to_le64((__u64)value << offset), (__le64*)report);
++ u64 x;
++ u64 m = (1ULL << n) - 1;
++
++ WARN_ON(n > 32);
++
++ WARN_ON(value > m);
++ value &= m;
++
++ report += offset >> 3;
++ offset &= 7;
++
++ x = get_unaligned((u64 *)report);
++ x &= cpu_to_le64(~(m << offset));
++ x |= cpu_to_le64(((u64) value) << offset);
++ put_unaligned(x, (u64 *) report);
+ }
+
+ /*
+@@ -782,13 +815,13 @@ static __inline__ int search(__s32 *arra
+ return -1;
+ }
+
+-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs)
++static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
+ {
+ hid_dump_input(usage, value);
+ if (hid->claimed & HID_CLAIMED_INPUT)
+- hidinput_hid_event(hid, field, usage, value, regs);
++ hidinput_hid_event(hid, field, usage, value);
+ if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
+- hiddev_hid_event(hid, field, usage, value, regs);
++ hiddev_hid_event(hid, field, usage, value);
+ }
+
+ /*
+@@ -797,7 +830,7 @@ static void hid_process_event(struct hid
+ * reporting to the layer).
+ */
+
+-static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs)
++static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
+ {
+ unsigned n;
+ unsigned count = field->report_count;
+@@ -824,19 +857,19 @@ static void hid_input_field(struct hid_d
+ for (n = 0; n < count; n++) {
+
+ if (HID_MAIN_ITEM_VARIABLE & field->flags) {
+- hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs);
++ hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
+ continue;
+ }
+
+ if (field->value[n] >= min && field->value[n] <= max
+ && field->usage[field->value[n] - min].hid
+ && search(value, field->value[n], count))
+- hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs);
++ hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
+
+ if (value[n] >= min && value[n] <= max
+ && field->usage[value[n] - min].hid
+ && search(field->value, value[n], count))
+- hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs);
++ hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
+ }
+
+ memcpy(field->value, value, count * sizeof(__s32));
+@@ -844,7 +877,7 @@ exit:
+ kfree(value);
+ }
+
+-static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs)
++static int hid_input_report(int type, struct urb *urb, int interrupt)
+ {
+ struct hid_device *hid = urb->context;
+ struct hid_report_enum *report_enum = hid->report_enum + type;
+@@ -894,7 +927,7 @@ static int hid_input_report(int type, st
+ hiddev_report_event(hid, report);
+
+ for (n = 0; n < report->maxfield; n++)
+- hid_input_field(hid, report->field[n], data, interrupt, regs);
++ hid_input_field(hid, report->field[n], data, interrupt);
+
+ if (hid->claimed & HID_CLAIMED_INPUT)
+ hidinput_report_event(hid, report);
+@@ -1006,7 +1039,7 @@ done:
+ * Input interrupt completion handler.
+ */
+
+-static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
++static void hid_irq_in(struct urb *urb)
+ {
+ struct hid_device *hid = urb->context;
+ int status;
+@@ -1014,7 +1047,7 @@ static void hid_irq_in(struct urb *urb,
+ switch (urb->status) {
+ case 0: /* success */
+ hid->retry_delay = 0;
+- hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
++ hid_input_report(HID_INPUT_REPORT, urb, 1);
+ break;
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+@@ -1023,7 +1056,8 @@ static void hid_irq_in(struct urb *urb,
+ return;
+ case -EILSEQ: /* protocol error or unplug */
+ case -EPROTO: /* protocol error or unplug */
+- case -ETIMEDOUT: /* NAK */
++ case -ETIME: /* protocol error or unplug */
++ case -ETIMEDOUT: /* Should never happen, but... */
+ clear_bit(HID_IN_RUNNING, &hid->iofl);
+ hid_io_error(hid);
+ return;
+@@ -1108,7 +1142,7 @@ int hid_set_field(struct hid_field *fiel
+ /*
+ * Find a report field with a specified HID usage.
+ */
+-
++#if 0
+ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
+ {
+ struct hid_report *report;
+@@ -1120,6 +1154,7 @@ struct hid_field *hid_find_field_by_usag
+ return report->field[i];
+ return NULL;
+ }
++#endif /* 0 */
+
+ static int hid_submit_out(struct hid_device *hid)
+ {
+@@ -1193,7 +1228,7 @@ static int hid_submit_ctrl(struct hid_de
+ * Output interrupt completion handler.
+ */
+
+-static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
++static void hid_irq_out(struct urb *urb)
+ {
+ struct hid_device *hid = urb->context;
+ unsigned long flags;
+@@ -1238,7 +1273,7 @@ static void hid_irq_out(struct urb *urb,
+ * Control pipe completion handler.
+ */
+
+-static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
++static void hid_ctrl(struct urb *urb)
+ {
+ struct hid_device *hid = urb->context;
+ unsigned long flags;
+@@ -1249,7 +1284,7 @@ static void hid_ctrl(struct urb *urb, st
+ switch (urb->status) {
+ case 0: /* success */
+ if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
+- hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
++ hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0);
+ break;
+ case -ESHUTDOWN: /* unplug */
+ unplug = 1;
+@@ -1381,6 +1416,9 @@ void hid_close(struct hid_device *hid)
+
+ #define USB_VENDOR_ID_PANJIT 0x134c
+
++#define USB_VENDOR_ID_TURBOX 0x062a
++#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
++
+ /*
+ * Initialize all reports
+ */
+@@ -1535,13 +1573,17 @@ void hid_init_reports(struct hid_device
+ #define USB_VENDOR_ID_GLAB 0x06c2
+ #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
+ #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
+-#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
+ #define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
++#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
++#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
++#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
+ #define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
++#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
+
+ #define USB_VENDOR_ID_WISEGROUP 0x0925
+ #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
+ #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
++#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
+ #define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
+
+ #define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
+@@ -1591,6 +1633,16 @@ void hid_init_reports(struct hid_device
+
+ #define USB_VENDOR_ID_YEALINK 0x6993
+ #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
++
++#define USB_VENDOR_ID_ALCOR 0x058f
++#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
++
++#define USB_VENDOR_ID_SUN 0x0430
++#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
++
++#define USB_VENDOR_ID_AIRCABLE 0x16CA
++#define USB_DEVICE_ID_AIRCABLE1 0x1502
++
+ /*
+ * Alphabetically sorted blacklist by quirk type.
+ */
+@@ -1608,6 +1660,8 @@ static const struct hid_blacklist {
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
+@@ -1620,9 +1674,12 @@ static const struct hid_blacklist {
+ { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
+@@ -1690,7 +1747,11 @@ static const struct hid_blacklist {
+ { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
++ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
+@@ -1701,6 +1762,7 @@ static const struct hid_blacklist {
+ { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
+ { 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_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
+
+ { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
+@@ -1711,6 +1773,7 @@ static const struct hid_blacklist {
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
++ { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+
+@@ -1747,6 +1810,8 @@ static const struct hid_blacklist {
+ { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
+
++ { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
++
+ { 0, 0 }
+ };
+
+@@ -1818,7 +1883,7 @@ static struct hid_device *usb_hid_config
+ int n, len, insize = 0;
+
+ /* Ignore all Wacom devices */
+- if (dev->descriptor.idVendor == USB_VENDOR_ID_WACOM)
++ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
+ return NULL;
+
+ for (n = 0; hid_blacklist[n].idVendor; n++)
+diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
+index d5c91ee..a8fc46c 100644
+--- a/drivers/usb/input/hid-ff.c
++++ b/drivers/usb/input/hid-ff.c
+@@ -44,45 +44,38 @@ struct hid_ff_initializer {
+ int (*init)(struct hid_device*);
+ };
+
++/*
++ * We try pidff when no other driver is found because PID is the
++ * standards compliant way of implementing force feedback in HID.
++ * pidff_init() will quickly abort if the device doesn't appear to
++ * be a PID device
++ */
+ static struct hid_ff_initializer inits[] = {
+ #ifdef CONFIG_LOGITECH_FF
+- {0x46d, 0xc211, hid_lgff_init}, // Logitech Cordless rumble pad
+- {0x46d, 0xc283, hid_lgff_init}, // Logitech Wingman Force 3d
+- {0x46d, 0xc295, hid_lgff_init}, // Logitech MOMO force wheel
+- {0x46d, 0xc219, hid_lgff_init}, // Logitech Cordless rumble pad 2
+-#endif
+-#ifdef CONFIG_HID_PID
+- {0x45e, 0x001b, hid_pid_init},
++ { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
++ { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
++ { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
++ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
+ #endif
+ #ifdef CONFIG_THRUSTMASTER_FF
+- {0x44f, 0xb304, hid_tmff_init},
++ { 0x44f, 0xb304, hid_tmff_init },
+ #endif
+- {0, 0, NULL} /* Terminating entry */
++#ifdef CONFIG_ZEROPLUS_FF
++ { 0xc12, 0x0005, hid_zpff_init },
++ { 0xc12, 0x0030, hid_zpff_init },
++#endif
++ { 0, 0, hid_pidff_init} /* Matches anything */
+ };
+
+-static struct hid_ff_initializer *hid_get_ff_init(__u16 idVendor,
+- __u16 idProduct)
+-{
+- struct hid_ff_initializer *init;
+- for (init = inits;
+- init->idVendor
+- && !(init->idVendor == idVendor
+- && init->idProduct == idProduct);
+- init++);
+-
+- return init->idVendor? init : NULL;
+-}
+-
+ int hid_ff_init(struct hid_device* hid)
+ {
+ struct hid_ff_initializer *init;
++ int vendor = le16_to_cpu(hid->dev->descriptor.idVendor);
++ int product = le16_to_cpu(hid->dev->descriptor.idProduct);
+
+- init = hid_get_ff_init(le16_to_cpu(hid->dev->descriptor.idVendor),
+- le16_to_cpu(hid->dev->descriptor.idProduct));
++ for (init = inits; init->idVendor; init++)
++ if (init->idVendor == vendor && init->idProduct == product)
++ break;
+
+- if (!init) {
+- dbg("hid_ff_init could not find initializer");
+- return -ENOSYS;
+- }
+ return init->init(hid);
+ }
+diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
+index 7208839..9a808a3 100644
+--- a/drivers/usb/input/hid-input.c
++++ b/drivers/usb/input/hid-input.c
+@@ -65,11 +65,9 @@ static const struct {
+ #define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
+ #define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
+ #define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
+-#define map_ff(c) do { usage->code = c; usage->type = EV_FF; bit = input->ffbit; max = FF_MAX; } while (0)
+
+ #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
+ #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
+-#define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0)
+
+ #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+
+@@ -525,23 +523,7 @@ static void hidinput_configure_usage(str
+
+ case HID_UP_PID:
+
+- set_bit(EV_FF, input->evbit);
+ switch(usage->hid & HID_USAGE) {
+- case 0x26: map_ff_effect(FF_CONSTANT); goto ignore;
+- case 0x27: map_ff_effect(FF_RAMP); goto ignore;
+- case 0x28: map_ff_effect(FF_CUSTOM); goto ignore;
+- case 0x30: map_ff_effect(FF_SQUARE); map_ff_effect(FF_PERIODIC); goto ignore;
+- case 0x31: map_ff_effect(FF_SINE); map_ff_effect(FF_PERIODIC); goto ignore;
+- case 0x32: map_ff_effect(FF_TRIANGLE); map_ff_effect(FF_PERIODIC); goto ignore;
+- case 0x33: map_ff_effect(FF_SAW_UP); map_ff_effect(FF_PERIODIC); goto ignore;
+- case 0x34: map_ff_effect(FF_SAW_DOWN); map_ff_effect(FF_PERIODIC); goto ignore;
+- case 0x40: map_ff_effect(FF_SPRING); goto ignore;
+- case 0x41: map_ff_effect(FF_DAMPER); goto ignore;
+- case 0x42: map_ff_effect(FF_INERTIA); goto ignore;
+- case 0x43: map_ff_effect(FF_FRICTION); goto ignore;
+- case 0x7e: map_ff(FF_GAIN); break;
+- case 0x83: input->ff_effects_max = field->value[0]; goto ignore;
+- case 0x98: map_ff(FF_AUTOCENTER); break;
+ case 0xa4: map_key_clear(BTN_DEAD); break;
+ default: goto ignore;
+ }
+@@ -631,7 +613,7 @@ ignore:
+ return;
+ }
+
+-void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
++void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
+ {
+ struct input_dev *input;
+ int *quirks = &hid->quirks;
+@@ -641,8 +623,6 @@ void hidinput_hid_event(struct hid_devic
+
+ input = field->hidinput->input;
+
+- input_regs(input, regs);
+-
+ if (!usage->type)
+ return;
+
+@@ -698,8 +678,7 @@ void hidinput_hid_event(struct hid_devic
+ }
+
+ if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
+- input->ff_effects_max = value;
+- dbg("Maximum Effects - %d",input->ff_effects_max);
++ dbg("Maximum Effects - %d",value);
+ return;
+ }
+
+@@ -748,7 +727,7 @@ static int hidinput_input_event(struct i
+ int offset;
+
+ if (type == EV_FF)
+- return hid_ff_event(hid, dev, type, code, value);
++ return input_ff_event(dev, type, code, value);
+
+ if (type != EV_LED)
+ return -1;
+diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
+index f07d443..93da222 100644
+--- a/drivers/usb/input/hid-lgff.c
++++ b/drivers/usb/input/hid-lgff.c
+@@ -1,12 +1,11 @@
+ /*
+- * $$
+- *
+ * Force feedback support for hid-compliant for some of the devices from
+ * Logitech, namely:
+ * - WingMan Cordless RumblePad
+ * - WingMan Force 3D
+ *
+ * Copyright (c) 2002-2004 Johann Deneux
++ * Copyright (c) 2006 Anssi Hannula <anssi.hannula at gmail.com>
+ */
+
+ /*
+@@ -29,495 +28,117 @@
+ */
+
+ #include <linux/input.h>
+-#include <linux/sched.h>
+-
+-//#define DEBUG
+ #include <linux/usb.h>
+-
+-#include <linux/circ_buf.h>
+-
+ #include "hid.h"
+-#include "fixp-arith.h"
+-
+-
+-/* Periodicity of the update */
+-#define PERIOD (HZ/10)
+-
+-#define RUN_AT(t) (jiffies + (t))
+-
+-/* Effect status */
+-#define EFFECT_STARTED 0 /* Effect is going to play after some time
+- (ff_replay.delay) */
+-#define EFFECT_PLAYING 1 /* Effect is being played */
+-#define EFFECT_USED 2
+-
+-// For lgff_device::flags
+-#define DEVICE_CLOSING 0 /* The driver is being unitialised */
+-
+-/* Check that the current process can access an effect */
+-#define CHECK_OWNERSHIP(effect) (current->pid == 0 \
+- || effect.owner == current->pid)
+-
+-#define LGFF_CHECK_OWNERSHIP(i, l) \
+- (i>=0 && i<LGFF_EFFECTS \
+- && test_bit(EFFECT_USED, l->effects[i].flags) \
+- && CHECK_OWNERSHIP(l->effects[i]))
+-
+-#define LGFF_EFFECTS 8
+
+ struct device_type {
+ u16 idVendor;
+ u16 idProduct;
+- signed short *ff;
+-};
+-
+-struct lgff_effect {
+- pid_t owner;
+-
+- struct ff_effect effect;
+-
+- unsigned long flags[1];
+- unsigned int count; /* Number of times left to play */
+- unsigned long started_at; /* When the effect started to play */
+-};
+-
+-struct lgff_device {
+- struct hid_device* hid;
+-
+- struct hid_report* constant;
+- struct hid_report* rumble;
+- struct hid_report* condition;
+-
+- struct lgff_effect effects[LGFF_EFFECTS];
+- spinlock_t lock; /* device-level lock. Having locks on
+- a per-effect basis could be nice, but
+- isn't really necessary */
+-
+- unsigned long flags[1]; /* Contains various information about the
+- state of the driver for this device */
+-
+- struct timer_list timer;
++ const signed short *ff;
+ };
+
+-/* Callbacks */
+-static void hid_lgff_exit(struct hid_device* hid);
+-static int hid_lgff_event(struct hid_device *hid, struct input_dev *input,
+- unsigned int type, unsigned int code, int value);
+-static int hid_lgff_flush(struct input_dev *input, struct file *file);
+-static int hid_lgff_upload_effect(struct input_dev *input,
+- struct ff_effect *effect);
+-static int hid_lgff_erase(struct input_dev *input, int id);
+-
+-/* Local functions */
+-static void hid_lgff_input_init(struct hid_device* hid);
+-static void hid_lgff_timer(unsigned long timer_data);
+-static struct hid_report* hid_lgff_duplicate_report(struct hid_report*);
+-static void hid_lgff_delete_report(struct hid_report*);
+-
+-static signed short ff_rumble[] = {
++static const signed short ff_rumble[] = {
+ FF_RUMBLE,
+ -1
+ };
+
+-static signed short ff_joystick[] = {
++static const signed short ff_joystick[] = {
+ FF_CONSTANT,
+ -1
+ };
+
+-static struct device_type devices[] = {
+- {0x046d, 0xc211, ff_rumble},
+- {0x046d, 0xc219, ff_rumble},
+- {0x046d, 0xc283, ff_joystick},
+- {0x0000, 0x0000, ff_joystick}
++static const struct device_type devices[] = {
++ { 0x046d, 0xc211, ff_rumble },
++ { 0x046d, 0xc219, ff_rumble },
++ { 0x046d, 0xc283, ff_joystick },
++ { 0x0000, 0x0000, ff_joystick }
+ };
+
++static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
++{
++ struct hid_device *hid = dev->private;
++ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
++ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
++ int x, y;
++ unsigned int left, right;
++
++#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
++
++ switch (effect->type) {
++ case FF_CONSTANT:
++ x = effect->u.ramp.start_level + 0x7f; /* 0x7f is center */
++ y = effect->u.ramp.end_level + 0x7f;
++ CLAMP(x);
++ CLAMP(y);
++ report->field[0]->value[0] = 0x51;
++ report->field[0]->value[1] = 0x08;
++ report->field[0]->value[2] = x;
++ report->field[0]->value[3] = y;
++ dbg("(x, y)=(%04x, %04x)", x, y);
++ hid_submit_report(hid, report, USB_DIR_OUT);
++ break;
++
++ case FF_RUMBLE:
++ right = effect->u.rumble.strong_magnitude;
++ left = effect->u.rumble.weak_magnitude;
++ right = right * 0xff / 0xffff;
++ left = left * 0xff / 0xffff;
++ CLAMP(left);
++ CLAMP(right);
++ report->field[0]->value[0] = 0x42;
++ report->field[0]->value[1] = 0x00;
++ report->field[0]->value[2] = left;
++ report->field[0]->value[3] = right;
++ dbg("(left, right)=(%04x, %04x)", left, right);
++ hid_submit_report(hid, report, USB_DIR_OUT);
++ break;
++ }
++ return 0;
++}
++
+ int hid_lgff_init(struct hid_device* hid)
+ {
+- struct lgff_device *private;
+- struct hid_report* report;
+- struct hid_field* field;
++ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
++ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
++ struct input_dev *dev = hidinput->input;
++ struct hid_report *report;
++ struct hid_field *field;
++ int error;
++ int i, j;
+
+ /* Find the report to use */
+- if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
++ if (list_empty(report_list)) {
+ err("No output report found");
+ return -1;
+ }
++
+ /* Check that the report looks ok */
+- report = (struct hid_report*)hid->report_enum[HID_OUTPUT_REPORT].report_list.next;
++ report = list_entry(report_list->next, struct hid_report, list);
+ if (!report) {
+ err("NULL output report");
+ return -1;
+ }
++
+ field = report->field[0];
+ if (!field) {
+ err("NULL field");
+ return -1;
+ }
+
+- private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
+- if (!private)
+- return -1;
+- hid->ff_private = private;
+-
+- /* Input init */
+- hid_lgff_input_init(hid);
+-
+-
+- private->constant = hid_lgff_duplicate_report(report);
+- if (!private->constant) {
+- kfree(private);
+- return -1;
+- }
+- private->constant->field[0]->value[0] = 0x51;
+- private->constant->field[0]->value[1] = 0x08;
+- private->constant->field[0]->value[2] = 0x7f;
+- private->constant->field[0]->value[3] = 0x7f;
+-
+- private->rumble = hid_lgff_duplicate_report(report);
+- if (!private->rumble) {
+- hid_lgff_delete_report(private->constant);
+- kfree(private);
+- return -1;
+- }
+- private->rumble->field[0]->value[0] = 0x42;
+-
+-
+- private->condition = hid_lgff_duplicate_report(report);
+- if (!private->condition) {
+- hid_lgff_delete_report(private->rumble);
+- hid_lgff_delete_report(private->constant);
+- kfree(private);
+- return -1;
+- }
+-
+- private->hid = hid;
+-
+- spin_lock_init(&private->lock);
+- init_timer(&private->timer);
+- private->timer.data = (unsigned long)private;
+- private->timer.function = hid_lgff_timer;
+-
+- /* Event and exit callbacks */
+- hid->ff_exit = hid_lgff_exit;
+- hid->ff_event = hid_lgff_event;
+-
+- /* Start the update task */
+- private->timer.expires = RUN_AT(PERIOD);
+- add_timer(&private->timer); /*TODO: only run the timer when at least
+- one effect is playing */
+-
+- printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux at it.uu.se>\n");
+-
+- return 0;
+-}
+-
+-static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
+-{
+- struct hid_report* ret;
+-
+- ret = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
+- if (!ret)
+- return NULL;
+- *ret = *report;
+-
+- ret->field[0] = kmalloc(sizeof(struct hid_field), GFP_KERNEL);
+- if (!ret->field[0]) {
+- kfree(ret);
+- return NULL;
+- }
+- *ret->field[0] = *report->field[0];
+-
+- ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
+- if (!ret->field[0]->value) {
+- kfree(ret->field[0]);
+- kfree(ret);
+- return NULL;
+- }
+-
+- return ret;
+-}
+-
+-static void hid_lgff_delete_report(struct hid_report* report)
+-{
+- if (report) {
+- kfree(report->field[0]->value);
+- kfree(report->field[0]);
+- kfree(report);
+- }
+-}
+-
+-static void hid_lgff_input_init(struct hid_device* hid)
+-{
+- struct device_type* dev = devices;
+- signed short* ff;
+- u16 idVendor = le16_to_cpu(hid->dev->descriptor.idVendor);
+- u16 idProduct = le16_to_cpu(hid->dev->descriptor.idProduct);
+- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+- struct input_dev *input_dev = hidinput->input;
+-
+- while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct))
+- dev++;
+-
+- for (ff = dev->ff; *ff >= 0; ff++)
+- set_bit(*ff, input_dev->ffbit);
+-
+- input_dev->upload_effect = hid_lgff_upload_effect;
+- input_dev->flush = hid_lgff_flush;
+-
+- set_bit(EV_FF, input_dev->evbit);
+- input_dev->ff_effects_max = LGFF_EFFECTS;
+-}
+-
+-static void hid_lgff_exit(struct hid_device* hid)
+-{
+- struct lgff_device *lgff = hid->ff_private;
+-
+- set_bit(DEVICE_CLOSING, lgff->flags);
+- del_timer_sync(&lgff->timer);
+-
+- hid_lgff_delete_report(lgff->condition);
+- hid_lgff_delete_report(lgff->rumble);
+- hid_lgff_delete_report(lgff->constant);
+-
+- kfree(lgff);
+-}
+-
+-static int hid_lgff_event(struct hid_device *hid, struct input_dev* input,
+- unsigned int type, unsigned int code, int value)
+-{
+- struct lgff_device *lgff = hid->ff_private;
+- struct lgff_effect *effect = lgff->effects + code;
+- unsigned long flags;
+-
+- if (type != EV_FF) return -EINVAL;
+- 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);
+- return -EBUSY;
+- }
+- if (test_bit(EFFECT_PLAYING, effect->flags)) {
+- spin_unlock_irqrestore(&lgff->lock, flags);
+- return -EBUSY;
+- }
+-
+- effect->count = value;
+-
+- if (effect->effect.replay.delay) {
+- set_bit(EFFECT_STARTED, effect->flags);
+- } else {
+- set_bit(EFFECT_PLAYING, effect->flags);
+- }
+- effect->started_at = jiffies;
+- }
+- else { /* value == 0 */
+- clear_bit(EFFECT_STARTED, effect->flags);
+- clear_bit(EFFECT_PLAYING, effect->flags);
+- }
+-
+- spin_unlock_irqrestore(&lgff->lock, flags);
+-
+- return 0;
+-
+-}
+-
+-/* Erase all effects this process owns */
+-static int hid_lgff_flush(struct input_dev *dev, struct file *file)
+-{
+- struct hid_device *hid = dev->private;
+- struct lgff_device *lgff = hid->ff_private;
+- int i;
+-
+- for (i=0; i<dev->ff_effects_max; ++i) {
+-
+- /*NOTE: no need to lock here. The only times EFFECT_USED is
+- modified is when effects are uploaded or when an effect is
+- erased. But a process cannot close its dev/input/eventX fd
+- 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);
+- }
+-
+- }
+-
+- return 0;
+-}
+-
+-static int hid_lgff_erase(struct input_dev *dev, int id)
+-{
+- struct hid_device *hid = dev->private;
+- struct lgff_device *lgff = hid->ff_private;
+- unsigned long flags;
+-
+- if (!LGFF_CHECK_OWNERSHIP(id, lgff)) return -EACCES;
+-
+- spin_lock_irqsave(&lgff->lock, flags);
+- lgff->effects[id].flags[0] = 0;
+- spin_unlock_irqrestore(&lgff->lock, flags);
+-
+- return 0;
+-}
+-
+-static int hid_lgff_upload_effect(struct input_dev* input,
+- struct ff_effect* effect)
+-{
+- struct hid_device *hid = input->private;
+- struct lgff_device *lgff = hid->ff_private;
+- struct lgff_effect new;
+- int id;
+- unsigned long flags;
+-
+- dbg("ioctl rumble");
+-
+- if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
+-
+- spin_lock_irqsave(&lgff->lock, flags);
+-
+- if (effect->id == -1) {
+- int i;
+-
+- for (i=0; i<LGFF_EFFECTS && test_bit(EFFECT_USED, lgff->effects[i].flags); ++i);
+- if (i >= LGFF_EFFECTS) {
+- spin_unlock_irqrestore(&lgff->lock, flags);
+- return -ENOSPC;
++ for (i = 0; i < ARRAY_SIZE(devices); i++) {
++ if (dev->id.vendor == devices[i].idVendor &&
++ dev->id.product == devices[i].idProduct) {
++ for (j = 0; devices[i].ff[j] >= 0; j++)
++ set_bit(devices[i].ff[j], dev->ffbit);
++ break;
+ }
+-
+- effect->id = i;
+- lgff->effects[i].owner = current->pid;
+- lgff->effects[i].flags[0] = 0;
+- set_bit(EFFECT_USED, lgff->effects[i].flags);
+ }
+- else if (!LGFF_CHECK_OWNERSHIP(effect->id, lgff)) {
+- spin_unlock_irqrestore(&lgff->lock, flags);
+- return -EACCES;
+- }
+-
+- id = effect->id;
+- new = lgff->effects[id];
+-
+- new.effect = *effect;
+-
+- if (test_bit(EFFECT_STARTED, lgff->effects[id].flags)
+- || test_bit(EFFECT_STARTED, lgff->effects[id].flags)) {
+-
+- /* Changing replay parameters is not allowed (for the time
+- being) */
+- if (new.effect.replay.delay != lgff->effects[id].effect.replay.delay
+- || new.effect.replay.length != lgff->effects[id].effect.replay.length) {
+- spin_unlock_irqrestore(&lgff->lock, flags);
+- return -ENOSYS;
+- }
+
+- lgff->effects[id] = new;
++ error = input_ff_create_memless(dev, NULL, hid_lgff_play);
++ if (error)
++ return error;
+
+- } else {
+- lgff->effects[id] = new;
+- }
++ printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux at it.uu.se>\n");
+
+- spin_unlock_irqrestore(&lgff->lock, flags);
+ return 0;
+ }
+-
+-static void hid_lgff_timer(unsigned long timer_data)
+-{
+- struct lgff_device *lgff = (struct lgff_device*)timer_data;
+- struct hid_device *hid = lgff->hid;
+- unsigned long flags;
+- int x = 0x7f, y = 0x7f; // Coordinates of constant effects
+- unsigned int left = 0, right = 0; // Rumbling
+- int i;
+-
+- spin_lock_irqsave(&lgff->lock, flags);
+-
+- for (i=0; i<LGFF_EFFECTS; ++i) {
+- struct lgff_effect* effect = lgff->effects +i;
+-
+- if (test_bit(EFFECT_PLAYING, effect->flags)) {
+-
+- switch (effect->effect.type) {
+- case FF_CONSTANT: {
+- //TODO: handle envelopes
+- int degrees = effect->effect.direction * 360 >> 16;
+- x += fixp_mult(fixp_sin(degrees),
+- fixp_new16(effect->effect.u.constant.level));
+- y += fixp_mult(-fixp_cos(degrees),
+- fixp_new16(effect->effect.u.constant.level));
+- } break;
+- case FF_RUMBLE:
+- right += effect->effect.u.rumble.strong_magnitude;
+- left += effect->effect.u.rumble.weak_magnitude;
+- break;
+- };
+-
+- /* One run of the effect is finished playing */
+- if (time_after(jiffies,
+- effect->started_at
+- + effect->effect.replay.delay*HZ/1000
+- + effect->effect.replay.length*HZ/1000)) {
+- dbg("Finished playing once %d", i);
+- if (--effect->count <= 0) {
+- dbg("Stopped %d", i);
+- clear_bit(EFFECT_PLAYING, effect->flags);
+- }
+- else {
+- dbg("Start again %d", i);
+- if (effect->effect.replay.length != 0) {
+- clear_bit(EFFECT_PLAYING, effect->flags);
+- set_bit(EFFECT_STARTED, effect->flags);
+- }
+- effect->started_at = jiffies;
+- }
+- }
+-
+- } else if (test_bit(EFFECT_STARTED, lgff->effects[i].flags)) {
+- /* Check if we should start playing the effect */
+- if (time_after(jiffies,
+- lgff->effects[i].started_at
+- + lgff->effects[i].effect.replay.delay*HZ/1000)) {
+- dbg("Now playing %d", i);
+- clear_bit(EFFECT_STARTED, lgff->effects[i].flags);
+- set_bit(EFFECT_PLAYING, lgff->effects[i].flags);
+- }
+- }
+- }
+-
+-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+-
+- // Clamp values
+- CLAMP(x);
+- CLAMP(y);
+- CLAMP(left);
+- CLAMP(right);
+-
+-#undef CLAMP
+-
+- if (x != lgff->constant->field[0]->value[2]
+- || y != lgff->constant->field[0]->value[3]) {
+- lgff->constant->field[0]->value[2] = x;
+- lgff->constant->field[0]->value[3] = y;
+- dbg("(x,y)=(%04x, %04x)", x, y);
+- hid_submit_report(hid, lgff->constant, USB_DIR_OUT);
+- }
+-
+- if (left != lgff->rumble->field[0]->value[2]
+- || right != lgff->rumble->field[0]->value[3]) {
+- lgff->rumble->field[0]->value[2] = left;
+- lgff->rumble->field[0]->value[3] = right;
+- dbg("(left,right)=(%04x, %04x)", left, right);
+- hid_submit_report(hid, lgff->rumble, USB_DIR_OUT);
+- }
+-
+- if (!test_bit(DEVICE_CLOSING, lgff->flags)) {
+- lgff->timer.expires = RUN_AT(PERIOD);
+- add_timer(&lgff->timer);
+- }
+-
+- spin_unlock_irqrestore(&lgff->lock, flags);
+-}
+diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c
+new file mode 100644
+index 0000000..5420c13
+--- /dev/null
++++ b/drivers/usb/input/hid-pidff.c
+@@ -0,0 +1,1330 @@
++/*
++ * Force feedback driver for USB HID PID compliant devices
++ *
++ * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula at gmail.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
++ */
++
++/* #define DEBUG */
++
++#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
++
++#include <linux/sched.h>
++#include <linux/input.h>
++#include <linux/usb.h>
++
++#include "hid.h"
++
++#define PID_EFFECTS_MAX 64
++
++/* Report usage table used to put reports into an array */
++
++#define PID_SET_EFFECT 0
++#define PID_EFFECT_OPERATION 1
++#define PID_DEVICE_GAIN 2
++#define PID_POOL 3
++#define PID_BLOCK_LOAD 4
++#define PID_BLOCK_FREE 5
++#define PID_DEVICE_CONTROL 6
++#define PID_CREATE_NEW_EFFECT 7
++
++#define PID_REQUIRED_REPORTS 7
++
++#define PID_SET_ENVELOPE 8
++#define PID_SET_CONDITION 9
++#define PID_SET_PERIODIC 10
++#define PID_SET_CONSTANT 11
++#define PID_SET_RAMP 12
++static const u8 pidff_reports[] = {
++ 0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab,
++ 0x5a, 0x5f, 0x6e, 0x73, 0x74
++};
++
++/* device_control is really 0x95, but 0x96 specified as it is the usage of
++the only field in that report */
++
++/* Value usage tables used to put fields and values into arrays */
++
++#define PID_EFFECT_BLOCK_INDEX 0
++
++#define PID_DURATION 1
++#define PID_GAIN 2
++#define PID_TRIGGER_BUTTON 3
++#define PID_TRIGGER_REPEAT_INT 4
++#define PID_DIRECTION_ENABLE 5
++#define PID_START_DELAY 6
++static const u8 pidff_set_effect[] = {
++ 0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7
++};
++
++#define PID_ATTACK_LEVEL 1
++#define PID_ATTACK_TIME 2
++#define PID_FADE_LEVEL 3
++#define PID_FADE_TIME 4
++static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e };
++
++#define PID_PARAM_BLOCK_OFFSET 1
++#define PID_CP_OFFSET 2
++#define PID_POS_COEFFICIENT 3
++#define PID_NEG_COEFFICIENT 4
++#define PID_POS_SATURATION 5
++#define PID_NEG_SATURATION 6
++#define PID_DEAD_BAND 7
++static const u8 pidff_set_condition[] = {
++ 0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65
++};
++
++#define PID_MAGNITUDE 1
++#define PID_OFFSET 2
++#define PID_PHASE 3
++#define PID_PERIOD 4
++static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 };
++static const u8 pidff_set_constant[] = { 0x22, 0x70 };
++
++#define PID_RAMP_START 1
++#define PID_RAMP_END 2
++static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 };
++
++#define PID_RAM_POOL_AVAILABLE 1
++static const u8 pidff_block_load[] = { 0x22, 0xac };
++
++#define PID_LOOP_COUNT 1
++static const u8 pidff_effect_operation[] = { 0x22, 0x7c };
++
++static const u8 pidff_block_free[] = { 0x22 };
++
++#define PID_DEVICE_GAIN_FIELD 0
++static const u8 pidff_device_gain[] = { 0x7e };
++
++#define PID_RAM_POOL_SIZE 0
++#define PID_SIMULTANEOUS_MAX 1
++#define PID_DEVICE_MANAGED_POOL 2
++static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 };
++
++/* Special field key tables used to put special field keys into arrays */
++
++#define PID_ENABLE_ACTUATORS 0
++#define PID_RESET 1
++static const u8 pidff_device_control[] = { 0x97, 0x9a };
++
++#define PID_CONSTANT 0
++#define PID_RAMP 1
++#define PID_SQUARE 2
++#define PID_SINE 3
++#define PID_TRIANGLE 4
++#define PID_SAW_UP 5
++#define PID_SAW_DOWN 6
++#define PID_SPRING 7
++#define PID_DAMPER 8
++#define PID_INERTIA 9
++#define PID_FRICTION 10
++static const u8 pidff_effect_types[] = {
++ 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34,
++ 0x40, 0x41, 0x42, 0x43
++};
++
++#define PID_BLOCK_LOAD_SUCCESS 0
++#define PID_BLOCK_LOAD_FULL 1
++static const u8 pidff_block_load_status[] = { 0x8c, 0x8d };
++
++#define PID_EFFECT_START 0
++#define PID_EFFECT_STOP 1
++static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b };
++
++struct pidff_usage {
++ struct hid_field *field;
++ s32 *value;
++};
++
++struct pidff_device {
++ struct hid_device *hid;
++
++ struct hid_report *reports[sizeof(pidff_reports)];
++
++ struct pidff_usage set_effect[sizeof(pidff_set_effect)];
++ struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];
++ struct pidff_usage set_condition[sizeof(pidff_set_condition)];
++ struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];
++ struct pidff_usage set_constant[sizeof(pidff_set_constant)];
++ struct pidff_usage set_ramp[sizeof(pidff_set_ramp)];
++
++ struct pidff_usage device_gain[sizeof(pidff_device_gain)];
++ struct pidff_usage block_load[sizeof(pidff_block_load)];
++ struct pidff_usage pool[sizeof(pidff_pool)];
++ struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];
++ struct pidff_usage block_free[sizeof(pidff_block_free)];
++
++ /* Special field is a field that is not composed of
++ usage<->value pairs that pidff_usage values are */
++
++ /* Special field in create_new_effect */
++ struct hid_field *create_new_effect_type;
++
++ /* Special fields in set_effect */
++ struct hid_field *set_effect_type;
++ struct hid_field *effect_direction;
++
++ /* Special field in device_control */
++ struct hid_field *device_control;
++
++ /* Special field in block_load */
++ struct hid_field *block_load_status;
++
++ /* Special field in effect_operation */
++ struct hid_field *effect_operation_status;
++
++ int control_id[sizeof(pidff_device_control)];
++ int type_id[sizeof(pidff_effect_types)];
++ int status_id[sizeof(pidff_block_load_status)];
++ int operation_id[sizeof(pidff_effect_operation_status)];
++
++ int pid_id[PID_EFFECTS_MAX];
++};
++
++/*
++ * Scale an unsigned value with range 0..max for the given field
++ */
++static int pidff_rescale(int i, int max, struct hid_field *field)
++{
++ return i * (field->logical_maximum - field->logical_minimum) / max +
++ field->logical_minimum;
++}
++
++/*
++ * Scale a signed value in range -0x8000..0x7fff for the given field
++ */
++static int pidff_rescale_signed(int i, struct hid_field *field)
++{
++ return i == 0 ? 0 : i >
++ 0 ? i * field->logical_maximum / 0x7fff : i *
++ field->logical_minimum / -0x8000;
++}
++
++static void pidff_set(struct pidff_usage *usage, u16 value)
++{
++ usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
++ debug("calculated from %d to %d", value, usage->value[0]);
++}
++
++static void pidff_set_signed(struct pidff_usage *usage, s16 value)
++{
++ if (usage->field->logical_minimum < 0)
++ usage->value[0] = pidff_rescale_signed(value, usage->field);
++ else {
++ if (value < 0)
++ usage->value[0] =
++ pidff_rescale(-value, 0x8000, usage->field);
++ else
++ usage->value[0] =
++ pidff_rescale(value, 0x7fff, usage->field);
++ }
++ debug("calculated from %d to %d", value, usage->value[0]);
++}
++
++/*
++ * Send envelope report to the device
++ */
++static void pidff_set_envelope_report(struct pidff_device *pidff,
++ struct ff_envelope *envelope)
++{
++ pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++
++ pidff->set_envelope[PID_ATTACK_LEVEL].value[0] =
++ pidff_rescale(envelope->attack_level >
++ 0x7fff ? 0x7fff : envelope->attack_level, 0x7fff,
++ pidff->set_envelope[PID_ATTACK_LEVEL].field);
++ pidff->set_envelope[PID_FADE_LEVEL].value[0] =
++ pidff_rescale(envelope->fade_level >
++ 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,
++ pidff->set_envelope[PID_FADE_LEVEL].field);
++
++ pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
++ pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
++
++ debug("attack %u => %d", envelope->attack_level,
++ pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
++
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
++ USB_DIR_OUT);
++}
++
++/*
++ * Test if the new envelope differs from old one
++ */
++static int pidff_needs_set_envelope(struct ff_envelope *envelope,
++ struct ff_envelope *old)
++{
++ return envelope->attack_level != old->attack_level ||
++ envelope->fade_level != old->fade_level ||
++ envelope->attack_length != old->attack_length ||
++ envelope->fade_length != old->fade_length;
++}
++
++/*
++ * Send constant force report to the device
++ */
++static void pidff_set_constant_force_report(struct pidff_device *pidff,
++ struct ff_effect *effect)
++{
++ pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++ pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
++ effect->u.constant.level);
++
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
++ USB_DIR_OUT);
++}
++
++/*
++ * Test if the constant parameters have changed between effects
++ */
++static int pidff_needs_set_constant(struct ff_effect *effect,
++ struct ff_effect *old)
++{
++ return effect->u.constant.level != old->u.constant.level;
++}
++
++/*
++ * Send set effect report to the device
++ */
++static void pidff_set_effect_report(struct pidff_device *pidff,
++ struct ff_effect *effect)
++{
++ pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++ pidff->set_effect_type->value[0] =
++ pidff->create_new_effect_type->value[0];
++ pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
++ pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
++ pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
++ effect->trigger.interval;
++ pidff->set_effect[PID_GAIN].value[0] =
++ pidff->set_effect[PID_GAIN].field->logical_maximum;
++ pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
++ pidff->effect_direction->value[0] =
++ pidff_rescale(effect->direction, 0xffff,
++ pidff->effect_direction);
++ pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
++
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
++ USB_DIR_OUT);
++}
++
++/*
++ * Test if the values used in set_effect have changed
++ */
++static int pidff_needs_set_effect(struct ff_effect *effect,
++ struct ff_effect *old)
++{
++ return effect->replay.length != old->replay.length ||
++ effect->trigger.interval != old->trigger.interval ||
++ effect->trigger.button != old->trigger.button ||
++ effect->direction != old->direction ||
++ effect->replay.delay != old->replay.delay;
++}
++
++/*
++ * Send periodic effect report to the device
++ */
++static void pidff_set_periodic_report(struct pidff_device *pidff,
++ struct ff_effect *effect)
++{
++ pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++ pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE],
++ effect->u.periodic.magnitude);
++ pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
++ effect->u.periodic.offset);
++ pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
++ pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
++
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
++ USB_DIR_OUT);
++
++}
++
++/*
++ * Test if periodic effect parameters have changed
++ */
++static int pidff_needs_set_periodic(struct ff_effect *effect,
++ struct ff_effect *old)
++{
++ return effect->u.periodic.magnitude != old->u.periodic.magnitude ||
++ effect->u.periodic.offset != old->u.periodic.offset ||
++ effect->u.periodic.phase != old->u.periodic.phase ||
++ effect->u.periodic.period != old->u.periodic.period;
++}
++
++/*
++ * Send condition effect reports to the device
++ */
++static void pidff_set_condition_report(struct pidff_device *pidff,
++ struct ff_effect *effect)
++{
++ int i;
++
++ pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++
++ for (i = 0; i < 2; i++) {
++ pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
++ pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],
++ effect->u.condition[i].center);
++ pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],
++ effect->u.condition[i].right_coeff);
++ pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT],
++ effect->u.condition[i].left_coeff);
++ pidff_set(&pidff->set_condition[PID_POS_SATURATION],
++ effect->u.condition[i].right_saturation);
++ pidff_set(&pidff->set_condition[PID_NEG_SATURATION],
++ effect->u.condition[i].left_saturation);
++ pidff_set(&pidff->set_condition[PID_DEAD_BAND],
++ effect->u.condition[i].deadband);
++ hid_wait_io(pidff->hid);
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
++ USB_DIR_OUT);
++ }
++}
++
++/*
++ * Test if condition effect parameters have changed
++ */
++static int pidff_needs_set_condition(struct ff_effect *effect,
++ struct ff_effect *old)
++{
++ int i;
++ int ret = 0;
++
++ for (i = 0; i < 2; i++) {
++ struct ff_condition_effect *cond = &effect->u.condition[i];
++ struct ff_condition_effect *old_cond = &old->u.condition[i];
++
++ ret |= cond->center != old_cond->center ||
++ cond->right_coeff != old_cond->right_coeff ||
++ cond->left_coeff != old_cond->left_coeff ||
++ cond->right_saturation != old_cond->right_saturation ||
++ cond->left_saturation != old_cond->left_saturation ||
++ cond->deadband != old_cond->deadband;
++ }
++
++ return ret;
++}
++
++/*
++ * Send ramp force report to the device
++ */
++static void pidff_set_ramp_force_report(struct pidff_device *pidff,
++ struct ff_effect *effect)
++{
++ pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++ pidff_set_signed(&pidff->set_ramp[PID_RAMP_START],
++ effect->u.ramp.start_level);
++ pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
++ effect->u.ramp.end_level);
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
++ USB_DIR_OUT);
++}
++
++/*
++ * Test if ramp force parameters have changed
++ */
++static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old)
++{
++ return effect->u.ramp.start_level != old->u.ramp.start_level ||
++ effect->u.ramp.end_level != old->u.ramp.end_level;
++}
++
++/*
++ * Send a request for effect upload to the device
++ *
++ * Returns 0 if device reported success, -ENOSPC if the device reported memory
++ * is full. Upon unknown response the function will retry for 60 times, if
++ * still unsuccessful -EIO is returned.
++ */
++static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
++{
++ int j;
++
++ pidff->create_new_effect_type->value[0] = efnum;
++ hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
++ USB_DIR_OUT);
++ debug("create_new_effect sent, type: %d", efnum);
++
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
++ pidff->block_load_status->value[0] = 0;
++ hid_wait_io(pidff->hid);
++
++ for (j = 0; j < 60; j++) {
++ debug("pid_block_load requested");
++ hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
++ USB_DIR_IN);
++ hid_wait_io(pidff->hid);
++ if (pidff->block_load_status->value[0] ==
++ pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
++ debug("device reported free memory: %d bytes",
++ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
++ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
++ return 0;
++ }
++ if (pidff->block_load_status->value[0] ==
++ pidff->status_id[PID_BLOCK_LOAD_FULL]) {
++ debug("not enough memory free: %d bytes",
++ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
++ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
++ return -ENOSPC;
++ }
++ }
++ printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
++ return -EIO;
++}
++
++/*
++ * Play the effect with PID id n times
++ */
++static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
++{
++ pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
++
++ if (n == 0) {
++ pidff->effect_operation_status->value[0] =
++ pidff->operation_id[PID_EFFECT_STOP];
++ } else {
++ pidff->effect_operation_status->value[0] =
++ pidff->operation_id[PID_EFFECT_START];
++ pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
++ }
++
++ hid_wait_io(pidff->hid);
++ hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
++ USB_DIR_OUT);
++}
++
++/**
++ * Play the effect with effect id @effect_id for @value times
++ */
++static int pidff_playback(struct input_dev *dev, int effect_id, int value)
++{
++ struct pidff_device *pidff = dev->ff->private;
++
++ pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
++
++ return 0;
++}
++
++/*
++ * Erase effect with PID id
++ */
++static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
++{
++ pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
++ hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
++ USB_DIR_OUT);
++}
++
++/*
++ * Stop and erase effect with effect_id
++ */
++static int pidff_erase_effect(struct input_dev *dev, int effect_id)
++{
++ struct pidff_device *pidff = dev->ff->private;
++ int pid_id = pidff->pid_id[effect_id];
++
++ debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
++ pidff_playback_pid(pidff, pid_id, 0);
++ pidff_erase_pid(pidff, pid_id);
++
++ return 0;
++}
++
++/*
++ * Effect upload handler
++ */
++static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
++ struct ff_effect *old)
++{
++ struct pidff_device *pidff = dev->ff->private;
++ int type_id;
++ int error;
++
++ switch (effect->type) {
++ case FF_CONSTANT:
++ if (!old) {
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[PID_CONSTANT]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_constant(effect, old))
++ pidff_set_constant_force_report(pidff, effect);
++ if (!old ||
++ pidff_needs_set_envelope(&effect->u.constant.envelope,
++ &old->u.constant.envelope))
++ pidff_set_envelope_report(pidff,
++ &effect->u.constant.envelope);
++ break;
++
++ case FF_PERIODIC:
++ if (!old) {
++ switch (effect->u.periodic.waveform) {
++ case FF_SQUARE:
++ type_id = PID_SQUARE;
++ break;
++ case FF_TRIANGLE:
++ type_id = PID_TRIANGLE;
++ break;
++ case FF_SINE:
++ type_id = PID_SINE;
++ break;
++ case FF_SAW_UP:
++ type_id = PID_SAW_UP;
++ break;
++ case FF_SAW_DOWN:
++ type_id = PID_SAW_DOWN;
++ break;
++ default:
++ printk(KERN_ERR
++ "hid-pidff: invalid waveform\n");
++ return -EINVAL;
++ }
++
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[type_id]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_periodic(effect, old))
++ pidff_set_periodic_report(pidff, effect);
++ if (!old ||
++ pidff_needs_set_envelope(&effect->u.periodic.envelope,
++ &old->u.periodic.envelope))
++ pidff_set_envelope_report(pidff,
++ &effect->u.periodic.envelope);
++ break;
++
++ case FF_RAMP:
++ if (!old) {
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[PID_RAMP]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_ramp(effect, old))
++ pidff_set_ramp_force_report(pidff, effect);
++ if (!old ||
++ pidff_needs_set_envelope(&effect->u.ramp.envelope,
++ &old->u.ramp.envelope))
++ pidff_set_envelope_report(pidff,
++ &effect->u.ramp.envelope);
++ break;
++
++ case FF_SPRING:
++ if (!old) {
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[PID_SPRING]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_condition(effect, old))
++ pidff_set_condition_report(pidff, effect);
++ break;
++
++ case FF_FRICTION:
++ if (!old) {
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[PID_FRICTION]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_condition(effect, old))
++ pidff_set_condition_report(pidff, effect);
++ break;
++
++ case FF_DAMPER:
++ if (!old) {
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[PID_DAMPER]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_condition(effect, old))
++ pidff_set_condition_report(pidff, effect);
++ break;
++
++ case FF_INERTIA:
++ if (!old) {
++ error = pidff_request_effect_upload(pidff,
++ pidff->type_id[PID_INERTIA]);
++ if (error)
++ return error;
++ }
++ if (!old || pidff_needs_set_effect(effect, old))
++ pidff_set_effect_report(pidff, effect);
++ if (!old || pidff_needs_set_condition(effect, old))
++ pidff_set_condition_report(pidff, effect);
++ break;
++
++ default:
++ printk(KERN_ERR "hid-pidff: invalid type\n");
++ return -EINVAL;
++ }
++
++ if (!old)
++ pidff->pid_id[effect->id] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
++
++ debug("uploaded");
++
++ return 0;
++}
++
++/*
++ * set_gain() handler
++ */
++static void pidff_set_gain(struct input_dev *dev, u16 gain)
++{
++ struct pidff_device *pidff = dev->ff->private;
++
++ pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
++ hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
++ USB_DIR_OUT);
++}
++
++static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
++{
++ struct hid_field *field =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field;
++
++ if (!magnitude) {
++ pidff_playback_pid(pidff, field->logical_minimum, 0);
++ return;
++ }
++
++ pidff_playback_pid(pidff, field->logical_minimum, 1);
++
++ pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum;
++ pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING];
++ pidff->set_effect[PID_DURATION].value[0] = 0;
++ pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
++ pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
++ pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
++ pidff->set_effect[PID_START_DELAY].value[0] = 0;
++
++ hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
++ USB_DIR_OUT);
++}
++
++/*
++ * pidff_set_autocenter() handler
++ */
++static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
++{
++ struct pidff_device *pidff = dev->ff->private;
++
++ pidff_autocenter(pidff, magnitude);
++}
++
++/*
++ * Find fields from a report and fill a pidff_usage
++ */
++static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
++ struct hid_report *report, int count, int strict)
++{
++ int i, j, k, found;
++
++ for (k = 0; k < count; k++) {
++ found = 0;
++ for (i = 0; i < report->maxfield; i++) {
++ if (report->field[i]->maxusage !=
++ report->field[i]->report_count) {
++ debug("maxusage and report_count do not match, "
++ "skipping");
++ continue;
++ }
++ for (j = 0; j < report->field[i]->maxusage; j++) {
++ if (report->field[i]->usage[j].hid ==
++ (HID_UP_PID | table[k])) {
++ debug("found %d at %d->%d", k, i, j);
++ usage[k].field = report->field[i];
++ usage[k].value =
++ &report->field[i]->value[j];
++ found = 1;
++ break;
++ }
++ }
++ if (found)
++ break;
++ }
++ if (!found && strict) {
++ debug("failed to locate %d", k);
++ return -1;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Return index into pidff_reports for the given usage
++ */
++static int pidff_check_usage(int usage)
++{
++ int i;
++
++ for (i = 0; i < sizeof(pidff_reports); i++)
++ if (usage == (HID_UP_PID | pidff_reports[i]))
++ return i;
++
++ return -1;
++}
++
++/*
++ * Find the reports and fill pidff->reports[]
++ * report_type specifies either OUTPUT or FEATURE reports
++ */
++static void pidff_find_reports(struct hid_device *hid, int report_type,
++ struct pidff_device *pidff)
++{
++ struct hid_report *report;
++ int i, ret;
++
++ list_for_each_entry(report,
++ &hid->report_enum[report_type].report_list, list) {
++ if (report->maxfield < 1)
++ continue;
++ ret = pidff_check_usage(report->field[0]->logical);
++ if (ret != -1) {
++ debug("found usage 0x%02x from field->logical",
++ pidff_reports[ret]);
++ pidff->reports[ret] = report;
++ continue;
++ }
++
++ /*
++ * Sometimes logical collections are stacked to indicate
++ * different usages for the report and the field, in which
++ * case we want the usage of the parent. However, Linux HID
++ * implementation hides this fact, so we have to dig it up
++ * ourselves
++ */
++ i = report->field[0]->usage[0].collection_index;
++ if (i <= 0 ||
++ hid->collection[i - 1].type != HID_COLLECTION_LOGICAL)
++ continue;
++ ret = pidff_check_usage(hid->collection[i - 1].usage);
++ if (ret != -1 && !pidff->reports[ret]) {
++ debug("found usage 0x%02x from collection array",
++ pidff_reports[ret]);
++ pidff->reports[ret] = report;
++ }
++ }
++}
++
++/*
++ * Test if the required reports have been found
++ */
++static int pidff_reports_ok(struct pidff_device *pidff)
++{
++ int i;
++
++ for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
++ if (!pidff->reports[i]) {
++ debug("%d missing", i);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++/*
++ * Find a field with a specific usage within a report
++ */
++static struct hid_field *pidff_find_special_field(struct hid_report *report,
++ int usage, int enforce_min)
++{
++ int i;
++
++ for (i = 0; i < report->maxfield; i++) {
++ if (report->field[i]->logical == (HID_UP_PID | usage) &&
++ report->field[i]->report_count > 0) {
++ if (!enforce_min ||
++ report->field[i]->logical_minimum == 1)
++ return report->field[i];
++ else {
++ printk(KERN_ERR "hid-pidff: logical_minimum "
++ "is not 1 as it should be\n");
++ return NULL;
++ }
++ }
++ }
++ return NULL;
++}
++
++/*
++ * Fill a pidff->*_id struct table
++ */
++static int pidff_find_special_keys(int *keys, struct hid_field *fld,
++ const u8 *usagetable, int count)
++{
++
++ int i, j;
++ int found = 0;
++
++ for (i = 0; i < count; i++) {
++ for (j = 0; j < fld->maxusage; j++) {
++ if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) {
++ keys[i] = j + 1;
++ found++;
++ break;
++ }
++ }
++ }
++ return found;
++}
++
++#define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \
++ pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \
++ sizeof(pidff_ ## name))
++
++/*
++ * Find and check the special fields
++ */
++static int pidff_find_special_fields(struct pidff_device *pidff)
++{
++ debug("finding special fields");
++
++ pidff->create_new_effect_type =
++ pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
++ 0x25, 1);
++ pidff->set_effect_type =
++ pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
++ 0x25, 1);
++ pidff->effect_direction =
++ pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
++ 0x57, 0);
++ pidff->device_control =
++ pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL],
++ 0x96, 1);
++ pidff->block_load_status =
++ pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD],
++ 0x8b, 1);
++ pidff->effect_operation_status =
++ pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
++ 0x78, 1);
++
++ debug("search done");
++
++ if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
++ printk(KERN_ERR "hid-pidff: effect lists not found\n");
++ return -1;
++ }
++
++ if (!pidff->effect_direction) {
++ printk(KERN_ERR "hid-pidff: direction field not found\n");
++ return -1;
++ }
++
++ if (!pidff->device_control) {
++ printk(KERN_ERR "hid-pidff: device control field not found\n");
++ return -1;
++ }
++
++ if (!pidff->block_load_status) {
++ printk(KERN_ERR
++ "hid-pidff: block load status field not found\n");
++ return -1;
++ }
++
++ if (!pidff->effect_operation_status) {
++ printk(KERN_ERR
++ "hid-pidff: effect operation field not found\n");
++ return -1;
++ }
++
++ pidff_find_special_keys(pidff->control_id, pidff->device_control,
++ pidff_device_control,
++ sizeof(pidff_device_control));
++
++ PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control);
++
++ if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
++ effect_types)) {
++ printk(KERN_ERR "hid-pidff: no effect types found\n");
++ return -1;
++ }
++
++ if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
++ block_load_status) !=
++ sizeof(pidff_block_load_status)) {
++ printk(KERN_ERR
++ "hidpidff: block load status identifiers not found\n");
++ return -1;
++ }
++
++ if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
++ effect_operation_status) !=
++ sizeof(pidff_effect_operation_status)) {
++ printk(KERN_ERR
++ "hidpidff: effect operation identifiers not found\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++/**
++ * Find the implemented effect types
++ */
++static int pidff_find_effects(struct pidff_device *pidff,
++ struct input_dev *dev)
++{
++ int i;
++
++ for (i = 0; i < sizeof(pidff_effect_types); i++) {
++ int pidff_type = pidff->type_id[i];
++ if (pidff->set_effect_type->usage[pidff_type].hid !=
++ pidff->create_new_effect_type->usage[pidff_type].hid) {
++ printk(KERN_ERR "hid-pidff: "
++ "effect type number %d is invalid\n", i);
++ return -1;
++ }
++ }
++
++ if (pidff->type_id[PID_CONSTANT])
++ set_bit(FF_CONSTANT, dev->ffbit);
++ if (pidff->type_id[PID_RAMP])
++ set_bit(FF_RAMP, dev->ffbit);
++ if (pidff->type_id[PID_SQUARE]) {
++ set_bit(FF_SQUARE, dev->ffbit);
++ set_bit(FF_PERIODIC, dev->ffbit);
++ }
++ if (pidff->type_id[PID_SINE]) {
++ set_bit(FF_SINE, dev->ffbit);
++ set_bit(FF_PERIODIC, dev->ffbit);
++ }
++ if (pidff->type_id[PID_TRIANGLE]) {
++ set_bit(FF_TRIANGLE, dev->ffbit);
++ set_bit(FF_PERIODIC, dev->ffbit);
++ }
++ if (pidff->type_id[PID_SAW_UP]) {
++ set_bit(FF_SAW_UP, dev->ffbit);
++ set_bit(FF_PERIODIC, dev->ffbit);
++ }
++ if (pidff->type_id[PID_SAW_DOWN]) {
++ set_bit(FF_SAW_DOWN, dev->ffbit);
++ set_bit(FF_PERIODIC, dev->ffbit);
++ }
++ if (pidff->type_id[PID_SPRING])
++ set_bit(FF_SPRING, dev->ffbit);
++ if (pidff->type_id[PID_DAMPER])
++ set_bit(FF_DAMPER, dev->ffbit);
++ if (pidff->type_id[PID_INERTIA])
++ set_bit(FF_INERTIA, dev->ffbit);
++ if (pidff->type_id[PID_FRICTION])
++ set_bit(FF_FRICTION, dev->ffbit);
++
++ return 0;
++
++}
++
++#define PIDFF_FIND_FIELDS(name, report, strict) \
++ pidff_find_fields(pidff->name, pidff_ ## name, \
++ pidff->reports[report], \
++ sizeof(pidff_ ## name), strict)
++
++/*
++ * Fill and check the pidff_usages
++ */
++static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
++{
++ int envelope_ok = 0;
++
++ if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
++ printk(KERN_ERR
++ "hid-pidff: unknown set_effect report layout\n");
++ return -ENODEV;
++ }
++
++ PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
++ if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
++ printk(KERN_ERR
++ "hid-pidff: unknown pid_block_load report layout\n");
++ return -ENODEV;
++ }
++
++ if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
++ printk(KERN_ERR
++ "hid-pidff: unknown effect_operation report layout\n");
++ return -ENODEV;
++ }
++
++ if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
++ printk(KERN_ERR
++ "hid-pidff: unknown pid_block_free report layout\n");
++ return -ENODEV;
++ }
++
++ if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1))
++ envelope_ok = 1;
++
++ if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev))
++ return -ENODEV;
++
++ if (!envelope_ok) {
++ if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
++ printk(KERN_WARNING "hid-pidff: "
++ "has constant effect but no envelope\n");
++ if (test_and_clear_bit(FF_RAMP, dev->ffbit))
++ printk(KERN_WARNING "hid-pidff: "
++ "has ramp effect but no envelope\n");
++
++ if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
++ printk(KERN_WARNING "hid-pidff: "
++ "has periodic effect but no envelope\n");
++ }
++
++ if (test_bit(FF_CONSTANT, dev->ffbit) &&
++ PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
++ printk(KERN_WARNING
++ "hid-pidff: unknown constant effect layout\n");
++ clear_bit(FF_CONSTANT, dev->ffbit);
++ }
++
++ if (test_bit(FF_RAMP, dev->ffbit) &&
++ PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
++ printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
++ clear_bit(FF_RAMP, dev->ffbit);
++ }
++
++ if ((test_bit(FF_SPRING, dev->ffbit) ||
++ test_bit(FF_DAMPER, dev->ffbit) ||
++ test_bit(FF_FRICTION, dev->ffbit) ||
++ test_bit(FF_INERTIA, dev->ffbit)) &&
++ PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
++ printk(KERN_WARNING
++ "hid-pidff: unknown condition effect layout\n");
++ clear_bit(FF_SPRING, dev->ffbit);
++ clear_bit(FF_DAMPER, dev->ffbit);
++ clear_bit(FF_FRICTION, dev->ffbit);
++ clear_bit(FF_INERTIA, dev->ffbit);
++ }
++
++ if (test_bit(FF_PERIODIC, dev->ffbit) &&
++ PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
++ printk(KERN_WARNING
++ "hid-pidff: unknown periodic effect layout\n");
++ clear_bit(FF_PERIODIC, dev->ffbit);
++ }
++
++ PIDFF_FIND_FIELDS(pool, PID_POOL, 0);
++
++ if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1))
++ set_bit(FF_GAIN, dev->ffbit);
++
++ return 0;
++}
++
++/*
++ * Reset the device
++ */
++static void pidff_reset(struct pidff_device *pidff)
++{
++ struct hid_device *hid = pidff->hid;
++ int i = 0;
++
++ pidff->device_control->value[0] = pidff->control_id[PID_RESET];
++ /* We reset twice as sometimes hid_wait_io isn't waiting long enough */
++ hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
++ hid_wait_io(hid);
++ hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
++ hid_wait_io(hid);
++
++ pidff->device_control->value[0] =
++ pidff->control_id[PID_ENABLE_ACTUATORS];
++ hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
++ hid_wait_io(hid);
++
++ /* pool report is sometimes messed up, refetch it */
++ hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
++ hid_wait_io(hid);
++
++ if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
++ int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
++ while (sim_effects < 2) {
++ if (i++ > 20) {
++ printk(KERN_WARNING "hid-pidff: device reports "
++ "%d simultaneous effects\n",
++ sim_effects);
++ break;
++ }
++ debug("pid_pool requested again");
++ hid_submit_report(hid, pidff->reports[PID_POOL],
++ USB_DIR_IN);
++ hid_wait_io(hid);
++ }
++ }
++}
++
++/*
++ * Test if autocenter modification is using the supported method
++ */
++static int pidff_check_autocenter(struct pidff_device *pidff,
++ struct input_dev *dev)
++{
++ int error;
++
++ /*
++ * Let's find out if autocenter modification is supported
++ * Specification doesn't specify anything, so we request an
++ * effect upload and cancel it immediately. If the approved
++ * effect id was one above the minimum, then we assume the first
++ * effect id is a built-in spring type effect used for autocenter
++ */
++
++ error = pidff_request_effect_upload(pidff, 1);
++ if (error) {
++ printk(KERN_ERR "hid-pidff: upload request failed\n");
++ return error;
++ }
++
++ if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] ==
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) {
++ pidff_autocenter(pidff, 0xffff);
++ set_bit(FF_AUTOCENTER, dev->ffbit);
++ } else {
++ printk(KERN_NOTICE "hid-pidff: "
++ "device has unknown autocenter control method\n");
++ }
++
++ pidff_erase_pid(pidff,
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]);
++
++ return 0;
++
++}
++
++/*
++ * Check if the device is PID and initialize it
++ */
++int hid_pidff_init(struct hid_device *hid)
++{
++ struct pidff_device *pidff;
++ struct hid_input *hidinput = list_entry(hid->inputs.next,
++ struct hid_input, list);
++ struct input_dev *dev = hidinput->input;
++ struct ff_device *ff;
++ int max_effects;
++ int error;
++
++ debug("starting pid init");
++
++ if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
++ debug("not a PID device, no output report");
++ return -ENODEV;
++ }
++
++ pidff = kzalloc(sizeof(*pidff), GFP_KERNEL);
++ if (!pidff)
++ return -ENOMEM;
++
++ pidff->hid = hid;
++
++ pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
++ pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
++
++ if (!pidff_reports_ok(pidff)) {
++ debug("reports not ok, aborting");
++ error = -ENODEV;
++ goto fail;
++ }
++
++ error = pidff_init_fields(pidff, dev);
++ if (error)
++ goto fail;
++
++ pidff_reset(pidff);
++
++ if (test_bit(FF_GAIN, dev->ffbit)) {
++ pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
++ hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
++ USB_DIR_OUT);
++ }
++
++ error = pidff_check_autocenter(pidff, dev);
++ if (error)
++ goto fail;
++
++ max_effects =
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
++ 1;
++ debug("max effects is %d", max_effects);
++
++ if (max_effects > PID_EFFECTS_MAX)
++ max_effects = PID_EFFECTS_MAX;
++
++ if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
++ debug("max simultaneous effects is %d",
++ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
++
++ if (pidff->pool[PID_RAM_POOL_SIZE].value)
++ debug("device memory size is %d bytes",
++ pidff->pool[PID_RAM_POOL_SIZE].value[0]);
++
++ if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
++ pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
++ printk(KERN_NOTICE "hid-pidff: "
++ "device does not support device managed pool\n");
++ goto fail;
++ }
++
++ error = input_ff_create(dev, max_effects);
++ if (error)
++ goto fail;
++
++ ff = dev->ff;
++ ff->private = pidff;
++ ff->upload = pidff_upload_effect;
++ ff->erase = pidff_erase_effect;
++ ff->set_gain = pidff_set_gain;
++ ff->set_autocenter = pidff_set_autocenter;
++ ff->playback = pidff_playback;
++
++ printk(KERN_INFO "Force feedback for USB HID PID devices by "
++ "Anssi Hannula <anssi.hannula at gmail.com>\n");
++
++ return 0;
++
++ fail:
++ kfree(pidff);
++ return error;
++}
+diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
+index 534425c..2d5be4c 100644
+--- a/drivers/usb/input/hid-tmff.c
++++ b/drivers/usb/input/hid-tmff.c
+@@ -28,97 +28,65 @@
+ */
+
+ #include <linux/input.h>
+-#include <linux/sched.h>
+
+ #undef DEBUG
+ #include <linux/usb.h>
+
+-#include <linux/circ_buf.h>
+-
+ #include "hid.h"
+-#include "fixp-arith.h"
+
+ /* Usages for thrustmaster devices I know about */
+ #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
+-#define DELAY_CALC(t,delay) ((t) + (delay)*HZ/1000)
+-
+-/* Effect status */
+-#define EFFECT_STARTED 0 /* Effect is going to play after some time */
+-#define EFFECT_PLAYING 1 /* Effect is playing */
+-#define EFFECT_USED 2
+-
+-/* For tmff_device::flags */
+-#define DEVICE_CLOSING 0 /* The driver is being unitialised */
+-
+-/* Check that the current process can access an effect */
+-#define CHECK_OWNERSHIP(effect) (current->pid == 0 \
+- || effect.owner == current->pid)
+-
+-#define TMFF_CHECK_ID(id) ((id) >= 0 && (id) < TMFF_EFFECTS)
+
+-#define TMFF_CHECK_OWNERSHIP(i, l) \
+- (test_bit(EFFECT_USED, l->effects[i].flags) \
+- && CHECK_OWNERSHIP(l->effects[i]))
+-
+-#define TMFF_EFFECTS 8
+-
+-struct tmff_effect {
+- pid_t owner;
+-
+- struct ff_effect effect;
+-
+- unsigned long flags[1];
+- unsigned int count; /* Number of times left to play */
+-
+- unsigned long play_at; /* When the effect starts to play */
+- unsigned long stop_at; /* When the effect ends */
+-};
+
+ struct tmff_device {
+- struct hid_device *hid;
+-
+ struct hid_report *report;
+-
+ struct hid_field *rumble;
++};
+
+- unsigned int effects_playing;
+- struct tmff_effect effects[TMFF_EFFECTS];
+- spinlock_t lock; /* device-level lock. Having locks on
+- a per-effect basis could be nice, but
+- isn't really necessary */
++/* Changes values from 0 to 0xffff into values from minimum to maximum */
++static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
++{
++ int ret;
+
+- unsigned long flags[1]; /* Contains various information about the
+- state of the driver for this device */
++ ret = (in * (maximum - minimum) / 0xffff) + minimum;
++ if (ret < minimum)
++ return minimum;
++ if (ret > maximum)
++ return maximum;
++ return ret;
++}
+
+- struct timer_list timer;
+-};
++static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
++{
++ struct hid_device *hid = dev->private;
++ struct tmff_device *tmff = data;
++ int left, right; /* Rumbling */
+
+-/* Callbacks */
+-static void hid_tmff_exit(struct hid_device *hid);
+-static int hid_tmff_event(struct hid_device *hid, struct input_dev *input,
+- unsigned int type, unsigned int code, int value);
+-static int hid_tmff_flush(struct input_dev *input, struct file *file);
+-static int hid_tmff_upload_effect(struct input_dev *input,
+- struct ff_effect *effect);
+-static int hid_tmff_erase(struct input_dev *input, int id);
++ left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
++ tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
++ right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
++ tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
+
+-/* Local functions */
+-static void hid_tmff_recalculate_timer(struct tmff_device *tmff);
+-static void hid_tmff_timer(unsigned long timer_data);
++ tmff->rumble->value[0] = left;
++ tmff->rumble->value[1] = right;
++ dbg("(left,right)=(%08x, %08x)", left, right);
++ hid_submit_report(hid, tmff->report, USB_DIR_OUT);
++
++ return 0;
++}
+
+ int hid_tmff_init(struct hid_device *hid)
+ {
+- struct tmff_device *private;
++ struct tmff_device *tmff;
+ struct list_head *pos;
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
++ int error;
+
+- private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
+- if (!private)
++ tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
++ if (!tmff)
+ return -ENOMEM;
+
+- hid->ff_private = private;
+-
+ /* Find the report to use */
+ __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+ struct hid_report *report = (struct hid_report *)pos;
+@@ -142,18 +110,18 @@ int hid_tmff_init(struct hid_device *hid
+ continue;
+ }
+
+- if (private->report && private->report != report) {
++ if (tmff->report && tmff->report != report) {
+ warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
+ continue;
+ }
+
+- if (private->rumble && private->rumble != field) {
++ if (tmff->rumble && tmff->rumble != field) {
+ warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
+ continue;
+ }
+
+- private->report = report;
+- private->rumble = field;
++ tmff->report = report;
++ tmff->rumble = field;
+
+ set_bit(FF_RUMBLE, input_dev->ffbit);
+ break;
+@@ -162,302 +130,17 @@ int hid_tmff_init(struct hid_device *hid
+ warn("ignoring unknown output usage %08x", field->usage[0].hid);
+ continue;
+ }
+-
+- /* Fallthrough to here only when a valid usage is found */
+- input_dev->upload_effect = hid_tmff_upload_effect;
+- input_dev->flush = hid_tmff_flush;
+-
+- set_bit(EV_FF, input_dev->evbit);
+- input_dev->ff_effects_max = TMFF_EFFECTS;
+ }
+ }
+
+- private->hid = hid;
+-
+- spin_lock_init(&private->lock);
+- init_timer(&private->timer);
+- private->timer.data = (unsigned long)private;
+- private->timer.function = hid_tmff_timer;
+-
+- /* Event and exit callbacks */
+- hid->ff_exit = hid_tmff_exit;
+- hid->ff_event = hid_tmff_event;
+-
+- info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx at epicsol.org>");
+-
+- return 0;
+-}
+-
+-static void hid_tmff_exit(struct hid_device *hid)
+-{
+- struct tmff_device *tmff = hid->ff_private;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&tmff->lock, flags);
+-
+- set_bit(DEVICE_CLOSING, tmff->flags);
+- del_timer_sync(&tmff->timer);
+-
+- spin_unlock_irqrestore(&tmff->lock, flags);
+-
+- kfree(tmff);
+-}
+-
+-static int hid_tmff_event(struct hid_device *hid, struct input_dev *input,
+- unsigned int type, unsigned int code, int value)
+-{
+- struct tmff_device *tmff = hid->ff_private;
+- struct tmff_effect *effect = &tmff->effects[code];
+- unsigned long flags;
+-
+- if (type != EV_FF)
+- return -EINVAL;
+- if (!TMFF_CHECK_ID(code))
+- return -EINVAL;
+- if (!TMFF_CHECK_OWNERSHIP(code, tmff))
+- return -EACCES;
+- if (value < 0)
+- return -EINVAL;
+-
+- spin_lock_irqsave(&tmff->lock, flags);
+-
+- if (value > 0) {
+- set_bit(EFFECT_STARTED, effect->flags);
+- clear_bit(EFFECT_PLAYING, effect->flags);
+- effect->count = value;
+- effect->play_at = DELAY_CALC(jiffies, effect->effect.replay.delay);
+- } else {
+- clear_bit(EFFECT_STARTED, effect->flags);
+- clear_bit(EFFECT_PLAYING, effect->flags);
+- }
+-
+- hid_tmff_recalculate_timer(tmff);
+-
+- spin_unlock_irqrestore(&tmff->lock, flags);
+-
+- return 0;
+-
+-}
+-
+-/* Erase all effects this process owns */
+-
+-static int hid_tmff_flush(struct input_dev *dev, struct file *file)
+-{
+- struct hid_device *hid = dev->private;
+- struct tmff_device *tmff = hid->ff_private;
+- int i;
+-
+- for (i=0; i<dev->ff_effects_max; ++i)
+-
+- /* NOTE: no need to lock here. The only times EFFECT_USED is
+- modified is when effects are uploaded or when an effect is
+- erased. But a process cannot close its dev/input/eventX fd
+- and perform ioctls on the same fd all at the same time */
+-
+- if (current->pid == tmff->effects[i].owner
+- && test_bit(EFFECT_USED, tmff->effects[i].flags))
+- if (hid_tmff_erase(dev, i))
+- warn("erase effect %d failed", i);
+-
+-
+- return 0;
+-}
+-
+-static int hid_tmff_erase(struct input_dev *dev, int id)
+-{
+- struct hid_device *hid = dev->private;
+- struct tmff_device *tmff = hid->ff_private;
+- unsigned long flags;
+-
+- if (!TMFF_CHECK_ID(id))
+- return -EINVAL;
+- if (!TMFF_CHECK_OWNERSHIP(id, tmff))
+- return -EACCES;
+-
+- spin_lock_irqsave(&tmff->lock, flags);
+-
+- tmff->effects[id].flags[0] = 0;
+- hid_tmff_recalculate_timer(tmff);
+-
+- spin_unlock_irqrestore(&tmff->lock, flags);
+-
+- return 0;
+-}
+-
+-static int hid_tmff_upload_effect(struct input_dev *input,
+- struct ff_effect *effect)
+-{
+- struct hid_device *hid = input->private;
+- struct tmff_device *tmff = hid->ff_private;
+- int id;
+- unsigned long flags;
+-
+- if (!test_bit(effect->type, input->ffbit))
+- return -EINVAL;
+- if (effect->id != -1 && !TMFF_CHECK_ID(effect->id))
+- return -EINVAL;
+-
+- spin_lock_irqsave(&tmff->lock, flags);
+-
+- if (effect->id == -1) {
+- /* Find a free effect */
+- for (id = 0; id < TMFF_EFFECTS && test_bit(EFFECT_USED, tmff->effects[id].flags); ++id);
+-
+- if (id >= TMFF_EFFECTS) {
+- spin_unlock_irqrestore(&tmff->lock, flags);
+- return -ENOSPC;
+- }
+-
+- effect->id = id;
+- tmff->effects[id].owner = current->pid;
+- tmff->effects[id].flags[0] = 0;
+- set_bit(EFFECT_USED, tmff->effects[id].flags);
+-
+- } else {
+- /* Re-uploading an owned effect, to change parameters */
+- id = effect->id;
+- clear_bit(EFFECT_PLAYING, tmff->effects[id].flags);
++ error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
++ if (error) {
++ kfree(tmff);
++ return error;
+ }
+
+- tmff->effects[id].effect = *effect;
+-
+- hid_tmff_recalculate_timer(tmff);
++ info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx at epicsol.org>");
+
+- spin_unlock_irqrestore(&tmff->lock, flags);
+ return 0;
+ }
+
+-/* Start the timer for the next start/stop/delay */
+-/* Always call this while tmff->lock is locked */
+-
+-static void hid_tmff_recalculate_timer(struct tmff_device *tmff)
+-{
+- int i;
+- int events = 0;
+- unsigned long next_time;
+-
+- next_time = 0; /* Shut up compiler's incorrect warning */
+-
+- /* Find the next change in an effect's status */
+- for (i = 0; i < TMFF_EFFECTS; ++i) {
+- struct tmff_effect *effect = &tmff->effects[i];
+- unsigned long play_time;
+-
+- if (!test_bit(EFFECT_STARTED, effect->flags))
+- continue;
+-
+- effect->stop_at = DELAY_CALC(effect->play_at, effect->effect.replay.length);
+-
+- if (!test_bit(EFFECT_PLAYING, effect->flags))
+- play_time = effect->play_at;
+- else
+- play_time = effect->stop_at;
+-
+- events++;
+-
+- if (time_after(jiffies, play_time))
+- play_time = jiffies;
+-
+- if (events == 1)
+- next_time = play_time;
+- else {
+- if (time_after(next_time, play_time))
+- next_time = play_time;
+- }
+- }
+-
+- if (!events && tmff->effects_playing) {
+- /* Treat all effects turning off as an event */
+- events = 1;
+- next_time = jiffies;
+- }
+-
+- if (!events) {
+- /* No events, no time, no need for a timer. */
+- del_timer_sync(&tmff->timer);
+- return;
+- }
+-
+- mod_timer(&tmff->timer, next_time);
+-}
+-
+-/* Changes values from 0 to 0xffff into values from minimum to maximum */
+-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+-{
+- int ret;
+-
+- ret = (in * (maximum - minimum) / 0xffff) + minimum;
+- if (ret < minimum)
+- return minimum;
+- if (ret > maximum)
+- return maximum;
+- return ret;
+-}
+-
+-static void hid_tmff_timer(unsigned long timer_data)
+-{
+- struct tmff_device *tmff = (struct tmff_device *) timer_data;
+- struct hid_device *hid = tmff->hid;
+- unsigned long flags;
+- int left = 0, right = 0; /* Rumbling */
+- int i;
+-
+- spin_lock_irqsave(&tmff->lock, flags);
+-
+- tmff->effects_playing = 0;
+-
+- for (i = 0; i < TMFF_EFFECTS; ++i) {
+- struct tmff_effect *effect = &tmff->effects[i];
+-
+- if (!test_bit(EFFECT_STARTED, effect->flags))
+- continue;
+-
+- if (!time_after(jiffies, effect->play_at))
+- continue;
+-
+- if (time_after(jiffies, effect->stop_at)) {
+-
+- dbg("Finished playing once %d", i);
+- clear_bit(EFFECT_PLAYING, effect->flags);
+-
+- if (--effect->count <= 0) {
+- dbg("Stopped %d", i);
+- clear_bit(EFFECT_STARTED, effect->flags);
+- continue;
+- } else {
+- dbg("Start again %d", i);
+- effect->play_at = DELAY_CALC(jiffies, effect->effect.replay.delay);
+- continue;
+- }
+- }
+-
+- ++tmff->effects_playing;
+-
+- set_bit(EFFECT_PLAYING, effect->flags);
+-
+- switch (effect->effect.type) {
+- case FF_RUMBLE:
+- right += effect->effect.u.rumble.strong_magnitude;
+- left += effect->effect.u.rumble.weak_magnitude;
+- break;
+- default:
+- BUG();
+- break;
+- }
+- }
+-
+- left = hid_tmff_scale(left, tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
+- right = hid_tmff_scale(right, tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
+-
+- if (left != tmff->rumble->value[0] || right != tmff->rumble->value[1]) {
+- tmff->rumble->value[0] = left;
+- tmff->rumble->value[1] = right;
+- dbg("(left,right)=(%08x, %08x)", left, right);
+- hid_submit_report(hid, tmff->report, USB_DIR_OUT);
+- }
+-
+- if (!test_bit(DEVICE_CLOSING, tmff->flags))
+- hid_tmff_recalculate_timer(tmff);
+-
+- spin_unlock_irqrestore(&tmff->lock, flags);
+-}
+diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c
+new file mode 100644
+index 0000000..d2ce321
+--- /dev/null
++++ b/drivers/usb/input/hid-zpff.c
+@@ -0,0 +1,110 @@
++/*
++ * Force feedback support for Zeroplus based devices
++ *
++ * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula at gmail.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
++ */
++
++
++/* #define DEBUG */
++
++#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg)
++
++#include <linux/input.h>
++#include <linux/usb.h>
++#include "hid.h"
++
++struct zpff_device {
++ struct hid_report *report;
++};
++
++static int hid_zpff_play(struct input_dev *dev, void *data,
++ struct ff_effect *effect)
++{
++ struct hid_device *hid = dev->private;
++ struct zpff_device *zpff = data;
++ int left, right;
++
++ /*
++ * The following is specified the other way around in the Zeroplus
++ * datasheet but the order below is correct for the XFX Executioner;
++ * however it is possible that the XFX Executioner is an exception
++ */
++
++ left = effect->u.rumble.strong_magnitude;
++ right = effect->u.rumble.weak_magnitude;
++ debug("called with 0x%04x 0x%04x", left, right);
++
++ left = left * 0x7f / 0xffff;
++ right = right * 0x7f / 0xffff;
++
++ zpff->report->field[2]->value[0] = left;
++ zpff->report->field[3]->value[0] = right;
++ debug("running with 0x%02x 0x%02x", left, right);
++ hid_submit_report(hid, zpff->report, USB_DIR_OUT);
++
++ return 0;
++}
++
++int hid_zpff_init(struct hid_device *hid)
++{
++ struct zpff_device *zpff;
++ struct hid_report *report;
++ struct hid_input *hidinput = list_entry(hid->inputs.next,
++ struct hid_input, list);
++ struct list_head *report_list =
++ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
++ struct input_dev *dev = hidinput->input;
++ int error;
++
++ if (list_empty(report_list)) {
++ printk(KERN_ERR "hid-zpff: no output report found\n");
++ return -ENODEV;
++ }
++
++ report = list_entry(report_list->next, struct hid_report, list);
++
++ if (report->maxfield < 4) {
++ printk(KERN_ERR "hid-zpff: not enough fields in report\n");
++ return -ENODEV;
++ }
++
++ zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
++ if (!zpff)
++ return -ENOMEM;
++
++ set_bit(FF_RUMBLE, dev->ffbit);
++
++ error = input_ff_create_memless(dev, zpff, hid_zpff_play);
++ if (error) {
++ kfree(zpff);
++ return error;
++ }
++
++ zpff->report = report;
++ zpff->report->field[0]->value[0] = 0x00;
++ zpff->report->field[1]->value[0] = 0x02;
++ zpff->report->field[2]->value[0] = 0x00;
++ zpff->report->field[3]->value[0] = 0x00;
++ hid_submit_report(hid, zpff->report, USB_DIR_OUT);
++
++ printk(KERN_INFO "Force feedback for Zeroplus based devices by "
++ "Anssi Hannula <anssi.hannula at gmail.com>\n");
++
++ return 0;
++}
+diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
+index 778e575..9b50eff 100644
+--- a/drivers/usb/input/hid.h
++++ b/drivers/usb/input/hid.h
+@@ -449,11 +449,6 @@ struct hid_device { /* device repo
+ char phys[64]; /* Device physical location */
+ char uniq[64]; /* Device unique identifier (serial #) */
+
+- void *ff_private; /* Private data for the force-feedback driver */
+- void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */
+- int (*ff_event)(struct hid_device *hid, struct input_dev *input,
+- unsigned int type, unsigned int code, int value);
+-
+ #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+ unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
+ unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
+@@ -504,13 +499,13 @@ struct hid_descriptor {
+ /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
+ /* We ignore a few input applications that are not widely used */
+ #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
+-extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32, struct pt_regs *regs);
++extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
+ extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
+ extern int hidinput_connect(struct hid_device *);
+ extern void hidinput_disconnect(struct hid_device *);
+ #else
+ #define IS_INPUT_APPLICATION(a) (0)
+-static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) { }
++static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
+ static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { }
+ static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
+ static inline void hidinput_disconnect(struct hid_device *hid) { }
+@@ -521,29 +516,22 @@ void hid_close(struct hid_device *);
+ int hid_set_field(struct hid_field *, unsigned, __s32);
+ void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
+ void hid_init_reports(struct hid_device *hid);
+-struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type);
+ int hid_wait_io(struct hid_device* hid);
+
+
+ #ifdef CONFIG_HID_FF
+ int hid_ff_init(struct hid_device *hid);
++
++int hid_lgff_init(struct hid_device *hid);
++int hid_tmff_init(struct hid_device *hid);
++int hid_zpff_init(struct hid_device *hid);
++#ifdef CONFIG_HID_PID
++int hid_pidff_init(struct hid_device *hid);
++#else
++static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
++#endif
++
+ #else
+ static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+ #endif
+-static inline void hid_ff_exit(struct hid_device *hid)
+-{
+- if (hid->ff_exit)
+- hid->ff_exit(hid);
+-}
+-static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input,
+- unsigned int type, unsigned int code, int value)
+-{
+- if (hid->ff_event)
+- return hid->ff_event(hid, input, type, code, value);
+- return -ENOSYS;
+-}
+-
+-int hid_lgff_init(struct hid_device* hid);
+-int hid_tmff_init(struct hid_device* hid);
+-int hid_pid_init(struct hid_device* hid);
+
+diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
+index f6b839c..7dc14d0 100644
+--- a/drivers/usb/input/hiddev.c
++++ b/drivers/usb/input/hiddev.c
+@@ -179,7 +179,7 @@ static void hiddev_send_event(struct hid
+ * the interrupt pipe
+ */
+ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+- struct hid_usage *usage, __s32 value, struct pt_regs *regs)
++ struct hid_usage *usage, __s32 value)
+ {
+ unsigned type = field->report_type;
+ struct hiddev_usage_ref uref;
+@@ -722,7 +722,7 @@ inval:
+ return -EINVAL;
+ }
+
+-static struct file_operations hiddev_fops = {
++static const struct file_operations hiddev_fops = {
+ .owner = THIS_MODULE,
+ .read = hiddev_read,
+ .write = hiddev_write,
+diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
+index 86acb5f..aac968a 100644
+--- a/drivers/usb/input/itmtouch.c
++++ b/drivers/usb/input/itmtouch.c
+@@ -36,7 +36,11 @@
+ *
+ * 1.2.1 09/03/2005 (HCE) hc at mivu.no
+ * Code cleanup and adjusting syntax to start matching kernel standards
+- *
++ *
++ * 1.2.2 10/05/2006 (MJA) massad at gmail.com
++ * Flag for detecting if the screen was being touch was incorrectly
++ * inverted, so no touch events were being detected.
++ *
+ *****************************************************************************/
+
+ #include <linux/kernel.h>
+@@ -53,7 +57,7 @@
+ #define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9
+
+ #define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc at mivu.no>"
+-#define DRIVER_VERSION "v1.2.1"
++#define DRIVER_VERSION "v1.2.2"
+ #define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
+ #define DRIVER_LICENSE "GPL"
+
+@@ -76,7 +80,7 @@ static struct usb_device_id itmtouch_ids
+ { }
+ };
+
+-static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
++static void itmtouch_irq(struct urb *urb)
+ {
+ struct itmtouch_dev *itmtouch = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -87,7 +91,7 @@ static void itmtouch_irq(struct urb *urb
+ case 0:
+ /* success */
+ break;
+- case -ETIMEDOUT:
++ case -ETIME:
+ /* this urb is timing out */
+ dbg("%s - urb timed out - was the device unplugged?",
+ __FUNCTION__);
+@@ -105,10 +109,8 @@ static void itmtouch_irq(struct urb *urb
+ goto exit;
+ }
+
+- input_regs(dev, regs);
+-
+ /* if pressure has been released, then don't report X/Y */
+- if (data[7] & 0x20) {
++ 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));
+ }
+diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
+index 604ade3..fedbcb1 100644
+--- a/drivers/usb/input/kbtab.c
++++ b/drivers/usb/input/kbtab.c
+@@ -41,7 +41,7 @@ struct kbtab {
+ char phys[32];
+ };
+
+-static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
++static void kbtab_irq(struct urb *urb)
+ {
+ struct kbtab *kbtab = urb->context;
+ unsigned char *data = kbtab->data;
+diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c
+index 4723b31..50aa810 100644
+--- a/drivers/usb/input/keyspan_remote.c
++++ b/drivers/usb/input/keyspan_remote.c
+@@ -176,7 +176,7 @@ static int keyspan_load_tester(struct us
+ /*
+ * 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)
++static void keyspan_check_data(struct usb_keyspan *remote)
+ {
+ int i;
+ int found = 0;
+@@ -311,7 +311,6 @@ static void keyspan_check_data(struct us
+ __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);
+@@ -361,7 +360,7 @@ static int keyspan_setup(struct usb_devi
+ /*
+ * Routine used to handle a new message that has come in.
+ */
+-static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs)
++static void keyspan_irq_recv(struct urb *urb)
+ {
+ struct usb_keyspan *dev = urb->context;
+ int retval;
+@@ -385,7 +384,7 @@ static void keyspan_irq_recv(struct urb
+ if (debug)
+ keyspan_print(dev);
+
+- keyspan_check_data(dev, regs);
++ keyspan_check_data(dev);
+
+ resubmit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+@@ -420,8 +419,7 @@ static struct usb_endpoint_descriptor *k
+ for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+ endpoint = &iface->endpoint[i].desc;
+
+- if ((endpoint->bEndpointAddress & USB_DIR_IN) &&
+- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
++ if (usb_endpoint_is_int_in(endpoint)) {
+ /* we found our interrupt in endpoint */
+ return endpoint;
+ }
+diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
+index a9ccda8..79a85d4 100644
+--- a/drivers/usb/input/mtouchusb.c
++++ b/drivers/usb/input/mtouchusb.c
+@@ -98,7 +98,7 @@ static struct usb_device_id mtouchusb_de
+ { }
+ };
+
+-static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
++static void mtouchusb_irq(struct urb *urb)
+ {
+ struct mtouch_usb *mtouch = urb->context;
+ int retval;
+@@ -107,7 +107,7 @@ static void mtouchusb_irq(struct urb *ur
+ case 0:
+ /* success */
+ break;
+- case -ETIMEDOUT:
++ case -ETIME:
+ /* this urb is timing out */
+ dbg("%s - urb timed out - was the device unplugged?",
+ __FUNCTION__);
+@@ -125,7 +125,6 @@ static void mtouchusb_irq(struct urb *ur
+ 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));
+diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
+deleted file mode 100644
+index d9d9f65..0000000
+--- a/drivers/usb/input/pid.c
++++ /dev/null
+@@ -1,295 +0,0 @@
+-/*
+- * PID Force feedback support for hid devices.
+- *
+- * Copyright (c) 2002 Rodrigo Damazio.
+- * Portions by Johann Deneux and Bjorn Augustson
+- */
+-
+-/*
+- * 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 by
+- * e-mail - mail your message to <rdamazio at lsi.usp.br>
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/slab.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/mm.h>
+-#include <linux/smp_lock.h>
+-#include <linux/spinlock.h>
+-#include <linux/input.h>
+-#include <linux/usb.h>
+-#include "hid.h"
+-#include "pid.h"
+-
+-#define CHECK_OWNERSHIP(i, hid_pid) \
+- ((i) < FF_EFFECTS_MAX && i >= 0 && \
+- test_bit(FF_PID_FLAGS_USED, &hid_pid->effects[(i)].flags) && \
+- (current->pid == 0 || \
+- (hid_pid)->effects[(i)].owner == current->pid))
+-
+-/* Called when a transfer is completed */
+-static void hid_pid_ctrl_out(struct urb *u, struct pt_regs *regs)
+-{
+- dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n");
+-}
+-
+-static void hid_pid_exit(struct hid_device *hid)
+-{
+- struct hid_ff_pid *private = hid->ff_private;
+-
+- if (private->urbffout) {
+- usb_kill_urb(private->urbffout);
+- usb_free_urb(private->urbffout);
+- }
+-}
+-
+-static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+-{
+- dev_info(&pid->hid->dev->dev, "requested periodic force upload\n");
+- return 0;
+-}
+-
+-static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+-{
+- dev_info(&pid->hid->dev->dev, "requested constant force upload\n");
+- return 0;
+-}
+-
+-static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+-{
+- dev_info(&pid->hid->dev->dev, "requested Condition force upload\n");
+- return 0;
+-}
+-
+-static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+-{
+- dev_info(&pid->hid->dev->dev, "request ramp force upload\n");
+- return 0;
+-}
+-
+-static int hid_pid_event(struct hid_device *hid, struct input_dev *input,
+- unsigned int type, unsigned int code, int value)
+-{
+- dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value);
+-
+- if (type != EV_FF)
+- return -1;
+-
+- return 0;
+-}
+-
+-/* Lock must be held by caller */
+-static void hid_pid_ctrl_playback(struct hid_device *hid, struct hid_pid_effect *effect, int play)
+-{
+- if (play)
+- set_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
+- else
+- clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
+-}
+-
+-static int hid_pid_erase(struct input_dev *dev, int id)
+-{
+- struct hid_device *hid = dev->private;
+- struct hid_ff_pid *pid = hid->ff_private;
+- struct hid_field *field;
+- unsigned long flags;
+- int ret;
+-
+- if (!CHECK_OWNERSHIP(id, pid))
+- return -EACCES;
+-
+- /* Find report */
+- field = hid_find_field_by_usage(hid, HID_UP_PID | FF_PID_USAGE_BLOCK_FREE,
+- HID_OUTPUT_REPORT);
+- if (!field) {
+- dev_err(&hid->dev->dev, "couldn't find report\n");
+- return -EIO;
+- }
+-
+- ret = hid_set_field(field, 0, pid->effects[id].device_id);
+- if (ret) {
+- dev_err(&hid->dev->dev, "couldn't set field\n");
+- return ret;
+- }
+-
+- hid_submit_report(hid, field->report, USB_DIR_OUT);
+-
+- spin_lock_irqsave(&pid->lock, flags);
+- hid_pid_ctrl_playback(hid, pid->effects + id, 0);
+- pid->effects[id].flags = 0;
+- spin_unlock_irqrestore(&pid->lock, flags);
+-
+- return 0;
+-}
+-
+-/* Erase all effects this process owns */
+-static int hid_pid_flush(struct input_dev *dev, struct file *file)
+-{
+- struct hid_device *hid = dev->private;
+- struct hid_ff_pid *pid = hid->ff_private;
+- int i;
+-
+- /*NOTE: no need to lock here. The only times EFFECT_USED is
+- modified is when effects are uploaded or when an effect is
+- erased. But a process cannot close its dev/input/eventX fd
+- and perform ioctls on the same fd all at the same time */
+- /*FIXME: multiple threads, anyone? */
+- for (i = 0; i < dev->ff_effects_max; ++i)
+- if (current->pid == pid->effects[i].owner
+- && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
+- if (hid_pid_erase(dev, i))
+- dev_warn(&hid->dev->dev, "erase effect %d failed", i);
+-
+- return 0;
+-}
+-
+-static int hid_pid_upload_effect(struct input_dev *dev,
+- struct ff_effect *effect)
+-{
+- struct hid_ff_pid *pid_private = (struct hid_ff_pid *)(dev->private);
+- int ret;
+- int is_update;
+- unsigned long flags;
+-
+- dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n", effect->type);
+- /* Check this effect type is supported by this device */
+- if (!test_bit(effect->type, dev->ffbit)) {
+- dev_dbg(&pid_private->hid->dev->dev,
+- "invalid kind of effect requested.\n");
+- return -EINVAL;
+- }
+-
+- /*
+- * If we want to create a new effect, get a free id
+- */
+- if (effect->id == -1) {
+- int id = 0;
+-
+- // Spinlock so we don`t get a race condition when choosing IDs
+- spin_lock_irqsave(&pid_private->lock, flags);
+-
+- while (id < FF_EFFECTS_MAX)
+- if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags))
+- break;
+-
+- if (id == FF_EFFECTS_MAX) {
+- spin_unlock_irqrestore(&pid_private->lock, flags);
+-// TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) {
+- dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n");
+- return -ENOMEM;
+- }
+-
+- effect->id = id;
+- dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d.\n", id);
+- pid_private->effects[id].owner = current->pid;
+- pid_private->effects[id].flags = (1 << FF_PID_FLAGS_USED);
+- spin_unlock_irqrestore(&pid_private->lock, flags);
+-
+- is_update = FF_PID_FALSE;
+- } else {
+- /* We want to update an effect */
+- if (!CHECK_OWNERSHIP(effect->id, pid_private))
+- return -EACCES;
+-
+- /* Parameter type cannot be updated */
+- if (effect->type != pid_private->effects[effect->id].effect.type)
+- return -EINVAL;
+-
+- /* Check the effect is not already being updated */
+- if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags))
+- return -EAGAIN;
+-
+- is_update = FF_PID_TRUE;
+- }
+-
+- /*
+- * Upload the effect
+- */
+- switch (effect->type) {
+- case FF_PERIODIC:
+- ret = pid_upload_periodic(pid_private, effect, is_update);
+- break;
+-
+- case FF_CONSTANT:
+- ret = pid_upload_constant(pid_private, effect, is_update);
+- break;
+-
+- case FF_SPRING:
+- case FF_FRICTION:
+- case FF_DAMPER:
+- case FF_INERTIA:
+- ret = pid_upload_condition(pid_private, effect, is_update);
+- break;
+-
+- case FF_RAMP:
+- ret = pid_upload_ramp(pid_private, effect, is_update);
+- break;
+-
+- default:
+- dev_dbg(&pid_private->hid->dev->dev,
+- "invalid type of effect requested - %x.\n",
+- effect->type);
+- return -EINVAL;
+- }
+- /* If a packet was sent, forbid new updates until we are notified
+- * that the packet was updated
+- */
+- if (ret == 0)
+- set_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags);
+- pid_private->effects[effect->id].effect = *effect;
+- return ret;
+-}
+-
+-int hid_pid_init(struct hid_device *hid)
+-{
+- struct hid_ff_pid *private;
+- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+- struct input_dev *input_dev = hidinput->input;
+-
+- private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
+- if (!private)
+- return -ENOMEM;
+-
+- private->hid = hid;
+-
+- hid->ff_exit = hid_pid_exit;
+- hid->ff_event = hid_pid_event;
+-
+- /* Open output URB */
+- if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
+- kfree(private);
+- return -1;
+- }
+-
+- usb_fill_control_urb(private->urbffout, hid->dev, 0,
+- (void *)&private->ffcr, private->ctrl_buffer, 8,
+- hid_pid_ctrl_out, hid);
+-
+- input_dev->upload_effect = hid_pid_upload_effect;
+- input_dev->flush = hid_pid_flush;
+- input_dev->ff_effects_max = 8; // A random default
+- set_bit(EV_FF, input_dev->evbit);
+- set_bit(EV_FF_STATUS, input_dev->evbit);
+-
+- spin_lock_init(&private->lock);
+-
+- printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio at lsi.usp.br>.\n");
+-
+- return 0;
+-}
+diff --git a/drivers/usb/input/pid.h b/drivers/usb/input/pid.h
+deleted file mode 100644
+index a2cb962..0000000
+--- a/drivers/usb/input/pid.h
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*
+- * PID Force feedback support for hid devices.
+- *
+- * Copyright (c) 2002 Rodrigo Damazio.
+- */
+-
+-/*
+- * 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 by
+- * e-mail - mail your message to <rdamazio at lsi.usp.br>
+- */
+-
+-#define FF_EFFECTS_MAX 64
+-
+-#define FF_PID_FLAGS_USED 1 /* If the effect exists */
+-#define FF_PID_FLAGS_UPDATING 2 /* If the effect is being updated */
+-#define FF_PID_FLAGS_PLAYING 3 /* If the effect is currently being played */
+-
+-#define FF_PID_FALSE 0
+-#define FF_PID_TRUE 1
+-
+-struct hid_pid_effect {
+- unsigned long flags;
+- pid_t owner;
+- unsigned int device_id; /* The device-assigned ID */
+- struct ff_effect effect;
+-};
+-
+-struct hid_ff_pid {
+- struct hid_device *hid;
+- unsigned long gain;
+-
+- struct urb *urbffout;
+- struct usb_ctrlrequest ffcr;
+- spinlock_t lock;
+-
+- unsigned char ctrl_buffer[8];
+-
+- struct hid_pid_effect effects[FF_EFFECTS_MAX];
+-};
+-
+-/*
+- * Constants from the PID usage table (still far from complete)
+- */
+-
+-#define FF_PID_USAGE_BLOCK_LOAD 0x89UL
+-#define FF_PID_USAGE_BLOCK_FREE 0x90UL
+-#define FF_PID_USAGE_NEW_EFFECT 0xABUL
+-#define FF_PID_USAGE_POOL_REPORT 0x7FUL
+diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
+index b3c0d0c..0bf9177 100644
+--- a/drivers/usb/input/powermate.c
++++ b/drivers/usb/input/powermate.c
+@@ -80,10 +80,10 @@ struct powermate_device {
+ static char pm_name_powermate[] = "Griffin PowerMate";
+ static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+-static void powermate_config_complete(struct urb *urb, struct pt_regs *regs);
++static void powermate_config_complete(struct urb *urb);
+
+ /* Callback for data arriving from the PowerMate over the USB interrupt pipe */
+-static void powermate_irq(struct urb *urb, struct pt_regs *regs)
++static void powermate_irq(struct urb *urb)
+ {
+ struct powermate_device *pm = urb->context;
+ int retval;
+@@ -104,7 +104,6 @@ static void powermate_irq(struct urb *ur
+ }
+
+ /* handle updates to device state */
+- input_regs(pm->input, regs);
+ input_report_key(pm->input, BTN_0, pm->data[0] & 0x01);
+ input_report_rel(pm->input, REL_DIAL, pm->data[1]);
+ input_sync(pm->input);
+@@ -191,7 +190,7 @@ static void powermate_sync_state(struct
+ }
+
+ /* Called when our asynchronous control message completes. We may need to issue another immediately */
+-static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
++static void powermate_config_complete(struct urb *urb)
+ {
+ struct powermate_device *pm = urb->context;
+ unsigned long flags;
+@@ -313,9 +312,7 @@ static int powermate_probe(struct usb_in
+
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+- if (!(endpoint->bEndpointAddress & 0x80))
+- return -EIO;
+- if ((endpoint->bmAttributes & 3) != 3)
++ if (!usb_endpoint_is_int_in(endpoint))
+ return -EIO;
+
+ usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
+index 0149043..05c0d1c 100644
+--- a/drivers/usb/input/touchkitusb.c
++++ b/drivers/usb/input/touchkitusb.c
+@@ -92,8 +92,7 @@ static inline int touchkit_get_y(char *d
+
+
+ /* processes one input packet. */
+-static void touchkit_process_pkt(struct touchkit_usb *touchkit,
+- struct pt_regs *regs, char *pkt)
++static void touchkit_process_pkt(struct touchkit_usb *touchkit, char *pkt)
+ {
+ int x, y;
+
+@@ -109,7 +108,6 @@ static void touchkit_process_pkt(struct
+ y = touchkit_get_y(pkt);
+ }
+
+- input_regs(touchkit->input, regs);
+ input_report_key(touchkit->input, BTN_TOUCH, touchkit_get_touched(pkt));
+ input_report_abs(touchkit->input, ABS_X, x);
+ input_report_abs(touchkit->input, ABS_Y, y);
+@@ -130,8 +128,7 @@ static int touchkit_get_pkt_len(char *bu
+ return 0;
+ }
+
+-static void touchkit_process(struct touchkit_usb *touchkit, int len,
+- struct pt_regs *regs)
++static void touchkit_process(struct touchkit_usb *touchkit, int len)
+ {
+ char *buffer;
+ int pkt_len, buf_len, pos;
+@@ -153,7 +150,7 @@ static void touchkit_process(struct touc
+ /* append, process */
+ tmp = pkt_len - touchkit->buf_len;
+ memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp);
+- touchkit_process_pkt(touchkit, regs, touchkit->buffer);
++ touchkit_process_pkt(touchkit, touchkit->buffer);
+
+ buffer = touchkit->data + tmp;
+ buf_len = len - tmp;
+@@ -181,7 +178,7 @@ static void touchkit_process(struct touc
+
+ /* full packet: process */
+ if (likely(pkt_len <= buf_len)) {
+- touchkit_process_pkt(touchkit, regs, buffer + pos);
++ touchkit_process_pkt(touchkit, buffer + pos);
+ } else {
+ /* incomplete packet: save in buffer */
+ memcpy(touchkit->buffer, buffer + pos, buf_len - pos);
+@@ -192,7 +189,7 @@ static void touchkit_process(struct touc
+ }
+
+
+-static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
++static void touchkit_irq(struct urb *urb)
+ {
+ struct touchkit_usb *touchkit = urb->context;
+ int retval;
+@@ -201,7 +198,7 @@ static void touchkit_irq(struct urb *urb
+ case 0:
+ /* success */
+ break;
+- case -ETIMEDOUT:
++ case -ETIME:
+ /* this urb is timing out */
+ dbg("%s - urb timed out - was the device unplugged?",
+ __FUNCTION__);
+@@ -219,7 +216,7 @@ static void touchkit_irq(struct urb *urb
+ goto exit;
+ }
+
+- touchkit_process(touchkit, urb->actual_length, regs);
++ touchkit_process(touchkit, urb->actual_length);
+
+ exit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
+index 5067a6a..c73285c 100644
+--- a/drivers/usb/input/usbkbd.c
++++ b/drivers/usb/input/usbkbd.c
+@@ -80,7 +80,7 @@ struct usb_kbd {
+ dma_addr_t leds_dma;
+ };
+
+-static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)
++static void usb_kbd_irq(struct urb *urb)
+ {
+ struct usb_kbd *kbd = urb->context;
+ int i;
+@@ -97,8 +97,6 @@ static void usb_kbd_irq(struct urb *urb,
+ goto resubmit;
+ }
+
+- input_regs(kbd->dev, regs);
+-
+ for (i = 0; i < 8; i++)
+ input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
+
+@@ -158,7 +156,7 @@ static int usb_kbd_event(struct input_de
+ return 0;
+ }
+
+-static void usb_kbd_led(struct urb *urb, struct pt_regs *regs)
++static void usb_kbd_led(struct urb *urb)
+ {
+ struct usb_kbd *kbd = urb->context;
+
+diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
+index 446935b..cbbbea3 100644
+--- a/drivers/usb/input/usbmouse.c
++++ b/drivers/usb/input/usbmouse.c
+@@ -55,7 +55,7 @@ struct usb_mouse {
+ dma_addr_t data_dma;
+ };
+
+-static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs)
++static void usb_mouse_irq(struct urb *urb)
+ {
+ struct usb_mouse *mouse = urb->context;
+ signed char *data = mouse->data;
+@@ -74,8 +74,6 @@ static void usb_mouse_irq(struct urb *ur
+ goto resubmit;
+ }
+
+- input_regs(dev, regs);
+-
+ input_report_key(dev, BTN_LEFT, data[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+ input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
+@@ -218,7 +216,7 @@ static void usb_mouse_disconnect(struct
+
+ static struct usb_device_id usb_mouse_id_table [] = {
+ { USB_INTERFACE_INFO(3, 1, 2) },
+- { } /* Terminating entry */
++ { } /* Terminating entry */
+ };
+
+ MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
+diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c
+index a338bf4..933cedd 100644
+--- a/drivers/usb/input/usbtouchscreen.c
++++ b/drivers/usb/input/usbtouchscreen.c
+@@ -2,9 +2,12 @@
+ * usbtouchscreen.c
+ * Driver for USB Touchscreens, supporting those devices:
+ * - eGalax Touchkit
+- * - 3M/Microtouch
++ * includes eTurboTouch CT-410/510/700
++ * - 3M/Microtouch EX II series
+ * - ITM
+ * - PanJit TouchSet
++ * - eTurboTouch
++ * - Gunze AHL61
+ *
+ * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz at gmx.ch>
+ * Copyright (C) by Todd E. Johnson (mtouchusb.c)
+@@ -32,7 +35,6 @@
+
+ //#define DEBUG
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/input.h>
+@@ -42,7 +44,7 @@
+ #include <linux/usb/input.h>
+
+
+-#define DRIVER_VERSION "v0.3"
++#define DRIVER_VERSION "v0.4"
+ #define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz at gmx.ch>"
+ #define DRIVER_DESC "USB Touchscreen Driver"
+
+@@ -59,7 +61,8 @@ struct usbtouch_device_info {
+ int rept_size;
+ int flags;
+
+- void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len);
++ void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
++ int (*get_pkt_len) (unsigned char *pkt, int len);
+ int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press);
+ int (*init) (struct usbtouch_usb *usbtouch);
+ };
+@@ -81,8 +84,15 @@ struct usbtouch_usb {
+ char phys[64];
+ };
+
+-static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
+- struct pt_regs *regs, unsigned char *pkt, int len);
++
++#if defined(CONFIG_USB_TOUCHSCREEN_EGALAX) || defined(CONFIG_USB_TOUCHSCREEN_ETURBO)
++#define MULTI_PACKET
++#endif
++
++#ifdef MULTI_PACKET
++static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
++ unsigned char *pkt, int len);
++#endif
+
+ /* device types */
+ enum {
+@@ -91,14 +101,19 @@ enum {
+ DEVTYPE_PANJIT,
+ DEVTYPE_3M,
+ DEVTYPE_ITM,
++ DEVTYPE_ETURBO,
++ DEVTYPE_GUNZE,
+ };
+
+ static struct usb_device_id usbtouch_devices[] = {
+ #ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
+ {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
++ {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
++ {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
++ {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
+ #endif
+
+ #ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
+@@ -116,6 +131,14 @@ static struct usb_device_id usbtouch_dev
+ {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
+ #endif
+
++#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
++ {USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
++#endif
++
++#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
++ {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
++#endif
++
+ {}
+ };
+
+@@ -140,82 +163,23 @@ static int egalax_read_data(unsigned cha
+ *touch = pkt[0] & 0x01;
+
+ return 1;
+-
+ }
+
+-static int egalax_get_pkt_len(unsigned char *buf)
++static int egalax_get_pkt_len(unsigned char *buf, int len)
+ {
+ switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
+ case EGALAX_PKT_TYPE_REPT:
+ return 5;
+
+ case EGALAX_PKT_TYPE_DIAG:
++ if (len < 2)
++ return -1;
++
+ return buf[1] + 2;
+ }
+
+ return 0;
+ }
+-
+-static void egalax_process(struct usbtouch_usb *usbtouch, struct pt_regs *regs,
+- unsigned char *pkt, int len)
+-{
+- unsigned char *buffer;
+- int pkt_len, buf_len, pos;
+-
+- /* if the buffer contains data, append */
+- if (unlikely(usbtouch->buf_len)) {
+- int tmp;
+-
+- /* if only 1 byte in buffer, add another one to get length */
+- if (usbtouch->buf_len == 1)
+- usbtouch->buffer[1] = pkt[0];
+-
+- pkt_len = egalax_get_pkt_len(usbtouch->buffer);
+-
+- /* unknown packet: drop everything */
+- if (!pkt_len)
+- return;
+-
+- /* append, process */
+- tmp = pkt_len - usbtouch->buf_len;
+- memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
+- usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len);
+-
+- buffer = pkt + tmp;
+- buf_len = len - tmp;
+- } else {
+- buffer = pkt;
+- buf_len = len;
+- }
+-
+- /* only one byte left in buffer */
+- if (unlikely(buf_len == 1)) {
+- usbtouch->buffer[0] = buffer[0];
+- usbtouch->buf_len = 1;
+- return;
+- }
+-
+- /* loop over the buffer */
+- pos = 0;
+- while (pos < buf_len) {
+- /* get packet len */
+- pkt_len = egalax_get_pkt_len(buffer + pos);
+-
+- /* unknown packet: drop everything */
+- if (unlikely(!pkt_len))
+- return;
+-
+- /* full packet: process */
+- if (likely(pkt_len <= buf_len)) {
+- usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len);
+- } else {
+- /* incomplete packet: save in buffer */
+- memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
+- usbtouch->buf_len = buf_len - pos;
+- }
+- pos += pkt_len;
+- }
+-}
+ #endif
+
+
+@@ -254,7 +218,7 @@ static int mtouch_read_data(unsigned cha
+
+ static int mtouch_init(struct usbtouch_usb *usbtouch)
+ {
+- int ret;
++ int ret, i;
+
+ ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ MTOUCHUSB_RESET,
+@@ -264,15 +228,20 @@ static int mtouch_init(struct usbtouch_u
+ __FUNCTION__, ret);
+ if (ret < 0)
+ return ret;
+-
+- ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->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__, ret);
+- if (ret < 0)
+- return ret;
++ msleep(150);
++
++ for (i = 0; i < 3; i++) {
++ ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->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__, ret);
++ if (ret >= 0)
++ break;
++ if (ret != -EPIPE)
++ return ret;
++ }
+
+ return 0;
+ }
+@@ -287,15 +256,63 @@ static int itm_read_data(unsigned char *
+ {
+ *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
+ *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
+- *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F);
++ *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
+ *touch = ~pkt[7] & 0x20;
+
++ return *touch;
++}
++#endif
++
++
++/*****************************************************************************
++ * eTurboTouch part
++ */
++#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
++static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
++{
++ unsigned int shift;
++
++ /* packets should start with sync */
++ if (!(pkt[0] & 0x80))
++ return 0;
++
++ shift = (6 - (pkt[0] & 0x03));
++ *x = ((pkt[3] << 7) | pkt[4]) >> shift;
++ *y = ((pkt[1] << 7) | pkt[2]) >> shift;
++ *touch = (pkt[0] & 0x10) ? 1 : 0;
++
+ return 1;
+ }
++
++static int eturbo_get_pkt_len(unsigned char *buf, int len)
++{
++ if (buf[0] & 0x80)
++ return 5;
++ if (buf[0] == 0x01)
++ return 3;
++ return 0;
++}
+ #endif
+
+
+ /*****************************************************************************
++ * Gunze part
++ */
++#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
++static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
++{
++ if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
++ return 0;
++
++ *x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
++ *y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
++ *touch = pkt[0] & 0x20;
++
++ return 1;
++}
++#endif
++
++/*****************************************************************************
+ * the different device descriptors
+ */
+ static struct usbtouch_device_info usbtouch_dev_info[] = {
+@@ -307,7 +324,8 @@ static struct usbtouch_device_info usbto
+ .max_yc = 0x07ff,
+ .rept_size = 16,
+ .flags = USBTOUCH_FLG_BUFFER,
+- .process_pkt = egalax_process,
++ .process_pkt = usbtouch_process_multi,
++ .get_pkt_len = egalax_get_pkt_len,
+ .read_data = egalax_read_data,
+ },
+ #endif
+@@ -346,6 +364,31 @@ static struct usbtouch_device_info usbto
+ .read_data = itm_read_data,
+ },
+ #endif
++
++#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
++ [DEVTYPE_ETURBO] = {
++ .min_xc = 0x0,
++ .max_xc = 0x07ff,
++ .min_yc = 0x0,
++ .max_yc = 0x07ff,
++ .rept_size = 8,
++ .flags = USBTOUCH_FLG_BUFFER,
++ .process_pkt = usbtouch_process_multi,
++ .get_pkt_len = eturbo_get_pkt_len,
++ .read_data = eturbo_read_data,
++ },
++#endif
++
++#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
++ [DEVTYPE_GUNZE] = {
++ .min_xc = 0x0,
++ .max_xc = 0x0fff,
++ .min_yc = 0x0,
++ .max_yc = 0x0fff,
++ .rept_size = 4,
++ .read_data = gunze_read_data,
++ },
++#endif
+ };
+
+
+@@ -353,7 +396,7 @@ static struct usbtouch_device_info usbto
+ * Generic Part
+ */
+ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
+- struct pt_regs *regs, unsigned char *pkt, int len)
++ unsigned char *pkt, int len)
+ {
+ int x, y, touch, press;
+ struct usbtouch_device_info *type = usbtouch->type;
+@@ -361,7 +404,6 @@ static void usbtouch_process_pkt(struct
+ if (!type->read_data(pkt, &x, &y, &touch, &press))
+ return;
+
+- input_regs(usbtouch->input, regs);
+ input_report_key(usbtouch->input, BTN_TOUCH, touch);
+
+ if (swap_xy) {
+@@ -377,7 +419,83 @@ static void usbtouch_process_pkt(struct
+ }
+
+
+-static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
++#ifdef MULTI_PACKET
++static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
++ unsigned char *pkt, int len)
++{
++ unsigned char *buffer;
++ int pkt_len, pos, buf_len, tmp;
++
++ /* process buffer */
++ if (unlikely(usbtouch->buf_len)) {
++ /* try to get size */
++ pkt_len = usbtouch->type->get_pkt_len(
++ usbtouch->buffer, usbtouch->buf_len);
++
++ /* drop? */
++ if (unlikely(!pkt_len))
++ goto out_flush_buf;
++
++ /* need to append -pkt_len bytes before able to get size */
++ if (unlikely(pkt_len < 0)) {
++ int append = -pkt_len;
++ if (unlikely(append > len))
++ append = len;
++ if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
++ goto out_flush_buf;
++ memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
++ usbtouch->buf_len += append;
++
++ pkt_len = usbtouch->type->get_pkt_len(
++ usbtouch->buffer, usbtouch->buf_len);
++ if (pkt_len < 0)
++ return;
++ }
++
++ /* append */
++ tmp = pkt_len - usbtouch->buf_len;
++ if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
++ goto out_flush_buf;
++ memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
++ usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
++
++ buffer = pkt + tmp;
++ buf_len = len - tmp;
++ } else {
++ buffer = pkt;
++ buf_len = len;
++ }
++
++ /* loop over the received packet, process */
++ pos = 0;
++ while (pos < buf_len) {
++ /* get packet len */
++ pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len);
++
++ /* unknown packet: drop everything */
++ if (unlikely(!pkt_len))
++ goto out_flush_buf;
++
++ /* full packet: process */
++ if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
++ usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
++ } else {
++ /* incomplete packet: save in buffer */
++ memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
++ usbtouch->buf_len = buf_len - pos;
++ return;
++ }
++ pos += pkt_len;
++ }
++
++out_flush_buf:
++ usbtouch->buf_len = 0;
++ return;
++}
++#endif
++
++
++static void usbtouch_irq(struct urb *urb)
+ {
+ struct usbtouch_usb *usbtouch = urb->context;
+ int retval;
+@@ -386,7 +504,7 @@ static void usbtouch_irq(struct urb *urb
+ case 0:
+ /* success */
+ break;
+- case -ETIMEDOUT:
++ case -ETIME:
+ /* this urb is timing out */
+ dbg("%s - urb timed out - was the device unplugged?",
+ __FUNCTION__);
+@@ -404,7 +522,7 @@ static void usbtouch_irq(struct urb *urb
+ goto exit;
+ }
+
+- usbtouch->type->process_pkt(usbtouch, regs, usbtouch->data, urb->actual_length);
++ usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
+
+ exit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+@@ -452,7 +570,7 @@ static int usbtouch_probe(struct usb_int
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usbtouch_device_info *type;
+- int err;
++ int err = -ENOMEM;
+
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+@@ -522,10 +640,11 @@ static int usbtouch_probe(struct usb_int
+ type->max_press, 0, 0);
+
+ usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
+- usb_rcvintpipe(usbtouch->udev, 0x81),
++ usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
+ usbtouch->data, type->rept_size,
+ usbtouch_irq, usbtouch, endpoint->bInterval);
+
++ usbtouch->irq->dev = usbtouch->udev;
+ usbtouch->irq->transfer_dma = usbtouch->data_dma;
+ usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+@@ -553,7 +672,7 @@ out_free_buffers:
+ out_free:
+ input_free_device(input_dev);
+ kfree(usbtouch);
+- return -ENOMEM;
++ return err;
+ }
+
+ static void usbtouch_disconnect(struct usb_interface *intf)
+diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
+deleted file mode 100644
+index 369461a..0000000
+--- a/drivers/usb/input/wacom.c
++++ /dev/null
+@@ -1,1003 +0,0 @@
+-/*
+- * USB Wacom Graphire and Wacom Intuos tablet support
+- *
+- * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech at ucw.cz>
+- * Copyright (c) 2000 Andreas Bach Aaen <abach at stofanet.dk>
+- * Copyright (c) 2000 Clifford Wolf <clifford at clifford.at>
+- * Copyright (c) 2000 Sam Mosel <sam.mosel at computer.org>
+- * Copyright (c) 2000 James E. Blair <corvus at gnu.org>
+- * Copyright (c) 2000 Daniel Egger <egger at suse.de>
+- * Copyright (c) 2001 Frederic Lepied <flepied at mandrakesoft.com>
+- * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris at mech.kuleuven.ac.be>
+- * Copyright (c) 2002-2006 Ping Cheng <pingc at wacom.com>
+- *
+- * ChangeLog:
+- * v0.1 (vp) - Initial release
+- * v0.2 (aba) - Support for all buttons / combinations
+- * v0.3 (vp) - Support for Intuos added
+- * v0.4 (sm) - Support for more Intuos models, menustrip
+- * relative mode, proximity.
+- * v0.5 (vp) - Big cleanup, nifty features removed,
+- * 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
+- * v1.11 (vp) - Add URB ->dev setting for new kernels
+- * v1.11 (jb) - Add support for the 4D Mouse & Lens
+- * v1.12 (de) - Add support for two more inking pen IDs
+- * v1.14 (vp) - Use new USB device id probing scheme.
+- * Fix Wacom Graphire mouse wheel
+- * v1.18 (vp) - Fix mouse wheel direction
+- * Make mouse relative
+- * v1.20 (fl) - Report tool id for Intuos devices
+- * - Multi tools support
+- * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
+- * - Add PL models support
+- * - Fix Wacom Graphire mouse wheel again
+- * v1.21 (vp) - Removed protocol descriptions
+- * - Added MISC_SERIAL for tool serial numbers
+- * (gb) - Identify version on module load.
+- * v1.21.1 (fl) - added Graphire2 support
+- * v1.21.2 (fl) - added Intuos2 support
+- * - added all the PL ids
+- * v1.21.3 (fl) - added another eraser id from Neil Okamoto
+- * - added smooth filter for Graphire from Peri Hankey
+- * - added PenPartner support from Olaf van Es
+- * - new tool ids from Ole Martin Bjoerndalen
+- * v1.29 (pc) - Add support for more tablets
+- * - Fix pressure reporting
+- * v1.30 (vp) - Merge 2.4 and 2.5 drivers
+- * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
+- * - 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
+- * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
+- * - Report Device IDs
+- * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
+- * - Minor data report fix
+- */
+-
+-/*
+- * 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/slab.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/usb/input.h>
+-#include <asm/unaligned.h>
+-
+-/*
+- * Version Information
+- */
+-#define DRIVER_VERSION "v1.45"
+-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech at ucw.cz>"
+-#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
+-#define DRIVER_LICENSE "GPL"
+-
+-MODULE_AUTHOR(DRIVER_AUTHOR);
+-MODULE_DESCRIPTION(DRIVER_DESC);
+-MODULE_LICENSE(DRIVER_LICENSE);
+-
+-#define USB_VENDOR_ID_WACOM 0x056a
+-#define STYLUS_DEVICE_ID 0x02
+-#define CURSOR_DEVICE_ID 0x06
+-#define ERASER_DEVICE_ID 0x0A
+-
+-enum {
+- PENPARTNER = 0,
+- GRAPHIRE,
+- WACOM_G4,
+- PL,
+- INTUOS,
+- INTUOS3,
+- INTUOS312,
+- INTUOS319,
+- CINTIQ,
+- MAX_TYPE
+-};
+-
+-struct wacom_features {
+- char *name;
+- int pktlen;
+- int x_max;
+- int y_max;
+- int pressure_max;
+- int distance_max;
+- int type;
+- usb_complete_t irq;
+-};
+-
+-struct wacom {
+- signed char *data;
+- dma_addr_t data_dma;
+- struct input_dev *dev;
+- struct usb_device *usbdev;
+- struct urb *irq;
+- struct wacom_features *features;
+- int tool[2];
+- int id[2];
+- __u32 serial[2];
+- char phys[32];
+-};
+-
+-#define USB_REQ_GET_REPORT 0x01
+-#define USB_REQ_SET_REPORT 0x09
+-
+-static int usb_get_report(struct usb_interface *intf, unsigned char type,
+- unsigned char id, void *buf, int size)
+-{
+- return usb_control_msg(interface_to_usbdev(intf),
+- usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
+- USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+- (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+- buf, size, 100);
+-}
+-
+-static int usb_set_report(struct usb_interface *intf, unsigned char type,
+- unsigned char id, void *buf, int size)
+-{
+- return usb_control_msg(interface_to_usbdev(intf),
+- usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+- USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+- (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+- buf, size, 1000);
+-}
+-
+-static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
+-{
+- struct wacom *wacom = urb->context;
+- unsigned char *data = wacom->data;
+- struct input_dev *dev = wacom->dev;
+- int prox, pressure, id;
+- int 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;
+- }
+-
+- if (data[0] != 2) {
+- dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+- goto exit;
+- }
+-
+- prox = data[1] & 0x40;
+-
+- input_regs(dev, regs);
+-
+- id = ERASER_DEVICE_ID;
+- if (prox) {
+-
+- pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+- if (wacom->features->pressure_max > 255)
+- pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+- pressure += (wacom->features->pressure_max + 1) / 2;
+-
+- /*
+- * if going from out of proximity into proximity select between the eraser
+- * and the pen based on the state of the stylus2 button, choose eraser if
+- * pressed else choose pen. if not a proximity change from out to in, send
+- * an out of proximity for previous tool then a in for new tool.
+- */
+- if (!wacom->tool[0]) {
+- /* Eraser bit set for DTF */
+- if (data[1] & 0x10)
+- wacom->tool[1] = BTN_TOOL_RUBBER;
+- else
+- /* Going into proximity select tool */
+- wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+- } else {
+- /* was entered with stylus2 pressed */
+- if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
+- /* report out proximity for previous tool */
+- input_report_key(dev, wacom->tool[1], 0);
+- input_sync(dev);
+- wacom->tool[1] = BTN_TOOL_PEN;
+- goto exit;
+- }
+- }
+- if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+- /* Unknown tool selected default to pen tool */
+- wacom->tool[1] = BTN_TOOL_PEN;
+- id = STYLUS_DEVICE_ID;
+- }
+- input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
+- input_report_abs(dev, ABS_MISC, id); /* report tool id */
+- 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 {
+- /* report proximity-out of a (valid) tool */
+- if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+- /* Unknown tool selected default to pen tool */
+- wacom->tool[1] = BTN_TOOL_PEN;
+- }
+- input_report_key(dev, wacom->tool[1], prox);
+- }
+-
+- wacom->tool[0] = prox; /* Save proximity state */
+- 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_ptu_irq(struct urb *urb, struct pt_regs *regs)
+-{
+- struct wacom *wacom = urb->context;
+- unsigned char *data = wacom->data;
+- struct input_dev *dev = wacom->dev;
+- int retval, id;
+-
+- 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;
+- }
+-
+- 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) {
+- input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
+- input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
+- id = ERASER_DEVICE_ID;
+- } else {
+- input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
+- input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
+- id = STYLUS_DEVICE_ID;
+- }
+- input_report_abs(dev, ABS_MISC, id); /* report tool id */
+- input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2]));
+- input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4]));
+- input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
+- input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
+- input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
+-
+- 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_penpartner_irq(struct urb *urb, struct pt_regs *regs)
+-{
+- struct wacom *wacom = urb->context;
+- unsigned char *data = wacom->data;
+- struct input_dev *dev = wacom->dev;
+- int 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;
+- }
+-
+- if (data[0] != 2) {
+- printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+- goto exit;
+- }
+-
+- input_regs(dev, regs);
+- input_report_key(dev, BTN_TOOL_PEN, 1);
+- input_report_abs(dev, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
+- input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1]));
+- input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3]));
+- input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
+- input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
+- input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
+- 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_graphire_irq(struct urb *urb, struct pt_regs *regs)
+-{
+- struct wacom *wacom = urb->context;
+- unsigned char *data = wacom->data;
+- struct input_dev *dev = wacom->dev;
+- int x, y, id, rw;
+- int 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;
+- }
+-
+- if (data[0] == 99) return; /* for Volito tablets */
+-
+- if (data[0] != 2) {
+- dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+- goto exit;
+- }
+-
+- input_regs(dev, regs);
+-
+- id = STYLUS_DEVICE_ID;
+- if (data[1] & 0x10) { /* in prox */
+-
+- switch ((data[1] >> 5) & 3) {
+-
+- case 0: /* Pen */
+- wacom->tool[0] = BTN_TOOL_PEN;
+- break;
+-
+- case 1: /* Rubber */
+- wacom->tool[0] = BTN_TOOL_RUBBER;
+- id = ERASER_DEVICE_ID;
+- break;
+-
+- case 2: /* Mouse with wheel */
+- input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
+- if (wacom->features->type == WACOM_G4) {
+- rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
+- input_report_rel(dev, REL_WHEEL, -rw);
+- } else
+- input_report_rel(dev, REL_WHEEL, -(signed char) data[6]);
+- /* fall through */
+-
+- case 3: /* Mouse without wheel */
+- wacom->tool[0] = BTN_TOOL_MOUSE;
+- id = CURSOR_DEVICE_ID;
+- input_report_key(dev, BTN_LEFT, data[1] & 0x01);
+- input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
+- if (wacom->features->type == WACOM_G4)
+- input_report_abs(dev, ABS_DISTANCE, data[6]);
+- else
+- input_report_abs(dev, ABS_DISTANCE, data[7]);
+- break;
+- }
+- }
+-
+- if (data[1] & 0x90) {
+- x = le16_to_cpu(*(__le16 *) &data[2]);
+- y = le16_to_cpu(*(__le16 *) &data[4]);
+- 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, data[6] | ((data[7] & 0x01) << 8));
+- 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);
+- }
+- }
+-
+- if (data[1] & 0x10)
+- input_report_abs(dev, ABS_MISC, id); /* report tool id */
+- else
+- input_report_abs(dev, ABS_MISC, 0); /* reset tool id */
+- input_report_key(dev, wacom->tool[0], data[1] & 0x10);
+- input_sync(dev);
+-
+- /* send pad data */
+- if (wacom->features->type == WACOM_G4) {
+- if ((wacom->serial[1] & 0xc0) != (data[7] & 0xf8)) {
+- wacom->id[1] = 1;
+- wacom->serial[1] = (data[7] & 0xf8);
+- input_report_key(dev, BTN_0, (data[7] & 0x40));
+- input_report_key(dev, BTN_4, (data[7] & 0x80));
+- rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
+- input_report_rel(dev, REL_WHEEL, rw);
+- input_report_key(dev, BTN_TOOL_FINGER, 0xf0);
+- input_event(dev, EV_MSC, MSC_SERIAL, 0xf0);
+- } else if (wacom->id[1]) {
+- wacom->id[1] = 0;
+- input_report_key(dev, BTN_TOOL_FINGER, 0);
+- input_event(dev, EV_MSC, MSC_SERIAL, 0xf0);
+- }
+- 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 int wacom_intuos_inout(struct urb *urb)
+-{
+- struct wacom *wacom = urb->context;
+- unsigned char *data = wacom->data;
+- struct input_dev *dev = wacom->dev;
+- int idx;
+-
+- /* tool number */
+- idx = data[1] & 0x01;
+-
+- /* Enter report */
+- if ((data[1] & 0xfc) == 0xc0) {
+- /* serial number of the tool */
+- wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+- (data[4] << 20) + (data[5] << 12) +
+- (data[6] << 4) + (data[7] >> 4);
+-
+- wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
+- switch (wacom->id[idx]) {
+- case 0x812: /* Inking pen */
+- case 0x801: /* Intuos3 Inking pen */
+- case 0x012:
+- wacom->tool[idx] = BTN_TOOL_PENCIL;
+- break;
+- case 0x822: /* Pen */
+- case 0x842:
+- case 0x852:
+- case 0x823: /* Intuos3 Grip Pen */
+- case 0x813: /* Intuos3 Classic Pen */
+- case 0x885: /* Intuos3 Marker Pen */
+- case 0x022:
+- wacom->tool[idx] = BTN_TOOL_PEN;
+- break;
+- case 0x832: /* Stroke pen */
+- case 0x032:
+- wacom->tool[idx] = BTN_TOOL_BRUSH;
+- break;
+- case 0x007: /* Mouse 4D and 2D */
+- case 0x09c:
+- case 0x094:
+- case 0x017: /* Intuos3 2D Mouse */
+- wacom->tool[idx] = BTN_TOOL_MOUSE;
+- break;
+- case 0x096: /* Lens cursor */
+- case 0x097: /* Intuos3 Lens cursor */
+- wacom->tool[idx] = BTN_TOOL_LENS;
+- break;
+- case 0x82a: /* Eraser */
+- case 0x85a:
+- case 0x91a:
+- case 0xd1a:
+- case 0x0fa:
+- case 0x82b: /* Intuos3 Grip Pen Eraser */
+- case 0x81b: /* Intuos3 Classic Pen Eraser */
+- case 0x91b: /* Intuos3 Airbrush Eraser */
+- wacom->tool[idx] = BTN_TOOL_RUBBER;
+- break;
+- case 0xd12:
+- case 0x912:
+- case 0x112:
+- case 0x913: /* Intuos3 Airbrush */
+- wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+- break;
+- default: /* Unknown tool */
+- wacom->tool[idx] = BTN_TOOL_PEN;
+- }
+- if(!((wacom->tool[idx] == BTN_TOOL_LENS) &&
+- ((wacom->features->type == INTUOS312)
+- || (wacom->features->type == INTUOS319)))) {
+- input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */
+- input_report_key(dev, wacom->tool[idx], 1);
+- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+- input_sync(dev);
+- }
+- return 1;
+- }
+-
+- /* Exit report */
+- if ((data[1] & 0xfe) == 0x80) {
+- input_report_key(dev, wacom->tool[idx], 0);
+- input_report_abs(dev, ABS_MISC, 0); /* reset tool id */
+- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+- input_sync(dev);
+- return 1;
+- }
+-
+- if((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS312)
+- || (wacom->features->type == INTUOS319)))
+- return 1;
+- else
+- return 0;
+-}
+-
+-static void wacom_intuos_general(struct urb *urb)
+-{
+- struct wacom *wacom = urb->context;
+- unsigned char *data = wacom->data;
+- struct input_dev *dev = wacom->dev;
+- unsigned int t;
+-
+- /* general pen packet */
+- 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));
+- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+- input_report_key(dev, BTN_STYLUS, data[1] & 2);
+- input_report_key(dev, BTN_STYLUS2, data[1] & 4);
+- input_report_key(dev, BTN_TOUCH, t > 10);
+- }
+-
+- /* airbrush second packet */
+- if ((data[1] & 0xbc) == 0xb4) {
+- input_report_abs(dev, ABS_WHEEL,
+- (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);
+- }
+- return;
+-}
+-
+-static void wacom_intuos_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;
+- int 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;
+- }
+-
+- 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;
+- }
+-
+- input_regs(dev, regs);
+-
+- /* tool number */
+- idx = data[1] & 0x01;
+-
+- /* pad packets. Works as a second tool and is always in prox */
+- if (data[0] == 12) {
+- /* initiate the pad as a device */
+- if (wacom->tool[1] != BTN_TOOL_FINGER)
+- wacom->tool[1] = BTN_TOOL_FINGER;
+-
+- input_report_key(dev, BTN_0, (data[5] & 0x01));
+- input_report_key(dev, BTN_1, (data[5] & 0x02));
+- input_report_key(dev, BTN_2, (data[5] & 0x04));
+- input_report_key(dev, BTN_3, (data[5] & 0x08));
+- input_report_key(dev, BTN_4, (data[6] & 0x01));
+- input_report_key(dev, BTN_5, (data[6] & 0x02));
+- input_report_key(dev, BTN_6, (data[6] & 0x04));
+- input_report_key(dev, BTN_7, (data[6] & 0x08));
+- input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+- input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+-
+- if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2])
+- input_report_key(dev, wacom->tool[1], 1);
+- else
+- input_report_key(dev, wacom->tool[1], 0);
+- input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+- input_sync(dev);
+- goto exit;
+- }
+-
+- /* process in/out prox events */
+- if (wacom_intuos_inout(urb))
+- goto exit;
+-
+- /* Cintiq doesn't send data when RDY bit isn't set */
+- if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+- goto exit;
+-
+- 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);
+-
+- /* 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);
+- }
+-
+- } 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_rel(dev, REL_WHEEL, (data[8] & 0x01)
+- - ((data[8] & 0x02) >> 1));
+-
+- /* 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);
+- }
+- }
+-
+- input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */
+- 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 struct wacom_features wacom_features[] = {
+- { "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 Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_graphire_irq },
+- { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_graphire_irq },
+- { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
+- { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_graphire_irq },
+- { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
+- { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_graphire_irq },
+- { "Wacom PenPartner2", 8, 3250, 2320, 255, 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 PL700", 8, 6758, 5406, 511, 32, PL, wacom_pl_irq },
+- { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq },
+- { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq },
+- { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq },
+- { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_pl_irq },
+- { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_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 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 Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS312, wacom_intuos_irq },
+- { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS319, wacom_intuos_irq },
+- { "Wacom Intuos3 6x11", 10, 54204, 31750, 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[] = {
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC3) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
+- { 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, 0xB3) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
+- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
+- { }
+-};
+-
+-MODULE_DEVICE_TABLE(usb, wacom_ids);
+-
+-static int wacom_open(struct input_dev *dev)
+-{
+- struct wacom *wacom = dev->private;
+-
+- wacom->irq->dev = wacom->usbdev;
+- if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+- return -EIO;
+-
+- return 0;
+-}
+-
+-static void wacom_close(struct input_dev *dev)
+-{
+- struct wacom *wacom = dev->private;
+-
+- usb_kill_urb(wacom->irq);
+-}
+-
+-static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
+-{
+- struct usb_device *dev = interface_to_usbdev(intf);
+- struct usb_endpoint_descriptor *endpoint;
+- struct wacom *wacom;
+- struct input_dev *input_dev;
+- char rep_data[2], limit = 0;
+-
+- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+- input_dev = input_allocate_device();
+- if (!wacom || !input_dev)
+- goto fail1;
+-
+- wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
+- if (!wacom->data)
+- goto fail1;
+-
+- wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
+- if (!wacom->irq)
+- goto fail2;
+-
+- wacom->usbdev = dev;
+- wacom->dev = input_dev;
+- usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
+- strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
+-
+- wacom->features = wacom_features + (id - wacom_ids);
+- if (wacom->features->pktlen > 10)
+- BUG();
+-
+- input_dev->name = wacom->features->name;
+- usb_to_input_id(dev, &input_dev->id);
+-
+- input_dev->cdev.dev = &intf->dev;
+- input_dev->private = wacom;
+- input_dev->open = wacom_open;
+- input_dev->close = wacom_close;
+-
+- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
+- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
+- input_set_abs_params(input_dev, ABS_X, 0, wacom->features->x_max, 4, 0);
+- input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0);
+- input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0);
+- input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
+-
+- switch (wacom->features->type) {
+- case WACOM_G4:
+- input_dev->evbit[0] |= BIT(EV_MSC);
+- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+- input_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);
+- /* fall through */
+-
+- case GRAPHIRE:
+- input_dev->evbit[0] |= BIT(EV_REL);
+- input_dev->relbit[0] |= BIT(REL_WHEEL);
+- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0);
+- break;
+-
+- case INTUOS3:
+- case INTUOS312:
+- case INTUOS319:
+- case CINTIQ:
+- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+- input_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);
+- input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
+- input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
+- /* fall through */
+-
+- case INTUOS:
+- input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
+- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+- input_dev->relbit[0] |= BIT(REL_WHEEL);
+- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+- input_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);
+- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0);
+- input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
+- input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
+- input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+- input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
+- input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
+- break;
+-
+- case PL:
+- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+- break;
+- }
+-
+- endpoint = &intf->cur_altsetting->endpoint[0].desc;
+-
+- if (wacom->features->pktlen > 10)
+- BUG();
+-
+- usb_fill_int_urb(wacom->irq, dev,
+- usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+- wacom->data, wacom->features->pktlen,
+- wacom->features->irq, wacom, endpoint->bInterval);
+- wacom->irq->transfer_dma = wacom->data_dma;
+- wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+-
+- input_register_device(wacom->dev);
+-
+- /* Ask the tablet to report tablet data. Repeat until it succeeds */
+- do {
+- rep_data[0] = 2;
+- rep_data[1] = 2;
+- usb_set_report(intf, 3, 2, rep_data, 2);
+- usb_get_report(intf, 3, 2, rep_data, 2);
+- } while (rep_data[1] != 2 && limit++ < 5);
+-
+- usb_set_intfdata(intf, wacom);
+- return 0;
+-
+-fail2: usb_buffer_free(dev, 10, wacom->data, wacom->data_dma);
+-fail1: input_free_device(input_dev);
+- kfree(wacom);
+- return -ENOMEM;
+-}
+-
+-static void wacom_disconnect(struct usb_interface *intf)
+-{
+- struct wacom *wacom = usb_get_intfdata (intf);
+-
+- usb_set_intfdata(intf, NULL);
+- if (wacom) {
+- usb_kill_urb(wacom->irq);
+- input_unregister_device(wacom->dev);
+- usb_free_urb(wacom->irq);
+- usb_buffer_free(interface_to_usbdev(intf), 10, wacom->data, wacom->data_dma);
+- kfree(wacom);
+- }
+-}
+-
+-static struct usb_driver wacom_driver = {
+- .name = "wacom",
+- .probe = wacom_probe,
+- .disconnect = wacom_disconnect,
+- .id_table = wacom_ids,
+-};
+-
+-static int __init wacom_init(void)
+-{
+- int result = usb_register(&wacom_driver);
+- if (result == 0)
+- info(DRIVER_VERSION ":" DRIVER_DESC);
+- return result;
+-}
+-
+-static void __exit wacom_exit(void)
+-{
+- usb_deregister(&wacom_driver);
+-}
+-
+-module_init(wacom_init);
+-module_exit(wacom_exit);
+diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h
+new file mode 100644
+index 0000000..1cf08f0
+--- /dev/null
++++ b/drivers/usb/input/wacom.h
+@@ -0,0 +1,132 @@
++/*
++ * drivers/usb/input/wacom.h
++ *
++ * USB Wacom Graphire and Wacom Intuos tablet support
++ *
++ * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech at ucw.cz>
++ * Copyright (c) 2000 Andreas Bach Aaen <abach at stofanet.dk>
++ * Copyright (c) 2000 Clifford Wolf <clifford at clifford.at>
++ * Copyright (c) 2000 Sam Mosel <sam.mosel at computer.org>
++ * Copyright (c) 2000 James E. Blair <corvus at gnu.org>
++ * Copyright (c) 2000 Daniel Egger <egger at suse.de>
++ * Copyright (c) 2001 Frederic Lepied <flepied at mandrakesoft.com>
++ * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris at mech.kuleuven.ac.be>
++ * Copyright (c) 2002-2006 Ping Cheng <pingc at wacom.com>
++ *
++ * ChangeLog:
++ * v0.1 (vp) - Initial release
++ * v0.2 (aba) - Support for all buttons / combinations
++ * v0.3 (vp) - Support for Intuos added
++ * v0.4 (sm) - Support for more Intuos models, menustrip
++ * relative mode, proximity.
++ * v0.5 (vp) - Big cleanup, nifty features removed,
++ * 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
++ * v1.11 (vp) - Add URB ->dev setting for new kernels
++ * v1.11 (jb) - Add support for the 4D Mouse & Lens
++ * v1.12 (de) - Add support for two more inking pen IDs
++ * v1.14 (vp) - Use new USB device id probing scheme.
++ * Fix Wacom Graphire mouse wheel
++ * v1.18 (vp) - Fix mouse wheel direction
++ * Make mouse relative
++ * v1.20 (fl) - Report tool id for Intuos devices
++ * - Multi tools support
++ * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
++ * - Add PL models support
++ * - Fix Wacom Graphire mouse wheel again
++ * v1.21 (vp) - Removed protocol descriptions
++ * - Added MISC_SERIAL for tool serial numbers
++ * (gb) - Identify version on module load.
++ * v1.21.1 (fl) - added Graphire2 support
++ * v1.21.2 (fl) - added Intuos2 support
++ * - added all the PL ids
++ * v1.21.3 (fl) - added another eraser id from Neil Okamoto
++ * - added smooth filter for Graphire from Peri Hankey
++ * - added PenPartner support from Olaf van Es
++ * - new tool ids from Ole Martin Bjoerndalen
++ * v1.29 (pc) - Add support for more tablets
++ * - Fix pressure reporting
++ * v1.30 (vp) - Merge 2.4 and 2.5 drivers
++ * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
++ * - 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
++ * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
++ * - Report Device IDs
++ * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
++ * - Minor data report fix
++ * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
++ * - where wacom_sys.c deals with system specific code,
++ * - and wacom_wac.c deals with Wacom specific code
++ * - Support Intuos3 4x6
++ */
++
++/*
++ * 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.
++ */
++#ifndef WACOM_H
++#define WACOM_H
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/usb/input.h>
++#include <asm/unaligned.h>
++
++/*
++ * Version Information
++ */
++#define DRIVER_VERSION "v1.46"
++#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech at ucw.cz>"
++#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
++#define DRIVER_LICENSE "GPL"
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE(DRIVER_LICENSE);
++
++#define USB_VENDOR_ID_WACOM 0x056a
++
++struct wacom {
++ dma_addr_t data_dma;
++ struct input_dev *dev;
++ struct usb_device *usbdev;
++ struct urb *irq;
++ struct wacom_wac * wacom_wac;
++ char phys[32];
++};
++
++struct wacom_combo {
++ struct wacom * wacom;
++ struct urb * urb;
++};
++
++extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
++extern void wacom_sys_irq(struct urb *urb);
++extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
++extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
++extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data);
++extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value);
++extern void wacom_input_sync(void *wcombo);
++extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
++extern __u16 wacom_le16_to_cpu(unsigned char *data);
++extern __u16 wacom_be16_to_cpu(unsigned char *data);
++extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
++extern const struct usb_device_id * get_device_table(void);
++
++#endif
+diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c
+new file mode 100644
+index 0000000..3498b89
+--- /dev/null
++++ b/drivers/usb/input/wacom_sys.c
+@@ -0,0 +1,312 @@
++/*
++ * drivers/usb/input/wacom_sys.c
++ *
++ * USB Wacom Graphire and Wacom Intuos tablet support - system specific code
++ */
++
++/*
++ * 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 "wacom.h"
++#include "wacom_wac.h"
++
++#define USB_REQ_GET_REPORT 0x01
++#define USB_REQ_SET_REPORT 0x09
++
++static int usb_get_report(struct usb_interface *intf, unsigned char type,
++ unsigned char id, void *buf, int size)
++{
++ return usb_control_msg(interface_to_usbdev(intf),
++ usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
++ USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
++ (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
++ buf, size, 100);
++}
++
++static int usb_set_report(struct usb_interface *intf, unsigned char type,
++ unsigned char id, void *buf, int size)
++{
++ return usb_control_msg(interface_to_usbdev(intf),
++ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
++ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
++ (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
++ buf, size, 1000);
++}
++
++static struct input_dev * get_input_dev(struct wacom_combo *wcombo)
++{
++ return wcombo->wacom->dev;
++}
++
++void wacom_sys_irq(struct urb *urb)
++{
++ struct wacom *wacom = urb->context;
++ struct wacom_combo wcombo;
++ int 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;
++ }
++
++ wcombo.wacom = wacom;
++ wcombo.urb = urb;
++
++ if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo))
++ input_sync(get_input_dev(&wcombo));
++
++ exit:
++ retval = usb_submit_urb (urb, GFP_ATOMIC);
++ if (retval)
++ err ("%s - usb_submit_urb failed with result %d",
++ __FUNCTION__, retval);
++}
++
++void wacom_report_key(void *wcombo, unsigned int key_type, int key_data)
++{
++ input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data);
++ return;
++}
++
++void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data)
++{
++ input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data);
++ return;
++}
++
++void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data)
++{
++ input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data);
++ return;
++}
++
++void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value)
++{
++ input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value);
++ return;
++}
++
++__u16 wacom_be16_to_cpu(unsigned char *data)
++{
++ __u16 value;
++ value = be16_to_cpu(*(__be16 *) data);
++ return value;
++}
++
++__u16 wacom_le16_to_cpu(unsigned char *data)
++{
++ __u16 value;
++ value = le16_to_cpu(*(__le16 *) data);
++ return value;
++}
++
++void wacom_input_sync(void *wcombo)
++{
++ input_sync(get_input_dev((struct wacom_combo *)wcombo));
++ return;
++}
++
++static int wacom_open(struct input_dev *dev)
++{
++ struct wacom *wacom = dev->private;
++
++ wacom->irq->dev = wacom->usbdev;
++ if (usb_submit_urb(wacom->irq, GFP_KERNEL))
++ return -EIO;
++
++ return 0;
++}
++
++static void wacom_close(struct input_dev *dev)
++{
++ struct wacom *wacom = dev->private;
++
++ usb_kill_urb(wacom->irq);
++}
++
++void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->evbit[0] |= BIT(EV_MSC);
++ input_dev->mscbit[0] |= BIT(MSC_SERIAL);
++ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
++ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
++}
++
++void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->evbit[0] |= BIT(EV_REL);
++ input_dev->relbit[0] |= BIT(REL_WHEEL);
++ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
++ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
++ input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
++}
++
++void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
++ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
++ input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
++}
++
++void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
++ input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
++}
++
++void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
++ input_dev->mscbit[0] |= BIT(MSC_SERIAL);
++ input_dev->relbit[0] |= BIT(REL_WHEEL);
++ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
++ input_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);
++ input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
++ input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
++ input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
++ input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
++ input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
++ input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
++}
++
++void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
++}
++
++void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER);
++}
++
++static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
++{
++ struct usb_device *dev = interface_to_usbdev(intf);
++ struct usb_endpoint_descriptor *endpoint;
++ struct wacom *wacom;
++ struct wacom_wac *wacom_wac;
++ struct input_dev *input_dev;
++ char rep_data[2], limit = 0;
++
++ wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
++ wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!wacom || !input_dev || !wacom_wac)
++ goto fail1;
++
++ wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
++ if (!wacom_wac->data)
++ goto fail1;
++
++ wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
++ if (!wacom->irq)
++ goto fail2;
++
++ wacom->usbdev = dev;
++ wacom->dev = input_dev;
++ usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
++ strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
++
++ wacom_wac->features = get_wacom_feature(id);
++ BUG_ON(wacom_wac->features->pktlen > 10);
++
++ input_dev->name = wacom_wac->features->name;
++ wacom->wacom_wac = wacom_wac;
++ usb_to_input_id(dev, &input_dev->id);
++
++ input_dev->cdev.dev = &intf->dev;
++ input_dev->private = wacom;
++ input_dev->open = wacom_open;
++ input_dev->close = wacom_close;
++
++ input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
++ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
++ input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
++ input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
++ input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
++
++ wacom_init_input_dev(input_dev, wacom_wac);
++
++ endpoint = &intf->cur_altsetting->endpoint[0].desc;
++
++ usb_fill_int_urb(wacom->irq, dev,
++ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
++ wacom_wac->data, wacom_wac->features->pktlen,
++ wacom_sys_irq, wacom, endpoint->bInterval);
++ wacom->irq->transfer_dma = wacom->data_dma;
++ wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++
++ input_register_device(wacom->dev);
++
++ /* Ask the tablet to report tablet data. Repeat until it succeeds */
++ do {
++ rep_data[0] = 2;
++ rep_data[1] = 2;
++ usb_set_report(intf, 3, 2, rep_data, 2);
++ usb_get_report(intf, 3, 2, rep_data, 2);
++ } while (rep_data[1] != 2 && limit++ < 5);
++
++ usb_set_intfdata(intf, wacom);
++ return 0;
++
++fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
++fail1: input_free_device(input_dev);
++ kfree(wacom);
++ kfree(wacom_wac);
++ return -ENOMEM;
++}
++
++static void wacom_disconnect(struct usb_interface *intf)
++{
++ struct wacom *wacom = usb_get_intfdata (intf);
++
++ usb_set_intfdata(intf, NULL);
++ if (wacom) {
++ usb_kill_urb(wacom->irq);
++ input_unregister_device(wacom->dev);
++ usb_free_urb(wacom->irq);
++ usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
++ kfree(wacom->wacom_wac);
++ kfree(wacom);
++ }
++}
++
++static struct usb_driver wacom_driver = {
++ .name = "wacom",
++ .probe = wacom_probe,
++ .disconnect = wacom_disconnect,
++};
++
++static int __init wacom_init(void)
++{
++ int result;
++ wacom_driver.id_table = get_device_table();
++ result = usb_register(&wacom_driver);
++ if (result == 0)
++ info(DRIVER_VERSION ":" DRIVER_DESC);
++ return result;
++}
++
++static void __exit wacom_exit(void)
++{
++ usb_deregister(&wacom_driver);
++}
++
++module_init(wacom_init);
++module_exit(wacom_exit);
+diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
+new file mode 100644
+index 0000000..92726fe
+--- /dev/null
++++ b/drivers/usb/input/wacom_wac.c
+@@ -0,0 +1,648 @@
++/*
++ * drivers/usb/input/wacom_wac.c
++ *
++ * USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
++ *
++ */
++
++/*
++ * 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 "wacom.h"
++#include "wacom_wac.h"
++
++static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++
++ switch (data[0]) {
++ case 1:
++ if (data[5] & 0x80) {
++ wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
++ wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
++ wacom_report_key(wcombo, wacom->tool[0], 1);
++ wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
++ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
++ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
++ wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
++ wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -127));
++ wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
++ } else {
++ wacom_report_key(wcombo, wacom->tool[0], 0);
++ wacom_report_abs(wcombo, ABS_MISC, 0); /* report tool id */
++ wacom_report_abs(wcombo, ABS_PRESSURE, -1);
++ wacom_report_key(wcombo, BTN_TOUCH, 0);
++ }
++ break;
++ case 2:
++ wacom_report_key(wcombo, BTN_TOOL_PEN, 1);
++ wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
++ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
++ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
++ wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
++ wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
++ wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
++ break;
++ default:
++ printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
++ return 0;
++ }
++ return 1;
++}
++
++static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++ int prox, id, pressure;
++
++ if (data[0] != 2) {
++ dbg("wacom_pl_irq: received unknown report #%d", data[0]);
++ return 0;
++ }
++
++ prox = data[1] & 0x40;
++
++ id = ERASER_DEVICE_ID;
++ if (prox) {
++
++ pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
++ if (wacom->features->pressure_max > 255)
++ pressure = (pressure << 1) | ((data[4] >> 6) & 1);
++ pressure += (wacom->features->pressure_max + 1) / 2;
++
++ /*
++ * if going from out of proximity into proximity select between the eraser
++ * and the pen based on the state of the stylus2 button, choose eraser if
++ * pressed else choose pen. if not a proximity change from out to in, send
++ * an out of proximity for previous tool then a in for new tool.
++ */
++ if (!wacom->tool[0]) {
++ /* Eraser bit set for DTF */
++ if (data[1] & 0x10)
++ wacom->tool[1] = BTN_TOOL_RUBBER;
++ else
++ /* Going into proximity select tool */
++ wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
++ } else {
++ /* was entered with stylus2 pressed */
++ if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
++ /* report out proximity for previous tool */
++ wacom_report_key(wcombo, wacom->tool[1], 0);
++ wacom_input_sync(wcombo);
++ wacom->tool[1] = BTN_TOOL_PEN;
++ return 0;
++ }
++ }
++ if (wacom->tool[1] != BTN_TOOL_RUBBER) {
++ /* Unknown tool selected default to pen tool */
++ wacom->tool[1] = BTN_TOOL_PEN;
++ id = STYLUS_DEVICE_ID;
++ }
++ wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */
++ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
++ wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
++ wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
++ wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
++
++ wacom_report_key(wcombo, BTN_TOUCH, data[4] & 0x08);
++ wacom_report_key(wcombo, BTN_STYLUS, data[4] & 0x10);
++ /* Only allow the stylus2 button to be reported for the pen tool. */
++ wacom_report_key(wcombo, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
++ } else {
++ /* report proximity-out of a (valid) tool */
++ if (wacom->tool[1] != BTN_TOOL_RUBBER) {
++ /* Unknown tool selected default to pen tool */
++ wacom->tool[1] = BTN_TOOL_PEN;
++ }
++ wacom_report_key(wcombo, wacom->tool[1], prox);
++ }
++
++ wacom->tool[0] = prox; /* Save proximity state */
++ return 1;
++}
++
++static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++ int id;
++
++ if (data[0] != 2) {
++ printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
++ return 0;
++ }
++
++ if (data[1] & 0x04) {
++ wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20);
++ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08);
++ id = ERASER_DEVICE_ID;
++ } else {
++ wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20);
++ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
++ id = STYLUS_DEVICE_ID;
++ }
++ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
++ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
++ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
++ wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
++ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
++ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
++ return 1;
++}
++
++static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++ int x, y, id, rw;
++
++ if (data[0] != 2) {
++ dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
++ return 0;
++ }
++
++ id = STYLUS_DEVICE_ID;
++ if (data[1] & 0x10) { /* in prox */
++
++ switch ((data[1] >> 5) & 3) {
++
++ case 0: /* Pen */
++ wacom->tool[0] = BTN_TOOL_PEN;
++ break;
++
++ case 1: /* Rubber */
++ wacom->tool[0] = BTN_TOOL_RUBBER;
++ id = ERASER_DEVICE_ID;
++ break;
++
++ case 2: /* Mouse with wheel */
++ wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
++ if (wacom->features->type == WACOM_G4) {
++ rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
++ wacom_report_rel(wcombo, REL_WHEEL, -rw);
++ } else
++ wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
++ /* fall through */
++
++ case 3: /* Mouse without wheel */
++ wacom->tool[0] = BTN_TOOL_MOUSE;
++ id = CURSOR_DEVICE_ID;
++ wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
++ wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
++ if (wacom->features->type == WACOM_G4)
++ wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
++ else
++ wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
++ break;
++ }
++ }
++
++ if (data[1] & 0x90) {
++ x = wacom_le16_to_cpu(&data[2]);
++ y = wacom_le16_to_cpu(&data[4]);
++ wacom_report_abs(wcombo, ABS_X, x);
++ wacom_report_abs(wcombo, ABS_Y, y);
++ if (wacom->tool[0] != BTN_TOOL_MOUSE) {
++ wacom_report_abs(wcombo, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
++ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
++ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
++ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
++ }
++ }
++
++ if (data[1] & 0x10)
++ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
++ else
++ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
++ wacom_report_key(wcombo, wacom->tool[0], data[1] & 0x10);
++ wacom_input_sync(wcombo);
++
++ /* send pad data */
++ if (wacom->features->type == WACOM_G4) {
++ if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) {
++ wacom->id[1] = 1;
++ wacom->serial[1] = (data[7] & 0xf8);
++ wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
++ wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
++ rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
++ wacom_report_rel(wcombo, REL_WHEEL, rw);
++ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
++ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
++ } else if (wacom->id[1]) {
++ wacom->id[1] = 0;
++ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
++ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
++ }
++ }
++ return 1;
++}
++
++static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++ int idx;
++
++ /* tool number */
++ idx = data[1] & 0x01;
++
++ /* Enter report */
++ if ((data[1] & 0xfc) == 0xc0) {
++ /* serial number of the tool */
++ wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
++ (data[4] << 20) + (data[5] << 12) +
++ (data[6] << 4) + (data[7] >> 4);
++
++ wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
++ switch (wacom->id[idx]) {
++ case 0x812: /* Inking pen */
++ case 0x801: /* Intuos3 Inking pen */
++ case 0x012:
++ wacom->tool[idx] = BTN_TOOL_PENCIL;
++ break;
++ case 0x822: /* Pen */
++ case 0x842:
++ case 0x852:
++ case 0x823: /* Intuos3 Grip Pen */
++ case 0x813: /* Intuos3 Classic Pen */
++ case 0x885: /* Intuos3 Marker Pen */
++ case 0x022:
++ wacom->tool[idx] = BTN_TOOL_PEN;
++ break;
++ case 0x832: /* Stroke pen */
++ case 0x032:
++ wacom->tool[idx] = BTN_TOOL_BRUSH;
++ break;
++ case 0x007: /* Mouse 4D and 2D */
++ case 0x09c:
++ case 0x094:
++ case 0x017: /* Intuos3 2D Mouse */
++ wacom->tool[idx] = BTN_TOOL_MOUSE;
++ break;
++ case 0x096: /* Lens cursor */
++ case 0x097: /* Intuos3 Lens cursor */
++ wacom->tool[idx] = BTN_TOOL_LENS;
++ break;
++ case 0x82a: /* Eraser */
++ case 0x85a:
++ case 0x91a:
++ case 0xd1a:
++ case 0x0fa:
++ case 0x82b: /* Intuos3 Grip Pen Eraser */
++ case 0x81b: /* Intuos3 Classic Pen Eraser */
++ case 0x91b: /* Intuos3 Airbrush Eraser */
++ wacom->tool[idx] = BTN_TOOL_RUBBER;
++ break;
++ case 0xd12:
++ case 0x912:
++ case 0x112:
++ case 0x913: /* Intuos3 Airbrush */
++ wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
++ break;
++ default: /* Unknown tool */
++ wacom->tool[idx] = BTN_TOOL_PEN;
++ }
++ /* only large I3 support Lens Cursor */
++ if(!((wacom->tool[idx] == BTN_TOOL_LENS)
++ && ((wacom->features->type == INTUOS3)
++ || (wacom->features->type == INTUOS3S)))) {
++ wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
++ wacom_report_key(wcombo, wacom->tool[idx], 1);
++ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
++ return 2;
++ }
++ return 1;
++ }
++
++ /* Exit report */
++ if ((data[1] & 0xfe) == 0x80) {
++ if(!((wacom->tool[idx] == BTN_TOOL_LENS)
++ && ((wacom->features->type == INTUOS3)
++ || (wacom->features->type == INTUOS3S)))) {
++ wacom_report_key(wcombo, wacom->tool[idx], 0);
++ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
++ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
++ return 2;
++ }
++ }
++ return 0;
++}
++
++static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++ unsigned int t;
++
++ /* general pen packet */
++ if ((data[1] & 0xb8) == 0xa0) {
++ t = (data[6] << 2) | ((data[7] >> 6) & 3);
++ wacom_report_abs(wcombo, ABS_PRESSURE, t);
++ wacom_report_abs(wcombo, ABS_TILT_X,
++ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
++ wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
++ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 2);
++ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 4);
++ wacom_report_key(wcombo, BTN_TOUCH, t > 10);
++ }
++
++ /* airbrush second packet */
++ if ((data[1] & 0xbc) == 0xb4) {
++ wacom_report_abs(wcombo, ABS_WHEEL,
++ (data[6] << 2) | ((data[7] >> 6) & 3));
++ wacom_report_abs(wcombo, ABS_TILT_X,
++ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
++ wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
++ }
++ return;
++}
++
++static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
++{
++ unsigned char *data = wacom->data;
++ unsigned int t;
++ int idx, result;
++
++ if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
++ dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
++ return 0;
++ }
++
++ /* tool number */
++ idx = data[1] & 0x01;
++
++ /* pad packets. Works as a second tool and is always in prox */
++ if (data[0] == 12) {
++ /* initiate the pad as a device */
++ if (wacom->tool[1] != BTN_TOOL_FINGER)
++ wacom->tool[1] = BTN_TOOL_FINGER;
++
++ wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
++ wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
++ wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
++ wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
++ wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
++ wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
++ wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
++ wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
++ wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
++ wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
++
++ if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) |
++ data[2] | (data[3] & 0x1f) | data[4])
++ wacom_report_key(wcombo, wacom->tool[1], 1);
++ else
++ wacom_report_key(wcombo, wacom->tool[1], 0);
++ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
++ return 1;
++ }
++
++ /* process in/out prox events */
++ result = wacom_intuos_inout(wacom, wcombo);
++ if (result)
++ return result-1;
++
++ /* Cintiq doesn't send data when RDY bit isn't set */
++ if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
++ return 0;
++
++ if (wacom->features->type >= INTUOS3) {
++ wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
++ wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
++ wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
++ } else {
++ wacom_report_abs(wcombo, ABS_X, wacom_be16_to_cpu(&data[2]));
++ wacom_report_abs(wcombo, ABS_Y, wacom_be16_to_cpu(&data[4]));
++ wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
++ }
++
++ /* process general packets */
++ wacom_intuos_general(wacom, wcombo);
++
++ /* 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) ;
++ wacom_report_abs(wcombo, ABS_WHEEL, t);
++ } else {
++ /* 4D mouse rotation packet */
++ t = (data[6] << 3) | ((data[7] >> 5) & 7);
++ wacom_report_abs(wcombo, ABS_RZ, (data[7] & 0x20) ?
++ ((t - 1) / 2) : -t / 2);
++ }
++
++ } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
++ /* 4D mouse packet */
++ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
++ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
++ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04);
++
++ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x20);
++ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x10);
++ t = (data[6] << 2) | ((data[7] >> 6) & 3);
++ wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
++
++ } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
++ /* 2D mouse packet */
++ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04);
++ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
++ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10);
++ wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
++ - ((data[8] & 0x02) >> 1));
++
++ /* I3 2D mouse side buttons */
++ if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
++ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
++ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
++ }
++
++ } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
++ /* Lens cursor packets */
++ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
++ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
++ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04);
++ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x10);
++ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x08);
++ }
++ }
++
++ wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
++ wacom_report_key(wcombo, wacom->tool[idx], 1);
++ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
++ return 1;
++}
++
++int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
++{
++ switch (wacom_wac->features->type) {
++ case PENPARTNER:
++ return (wacom_penpartner_irq(wacom_wac, wcombo));
++ break;
++ case PL:
++ return (wacom_pl_irq(wacom_wac, wcombo));
++ break;
++ case WACOM_G4:
++ case GRAPHIRE:
++ return (wacom_graphire_irq(wacom_wac, wcombo));
++ break;
++ case PTU:
++ return (wacom_ptu_irq(wacom_wac, wcombo));
++ break;
++ case INTUOS:
++ case INTUOS3S:
++ case INTUOS3:
++ case INTUOS3L:
++ case CINTIQ:
++ return (wacom_intuos_irq(wacom_wac, wcombo));
++ break;
++ default:
++ return 0;
++ }
++ return 0;
++}
++
++void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
++{
++ switch (wacom_wac->features->type) {
++ case WACOM_G4:
++ input_dev_g4(input_dev, wacom_wac);
++ /* fall through */
++ case GRAPHIRE:
++ input_dev_g(input_dev, wacom_wac);
++ break;
++ case INTUOS3:
++ case INTUOS3L:
++ case CINTIQ:
++ input_dev_i3(input_dev, wacom_wac);
++ /* fall through */
++ case INTUOS3S:
++ input_dev_i3s(input_dev, wacom_wac);
++ case INTUOS:
++ input_dev_i(input_dev, wacom_wac);
++ break;
++ case PL:
++ case PTU:
++ input_dev_pl(input_dev, wacom_wac);
++ break;
++ case PENPARTNER:
++ input_dev_pt(input_dev, wacom_wac);
++ break;
++ }
++ return;
++}
++
++static struct wacom_features wacom_features[] = {
++ { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER },
++ { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE },
++ { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE },
++ { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE },
++ { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE },
++ { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE },
++ { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 },
++ { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 },
++ { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE },
++ { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE },
++ { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE },
++ { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE },
++ { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE },
++ { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
++ { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
++ { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
++ { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
++ { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
++ { "Wacom PL400", 8, 5408, 4056, 255, 0, PL },
++ { "Wacom PL500", 8, 6144, 4608, 255, 0, PL },
++ { "Wacom PL600", 8, 6126, 4604, 255, 0, PL },
++ { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL },
++ { "Wacom PL550", 8, 6144, 4608, 511, 0, PL },
++ { "Wacom PL800", 8, 7220, 5780, 511, 0, PL },
++ { "Wacom PL700", 8, 6758, 5406, 511, 0, PL },
++ { "Wacom PL510", 8, 6282, 4762, 511, 0, PL },
++ { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL },
++ { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL },
++ { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL },
++ { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU },
++ { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
++ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
++ { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
++ { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
++ { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
++ { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S },
++ { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 },
++ { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 },
++ { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
++ { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
++ { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
++ { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S },
++ { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
++ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
++ { }
++};
++
++static struct usb_device_id wacom_ids[] = {
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
++ { 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, 0xB3) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
++ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
++ { }
++};
++
++const struct usb_device_id * get_device_table(void) {
++ const struct usb_device_id * id_table = wacom_ids;
++ return id_table;
++}
++
++struct wacom_features * get_wacom_feature(const struct usb_device_id * id) {
++ int index = id - wacom_ids;
++ struct wacom_features *wf = &wacom_features[index];
++ return wf;
++}
++
++MODULE_DEVICE_TABLE(usb, wacom_ids);
+diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h
+new file mode 100644
+index 0000000..a1d9ce0
+--- /dev/null
++++ b/drivers/usb/input/wacom_wac.h
+@@ -0,0 +1,48 @@
++/*
++ * drivers/usb/input/wacom_wac.h
++ *
++ * 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.
++ */
++#ifndef WACOM_WAC_H
++#define WACOM_WAC_H
++
++#define STYLUS_DEVICE_ID 0x02
++#define CURSOR_DEVICE_ID 0x06
++#define ERASER_DEVICE_ID 0x0A
++
++enum {
++ PENPARTNER = 0,
++ GRAPHIRE,
++ WACOM_G4,
++ PTU,
++ PL,
++ INTUOS,
++ INTUOS3S,
++ INTUOS3,
++ INTUOS3L,
++ CINTIQ,
++ MAX_TYPE
++};
++
++struct wacom_features {
++ char *name;
++ int pktlen;
++ int x_max;
++ int y_max;
++ int pressure_max;
++ int distance_max;
++ int type;
++};
++
++struct wacom_wac {
++ signed char *data;
++ int tool[2];
++ int id[2];
++ __u32 serial[2];
++ struct wacom_features *features;
++};
++
++#endif
+diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
+index 9889b1c..df97e5c 100644
+--- a/drivers/usb/input/xpad.c
++++ b/drivers/usb/input/xpad.c
+@@ -1,8 +1,13 @@
+ /*
+- * X-Box gamepad - v0.0.5
++ * X-Box gamepad - v0.0.6
+ *
+ * Copyright (c) 2002 Marko Friedemann <mfr at bmx-chemnitz.de>
+- *
++ * 2004 Oliver Schwartz <Oliver.Schwartz at gmx.de>,
++ * Steven Toth <steve at toth.demon.co.uk>,
++ * Franz Lehner <franz at caos.at>,
++ * Ivan Hawkes <blackhawk at ivanhawkes.com>
++ * 2005 Dominic Cerquetti <binary1230 at yahoo.com>
++ * 2006 Adam Buchbinder <adam.buchbinder at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+@@ -28,11 +33,13 @@
+ * - ITO Takayuki for providing essential xpad information on his website
+ * - Vojtech Pavlik - iforce driver / input subsystem
+ * - Greg Kroah-Hartman - usb-skeleton driver
++ * - XBOX Linux project - extra USB id's
+ *
+ * TODO:
+- * - fine tune axes
++ * - fine tune axes (especially trigger axes)
+ * - fix "analog" buttons (reported as digital now)
+ * - get rumble working
++ * - need USB IDs for other dance pads
+ *
+ * History:
+ *
+@@ -52,30 +59,79 @@
+ * - fixed d-pad to axes mapping
+ *
+ * 2002-07-17 - 0.0.5 : simplified d-pad handling
++ *
++ * 2004-10-02 - 0.0.6 : DDR pad support
++ * - borrowed from the XBOX linux kernel
++ * - USB id's for commonly used dance pads are present
++ * - dance pads will map D-PAD to buttons, not axes
++ * - pass the module paramater 'dpad_to_buttons' to force
++ * the D-PAD to map to buttons if your pad is not detected
+ */
+
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
++#include <linux/stat.h>
+ #include <linux/module.h>
++#include <linux/moduleparam.h>
+ #include <linux/smp_lock.h>
+ #include <linux/usb/input.h>
+
+-#define DRIVER_VERSION "v0.0.5"
++#define DRIVER_VERSION "v0.0.6"
+ #define DRIVER_AUTHOR "Marko Friedemann <mfr at bmx-chemnitz.de>"
+ #define DRIVER_DESC "X-Box pad driver"
+
+ #define XPAD_PKT_LEN 32
+
++/* xbox d-pads should map to buttons, as is required for DDR pads
++ but we map them to axes when possible to simplify things */
++#define MAP_DPAD_TO_BUTTONS 0
++#define MAP_DPAD_TO_AXES 1
++#define MAP_DPAD_UNKNOWN -1
++
++static int dpad_to_buttons;
++module_param(dpad_to_buttons, bool, S_IRUGO);
++MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
++
+ static const struct xpad_device {
+ u16 idVendor;
+ u16 idProduct;
+ char *name;
++ u8 dpad_mapping;
+ } xpad_device[] = {
+- { 0x045e, 0x0202, "Microsoft X-Box pad (US)" },
+- { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" },
+- { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" },
+- { 0x0000, 0x0000, "X-Box pad" }
++ { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
++ { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
++ { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
++ { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES },
++ { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
++ { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES },
++ { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES },
++ { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES },
++ { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES },
++ { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
++ { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES },
++ { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES },
++ { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES },
++ { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES },
++ { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS },
++ { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES },
++ { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS },
++ { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES },
++ { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES },
++ { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES },
++ { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES },
++ { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES},
++ { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES },
++ { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES },
++ { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES },
++ { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES },
++ { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES },
++ { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES },
++ { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES },
++ { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS },
++ { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS },
++ { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES },
++ { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
+ };
+
+ static const signed short xpad_btn[] = {
+@@ -84,11 +140,23 @@ static const signed short xpad_btn[] = {
+ -1 /* terminating entry */
+ };
+
++/* only used if MAP_DPAD_TO_BUTTONS */
++static const signed short xpad_btn_pad[] = {
++ BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
++ BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
++ -1 /* terminating entry */
++};
++
+ static const signed short xpad_abs[] = {
+ ABS_X, ABS_Y, /* left stick */
+ ABS_RX, ABS_RY, /* right stick */
+ ABS_Z, ABS_RZ, /* triggers left/right */
+- ABS_HAT0X, ABS_HAT0Y, /* digital pad */
++ -1 /* terminating entry */
++};
++
++/* only used if MAP_DPAD_TO_AXES */
++static const signed short xpad_abs_pad[] = {
++ ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
+ -1 /* terminating entry */
+ };
+
+@@ -100,14 +168,16 @@ static struct usb_device_id xpad_table [
+ MODULE_DEVICE_TABLE (usb, xpad_table);
+
+ struct usb_xpad {
+- struct input_dev *dev; /* input device interface */
+- struct usb_device *udev; /* usb device */
++ 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 */
++ 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 */
++ char phys[65]; /* physical device path */
++
++ int dpad_mapping; /* map d-pad to buttons or to axes */
+ };
+
+ /*
+@@ -120,12 +190,10 @@ struct usb_xpad {
+ * http://euc.jp/periphs/xbox-controller.ja.html
+ */
+
+-static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, struct pt_regs *regs)
++static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+ {
+ 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]));
+@@ -139,14 +207,21 @@ static void xpad_process_packet(struct u
+ 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));
++ if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
++ input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
++ input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
++ } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
++ input_report_key(dev, BTN_LEFT, data[2] & 0x04);
++ input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
++ input_report_key(dev, BTN_0, data[2] & 0x01); // up
++ input_report_key(dev, BTN_1, data[2] & 0x02); // down
++ }
+
+ /* 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);
++ input_report_key(dev, BTN_START, data[2] & 0x10);
++ input_report_key(dev, BTN_BACK, data[2] & 0x20);
++ input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
++ input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
+
+ /* "analog" buttons A, B, X, Y */
+ input_report_key(dev, BTN_A, data[4]);
+@@ -161,7 +236,7 @@ static void xpad_process_packet(struct u
+ input_sync(dev);
+ }
+
+-static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
++static void xpad_irq_in(struct urb *urb)
+ {
+ struct usb_xpad *xpad = urb->context;
+ int retval;
+@@ -181,7 +256,7 @@ static void xpad_irq_in(struct urb *urb,
+ goto exit;
+ }
+
+- xpad_process_packet(xpad, 0, xpad->idata, regs);
++ xpad_process_packet(xpad, 0, xpad->idata);
+
+ exit:
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+@@ -208,6 +283,28 @@ static void xpad_close (struct input_dev
+ usb_kill_urb(xpad->irq_in);
+ }
+
++static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
++{
++ set_bit(abs, input_dev->absbit);
++
++ switch (abs) {
++ case ABS_X:
++ case ABS_Y:
++ case ABS_RX:
++ case ABS_RY: /* the two sticks */
++ input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
++ break;
++ case ABS_Z:
++ case ABS_RZ: /* the triggers */
++ input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
++ break;
++ case ABS_HAT0X:
++ case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
++ input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
++ break;
++ }
++}
++
+ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ struct usb_device *udev = interface_to_usbdev (intf);
+@@ -237,6 +334,9 @@ static int xpad_probe(struct usb_interfa
+ goto fail2;
+
+ xpad->udev = udev;
++ xpad->dpad_mapping = xpad_device[i].dpad_mapping;
++ if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
++ xpad->dpad_mapping = dpad_to_buttons;
+ xpad->dev = input_dev;
+ usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
+ strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
+@@ -251,32 +351,19 @@ static int xpad_probe(struct usb_interfa
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
++ /* set up buttons */
+ for (i = 0; xpad_btn[i] >= 0; i++)
+ set_bit(xpad_btn[i], input_dev->keybit);
++ if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
++ for (i = 0; xpad_btn_pad[i] >= 0; i++)
++ set_bit(xpad_btn_pad[i], input_dev->keybit);
+
+- for (i = 0; xpad_abs[i] >= 0; i++) {
+-
+- signed short t = xpad_abs[i];
+-
+- set_bit(t, input_dev->absbit);
+-
+- switch (t) {
+- case ABS_X:
+- case ABS_Y:
+- case ABS_RX:
+- case ABS_RY: /* the two sticks */
+- input_set_abs_params(input_dev, t, -32768, 32767, 16, 128);
+- break;
+- case ABS_Z:
+- case ABS_RZ: /* the triggers */
+- input_set_abs_params(input_dev, t, 0, 255, 0, 0);
+- break;
+- case ABS_HAT0X:
+- case ABS_HAT0Y: /* the d-pad */
+- input_set_abs_params(input_dev, t, -1, 1, 0, 0);
+- break;
+- }
+- }
++ /* set up axes */
++ for (i = 0; xpad_abs[i] >= 0; i++)
++ xpad_set_up_abs(input_dev, xpad_abs[i]);
++ if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
++ for (i = 0; xpad_abs_pad[i] >= 0; i++)
++ xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+
+ ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(xpad->irq_in, udev,
+@@ -307,7 +394,8 @@ static void xpad_disconnect(struct usb_i
+ usb_kill_urb(xpad->irq_in);
+ input_unregister_device(xpad->dev);
+ usb_free_urb(xpad->irq_in);
+- usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
++ usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
++ xpad->idata, xpad->idata_dma);
+ kfree(xpad);
+ }
+ }
+diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c
+index 7b45fd3..905bf63 100644
+--- a/drivers/usb/input/yealink.c
++++ b/drivers/usb/input/yealink.c
+@@ -233,11 +233,10 @@ static int map_p1k_to_key(int scancode)
+ *
+ * The key parameter can be cascaded: key2 << 8 | key1
+ */
+-static void report_key(struct yealink_dev *yld, int key, struct pt_regs *regs)
++static void report_key(struct yealink_dev *yld, int key)
+ {
+ struct input_dev *idev = yld->idev;
+
+- input_regs(idev, regs);
+ if (yld->key_code >= 0) {
+ /* old key up */
+ input_report_key(idev, yld->key_code & 0xff, 0);
+@@ -422,7 +421,7 @@ send_update:
+ * error,start
+ *
+ */
+-static void urb_irq_callback(struct urb *urb, struct pt_regs *regs)
++static void urb_irq_callback(struct urb *urb)
+ {
+ struct yealink_dev *yld = urb->context;
+ int ret;
+@@ -439,7 +438,7 @@ static void urb_irq_callback(struct urb
+ case CMD_SCANCODE:
+ dbg("get scancode %x", yld->irq_data->data[0]);
+
+- report_key(yld, map_p1k_to_key(yld->irq_data->data[0]), regs);
++ report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
+ break;
+
+ default:
+@@ -453,7 +452,7 @@ static void urb_irq_callback(struct urb
+ err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+ }
+
+-static void urb_ctl_callback(struct urb *urb, struct pt_regs *regs)
++static void urb_ctl_callback(struct urb *urb)
+ {
+ struct yealink_dev *yld = urb->context;
+ int ret;
+@@ -971,7 +970,7 @@ static int usb_probe(struct usb_interfac
+ DRIVER_VERSION, sizeof(DRIVER_VERSION));
+
+ /* Register sysfs hooks (don't care about failure) */
+- sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
++ ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+ return 0;
+ }
+
+diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
+index 88928a4..a74bf86 100644
+--- a/drivers/usb/misc/Kconfig
++++ b/drivers/usb/misc/Kconfig
+@@ -32,6 +32,16 @@ config USB_EMI26
+ To compile this driver as a module, choose M here: the
+ module will be called emi26.
+
++config USB_ADUTUX
++ tristate "ADU devices from Ontrak Control Systems (EXPERIMENTAL)"
++ depends on USB && EXPERIMENTAL
++ help
++ Say Y if you want to use an ADU device from Ontrak Control
++ Systems.
++
++ To compile this driver as a module, choose M here. The module
++ will be called adutux.
++
+ config USB_AUERSWALD
+ tristate "USB Auerswald ISDN support (EXPERIMENTAL)"
+ depends on USB && EXPERIMENTAL
+@@ -115,19 +125,36 @@ config USB_CYTHERM
+ To compile this driver as a module, choose M here: the
+ module will be called cytherm.
+
+-config USB_PHIDGETKIT
+- tristate "USB PhidgetKit support"
++config USB_PHIDGET
++ tristate "USB Phidgets drivers"
+ depends on USB
+ help
+- Say Y here if you want to connect a PhidgetKit USB device from
+- Phidgets Inc.
++ Say Y here to enable the various drivers for devices from
++ Phidgets inc.
++
++config USB_PHIDGETKIT
++ tristate "USB PhidgetInterfaceKit support"
++ depends on USB_PHIDGET
++ help
++ Say Y here if you want to connect a PhidgetInterfaceKit USB device
++ from Phidgets Inc.
+
+ To compile this driver as a module, choose M here: the
+ module will be called phidgetkit.
+
++config USB_PHIDGETMOTORCONTROL
++ tristate "USB PhidgetMotorControl support"
++ depends on USB_PHIDGET
++ help
++ Say Y here if you want to connect a PhidgetMotorControl USB device
++ from Phidgets Inc.
++
++ To compile this driver as a module, choose M here: the
++ module will be called phidgetmotorcontrol.
++
+ config USB_PHIDGETSERVO
+ tristate "USB PhidgetServo support"
+- depends on USB
++ depends on USB_PHIDGET
+ help
+ Say Y here if you want to connect an 1 or 4 Motor PhidgetServo
+ servo controller version 2.0 or 3.0.
+@@ -151,6 +178,30 @@ config USB_IDMOUSE
+
+ See also <http://www.fs.tum.de/~echtler/idmouse/>.
+
++config USB_FTDI_ELAN
++ tristate "Elan PCMCIA CardBus Adapter USB Client"
++ depends on USB
++ default M
++ help
++ ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.
++ Currently only the U132 adapter is available.
++
++ The U132 is specifically designed for CardBus PC cards that contain
++ an OHCI host controller. Typical PC cards are the Orange Mobile 3G
++ Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work
++ with PC cards that do not contain an OHCI controller. To use a U132
++ adapter you will need this "ftdi-elan" module as well as the "u132-hcd"
++ module which is a USB host controller driver that talks to the OHCI
++ controller within CardBus card that are inserted in the U132 adapter.
++
++ This driver has been tested with a CardBus OHCI USB adapter, and
++ worked with a USB PEN Drive inserted into the first USB port of
++ the PCCARD. A rather pointless thing to do, but useful for testing.
++
++ See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller"
++
++ It is safe to say M here.
++
+ config USB_APPLEDISPLAY
+ tristate "Apple Cinema Display support"
+ depends on USB
+@@ -172,6 +223,16 @@ config USB_LD
+ To compile this driver as a module, choose M here: the
+ module will be called ldusb.
+
++config USB_TRANCEVIBRATOR
++ tristate "PlayStation 2 Trance Vibrator driver support"
++ depends on USB
++ help
++ Say Y here if you want to connect a PlayStation 2 Trance Vibrator
++ device to your computer's USB port.
++
++ To compile this driver as a module, choose M here: the
++ module will be called trancevibrator.
++
+ 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 2927260..11dc595 100644
+--- a/drivers/usb/misc/Makefile
++++ b/drivers/usb/misc/Makefile
+@@ -3,22 +3,26 @@
+ # (the ones that don't fit into any other categories)
+ #
+
++obj-$(CONFIG_USB_ADUTUX) += adutux.o
+ obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
+ obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
+ obj-$(CONFIG_USB_CYTHERM) += cytherm.o
+ obj-$(CONFIG_USB_EMI26) += emi26.o
+ obj-$(CONFIG_USB_EMI62) += emi62.o
++obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.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_PHIDGET) += phidget.o
+ obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o
++obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o
+ obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
+ obj-$(CONFIG_USB_RIO500) += rio500.o
+ obj-$(CONFIG_USB_TEST) += usbtest.o
++obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
+ obj-$(CONFIG_USB_USS720) += uss720.o
+-obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
+
+ obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
+
+diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
+new file mode 100644
+index 0000000..af2934e
+--- /dev/null
++++ b/drivers/usb/misc/adutux.c
+@@ -0,0 +1,901 @@
++/*
++ * adutux - driver for ADU devices from Ontrak Control Systems
++ * This is an experimental driver. Use at your own risk.
++ * This driver is not supported by Ontrak Control Systems.
++ *
++ * Copyright (c) 2003 John Homppi (SCO, leave this notice here)
++ *
++ * 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 the Lego USB Tower driver 0.56:
++ * Copyright (c) 2003 David Glance <davidgsf at sourceforge.net>
++ * 2001 Juergen Stuber <stuber at loria.fr>
++ * that was derived from USB Skeleton driver - 0.5
++ * Copyright (c) 2001 Greg Kroah-Hartman (greg at kroah.com)
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++#include <asm/uaccess.h>
++
++#ifdef CONFIG_USB_DEBUG
++static int debug = 5;
++#else
++static int debug = 1;
++#endif
++
++/* Use our own dbg macro */
++#undef dbg
++#define dbg(lvl, format, arg...) \
++do { \
++ if (debug >= lvl) \
++ printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); \
++} while (0)
++
++
++/* Version Information */
++#define DRIVER_VERSION "v0.0.13"
++#define DRIVER_AUTHOR "John Homppi"
++#define DRIVER_DESC "adutux (see www.ontrak.net)"
++
++/* Module parameters */
++module_param(debug, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled or not");
++
++/* Define these values to match your device */
++#define ADU_VENDOR_ID 0x0a07
++#define ADU_PRODUCT_ID 0x0064
++
++/* table of devices that work with this driver */
++static struct usb_device_id device_table [] = {
++ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) }, /* ADU100 */
++ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) }, /* ADU120 */
++ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) }, /* ADU130 */
++ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+100) }, /* ADU200 */
++ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+108) }, /* ADU208 */
++ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+118) }, /* ADU218 */
++ { }/* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE(usb, device_table);
++
++#ifdef CONFIG_USB_DYNAMIC_MINORS
++#define ADU_MINOR_BASE 0
++#else
++#define ADU_MINOR_BASE 67
++#endif
++
++/* we can have up to this number of device plugged in at once */
++#define MAX_DEVICES 16
++
++#define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */
++
++/* Structure to hold all of our device specific stuff */
++struct adu_device {
++ struct semaphore sem; /* locks this structure */
++ struct usb_device* udev; /* save off the usb device pointer */
++ struct usb_interface* interface;
++ unsigned char minor; /* the starting minor number for this device */
++ char serial_number[8];
++
++ int open_count; /* number of times this port has been opened */
++
++ char* read_buffer_primary;
++ int read_buffer_length;
++ char* read_buffer_secondary;
++ int secondary_head;
++ int secondary_tail;
++ spinlock_t buflock;
++
++ 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 read_urb_finished;
++
++ char* interrupt_out_buffer;
++ struct usb_endpoint_descriptor* interrupt_out_endpoint;
++ struct urb* interrupt_out_urb;
++};
++
++/* prevent races between open() and disconnect */
++static DEFINE_MUTEX(disconnect_mutex);
++static struct usb_driver adu_driver;
++
++static void adu_debug_data(int level, const char *function, int size,
++ const unsigned char *data)
++{
++ int i;
++
++ if (debug < level)
++ return;
++
++ printk(KERN_DEBUG __FILE__": %s - length = %d, data = ",
++ function, size);
++ for (i = 0; i < size; ++i)
++ printk("%.2x ", data[i]);
++ printk("\n");
++}
++
++/**
++ * adu_abort_transfers
++ * aborts transfers and frees associated data structures
++ */
++static void adu_abort_transfers(struct adu_device *dev)
++{
++ dbg(2," %s : enter", __FUNCTION__);
++
++ if (dev == NULL) {
++ dbg(1," %s : dev is null", __FUNCTION__);
++ goto exit;
++ }
++
++ if (dev->udev == NULL) {
++ dbg(1," %s : udev is null", __FUNCTION__);
++ goto exit;
++ }
++
++ dbg(2," %s : udev state %d", __FUNCTION__, dev->udev->state);
++ if (dev->udev->state == USB_STATE_NOTATTACHED) {
++ dbg(1," %s : udev is not attached", __FUNCTION__);
++ goto exit;
++ }
++
++ /* shutdown transfer */
++ usb_unlink_urb(dev->interrupt_in_urb);
++ usb_unlink_urb(dev->interrupt_out_urb);
++
++exit:
++ dbg(2," %s : leave", __FUNCTION__);
++}
++
++static void adu_delete(struct adu_device *dev)
++{
++ dbg(2, "%s enter", __FUNCTION__);
++
++ adu_abort_transfers(dev);
++
++ /* free data structures */
++ usb_free_urb(dev->interrupt_in_urb);
++ usb_free_urb(dev->interrupt_out_urb);
++ kfree(dev->read_buffer_primary);
++ kfree(dev->read_buffer_secondary);
++ kfree(dev->interrupt_in_buffer);
++ kfree(dev->interrupt_out_buffer);
++ kfree(dev);
++
++ dbg(2, "%s : leave", __FUNCTION__);
++}
++
++static void adu_interrupt_in_callback(struct urb *urb)
++{
++ struct adu_device *dev = urb->context;
++
++ dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
++ adu_debug_data(5, __FUNCTION__, urb->actual_length,
++ urb->transfer_buffer);
++
++ spin_lock(&dev->buflock);
++
++ if (urb->status != 0) {
++ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
++ dbg(1," %s : nonzero status received: %d",
++ __FUNCTION__, urb->status);
++ }
++ goto exit;
++ }
++
++ if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
++ if (dev->read_buffer_length <
++ (4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) -
++ (urb->actual_length)) {
++ memcpy (dev->read_buffer_primary +
++ dev->read_buffer_length,
++ dev->interrupt_in_buffer, urb->actual_length);
++
++ dev->read_buffer_length += urb->actual_length;
++ dbg(2," %s reading %d ", __FUNCTION__,
++ urb->actual_length);
++ } else {
++ dbg(1," %s : read_buffer overflow", __FUNCTION__);
++ }
++ }
++
++exit:
++ dev->read_urb_finished = 1;
++ spin_unlock(&dev->buflock);
++ /* always wake up so we recover from errors */
++ wake_up_interruptible(&dev->read_wait);
++ adu_debug_data(5, __FUNCTION__, urb->actual_length,
++ urb->transfer_buffer);
++ dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
++}
++
++static void adu_interrupt_out_callback(struct urb *urb)
++{
++ struct adu_device *dev = urb->context;
++
++ dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
++ adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
++
++ if (urb->status != 0) {
++ if ((urb->status != -ENOENT) &&
++ (urb->status != -ECONNRESET)) {
++ dbg(1, " %s :nonzero status received: %d",
++ __FUNCTION__, urb->status);
++ }
++ goto exit;
++ }
++
++ wake_up_interruptible(&dev->write_wait);
++exit:
++
++ adu_debug_data(5, __FUNCTION__, urb->actual_length,
++ urb->transfer_buffer);
++ dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
++}
++
++static int adu_open(struct inode *inode, struct file *file)
++{
++ struct adu_device *dev = NULL;
++ struct usb_interface *interface;
++ int subminor;
++ int retval = 0;
++
++ dbg(2,"%s : enter", __FUNCTION__);
++
++ subminor = iminor(inode);
++
++ mutex_lock(&disconnect_mutex);
++
++ interface = usb_find_interface(&adu_driver, subminor);
++ if (!interface) {
++ err("%s - error, can't find device for minor %d",
++ __FUNCTION__, subminor);
++ retval = -ENODEV;
++ goto exit_no_device;
++ }
++
++ dev = usb_get_intfdata(interface);
++ if (!dev) {
++ retval = -ENODEV;
++ goto exit_no_device;
++ }
++
++ /* lock this device */
++ if ((retval = down_interruptible(&dev->sem))) {
++ dbg(2, "%s : sem down failed", __FUNCTION__);
++ goto exit_no_device;
++ }
++
++ /* increment our usage count for the device */
++ ++dev->open_count;
++ dbg(2,"%s : open count %d", __FUNCTION__, dev->open_count);
++
++ /* save device in the file's private structure */
++ file->private_data = dev;
++
++ /* initialize in direction */
++ dev->read_buffer_length = 0;
++
++ /* fixup first read by having urb waiting for it */
++ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
++ usb_rcvintpipe(dev->udev,
++ dev->interrupt_in_endpoint->bEndpointAddress),
++ dev->interrupt_in_buffer,
++ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
++ adu_interrupt_in_callback, dev,
++ dev->interrupt_in_endpoint->bInterval);
++ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
++ dev->read_urb_finished = 0;
++ usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
++ /* we ignore failure */
++ /* end of fixup for first read */
++
++ up(&dev->sem);
++
++exit_no_device:
++ mutex_unlock(&disconnect_mutex);
++ dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
++
++ return retval;
++}
++
++static int adu_release_internal(struct adu_device *dev)
++{
++ int retval = 0;
++
++ dbg(2," %s : enter", __FUNCTION__);
++
++ if (dev->udev == NULL) {
++ /* the device was unplugged before the file was released */
++ adu_delete(dev);
++ goto exit;
++ }
++
++ /* decrement our usage count for the device */
++ --dev->open_count;
++ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
++ if (dev->open_count <= 0) {
++ adu_abort_transfers(dev);
++ dev->open_count = 0;
++ }
++
++exit:
++ dbg(2," %s : leave", __FUNCTION__);
++ return retval;
++}
++
++static int adu_release(struct inode *inode, struct file *file)
++{
++ struct adu_device *dev = NULL;
++ int retval = 0;
++
++ dbg(2," %s : enter", __FUNCTION__);
++
++ if (file == NULL) {
++ dbg(1," %s : file is NULL", __FUNCTION__);
++ retval = -ENODEV;
++ goto exit;
++ }
++
++ dev = file->private_data;
++
++ if (dev == NULL) {
++ dbg(1," %s : object is NULL", __FUNCTION__);
++ retval = -ENODEV;
++ goto exit;
++ }
++
++ /* lock our device */
++ down(&dev->sem); /* not interruptible */
++
++ if (dev->open_count <= 0) {
++ dbg(1," %s : device not opened", __FUNCTION__);
++ retval = -ENODEV;
++ goto exit;
++ }
++
++ /* do the work */
++ retval = adu_release_internal(dev);
++
++exit:
++ if (dev)
++ up(&dev->sem);
++ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
++ return retval;
++}
++
++static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
++ loff_t *ppos)
++{
++ struct adu_device *dev;
++ size_t bytes_read = 0;
++ size_t bytes_to_read = count;
++ int i;
++ int retval = 0;
++ int timeout = 0;
++ int should_submit = 0;
++ unsigned long flags;
++ DECLARE_WAITQUEUE(wait, current);
++
++ dbg(2," %s : enter, count = %Zd, file=%p", __FUNCTION__, count, file);
++
++ dev = file->private_data;
++ dbg(2," %s : dev=%p", __FUNCTION__, dev);
++ /* lock this object */
++ if (down_interruptible(&dev->sem))
++ return -ERESTARTSYS;
++
++ /* verify that the device wasn't unplugged */
++ if (dev->udev == NULL || dev->minor == 0) {
++ retval = -ENODEV;
++ err("No device or device unplugged %d", retval);
++ goto exit;
++ }
++
++ /* verify that some data was requested */
++ if (count == 0) {
++ dbg(1," %s : read request of 0 bytes", __FUNCTION__);
++ goto exit;
++ }
++
++ timeout = COMMAND_TIMEOUT;
++ dbg(2," %s : about to start looping", __FUNCTION__);
++ while (bytes_to_read) {
++ int data_in_secondary = dev->secondary_tail - dev->secondary_head;
++ dbg(2," %s : while, data_in_secondary=%d, status=%d",
++ __FUNCTION__, data_in_secondary,
++ dev->interrupt_in_urb->status);
++
++ if (data_in_secondary) {
++ /* drain secondary buffer */
++ int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
++ i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
++ if (i < 0) {
++ retval = -EFAULT;
++ goto exit;
++ }
++ dev->secondary_head += (amount - i);
++ bytes_read += (amount - i);
++ bytes_to_read -= (amount - i);
++ if (i) {
++ retval = bytes_read ? bytes_read : -EFAULT;
++ goto exit;
++ }
++ } else {
++ /* we check the primary buffer */
++ spin_lock_irqsave (&dev->buflock, flags);
++ if (dev->read_buffer_length) {
++ /* we secure access to the primary */
++ char *tmp;
++ dbg(2," %s : swap, read_buffer_length = %d",
++ __FUNCTION__, dev->read_buffer_length);
++ tmp = dev->read_buffer_secondary;
++ dev->read_buffer_secondary = dev->read_buffer_primary;
++ dev->read_buffer_primary = tmp;
++ dev->secondary_head = 0;
++ dev->secondary_tail = dev->read_buffer_length;
++ dev->read_buffer_length = 0;
++ spin_unlock_irqrestore(&dev->buflock, flags);
++ /* we have a free buffer so use it */
++ should_submit = 1;
++ } else {
++ /* even the primary was empty - we may need to do IO */
++ if (dev->interrupt_in_urb->status == -EINPROGRESS) {
++ /* somebody is doing IO */
++ spin_unlock_irqrestore(&dev->buflock, flags);
++ dbg(2," %s : submitted already", __FUNCTION__);
++ } else {
++ /* we must initiate input */
++ dbg(2," %s : initiate input", __FUNCTION__);
++ dev->read_urb_finished = 0;
++
++ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
++ usb_rcvintpipe(dev->udev,
++ dev->interrupt_in_endpoint->bEndpointAddress),
++ dev->interrupt_in_buffer,
++ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
++ adu_interrupt_in_callback,
++ dev,
++ dev->interrupt_in_endpoint->bInterval);
++ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
++ if (!retval) {
++ spin_unlock_irqrestore(&dev->buflock, flags);
++ dbg(2," %s : submitted OK", __FUNCTION__);
++ } else {
++ if (retval == -ENOMEM) {
++ retval = bytes_read ? bytes_read : -ENOMEM;
++ }
++ spin_unlock_irqrestore(&dev->buflock, flags);
++ dbg(2," %s : submit failed", __FUNCTION__);
++ goto exit;
++ }
++ }
++
++ /* we wait for I/O to complete */
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&dev->read_wait, &wait);
++ if (!dev->read_urb_finished)
++ timeout = schedule_timeout(COMMAND_TIMEOUT);
++ else
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&dev->read_wait, &wait);
++
++ if (timeout <= 0) {
++ dbg(2," %s : timeout", __FUNCTION__);
++ retval = bytes_read ? bytes_read : -ETIMEDOUT;
++ goto exit;
++ }
++
++ if (signal_pending(current)) {
++ dbg(2," %s : signal pending", __FUNCTION__);
++ retval = bytes_read ? bytes_read : -EINTR;
++ goto exit;
++ }
++ }
++ }
++ }
++
++ retval = bytes_read;
++ /* if the primary buffer is empty then use it */
++ if (should_submit && !dev->interrupt_in_urb->status==-EINPROGRESS) {
++ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
++ usb_rcvintpipe(dev->udev,
++ dev->interrupt_in_endpoint->bEndpointAddress),
++ dev->interrupt_in_buffer,
++ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
++ adu_interrupt_in_callback,
++ dev,
++ dev->interrupt_in_endpoint->bInterval);
++ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
++ dev->read_urb_finished = 0;
++ usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
++ /* we ignore failure */
++ }
++
++exit:
++ /* unlock the device */
++ up(&dev->sem);
++
++ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
++ return retval;
++}
++
++static ssize_t adu_write(struct file *file, const __user char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct adu_device *dev;
++ size_t bytes_written = 0;
++ size_t bytes_to_write;
++ size_t buffer_size;
++ int retval = 0;
++ int timeout = 0;
++
++ dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);
++
++ dev = file->private_data;
++
++ /* lock this object */
++ down_interruptible(&dev->sem);
++
++ /* verify that the device wasn't unplugged */
++ if (dev->udev == NULL || dev->minor == 0) {
++ retval = -ENODEV;
++ err("No device or device unplugged %d", retval);
++ goto exit;
++ }
++
++ /* verify that we actually have some data to write */
++ if (count == 0) {
++ dbg(1," %s : write request of 0 bytes", __FUNCTION__);
++ goto exit;
++ }
++
++
++ while (count > 0) {
++ if (dev->interrupt_out_urb->status == -EINPROGRESS) {
++ timeout = COMMAND_TIMEOUT;
++
++ while (timeout > 0) {
++ if (signal_pending(current)) {
++ dbg(1," %s : interrupted", __FUNCTION__);
++ retval = -EINTR;
++ goto exit;
++ }
++ up(&dev->sem);
++ timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
++ down_interruptible(&dev->sem);
++ if (timeout > 0) {
++ break;
++ }
++ dbg(1," %s : interrupted timeout: %d", __FUNCTION__, timeout);
++ }
++
++
++ dbg(1," %s : final timeout: %d", __FUNCTION__, timeout);
++
++ if (timeout == 0) {
++ dbg(1, "%s - command timed out.", __FUNCTION__);
++ retval = -ETIMEDOUT;
++ goto exit;
++ }
++
++ dbg(4," %s : in progress, count = %Zd", __FUNCTION__, count);
++
++ } else {
++ dbg(4," %s : sending, count = %Zd", __FUNCTION__, count);
++
++ /* write the data into interrupt_out_buffer from userspace */
++ buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
++ bytes_to_write = count > buffer_size ? buffer_size : count;
++ dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
++ __FUNCTION__, buffer_size, count, bytes_to_write);
++
++ if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
++ retval = -EFAULT;
++ goto exit;
++ }
++
++ /* send off the urb */
++ usb_fill_int_urb(
++ dev->interrupt_out_urb,
++ dev->udev,
++ usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),
++ dev->interrupt_out_buffer,
++ bytes_to_write,
++ adu_interrupt_out_callback,
++ dev,
++ dev->interrupt_in_endpoint->bInterval);
++ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
++ dev->interrupt_out_urb->actual_length = bytes_to_write;
++ retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
++ if (retval < 0) {
++ err("Couldn't submit interrupt_out_urb %d", retval);
++ goto exit;
++ }
++
++ buffer += bytes_to_write;
++ count -= bytes_to_write;
++
++ bytes_written += bytes_to_write;
++ }
++ }
++
++ retval = bytes_written;
++
++exit:
++ /* unlock the device */
++ up(&dev->sem);
++
++ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
++
++ return retval;
++}
++
++/* file operations needed when we register this driver */
++static struct file_operations adu_fops = {
++ .owner = THIS_MODULE,
++ .read = adu_read,
++ .write = adu_write,
++ .open = adu_open,
++ .release = adu_release,
++};
++
++/*
++ * usb class driver info in order to get a minor number from the usb core,
++ * and to have the device registered with devfs and the driver core
++ */
++static struct usb_class_driver adu_class = {
++ .name = "usb/adutux%d",
++ .fops = &adu_fops,
++ .minor_base = ADU_MINOR_BASE,
++};
++
++/**
++ * adu_probe
++ *
++ * Called by the usb core when a new device is connected that it thinks
++ * this driver might be interested in.
++ */
++static int adu_probe(struct usb_interface *interface,
++ const struct usb_device_id *id)
++{
++ struct usb_device *udev = interface_to_usbdev(interface);
++ struct adu_device *dev = NULL;
++ struct usb_host_interface *iface_desc;
++ struct usb_endpoint_descriptor *endpoint;
++ int retval = -ENODEV;
++ int in_end_size;
++ int out_end_size;
++ int i;
++
++ dbg(2," %s : enter", __FUNCTION__);
++
++ if (udev == NULL) {
++ dev_err(&interface->dev, "udev is NULL.\n");
++ goto exit;
++ }
++
++ /* allocate memory for our device state and intialize it */
++ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);
++ if (dev == NULL) {
++ dev_err(&interface->dev, "Out of memory\n");
++ retval = -ENOMEM;
++ goto exit;
++ }
++
++ init_MUTEX(&dev->sem);
++ spin_lock_init(&dev->buflock);
++ dev->udev = udev;
++ init_waitqueue_head(&dev->read_wait);
++ init_waitqueue_head(&dev->write_wait);
++
++ iface_desc = &interface->altsetting[0];
++
++ /* set up the endpoint information */
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
++ endpoint = &iface_desc->endpoint[i].desc;
++
++ if (usb_endpoint_is_int_in(endpoint))
++ dev->interrupt_in_endpoint = endpoint;
++
++ if (usb_endpoint_is_int_out(endpoint))
++ dev->interrupt_out_endpoint = endpoint;
++ }
++ if (dev->interrupt_in_endpoint == NULL) {
++ dev_err(&interface->dev, "interrupt in endpoint not found\n");
++ goto error;
++ }
++ if (dev->interrupt_out_endpoint == NULL) {
++ dev_err(&interface->dev, "interrupt out endpoint not found\n");
++ goto error;
++ }
++
++ in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
++ out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
++
++ dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
++ if (!dev->read_buffer_primary) {
++ dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n");
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ /* debug code prime the buffer */
++ memset(dev->read_buffer_primary, 'a', in_end_size);
++ memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size);
++ memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size);
++ memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size);
++
++ dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL);
++ if (!dev->read_buffer_secondary) {
++ dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n");
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ /* debug code prime the buffer */
++ memset(dev->read_buffer_secondary, 'e', in_end_size);
++ memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size);
++ memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size);
++ memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size);
++
++ dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL);
++ if (!dev->interrupt_in_buffer) {
++ dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
++ goto error;
++ }
++
++ /* debug code prime the buffer */
++ memset(dev->interrupt_in_buffer, 'i', in_end_size);
++
++ dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!dev->interrupt_in_urb) {
++ dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");
++ goto error;
++ }
++ dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL);
++ if (!dev->interrupt_out_buffer) {
++ dev_err(&interface->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(&interface->dev, "Couldn't allocate interrupt_out_urb\n");
++ goto error;
++ }
++
++ if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number,
++ sizeof(dev->serial_number))) {
++ dev_err(&interface->dev, "Could not retrieve serial number\n");
++ goto error;
++ }
++ dbg(2," %s : serial_number=%s", __FUNCTION__, dev->serial_number);
++
++ /* we can register the device now, as it is ready */
++ usb_set_intfdata(interface, dev);
++
++ retval = usb_register_dev(interface, &adu_class);
++
++ if (retval) {
++ /* something prevented us from registering this driver */
++ dev_err(&interface->dev, "Not able to get a minor for this device.\n");
++ usb_set_intfdata(interface, NULL);
++ goto error;
++ }
++
++ dev->minor = interface->minor;
++
++ /* let the user know what node this device is now attached to */
++ dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d",
++ udev->descriptor.idProduct, dev->serial_number,
++ (dev->minor - ADU_MINOR_BASE));
++exit:
++ dbg(2," %s : leave, return value %p (dev)", __FUNCTION__, dev);
++
++ return retval;
++
++error:
++ adu_delete(dev);
++ return retval;
++}
++
++/**
++ * adu_disconnect
++ *
++ * Called by the usb core when the device is removed from the system.
++ */
++static void adu_disconnect(struct usb_interface *interface)
++{
++ struct adu_device *dev;
++ int minor;
++
++ dbg(2," %s : enter", __FUNCTION__);
++
++ mutex_lock(&disconnect_mutex); /* not interruptible */
++
++ dev = usb_get_intfdata(interface);
++ usb_set_intfdata(interface, NULL);
++
++ down(&dev->sem); /* not interruptible */
++
++ minor = dev->minor;
++
++ /* give back our minor */
++ usb_deregister_dev(interface, &adu_class);
++ dev->minor = 0;
++
++ /* if the device is not opened, then we clean up right now */
++ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
++ if (!dev->open_count) {
++ up(&dev->sem);
++ adu_delete(dev);
++ } else {
++ dev->udev = NULL;
++ up(&dev->sem);
++ }
++
++ mutex_unlock(&disconnect_mutex);
++
++ dev_info(&interface->dev, "ADU device adutux%d now disconnected",
++ (minor - ADU_MINOR_BASE));
++
++ dbg(2," %s : leave", __FUNCTION__);
++}
++
++/* usb specific object needed to register this driver with the usb subsystem */
++static struct usb_driver adu_driver = {
++ .name = "adutux",
++ .probe = adu_probe,
++ .disconnect = adu_disconnect,
++ .id_table = device_table,
++};
++
++static int __init adu_init(void)
++{
++ int result;
++
++ dbg(2," %s : enter", __FUNCTION__);
++
++ /* register this driver with the USB subsystem */
++ result = usb_register(&adu_driver);
++ if (result < 0) {
++ err("usb_register failed for the "__FILE__" driver. "
++ "Error number %d", result);
++ goto exit;
++ }
++
++ info("adutux " DRIVER_DESC " " DRIVER_VERSION);
++ info("adutux is an experimental driver. Use at your own risk");
++
++exit:
++ dbg(2," %s : leave, return value %d", __FUNCTION__, result);
++
++ return result;
++}
++
++static void __exit adu_exit(void)
++{
++ dbg(2," %s : enter", __FUNCTION__);
++ /* deregister this driver with the USB subsystem */
++ usb_deregister(&adu_driver);
++ dbg(2," %s : leave", __FUNCTION__);
++}
++
++module_init(adu_init);
++module_exit(adu_exit);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
+index bfde82f..6b23a1d 100644
+--- a/drivers/usb/misc/appledisplay.c
++++ b/drivers/usb/misc/appledisplay.c
+@@ -20,7 +20,6 @@
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+@@ -85,7 +84,7 @@ struct appledisplay {
+ static atomic_t count_displays = ATOMIC_INIT(0);
+ static struct workqueue_struct *wq;
+
+-static void appledisplay_complete(struct urb *urb, struct pt_regs *regs)
++static void appledisplay_complete(struct urb *urb)
+ {
+ struct appledisplay *pdata = urb->context;
+ unsigned long flags;
+diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
+index 1fef36e..0be9d62 100644
+--- a/drivers/usb/misc/auerswald.c
++++ b/drivers/usb/misc/auerswald.c
+@@ -267,7 +267,7 @@ typedef struct
+
+ /*-------------------------------------------------------------------*/
+ /* Forwards */
+-static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs);
++static void auerswald_ctrlread_complete (struct urb * urb);
+ static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
+ static struct usb_driver auerswald_driver;
+
+@@ -277,7 +277,7 @@ static struct usb_driver auerswald_drive
+ /* -------------------------- */
+
+ /* completion function for chained urbs */
+-static void auerchain_complete (struct urb * urb, struct pt_regs *regs)
++static void auerchain_complete (struct urb * urb)
+ {
+ unsigned long flags;
+ int result;
+@@ -296,7 +296,7 @@ static void auerchain_complete (struct u
+ NOTE: this function may lead to more urbs submitted into the chain.
+ (no chain lock at calling complete()!)
+ acp->active != NULL is protecting us against recursion.*/
+- urb->complete (urb, regs);
++ urb->complete (urb);
+
+ /* detach element from chain data structure */
+ spin_lock_irqsave (&acp->lock, flags);
+@@ -331,7 +331,7 @@ static void auerchain_complete (struct u
+ urb->status = result;
+ dbg("auerchain_complete: usb_submit_urb with error code %d", result);
+ /* and do error handling via *this* completion function (recursive) */
+- auerchain_complete( urb, NULL);
++ auerchain_complete( urb);
+ }
+ } else {
+ /* simple return without submitting a new urb.
+@@ -408,7 +408,7 @@ static int auerchain_submit_urb_list (pa
+ urb->status = result;
+ dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
+ /* and do error handling via completion function */
+- auerchain_complete( urb, NULL);
++ auerchain_complete( urb);
+ }
+ }
+
+@@ -448,7 +448,7 @@ static int auerchain_unlink_urb (pauerch
+ spin_unlock_irqrestore (&acp->lock, flags);
+ dbg ("unlink waiting urb");
+ urb->status = -ENOENT;
+- urb->complete (urb, NULL);
++ urb->complete (urb);
+ return 0;
+ }
+ }
+@@ -505,7 +505,7 @@ static void auerchain_unlink_all (pauerc
+ spin_unlock_irqrestore (&acp->lock, flags);
+ dbg ("unlink waiting urb");
+ urbp->status = -ENOENT;
+- urbp->complete (urbp, NULL);
++ urbp->complete (urbp);
+ spin_lock_irqsave (&acp->lock, flags);
+ }
+ spin_unlock_irqrestore (&acp->lock, flags);
+@@ -591,7 +591,7 @@ ac_fail:/* free the elements */
+
+
+ /* completion handler for synchronous chained URBs */
+-static void auerchain_blocking_completion (struct urb *urb, struct pt_regs *regs)
++static void auerchain_blocking_completion (struct urb *urb)
+ {
+ pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
+ pchs->done = 1;
+@@ -806,7 +806,7 @@ static void auerbuf_releasebuf( pauerbuf
+ 0 Initial, OK
+ -EINPROGRESS during submission until end
+ -ENOENT if urb is unlinked
+--ETIMEDOUT Transfer timed out, NAK
++-ETIME Device did not respond
+ -ENOMEM Memory Overflow
+ -ENODEV Specified USB-device or bus doesn't exist
+ -ENXIO URB already queued
+@@ -832,7 +832,7 @@ static int auerswald_status_retry (int s
+ {
+ switch (status) {
+ case 0:
+- case -ETIMEDOUT:
++ case -ETIME:
+ case -EOVERFLOW:
+ case -EAGAIN:
+ case -EPIPE:
+@@ -846,7 +846,7 @@ static int auerswald_status_retry (int s
+ }
+
+ /* Completion of asynchronous write block */
+-static void auerchar_ctrlwrite_complete (struct urb * urb, struct pt_regs *regs)
++static void auerchar_ctrlwrite_complete (struct urb * urb)
+ {
+ pauerbuf_t bp = (pauerbuf_t) urb->context;
+ pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
+@@ -859,7 +859,7 @@ static void auerchar_ctrlwrite_complete
+ }
+
+ /* Completion handler for dummy retry packet */
+-static void auerswald_ctrlread_wretcomplete (struct urb * urb, struct pt_regs *regs)
++static void auerswald_ctrlread_wretcomplete (struct urb * urb)
+ {
+ pauerbuf_t bp = (pauerbuf_t) urb->context;
+ pauerswald_t cp;
+@@ -893,12 +893,12 @@ static void auerswald_ctrlread_wretcompl
+ if (ret) {
+ dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
+ bp->urbp->status = ret;
+- auerswald_ctrlread_complete (bp->urbp, NULL);
++ auerswald_ctrlread_complete (bp->urbp);
+ }
+ }
+
+ /* completion handler for receiving of control messages */
+-static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs)
++static void auerswald_ctrlread_complete (struct urb * urb)
+ {
+ unsigned int serviceid;
+ pauerswald_t cp;
+@@ -941,7 +941,7 @@ static void auerswald_ctrlread_complete
+ if (ret) {
+ dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
+ bp->urbp->status = ret;
+- auerswald_ctrlread_wretcomplete (bp->urbp, regs);
++ auerswald_ctrlread_wretcomplete (bp->urbp);
+ }
+ return;
+ }
+@@ -970,7 +970,7 @@ static void auerswald_ctrlread_complete
+ messages from the USB device.
+ */
+ /* int completion handler. */
+-static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs)
++static void auerswald_int_complete (struct urb * urb)
+ {
+ unsigned long flags;
+ unsigned int channelid;
+@@ -1070,7 +1070,7 @@ static void auerswald_int_complete (stru
+ if (ret) {
+ dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret);
+ bp->urbp->status = ret;
+- auerswald_ctrlread_complete( bp->urbp, NULL);
++ auerswald_ctrlread_complete( bp->urbp);
+ /* here applies the same problem as above: device locking! */
+ }
+ exit:
+@@ -1858,7 +1858,7 @@ static int auerchar_release (struct inod
+
+ /*----------------------------------------------------------------------*/
+ /* File operation structure */
+-static struct file_operations auerswald_fops =
++static const struct file_operations auerswald_fops =
+ {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
+index 9c46746..b63b5f3 100644
+--- a/drivers/usb/misc/cypress_cy7c63.c
++++ b/drivers/usb/misc/cypress_cy7c63.c
+@@ -209,7 +209,7 @@ static int cypress_probe(struct usb_inte
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory!\n");
+- goto error;
++ goto error_mem;
+ }
+
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+@@ -218,15 +218,26 @@ static int cypress_probe(struct usb_inte
+ usb_set_intfdata(interface, dev);
+
+ /* create device attribute files */
+- device_create_file(&interface->dev, &dev_attr_port0);
+- device_create_file(&interface->dev, &dev_attr_port1);
++ retval = device_create_file(&interface->dev, &dev_attr_port0);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_port1);
++ if (retval)
++ goto error;
+
+ /* let the user know that the device is now attached */
+ dev_info(&interface->dev,
+ "Cypress CY7C63xxx device now attached\n");
++ return 0;
+
+- retval = 0;
+ error:
++ device_remove_file(&interface->dev, &dev_attr_port0);
++ device_remove_file(&interface->dev, &dev_attr_port1);
++ usb_set_intfdata(interface, NULL);
++ usb_put_dev(dev->udev);
++ kfree(dev);
++
++error_mem:
+ return retval;
+ }
+
+diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
+index b20bec4..04e87ac 100644
+--- a/drivers/usb/misc/cytherm.c
++++ b/drivers/usb/misc/cytherm.c
+@@ -353,7 +353,7 @@ static int cytherm_probe(struct usb_inte
+ dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err (&interface->dev, "Out of memory\n");
+- goto error;
++ goto error_mem;
+ }
+
+ dev->udev = usb_get_dev(udev);
+@@ -362,18 +362,35 @@ static int cytherm_probe(struct usb_inte
+
+ dev->brightness = 0xFF;
+
+- device_create_file(&interface->dev, &dev_attr_brightness);
+- device_create_file(&interface->dev, &dev_attr_temp);
+- device_create_file(&interface->dev, &dev_attr_button);
+- device_create_file(&interface->dev, &dev_attr_port0);
+- device_create_file(&interface->dev, &dev_attr_port1);
++ retval = device_create_file(&interface->dev, &dev_attr_brightness);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_temp);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_button);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_port0);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_port1);
++ if (retval)
++ goto error;
+
+- dev_info (&interface->dev,
++ dev_info (&interface->dev,
+ "Cypress thermometer device now attached\n");
+ return 0;
+-
+- error:
++error:
++ device_remove_file(&interface->dev, &dev_attr_brightness);
++ device_remove_file(&interface->dev, &dev_attr_temp);
++ device_remove_file(&interface->dev, &dev_attr_button);
++ device_remove_file(&interface->dev, &dev_attr_port0);
++ device_remove_file(&interface->dev, &dev_attr_port1);
++ usb_set_intfdata (interface, NULL);
++ usb_put_dev(dev->udev);
+ kfree(dev);
++error_mem:
+ return retval;
+ }
+
+diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
+new file mode 100644
+index 0000000..9b591b8
+--- /dev/null
++++ b/drivers/usb/misc/ftdi-elan.c
+@@ -0,0 +1,2794 @@
++/*
++* USB FTDI client driver for Elan Digital Systems's Uxxx adapters
++*
++* Copyright(C) 2006 Elan Digital Systems Limited
++* http://www.elandigitalsystems.com
++*
++* Author and Maintainer - Tony Olech - Elan Digital Systems
++* tony.olech at elandigitalsystems.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 was written by Tony Olech(tony.olech at elandigitalsystems.com)
++* based on various USB client drivers in the 2.6.15 linux kernel
++* with constant reference to the 3rd Edition of Linux Device Drivers
++* published by O'Reilly
++*
++* The U132 adapter is a USB to CardBus adapter specifically designed
++* for PC cards that contain an OHCI host controller. Typical PC cards
++* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
++*
++* The U132 adapter will *NOT *work with PC cards that do not contain
++* an OHCI controller. A simple way to test whether a PC card has an
++* OHCI controller as an interface is to insert the PC card directly
++* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
++* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
++* then there is a good chance that the U132 adapter will support the
++* PC card.(you also need the specific client driver for the PC card)
++*
++* Please inform the Author and Maintainer about any PC cards that
++* contain OHCI Host Controller and work when directly connected to
++* an embedded CardBus slot but do not work when they are connected
++* via an ELAN U132 adapter.
++*
++*/
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/ioctl.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/kref.h>
++#include <asm/uaccess.h>
++#include <linux/usb.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++MODULE_AUTHOR("Tony Olech");
++MODULE_DESCRIPTION("FTDI ELAN driver");
++MODULE_LICENSE("GPL");
++#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
++extern struct platform_driver u132_platform_driver;
++static struct workqueue_struct *status_queue;
++static struct workqueue_struct *command_queue;
++static struct workqueue_struct *respond_queue;
++/*
++* ftdi_module_lock exists to protect access to global variables
++*
++*/
++static struct semaphore ftdi_module_lock;
++static int ftdi_instances = 0;
++static struct list_head ftdi_static_list;
++/*
++* end of the global variables protected by ftdi_module_lock
++*/
++#include "usb_u132.h"
++#define TD_DEVNOTRESP 5
++/* Define these values to match your devices*/
++#define USB_FTDI_ELAN_VENDOR_ID 0x0403
++#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
++/* table of devices that work with this driver*/
++static struct usb_device_id ftdi_elan_table[] = {
++ {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
++ { /* Terminating entry */ }
++};
++
++MODULE_DEVICE_TABLE(usb, ftdi_elan_table);
++/* only the jtag(firmware upgrade device) interface requires
++* a device file and corresponding minor number, but the
++* interface is created unconditionally - I suppose it could
++* be configured or not according to a module parameter.
++* But since we(now) require one interface per device,
++* and since it unlikely that a normal installation would
++* require more than a couple of elan-ftdi devices, 8 seems
++* like a reasonable limit to have here, and if someone
++* really requires more than 8 devices, then they can frig the
++* code and recompile
++*/
++#define USB_FTDI_ELAN_MINOR_BASE 192
++#define COMMAND_BITS 5
++#define COMMAND_SIZE (1<<COMMAND_BITS)
++#define COMMAND_MASK (COMMAND_SIZE-1)
++struct u132_command {
++ u8 header;
++ u16 length;
++ u8 address;
++ u8 width;
++ u32 value;
++ int follows;
++ void *buffer;
++};
++#define RESPOND_BITS 5
++#define RESPOND_SIZE (1<<RESPOND_BITS)
++#define RESPOND_MASK (RESPOND_SIZE-1)
++struct u132_respond {
++ u8 header;
++ u8 address;
++ u32 *value;
++ int *result;
++ struct completion wait_completion;
++};
++struct u132_target {
++ void *endp;
++ struct urb *urb;
++ int toggle_bits;
++ int error_count;
++ int condition_code;
++ int repeat_number;
++ int halted;
++ int skipped;
++ int actual;
++ int non_null;
++ int active;
++ int abandoning;
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code,
++ int repeat_number, int halted, int skipped, int actual,
++ int non_null);
++};
++/* Structure to hold all of our device specific stuff*/
++struct usb_ftdi {
++ struct list_head ftdi_list;
++ struct semaphore u132_lock;
++ int command_next;
++ int command_head;
++ struct u132_command command[COMMAND_SIZE];
++ int respond_next;
++ int respond_head;
++ struct u132_respond respond[RESPOND_SIZE];
++ struct u132_target target[4];
++ char device_name[16];
++ unsigned synchronized:1;
++ unsigned enumerated:1;
++ unsigned registered:1;
++ unsigned initialized:1;
++ unsigned card_ejected:1;
++ int function;
++ int sequence_num;
++ int disconnected;
++ int gone_away;
++ int stuck_status;
++ int status_queue_delay;
++ struct semaphore sw_lock;
++ struct usb_device *udev;
++ struct usb_interface *interface;
++ struct usb_class_driver *class;
++ struct work_struct status_work;
++ struct work_struct command_work;
++ struct work_struct respond_work;
++ struct u132_platform_data platform_data;
++ struct resource resources[0];
++ struct platform_device platform_dev;
++ unsigned char *bulk_in_buffer;
++ size_t bulk_in_size;
++ size_t bulk_in_last;
++ size_t bulk_in_left;
++ __u8 bulk_in_endpointAddr;
++ __u8 bulk_out_endpointAddr;
++ struct kref kref;
++ u32 controlreg;
++ u8 response[4 + 1024];
++ int expected;
++ int recieved;
++ int ed_found;
++};
++#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref)
++#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \
++ platform_dev)
++static struct usb_driver ftdi_elan_driver;
++static void ftdi_elan_delete(struct kref *kref)
++{
++ struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref);
++ dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
++ usb_put_dev(ftdi->udev);
++ ftdi->disconnected += 1;
++ down(&ftdi_module_lock);
++ list_del_init(&ftdi->ftdi_list);
++ ftdi_instances -= 1;
++ up(&ftdi_module_lock);
++ kfree(ftdi->bulk_in_buffer);
++ ftdi->bulk_in_buffer = NULL;
++}
++
++static void ftdi_elan_put_kref(struct usb_ftdi *ftdi)
++{
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++}
++
++static void ftdi_elan_get_kref(struct usb_ftdi *ftdi)
++{
++ kref_get(&ftdi->kref);
++}
++
++static void ftdi_elan_init_kref(struct usb_ftdi *ftdi)
++{
++ kref_init(&ftdi->kref);
++}
++
++static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
++ return;
++ } else if (queue_work(status_queue, &ftdi->status_work))
++ return;
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++ return;
++}
++
++static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
++ kref_get(&ftdi->kref);
++ } else if (queue_work(status_queue, &ftdi->status_work))
++ kref_get(&ftdi->kref);
++ return;
++}
++
++static void ftdi_status_cancel_work(struct usb_ftdi *ftdi)
++{
++ if (cancel_delayed_work(&ftdi->status_work))
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++}
++
++static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(command_queue, &ftdi->command_work,
++ delta))
++ return;
++ } else if (queue_work(command_queue, &ftdi->command_work))
++ return;
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++ return;
++}
++
++static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(command_queue, &ftdi->command_work,
++ delta))
++ kref_get(&ftdi->kref);
++ } else if (queue_work(command_queue, &ftdi->command_work))
++ kref_get(&ftdi->kref);
++ return;
++}
++
++static void ftdi_command_cancel_work(struct usb_ftdi *ftdi)
++{
++ if (cancel_delayed_work(&ftdi->command_work))
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++}
++
++static void ftdi_response_requeue_work(struct usb_ftdi *ftdi,
++ unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(respond_queue, &ftdi->respond_work,
++ delta))
++ return;
++ } else if (queue_work(respond_queue, &ftdi->respond_work))
++ return;
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++ return;
++}
++
++static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
++{
++ if (delta > 0) {
++ if (queue_delayed_work(respond_queue, &ftdi->respond_work,
++ delta))
++ kref_get(&ftdi->kref);
++ } else if (queue_work(respond_queue, &ftdi->respond_work))
++ kref_get(&ftdi->kref);
++ return;
++}
++
++static void ftdi_response_cancel_work(struct usb_ftdi *ftdi)
++{
++ if (cancel_delayed_work(&ftdi->respond_work))
++ kref_put(&ftdi->kref, ftdi_elan_delete);
++}
++
++void ftdi_elan_gone_away(struct platform_device *pdev)
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ ftdi->gone_away += 1;
++ ftdi_elan_put_kref(ftdi);
++}
++
++
++EXPORT_SYMBOL_GPL(ftdi_elan_gone_away);
++void ftdi_release_platform_dev(struct device *dev)
++{
++ dev->parent = NULL;
++}
++
++static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
++ struct u132_target *target, u8 *buffer, int length);
++static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi);
++static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi);
++static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi);
++static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi);
++static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi);
++static int ftdi_elan_synchronize(struct usb_ftdi *ftdi);
++static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi);
++static int ftdi_elan_command_engine(struct usb_ftdi *ftdi);
++static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);
++static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)
++{
++ int result;
++ if (ftdi->platform_dev.dev.parent)
++ return -EBUSY;
++ ftdi_elan_get_kref(ftdi);
++ ftdi->platform_data.potpg = 100;
++ ftdi->platform_data.reset = NULL;
++ ftdi->platform_dev.id = ftdi->sequence_num;
++ ftdi->platform_dev.resource = ftdi->resources;
++ ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources);
++ ftdi->platform_dev.dev.platform_data = &ftdi->platform_data;
++ ftdi->platform_dev.dev.parent = NULL;
++ ftdi->platform_dev.dev.release = ftdi_release_platform_dev;
++ ftdi->platform_dev.dev.dma_mask = NULL;
++ snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd");
++ ftdi->platform_dev.name = ftdi->device_name;
++ dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd");
++ request_module("u132_hcd");
++ dev_info(&ftdi->udev->dev, "registering '%s'\n",
++ ftdi->platform_dev.name);
++ result = platform_device_register(&ftdi->platform_dev);
++ return result;
++}
++
++static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
++{
++ down(&ftdi->u132_lock);
++ while (ftdi->respond_next > ftdi->respond_head) {
++ struct u132_respond *respond = &ftdi->respond[RESPOND_MASK &
++ ftdi->respond_head++];
++ *respond->result = -ESHUTDOWN;
++ *respond->value = 0;
++ complete(&respond->wait_completion);
++ } up(&ftdi->u132_lock);
++}
++
++static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
++{
++ int ed_number = 4;
++ down(&ftdi->u132_lock);
++ while (ed_number-- > 0) {
++ struct u132_target *target = &ftdi->target[ed_number];
++ if (target->active == 1) {
++ target->condition_code = TD_DEVNOTRESP;
++ up(&ftdi->u132_lock);
++ ftdi_elan_do_callback(ftdi, target, NULL, 0);
++ down(&ftdi->u132_lock);
++ }
++ }
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ up(&ftdi->u132_lock);
++}
++
++static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
++{
++ int ed_number = 4;
++ down(&ftdi->u132_lock);
++ while (ed_number-- > 0) {
++ struct u132_target *target = &ftdi->target[ed_number];
++ target->abandoning = 1;
++ wait_1:if (target->active == 1) {
++ int command_size = ftdi->command_next -
++ ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x80 | (ed_number << 5) | 0x4;
++ command->length = 0x00;
++ command->address = 0x00;
++ command->width = 0x00;
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ down(&ftdi->u132_lock);
++ goto wait_1;
++ }
++ }
++ wait_2:if (target->active == 1) {
++ int command_size = ftdi->command_next -
++ ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x90 | (ed_number << 5);
++ command->length = 0x00;
++ command->address = 0x00;
++ command->width = 0x00;
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ down(&ftdi->u132_lock);
++ goto wait_2;
++ }
++ }
++ }
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ up(&ftdi->u132_lock);
++}
++
++static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
++{
++ int ed_number = 4;
++ down(&ftdi->u132_lock);
++ while (ed_number-- > 0) {
++ struct u132_target *target = &ftdi->target[ed_number];
++ target->abandoning = 1;
++ wait:if (target->active == 1) {
++ int command_size = ftdi->command_next -
++ ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x80 | (ed_number << 5) | 0x4;
++ command->length = 0x00;
++ command->address = 0x00;
++ command->width = 0x00;
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ down(&ftdi->u132_lock);
++ goto wait;
++ }
++ }
++ }
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ up(&ftdi->u132_lock);
++}
++
++static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
++{
++ ftdi_command_queue_work(ftdi, 0);
++ return;
++}
++
++static void ftdi_elan_command_work(void *data)
++{
++ struct usb_ftdi *ftdi = data;
++ if (ftdi->disconnected > 0) {
++ ftdi_elan_put_kref(ftdi);
++ return;
++ } else {
++ int retval = ftdi_elan_command_engine(ftdi);
++ if (retval == -ESHUTDOWN) {
++ ftdi->disconnected += 1;
++ } else if (retval == -ENODEV) {
++ ftdi->disconnected += 1;
++ } else if (retval)
++ dev_err(&ftdi->udev->dev, "command error %d\n", retval);
++ ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10));
++ return;
++ }
++}
++
++static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)
++{
++ ftdi_respond_queue_work(ftdi, 0);
++ return;
++}
++
++static void ftdi_elan_respond_work(void *data)
++{
++ struct usb_ftdi *ftdi = data;
++ if (ftdi->disconnected > 0) {
++ ftdi_elan_put_kref(ftdi);
++ return;
++ } else {
++ int retval = ftdi_elan_respond_engine(ftdi);
++ if (retval == 0) {
++ } else if (retval == -ESHUTDOWN) {
++ ftdi->disconnected += 1;
++ } else if (retval == -ENODEV) {
++ ftdi->disconnected += 1;
++ } else if (retval == -EILSEQ) {
++ ftdi->disconnected += 1;
++ } else {
++ ftdi->disconnected += 1;
++ dev_err(&ftdi->udev->dev, "respond error %d\n", retval);
++ }
++ if (ftdi->disconnected > 0) {
++ ftdi_elan_abandon_completions(ftdi);
++ ftdi_elan_abandon_targets(ftdi);
++ }
++ ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10));
++ return;
++ }
++}
++
++
++/*
++* the sw_lock is initially held and will be freed
++* after the FTDI has been synchronized
++*
++*/
++static void ftdi_elan_status_work(void *data)
++{
++ struct usb_ftdi *ftdi = data;
++ int work_delay_in_msec = 0;
++ if (ftdi->disconnected > 0) {
++ ftdi_elan_put_kref(ftdi);
++ return;
++ } else if (ftdi->synchronized == 0) {
++ down(&ftdi->sw_lock);
++ if (ftdi_elan_synchronize(ftdi) == 0) {
++ ftdi->synchronized = 1;
++ ftdi_command_queue_work(ftdi, 1);
++ ftdi_respond_queue_work(ftdi, 1);
++ up(&ftdi->sw_lock);
++ work_delay_in_msec = 100;
++ } else {
++ dev_err(&ftdi->udev->dev, "synchronize failed\n");
++ up(&ftdi->sw_lock);
++ work_delay_in_msec = 10 *1000;
++ }
++ } else if (ftdi->stuck_status > 0) {
++ if (ftdi_elan_stuck_waiting(ftdi) == 0) {
++ ftdi->stuck_status = 0;
++ ftdi->synchronized = 0;
++ } else if ((ftdi->stuck_status++ % 60) == 1) {
++ dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
++ "- please remove\n");
++ } else
++ dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
++ "- checked %d times\n", ftdi->stuck_status);
++ work_delay_in_msec = 100;
++ } else if (ftdi->enumerated == 0) {
++ if (ftdi_elan_enumeratePCI(ftdi) == 0) {
++ ftdi->enumerated = 1;
++ work_delay_in_msec = 250;
++ } else
++ work_delay_in_msec = 1000;
++ } else if (ftdi->initialized == 0) {
++ if (ftdi_elan_setupOHCI(ftdi) == 0) {
++ ftdi->initialized = 1;
++ work_delay_in_msec = 500;
++ } else {
++ dev_err(&ftdi->udev->dev, "initialized failed - trying "
++ "again in 10 seconds\n");
++ work_delay_in_msec = 10 *1000;
++ }
++ } else if (ftdi->registered == 0) {
++ work_delay_in_msec = 10;
++ if (ftdi_elan_hcd_init(ftdi) == 0) {
++ ftdi->registered = 1;
++ } else
++ dev_err(&ftdi->udev->dev, "register failed\n");
++ work_delay_in_msec = 250;
++ } else {
++ if (ftdi_elan_checkingPCI(ftdi) == 0) {
++ work_delay_in_msec = 250;
++ } else if (ftdi->controlreg & 0x00400000) {
++ if (ftdi->gone_away > 0) {
++ dev_err(&ftdi->udev->dev, "PCI device eject con"
++ "firmed platform_dev.dev.parent=%p plat"
++ "form_dev.dev=%p\n",
++ ftdi->platform_dev.dev.parent,
++ &ftdi->platform_dev.dev);
++ platform_device_unregister(&ftdi->platform_dev);
++ ftdi->platform_dev.dev.parent = NULL;
++ ftdi->registered = 0;
++ ftdi->enumerated = 0;
++ ftdi->card_ejected = 0;
++ ftdi->initialized = 0;
++ ftdi->gone_away = 0;
++ } else
++ ftdi_elan_flush_targets(ftdi);
++ work_delay_in_msec = 250;
++ } else {
++ dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"
++ );
++ ftdi_elan_cancel_targets(ftdi);
++ work_delay_in_msec = 500;
++ ftdi->enumerated = 0;
++ ftdi->initialized = 0;
++ }
++ }
++ if (ftdi->disconnected > 0) {
++ ftdi_elan_put_kref(ftdi);
++ return;
++ } else {
++ ftdi_status_requeue_work(ftdi,
++ msecs_to_jiffies(work_delay_in_msec));
++ return;
++ }
++}
++
++
++/*
++* file_operations for the jtag interface
++*
++* the usage count for the device is incremented on open()
++* and decremented on release()
++*/
++static int ftdi_elan_open(struct inode *inode, struct file *file)
++{
++ int subminor = iminor(inode);
++ struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver,
++ subminor);
++ if (!interface) {
++ printk(KERN_ERR "can't find device for minor %d\n", subminor);
++ return -ENODEV;
++ } else {
++ struct usb_ftdi *ftdi = usb_get_intfdata(interface);
++ if (!ftdi) {
++ return -ENODEV;
++ } else {
++ if (down_interruptible(&ftdi->sw_lock)) {
++ return -EINTR;
++ } else {
++ ftdi_elan_get_kref(ftdi);
++ file->private_data = ftdi;
++ return 0;
++ }
++ }
++ }
++}
++
++static int ftdi_elan_release(struct inode *inode, struct file *file)
++{
++ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
++ if (ftdi == NULL)
++ return -ENODEV;
++ up(&ftdi->sw_lock); /* decrement the count on our device */
++ ftdi_elan_put_kref(ftdi);
++ return 0;
++}
++
++
++#define FTDI_ELAN_IOC_MAGIC 0xA1
++#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132)
++static int ftdi_elan_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ case FTDI_ELAN_IOCDEBUG:{
++ char line[132];
++ int size = strncpy_from_user(line,
++ (const char __user *)arg, sizeof(line));
++ if (size < 0) {
++ return -EINVAL;
++ } else {
++ printk(KERN_ERR "TODO: ioctl %s\n", line);
++ return 0;
++ }
++ }
++ default:
++ return -EFAULT;
++ }
++}
++
++
++/*
++*
++* blocking bulk reads are used to get data from the device
++*
++*/
++static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
++ size_t count, loff_t *ppos)
++{
++ char data[30 *3 + 4];
++ char *d = data;
++ int m = (sizeof(data) - 1) / 3;
++ int bytes_read = 0;
++ int retry_on_empty = 10;
++ int retry_on_timeout = 5;
++ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
++ if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ }
++ data[0] = 0;
++ have:if (ftdi->bulk_in_left > 0) {
++ if (count-- > 0) {
++ char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer;
++ ftdi->bulk_in_left -= 1;
++ if (bytes_read < m) {
++ d += sprintf(d, " %02X", 0x000000FF & *p);
++ } else if (bytes_read > m) {
++ } else
++ d += sprintf(d, " ..");
++ if (copy_to_user(buffer++, p, 1)) {
++ return -EFAULT;
++ } else {
++ bytes_read += 1;
++ goto have;
++ }
++ } else
++ return bytes_read;
++ }
++ more:if (count > 0) {
++ int packet_bytes = 0;
++ int retval = usb_bulk_msg(ftdi->udev,
++ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
++ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
++ &packet_bytes, msecs_to_jiffies(50));
++ if (packet_bytes > 2) {
++ ftdi->bulk_in_left = packet_bytes - 2;
++ ftdi->bulk_in_last = 1;
++ goto have;
++ } else if (retval == -ETIMEDOUT) {
++ if (retry_on_timeout-- > 0) {
++ goto more;
++ } else if (bytes_read > 0) {
++ return bytes_read;
++ } else
++ return retval;
++ } else if (retval == 0) {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else
++ return bytes_read;
++ } else
++ return retval;
++ } else
++ return bytes_read;
++}
++
++static void ftdi_elan_write_bulk_callback(struct urb *urb)
++{
++ struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
++ if (urb->status && !(urb->status == -ENOENT || urb->status ==
++ -ECONNRESET || urb->status == -ESHUTDOWN)) {
++ dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
++ "d\n", urb, urb->status);
++ }
++ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
++ urb->transfer_buffer, urb->transfer_dma);
++}
++
++static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi,
++ char *buf, int command_size, int total_size)
++{
++ int ed_commands = 0;
++ int b = 0;
++ int I = command_size;
++ int i = ftdi->command_head;
++ while (I-- > 0) {
++ struct u132_command *command = &ftdi->command[COMMAND_MASK &
++ i++];
++ int F = command->follows;
++ u8 *f = command->buffer;
++ if (command->header & 0x80) {
++ ed_commands |= 1 << (0x3 & (command->header >> 5));
++ }
++ buf[b++] = command->header;
++ buf[b++] = (command->length >> 0) & 0x00FF;
++ buf[b++] = (command->length >> 8) & 0x00FF;
++ buf[b++] = command->address;
++ buf[b++] = command->width;
++ while (F-- > 0) {
++ buf[b++] = *f++;
++ }
++ }
++ return ed_commands;
++}
++
++static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)
++{
++ int total_size = 0;
++ int I = command_size;
++ int i = ftdi->command_head;
++ while (I-- > 0) {
++ struct u132_command *command = &ftdi->command[COMMAND_MASK &
++ i++];
++ total_size += 5 + command->follows;
++ } return total_size;
++}
++
++static int ftdi_elan_command_engine(struct usb_ftdi *ftdi)
++{
++ int retval;
++ char *buf;
++ int ed_commands;
++ int total_size;
++ struct urb *urb;
++ int command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size == 0)
++ return 0;
++ total_size = ftdi_elan_total_command_size(ftdi, command_size);
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm"
++ "ands totaling %d bytes to the Uxxx\n", command_size,
++ total_size);
++ return -ENOMEM;
++ }
++ buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL,
++ &urb->transfer_dma);
++ if (!buf) {
++ dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c"
++ "ommands totaling %d bytes to the Uxxx\n", command_size,
++ total_size);
++ usb_free_urb(urb);
++ return -ENOMEM;
++ }
++ ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf,
++ command_size, total_size);
++ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
++ ftdi->bulk_out_endpointAddr), buf, total_size,
++ ftdi_elan_write_bulk_callback, ftdi);
++ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++ if (ed_commands) {
++ char diag[40 *3 + 4];
++ char *d = diag;
++ int m = total_size;
++ u8 *c = buf;
++ int s = (sizeof(diag) - 1) / 3;
++ diag[0] = 0;
++ while (s-- > 0 && m-- > 0) {
++ if (s > 0 || m == 0) {
++ d += sprintf(d, " %02X", *c++);
++ } else
++ d += sprintf(d, " ..");
++ }
++ }
++ retval = usb_submit_urb(urb, GFP_KERNEL);
++ if (retval) {
++ dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write "
++ "%d commands totaling %d bytes to the Uxxx\n", retval,
++ urb, command_size, total_size);
++ usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma);
++ usb_free_urb(urb);
++ return retval;
++ }
++ usb_free_urb(urb); /* release our reference to this urb,
++ the USB core will eventually free it entirely */
++ ftdi->command_head += command_size;
++ ftdi_elan_kick_respond_queue(ftdi);
++ return 0;
++}
++
++static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
++ struct u132_target *target, u8 *buffer, int length)
++{
++ struct urb *urb = target->urb;
++ int halted = target->halted;
++ int skipped = target->skipped;
++ int actual = target->actual;
++ int non_null = target->non_null;
++ int toggle_bits = target->toggle_bits;
++ int error_count = target->error_count;
++ int condition_code = target->condition_code;
++ int repeat_number = target->repeat_number;
++ void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int,
++ int, int, int, int) = target->callback;
++ target->active -= 1;
++ target->callback = NULL;
++ (*callback) (target->endp, urb, buffer, length, toggle_bits,
++ error_count, condition_code, repeat_number, halted, skipped,
++ actual, non_null);
++}
++
++static char *have_ed_set_response(struct usb_ftdi *ftdi,
++ struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
++ char *b)
++{
++ int payload = (ed_length >> 0) & 0x07FF;
++ down(&ftdi->u132_lock);
++ target->actual = 0;
++ target->non_null = (ed_length >> 15) & 0x0001;
++ target->repeat_number = (ed_length >> 11) & 0x000F;
++ if (ed_type == 0x02) {
++ if (payload == 0 || target->abandoning > 0) {
++ target->abandoning = 0;
++ up(&ftdi->u132_lock);
++ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
++ payload);
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ return ftdi->response;
++ } else {
++ ftdi->expected = 4 + payload;
++ ftdi->ed_found = 1;
++ up(&ftdi->u132_lock);
++ return b;
++ }
++ } else if (ed_type == 0x03) {
++ if (payload == 0 || target->abandoning > 0) {
++ target->abandoning = 0;
++ up(&ftdi->u132_lock);
++ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
++ payload);
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ return ftdi->response;
++ } else {
++ ftdi->expected = 4 + payload;
++ ftdi->ed_found = 1;
++ up(&ftdi->u132_lock);
++ return b;
++ }
++ } else if (ed_type == 0x01) {
++ target->abandoning = 0;
++ up(&ftdi->u132_lock);
++ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
++ payload);
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ return ftdi->response;
++ } else {
++ target->abandoning = 0;
++ up(&ftdi->u132_lock);
++ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
++ payload);
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ return ftdi->response;
++ }
++}
++
++static char *have_ed_get_response(struct usb_ftdi *ftdi,
++ struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
++ char *b)
++{
++ down(&ftdi->u132_lock);
++ target->condition_code = TD_DEVNOTRESP;
++ target->actual = (ed_length >> 0) & 0x01FF;
++ target->non_null = (ed_length >> 15) & 0x0001;
++ target->repeat_number = (ed_length >> 11) & 0x000F;
++ up(&ftdi->u132_lock);
++ if (target->active)
++ ftdi_elan_do_callback(ftdi, target, NULL, 0);
++ target->abandoning = 0;
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ return ftdi->response;
++}
++
++
++/*
++* The engine tries to empty the FTDI fifo
++*
++* all responses found in the fifo data are dispatched thus
++* the response buffer can only ever hold a maximum sized
++* response from the Uxxx.
++*
++*/
++static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)
++{
++ u8 *b = ftdi->response + ftdi->recieved;
++ int bytes_read = 0;
++ int retry_on_empty = 1;
++ int retry_on_timeout = 3;
++ int empty_packets = 0;
++ read:{
++ int packet_bytes = 0;
++ int retval = usb_bulk_msg(ftdi->udev,
++ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
++ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
++ &packet_bytes, msecs_to_jiffies(500));
++ char diag[30 *3 + 4];
++ char *d = diag;
++ int m = packet_bytes;
++ u8 *c = ftdi->bulk_in_buffer;
++ int s = (sizeof(diag) - 1) / 3;
++ diag[0] = 0;
++ while (s-- > 0 && m-- > 0) {
++ if (s > 0 || m == 0) {
++ d += sprintf(d, " %02X", *c++);
++ } else
++ d += sprintf(d, " ..");
++ }
++ if (packet_bytes > 2) {
++ ftdi->bulk_in_left = packet_bytes - 2;
++ ftdi->bulk_in_last = 1;
++ goto have;
++ } else if (retval == -ETIMEDOUT) {
++ if (retry_on_timeout-- > 0) {
++ dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
++ "t_bytes = %d with total %d bytes%s\n",
++ packet_bytes, bytes_read, diag);
++ goto more;
++ } else if (bytes_read > 0) {
++ dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n",
++ bytes_read, diag);
++ return -ENOMEM;
++ } else {
++ dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
++ "t_bytes = %d with total %d bytes%s\n",
++ packet_bytes, bytes_read, diag);
++ return -ENOMEM;
++ }
++ } else if (retval == -EILSEQ) {
++ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
++ " = %d with total %d bytes%s\n", retval,
++ packet_bytes, bytes_read, diag);
++ return retval;
++ } else if (retval) {
++ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
++ " = %d with total %d bytes%s\n", retval,
++ packet_bytes, bytes_read, diag);
++ return retval;
++ } else if (packet_bytes == 2) {
++ unsigned char s0 = ftdi->bulk_in_buffer[0];
++ unsigned char s1 = ftdi->bulk_in_buffer[1];
++ empty_packets += 1;
++ if (s0 == 0x31 && s1 == 0x60) {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else
++ return 0;
++ } else if (s0 == 0x31 && s1 == 0x00) {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else
++ return 0;
++ } else {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else
++ return 0;
++ }
++ } else if (packet_bytes == 1) {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else
++ return 0;
++ } else {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else
++ return 0;
++ }
++ }
++ more:{
++ goto read;
++ }
++ have:if (ftdi->bulk_in_left > 0) {
++ u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last];
++ bytes_read += 1;
++ ftdi->bulk_in_left -= 1;
++ if (ftdi->recieved == 0 && c == 0xFF) {
++ goto have;
++ } else
++ *b++ = c;
++ if (++ftdi->recieved < ftdi->expected) {
++ goto have;
++ } else if (ftdi->ed_found) {
++ int ed_number = (ftdi->response[0] >> 5) & 0x03;
++ u16 ed_length = (ftdi->response[2] << 8) |
++ ftdi->response[1];
++ struct u132_target *target = &ftdi->target[ed_number];
++ int payload = (ed_length >> 0) & 0x07FF;
++ char diag[30 *3 + 4];
++ char *d = diag;
++ int m = payload;
++ u8 *c = 4 + ftdi->response;
++ int s = (sizeof(diag) - 1) / 3;
++ diag[0] = 0;
++ while (s-- > 0 && m-- > 0) {
++ if (s > 0 || m == 0) {
++ d += sprintf(d, " %02X", *c++);
++ } else
++ d += sprintf(d, " ..");
++ }
++ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
++ payload);
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ b = ftdi->response;
++ goto have;
++ } else if (ftdi->expected == 8) {
++ u8 buscmd;
++ int respond_head = ftdi->respond_head++;
++ struct u132_respond *respond = &ftdi->respond[
++ RESPOND_MASK & respond_head];
++ u32 data = ftdi->response[7];
++ data <<= 8;
++ data |= ftdi->response[6];
++ data <<= 8;
++ data |= ftdi->response[5];
++ data <<= 8;
++ data |= ftdi->response[4];
++ *respond->value = data;
++ *respond->result = 0;
++ complete(&respond->wait_completion);
++ ftdi->recieved = 0;
++ ftdi->expected = 4;
++ ftdi->ed_found = 0;
++ b = ftdi->response;
++ buscmd = (ftdi->response[0] >> 0) & 0x0F;
++ if (buscmd == 0x00) {
++ } else if (buscmd == 0x02) {
++ } else if (buscmd == 0x06) {
++ } else if (buscmd == 0x0A) {
++ } else
++ dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va"
++ "lue = %08X\n", buscmd, data);
++ goto have;
++ } else {
++ if ((ftdi->response[0] & 0x80) == 0x00) {
++ ftdi->expected = 8;
++ goto have;
++ } else {
++ int ed_number = (ftdi->response[0] >> 5) & 0x03;
++ int ed_type = (ftdi->response[0] >> 0) & 0x03;
++ u16 ed_length = (ftdi->response[2] << 8) |
++ ftdi->response[1];
++ struct u132_target *target = &ftdi->target[
++ ed_number];
++ target->halted = (ftdi->response[0] >> 3) &
++ 0x01;
++ target->skipped = (ftdi->response[0] >> 2) &
++ 0x01;
++ target->toggle_bits = (ftdi->response[3] >> 6)
++ & 0x03;
++ target->error_count = (ftdi->response[3] >> 4)
++ & 0x03;
++ target->condition_code = (ftdi->response[
++ 3] >> 0) & 0x0F;
++ if ((ftdi->response[0] & 0x10) == 0x00) {
++ b = have_ed_set_response(ftdi, target,
++ ed_length, ed_number, ed_type,
++ b);
++ goto have;
++ } else {
++ b = have_ed_get_response(ftdi, target,
++ ed_length, ed_number, ed_type,
++ b);
++ goto have;
++ }
++ }
++ }
++ } else
++ goto more;
++}
++
++
++/*
++* create a urb, and a buffer for it, and copy the data to the urb
++*
++*/
++static ssize_t ftdi_elan_write(struct file *file,
++ const char __user *user_buffer, size_t count,
++ loff_t *ppos)
++{
++ int retval = 0;
++ struct urb *urb;
++ char *buf;
++ struct usb_ftdi *ftdi = file->private_data;
++
++ if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ }
++ if (count == 0) {
++ goto exit;
++ }
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ retval = -ENOMEM;
++ goto error_1;
++ }
++ buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL,
++ &urb->transfer_dma);
++ if (!buf) {
++ retval = -ENOMEM;
++ goto error_2;
++ }
++ if (copy_from_user(buf, user_buffer, count)) {
++ retval = -EFAULT;
++ goto error_3;
++ }
++ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
++ ftdi->bulk_out_endpointAddr), buf, count,
++ ftdi_elan_write_bulk_callback, ftdi);
++ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++ retval = usb_submit_urb(urb, GFP_KERNEL);
++ if (retval) {
++ dev_err(&ftdi->udev->dev, "failed submitting write urb, error %"
++ "d\n", retval);
++ goto error_3;
++ }
++ usb_free_urb(urb);
++
++exit:
++ return count;
++error_3:
++ usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma);
++error_2:
++ usb_free_urb(urb);
++error_1:
++ return retval;
++}
++
++static struct file_operations ftdi_elan_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .ioctl = ftdi_elan_ioctl,
++ .read = ftdi_elan_read,
++ .write = ftdi_elan_write,
++ .open = ftdi_elan_open,
++ .release = ftdi_elan_release,
++};
++
++/*
++* usb class driver info in order to get a minor number from the usb core,
++* and to have the device registered with the driver core
++*/
++static struct usb_class_driver ftdi_elan_jtag_class = {
++ .name = "ftdi-%d-jtag",
++ .fops = &ftdi_elan_fops,
++ .minor_base = USB_FTDI_ELAN_MINOR_BASE,
++};
++
++/*
++* the following definitions are for the
++* ELAN FPGA state machgine processor that
++* lies on the other side of the FTDI chip
++*/
++#define cPCIu132rd 0x0
++#define cPCIu132wr 0x1
++#define cPCIiord 0x2
++#define cPCIiowr 0x3
++#define cPCImemrd 0x6
++#define cPCImemwr 0x7
++#define cPCIcfgrd 0xA
++#define cPCIcfgwr 0xB
++#define cPCInull 0xF
++#define cU132cmd_status 0x0
++#define cU132flash 0x1
++#define cPIDsetup 0x0
++#define cPIDout 0x1
++#define cPIDin 0x2
++#define cPIDinonce 0x3
++#define cCCnoerror 0x0
++#define cCCcrc 0x1
++#define cCCbitstuff 0x2
++#define cCCtoggle 0x3
++#define cCCstall 0x4
++#define cCCnoresp 0x5
++#define cCCbadpid1 0x6
++#define cCCbadpid2 0x7
++#define cCCdataoverrun 0x8
++#define cCCdataunderrun 0x9
++#define cCCbuffoverrun 0xC
++#define cCCbuffunderrun 0xD
++#define cCCnotaccessed 0xF
++static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
++{
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x00 | cPCIu132wr;
++ command->length = 0x04;
++ command->address = 0x00;
++ command->width = 0x00;
++ command->follows = 4;
++ command->value = data;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
++ u8 width, u32 data)
++{
++ u8 addressofs = config_offset / 4;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x00 | (cPCIcfgwr & 0x0F);
++ command->length = 0x04;
++ command->address = addressofs;
++ command->width = 0x00 | (width & 0x0F);
++ command->follows = 4;
++ command->value = data;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
++ u8 width, u32 data)
++{
++ u8 addressofs = mem_offset / 4;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x00 | (cPCImemwr & 0x0F);
++ command->length = 0x04;
++ command->address = addressofs;
++ command->width = 0x00 | (width & 0x0F);
++ command->follows = 4;
++ command->value = data;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset,
++ u8 width, u32 data)
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem);
++static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
++{
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ int respond_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ respond_size = ftdi->respond_next - ftdi->respond_head;
++ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
++ {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ struct u132_respond *respond = &ftdi->respond[
++ RESPOND_MASK & ftdi->respond_next];
++ int result = -ENODEV;
++ respond->result = &result;
++ respond->header = command->header = 0x00 | cPCIu132rd;
++ command->length = 0x04;
++ respond->address = command->address = cU132cmd_status;
++ command->width = 0x00;
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = NULL;
++ respond->value = data;
++ init_completion(&respond->wait_completion);
++ ftdi->command_next += 1;
++ ftdi->respond_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ wait_for_completion(&respond->wait_completion);
++ return result;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data)
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_read_reg(ftdi, data);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_reg);
++static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
++ u8 width, u32 *data)
++{
++ u8 addressofs = config_offset / 4;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ int respond_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ respond_size = ftdi->respond_next - ftdi->respond_head;
++ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
++ {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ struct u132_respond *respond = &ftdi->respond[
++ RESPOND_MASK & ftdi->respond_next];
++ int result = -ENODEV;
++ respond->result = &result;
++ respond->header = command->header = 0x00 | (cPCIcfgrd &
++ 0x0F);
++ command->length = 0x04;
++ respond->address = command->address = addressofs;
++ command->width = 0x00 | (width & 0x0F);
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = NULL;
++ respond->value = data;
++ init_completion(&respond->wait_completion);
++ ftdi->command_next += 1;
++ ftdi->respond_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ wait_for_completion(&respond->wait_completion);
++ return result;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
++ u8 width, u32 *data)
++{
++ u8 addressofs = mem_offset / 4;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ int respond_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ respond_size = ftdi->respond_next - ftdi->respond_head;
++ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
++ {
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ struct u132_respond *respond = &ftdi->respond[
++ RESPOND_MASK & ftdi->respond_next];
++ int result = -ENODEV;
++ respond->result = &result;
++ respond->header = command->header = 0x00 | (cPCImemrd &
++ 0x0F);
++ command->length = 0x04;
++ respond->address = command->address = addressofs;
++ command->width = 0x00 | (width & 0x0F);
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = NULL;
++ respond->value = data;
++ init_completion(&respond->wait_completion);
++ ftdi->command_next += 1;
++ ftdi->respond_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ wait_for_completion(&respond->wait_completion);
++ return result;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset,
++ u8 width, u32 *data)
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else
++ return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem);
++static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ u8 ed = ed_number - 1;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_target *target = &ftdi->target[ed];
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x80 | (ed << 5);
++ command->length = 0x8007;
++ command->address = (toggle_bits << 6) | (ep_number << 2)
++ | (address << 0);
++ command->width = usb_maxpacket(urb->dev, urb->pipe,
++ usb_pipeout(urb->pipe));
++ command->follows = 8;
++ command->value = 0;
++ command->buffer = urb->setup_packet;
++ target->callback = callback;
++ target->endp = endp;
++ target->urb = urb;
++ target->active = 1;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address,
++ ep_number, toggle_bits, callback);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup);
++static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ u8 ed = ed_number - 1;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_target *target = &ftdi->target[ed];
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ int remaining_length = urb->transfer_buffer_length -
++ urb->actual_length;
++ command->header = 0x82 | (ed << 5);
++ if (remaining_length == 0) {
++ command->length = 0x0000;
++ } else if (remaining_length > 1024) {
++ command->length = 0x8000 | 1023;
++ } else
++ command->length = 0x8000 | (remaining_length -
++ 1);
++ command->address = (toggle_bits << 6) | (ep_number << 2)
++ | (address << 0);
++ command->width = usb_maxpacket(urb->dev, urb->pipe,
++ usb_pipeout(urb->pipe));
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = NULL;
++ target->callback = callback;
++ target->endp = endp;
++ target->urb = urb;
++ target->active = 1;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address,
++ ep_number, toggle_bits, callback);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input);
++static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ u8 ed = ed_number - 1;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_target *target = &ftdi->target[ed];
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x81 | (ed << 5);
++ command->length = 0x0000;
++ command->address = (toggle_bits << 6) | (ep_number << 2)
++ | (address << 0);
++ command->width = usb_maxpacket(urb->dev, urb->pipe,
++ usb_pipeout(urb->pipe));
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = NULL;
++ target->callback = callback;
++ target->endp = endp;
++ target->urb = urb;
++ target->active = 1;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address,
++ ep_number, toggle_bits, callback);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty);
++static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ u8 ed = ed_number - 1;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ u8 *b;
++ u16 urb_size;
++ int i = 0;
++ char data[30 *3 + 4];
++ char *d = data;
++ int m = (sizeof(data) - 1) / 3;
++ int l = 0;
++ struct u132_target *target = &ftdi->target[ed];
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x81 | (ed << 5);
++ command->address = (toggle_bits << 6) | (ep_number << 2)
++ | (address << 0);
++ command->width = usb_maxpacket(urb->dev, urb->pipe,
++ usb_pipeout(urb->pipe));
++ command->follows = min(1024,
++ urb->transfer_buffer_length -
++ urb->actual_length);
++ command->value = 0;
++ command->buffer = urb->transfer_buffer +
++ urb->actual_length;
++ command->length = 0x8000 | (command->follows - 1);
++ b = command->buffer;
++ urb_size = command->follows;
++ data[0] = 0;
++ while (urb_size-- > 0) {
++ if (i > m) {
++ } else if (i++ < m) {
++ int w = sprintf(d, " %02X", *b++);
++ d += w;
++ l += w;
++ } else
++ d += sprintf(d, " ..");
++ }
++ target->callback = callback;
++ target->endp = endp;
++ target->urb = urb;
++ target->active = 1;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address,
++ ep_number, toggle_bits, callback);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output);
++static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ u8 ed = ed_number - 1;
++ wait:if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else {
++ int command_size;
++ down(&ftdi->u132_lock);
++ command_size = ftdi->command_next - ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ int remaining_length = urb->transfer_buffer_length -
++ urb->actual_length;
++ struct u132_target *target = &ftdi->target[ed];
++ struct u132_command *command = &ftdi->command[
++ COMMAND_MASK & ftdi->command_next];
++ command->header = 0x83 | (ed << 5);
++ if (remaining_length == 0) {
++ command->length = 0x0000;
++ } else if (remaining_length > 1024) {
++ command->length = 0x8000 | 1023;
++ } else
++ command->length = 0x8000 | (remaining_length -
++ 1);
++ command->address = (toggle_bits << 6) | (ep_number << 2)
++ | (address << 0);
++ command->width = usb_maxpacket(urb->dev, urb->pipe,
++ usb_pipeout(urb->pipe));
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = NULL;
++ target->callback = callback;
++ target->endp = endp;
++ target->urb = urb;
++ target->active = 1;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ goto wait;
++ }
++ }
++}
++
++int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null))
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address,
++ ep_number, toggle_bits, callback);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single);
++static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
++ void *endp)
++{
++ u8 ed = ed_number - 1;
++ if (ftdi->disconnected > 0) {
++ return -ENODEV;
++ } else if (ftdi->initialized == 0) {
++ return -ENODEV;
++ } else {
++ struct u132_target *target = &ftdi->target[ed];
++ down(&ftdi->u132_lock);
++ if (target->abandoning > 0) {
++ up(&ftdi->u132_lock);
++ return 0;
++ } else {
++ target->abandoning = 1;
++ wait_1:if (target->active == 1) {
++ int command_size = ftdi->command_next -
++ ftdi->command_head;
++ if (command_size < COMMAND_SIZE) {
++ struct u132_command *command =
++ &ftdi->command[COMMAND_MASK &
++ ftdi->command_next];
++ command->header = 0x80 | (ed << 5) |
++ 0x4;
++ command->length = 0x00;
++ command->address = 0x00;
++ command->width = 0x00;
++ command->follows = 0;
++ command->value = 0;
++ command->buffer = &command->value;
++ ftdi->command_next += 1;
++ ftdi_elan_kick_command_queue(ftdi);
++ } else {
++ up(&ftdi->u132_lock);
++ msleep(100);
++ down(&ftdi->u132_lock);
++ goto wait_1;
++ }
++ }
++ up(&ftdi->u132_lock);
++ return 0;
++ }
++ }
++}
++
++int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
++ void *endp)
++{
++ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
++ return ftdi_elan_edset_flush(ftdi, ed_number, endp);
++}
++
++
++EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush);
++static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)
++{
++ int retry_on_empty = 10;
++ int retry_on_timeout = 5;
++ int retry_on_status = 20;
++ more:{
++ int packet_bytes = 0;
++ int retval = usb_bulk_msg(ftdi->udev,
++ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
++ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
++ &packet_bytes, msecs_to_jiffies(100));
++ if (packet_bytes > 2) {
++ char diag[30 *3 + 4];
++ char *d = diag;
++ int m = (sizeof(diag) - 1) / 3;
++ char *b = ftdi->bulk_in_buffer;
++ int bytes_read = 0;
++ diag[0] = 0;
++ while (packet_bytes-- > 0) {
++ char c = *b++;
++ if (bytes_read < m) {
++ d += sprintf(d, " %02X",
++ 0x000000FF & c);
++ } else if (bytes_read > m) {
++ } else
++ d += sprintf(d, " ..");
++ bytes_read += 1;
++ continue;
++ }
++ goto more;
++ } else if (packet_bytes > 1) {
++ char s1 = ftdi->bulk_in_buffer[0];
++ char s2 = ftdi->bulk_in_buffer[1];
++ if (s1 == 0x31 && s2 == 0x60) {
++ return 0;
++ } else if (retry_on_status-- > 0) {
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
++ "imit reached\n");
++ return -EFAULT;
++ }
++ } else if (packet_bytes > 0) {
++ char b1 = ftdi->bulk_in_buffer[0];
++ dev_err(&ftdi->udev->dev, "only one byte flushed from F"
++ "TDI = %02X\n", b1);
++ if (retry_on_status-- > 0) {
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
++ "imit reached\n");
++ return -EFAULT;
++ }
++ } else if (retval == -ETIMEDOUT) {
++ if (retry_on_timeout-- > 0) {
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
++ "t reached\n");
++ return -ENOMEM;
++ }
++ } else if (retval == 0) {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "empty packet retry l"
++ "imit reached\n");
++ return -ENOMEM;
++ }
++ } else {
++ dev_err(&ftdi->udev->dev, "error = %d\n", retval);
++ return retval;
++ }
++ }
++ return -1;
++}
++
++
++/*
++* send the long flush sequence
++*
++*/
++static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi)
++{
++ int retval;
++ struct urb *urb;
++ char *buf;
++ int I = 257;
++ int i = 0;
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ"
++ "ence\n");
++ return -ENOMEM;
++ }
++ buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
++ if (!buf) {
++ dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq"
++ "uence\n");
++ usb_free_urb(urb);
++ return -ENOMEM;
++ }
++ while (I-- > 0)
++ buf[i++] = 0x55;
++ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
++ ftdi->bulk_out_endpointAddr), buf, i,
++ ftdi_elan_write_bulk_callback, ftdi);
++ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++ retval = usb_submit_urb(urb, GFP_KERNEL);
++ if (retval) {
++ dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
++ "flush sequence\n");
++ usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
++ usb_free_urb(urb);
++ return -ENOMEM;
++ }
++ usb_free_urb(urb);
++ return 0;
++}
++
++
++/*
++* send the reset sequence
++*
++*/
++static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi)
++{
++ int retval;
++ struct urb *urb;
++ char *buf;
++ int I = 4;
++ int i = 0;
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ dev_err(&ftdi->udev->dev, "could not get a urb for the reset se"
++ "quence\n");
++ return -ENOMEM;
++ }
++ buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
++ if (!buf) {
++ dev_err(&ftdi->udev->dev, "could not get a buffer for the reset"
++ " sequence\n");
++ usb_free_urb(urb);
++ return -ENOMEM;
++ }
++ buf[i++] = 0x55;
++ buf[i++] = 0xAA;
++ buf[i++] = 0x5A;
++ buf[i++] = 0xA5;
++ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
++ ftdi->bulk_out_endpointAddr), buf, i,
++ ftdi_elan_write_bulk_callback, ftdi);
++ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++ retval = usb_submit_urb(urb, GFP_KERNEL);
++ if (retval) {
++ dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
++ "reset sequence\n");
++ usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
++ usb_free_urb(urb);
++ return -ENOMEM;
++ }
++ usb_free_urb(urb);
++ return 0;
++}
++
++static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
++{
++ int retval;
++ int long_stop = 10;
++ int retry_on_timeout = 5;
++ int retry_on_empty = 10;
++ int err_count = 0;
++ retval = ftdi_elan_flush_input_fifo(ftdi);
++ if (retval)
++ return retval;
++ ftdi->bulk_in_left = 0;
++ ftdi->bulk_in_last = -1;
++ while (long_stop-- > 0) {
++ int read_stop;
++ int read_stuck;
++ retval = ftdi_elan_synchronize_flush(ftdi);
++ if (retval)
++ return retval;
++ retval = ftdi_elan_flush_input_fifo(ftdi);
++ if (retval)
++ return retval;
++ reset:retval = ftdi_elan_synchronize_reset(ftdi);
++ if (retval)
++ return retval;
++ read_stop = 100;
++ read_stuck = 10;
++ read:{
++ int packet_bytes = 0;
++ retval = usb_bulk_msg(ftdi->udev,
++ usb_rcvbulkpipe(ftdi->udev,
++ ftdi->bulk_in_endpointAddr),
++ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
++ &packet_bytes, msecs_to_jiffies(500));
++ if (packet_bytes > 2) {
++ char diag[30 *3 + 4];
++ char *d = diag;
++ int m = (sizeof(diag) - 1) / 3;
++ char *b = ftdi->bulk_in_buffer;
++ int bytes_read = 0;
++ unsigned char c = 0;
++ diag[0] = 0;
++ while (packet_bytes-- > 0) {
++ c = *b++;
++ if (bytes_read < m) {
++ d += sprintf(d, " %02X", c);
++ } else if (bytes_read > m) {
++ } else
++ d += sprintf(d, " ..");
++ bytes_read += 1;
++ continue;
++ }
++ if (c == 0x7E) {
++ return 0;
++ } else {
++ if (c == 0x55) {
++ goto read;
++ } else if (read_stop-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "retr"
++ "y limit reached\n");
++ continue;
++ }
++ }
++ } else if (packet_bytes > 1) {
++ unsigned char s1 = ftdi->bulk_in_buffer[0];
++ unsigned char s2 = ftdi->bulk_in_buffer[1];
++ if (s1 == 0x31 && s2 == 0x00) {
++ if (read_stuck-- > 0) {
++ goto read;
++ } else
++ goto reset;
++ } else if (s1 == 0x31 && s2 == 0x60) {
++ if (read_stop-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "retr"
++ "y limit reached\n");
++ continue;
++ }
++ } else {
++ if (read_stop-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "retr"
++ "y limit reached\n");
++ continue;
++ }
++ }
++ } else if (packet_bytes > 0) {
++ if (read_stop-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "retry limit "
++ "reached\n");
++ continue;
++ }
++ } else if (retval == -ETIMEDOUT) {
++ if (retry_on_timeout-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "TIMED OUT re"
++ "try limit reached\n");
++ continue;
++ }
++ } else if (retval == 0) {
++ if (retry_on_empty-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "empty packet"
++ " retry limit reached\n");
++ continue;
++ }
++ } else {
++ err_count += 1;
++ dev_err(&ftdi->udev->dev, "error = %d\n",
++ retval);
++ if (read_stop-- > 0) {
++ goto read;
++ } else {
++ dev_err(&ftdi->udev->dev, "retry limit "
++ "reached\n");
++ continue;
++ }
++ }
++ }
++ }
++ dev_err(&ftdi->udev->dev, "failed to synchronize\n");
++ return -EFAULT;
++}
++
++static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)
++{
++ int retry_on_empty = 10;
++ int retry_on_timeout = 5;
++ int retry_on_status = 50;
++ more:{
++ int packet_bytes = 0;
++ int retval = usb_bulk_msg(ftdi->udev,
++ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
++ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
++ &packet_bytes, msecs_to_jiffies(1000));
++ if (packet_bytes > 2) {
++ char diag[30 *3 + 4];
++ char *d = diag;
++ int m = (sizeof(diag) - 1) / 3;
++ char *b = ftdi->bulk_in_buffer;
++ int bytes_read = 0;
++ diag[0] = 0;
++ while (packet_bytes-- > 0) {
++ char c = *b++;
++ if (bytes_read < m) {
++ d += sprintf(d, " %02X",
++ 0x000000FF & c);
++ } else if (bytes_read > m) {
++ } else
++ d += sprintf(d, " ..");
++ bytes_read += 1;
++ continue;
++ }
++ goto more;
++ } else if (packet_bytes > 1) {
++ char s1 = ftdi->bulk_in_buffer[0];
++ char s2 = ftdi->bulk_in_buffer[1];
++ if (s1 == 0x31 && s2 == 0x60) {
++ return 0;
++ } else if (retry_on_status-- > 0) {
++ msleep(5);
++ goto more;
++ } else
++ return -EFAULT;
++ } else if (packet_bytes > 0) {
++ char b1 = ftdi->bulk_in_buffer[0];
++ dev_err(&ftdi->udev->dev, "only one byte flushed from F"
++ "TDI = %02X\n", b1);
++ if (retry_on_status-- > 0) {
++ msleep(5);
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
++ "imit reached\n");
++ return -EFAULT;
++ }
++ } else if (retval == -ETIMEDOUT) {
++ if (retry_on_timeout-- > 0) {
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
++ "t reached\n");
++ return -ENOMEM;
++ }
++ } else if (retval == 0) {
++ if (retry_on_empty-- > 0) {
++ goto more;
++ } else {
++ dev_err(&ftdi->udev->dev, "empty packet retry l"
++ "imit reached\n");
++ return -ENOMEM;
++ }
++ } else {
++ dev_err(&ftdi->udev->dev, "error = %d\n", retval);
++ return -ENOMEM;
++ }
++ }
++ return -1;
++}
++
++static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
++{
++ int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg);
++ if (UxxxStatus)
++ return UxxxStatus;
++ if (ftdi->controlreg & 0x00400000) {
++ if (ftdi->card_ejected) {
++ } else {
++ ftdi->card_ejected = 1;
++ dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = "
++ "%08X\n", ftdi->controlreg);
++ }
++ return -ENODEV;
++ } else {
++ u8 fn = ftdi->function - 1;
++ int activePCIfn = fn << 8;
++ u32 pcidata;
++ u32 pciVID;
++ u32 pciPID;
++ int reg = 0;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &pcidata);
++ if (UxxxStatus)
++ return UxxxStatus;
++ pciVID = pcidata & 0xFFFF;
++ pciPID = (pcidata >> 16) & 0xFFFF;
++ if (pciVID == ftdi->platform_data.vendor && pciPID ==
++ ftdi->platform_data.device) {
++ return 0;
++ } else {
++ dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi"
++ "ce=%04X pciPID=%04X\n",
++ ftdi->platform_data.vendor, pciVID,
++ ftdi->platform_data.device, pciPID);
++ return -ENODEV;
++ }
++ }
++}
++
++static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
++{
++ u32 latence_timer;
++ u32 controlreg;
++ int UxxxStatus;
++ u32 pcidata;
++ int reg = 0;
++ int foundOHCI = 0;
++ u8 fn;
++ int activePCIfn = 0;
++ u32 pciVID = 0;
++ u32 pciPID = 0;
++ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
++ if (UxxxStatus)
++ return UxxxStatus;
++ msleep(750);
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
++ if (UxxxStatus)
++ return UxxxStatus;
++ msleep(250);
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
++ if (UxxxStatus)
++ return UxxxStatus;
++ msleep(1000);
++ for (fn = 0; (fn < 4) && (!foundOHCI); fn++) {
++ activePCIfn = fn << 8;
++ ftdi->function = fn + 1;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &pcidata);
++ if (UxxxStatus)
++ return UxxxStatus;
++ pciVID = pcidata & 0xFFFF;
++ pciPID = (pcidata >> 16) & 0xFFFF;
++ if ((pciVID == 0x1045) && (pciPID == 0xc861)) {
++ foundOHCI = 1;
++ } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) {
++ foundOHCI = 1;
++ } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) {
++ foundOHCI = 1;
++ } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) {
++ foundOHCI = 1;
++ } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) {
++ }
++ }
++ if (foundOHCI == 0) {
++ return -ENXIO;
++ }
++ ftdi->platform_data.vendor = pciVID;
++ ftdi->platform_data.device = pciPID;
++ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
++ if (UxxxStatus)
++ return UxxxStatus;
++ reg = 16;
++ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
++ 0xFFFFFFFF);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &pcidata);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
++ 0xF0000000);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &pcidata);
++ if (UxxxStatus)
++ return UxxxStatus;
++ reg = 12;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &latence_timer);
++ if (UxxxStatus)
++ return UxxxStatus;
++ latence_timer &= 0xFFFF00FF;
++ latence_timer |= 0x00001600;
++ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
++ latence_timer);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &pcidata);
++ if (UxxxStatus)
++ return UxxxStatus;
++ reg = 4;
++ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
++ 0x06);
++ if (UxxxStatus)
++ return UxxxStatus;
++ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
++ &pcidata);
++ if (UxxxStatus)
++ return UxxxStatus;
++ return 0;
++}
++
++static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
++{
++ u32 pcidata;
++ int U132Status;
++ int reg;
++ int reset_repeat = 0;
++ do_reset:reg = 8;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01);
++ if (U132Status)
++ return U132Status;
++ reset_check:{
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ if (pcidata & 1) {
++ msleep(500);
++ if (reset_repeat++ > 100) {
++ reset_repeat = 0;
++ goto do_reset;
++ } else
++ goto reset_check;
++ }
++ }
++ goto dump_regs;
++ msleep(500);
++ reg = 0x28;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x40;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x34;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 4;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ msleep(250);
++ reg = 8;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x28;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 8;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x48;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x54;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x58;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x34;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ msleep(100);
++ reg = 0x50;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000);
++ if (U132Status)
++ return U132Status;
++ reg = 0x54;
++ power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ if (!(pcidata & 1)) {
++ msleep(500);
++ goto power_check;
++ }
++ msleep(3000);
++ reg = 0x54;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x58;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x54;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x54;
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10);
++ if (U132Status)
++ return U132Status;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ msleep(750);
++ reg = 0x54;
++ if (0) {
++ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
++ if (U132Status)
++ return U132Status;
++ }
++ if (0) {
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ }
++ reg = 0x54;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ reg = 0x58;
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ dump_regs:for (reg = 0; reg <= 0x54; reg += 4) {
++ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
++ if (U132Status)
++ return U132Status;
++ }
++ return 0;
++}
++
++
++/*
++* we use only the first bulk-in and bulk-out endpoints
++*/
++static int ftdi_elan_probe(struct usb_interface *interface,
++ const struct usb_device_id *id)
++{
++ struct usb_host_interface *iface_desc;
++ struct usb_endpoint_descriptor *endpoint;
++ size_t buffer_size;
++ int i;
++ int retval = -ENOMEM;
++ struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
++ if (ftdi == NULL) {
++ printk(KERN_ERR "Out of memory\n");
++ return -ENOMEM;
++ }
++ memset(ftdi, 0x00, sizeof(struct usb_ftdi));
++ down(&ftdi_module_lock);
++ list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
++ ftdi->sequence_num = ++ftdi_instances;
++ up(&ftdi_module_lock);
++ ftdi_elan_init_kref(ftdi);
++ init_MUTEX(&ftdi->sw_lock);
++ ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
++ ftdi->interface = interface;
++ init_MUTEX(&ftdi->u132_lock);
++ ftdi->expected = 4;
++ iface_desc = interface->cur_altsetting;
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
++ endpoint = &iface_desc->endpoint[i].desc;
++ if (!ftdi->bulk_in_endpointAddr &&
++ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
++ == USB_DIR_IN) && ((endpoint->bmAttributes &
++ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
++ {
++ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
++ ftdi->bulk_in_size = buffer_size;
++ ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
++ ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
++ if (!ftdi->bulk_in_buffer) {
++ dev_err(&ftdi->udev->dev, "Could not allocate b"
++ "ulk_in_buffer\n");
++ retval = -ENOMEM;
++ goto error;
++ }
++ }
++ if (!ftdi->bulk_out_endpointAddr &&
++ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
++ == USB_DIR_OUT) && ((endpoint->bmAttributes &
++ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
++ {
++ ftdi->bulk_out_endpointAddr =
++ endpoint->bEndpointAddress;
++ }
++ }
++ if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) {
++ dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk"
++ "-out endpoints\n");
++ retval = -ENODEV;
++ goto error;
++ }
++ dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n",
++ iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr,
++ ftdi->bulk_out_endpointAddr);
++ usb_set_intfdata(interface, ftdi);
++ if (iface_desc->desc.bInterfaceNumber == 0 &&
++ ftdi->bulk_in_endpointAddr == 0x81 &&
++ ftdi->bulk_out_endpointAddr == 0x02) {
++ retval = usb_register_dev(interface, &ftdi_elan_jtag_class);
++ if (retval) {
++ dev_err(&ftdi->udev->dev, "Not able to get a minor for "
++ "this device.\n");
++ usb_set_intfdata(interface, NULL);
++ retval = -ENOMEM;
++ goto error;
++ } else {
++ ftdi->class = &ftdi_elan_jtag_class;
++ dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface "
++ "%d now attached to ftdi%d\n", ftdi,
++ iface_desc->desc.bInterfaceNumber,
++ interface->minor);
++ return 0;
++ }
++ } else if (iface_desc->desc.bInterfaceNumber == 1 &&
++ ftdi->bulk_in_endpointAddr == 0x83 &&
++ ftdi->bulk_out_endpointAddr == 0x04) {
++ ftdi->class = NULL;
++ dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a"
++ "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber);
++ INIT_WORK(&ftdi->status_work, ftdi_elan_status_work,
++ (void *)ftdi);
++ INIT_WORK(&ftdi->command_work, ftdi_elan_command_work,
++ (void *)ftdi);
++ INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work,
++ (void *)ftdi);
++ ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000));
++ return 0;
++ } else {
++ dev_err(&ftdi->udev->dev,
++ "Could not find ELAN's U132 device\n");
++ retval = -ENODEV;
++ goto error;
++ }
++ error:if (ftdi) {
++ ftdi_elan_put_kref(ftdi);
++ }
++ return retval;
++}
++
++static void ftdi_elan_disconnect(struct usb_interface *interface)
++{
++ struct usb_ftdi *ftdi = usb_get_intfdata(interface);
++ ftdi->disconnected += 1;
++ if (ftdi->class) {
++ int minor = interface->minor;
++ struct usb_class_driver *class = ftdi->class;
++ usb_set_intfdata(interface, NULL);
++ usb_deregister_dev(interface, class);
++ dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min"
++ "or %d now disconnected\n", minor);
++ } else {
++ ftdi_status_cancel_work(ftdi);
++ ftdi_command_cancel_work(ftdi);
++ ftdi_response_cancel_work(ftdi);
++ ftdi_elan_abandon_completions(ftdi);
++ ftdi_elan_abandon_targets(ftdi);
++ if (ftdi->registered) {
++ platform_device_unregister(&ftdi->platform_dev);
++ ftdi->synchronized = 0;
++ ftdi->enumerated = 0;
++ ftdi->registered = 0;
++ }
++ flush_workqueue(status_queue);
++ flush_workqueue(command_queue);
++ flush_workqueue(respond_queue);
++ ftdi->disconnected += 1;
++ usb_set_intfdata(interface, NULL);
++ dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter"
++ "face now disconnected\n");
++ }
++ ftdi_elan_put_kref(ftdi);
++}
++
++static struct usb_driver ftdi_elan_driver = {
++ .name = "ftdi-elan",
++ .probe = ftdi_elan_probe,
++ .disconnect = ftdi_elan_disconnect,
++ .id_table = ftdi_elan_table,
++};
++static int __init ftdi_elan_init(void)
++{
++ int result;
++ printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
++ __TIME__, __DATE__);
++ init_MUTEX(&ftdi_module_lock);
++ INIT_LIST_HEAD(&ftdi_static_list);
++ status_queue = create_singlethread_workqueue("ftdi-status-control");
++ command_queue = create_singlethread_workqueue("ftdi-command-engine");
++ respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
++ result = usb_register(&ftdi_elan_driver);
++ if (result)
++ printk(KERN_ERR "usb_register failed. Error number %d\n",
++ result);
++ return result;
++}
++
++static void __exit ftdi_elan_exit(void)
++{
++ struct usb_ftdi *ftdi;
++ struct usb_ftdi *temp;
++ usb_deregister(&ftdi_elan_driver);
++ printk(KERN_INFO "ftdi_u132 driver deregistered\n");
++ list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) {
++ ftdi_status_cancel_work(ftdi);
++ ftdi_command_cancel_work(ftdi);
++ ftdi_response_cancel_work(ftdi);
++ } flush_workqueue(status_queue);
++ destroy_workqueue(status_queue);
++ status_queue = NULL;
++ flush_workqueue(command_queue);
++ destroy_workqueue(command_queue);
++ command_queue = NULL;
++ flush_workqueue(respond_queue);
++ destroy_workqueue(respond_queue);
++ respond_queue = NULL;
++}
++
++
++module_init(ftdi_elan_init);
++module_exit(ftdi_elan_exit);
+diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
+index fcd69c5..8e6e195 100644
+--- a/drivers/usb/misc/idmouse.c
++++ b/drivers/usb/misc/idmouse.c
+@@ -98,7 +98,7 @@ static int idmouse_probe(struct usb_inte
+ static void idmouse_disconnect(struct usb_interface *interface);
+
+ /* file operation pointers */
+-static struct file_operations idmouse_fops = {
++static const struct file_operations idmouse_fops = {
+ .owner = THIS_MODULE,
+ .read = idmouse_read,
+ .open = idmouse_open,
+diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
+index f30ab1f..788a11e 100644
+--- a/drivers/usb/misc/ldusb.c
++++ b/drivers/usb/misc/ldusb.c
+@@ -212,7 +212,7 @@ static void ld_usb_delete(struct ld_usb
+ /**
+ * ld_usb_interrupt_in_callback
+ */
+-static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs)
++static void ld_usb_interrupt_in_callback(struct urb *urb)
+ {
+ struct ld_usb *dev = urb->context;
+ size_t *actual_buffer;
+@@ -264,7 +264,7 @@ exit:
+ /**
+ * ld_usb_interrupt_out_callback
+ */
+-static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs)
++static void ld_usb_interrupt_out_callback(struct urb *urb)
+ {
+ struct ld_usb *dev = urb->context;
+
+@@ -589,7 +589,7 @@ exit:
+ }
+
+ /* file operations needed when we register this driver */
+-static struct file_operations ld_usb_fops = {
++static const struct file_operations ld_usb_fops = {
+ .owner = THIS_MODULE,
+ .read = ld_usb_read,
+ .write = ld_usb_write,
+@@ -657,15 +657,11 @@ static int ld_usb_probe(struct usb_inter
+ 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)) {
++ if (usb_endpoint_is_int_in(endpoint))
+ 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)) {
++ if (usb_endpoint_is_int_out(endpoint))
+ dev->interrupt_out_endpoint = endpoint;
+- }
+ }
+ if (dev->interrupt_in_endpoint == NULL) {
+ dev_err(&intf->dev, "Interrupt in endpoint not found\n");
+diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
+index 7699d97..2708949 100644
+--- a/drivers/usb/misc/legousbtower.c
++++ b/drivers/usb/misc/legousbtower.c
+@@ -248,8 +248,8 @@ static loff_t tower_llseek (struct file
+
+ static void tower_abort_transfers (struct lego_usb_tower *dev);
+ static void tower_check_for_read_packet (struct lego_usb_tower *dev);
+-static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs);
+-static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs);
++static void tower_interrupt_in_callback (struct urb *urb);
++static void tower_interrupt_out_callback (struct urb *urb);
+
+ static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id);
+ static void tower_disconnect (struct usb_interface *interface);
+@@ -259,7 +259,7 @@ static void tower_disconnect (struct usb
+ static DEFINE_MUTEX (disconnect_mutex);
+
+ /* file operations needed when we register this driver */
+-static struct file_operations tower_fops = {
++static const struct file_operations tower_fops = {
+ .owner = THIS_MODULE,
+ .read = tower_read,
+ .write = tower_write,
+@@ -755,7 +755,7 @@ exit:
+ /**
+ * tower_interrupt_in_callback
+ */
+-static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs)
++static void tower_interrupt_in_callback (struct urb *urb)
+ {
+ struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int retval;
+@@ -811,7 +811,7 @@ exit:
+ /**
+ * tower_interrupt_out_callback
+ */
+-static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs)
++static void tower_interrupt_out_callback (struct urb *urb)
+ {
+ struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+
+diff --git a/drivers/usb/misc/phidget.c b/drivers/usb/misc/phidget.c
+new file mode 100644
+index 0000000..735ed33
+--- /dev/null
++++ b/drivers/usb/misc/phidget.c
+@@ -0,0 +1,43 @@
++/*
++ * USB Phidgets class
++ *
++ * Copyright (C) 2006 Sean Young <sean at mess.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
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/device.h>
++
++struct class *phidget_class;
++
++static int __init init_phidget(void)
++{
++ phidget_class = class_create(THIS_MODULE, "phidget");
++
++ if (IS_ERR(phidget_class))
++ return PTR_ERR(phidget_class);
++
++ return 0;
++}
++
++static void __exit cleanup_phidget(void)
++{
++ class_destroy(phidget_class);
++}
++
++EXPORT_SYMBOL_GPL(phidget_class);
++
++module_init(init_phidget);
++module_exit(cleanup_phidget);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Sean Young <sean at mess.org>");
++MODULE_DESCRIPTION("Container module for phidget class");
++
+diff --git a/drivers/usb/misc/phidget.h b/drivers/usb/misc/phidget.h
+new file mode 100644
+index 0000000..c401190
+--- /dev/null
++++ b/drivers/usb/misc/phidget.h
+@@ -0,0 +1,12 @@
++/*
++ * USB Phidgets class
++ *
++ * Copyright (C) 2006 Sean Young <sean at mess.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
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++extern struct class *phidget_class;
+diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
+index bfbbbfb..abb4dcd 100644
+--- a/drivers/usb/misc/phidgetkit.c
++++ b/drivers/usb/misc/phidgetkit.c
+@@ -20,6 +20,8 @@
+ #include <linux/module.h>
+ #include <linux/usb.h>
+
++#include "phidget.h"
++
+ #define DRIVER_AUTHOR "Sean Young <sean at mess.org>"
+ #define DRIVER_DESC "USB PhidgetInterfaceKit Driver"
+
+@@ -42,26 +44,35 @@ struct driver_interfacekit {
+ int inputs;
+ int outputs;
+ int has_lcd;
++ int amnesiac;
+ };
+-#define ifkit(_sensors, _inputs, _outputs, _lcd) \
+-static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \
++
++#define ifkit(_sensors, _inputs, _outputs, _lcd, _amnesiac) \
++{ \
+ .sensors = _sensors, \
+ .inputs = _inputs, \
+ .outputs = _outputs, \
+ .has_lcd = _lcd, \
++ .amnesiac = _amnesiac \
+ };
+-ifkit(0, 0, 4, 0);
+-ifkit(8, 8, 8, 0);
+-ifkit(0, 4, 7, 1);
+-ifkit(8, 8, 4, 0);
+-ifkit(0, 8, 8, 1);
+-ifkit(0, 16, 16, 0);
++
++static const struct driver_interfacekit ph_004 = ifkit(0, 0, 4, 0, 0);
++static const struct driver_interfacekit ph_888n = ifkit(8, 8, 8, 0, 1);
++static const struct driver_interfacekit ph_888o = ifkit(8, 8, 8, 0, 0);
++static const struct driver_interfacekit ph_047 = ifkit(0, 4, 7, 1, 0);
++static const struct driver_interfacekit ph_884 = ifkit(8, 8, 4, 0, 0);
++static const struct driver_interfacekit ph_088 = ifkit(0, 8, 8, 1, 0);
++static const struct driver_interfacekit ph_01616 = ifkit(0, 16, 16, 0, 0);
++
++static unsigned long device_no;
+
+ struct interfacekit {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct driver_interfacekit *ifkit;
++ struct device *dev;
+ unsigned long outputs;
++ int dev_no;
+ u8 inputs[MAX_INTERFACES];
+ u16 sensors[MAX_INTERFACES];
+ u8 lcd_files_on;
+@@ -71,6 +82,7 @@ struct interfacekit {
+ dma_addr_t data_dma;
+
+ struct work_struct do_notify;
++ struct work_struct do_resubmit;
+ unsigned long input_events;
+ unsigned long sensor_events;
+ };
+@@ -78,8 +90,10 @@ struct interfacekit {
+ static struct usb_device_id id_table[] = {
+ {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004),
+ .driver_info = (kernel_ulong_t)&ph_004},
+- {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888),
+- .driver_info = (kernel_ulong_t)&ph_888},
++ {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0, 0x814),
++ .driver_info = (kernel_ulong_t)&ph_888o},
++ {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0x0815, 0xffff),
++ .driver_info = (kernel_ulong_t)&ph_888n},
+ {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047),
+ .driver_info = (kernel_ulong_t)&ph_047},
+ {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
+@@ -92,16 +106,11 @@ static struct usb_device_id id_table[] =
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+
+-static int change_outputs(struct interfacekit *kit, int output_num, int enable)
++static int set_outputs(struct interfacekit *kit)
+ {
+ u8 *buffer;
+ int retval;
+
+- if (enable)
+- set_bit(output_num, &kit->outputs);
+- else
+- clear_bit(output_num, &kit->outputs);
+-
+ buffer = kzalloc(4, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+@@ -121,6 +130,9 @@ static int change_outputs(struct interfa
+ retval);
+ kfree(buffer);
+
++ if (kit->ifkit->amnesiac)
++ schedule_delayed_work(&kit->do_resubmit, HZ / 2);
++
+ return retval < 0 ? retval : 0;
+ }
+
+@@ -180,21 +192,24 @@ exit:
+ }
+
+ #define set_lcd_line(number) \
+-static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+-{ \
+- struct usb_interface *intf = to_usb_interface(dev); \
+- struct interfacekit *kit = usb_get_intfdata(intf); \
+- change_string(kit, buf, number - 1); \
+- return count; \
+-} \
+-static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number);
++static ssize_t lcd_line_##number(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct interfacekit *kit = dev_get_drvdata(dev); \
++ change_string(kit, buf, number - 1); \
++ return count; \
++}
++
++#define lcd_line_attr(number) \
++ __ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number)
++
+ set_lcd_line(1);
+ set_lcd_line(2);
+
+ static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {
+- struct usb_interface *intf = to_usb_interface(dev);
+- struct interfacekit *kit = usb_get_intfdata(intf);
++ struct interfacekit *kit = dev_get_drvdata(dev);
+ int enabled;
+ unsigned char *buffer;
+ int retval = -ENOMEM;
+@@ -226,23 +241,30 @@ exit:
+ kfree(buffer);
+ return retval;
+ }
+-static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight);
++
++static struct device_attribute dev_lcd_line_attrs[] = {
++ lcd_line_attr(1),
++ lcd_line_attr(2),
++ __ATTR(backlight, S_IWUGO, NULL, set_backlight)
++};
+
+ static void remove_lcd_files(struct interfacekit *kit)
+ {
++ int i;
++
+ if (kit->lcd_files_on) {
+ dev_dbg(&kit->udev->dev, "Removing lcd files\n");
+- device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1);
+- device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2);
+- device_remove_file(&kit->intf->dev, &dev_attr_backlight);
++
++ for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++)
++ device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
+ }
+ }
+
+ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {
+- struct usb_interface *intf = to_usb_interface(dev);
+- struct interfacekit *kit = usb_get_intfdata(intf);
++ struct interfacekit *kit = dev_get_drvdata(dev);
+ int enable;
++ int i, rc;
+
+ if (kit->ifkit->has_lcd == 0)
+ return -ENODEV;
+@@ -253,9 +275,12 @@ static ssize_t enable_lcd_files(struct d
+ if (enable) {
+ if (!kit->lcd_files_on) {
+ dev_dbg(&kit->udev->dev, "Adding lcd files\n");
+- device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1);
+- device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2);
+- device_create_file(&kit->intf->dev, &dev_attr_backlight);
++ for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++) {
++ rc = device_create_file(kit->dev,
++ &dev_lcd_line_attrs[i]);
++ if (rc)
++ goto out;
++ }
+ kit->lcd_files_on = 1;
+ }
+ } else {
+@@ -266,10 +291,16 @@ static ssize_t enable_lcd_files(struct d
+ }
+
+ return count;
++out:
++ while (i-- > 0)
++ device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
++
++ return rc;
+ }
++
+ static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
+
+-static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
++static void interfacekit_irq(struct urb *urb)
+ {
+ struct interfacekit *kit = urb->context;
+ unsigned char *buffer = kit->data;
+@@ -362,44 +393,58 @@ static void do_notify(void *data)
+ for (i=0; i<kit->ifkit->inputs; i++) {
+ if (test_and_clear_bit(i, &kit->input_events)) {
+ sprintf(sysfs_file, "input%d", i + 1);
+- sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
++ sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
+ }
+ }
+
+ for (i=0; i<kit->ifkit->sensors; i++) {
+ if (test_and_clear_bit(i, &kit->sensor_events)) {
+ sprintf(sysfs_file, "sensor%d", i + 1);
+- sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
++ sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
+ }
+ }
+ }
+
++static void do_resubmit(void *data)
++{
++ set_outputs(data);
++}
++
+ #define show_set_output(value) \
+-static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \
+- size_t count) \
++static ssize_t set_output##value(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t count) \
+ { \
+- struct usb_interface *intf = to_usb_interface(dev); \
+- struct interfacekit *kit = usb_get_intfdata(intf); \
+- int enabled; \
++ struct interfacekit *kit = dev_get_drvdata(dev); \
++ int enable; \
+ int retval; \
+ \
+- if (sscanf(buf, "%d", &enabled) < 1) \
++ if (sscanf(buf, "%d", &enable) < 1) \
+ return -EINVAL; \
+ \
+- retval = change_outputs(kit, value - 1, enabled); \
++ if (enable) \
++ set_bit(value - 1, &kit->outputs); \
++ else \
++ clear_bit(value - 1, &kit->outputs); \
++ \
++ retval = set_outputs(kit); \
+ \
+ return retval ? retval : count; \
+ } \
+ \
+-static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \
++static ssize_t show_output##value(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
+ { \
+- struct usb_interface *intf = to_usb_interface(dev); \
+- struct interfacekit *kit = usb_get_intfdata(intf); \
++ struct interfacekit *kit = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\
+-} \
+-static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \
+- show_output##value, set_output##value);
++}
++
++#define output_attr(value) \
++ __ATTR(output##value, S_IWUGO | S_IRUGO, \
++ show_output##value, set_output##value)
++
+ show_set_output(1);
+ show_set_output(2);
+ show_set_output(3);
+@@ -417,15 +462,24 @@ show_set_output(14);
+ show_set_output(15);
+ show_set_output(16);
+
++static struct device_attribute dev_output_attrs[] = {
++ output_attr(1), output_attr(2), output_attr(3), output_attr(4),
++ output_attr(5), output_attr(6), output_attr(7), output_attr(8),
++ output_attr(9), output_attr(10), output_attr(11), output_attr(12),
++ output_attr(13), output_attr(14), output_attr(15), output_attr(16)
++};
++
+ #define show_input(value) \
+-static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \
++static ssize_t show_input##value(struct device *dev, \
++ struct device_attribute *attr, char *buf) \
+ { \
+- struct usb_interface *intf = to_usb_interface(dev); \
+- struct interfacekit *kit = usb_get_intfdata(intf); \
++ struct interfacekit *kit = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]); \
+-} \
+-static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL);
++}
++
++#define input_attr(value) \
++ __ATTR(input##value, S_IRUGO, show_input##value, NULL)
+
+ show_input(1);
+ show_input(2);
+@@ -444,15 +498,25 @@ show_input(14);
+ show_input(15);
+ show_input(16);
+
++static struct device_attribute dev_input_attrs[] = {
++ input_attr(1), input_attr(2), input_attr(3), input_attr(4),
++ input_attr(5), input_attr(6), input_attr(7), input_attr(8),
++ input_attr(9), input_attr(10), input_attr(11), input_attr(12),
++ input_attr(13), input_attr(14), input_attr(15), input_attr(16)
++};
++
+ #define show_sensor(value) \
+-static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \
++static ssize_t show_sensor##value(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
+ { \
+- struct usb_interface *intf = to_usb_interface(dev); \
+- struct interfacekit *kit = usb_get_intfdata(intf); \
++ struct interfacekit *kit = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]); \
+-} \
+-static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL);
++}
++
++#define sensor_attr(value) \
++ __ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL)
+
+ show_sensor(1);
+ show_sensor(2);
+@@ -463,6 +527,11 @@ show_sensor(6);
+ show_sensor(7);
+ show_sensor(8);
+
++static struct device_attribute dev_sensor_attrs[] = {
++ sensor_attr(1), sensor_attr(2), sensor_attr(3), sensor_attr(4),
++ sensor_attr(5), sensor_attr(6), sensor_attr(7), sensor_attr(8)
++};
++
+ static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ struct usb_device *dev = interface_to_usbdev(intf);
+@@ -471,6 +540,7 @@ static int interfacekit_probe(struct usb
+ struct interfacekit *kit;
+ struct driver_interfacekit *ifkit;
+ int pipe, maxp, rc = -ENOMEM;
++ int bit, value, i;
+
+ ifkit = (struct driver_interfacekit *)id->driver_info;
+ if (!ifkit)
+@@ -493,6 +563,7 @@ static int interfacekit_probe(struct usb
+ if (!kit)
+ goto out;
+
++ kit->dev_no = -1;
+ kit->ifkit = ifkit;
+ kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma);
+ if (!kit->data)
+@@ -505,6 +576,7 @@ static int interfacekit_probe(struct usb
+ kit->udev = usb_get_dev(dev);
+ kit->intf = intf;
+ INIT_WORK(&kit->do_notify, do_notify, kit);
++ INIT_WORK(&kit->do_resubmit, do_resubmit, kit);
+ usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
+ maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
+ interfacekit_irq, kit, endpoint->bInterval);
+@@ -513,85 +585,80 @@ static int interfacekit_probe(struct usb
+
+ usb_set_intfdata(intf, kit);
+
++ do {
++ bit = find_first_zero_bit(&device_no, sizeof(device_no));
++ value = test_and_set_bit(bit, &device_no);
++ } while(value);
++ kit->dev_no = bit;
++
++ kit->dev = device_create(phidget_class, &kit->udev->dev, 0,
++ "interfacekit%d", kit->dev_no);
++ if (IS_ERR(kit->dev)) {
++ rc = PTR_ERR(kit->dev);
++ kit->dev = NULL;
++ goto out;
++ }
++ dev_set_drvdata(kit->dev, kit);
++
+ if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
+ rc = -EIO;
+ goto out;
+ }
+
+- if (ifkit->outputs >= 4) {
+- device_create_file(&intf->dev, &dev_attr_output1);
+- device_create_file(&intf->dev, &dev_attr_output2);
+- device_create_file(&intf->dev, &dev_attr_output3);
+- device_create_file(&intf->dev, &dev_attr_output4);
+- }
+- if (ifkit->outputs >= 8) {
+- device_create_file(&intf->dev, &dev_attr_output5);
+- device_create_file(&intf->dev, &dev_attr_output6);
+- device_create_file(&intf->dev, &dev_attr_output7);
+- device_create_file(&intf->dev, &dev_attr_output8);
+- }
+- if (ifkit->outputs == 16) {
+- device_create_file(&intf->dev, &dev_attr_output9);
+- device_create_file(&intf->dev, &dev_attr_output10);
+- device_create_file(&intf->dev, &dev_attr_output11);
+- device_create_file(&intf->dev, &dev_attr_output12);
+- device_create_file(&intf->dev, &dev_attr_output13);
+- device_create_file(&intf->dev, &dev_attr_output14);
+- device_create_file(&intf->dev, &dev_attr_output15);
+- device_create_file(&intf->dev, &dev_attr_output16);
++ for (i=0; i<ifkit->outputs; i++ ) {
++ rc = device_create_file(kit->dev, &dev_output_attrs[i]);
++ if (rc)
++ goto out2;
+ }
+
+- if (ifkit->inputs >= 4) {
+- device_create_file(&intf->dev, &dev_attr_input1);
+- device_create_file(&intf->dev, &dev_attr_input2);
+- device_create_file(&intf->dev, &dev_attr_input3);
+- device_create_file(&intf->dev, &dev_attr_input4);
+- }
+- if (ifkit->inputs >= 8) {
+- device_create_file(&intf->dev, &dev_attr_input5);
+- device_create_file(&intf->dev, &dev_attr_input6);
+- device_create_file(&intf->dev, &dev_attr_input7);
+- device_create_file(&intf->dev, &dev_attr_input8);
+- }
+- if (ifkit->inputs == 16) {
+- device_create_file(&intf->dev, &dev_attr_input9);
+- device_create_file(&intf->dev, &dev_attr_input10);
+- device_create_file(&intf->dev, &dev_attr_input11);
+- device_create_file(&intf->dev, &dev_attr_input12);
+- device_create_file(&intf->dev, &dev_attr_input13);
+- device_create_file(&intf->dev, &dev_attr_input14);
+- device_create_file(&intf->dev, &dev_attr_input15);
+- device_create_file(&intf->dev, &dev_attr_input16);
++ for (i=0; i<ifkit->inputs; i++ ) {
++ rc = device_create_file(kit->dev, &dev_input_attrs[i]);
++ if (rc)
++ goto out3;
+ }
+
+- if (ifkit->sensors >= 4) {
+- device_create_file(&intf->dev, &dev_attr_sensor1);
+- device_create_file(&intf->dev, &dev_attr_sensor2);
+- device_create_file(&intf->dev, &dev_attr_sensor3);
+- device_create_file(&intf->dev, &dev_attr_sensor4);
++ for (i=0; i<ifkit->sensors; i++ ) {
++ rc = device_create_file(kit->dev, &dev_sensor_attrs[i]);
++ if (rc)
++ goto out4;
+ }
+- if (ifkit->sensors >= 7) {
+- device_create_file(&intf->dev, &dev_attr_sensor5);
+- device_create_file(&intf->dev, &dev_attr_sensor6);
+- device_create_file(&intf->dev, &dev_attr_sensor7);
+- }
+- if (ifkit->sensors == 8)
+- device_create_file(&intf->dev, &dev_attr_sensor8);
+
+- if (ifkit->has_lcd)
+- device_create_file(&intf->dev, &dev_attr_lcd);
++ if (ifkit->has_lcd) {
++ rc = device_create_file(kit->dev, &dev_attr_lcd);
++ if (rc)
++ goto out4;
++
++ }
+
+ dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
+ ifkit->sensors, ifkit->inputs, ifkit->outputs);
+
+ return 0;
+
++out4:
++ while (i-- > 0)
++ device_remove_file(kit->dev, &dev_sensor_attrs[i]);
++
++ i = ifkit->inputs;
++out3:
++ while (i-- > 0)
++ device_remove_file(kit->dev, &dev_input_attrs[i]);
++
++ i = ifkit->outputs;
++out2:
++ while (i-- > 0)
++ device_remove_file(kit->dev, &dev_output_attrs[i]);
+ out:
+ if (kit) {
+ if (kit->irq)
+ usb_free_urb(kit->irq);
+ if (kit->data)
+ usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma);
++ if (kit->dev)
++ device_unregister(kit->dev);
++ if (kit->dev_no >= 0)
++ clear_bit(kit->dev_no, &device_no);
++
+ kfree(kit);
+ }
+
+@@ -601,6 +668,7 @@ out:
+ static void interfacekit_disconnect(struct usb_interface *interface)
+ {
+ struct interfacekit *kit;
++ int i;
+
+ kit = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+@@ -612,74 +680,30 @@ static void interfacekit_disconnect(stru
+ usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma);
+
+ cancel_delayed_work(&kit->do_notify);
++ cancel_delayed_work(&kit->do_resubmit);
+
+- if (kit->ifkit->outputs >= 4) {
+- device_remove_file(&interface->dev, &dev_attr_output1);
+- device_remove_file(&interface->dev, &dev_attr_output2);
+- device_remove_file(&interface->dev, &dev_attr_output3);
+- device_remove_file(&interface->dev, &dev_attr_output4);
+- }
+- if (kit->ifkit->outputs >= 8) {
+- device_remove_file(&interface->dev, &dev_attr_output5);
+- device_remove_file(&interface->dev, &dev_attr_output6);
+- device_remove_file(&interface->dev, &dev_attr_output7);
+- device_remove_file(&interface->dev, &dev_attr_output8);
+- }
+- if (kit->ifkit->outputs == 16) {
+- device_remove_file(&interface->dev, &dev_attr_output9);
+- device_remove_file(&interface->dev, &dev_attr_output10);
+- device_remove_file(&interface->dev, &dev_attr_output11);
+- device_remove_file(&interface->dev, &dev_attr_output12);
+- device_remove_file(&interface->dev, &dev_attr_output13);
+- device_remove_file(&interface->dev, &dev_attr_output14);
+- device_remove_file(&interface->dev, &dev_attr_output15);
+- device_remove_file(&interface->dev, &dev_attr_output16);
+- }
++ for (i=0; i<kit->ifkit->outputs; i++)
++ device_remove_file(kit->dev, &dev_output_attrs[i]);
+
+- if (kit->ifkit->inputs >= 4) {
+- device_remove_file(&interface->dev, &dev_attr_input1);
+- device_remove_file(&interface->dev, &dev_attr_input2);
+- device_remove_file(&interface->dev, &dev_attr_input3);
+- device_remove_file(&interface->dev, &dev_attr_input4);
+- }
+- if (kit->ifkit->inputs >= 8) {
+- device_remove_file(&interface->dev, &dev_attr_input5);
+- device_remove_file(&interface->dev, &dev_attr_input6);
+- device_remove_file(&interface->dev, &dev_attr_input7);
+- device_remove_file(&interface->dev, &dev_attr_input8);
+- }
+- if (kit->ifkit->inputs == 16) {
+- device_remove_file(&interface->dev, &dev_attr_input9);
+- device_remove_file(&interface->dev, &dev_attr_input10);
+- device_remove_file(&interface->dev, &dev_attr_input11);
+- device_remove_file(&interface->dev, &dev_attr_input12);
+- device_remove_file(&interface->dev, &dev_attr_input13);
+- device_remove_file(&interface->dev, &dev_attr_input14);
+- device_remove_file(&interface->dev, &dev_attr_input15);
+- device_remove_file(&interface->dev, &dev_attr_input16);
+- }
++ for (i=0; i<kit->ifkit->inputs; i++)
++ device_remove_file(kit->dev, &dev_input_attrs[i]);
+
+- if (kit->ifkit->sensors >= 4) {
+- device_remove_file(&interface->dev, &dev_attr_sensor1);
+- device_remove_file(&interface->dev, &dev_attr_sensor2);
+- device_remove_file(&interface->dev, &dev_attr_sensor3);
+- device_remove_file(&interface->dev, &dev_attr_sensor4);
+- }
+- if (kit->ifkit->sensors >= 7) {
+- device_remove_file(&interface->dev, &dev_attr_sensor5);
+- device_remove_file(&interface->dev, &dev_attr_sensor6);
+- device_remove_file(&interface->dev, &dev_attr_sensor7);
++ for (i=0; i<kit->ifkit->sensors; i++)
++ device_remove_file(kit->dev, &dev_sensor_attrs[i]);
++
++ if (kit->ifkit->has_lcd) {
++ device_remove_file(kit->dev, &dev_attr_lcd);
++ remove_lcd_files(kit);
+ }
+- if (kit->ifkit->sensors == 8)
+- device_remove_file(&interface->dev, &dev_attr_sensor8);
+
+- if (kit->ifkit->has_lcd)
+- device_remove_file(&interface->dev, &dev_attr_lcd);
++ device_unregister(kit->dev);
+
+ dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
+ kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
+
+ usb_put_dev(kit->udev);
++ clear_bit(kit->dev_no, &device_no);
++
+ kfree(kit);
+ }
+
+diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
+new file mode 100644
+index 0000000..5c780ca
+--- /dev/null
++++ b/drivers/usb/misc/phidgetmotorcontrol.c
+@@ -0,0 +1,466 @@
++/*
++ * USB Phidget MotorControl driver
++ *
++ * Copyright (C) 2006 Sean Young <sean at mess.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
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++
++#include "phidget.h"
++
++#define DRIVER_AUTHOR "Sean Young <sean at mess.org>"
++#define DRIVER_DESC "USB PhidgetMotorControl Driver"
++
++#define USB_VENDOR_ID_GLAB 0x06c2
++#define USB_DEVICE_ID_MOTORCONTROL 0x0058
++
++#define URB_INT_SIZE 8
++
++static unsigned long device_no;
++
++struct motorcontrol {
++ struct usb_device *udev;
++ struct usb_interface *intf;
++ struct device *dev;
++ int dev_no;
++ u8 inputs[4];
++ s8 desired_speed[2];
++ s8 speed[2];
++ s16 _current[2];
++ s8 acceleration[2];
++ struct urb *irq;
++ unsigned char *data;
++ dma_addr_t data_dma;
++
++ struct work_struct do_notify;
++ unsigned long input_events;
++ unsigned long speed_events;
++ unsigned long exceed_events;
++};
++
++static struct usb_device_id id_table[] = {
++ { USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_MOTORCONTROL) },
++ {}
++};
++MODULE_DEVICE_TABLE(usb, id_table);
++
++static int set_motor(struct motorcontrol *mc, int motor)
++{
++ u8 *buffer;
++ int speed, speed2, acceleration;
++ int retval;
++
++ buffer = kzalloc(8, GFP_KERNEL);
++ if (!buffer) {
++ dev_err(&mc->intf->dev, "%s - out of memory\n", __FUNCTION__);
++ return -ENOMEM;
++ }
++
++ acceleration = mc->acceleration[motor] * 10;
++ /* -127 <= speed <= 127 */
++ speed = (mc->desired_speed[motor] * 127) / 100;
++ /* -0x7300 <= speed2 <= 0x7300 */
++ speed2 = (mc->desired_speed[motor] * 230 * 128) / 100;
++
++ buffer[0] = motor;
++ buffer[1] = speed;
++ buffer[2] = acceleration >> 8;
++ buffer[3] = acceleration;
++ buffer[4] = speed2 >> 8;
++ buffer[5] = speed2;
++
++ retval = usb_control_msg(mc->udev,
++ usb_sndctrlpipe(mc->udev, 0),
++ 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
++
++ if (retval != 8)
++ dev_err(&mc->intf->dev, "usb_control_msg returned %d\n",
++ retval);
++ kfree(buffer);
++
++ return retval < 0 ? retval : 0;
++}
++
++static void motorcontrol_irq(struct urb *urb)
++{
++ struct motorcontrol *mc = urb->context;
++ unsigned char *buffer = mc->data;
++ int i, level;
++ int status;
++
++ switch (urb->status) {
++ case 0: /* success */
++ break;
++ case -ECONNRESET: /* unlink */
++ case -ENOENT:
++ case -ESHUTDOWN:
++ return;
++ /* -EPIPE: should clear the halt */
++ default: /* error */
++ goto resubmit;
++ }
++
++ /* digital inputs */
++ for (i=0; i<4; i++) {
++ level = (buffer[0] >> i) & 1;
++ if (mc->inputs[i] != level) {
++ mc->inputs[i] = level;
++ set_bit(i, &mc->input_events);
++ }
++ }
++
++ /* motor speed */
++ if (buffer[2] == 0) {
++ for (i=0; i<2; i++) {
++ level = ((s8)buffer[4+i]) * 100 / 127;
++ if (mc->speed[i] != level) {
++ mc->speed[i] = level;
++ set_bit(i, &mc->speed_events);
++ }
++ }
++ } else {
++ int index = buffer[3] & 1;
++
++ level = ((s8)buffer[4] << 8) | buffer[5];
++ level = level * 100 / 29440;
++ if (mc->speed[index] != level) {
++ mc->speed[index] = level;
++ set_bit(index, &mc->speed_events);
++ }
++
++ level = ((s8)buffer[6] << 8) | buffer[7];
++ mc->_current[index] = level * 100 / 1572;
++ }
++
++ if (buffer[1] & 1)
++ set_bit(0, &mc->exceed_events);
++
++ if (buffer[1] & 2)
++ set_bit(1, &mc->exceed_events);
++
++ if (mc->input_events || mc->exceed_events || mc->speed_events)
++ schedule_work(&mc->do_notify);
++
++resubmit:
++ status = usb_submit_urb(urb, SLAB_ATOMIC);
++ if (status)
++ dev_err(&mc->intf->dev,
++ "can't resubmit intr, %s-%s/motorcontrol0, status %d",
++ mc->udev->bus->bus_name,
++ mc->udev->devpath, status);
++}
++
++static void do_notify(void *data)
++{
++ struct motorcontrol *mc = data;
++ int i;
++ char sysfs_file[8];
++
++ for (i=0; i<4; i++) {
++ if (test_and_clear_bit(i, &mc->input_events)) {
++ sprintf(sysfs_file, "input%d", i);
++ sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
++ }
++ }
++
++ for (i=0; i<2; i++) {
++ if (test_and_clear_bit(i, &mc->speed_events)) {
++ sprintf(sysfs_file, "speed%d", i);
++ sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
++ }
++ }
++
++ for (i=0; i<2; i++) {
++ if (test_and_clear_bit(i, &mc->exceed_events))
++ dev_warn(&mc->intf->dev,
++ "motor #%d exceeds 1.5 Amp current limit\n", i);
++ }
++}
++
++#define show_set_speed(value) \
++static ssize_t set_speed##value(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct motorcontrol *mc = dev_get_drvdata(dev); \
++ int speed; \
++ int retval; \
++ \
++ if (sscanf(buf, "%d", &speed) < 1) \
++ return -EINVAL; \
++ \
++ if (speed < -100 || speed > 100) \
++ return -EINVAL; \
++ \
++ mc->desired_speed[value] = speed; \
++ \
++ retval = set_motor(mc, value); \
++ \
++ return retval ? retval : count; \
++} \
++ \
++static ssize_t show_speed##value(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct motorcontrol *mc = dev_get_drvdata(dev); \
++ \
++ return sprintf(buf, "%d\n", mc->speed[value]); \
++}
++
++#define speed_attr(value) \
++ __ATTR(speed##value, S_IWUGO | S_IRUGO, \
++ show_speed##value, set_speed##value)
++
++show_set_speed(0);
++show_set_speed(1);
++
++#define show_set_acceleration(value) \
++static ssize_t set_acceleration##value(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct motorcontrol *mc = dev_get_drvdata(dev); \
++ int acceleration; \
++ int retval; \
++ \
++ if (sscanf(buf, "%d", &acceleration) < 1) \
++ return -EINVAL; \
++ \
++ if (acceleration < 0 || acceleration > 100) \
++ return -EINVAL; \
++ \
++ mc->acceleration[value] = acceleration; \
++ \
++ retval = set_motor(mc, value); \
++ \
++ return retval ? retval : count; \
++} \
++ \
++static ssize_t show_acceleration##value(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct motorcontrol *mc = dev_get_drvdata(dev); \
++ \
++ return sprintf(buf, "%d\n", mc->acceleration[value]); \
++}
++
++#define acceleration_attr(value) \
++ __ATTR(acceleration##value, S_IWUGO | S_IRUGO, \
++ show_acceleration##value, set_acceleration##value)
++
++show_set_acceleration(0);
++show_set_acceleration(1);
++
++#define show_current(value) \
++static ssize_t show_current##value(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct motorcontrol *mc = dev_get_drvdata(dev); \
++ \
++ return sprintf(buf, "%dmA\n", (int)mc->_current[value]); \
++}
++
++#define current_attr(value) \
++ __ATTR(current##value, S_IRUGO, show_current##value, NULL)
++
++show_current(0);
++show_current(1);
++
++#define show_input(value) \
++static ssize_t show_input##value(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct motorcontrol *mc = dev_get_drvdata(dev); \
++ \
++ return sprintf(buf, "%d\n", (int)mc->inputs[value]); \
++}
++
++#define input_attr(value) \
++ __ATTR(input##value, S_IRUGO, show_input##value, NULL)
++
++show_input(0);
++show_input(1);
++show_input(2);
++show_input(3);
++
++static struct device_attribute dev_attrs[] = {
++ input_attr(0),
++ input_attr(1),
++ input_attr(2),
++ input_attr(3),
++ speed_attr(0),
++ speed_attr(1),
++ acceleration_attr(0),
++ acceleration_attr(1),
++ current_attr(0),
++ current_attr(1)
++};
++
++static int motorcontrol_probe(struct usb_interface *intf, const struct usb_device_id *id)
++{
++ struct usb_device *dev = interface_to_usbdev(intf);
++ struct usb_host_interface *interface;
++ struct usb_endpoint_descriptor *endpoint;
++ struct motorcontrol *mc;
++ int pipe, maxp, rc = -ENOMEM;
++ int bit, value, i;
++
++ interface = intf->cur_altsetting;
++ if (interface->desc.bNumEndpoints != 1)
++ return -ENODEV;
++
++ endpoint = &interface->endpoint[0].desc;
++ if (!(endpoint->bEndpointAddress & 0x80))
++ return -ENODEV;
++
++ /*
++ * bmAttributes
++ */
++ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
++ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
++
++ mc = kzalloc(sizeof(*mc), GFP_KERNEL);
++ if (!mc)
++ goto out;
++
++ mc->dev_no = -1;
++ mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &mc->data_dma);
++ if (!mc->data)
++ goto out;
++
++ mc->irq = usb_alloc_urb(0, GFP_KERNEL);
++ if (!mc->irq)
++ goto out;
++
++ mc->udev = usb_get_dev(dev);
++ mc->intf = intf;
++ mc->acceleration[0] = mc->acceleration[1] = 10;
++ INIT_WORK(&mc->do_notify, do_notify, mc);
++ usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data,
++ maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
++ motorcontrol_irq, mc, endpoint->bInterval);
++ mc->irq->transfer_dma = mc->data_dma;
++ mc->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++
++ usb_set_intfdata(intf, mc);
++
++ do {
++ bit = find_first_zero_bit(&device_no, sizeof(device_no));
++ value = test_and_set_bit(bit, &device_no);
++ } while(value);
++ mc->dev_no = bit;
++
++ mc->dev = device_create(phidget_class, &mc->udev->dev, 0,
++ "motorcontrol%d", mc->dev_no);
++ if (IS_ERR(mc->dev)) {
++ rc = PTR_ERR(mc->dev);
++ mc->dev = NULL;
++ goto out;
++ }
++
++ dev_set_drvdata(mc->dev, mc);
++
++ if (usb_submit_urb(mc->irq, GFP_KERNEL)) {
++ rc = -EIO;
++ goto out;
++ }
++
++ for (i=0; i<ARRAY_SIZE(dev_attrs); i++) {
++ rc = device_create_file(mc->dev, &dev_attrs[i]);
++ if (rc)
++ goto out2;
++ }
++
++ dev_info(&intf->dev, "USB PhidgetMotorControl attached\n");
++
++ return 0;
++out2:
++ while (i-- > 0)
++ device_remove_file(mc->dev, &dev_attrs[i]);
++out:
++ if (mc) {
++ if (mc->irq)
++ usb_free_urb(mc->irq);
++ if (mc->data)
++ usb_buffer_free(dev, URB_INT_SIZE, mc->data, mc->data_dma);
++ if (mc->dev)
++ device_unregister(mc->dev);
++ if (mc->dev_no >= 0)
++ clear_bit(mc->dev_no, &device_no);
++
++ kfree(mc);
++ }
++
++ return rc;
++}
++
++static void motorcontrol_disconnect(struct usb_interface *interface)
++{
++ struct motorcontrol *mc;
++ int i;
++
++ mc = usb_get_intfdata(interface);
++ usb_set_intfdata(interface, NULL);
++ if (!mc)
++ return;
++
++ usb_kill_urb(mc->irq);
++ usb_free_urb(mc->irq);
++ usb_buffer_free(mc->udev, URB_INT_SIZE, mc->data, mc->data_dma);
++
++ cancel_delayed_work(&mc->do_notify);
++
++ for (i=0; i<ARRAY_SIZE(dev_attrs); i++)
++ device_remove_file(mc->dev, &dev_attrs[i]);
++
++ device_unregister(mc->dev);
++
++ usb_put_dev(mc->udev);
++ clear_bit(mc->dev_no, &device_no);
++ kfree(mc);
++
++ dev_info(&interface->dev, "USB PhidgetMotorControl detached\n");
++}
++
++static struct usb_driver motorcontrol_driver = {
++ .name = "phidgetmotorcontrol",
++ .probe = motorcontrol_probe,
++ .disconnect = motorcontrol_disconnect,
++ .id_table = id_table
++};
++
++static int __init motorcontrol_init(void)
++{
++ int retval = 0;
++
++ retval = usb_register(&motorcontrol_driver);
++ if (retval)
++ err("usb_register failed. Error number %d", retval);
++
++ return retval;
++}
++
++static void __exit motorcontrol_exit(void)
++{
++ usb_deregister(&motorcontrol_driver);
++}
++
++module_init(motorcontrol_init);
++module_exit(motorcontrol_exit);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
+index c0df79c..7163f05 100644
+--- a/drivers/usb/misc/phidgetservo.c
++++ b/drivers/usb/misc/phidgetservo.c
+@@ -1,7 +1,7 @@
+ /*
+ * USB PhidgetServo driver 1.0
+ *
+- * Copyright (C) 2004 Sean Young <sean at mess.org>
++ * Copyright (C) 2004, 2006 Sean Young <sean at mess.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
+@@ -15,14 +15,6 @@
+ *
+ * CAUTION: Generally you should use 0 < degrees < 180 as anything else
+ * is probably beyond the range of your servo and may damage it.
+- *
+- * Jun 16, 2004: Sean Young <sean at mess.org>
+- * - cleanups
+- * - was using memory after kfree()
+- * Aug 8, 2004: Sean Young <sean at mess.org>
+- * - set the highest angle as high as the hardware allows, there are
+- * some odd servos out there
+- *
+ */
+
+ #include <linux/kernel.h>
+@@ -32,6 +24,8 @@
+ #include <linux/module.h>
+ #include <linux/usb.h>
+
++#include "phidget.h"
++
+ #define DRIVER_AUTHOR "Sean Young <sean at mess.org>"
+ #define DRIVER_DESC "USB PhidgetServo Driver"
+
+@@ -70,8 +64,12 @@ static struct usb_device_id id_table[] =
+
+ MODULE_DEVICE_TABLE(usb, id_table);
+
++static int unsigned long device_no;
++
+ struct phidget_servo {
+ struct usb_device *udev;
++ struct device *dev;
++ int dev_no;
+ ulong type;
+ int pulse[4];
+ int degrees[4];
+@@ -203,16 +201,16 @@ change_position_v20(struct phidget_servo
+ }
+
+ #define show_set(value) \
+-static ssize_t set_servo##value (struct device *dev, struct device_attribute *attr, \
++static ssize_t set_servo##value (struct device *dev, \
++ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ int degrees, minutes, retval; \
+- struct usb_interface *intf = to_usb_interface (dev); \
+- struct phidget_servo *servo = usb_get_intfdata (intf); \
++ struct phidget_servo *servo = dev_get_drvdata(dev); \
+ \
+ minutes = 0; \
+ /* must at least convert degrees */ \
+- if (sscanf (buf, "%d.%d", °rees, &minutes) < 1) { \
++ if (sscanf(buf, "%d.%d", °rees, &minutes) < 1) { \
+ return -EINVAL; \
+ } \
+ \
+@@ -220,86 +218,127 @@ static ssize_t set_servo##value (struct
+ return -EINVAL; \
+ \
+ if (servo->type & SERVO_VERSION_30) \
+- retval = change_position_v30 (servo, value, degrees, \
++ retval = change_position_v30(servo, value, degrees, \
+ minutes); \
+ else \
+- retval = change_position_v20 (servo, value, degrees, \
++ retval = change_position_v20(servo, value, degrees, \
+ minutes); \
+ \
+ return retval < 0 ? retval : count; \
+ } \
+ \
+-static ssize_t show_servo##value (struct device *dev, struct device_attribute *attr, char *buf) \
++static ssize_t show_servo##value (struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
+ { \
+- struct usb_interface *intf = to_usb_interface (dev); \
+- struct phidget_servo *servo = usb_get_intfdata (intf); \
++ struct phidget_servo *servo = dev_get_drvdata(dev); \
+ \
+- return sprintf (buf, "%d.%02d\n", servo->degrees[value], \
++ return sprintf(buf, "%d.%02d\n", servo->degrees[value], \
+ servo->minutes[value]); \
+-} \
+-static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \
+- show_servo##value, set_servo##value);
++}
+
++#define servo_attr(value) \
++ __ATTR(servo##value, S_IWUGO | S_IRUGO, \
++ show_servo##value, set_servo##value)
+ show_set(0);
+ show_set(1);
+ show_set(2);
+ show_set(3);
+
++static struct device_attribute dev_attrs[] = {
++ servo_attr(0), servo_attr(1), servo_attr(2), servo_attr(3)
++};
++
+ static int
+ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
+ {
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct phidget_servo *dev;
++ int bit, value, rc;
++ int servo_count, i;
+
+ dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
+- return -ENOMEM;
++ rc = -ENOMEM;
++ goto out;
+ }
+
+ dev->udev = usb_get_dev(udev);
+ dev->type = id->driver_info;
++ dev->dev_no = -1;
+ usb_set_intfdata(interface, dev);
+
+- device_create_file(&interface->dev, &dev_attr_servo0);
+- if (dev->type & SERVO_COUNT_QUAD) {
+- device_create_file(&interface->dev, &dev_attr_servo1);
+- device_create_file(&interface->dev, &dev_attr_servo2);
+- device_create_file(&interface->dev, &dev_attr_servo3);
++ do {
++ bit = find_first_zero_bit(&device_no, sizeof(device_no));
++ value = test_and_set_bit(bit, &device_no);
++ } while (value);
++ dev->dev_no = bit;
++
++ dev->dev = device_create(phidget_class, &dev->udev->dev, 0,
++ "servo%d", dev->dev_no);
++ if (IS_ERR(dev->dev)) {
++ rc = PTR_ERR(dev->dev);
++ dev->dev = NULL;
++ goto out;
++ }
++
++ servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
++
++ for (i=0; i<servo_count; i++) {
++ rc = device_create_file(dev->dev, &dev_attrs[i]);
++ if (rc)
++ goto out2;
+ }
+
+ dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
+- dev->type & SERVO_COUNT_QUAD ? 4 : 1,
+- dev->type & SERVO_VERSION_30 ? 3 : 2);
++ servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
+
+- if(!(dev->type & SERVO_VERSION_30))
++ if (!(dev->type & SERVO_VERSION_30))
+ dev_info(&interface->dev,
+ "WARNING: v2.0 not tested! Please report if it works.\n");
+
+ return 0;
++out2:
++ while (i-- > 0)
++ device_remove_file(dev->dev, &dev_attrs[i]);
++out:
++ if (dev) {
++ if (dev->dev)
++ device_unregister(dev->dev);
++ if (dev->dev_no >= 0)
++ clear_bit(dev->dev_no, &device_no);
++
++ kfree(dev);
++ }
++
++ return rc;
+ }
+
+ static void
+ servo_disconnect(struct usb_interface *interface)
+ {
+ struct phidget_servo *dev;
++ int servo_count, i;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+- device_remove_file(&interface->dev, &dev_attr_servo0);
+- if (dev->type & SERVO_COUNT_QUAD) {
+- device_remove_file(&interface->dev, &dev_attr_servo1);
+- device_remove_file(&interface->dev, &dev_attr_servo2);
+- device_remove_file(&interface->dev, &dev_attr_servo3);
+- }
++ if (!dev)
++ return;
++
++ servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
++
++ for (i=0; i<servo_count; i++)
++ device_remove_file(dev->dev, &dev_attrs[i]);
+
++ device_unregister(dev->dev);
+ usb_put_dev(dev->udev);
+
+ dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
+- dev->type & SERVO_COUNT_QUAD ? 4 : 1,
+- dev->type & SERVO_VERSION_30 ? 3 : 2);
++ servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
+
++ clear_bit(dev->dev_no, &device_no);
+ kfree(dev);
+ }
+
+diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
+index e16582f..b99ca9c 100644
+--- a/drivers/usb/misc/sisusbvga/sisusb.c
++++ b/drivers/usb/misc/sisusbvga/sisusb.c
+@@ -36,7 +36,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/mutex.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -210,7 +209,7 @@ sisusb_free_outbuf(struct sisusb_usb_dat
+ /* completion callback */
+
+ static void
+-sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
++sisusb_bulk_completeout(struct urb *urb)
+ {
+ struct sisusb_urb_context *context = urb->context;
+ struct sisusb_usb_data *sisusb;
+@@ -289,7 +288,7 @@ sisusb_bulkout_msg(struct sisusb_usb_dat
+ /* completion callback */
+
+ static void
+-sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
++sisusb_bulk_completein(struct urb *urb)
+ {
+ struct sisusb_usb_data *sisusb = urb->context;
+
+@@ -3179,7 +3178,7 @@ sisusb_compat_ioctl(struct file *f, unsi
+ }
+ #endif
+
+-static struct file_operations usb_sisusb_fops = {
++static const struct file_operations usb_sisusb_fops = {
+ .owner = THIS_MODULE,
+ .open = sisusb_open,
+ .release = sisusb_release,
+diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
+index fb48fec..bf26c3c 100644
+--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
++++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
+@@ -47,7 +47,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/mutex.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
+new file mode 100644
+index 0000000..33cd91d
+--- /dev/null
++++ b/drivers/usb/misc/trancevibrator.c
+@@ -0,0 +1,159 @@
++/*
++ * PlayStation 2 Trance Vibrator driver
++ *
++ * Copyright (C) 2006 Sam Hocevar <sam at zoy.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
++ * 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.
++ */
++
++/* Standard include files */
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++
++/* Version Information */
++#define DRIVER_VERSION "v1.1"
++#define DRIVER_AUTHOR "Sam Hocevar, sam at zoy.org"
++#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver"
++
++#define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */
++#define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */
++
++static struct usb_device_id id_table [] = {
++ { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
++ { },
++};
++MODULE_DEVICE_TABLE (usb, id_table);
++
++/* Driver-local specific stuff */
++struct trancevibrator {
++ struct usb_device *udev;
++ unsigned int speed;
++};
++
++static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct usb_interface *intf = to_usb_interface(dev);
++ struct trancevibrator *tv = usb_get_intfdata(intf);
++
++ return sprintf(buf, "%d\n", tv->speed);
++}
++
++static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct usb_interface *intf = to_usb_interface(dev);
++ struct trancevibrator *tv = usb_get_intfdata(intf);
++ int temp, retval;
++
++ temp = simple_strtoul(buf, NULL, 10);
++ if (temp > 255)
++ temp = 255;
++ else if (temp < 0)
++ temp = 0;
++ tv->speed = temp;
++
++ dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
++
++ /* Set speed */
++ retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
++ 0x01, /* vendor request: set speed */
++ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
++ tv->speed, /* speed value */
++ 0, NULL, 0, USB_CTRL_GET_TIMEOUT);
++ if (retval) {
++ dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
++ return retval;
++ }
++ return count;
++}
++
++static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
++
++static int tv_probe(struct usb_interface *interface,
++ const struct usb_device_id *id)
++{
++ struct usb_device *udev = interface_to_usbdev(interface);
++ struct trancevibrator *dev;
++ int retval;
++
++ dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL);
++ if (dev == NULL) {
++ dev_err(&interface->dev, "Out of memory\n");
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ dev->udev = usb_get_dev(udev);
++ usb_set_intfdata(interface, dev);
++ retval = device_create_file(&interface->dev, &dev_attr_speed);
++ if (retval)
++ goto error_create_file;
++
++ return 0;
++
++error_create_file:
++ usb_put_dev(udev);
++ usb_set_intfdata(interface, NULL);
++error:
++ kfree(dev);
++ return retval;
++}
++
++static void tv_disconnect(struct usb_interface *interface)
++{
++ struct trancevibrator *dev;
++
++ dev = usb_get_intfdata (interface);
++ usb_set_intfdata(interface, NULL);
++ device_remove_file(&interface->dev, &dev_attr_speed);
++ usb_put_dev(dev->udev);
++ kfree(dev);
++}
++
++/* USB subsystem object */
++static struct usb_driver tv_driver = {
++ .name = "trancevibrator",
++ .probe = tv_probe,
++ .disconnect = tv_disconnect,
++ .id_table = id_table,
++};
++
++static int __init tv_init(void)
++{
++ int retval = usb_register(&tv_driver);
++ if (retval) {
++ err("usb_register failed. Error number %d", retval);
++ return retval;
++ }
++
++ info(DRIVER_VERSION ":" DRIVER_DESC);
++ return 0;
++}
++
++static void __exit tv_exit(void)
++{
++ usb_deregister(&tv_driver);
++}
++
++module_init (tv_init);
++module_exit (tv_exit);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h
+new file mode 100644
+index 0000000..551ba89
+--- /dev/null
++++ b/drivers/usb/misc/usb_u132.h
+@@ -0,0 +1,97 @@
++/*
++* Common Header File for the Elan Digital Systems U132 adapter
++* this file should be included by both the "ftdi-u132" and
++* the "u132-hcd" modules.
++*
++* Copyright(C) 2006 Elan Digital Systems Limited
++*(http://www.elandigitalsystems.com)
++*
++* Author and Maintainer - Tony Olech - Elan Digital Systems
++*(tony.olech at elandigitalsystems.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.
++*
++*
++* The driver was written by Tony Olech(tony.olech at elandigitalsystems.com)
++* based on various USB client drivers in the 2.6.15 linux kernel
++* with constant reference to the 3rd Edition of Linux Device Drivers
++* published by O'Reilly
++*
++* The U132 adapter is a USB to CardBus adapter specifically designed
++* for PC cards that contain an OHCI host controller. Typical PC cards
++* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
++*
++* The U132 adapter will *NOT *work with PC cards that do not contain
++* an OHCI controller. A simple way to test whether a PC card has an
++* OHCI controller as an interface is to insert the PC card directly
++* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
++* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
++* then there is a good chance that the U132 adapter will support the
++* PC card.(you also need the specific client driver for the PC card)
++*
++* Please inform the Author and Maintainer about any PC cards that
++* contain OHCI Host Controller and work when directly connected to
++* an embedded CardBus slot but do not work when they are connected
++* via an ELAN U132 adapter.
++*
++* The driver consists of two modules, the "ftdi-u132" module is
++* a USB client driver that interfaces to the FTDI chip within
++* the U132 adapter manufactured by Elan Digital Systems, and the
++* "u132-hcd" module is a USB host controller driver that talks
++* to the OHCI controller within CardBus card that are inserted
++* in the U132 adapter.
++*
++* The "ftdi-u132" module should be loaded automatically by the
++* hot plug system when the U132 adapter is plugged in. The module
++* initialises the adapter which mostly consists of synchronising
++* the FTDI chip, before continuously polling the adapter to detect
++* PC card insertions. As soon as a PC card containing a recognised
++* OHCI controller is seen the "ftdi-u132" module explicitly requests
++* the kernel to load the "u132-hcd" module.
++*
++* The "ftdi-u132" module provides the interface to the inserted
++* PC card and the "u132-hcd" module uses the API to send and recieve
++* data. The API features call-backs, so that part of the "u132-hcd"
++* module code will run in the context of one of the kernel threads
++* of the "ftdi-u132" module.
++*
++*/
++int ftdi_elan_switch_on_diagnostics(int number);
++void ftdi_elan_gone_away(struct platform_device *pdev);
++void start_usb_lock_device_tracing(void);
++struct u132_platform_data {
++ u16 vendor;
++ u16 device;
++ u8 potpg;
++ void (*port_power) (struct device *dev, int is_on);
++ void (*reset) (struct device *dev);
++};
++int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null));
++int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null));
++int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null));
++int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null));
++int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
++ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
++ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
++ int toggle_bits, int error_count, int condition_code, int repeat_number,
++ int halted, int skipped, int actual, int non_null));
++int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
++ void *endp);
+diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
+index e095772..ada2ebc 100644
+--- a/drivers/usb/misc/usblcd.c
++++ b/drivers/usb/misc/usblcd.c
+@@ -165,7 +165,7 @@ static int lcd_ioctl(struct inode *inode
+ return 0;
+ }
+
+-static void lcd_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void lcd_write_bulk_callback(struct urb *urb)
+ {
+ struct usb_lcd *dev;
+
+@@ -239,7 +239,7 @@ error:
+ return retval;
+ }
+
+-static struct file_operations lcd_fops = {
++static const struct file_operations lcd_fops = {
+ .owner = THIS_MODULE,
+ .read = lcd_read,
+ .write = lcd_write,
+@@ -290,9 +290,7 @@ static int lcd_probe(struct usb_interfac
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (!dev->bulk_in_endpointAddr &&
+- (endpoint->bEndpointAddress & USB_DIR_IN) &&
+- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+- == USB_ENDPOINT_XFER_BULK)) {
++ usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found a bulk in endpoint */
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ dev->bulk_in_size = buffer_size;
+@@ -305,9 +303,7 @@ static int lcd_probe(struct usb_interfac
+ }
+
+ if (!dev->bulk_out_endpointAddr &&
+- !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+- == USB_ENDPOINT_XFER_BULK)) {
++ usb_endpoint_is_bulk_out(endpoint)) {
+ /* we found a bulk out endpoint */
+ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ }
+diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
+index 0c5ee0a..49c5c5c 100644
+--- a/drivers/usb/misc/usbled.c
++++ b/drivers/usb/misc/usbled.c
+@@ -108,22 +108,34 @@ static int led_probe(struct usb_interfac
+ dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+- goto error;
++ goto error_mem;
+ }
+
+ dev->udev = usb_get_dev(udev);
+
+ usb_set_intfdata (interface, dev);
+
+- device_create_file(&interface->dev, &dev_attr_blue);
+- device_create_file(&interface->dev, &dev_attr_red);
+- device_create_file(&interface->dev, &dev_attr_green);
++ retval = device_create_file(&interface->dev, &dev_attr_blue);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_red);
++ if (retval)
++ goto error;
++ retval = device_create_file(&interface->dev, &dev_attr_green);
++ if (retval)
++ goto error;
+
+ dev_info(&interface->dev, "USB LED device now attached\n");
+ return 0;
+
+ error:
++ device_remove_file(&interface->dev, &dev_attr_blue);
++ device_remove_file(&interface->dev, &dev_attr_red);
++ device_remove_file(&interface->dev, &dev_attr_green);
++ usb_set_intfdata (interface, NULL);
++ usb_put_dev(dev->udev);
+ kfree(dev);
++error_mem:
+ return retval;
+ }
+
+diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
+index 983e104..7c2cbdf 100644
+--- a/drivers/usb/misc/usbtest.c
++++ b/drivers/usb/misc/usbtest.c
+@@ -198,7 +198,7 @@ found:
+ * them with non-zero test data (or test for it) when appropriate.
+ */
+
+-static void simple_callback (struct urb *urb, struct pt_regs *regs)
++static void simple_callback (struct urb *urb)
+ {
+ complete ((struct completion *) urb->context);
+ }
+@@ -730,7 +730,7 @@ struct subcase {
+ int expected;
+ };
+
+-static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
++static void ctrl_complete (struct urb *urb)
+ {
+ struct ctrl_ctx *ctx = urb->context;
+ struct usb_ctrlrequest *reqp;
+@@ -1035,7 +1035,7 @@ cleanup:
+
+ /*-------------------------------------------------------------------------*/
+
+-static void unlink1_callback (struct urb *urb, struct pt_regs *regs)
++static void unlink1_callback (struct urb *urb)
+ {
+ int status = urb->status;
+
+@@ -1343,7 +1343,7 @@ struct iso_context {
+ struct usbtest_dev *dev;
+ };
+
+-static void iso_callback (struct urb *urb, struct pt_regs *regs)
++static void iso_callback (struct urb *urb)
+ {
+ struct iso_context *ctx = urb->context;
+
+diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
+index 4081990..7e8a0ac 100644
+--- a/drivers/usb/misc/uss720.c
++++ b/drivers/usb/misc/uss720.c
+@@ -106,7 +106,7 @@ static void destroy_async(struct kref *k
+
+ /* --------------------------------------------------------------------- */
+
+-static void async_complete(struct urb *urb, struct pt_regs *ptregs)
++static void async_complete(struct urb *urb)
+ {
+ struct uss720_async_request *rq;
+ struct parport *pp;
+@@ -127,7 +127,7 @@ static void async_complete(struct urb *u
+ #endif
+ /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+ if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
+- parport_generic_irq(0, pp, NULL);
++ parport_generic_irq(0, pp);
+ }
+ complete(&rq->compl);
+ kref_put(&rq->ref_count, destroy_async);
+diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
+index 275a66f..394bbf2 100644
+--- a/drivers/usb/mon/mon_main.c
++++ b/drivers/usb/mon/mon_main.c
+@@ -265,7 +265,6 @@ static void mon_dissolve(struct mon_bus
+ ubus->mon_bus = NULL;
+ mbus->u_bus = NULL;
+ mb();
+- // usb_bus_put(ubus);
+ }
+
+ /*
+@@ -297,12 +296,12 @@ static void mon_bus_init(struct dentry *
+ INIT_LIST_HEAD(&mbus->r_list);
+
+ /*
+- * This usb_bus_get here is superfluous, because we receive
+- * a notification if usb_bus is about to be removed.
++ * We don't need to take a reference to ubus, because we receive
++ * a notification if the bus is about to be removed.
+ */
+- // usb_bus_get(ubus);
+ mbus->u_bus = ubus;
+ ubus->mon_bus = mbus;
++ mbus->uses_dma = ubus->uses_dma;
+
+ rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
+index 1fe01d9..f6d1491 100644
+--- a/drivers/usb/mon/mon_stat.c
++++ b/drivers/usb/mon/mon_stat.c
+@@ -28,7 +28,7 @@ static int mon_stat_open(struct inode *i
+ if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+- mbus = inode->u.generic_ip;
++ mbus = inode->i_private;
+
+ sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
+ "nreaders %d events %u text_lost %u\n",
+@@ -62,7 +62,7 @@ static int mon_stat_release(struct inode
+ return 0;
+ }
+
+-struct file_operations mon_fops_stat = {
++const struct file_operations mon_fops_stat = {
+ .owner = THIS_MODULE,
+ .open = mon_stat_open,
+ .llseek = no_llseek,
+diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
+index f961a77..7a2346c 100644
+--- a/drivers/usb/mon/mon_text.c
++++ b/drivers/usb/mon/mon_text.c
+@@ -75,13 +75,13 @@ static void mon_text_ctor(void *, kmem_c
+ */
+
+ static inline char mon_text_get_setup(struct mon_event_text *ep,
+- struct urb *urb, char ev_type)
++ struct urb *urb, char ev_type, struct mon_bus *mbus)
+ {
+
+ if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ return '-';
+
+- if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
++ if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
+ if (urb->setup_packet == NULL)
+ return 'Z'; /* '0' would be not as pretty. */
+@@ -91,7 +91,7 @@ static inline char mon_text_get_setup(st
+ }
+
+ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
+- int len, char ev_type)
++ int len, char ev_type, struct mon_bus *mbus)
+ {
+ int pipe = urb->pipe;
+
+@@ -117,7 +117,7 @@ static inline char mon_text_get_data(str
+ * contain non-NULL garbage in case the upper level promised to
+ * set DMA for the HCD.
+ */
+- if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
++ if (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ return mon_dmapeek(ep->data, urb->transfer_dma, len);
+
+ if (urb->transfer_buffer == NULL)
+@@ -161,8 +161,9 @@ static void mon_text_event(struct mon_re
+ /* 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);
++ ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus);
++ ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type,
++ rp->r.m_bus);
+
+ rp->nevents++;
+ list_add_tail(&ep->e_link, &rp->e_list);
+@@ -238,7 +239,7 @@ static int mon_text_open(struct inode *i
+ int rc;
+
+ mutex_lock(&mon_lock);
+- mbus = inode->u.generic_ip;
++ mbus = inode->i_private;
+ ubus = mbus->u_bus;
+
+ rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
+@@ -401,7 +402,7 @@ static int mon_text_release(struct inode
+ struct mon_event_text *ep;
+
+ mutex_lock(&mon_lock);
+- mbus = inode->u.generic_ip;
++ mbus = inode->i_private;
+
+ if (mbus->nreaders <= 0) {
+ printk(KERN_ERR TAG ": consistency error on close\n");
+@@ -435,7 +436,7 @@ static int mon_text_release(struct inode
+ return 0;
+ }
+
+-struct file_operations mon_fops_text = {
++const struct file_operations mon_fops_text = {
+ .owner = THIS_MODULE,
+ .open = mon_text_open,
+ .llseek = no_llseek,
+diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
+index 33678c2..ab9d02d 100644
+--- a/drivers/usb/mon/usb_mon.h
++++ b/drivers/usb/mon/usb_mon.h
+@@ -20,6 +20,7 @@ struct mon_bus {
+ struct dentry *dent_s; /* Debugging file */
+ struct dentry *dent_t; /* Text interface file */
+ struct usb_bus *u_bus;
++ int uses_dma;
+
+ /* Ref */
+ int nreaders; /* Under mon_lock AND mbus->lock */
+@@ -53,7 +54,7 @@ extern char mon_dmapeek(unsigned char *d
+
+ extern struct mutex mon_lock;
+
+-extern struct file_operations mon_fops_text;
+-extern struct file_operations mon_fops_stat;
++extern const struct file_operations mon_fops_text;
++extern const struct file_operations mon_fops_stat;
+
+ #endif /* __USB_MON_H */
+diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
+index 0540596..e081836 100644
+--- a/drivers/usb/net/Kconfig
++++ b/drivers/usb/net/Kconfig
+@@ -92,8 +92,13 @@ config USB_RTL8150
+ To compile this driver as a module, choose M here: the
+ module will be called rtl8150.
+
++config USB_USBNET_MII
++ tristate
++ default n
++
+ config USB_USBNET
+ tristate "Multi-purpose USB Networking Framework"
++ select MII if USBNET_MII != n
+ ---help---
+ This driver supports several kinds of network links over USB,
+ with "minidrivers" built around a common network driver core
+@@ -129,7 +134,7 @@ config USB_NET_AX8817X
+ tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
+ depends on USB_USBNET && NET_ETHERNET
+ select CRC32
+- select MII
++ select USB_USBNET_MII
+ default y
+ help
+ This option adds support for ASIX AX88xxx based USB 2.0
+@@ -207,6 +212,15 @@ config USB_NET_PLUSB
+ Choose this option if you're using a host-to-host cable
+ with one of these chips.
+
++config USB_NET_MCS7830
++ tristate "MosChip MCS7830 based Ethernet adapters"
++ depends on USB_USBNET
++ select USB_USBNET_MII
++ help
++ Choose this option if you're using a 10/100 Ethernet USB2
++ adapter based on the MosChip 7830 controller. This includes
++ adapters marketed under the DeLOCK brand.
++
+ config USB_NET_RNDIS_HOST
+ tristate "Host for RNDIS devices (EXPERIMENTAL)"
+ depends on USB_USBNET && EXPERIMENTAL
+diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
+index 160f19d..7b51964 100644
+--- a/drivers/usb/net/Makefile
++++ b/drivers/usb/net/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
+ obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
+ obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
+ obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
++obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
+ obj-$(CONFIG_USB_USBNET) += usbnet.o
+
+ ifeq ($(CONFIG_USB_DEBUG),y)
+diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
+index 2e2bbc0..881841e 100644
+--- a/drivers/usb/net/asix.c
++++ b/drivers/usb/net/asix.c
+@@ -1,7 +1,8 @@
+ /*
+ * ASIX AX8817X based USB 2.0 Ethernet Devices
+- * Copyright (C) 2003-2005 David Hollis <dhollis at davehollis.com>
++ * Copyright (C) 2003-2006 David Hollis <dhollis at davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23 at sbcglobal.net>
++ * Copyright (C) 2006 James Painter <jamie.painter at iname.com>
+ * Copyright (c) 2002-2003 TiVo Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+@@ -36,6 +37,9 @@
+
+ #include "usbnet.h"
+
++#define DRIVER_VERSION "14-Jun-2006"
++static const char driver_name [] = "asix";
++
+ /* ASIX AX8817X based USB 2.0 Ethernet Devices */
+
+ #define AX_CMD_SET_SW_MII 0x06
+@@ -46,23 +50,25 @@
+ #define AX_CMD_WRITE_EEPROM 0x0c
+ #define AX_CMD_WRITE_ENABLE 0x0d
+ #define AX_CMD_WRITE_DISABLE 0x0e
++#define AX_CMD_READ_RX_CTL 0x0f
+ #define AX_CMD_WRITE_RX_CTL 0x10
+ #define AX_CMD_READ_IPG012 0x11
+ #define AX_CMD_WRITE_IPG0 0x12
+ #define AX_CMD_WRITE_IPG1 0x13
++#define AX_CMD_READ_NODE_ID 0x13
+ #define AX_CMD_WRITE_IPG2 0x14
+ #define AX_CMD_WRITE_MULTI_FILTER 0x16
+-#define AX_CMD_READ_NODE_ID 0x17
++#define AX88172_CMD_READ_NODE_ID 0x17
+ #define AX_CMD_READ_PHY_ID 0x19
+ #define AX_CMD_READ_MEDIUM_STATUS 0x1a
+ #define AX_CMD_WRITE_MEDIUM_MODE 0x1b
+ #define AX_CMD_READ_MONITOR_MODE 0x1c
+ #define AX_CMD_WRITE_MONITOR_MODE 0x1d
++#define AX_CMD_READ_GPIOS 0x1e
+ #define AX_CMD_WRITE_GPIOS 0x1f
+ #define AX_CMD_SW_RESET 0x20
+ #define AX_CMD_SW_PHY_STATUS 0x21
+ #define AX_CMD_SW_PHY_SELECT 0x22
+-#define AX88772_CMD_READ_NODE_ID 0x13
+
+ #define AX_MONITOR_MODE 0x01
+ #define AX_MONITOR_LINK 0x02
+@@ -70,15 +76,15 @@
+ #define AX_MONITOR_HSFS 0x10
+
+ /* AX88172 Medium Status Register values */
+-#define AX_MEDIUM_FULL_DUPLEX 0x02
+-#define AX_MEDIUM_TX_ABORT_ALLOW 0x04
+-#define AX_MEDIUM_FLOW_CONTROL_EN 0x10
++#define AX88172_MEDIUM_FD 0x02
++#define AX88172_MEDIUM_TX 0x04
++#define AX88172_MEDIUM_FC 0x10
++#define AX88172_MEDIUM_DEFAULT \
++ ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )
+
+ #define AX_MCAST_FILTER_SIZE 8
+ #define AX_MAX_MCAST 64
+
+-#define AX_EEPROM_LEN 0x40
+-
+ #define AX_SWRESET_CLEAR 0x00
+ #define AX_SWRESET_RR 0x01
+ #define AX_SWRESET_RT 0x02
+@@ -92,23 +98,78 @@
+ #define AX88772_IPG1_DEFAULT 0x0c
+ #define AX88772_IPG2_DEFAULT 0x12
+
+-#define AX88772_MEDIUM_FULL_DUPLEX 0x0002
+-#define AX88772_MEDIUM_RESERVED 0x0004
+-#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010
+-#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020
+-#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080
+-#define AX88772_MEDIUM_RX_ENABLE 0x0100
+-#define AX88772_MEDIUM_100MB 0x0200
+-#define AX88772_MEDIUM_DEFAULT \
+- (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
+- AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
+- AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
++/* AX88772 & AX88178 Medium Mode Register */
++#define AX_MEDIUM_PF 0x0080
++#define AX_MEDIUM_JFE 0x0040
++#define AX_MEDIUM_TFC 0x0020
++#define AX_MEDIUM_RFC 0x0010
++#define AX_MEDIUM_ENCK 0x0008
++#define AX_MEDIUM_AC 0x0004
++#define AX_MEDIUM_FD 0x0002
++#define AX_MEDIUM_GM 0x0001
++#define AX_MEDIUM_SM 0x1000
++#define AX_MEDIUM_SBP 0x0800
++#define AX_MEDIUM_PS 0x0200
++#define AX_MEDIUM_RE 0x0100
++
++#define AX88178_MEDIUM_DEFAULT \
++ (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
++ AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
++ AX_MEDIUM_RE )
+
+-#define AX_EEPROM_MAGIC 0xdeadbeef
++#define AX88772_MEDIUM_DEFAULT \
++ (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
++ AX_MEDIUM_TFC | AX_MEDIUM_PS | \
++ AX_MEDIUM_AC | AX_MEDIUM_RE )
++
++/* AX88772 & AX88178 RX_CTL values */
++#define AX_RX_CTL_SO 0x0080
++#define AX_RX_CTL_AP 0x0020
++#define AX_RX_CTL_AM 0x0010
++#define AX_RX_CTL_AB 0x0008
++#define AX_RX_CTL_SEP 0x0004
++#define AX_RX_CTL_AMALL 0x0002
++#define AX_RX_CTL_PRO 0x0001
++#define AX_RX_CTL_MFB_2048 0x0000
++#define AX_RX_CTL_MFB_4096 0x0100
++#define AX_RX_CTL_MFB_8192 0x0200
++#define AX_RX_CTL_MFB_16384 0x0300
++
++#define AX_DEFAULT_RX_CTL \
++ (AX_RX_CTL_SO | AX_RX_CTL_AB )
++
++/* GPIO 0 .. 2 toggles */
++#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
++#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */
++#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */
++#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */
++#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
++#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
++#define AX_GPIO_RESERVED 0x40 /* Reserved */
++#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
++
++#define AX_EEPROM_MAGIC 0xdeadbeef
++#define AX88172_EEPROM_LEN 0x40
++#define AX88772_EEPROM_LEN 0xff
++
++#define PHY_MODE_MARVELL 0x0000
++#define MII_MARVELL_LED_CTRL 0x0018
++#define MII_MARVELL_STATUS 0x001b
++#define MII_MARVELL_CTRL 0x0014
++
++#define MARVELL_LED_MANUAL 0x0019
++
++#define MARVELL_STATUS_HWCFG 0x0004
++
++#define MARVELL_CTRL_TXDELAY 0x0002
++#define MARVELL_CTRL_RXDELAY 0x0080
+
+ /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+ struct asix_data {
+ u8 multi_filter[AX_MCAST_FILTER_SIZE];
++ u8 phymode;
++ u8 ledmode;
++ u8 eeprom_len;
+ };
+
+ struct ax88172_int_data {
+@@ -122,6 +183,8 @@ struct ax88172_int_data {
+ static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+ {
++ devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
++ cmd, value, index, size);
+ return usb_control_msg(
+ dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+@@ -137,6 +200,8 @@ static int asix_read_cmd(struct usbnet *
+ static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+ {
++ devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
++ cmd, value, index, size);
+ return usb_control_msg(
+ dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+@@ -149,7 +214,7 @@ static int asix_write_cmd(struct usbnet
+ USB_CTRL_SET_TIMEOUT);
+ }
+
+-static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
++static void asix_async_cmd_callback(struct urb *urb)
+ {
+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+@@ -161,12 +226,167 @@ static void asix_async_cmd_callback(stru
+ usb_free_urb(urb);
+ }
+
++static void
++asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
++ u16 size, void *data)
++{
++ struct usb_ctrlrequest *req;
++ int status;
++ struct urb *urb;
++
++ devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
++ cmd, value, index, size);
++ if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
++ deverr(dev, "Error allocating URB in write_cmd_async!");
++ return;
++ }
++
++ if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
++ deverr(dev, "Failed to allocate memory for control request");
++ usb_free_urb(urb);
++ return;
++ }
++
++ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
++ req->bRequest = cmd;
++ req->wValue = value;
++ req->wIndex = index;
++ req->wLength = size;
++
++ usb_fill_control_urb(urb, dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ (void *)req, data, size,
++ asix_async_cmd_callback, req);
++
++ if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
++ deverr(dev, "Error submitting the control message: status=%d",
++ status);
++ kfree(req);
++ usb_free_urb(urb);
++ }
++}
++
++static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
++{
++ u8 *head;
++ u32 header;
++ char *packet;
++ struct sk_buff *ax_skb;
++ u16 size;
++
++ head = (u8 *) skb->data;
++ memcpy(&header, head, sizeof(header));
++ le32_to_cpus(&header);
++ packet = head + sizeof(header);
++
++ skb_pull(skb, 4);
++
++ while (skb->len > 0) {
++ if ((short)(header & 0x0000ffff) !=
++ ~((short)((header & 0xffff0000) >> 16))) {
++ deverr(dev,"asix_rx_fixup() Bad Header Length");
++ }
++ /* get the packet length */
++ size = (u16) (header & 0x0000ffff);
++
++ if ((skb->len) - ((size + 1) & 0xfffe) == 0)
++ return 2;
++ if (size > ETH_FRAME_LEN) {
++ deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);
++ return 0;
++ }
++ ax_skb = skb_clone(skb, GFP_ATOMIC);
++ if (ax_skb) {
++ ax_skb->len = size;
++ ax_skb->data = packet;
++ ax_skb->tail = packet + size;
++ usbnet_skb_return(dev, ax_skb);
++ } else {
++ return 0;
++ }
++
++ skb_pull(skb, (size + 1) & 0xfffe);
++
++ if (skb->len == 0)
++ break;
++
++ head = (u8 *) skb->data;
++ memcpy(&header, head, sizeof(header));
++ le32_to_cpus(&header);
++ packet = head + sizeof(header);
++ skb_pull(skb, 4);
++ }
++
++ if (skb->len < 0) {
++ deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len);
++ return 0;
++ }
++ return 1;
++}
++
++static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
++ gfp_t flags)
++{
++ int padlen;
++ int headroom = skb_headroom(skb);
++ int tailroom = skb_tailroom(skb);
++ u32 packet_len;
++ u32 padbytes = 0xffff0000;
++
++ padlen = ((skb->len + 4) % 512) ? 0 : 4;
++
++ if ((!skb_cloned(skb))
++ && ((headroom + tailroom) >= (4 + padlen))) {
++ if ((headroom < 4) || (tailroom < padlen)) {
++ skb->data = memmove(skb->head + 4, skb->data, skb->len);
++ skb->tail = skb->data + skb->len;
++ }
++ } else {
++ struct sk_buff *skb2;
++ skb2 = skb_copy_expand(skb, 4, padlen, flags);
++ dev_kfree_skb_any(skb);
++ skb = skb2;
++ if (!skb)
++ return NULL;
++ }
++
++ skb_push(skb, 4);
++ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
++ memcpy(skb->data, &packet_len, sizeof(packet_len));
++
++ if ((skb->len % 512) == 0) {
++ memcpy( skb->tail, &padbytes, sizeof(padbytes));
++ skb_put(skb, sizeof(padbytes));
++ }
++ return skb;
++}
++
++static void asix_status(struct usbnet *dev, struct urb *urb)
++{
++ struct ax88172_int_data *event;
++ int link;
++
++ if (urb->actual_length < 8)
++ return;
++
++ event = urb->transfer_buffer;
++ link = event->link & 0x01;
++ if (netif_carrier_ok(dev->net) != link) {
++ if (link) {
++ netif_carrier_on(dev->net);
++ usbnet_defer_kevent (dev, EVENT_LINK_RESET );
++ } else
++ netif_carrier_off(dev->net);
++ devdbg(dev, "Link Status is: %d", link);
++ }
++}
++
+ static inline int asix_set_sw_mii(struct usbnet *dev)
+ {
+ int ret;
+ ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+- devdbg(dev, "Failed to enable software MII access");
++ deverr(dev, "Failed to enable software MII access");
+ return ret;
+ }
+
+@@ -175,24 +395,27 @@ static inline int asix_set_hw_mii(struct
+ int ret;
+ ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+- devdbg(dev, "Failed to enable hardware MII access");
++ deverr(dev, "Failed to enable hardware MII access");
+ return ret;
+ }
+
+-static inline int asix_get_phyid(struct usbnet *dev)
++static inline int asix_get_phy_addr(struct usbnet *dev)
+ {
+ int ret = 0;
+ void *buf;
+
++ devdbg(dev, "asix_get_phy_addr()");
++
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ goto out1;
+
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID,
+ 0, 0, 2, buf)) < 2) {
+- devdbg(dev, "Error reading PHYID register: %02x", ret);
++ deverr(dev, "Error reading PHYID register: %02x", ret);
+ goto out2;
+ }
++ devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((u16 *)buf));
+ ret = *((u8 *)buf + 1);
+ out2:
+ kfree(buf);
+@@ -206,91 +429,109 @@ static int asix_sw_reset(struct usbnet *
+
+ ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
+ if (ret < 0)
+- devdbg(dev,"Failed to send software reset: %02x", ret);
++ deverr(dev,"Failed to send software reset: %02x", ret);
+
+ return ret;
+ }
+
++static u16 asix_read_rx_ctl(struct usbnet *dev)
++{
++ u16 ret = 0;
++ void *buf;
++
++ buf = kmalloc(2, GFP_KERNEL);
++ if (!buf)
++ goto out1;
++
++ if ((ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL,
++ 0, 0, 2, buf)) < 2) {
++ deverr(dev, "Error reading RX_CTL register: %02x", ret);
++ goto out2;
++ }
++ ret = le16_to_cpu(*((u16 *)buf));
++out2:
++ kfree(buf);
++out1:
++ return ret;
++}
++
+ static int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
+ {
+ int ret;
+
++ devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+ if (ret < 0)
+- devdbg(dev, "Failed to write RX_CTL mode: %02x", ret);
++ deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x",
++ mode, ret);
+
+ return ret;
+ }
+
+-static void asix_status(struct usbnet *dev, struct urb *urb)
++static u16 asix_read_medium_status(struct usbnet *dev)
+ {
+- struct ax88172_int_data *event;
+- int link;
++ u16 ret = 0;
++ void *buf;
+
+- if (urb->actual_length < 8)
+- return;
++ buf = kmalloc(2, GFP_KERNEL);
++ if (!buf)
++ goto out1;
+
+- event = urb->transfer_buffer;
+- link = event->link & 0x01;
+- if (netif_carrier_ok(dev->net) != link) {
+- if (link) {
+- netif_carrier_on(dev->net);
+- usbnet_defer_kevent (dev, EVENT_LINK_RESET );
+- } else
+- netif_carrier_off(dev->net);
+- devdbg(dev, "Link Status is: %d", link);
++ if ((ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS,
++ 0, 0, 2, buf)) < 2) {
++ deverr(dev, "Error reading Medium Status register: %02x", ret);
++ goto out2;
+ }
++ ret = le16_to_cpu(*((u16 *)buf));
++out2:
++ kfree(buf);
++out1:
++ return ret;
+ }
+
+-static void
+-asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+- u16 size, void *data)
++static int asix_write_medium_mode(struct usbnet *dev, u16 mode)
+ {
+- struct usb_ctrlrequest *req;
+- int status;
+- struct urb *urb;
++ int ret;
+
+- if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
+- devdbg(dev, "Error allocating URB in write_cmd_async!");
+- return;
+- }
++ devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode);
++ ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
++ if (ret < 0)
++ deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x",
++ mode, ret);
+
+- if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
+- deverr(dev, "Failed to allocate memory for control request");
+- usb_free_urb(urb);
+- return;
+- }
++ return ret;
++}
+
+- req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+- req->bRequest = cmd;
+- req->wValue = cpu_to_le16(value);
+- req->wIndex = cpu_to_le16(index);
+- req->wLength = cpu_to_le16(size);
++static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
++{
++ int ret;
+
+- usb_fill_control_urb(urb, dev->udev,
+- usb_sndctrlpipe(dev->udev, 0),
+- (void *)req, data, size,
+- asix_async_cmd_callback, req);
++ devdbg(dev,"asix_write_gpio() - value = 0x%04x", value);
++ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
++ if (ret < 0)
++ deverr(dev, "Failed to write GPIO value 0x%04x: %02x",
++ value, ret);
+
+- if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+- deverr(dev, "Error submitting the control message: status=%d",
+- status);
+- kfree(req);
+- usb_free_urb(urb);
+- }
++ if (sleep)
++ msleep(sleep);
++
++ return ret;
+ }
+
++/*
++ * AX88772 & AX88178 have a 16-bit RX_CTL value
++ */
+ static void asix_set_multicast(struct net_device *net)
+ {
+ struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+- u8 rx_ctl = 0x8c;
++ u16 rx_ctl = AX_DEFAULT_RX_CTL;
+
+ if (net->flags & IFF_PROMISC) {
+- rx_ctl |= 0x01;
++ rx_ctl |= AX_RX_CTL_PRO;
+ } else if (net->flags & IFF_ALLMULTI
+ || net->mc_count > AX_MAX_MCAST) {
+- rx_ctl |= 0x02;
++ rx_ctl |= AX_RX_CTL_AMALL;
+ } else if (net->mc_count == 0) {
+ /* just broadcast and directed */
+ } else {
+@@ -317,7 +558,7 @@ static void asix_set_multicast(struct ne
+ asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+ AX_MCAST_FILTER_SIZE, data->multi_filter);
+
+- rx_ctl |= 0x10;
++ rx_ctl |= AX_RX_CTL_AM;
+ }
+
+ asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+@@ -328,55 +569,52 @@ static int asix_mdio_read(struct net_dev
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 res;
+
++ mutex_lock(&dev->phy_mutex);
+ asix_set_sw_mii(dev);
+ asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
+ (__u16)loc, 2, (u16 *)&res);
+ asix_set_hw_mii(dev);
++ mutex_unlock(&dev->phy_mutex);
+
+- return res & 0xffff;
+-}
++ devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff));
+
+-/* same as above, but converts resulting value to cpu byte order */
+-static int asix_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
+-{
+- return le16_to_cpu(asix_mdio_read(netdev,phy_id, loc));
++ return le16_to_cpu(res & 0xffff);
+ }
+
+ static void
+ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+ {
+ struct usbnet *dev = netdev_priv(netdev);
+- u16 res = val;
++ u16 res = cpu_to_le16(val);
+
++ devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);
++ mutex_lock(&dev->phy_mutex);
+ asix_set_sw_mii(dev);
+ asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
+ (__u16)loc, 2, (u16 *)&res);
+ asix_set_hw_mii(dev);
++ mutex_unlock(&dev->phy_mutex);
+ }
+
+-/* same as above, but converts new value to le16 byte order before writing */
+-static void
+-asix_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
++/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
++static u32 asix_get_phyid(struct usbnet *dev)
+ {
+- asix_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
+-}
++ int phy_reg;
++ u32 phy_id;
+
+-static int ax88172_link_reset(struct usbnet *dev)
+-{
+- u16 lpa;
+- u16 adv;
+- u16 res;
+- u8 mode;
++ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
++ if (phy_reg < 0)
++ return 0;
+
+- mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
+- lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+- adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+- res = mii_nway_result(lpa|adv);
+- if (res & LPA_DUPLEX)
+- mode |= AX_MEDIUM_FULL_DUPLEX;
+- asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
++ phy_id = (phy_reg & 0xffff) << 16;
+
+- return 0;
++ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
++ if (phy_reg < 0)
++ return 0;
++
++ phy_id |= (phy_reg & 0xffff);
++
++ return phy_id;
+ }
+
+ static void
+@@ -423,7 +661,10 @@ asix_set_wol(struct net_device *net, str
+
+ static int asix_get_eeprom_len(struct net_device *net)
+ {
+- return AX_EEPROM_LEN;
++ struct usbnet *dev = netdev_priv(net);
++ struct asix_data *data = (struct asix_data *)&dev->data;
++
++ return data->eeprom_len;
+ }
+
+ static int asix_get_eeprom(struct net_device *net,
+@@ -453,23 +694,28 @@ static int asix_get_eeprom(struct net_de
+ static void asix_get_drvinfo (struct net_device *net,
+ struct ethtool_drvinfo *info)
+ {
++ struct usbnet *dev = netdev_priv(net);
++ struct asix_data *data = (struct asix_data *)&dev->data;
++
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+- info->eedump_len = 0x3e;
++ strncpy (info->driver, driver_name, sizeof info->driver);
++ strncpy (info->version, DRIVER_VERSION, sizeof info->version);
++ info->eedump_len = data->eeprom_len;
+ }
+
+-static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
++static u32 asix_get_link(struct net_device *net)
+ {
+ struct usbnet *dev = netdev_priv(net);
+
+- return mii_ethtool_gset(&dev->mii,cmd);
++ return mii_link_ok(&dev->mii);
+ }
+
+-static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
++static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+ {
+ struct usbnet *dev = netdev_priv(net);
+
+- return mii_ethtool_sset(&dev->mii,cmd);
++ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+ }
+
+ /* We need to override some ethtool_ops so we require our
+@@ -477,22 +723,78 @@ static int asix_set_settings(struct net_
+ devices that may be connected at the same time. */
+ static struct ethtool_ops ax88172_ethtool_ops = {
+ .get_drvinfo = asix_get_drvinfo,
+- .get_link = ethtool_op_get_link,
++ .get_link = asix_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = asix_get_wol,
+ .set_wol = asix_set_wol,
+ .get_eeprom_len = asix_get_eeprom_len,
+ .get_eeprom = asix_get_eeprom,
+- .get_settings = asix_get_settings,
+- .set_settings = asix_set_settings,
++ .get_settings = usbnet_get_settings,
++ .set_settings = usbnet_set_settings,
++ .nway_reset = usbnet_nway_reset,
+ };
+
+-static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
++static void ax88172_set_multicast(struct net_device *net)
+ {
+ struct usbnet *dev = netdev_priv(net);
++ struct asix_data *data = (struct asix_data *)&dev->data;
++ u8 rx_ctl = 0x8c;
+
+- return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
++ if (net->flags & IFF_PROMISC) {
++ rx_ctl |= 0x01;
++ } else if (net->flags & IFF_ALLMULTI
++ || net->mc_count > AX_MAX_MCAST) {
++ rx_ctl |= 0x02;
++ } else if (net->mc_count == 0) {
++ /* just broadcast and directed */
++ } else {
++ /* We use the 20 byte dev->data
++ * for our 8 byte filter buffer
++ * to avoid allocating memory that
++ * is tricky to free later */
++ struct dev_mc_list *mc_list = net->mc_list;
++ u32 crc_bits;
++ int i;
++
++ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
++
++ /* Build the multicast hash filter. */
++ for (i = 0; i < net->mc_count; i++) {
++ crc_bits =
++ ether_crc(ETH_ALEN,
++ mc_list->dmi_addr) >> 26;
++ data->multi_filter[crc_bits >> 3] |=
++ 1 << (crc_bits & 7);
++ mc_list = mc_list->next;
++ }
++
++ asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
++ AX_MCAST_FILTER_SIZE, data->multi_filter);
++
++ rx_ctl |= 0x10;
++ }
++
++ asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
++}
++
++static int ax88172_link_reset(struct usbnet *dev)
++{
++ u8 mode;
++ struct ethtool_cmd ecmd;
++
++ mii_check_media(&dev->mii, 1, 1);
++ mii_ethtool_gset(&dev->mii, &ecmd);
++ mode = AX88172_MEDIUM_DEFAULT;
++
++ if (ecmd.duplex != DUPLEX_FULL)
++ mode |= ~AX88172_MEDIUM_FD;
++
++ devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
++
++ asix_write_medium_mode(dev, mode);
++
++ return 0;
+ }
+
+ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
+@@ -501,6 +803,9 @@ static int ax88172_bind(struct usbnet *d
+ void *buf;
+ int i;
+ unsigned long gpio_bits = dev->driver_info->data;
++ struct asix_data *data = (struct asix_data *)&dev->data;
++
++ data->eeprom_len = AX88172_EEPROM_LEN;
+
+ usbnet_get_endpoints(dev,intf);
+
+@@ -519,12 +824,12 @@ static int ax88172_bind(struct usbnet *d
+ msleep(5);
+ }
+
+- if ((ret = asix_write_rx_ctl(dev,0x80)) < 0)
++ if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0)
+ goto out2;
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
++ if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
+ 0, 0, 6, buf)) < 0) {
+ dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
+ goto out2;
+@@ -537,14 +842,14 @@ static int ax88172_bind(struct usbnet *d
+ dev->mii.mdio_write = asix_mdio_write;
+ dev->mii.phy_id_mask = 0x3f;
+ dev->mii.reg_num_mask = 0x1f;
+- dev->mii.phy_id = asix_get_phyid(dev);
++ dev->mii.phy_id = asix_get_phy_addr(dev);
+ dev->net->do_ioctl = asix_ioctl;
+
+- dev->net->set_multicast_list = asix_set_multicast;
++ dev->net->set_multicast_list = ax88172_set_multicast;
+ dev->net->ethtool_ops = &ax88172_ethtool_ops;
+
+- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(&dev->mii);
+
+@@ -557,21 +862,49 @@ out1:
+
+ static struct ethtool_ops ax88772_ethtool_ops = {
+ .get_drvinfo = asix_get_drvinfo,
+- .get_link = ethtool_op_get_link,
++ .get_link = asix_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = asix_get_wol,
+ .set_wol = asix_set_wol,
+ .get_eeprom_len = asix_get_eeprom_len,
+ .get_eeprom = asix_get_eeprom,
+- .get_settings = asix_get_settings,
+- .set_settings = asix_set_settings,
++ .get_settings = usbnet_get_settings,
++ .set_settings = usbnet_set_settings,
++ .nway_reset = usbnet_nway_reset,
+ };
+
++static int ax88772_link_reset(struct usbnet *dev)
++{
++ u16 mode;
++ struct ethtool_cmd ecmd;
++
++ mii_check_media(&dev->mii, 1, 1);
++ mii_ethtool_gset(&dev->mii, &ecmd);
++ mode = AX88772_MEDIUM_DEFAULT;
++
++ if (ecmd.speed != SPEED_100)
++ mode &= ~AX_MEDIUM_PS;
++
++ if (ecmd.duplex != DUPLEX_FULL)
++ mode &= ~AX_MEDIUM_FD;
++
++ devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
++
++ asix_write_medium_mode(dev, mode);
++
++ return 0;
++}
++
+ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+ {
+ int ret;
+ void *buf;
++ u16 rx_ctl;
++ struct asix_data *data = (struct asix_data *)&dev->data;
++ u32 phyid;
++
++ data->eeprom_len = AX88772_EEPROM_LEN;
+
+ usbnet_get_endpoints(dev,intf);
+
+@@ -582,13 +915,12 @@ static int ax88772_bind(struct usbnet *d
+ goto out1;
+ }
+
+- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+- 0x00B0, 0, 0, buf)) < 0)
++ if ((ret = asix_write_gpio(dev,
++ AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)
+ goto out2;
+
+- msleep(5);
+ if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+- 0x0001, 0, 0, buf)) < 0) {
++ 0x0000, 0, 0, buf)) < 0) {
+ dbg("Select PHY #1 failed: %d", ret);
+ goto out2;
+ }
+@@ -605,36 +937,34 @@ static int ax88772_bind(struct usbnet *d
+ goto out2;
+
+ msleep(150);
+- if ((ret = asix_write_rx_ctl(dev, 0x00)) < 0)
++ rx_ctl = asix_read_rx_ctl(dev);
++ dbg("RX_CTL is 0x%04x after software reset", rx_ctl);
++ if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0)
+ goto out2;
+
++ rx_ctl = asix_read_rx_ctl(dev);
++ dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
++
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+- if ((ret = asix_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
++ if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ 0, 0, ETH_ALEN, buf)) < 0) {
+ dbg("Failed to read MAC address: %d", ret);
+ goto out2;
+ }
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+- if ((ret = asix_set_sw_mii(dev)) < 0)
+- goto out2;
+-
+- if (((ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG,
+- 0x0010, 2, 2, buf)) < 0)
+- || (*((u16 *)buf) != 0x003b)) {
+- dbg("Read PHY register 2 must be 0x3b00: %d", ret);
+- goto out2;
+- }
+-
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = asix_mdio_read;
+ dev->mii.mdio_write = asix_mdio_write;
+- dev->mii.phy_id_mask = 0xff;
+- dev->mii.reg_num_mask = 0xff;
++ dev->mii.phy_id_mask = 0x1f;
++ dev->mii.reg_num_mask = 0x1f;
+ dev->net->do_ioctl = asix_ioctl;
+- dev->mii.phy_id = asix_get_phyid(dev);
++ dev->mii.phy_id = asix_get_phy_addr(dev);
++
++ phyid = asix_get_phyid(dev);
++ dbg("PHYID=0x%08x", phyid);
+
+ if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0)
+ goto out2;
+@@ -649,16 +979,13 @@ static int ax88772_bind(struct usbnet *d
+ dev->net->set_multicast_list = asix_set_multicast;
+ dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA);
+ mii_nway_restart(&dev->mii);
+
+- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+- AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) {
+- dbg("Write medium mode register: %d", ret);
++ if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0)
+ goto out2;
+- }
+
+ if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
+ AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
+@@ -666,13 +993,17 @@ static int ax88772_bind(struct usbnet *d
+ dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
+ goto out2;
+ }
+- if ((ret = asix_set_hw_mii(dev)) < 0)
+- goto out2;
+
+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+- if ((ret = asix_write_rx_ctl(dev, 0x0088)) < 0)
++ if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
+ goto out2;
+
++ rx_ctl = asix_read_rx_ctl(dev);
++ dbg("RX_CTL is 0x%04x after all initializations", rx_ctl);
++
++ rx_ctl = asix_read_medium_status(dev);
++ dbg("Medium Status is 0x%04x after all initializations", rx_ctl);
++
+ kfree(buf);
+
+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+@@ -690,120 +1021,285 @@ out1:
+ return ret;
+ }
+
+-static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
++static struct ethtool_ops ax88178_ethtool_ops = {
++ .get_drvinfo = asix_get_drvinfo,
++ .get_link = asix_get_link,
++ .get_msglevel = usbnet_get_msglevel,
++ .set_msglevel = usbnet_set_msglevel,
++ .get_wol = asix_get_wol,
++ .set_wol = asix_set_wol,
++ .get_eeprom_len = asix_get_eeprom_len,
++ .get_eeprom = asix_get_eeprom,
++ .get_settings = usbnet_get_settings,
++ .set_settings = usbnet_set_settings,
++ .nway_reset = usbnet_nway_reset,
++};
++
++static int marvell_phy_init(struct usbnet *dev)
+ {
+- u8 *head;
+- u32 header;
+- char *packet;
+- struct sk_buff *ax_skb;
+- u16 size;
++ struct asix_data *data = (struct asix_data *)&dev->data;
++ u16 reg;
+
+- head = (u8 *) skb->data;
+- memcpy(&header, head, sizeof(header));
+- le32_to_cpus(&header);
+- packet = head + sizeof(header);
++ devdbg(dev,"marvell_phy_init()");
+
+- skb_pull(skb, 4);
++ reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS);
++ devdbg(dev,"MII_MARVELL_STATUS = 0x%04x", reg);
+
+- while (skb->len > 0) {
+- if ((short)(header & 0x0000ffff) !=
+- ~((short)((header & 0xffff0000) >> 16))) {
+- devdbg(dev,"header length data is error");
+- }
+- /* get the packet length */
+- size = (u16) (header & 0x0000ffff);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL,
++ MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
+
+- if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+- return 2;
+- if (size > ETH_FRAME_LEN) {
+- devdbg(dev,"invalid rx length %d", size);
+- return 0;
+- }
+- ax_skb = skb_clone(skb, GFP_ATOMIC);
+- if (ax_skb) {
+- ax_skb->len = size;
+- ax_skb->data = packet;
+- ax_skb->tail = packet + size;
+- usbnet_skb_return(dev, ax_skb);
+- } else {
+- return 0;
+- }
++ if (data->ledmode) {
++ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
++ MII_MARVELL_LED_CTRL);
++ devdbg(dev,"MII_MARVELL_LED_CTRL (1) = 0x%04x", reg);
+
+- skb_pull(skb, (size + 1) & 0xfffe);
++ reg &= 0xf8ff;
++ reg |= (1 + 0x0100);
++ asix_mdio_write(dev->net, dev->mii.phy_id,
++ MII_MARVELL_LED_CTRL, reg);
+
+- if (skb->len == 0)
+- break;
++ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
++ MII_MARVELL_LED_CTRL);
++ devdbg(dev,"MII_MARVELL_LED_CTRL (2) = 0x%04x", reg);
++ reg &= 0xfc0f;
++ }
+
+- head = (u8 *) skb->data;
+- memcpy(&header, head, sizeof(header));
+- le32_to_cpus(&header);
+- packet = head + sizeof(header);
+- skb_pull(skb, 4);
++ return 0;
++}
++
++static int marvell_led_status(struct usbnet *dev, u16 speed)
++{
++ u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
++
++ devdbg(dev, "marvell_led_status() read 0x%04x", reg);
++
++ /* Clear out the center LED bits - 0x03F0 */
++ reg &= 0xfc0f;
++
++ switch (speed) {
++ case SPEED_1000:
++ reg |= 0x03e0;
++ break;
++ case SPEED_100:
++ reg |= 0x03b0;
++ break;
++ default:
++ reg |= 0x02f0;
+ }
+
+- if (skb->len < 0) {
+- devdbg(dev,"invalid rx length %d", skb->len);
+- return 0;
++ devdbg(dev, "marvell_led_status() writing 0x%04x", reg);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg);
++
++ return 0;
++}
++
++static int ax88178_link_reset(struct usbnet *dev)
++{
++ u16 mode;
++ struct ethtool_cmd ecmd;
++ struct asix_data *data = (struct asix_data *)&dev->data;
++
++ devdbg(dev,"ax88178_link_reset()");
++
++ mii_check_media(&dev->mii, 1, 1);
++ mii_ethtool_gset(&dev->mii, &ecmd);
++ mode = AX88178_MEDIUM_DEFAULT;
++
++ if (ecmd.speed == SPEED_1000)
++ mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK;
++ else if (ecmd.speed == SPEED_100)
++ mode |= AX_MEDIUM_PS;
++ else
++ mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
++
++ if (ecmd.duplex == DUPLEX_FULL)
++ mode |= AX_MEDIUM_FD;
++ else
++ mode &= ~AX_MEDIUM_FD;
++
++ devdbg(dev, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
++
++ asix_write_medium_mode(dev, mode);
++
++ if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
++ marvell_led_status(dev, ecmd.speed);
++
++ return 0;
++}
++
++static void ax88178_set_mfb(struct usbnet *dev)
++{
++ u16 mfb = AX_RX_CTL_MFB_16384;
++ u16 rxctl;
++ u16 medium;
++ int old_rx_urb_size = dev->rx_urb_size;
++
++ if (dev->hard_mtu < 2048) {
++ dev->rx_urb_size = 2048;
++ mfb = AX_RX_CTL_MFB_2048;
++ } else if (dev->hard_mtu < 4096) {
++ dev->rx_urb_size = 4096;
++ mfb = AX_RX_CTL_MFB_4096;
++ } else if (dev->hard_mtu < 8192) {
++ dev->rx_urb_size = 8192;
++ mfb = AX_RX_CTL_MFB_8192;
++ } else if (dev->hard_mtu < 16384) {
++ dev->rx_urb_size = 16384;
++ mfb = AX_RX_CTL_MFB_16384;
+ }
+- return 1;
++
++ rxctl = asix_read_rx_ctl(dev);
++ asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb);
++
++ medium = asix_read_medium_status(dev);
++ if (dev->net->mtu > 1500)
++ medium |= AX_MEDIUM_JFE;
++ else
++ medium &= ~AX_MEDIUM_JFE;
++ asix_write_medium_mode(dev, medium);
++
++ if (dev->rx_urb_size > old_rx_urb_size)
++ usbnet_unlink_rx_urbs(dev);
+ }
+
+-static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+- gfp_t flags)
++static int ax88178_change_mtu(struct net_device *net, int new_mtu)
+ {
+- int padlen;
+- int headroom = skb_headroom(skb);
+- int tailroom = skb_tailroom(skb);
+- u32 packet_len;
+- u32 padbytes = 0xffff0000;
++ struct usbnet *dev = netdev_priv(net);
++ int ll_mtu = new_mtu + net->hard_header_len + 4;
+
+- padlen = ((skb->len + 4) % 512) ? 0 : 4;
++ devdbg(dev, "ax88178_change_mtu() new_mtu=%d", new_mtu);
+
+- if ((!skb_cloned(skb))
+- && ((headroom + tailroom) >= (4 + padlen))) {
+- if ((headroom < 4) || (tailroom < padlen)) {
+- skb->data = memmove(skb->head + 4, skb->data, skb->len);
+- skb->tail = skb->data + skb->len;
+- }
++ if (new_mtu <= 0 || ll_mtu > 16384)
++ return -EINVAL;
++
++ if ((ll_mtu % dev->maxpacket) == 0)
++ return -EDOM;
++
++ net->mtu = new_mtu;
++ dev->hard_mtu = net->mtu + net->hard_header_len;
++ ax88178_set_mfb(dev);
++
++ return 0;
++}
++
++static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
++{
++ struct asix_data *data = (struct asix_data *)&dev->data;
++ int ret;
++ void *buf;
++ u16 eeprom;
++ int gpio0 = 0;
++ u32 phyid;
++
++ usbnet_get_endpoints(dev,intf);
++
++ buf = kmalloc(6, GFP_KERNEL);
++ if(!buf) {
++ dbg ("Cannot allocate memory for buffer");
++ ret = -ENOMEM;
++ goto out1;
++ }
++
++ eeprom = 0;
++ asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &eeprom);
++ dbg("GPIO Status: 0x%04x", eeprom);
++
++ asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
++ asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
++ asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
++
++ dbg("EEPROM index 0x17 is 0x%04x", eeprom);
++
++ if (eeprom == 0xffff) {
++ data->phymode = PHY_MODE_MARVELL;
++ data->ledmode = 0;
++ gpio0 = 1;
+ } else {
+- struct sk_buff *skb2;
+- skb2 = skb_copy_expand(skb, 4, padlen, flags);
+- dev_kfree_skb_any(skb);
+- skb = skb2;
+- if (!skb)
+- return NULL;
++ data->phymode = eeprom & 7;
++ data->ledmode = eeprom >> 8;
++ gpio0 = (eeprom & 0x80) ? 0 : 1;
+ }
++ dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
+
+- skb_push(skb, 4);
+- packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+- memcpy(skb->data, &packet_len, sizeof(packet_len));
++ asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
++ if ((eeprom >> 8) != 1) {
++ asix_write_gpio(dev, 0x003c, 30);
++ asix_write_gpio(dev, 0x001c, 300);
++ asix_write_gpio(dev, 0x003c, 30);
++ } else {
++ dbg("gpio phymode == 1 path");
++ asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
++ asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
++ }
+
+- if ((skb->len % 512) == 0) {
+- memcpy( skb->tail, &padbytes, sizeof(padbytes));
+- skb_put(skb, sizeof(padbytes));
++ asix_sw_reset(dev, 0);
++ msleep(150);
++
++ asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
++ msleep(150);
++
++ asix_write_rx_ctl(dev, 0);
++
++ /* Get the MAC address */
++ memset(buf, 0, ETH_ALEN);
++ if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
++ 0, 0, ETH_ALEN, buf)) < 0) {
++ dbg("Failed to read MAC address: %d", ret);
++ goto out2;
+ }
+- return skb;
+-}
++ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+-static int ax88772_link_reset(struct usbnet *dev)
+-{
+- u16 lpa;
+- u16 adv;
+- u16 res;
+- u16 mode;
++ /* Initialize MII structure */
++ dev->mii.dev = dev->net;
++ dev->mii.mdio_read = asix_mdio_read;
++ dev->mii.mdio_write = asix_mdio_write;
++ dev->mii.phy_id_mask = 0x1f;
++ dev->mii.reg_num_mask = 0xff;
++ dev->mii.supports_gmii = 1;
++ dev->net->do_ioctl = asix_ioctl;
++ dev->mii.phy_id = asix_get_phy_addr(dev);
++ dev->net->set_multicast_list = asix_set_multicast;
++ dev->net->ethtool_ops = &ax88178_ethtool_ops;
++ dev->net->change_mtu = &ax88178_change_mtu;
+
+- mode = AX88772_MEDIUM_DEFAULT;
+- lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+- adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+- res = mii_nway_result(lpa|adv);
++ phyid = asix_get_phyid(dev);
++ dbg("PHYID=0x%08x", phyid);
++
++ if (data->phymode == PHY_MODE_MARVELL) {
++ marvell_phy_init(dev);
++ msleep(60);
++ }
+
+- if ((res & LPA_DUPLEX) == 0)
+- mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
+- if ((res & LPA_100) == 0)
+- mode &= ~AX88772_MEDIUM_100MB;
+- asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
++ BMCR_RESET | BMCR_ANENABLE);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
++ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
++ asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
++ ADVERTISE_1000FULL);
++
++ mii_nway_restart(&dev->mii);
++
++ if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0)
++ goto out2;
++
++ if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
++ goto out2;
++
++ kfree(buf);
++
++ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
++ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
++ /* hard_mtu is still the default - the device does not support
++ jumbo eth frames */
++ dev->rx_urb_size = 2048;
++ }
+
+ return 0;
++
++out2:
++ kfree(buf);
++out1:
++ return ret;
+ }
+
+ static const struct driver_info ax8817x_info = {
+@@ -853,8 +1349,19 @@ static const struct driver_info ax88772_
+ .link_reset = ax88772_link_reset,
+ .reset = ax88772_link_reset,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+- .rx_fixup = ax88772_rx_fixup,
+- .tx_fixup = ax88772_tx_fixup,
++ .rx_fixup = asix_rx_fixup,
++ .tx_fixup = asix_tx_fixup,
++};
++
++static const struct driver_info ax88178_info = {
++ .description = "ASIX AX88178 USB 2.0 Ethernet",
++ .bind = ax88178_bind,
++ .status = asix_status,
++ .link_reset = ax88178_link_reset,
++ .reset = ax88178_link_reset,
++ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
++ .rx_fixup = asix_rx_fixup,
++ .tx_fixup = asix_tx_fixup,
+ };
+
+ static const struct usb_device_id products [] = {
+@@ -913,7 +1420,7 @@ static const struct usb_device_id produc
+ }, {
+ // ASIX AX88178 10/100/1000
+ USB_DEVICE (0x0b95, 0x1780),
+- .driver_info = (unsigned long) &ax88772_info,
++ .driver_info = (unsigned long) &ax88178_info,
+ }, {
+ // Linksys USB200M Rev 2
+ USB_DEVICE (0x13b1, 0x0018),
+@@ -922,6 +1429,18 @@ static const struct usb_device_id produc
+ // 0Q0 cable ethernet
+ USB_DEVICE (0x1557, 0x7720),
+ .driver_info = (unsigned long) &ax88772_info,
++}, {
++ // DLink DUB-E100 H/W Ver B1
++ USB_DEVICE (0x07d1, 0x3c05),
++ .driver_info = (unsigned long) &ax88772_info,
++}, {
++ // DLink DUB-E100 H/W Ver B1 Alternate
++ USB_DEVICE (0x2001, 0x3c05),
++ .driver_info = (unsigned long) &ax88772_info,
++}, {
++ // Linksys USB1000
++ USB_DEVICE (0x1737, 0x0039),
++ .driver_info = (unsigned long) &ax88178_info,
+ },
+ { }, // END
+ };
+diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
+index be5f5e1..f740325 100644
+--- a/drivers/usb/net/catc.c
++++ b/drivers/usb/net/catc.c
+@@ -223,7 +223,7 @@ struct catc {
+ * Receive routines.
+ */
+
+-static void catc_rx_done(struct urb *urb, struct pt_regs *regs)
++static void catc_rx_done(struct urb *urb)
+ {
+ struct catc *catc = urb->context;
+ u8 *pkt_start = urb->transfer_buffer;
+@@ -289,7 +289,7 @@ static void catc_rx_done(struct urb *urb
+ }
+ }
+
+-static void catc_irq_done(struct urb *urb, struct pt_regs *regs)
++static void catc_irq_done(struct urb *urb)
+ {
+ struct catc *catc = urb->context;
+ u8 *data = urb->transfer_buffer;
+@@ -376,7 +376,7 @@ static void catc_tx_run(struct catc *cat
+ catc->netdev->trans_start = jiffies;
+ }
+
+-static void catc_tx_done(struct urb *urb, struct pt_regs *regs)
++static void catc_tx_done(struct urb *urb)
+ {
+ struct catc *catc = urb->context;
+ unsigned long flags;
+@@ -486,7 +486,7 @@ static void catc_ctrl_run(struct catc *c
+ err("submit(ctrl_urb) status %d", status);
+ }
+
+-static void catc_ctrl_done(struct urb *urb, struct pt_regs *regs)
++static void catc_ctrl_done(struct urb *urb)
+ {
+ struct catc *catc = urb->context;
+ struct ctrl_queue *q;
+diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
+index 82ce035..f6971b8 100644
+--- a/drivers/usb/net/cdc_ether.c
++++ b/drivers/usb/net/cdc_ether.c
+@@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = {
+
+ static int __init cdc_init(void)
+ {
+- BUG_ON((sizeof(((struct usbnet *)0)->data)
++ BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
+ < sizeof(struct cdc_state)));
+
+ return usb_register(&cdc_driver);
+diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
+index 3155f25..a3242be 100644
+--- a/drivers/usb/net/gl620a.c
++++ b/drivers/usb/net/gl620a.c
+@@ -106,7 +106,7 @@ static inline int gl_control_write(struc
+ return retval;
+ }
+
+-static void gl_interrupt_complete(struct urb *urb, struct pt_regs *regs)
++static void gl_interrupt_complete(struct urb *urb)
+ {
+ int status = urb->status;
+
+diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
+index def3bb8..7c906a4 100644
+--- a/drivers/usb/net/kaweth.c
++++ b/drivers/usb/net/kaweth.c
+@@ -65,16 +65,6 @@
+
+ #undef DEBUG
+
+-#ifdef DEBUG
+-#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg)
+-#else
+-#define kaweth_dbg(format, arg...) do {} while (0)
+-#endif
+-#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)
+-#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
+-#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg)
+-
+-
+ #include "kawethfw.h"
+
+ #define KAWETH_MTU 1514
+@@ -86,6 +76,9 @@
+
+ #define KAWETH_STATUS_BROKEN 0x0000001
+ #define KAWETH_STATUS_CLOSING 0x0000002
++#define KAWETH_STATUS_SUSPENDING 0x0000004
++
++#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
+
+ #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
+ #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
+@@ -112,6 +105,8 @@
+ #define STATE_MASK 0x40
+ #define STATE_SHIFT 5
+
++#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
++
+
+ MODULE_AUTHOR("Michael Zappe <zapman at interlan.net>, Stephane Alnet <stephane at u-picardie.fr>, Brad Hards <bhards at bigpond.net.au> and Oliver Neukum <oliver at neukum.org>");
+ MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
+@@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(s
+ unsigned int pipe,
+ struct usb_ctrlrequest *cmd, void *data,
+ int len, int timeout);
++static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
++static int kaweth_resume(struct usb_interface *intf);
+
+ /****************************************************************
+ * usb_device_id
+@@ -165,6 +162,7 @@ static struct usb_device_id usb_klsi_tab
+ { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
+ { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
+ { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
++ { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */
+ { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
+ {} /* Null terminator */
+ };
+@@ -178,6 +176,8 @@ static struct usb_driver kaweth_driver =
+ .name = driver_name,
+ .probe = kaweth_probe,
+ .disconnect = kaweth_disconnect,
++ .suspend = kaweth_suspend,
++ .resume = kaweth_resume,
+ .id_table = usb_klsi_table,
+ };
+
+@@ -221,6 +221,7 @@ struct kaweth_device
+ int suspend_lowmem_rx;
+ int suspend_lowmem_ctrl;
+ int linkstate;
++ int opened;
+ struct work_struct lowmem_work;
+
+ struct usb_device *dev;
+@@ -264,17 +265,17 @@ static int kaweth_control(struct kaweth_
+ {
+ struct usb_ctrlrequest *dr;
+
+- kaweth_dbg("kaweth_control()");
++ dbg("kaweth_control()");
+
+ if(in_interrupt()) {
+- kaweth_dbg("in_interrupt()");
++ dbg("in_interrupt()");
+ return -EBUSY;
+ }
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+
+ if (!dr) {
+- kaweth_dbg("kmalloc() failed");
++ dbg("kmalloc() failed");
+ return -ENOMEM;
+ }
+
+@@ -299,7 +300,7 @@ static int kaweth_read_configuration(str
+ {
+ int retval;
+
+- kaweth_dbg("Reading kaweth configuration");
++ dbg("Reading kaweth configuration");
+
+ retval = kaweth_control(kaweth,
+ usb_rcvctrlpipe(kaweth->dev, 0),
+@@ -321,7 +322,7 @@ static int kaweth_set_urb_size(struct ka
+ {
+ int retval;
+
+- kaweth_dbg("Setting URB size to %d", (unsigned)urb_size);
++ dbg("Setting URB size to %d", (unsigned)urb_size);
+
+ retval = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+@@ -343,7 +344,7 @@ static int kaweth_set_sofs_wait(struct k
+ {
+ int retval;
+
+- kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
++ dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
+
+ retval = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+@@ -366,7 +367,7 @@ static int kaweth_set_receive_filter(str
+ {
+ int retval;
+
+- kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter);
++ dbg("Set receive filter to %d", (unsigned)receive_filter);
+
+ retval = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+@@ -391,7 +392,7 @@ static int kaweth_download_firmware(stru
+ __u8 type)
+ {
+ if(data_len > KAWETH_FIRMWARE_BUF_SIZE) {
+- kaweth_err("Firmware too big: %d", data_len);
++ err("Firmware too big: %d", data_len);
+ return -ENOSPC;
+ }
+
+@@ -402,13 +403,13 @@ static int kaweth_download_firmware(stru
+ kaweth->firmware_buf[4] = type;
+ kaweth->firmware_buf[5] = interrupt;
+
+- kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
++ dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
+ kaweth->firmware_buf[2]);
+
+- kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
++ dbg("Downloading firmware at %p to kaweth device at %p",
+ data,
+ kaweth);
+- kaweth_dbg("Firmware length: %d", data_len);
++ dbg("Firmware length: %d", data_len);
+
+ return kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+@@ -436,7 +437,7 @@ static int kaweth_trigger_firmware(struc
+ kaweth->firmware_buf[6] = 0x00;
+ kaweth->firmware_buf[7] = 0x00;
+
+- kaweth_dbg("Triggering firmware");
++ dbg("Triggering firmware");
+
+ return kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+@@ -456,7 +457,7 @@ static int kaweth_reset(struct kaweth_de
+ {
+ int result;
+
+- kaweth_dbg("kaweth_reset(%p)", kaweth);
++ dbg("kaweth_reset(%p)", kaweth);
+ result = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+@@ -469,12 +470,12 @@ static int kaweth_reset(struct kaweth_de
+
+ mdelay(10);
+
+- kaweth_dbg("kaweth_reset() returns %d.",result);
++ dbg("kaweth_reset() returns %d.",result);
+
+ return result;
+ }
+
+-static void kaweth_usb_receive(struct urb *, struct pt_regs *regs);
++static void kaweth_usb_receive(struct urb *);
+ static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t);
+
+ /****************************************************************
+@@ -499,7 +500,7 @@ static void kaweth_resubmit_int_urb(stru
+ kaweth->dev->devpath, status);
+ }
+
+-static void int_callback(struct urb *u, struct pt_regs *regs)
++static void int_callback(struct urb *u)
+ {
+ struct kaweth_device *kaweth = u->context;
+ int act_state;
+@@ -533,7 +534,7 @@ static void kaweth_resubmit_tl(void *d)
+ {
+ struct kaweth_device *kaweth = (struct kaweth_device *)d;
+
+- if (kaweth->status | KAWETH_STATUS_CLOSING)
++ if (IS_BLOCKED(kaweth->status))
+ return;
+
+ if (kaweth->suspend_lowmem_rx)
+@@ -567,7 +568,7 @@ static int kaweth_resubmit_rx_urb(struct
+ kaweth->suspend_lowmem_rx = 1;
+ schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
+ }
+- kaweth_err("resubmitting rx_urb %d failed", result);
++ err("resubmitting rx_urb %d failed", result);
+ } else {
+ kaweth->suspend_lowmem_rx = 0;
+ }
+@@ -580,7 +581,7 @@ static void kaweth_async_set_rx_mode(str
+ /****************************************************************
+ * kaweth_usb_receive
+ ****************************************************************/
+-static void kaweth_usb_receive(struct urb *urb, struct pt_regs *regs)
++static void kaweth_usb_receive(struct urb *urb)
+ {
+ struct kaweth_device *kaweth = urb->context;
+ struct net_device *net = kaweth->net;
+@@ -600,11 +601,15 @@ static void kaweth_usb_receive(struct ur
+ return;
+ }
+
+- if (kaweth->status & KAWETH_STATUS_CLOSING)
++ spin_lock(&kaweth->device_lock);
++ if (IS_BLOCKED(kaweth->status)) {
++ spin_unlock(&kaweth->device_lock);
+ return;
++ }
++ spin_unlock(&kaweth->device_lock);
+
+ if(urb->status && urb->status != -EREMOTEIO && count != 1) {
+- kaweth_err("%s RX status: %d count: %d packet_len: %d",
++ err("%s RX status: %d count: %d packet_len: %d",
+ net->name,
+ urb->status,
+ count,
+@@ -615,9 +620,9 @@ static void kaweth_usb_receive(struct ur
+
+ if(kaweth->net && (count > 2)) {
+ if(pkt_len > (count - 2)) {
+- kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
+- kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
+- kaweth_err("Count 2: %x", count2);
++ err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
++ err("Packet len & 2047: %x", pkt_len & 2047);
++ err("Count 2: %x", count2);
+ kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
+ return;
+ }
+@@ -654,7 +659,7 @@ static int kaweth_open(struct net_device
+ struct kaweth_device *kaweth = netdev_priv(net);
+ int res;
+
+- kaweth_dbg("Opening network device.");
++ dbg("Opening network device.");
+
+ res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
+ if (res)
+@@ -677,6 +682,7 @@ static int kaweth_open(struct net_device
+ usb_kill_urb(kaweth->rx_urb);
+ return -EIO;
+ }
++ kaweth->opened = 1;
+
+ netif_start_queue(net);
+
+@@ -687,14 +693,8 @@ static int kaweth_open(struct net_device
+ /****************************************************************
+ * kaweth_close
+ ****************************************************************/
+-static int kaweth_close(struct net_device *net)
++static void kaweth_kill_urbs(struct kaweth_device *kaweth)
+ {
+- struct kaweth_device *kaweth = netdev_priv(net);
+-
+- netif_stop_queue(net);
+-
+- kaweth->status |= KAWETH_STATUS_CLOSING;
+-
+ usb_kill_urb(kaweth->irq_urb);
+ usb_kill_urb(kaweth->rx_urb);
+ usb_kill_urb(kaweth->tx_urb);
+@@ -705,6 +705,21 @@ static int kaweth_close(struct net_devic
+ we hit them again */
+ usb_kill_urb(kaweth->irq_urb);
+ usb_kill_urb(kaweth->rx_urb);
++}
++
++/****************************************************************
++ * kaweth_close
++ ****************************************************************/
++static int kaweth_close(struct net_device *net)
++{
++ struct kaweth_device *kaweth = netdev_priv(net);
++
++ netif_stop_queue(net);
++ kaweth->opened = 0;
++
++ kaweth->status |= KAWETH_STATUS_CLOSING;
++
++ kaweth_kill_urbs(kaweth);
+
+ kaweth->status &= ~KAWETH_STATUS_CLOSING;
+
+@@ -724,14 +739,14 @@ static struct ethtool_ops ops = {
+ /****************************************************************
+ * kaweth_usb_transmit_complete
+ ****************************************************************/
+-static void kaweth_usb_transmit_complete(struct urb *urb, struct pt_regs *regs)
++static void kaweth_usb_transmit_complete(struct urb *urb)
+ {
+ struct kaweth_device *kaweth = urb->context;
+ struct sk_buff *skb = kaweth->tx_skb;
+
+ if (unlikely(urb->status != 0))
+ if (urb->status != -ENOENT)
+- kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
++ dbg("%s: TX status %d.", kaweth->net->name, urb->status);
+
+ netif_wake_queue(kaweth->net);
+ dev_kfree_skb_irq(skb);
+@@ -751,6 +766,9 @@ static int kaweth_start_xmit(struct sk_b
+
+ kaweth_async_set_rx_mode(kaweth);
+ netif_stop_queue(net);
++ if (IS_BLOCKED(kaweth->status)) {
++ goto skip;
++ }
+
+ /* We now decide whether we can put our special header into the sk_buff */
+ if (skb_cloned(skb) || skb_headroom(skb) < 2) {
+@@ -782,7 +800,8 @@ static int kaweth_start_xmit(struct sk_b
+
+ if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
+ {
+- kaweth_warn("kaweth failed tx_urb %d", res);
++ warn("kaweth failed tx_urb %d", res);
++skip:
+ kaweth->stats.tx_errors++;
+
+ netif_start_queue(net);
+@@ -811,7 +830,7 @@ static void kaweth_set_rx_mode(struct ne
+ KAWETH_PACKET_FILTER_BROADCAST |
+ KAWETH_PACKET_FILTER_MULTICAST;
+
+- kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap);
++ dbg("Setting Rx mode to %d", packet_filter_bitmap);
+
+ netif_stop_queue(net);
+
+@@ -849,10 +868,10 @@ static void kaweth_async_set_rx_mode(str
+ KAWETH_CONTROL_TIMEOUT);
+
+ if(result < 0) {
+- kaweth_err("Failed to set Rx mode: %d", result);
++ err("Failed to set Rx mode: %d", result);
+ }
+ else {
+- kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap);
++ dbg("Set Rx mode to %d", packet_filter_bitmap);
+ }
+ }
+ }
+@@ -873,7 +892,7 @@ static void kaweth_tx_timeout(struct net
+ {
+ struct kaweth_device *kaweth = netdev_priv(net);
+
+- kaweth_warn("%s: Tx timed out. Resetting.", net->name);
++ warn("%s: Tx timed out. Resetting.", net->name);
+ kaweth->stats.tx_errors++;
+ net->trans_start = jiffies;
+
+@@ -881,6 +900,42 @@ static void kaweth_tx_timeout(struct net
+ }
+
+ /****************************************************************
++ * kaweth_suspend
++ ****************************************************************/
++static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
++{
++ struct kaweth_device *kaweth = usb_get_intfdata(intf);
++ unsigned long flags;
++
++ spin_lock_irqsave(&kaweth->device_lock, flags);
++ kaweth->status |= KAWETH_STATUS_SUSPENDING;
++ spin_unlock_irqrestore(&kaweth->device_lock, flags);
++
++ kaweth_kill_urbs(kaweth);
++ return 0;
++}
++
++/****************************************************************
++ * kaweth_resume
++ ****************************************************************/
++static int kaweth_resume(struct usb_interface *intf)
++{
++ struct kaweth_device *kaweth = usb_get_intfdata(intf);
++ unsigned long flags;
++
++ spin_lock_irqsave(&kaweth->device_lock, flags);
++ kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
++ spin_unlock_irqrestore(&kaweth->device_lock, flags);
++
++ if (!kaweth->opened)
++ return 0;
++ kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
++ kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
++
++ return 0;
++}
++
++/****************************************************************
+ * kaweth_probe
+ ****************************************************************/
+ static int kaweth_probe(
+@@ -894,15 +949,15 @@ static int kaweth_probe(
+ const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ int result = 0;
+
+- kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
++ dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
+ dev->devnum,
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct),
+ le16_to_cpu(dev->descriptor.bcdDevice));
+
+- kaweth_dbg("Device at %p", dev);
++ dbg("Device at %p", dev);
+
+- kaweth_dbg("Descriptor length: %x type: %x",
++ dbg("Descriptor length: %x type: %x",
+ (int)dev->descriptor.bLength,
+ (int)dev->descriptor.bDescriptorType);
+
+@@ -917,7 +972,7 @@ static int kaweth_probe(
+ spin_lock_init(&kaweth->device_lock);
+ init_waitqueue_head(&kaweth->term_wait);
+
+- kaweth_dbg("Resetting.");
++ dbg("Resetting.");
+
+ kaweth_reset(kaweth);
+
+@@ -927,17 +982,17 @@ static int kaweth_probe(
+ */
+
+ if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) {
+- kaweth_info("Firmware present in device.");
++ info("Firmware present in device.");
+ } else {
+ /* Download the firmware */
+- kaweth_info("Downloading firmware...");
++ info("Downloading firmware...");
+ kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
+ if ((result = kaweth_download_firmware(kaweth,
+ kaweth_new_code,
+ len_kaweth_new_code,
+ 100,
+ 2)) < 0) {
+- kaweth_err("Error downloading firmware (%d)", result);
++ err("Error downloading firmware (%d)", result);
+ goto err_fw;
+ }
+
+@@ -946,7 +1001,7 @@ static int kaweth_probe(
+ len_kaweth_new_code_fix,
+ 100,
+ 3)) < 0) {
+- kaweth_err("Error downloading firmware fix (%d)", result);
++ err("Error downloading firmware fix (%d)", result);
+ goto err_fw;
+ }
+
+@@ -955,7 +1010,7 @@ static int kaweth_probe(
+ len_kaweth_trigger_code,
+ 126,
+ 2)) < 0) {
+- kaweth_err("Error downloading trigger code (%d)", result);
++ err("Error downloading trigger code (%d)", result);
+ goto err_fw;
+
+ }
+@@ -965,18 +1020,18 @@ static int kaweth_probe(
+ len_kaweth_trigger_code_fix,
+ 126,
+ 3)) < 0) {
+- kaweth_err("Error downloading trigger code fix (%d)", result);
++ err("Error downloading trigger code fix (%d)", result);
+ goto err_fw;
+ }
+
+
+ if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
+- kaweth_err("Error triggering firmware (%d)", result);
++ err("Error triggering firmware (%d)", result);
+ goto err_fw;
+ }
+
+ /* Device will now disappear for a moment... */
+- kaweth_info("Firmware loaded. I'll be back...");
++ info("Firmware loaded. I'll be back...");
+ err_fw:
+ free_page((unsigned long)kaweth->firmware_buf);
+ free_netdev(netdev);
+@@ -986,14 +1041,14 @@ err_fw:
+ result = kaweth_read_configuration(kaweth);
+
+ if(result < 0) {
+- kaweth_err("Error reading configuration (%d), no net device created", result);
++ err("Error reading configuration (%d), no net device created", result);
+ goto err_free_netdev;
+ }
+
+- kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
+- kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+- kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
+- kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
++ info("Statistics collection: %x", kaweth->configuration.statistics_mask);
++ info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
++ info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
++ info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ (int)kaweth->configuration.hw_addr[0],
+ (int)kaweth->configuration.hw_addr[1],
+ (int)kaweth->configuration.hw_addr[2],
+@@ -1004,17 +1059,17 @@ err_fw:
+ if(!memcmp(&kaweth->configuration.hw_addr,
+ &bcast_addr,
+ sizeof(bcast_addr))) {
+- kaweth_err("Firmware not functioning properly, no net device created");
++ err("Firmware not functioning properly, no net device created");
+ goto err_free_netdev;
+ }
+
+ if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
+- kaweth_dbg("Error setting URB size");
++ dbg("Error setting URB size");
+ goto err_free_netdev;
+ }
+
+ if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
+- kaweth_err("Error setting SOFS wait");
++ err("Error setting SOFS wait");
+ goto err_free_netdev;
+ }
+
+@@ -1024,11 +1079,11 @@ err_fw:
+ KAWETH_PACKET_FILTER_MULTICAST);
+
+ if(result < 0) {
+- kaweth_err("Error setting receive filter");
++ err("Error setting receive filter");
+ goto err_free_netdev;
+ }
+
+- kaweth_dbg("Initializing net device.");
++ dbg("Initializing net device.");
+
+ kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kaweth->tx_urb)
+@@ -1085,13 +1140,13 @@ err_fw:
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+ if (register_netdev(netdev) != 0) {
+- kaweth_err("Error registering netdev.");
++ err("Error registering netdev.");
+ goto err_intfdata;
+ }
+
+- kaweth_info("kaweth interface created at %s", kaweth->net->name);
++ info("kaweth interface created at %s", kaweth->net->name);
+
+- kaweth_dbg("Kaweth probe returning.");
++ dbg("Kaweth probe returning.");
+
+ return 0;
+
+@@ -1120,16 +1175,16 @@ static void kaweth_disconnect(struct usb
+ struct kaweth_device *kaweth = usb_get_intfdata(intf);
+ struct net_device *netdev;
+
+- kaweth_info("Unregistering");
++ info("Unregistering");
+
+ usb_set_intfdata(intf, NULL);
+ if (!kaweth) {
+- kaweth_warn("unregistering non-existant device");
++ warn("unregistering non-existant device");
+ return;
+ }
+ netdev = kaweth->net;
+
+- kaweth_dbg("Unregistering net device");
++ dbg("Unregistering net device");
+ unregister_netdev(netdev);
+
+ usb_free_urb(kaweth->rx_urb);
+@@ -1153,7 +1208,7 @@ struct usb_api_data {
+ /*-------------------------------------------------------------------*
+ * completion handler for compatibility wrappers (sync control/bulk) *
+ *-------------------------------------------------------------------*/
+-static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
++static void usb_api_blocking_completion(struct urb *urb)
+ {
+ struct usb_api_data *awd = (struct usb_api_data *)urb->context;
+
+@@ -1184,7 +1239,7 @@ static int usb_start_wait_urb(struct urb
+
+ if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
+ // timeout
+- kaweth_warn("usb_control/bulk_msg: timeout");
++ warn("usb_control/bulk_msg: timeout");
+ usb_kill_urb(urb); // remove urb safely
+ status = -ETIMEDOUT;
+ }
+@@ -1233,7 +1288,7 @@ static int kaweth_internal_control_msg(s
+ ****************************************************************/
+ static int __init kaweth_init(void)
+ {
+- kaweth_dbg("Driver loading");
++ dbg("Driver loading");
+ return usb_register(&kaweth_driver);
+ }
+
+diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c
+new file mode 100644
+index 0000000..6240b97
+--- /dev/null
++++ b/drivers/usb/net/mcs7830.c
+@@ -0,0 +1,534 @@
++/*
++ * MosChips MCS7830 based USB 2.0 Ethernet Devices
++ *
++ * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
++ *
++ * Copyright (C) 2006 Arnd Bergmann <arnd at arndb.de>
++ * Copyright (C) 2003-2005 David Hollis <dhollis at davehollis.com>
++ * Copyright (C) 2005 Phil Chang <pchang23 at sbcglobal.net>
++ * Copyright (c) 2002-2003 TiVo Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/crc32.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/init.h>
++#include <linux/mii.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/usb.h>
++
++#include "usbnet.h"
++
++/* requests */
++#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \
++ USB_RECIP_DEVICE)
++#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \
++ USB_RECIP_DEVICE)
++#define MCS7830_RD_BREQ 0x0E
++#define MCS7830_WR_BREQ 0x0D
++
++#define MCS7830_CTRL_TIMEOUT 1000
++#define MCS7830_MAX_MCAST 64
++
++#define MCS7830_VENDOR_ID 0x9710
++#define MCS7830_PRODUCT_ID 0x7830
++
++#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
++ ADVERTISE_100HALF | ADVERTISE_10FULL | \
++ ADVERTISE_10HALF | ADVERTISE_CSMA)
++
++/* HIF_REG_XX coressponding index value */
++enum {
++ HIF_REG_MULTICAST_HASH = 0x00,
++ HIF_REG_PACKET_GAP1 = 0x08,
++ HIF_REG_PACKET_GAP2 = 0x09,
++ HIF_REG_PHY_DATA = 0x0a,
++ HIF_REG_PHY_CMD1 = 0x0c,
++ HIF_REG_PHY_CMD1_READ = 0x40,
++ HIF_REG_PHY_CMD1_WRITE = 0x20,
++ HIF_REG_PHY_CMD1_PHYADDR = 0x01,
++ HIF_REG_PHY_CMD2 = 0x0d,
++ HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80,
++ HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40,
++ HIF_REG_CONFIG = 0x0e,
++ HIF_REG_CONFIG_CFG = 0x80,
++ HIF_REG_CONFIG_SPEED100 = 0x40,
++ HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
++ HIF_REG_CONFIG_RXENABLE = 0x10,
++ HIF_REG_CONFIG_TXENABLE = 0x08,
++ HIF_REG_CONFIG_SLEEPMODE = 0x04,
++ HIF_REG_CONFIG_ALLMULTICAST = 0x02,
++ HIF_REG_CONFIG_PROMISCIOUS = 0x01,
++ HIF_REG_ETHERNET_ADDR = 0x0f,
++ HIF_REG_22 = 0x15,
++ HIF_REG_PAUSE_THRESHOLD = 0x16,
++ HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0,
++};
++
++struct mcs7830_data {
++ u8 multi_filter[8];
++ u8 config;
++};
++
++static const char driver_name[] = "MOSCHIP usb-ethernet driver";
++
++static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
++{
++ struct usb_device *xdev = dev->udev;
++ int ret;
++
++ ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
++ MCS7830_RD_BMREQ, 0x0000, index, data,
++ size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
++ return ret;
++}
++
++static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
++{
++ struct usb_device *xdev = dev->udev;
++ int ret;
++
++ ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
++ MCS7830_WR_BMREQ, 0x0000, index, data,
++ size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
++ return ret;
++}
++
++static void mcs7830_async_cmd_callback(struct urb *urb)
++{
++ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
++
++ if (urb->status < 0)
++ printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d",
++ urb->status);
++
++ kfree(req);
++ usb_free_urb(urb);
++}
++
++static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
++{
++ struct usb_ctrlrequest *req;
++ int ret;
++ struct urb *urb;
++
++ urb = usb_alloc_urb(0, GFP_ATOMIC);
++ if (!urb) {
++ dev_dbg(&dev->udev->dev, "Error allocating URB "
++ "in write_cmd_async!");
++ return;
++ }
++
++ req = kmalloc(sizeof *req, GFP_ATOMIC);
++ if (!req) {
++ dev_err(&dev->udev->dev, "Failed to allocate memory for "
++ "control request");
++ goto out;
++ }
++ req->bRequestType = MCS7830_WR_BMREQ;
++ req->bRequest = MCS7830_WR_BREQ;
++ req->wValue = 0;
++ req->wIndex = cpu_to_le16(index);
++ req->wLength = cpu_to_le16(size);
++
++ usb_fill_control_urb(urb, dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ (void *)req, data, size,
++ mcs7830_async_cmd_callback, req);
++
++ ret = usb_submit_urb(urb, GFP_ATOMIC);
++ if (ret < 0) {
++ dev_err(&dev->udev->dev, "Error submitting the control "
++ "message: ret=%d", ret);
++ goto out;
++ }
++ return;
++out:
++ kfree(req);
++ usb_free_urb(urb);
++}
++
++static int mcs7830_get_address(struct usbnet *dev)
++{
++ int ret;
++ ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
++ dev->net->dev_addr);
++ if (ret < 0)
++ return ret;
++ return 0;
++}
++
++static int mcs7830_read_phy(struct usbnet *dev, u8 index)
++{
++ int ret;
++ int i;
++ __le16 val;
++
++ u8 cmd[2] = {
++ HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
++ HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
++ };
++
++ mutex_lock(&dev->phy_mutex);
++ /* write the MII command */
++ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
++ if (ret < 0)
++ goto out;
++
++ /* wait for the data to become valid, should be within < 1ms */
++ for (i = 0; i < 10; i++) {
++ ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
++ if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
++ break;
++ ret = -EIO;
++ msleep(1);
++ }
++ if (ret < 0)
++ goto out;
++
++ /* read actual register contents */
++ ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
++ if (ret < 0)
++ goto out;
++ ret = le16_to_cpu(val);
++ dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
++ index, val, i);
++out:
++ mutex_unlock(&dev->phy_mutex);
++ return ret;
++}
++
++static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
++{
++ int ret;
++ int i;
++ __le16 le_val;
++
++ u8 cmd[2] = {
++ HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
++ HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
++ };
++
++ mutex_lock(&dev->phy_mutex);
++
++ /* write the new register contents */
++ le_val = cpu_to_le16(val);
++ ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
++ if (ret < 0)
++ goto out;
++
++ /* write the MII command */
++ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
++ if (ret < 0)
++ goto out;
++
++ /* wait for the command to be accepted by the PHY */
++ for (i = 0; i < 10; i++) {
++ ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
++ if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
++ break;
++ ret = -EIO;
++ msleep(1);
++ }
++ if (ret < 0)
++ goto out;
++
++ ret = 0;
++ dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
++ index, val, i);
++out:
++ mutex_unlock(&dev->phy_mutex);
++ return ret;
++}
++
++/*
++ * This algorithm comes from the original mcs7830 version 1.4 driver,
++ * not sure if it is needed.
++ */
++static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
++{
++ int ret;
++ /* Enable all media types */
++ ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
++
++ /* First reset BMCR */
++ if (!ret)
++ ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
++ /* Enable Auto Neg */
++ if (!ret)
++ ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
++ /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
++ if (!ret)
++ ret = mcs7830_write_phy(dev, MII_BMCR,
++ BMCR_ANENABLE | BMCR_ANRESTART );
++ return ret < 0 ? : 0;
++}
++
++
++/*
++ * if we can read register 22, the chip revision is C or higher
++ */
++static int mcs7830_get_rev(struct usbnet *dev)
++{
++ u8 dummy[2];
++ int ret;
++ ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
++ if (ret > 0)
++ return 2; /* Rev C or later */
++ return 1; /* earlier revision */
++}
++
++/*
++ * On rev. C we need to set the pause threshold
++ */
++static void mcs7830_rev_C_fixup(struct usbnet *dev)
++{
++ u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
++ int retry;
++
++ for (retry = 0; retry < 2; retry++) {
++ if (mcs7830_get_rev(dev) == 2) {
++ dev_info(&dev->udev->dev, "applying rev.C fixup\n");
++ mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
++ 1, &pause_threshold);
++ }
++ msleep(1);
++ }
++}
++
++static int mcs7830_init_dev(struct usbnet *dev)
++{
++ int ret;
++ int retry;
++
++ /* Read MAC address from EEPROM */
++ ret = -EINVAL;
++ for (retry = 0; retry < 5 && ret; retry++)
++ ret = mcs7830_get_address(dev);
++ if (ret) {
++ dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
++ goto out;
++ }
++
++ /* Set up PHY */
++ ret = mcs7830_set_autoneg(dev, 0);
++ if (ret) {
++ dev_info(&dev->udev->dev, "Cannot set autoneg\n");
++ goto out;
++ }
++
++ mcs7830_rev_C_fixup(dev);
++ ret = 0;
++out:
++ return ret;
++}
++
++static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
++ int location)
++{
++ struct usbnet *dev = netdev->priv;
++ return mcs7830_read_phy(dev, location);
++}
++
++static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
++ int location, int val)
++{
++ struct usbnet *dev = netdev->priv;
++ mcs7830_write_phy(dev, location, val);
++}
++
++static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
++{
++ struct usbnet *dev = netdev_priv(net);
++ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
++}
++
++/* credits go to asix_set_multicast */
++static void mcs7830_set_multicast(struct net_device *net)
++{
++ struct usbnet *dev = netdev_priv(net);
++ struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
++
++ data->config = HIF_REG_CONFIG_TXENABLE;
++
++ /* this should not be needed, but it doesn't work otherwise */
++ data->config |= HIF_REG_CONFIG_ALLMULTICAST;
++
++ if (net->flags & IFF_PROMISC) {
++ data->config |= HIF_REG_CONFIG_PROMISCIOUS;
++ } else if (net->flags & IFF_ALLMULTI
++ || net->mc_count > MCS7830_MAX_MCAST) {
++ data->config |= HIF_REG_CONFIG_ALLMULTICAST;
++ } else if (net->mc_count == 0) {
++ /* just broadcast and directed */
++ } else {
++ /* We use the 20 byte dev->data
++ * for our 8 byte filter buffer
++ * to avoid allocating memory that
++ * is tricky to free later */
++ struct dev_mc_list *mc_list = net->mc_list;
++ u32 crc_bits;
++ int i;
++
++ memset(data->multi_filter, 0, sizeof data->multi_filter);
++
++ /* Build the multicast hash filter. */
++ for (i = 0; i < net->mc_count; i++) {
++ crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
++ data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
++ mc_list = mc_list->next;
++ }
++
++ mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
++ sizeof data->multi_filter,
++ data->multi_filter);
++ }
++
++ mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
++}
++
++static int mcs7830_get_regs_len(struct net_device *net)
++{
++ struct usbnet *dev = netdev_priv(net);
++
++ switch (mcs7830_get_rev(dev)) {
++ case 1:
++ return 21;
++ case 2:
++ return 32;
++ }
++ return 0;
++}
++
++static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
++{
++ usbnet_get_drvinfo(net, drvinfo);
++ drvinfo->regdump_len = mcs7830_get_regs_len(net);
++}
++
++static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
++{
++ struct usbnet *dev = netdev_priv(net);
++
++ regs->version = mcs7830_get_rev(dev);
++ mcs7830_get_reg(dev, 0, regs->len, data);
++}
++
++static struct ethtool_ops mcs7830_ethtool_ops = {
++ .get_drvinfo = mcs7830_get_drvinfo,
++ .get_regs_len = mcs7830_get_regs_len,
++ .get_regs = mcs7830_get_regs,
++
++ /* common usbnet calls */
++ .get_link = usbnet_get_link,
++ .get_msglevel = usbnet_get_msglevel,
++ .set_msglevel = usbnet_set_msglevel,
++ .get_settings = usbnet_get_settings,
++ .set_settings = usbnet_set_settings,
++ .nway_reset = usbnet_nway_reset,
++};
++
++static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
++{
++ struct net_device *net = dev->net;
++ int ret;
++
++ ret = mcs7830_init_dev(dev);
++ if (ret)
++ goto out;
++
++ net->do_ioctl = mcs7830_ioctl;
++ net->ethtool_ops = &mcs7830_ethtool_ops;
++ net->set_multicast_list = mcs7830_set_multicast;
++ mcs7830_set_multicast(net);
++
++ /* reserve space for the status byte on rx */
++ dev->rx_urb_size = ETH_FRAME_LEN + 1;
++
++ dev->mii.mdio_read = mcs7830_mdio_read;
++ dev->mii.mdio_write = mcs7830_mdio_write;
++ dev->mii.dev = net;
++ dev->mii.phy_id_mask = 0x3f;
++ dev->mii.reg_num_mask = 0x1f;
++ dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
++
++ ret = usbnet_get_endpoints(dev, udev);
++out:
++ return ret;
++}
++
++/* The chip always appends a status bytes that we need to strip */
++static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
++{
++ u8 status;
++
++ if (skb->len == 0) {
++ dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
++ return 0;
++ }
++
++ skb_trim(skb, skb->len - 1);
++ status = skb->data[skb->len];
++
++ if (status != 0x20)
++ dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
++
++ return skb->len > 0;
++}
++
++static const struct driver_info moschip_info = {
++ .description = "MOSCHIP 7830 usb-NET adapter",
++ .bind = mcs7830_bind,
++ .rx_fixup = mcs7830_rx_fixup,
++ .flags = FLAG_ETHER,
++ .in = 1,
++ .out = 2,
++};
++
++static const struct usb_device_id products[] = {
++ {
++ USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
++ .driver_info = (unsigned long) &moschip_info,
++ },
++ {},
++};
++MODULE_DEVICE_TABLE(usb, products);
++
++static struct usb_driver mcs7830_driver = {
++ .name = driver_name,
++ .id_table = products,
++ .probe = usbnet_probe,
++ .disconnect = usbnet_disconnect,
++ .suspend = usbnet_suspend,
++ .resume = usbnet_resume,
++};
++
++static int __init mcs7830_init(void)
++{
++ return usb_register(&mcs7830_driver);
++}
++module_init(mcs7830_init);
++
++static void __exit mcs7830_exit(void)
++{
++ usb_deregister(&mcs7830_driver);
++}
++module_exit(mcs7830_exit);
++
++MODULE_DESCRIPTION("USB to network adapter MCS7830)");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c
+index a9b6eea..ce00de8 100644
+--- a/drivers/usb/net/net1080.c
++++ b/drivers/usb/net/net1080.c
+@@ -368,7 +368,7 @@ static int net1080_check_connect(struct
+ return 0;
+ }
+
+-static void nc_flush_complete(struct urb *urb, struct pt_regs *regs)
++static void nc_flush_complete(struct urb *urb)
+ {
+ kfree(urb->context);
+ usb_free_urb(urb);
+@@ -498,25 +498,24 @@ static int net1080_rx_fixup(struct usbne
+ static struct sk_buff *
+ net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+ {
+- int padlen;
+ struct sk_buff *skb2;
+ struct nc_header *header = NULL;
+ struct nc_trailer *trailer = NULL;
++ int padlen = sizeof (struct nc_trailer);
+ int len = skb->len;
+
+- padlen = ((len + sizeof (struct nc_header)
+- + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
++ if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
++ padlen++;
+ if (!skb_cloned(skb)) {
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+
+- if ((padlen + sizeof (struct nc_trailer)) <= tailroom
+- && sizeof (struct nc_header) <= headroom)
++ if (padlen <= tailroom &&
++ sizeof(struct nc_header) <= headroom)
+ /* There's enough head and tail room */
+ goto encapsulate;
+
+- if ((sizeof (struct nc_header) + padlen
+- + sizeof (struct nc_trailer)) <
++ if ((sizeof (struct nc_header) + padlen) <
+ (headroom + tailroom)) {
+ /* There's enough total room, so just readjust */
+ skb->data = memmove(skb->head
+@@ -530,7 +529,7 @@ net1080_tx_fixup(struct usbnet *dev, str
+ /* Create a new skb to use with the correct size */
+ skb2 = skb_copy_expand(skb,
+ sizeof (struct nc_header),
+- sizeof (struct nc_trailer) + padlen,
++ padlen,
+ flags);
+ dev_kfree_skb_any(skb);
+ if (!skb2)
+diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
+index ab21f96..33abbd2 100644
+--- a/drivers/usb/net/pegasus.c
++++ b/drivers/usb/net/pegasus.c
+@@ -45,7 +45,7 @@
+ /*
+ * Version Information
+ */
+-#define DRIVER_VERSION "v0.6.13 (2005/11/13)"
++#define DRIVER_VERSION "v0.6.14 (2006/09/27)"
+ #define DRIVER_AUTHOR "Petko Manolov <petkan at users.sourceforge.net>"
+ #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
+
+@@ -96,7 +96,7 @@ MODULE_DEVICE_TABLE(usb, pegasus_ids);
+
+ static int update_eth_regs_async(pegasus_t *);
+ /* Aargh!!! I _really_ hate such tweaks */
+-static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
++static void ctrl_callback(struct urb *urb)
+ {
+ pegasus_t *pegasus = urb->context;
+
+@@ -339,7 +339,7 @@ static int read_mii_word(pegasus_t * peg
+ }
+ fail:
+ if (netif_msg_drv(pegasus))
+- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
++ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+
+ return ret;
+ }
+@@ -376,7 +376,7 @@ static int write_mii_word(pegasus_t * pe
+
+ fail:
+ if (netif_msg_drv(pegasus))
+- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
++ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+
+@@ -413,7 +413,7 @@ static int read_eprom_word(pegasus_t * p
+
+ fail:
+ if (netif_msg_drv(pegasus))
+- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
++ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+
+@@ -461,7 +461,7 @@ static int write_eprom_word(pegasus_t *
+ return ret;
+ fail:
+ if (netif_msg_drv(pegasus))
+- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
++ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+ #endif /* PEGASUS_WRITE_EEPROM */
+@@ -481,8 +481,12 @@ static void set_ethernet_addr(pegasus_t
+ {
+ __u8 node_id[6];
+
+- get_node_id(pegasus, node_id);
+- set_registers(pegasus, EthID, sizeof (node_id), node_id);
++ if (pegasus->features & PEGASUS_II) {
++ get_registers(pegasus, 0x10, sizeof(node_id), node_id);
++ } else {
++ get_node_id(pegasus, node_id);
++ set_registers(pegasus, EthID, sizeof (node_id), node_id);
++ }
+ memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
+ }
+
+@@ -601,7 +605,7 @@ static inline struct sk_buff *pull_skb(p
+ return NULL;
+ }
+
+-static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void read_bulk_callback(struct urb *urb)
+ {
+ pegasus_t *pegasus = urb->context;
+ struct net_device *net;
+@@ -619,7 +623,7 @@ static void read_bulk_callback(struct ur
+ switch (urb->status) {
+ case 0:
+ break;
+- case -ETIMEDOUT:
++ case -ETIME:
+ if (netif_msg_rx_err(pegasus))
+ pr_debug("%s: reset MAC\n", net->name);
+ pegasus->flags &= ~PEGASUS_RX_BUSY;
+@@ -760,7 +764,7 @@ done:
+ spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);
+ }
+
+-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void write_bulk_callback(struct urb *urb)
+ {
+ pegasus_t *pegasus = urb->context;
+ struct net_device *net = pegasus->net;
+@@ -797,7 +801,7 @@ static void write_bulk_callback(struct u
+ netif_wake_queue(net);
+ }
+
+-static void intr_callback(struct urb *urb, struct pt_regs *regs)
++static void intr_callback(struct urb *urb)
+ {
+ pegasus_t *pegasus = urb->context;
+ struct net_device *net;
+@@ -1222,7 +1226,7 @@ static void pegasus_set_multicast(struct
+ }
+
+ pegasus->flags |= ETH_REGS_CHANGE;
+- ctrl_callback(pegasus->ctrl_urb, NULL);
++ ctrl_callback(pegasus->ctrl_urb);
+ }
+
+ static __u8 mii_phy_probe(pegasus_t * pegasus)
+@@ -1429,11 +1433,11 @@ static int pegasus_resume (struct usb_in
+ if (netif_running(pegasus->net)) {
+ pegasus->rx_urb->status = 0;
+ pegasus->rx_urb->actual_length = 0;
+- read_bulk_callback(pegasus->rx_urb, NULL);
++ read_bulk_callback(pegasus->rx_urb);
+
+ pegasus->intr_urb->status = 0;
+ pegasus->intr_urb->actual_length = 0;
+- intr_callback(pegasus->intr_urb, NULL);
++ intr_callback(pegasus->intr_urb);
+ }
+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+ CARRIER_CHECK_DELAY);
+diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
+index a72685b..72171f9 100644
+--- a/drivers/usb/net/rtl8150.c
++++ b/drivers/usb/net/rtl8150.c
+@@ -208,7 +208,7 @@ static int set_registers(rtl8150_t * dev
+ indx, 0, data, size, 500);
+ }
+
+-static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
++static void ctrl_callback(struct urb *urb)
+ {
+ rtl8150_t *dev;
+
+@@ -415,7 +415,7 @@ static inline struct sk_buff *pull_skb(r
+ return NULL;
+ }
+
+-static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void read_bulk_callback(struct urb *urb)
+ {
+ rtl8150_t *dev;
+ unsigned pkt_len, res;
+@@ -438,7 +438,7 @@ static void read_bulk_callback(struct ur
+ break;
+ case -ENOENT:
+ return; /* the urb is in unlink state */
+- case -ETIMEDOUT:
++ case -ETIME:
+ warn("may be reset is needed?..");
+ goto goon;
+ default:
+@@ -525,7 +525,7 @@ tlsched:
+ tasklet_schedule(&dev->tl);
+ }
+
+-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void write_bulk_callback(struct urb *urb)
+ {
+ rtl8150_t *dev;
+
+@@ -541,7 +541,7 @@ static void write_bulk_callback(struct u
+ netif_wake_queue(dev->netdev);
+ }
+
+-static void intr_callback(struct urb *urb, struct pt_regs *regs)
++static void intr_callback(struct urb *urb)
+ {
+ rtl8150_t *dev;
+ __u8 *d;
+@@ -617,11 +617,11 @@ static int rtl8150_resume(struct usb_int
+ if (netif_running(dev->netdev)) {
+ dev->rx_urb->status = 0;
+ dev->rx_urb->actual_length = 0;
+- read_bulk_callback(dev->rx_urb, NULL);
++ read_bulk_callback(dev->rx_urb);
+
+ dev->intr_urb->status = 0;
+ dev->intr_urb->actual_length = 0;
+- intr_callback(dev->intr_urb, NULL);
++ intr_callback(dev->intr_urb);
+ }
+ return 0;
+ }
+diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
+index 54183e1..760b532 100644
+--- a/drivers/usb/net/usbnet.c
++++ b/drivers/usb/net/usbnet.c
+@@ -61,8 +61,11 @@
+ * let the USB host controller be busy for 5msec or more before an irq
+ * is required, under load. Jumbograms change the equation.
+ */
+-#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
+-#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
++#define RX_MAX_QUEUE_MEMORY (60 * 1518)
++#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
++ (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
++#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
++ (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
+
+ // reawaken network queue this soon after stopping; else watchdog barks
+ #define TX_TIMEOUT_JIFFIES (5*HZ)
+@@ -155,7 +158,7 @@ int usbnet_get_endpoints(struct usbnet *
+ }
+ EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
+
+-static void intr_complete (struct urb *urb, struct pt_regs *regs);
++static void intr_complete (struct urb *urb);
+
+ static int init_status (struct usbnet *dev, struct usb_interface *intf)
+ {
+@@ -227,13 +230,23 @@ static int usbnet_change_mtu (struct net
+ {
+ struct usbnet *dev = netdev_priv(net);
+ int ll_mtu = new_mtu + net->hard_header_len;
++ int old_hard_mtu = dev->hard_mtu;
++ int old_rx_urb_size = dev->rx_urb_size;
+
+- if (new_mtu <= 0 || ll_mtu > dev->hard_mtu)
++ if (new_mtu <= 0)
+ return -EINVAL;
+ // no second zero-length packet read wanted after mtu-sized packets
+ if ((ll_mtu % dev->maxpacket) == 0)
+ return -EDOM;
+ net->mtu = new_mtu;
++
++ dev->hard_mtu = net->mtu + net->hard_header_len;
++ if (dev->rx_urb_size == old_hard_mtu) {
++ dev->rx_urb_size = dev->hard_mtu;
++ if (dev->rx_urb_size > old_rx_urb_size)
++ usbnet_unlink_rx_urbs(dev);
++ }
++
+ return 0;
+ }
+
+@@ -282,7 +295,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
+
+ /*-------------------------------------------------------------------------*/
+
+-static void rx_complete (struct urb *urb, struct pt_regs *regs);
++static void rx_complete (struct urb *urb);
+
+ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
+ {
+@@ -370,7 +383,7 @@ error:
+
+ /*-------------------------------------------------------------------------*/
+
+-static void rx_complete (struct urb *urb, struct pt_regs *regs)
++static void rx_complete (struct urb *urb)
+ {
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct skb_data *entry = (struct skb_data *) skb->cb;
+@@ -412,9 +425,9 @@ static void rx_complete (struct urb *urb
+ // we get controller i/o faults during khubd disconnect() delays.
+ // throttle down resubmits, to avoid log floods; just temporarily,
+ // so we still recover when the fault isn't a khubd delay.
+- case -EPROTO: // ehci
+- case -ETIMEDOUT: // ohci
+- case -EILSEQ: // uhci
++ case -EPROTO:
++ case -ETIME:
++ case -EILSEQ:
+ dev->stats.rx_errors++;
+ if (!timer_pending (&dev->delay)) {
+ mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
+@@ -454,7 +467,7 @@ block:
+ devdbg (dev, "no read resubmitted");
+ }
+
+-static void intr_complete (struct urb *urb, struct pt_regs *regs)
++static void intr_complete (struct urb *urb)
+ {
+ struct usbnet *dev = urb->context;
+ int status = urb->status;
+@@ -521,6 +534,17 @@ static int unlink_urbs (struct usbnet *d
+ return count;
+ }
+
++// Flush all pending rx urbs
++// minidrivers may need to do this when the MTU changes
++
++void usbnet_unlink_rx_urbs(struct usbnet *dev)
++{
++ if (netif_running(dev->net)) {
++ (void) unlink_urbs (dev, &dev->rxq);
++ tasklet_schedule(&dev->bh);
++ }
++}
++EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
+
+ /*-------------------------------------------------------------------------*/
+
+@@ -530,7 +554,7 @@ static int usbnet_stop (struct net_devic
+ {
+ struct usbnet *dev = netdev_priv(net);
+ int temp;
+- DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
+ DECLARE_WAITQUEUE (wait, current);
+
+ netif_stop_queue (net);
+@@ -629,7 +653,7 @@ static int usbnet_open (struct net_devic
+
+ devinfo (dev, "open: enable queueing "
+ "(rx %d, tx %d) mtu %d %s framing",
+- RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu,
++ (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu,
+ framing);
+ }
+
+@@ -645,20 +669,40 @@ done:
+ * they'll probably want to use this base set.
+ */
+
+-void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
++#if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE)
++#define HAVE_MII
++
++int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
+ {
+ struct usbnet *dev = netdev_priv(net);
+
+- /* REVISIT don't always return "usbnet" */
+- strncpy (info->driver, driver_name, sizeof info->driver);
+- strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+- strncpy (info->fw_version, dev->driver_info->description,
+- sizeof info->fw_version);
+- usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
++ if (!dev->mii.mdio_read)
++ return -EOPNOTSUPP;
++
++ return mii_ethtool_gset(&dev->mii, cmd);
+ }
+-EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
++EXPORT_SYMBOL_GPL(usbnet_get_settings);
++
++int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
++{
++ struct usbnet *dev = netdev_priv(net);
++ int retval;
++
++ if (!dev->mii.mdio_write)
++ return -EOPNOTSUPP;
++
++ retval = mii_ethtool_sset(&dev->mii, cmd);
++
++ /* link speed/duplex might have changed */
++ if (dev->driver_info->link_reset)
++ dev->driver_info->link_reset(dev);
++
++ return retval;
++
++}
++EXPORT_SYMBOL_GPL(usbnet_set_settings);
+
+-static u32 usbnet_get_link (struct net_device *net)
++u32 usbnet_get_link (struct net_device *net)
+ {
+ struct usbnet *dev = netdev_priv(net);
+
+@@ -666,9 +710,40 @@ static u32 usbnet_get_link (struct net_d
+ if (dev->driver_info->check_connect)
+ return dev->driver_info->check_connect (dev) == 0;
+
++ /* if the device has mii operations, use those */
++ if (dev->mii.mdio_read)
++ return mii_link_ok(&dev->mii);
++
+ /* Otherwise, say we're up (to avoid breaking scripts) */
+ return 1;
+ }
++EXPORT_SYMBOL_GPL(usbnet_get_link);
++
++int usbnet_nway_reset(struct net_device *net)
++{
++ struct usbnet *dev = netdev_priv(net);
++
++ if (!dev->mii.mdio_write)
++ return -EOPNOTSUPP;
++
++ return mii_nway_restart(&dev->mii);
++}
++EXPORT_SYMBOL_GPL(usbnet_nway_reset);
++
++#endif /* HAVE_MII */
++
++void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
++{
++ struct usbnet *dev = netdev_priv(net);
++
++ /* REVISIT don't always return "usbnet" */
++ strncpy (info->driver, driver_name, sizeof info->driver);
++ strncpy (info->version, DRIVER_VERSION, sizeof info->version);
++ strncpy (info->fw_version, dev->driver_info->description,
++ sizeof info->fw_version);
++ usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
++}
++EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
+
+ u32 usbnet_get_msglevel (struct net_device *net)
+ {
+@@ -688,8 +763,13 @@ EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
+
+ /* drivers may override default ethtool_ops in their bind() routine */
+ static struct ethtool_ops usbnet_ethtool_ops = {
+- .get_drvinfo = usbnet_get_drvinfo,
++#ifdef HAVE_MII
++ .get_settings = usbnet_get_settings,
++ .set_settings = usbnet_set_settings,
+ .get_link = usbnet_get_link,
++ .nway_reset = usbnet_nway_reset,
++#endif
++ .get_drvinfo = usbnet_get_drvinfo,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ };
+@@ -773,7 +853,7 @@ kevent (void *data)
+
+ /*-------------------------------------------------------------------------*/
+
+-static void tx_complete (struct urb *urb, struct pt_regs *regs)
++static void tx_complete (struct urb *urb)
+ {
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct skb_data *entry = (struct skb_data *) skb->cb;
+@@ -797,9 +877,9 @@ static void tx_complete (struct urb *urb
+
+ // like rx, tx gets controller i/o faults during khubd delays
+ // and so it uses the same throttling mechanism.
+- case -EPROTO: // ehci
+- case -ETIMEDOUT: // ohci
+- case -EILSEQ: // uhci
++ case -EPROTO:
++ case -ETIME:
++ case -EILSEQ:
+ if (!timer_pending (&dev->delay)) {
+ mod_timer (&dev->delay,
+ jiffies + THROTTLE_JIFFIES);
+@@ -1070,6 +1150,7 @@ usbnet_probe (struct usb_interface *udev
+ dev->delay.function = usbnet_bh;
+ dev->delay.data = (unsigned long) dev;
+ init_timer (&dev->delay);
++ mutex_init (&dev->phy_mutex);
+
+ SET_MODULE_OWNER (net);
+ dev->net = net;
+@@ -1201,7 +1282,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
+ static int __init usbnet_init(void)
+ {
+ /* compiler should optimize this out */
+- BUG_ON (sizeof (((struct sk_buff *)0)->cb)
++ BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)
+ < sizeof (struct skb_data));
+
+ random_ether_addr(node_id);
+diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h
+index 89fc495..07c70ab 100644
+--- a/drivers/usb/net/usbnet.h
++++ b/drivers/usb/net/usbnet.h
+@@ -30,6 +30,7 @@ struct usbnet {
+ struct usb_device *udev;
+ struct driver_info *driver_info;
+ wait_queue_head_t *wait;
++ struct mutex phy_mutex;
+
+ /* i/o info: pipes etc */
+ unsigned in, out;
+@@ -166,10 +167,15 @@ struct skb_data { /* skb->cb is one of t
+ extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
+ extern void usbnet_defer_kevent (struct usbnet *, int);
+ extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
++extern void usbnet_unlink_rx_urbs(struct usbnet *);
+
++extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
++extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
++extern u32 usbnet_get_link (struct net_device *net);
+ extern u32 usbnet_get_msglevel (struct net_device *);
+ extern void usbnet_set_msglevel (struct net_device *, u32);
+ extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
++extern int usbnet_nway_reset(struct net_device *net);
+
+ /* messaging support includes the interface name, so it must not be
+ * used before it has one ... notably, in minidriver bind() calls.
+diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
+index f5b9438..2a8dd4c 100644
+--- a/drivers/usb/serial/Kconfig
++++ b/drivers/usb/serial/Kconfig
+@@ -53,6 +53,15 @@ config USB_SERIAL_GENERIC
+ support" be compiled as a module for this driver to be used
+ properly.
+
++config USB_SERIAL_AIRCABLE
++ tristate "USB AIRcable Bluetooth Dongle Driver (EXPERIMENTAL)"
++ depends on USB_SERIAL && EXPERIMENTAL
++ help
++ Say Y here if you want to use USB AIRcable Bluetooth Dongle.
++
++ To compile this driver as a module, choose M here: the module
++ will be called aircable.
++
+ config USB_SERIAL_AIRPRIME
+ tristate "USB AirPrime CDMA Wireless Driver"
+ depends on USB_SERIAL
+@@ -413,6 +422,31 @@ config USB_SERIAL_MCT_U232
+ To compile this driver as a module, choose M here: the
+ module will be called mct_u232.
+
++config USB_SERIAL_MOS7720
++ tristate "USB Moschip 7720 Single Port Serial Driver"
++ depends on USB_SERIAL
++ ---help---
++ Say Y here if you want to use a USB Serial single port adapter from
++ Moschip Semiconductor Tech.
++
++ To compile this driver as a module, choose M here: the
++ module will be called mos7720.
++
++config USB_SERIAL_MOS7840
++ tristate "USB Moschip 7840/7820 USB Serial Driver"
++ depends on USB_SERIAL
++ ---help---
++ Say Y here if you want to use a MCS7840 Quad-Serial or MCS7820
++ Dual-Serial port device from MosChip Semiconductor.
++
++ The MCS7840 and MCS7820 have been developed to connect a wide range
++ of standard serial devices to a USB host. The MCS7840 has a USB
++ device controller connected to four (4) individual UARTs while the
++ MCS7820 controller connects to two (2) individual UARTs.
++
++ To compile this driver as a module, choose M here: the
++ module will be called mos7840. If unsure, choose N.
++
+ config USB_SERIAL_NAVMAN
+ tristate "USB Navman GPS device"
+ depends on USB_SERIAL
+@@ -503,8 +537,7 @@ config USB_SERIAL_OPTION
+ The USB bus on these cards is not accessible externally.
+
+ Supported devices include (some of?) those made by:
+- Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
+- Anydata.
++ Option, Huawei, Audiovox, Novatel Wireless, or Anydata.
+
+ To compile this driver as a module, choose M here: the
+ module will be called option.
+@@ -526,5 +559,6 @@ config USB_EZUSB
+ depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
+ default y
+
++
+ endmenu
+
+diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
+index 8efed2c..a5047dc 100644
+--- a/drivers/usb/serial/Makefile
++++ b/drivers/usb/serial/Makefile
+@@ -11,6 +11,7 @@ usbserial-obj-$(CONFIG_USB_EZUSB) += ez
+
+ usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
+
++obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
+ obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
+ obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
+ obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
+@@ -33,6 +34,8 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) +=
+ obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
+ obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
+ obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
++obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
++obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
+ obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
+ obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
+ obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
+diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
+new file mode 100644
+index 0000000..8122755
+--- /dev/null
++++ b/drivers/usb/serial/aircable.c
+@@ -0,0 +1,625 @@
++/*
++ * AIRcable USB Bluetooth Dongle Driver.
++ *
++ * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel at gmail.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.
++ *
++ * The device works as an standard CDC device, it has 2 interfaces, the first
++ * one is for firmware access and the second is the serial one.
++ * The protocol is very simply, there are two posibilities reading or writing.
++ * When writting the first urb must have a Header that starts with 0x20 0x29 the
++ * next two bytes must say how much data will be sended.
++ * When reading the process is almost equal except that the header starts with
++ * 0x00 0x20.
++ *
++ * The device simply need some stuff to understand data comming from the usb
++ * buffer: The First and Second byte is used for a Header, the Third and Fourth
++ * tells the device the amount of information the package holds.
++ * Packages are 60 bytes long Header Stuff.
++ * When writting to the device the first two bytes of the header are 0x20 0x29
++ * When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange
++ * situation, when too much data arrives to the device because it sends the data
++ * but with out the header. I will use a simply hack to override this situation,
++ * if there is data coming that does not contain any header, then that is data
++ * that must go directly to the tty, as there is no documentation about if there
++ * is any other control code, I will simply check for the first
++ * one.
++ *
++ * The driver registers himself with the USB-serial core and the USB Core. I had
++ * to implement a probe function agains USB-serial, because other way, the
++ * driver was attaching himself to both interfaces. I have tryed with different
++ * configurations of usb_serial_driver with out exit, only the probe function
++ * could handle this correctly.
++ *
++ * I have taken some info from a Greg Kroah-Hartman article:
++ * http://www.linuxjournal.com/article/6573
++ * And from Linux Device Driver Kit CD, which is a great work, the authors taken
++ * the work to recompile lots of information an knowladge in drivers development
++ * and made it all avaible inside a cd.
++ * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/
++ *
++ */
++
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/circ_buf.h>
++#include <linux/usb.h>
++#include <linux/usb/serial.h>
++
++static int debug;
++
++/* Vendor and Product ID */
++#define AIRCABLE_VID 0x16CA
++#define AIRCABLE_USB_PID 0x1502
++
++/* write buffer size defines */
++#define AIRCABLE_BUF_SIZE 2048
++
++/* Protocol Stuff */
++#define HCI_HEADER_LENGTH 0x4
++#define TX_HEADER_0 0x20
++#define TX_HEADER_1 0x29
++#define RX_HEADER_0 0x00
++#define RX_HEADER_1 0x20
++#define MAX_HCI_FRAMESIZE 60
++#define HCI_COMPLETE_FRAME 64
++
++/* rx_flags */
++#define THROTTLED 0x01
++#define ACTUALLY_THROTTLED 0x02
++
++/*
++ * Version Information
++ */
++#define DRIVER_VERSION "v1.0b2"
++#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel at gmail.com>"
++#define DRIVER_DESC "AIRcable USB Driver"
++
++/* ID table that will be registered with USB core */
++static struct usb_device_id id_table [] = {
++ { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) },
++ { },
++};
++MODULE_DEVICE_TABLE(usb, id_table);
++
++
++/* Internal Structure */
++struct aircable_private {
++ spinlock_t rx_lock; /* spinlock for the receive lines */
++ struct circ_buf *tx_buf; /* write buffer */
++ struct circ_buf *rx_buf; /* read buffer */
++ int rx_flags; /* for throttilng */
++ struct work_struct rx_work; /* work cue for the receiving line */
++};
++
++/* Private methods */
++
++/* Circular Buffer Methods, code from ti_usb_3410_5052 used */
++/*
++ * serial_buf_clear
++ *
++ * Clear out all data in the circular buffer.
++ */
++static void serial_buf_clear(struct circ_buf *cb)
++{
++ cb->head = cb->tail = 0;
++}
++
++/*
++ * serial_buf_alloc
++ *
++ * Allocate a circular buffer and all associated memory.
++ */
++static struct circ_buf *serial_buf_alloc(void)
++{
++ struct circ_buf *cb;
++ cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
++ if (cb == NULL)
++ return NULL;
++ cb->buf = kmalloc(AIRCABLE_BUF_SIZE, GFP_KERNEL);
++ if (cb->buf == NULL) {
++ kfree(cb);
++ return NULL;
++ }
++ serial_buf_clear(cb);
++ return cb;
++}
++
++/*
++ * serial_buf_free
++ *
++ * Free the buffer and all associated memory.
++ */
++static void serial_buf_free(struct circ_buf *cb)
++{
++ kfree(cb->buf);
++ kfree(cb);
++}
++
++/*
++ * serial_buf_data_avail
++ *
++ * Return the number of bytes of data available in the circular
++ * buffer.
++ */
++static int serial_buf_data_avail(struct circ_buf *cb)
++{
++ return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
++}
++
++/*
++ * serial_buf_put
++ *
++ * Copy data data from a user buffer and put it into the circular buffer.
++ * Restrict to the amount of space available.
++ *
++ * Return the number of bytes copied.
++ */
++static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
++{
++ int c, ret = 0;
++ while (1) {
++ c = CIRC_SPACE_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
++ if (count < c)
++ c = count;
++ if (c <= 0)
++ break;
++ memcpy(cb->buf + cb->head, buf, c);
++ cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
++ buf += c;
++ count -= c;
++ ret= c;
++ }
++ return ret;
++}
++
++/*
++ * serial_buf_get
++ *
++ * Get data from the circular buffer and copy to the given buffer.
++ * Restrict to the amount of data available.
++ *
++ * Return the number of bytes copied.
++ */
++static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
++{
++ int c, ret = 0;
++ while (1) {
++ c = CIRC_CNT_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
++ if (count < c)
++ c = count;
++ if (c <= 0)
++ break;
++ memcpy(buf, cb->buf + cb->tail, c);
++ cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
++ buf += c;
++ count -= c;
++ ret= c;
++ }
++ return ret;
++}
++
++/* End of circula buffer methods */
++
++static void aircable_send(struct usb_serial_port *port)
++{
++ int count, result;
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ unsigned char* buf;
++ dbg("%s - port %d", __FUNCTION__, port->number);
++ if (port->write_urb_busy)
++ return;
++
++ count = min(serial_buf_data_avail(priv->tx_buf), MAX_HCI_FRAMESIZE);
++ if (count == 0)
++ return;
++
++ buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC);
++ if (!buf) {
++ err("%s- kzalloc(%d) failed.", __FUNCTION__,
++ count + HCI_HEADER_LENGTH);
++ return;
++ }
++
++ buf[0] = TX_HEADER_0;
++ buf[1] = TX_HEADER_1;
++ buf[2] = (unsigned char)count;
++ buf[3] = (unsigned char)(count >> 8);
++ serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
++
++ memcpy(port->write_urb->transfer_buffer, buf,
++ count + HCI_HEADER_LENGTH);
++
++ kfree(buf);
++ port->write_urb_busy = 1;
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
++ count + HCI_HEADER_LENGTH,
++ port->write_urb->transfer_buffer);
++ port->write_urb->transfer_buffer_length = count + HCI_HEADER_LENGTH;
++ port->write_urb->dev = port->serial->dev;
++ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++
++ if (result) {
++ dev_err(&port->dev,
++ "%s - failed submitting write urb, error %d\n",
++ __FUNCTION__, result);
++ port->write_urb_busy = 0;
++ }
++
++ schedule_work(&port->work);
++}
++
++static void aircable_read(void *params)
++{
++ struct usb_serial_port *port = params;
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ struct tty_struct *tty;
++ unsigned char *data;
++ int count;
++ if (priv->rx_flags & THROTTLED){
++ if (priv->rx_flags & ACTUALLY_THROTTLED)
++ schedule_work(&priv->rx_work);
++ return;
++ }
++
++ /* By now I will flush data to the tty in packages of no more than
++ * 64 bytes, to ensure I do not get throttled.
++ * Ask USB mailing list for better aproach.
++ */
++ tty = port->tty;
++
++ if (!tty)
++ schedule_work(&priv->rx_work);
++
++ count = min(64, serial_buf_data_avail(priv->rx_buf));
++
++ if (count <= 0)
++ return; //We have finished sending everything.
++
++ tty_prepare_flip_string(tty, &data, count);
++ if (!data){
++ err("%s- kzalloc(%d) failed.", __FUNCTION__, count);
++ return;
++ }
++
++ serial_buf_get(priv->rx_buf, data, count);
++
++ tty_flip_buffer_push(tty);
++
++ if (serial_buf_data_avail(priv->rx_buf))
++ schedule_work(&priv->rx_work);
++
++ return;
++}
++/* End of private methods */
++
++static int aircable_probe(struct usb_serial *serial,
++ const struct usb_device_id *id)
++{
++ struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
++ struct usb_endpoint_descriptor *endpoint;
++ int num_bulk_out=0;
++ int i;
++
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
++ endpoint = &iface_desc->endpoint[i].desc;
++ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
++ ((endpoint->bmAttributes & 3) == 0x02)) {
++ /* we found our bulk out endpoint */
++ dbg("found bulk out on endpoint %d", i);
++ ++num_bulk_out;
++ }
++ }
++
++ if (num_bulk_out == 0) {
++ dbg("Invalid interface, discarding");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int aircable_attach (struct usb_serial *serial)
++{
++ struct usb_serial_port *port = serial->port[0];
++ struct aircable_private *priv;
++
++ priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
++ if (!priv){
++ err("%s- kmalloc(%Zd) failed.", __FUNCTION__,
++ sizeof(struct aircable_private));
++ return -ENOMEM;
++ }
++
++ /* Allocation of Circular Buffers */
++ priv->tx_buf = serial_buf_alloc();
++ if (priv->tx_buf == NULL) {
++ kfree(priv);
++ return -ENOMEM;
++ }
++
++ priv->rx_buf = serial_buf_alloc();
++ if (priv->rx_buf == NULL) {
++ kfree(priv->tx_buf);
++ kfree(priv);
++ return -ENOMEM;
++ }
++
++ priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
++ INIT_WORK(&priv->rx_work, aircable_read, port);
++
++ usb_set_serial_port_data(serial->port[0], priv);
++
++ return 0;
++}
++
++static void aircable_shutdown(struct usb_serial *serial)
++{
++
++ struct usb_serial_port *port = serial->port[0];
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++
++ dbg("%s", __FUNCTION__);
++
++ if (priv) {
++ serial_buf_free(priv->tx_buf);
++ serial_buf_free(priv->rx_buf);
++ usb_set_serial_port_data(port, NULL);
++ kfree(priv);
++ }
++}
++
++static int aircable_write_room(struct usb_serial_port *port)
++{
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ return serial_buf_data_avail(priv->tx_buf);
++}
++
++static int aircable_write(struct usb_serial_port *port,
++ const unsigned char *source, int count)
++{
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ int temp;
++
++ dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
++
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, source);
++
++ if (!count){
++ dbg("%s - write request of 0 bytes", __FUNCTION__);
++ return count;
++ }
++
++ temp = serial_buf_put(priv->tx_buf, source, count);
++
++ aircable_send(port);
++
++ if (count > AIRCABLE_BUF_SIZE)
++ count = AIRCABLE_BUF_SIZE;
++
++ return count;
++
++}
++
++static void aircable_write_bulk_callback(struct urb *urb)
++{
++ struct usb_serial_port *port = urb->context;
++ int result;
++
++ dbg("%s - urb->status: %d", __FUNCTION__ , urb->status);
++
++ /* This has been taken from cypress_m8.c cypress_write_int_callback */
++ 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);
++ port->write_urb_busy = 0;
++ return;
++ default:
++ /* error in the urb, so we have to resubmit it */
++ dbg("%s - Overflow in write", __FUNCTION__);
++ dbg("%s - nonzero write bulk status received: %d",
++ __FUNCTION__, urb->status);
++ port->write_urb->transfer_buffer_length = 1;
++ port->write_urb->dev = port->serial->dev;
++ result = usb_submit_urb(port->write_urb, GFP_KERNEL);
++ if (result)
++ dev_err(&urb->dev->dev,
++ "%s - failed resubmitting write urb, error %d\n",
++ __FUNCTION__, result);
++ else
++ return;
++ }
++
++ port->write_urb_busy = 0;
++
++ aircable_send(port);
++}
++
++static void aircable_read_bulk_callback(struct urb *urb)
++{
++ struct usb_serial_port *port = urb->context;
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ struct tty_struct *tty;
++ unsigned long no_packages, remaining, package_length, i;
++ int result, shift = 0;
++ unsigned char *temp;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ if (urb->status) {
++ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++ if (!port->open_count) {
++ dbg("%s - port is closed, exiting.", __FUNCTION__);
++ return;
++ }
++ if (urb->status == -EPROTO) {
++ dbg("%s - caught -EPROTO, resubmitting the urb",
++ __FUNCTION__);
++ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++ usb_rcvbulkpipe(port->serial->dev,
++ port->bulk_in_endpointAddress),
++ port->read_urb->transfer_buffer,
++ port->read_urb->transfer_buffer_length,
++ aircable_read_bulk_callback, port);
++
++ result = usb_submit_urb(urb, GFP_ATOMIC);
++ if (result)
++ dev_err(&urb->dev->dev,
++ "%s - failed resubmitting read urb, error %d\n",
++ __FUNCTION__, result);
++ return;
++ }
++ dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
++ return;
++ }
++
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
++ urb->actual_length,urb->transfer_buffer);
++
++ tty = port->tty;
++ if (tty && urb->actual_length) {
++ if (urb->actual_length <= 2) {
++ /* This is an incomplete package */
++ serial_buf_put(priv->rx_buf, urb->transfer_buffer,
++ urb->actual_length);
++ } else {
++ temp = urb->transfer_buffer;
++ if (temp[0] == RX_HEADER_0)
++ shift = HCI_HEADER_LENGTH;
++
++ remaining = urb->actual_length;
++ no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
++
++ if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
++ no_packages+=1;
++
++ for (i = 0; i < no_packages ;i++) {
++ if (remaining > (HCI_COMPLETE_FRAME))
++ package_length = HCI_COMPLETE_FRAME;
++ else
++ package_length = remaining;
++ remaining -= package_length;
++
++ serial_buf_put(priv->rx_buf,
++ urb->transfer_buffer + shift +
++ (HCI_COMPLETE_FRAME) * (i),
++ package_length - shift);
++ }
++ }
++ aircable_read(port);
++ }
++
++ /* Schedule the next read _if_ we are still open */
++ if (port->open_count) {
++ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++ usb_rcvbulkpipe(port->serial->dev,
++ port->bulk_in_endpointAddress),
++ port->read_urb->transfer_buffer,
++ port->read_urb->transfer_buffer_length,
++ aircable_read_bulk_callback, port);
++
++ result = usb_submit_urb(urb, GFP_ATOMIC);
++ if (result)
++ dev_err(&urb->dev->dev,
++ "%s - failed resubmitting read urb, error %d\n",
++ __FUNCTION__, result);
++ }
++
++ return;
++}
++
++/* Based on ftdi_sio.c throttle */
++static void aircable_throttle(struct usb_serial_port *port)
++{
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ unsigned long flags;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ spin_lock_irqsave(&priv->rx_lock, flags);
++ priv->rx_flags |= THROTTLED;
++ spin_unlock_irqrestore(&priv->rx_lock, flags);
++}
++
++/* Based on ftdi_sio.c unthrottle */
++static void aircable_unthrottle(struct usb_serial_port *port)
++{
++ struct aircable_private *priv = usb_get_serial_port_data(port);
++ int actually_throttled;
++ unsigned long flags;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ spin_lock_irqsave(&priv->rx_lock, flags);
++ actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
++ priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
++ spin_unlock_irqrestore(&priv->rx_lock, flags);
++
++ if (actually_throttled)
++ schedule_work(&priv->rx_work);
++}
++
++static struct usb_serial_driver aircable_device = {
++ .description = "aircable",
++ .id_table = id_table,
++ .num_ports = 1,
++ .attach = aircable_attach,
++ .probe = aircable_probe,
++ .shutdown = aircable_shutdown,
++ .write = aircable_write,
++ .write_room = aircable_write_room,
++ .write_bulk_callback = aircable_write_bulk_callback,
++ .read_bulk_callback = aircable_read_bulk_callback,
++ .throttle = aircable_throttle,
++ .unthrottle = aircable_unthrottle,
++};
++
++static struct usb_driver aircable_driver = {
++ .name = "aircable",
++ .probe = usb_serial_probe,
++ .disconnect = usb_serial_disconnect,
++ .id_table = id_table,
++};
++
++static int __init aircable_init (void)
++{
++ int retval;
++ retval = usb_serial_register(&aircable_device);
++ if (retval)
++ goto failed_serial_register;
++ retval = usb_register(&aircable_driver);
++ if (retval)
++ goto failed_usb_register;
++ return 0;
++
++failed_serial_register:
++ usb_serial_deregister(&aircable_device);
++failed_usb_register:
++ return retval;
++}
++
++static void __exit aircable_exit (void)
++{
++ usb_deregister(&aircable_driver);
++ usb_serial_deregister(&aircable_device);
++}
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_VERSION(DRIVER_VERSION);
++MODULE_LICENSE("GPL");
++
++module_init(aircable_init);
++module_exit(aircable_exit);
++
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled or not");
+diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
+index 6208253..7f5d546 100644
+--- a/drivers/usb/serial/airprime.c
++++ b/drivers/usb/serial/airprime.c
+@@ -1,7 +1,7 @@
+ /*
+ * AirPrime CDMA Wireless Serial USB driver
+ *
+- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh at suse.de>
++ * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh at suse.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+@@ -11,26 +11,261 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/tty.h>
++#include <linux/tty_flip.h>
+ #include <linux/module.h>
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
+
+ static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
+- { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
+ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
+- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
++ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
+ { },
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+
++#define URB_TRANSFER_BUFFER_SIZE 4096
++#define NUM_READ_URBS 4
++#define NUM_WRITE_URBS 4
++#define NUM_BULK_EPS 3
++#define MAX_BULK_EPS 6
++
++/* if overridden by the user, then use their value for the size of the
++ * read and write urbs, and the number of endpoints */
++static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
++static int endpoints = NUM_BULK_EPS;
++static int debug;
++struct airprime_private {
++ spinlock_t lock;
++ int outstanding_urbs;
++ int throttled;
++ struct urb *read_urbp[NUM_READ_URBS];
++};
++
++static void airprime_read_bulk_callback(struct urb *urb)
++{
++ struct usb_serial_port *port = urb->context;
++ unsigned char *data = urb->transfer_buffer;
++ struct tty_struct *tty;
++ int result;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ if (urb->status) {
++ dbg("%s - nonzero read bulk status received: %d",
++ __FUNCTION__, urb->status);
++ /* something happened, so free up the memory for this urb */
++ if (urb->transfer_buffer) {
++ kfree (urb->transfer_buffer);
++ urb->transfer_buffer = NULL;
++ }
++ return;
++ }
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
++
++ tty = port->tty;
++ if (tty && urb->actual_length) {
++ tty_insert_flip_string (tty, data, urb->actual_length);
++ tty_flip_buffer_push (tty);
++ }
++
++ result = usb_submit_urb (urb, GFP_ATOMIC);
++ if (result)
++ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
++ __FUNCTION__, result);
++ return;
++}
++
++static void airprime_write_bulk_callback(struct urb *urb)
++{
++ struct usb_serial_port *port = urb->context;
++ struct airprime_private *priv = usb_get_serial_port_data(port);
++ unsigned long flags;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* free up the transfer buffer, as usb_free_urb() does not do this */
++ kfree (urb->transfer_buffer);
++
++ if (urb->status)
++ dbg("%s - nonzero write bulk status received: %d",
++ __FUNCTION__, urb->status);
++ spin_lock_irqsave(&priv->lock, flags);
++ --priv->outstanding_urbs;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ usb_serial_port_softint(port);
++}
++
++static int airprime_open(struct usb_serial_port *port, struct file *filp)
++{
++ struct airprime_private *priv = usb_get_serial_port_data(port);
++ struct usb_serial *serial = port->serial;
++ struct urb *urb;
++ char *buffer = NULL;
++ int i;
++ int result = 0;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* initialize our private data structure if it isn't already created */
++ if (!priv) {
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv) {
++ result = -ENOMEM;
++ goto out;
++ }
++ spin_lock_init(&priv->lock);
++ usb_set_serial_port_data(port, priv);
++ }
++
++ for (i = 0; i < NUM_READ_URBS; ++i) {
++ buffer = kmalloc(buffer_size, GFP_KERNEL);
++ if (!buffer) {
++ dev_err(&port->dev, "%s - out of memory.\n",
++ __FUNCTION__);
++ result = -ENOMEM;
++ goto errout;
++ }
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ kfree(buffer);
++ dev_err(&port->dev, "%s - no more urbs?\n",
++ __FUNCTION__);
++ result = -ENOMEM;
++ goto errout;
++ }
++ usb_fill_bulk_urb(urb, serial->dev,
++ usb_rcvbulkpipe(serial->dev,
++ port->bulk_out_endpointAddress),
++ buffer, buffer_size,
++ airprime_read_bulk_callback, port);
++ result = usb_submit_urb(urb, GFP_KERNEL);
++ if (result) {
++ dev_err(&port->dev,
++ "%s - failed submitting read urb %d for port %d, error %d\n",
++ __FUNCTION__, i, port->number, result);
++ goto errout;
++ }
++ /* remember this urb so we can kill it when the port is closed */
++ priv->read_urbp[i] = urb;
++ }
++ goto out;
++
++ errout:
++ /* some error happened, cancel any submitted urbs and clean up anything that
++ got allocated successfully */
++
++ for ( ; i >= 0; --i) {
++ urb = priv->read_urbp[i];
++ if (urb) {
++ /* This urb was submitted successfully. So we have to
++ cancel it.
++ Unlinking the urb will invoke read_bulk_callback()
++ with an error status, so its transfer buffer will
++ be freed there */
++ if (usb_unlink_urb (urb) != -EINPROGRESS) {
++ /* comments in drivers/usb/core/urb.c say this
++ can only happen if the urb was never submitted,
++ or has completed already.
++ Either way we may have to free the transfer
++ buffer here. */
++ if (urb->transfer_buffer) {
++ kfree (urb->transfer_buffer);
++ urb->transfer_buffer = NULL;
++ }
++ }
++ usb_free_urb (urb);
++ }
++ }
++
++ out:
++ return result;
++}
++
++static void airprime_close(struct usb_serial_port *port, struct file * filp)
++{
++ struct airprime_private *priv = usb_get_serial_port_data(port);
++ int i;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* killing the urb will invoke read_bulk_callback() with an error status,
++ so the transfer buffer will be freed there */
++ for (i = 0; i < NUM_READ_URBS; ++i) {
++ usb_kill_urb (priv->read_urbp[i]);
++ usb_free_urb (priv->read_urbp[i]);
++ }
++
++ /* free up private structure */
++ kfree (priv);
++ usb_set_serial_port_data(port, NULL);
++}
++
++static int airprime_write(struct usb_serial_port *port,
++ const unsigned char *buf, int count)
++{
++ struct airprime_private *priv = usb_get_serial_port_data(port);
++ struct usb_serial *serial = port->serial;
++ struct urb *urb;
++ unsigned char *buffer;
++ unsigned long flags;
++ int status;
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->outstanding_urbs > NUM_WRITE_URBS) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ dbg("%s - write limit hit\n", __FUNCTION__);
++ return 0;
++ }
++ spin_unlock_irqrestore(&priv->lock, flags);
++ buffer = kmalloc(count, GFP_ATOMIC);
++ if (!buffer) {
++ dev_err(&port->dev, "out of memory\n");
++ return -ENOMEM;
++ }
++ urb = usb_alloc_urb(0, GFP_ATOMIC);
++ if (!urb) {
++ dev_err(&port->dev, "no more free urbs\n");
++ kfree (buffer);
++ return -ENOMEM;
++ }
++ memcpy (buffer, buf, count);
++
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
++
++ usb_fill_bulk_urb(urb, serial->dev,
++ usb_sndbulkpipe(serial->dev,
++ port->bulk_out_endpointAddress),
++ buffer, count,
++ airprime_write_bulk_callback, port);
++
++ /* send it down the pipe */
++ status = usb_submit_urb(urb, GFP_ATOMIC);
++ if (status) {
++ dev_err(&port->dev,
++ "%s - usb_submit_urb(write bulk) failed with status = %d\n",
++ __FUNCTION__, status);
++ count = status;
++ kfree (buffer);
++ } else {
++ spin_lock_irqsave(&priv->lock, flags);
++ ++priv->outstanding_urbs;
++ spin_unlock_irqrestore(&priv->lock, flags);
++ }
++ /* we are done with this urb, so let the host driver
++ * really free it when it is finished with it */
++ usb_free_urb (urb);
++ return count;
++}
++
+ static struct usb_driver airprime_driver = {
+ .name = "airprime",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+- .no_dynamic_id = 1,
++ .no_dynamic_id = 1,
+ };
+
+ static struct usb_serial_driver airprime_device = {
+@@ -42,13 +277,17 @@ static struct usb_serial_driver airprime
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+- .num_ports = 1,
++ .open = airprime_open,
++ .close = airprime_close,
++ .write = airprime_write,
+ };
+
+ static int __init airprime_init(void)
+ {
+ int retval;
+
++ airprime_device.num_ports =
++ (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
+ retval = usb_serial_register(&airprime_device);
+ if (retval)
+ return retval;
+@@ -60,6 +299,8 @@ static int __init airprime_init(void)
+
+ static void __exit airprime_exit(void)
+ {
++ dbg("%s", __FUNCTION__);
++
+ usb_deregister(&airprime_driver);
+ usb_serial_deregister(&airprime_device);
+ }
+@@ -67,3 +308,10 @@ static void __exit airprime_exit(void)
+ module_init(airprime_init);
+ module_exit(airprime_exit);
+ MODULE_LICENSE("GPL");
++
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled");
++module_param(buffer_size, int, 0);
++MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
++module_param(endpoints, int, 0);
++MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
+diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
+index 970d9ef..ca52f12 100644
+--- a/drivers/usb/serial/ark3116.c
++++ b/drivers/usb/serial/ark3116.c
+@@ -1,4 +1,7 @@
+ /*
++ * Copyright (C) 2006
++ * Simon Schulz (ark3116_driver <at> auctionant.de)
++ *
+ * ark3116
+ * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547,
+ * productid=0x0232) (used in a datacable called KQ-U8A)
+@@ -8,8 +11,6 @@
+ *
+ * - based on logs created by usbsnoopy
+ *
+- * Author : Simon Schulz [ark3116_driver<AT>auctionant.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
+@@ -22,6 +23,8 @@
+ #include <linux/module.h>
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
++#include <linux/serial.h>
++#include <asm/uaccess.h>
+
+
+ static int debug;
+@@ -43,10 +46,10 @@ static inline void ARK3116_SND(struct us
+ {
+ int result;
+ result = usb_control_msg(serial->dev,
+- usb_sndctrlpipe(serial->dev,0),
++ usb_sndctrlpipe(serial->dev, 0),
+ request, requesttype, value, index,
+- NULL,0x00, 1000);
+- dbg("%03d > ok",seq);
++ NULL, 0x00, 1000);
++ dbg("%03d > ok", seq);
+ }
+
+ static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
+@@ -56,27 +59,25 @@ static inline void ARK3116_RCV(struct us
+ {
+ int result;
+ result = usb_control_msg(serial->dev,
+- usb_rcvctrlpipe(serial->dev,0),
+- request, requesttype, value, index,
+- buf, 0x0000001, 1000);
++ usb_rcvctrlpipe(serial->dev, 0),
++ request, requesttype, value, index,
++ buf, 0x0000001, 1000);
+ if (result)
+- dbg("%03d < %d bytes [0x%02X]",seq, result, buf[0]);
++ dbg("%03d < %d bytes [0x%02X]", seq, result, buf[0]);
+ else
+ dbg("%03d < 0 bytes", seq);
+ }
+
+-
+ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
+ __u8 request, __u8 requesttype,
+ __u16 value, __u16 index, char *buf)
+ {
+ usb_control_msg(serial->dev,
+- usb_rcvctrlpipe(serial->dev,0),
++ usb_rcvctrlpipe(serial->dev, 0),
+ request, requesttype, value, index,
+ buf, 0x0000001, 1000);
+ }
+
+-
+ static int ark3116_attach(struct usb_serial *serial)
+ {
+ char *buf;
+@@ -84,10 +85,10 @@ static int ark3116_attach(struct usb_ser
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+- priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL);
++ priv = kmalloc(sizeof (struct ark3116_private), GFP_KERNEL);
+ if (!priv)
+ goto cleanup;
+- memset (priv, 0x00, sizeof (struct ark3116_private));
++ memset(priv, 0x00, sizeof (struct ark3116_private));
+ spin_lock_init(&priv->lock);
+
+ usb_set_serial_port_data(serial->port[i], priv);
+@@ -95,63 +96,62 @@ static int ark3116_attach(struct usb_ser
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+- dbg("error kmalloc -> out of mem ?");
++ dbg("error kmalloc -> out of mem?");
+ goto cleanup;
+ }
+
+ /* 3 */
+- ARK3116_SND(serial, 3,0xFE,0x40,0x0008,0x0002);
+- ARK3116_SND(serial, 4,0xFE,0x40,0x0008,0x0001);
+- ARK3116_SND(serial, 5,0xFE,0x40,0x0000,0x0008);
+- ARK3116_SND(serial, 6,0xFE,0x40,0x0000,0x000B);
++ ARK3116_SND(serial, 3, 0xFE, 0x40, 0x0008, 0x0002);
++ ARK3116_SND(serial, 4, 0xFE, 0x40, 0x0008, 0x0001);
++ ARK3116_SND(serial, 5, 0xFE, 0x40, 0x0000, 0x0008);
++ ARK3116_SND(serial, 6, 0xFE, 0x40, 0x0000, 0x000B);
+
+ /* <-- seq7 */
+- ARK3116_RCV(serial, 7,0xFE,0xC0,0x0000,0x0003, 0x00, buf);
+- ARK3116_SND(serial, 8,0xFE,0x40,0x0080,0x0003);
+- ARK3116_SND(serial, 9,0xFE,0x40,0x001A,0x0000);
+- ARK3116_SND(serial,10,0xFE,0x40,0x0000,0x0001);
+- ARK3116_SND(serial,11,0xFE,0x40,0x0000,0x0003);
++ ARK3116_RCV(serial, 7, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
++ ARK3116_SND(serial, 8, 0xFE, 0x40, 0x0080, 0x0003);
++ ARK3116_SND(serial, 9, 0xFE, 0x40, 0x001A, 0x0000);
++ ARK3116_SND(serial, 10, 0xFE, 0x40, 0x0000, 0x0001);
++ ARK3116_SND(serial, 11, 0xFE, 0x40, 0x0000, 0x0003);
+
+ /* <-- seq12 */
+- ARK3116_RCV(serial,12,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+- ARK3116_SND(serial,13,0xFE,0x40,0x0000,0x0004);
++ ARK3116_RCV(serial, 12, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
++ ARK3116_SND(serial, 13, 0xFE, 0x40, 0x0000, 0x0004);
+
+ /* 14 */
+- ARK3116_RCV(serial,14,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+- ARK3116_SND(serial,15,0xFE,0x40,0x0000,0x0004);
++ ARK3116_RCV(serial, 14, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
++ ARK3116_SND(serial, 15, 0xFE, 0x40, 0x0000, 0x0004);
+
+ /* 16 */
+- ARK3116_RCV(serial,16,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
++ ARK3116_RCV(serial, 16, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
+ /* --> seq17 */
+- ARK3116_SND(serial,17,0xFE,0x40,0x0001,0x0004);
++ ARK3116_SND(serial, 17, 0xFE, 0x40, 0x0001, 0x0004);
+
+ /* <-- seq18 */
+- ARK3116_RCV(serial,18,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
++ ARK3116_RCV(serial, 18, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
+
+ /* --> seq19 */
+- ARK3116_SND(serial,19,0xFE,0x40,0x0003,0x0004);
+-
++ ARK3116_SND(serial, 19, 0xFE, 0x40, 0x0003, 0x0004);
+
+ /* <-- seq20 */
+- /* seems like serial port status info (RTS, CTS,...) */
+- /* returns modem control line status ?! */
+- ARK3116_RCV(serial,20,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
+-
+- /* set 9600 baud & do some init ?! */
+- ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
+- ARK3116_SND(serial,148,0xFE,0x40,0x0038,0x0000);
+- ARK3116_SND(serial,149,0xFE,0x40,0x0001,0x0001);
+- ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
+- ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
+- ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
+- ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
+- ARK3116_SND(serial,154,0xFE,0x40,0x0003,0x0003);
++ /* seems like serial port status info (RTS, CTS, ...) */
++ /* returns modem control line status?! */
++ ARK3116_RCV(serial, 20, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
++
++ /* set 9600 baud & do some init?! */
++ ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
++ ARK3116_SND(serial, 148, 0xFE, 0x40, 0x0038, 0x0000);
++ ARK3116_SND(serial, 149, 0xFE, 0x40, 0x0001, 0x0001);
++ ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
++ ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
++ ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
++ ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
++ ARK3116_SND(serial, 154, 0xFE, 0x40, 0x0003, 0x0003);
+
+ kfree(buf);
+- return(0);
++ return 0;
+
+ cleanup:
+- for (--i; i>=0; --i)
++ for (--i; i >= 0; --i)
+ usb_set_serial_port_data(serial->port[i], NULL);
+ return -ENOMEM;
+ }
+@@ -180,7 +180,8 @@ static void ark3116_set_termios(struct u
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+- port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++ port->tty->termios->c_cflag = B9600 | CS8
++ | CREAD | HUPCL | CLOCAL;
+ priv->termios_initialized = 1;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+@@ -204,8 +205,8 @@ static void ark3116_set_termios(struct u
+ }
+
+ /* set data bit count (8/7/6/5) */
+- if (cflag & CSIZE){
+- switch (cflag & CSIZE){
++ if (cflag & CSIZE) {
++ switch (cflag & CSIZE) {
+ case CS5:
+ config |= 0x00;
+ dbg("setting CS5");
+@@ -219,7 +220,8 @@ static void ark3116_set_termios(struct u
+ dbg("setting CS7");
+ break;
+ default:
+- err ("CSIZE was set but not CS5-CS8, using CS8!");
++ err("CSIZE was set but not CS5-CS8, using CS8!");
++ /* fall through */
+ case CS8:
+ config |= 0x03;
+ dbg("setting CS8");
+@@ -227,8 +229,8 @@ static void ark3116_set_termios(struct u
+ }
+ }
+
+- /* set parity (NONE,EVEN,ODD) */
+- if (cflag & PARENB){
++ /* set parity (NONE/EVEN/ODD) */
++ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ config |= 0x08;
+ dbg("setting parity to ODD");
+@@ -240,20 +242,19 @@ static void ark3116_set_termios(struct u
+ dbg("setting parity to NONE");
+ }
+
+- /* SET STOPBIT (1/2) */
++ /* set stop bit (1/2) */
+ if (cflag & CSTOPB) {
+ config |= 0x04;
+- dbg ("setting 2 stop bits");
++ dbg("setting 2 stop bits");
+ } else {
+- dbg ("setting 1 stop bit");
++ dbg("setting 1 stop bit");
+ }
+
+-
+- /* set baudrate: */
++ /* set baudrate */
+ baud = 0;
+- switch (cflag & CBAUD){
++ switch (cflag & CBAUD) {
+ case B0:
+- err("can't set 0baud, using 9600 instead");
++ err("can't set 0 baud, using 9600 instead");
+ break;
+ case B75: baud = 75; break;
+ case B150: baud = 150; break;
+@@ -285,38 +286,40 @@ static void ark3116_set_termios(struct u
+ */
+ if (baud == 460800)
+ /* strange, for 460800 the formula is wrong
+- * (dont use round(), then 9600baud is wrong) */
++ * if using round() then 9600baud is wrong) */
+ ark3116_baud = 7;
+ else
+ ark3116_baud = 3000000 / baud;
+
+ /* ? */
+- ARK3116_RCV(serial,0,0xFE,0xC0,0x0000,0x0003, 0x03, buf);
++ ARK3116_RCV(serial, 0, 0xFE, 0xC0, 0x0000, 0x0003, 0x03, buf);
++
+ /* offset = buf[0]; */
+ /* offset = 0x03; */
+- /* dbg("using 0x%04X as target for 0x0003:",0x0080+offset); */
+-
++ /* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */
+
+ /* set baudrate */
+- dbg("setting baudrate to %d (->reg=%d)",baud,ark3116_baud);
+- ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
+- ARK3116_SND(serial,148,0xFE,0x40,(ark3116_baud & 0x00FF) ,0x0000);
+- ARK3116_SND(serial,149,0xFE,0x40,(ark3116_baud & 0xFF00)>>8,0x0001);
+- ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
++ dbg("setting baudrate to %d (->reg=%d)", baud, ark3116_baud);
++ ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
++ ARK3116_SND(serial, 148, 0xFE, 0x40,
++ (ark3116_baud & 0x00FF), 0x0000);
++ ARK3116_SND(serial, 149, 0xFE, 0x40,
++ (ark3116_baud & 0xFF00) >> 8, 0x0001);
++ ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
+
+ /* ? */
+- ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
+- ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
++ ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
++ ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
+
+ /* set data bit count, stop bit count & parity: */
+ dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config);
+- ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
+- ARK3116_SND(serial,154,0xFE,0x40,config,0x0003);
++ ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
++ ARK3116_SND(serial, 154, 0xFE, 0x40, config, 0x0003);
+
+ if (cflag & CRTSCTS)
+- dbg("CRTSCTS not supported by chipset ?!");
++ dbg("CRTSCTS not supported by chipset?!");
+
+- /* TEST ARK3116_SND(154,0xFE,0x40,0xFFFF, 0x0006); */
++ /* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
+
+ kfree(buf);
+ return;
+@@ -329,11 +332,11 @@ static int ark3116_open(struct usb_seria
+ char *buf;
+ int result = 0;
+
+- dbg("%s - port %d", __FUNCTION__, port->number);
++ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+- dbg("error kmalloc -> out of mem ?");
++ dbg("error kmalloc -> out of mem?");
+ return -ENOMEM;
+ }
+
+@@ -342,44 +345,68 @@ static int ark3116_open(struct usb_seria
+ return result;
+
+ /* open */
+- ARK3116_RCV(serial,111,0xFE,0xC0,0x0000,0x0003, 0x02, buf);
++ ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
+
+- ARK3116_SND(serial,112,0xFE,0x40,0x0082,0x0003);
+- ARK3116_SND(serial,113,0xFE,0x40,0x001A,0x0000);
+- ARK3116_SND(serial,114,0xFE,0x40,0x0000,0x0001);
+- ARK3116_SND(serial,115,0xFE,0x40,0x0002,0x0003);
++ ARK3116_SND(serial, 112, 0xFE, 0x40, 0x0082, 0x0003);
++ ARK3116_SND(serial, 113, 0xFE, 0x40, 0x001A, 0x0000);
++ ARK3116_SND(serial, 114, 0xFE, 0x40, 0x0000, 0x0001);
++ ARK3116_SND(serial, 115, 0xFE, 0x40, 0x0002, 0x0003);
+
+- ARK3116_RCV(serial,116,0xFE,0xC0,0x0000,0x0004, 0x03, buf);
+- ARK3116_SND(serial,117,0xFE,0x40,0x0002,0x0004);
++ ARK3116_RCV(serial, 116, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
++ ARK3116_SND(serial, 117, 0xFE, 0x40, 0x0002, 0x0004);
+
+- ARK3116_RCV(serial,118,0xFE,0xC0,0x0000,0x0004, 0x02, buf);
+- ARK3116_SND(serial,119,0xFE,0x40,0x0000,0x0004);
++ ARK3116_RCV(serial, 118, 0xFE, 0xC0, 0x0000, 0x0004, 0x02, buf);
++ ARK3116_SND(serial, 119, 0xFE, 0x40, 0x0000, 0x0004);
+
+- ARK3116_RCV(serial,120,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
++ ARK3116_RCV(serial, 120, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
+
+- ARK3116_SND(serial,121,0xFE,0x40,0x0001,0x0004);
++ ARK3116_SND(serial, 121, 0xFE, 0x40, 0x0001, 0x0004);
+
+- ARK3116_RCV(serial,122,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
++ ARK3116_RCV(serial, 122, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
+
+- ARK3116_SND(serial,123,0xFE,0x40,0x0003,0x0004);
++ ARK3116_SND(serial, 123, 0xFE, 0x40, 0x0003, 0x0004);
+
+- /* returns different values (control lines ?!) */
+- ARK3116_RCV(serial,124,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
++ /* returns different values (control lines?!) */
++ ARK3116_RCV(serial, 124, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
+
+- /* initialise termios: */
++ /* initialise termios */
+ if (port->tty)
+ ark3116_set_termios(port, &tmp_termios);
+
+ kfree(buf);
+
+ return result;
+-
+ }
+
+ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+- dbg("ioctl not supported yet...");
++ struct serial_struct serstruct;
++ void __user *user_arg = (void __user *)arg;
++
++ switch (cmd) {
++ case TIOCGSERIAL:
++ /* XXX: Some of these values are probably wrong. */
++ memset(&serstruct, 0, sizeof (serstruct));
++ serstruct.type = PORT_16654;
++ serstruct.line = port->serial->minor;
++ serstruct.port = port->number;
++ serstruct.custom_divisor = 0;
++ serstruct.baud_base = 460800;
++
++ if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
++ return -EFAULT;
++
++ return 0;
++ case TIOCSSERIAL:
++ if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
++ return -EFAULT;
++ return 0;
++ default:
++ dbg("%s cmd 0x%04x not supported", __FUNCTION__, cmd);
++ break;
++ }
++
+ return -ENOIOCTLCMD;
+ }
+
+@@ -389,7 +416,7 @@ static int ark3116_tiocmget(struct usb_s
+ char *buf;
+ char temp;
+
+- /* seems like serial port status info (RTS, CTS,...) is stored
++ /* seems like serial port status info (RTS, CTS, ...) is stored
+ * in reg(?) 0x0006
+ * pcb connection point 11 = GND -> sets bit4 of response
+ * pcb connection point 7 = GND -> sets bit6 of response
+@@ -401,16 +428,16 @@ static int ark3116_tiocmget(struct usb_s
+ return -ENOMEM;
+ }
+
+- /* read register: */
+- ARK3116_RCV_QUIET(serial,0xFE,0xC0,0x0000,0x0006,buf);
++ /* read register */
++ ARK3116_RCV_QUIET(serial, 0xFE, 0xC0, 0x0000, 0x0006, buf);
+ temp = buf[0];
+ kfree(buf);
+
+- /* i do not really know if bit4=CTS and bit6=DSR... was just a
+- * quick guess !!
++ /* i do not really know if bit4=CTS and bit6=DSR... just a
++ * quick guess!
+ */
+- return (temp & (1<<4) ? TIOCM_CTS : 0) |
+- (temp & (1<<6) ? TIOCM_DSR : 0);
++ return (temp & (1<<4) ? TIOCM_CTS : 0)
++ | (temp & (1<<6) ? TIOCM_DSR : 0);
+ }
+
+ static struct usb_driver ark3116_driver = {
+diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
+index 70ece9e..8835bb5 100644
+--- a/drivers/usb/serial/belkin_sa.c
++++ b/drivers/usb/serial/belkin_sa.c
+@@ -91,7 +91,7 @@ static int belkin_sa_startup (struct u
+ static void belkin_sa_shutdown (struct usb_serial *serial);
+ static int belkin_sa_open (struct usb_serial_port *port, struct file *filp);
+ static void belkin_sa_close (struct usb_serial_port *port, struct file *filp);
+-static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs);
++static void belkin_sa_read_int_callback (struct urb *urb);
+ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);
+ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+ static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state );
+@@ -248,7 +248,7 @@ static void belkin_sa_close (struct usb_
+ } /* belkin_sa_close */
+
+
+-static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs)
++static void belkin_sa_read_int_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct belkin_sa_private *priv;
+diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
+index 486c741..f95d42c 100644
+--- a/drivers/usb/serial/cp2101.c
++++ b/drivers/usb/serial/cp2101.c
+@@ -64,7 +64,11 @@ static struct usb_device_id id_table []
+ { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
+ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
+ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
++ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
++ { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
++ { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
+ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
++ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+ { } /* Terminating Entry */
+ };
+diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
+index 6286aba..a63c328 100644
+--- a/drivers/usb/serial/cyberjack.c
++++ b/drivers/usb/serial/cyberjack.c
+@@ -63,9 +63,9 @@ static int cyberjack_open (struct usb_s
+ static void cyberjack_close (struct usb_serial_port *port, struct file *filp);
+ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *buf, int count);
+ static int cyberjack_write_room( struct usb_serial_port *port );
+-static void cyberjack_read_int_callback (struct urb *urb, struct pt_regs *regs);
+-static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void cyberjack_read_int_callback (struct urb *urb);
++static void cyberjack_read_bulk_callback (struct urb *urb);
++static void cyberjack_write_bulk_callback (struct urb *urb);
+
+ static struct usb_device_id id_table [] = {
+ { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
+@@ -214,14 +214,14 @@ static int cyberjack_write (struct usb_s
+ return (0);
+ }
+
+- spin_lock(&port->lock);
++ spin_lock_bh(&port->lock);
+ if (port->write_urb_busy) {
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
+ }
+ port->write_urb_busy = 1;
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+@@ -299,7 +299,7 @@ static int cyberjack_write_room( struct
+ return CYBERJACK_LOCAL_BUF_SIZE;
+ }
+
+-static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs )
++static void cyberjack_read_int_callback( struct urb *urb )
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cyberjack_private *priv = usb_get_serial_port_data(port);
+@@ -356,7 +356,7 @@ resubmit:
+ dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
+ }
+
+-static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void cyberjack_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cyberjack_private *priv = usb_get_serial_port_data(port);
+@@ -406,7 +406,7 @@ static void cyberjack_read_bulk_callback
+ }
+ }
+
+-static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void cyberjack_write_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cyberjack_private *priv = usb_get_serial_port_data(port);
+diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
+index ee70fdd..f2e89a0 100644
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -129,6 +129,9 @@ struct cypress_private {
+ int cmd_ctrl; /* always set this to 1 before issuing a command */
+ struct cypress_buf *buf; /* write buffer */
+ int write_urb_in_use; /* write urb in use indicator */
++ int write_urb_interval; /* interval to use for write urb */
++ int read_urb_interval; /* interval to use for read urb */
++ int comm_is_ok; /* true if communication is (still) ok */
+ int termios_initialized;
+ __u8 line_control; /* holds dtr / rts value */
+ __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
+@@ -168,8 +171,9 @@ static int cypress_tiocmset (struct us
+ static int cypress_chars_in_buffer (struct usb_serial_port *port);
+ static void cypress_throttle (struct usb_serial_port *port);
+ static void cypress_unthrottle (struct usb_serial_port *port);
+-static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs);
+-static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs);
++static void cypress_set_dead (struct usb_serial_port *port);
++static void cypress_read_int_callback (struct urb *urb);
++static void cypress_write_int_callback (struct urb *urb);
+ /* baud helper functions */
+ static int mask_to_rate (unsigned mask);
+ static unsigned rate_to_mask (int rate);
+@@ -288,6 +292,9 @@ static int cypress_serial_control (struc
+
+ priv = usb_get_serial_port_data(port);
+
++ if (!priv->comm_is_ok)
++ return -ENODEV;
++
+ switch(cypress_request_type) {
+ case CYPRESS_SET_CONFIG:
+
+@@ -365,13 +372,12 @@ static int cypress_serial_control (struc
+ if (tries++ >= 3)
+ break;
+
+- if (retval == EPIPE)
+- usb_clear_halt(port->serial->dev, 0x00);
+- } while (retval != 8 && retval != ENODEV);
++ } while (retval != 8 && retval != -ENODEV);
+
+- if (retval != 8)
++ if (retval != 8) {
+ err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
+- else {
++ cypress_set_dead(port);
++ } else {
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->baud_rate = new_baudrate;
+ priv->cbr_mask = baud_mask;
+@@ -392,12 +398,11 @@ static int cypress_serial_control (struc
+ if (tries++ >= 3)
+ break;
+
+- if (retval == EPIPE)
+- usb_clear_halt(port->serial->dev, 0x00);
+- } while (retval != 5 && retval != ENODEV);
++ } while (retval != 5 && retval != -ENODEV);
+
+ if (retval != 5) {
+ err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval);
++ cypress_set_dead(port);
+ return retval;
+ } else {
+ spin_lock_irqsave(&priv->lock, flags);
+@@ -419,6 +424,24 @@ static int cypress_serial_control (struc
+ } /* cypress_serial_control */
+
+
++static void cypress_set_dead(struct usb_serial_port *port)
++{
++ struct cypress_private *priv = usb_get_serial_port_data(port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (!priv->comm_is_ok) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return;
++ }
++ priv->comm_is_ok = 0;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ err("cypress_m8 suspending failing port %d - interval might be too short",
++ port->number);
++}
++
++
+ /* given a baud mask, it will return integer baud on success */
+ static int mask_to_rate (unsigned mask)
+ {
+@@ -472,13 +495,15 @@ static unsigned rate_to_mask (int rate)
+ static int generic_startup (struct usb_serial *serial)
+ {
+ struct cypress_private *priv;
++ struct usb_serial_port *port = serial->port[0];
+
+- dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
++ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
++ priv->comm_is_ok = !0;
+ spin_lock_init(&priv->lock);
+ priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
+ if (priv->buf == NULL) {
+@@ -489,13 +514,24 @@ static int generic_startup (struct usb_s
+
+ usb_reset_configuration (serial->dev);
+
+- interval = 1;
+ priv->cmd_ctrl = 0;
+ priv->line_control = 0;
+ priv->termios_initialized = 0;
+ priv->rx_flags = 0;
+ priv->cbr_mask = B300;
+- usb_set_serial_port_data(serial->port[0], priv);
++ if (interval > 0) {
++ priv->write_urb_interval = interval;
++ priv->read_urb_interval = interval;
++ dbg("%s - port %d read & write intervals forced to %d",
++ __FUNCTION__,port->number,interval);
++ } else {
++ priv->write_urb_interval = port->interrupt_out_urb->interval;
++ priv->read_urb_interval = port->interrupt_in_urb->interval;
++ dbg("%s - port %d intervals: read=%d write=%d",
++ __FUNCTION__,port->number,
++ priv->read_urb_interval,priv->write_urb_interval);
++ }
++ usb_set_serial_port_data(port, priv);
+
+ return 0;
+ }
+@@ -585,6 +621,9 @@ static int cypress_open (struct usb_seri
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
++ if (!priv->comm_is_ok)
++ return -EIO;
++
+ /* clear halts before open */
+ usb_clear_halt(serial->dev, 0x81);
+ usb_clear_halt(serial->dev, 0x02);
+@@ -624,11 +663,12 @@ static int cypress_open (struct usb_seri
+ usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
+ usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
+ port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
+- cypress_read_int_callback, port, interval);
++ cypress_read_int_callback, port, priv->read_urb_interval);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+
+ if (result){
+ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
++ cypress_set_dead(port);
+ }
+
+ return result;
+@@ -733,6 +773,9 @@ static void cypress_send(struct usb_seri
+ struct cypress_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
++ if (!priv->comm_is_ok)
++ return;
++
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
+
+@@ -806,14 +849,16 @@ send:
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
+ port->interrupt_out_urb->transfer_buffer);
+
+- port->interrupt_out_urb->transfer_buffer_length = actual_size;
+- port->interrupt_out_urb->dev = port->serial->dev;
+- port->interrupt_out_urb->interval = interval;
++ usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
++ usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
++ port->interrupt_out_buffer, port->interrupt_out_size,
++ cypress_write_int_callback, port, priv->write_urb_interval);
+ result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
+ if (result) {
+ dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
+ result);
+ priv->write_urb_in_use = 0;
++ cypress_set_dead(port);
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+@@ -1214,18 +1259,23 @@ static void cypress_unthrottle (struct u
+ priv->rx_flags = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
++ if (!priv->comm_is_ok)
++ return;
++
+ if (actually_throttled) {
+ port->interrupt_in_urb->dev = port->serial->dev;
+
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+- if (result)
++ if (result) {
+ dev_err(&port->dev, "%s - failed submitting read urb, "
+ "error %d\n", __FUNCTION__, result);
++ cypress_set_dead(port);
++ }
+ }
+ }
+
+
+-static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
++static void cypress_read_int_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cypress_private *priv = usb_get_serial_port_data(port);
+@@ -1240,9 +1290,22 @@ static void cypress_read_int_callback(st
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+- if (urb->status) {
+- dbg("%s - nonzero read status received: %d", __FUNCTION__,
+- urb->status);
++ switch (urb->status) {
++ case 0: /* success */
++ break;
++ case -ECONNRESET:
++ case -ENOENT:
++ case -ESHUTDOWN:
++ /* precursor to disconnect so just go away */
++ return;
++ case -EPIPE:
++ usb_clear_halt(port->serial->dev,0x81);
++ break;
++ default:
++ /* something ugly is going on... */
++ dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
++ __FUNCTION__,urb->status);
++ cypress_set_dead(port);
+ return;
+ }
+
+@@ -1343,25 +1406,27 @@ continue_read:
+
+ /* Continue trying to always read... unless the port has closed. */
+
+- if (port->open_count > 0) {
++ if (port->open_count > 0 && priv->comm_is_ok) {
+ usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
+ usb_rcvintpipe(port->serial->dev,
+ port->interrupt_in_endpointAddress),
+ port->interrupt_in_urb->transfer_buffer,
+ port->interrupt_in_urb->transfer_buffer_length,
+- cypress_read_int_callback, port, interval);
++ cypress_read_int_callback, port, priv->read_urb_interval);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+- if (result)
++ if (result) {
+ dev_err(&urb->dev->dev, "%s - failed resubmitting "
+ "read urb, error %d\n", __FUNCTION__,
+ result);
++ cypress_set_dead(port);
++ }
+ }
+
+ return;
+ } /* cypress_read_int_callback */
+
+
+-static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
++static void cypress_write_int_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cypress_private *priv = usb_get_serial_port_data(port);
+@@ -1380,20 +1445,26 @@ static void cypress_write_int_callback(s
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ priv->write_urb_in_use = 0;
+ return;
+- case -EPIPE: /* no break needed */
++ case -EPIPE: /* no break needed; clear halt and resubmit */
++ if (!priv->comm_is_ok)
++ break;
+ usb_clear_halt(port->serial->dev, 0x02);
+- default:
+ /* error in the urb, so we have to resubmit it */
+- dbg("%s - Overflow in write", __FUNCTION__);
+ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ port->interrupt_out_urb->transfer_buffer_length = 1;
+ port->interrupt_out_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
+- if (result)
+- dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
+- __FUNCTION__, result);
+- else
++ if (!result)
+ return;
++ dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
++ __FUNCTION__, result);
++ cypress_set_dead(port);
++ break;
++ default:
++ dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
++ __FUNCTION__,urb->status);
++ cypress_set_dead(port);
++ break;
+ }
+
+ priv->write_urb_in_use = 0;
+diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
+index 9b22518..bdb5810 100644
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -456,7 +456,7 @@ static int digi_tiocmget( struct usb_ser
+ static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear );
+ static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count );
+-static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs );
++static void digi_write_bulk_callback( struct urb *urb );
+ static int digi_write_room( struct usb_serial_port *port );
+ static int digi_chars_in_buffer( struct usb_serial_port *port );
+ static int digi_open( struct usb_serial_port *port, struct file *filp );
+@@ -464,7 +464,7 @@ static void digi_close( struct usb_seria
+ static int digi_startup_device( struct usb_serial *serial );
+ static int digi_startup( struct usb_serial *serial );
+ static void digi_shutdown( struct usb_serial *serial );
+-static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs );
++static void digi_read_bulk_callback( struct urb *urb );
+ static int digi_read_inb_callback( struct urb *urb );
+ static int digi_read_oob_callback( struct urb *urb );
+
+@@ -1336,7 +1336,7 @@ dbg( "digi_write: returning %d", ret );
+ }
+
+
+-static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs )
++static void digi_write_bulk_callback( struct urb *urb )
+ {
+
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+@@ -1754,7 +1754,7 @@ dbg( "digi_shutdown: TOP, in_interrupt()
+ }
+
+
+-static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs )
++static void digi_read_bulk_callback( struct urb *urb )
+ {
+
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
+index daafe40..4ce10a8 100644
+--- a/drivers/usb/serial/empeg.c
++++ b/drivers/usb/serial/empeg.c
+@@ -93,8 +93,8 @@ static int empeg_ioctl (struct usb_se
+ unsigned int cmd,
+ unsigned long arg);
+ static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+-static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void empeg_write_bulk_callback (struct urb *urb);
++static void empeg_read_bulk_callback (struct urb *urb);
+
+ static struct usb_device_id id_table [] = {
+ { USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
+@@ -323,7 +323,7 @@ static int empeg_chars_in_buffer (struct
+ }
+
+
+-static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void empeg_write_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+@@ -338,7 +338,7 @@ static void empeg_write_bulk_callback (s
+ }
+
+
+-static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void empeg_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct tty_struct *tty;
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index c6115aa..bd76b4c 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -1,16 +1,16 @@
+ /*
+ * USB FTDI SIO driver
+ *
+- * Copyright (C) 1999 - 2001
+- * Greg Kroah-Hartman (greg at kroah.com)
++ * Copyright (C) 1999 - 2001
++ * Greg Kroah-Hartman (greg at kroah.com)
+ * Bill Ryder (bryder at sgi.com)
+ * Copyright (C) 2002
+ * Kuba Ober (kuba at mareimbrium.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
+- * 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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+@@ -32,7 +32,7 @@
+ * Changed full name of USB-UIRT device to avoid "/" character.
+ * Added FTDI's alternate PID (0x6006) for FT232/245 devices.
+ * Added PID for "ELV USB Module UO100" from Stefan Frings.
+- *
++ *
+ * (21/Oct/2003) Ian Abbott
+ * Renamed some VID/PID macros for Matrix Orbital and Perle Systems
+ * devices. Removed Matrix Orbital and Perle Systems devices from the
+@@ -69,7 +69,7 @@
+ * does not incure any measurable overhead. This also relies on the fact
+ * that we have proper reference counting logic for urbs. I nicked this
+ * from Greg KH's Visor driver.
+- *
++ *
+ * (23/Jun/2003) Ian Abbott
+ * Reduced flip buffer pushes and corrected a data length test in
+ * ftdi_read_bulk_callback.
+@@ -77,7 +77,7 @@
+ *
+ * (21/Jun/2003) Erik Nygren
+ * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
+- * See <http://www.home-electro.com/tira1.htm>. Only operates properly
++ * See <http://www.home-electro.com/tira1.htm>. Only operates properly
+ * at 100000 and RTS-CTS, so set custom divisor mode on startup.
+ * Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
+ *
+@@ -137,17 +137,17 @@
+ * (17/Feb/2003) Bill Ryder
+ * Added write urb buffer pool on a per device basis
+ * Added more checking for open file on callbacks (fixed OOPS)
+- * Added CrystalFontz 632 and 634 PIDs
++ * Added CrystalFontz 632 and 634 PIDs
+ * (thanx to CrystalFontz for the sample devices - they flushed out
+ * some driver bugs)
+ * Minor debugging message changes
+ * Added throttle, unthrottle and chars_in_buffer functions
+ * Fixed FTDI_SIO (the original device) bug
+ * Fixed some shutdown handling
+- *
+- *
+- *
+- *
++ *
++ *
++ *
++ *
+ * (07/Jun/2002) Kuba Ober
+ * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+ * function. It was getting too complex.
+@@ -158,7 +158,7 @@
+ *
+ * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
+ * Not tested by me but it doesn't break anything I use.
+- *
++ *
+ * (04/Jan/2002) Kuba Ober
+ * Implemented 38400 baudrate kludge, where it can be substituted with other
+ * values. That's the only way to set custom baudrates.
+@@ -179,7 +179,7 @@
+ * (the previous version caused panics)
+ * Removed port iteration code since the device only has one I/O port and it
+ * was wrong anyway.
+- *
++ *
+ * (31/May/2001) gkh
+ * Switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
+@@ -188,16 +188,16 @@
+ * Cleaned up comments for 8U232
+ * Added parity, framing and overrun error handling
+ * Added receive break handling.
+- *
++ *
+ * (04/08/2001) gb
+ * Identify version on module load.
+- *
++ *
+ * (18/March/2001) Bill Ryder
+ * (Not released)
+ * Added send break handling. (requires kernel patch too)
+ * Fixed 8U232AM hardware RTS/CTS etc status reporting.
+ * Added flipbuf fix copied from generic device
+- *
++ *
+ * (12/3/2000) Bill Ryder
+ * Added support for 8U232AM device.
+ * Moved PID and VIDs into header file only.
+@@ -211,14 +211,14 @@
+ * Cleaned up comments. Removed multiple PID/VID definitions.
+ * Factorised cts/dtr code
+ * Made use of __FUNCTION__ in dbg's
+- *
++ *
+ * (11/01/2000) Adam J. Richter
+ * usb_device_id table support
+- *
++ *
+ * (10/05/2000) gkh
+ * Fixed bug with urb->dev not being set properly, now that the usb
+ * core needs it.
+- *
++ *
+ * (09/11/2000) gkh
+ * Removed DEBUG #ifdefs with call to usb_serial_debug_data
+ *
+@@ -226,11 +226,11 @@
+ * Added module_init and module_exit functions to handle the fact that this
+ * driver is a loadable module now.
+ *
+- * (04/04/2000) Bill Ryder
++ * (04/04/2000) Bill Ryder
+ * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
+ * handled elsewhere in the tty io driver chain).
+ *
+- * (03/30/2000) Bill Ryder
++ * (03/30/2000) Bill Ryder
+ * Implemented lots of ioctls
+ * Fixed a race condition in write
+ * Changed some dbg's to errs
+@@ -344,6 +344,7 @@ static struct usb_device_id id_table_com
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
++ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
+@@ -443,13 +444,13 @@ static struct usb_device_id id_table_com
+ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
+ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
+ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
+- { 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, 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) },
+ { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
+ { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
+@@ -507,6 +508,9 @@ static struct usb_device_id id_table_com
+ { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
+ { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
+ { }, /* Optional parameter entry */
+ { } /* Terminating entry */
+ };
+@@ -518,7 +522,7 @@ static struct usb_driver ftdi_driver = {
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table_combined,
+- .no_dynamic_id = 1,
++ .no_dynamic_id = 1,
+ };
+
+ static const char *ftdi_chip_name[] = {
+@@ -544,13 +548,13 @@ struct ftdi_private {
+ int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
+ __u16 last_set_data_urb_value ;
+ /* the last data state set - needed for doing a break */
+- int write_offset; /* This is the offset in the usb data block to write the serial data -
++ int write_offset; /* This is the offset in the usb data block to write the serial data -
+ * it is different between devices
+ */
+ int flags; /* some ASYNC_xxxx flags are supported */
+ unsigned long last_dtr_rts; /* saved modem control outputs */
+ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+- char prev_status, diff_status; /* Used for TIOCMIWAIT */
++ char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ __u8 rx_flags; /* receive state flags (throttling) */
+ spinlock_t rx_lock; /* spinlock for receive state */
+ struct work_struct rx_work;
+@@ -585,8 +589,8 @@ static void ftdi_close (struct usb_ser
+ static int ftdi_write (struct usb_serial_port *port, const unsigned char *buf, int count);
+ static int ftdi_write_room (struct usb_serial_port *port);
+ static int ftdi_chars_in_buffer (struct usb_serial_port *port);
+-static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void ftdi_write_bulk_callback (struct urb *urb);
++static void ftdi_read_bulk_callback (struct urb *urb);
+ static void ftdi_process_read (void *param);
+ static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
+ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file);
+@@ -717,7 +721,7 @@ static int update_mctrl(struct usb_seria
+ urb_value |= FTDI_SIO_SET_RTS_HIGH;
+ rv = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
++ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value, priv->interface,
+ buf, 0, WDR_TIMEOUT);
+@@ -764,7 +768,7 @@ static int change_speed(struct usb_seria
+ if (priv->interface) { /* FT2232C */
+ urb_index = (__u16)((urb_index << 8) | priv->interface);
+ }
+-
++
+ rv = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+@@ -823,7 +827,7 @@ static __u32 get_ftdi_divisor(struct usb
+
+ /* 3. Convert baudrate to device-specific divisor */
+
+- if (!baud) baud = 9600;
++ if (!baud) baud = 9600;
+ switch(priv->chip_type) {
+ case SIO: /* SIO chip */
+ switch(baud) {
+@@ -839,7 +843,7 @@ static __u32 get_ftdi_divisor(struct usb
+ case 115200: div_value = ftdi_sio_b115200; break;
+ } /* baud */
+ if (div_value == 0) {
+- dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
++ dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
+ div_value = ftdi_sio_b9600;
+ div_okay = 0;
+ }
+@@ -921,7 +925,7 @@ static int set_serial_info(struct usb_se
+ /* Make the changes - these are privileged changes! */
+
+ priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
+- (new_serial.flags & ASYNC_FLAGS));
++ (new_serial.flags & ASYNC_FLAGS));
+ priv->custom_divisor = new_serial.custom_divisor;
+
+ port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+@@ -946,7 +950,7 @@ check_and_exit:
+ (old_priv.custom_divisor != priv->custom_divisor))) {
+ change_speed(port);
+ }
+-
++
+ return (0);
+
+ } /* set_serial_info */
+@@ -1018,18 +1022,18 @@ static ssize_t show_latency_timer(struct
+ struct usb_device *udev;
+ unsigned short latency = 0;
+ int rv = 0;
+-
++
+ udev = to_usb_device(dev);
+-
++
+ dbg("%s",__FUNCTION__);
+-
++
+ rv = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
+ FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
+- 0, priv->interface,
++ 0, priv->interface,
+ (char*) &latency, 1, WDR_TIMEOUT);
+-
++
+ if (rv < 0) {
+ dev_err(dev, "Unable to read latency timer: %i", rv);
+ return -EIO;
+@@ -1047,23 +1051,23 @@ static ssize_t store_latency_timer(struc
+ char buf[1];
+ int v = simple_strtoul(valbuf, NULL, 10);
+ int rv = 0;
+-
++
+ udev = to_usb_device(dev);
+-
++
+ dbg("%s: setting latency timer = %i", __FUNCTION__, v);
+-
++
+ rv = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
+ FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+- v, priv->interface,
++ v, priv->interface,
+ buf, 0, WDR_TIMEOUT);
+-
++
+ if (rv < 0) {
+ dev_err(dev, "Unable to write latency timer: %i", rv);
+ return -EIO;
+ }
+-
++
+ return count;
+ }
+
+@@ -1078,48 +1082,52 @@ static ssize_t store_event_char(struct d
+ char buf[1];
+ int v = simple_strtoul(valbuf, NULL, 10);
+ int rv = 0;
+-
++
+ udev = to_usb_device(dev);
+-
++
+ dbg("%s: setting event char = %i", __FUNCTION__, v);
+-
++
+ rv = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ FTDI_SIO_SET_EVENT_CHAR_REQUEST,
+ FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
+- v, priv->interface,
++ v, priv->interface,
+ buf, 0, WDR_TIMEOUT);
+-
++
+ if (rv < 0) {
+ dbg("Unable to write event character: %i", rv);
+ return -EIO;
+ }
+-
++
+ return count;
+ }
+
+ static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);
+ static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
+
+-static void create_sysfs_attrs(struct usb_serial *serial)
+-{
++static int create_sysfs_attrs(struct usb_serial *serial)
++{
+ struct ftdi_private *priv;
+ struct usb_device *udev;
++ int retval = 0;
+
+ dbg("%s",__FUNCTION__);
+-
++
+ priv = usb_get_serial_port_data(serial->port[0]);
+ udev = serial->dev;
+-
++
+ /* XXX I've no idea if the original SIO supports the event_char
+ * sysfs parameter, so I'm playing it safe. */
+ if (priv->chip_type != SIO) {
+ dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
+- device_create_file(&udev->dev, &dev_attr_event_char);
+- if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+- device_create_file(&udev->dev, &dev_attr_latency_timer);
++ retval = device_create_file(&udev->dev, &dev_attr_event_char);
++ if ((!retval) &&
++ (priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
++ retval = device_create_file(&udev->dev,
++ &dev_attr_latency_timer);
+ }
+ }
++ return retval;
+ }
+
+ static void remove_sysfs_attrs(struct usb_serial *serial)
+@@ -1127,11 +1135,11 @@ static void remove_sysfs_attrs(struct us
+ struct ftdi_private *priv;
+ struct usb_device *udev;
+
+- dbg("%s",__FUNCTION__);
++ dbg("%s",__FUNCTION__);
+
+ priv = usb_get_serial_port_data(serial->port[0]);
+ udev = serial->dev;
+-
++
+ /* XXX see create_sysfs_attrs */
+ if (priv->chip_type != SIO) {
+ device_remove_file(&udev->dev, &dev_attr_event_char);
+@@ -1139,7 +1147,7 @@ static void remove_sysfs_attrs(struct us
+ device_remove_file(&udev->dev, &dev_attr_latency_timer);
+ }
+ }
+-
++
+ }
+
+ /*
+@@ -1162,7 +1170,8 @@ static int ftdi_sio_attach (struct usb_s
+ struct usb_serial_port *port = serial->port[0];
+ struct ftdi_private *priv;
+ struct ftdi_sio_quirk *quirk;
+-
++ int retval;
++
+ dbg("%s",__FUNCTION__);
+
+ priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+@@ -1203,15 +1212,18 @@ static int ftdi_sio_attach (struct usb_s
+ usb_set_serial_port_data(serial->port[0], priv);
+
+ ftdi_determine_type (serial->port[0]);
+- create_sysfs_attrs(serial);
++ retval = create_sysfs_attrs(serial);
++ if (retval)
++ dev_err(&serial->dev->dev, "Error creating sysfs files, "
++ "continuing\n");
+
+ /* Check for device requiring special set up. */
+ quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
+ if (quirk && quirk->setup) {
+ quirk->setup(serial);
+ }
+-
+- return (0);
++
++ return 0;
+ } /* ftdi_sio_attach */
+
+
+@@ -1246,7 +1258,7 @@ static void ftdi_HE_TIRA1_setup (struct
+ } /* ftdi_HE_TIRA1_setup */
+
+
+-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
++/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
+ * it is called when the usb device is disconnected
+ *
+ * usbserial:usb_serial_disconnect
+@@ -1257,16 +1269,16 @@ static void ftdi_HE_TIRA1_setup (struct
+
+ static void ftdi_shutdown (struct usb_serial *serial)
+ { /* ftdi_shutdown */
+-
++
+ struct usb_serial_port *port = serial->port[0];
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s", __FUNCTION__);
+
+ remove_sysfs_attrs(serial);
+-
+- /* all open ports are closed at this point
+- * (by usbserial.c:__serial_close, which calls ftdi_close)
++
++ /* all open ports are closed at this point
++ * (by usbserial.c:__serial_close, which calls ftdi_close)
+ */
+
+ if (priv) {
+@@ -1281,7 +1293,7 @@ static int ftdi_open (struct usb_serial
+ struct usb_device *dev = port->serial->dev;
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+-
++
+ int result = 0;
+ char buf[1]; /* Needed for the usb_control_msg I think */
+
+@@ -1300,8 +1312,8 @@ static int ftdi_open (struct usb_serial
+ /* No error checking for this (will get errors later anyway) */
+ /* See ftdi_sio.h for description of what is reset */
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+- FTDI_SIO_RESET_SIO,
++ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
++ FTDI_SIO_RESET_SIO,
+ priv->interface, buf, 0, WDR_TIMEOUT);
+
+ /* Termios defaults are set by usb_serial_init. We don't change
+@@ -1338,12 +1350,12 @@ static int ftdi_open (struct usb_serial
+
+
+
+-/*
++/*
+ * usbserial:__serial_close only calls ftdi_close if the point is open
+ *
+ * This only gets called when it is the last close
+- *
+- *
++ *
++ *
+ */
+
+ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
+@@ -1356,14 +1368,14 @@ static void ftdi_close (struct usb_seria
+
+ if (c_cflag & HUPCL){
+ /* Disable flow control */
+- if (usb_control_msg(port->serial->dev,
++ if (usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, priv->interface, buf, 0,
+ WDR_TIMEOUT) < 0) {
+ err("error from flowcontrol urb");
+- }
++ }
+
+ /* drop RTS and DTR */
+ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+@@ -1372,14 +1384,14 @@ static void ftdi_close (struct usb_seria
+ /* cancel any scheduled reading */
+ cancel_delayed_work(&priv->rx_work);
+ flush_scheduled_work();
+-
++
+ /* shutdown our bulk read */
+ if (port->read_urb)
+ usb_kill_urb(port->read_urb);
+ } /* ftdi_close */
+
+
+-
++
+ /* The SIO requires the first byte to have:
+ * B0 1
+ * B1 0
+@@ -1411,7 +1423,7 @@ static int ftdi_write (struct usb_serial
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+-
++
+ data_offset = priv->write_offset;
+ dbg("data_offset set to %d",data_offset);
+
+@@ -1450,7 +1462,7 @@ static int ftdi_write (struct usb_serial
+ user_pktsz = todo;
+ }
+ /* Write the control byte at the front of the packet*/
+- *first_byte = 1 | ((user_pktsz) << 2);
++ *first_byte = 1 | ((user_pktsz) << 2);
+ /* Copy data for packet */
+ memcpy (first_byte + data_offset,
+ current_position, user_pktsz);
+@@ -1467,7 +1479,7 @@ static int ftdi_write (struct usb_serial
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
+
+ /* fill the buffer and send it */
+- usb_fill_bulk_urb(urb, port->serial->dev,
++ usb_fill_bulk_urb(urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
+ buffer, transfer_size,
+ ftdi_write_bulk_callback, port);
+@@ -1496,7 +1508,7 @@ static int ftdi_write (struct usb_serial
+
+ /* This function may get called when the device is closed */
+
+-static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void ftdi_write_bulk_callback (struct urb *urb)
+ {
+ unsigned long flags;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+@@ -1508,7 +1520,7 @@ static void ftdi_write_bulk_callback (st
+ kfree (urb->transfer_buffer);
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+-
++
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+@@ -1579,7 +1591,7 @@ static int ftdi_chars_in_buffer (struct
+
+
+
+-static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void ftdi_read_bulk_callback (struct urb *urb)
+ { /* ftdi_read_bulk_callback */
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct tty_struct *tty;
+@@ -1639,7 +1651,7 @@ static void ftdi_process_read (void *par
+ struct tty_struct *tty;
+ struct ftdi_private *priv;
+ char error_flag;
+- unsigned char *data;
++ unsigned char *data;
+
+ int i;
+ int result;
+@@ -1747,7 +1759,7 @@ static void ftdi_process_read (void *par
+ }
+ if (length > 0) {
+ for (i = 2; i < length+2; i++) {
+- /* Note that the error flag is duplicated for
++ /* Note that the error flag is duplicated for
+ every character received since we don't know
+ which character it applied to */
+ tty_insert_flip_char(tty, data[packet_offset+i], error_flag);
+@@ -1761,7 +1773,7 @@ static void ftdi_process_read (void *par
+ This doesn't work well since the application receives a never
+ ending stream of bad data - even though new data hasn't been sent.
+ Therefore I (bill) have taken this out.
+- However - this might make sense for framing errors and so on
++ However - this might make sense for framing errors and so on
+ so I am leaving the code in for now.
+ */
+ else {
+@@ -1815,7 +1827,7 @@ static void ftdi_process_read (void *par
+ /* if the port is closed stop trying to read */
+ if (port->open_count > 0){
+ /* Continue trying to always read */
+- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ftdi_read_bulk_callback, port);
+@@ -1832,9 +1844,9 @@ static void ftdi_process_read (void *par
+ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
+ {
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+- __u16 urb_value = 0;
++ __u16 urb_value = 0;
+ char buf[1];
+-
++
+ /* break_state = -1 to turn on break, and 0 to turn off break */
+ /* see drivers/char/tty_io.c to see it used */
+ /* last_set_data_urb_value NEVER has the break bit set in it */
+@@ -1842,20 +1854,20 @@ static void ftdi_break_ctl( struct usb_s
+ if (break_state) {
+ urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
+ } else {
+- urb_value = priv->last_set_data_urb_value;
++ urb_value = priv->last_set_data_urb_value;
+ }
+
+-
++
+ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
+- FTDI_SIO_SET_DATA_REQUEST,
++ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ urb_value , priv->interface,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
+- }
++ }
+
+ dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
+-
++
+ }
+
+
+@@ -1871,12 +1883,12 @@ static void ftdi_set_termios (struct usb
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ __u16 urb_value; /* will hold the new flags */
+ char buf[1]; /* Perhaps I should dynamically alloc this? */
+-
++
+ // Added for xon/xoff support
+ unsigned int iflag = port->tty->termios->c_iflag;
+ unsigned char vstop;
+ unsigned char vstart;
+-
++
+ dbg("%s", __FUNCTION__);
+
+ /* Force baud rate if this device requires it, unless it is set to B0. */
+@@ -1894,20 +1906,20 @@ static void ftdi_set_termios (struct usb
+
+ cflag = port->tty->termios->c_cflag;
+
+- /* FIXME -For this cut I don't care if the line is really changing or
+- not - so just do the change regardless - should be able to
++ /* FIXME -For this cut I don't care if the line is really changing or
++ not - so just do the change regardless - should be able to
+ compare old_termios and tty->termios */
+- /* NOTE These routines can get interrupted by
+- ftdi_sio_read_bulk_callback - need to examine what this
++ /* NOTE These routines can get interrupted by
++ ftdi_sio_read_bulk_callback - need to examine what this
+ means - don't see any problems yet */
+-
++
+ /* Set number of data bits, parity, stop bits */
+-
++
+ urb_value = 0;
+ urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+ FTDI_SIO_SET_DATA_STOP_BITS_1);
+- urb_value |= (cflag & PARENB ?
+- (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
++ urb_value |= (cflag & PARENB ?
++ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ FTDI_SIO_SET_DATA_PARITY_EVEN) :
+ FTDI_SIO_SET_DATA_PARITY_NONE);
+ if (cflag & CSIZE) {
+@@ -1924,25 +1936,25 @@ static void ftdi_set_termios (struct usb
+ /* This is needed by the break command since it uses the same command - but is
+ * or'ed with this value */
+ priv->last_set_data_urb_value = urb_value;
+-
++
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+- FTDI_SIO_SET_DATA_REQUEST,
++ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ urb_value , priv->interface,
+ buf, 0, WDR_SHORT_TIMEOUT) < 0) {
+ err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
+- }
++ }
+
+ /* Now do the baudrate */
+ if ((cflag & CBAUD) == B0 ) {
+ /* Disable flow control */
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
++ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+- 0, priv->interface,
++ 0, priv->interface,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("%s error from disable flowcontrol urb", __FUNCTION__);
+- }
++ }
+ /* Drop RTS and DTR */
+ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ } else {
+@@ -1960,16 +1972,16 @@ static void ftdi_set_termios (struct usb
+ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+ if (cflag & CRTSCTS) {
+ dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
+- if (usb_control_msg(dev,
++ if (usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
++ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("urb failed to set to rts/cts flow control");
+- }
+-
+- } else {
++ }
++
++ } else {
+ /*
+ * Xon/Xoff code
+ *
+@@ -1999,16 +2011,16 @@ static void ftdi_set_termios (struct usb
+ /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
+ /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
+ dbg("%s Turning off hardware flow control", __FUNCTION__);
+- if (usb_control_msg(dev,
++ if (usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
++ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+- 0, priv->interface,
++ 0, priv->interface,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("urb failed to clear flow control");
+- }
++ }
+ }
+-
++
+ }
+ return;
+ } /* ftdi_termios */
+@@ -2024,11 +2036,11 @@ static int ftdi_tiocmget (struct usb_ser
+ switch (priv->chip_type) {
+ case SIO:
+ /* Request the status from the device */
+- if ((ret = usb_control_msg(port->serial->dev,
++ if ((ret = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
++ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+- 0, 0,
++ 0, 0,
+ buf, 1, WDR_TIMEOUT)) < 0 ) {
+ err("%s Could not get modem status of device - err: %d", __FUNCTION__,
+ ret);
+@@ -2040,11 +2052,11 @@ static int ftdi_tiocmget (struct usb_ser
+ case FT2232C:
+ /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
+ format as the data returned from the in point */
+- if ((ret = usb_control_msg(port->serial->dev,
++ if ((ret = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
++ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+- 0, priv->interface,
++ 0, priv->interface,
+ buf, 2, WDR_TIMEOUT)) < 0 ) {
+ err("%s Could not get modem status of device - err: %d", __FUNCTION__,
+ ret);
+@@ -2055,12 +2067,12 @@ static int ftdi_tiocmget (struct usb_ser
+ return -EFAULT;
+ break;
+ }
+-
++
+ return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+ (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
+ (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
+ (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
+- priv->last_dtr_rts;
++ priv->last_dtr_rts;
+ }
+
+ static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
+@@ -2126,11 +2138,11 @@ static int ftdi_ioctl (struct usb_serial
+ break;
+ default:
+ break;
+-
++
+ }
+
+
+- /* This is not necessarily an error - turns out the higher layers will do
++ /* This is not necessarily an error - turns out the higher layers will do
+ * some ioctls itself (see comment above)
+ */
+ dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
+@@ -2187,7 +2199,7 @@ static int __init ftdi_init (void)
+ if (retval)
+ goto failed_sio_register;
+ retval = usb_register(&ftdi_driver);
+- if (retval)
++ if (retval)
+ goto failed_usb_register;
+
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
+index 7729999..f0edb87 100644
+--- a/drivers/usb/serial/ftdi_sio.h
++++ b/drivers/usb/serial/ftdi_sio.h
+@@ -111,6 +111,7 @@
+ #define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
+ #define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
+ #define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
++#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
+ #define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
+ #define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
+ #define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
+@@ -472,6 +473,15 @@
+ */
+ #define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
+
++/*
++ * Tactrix OpenPort (ECU) devices.
++ * OpenPort 1.3M submitted by Donour Sizemore.
++ * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
++ */
++#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
++#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
++#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
++
+ /* Commands */
+ #define FTDI_SIO_RESET 0 /* Reset the port */
+ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
+diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
+index 7278526..4543152 100644
+--- a/drivers/usb/serial/garmin_gps.c
++++ b/drivers/usb/serial/garmin_gps.c
+@@ -1,7 +1,7 @@
+ /*
+ * Garmin GPS driver
+ *
+- * Copyright (C) 2004 Hermann Kneissel herkne at users.sourceforge.net
++ * Copyright (C) 2006 Hermann Kneissel herkne at users.sourceforge.net
+ *
+ * The latest version of the driver can be found at
+ * http://sourceforge.net/projects/garmin-gps/
+@@ -37,6 +37,8 @@
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
+
++#include <linux/version.h>
++
+ /* the mode to be set when the port ist opened */
+ static int initial_mode = 1;
+
+@@ -50,7 +52,7 @@ static int debug = 0;
+ */
+
+ #define VERSION_MAJOR 0
+-#define VERSION_MINOR 23
++#define VERSION_MINOR 28
+
+ #define _STR(s) #s
+ #define _DRIVER_VERSION(a,b) "v" _STR(a) "." _STR(b)
+@@ -164,7 +166,8 @@ struct garmin_data {
+ #define FLAGS_SESSION_REPLY1_SEEN 0x0080
+ #define FLAGS_SESSION_REPLY2_SEEN 0x0040
+ #define FLAGS_BULK_IN_ACTIVE 0x0020
+-#define FLAGS_THROTTLED 0x0010
++#define FLAGS_BULK_IN_RESTART 0x0010
++#define FLAGS_THROTTLED 0x0008
+ #define CLEAR_HALT_REQUIRED 0x0001
+
+ #define FLAGS_QUEUING 0x0100
+@@ -224,7 +227,7 @@ static struct usb_driver garmin_driver =
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+- .no_dynamic_id = 1,
++ .no_dynamic_id = 1,
+ };
+
+
+@@ -270,7 +273,7 @@ static inline int isAbortTrfCmnd(const u
+
+
+ static void send_to_tty(struct usb_serial_port *port,
+- char *data, unsigned int actual_length)
++ char *data, unsigned int actual_length)
+ {
+ struct tty_struct *tty = port->tty;
+
+@@ -294,15 +297,15 @@ static void send_to_tty(struct usb_seria
+ * queue a received (usb-)packet for later processing
+ */
+ static int pkt_add(struct garmin_data * garmin_data_p,
+- unsigned char *data, unsigned int data_length)
++ unsigned char *data, unsigned int data_length)
+ {
++ int state = 0;
+ int result = 0;
+ unsigned long flags;
+ struct garmin_packet *pkt;
+
+ /* process only packets containg data ... */
+ if (data_length) {
+- garmin_data_p->flags |= FLAGS_QUEUING;
+ pkt = kmalloc(sizeof(struct garmin_packet)+data_length,
+ GFP_ATOMIC);
+ if (pkt == NULL) {
+@@ -313,14 +316,16 @@ static int pkt_add(struct garmin_data *
+ memcpy(pkt->data, data, data_length);
+
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
++ garmin_data_p->flags |= FLAGS_QUEUING;
+ result = list_empty(&garmin_data_p->pktlist);
+ pkt->seq = garmin_data_p->seq_counter++;
+ list_add_tail(&pkt->list, &garmin_data_p->pktlist);
++ state = garmin_data_p->state;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ /* in serial mode, if someone is waiting for data from
+ the device, iconvert and send the next packet to tty. */
+- if (result && (garmin_data_p->state == STATE_GSP_WAIT_DATA)) {
++ if (result && (state == STATE_GSP_WAIT_DATA)) {
+ gsp_next_packet(garmin_data_p);
+ }
+ }
+@@ -370,9 +375,9 @@ static void pkt_clear(struct garmin_data
+ static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
+ {
+ __u8 pkt[10];
+- __u8 cksum = 0;
+- __u8 *ptr = pkt;
+- unsigned l = 0;
++ __u8 cksum = 0;
++ __u8 *ptr = pkt;
++ unsigned l = 0;
+
+ dbg("%s - pkt-id: 0x%X.", __FUNCTION__, 0xFF & pkt_id);
+
+@@ -416,7 +421,7 @@ static int gsp_send_ack(struct garmin_da
+ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
+ {
+ const __u8* recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET;
+- __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
++ __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
+
+ int cksum = 0;
+ int n = 0;
+@@ -447,11 +452,11 @@ static int gsp_rec_packet(struct garmin_
+ n++;
+ }
+
+- if ((0xff & (cksum + *recpkt)) != 0) {
+- dbg("%s - invalid checksum, expected %02x, got %02x",
+- __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
+- return -EINVPKT;
+- }
++ if ((0xff & (cksum + *recpkt)) != 0) {
++ dbg("%s - invalid checksum, expected %02x, got %02x",
++ __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
++ return -EINVPKT;
++ }
+
+ usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL);
+ usbdata[1] = __cpu_to_le32(pktid);
+@@ -491,20 +496,28 @@ static int gsp_rec_packet(struct garmin_
+ */
+
+ static int gsp_receive(struct garmin_data * garmin_data_p,
+- const unsigned char *buf, int count)
++ const unsigned char *buf, int count)
+ {
++ unsigned long flags;
+ int offs = 0;
+ int ack_or_nak_seen = 0;
+ int i = 0;
+- __u8 *dest = garmin_data_p->inbuffer;
+- int size = garmin_data_p->insize;
++ __u8 *dest;
++ int size;
+ // dleSeen: set if last byte read was a DLE
+- int dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
++ int dleSeen;
+ // skip: if set, skip incoming data until possible start of
+ // new packet
+- int skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
++ int skip;
+ __u8 data;
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
++ dest = garmin_data_p->inbuffer;
++ size = garmin_data_p->insize;
++ dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
++ skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
++
+ dbg("%s - dle=%d skip=%d size=%d count=%d",
+ __FUNCTION__, dleSeen, skip, size, count);
+
+@@ -572,6 +585,8 @@ static int gsp_receive(struct garmin_dat
+ }
+ }
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
++
+ garmin_data_p->insize = size;
+
+ // copy flags back to structure
+@@ -587,6 +602,11 @@ static int gsp_receive(struct garmin_dat
+
+ if (ack_or_nak_seen) {
+ garmin_data_p->state = STATE_GSP_WAIT_DATA;
++ }
++
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
++
++ if (ack_or_nak_seen) {
+ gsp_next_packet(garmin_data_p);
+ }
+
+@@ -676,7 +696,7 @@ static int gsp_send(struct garmin_data *
+ src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH;
+ if (k > (GARMIN_PKTHDR_LENGTH-2)) {
+ /* can't add stuffing DLEs in place, move data to end
+- of buffer ... */
++ of buffer ... */
+ dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen;
+ memcpy(dst, src, datalen);
+ src = dst;
+@@ -755,8 +775,9 @@ static void gsp_next_packet(struct garmi
+ * or even incomplete packets
+ */
+ static int nat_receive(struct garmin_data * garmin_data_p,
+- const unsigned char *buf, int count)
++ const unsigned char *buf, int count)
+ {
++ unsigned long flags;
+ __u8 * dest;
+ int offs = 0;
+ int result = count;
+@@ -803,7 +824,9 @@ static int nat_receive(struct garmin_dat
+ /* if this was an abort-transfer command,
+ flush all queued data. */
+ if (isAbortTrfCmnd(garmin_data_p->inbuffer)) {
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_DROP_DATA;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ pkt_clear(garmin_data_p);
+ }
+ }
+@@ -839,12 +862,15 @@ static void priv_status_resp(struct usb_
+
+ static int process_resetdev_request(struct usb_serial_port *port)
+ {
++ unsigned long flags;
+ int status;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED);
+ garmin_data_p->state = STATE_RESET;
+ garmin_data_p->serial_num = 0;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ usb_kill_urb (port->interrupt_in_urb);
+ dbg("%s - usb_reset_device", __FUNCTION__ );
+@@ -862,6 +888,7 @@ static int process_resetdev_request(stru
+ */
+ static int garmin_clear(struct garmin_data * garmin_data_p)
+ {
++ unsigned long flags;
+ int status = 0;
+
+ struct usb_serial_port *port = garmin_data_p->port;
+@@ -875,8 +902,10 @@ static int garmin_clear(struct garmin_da
+ /* flush all queued data */
+ pkt_clear(garmin_data_p);
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->insize = 0;
+ garmin_data_p->outsize = 0;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ return status;
+ }
+@@ -888,6 +917,7 @@ static int garmin_clear(struct garmin_da
+
+ static int garmin_init_session(struct usb_serial_port *port)
+ {
++ unsigned long flags;
+ struct usb_serial *serial = port->serial;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ int status = 0;
+@@ -913,7 +943,9 @@ static int garmin_init_session(struct us
+
+ if (status >= 0) {
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->ignorePkts++;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ /* not needed, but the win32 driver does it too ... */
+ status = garmin_write_bulk(port,
+@@ -921,7 +953,9 @@ static int garmin_init_session(struct us
+ sizeof(GARMIN_START_SESSION_REQ2));
+ if (status >= 0) {
+ status = 0;
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->ignorePkts++;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+ }
+ }
+@@ -935,6 +969,7 @@ static int garmin_init_session(struct us
+
+ static int garmin_open (struct usb_serial_port *port, struct file *filp)
+ {
++ unsigned long flags;
+ int status = 0;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+
+@@ -948,9 +983,11 @@ static int garmin_open (struct usb_seria
+ if (port->tty)
+ port->tty->low_latency = 1;
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->mode = initial_mode;
+ garmin_data_p->count = 0;
+ garmin_data_p->flags = 0;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ /* shutdown any bulk reads that might be going on */
+ usb_kill_urb (port->write_urb);
+@@ -994,8 +1031,9 @@ static void garmin_close (struct usb_ser
+ }
+
+
+-static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void garmin_write_bulk_callback (struct urb *urb)
+ {
++ unsigned long flags;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+
+@@ -1007,7 +1045,9 @@ static void garmin_write_bulk_callback (
+ if (urb->status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+
+ usb_serial_port_softint(port);
+@@ -1015,8 +1055,9 @@ static void garmin_write_bulk_callback (
+
+
+ static int garmin_write_bulk (struct usb_serial_port *port,
+- const unsigned char *buf, int count)
++ const unsigned char *buf, int count)
+ {
++ unsigned long flags;
+ struct usb_serial *serial = port->serial;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ struct urb *urb;
+@@ -1026,7 +1067,9 @@ static int garmin_write_bulk (struct usb
+ dbg("%s - port %d, state %d", __FUNCTION__, port->number,
+ garmin_data_p->state);
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_DROP_DATA;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ buffer = kmalloc (count, GFP_ATOMIC);
+ if (!buffer) {
+@@ -1053,7 +1096,9 @@ static int garmin_write_bulk (struct usb
+ urb->transfer_flags |= URB_ZERO_PACKET;
+
+ if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
+ pkt_clear(garmin_data_p);
+ garmin_data_p->state = STATE_GSP_WAIT_DATA;
+@@ -1087,8 +1132,9 @@ static int garmin_write_bulk (struct usb
+
+
+ static int garmin_write (struct usb_serial_port *port,
+- const unsigned char *buf, int count)
++ const unsigned char *buf, int count)
+ {
++ unsigned long flags;
+ int pktid, pktsiz, len;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ __le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
+@@ -1139,7 +1185,9 @@ static int garmin_write (struct usb_seri
+ break;
+
+ case PRIV_PKTID_RESET_REQ:
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ break;
+
+ case PRIV_PKTID_SET_DEF_MODE:
+@@ -1155,6 +1203,8 @@ static int garmin_write (struct usb_seri
+ }
+ }
+
++ garmin_data_p->ignorePkts = 0;
++
+ if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
+ return gsp_receive(garmin_data_p, buf, count);
+ } else { /* MODE_NATIVE */
+@@ -1177,10 +1227,10 @@ static int garmin_chars_in_buffer (struc
+ {
+ /*
+ * Report back the number of bytes currently in our input buffer.
+- * Will this lock up the driver - the buffer contains an incomplete
+- * package which will not be written to the device until it
+- * has been completed ?
+- */
++ * Will this lock up the driver - the buffer contains an incomplete
++ * package which will not be written to the device until it
++ * has been completed ?
++ */
+ //struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ //return garmin_data_p->insize;
+ return 0;
+@@ -1190,6 +1240,8 @@ static int garmin_chars_in_buffer (struc
+ static void garmin_read_process(struct garmin_data * garmin_data_p,
+ unsigned char *data, unsigned data_length)
+ {
++ unsigned long flags;
++
+ if (garmin_data_p->flags & FLAGS_DROP_DATA) {
+ /* abort-transfer cmd is actice */
+ dbg("%s - pkt dropped", __FUNCTION__);
+@@ -1200,11 +1252,14 @@ static void garmin_read_process(struct g
+ if a reset is required or not when closing
+ the device */
+ if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
+- sizeof(GARMIN_APP_LAYER_REPLY)))
++ sizeof(GARMIN_APP_LAYER_REPLY))) {
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_APP_RESP_SEEN;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
++ }
+
+ /* if throttling is active or postprecessing is required
+- put the received data in th input queue, otherwise
++ put the received data in the input queue, otherwise
+ send it directly to the tty port */
+ if (garmin_data_p->flags & FLAGS_QUEUING) {
+ pkt_add(garmin_data_p, data, data_length);
+@@ -1219,8 +1274,9 @@ static void garmin_read_process(struct g
+ }
+
+
+-static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void garmin_read_bulk_callback (struct urb *urb)
+ {
++ unsigned long flags;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+@@ -1245,26 +1301,38 @@ static void garmin_read_bulk_callback (s
+
+ garmin_read_process(garmin_data_p, data, urb->actual_length);
+
+- /* Continue trying to read until nothing more is received */
+- if (urb->actual_length > 0) {
+- usb_fill_bulk_urb (port->read_urb, serial->dev,
+- usb_rcvbulkpipe (serial->dev,
+- port->bulk_in_endpointAddress),
+- port->read_urb->transfer_buffer,
+- port->read_urb->transfer_buffer_length,
+- garmin_read_bulk_callback, port);
++ if (urb->actual_length == 0 &&
++ 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) {
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
++ garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, status);
++ } else if (urb->actual_length > 0) {
++ /* Continue trying to read until nothing more is received */
++ if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
++ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++ if (status)
++ dev_err(&port->dev,
++ "%s - failed resubmitting read urb, error %d\n",
++ __FUNCTION__, status);
++ }
++ } else {
++ dbg("%s - end of bulk data", __FUNCTION__);
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
++ garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+ return;
+ }
+
+
+-static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
++static void garmin_read_int_callback (struct urb *urb)
+ {
++ unsigned long flags;
+ int status;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+@@ -1297,25 +1365,41 @@ static void garmin_read_int_callback (st
+
+ dbg("%s - bulk data available.", __FUNCTION__);
+
+- /* bulk data available */
+- usb_fill_bulk_urb (port->read_urb, serial->dev,
+- usb_rcvbulkpipe (serial->dev,
+- port->bulk_in_endpointAddress),
+- port->read_urb->transfer_buffer,
+- port->read_urb->transfer_buffer_length,
+- garmin_read_bulk_callback, port);
+- status = usb_submit_urb(port->read_urb, GFP_KERNEL);
+- if (status) {
+- dev_err(&port->dev,
+- "%s - failed submitting read urb, error %d\n",
+- __FUNCTION__, status);
++ if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
++
++ /* bulk data available */
++ usb_fill_bulk_urb (port->read_urb, serial->dev,
++ usb_rcvbulkpipe (serial->dev,
++ port->bulk_in_endpointAddress),
++ port->read_urb->transfer_buffer,
++ port->read_urb->transfer_buffer_length,
++ garmin_read_bulk_callback, port);
++ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++ if (status) {
++ dev_err(&port->dev,
++ "%s - failed submitting read urb, error %d\n",
++ __FUNCTION__, status);
++ } else {
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
++ garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
++ /* do not send this packet to the user */
++ garmin_data_p->ignorePkts = 1;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
++ }
++ } else {
++ /* bulk-in transfer still active */
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
++ garmin_data_p->flags |= FLAGS_BULK_IN_RESTART;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+
+ } else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY))
+ && 0 == memcmp(data, GARMIN_START_SESSION_REPLY,
+ sizeof(GARMIN_START_SESSION_REPLY))) {
+
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ /* save the serial number */
+ garmin_data_p->serial_num
+@@ -1330,7 +1414,9 @@ static void garmin_read_int_callback (st
+ ignore it. */
+ dbg("%s - pkt ignored (%d)",
+ __FUNCTION__, garmin_data_p->ignorePkts);
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->ignorePkts--;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ } else {
+ garmin_read_process(garmin_data_p, data, urb->actual_length);
+ }
+@@ -1351,18 +1437,20 @@ static void garmin_read_int_callback (st
+ */
+ static int garmin_flush_queue(struct garmin_data * garmin_data_p)
+ {
++ unsigned long flags;
+ struct garmin_packet *pkt;
+
+ if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) {
+ pkt = pkt_pop(garmin_data_p);
+ if (pkt != NULL) {
+-
+ send_to_tty(garmin_data_p->port, pkt->data, pkt->size);
+ kfree(pkt);
+ mod_timer(&garmin_data_p->timer, (1)+jiffies);
+
+ } else {
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_QUEUING;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+ }
+ return 0;
+@@ -1371,26 +1459,41 @@ static int garmin_flush_queue(struct gar
+
+ static void garmin_throttle (struct usb_serial_port *port)
+ {
++ unsigned long flags;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ /* set flag, data received will be put into a queue
+ for later processing */
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+
+
+ static void garmin_unthrottle (struct usb_serial_port *port)
+ {
++ unsigned long flags;
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
++ int status;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
++ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_THROTTLED;
++ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ /* in native mode send queued data to tty, in
+ serial mode nothing needs to be done here */
+ if (garmin_data_p->mode == MODE_NATIVE)
+ garmin_flush_queue(garmin_data_p);
++
++ if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
++ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++ if (status)
++ dev_err(&port->dev,
++ "%s - failed resubmitting read urb, error %d\n",
++ __FUNCTION__, status);
++ }
+ }
+
+
+@@ -1420,11 +1523,12 @@ static int garmin_attach (struct usb_ser
+
+ dbg("%s", __FUNCTION__);
+
+- garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
++ garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL);
+ if (garmin_data_p == NULL) {
+ dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
++ memset (garmin_data_p, 0, sizeof(struct garmin_data));
+ init_timer(&garmin_data_p->timer);
+ spin_lock_init(&garmin_data_p->lock);
+ INIT_LIST_HEAD(&garmin_data_p->pktlist);
+@@ -1459,10 +1563,10 @@ static void garmin_shutdown (struct usb_
+ /* All of the device info needed */
+ static struct usb_serial_driver garmin_device = {
+ .driver = {
+- .owner = THIS_MODULE,
+- .name = "garmin_gps",
++ .owner = THIS_MODULE,
++ .name = "garmin_gps",
+ },
+- .description = "Garmin GPS usb/tty",
++ .description = "Garmin GPS usb/tty",
+ .id_table = id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+@@ -1483,6 +1587,7 @@ static struct usb_serial_driver garmin_d
+ };
+
+
++
+ static int __init garmin_init (void)
+ {
+ int retval;
+diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
+index 1727135..3604293 100644
+--- a/drivers/usb/serial/generic.c
++++ b/drivers/usb/serial/generic.c
+@@ -175,14 +175,14 @@ int usb_serial_generic_write(struct usb_
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+- spin_lock(&port->lock);
++ spin_lock_bh(&port->lock);
+ if (port->write_urb_busy) {
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
+ }
+ port->write_urb_busy = 1;
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+@@ -248,7 +248,7 @@ int usb_serial_generic_chars_in_buffer (
+ return (chars);
+ }
+
+-void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++void usb_serial_generic_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+@@ -287,7 +287,7 @@ void usb_serial_generic_read_bulk_callba
+ }
+ EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
+
+-void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++void usb_serial_generic_write_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
+index c49976c..91bd301 100644
+--- a/drivers/usb/serial/io_edgeport.c
++++ b/drivers/usb/serial/io_edgeport.c
+@@ -216,10 +216,10 @@ static int CmdUrbs = 0; /* Number of ou
+ /* local function prototypes */
+
+ /* function prototypes for all URB callbacks */
+-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs);
+-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs);
+-static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs);
+-static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs);
++static void edge_interrupt_callback (struct urb *urb);
++static void edge_bulk_in_callback (struct urb *urb);
++static void edge_bulk_out_data_callback (struct urb *urb);
++static void edge_bulk_out_cmd_callback (struct urb *urb);
+
+ /* function prototypes for the usbserial callbacks */
+ static int edge_open (struct usb_serial_port *port, struct file *filp);
+@@ -534,7 +534,7 @@ static void get_product_info(struct edge
+ * this is the callback function for when we have received data on the
+ * interrupt endpoint.
+ *****************************************************************************/
+-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_interrupt_callback (struct urb *urb)
+ {
+ struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
+ struct edgeport_port *edge_port;
+@@ -631,7 +631,7 @@ exit:
+ * this is the callback function for when we have received data on the
+ * bulk in endpoint.
+ *****************************************************************************/
+-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_bulk_in_callback (struct urb *urb)
+ {
+ struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -687,7 +687,7 @@ static void edge_bulk_in_callback (struc
+ * this is the callback function for when we have finished sending serial data
+ * on the bulk out endpoint.
+ *****************************************************************************/
+-static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_bulk_out_data_callback (struct urb *urb)
+ {
+ struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+ struct tty_struct *tty;
+@@ -718,7 +718,7 @@ static void edge_bulk_out_data_callback
+ * this is the callback function for when we have finished sending a command
+ * on the bulk out endpoint.
+ *****************************************************************************/
+-static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_bulk_out_cmd_callback (struct urb *urb)
+ {
+ struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+ struct tty_struct *tty;
+diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
+index 17c5b1d..ee0c921 100644
+--- a/drivers/usb/serial/io_ti.c
++++ b/drivers/usb/serial/io_ti.c
+@@ -1697,7 +1697,7 @@ static void handle_new_lsr (struct edgep
+ }
+
+
+-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_interrupt_callback (struct urb *urb)
+ {
+ struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
+ struct usb_serial_port *port;
+@@ -1787,7 +1787,7 @@ exit:
+ __FUNCTION__, status);
+ }
+
+-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_bulk_in_callback (struct urb *urb)
+ {
+ struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -1879,7 +1879,7 @@ static void edge_tty_recv(struct device
+ tty_flip_buffer_push(tty);
+ }
+
+-static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs)
++static void edge_bulk_out_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
+index 9840bad..6238aff 100644
+--- a/drivers/usb/serial/ipaq.c
++++ b/drivers/usb/serial/ipaq.c
+@@ -83,8 +83,8 @@ static int ipaq_write(struct usb_serial_
+ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *buf,
+ int count);
+ static void ipaq_write_gather(struct usb_serial_port *port);
+-static void ipaq_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs);
++static void ipaq_read_bulk_callback (struct urb *urb);
++static void ipaq_write_bulk_callback(struct urb *urb);
+ static int ipaq_write_room(struct usb_serial_port *port);
+ static int ipaq_chars_in_buffer(struct usb_serial_port *port);
+ static void ipaq_destroy_lists(struct usb_serial_port *port);
+@@ -479,6 +479,7 @@ static struct usb_device_id ipaq_id_tabl
+ { USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */
+ { USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */
+ { USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */
++ { USB_DEVICE(0x0BB4, 0x0BCE) }, /* "High Tech Computer Corp" */
+ { USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */
+ { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */
+ { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
+@@ -652,11 +653,6 @@ static int ipaq_open(struct usb_serial_p
+ port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+
+ msleep(1000*initial_wait);
+- /* Start reading from the device */
+- usb_fill_bulk_urb(port->read_urb, serial->dev,
+- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+- ipaq_read_bulk_callback, port);
+
+ /*
+ * Send out control message observed in win98 sniffs. Not sure what
+@@ -670,18 +666,31 @@ static int ipaq_open(struct usb_serial_p
+ result = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+ 0x1, 0, NULL, 0, 100);
+- if (result == 0) {
+- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+- if (result) {
+- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+- goto error;
+- }
+- return 0;
+- }
++ if (!result)
++ break;
++
+ msleep(1000);
+ }
+- err("%s - failed doing control urb, error %d", __FUNCTION__, result);
+- goto error;
++
++ if (!retries && result) {
++ err("%s - failed doing control urb, error %d", __FUNCTION__,
++ result);
++ goto error;
++ }
++
++ /* Start reading from the device */
++ usb_fill_bulk_urb(port->read_urb, serial->dev,
++ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
++ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
++ ipaq_read_bulk_callback, port);
++
++ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
++ if (result) {
++ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
++ goto error;
++ }
++
++ return 0;
+
+ enomem:
+ result = -ENOMEM;
+@@ -712,7 +721,7 @@ static void ipaq_close(struct usb_serial
+ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
+ }
+
+-static void ipaq_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void ipaq_read_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct tty_struct *tty;
+@@ -850,7 +859,7 @@ static void ipaq_write_gather(struct usb
+ return;
+ }
+
+-static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void ipaq_write_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct ipaq_private *priv = usb_get_serial_port_data(port);
+diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
+index 87306cb..2a4bb66 100644
+--- a/drivers/usb/serial/ipw.c
++++ b/drivers/usb/serial/ipw.c
+@@ -161,7 +161,7 @@ static struct usb_driver usb_ipw_driver
+
+ static int debug;
+
+-static void ipw_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void ipw_read_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -367,7 +367,7 @@ static void ipw_close(struct usb_serial_
+ usb_kill_urb(port->write_urb);
+ }
+
+-static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void ipw_write_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = urb->context;
+
+@@ -394,14 +394,14 @@ static int ipw_write(struct usb_serial_p
+ return 0;
+ }
+
+- spin_lock(&port->lock);
++ spin_lock_bh(&port->lock);
+ if (port->write_urb_busy) {
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
+ }
+ port->write_urb_busy = 1;
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+
+ count = min(count, port->bulk_out_size);
+ memcpy(port->bulk_out_buffer, buf, count);
+diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
+index 1738b0b..331bf81 100644
+--- a/drivers/usb/serial/ir-usb.c
++++ b/drivers/usb/serial/ir-usb.c
+@@ -105,8 +105,8 @@ static int ir_startup (struct usb_seria
+ static int ir_open (struct usb_serial_port *port, struct file *filep);
+ static void ir_close (struct usb_serial_port *port, struct file *filep);
+ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count);
+-static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void ir_write_bulk_callback (struct urb *urb);
++static void ir_read_bulk_callback (struct urb *urb);
+ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+
+ static u8 ir_baud = 0;
+@@ -342,14 +342,14 @@ static int ir_write (struct usb_serial_p
+ if (count == 0)
+ return 0;
+
+- spin_lock(&port->lock);
++ spin_lock_bh(&port->lock);
+ if (port->write_urb_busy) {
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
+ }
+ port->write_urb_busy = 1;
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+
+ transfer_buffer = port->write_urb->transfer_buffer;
+ transfer_size = min(count, port->bulk_out_size - 1);
+@@ -388,7 +388,7 @@ static int ir_write (struct usb_serial_p
+ return result;
+ }
+
+-static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void ir_write_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+@@ -410,7 +410,7 @@ static void ir_write_bulk_callback (stru
+ usb_serial_port_softint(port);
+ }
+
+-static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void ir_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct tty_struct *tty;
+diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
+index 015ad6c..53be824 100644
+--- a/drivers/usb/serial/keyspan.c
++++ b/drivers/usb/serial/keyspan.c
+@@ -412,7 +412,7 @@ static int keyspan_write(struct usb_seri
+ return count - left;
+ }
+
+-static void usa26_indat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa26_indat_callback(struct urb *urb)
+ {
+ int i, err;
+ int endpoint;
+@@ -470,7 +470,7 @@ static void usa26_indat_callback(struct
+ }
+
+ /* Outdat handling is common for all devices */
+-static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa2x_outdat_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+@@ -483,13 +483,13 @@ static void usa2x_outdat_callback(struct
+ usb_serial_port_softint(port);
+ }
+
+-static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs)
++static void usa26_inack_callback(struct urb *urb)
+ {
+ dbg ("%s", __FUNCTION__);
+
+ }
+
+-static void usa26_outcont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa26_outcont_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+@@ -503,7 +503,7 @@ static void usa26_outcont_callback(struc
+ }
+ }
+
+-static void usa26_instat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa26_instat_callback(struct urb *urb)
+ {
+ unsigned char *data = urb->transfer_buffer;
+ struct keyspan_usa26_portStatusMessage *msg;
+@@ -565,14 +565,14 @@ static void usa26_instat_callback(struct
+ exit: ;
+ }
+
+-static void usa26_glocont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa26_glocont_callback(struct urb *urb)
+ {
+ dbg ("%s", __FUNCTION__);
+
+ }
+
+
+-static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa28_indat_callback(struct urb *urb)
+ {
+ int i, err;
+ struct usb_serial_port *port;
+@@ -620,12 +620,12 @@ static void usa28_indat_callback(struct
+ } while (urb->status != -EINPROGRESS);
+ }
+
+-static void usa28_inack_callback(struct urb *urb, struct pt_regs *regs)
++static void usa28_inack_callback(struct urb *urb)
+ {
+ dbg ("%s", __FUNCTION__);
+ }
+
+-static void usa28_outcont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa28_outcont_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+@@ -639,7 +639,7 @@ static void usa28_outcont_callback(struc
+ }
+ }
+
+-static void usa28_instat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa28_instat_callback(struct urb *urb)
+ {
+ int err;
+ unsigned char *data = urb->transfer_buffer;
+@@ -700,13 +700,13 @@ static void usa28_instat_callback(struct
+ exit: ;
+ }
+
+-static void usa28_glocont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa28_glocont_callback(struct urb *urb)
+ {
+ dbg ("%s", __FUNCTION__);
+ }
+
+
+-static void usa49_glocont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa49_glocont_callback(struct urb *urb)
+ {
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+@@ -730,7 +730,7 @@ static void usa49_glocont_callback(struc
+
+ /* This is actually called glostat in the Keyspan
+ doco */
+-static void usa49_instat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa49_instat_callback(struct urb *urb)
+ {
+ int err;
+ unsigned char *data = urb->transfer_buffer;
+@@ -793,12 +793,12 @@ static void usa49_instat_callback(struct
+ exit: ;
+ }
+
+-static void usa49_inack_callback(struct urb *urb, struct pt_regs *regs)
++static void usa49_inack_callback(struct urb *urb)
+ {
+ dbg ("%s", __FUNCTION__);
+ }
+
+-static void usa49_indat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa49_indat_callback(struct urb *urb)
+ {
+ int i, err;
+ int endpoint;
+@@ -851,12 +851,12 @@ static void usa49_indat_callback(struct
+ }
+
+ /* not used, usa-49 doesn't have per-port control endpoints */
+-static void usa49_outcont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa49_outcont_callback(struct urb *urb)
+ {
+ dbg ("%s", __FUNCTION__);
+ }
+
+-static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa90_indat_callback(struct urb *urb)
+ {
+ int i, err;
+ int endpoint;
+@@ -930,7 +930,7 @@ static void usa90_indat_callback(struct
+ }
+
+
+-static void usa90_instat_callback(struct urb *urb, struct pt_regs *regs)
++static void usa90_instat_callback(struct urb *urb)
+ {
+ unsigned char *data = urb->transfer_buffer;
+ struct keyspan_usa90_portStatusMessage *msg;
+@@ -981,7 +981,7 @@ exit:
+ ;
+ }
+
+-static void usa90_outcont_callback(struct urb *urb, struct pt_regs *regs)
++static void usa90_outcont_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+@@ -1277,7 +1277,7 @@ static int keyspan_fake_startup (struct
+ /* Helper functions used by keyspan_setup_urbs */
+ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+- void (*callback)(struct urb *, struct pt_regs *regs))
++ void (*callback)(struct urb *))
+ {
+ struct urb *urb;
+
+@@ -1300,12 +1300,12 @@ static struct urb *keyspan_setup_urb (st
+ }
+
+ static struct callbacks {
+- void (*instat_callback)(struct urb *, struct pt_regs *regs);
+- void (*glocont_callback)(struct urb *, struct pt_regs *regs);
+- void (*indat_callback)(struct urb *, struct pt_regs *regs);
+- void (*outdat_callback)(struct urb *, struct pt_regs *regs);
+- void (*inack_callback)(struct urb *, struct pt_regs *regs);
+- void (*outcont_callback)(struct urb *, struct pt_regs *regs);
++ void (*instat_callback)(struct urb *);
++ void (*glocont_callback)(struct urb *);
++ void (*indat_callback)(struct urb *);
++ void (*outdat_callback)(struct urb *);
++ void (*inack_callback)(struct urb *);
++ void (*outcont_callback)(struct urb *);
+ } keyspan_callbacks[] = {
+ {
+ /* msg_usa26 callbacks */
+diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
+index 49b8dc0..9090051 100644
+--- a/drivers/usb/serial/keyspan_pda.c
++++ b/drivers/usb/serial/keyspan_pda.c
+@@ -210,7 +210,7 @@ static void keyspan_pda_request_unthrott
+ }
+
+
+-static void keyspan_pda_rx_interrupt (struct urb *urb, struct pt_regs *regs)
++static void keyspan_pda_rx_interrupt (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct tty_struct *tty = port->tty;
+@@ -518,13 +518,13 @@ static int keyspan_pda_write(struct usb_
+ the TX urb is in-flight (wait until it completes)
+ the device is full (wait until it says there is room)
+ */
+- spin_lock(&port->lock);
++ spin_lock_bh(&port->lock);
+ if (port->write_urb_busy || priv->tx_throttled) {
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+ return 0;
+ }
+ port->write_urb_busy = 1;
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&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
+@@ -601,7 +601,7 @@ exit:
+ }
+
+
+-static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void keyspan_pda_write_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct keyspan_pda_private *priv;
+diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
+index 2a2f3e2..17e2056 100644
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -80,11 +80,11 @@ static void klsi_105_close (str
+ static int klsi_105_write (struct usb_serial_port *port,
+ const unsigned char *buf,
+ int count);
+-static void klsi_105_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void klsi_105_write_bulk_callback (struct urb *urb);
+ static int klsi_105_chars_in_buffer (struct usb_serial_port *port);
+ static int klsi_105_write_room (struct usb_serial_port *port);
+
+-static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void klsi_105_read_bulk_callback (struct urb *urb);
+ static void klsi_105_set_termios (struct usb_serial_port *port,
+ struct termios * old);
+ static int klsi_105_ioctl (struct usb_serial_port *port,
+@@ -556,7 +556,7 @@ exit:
+ return bytes_sent; /* that's how much we wrote */
+ } /* klsi_105_write */
+
+-static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs)
++static void klsi_105_write_bulk_callback ( struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+@@ -616,7 +616,7 @@ static int klsi_105_write_room (struct u
+
+
+
+-static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void klsi_105_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct klsi_105_private *priv = usb_get_serial_port_data(port);
+diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
+index d50dce0..ff03331 100644
+--- a/drivers/usb/serial/kobil_sct.c
++++ b/drivers/usb/serial/kobil_sct.c
+@@ -80,8 +80,8 @@ static int kobil_ioctl(struct usb_seria
+ static int kobil_tiocmget(struct usb_serial_port *port, struct file *file);
+ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear);
+-static void kobil_read_int_callback( struct urb *urb, struct pt_regs *regs );
+-static void kobil_write_callback( struct urb *purb, struct pt_regs *regs );
++static void kobil_read_int_callback( struct urb *urb );
++static void kobil_write_callback( struct urb *purb );
+
+
+ static struct usb_device_id id_table [] = {
+@@ -360,7 +360,7 @@ static void kobil_close (struct usb_seri
+ }
+
+
+-static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
++static void kobil_read_int_callback( struct urb *purb)
+ {
+ int result;
+ struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
+@@ -405,7 +405,7 @@ static void kobil_read_int_callback( str
+ }
+
+
+-static void kobil_write_callback( struct urb *purb, struct pt_regs *regs )
++static void kobil_write_callback( struct urb *purb )
+ {
+ }
+
+diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
+index f4d4305..b7582cc 100644
+--- a/drivers/usb/serial/mct_u232.c
++++ b/drivers/usb/serial/mct_u232.c
+@@ -96,7 +96,7 @@ static int mct_u232_open (stru
+ struct file *filp);
+ static void mct_u232_close (struct usb_serial_port *port,
+ struct file *filp);
+-static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs);
++static void mct_u232_read_int_callback (struct urb *urb);
+ static void mct_u232_set_termios (struct usb_serial_port *port,
+ struct termios * old);
+ static int mct_u232_ioctl (struct usb_serial_port *port,
+@@ -466,7 +466,7 @@ static void mct_u232_close (struct usb_s
+ } /* mct_u232_close */
+
+
+-static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs)
++static void mct_u232_read_int_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
+diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
+new file mode 100644
+index 0000000..82cd15b
+--- /dev/null
++++ b/drivers/usb/serial/mos7720.c
+@@ -0,0 +1,1683 @@
++/*
++ * mos7720.c
++ * Controls the Moschip 7720 usb to dual port serial convertor
++ *
++ * Copyright 2006 Moschip Semiconductor Tech. 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, version 2 of the License.
++ *
++ * Developed by:
++ * VijayaKumar.G.N. <vijaykumar at aspirecom.net>
++ * AjayKumar <ajay at aspirecom.net>
++ * Gurudeva.N. <gurudev at aspirecom.net>
++ *
++ * Cleaned up from the original by:
++ * Greg Kroah-Hartman <gregkh at suse.de>
++ *
++ * Originally based on drivers/usb/serial/io_edgeport.c which is:
++ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
++ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg at kroah.com>
++ */
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <linux/usb.h>
++#include <linux/usb/serial.h>
++#include <asm/uaccess.h>
++
++
++/*
++ * Version Information
++ */
++#define DRIVER_VERSION "1.0.0.4F"
++#define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
++#define DRIVER_DESC "Moschip USB Serial Driver"
++
++/* default urb timeout */
++#define MOS_WDR_TIMEOUT (HZ * 5)
++
++#define MOS_PORT1 0x0200
++#define MOS_PORT2 0x0300
++#define MOS_VENREG 0x0000
++#define MOS_MAX_PORT 0x02
++#define MOS_WRITE 0x0E
++#define MOS_READ 0x0D
++
++/* Interrupt Rotinue Defines */
++#define SERIAL_IIR_RLS 0x06
++#define SERIAL_IIR_RDA 0x04
++#define SERIAL_IIR_CTI 0x0c
++#define SERIAL_IIR_THR 0x02
++#define SERIAL_IIR_MS 0x00
++
++#define NUM_URBS 16 /* URB Count */
++#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
++
++/* This structure holds all of the local port information */
++struct moschip_port
++{
++ __u8 shadowLCR; /* last LCR value received */
++ __u8 shadowMCR; /* last MCR value received */
++ __u8 shadowMSR; /* last MSR value received */
++ char open;
++ struct async_icount icount;
++ struct usb_serial_port *port; /* loop back to the owner */
++ struct urb *write_urb_pool[NUM_URBS];
++};
++
++/* This structure holds all of the individual serial device information */
++struct moschip_serial
++{
++ int interrupt_started;
++};
++
++static int debug;
++
++#define USB_VENDOR_ID_MOSCHIP 0x9710
++#define MOSCHIP_DEVICE_ID_7720 0x7720
++#define MOSCHIP_DEVICE_ID_7715 0x7715
++
++static struct usb_device_id moschip_port_id_table [] = {
++ { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) },
++ { } /* terminating entry */
++};
++MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
++
++
++/*
++ * mos7720_interrupt_callback
++ * this is the callback function for when we have received data on the
++ * interrupt endpoint.
++ */
++static void mos7720_interrupt_callback(struct urb *urb)
++{
++ int result;
++ int length;
++ __u32 *data;
++ unsigned int status;
++ __u8 sp1;
++ __u8 sp2;
++ __u8 st;
++
++ dbg("%s"," : Entering\n");
++
++ if (!urb) {
++ dbg("%s","Invalid Pointer !!!!:\n");
++ return;
++ }
++
++ 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;
++ }
++
++ length = urb->actual_length;
++ data = urb->transfer_buffer;
++
++ /* Moschip get 4 bytes
++ * Byte 1 IIR Port 1 (port.number is 0)
++ * Byte 2 IIR Port 2 (port.number is 1)
++ * Byte 3 --------------
++ * Byte 4 FIFO status for both */
++ if (length && length > 4) {
++ dbg("Wrong data !!!");
++ return;
++ }
++
++ status = *data;
++
++ sp1 = (status & 0xff000000)>>24;
++ sp2 = (status & 0x00ff0000)>>16;
++ st = status & 0x000000ff;
++
++ if ((sp1 & 0x01) || (sp2 & 0x01)) {
++ /* No Interrupt Pending in both the ports */
++ dbg("No Interrupt !!!");
++ } else {
++ switch (sp1 & 0x0f) {
++ case SERIAL_IIR_RLS:
++ dbg("Serial Port 1: Receiver status error or address "
++ "bit detected in 9-bit mode\n");
++ break;
++ case SERIAL_IIR_CTI:
++ dbg("Serial Port 1: Receiver time out");
++ break;
++ case SERIAL_IIR_MS:
++ dbg("Serial Port 1: Modem status change");
++ break;
++ }
++
++ switch (sp2 & 0x0f) {
++ case SERIAL_IIR_RLS:
++ dbg("Serial Port 2: Receiver status error or address "
++ "bit detected in 9-bit mode");
++ break;
++ case SERIAL_IIR_CTI:
++ dbg("Serial Port 2: Receiver time out");
++ break;
++ case SERIAL_IIR_MS:
++ dbg("Serial Port 2: Modem status change");
++ break;
++ }
++ }
++
++exit:
++ result = usb_submit_urb(urb, GFP_ATOMIC);
++ if (result)
++ dev_err(&urb->dev->dev,
++ "%s - Error %d submitting control urb\n",
++ __FUNCTION__, result);
++ return;
++}
++
++/*
++ * mos7720_bulk_in_callback
++ * this is the callback function for when we have received data on the
++ * bulk in endpoint.
++ */
++static void mos7720_bulk_in_callback(struct urb *urb)
++{
++ int status;
++ unsigned char *data ;
++ struct usb_serial_port *port;
++ struct moschip_port *mos7720_port;
++ struct tty_struct *tty;
++
++ if (urb->status) {
++ dbg("nonzero read bulk status received: %d",urb->status);
++ return;
++ }
++
++ mos7720_port = urb->context;
++ if (!mos7720_port) {
++ dbg("%s","NULL mos7720_port pointer \n");
++ return ;
++ }
++
++ port = mos7720_port->port;
++
++ dbg("Entering...%s", __FUNCTION__);
++
++ data = urb->transfer_buffer;
++
++ tty = port->tty;
++ if (tty && urb->actual_length) {
++ tty_buffer_request_room(tty, urb->actual_length);
++ tty_insert_flip_string(tty, data, urb->actual_length);
++ tty_flip_buffer_push(tty);
++ }
++
++ if (!port->read_urb) {
++ dbg("URB KILLED !!!");
++ return;
++ }
++
++ if (port->read_urb->status != -EINPROGRESS) {
++ port->read_urb->dev = port->serial->dev;
++
++ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++ if (status)
++ dbg("usb_submit_urb(read bulk) failed, status = %d",
++ status);
++ }
++}
++
++/*
++ * mos7720_bulk_out_data_callback
++ * this is the callback function for when we have finished sending serial
++ * data on the bulk out endpoint.
++ */
++static void mos7720_bulk_out_data_callback(struct urb *urb)
++{
++ struct moschip_port *mos7720_port;
++ struct tty_struct *tty;
++
++ if (urb->status) {
++ dbg("nonzero write bulk status received:%d", urb->status);
++ return;
++ }
++
++ mos7720_port = urb->context;
++ if (!mos7720_port) {
++ dbg("NULL mos7720_port pointer");
++ return ;
++ }
++
++ dbg("Entering .........");
++
++ tty = mos7720_port->port->tty;
++
++ if (tty && mos7720_port->open) {
++ /* let the tty driver wakeup if it has a special *
++ * write_wakeup function */
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ (tty->ldisc.write_wakeup)(tty);
++
++ /* tell the tty driver that something has changed */
++ wake_up_interruptible(&tty->write_wait);
++ }
++
++ /* schedule_work(&mos7720_port->port->work); */
++}
++
++/*
++ * send_mos_cmd
++ * this function will be used for sending command to device
++ */
++static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
++ __u16 index, void *data)
++{
++ int status;
++ unsigned int pipe;
++ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
++ __u8 requesttype;
++ __u16 size = 0x0000;
++
++ if (value < MOS_MAX_PORT) {
++ if (product == MOSCHIP_DEVICE_ID_7715) {
++ value = value*0x100+0x100;
++ } else {
++ value = value*0x100+0x200;
++ }
++ } else {
++ value = 0x0000;
++ if ((product == MOSCHIP_DEVICE_ID_7715) &&
++ (index != 0x08)) {
++ dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
++ //index = 0x01 ;
++ }
++ }
++
++ if (request == MOS_WRITE) {
++ request = (__u8)MOS_WRITE;
++ requesttype = (__u8)0x40;
++ value = value + (__u16)*((unsigned char *)data);
++ data = NULL;
++ pipe = usb_sndctrlpipe(serial->dev, 0);
++ } else {
++ request = (__u8)MOS_READ;
++ requesttype = (__u8)0xC0;
++ size = 0x01;
++ pipe = usb_rcvctrlpipe(serial->dev,0);
++ }
++
++ status = usb_control_msg(serial->dev, pipe, request, requesttype,
++ value, index, data, size, MOS_WDR_TIMEOUT);
++
++ if (status < 0)
++ dbg("Command Write failed Value %x index %x\n",value,index);
++
++ return status;
++}
++
++static int mos7720_open(struct usb_serial_port *port, struct file * filp)
++{
++ struct usb_serial *serial;
++ struct usb_serial_port *port0;
++ struct urb *urb;
++ struct moschip_serial *mos7720_serial;
++ struct moschip_port *mos7720_port;
++ int response;
++ int port_number;
++ char data;
++ int j;
++
++ serial = port->serial;
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL)
++ return -ENODEV;
++
++ port0 = serial->port[0];
++
++ mos7720_serial = usb_get_serial_data(serial);
++
++ if (mos7720_serial == NULL || port0 == NULL)
++ return -ENODEV;
++
++ usb_clear_halt(serial->dev, port->write_urb->pipe);
++ usb_clear_halt(serial->dev, port->read_urb->pipe);
++
++ /* Initialising the write urb pool */
++ for (j = 0; j < NUM_URBS; ++j) {
++ urb = usb_alloc_urb(0,SLAB_ATOMIC);
++ mos7720_port->write_urb_pool[j] = urb;
++
++ if (urb == NULL) {
++ err("No more urbs???");
++ continue;
++ }
++
++ urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
++ GFP_KERNEL);
++ if (!urb->transfer_buffer) {
++ err("%s-out of memory for urb buffers.", __FUNCTION__);
++ continue;
++ }
++ }
++
++ /* Initialize MCS7720 -- Write Init values to corresponding Registers
++ *
++ * Register Index
++ * 1 : IER
++ * 2 : FCR
++ * 3 : LCR
++ * 4 : MCR
++ *
++ * 0x08 : SP1/2 Control Reg
++ */
++ port_number = port->number - port->serial->minor;
++ send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
++ dbg("SS::%p LSR:%x\n",mos7720_port, data);
++
++ dbg("Check:Sending Command ..........");
++
++ data = 0x02;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
++ data = 0x02;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
++
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
++
++ data = 0xCF;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
++ data = 0x03;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
++ data = 0x0b;
++ mos7720_port->shadowMCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++ data = 0x0b;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++
++ data = 0x00;
++ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
++
++/* data = 0x00;
++ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
++ data = 0x03;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
++ data = 0x00;
++ send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
++*/
++ data = 0x00;
++ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
++
++ data = data | (port->number - port->serial->minor + 1);
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
++
++ data = 0x83;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
++ data = 0x0c;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
++ data = 0x03;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
++ data = 0x0c;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
++ data = 0x0c;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
++
++//Matrix
++
++ /* force low_latency on so that our tty_push actually forces *
++ * the data through,otherwise it is scheduled, and with *
++ * high data rates (like with OHCI) data can get lost. */
++
++ if (port->tty)
++ port->tty->low_latency = 1;
++
++ /* see if we've set up our endpoint info yet *
++ * (can't set it up in mos7720_startup as the *
++ * structures were not set up at that time.) */
++ if (!mos7720_serial->interrupt_started) {
++ dbg("Interrupt buffer NULL !!!");
++
++ /* not set up yet, so do it now */
++ mos7720_serial->interrupt_started = 1;
++
++ dbg("To Submit URB !!!");
++
++ /* set up our interrupt urb */
++ usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
++ usb_rcvintpipe(serial->dev,
++ port->interrupt_in_endpointAddress),
++ port0->interrupt_in_buffer,
++ port0->interrupt_in_urb->transfer_buffer_length,
++ mos7720_interrupt_callback, mos7720_port,
++ port0->interrupt_in_urb->interval);
++
++ /* start interrupt read for this mos7720 this interrupt *
++ * will continue as long as the mos7720 is connected */
++ dbg("Submit URB over !!!");
++ response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
++ if (response)
++ dev_err(&port->dev,
++ "%s - Error %d submitting control urb",
++ __FUNCTION__, response);
++ }
++
++ /* set up our bulk in urb */
++ usb_fill_bulk_urb(port->read_urb, serial->dev,
++ usb_rcvbulkpipe(serial->dev,
++ port->bulk_in_endpointAddress),
++ port->bulk_in_buffer,
++ port->read_urb->transfer_buffer_length,
++ mos7720_bulk_in_callback, mos7720_port);
++ response = usb_submit_urb(port->read_urb, GFP_KERNEL);
++ if (response)
++ dev_err(&port->dev,
++ "%s - Error %d submitting read urb", __FUNCTION__, response);
++
++ /* initialize our icount structure */
++ memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
++
++ /* initialize our port settings */
++ mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
++
++ /* send a open port command */
++ mos7720_port->open = 1;
++
++ return 0;
++}
++
++/*
++ * mos7720_chars_in_buffer
++ * this function is called by the tty driver when it wants to know how many
++ * bytes of data we currently have outstanding in the port (data that has
++ * been written, but hasn't made it out the port yet)
++ * If successful, we return the number of bytes left to be written in the
++ * system,
++ * Otherwise we return a negative error number.
++ */
++static int mos7720_chars_in_buffer(struct usb_serial_port *port)
++{
++ int i;
++ int chars = 0;
++ struct moschip_port *mos7720_port;
++
++ dbg("%s:entering ...........", __FUNCTION__);
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL) {
++ dbg("%s:leaving ...........", __FUNCTION__);
++ return -ENODEV;
++ }
++
++ for (i = 0; i < NUM_URBS; ++i) {
++ if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
++ chars += URB_TRANSFER_BUFFER_SIZE;
++ }
++ dbg("%s - returns %d", __FUNCTION__, chars);
++ return chars;
++}
++
++static void mos7720_close(struct usb_serial_port *port, struct file *filp)
++{
++ struct usb_serial *serial;
++ struct moschip_port *mos7720_port;
++ char data;
++ int j;
++
++ dbg("mos7720_close:entering...");
++
++ serial = port->serial;
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL)
++ return;
++
++ for (j = 0; j < NUM_URBS; ++j)
++ usb_kill_urb(mos7720_port->write_urb_pool[j]);
++
++ /* Freeing Write URBs */
++ for (j = 0; j < NUM_URBS; ++j) {
++ if (mos7720_port->write_urb_pool[j]) {
++ kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
++ usb_free_urb(mos7720_port->write_urb_pool[j]);
++ }
++ }
++
++ /* While closing port, shutdown all bulk read, write *
++ * and interrupt read if they exists */
++ if (serial->dev) {
++ dbg("Shutdown bulk write");
++ usb_kill_urb(port->write_urb);
++ dbg("Shutdown bulk read");
++ usb_kill_urb(port->read_urb);
++ }
++
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
++ 0x04, &data);
++
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
++ 0x01, &data);
++
++ mos7720_port->open = 0;
++
++ dbg("Leaving %s", __FUNCTION__);
++}
++
++static void mos7720_break(struct usb_serial_port *port, int break_state)
++{
++ unsigned char data;
++ struct usb_serial *serial;
++ struct moschip_port *mos7720_port;
++
++ dbg("Entering %s", __FUNCTION__);
++
++ serial = port->serial;
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL)
++ return;
++
++ if (break_state == -1)
++ data = mos7720_port->shadowLCR | UART_LCR_SBC;
++ else
++ data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
++
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
++ 0x03, &data);
++
++ return;
++}
++
++/*
++ * mos7720_write_room
++ * this function is called by the tty driver when it wants to know how many
++ * bytes of data we can accept for a specific port.
++ * If successful, we return the amount of room that we have for this port
++ * Otherwise we return a negative error number.
++ */
++static int mos7720_write_room(struct usb_serial_port *port)
++{
++ struct moschip_port *mos7720_port;
++ int room = 0;
++ int i;
++
++ dbg("%s:entering ...........", __FUNCTION__);
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL) {
++ dbg("%s:leaving ...........", __FUNCTION__);
++ return -ENODEV;
++ }
++
++ for (i = 0; i < NUM_URBS; ++i) {
++ if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
++ room += URB_TRANSFER_BUFFER_SIZE;
++ }
++
++ dbg("%s - returns %d", __FUNCTION__, room);
++ return room;
++}
++
++static int mos7720_write(struct usb_serial_port *port,
++ const unsigned char *data, int count)
++{
++ int status;
++ int i;
++ int bytes_sent = 0;
++ int transfer_size;
++
++ struct moschip_port *mos7720_port;
++ struct usb_serial *serial;
++ struct urb *urb;
++ const unsigned char *current_position = data;
++
++ dbg("%s:entering ...........", __FUNCTION__);
++
++ serial = port->serial;
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL) {
++ dbg("mos7720_port is NULL");
++ return -ENODEV;
++ }
++
++ /* try to find a free urb in the list */
++ urb = NULL;
++
++ for (i = 0; i < NUM_URBS; ++i) {
++ if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
++ urb = mos7720_port->write_urb_pool[i];
++ dbg("URB:%d",i);
++ break;
++ }
++ }
++
++ if (urb == NULL) {
++ dbg("%s - no more free urbs", __FUNCTION__);
++ goto exit;
++ }
++
++ if (urb->transfer_buffer == NULL) {
++ urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
++ GFP_KERNEL);
++ if (urb->transfer_buffer == NULL) {
++ err("%s no more kernel memory...", __FUNCTION__);
++ goto exit;
++ }
++ }
++ transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
++
++ memcpy(urb->transfer_buffer, current_position, transfer_size);
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size,
++ urb->transfer_buffer);
++
++ /* fill urb with data and submit */
++ usb_fill_bulk_urb(urb, serial->dev,
++ usb_sndbulkpipe(serial->dev,
++ port->bulk_out_endpointAddress),
++ urb->transfer_buffer, transfer_size,
++ mos7720_bulk_out_data_callback, mos7720_port);
++
++ /* send it down the pipe */
++ status = usb_submit_urb(urb,GFP_ATOMIC);
++ if (status) {
++ err("%s - usb_submit_urb(write bulk) failed with status = %d",
++ __FUNCTION__, status);
++ bytes_sent = status;
++ goto exit;
++ }
++ bytes_sent = transfer_size;
++
++exit:
++ return bytes_sent;
++}
++
++static void mos7720_throttle(struct usb_serial_port *port)
++{
++ struct moschip_port *mos7720_port;
++ struct tty_struct *tty;
++ int status;
++
++ dbg("%s- port %d\n", __FUNCTION__, port->number);
++
++ mos7720_port = usb_get_serial_port_data(port);
++
++ if (mos7720_port == NULL)
++ return;
++
++ if (!mos7720_port->open) {
++ dbg("port not opened");
++ return;
++ }
++
++ dbg("%s: Entering ..........", __FUNCTION__);
++
++ tty = port->tty;
++ if (!tty) {
++ dbg("%s - no tty available", __FUNCTION__);
++ return;
++ }
++
++ /* if we are implementing XON/XOFF, send the stop character */
++ if (I_IXOFF(tty)) {
++ unsigned char stop_char = STOP_CHAR(tty);
++ status = mos7720_write(port, &stop_char, 1);
++ if (status <= 0)
++ return;
++ }
++
++ /* if we are implementing RTS/CTS, toggle that line */
++ if (tty->termios->c_cflag & CRTSCTS) {
++ mos7720_port->shadowMCR &= ~UART_MCR_RTS;
++ status = send_mos_cmd(port->serial, MOS_WRITE,
++ port->number - port->serial->minor,
++ UART_MCR, &mos7720_port->shadowMCR);
++ if (status != 0)
++ return;
++ }
++}
++
++static void mos7720_unthrottle(struct usb_serial_port *port)
++{
++ struct tty_struct *tty;
++ int status;
++ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
++
++ if (mos7720_port == NULL)
++ return;
++
++ if (!mos7720_port->open) {
++ dbg("%s - port not opened", __FUNCTION__);
++ return;
++ }
++
++ dbg("%s: Entering ..........", __FUNCTION__);
++
++ tty = port->tty;
++ if (!tty) {
++ dbg("%s - no tty available", __FUNCTION__);
++ return;
++ }
++
++ /* if we are implementing XON/XOFF, send the start character */
++ if (I_IXOFF(tty)) {
++ unsigned char start_char = START_CHAR(tty);
++ status = mos7720_write(port, &start_char, 1);
++ if (status <= 0)
++ return;
++ }
++
++ /* if we are implementing RTS/CTS, toggle that line */
++ if (tty->termios->c_cflag & CRTSCTS) {
++ mos7720_port->shadowMCR |= UART_MCR_RTS;
++ status = send_mos_cmd(port->serial, MOS_WRITE,
++ port->number - port->serial->minor,
++ UART_MCR, &mos7720_port->shadowMCR);
++ if (status != 0)
++ return;
++ }
++}
++
++static int set_higher_rates(struct moschip_port *mos7720_port,
++ unsigned int baud)
++{
++ unsigned char data;
++ struct usb_serial_port *port;
++ struct usb_serial *serial;
++ int port_number;
++
++ if (mos7720_port == NULL)
++ return -EINVAL;
++
++ port = mos7720_port->port;
++ serial = port->serial;
++
++ /***********************************************
++ * Init Sequence for higher rates
++ ***********************************************/
++ dbg("Sending Setting Commands ..........");
++ port_number = port->number - port->serial->minor;
++
++ data = 0x000;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
++ data = 0x000;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
++ data = 0x0CF;
++ send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
++ data = 0x00b;
++ mos7720_port->shadowMCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++ data = 0x00b;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++
++ data = 0x000;
++ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
++ data = 0x000;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
++
++
++ /***********************************************
++ * Set for higher rates *
++ ***********************************************/
++
++ data = baud * 0x10;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data);
++
++ data = 0x003;
++ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
++ data = 0x003;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
++
++ data = 0x02b;
++ mos7720_port->shadowMCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++ data = 0x02b;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++
++ /***********************************************
++ * Set DLL/DLM
++ ***********************************************/
++
++ data = mos7720_port->shadowLCR | UART_LCR_DLAB;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
++
++ data = 0x001; /* DLL */
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
++ data = 0x000; /* DLM */
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
++
++ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
++
++ return 0;
++}
++
++/* baud rate information */
++struct divisor_table_entry
++{
++ __u32 baudrate;
++ __u16 divisor;
++};
++
++/* Define table of divisors for moschip 7720 hardware *
++ * These assume a 3.6864MHz crystal, the standard /16, and *
++ * MCR.7 = 0. */
++static struct divisor_table_entry divisor_table[] = {
++ { 50, 2304},
++ { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */
++ { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */
++ { 150, 768},
++ { 300, 384},
++ { 600, 192},
++ { 1200, 96},
++ { 1800, 64},
++ { 2400, 48},
++ { 4800, 24},
++ { 7200, 16},
++ { 9600, 12},
++ { 19200, 6},
++ { 38400, 3},
++ { 57600, 2},
++ { 115200, 1},
++};
++
++/*****************************************************************************
++ * calc_baud_rate_divisor
++ * this function calculates the proper baud rate divisor for the specified
++ * baud rate.
++ *****************************************************************************/
++static int calc_baud_rate_divisor(int baudrate, int *divisor)
++{
++ int i;
++ __u16 custom;
++ __u16 round1;
++ __u16 round;
++
++
++ dbg("%s - %d", __FUNCTION__, baudrate);
++
++ for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
++ if (divisor_table[i].baudrate == baudrate) {
++ *divisor = divisor_table[i].divisor;
++ return 0;
++ }
++ }
++
++ /* After trying for all the standard baud rates *
++ * Try calculating the divisor for this baud rate */
++ if (baudrate > 75 && baudrate < 230400) {
++ /* get the divisor */
++ custom = (__u16)(230400L / baudrate);
++
++ /* Check for round off */
++ round1 = (__u16)(2304000L / baudrate);
++ round = (__u16)(round1 - (custom * 10));
++ if (round > 4)
++ custom++;
++ *divisor = custom;
++
++ dbg("Baud %d = %d",baudrate, custom);
++ return 0;
++ }
++
++ dbg("Baud calculation Failed...");
++ return -EINVAL;
++}
++
++/*
++ * send_cmd_write_baud_rate
++ * this function sends the proper command to change the baud rate of the
++ * specified port.
++ */
++static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
++ int baudrate)
++{
++ struct usb_serial_port *port;
++ struct usb_serial *serial;
++ int divisor;
++ int status;
++ unsigned char data;
++ unsigned char number;
++
++ if (mos7720_port == NULL)
++ return -1;
++
++ port = mos7720_port->port;
++ serial = port->serial;
++
++ dbg("%s: Entering ..........", __FUNCTION__);
++
++ number = port->number - port->serial->minor;
++ dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate);
++
++ /* Calculate the Divisor */
++ status = calc_baud_rate_divisor(baudrate, &divisor);
++ if (status) {
++ err("%s - bad baud rate", __FUNCTION__);
++ return status;
++ }
++
++ /* Enable access to divisor latch */
++ data = mos7720_port->shadowLCR | UART_LCR_DLAB;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
++
++ /* Write the divisor */
++ data = ((unsigned char)(divisor & 0xff));
++ send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
++
++ data = ((unsigned char)((divisor & 0xff00) >> 8));
++ send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
++
++ /* Disable access to divisor latch */
++ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
++ mos7720_port->shadowLCR = data;
++ send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
++
++ return status;
++}
++
++/*
++ * change_port_settings
++ * This routine is called to set the UART on the device to match
++ * the specified new settings.
++ */
++static void change_port_settings(struct moschip_port *mos7720_port,
++ struct termios *old_termios)
++{
++ struct usb_serial_port *port;
++ struct usb_serial *serial;
++ struct tty_struct *tty;
++ int baud;
++ unsigned cflag;
++ unsigned iflag;
++ __u8 mask = 0xff;
++ __u8 lData;
++ __u8 lParity;
++ __u8 lStop;
++ int status;
++ int port_number;
++ char data;
++
++ if (mos7720_port == NULL)
++ return ;
++
++ port = mos7720_port->port;
++ serial = port->serial;
++ port_number = port->number - port->serial->minor;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ if (!mos7720_port->open) {
++ dbg("%s - port not opened", __FUNCTION__);
++ return;
++ }
++
++ tty = mos7720_port->port->tty;
++
++ if ((!tty) || (!tty->termios)) {
++ dbg("%s - no tty structures", __FUNCTION__);
++ return;
++ }
++
++ dbg("%s: Entering ..........", __FUNCTION__);
++
++ lData = UART_LCR_WLEN8;
++ lStop = 0x00; /* 1 stop bit */
++ lParity = 0x00; /* No parity */
++
++ cflag = tty->termios->c_cflag;
++ iflag = tty->termios->c_iflag;
++
++ /* Change the number of bits */
++ switch (cflag & CSIZE) {
++ case CS5:
++ lData = UART_LCR_WLEN5;
++ mask = 0x1f;
++ break;
++
++ case CS6:
++ lData = UART_LCR_WLEN6;
++ mask = 0x3f;
++ break;
++
++ case CS7:
++ lData = UART_LCR_WLEN7;
++ mask = 0x7f;
++ break;
++ default:
++ case CS8:
++ lData = UART_LCR_WLEN8;
++ break;
++ }
++
++ /* Change the Parity bit */
++ if (cflag & PARENB) {
++ if (cflag & PARODD) {
++ lParity = UART_LCR_PARITY;
++ dbg("%s - parity = odd", __FUNCTION__);
++ } else {
++ lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
++ dbg("%s - parity = even", __FUNCTION__);
++ }
++
++ } else {
++ dbg("%s - parity = none", __FUNCTION__);
++ }
++
++ if (cflag & CMSPAR)
++ lParity = lParity | 0x20;
++
++ /* Change the Stop bit */
++ if (cflag & CSTOPB) {
++ lStop = UART_LCR_STOP;
++ dbg("%s - stop bits = 2", __FUNCTION__);
++ } else {
++ lStop = 0x00;
++ dbg("%s - stop bits = 1", __FUNCTION__);
++ }
++
++#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
++#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
++#define LCR_PAR_MASK 0x38 /* Mask for parity field */
++
++ /* Update the LCR with the correct value */
++ mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
++ mos7720_port->shadowLCR |= (lData | lParity | lStop);
++
++
++ /* Disable Interrupts */
++ data = 0x00;
++ send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data);
++
++ data = 0x00;
++ send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
++
++ data = 0xcf;
++ send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
++
++ /* Send the updated LCR value to the mos7720 */
++ data = mos7720_port->shadowLCR;
++ send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
++
++ data = 0x00b;
++ mos7720_port->shadowMCR = data;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++ data = 0x00b;
++ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
++
++ /* set up the MCR register and send it to the mos7720 */
++ mos7720_port->shadowMCR = UART_MCR_OUT2;
++ if (cflag & CBAUD)
++ mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
++
++ if (cflag & CRTSCTS) {
++ mos7720_port->shadowMCR |= (UART_MCR_XONANY);
++
++ /* To set hardware flow control to the specified *
++ * serial port, in SP1/2_CONTROL_REG */
++ if (port->number) {
++ data = 0x001;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
++ 0x08, &data);
++ } else {
++ data = 0x002;
++ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
++ 0x08, &data);
++ }
++ } else {
++ mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
++ }
++
++ data = mos7720_port->shadowMCR;
++ send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
++
++ /* Determine divisor based on baud rate */
++ baud = tty_get_baud_rate(tty);
++ if (!baud) {
++ /* pick a default, any default... */
++ dbg("Picked default baud...");
++ baud = 9600;
++ }
++
++ if (baud >= 230400) {
++ set_higher_rates(mos7720_port, baud);
++ /* Enable Interrupts */
++ data = 0x0c;
++ send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
++ return;
++ }
++
++ dbg("%s - baud rate = %d", __FUNCTION__, baud);
++ status = send_cmd_write_baud_rate(mos7720_port, baud);
++
++ /* Enable Interrupts */
++ data = 0x0c;
++ send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
++
++ if (port->read_urb->status != -EINPROGRESS) {
++ port->read_urb->dev = serial->dev;
++
++ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++ if (status)
++ dbg("usb_submit_urb(read bulk) failed, status = %d",
++ status);
++ }
++ return;
++}
++
++/*
++ * mos7720_set_termios
++ * this function is called by the tty driver when it wants to change the
++ * termios structure.
++ */
++static void mos7720_set_termios(struct usb_serial_port *port,
++ struct termios *old_termios)
++{
++ int status;
++ unsigned int cflag;
++ struct usb_serial *serial;
++ struct moschip_port *mos7720_port;
++ struct tty_struct *tty;
++
++ serial = port->serial;
++
++ mos7720_port = usb_get_serial_port_data(port);
++
++ if (mos7720_port == NULL)
++ return;
++
++ tty = port->tty;
++
++ if (!port->tty || !port->tty->termios) {
++ dbg("%s - no tty or termios", __FUNCTION__);
++ return;
++ }
++
++ if (!mos7720_port->open) {
++ dbg("%s - port not opened", __FUNCTION__);
++ return;
++ }
++
++ dbg("%s\n","setting termios - ASPIRE");
++
++ cflag = tty->termios->c_cflag;
++
++ if (!cflag) {
++ printk("%s %s\n",__FUNCTION__,"cflag is NULL");
++ return;
++ }
++
++ /* check that they really want us to change something */
++ if (old_termios) {
++ if ((cflag == old_termios->c_cflag) &&
++ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
++ RELEVANT_IFLAG(old_termios->c_iflag))) {
++ dbg("Nothing to change");
++ return;
++ }
++ }
++
++ dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
++ tty->termios->c_cflag,
++ RELEVANT_IFLAG(tty->termios->c_iflag));
++
++ if (old_termios)
++ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
++ old_termios->c_cflag,
++ RELEVANT_IFLAG(old_termios->c_iflag));
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* change the port settings to the new ones specified */
++ change_port_settings(mos7720_port, old_termios);
++
++ if(!port->read_urb) {
++ dbg("%s","URB KILLED !!!!!\n");
++ return;
++ }
++
++ if(port->read_urb->status != -EINPROGRESS) {
++ port->read_urb->dev = serial->dev;
++ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++ if (status)
++ dbg("usb_submit_urb(read bulk) failed, status = %d",
++ status);
++ }
++ return;
++}
++
++/*
++ * 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 moschip_port *mos7720_port,
++ unsigned int __user *value)
++{
++ int count;
++ unsigned int result = 0;
++
++ count = mos7720_chars_in_buffer(mos7720_port->port);
++ if (count == 0) {
++ dbg("%s -- Empty", __FUNCTION__);
++ result = TIOCSER_TEMT;
++ }
++
++ if (copy_to_user(value, &result, sizeof(int)))
++ return -EFAULT;
++ return 0;
++}
++
++/*
++ * get_number_bytes_avail - get number of bytes available
++ *
++ * Purpose: Let user call ioctl to get the count of number of bytes available.
++ */
++static int get_number_bytes_avail(struct moschip_port *mos7720_port,
++ unsigned int __user *value)
++{
++ unsigned int result = 0;
++ struct tty_struct *tty = mos7720_port->port->tty;
++
++ if (!tty)
++ return -ENOIOCTLCMD;
++
++ result = tty->read_cnt;
++
++ dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result);
++ if (copy_to_user(value, &result, sizeof(int)))
++ return -EFAULT;
++
++ return -ENOIOCTLCMD;
++}
++
++static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
++ unsigned int __user *value)
++{
++ unsigned int mcr ;
++ unsigned int arg;
++ unsigned char data;
++
++ struct usb_serial_port *port;
++
++ if (mos7720_port == NULL)
++ return -1;
++
++ port = (struct usb_serial_port*)mos7720_port->port;
++ mcr = mos7720_port->shadowMCR;
++
++ if (copy_from_user(&arg, value, sizeof(int)))
++ return -EFAULT;
++
++ switch (cmd) {
++ case TIOCMBIS:
++ if (arg & TIOCM_RTS)
++ mcr |= UART_MCR_RTS;
++ if (arg & TIOCM_DTR)
++ mcr |= UART_MCR_RTS;
++ if (arg & TIOCM_LOOP)
++ mcr |= UART_MCR_LOOP;
++ break;
++
++ case TIOCMBIC:
++ if (arg & TIOCM_RTS)
++ mcr &= ~UART_MCR_RTS;
++ if (arg & TIOCM_DTR)
++ mcr &= ~UART_MCR_RTS;
++ if (arg & TIOCM_LOOP)
++ mcr &= ~UART_MCR_LOOP;
++ break;
++
++ case TIOCMSET:
++ /* turn off the RTS and DTR and LOOPBACK
++ * and then only turn on what was asked to */
++ mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);
++ mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0);
++ mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
++ mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0);
++ break;
++ }
++
++ mos7720_port->shadowMCR = mcr;
++
++ data = mos7720_port->shadowMCR;
++ send_mos_cmd(port->serial, MOS_WRITE,
++ port->number - port->serial->minor, UART_MCR, &data);
++
++ return 0;
++}
++
++static int get_modem_info(struct moschip_port *mos7720_port,
++ unsigned int __user *value)
++{
++ unsigned int result = 0;
++ unsigned int msr = mos7720_port->shadowMSR;
++ unsigned int mcr = mos7720_port->shadowMCR;
++
++ result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */
++ | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */
++ | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */
++ | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */
++ | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */
++ | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
++
++
++ dbg("%s -- %x", __FUNCTION__, result);
++
++ if (copy_to_user(value, &result, sizeof(int)))
++ return -EFAULT;
++ return 0;
++}
++
++static int get_serial_info(struct moschip_port *mos7720_port,
++ struct serial_struct __user *retinfo)
++{
++ struct serial_struct tmp;
++
++ if (!retinfo)
++ return -EFAULT;
++
++ memset(&tmp, 0, sizeof(tmp));
++
++ tmp.type = PORT_16550A;
++ tmp.line = mos7720_port->port->serial->minor;
++ tmp.port = mos7720_port->port->number;
++ tmp.irq = 0;
++ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
++ tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
++ tmp.baud_base = 9600;
++ tmp.close_delay = 5*HZ;
++ tmp.closing_wait = 30*HZ;
++
++ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
++ return -EFAULT;
++ return 0;
++}
++
++static int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct moschip_port *mos7720_port;
++ struct async_icount cnow;
++ struct async_icount cprev;
++ struct serial_icounter_struct icount;
++
++ mos7720_port = usb_get_serial_port_data(port);
++ if (mos7720_port == NULL)
++ return -ENODEV;
++
++ dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
++
++ switch (cmd) {
++ case TIOCINQ:
++ /* return number of bytes available */
++ dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
++ return get_number_bytes_avail(mos7720_port,
++ (unsigned int __user *)arg);
++ break;
++
++ case TIOCSERGETLSR:
++ dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
++ return get_lsr_info(mos7720_port, (unsigned int __user *)arg);
++ return 0;
++
++ case TIOCMBIS:
++ case TIOCMBIC:
++ case TIOCMSET:
++ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
++ port->number);
++ return set_modem_info(mos7720_port, cmd,
++ (unsigned int __user *)arg);
++
++ case TIOCMGET:
++ dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
++ return get_modem_info(mos7720_port,
++ (unsigned int __user *)arg);
++
++ case TIOCGSERIAL:
++ dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
++ return get_serial_info(mos7720_port,
++ (struct serial_struct __user *)arg);
++
++ case TIOCSSERIAL:
++ dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
++ break;
++
++ case TIOCMIWAIT:
++ dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
++ cprev = mos7720_port->icount;
++ while (1) {
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++ cnow = mos7720_port->icount;
++ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
++ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
++ return -EIO; /* no change => error */
++ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
++ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
++ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
++ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
++ return 0;
++ }
++ cprev = cnow;
++ }
++ /* NOTREACHED */
++ break;
++
++ case TIOCGICOUNT:
++ cnow = mos7720_port->icount;
++ icount.cts = cnow.cts;
++ icount.dsr = cnow.dsr;
++ icount.rng = cnow.rng;
++ icount.dcd = cnow.dcd;
++ icount.rx = cnow.rx;
++ icount.tx = cnow.tx;
++ icount.frame = cnow.frame;
++ icount.overrun = cnow.overrun;
++ icount.parity = cnow.parity;
++ icount.brk = cnow.brk;
++ icount.buf_overrun = cnow.buf_overrun;
++
++ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
++ port->number, icount.rx, icount.tx );
++ if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
++ return -EFAULT;
++ return 0;
++ }
++
++ return -ENOIOCTLCMD;
++}
++
++static int mos7720_startup(struct usb_serial *serial)
++{
++ struct moschip_serial *mos7720_serial;
++ struct moschip_port *mos7720_port;
++ struct usb_device *dev;
++ int i;
++ char data;
++
++ dbg("%s: Entering ..........", __FUNCTION__);
++
++ if (!serial) {
++ dbg("Invalid Handler");
++ return -ENODEV;
++ }
++
++ dev = serial->dev;
++
++ /* create our private serial structure */
++ mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
++ if (mos7720_serial == NULL) {
++ err("%s - Out of memory", __FUNCTION__);
++ return -ENOMEM;
++ }
++
++ usb_set_serial_data(serial, mos7720_serial);
++
++ /* we set up the pointers to the endpoints in the mos7720_open *
++ * function, as the structures aren't created yet. */
++
++ /* set up port private structures */
++ for (i = 0; i < serial->num_ports; ++i) {
++ mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
++ if (mos7720_port == NULL) {
++ err("%s - Out of memory", __FUNCTION__);
++ usb_set_serial_data(serial, NULL);
++ kfree(mos7720_serial);
++ return -ENOMEM;
++ }
++
++ /* Initialize all port interrupt end point to port 0 int
++ * endpoint. Our device has only one interrupt endpoint
++ * comman to all ports */
++ serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
++
++ mos7720_port->port = serial->port[i];
++ usb_set_serial_port_data(serial->port[i], mos7720_port);
++
++ dbg("port number is %d", serial->port[i]->number);
++ dbg("serial number is %d", serial->minor);
++ }
++
++
++ /* setting configuration feature to one */
++ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
++ (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ);
++
++ send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1
++ dbg("LSR:%x",data);
++
++ send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2
++ dbg("LSR:%x",data);
++
++ return 0;
++}
++
++static void mos7720_shutdown(struct usb_serial *serial)
++{
++ int i;
++
++ /* free private structure allocated for serial port */
++ for (i=0; i < serial->num_ports; ++i) {
++ kfree(usb_get_serial_port_data(serial->port[i]));
++ usb_set_serial_port_data(serial->port[i], NULL);
++ }
++
++ /* free private structure allocated for serial device */
++ kfree(usb_get_serial_data(serial));
++ usb_set_serial_data(serial, NULL);
++}
++
++static struct usb_serial_driver moschip7720_2port_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "moschip7720",
++ },
++ .description = "Moschip 2 port adapter",
++ .id_table = moschip_port_id_table,
++ .num_interrupt_in = 1,
++ .num_bulk_in = 2,
++ .num_bulk_out = 2,
++ .num_ports = 2,
++ .open = mos7720_open,
++ .close = mos7720_close,
++ .throttle = mos7720_throttle,
++ .unthrottle = mos7720_unthrottle,
++ .attach = mos7720_startup,
++ .shutdown = mos7720_shutdown,
++ .ioctl = mos7720_ioctl,
++ .set_termios = mos7720_set_termios,
++ .write = mos7720_write,
++ .write_room = mos7720_write_room,
++ .chars_in_buffer = mos7720_chars_in_buffer,
++ .break_ctl = mos7720_break,
++ .read_bulk_callback = mos7720_bulk_in_callback,
++};
++
++static struct usb_driver usb_driver = {
++ .name = "moschip7720",
++ .probe = usb_serial_probe,
++ .disconnect = usb_serial_disconnect,
++ .id_table = moschip_port_id_table,
++};
++
++static int __init moschip7720_init(void)
++{
++ int retval;
++
++ dbg("%s: Entering ..........", __FUNCTION__);
++
++ /* Register with the usb serial */
++ retval = usb_serial_register(&moschip7720_2port_driver);
++ if (retval)
++ goto failed_port_device_register;
++
++ info(DRIVER_DESC " " DRIVER_VERSION);
++
++ /* Register with the usb */
++ retval = usb_register(&usb_driver);
++ if (retval)
++ goto failed_usb_register;
++
++ return 0;
++
++failed_usb_register:
++ usb_serial_deregister(&moschip7720_2port_driver);
++
++failed_port_device_register:
++ return retval;
++}
++
++static void __exit moschip7720_exit(void)
++{
++ usb_deregister(&usb_driver);
++ usb_serial_deregister(&moschip7720_2port_driver);
++}
++
++module_init(moschip7720_init);
++module_exit(moschip7720_exit);
++
++/* Module information */
++MODULE_AUTHOR( DRIVER_AUTHOR );
++MODULE_DESCRIPTION( DRIVER_DESC );
++MODULE_LICENSE("GPL");
++
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled or not");
+diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
+new file mode 100644
+index 0000000..5b71962
+--- /dev/null
++++ b/drivers/usb/serial/mos7840.c
+@@ -0,0 +1,2948 @@
++/*
++ * 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
++ *
++ * Clean ups from Moschip version and a few ioctl implementations by:
++ * Paul B Schroeder <pschroeder "at" uplogix "dot" com>
++ *
++ * Originally based on drivers/usb/serial/io_edgeport.c which is:
++ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
++ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg at kroah.com>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/module.h>
++#include <linux/serial.h>
++#include <linux/usb.h>
++#include <linux/usb/serial.h>
++#include <asm/uaccess.h>
++
++/*
++ * Version Information
++ */
++#define DRIVER_VERSION "1.3.1"
++#define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver"
++
++/*
++ * 16C50 UART register defines
++ */
++
++#define LCR_BITS_5 0x00 /* 5 bits/char */
++#define LCR_BITS_6 0x01 /* 6 bits/char */
++#define LCR_BITS_7 0x02 /* 7 bits/char */
++#define LCR_BITS_8 0x03 /* 8 bits/char */
++#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
++
++#define LCR_STOP_1 0x00 /* 1 stop bit */
++#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
++#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
++#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
++
++#define LCR_PAR_NONE 0x00 /* No parity */
++#define LCR_PAR_ODD 0x08 /* Odd parity */
++#define LCR_PAR_EVEN 0x18 /* Even parity */
++#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
++#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
++#define LCR_PAR_MASK 0x38 /* Mask for parity field */
++
++#define LCR_SET_BREAK 0x40 /* Set Break condition */
++#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
++
++#define MCR_DTR 0x01 /* Assert DTR */
++#define MCR_RTS 0x02 /* Assert RTS */
++#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
++#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
++#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
++#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
++
++#define MOS7840_MSR_CTS 0x10 /* Current state of CTS */
++#define MOS7840_MSR_DSR 0x20 /* Current state of DSR */
++#define MOS7840_MSR_RI 0x40 /* Current state of RI */
++#define MOS7840_MSR_CD 0x80 /* Current state of CD */
++
++/*
++ * Defines used for sending commands to port
++ */
++
++#define WAIT_FOR_EVER (HZ * 0 ) /* timeout urb is wait for ever */
++#define MOS_WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
++
++#define MOS_PORT1 0x0200
++#define MOS_PORT2 0x0300
++#define MOS_VENREG 0x0000
++#define MOS_MAX_PORT 0x02
++#define MOS_WRITE 0x0E
++#define MOS_READ 0x0D
++
++/* Requests */
++#define MCS_RD_RTYPE 0xC0
++#define MCS_WR_RTYPE 0x40
++#define MCS_RDREQ 0x0D
++#define MCS_WRREQ 0x0E
++#define MCS_CTRL_TIMEOUT 500
++#define VENDOR_READ_LENGTH (0x01)
++
++#define MAX_NAME_LEN 64
++
++#define ZLP_REG1 0x3A //Zero_Flag_Reg1 58
++#define ZLP_REG5 0x3E //Zero_Flag_Reg5 62
++
++/* For higher baud Rates use TIOCEXBAUD */
++#define TIOCEXBAUD 0x5462
++
++/* vendor id and device id defines */
++
++#define USB_VENDOR_ID_MOSCHIP 0x9710
++#define MOSCHIP_DEVICE_ID_7840 0x7840
++#define MOSCHIP_DEVICE_ID_7820 0x7820
++
++/* Interrupt Rotinue Defines */
++
++#define SERIAL_IIR_RLS 0x06
++#define SERIAL_IIR_MS 0x00
++
++/*
++ * Emulation of the bit mask on the LINE STATUS REGISTER.
++ */
++#define SERIAL_LSR_DR 0x0001
++#define SERIAL_LSR_OE 0x0002
++#define SERIAL_LSR_PE 0x0004
++#define SERIAL_LSR_FE 0x0008
++#define SERIAL_LSR_BI 0x0010
++
++#define MOS_MSR_DELTA_CTS 0x10
++#define MOS_MSR_DELTA_DSR 0x20
++#define MOS_MSR_DELTA_RI 0x40
++#define MOS_MSR_DELTA_CD 0x80
++
++// Serial Port register Address
++#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
++#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
++#define LINE_CONTROL_REGISTER ((__u16)(0x03))
++#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
++#define LINE_STATUS_REGISTER ((__u16)(0x05))
++#define MODEM_STATUS_REGISTER ((__u16)(0x06))
++#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
++#define DIVISOR_LATCH_LSB ((__u16)(0x00))
++#define DIVISOR_LATCH_MSB ((__u16)(0x01))
++
++#define CLK_MULTI_REGISTER ((__u16)(0x02))
++#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
++
++#define SERIAL_LCR_DLAB ((__u16)(0x0080))
++
++/*
++ * URB POOL related defines
++ */
++#define NUM_URBS 16 /* URB Count */
++#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
++
++
++static struct usb_device_id moschip_port_id_table[] = {
++ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
++ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
++ {} /* terminating entry */
++};
++
++static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
++ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
++ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
++ {} /* terminating entry */
++};
++
++MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
++
++/* This structure holds all of the local port information */
++
++struct moschip_port {
++ int port_num; /*Actual port number in the device(1,2,etc) */
++ struct urb *write_urb; /* write URB for this port */
++ struct urb *read_urb; /* read URB for this port */
++ __u8 shadowLCR; /* last LCR value received */
++ __u8 shadowMCR; /* last MCR value received */
++ char open;
++ wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
++ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
++ int delta_msr_cond;
++ struct async_icount icount;
++ struct usb_serial_port *port; /* loop back to the owner of this object */
++
++ /*Offsets */
++ __u8 SpRegOffset;
++ __u8 ControlRegOffset;
++ __u8 DcrRegOffset;
++ //for processing control URBS in interrupt context
++ struct urb *control_urb;
++ char *ctrl_buf;
++ int MsrLsr;
++
++ struct urb *write_urb_pool[NUM_URBS];
++};
++
++
++static int debug;
++static int mos7840_num_ports; //this says the number of ports in the device
++static int mos7840_num_open_ports;
++
++
++/*
++ * mos7840_set_reg_sync
++ * To set the Control register by calling usb_fill_control_urb function
++ * by passing usb_sndctrlpipe function as parameter.
++ */
++
++static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg,
++ __u16 val)
++{
++ struct usb_device *dev = port->serial->dev;
++ val = val & 0x00ff;
++ dbg("mos7840_set_reg_sync offset is %x, value %x\n", reg, val);
++
++ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
++ MCS_WR_RTYPE, val, reg, NULL, 0,
++ MOS_WDR_TIMEOUT);
++}
++
++/*
++ * mos7840_get_reg_sync
++ * To set the Uart register by calling usb_fill_control_urb function by
++ * passing usb_rcvctrlpipe function as parameter.
++ */
++
++static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
++ __u16 * val)
++{
++ struct usb_device *dev = port->serial->dev;
++ int ret = 0;
++
++ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
++ MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
++ MOS_WDR_TIMEOUT);
++ dbg("mos7840_get_reg_sync offset is %x, return val %x\n", reg, *val);
++ *val = (*val) & 0x00ff;
++ return ret;
++}
++
++/*
++ * mos7840_set_uart_reg
++ * To set the Uart register by calling usb_fill_control_urb function by
++ * passing usb_sndctrlpipe function as parameter.
++ */
++
++static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
++ __u16 val)
++{
++
++ struct usb_device *dev = port->serial->dev;
++ val = val & 0x00ff;
++ // For the UART control registers, the application number need to be Or'ed
++ if (mos7840_num_ports == 4) {
++ val |=
++ (((__u16) port->number - (__u16) (port->serial->minor)) +
++ 1) << 8;
++ dbg("mos7840_set_uart_reg application number is %x\n", val);
++ } else {
++ if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
++ val |=
++ (((__u16) port->number -
++ (__u16) (port->serial->minor)) + 1) << 8;
++ dbg("mos7840_set_uart_reg application number is %x\n",
++ val);
++ } else {
++ val |=
++ (((__u16) port->number -
++ (__u16) (port->serial->minor)) + 2) << 8;
++ dbg("mos7840_set_uart_reg application number is %x\n",
++ val);
++ }
++ }
++ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
++ MCS_WR_RTYPE, val, reg, NULL, 0,
++ MOS_WDR_TIMEOUT);
++
++}
++
++/*
++ * mos7840_get_uart_reg
++ * To set the Control register by calling usb_fill_control_urb function
++ * by passing usb_rcvctrlpipe function as parameter.
++ */
++static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
++ __u16 * val)
++{
++ struct usb_device *dev = port->serial->dev;
++ int ret = 0;
++ __u16 Wval;
++
++ //dbg("application number is %4x \n",(((__u16)port->number - (__u16)(port->serial->minor))+1)<<8);
++ /*Wval is same as application number */
++ if (mos7840_num_ports == 4) {
++ Wval =
++ (((__u16) port->number - (__u16) (port->serial->minor)) +
++ 1) << 8;
++ dbg("mos7840_get_uart_reg application number is %x\n", Wval);
++ } else {
++ if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
++ Wval =
++ (((__u16) port->number -
++ (__u16) (port->serial->minor)) + 1) << 8;
++ dbg("mos7840_get_uart_reg application number is %x\n",
++ Wval);
++ } else {
++ Wval =
++ (((__u16) port->number -
++ (__u16) (port->serial->minor)) + 2) << 8;
++ dbg("mos7840_get_uart_reg application number is %x\n",
++ Wval);
++ }
++ }
++ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
++ MCS_RD_RTYPE, Wval, reg, val, VENDOR_READ_LENGTH,
++ MOS_WDR_TIMEOUT);
++ *val = (*val) & 0x00ff;
++ return ret;
++}
++
++static void mos7840_dump_serial_port(struct moschip_port *mos7840_port)
++{
++
++ dbg("***************************************\n");
++ dbg("SpRegOffset is %2x\n", mos7840_port->SpRegOffset);
++ dbg("ControlRegOffset is %2x \n", mos7840_port->ControlRegOffset);
++ dbg("DCRRegOffset is %2x \n", mos7840_port->DcrRegOffset);
++ dbg("***************************************\n");
++
++}
++
++/************************************************************************/
++/************************************************************************/
++/* I N T E R F A C E F U N C T I O N S */
++/* I N T E R F A C E F U N C T I O N S */
++/************************************************************************/
++/************************************************************************/
++
++static inline void mos7840_set_port_private(struct usb_serial_port *port,
++ struct moschip_port *data)
++{
++ usb_set_serial_port_data(port, (void *)data);
++}
++
++static inline struct moschip_port *mos7840_get_port_private(struct
++ usb_serial_port
++ *port)
++{
++ return (struct moschip_port *)usb_get_serial_port_data(port);
++}
++
++static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
++{
++ struct moschip_port *mos7840_port;
++ struct async_icount *icount;
++ mos7840_port = port;
++ icount = &mos7840_port->icount;
++ if (new_msr &
++ (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
++ MOS_MSR_DELTA_CD)) {
++ icount = &mos7840_port->icount;
++
++ /* update input line counters */
++ if (new_msr & MOS_MSR_DELTA_CTS) {
++ icount->cts++;
++ }
++ if (new_msr & MOS_MSR_DELTA_DSR) {
++ icount->dsr++;
++ }
++ if (new_msr & MOS_MSR_DELTA_CD) {
++ icount->dcd++;
++ }
++ if (new_msr & MOS_MSR_DELTA_RI) {
++ icount->rng++;
++ }
++ }
++
++ return 0;
++}
++
++static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
++{
++ struct async_icount *icount;
++
++ dbg("%s - %02x", __FUNCTION__, new_lsr);
++
++ if (new_lsr & SERIAL_LSR_BI) {
++ //
++ // Parity and Framing errors only count if they
++ // occur exclusive of a break being
++ // received.
++ //
++ new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
++ }
++
++ /* update input line counters */
++ icount = &port->icount;
++ if (new_lsr & SERIAL_LSR_BI) {
++ icount->brk++;
++ }
++ if (new_lsr & SERIAL_LSR_OE) {
++ icount->overrun++;
++ }
++ if (new_lsr & SERIAL_LSR_PE) {
++ icount->parity++;
++ }
++ if (new_lsr & SERIAL_LSR_FE) {
++ icount->frame++;
++ }
++
++ return 0;
++}
++
++/************************************************************************/
++/************************************************************************/
++/* U S B C A L L B A C K F U N C T I O N S */
++/* U S B C A L L B A C K F U N C T I O N S */
++/************************************************************************/
++/************************************************************************/
++
++static void mos7840_control_callback(struct urb *urb)
++{
++ unsigned char *data;
++ struct moschip_port *mos7840_port;
++ __u8 regval = 0x0;
++
++ if (!urb) {
++ dbg("%s", "Invalid Pointer !!!!:\n");
++ return;
++ }
++
++ 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;
++ }
++
++ mos7840_port = (struct moschip_port *)urb->context;
++
++ dbg("%s urb buffer size is %d\n", __FUNCTION__, urb->actual_length);
++ dbg("%s mos7840_port->MsrLsr is %d port %d\n", __FUNCTION__,
++ mos7840_port->MsrLsr, mos7840_port->port_num);
++ data = urb->transfer_buffer;
++ regval = (__u8) data[0];
++ dbg("%s data is %x\n", __FUNCTION__, regval);
++ if (mos7840_port->MsrLsr == 0)
++ mos7840_handle_new_msr(mos7840_port, regval);
++ else if (mos7840_port->MsrLsr == 1)
++ mos7840_handle_new_lsr(mos7840_port, regval);
++
++ exit:
++ return;
++}
++
++static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
++ __u16 * val)
++{
++ struct usb_device *dev = mcs->port->serial->dev;
++ struct usb_ctrlrequest *dr = NULL;
++ unsigned char *buffer = NULL;
++ int ret = 0;
++ buffer = (__u8 *) mcs->ctrl_buf;
++
++// dr=(struct usb_ctrlrequest *)(buffer);
++ dr = (void *)(buffer + 2);
++ dr->bRequestType = MCS_RD_RTYPE;
++ dr->bRequest = MCS_RDREQ;
++ dr->wValue = cpu_to_le16(Wval); //0;
++ dr->wIndex = cpu_to_le16(reg);
++ dr->wLength = cpu_to_le16(2);
++
++ usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0),
++ (unsigned char *)dr, buffer, 2,
++ mos7840_control_callback, mcs);
++ mcs->control_urb->transfer_buffer_length = 2;
++ ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
++ return ret;
++}
++
++/*****************************************************************************
++ * mos7840_interrupt_callback
++ * this is the callback function for when we have received data on the
++ * interrupt endpoint.
++ *****************************************************************************/
++
++static void mos7840_interrupt_callback(struct urb *urb)
++{
++ int result;
++ int length;
++ struct moschip_port *mos7840_port;
++ struct usb_serial *serial;
++ __u16 Data;
++ unsigned char *data;
++ __u8 sp[5], st;
++ int i;
++ __u16 wval;
++
++ dbg("%s", " : Entering\n");
++ if (!urb) {
++ dbg("%s", "Invalid Pointer !!!!:\n");
++ return;
++ }
++
++ 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;
++ }
++
++ length = urb->actual_length;
++ data = urb->transfer_buffer;
++
++ serial = (struct usb_serial *)urb->context;
++
++ /* Moschip get 5 bytes
++ * Byte 1 IIR Port 1 (port.number is 0)
++ * Byte 2 IIR Port 2 (port.number is 1)
++ * Byte 3 IIR Port 3 (port.number is 2)
++ * Byte 4 IIR Port 4 (port.number is 3)
++ * Byte 5 FIFO status for both */
++
++ if (length && length > 5) {
++ dbg("%s \n", "Wrong data !!!");
++ return;
++ }
++
++ sp[0] = (__u8) data[0];
++ sp[1] = (__u8) data[1];
++ sp[2] = (__u8) data[2];
++ sp[3] = (__u8) data[3];
++ st = (__u8) data[4];
++
++ for (i = 0; i < serial->num_ports; i++) {
++ mos7840_port = mos7840_get_port_private(serial->port[i]);
++ wval =
++ (((__u16) serial->port[i]->number -
++ (__u16) (serial->minor)) + 1) << 8;
++ if (mos7840_port->open) {
++ if (sp[i] & 0x01) {
++ dbg("SP%d No Interrupt !!!\n", i);
++ } else {
++ switch (sp[i] & 0x0f) {
++ case SERIAL_IIR_RLS:
++ dbg("Serial Port %d: Receiver status error or ", i);
++ dbg("address bit detected in 9-bit mode\n");
++ mos7840_port->MsrLsr = 1;
++ mos7840_get_reg(mos7840_port, wval,
++ LINE_STATUS_REGISTER,
++ &Data);
++ break;
++ case SERIAL_IIR_MS:
++ dbg("Serial Port %d: Modem status change\n", i);
++ mos7840_port->MsrLsr = 0;
++ mos7840_get_reg(mos7840_port, wval,
++ MODEM_STATUS_REGISTER,
++ &Data);
++ break;
++ }
++ }
++ }
++ }
++ exit:
++ result = usb_submit_urb(urb, GFP_ATOMIC);
++ if (result) {
++ dev_err(&urb->dev->dev,
++ "%s - Error %d submitting interrupt urb\n",
++ __FUNCTION__, result);
++ }
++
++ return;
++
++}
++
++static int mos7840_port_paranoia_check(struct usb_serial_port *port,
++ const char *function)
++{
++ if (!port) {
++ dbg("%s - port == NULL", function);
++ return -1;
++ }
++ if (!port->serial) {
++ dbg("%s - port->serial == NULL", function);
++ return -1;
++ }
++
++ return 0;
++}
++
++/* Inline functions to check the sanity of a pointer that is passed to us */
++static int mos7840_serial_paranoia_check(struct usb_serial *serial,
++ const char *function)
++{
++ if (!serial) {
++ dbg("%s - serial == NULL", function);
++ return -1;
++ }
++ if (!serial->type) {
++ dbg("%s - serial->type == NULL!", function);
++ return -1;
++ }
++
++ return 0;
++}
++
++static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
++ const char *function)
++{
++ /* if no port was specified, or it fails a paranoia check */
++ if (!port ||
++ mos7840_port_paranoia_check(port, function) ||
++ mos7840_serial_paranoia_check(port->serial, function)) {
++ /* then say that we don't have a valid usb_serial thing, which will * end up genrating -ENODEV return values */
++ return NULL;
++ }
++
++ return port->serial;
++}
++
++/*****************************************************************************
++ * mos7840_bulk_in_callback
++ * this is the callback function for when we have received data on the
++ * bulk in endpoint.
++ *****************************************************************************/
++
++static void mos7840_bulk_in_callback(struct urb *urb)
++{
++ int status;
++ unsigned char *data;
++ struct usb_serial *serial;
++ struct usb_serial_port *port;
++ struct moschip_port *mos7840_port;
++ struct tty_struct *tty;
++
++ if (!urb) {
++ dbg("%s", "Invalid Pointer !!!!:\n");
++ return;
++ }
++
++ if (urb->status) {
++ dbg("nonzero read bulk status received: %d", urb->status);
++ return;
++ }
++
++ mos7840_port = (struct moschip_port *)urb->context;
++ if (!mos7840_port) {
++ dbg("%s", "NULL mos7840_port pointer \n");
++ return;
++ }
++
++ port = (struct usb_serial_port *)mos7840_port->port;
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Port Paranoia failed \n");
++ return;
++ }
++
++ serial = mos7840_get_usb_serial(port, __FUNCTION__);
++ if (!serial) {
++ dbg("%s\n", "Bad serial pointer ");
++ return;
++ }
++
++ dbg("%s\n", "Entering... \n");
++
++ data = urb->transfer_buffer;
++
++ dbg("%s", "Entering ........... \n");
++
++ if (urb->actual_length) {
++ tty = mos7840_port->port->tty;
++ if (tty) {
++ tty_buffer_request_room(tty, urb->actual_length);
++ tty_insert_flip_string(tty, data, urb->actual_length);
++ dbg(" %s \n", data);
++ tty_flip_buffer_push(tty);
++ }
++ mos7840_port->icount.rx += urb->actual_length;
++ dbg("mos7840_port->icount.rx is %d:\n",
++ mos7840_port->icount.rx);
++ }
++
++ if (!mos7840_port->read_urb) {
++ dbg("%s", "URB KILLED !!!\n");
++ return;
++ }
++
++ if (mos7840_port->read_urb->status != -EINPROGRESS) {
++ mos7840_port->read_urb->dev = serial->dev;
++
++ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
++
++ if (status) {
++ dbg(" usb_submit_urb(read bulk) failed, status = %d",
++ status);
++ }
++ }
++}
++
++/*****************************************************************************
++ * mos7840_bulk_out_data_callback
++ * this is the callback function for when we have finished sending serial data
++ * on the bulk out endpoint.
++ *****************************************************************************/
++
++static void mos7840_bulk_out_data_callback(struct urb *urb)
++{
++ struct moschip_port *mos7840_port;
++ struct tty_struct *tty;
++ if (!urb) {
++ dbg("%s", "Invalid Pointer !!!!:\n");
++ return;
++ }
++
++ if (urb->status) {
++ dbg("nonzero write bulk status received:%d\n", urb->status);
++ return;
++ }
++
++ mos7840_port = (struct moschip_port *)urb->context;
++ if (!mos7840_port) {
++ dbg("%s", "NULL mos7840_port pointer \n");
++ return;
++ }
++
++ if (mos7840_port_paranoia_check(mos7840_port->port, __FUNCTION__)) {
++ dbg("%s", "Port Paranoia failed \n");
++ return;
++ }
++
++ dbg("%s \n", "Entering .........");
++
++ tty = mos7840_port->port->tty;
++
++ if (tty && mos7840_port->open) {
++ /* let the tty driver wakeup if it has a special *
++ * write_wakeup function */
++
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
++ && tty->ldisc.write_wakeup) {
++ (tty->ldisc.write_wakeup) (tty);
++ }
++
++ /* tell the tty driver that something has changed */
++ wake_up_interruptible(&tty->write_wait);
++ }
++
++}
++
++/************************************************************************/
++/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
++/************************************************************************/
++#ifdef MCSSerialProbe
++static int mos7840_serial_probe(struct usb_serial *serial,
++ const struct usb_device_id *id)
++{
++
++ /*need to implement the mode_reg reading and updating\
++ structures usb_serial_ device_type\
++ (i.e num_ports, num_bulkin,bulkout etc) */
++ /* Also we can update the changes attach */
++ return 1;
++}
++#endif
++
++/*****************************************************************************
++ * mos7840_open
++ * this function is called by the tty driver when a port is opened
++ * If successful, we return 0
++ * Otherwise we return a negative error number.
++ *****************************************************************************/
++
++static int mos7840_open(struct usb_serial_port *port, struct file *filp)
++{
++ int response;
++ int j;
++ struct usb_serial *serial;
++ struct urb *urb;
++ __u16 Data;
++ int status;
++ struct moschip_port *mos7840_port;
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Port Paranoia failed \n");
++ return -ENODEV;
++ }
++
++ mos7840_num_open_ports++;
++ serial = port->serial;
++
++ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
++ dbg("%s", "Serial Paranoia failed \n");
++ return -ENODEV;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL)
++ return -ENODEV;
++
++ usb_clear_halt(serial->dev, port->write_urb->pipe);
++ usb_clear_halt(serial->dev, port->read_urb->pipe);
++
++ /* Initialising the write urb pool */
++ for (j = 0; j < NUM_URBS; ++j) {
++ urb = usb_alloc_urb(0, SLAB_ATOMIC);
++ mos7840_port->write_urb_pool[j] = urb;
++
++ if (urb == NULL) {
++ err("No more urbs???");
++ continue;
++ }
++
++ urb->transfer_buffer = NULL;
++ urb->transfer_buffer =
++ kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
++ if (!urb->transfer_buffer) {
++ err("%s-out of memory for urb buffers.", __FUNCTION__);
++ continue;
++ }
++ }
++
++/*****************************************************************************
++ * Initialize MCS7840 -- Write Init values to corresponding Registers
++ *
++ * Register Index
++ * 1 : IER
++ * 2 : FCR
++ * 3 : LCR
++ * 4 : MCR
++ *
++ * 0x08 : SP1/2 Control Reg
++ *****************************************************************************/
++
++//NEED to check the following Block
++
++ status = 0;
++ Data = 0x0;
++ status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
++ if (status < 0) {
++ dbg("Reading Spreg failed\n");
++ return -1;
++ }
++ Data |= 0x80;
++ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
++ if (status < 0) {
++ dbg("writing Spreg failed\n");
++ return -1;
++ }
++
++ Data &= ~0x80;
++ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
++ if (status < 0) {
++ dbg("writing Spreg failed\n");
++ return -1;
++ }
++//End of block to be checked
++
++ status = 0;
++ Data = 0x0;
++ status =
++ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
++ if (status < 0) {
++ dbg("Reading Controlreg failed\n");
++ return -1;
++ }
++ Data |= 0x08; //Driver done bit
++ Data |= 0x20; //rx_disable
++ status = 0;
++ status =
++ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
++ if (status < 0) {
++ dbg("writing Controlreg failed\n");
++ return -1;
++ }
++ //do register settings here
++ // Set all regs to the device default values.
++ ////////////////////////////////////
++ // First Disable all interrupts.
++ ////////////////////////////////////
++
++ Data = 0x00;
++ status = 0;
++ status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
++ if (status < 0) {
++ dbg("disableing interrupts failed\n");
++ return -1;
++ }
++ // Set FIFO_CONTROL_REGISTER to the default value
++ Data = 0x00;
++ status = 0;
++ status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
++ if (status < 0) {
++ dbg("Writing FIFO_CONTROL_REGISTER failed\n");
++ return -1;
++ }
++
++ Data = 0xcf;
++ status = 0;
++ status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
++ if (status < 0) {
++ dbg("Writing FIFO_CONTROL_REGISTER failed\n");
++ return -1;
++ }
++
++ Data = 0x03;
++ status = 0;
++ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++ mos7840_port->shadowLCR = Data;
++
++ Data = 0x0b;
++ status = 0;
++ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++ mos7840_port->shadowMCR = Data;
++
++ Data = 0x00;
++ status = 0;
++ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
++ mos7840_port->shadowLCR = Data;
++
++ Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
++ status = 0;
++ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++
++ Data = 0x0c;
++ status = 0;
++ status = mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
++
++ Data = 0x0;
++ status = 0;
++ status = mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
++
++ Data = 0x00;
++ status = 0;
++ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
++
++ Data = Data & ~SERIAL_LCR_DLAB;
++ status = 0;
++ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++ mos7840_port->shadowLCR = Data;
++
++ //clearing Bulkin and Bulkout Fifo
++ Data = 0x0;
++ status = 0;
++ status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
++
++ Data = Data | 0x0c;
++ status = 0;
++ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
++
++ Data = Data & ~0x0c;
++ status = 0;
++ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
++ //Finally enable all interrupts
++ Data = 0x0;
++ Data = 0x0c;
++ status = 0;
++ status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
++
++ //clearing rx_disable
++ Data = 0x0;
++ status = 0;
++ status =
++ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
++ Data = Data & ~0x20;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
++
++ // rx_negate
++ Data = 0x0;
++ status = 0;
++ status =
++ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
++ Data = Data | 0x10;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
++
++ /* force low_latency on so that our tty_push actually forces *
++ * the data through,otherwise it is scheduled, and with *
++ * high data rates (like with OHCI) data can get lost. */
++
++ if (port->tty)
++ port->tty->low_latency = 1;
++/* Check to see if we've set up our endpoint info yet *
++ * (can't set it up in mos7840_startup as the structures *
++ * were not set up at that time.) */
++ if (mos7840_num_open_ports == 1) {
++ if (serial->port[0]->interrupt_in_buffer == NULL) {
++
++ /* set up interrupt urb */
++
++ usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
++ serial->dev,
++ usb_rcvintpipe(serial->dev,
++ serial->port[0]->
++ interrupt_in_endpointAddress),
++ serial->port[0]->interrupt_in_buffer,
++ serial->port[0]->interrupt_in_urb->
++ transfer_buffer_length,
++ mos7840_interrupt_callback,
++ serial,
++ serial->port[0]->interrupt_in_urb->
++ interval);
++
++ /* start interrupt read for mos7840 *
++ * will continue as long as mos7840 is connected */
++
++ response =
++ usb_submit_urb(serial->port[0]->interrupt_in_urb,
++ GFP_KERNEL);
++ if (response) {
++ err("%s - Error %d submitting interrupt urb",
++ __FUNCTION__, response);
++ }
++
++ }
++
++ }
++
++ /* see if we've set up our endpoint info yet *
++ * (can't set it up in mos7840_startup as the *
++ * structures were not set up at that time.) */
++
++ dbg("port number is %d \n", port->number);
++ dbg("serial number is %d \n", port->serial->minor);
++ dbg("Bulkin endpoint is %d \n", port->bulk_in_endpointAddress);
++ dbg("BulkOut endpoint is %d \n", port->bulk_out_endpointAddress);
++ dbg("Interrupt endpoint is %d \n", port->interrupt_in_endpointAddress);
++ dbg("port's number in the device is %d\n", mos7840_port->port_num);
++ mos7840_port->read_urb = port->read_urb;
++
++ /* set up our bulk in urb */
++
++ usb_fill_bulk_urb(mos7840_port->read_urb,
++ serial->dev,
++ usb_rcvbulkpipe(serial->dev,
++ port->bulk_in_endpointAddress),
++ port->bulk_in_buffer,
++ mos7840_port->read_urb->transfer_buffer_length,
++ mos7840_bulk_in_callback, mos7840_port);
++
++ dbg("mos7840_open: bulkin endpoint is %d\n",
++ port->bulk_in_endpointAddress);
++ response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
++ if (response) {
++ err("%s - Error %d submitting control urb", __FUNCTION__,
++ response);
++ }
++
++ /* initialize our wait queues */
++ init_waitqueue_head(&mos7840_port->wait_chase);
++ init_waitqueue_head(&mos7840_port->delta_msr_wait);
++
++ /* initialize our icount structure */
++ memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
++
++ /* initialize our port settings */
++ mos7840_port->shadowMCR = MCR_MASTER_IE; /* Must set to enable ints! */
++ /* send a open port command */
++ mos7840_port->open = 1;
++ //mos7840_change_port_settings(mos7840_port,old_termios);
++ mos7840_port->icount.tx = 0;
++ mos7840_port->icount.rx = 0;
++
++ dbg("\n\nusb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p\n\n", serial, mos7840_port, port);
++
++ return 0;
++
++}
++
++/*****************************************************************************
++ * mos7840_chars_in_buffer
++ * this function is called by the tty driver when it wants to know how many
++ * bytes of data we currently have outstanding in the port (data that has
++ * been written, but hasn't made it out the port yet)
++ * If successful, we return the number of bytes left to be written in the
++ * system,
++ * Otherwise we return a negative error number.
++ *****************************************************************************/
++
++static int mos7840_chars_in_buffer(struct usb_serial_port *port)
++{
++ int i;
++ int chars = 0;
++ struct moschip_port *mos7840_port;
++
++ dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return -1;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++ if (mos7840_port == NULL) {
++ dbg("%s \n", "mos7840_break:leaving ...........");
++ return -1;
++ }
++
++ for (i = 0; i < NUM_URBS; ++i) {
++ if (mos7840_port->write_urb_pool[i]->status == -EINPROGRESS) {
++ chars += URB_TRANSFER_BUFFER_SIZE;
++ }
++ }
++ dbg("%s - returns %d", __FUNCTION__, chars);
++ return (chars);
++
++}
++
++/************************************************************************
++ *
++ * mos7840_block_until_tx_empty
++ *
++ * This function will block the close until one of the following:
++ * 1. TX count are 0
++ * 2. The mos7840 has stopped
++ * 3. A timout of 3 seconds without activity has expired
++ *
++ ************************************************************************/
++static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
++{
++ int timeout = HZ / 10;
++ int wait = 30;
++ int count;
++
++ while (1) {
++
++ count = mos7840_chars_in_buffer(mos7840_port->port);
++
++ /* Check for Buffer status */
++ if (count <= 0) {
++ return;
++ }
++
++ /* Block the thread for a while */
++ interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
++ timeout);
++
++ /* No activity.. count down section */
++ wait--;
++ if (wait == 0) {
++ dbg("%s - TIMEOUT", __FUNCTION__);
++ return;
++ } else {
++ /* Reset timout value back to seconds */
++ wait = 30;
++ }
++ }
++}
++
++/*****************************************************************************
++ * mos7840_close
++ * this function is called by the tty driver when a port is closed
++ *****************************************************************************/
++
++static void mos7840_close(struct usb_serial_port *port, struct file *filp)
++{
++ struct usb_serial *serial;
++ struct moschip_port *mos7840_port;
++ int j;
++ __u16 Data;
++
++ dbg("%s\n", "mos7840_close:entering...");
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Port Paranoia failed \n");
++ return;
++ }
++
++ serial = mos7840_get_usb_serial(port, __FUNCTION__);
++ if (!serial) {
++ dbg("%s", "Serial Paranoia failed \n");
++ return;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL) {
++ return;
++ }
++
++ for (j = 0; j < NUM_URBS; ++j)
++ usb_kill_urb(mos7840_port->write_urb_pool[j]);
++
++ /* Freeing Write URBs */
++ for (j = 0; j < NUM_URBS; ++j) {
++ if (mos7840_port->write_urb_pool[j]) {
++ if (mos7840_port->write_urb_pool[j]->transfer_buffer)
++ kfree(mos7840_port->write_urb_pool[j]->
++ transfer_buffer);
++
++ usb_free_urb(mos7840_port->write_urb_pool[j]);
++ }
++ }
++
++ if (serial->dev) {
++ /* flush and block until tx is empty */
++ mos7840_block_until_tx_empty(mos7840_port);
++ }
++
++ /* While closing port, shutdown all bulk read, write *
++ * and interrupt read if they exists */
++ if (serial->dev) {
++
++ if (mos7840_port->write_urb) {
++ dbg("%s", "Shutdown bulk write\n");
++ usb_kill_urb(mos7840_port->write_urb);
++ }
++
++ if (mos7840_port->read_urb) {
++ dbg("%s", "Shutdown bulk read\n");
++ usb_kill_urb(mos7840_port->read_urb);
++ }
++ if ((&mos7840_port->control_urb)) {
++ dbg("%s", "Shutdown control read\n");
++ // usb_kill_urb (mos7840_port->control_urb);
++
++ }
++ }
++// if(mos7840_port->ctrl_buf != NULL)
++// kfree(mos7840_port->ctrl_buf);
++ mos7840_num_open_ports--;
++ dbg("mos7840_num_open_ports in close%d:in port%d\n",
++ mos7840_num_open_ports, port->number);
++ if (mos7840_num_open_ports == 0) {
++ if (serial->port[0]->interrupt_in_urb) {
++ dbg("%s", "Shutdown interrupt_in_urb\n");
++ }
++ }
++
++ if (mos7840_port->write_urb) {
++ /* if this urb had a transfer buffer already (old tx) free it */
++
++ if (mos7840_port->write_urb->transfer_buffer != NULL) {
++ kfree(mos7840_port->write_urb->transfer_buffer);
++ }
++ usb_free_urb(mos7840_port->write_urb);
++ }
++
++ Data = 0x0;
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++
++ Data = 0x00;
++ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
++
++ mos7840_port->open = 0;
++
++ dbg("%s \n", "Leaving ............");
++}
++
++/************************************************************************
++ *
++ * mos7840_block_until_chase_response
++ *
++ * This function will block the close until one of the following:
++ * 1. Response to our Chase comes from mos7840
++ * 2. A timout of 10 seconds without activity has expired
++ * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
++ *
++ ************************************************************************/
++
++static void mos7840_block_until_chase_response(struct moschip_port
++ *mos7840_port)
++{
++ int timeout = 1 * HZ;
++ int wait = 10;
++ int count;
++
++ while (1) {
++ count = mos7840_chars_in_buffer(mos7840_port->port);
++
++ /* Check for Buffer status */
++ if (count <= 0) {
++ return;
++ }
++
++ /* Block the thread for a while */
++ interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
++ timeout);
++ /* No activity.. count down section */
++ wait--;
++ if (wait == 0) {
++ dbg("%s - TIMEOUT", __FUNCTION__);
++ return;
++ } else {
++ /* Reset timout value back to seconds */
++ wait = 10;
++ }
++ }
++
++}
++
++/*****************************************************************************
++ * mos7840_break
++ * this function sends a break to the port
++ *****************************************************************************/
++static void mos7840_break(struct usb_serial_port *port, int break_state)
++{
++ unsigned char data;
++ struct usb_serial *serial;
++ struct moschip_port *mos7840_port;
++
++ dbg("%s \n", "Entering ...........");
++ dbg("mos7840_break: Start\n");
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Port Paranoia failed \n");
++ return;
++ }
++
++ serial = mos7840_get_usb_serial(port, __FUNCTION__);
++ if (!serial) {
++ dbg("%s", "Serial Paranoia failed \n");
++ return;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL) {
++ return;
++ }
++
++ if (serial->dev) {
++
++ /* flush and block until tx is empty */
++ mos7840_block_until_chase_response(mos7840_port);
++ }
++
++ if (break_state == -1) {
++ data = mos7840_port->shadowLCR | LCR_SET_BREAK;
++ } else {
++ data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
++ }
++
++ mos7840_port->shadowLCR = data;
++ dbg("mcs7840_break mos7840_port->shadowLCR is %x\n",
++ mos7840_port->shadowLCR);
++ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
++ mos7840_port->shadowLCR);
++
++ return;
++}
++
++/*****************************************************************************
++ * mos7840_write_room
++ * this function is called by the tty driver when it wants to know how many
++ * bytes of data we can accept for a specific port.
++ * If successful, we return the amount of room that we have for this port
++ * Otherwise we return a negative error number.
++ *****************************************************************************/
++
++static int mos7840_write_room(struct usb_serial_port *port)
++{
++ int i;
++ int room = 0;
++ struct moschip_port *mos7840_port;
++
++ dbg("%s \n", " mos7840_write_room:entering ...........");
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ dbg("%s \n", " mos7840_write_room:leaving ...........");
++ return -1;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++ if (mos7840_port == NULL) {
++ dbg("%s \n", "mos7840_break:leaving ...........");
++ return -1;
++ }
++
++ for (i = 0; i < NUM_URBS; ++i) {
++ if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
++ room += URB_TRANSFER_BUFFER_SIZE;
++ }
++ }
++
++ dbg("%s - returns %d", __FUNCTION__, room);
++ return (room);
++
++}
++
++/*****************************************************************************
++ * mos7840_write
++ * this function is called by the tty driver when data should be written to
++ * the port.
++ * If successful, we return the number of bytes written, otherwise we
++ * return a negative error number.
++ *****************************************************************************/
++
++static int mos7840_write(struct usb_serial_port *port,
++ const unsigned char *data, int count)
++{
++ int status;
++ int i;
++ int bytes_sent = 0;
++ int transfer_size;
++
++ struct moschip_port *mos7840_port;
++ struct usb_serial *serial;
++ struct urb *urb;
++ //__u16 Data;
++ const unsigned char *current_position = data;
++ unsigned char *data1;
++ dbg("%s \n", "entering ...........");
++ //dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",mos7840_port->shadowLCR);
++
++#ifdef NOTMOS7840
++ Data = 0x00;
++ status = 0;
++ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
++ mos7840_port->shadowLCR = Data;
++ dbg("mos7840_write: LINE_CONTROL_REGISTER is %x\n", Data);
++ dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
++ mos7840_port->shadowLCR);
++
++ //Data = 0x03;
++ //status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data);
++ //mos7840_port->shadowLCR=Data;//Need to add later
++
++ Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
++ status = 0;
++ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++
++ //Data = 0x0c;
++ //status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data);
++ Data = 0x00;
++ status = 0;
++ status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
++ dbg("mos7840_write:DLL value is %x\n", Data);
++
++ Data = 0x0;
++ status = 0;
++ status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
++ dbg("mos7840_write:DLM value is %x\n", Data);
++
++ Data = Data & ~SERIAL_LCR_DLAB;
++ dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
++ mos7840_port->shadowLCR);
++ status = 0;
++ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++#endif
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Port Paranoia failed \n");
++ return -1;
++ }
++
++ serial = port->serial;
++ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
++ dbg("%s", "Serial Paranoia failed \n");
++ return -1;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++ if (mos7840_port == NULL) {
++ dbg("%s", "mos7840_port is NULL\n");
++ return -1;
++ }
++
++ /* try to find a free urb in the list */
++ urb = NULL;
++
++ for (i = 0; i < NUM_URBS; ++i) {
++ if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
++ urb = mos7840_port->write_urb_pool[i];
++ dbg("\nURB:%d", i);
++ break;
++ }
++ }
++
++ if (urb == NULL) {
++ dbg("%s - no more free urbs", __FUNCTION__);
++ goto exit;
++ }
++
++ if (urb->transfer_buffer == NULL) {
++ urb->transfer_buffer =
++ kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
++
++ if (urb->transfer_buffer == NULL) {
++ err("%s no more kernel memory...", __FUNCTION__);
++ goto exit;
++ }
++ }
++ transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
++
++ memcpy(urb->transfer_buffer, current_position, transfer_size);
++
++ /* fill urb with data and submit */
++ usb_fill_bulk_urb(urb,
++ serial->dev,
++ usb_sndbulkpipe(serial->dev,
++ port->bulk_out_endpointAddress),
++ urb->transfer_buffer,
++ transfer_size,
++ mos7840_bulk_out_data_callback, mos7840_port);
++
++ data1 = urb->transfer_buffer;
++ dbg("\nbulkout endpoint is %d", port->bulk_out_endpointAddress);
++
++ /* send it down the pipe */
++ status = usb_submit_urb(urb, GFP_ATOMIC);
++
++ if (status) {
++ err("%s - usb_submit_urb(write bulk) failed with status = %d",
++ __FUNCTION__, status);
++ bytes_sent = status;
++ goto exit;
++ }
++ bytes_sent = transfer_size;
++ mos7840_port->icount.tx += transfer_size;
++ dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
++ exit:
++
++ return bytes_sent;
++
++}
++
++/*****************************************************************************
++ * mos7840_throttle
++ * this function is called by the tty driver when it wants to stop the data
++ * being read from the port.
++ *****************************************************************************/
++
++static void mos7840_throttle(struct usb_serial_port *port)
++{
++ struct moschip_port *mos7840_port;
++ struct tty_struct *tty;
++ int status;
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return;
++ }
++
++ dbg("- port %d\n", port->number);
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL)
++ return;
++
++ if (!mos7840_port->open) {
++ dbg("%s\n", "port not opened");
++ return;
++ }
++
++ dbg("%s", "Entering .......... \n");
++
++ tty = port->tty;
++ if (!tty) {
++ dbg("%s - no tty available", __FUNCTION__);
++ return;
++ }
++
++ /* if we are implementing XON/XOFF, send the stop character */
++ if (I_IXOFF(tty)) {
++ unsigned char stop_char = STOP_CHAR(tty);
++ status = mos7840_write(port, &stop_char, 1);
++ if (status <= 0) {
++ return;
++ }
++ }
++
++ /* if we are implementing RTS/CTS, toggle that line */
++ if (tty->termios->c_cflag & CRTSCTS) {
++ mos7840_port->shadowMCR &= ~MCR_RTS;
++ status = 0;
++ status =
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
++ mos7840_port->shadowMCR);
++
++ if (status < 0) {
++ return;
++ }
++ }
++
++ return;
++}
++
++/*****************************************************************************
++ * mos7840_unthrottle
++ * this function is called by the tty driver when it wants to resume the data
++ * being read from the port (called after SerialThrottle is called)
++ *****************************************************************************/
++static void mos7840_unthrottle(struct usb_serial_port *port)
++{
++ struct tty_struct *tty;
++ int status;
++ struct moschip_port *mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return;
++ }
++
++ if (mos7840_port == NULL)
++ return;
++
++ if (!mos7840_port->open) {
++ dbg("%s - port not opened", __FUNCTION__);
++ return;
++ }
++
++ dbg("%s", "Entering .......... \n");
++
++ tty = port->tty;
++ if (!tty) {
++ dbg("%s - no tty available", __FUNCTION__);
++ return;
++ }
++
++ /* if we are implementing XON/XOFF, send the start character */
++ if (I_IXOFF(tty)) {
++ unsigned char start_char = START_CHAR(tty);
++ status = mos7840_write(port, &start_char, 1);
++ if (status <= 0) {
++ return;
++ }
++ }
++
++ /* if we are implementing RTS/CTS, toggle that line */
++ if (tty->termios->c_cflag & CRTSCTS) {
++ mos7840_port->shadowMCR |= MCR_RTS;
++ status = 0;
++ status =
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
++ mos7840_port->shadowMCR);
++ if (status < 0) {
++ return;
++ }
++ }
++
++ return;
++}
++
++static int mos7840_tiocmget(struct usb_serial_port *port, struct file *file)
++{
++ struct moschip_port *mos7840_port;
++ unsigned int result;
++ __u16 msr;
++ __u16 mcr;
++ int status = 0;
++ mos7840_port = mos7840_get_port_private(port);
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ if (mos7840_port == NULL)
++ return -ENODEV;
++
++ status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
++ status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
++ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
++ | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
++ | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
++ | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0)
++ | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0)
++ | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
++ | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
++
++ dbg("%s - 0x%04X", __FUNCTION__, result);
++
++ return result;
++}
++
++static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
++ unsigned int set, unsigned int clear)
++{
++ struct moschip_port *mos7840_port;
++ unsigned int mcr;
++ unsigned int status;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL)
++ return -ENODEV;
++
++ mcr = mos7840_port->shadowMCR;
++ if (clear & TIOCM_RTS)
++ mcr &= ~MCR_RTS;
++ if (clear & TIOCM_DTR)
++ mcr &= ~MCR_DTR;
++ if (clear & TIOCM_LOOP)
++ mcr &= ~MCR_LOOPBACK;
++
++ if (set & TIOCM_RTS)
++ mcr |= MCR_RTS;
++ if (set & TIOCM_DTR)
++ mcr |= MCR_DTR;
++ if (set & TIOCM_LOOP)
++ mcr |= MCR_LOOPBACK;
++
++ mos7840_port->shadowMCR = mcr;
++
++ status = 0;
++ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
++ if (status < 0) {
++ dbg("setting MODEM_CONTROL_REGISTER Failed\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++/*****************************************************************************
++ * mos7840_calc_baud_rate_divisor
++ * this function calculates the proper baud rate divisor for the specified
++ * baud rate.
++ *****************************************************************************/
++static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
++ __u16 * clk_sel_val)
++{
++
++ dbg("%s - %d", __FUNCTION__, baudRate);
++
++ if (baudRate <= 115200) {
++ *divisor = 115200 / baudRate;
++ *clk_sel_val = 0x0;
++ }
++ if ((baudRate > 115200) && (baudRate <= 230400)) {
++ *divisor = 230400 / baudRate;
++ *clk_sel_val = 0x10;
++ } else if ((baudRate > 230400) && (baudRate <= 403200)) {
++ *divisor = 403200 / baudRate;
++ *clk_sel_val = 0x20;
++ } else if ((baudRate > 403200) && (baudRate <= 460800)) {
++ *divisor = 460800 / baudRate;
++ *clk_sel_val = 0x30;
++ } else if ((baudRate > 460800) && (baudRate <= 806400)) {
++ *divisor = 806400 / baudRate;
++ *clk_sel_val = 0x40;
++ } else if ((baudRate > 806400) && (baudRate <= 921600)) {
++ *divisor = 921600 / baudRate;
++ *clk_sel_val = 0x50;
++ } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
++ *divisor = 1572864 / baudRate;
++ *clk_sel_val = 0x60;
++ } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
++ *divisor = 3145728 / baudRate;
++ *clk_sel_val = 0x70;
++ }
++ return 0;
++
++#ifdef NOTMCS7840
++
++ for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
++ if (mos7840_divisor_table[i].BaudRate == baudrate) {
++ *divisor = mos7840_divisor_table[i].Divisor;
++ return 0;
++ }
++ }
++
++ /* After trying for all the standard baud rates *
++ * Try calculating the divisor for this baud rate */
++
++ if (baudrate > 75 && baudrate < 230400) {
++ /* get the divisor */
++ custom = (__u16) (230400L / baudrate);
++
++ /* Check for round off */
++ round1 = (__u16) (2304000L / baudrate);
++ round = (__u16) (round1 - (custom * 10));
++ if (round > 4) {
++ custom++;
++ }
++ *divisor = custom;
++
++ dbg(" Baud %d = %d\n", baudrate, custom);
++ return 0;
++ }
++
++ dbg("%s\n", " Baud calculation Failed...");
++ return -1;
++#endif
++}
++
++/*****************************************************************************
++ * mos7840_send_cmd_write_baud_rate
++ * this function sends the proper command to change the baud rate of the
++ * specified port.
++ *****************************************************************************/
++
++static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
++ int baudRate)
++{
++ int divisor = 0;
++ int status;
++ __u16 Data;
++ unsigned char number;
++ __u16 clk_sel_val;
++ struct usb_serial_port *port;
++
++ if (mos7840_port == NULL)
++ return -1;
++
++ port = (struct usb_serial_port *)mos7840_port->port;
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return -1;
++ }
++
++ if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
++ dbg("%s", "Invalid Serial \n");
++ return -1;
++ }
++
++ dbg("%s", "Entering .......... \n");
++
++ number = mos7840_port->port->number - mos7840_port->port->serial->minor;
++
++ dbg("%s - port = %d, baud = %d", __FUNCTION__,
++ mos7840_port->port->number, baudRate);
++ //reset clk_uart_sel in spregOffset
++ if (baudRate > 115200) {
++#ifdef HW_flow_control
++ //NOTE: need to see the pther register to modify
++ //setting h/w flow control bit to 1;
++ status = 0;
++ Data = 0x2b;
++ mos7840_port->shadowMCR = Data;
++ status =
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++ if (status < 0) {
++ dbg("Writing spreg failed in set_serial_baud\n");
++ return -1;
++ }
++#endif
++
++ } else {
++#ifdef HW_flow_control
++ //setting h/w flow control bit to 0;
++ status = 0;
++ Data = 0xb;
++ mos7840_port->shadowMCR = Data;
++ status =
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++ if (status < 0) {
++ dbg("Writing spreg failed in set_serial_baud\n");
++ return -1;
++ }
++#endif
++
++ }
++
++ if (1) //baudRate <= 115200)
++ {
++ clk_sel_val = 0x0;
++ Data = 0x0;
++ status = 0;
++ status =
++ mos7840_calc_baud_rate_divisor(baudRate, &divisor,
++ &clk_sel_val);
++ status =
++ mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
++ &Data);
++ if (status < 0) {
++ dbg("reading spreg failed in set_serial_baud\n");
++ return -1;
++ }
++ Data = (Data & 0x8f) | clk_sel_val;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
++ if (status < 0) {
++ dbg("Writing spreg failed in set_serial_baud\n");
++ return -1;
++ }
++ /* Calculate the Divisor */
++
++ if (status) {
++ err("%s - bad baud rate", __FUNCTION__);
++ dbg("%s\n", "bad baud rate");
++ return status;
++ }
++ /* Enable access to divisor latch */
++ Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB;
++ mos7840_port->shadowLCR = Data;
++ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++
++ /* Write the divisor */
++ Data = (unsigned char)(divisor & 0xff);
++ dbg("set_serial_baud Value to write DLL is %x\n", Data);
++ mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
++
++ Data = (unsigned char)((divisor & 0xff00) >> 8);
++ dbg("set_serial_baud Value to write DLM is %x\n", Data);
++ mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
++
++ /* Disable access to divisor latch */
++ Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB;
++ mos7840_port->shadowLCR = Data;
++ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++
++ }
++
++ return status;
++}
++
++/*****************************************************************************
++ * mos7840_change_port_settings
++ * This routine is called to set the UART on the device to match
++ * the specified new settings.
++ *****************************************************************************/
++
++static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
++ struct termios *old_termios)
++{
++ struct tty_struct *tty;
++ int baud;
++ unsigned cflag;
++ unsigned iflag;
++ __u8 lData;
++ __u8 lParity;
++ __u8 lStop;
++ int status;
++ __u16 Data;
++ struct usb_serial_port *port;
++ struct usb_serial *serial;
++
++ if (mos7840_port == NULL)
++ return;
++
++ port = (struct usb_serial_port *)mos7840_port->port;
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return;
++ }
++
++ if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
++ dbg("%s", "Invalid Serial \n");
++ return;
++ }
++
++ serial = port->serial;
++
++ dbg("%s - port %d", __FUNCTION__, mos7840_port->port->number);
++
++ if (!mos7840_port->open) {
++ dbg("%s - port not opened", __FUNCTION__);
++ return;
++ }
++
++ tty = mos7840_port->port->tty;
++
++ if ((!tty) || (!tty->termios)) {
++ dbg("%s - no tty structures", __FUNCTION__);
++ return;
++ }
++
++ dbg("%s", "Entering .......... \n");
++
++ lData = LCR_BITS_8;
++ lStop = LCR_STOP_1;
++ lParity = LCR_PAR_NONE;
++
++ cflag = tty->termios->c_cflag;
++ iflag = tty->termios->c_iflag;
++
++ /* Change the number of bits */
++ if (cflag & CSIZE) {
++ switch (cflag & CSIZE) {
++ case CS5:
++ lData = LCR_BITS_5;
++ break;
++
++ case CS6:
++ lData = LCR_BITS_6;
++ break;
++
++ case CS7:
++ lData = LCR_BITS_7;
++ break;
++ default:
++ case CS8:
++ lData = LCR_BITS_8;
++ break;
++ }
++ }
++ /* Change the Parity bit */
++ if (cflag & PARENB) {
++ if (cflag & PARODD) {
++ lParity = LCR_PAR_ODD;
++ dbg("%s - parity = odd", __FUNCTION__);
++ } else {
++ lParity = LCR_PAR_EVEN;
++ dbg("%s - parity = even", __FUNCTION__);
++ }
++
++ } else {
++ dbg("%s - parity = none", __FUNCTION__);
++ }
++
++ if (cflag & CMSPAR) {
++ lParity = lParity | 0x20;
++ }
++
++ /* Change the Stop bit */
++ if (cflag & CSTOPB) {
++ lStop = LCR_STOP_2;
++ dbg("%s - stop bits = 2", __FUNCTION__);
++ } else {
++ lStop = LCR_STOP_1;
++ dbg("%s - stop bits = 1", __FUNCTION__);
++ }
++
++ /* Update the LCR with the correct value */
++ mos7840_port->shadowLCR &=
++ ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
++ mos7840_port->shadowLCR |= (lData | lParity | lStop);
++
++ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n",
++ mos7840_port->shadowLCR);
++ /* Disable Interrupts */
++ Data = 0x00;
++ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
++
++ Data = 0x00;
++ mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
++
++ Data = 0xcf;
++ mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
++
++ /* Send the updated LCR value to the mos7840 */
++ Data = mos7840_port->shadowLCR;
++
++ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
++
++ Data = 0x00b;
++ mos7840_port->shadowMCR = Data;
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++ Data = 0x00b;
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++
++ /* set up the MCR register and send it to the mos7840 */
++
++ mos7840_port->shadowMCR = MCR_MASTER_IE;
++ if (cflag & CBAUD) {
++ mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS);
++ }
++
++ if (cflag & CRTSCTS) {
++ mos7840_port->shadowMCR |= (MCR_XON_ANY);
++
++ } else {
++ mos7840_port->shadowMCR &= ~(MCR_XON_ANY);
++ }
++
++ Data = mos7840_port->shadowMCR;
++ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++
++ /* Determine divisor based on baud rate */
++ baud = tty_get_baud_rate(tty);
++
++ if (!baud) {
++ /* pick a default, any default... */
++ dbg("%s\n", "Picked default baud...");
++ baud = 9600;
++ }
++
++ dbg("%s - baud rate = %d", __FUNCTION__, baud);
++ status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
++
++ /* Enable Interrupts */
++ Data = 0x0c;
++ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
++
++ if (mos7840_port->read_urb->status != -EINPROGRESS) {
++ mos7840_port->read_urb->dev = serial->dev;
++
++ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
++
++ if (status) {
++ dbg(" usb_submit_urb(read bulk) failed, status = %d",
++ status);
++ }
++ }
++ wake_up(&mos7840_port->delta_msr_wait);
++ mos7840_port->delta_msr_cond = 1;
++ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x\n",
++ mos7840_port->shadowLCR);
++
++ return;
++}
++
++/*****************************************************************************
++ * mos7840_set_termios
++ * this function is called by the tty driver when it wants to change
++ * the termios structure
++ *****************************************************************************/
++
++static void mos7840_set_termios(struct usb_serial_port *port,
++ struct termios *old_termios)
++{
++ int status;
++ unsigned int cflag;
++ struct usb_serial *serial;
++ struct moschip_port *mos7840_port;
++ struct tty_struct *tty;
++ dbg("mos7840_set_termios: START\n");
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return;
++ }
++
++ serial = port->serial;
++
++ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
++ dbg("%s", "Invalid Serial \n");
++ return;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL)
++ return;
++
++ tty = port->tty;
++
++ if (!port->tty || !port->tty->termios) {
++ dbg("%s - no tty or termios", __FUNCTION__);
++ return;
++ }
++
++ if (!mos7840_port->open) {
++ dbg("%s - port not opened", __FUNCTION__);
++ return;
++ }
++
++ dbg("%s\n", "setting termios - ");
++
++ cflag = tty->termios->c_cflag;
++
++ if (!cflag) {
++ dbg("%s %s\n", __FUNCTION__, "cflag is NULL");
++ return;
++ }
++
++ /* check that they really want us to change something */
++ if (old_termios) {
++ if ((cflag == old_termios->c_cflag) &&
++ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
++ RELEVANT_IFLAG(old_termios->c_iflag))) {
++ dbg("%s\n", "Nothing to change");
++ return;
++ }
++ }
++
++ dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
++ tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
++
++ if (old_termios) {
++ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
++ old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
++ }
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* change the port settings to the new ones specified */
++
++ mos7840_change_port_settings(mos7840_port, old_termios);
++
++ if (!mos7840_port->read_urb) {
++ dbg("%s", "URB KILLED !!!!!\n");
++ return;
++ }
++
++ if (mos7840_port->read_urb->status != -EINPROGRESS) {
++ mos7840_port->read_urb->dev = serial->dev;
++ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
++ if (status) {
++ dbg(" usb_submit_urb(read bulk) failed, status = %d",
++ status);
++ }
++ }
++ return;
++}
++
++/*****************************************************************************
++ * mos7840_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 mos7840_get_lsr_info(struct moschip_port *mos7840_port,
++ unsigned int __user *value)
++{
++ int count;
++ unsigned int result = 0;
++
++ count = mos7840_chars_in_buffer(mos7840_port->port);
++ if (count == 0) {
++ dbg("%s -- Empty", __FUNCTION__);
++ result = TIOCSER_TEMT;
++ }
++
++ if (copy_to_user(value, &result, sizeof(int)))
++ return -EFAULT;
++ return 0;
++}
++
++/*****************************************************************************
++ * mos7840_get_bytes_avail - get number of bytes available
++ *
++ * Purpose: Let user call ioctl to get the count of number of bytes available.
++ *****************************************************************************/
++
++static int mos7840_get_bytes_avail(struct moschip_port *mos7840_port,
++ unsigned int __user *value)
++{
++ unsigned int result = 0;
++ struct tty_struct *tty = mos7840_port->port->tty;
++
++ if (!tty)
++ return -ENOIOCTLCMD;
++
++ result = tty->read_cnt;
++
++ dbg("%s(%d) = %d", __FUNCTION__, mos7840_port->port->number, result);
++ if (copy_to_user(value, &result, sizeof(int)))
++ return -EFAULT;
++
++ return -ENOIOCTLCMD;
++}
++
++/*****************************************************************************
++ * mos7840_set_modem_info
++ * function to set modem info
++ *****************************************************************************/
++
++static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
++ unsigned int cmd, unsigned int __user *value)
++{
++ unsigned int mcr;
++ unsigned int arg;
++ __u16 Data;
++ int status;
++ struct usb_serial_port *port;
++
++ if (mos7840_port == NULL)
++ return -1;
++
++ port = (struct usb_serial_port *)mos7840_port->port;
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return -1;
++ }
++
++ mcr = mos7840_port->shadowMCR;
++
++ if (copy_from_user(&arg, value, sizeof(int)))
++ return -EFAULT;
++
++ switch (cmd) {
++ case TIOCMBIS:
++ if (arg & TIOCM_RTS)
++ mcr |= MCR_RTS;
++ if (arg & TIOCM_DTR)
++ mcr |= MCR_RTS;
++ if (arg & TIOCM_LOOP)
++ mcr |= MCR_LOOPBACK;
++ break;
++
++ case TIOCMBIC:
++ if (arg & TIOCM_RTS)
++ mcr &= ~MCR_RTS;
++ if (arg & TIOCM_DTR)
++ mcr &= ~MCR_RTS;
++ if (arg & TIOCM_LOOP)
++ mcr &= ~MCR_LOOPBACK;
++ break;
++
++ case TIOCMSET:
++ /* turn off the RTS and DTR and LOOPBACK
++ * and then only turn on what was asked to */
++ mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
++ mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
++ mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
++ mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
++ break;
++ }
++
++ mos7840_port->shadowMCR = mcr;
++
++ Data = mos7840_port->shadowMCR;
++ status = 0;
++ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
++ if (status < 0) {
++ dbg("setting MODEM_CONTROL_REGISTER Failed\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++/*****************************************************************************
++ * mos7840_get_modem_info
++ * function to get modem info
++ *****************************************************************************/
++
++static int mos7840_get_modem_info(struct moschip_port *mos7840_port,
++ unsigned int __user *value)
++{
++ unsigned int result = 0;
++ __u16 msr;
++ unsigned int mcr = mos7840_port->shadowMCR;
++ int status = 0;
++ status =
++ mos7840_get_uart_reg(mos7840_port->port, MODEM_STATUS_REGISTER,
++ &msr);
++ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */
++ |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */
++ |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
++ |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */
++ |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
++ |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
++
++ dbg("%s -- %x", __FUNCTION__, result);
++
++ if (copy_to_user(value, &result, sizeof(int)))
++ return -EFAULT;
++ return 0;
++}
++
++/*****************************************************************************
++ * mos7840_get_serial_info
++ * function to get information about serial port
++ *****************************************************************************/
++
++static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
++ struct serial_struct __user *retinfo)
++{
++ struct serial_struct tmp;
++
++ if (mos7840_port == NULL)
++ return -1;
++
++ if (!retinfo)
++ return -EFAULT;
++
++ memset(&tmp, 0, sizeof(tmp));
++
++ tmp.type = PORT_16550A;
++ tmp.line = mos7840_port->port->serial->minor;
++ tmp.port = mos7840_port->port->number;
++ tmp.irq = 0;
++ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
++ tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
++ tmp.baud_base = 9600;
++ tmp.close_delay = 5 * HZ;
++ tmp.closing_wait = 30 * HZ;
++
++ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
++ return -EFAULT;
++ return 0;
++}
++
++/*****************************************************************************
++ * SerialIoctl
++ * this function handles any ioctl calls to the driver
++ *****************************************************************************/
++
++static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ void __user *argp = (void __user *)arg;
++ struct moschip_port *mos7840_port;
++ struct tty_struct *tty;
++
++ struct async_icount cnow;
++ struct async_icount cprev;
++ struct serial_icounter_struct icount;
++ int mosret = 0;
++ int retval;
++ struct tty_ldisc *ld;
++
++ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
++ dbg("%s", "Invalid port \n");
++ return -1;
++ }
++
++ mos7840_port = mos7840_get_port_private(port);
++
++ if (mos7840_port == NULL)
++ return -1;
++
++ tty = mos7840_port->port->tty;
++
++ dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
++
++ switch (cmd) {
++ /* return number of bytes available */
++
++ case TIOCINQ:
++ dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
++ return mos7840_get_bytes_avail(mos7840_port, argp);
++
++ case TIOCOUTQ:
++ dbg("%s (%d) TIOCOUTQ", __FUNCTION__, port->number);
++ return put_user(tty->driver->chars_in_buffer ?
++ tty->driver->chars_in_buffer(tty) : 0,
++ (int __user *)arg);
++
++ case TCFLSH:
++ retval = tty_check_change(tty);
++ if (retval)
++ return retval;
++
++ ld = tty_ldisc_ref(tty);
++ switch (arg) {
++ case TCIFLUSH:
++ if (ld && ld->flush_buffer)
++ ld->flush_buffer(tty);
++ break;
++ case TCIOFLUSH:
++ if (ld && ld->flush_buffer)
++ ld->flush_buffer(tty);
++ /* fall through */
++ case TCOFLUSH:
++ if (tty->driver->flush_buffer)
++ tty->driver->flush_buffer(tty);
++ break;
++ default:
++ tty_ldisc_deref(ld);
++ return -EINVAL;
++ }
++ tty_ldisc_deref(ld);
++ return 0;
++
++ case TCGETS:
++ if (kernel_termios_to_user_termios
++ ((struct termios __user *)argp, tty->termios))
++ return -EFAULT;
++ return 0;
++
++ case TIOCSERGETLSR:
++ dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
++ return mos7840_get_lsr_info(mos7840_port, argp);
++ return 0;
++
++ case TIOCMBIS:
++ case TIOCMBIC:
++ case TIOCMSET:
++ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
++ port->number);
++ mosret =
++ mos7840_set_modem_info(mos7840_port, cmd, argp);
++ return mosret;
++
++ case TIOCMGET:
++ dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
++ return mos7840_get_modem_info(mos7840_port, argp);
++
++ case TIOCGSERIAL:
++ dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
++ return mos7840_get_serial_info(mos7840_port, argp);
++
++ case TIOCSSERIAL:
++ dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
++ break;
++
++ case TIOCMIWAIT:
++ dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
++ cprev = mos7840_port->icount;
++ while (1) {
++ //interruptible_sleep_on(&mos7840_port->delta_msr_wait);
++ mos7840_port->delta_msr_cond = 0;
++ wait_event_interruptible(mos7840_port->delta_msr_wait,
++ (mos7840_port->
++ delta_msr_cond == 1));
++
++ /* see if a signal did it */
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++ cnow = mos7840_port->icount;
++ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
++ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
++ return -EIO; /* no change => error */
++ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
++ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
++ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
++ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
++ return 0;
++ }
++ cprev = cnow;
++ }
++ /* NOTREACHED */
++ break;
++
++ case TIOCGICOUNT:
++ cnow = mos7840_port->icount;
++ icount.cts = cnow.cts;
++ icount.dsr = cnow.dsr;
++ icount.rng = cnow.rng;
++ icount.dcd = cnow.dcd;
++ icount.rx = cnow.rx;
++ icount.tx = cnow.tx;
++ icount.frame = cnow.frame;
++ icount.overrun = cnow.overrun;
++ icount.parity = cnow.parity;
++ icount.brk = cnow.brk;
++ icount.buf_overrun = cnow.buf_overrun;
++
++ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
++ port->number, icount.rx, icount.tx);
++ if (copy_to_user(argp, &icount, sizeof(icount)))
++ return -EFAULT;
++ return 0;
++
++ case TIOCEXBAUD:
++ return 0;
++ default:
++ break;
++ }
++
++ return -ENOIOCTLCMD;
++}
++
++static int mos7840_calc_num_ports(struct usb_serial *serial)
++{
++
++ dbg("numberofendpoints: %d \n",
++ (int)serial->interface->cur_altsetting->desc.bNumEndpoints);
++ dbg("numberofendpoints: %d \n",
++ (int)serial->interface->altsetting->desc.bNumEndpoints);
++ if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
++ mos7840_num_ports = 2;
++ serial->type->num_ports = 2;
++ } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) {
++ mos7840_num_ports = 4;
++ serial->type->num_bulk_in = 4;
++ serial->type->num_bulk_out = 4;
++ serial->type->num_ports = 4;
++ }
++
++ return mos7840_num_ports;
++}
++
++/****************************************************************************
++ * mos7840_startup
++ ****************************************************************************/
++
++static int mos7840_startup(struct usb_serial *serial)
++{
++ struct moschip_port *mos7840_port;
++ struct usb_device *dev;
++ int i, status;
++
++ __u16 Data;
++ dbg("%s \n", " mos7840_startup :entering..........");
++
++ if (!serial) {
++ dbg("%s\n", "Invalid Handler");
++ return -1;
++ }
++
++ dev = serial->dev;
++
++ dbg("%s\n", "Entering...");
++
++ /* we set up the pointers to the endpoints in the mos7840_open *
++ * function, as the structures aren't created yet. */
++
++ /* set up port private structures */
++ for (i = 0; i < serial->num_ports; ++i) {
++ mos7840_port = kmalloc(sizeof(struct moschip_port), GFP_KERNEL);
++ if (mos7840_port == NULL) {
++ err("%s - Out of memory", __FUNCTION__);
++ return -ENOMEM;
++ }
++ memset(mos7840_port, 0, sizeof(struct moschip_port));
++
++ /* Initialize all port interrupt end point to port 0 int endpoint *
++ * Our device has only one interrupt end point comman to all port */
++
++ mos7840_port->port = serial->port[i];
++ mos7840_set_port_private(serial->port[i], mos7840_port);
++
++ mos7840_port->port_num = ((serial->port[i]->number -
++ (serial->port[i]->serial->minor)) +
++ 1);
++
++ if (mos7840_port->port_num == 1) {
++ mos7840_port->SpRegOffset = 0x0;
++ mos7840_port->ControlRegOffset = 0x1;
++ mos7840_port->DcrRegOffset = 0x4;
++ } else if ((mos7840_port->port_num == 2)
++ && (mos7840_num_ports == 4)) {
++ mos7840_port->SpRegOffset = 0x8;
++ mos7840_port->ControlRegOffset = 0x9;
++ mos7840_port->DcrRegOffset = 0x16;
++ } else if ((mos7840_port->port_num == 2)
++ && (mos7840_num_ports == 2)) {
++ mos7840_port->SpRegOffset = 0xa;
++ mos7840_port->ControlRegOffset = 0xb;
++ mos7840_port->DcrRegOffset = 0x19;
++ } else if ((mos7840_port->port_num == 3)
++ && (mos7840_num_ports == 4)) {
++ mos7840_port->SpRegOffset = 0xa;
++ mos7840_port->ControlRegOffset = 0xb;
++ mos7840_port->DcrRegOffset = 0x19;
++ } else if ((mos7840_port->port_num == 4)
++ && (mos7840_num_ports == 4)) {
++ mos7840_port->SpRegOffset = 0xc;
++ mos7840_port->ControlRegOffset = 0xd;
++ mos7840_port->DcrRegOffset = 0x1c;
++ }
++ mos7840_dump_serial_port(mos7840_port);
++
++ mos7840_set_port_private(serial->port[i], mos7840_port);
++
++ //enable rx_disable bit in control register
++
++ status =
++ mos7840_get_reg_sync(serial->port[i],
++ mos7840_port->ControlRegOffset, &Data);
++ if (status < 0) {
++ dbg("Reading ControlReg failed status-0x%x\n", status);
++ break;
++ } else
++ dbg("ControlReg Reading success val is %x, status%d\n",
++ Data, status);
++ Data |= 0x08; //setting driver done bit
++ Data |= 0x04; //sp1_bit to have cts change reflect in modem status reg
++
++ //Data |= 0x20; //rx_disable bit
++ status = 0;
++ status =
++ mos7840_set_reg_sync(serial->port[i],
++ mos7840_port->ControlRegOffset, Data);
++ if (status < 0) {
++ dbg("Writing ControlReg failed(rx_disable) status-0x%x\n", status);
++ break;
++ } else
++ dbg("ControlReg Writing success(rx_disable) status%d\n",
++ status);
++
++ //Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 and 0x24 in DCR3
++ Data = 0x01;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(serial->port[i],
++ (__u16) (mos7840_port->DcrRegOffset +
++ 0), Data);
++ if (status < 0) {
++ dbg("Writing DCR0 failed status-0x%x\n", status);
++ break;
++ } else
++ dbg("DCR0 Writing success status%d\n", status);
++
++ Data = 0x05;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(serial->port[i],
++ (__u16) (mos7840_port->DcrRegOffset +
++ 1), Data);
++ if (status < 0) {
++ dbg("Writing DCR1 failed status-0x%x\n", status);
++ break;
++ } else
++ dbg("DCR1 Writing success status%d\n", status);
++
++ Data = 0x24;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(serial->port[i],
++ (__u16) (mos7840_port->DcrRegOffset +
++ 2), Data);
++ if (status < 0) {
++ dbg("Writing DCR2 failed status-0x%x\n", status);
++ break;
++ } else
++ dbg("DCR2 Writing success status%d\n", status);
++
++ // write values in clkstart0x0 and clkmulti 0x20
++ Data = 0x0;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(serial->port[i],
++ CLK_START_VALUE_REGISTER, Data);
++ if (status < 0) {
++ dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
++ break;
++ } else
++ dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status);
++
++ Data = 0x20;
++ status = 0;
++ status =
++ mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER,
++ Data);
++ if (status < 0) {
++ dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n",
++ status);
++ break;
++ } else
++ dbg("CLK_MULTI_REGISTER Writing success status%d\n",
++ status);
++
++ //write value 0x0 to scratchpad register
++ Data = 0x00;
++ status = 0;
++ status =
++ mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER,
++ Data);
++ if (status < 0) {
++ dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n",
++ status);
++ break;
++ } else
++ dbg("SCRATCH_PAD_REGISTER Writing success status%d\n",
++ status);
++
++ //Zero Length flag register
++ if ((mos7840_port->port_num != 1)
++ && (mos7840_num_ports == 2)) {
++
++ Data = 0xff;
++ status = 0;
++ status = mos7840_set_reg_sync(serial->port[i],
++ (__u16) (ZLP_REG1 +
++ ((__u16)
++ mos7840_port->
++ port_num)),
++ Data);
++ dbg("ZLIP offset%x\n",
++ (__u16) (ZLP_REG1 +
++ ((__u16) mos7840_port->port_num)));
++ if (status < 0) {
++ dbg("Writing ZLP_REG%d failed status-0x%x\n",
++ i + 2, status);
++ break;
++ } else
++ dbg("ZLP_REG%d Writing success status%d\n",
++ i + 2, status);
++ } else {
++ Data = 0xff;
++ status = 0;
++ status = mos7840_set_reg_sync(serial->port[i],
++ (__u16) (ZLP_REG1 +
++ ((__u16)
++ mos7840_port->
++ port_num) -
++ 0x1), Data);
++ dbg("ZLIP offset%x\n",
++ (__u16) (ZLP_REG1 +
++ ((__u16) mos7840_port->port_num) - 0x1));
++ if (status < 0) {
++ dbg("Writing ZLP_REG%d failed status-0x%x\n",
++ i + 1, status);
++ break;
++ } else
++ dbg("ZLP_REG%d Writing success status%d\n",
++ i + 1, status);
++
++ }
++ mos7840_port->control_urb = usb_alloc_urb(0, SLAB_ATOMIC);
++ mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
++
++ }
++
++ //Zero Length flag enable
++ Data = 0x0f;
++ status = 0;
++ status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
++ if (status < 0) {
++ dbg("Writing ZLP_REG5 failed status-0x%x\n", status);
++ return -1;
++ } else
++ dbg("ZLP_REG5 Writing success status%d\n", status);
++
++ /* setting configuration feature to one */
++ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
++ (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
++ return 0;
++}
++
++/****************************************************************************
++ * mos7840_shutdown
++ * This function is called whenever the device is removed from the usb bus.
++ ****************************************************************************/
++
++static void mos7840_shutdown(struct usb_serial *serial)
++{
++ int i;
++ struct moschip_port *mos7840_port;
++ dbg("%s \n", " shutdown :entering..........");
++
++ if (!serial) {
++ dbg("%s", "Invalid Handler \n");
++ return;
++ }
++
++ /* check for the ports to be closed,close the ports and disconnect */
++
++ /* free private structure allocated for serial port *
++ * stop reads and writes on all ports */
++
++ for (i = 0; i < serial->num_ports; ++i) {
++ mos7840_port = mos7840_get_port_private(serial->port[i]);
++ kfree(mos7840_port->ctrl_buf);
++ usb_kill_urb(mos7840_port->control_urb);
++ kfree(mos7840_port);
++ mos7840_set_port_private(serial->port[i], NULL);
++ }
++
++ dbg("%s\n", "Thank u :: ");
++
++}
++
++static struct usb_serial_driver moschip7840_4port_device = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "mos7840",
++ },
++ .description = DRIVER_DESC,
++ .id_table = moschip_port_id_table,
++ .num_interrupt_in = 1, //NUM_DONT_CARE,//1,
++#ifdef check
++ .num_bulk_in = 4,
++ .num_bulk_out = 4,
++ .num_ports = 4,
++#endif
++ .open = mos7840_open,
++ .close = mos7840_close,
++ .write = mos7840_write,
++ .write_room = mos7840_write_room,
++ .chars_in_buffer = mos7840_chars_in_buffer,
++ .throttle = mos7840_throttle,
++ .unthrottle = mos7840_unthrottle,
++ .calc_num_ports = mos7840_calc_num_ports,
++#ifdef MCSSerialProbe
++ .probe = mos7840_serial_probe,
++#endif
++ .ioctl = mos7840_ioctl,
++ .set_termios = mos7840_set_termios,
++ .break_ctl = mos7840_break,
++ .tiocmget = mos7840_tiocmget,
++ .tiocmset = mos7840_tiocmset,
++ .attach = mos7840_startup,
++ .shutdown = mos7840_shutdown,
++ .read_bulk_callback = mos7840_bulk_in_callback,
++ .read_int_callback = mos7840_interrupt_callback,
++};
++
++static struct usb_driver io_driver = {
++ .name = "mos7840",
++ .probe = usb_serial_probe,
++ .disconnect = usb_serial_disconnect,
++ .id_table = moschip_id_table_combined,
++};
++
++/****************************************************************************
++ * moschip7840_init
++ * This is called by the module subsystem, or on startup to initialize us
++ ****************************************************************************/
++static int __init moschip7840_init(void)
++{
++ int retval;
++
++ dbg("%s \n", " mos7840_init :entering..........");
++
++ /* Register with the usb serial */
++ retval = usb_serial_register(&moschip7840_4port_device);
++
++ if (retval)
++ goto failed_port_device_register;
++
++ dbg("%s\n", "Entring...");
++ info(DRIVER_DESC " " DRIVER_VERSION);
++
++ /* Register with the usb */
++ retval = usb_register(&io_driver);
++
++ if (retval)
++ goto failed_usb_register;
++
++ if (retval == 0) {
++ dbg("%s\n", "Leaving...");
++ return 0;
++ }
++
++ failed_usb_register:
++ usb_serial_deregister(&moschip7840_4port_device);
++
++ failed_port_device_register:
++
++ return retval;
++}
++
++/****************************************************************************
++ * moschip7840_exit
++ * Called when the driver is about to be unloaded.
++ ****************************************************************************/
++static void __exit moschip7840_exit(void)
++{
++
++ dbg("%s \n", " mos7840_exit :entering..........");
++
++ usb_deregister(&io_driver);
++
++ usb_serial_deregister(&moschip7840_4port_device);
++
++ dbg("%s\n", "Entring...");
++}
++
++module_init(moschip7840_init);
++module_exit(moschip7840_exit);
++
++/* Module information */
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled or not");
+diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
+index ac3f8b5..0610409 100644
+--- a/drivers/usb/serial/navman.c
++++ b/drivers/usb/serial/navman.c
+@@ -32,7 +32,7 @@ static struct usb_driver navman_driver =
+ .no_dynamic_id = 1,
+ };
+
+-static void navman_read_int_callback(struct urb *urb, struct pt_regs *regs)
++static void navman_read_int_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
+index e49f409..bc91d3b 100644
+--- a/drivers/usb/serial/omninet.c
++++ b/drivers/usb/serial/omninet.c
+@@ -64,8 +64,8 @@ static int debug;
+ /* function prototypes */
+ static int omninet_open (struct usb_serial_port *port, struct file *filp);
+ static void omninet_close (struct usb_serial_port *port, struct file *filp);
+-static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
++static void omninet_read_bulk_callback (struct urb *urb);
++static void omninet_write_bulk_callback (struct urb *urb);
+ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count);
+ static int omninet_write_room (struct usb_serial_port *port);
+ static void omninet_shutdown (struct usb_serial *serial);
+@@ -194,7 +194,7 @@ static void omninet_close (struct usb_se
+ #define OMNINET_HEADERLEN sizeof(struct omninet_header)
+ #define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
+
+-static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void omninet_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -256,14 +256,14 @@ static int omninet_write (struct usb_ser
+ return (0);
+ }
+
+- spin_lock(&wport->lock);
++ spin_lock_bh(&wport->lock);
+ if (wport->write_urb_busy) {
+- spin_unlock(&wport->lock);
++ spin_unlock_bh(&wport->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
+ }
+ wport->write_urb_busy = 1;
+- spin_unlock(&wport->lock);
++ spin_unlock_bh(&wport->lock);
+
+ count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+
+@@ -306,7 +306,7 @@ static int omninet_write_room (struct us
+ return (room);
+ }
+
+-static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void omninet_write_bulk_callback (struct urb *urb)
+ {
+ /* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index c856e6f..130afbb 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -50,7 +50,7 @@ static void option_rx_throttle(struct us
+ static void option_rx_unthrottle(struct usb_serial_port *port);
+ static int option_write_room(struct usb_serial_port *port);
+
+-static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
++static void option_instat_callback(struct urb *urb);
+
+ static int option_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count);
+@@ -337,7 +337,7 @@ static int option_write(struct usb_seria
+ return count;
+ }
+
+-static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
++static void option_indat_callback(struct urb *urb)
+ {
+ int err;
+ int endpoint;
+@@ -374,7 +374,7 @@ static void option_indat_callback(struct
+ return;
+ }
+
+-static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
++static void option_outdat_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port;
+
+@@ -385,7 +385,7 @@ static void option_outdat_callback(struc
+ usb_serial_port_softint(port);
+ }
+
+-static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
++static void option_instat_callback(struct urb *urb)
+ {
+ int err;
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+@@ -565,7 +565,7 @@ static void option_close(struct usb_seri
+ /* Helper functions used by option_setup_urbs */
+ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+- void (*callback)(struct urb *, struct pt_regs *regs))
++ void (*callback)(struct urb *))
+ {
+ struct urb *urb;
+
+diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
+index 65e4d04..bc800c8 100644
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -81,10 +81,12 @@ static struct usb_device_id id_table []
+ { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
+ { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
+ { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
++ { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
++ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
+ { } /* Terminating entry */
+ };
+
+-MODULE_DEVICE_TABLE (usb, id_table);
++MODULE_DEVICE_TABLE(usb, id_table);
+
+ static struct usb_driver pl2303_driver = {
+ .name = "pl2303",
+@@ -127,65 +129,6 @@ static struct usb_driver pl2303_driver =
+ #define UART_OVERRUN_ERROR 0x40
+ #define UART_CTS 0x80
+
+-/* function prototypes for a PL2303 serial converter */
+-static int pl2303_open (struct usb_serial_port *port, struct file *filp);
+-static void pl2303_close (struct usb_serial_port *port, struct file *filp);
+-static void pl2303_set_termios (struct usb_serial_port *port,
+- struct termios *old);
+-static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+- unsigned int cmd, unsigned long arg);
+-static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);
+-static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static int pl2303_write (struct usb_serial_port *port,
+- const unsigned char *buf, int count);
+-static void pl2303_send (struct usb_serial_port *port);
+-static int pl2303_write_room(struct usb_serial_port *port);
+-static int pl2303_chars_in_buffer(struct usb_serial_port *port);
+-static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
+-static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
+-static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
+- unsigned int set, unsigned int clear);
+-static int pl2303_startup (struct usb_serial *serial);
+-static void pl2303_shutdown (struct usb_serial *serial);
+-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
+-static void pl2303_buf_free(struct pl2303_buf *pb);
+-static void pl2303_buf_clear(struct pl2303_buf *pb);
+-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
+-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
+-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+- unsigned int count);
+-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+- unsigned int count);
+-
+-
+-/* All of the device info needed for the PL2303 SIO serial converter */
+-static struct usb_serial_driver pl2303_device = {
+- .driver = {
+- .owner = THIS_MODULE,
+- .name = "pl2303",
+- },
+- .id_table = id_table,
+- .num_interrupt_in = NUM_DONT_CARE,
+- .num_bulk_in = 1,
+- .num_bulk_out = 1,
+- .num_ports = 1,
+- .open = pl2303_open,
+- .close = pl2303_close,
+- .write = pl2303_write,
+- .ioctl = pl2303_ioctl,
+- .break_ctl = pl2303_break_ctl,
+- .set_termios = pl2303_set_termios,
+- .tiocmget = pl2303_tiocmget,
+- .tiocmset = pl2303_tiocmset,
+- .read_bulk_callback = pl2303_read_bulk_callback,
+- .read_int_callback = pl2303_read_int_callback,
+- .write_bulk_callback = pl2303_write_bulk_callback,
+- .write_room = pl2303_write_room,
+- .chars_in_buffer = pl2303_chars_in_buffer,
+- .attach = pl2303_startup,
+- .shutdown = pl2303_shutdown,
+-};
+
+ enum pl2303_type {
+ type_0, /* don't know the difference between type 0 and */
+@@ -204,8 +147,166 @@ struct pl2303_private {
+ enum pl2303_type type;
+ };
+
++/*
++ * pl2303_buf_alloc
++ *
++ * Allocate a circular buffer and all associated memory.
++ */
++static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
++{
++ struct pl2303_buf *pb;
++
++ if (size == 0)
++ return NULL;
++
++ pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
++ if (pb == NULL)
++ return NULL;
++
++ pb->buf_buf = kmalloc(size, GFP_KERNEL);
++ if (pb->buf_buf == NULL) {
++ kfree(pb);
++ return NULL;
++ }
++
++ pb->buf_size = size;
++ pb->buf_get = pb->buf_put = pb->buf_buf;
+
+-static int pl2303_startup (struct usb_serial *serial)
++ return pb;
++}
++
++/*
++ * pl2303_buf_free
++ *
++ * Free the buffer and all associated memory.
++ */
++static void pl2303_buf_free(struct pl2303_buf *pb)
++{
++ if (pb) {
++ kfree(pb->buf_buf);
++ kfree(pb);
++ }
++}
++
++/*
++ * pl2303_buf_clear
++ *
++ * Clear out all data in the circular buffer.
++ */
++static void pl2303_buf_clear(struct pl2303_buf *pb)
++{
++ if (pb != NULL)
++ pb->buf_get = pb->buf_put;
++ /* equivalent to a get of all data available */
++}
++
++/*
++ * pl2303_buf_data_avail
++ *
++ * Return the number of bytes of data available in the circular
++ * buffer.
++ */
++static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
++{
++ if (pb == NULL)
++ return 0;
++
++ return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
++}
++
++/*
++ * pl2303_buf_space_avail
++ *
++ * Return the number of bytes of space available in the circular
++ * buffer.
++ */
++static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
++{
++ if (pb == NULL)
++ return 0;
++
++ return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
++}
++
++/*
++ * pl2303_buf_put
++ *
++ * Copy data data from a user buffer and put it into the circular buffer.
++ * Restrict to the amount of space available.
++ *
++ * Return the number of bytes copied.
++ */
++static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
++ unsigned int count)
++{
++ unsigned int len;
++
++ if (pb == NULL)
++ return 0;
++
++ len = pl2303_buf_space_avail(pb);
++ if (count > len)
++ count = len;
++
++ if (count == 0)
++ return 0;
++
++ len = pb->buf_buf + pb->buf_size - pb->buf_put;
++ if (count > len) {
++ memcpy(pb->buf_put, buf, len);
++ memcpy(pb->buf_buf, buf+len, count - len);
++ pb->buf_put = pb->buf_buf + count - len;
++ } else {
++ memcpy(pb->buf_put, buf, count);
++ if (count < len)
++ pb->buf_put += count;
++ else /* count == len */
++ pb->buf_put = pb->buf_buf;
++ }
++
++ return count;
++}
++
++/*
++ * pl2303_buf_get
++ *
++ * Get data from the circular buffer and copy to the given buffer.
++ * Restrict to the amount of data available.
++ *
++ * Return the number of bytes copied.
++ */
++static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
++ unsigned int count)
++{
++ unsigned int len;
++
++ if (pb == NULL)
++ return 0;
++
++ len = pl2303_buf_data_avail(pb);
++ if (count > len)
++ count = len;
++
++ if (count == 0)
++ return 0;
++
++ len = pb->buf_buf + pb->buf_size - pb->buf_get;
++ if (count > len) {
++ memcpy(buf, pb->buf_get, len);
++ memcpy(buf+len, pb->buf_buf, count - len);
++ pb->buf_get = pb->buf_buf + count - len;
++ } else {
++ memcpy(buf, pb->buf_get, count);
++ if (count < len)
++ pb->buf_get += count;
++ else /* count == len */
++ pb->buf_get = pb->buf_buf;
++ }
++
++ return count;
++}
++
++static int pl2303_startup(struct usb_serial *serial)
+ {
+ struct pl2303_private *priv;
+ enum pl2303_type type = type_0;
+@@ -247,36 +348,17 @@ cleanup:
+ return -ENOMEM;
+ }
+
+-static int set_control_lines (struct usb_device *dev, u8 value)
++static int set_control_lines(struct usb_device *dev, u8 value)
+ {
+ int retval;
+
+- retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
+- SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
+- value, 0, NULL, 0, 100);
++ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
++ SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
++ value, 0, NULL, 0, 100);
+ dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
+ return retval;
+ }
+
+-static int pl2303_write (struct usb_serial_port *port, const unsigned char *buf, int count)
+-{
+- struct pl2303_private *priv = usb_get_serial_port_data(port);
+- unsigned long flags;
+-
+- dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+-
+- if (!count)
+- return count;
+-
+- spin_lock_irqsave(&priv->lock, flags);
+- count = pl2303_buf_put(priv->buf, buf, count);
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+- pl2303_send(port);
+-
+- return count;
+-}
+-
+ static void pl2303_send(struct usb_serial_port *port)
+ {
+ int count, result;
+@@ -293,7 +375,7 @@ static void pl2303_send(struct usb_seria
+ }
+
+ count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
+- port->bulk_out_size);
++ port->bulk_out_size);
+
+ if (count == 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+@@ -304,13 +386,15 @@ static void pl2303_send(struct usb_seria
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
++ port->write_urb->transfer_buffer);
+
+ port->write_urb->transfer_buffer_length = count;
+ port->write_urb->dev = port->serial->dev;
+- result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
++ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result) {
+- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
++ dev_err(&port->dev, "%s - failed submitting write urb,"
++ " error %d\n", __FUNCTION__, result);
+ priv->write_urb_in_use = 0;
+ // TODO: reschedule pl2303_send
+ }
+@@ -318,6 +402,26 @@ static void pl2303_send(struct usb_seria
+ usb_serial_port_softint(port);
+ }
+
++static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
++ int count)
++{
++ struct pl2303_private *priv = usb_get_serial_port_data(port);
++ unsigned long flags;
++
++ dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
++
++ if (!count)
++ return count;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ count = pl2303_buf_put(priv->buf, buf, count);
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ pl2303_send(port);
++
++ return count;
++}
++
+ static int pl2303_write_room(struct usb_serial_port *port)
+ {
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+@@ -350,7 +454,8 @@ static int pl2303_chars_in_buffer(struct
+ return chars;
+ }
+
+-static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
++static void pl2303_set_termios(struct usb_serial_port *port,
++ struct termios *old_termios)
+ {
+ struct usb_serial *serial = port->serial;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+@@ -371,7 +476,8 @@ static void pl2303_set_termios (struct u
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+- port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++ port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
++ HUPCL | CLOCAL;
+ priv->termios_initialized = 1;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+@@ -380,24 +486,24 @@ static void pl2303_set_termios (struct u
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+- dbg("%s - nothing to change...", __FUNCTION__);
+- return;
++ (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
++ RELEVANT_IFLAG(old_termios->c_iflag))) {
++ dbg("%s - nothing to change...", __FUNCTION__);
++ return;
+ }
+ }
+
+- buf = kzalloc (7, GFP_KERNEL);
++ buf = kzalloc(7, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
+ return;
+ }
+-
+- i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+- 0, 0, buf, 7, 100);
+- dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
++ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
++ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
++ 0, 0, buf, 7, 100);
++ dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
++ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+@@ -429,7 +535,8 @@ static void pl2303_set_termios (struct u
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ default:
+- dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n");
++ dev_err(&port->dev, "pl2303 driver does not support"
++ " the baudrate requested (fix it)\n");
+ break;
+ }
+ dbg("%s - baud = %d", __FUNCTION__, baud);
+@@ -469,10 +576,10 @@ static void pl2303_set_termios (struct u
+ dbg("%s - parity = none", __FUNCTION__);
+ }
+
+- i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+- SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
+- 0, 0, buf, 7, 100);
+- dbg ("0x21:0x20:0:0 %d", i);
++ i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
++ SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
++ 0, 0, buf, 7, 100);
++ dbg("0x21:0x20:0:0 %d", i);
+
+ /* change control lines if we are switching to or from B0 */
+ spin_lock_irqsave(&priv->lock, flags);
+@@ -488,13 +595,13 @@ static void pl2303_set_termios (struct u
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+-
++
+ buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
+
+- i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+- 0, 0, buf, 7, 100);
+- dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
++ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
++ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
++ 0, 0, buf, 7, 100);
++ dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+ if (cflag & CRTSCTS) {
+@@ -503,18 +610,82 @@ static void pl2303_set_termios (struct u
+ index = 0x61;
+ else
+ index = 0x41;
+- i = usb_control_msg(serial->dev,
++ i = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ VENDOR_WRITE_REQUEST,
+ VENDOR_WRITE_REQUEST_TYPE,
+ 0x0, index, NULL, 0, 100);
+- dbg ("0x40:0x1:0x0:0x%x %d", index, i);
++ dbg("0x40:0x1:0x0:0x%x %d", index, i);
++ }
++
++ kfree(buf);
++}
++
++static void pl2303_close(struct usb_serial_port *port, struct file *filp)
++{
++ struct pl2303_private *priv = usb_get_serial_port_data(port);
++ unsigned long flags;
++ unsigned int c_cflag;
++ int bps;
++ long timeout;
++ wait_queue_t wait;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* wait for data to drain from the buffer */
++ spin_lock_irqsave(&priv->lock, flags);
++ timeout = PL2303_CLOSING_WAIT;
++ init_waitqueue_entry(&wait, current);
++ add_wait_queue(&port->tty->write_wait, &wait);
++ for (;;) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (pl2303_buf_data_avail(priv->buf) == 0 ||
++ timeout == 0 || signal_pending(current) ||
++ !usb_get_intfdata(port->serial->interface)) /* disconnect */
++ break;
++ spin_unlock_irqrestore(&priv->lock, flags);
++ timeout = schedule_timeout(timeout);
++ spin_lock_irqsave(&priv->lock, flags);
+ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&port->tty->write_wait, &wait);
++ /* clear out any remaining data in the buffer */
++ pl2303_buf_clear(priv->buf);
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ /* wait for characters to drain from the device */
++ /* (this is long enough for the entire 256 byte */
++ /* pl2303 hardware buffer to drain with no flow */
++ /* control for data rates of 1200 bps or more, */
++ /* for lower rates we should really know how much */
++ /* data is in the buffer to compute a delay */
++ /* that is not unnecessarily long) */
++ bps = tty_get_baud_rate(port->tty);
++ if (bps > 1200)
++ timeout = max((HZ*2560)/bps,HZ/10);
++ else
++ timeout = 2*HZ;
++ schedule_timeout_interruptible(timeout);
+
+- kfree (buf);
++ /* shutdown our urbs */
++ dbg("%s - shutting down urbs", __FUNCTION__);
++ usb_kill_urb(port->write_urb);
++ usb_kill_urb(port->read_urb);
++ usb_kill_urb(port->interrupt_in_urb);
++
++ if (port->tty) {
++ c_cflag = port->tty->termios->c_cflag;
++ if (c_cflag & HUPCL) {
++ /* drop DTR and RTS */
++ spin_lock_irqsave(&priv->lock, flags);
++ priv->line_control = 0;
++ spin_unlock_irqrestore(&priv->lock, flags);
++ set_control_lines(port->serial->dev, 0);
++ }
++ }
+ }
+
+-static int pl2303_open (struct usb_serial_port *port, struct file *filp)
++static int pl2303_open(struct usb_serial_port *port, struct file *filp)
+ {
+ struct termios tmp_termios;
+ struct usb_serial *serial = port->serial;
+@@ -568,98 +739,35 @@ static int pl2303_open (struct usb_seria
+
+ /* Setup termios */
+ if (port->tty) {
+- pl2303_set_termios (port, &tmp_termios);
++ pl2303_set_termios(port, &tmp_termios);
+ }
+
+ //FIXME: need to assert RTS and DTR if CRTSCTS off
+
+ dbg("%s - submitting read urb", __FUNCTION__);
+ port->read_urb->dev = serial->dev;
+- result = usb_submit_urb (port->read_urb, GFP_KERNEL);
++ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result) {
+- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+- pl2303_close (port, NULL);
++ dev_err(&port->dev, "%s - failed submitting read urb,"
++ " error %d\n", __FUNCTION__, result);
++ pl2303_close(port, NULL);
+ return -EPROTO;
+ }
+
+ dbg("%s - submitting interrupt urb", __FUNCTION__);
+ port->interrupt_in_urb->dev = serial->dev;
+- result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
++ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (result) {
+- dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result);
+- pl2303_close (port, NULL);
++ dev_err(&port->dev, "%s - failed submitting interrupt urb,"
++ " error %d\n", __FUNCTION__, result);
++ pl2303_close(port, NULL);
+ return -EPROTO;
+ }
+ return 0;
+ }
+
+-
+-static void pl2303_close (struct usb_serial_port *port, struct file *filp)
+-{
+- struct pl2303_private *priv = usb_get_serial_port_data(port);
+- unsigned long flags;
+- unsigned int c_cflag;
+- int bps;
+- long timeout;
+- wait_queue_t wait;
+-
+- dbg("%s - port %d", __FUNCTION__, port->number);
+-
+- /* wait for data to drain from the buffer */
+- spin_lock_irqsave(&priv->lock, flags);
+- timeout = PL2303_CLOSING_WAIT;
+- init_waitqueue_entry(&wait, current);
+- add_wait_queue(&port->tty->write_wait, &wait);
+- for (;;) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (pl2303_buf_data_avail(priv->buf) == 0
+- || timeout == 0 || signal_pending(current)
+- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+- break;
+- spin_unlock_irqrestore(&priv->lock, flags);
+- timeout = schedule_timeout(timeout);
+- spin_lock_irqsave(&priv->lock, flags);
+- }
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&port->tty->write_wait, &wait);
+- /* clear out any remaining data in the buffer */
+- pl2303_buf_clear(priv->buf);
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+- /* wait for characters to drain from the device */
+- /* (this is long enough for the entire 256 byte */
+- /* pl2303 hardware buffer to drain with no flow */
+- /* control for data rates of 1200 bps or more, */
+- /* for lower rates we should really know how much */
+- /* data is in the buffer to compute a delay */
+- /* that is not unnecessarily long) */
+- bps = tty_get_baud_rate(port->tty);
+- if (bps > 1200)
+- timeout = max((HZ*2560)/bps,HZ/10);
+- else
+- timeout = 2*HZ;
+- schedule_timeout_interruptible(timeout);
+-
+- /* shutdown our urbs */
+- dbg("%s - shutting down urbs", __FUNCTION__);
+- usb_kill_urb(port->write_urb);
+- usb_kill_urb(port->read_urb);
+- usb_kill_urb(port->interrupt_in_urb);
+-
+- if (port->tty) {
+- c_cflag = port->tty->termios->c_cflag;
+- if (c_cflag & HUPCL) {
+- /* drop DTR and RTS */
+- spin_lock_irqsave(&priv->lock, flags);
+- priv->line_control = 0;
+- spin_unlock_irqrestore (&priv->lock, flags);
+- set_control_lines (port->serial->dev, 0);
+- }
+- }
+-}
+-
+-static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
+- unsigned int set, unsigned int clear)
++static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
++ unsigned int set, unsigned int clear)
+ {
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+@@ -668,7 +776,7 @@ static int pl2303_tiocmset (struct usb_s
+ if (!usb_get_intfdata(port->serial->interface))
+ return -ENODEV;
+
+- spin_lock_irqsave (&priv->lock, flags);
++ spin_lock_irqsave(&priv->lock, flags);
+ if (set & TIOCM_RTS)
+ priv->line_control |= CONTROL_RTS;
+ if (set & TIOCM_DTR)
+@@ -678,12 +786,12 @@ static int pl2303_tiocmset (struct usb_s
+ if (clear & TIOCM_DTR)
+ priv->line_control &= ~CONTROL_DTR;
+ control = priv->line_control;
+- spin_unlock_irqrestore (&priv->lock, flags);
++ spin_unlock_irqrestore(&priv->lock, flags);
+
+- return set_control_lines (port->serial->dev, control);
++ return set_control_lines(port->serial->dev, control);
+ }
+
+-static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
++static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
+ {
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+@@ -696,10 +804,10 @@ static int pl2303_tiocmget (struct usb_s
+ if (!usb_get_intfdata(port->serial->interface))
+ return -ENODEV;
+
+- spin_lock_irqsave (&priv->lock, flags);
++ spin_lock_irqsave(&priv->lock, flags);
+ mcr = priv->line_control;
+ status = priv->line_status;
+- spin_unlock_irqrestore (&priv->lock, flags);
++ spin_unlock_irqrestore(&priv->lock, flags);
+
+ result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
+ | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
+@@ -721,22 +829,22 @@ static int wait_modem_info(struct usb_se
+ unsigned int status;
+ unsigned int changed;
+
+- spin_lock_irqsave (&priv->lock, flags);
++ spin_lock_irqsave(&priv->lock, flags);
+ prevstatus = priv->line_status;
+- spin_unlock_irqrestore (&priv->lock, flags);
++ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+ interruptible_sleep_on(&priv->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+-
+- spin_lock_irqsave (&priv->lock, flags);
++
++ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+- spin_unlock_irqrestore (&priv->lock, flags);
+-
++ spin_unlock_irqrestore(&priv->lock, flags);
++
+ changed=prevstatus^status;
+-
++
+ if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
+ ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
+ ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
+@@ -749,7 +857,8 @@ static int wait_modem_info(struct usb_se
+ return 0;
+ }
+
+-static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
++static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
++ unsigned int cmd, unsigned long arg)
+ {
+ dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
+
+@@ -766,7 +875,7 @@ static int pl2303_ioctl (struct usb_seri
+ return -ENOIOCTLCMD;
+ }
+
+-static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
++static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
+ {
+ struct usb_serial *serial = port->serial;
+ u16 state;
+@@ -780,15 +889,14 @@ static void pl2303_break_ctl (struct usb
+ state = BREAK_ON;
+ dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
+
+- result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+- BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
+- 0, NULL, 0, 100);
++ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
++ BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
++ 0, NULL, 0, 100);
+ if (result)
+ dbg("%s - error sending break = %d", __FUNCTION__, result);
+ }
+
+-
+-static void pl2303_shutdown (struct usb_serial *serial)
++static void pl2303_shutdown(struct usb_serial *serial)
+ {
+ int i;
+ struct pl2303_private *priv;
+@@ -802,7 +910,7 @@ static void pl2303_shutdown (struct usb_
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+- }
++ }
+ }
+
+ static void pl2303_update_line_status(struct usb_serial_port *port,
+@@ -814,29 +922,33 @@ static void pl2303_update_line_status(st
+ unsigned long flags;
+ u8 status_idx = UART_STATE;
+ u8 length = UART_STATE + 1;
++ u16 idv, idp;
++
++ idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
++ idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
+
+- if ((le16_to_cpu(port->serial->dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
+- (le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X65 ||
+- le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_SX1 ||
+- le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X75)) {
+- length = 1;
+- status_idx = 0;
++
++ if (idv == SIEMENS_VENDOR_ID) {
++ if (idp == SIEMENS_PRODUCT_ID_X65 ||
++ idp == SIEMENS_PRODUCT_ID_SX1 ||
++ idp == SIEMENS_PRODUCT_ID_X75) {
++
++ length = 1;
++ status_idx = 0;
++ }
+ }
+
+ if (actual_length < length)
+- goto exit;
++ return;
+
+ /* Save off the uart status for others to look at */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_status = data[status_idx];
+ spin_unlock_irqrestore(&priv->lock, flags);
+- wake_up_interruptible (&priv->delta_msr_wait);
+-
+-exit:
+- return;
++ wake_up_interruptible(&priv->delta_msr_wait);
+ }
+
+-static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
++static void pl2303_read_int_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -853,25 +965,29 @@ static void pl2303_read_int_callback (st
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
++ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
++ urb->status);
+ return;
+ default:
+- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
++ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
++ urb->status);
+ goto exit;
+ }
+
+- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
++ urb->actual_length, urb->transfer_buffer);
++
+ pl2303_update_line_status(port, data, actual_length);
+
+ exit:
+- status = usb_submit_urb (urb, GFP_ATOMIC);
++ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status)
+- dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
++ dev_err(&urb->dev->dev,
++ "%s - usb_submit_urb failed with result %d\n",
+ __FUNCTION__, status);
+ }
+
+-
+-static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void pl2303_read_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+@@ -892,20 +1008,25 @@ static void pl2303_read_bulk_callback (s
+ return;
+ }
+ if (urb->status == -EPROTO) {
+- /* PL2303 mysteriously fails with -EPROTO reschedule the read */
+- dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
++ /* PL2303 mysteriously fails with -EPROTO reschedule
++ * the read */
++ dbg("%s - caught -EPROTO, resubmitting the urb",
++ __FUNCTION__);
+ urb->status = 0;
+ urb->dev = port->serial->dev;
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
++ dev_err(&urb->dev->dev, "%s - failed"
++ " resubmitting read urb, error %d\n",
++ __FUNCTION__, result);
+ return;
+ }
+ dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
+ return;
+ }
+
+- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
++ urb->actual_length, data);
+
+ /* get tty_flag from status */
+ tty_flag = TTY_NORMAL;
+@@ -914,7 +1035,7 @@ static void pl2303_read_bulk_callback (s
+ status = priv->line_status;
+ priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+- wake_up_interruptible (&priv->delta_msr_wait);
++ wake_up_interruptible(&priv->delta_msr_wait);
+
+ /* break takes precedence over parity, */
+ /* which takes precedence over framing errors */
+@@ -933,8 +1054,8 @@ static void pl2303_read_bulk_callback (s
+ if (status & UART_OVERRUN_ERROR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ for (i = 0; i < urb->actual_length; ++i)
+- tty_insert_flip_char (tty, data[i], tty_flag);
+- tty_flip_buffer_push (tty);
++ tty_insert_flip_char(tty, data[i], tty_flag);
++ tty_flip_buffer_push(tty);
+ }
+
+ /* Schedule the next read _if_ we are still open */
+@@ -942,15 +1063,14 @@ static void pl2303_read_bulk_callback (s
+ urb->dev = port->serial->dev;
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
++ dev_err(&urb->dev->dev, "%s - failed resubmitting"
++ " read urb, error %d\n", __FUNCTION__, result);
+ }
+
+ return;
+ }
+
+-
+-
+-static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void pl2303_write_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+@@ -966,18 +1086,21 @@ static void pl2303_write_bulk_callback (
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
++ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
++ urb->status);
+ priv->write_urb_in_use = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __FUNCTION__);
+- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
++ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
++ urb->status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+- result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
++ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result)
+- dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
++ dev_err(&urb->dev->dev, "%s - failed resubmitting write"
++ " urb, error %d\n", __FUNCTION__, result);
+ else
+ return;
+ }
+@@ -988,191 +1111,38 @@ static void pl2303_write_bulk_callback (
+ pl2303_send(port);
+ }
+
++/* All of the device info needed for the PL2303 SIO serial converter */
++static struct usb_serial_driver pl2303_device = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "pl2303",
++ },
++ .id_table = id_table,
++ .num_interrupt_in = NUM_DONT_CARE,
++ .num_bulk_in = 1,
++ .num_bulk_out = 1,
++ .num_ports = 1,
++ .open = pl2303_open,
++ .close = pl2303_close,
++ .write = pl2303_write,
++ .ioctl = pl2303_ioctl,
++ .break_ctl = pl2303_break_ctl,
++ .set_termios = pl2303_set_termios,
++ .tiocmget = pl2303_tiocmget,
++ .tiocmset = pl2303_tiocmset,
++ .read_bulk_callback = pl2303_read_bulk_callback,
++ .read_int_callback = pl2303_read_int_callback,
++ .write_bulk_callback = pl2303_write_bulk_callback,
++ .write_room = pl2303_write_room,
++ .chars_in_buffer = pl2303_chars_in_buffer,
++ .attach = pl2303_startup,
++ .shutdown = pl2303_shutdown,
++};
+
+-/*
+- * pl2303_buf_alloc
+- *
+- * Allocate a circular buffer and all associated memory.
+- */
+-
+-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+-{
+-
+- struct pl2303_buf *pb;
+-
+-
+- if (size == 0)
+- return NULL;
+-
+- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+- if (pb == NULL)
+- return NULL;
+-
+- pb->buf_buf = kmalloc(size, GFP_KERNEL);
+- if (pb->buf_buf == NULL) {
+- kfree(pb);
+- return NULL;
+- }
+-
+- pb->buf_size = size;
+- pb->buf_get = pb->buf_put = pb->buf_buf;
+-
+- return pb;
+-
+-}
+-
+-
+-/*
+- * pl2303_buf_free
+- *
+- * Free the buffer and all associated memory.
+- */
+-
+-static void pl2303_buf_free(struct pl2303_buf *pb)
+-{
+- if (pb) {
+- kfree(pb->buf_buf);
+- kfree(pb);
+- }
+-}
+-
+-
+-/*
+- * pl2303_buf_clear
+- *
+- * Clear out all data in the circular buffer.
+- */
+-
+-static void pl2303_buf_clear(struct pl2303_buf *pb)
+-{
+- if (pb != NULL)
+- pb->buf_get = pb->buf_put;
+- /* equivalent to a get of all data available */
+-}
+-
+-
+-/*
+- * pl2303_buf_data_avail
+- *
+- * Return the number of bytes of data available in the circular
+- * buffer.
+- */
+-
+-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+-{
+- if (pb != NULL)
+- return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
+- else
+- return 0;
+-}
+-
+-
+-/*
+- * pl2303_buf_space_avail
+- *
+- * Return the number of bytes of space available in the circular
+- * buffer.
+- */
+-
+-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+-{
+- if (pb != NULL)
+- return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
+- else
+- return 0;
+-}
+-
+-
+-/*
+- * pl2303_buf_put
+- *
+- * Copy data data from a user buffer and put it into the circular buffer.
+- * Restrict to the amount of space available.
+- *
+- * Return the number of bytes copied.
+- */
+-
+-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+- unsigned int count)
+-{
+-
+- unsigned int len;
+-
+-
+- if (pb == NULL)
+- return 0;
+-
+- len = pl2303_buf_space_avail(pb);
+- if (count > len)
+- count = len;
+-
+- if (count == 0)
+- return 0;
+-
+- len = pb->buf_buf + pb->buf_size - pb->buf_put;
+- if (count > len) {
+- memcpy(pb->buf_put, buf, len);
+- memcpy(pb->buf_buf, buf+len, count - len);
+- pb->buf_put = pb->buf_buf + count - len;
+- } else {
+- memcpy(pb->buf_put, buf, count);
+- if (count < len)
+- pb->buf_put += count;
+- else /* count == len */
+- pb->buf_put = pb->buf_buf;
+- }
+-
+- return count;
+-
+-}
+-
+-
+-/*
+- * pl2303_buf_get
+- *
+- * Get data from the circular buffer and copy to the given buffer.
+- * Restrict to the amount of data available.
+- *
+- * Return the number of bytes copied.
+- */
+-
+-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+- unsigned int count)
+-{
+-
+- unsigned int len;
+-
+-
+- if (pb == NULL)
+- return 0;
+-
+- len = pl2303_buf_data_avail(pb);
+- if (count > len)
+- count = len;
+-
+- if (count == 0)
+- return 0;
+-
+- len = pb->buf_buf + pb->buf_size - pb->buf_get;
+- if (count > len) {
+- memcpy(buf, pb->buf_get, len);
+- memcpy(buf+len, pb->buf_buf, count - len);
+- pb->buf_get = pb->buf_buf + count - len;
+- } else {
+- memcpy(buf, pb->buf_get, count);
+- if (count < len)
+- pb->buf_get += count;
+- else /* count == len */
+- pb->buf_get = pb->buf_buf;
+- }
+-
+- return count;
+-
+-}
+-
+-static int __init pl2303_init (void)
++static int __init pl2303_init(void)
+ {
+ int retval;
++
+ retval = usb_serial_register(&pl2303_device);
+ if (retval)
+ goto failed_usb_serial_register;
+@@ -1187,14 +1157,12 @@ failed_usb_serial_register:
+ return retval;
+ }
+
+-
+-static void __exit pl2303_exit (void)
++static void __exit pl2303_exit(void)
+ {
+- usb_deregister (&pl2303_driver);
+- usb_serial_deregister (&pl2303_device);
++ usb_deregister(&pl2303_driver);
++ usb_serial_deregister(&pl2303_device);
+ }
+
+-
+ module_init(pl2303_init);
+ module_exit(pl2303_exit);
+
+diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
+index 55195e7..65a5039 100644
+--- a/drivers/usb/serial/pl2303.h
++++ b/drivers/usb/serial/pl2303.h
+@@ -89,3 +89,11 @@
+ /* Belkin "F5U257" Serial Adapter */
+ #define BELKIN_VENDOR_ID 0x050d
+ #define BELKIN_PRODUCT_ID 0x0257
++
++/* Alcor Micro Corp. USB 2.0 TO RS-232 */
++#define ALCOR_VENDOR_ID 0x058F
++#define ALCOR_PRODUCT_ID 0x9720
++
++/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
++#define HUAWEI_VENDOR_ID 0x12d1
++#define HUAWEI_PRODUCT_ID 0x1001
+diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
+index 789771e..30b7ebc 100644
+--- a/drivers/usb/serial/safe_serial.c
++++ b/drivers/usb/serial/safe_serial.c
+@@ -204,7 +204,7 @@ static __u16 __inline__ fcs_compute10 (u
+ return fcs;
+ }
+
+-static void safe_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void safe_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ unsigned char *data = urb->transfer_buffer;
+@@ -298,14 +298,14 @@ static int safe_write (struct usb_serial
+ dbg ("%s - write request of 0 bytes", __FUNCTION__);
+ return (0);
+ }
+- spin_lock(&port->lock);
++ spin_lock_bh(&port->lock);
+ if (port->write_urb_busy) {
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
+ }
+ port->write_urb_busy = 1;
+- spin_unlock(&port->lock);
++ spin_unlock_bh(&port->lock);
+
+ packet_length = port->bulk_out_size; // get max packetsize
+
+diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
+index d29638d..4b5097f 100644
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -1,75 +1,713 @@
+ /*
+- * Sierra Wireless CDMA Wireless Serial USB driver
+- *
+- * Current Copy modified by: Kevin Lloyd <linux at sierrawireless.com>
+- * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh at suse.de>
+- *
+- * 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.
+- */
++ USB Driver for Sierra Wireless
++
++ Copyright (C) 2006 Kevin Lloyd <linux at sierrawireless.com>
++
++ IMPORTANT DISCLAIMER: This driver is not commercially supported by
++ Sierra Wireless. Use at your own risk.
++
++ This driver is free software; you can redistribute it and/or modify
++ it under the terms of Version 2 of the GNU General Public License as
++ published by the Free Software Foundation.
++
++ Portions based on the option driver by Matthias Urlichs <smurf at smurf.noris.de>
++ Whom based his on the Keyspan driver by Hugh Blemings <hugh at blemings.org>
++
++ History:
++*/
++
++#define DRIVER_VERSION "v.1.0.5"
++#define DRIVER_AUTHOR "Kevin Lloyd <linux at sierrawireless.com>"
++#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
+
+ #include <linux/kernel.h>
+-#include <linux/init.h>
++#include <linux/jiffies.h>
++#include <linux/errno.h>
+ #include <linux/tty.h>
++#include <linux/tty_flip.h>
+ #include <linux/module.h>
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
+
++
+ static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
++ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
++ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+- /* Following devices are supported in the airprime.c driver */
+- /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */
+- /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */
++
++ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
++ { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+ { }
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+
++static struct usb_device_id id_table_1port [] = {
++ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
++ { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
++ { }
++};
++
++static struct usb_device_id id_table_3port [] = {
++ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
++ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
++ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
++ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
++ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
++ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
++ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
++ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
++ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
++ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
++ { }
++};
++
+ static struct usb_driver sierra_driver = {
+- .name = "sierra_wireless",
+- .probe = usb_serial_probe,
+- .disconnect = usb_serial_disconnect,
+- .id_table = id_table,
++ .name = "sierra",
++ .probe = usb_serial_probe,
++ .disconnect = usb_serial_disconnect,
++ .id_table = id_table,
++ .no_dynamic_id = 1,
++};
++
++
++static int debug;
++
++/* per port private data */
++#define N_IN_URB 4
++#define N_OUT_URB 1
++#define IN_BUFLEN 4096
++#define OUT_BUFLEN 128
++
++struct sierra_port_private {
++ /* Input endpoints and buffer for this port */
++ struct urb *in_urbs[N_IN_URB];
++ char in_buffer[N_IN_URB][IN_BUFLEN];
++ /* Output endpoints and buffer for this port */
++ struct urb *out_urbs[N_OUT_URB];
++ char out_buffer[N_OUT_URB][OUT_BUFLEN];
++
++ /* Settings for the port */
++ int rts_state; /* Handshaking pins (outputs) */
++ int dtr_state;
++ int cts_state; /* Handshaking pins (inputs) */
++ int dsr_state;
++ int dcd_state;
++ int ri_state;
++
++ unsigned long tx_start_time[N_OUT_URB];
++};
++
++static int sierra_send_setup(struct usb_serial_port *port)
++{
++ struct usb_serial *serial = port->serial;
++ struct sierra_port_private *portdata;
++
++ dbg("%s", __FUNCTION__);
++
++ portdata = usb_get_serial_port_data(port);
++
++ if (port->tty) {
++ int val = 0;
++ if (portdata->dtr_state)
++ val |= 0x01;
++ if (portdata->rts_state)
++ val |= 0x02;
++
++ return usb_control_msg(serial->dev,
++ usb_rcvctrlpipe(serial->dev, 0),
++ 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
++ }
++
++ return 0;
++}
++
++static void sierra_rx_throttle(struct usb_serial_port *port)
++{
++ dbg("%s", __FUNCTION__);
++}
++
++static void sierra_rx_unthrottle(struct usb_serial_port *port)
++{
++ dbg("%s", __FUNCTION__);
++}
++
++static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
++{
++ /* Unfortunately, I don't know how to send a break */
++ dbg("%s", __FUNCTION__);
++}
++
++static void sierra_set_termios(struct usb_serial_port *port,
++ struct termios *old_termios)
++{
++ dbg("%s", __FUNCTION__);
++
++ sierra_send_setup(port);
++}
++
++static int sierra_tiocmget(struct usb_serial_port *port, struct file *file)
++{
++ unsigned int value;
++ struct sierra_port_private *portdata;
++
++ portdata = usb_get_serial_port_data(port);
++
++ value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
++ ((portdata->dtr_state) ? TIOCM_DTR : 0) |
++ ((portdata->cts_state) ? TIOCM_CTS : 0) |
++ ((portdata->dsr_state) ? TIOCM_DSR : 0) |
++ ((portdata->dcd_state) ? TIOCM_CAR : 0) |
++ ((portdata->ri_state) ? TIOCM_RNG : 0);
++
++ return value;
++}
++
++static int sierra_tiocmset(struct usb_serial_port *port, struct file *file,
++ unsigned int set, unsigned int clear)
++{
++ struct sierra_port_private *portdata;
++
++ portdata = usb_get_serial_port_data(port);
++
++ if (set & TIOCM_RTS)
++ portdata->rts_state = 1;
++ if (set & TIOCM_DTR)
++ portdata->dtr_state = 1;
++
++ if (clear & TIOCM_RTS)
++ portdata->rts_state = 0;
++ if (clear & TIOCM_DTR)
++ portdata->dtr_state = 0;
++ return sierra_send_setup(port);
++}
++
++static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ return -ENOIOCTLCMD;
++}
++
++/* Write */
++static int sierra_write(struct usb_serial_port *port,
++ const unsigned char *buf, int count)
++{
++ struct sierra_port_private *portdata;
++ int i;
++ int left, todo;
++ struct urb *this_urb = NULL; /* spurious */
++ int err;
++
++ portdata = usb_get_serial_port_data(port);
++
++ dbg("%s: write (%d chars)", __FUNCTION__, count);
++
++ i = 0;
++ left = count;
++ for (i=0; left > 0 && i < N_OUT_URB; i++) {
++ todo = left;
++ if (todo > OUT_BUFLEN)
++ todo = OUT_BUFLEN;
++
++ this_urb = portdata->out_urbs[i];
++ if (this_urb->status == -EINPROGRESS) {
++ if (time_before(jiffies,
++ portdata->tx_start_time[i] + 10 * HZ))
++ continue;
++ usb_unlink_urb(this_urb);
++ continue;
++ }
++ if (this_urb->status != 0)
++ dbg("usb_write %p failed (err=%d)",
++ this_urb, this_urb->status);
++
++ dbg("%s: endpoint %d buf %d", __FUNCTION__,
++ usb_pipeendpoint(this_urb->pipe), i);
++
++ /* send the data */
++ memcpy (this_urb->transfer_buffer, buf, todo);
++ this_urb->transfer_buffer_length = todo;
++
++ this_urb->dev = port->serial->dev;
++ err = usb_submit_urb(this_urb, GFP_ATOMIC);
++ if (err) {
++ dbg("usb_submit_urb %p (write bulk) failed "
++ "(%d, has %d)", this_urb,
++ err, this_urb->status);
++ continue;
++ }
++ portdata->tx_start_time[i] = jiffies;
++ buf += todo;
++ left -= todo;
++ }
++
++ count -= left;
++ dbg("%s: wrote (did %d)", __FUNCTION__, count);
++ return count;
++}
++
++static void sierra_indat_callback(struct urb *urb)
++{
++ int err;
++ int endpoint;
++ struct usb_serial_port *port;
++ struct tty_struct *tty;
++ unsigned char *data = urb->transfer_buffer;
++
++ dbg("%s: %p", __FUNCTION__, urb);
++
++ endpoint = usb_pipeendpoint(urb->pipe);
++ port = (struct usb_serial_port *) urb->context;
++
++ if (urb->status) {
++ dbg("%s: nonzero status: %d on endpoint %02x.",
++ __FUNCTION__, urb->status, endpoint);
++ } else {
++ tty = port->tty;
++ if (urb->actual_length) {
++ tty_buffer_request_room(tty, urb->actual_length);
++ tty_insert_flip_string(tty, data, urb->actual_length);
++ tty_flip_buffer_push(tty);
++ } else {
++ dbg("%s: empty read urb received", __FUNCTION__);
++ }
++
++ /* Resubmit urb so we continue receiving */
++ if (port->open_count && urb->status != -ESHUTDOWN) {
++ err = usb_submit_urb(urb, GFP_ATOMIC);
++ if (err)
++ printk(KERN_ERR "%s: resubmit read urb failed. "
++ "(%d)", __FUNCTION__, err);
++ }
++ }
++ return;
++}
++
++static void sierra_outdat_callback(struct urb *urb)
++{
++ struct usb_serial_port *port;
++
++ dbg("%s", __FUNCTION__);
++
++ port = (struct usb_serial_port *) urb->context;
++
++ usb_serial_port_softint(port);
++}
++
++static void sierra_instat_callback(struct urb *urb)
++{
++ int err;
++ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
++ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
++ struct usb_serial *serial = port->serial;
++
++ dbg("%s", __FUNCTION__);
++ dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
++
++ if (urb->status == 0) {
++ struct usb_ctrlrequest *req_pkt =
++ (struct usb_ctrlrequest *)urb->transfer_buffer;
++
++ if (!req_pkt) {
++ dbg("%s: NULL req_pkt\n", __FUNCTION__);
++ return;
++ }
++ if ((req_pkt->bRequestType == 0xA1) &&
++ (req_pkt->bRequest == 0x20)) {
++ int old_dcd_state;
++ unsigned char signals = *((unsigned char *)
++ urb->transfer_buffer +
++ sizeof(struct usb_ctrlrequest));
++
++ dbg("%s: signal x%x", __FUNCTION__, signals);
++
++ old_dcd_state = portdata->dcd_state;
++ portdata->cts_state = 1;
++ portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
++ portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
++ portdata->ri_state = ((signals & 0x08) ? 1 : 0);
++
++ if (port->tty && !C_CLOCAL(port->tty) &&
++ old_dcd_state && !portdata->dcd_state)
++ tty_hangup(port->tty);
++ } else {
++ dbg("%s: type %x req %x", __FUNCTION__,
++ req_pkt->bRequestType,req_pkt->bRequest);
++ }
++ } else
++ dbg("%s: error %d", __FUNCTION__, urb->status);
++
++ /* Resubmit urb so we continue receiving IRQ data */
++ if (urb->status != -ESHUTDOWN) {
++ urb->dev = serial->dev;
++ err = usb_submit_urb(urb, GFP_ATOMIC);
++ if (err)
++ dbg("%s: resubmit intr urb failed. (%d)",
++ __FUNCTION__, err);
++ }
++}
++
++static int sierra_write_room(struct usb_serial_port *port)
++{
++ struct sierra_port_private *portdata;
++ int i;
++ int data_len = 0;
++ struct urb *this_urb;
++
++ portdata = usb_get_serial_port_data(port);
++
++ for (i=0; i < N_OUT_URB; i++) {
++ this_urb = portdata->out_urbs[i];
++ if (this_urb && this_urb->status != -EINPROGRESS)
++ data_len += OUT_BUFLEN;
++ }
++
++ dbg("%s: %d", __FUNCTION__, data_len);
++ return data_len;
++}
++
++static int sierra_chars_in_buffer(struct usb_serial_port *port)
++{
++ struct sierra_port_private *portdata;
++ int i;
++ int data_len = 0;
++ struct urb *this_urb;
++
++ portdata = usb_get_serial_port_data(port);
++
++ for (i=0; i < N_OUT_URB; i++) {
++ this_urb = portdata->out_urbs[i];
++ if (this_urb && this_urb->status == -EINPROGRESS)
++ data_len += this_urb->transfer_buffer_length;
++ }
++ dbg("%s: %d", __FUNCTION__, data_len);
++ return data_len;
++}
++
++static int sierra_open(struct usb_serial_port *port, struct file *filp)
++{
++ struct sierra_port_private *portdata;
++ struct usb_serial *serial = port->serial;
++ int i, err;
++ struct urb *urb;
++
++ portdata = usb_get_serial_port_data(port);
++
++ dbg("%s", __FUNCTION__);
++
++ /* Set some sane defaults */
++ portdata->rts_state = 1;
++ portdata->dtr_state = 1;
++
++ /* Reset low level data toggle and start reading from endpoints */
++ for (i = 0; i < N_IN_URB; i++) {
++ urb = portdata->in_urbs[i];
++ if (! urb)
++ continue;
++ if (urb->dev != serial->dev) {
++ dbg("%s: dev %p != %p", __FUNCTION__,
++ urb->dev, serial->dev);
++ continue;
++ }
++
++ /*
++ * make sure endpoint data toggle is synchronized with the
++ * device
++ */
++ usb_clear_halt(urb->dev, urb->pipe);
++
++ err = usb_submit_urb(urb, GFP_KERNEL);
++ if (err) {
++ dbg("%s: submit urb %d failed (%d) %d",
++ __FUNCTION__, i, err,
++ urb->transfer_buffer_length);
++ }
++ }
++
++ /* Reset low level data toggle on out endpoints */
++ for (i = 0; i < N_OUT_URB; i++) {
++ urb = portdata->out_urbs[i];
++ if (! urb)
++ continue;
++ urb->dev = serial->dev;
++ /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), 0); */
++ }
++
++ port->tty->low_latency = 1;
++
++ sierra_send_setup(port);
++
++ return (0);
++}
++
++static inline void stop_urb(struct urb *urb)
++{
++ if (urb && urb->status == -EINPROGRESS)
++ usb_kill_urb(urb);
++}
++
++static void sierra_close(struct usb_serial_port *port, struct file *filp)
++{
++ int i;
++ struct usb_serial *serial = port->serial;
++ struct sierra_port_private *portdata;
++
++ dbg("%s", __FUNCTION__);
++ portdata = usb_get_serial_port_data(port);
++
++ portdata->rts_state = 0;
++ portdata->dtr_state = 0;
++
++ if (serial->dev) {
++ sierra_send_setup(port);
++
++ /* Stop reading/writing urbs */
++ for (i = 0; i < N_IN_URB; i++)
++ stop_urb(portdata->in_urbs[i]);
++ for (i = 0; i < N_OUT_URB; i++)
++ stop_urb(portdata->out_urbs[i]);
++ }
++ port->tty = NULL;
++}
++
++/* Helper functions used by sierra_setup_urbs */
++static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
++ int dir, void *ctx, char *buf, int len,
++ usb_complete_t callback)
++{
++ struct urb *urb;
++
++ if (endpoint == -1)
++ return NULL; /* endpoint not needed */
++
++ urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
++ if (urb == NULL) {
++ dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
++ return NULL;
++ }
++
++ /* Fill URB using supplied data. */
++ usb_fill_bulk_urb(urb, serial->dev,
++ usb_sndbulkpipe(serial->dev, endpoint) | dir,
++ buf, len, callback, ctx);
++
++ return urb;
++}
++
++/* Setup urbs */
++static void sierra_setup_urbs(struct usb_serial *serial)
++{
++ int i,j;
++ struct usb_serial_port *port;
++ struct sierra_port_private *portdata;
++
++ dbg("%s", __FUNCTION__);
++
++ for (i = 0; i < serial->num_ports; i++) {
++ port = serial->port[i];
++ portdata = usb_get_serial_port_data(port);
++
++ /* Do indat endpoints first */
++ for (j = 0; j < N_IN_URB; ++j) {
++ portdata->in_urbs[j] = sierra_setup_urb (serial,
++ port->bulk_in_endpointAddress, USB_DIR_IN, port,
++ portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback);
++ }
++
++ /* outdat endpoints */
++ for (j = 0; j < N_OUT_URB; ++j) {
++ portdata->out_urbs[j] = sierra_setup_urb (serial,
++ port->bulk_out_endpointAddress, USB_DIR_OUT, port,
++ portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback);
++ }
++ }
++}
++
++static int sierra_startup(struct usb_serial *serial)
++{
++ int i, err;
++ struct usb_serial_port *port;
++ struct sierra_port_private *portdata;
++
++ dbg("%s", __FUNCTION__);
++
++ /* Now setup per port private data */
++ for (i = 0; i < serial->num_ports; i++) {
++ port = serial->port[i];
++ portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
++ if (!portdata) {
++ dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
++ __FUNCTION__, i);
++ return (1);
++ }
++
++ usb_set_serial_port_data(port, portdata);
++
++ if (! port->interrupt_in_urb)
++ continue;
++ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
++ if (err)
++ dbg("%s: submit irq_in urb failed %d",
++ __FUNCTION__, err);
++ }
++
++ sierra_setup_urbs(serial);
++
++ return (0);
++}
++
++static void sierra_shutdown(struct usb_serial *serial)
++{
++ int i, j;
++ struct usb_serial_port *port;
++ struct sierra_port_private *portdata;
++
++ dbg("%s", __FUNCTION__);
++
++ /* Stop reading/writing urbs */
++ for (i = 0; i < serial->num_ports; ++i) {
++ port = serial->port[i];
++ portdata = usb_get_serial_port_data(port);
++ for (j = 0; j < N_IN_URB; j++)
++ stop_urb(portdata->in_urbs[j]);
++ for (j = 0; j < N_OUT_URB; j++)
++ stop_urb(portdata->out_urbs[j]);
++ }
++
++ /* Now free them */
++ for (i = 0; i < serial->num_ports; ++i) {
++ port = serial->port[i];
++ portdata = usb_get_serial_port_data(port);
++
++ for (j = 0; j < N_IN_URB; j++) {
++ if (portdata->in_urbs[j]) {
++ usb_free_urb(portdata->in_urbs[j]);
++ portdata->in_urbs[j] = NULL;
++ }
++ }
++ for (j = 0; j < N_OUT_URB; j++) {
++ if (portdata->out_urbs[j]) {
++ usb_free_urb(portdata->out_urbs[j]);
++ portdata->out_urbs[j] = NULL;
++ }
++ }
++ }
++
++ /* Now free per port private data */
++ for (i = 0; i < serial->num_ports; i++) {
++ port = serial->port[i];
++ kfree(usb_get_serial_port_data(port));
++ }
++}
++
++static struct usb_serial_driver sierra_1port_device = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "sierra1",
++ },
++ .description = "Sierra USB modem (1 port)",
++ .id_table = id_table_1port,
++ .num_interrupt_in = NUM_DONT_CARE,
++ .num_bulk_in = 1,
++ .num_bulk_out = 1,
++ .num_ports = 1,
++ .open = sierra_open,
++ .close = sierra_close,
++ .write = sierra_write,
++ .write_room = sierra_write_room,
++ .chars_in_buffer = sierra_chars_in_buffer,
++ .throttle = sierra_rx_throttle,
++ .unthrottle = sierra_rx_unthrottle,
++ .ioctl = sierra_ioctl,
++ .set_termios = sierra_set_termios,
++ .break_ctl = sierra_break_ctl,
++ .tiocmget = sierra_tiocmget,
++ .tiocmset = sierra_tiocmset,
++ .attach = sierra_startup,
++ .shutdown = sierra_shutdown,
++ .read_int_callback = sierra_instat_callback,
+ };
+
+-static struct usb_serial_driver sierra_device = {
++static struct usb_serial_driver sierra_3port_device = {
+ .driver = {
+- .owner = THIS_MODULE,
+- .name = "Sierra_Wireless",
++ .owner = THIS_MODULE,
++ .name = "sierra3",
+ },
+- .id_table = id_table,
+- .num_interrupt_in = NUM_DONT_CARE,
+- .num_bulk_in = NUM_DONT_CARE,
+- .num_bulk_out = NUM_DONT_CARE,
+- .num_ports = 3,
++ .description = "Sierra USB modem (3 port)",
++ .id_table = id_table_3port,
++ .num_interrupt_in = NUM_DONT_CARE,
++ .num_bulk_in = 3,
++ .num_bulk_out = 3,
++ .num_ports = 3,
++ .open = sierra_open,
++ .close = sierra_close,
++ .write = sierra_write,
++ .write_room = sierra_write_room,
++ .chars_in_buffer = sierra_chars_in_buffer,
++ .throttle = sierra_rx_throttle,
++ .unthrottle = sierra_rx_unthrottle,
++ .ioctl = sierra_ioctl,
++ .set_termios = sierra_set_termios,
++ .break_ctl = sierra_break_ctl,
++ .tiocmget = sierra_tiocmget,
++ .tiocmset = sierra_tiocmset,
++ .attach = sierra_startup,
++ .shutdown = sierra_shutdown,
++ .read_int_callback = sierra_instat_callback,
+ };
+
++/* Functions used by new usb-serial code. */
+ static int __init sierra_init(void)
+ {
+ int retval;
+-
+- retval = usb_serial_register(&sierra_device);
++ retval = usb_serial_register(&sierra_1port_device);
++ if (retval)
++ goto failed_1port_device_register;
++ retval = usb_serial_register(&sierra_3port_device);
+ if (retval)
+- return retval;
++ goto failed_3port_device_register;
++
++
+ retval = usb_register(&sierra_driver);
+ if (retval)
+- usb_serial_deregister(&sierra_device);
++ goto failed_driver_register;
++
++ info(DRIVER_DESC ": " DRIVER_VERSION);
++
++ return 0;
++
++failed_driver_register:
++ usb_serial_deregister(&sierra_3port_device);
++failed_3port_device_register:
++ usb_serial_deregister(&sierra_1port_device);
++failed_1port_device_register:
+ return retval;
+ }
+
+ static void __exit sierra_exit(void)
+ {
+- usb_deregister(&sierra_driver);
+- usb_serial_deregister(&sierra_device);
++ usb_deregister (&sierra_driver);
++ usb_serial_deregister(&sierra_1port_device);
++ usb_serial_deregister(&sierra_3port_device);
+ }
+
+ module_init(sierra_init);
+ module_exit(sierra_exit);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_VERSION(DRIVER_VERSION);
+ MODULE_LICENSE("GPL");
++
++#ifdef CONFIG_USB_DEBUG
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug messages");
++#endif
++
+diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
+index ac9b8ee..07400c0 100644
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -166,9 +166,9 @@ static int ti_tiocmget(struct usb_serial
+ static int ti_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear);
+ static void ti_break(struct usb_serial_port *port, int break_state);
+-static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs);
+-static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs);
+-static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs);
++static void ti_interrupt_callback(struct urb *urb);
++static void ti_bulk_in_callback(struct urb *urb);
++static void ti_bulk_out_callback(struct urb *urb);
+
+ static void ti_recv(struct device *dev, struct tty_struct *tty,
+ unsigned char *data, int length);
+@@ -1098,7 +1098,7 @@ static void ti_break(struct usb_serial_p
+ }
+
+
+-static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs)
++static void ti_interrupt_callback(struct urb *urb)
+ {
+ struct ti_device *tdev = (struct ti_device *)urb->context;
+ struct usb_serial_port *port;
+@@ -1178,7 +1178,7 @@ exit:
+ }
+
+
+-static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs)
++static void ti_bulk_in_callback(struct urb *urb)
+ {
+ struct ti_port *tport = (struct ti_port *)urb->context;
+ struct usb_serial_port *port = tport->tp_port;
+@@ -1241,7 +1241,7 @@ exit:
+ }
+
+
+-static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs)
++static void ti_bulk_out_callback(struct urb *urb)
+ {
+ struct ti_port *tport = (struct ti_port *)urb->context;
+ struct usb_serial_port *port = tport->tp_port;
+diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
+index e06a41b..8006e51 100644
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -676,33 +676,29 @@ int usb_serial_probe(struct usb_interfac
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+-
+- if ((endpoint->bEndpointAddress & 0x80) &&
+- ((endpoint->bmAttributes & 3) == 0x02)) {
++
++ if (usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in on endpoint %d", i);
+ bulk_in_endpoint[num_bulk_in] = endpoint;
+ ++num_bulk_in;
+ }
+
+- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+- ((endpoint->bmAttributes & 3) == 0x02)) {
++ if (usb_endpoint_is_bulk_out(endpoint)) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out on endpoint %d", i);
+ bulk_out_endpoint[num_bulk_out] = endpoint;
+ ++num_bulk_out;
+ }
+-
+- if ((endpoint->bEndpointAddress & 0x80) &&
+- ((endpoint->bmAttributes & 3) == 0x03)) {
++
++ if (usb_endpoint_is_int_in(endpoint)) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in on endpoint %d", i);
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
+ ++num_interrupt_in;
+ }
+
+- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+- ((endpoint->bmAttributes & 3) == 0x03)) {
++ if (usb_endpoint_is_int_out(endpoint)) {
+ /* we found an interrupt out endpoint */
+ dbg("found interrupt out on endpoint %d", i);
+ interrupt_out_endpoint[num_interrupt_out] = endpoint;
+@@ -716,14 +712,15 @@ int usb_serial_probe(struct usb_interfac
+ if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
+ ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
+- (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID))) {
++ (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
++ ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
++ (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
+ if (interface != dev->actconfig->interface[0]) {
+ /* check out the endpoints of the other interface*/
+ iface_desc = dev->actconfig->interface[0]->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+- if ((endpoint->bEndpointAddress & 0x80) &&
+- ((endpoint->bmAttributes & 3) == 0x03)) {
++ if (usb_endpoint_is_int_in(endpoint)) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in for Prolific device on separate interface");
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
+@@ -937,7 +934,10 @@ int usb_serial_probe(struct usb_interfac
+
+ snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
+ dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
+- device_register (&port->dev);
++ retval = device_register(&port->dev);
++ if (retval)
++ dev_err(&port->dev, "Error registering port device, "
++ "continuing\n");
+ }
+
+ usb_serial_console_init (debug, minor);
+@@ -1015,7 +1015,7 @@ void usb_serial_disconnect(struct usb_in
+ dev_info(dev, "device disconnected\n");
+ }
+
+-static struct tty_operations serial_ops = {
++static const struct tty_operations serial_ops = {
+ .open = serial_open,
+ .close = serial_close,
+ .write = serial_write,
+diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
+index 88949f7..befe2e1 100644
+--- a/drivers/usb/serial/visor.c
++++ b/drivers/usb/serial/visor.c
+@@ -47,9 +47,9 @@ static int visor_calc_num_ports(struct
+ static void visor_shutdown (struct usb_serial *serial);
+ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+ static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+-static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs);
++static void visor_write_bulk_callback (struct urb *urb);
++static void visor_read_bulk_callback (struct urb *urb);
++static void visor_read_int_callback (struct urb *urb);
+ static int clie_3_5_startup (struct usb_serial *serial);
+ static int treo_attach (struct usb_serial *serial);
+ static int clie_5_attach (struct usb_serial *serial);
+@@ -471,7 +471,7 @@ static int visor_chars_in_buffer (struct
+ }
+
+
+-static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void visor_write_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct visor_private *priv = usb_get_serial_port_data(port);
+@@ -494,7 +494,7 @@ static void visor_write_bulk_callback (s
+ }
+
+
+-static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
++static void visor_read_bulk_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct visor_private *priv = usb_get_serial_port_data(port);
+@@ -539,7 +539,7 @@ static void visor_read_bulk_callback (st
+ return;
+ }
+
+-static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs)
++static void visor_read_int_callback (struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
+index 6e6c793..4d1cd7a 100644
+--- a/drivers/usb/serial/whiteheat.c
++++ b/drivers/usb/serial/whiteheat.c
+@@ -152,8 +152,8 @@ static void whiteheat_break_ctl (struct
+ static int whiteheat_chars_in_buffer (struct usb_serial_port *port);
+ static void whiteheat_throttle (struct usb_serial_port *port);
+ static void whiteheat_unthrottle (struct usb_serial_port *port);
+-static void whiteheat_read_callback (struct urb *urb, struct pt_regs *regs);
+-static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs);
++static void whiteheat_read_callback (struct urb *urb);
++static void whiteheat_write_callback (struct urb *urb);
+
+ static struct usb_serial_driver whiteheat_fake_device = {
+ .driver = {
+@@ -235,8 +235,8 @@ struct whiteheat_private {
+ /* local function prototypes */
+ static int start_command_port(struct usb_serial *serial);
+ static void stop_command_port(struct usb_serial *serial);
+-static void command_port_write_callback(struct urb *urb, struct pt_regs *regs);
+-static void command_port_read_callback(struct urb *urb, struct pt_regs *regs);
++static void command_port_write_callback(struct urb *urb);
++static void command_port_read_callback(struct urb *urb);
+
+ static int start_port_read(struct usb_serial_port *port);
+ static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head);
+@@ -958,7 +958,7 @@ static void whiteheat_unthrottle (struct
+ /*****************************************************************************
+ * Connect Tech's White Heat callback routines
+ *****************************************************************************/
+-static void command_port_write_callback (struct urb *urb, struct pt_regs *regs)
++static void command_port_write_callback (struct urb *urb)
+ {
+ dbg("%s", __FUNCTION__);
+
+@@ -969,7 +969,7 @@ static void command_port_write_callback
+ }
+
+
+-static void command_port_read_callback (struct urb *urb, struct pt_regs *regs)
++static void command_port_read_callback (struct urb *urb)
+ {
+ struct usb_serial_port *command_port = (struct usb_serial_port *)urb->context;
+ struct whiteheat_command_private *command_info;
+@@ -1019,7 +1019,7 @@ static void command_port_read_callback (
+ }
+
+
+-static void whiteheat_read_callback(struct urb *urb, struct pt_regs *regs)
++static void whiteheat_read_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct whiteheat_urb_wrap *wrap;
+@@ -1061,7 +1061,7 @@ static void whiteheat_read_callback(stru
+ }
+
+
+-static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs)
++static void whiteheat_write_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct whiteheat_private *info = usb_get_serial_port_data(port);
+diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
+index be9eec2..fe2c4cd 100644
+--- a/drivers/usb/storage/Kconfig
++++ b/drivers/usb/storage/Kconfig
+@@ -8,8 +8,7 @@ comment "may also be needed; see USB_STO
+
+ config USB_STORAGE
+ tristate "USB Mass Storage support"
+- depends on USB
+- select SCSI
++ depends on USB && SCSI
+ ---help---
+ Say Y here if you want to connect USB mass storage devices to your
+ computer's USB port. This is the driver you need for USB
+@@ -18,7 +17,7 @@ config USB_STORAGE
+ similar devices. This driver may also be used for some cameras
+ and card readers.
+
+- This option 'selects' (turns on, enables) 'SCSI', but you
++ This option depends on 'SCSI' support being enabled, but you
+ probably also need 'SCSI device support: SCSI disk support'
+ (BLK_DEV_SD) for most USB storage devices.
+
+@@ -120,7 +119,7 @@ config USB_STORAGE_ALAUDA
+ Say Y here to include additional code to support the Olympus MAUSB-10
+ and Fujifilm DPC-R1 USB Card reader/writer devices.
+
+- These devices are based on the Alauda chip and support support both
++ These devices are based on the Alauda chip and support both
+ XD and SmartMedia cards.
+
+ config USB_STORAGE_ONETOUCH
+@@ -135,6 +134,18 @@ config USB_STORAGE_ONETOUCH
+ this input in any keybinding software. (e.g. gnome's keyboard short-
+ cuts)
+
++config USB_STORAGE_KARMA
++ bool "Support for Rio Karma music player"
++ depends on USB_STORAGE
++ help
++ Say Y here to include additional code to support the Rio Karma
++ USB interface.
++
++ This code places the Rio Karma into mass storage mode, enabling
++ it to be mounted as an ordinary filesystem. Performing an eject
++ on the resulting scsi device node returns the Karma to normal
++ operation.
++
+ config USB_LIBUSUAL
+ bool "The shared table of common (or usual) storage devices"
+ depends on USB
+diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
+index 8cbba22..023969b 100644
+--- a/drivers/usb/storage/Makefile
++++ b/drivers/usb/storage/Makefile
+@@ -20,6 +20,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DAT
+ usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
+ usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
+ usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
++usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
+
+ usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
+ initializers.o $(usb-storage-obj-y)
+diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
+index ab173b3..5b06f92 100644
+--- a/drivers/usb/storage/initializers.c
++++ b/drivers/usb/storage/initializers.c
+@@ -45,12 +45,6 @@
+ #include "debug.h"
+ #include "transport.h"
+
+-#define RIO_MSC 0x08
+-#define RIOP_INIT "RIOP\x00\x01\x08"
+-#define RIOP_INIT_LEN 7
+-#define RIO_SEND_LEN 40
+-#define RIO_RECV_LEN 0x200
+-
+ /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
+ * mode */
+ int usb_stor_euscsi_init(struct us_data *us)
+@@ -97,70 +91,3 @@ int usb_stor_ucr61s2b_init(struct us_dat
+
+ return (res ? -1 : 0);
+ }
+-
+-/* Place the Rio Karma into mass storage mode.
+- *
+- * The initialization begins by sending 40 bytes starting
+- * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte
+- * packet with the high four bits set and everything else null.
+- *
+- * Next, we send RIOP\x80\x00\x08\x00. Each time, a 512 byte response
+- * must be read, but we must loop until byte 5 in the response is 0x08,
+- * indicating success. */
+-int rio_karma_init(struct us_data *us)
+-{
+- int result, partial;
+- char *recv;
+- unsigned long timeout;
+-
+- // us->iobuf is big enough to hold cmd but not receive
+- if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL)))
+- goto die_nomem;
+-
+- US_DEBUGP("Initializing Karma...\n");
+-
+- memset(us->iobuf, 0, RIO_SEND_LEN);
+- memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN);
+-
+- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+- us->iobuf, RIO_SEND_LEN, &partial);
+- if (result != USB_STOR_XFER_GOOD)
+- goto die;
+-
+- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+- recv, RIO_RECV_LEN, &partial);
+- if (result != USB_STOR_XFER_GOOD)
+- goto die;
+-
+- us->iobuf[4] = 0x80;
+- us->iobuf[5] = 0;
+- timeout = jiffies + msecs_to_jiffies(3000);
+- for (;;) {
+- US_DEBUGP("Sending init command\n");
+- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+- us->iobuf, RIO_SEND_LEN, &partial);
+- if (result != USB_STOR_XFER_GOOD)
+- goto die;
+-
+- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+- recv, RIO_RECV_LEN, &partial);
+- if (result != USB_STOR_XFER_GOOD)
+- goto die;
+-
+- if (recv[5] == RIO_MSC)
+- break;
+- if (time_after(jiffies, timeout))
+- goto die;
+- msleep(10);
+- }
+- US_DEBUGP("Karma initialized.\n");
+- kfree(recv);
+- return 0;
+-
+-die:
+- kfree(recv);
+-die_nomem:
+- US_DEBUGP("Could not initialize karma.\n");
+- return USB_STOR_TRANSPORT_FAILED;
+-}
+-
+diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
+index 927f778..e2967a4 100644
+--- a/drivers/usb/storage/initializers.h
++++ b/drivers/usb/storage/initializers.h
+@@ -47,4 +47,3 @@ int usb_stor_euscsi_init(struct us_data
+ /* This function is required to activate all four slots on the UCR-61S2B
+ * flash reader */
+ int usb_stor_ucr61s2b_init(struct us_data *us);
+-int rio_karma_init(struct us_data *us);
+diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
+new file mode 100644
+index 0000000..0d79ae5
+--- /dev/null
++++ b/drivers/usb/storage/karma.c
+@@ -0,0 +1,155 @@
++/* Driver for Rio Karma
++ *
++ * (c) 2006 Bob Copeland <me at bobcopeland.com>
++ * (c) 2006 Keith Bennett <keith at mcs.st-and.ac.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; 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.
++ */
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++
++#include "usb.h"
++#include "transport.h"
++#include "debug.h"
++#include "karma.h"
++
++#define RIO_PREFIX "RIOP\x00"
++#define RIO_PREFIX_LEN 5
++#define RIO_SEND_LEN 40
++#define RIO_RECV_LEN 0x200
++
++#define RIO_ENTER_STORAGE 0x1
++#define RIO_LEAVE_STORAGE 0x2
++#define RIO_RESET 0xC
++
++extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data *);
++
++struct karma_data {
++ int in_storage;
++ char *recv;
++};
++
++/*
++ * Send commands to Rio Karma.
++ *
++ * For each command we send 40 bytes starting 'RIOP\0' followed by
++ * the command number and a sequence number, which the device will ack
++ * with a 512-byte packet with the high four bits set and everything
++ * else null. Then we send 'RIOP\x80' followed by a zero and the
++ * sequence number, until byte 5 in the response repeats the sequence
++ * number.
++ */
++static int rio_karma_send_command(char cmd, struct us_data *us)
++{
++ int result, partial;
++ unsigned long timeout;
++ static unsigned char seq = 1;
++ struct karma_data *data = (struct karma_data *) us->extra;
++
++ US_DEBUGP("karma: sending command %04x\n", cmd);
++ memset(us->iobuf, 0, RIO_SEND_LEN);
++ memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
++ us->iobuf[5] = cmd;
++ us->iobuf[6] = seq;
++
++ timeout = jiffies + msecs_to_jiffies(6000);
++ for (;;) {
++ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ us->iobuf, RIO_SEND_LEN, &partial);
++ if (result != USB_STOR_XFER_GOOD)
++ goto err;
++
++ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ data->recv, RIO_RECV_LEN, &partial);
++ if (result != USB_STOR_XFER_GOOD)
++ goto err;
++
++ if (data->recv[5] == seq)
++ break;
++
++ if (time_after(jiffies, timeout))
++ goto err;
++
++ us->iobuf[4] = 0x80;
++ us->iobuf[5] = 0;
++ msleep(50);
++ }
++
++ seq++;
++ if (seq == 0)
++ seq = 1;
++
++ US_DEBUGP("karma: sent command %04x\n", cmd);
++ return 0;
++err:
++ US_DEBUGP("karma: command %04x failed\n", cmd);
++ return USB_STOR_TRANSPORT_FAILED;
++}
++
++/*
++ * Trap START_STOP and READ_10 to leave/re-enter storage mode.
++ * Everything else is propagated to the normal bulk layer.
++ */
++int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us)
++{
++ int ret;
++ struct karma_data *data = (struct karma_data *) us->extra;
++
++ if (srb->cmnd[0] == READ_10 && !data->in_storage) {
++ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
++ if (ret)
++ return ret;
++
++ data->in_storage = 1;
++ return usb_stor_Bulk_transport(srb, us);
++ } else if (srb->cmnd[0] == START_STOP) {
++ ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us);
++ if (ret)
++ return ret;
++
++ data->in_storage = 0;
++ return rio_karma_send_command(RIO_RESET, us);
++ }
++ return usb_stor_Bulk_transport(srb, us);
++}
++
++static void rio_karma_destructor(void *extra)
++{
++ struct karma_data *data = (struct karma_data *) extra;
++ kfree(data->recv);
++}
++
++int rio_karma_init(struct us_data *us)
++{
++ int ret = 0;
++ struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
++ if (!data)
++ goto out;
++
++ data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
++ if (!data->recv) {
++ kfree(data);
++ goto out;
++ }
++
++ us->extra = data;
++ us->extra_destructor = rio_karma_destructor;
++ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
++ data->in_storage = (ret == 0);
++out:
++ return ret;
++}
+diff --git a/drivers/usb/storage/karma.h b/drivers/usb/storage/karma.h
+new file mode 100644
+index 0000000..8a60972
+--- /dev/null
++++ b/drivers/usb/storage/karma.h
+@@ -0,0 +1,7 @@
++#ifndef _KARMA_USB_H
++#define _KARMA_USB_H
++
++extern int rio_karma_init(struct us_data *us);
++extern int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us);
++
++#endif
+diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
+index b1ec4a7..599ad10 100644
+--- a/drivers/usb/storage/libusual.c
++++ b/drivers/usb/storage/libusual.c
+@@ -8,6 +8,7 @@
+ #include <linux/usb.h>
+ #include <linux/usb_usual.h>
+ #include <linux/vmalloc.h>
++#include <linux/kthread.h>
+
+ /*
+ */
+@@ -117,7 +118,7 @@ static int usu_probe(struct usb_interfac
+ const struct usb_device_id *id)
+ {
+ unsigned long type;
+- int rc;
++ struct task_struct* task;
+ unsigned long flags;
+
+ type = USB_US_TYPE(id->driver_info);
+@@ -132,8 +133,9 @@ static int usu_probe(struct usb_interfac
+ stat[type].fls |= USU_MOD_FL_THREAD;
+ spin_unlock_irqrestore(&usu_lock, flags);
+
+- rc = kernel_thread(usu_probe_thread, (void*)type, CLONE_VM);
+- if (rc < 0) {
++ task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
++ if (IS_ERR(task)) {
++ int rc = PTR_ERR(task);
+ printk(KERN_WARNING "libusual: "
+ "Unable to start the thread for %s: %d\n",
+ bias_names[type], rc);
+@@ -175,8 +177,6 @@ static int usu_probe_thread(void *arg)
+ int rc;
+ unsigned long flags;
+
+- daemonize("libusual_%d", type); /* "usb-storage" is kinda too long */
+-
+ /* A completion does not work here because it's counted. */
+ down(&usu_init_notify);
+ up(&usu_init_notify);
+diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
+index 313920d..3baf448 100644
+--- a/drivers/usb/storage/onetouch.c
++++ b/drivers/usb/storage/onetouch.c
+@@ -53,7 +53,7 @@ struct usb_onetouch {
+ unsigned int is_open:1;
+ };
+
+-static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
++static void usb_onetouch_irq(struct urb *urb)
+ {
+ struct usb_onetouch *onetouch = urb->context;
+ signed char *data = onetouch->data;
+@@ -72,7 +72,6 @@ static void usb_onetouch_irq(struct urb
+ goto resubmit;
+ }
+
+- input_regs(dev, regs);
+ input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
+ input_sync(dev);
+
+@@ -135,6 +134,7 @@ int onetouch_connect_input(struct us_dat
+ struct usb_onetouch *onetouch;
+ struct input_dev *input_dev;
+ int pipe, maxp;
++ int error = -ENOMEM;
+
+ interface = ss->pusb_intf->cur_altsetting;
+
+@@ -211,15 +211,18 @@ int onetouch_connect_input(struct us_dat
+ ss->suspend_resume_hook = usb_onetouch_pm_hook;
+ #endif
+
+- input_register_device(onetouch->dev);
++ error = input_register_device(onetouch->dev);
++ if (error)
++ goto fail3;
+
+ return 0;
+
++ fail3: usb_free_urb(onetouch->irq);
+ fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN,
+ onetouch->data, onetouch->data_dma);
+ fail1: kfree(onetouch);
+ input_free_device(input_dev);
+- return -ENOMEM;
++ return error;
+ }
+
+ void onetouch_release_input(void *onetouch_)
+diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
+index a4b7df9..e1072d5 100644
+--- a/drivers/usb/storage/scsiglue.c
++++ b/drivers/usb/storage/scsiglue.c
+@@ -72,12 +72,27 @@ static const char* host_info(struct Scsi
+
+ static int slave_alloc (struct scsi_device *sdev)
+ {
++ struct us_data *us = host_to_us(sdev->host);
++
+ /*
+ * Set the INQUIRY transfer length to 36. We don't use any of
+ * the extra data and many devices choke if asked for more or
+ * less than 36 bytes.
+ */
+ sdev->inquiry_len = 36;
++
++ /*
++ * The UFI spec treates the Peripheral Qualifier bits in an
++ * INQUIRY result as reserved and requires devices to set them
++ * to 0. However the SCSI spec requires these bits to be set
++ * to 3 to indicate when a LUN is not present.
++ *
++ * Let the scanning code know if this target merely sets
++ * Peripheral Device Type to 0x1f to indicate no LUN.
++ */
++ if (us->subclass == US_SC_UFI)
++ sdev->sdev_target->pdt_1f_for_no_lun = 1;
++
+ return 0;
+ }
+
+diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
+index d6acc92..47644b5 100644
+--- a/drivers/usb/storage/transport.c
++++ b/drivers/usb/storage/transport.c
+@@ -108,7 +108,7 @@
+ /* This is the completion handler which will wake us up when an URB
+ * completes.
+ */
+-static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs)
++static void usb_stor_blocking_completion(struct urb *urb)
+ {
+ struct completion *urb_done_ptr = (struct completion *)urb->context;
+
+@@ -294,11 +294,6 @@ static int interpret_urb_result(struct u
+ return USB_STOR_XFER_ERROR;
+ return USB_STOR_XFER_STALLED;
+
+- /* timeout or excessively long NAK */
+- case -ETIMEDOUT:
+- US_DEBUGP("-- timeout or NAK\n");
+- return USB_STOR_XFER_ERROR;
+-
+ /* babble - the device tried to send more than we wanted to read */
+ case -EOVERFLOW:
+ US_DEBUGP("-- babble\n");
+diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
+index b130e17..bc1ac07 100644
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
+
+-UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100,
++/* modified by Tobias Lorenz <tobias.lorenz at gmx.net> */
++UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200,
+ "Mitsumi",
+ "USB FDD",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+@@ -152,6 +153,13 @@ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
++/* Reported by Jon Hart <Jon.Hart at web.de> */
++UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100,
++ "Nokia",
++ "E60",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
++
+ /* Reported by Sumedha Swamy <sumedhaswamy at gmail.com> and
+ * Einar Th. Einarsson <einarthered at gmail.com> */
+ UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100,
+@@ -175,6 +183,20 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
++/* Reported by Bardur Arantsson <bardur at scientician.net> */
++UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
++ "Nokia",
++ "6131",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_MAX_SECTORS_64 ),
++
++/* Reported by Alex Corcoles <alex at corcoles.net> */
++UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370,
++ "Nokia",
++ "6234",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_MAX_SECTORS_64 ),
++
+ /* Reported by Olaf Hering <olh at suse.de> from novell bug #105878 */
+ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
+ "SMSC",
+@@ -218,10 +240,12 @@ UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE ),
+
++#ifdef CONFIG_USB_STORAGE_KARMA
+ UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
+ "Rio",
+ "Rio Karma",
+- US_SC_SCSI, US_PR_BULK, rio_karma_init, 0),
++ US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0),
++#endif
+
+ /* Patch submitted by Philipp Friedrich <philipp at void.at> */
+ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
+@@ -631,6 +655,13 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x
+ "Digital Camera EX-20 DSC",
+ US_SC_8070, US_PR_DEVICE, NULL, 0 ),
+
++/* Reported by <Hendryk.Pfeiffer at gmx.de> */
++UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000,
++ "LaCie",
++ "DVD+-RW",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_GO_SLOW ),
++
+ /* Submitted by Joel Bourquard <numlock at freesurf.ch>
+ * Some versions of this device need the SubClass and Protocol overrides
+ * while others don't.
+@@ -1205,7 +1236,7 @@ UNUSUAL_DEV( 0x0e21, 0x0520, 0x0100, 0x0
+ "Cowon Systems",
+ "iAUDIO M5",
+ US_SC_DEVICE, US_PR_BULK, NULL,
+- 0 ),
++ US_FL_NEED_OVERRIDE ),
+
+ /* Submitted by Antoine Mairesse <antoine.mairesse at free.fr> */
+ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
+@@ -1254,6 +1285,13 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NO_WP_DETECT ),
+
++/* Reported by Jan Mate <mate at fiit.stuba.sk> */
++UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
++ "Sony Ericsson",
++ "P990i",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_FIX_CAPACITY ),
++
+ /* Reported by Emmanuel Vasilakis <evas at forthnet.gr> */
+ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
+ "Sony Ericsson",
+@@ -1261,6 +1299,27 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
++/* Reported by Jan Mate <mate at fiit.stuba.sk> */
++UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
++ "Sony Ericsson",
++ "P990i",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_FIX_CAPACITY ),
++
++/* Reported by Jan Mate <mate at fiit.stuba.sk> */
++UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
++ "Sony Ericsson",
++ "P990i",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_FIX_CAPACITY ),
++
++/* Reported by Jan Mate <mate at fiit.stuba.sk> */
++UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
++ "Sony Ericsson",
++ "P990i",
++ US_SC_DEVICE, US_PR_DEVICE, NULL,
++ US_FL_FIX_CAPACITY ),
++
+ /* Reported by Kevin Cernekee <kpc-usbdev at gelato.uiuc.edu>
+ * Tested on hardware version 1.10.
+ * Entry is needed only for the initializer function override.
+diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
+index 8d7bdcb..b8d6031 100644
+--- a/drivers/usb/storage/usb.c
++++ b/drivers/usb/storage/usb.c
+@@ -98,6 +98,9 @@
+ #ifdef CONFIG_USB_STORAGE_ALAUDA
+ #include "alauda.h"
+ #endif
++#ifdef CONFIG_USB_STORAGE_KARMA
++#include "karma.h"
++#endif
+
+ /* Some informational data */
+ MODULE_AUTHOR("Matthew Dharm <mdharm-usb at one-eyed-alien.net>");
+@@ -646,6 +649,14 @@ static int get_transport(struct us_data
+ break;
+ #endif
+
++#ifdef CONFIG_USB_STORAGE_KARMA
++ case US_PR_KARMA:
++ us->transport_name = "Rio Karma/Bulk";
++ us->transport = rio_karma_transport;
++ us->transport_reset = usb_stor_Bulk_reset;
++ break;
++#endif
++
+ default:
+ return -EIO;
+ }
+diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
+index b362039..296b091 100644
+--- a/drivers/usb/usb-skeleton.c
++++ b/drivers/usb/usb-skeleton.c
+@@ -1,5 +1,5 @@
+ /*
+- * USB Skeleton driver - 2.0
++ * USB Skeleton driver - 2.2
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg at kroah.com)
+ *
+@@ -7,9 +7,8 @@
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+- * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
+- * but has been rewritten to be easy to read and use, as no locks are now
+- * needed anymore.
++ * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
++ * but has been rewritten to be easier to read and use.
+ *
+ */
+
+@@ -21,6 +20,7 @@
+ #include <linux/kref.h>
+ #include <asm/uaccess.h>
+ #include <linux/usb.h>
++#include <linux/mutex.h>
+
+
+ /* Define these values to match your devices */
+@@ -32,38 +32,39 @@ static struct usb_device_id skel_table [
+ { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+ { } /* Terminating entry */
+ };
+-MODULE_DEVICE_TABLE (usb, skel_table);
++MODULE_DEVICE_TABLE(usb, skel_table);
+
+
+ /* Get a minor range for your devices from the usb maintainer */
+ #define USB_SKEL_MINOR_BASE 192
+
+ /* our private defines. if this grows any larger, use your own .h file */
+-#define MAX_TRANSFER ( PAGE_SIZE - 512 )
++#define MAX_TRANSFER (PAGE_SIZE - 512)
+ #define WRITES_IN_FLIGHT 8
+
+ /* Structure to hold all of our device specific stuff */
+ struct usb_skel {
+- struct usb_device * udev; /* the usb device for this device */
+- struct usb_interface * interface; /* the interface for this device */
++ struct usb_device *dev; /* the usb device for this device */
++ struct usb_interface *interface; /* the interface for this device */
+ struct semaphore limit_sem; /* limiting the number of writes in progress */
+- unsigned char * bulk_in_buffer; /* the buffer to receive data */
++ unsigned char *bulk_in_buffer; /* the buffer to receive data */
+ size_t bulk_in_size; /* the size of the receive buffer */
+ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
+ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
+ struct kref kref;
++ struct mutex io_mutex; /* synchronize I/O with disconnect */
+ };
+ #define to_skel_dev(d) container_of(d, struct usb_skel, kref)
+
+ static struct usb_driver skel_driver;
+
+ static void skel_delete(struct kref *kref)
+-{
++{
+ struct usb_skel *dev = to_skel_dev(kref);
+
+ usb_put_dev(dev->udev);
+- kfree (dev->bulk_in_buffer);
+- kfree (dev);
++ kfree(dev->bulk_in_buffer);
++ kfree(dev);
+ }
+
+ static int skel_open(struct inode *inode, struct file *file)
+@@ -89,6 +90,11 @@ static int skel_open(struct inode *inode
+ goto exit;
+ }
+
++ /* prevent the device from being autosuspended */
++ retval = usb_autopm_get_interface(interface);
++ if (retval)
++ goto exit;
++
+ /* increment our usage count for the device */
+ kref_get(&dev->kref);
+
+@@ -107,6 +113,12 @@ static int skel_release(struct inode *in
+ if (dev == NULL)
+ return -ENODEV;
+
++ /* allow the device to be autosuspended */
++ mutex_lock(&dev->io_mutex);
++ if (dev->interface)
++ usb_autopm_put_interface(dev->interface);
++ mutex_unlock(&dev->io_mutex);
++
+ /* decrement the count on our device */
+ kref_put(&dev->kref, skel_delete);
+ return 0;
+@@ -115,11 +127,17 @@ static int skel_release(struct inode *in
+ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+ {
+ struct usb_skel *dev;
+- int retval = 0;
++ int retval;
+ int bytes_read;
+
+ dev = (struct usb_skel *)file->private_data;
+-
++
++ mutex_lock(&dev->io_mutex);
++ if (!dev->interface) { /* disconnect() was called */
++ retval = -ENODEV;
++ goto exit;
++ }
++
+ /* do a blocking bulk read to get data from the device */
+ retval = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+@@ -135,26 +153,28 @@ static ssize_t skel_read(struct file *fi
+ retval = bytes_read;
+ }
+
++exit:
++ mutex_unlock(&dev->io_mutex);
+ return retval;
+ }
+
+-static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
++static void skel_write_bulk_callback(struct urb *urb)
+ {
+ struct usb_skel *dev;
+
+ dev = (struct usb_skel *)urb->context;
+
+ /* sync/async unlink faults aren't errors */
+- if (urb->status &&
+- !(urb->status == -ENOENT ||
++ if (urb->status &&
++ !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)) {
+- dbg("%s - nonzero write bulk status received: %d",
++ err("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ }
+
+ /* free up our allocated buffer */
+- usb_buffer_free(urb->dev, urb->transfer_buffer_length,
++ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ up(&dev->limit_sem);
+ }
+@@ -179,6 +199,12 @@ static ssize_t skel_write(struct file *f
+ goto exit;
+ }
+
++ mutex_lock(&dev->io_mutex);
++ if (!dev->interface) { /* disconnect() was called */
++ retval = -ENODEV;
++ goto error;
++ }
++
+ /* create a urb, and a buffer for it, and copy the data to the urb */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+@@ -213,17 +239,22 @@ static ssize_t skel_write(struct file *f
+ /* release our reference to this urb, the USB core will eventually free it entirely */
+ usb_free_urb(urb);
+
+-exit:
++ mutex_unlock(&dev->io_mutex);
+ return writesize;
+
+ error:
+- usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
+- usb_free_urb(urb);
++ if (urb) {
++ usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
++ usb_free_urb(urb);
++ }
++ mutex_unlock(&dev->io_mutex);
+ up(&dev->limit_sem);
++
++exit:
+ return retval;
+ }
+
+-static struct file_operations skel_fops = {
++static const struct file_operations skel_fops = {
+ .owner = THIS_MODULE,
+ .read = skel_read,
+ .write = skel_write,
+@@ -231,7 +262,7 @@ static struct file_operations skel_fops
+ .release = skel_release,
+ };
+
+-/*
++/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with the driver core
+ */
+@@ -243,7 +274,7 @@ static struct usb_class_driver skel_clas
+
+ static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
+ {
+- struct usb_skel *dev = NULL;
++ struct usb_skel *dev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ size_t buffer_size;
+@@ -252,12 +283,13 @@ static int skel_probe(struct usb_interfa
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (dev == NULL) {
++ if (!dev) {
+ err("Out of memory");
+ goto error;
+ }
+ kref_init(&dev->kref);
+ sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
++ mutex_init(&dev->io_mutex);
+
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+@@ -269,10 +301,7 @@ static int skel_probe(struct usb_interfa
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (!dev->bulk_in_endpointAddr &&
+- ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+- == USB_DIR_IN) &&
+- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+- == USB_ENDPOINT_XFER_BULK)) {
++ usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found a bulk in endpoint */
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ dev->bulk_in_size = buffer_size;
+@@ -285,10 +314,7 @@ static int skel_probe(struct usb_interfa
+ }
+
+ if (!dev->bulk_out_endpointAddr &&
+- ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+- == USB_DIR_OUT) &&
+- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+- == USB_ENDPOINT_XFER_BULK)) {
++ usb_endpoint_is_bulk_out(endpoint)) {
+ /* we found a bulk out endpoint */
+ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ }
+@@ -334,6 +360,11 @@ static void skel_disconnect(struct usb_i
+ /* give back our minor */
+ usb_deregister_dev(interface, &skel_class);
+
++ /* prevent more I/O from starting */
++ mutex_lock(&dev->io_mutex);
++ dev->interface = NULL;
++ mutex_unlock(&dev->io_mutex);
++
+ unlock_kernel();
+
+ /* decrement our usage count */
+@@ -367,7 +398,7 @@ static void __exit usb_skel_exit(void)
+ usb_deregister(&skel_driver);
+ }
+
+-module_init (usb_skel_init);
+-module_exit (usb_skel_exit);
++module_init(usb_skel_init);
++module_exit(usb_skel_exit);
+
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 702eb93..7a43020 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -53,6 +53,11 @@ config FB
+ (e.g. an accelerated X server) and that are not frame buffer
+ device-aware may cause unexpected results. If unsure, say N.
+
++config FB_DDC
++ tristate
++ depends on FB && I2C && I2C_ALGOBIT
++ default n
++
+ config FB_CFB_FILLRECT
+ tristate
+ depends on FB
+@@ -183,7 +188,7 @@ config FB_ARMCLCD_SHARP_LQ035Q7DB02_HRTF
+ bool "LogicPD LCD 3.5\" QVGA w/HRTFT IC"
+ help
+ This is an implementation of the Sharp LQ035Q7DB02, a 3.5"
+- color QVGA, HRTFT panel. The LogicPD device includes an
++ color QVGA, HRTFT panel. The LogicPD device includes
+ an integrated HRTFT controller IC.
+ The native resolution is 240x320.
+
+@@ -398,7 +403,7 @@ config FB_ARC
+ is based on the KS-108 lcd controller and is typically a matrix
+ of 2*n chips. This driver was tested with a 128x64 panel. This
+ driver supports it for use with x86 SBCs through a 16 bit GPIO
+- interface (8 bit data, 8 bit control). If you anticpate using
++ interface (8 bit data, 8 bit control). If you anticipate using
+ this driver, say Y or M; otherwise say N. You must specify the
+ GPIO IO address to be used for setting control and data.
+
+@@ -734,6 +739,7 @@ config FB_RIVA
+ depends on FB && PCI
+ select I2C_ALGOBIT if FB_RIVA_I2C
+ select I2C if FB_RIVA_I2C
++ select FB_DDC if FB_RIVA_I2C
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+@@ -764,7 +770,7 @@ config FB_RIVA_DEBUG
+ default n
+ help
+ Say Y here if you want the Riva driver to output all sorts
+- of debugging informations to provide to the maintainer when
++ of debugging information to provide to the maintainer when
+ something goes wrong.
+
+ config FB_RIVA_BACKLIGHT
+@@ -822,33 +828,52 @@ config FB_I810_I2C
+ depends on FB_I810 && FB_I810_GTF
+ select I2C
+ select I2C_ALGOBIT
++ select FB_DDC
+ help
+
+ config FB_INTEL
+- tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
++ tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)"
+ depends on FB && EXPERIMENTAL && PCI && X86
+ select AGP
+ select AGP_INTEL
++ select I2C_ALGOBIT if FB_INTEL_I2C
++ select I2C if FB_INTEL_I2C
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This driver supports the on-board graphics built in to the Intel
+- 830M/845G/852GM/855GM/865G chipsets.
++ 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets.
+ Say Y if you have and plan to use such a board.
+
+- To compile this driver as a module, choose M here: the
++ If you say Y here and want DDC/I2C support you must first say Y to
++ "I2C support" and "I2C bit-banging support" in the character devices
++ section.
++
++ If you say M here then "I2C support" and "I2C bit-banging support"
++ can be build either as modules or built-in.
++
++ To compile this driver as a module, choose M here: the
+ module will be called intelfb.
+
++ For more information, please read <file:Documentation/fb/intelfb.txt>
++
+ config FB_INTEL_DEBUG
+- bool "Intel driver Debug Messages"
++ bool "Intel driver Debug Messages"
+ depends on FB_INTEL
+ ---help---
+ Say Y here if you want the Intel driver to output all sorts
+- of debugging informations to provide to the maintainer when
++ of debugging information to provide to the maintainer when
+ something goes wrong.
+
++config FB_INTEL_I2C
++ bool "DDC/I2C for Intel framebuffer support"
++ depends on FB_INTEL
++ default y
++ help
++ Say Y here if you want DDC/I2C support for your on-board Intel graphics.
++
+ config FB_MATROX
+ tristate "Matrox acceleration"
+ depends on FB && PCI
+@@ -994,6 +1019,7 @@ config FB_RADEON
+ depends on FB && PCI
+ select I2C_ALGOBIT if FB_RADEON_I2C
+ select I2C if FB_RADEON_I2C
++ select FB_DDC if FB_RADEON_I2C
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+@@ -1035,7 +1061,7 @@ config FB_RADEON_DEBUG
+ default n
+ help
+ Say Y here if you want the Radeon driver to output all sorts
+- of debugging informations to provide to the maintainer when
++ of debugging information to provide to the maintainer when
+ something goes wrong.
+
+ config FB_ATY128
+@@ -1122,6 +1148,7 @@ config FB_SAVAGE
+ depends on FB && PCI && EXPERIMENTAL
+ select I2C_ALGOBIT if FB_SAVAGE_I2C
+ select I2C if FB_SAVAGE_I2C
++ select FB_DDC if FB_SAVAGE_I2C
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+@@ -1601,7 +1628,8 @@ config FB_VIRTUAL
+ kernel option `video=vfb:'.
+
+ To compile this driver as a module, choose M here: the
+- module will be called vfb.
++ module will be called vfb. In order to load it, you must use
++ the vfb_enable=1 option.
+
+ If unsure, say N.
+ if VT
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 481c6c9..a6980e9 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfil
+ obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
+ obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+ obj-$(CONFIG_FB_MACMODES) += macmodes.o
++obj-$(CONFIG_FB_DDC) += fb_ddc.o
+
+ # Hardware specific drivers go first
+ obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
+diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
+index afd146f..397005e 100644
+--- a/drivers/video/S3triofb.c
++++ b/drivers/video/S3triofb.c
+@@ -349,30 +349,30 @@ static void __init s3triofb_of_init(stru
+ s3trio_name[sizeof(s3trio_name)-1] = '\0';
+ strcpy(fb_fix.id, s3trio_name);
+
+- if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
++ if((pp = get_property(dp, "vendor-id", &len)) != NULL
+ && *pp!=PCI_VENDOR_ID_S3) {
+ printk("%s: can't find S3 Trio board\n", dp->full_name);
+ return;
+ }
+
+- if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
++ if((pp = get_property(dp, "device-id", &len)) != NULL
+ && *pp!=PCI_DEVICE_ID_S3_TRIO) {
+ printk("%s: can't find S3 Trio board\n", dp->full_name);
+ return;
+ }
+
+- if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
++ if ((pp = get_property(dp, "depth", &len)) != NULL
+ && len == sizeof(int) && *pp != 8) {
+ printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+ return;
+ }
+- if ((pp = (int *)get_property(dp, "width", &len)) != NULL
++ if ((pp = get_property(dp, "width", &len)) != NULL
+ && len == sizeof(int))
+ fb_var.xres = fb_var.xres_virtual = *pp;
+- if ((pp = (int *)get_property(dp, "height", &len)) != NULL
++ if ((pp = get_property(dp, "height", &len)) != NULL
+ && len == sizeof(int))
+ fb_var.yres = fb_var.yres_virtual = *pp;
+- if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
++ if ((pp = get_property(dp, "linebytes", &len)) != NULL
+ && len == sizeof(int))
+ fb_fix.line_length = *pp;
+ else
+diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
+index f1ba54f..a4e3fca 100644
+--- a/drivers/video/amifb.c
++++ b/drivers/video/amifb.c
+@@ -1144,7 +1144,7 @@ static void amifb_deinit(void);
+ */
+
+ static int flash_cursor(void);
+-static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
++static irqreturn_t amifb_interrupt(int irq, void *dev_id);
+ static u_long chipalloc(u_long size);
+ static void chipfree(void);
+
+@@ -2492,7 +2492,7 @@ static int flash_cursor(void)
+ * VBlank Display Interrupt
+ */
+
+-static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t amifb_interrupt(int irq, void *dev_id)
+ {
+ if (do_vmode_pan || do_vmode_full)
+ ami_update_display();
+diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
+index 70dd811..ab34b96 100644
+--- a/drivers/video/arcfb.c
++++ b/drivers/video/arcfb.c
+@@ -218,8 +218,7 @@ static int arcfb_pan_display(struct fb_v
+ return -EINVAL;
+ }
+
+-static irqreturn_t arcfb_interrupt(int vec, void *dev_instance,
+- struct pt_regs *regs)
++static irqreturn_t arcfb_interrupt(int vec, void *dev_instance)
+ {
+ struct fb_info *info = dev_instance;
+ unsigned char ctl2status;
+diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
+index 5831893..02c41a6 100644
+--- a/drivers/video/atafb.c
++++ b/drivers/video/atafb.c
+@@ -1521,7 +1521,7 @@ static void falcon_set_par( struct atafb
+ }
+
+
+-static irqreturn_t falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
++static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
+ {
+ struct falcon_hw *hw = &f_new_mode;
+
+diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
+index 55fb8b0..b04f49f 100644
+--- a/drivers/video/aty/atyfb.h
++++ b/drivers/video/aty/atyfb.h
+@@ -355,5 +355,9 @@ static inline void wait_for_idle(struct
+
+ extern void aty_reset_engine(const struct atyfb_par *par);
+ extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
+-extern void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par);
+ extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
++
++void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
++void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
++void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
++
+diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
+index 19a71f0..b77b309 100644
+--- a/drivers/video/aty/atyfb_base.c
++++ b/drivers/video/aty/atyfb_base.c
+@@ -240,9 +240,6 @@ static int atyfb_setcolreg(u_int regno,
+ static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+ static int atyfb_blank(int blank, struct fb_info *info);
+ static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
+-extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+-extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+-extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
+ #ifdef __sparc__
+ static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+ #endif
+@@ -1535,7 +1532,7 @@ static int atyfb_open(struct fb_info *in
+ return (0);
+ }
+
+-static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t aty_irq(int irq, void *dev_id)
+ {
+ struct atyfb_par *par = dev_id;
+ int handled = 0;
+@@ -3863,6 +3860,7 @@ static int __devinit atyfb_setup(char *o
+
+ static int __devinit atyfb_init(void)
+ {
++ int err1 = 1, err2 = 1;
+ #ifndef MODULE
+ char *option = NULL;
+
+@@ -3872,12 +3870,13 @@ static int __devinit atyfb_init(void)
+ #endif
+
+ #ifdef CONFIG_PCI
+- pci_register_driver(&atyfb_driver);
++ err1 = pci_register_driver(&atyfb_driver);
+ #endif
+ #ifdef CONFIG_ATARI
+- atyfb_atari_probe();
++ err2 = atyfb_atari_probe();
+ #endif
+- return 0;
++
++ return (err1 && err2) ? -ENODEV : 0;
+ }
+
+ static void __exit atyfb_exit(void)
+diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
+index e705693..5080816 100644
+--- a/drivers/video/aty/mach64_ct.c
++++ b/drivers/video/aty/mach64_ct.c
+@@ -27,7 +27,7 @@ u8 aty_ld_pll_ct(int offset, const struc
+ return res;
+ }
+
+-void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
++static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
+ {
+ /* write addr byte */
+ aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
+diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
+index 8e3400d..0ed577e 100644
+--- a/drivers/video/aty/radeon_base.c
++++ b/drivers/video/aty/radeon_base.c
+@@ -413,11 +413,11 @@ static int __devinit radeon_find_mem_vb
+ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
+ {
+ struct device_node *dp = rinfo->of_node;
+- u32 *val;
++ const u32 *val;
+
+ if (dp == NULL)
+ return -ENODEV;
+- val = (u32 *) get_property(dp, "ATY,RefCLK", NULL);
++ val = get_property(dp, "ATY,RefCLK", NULL);
+ if (!val || !*val) {
+ printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
+ return -EINVAL;
+@@ -425,11 +425,11 @@ static int __devinit radeon_read_xtal_OF
+
+ rinfo->pll.ref_clk = (*val) / 10;
+
+- val = (u32 *) get_property(dp, "ATY,SCLK", NULL);
++ val = get_property(dp, "ATY,SCLK", NULL);
+ if (val && *val)
+ rinfo->pll.sclk = (*val) / 10;
+
+- val = (u32 *) get_property(dp, "ATY,MCLK", NULL);
++ val = get_property(dp, "ATY,MCLK", NULL);
+ if (val && *val)
+ rinfo->pll.mclk = (*val) / 10;
+
+diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
+index 9aaca58..6767545 100644
+--- a/drivers/video/aty/radeon_i2c.c
++++ b/drivers/video/aty/radeon_i2c.c
+@@ -16,8 +16,6 @@
+ #include "radeonfb.h"
+ #include "../edid.h"
+
+-#define RADEON_DDC 0x50
+-
+ static void radeon_gpio_setscl(void* data, int state)
+ {
+ struct radeon_i2c_chan *chan = data;
+@@ -138,108 +136,10 @@ void radeon_delete_i2c_busses(struct rad
+ rinfo->i2c[3].rinfo = NULL;
+ }
+
+-
+-static u8 *radeon_do_probe_i2c_edid(struct radeon_i2c_chan *chan)
+-{
+- u8 start = 0x0;
+- struct i2c_msg msgs[] = {
+- {
+- .addr = RADEON_DDC,
+- .len = 1,
+- .buf = &start,
+- }, {
+- .addr = RADEON_DDC,
+- .flags = I2C_M_RD,
+- .len = EDID_LENGTH,
+- },
+- };
+- u8 *buf;
+-
+- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+- if (!buf) {
+- dev_warn(&chan->rinfo->pdev->dev, "Out of memory!\n");
+- return NULL;
+- }
+- msgs[1].buf = buf;
+-
+- if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
+- return buf;
+- dev_dbg(&chan->rinfo->pdev->dev, "Unable to read EDID block.\n");
+- kfree(buf);
+- return NULL;
+-}
+-
+-
+-int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid)
++int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
++ u8 **out_edid)
+ {
+- u32 reg = rinfo->i2c[conn-1].ddc_reg;
+- u8 *edid = NULL;
+- int i, j;
+-
+- OUTREG(reg, INREG(reg) &
+- ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
+-
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
+- (void)INREG(reg);
+-
+- for (i = 0; i < 3; i++) {
+- /* For some old monitors we need the
+- * following process to initialize/stop DDC
+- */
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
+- (void)INREG(reg);
+- msleep(13);
+-
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
+- (void)INREG(reg);
+- for (j = 0; j < 5; j++) {
+- msleep(10);
+- if (INREG(reg) & VGA_DDC_CLK_INPUT)
+- break;
+- }
+- if (j == 5)
+- continue;
+-
+- OUTREG(reg, INREG(reg) | VGA_DDC_DATA_OUT_EN);
+- (void)INREG(reg);
+- msleep(15);
+- OUTREG(reg, INREG(reg) | VGA_DDC_CLK_OUT_EN);
+- (void)INREG(reg);
+- msleep(15);
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
+- (void)INREG(reg);
+- msleep(15);
+-
+- /* Do the real work */
+- edid = radeon_do_probe_i2c_edid(&rinfo->i2c[conn-1]);
+-
+- OUTREG(reg, INREG(reg) |
+- (VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
+- (void)INREG(reg);
+- msleep(15);
+-
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
+- (void)INREG(reg);
+- for (j = 0; j < 10; j++) {
+- msleep(10);
+- if (INREG(reg) & VGA_DDC_CLK_INPUT)
+- break;
+- }
+-
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
+- (void)INREG(reg);
+- msleep(15);
+- OUTREG(reg, INREG(reg) |
+- (VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
+- (void)INREG(reg);
+- if (edid)
+- break;
+- }
+- /* Release the DDC lines when done or the Apple Cinema HD display
+- * will switch off
+- */
+- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN | VGA_DDC_DATA_OUT_EN));
+- (void)INREG(reg);
++ u8 *edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
+
+ if (out_edid)
+ *out_edid = edid;
+diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
+index 98c05bc..ea531a6 100644
+--- a/drivers/video/aty/radeon_monitor.c
++++ b/drivers/video/aty/radeon_monitor.c
+@@ -64,13 +64,13 @@ static int __devinit radeon_parse_montyp
+ {
+ static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
+ "EDID1", "EDID2", NULL };
+- u8 *pedid = NULL;
+- u8 *pmt = NULL;
++ const u8 *pedid = NULL;
++ const u8 *pmt = NULL;
+ u8 *tmp;
+ int i, mt = MT_NONE;
+
+ RTRACE("analyzing OF properties...\n");
+- pmt = (u8 *)get_property(dp, "display-type", NULL);
++ pmt = get_property(dp, "display-type", NULL);
+ if (!pmt)
+ return MT_NONE;
+ RTRACE("display-type: %s\n", pmt);
+@@ -89,7 +89,7 @@ static int __devinit radeon_parse_montyp
+ }
+
+ for (i = 0; propnames[i] != NULL; ++i) {
+- pedid = (u8 *)get_property(dp, propnames[i], NULL);
++ pedid = get_property(dp, propnames[i], NULL);
+ if (pedid != NULL)
+ break;
+ }
+@@ -124,14 +124,14 @@ static int __devinit radeon_probe_OF_hea
+ return MT_NONE;
+
+ if (rinfo->has_CRTC2) {
+- char *pname;
++ const char *pname;
+ int len, second = 0;
+
+ dp = dp->child;
+ do {
+ if (!dp)
+ return MT_NONE;
+- pname = (char *)get_property(dp, "name", NULL);
++ pname = get_property(dp, "name", NULL);
+ if (!pname)
+ return MT_NONE;
+ len = strlen(pname);
+diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
+index f31e606..9a2b0d6 100644
+--- a/drivers/video/aty/radeon_pm.c
++++ b/drivers/video/aty/radeon_pm.c
+@@ -86,6 +86,9 @@ static struct radeon_device_id radeon_wo
+ BUGFIX("Samsung P35",
+ PCI_VENDOR_ID_SAMSUNG, 0xc00c,
+ radeon_pm_off, radeon_reinitialize_M10),
++ BUGFIX("Acer Aspire 2010",
++ PCI_VENDOR_ID_AI, 0x0061,
++ radeon_pm_off, radeon_reinitialize_M10),
+ { .ident = NULL }
+ };
+
+@@ -1268,7 +1271,7 @@ static void radeon_pm_full_reset_sdram(s
+ 0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
+ 0x31320032 };
+
+- u32 *mrtable = default_mrtable;
++ const u32 *mrtable = default_mrtable;
+ int i, mrtable_size = ARRAY_SIZE(default_mrtable);
+
+ mdelay(30);
+@@ -1287,7 +1290,7 @@ static void radeon_pm_full_reset_sdram(s
+ if (rinfo->of_node != NULL) {
+ int size;
+
+- mrtable = (u32 *)get_property(rinfo->of_node, "ATY,MRT", &size);
++ mrtable = get_property(rinfo->of_node, "ATY,MRT", &size);
+ if (mrtable)
+ mrtable_size = size >> 2;
+ else
+@@ -2621,25 +2624,28 @@ static int radeon_restore_pci_cfg(struct
+ }
+
+
+-int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
++int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+ {
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct radeonfb_info *rinfo = info->par;
+ int i;
+
+- if (state.event == pdev->dev.power.power_state.event)
++ if (mesg.event == pdev->dev.power.power_state.event)
+ return 0;
+
+- printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
+- pci_name(pdev), state.event);
++ printk(KERN_DEBUG "radeonfb (%s): suspending for event: %d...\n",
++ pci_name(pdev), mesg.event);
+
+ /* For suspend-to-disk, we cheat here. We don't suspend anything and
+ * let fbcon continue drawing until we are all set. That shouldn't
+ * really cause any problem at this point, provided that the wakeup
+ * code knows that any state in memory may not match the HW
+ */
+- if (state.event == PM_EVENT_FREEZE)
++ switch (mesg.event) {
++ case PM_EVENT_FREEZE: /* about to take snapshot */
++ case PM_EVENT_PRETHAW: /* before restoring snapshot */
+ goto done;
++ }
+
+ acquire_console_sem();
+
+@@ -2706,7 +2712,7 @@ int radeonfb_pci_suspend(struct pci_dev
+ release_console_sem();
+
+ done:
+- pdev->dev.power.power_state = state;
++ pdev->dev.power.power_state = mesg;
+
+ return 0;
+ }
+diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
+index f25d5d6..ef5c16f 100644
+--- a/drivers/video/au1100fb.c
++++ b/drivers/video/au1100fb.c
+@@ -8,6 +8,7 @@
+ * <c.pellegrin at exadron.com>
+ *
+ * PM support added by Rodolfo Giometti <giometti at linux.it>
++ * Cursor enable/disable by Rodolfo Giometti <giometti at linux.it>
+ *
+ * Copyright 2002 MontaVista Software
+ * Author: MontaVista Software, Inc.
+@@ -110,6 +111,10 @@ static struct fb_var_screeninfo au1100fb
+
+ static struct au1100fb_drv_info drv_info;
+
++static int nocursor = 0;
++module_param(nocursor, int, 0644);
++MODULE_PARM_DESC(nocursor, "cursor enable/disable");
++
+ /*
+ * Set hardware with var settings. This will enable the controller with a specific
+ * mode, normally validated with the fb_check_var method
+@@ -422,6 +427,17 @@ int au1100fb_fb_mmap(struct fb_info *fbi
+ return 0;
+ }
+
++/* fb_cursor
++ * Used to disable cursor drawing...
++ */
++int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
++{
++ if (nocursor)
++ return 0;
++ else
++ return -EINVAL; /* just to force soft_cursor() call */
++}
++
+ static struct fb_ops au1100fb_ops =
+ {
+ .owner = THIS_MODULE,
+@@ -433,6 +449,7 @@ static struct fb_ops au1100fb_ops =
+ .fb_imageblit = cfb_imageblit,
+ .fb_rotate = au1100fb_fb_rotate,
+ .fb_mmap = au1100fb_fb_mmap,
++ .fb_cursor = au1100fb_fb_cursor,
+ };
+
+
+@@ -677,7 +694,7 @@ int au1100fb_setup(char *options)
+ if (options) {
+ while ((this_opt = strsep(&options,",")) != NULL) {
+ /* Panel option */
+- if (!strncmp(this_opt, "panel:", 6)) {
++ if (!strncmp(this_opt, "panel:", 6)) {
+ int i;
+ this_opt += 6;
+ for (i = 0; i < num_panels; i++) {
+@@ -685,13 +702,18 @@ int au1100fb_setup(char *options)
+ known_lcd_panels[i].name,
+ strlen(this_opt))) {
+ panel_idx = i;
+- break;
++ break;
++ }
+ }
+- }
+ if (i >= num_panels) {
+ print_warn("Panel %s not supported!", this_opt);
+ }
+ }
++ if (!strncmp(this_opt, "nocursor", 8)) {
++ this_opt += 8;
++ nocursor = 1;
++ print_info("Cursor disabled");
++ }
+ /* Mode option (only option that start with digit) */
+ else if (isdigit(this_opt[0])) {
+ mode = kmalloc(strlen(this_opt) + 1, GFP_KERNEL);
+@@ -700,7 +722,7 @@ int au1100fb_setup(char *options)
+ /* Unsupported option */
+ else {
+ print_warn("Unsupported option \"%s\"", this_opt);
+- }
++ }
+ }
+ }
+
+diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
+index c6a5f0c..dbf4ec3 100644
+--- a/drivers/video/au1200fb.c
++++ b/drivers/video/au1200fb.c
+@@ -1545,7 +1545,7 @@ static struct fb_ops au1200fb_fb_ops = {
+
+ /*-------------------------------------------------------------------------*/
+
+-static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
++static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
+ {
+ /* Nothing to do for now, just clear any pending interrupt */
+ lcd->intstatus = lcd->intstatus;
+diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
+index 2ebbfd9..d07ecb5 100644
+--- a/drivers/video/backlight/corgi_bl.c
++++ b/drivers/video/backlight/corgi_bl.c
+@@ -111,7 +111,7 @@ static struct backlight_properties corgi
+ .update_status = corgibl_set_intensity,
+ };
+
+-static int __init corgibl_probe(struct platform_device *pdev)
++static int corgibl_probe(struct platform_device *pdev)
+ {
+ struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
+
+@@ -166,4 +166,4 @@ module_exit(corgibl_exit);
+
+ MODULE_AUTHOR("Richard Purdie <rpurdie at rpsys.net>");
+ MODULE_DESCRIPTION("Corgi Backlight Driver");
+-MODULE_LICENSE("GPLv2");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
+index ffc72ae..e399321 100644
+--- a/drivers/video/backlight/hp680_bl.c
++++ b/drivers/video/backlight/hp680_bl.c
+@@ -19,8 +19,8 @@
+ #include <linux/backlight.h>
+
+ #include <asm/cpu/dac.h>
+-#include <asm/hp6xx/hp6xx.h>
+-#include <asm/hd64461/hd64461.h>
++#include <asm/hp6xx.h>
++#include <asm/hd64461.h>
+
+ #define HP680_MAX_INTENSITY 255
+ #define HP680_DEFAULT_INTENSITY 10
+@@ -163,6 +163,6 @@ static void __exit hp680bl_exit(void)
+ module_init(hp680bl_init);
+ module_exit(hp680bl_exit);
+
+-MODULE_AUTHOR("Andriy Skulysh <askulysh at image.kiev.ua>");
++MODULE_AUTHOR("Andriy Skulysh <askulysh at gmail.com>");
+ MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
+index caf1eca..628571c 100644
+--- a/drivers/video/backlight/locomolcd.c
++++ b/drivers/video/backlight/locomolcd.c
+@@ -33,19 +33,19 @@ static unsigned long locomolcd_flags;
+
+ static void locomolcd_on(int comadj)
+ {
+- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
++ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1);
+ mdelay(2);
+
+- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
++ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1);
+ mdelay(2);
+
+ locomo_m62332_senddata(locomolcd_dev, comadj, 0);
+ mdelay(5);
+
+- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
++ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1);
+ mdelay(10);
+
+ /* TFTCRST | CPSOUT=0 | CPSEN */
+@@ -58,8 +58,8 @@ static void locomolcd_on(int comadj)
+ locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
+ mdelay(10);
+
+- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
++ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1);
+ }
+
+ static void locomolcd_off(int comadj)
+@@ -68,16 +68,16 @@ static void locomolcd_off(int comadj)
+ locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
+ mdelay(1);
+
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ mdelay(110);
+
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ mdelay(700);
+
+ /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
+ locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
++ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ }
+
+ void locomolcd_power(int on)
+@@ -167,14 +167,14 @@ static int locomolcd_resume(struct locom
+ #define locomolcd_resume NULL
+ #endif
+
+-static int locomolcd_probe(struct locomo_dev *dev)
++static int locomolcd_probe(struct locomo_dev *ldev)
+ {
+ unsigned long flags;
+
+ local_irq_save(flags);
+- locomolcd_dev = dev;
++ locomolcd_dev = ldev;
+
+- locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0);
++ locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
+
+ /* the poodle_lcd_power function is called for the first time
+ * from fs_initcall, which is before locomo is activated.
+diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
+index 4444bef..aa3935d 100644
+--- a/drivers/video/console/Kconfig
++++ b/drivers/video/console/Kconfig
+@@ -6,7 +6,7 @@ menu "Console display driver support"
+
+ config VGA_CONSOLE
+ bool "VGA text console" if EMBEDDED || !X86
+- depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE
++ depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH
+ default y
+ help
+ Saying Y here will allow you to use Linux in text mode through a
+diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
+index 390439b..302174b 100644
+--- a/drivers/video/console/fbcon.c
++++ b/drivers/video/console/fbcon.c
+@@ -133,6 +133,7 @@ static int info_idx = -1;
+
+ /* console rotation */
+ static int rotate;
++static int fbcon_has_sysfs;
+
+ static const struct consw fb_con;
+
+@@ -203,7 +204,7 @@ static struct class_device *fbcon_class_
+ */
+ static int vbl_detected;
+
+-static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t fb_vbl_detect(int irq, void *dummy)
+ {
+ vbl_detected++;
+ return IRQ_HANDLED;
+@@ -396,9 +397,8 @@ static void fb_flashcursor(void *private
+ vc = vc_cons[ops->currcon].d;
+
+ if (!vc || !CON_IS_VISIBLE(vc) ||
+- fbcon_is_inactive(vc, info) ||
+ registered_fb[con2fb_map[vc->vc_num]] != info ||
+- vc_cons[ops->currcon].d->vc_deccm != 1) {
++ vc->vc_deccm != 1) {
+ release_console_sem();
+ return;
+ }
+@@ -414,7 +414,7 @@ static void fb_flashcursor(void *private
+
+ #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)
++static irqreturn_t fb_vbl_handler(int irq, void *dev_id)
+ {
+ struct fb_info *info = dev_id;
+
+@@ -2166,7 +2166,12 @@ static int fbcon_switch(struct vc_data *
+ fbcon_del_cursor_timer(old_info);
+ }
+
+- fbcon_add_cursor_timer(info);
++ if (fbcon_is_inactive(vc, info) ||
++ ops->blank_state != FB_BLANK_UNBLANK)
++ fbcon_del_cursor_timer(info);
++ else
++ fbcon_add_cursor_timer(info);
++
+ set_blitting_type(vc, info);
+ ops->cursor_reset = 1;
+
+@@ -2276,10 +2281,11 @@ static int fbcon_blank(struct vc_data *v
+ update_screen(vc);
+ }
+
+- if (!blank)
+- fbcon_add_cursor_timer(info);
+- else
++ if (fbcon_is_inactive(vc, info) ||
++ ops->blank_state != FB_BLANK_UNBLANK)
+ fbcon_del_cursor_timer(info);
++ else
++ fbcon_add_cursor_timer(info);
+
+ return 0;
+ }
+@@ -3161,11 +3167,26 @@ static struct class_device_attribute cla
+
+ static int fbcon_init_class_device(void)
+ {
+- int i;
++ int i, error = 0;
++
++ fbcon_has_sysfs = 1;
++
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
++ error = class_device_create_file(fbcon_class_device,
++ &class_device_attrs[i]);
++
++ if (error)
++ break;
++ }
++
++ if (error) {
++ while (--i >= 0)
++ class_device_remove_file(fbcon_class_device,
++ &class_device_attrs[i]);
++
++ fbcon_has_sysfs = 0;
++ }
+
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_create_file(fbcon_class_device,
+- &class_device_attrs[i]);
+ return 0;
+ }
+
+@@ -3197,11 +3218,11 @@ static void fbcon_exit(void)
+ return;
+
+ #ifdef CONFIG_ATARI
+- free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
++ free_irq(IRQ_AUTO_4, fb_vbl_handler);
+ #endif
+ #ifdef CONFIG_MAC
+ if (MACH_IS_MAC && vbl_detected)
+- free_irq(IRQ_MAC_VBL, fbcon_vbl_handler);
++ free_irq(IRQ_MAC_VBL, fb_vbl_handler);
+ #endif
+
+ kfree((void *)softback_buf);
+@@ -3225,7 +3246,10 @@ static void fbcon_exit(void)
+ module_put(info->fbops->owner);
+
+ if (info->fbcon_par) {
++ struct fbcon_ops *ops = info->fbcon_par;
++
+ fbcon_del_cursor_timer(info);
++ kfree(ops->cursor_src);
+ kfree(info->fbcon_par);
+ info->fbcon_par = NULL;
+ }
+@@ -3271,9 +3295,13 @@ static void __exit fbcon_deinit_class_de
+ {
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_remove_file(fbcon_class_device,
+- &class_device_attrs[i]);
++ if (fbcon_has_sysfs) {
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
++ class_device_remove_file(fbcon_class_device,
++ &class_device_attrs[i]);
++
++ fbcon_has_sysfs = 0;
++ }
+ }
+
+ static void __exit fb_console_exit(void)
+diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
+index f244ad0..b9386d1 100644
+--- a/drivers/video/console/fbcon.h
++++ b/drivers/video/console/fbcon.h
+@@ -80,6 +80,8 @@ struct fbcon_ops {
+ char *cursor_data;
+ u8 *fontbuffer;
+ u8 *fontdata;
++ u8 *cursor_src;
++ u32 cursor_size;
+ u32 fd_size;
+ };
+ /*
+diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
+index 4481c80..825e6d6 100644
+--- a/drivers/video/console/fbcon_ccw.c
++++ b/drivers/video/console/fbcon_ccw.c
+@@ -391,7 +391,7 @@ static void ccw_cursor(struct vc_data *v
+ ops->cursor_reset = 0;
+ }
+
+-int ccw_update_start(struct fb_info *info)
++static int ccw_update_start(struct fb_info *info)
+ {
+ struct fbcon_ops *ops = info->fbcon_par;
+ u32 yoffset;
+diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
+index 7f92c06..c637e63 100644
+--- a/drivers/video/console/fbcon_cw.c
++++ b/drivers/video/console/fbcon_cw.c
+@@ -375,7 +375,7 @@ static void cw_cursor(struct vc_data *vc
+ ops->cursor_reset = 0;
+ }
+
+-int cw_update_start(struct fb_info *info)
++static int cw_update_start(struct fb_info *info)
+ {
+ struct fbcon_ops *ops = info->fbcon_par;
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
+diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
+index ab91005..1473506 100644
+--- a/drivers/video/console/fbcon_ud.c
++++ b/drivers/video/console/fbcon_ud.c
+@@ -415,7 +415,7 @@ static void ud_cursor(struct vc_data *vc
+ ops->cursor_reset = 0;
+ }
+
+-int ud_update_start(struct fb_info *info)
++static int ud_update_start(struct fb_info *info)
+ {
+ struct fbcon_ops *ops = info->fbcon_par;
+ int xoffset, yoffset;
+diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
+index 557c563..7d07d83 100644
+--- a/drivers/video/console/softcursor.c
++++ b/drivers/video/console/softcursor.c
+@@ -20,11 +20,12 @@
+
+ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
+ {
++ struct fbcon_ops *ops = info->fbcon_par;
+ unsigned int scan_align = info->pixmap.scan_align - 1;
+ unsigned int buf_align = info->pixmap.buf_align - 1;
+ unsigned int i, size, dsize, s_pitch, d_pitch;
+ struct fb_image *image;
+- u8 *dst, *src;
++ u8 *dst;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return 0;
+@@ -32,11 +33,19 @@ int soft_cursor(struct fb_info *info, st
+ s_pitch = (cursor->image.width + 7) >> 3;
+ dsize = s_pitch * cursor->image.height;
+
+- src = kmalloc(dsize + sizeof(struct fb_image), GFP_ATOMIC);
+- if (!src)
+- return -ENOMEM;
++ if (dsize + sizeof(struct fb_image) != ops->cursor_size) {
++ if (ops->cursor_src != NULL)
++ kfree(ops->cursor_src);
++ ops->cursor_size = dsize + sizeof(struct fb_image);
+
+- image = (struct fb_image *) (src + dsize);
++ ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC);
++ if (!ops->cursor_src) {
++ ops->cursor_size = 0;
++ return -ENOMEM;
++ }
++ }
++
++ image = (struct fb_image *) (ops->cursor_src + dsize);
+ *image = cursor->image;
+ d_pitch = (s_pitch + scan_align) & ~scan_align;
+
+@@ -48,21 +57,23 @@ int soft_cursor(struct fb_info *info, st
+ switch (cursor->rop) {
+ case ROP_XOR:
+ for (i = 0; i < dsize; i++)
+- src[i] = image->data[i] ^ cursor->mask[i];
++ ops->cursor_src[i] = image->data[i] ^
++ cursor->mask[i];
+ break;
+ case ROP_COPY:
+ default:
+ for (i = 0; i < dsize; i++)
+- src[i] = image->data[i] & cursor->mask[i];
++ ops->cursor_src[i] = image->data[i] &
++ cursor->mask[i];
+ break;
+ }
+ } else
+- memcpy(src, image->data, dsize);
++ memcpy(ops->cursor_src, image->data, dsize);
+
+- fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
++ fb_pad_aligned_buffer(dst, d_pitch, ops->cursor_src, s_pitch,
++ image->height);
+ image->data = dst;
+ info->fbops->fb_imageblit(info, image);
+- kfree(src);
+ return 0;
+ }
+
+diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
+index 8cc6c0e..04c6d92 100644
+--- a/drivers/video/controlfb.c
++++ b/drivers/video/controlfb.c
+@@ -415,13 +415,15 @@ static int __init init_control(struct fb
+ full = p->total_vram == 0x400000;
+
+ /* Try to pick a video mode out of NVRAM if we have one. */
++#ifdef CONFIG_NVRAM
+ if (default_cmode == CMODE_NVRAM){
+ cmode = nvram_read_byte(NV_CMODE);
+ if(cmode < CMODE_8 || cmode > CMODE_32)
+ cmode = CMODE_8;
+ } else
++#endif
+ cmode=default_cmode;
+-
++#ifdef CONFIG_NVRAM
+ if (default_vmode == VMODE_NVRAM) {
+ vmode = nvram_read_byte(NV_VMODE);
+ if (vmode < 1 || vmode > VMODE_MAX ||
+@@ -432,7 +434,9 @@ static int __init init_control(struct fb
+ if (control_mac_modes[vmode - 1].m[full] < cmode)
+ vmode = VMODE_640_480_60;
+ }
+- } else {
++ } else
++#endif
++ {
+ vmode=default_vmode;
+ if (control_mac_modes[vmode - 1].m[full] < cmode) {
+ if (cmode > CMODE_8)
+diff --git a/drivers/video/fb_ddc.c b/drivers/video/fb_ddc.c
+new file mode 100644
+index 0000000..3aa6ebf
+--- /dev/null
++++ b/drivers/video/fb_ddc.c
+@@ -0,0 +1,116 @@
++/*
++ * driver/vide/fb_ddc.c - DDC/EDID read support.
++ *
++ * Copyright (C) 2006 Dennis Munsie <dmunsie at cecropia.com>
++ *
++ * 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/delay.h>
++#include <linux/device.h>
++#include <linux/fb.h>
++#include <linux/i2c-algo-bit.h>
++
++#include "edid.h"
++
++#define DDC_ADDR 0x50
++
++static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
++{
++ unsigned char start = 0x0;
++ struct i2c_msg msgs[] = {
++ {
++ .addr = DDC_ADDR,
++ .len = 1,
++ .buf = &start,
++ }, {
++ .addr = DDC_ADDR,
++ .flags = I2C_M_RD,
++ .len = EDID_LENGTH,
++ }
++ };
++ unsigned char *buf;
++
++ buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
++ if (!buf) {
++ dev_warn(&adapter->dev, "unable to allocate memory for EDID "
++ "block.\n");
++ return NULL;
++ }
++ msgs[1].buf = buf;
++
++ if (i2c_transfer(adapter, msgs, 2) == 2)
++ return buf;
++
++ dev_warn(&adapter->dev, "unable to read EDID block.\n");
++ kfree(buf);
++ return NULL;
++}
++
++unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
++{
++ struct i2c_algo_bit_data *algo_data = adapter->algo_data;
++ unsigned char *edid = NULL;
++ int i, j;
++
++ algo_data->setscl(algo_data->data, 1);
++ algo_data->setscl(algo_data->data, 0);
++
++ for (i = 0; i < 3; i++) {
++ /* For some old monitors we need the
++ * following process to initialize/stop DDC
++ */
++ algo_data->setsda(algo_data->data, 0);
++ msleep(13);
++
++ algo_data->setscl(algo_data->data, 1);
++ for (j = 0; j < 5; j++) {
++ msleep(10);
++ if (algo_data->getscl(algo_data->data))
++ break;
++ }
++ if (j == 5)
++ continue;
++
++ algo_data->setsda(algo_data->data, 0);
++ msleep(15);
++ algo_data->setscl(algo_data->data, 0);
++ msleep(15);
++ algo_data->setsda(algo_data->data, 1);
++ msleep(15);
++
++ /* Do the real work */
++ edid = fb_do_probe_ddc_edid(adapter);
++ algo_data->setsda(algo_data->data, 0);
++ algo_data->setscl(algo_data->data, 0);
++ msleep(15);
++
++ algo_data->setscl(algo_data->data, 1);
++ for (j = 0; j < 10; j++) {
++ msleep(10);
++ if (algo_data->getscl(algo_data->data))
++ break;
++ }
++
++ algo_data->setsda(algo_data->data, 1);
++ msleep(15);
++ algo_data->setscl(algo_data->data, 0);
++ if (edid)
++ break;
++ }
++ /* Release the DDC lines when done or the Apple Cinema HD display
++ * will switch off
++ */
++ algo_data->setsda(algo_data->data, 0);
++ algo_data->setscl(algo_data->data, 0);
++
++ return edid;
++}
++
++EXPORT_SYMBOL_GPL(fb_ddc_read);
++
++MODULE_AUTHOR("Dennis Munsie <dmunsie at cecropia.com>");
++MODULE_DESCRIPTION("DDC/EDID reading support");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
+index 17961e3..93ffcdd 100644
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -554,7 +554,8 @@ static int fbmem_read_proc(char *buf, ch
+ int clen;
+
+ clen = 0;
+- for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && len < 4000; fi++)
++ for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && clen < 4000;
++ fi++)
+ if (*fi)
+ clen += sprintf(buf + clen, "%d %s\n",
+ (*fi)->node,
+diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
+index 4f78f23..d3a5041 100644
+--- a/drivers/video/fbsysfs.c
++++ b/drivers/video/fbsysfs.c
+@@ -20,6 +20,8 @@
+ #include <linux/console.h>
+ #include <linux/module.h>
+
++#define FB_SYSFS_FLAG_ATTR 1
++
+ /**
+ * framebuffer_alloc - creates a new frame buffer info structure
+ *
+@@ -397,6 +399,12 @@ static ssize_t store_bl_curve(struct cla
+ u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+ unsigned int i;
+
++ /* Some drivers don't use framebuffer_alloc(), but those also
++ * don't have backlights.
++ */
++ if (!fb_info || !fb_info->bl_dev)
++ return -ENODEV;
++
+ if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+ return -EINVAL;
+
+@@ -430,6 +438,12 @@ static ssize_t show_bl_curve(struct clas
+ ssize_t len = 0;
+ unsigned int i;
+
++ /* Some drivers don't use framebuffer_alloc(), but those also
++ * don't have backlights.
++ */
++ if (!fb_info || !fb_info->bl_dev)
++ return -ENODEV;
++
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+ len += snprintf(&buf[len], PAGE_SIZE,
+@@ -471,12 +485,27 @@ static struct class_device_attribute cla
+
+ int fb_init_class_device(struct fb_info *fb_info)
+ {
+- unsigned int i;
++ int i, error = 0;
++
+ class_set_devdata(fb_info->class_device, fb_info);
+
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_create_file(fb_info->class_device,
+- &class_device_attrs[i]);
++ fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;
++
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
++ error = class_device_create_file(fb_info->class_device,
++ &class_device_attrs[i]);
++
++ if (error)
++ break;
++ }
++
++ if (error) {
++ while (--i >= 0)
++ class_device_remove_file(fb_info->class_device,
++ &class_device_attrs[i]);
++ fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
++ }
++
+ return 0;
+ }
+
+@@ -484,9 +513,13 @@ void fb_cleanup_class_device(struct fb_i
+ {
+ unsigned int i;
+
+- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+- class_device_remove_file(fb_info->class_device,
+- &class_device_attrs[i]);
++ if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) {
++ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
++ class_device_remove_file(fb_info->class_device,
++ &class_device_attrs[i]);
++
++ fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
++ }
+ }
+
+ #ifdef CONFIG_FB_BACKLIGHT
+diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
+index 4cc6b45..3dc4942 100644
+--- a/drivers/video/hitfb.c
++++ b/drivers/video/hitfb.c
+@@ -4,7 +4,7 @@
+ * (C) 1999 Mihai Spatar
+ * (C) 2000 YAEGASHI Takeshi
+ * (C) 2003, 2004 Paul Mundt
+- * (C) 2003, 2004 Andriy Skulysh
++ * (C) 2003, 2004, 2006 Andriy Skulysh
+ *
+ * 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
+@@ -20,18 +20,15 @@
+ #include <linux/slab.h>
+ #include <linux/delay.h>
+ #include <linux/init.h>
++#include <linux/platform_device.h>
+ #include <linux/fb.h>
+
+ #include <asm/machvec.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+ #include <asm/io.h>
+-#include <asm/hd64461/hd64461.h>
+-
+-#ifdef MACH_HP600
++#include <asm/hd64461.h>
+ #include <asm/cpu/dac.h>
+-#include <asm/hp6xx/hp6xx.h>
+-#endif
+
+ #define WIDTH 640
+
+@@ -45,7 +42,6 @@ static struct fb_var_screeninfo hitfb_va
+ static struct fb_fix_screeninfo hitfb_fix __initdata = {
+ .id = "Hitachi HD64461",
+ .type = FB_TYPE_PACKED_PIXELS,
+- .ypanstep = 8,
+ .accel = FB_ACCEL_NONE,
+ };
+
+@@ -73,26 +69,14 @@ static inline void hitfb_accel_set_dest(
+ if (truecolor)
+ saddr <<= 1;
+
+- fb_writew(width, HD64461_BBTDWR);
+- fb_writew(height, HD64461_BBTDHR);
++ fb_writew(width-1, HD64461_BBTDWR);
++ fb_writew(height-1, HD64461_BBTDHR);
+
+ fb_writew(saddr & 0xffff, HD64461_BBTDSARL);
+ fb_writew(saddr >> 16, HD64461_BBTDSARH);
+
+ }
+
+-static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy,
+- u16 width, u16 height, u16 color)
+-{
+- hitfb_accel_set_dest(truecolor, dx, dy, width, height);
+-
+- fb_writew(0x00f0, HD64461_BBTROPR);
+- fb_writew(16, HD64461_BBTMDR);
+- fb_writew(color, HD64461_GRSCR);
+-
+- hitfb_accel_start(truecolor);
+-}
+-
+ static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
+ u16 dy, u16 width, u16 height, u16 rop,
+ u32 mask_addr)
+@@ -100,6 +84,8 @@ static inline void hitfb_accel_bitblt(in
+ u32 saddr, daddr;
+ u32 maddr = 0;
+
++ height--;
++ width--;
+ fb_writew(rop, HD64461_BBTROPR);
+ if ((sy < dy) || ((sy == dy) && (sx <= dx))) {
+ saddr = WIDTH * (sy + height) + sx + width;
+@@ -146,6 +132,7 @@ static void hitfb_fillrect(struct fb_inf
+ if (rect->rop != ROP_COPY)
+ cfb_fillrect(p, rect);
+ else {
++ hitfb_accel_wait();
+ fb_writew(0x00f0, HD64461_BBTROPR);
+ fb_writew(16, HD64461_BBTMDR);
+
+@@ -161,16 +148,15 @@ static void hitfb_fillrect(struct fb_inf
+ rect->height);
+ hitfb_accel_start(0);
+ }
+- hitfb_accel_wait();
+ }
+ }
+
+ static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+ {
++ hitfb_accel_wait();
+ hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy,
+ area->dx, area->dy, area->width, area->height,
+ 0x00cc, 0);
+- hitfb_accel_wait();
+ }
+
+ static int hitfb_pan_display(struct fb_var_screeninfo *var,
+@@ -182,7 +168,7 @@ static int hitfb_pan_display(struct fb_v
+ if (xoffset != 0)
+ return -EINVAL;
+
+- fb_writew(yoffset, HD64461_LCDCBAR);
++ fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR);
+
+ return 0;
+ }
+@@ -192,12 +178,6 @@ int hitfb_blank(int blank_mode, struct f
+ unsigned short v;
+
+ if (blank_mode) {
+-#ifdef MACH_HP600
+- sh_dac_disable(DAC_LCD_BRIGHTNESS);
+- v = fb_readw(HD64461_GPBDR);
+- v |= HD64461_GPBDR_LCDOFF;
+- fb_writew(v, HD64461_GPBDR);
+-#endif
+ v = fb_readw(HD64461_LDR1);
+ v &= ~HD64461_LDR1_DON;
+ fb_writew(v, HD64461_LDR1);
+@@ -213,19 +193,18 @@ int hitfb_blank(int blank_mode, struct f
+ v = fb_readw(HD64461_STBCR);
+ v &= ~HD64461_STBCR_SLCDST;
+ fb_writew(v, HD64461_STBCR);
+-#ifdef MACH_HP600
+- sh_dac_enable(DAC_LCD_BRIGHTNESS);
+- v = fb_readw(HD64461_GPBDR);
+- v &= ~HD64461_GPBDR_LCDOFF;
+- fb_writew(v, HD64461_GPBDR);
+-#endif
+- v = fb_readw(HD64461_LDR1);
+- v |= HD64461_LDR1_DON;
+- fb_writew(v, HD64461_LDR1);
+
+ v = fb_readw(HD64461_LCDCCR);
+- v &= ~HD64461_LCDCCR_MOFF;
++ v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ);
+ fb_writew(v, HD64461_LCDCCR);
++
++ do {
++ v = fb_readw(HD64461_LCDCCR);
++ } while(v&HD64461_LCDCCR_STBACK);
++
++ v = fb_readw(HD64461_LDR1);
++ v |= HD64461_LDR1_DON;
++ fb_writew(v, HD64461_LDR1);
+ }
+ return 0;
+ }
+@@ -233,7 +212,7 @@ int hitfb_blank(int blank_mode, struct f
+ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+ {
+- if (regno >= info->cmap.len)
++ if (regno >= 256)
+ return 1;
+
+ switch (info->var.bits_per_pixel) {
+@@ -244,6 +223,8 @@ static int hitfb_setcolreg(unsigned regn
+ fb_writew(blue >> 10, HD64461_CPTWDR);
+ break;
+ case 16:
++ if (regno >= 16)
++ return 1;
+ ((u32 *) (info->pseudo_palette))[regno] =
+ ((red & 0xf800)) |
+ ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+@@ -252,26 +233,113 @@ static int hitfb_setcolreg(unsigned regn
+ return 0;
+ }
+
++static int hitfb_sync(struct fb_info *info)
++{
++ hitfb_accel_wait();
++
++ return 0;
++}
++
++static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++ int maxy;
++
++ var->xres = info->var.xres;
++ var->xres_virtual = info->var.xres;
++ var->yres = info->var.yres;
++
++ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16))
++ var->bits_per_pixel = info->var.bits_per_pixel;
++
++ if (var->yres_virtual < var->yres)
++ var->yres_virtual = var->yres;
++
++ maxy = info->fix.smem_len / var->xres;
++
++ if (var->bits_per_pixel == 16)
++ maxy /= 2;
++
++ if (var->yres_virtual > maxy)
++ var->yres_virtual = maxy;
++
++ var->xoffset = 0;
++ var->yoffset = 0;
++
++ switch (var->bits_per_pixel) {
++ case 8:
++ var->red.offset = 0;
++ var->red.length = 8;
++ var->green.offset = 0;
++ var->green.length = 8;
++ var->blue.offset = 0;
++ var->blue.length = 8;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++ case 16: /* RGB 565 */
++ var->red.offset = 11;
++ var->red.length = 5;
++ var->green.offset = 5;
++ var->green.length = 6;
++ var->blue.offset = 0;
++ var->blue.length = 5;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++ }
++
++ return 0;
++}
++
++static int hitfb_set_par(struct fb_info *info)
++{
++ unsigned short ldr3;
++
++ switch (info->var.bits_per_pixel) {
++ case 8:
++ info->fix.line_length = info->var.xres;
++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
++ info->fix.ypanstep = 16;
++ break;
++ case 16:
++ info->fix.line_length = info->var.xres*2;
++ info->fix.visual = FB_VISUAL_TRUECOLOR;
++ info->fix.ypanstep = 8;
++ break;
++ }
++
++ fb_writew(info->fix.line_length, HD64461_LCDCLOR);
++ ldr3 = fb_readw(HD64461_LDR3);
++ ldr3 &= ~15;
++ ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8;
++ fb_writew(ldr3, HD64461_LDR3);
++ return 0;
++}
++
+ static struct fb_ops hitfb_ops = {
+ .owner = THIS_MODULE,
++ .fb_check_var = hitfb_check_var,
++ .fb_set_par = hitfb_set_par,
+ .fb_setcolreg = hitfb_setcolreg,
+ .fb_blank = hitfb_blank,
++ .fb_sync = hitfb_sync,
+ .fb_pan_display = hitfb_pan_display,
+ .fb_fillrect = hitfb_fillrect,
+ .fb_copyarea = hitfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ };
+
+-int __init hitfb_init(void)
++static int __init hitfb_probe(struct platform_device *dev)
+ {
+ unsigned short lcdclor, ldr3, ldvndr;
+- int size;
+
+ if (fb_get_options("hitfb", NULL))
+ return -ENODEV;
+
++ hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000;
++ hitfb_fix.mmio_len = 0x1000;
+ hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
+- hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024;
++ hitfb_fix.smem_len = 512 * 1024;
+
+ lcdclor = fb_readw(HD64461_LCDCLOR);
+ ldvndr = fb_readw(HD64461_LDVNDR);
+@@ -321,12 +389,12 @@ int __init hitfb_init(void)
+ fb_info.var = hitfb_var;
+ fb_info.fix = hitfb_fix;
+ fb_info.pseudo_palette = pseudo_palette;
+- fb_info.flags = FBINFO_DEFAULT;
++ fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
++ FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
+
+ fb_info.screen_base = (void *)hitfb_fix.smem_start;
+
+- size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
+- fb_alloc_cmap(&fb_info.cmap, size, 0);
++ fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+ if (register_framebuffer(&fb_info) < 0)
+ return -EINVAL;
+@@ -336,9 +404,75 @@ int __init hitfb_init(void)
+ return 0;
+ }
+
++static int __devexit hitfb_remove(struct platform_device *dev)
++{
++ return unregister_framebuffer(&fb_info);
++}
++
++#ifdef CONFIG_PM
++static int hitfb_suspend(struct platform_device *dev, pm_message_t state)
++{
++ u16 v;
++
++ hitfb_blank(1,0);
++ v = fb_readw(HD64461_STBCR);
++ v |= HD64461_STBCR_SLCKE_IST;
++ fb_writew(v, HD64461_STBCR);
++
++ return 0;
++}
++
++static int hitfb_resume(struct platform_device *dev)
++{
++ u16 v;
++
++ v = fb_readw(HD64461_STBCR);
++ v &= ~HD64461_STBCR_SLCKE_OST;
++ msleep(100);
++ v = fb_readw(HD64461_STBCR);
++ v &= ~HD64461_STBCR_SLCKE_IST;
++ fb_writew(v, HD64461_STBCR);
++ hitfb_blank(0,0);
++
++ return 0;
++}
++#endif
++
++static struct platform_driver hitfb_driver = {
++ .probe = hitfb_probe,
++ .remove = __devexit_p(hitfb_remove),
++#ifdef CONFIG_PM
++ .suspend = hitfb_suspend,
++ .resume = hitfb_resume,
++#endif
++ .driver = {
++ .name = "hitfb",
++ },
++};
++
++static struct platform_device hitfb_device = {
++ .name = "hitfb",
++ .id = -1,
++};
++
++static int __init hitfb_init(void)
++{
++ int ret;
++
++ ret = platform_driver_register(&hitfb_driver);
++ if (!ret) {
++ ret = platform_device_register(&hitfb_device);
++ if (ret)
++ platform_driver_unregister(&hitfb_driver);
++ }
++ return ret;
++}
++
++
+ static void __exit hitfb_exit(void)
+ {
+- unregister_framebuffer(&fb_info);
++ platform_device_unregister(&hitfb_device);
++ platform_driver_unregister(&hitfb_driver);
+ }
+
+ module_init(hitfb_init);
+diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
+index c1f7b49..b38d805 100644
+--- a/drivers/video/i810/i810-i2c.c
++++ b/drivers/video/i810/i810-i2c.c
+@@ -19,7 +19,6 @@
+ #include "i810_main.h"
+ #include "../edid.h"
+
+-#define I810_DDC 0x50
+ /* bit locations in the registers */
+ #define SCL_DIR_MASK 0x0001
+ #define SCL_DIR 0x0002
+@@ -98,7 +97,6 @@ static int i810_setup_i2c_bus(struct i81
+ chan->algo.getsda = i810i2c_getsda;
+ chan->algo.getscl = i810i2c_getscl;
+ chan->algo.udelay = 10;
+- chan->algo.mdelay = 10;
+ chan->algo.timeout = (HZ/2);
+ chan->algo.data = chan;
+
+@@ -151,53 +149,14 @@ void i810_delete_i2c_busses(struct i810f
+ par->chan[2].par = NULL;
+ }
+
+-static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan)
+-{
+- u8 start = 0x0;
+- struct i2c_msg msgs[] = {
+- {
+- .addr = I810_DDC,
+- .len = 1,
+- .buf = &start,
+- }, {
+- .addr = I810_DDC,
+- .flags = I2C_M_RD,
+- .len = EDID_LENGTH,
+- },
+- };
+- u8 *buf;
+-
+- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+- if (!buf) {
+- DPRINTK("i810-i2c: Failed to allocate memory\n");
+- return NULL;
+- }
+- msgs[1].buf = buf;
+-
+- if (i2c_transfer(&chan->adapter, msgs, 2) == 2) {
+- DPRINTK("i810-i2c: I2C Transfer successful\n");
+- return buf;
+- }
+-
+- DPRINTK("i810-i2c: Unable to read EDID block.\n");
+- kfree(buf);
+- return NULL;
+-}
+-
+ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
+ {
+ struct i810fb_par *par = info->par;
+ u8 *edid = NULL;
+- int i;
+
+ DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
+ if (conn < par->ddc_num) {
+- for (i = 0; i < 3; i++) {
+- /* Do the real work */
+- edid = i810_do_probe_i2c_edid(&par->chan[conn]);
+- if (edid)
+- break;
+- }
++ edid = fb_ddc_read(&par->chan[conn].adapter);
+ } else {
+ const u8 *e = fb_firmware_edid(info->device);
+
+diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
+index a6ca02f..b55a12d 100644
+--- a/drivers/video/i810/i810_main.c
++++ b/drivers/video/i810/i810_main.c
+@@ -1554,15 +1554,17 @@ static struct fb_ops i810fb_ops __devini
+ /***********************************************************************
+ * Power Management *
+ ***********************************************************************/
+-static int i810fb_suspend(struct pci_dev *dev, pm_message_t state)
++static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
+ {
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct i810fb_par *par = info->par;
+
+- par->cur_state = state.event;
++ par->cur_state = mesg.event;
+
+- if (state.event == PM_EVENT_FREEZE) {
+- dev->dev.power.power_state = state;
++ switch (mesg.event) {
++ case PM_EVENT_FREEZE:
++ case PM_EVENT_PRETHAW:
++ dev->dev.power.power_state = mesg;
+ return 0;
+ }
+
+@@ -1578,7 +1580,7 @@ static int i810fb_suspend(struct pci_dev
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+- pci_set_power_state(dev, pci_choose_state(dev, state));
++ pci_set_power_state(dev, pci_choose_state(dev, mesg));
+ release_console_sem();
+
+ return 0;
+@@ -1600,7 +1602,10 @@ static int i810fb_resume(struct pci_dev
+ acquire_console_sem();
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+- pci_enable_device(dev);
++
++ if (pci_enable_device(dev))
++ goto fail;
++
+ pci_set_master(dev);
+ agp_bind_memory(par->i810_gtt.i810_fb_memory,
+ par->fb.offset);
+@@ -1609,6 +1614,7 @@ static int i810fb_resume(struct pci_dev
+ i810fb_set_par(info);
+ fb_set_suspend (info, 0);
+ info->fbops->fb_blank(VESA_NO_BLANKING, info);
++fail:
+ release_console_sem();
+ return 0;
+ }
+diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
+index 67f384f..e6df492 100644
+--- a/drivers/video/igafb.c
++++ b/drivers/video/igafb.c
+@@ -573,3 +573,10 @@ int __init igafb_setup(char *options)
+
+ module_init(igafb_init);
+ MODULE_LICENSE("GPL");
++static struct pci_device_id igafb_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
++};
++
++MODULE_DEVICE_TABLE(pci, igafb_pci_tbl);
+diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile
+index 722d21d..6c782d3 100644
+--- a/drivers/video/intelfb/Makefile
++++ b/drivers/video/intelfb/Makefile
+@@ -1,6 +1,8 @@
+ obj-$(CONFIG_FB_INTEL) += intelfb.o
+
+-intelfb-objs := intelfbdrv.o intelfbhw.o
++intelfb-y := intelfbdrv.o intelfbhw.o
++intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o
++intelfb-objs := $(intelfb-y)
+
+ ifdef CONFIG_FB_INTEL_DEBUG
+ #EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
+diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
+index e290d74..80b94c1 100644
+--- a/drivers/video/intelfb/intelfb.h
++++ b/drivers/video/intelfb/intelfb.h
+@@ -6,6 +6,10 @@
+ #include <linux/agp_backend.h>
+ #include <linux/fb.h>
+
++#ifdef CONFIG_FB_INTEL_I2C
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++#endif
+
+ /*** Version/name ***/
+ #define INTELFB_VERSION "0.9.4"
+@@ -115,6 +119,29 @@
+ /* Intel agpgart driver */
+ #define AGP_PHYSICAL_MEMORY 2
+
++/* store information about an Ixxx DVO */
++/* The i830->i865 use multiple DVOs with multiple i2cs */
++/* the i915, i945 have a single sDVO i2c bus - which is different */
++#define MAX_OUTPUTS 6
++
++/* these are outputs from the chip - integrated only
++ external chips are via DVO or SDVO output */
++#define INTELFB_OUTPUT_UNUSED 0
++#define INTELFB_OUTPUT_ANALOG 1
++#define INTELFB_OUTPUT_DVO 2
++#define INTELFB_OUTPUT_SDVO 3
++#define INTELFB_OUTPUT_LVDS 4
++#define INTELFB_OUTPUT_TVOUT 5
++
++#define INTELFB_DVO_CHIP_NONE 0
++#define INTELFB_DVO_CHIP_LVDS 1
++#define INTELFB_DVO_CHIP_TMDS 2
++#define INTELFB_DVO_CHIP_TVOUT 4
++
++#define INTELFB_OUTPUT_PIPE_NC 0
++#define INTELFB_OUTPUT_PIPE_A 1
++#define INTELFB_OUTPUT_PIPE_B 2
++
+ /*** Data Types ***/
+
+ /* supported chipsets */
+@@ -195,6 +222,10 @@ struct intelfb_hwstate {
+ u32 mem_mode;
+ u32 fw_blc_0;
+ u32 fw_blc_1;
++ u16 hwstam;
++ u16 ier;
++ u16 iir;
++ u16 imr;
+ };
+
+ struct intelfb_heap_data {
+@@ -204,6 +235,33 @@ struct intelfb_heap_data {
+ u32 size; // in bytes
+ };
+
++#ifdef CONFIG_FB_INTEL_I2C
++struct intelfb_i2c_chan {
++ struct intelfb_info *dinfo;
++ u32 reg;
++ struct i2c_adapter adapter;
++ struct i2c_algo_bit_data algo;
++};
++#endif
++
++struct intelfb_output_rec {
++ int type;
++ int pipe;
++ int flags;
++
++#ifdef CONFIG_FB_INTEL_I2C
++ struct intelfb_i2c_chan i2c_bus;
++ struct intelfb_i2c_chan ddc_bus;
++#endif
++};
++
++struct intelfb_vsync {
++ wait_queue_head_t wait;
++ unsigned int count;
++ int pan_display;
++ u32 pan_offset;
++};
++
+ struct intelfb_info {
+ struct fb_info *info;
+ struct fb_ops *fbops;
+@@ -220,7 +278,7 @@ struct intelfb_info {
+ u8 fbmem_gart;
+
+ /* mtrr support */
+- u32 mtrr_reg;
++ int mtrr_reg;
+ u32 has_mtrr;
+
+ /* heap data */
+@@ -267,6 +325,12 @@ struct intelfb_info {
+ int fixed_mode;
+ int ring_active;
+ int flag;
++ unsigned long irq_flags;
++ int open;
++
++ /* vsync */
++ struct intelfb_vsync vsync;
++ spinlock_t int_lock;
+
+ /* hw cursor */
+ int cursor_on;
+@@ -285,12 +349,25 @@ struct intelfb_info {
+
+ /* index into plls */
+ int pll_index;
++
++ /* outputs */
++ int num_outputs;
++ struct intelfb_output_rec output[MAX_OUTPUTS];
+ };
+
+ #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
+
++#ifndef FBIO_WAITFORVSYNC
++#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
++#endif
++
+ /*** function prototypes ***/
+
+ extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
+
++#ifdef CONFIG_FB_INTEL_I2C
++extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo);
++extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo);
++#endif
++
+ #endif /* _INTELFB_H */
+diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
+new file mode 100644
+index 0000000..5686e21
+--- /dev/null
++++ b/drivers/video/intelfb/intelfb_i2c.c
+@@ -0,0 +1,199 @@
++/**************************************************************************
++
++ Copyright 2006 Dave Airlie <airlied at linux.ie>
++
++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
++on 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 AND/OR THEIR 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/kernel.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/fb.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-id.h>
++#include <linux/i2c-algo-bit.h>
++
++#include <asm/io.h>
++
++#include "intelfb.h"
++#include "intelfbhw.h"
++
++/* bit locations in the registers */
++#define SCL_DIR_MASK 0x0001
++#define SCL_DIR 0x0002
++#define SCL_VAL_MASK 0x0004
++#define SCL_VAL_OUT 0x0008
++#define SCL_VAL_IN 0x0010
++#define SDA_DIR_MASK 0x0100
++#define SDA_DIR 0x0200
++#define SDA_VAL_MASK 0x0400
++#define SDA_VAL_OUT 0x0800
++#define SDA_VAL_IN 0x1000
++
++static void intelfb_gpio_setscl(void *data, int state)
++{
++ struct intelfb_i2c_chan *chan = data;
++ struct intelfb_info *dinfo = chan->dinfo;
++ u32 val;
++
++ OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
++ val = INREG(chan->reg);
++}
++
++static void intelfb_gpio_setsda(void *data, int state)
++{
++ struct intelfb_i2c_chan *chan = data;
++ struct intelfb_info *dinfo = chan->dinfo;
++ u32 val;
++
++ OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
++ val = INREG(chan->reg);
++}
++
++static int intelfb_gpio_getscl(void *data)
++{
++ struct intelfb_i2c_chan *chan = data;
++ struct intelfb_info *dinfo = chan->dinfo;
++ u32 val;
++
++ OUTREG(chan->reg, SCL_DIR_MASK);
++ OUTREG(chan->reg, 0);
++ val = INREG(chan->reg);
++ return ((val & SCL_VAL_IN) != 0);
++}
++
++static int intelfb_gpio_getsda(void *data)
++{
++ struct intelfb_i2c_chan *chan = data;
++ struct intelfb_info *dinfo = chan->dinfo;
++ u32 val;
++
++ OUTREG(chan->reg, SDA_DIR_MASK);
++ OUTREG(chan->reg, 0);
++ val = INREG(chan->reg);
++ return ((val & SDA_VAL_IN) != 0);
++}
++
++static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
++ struct intelfb_i2c_chan *chan,
++ const u32 reg, const char *name)
++{
++ int rc;
++
++ chan->dinfo = dinfo;
++ chan->reg = reg;
++ snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name);
++ chan->adapter.owner = THIS_MODULE;
++ chan->adapter.id = I2C_HW_B_INTELFB;
++ chan->adapter.algo_data = &chan->algo;
++ chan->adapter.dev.parent = &chan->dinfo->pdev->dev;
++ chan->algo.setsda = intelfb_gpio_setsda;
++ chan->algo.setscl = intelfb_gpio_setscl;
++ chan->algo.getsda = intelfb_gpio_getsda;
++ chan->algo.getscl = intelfb_gpio_getscl;
++ chan->algo.udelay = 40;
++ chan->algo.timeout = 20;
++ chan->algo.data = chan;
++
++ i2c_set_adapdata(&chan->adapter, chan);
++
++ /* Raise SCL and SDA */
++ intelfb_gpio_setsda(chan, 1);
++ intelfb_gpio_setscl(chan, 1);
++ udelay(20);
++
++ rc = i2c_bit_add_bus(&chan->adapter);
++ if (rc == 0)
++ DBG_MSG("I2C bus %s registered.\n", name);
++ else
++ WRN_MSG("Failed to register I2C bus %s.\n", name);
++ return rc;
++}
++
++void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
++{
++ int i = 0;
++
++ /* everyone has at least a single analog output */
++ dinfo->num_outputs = 1;
++ dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
++
++ /* setup the DDC bus for analog output */
++ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A");
++ i++;
++
++ /* need to add the output busses for each device
++ - this function is very incomplete
++ - i915GM has LVDS and TVOUT for example
++ */
++ switch(dinfo->chipset) {
++ case INTEL_830M:
++ case INTEL_845G:
++ case INTEL_855GM:
++ case INTEL_865G:
++ dinfo->output[i].type = INTELFB_OUTPUT_DVO;
++ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D");
++ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E");
++ i++;
++ break;
++ case INTEL_915G:
++ case INTEL_915GM:
++ /* has some LVDS + tv-out */
++ case INTEL_945G:
++ case INTEL_945GM:
++ /* SDVO ports have a single control bus - 2 devices */
++ dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
++ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E");
++ /* TODO: initialize the SDVO */
++// I830SDVOInit(pScrn, i, DVOB);
++ i++;
++
++ /* set up SDVOC */
++ dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
++ dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
++ /* TODO: initialize the SDVO */
++// I830SDVOInit(pScrn, i, DVOC);
++ i++;
++ break;
++ }
++ dinfo->num_outputs = i;
++}
++
++void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
++{
++ int i;
++
++ for (i = 0; i < MAX_OUTPUTS; i++) {
++ if (dinfo->output[i].i2c_bus.dinfo) {
++ i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter);
++ dinfo->output[i].i2c_bus.dinfo = NULL;
++ }
++ if (dinfo->output[i].ddc_bus.dinfo) {
++ i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter);
++ dinfo->output[i].ddc_bus.dinfo = NULL;
++ }
++ }
++}
+diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
+index 06af89d..6f9de04 100644
+--- a/drivers/video/intelfb/intelfbdrv.c
++++ b/drivers/video/intelfb/intelfbdrv.c
+@@ -136,6 +136,8 @@
+ static void __devinit get_initial_mode(struct intelfb_info *dinfo);
+ static void update_dinfo(struct intelfb_info *dinfo,
+ struct fb_var_screeninfo *var);
++static int intelfb_open(struct fb_info *info, int user);
++static int intelfb_release(struct fb_info *info, int user);
+ static int intelfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+ static int intelfb_set_par(struct fb_info *info);
+@@ -194,6 +196,8 @@ static int num_registered = 0;
+ /* fb ops */
+ static struct fb_ops intel_fb_ops = {
+ .owner = THIS_MODULE,
++ .fb_open = intelfb_open,
++ .fb_release = intelfb_release,
+ .fb_check_var = intelfb_check_var,
+ .fb_set_par = intelfb_set_par,
+ .fb_setcolreg = intelfb_setcolreg,
+@@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
+ if (!dinfo)
+ return;
+
++ intelfbhw_disable_irq(dinfo);
++
+ fb_dealloc_cmap(&dinfo->info->cmap);
+ kfree(dinfo->info->pixmap.addr);
+
+@@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
+ agp_free_memory(dinfo->gtt_ring_mem);
+ }
+
++#ifdef CONFIG_FB_INTEL_I2C
++ /* un-register I2C bus */
++ intelfb_delete_i2c_busses(dinfo);
++#endif
++
+ if (dinfo->mmio_base)
+ iounmap((void __iomem *)dinfo->mmio_base);
+ if (dinfo->aperture.virtual)
+@@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pde
+ if (bailearly == 5)
+ bailout(dinfo);
+
++#ifdef CONFIG_FB_INTEL_I2C
++ /* register I2C bus */
++ intelfb_create_i2c_busses(dinfo);
++#endif
++
+ if (bailearly == 6)
+ bailout(dinfo);
+
+@@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pde
+ }
+
+ dinfo->registered = 1;
++ dinfo->open = 0;
++
++ init_waitqueue_head(&dinfo->vsync.wait);
++ spin_lock_init(&dinfo->int_lock);
++ dinfo->irq_flags = 0;
++ dinfo->vsync.pan_display = 0;
++ dinfo->vsync.pan_offset = 0;
+
+ return 0;
+
+@@ -1188,6 +1211,34 @@ update_dinfo(struct intelfb_info *dinfo,
+ ***************************************************************/
+
+ static int
++intelfb_open(struct fb_info *info, int user)
++{
++ struct intelfb_info *dinfo = GET_DINFO(info);
++
++ if (user) {
++ dinfo->open++;
++ }
++
++ return 0;
++}
++
++static int
++intelfb_release(struct fb_info *info, int user)
++{
++ struct intelfb_info *dinfo = GET_DINFO(info);
++
++ if (user) {
++ dinfo->open--;
++ msleep(1);
++ if (!dinfo->open) {
++ intelfbhw_disable_irq(dinfo);
++ }
++ }
++
++ return 0;
++}
++
++static int
+ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ int change_var = 0;
+@@ -1433,6 +1484,19 @@ static int
+ intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+ {
+ int retval = 0;
++ struct intelfb_info *dinfo = GET_DINFO(info);
++ u32 pipe = 0;
++
++ switch (cmd) {
++ case FBIO_WAITFORVSYNC:
++ if (get_user(pipe, (__u32 __user *)arg))
++ return -EFAULT;
++
++ retval = intelfbhw_wait_for_vsync(dinfo, pipe);
++ break;
++ default:
++ break;
++ }
+
+ return retval;
+ }
+diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
+index 2a9322f..a958368 100644
+--- a/drivers/video/intelfb/intelfbhw.c
++++ b/drivers/video/intelfb/intelfbhw.c
+@@ -32,6 +32,7 @@
+ #include <linux/pci.h>
+ #include <linux/vmalloc.h>
+ #include <linux/pagemap.h>
++#include <linux/interrupt.h>
+
+ #include <asm/io.h>
+
+@@ -160,7 +161,7 @@ intelfbhw_get_memory(struct pci_dev *pde
+ return 1;
+
+ /* Find the bridge device. It is always 0:0.0 */
+- if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) {
++ if (!(bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)))) {
+ ERR_MSG("cannot find bridge device\n");
+ return 1;
+ }
+@@ -168,6 +169,8 @@ intelfbhw_get_memory(struct pci_dev *pde
+ /* Get the fb aperture size and "stolen" memory amount. */
+ tmp = 0;
+ pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
++ pci_dev_put(bridge_dev);
++
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_915G:
+ case PCI_DEVICE_ID_INTEL_915GM:
+@@ -368,7 +371,13 @@ intelfbhw_pan_display(struct fb_var_scre
+
+ offset += dinfo->fb.offset << 12;
+
+- OUTREG(DSPABASE, offset);
++ dinfo->vsync.pan_offset = offset;
++ if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
++ dinfo->vsync.pan_display = 1;
++ } else {
++ dinfo->vsync.pan_display = 0;
++ OUTREG(DSPABASE, offset);
++ }
+
+ return 0;
+ }
+@@ -585,6 +594,11 @@ intelfbhw_read_hw_state(struct intelfb_i
+ hw->fw_blc_0 = INREG(FW_BLC_0);
+ hw->fw_blc_1 = INREG(FW_BLC_1);
+
++ hw->hwstam = INREG16(HWSTAM);
++ hw->ier = INREG16(IER);
++ hw->iir = INREG16(IIR);
++ hw->imr = INREG16(IMR);
++
+ return 0;
+ }
+
+@@ -613,6 +627,7 @@ static int calc_vclock(int index, int m1
+ return vco / p;
+ }
+
++#if REGDUMP
+ static void
+ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
+ {
+@@ -638,6 +653,7 @@ intelfbhw_get_p1p2(struct intelfb_info *
+ *o_p1 = p1;
+ *o_p2 = p2;
+ }
++#endif
+
+
+ void
+@@ -648,7 +664,7 @@ intelfbhw_print_hw_state(struct intelfb_
+ int index = dinfo->pll_index;
+ DBG_MSG("intelfbhw_print_hw_state\n");
+
+- if (!hw || !dinfo)
++ if (!hw)
+ return;
+ /* Read in as much of the HW state as possible. */
+ printk("hw state dump start\n");
+@@ -794,6 +810,10 @@ intelfbhw_print_hw_state(struct intelfb_
+ printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0);
+ printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1);
+
++ printk(" HWSTAM 0x%04x\n", hw->hwstam);
++ printk(" IER 0x%04x\n", hw->ier);
++ printk(" IIR 0x%04x\n", hw->iir);
++ printk(" IMR 0x%04x\n", hw->imr);
+ printk("hw state dump end\n");
+ #endif
+ }
+@@ -1932,3 +1952,119 @@ intelfbhw_cursor_reset(struct intelfb_in
+ addr += 16;
+ }
+ }
++
++static irqreturn_t
++intelfbhw_irq(int irq, void *dev_id) {
++ int handled = 0;
++ u16 tmp;
++ struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
++
++ spin_lock(&dinfo->int_lock);
++
++ tmp = INREG16(IIR);
++ tmp &= VSYNC_PIPE_A_INTERRUPT;
++
++ if (tmp == 0) {
++ spin_unlock(&dinfo->int_lock);
++ return IRQ_RETVAL(handled);
++ }
++
++ OUTREG16(IIR, tmp);
++
++ if (tmp & VSYNC_PIPE_A_INTERRUPT) {
++ dinfo->vsync.count++;
++ if (dinfo->vsync.pan_display) {
++ dinfo->vsync.pan_display = 0;
++ OUTREG(DSPABASE, dinfo->vsync.pan_offset);
++ }
++ wake_up_interruptible(&dinfo->vsync.wait);
++ handled = 1;
++ }
++
++ spin_unlock(&dinfo->int_lock);
++
++ return IRQ_RETVAL(handled);
++}
++
++int
++intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
++
++ if (!test_and_set_bit(0, &dinfo->irq_flags)) {
++ if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
++ clear_bit(0, &dinfo->irq_flags);
++ return -EINVAL;
++ }
++
++ spin_lock_irq(&dinfo->int_lock);
++ OUTREG16(HWSTAM, 0xfffe);
++ OUTREG16(IMR, 0x0);
++ OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
++ spin_unlock_irq(&dinfo->int_lock);
++ } else if (reenable) {
++ u16 ier;
++
++ spin_lock_irq(&dinfo->int_lock);
++ ier = INREG16(IER);
++ if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
++ DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
++ OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
++ }
++ spin_unlock_irq(&dinfo->int_lock);
++ }
++ return 0;
++}
++
++void
++intelfbhw_disable_irq(struct intelfb_info *dinfo) {
++ u16 tmp;
++
++ if (test_and_clear_bit(0, &dinfo->irq_flags)) {
++ if (dinfo->vsync.pan_display) {
++ dinfo->vsync.pan_display = 0;
++ OUTREG(DSPABASE, dinfo->vsync.pan_offset);
++ }
++ spin_lock_irq(&dinfo->int_lock);
++ OUTREG16(HWSTAM, 0xffff);
++ OUTREG16(IMR, 0xffff);
++ OUTREG16(IER, 0x0);
++
++ tmp = INREG16(IIR);
++ OUTREG16(IIR, tmp);
++ spin_unlock_irq(&dinfo->int_lock);
++
++ free_irq(dinfo->pdev->irq, dinfo);
++ }
++}
++
++int
++intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
++ struct intelfb_vsync *vsync;
++ unsigned int count;
++ int ret;
++
++ switch (pipe) {
++ case 0:
++ vsync = &dinfo->vsync;
++ break;
++ default:
++ return -ENODEV;
++ }
++
++ ret = intelfbhw_enable_irq(dinfo, 0);
++ if (ret) {
++ return ret;
++ }
++
++ count = vsync->count;
++ ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
++ if (ret < 0) {
++ return ret;
++ }
++ if (ret == 0) {
++ intelfbhw_enable_irq(dinfo, 1);
++ DBG_MSG("wait_for_vsync timed out!\n");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
+diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
+index 10acda0..8c54ba8 100644
+--- a/drivers/video/intelfb/intelfbhw.h
++++ b/drivers/video/intelfb/intelfbhw.h
+@@ -88,6 +88,19 @@
+ #define INSTDONE 0x2090
+ #define PRI_RING_EMPTY 1
+
++#define HWSTAM 0x2098
++#define IER 0x20A0
++#define IIR 0x20A4
++#define IMR 0x20A8
++#define VSYNC_PIPE_A_INTERRUPT (1 << 7)
++#define PIPE_A_EVENT_INTERRUPT (1 << 4)
++#define VSYNC_PIPE_B_INTERRUPT (1 << 5)
++#define PIPE_B_EVENT_INTERRUPT (1 << 4)
++#define HOST_PORT_EVENT_INTERRUPT (1 << 3)
++#define CAPTURE_EVENT_INTERRUPT (1 << 2)
++#define USER_DEFINED_INTERRUPT (1 << 1)
++#define BREAKPOINT_INTERRUPT 1
++
+ #define INSTPM 0x20c0
+ #define SYNC_FLUSH_ENABLE (1 << 5)
+
+@@ -113,6 +126,12 @@
+ #define FW_DISPC_BL_SHIFT 8
+ #define FW_DISPC_BL_MASK 0x7
+
++#define GPIOA 0x5010
++#define GPIOB 0x5014
++#define GPIOC 0x5018 // this may be external DDC on i830
++#define GPIOD 0x501C // this is DVO DDC
++#define GPIOE 0x5020 // this is DVO i2C
++#define GPIOF 0x5024
+
+ /* PLL registers */
+ #define VGA0_DIVISOR 0x06000
+@@ -468,9 +487,12 @@
+
+ /* I/O macros */
+ #define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
++#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr)))
+ #define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
+ #define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
+ (addr)))
++#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \
++ (addr)))
+ #define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \
+ (addr)))
+
+@@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(st
+ extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
+ int height, u8 *data);
+ extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
++extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable);
++extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
++extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
+
+ #endif /* _INTELFBHW_H */
+diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
+index 57abbae..795c1a9 100644
+--- a/drivers/video/matrox/i2c-matroxfb.c
++++ b/drivers/video/matrox/i2c-matroxfb.c
+@@ -95,12 +95,12 @@ static struct i2c_adapter matrox_i2c_ada
+
+ static struct i2c_algo_bit_data matrox_i2c_algo_template =
+ {
+- NULL,
+- matroxfb_gpio_setsda,
+- matroxfb_gpio_setscl,
+- matroxfb_gpio_getsda,
+- matroxfb_gpio_getscl,
+- 10, 10, 100,
++ .setsda = matroxfb_gpio_setsda,
++ .setscl = matroxfb_gpio_setscl,
++ .getsda = matroxfb_gpio_getsda,
++ .getscl = matroxfb_gpio_getscl,
++ .udelay = 10,
++ .timeout = 100,
+ };
+
+ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
+diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
+index 4a57dab..e9b4115 100644
+--- a/drivers/video/matrox/matroxfb_base.c
++++ b/drivers/video/matrox/matroxfb_base.c
+@@ -198,7 +198,7 @@ static void matroxfb_crtc1_panpos(WPMINF
+ }
+ }
+
+-static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t matrox_irq(int irq, void *dev_id)
+ {
+ u_int32_t status;
+ int handled = 0;
+@@ -2277,10 +2277,13 @@ static void __init matroxfb_init_params(
+ }
+ }
+
+-static void __init matrox_init(void) {
++static int __init matrox_init(void) {
++ int err;
++
+ matroxfb_init_params();
+- pci_register_driver(&matroxfb_driver);
++ err = pci_register_driver(&matroxfb_driver);
+ dev = -1; /* accept all new devices... */
++ return err;
+ }
+
+ /* **************************** exit-time only **************************** */
+@@ -2437,6 +2440,7 @@ static int __initdata initialized = 0;
+ static int __init matroxfb_init(void)
+ {
+ char *option = NULL;
++ int err = 0;
+
+ DBG(__FUNCTION__)
+
+@@ -2448,11 +2452,11 @@ static int __init matroxfb_init(void)
+ return -ENXIO;
+ if (!initialized) {
+ initialized = 1;
+- matrox_init();
++ err = matrox_init();
+ }
+ hotplug = 1;
+ /* never return failure, user can hotplug matrox later... */
+- return 0;
++ return err;
+ }
+
+ module_init(matroxfb_init);
+diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
+index 6849ab7..a32d1af 100644
+--- a/drivers/video/mbx/mbxfb.c
++++ b/drivers/video/mbx/mbxfb.c
+@@ -118,8 +118,19 @@ static unsigned int mbxfb_get_pixclock(u
+ /* convert pixclock to KHz */
+ pixclock = PICOS2KHZ(pixclock_ps);
+
++ /* PLL output freq = (ref_clk * M) / (N * 2^P)
++ *
++ * M: 1 to 63
++ * N: 1 to 7
++ * P: 0 to 7
++ */
++
++ /* RAPH: When N==1, the resulting pixel clock appears to
++ * get divided by 2. Preventing N=1 by starting the following
++ * loop at 2 prevents this. Is this a bug with my chip
++ * revision or something I dont understand? */
+ for (m = 1; m < 64; m++) {
+- for (n = 1; n < 8; n++) {
++ for (n = 2; n < 8; n++) {
+ for (p = 0; p < 8; p++) {
+ clk = (ref_clk * m) / (n * (1 << p));
+ err = (clk > pixclock) ? (clk - pixclock) :
+@@ -244,8 +255,8 @@ static int mbxfb_set_par(struct fb_info
+
+ /* setup resolution */
+ gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
+- gsctrl |= Gsctrl_Width(info->var.xres - 1) |
+- Gsctrl_Height(info->var.yres - 1);
++ gsctrl |= Gsctrl_Width(info->var.xres) |
++ Gsctrl_Height(info->var.yres);
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+
+@@ -402,8 +413,8 @@ static void __devinit setup_graphics(str
+ {
+ unsigned long gsctrl;
+
+- gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres - 1) |
+- Gsctrl_Height(fbi->var.yres - 1);
++ gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
++ Gsctrl_Height(fbi->var.yres);
+ switch (fbi->var.bits_per_pixel) {
+ case 16:
+ if (fbi->var.green.length == 5)
+diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
+index 8209106..d9af88c 100644
+--- a/drivers/video/nvidia/nv_of.c
++++ b/drivers/video/nvidia/nv_of.c
+@@ -32,7 +32,7 @@ int nvidia_probe_of_connector(struct fb_
+ {
+ struct nvidia_par *par = info->par;
+ struct device_node *parent, *dp;
+- unsigned char *pedid = NULL;
++ const unsigned char *pedid = NULL;
+ static char *propnames[] = {
+ "DFP,EDID", "LCD,EDID", "EDID", "EDID1",
+ "EDID,B", "EDID,A", NULL };
+@@ -42,20 +42,19 @@ int nvidia_probe_of_connector(struct fb_
+ if (parent == NULL)
+ return -1;
+ if (par->twoHeads) {
+- char *pname;
++ const char *pname;
+ int len;
+
+ for (dp = NULL;
+ (dp = of_get_next_child(parent, dp)) != NULL;) {
+- pname = (char *)get_property(dp, "name", NULL);
++ pname = get_property(dp, "name", NULL);
+ if (!pname)
+ continue;
+ len = strlen(pname);
+ if ((pname[len-1] == 'A' && conn == 1) ||
+ (pname[len-1] == 'B' && conn == 2)) {
+ for (i = 0; propnames[i] != NULL; ++i) {
+- pedid = (unsigned char *)
+- get_property(dp, propnames[i],
++ pedid = get_property(dp, propnames[i],
+ NULL);
+ if (pedid != NULL)
+ break;
+@@ -67,8 +66,7 @@ int nvidia_probe_of_connector(struct fb_
+ }
+ if (pedid == NULL) {
+ for (i = 0; propnames[i] != NULL; ++i) {
+- pedid = (unsigned char *)
+- get_property(parent, propnames[i], NULL);
++ pedid = get_property(parent, propnames[i], NULL);
+ if (pedid != NULL)
+ break;
+ }
+diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
+index d4f8501..eb24107 100644
+--- a/drivers/video/nvidia/nvidia.c
++++ b/drivers/video/nvidia/nvidia.c
+@@ -28,6 +28,9 @@
+ #include <asm/prom.h>
+ #include <asm/pci-bridge.h>
+ #endif
++#ifdef CONFIG_BOOTX_TEXT
++#include <asm/btext.h>
++#endif
+
+ #include "nv_local.h"
+ #include "nv_type.h"
+@@ -681,6 +684,13 @@ static int nvidiafb_set_par(struct fb_in
+
+ nvidia_vga_protect(par, 0);
+
++#ifdef CONFIG_BOOTX_TEXT
++ /* Update debug text engine */
++ btext_update_display(info->fix.smem_start,
++ info->var.xres, info->var.yres,
++ info->var.bits_per_pixel, info->fix.line_length);
++#endif
++
+ NVTRACE_LEAVE();
+ return 0;
+ }
+@@ -950,24 +960,25 @@ static struct fb_ops nvidia_fb_ops = {
+ };
+
+ #ifdef CONFIG_PM
+-static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t state)
++static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
+ {
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct nvidia_par *par = info->par;
+
++ if (mesg.event == PM_EVENT_PRETHAW)
++ mesg.event = PM_EVENT_FREEZE;
+ acquire_console_sem();
+- par->pm_state = state.event;
++ par->pm_state = mesg.event;
+
+- if (state.event == PM_EVENT_FREEZE) {
+- dev->dev.power.power_state = state;
+- } else {
++ if (mesg.event == PM_EVENT_SUSPEND) {
+ fb_set_suspend(info, 1);
+ nvidiafb_blank(FB_BLANK_POWERDOWN, info);
+ nvidia_write_regs(par, &par->SavedReg);
+ pci_save_state(dev);
+ pci_disable_device(dev);
+- pci_set_power_state(dev, pci_choose_state(dev, state));
++ pci_set_power_state(dev, pci_choose_state(dev, mesg));
+ }
++ dev->dev.power.power_state = mesg;
+
+ release_console_sem();
+ return 0;
+@@ -983,7 +994,10 @@ static int nvidiafb_resume(struct pci_de
+
+ if (par->pm_state != PM_EVENT_FREEZE) {
+ pci_restore_state(dev);
+- pci_enable_device(dev);
++
++ if (pci_enable_device(dev))
++ goto fail;
++
+ pci_set_master(dev);
+ }
+
+@@ -992,6 +1006,7 @@ static int nvidiafb_resume(struct pci_de
+ fb_set_suspend (info, 0);
+ nvidiafb_blank(FB_BLANK_UNBLANK, info);
+
++fail:
+ release_console_sem();
+ return 0;
+ }
+diff --git a/drivers/video/offb.c b/drivers/video/offb.c
+index 0013311..9a40bbe 100644
+--- a/drivers/video/offb.c
++++ b/drivers/video/offb.c
+@@ -157,7 +157,7 @@ static int offb_setcolreg(u_int regno, u
+ out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
+ break;
+ case cmap_gxt2000:
+- out_le32((unsigned __iomem *) par->cmap_adr + regno,
++ out_le32(((unsigned __iomem *) par->cmap_adr) + regno,
+ (red << 16 | green << 8 | blue));
+ break;
+ }
+@@ -213,7 +213,7 @@ static int offb_blank(int blank, struct
+ out_le32(par->cmap_adr + 0xb4, 0);
+ break;
+ case cmap_gxt2000:
+- out_le32((unsigned __iomem *) par->cmap_adr + i,
++ out_le32(((unsigned __iomem *) par->cmap_adr) + i,
+ 0);
+ break;
+ }
+@@ -226,13 +226,23 @@ static int offb_blank(int blank, struct
+ static void __iomem *offb_map_reg(struct device_node *np, int index,
+ unsigned long offset, unsigned long size)
+ {
+- struct resource r;
+-
+- if (of_address_to_resource(np, index, &r))
+- return 0;
+- if ((r.start + offset + size) > r.end)
+- return 0;
+- return ioremap(r.start + offset, size);
++ const u32 *addrp;
++ u64 asize, taddr;
++ unsigned int flags;
++
++ addrp = of_get_pci_address(np, index, &asize, &flags);
++ if (addrp == NULL)
++ addrp = of_get_address(np, index, &asize, &flags);
++ if (addrp == NULL)
++ return NULL;
++ if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
++ return NULL;
++ if ((offset + size) > asize)
++ return NULL;
++ taddr = of_translate_address(np, addrp);
++ if (taddr == OF_BAD_ADDR)
++ return NULL;
++ return ioremap(taddr + offset, size);
+ }
+
+ static void __init offb_init_fb(const char *name, const char *full_name,
+@@ -289,7 +299,6 @@ static void __init offb_init_fb(const ch
+
+ par->cmap_type = cmap_unknown;
+ if (depth == 8) {
+- /* Palette hacks disabled for now */
+ if (dp && !strncmp(name, "ATY,Rage128", 11)) {
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+@@ -313,7 +322,8 @@ static void __init offb_init_fb(const ch
+ ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
+ par->cmap_data = par->cmap_adr + 1;
+ par->cmap_type = cmap_m64;
+- } else if (dp && device_is_compatible(dp, "pci1014,b7")) {
++ } else if (dp && (device_is_compatible(dp, "pci1014,b7") ||
++ device_is_compatible(dp, "pci1014,21c"))) {
+ par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_gxt2000;
+@@ -409,31 +419,31 @@ static void __init offb_init_nodriver(st
+ unsigned int flags, rsize, addr_prop = 0;
+ unsigned long max_size = 0;
+ u64 rstart, address = OF_BAD_ADDR;
+- u32 *pp, *addrp, *up;
++ const u32 *pp, *addrp, *up;
+ u64 asize;
+
+- pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
++ pp = get_property(dp, "linux,bootx-depth", &len);
+ if (pp == NULL)
+- pp = (u32 *)get_property(dp, "depth", &len);
++ pp = get_property(dp, "depth", &len);
+ if (pp && len == sizeof(u32))
+ depth = *pp;
+
+- pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
++ pp = get_property(dp, "linux,bootx-width", &len);
+ if (pp == NULL)
+- pp = (u32 *)get_property(dp, "width", &len);
++ pp = get_property(dp, "width", &len);
+ if (pp && len == sizeof(u32))
+ width = *pp;
+
+- pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
++ pp = get_property(dp, "linux,bootx-height", &len);
+ if (pp == NULL)
+- pp = (u32 *)get_property(dp, "height", &len);
++ pp = get_property(dp, "height", &len);
+ if (pp && len == sizeof(u32))
+ height = *pp;
+
+- pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
++ pp = get_property(dp, "linux,bootx-linebytes", &len);
+ if (pp == NULL)
+- pp = (u32 *)get_property(dp, "linebytes", &len);
+- if (pp && len == sizeof(u32))
++ pp = get_property(dp, "linebytes", &len);
++ if (pp && len == sizeof(u32) && (*pp != 0xffffffffu))
+ pitch = *pp;
+ else
+ pitch = width * ((depth + 7) / 8);
+@@ -450,9 +460,9 @@ static void __init offb_init_nodriver(st
+ * ranges and pick one that is both big enough and if possible encloses
+ * the "address" property. If none match, we pick the biggest
+ */
+- up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
++ up = get_property(dp, "linux,bootx-addr", &len);
+ if (up == NULL)
+- up = (u32 *)get_property(dp, "address", &len);
++ up = get_property(dp, "address", &len);
+ if (up && len == sizeof(u32))
+ addr_prop = *up;
+
+@@ -496,7 +506,7 @@ static void __init offb_init_nodriver(st
+ offb_init_fb(no_real_node ? "bootx" : dp->name,
+ no_real_node ? "display" : dp->full_name,
+ width, height, depth, pitch, address,
+- no_real_node ? dp : NULL);
++ no_real_node ? NULL : dp);
+ }
+ }
+
+diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
+index 983be3e..fdb33cd 100644
+--- a/drivers/video/platinumfb.c
++++ b/drivers/video/platinumfb.c
+@@ -339,11 +339,12 @@ static int __devinit platinum_init_fb(st
+
+ sense = read_platinum_sense(pinfo);
+ printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
+-
+ if (default_vmode == VMODE_NVRAM) {
++#ifdef CONFIG_NVRAM
+ default_vmode = nvram_read_byte(NV_VMODE);
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
+ !platinum_reg_init[default_vmode-1])
++#endif
+ default_vmode = VMODE_CHOOSE;
+ }
+ if (default_vmode == VMODE_CHOOSE) {
+@@ -351,8 +352,10 @@ static int __devinit platinum_init_fb(st
+ }
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+ default_vmode = VMODE_640_480_60;
++#ifdef CONFIG_NVRAM
+ if (default_cmode == CMODE_NVRAM)
+ default_cmode = nvram_read_byte(NV_CMODE);
++#endif
+ if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+ default_cmode = CMODE_8;
+ /*
+diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
+index 940ba2b..c7bc809 100644
+--- a/drivers/video/pvr2fb.c
++++ b/drivers/video/pvr2fb.c
+@@ -187,7 +187,7 @@ static short do_blank = 0; /* (Un)Blank
+ static unsigned int is_blanked = 0; /* Is the screen blanked? */
+
+ #ifdef CONFIG_SH_STORE_QUEUES
+-static struct sq_mapping *pvr2fb_map;
++static unsigned long pvr2fb_map;
+ #endif
+
+ #ifdef CONFIG_SH_DMA
+@@ -209,19 +209,21 @@ static int pvr2fb_set_par(struct fb_info
+ static void pvr2_update_display(struct fb_info *info);
+ static void pvr2_init_display(struct fb_info *info);
+ static void pvr2_do_blank(void);
+-static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
++static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id);
+ static int pvr2_init_cable(void);
+ static int pvr2_get_param(const struct pvr2_params *p, const char *s,
+ int val, int size);
++#ifdef CONFIG_SH_DMA
+ static ssize_t pvr2fb_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos);
++#endif
+
+ static struct fb_ops pvr2fb_ops = {
+- .owner = THIS_MODULE,
+- .fb_setcolreg = pvr2fb_setcolreg,
+- .fb_blank = pvr2fb_blank,
+- .fb_check_var = pvr2fb_check_var,
+- .fb_set_par = pvr2fb_set_par,
++ .owner = THIS_MODULE,
++ .fb_setcolreg = pvr2fb_setcolreg,
++ .fb_blank = pvr2fb_blank,
++ .fb_check_var = pvr2fb_check_var,
++ .fb_set_par = pvr2fb_set_par,
+ #ifdef CONFIG_SH_DMA
+ .fb_write = pvr2fb_write,
+ #endif
+@@ -624,7 +626,7 @@ static void pvr2_do_blank(void)
+ is_blanked = do_blank > 0 ? do_blank : 0;
+ }
+
+-static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id)
+ {
+ struct fb_info *info = dev_id;
+
+@@ -783,7 +785,7 @@ static int __init pvr2fb_common_init(voi
+ goto out_err;
+ }
+
+- fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len);
++ fb_memset(fb_info->screen_base, 0, pvr2_fix.smem_len);
+
+ pvr2_fix.ypanstep = nopan ? 0 : 1;
+ pvr2_fix.ywrapstep = nowrap ? 0 : 1;
+@@ -820,7 +822,7 @@ static int __init pvr2fb_common_init(voi
+ modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10));
+ printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n",
+ fb_info->node, fb_info->var.xres, fb_info->var.yres,
+- fb_info->var.bits_per_pixel,
++ fb_info->var.bits_per_pixel,
+ get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
+ (char *)pvr2_get_param(cables, NULL, cable_type, 3),
+ (char *)pvr2_get_param(outputs, NULL, video_output, 3));
+@@ -829,10 +831,10 @@ static int __init pvr2fb_common_init(voi
+ printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
+
+ pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
+- fb_info->fix.id);
++ fb_info->fix.id, pgprot_val(PAGE_SHARED));
+
+ printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
+- fb_info->node, pvr2fb_map->sq_addr);
++ fb_info->node, pvr2fb_map);
+ #endif
+
+ return 0;
+diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
+index bbb0710..8a8ae55 100644
+--- a/drivers/video/pxafb.c
++++ b/drivers/video/pxafb.c
+@@ -59,7 +59,7 @@
+ #define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
+
+ static void (*pxafb_backlight_power)(int);
+-static void (*pxafb_lcd_power)(int);
++static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
+
+ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+@@ -214,6 +214,48 @@ extern unsigned int get_clk_frequency_kh
+ #endif
+
+ /*
++ * Select the smallest mode that allows the desired resolution to be
++ * displayed. If desired parameters can be rounded up.
++ */
++static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
++{
++ struct pxafb_mode_info *mode = NULL;
++ struct pxafb_mode_info *modelist = mach->modes;
++ unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
++ unsigned int i;
++
++ for (i = 0 ; i < mach->num_modes ; i++) {
++ if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
++ modelist[i].xres < best_x && modelist[i].yres < best_y &&
++ modelist[i].bpp >= var->bits_per_pixel ) {
++ best_x = modelist[i].xres;
++ best_y = modelist[i].yres;
++ mode = &modelist[i];
++ }
++ }
++
++ return mode;
++}
++
++static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
++{
++ var->xres = mode->xres;
++ var->yres = mode->yres;
++ var->bits_per_pixel = mode->bpp;
++ var->pixclock = mode->pixclock;
++ var->hsync_len = mode->hsync_len;
++ var->left_margin = mode->left_margin;
++ var->right_margin = mode->right_margin;
++ var->vsync_len = mode->vsync_len;
++ var->upper_margin = mode->upper_margin;
++ var->lower_margin = mode->lower_margin;
++ var->sync = mode->sync;
++ var->grayscale = mode->cmap_greyscale;
++ var->xres_virtual = var->xres;
++ var->yres_virtual = var->yres;
++}
++
++/*
+ * pxafb_check_var():
+ * Get the video params out of 'var'. If a value doesn't fit, round it up,
+ * if it's too big, return -EINVAL.
+@@ -225,15 +267,29 @@ extern unsigned int get_clk_frequency_kh
+ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+- if (var->xres > fbi->max_xres)
+- return -EINVAL;
+- if (var->yres > fbi->max_yres)
+- return -EINVAL;
++
++ if (inf->fixed_modes) {
++ struct pxafb_mode_info *mode;
++
++ mode = pxafb_getmode(inf, var);
++ if (!mode)
++ return -EINVAL;
++ pxafb_setmode(var, mode);
++ } else {
++ if (var->xres > inf->modes->xres)
++ return -EINVAL;
++ if (var->yres > inf->modes->yres)
++ return -EINVAL;
++ if (var->bits_per_pixel > inf->modes->bpp)
++ return -EINVAL;
++ }
++
+ var->xres_virtual =
+ max(var->xres_virtual, var->xres);
+ var->yres_virtual =
+@@ -693,7 +749,7 @@ static inline void __pxafb_lcd_power(str
+ pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff");
+
+ if (pxafb_lcd_power)
+- pxafb_lcd_power(on);
++ pxafb_lcd_power(on, &fbi->fb.var);
+ }
+
+ static void pxafb_setup_gpio(struct pxafb_info *fbi)
+@@ -790,7 +846,7 @@ static void pxafb_disable_controller(str
+ /*
+ * pxafb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+-static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
+ {
+ struct pxafb_info *fbi = dev_id;
+ unsigned int lcsr = LCSR;
+@@ -869,9 +925,11 @@ static void set_ctrlr_state(struct pxafb
+ * registers.
+ */
+ if (old_state == C_ENABLE) {
++ __pxafb_lcd_power(fbi, 0);
+ pxafb_disable_controller(fbi);
+ pxafb_setup_gpio(fbi);
+ pxafb_enable_controller(fbi);
++ __pxafb_lcd_power(fbi, 1);
+ }
+ break;
+
+@@ -1049,6 +1107,8 @@ static struct pxafb_info * __init pxafb_
+ struct pxafb_info *fbi;
+ void *addr;
+ struct pxafb_mach_info *inf = dev->platform_data;
++ struct pxafb_mode_info *mode = inf->modes;
++ int i, smemlen;
+
+ /* Alloc the pxafb_info and pseudo_palette in one step */
+ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
+@@ -1082,31 +1142,21 @@ static struct pxafb_info * __init pxafb_
+ addr = addr + sizeof(struct pxafb_info);
+ fbi->fb.pseudo_palette = addr;
+
+- fbi->max_xres = inf->xres;
+- fbi->fb.var.xres = inf->xres;
+- fbi->fb.var.xres_virtual = inf->xres;
+- fbi->max_yres = inf->yres;
+- fbi->fb.var.yres = inf->yres;
+- fbi->fb.var.yres_virtual = inf->yres;
+- fbi->max_bpp = inf->bpp;
+- fbi->fb.var.bits_per_pixel = inf->bpp;
+- fbi->fb.var.pixclock = inf->pixclock;
+- fbi->fb.var.hsync_len = inf->hsync_len;
+- fbi->fb.var.left_margin = inf->left_margin;
+- fbi->fb.var.right_margin = inf->right_margin;
+- fbi->fb.var.vsync_len = inf->vsync_len;
+- fbi->fb.var.upper_margin = inf->upper_margin;
+- fbi->fb.var.lower_margin = inf->lower_margin;
+- fbi->fb.var.sync = inf->sync;
+- fbi->fb.var.grayscale = inf->cmap_greyscale;
++ pxafb_setmode(&fbi->fb.var, mode);
++
+ fbi->cmap_inverse = inf->cmap_inverse;
+ fbi->cmap_static = inf->cmap_static;
++
+ fbi->lccr0 = inf->lccr0;
+ fbi->lccr3 = inf->lccr3;
+ fbi->state = C_STARTUP;
+ fbi->task_state = (u_char)-1;
+- fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
+- fbi->max_bpp / 8;
++
++ for (i = 0; i < inf->num_modes; i++) {
++ smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
++ if (smemlen > fbi->fb.fix.smem_len)
++ fbi->fb.fix.smem_len = smemlen;
++ }
+
+ init_waitqueue_head(&fbi->ctrlr_wait);
+ INIT_WORK(&fbi->task, pxafb_task, fbi);
+@@ -1307,12 +1357,12 @@ int __init pxafb_probe(struct platform_d
+ (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
+ dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+- (inf->upper_margin || inf->lower_margin))
++ (inf->modes->upper_margin || inf->modes->lower_margin))
+ dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
+ #endif
+
+- dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
+- if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
++ dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
++ if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
+ dev_err(&dev->dev, "Invalid resolution or bit depth\n");
+ ret = -EINVAL;
+ goto failed;
+diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
+index 47f41f7..7499a1c 100644
+--- a/drivers/video/pxafb.h
++++ b/drivers/video/pxafb.h
+@@ -41,10 +41,6 @@ struct pxafb_info {
+ struct fb_info fb;
+ struct device *dev;
+
+- u_int max_bpp;
+- u_int max_xres;
+- u_int max_yres;
+-
+ /*
+ * These are the addresses we mapped
+ * the framebuffer memory region to.
+diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
+index 8ddb47a..a433cc7 100644
+--- a/drivers/video/riva/fbdev.c
++++ b/drivers/video/riva/fbdev.c
+@@ -393,8 +393,8 @@ static void riva_bl_init(struct riva_par
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+- 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+- 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
++ MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,
++ FB_BACKLIGHT_MAX);
+ mutex_unlock(&info->bl_mutex);
+
+ down(&bd->sem);
+@@ -784,7 +784,7 @@ static void riva_load_video_mode(struct
+
+ NVTRACE_ENTER();
+ /* time to calculate */
+- rivafb_blank(1, info);
++ rivafb_blank(FB_BLANK_NORMAL, info);
+
+ bpp = info->var.bits_per_pixel;
+ if (bpp == 16 && info->var.green.length == 5)
+@@ -917,7 +917,7 @@ static void riva_load_video_mode(struct
+ par->current_state = newmode;
+ riva_load_state(par, &par->current_state);
+ par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
+- rivafb_blank(0, info);
++ rivafb_blank(FB_BLANK_UNBLANK, info);
+ NVTRACE_LEAVE();
+ }
+
+@@ -1826,8 +1826,8 @@ static int __devinit riva_get_EDID_OF(st
+ {
+ struct riva_par *par = info->par;
+ struct device_node *dp;
+- unsigned char *pedid = NULL;
+- unsigned char *disptype = NULL;
++ const unsigned char *pedid = NULL;
++ const unsigned char *disptype = NULL;
+ static char *propnames[] = {
+ "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL };
+ int i;
+@@ -1835,16 +1835,15 @@ static int __devinit riva_get_EDID_OF(st
+ NVTRACE_ENTER();
+ dp = pci_device_to_OF_node(pd);
+ for (; dp != NULL; dp = dp->child) {
+- disptype = (unsigned char *)get_property(dp, "display-type", NULL);
++ disptype = get_property(dp, "display-type", NULL);
+ if (disptype == NULL)
+ continue;
+ if (strncmp(disptype, "LCD", 3) != 0)
+ continue;
+ for (i = 0; propnames[i] != NULL; ++i) {
+- pedid = (unsigned char *)
+- get_property(dp, propnames[i], NULL);
++ pedid = get_property(dp, propnames[i], NULL);
+ if (pedid != NULL) {
+- par->EDID = pedid;
++ par->EDID = (unsigned char *)pedid;
+ NVTRACE("LCD found.\n");
+ return 1;
+ }
+diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
+index 9751c37..c15b259 100644
+--- a/drivers/video/riva/rivafb-i2c.c
++++ b/drivers/video/riva/rivafb-i2c.c
+@@ -25,8 +25,6 @@
+ #include "rivafb.h"
+ #include "../edid.h"
+
+-#define RIVA_DDC 0x50
+-
+ static void riva_gpio_setscl(void* data, int state)
+ {
+ struct riva_i2c_chan *chan = data;
+@@ -158,50 +156,12 @@ void riva_delete_i2c_busses(struct riva_
+ par->chan[2].par = NULL;
+ }
+
+-static u8 *riva_do_probe_i2c_edid(struct riva_i2c_chan *chan)
+-{
+- u8 start = 0x0;
+- struct i2c_msg msgs[] = {
+- {
+- .addr = RIVA_DDC,
+- .len = 1,
+- .buf = &start,
+- }, {
+- .addr = RIVA_DDC,
+- .flags = I2C_M_RD,
+- .len = EDID_LENGTH,
+- },
+- };
+- u8 *buf;
+-
+- if (!chan->par)
+- return NULL;
+-
+- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+- if (!buf) {
+- dev_warn(&chan->par->pdev->dev, "Out of memory!\n");
+- return NULL;
+- }
+- msgs[1].buf = buf;
+-
+- if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
+- return buf;
+- dev_dbg(&chan->par->pdev->dev, "Unable to read EDID block.\n");
+- kfree(buf);
+- return NULL;
+-}
+-
+ int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
+ {
+ u8 *edid = NULL;
+- int i;
+
+- for (i = 0; i < 3; i++) {
+- /* Do the real work */
+- edid = riva_do_probe_i2c_edid(&par->chan[conn-1]);
+- if (edid)
+- break;
+- }
++ edid = fb_ddc_read(&par->chan[conn-1].adapter);
++
+ if (out_edid)
+ *out_edid = edid;
+ if (!edid)
+diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
+index ad3bdd6..5940734 100644
+--- a/drivers/video/s3c2410fb.c
++++ b/drivers/video/s3c2410fb.c
+@@ -614,7 +614,7 @@ static void s3c2410fb_write_palette(stru
+ }
+ }
+
+-static irqreturn_t s3c2410fb_irq(int irq, void *dev_id, struct pt_regs *r)
++static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
+ {
+ struct s3c2410fb_info *fbi = dev_id;
+ unsigned long lcdirq = readl(S3C2410_LCDINTPND);
+diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
+index be40968..f3f8a8e 100644
+--- a/drivers/video/s3c2410fb.h
++++ b/drivers/video/s3c2410fb.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/s3c2410fb.h
++ * linux/drivers/video/s3c2410fb.h
+ * Copyright (c) Arnaud Patard
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
+index a2e6e72..cd10b18 100644
+--- a/drivers/video/sa1100fb.c
++++ b/drivers/video/sa1100fb.c
+@@ -1085,7 +1085,7 @@ static void sa1100fb_disable_controller(
+ /*
+ * sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+-static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
+ {
+ struct sa1100fb_info *fbi = dev_id;
+ unsigned int lcsr = LCSR;
+diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
+index e83befd..3f94223 100644
+--- a/drivers/video/savage/savagefb-i2c.c
++++ b/drivers/video/savage/savagefb-i2c.c
+@@ -148,7 +148,6 @@ static int savage_setup_i2c_bus(struct s
+ chan->adapter.algo_data = &chan->algo;
+ chan->adapter.dev.parent = &chan->par->pcidev->dev;
+ chan->algo.udelay = 40;
+- chan->algo.mdelay = 5;
+ chan->algo.timeout = 20;
+ chan->algo.data = chan;
+
+@@ -214,52 +213,15 @@ void savagefb_delete_i2c_busses(struct f
+ par->chan.par = NULL;
+ }
+
+-static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
+-{
+- u8 start = 0x0;
+- struct i2c_msg msgs[] = {
+- {
+- .addr = SAVAGE_DDC,
+- .len = 1,
+- .buf = &start,
+- }, {
+- .addr = SAVAGE_DDC,
+- .flags = I2C_M_RD,
+- .len = EDID_LENGTH,
+- },
+- };
+- u8 *buf = NULL;
+-
+- if (chan->par) {
+- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+-
+- if (buf) {
+- msgs[1].buf = buf;
+-
+- if (i2c_transfer(&chan->adapter, msgs, 2) != 2) {
+- dev_dbg(&chan->par->pcidev->dev,
+- "Unable to read EDID block.\n");
+- kfree(buf);
+- buf = NULL;
+- }
+- }
+- }
+-
+- return buf;
+-}
+-
+ int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid)
+ {
+ struct savagefb_par *par = info->par;
+- u8 *edid = NULL;
+- int i;
+-
+- for (i = 0; i < 3; i++) {
+- /* Do the real work */
+- edid = savage_do_probe_i2c_edid(&par->chan);
+- if (edid)
+- break;
+- }
++ u8 *edid;
++
++ if (par->chan.par)
++ edid = fb_ddc_read(&par->chan.adapter);
++ else
++ edid = NULL;
+
+ if (!edid) {
+ /* try to get from firmware */
+diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
+index 461e094..82b3dea 100644
+--- a/drivers/video/savage/savagefb_driver.c
++++ b/drivers/video/savage/savagefb_driver.c
+@@ -2323,24 +2323,24 @@ static void __devexit savagefb_remove(st
+ }
+ }
+
+-static int savagefb_suspend(struct pci_dev* dev, pm_message_t state)
++static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
+ {
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct savagefb_par *par = info->par;
+
+ DBG("savagefb_suspend");
+
+-
+- par->pm_state = state.event;
++ if (mesg.event == PM_EVENT_PRETHAW)
++ mesg.event = PM_EVENT_FREEZE;
++ par->pm_state = mesg.event;
++ dev->dev.power.power_state = mesg;
+
+ /*
+ * For PM_EVENT_FREEZE, do not power down so the console
+ * can remain active.
+ */
+- if (state.event == PM_EVENT_FREEZE) {
+- dev->dev.power.power_state = state;
++ if (mesg.event == PM_EVENT_FREEZE)
+ return 0;
+- }
+
+ acquire_console_sem();
+ fb_set_suspend(info, 1);
+@@ -2353,7 +2353,7 @@ static int savagefb_suspend(struct pci_d
+ savage_disable_mmio(par);
+ pci_save_state(dev);
+ pci_disable_device(dev);
+- pci_set_power_state(dev, pci_choose_state(dev, state));
++ pci_set_power_state(dev, pci_choose_state(dev, mesg));
+ release_console_sem();
+
+ return 0;
+diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
+index 7ecab87..59d1284 100644
+--- a/drivers/video/sis/init.h
++++ b/drivers/video/sis/init.h
+@@ -77,16 +77,9 @@
+ #include <linux/types.h>
+ #include <asm/io.h>
+ #include <linux/fb.h>
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <video/fbcon.h>
+-#endif
+ #include "sis.h"
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <linux/sisfb.h>
+-#else
+ #include <video/sisfb.h>
+ #endif
+-#endif
+
+ /* Mode numbers */
+ static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
+diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
+index bc321dc..4f3a286 100644
+--- a/drivers/video/sis/init301.h
++++ b/drivers/video/sis/init301.h
+@@ -71,16 +71,9 @@
+ #include <linux/types.h>
+ #include <asm/io.h>
+ #include <linux/fb.h>
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <video/fbcon.h>
+-#endif
+ #include "sis.h"
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <linux/sisfb.h>
+-#else
+ #include <video/sisfb.h>
+ #endif
+-#endif
+
+ static const unsigned char SiS_YPbPrTable[3][64] = {
+ {
+diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
+index 09f5d75..c3884a2 100644
+--- a/drivers/video/sis/initextlfb.c
++++ b/drivers/video/sis/initextlfb.c
+@@ -34,12 +34,10 @@
+ #include <linux/types.h>
+ #include <linux/fb.h>
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
+ unsigned char modeno, unsigned char rateindex);
+ int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ unsigned char rateindex, struct fb_var_screeninfo *var);
+-#endif
+ BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ int *htotal, int *vtotal, unsigned char rateindex);
+
+@@ -49,7 +47,6 @@ extern BOOLEAN SiS_SearchModeID(struct S
+ extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
+ int xres, int yres, struct fb_var_screeninfo *var, BOOLEAN writeres);
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ int
+ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ unsigned char rateindex)
+@@ -177,7 +174,6 @@ sisfb_mode_rate_to_ddata(struct SiS_Priv
+
+ return 1;
+ }
+-#endif /* Linux >= 2.5 */
+
+ BOOLEAN
+ sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal,
+diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
+index f595680..d048bd3 100644
+--- a/drivers/video/sis/osdef.h
++++ b/drivers/video/sis/osdef.h
+@@ -100,11 +100,7 @@
+ #define SIS315H
+ #endif
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ #define SIS_LINUX_KERNEL_26
+-#else
+-#define SIS_LINUX_KERNEL_24
+-#endif
+
+ #if !defined(SIS300) && !defined(SIS315H)
+ #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
+diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c
+index 3b7ce03..7addf91 100644
+--- a/drivers/video/sis/sis_accel.c
++++ b/drivers/video/sis/sis_accel.c
+@@ -32,22 +32,10 @@
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/fb.h>
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <linux/console.h>
+-#endif
+ #include <linux/ioport.h>
+ #include <linux/types.h>
+-
+ #include <asm/io.h>
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <video/fbcon.h>
+-#include <video/fbcon-cfb8.h>
+-#include <video/fbcon-cfb16.h>
+-#include <video/fbcon-cfb24.h>
+-#include <video/fbcon-cfb32.h>
+-#endif
+-
+ #include "sis.h"
+ #include "sis_accel.h"
+
+@@ -91,11 +79,9 @@ static const u8 sisPatALUConv[] =
+ 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
+ };
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+ static const int myrops[] = {
+ 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+ };
+-#endif
+
+ /* 300 series ----------------------------------------------------- */
+ #ifdef CONFIG_FB_SIS_300
+@@ -315,8 +301,6 @@ void sisfb_syncaccel(struct sis_video_in
+ }
+ }
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* --------------- 2.5 --------------- */
+-
+ int fbcon_sis_sync(struct fb_info *info)
+ {
+ struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+@@ -438,13 +422,3 @@ void fbcon_sis_copyarea(struct fb_info *
+
+ sisfb_syncaccel(ivideo);
+ }
+-
+-#endif
+-
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */
+-
+-#include "sisfb_accel_2_4.h"
+-
+-#endif /* KERNEL VERSION */
+-
+-
+diff --git a/drivers/video/sis/sis_accel.h b/drivers/video/sis/sis_accel.h
+index 046e2c4..30e03cd 100644
+--- a/drivers/video/sis/sis_accel.h
++++ b/drivers/video/sis/sis_accel.h
+@@ -390,25 +390,11 @@
+ MMIO_OUT32(ivideo->mmio_vbase, FIRE_TRIGGER, 0); \
+ CmdQueLen -= 2;
+
+-
+ int sisfb_initaccel(struct sis_video_info *ivideo);
+ void sisfb_syncaccel(struct sis_video_info *ivideo);
+
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+-void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty,
+- int dstx, int height, int width);
+-void fbcon_sis_revc(struct display *p, int srcy, int srcx);
+-void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy,
+- int srcx, int height, int width);
+-void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy,
+- int srcx, int height, int width);
+-void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy,
+- int srcx, int height, int width);
+-#endif
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+ int fbcon_sis_sync(struct fb_info *info);
+ void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+ void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+-#endif
+
+ #endif
+diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
+index 895ebda..baaf495 100644
+--- a/drivers/video/sis/sis_main.c
++++ b/drivers/video/sis/sis_main.c
+@@ -35,9 +35,7 @@
+
+ #include <linux/version.h>
+ #include <linux/module.h>
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ #include <linux/moduleparam.h>
+-#endif
+ #include <linux/kernel.h>
+ #include <linux/smp_lock.h>
+ #include <linux/spinlock.h>
+@@ -58,9 +56,6 @@
+ #include <linux/init.h>
+ #include <linux/pci.h>
+ #include <linux/vmalloc.h>
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <linux/vt_kern.h>
+-#endif
+ #include <linux/capability.h>
+ #include <linux/fs.h>
+ #include <linux/types.h>
+@@ -70,35 +65,9 @@
+ #include <asm/mtrr.h>
+ #endif
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#include <video/fbcon.h>
+-#include <video/fbcon-cfb8.h>
+-#include <video/fbcon-cfb16.h>
+-#include <video/fbcon-cfb24.h>
+-#include <video/fbcon-cfb32.h>
+-#endif
+-
+ #include "sis.h"
+ #include "sis_main.h"
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
+-#error "This version of sisfb requires at least 2.6.3"
+-#endif
+-#endif
+-
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#ifdef FBCON_HAS_CFB8
+-extern struct display_switch fbcon_sis8;
+-#endif
+-#ifdef FBCON_HAS_CFB16
+-extern struct display_switch fbcon_sis16;
+-#endif
+-#ifdef FBCON_HAS_CFB32
+-extern struct display_switch fbcon_sis32;
+-#endif
+-#endif
+-
+ static void sisfb_handle_command(struct sis_video_info *ivideo,
+ struct sisfb_cmd *sisfb_command);
+
+@@ -114,17 +83,7 @@ sisfb_setdefaultparms(void)
+ sisfb_max = -1;
+ sisfb_userom = -1;
+ sisfb_useoem = -1;
+-#ifdef MODULE
+- /* Module: "None" for 2.4, default mode for 2.5+ */
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+- sisfb_mode_idx = -1;
+-#else
+- sisfb_mode_idx = MODE_INDEX_NONE;
+-#endif
+-#else
+- /* Static: Default mode */
+ sisfb_mode_idx = -1;
+-#endif
+ sisfb_parm_rate = -1;
+ sisfb_crt1off = 0;
+ sisfb_forcecrt1 = -1;
+@@ -142,10 +101,6 @@ sisfb_setdefaultparms(void)
+ sisfb_tvxposoffset = 0;
+ sisfb_tvyposoffset = 0;
+ sisfb_nocrt2rate = 0;
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- sisfb_inverse = 0;
+- sisfb_fontname[0] = 0;
+-#endif
+ #if !defined(__i386__) && !defined(__x86_64__)
+ sisfb_resetcard = 0;
+ sisfb_videoram = 0;
+@@ -162,14 +117,11 @@ sisfb_search_vesamode(unsigned int vesam
+ /* We don't know the hardware specs yet and there is no ivideo */
+
+ if(vesamode == 0) {
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- sisfb_mode_idx = MODE_INDEX_NONE;
+-#else
+ if(!quiet)
+ printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
+
+ sisfb_mode_idx = DEFAULT_MODE;
+-#endif
++
+ return;
+ }
+
+@@ -215,7 +167,6 @@ sisfb_search_mode(char *name, BOOLEAN qu
+ return;
+ }
+
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
+ if(!quiet)
+ printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
+@@ -223,7 +174,7 @@ sisfb_search_mode(char *name, BOOLEAN qu
+ sisfb_mode_idx = DEFAULT_MODE;
+ return;
+ }
+-#endif
++
+ if(strlen(name) <= 19) {
+ strcpy(strbuf1, name);
+ for(i = 0; i < strlen(strbuf1); i++) {
+@@ -1315,20 +1266,7 @@ sisfb_do_set_var(struct fb_var_screeninf
+ ivideo->refresh_rate = 60;
+ }
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- if(ivideo->sisfb_thismonitor.datavalid) {
+- if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
+- ivideo->rate_idx, ivideo->refresh_rate)) {
+- printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+- }
+- }
+-#endif
+-
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+-#else
+ if(isactive) {
+-#endif
+ /* If acceleration to be used? Need to know
+ * before pre/post_set_mode()
+ */
+@@ -1367,9 +1305,7 @@ sisfb_do_set_var(struct fb_var_screeninf
+ ivideo->current_linelength = ivideo->video_linelength;
+ ivideo->current_pixclock = var->pixclock;
+ ivideo->current_refresh_rate = ivideo->refresh_rate;
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
+-#endif
+ }
+
+ return 0;
+@@ -1435,18 +1371,6 @@ sisfb_pan_var(struct sis_video_info *ivi
+ return 0;
+ }
+
+-/* ------------ FBDev related routines for 2.4 series ----------- */
+-
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-
+-#include "sisfb_fbdev_2_4.h"
+-
+-#endif
+-
+-/* ------------ FBDev related routines for 2.6 series ----------- */
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+-
+ static int
+ sisfb_open(struct fb_info *info, int user)
+ {
+@@ -1744,8 +1668,6 @@ sisfb_blank(int blank, struct fb_info *i
+ return sisfb_myblank(ivideo, blank);
+ }
+
+-#endif
+-
+ /* ----------- FBDev related routines for all series ---------- */
+
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+@@ -1969,20 +1891,6 @@ sisfb_get_fix(struct fb_fix_screeninfo *
+
+ /* ---------------- fb_ops structures ----------------- */
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-static struct fb_ops sisfb_ops = {
+- .owner = THIS_MODULE,
+- .fb_get_fix = sisfb_get_fix,
+- .fb_get_var = sisfb_get_var,
+- .fb_set_var = sisfb_set_var,
+- .fb_get_cmap = sisfb_get_cmap,
+- .fb_set_cmap = sisfb_set_cmap,
+- .fb_pan_display = sisfb_pan_display,
+- .fb_ioctl = sisfb_ioctl
+-};
+-#endif
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ static struct fb_ops sisfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = sisfb_open,
+@@ -2004,7 +1912,6 @@ static struct fb_ops sisfb_ops = {
+ #endif
+ .fb_ioctl = sisfb_ioctl
+ };
+-#endif
+
+ /* ---------------- Chip generation dependent routines ---------------- */
+
+@@ -4100,16 +4007,6 @@ sisfb_setup(char *options)
+ sisfb_search_mode(this_opt + 5, FALSE);
+ } else if(!strnicmp(this_opt, "vesa:", 5)) {
+ sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- } else if(!strnicmp(this_opt, "inverse", 7)) {
+- sisfb_inverse = 1;
+- /* fb_invert_cmaps(); */
+- } else if(!strnicmp(this_opt, "font:", 5)) {
+- if(strlen(this_opt + 5) < 40) {
+- strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
+- sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
+- }
+-#endif
+ } else if(!strnicmp(this_opt, "rate:", 5)) {
+ sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
+ } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
+@@ -5870,17 +5767,9 @@ sisfb_probe(struct pci_dev *pdev, const
+ if(sisfb_off)
+ return -ENXIO;
+
+-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+ sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
+ if(!sis_fb_info)
+ return -ENOMEM;
+-#else
+- sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
+- if(!sis_fb_info)
+- return -ENOMEM;
+- memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
+- sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
+-#endif
+
+ ivideo = (struct sis_video_info *)sis_fb_info->par;
+ ivideo->memyselfandi = sis_fb_info;
+@@ -5970,10 +5859,6 @@ sisfb_probe(struct pci_dev *pdev, const
+ ivideo->tvxpos = sisfb_tvxposoffset;
+ ivideo->tvypos = sisfb_tvyposoffset;
+ ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+- ivideo->sisfb_inverse = sisfb_inverse;
+-#endif
+-
+ ivideo->refresh_rate = 0;
+ if(ivideo->sisfb_parm_rate != -1) {
+ ivideo->refresh_rate = ivideo->sisfb_parm_rate;
+@@ -6049,10 +5934,6 @@ sisfb_probe(struct pci_dev *pdev, const
+ }
+ }
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- strcpy(sis_fb_info->modename, ivideo->myid);
+-#endif
+-
+ ivideo->SiS_Pr.ChipType = ivideo->chip;
+
+ ivideo->SiS_Pr.ivideo = (void *)ivideo;
+@@ -6134,20 +6015,6 @@ sisfb_probe(struct pci_dev *pdev, const
+ #endif
+ }
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-#ifdef MODULE
+- if((reg & 0x80) && (reg != 0xff)) {
+- if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
+- != 0xFF) {
+- printk(KERN_INFO "sisfb: Cannot initialize display mode, "
+- "X server is active\n");
+- ret = -EBUSY;
+- goto error_4;
+- }
+- }
+-#endif
+-#endif
+-
+ /* Search and copy ROM image */
+ ivideo->bios_abase = NULL;
+ ivideo->SiS_Pr.VirtualRomBase = NULL;
+@@ -6281,9 +6148,6 @@ error_0: iounmap(ivideo->video_vbase);
+ error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
+ error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+ error_3: vfree(ivideo->bios_abase);
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-error_4:
+-#endif
+ if(ivideo->lpcdev)
+ SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+ if(ivideo->nbridge)
+@@ -6586,7 +6450,6 @@ error_4:
+ sis_fb_info->fix = ivideo->sisfb_fix;
+ sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
+ sis_fb_info->fbops = &sisfb_ops;
+-
+ sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
+ sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
+
+@@ -6603,10 +6466,6 @@ error_4:
+ }
+ #endif
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- vc_resize_con(1, 1, 0);
+-#endif
+-
+ if(register_framebuffer(sis_fb_info) < 0) {
+ printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
+ ret = -EINVAL;
+@@ -6653,12 +6512,7 @@ error_4:
+
+
+ printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- GET_FB_IDX(sis_fb_info->node),
+-#else
+- sis_fb_info->node,
+-#endif
+- ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
++ sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+
+ printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
+
+@@ -6732,11 +6586,7 @@ static void __devexit sisfb_remove(struc
+ /* Unregister the framebuffer */
+ if(ivideo->registered) {
+ unregister_framebuffer(sis_fb_info);
+-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+ framebuffer_release(sis_fb_info);
+-#else
+- kfree(sis_fb_info);
+-#endif
+ }
+
+ /* OK, our ivideo is gone for good from here. */
+@@ -6762,7 +6612,6 @@ static struct pci_driver sisfb_driver =
+
+ SISINITSTATIC int __init sisfb_init(void)
+ {
+-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+ #ifndef MODULE
+ char *options = NULL;
+
+@@ -6771,15 +6620,12 @@ SISINITSTATIC int __init sisfb_init(void
+
+ sisfb_setup(options);
+ #endif
+-#endif
+ return pci_register_driver(&sisfb_driver);
+ }
+
+-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+ #ifndef MODULE
+ module_init(sisfb_init);
+ #endif
+-#endif
+
+ /*****************************************************/
+ /* MODULE */
+@@ -6799,9 +6645,6 @@ static int pdc1 = -1;
+ static int noaccel = -1;
+ static int noypan = -1;
+ static int nomax = -1;
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-static int inverse = 0;
+-#endif
+ static int userom = -1;
+ static int useoem = -1;
+ static char *tvstandard = NULL;
+@@ -6861,10 +6704,6 @@ static int __init sisfb_init_module(void
+ else if(nomax == 0)
+ sisfb_max = 1;
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+- if(inverse) sisfb_inverse = 1;
+-#endif
+-
+ if(mem)
+ sisfb_parm_mem = mem;
+
+@@ -6913,35 +6752,6 @@ MODULE_DESCRIPTION("SiS 300/540/630/730/
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Thomas Winischhofer <thomas at winischhofer.net>, Others");
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-MODULE_PARM(mem, "i");
+-MODULE_PARM(noaccel, "i");
+-MODULE_PARM(noypan, "i");
+-MODULE_PARM(nomax, "i");
+-MODULE_PARM(userom, "i");
+-MODULE_PARM(useoem, "i");
+-MODULE_PARM(mode, "s");
+-MODULE_PARM(vesa, "i");
+-MODULE_PARM(rate, "i");
+-MODULE_PARM(forcecrt1, "i");
+-MODULE_PARM(forcecrt2type, "s");
+-MODULE_PARM(scalelcd, "i");
+-MODULE_PARM(pdc, "i");
+-MODULE_PARM(pdc1, "i");
+-MODULE_PARM(specialtiming, "s");
+-MODULE_PARM(lvdshl, "i");
+-MODULE_PARM(tvstandard, "s");
+-MODULE_PARM(tvxposoffset, "i");
+-MODULE_PARM(tvyposoffset, "i");
+-MODULE_PARM(nocrt2rate, "i");
+-MODULE_PARM(inverse, "i");
+-#if !defined(__i386__) && !defined(__x86_64__)
+-MODULE_PARM(resetcard, "i");
+-MODULE_PARM(videoram, "i");
+-#endif
+-#endif
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ module_param(mem, int, 0);
+ module_param(noaccel, int, 0);
+ module_param(noypan, int, 0);
+@@ -6966,18 +6776,7 @@ module_param(nocrt2rate, int, 0);
+ module_param(resetcard, int, 0);
+ module_param(videoram, int, 0);
+ #endif
+-#endif
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-MODULE_PARM_DESC(mem,
+- "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+- "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+- "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
+- "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+- "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
+- "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
+- "for XFree86 4.x/X.org 6.7 and later.\n");
+-#else
+ MODULE_PARM_DESC(mem,
+ "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+ "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+@@ -6985,7 +6784,6 @@ MODULE_PARM_DESC(mem,
+ "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+ "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
+ "The value is to be specified without 'KB'.\n");
+-#endif
+
+ MODULE_PARM_DESC(noaccel,
+ "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
+@@ -7002,23 +6800,6 @@ MODULE_PARM_DESC(nomax,
+ "enable the user to positively specify a virtual Y size of the screen using\n"
+ "fbset. (default: 0)\n");
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-MODULE_PARM_DESC(mode,
+- "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+- "1024x768x16. Other formats supported include XxY-Depth and\n"
+- "XxY-Depth at Rate. If the parameter is only one (decimal or hexadecimal)\n"
+- "number, it will be interpreted as a VESA mode number. (default: none if\n"
+- "sisfb is a module; this leaves the console untouched and the driver will\n"
+- "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
+- "is in the kernel)\n");
+-MODULE_PARM_DESC(vesa,
+- "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+- "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+- "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+- "0x0103 if sisfb is in the kernel)\n");
+-#endif
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ MODULE_PARM_DESC(mode,
+ "\nSelects the desired default display mode in the format XxYxDepth,\n"
+ "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
+@@ -7028,7 +6809,6 @@ MODULE_PARM_DESC(mode,
+ MODULE_PARM_DESC(vesa,
+ "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
+ "0x117 (default: 0x0103)\n");
+-#endif
+
+ MODULE_PARM_DESC(rate,
+ "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
+@@ -7094,12 +6874,6 @@ MODULE_PARM_DESC(nocrt2rate,
+ "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
+ "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-MODULE_PARM_DESC(inverse,
+- "\nSetting this to anything but 0 should invert the display colors, but this\n"
+- "does not seem to work. (default: 0)\n");
+-#endif
+-
+ #if !defined(__i386__) && !defined(__x86_64__)
+ #ifdef CONFIG_FB_SIS_300
+ MODULE_PARM_DESC(resetcard,
+diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
+index 70b6df3..88e4f1e 100644
+--- a/drivers/video/sis/sis_main.h
++++ b/drivers/video/sis/sis_main.h
+@@ -67,15 +67,7 @@ static int sisfb_ypan = -1;
+ static int sisfb_max = -1;
+ static int sisfb_userom = 1;
+ static int sisfb_useoem = -1;
+-#ifdef MODULE
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+-static int sisfb_mode_idx = -1;
+-#else
+-static int sisfb_mode_idx = MODE_INDEX_NONE; /* Don't use a mode by default if we are a module */
+-#endif
+-#else
+ static int sisfb_mode_idx = -1; /* Use a default mode if we are inside the kernel */
+-#endif
+ static int sisfb_parm_rate = -1;
+ static int sisfb_crt1off = 0;
+ static int sisfb_forcecrt1 = -1;
+@@ -93,10 +85,6 @@ static int sisfb_tvstd = -1;
+ static int sisfb_tvxposoffset = 0;
+ static int sisfb_tvyposoffset = 0;
+ static int sisfb_nocrt2rate = 0;
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-static int sisfb_inverse = 0;
+-static char sisfb_fontname[40];
+-#endif
+ #if !defined(__i386__) && !defined(__x86_64__)
+ static int sisfb_resetcard = 0;
+ static int sisfb_videoram = 0;
+@@ -687,54 +675,8 @@ SISINITSTATIC int sisfb_init(void);
+ static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-static int sisfb_get_fix(struct fb_fix_screeninfo *fix,
+- int con,
+- struct fb_info *info);
+-static int sisfb_get_var(struct fb_var_screeninfo *var,
+- int con,
+- struct fb_info *info);
+-static int sisfb_set_var(struct fb_var_screeninfo *var,
+- int con,
+- struct fb_info *info);
+-static void sisfb_crtc_to_var(struct sis_video_info *ivideo,
+- struct fb_var_screeninfo *var);
+-static int sisfb_get_cmap(struct fb_cmap *cmap,
+- int kspc,
+- int con,
+- struct fb_info *info);
+-static int sisfb_set_cmap(struct fb_cmap *cmap,
+- int kspc,
+- int con,
+- struct fb_info *info);
+-static int sisfb_update_var(int con,
+- struct fb_info *info);
+-static int sisfb_switch(int con,
+- struct fb_info *info);
+-static void sisfb_blank(int blank,
+- struct fb_info *info);
+-static void sisfb_set_disp(int con,
+- struct fb_var_screeninfo *var,
+- struct fb_info *info);
+-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+- unsigned *blue, unsigned *transp,
+- struct fb_info *fb_info);
+-static void sisfb_do_install_cmap(int con,
+- struct fb_info *info);
+-static int sisfb_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg, int con,
+- struct fb_info *info);
+-#endif
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+ static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+-#else
+-static int sisfb_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg,
+- struct fb_info *info);
+-#endif
+ static int sisfb_set_par(struct fb_info *info);
+ static int sisfb_blank(int blank,
+ struct fb_info *info);
+@@ -743,7 +685,6 @@ extern void fbcon_sis_fillrect(struct fb
+ extern void fbcon_sis_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area);
+ extern int fbcon_sis_sync(struct fb_info *info);
+-#endif
+
+ /* Internal 2D accelerator functions */
+ extern int sisfb_initaccel(struct sis_video_info *ivideo);
+@@ -811,16 +752,10 @@ extern BOOLEAN SiSDetermineROMLayout661
+
+ extern BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ int *htotal, int *vtotal, unsigned char rateindex);
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ extern int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
+ unsigned char modeno, unsigned char rateindex);
+ extern int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ unsigned char rateindex, struct fb_var_screeninfo *var);
+-#endif
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+-extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
+- int yres, struct fb_var_screeninfo *var, BOOLEAN writeres);
+-#endif
+
+ /* Chrontel TV, DDC and DPMS functions */
+ extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg);
+diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
+index 831b9f4..05d08b7 100644
+--- a/drivers/video/sis/vgatypes.h
++++ b/drivers/video/sis/vgatypes.h
+@@ -73,12 +73,10 @@ typedef unsigned int BOOLEAN;
+
+ #ifdef SIS_LINUX_KERNEL
+ typedef unsigned long SISIOADDRESS;
+-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+ #include <linux/types.h> /* Need __iomem */
+ #undef SISIOMEMTYPE
+ #define SISIOMEMTYPE __iomem
+ #endif
+-#endif
+
+ #ifdef SIS_XORG_XF86
+ #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
+diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
+index dad54e7..711cb11 100644
+--- a/drivers/video/sstfb.c
++++ b/drivers/video/sstfb.c
+@@ -17,7 +17,10 @@
+ * (port driver to new frambuffer infrastructure)
+ * 01/2003 Helge Deller <deller at gmx.de>
+ * (initial work on fb hardware acceleration for voodoo2)
+- *
++ * 08/2006 Alan Cox <alan at redhat.com>
++ * Remove never finished and bogus 24/32bit support
++ * Clean up macro abuse
++ * Minor tidying for format.
+ */
+
+ /*
+@@ -40,6 +43,7 @@
+ through the fifo. warning: issuing a nop command seems to need pci_fifo
+ -FIXME: in case of failure in the init sequence, be sure we return to a safe
+ state.
++- FIXME: Use accelerator for 2D scroll
+ -FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20)
+ */
+
+@@ -67,9 +71,6 @@
+
+ #undef SST_DEBUG
+
+-/* enable 24/32 bpp functions ? (completely untested!) */
+-#undef EN_24_32_BPP
+-
+ /*
+ Default video mode .
+ 0 800x600 at 60 took from glide
+@@ -377,7 +378,11 @@ static void sstfb_clear_screen(struct fb
+ * sstfb_check_var - Optional function. Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
++ *
++ * Limit to the abilities of a single chip as SLI is not supported
++ * by this driver.
+ */
++
+ static int sstfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+ {
+@@ -390,7 +395,7 @@ static int sstfb_check_var(struct fb_var
+ unsigned int freq;
+
+ if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) {
+- eprintk("Pixclock at %ld KHZ out of range\n",
++ printk(KERN_ERR "sstfb: Pixclock at %ld KHZ out of range\n",
+ PICOS2KHZ(var->pixclock));
+ return -EINVAL;
+ }
+@@ -409,27 +414,15 @@ static int sstfb_check_var(struct fb_var
+ case 0 ... 16 :
+ var->bits_per_pixel = 16;
+ break;
+-#ifdef EN_24_32_BPP
+- case 17 ... 24 :
+- var->bits_per_pixel = 24;
+- break;
+- case 25 ... 32 :
+- var->bits_per_pixel = 32;
+- break;
+-#endif
+ default :
+- eprintk("Unsupported bpp %d\n", var->bits_per_pixel);
++ printk(KERN_ERR "sstfb: Unsupported bpp %d\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* validity tests */
+- if ((var->xres <= 1) || (yDim <= 0 )
+- || (var->hsync_len <= 1)
+- || (hSyncOff <= 1)
+- || (var->left_margin <= 2)
+- || (vSyncOn <= 0)
+- || (vSyncOff <= 0)
+- || (vBackPorch <= 0)) {
++ if (var->xres <= 1 || yDim <= 0 || var->hsync_len <= 1 ||
++ hSyncOff <= 1 || var->left_margin <= 2 || vSyncOn <= 0 ||
++ vSyncOff <= 0 || vBackPorch <= 0) {
+ return -EINVAL;
+ }
+
+@@ -437,21 +430,17 @@ static int sstfb_check_var(struct fb_var
+ /* Voodoo 2 limits */
+ tiles_in_X = (var->xres + 63 ) / 64 * 2;
+
+- if (((var->xres - 1) >= POW2(11)) || (yDim >= POW2(11))) {
+- eprintk("Unsupported resolution %dx%d\n",
++ if (var->xres > POW2(11) || yDim >= POW2(11)) {
++ printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n",
+ var->xres, var->yres);
+ return -EINVAL;
+ }
+
+- if (((var->hsync_len-1) >= POW2(9))
+- || ((hSyncOff-1) >= POW2(11))
+- || ((var->left_margin - 2) >= POW2(9))
+- || (vSyncOn >= POW2(13))
+- || (vSyncOff >= POW2(13))
+- || (vBackPorch >= POW2(9))
+- || (tiles_in_X >= POW2(6))
+- || (tiles_in_X <= 0)) {
+- eprintk("Unsupported Timings\n");
++ if (var->hsync_len > POW2(9) || hSyncOff > POW2(11) ||
++ var->left_margin - 2 >= POW2(9) || vSyncOn >= POW2(13) ||
++ vSyncOff >= POW2(13) || vBackPorch >= POW2(9) ||
++ tiles_in_X >= POW2(6) || tiles_in_X <= 0) {
++ printk(KERN_ERR "sstfb: Unsupported timings\n");
+ return -EINVAL;
+ }
+ } else {
+@@ -459,24 +448,20 @@ static int sstfb_check_var(struct fb_var
+ tiles_in_X = (var->xres + 63 ) / 64;
+
+ if (var->vmode) {
+- eprintk("Interlace/Doublescan not supported %#x\n",
++ printk(KERN_ERR "sstfb: Interlace/doublescan not supported %#x\n",
+ var->vmode);
+ return -EINVAL;
+ }
+- if (((var->xres - 1) >= POW2(10)) || (var->yres >= POW2(10))) {
+- eprintk("Unsupported resolution %dx%d\n",
++ if (var->xres > POW2(10) || var->yres >= POW2(10)) {
++ printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n",
+ var->xres, var->yres);
+ return -EINVAL;
+ }
+- if (((var->hsync_len - 1) >= POW2(8))
+- || ((hSyncOff-1) >= POW2(10))
+- || ((var->left_margin - 2) >= POW2(8))
+- || (vSyncOn >= POW2(12))
+- || (vSyncOff >= POW2(12))
+- || (vBackPorch >= POW2(8))
+- || (tiles_in_X >= POW2(4))
+- || (tiles_in_X <= 0)) {
+- eprintk("Unsupported Timings\n");
++ if (var->hsync_len > POW2(8) || hSyncOff - 1 > POW2(10) ||
++ var->left_margin - 2 >= POW2(8) || vSyncOn >= POW2(12) ||
++ vSyncOff >= POW2(12) || vBackPorch >= POW2(8) ||
++ tiles_in_X >= POW2(4) || tiles_in_X <= 0) {
++ printk(KERN_ERR "sstfb: Unsupported timings\n");
+ return -EINVAL;
+ }
+ }
+@@ -486,8 +471,8 @@ static int sstfb_check_var(struct fb_var
+ real_length = tiles_in_X * (IS_VOODOO2(par) ? 32 : 64 )
+ * ((var->bits_per_pixel == 16) ? 2 : 4);
+
+- if ((real_length * yDim) > info->fix.smem_len) {
+- eprintk("Not enough video memory\n");
++ if (real_length * yDim > info->fix.smem_len) {
++ printk(KERN_ERR "sstfb: Not enough video memory\n");
+ return -ENOMEM;
+ }
+
+@@ -515,20 +500,6 @@ static int sstfb_check_var(struct fb_var
+ var->blue.offset = 0;
+ var->transp.offset = 0;
+ break;
+-#ifdef EN_24_32_BPP
+- case 24: /* RGB 888 LfbMode 4 */
+- case 32: /* ARGB 8888 LfbMode 5 */
+- var->red.length = 8;
+- var->green.length = 8;
+- var->blue.length = 8;
+- var->transp.length = 0;
+-
+- var->red.offset = 16;
+- var->green.offset = 8;
+- var->blue.offset = 0;
+- var->transp.offset = 0; /* in 24bpp we fake a 32 bpp mode */
+- break;
+-#endif
+ default:
+ return -EINVAL;
+ }
+@@ -653,13 +624,6 @@ static int sstfb_set_par(struct fb_info
+ case 16:
+ fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL;
+ break;
+-#ifdef EN_24_32_BPP
+- case 24:
+- case 32:
+- /* sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP);*/
+- fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP;
+- break;
+-#endif
+ default:
+ return -EINVAL;
+ }
+@@ -690,14 +654,6 @@ static int sstfb_set_par(struct fb_info
+ case 16:
+ lfbmode = LFB_565;
+ break;
+-#ifdef EN_24_32_BPP
+- case 24:
+- lfbmode = LFB_888;
+- break;
+- case 32:
+- lfbmode = LFB_8888;
+- break;
+-#endif
+ default:
+ return -EINVAL;
+ }
+@@ -789,8 +745,7 @@ static int sstfb_ioctl(struct fb_info *i
+ return -EFAULT;
+ if (val > info->fix.smem_len)
+ val = info->fix.smem_len;
+- printk("filling %#x \n", val);
+- for (p=0 ; p<val; p+=2)
++ for (p = 0 ; p < val; p += 2)
+ writew(p >> 6, info->screen_base + p);
+ return 0;
+
+@@ -802,13 +757,10 @@ static int sstfb_ioctl(struct fb_info *i
+ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
+ tmp | PCI_EN_INIT_WR );
+ fbiinit0 = sst_read (FBIINIT0);
+- if (val) {
++ if (val)
+ sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH);
+- iprintk("Disabling VGA pass-through\n");
+- } else {
++ else
+ sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH);
+- iprintk("Enabling VGA pass-through\n");
+- }
+ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
+ return 0;
+
+@@ -884,9 +836,9 @@ static int __devinit sst_get_memsize(str
+ u8 __iomem *fbbase_virt = info->screen_base;
+
+ /* force memsize */
+- if ((mem >= 1 ) && (mem <= 4)) {
++ if (mem >= 1 && mem <= 4) {
+ *memsize = (mem * 0x100000);
+- iprintk("supplied memsize: %#x\n", *memsize);
++ printk(KERN_INFO "supplied memsize: %#x\n", *memsize);
+ return 1;
+ }
+
+@@ -927,7 +879,7 @@ static int __devinit sst_detect_att(stru
+ struct sstfb_par *par = info->par;
+ int i, mir, dir;
+
+- for (i=0; i<3; i++) {
++ for (i = 0; i < 3; i++) {
+ sst_dac_write(DACREG_WMA, 0); /* backdoor */
+ sst_dac_read(DACREG_RMR); /* read 4 times RMR */
+ sst_dac_read(DACREG_RMR);
+@@ -940,7 +892,7 @@ static int __devinit sst_detect_att(stru
+ /*the 7th, device ID register */
+ dir = sst_dac_read(DACREG_RMR);
+ f_ddprintk("mir: %#x, dir: %#x\n", mir, dir);
+- if ((mir == DACREG_MIR_ATT ) && (dir == DACREG_DIR_ATT)) {
++ if (mir == DACREG_MIR_ATT && dir == DACREG_DIR_ATT) {
+ return 1;
+ }
+ }
+@@ -1134,12 +1086,6 @@ static void sst_set_vidmod_att_ti(struct
+ case 16:
+ sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP);
+ break;
+-#ifdef EN_24_32_BPP
+- case 24:
+- case 32:
+- sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_24BPP);
+- break;
+-#endif
+ default:
+ dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
+ break;
+@@ -1154,12 +1100,6 @@ static void sst_set_vidmod_ics(struct fb
+ case 16:
+ sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP);
+ break;
+-#ifdef EN_24_32_BPP
+- case 24:
+- case 32:
+- sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_24BPP);
+- break;
+-#endif
+ default:
+ dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
+ break;
+@@ -1250,7 +1190,7 @@ static int __devinit sst_init(struct fb_
+ PCI_EN_INIT_WR | PCI_REMAP_DAC );
+ /* detect dac type */
+ if (!sst_detect_dactype(info, par)) {
+- eprintk("Unknown dac type\n");
++ printk(KERN_ERR "sstfb: unknown dac type.\n");
+ //FIXME watch it: we are not in a safe state, bad bad bad.
+ return 0;
+ }
+@@ -1258,10 +1198,10 @@ static int __devinit sst_init(struct fb_
+ /* set graphic clock */
+ par->gfx_clock = spec->default_gfx_clock;
+ if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
+- iprintk("Using supplied graphic freq : %dMHz\n", gfxclk);
++ printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk);
+ par->gfx_clock = gfxclk *1000;
+ } else if (gfxclk) {
+- wprintk ("%dMhz is way out of spec! Using default\n", gfxclk);
++ printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk);
+ }
+
+ sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings);
+@@ -1396,7 +1336,7 @@ static int __devinit sstfb_probe(struct
+
+ /* Enable device in PCI config. */
+ if ((err=pci_enable_device(pdev))) {
+- eprintk("cannot enable device\n");
++ printk(KERN_ERR "cannot enable device\n");
+ return err;
+ }
+
+@@ -1422,39 +1362,39 @@ static int __devinit sstfb_probe(struct
+ fix->smem_start = fix->mmio_start + 0x400000;
+
+ if (!request_mem_region(fix->mmio_start, fix->mmio_len, "sstfb MMIO")) {
+- eprintk("cannot reserve mmio memory\n");
++ printk(KERN_ERR "sstfb: cannot reserve mmio memory\n");
+ goto fail_mmio_mem;
+ }
+
+ if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) {
+- eprintk("cannot reserve fb memory\n");
++ printk(KERN_ERR "sstfb: cannot reserve fb memory\n");
+ goto fail_fb_mem;
+ }
+
+ par->mmio_vbase = ioremap_nocache(fix->mmio_start,
+ fix->mmio_len);
+ if (!par->mmio_vbase) {
+- eprintk("cannot remap register area %#lx\n",
++ printk(KERN_ERR "sstfb: cannot remap register area %#lx\n",
+ fix->mmio_start);
+ goto fail_mmio_remap;
+ }
+ info->screen_base = ioremap_nocache(fix->smem_start, 0x400000);
+ if (!info->screen_base) {
+- eprintk("cannot remap framebuffer %#lx\n",
++ printk(KERN_ERR "sstfb: cannot remap framebuffer %#lx\n",
+ fix->smem_start);
+ goto fail_fb_remap;
+ }
+
+ if (!sst_init(info, par)) {
+- eprintk("Init failed\n");
++ printk(KERN_ERR "sstfb: Init failed\n");
+ goto fail;
+ }
+ sst_get_memsize(info, &fix->smem_len);
+ strlcpy(fix->id, spec->name, sizeof(fix->id));
+
+- iprintk("%s (revision %d) with %s dac\n",
++ printk(KERN_INFO "%s (revision %d) with %s dac\n",
+ fix->id, par->revision, par->dac_sw.name);
+- iprintk("framebuffer at %#lx, mapped to 0x%p, size %dMB\n",
++ printk(KERN_INFO "framebuffer at %#lx, mapped to 0x%p, size %dMB\n",
+ fix->smem_start, info->screen_base,
+ fix->smem_len >> 20);
+
+@@ -1471,24 +1411,25 @@ static int __devinit sstfb_probe(struct
+ fix->accel = FB_ACCEL_NONE; /* FIXME */
+ /*
+ * According to the specs, the linelength must be of 1024 *pixels*
+- * and the 24bpp mode is in fact a 32 bpp mode.
++ * and the 24bpp mode is in fact a 32 bpp mode (and both are in
++ * fact dithered to 16bit).
+ */
+ fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */
+
+ if ( mode_option &&
+ fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16)) {
+- eprintk("can't set supplied video mode. Using default\n");
++ printk(KERN_ERR "sstfb: can't set supplied video mode. Using default\n");
+ info->var = sstfb_default;
+ } else
+ info->var = sstfb_default;
+
+ if (sstfb_check_var(&info->var, info)) {
+- eprintk("invalid default video mode.\n");
++ printk(KERN_ERR "sstfb: invalid default video mode.\n");
+ goto fail;
+ }
+
+ if (sstfb_set_par(info)) {
+- eprintk("can't set default video mode.\n");
++ printk(KERN_ERR "sstfb: can't set default video mode.\n");
+ goto fail;
+ }
+
+@@ -1497,7 +1438,7 @@ static int __devinit sstfb_probe(struct
+ /* register fb */
+ info->device = &pdev->dev;
+ if (register_framebuffer(info) < 0) {
+- eprintk("can't register framebuffer.\n");
++ printk(KERN_ERR "sstfb: can't register framebuffer.\n");
+ goto fail;
+ }
+
+@@ -1711,4 +1652,3 @@ module_param(gfxclk, int, 0);
+ MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)");
+ module_param(slowpci, bool, 0);
+ MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)");
+-
+diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
+index 47f2792..06fc19a 100644
+--- a/drivers/video/valkyriefb.c
++++ b/drivers/video/valkyriefb.c
+@@ -284,7 +284,7 @@ static void __init valkyrie_choose_mode(
+ printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense);
+
+ /* Try to pick a video mode out of NVRAM if we have one. */
+-#ifndef CONFIG_MAC
++#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
+ if (default_vmode == VMODE_NVRAM) {
+ default_vmode = nvram_read_byte(NV_VMODE);
+ if (default_vmode <= 0
+@@ -297,7 +297,7 @@ static void __init valkyrie_choose_mode(
+ default_vmode = mac_map_monitor_sense(p->sense);
+ if (!valkyrie_reg_init[default_vmode - 1])
+ default_vmode = VMODE_640_480_67;
+-#ifndef CONFIG_MAC
++#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
+ if (default_cmode == CMODE_NVRAM)
+ default_cmode = nvram_read_byte(NV_CMODE);
+ #endif
+diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
+index 8b3d0f0..c287a9a 100644
+--- a/drivers/w1/Kconfig
++++ b/drivers/w1/Kconfig
+@@ -2,7 +2,6 @@ menu "Dallas's 1-wire bus"
+
+ config W1
+ tristate "Dallas's 1-wire support"
+- depends on CONNECTOR
+ ---help---
+ Dallas' 1-wire bus is useful to connect slow 1-pin devices
+ such as iButtons and thermal sensors.
+@@ -21,7 +20,7 @@ config W1_CON
+ There are three types of messages between w1 core and userspace:
+ 1. Events. They are generated each time new master or slave device found
+ either due to automatic or requested search.
+- 2. Userspace commands. Includes read/write and search/alarm search comamnds.
++ 2. Userspace commands. Includes read/write and search/alarm search commands.
+ 3. Replies to userspace commands.
+
+ source drivers/w1/masters/Kconfig
+diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
+index 22f7ccd..0f62804 100644
+--- a/fs/9p/v9fs.c
++++ b/fs/9p/v9fs.c
+@@ -460,8 +460,10 @@ static int __init init_v9fs(void)
+
+ ret = v9fs_mux_global_init();
+ if (!ret)
+- ret = register_filesystem(&v9fs_fs_type);
+-
++ return ret;
++ ret = register_filesystem(&v9fs_fs_type);
++ if (!ret)
++ v9fs_mux_global_exit();
+ return ret;
+ }
+
+diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
+index eae50c9..5241c60 100644
+--- a/fs/9p/vfs_inode.c
++++ b/fs/9p/vfs_inode.c
+@@ -204,7 +204,6 @@ struct inode *v9fs_get_inode(struct supe
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = sb->s_blocksize;
+ inode->i_blocks = 0;
+ inode->i_rdev = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+@@ -234,7 +233,7 @@ struct inode *v9fs_get_inode(struct supe
+ inode->i_op = &v9fs_symlink_inode_operations;
+ break;
+ case S_IFDIR:
+- inode->i_nlink++;
++ inc_nlink(inode);
+ if(v9ses->extended)
+ inode->i_op = &v9fs_dir_inode_operations_ext;
+ else
+@@ -950,9 +949,8 @@ v9fs_stat2inode(struct v9fs_stat *stat,
+
+ inode->i_size = stat->length;
+
+- inode->i_blksize = sb->s_blocksize;
+ inode->i_blocks =
+- (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits;
++ (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ }
+
+ /**
+diff --git a/fs/Kconfig b/fs/Kconfig
+index 3f00a9f..133dcc8 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -4,6 +4,8 @@
+
+ menu "File systems"
+
++if BLOCK
++
+ config EXT2_FS
+ tristate "Second extended fs support"
+ help
+@@ -72,11 +74,11 @@ config EXT3_FS
+ tristate "Ext3 journalling file system support"
+ select JBD
+ help
+- This is the journaling version of the Second extended file system
++ This is the journalling version of the Second extended file system
+ (often called ext3), the de facto standard Linux file system
+ (method to organize files on a storage device) for hard disks.
+
+- The journaling code included in this driver means you do not have
++ The journalling code included in this driver means you do not have
+ to run e2fsck (file system checker) on your file systems after a
+ crash. The journal keeps track of any changes that were being made
+ at the time the system crashed, and can ensure that your file system
+@@ -138,10 +140,77 @@ config EXT3_FS_SECURITY
+ If you are not using a security module that requires using
+ extended attributes for file security labels, say N.
+
++config EXT4DEV_FS
++ tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ select JBD2
++ help
++ Ext4dev is a predecessor filesystem of the next generation
++ extended fs ext4, based on ext3 filesystem code. It will be
++ renamed ext4 fs later, once ext4dev is mature and stabilized.
++
++ Unlike the change from ext2 filesystem to ext3 filesystem,
++ the on-disk format of ext4dev is not the same as ext3 any more:
++ it is based on extent maps and it supports 48-bit physical block
++ numbers. These combined on-disk format changes will allow
++ ext4dev/ext4 to handle more than 16 TB filesystem volumes --
++ a hard limit that ext3 cannot overcome without changing the
++ on-disk format.
++
++ Other than extent maps and 48-bit block numbers, ext4dev also is
++ likely to have other new features such as persistent preallocation,
++ high resolution time stamps, and larger file support etc. These
++ features will be added to ext4dev gradually.
++
++ To compile this file system support as a module, choose M here. The
++ module will be called ext4dev. Be aware, however, that the filesystem
++ of your root partition (the one containing the directory /) cannot
++ be compiled as a module, and so this could be dangerous.
++
++ If unsure, say N.
++
++config EXT4DEV_FS_XATTR
++ bool "Ext4dev extended attributes"
++ depends on EXT4DEV_FS
++ default y
++ help
++ Extended attributes are name:value pairs associated with inodes by
++ the kernel or by users (see the attr(5) manual page, or visit
++ <http://acl.bestbits.at/> for details).
++
++ If unsure, say N.
++
++ You need this for POSIX ACL support on ext4dev/ext4.
++
++config EXT4DEV_FS_POSIX_ACL
++ bool "Ext4dev POSIX Access Control Lists"
++ depends on EXT4DEV_FS_XATTR
++ select FS_POSIX_ACL
++ help
++ POSIX Access Control Lists (ACLs) support permissions for users and
++ groups beyond the owner/group/world scheme.
++
++ To learn more about Access Control Lists, visit the POSIX ACLs for
++ Linux website <http://acl.bestbits.at/>.
++
++ If you don't know what Access Control Lists are, say N
++
++config EXT4DEV_FS_SECURITY
++ bool "Ext4dev Security Labels"
++ depends on EXT4DEV_FS_XATTR
++ help
++ Security labels support alternative access control models
++ implemented by security modules like SELinux. This option
++ enables an extended attribute handler for file security
++ labels in the ext4dev/ext4 filesystem.
++
++ If you are not using a security module that requires using
++ extended attributes for file security labels, say N.
++
+ config JBD
+ tristate
+ help
+- This is a generic journaling layer for block devices. It is
++ This is a generic journalling layer for block devices. It is
+ currently used by the ext3 and OCFS2 file systems, but it could
+ also be used to add journal support to other file systems or block
+ devices such as RAID or LVM.
+@@ -170,18 +239,50 @@ config JBD_DEBUG
+ generated. To turn debugging off again, do
+ "echo 0 > /proc/sys/fs/jbd-debug".
+
++config JBD2
++ tristate
++ help
++ This is a generic journaling layer for block devices that support
++ both 32-bit and 64-bit block numbers. It is currently used by
++ the ext4dev/ext4 filesystem, but it could also be used to add
++ journal support to other file systems or block devices such
++ as RAID or LVM.
++
++ If you are using ext4dev/ext4, you need to say Y here. If you are not
++ using ext4dev/ext4 then you will probably want to say N.
++
++ To compile this device as a module, choose M here. The module will be
++ called jbd2. If you are compiling ext4dev/ext4 into the kernel,
++ you cannot compile this code as a module.
++
++config JBD2_DEBUG
++ bool "JBD2 (ext4dev/ext4) debugging support"
++ depends on JBD2
++ help
++ If you are using the ext4dev/ext4 journaled file system (or
++ potentially any other filesystem/device using JBD2), this option
++ allows you to enable debugging output while the system is running,
++ in order to help track down any problems you are having.
++ By default, the debugging output will be turned off.
++
++ If you select Y here, then you will be able to turn on debugging
++ with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between
++ 1 and 5. The higher the number, the more debugging output is
++ generated. To turn debugging off again, do
++ "echo 0 > /proc/sys/fs/jbd2-debug".
++
+ config FS_MBCACHE
+-# Meta block cache for Extended Attributes (ext2/ext3)
++# Meta block cache for Extended Attributes (ext2/ext3/ext4)
+ tristate
+- depends on EXT2_FS_XATTR || EXT3_FS_XATTR
+- default y if EXT2_FS=y || EXT3_FS=y
+- default m if EXT2_FS=m || EXT3_FS=m
++ depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR
++ default y if EXT2_FS=y || EXT3_FS=y || EXT4DEV_FS=y
++ default m if EXT2_FS=m || EXT3_FS=m || EXT4DEV_FS=m
+
+ config REISERFS_FS
+ tristate "Reiserfs support"
+ help
+ Stores not just filenames but the files themselves in a balanced
+- tree. Uses journaling.
++ tree. Uses journalling.
+
+ Balanced trees are more efficient than traditional file system
+ architectural foundations.
+@@ -323,10 +424,11 @@ config FS_POSIX_ACL
+ default n
+
+ source "fs/xfs/Kconfig"
++source "fs/gfs2/Kconfig"
+
+ config OCFS2_FS
+- tristate "OCFS2 file system support (EXPERIMENTAL)"
+- depends on NET && SYSFS && EXPERIMENTAL
++ tristate "OCFS2 file system support"
++ depends on NET && SYSFS
+ select CONFIGFS_FS
+ select JBD
+ select CRC32
+@@ -399,6 +501,8 @@ config ROMFS_FS
+ If you don't know whether you need it, then you don't need it:
+ answer N.
+
++endif
++
+ config INOTIFY
+ bool "Inotify file change notification support"
+ default y
+@@ -530,6 +634,11 @@ config FUSE_FS
+ If you want to develop a userspace FS, or if you want to use
+ a filesystem based on FUSE, answer Y or M.
+
++config GENERIC_ACL
++ bool
++ select FS_POSIX_ACL
++
++if BLOCK
+ menu "CD-ROM/DVD Filesystems"
+
+ config ISO9660_FS
+@@ -597,7 +706,9 @@ config UDF_NLS
+ depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y)
+
+ endmenu
++endif
+
++if BLOCK
+ menu "DOS/FAT/NT Filesystems"
+
+ config FAT_FS
+@@ -782,6 +893,7 @@ config NTFS_RW
+ It is perfectly safe to say N here.
+
+ endmenu
++endif
+
+ menu "Pseudo filesystems"
+
+@@ -826,6 +938,25 @@ config PROC_VMCORE
+ help
+ Exports the dump image of crashed kernel in ELF format.
+
++config PROC_SYSCTL
++ bool "Sysctl support (/proc/sys)" if EMBEDDED
++ depends on PROC_FS
++ select SYSCTL
++ default y
++ ---help---
++ The sysctl interface provides a means of dynamically changing
++ certain kernel parameters and variables on the fly without requiring
++ a recompile of the kernel or reboot of the system. The primary
++ interface is through /proc/sys. If you say Y here a tree of
++ modifiable sysctl entries will be generated beneath the
++ /proc/sys directory. They are explained in the files
++ in <file:Documentation/sysctl/>. Note that enabling this
++ option will enlarge the kernel by at least 8 KB.
++
++ As it is generally a good thing, you should say Y here unless
++ building a kernel for install/rescue disks or your system is very
++ limited in memory.
++
+ config SYSFS
+ bool "sysfs file system support" if EMBEDDED
+ default y
+@@ -862,6 +993,19 @@ config TMPFS
+
+ See <file:Documentation/filesystems/tmpfs.txt> for details.
+
++config TMPFS_POSIX_ACL
++ bool "Tmpfs POSIX Access Control Lists"
++ depends on TMPFS
++ select GENERIC_ACL
++ help
++ POSIX Access Control Lists (ACLs) support permissions for users and
++ groups beyond the owner/group/world scheme.
++
++ To learn more about Access Control Lists, visit the POSIX ACLs for
++ Linux website <http://acl.bestbits.at/>.
++
++ If you don't know what Access Control Lists are, say N.
++
+ config HUGETLBFS
+ bool "HugeTLB file system support"
+ depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
+@@ -907,7 +1051,7 @@ menu "Miscellaneous filesystems"
+
+ config ADFS_FS
+ tristate "ADFS file system support (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on BLOCK && EXPERIMENTAL
+ help
+ The Acorn Disc Filing System is the standard file system of the
+ RiscOS operating system which runs on Acorn's ARM-based Risc PC
+@@ -935,7 +1079,7 @@ config ADFS_FS_RW
+
+ config AFFS_FS
+ tristate "Amiga FFS file system support (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on BLOCK && EXPERIMENTAL
+ help
+ The Fast File System (FFS) is the common file system used on hard
+ disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y
+@@ -955,9 +1099,21 @@ config AFFS_FS
+ To compile this file system support as a module, choose M here: the
+ module will be called affs. If unsure, say N.
+
++config ECRYPT_FS
++ tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
++ depends on EXPERIMENTAL && KEYS && CRYPTO
++ help
++ Encrypted filesystem that operates on the VFS layer. See
++ <file:Documentation/ecryptfs.txt> to learn more about
++ eCryptfs. Userspace components are required and can be
++ obtained from <http://ecryptfs.sf.net>.
++
++ To compile this file system support as a module, choose M here: the
++ module will be called ecryptfs.
++
+ config HFS_FS
+ tristate "Apple Macintosh file system support (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on BLOCK && EXPERIMENTAL
+ select NLS
+ help
+ If you say Y here, you will be able to mount Macintosh-formatted
+@@ -970,6 +1126,7 @@ config HFS_FS
+
+ config HFSPLUS_FS
+ tristate "Apple Extended HFS file system support"
++ depends on BLOCK
+ select NLS
+ select NLS_UTF8
+ help
+@@ -983,7 +1140,7 @@ config HFSPLUS_FS
+
+ config BEFS_FS
+ tristate "BeOS file system (BeFS) support (read only) (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on BLOCK && EXPERIMENTAL
+ select NLS
+ help
+ The BeOS File System (BeFS) is the native file system of Be, Inc's
+@@ -991,7 +1148,7 @@ config BEFS_FS
+ on files and directories, and database-like indeces on selected
+ attributes. (Also note that this driver doesn't make those features
+ available at this time). It is a 64 bit filesystem, so it supports
+- extremly large volumes and files.
++ extremely large volumes and files.
+
+ If you use this filesystem, you should also say Y to at least one
+ of the NLS (native language support) options below.
+@@ -1010,7 +1167,7 @@ config BEFS_DEBUG
+
+ config BFS_FS
+ tristate "BFS file system support (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on BLOCK && EXPERIMENTAL
+ help
+ Boot File System (BFS) is a file system used under SCO UnixWare to
+ allow the bootloader access to the kernel image and other important
+@@ -1032,7 +1189,7 @@ config BFS_FS
+
+ config EFS_FS
+ tristate "EFS file system support (read only) (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on BLOCK && EXPERIMENTAL
+ help
+ EFS is an older file system used for non-ISO9660 CD-ROMs and hard
+ disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer
+@@ -1047,9 +1204,9 @@ config EFS_FS
+
+ config JFFS_FS
+ tristate "Journalling Flash File System (JFFS) support"
+- depends on MTD
++ depends on MTD && BLOCK
+ help
+- JFFS is the Journaling Flash File System developed by Axis
++ JFFS is the Journalling Flash File System developed by Axis
+ Communications in Sweden, aimed at providing a crash/powerdown-safe
+ file system for disk-less embedded devices. Further information is
+ available at (<http://developer.axis.com/software/jffs/>).
+@@ -1219,7 +1376,7 @@ config JFFS2_CMODE_NONE
+ config JFFS2_CMODE_PRIORITY
+ bool "priority"
+ help
+- Tries the compressors in a predefinied order and chooses the first
++ Tries the compressors in a predefined order and chooses the first
+ successful one.
+
+ config JFFS2_CMODE_SIZE
+@@ -1232,6 +1389,7 @@ endchoice
+
+ config CRAMFS
+ tristate "Compressed ROM file system support (cramfs)"
++ depends on BLOCK
+ select ZLIB_INFLATE
+ help
+ Saying Y here includes support for CramFs (Compressed ROM File
+@@ -1251,6 +1409,7 @@ config CRAMFS
+
+ config VXFS_FS
+ tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
++ depends on BLOCK
+ help
+ FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
+ file system format. VERITAS VxFS(TM) is the standard file system
+@@ -1268,6 +1427,7 @@ config VXFS_FS
+
+ config HPFS_FS
+ tristate "OS/2 HPFS file system support"
++ depends on BLOCK
+ help
+ OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
+ is the file system used for organizing files on OS/2 hard disk
+@@ -1284,6 +1444,7 @@ config HPFS_FS
+
+ config QNX4FS_FS
+ tristate "QNX4 file system support (read only)"
++ depends on BLOCK
+ help
+ This is the file system used by the real-time operating systems
+ QNX 4 and QNX 6 (the latter is also called QNX RTP).
+@@ -1311,6 +1472,7 @@ config QNX4FS_RW
+
+ config SYSV_FS
+ tristate "System V/Xenix/V7/Coherent file system support"
++ depends on BLOCK
+ help
+ SCO, Xenix and Coherent are commercial Unix systems for Intel
+ machines, and Version 7 was used on the DEC PDP-11. Saying Y
+@@ -1319,7 +1481,7 @@ config SYSV_FS
+
+ If you have floppies or hard disk partitions like that, it is likely
+ that they contain binaries from those other Unix systems; in order
+- to run these binaries, you will want to install linux-abi which is a
++ to run these binaries, you will want to install linux-abi which is
+ a set of kernel modules that lets you run SCO, Xenix, Wyse,
+ UnixWare, Dell Unix and System V programs under Linux. It is
+ available via FTP (user: ftp) from
+@@ -1349,6 +1511,7 @@ config SYSV_FS
+
+ config UFS_FS
+ tristate "UFS file system support (read only)"
++ depends on BLOCK
+ help
+ BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
+ OpenBSD and NeXTstep) use a file system called UFS. Some System V
+@@ -1471,8 +1634,8 @@ config NFS_V4
+ If unsure, say N.
+
+ config NFS_DIRECTIO
+- bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
+- depends on NFS_FS && EXPERIMENTAL
++ bool "Allow direct I/O on NFS files"
++ depends on NFS_FS
+ help
+ This option enables applications to perform uncached I/O on files
+ in NFS file systems using the O_DIRECT open() flag. When O_DIRECT
+@@ -1614,6 +1777,7 @@ config RPCSEC_GSS_KRB5
+ select CRYPTO
+ select CRYPTO_MD5
+ select CRYPTO_DES
++ select CRYPTO_CBC
+ help
+ Provides for secure RPC calls by means of a gss-api
+ mechanism based on Kerberos V5. This is required for
+@@ -1632,6 +1796,7 @@ config RPCSEC_GSS_SPKM3
+ select CRYPTO_MD5
+ select CRYPTO_DES
+ select CRYPTO_CAST5
++ select CRYPTO_CBC
+ help
+ Provides for secure RPC calls by means of a gss-api
+ mechanism based on the SPKM3 public-key mechanism.
+@@ -1827,7 +1992,7 @@ config CIFS_EXPERIMENTAL
+ config CIFS_UPCALL
+ bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
+ depends on CIFS_EXPERIMENTAL
+- select CONNECTOR
++ depends on CONNECTOR
+ help
+ Enables an upcall mechanism for CIFS which will be used to contact
+ userspace helper utilities to provide SPNEGO packaged Kerberos
+@@ -1903,7 +2068,7 @@ config AFS_FS
+ If you say Y here, you will get an experimental Andrew File System
+ driver. It currently only supports unsecured read-only AFS access.
+
+- See <file:Documentation/filesystems/afs.txt> for more intormation.
++ See <file:Documentation/filesystems/afs.txt> for more information.
+
+ If unsure, say N.
+
+@@ -1923,13 +2088,16 @@ config 9P_FS
+
+ endmenu
+
++if BLOCK
+ menu "Partition Types"
+
+ source "fs/partitions/Kconfig"
+
+ endmenu
++endif
+
+ source "fs/nls/Kconfig"
++source "fs/dlm/Kconfig"
+
+ endmenu
+
+diff --git a/fs/Makefile b/fs/Makefile
+index 8913542..9a5ce93 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -5,12 +5,18 @@
+ # Rewritten to use lists instead of if-statements.
+ #
+
+-obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
+- block_dev.o char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
++obj-y := open.o read_write.o file_table.o super.o \
++ char_dev.o stat.o exec.o pipe.o namei.o fcntl.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 pnode.o drop_caches.o splice.o sync.o
++ seq_file.o xattr.o libfs.o fs-writeback.o \
++ pnode.o drop_caches.o splice.o sync.o utimes.o
++
++ifeq ($(CONFIG_BLOCK),y)
++obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
++else
++obj-y += no-block.o
++endif
+
+ obj-$(CONFIG_INOTIFY) += inotify.o
+ obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
+@@ -35,6 +41,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat
+ obj-$(CONFIG_FS_MBCACHE) += mbcache.o
+ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
+ obj-$(CONFIG_NFS_COMMON) += nfs_common/
++obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
+
+ obj-$(CONFIG_QUOTA) += dquot.o
+ obj-$(CONFIG_QFMT_V1) += quota_v1.o
+@@ -50,11 +57,14 @@ obj-$(CONFIG_CONFIGFS_FS) += configfs/
+ obj-y += devpts/
+
+ obj-$(CONFIG_PROFILING) += dcookies.o
++obj-$(CONFIG_DLM) += dlm/
+
+ # Do not add any filesystems before this line
+ obj-$(CONFIG_REISERFS_FS) += reiserfs/
+ obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3
++obj-$(CONFIG_EXT4DEV_FS) += ext4/ # Before ext2 so root fs can be ext4dev
+ obj-$(CONFIG_JBD) += jbd/
++obj-$(CONFIG_JBD2) += jbd2/
+ obj-$(CONFIG_EXT2_FS) += ext2/
+ obj-$(CONFIG_CRAMFS) += cramfs/
+ obj-$(CONFIG_RAMFS) += ramfs/
+@@ -68,6 +78,7 @@ obj-$(CONFIG_BFS_FS) += bfs/
+ obj-$(CONFIG_ISO9660_FS) += isofs/
+ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+
+ obj-$(CONFIG_HFS_FS) += hfs/
++obj-$(CONFIG_ECRYPT_FS) += ecryptfs/
+ obj-$(CONFIG_VXFS_FS) += freevxfs/
+ obj-$(CONFIG_NFS_FS) += nfs/
+ obj-$(CONFIG_EXPORTFS) += exportfs/
+@@ -102,3 +113,4 @@ obj-$(CONFIG_HOSTFS) += hostfs/
+ obj-$(CONFIG_HPPFS) += hppfs/
+ obj-$(CONFIG_DEBUG_FS) += debugfs/
+ obj-$(CONFIG_OCFS2_FS) += ocfs2/
++obj-$(CONFIG_GFS2_FS) += gfs2/
+diff --git a/fs/adfs/file.c b/fs/adfs/file.c
+index 1014b9f..6101ea6 100644
+--- a/fs/adfs/file.c
++++ b/fs/adfs/file.c
+@@ -27,10 +27,12 @@
+
+ const struct file_operations adfs_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
+ .mmap = generic_file_mmap,
+ .fsync = file_fsync,
+- .write = generic_file_write,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .sendfile = generic_file_sendfile,
+ };
+
+diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
+index 534f3ee..7e7a04b 100644
+--- a/fs/adfs/inode.c
++++ b/fs/adfs/inode.c
+@@ -269,7 +269,6 @@ adfs_iget(struct super_block *sb, struct
+ inode->i_ino = obj->file_id;
+ inode->i_size = obj->size;
+ inode->i_nlink = 2;
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >>
+ sb->s_blocksize_bits;
+
+diff --git a/fs/adfs/super.c b/fs/adfs/super.c
+index 8201101..9ade139 100644
+--- a/fs/adfs/super.c
++++ b/fs/adfs/super.c
+@@ -251,8 +251,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(adfs_inode_cachep))
+- printk(KERN_INFO "adfs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(adfs_inode_cachep);
+ }
+
+ static struct super_operations adfs_sops = {
+@@ -339,11 +338,10 @@ static int adfs_fill_super(struct super_
+
+ sb->s_flags |= MS_NODIRATIME;
+
+- asb = kmalloc(sizeof(*asb), GFP_KERNEL);
++ asb = kzalloc(sizeof(*asb), GFP_KERNEL);
+ if (!asb)
+ return -ENOMEM;
+ sb->s_fs_info = asb;
+- memset(asb, 0, sizeof(*asb));
+
+ /* set default options */
+ asb->s_uid = 0;
+diff --git a/fs/affs/affs.h b/fs/affs/affs.h
+index 0ddd4cc..1dc8438 100644
+--- a/fs/affs/affs.h
++++ b/fs/affs/affs.h
+@@ -1,7 +1,6 @@
+ #include <linux/types.h>
+ #include <linux/fs.h>
+ #include <linux/buffer_head.h>
+-#include <linux/affs_fs.h>
+ #include <linux/amigaffs.h>
+
+ /* AmigaOS allows file names with up to 30 characters length.
+diff --git a/fs/affs/file.c b/fs/affs/file.c
+index 3de8590..05b5e22 100644
+--- a/fs/affs/file.c
++++ b/fs/affs/file.c
+@@ -27,8 +27,10 @@ static int affs_file_release(struct inod
+
+ const struct file_operations affs_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .open = affs_file_open,
+ .release = affs_file_release,
+diff --git a/fs/affs/super.c b/fs/affs/super.c
+index 5200f49..5ea72c3 100644
+--- a/fs/affs/super.c
++++ b/fs/affs/super.c
+@@ -14,6 +14,7 @@
+ #include <linux/init.h>
+ #include <linux/statfs.h>
+ #include <linux/parser.h>
++#include <linux/magic.h>
+ #include "affs.h"
+
+ extern struct timezone sys_tz;
+@@ -108,8 +109,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(affs_inode_cachep))
+- printk(KERN_INFO "affs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(affs_inode_cachep);
+ }
+
+ static struct super_operations affs_sops = {
+@@ -279,11 +279,10 @@ static int affs_fill_super(struct super_
+ sb->s_op = &affs_sops;
+ sb->s_flags |= MS_NODIRATIME;
+
+- sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(*sbi));
+ init_MUTEX(&sbi->s_bmlock);
+
+ if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
+diff --git a/fs/afs/dir.c b/fs/afs/dir.c
+index 2fc9987..a6ec75c 100644
+--- a/fs/afs/dir.c
++++ b/fs/afs/dir.c
+@@ -30,7 +30,7 @@ static int afs_dir_readdir(struct file *
+ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
+ static int afs_d_delete(struct dentry *dentry);
+ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
+- loff_t fpos, ino_t ino, unsigned dtype);
++ loff_t fpos, u64 ino, unsigned dtype);
+
+ const struct file_operations afs_dir_file_operations = {
+ .open = afs_dir_open,
+@@ -211,8 +211,8 @@ static int afs_dir_open(struct inode *in
+ {
+ _enter("{%lu}", inode->i_ino);
+
+- BUG_ON(sizeof(union afs_dir_block) != 2048);
+- BUG_ON(sizeof(union afs_dirent) != 32);
++ BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
++ BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
+
+ if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED)
+ return -ENOENT;
+@@ -409,7 +409,7 @@ static int afs_dir_readdir(struct file *
+ * uniquifier through dtype
+ */
+ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
+- loff_t fpos, ino_t ino, unsigned dtype)
++ loff_t fpos, u64 ino, unsigned dtype)
+ {
+ struct afs_dir_lookup_cookie *cookie = _cookie;
+
+@@ -446,8 +446,8 @@ static struct dentry *afs_dir_lookup(str
+ _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name);
+
+ /* insanity checks first */
+- BUG_ON(sizeof(union afs_dir_block) != 2048);
+- BUG_ON(sizeof(union afs_dirent) != 32);
++ BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
++ BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
+
+ if (dentry->d_name.len > 255) {
+ _leave(" = -ENAMETOOLONG");
+diff --git a/fs/afs/file.c b/fs/afs/file.c
+index 67d6634..2e8c426 100644
+--- a/fs/afs/file.c
++++ b/fs/afs/file.c
+@@ -16,7 +16,6 @@
+ #include <linux/slab.h>
+ #include <linux/fs.h>
+ #include <linux/pagemap.h>
+-#include <linux/buffer_head.h>
+ #include "volume.h"
+ #include "vnode.h"
+ #include <rxrpc/call.h>
+@@ -37,7 +36,6 @@ struct inode_operations afs_file_inode_o
+
+ const struct address_space_operations afs_fs_aops = {
+ .readpage = afs_file_readpage,
+- .sync_page = block_sync_page,
+ .set_page_dirty = __set_page_dirty_nobuffers,
+ .releasepage = afs_file_releasepage,
+ .invalidatepage = afs_file_invalidatepage,
+diff --git a/fs/afs/inode.c b/fs/afs/inode.c
+index 4ebb30a..6f37754 100644
+--- a/fs/afs/inode.c
++++ b/fs/afs/inode.c
+@@ -72,7 +72,6 @@ static int afs_inode_map_status(struct a
+ inode->i_ctime.tv_sec = vnode->status.mtime_server;
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_version = vnode->fid.unique;
+ inode->i_mapping->a_ops = &afs_fs_aops;
+diff --git a/fs/afs/proc.c b/fs/afs/proc.c
+index 101d21b..86463ec 100644
+--- a/fs/afs/proc.c
++++ b/fs/afs/proc.c
+@@ -775,6 +775,7 @@ static int afs_proc_cell_servers_release
+ * first item
+ */
+ static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
++ __acquires(m->private->sv_lock)
+ {
+ struct list_head *_p;
+ struct afs_cell *cell = m->private;
+@@ -823,6 +824,7 @@ static void *afs_proc_cell_servers_next(
+ * clean up after reading from the cells list
+ */
+ static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
++ __releases(p->private->sv_lock)
+ {
+ struct afs_cell *cell = p->private;
+
+diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
+index 331f730..782ee7c 100644
+--- a/fs/afs/vlocation.c
++++ b/fs/afs/vlocation.c
+@@ -281,11 +281,10 @@ int afs_vlocation_lookup(struct afs_cell
+ spin_unlock(&cell->vl_gylock);
+
+ /* not in the cell's in-memory lists - create a new record */
+- vlocation = kmalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
++ vlocation = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
+ if (!vlocation)
+ return -ENOMEM;
+
+- memset(vlocation, 0, sizeof(struct afs_vlocation));
+ atomic_set(&vlocation->usage, 1);
+ INIT_LIST_HEAD(&vlocation->link);
+ rwlock_init(&vlocation->lock);
+diff --git a/fs/afs/volume.c b/fs/afs/volume.c
+index 0ff4b86..768c6db 100644
+--- a/fs/afs/volume.c
++++ b/fs/afs/volume.c
+@@ -186,11 +186,10 @@ int afs_volume_lookup(const char *name,
+ _debug("creating new volume record");
+
+ ret = -ENOMEM;
+- volume = kmalloc(sizeof(struct afs_volume), GFP_KERNEL);
++ volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
+ if (!volume)
+ goto error_up;
+
+- memset(volume, 0, sizeof(struct afs_volume));
+ atomic_set(&volume->usage, 1);
+ volume->type = type;
+ volume->type_force = force;
+diff --git a/fs/aio.c b/fs/aio.c
+index 9506301..9476659 100644
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -15,6 +15,7 @@
+ #include <linux/aio_abi.h>
+ #include <linux/module.h>
+ #include <linux/syscalls.h>
++#include <linux/uio.h>
+
+ #define DEBUG 0
+
+@@ -414,6 +415,7 @@ static struct kiocb fastcall *__aio_get_
+ req->ki_retry = NULL;
+ req->ki_dtor = NULL;
+ req->private = NULL;
++ req->ki_iovec = NULL;
+ INIT_LIST_HEAD(&req->ki_run_list);
+
+ /* Check if the completion queue has enough free space to
+@@ -459,6 +461,8 @@ static inline void really_put_req(struct
+
+ if (req->ki_dtor)
+ req->ki_dtor(req);
++ if (req->ki_iovec != &req->ki_inline_vec)
++ kfree(req->ki_iovec);
+ kmem_cache_free(kiocb_cachep, req);
+ ctx->reqs_active--;
+
+@@ -671,7 +675,7 @@ static ssize_t aio_run_iocb(struct kiocb
+ }
+
+ if (!(iocb->ki_retried & 0xff)) {
+- pr_debug("%ld retry: %d of %d\n", iocb->ki_retried,
++ pr_debug("%ld retry: %zd of %zd\n", iocb->ki_retried,
+ iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
+ }
+
+@@ -1004,7 +1008,7 @@ int fastcall aio_complete(struct kiocb *
+
+ pr_debug("added to ring %p at [%lu]\n", iocb, tail);
+
+- pr_debug("%ld retries: %d of %d\n", iocb->ki_retried,
++ pr_debug("%ld retries: %zd of %zd\n", iocb->ki_retried,
+ iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
+ put_rq:
+ /* everything turned out well, dispose of the aiocb. */
+@@ -1300,63 +1304,63 @@ asmlinkage long sys_io_destroy(aio_conte
+ return -EINVAL;
+ }
+
+-/*
+- * aio_p{read,write} are the default ki_retry methods for
+- * IO_CMD_P{READ,WRITE}. They maintains kiocb retry state around potentially
+- * multiple calls to f_op->aio_read(). They loop around partial progress
+- * instead of returning -EIOCBRETRY because they don't have the means to call
+- * kick_iocb().
+- */
+-static ssize_t aio_pread(struct kiocb *iocb)
++static void aio_advance_iovec(struct kiocb *iocb, ssize_t ret)
+ {
+- struct file *file = iocb->ki_filp;
+- struct address_space *mapping = file->f_mapping;
+- struct inode *inode = mapping->host;
+- ssize_t ret = 0;
+-
+- do {
+- ret = file->f_op->aio_read(iocb, iocb->ki_buf,
+- iocb->ki_left, iocb->ki_pos);
+- /*
+- * Can't just depend on iocb->ki_left to determine
+- * whether we are done. This may have been a short read.
+- */
+- if (ret > 0) {
+- iocb->ki_buf += ret;
+- iocb->ki_left -= ret;
++ struct iovec *iov = &iocb->ki_iovec[iocb->ki_cur_seg];
++
++ BUG_ON(ret <= 0);
++
++ while (iocb->ki_cur_seg < iocb->ki_nr_segs && ret > 0) {
++ ssize_t this = min((ssize_t)iov->iov_len, ret);
++ iov->iov_base += this;
++ iov->iov_len -= this;
++ iocb->ki_left -= this;
++ ret -= this;
++ if (iov->iov_len == 0) {
++ iocb->ki_cur_seg++;
++ iov++;
+ }
++ }
+
+- /*
+- * For pipes and sockets we return once we have some data; for
+- * regular files we retry till we complete the entire read or
+- * find that we can't read any more data (e.g short reads).
+- */
+- } while (ret > 0 && iocb->ki_left > 0 &&
+- !S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode));
+-
+- /* This means we must have transferred all that we could */
+- /* No need to retry anymore */
+- if ((ret == 0) || (iocb->ki_left == 0))
+- ret = iocb->ki_nbytes - iocb->ki_left;
+-
+- return ret;
++ /* the caller should not have done more io than what fit in
++ * the remaining iovecs */
++ BUG_ON(ret > 0 && iocb->ki_left == 0);
+ }
+
+-/* see aio_pread() */
+-static ssize_t aio_pwrite(struct kiocb *iocb)
++static ssize_t aio_rw_vect_retry(struct kiocb *iocb)
+ {
+ struct file *file = iocb->ki_filp;
++ struct address_space *mapping = file->f_mapping;
++ struct inode *inode = mapping->host;
++ ssize_t (*rw_op)(struct kiocb *, const struct iovec *,
++ unsigned long, loff_t);
+ ssize_t ret = 0;
++ unsigned short opcode;
++
++ if ((iocb->ki_opcode == IOCB_CMD_PREADV) ||
++ (iocb->ki_opcode == IOCB_CMD_PREAD)) {
++ rw_op = file->f_op->aio_read;
++ opcode = IOCB_CMD_PREADV;
++ } else {
++ rw_op = file->f_op->aio_write;
++ opcode = IOCB_CMD_PWRITEV;
++ }
+
+ do {
+- ret = file->f_op->aio_write(iocb, iocb->ki_buf,
+- iocb->ki_left, iocb->ki_pos);
+- if (ret > 0) {
+- iocb->ki_buf += ret;
+- iocb->ki_left -= ret;
+- }
+- } while (ret > 0 && iocb->ki_left > 0);
++ ret = rw_op(iocb, &iocb->ki_iovec[iocb->ki_cur_seg],
++ iocb->ki_nr_segs - iocb->ki_cur_seg,
++ iocb->ki_pos);
++ if (ret > 0)
++ aio_advance_iovec(iocb, ret);
++
++ /* retry all partial writes. retry partial reads as long as its a
++ * regular file. */
++ } while (ret > 0 && iocb->ki_left > 0 &&
++ (opcode == IOCB_CMD_PWRITEV ||
++ (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode))));
+
++ /* This means we must have transferred all that we could */
++ /* No need to retry anymore */
+ if ((ret == 0) || (iocb->ki_left == 0))
+ ret = iocb->ki_nbytes - iocb->ki_left;
+
+@@ -1383,6 +1387,38 @@ static ssize_t aio_fsync(struct kiocb *i
+ return ret;
+ }
+
++static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb)
++{
++ ssize_t ret;
++
++ ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf,
++ kiocb->ki_nbytes, 1,
++ &kiocb->ki_inline_vec, &kiocb->ki_iovec);
++ if (ret < 0)
++ goto out;
++
++ kiocb->ki_nr_segs = kiocb->ki_nbytes;
++ kiocb->ki_cur_seg = 0;
++ /* ki_nbytes/left now reflect bytes instead of segs */
++ kiocb->ki_nbytes = ret;
++ kiocb->ki_left = ret;
++
++ ret = 0;
++out:
++ return ret;
++}
++
++static ssize_t aio_setup_single_vector(struct kiocb *kiocb)
++{
++ kiocb->ki_iovec = &kiocb->ki_inline_vec;
++ kiocb->ki_iovec->iov_base = kiocb->ki_buf;
++ kiocb->ki_iovec->iov_len = kiocb->ki_left;
++ kiocb->ki_nr_segs = 1;
++ kiocb->ki_cur_seg = 0;
++ kiocb->ki_nbytes = kiocb->ki_left;
++ return 0;
++}
++
+ /*
+ * aio_setup_iocb:
+ * Performs the initial checks and aio retry method
+@@ -1405,9 +1441,12 @@ static ssize_t aio_setup_iocb(struct kio
+ ret = security_file_permission(file, MAY_READ);
+ if (unlikely(ret))
+ break;
++ ret = aio_setup_single_vector(kiocb);
++ if (ret)
++ break;
+ ret = -EINVAL;
+ if (file->f_op->aio_read)
+- kiocb->ki_retry = aio_pread;
++ kiocb->ki_retry = aio_rw_vect_retry;
+ break;
+ case IOCB_CMD_PWRITE:
+ ret = -EBADF;
+@@ -1420,9 +1459,40 @@ static ssize_t aio_setup_iocb(struct kio
+ ret = security_file_permission(file, MAY_WRITE);
+ if (unlikely(ret))
+ break;
++ ret = aio_setup_single_vector(kiocb);
++ if (ret)
++ break;
++ ret = -EINVAL;
++ if (file->f_op->aio_write)
++ kiocb->ki_retry = aio_rw_vect_retry;
++ break;
++ case IOCB_CMD_PREADV:
++ ret = -EBADF;
++ if (unlikely(!(file->f_mode & FMODE_READ)))
++ break;
++ ret = security_file_permission(file, MAY_READ);
++ if (unlikely(ret))
++ break;
++ ret = aio_setup_vectored_rw(READ, kiocb);
++ if (ret)
++ break;
++ ret = -EINVAL;
++ if (file->f_op->aio_read)
++ kiocb->ki_retry = aio_rw_vect_retry;
++ break;
++ case IOCB_CMD_PWRITEV:
++ ret = -EBADF;
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ break;
++ ret = security_file_permission(file, MAY_WRITE);
++ if (unlikely(ret))
++ break;
++ ret = aio_setup_vectored_rw(WRITE, kiocb);
++ if (ret)
++ break;
+ ret = -EINVAL;
+ if (file->f_op->aio_write)
+- kiocb->ki_retry = aio_pwrite;
++ kiocb->ki_retry = aio_rw_vect_retry;
+ break;
+ case IOCB_CMD_FDSYNC:
+ ret = -EINVAL;
+diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
+index a62327f..906ba5c 100644
+--- a/fs/autofs/autofs_i.h
++++ b/fs/autofs/autofs_i.h
+@@ -37,8 +37,6 @@
+ #define DPRINTK(D) ((void)0)
+ #endif
+
+-#define AUTOFS_SUPER_MAGIC 0x0187
+-
+ /*
+ * If the daemon returns a negative response (AUTOFS_IOC_FAIL) then the
+ * kernel will keep the negative response cached for up to the time given
+@@ -151,6 +149,7 @@ extern const struct file_operations auto
+ /* Initializing function */
+
+ int autofs_fill_super(struct super_block *, void *, int);
++void autofs_kill_sb(struct super_block *sb);
+
+ /* Queue management functions */
+
+diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
+index 3fded38..bf8c8af 100644
+--- a/fs/autofs/dirhash.c
++++ b/fs/autofs/dirhash.c
+@@ -246,5 +246,4 @@ void autofs_hash_nuke(struct autofs_sb_i
+ kfree(ent);
+ }
+ }
+- shrink_dcache_sb(sbi->sb);
+ }
+diff --git a/fs/autofs/init.c b/fs/autofs/init.c
+index aca1237..cea5219 100644
+--- a/fs/autofs/init.c
++++ b/fs/autofs/init.c
+@@ -24,7 +24,7 @@ static struct file_system_type autofs_fs
+ .owner = THIS_MODULE,
+ .name = "autofs",
+ .get_sb = autofs_get_sb,
+- .kill_sb = kill_anon_super,
++ .kill_sb = autofs_kill_sb,
+ };
+
+ static int __init init_autofs_fs(void)
+diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
+index 65e5ed4..54c518c 100644
+--- a/fs/autofs/inode.c
++++ b/fs/autofs/inode.c
+@@ -16,10 +16,11 @@
+ #include <linux/file.h>
+ #include <linux/parser.h>
+ #include <linux/bitops.h>
++#include <linux/magic.h>
+ #include "autofs_i.h"
+ #include <linux/module.h>
+
+-static void autofs_put_super(struct super_block *sb)
++void autofs_kill_sb(struct super_block *sb)
+ {
+ struct autofs_sb_info *sbi = autofs_sbi(sb);
+ unsigned int n;
+@@ -36,13 +37,13 @@ static void autofs_put_super(struct supe
+ kfree(sb->s_fs_info);
+
+ DPRINTK(("autofs: shutting down\n"));
++ kill_anon_super(sb);
+ }
+
+ static void autofs_read_inode(struct inode *inode);
+
+ static struct super_operations autofs_sops = {
+ .read_inode = autofs_read_inode,
+- .put_super = autofs_put_super,
+ .statfs = simple_statfs,
+ };
+
+@@ -128,10 +129,9 @@ int autofs_fill_super(struct super_block
+ struct autofs_sb_info *sbi;
+ int minproto, maxproto;
+
+- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if ( !sbi )
+ goto fail_unlock;
+- memset(sbi, 0, sizeof(*sbi));
+ DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
+
+ s->s_fs_info = sbi;
+@@ -216,7 +216,6 @@ static void autofs_read_inode(struct ino
+ inode->i_nlink = 2;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+- inode->i_blksize = 1024;
+
+ if ( ino == AUTOFS_ROOT_INO ) {
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+@@ -241,7 +240,7 @@ static void autofs_read_inode(struct ino
+
+ inode->i_op = &autofs_symlink_inode_operations;
+ sl = &sbi->symlink[n];
+- inode->u.generic_ip = sl;
++ inode->i_private = sl;
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = sl->mtime;
+ inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0;
+diff --git a/fs/autofs/root.c b/fs/autofs/root.c
+index 9cac08d..368a1c3 100644
+--- a/fs/autofs/root.c
++++ b/fs/autofs/root.c
+@@ -414,7 +414,7 @@ static int autofs_root_rmdir(struct inod
+
+ dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
+ autofs_hash_delete(ent);
+- dir->i_nlink--;
++ drop_nlink(dir);
+ d_drop(dentry);
+ unlock_kernel();
+
+@@ -466,7 +466,7 @@ static int autofs_root_mkdir(struct inod
+ ent->dentry = dentry;
+ autofs_hash_insert(dh,ent);
+
+- dir->i_nlink++;
++ inc_nlink(dir);
+ d_instantiate(dentry, iget(dir->i_sb,ino));
+ unlock_kernel();
+
+diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
+index 52e8772..c74f2eb 100644
+--- a/fs/autofs/symlink.c
++++ b/fs/autofs/symlink.c
+@@ -15,7 +15,7 @@
+ /* Nothing to release.. */
+ static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
+ {
+- char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
++ char *s=((struct autofs_symlink *)dentry->d_inode->i_private)->data;
+ nd_set_link(nd, s);
+ return NULL;
+ }
+diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
+index d6603d0..b13f32c 100644
+--- a/fs/autofs4/autofs_i.h
++++ b/fs/autofs4/autofs_i.h
+@@ -40,8 +40,6 @@
+ #define DPRINTK(fmt,args...) do {} while(0)
+ #endif
+
+-#define AUTOFS_SUPER_MAGIC 0x0187
+-
+ /* Unified info structure. This is pointed to by both the dentry and
+ inode structures. Each file in the filesystem has an instance of this
+ structure. It holds a reference to the dentry, so dentries are never
+@@ -96,7 +94,6 @@ struct autofs_wait_queue {
+
+ struct autofs_sb_info {
+ u32 magic;
+- struct dentry *root;
+ int pipefd;
+ struct file *pipe;
+ pid_t oz_pgrp;
+@@ -231,4 +228,4 @@ out:
+ }
+
+ void autofs4_dentry_release(struct dentry *);
+-
++extern void autofs4_kill_sb(struct super_block *);
+diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
+index 8dbd44f..d96e5c1 100644
+--- a/fs/autofs4/expire.c
++++ b/fs/autofs4/expire.c
+@@ -32,7 +32,7 @@ static inline int autofs4_can_expire(str
+
+ if (!do_now) {
+ /* Too young to die */
+- if (time_after(ino->last_used + timeout, now))
++ if (!timeout || time_after(ino->last_used + timeout, now))
+ return 0;
+
+ /* update last_used here :-
+@@ -253,7 +253,7 @@ static struct dentry *autofs4_expire_dir
+ struct dentry *root = dget(sb->s_root);
+ int do_now = how & AUTOFS_EXP_IMMEDIATE;
+
+- if (!sbi->exp_timeout || !root)
++ if (!root)
+ return NULL;
+
+ now = jiffies;
+@@ -293,7 +293,7 @@ static struct dentry *autofs4_expire_ind
+ int do_now = how & AUTOFS_EXP_IMMEDIATE;
+ int exp_leaves = how & AUTOFS_EXP_LEAVES;
+
+- if ( !sbi->exp_timeout || !root )
++ if (!root)
+ return NULL;
+
+ now = jiffies;
+diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
+index 5d91933..723a1c5 100644
+--- a/fs/autofs4/init.c
++++ b/fs/autofs4/init.c
+@@ -24,7 +24,7 @@ static struct file_system_type autofs_fs
+ .owner = THIS_MODULE,
+ .name = "autofs",
+ .get_sb = autofs_get_sb,
+- .kill_sb = kill_anon_super,
++ .kill_sb = autofs4_kill_sb,
+ };
+
+ static int __init init_autofs4_fs(void)
+diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
+index fde78b1..51fd859 100644
+--- a/fs/autofs4/inode.c
++++ b/fs/autofs4/inode.c
+@@ -19,6 +19,7 @@
+ #include <linux/parser.h>
+ #include <linux/bitops.h>
+ #include <linux/smp_lock.h>
++#include <linux/magic.h>
+ #include "autofs_i.h"
+ #include <linux/module.h>
+
+@@ -95,7 +96,7 @@ void autofs4_free_ino(struct autofs_info
+ */
+ static void autofs4_force_release(struct autofs_sb_info *sbi)
+ {
+- struct dentry *this_parent = sbi->root;
++ struct dentry *this_parent = sbi->sb->s_root;
+ struct list_head *next;
+
+ spin_lock(&dcache_lock);
+@@ -126,7 +127,7 @@ resume:
+ spin_lock(&dcache_lock);
+ }
+
+- if (this_parent != sbi->root) {
++ if (this_parent != sbi->sb->s_root) {
+ struct dentry *dentry = this_parent;
+
+ next = this_parent->d_u.d_child.next;
+@@ -139,15 +140,9 @@ resume:
+ goto resume;
+ }
+ spin_unlock(&dcache_lock);
+-
+- dput(sbi->root);
+- sbi->root = NULL;
+- shrink_dcache_sb(sbi->sb);
+-
+- return;
+ }
+
+-static void autofs4_put_super(struct super_block *sb)
++void autofs4_kill_sb(struct super_block *sb)
+ {
+ struct autofs_sb_info *sbi = autofs4_sbi(sb);
+
+@@ -162,6 +157,7 @@ static void autofs4_put_super(struct sup
+ kfree(sbi);
+
+ DPRINTK("shutting down");
++ kill_anon_super(sb);
+ }
+
+ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
+@@ -188,7 +184,6 @@ static int autofs4_show_options(struct s
+ }
+
+ static struct super_operations autofs4_sops = {
+- .put_super = autofs4_put_super,
+ .statfs = simple_statfs,
+ .show_options = autofs4_show_options,
+ };
+@@ -314,7 +309,6 @@ int autofs4_fill_super(struct super_bloc
+
+ s->s_fs_info = sbi;
+ sbi->magic = AUTOFS_SBI_MAGIC;
+- sbi->root = NULL;
+ sbi->pipefd = -1;
+ sbi->catatonic = 0;
+ sbi->exp_timeout = 0;
+@@ -396,13 +390,6 @@ int autofs4_fill_super(struct super_bloc
+ sbi->pipefd = pipefd;
+
+ /*
+- * Take a reference to the root dentry so we get a chance to
+- * clean up the dentry tree on umount.
+- * See autofs4_force_release.
+- */
+- sbi->root = dget(root);
+-
+- /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ s->s_root = root;
+@@ -446,7 +433,6 @@ struct inode *autofs4_get_inode(struct s
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ }
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+
+diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
+index 5100f98..c149352 100644
+--- a/fs/autofs4/root.c
++++ b/fs/autofs4/root.c
+@@ -137,7 +137,9 @@ static int autofs4_dir_open(struct inode
+ nd.flags = LOOKUP_DIRECTORY;
+ ret = (dentry->d_op->d_revalidate)(dentry, &nd);
+
+- if (!ret) {
++ if (ret <= 0) {
++ if (ret < 0)
++ status = ret;
+ dcache_dir_close(inode, file);
+ goto out;
+ }
+@@ -279,9 +281,6 @@ static int try_to_fill_dentry(struct den
+
+ DPRINTK("mount done status=%d", status);
+
+- if (status && dentry->d_inode)
+- return status; /* Try to get the kernel to invalidate this dentry */
+-
+ /* Turn this into a real negative dentry? */
+ if (status == -ENOENT) {
+ spin_lock(&dentry->d_lock);
+@@ -357,7 +356,7 @@ static void *autofs4_follow_link(struct
+ * don't try to mount it again.
+ */
+ spin_lock(&dcache_lock);
+- if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
++ if (!d_mountpoint(dentry) && __simple_empty(dentry)) {
+ spin_unlock(&dcache_lock);
+
+ status = try_to_fill_dentry(dentry, 0);
+@@ -400,13 +399,23 @@ static int autofs4_revalidate(struct den
+ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
+ int oz_mode = autofs4_oz_mode(sbi);
+ int flags = nd ? nd->flags : 0;
+- int status = 0;
++ int status = 1;
+
+ /* Pending dentry */
+ if (autofs4_ispending(dentry)) {
+- if (!oz_mode)
+- status = try_to_fill_dentry(dentry, flags);
+- return !status;
++ /* The daemon never causes a mount to trigger */
++ if (oz_mode)
++ return 1;
++
++ /*
++ * A zero status is success otherwise we have a
++ * negative error code.
++ */
++ status = try_to_fill_dentry(dentry, flags);
++ if (status == 0)
++ return 1;
++
++ return status;
+ }
+
+ /* Negative dentry.. invalidate if "old" */
+@@ -421,9 +430,19 @@ static int autofs4_revalidate(struct den
+ DPRINTK("dentry=%p %.*s, emptydir",
+ dentry, dentry->d_name.len, dentry->d_name.name);
+ spin_unlock(&dcache_lock);
+- if (!oz_mode)
+- status = try_to_fill_dentry(dentry, flags);
+- return !status;
++ /* The daemon never causes a mount to trigger */
++ if (oz_mode)
++ return 1;
++
++ /*
++ * A zero status is success otherwise we have a
++ * negative error code.
++ */
++ status = try_to_fill_dentry(dentry, flags);
++ if (status == 0)
++ return 1;
++
++ return status;
+ }
+ spin_unlock(&dcache_lock);
+
+@@ -518,6 +537,9 @@ static struct dentry *autofs4_lookup(str
+ return ERR_PTR(-ERESTARTNOINTR);
+ }
+ }
++ spin_lock(&dentry->d_lock);
++ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
++ spin_unlock(&dentry->d_lock);
+ }
+
+ /*
+@@ -616,7 +638,7 @@ static int autofs4_dir_unlink(struct ino
+ dput(ino->dentry);
+
+ dentry->d_inode->i_size = 0;
+- dentry->d_inode->i_nlink = 0;
++ clear_nlink(dentry->d_inode);
+
+ dir->i_mtime = CURRENT_TIME;
+
+@@ -651,10 +673,10 @@ static int autofs4_dir_rmdir(struct inod
+ }
+ dput(ino->dentry);
+ dentry->d_inode->i_size = 0;
+- dentry->d_inode->i_nlink = 0;
++ clear_nlink(dentry->d_inode);
+
+ if (dir->i_nlink)
+- dir->i_nlink--;
++ drop_nlink(dir);
+
+ return 0;
+ }
+@@ -691,7 +713,7 @@ static int autofs4_dir_mkdir(struct inod
+ if (p_ino && dentry->d_parent != dentry)
+ atomic_inc(&p_ino->count);
+ ino->inode = inode;
+- dir->i_nlink++;
++ inc_nlink(dir);
+ dir->i_mtime = CURRENT_TIME;
+
+ return 0;
+diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
+index ce103e7..c0a6c8d 100644
+--- a/fs/autofs4/waitq.c
++++ b/fs/autofs4/waitq.c
+@@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autof
+ fput(sbi->pipe); /* Close the pipe */
+ sbi->pipe = NULL;
+ }
+- shrink_dcache_sb(sbi->sb);
+ }
+
+ static int autofs4_write(struct file *file, const void *addr, int bytes)
+diff --git a/fs/bad_inode.c b/fs/bad_inode.c
+index 80599ae..34e6d7b 100644
+--- a/fs/bad_inode.c
++++ b/fs/bad_inode.c
+@@ -40,8 +40,6 @@ static const struct file_operations bad_
+ .aio_fsync = EIO_ERROR,
+ .fasync = EIO_ERROR,
+ .lock = EIO_ERROR,
+- .readv = EIO_ERROR,
+- .writev = EIO_ERROR,
+ .sendfile = EIO_ERROR,
+ .sendpage = EIO_ERROR,
+ .get_unmapped_area = EIO_ERROR,
+diff --git a/fs/befs/befs.h b/fs/befs/befs.h
+index 057a2c3..d9a40ab 100644
+--- a/fs/befs/befs.h
++++ b/fs/befs/befs.h
+@@ -94,7 +94,7 @@ void befs_debug(const struct super_block
+
+ void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
+ void befs_dump_inode(const struct super_block *sb, befs_inode *);
+-void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
++void befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super *);
+ void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
+ /****************************/
+
+@@ -136,7 +136,7 @@ blockno2iaddr(struct super_block *sb, be
+ static inline unsigned int
+ befs_iaddrs_per_block(struct super_block *sb)
+ {
+- return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
++ return BEFS_SB(sb)->block_size / sizeof (befs_disk_inode_addr);
+ }
+
+ static inline int
+@@ -151,4 +151,6 @@ befs_brun_size(struct super_block *sb, b
+ return BEFS_SB(sb)->block_size * run.len;
+ }
+
++#include "endian.h"
++
+ #endif /* _LINUX_BEFS_H */
+diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h
+index 9095518..e2595c2 100644
+--- a/fs/befs/befs_fs_types.h
++++ b/fs/befs/befs_fs_types.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/linux/befs_fs_types.h
++ * fs/befs/befs_fs_types.h
+ *
+ * Copyright (C) 2001 Will Dyson (will at cs.earlham.edu)
+ *
+@@ -79,17 +79,27 @@ enum inode_flags {
+ * On-Disk datastructures of BeFS
+ */
+
++typedef u64 __bitwise fs64;
++typedef u32 __bitwise fs32;
++typedef u16 __bitwise fs16;
++
+ typedef u64 befs_off_t;
+-typedef u64 befs_time_t;
+-typedef void befs_binode_etc;
++typedef fs64 befs_time_t;
+
+ /* Block runs */
+ typedef struct {
++ fs32 allocation_group;
++ fs16 start;
++ fs16 len;
++} PACKED befs_disk_block_run;
++
++typedef struct {
+ u32 allocation_group;
+ u16 start;
+ u16 len;
+ } PACKED befs_block_run;
+
++typedef befs_disk_block_run befs_disk_inode_addr;
+ typedef befs_block_run befs_inode_addr;
+
+ /*
+@@ -97,31 +107,31 @@ typedef befs_block_run befs_inode_addr;
+ */
+ typedef struct {
+ char name[B_OS_NAME_LENGTH];
+- u32 magic1;
+- u32 fs_byte_order;
++ fs32 magic1;
++ fs32 fs_byte_order;
+
+- u32 block_size;
+- u32 block_shift;
++ fs32 block_size;
++ fs32 block_shift;
+
+- befs_off_t num_blocks;
+- befs_off_t used_blocks;
++ fs64 num_blocks;
++ fs64 used_blocks;
+
+- u32 inode_size;
++ fs32 inode_size;
+
+- u32 magic2;
+- u32 blocks_per_ag;
+- u32 ag_shift;
+- u32 num_ags;
++ fs32 magic2;
++ fs32 blocks_per_ag;
++ fs32 ag_shift;
++ fs32 num_ags;
+
+- u32 flags;
++ fs32 flags;
+
+- befs_block_run log_blocks;
+- befs_off_t log_start;
+- befs_off_t log_end;
++ befs_disk_block_run log_blocks;
++ fs64 log_start;
++ fs64 log_end;
+
+- u32 magic3;
+- befs_inode_addr root_dir;
+- befs_inode_addr indices;
++ fs32 magic3;
++ befs_disk_inode_addr root_dir;
++ befs_disk_inode_addr indices;
+
+ } PACKED befs_super_block;
+
+@@ -130,6 +140,16 @@ typedef struct {
+ * be longer than one block!
+ */
+ typedef struct {
++ befs_disk_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
++ fs64 max_direct_range;
++ befs_disk_block_run indirect;
++ fs64 max_indirect_range;
++ befs_disk_block_run double_indirect;
++ fs64 max_double_indirect_range;
++ fs64 size;
++} PACKED befs_disk_data_stream;
++
++typedef struct {
+ befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
+ befs_off_t max_direct_range;
+ befs_block_run indirect;
+@@ -141,35 +161,35 @@ typedef struct {
+
+ /* Attribute */
+ typedef struct {
+- u32 type;
+- u16 name_size;
+- u16 data_size;
++ fs32 type;
++ fs16 name_size;
++ fs16 data_size;
+ char name[1];
+ } PACKED befs_small_data;
+
+ /* Inode structure */
+ typedef struct {
+- u32 magic1;
+- befs_inode_addr inode_num;
+- u32 uid;
+- u32 gid;
+- u32 mode;
+- u32 flags;
++ fs32 magic1;
++ befs_disk_inode_addr inode_num;
++ fs32 uid;
++ fs32 gid;
++ fs32 mode;
++ fs32 flags;
+ befs_time_t create_time;
+ befs_time_t last_modified_time;
+- befs_inode_addr parent;
+- befs_inode_addr attributes;
+- u32 type;
++ befs_disk_inode_addr parent;
++ befs_disk_inode_addr attributes;
++ fs32 type;
+
+- u32 inode_size;
+- u32 etc; /* not use */
++ fs32 inode_size;
++ fs32 etc; /* not use */
+
+ union {
+- befs_data_stream datastream;
++ befs_disk_data_stream datastream;
+ char symlink[BEFS_SYMLINK_LEN];
+ } data;
+
+- u32 pad[4]; /* not use */
++ fs32 pad[4]; /* not use */
+ befs_small_data small_data[1];
+ } PACKED befs_inode;
+
+@@ -190,6 +210,16 @@ enum btree_types {
+ };
+
+ typedef struct {
++ fs32 magic;
++ fs32 node_size;
++ fs32 max_depth;
++ fs32 data_type;
++ fs64 root_node_ptr;
++ fs64 free_node_ptr;
++ fs64 max_size;
++} PACKED befs_disk_btree_super;
++
++typedef struct {
+ u32 magic;
+ u32 node_size;
+ u32 max_depth;
+@@ -203,11 +233,19 @@ typedef struct {
+ * Header stucture of each btree node
+ */
+ typedef struct {
++ fs64 left;
++ fs64 right;
++ fs64 overflow;
++ fs16 all_key_count;
++ fs16 all_key_length;
++} PACKED befs_btree_nodehead;
++
++typedef struct {
+ befs_off_t left;
+ befs_off_t right;
+ befs_off_t overflow;
+ u16 all_key_count;
+ u16 all_key_length;
+-} PACKED befs_btree_nodehead;
++} PACKED befs_host_btree_nodehead;
+
+ #endif /* _LINUX_BEFS_FS_TYPES */
+diff --git a/fs/befs/btree.c b/fs/befs/btree.c
+index 76e2197..81b042e 100644
+--- a/fs/befs/btree.c
++++ b/fs/befs/btree.c
+@@ -30,7 +30,6 @@
+ #include "befs.h"
+ #include "btree.h"
+ #include "datastream.h"
+-#include "endian.h"
+
+ /*
+ * The btree functions in this file are built on top of the
+@@ -80,7 +79,7 @@
+ * In memory structure of each btree node
+ */
+ typedef struct {
+- befs_btree_nodehead head; /* head of node converted to cpu byteorder */
++ befs_host_btree_nodehead head; /* head of node converted to cpu byteorder */
+ struct buffer_head *bh;
+ befs_btree_nodehead *od_node; /* on disk node */
+ } befs_btree_node;
+@@ -102,9 +101,9 @@ static int befs_bt_read_node(struct supe
+
+ static int befs_leafnode(befs_btree_node * node);
+
+-static u16 *befs_bt_keylen_index(befs_btree_node * node);
++static fs16 *befs_bt_keylen_index(befs_btree_node * node);
+
+-static befs_off_t *befs_bt_valarray(befs_btree_node * node);
++static fs64 *befs_bt_valarray(befs_btree_node * node);
+
+ static char *befs_bt_keydata(befs_btree_node * node);
+
+@@ -136,7 +135,7 @@ befs_bt_read_super(struct super_block *s
+ befs_btree_super * sup)
+ {
+ struct buffer_head *bh = NULL;
+- befs_btree_super *od_sup = NULL;
++ befs_disk_btree_super *od_sup = NULL;
+
+ befs_debug(sb, "---> befs_btree_read_super()");
+
+@@ -146,7 +145,7 @@ befs_bt_read_super(struct super_block *s
+ befs_error(sb, "Couldn't read index header.");
+ goto error;
+ }
+- od_sup = (befs_btree_super *) bh->b_data;
++ od_sup = (befs_disk_btree_super *) bh->b_data;
+ befs_dump_index_entry(sb, od_sup);
+
+ sup->magic = fs32_to_cpu(sb, od_sup->magic);
+@@ -342,7 +341,7 @@ befs_find_key(struct super_block *sb, be
+ u16 keylen;
+ int findkey_len;
+ char *thiskey;
+- befs_off_t *valarray;
++ fs64 *valarray;
+
+ befs_debug(sb, "---> befs_find_key() %s", findkey);
+
+@@ -422,7 +421,7 @@ befs_btree_read(struct super_block *sb,
+ befs_btree_super bt_super;
+ befs_off_t node_off = 0;
+ int cur_key;
+- befs_off_t *valarray;
++ fs64 *valarray;
+ char *keystart;
+ u16 keylen;
+ int res;
+@@ -572,7 +571,7 @@ befs_btree_seekleaf(struct super_block *
+ this_node->head.overflow);
+ *node_off = this_node->head.overflow;
+ } else {
+- befs_off_t *valarray = befs_bt_valarray(this_node);
++ fs64 *valarray = befs_bt_valarray(this_node);
+ *node_off = fs64_to_cpu(sb, valarray[0]);
+ }
+ if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
+@@ -622,7 +621,7 @@ befs_leafnode(befs_btree_node * node)
+ *
+ * Except that rounding up to 8 works, and rounding up to 4 doesn't.
+ */
+-static u16 *
++static fs16 *
+ befs_bt_keylen_index(befs_btree_node * node)
+ {
+ const int keylen_align = 8;
+@@ -633,7 +632,7 @@ befs_bt_keylen_index(befs_btree_node * n
+ if (tmp)
+ off += keylen_align - tmp;
+
+- return (u16 *) ((void *) node->od_node + off);
++ return (fs16 *) ((void *) node->od_node + off);
+ }
+
+ /**
+@@ -643,13 +642,13 @@ befs_bt_keylen_index(befs_btree_node * n
+ * Returns a pointer to the start of the value array
+ * of the node pointed to by the node header
+ */
+-static befs_off_t *
++static fs64 *
+ befs_bt_valarray(befs_btree_node * node)
+ {
+ void *keylen_index_start = (void *) befs_bt_keylen_index(node);
+- size_t keylen_index_size = node->head.all_key_count * sizeof (u16);
++ size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
+
+- return (befs_off_t *) (keylen_index_start + keylen_index_size);
++ return (fs64 *) (keylen_index_start + keylen_index_size);
+ }
+
+ /**
+@@ -681,7 +680,7 @@ befs_bt_get_key(struct super_block *sb,
+ {
+ int prev_key_end;
+ char *keystart;
+- u16 *keylen_index;
++ fs16 *keylen_index;
+
+ if (index < 0 || index > node->head.all_key_count) {
+ *keylen = 0;
+diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c
+index b7d6b92..aacb4da 100644
+--- a/fs/befs/datastream.c
++++ b/fs/befs/datastream.c
+@@ -18,7 +18,6 @@
+ #include "befs.h"
+ #include "datastream.h"
+ #include "io.h"
+-#include "endian.h"
+
+ const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
+
+@@ -312,7 +311,7 @@ befs_find_brun_indirect(struct super_blo
+ befs_blocknr_t indir_start_blk;
+ befs_blocknr_t search_blk;
+ struct buffer_head *indirblock;
+- befs_block_run *array;
++ befs_disk_block_run *array;
+
+ befs_block_run indirect = data->indirect;
+ befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
+@@ -334,7 +333,7 @@ befs_find_brun_indirect(struct super_blo
+ return BEFS_ERR;
+ }
+
+- array = (befs_block_run *) indirblock->b_data;
++ array = (befs_disk_block_run *) indirblock->b_data;
+
+ for (j = 0; j < arraylen; ++j) {
+ int len = fs16_to_cpu(sb, array[j].len);
+@@ -427,7 +426,7 @@ befs_find_brun_dblindirect(struct super_
+ struct buffer_head *dbl_indir_block;
+ struct buffer_head *indir_block;
+ befs_block_run indir_run;
+- befs_inode_addr *iaddr_array = NULL;
++ befs_disk_inode_addr *iaddr_array = NULL;
+ befs_sb_info *befs_sb = BEFS_SB(sb);
+
+ befs_blocknr_t indir_start_blk =
+@@ -482,7 +481,7 @@ befs_find_brun_dblindirect(struct super_
+
+ dbl_block_indx =
+ dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
+- iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data;
++ iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
+ indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
+ brelse(dbl_indir_block);
+ iaddr_array = NULL;
+@@ -507,7 +506,7 @@ befs_find_brun_dblindirect(struct super_
+ }
+
+ block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
+- iaddr_array = (befs_inode_addr *) indir_block->b_data;
++ iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
+ *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
+ brelse(indir_block);
+ iaddr_array = NULL;
+diff --git a/fs/befs/debug.c b/fs/befs/debug.c
+index 875cc0a..e831a8f 100644
+--- a/fs/befs/debug.c
++++ b/fs/befs/debug.c
+@@ -21,7 +21,6 @@
+ #endif /* __KERNEL__ */
+
+ #include "befs.h"
+-#include "endian.h"
+
+ #define ERRBUFSIZE 1024
+
+@@ -125,7 +124,7 @@ befs_dump_inode(const struct super_block
+ befs_debug(sb, " type %08x", fs32_to_cpu(sb, inode->type));
+ befs_debug(sb, " inode_size %u", fs32_to_cpu(sb, inode->inode_size));
+
+- if (S_ISLNK(inode->mode)) {
++ if (S_ISLNK(fs32_to_cpu(sb, inode->mode))) {
+ befs_debug(sb, " Symbolic link [%s]", inode->data.symlink);
+ } else {
+ int i;
+@@ -231,21 +230,20 @@ befs_dump_small_data(const struct super_
+
+ /* unused */
+ void
+-befs_dump_run(const struct super_block *sb, befs_block_run run)
++befs_dump_run(const struct super_block *sb, befs_disk_block_run run)
+ {
+ #ifdef CONFIG_BEFS_DEBUG
+
+- run = fsrun_to_cpu(sb, run);
++ befs_block_run n = fsrun_to_cpu(sb, run);
+
+- befs_debug(sb, "[%u, %hu, %hu]",
+- run.allocation_group, run.start, run.len);
++ befs_debug(sb, "[%u, %hu, %hu]", n.allocation_group, n.start, n.len);
+
+ #endif //CONFIG_BEFS_DEBUG
+ }
+ #endif /* 0 */
+
+ void
+-befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super)
++befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super * super)
+ {
+ #ifdef CONFIG_BEFS_DEBUG
+
+diff --git a/fs/befs/endian.h b/fs/befs/endian.h
+index 9ecaea4..e254a20 100644
+--- a/fs/befs/endian.h
++++ b/fs/befs/endian.h
+@@ -10,85 +10,84 @@
+ #define LINUX_BEFS_ENDIAN
+
+ #include <linux/byteorder/generic.h>
+-#include "befs.h"
+
+ static inline u64
+-fs64_to_cpu(const struct super_block *sb, u64 n)
++fs64_to_cpu(const struct super_block *sb, fs64 n)
+ {
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+- return le64_to_cpu(n);
++ return le64_to_cpu((__force __le64)n);
+ else
+- return be64_to_cpu(n);
++ return be64_to_cpu((__force __be64)n);
+ }
+
+-static inline u64
++static inline fs64
+ cpu_to_fs64(const struct super_block *sb, u64 n)
+ {
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+- return cpu_to_le64(n);
++ return (__force fs64)cpu_to_le64(n);
+ else
+- return cpu_to_be64(n);
++ return (__force fs64)cpu_to_be64(n);
+ }
+
+ static inline u32
+-fs32_to_cpu(const struct super_block *sb, u32 n)
++fs32_to_cpu(const struct super_block *sb, fs32 n)
+ {
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+- return le32_to_cpu(n);
++ return le32_to_cpu((__force __le32)n);
+ else
+- return be32_to_cpu(n);
++ return be32_to_cpu((__force __be32)n);
+ }
+
+-static inline u32
++static inline fs32
+ cpu_to_fs32(const struct super_block *sb, u32 n)
+ {
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+- return cpu_to_le32(n);
++ return (__force fs32)cpu_to_le32(n);
+ else
+- return cpu_to_be32(n);
++ return (__force fs32)cpu_to_be32(n);
+ }
+
+ static inline u16
+-fs16_to_cpu(const struct super_block *sb, u16 n)
++fs16_to_cpu(const struct super_block *sb, fs16 n)
+ {
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+- return le16_to_cpu(n);
++ return le16_to_cpu((__force __le16)n);
+ else
+- return be16_to_cpu(n);
++ return be16_to_cpu((__force __be16)n);
+ }
+
+-static inline u16
++static inline fs16
+ cpu_to_fs16(const struct super_block *sb, u16 n)
+ {
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+- return cpu_to_le16(n);
++ return (__force fs16)cpu_to_le16(n);
+ else
+- return cpu_to_be16(n);
++ return (__force fs16)cpu_to_be16(n);
+ }
+
+ /* Composite types below here */
+
+ static inline befs_block_run
+-fsrun_to_cpu(const struct super_block *sb, befs_block_run n)
++fsrun_to_cpu(const struct super_block *sb, befs_disk_block_run n)
+ {
+ befs_block_run run;
+
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
+- run.allocation_group = le32_to_cpu(n.allocation_group);
+- run.start = le16_to_cpu(n.start);
+- run.len = le16_to_cpu(n.len);
++ run.allocation_group = le32_to_cpu((__force __le32)n.allocation_group);
++ run.start = le16_to_cpu((__force __le16)n.start);
++ run.len = le16_to_cpu((__force __le16)n.len);
+ } else {
+- run.allocation_group = be32_to_cpu(n.allocation_group);
+- run.start = be16_to_cpu(n.start);
+- run.len = be16_to_cpu(n.len);
++ run.allocation_group = be32_to_cpu((__force __be32)n.allocation_group);
++ run.start = be16_to_cpu((__force __be16)n.start);
++ run.len = be16_to_cpu((__force __be16)n.len);
+ }
+ return run;
+ }
+
+-static inline befs_block_run
++static inline befs_disk_block_run
+ cpu_to_fsrun(const struct super_block *sb, befs_block_run n)
+ {
+- befs_block_run run;
++ befs_disk_block_run run;
+
+ if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
+ run.allocation_group = cpu_to_le32(n.allocation_group);
+@@ -103,7 +102,7 @@ cpu_to_fsrun(const struct super_block *s
+ }
+
+ static inline befs_data_stream
+-fsds_to_cpu(const struct super_block *sb, befs_data_stream n)
++fsds_to_cpu(const struct super_block *sb, befs_disk_data_stream n)
+ {
+ befs_data_stream data;
+ int i;
+diff --git a/fs/befs/inode.c b/fs/befs/inode.c
+index d41c924..94c17f9 100644
+--- a/fs/befs/inode.c
++++ b/fs/befs/inode.c
+@@ -8,7 +8,6 @@
+
+ #include "befs.h"
+ #include "inode.h"
+-#include "endian.h"
+
+ /*
+ Validates the correctness of the befs inode
+diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
+index 50cfca5..07f7144 100644
+--- a/fs/befs/linuxvfs.c
++++ b/fs/befs/linuxvfs.c
+@@ -22,7 +22,6 @@
+ #include "datastream.h"
+ #include "super.h"
+ #include "io.h"
+-#include "endian.h"
+
+ MODULE_DESCRIPTION("BeOS File System (BeFS) driver");
+ MODULE_AUTHOR("Will Dyson");
+@@ -365,7 +364,6 @@ befs_read_inode(struct inode *inode)
+ inode->i_mtime.tv_nsec = 0; /* lower 16 bits are not a time */
+ inode->i_ctime = inode->i_mtime;
+ inode->i_atime = inode->i_mtime;
+- inode->i_blksize = befs_sb->block_size;
+
+ befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
+ befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent);
+@@ -446,9 +444,7 @@ befs_init_inodecache(void)
+ static void
+ befs_destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(befs_inode_cachep))
+- printk(KERN_ERR "befs_destroy_inodecache: "
+- "not all structures were freed\n");
++ kmem_cache_destroy(befs_inode_cachep);
+ }
+
+ /*
+diff --git a/fs/befs/super.c b/fs/befs/super.c
+index 4557acb..8c3401f 100644
+--- a/fs/befs/super.c
++++ b/fs/befs/super.c
+@@ -11,7 +11,6 @@
+
+ #include "befs.h"
+ #include "super.h"
+-#include "endian.h"
+
+ /**
+ * load_befs_sb -- Read from disk and properly byteswap all the fields
+diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
+index 26fad96..a650f1d 100644
+--- a/fs/bfs/dir.c
++++ b/fs/bfs/dir.c
+@@ -102,7 +102,7 @@ static int bfs_create(struct inode * dir
+ inode->i_uid = current->fsuid;
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+ inode->i_op = &bfs_file_inops;
+ inode->i_fop = &bfs_file_operations;
+ inode->i_mapping->a_ops = &bfs_aops;
+@@ -117,8 +117,7 @@ static int bfs_create(struct inode * dir
+
+ err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
+ if (err) {
+- inode->i_nlink--;
+- mark_inode_dirty(inode);
++ inode_dec_link_count(inode);
+ iput(inode);
+ unlock_kernel();
+ return err;
+@@ -164,7 +163,7 @@ static int bfs_link(struct dentry * old,
+ unlock_kernel();
+ return err;
+ }
+- inode->i_nlink++;
++ inc_nlink(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+ atomic_inc(&inode->i_count);
+@@ -196,9 +195,8 @@ static int bfs_unlink(struct inode * dir
+ mark_buffer_dirty(bh);
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ mark_inode_dirty(dir);
+- inode->i_nlink--;
+ inode->i_ctime = dir->i_ctime;
+- mark_inode_dirty(inode);
++ inode_dec_link_count(inode);
+ error = 0;
+
+ out_brelse:
+@@ -249,9 +247,8 @@ static int bfs_rename(struct inode * old
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+- new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+- mark_inode_dirty(new_inode);
++ inode_dec_link_count(new_inode);
+ }
+ mark_buffer_dirty(old_bh);
+ error = 0;
+diff --git a/fs/bfs/file.c b/fs/bfs/file.c
+index 3d5aca2..a9164a8 100644
+--- a/fs/bfs/file.c
++++ b/fs/bfs/file.c
+@@ -19,8 +19,10 @@
+
+ const struct file_operations bfs_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .sendfile = generic_file_sendfile,
+ };
+diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
+index cf74f3d..ed27ffb 100644
+--- a/fs/bfs/inode.c
++++ b/fs/bfs/inode.c
+@@ -76,7 +76,6 @@ static void bfs_read_inode(struct inode
+ inode->i_size = BFS_FILESIZE(di);
+ inode->i_blocks = BFS_FILEBLOCKS(di);
+ if (inode->i_size || inode->i_blocks) dprintf("Registered inode with %lld size, %ld blocks\n", inode->i_size, inode->i_blocks);
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_atime.tv_sec = le32_to_cpu(di->i_atime);
+ inode->i_mtime.tv_sec = le32_to_cpu(di->i_mtime);
+ inode->i_ctime.tv_sec = le32_to_cpu(di->i_ctime);
+@@ -268,8 +267,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(bfs_inode_cachep))
+- printk(KERN_INFO "bfs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(bfs_inode_cachep);
+ }
+
+ static struct super_operations bfs_sops = {
+@@ -311,11 +309,10 @@ static int bfs_fill_super(struct super_b
+ unsigned i, imap_len;
+ struct bfs_sb_info * info;
+
+- info = kmalloc(sizeof(*info), GFP_KERNEL);
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ s->s_fs_info = info;
+- memset(info, 0, sizeof(*info));
+
+ sb_set_blocksize(s, BFS_BSIZE);
+
+@@ -338,10 +335,9 @@ static int bfs_fill_super(struct super_b
+ + BFS_ROOT_INO - 1;
+
+ imap_len = info->si_lasti/8 + 1;
+- info->si_imap = kmalloc(imap_len, GFP_KERNEL);
++ info->si_imap = kzalloc(imap_len, GFP_KERNEL);
+ if (!info->si_imap)
+ goto out;
+- memset(info->si_imap, 0, imap_len);
+ for (i=0; i<BFS_ROOT_INO; i++)
+ set_bit(i, info->si_imap);
+
+diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
+index f312103..517e111 100644
+--- a/fs/binfmt_aout.c
++++ b/fs/binfmt_aout.c
+@@ -278,6 +278,13 @@ static int load_aout_binary(struct linux
+ return -ENOEXEC;
+ }
+
++ /*
++ * Requires a mmap handler. This prevents people from using a.out
++ * as part of an exploit attack against /proc-related vulnerabilities.
++ */
++ if (!bprm->file->f_op || !bprm->file->f_op->mmap)
++ return -ENOEXEC;
++
+ fd_offset = N_TXTOFF(ex);
+
+ /* Check initial limits. This avoids letting people circumvent
+@@ -476,6 +483,13 @@ static int load_aout_library(struct file
+ goto out;
+ }
+
++ /*
++ * Requires a mmap handler. This prevents people from using a.out
++ * as part of an exploit attack against /proc-related vulnerabilities.
++ */
++ if (!file->f_op || !file->f_op->mmap)
++ goto out;
++
+ if (N_FLAGS(ex))
+ goto out;
+
+diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
+index 672a3b9..79b05a1 100644
+--- a/fs/binfmt_elf.c
++++ b/fs/binfmt_elf.c
+@@ -46,7 +46,6 @@
+ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
+ static int load_elf_library(struct file *);
+ static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
+-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+
+ #ifndef elf_addr_t
+ #define elf_addr_t unsigned long
+@@ -515,7 +514,8 @@ static unsigned long randomize_stack_top
+ {
+ unsigned int random_variable = 0;
+
+- if (current->flags & PF_RANDOMIZE) {
++ if ((current->flags & PF_RANDOMIZE) &&
++ !(current->personality & ADDR_NO_RANDOMIZE)) {
+ random_variable = get_random_int() & STACK_RND_MASK;
+ random_variable <<= PAGE_SHIFT;
+ }
+@@ -1037,10 +1037,8 @@ out_free_interp:
+ out_free_file:
+ sys_close(elf_exec_fileno);
+ out_free_fh:
+- if (files) {
+- put_files_struct(current->files);
+- current->files = files;
+- }
++ if (files)
++ reset_files_struct(current, files);
+ out_free_ph:
+ kfree(elf_phdata);
+ goto out;
+@@ -1153,11 +1151,23 @@ static int dump_write(struct file *file,
+
+ static int dump_seek(struct file *file, loff_t off)
+ {
+- if (file->f_op->llseek) {
+- if (file->f_op->llseek(file, off, 0) != off)
++ if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
++ if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
+ return 0;
+- } else
+- file->f_pos = off;
++ } else {
++ char *buf = (char *)get_zeroed_page(GFP_KERNEL);
++ if (!buf)
++ return 0;
++ while (off > 0) {
++ unsigned long n = off;
++ if (n > PAGE_SIZE)
++ n = PAGE_SIZE;
++ if (!dump_write(file, buf, n))
++ return 0;
++ off -= n;
++ }
++ free_page((unsigned long)buf);
++ }
+ return 1;
+ }
+
+@@ -1205,30 +1215,35 @@ static int notesize(struct memelfnote *e
+ return sz;
+ }
+
+-#define DUMP_WRITE(addr, nr) \
+- do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
+-#define DUMP_SEEK(off) \
+- do { if (!dump_seek(file, (off))) return 0; } while(0)
++#define DUMP_WRITE(addr, nr, foffset) \
++ do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)
+
+-static int writenote(struct memelfnote *men, struct file *file)
++static int alignfile(struct file *file, loff_t *foffset)
+ {
+- struct elf_note en;
++ static const char buf[4] = { 0, };
++ DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
++ return 1;
++}
+
++static int writenote(struct memelfnote *men, struct file *file,
++ loff_t *foffset)
++{
++ struct elf_note en;
+ en.n_namesz = strlen(men->name) + 1;
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+- DUMP_WRITE(&en, sizeof(en));
+- DUMP_WRITE(men->name, en.n_namesz);
+- /* XXX - cast from long long to long to avoid need for libgcc.a */
+- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+- DUMP_WRITE(men->data, men->datasz);
+- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
++ DUMP_WRITE(&en, sizeof(en), foffset);
++ DUMP_WRITE(men->name, en.n_namesz, foffset);
++ if (!alignfile(file, foffset))
++ return 0;
++ DUMP_WRITE(men->data, men->datasz, foffset);
++ if (!alignfile(file, foffset))
++ return 0;
+
+ return 1;
+ }
+ #undef DUMP_WRITE
+-#undef DUMP_SEEK
+
+ #define DUMP_WRITE(addr, nr) \
+ if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
+@@ -1262,7 +1277,7 @@ static void fill_elf_header(struct elfhd
+ return;
+ }
+
+-static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
++static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
+ {
+ phdr->p_type = PT_NOTE;
+ phdr->p_offset = offset;
+@@ -1428,7 +1443,7 @@ static int elf_core_dump(long signr, str
+ int i;
+ struct vm_area_struct *vma;
+ struct elfhdr *elf = NULL;
+- off_t offset = 0, dataoff;
++ loff_t offset = 0, dataoff, foffset;
+ unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
+ int numnote;
+ struct memelfnote *notes = NULL;
+@@ -1480,20 +1495,19 @@ static int elf_core_dump(long signr, str
+
+ if (signr) {
+ struct elf_thread_status *tmp;
+- read_lock(&tasklist_lock);
++ rcu_read_lock();
+ do_each_thread(g,p)
+ if (current->mm == p->mm && current != p) {
+ tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
+ if (!tmp) {
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+ goto cleanup;
+ }
+- INIT_LIST_HEAD(&tmp->list);
+ tmp->thread = p;
+ list_add(&tmp->list, &thread_list);
+ }
+ while_each_thread(g,p);
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+ list_for_each(t, &thread_list) {
+ struct elf_thread_status *tmp;
+ int sz;
+@@ -1555,7 +1569,8 @@ static int elf_core_dump(long signr, str
+
+ DUMP_WRITE(elf, sizeof(*elf));
+ offset += sizeof(*elf); /* Elf header */
+- offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
++ offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */
++ foffset = offset;
+
+ /* Write notes phdr entry */
+ {
+@@ -1572,7 +1587,6 @@ static int elf_core_dump(long signr, str
+ DUMP_WRITE(&phdr, sizeof(phdr));
+ }
+
+- /* Page-align dumped data */
+ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+
+ /* Write program headers for segments dump */
+@@ -1605,7 +1619,7 @@ static int elf_core_dump(long signr, str
+
+ /* write out the notes section */
+ for (i = 0; i < numnote; i++)
+- if (!writenote(notes + i, file))
++ if (!writenote(notes + i, file, &foffset))
+ goto end_coredump;
+
+ /* write out the thread status notes section */
+@@ -1614,11 +1628,12 @@ static int elf_core_dump(long signr, str
+ list_entry(t, struct elf_thread_status, list);
+
+ for (i = 0; i < tmp->num_notes; i++)
+- if (!writenote(&tmp->notes[i], file))
++ if (!writenote(&tmp->notes[i], file, &foffset))
+ goto end_coredump;
+ }
+-
+- DUMP_SEEK(dataoff);
++
++ /* Align to page */
++ DUMP_SEEK(dataoff - foffset);
+
+ for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ unsigned long addr;
+@@ -1634,10 +1649,10 @@ static int elf_core_dump(long signr, str
+
+ if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+ &page, &vma) <= 0) {
+- DUMP_SEEK(file->f_pos + PAGE_SIZE);
++ DUMP_SEEK(PAGE_SIZE);
+ } else {
+ if (page == ZERO_PAGE(addr)) {
+- DUMP_SEEK(file->f_pos + PAGE_SIZE);
++ DUMP_SEEK(PAGE_SIZE);
+ } else {
+ void *kaddr;
+ flush_cache_page(vma, addr,
+@@ -1661,13 +1676,6 @@ static int elf_core_dump(long signr, str
+ ELF_CORE_WRITE_EXTRA_DATA;
+ #endif
+
+- if ((off_t)file->f_pos != offset) {
+- /* Sanity check */
+- printk(KERN_WARNING
+- "elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
+- (off_t)file->f_pos, offset);
+- }
+-
+ end_coredump:
+ set_fs(fs);
+
+diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
+index 2f33658..f86d5c9 100644
+--- a/fs/binfmt_elf_fdpic.c
++++ b/fs/binfmt_elf_fdpic.c
+@@ -1597,20 +1597,19 @@ static int elf_fdpic_core_dump(long sign
+
+ if (signr) {
+ struct elf_thread_status *tmp;
+- read_lock(&tasklist_lock);
++ rcu_read_lock();
+ do_each_thread(g,p)
+ if (current->mm == p->mm && current != p) {
+ tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
+ if (!tmp) {
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+ goto cleanup;
+ }
+- INIT_LIST_HEAD(&tmp->list);
+ tmp->thread = p;
+ list_add(&tmp->list, &thread_list);
+ }
+ while_each_thread(g,p);
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+ list_for_each(t, &thread_list) {
+ struct elf_thread_status *tmp;
+ int sz;
+diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
+index 34ebbc1..1713c48 100644
+--- a/fs/binfmt_misc.c
++++ b/fs/binfmt_misc.c
+@@ -215,10 +215,8 @@ _error:
+ bprm->interp_flags = 0;
+ bprm->interp_data = 0;
+ _unshare:
+- if (files) {
+- put_files_struct(current->files);
+- current->files = files;
+- }
++ if (files)
++ reset_files_struct(current, files);
+ goto _ret;
+ }
+
+@@ -507,7 +505,6 @@ static struct inode *bm_get_inode(struct
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime =
+ current_fs_time(inode->i_sb);
+@@ -517,7 +514,7 @@ static struct inode *bm_get_inode(struct
+
+ static void bm_clear_inode(struct inode *inode)
+ {
+- kfree(inode->u.generic_ip);
++ kfree(inode->i_private);
+ }
+
+ static void kill_node(Node *e)
+@@ -545,7 +542,7 @@ static void kill_node(Node *e)
+ static ssize_t
+ bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
+ {
+- Node *e = file->f_dentry->d_inode->u.generic_ip;
++ Node *e = file->f_dentry->d_inode->i_private;
+ loff_t pos = *ppos;
+ ssize_t res;
+ char *page;
+@@ -579,7 +576,7 @@ static ssize_t bm_entry_write(struct fil
+ size_t count, loff_t *ppos)
+ {
+ struct dentry *root;
+- Node *e = file->f_dentry->d_inode->u.generic_ip;
++ Node *e = file->f_dentry->d_inode->i_private;
+ int res = parse_command(buffer, count);
+
+ switch (res) {
+@@ -646,7 +643,7 @@ static ssize_t bm_register_write(struct
+ }
+
+ e->dentry = dget(dentry);
+- inode->u.generic_ip = e;
++ inode->i_private = e;
+ inode->i_fop = &bm_entry_operations;
+
+ d_instantiate(dentry, inode);
+diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
+index 32b5d62..5bcdaaf 100644
+--- a/fs/binfmt_som.c
++++ b/fs/binfmt_som.c
+@@ -29,6 +29,7 @@
+ #include <linux/personality.h>
+ #include <linux/init.h>
+
++#include <asm/a.out.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+
+@@ -194,6 +195,7 @@ load_som_binary(struct linux_binprm * bp
+ unsigned long som_entry;
+ struct som_hdr *som_ex;
+ struct som_exec_auxhdr *hpuxhdr;
++ struct files_struct *files;
+
+ /* Get the exec-header */
+ som_ex = (struct som_hdr *) bprm->buf;
+@@ -208,15 +210,27 @@ load_som_binary(struct linux_binprm * bp
+ size = som_ex->aux_header_size;
+ if (size > SOM_PAGESIZE)
+ goto out;
+- hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL);
++ hpuxhdr = kmalloc(size, GFP_KERNEL);
+ if (!hpuxhdr)
+ goto out;
+
+ retval = kernel_read(bprm->file, som_ex->aux_header_location,
+ (char *) hpuxhdr, size);
++ if (retval != size) {
++ if (retval >= 0)
++ retval = -EIO;
++ goto out_free;
++ }
++
++ files = current->files; /* Refcounted so ok */
++ retval = unshare_files();
+ if (retval < 0)
+ goto out_free;
+-#error "Fix security hole before enabling me"
++ if (files == current->files) {
++ put_files_struct(files);
++ files = NULL;
++ }
++
+ retval = get_unused_fd();
+ if (retval < 0)
+ goto out_free;
+diff --git a/fs/bio.c b/fs/bio.c
+index 6a0b9ad..f95c874 100644
+--- a/fs/bio.c
++++ b/fs/bio.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2001 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2001 Jens Axboe <axboe at kernel.dk>
+ *
+ * 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
+@@ -79,7 +79,6 @@ static struct bio_set *fs_bio_set;
+ static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
+ {
+ struct bio_vec *bvl;
+- struct biovec_slab *bp;
+
+ /*
+ * see comment near bvec_array define!
+@@ -98,10 +97,12 @@ static inline struct bio_vec *bvec_alloc
+ * idx now points to the pool we want to allocate from
+ */
+
+- bp = bvec_slabs + *idx;
+ bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
+- if (bvl)
++ if (bvl) {
++ struct biovec_slab *bp = bvec_slabs + *idx;
++
+ memset(bvl, 0, bp->nr_vecs * sizeof(struct bio_vec));
++ }
+
+ return bvl;
+ }
+@@ -166,7 +167,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_m
+
+ bio_init(bio);
+ if (likely(nr_iovecs)) {
+- unsigned long idx;
++ unsigned long idx = 0; /* shut up gcc */
+
+ bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
+ if (unlikely(!bvl)) {
+@@ -1142,7 +1143,7 @@ static int biovec_create_pools(struct bi
+ struct biovec_slab *bp = bvec_slabs + i;
+ mempool_t **bvp = bs->bvec_pools + i;
+
+- if (i >= scale)
++ if (pool_entries > 1 && i >= scale)
+ pool_entries >>= 1;
+
+ *bvp = mempool_create_slab_pool(pool_entries, bp->slab);
+diff --git a/fs/block_dev.c b/fs/block_dev.c
+index 045f988..36c0e7a 100644
+--- a/fs/block_dev.c
++++ b/fs/block_dev.c
+@@ -17,11 +17,13 @@
+ #include <linux/module.h>
+ #include <linux/blkpg.h>
+ #include <linux/buffer_head.h>
++#include <linux/writeback.h>
+ #include <linux/mpage.h>
+ #include <linux/mount.h>
+ #include <linux/uio.h>
+ #include <linux/namei.h>
+ #include <asm/uaccess.h>
++#include "internal.h"
+
+ struct bdev_inode {
+ struct block_device bdev;
+@@ -543,11 +545,11 @@ static struct kobject *bdev_get_holder(s
+ return kobject_get(bdev->bd_disk->holder_dir);
+ }
+
+-static void add_symlink(struct kobject *from, struct kobject *to)
++static int add_symlink(struct kobject *from, struct kobject *to)
+ {
+ if (!from || !to)
+- return;
+- sysfs_create_link(from, to, kobject_name(to));
++ return 0;
++ return sysfs_create_link(from, to, kobject_name(to));
+ }
+
+ static void del_symlink(struct kobject *from, struct kobject *to)
+@@ -640,38 +642,59 @@ static void free_bd_holder(struct bd_hol
+ }
+
+ /**
++ * find_bd_holder - find matching struct bd_holder from the block device
++ *
++ * @bdev: struct block device to be searched
++ * @bo: target struct bd_holder
++ *
++ * Returns matching entry with @bo in @bdev->bd_holder_list.
++ * If found, increment the reference count and return the pointer.
++ * If not found, returns NULL.
++ */
++static struct bd_holder *find_bd_holder(struct block_device *bdev,
++ struct bd_holder *bo)
++{
++ struct bd_holder *tmp;
++
++ list_for_each_entry(tmp, &bdev->bd_holder_list, list)
++ if (tmp->sdir == bo->sdir) {
++ tmp->count++;
++ return tmp;
++ }
++
++ return NULL;
++}
++
++/**
+ * add_bd_holder - create sysfs symlinks for bd_claim() relationship
+ *
+ * @bdev: block device to be bd_claimed
+ * @bo: preallocated and initialized by alloc_bd_holder()
+ *
+- * If there is no matching entry with @bo in @bdev->bd_holder_list,
+- * add @bo to the list, create symlinks.
++ * Add @bo to @bdev->bd_holder_list, create symlinks.
+ *
+- * Returns 1 if @bo was added to the list.
+- * Returns 0 if @bo wasn't used by any reason and should be freed.
++ * Returns 0 if symlinks are created.
++ * Returns -ve if something fails.
+ */
+ static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
+ {
+- struct bd_holder *tmp;
++ int ret;
+
+ if (!bo)
+- return 0;
+-
+- list_for_each_entry(tmp, &bdev->bd_holder_list, list) {
+- if (tmp->sdir == bo->sdir) {
+- tmp->count++;
+- return 0;
+- }
+- }
++ return -EINVAL;
+
+ if (!bd_holder_grab_dirs(bdev, bo))
+- return 0;
++ return -EBUSY;
+
+- add_symlink(bo->sdir, bo->sdev);
+- add_symlink(bo->hdir, bo->hdev);
+- list_add_tail(&bo->list, &bdev->bd_holder_list);
+- return 1;
++ ret = add_symlink(bo->sdir, bo->sdev);
++ if (ret == 0) {
++ ret = add_symlink(bo->hdir, bo->hdev);
++ if (ret)
++ del_symlink(bo->sdir, bo->sdev);
++ }
++ if (ret == 0)
++ list_add_tail(&bo->list, &bdev->bd_holder_list);
++ return ret;
+ }
+
+ /**
+@@ -730,7 +753,7 @@ static int bd_claim_by_kobject(struct bl
+ struct kobject *kobj)
+ {
+ int res;
+- struct bd_holder *bo;
++ struct bd_holder *bo, *found;
+
+ if (!kobj)
+ return -EINVAL;
+@@ -741,7 +764,16 @@ static int bd_claim_by_kobject(struct bl
+
+ mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION);
+ res = bd_claim(bdev, holder);
+- if (res || !add_bd_holder(bdev, bo))
++ if (res == 0) {
++ found = find_bd_holder(bdev, bo);
++ if (found == NULL) {
++ res = add_bd_holder(bdev, bo);
++ if (res)
++ bd_release(bdev);
++ }
++ }
++
++ if (res || found)
+ free_bd_holder(bo);
+ mutex_unlock(&bdev->bd_mutex);
+
+@@ -1021,7 +1053,7 @@ do_open(struct block_device *bdev, struc
+ rescan_partitions(bdev->bd_disk, bdev);
+ } else {
+ mutex_lock_nested(&bdev->bd_contains->bd_mutex,
+- BD_MUTEX_PARTITION);
++ BD_MUTEX_WHOLE);
+ bdev->bd_contains->bd_part_count++;
+ mutex_unlock(&bdev->bd_contains->bd_mutex);
+ }
+@@ -1119,6 +1151,8 @@ static int blkdev_open(struct inode * in
+ filp->f_flags |= O_LARGEFILE;
+
+ bdev = bd_acquire(inode);
++ if (bdev == NULL)
++ return -ENOMEM;
+
+ res = do_open(bdev, filp, BD_MUTEX_NORMAL);
+ if (res)
+@@ -1142,22 +1176,6 @@ static int blkdev_close(struct inode * i
+ return blkdev_put(bdev);
+ }
+
+-static ssize_t blkdev_file_write(struct file *file, const char __user *buf,
+- size_t count, loff_t *ppos)
+-{
+- struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
+-
+- return generic_file_write_nolock(file, &local_iov, 1, ppos);
+-}
+-
+-static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos)
+-{
+- struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
+-
+- return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+-}
+-
+ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+ {
+ return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
+@@ -1177,18 +1195,16 @@ const struct file_operations def_blk_fop
+ .open = blkdev_open,
+ .release = blkdev_close,
+ .llseek = block_llseek,
+- .read = generic_file_read,
+- .write = blkdev_file_write,
++ .read = do_sync_read,
++ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+- .aio_write = blkdev_file_aio_write,
++ .aio_write = generic_file_aio_write_nolock,
+ .mmap = generic_file_mmap,
+ .fsync = block_fsync,
+ .unlocked_ioctl = block_ioctl,
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_blkdev_ioctl,
+ #endif
+- .readv = generic_file_readv,
+- .writev = generic_file_write_nolock,
+ .sendfile = generic_file_sendfile,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+@@ -1303,3 +1319,24 @@ void close_bdev_excl(struct block_device
+ }
+
+ EXPORT_SYMBOL(close_bdev_excl);
++
++int __invalidate_device(struct block_device *bdev)
++{
++ struct super_block *sb = get_super(bdev);
++ int res = 0;
++
++ if (sb) {
++ /*
++ * no need to lock the super, get_super holds the
++ * read mutex so the filesystem cannot go away
++ * under us (->put_super runs with the write lock
++ * hold).
++ */
++ shrink_dcache_sb(sb);
++ res = invalidate_inodes(sb);
++ drop_super(sb);
++ }
++ invalidate_bdev(bdev, 0);
++ return res;
++}
++EXPORT_SYMBOL(__invalidate_device);
+diff --git a/fs/buffer.c b/fs/buffer.c
+index 71649ef..35527dc 100644
+--- a/fs/buffer.c
++++ b/fs/buffer.c
+@@ -159,31 +159,6 @@ int sync_blockdev(struct block_device *b
+ }
+ EXPORT_SYMBOL(sync_blockdev);
+
+-static void __fsync_super(struct super_block *sb)
+-{
+- sync_inodes_sb(sb, 0);
+- DQUOT_SYNC(sb);
+- lock_super(sb);
+- if (sb->s_dirt && sb->s_op->write_super)
+- sb->s_op->write_super(sb);
+- unlock_super(sb);
+- if (sb->s_op->sync_fs)
+- sb->s_op->sync_fs(sb, 1);
+- sync_blockdev(sb->s_bdev);
+- sync_inodes_sb(sb, 1);
+-}
+-
+-/*
+- * Write out and wait upon all dirty data associated with this
+- * superblock. Filesystem data as well as the underlying block
+- * device. Takes the superblock lock.
+- */
+-int fsync_super(struct super_block *sb)
+-{
+- __fsync_super(sb);
+- return sync_blockdev(sb->s_bdev);
+-}
+-
+ /*
+ * Write out and wait upon all dirty data associated with this
+ * device. Filesystem data as well as the underlying block
+@@ -260,118 +235,6 @@ void thaw_bdev(struct block_device *bdev
+ EXPORT_SYMBOL(thaw_bdev);
+
+ /*
+- * sync everything. Start out by waking pdflush, because that writes back
+- * all queues in parallel.
+- */
+-static void do_sync(unsigned long wait)
+-{
+- wakeup_pdflush(0);
+- sync_inodes(0); /* All mappings, inodes and their blockdevs */
+- DQUOT_SYNC(NULL);
+- sync_supers(); /* Write the superblocks */
+- sync_filesystems(0); /* Start syncing the filesystems */
+- sync_filesystems(wait); /* Waitingly sync the filesystems */
+- sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
+- if (!wait)
+- printk("Emergency Sync complete\n");
+- if (unlikely(laptop_mode))
+- laptop_sync_completion();
+-}
+-
+-asmlinkage long sys_sync(void)
+-{
+- do_sync(1);
+- return 0;
+-}
+-
+-void emergency_sync(void)
+-{
+- pdflush_operation(do_sync, 0);
+-}
+-
+-/*
+- * Generic function to fsync a file.
+- *
+- * filp may be NULL if called via the msync of a vma.
+- */
+-
+-int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+-{
+- struct inode * inode = dentry->d_inode;
+- struct super_block * sb;
+- int ret, err;
+-
+- /* sync the inode to buffers */
+- ret = write_inode_now(inode, 0);
+-
+- /* sync the superblock to buffers */
+- sb = inode->i_sb;
+- lock_super(sb);
+- if (sb->s_op->write_super)
+- sb->s_op->write_super(sb);
+- unlock_super(sb);
+-
+- /* .. finally sync the buffers to disk */
+- err = sync_blockdev(sb->s_bdev);
+- if (!ret)
+- ret = err;
+- return ret;
+-}
+-
+-long do_fsync(struct file *file, int datasync)
+-{
+- int ret;
+- int err;
+- struct address_space *mapping = file->f_mapping;
+-
+- if (!file->f_op || !file->f_op->fsync) {
+- /* Why? We can still call filemap_fdatawrite */
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- ret = filemap_fdatawrite(mapping);
+-
+- /*
+- * We need to protect against concurrent writers, which could cause
+- * livelocks in fsync_buffers_list().
+- */
+- mutex_lock(&mapping->host->i_mutex);
+- err = file->f_op->fsync(file, file->f_dentry, datasync);
+- if (!ret)
+- ret = err;
+- mutex_unlock(&mapping->host->i_mutex);
+- err = filemap_fdatawait(mapping);
+- if (!ret)
+- ret = err;
+-out:
+- return ret;
+-}
+-
+-static long __do_fsync(unsigned int fd, int datasync)
+-{
+- struct file *file;
+- int ret = -EBADF;
+-
+- file = fget(fd);
+- if (file) {
+- ret = do_fsync(file, datasync);
+- fput(file);
+- }
+- return ret;
+-}
+-
+-asmlinkage long sys_fsync(unsigned int fd)
+-{
+- return __do_fsync(fd, 0);
+-}
+-
+-asmlinkage long sys_fdatasync(unsigned int fd)
+-{
+- return __do_fsync(fd, 1);
+-}
+-
+-/*
+ * Various filesystems appear to want __find_get_block to be non-blocking.
+ * But it's the page lock which protects the buffers. To get around this,
+ * we get exclusion from try_to_free_buffers with the blockdev mapping's
+@@ -589,6 +452,7 @@ static void end_buffer_async_write(struc
+ bdevname(bh->b_bdev, b));
+ }
+ set_bit(AS_EIO, &page->mapping->flags);
++ set_buffer_write_io_error(bh);
+ clear_buffer_uptodate(bh);
+ SetPageError(page);
+ }
+@@ -708,6 +572,10 @@ EXPORT_SYMBOL(mark_buffer_async_write);
+ static inline void __remove_assoc_queue(struct buffer_head *bh)
+ {
+ list_del_init(&bh->b_assoc_buffers);
++ WARN_ON(!bh->b_assoc_map);
++ if (buffer_write_io_error(bh))
++ set_bit(AS_EIO, &bh->b_assoc_map->flags);
++ bh->b_assoc_map = NULL;
+ }
+
+ int inode_has_buffers(struct inode *inode)
+@@ -806,6 +674,7 @@ void mark_buffer_dirty_inode(struct buff
+ spin_lock(&buffer_mapping->private_lock);
+ list_move_tail(&bh->b_assoc_buffers,
+ &mapping->private_list);
++ bh->b_assoc_map = mapping;
+ spin_unlock(&buffer_mapping->private_lock);
+ }
+ }
+@@ -838,7 +707,10 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode);
+ */
+ int __set_page_dirty_buffers(struct page *page)
+ {
+- struct address_space * const mapping = page->mapping;
++ struct address_space * const mapping = page_mapping(page);
++
++ if (unlikely(!mapping))
++ return !TestSetPageDirty(page);
+
+ spin_lock(&mapping->private_lock);
+ if (page_has_buffers(page)) {
+@@ -899,7 +771,7 @@ static int fsync_buffers_list(spinlock_t
+ spin_lock(lock);
+ while (!list_empty(list)) {
+ bh = BH_ENTRY(list->next);
+- list_del_init(&bh->b_assoc_buffers);
++ __remove_assoc_queue(bh);
+ if (buffer_dirty(bh) || buffer_locked(bh)) {
+ list_add(&bh->b_assoc_buffers, &tmp);
+ if (buffer_dirty(bh)) {
+@@ -920,7 +792,7 @@ static int fsync_buffers_list(spinlock_t
+
+ while (!list_empty(&tmp)) {
+ bh = BH_ENTRY(tmp.prev);
+- __remove_assoc_queue(bh);
++ list_del_init(&bh->b_assoc_buffers);
+ get_bh(bh);
+ spin_unlock(lock);
+ wait_on_buffer(bh);
+@@ -1176,8 +1048,21 @@ grow_buffers(struct block_device *bdev,
+ } while ((size << sizebits) < PAGE_SIZE);
+
+ index = block >> sizebits;
+- block = index << sizebits;
+
++ /*
++ * Check for a block which wants to lie outside our maximum possible
++ * pagecache index. (this comparison is done using sector_t types).
++ */
++ if (unlikely(index != block >> sizebits)) {
++ char b[BDEVNAME_SIZE];
++
++ printk(KERN_ERR "%s: requested out-of-range block %llu for "
++ "device %s\n",
++ __FUNCTION__, (unsigned long long)block,
++ bdevname(bdev, b));
++ return -EIO;
++ }
++ block = index << sizebits;
+ /* Create a page with the proper size buffers.. */
+ page = grow_dev_page(bdev, block, index, size);
+ if (!page)
+@@ -1204,12 +1089,16 @@ __getblk_slow(struct block_device *bdev,
+
+ for (;;) {
+ struct buffer_head * bh;
++ int ret;
+
+ bh = __find_get_block(bdev, block, size);
+ if (bh)
+ return bh;
+
+- if (!grow_buffers(bdev, block, size))
++ ret = grow_buffers(bdev, block, size);
++ if (ret < 0)
++ return NULL;
++ if (ret == 0)
+ free_more_memory();
+ }
+ }
+@@ -1284,6 +1173,7 @@ void __bforget(struct buffer_head *bh)
+
+ spin_lock(&buffer_mapping->private_lock);
+ list_del_init(&bh->b_assoc_buffers);
++ bh->b_assoc_map = NULL;
+ spin_unlock(&buffer_mapping->private_lock);
+ }
+ __brelse(bh);
+@@ -1551,35 +1441,6 @@ static void discard_buffer(struct buffer
+ }
+
+ /**
+- * try_to_release_page() - release old fs-specific metadata on a page
+- *
+- * @page: the page which the kernel is trying to free
+- * @gfp_mask: memory allocation flags (and I/O mode)
+- *
+- * The address_space is to try to release any data against the page
+- * (presumably at page->private). If the release was successful, return `1'.
+- * Otherwise return zero.
+- *
+- * The @gfp_mask argument specifies whether I/O may be performed to release
+- * this page (__GFP_IO), and whether the call may block (__GFP_WAIT).
+- *
+- * NOTE: @gfp_mask may go away, and this function may become non-blocking.
+- */
+-int try_to_release_page(struct page *page, gfp_t gfp_mask)
+-{
+- struct address_space * const mapping = page->mapping;
+-
+- BUG_ON(!PageLocked(page));
+- if (PageWriteback(page))
+- return 0;
+-
+- if (mapping && mapping->a_ops->releasepage)
+- return mapping->a_ops->releasepage(page, gfp_mask);
+- return try_to_free_buffers(page);
+-}
+-EXPORT_SYMBOL(try_to_release_page);
+-
+-/**
+ * block_invalidatepage - invalidate part of all of a buffer-backed page
+ *
+ * @page: the page which is affected
+@@ -1630,14 +1491,6 @@ out:
+ }
+ EXPORT_SYMBOL(block_invalidatepage);
+
+-void do_invalidatepage(struct page *page, unsigned long offset)
+-{
+- void (*invalidatepage)(struct page *, unsigned long);
+- invalidatepage = page->mapping->a_ops->invalidatepage ? :
+- block_invalidatepage;
+- (*invalidatepage)(page, offset);
+-}
+-
+ /*
+ * We attach and possibly dirty the buffers atomically wrt
+ * __set_page_dirty_buffers() via private_lock. try_to_free_buffers
+@@ -2008,6 +1861,7 @@ static int __block_prepare_write(struct
+ clear_buffer_new(bh);
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr+block_start, 0, bh->b_size);
++ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+@@ -2514,6 +2368,7 @@ failed:
+ */
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr, 0, PAGE_CACHE_SIZE);
++ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ SetPageUptodate(page);
+ set_page_dirty(page);
+@@ -2987,6 +2842,7 @@ int try_to_free_buffers(struct page *pag
+
+ spin_lock(&mapping->private_lock);
+ ret = drop_buffers(page, &buffers_to_free);
++ spin_unlock(&mapping->private_lock);
+ if (ret) {
+ /*
+ * If the filesystem writes its buffers by hand (eg ext3)
+@@ -2998,7 +2854,6 @@ int try_to_free_buffers(struct page *pag
+ */
+ clear_page_dirty(page);
+ }
+- spin_unlock(&mapping->private_lock);
+ out:
+ if (buffers_to_free) {
+ struct buffer_head *bh = buffers_to_free;
+diff --git a/fs/char_dev.c b/fs/char_dev.c
+index 3483d3c..a885f46 100644
+--- a/fs/char_dev.c
++++ b/fs/char_dev.c
+@@ -19,10 +19,30 @@
+ #include <linux/kobj_map.h>
+ #include <linux/cdev.h>
+ #include <linux/mutex.h>
++#include <linux/backing-dev.h>
+
+ #ifdef CONFIG_KMOD
+ #include <linux/kmod.h>
+ #endif
++#include "internal.h"
++
++/*
++ * capabilities for /dev/mem, /dev/kmem and similar directly mappable character
++ * devices
++ * - permits shared-mmap for read, write and/or exec
++ * - does not permit private mmap in NOMMU mode (can't do COW)
++ * - no readahead or I/O queue unplugging required
++ */
++struct backing_dev_info directly_mappable_cdev_bdi = {
++ .capabilities = (
++#ifdef CONFIG_MMU
++ /* permit private copies of the data to be taken */
++ BDI_CAP_MAP_COPY |
++#endif
++ /* permit direct mmap, for read, write or exec */
++ BDI_CAP_MAP_DIRECT |
++ BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP),
++};
+
+ static struct kobj_map *cdev_map;
+
+@@ -109,13 +129,31 @@ __register_chrdev_region(unsigned int ma
+
+ for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
+ if ((*cp)->major > major ||
+- ((*cp)->major == major && (*cp)->baseminor >= baseminor))
++ ((*cp)->major == major &&
++ (((*cp)->baseminor >= baseminor) ||
++ ((*cp)->baseminor + (*cp)->minorct > baseminor))))
+ break;
+- if (*cp && (*cp)->major == major &&
+- (*cp)->baseminor < baseminor + minorct) {
+- ret = -EBUSY;
+- goto out;
++
++ /* Check for overlapping minor ranges. */
++ if (*cp && (*cp)->major == major) {
++ int old_min = (*cp)->baseminor;
++ int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
++ int new_min = baseminor;
++ int new_max = baseminor + minorct - 1;
++
++ /* New driver overlaps from the left. */
++ if (new_max >= old_min && new_max <= old_max) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ /* New driver overlaps from the right. */
++ if (new_min <= old_max && new_min >= old_min) {
++ ret = -EBUSY;
++ goto out;
++ }
+ }
++
+ cd->next = *cp;
+ *cp = cd;
+ mutex_unlock(&chrdevs_lock);
+@@ -146,6 +184,15 @@ __unregister_chrdev_region(unsigned majo
+ return cd;
+ }
+
++/**
++ * register_chrdev_region() - register a range of device numbers
++ * @from: the first in the desired range of device numbers; must include
++ * the major number.
++ * @count: the number of consecutive device numbers required
++ * @name: the name of the device or driver.
++ *
++ * Return value is zero on success, a negative error code on failure.
++ */
+ int register_chrdev_region(dev_t from, unsigned count, const char *name)
+ {
+ struct char_device_struct *cd;
+@@ -171,6 +218,17 @@ fail:
+ return PTR_ERR(cd);
+ }
+
++/**
++ * alloc_chrdev_region() - register a range of char device numbers
++ * @dev: output parameter for first assigned number
++ * @baseminor: first of the requested range of minor numbers
++ * @count: the number of minor numbers required
++ * @name: the name of the associated device or driver
++ *
++ * Allocates a range of char device numbers. The major number will be
++ * chosen dynamically, and returned (along with the first minor number)
++ * in @dev. Returns zero or a negative error code.
++ */
+ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
+ const char *name)
+ {
+@@ -240,6 +298,15 @@ out2:
+ return err;
+ }
+
++/**
++ * unregister_chrdev_region() - return a range of device numbers
++ * @from: the first in the range of numbers to unregister
++ * @count: the number of device numbers to unregister
++ *
++ * This function will unregister a range of @count device numbers,
++ * starting with @from. The caller should normally be the one who
++ * allocated those numbers in the first place...
++ */
+ void unregister_chrdev_region(dev_t from, unsigned count)
+ {
+ dev_t to = from + count;
+@@ -377,6 +444,16 @@ static int exact_lock(dev_t dev, void *d
+ return cdev_get(p) ? 0 : -1;
+ }
+
++/**
++ * cdev_add() - add a char device to the system
++ * @p: the cdev structure for the device
++ * @dev: the first device number for which this device is responsible
++ * @count: the number of consecutive minor numbers corresponding to this
++ * device
++ *
++ * cdev_add() adds the device represented by @p to the system, making it
++ * live immediately. A negative error code is returned on failure.
++ */
+ int cdev_add(struct cdev *p, dev_t dev, unsigned count)
+ {
+ p->dev = dev;
+@@ -389,6 +466,13 @@ static void cdev_unmap(dev_t dev, unsign
+ kobj_unmap(cdev_map, dev, count);
+ }
+
++/**
++ * cdev_del() - remove a cdev from the system
++ * @p: the cdev structure to be removed
++ *
++ * cdev_del() removes @p from the system, possibly freeing the structure
++ * itself.
++ */
+ void cdev_del(struct cdev *p)
+ {
+ cdev_unmap(p->dev, p->count);
+@@ -417,6 +501,11 @@ static struct kobj_type ktype_cdev_dynam
+ .release = cdev_dynamic_release,
+ };
+
++/**
++ * cdev_alloc() - allocate a cdev structure
++ *
++ * Allocates and returns a cdev structure, or NULL on failure.
++ */
+ struct cdev *cdev_alloc(void)
+ {
+ struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
+@@ -428,6 +517,14 @@ struct cdev *cdev_alloc(void)
+ return p;
+ }
+
++/**
++ * cdev_init() - initialize a cdev structure
++ * @cdev: the structure to initialize
++ * @fops: the file_operations for this device
++ *
++ * Initializes @cdev, remembering @fops, making it ready to add to the
++ * system with cdev_add().
++ */
+ void cdev_init(struct cdev *cdev, const struct file_operations *fops)
+ {
+ memset(cdev, 0, sizeof *cdev);
+@@ -461,3 +558,4 @@ EXPORT_SYMBOL(cdev_del);
+ EXPORT_SYMBOL(cdev_add);
+ EXPORT_SYMBOL(register_chrdev);
+ EXPORT_SYMBOL(unregister_chrdev);
++EXPORT_SYMBOL(directly_mappable_cdev_bdi);
+diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
+index 0feb3bd..0b3c37e 100644
+--- a/fs/cifs/CHANGES
++++ b/fs/cifs/CHANGES
+@@ -1,3 +1,12 @@
++Version 1.46
++------------
++Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps.
++Allow null user to be specified on mount ("username="). Do not return
++EINVAL on readdir when filldir fails due to overwritten blocksize
++(fixes FC problem). Return error in rename 2nd attempt retry (ie report
++if rename by handle also fails, after rename by path fails, we were
++not reporting whether the retry worked or not).
++
+ Version 1.45
+ ------------
+ Do not time out lockw calls when using posix extensions. Do not
+@@ -6,7 +15,8 @@ on requests on other threads. Improve P
+ (lock cancel now works, and unlock of merged range works even
+ to Windows servers now). Fix oops on mount to lanman servers
+ (win9x, os/2 etc.) when null password. Do not send listxattr
+-(SMB to query all EAs) if nouser_xattr specified.
++(SMB to query all EAs) if nouser_xattr specified. Fix SE Linux
++problem (instantiate inodes/dentries in right order for readdir).
+
+ Version 1.44
+ ------------
+diff --git a/fs/cifs/README b/fs/cifs/README
+index 5f0e1bd..432e515 100644
+--- a/fs/cifs/README
++++ b/fs/cifs/README
+@@ -269,7 +269,7 @@ A partial list of the supported mount op
+ (gid) mount option is specified. For the uid (gid) of newly
+ created files and directories, ie files created since
+ the last mount of the server share, the expected uid
+- (gid) is cached as as long as the inode remains in
++ (gid) is cached as long as the inode remains in
+ memory on the client. Also note that permission
+ checks (authorization checks) on accesses to a file occur
+ at the server, but there are cases in which an administrator
+@@ -375,7 +375,7 @@ A partial list of the supported mount op
+ the local process on newly created files, directories, and
+ devices (create, mkdir, mknod). If the CIFS Unix Extensions
+ are not negotiated, for newly created files and directories
+- instead of using the default uid and gid specified on the
++ instead of using the default uid and gid specified on
+ the mount, cache the new file's uid and gid locally which means
+ that the uid for the file can change when the inode is
+ reloaded (or the user remounts the share).
+@@ -440,7 +440,7 @@ A partial list of the supported mount op
+ create device files and fifos in a format compatible with
+ Services for Unix (SFU). In addition retrieve bits 10-12
+ of the mode via the SETFILEBITS extended attribute (as
+- SFU does). In the future the bottom 9 bits of the mode
++ SFU does). In the future the bottom 9 bits of the
+ mode also will be emulated using queries of the security
+ descriptor (ACL).
+ sign Must use packet signing (helps avoid unwanted data modification
+diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
+index ad58eb0..fd1e52e 100644
+--- a/fs/cifs/cifs_fs_sb.h
++++ b/fs/cifs/cifs_fs_sb.h
+@@ -40,5 +40,7 @@ struct cifs_sb_info {
+ mode_t mnt_file_mode;
+ mode_t mnt_dir_mode;
+ int mnt_cifs_flags;
++ int prepathlen;
++ char * prepath;
+ };
+ #endif /* _CIFS_FS_SB_H */
+diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
+index d0776ac..5eff35d 100644
+--- a/fs/cifs/cifsacl.h
++++ b/fs/cifs/cifsacl.h
+@@ -31,8 +31,8 @@ struct cifs_sid {
+ } __attribute__((packed));
+
+ /* everyone */
+-extern const struct cifs_sid sid_everyone;
++/* extern const struct cifs_sid sid_everyone;*/
+ /* group users */
+-extern const struct cifs_sid sid_user;
++/* extern const struct cifs_sid sid_user;*/
+
+ #endif /* _CIFSACL_H */
+diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
+index 03e359b..152fa2d 100644
+--- a/fs/cifs/cifsencrypt.h
++++ b/fs/cifs/cifsencrypt.h
+@@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, u
+ /* smbdes.c */
+ extern void E_P16(unsigned char *p14, unsigned char *p16);
+ extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+-extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
+-extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *);
+
+
+
+diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
+index 3cd7500..84976cd 100644
+--- a/fs/cifs/cifsfs.c
++++ b/fs/cifs/cifsfs.c
+@@ -63,6 +63,7 @@ extern struct task_struct * oplockThread
+ struct task_struct * oplockThread = NULL;
+ extern struct task_struct * dnotifyThread; /* remove sparse warning */
+ struct task_struct * dnotifyThread = NULL;
++static struct super_operations cifs_super_ops;
+ unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
+ module_param(CIFSMaxBufSize, int, 0);
+ MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
+@@ -189,7 +190,6 @@ cifs_statfs(struct dentry *dentry, struc
+ buf->f_files = 0; /* undefined */
+ buf->f_ffree = 0; /* unlimited */
+
+-#ifdef CONFIG_CIFS_EXPERIMENTAL
+ /* BB we could add a second check for a QFS Unix capability bit */
+ /* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
+ if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
+@@ -199,11 +199,12 @@ cifs_statfs(struct dentry *dentry, struc
+ /* Only need to call the old QFSInfo if failed
+ on newer one */
+ if(rc)
+-#endif /* CIFS_EXPERIMENTAL */
+- rc = CIFSSMBQFSInfo(xid, pTcon, buf);
++ if(pTcon->ses->capabilities & CAP_NT_SMBS)
++ rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
+
+- /* Old Windows servers do not support level 103, retry with level
+- one if old server failed the previous call */
++ /* Some old Windows servers also do not support level 103, retry with
++ older level one if old server failed the previous call or we
++ bypassed it because we detected that this was an older LANMAN sess */
+ if(rc)
+ rc = SMBOldQFSInfo(xid, pTcon, buf);
+ /*
+@@ -255,7 +256,6 @@ cifs_alloc_inode(struct super_block *sb)
+ file data or metadata */
+ cifs_inode->clientCanCacheRead = FALSE;
+ cifs_inode->clientCanCacheAll = FALSE;
+- cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
+ cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
+ cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
+ INIT_LIST_HEAD(&cifs_inode->openFileList);
+@@ -438,13 +438,21 @@ static void cifs_umount_begin(struct vfs
+ return;
+ }
+
++#ifdef CONFIG_CIFS_STATS2
++static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt)
++{
++ /* BB FIXME */
++ return 0;
++}
++#endif
++
+ static int cifs_remount(struct super_block *sb, int *flags, char *data)
+ {
+ *flags |= MS_NODIRATIME;
+ return 0;
+ }
+
+-struct super_operations cifs_super_ops = {
++static struct super_operations cifs_super_ops = {
+ .read_inode = cifs_read_inode,
+ .put_super = cifs_put_super,
+ .statfs = cifs_statfs,
+@@ -457,6 +465,9 @@ struct super_operations cifs_super_ops =
+ .show_options = cifs_show_options,
+ .umount_begin = cifs_umount_begin,
+ .remount_fs = cifs_remount,
++#ifdef CONFIG_CIFS_STATS2
++ .show_stats = cifs_show_stats,
++#endif
+ };
+
+ static int
+@@ -483,25 +494,13 @@ cifs_get_sb(struct file_system_type *fs_
+ return simple_set_mnt(mnt, sb);
+ }
+
+-static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct inode *inode = file->f_dentry->d_inode;
+- ssize_t written;
+-
+- written = generic_file_writev(file, iov, nr_segs, ppos);
+- if (!CIFS_I(inode)->clientCanCacheAll)
+- filemap_fdatawrite(inode->i_mapping);
+- return written;
+-}
+-
+-static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos)
++static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+ ssize_t written;
+
+- written = generic_file_aio_write(iocb, buf, count, pos);
++ written = generic_file_aio_write(iocb, iov, nr_segs, pos);
+ if (!CIFS_I(inode)->clientCanCacheAll)
+ filemap_fdatawrite(inode->i_mapping);
+ return written;
+@@ -510,7 +509,7 @@ static ssize_t cifs_file_aio_write(struc
+ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
+ {
+ /* origin == SEEK_END => we must revalidate the cached file length */
+- if (origin == 2) {
++ if (origin == SEEK_END) {
+ int retval = cifs_revalidate(file->f_dentry);
+ if (retval < 0)
+ return (loff_t)retval;
+@@ -580,8 +579,6 @@ struct inode_operations cifs_symlink_ino
+ const struct file_operations cifs_file_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+- .readv = generic_file_readv,
+- .writev = cifs_file_writev,
+ .aio_read = generic_file_aio_read,
+ .aio_write = cifs_file_aio_write,
+ .open = cifs_open,
+@@ -623,8 +620,6 @@ const struct file_operations cifs_file_d
+ const struct file_operations cifs_file_nobrl_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+- .readv = generic_file_readv,
+- .writev = cifs_file_writev,
+ .aio_read = generic_file_aio_read,
+ .aio_write = cifs_file_aio_write,
+ .open = cifs_open,
+@@ -701,8 +696,7 @@ cifs_init_inodecache(void)
+ static void
+ cifs_destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(cifs_inode_cachep))
+- printk(KERN_WARNING "cifs_inode_cache: error freeing\n");
++ kmem_cache_destroy(cifs_inode_cachep);
+ }
+
+ static int
+@@ -780,13 +774,9 @@ static void
+ cifs_destroy_request_bufs(void)
+ {
+ mempool_destroy(cifs_req_poolp);
+- if (kmem_cache_destroy(cifs_req_cachep))
+- printk(KERN_WARNING
+- "cifs_destroy_request_cache: error not all structures were freed\n");
++ kmem_cache_destroy(cifs_req_cachep);
+ mempool_destroy(cifs_sm_req_poolp);
+- if (kmem_cache_destroy(cifs_sm_req_cachep))
+- printk(KERN_WARNING
+- "cifs_destroy_request_cache: cifs_small_rq free error\n");
++ kmem_cache_destroy(cifs_sm_req_cachep);
+ }
+
+ static int
+@@ -821,13 +811,8 @@ static void
+ cifs_destroy_mids(void)
+ {
+ mempool_destroy(cifs_mid_poolp);
+- if (kmem_cache_destroy(cifs_mid_cachep))
+- printk(KERN_WARNING
+- "cifs_destroy_mids: error not all structures were freed\n");
+-
+- if (kmem_cache_destroy(cifs_oplock_cachep))
+- printk(KERN_WARNING
+- "error not all oplock structures were freed\n");
++ kmem_cache_destroy(cifs_mid_cachep);
++ kmem_cache_destroy(cifs_oplock_cachep);
+ }
+
+ static int cifs_oplock_thread(void * dummyarg)
+@@ -932,7 +917,7 @@ init_cifs(void)
+ #ifdef CONFIG_PROC_FS
+ cifs_proc_init();
+ #endif
+- INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
++/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */
+ INIT_LIST_HEAD(&GlobalSMBSessionList);
+ INIT_LIST_HEAD(&GlobalTreeConnectionList);
+ INIT_LIST_HEAD(&GlobalOplock_Q);
+@@ -960,6 +945,7 @@ init_cifs(void)
+ GlobalCurrentXid = 0;
+ GlobalTotalActiveXid = 0;
+ GlobalMaxActiveXid = 0;
++ memset(Local_System_Name, 0, 15);
+ rwlock_init(&GlobalSMBSeslock);
+ spin_lock_init(&GlobalMid_Lock);
+
+diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
+index 39ee8ef..a243f77 100644
+--- a/fs/cifs/cifsfs.h
++++ b/fs/cifs/cifsfs.h
+@@ -36,7 +36,7 @@ extern const struct address_space_operat
+ extern const struct address_space_operations cifs_addr_ops_smallbuf;
+
+ /* Functions related to super block operations */
+-extern struct super_operations cifs_super_ops;
++/* extern struct super_operations cifs_super_ops;*/
+ extern void cifs_read_inode(struct inode *);
+ extern void cifs_delete_inode(struct inode *);
+ /* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
+@@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dent
+ extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
+ extern int cifs_ioctl (struct inode * inode, struct file * filep,
+ unsigned int command, unsigned long arg);
+-#define CIFS_VERSION "1.45"
++#define CIFS_VERSION "1.46"
+ #endif /* _CIFSFS_H */
+diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
+index b24006c..74d3ccb 100644
+--- a/fs/cifs/cifsglob.h
++++ b/fs/cifs/cifsglob.h
+@@ -153,7 +153,7 @@ struct TCP_Server_Info {
+ char sessid[4]; /* unique token id for this session */
+ /* (returned on Negotiate */
+ int capabilities; /* allow selective disabling of caps by smb sess */
+- __u16 timeZone;
++ int timeAdj; /* Adjust for difference in server time zone in sec */
+ __u16 CurrentMid; /* multiplex id - rotating counter */
+ char cryptKey[CIFS_CRYPTO_KEY_SIZE];
+ /* 16th byte of RFC1001 workstation name is always null */
+@@ -203,9 +203,14 @@ struct cifsSesInfo {
+ char * domainName;
+ char * password;
+ };
+-/* session flags */
++/* no more than one of the following three session flags may be set */
+ #define CIFS_SES_NT4 1
+-
++#define CIFS_SES_OS2 2
++#define CIFS_SES_W9X 4
++/* following flag is set for old servers such as OS2 (and Win95?)
++ which do not negotiate NTLM or POSIX dialects, but instead
++ negotiate one of the older LANMAN dialects */
++#define CIFS_SES_LANMAN 8
+ /*
+ * there is one of these for each connection to a resource on a particular
+ * session
+@@ -512,7 +517,8 @@ require use of the stronger protocol */
+ * This list helps improve performance and eliminate the messages indicating
+ * that we had a communications error talking to the server in this list.
+ */
+-GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
++/* Feature not supported */
++/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
+
+ /*
+ * The following is a hash table of all the users we know about.
+@@ -568,7 +574,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEn
+ GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
+ with more secure ntlmssp2 challenge/resp */
+ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
+-GLOBAL_EXTERN unsigned int secFlags;
+ GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
+ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
+ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
+diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
+index 8623902..6df9dad 100644
+--- a/fs/cifs/cifspdu.h
++++ b/fs/cifs/cifspdu.h
+@@ -26,7 +26,8 @@
+
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+ #define LANMAN_PROT 0
+-#define CIFS_PROT 1
++#define LANMAN2_PROT 1
++#define CIFS_PROT 2
+ #else
+ #define CIFS_PROT 0
+ #endif
+@@ -408,6 +409,8 @@ typedef struct negotiate_req {
+
+ /* Dialect index is 13 for LANMAN */
+
++#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */
++
+ typedef struct lanman_neg_rsp {
+ struct smb_hdr hdr; /* wct = 13 */
+ __le16 DialectIndex;
+@@ -417,7 +420,10 @@ typedef struct lanman_neg_rsp {
+ __le16 MaxNumberVcs;
+ __le16 RawMode;
+ __le32 SessionKey;
+- __le32 ServerTime;
++ struct {
++ __le16 Time;
++ __le16 Date;
++ } __attribute__((packed)) SrvTime;
+ __le16 ServerTimeZone;
+ __le16 EncryptionKeyLength;
+ __le16 Reserved;
+@@ -674,7 +680,7 @@ typedef union smb_com_tree_disconnect {
+ typedef struct smb_com_close_req {
+ struct smb_hdr hdr; /* wct = 3 */
+ __u16 FileID;
+- __u32 LastWriteTime; /* should be zero */
++ __u32 LastWriteTime; /* should be zero or -1 */
+ __u16 ByteCount; /* 0 */
+ } __attribute__((packed)) CLOSE_REQ;
+
+@@ -1344,6 +1350,7 @@ struct smb_t2_rsp {
+ #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */
+ #define SMB_QUERY_POSIX_PERMISSION 0x207
+ #define SMB_QUERY_POSIX_LOCK 0x208
++/* #define SMB_POSIX_OPEN 0x209 */
+ #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
+ #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
+ #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
+@@ -1363,6 +1370,7 @@ struct smb_t2_rsp {
+ #define SMB_SET_XATTR 0x205
+ #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
+ #define SMB_SET_POSIX_LOCK 0x208
++#define SMB_POSIX_OPEN 0x209
+ #define SMB_SET_FILE_BASIC_INFO2 0x3ec
+ #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
+ #define SMB_FILE_ALL_INFO2 0x3fa
+diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
+index b35c55c..f1f8225 100644
+--- a/fs/cifs/cifsproto.h
++++ b/fs/cifs/cifsproto.h
+@@ -50,12 +50,12 @@ extern int SendReceive(const unsigned in
+ extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
+ struct kvec *, int /* nvec to send */,
+ int * /* type of buf returned */ , const int long_op);
+-extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
++extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
++ struct cifsTconInfo *,
+ struct smb_hdr * /* input */ ,
+ struct smb_hdr * /* out */ ,
+ int * /* bytes returned */);
+-extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
+-extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
++extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
+ extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
+ extern int is_size_safe_to_change(struct cifsInodeInfo *);
+ extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
+@@ -80,6 +80,9 @@ extern struct oplock_q_entry * AllocOplo
+ extern void DeleteOplockQEntry(struct oplock_q_entry *);
+ extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
+ extern u64 cifs_UnixTimeToNT(struct timespec);
++extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
++extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
++
+ extern int cifs_get_inode_info(struct inode **pinode,
+ const unsigned char *search_path,
+ FILE_ALL_INFO * pfile_info,
+@@ -116,6 +119,7 @@ extern int CIFSFindClose(const int, stru
+ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ FILE_ALL_INFO * findData,
++ int legacy /* whether to use old info level */,
+ const struct nls_table *nls_codepage, int remap);
+ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+@@ -279,8 +283,6 @@ extern void sesInfoFree(struct cifsSesIn
+ extern struct cifsTconInfo *tconInfoAlloc(void);
+ extern void tconInfoFree(struct cifsTconInfo *);
+
+-extern int cifs_reconnect(struct TCP_Server_Info *server);
+-
+ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
+ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
+ __u32 *);
+diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
+index 075d8fb..098790e 100644
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -46,6 +46,7 @@ static struct {
+ } protocols[] = {
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+ {LANMAN_PROT, "\2LM1.2X002"},
++ {LANMAN2_PROT, "\2LANMAN2.1"},
+ #endif /* weak password hashing for legacy clients */
+ {CIFS_PROT, "\2NT LM 0.12"},
+ {POSIX_PROT, "\2POSIX 2"},
+@@ -58,6 +59,7 @@ static struct {
+ } protocols[] = {
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+ {LANMAN_PROT, "\2LM1.2X002"},
++ {LANMAN2_PROT, "\2LANMAN2.1"},
+ #endif /* weak password hashing for legacy clients */
+ {CIFS_PROT, "\2NT LM 0.12"},
+ {BAD_PROT, "\2"}
+@@ -67,13 +69,13 @@ static struct {
+ /* define the number of elements in the cifs dialect array */
+ #ifdef CONFIG_CIFS_POSIX
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+-#define CIFS_NUM_PROT 3
++#define CIFS_NUM_PROT 4
+ #else
+ #define CIFS_NUM_PROT 2
+ #endif /* CIFS_WEAK_PW_HASH */
+ #else /* not posix */
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+-#define CIFS_NUM_PROT 2
++#define CIFS_NUM_PROT 3
+ #else
+ #define CIFS_NUM_PROT 1
+ #endif /* CONFIG_CIFS_WEAK_PW_HASH */
+@@ -397,6 +399,7 @@ CIFSSMBNegotiate(unsigned int xid, struc
+ struct TCP_Server_Info * server;
+ u16 count;
+ unsigned int secFlags;
++ u16 dialect;
+
+ if(ses->server)
+ server = ses->server;
+@@ -436,9 +439,10 @@ CIFSSMBNegotiate(unsigned int xid, struc
+ if (rc != 0)
+ goto neg_err_exit;
+
+- cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
++ dialect = le16_to_cpu(pSMBr->DialectIndex);
++ cFYI(1,("Dialect: %d", dialect));
+ /* Check wct = 1 error case */
+- if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
++ if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
+ /* core returns wct = 1, but we do not ask for core - otherwise
+ small wct just comes when dialect index is -1 indicating we
+ could not negotiate a common dialect */
+@@ -446,7 +450,9 @@ CIFSSMBNegotiate(unsigned int xid, struc
+ goto neg_err_exit;
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+ } else if((pSMBr->hdr.WordCount == 13)
+- && (pSMBr->DialectIndex == LANMAN_PROT)) {
++ && ((dialect == LANMAN_PROT)
++ || (dialect == LANMAN2_PROT))) {
++ __s16 tmp;
+ struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
+
+ if((secFlags & CIFSSEC_MAY_LANMAN) ||
+@@ -472,12 +478,44 @@ CIFSSMBNegotiate(unsigned int xid, struc
+ server->maxRw = 0;/* we do not need to use raw anyway */
+ server->capabilities = CAP_MPX_MODE;
+ }
+- server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
++ tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
++ if (tmp == -1) {
++ /* OS/2 often does not set timezone therefore
++ * we must use server time to calc time zone.
++ * Could deviate slightly from the right zone.
++ * Smallest defined timezone difference is 15 minutes
++ * (i.e. Nepal). Rounding up/down is done to match
++ * this requirement.
++ */
++ int val, seconds, remain, result;
++ struct timespec ts, utc;
++ utc = CURRENT_TIME;
++ ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
++ le16_to_cpu(rsp->SrvTime.Time));
++ cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
++ (int)ts.tv_sec, (int)utc.tv_sec,
++ (int)(utc.tv_sec - ts.tv_sec)));
++ val = (int)(utc.tv_sec - ts.tv_sec);
++ seconds = val < 0 ? -val : val;
++ result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
++ remain = seconds % MIN_TZ_ADJ;
++ if(remain >= (MIN_TZ_ADJ / 2))
++ result += MIN_TZ_ADJ;
++ if(val < 0)
++ result = - result;
++ server->timeAdj = result;
++ } else {
++ server->timeAdj = (int)tmp;
++ server->timeAdj *= 60; /* also in seconds */
++ }
++ cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
++
+
+ /* BB get server time for time conversions and add
+ code to use it and timezone since this is not UTC */
+
+- if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
++ if (rsp->EncryptionKeyLength ==
++ cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
+ memcpy(server->cryptKey, rsp->EncryptionKey,
+ CIFS_CRYPTO_KEY_SIZE);
+ } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+@@ -531,7 +569,8 @@ CIFSSMBNegotiate(unsigned int xid, struc
+ cFYI(0, ("Max buf = %d", ses->server->maxBuf));
+ GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
+ server->capabilities = le32_to_cpu(pSMBr->Capabilities);
+- server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
++ server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
++ server->timeAdj *= 60;
+ if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+ memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
+ CIFS_CRYPTO_KEY_SIZE);
+@@ -1617,7 +1656,7 @@ CIFSSMBClose(const int xid, struct cifsT
+ pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
+
+ pSMB->FileID = (__u16) smb_file_id;
+- pSMB->LastWriteTime = 0;
++ pSMB->LastWriteTime = 0xFFFFFFFF;
+ pSMB->ByteCount = 0;
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+@@ -2773,9 +2812,11 @@ GetExtAttrOut:
+
+
+ /* security id for everyone */
+-const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
++const static struct cifs_sid sid_everyone =
++ {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
+ /* group users */
+-const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
++const static struct cifs_sid sid_user =
++ {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
+
+ /* Convert CIFS ACL to POSIX form */
+ static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
+@@ -2856,7 +2897,6 @@ qsec_out:
+ return rc;
+ }
+
+-
+ /* Legacy Query Path Information call for lookup to old servers such
+ as Win9x/WinME */
+ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+@@ -2898,7 +2938,16 @@ QInfRetry:
+ if (rc) {
+ cFYI(1, ("Send error in QueryInfo = %d", rc));
+ } else if (pFinfo) { /* decode response */
++ struct timespec ts;
++ __u32 time = le32_to_cpu(pSMBr->last_write_time);
++ /* BB FIXME - add time zone adjustment BB */
+ memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
++ ts.tv_nsec = 0;
++ ts.tv_sec = time;
++ /* decode time fields */
++ pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
++ pFinfo->LastWriteTime = pFinfo->ChangeTime;
++ pFinfo->LastAccessTime = 0;
+ pFinfo->AllocationSize =
+ cpu_to_le64(le32_to_cpu(pSMBr->size));
+ pFinfo->EndOfFile = pFinfo->AllocationSize;
+@@ -2922,6 +2971,7 @@ int
+ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ FILE_ALL_INFO * pFindData,
++ int legacy /* old style infolevel */,
+ const struct nls_table *nls_codepage, int remap)
+ {
+ /* level 263 SMB_QUERY_FILE_ALL_INFO */
+@@ -2970,7 +3020,10 @@ QPathInfoRetry:
+ byte_count = params + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(params);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
++ if(legacy)
++ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
++ else
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->ByteCount = cpu_to_le16(byte_count);
+@@ -2982,13 +3035,24 @@ QPathInfoRetry:
+ } else { /* decode response */
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+- if (rc || (pSMBr->ByteCount < 40))
++ if (rc) /* BB add auto retry on EOPNOTSUPP? */
++ rc = -EIO;
++ else if (!legacy && (pSMBr->ByteCount < 40))
+ rc = -EIO; /* bad smb */
++ else if(legacy && (pSMBr->ByteCount < 24))
++ rc = -EIO; /* 24 or 26 expected but we do not read last field */
+ else if (pFindData){
++ int size;
+ __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
++ if(legacy) /* we do not read the last field, EAsize, fortunately
++ since it varies by subdialect and on Set vs. Get, is
++ two bytes or 4 bytes depending but we don't care here */
++ size = sizeof(FILE_INFO_STANDARD);
++ else
++ size = sizeof(FILE_ALL_INFO);
+ memcpy((char *) pFindData,
+ (char *) &pSMBr->hdr.Protocol +
+- data_offset, sizeof (FILE_ALL_INFO));
++ data_offset, size);
+ } else
+ rc = -ENOMEM;
+ }
+@@ -3613,6 +3677,14 @@ getDFSRetry:
+ strncpy(pSMB->RequestFileName, searchName, name_len);
+ }
+
++ if(ses->server) {
++ if(ses->server->secMode &
++ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++ }
++
++ pSMB->hdr.Uid = ses->Suid;
++
+ params = 2 /* level */ + name_len /*includes null */ ;
+ pSMB->TotalDataCount = 0;
+ pSMB->DataCount = 0;
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index 5d394c7..71f7791 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -89,6 +89,7 @@ struct smb_vol {
+ unsigned int wsize;
+ unsigned int sockopt;
+ unsigned short int port;
++ char * prepath;
+ };
+
+ static int ipv4_connect(struct sockaddr_in *psin_server,
+@@ -108,7 +109,7 @@ static int ipv6_connect(struct sockaddr_
+ * wake up waiters on reconnection? - (not needed currently)
+ */
+
+-int
++static int
+ cifs_reconnect(struct TCP_Server_Info *server)
+ {
+ int rc = 0;
+@@ -770,13 +771,18 @@ cifs_parse_mount_options(char *options,
+ separator[0] = ',';
+ separator[1] = 0;
+
+- memset(vol->source_rfc1001_name,0x20,15);
+- for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
+- /* does not have to be a perfect mapping since the field is
+- informational, only used for servers that do not support
+- port 445 and it can be overridden at mount time */
+- vol->source_rfc1001_name[i] =
+- toupper(system_utsname.nodename[i]);
++ if (Local_System_Name[0] != 0)
++ memcpy(vol->source_rfc1001_name, Local_System_Name,15);
++ else {
++ char *nodename = utsname()->nodename;
++ int n = strnlen(nodename,15);
++ memset(vol->source_rfc1001_name,0x20,15);
++ for(i=0 ; i < n ; i++) {
++ /* does not have to be perfect mapping since field is
++ informational, only used for servers that do not support
++ port 445 and it can be overridden at mount time */
++ vol->source_rfc1001_name[i] = toupper(nodename[i]);
++ }
+ }
+ vol->source_rfc1001_name[15] = 0;
+ /* null target name indicates to use *SMBSERVR default called name
+@@ -816,10 +822,13 @@ cifs_parse_mount_options(char *options,
+ } else if (strnicmp(data, "nouser_xattr",12) == 0) {
+ vol->no_xattr = 1;
+ } else if (strnicmp(data, "user", 4) == 0) {
+- if (!value || !*value) {
++ if (!value) {
+ printk(KERN_WARNING
+ "CIFS: invalid or missing username\n");
+ return 1; /* needs_arg; */
++ } else if(!*value) {
++ /* null user, ie anonymous, authentication */
++ vol->nullauth = 1;
+ }
+ if (strnlen(value, 200) < 200) {
+ vol->username = value;
+@@ -993,6 +1002,28 @@ cifs_parse_mount_options(char *options,
+ printk(KERN_WARNING "CIFS: domain name too long\n");
+ return 1;
+ }
++ } else if (strnicmp(data, "prefixpath", 10) == 0) {
++ if (!value || !*value) {
++ printk(KERN_WARNING
++ "CIFS: invalid path prefix\n");
++ return 1; /* needs_arg; */
++ }
++ if ((temp_len = strnlen(value, 1024)) < 1024) {
++ if(value[0] != '/')
++ temp_len++; /* missing leading slash */
++ vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
++ if(vol->prepath == NULL)
++ return 1;
++ if(value[0] != '/') {
++ vol->prepath[0] = '/';
++ strcpy(vol->prepath+1,value);
++ } else
++ strcpy(vol->prepath,value);
++ cFYI(1,("prefix path %s",vol->prepath));
++ } else {
++ printk(KERN_WARNING "CIFS: prefix too long\n");
++ return 1;
++ }
+ } else if (strnicmp(data, "iocharset", 9) == 0) {
+ if (!value || !*value) {
+ printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
+@@ -1605,6 +1636,7 @@ cifs_mount(struct super_block *sb, struc
+ if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+@@ -1613,12 +1645,15 @@ cifs_mount(struct super_block *sb, struc
+ /* BB fixme parse for domain name here */
+ cFYI(1, ("Username: %s ", volume_info.username));
+
++ } else if (volume_info.nullauth) {
++ cFYI(1,("null user"));
+ } else {
+ cifserror("No username specified");
+ /* In userspace mount helper we can get user name from alternate
+ locations such as env variables and files on disk */
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+@@ -1639,6 +1674,7 @@ cifs_mount(struct super_block *sb, struc
+ /* we failed translating address */
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+@@ -1651,6 +1687,7 @@ cifs_mount(struct super_block *sb, struc
+ cERROR(1,("Connecting to DFS root not implemented yet"));
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ } else /* which servers DFS root would we conect to */ {
+@@ -1658,6 +1695,7 @@ cifs_mount(struct super_block *sb, struc
+ ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+@@ -1672,6 +1710,7 @@ cifs_mount(struct super_block *sb, struc
+ cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -ELIBACC;
+ }
+@@ -1688,6 +1727,7 @@ cifs_mount(struct super_block *sb, struc
+ else {
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+@@ -1710,6 +1750,7 @@ cifs_mount(struct super_block *sb, struc
+ sock_release(csocket);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return rc;
+ }
+@@ -1720,6 +1761,7 @@ cifs_mount(struct super_block *sb, struc
+ sock_release(csocket);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return rc;
+ } else {
+@@ -1744,6 +1786,7 @@ cifs_mount(struct super_block *sb, struc
+ sock_release(csocket);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return rc;
+ }
+@@ -1831,6 +1874,14 @@ cifs_mount(struct super_block *sb, struc
+ /* Windows ME may prefer this */
+ cFYI(1,("readsize set to minimum 2048"));
+ }
++ /* calculate prepath */
++ cifs_sb->prepath = volume_info.prepath;
++ if(cifs_sb->prepath) {
++ cifs_sb->prepathlen = strlen(cifs_sb->prepath);
++ cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
++ volume_info.prepath = NULL;
++ } else
++ cifs_sb->prepathlen = 0;
+ cifs_sb->mnt_uid = volume_info.linux_uid;
+ cifs_sb->mnt_gid = volume_info.linux_gid;
+ cifs_sb->mnt_file_mode = volume_info.file_mode;
+@@ -2008,6 +2059,7 @@ cifs_mount(struct super_block *sb, struc
+ the password ptr is put in the new session structure (in which case the
+ password will be freed at unmount time) */
+ kfree(volume_info.UNC);
++ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return rc;
+ }
+@@ -2111,7 +2163,7 @@ CIFSSessSetup(unsigned int xid, struct c
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
++ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+@@ -2138,8 +2190,8 @@ CIFSSessSetup(unsigned int xid, struct c
+ }
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+- strcpy(bcc_ptr, system_utsname.release);
+- bcc_ptr += strlen(system_utsname.release) + 1;
++ strcpy(bcc_ptr, utsname()->release);
++ bcc_ptr += strlen(utsname()->release) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ }
+@@ -2403,7 +2455,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
++ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2; /* null terminate Linux version */
+@@ -2420,8 +2472,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i
+ } else { /* ASCII */
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+- strcpy(bcc_ptr, system_utsname.release);
+- bcc_ptr += strlen(system_utsname.release) + 1;
++ strcpy(bcc_ptr, utsname()->release);
++ bcc_ptr += strlen(utsname()->release) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ bcc_ptr++; /* empty domain field */
+@@ -2794,7 +2846,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
++ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2; /* null term version string */
+@@ -2846,8 +2898,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi
+
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+- strcpy(bcc_ptr, system_utsname.release);
+- bcc_ptr += strlen(system_utsname.release) + 1;
++ strcpy(bcc_ptr, utsname()->release);
++ bcc_ptr += strlen(utsname()->release) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ bcc_ptr++; /* null domain */
+@@ -3173,7 +3225,9 @@ CIFSTCon(unsigned int xid, struct cifsSe
+ }
+ /* else do not bother copying these informational fields */
+ }
+- if(smb_buffer_response->WordCount == 3)
++ if((smb_buffer_response->WordCount == 3) ||
++ (smb_buffer_response->WordCount == 7))
++ /* field is in same location */
+ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+ else
+ tcon->Flags = 0;
+@@ -3195,6 +3249,7 @@ cifs_umount(struct super_block *sb, stru
+ int xid;
+ struct cifsSesInfo *ses = NULL;
+ struct task_struct *cifsd_task;
++ char * tmp;
+
+ xid = GetXid();
+
+@@ -3228,6 +3283,10 @@ cifs_umount(struct super_block *sb, stru
+ }
+
+ cifs_sb->tcon = NULL;
++ tmp = cifs_sb->prepath;
++ cifs_sb->prepathlen = 0;
++ cifs_sb->prepath = NULL;
++ kfree(tmp);
+ if (ses)
+ schedule_timeout_interruptible(msecs_to_jiffies(500));
+ if (ses)
+@@ -3265,19 +3324,21 @@ int cifs_setup_session(unsigned int xid,
+ first_time = 1;
+ }
+ if (!rc) {
++ pSesInfo->flags = 0;
+ pSesInfo->capabilities = pSesInfo->server->capabilities;
+ if(linuxExtEnabled == 0)
+ pSesInfo->capabilities &= (~CAP_UNIX);
+ /* pSesInfo->sequence_number = 0;*/
+- cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
++ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
+ pSesInfo->server->secMode,
+ pSesInfo->server->capabilities,
+- pSesInfo->server->timeZone));
++ pSesInfo->server->timeAdj));
+ if(experimEnabled < 2)
+ rc = CIFS_SessSetup(xid, pSesInfo,
+ first_time, nls_info);
+ else if (extended_security
+- && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
++ && (pSesInfo->capabilities
++ & CAP_EXTENDED_SECURITY)
+ && (pSesInfo->server->secType == NTLMSSP)) {
+ rc = -EOPNOTSUPP;
+ } else if (extended_security
+@@ -3291,7 +3352,7 @@ int cifs_setup_session(unsigned int xid,
+ if (!rc) {
+ if(ntlmv2_flag) {
+ char * v2_response;
+- cFYI(1,("Can use more secure NTLM version 2 password hash"));
++ cFYI(1,("more secure NTLM ver2 hash"));
+ if(CalcNTLMv2_partial_mac_key(pSesInfo,
+ nls_info)) {
+ rc = -ENOMEM;
+diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
+index 914239d..66b825a 100644
+--- a/fs/cifs/dir.c
++++ b/fs/cifs/dir.c
+@@ -46,7 +46,8 @@ char *
+ build_path_from_dentry(struct dentry *direntry)
+ {
+ struct dentry *temp;
+- int namelen = 0;
++ int namelen;
++ int pplen;
+ char *full_path;
+ char dirsep;
+
+@@ -56,7 +57,9 @@ build_path_from_dentry(struct dentry *di
+ when the server crashed */
+
+ dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
++ pplen = CIFS_SB(direntry->d_sb)->prepathlen;
+ cifs_bp_rename_retry:
++ namelen = pplen;
+ for (temp = direntry; !IS_ROOT(temp);) {
+ namelen += (1 + temp->d_name.len);
+ temp = temp->d_parent;
+@@ -70,7 +73,6 @@ cifs_bp_rename_retry:
+ if(full_path == NULL)
+ return full_path;
+ full_path[namelen] = 0; /* trailing null */
+-
+ for (temp = direntry; !IS_ROOT(temp);) {
+ namelen -= 1 + temp->d_name.len;
+ if (namelen < 0) {
+@@ -79,7 +81,7 @@ cifs_bp_rename_retry:
+ full_path[namelen] = dirsep;
+ strncpy(full_path + namelen + 1, temp->d_name.name,
+ temp->d_name.len);
+- cFYI(0, (" name: %s ", full_path + namelen));
++ cFYI(0, ("name: %s", full_path + namelen));
+ }
+ temp = temp->d_parent;
+ if(temp == NULL) {
+@@ -88,18 +90,23 @@ cifs_bp_rename_retry:
+ return NULL;
+ }
+ }
+- if (namelen != 0) {
++ if (namelen != pplen) {
+ cERROR(1,
+- ("We did not end path lookup where we expected namelen is %d",
++ ("did not end path lookup where expected namelen is %d",
+ namelen));
+- /* presumably this is only possible if we were racing with a rename
++ /* presumably this is only possible if racing with a rename
+ of one of the parent directories (we can not lock the dentries
+ above us to prevent this, but retrying should be harmless) */
+ kfree(full_path);
+- namelen = 0;
+ goto cifs_bp_rename_retry;
+ }
+-
++ /* DIR_SEP already set for byte 0 / vs \ but not for
++ subsequent slashes in prepath which currently must
++ be entered the right way - not sure if there is an alternative
++ since the '\' is a valid posix character so we can not switch
++ those safely to '/' if any are found in the middle of the prepath */
++ /* BB test paths to Windows with '/' in the midst of prepath */
++ strncpy(full_path,CIFS_SB(direntry->d_sb)->prepath,pplen);
+ return full_path;
+ }
+
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index e9c5ba9..7e056b9 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -25,7 +25,6 @@
+ #include <linux/backing-dev.h>
+ #include <linux/stat.h>
+ #include <linux/fcntl.h>
+-#include <linux/mpage.h>
+ #include <linux/pagemap.h>
+ #include <linux/pagevec.h>
+ #include <linux/smp_lock.h>
+@@ -752,6 +751,7 @@ int cifs_lock(struct file *file, int cmd
+ int stored_rc = 0;
+ struct cifsLockInfo *li, *tmp;
+
++ rc = 0;
+ down(&fid->lock_sem);
+ list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
+ if (pfLock->fl_start <= li->offset &&
+@@ -766,7 +766,7 @@ int cifs_lock(struct file *file, int cmd
+ kfree(li);
+ }
+ }
+- up(&fid->lock_sem);
++ up(&fid->lock_sem);
+ }
+ }
+
+@@ -1806,13 +1806,6 @@ static int cifs_readpages(struct file *f
+ }
+ if ((rc < 0) || (smb_read_data == NULL)) {
+ cFYI(1, ("Read error in readpages: %d", rc));
+- /* clean up remaing pages off list */
+- while (!list_empty(page_list) && (i < num_pages)) {
+- page = list_entry(page_list->prev, struct page,
+- lru);
+- list_del(&page->lru);
+- page_cache_release(page);
+- }
+ break;
+ } else if (bytes_read > 0) {
+ pSMBr = (struct smb_com_read_rsp *)smb_read_data;
+@@ -1831,13 +1824,7 @@ static int cifs_readpages(struct file *f
+ this case is ok - if we are at server EOF
+ we will hit it on next read */
+
+- /* while (!list_empty(page_list) && (i < num_pages)) {
+- page = list_entry(page_list->prev,
+- struct page, list);
+- list_del(&page->list);
+- page_cache_release(page);
+- }
+- break; */
++ /* break; */
+ }
+ } else {
+ cFYI(1, ("No bytes read (%d) at offset %lld . "
+@@ -1845,14 +1832,6 @@ static int cifs_readpages(struct file *f
+ bytes_read, offset));
+ /* BB turn off caching and do new lookup on
+ file size at server? */
+- while (!list_empty(page_list) && (i < num_pages)) {
+- page = list_entry(page_list->prev, struct page,
+- lru);
+- list_del(&page->lru);
+-
+- /* BB removeme - replace with zero of page? */
+- page_cache_release(page);
+- }
+ break;
+ }
+ if (smb_read_data) {
+diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
+index b88147c..dffe295 100644
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -19,7 +19,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #include <linux/fs.h>
+-#include <linux/buffer_head.h>
+ #include <linux/stat.h>
+ #include <linux/pagemap.h>
+ #include <asm/div64.h>
+@@ -338,6 +337,7 @@ int cifs_get_inode_info(struct inode **p
+ pfindData = (FILE_ALL_INFO *)buf;
+ /* could do find first instead but this returns more info */
+ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
++ 0 /* not legacy */,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ /* BB optimize code so we do not make the above call
+@@ -385,8 +385,10 @@ int cifs_get_inode_info(struct inode **p
+ /* get new inode */
+ if (*pinode == NULL) {
+ *pinode = new_inode(sb);
+- if (*pinode == NULL)
++ if (*pinode == NULL) {
++ kfree(buf);
+ return -ENOMEM;
++ }
+ /* Is an i_ino of zero legal? Can we use that to check
+ if the server supports returning inode numbers? Are
+ there other sanity checks we can use to ensure that
+@@ -432,8 +434,11 @@ int cifs_get_inode_info(struct inode **p
+ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
+
+ /* Linux can not store file creation time so ignore it */
+- inode->i_atime =
+- cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
++ if(pfindData->LastAccessTime)
++ inode->i_atime = cifs_NTtimeToUnix
++ (le64_to_cpu(pfindData->LastAccessTime));
++ else /* do not need to use current_fs_time - time not stored */
++ inode->i_atime = CURRENT_TIME;
+ inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+ inode->i_ctime =
+@@ -591,7 +596,7 @@ int cifs_unlink(struct inode *inode, str
+
+ if (!rc) {
+ if (direntry->d_inode)
+- direntry->d_inode->i_nlink--;
++ drop_nlink(direntry->d_inode);
+ } else if (rc == -ENOENT) {
+ d_drop(direntry);
+ } else if (rc == -ETXTBSY) {
+@@ -610,7 +615,7 @@ int cifs_unlink(struct inode *inode, str
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ CIFSSMBClose(xid, pTcon, netfid);
+ if (direntry->d_inode)
+- direntry->d_inode->i_nlink--;
++ drop_nlink(direntry->d_inode);
+ }
+ } else if (rc == -EACCES) {
+ /* try only if r/o attribute set in local lookup data? */
+@@ -664,7 +669,7 @@ int cifs_unlink(struct inode *inode, str
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (!rc) {
+ if (direntry->d_inode)
+- direntry->d_inode->i_nlink--;
++ drop_nlink(direntry->d_inode);
+ } else if (rc == -ETXTBSY) {
+ int oplock = FALSE;
+ __u16 netfid;
+@@ -685,7 +690,7 @@ int cifs_unlink(struct inode *inode, str
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ CIFSSMBClose(xid, pTcon, netfid);
+ if (direntry->d_inode)
+- direntry->d_inode->i_nlink--;
++ drop_nlink(direntry->d_inode);
+ }
+ /* BB if rc = -ETXTBUSY goto the rename logic BB */
+ }
+@@ -736,7 +741,7 @@ int cifs_mkdir(struct inode *inode, stru
+ cFYI(1, ("cifs_mkdir returned 0x%x", rc));
+ d_drop(direntry);
+ } else {
+- inode->i_nlink++;
++ inc_nlink(inode);
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&newinode, full_path,
+ inode->i_sb,xid);
+@@ -817,9 +822,9 @@ int cifs_rmdir(struct inode *inode, stru
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ if (!rc) {
+- inode->i_nlink--;
++ drop_nlink(inode);
+ i_size_write(direntry->d_inode,0);
+- direntry->d_inode->i_nlink = 0;
++ clear_nlink(direntry->d_inode);
+ }
+
+ cifsInode = CIFS_I(direntry->d_inode);
+@@ -880,10 +885,14 @@ int cifs_rename(struct inode *source_ino
+ kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ if (info_buf_source != NULL) {
+ info_buf_target = info_buf_source + 1;
+- rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
+- info_buf_source, cifs_sb_source->local_nls,
+- cifs_sb_source->mnt_cifs_flags &
+- CIFS_MOUNT_MAP_SPECIAL_CHR);
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
++ info_buf_source,
++ cifs_sb_source->local_nls,
++ cifs_sb_source->mnt_cifs_flags &
++ CIFS_MOUNT_MAP_SPECIAL_CHR);
++ /* else rc is still EEXIST so will fall through to
++ unlink the target and retry rename */
+ if (rc == 0) {
+ rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
+ info_buf_target,
+@@ -932,7 +941,7 @@ int cifs_rename(struct inode *source_ino
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc==0) {
+- CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
++ rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
+index b0ea668..e34c7db 100644
+--- a/fs/cifs/ioctl.c
++++ b/fs/cifs/ioctl.c
+@@ -22,7 +22,6 @@
+ */
+
+ #include <linux/fs.h>
+-#include <linux/ext2_fs.h>
+ #include "cifspdu.h"
+ #include "cifsglob.h"
+ #include "cifsproto.h"
+@@ -74,7 +73,7 @@ int cifs_ioctl (struct inode * inode, st
+ }
+ break;
+ #ifdef CONFIG_CIFS_POSIX
+- case EXT2_IOC_GETFLAGS:
++ case FS_IOC_GETFLAGS:
+ if(CIFS_UNIX_EXTATTR_CAP & caps) {
+ if (pSMBFile == NULL)
+ break;
+@@ -82,12 +81,12 @@ int cifs_ioctl (struct inode * inode, st
+ &ExtAttrBits, &ExtAttrMask);
+ if(rc == 0)
+ rc = put_user(ExtAttrBits &
+- EXT2_FL_USER_VISIBLE,
++ FS_FL_USER_VISIBLE,
+ (int __user *)arg);
+ }
+ break;
+
+- case EXT2_IOC_SETFLAGS:
++ case FS_IOC_SETFLAGS:
+ if(CIFS_UNIX_EXTATTR_CAP & caps) {
+ if(get_user(ExtAttrBits,(int __user *)arg)) {
+ rc = -EFAULT;
+diff --git a/fs/cifs/link.c b/fs/cifs/link.c
+index a57f5d6..0bee8b7 100644
+--- a/fs/cifs/link.c
++++ b/fs/cifs/link.c
+@@ -254,7 +254,11 @@ cifs_readlink(struct dentry *direntry, c
+ tmpbuffer,
+ len - 1,
+ cifs_sb->local_nls);
+- else {
++ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
++ cERROR(1,("SFU style symlinks not implemented yet"));
++ /* add open and read as in fs/cifs/inode.c */
++
++ } else {
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
+ OPEN_REPARSE_POINT,&fid, &oplock, NULL,
+ cifs_sb->local_nls,
+diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
+index 7aa2349..ccebf9b 100644
+--- a/fs/cifs/md5.c
++++ b/fs/cifs/md5.c
+@@ -252,10 +252,11 @@ MD5Transform(__u32 buf[4], __u32 const i
+ buf[3] += d;
+ }
+
++#if 0 /* currently unused */
+ /***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+ ***********************************************************************/
+-void
++static void
+ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx)
+ {
+@@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+ }
++#endif
+
+ /***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+@@ -350,7 +352,8 @@ hmac_md5_final(unsigned char *digest, st
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+ ************************************************************/
+-void
++#if 0 /* currently unused */
++static void
+ hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+ unsigned char *digest)
+ {
+@@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned
+ }
+ hmac_md5_final(digest, &ctx);
+ }
++#endif
+diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h
+index 00e1c53..f7d4f41 100644
+--- a/fs/cifs/md5.h
++++ b/fs/cifs/md5.h
+@@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16],
+
+ /* The following definitions come from lib/hmacmd5.c */
+
+-void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+- struct HMACMD5Context *ctx);
++/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
++ struct HMACMD5Context *ctx);*/
+ void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx);
+ void hmac_md5_update(const unsigned char *text, int text_len,
+ struct HMACMD5Context *ctx);
+ void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
+-void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+- unsigned char *digest);
++/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
++ unsigned char *digest);*/
+diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
+index 22c937e..bbc9cd3 100644
+--- a/fs/cifs/misc.c
++++ b/fs/cifs/misc.c
+@@ -389,7 +389,7 @@ header_assemble(struct smb_hdr *buffer,
+ return;
+ }
+
+-int
++static int
+ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
+ {
+ /* Make sure that this really is an SMB, that it is a response,
+@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 m
+ }
+
+ int
+-checkSMB(struct smb_hdr *smb, __u16 mid, int length)
++checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
+ {
+ __u32 len = smb->smb_buf_length;
+ __u32 clc_len; /* calculated length */
+ cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
+- if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
+- (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
+- if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
+- if (((unsigned int)length >=
+- sizeof (struct smb_hdr) - 1)
++
++ if (length < 2 + sizeof (struct smb_hdr)) {
++ if ((length >= sizeof (struct smb_hdr) - 1)
+ && (smb->Status.CifsError != 0)) {
+- smb->WordCount = 0;
+- /* some error cases do not return wct and bcc */
++ smb->WordCount = 0;
++ /* some error cases do not return wct and bcc */
++ return 0;
++ } else if ((length == sizeof(struct smb_hdr) + 1) &&
++ (smb->WordCount == 0)) {
++ char * tmp = (char *)smb;
++ /* Need to work around a bug in two servers here */
++ /* First, check if the part of bcc they sent was zero */
++ if (tmp[sizeof(struct smb_hdr)] == 0) {
++ /* some servers return only half of bcc
++ * on simple responses (wct, bcc both zero)
++ * in particular have seen this on
++ * ulogoffX and FindClose. This leaves
++ * one byte of bcc potentially unitialized
++ */
++ /* zero rest of bcc */
++ tmp[sizeof(struct smb_hdr)+1] = 0;
+ return 0;
+- } else {
+- cERROR(1, ("Length less than smb header size"));
+ }
++ cERROR(1,("rcvd invalid byte count (bcc)"));
++ } else {
++ cERROR(1, ("Length less than smb header size"));
+ }
+- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
+- cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
++ return 1;
++ }
++ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
++ cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
+ smb->Mid));
+ return 1;
+ }
+@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid,
+ return 1;
+ clc_len = smbCalcSize_LE(smb);
+
+- if(4 + len != (unsigned int)length) {
++ if(4 + len != length) {
+ cERROR(1, ("Length read does not match RFC1001 length %d",len));
+ return 1;
+ }
+diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
+index ce87550..992e80e 100644
+--- a/fs/cifs/netmisc.c
++++ b/fs/cifs/netmisc.c
+@@ -909,3 +909,61 @@ cifs_UnixTimeToNT(struct timespec t)
+ /* Convert to 100ns intervals and then add the NTFS time offset. */
+ return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
+ }
++
++static int total_days_of_prev_months[] =
++{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
++
++
++__le64 cnvrtDosCifsTm(__u16 date, __u16 time)
++{
++ return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time)));
++}
++
++struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
++{
++ struct timespec ts;
++ int sec, min, days, month, year;
++ SMB_TIME * st = (SMB_TIME *)&time;
++ SMB_DATE * sd = (SMB_DATE *)&date;
++
++ cFYI(1,("date %d time %d",date, time));
++
++ sec = 2 * st->TwoSeconds;
++ min = st->Minutes;
++ if((sec > 59) || (min > 59))
++ cERROR(1,("illegal time min %d sec %d", min, sec));
++ sec += (min * 60);
++ sec += 60 * 60 * st->Hours;
++ if(st->Hours > 24)
++ cERROR(1,("illegal hours %d",st->Hours));
++ days = sd->Day;
++ month = sd->Month;
++ if((days > 31) || (month > 12))
++ cERROR(1,("illegal date, month %d day: %d", month, days));
++ month -= 1;
++ days += total_days_of_prev_months[month];
++ days += 3652; /* account for difference in days between 1980 and 1970 */
++ year = sd->Year;
++ days += year * 365;
++ days += (year/4); /* leap year */
++ /* generalized leap year calculation is more complex, ie no leap year
++ for years/100 except for years/400, but since the maximum number for DOS
++ year is 2**7, the last year is 1980+127, which means we need only
++ consider 2 special case years, ie the years 2000 and 2100, and only
++ adjust for the lack of leap year for the year 2100, as 2000 was a
++ leap year (divisable by 400) */
++ if(year >= 120) /* the year 2100 */
++ days = days - 1; /* do not count leap year for the year 2100 */
++
++ /* adjust for leap year where we are still before leap day */
++ if(year != 120)
++ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
++ sec += 24 * 60 * 60 * days;
++
++ ts.tv_sec = sec;
++
++ /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */
++
++ ts.tv_nsec = 0;
++ return ts;
++}
+diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
+index 9aeb58a..ed18c39 100644
+--- a/fs/cifs/readdir.c
++++ b/fs/cifs/readdir.c
+@@ -106,6 +106,17 @@ static int construct_dentry(struct qstr
+ return rc;
+ }
+
++static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
++{
++ if((tcon) && (tcon->ses) && (tcon->ses->server)) {
++ inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
++ inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
++ inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
++ }
++ return;
++}
++
++
+ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
+ char * buf, int *pobject_type, int isNewInode)
+ {
+@@ -135,16 +146,23 @@ static void fill_in_inode(struct inode *
+ tmp_inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+ } else { /* legacy, OS2 and DOS style */
++/* struct timespec ts;*/
+ FIND_FILE_STANDARD_INFO * pfindData =
+ (FIND_FILE_STANDARD_INFO *)buf;
+
++ tmp_inode->i_mtime = cnvrtDosUnixTm(
++ le16_to_cpu(pfindData->LastWriteDate),
++ le16_to_cpu(pfindData->LastWriteTime));
++ tmp_inode->i_atime = cnvrtDosUnixTm(
++ le16_to_cpu(pfindData->LastAccessDate),
++ le16_to_cpu(pfindData->LastAccessTime));
++ tmp_inode->i_ctime = cnvrtDosUnixTm(
++ le16_to_cpu(pfindData->LastWriteDate),
++ le16_to_cpu(pfindData->LastWriteTime));
++ AdjustForTZ(cifs_sb->tcon, tmp_inode);
+ attr = le16_to_cpu(pfindData->Attributes);
+ allocation_size = le32_to_cpu(pfindData->AllocationSize);
+ end_of_file = le32_to_cpu(pfindData->DataSize);
+- tmp_inode->i_atime = CURRENT_TIME;
+- /* tmp_inode->i_mtime = BB FIXME - add dos time handling
+- tmp_inode->i_ctime = 0; BB FIXME */
+-
+ }
+
+ /* Linux can not store file creation time unfortunately so ignore it */
+@@ -216,10 +234,9 @@ static void fill_in_inode(struct inode *
+
+ if (allocation_size < end_of_file)
+ cFYI(1, ("May be sparse file, allocation less than file size"));
+- cFYI(1, ("File Size %ld and blocks %llu and blocksize %ld",
++ cFYI(1, ("File Size %ld and blocks %llu",
+ (unsigned long)tmp_inode->i_size,
+- (unsigned long long)tmp_inode->i_blocks,
+- tmp_inode->i_blksize));
++ (unsigned long long)tmp_inode->i_blocks));
+ if (S_ISREG(tmp_inode->i_mode)) {
+ cFYI(1, ("File inode"));
+ tmp_inode->i_op = &cifs_file_inode_ops;
+@@ -879,6 +896,10 @@ static int cifs_filldir(char *pfindEntry
+ tmp_inode->i_ino,obj_type);
+ if(rc) {
+ cFYI(1,("filldir rc = %d",rc));
++ /* we can not return filldir errors to the caller
++ since they are "normal" when the stat blocksize
++ is too small - we return remapped error instead */
++ rc = -EOVERFLOW;
+ }
+
+ dput(tmp_dentry);
+@@ -939,6 +960,7 @@ static int cifs_save_resume_key(const ch
+ filename = &pFindData->FileName[0];
+ /* one byte length, no name conversion */
+ len = (unsigned int)pFindData->FileNameLength;
++ cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+ } else {
+ cFYI(1,("Unknown findfirst level %d",level));
+ return -EINVAL;
+@@ -1056,6 +1078,11 @@ int cifs_readdir(struct file *file, void
+ we want to check for that here? */
+ rc = cifs_filldir(current_entry, file,
+ filldir, direntry, tmp_buf, max_len);
++ if(rc == -EOVERFLOW) {
++ rc = 0;
++ break;
++ }
++
+ file->f_pos++;
+ if(file->f_pos ==
+ cifsFile->srch_inf.index_of_last_entry) {
+diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
+index d1705ab..a8a0835 100644
+--- a/fs/cifs/sess.c
++++ b/fs/cifs/sess.c
+@@ -111,7 +111,7 @@ static void unicode_ssetup_strings(char
+ bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
+ nls_cp);
+ bcc_ptr += 2 * bytes_ret;
+- bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
++ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release,
+ 32, nls_cp);
+ bcc_ptr += 2 * bytes_ret;
+ bcc_ptr += 2; /* trailing null */
+@@ -158,8 +158,8 @@ static void ascii_ssetup_strings(char **
+
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+- strcpy(bcc_ptr, system_utsname.release);
+- bcc_ptr += strlen(system_utsname.release) + 1;
++ strcpy(bcc_ptr, init_utsname()->release);
++ bcc_ptr += strlen(init_utsname()->release) + 1;
+
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+@@ -268,6 +268,10 @@ static int decode_ascii_ssetup(char ** p
+ ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
+ if(ses->serverOS)
+ strncpy(ses->serverOS, bcc_ptr, len);
++ if(strncmp(ses->serverOS, "OS/2",4) == 0) {
++ cFYI(1,("OS/2 server"));
++ ses->flags |= CIFS_SES_OS2;
++ }
+
+ bcc_ptr += len + 1;
+ bleft -= len + 1;
+@@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** p
+ if(len > bleft)
+ return rc;
+
+- if(ses->serverDomain)
+- kfree(ses->serverDomain);
+-
+- ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
+- if(ses->serverOS)
+- strncpy(ses->serverOS, bcc_ptr, len);
+-
+- bcc_ptr += len + 1;
+- bleft -= len + 1;
+-
++ /* No domain field in LANMAN case. Domain is
++ returned by old servers in the SMB negprot response */
++ /* BB For newer servers which do not support Unicode,
++ but thus do return domain here we could add parsing
++ for it later, but it is not very important */
+ cFYI(1,("ascii: bytes left %d",bleft));
+
+ return rc;
+@@ -366,6 +365,8 @@ CIFS_SessSetup(unsigned int xid, struct
+ str_area = kmalloc(2000, GFP_KERNEL);
+ bcc_ptr = str_area;
+
++ ses->flags &= ~CIFS_SES_LANMAN;
++
+ if(type == LANMAN) {
+ #ifdef CONFIG_CIFS_WEAK_PW_HASH
+ char lnm_session_key[CIFS_SESS_KEY_SIZE];
+@@ -377,7 +378,7 @@ CIFS_SessSetup(unsigned int xid, struct
+ /* and copy into bcc */
+
+ calc_lanman_hash(ses, lnm_session_key);
+-
++ ses->flags |= CIFS_SES_LANMAN;
+ /* #ifdef CONFIG_CIFS_DEBUG2
+ cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
+ CIFS_SESS_KEY_SIZE);
+diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
+index efaa044..7a1b2b9 100644
+--- a/fs/cifs/smbdes.c
++++ b/fs/cifs/smbdes.c
+@@ -364,20 +364,20 @@ E_P24(unsigned char *p21, unsigned char
+ smbhash(p24 + 16, c8, p21 + 14, 1);
+ }
+
+-void
++#if 0 /* currently unsued */
++static void
+ D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
+ {
+ smbhash(out, in, p14, 0);
+ smbhash(out + 8, in + 8, p14 + 7, 0);
+ }
+
+-void
++static void
+ E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
+ {
+ smbhash(out, in, p14, 1);
+ smbhash(out + 8, in + 8, p14 + 7, 1);
+ }
+-#if 0
+ /* these routines are currently unneeded, but may be
+ needed later */
+ void
+diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
+index f518c5e..4b25ba9 100644
+--- a/fs/cifs/smbencrypt.c
++++ b/fs/cifs/smbencrypt.c
+@@ -51,11 +51,8 @@
+
+ void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+ void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+-void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
+ static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+ unsigned char p24[24]);
+-void NTLMSSPOWFencrypt(unsigned char passwd[8],
+- unsigned char *ntlmchalresp, unsigned char p24[24]);
+ void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+
+ /*
+@@ -144,8 +141,9 @@ E_md4hash(const unsigned char *passwd, u
+ memset(wpwd,0,129 * 2);
+ }
+
++#if 0 /* currently unused */
+ /* Does both the NT and LM owfs of a user's password */
+-void
++static void
+ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
+ {
+ char passwd[514];
+@@ -171,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char n
+ /* clear out local copy of user's password (just being paranoid). */
+ memset(passwd, '\0', sizeof (passwd));
+ }
++#endif
+
+ /* Does the NTLMv2 owfs of a user's password */
+ #if 0 /* function not needed yet - but will be soon */
+@@ -223,7 +222,8 @@ SMBOWFencrypt(unsigned char passwd[16],
+ }
+
+ /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
+-void
++#if 0 /* currently unused */
++static void
+ NTLMSSPOWFencrypt(unsigned char passwd[8],
+ unsigned char *ntlmchalresp, unsigned char p24[24])
+ {
+@@ -235,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8
+
+ E_P24(p21, ntlmchalresp, p24);
+ }
++#endif
+
+ /* Does the NT MD4 hash then des encryption. */
+
+diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
+index 067648b..18fcec1 100644
+--- a/fs/cifs/xattr.c
++++ b/fs/cifs/xattr.c
+@@ -269,7 +269,7 @@ ssize_t cifs_getxattr(struct dentry * di
+ rc = CIFSSMBGetCIFSACL(xid, pTcon, fid,
+ ea_value, buf_size,
+ ACL_TYPE_ACCESS);
+- CIFSSMBClose(xid, pTcon, fid)
++ CIFSSMBClose(xid, pTcon, fid);
+ }
+ } */ /* BB enable after fixing up return data */
+
+diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
+index 5597080..95a5425 100644
+--- a/fs/coda/coda_linux.c
++++ b/fs/coda/coda_linux.c
+@@ -110,8 +110,6 @@ void coda_vattr_to_iattr(struct inode *i
+ inode->i_nlink = attr->va_nlink;
+ if (attr->va_size != -1)
+ inode->i_size = attr->va_size;
+- if (attr->va_blocksize != -1)
+- inode->i_blksize = attr->va_blocksize;
+ if (attr->va_size != -1)
+ inode->i_blocks = (attr->va_size + 511) >> 9;
+ if (attr->va_atime.tv_sec != -1)
+diff --git a/fs/coda/dir.c b/fs/coda/dir.c
+index 71f2ea6..0102b28 100644
+--- a/fs/coda/dir.c
++++ b/fs/coda/dir.c
+@@ -304,7 +304,7 @@ static int coda_link(struct dentry *sour
+ coda_dir_changed(dir_inode, 0);
+ atomic_inc(&inode->i_count);
+ d_instantiate(de, inode);
+- inode->i_nlink++;
++ inc_nlink(inode);
+
+ out:
+ unlock_kernel();
+@@ -367,7 +367,7 @@ int coda_unlink(struct inode *dir, struc
+ }
+
+ coda_dir_changed(dir, 0);
+- de->d_inode->i_nlink--;
++ drop_nlink(de->d_inode);
+ unlock_kernel();
+
+ return 0;
+@@ -394,7 +394,7 @@ int coda_rmdir(struct inode *dir, struct
+ }
+
+ coda_dir_changed(dir, -1);
+- de->d_inode->i_nlink--;
++ drop_nlink(de->d_inode);
+ d_delete(de);
+ unlock_kernel();
+
+@@ -513,7 +513,7 @@ static int coda_venus_readdir(struct fil
+ ino_t ino;
+ int ret, i;
+
+- vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
++ vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
+ if (!vdir) return -ENOMEM;
+
+ i = filp->f_pos;
+diff --git a/fs/coda/inode.c b/fs/coda/inode.c
+index 87f1dc8..88d1233 100644
+--- a/fs/coda/inode.c
++++ b/fs/coda/inode.c
+@@ -80,8 +80,7 @@ int coda_init_inodecache(void)
+
+ void coda_destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(coda_inode_cachep))
+- printk(KERN_INFO "coda_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(coda_inode_cachep);
+ }
+
+ static int coda_remount(struct super_block *sb, int *flags, char *data)
+diff --git a/fs/compat.c b/fs/compat.c
+index e31e9cf..8d0a001 100644
+--- a/fs/compat.c
++++ b/fs/compat.c
+@@ -44,7 +44,7 @@
+ #include <linux/nfsd/syscall.h>
+ #include <linux/personality.h>
+ #include <linux/rwsem.h>
+-#include <linux/acct.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/mm.h>
+
+ #include <net/sock.h> /* siocdevprivate_ioctl */
+@@ -52,8 +52,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/mmu_context.h>
+ #include <asm/ioctls.h>
+-
+-extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
++#include "internal.h"
+
+ int compat_log = 1;
+
+@@ -69,6 +68,8 @@ int compat_printk(const char *fmt, ...)
+ return ret;
+ }
+
++#include "read_write.h"
++
+ /*
+ * Not all architectures have sys_utime, so implement this in terms
+ * of sys_utimes.
+@@ -313,9 +314,6 @@ out:
+ #define IOCTL_HASHSIZE 256
+ static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
+
+-extern struct ioctl_trans ioctl_start[];
+-extern int ioctl_table_size;
+-
+ static inline unsigned long ioctl32_hash(unsigned long cmd)
+ {
+ return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
+@@ -838,8 +836,6 @@ static int do_nfs4_super_data_conv(void
+ return 0;
+ }
+
+-extern int copy_mount_options (const void __user *, unsigned long *);
+-
+ #define SMBFS_NAME "smbfs"
+ #define NCPFS_NAME "ncpfs"
+ #define NFS4_NAME "nfs4"
+@@ -918,20 +914,24 @@ struct compat_readdir_callback {
+ };
+
+ static int compat_fillonedir(void *__buf, const char *name, int namlen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct compat_readdir_callback *buf = __buf;
+ struct compat_old_linux_dirent __user *dirent;
++ compat_ulong_t d_ino;
+
+ if (buf->result)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ buf->result++;
+ dirent = buf->dirent;
+ if (!access_ok(VERIFY_WRITE, dirent,
+ (unsigned long)(dirent->d_name + namlen + 1) -
+ (unsigned long)dirent))
+ goto efault;
+- if ( __put_user(ino, &dirent->d_ino) ||
++ if ( __put_user(d_ino, &dirent->d_ino) ||
+ __put_user(offset, &dirent->d_offset) ||
+ __put_user(namlen, &dirent->d_namlen) ||
+ __copy_to_user(dirent->d_name, name, namlen) ||
+@@ -982,22 +982,26 @@ struct compat_getdents_callback {
+ };
+
+ static int compat_filldir(void *__buf, const char *name, int namlen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct compat_linux_dirent __user * dirent;
+ struct compat_getdents_callback *buf = __buf;
++ compat_ulong_t d_ino;
+ int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent) {
+ if (__put_user(offset, &dirent->d_off))
+ goto efault;
+ }
+ dirent = buf->current_dir;
+- if (__put_user(ino, &dirent->d_ino))
++ if (__put_user(d_ino, &dirent->d_ino))
+ goto efault;
+ if (__put_user(reclen, &dirent->d_reclen))
+ goto efault;
+@@ -1068,7 +1072,7 @@ struct compat_getdents_callback64 {
+ };
+
+ static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
+- ino_t ino, unsigned int d_type)
++ u64 ino, unsigned int d_type)
+ {
+ struct linux_dirent64 __user *dirent;
+ struct compat_getdents_callback64 *buf = __buf;
+@@ -1153,9 +1157,6 @@ static ssize_t compat_do_readv_writev(in
+ const struct compat_iovec __user *uvector,
+ unsigned long nr_segs, loff_t *pos)
+ {
+- typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
+- typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
+-
+ compat_ssize_t tot_len;
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov=iovstack, *vector;
+@@ -1238,39 +1239,18 @@ static ssize_t compat_do_readv_writev(in
+ fnv = NULL;
+ if (type == READ) {
+ fn = file->f_op->read;
+- fnv = file->f_op->readv;
++ fnv = file->f_op->aio_read;
+ } else {
+ fn = (io_fn_t)file->f_op->write;
+- fnv = file->f_op->writev;
+- }
+- if (fnv) {
+- ret = fnv(file, iov, nr_segs, pos);
+- goto out;
++ fnv = file->f_op->aio_write;
+ }
+
+- /* Do it by hand, with file-ops */
+- ret = 0;
+- vector = iov;
+- while (nr_segs > 0) {
+- void __user * base;
+- size_t len;
+- ssize_t nr;
+-
+- base = vector->iov_base;
+- len = vector->iov_len;
+- vector++;
+- nr_segs--;
+-
+- nr = fn(file, base, len, pos);
++ if (fnv)
++ ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
++ pos, fnv);
++ else
++ ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
+
+- if (nr < 0) {
+- if (!ret) ret = nr;
+- break;
+- }
+- ret += nr;
+- if (nr != len)
+- break;
+- }
+ out:
+ if (iov != iovstack)
+ kfree(iov);
+@@ -1298,7 +1278,7 @@ compat_sys_readv(unsigned long fd, const
+ goto out;
+
+ ret = -EINVAL;
+- if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
++ if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
+ goto out;
+
+ ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
+@@ -1321,7 +1301,7 @@ compat_sys_writev(unsigned long fd, cons
+ goto out;
+
+ ret = -EINVAL;
+- if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
++ if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
+ goto out;
+
+ ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
+@@ -1336,7 +1316,7 @@ compat_sys_vmsplice(int fd, const struct
+ unsigned int nr_segs, unsigned int flags)
+ {
+ unsigned i;
+- struct iovec *iov;
++ struct iovec __user *iov;
+ if (nr_segs > UIO_MAXIOV)
+ return -EINVAL;
+ iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
+@@ -1855,9 +1835,12 @@ asmlinkage long compat_sys_pselect7(int
+
+ } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec));
+
+- if (tsp && !(current->personality & STICKY_TIMEOUTS)) {
++ if (tsp) {
+ struct compat_timespec rts;
+
++ if (current->personality & STICKY_TIMEOUTS)
++ goto sticky;
++
+ rts.tv_sec = timeout / HZ;
+ rts.tv_nsec = (timeout % HZ) * (NSEC_PER_SEC/HZ);
+ if (rts.tv_nsec >= NSEC_PER_SEC) {
+@@ -1866,7 +1849,19 @@ asmlinkage long compat_sys_pselect7(int
+ }
+ if (compat_timespec_compare(&rts, &ts) >= 0)
+ rts = ts;
+- copy_to_user(tsp, &rts, sizeof(rts));
++ if (copy_to_user(tsp, &rts, sizeof(rts))) {
++sticky:
++ /*
++ * If an application puts its timeval in read-only
++ * memory, we don't want the Linux-specific update to
++ * the timeval to cause a fault after the select has
++ * completed successfully. However, because we're not
++ * updating the timeval, we can't restart the system
++ * call.
++ */
++ if (ret == -ERESTARTNOHAND)
++ ret = -EINTR;
++ }
+ }
+
+ if (ret == -ERESTARTNOHAND) {
+diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
+index 4063a93..a91f262 100644
+--- a/fs/compat_ioctl.c
++++ b/fs/compat_ioctl.c
+@@ -40,15 +40,11 @@
+ #include <linux/if_pppox.h>
+ #include <linux/mtio.h>
+ #include <linux/cdrom.h>
+-#include <linux/loop.h>
+ #include <linux/auto_fs.h>
+ #include <linux/auto_fs4.h>
+ #include <linux/tty.h>
+ #include <linux/vt_kern.h>
+ #include <linux/fb.h>
+-#include <linux/ext2_fs.h>
+-#include <linux/ext3_jbd.h>
+-#include <linux/ext3_fs.h>
+ #include <linux/videodev.h>
+ #include <linux/netdevice.h>
+ #include <linux/raw.h>
+@@ -60,12 +56,10 @@
+ #include <linux/pci.h>
+ #include <linux/module.h>
+ #include <linux/serial.h>
+-#include <linux/reiserfs_fs.h>
+ #include <linux/if_tun.h>
+ #include <linux/ctype.h>
+ #include <linux/ioctl32.h>
+ #include <linux/syscalls.h>
+-#include <linux/ncp_fs.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-dev.h>
+ #include <linux/wireless.h>
+@@ -113,7 +107,6 @@
+ #include <linux/nbd.h>
+ #include <linux/random.h>
+ #include <linux/filter.h>
+-#include <linux/msdos_fs.h>
+ #include <linux/pktcdvd.h>
+
+ #include <linux/hiddev.h>
+@@ -124,21 +117,6 @@
+ #include <linux/dvb/video.h>
+ #include <linux/lp.h>
+
+-/* Aiee. Someone does not find a difference between int and long */
+-#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)
+-#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)
+-#define EXT3_IOC32_GETVERSION _IOR('f', 3, int)
+-#define EXT3_IOC32_SETVERSION _IOW('f', 4, int)
+-#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int)
+-#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int)
+-#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
+-#ifdef CONFIG_JBD_DEBUG
+-#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
+-#endif
+-
+-#define EXT2_IOC32_GETVERSION _IOR('v', 1, int)
+-#define EXT2_IOC32_SETVERSION _IOW('v', 2, int)
+-
+ static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
+ unsigned long arg, struct file *f)
+ {
+@@ -176,34 +154,6 @@ static int rw_long(unsigned int fd, unsi
+ return err;
+ }
+
+-static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- /* These are just misnamed, they actually get/put from/to user an int */
+- switch (cmd) {
+- case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+- case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+- case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+- case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+- }
+- return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
+-}
+-
+-static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- /* These are just misnamed, they actually get/put from/to user an int */
+- switch (cmd) {
+- case EXT3_IOC32_GETVERSION: cmd = EXT3_IOC_GETVERSION; break;
+- case EXT3_IOC32_SETVERSION: cmd = EXT3_IOC_SETVERSION; break;
+- case EXT3_IOC32_GETRSVSZ: cmd = EXT3_IOC_GETRSVSZ; break;
+- case EXT3_IOC32_SETRSVSZ: cmd = EXT3_IOC_SETRSVSZ; break;
+- case EXT3_IOC32_GROUP_EXTEND: cmd = EXT3_IOC_GROUP_EXTEND; break;
+-#ifdef CONFIG_JBD_DEBUG
+- case EXT3_IOC32_WAIT_FOR_READONLY: cmd = EXT3_IOC_WAIT_FOR_READONLY; break;
+-#endif
+- }
+- return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
+-}
+-
+ struct compat_video_event {
+ int32_t type;
+ compat_time_t timestamp;
+@@ -694,6 +644,7 @@ out:
+ }
+ #endif
+
++#ifdef CONFIG_BLOCK
+ struct hd_geometry32 {
+ unsigned char heads;
+ unsigned char sectors;
+@@ -918,6 +869,7 @@ static int sg_grt_trans(unsigned int fd,
+ }
+ return err;
+ }
++#endif /* CONFIG_BLOCK */
+
+ struct sock_fprog32 {
+ unsigned short len;
+@@ -1041,6 +993,7 @@ static int ppp_ioctl_trans(unsigned int
+ }
+
+
++#ifdef CONFIG_BLOCK
+ struct mtget32 {
+ compat_long_t mt_type;
+ compat_long_t mt_resid;
+@@ -1213,73 +1166,7 @@ static int cdrom_ioctl_trans(unsigned in
+
+ return err;
+ }
+-
+-struct loop_info32 {
+- compat_int_t lo_number; /* ioctl r/o */
+- compat_dev_t lo_device; /* ioctl r/o */
+- compat_ulong_t lo_inode; /* ioctl r/o */
+- compat_dev_t lo_rdevice; /* ioctl r/o */
+- compat_int_t lo_offset;
+- compat_int_t lo_encrypt_type;
+- compat_int_t lo_encrypt_key_size; /* ioctl w/o */
+- compat_int_t lo_flags; /* ioctl r/o */
+- char lo_name[LO_NAME_SIZE];
+- unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+- compat_ulong_t lo_init[2];
+- char reserved[4];
+-};
+-
+-static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- mm_segment_t old_fs = get_fs();
+- struct loop_info l;
+- struct loop_info32 __user *ul;
+- int err = -EINVAL;
+-
+- ul = compat_ptr(arg);
+- switch(cmd) {
+- case LOOP_SET_STATUS:
+- err = get_user(l.lo_number, &ul->lo_number);
+- err |= __get_user(l.lo_device, &ul->lo_device);
+- err |= __get_user(l.lo_inode, &ul->lo_inode);
+- err |= __get_user(l.lo_rdevice, &ul->lo_rdevice);
+- err |= __copy_from_user(&l.lo_offset, &ul->lo_offset,
+- 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+- if (err) {
+- err = -EFAULT;
+- } else {
+- set_fs (KERNEL_DS);
+- err = sys_ioctl (fd, cmd, (unsigned long)&l);
+- set_fs (old_fs);
+- }
+- break;
+- case LOOP_GET_STATUS:
+- set_fs (KERNEL_DS);
+- err = sys_ioctl (fd, cmd, (unsigned long)&l);
+- set_fs (old_fs);
+- if (!err) {
+- err = put_user(l.lo_number, &ul->lo_number);
+- err |= __put_user(l.lo_device, &ul->lo_device);
+- err |= __put_user(l.lo_inode, &ul->lo_inode);
+- err |= __put_user(l.lo_rdevice, &ul->lo_rdevice);
+- err |= __copy_to_user(&ul->lo_offset, &l.lo_offset,
+- (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+- if (err)
+- err = -EFAULT;
+- }
+- break;
+- default: {
+- static int count;
+- if (++count <= 20)
+- printk("%s: Unknown loop ioctl cmd, fd(%d) "
+- "cmd(%08x) arg(%08lx)\n",
+- __FUNCTION__, fd, cmd, arg);
+- }
+- }
+- return err;
+-}
+-
+-extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
++#endif /* CONFIG_BLOCK */
+
+ #ifdef CONFIG_VT
+
+@@ -1607,6 +1494,7 @@ ret_einval(unsigned int fd, unsigned int
+ return -EINVAL;
+ }
+
++#ifdef CONFIG_BLOCK
+ static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+ {
+ /* The mkswap binary hard codes it to Intel value :-((( */
+@@ -1641,12 +1529,14 @@ static int blkpg_ioctl_trans(unsigned in
+
+ return sys_ioctl(fd, cmd, (unsigned long)a);
+ }
++#endif
+
+ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+ {
+ return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+ }
+
++#ifdef CONFIG_BLOCK
+ /* Fix sizeof(sizeof()) breakage */
+ #define BLKBSZGET_32 _IOR(0x12,112,int)
+ #define BLKBSZSET_32 _IOW(0x12,113,int)
+@@ -1667,6 +1557,7 @@ static int do_blkgetsize64(unsigned int
+ {
+ return sys_ioctl(fd, BLKGETSIZE64, (unsigned long)compat_ptr(arg));
+ }
++#endif
+
+ /* Bluetooth ioctls */
+ #define HCIUARTSETPROTO _IOW('U', 200, int)
+@@ -1687,6 +1578,7 @@ static int do_blkgetsize64(unsigned int
+ #define HIDPGETCONNLIST _IOR('H', 210, int)
+ #define HIDPGETCONNINFO _IOR('H', 211, int)
+
++#ifdef CONFIG_BLOCK
+ struct floppy_struct32 {
+ compat_uint_t size;
+ compat_uint_t sect;
+@@ -2011,6 +1903,7 @@ out:
+ kfree(karg);
+ return err;
+ }
++#endif
+
+ struct mtd_oob_buf32 {
+ u_int32_t start;
+@@ -2052,61 +1945,7 @@ static int mtd_rw_oob(unsigned int fd, u
+ return err;
+ }
+
+-#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
+-#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
+-
+-static long
+-put_dirent32 (struct dirent *d, struct compat_dirent __user *d32)
+-{
+- if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
+- return -EFAULT;
+-
+- __put_user(d->d_ino, &d32->d_ino);
+- __put_user(d->d_off, &d32->d_off);
+- __put_user(d->d_reclen, &d32->d_reclen);
+- if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
+- return -EFAULT;
+-
+- return 0;
+-}
+-
+-static int vfat_ioctl32(unsigned fd, unsigned cmd, unsigned long arg)
+-{
+- struct compat_dirent __user *p = compat_ptr(arg);
+- int ret;
+- mm_segment_t oldfs = get_fs();
+- struct dirent d[2];
+-
+- switch(cmd)
+- {
+- case VFAT_IOCTL_READDIR_BOTH32:
+- cmd = VFAT_IOCTL_READDIR_BOTH;
+- break;
+- case VFAT_IOCTL_READDIR_SHORT32:
+- cmd = VFAT_IOCTL_READDIR_SHORT;
+- break;
+- }
+-
+- set_fs(KERNEL_DS);
+- ret = sys_ioctl(fd,cmd,(unsigned long)&d);
+- set_fs(oldfs);
+- if (ret >= 0) {
+- ret |= put_dirent32(&d[0], p);
+- ret |= put_dirent32(&d[1], p + 1);
+- }
+- return ret;
+-}
+-
+-#define REISERFS_IOC_UNPACK32 _IOW(0xCD,1,int)
+-
+-static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr)
+-{
+- if (cmd == REISERFS_IOC_UNPACK32)
+- cmd = REISERFS_IOC_UNPACK;
+-
+- return sys_ioctl(fd,cmd,ptr);
+-}
+-
++#ifdef CONFIG_BLOCK
+ struct raw32_config_request
+ {
+ compat_int_t raw_minor;
+@@ -2171,6 +2010,7 @@ static int raw_ioctl(unsigned fd, unsign
+ }
+ return ret;
+ }
++#endif /* CONFIG_BLOCK */
+
+ struct serial_struct32 {
+ compat_int_t type;
+@@ -2507,193 +2347,6 @@ static int rtc_ioctl(unsigned fd, unsign
+ }
+ }
+
+-#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE)
+-struct ncp_ioctl_request_32 {
+- u32 function;
+- u32 size;
+- compat_caddr_t data;
+-};
+-
+-struct ncp_fs_info_v2_32 {
+- s32 version;
+- u32 mounted_uid;
+- u32 connection;
+- u32 buffer_size;
+-
+- u32 volume_number;
+- u32 directory_id;
+-
+- u32 dummy1;
+- u32 dummy2;
+- u32 dummy3;
+-};
+-
+-struct ncp_objectname_ioctl_32
+-{
+- s32 auth_type;
+- u32 object_name_len;
+- compat_caddr_t object_name; /* an userspace data, in most cases user name */
+-};
+-
+-struct ncp_privatedata_ioctl_32
+-{
+- u32 len;
+- compat_caddr_t data; /* ~1000 for NDS */
+-};
+-
+-#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct ncp_ioctl_request_32)
+-#define NCP_IOC_GETMOUNTUID2_32 _IOW('n', 2, u32)
+-#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct ncp_fs_info_v2_32)
+-#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct ncp_objectname_ioctl_32)
+-#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct ncp_objectname_ioctl_32)
+-#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct ncp_privatedata_ioctl_32)
+-#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct ncp_privatedata_ioctl_32)
+-
+-static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- struct ncp_ioctl_request_32 n32;
+- struct ncp_ioctl_request __user *p = compat_alloc_user_space(sizeof(*p));
+-
+- if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)) ||
+- put_user(n32.function, &p->function) ||
+- put_user(n32.size, &p->size) ||
+- put_user(compat_ptr(n32.data), &p->data))
+- return -EFAULT;
+-
+- return sys_ioctl(fd, NCP_IOC_NCPREQUEST, (unsigned long)p);
+-}
+-
+-static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- mm_segment_t old_fs = get_fs();
+- __kernel_uid_t kuid;
+- int err;
+-
+- cmd = NCP_IOC_GETMOUNTUID2;
+-
+- set_fs(KERNEL_DS);
+- err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+- set_fs(old_fs);
+-
+- if (!err)
+- err = put_user(kuid,
+- (unsigned int __user *) compat_ptr(arg));
+-
+- return err;
+-}
+-
+-static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- mm_segment_t old_fs = get_fs();
+- struct ncp_fs_info_v2_32 n32;
+- struct ncp_fs_info_v2 n;
+- int err;
+-
+- if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)))
+- return -EFAULT;
+- if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
+- return -EINVAL;
+- n.version = NCP_GET_FS_INFO_VERSION_V2;
+-
+- set_fs(KERNEL_DS);
+- err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
+- set_fs(old_fs);
+-
+- if (!err) {
+- n32.version = n.version;
+- n32.mounted_uid = n.mounted_uid;
+- n32.connection = n.connection;
+- n32.buffer_size = n.buffer_size;
+- n32.volume_number = n.volume_number;
+- n32.directory_id = n.directory_id;
+- n32.dummy1 = n.dummy1;
+- n32.dummy2 = n.dummy2;
+- n32.dummy3 = n.dummy3;
+- err = copy_to_user(compat_ptr(arg), &n32, sizeof(n32)) ? -EFAULT : 0;
+- }
+- return err;
+-}
+-
+-static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- struct ncp_objectname_ioctl_32 n32, __user *p32 = compat_ptr(arg);
+- struct ncp_objectname_ioctl __user *p = compat_alloc_user_space(sizeof(*p));
+- s32 auth_type;
+- u32 name_len;
+- int err;
+-
+- if (copy_from_user(&n32, p32, sizeof(n32)) ||
+- put_user(n32.object_name_len, &p->object_name_len) ||
+- put_user(compat_ptr(n32.object_name), &p->object_name))
+- return -EFAULT;
+-
+- err = sys_ioctl(fd, NCP_IOC_GETOBJECTNAME, (unsigned long)p);
+- if (err)
+- return err;
+-
+- if (get_user(auth_type, &p->auth_type) ||
+- put_user(auth_type, &p32->auth_type) ||
+- get_user(name_len, &p->object_name_len) ||
+- put_user(name_len, &p32->object_name_len))
+- return -EFAULT;
+-
+- return 0;
+-}
+-
+-static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- struct ncp_objectname_ioctl_32 n32, __user *p32 = compat_ptr(arg);
+- struct ncp_objectname_ioctl __user *p = compat_alloc_user_space(sizeof(*p));
+-
+- if (copy_from_user(&n32, p32, sizeof(n32)) ||
+- put_user(n32.auth_type, &p->auth_type) ||
+- put_user(n32.object_name_len, &p->object_name_len) ||
+- put_user(compat_ptr(n32.object_name), &p->object_name))
+- return -EFAULT;
+-
+- return sys_ioctl(fd, NCP_IOC_SETOBJECTNAME, (unsigned long)p);
+-}
+-
+-static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- struct ncp_privatedata_ioctl_32 n32, __user *p32 = compat_ptr(arg);
+- struct ncp_privatedata_ioctl __user *p =
+- compat_alloc_user_space(sizeof(*p));
+- u32 len;
+- int err;
+-
+- if (copy_from_user(&n32, p32, sizeof(n32)) ||
+- put_user(n32.len, &p->len) ||
+- put_user(compat_ptr(n32.data), &p->data))
+- return -EFAULT;
+-
+- err = sys_ioctl(fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)p);
+- if (err)
+- return err;
+-
+- if (get_user(len, &p->len) ||
+- put_user(len, &p32->len))
+- return -EFAULT;
+-
+- return 0;
+-}
+-
+-static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+-{
+- struct ncp_privatedata_ioctl_32 n32;
+- struct ncp_privatedata_ioctl_32 __user *p32 = compat_ptr(arg);
+- struct ncp_privatedata_ioctl __user *p =
+- compat_alloc_user_space(sizeof(*p));
+-
+- if (copy_from_user(&n32, p32, sizeof(n32)) ||
+- put_user(n32.len, &p->len) ||
+- put_user(compat_ptr(n32.data), &p->data))
+- return -EFAULT;
+-
+- return sys_ioctl(fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)p);
+-}
+-#endif
+-
+ static int
+ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+ {
+@@ -2777,6 +2430,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
+ HANDLE_IOCTL(SIOCRTMSG, ret_einval)
+ HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+ #endif
++#ifdef CONFIG_BLOCK
+ HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
+ HANDLE_IOCTL(BLKRAGET, w_long)
+ HANDLE_IOCTL(BLKGETSIZE, w_long)
+@@ -2784,13 +2438,17 @@ HANDLE_IOCTL(0x1260, broken_blkgetsize)
+ HANDLE_IOCTL(BLKFRAGET, w_long)
+ HANDLE_IOCTL(BLKSECTGET, w_long)
+ HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
+-HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
+ HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
+-HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
+-HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
+ HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
+ HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
+ HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_WCACHE, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_ACOUSTIC, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_ADDRESS, hdio_ioctl_trans)
++HANDLE_IOCTL(HDIO_GET_BUSSTATE, hdio_ioctl_trans)
+ HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans)
+ HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans)
+ HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans)
+@@ -2802,16 +2460,17 @@ HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_tr
+ HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+ HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
+ HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans)
++#endif
+ HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
+ HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+ HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
+ HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans)
++#ifdef CONFIG_BLOCK
+ HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
+ HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
+ HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
+ HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
+-HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
+-HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
++#endif
+ #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+ HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
+ #ifdef CONFIG_VT
+@@ -2821,19 +2480,6 @@ HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl
+ HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
+ HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
+ #endif
+-HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
+-HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
+-HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
+-HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl)
+-HANDLE_IOCTL(EXT3_IOC32_GETVERSION, do_ext3_ioctl)
+-HANDLE_IOCTL(EXT3_IOC32_SETVERSION, do_ext3_ioctl)
+-HANDLE_IOCTL(EXT3_IOC32_GETRSVSZ, do_ext3_ioctl)
+-HANDLE_IOCTL(EXT3_IOC32_SETRSVSZ, do_ext3_ioctl)
+-HANDLE_IOCTL(EXT3_IOC32_GROUP_EXTEND, do_ext3_ioctl)
+-COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD)
+-#ifdef CONFIG_JBD_DEBUG
+-HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl)
+-#endif
+ /* One SMB ioctl needs translations. */
+ #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
+ HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
+@@ -2863,16 +2509,14 @@ HANDLE_IOCTL(SONET_SETFRAMING, do_atm_io
+ HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
+ HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
+ /* block stuff */
++#ifdef CONFIG_BLOCK
+ HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+ HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+ HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
+-/* vfat */
+-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
+-HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
+ /* Raw devices */
+ HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
+ HANDLE_IOCTL(RAW_GETBIND, raw_ioctl)
++#endif
+ /* Serial */
+ HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
+ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
+@@ -2920,16 +2564,6 @@ HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl)
+ HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl)
+ HANDLE_IOCTL(RTC_EPOCH_SET32, rtc_ioctl)
+
+-#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE)
+-HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
+-HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
+-HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
+-HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
+-HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
+-HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
+-HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
+-#endif
+-
+ /* dvb */
+ HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event)
+ HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture)
+diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
+index df02545..8a3b6a1 100644
+--- a/fs/configfs/dir.c
++++ b/fs/configfs/dir.c
+@@ -86,6 +86,32 @@ static struct configfs_dirent *configfs_
+ return sd;
+ }
+
++/*
++ *
++ * Return -EEXIST if there is already a configfs element with the same
++ * name for the same parent.
++ *
++ * called with parent inode's i_mutex held
++ */
++int configfs_dirent_exists(struct configfs_dirent *parent_sd,
++ const unsigned char *new)
++{
++ struct configfs_dirent * sd;
++
++ list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
++ if (sd->s_element) {
++ const unsigned char *existing = configfs_get_name(sd);
++ if (strcmp(existing, new))
++ continue;
++ else
++ return -EEXIST;
++ }
++ }
++
++ return 0;
++}
++
++
+ int configfs_make_dirent(struct configfs_dirent * parent_sd,
+ struct dentry * dentry, void * element,
+ umode_t mode, int type)
+@@ -113,7 +139,7 @@ static int init_dir(struct inode * inode
+ inode->i_fop = &configfs_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ return 0;
+ }
+
+@@ -136,12 +162,14 @@ static int create_dir(struct config_item
+ int error;
+ umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
+
+- error = configfs_make_dirent(p->d_fsdata, d, k, mode,
+- CONFIGFS_DIR);
++ error = configfs_dirent_exists(p->d_fsdata, d->d_name.name);
++ if (!error)
++ error = configfs_make_dirent(p->d_fsdata, d, k, mode,
++ CONFIGFS_DIR);
+ if (!error) {
+ error = configfs_create(d, mode, init_dir);
+ if (!error) {
+- p->d_inode->i_nlink++;
++ inc_nlink(p->d_inode);
+ (d)->d_op = &configfs_dentry_ops;
+ } else {
+ struct configfs_dirent *sd = d->d_fsdata;
+diff --git a/fs/configfs/file.c b/fs/configfs/file.c
+index f499803..cf33fac 100644
+--- a/fs/configfs/file.c
++++ b/fs/configfs/file.c
+@@ -137,8 +137,8 @@ configfs_read_file(struct file *file, ch
+ if ((retval = fill_read_buffer(file->f_dentry,buffer)))
+ goto out;
+ }
+- pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
+- __FUNCTION__,count,*ppos,buffer->page);
++ pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
++ __FUNCTION__, count, *ppos, buffer->page);
+ retval = flush_read_buffer(buffer,buf,count,ppos);
+ out:
+ up(&buffer->sem);
+@@ -274,15 +274,15 @@ static int check_perm(struct inode * ino
+ /* No error? Great, allocate a buffer for the file, and store it
+ * it in file->private_data for easy access.
+ */
+- buffer = kmalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
+- if (buffer) {
+- memset(buffer,0,sizeof(struct configfs_buffer));
+- init_MUTEX(&buffer->sem);
+- buffer->needs_read_fill = 1;
+- buffer->ops = ops;
+- file->private_data = buffer;
+- } else
++ buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
++ if (!buffer) {
+ error = -ENOMEM;
++ goto Enomem;
++ }
++ init_MUTEX(&buffer->sem);
++ buffer->needs_read_fill = 1;
++ buffer->ops = ops;
++ file->private_data = buffer;
+ goto Done;
+
+ Einval:
+@@ -290,6 +290,7 @@ static int check_perm(struct inode * ino
+ goto Done;
+ Eaccess:
+ error = -EACCES;
++ Enomem:
+ module_put(attr->ca_owner);
+ Done:
+ if (error && item)
+diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
+index e14488c..fb18917 100644
+--- a/fs/configfs/inode.c
++++ b/fs/configfs/inode.c
+@@ -76,11 +76,10 @@ int configfs_setattr(struct dentry * den
+
+ if (!sd_iattr) {
+ /* setting attributes for the first time, allocate now */
+- sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
++ sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
+ if (!sd_iattr)
+ return -ENOMEM;
+ /* assign default attributes */
+- memset(sd_iattr, 0, sizeof(struct iattr));
+ sd_iattr->ia_mode = sd->s_mode;
+ sd_iattr->ia_uid = 0;
+ sd_iattr->ia_gid = 0;
+@@ -136,7 +135,6 @@ struct inode * configfs_new_inode(mode_t
+ {
+ struct inode * inode = new_inode(configfs_sb);
+ if (inode) {
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->a_ops = &configfs_aops;
+ inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
+diff --git a/fs/configfs/item.c b/fs/configfs/item.c
+index e07485a..2442120 100644
+--- a/fs/configfs/item.c
++++ b/fs/configfs/item.c
+@@ -224,4 +224,4 @@ EXPORT_SYMBOL(config_item_init);
+ EXPORT_SYMBOL(config_group_init);
+ EXPORT_SYMBOL(config_item_get);
+ EXPORT_SYMBOL(config_item_put);
+-
++EXPORT_SYMBOL(config_group_find_obj);
+diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
+index 3e5fe84..68bd5c9 100644
+--- a/fs/configfs/mount.c
++++ b/fs/configfs/mount.c
+@@ -84,7 +84,7 @@ static int configfs_fill_super(struct su
+ inode->i_op = &configfs_dir_inode_operations;
+ inode->i_fop = &configfs_dir_operations;
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ } else {
+ pr_debug("configfs: could not get root inode\n");
+ return -ENOMEM;
+diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
+index 223c043..a624c3e 100644
+--- a/fs/cramfs/inode.c
++++ b/fs/cramfs/inode.c
+@@ -73,7 +73,6 @@ static int cramfs_iget5_set(struct inode
+ inode->i_uid = cramfs_inode->uid;
+ inode->i_size = cramfs_inode->size;
+ inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_gid = cramfs_inode->gid;
+ /* Struct copy intentional */
+ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
+@@ -242,11 +241,10 @@ static int cramfs_fill_super(struct supe
+
+ sb->s_flags |= MS_RDONLY;
+
+- sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(struct cramfs_sb_info));
+
+ /* Invalidate the read buffers on mount: think disk change.. */
+ mutex_lock(&read_mutex);
+@@ -545,8 +543,15 @@ static struct file_system_type cramfs_fs
+
+ static int __init init_cramfs_fs(void)
+ {
+- cramfs_uncompress_init();
+- return register_filesystem(&cramfs_fs_type);
++ int rv;
++
++ rv = cramfs_uncompress_init();
++ if (rv < 0)
++ return rv;
++ rv = register_filesystem(&cramfs_fs_type);
++ if (rv < 0)
++ cramfs_uncompress_exit();
++ return rv;
+ }
+
+ static void __exit exit_cramfs_fs(void)
+diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c
+index 8def89f..fc3ccb7 100644
+--- a/fs/cramfs/uncompress.c
++++ b/fs/cramfs/uncompress.c
+@@ -68,11 +68,10 @@ int cramfs_uncompress_init(void)
+ return 0;
+ }
+
+-int cramfs_uncompress_exit(void)
++void cramfs_uncompress_exit(void)
+ {
+ if (!--initialized) {
+ zlib_inflateEnd(&stream);
+ vfree(stream.workspace);
+ }
+- return 0;
+ }
+diff --git a/fs/dcache.c b/fs/dcache.c
+index 1b4a3a3..fd4a428 100644
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -32,6 +32,7 @@
+ #include <linux/seqlock.h>
+ #include <linux/swap.h>
+ #include <linux/bootmem.h>
++#include "internal.h"
+
+
+ int sysctl_vfs_cache_pressure __read_mostly = 100;
+@@ -290,9 +291,9 @@ struct dentry * dget_locked(struct dentr
+ * it can be unhashed only if it has no children, or if it is the root
+ * of a filesystem.
+ *
+- * If the inode has a DCACHE_DISCONNECTED alias, then prefer
++ * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
+ * any other hashed alias over that one unless @want_discon is set,
+- * in which case only return a DCACHE_DISCONNECTED alias.
++ * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
+ */
+
+ static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
+@@ -308,7 +309,8 @@ static struct dentry * __d_find_alias(st
+ prefetch(next);
+ alias = list_entry(tmp, struct dentry, d_alias);
+ if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
+- if (alias->d_flags & DCACHE_DISCONNECTED)
++ if (IS_ROOT(alias) &&
++ (alias->d_flags & DCACHE_DISCONNECTED))
+ discon_alias = alias;
+ else if (!want_discon) {
+ __dget_locked(alias);
+@@ -476,11 +478,12 @@ static void prune_dcache(int count, stru
+ up_read(s_umount);
+ }
+ spin_unlock(&dentry->d_lock);
+- /* Cannot remove the first dentry, and it isn't appropriate
+- * to move it to the head of the list, so give up, and try
+- * later
++ /*
++ * Insert dentry at the head of the list as inserting at the
++ * tail leads to a cycle.
+ */
+- break;
++ list_add(&dentry->d_lru, &dentry_unused);
++ dentry_stat.nr_unused++;
+ }
+ spin_unlock(&dcache_lock);
+ }
+@@ -547,6 +550,142 @@ repeat:
+ }
+
+ /*
++ * destroy a single subtree of dentries for unmount
++ * - see the comments on shrink_dcache_for_umount() for a description of the
++ * locking
++ */
++static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
++{
++ struct dentry *parent;
++ unsigned detached = 0;
++
++ BUG_ON(!IS_ROOT(dentry));
++
++ /* detach this root from the system */
++ spin_lock(&dcache_lock);
++ if (!list_empty(&dentry->d_lru)) {
++ dentry_stat.nr_unused--;
++ list_del_init(&dentry->d_lru);
++ }
++ __d_drop(dentry);
++ spin_unlock(&dcache_lock);
++
++ for (;;) {
++ /* descend to the first leaf in the current subtree */
++ while (!list_empty(&dentry->d_subdirs)) {
++ struct dentry *loop;
++
++ /* this is a branch with children - detach all of them
++ * from the system in one go */
++ spin_lock(&dcache_lock);
++ list_for_each_entry(loop, &dentry->d_subdirs,
++ d_u.d_child) {
++ if (!list_empty(&loop->d_lru)) {
++ dentry_stat.nr_unused--;
++ list_del_init(&loop->d_lru);
++ }
++
++ __d_drop(loop);
++ cond_resched_lock(&dcache_lock);
++ }
++ spin_unlock(&dcache_lock);
++
++ /* move to the first child */
++ dentry = list_entry(dentry->d_subdirs.next,
++ struct dentry, d_u.d_child);
++ }
++
++ /* consume the dentries from this leaf up through its parents
++ * until we find one with children or run out altogether */
++ do {
++ struct inode *inode;
++
++ if (atomic_read(&dentry->d_count) != 0) {
++ printk(KERN_ERR
++ "BUG: Dentry %p{i=%lx,n=%s}"
++ " still in use (%d)"
++ " [unmount of %s %s]\n",
++ dentry,
++ dentry->d_inode ?
++ dentry->d_inode->i_ino : 0UL,
++ dentry->d_name.name,
++ atomic_read(&dentry->d_count),
++ dentry->d_sb->s_type->name,
++ dentry->d_sb->s_id);
++ BUG();
++ }
++
++ parent = dentry->d_parent;
++ if (parent == dentry)
++ parent = NULL;
++ else
++ atomic_dec(&parent->d_count);
++
++ list_del(&dentry->d_u.d_child);
++ detached++;
++
++ inode = dentry->d_inode;
++ if (inode) {
++ dentry->d_inode = NULL;
++ list_del_init(&dentry->d_alias);
++ if (dentry->d_op && dentry->d_op->d_iput)
++ dentry->d_op->d_iput(dentry, inode);
++ else
++ iput(inode);
++ }
++
++ d_free(dentry);
++
++ /* finished when we fall off the top of the tree,
++ * otherwise we ascend to the parent and move to the
++ * next sibling if there is one */
++ if (!parent)
++ goto out;
++
++ dentry = parent;
++
++ } while (list_empty(&dentry->d_subdirs));
++
++ dentry = list_entry(dentry->d_subdirs.next,
++ struct dentry, d_u.d_child);
++ }
++out:
++ /* several dentries were freed, need to correct nr_dentry */
++ spin_lock(&dcache_lock);
++ dentry_stat.nr_dentry -= detached;
++ spin_unlock(&dcache_lock);
++}
++
++/*
++ * destroy the dentries attached to a superblock on unmounting
++ * - we don't need to use dentry->d_lock, and only need dcache_lock when
++ * removing the dentry from the system lists and hashes because:
++ * - the superblock is detached from all mountings and open files, so the
++ * dentry trees will not be rearranged by the VFS
++ * - s_umount is write-locked, so the memory pressure shrinker will ignore
++ * any dentries belonging to this superblock that it comes across
++ * - the filesystem itself is no longer permitted to rearrange the dentries
++ * in this superblock
++ */
++void shrink_dcache_for_umount(struct super_block *sb)
++{
++ struct dentry *dentry;
++
++ if (down_read_trylock(&sb->s_umount))
++ BUG();
++
++ dentry = sb->s_root;
++ sb->s_root = NULL;
++ atomic_dec(&dentry->d_count);
++ shrink_dcache_for_umount_subtree(dentry);
++
++ while (!hlist_empty(&sb->s_anon)) {
++ dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash);
++ shrink_dcache_for_umount_subtree(dentry);
++ }
++}
++
++/*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+@@ -828,17 +967,19 @@ void d_instantiate(struct dentry *entry,
+ * (or otherwise set) by the caller to indicate that it is now
+ * in use by the dcache.
+ */
+-struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
++static struct dentry *__d_instantiate_unique(struct dentry *entry,
++ struct inode *inode)
+ {
+ struct dentry *alias;
+ int len = entry->d_name.len;
+ const char *name = entry->d_name.name;
+ unsigned int hash = entry->d_name.hash;
+
+- BUG_ON(!list_empty(&entry->d_alias));
+- spin_lock(&dcache_lock);
+- if (!inode)
+- goto do_negative;
++ if (!inode) {
++ entry->d_inode = NULL;
++ return NULL;
++ }
++
+ list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ struct qstr *qstr = &alias->d_name;
+
+@@ -851,19 +992,35 @@ struct dentry *d_instantiate_unique(stru
+ if (memcmp(qstr->name, name, len))
+ continue;
+ dget_locked(alias);
+- spin_unlock(&dcache_lock);
+- BUG_ON(!d_unhashed(alias));
+- iput(inode);
+ return alias;
+ }
++
+ list_add(&entry->d_alias, &inode->i_dentry);
+-do_negative:
+ entry->d_inode = inode;
+ fsnotify_d_instantiate(entry, inode);
+- spin_unlock(&dcache_lock);
+- security_d_instantiate(entry, inode);
+ return NULL;
+ }
++
++struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
++{
++ struct dentry *result;
++
++ BUG_ON(!list_empty(&entry->d_alias));
++
++ spin_lock(&dcache_lock);
++ result = __d_instantiate_unique(entry, inode);
++ spin_unlock(&dcache_lock);
++
++ if (!result) {
++ security_d_instantiate(entry, inode);
++ return NULL;
++ }
++
++ BUG_ON(!d_unhashed(result));
++ iput(inode);
++ return result;
++}
++
+ EXPORT_SYMBOL(d_instantiate_unique);
+
+ /**
+@@ -985,7 +1142,7 @@ struct dentry *d_splice_alias(struct ino
+ {
+ struct dentry *new = NULL;
+
+- if (inode) {
++ if (inode && S_ISDIR(inode->i_mode)) {
+ spin_lock(&dcache_lock);
+ new = __d_find_alias(inode, 1);
+ if (new) {
+@@ -1235,6 +1392,11 @@ static void __d_rehash(struct dentry * e
+ hlist_add_head_rcu(&entry->d_hash, list);
+ }
+
++static void _d_rehash(struct dentry * entry)
++{
++ __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash));
++}
++
+ /**
+ * d_rehash - add an entry back to the hash
+ * @entry: dentry to add to the hash
+@@ -1244,11 +1406,9 @@ static void __d_rehash(struct dentry * e
+
+ void d_rehash(struct dentry * entry)
+ {
+- struct hlist_head *list = d_hash(entry->d_parent, entry->d_name.hash);
+-
+ spin_lock(&dcache_lock);
+ spin_lock(&entry->d_lock);
+- __d_rehash(entry, list);
++ _d_rehash(entry);
+ spin_unlock(&entry->d_lock);
+ spin_unlock(&dcache_lock);
+ }
+@@ -1316,23 +1476,21 @@ static void switch_names(struct dentry *
+ * deleted it.
+ */
+
+-/**
+- * d_move - move a dentry
++/*
++ * d_move_locked - move a dentry
+ * @dentry: entry to move
+ * @target: new dentry
+ *
+ * Update the dcache to reflect the move of a file name. Negative
+ * dcache entries should not be moved in this way.
+ */
+-
+-void d_move(struct dentry * dentry, struct dentry * target)
++static void d_move_locked(struct dentry * dentry, struct dentry * target)
+ {
+ struct hlist_head *list;
+
+ if (!dentry->d_inode)
+ printk(KERN_WARNING "VFS: moving negative dcache entry\n");
+
+- spin_lock(&dcache_lock);
+ write_seqlock(&rename_lock);
+ /*
+ * XXXX: do we really need to take target->d_lock?
+@@ -1383,9 +1541,188 @@ already_unhashed:
+ fsnotify_d_move(dentry);
+ spin_unlock(&dentry->d_lock);
+ write_sequnlock(&rename_lock);
++}
++
++/**
++ * d_move - move a dentry
++ * @dentry: entry to move
++ * @target: new dentry
++ *
++ * Update the dcache to reflect the move of a file name. Negative
++ * dcache entries should not be moved in this way.
++ */
++
++void d_move(struct dentry * dentry, struct dentry * target)
++{
++ spin_lock(&dcache_lock);
++ d_move_locked(dentry, target);
+ spin_unlock(&dcache_lock);
+ }
+
++/*
++ * Helper that returns 1 if p1 is a parent of p2, else 0
++ */
++static int d_isparent(struct dentry *p1, struct dentry *p2)
++{
++ struct dentry *p;
++
++ for (p = p2; p->d_parent != p; p = p->d_parent) {
++ if (p->d_parent == p1)
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * This helper attempts to cope with remotely renamed directories
++ *
++ * It assumes that the caller is already holding
++ * dentry->d_parent->d_inode->i_mutex and the dcache_lock
++ *
++ * Note: If ever the locking in lock_rename() changes, then please
++ * remember to update this too...
++ *
++ * On return, dcache_lock will have been unlocked.
++ */
++static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
++{
++ struct mutex *m1 = NULL, *m2 = NULL;
++ struct dentry *ret;
++
++ /* If alias and dentry share a parent, then no extra locks required */
++ if (alias->d_parent == dentry->d_parent)
++ goto out_unalias;
++
++ /* Check for loops */
++ ret = ERR_PTR(-ELOOP);
++ if (d_isparent(alias, dentry))
++ goto out_err;
++
++ /* See lock_rename() */
++ ret = ERR_PTR(-EBUSY);
++ if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
++ goto out_err;
++ m1 = &dentry->d_sb->s_vfs_rename_mutex;
++ if (!mutex_trylock(&alias->d_parent->d_inode->i_mutex))
++ goto out_err;
++ m2 = &alias->d_parent->d_inode->i_mutex;
++out_unalias:
++ d_move_locked(alias, dentry);
++ ret = alias;
++out_err:
++ spin_unlock(&dcache_lock);
++ if (m2)
++ mutex_unlock(m2);
++ if (m1)
++ mutex_unlock(m1);
++ return ret;
++}
++
++/*
++ * Prepare an anonymous dentry for life in the superblock's dentry tree as a
++ * named dentry in place of the dentry to be replaced.
++ */
++static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
++{
++ struct dentry *dparent, *aparent;
++
++ switch_names(dentry, anon);
++ do_switch(dentry->d_name.len, anon->d_name.len);
++ do_switch(dentry->d_name.hash, anon->d_name.hash);
++
++ dparent = dentry->d_parent;
++ aparent = anon->d_parent;
++
++ dentry->d_parent = (aparent == anon) ? dentry : aparent;
++ list_del(&dentry->d_u.d_child);
++ if (!IS_ROOT(dentry))
++ list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
++ else
++ INIT_LIST_HEAD(&dentry->d_u.d_child);
++
++ anon->d_parent = (dparent == dentry) ? anon : dparent;
++ list_del(&anon->d_u.d_child);
++ if (!IS_ROOT(anon))
++ list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs);
++ else
++ INIT_LIST_HEAD(&anon->d_u.d_child);
++
++ anon->d_flags &= ~DCACHE_DISCONNECTED;
++}
++
++/**
++ * d_materialise_unique - introduce an inode into the tree
++ * @dentry: candidate dentry
++ * @inode: inode to bind to the dentry, to which aliases may be attached
++ *
++ * Introduces an dentry into the tree, substituting an extant disconnected
++ * root directory alias in its place if there is one
++ */
++struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
++{
++ struct dentry *actual;
++
++ BUG_ON(!d_unhashed(dentry));
++
++ spin_lock(&dcache_lock);
++
++ if (!inode) {
++ actual = dentry;
++ dentry->d_inode = NULL;
++ goto found_lock;
++ }
++
++ if (S_ISDIR(inode->i_mode)) {
++ struct dentry *alias;
++
++ /* Does an aliased dentry already exist? */
++ alias = __d_find_alias(inode, 0);
++ if (alias) {
++ actual = alias;
++ /* Is this an anonymous mountpoint that we could splice
++ * into our tree? */
++ if (IS_ROOT(alias)) {
++ spin_lock(&alias->d_lock);
++ __d_materialise_dentry(dentry, alias);
++ __d_drop(alias);
++ goto found;
++ }
++ /* Nope, but we must(!) avoid directory aliasing */
++ actual = __d_unalias(dentry, alias);
++ if (IS_ERR(actual))
++ dput(alias);
++ goto out_nolock;
++ }
++ }
++
++ /* Add a unique reference */
++ actual = __d_instantiate_unique(dentry, inode);
++ if (!actual)
++ actual = dentry;
++ else if (unlikely(!d_unhashed(actual)))
++ goto shouldnt_be_hashed;
++
++found_lock:
++ spin_lock(&actual->d_lock);
++found:
++ _d_rehash(actual);
++ spin_unlock(&actual->d_lock);
++ spin_unlock(&dcache_lock);
++out_nolock:
++ if (actual == dentry) {
++ security_d_instantiate(dentry, inode);
++ return NULL;
++ }
++
++ iput(inode);
++ return actual;
++
++shouldnt_be_hashed:
++ spin_unlock(&dcache_lock);
++ BUG();
++ goto shouldnt_be_hashed;
++}
++
+ /**
+ * d_path - return the path of a dentry
+ * @dentry: dentry to report
+@@ -1742,9 +2079,6 @@ kmem_cache_t *filp_cachep __read_mostly;
+
+ EXPORT_SYMBOL(d_genocide);
+
+-extern void bdev_cache_init(void);
+-extern void chrdev_init(void);
+-
+ void __init vfs_caches_init_early(void)
+ {
+ dcache_init_early();
+@@ -1784,6 +2118,7 @@ EXPORT_SYMBOL(d_instantiate);
+ EXPORT_SYMBOL(d_invalidate);
+ EXPORT_SYMBOL(d_lookup);
+ EXPORT_SYMBOL(d_move);
++EXPORT_SYMBOL_GPL(d_materialise_unique);
+ EXPORT_SYMBOL(d_path);
+ EXPORT_SYMBOL(d_prune_aliases);
+ EXPORT_SYMBOL(d_rehash);
+diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
+index 39640fd..bf3901a 100644
+--- a/fs/debugfs/file.c
++++ b/fs/debugfs/file.c
+@@ -32,8 +32,8 @@ static ssize_t default_write_file(struct
+
+ static int default_open(struct inode *inode, struct file *file)
+ {
+- if (inode->u.generic_ip)
+- file->private_data = inode->u.generic_ip;
++ if (inode->i_private)
++ file->private_data = inode->i_private;
+
+ return 0;
+ }
+@@ -55,12 +55,11 @@ static u64 debugfs_u8_get(void *data)
+ DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
+
+ /**
+- * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write an unsigned 8 bit value.
+- *
++ * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+- * directory dentry if set. If this paramater is NULL, then the
++ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ * from.
+@@ -72,11 +71,11 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_u8(const char *name, mode_t mode,
+@@ -97,12 +96,11 @@ static u64 debugfs_u16_get(void *data)
+ DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
+
+ /**
+- * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write an unsigned 16 bit value.
+- *
++ * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+- * directory dentry if set. If this paramater is NULL, then the
++ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ * from.
+@@ -114,11 +112,11 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugf
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_u16(const char *name, mode_t mode,
+@@ -139,12 +137,11 @@ static u64 debugfs_u32_get(void *data)
+ DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
+
+ /**
+- * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write an unsigned 32 bit value.
+- *
++ * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+- * directory dentry if set. If this paramater is NULL, then the
++ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ * from.
+@@ -156,11 +153,11 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugf
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
+@@ -219,12 +216,11 @@ static const struct file_operations fops
+ };
+
+ /**
+- * debugfs_create_bool - create a file in the debugfs filesystem that is used to read and write a boolean value.
+- *
++ * debugfs_create_bool - create a debugfs file that is used to read and write a boolean value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+- * directory dentry if set. If this paramater is NULL, then the
++ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ * from.
+@@ -236,11 +232,11 @@ static const struct file_operations fops
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_bool(const char *name, mode_t mode,
+@@ -264,13 +260,11 @@ static struct file_operations fops_blob
+ };
+
+ /**
+- * debugfs_create_blob - create a file in the debugfs filesystem that is
+- * used to read and write a binary blob.
+- *
++ * debugfs_create_blob - create a debugfs file that is used to read and write a binary blob
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+- * directory dentry if set. If this paramater is NULL, then the
++ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
+ * to the blob data and the size of the data.
+@@ -282,11 +276,11 @@ static struct file_operations fops_blob
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
+index e8ae304..e77676d 100644
+--- a/fs/debugfs/inode.c
++++ b/fs/debugfs/inode.c
+@@ -40,7 +40,6 @@ static struct inode *debugfs_get_inode(s
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+@@ -55,7 +54,7 @@ static struct inode *debugfs_get_inode(s
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ break;
+ }
+ }
+@@ -88,7 +87,7 @@ static int debugfs_mkdir(struct inode *d
+ mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+ res = debugfs_mknod(dir, dentry, mode, 0);
+ if (!res)
+- dir->i_nlink++;
++ inc_nlink(dir);
+ return res;
+ }
+
+@@ -162,14 +161,13 @@ static int debugfs_create_by_name(const
+
+ /**
+ * debugfs_create_file - create a file in the debugfs filesystem
+- *
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+ * directory dentry if set. If this paramater is NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @data: a pointer to something that the caller will want to get to later
+- * on. The inode.u.generic_ip pointer will point to this value on
++ * on. The inode.i_private pointer will point to this value on
+ * the open() call.
+ * @fops: a pointer to a struct file_operations that should be used for
+ * this file.
+@@ -182,11 +180,11 @@ static int debugfs_create_by_name(const
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_file(const char *name, mode_t mode,
+@@ -210,7 +208,7 @@ struct dentry *debugfs_create_file(const
+
+ if (dentry->d_inode) {
+ if (data)
+- dentry->d_inode->u.generic_ip = data;
++ dentry->d_inode->i_private = data;
+ if (fops)
+ dentry->d_inode->i_fop = fops;
+ }
+@@ -221,7 +219,6 @@ EXPORT_SYMBOL_GPL(debugfs_create_file);
+
+ /**
+ * debugfs_create_dir - create a directory in the debugfs filesystem
+- *
+ * @name: a pointer to a string containing the name of the directory to
+ * create.
+ * @parent: a pointer to the parent dentry for this file. This should be a
+@@ -233,11 +230,11 @@ EXPORT_SYMBOL_GPL(debugfs_create_file);
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+- * you are responsible here.) If an error occurs, NULL will be returned.
++ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+- * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
+@@ -250,13 +247,12 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir);
+
+ /**
+ * debugfs_remove - removes a file or directory from the debugfs filesystem
+- *
+ * @dentry: a pointer to a the dentry of the file or directory to be
+ * removed.
+ *
+ * This function removes a file or directory in debugfs that was previously
+ * created with a call to another debugfs function (like
+- * debufs_create_file() or variants thereof.)
++ * debugfs_create_file() or variants thereof.)
+ *
+ * This function is required to be called in order for the file to be
+ * removed, no automatic cleanup of files will happen when a module is
+diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
+index f7aef5b..5f7b5a6 100644
+--- a/fs/devpts/inode.c
++++ b/fs/devpts/inode.c
+@@ -113,7 +113,6 @@ devpts_fill_super(struct super_block *s,
+ inode->i_ino = 1;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+- inode->i_blksize = 1024;
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+ inode->i_op = &simple_dir_inode_operations;
+@@ -172,12 +171,11 @@ int devpts_pty_new(struct tty_struct *tt
+ return -ENOMEM;
+
+ inode->i_ino = number+2;
+- inode->i_blksize = 1024;
+ inode->i_uid = config.setuid ? config.uid : current->fsuid;
+ inode->i_gid = config.setgid ? config.gid : current->fsgid;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ init_special_inode(inode, S_IFCHR|config.mode, device);
+- inode->u.generic_ip = tty;
++ inode->i_private = tty;
+
+ dentry = get_node(number);
+ if (!IS_ERR(dentry) && !dentry->d_inode)
+@@ -196,7 +194,7 @@ struct tty_struct *devpts_get_tty(int nu
+ tty = NULL;
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode)
+- tty = dentry->d_inode->u.generic_ip;
++ tty = dentry->d_inode->i_private;
+ dput(dentry);
+ }
+
+diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
+new file mode 100644
+index 0000000..81b2c64
+--- /dev/null
++++ b/fs/dlm/Kconfig
+@@ -0,0 +1,20 @@
++menu "Distributed Lock Manager"
++ depends on INET && IP_SCTP && EXPERIMENTAL
++
++config DLM
++ tristate "Distributed Lock Manager (DLM)"
++ depends on IPV6 || IPV6=n
++ select CONFIGFS_FS
++ help
++ A general purpose distributed lock manager for kernel or userspace
++ applications.
++
++config DLM_DEBUG
++ bool "DLM debugging"
++ depends on DLM
++ help
++ Under the debugfs mount point, the name of each lockspace will
++ appear as a file in the "dlm" directory. The output is the
++ list of resource and locks the local node knows about.
++
++endmenu
+diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile
+new file mode 100644
+index 0000000..1832e02
+--- /dev/null
++++ b/fs/dlm/Makefile
+@@ -0,0 +1,19 @@
++obj-$(CONFIG_DLM) += dlm.o
++dlm-y := ast.o \
++ config.o \
++ dir.o \
++ lock.o \
++ lockspace.o \
++ lowcomms.o \
++ main.o \
++ member.o \
++ memory.o \
++ midcomms.o \
++ rcom.o \
++ recover.o \
++ recoverd.o \
++ requestqueue.o \
++ user.o \
++ util.o
++dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o
++
+diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
+new file mode 100644
+index 0000000..f91d39c
+--- /dev/null
++++ b/fs/dlm/ast.c
+@@ -0,0 +1,173 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lock.h"
++#include "user.h"
++
++#define WAKE_ASTS 0
++
++static struct list_head ast_queue;
++static spinlock_t ast_queue_lock;
++static struct task_struct * astd_task;
++static unsigned long astd_wakeflags;
++static struct mutex astd_running;
++
++
++void dlm_del_ast(struct dlm_lkb *lkb)
++{
++ spin_lock(&ast_queue_lock);
++ if (lkb->lkb_ast_type & (AST_COMP | AST_BAST))
++ list_del(&lkb->lkb_astqueue);
++ spin_unlock(&ast_queue_lock);
++}
++
++void dlm_add_ast(struct dlm_lkb *lkb, int type)
++{
++ if (lkb->lkb_flags & DLM_IFL_USER) {
++ dlm_user_add_ast(lkb, type);
++ return;
++ }
++ DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb););
++
++ spin_lock(&ast_queue_lock);
++ if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
++ kref_get(&lkb->lkb_ref);
++ list_add_tail(&lkb->lkb_astqueue, &ast_queue);
++ }
++ lkb->lkb_ast_type |= type;
++ spin_unlock(&ast_queue_lock);
++
++ set_bit(WAKE_ASTS, &astd_wakeflags);
++ wake_up_process(astd_task);
++}
++
++static void process_asts(void)
++{
++ struct dlm_ls *ls = NULL;
++ struct dlm_rsb *r = NULL;
++ struct dlm_lkb *lkb;
++ void (*cast) (long param);
++ void (*bast) (long param, int mode);
++ int type = 0, found, bmode;
++
++ for (;;) {
++ found = 0;
++ spin_lock(&ast_queue_lock);
++ list_for_each_entry(lkb, &ast_queue, lkb_astqueue) {
++ r = lkb->lkb_resource;
++ ls = r->res_ls;
++
++ if (dlm_locking_stopped(ls))
++ continue;
++
++ list_del(&lkb->lkb_astqueue);
++ type = lkb->lkb_ast_type;
++ lkb->lkb_ast_type = 0;
++ found = 1;
++ break;
++ }
++ spin_unlock(&ast_queue_lock);
++
++ if (!found)
++ break;
++
++ cast = lkb->lkb_astaddr;
++ bast = lkb->lkb_bastaddr;
++ bmode = lkb->lkb_bastmode;
++
++ if ((type & AST_COMP) && cast)
++ cast(lkb->lkb_astparam);
++
++ /* FIXME: Is it safe to look at lkb_grmode here
++ without doing a lock_rsb() ?
++ Look at other checks in v1 to avoid basts. */
++
++ if ((type & AST_BAST) && bast)
++ if (!dlm_modes_compat(lkb->lkb_grmode, bmode))
++ bast(lkb->lkb_astparam, bmode);
++
++ /* this removes the reference added by dlm_add_ast
++ and may result in the lkb being freed */
++ dlm_put_lkb(lkb);
++
++ schedule();
++ }
++}
++
++static inline int no_asts(void)
++{
++ int ret;
++
++ spin_lock(&ast_queue_lock);
++ ret = list_empty(&ast_queue);
++ spin_unlock(&ast_queue_lock);
++ return ret;
++}
++
++static int dlm_astd(void *data)
++{
++ while (!kthread_should_stop()) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (!test_bit(WAKE_ASTS, &astd_wakeflags))
++ schedule();
++ set_current_state(TASK_RUNNING);
++
++ mutex_lock(&astd_running);
++ if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
++ process_asts();
++ mutex_unlock(&astd_running);
++ }
++ return 0;
++}
++
++void dlm_astd_wake(void)
++{
++ if (!no_asts()) {
++ set_bit(WAKE_ASTS, &astd_wakeflags);
++ wake_up_process(astd_task);
++ }
++}
++
++int dlm_astd_start(void)
++{
++ struct task_struct *p;
++ int error = 0;
++
++ INIT_LIST_HEAD(&ast_queue);
++ spin_lock_init(&ast_queue_lock);
++ mutex_init(&astd_running);
++
++ p = kthread_run(dlm_astd, NULL, "dlm_astd");
++ if (IS_ERR(p))
++ error = PTR_ERR(p);
++ else
++ astd_task = p;
++ return error;
++}
++
++void dlm_astd_stop(void)
++{
++ kthread_stop(astd_task);
++}
++
++void dlm_astd_suspend(void)
++{
++ mutex_lock(&astd_running);
++}
++
++void dlm_astd_resume(void)
++{
++ mutex_unlock(&astd_running);
++}
++
+diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h
+new file mode 100644
+index 0000000..6ee276c
+--- /dev/null
++++ b/fs/dlm/ast.h
+@@ -0,0 +1,26 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __ASTD_DOT_H__
++#define __ASTD_DOT_H__
++
++void dlm_add_ast(struct dlm_lkb *lkb, int type);
++void dlm_del_ast(struct dlm_lkb *lkb);
++
++void dlm_astd_wake(void);
++int dlm_astd_start(void);
++void dlm_astd_stop(void);
++void dlm_astd_suspend(void);
++void dlm_astd_resume(void);
++
++#endif
++
+diff --git a/fs/dlm/config.c b/fs/dlm/config.c
+new file mode 100644
+index 0000000..8855305
+--- /dev/null
++++ b/fs/dlm/config.c
+@@ -0,0 +1,789 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/configfs.h>
++#include <net/sock.h>
++
++#include "config.h"
++#include "lowcomms.h"
++
++/*
++ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/nodeid
++ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/weight
++ * /config/dlm/<cluster>/comms/<comm>/nodeid
++ * /config/dlm/<cluster>/comms/<comm>/local
++ * /config/dlm/<cluster>/comms/<comm>/addr
++ * The <cluster> level is useless, but I haven't figured out how to avoid it.
++ */
++
++static struct config_group *space_list;
++static struct config_group *comm_list;
++static struct comm *local_comm;
++
++struct clusters;
++struct cluster;
++struct spaces;
++struct space;
++struct comms;
++struct comm;
++struct nodes;
++struct node;
++
++static struct config_group *make_cluster(struct config_group *, const char *);
++static void drop_cluster(struct config_group *, struct config_item *);
++static void release_cluster(struct config_item *);
++static struct config_group *make_space(struct config_group *, const char *);
++static void drop_space(struct config_group *, struct config_item *);
++static void release_space(struct config_item *);
++static struct config_item *make_comm(struct config_group *, const char *);
++static void drop_comm(struct config_group *, struct config_item *);
++static void release_comm(struct config_item *);
++static struct config_item *make_node(struct config_group *, const char *);
++static void drop_node(struct config_group *, struct config_item *);
++static void release_node(struct config_item *);
++
++static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
++ char *buf);
++static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
++ const char *buf, size_t len);
++static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
++ char *buf);
++static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
++ const char *buf, size_t len);
++
++static ssize_t comm_nodeid_read(struct comm *cm, char *buf);
++static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len);
++static ssize_t comm_local_read(struct comm *cm, char *buf);
++static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len);
++static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len);
++static ssize_t node_nodeid_read(struct node *nd, char *buf);
++static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len);
++static ssize_t node_weight_read(struct node *nd, char *buf);
++static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len);
++
++enum {
++ COMM_ATTR_NODEID = 0,
++ COMM_ATTR_LOCAL,
++ COMM_ATTR_ADDR,
++};
++
++struct comm_attribute {
++ struct configfs_attribute attr;
++ ssize_t (*show)(struct comm *, char *);
++ ssize_t (*store)(struct comm *, const char *, size_t);
++};
++
++static struct comm_attribute comm_attr_nodeid = {
++ .attr = { .ca_owner = THIS_MODULE,
++ .ca_name = "nodeid",
++ .ca_mode = S_IRUGO | S_IWUSR },
++ .show = comm_nodeid_read,
++ .store = comm_nodeid_write,
++};
++
++static struct comm_attribute comm_attr_local = {
++ .attr = { .ca_owner = THIS_MODULE,
++ .ca_name = "local",
++ .ca_mode = S_IRUGO | S_IWUSR },
++ .show = comm_local_read,
++ .store = comm_local_write,
++};
++
++static struct comm_attribute comm_attr_addr = {
++ .attr = { .ca_owner = THIS_MODULE,
++ .ca_name = "addr",
++ .ca_mode = S_IRUGO | S_IWUSR },
++ .store = comm_addr_write,
++};
++
++static struct configfs_attribute *comm_attrs[] = {
++ [COMM_ATTR_NODEID] = &comm_attr_nodeid.attr,
++ [COMM_ATTR_LOCAL] = &comm_attr_local.attr,
++ [COMM_ATTR_ADDR] = &comm_attr_addr.attr,
++ NULL,
++};
++
++enum {
++ NODE_ATTR_NODEID = 0,
++ NODE_ATTR_WEIGHT,
++};
++
++struct node_attribute {
++ struct configfs_attribute attr;
++ ssize_t (*show)(struct node *, char *);
++ ssize_t (*store)(struct node *, const char *, size_t);
++};
++
++static struct node_attribute node_attr_nodeid = {
++ .attr = { .ca_owner = THIS_MODULE,
++ .ca_name = "nodeid",
++ .ca_mode = S_IRUGO | S_IWUSR },
++ .show = node_nodeid_read,
++ .store = node_nodeid_write,
++};
++
++static struct node_attribute node_attr_weight = {
++ .attr = { .ca_owner = THIS_MODULE,
++ .ca_name = "weight",
++ .ca_mode = S_IRUGO | S_IWUSR },
++ .show = node_weight_read,
++ .store = node_weight_write,
++};
++
++static struct configfs_attribute *node_attrs[] = {
++ [NODE_ATTR_NODEID] = &node_attr_nodeid.attr,
++ [NODE_ATTR_WEIGHT] = &node_attr_weight.attr,
++ NULL,
++};
++
++struct clusters {
++ struct configfs_subsystem subsys;
++};
++
++struct cluster {
++ struct config_group group;
++};
++
++struct spaces {
++ struct config_group ss_group;
++};
++
++struct space {
++ struct config_group group;
++ struct list_head members;
++ struct mutex members_lock;
++ int members_count;
++};
++
++struct comms {
++ struct config_group cs_group;
++};
++
++struct comm {
++ struct config_item item;
++ int nodeid;
++ int local;
++ int addr_count;
++ struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
++};
++
++struct nodes {
++ struct config_group ns_group;
++};
++
++struct node {
++ struct config_item item;
++ struct list_head list; /* space->members */
++ int nodeid;
++ int weight;
++};
++
++static struct configfs_group_operations clusters_ops = {
++ .make_group = make_cluster,
++ .drop_item = drop_cluster,
++};
++
++static struct configfs_item_operations cluster_ops = {
++ .release = release_cluster,
++};
++
++static struct configfs_group_operations spaces_ops = {
++ .make_group = make_space,
++ .drop_item = drop_space,
++};
++
++static struct configfs_item_operations space_ops = {
++ .release = release_space,
++};
++
++static struct configfs_group_operations comms_ops = {
++ .make_item = make_comm,
++ .drop_item = drop_comm,
++};
++
++static struct configfs_item_operations comm_ops = {
++ .release = release_comm,
++ .show_attribute = show_comm,
++ .store_attribute = store_comm,
++};
++
++static struct configfs_group_operations nodes_ops = {
++ .make_item = make_node,
++ .drop_item = drop_node,
++};
++
++static struct configfs_item_operations node_ops = {
++ .release = release_node,
++ .show_attribute = show_node,
++ .store_attribute = store_node,
++};
++
++static struct config_item_type clusters_type = {
++ .ct_group_ops = &clusters_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type cluster_type = {
++ .ct_item_ops = &cluster_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type spaces_type = {
++ .ct_group_ops = &spaces_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type space_type = {
++ .ct_item_ops = &space_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type comms_type = {
++ .ct_group_ops = &comms_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type comm_type = {
++ .ct_item_ops = &comm_ops,
++ .ct_attrs = comm_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type nodes_type = {
++ .ct_group_ops = &nodes_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item_type node_type = {
++ .ct_item_ops = &node_ops,
++ .ct_attrs = node_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct cluster *to_cluster(struct config_item *i)
++{
++ return i ? container_of(to_config_group(i), struct cluster, group):NULL;
++}
++
++static struct space *to_space(struct config_item *i)
++{
++ return i ? container_of(to_config_group(i), struct space, group) : NULL;
++}
++
++static struct comm *to_comm(struct config_item *i)
++{
++ return i ? container_of(i, struct comm, item) : NULL;
++}
++
++static struct node *to_node(struct config_item *i)
++{
++ return i ? container_of(i, struct node, item) : NULL;
++}
++
++static struct config_group *make_cluster(struct config_group *g,
++ const char *name)
++{
++ struct cluster *cl = NULL;
++ struct spaces *sps = NULL;
++ struct comms *cms = NULL;
++ void *gps = NULL;
++
++ cl = kzalloc(sizeof(struct cluster), GFP_KERNEL);
++ gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
++ sps = kzalloc(sizeof(struct spaces), GFP_KERNEL);
++ cms = kzalloc(sizeof(struct comms), GFP_KERNEL);
++
++ if (!cl || !gps || !sps || !cms)
++ goto fail;
++
++ config_group_init_type_name(&cl->group, name, &cluster_type);
++ config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type);
++ config_group_init_type_name(&cms->cs_group, "comms", &comms_type);
++
++ cl->group.default_groups = gps;
++ cl->group.default_groups[0] = &sps->ss_group;
++ cl->group.default_groups[1] = &cms->cs_group;
++ cl->group.default_groups[2] = NULL;
++
++ space_list = &sps->ss_group;
++ comm_list = &cms->cs_group;
++ return &cl->group;
++
++ fail:
++ kfree(cl);
++ kfree(gps);
++ kfree(sps);
++ kfree(cms);
++ return NULL;
++}
++
++static void drop_cluster(struct config_group *g, struct config_item *i)
++{
++ struct cluster *cl = to_cluster(i);
++ struct config_item *tmp;
++ int j;
++
++ for (j = 0; cl->group.default_groups[j]; j++) {
++ tmp = &cl->group.default_groups[j]->cg_item;
++ cl->group.default_groups[j] = NULL;
++ config_item_put(tmp);
++ }
++
++ space_list = NULL;
++ comm_list = NULL;
++
++ config_item_put(i);
++}
++
++static void release_cluster(struct config_item *i)
++{
++ struct cluster *cl = to_cluster(i);
++ kfree(cl->group.default_groups);
++ kfree(cl);
++}
++
++static struct config_group *make_space(struct config_group *g, const char *name)
++{
++ struct space *sp = NULL;
++ struct nodes *nds = NULL;
++ void *gps = NULL;
++
++ sp = kzalloc(sizeof(struct space), GFP_KERNEL);
++ gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL);
++ nds = kzalloc(sizeof(struct nodes), GFP_KERNEL);
++
++ if (!sp || !gps || !nds)
++ goto fail;
++
++ config_group_init_type_name(&sp->group, name, &space_type);
++ config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
++
++ sp->group.default_groups = gps;
++ sp->group.default_groups[0] = &nds->ns_group;
++ sp->group.default_groups[1] = NULL;
++
++ INIT_LIST_HEAD(&sp->members);
++ mutex_init(&sp->members_lock);
++ sp->members_count = 0;
++ return &sp->group;
++
++ fail:
++ kfree(sp);
++ kfree(gps);
++ kfree(nds);
++ return NULL;
++}
++
++static void drop_space(struct config_group *g, struct config_item *i)
++{
++ struct space *sp = to_space(i);
++ struct config_item *tmp;
++ int j;
++
++ /* assert list_empty(&sp->members) */
++
++ for (j = 0; sp->group.default_groups[j]; j++) {
++ tmp = &sp->group.default_groups[j]->cg_item;
++ sp->group.default_groups[j] = NULL;
++ config_item_put(tmp);
++ }
++
++ config_item_put(i);
++}
++
++static void release_space(struct config_item *i)
++{
++ struct space *sp = to_space(i);
++ kfree(sp->group.default_groups);
++ kfree(sp);
++}
++
++static struct config_item *make_comm(struct config_group *g, const char *name)
++{
++ struct comm *cm;
++
++ cm = kzalloc(sizeof(struct comm), GFP_KERNEL);
++ if (!cm)
++ return NULL;
++
++ config_item_init_type_name(&cm->item, name, &comm_type);
++ cm->nodeid = -1;
++ cm->local = 0;
++ cm->addr_count = 0;
++ return &cm->item;
++}
++
++static void drop_comm(struct config_group *g, struct config_item *i)
++{
++ struct comm *cm = to_comm(i);
++ if (local_comm == cm)
++ local_comm = NULL;
++ dlm_lowcomms_close(cm->nodeid);
++ while (cm->addr_count--)
++ kfree(cm->addr[cm->addr_count]);
++ config_item_put(i);
++}
++
++static void release_comm(struct config_item *i)
++{
++ struct comm *cm = to_comm(i);
++ kfree(cm);
++}
++
++static struct config_item *make_node(struct config_group *g, const char *name)
++{
++ struct space *sp = to_space(g->cg_item.ci_parent);
++ struct node *nd;
++
++ nd = kzalloc(sizeof(struct node), GFP_KERNEL);
++ if (!nd)
++ return NULL;
++
++ config_item_init_type_name(&nd->item, name, &node_type);
++ nd->nodeid = -1;
++ nd->weight = 1; /* default weight of 1 if none is set */
++
++ mutex_lock(&sp->members_lock);
++ list_add(&nd->list, &sp->members);
++ sp->members_count++;
++ mutex_unlock(&sp->members_lock);
++
++ return &nd->item;
++}
++
++static void drop_node(struct config_group *g, struct config_item *i)
++{
++ struct space *sp = to_space(g->cg_item.ci_parent);
++ struct node *nd = to_node(i);
++
++ mutex_lock(&sp->members_lock);
++ list_del(&nd->list);
++ sp->members_count--;
++ mutex_unlock(&sp->members_lock);
++
++ config_item_put(i);
++}
++
++static void release_node(struct config_item *i)
++{
++ struct node *nd = to_node(i);
++ kfree(nd);
++}
++
++static struct clusters clusters_root = {
++ .subsys = {
++ .su_group = {
++ .cg_item = {
++ .ci_namebuf = "dlm",
++ .ci_type = &clusters_type,
++ },
++ },
++ },
++};
++
++int dlm_config_init(void)
++{
++ config_group_init(&clusters_root.subsys.su_group);
++ init_MUTEX(&clusters_root.subsys.su_sem);
++ return configfs_register_subsystem(&clusters_root.subsys);
++}
++
++void dlm_config_exit(void)
++{
++ configfs_unregister_subsystem(&clusters_root.subsys);
++}
++
++/*
++ * Functions for user space to read/write attributes
++ */
++
++static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
++ char *buf)
++{
++ struct comm *cm = to_comm(i);
++ struct comm_attribute *cma =
++ container_of(a, struct comm_attribute, attr);
++ return cma->show ? cma->show(cm, buf) : 0;
++}
++
++static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
++ const char *buf, size_t len)
++{
++ struct comm *cm = to_comm(i);
++ struct comm_attribute *cma =
++ container_of(a, struct comm_attribute, attr);
++ return cma->store ? cma->store(cm, buf, len) : -EINVAL;
++}
++
++static ssize_t comm_nodeid_read(struct comm *cm, char *buf)
++{
++ return sprintf(buf, "%d\n", cm->nodeid);
++}
++
++static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len)
++{
++ cm->nodeid = simple_strtol(buf, NULL, 0);
++ return len;
++}
++
++static ssize_t comm_local_read(struct comm *cm, char *buf)
++{
++ return sprintf(buf, "%d\n", cm->local);
++}
++
++static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len)
++{
++ cm->local= simple_strtol(buf, NULL, 0);
++ if (cm->local && !local_comm)
++ local_comm = cm;
++ return len;
++}
++
++static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len)
++{
++ struct sockaddr_storage *addr;
++
++ if (len != sizeof(struct sockaddr_storage))
++ return -EINVAL;
++
++ if (cm->addr_count >= DLM_MAX_ADDR_COUNT)
++ return -ENOSPC;
++
++ addr = kzalloc(sizeof(*addr), GFP_KERNEL);
++ if (!addr)
++ return -ENOMEM;
++
++ memcpy(addr, buf, len);
++ cm->addr[cm->addr_count++] = addr;
++ return len;
++}
++
++static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
++ char *buf)
++{
++ struct node *nd = to_node(i);
++ struct node_attribute *nda =
++ container_of(a, struct node_attribute, attr);
++ return nda->show ? nda->show(nd, buf) : 0;
++}
++
++static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
++ const char *buf, size_t len)
++{
++ struct node *nd = to_node(i);
++ struct node_attribute *nda =
++ container_of(a, struct node_attribute, attr);
++ return nda->store ? nda->store(nd, buf, len) : -EINVAL;
++}
++
++static ssize_t node_nodeid_read(struct node *nd, char *buf)
++{
++ return sprintf(buf, "%d\n", nd->nodeid);
++}
++
++static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len)
++{
++ nd->nodeid = simple_strtol(buf, NULL, 0);
++ return len;
++}
++
++static ssize_t node_weight_read(struct node *nd, char *buf)
++{
++ return sprintf(buf, "%d\n", nd->weight);
++}
++
++static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len)
++{
++ nd->weight = simple_strtol(buf, NULL, 0);
++ return len;
++}
++
++/*
++ * Functions for the dlm to get the info that's been configured
++ */
++
++static struct space *get_space(char *name)
++{
++ if (!space_list)
++ return NULL;
++ return to_space(config_group_find_obj(space_list, name));
++}
++
++static void put_space(struct space *sp)
++{
++ config_item_put(&sp->group.cg_item);
++}
++
++static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr)
++{
++ struct config_item *i;
++ struct comm *cm = NULL;
++ int found = 0;
++
++ if (!comm_list)
++ return NULL;
++
++ down(&clusters_root.subsys.su_sem);
++
++ list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
++ cm = to_comm(i);
++
++ if (nodeid) {
++ if (cm->nodeid != nodeid)
++ continue;
++ found = 1;
++ break;
++ } else {
++ if (!cm->addr_count ||
++ memcmp(cm->addr[0], addr, sizeof(*addr)))
++ continue;
++ found = 1;
++ break;
++ }
++ }
++ up(&clusters_root.subsys.su_sem);
++
++ if (found)
++ config_item_get(i);
++ else
++ cm = NULL;
++ return cm;
++}
++
++static void put_comm(struct comm *cm)
++{
++ config_item_put(&cm->item);
++}
++
++/* caller must free mem */
++int dlm_nodeid_list(char *lsname, int **ids_out)
++{
++ struct space *sp;
++ struct node *nd;
++ int i = 0, rv = 0;
++ int *ids;
++
++ sp = get_space(lsname);
++ if (!sp)
++ return -EEXIST;
++
++ mutex_lock(&sp->members_lock);
++ if (!sp->members_count) {
++ rv = 0;
++ goto out;
++ }
++
++ ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL);
++ if (!ids) {
++ rv = -ENOMEM;
++ goto out;
++ }
++
++ rv = sp->members_count;
++ list_for_each_entry(nd, &sp->members, list)
++ ids[i++] = nd->nodeid;
++
++ if (rv != i)
++ printk("bad nodeid count %d %d\n", rv, i);
++
++ *ids_out = ids;
++ out:
++ mutex_unlock(&sp->members_lock);
++ put_space(sp);
++ return rv;
++}
++
++int dlm_node_weight(char *lsname, int nodeid)
++{
++ struct space *sp;
++ struct node *nd;
++ int w = -EEXIST;
++
++ sp = get_space(lsname);
++ if (!sp)
++ goto out;
++
++ mutex_lock(&sp->members_lock);
++ list_for_each_entry(nd, &sp->members, list) {
++ if (nd->nodeid != nodeid)
++ continue;
++ w = nd->weight;
++ break;
++ }
++ mutex_unlock(&sp->members_lock);
++ put_space(sp);
++ out:
++ return w;
++}
++
++int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
++{
++ struct comm *cm = get_comm(nodeid, NULL);
++ if (!cm)
++ return -EEXIST;
++ if (!cm->addr_count)
++ return -ENOENT;
++ memcpy(addr, cm->addr[0], sizeof(*addr));
++ put_comm(cm);
++ return 0;
++}
++
++int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
++{
++ struct comm *cm = get_comm(0, addr);
++ if (!cm)
++ return -EEXIST;
++ *nodeid = cm->nodeid;
++ put_comm(cm);
++ return 0;
++}
++
++int dlm_our_nodeid(void)
++{
++ return local_comm ? local_comm->nodeid : 0;
++}
++
++/* num 0 is first addr, num 1 is second addr */
++int dlm_our_addr(struct sockaddr_storage *addr, int num)
++{
++ if (!local_comm)
++ return -1;
++ if (num + 1 > local_comm->addr_count)
++ return -1;
++ memcpy(addr, local_comm->addr[num], sizeof(*addr));
++ return 0;
++}
++
++/* Config file defaults */
++#define DEFAULT_TCP_PORT 21064
++#define DEFAULT_BUFFER_SIZE 4096
++#define DEFAULT_RSBTBL_SIZE 256
++#define DEFAULT_LKBTBL_SIZE 1024
++#define DEFAULT_DIRTBL_SIZE 512
++#define DEFAULT_RECOVER_TIMER 5
++#define DEFAULT_TOSS_SECS 10
++#define DEFAULT_SCAN_SECS 5
++
++struct dlm_config_info dlm_config = {
++ .tcp_port = DEFAULT_TCP_PORT,
++ .buffer_size = DEFAULT_BUFFER_SIZE,
++ .rsbtbl_size = DEFAULT_RSBTBL_SIZE,
++ .lkbtbl_size = DEFAULT_LKBTBL_SIZE,
++ .dirtbl_size = DEFAULT_DIRTBL_SIZE,
++ .recover_timer = DEFAULT_RECOVER_TIMER,
++ .toss_secs = DEFAULT_TOSS_SECS,
++ .scan_secs = DEFAULT_SCAN_SECS
++};
++
+diff --git a/fs/dlm/config.h b/fs/dlm/config.h
+new file mode 100644
+index 0000000..9da7839
+--- /dev/null
++++ b/fs/dlm/config.h
+@@ -0,0 +1,42 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __CONFIG_DOT_H__
++#define __CONFIG_DOT_H__
++
++#define DLM_MAX_ADDR_COUNT 3
++
++struct dlm_config_info {
++ int tcp_port;
++ int buffer_size;
++ int rsbtbl_size;
++ int lkbtbl_size;
++ int dirtbl_size;
++ int recover_timer;
++ int toss_secs;
++ int scan_secs;
++};
++
++extern struct dlm_config_info dlm_config;
++
++int dlm_config_init(void);
++void dlm_config_exit(void);
++int dlm_node_weight(char *lsname, int nodeid);
++int dlm_nodeid_list(char *lsname, int **ids_out);
++int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
++int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
++int dlm_our_nodeid(void);
++int dlm_our_addr(struct sockaddr_storage *addr, int num);
++
++#endif /* __CONFIG_DOT_H__ */
++
+diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
+new file mode 100644
+index 0000000..ca94a83
+--- /dev/null
++++ b/fs/dlm/debug_fs.c
+@@ -0,0 +1,387 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include <linux/pagemap.h>
++#include <linux/seq_file.h>
++#include <linux/module.h>
++#include <linux/ctype.h>
++#include <linux/debugfs.h>
++
++#include "dlm_internal.h"
++
++#define DLM_DEBUG_BUF_LEN 4096
++static char debug_buf[DLM_DEBUG_BUF_LEN];
++static struct mutex debug_buf_lock;
++
++static struct dentry *dlm_root;
++
++struct rsb_iter {
++ int entry;
++ struct dlm_ls *ls;
++ struct list_head *next;
++ struct dlm_rsb *rsb;
++};
++
++/*
++ * dump all rsb's in the lockspace hash table
++ */
++
++static char *print_lockmode(int mode)
++{
++ switch (mode) {
++ case DLM_LOCK_IV:
++ return "--";
++ case DLM_LOCK_NL:
++ return "NL";
++ case DLM_LOCK_CR:
++ return "CR";
++ case DLM_LOCK_CW:
++ return "CW";
++ case DLM_LOCK_PR:
++ return "PR";
++ case DLM_LOCK_PW:
++ return "PW";
++ case DLM_LOCK_EX:
++ return "EX";
++ default:
++ return "??";
++ }
++}
++
++static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
++ struct dlm_rsb *res)
++{
++ seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
++
++ if (lkb->lkb_status == DLM_LKSTS_CONVERT
++ || lkb->lkb_status == DLM_LKSTS_WAITING)
++ seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
++
++ if (lkb->lkb_nodeid) {
++ if (lkb->lkb_nodeid != res->res_nodeid)
++ seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
++ lkb->lkb_remid);
++ else
++ seq_printf(s, " Master: %08x", lkb->lkb_remid);
++ }
++
++ if (lkb->lkb_wait_type)
++ seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
++
++ seq_printf(s, "\n");
++}
++
++static int print_resource(struct dlm_rsb *res, struct seq_file *s)
++{
++ struct dlm_lkb *lkb;
++ int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
++
++ seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
++ for (i = 0; i < res->res_length; i++) {
++ if (isprint(res->res_name[i]))
++ seq_printf(s, "%c", res->res_name[i]);
++ else
++ seq_printf(s, "%c", '.');
++ }
++ if (res->res_nodeid > 0)
++ seq_printf(s, "\" \nLocal Copy, Master is node %d\n",
++ res->res_nodeid);
++ else if (res->res_nodeid == 0)
++ seq_printf(s, "\" \nMaster Copy\n");
++ else if (res->res_nodeid == -1)
++ seq_printf(s, "\" \nLooking up master (lkid %x)\n",
++ res->res_first_lkid);
++ else
++ seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid);
++
++ /* Print the LVB: */
++ if (res->res_lvbptr) {
++ seq_printf(s, "LVB: ");
++ for (i = 0; i < lvblen; i++) {
++ if (i == lvblen / 2)
++ seq_printf(s, "\n ");
++ seq_printf(s, "%02x ",
++ (unsigned char) res->res_lvbptr[i]);
++ }
++ if (rsb_flag(res, RSB_VALNOTVALID))
++ seq_printf(s, " (INVALID)");
++ seq_printf(s, "\n");
++ }
++
++ root_list = !list_empty(&res->res_root_list);
++ recover_list = !list_empty(&res->res_recover_list);
++
++ if (root_list || recover_list) {
++ seq_printf(s, "Recovery: root %d recover %d flags %lx "
++ "count %d\n", root_list, recover_list,
++ res->res_flags, res->res_recover_locks_count);
++ }
++
++ /* Print the locks attached to this resource */
++ seq_printf(s, "Granted Queue\n");
++ list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
++ print_lock(s, lkb, res);
++
++ seq_printf(s, "Conversion Queue\n");
++ list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
++ print_lock(s, lkb, res);
++
++ seq_printf(s, "Waiting Queue\n");
++ list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
++ print_lock(s, lkb, res);
++
++ if (list_empty(&res->res_lookup))
++ goto out;
++
++ seq_printf(s, "Lookup Queue\n");
++ list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
++ seq_printf(s, "%08x %s", lkb->lkb_id,
++ print_lockmode(lkb->lkb_rqmode));
++ if (lkb->lkb_wait_type)
++ seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
++ seq_printf(s, "\n");
++ }
++ out:
++ return 0;
++}
++
++static int rsb_iter_next(struct rsb_iter *ri)
++{
++ struct dlm_ls *ls = ri->ls;
++ int i;
++
++ if (!ri->next) {
++ top:
++ /* Find the next non-empty hash bucket */
++ for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
++ read_lock(&ls->ls_rsbtbl[i].lock);
++ if (!list_empty(&ls->ls_rsbtbl[i].list)) {
++ ri->next = ls->ls_rsbtbl[i].list.next;
++ read_unlock(&ls->ls_rsbtbl[i].lock);
++ break;
++ }
++ read_unlock(&ls->ls_rsbtbl[i].lock);
++ }
++ ri->entry = i;
++
++ if (ri->entry >= ls->ls_rsbtbl_size)
++ return 1;
++ } else {
++ i = ri->entry;
++ read_lock(&ls->ls_rsbtbl[i].lock);
++ ri->next = ri->next->next;
++ if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
++ /* End of list - move to next bucket */
++ ri->next = NULL;
++ ri->entry++;
++ read_unlock(&ls->ls_rsbtbl[i].lock);
++ goto top;
++ }
++ read_unlock(&ls->ls_rsbtbl[i].lock);
++ }
++ ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
++
++ return 0;
++}
++
++static void rsb_iter_free(struct rsb_iter *ri)
++{
++ kfree(ri);
++}
++
++static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
++{
++ struct rsb_iter *ri;
++
++ ri = kmalloc(sizeof *ri, GFP_KERNEL);
++ if (!ri)
++ return NULL;
++
++ ri->ls = ls;
++ ri->entry = 0;
++ ri->next = NULL;
++
++ if (rsb_iter_next(ri)) {
++ rsb_iter_free(ri);
++ return NULL;
++ }
++
++ return ri;
++}
++
++static void *rsb_seq_start(struct seq_file *file, loff_t *pos)
++{
++ struct rsb_iter *ri;
++ loff_t n = *pos;
++
++ ri = rsb_iter_init(file->private);
++ if (!ri)
++ return NULL;
++
++ while (n--) {
++ if (rsb_iter_next(ri)) {
++ rsb_iter_free(ri);
++ return NULL;
++ }
++ }
++
++ return ri;
++}
++
++static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
++{
++ struct rsb_iter *ri = iter_ptr;
++
++ (*pos)++;
++
++ if (rsb_iter_next(ri)) {
++ rsb_iter_free(ri);
++ return NULL;
++ }
++
++ return ri;
++}
++
++static void rsb_seq_stop(struct seq_file *file, void *iter_ptr)
++{
++ /* nothing for now */
++}
++
++static int rsb_seq_show(struct seq_file *file, void *iter_ptr)
++{
++ struct rsb_iter *ri = iter_ptr;
++
++ print_resource(ri->rsb, file);
++
++ return 0;
++}
++
++static struct seq_operations rsb_seq_ops = {
++ .start = rsb_seq_start,
++ .next = rsb_seq_next,
++ .stop = rsb_seq_stop,
++ .show = rsb_seq_show,
++};
++
++static int rsb_open(struct inode *inode, struct file *file)
++{
++ struct seq_file *seq;
++ int ret;
++
++ ret = seq_open(file, &rsb_seq_ops);
++ if (ret)
++ return ret;
++
++ seq = file->private_data;
++ seq->private = inode->i_private;
++
++ return 0;
++}
++
++static struct file_operations rsb_fops = {
++ .owner = THIS_MODULE,
++ .open = rsb_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release
++};
++
++/*
++ * dump lkb's on the ls_waiters list
++ */
++
++static int waiters_open(struct inode *inode, struct file *file)
++{
++ file->private_data = inode->i_private;
++ return 0;
++}
++
++static ssize_t waiters_read(struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ struct dlm_ls *ls = file->private_data;
++ struct dlm_lkb *lkb;
++ size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
++
++ mutex_lock(&debug_buf_lock);
++ mutex_lock(&ls->ls_waiters_mutex);
++ memset(debug_buf, 0, sizeof(debug_buf));
++
++ list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
++ ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
++ lkb->lkb_id, lkb->lkb_wait_type,
++ lkb->lkb_nodeid, lkb->lkb_resource->res_name);
++ if (ret >= len - pos)
++ break;
++ pos += ret;
++ }
++ mutex_unlock(&ls->ls_waiters_mutex);
++
++ rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
++ mutex_unlock(&debug_buf_lock);
++ return rv;
++}
++
++static struct file_operations waiters_fops = {
++ .owner = THIS_MODULE,
++ .open = waiters_open,
++ .read = waiters_read
++};
++
++int dlm_create_debug_file(struct dlm_ls *ls)
++{
++ char name[DLM_LOCKSPACE_LEN+8];
++
++ ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
++ S_IFREG | S_IRUGO,
++ dlm_root,
++ ls,
++ &rsb_fops);
++ if (!ls->ls_debug_rsb_dentry)
++ return -ENOMEM;
++
++ memset(name, 0, sizeof(name));
++ snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
++
++ ls->ls_debug_waiters_dentry = debugfs_create_file(name,
++ S_IFREG | S_IRUGO,
++ dlm_root,
++ ls,
++ &waiters_fops);
++ if (!ls->ls_debug_waiters_dentry) {
++ debugfs_remove(ls->ls_debug_rsb_dentry);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++void dlm_delete_debug_file(struct dlm_ls *ls)
++{
++ if (ls->ls_debug_rsb_dentry)
++ debugfs_remove(ls->ls_debug_rsb_dentry);
++ if (ls->ls_debug_waiters_dentry)
++ debugfs_remove(ls->ls_debug_waiters_dentry);
++}
++
++int dlm_register_debugfs(void)
++{
++ mutex_init(&debug_buf_lock);
++ dlm_root = debugfs_create_dir("dlm", NULL);
++ return dlm_root ? 0 : -ENOMEM;
++}
++
++void dlm_unregister_debugfs(void)
++{
++ debugfs_remove(dlm_root);
++}
++
+diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c
+new file mode 100644
+index 0000000..4675455
+--- /dev/null
++++ b/fs/dlm/dir.c
+@@ -0,0 +1,423 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "member.h"
++#include "lowcomms.h"
++#include "rcom.h"
++#include "config.h"
++#include "memory.h"
++#include "recover.h"
++#include "util.h"
++#include "lock.h"
++#include "dir.h"
++
++
++static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
++{
++ spin_lock(&ls->ls_recover_list_lock);
++ list_add(&de->list, &ls->ls_recover_list);
++ spin_unlock(&ls->ls_recover_list_lock);
++}
++
++static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
++{
++ int found = 0;
++ struct dlm_direntry *de;
++
++ spin_lock(&ls->ls_recover_list_lock);
++ list_for_each_entry(de, &ls->ls_recover_list, list) {
++ if (de->length == len) {
++ list_del(&de->list);
++ de->master_nodeid = 0;
++ memset(de->name, 0, len);
++ found = 1;
++ break;
++ }
++ }
++ spin_unlock(&ls->ls_recover_list_lock);
++
++ if (!found)
++ de = allocate_direntry(ls, len);
++ return de;
++}
++
++void dlm_clear_free_entries(struct dlm_ls *ls)
++{
++ struct dlm_direntry *de;
++
++ spin_lock(&ls->ls_recover_list_lock);
++ while (!list_empty(&ls->ls_recover_list)) {
++ de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
++ list);
++ list_del(&de->list);
++ free_direntry(de);
++ }
++ spin_unlock(&ls->ls_recover_list_lock);
++}
++
++/*
++ * We use the upper 16 bits of the hash value to select the directory node.
++ * Low bits are used for distribution of rsb's among hash buckets on each node.
++ *
++ * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
++ * num_nodes to the hash value. This value in the desired range is used as an
++ * offset into the sorted list of nodeid's to give the particular nodeid.
++ */
++
++int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
++{
++ struct list_head *tmp;
++ struct dlm_member *memb = NULL;
++ uint32_t node, n = 0;
++ int nodeid;
++
++ if (ls->ls_num_nodes == 1) {
++ nodeid = dlm_our_nodeid();
++ goto out;
++ }
++
++ if (ls->ls_node_array) {
++ node = (hash >> 16) % ls->ls_total_weight;
++ nodeid = ls->ls_node_array[node];
++ goto out;
++ }
++
++ /* make_member_array() failed to kmalloc ls_node_array... */
++
++ node = (hash >> 16) % ls->ls_num_nodes;
++
++ list_for_each(tmp, &ls->ls_nodes) {
++ if (n++ != node)
++ continue;
++ memb = list_entry(tmp, struct dlm_member, list);
++ break;
++ }
++
++ DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
++ ls->ls_num_nodes, n, node););
++ nodeid = memb->nodeid;
++ out:
++ return nodeid;
++}
++
++int dlm_dir_nodeid(struct dlm_rsb *r)
++{
++ return dlm_hash2nodeid(r->res_ls, r->res_hash);
++}
++
++static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
++{
++ uint32_t val;
++
++ val = jhash(name, len, 0);
++ val &= (ls->ls_dirtbl_size - 1);
++
++ return val;
++}
++
++static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
++{
++ uint32_t bucket;
++
++ bucket = dir_hash(ls, de->name, de->length);
++ list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
++}
++
++static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
++ int namelen, uint32_t bucket)
++{
++ struct dlm_direntry *de;
++
++ list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
++ if (de->length == namelen && !memcmp(name, de->name, namelen))
++ goto out;
++ }
++ de = NULL;
++ out:
++ return de;
++}
++
++void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
++{
++ struct dlm_direntry *de;
++ uint32_t bucket;
++
++ bucket = dir_hash(ls, name, namelen);
++
++ write_lock(&ls->ls_dirtbl[bucket].lock);
++
++ de = search_bucket(ls, name, namelen, bucket);
++
++ if (!de) {
++ log_error(ls, "remove fr %u none", nodeid);
++ goto out;
++ }
++
++ if (de->master_nodeid != nodeid) {
++ log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
++ goto out;
++ }
++
++ list_del(&de->list);
++ free_direntry(de);
++ out:
++ write_unlock(&ls->ls_dirtbl[bucket].lock);
++}
++
++void dlm_dir_clear(struct dlm_ls *ls)
++{
++ struct list_head *head;
++ struct dlm_direntry *de;
++ int i;
++
++ DLM_ASSERT(list_empty(&ls->ls_recover_list), );
++
++ for (i = 0; i < ls->ls_dirtbl_size; i++) {
++ write_lock(&ls->ls_dirtbl[i].lock);
++ head = &ls->ls_dirtbl[i].list;
++ while (!list_empty(head)) {
++ de = list_entry(head->next, struct dlm_direntry, list);
++ list_del(&de->list);
++ put_free_de(ls, de);
++ }
++ write_unlock(&ls->ls_dirtbl[i].lock);
++ }
++}
++
++int dlm_recover_directory(struct dlm_ls *ls)
++{
++ struct dlm_member *memb;
++ struct dlm_direntry *de;
++ char *b, *last_name = NULL;
++ int error = -ENOMEM, last_len, count = 0;
++ uint16_t namelen;
++
++ log_debug(ls, "dlm_recover_directory");
++
++ if (dlm_no_directory(ls))
++ goto out_status;
++
++ dlm_dir_clear(ls);
++
++ last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
++ if (!last_name)
++ goto out;
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ memset(last_name, 0, DLM_RESNAME_MAXLEN);
++ last_len = 0;
++
++ for (;;) {
++ error = dlm_recovery_stopped(ls);
++ if (error)
++ goto out_free;
++
++ error = dlm_rcom_names(ls, memb->nodeid,
++ last_name, last_len);
++ if (error)
++ goto out_free;
++
++ schedule();
++
++ /*
++ * pick namelen/name pairs out of received buffer
++ */
++
++ b = ls->ls_recover_buf + sizeof(struct dlm_rcom);
++
++ for (;;) {
++ memcpy(&namelen, b, sizeof(uint16_t));
++ namelen = be16_to_cpu(namelen);
++ b += sizeof(uint16_t);
++
++ /* namelen of 0xFFFFF marks end of names for
++ this node; namelen of 0 marks end of the
++ buffer */
++
++ if (namelen == 0xFFFF)
++ goto done;
++ if (!namelen)
++ break;
++
++ error = -ENOMEM;
++ de = get_free_de(ls, namelen);
++ if (!de)
++ goto out_free;
++
++ de->master_nodeid = memb->nodeid;
++ de->length = namelen;
++ last_len = namelen;
++ memcpy(de->name, b, namelen);
++ memcpy(last_name, b, namelen);
++ b += namelen;
++
++ add_entry_to_hash(ls, de);
++ count++;
++ }
++ }
++ done:
++ ;
++ }
++
++ out_status:
++ error = 0;
++ dlm_set_recover_status(ls, DLM_RS_DIR);
++ log_debug(ls, "dlm_recover_directory %d entries", count);
++ out_free:
++ kfree(last_name);
++ out:
++ dlm_clear_free_entries(ls);
++ return error;
++}
++
++static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
++ int namelen, int *r_nodeid)
++{
++ struct dlm_direntry *de, *tmp;
++ uint32_t bucket;
++
++ bucket = dir_hash(ls, name, namelen);
++
++ write_lock(&ls->ls_dirtbl[bucket].lock);
++ de = search_bucket(ls, name, namelen, bucket);
++ if (de) {
++ *r_nodeid = de->master_nodeid;
++ write_unlock(&ls->ls_dirtbl[bucket].lock);
++ if (*r_nodeid == nodeid)
++ return -EEXIST;
++ return 0;
++ }
++
++ write_unlock(&ls->ls_dirtbl[bucket].lock);
++
++ de = allocate_direntry(ls, namelen);
++ if (!de)
++ return -ENOMEM;
++
++ de->master_nodeid = nodeid;
++ de->length = namelen;
++ memcpy(de->name, name, namelen);
++
++ write_lock(&ls->ls_dirtbl[bucket].lock);
++ tmp = search_bucket(ls, name, namelen, bucket);
++ if (tmp) {
++ free_direntry(de);
++ de = tmp;
++ } else {
++ list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
++ }
++ *r_nodeid = de->master_nodeid;
++ write_unlock(&ls->ls_dirtbl[bucket].lock);
++ return 0;
++}
++
++int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
++ int *r_nodeid)
++{
++ return get_entry(ls, nodeid, name, namelen, r_nodeid);
++}
++
++/* Copy the names of master rsb's into the buffer provided.
++ Only select names whose dir node is the given nodeid. */
++
++void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
++ char *outbuf, int outlen, int nodeid)
++{
++ struct list_head *list;
++ struct dlm_rsb *start_r = NULL, *r = NULL;
++ int offset = 0, start_namelen, error, dir_nodeid;
++ char *start_name;
++ uint16_t be_namelen;
++
++ /*
++ * Find the rsb where we left off (or start again)
++ */
++
++ start_namelen = inlen;
++ start_name = inbuf;
++
++ if (start_namelen > 1) {
++ /*
++ * We could also use a find_rsb_root() function here that
++ * searched the ls_root_list.
++ */
++ error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER,
++ &start_r);
++ DLM_ASSERT(!error && start_r,
++ printk("error %d\n", error););
++ DLM_ASSERT(!list_empty(&start_r->res_root_list),
++ dlm_print_rsb(start_r););
++ dlm_put_rsb(start_r);
++ }
++
++ /*
++ * Send rsb names for rsb's we're master of and whose directory node
++ * matches the requesting node.
++ */
++
++ down_read(&ls->ls_root_sem);
++ if (start_r)
++ list = start_r->res_root_list.next;
++ else
++ list = ls->ls_root_list.next;
++
++ for (offset = 0; list != &ls->ls_root_list; list = list->next) {
++ r = list_entry(list, struct dlm_rsb, res_root_list);
++ if (r->res_nodeid)
++ continue;
++
++ dir_nodeid = dlm_dir_nodeid(r);
++ if (dir_nodeid != nodeid)
++ continue;
++
++ /*
++ * The block ends when we can't fit the following in the
++ * remaining buffer space:
++ * namelen (uint16_t) +
++ * name (r->res_length) +
++ * end-of-block record 0x0000 (uint16_t)
++ */
++
++ if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
++ /* Write end-of-block record */
++ be_namelen = 0;
++ memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
++ offset += sizeof(uint16_t);
++ goto out;
++ }
++
++ be_namelen = cpu_to_be16(r->res_length);
++ memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
++ offset += sizeof(uint16_t);
++ memcpy(outbuf + offset, r->res_name, r->res_length);
++ offset += r->res_length;
++ }
++
++ /*
++ * If we've reached the end of the list (and there's room) write a
++ * terminating record.
++ */
++
++ if ((list == &ls->ls_root_list) &&
++ (offset + sizeof(uint16_t) <= outlen)) {
++ be_namelen = 0xFFFF;
++ memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
++ offset += sizeof(uint16_t);
++ }
++
++ out:
++ up_read(&ls->ls_root_sem);
++}
++
+diff --git a/fs/dlm/dir.h b/fs/dlm/dir.h
+new file mode 100644
+index 0000000..0b0eb12
+--- /dev/null
++++ b/fs/dlm/dir.h
+@@ -0,0 +1,30 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __DIR_DOT_H__
++#define __DIR_DOT_H__
++
++
++int dlm_dir_nodeid(struct dlm_rsb *rsb);
++int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);
++void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);
++void dlm_dir_clear(struct dlm_ls *ls);
++void dlm_clear_free_entries(struct dlm_ls *ls);
++int dlm_recover_directory(struct dlm_ls *ls);
++int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
++ int *r_nodeid);
++void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
++ char *outbuf, int outlen, int nodeid);
++
++#endif /* __DIR_DOT_H__ */
++
+diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
+new file mode 100644
+index 0000000..1e5cd67
+--- /dev/null
++++ b/fs/dlm/dlm_internal.h
+@@ -0,0 +1,543 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __DLM_INTERNAL_DOT_H__
++#define __DLM_INTERNAL_DOT_H__
++
++/*
++ * This is the main header file to be included in each DLM source file.
++ */
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/ctype.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++#include <linux/list.h>
++#include <linux/errno.h>
++#include <linux/random.h>
++#include <linux/delay.h>
++#include <linux/socket.h>
++#include <linux/kthread.h>
++#include <linux/kobject.h>
++#include <linux/kref.h>
++#include <linux/kernel.h>
++#include <linux/jhash.h>
++#include <linux/miscdevice.h>
++#include <linux/mutex.h>
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++
++#include <linux/dlm.h>
++
++#define DLM_LOCKSPACE_LEN 64
++
++/* Size of the temp buffer midcomms allocates on the stack.
++ We try to make this large enough so most messages fit.
++ FIXME: should sctp make this unnecessary? */
++
++#define DLM_INBUF_LEN 148
++
++struct dlm_ls;
++struct dlm_lkb;
++struct dlm_rsb;
++struct dlm_member;
++struct dlm_lkbtable;
++struct dlm_rsbtable;
++struct dlm_dirtable;
++struct dlm_direntry;
++struct dlm_recover;
++struct dlm_header;
++struct dlm_message;
++struct dlm_rcom;
++struct dlm_mhandle;
++
++#define log_print(fmt, args...) \
++ printk(KERN_ERR "dlm: "fmt"\n" , ##args)
++#define log_error(ls, fmt, args...) \
++ printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args)
++
++#define DLM_LOG_DEBUG
++#ifdef DLM_LOG_DEBUG
++#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args)
++#else
++#define log_debug(ls, fmt, args...)
++#endif
++
++#define DLM_ASSERT(x, do) \
++{ \
++ if (!(x)) \
++ { \
++ printk(KERN_ERR "\nDLM: Assertion failed on line %d of file %s\n" \
++ "DLM: assertion: \"%s\"\n" \
++ "DLM: time = %lu\n", \
++ __LINE__, __FILE__, #x, jiffies); \
++ {do} \
++ printk("\n"); \
++ BUG(); \
++ panic("DLM: Record message above and reboot.\n"); \
++ } \
++}
++
++#define DLM_FAKE_USER_AST ERR_PTR(-EINVAL)
++
++
++struct dlm_direntry {
++ struct list_head list;
++ uint32_t master_nodeid;
++ uint16_t length;
++ char name[1];
++};
++
++struct dlm_dirtable {
++ struct list_head list;
++ rwlock_t lock;
++};
++
++struct dlm_rsbtable {
++ struct list_head list;
++ struct list_head toss;
++ rwlock_t lock;
++};
++
++struct dlm_lkbtable {
++ struct list_head list;
++ rwlock_t lock;
++ uint16_t counter;
++};
++
++/*
++ * Lockspace member (per node in a ls)
++ */
++
++struct dlm_member {
++ struct list_head list;
++ int nodeid;
++ int weight;
++};
++
++/*
++ * Save and manage recovery state for a lockspace.
++ */
++
++struct dlm_recover {
++ struct list_head list;
++ int *nodeids;
++ int node_count;
++ uint64_t seq;
++};
++
++/*
++ * Pass input args to second stage locking function.
++ */
++
++struct dlm_args {
++ uint32_t flags;
++ void *astaddr;
++ long astparam;
++ void *bastaddr;
++ int mode;
++ struct dlm_lksb *lksb;
++};
++
++
++/*
++ * Lock block
++ *
++ * A lock can be one of three types:
++ *
++ * local copy lock is mastered locally
++ * (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set)
++ * process copy lock is mastered on a remote node
++ * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set)
++ * master copy master node's copy of a lock owned by remote node
++ * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set)
++ *
++ * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or
++ * dlm_unlock. The dlm does not modify these or use any private flags in
++ * this field; it only contains DLM_LKF_ flags from dlm.h. These flags
++ * are sent as-is to the remote master when the lock is remote.
++ *
++ * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h.
++ * Some internal flags are shared between the master and process nodes;
++ * these shared flags are kept in the lower two bytes. One of these
++ * flags set on the master copy will be propagated to the process copy
++ * and v.v. Other internal flags are private to the master or process
++ * node (e.g. DLM_IFL_MSTCPY). These are kept in the high two bytes.
++ *
++ * lkb_sbflags: status block flags. These flags are copied directly into
++ * the caller's lksb.sb_flags prior to the dlm_lock/dlm_unlock completion
++ * ast. All defined in dlm.h with DLM_SBF_ prefix.
++ *
++ * lkb_status: the lock status indicates which rsb queue the lock is
++ * on, grant, convert, or wait. DLM_LKSTS_ WAITING/GRANTED/CONVERT
++ *
++ * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a
++ * reply is needed. Only set when the lkb is on the lockspace waiters
++ * list awaiting a reply from a remote node.
++ *
++ * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb
++ * is a master copy, nodeid specifies the remote lock holder, when the
++ * lkb is a process copy, the nodeid specifies the lock master.
++ */
++
++/* lkb_ast_type */
++
++#define AST_COMP 1
++#define AST_BAST 2
++
++/* lkb_status */
++
++#define DLM_LKSTS_WAITING 1
++#define DLM_LKSTS_GRANTED 2
++#define DLM_LKSTS_CONVERT 3
++
++/* lkb_flags */
++
++#define DLM_IFL_MSTCPY 0x00010000
++#define DLM_IFL_RESEND 0x00020000
++#define DLM_IFL_DEAD 0x00040000
++#define DLM_IFL_USER 0x00000001
++#define DLM_IFL_ORPHAN 0x00000002
++
++struct dlm_lkb {
++ struct dlm_rsb *lkb_resource; /* the rsb */
++ struct kref lkb_ref;
++ int lkb_nodeid; /* copied from rsb */
++ int lkb_ownpid; /* pid of lock owner */
++ uint32_t lkb_id; /* our lock ID */
++ uint32_t lkb_remid; /* lock ID on remote partner */
++ uint32_t lkb_exflags; /* external flags from caller */
++ uint32_t lkb_sbflags; /* lksb flags */
++ uint32_t lkb_flags; /* internal flags */
++ uint32_t lkb_lvbseq; /* lvb sequence number */
++
++ int8_t lkb_status; /* granted, waiting, convert */
++ int8_t lkb_rqmode; /* requested lock mode */
++ int8_t lkb_grmode; /* granted lock mode */
++ int8_t lkb_bastmode; /* requested mode */
++ int8_t lkb_highbast; /* highest mode bast sent for */
++
++ int8_t lkb_wait_type; /* type of reply waiting for */
++ int8_t lkb_ast_type; /* type of ast queued for */
++
++ struct list_head lkb_idtbl_list; /* lockspace lkbtbl */
++ struct list_head lkb_statequeue; /* rsb g/c/w list */
++ struct list_head lkb_rsb_lookup; /* waiting for rsb lookup */
++ struct list_head lkb_wait_reply; /* waiting for remote reply */
++ struct list_head lkb_astqueue; /* need ast to be sent */
++ struct list_head lkb_ownqueue; /* list of locks for a process */
++
++ char *lkb_lvbptr;
++ struct dlm_lksb *lkb_lksb; /* caller's status block */
++ void *lkb_astaddr; /* caller's ast function */
++ void *lkb_bastaddr; /* caller's bast function */
++ long lkb_astparam; /* caller's ast arg */
++};
++
++
++struct dlm_rsb {
++ struct dlm_ls *res_ls; /* the lockspace */
++ struct kref res_ref;
++ struct mutex res_mutex;
++ unsigned long res_flags;
++ int res_length; /* length of rsb name */
++ int res_nodeid;
++ uint32_t res_lvbseq;
++ uint32_t res_hash;
++ uint32_t res_bucket; /* rsbtbl */
++ unsigned long res_toss_time;
++ uint32_t res_first_lkid;
++ struct list_head res_lookup; /* lkbs waiting on first */
++ struct list_head res_hashchain; /* rsbtbl */
++ struct list_head res_grantqueue;
++ struct list_head res_convertqueue;
++ struct list_head res_waitqueue;
++
++ struct list_head res_root_list; /* used for recovery */
++ struct list_head res_recover_list; /* used for recovery */
++ int res_recover_locks_count;
++
++ char *res_lvbptr;
++ char res_name[1];
++};
++
++/* find_rsb() flags */
++
++#define R_MASTER 1 /* only return rsb if it's a master */
++#define R_CREATE 2 /* create/add rsb if not found */
++
++/* rsb_flags */
++
++enum rsb_flags {
++ RSB_MASTER_UNCERTAIN,
++ RSB_VALNOTVALID,
++ RSB_VALNOTVALID_PREV,
++ RSB_NEW_MASTER,
++ RSB_NEW_MASTER2,
++ RSB_RECOVER_CONVERT,
++ RSB_LOCKS_PURGED,
++};
++
++static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
++{
++ __set_bit(flag, &r->res_flags);
++}
++
++static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag)
++{
++ __clear_bit(flag, &r->res_flags);
++}
++
++static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
++{
++ return test_bit(flag, &r->res_flags);
++}
++
++
++/* dlm_header is first element of all structs sent between nodes */
++
++#define DLM_HEADER_MAJOR 0x00020000
++#define DLM_HEADER_MINOR 0x00000001
++
++#define DLM_MSG 1
++#define DLM_RCOM 2
++
++struct dlm_header {
++ uint32_t h_version;
++ uint32_t h_lockspace;
++ uint32_t h_nodeid; /* nodeid of sender */
++ uint16_t h_length;
++ uint8_t h_cmd; /* DLM_MSG, DLM_RCOM */
++ uint8_t h_pad;
++};
++
++
++#define DLM_MSG_REQUEST 1
++#define DLM_MSG_CONVERT 2
++#define DLM_MSG_UNLOCK 3
++#define DLM_MSG_CANCEL 4
++#define DLM_MSG_REQUEST_REPLY 5
++#define DLM_MSG_CONVERT_REPLY 6
++#define DLM_MSG_UNLOCK_REPLY 7
++#define DLM_MSG_CANCEL_REPLY 8
++#define DLM_MSG_GRANT 9
++#define DLM_MSG_BAST 10
++#define DLM_MSG_LOOKUP 11
++#define DLM_MSG_REMOVE 12
++#define DLM_MSG_LOOKUP_REPLY 13
++
++struct dlm_message {
++ struct dlm_header m_header;
++ uint32_t m_type; /* DLM_MSG_ */
++ uint32_t m_nodeid;
++ uint32_t m_pid;
++ uint32_t m_lkid; /* lkid on sender */
++ uint32_t m_remid; /* lkid on receiver */
++ uint32_t m_parent_lkid;
++ uint32_t m_parent_remid;
++ uint32_t m_exflags;
++ uint32_t m_sbflags;
++ uint32_t m_flags;
++ uint32_t m_lvbseq;
++ uint32_t m_hash;
++ int m_status;
++ int m_grmode;
++ int m_rqmode;
++ int m_bastmode;
++ int m_asts;
++ int m_result; /* 0 or -EXXX */
++ char m_extra[0]; /* name or lvb */
++};
++
++
++#define DLM_RS_NODES 0x00000001
++#define DLM_RS_NODES_ALL 0x00000002
++#define DLM_RS_DIR 0x00000004
++#define DLM_RS_DIR_ALL 0x00000008
++#define DLM_RS_LOCKS 0x00000010
++#define DLM_RS_LOCKS_ALL 0x00000020
++#define DLM_RS_DONE 0x00000040
++#define DLM_RS_DONE_ALL 0x00000080
++
++#define DLM_RCOM_STATUS 1
++#define DLM_RCOM_NAMES 2
++#define DLM_RCOM_LOOKUP 3
++#define DLM_RCOM_LOCK 4
++#define DLM_RCOM_STATUS_REPLY 5
++#define DLM_RCOM_NAMES_REPLY 6
++#define DLM_RCOM_LOOKUP_REPLY 7
++#define DLM_RCOM_LOCK_REPLY 8
++
++struct dlm_rcom {
++ struct dlm_header rc_header;
++ uint32_t rc_type; /* DLM_RCOM_ */
++ int rc_result; /* multi-purpose */
++ uint64_t rc_id; /* match reply with request */
++ char rc_buf[0];
++};
++
++struct rcom_config {
++ uint32_t rf_lvblen;
++ uint32_t rf_lsflags;
++ uint64_t rf_unused;
++};
++
++struct rcom_lock {
++ uint32_t rl_ownpid;
++ uint32_t rl_lkid;
++ uint32_t rl_remid;
++ uint32_t rl_parent_lkid;
++ uint32_t rl_parent_remid;
++ uint32_t rl_exflags;
++ uint32_t rl_flags;
++ uint32_t rl_lvbseq;
++ int rl_result;
++ int8_t rl_rqmode;
++ int8_t rl_grmode;
++ int8_t rl_status;
++ int8_t rl_asts;
++ uint16_t rl_wait_type;
++ uint16_t rl_namelen;
++ char rl_name[DLM_RESNAME_MAXLEN];
++ char rl_lvb[0];
++};
++
++struct dlm_ls {
++ struct list_head ls_list; /* list of lockspaces */
++ dlm_lockspace_t *ls_local_handle;
++ uint32_t ls_global_id; /* global unique lockspace ID */
++ uint32_t ls_exflags;
++ int ls_lvblen;
++ int ls_count; /* reference count */
++ unsigned long ls_flags; /* LSFL_ */
++ struct kobject ls_kobj;
++
++ struct dlm_rsbtable *ls_rsbtbl;
++ uint32_t ls_rsbtbl_size;
++
++ struct dlm_lkbtable *ls_lkbtbl;
++ uint32_t ls_lkbtbl_size;
++
++ struct dlm_dirtable *ls_dirtbl;
++ uint32_t ls_dirtbl_size;
++
++ struct mutex ls_waiters_mutex;
++ struct list_head ls_waiters; /* lkbs needing a reply */
++
++ struct list_head ls_nodes; /* current nodes in ls */
++ struct list_head ls_nodes_gone; /* dead node list, recovery */
++ int ls_num_nodes; /* number of nodes in ls */
++ int ls_low_nodeid;
++ int ls_total_weight;
++ int *ls_node_array;
++
++ struct dlm_rsb ls_stub_rsb; /* for returning errors */
++ struct dlm_lkb ls_stub_lkb; /* for returning errors */
++ struct dlm_message ls_stub_ms; /* for faking a reply */
++
++ struct dentry *ls_debug_rsb_dentry; /* debugfs */
++ struct dentry *ls_debug_waiters_dentry; /* debugfs */
++
++ wait_queue_head_t ls_uevent_wait; /* user part of join/leave */
++ int ls_uevent_result;
++
++ struct miscdevice ls_device;
++
++ /* recovery related */
++
++ struct timer_list ls_timer;
++ struct task_struct *ls_recoverd_task;
++ struct mutex ls_recoverd_active;
++ spinlock_t ls_recover_lock;
++ uint32_t ls_recover_status; /* DLM_RS_ */
++ uint64_t ls_recover_seq;
++ struct dlm_recover *ls_recover_args;
++ struct rw_semaphore ls_in_recovery; /* block local requests */
++ struct list_head ls_requestqueue;/* queue remote requests */
++ struct mutex ls_requestqueue_mutex;
++ char *ls_recover_buf;
++ int ls_recover_nodeid; /* for debugging */
++ uint64_t ls_rcom_seq;
++ struct list_head ls_recover_list;
++ spinlock_t ls_recover_list_lock;
++ int ls_recover_list_count;
++ wait_queue_head_t ls_wait_general;
++ struct mutex ls_clear_proc_locks;
++
++ struct list_head ls_root_list; /* root resources */
++ struct rw_semaphore ls_root_sem; /* protect root_list */
++
++ int ls_namelen;
++ char ls_name[1];
++};
++
++#define LSFL_WORK 0
++#define LSFL_RUNNING 1
++#define LSFL_RECOVERY_STOP 2
++#define LSFL_RCOM_READY 3
++#define LSFL_UEVENT_WAIT 4
++
++/* much of this is just saving user space pointers associated with the
++ lock that we pass back to the user lib with an ast */
++
++struct dlm_user_args {
++ struct dlm_user_proc *proc; /* each process that opens the lockspace
++ device has private data
++ (dlm_user_proc) on the struct file,
++ the process's locks point back to it*/
++ struct dlm_lksb lksb;
++ int old_mode;
++ int update_user_lvb;
++ struct dlm_lksb __user *user_lksb;
++ void __user *castparam;
++ void __user *castaddr;
++ void __user *bastparam;
++ void __user *bastaddr;
++};
++
++#define DLM_PROC_FLAGS_CLOSING 1
++#define DLM_PROC_FLAGS_COMPAT 2
++
++/* locks list is kept so we can remove all a process's locks when it
++ exits (or orphan those that are persistent) */
++
++struct dlm_user_proc {
++ dlm_lockspace_t *lockspace;
++ unsigned long flags; /* DLM_PROC_FLAGS */
++ struct list_head asts;
++ spinlock_t asts_spin;
++ struct list_head locks;
++ spinlock_t locks_spin;
++ wait_queue_head_t wait;
++};
++
++static inline int dlm_locking_stopped(struct dlm_ls *ls)
++{
++ return !test_bit(LSFL_RUNNING, &ls->ls_flags);
++}
++
++static inline int dlm_recovery_stopped(struct dlm_ls *ls)
++{
++ return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
++}
++
++static inline int dlm_no_directory(struct dlm_ls *ls)
++{
++ return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0;
++}
++
++#endif /* __DLM_INTERNAL_DOT_H__ */
++
+diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
+new file mode 100644
+index 0000000..3f2befa
+--- /dev/null
++++ b/fs/dlm/lock.c
+@@ -0,0 +1,3871 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++/* Central locking logic has four stages:
++
++ dlm_lock()
++ dlm_unlock()
++
++ request_lock(ls, lkb)
++ convert_lock(ls, lkb)
++ unlock_lock(ls, lkb)
++ cancel_lock(ls, lkb)
++
++ _request_lock(r, lkb)
++ _convert_lock(r, lkb)
++ _unlock_lock(r, lkb)
++ _cancel_lock(r, lkb)
++
++ do_request(r, lkb)
++ do_convert(r, lkb)
++ do_unlock(r, lkb)
++ do_cancel(r, lkb)
++
++ Stage 1 (lock, unlock) is mainly about checking input args and
++ splitting into one of the four main operations:
++
++ dlm_lock = request_lock
++ dlm_lock+CONVERT = convert_lock
++ dlm_unlock = unlock_lock
++ dlm_unlock+CANCEL = cancel_lock
++
++ Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is
++ provided to the next stage.
++
++ Stage 3, _xxxx_lock(), determines if the operation is local or remote.
++ When remote, it calls send_xxxx(), when local it calls do_xxxx().
++
++ Stage 4, do_xxxx(), is the guts of the operation. It manipulates the
++ given rsb and lkb and queues callbacks.
++
++ For remote operations, send_xxxx() results in the corresponding do_xxxx()
++ function being executed on the remote node. The connecting send/receive
++ calls on local (L) and remote (R) nodes:
++
++ L: send_xxxx() -> R: receive_xxxx()
++ R: do_xxxx()
++ L: receive_xxxx_reply() <- R: send_xxxx_reply()
++*/
++#include <linux/types.h>
++#include "dlm_internal.h"
++#include <linux/dlm_device.h>
++#include "memory.h"
++#include "lowcomms.h"
++#include "requestqueue.h"
++#include "util.h"
++#include "dir.h"
++#include "member.h"
++#include "lockspace.h"
++#include "ast.h"
++#include "lock.h"
++#include "rcom.h"
++#include "recover.h"
++#include "lvb_table.h"
++#include "user.h"
++#include "config.h"
++
++static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);
++static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static int send_remove(struct dlm_rsb *r);
++static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
++static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ struct dlm_message *ms);
++static int receive_extralen(struct dlm_message *ms);
++
++/*
++ * Lock compatibilty matrix - thanks Steve
++ * UN = Unlocked state. Not really a state, used as a flag
++ * PD = Padding. Used to make the matrix a nice power of two in size
++ * Other states are the same as the VMS DLM.
++ * Usage: matrix[grmode+1][rqmode+1] (although m[rq+1][gr+1] is the same)
++ */
++
++static const int __dlm_compat_matrix[8][8] = {
++ /* UN NL CR CW PR PW EX PD */
++ {1, 1, 1, 1, 1, 1, 1, 0}, /* UN */
++ {1, 1, 1, 1, 1, 1, 1, 0}, /* NL */
++ {1, 1, 1, 1, 1, 1, 0, 0}, /* CR */
++ {1, 1, 1, 1, 0, 0, 0, 0}, /* CW */
++ {1, 1, 1, 0, 1, 0, 0, 0}, /* PR */
++ {1, 1, 1, 0, 0, 0, 0, 0}, /* PW */
++ {1, 1, 0, 0, 0, 0, 0, 0}, /* EX */
++ {0, 0, 0, 0, 0, 0, 0, 0} /* PD */
++};
++
++/*
++ * This defines the direction of transfer of LVB data.
++ * Granted mode is the row; requested mode is the column.
++ * Usage: matrix[grmode+1][rqmode+1]
++ * 1 = LVB is returned to the caller
++ * 0 = LVB is written to the resource
++ * -1 = nothing happens to the LVB
++ */
++
++const int dlm_lvb_operations[8][8] = {
++ /* UN NL CR CW PR PW EX PD*/
++ { -1, 1, 1, 1, 1, 1, 1, -1 }, /* UN */
++ { -1, 1, 1, 1, 1, 1, 1, 0 }, /* NL */
++ { -1, -1, 1, 1, 1, 1, 1, 0 }, /* CR */
++ { -1, -1, -1, 1, 1, 1, 1, 0 }, /* CW */
++ { -1, -1, -1, -1, 1, 1, 1, 0 }, /* PR */
++ { -1, 0, 0, 0, 0, 0, 1, 0 }, /* PW */
++ { -1, 0, 0, 0, 0, 0, 0, 0 }, /* EX */
++ { -1, 0, 0, 0, 0, 0, 0, 0 } /* PD */
++};
++
++#define modes_compat(gr, rq) \
++ __dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]
++
++int dlm_modes_compat(int mode1, int mode2)
++{
++ return __dlm_compat_matrix[mode1 + 1][mode2 + 1];
++}
++
++/*
++ * Compatibility matrix for conversions with QUECVT set.
++ * Granted mode is the row; requested mode is the column.
++ * Usage: matrix[grmode+1][rqmode+1]
++ */
++
++static const int __quecvt_compat_matrix[8][8] = {
++ /* UN NL CR CW PR PW EX PD */
++ {0, 0, 0, 0, 0, 0, 0, 0}, /* UN */
++ {0, 0, 1, 1, 1, 1, 1, 0}, /* NL */
++ {0, 0, 0, 1, 1, 1, 1, 0}, /* CR */
++ {0, 0, 0, 0, 1, 1, 1, 0}, /* CW */
++ {0, 0, 0, 1, 0, 1, 1, 0}, /* PR */
++ {0, 0, 0, 0, 0, 0, 1, 0}, /* PW */
++ {0, 0, 0, 0, 0, 0, 0, 0}, /* EX */
++ {0, 0, 0, 0, 0, 0, 0, 0} /* PD */
++};
++
++void dlm_print_lkb(struct dlm_lkb *lkb)
++{
++ printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
++ " status %d rqmode %d grmode %d wait_type %d ast_type %d\n",
++ lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
++ lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
++ lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
++}
++
++void dlm_print_rsb(struct dlm_rsb *r)
++{
++ printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
++ r->res_nodeid, r->res_flags, r->res_first_lkid,
++ r->res_recover_locks_count, r->res_name);
++}
++
++void dlm_dump_rsb(struct dlm_rsb *r)
++{
++ struct dlm_lkb *lkb;
++
++ dlm_print_rsb(r);
++
++ printk(KERN_ERR "rsb: root_list empty %d recover_list empty %d\n",
++ list_empty(&r->res_root_list), list_empty(&r->res_recover_list));
++ printk(KERN_ERR "rsb lookup list\n");
++ list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup)
++ dlm_print_lkb(lkb);
++ printk(KERN_ERR "rsb grant queue:\n");
++ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue)
++ dlm_print_lkb(lkb);
++ printk(KERN_ERR "rsb convert queue:\n");
++ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue)
++ dlm_print_lkb(lkb);
++ printk(KERN_ERR "rsb wait queue:\n");
++ list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue)
++ dlm_print_lkb(lkb);
++}
++
++/* Threads cannot use the lockspace while it's being recovered */
++
++static inline void lock_recovery(struct dlm_ls *ls)
++{
++ down_read(&ls->ls_in_recovery);
++}
++
++static inline void unlock_recovery(struct dlm_ls *ls)
++{
++ up_read(&ls->ls_in_recovery);
++}
++
++static inline int lock_recovery_try(struct dlm_ls *ls)
++{
++ return down_read_trylock(&ls->ls_in_recovery);
++}
++
++static inline int can_be_queued(struct dlm_lkb *lkb)
++{
++ return !(lkb->lkb_exflags & DLM_LKF_NOQUEUE);
++}
++
++static inline int force_blocking_asts(struct dlm_lkb *lkb)
++{
++ return (lkb->lkb_exflags & DLM_LKF_NOQUEUEBAST);
++}
++
++static inline int is_demoted(struct dlm_lkb *lkb)
++{
++ return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
++}
++
++static inline int is_remote(struct dlm_rsb *r)
++{
++ DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
++ return !!r->res_nodeid;
++}
++
++static inline int is_process_copy(struct dlm_lkb *lkb)
++{
++ return (lkb->lkb_nodeid && !(lkb->lkb_flags & DLM_IFL_MSTCPY));
++}
++
++static inline int is_master_copy(struct dlm_lkb *lkb)
++{
++ if (lkb->lkb_flags & DLM_IFL_MSTCPY)
++ DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););
++ return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0;
++}
++
++static inline int middle_conversion(struct dlm_lkb *lkb)
++{
++ if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) ||
++ (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW))
++ return 1;
++ return 0;
++}
++
++static inline int down_conversion(struct dlm_lkb *lkb)
++{
++ return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
++}
++
++static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
++{
++ if (is_master_copy(lkb))
++ return;
++
++ DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
++
++ lkb->lkb_lksb->sb_status = rv;
++ lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
++
++ dlm_add_ast(lkb, AST_COMP);
++}
++
++static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
++{
++ if (is_master_copy(lkb))
++ send_bast(r, lkb, rqmode);
++ else {
++ lkb->lkb_bastmode = rqmode;
++ dlm_add_ast(lkb, AST_BAST);
++ }
++}
++
++/*
++ * Basic operations on rsb's and lkb's
++ */
++
++static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len)
++{
++ struct dlm_rsb *r;
++
++ r = allocate_rsb(ls, len);
++ if (!r)
++ return NULL;
++
++ r->res_ls = ls;
++ r->res_length = len;
++ memcpy(r->res_name, name, len);
++ mutex_init(&r->res_mutex);
++
++ INIT_LIST_HEAD(&r->res_lookup);
++ INIT_LIST_HEAD(&r->res_grantqueue);
++ INIT_LIST_HEAD(&r->res_convertqueue);
++ INIT_LIST_HEAD(&r->res_waitqueue);
++ INIT_LIST_HEAD(&r->res_root_list);
++ INIT_LIST_HEAD(&r->res_recover_list);
++
++ return r;
++}
++
++static int search_rsb_list(struct list_head *head, char *name, int len,
++ unsigned int flags, struct dlm_rsb **r_ret)
++{
++ struct dlm_rsb *r;
++ int error = 0;
++
++ list_for_each_entry(r, head, res_hashchain) {
++ if (len == r->res_length && !memcmp(name, r->res_name, len))
++ goto found;
++ }
++ return -EBADR;
++
++ found:
++ if (r->res_nodeid && (flags & R_MASTER))
++ error = -ENOTBLK;
++ *r_ret = r;
++ return error;
++}
++
++static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
++ unsigned int flags, struct dlm_rsb **r_ret)
++{
++ struct dlm_rsb *r;
++ int error;
++
++ error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r);
++ if (!error) {
++ kref_get(&r->res_ref);
++ goto out;
++ }
++ error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
++ if (error)
++ goto out;
++
++ list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list);
++
++ if (dlm_no_directory(ls))
++ goto out;
++
++ if (r->res_nodeid == -1) {
++ rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
++ r->res_first_lkid = 0;
++ } else if (r->res_nodeid > 0) {
++ rsb_set_flag(r, RSB_MASTER_UNCERTAIN);
++ r->res_first_lkid = 0;
++ } else {
++ DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r););
++ DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),);
++ }
++ out:
++ *r_ret = r;
++ return error;
++}
++
++static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
++ unsigned int flags, struct dlm_rsb **r_ret)
++{
++ int error;
++ write_lock(&ls->ls_rsbtbl[b].lock);
++ error = _search_rsb(ls, name, len, b, flags, r_ret);
++ write_unlock(&ls->ls_rsbtbl[b].lock);
++ return error;
++}
++
++/*
++ * Find rsb in rsbtbl and potentially create/add one
++ *
++ * Delaying the release of rsb's has a similar benefit to applications keeping
++ * NL locks on an rsb, but without the guarantee that the cached master value
++ * will still be valid when the rsb is reused. Apps aren't always smart enough
++ * to keep NL locks on an rsb that they may lock again shortly; this can lead
++ * to excessive master lookups and removals if we don't delay the release.
++ *
++ * Searching for an rsb means looking through both the normal list and toss
++ * list. When found on the toss list the rsb is moved to the normal list with
++ * ref count of 1; when found on normal list the ref count is incremented.
++ */
++
++static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
++ unsigned int flags, struct dlm_rsb **r_ret)
++{
++ struct dlm_rsb *r, *tmp;
++ uint32_t hash, bucket;
++ int error = 0;
++
++ if (dlm_no_directory(ls))
++ flags |= R_CREATE;
++
++ hash = jhash(name, namelen, 0);
++ bucket = hash & (ls->ls_rsbtbl_size - 1);
++
++ error = search_rsb(ls, name, namelen, bucket, flags, &r);
++ if (!error)
++ goto out;
++
++ if (error == -EBADR && !(flags & R_CREATE))
++ goto out;
++
++ /* the rsb was found but wasn't a master copy */
++ if (error == -ENOTBLK)
++ goto out;
++
++ error = -ENOMEM;
++ r = create_rsb(ls, name, namelen);
++ if (!r)
++ goto out;
++
++ r->res_hash = hash;
++ r->res_bucket = bucket;
++ r->res_nodeid = -1;
++ kref_init(&r->res_ref);
++
++ /* With no directory, the master can be set immediately */
++ if (dlm_no_directory(ls)) {
++ int nodeid = dlm_dir_nodeid(r);
++ if (nodeid == dlm_our_nodeid())
++ nodeid = 0;
++ r->res_nodeid = nodeid;
++ }
++
++ write_lock(&ls->ls_rsbtbl[bucket].lock);
++ error = _search_rsb(ls, name, namelen, bucket, 0, &tmp);
++ if (!error) {
++ write_unlock(&ls->ls_rsbtbl[bucket].lock);
++ free_rsb(r);
++ r = tmp;
++ goto out;
++ }
++ list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
++ write_unlock(&ls->ls_rsbtbl[bucket].lock);
++ error = 0;
++ out:
++ *r_ret = r;
++ return error;
++}
++
++int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
++ unsigned int flags, struct dlm_rsb **r_ret)
++{
++ return find_rsb(ls, name, namelen, flags, r_ret);
++}
++
++/* This is only called to add a reference when the code already holds
++ a valid reference to the rsb, so there's no need for locking. */
++
++static inline void hold_rsb(struct dlm_rsb *r)
++{
++ kref_get(&r->res_ref);
++}
++
++void dlm_hold_rsb(struct dlm_rsb *r)
++{
++ hold_rsb(r);
++}
++
++static void toss_rsb(struct kref *kref)
++{
++ struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
++ struct dlm_ls *ls = r->res_ls;
++
++ DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
++ kref_init(&r->res_ref);
++ list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss);
++ r->res_toss_time = jiffies;
++ if (r->res_lvbptr) {
++ free_lvb(r->res_lvbptr);
++ r->res_lvbptr = NULL;
++ }
++}
++
++/* When all references to the rsb are gone it's transfered to
++ the tossed list for later disposal. */
++
++static void put_rsb(struct dlm_rsb *r)
++{
++ struct dlm_ls *ls = r->res_ls;
++ uint32_t bucket = r->res_bucket;
++
++ write_lock(&ls->ls_rsbtbl[bucket].lock);
++ kref_put(&r->res_ref, toss_rsb);
++ write_unlock(&ls->ls_rsbtbl[bucket].lock);
++}
++
++void dlm_put_rsb(struct dlm_rsb *r)
++{
++ put_rsb(r);
++}
++
++/* See comment for unhold_lkb */
++
++static void unhold_rsb(struct dlm_rsb *r)
++{
++ int rv;
++ rv = kref_put(&r->res_ref, toss_rsb);
++ DLM_ASSERT(!rv, dlm_dump_rsb(r););
++}
++
++static void kill_rsb(struct kref *kref)
++{
++ struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
++
++ /* All work is done after the return from kref_put() so we
++ can release the write_lock before the remove and free. */
++
++ DLM_ASSERT(list_empty(&r->res_lookup), dlm_dump_rsb(r););
++ DLM_ASSERT(list_empty(&r->res_grantqueue), dlm_dump_rsb(r););
++ DLM_ASSERT(list_empty(&r->res_convertqueue), dlm_dump_rsb(r););
++ DLM_ASSERT(list_empty(&r->res_waitqueue), dlm_dump_rsb(r););
++ DLM_ASSERT(list_empty(&r->res_root_list), dlm_dump_rsb(r););
++ DLM_ASSERT(list_empty(&r->res_recover_list), dlm_dump_rsb(r););
++}
++
++/* Attaching/detaching lkb's from rsb's is for rsb reference counting.
++ The rsb must exist as long as any lkb's for it do. */
++
++static void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ hold_rsb(r);
++ lkb->lkb_resource = r;
++}
++
++static void detach_lkb(struct dlm_lkb *lkb)
++{
++ if (lkb->lkb_resource) {
++ put_rsb(lkb->lkb_resource);
++ lkb->lkb_resource = NULL;
++ }
++}
++
++static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
++{
++ struct dlm_lkb *lkb, *tmp;
++ uint32_t lkid = 0;
++ uint16_t bucket;
++
++ lkb = allocate_lkb(ls);
++ if (!lkb)
++ return -ENOMEM;
++
++ lkb->lkb_nodeid = -1;
++ lkb->lkb_grmode = DLM_LOCK_IV;
++ kref_init(&lkb->lkb_ref);
++ INIT_LIST_HEAD(&lkb->lkb_ownqueue);
++
++ get_random_bytes(&bucket, sizeof(bucket));
++ bucket &= (ls->ls_lkbtbl_size - 1);
++
++ write_lock(&ls->ls_lkbtbl[bucket].lock);
++
++ /* counter can roll over so we must verify lkid is not in use */
++
++ while (lkid == 0) {
++ lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16);
++
++ list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list,
++ lkb_idtbl_list) {
++ if (tmp->lkb_id != lkid)
++ continue;
++ lkid = 0;
++ break;
++ }
++ }
++
++ lkb->lkb_id = lkid;
++ list_add(&lkb->lkb_idtbl_list, &ls->ls_lkbtbl[bucket].list);
++ write_unlock(&ls->ls_lkbtbl[bucket].lock);
++
++ *lkb_ret = lkb;
++ return 0;
++}
++
++static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
++{
++ uint16_t bucket = lkid & 0xFFFF;
++ struct dlm_lkb *lkb;
++
++ list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {
++ if (lkb->lkb_id == lkid)
++ return lkb;
++ }
++ return NULL;
++}
++
++static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
++{
++ struct dlm_lkb *lkb;
++ uint16_t bucket = lkid & 0xFFFF;
++
++ if (bucket >= ls->ls_lkbtbl_size)
++ return -EBADSLT;
++
++ read_lock(&ls->ls_lkbtbl[bucket].lock);
++ lkb = __find_lkb(ls, lkid);
++ if (lkb)
++ kref_get(&lkb->lkb_ref);
++ read_unlock(&ls->ls_lkbtbl[bucket].lock);
++
++ *lkb_ret = lkb;
++ return lkb ? 0 : -ENOENT;
++}
++
++static void kill_lkb(struct kref *kref)
++{
++ struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
++
++ /* All work is done after the return from kref_put() so we
++ can release the write_lock before the detach_lkb */
++
++ DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
++}
++
++/* __put_lkb() is used when an lkb may not have an rsb attached to
++ it so we need to provide the lockspace explicitly */
++
++static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ uint16_t bucket = lkb->lkb_id & 0xFFFF;
++
++ write_lock(&ls->ls_lkbtbl[bucket].lock);
++ if (kref_put(&lkb->lkb_ref, kill_lkb)) {
++ list_del(&lkb->lkb_idtbl_list);
++ write_unlock(&ls->ls_lkbtbl[bucket].lock);
++
++ detach_lkb(lkb);
++
++ /* for local/process lkbs, lvbptr points to caller's lksb */
++ if (lkb->lkb_lvbptr && is_master_copy(lkb))
++ free_lvb(lkb->lkb_lvbptr);
++ free_lkb(lkb);
++ return 1;
++ } else {
++ write_unlock(&ls->ls_lkbtbl[bucket].lock);
++ return 0;
++ }
++}
++
++int dlm_put_lkb(struct dlm_lkb *lkb)
++{
++ struct dlm_ls *ls;
++
++ DLM_ASSERT(lkb->lkb_resource, dlm_print_lkb(lkb););
++ DLM_ASSERT(lkb->lkb_resource->res_ls, dlm_print_lkb(lkb););
++
++ ls = lkb->lkb_resource->res_ls;
++ return __put_lkb(ls, lkb);
++}
++
++/* This is only called to add a reference when the code already holds
++ a valid reference to the lkb, so there's no need for locking. */
++
++static inline void hold_lkb(struct dlm_lkb *lkb)
++{
++ kref_get(&lkb->lkb_ref);
++}
++
++/* This is called when we need to remove a reference and are certain
++ it's not the last ref. e.g. del_lkb is always called between a
++ find_lkb/put_lkb and is always the inverse of a previous add_lkb.
++ put_lkb would work fine, but would involve unnecessary locking */
++
++static inline void unhold_lkb(struct dlm_lkb *lkb)
++{
++ int rv;
++ rv = kref_put(&lkb->lkb_ref, kill_lkb);
++ DLM_ASSERT(!rv, dlm_print_lkb(lkb););
++}
++
++static void lkb_add_ordered(struct list_head *new, struct list_head *head,
++ int mode)
++{
++ struct dlm_lkb *lkb = NULL;
++
++ list_for_each_entry(lkb, head, lkb_statequeue)
++ if (lkb->lkb_rqmode < mode)
++ break;
++
++ if (!lkb)
++ list_add_tail(new, head);
++ else
++ __list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue);
++}
++
++/* add/remove lkb to rsb's grant/convert/wait queue */
++
++static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
++{
++ kref_get(&lkb->lkb_ref);
++
++ DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
++
++ lkb->lkb_status = status;
++
++ switch (status) {
++ case DLM_LKSTS_WAITING:
++ if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
++ list_add(&lkb->lkb_statequeue, &r->res_waitqueue);
++ else
++ list_add_tail(&lkb->lkb_statequeue, &r->res_waitqueue);
++ break;
++ case DLM_LKSTS_GRANTED:
++ /* convention says granted locks kept in order of grmode */
++ lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue,
++ lkb->lkb_grmode);
++ break;
++ case DLM_LKSTS_CONVERT:
++ if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
++ list_add(&lkb->lkb_statequeue, &r->res_convertqueue);
++ else
++ list_add_tail(&lkb->lkb_statequeue,
++ &r->res_convertqueue);
++ break;
++ default:
++ DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status););
++ }
++}
++
++static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ lkb->lkb_status = 0;
++ list_del(&lkb->lkb_statequeue);
++ unhold_lkb(lkb);
++}
++
++static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)
++{
++ hold_lkb(lkb);
++ del_lkb(r, lkb);
++ add_lkb(r, lkb, sts);
++ unhold_lkb(lkb);
++}
++
++/* add/remove lkb from global waiters list of lkb's waiting for
++ a reply from a remote node */
++
++static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
++{
++ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
++
++ mutex_lock(&ls->ls_waiters_mutex);
++ if (lkb->lkb_wait_type) {
++ log_print("add_to_waiters error %d", lkb->lkb_wait_type);
++ goto out;
++ }
++ lkb->lkb_wait_type = mstype;
++ kref_get(&lkb->lkb_ref);
++ list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
++ out:
++ mutex_unlock(&ls->ls_waiters_mutex);
++}
++
++static int _remove_from_waiters(struct dlm_lkb *lkb)
++{
++ int error = 0;
++
++ if (!lkb->lkb_wait_type) {
++ log_print("remove_from_waiters error");
++ error = -EINVAL;
++ goto out;
++ }
++ lkb->lkb_wait_type = 0;
++ list_del(&lkb->lkb_wait_reply);
++ unhold_lkb(lkb);
++ out:
++ return error;
++}
++
++static int remove_from_waiters(struct dlm_lkb *lkb)
++{
++ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
++ int error;
++
++ mutex_lock(&ls->ls_waiters_mutex);
++ error = _remove_from_waiters(lkb);
++ mutex_unlock(&ls->ls_waiters_mutex);
++ return error;
++}
++
++static void dir_remove(struct dlm_rsb *r)
++{
++ int to_nodeid;
++
++ if (dlm_no_directory(r->res_ls))
++ return;
++
++ to_nodeid = dlm_dir_nodeid(r);
++ if (to_nodeid != dlm_our_nodeid())
++ send_remove(r);
++ else
++ dlm_dir_remove_entry(r->res_ls, to_nodeid,
++ r->res_name, r->res_length);
++}
++
++/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is
++ found since they are in order of newest to oldest? */
++
++static int shrink_bucket(struct dlm_ls *ls, int b)
++{
++ struct dlm_rsb *r;
++ int count = 0, found;
++
++ for (;;) {
++ found = 0;
++ write_lock(&ls->ls_rsbtbl[b].lock);
++ list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
++ res_hashchain) {
++ if (!time_after_eq(jiffies, r->res_toss_time +
++ dlm_config.toss_secs * HZ))
++ continue;
++ found = 1;
++ break;
++ }
++
++ if (!found) {
++ write_unlock(&ls->ls_rsbtbl[b].lock);
++ break;
++ }
++
++ if (kref_put(&r->res_ref, kill_rsb)) {
++ list_del(&r->res_hashchain);
++ write_unlock(&ls->ls_rsbtbl[b].lock);
++
++ if (is_master(r))
++ dir_remove(r);
++ free_rsb(r);
++ count++;
++ } else {
++ write_unlock(&ls->ls_rsbtbl[b].lock);
++ log_error(ls, "tossed rsb in use %s", r->res_name);
++ }
++ }
++
++ return count;
++}
++
++void dlm_scan_rsbs(struct dlm_ls *ls)
++{
++ int i;
++
++ if (dlm_locking_stopped(ls))
++ return;
++
++ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
++ shrink_bucket(ls, i);
++ cond_resched();
++ }
++}
++
++/* lkb is master or local copy */
++
++static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int b, len = r->res_ls->ls_lvblen;
++
++ /* b=1 lvb returned to caller
++ b=0 lvb written to rsb or invalidated
++ b=-1 do nothing */
++
++ b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
++
++ if (b == 1) {
++ if (!lkb->lkb_lvbptr)
++ return;
++
++ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
++ return;
++
++ if (!r->res_lvbptr)
++ return;
++
++ memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len);
++ lkb->lkb_lvbseq = r->res_lvbseq;
++
++ } else if (b == 0) {
++ if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
++ rsb_set_flag(r, RSB_VALNOTVALID);
++ return;
++ }
++
++ if (!lkb->lkb_lvbptr)
++ return;
++
++ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
++ return;
++
++ if (!r->res_lvbptr)
++ r->res_lvbptr = allocate_lvb(r->res_ls);
++
++ if (!r->res_lvbptr)
++ return;
++
++ memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len);
++ r->res_lvbseq++;
++ lkb->lkb_lvbseq = r->res_lvbseq;
++ rsb_clear_flag(r, RSB_VALNOTVALID);
++ }
++
++ if (rsb_flag(r, RSB_VALNOTVALID))
++ lkb->lkb_sbflags |= DLM_SBF_VALNOTVALID;
++}
++
++static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ if (lkb->lkb_grmode < DLM_LOCK_PW)
++ return;
++
++ if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
++ rsb_set_flag(r, RSB_VALNOTVALID);
++ return;
++ }
++
++ if (!lkb->lkb_lvbptr)
++ return;
++
++ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
++ return;
++
++ if (!r->res_lvbptr)
++ r->res_lvbptr = allocate_lvb(r->res_ls);
++
++ if (!r->res_lvbptr)
++ return;
++
++ memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
++ r->res_lvbseq++;
++ rsb_clear_flag(r, RSB_VALNOTVALID);
++}
++
++/* lkb is process copy (pc) */
++
++static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ int b;
++
++ if (!lkb->lkb_lvbptr)
++ return;
++
++ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
++ return;
++
++ b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
++ if (b == 1) {
++ int len = receive_extralen(ms);
++ memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
++ lkb->lkb_lvbseq = ms->m_lvbseq;
++ }
++}
++
++/* Manipulate lkb's on rsb's convert/granted/waiting queues
++ remove_lock -- used for unlock, removes lkb from granted
++ revert_lock -- used for cancel, moves lkb from convert to granted
++ grant_lock -- used for request and convert, adds lkb to granted or
++ moves lkb from convert or waiting to granted
++
++ Each of these is used for master or local copy lkb's. There is
++ also a _pc() variation used to make the corresponding change on
++ a process copy (pc) lkb. */
++
++static void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ del_lkb(r, lkb);
++ lkb->lkb_grmode = DLM_LOCK_IV;
++ /* this unhold undoes the original ref from create_lkb()
++ so this leads to the lkb being freed */
++ unhold_lkb(lkb);
++}
++
++static void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ set_lvb_unlock(r, lkb);
++ _remove_lock(r, lkb);
++}
++
++static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ _remove_lock(r, lkb);
++}
++
++static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ lkb->lkb_rqmode = DLM_LOCK_IV;
++
++ switch (lkb->lkb_status) {
++ case DLM_LKSTS_GRANTED:
++ break;
++ case DLM_LKSTS_CONVERT:
++ move_lkb(r, lkb, DLM_LKSTS_GRANTED);
++ break;
++ case DLM_LKSTS_WAITING:
++ del_lkb(r, lkb);
++ lkb->lkb_grmode = DLM_LOCK_IV;
++ /* this unhold undoes the original ref from create_lkb()
++ so this leads to the lkb being freed */
++ unhold_lkb(lkb);
++ break;
++ default:
++ log_print("invalid status for revert %d", lkb->lkb_status);
++ }
++}
++
++static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ revert_lock(r, lkb);
++}
++
++static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ if (lkb->lkb_grmode != lkb->lkb_rqmode) {
++ lkb->lkb_grmode = lkb->lkb_rqmode;
++ if (lkb->lkb_status)
++ move_lkb(r, lkb, DLM_LKSTS_GRANTED);
++ else
++ add_lkb(r, lkb, DLM_LKSTS_GRANTED);
++ }
++
++ lkb->lkb_rqmode = DLM_LOCK_IV;
++}
++
++static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ set_lvb_lock(r, lkb);
++ _grant_lock(r, lkb);
++ lkb->lkb_highbast = 0;
++}
++
++static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ set_lvb_lock_pc(r, lkb, ms);
++ _grant_lock(r, lkb);
++}
++
++/* called by grant_pending_locks() which means an async grant message must
++ be sent to the requesting node in addition to granting the lock if the
++ lkb belongs to a remote node. */
++
++static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ grant_lock(r, lkb);
++ if (is_master_copy(lkb))
++ send_grant(r, lkb);
++ else
++ queue_cast(r, lkb, 0);
++}
++
++static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
++{
++ struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
++ lkb_statequeue);
++ if (lkb->lkb_id == first->lkb_id)
++ return 1;
++
++ return 0;
++}
++
++/* Check if the given lkb conflicts with another lkb on the queue. */
++
++static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)
++{
++ struct dlm_lkb *this;
++
++ list_for_each_entry(this, head, lkb_statequeue) {
++ if (this == lkb)
++ continue;
++ if (!modes_compat(this, lkb))
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * "A conversion deadlock arises with a pair of lock requests in the converting
++ * queue for one resource. The granted mode of each lock blocks the requested
++ * mode of the other lock."
++ *
++ * Part 2: if the granted mode of lkb is preventing the first lkb in the
++ * convert queue from being granted, then demote lkb (set grmode to NL).
++ * This second form requires that we check for conv-deadlk even when
++ * now == 0 in _can_be_granted().
++ *
++ * Example:
++ * Granted Queue: empty
++ * Convert Queue: NL->EX (first lock)
++ * PR->EX (second lock)
++ *
++ * The first lock can't be granted because of the granted mode of the second
++ * lock and the second lock can't be granted because it's not first in the
++ * list. We demote the granted mode of the second lock (the lkb passed to this
++ * function).
++ *
++ * After the resolution, the "grant pending" function needs to go back and try
++ * to grant locks on the convert queue again since the first lock can now be
++ * granted.
++ */
++
++static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb)
++{
++ struct dlm_lkb *this, *first = NULL, *self = NULL;
++
++ list_for_each_entry(this, &rsb->res_convertqueue, lkb_statequeue) {
++ if (!first)
++ first = this;
++ if (this == lkb) {
++ self = lkb;
++ continue;
++ }
++
++ if (!modes_compat(this, lkb) && !modes_compat(lkb, this))
++ return 1;
++ }
++
++ /* if lkb is on the convert queue and is preventing the first
++ from being granted, then there's deadlock and we demote lkb.
++ multiple converting locks may need to do this before the first
++ converting lock can be granted. */
++
++ if (self && self != first) {
++ if (!modes_compat(lkb, first) &&
++ !queue_conflict(&rsb->res_grantqueue, first))
++ return 1;
++ }
++
++ return 0;
++}
++
++/*
++ * Return 1 if the lock can be granted, 0 otherwise.
++ * Also detect and resolve conversion deadlocks.
++ *
++ * lkb is the lock to be granted
++ *
++ * now is 1 if the function is being called in the context of the
++ * immediate request, it is 0 if called later, after the lock has been
++ * queued.
++ *
++ * References are from chapter 6 of "VAXcluster Principles" by Roy Davis
++ */
++
++static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
++{
++ int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);
++
++ /*
++ * 6-10: Version 5.4 introduced an option to address the phenomenon of
++ * a new request for a NL mode lock being blocked.
++ *
++ * 6-11: If the optional EXPEDITE flag is used with the new NL mode
++ * request, then it would be granted. In essence, the use of this flag
++ * tells the Lock Manager to expedite theis request by not considering
++ * what may be in the CONVERTING or WAITING queues... As of this
++ * writing, the EXPEDITE flag can be used only with new requests for NL
++ * mode locks. This flag is not valid for conversion requests.
++ *
++ * A shortcut. Earlier checks return an error if EXPEDITE is used in a
++ * conversion or used with a non-NL requested mode. We also know an
++ * EXPEDITE request is always granted immediately, so now must always
++ * be 1. The full condition to grant an expedite request: (now &&
++ * !conv && lkb->rqmode == DLM_LOCK_NL && (flags & EXPEDITE)) can
++ * therefore be shortened to just checking the flag.
++ */
++
++ if (lkb->lkb_exflags & DLM_LKF_EXPEDITE)
++ return 1;
++
++ /*
++ * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be
++ * added to the remaining conditions.
++ */
++
++ if (queue_conflict(&r->res_grantqueue, lkb))
++ goto out;
++
++ /*
++ * 6-3: By default, a conversion request is immediately granted if the
++ * requested mode is compatible with the modes of all other granted
++ * locks
++ */
++
++ if (queue_conflict(&r->res_convertqueue, lkb))
++ goto out;
++
++ /*
++ * 6-5: But the default algorithm for deciding whether to grant or
++ * queue conversion requests does not by itself guarantee that such
++ * requests are serviced on a "first come first serve" basis. This, in
++ * turn, can lead to a phenomenon known as "indefinate postponement".
++ *
++ * 6-7: This issue is dealt with by using the optional QUECVT flag with
++ * the system service employed to request a lock conversion. This flag
++ * forces certain conversion requests to be queued, even if they are
++ * compatible with the granted modes of other locks on the same
++ * resource. Thus, the use of this flag results in conversion requests
++ * being ordered on a "first come first servce" basis.
++ *
++ * DCT: This condition is all about new conversions being able to occur
++ * "in place" while the lock remains on the granted queue (assuming
++ * nothing else conflicts.) IOW if QUECVT isn't set, a conversion
++ * doesn't _have_ to go onto the convert queue where it's processed in
++ * order. The "now" variable is necessary to distinguish converts
++ * being received and processed for the first time now, because once a
++ * convert is moved to the conversion queue the condition below applies
++ * requiring fifo granting.
++ */
++
++ if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT))
++ return 1;
++
++ /*
++ * The NOORDER flag is set to avoid the standard vms rules on grant
++ * order.
++ */
++
++ if (lkb->lkb_exflags & DLM_LKF_NOORDER)
++ return 1;
++
++ /*
++ * 6-3: Once in that queue [CONVERTING], a conversion request cannot be
++ * granted until all other conversion requests ahead of it are granted
++ * and/or canceled.
++ */
++
++ if (!now && conv && first_in_list(lkb, &r->res_convertqueue))
++ return 1;
++
++ /*
++ * 6-4: By default, a new request is immediately granted only if all
++ * three of the following conditions are satisfied when the request is
++ * issued:
++ * - The queue of ungranted conversion requests for the resource is
++ * empty.
++ * - The queue of ungranted new requests for the resource is empty.
++ * - The mode of the new request is compatible with the most
++ * restrictive mode of all granted locks on the resource.
++ */
++
++ if (now && !conv && list_empty(&r->res_convertqueue) &&
++ list_empty(&r->res_waitqueue))
++ return 1;
++
++ /*
++ * 6-4: Once a lock request is in the queue of ungranted new requests,
++ * it cannot be granted until the queue of ungranted conversion
++ * requests is empty, all ungranted new requests ahead of it are
++ * granted and/or canceled, and it is compatible with the granted mode
++ * of the most restrictive lock granted on the resource.
++ */
++
++ if (!now && !conv && list_empty(&r->res_convertqueue) &&
++ first_in_list(lkb, &r->res_waitqueue))
++ return 1;
++
++ out:
++ /*
++ * The following, enabled by CONVDEADLK, departs from VMS.
++ */
++
++ if (conv && (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) &&
++ conversion_deadlock_detect(r, lkb)) {
++ lkb->lkb_grmode = DLM_LOCK_NL;
++ lkb->lkb_sbflags |= DLM_SBF_DEMOTED;
++ }
++
++ return 0;
++}
++
++/*
++ * The ALTPR and ALTCW flags aren't traditional lock manager flags, but are a
++ * simple way to provide a big optimization to applications that can use them.
++ */
++
++static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
++{
++ uint32_t flags = lkb->lkb_exflags;
++ int rv;
++ int8_t alt = 0, rqmode = lkb->lkb_rqmode;
++
++ rv = _can_be_granted(r, lkb, now);
++ if (rv)
++ goto out;
++
++ if (lkb->lkb_sbflags & DLM_SBF_DEMOTED)
++ goto out;
++
++ if (rqmode != DLM_LOCK_PR && flags & DLM_LKF_ALTPR)
++ alt = DLM_LOCK_PR;
++ else if (rqmode != DLM_LOCK_CW && flags & DLM_LKF_ALTCW)
++ alt = DLM_LOCK_CW;
++
++ if (alt) {
++ lkb->lkb_rqmode = alt;
++ rv = _can_be_granted(r, lkb, now);
++ if (rv)
++ lkb->lkb_sbflags |= DLM_SBF_ALTMODE;
++ else
++ lkb->lkb_rqmode = rqmode;
++ }
++ out:
++ return rv;
++}
++
++static int grant_pending_convert(struct dlm_rsb *r, int high)
++{
++ struct dlm_lkb *lkb, *s;
++ int hi, demoted, quit, grant_restart, demote_restart;
++
++ quit = 0;
++ restart:
++ grant_restart = 0;
++ demote_restart = 0;
++ hi = DLM_LOCK_IV;
++
++ list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) {
++ demoted = is_demoted(lkb);
++ if (can_be_granted(r, lkb, 0)) {
++ grant_lock_pending(r, lkb);
++ grant_restart = 1;
++ } else {
++ hi = max_t(int, lkb->lkb_rqmode, hi);
++ if (!demoted && is_demoted(lkb))
++ demote_restart = 1;
++ }
++ }
++
++ if (grant_restart)
++ goto restart;
++ if (demote_restart && !quit) {
++ quit = 1;
++ goto restart;
++ }
++
++ return max_t(int, high, hi);
++}
++
++static int grant_pending_wait(struct dlm_rsb *r, int high)
++{
++ struct dlm_lkb *lkb, *s;
++
++ list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
++ if (can_be_granted(r, lkb, 0))
++ grant_lock_pending(r, lkb);
++ else
++ high = max_t(int, lkb->lkb_rqmode, high);
++ }
++
++ return high;
++}
++
++static void grant_pending_locks(struct dlm_rsb *r)
++{
++ struct dlm_lkb *lkb, *s;
++ int high = DLM_LOCK_IV;
++
++ DLM_ASSERT(is_master(r), dlm_dump_rsb(r););
++
++ high = grant_pending_convert(r, high);
++ high = grant_pending_wait(r, high);
++
++ if (high == DLM_LOCK_IV)
++ return;
++
++ /*
++ * If there are locks left on the wait/convert queue then send blocking
++ * ASTs to granted locks based on the largest requested mode (high)
++ * found above. FIXME: highbast < high comparison not valid for PR/CW.
++ */
++
++ list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
++ if (lkb->lkb_bastaddr && (lkb->lkb_highbast < high) &&
++ !__dlm_compat_matrix[lkb->lkb_grmode+1][high+1]) {
++ queue_bast(r, lkb, high);
++ lkb->lkb_highbast = high;
++ }
++ }
++}
++
++static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
++ struct dlm_lkb *lkb)
++{
++ struct dlm_lkb *gr;
++
++ list_for_each_entry(gr, head, lkb_statequeue) {
++ if (gr->lkb_bastaddr &&
++ gr->lkb_highbast < lkb->lkb_rqmode &&
++ !modes_compat(gr, lkb)) {
++ queue_bast(r, gr, lkb->lkb_rqmode);
++ gr->lkb_highbast = lkb->lkb_rqmode;
++ }
++ }
++}
++
++static void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ send_bast_queue(r, &r->res_grantqueue, lkb);
++}
++
++static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ send_bast_queue(r, &r->res_grantqueue, lkb);
++ send_bast_queue(r, &r->res_convertqueue, lkb);
++}
++
++/* set_master(r, lkb) -- set the master nodeid of a resource
++
++ The purpose of this function is to set the nodeid field in the given
++ lkb using the nodeid field in the given rsb. If the rsb's nodeid is
++ known, it can just be copied to the lkb and the function will return
++ 0. If the rsb's nodeid is _not_ known, it needs to be looked up
++ before it can be copied to the lkb.
++
++ When the rsb nodeid is being looked up remotely, the initial lkb
++ causing the lookup is kept on the ls_waiters list waiting for the
++ lookup reply. Other lkb's waiting for the same rsb lookup are kept
++ on the rsb's res_lookup list until the master is verified.
++
++ Return values:
++ 0: nodeid is set in rsb/lkb and the caller should go ahead and use it
++ 1: the rsb master is not available and the lkb has been placed on
++ a wait queue
++*/
++
++static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ struct dlm_ls *ls = r->res_ls;
++ int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
++
++ if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
++ rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
++ r->res_first_lkid = lkb->lkb_id;
++ lkb->lkb_nodeid = r->res_nodeid;
++ return 0;
++ }
++
++ if (r->res_first_lkid && r->res_first_lkid != lkb->lkb_id) {
++ list_add_tail(&lkb->lkb_rsb_lookup, &r->res_lookup);
++ return 1;
++ }
++
++ if (r->res_nodeid == 0) {
++ lkb->lkb_nodeid = 0;
++ return 0;
++ }
++
++ if (r->res_nodeid > 0) {
++ lkb->lkb_nodeid = r->res_nodeid;
++ return 0;
++ }
++
++ DLM_ASSERT(r->res_nodeid == -1, dlm_dump_rsb(r););
++
++ dir_nodeid = dlm_dir_nodeid(r);
++
++ if (dir_nodeid != our_nodeid) {
++ r->res_first_lkid = lkb->lkb_id;
++ send_lookup(r, lkb);
++ return 1;
++ }
++
++ for (;;) {
++ /* It's possible for dlm_scand to remove an old rsb for
++ this same resource from the toss list, us to create
++ a new one, look up the master locally, and find it
++ already exists just before dlm_scand does the
++ dir_remove() on the previous rsb. */
++
++ error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
++ r->res_length, &ret_nodeid);
++ if (!error)
++ break;
++ log_debug(ls, "dir_lookup error %d %s", error, r->res_name);
++ schedule();
++ }
++
++ if (ret_nodeid == our_nodeid) {
++ r->res_first_lkid = 0;
++ r->res_nodeid = 0;
++ lkb->lkb_nodeid = 0;
++ } else {
++ r->res_first_lkid = lkb->lkb_id;
++ r->res_nodeid = ret_nodeid;
++ lkb->lkb_nodeid = ret_nodeid;
++ }
++ return 0;
++}
++
++static void process_lookup_list(struct dlm_rsb *r)
++{
++ struct dlm_lkb *lkb, *safe;
++
++ list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
++ list_del(&lkb->lkb_rsb_lookup);
++ _request_lock(r, lkb);
++ schedule();
++ }
++}
++
++/* confirm_master -- confirm (or deny) an rsb's master nodeid */
++
++static void confirm_master(struct dlm_rsb *r, int error)
++{
++ struct dlm_lkb *lkb;
++
++ if (!r->res_first_lkid)
++ return;
++
++ switch (error) {
++ case 0:
++ case -EINPROGRESS:
++ r->res_first_lkid = 0;
++ process_lookup_list(r);
++ break;
++
++ case -EAGAIN:
++ /* the remote master didn't queue our NOQUEUE request;
++ make a waiting lkb the first_lkid */
++
++ r->res_first_lkid = 0;
++
++ if (!list_empty(&r->res_lookup)) {
++ lkb = list_entry(r->res_lookup.next, struct dlm_lkb,
++ lkb_rsb_lookup);
++ list_del(&lkb->lkb_rsb_lookup);
++ r->res_first_lkid = lkb->lkb_id;
++ _request_lock(r, lkb);
++ } else
++ r->res_nodeid = -1;
++ break;
++
++ default:
++ log_error(r->res_ls, "confirm_master unknown error %d", error);
++ }
++}
++
++static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
++ int namelen, uint32_t parent_lkid, void *ast,
++ void *astarg, void *bast, struct dlm_args *args)
++{
++ int rv = -EINVAL;
++
++ /* check for invalid arg usage */
++
++ if (mode < 0 || mode > DLM_LOCK_EX)
++ goto out;
++
++ if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))
++ goto out;
++
++ if (flags & DLM_LKF_CANCEL)
++ goto out;
++
++ if (flags & DLM_LKF_QUECVT && !(flags & DLM_LKF_CONVERT))
++ goto out;
++
++ if (flags & DLM_LKF_CONVDEADLK && !(flags & DLM_LKF_CONVERT))
++ goto out;
++
++ if (flags & DLM_LKF_CONVDEADLK && flags & DLM_LKF_NOQUEUE)
++ goto out;
++
++ if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_CONVERT)
++ goto out;
++
++ if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_QUECVT)
++ goto out;
++
++ if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_NOQUEUE)
++ goto out;
++
++ if (flags & DLM_LKF_EXPEDITE && mode != DLM_LOCK_NL)
++ goto out;
++
++ if (!ast || !lksb)
++ goto out;
++
++ if (flags & DLM_LKF_VALBLK && !lksb->sb_lvbptr)
++ goto out;
++
++ /* parent/child locks not yet supported */
++ if (parent_lkid)
++ goto out;
++
++ if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid)
++ goto out;
++
++ /* these args will be copied to the lkb in validate_lock_args,
++ it cannot be done now because when converting locks, fields in
++ an active lkb cannot be modified before locking the rsb */
++
++ args->flags = flags;
++ args->astaddr = ast;
++ args->astparam = (long) astarg;
++ args->bastaddr = bast;
++ args->mode = mode;
++ args->lksb = lksb;
++ rv = 0;
++ out:
++ return rv;
++}
++
++static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
++{
++ if (flags & ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK |
++ DLM_LKF_FORCEUNLOCK))
++ return -EINVAL;
++
++ args->flags = flags;
++ args->astparam = (long) astarg;
++ return 0;
++}
++
++static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_args *args)
++{
++ int rv = -EINVAL;
++
++ if (args->flags & DLM_LKF_CONVERT) {
++ if (lkb->lkb_flags & DLM_IFL_MSTCPY)
++ goto out;
++
++ if (args->flags & DLM_LKF_QUECVT &&
++ !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1])
++ goto out;
++
++ rv = -EBUSY;
++ if (lkb->lkb_status != DLM_LKSTS_GRANTED)
++ goto out;
++
++ if (lkb->lkb_wait_type)
++ goto out;
++ }
++
++ lkb->lkb_exflags = args->flags;
++ lkb->lkb_sbflags = 0;
++ lkb->lkb_astaddr = args->astaddr;
++ lkb->lkb_astparam = args->astparam;
++ lkb->lkb_bastaddr = args->bastaddr;
++ lkb->lkb_rqmode = args->mode;
++ lkb->lkb_lksb = args->lksb;
++ lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
++ lkb->lkb_ownpid = (int) current->pid;
++ rv = 0;
++ out:
++ return rv;
++}
++
++static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
++{
++ int rv = -EINVAL;
++
++ if (lkb->lkb_flags & DLM_IFL_MSTCPY)
++ goto out;
++
++ if (args->flags & DLM_LKF_FORCEUNLOCK)
++ goto out_ok;
++
++ if (args->flags & DLM_LKF_CANCEL &&
++ lkb->lkb_status == DLM_LKSTS_GRANTED)
++ goto out;
++
++ if (!(args->flags & DLM_LKF_CANCEL) &&
++ lkb->lkb_status != DLM_LKSTS_GRANTED)
++ goto out;
++
++ rv = -EBUSY;
++ if (lkb->lkb_wait_type)
++ goto out;
++
++ out_ok:
++ lkb->lkb_exflags = args->flags;
++ lkb->lkb_sbflags = 0;
++ lkb->lkb_astparam = args->astparam;
++
++ rv = 0;
++ out:
++ return rv;
++}
++
++/*
++ * Four stage 4 varieties:
++ * do_request(), do_convert(), do_unlock(), do_cancel()
++ * These are called on the master node for the given lock and
++ * from the central locking logic.
++ */
++
++static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error = 0;
++
++ if (can_be_granted(r, lkb, 1)) {
++ grant_lock(r, lkb);
++ queue_cast(r, lkb, 0);
++ goto out;
++ }
++
++ if (can_be_queued(lkb)) {
++ error = -EINPROGRESS;
++ add_lkb(r, lkb, DLM_LKSTS_WAITING);
++ send_blocking_asts(r, lkb);
++ goto out;
++ }
++
++ error = -EAGAIN;
++ if (force_blocking_asts(lkb))
++ send_blocking_asts_all(r, lkb);
++ queue_cast(r, lkb, -EAGAIN);
++
++ out:
++ return error;
++}
++
++static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error = 0;
++
++ /* changing an existing lock may allow others to be granted */
++
++ if (can_be_granted(r, lkb, 1)) {
++ grant_lock(r, lkb);
++ queue_cast(r, lkb, 0);
++ grant_pending_locks(r);
++ goto out;
++ }
++
++ if (can_be_queued(lkb)) {
++ if (is_demoted(lkb))
++ grant_pending_locks(r);
++ error = -EINPROGRESS;
++ del_lkb(r, lkb);
++ add_lkb(r, lkb, DLM_LKSTS_CONVERT);
++ send_blocking_asts(r, lkb);
++ goto out;
++ }
++
++ error = -EAGAIN;
++ if (force_blocking_asts(lkb))
++ send_blocking_asts_all(r, lkb);
++ queue_cast(r, lkb, -EAGAIN);
++
++ out:
++ return error;
++}
++
++static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ remove_lock(r, lkb);
++ queue_cast(r, lkb, -DLM_EUNLOCK);
++ grant_pending_locks(r);
++ return -DLM_EUNLOCK;
++}
++
++/* FIXME: if revert_lock() finds that the lkb is granted, we should
++ skip the queue_cast(ECANCEL). It indicates that the request/convert
++ completed (and queued a normal ast) just before the cancel; we don't
++ want to clobber the sb_result for the normal ast with ECANCEL. */
++
++static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ revert_lock(r, lkb);
++ queue_cast(r, lkb, -DLM_ECANCEL);
++ grant_pending_locks(r);
++ return -DLM_ECANCEL;
++}
++
++/*
++ * Four stage 3 varieties:
++ * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()
++ */
++
++/* add a new lkb to a possibly new rsb, called by requesting process */
++
++static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error;
++
++ /* set_master: sets lkb nodeid from r */
++
++ error = set_master(r, lkb);
++ if (error < 0)
++ goto out;
++ if (error) {
++ error = 0;
++ goto out;
++ }
++
++ if (is_remote(r))
++ /* receive_request() calls do_request() on remote node */
++ error = send_request(r, lkb);
++ else
++ error = do_request(r, lkb);
++ out:
++ return error;
++}
++
++/* change some property of an existing lkb, e.g. mode */
++
++static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error;
++
++ if (is_remote(r))
++ /* receive_convert() calls do_convert() on remote node */
++ error = send_convert(r, lkb);
++ else
++ error = do_convert(r, lkb);
++
++ return error;
++}
++
++/* remove an existing lkb from the granted queue */
++
++static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error;
++
++ if (is_remote(r))
++ /* receive_unlock() calls do_unlock() on remote node */
++ error = send_unlock(r, lkb);
++ else
++ error = do_unlock(r, lkb);
++
++ return error;
++}
++
++/* remove an existing lkb from the convert or wait queue */
++
++static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error;
++
++ if (is_remote(r))
++ /* receive_cancel() calls do_cancel() on remote node */
++ error = send_cancel(r, lkb);
++ else
++ error = do_cancel(r, lkb);
++
++ return error;
++}
++
++/*
++ * Four stage 2 varieties:
++ * request_lock(), convert_lock(), unlock_lock(), cancel_lock()
++ */
++
++static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name,
++ int len, struct dlm_args *args)
++{
++ struct dlm_rsb *r;
++ int error;
++
++ error = validate_lock_args(ls, lkb, args);
++ if (error)
++ goto out;
++
++ error = find_rsb(ls, name, len, R_CREATE, &r);
++ if (error)
++ goto out;
++
++ lock_rsb(r);
++
++ attach_lkb(r, lkb);
++ lkb->lkb_lksb->sb_lkid = lkb->lkb_id;
++
++ error = _request_lock(r, lkb);
++
++ unlock_rsb(r);
++ put_rsb(r);
++
++ out:
++ return error;
++}
++
++static int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_args *args)
++{
++ struct dlm_rsb *r;
++ int error;
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ error = validate_lock_args(ls, lkb, args);
++ if (error)
++ goto out;
++
++ error = _convert_lock(r, lkb);
++ out:
++ unlock_rsb(r);
++ put_rsb(r);
++ return error;
++}
++
++static int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_args *args)
++{
++ struct dlm_rsb *r;
++ int error;
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ error = validate_unlock_args(lkb, args);
++ if (error)
++ goto out;
++
++ error = _unlock_lock(r, lkb);
++ out:
++ unlock_rsb(r);
++ put_rsb(r);
++ return error;
++}
++
++static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_args *args)
++{
++ struct dlm_rsb *r;
++ int error;
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ error = validate_unlock_args(lkb, args);
++ if (error)
++ goto out;
++
++ error = _cancel_lock(r, lkb);
++ out:
++ unlock_rsb(r);
++ put_rsb(r);
++ return error;
++}
++
++/*
++ * Two stage 1 varieties: dlm_lock() and dlm_unlock()
++ */
++
++int dlm_lock(dlm_lockspace_t *lockspace,
++ int mode,
++ struct dlm_lksb *lksb,
++ uint32_t flags,
++ void *name,
++ unsigned int namelen,
++ uint32_t parent_lkid,
++ void (*ast) (void *astarg),
++ void *astarg,
++ void (*bast) (void *astarg, int mode))
++{
++ struct dlm_ls *ls;
++ struct dlm_lkb *lkb;
++ struct dlm_args args;
++ int error, convert = flags & DLM_LKF_CONVERT;
++
++ ls = dlm_find_lockspace_local(lockspace);
++ if (!ls)
++ return -EINVAL;
++
++ lock_recovery(ls);
++
++ if (convert)
++ error = find_lkb(ls, lksb->sb_lkid, &lkb);
++ else
++ error = create_lkb(ls, &lkb);
++
++ if (error)
++ goto out;
++
++ error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast,
++ astarg, bast, &args);
++ if (error)
++ goto out_put;
++
++ if (convert)
++ error = convert_lock(ls, lkb, &args);
++ else
++ error = request_lock(ls, lkb, name, namelen, &args);
++
++ if (error == -EINPROGRESS)
++ error = 0;
++ out_put:
++ if (convert || error)
++ __put_lkb(ls, lkb);
++ if (error == -EAGAIN)
++ error = 0;
++ out:
++ unlock_recovery(ls);
++ dlm_put_lockspace(ls);
++ return error;
++}
++
++int dlm_unlock(dlm_lockspace_t *lockspace,
++ uint32_t lkid,
++ uint32_t flags,
++ struct dlm_lksb *lksb,
++ void *astarg)
++{
++ struct dlm_ls *ls;
++ struct dlm_lkb *lkb;
++ struct dlm_args args;
++ int error;
++
++ ls = dlm_find_lockspace_local(lockspace);
++ if (!ls)
++ return -EINVAL;
++
++ lock_recovery(ls);
++
++ error = find_lkb(ls, lkid, &lkb);
++ if (error)
++ goto out;
++
++ error = set_unlock_args(flags, astarg, &args);
++ if (error)
++ goto out_put;
++
++ if (flags & DLM_LKF_CANCEL)
++ error = cancel_lock(ls, lkb, &args);
++ else
++ error = unlock_lock(ls, lkb, &args);
++
++ if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
++ error = 0;
++ out_put:
++ dlm_put_lkb(lkb);
++ out:
++ unlock_recovery(ls);
++ dlm_put_lockspace(ls);
++ return error;
++}
++
++/*
++ * send/receive routines for remote operations and replies
++ *
++ * send_args
++ * send_common
++ * send_request receive_request
++ * send_convert receive_convert
++ * send_unlock receive_unlock
++ * send_cancel receive_cancel
++ * send_grant receive_grant
++ * send_bast receive_bast
++ * send_lookup receive_lookup
++ * send_remove receive_remove
++ *
++ * send_common_reply
++ * receive_request_reply send_request_reply
++ * receive_convert_reply send_convert_reply
++ * receive_unlock_reply send_unlock_reply
++ * receive_cancel_reply send_cancel_reply
++ * receive_lookup_reply send_lookup_reply
++ */
++
++static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ int to_nodeid, int mstype,
++ struct dlm_message **ms_ret,
++ struct dlm_mhandle **mh_ret)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ char *mb;
++ int mb_len = sizeof(struct dlm_message);
++
++ switch (mstype) {
++ case DLM_MSG_REQUEST:
++ case DLM_MSG_LOOKUP:
++ case DLM_MSG_REMOVE:
++ mb_len += r->res_length;
++ break;
++ case DLM_MSG_CONVERT:
++ case DLM_MSG_UNLOCK:
++ case DLM_MSG_REQUEST_REPLY:
++ case DLM_MSG_CONVERT_REPLY:
++ case DLM_MSG_GRANT:
++ if (lkb && lkb->lkb_lvbptr)
++ mb_len += r->res_ls->ls_lvblen;
++ break;
++ }
++
++ /* get_buffer gives us a message handle (mh) that we need to
++ pass into lowcomms_commit and a message buffer (mb) that we
++ write our data into */
++
++ mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
++ if (!mh)
++ return -ENOBUFS;
++
++ memset(mb, 0, mb_len);
++
++ ms = (struct dlm_message *) mb;
++
++ ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
++ ms->m_header.h_lockspace = r->res_ls->ls_global_id;
++ ms->m_header.h_nodeid = dlm_our_nodeid();
++ ms->m_header.h_length = mb_len;
++ ms->m_header.h_cmd = DLM_MSG;
++
++ ms->m_type = mstype;
++
++ *mh_ret = mh;
++ *ms_ret = ms;
++ return 0;
++}
++
++/* further lowcomms enhancements or alternate implementations may make
++ the return value from this function useful at some point */
++
++static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms)
++{
++ dlm_message_out(ms);
++ dlm_lowcomms_commit_buffer(mh);
++ return 0;
++}
++
++static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ ms->m_nodeid = lkb->lkb_nodeid;
++ ms->m_pid = lkb->lkb_ownpid;
++ ms->m_lkid = lkb->lkb_id;
++ ms->m_remid = lkb->lkb_remid;
++ ms->m_exflags = lkb->lkb_exflags;
++ ms->m_sbflags = lkb->lkb_sbflags;
++ ms->m_flags = lkb->lkb_flags;
++ ms->m_lvbseq = lkb->lkb_lvbseq;
++ ms->m_status = lkb->lkb_status;
++ ms->m_grmode = lkb->lkb_grmode;
++ ms->m_rqmode = lkb->lkb_rqmode;
++ ms->m_hash = r->res_hash;
++
++ /* m_result and m_bastmode are set from function args,
++ not from lkb fields */
++
++ if (lkb->lkb_bastaddr)
++ ms->m_asts |= AST_BAST;
++ if (lkb->lkb_astaddr)
++ ms->m_asts |= AST_COMP;
++
++ if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP)
++ memcpy(ms->m_extra, r->res_name, r->res_length);
++
++ else if (lkb->lkb_lvbptr)
++ memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
++
++}
++
++static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int to_nodeid, error;
++
++ add_to_waiters(lkb, mstype);
++
++ to_nodeid = r->res_nodeid;
++
++ error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
++ if (error)
++ goto fail;
++
++ send_args(r, lkb, ms);
++
++ error = send_message(mh, ms);
++ if (error)
++ goto fail;
++ return 0;
++
++ fail:
++ remove_from_waiters(lkb);
++ return error;
++}
++
++static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ return send_common(r, lkb, DLM_MSG_REQUEST);
++}
++
++static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ int error;
++
++ error = send_common(r, lkb, DLM_MSG_CONVERT);
++
++ /* down conversions go without a reply from the master */
++ if (!error && down_conversion(lkb)) {
++ remove_from_waiters(lkb);
++ r->res_ls->ls_stub_ms.m_result = 0;
++ r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;
++ __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
++ }
++
++ return error;
++}
++
++/* FIXME: if this lkb is the only lock we hold on the rsb, then set
++ MASTER_UNCERTAIN to force the next request on the rsb to confirm
++ that the master is still correct. */
++
++static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ return send_common(r, lkb, DLM_MSG_UNLOCK);
++}
++
++static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ return send_common(r, lkb, DLM_MSG_CANCEL);
++}
++
++static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int to_nodeid, error;
++
++ to_nodeid = lkb->lkb_nodeid;
++
++ error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh);
++ if (error)
++ goto out;
++
++ send_args(r, lkb, ms);
++
++ ms->m_result = 0;
++
++ error = send_message(mh, ms);
++ out:
++ return error;
++}
++
++static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int to_nodeid, error;
++
++ to_nodeid = lkb->lkb_nodeid;
++
++ error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh);
++ if (error)
++ goto out;
++
++ send_args(r, lkb, ms);
++
++ ms->m_bastmode = mode;
++
++ error = send_message(mh, ms);
++ out:
++ return error;
++}
++
++static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int to_nodeid, error;
++
++ add_to_waiters(lkb, DLM_MSG_LOOKUP);
++
++ to_nodeid = dlm_dir_nodeid(r);
++
++ error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
++ if (error)
++ goto fail;
++
++ send_args(r, lkb, ms);
++
++ error = send_message(mh, ms);
++ if (error)
++ goto fail;
++ return 0;
++
++ fail:
++ remove_from_waiters(lkb);
++ return error;
++}
++
++static int send_remove(struct dlm_rsb *r)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int to_nodeid, error;
++
++ to_nodeid = dlm_dir_nodeid(r);
++
++ error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh);
++ if (error)
++ goto out;
++
++ memcpy(ms->m_extra, r->res_name, r->res_length);
++ ms->m_hash = r->res_hash;
++
++ error = send_message(mh, ms);
++ out:
++ return error;
++}
++
++static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ int mstype, int rv)
++{
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int to_nodeid, error;
++
++ to_nodeid = lkb->lkb_nodeid;
++
++ error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
++ if (error)
++ goto out;
++
++ send_args(r, lkb, ms);
++
++ ms->m_result = rv;
++
++ error = send_message(mh, ms);
++ out:
++ return error;
++}
++
++static int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
++{
++ return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv);
++}
++
++static int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
++{
++ return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv);
++}
++
++static int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
++{
++ return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv);
++}
++
++static int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
++{
++ return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv);
++}
++
++static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,
++ int ret_nodeid, int rv)
++{
++ struct dlm_rsb *r = &ls->ls_stub_rsb;
++ struct dlm_message *ms;
++ struct dlm_mhandle *mh;
++ int error, nodeid = ms_in->m_header.h_nodeid;
++
++ error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh);
++ if (error)
++ goto out;
++
++ ms->m_lkid = ms_in->m_lkid;
++ ms->m_result = rv;
++ ms->m_nodeid = ret_nodeid;
++
++ error = send_message(mh, ms);
++ out:
++ return error;
++}
++
++/* which args we save from a received message depends heavily on the type
++ of message, unlike the send side where we can safely send everything about
++ the lkb for any type of message */
++
++static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)
++{
++ lkb->lkb_exflags = ms->m_exflags;
++ lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
++ (ms->m_flags & 0x0000FFFF);
++}
++
++static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
++{
++ lkb->lkb_sbflags = ms->m_sbflags;
++ lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
++ (ms->m_flags & 0x0000FFFF);
++}
++
++static int receive_extralen(struct dlm_message *ms)
++{
++ return (ms->m_header.h_length - sizeof(struct dlm_message));
++}
++
++static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ int len;
++
++ if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
++ if (!lkb->lkb_lvbptr)
++ lkb->lkb_lvbptr = allocate_lvb(ls);
++ if (!lkb->lkb_lvbptr)
++ return -ENOMEM;
++ len = receive_extralen(ms);
++ memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
++ }
++ return 0;
++}
++
++static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ lkb->lkb_nodeid = ms->m_header.h_nodeid;
++ lkb->lkb_ownpid = ms->m_pid;
++ lkb->lkb_remid = ms->m_lkid;
++ lkb->lkb_grmode = DLM_LOCK_IV;
++ lkb->lkb_rqmode = ms->m_rqmode;
++ lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST);
++ lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP);
++
++ DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
++
++ if (receive_lvb(ls, lkb, ms))
++ return -ENOMEM;
++
++ return 0;
++}
++
++static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ if (lkb->lkb_nodeid != ms->m_header.h_nodeid) {
++ log_error(ls, "convert_args nodeid %d %d lkid %x %x",
++ lkb->lkb_nodeid, ms->m_header.h_nodeid,
++ lkb->lkb_id, lkb->lkb_remid);
++ return -EINVAL;
++ }
++
++ if (!is_master_copy(lkb))
++ return -EINVAL;
++
++ if (lkb->lkb_status != DLM_LKSTS_GRANTED)
++ return -EBUSY;
++
++ if (receive_lvb(ls, lkb, ms))
++ return -ENOMEM;
++
++ lkb->lkb_rqmode = ms->m_rqmode;
++ lkb->lkb_lvbseq = ms->m_lvbseq;
++
++ return 0;
++}
++
++static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ if (!is_master_copy(lkb))
++ return -EINVAL;
++ if (receive_lvb(ls, lkb, ms))
++ return -ENOMEM;
++ return 0;
++}
++
++/* We fill in the stub-lkb fields with the info that send_xxxx_reply()
++ uses to send a reply and that the remote end uses to process the reply. */
++
++static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb = &ls->ls_stub_lkb;
++ lkb->lkb_nodeid = ms->m_header.h_nodeid;
++ lkb->lkb_remid = ms->m_lkid;
++}
++
++static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error, namelen;
++
++ error = create_lkb(ls, &lkb);
++ if (error)
++ goto fail;
++
++ receive_flags(lkb, ms);
++ lkb->lkb_flags |= DLM_IFL_MSTCPY;
++ error = receive_request_args(ls, lkb, ms);
++ if (error) {
++ __put_lkb(ls, lkb);
++ goto fail;
++ }
++
++ namelen = receive_extralen(ms);
++
++ error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r);
++ if (error) {
++ __put_lkb(ls, lkb);
++ goto fail;
++ }
++
++ lock_rsb(r);
++
++ attach_lkb(r, lkb);
++ error = do_request(r, lkb);
++ send_request_reply(r, lkb, error);
++
++ unlock_rsb(r);
++ put_rsb(r);
++
++ if (error == -EINPROGRESS)
++ error = 0;
++ if (error)
++ dlm_put_lkb(lkb);
++ return;
++
++ fail:
++ setup_stub_lkb(ls, ms);
++ send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
++}
++
++static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error, reply = 1;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error)
++ goto fail;
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ receive_flags(lkb, ms);
++ error = receive_convert_args(ls, lkb, ms);
++ if (error)
++ goto out;
++ reply = !down_conversion(lkb);
++
++ error = do_convert(r, lkb);
++ out:
++ if (reply)
++ send_convert_reply(r, lkb, error);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ dlm_put_lkb(lkb);
++ return;
++
++ fail:
++ setup_stub_lkb(ls, ms);
++ send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
++}
++
++static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error)
++ goto fail;
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ receive_flags(lkb, ms);
++ error = receive_unlock_args(ls, lkb, ms);
++ if (error)
++ goto out;
++
++ error = do_unlock(r, lkb);
++ out:
++ send_unlock_reply(r, lkb, error);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ dlm_put_lkb(lkb);
++ return;
++
++ fail:
++ setup_stub_lkb(ls, ms);
++ send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
++}
++
++static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error)
++ goto fail;
++
++ receive_flags(lkb, ms);
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ error = do_cancel(r, lkb);
++ send_cancel_reply(r, lkb, error);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ dlm_put_lkb(lkb);
++ return;
++
++ fail:
++ setup_stub_lkb(ls, ms);
++ send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
++}
++
++static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error) {
++ log_error(ls, "receive_grant no lkb");
++ return;
++ }
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ receive_flags_reply(lkb, ms);
++ grant_lock_pc(r, lkb, ms);
++ queue_cast(r, lkb, 0);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ dlm_put_lkb(lkb);
++}
++
++static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error) {
++ log_error(ls, "receive_bast no lkb");
++ return;
++ }
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ queue_bast(r, lkb, ms->m_bastmode);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ dlm_put_lkb(lkb);
++}
++
++static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid;
++
++ from_nodeid = ms->m_header.h_nodeid;
++ our_nodeid = dlm_our_nodeid();
++
++ len = receive_extralen(ms);
++
++ dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
++ if (dir_nodeid != our_nodeid) {
++ log_error(ls, "lookup dir_nodeid %d from %d",
++ dir_nodeid, from_nodeid);
++ error = -EINVAL;
++ ret_nodeid = -1;
++ goto out;
++ }
++
++ error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &ret_nodeid);
++
++ /* Optimization: we're master so treat lookup as a request */
++ if (!error && ret_nodeid == our_nodeid) {
++ receive_request(ls, ms);
++ return;
++ }
++ out:
++ send_lookup_reply(ls, ms, ret_nodeid, error);
++}
++
++static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ int len, dir_nodeid, from_nodeid;
++
++ from_nodeid = ms->m_header.h_nodeid;
++
++ len = receive_extralen(ms);
++
++ dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
++ if (dir_nodeid != dlm_our_nodeid()) {
++ log_error(ls, "remove dir entry dir_nodeid %d from %d",
++ dir_nodeid, from_nodeid);
++ return;
++ }
++
++ dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
++}
++
++static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error, mstype;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error) {
++ log_error(ls, "receive_request_reply no lkb");
++ return;
++ }
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ mstype = lkb->lkb_wait_type;
++ error = remove_from_waiters(lkb);
++ if (error) {
++ log_error(ls, "receive_request_reply not on waiters");
++ goto out;
++ }
++
++ /* this is the value returned from do_request() on the master */
++ error = ms->m_result;
++
++ r = lkb->lkb_resource;
++ hold_rsb(r);
++ lock_rsb(r);
++
++ /* Optimization: the dir node was also the master, so it took our
++ lookup as a request and sent request reply instead of lookup reply */
++ if (mstype == DLM_MSG_LOOKUP) {
++ r->res_nodeid = ms->m_header.h_nodeid;
++ lkb->lkb_nodeid = r->res_nodeid;
++ }
++
++ switch (error) {
++ case -EAGAIN:
++ /* request would block (be queued) on remote master;
++ the unhold undoes the original ref from create_lkb()
++ so it leads to the lkb being freed */
++ queue_cast(r, lkb, -EAGAIN);
++ confirm_master(r, -EAGAIN);
++ unhold_lkb(lkb);
++ break;
++
++ case -EINPROGRESS:
++ case 0:
++ /* request was queued or granted on remote master */
++ receive_flags_reply(lkb, ms);
++ lkb->lkb_remid = ms->m_lkid;
++ if (error)
++ add_lkb(r, lkb, DLM_LKSTS_WAITING);
++ else {
++ grant_lock_pc(r, lkb, ms);
++ queue_cast(r, lkb, 0);
++ }
++ confirm_master(r, error);
++ break;
++
++ case -EBADR:
++ case -ENOTBLK:
++ /* find_rsb failed to find rsb or rsb wasn't master */
++ r->res_nodeid = -1;
++ lkb->lkb_nodeid = -1;
++ _request_lock(r, lkb);
++ break;
++
++ default:
++ log_error(ls, "receive_request_reply error %d", error);
++ }
++
++ unlock_rsb(r);
++ put_rsb(r);
++ out:
++ dlm_put_lkb(lkb);
++}
++
++static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ struct dlm_message *ms)
++{
++ int error = ms->m_result;
++
++ /* this is the value returned from do_convert() on the master */
++
++ switch (error) {
++ case -EAGAIN:
++ /* convert would block (be queued) on remote master */
++ queue_cast(r, lkb, -EAGAIN);
++ break;
++
++ case -EINPROGRESS:
++ /* convert was queued on remote master */
++ del_lkb(r, lkb);
++ add_lkb(r, lkb, DLM_LKSTS_CONVERT);
++ break;
++
++ case 0:
++ /* convert was granted on remote master */
++ receive_flags_reply(lkb, ms);
++ grant_lock_pc(r, lkb, ms);
++ queue_cast(r, lkb, 0);
++ break;
++
++ default:
++ log_error(r->res_ls, "receive_convert_reply error %d", error);
++ }
++}
++
++static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
++{
++ struct dlm_rsb *r = lkb->lkb_resource;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ __receive_convert_reply(r, lkb, ms);
++
++ unlock_rsb(r);
++ put_rsb(r);
++}
++
++static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error) {
++ log_error(ls, "receive_convert_reply no lkb");
++ return;
++ }
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ error = remove_from_waiters(lkb);
++ if (error) {
++ log_error(ls, "receive_convert_reply not on waiters");
++ goto out;
++ }
++
++ _receive_convert_reply(lkb, ms);
++ out:
++ dlm_put_lkb(lkb);
++}
++
++static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
++{
++ struct dlm_rsb *r = lkb->lkb_resource;
++ int error = ms->m_result;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ /* this is the value returned from do_unlock() on the master */
++
++ switch (error) {
++ case -DLM_EUNLOCK:
++ receive_flags_reply(lkb, ms);
++ remove_lock_pc(r, lkb);
++ queue_cast(r, lkb, -DLM_EUNLOCK);
++ break;
++ default:
++ log_error(r->res_ls, "receive_unlock_reply error %d", error);
++ }
++
++ unlock_rsb(r);
++ put_rsb(r);
++}
++
++static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error) {
++ log_error(ls, "receive_unlock_reply no lkb");
++ return;
++ }
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ error = remove_from_waiters(lkb);
++ if (error) {
++ log_error(ls, "receive_unlock_reply not on waiters");
++ goto out;
++ }
++
++ _receive_unlock_reply(lkb, ms);
++ out:
++ dlm_put_lkb(lkb);
++}
++
++static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
++{
++ struct dlm_rsb *r = lkb->lkb_resource;
++ int error = ms->m_result;
++
++ hold_rsb(r);
++ lock_rsb(r);
++
++ /* this is the value returned from do_cancel() on the master */
++
++ switch (error) {
++ case -DLM_ECANCEL:
++ receive_flags_reply(lkb, ms);
++ revert_lock_pc(r, lkb);
++ queue_cast(r, lkb, -DLM_ECANCEL);
++ break;
++ default:
++ log_error(r->res_ls, "receive_cancel_reply error %d", error);
++ }
++
++ unlock_rsb(r);
++ put_rsb(r);
++}
++
++static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ int error;
++
++ error = find_lkb(ls, ms->m_remid, &lkb);
++ if (error) {
++ log_error(ls, "receive_cancel_reply no lkb");
++ return;
++ }
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ error = remove_from_waiters(lkb);
++ if (error) {
++ log_error(ls, "receive_cancel_reply not on waiters");
++ goto out;
++ }
++
++ _receive_cancel_reply(lkb, ms);
++ out:
++ dlm_put_lkb(lkb);
++}
++
++static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error, ret_nodeid;
++
++ error = find_lkb(ls, ms->m_lkid, &lkb);
++ if (error) {
++ log_error(ls, "receive_lookup_reply no lkb");
++ return;
++ }
++
++ error = remove_from_waiters(lkb);
++ if (error) {
++ log_error(ls, "receive_lookup_reply not on waiters");
++ goto out;
++ }
++
++ /* this is the value returned by dlm_dir_lookup on dir node
++ FIXME: will a non-zero error ever be returned? */
++ error = ms->m_result;
++
++ r = lkb->lkb_resource;
++ hold_rsb(r);
++ lock_rsb(r);
++
++ ret_nodeid = ms->m_nodeid;
++ if (ret_nodeid == dlm_our_nodeid()) {
++ r->res_nodeid = 0;
++ ret_nodeid = 0;
++ r->res_first_lkid = 0;
++ } else {
++ /* set_master() will copy res_nodeid to lkb_nodeid */
++ r->res_nodeid = ret_nodeid;
++ }
++
++ _request_lock(r, lkb);
++
++ if (!ret_nodeid)
++ process_lookup_list(r);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ out:
++ dlm_put_lkb(lkb);
++}
++
++int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
++{
++ struct dlm_message *ms = (struct dlm_message *) hd;
++ struct dlm_ls *ls;
++ int error;
++
++ if (!recovery)
++ dlm_message_in(ms);
++
++ ls = dlm_find_lockspace_global(hd->h_lockspace);
++ if (!ls) {
++ log_print("drop message %d from %d for unknown lockspace %d",
++ ms->m_type, nodeid, hd->h_lockspace);
++ return -EINVAL;
++ }
++
++ /* recovery may have just ended leaving a bunch of backed-up requests
++ in the requestqueue; wait while dlm_recoverd clears them */
++
++ if (!recovery)
++ dlm_wait_requestqueue(ls);
++
++ /* recovery may have just started while there were a bunch of
++ in-flight requests -- save them in requestqueue to be processed
++ after recovery. we can't let dlm_recvd block on the recovery
++ lock. if dlm_recoverd is calling this function to clear the
++ requestqueue, it needs to be interrupted (-EINTR) if another
++ recovery operation is starting. */
++
++ while (1) {
++ if (dlm_locking_stopped(ls)) {
++ if (!recovery)
++ dlm_add_requestqueue(ls, nodeid, hd);
++ error = -EINTR;
++ goto out;
++ }
++
++ if (lock_recovery_try(ls))
++ break;
++ schedule();
++ }
++
++ switch (ms->m_type) {
++
++ /* messages sent to a master node */
++
++ case DLM_MSG_REQUEST:
++ receive_request(ls, ms);
++ break;
++
++ case DLM_MSG_CONVERT:
++ receive_convert(ls, ms);
++ break;
++
++ case DLM_MSG_UNLOCK:
++ receive_unlock(ls, ms);
++ break;
++
++ case DLM_MSG_CANCEL:
++ receive_cancel(ls, ms);
++ break;
++
++ /* messages sent from a master node (replies to above) */
++
++ case DLM_MSG_REQUEST_REPLY:
++ receive_request_reply(ls, ms);
++ break;
++
++ case DLM_MSG_CONVERT_REPLY:
++ receive_convert_reply(ls, ms);
++ break;
++
++ case DLM_MSG_UNLOCK_REPLY:
++ receive_unlock_reply(ls, ms);
++ break;
++
++ case DLM_MSG_CANCEL_REPLY:
++ receive_cancel_reply(ls, ms);
++ break;
++
++ /* messages sent from a master node (only two types of async msg) */
++
++ case DLM_MSG_GRANT:
++ receive_grant(ls, ms);
++ break;
++
++ case DLM_MSG_BAST:
++ receive_bast(ls, ms);
++ break;
++
++ /* messages sent to a dir node */
++
++ case DLM_MSG_LOOKUP:
++ receive_lookup(ls, ms);
++ break;
++
++ case DLM_MSG_REMOVE:
++ receive_remove(ls, ms);
++ break;
++
++ /* messages sent from a dir node (remove has no reply) */
++
++ case DLM_MSG_LOOKUP_REPLY:
++ receive_lookup_reply(ls, ms);
++ break;
++
++ default:
++ log_error(ls, "unknown message type %d", ms->m_type);
++ }
++
++ unlock_recovery(ls);
++ out:
++ dlm_put_lockspace(ls);
++ dlm_astd_wake();
++ return 0;
++}
++
++
++/*
++ * Recovery related
++ */
++
++static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ if (middle_conversion(lkb)) {
++ hold_lkb(lkb);
++ ls->ls_stub_ms.m_result = -EINPROGRESS;
++ _remove_from_waiters(lkb);
++ _receive_convert_reply(lkb, &ls->ls_stub_ms);
++
++ /* Same special case as in receive_rcom_lock_args() */
++ lkb->lkb_grmode = DLM_LOCK_IV;
++ rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT);
++ unhold_lkb(lkb);
++
++ } else if (lkb->lkb_rqmode >= lkb->lkb_grmode) {
++ lkb->lkb_flags |= DLM_IFL_RESEND;
++ }
++
++ /* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down
++ conversions are async; there's no reply from the remote master */
++}
++
++/* A waiting lkb needs recovery if the master node has failed, or
++ the master node is changing (only when no directory is used) */
++
++static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ if (dlm_is_removed(ls, lkb->lkb_nodeid))
++ return 1;
++
++ if (!dlm_no_directory(ls))
++ return 0;
++
++ if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)
++ return 1;
++
++ return 0;
++}
++
++/* Recovery for locks that are waiting for replies from nodes that are now
++ gone. We can just complete unlocks and cancels by faking a reply from the
++ dead node. Requests and up-conversions we flag to be resent after
++ recovery. Down-conversions can just be completed with a fake reply like
++ unlocks. Conversions between PR and CW need special attention. */
++
++void dlm_recover_waiters_pre(struct dlm_ls *ls)
++{
++ struct dlm_lkb *lkb, *safe;
++
++ mutex_lock(&ls->ls_waiters_mutex);
++
++ list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
++ log_debug(ls, "pre recover waiter lkid %x type %d flags %x",
++ lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);
++
++ /* all outstanding lookups, regardless of destination will be
++ resent after recovery is done */
++
++ if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) {
++ lkb->lkb_flags |= DLM_IFL_RESEND;
++ continue;
++ }
++
++ if (!waiter_needs_recovery(ls, lkb))
++ continue;
++
++ switch (lkb->lkb_wait_type) {
++
++ case DLM_MSG_REQUEST:
++ lkb->lkb_flags |= DLM_IFL_RESEND;
++ break;
++
++ case DLM_MSG_CONVERT:
++ recover_convert_waiter(ls, lkb);
++ break;
++
++ case DLM_MSG_UNLOCK:
++ hold_lkb(lkb);
++ ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
++ _remove_from_waiters(lkb);
++ _receive_unlock_reply(lkb, &ls->ls_stub_ms);
++ dlm_put_lkb(lkb);
++ break;
++
++ case DLM_MSG_CANCEL:
++ hold_lkb(lkb);
++ ls->ls_stub_ms.m_result = -DLM_ECANCEL;
++ _remove_from_waiters(lkb);
++ _receive_cancel_reply(lkb, &ls->ls_stub_ms);
++ dlm_put_lkb(lkb);
++ break;
++
++ default:
++ log_error(ls, "invalid lkb wait_type %d",
++ lkb->lkb_wait_type);
++ }
++ schedule();
++ }
++ mutex_unlock(&ls->ls_waiters_mutex);
++}
++
++static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
++{
++ struct dlm_lkb *lkb;
++ int rv = 0;
++
++ mutex_lock(&ls->ls_waiters_mutex);
++ list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
++ if (lkb->lkb_flags & DLM_IFL_RESEND) {
++ rv = lkb->lkb_wait_type;
++ _remove_from_waiters(lkb);
++ lkb->lkb_flags &= ~DLM_IFL_RESEND;
++ break;
++ }
++ }
++ mutex_unlock(&ls->ls_waiters_mutex);
++
++ if (!rv)
++ lkb = NULL;
++ *lkb_ret = lkb;
++ return rv;
++}
++
++/* Deal with lookups and lkb's marked RESEND from _pre. We may now be the
++ master or dir-node for r. Processing the lkb may result in it being placed
++ back on waiters. */
++
++int dlm_recover_waiters_post(struct dlm_ls *ls)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *r;
++ int error = 0, mstype;
++
++ while (1) {
++ if (dlm_locking_stopped(ls)) {
++ log_debug(ls, "recover_waiters_post aborted");
++ error = -EINTR;
++ break;
++ }
++
++ mstype = remove_resend_waiter(ls, &lkb);
++ if (!mstype)
++ break;
++
++ r = lkb->lkb_resource;
++
++ log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
++ lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
++
++ switch (mstype) {
++
++ case DLM_MSG_LOOKUP:
++ hold_rsb(r);
++ lock_rsb(r);
++ _request_lock(r, lkb);
++ if (is_master(r))
++ confirm_master(r, 0);
++ unlock_rsb(r);
++ put_rsb(r);
++ break;
++
++ case DLM_MSG_REQUEST:
++ hold_rsb(r);
++ lock_rsb(r);
++ _request_lock(r, lkb);
++ if (is_master(r))
++ confirm_master(r, 0);
++ unlock_rsb(r);
++ put_rsb(r);
++ break;
++
++ case DLM_MSG_CONVERT:
++ hold_rsb(r);
++ lock_rsb(r);
++ _convert_lock(r, lkb);
++ unlock_rsb(r);
++ put_rsb(r);
++ break;
++
++ default:
++ log_error(ls, "recover_waiters_post type %d", mstype);
++ }
++ }
++
++ return error;
++}
++
++static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
++ int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))
++{
++ struct dlm_ls *ls = r->res_ls;
++ struct dlm_lkb *lkb, *safe;
++
++ list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
++ if (test(ls, lkb)) {
++ rsb_set_flag(r, RSB_LOCKS_PURGED);
++ del_lkb(r, lkb);
++ /* this put should free the lkb */
++ if (!dlm_put_lkb(lkb))
++ log_error(ls, "purged lkb not released");
++ }
++ }
++}
++
++static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid));
++}
++
++static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ return is_master_copy(lkb);
++}
++
++static void purge_dead_locks(struct dlm_rsb *r)
++{
++ purge_queue(r, &r->res_grantqueue, &purge_dead_test);
++ purge_queue(r, &r->res_convertqueue, &purge_dead_test);
++ purge_queue(r, &r->res_waitqueue, &purge_dead_test);
++}
++
++void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
++{
++ purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test);
++ purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test);
++ purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test);
++}
++
++/* Get rid of locks held by nodes that are gone. */
++
++int dlm_purge_locks(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r;
++
++ log_debug(ls, "dlm_purge_locks");
++
++ down_write(&ls->ls_root_sem);
++ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
++ hold_rsb(r);
++ lock_rsb(r);
++ if (is_master(r))
++ purge_dead_locks(r);
++ unlock_rsb(r);
++ unhold_rsb(r);
++
++ schedule();
++ }
++ up_write(&ls->ls_root_sem);
++
++ return 0;
++}
++
++static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
++{
++ struct dlm_rsb *r, *r_ret = NULL;
++
++ read_lock(&ls->ls_rsbtbl[bucket].lock);
++ list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
++ if (!rsb_flag(r, RSB_LOCKS_PURGED))
++ continue;
++ hold_rsb(r);
++ rsb_clear_flag(r, RSB_LOCKS_PURGED);
++ r_ret = r;
++ break;
++ }
++ read_unlock(&ls->ls_rsbtbl[bucket].lock);
++ return r_ret;
++}
++
++void dlm_grant_after_purge(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r;
++ int bucket = 0;
++
++ while (1) {
++ r = find_purged_rsb(ls, bucket);
++ if (!r) {
++ if (bucket == ls->ls_rsbtbl_size - 1)
++ break;
++ bucket++;
++ continue;
++ }
++ lock_rsb(r);
++ if (is_master(r)) {
++ grant_pending_locks(r);
++ confirm_master(r, 0);
++ }
++ unlock_rsb(r);
++ put_rsb(r);
++ schedule();
++ }
++}
++
++static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
++ uint32_t remid)
++{
++ struct dlm_lkb *lkb;
++
++ list_for_each_entry(lkb, head, lkb_statequeue) {
++ if (lkb->lkb_nodeid == nodeid && lkb->lkb_remid == remid)
++ return lkb;
++ }
++ return NULL;
++}
++
++static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,
++ uint32_t remid)
++{
++ struct dlm_lkb *lkb;
++
++ lkb = search_remid_list(&r->res_grantqueue, nodeid, remid);
++ if (lkb)
++ return lkb;
++ lkb = search_remid_list(&r->res_convertqueue, nodeid, remid);
++ if (lkb)
++ return lkb;
++ lkb = search_remid_list(&r->res_waitqueue, nodeid, remid);
++ if (lkb)
++ return lkb;
++ return NULL;
++}
++
++static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
++ struct dlm_rsb *r, struct dlm_rcom *rc)
++{
++ struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
++ int lvblen;
++
++ lkb->lkb_nodeid = rc->rc_header.h_nodeid;
++ lkb->lkb_ownpid = rl->rl_ownpid;
++ lkb->lkb_remid = rl->rl_lkid;
++ lkb->lkb_exflags = rl->rl_exflags;
++ lkb->lkb_flags = rl->rl_flags & 0x0000FFFF;
++ lkb->lkb_flags |= DLM_IFL_MSTCPY;
++ lkb->lkb_lvbseq = rl->rl_lvbseq;
++ lkb->lkb_rqmode = rl->rl_rqmode;
++ lkb->lkb_grmode = rl->rl_grmode;
++ /* don't set lkb_status because add_lkb wants to itself */
++
++ lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST);
++ lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP);
++
++ if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
++ lkb->lkb_lvbptr = allocate_lvb(ls);
++ if (!lkb->lkb_lvbptr)
++ return -ENOMEM;
++ lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
++ sizeof(struct rcom_lock);
++ memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);
++ }
++
++ /* Conversions between PR and CW (middle modes) need special handling.
++ The real granted mode of these converting locks cannot be determined
++ until all locks have been rebuilt on the rsb (recover_conversion) */
++
++ if (rl->rl_wait_type == DLM_MSG_CONVERT && middle_conversion(lkb)) {
++ rl->rl_status = DLM_LKSTS_CONVERT;
++ lkb->lkb_grmode = DLM_LOCK_IV;
++ rsb_set_flag(r, RSB_RECOVER_CONVERT);
++ }
++
++ return 0;
++}
++
++/* This lkb may have been recovered in a previous aborted recovery so we need
++ to check if the rsb already has an lkb with the given remote nodeid/lkid.
++ If so we just send back a standard reply. If not, we create a new lkb with
++ the given values and send back our lkid. We send back our lkid by sending
++ back the rcom_lock struct we got but with the remid field filled in. */
++
++int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
++{
++ struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
++ struct dlm_rsb *r;
++ struct dlm_lkb *lkb;
++ int error;
++
++ if (rl->rl_parent_lkid) {
++ error = -EOPNOTSUPP;
++ goto out;
++ }
++
++ error = find_rsb(ls, rl->rl_name, rl->rl_namelen, R_MASTER, &r);
++ if (error)
++ goto out;
++
++ lock_rsb(r);
++
++ lkb = search_remid(r, rc->rc_header.h_nodeid, rl->rl_lkid);
++ if (lkb) {
++ error = -EEXIST;
++ goto out_remid;
++ }
++
++ error = create_lkb(ls, &lkb);
++ if (error)
++ goto out_unlock;
++
++ error = receive_rcom_lock_args(ls, lkb, r, rc);
++ if (error) {
++ __put_lkb(ls, lkb);
++ goto out_unlock;
++ }
++
++ attach_lkb(r, lkb);
++ add_lkb(r, lkb, rl->rl_status);
++ error = 0;
++
++ out_remid:
++ /* this is the new value returned to the lock holder for
++ saving in its process-copy lkb */
++ rl->rl_remid = lkb->lkb_id;
++
++ out_unlock:
++ unlock_rsb(r);
++ put_rsb(r);
++ out:
++ if (error)
++ log_print("recover_master_copy %d %x", error, rl->rl_lkid);
++ rl->rl_result = error;
++ return error;
++}
++
++int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
++{
++ struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
++ struct dlm_rsb *r;
++ struct dlm_lkb *lkb;
++ int error;
++
++ error = find_lkb(ls, rl->rl_lkid, &lkb);
++ if (error) {
++ log_error(ls, "recover_process_copy no lkid %x", rl->rl_lkid);
++ return error;
++ }
++
++ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
++
++ error = rl->rl_result;
++
++ r = lkb->lkb_resource;
++ hold_rsb(r);
++ lock_rsb(r);
++
++ switch (error) {
++ case -EEXIST:
++ log_debug(ls, "master copy exists %x", lkb->lkb_id);
++ /* fall through */
++ case 0:
++ lkb->lkb_remid = rl->rl_remid;
++ break;
++ default:
++ log_error(ls, "dlm_recover_process_copy unknown error %d %x",
++ error, lkb->lkb_id);
++ }
++
++ /* an ack for dlm_recover_locks() which waits for replies from
++ all the locks it sends to new masters */
++ dlm_recovered_lock(r);
++
++ unlock_rsb(r);
++ put_rsb(r);
++ dlm_put_lkb(lkb);
++
++ return 0;
++}
++
++int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
++ int mode, uint32_t flags, void *name, unsigned int namelen,
++ uint32_t parent_lkid)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_args args;
++ int error;
++
++ lock_recovery(ls);
++
++ error = create_lkb(ls, &lkb);
++ if (error) {
++ kfree(ua);
++ goto out;
++ }
++
++ if (flags & DLM_LKF_VALBLK) {
++ ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
++ if (!ua->lksb.sb_lvbptr) {
++ kfree(ua);
++ __put_lkb(ls, lkb);
++ error = -ENOMEM;
++ goto out;
++ }
++ }
++
++ /* After ua is attached to lkb it will be freed by free_lkb().
++ When DLM_IFL_USER is set, the dlm knows that this is a userspace
++ lock and that lkb_astparam is the dlm_user_args structure. */
++
++ error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid,
++ DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args);
++ lkb->lkb_flags |= DLM_IFL_USER;
++ ua->old_mode = DLM_LOCK_IV;
++
++ if (error) {
++ __put_lkb(ls, lkb);
++ goto out;
++ }
++
++ error = request_lock(ls, lkb, name, namelen, &args);
++
++ switch (error) {
++ case 0:
++ break;
++ case -EINPROGRESS:
++ error = 0;
++ break;
++ case -EAGAIN:
++ error = 0;
++ /* fall through */
++ default:
++ __put_lkb(ls, lkb);
++ goto out;
++ }
++
++ /* add this new lkb to the per-process list of locks */
++ spin_lock(&ua->proc->locks_spin);
++ kref_get(&lkb->lkb_ref);
++ list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
++ spin_unlock(&ua->proc->locks_spin);
++ out:
++ unlock_recovery(ls);
++ return error;
++}
++
++int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
++ int mode, uint32_t flags, uint32_t lkid, char *lvb_in)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_args args;
++ struct dlm_user_args *ua;
++ int error;
++
++ lock_recovery(ls);
++
++ error = find_lkb(ls, lkid, &lkb);
++ if (error)
++ goto out;
++
++ /* user can change the params on its lock when it converts it, or
++ add an lvb that didn't exist before */
++
++ ua = (struct dlm_user_args *)lkb->lkb_astparam;
++
++ if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
++ ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
++ if (!ua->lksb.sb_lvbptr) {
++ error = -ENOMEM;
++ goto out_put;
++ }
++ }
++ if (lvb_in && ua->lksb.sb_lvbptr)
++ memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
++
++ ua->castparam = ua_tmp->castparam;
++ ua->castaddr = ua_tmp->castaddr;
++ ua->bastparam = ua_tmp->bastparam;
++ ua->bastaddr = ua_tmp->bastaddr;
++ ua->user_lksb = ua_tmp->user_lksb;
++ ua->old_mode = lkb->lkb_grmode;
++
++ error = set_lock_args(mode, &ua->lksb, flags, 0, 0, DLM_FAKE_USER_AST,
++ ua, DLM_FAKE_USER_AST, &args);
++ if (error)
++ goto out_put;
++
++ error = convert_lock(ls, lkb, &args);
++
++ if (error == -EINPROGRESS || error == -EAGAIN)
++ error = 0;
++ out_put:
++ dlm_put_lkb(lkb);
++ out:
++ unlock_recovery(ls);
++ kfree(ua_tmp);
++ return error;
++}
++
++int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
++ uint32_t flags, uint32_t lkid, char *lvb_in)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_args args;
++ struct dlm_user_args *ua;
++ int error;
++
++ lock_recovery(ls);
++
++ error = find_lkb(ls, lkid, &lkb);
++ if (error)
++ goto out;
++
++ ua = (struct dlm_user_args *)lkb->lkb_astparam;
++
++ if (lvb_in && ua->lksb.sb_lvbptr)
++ memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
++ ua->castparam = ua_tmp->castparam;
++ ua->user_lksb = ua_tmp->user_lksb;
++
++ error = set_unlock_args(flags, ua, &args);
++ if (error)
++ goto out_put;
++
++ error = unlock_lock(ls, lkb, &args);
++
++ if (error == -DLM_EUNLOCK)
++ error = 0;
++ if (error)
++ goto out_put;
++
++ spin_lock(&ua->proc->locks_spin);
++ list_del_init(&lkb->lkb_ownqueue);
++ spin_unlock(&ua->proc->locks_spin);
++
++ /* this removes the reference for the proc->locks list added by
++ dlm_user_request */
++ unhold_lkb(lkb);
++ out_put:
++ dlm_put_lkb(lkb);
++ out:
++ unlock_recovery(ls);
++ return error;
++}
++
++int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
++ uint32_t flags, uint32_t lkid)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_args args;
++ struct dlm_user_args *ua;
++ int error;
++
++ lock_recovery(ls);
++
++ error = find_lkb(ls, lkid, &lkb);
++ if (error)
++ goto out;
++
++ ua = (struct dlm_user_args *)lkb->lkb_astparam;
++ ua->castparam = ua_tmp->castparam;
++ ua->user_lksb = ua_tmp->user_lksb;
++
++ error = set_unlock_args(flags, ua, &args);
++ if (error)
++ goto out_put;
++
++ error = cancel_lock(ls, lkb, &args);
++
++ if (error == -DLM_ECANCEL)
++ error = 0;
++ if (error)
++ goto out_put;
++
++ /* this lkb was removed from the WAITING queue */
++ if (lkb->lkb_grmode == DLM_LOCK_IV) {
++ spin_lock(&ua->proc->locks_spin);
++ list_del_init(&lkb->lkb_ownqueue);
++ spin_unlock(&ua->proc->locks_spin);
++ unhold_lkb(lkb);
++ }
++ out_put:
++ dlm_put_lkb(lkb);
++ out:
++ unlock_recovery(ls);
++ return error;
++}
++
++static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
++
++ if (ua->lksb.sb_lvbptr)
++ kfree(ua->lksb.sb_lvbptr);
++ kfree(ua);
++ lkb->lkb_astparam = (long)NULL;
++
++ /* TODO: propogate to master if needed */
++ return 0;
++}
++
++/* The force flag allows the unlock to go ahead even if the lkb isn't granted.
++ Regardless of what rsb queue the lock is on, it's removed and freed. */
++
++static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
++{
++ struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
++ struct dlm_args args;
++ int error;
++
++ /* FIXME: we need to handle the case where the lkb is in limbo
++ while the rsb is being looked up, currently we assert in
++ _unlock_lock/is_remote because rsb nodeid is -1. */
++
++ set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args);
++
++ error = unlock_lock(ls, lkb, &args);
++ if (error == -DLM_EUNLOCK)
++ error = 0;
++ return error;
++}
++
++/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which
++ 1) references lkb->ua which we free here and 2) adds lkbs to proc->asts,
++ which we clear here. */
++
++/* proc CLOSING flag is set so no more device_reads should look at proc->asts
++ list, and no more device_writes should add lkb's to proc->locks list; so we
++ shouldn't need to take asts_spin or locks_spin here. this assumes that
++ device reads/writes/closes are serialized -- FIXME: we may need to serialize
++ them ourself. */
++
++void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
++{
++ struct dlm_lkb *lkb, *safe;
++
++ lock_recovery(ls);
++ mutex_lock(&ls->ls_clear_proc_locks);
++
++ list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) {
++ if (lkb->lkb_ast_type) {
++ list_del(&lkb->lkb_astqueue);
++ unhold_lkb(lkb);
++ }
++
++ list_del_init(&lkb->lkb_ownqueue);
++
++ if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
++ lkb->lkb_flags |= DLM_IFL_ORPHAN;
++ orphan_proc_lock(ls, lkb);
++ } else {
++ lkb->lkb_flags |= DLM_IFL_DEAD;
++ unlock_proc_lock(ls, lkb);
++ }
++
++ /* this removes the reference for the proc->locks list
++ added by dlm_user_request, it may result in the lkb
++ being freed */
++
++ dlm_put_lkb(lkb);
++ }
++ mutex_unlock(&ls->ls_clear_proc_locks);
++ unlock_recovery(ls);
++}
+diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
+new file mode 100644
+index 0000000..0843a30
+--- /dev/null
++++ b/fs/dlm/lock.h
+@@ -0,0 +1,62 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __LOCK_DOT_H__
++#define __LOCK_DOT_H__
++
++void dlm_print_rsb(struct dlm_rsb *r);
++void dlm_dump_rsb(struct dlm_rsb *r);
++void dlm_print_lkb(struct dlm_lkb *lkb);
++int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
++int dlm_modes_compat(int mode1, int mode2);
++int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
++ unsigned int flags, struct dlm_rsb **r_ret);
++void dlm_put_rsb(struct dlm_rsb *r);
++void dlm_hold_rsb(struct dlm_rsb *r);
++int dlm_put_lkb(struct dlm_lkb *lkb);
++void dlm_scan_rsbs(struct dlm_ls *ls);
++
++int dlm_purge_locks(struct dlm_ls *ls);
++void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
++void dlm_grant_after_purge(struct dlm_ls *ls);
++int dlm_recover_waiters_post(struct dlm_ls *ls);
++void dlm_recover_waiters_pre(struct dlm_ls *ls);
++int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
++int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
++
++int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,
++ uint32_t flags, void *name, unsigned int namelen, uint32_t parent_lkid);
++int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
++ int mode, uint32_t flags, uint32_t lkid, char *lvb_in);
++int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
++ uint32_t flags, uint32_t lkid, char *lvb_in);
++int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
++ uint32_t flags, uint32_t lkid);
++void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);
++
++static inline int is_master(struct dlm_rsb *r)
++{
++ return !r->res_nodeid;
++}
++
++static inline void lock_rsb(struct dlm_rsb *r)
++{
++ mutex_lock(&r->res_mutex);
++}
++
++static inline void unlock_rsb(struct dlm_rsb *r)
++{
++ mutex_unlock(&r->res_mutex);
++}
++
++#endif
++
+diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
+new file mode 100644
+index 0000000..f8842ca
+--- /dev/null
++++ b/fs/dlm/lockspace.c
+@@ -0,0 +1,729 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "member.h"
++#include "recoverd.h"
++#include "ast.h"
++#include "dir.h"
++#include "lowcomms.h"
++#include "config.h"
++#include "memory.h"
++#include "lock.h"
++#include "recover.h"
++
++#ifdef CONFIG_DLM_DEBUG
++int dlm_create_debug_file(struct dlm_ls *ls);
++void dlm_delete_debug_file(struct dlm_ls *ls);
++#else
++static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; }
++static inline void dlm_delete_debug_file(struct dlm_ls *ls) { }
++#endif
++
++static int ls_count;
++static struct mutex ls_lock;
++static struct list_head lslist;
++static spinlock_t lslist_lock;
++static struct task_struct * scand_task;
++
++
++static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len)
++{
++ ssize_t ret = len;
++ int n = simple_strtol(buf, NULL, 0);
++
++ ls = dlm_find_lockspace_local(ls->ls_local_handle);
++ if (!ls)
++ return -EINVAL;
++
++ switch (n) {
++ case 0:
++ dlm_ls_stop(ls);
++ break;
++ case 1:
++ dlm_ls_start(ls);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ dlm_put_lockspace(ls);
++ return ret;
++}
++
++static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len)
++{
++ ls->ls_uevent_result = simple_strtol(buf, NULL, 0);
++ set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags);
++ wake_up(&ls->ls_uevent_wait);
++ return len;
++}
++
++static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id);
++}
++
++static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)
++{
++ ls->ls_global_id = simple_strtoul(buf, NULL, 0);
++ return len;
++}
++
++static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)
++{
++ uint32_t status = dlm_recover_status(ls);
++ return snprintf(buf, PAGE_SIZE, "%x\n", status);
++}
++
++static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid);
++}
++
++struct dlm_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct dlm_ls *, char *);
++ ssize_t (*store)(struct dlm_ls *, const char *, size_t);
++};
++
++static struct dlm_attr dlm_attr_control = {
++ .attr = {.name = "control", .mode = S_IWUSR},
++ .store = dlm_control_store
++};
++
++static struct dlm_attr dlm_attr_event = {
++ .attr = {.name = "event_done", .mode = S_IWUSR},
++ .store = dlm_event_store
++};
++
++static struct dlm_attr dlm_attr_id = {
++ .attr = {.name = "id", .mode = S_IRUGO | S_IWUSR},
++ .show = dlm_id_show,
++ .store = dlm_id_store
++};
++
++static struct dlm_attr dlm_attr_recover_status = {
++ .attr = {.name = "recover_status", .mode = S_IRUGO},
++ .show = dlm_recover_status_show
++};
++
++static struct dlm_attr dlm_attr_recover_nodeid = {
++ .attr = {.name = "recover_nodeid", .mode = S_IRUGO},
++ .show = dlm_recover_nodeid_show
++};
++
++static struct attribute *dlm_attrs[] = {
++ &dlm_attr_control.attr,
++ &dlm_attr_event.attr,
++ &dlm_attr_id.attr,
++ &dlm_attr_recover_status.attr,
++ &dlm_attr_recover_nodeid.attr,
++ NULL,
++};
++
++static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
++ struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
++ return a->show ? a->show(ls, buf) : 0;
++}
++
++static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr,
++ const char *buf, size_t len)
++{
++ struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
++ struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
++ return a->store ? a->store(ls, buf, len) : len;
++}
++
++static void lockspace_kobj_release(struct kobject *k)
++{
++ struct dlm_ls *ls = container_of(k, struct dlm_ls, ls_kobj);
++ kfree(ls);
++}
++
++static struct sysfs_ops dlm_attr_ops = {
++ .show = dlm_attr_show,
++ .store = dlm_attr_store,
++};
++
++static struct kobj_type dlm_ktype = {
++ .default_attrs = dlm_attrs,
++ .sysfs_ops = &dlm_attr_ops,
++ .release = lockspace_kobj_release,
++};
++
++static struct kset dlm_kset = {
++ .subsys = &kernel_subsys,
++ .kobj = {.name = "dlm",},
++ .ktype = &dlm_ktype,
++};
++
++static int kobject_setup(struct dlm_ls *ls)
++{
++ char lsname[DLM_LOCKSPACE_LEN];
++ int error;
++
++ memset(lsname, 0, DLM_LOCKSPACE_LEN);
++ snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
++
++ error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
++ if (error)
++ return error;
++
++ ls->ls_kobj.kset = &dlm_kset;
++ ls->ls_kobj.ktype = &dlm_ktype;
++ return 0;
++}
++
++static int do_uevent(struct dlm_ls *ls, int in)
++{
++ int error;
++
++ if (in)
++ kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE);
++ else
++ kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE);
++
++ error = wait_event_interruptible(ls->ls_uevent_wait,
++ test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags));
++ if (error)
++ goto out;
++
++ error = ls->ls_uevent_result;
++ out:
++ return error;
++}
++
++
++int dlm_lockspace_init(void)
++{
++ int error;
++
++ ls_count = 0;
++ mutex_init(&ls_lock);
++ INIT_LIST_HEAD(&lslist);
++ spin_lock_init(&lslist_lock);
++
++ error = kset_register(&dlm_kset);
++ if (error)
++ printk("dlm_lockspace_init: cannot register kset %d\n", error);
++ return error;
++}
++
++void dlm_lockspace_exit(void)
++{
++ kset_unregister(&dlm_kset);
++}
++
++static int dlm_scand(void *data)
++{
++ struct dlm_ls *ls;
++
++ while (!kthread_should_stop()) {
++ list_for_each_entry(ls, &lslist, ls_list)
++ dlm_scan_rsbs(ls);
++ schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
++ }
++ return 0;
++}
++
++static int dlm_scand_start(void)
++{
++ struct task_struct *p;
++ int error = 0;
++
++ p = kthread_run(dlm_scand, NULL, "dlm_scand");
++ if (IS_ERR(p))
++ error = PTR_ERR(p);
++ else
++ scand_task = p;
++ return error;
++}
++
++static void dlm_scand_stop(void)
++{
++ kthread_stop(scand_task);
++}
++
++static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen)
++{
++ struct dlm_ls *ls;
++
++ spin_lock(&lslist_lock);
++
++ list_for_each_entry(ls, &lslist, ls_list) {
++ if (ls->ls_namelen == namelen &&
++ memcmp(ls->ls_name, name, namelen) == 0)
++ goto out;
++ }
++ ls = NULL;
++ out:
++ spin_unlock(&lslist_lock);
++ return ls;
++}
++
++struct dlm_ls *dlm_find_lockspace_global(uint32_t id)
++{
++ struct dlm_ls *ls;
++
++ spin_lock(&lslist_lock);
++
++ list_for_each_entry(ls, &lslist, ls_list) {
++ if (ls->ls_global_id == id) {
++ ls->ls_count++;
++ goto out;
++ }
++ }
++ ls = NULL;
++ out:
++ spin_unlock(&lslist_lock);
++ return ls;
++}
++
++struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace)
++{
++ struct dlm_ls *ls;
++
++ spin_lock(&lslist_lock);
++ list_for_each_entry(ls, &lslist, ls_list) {
++ if (ls->ls_local_handle == lockspace) {
++ ls->ls_count++;
++ goto out;
++ }
++ }
++ ls = NULL;
++ out:
++ spin_unlock(&lslist_lock);
++ return ls;
++}
++
++struct dlm_ls *dlm_find_lockspace_device(int minor)
++{
++ struct dlm_ls *ls;
++
++ spin_lock(&lslist_lock);
++ list_for_each_entry(ls, &lslist, ls_list) {
++ if (ls->ls_device.minor == minor) {
++ ls->ls_count++;
++ goto out;
++ }
++ }
++ ls = NULL;
++ out:
++ spin_unlock(&lslist_lock);
++ return ls;
++}
++
++void dlm_put_lockspace(struct dlm_ls *ls)
++{
++ spin_lock(&lslist_lock);
++ ls->ls_count--;
++ spin_unlock(&lslist_lock);
++}
++
++static void remove_lockspace(struct dlm_ls *ls)
++{
++ for (;;) {
++ spin_lock(&lslist_lock);
++ if (ls->ls_count == 0) {
++ list_del(&ls->ls_list);
++ spin_unlock(&lslist_lock);
++ return;
++ }
++ spin_unlock(&lslist_lock);
++ ssleep(1);
++ }
++}
++
++static int threads_start(void)
++{
++ int error;
++
++ /* Thread which process lock requests for all lockspace's */
++ error = dlm_astd_start();
++ if (error) {
++ log_print("cannot start dlm_astd thread %d", error);
++ goto fail;
++ }
++
++ error = dlm_scand_start();
++ if (error) {
++ log_print("cannot start dlm_scand thread %d", error);
++ goto astd_fail;
++ }
++
++ /* Thread for sending/receiving messages for all lockspace's */
++ error = dlm_lowcomms_start();
++ if (error) {
++ log_print("cannot start dlm lowcomms %d", error);
++ goto scand_fail;
++ }
++
++ return 0;
++
++ scand_fail:
++ dlm_scand_stop();
++ astd_fail:
++ dlm_astd_stop();
++ fail:
++ return error;
++}
++
++static void threads_stop(void)
++{
++ dlm_scand_stop();
++ dlm_lowcomms_stop();
++ dlm_astd_stop();
++}
++
++static int new_lockspace(char *name, int namelen, void **lockspace,
++ uint32_t flags, int lvblen)
++{
++ struct dlm_ls *ls;
++ int i, size, error = -ENOMEM;
++
++ if (namelen > DLM_LOCKSPACE_LEN)
++ return -EINVAL;
++
++ if (!lvblen || (lvblen % 8))
++ return -EINVAL;
++
++ if (!try_module_get(THIS_MODULE))
++ return -EINVAL;
++
++ ls = dlm_find_lockspace_name(name, namelen);
++ if (ls) {
++ *lockspace = ls;
++ module_put(THIS_MODULE);
++ return -EEXIST;
++ }
++
++ ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);
++ if (!ls)
++ goto out;
++ memcpy(ls->ls_name, name, namelen);
++ ls->ls_namelen = namelen;
++ ls->ls_exflags = flags;
++ ls->ls_lvblen = lvblen;
++ ls->ls_count = 0;
++ ls->ls_flags = 0;
++
++ size = dlm_config.rsbtbl_size;
++ ls->ls_rsbtbl_size = size;
++
++ ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
++ if (!ls->ls_rsbtbl)
++ goto out_lsfree;
++ for (i = 0; i < size; i++) {
++ INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list);
++ INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss);
++ rwlock_init(&ls->ls_rsbtbl[i].lock);
++ }
++
++ size = dlm_config.lkbtbl_size;
++ ls->ls_lkbtbl_size = size;
++
++ ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
++ if (!ls->ls_lkbtbl)
++ goto out_rsbfree;
++ for (i = 0; i < size; i++) {
++ INIT_LIST_HEAD(&ls->ls_lkbtbl[i].list);
++ rwlock_init(&ls->ls_lkbtbl[i].lock);
++ ls->ls_lkbtbl[i].counter = 1;
++ }
++
++ size = dlm_config.dirtbl_size;
++ ls->ls_dirtbl_size = size;
++
++ ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
++ if (!ls->ls_dirtbl)
++ goto out_lkbfree;
++ for (i = 0; i < size; i++) {
++ INIT_LIST_HEAD(&ls->ls_dirtbl[i].list);
++ rwlock_init(&ls->ls_dirtbl[i].lock);
++ }
++
++ INIT_LIST_HEAD(&ls->ls_waiters);
++ mutex_init(&ls->ls_waiters_mutex);
++
++ INIT_LIST_HEAD(&ls->ls_nodes);
++ INIT_LIST_HEAD(&ls->ls_nodes_gone);
++ ls->ls_num_nodes = 0;
++ ls->ls_low_nodeid = 0;
++ ls->ls_total_weight = 0;
++ ls->ls_node_array = NULL;
++
++ memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb));
++ ls->ls_stub_rsb.res_ls = ls;
++
++ ls->ls_debug_rsb_dentry = NULL;
++ ls->ls_debug_waiters_dentry = NULL;
++
++ init_waitqueue_head(&ls->ls_uevent_wait);
++ ls->ls_uevent_result = 0;
++
++ ls->ls_recoverd_task = NULL;
++ mutex_init(&ls->ls_recoverd_active);
++ spin_lock_init(&ls->ls_recover_lock);
++ ls->ls_recover_status = 0;
++ ls->ls_recover_seq = 0;
++ ls->ls_recover_args = NULL;
++ init_rwsem(&ls->ls_in_recovery);
++ INIT_LIST_HEAD(&ls->ls_requestqueue);
++ mutex_init(&ls->ls_requestqueue_mutex);
++ mutex_init(&ls->ls_clear_proc_locks);
++
++ ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
++ if (!ls->ls_recover_buf)
++ goto out_dirfree;
++
++ INIT_LIST_HEAD(&ls->ls_recover_list);
++ spin_lock_init(&ls->ls_recover_list_lock);
++ ls->ls_recover_list_count = 0;
++ ls->ls_local_handle = ls;
++ init_waitqueue_head(&ls->ls_wait_general);
++ INIT_LIST_HEAD(&ls->ls_root_list);
++ init_rwsem(&ls->ls_root_sem);
++
++ down_write(&ls->ls_in_recovery);
++
++ spin_lock(&lslist_lock);
++ list_add(&ls->ls_list, &lslist);
++ spin_unlock(&lslist_lock);
++
++ /* needs to find ls in lslist */
++ error = dlm_recoverd_start(ls);
++ if (error) {
++ log_error(ls, "can't start dlm_recoverd %d", error);
++ goto out_rcomfree;
++ }
++
++ dlm_create_debug_file(ls);
++
++ error = kobject_setup(ls);
++ if (error)
++ goto out_del;
++
++ error = kobject_register(&ls->ls_kobj);
++ if (error)
++ goto out_del;
++
++ error = do_uevent(ls, 1);
++ if (error)
++ goto out_unreg;
++
++ *lockspace = ls;
++ return 0;
++
++ out_unreg:
++ kobject_unregister(&ls->ls_kobj);
++ out_del:
++ dlm_delete_debug_file(ls);
++ dlm_recoverd_stop(ls);
++ out_rcomfree:
++ spin_lock(&lslist_lock);
++ list_del(&ls->ls_list);
++ spin_unlock(&lslist_lock);
++ kfree(ls->ls_recover_buf);
++ out_dirfree:
++ kfree(ls->ls_dirtbl);
++ out_lkbfree:
++ kfree(ls->ls_lkbtbl);
++ out_rsbfree:
++ kfree(ls->ls_rsbtbl);
++ out_lsfree:
++ kfree(ls);
++ out:
++ module_put(THIS_MODULE);
++ return error;
++}
++
++int dlm_new_lockspace(char *name, int namelen, void **lockspace,
++ uint32_t flags, int lvblen)
++{
++ int error = 0;
++
++ mutex_lock(&ls_lock);
++ if (!ls_count)
++ error = threads_start();
++ if (error)
++ goto out;
++
++ error = new_lockspace(name, namelen, lockspace, flags, lvblen);
++ if (!error)
++ ls_count++;
++ out:
++ mutex_unlock(&ls_lock);
++ return error;
++}
++
++/* Return 1 if the lockspace still has active remote locks,
++ * 2 if the lockspace still has active local locks.
++ */
++static int lockspace_busy(struct dlm_ls *ls)
++{
++ int i, lkb_found = 0;
++ struct dlm_lkb *lkb;
++
++ /* NOTE: We check the lockidtbl here rather than the resource table.
++ This is because there may be LKBs queued as ASTs that have been
++ unlinked from their RSBs and are pending deletion once the AST has
++ been delivered */
++
++ for (i = 0; i < ls->ls_lkbtbl_size; i++) {
++ read_lock(&ls->ls_lkbtbl[i].lock);
++ if (!list_empty(&ls->ls_lkbtbl[i].list)) {
++ lkb_found = 1;
++ list_for_each_entry(lkb, &ls->ls_lkbtbl[i].list,
++ lkb_idtbl_list) {
++ if (!lkb->lkb_nodeid) {
++ read_unlock(&ls->ls_lkbtbl[i].lock);
++ return 2;
++ }
++ }
++ }
++ read_unlock(&ls->ls_lkbtbl[i].lock);
++ }
++ return lkb_found;
++}
++
++static int release_lockspace(struct dlm_ls *ls, int force)
++{
++ struct dlm_lkb *lkb;
++ struct dlm_rsb *rsb;
++ struct list_head *head;
++ int i;
++ int busy = lockspace_busy(ls);
++
++ if (busy > force)
++ return -EBUSY;
++
++ if (force < 3)
++ do_uevent(ls, 0);
++
++ dlm_recoverd_stop(ls);
++
++ remove_lockspace(ls);
++
++ dlm_delete_debug_file(ls);
++
++ dlm_astd_suspend();
++
++ kfree(ls->ls_recover_buf);
++
++ /*
++ * Free direntry structs.
++ */
++
++ dlm_dir_clear(ls);
++ kfree(ls->ls_dirtbl);
++
++ /*
++ * Free all lkb's on lkbtbl[] lists.
++ */
++
++ for (i = 0; i < ls->ls_lkbtbl_size; i++) {
++ head = &ls->ls_lkbtbl[i].list;
++ while (!list_empty(head)) {
++ lkb = list_entry(head->next, struct dlm_lkb,
++ lkb_idtbl_list);
++
++ list_del(&lkb->lkb_idtbl_list);
++
++ dlm_del_ast(lkb);
++
++ if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY)
++ free_lvb(lkb->lkb_lvbptr);
++
++ free_lkb(lkb);
++ }
++ }
++ dlm_astd_resume();
++
++ kfree(ls->ls_lkbtbl);
++
++ /*
++ * Free all rsb's on rsbtbl[] lists
++ */
++
++ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
++ head = &ls->ls_rsbtbl[i].list;
++ while (!list_empty(head)) {
++ rsb = list_entry(head->next, struct dlm_rsb,
++ res_hashchain);
++
++ list_del(&rsb->res_hashchain);
++ free_rsb(rsb);
++ }
++
++ head = &ls->ls_rsbtbl[i].toss;
++ while (!list_empty(head)) {
++ rsb = list_entry(head->next, struct dlm_rsb,
++ res_hashchain);
++ list_del(&rsb->res_hashchain);
++ free_rsb(rsb);
++ }
++ }
++
++ kfree(ls->ls_rsbtbl);
++
++ /*
++ * Free structures on any other lists
++ */
++
++ kfree(ls->ls_recover_args);
++ dlm_clear_free_entries(ls);
++ dlm_clear_members(ls);
++ dlm_clear_members_gone(ls);
++ kfree(ls->ls_node_array);
++ kobject_unregister(&ls->ls_kobj);
++ /* The ls structure will be freed when the kobject is done with */
++
++ mutex_lock(&ls_lock);
++ ls_count--;
++ if (!ls_count)
++ threads_stop();
++ mutex_unlock(&ls_lock);
++
++ module_put(THIS_MODULE);
++ return 0;
++}
++
++/*
++ * Called when a system has released all its locks and is not going to use the
++ * lockspace any longer. We free everything we're managing for this lockspace.
++ * Remaining nodes will go through the recovery process as if we'd died. The
++ * lockspace must continue to function as usual, participating in recoveries,
++ * until this returns.
++ *
++ * Force has 4 possible values:
++ * 0 - don't destroy locksapce if it has any LKBs
++ * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs
++ * 2 - destroy lockspace regardless of LKBs
++ * 3 - destroy lockspace as part of a forced shutdown
++ */
++
++int dlm_release_lockspace(void *lockspace, int force)
++{
++ struct dlm_ls *ls;
++
++ ls = dlm_find_lockspace_local(lockspace);
++ if (!ls)
++ return -EINVAL;
++ dlm_put_lockspace(ls);
++ return release_lockspace(ls, force);
++}
++
+diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h
+new file mode 100644
+index 0000000..891eabb
+--- /dev/null
++++ b/fs/dlm/lockspace.h
+@@ -0,0 +1,25 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __LOCKSPACE_DOT_H__
++#define __LOCKSPACE_DOT_H__
++
++int dlm_lockspace_init(void);
++void dlm_lockspace_exit(void);
++struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
++struct dlm_ls *dlm_find_lockspace_local(void *id);
++struct dlm_ls *dlm_find_lockspace_device(int minor);
++void dlm_put_lockspace(struct dlm_ls *ls);
++
++#endif /* __LOCKSPACE_DOT_H__ */
++
+diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
+new file mode 100644
+index 0000000..6da6b14
+--- /dev/null
++++ b/fs/dlm/lowcomms.c
+@@ -0,0 +1,1239 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++/*
++ * lowcomms.c
++ *
++ * This is the "low-level" comms layer.
++ *
++ * It is responsible for sending/receiving messages
++ * from other nodes in the cluster.
++ *
++ * Cluster nodes are referred to by their nodeids. nodeids are
++ * simply 32 bit numbers to the locking module - if they need to
++ * be expanded for the cluster infrastructure then that is it's
++ * responsibility. It is this layer's
++ * responsibility to resolve these into IP address or
++ * whatever it needs for inter-node communication.
++ *
++ * The comms level is two kernel threads that deal mainly with
++ * the receiving of messages from other nodes and passing them
++ * up to the mid-level comms layer (which understands the
++ * message format) for execution by the locking core, and
++ * a send thread which does all the setting up of connections
++ * to remote nodes and the sending of data. Threads are not allowed
++ * to send their own data because it may cause them to wait in times
++ * of high load. Also, this way, the sending thread can collect together
++ * messages bound for one node and send them in one block.
++ *
++ * I don't see any problem with the recv thread executing the locking
++ * code on behalf of remote processes as the locking code is
++ * short, efficient and never (well, hardly ever) waits.
++ *
++ */
++
++#include <asm/ioctls.h>
++#include <net/sock.h>
++#include <net/tcp.h>
++#include <net/sctp/user.h>
++#include <linux/pagemap.h>
++#include <linux/socket.h>
++#include <linux/idr.h>
++
++#include "dlm_internal.h"
++#include "lowcomms.h"
++#include "config.h"
++#include "midcomms.h"
++
++static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
++static int dlm_local_count;
++static int dlm_local_nodeid;
++
++/* One of these per connected node */
++
++#define NI_INIT_PENDING 1
++#define NI_WRITE_PENDING 2
++
++struct nodeinfo {
++ spinlock_t lock;
++ sctp_assoc_t assoc_id;
++ unsigned long flags;
++ struct list_head write_list; /* nodes with pending writes */
++ struct list_head writequeue; /* outgoing writequeue_entries */
++ spinlock_t writequeue_lock;
++ int nodeid;
++};
++
++static DEFINE_IDR(nodeinfo_idr);
++static struct rw_semaphore nodeinfo_lock;
++static int max_nodeid;
++
++struct cbuf {
++ unsigned base;
++ unsigned len;
++ unsigned mask;
++};
++
++/* Just the one of these, now. But this struct keeps
++ the connection-specific variables together */
++
++#define CF_READ_PENDING 1
++
++struct connection {
++ struct socket *sock;
++ unsigned long flags;
++ struct page *rx_page;
++ atomic_t waiting_requests;
++ struct cbuf cb;
++ int eagain_flag;
++};
++
++/* An entry waiting to be sent */
++
++struct writequeue_entry {
++ struct list_head list;
++ struct page *page;
++ int offset;
++ int len;
++ int end;
++ int users;
++ struct nodeinfo *ni;
++};
++
++#define CBUF_ADD(cb, n) do { (cb)->len += n; } while(0)
++#define CBUF_EMPTY(cb) ((cb)->len == 0)
++#define CBUF_MAY_ADD(cb, n) (((cb)->len + (n)) < ((cb)->mask + 1))
++#define CBUF_DATA(cb) (((cb)->base + (cb)->len) & (cb)->mask)
++
++#define CBUF_INIT(cb, size) \
++do { \
++ (cb)->base = (cb)->len = 0; \
++ (cb)->mask = ((size)-1); \
++} while(0)
++
++#define CBUF_EAT(cb, n) \
++do { \
++ (cb)->len -= (n); \
++ (cb)->base += (n); \
++ (cb)->base &= (cb)->mask; \
++} while(0)
++
++
++/* List of nodes which have writes pending */
++static struct list_head write_nodes;
++static spinlock_t write_nodes_lock;
++
++/* Maximum number of incoming messages to process before
++ * doing a schedule()
++ */
++#define MAX_RX_MSG_COUNT 25
++
++/* Manage daemons */
++static struct task_struct *recv_task;
++static struct task_struct *send_task;
++static wait_queue_head_t lowcomms_recv_wait;
++static atomic_t accepting;
++
++/* The SCTP connection */
++static struct connection sctp_con;
++
++
++static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
++{
++ struct sockaddr_storage addr;
++ int error;
++
++ if (!dlm_local_count)
++ return -1;
++
++ error = dlm_nodeid_to_addr(nodeid, &addr);
++ if (error)
++ return error;
++
++ if (dlm_local_addr[0]->ss_family == AF_INET) {
++ struct sockaddr_in *in4 = (struct sockaddr_in *) &addr;
++ struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
++ ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
++ } else {
++ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr;
++ struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
++ memcpy(&ret6->sin6_addr, &in6->sin6_addr,
++ sizeof(in6->sin6_addr));
++ }
++
++ return 0;
++}
++
++static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc)
++{
++ struct nodeinfo *ni;
++ int r;
++ int n;
++
++ down_read(&nodeinfo_lock);
++ ni = idr_find(&nodeinfo_idr, nodeid);
++ up_read(&nodeinfo_lock);
++
++ if (!ni && alloc) {
++ down_write(&nodeinfo_lock);
++
++ ni = idr_find(&nodeinfo_idr, nodeid);
++ if (ni)
++ goto out_up;
++
++ r = idr_pre_get(&nodeinfo_idr, alloc);
++ if (!r)
++ goto out_up;
++
++ ni = kmalloc(sizeof(struct nodeinfo), alloc);
++ if (!ni)
++ goto out_up;
++
++ r = idr_get_new_above(&nodeinfo_idr, ni, nodeid, &n);
++ if (r) {
++ kfree(ni);
++ ni = NULL;
++ goto out_up;
++ }
++ if (n != nodeid) {
++ idr_remove(&nodeinfo_idr, n);
++ kfree(ni);
++ ni = NULL;
++ goto out_up;
++ }
++ memset(ni, 0, sizeof(struct nodeinfo));
++ spin_lock_init(&ni->lock);
++ INIT_LIST_HEAD(&ni->writequeue);
++ spin_lock_init(&ni->writequeue_lock);
++ ni->nodeid = nodeid;
++
++ if (nodeid > max_nodeid)
++ max_nodeid = nodeid;
++ out_up:
++ up_write(&nodeinfo_lock);
++ }
++
++ return ni;
++}
++
++/* Don't call this too often... */
++static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
++{
++ int i;
++ struct nodeinfo *ni;
++
++ for (i=1; i<=max_nodeid; i++) {
++ ni = nodeid2nodeinfo(i, 0);
++ if (ni && ni->assoc_id == assoc)
++ return ni;
++ }
++ return NULL;
++}
++
++/* Data or notification available on socket */
++static void lowcomms_data_ready(struct sock *sk, int count_unused)
++{
++ atomic_inc(&sctp_con.waiting_requests);
++ if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
++ return;
++
++ wake_up_interruptible(&lowcomms_recv_wait);
++}
++
++
++/* Add the port number to an IP6 or 4 sockaddr and return the address length.
++ Also padd out the struct with zeros to make comparisons meaningful */
++
++static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
++ int *addr_len)
++{
++ struct sockaddr_in *local4_addr;
++ struct sockaddr_in6 *local6_addr;
++
++ if (!dlm_local_count)
++ return;
++
++ if (!port) {
++ if (dlm_local_addr[0]->ss_family == AF_INET) {
++ local4_addr = (struct sockaddr_in *)dlm_local_addr[0];
++ port = be16_to_cpu(local4_addr->sin_port);
++ } else {
++ local6_addr = (struct sockaddr_in6 *)dlm_local_addr[0];
++ port = be16_to_cpu(local6_addr->sin6_port);
++ }
++ }
++
++ saddr->ss_family = dlm_local_addr[0]->ss_family;
++ if (dlm_local_addr[0]->ss_family == AF_INET) {
++ struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
++ in4_addr->sin_port = cpu_to_be16(port);
++ memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
++ memset(in4_addr+1, 0, sizeof(struct sockaddr_storage) -
++ sizeof(struct sockaddr_in));
++ *addr_len = sizeof(struct sockaddr_in);
++ } else {
++ struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
++ in6_addr->sin6_port = cpu_to_be16(port);
++ memset(in6_addr+1, 0, sizeof(struct sockaddr_storage) -
++ sizeof(struct sockaddr_in6));
++ *addr_len = sizeof(struct sockaddr_in6);
++ }
++}
++
++/* Close the connection and tidy up */
++static void close_connection(void)
++{
++ if (sctp_con.sock) {
++ sock_release(sctp_con.sock);
++ sctp_con.sock = NULL;
++ }
++
++ if (sctp_con.rx_page) {
++ __free_page(sctp_con.rx_page);
++ sctp_con.rx_page = NULL;
++ }
++}
++
++/* We only send shutdown messages to nodes that are not part of the cluster */
++static void send_shutdown(sctp_assoc_t associd)
++{
++ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
++ struct msghdr outmessage;
++ struct cmsghdr *cmsg;
++ struct sctp_sndrcvinfo *sinfo;
++ int ret;
++
++ outmessage.msg_name = NULL;
++ outmessage.msg_namelen = 0;
++ outmessage.msg_control = outcmsg;
++ outmessage.msg_controllen = sizeof(outcmsg);
++ outmessage.msg_flags = MSG_EOR;
++
++ cmsg = CMSG_FIRSTHDR(&outmessage);
++ cmsg->cmsg_level = IPPROTO_SCTP;
++ cmsg->cmsg_type = SCTP_SNDRCV;
++ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
++ outmessage.msg_controllen = cmsg->cmsg_len;
++ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
++ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
++
++ sinfo->sinfo_flags |= MSG_EOF;
++ sinfo->sinfo_assoc_id = associd;
++
++ ret = kernel_sendmsg(sctp_con.sock, &outmessage, NULL, 0, 0);
++
++ if (ret != 0)
++ log_print("send EOF to node failed: %d", ret);
++}
++
++
++/* INIT failed but we don't know which node...
++ restart INIT on all pending nodes */
++static void init_failed(void)
++{
++ int i;
++ struct nodeinfo *ni;
++
++ for (i=1; i<=max_nodeid; i++) {
++ ni = nodeid2nodeinfo(i, 0);
++ if (!ni)
++ continue;
++
++ if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
++ ni->assoc_id = 0;
++ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
++ spin_lock_bh(&write_nodes_lock);
++ list_add_tail(&ni->write_list, &write_nodes);
++ spin_unlock_bh(&write_nodes_lock);
++ }
++ }
++ }
++ wake_up_process(send_task);
++}
++
++/* Something happened to an association */
++static void process_sctp_notification(struct msghdr *msg, char *buf)
++{
++ union sctp_notification *sn = (union sctp_notification *)buf;
++
++ if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
++ switch (sn->sn_assoc_change.sac_state) {
++
++ case SCTP_COMM_UP:
++ case SCTP_RESTART:
++ {
++ /* Check that the new node is in the lockspace */
++ struct sctp_prim prim;
++ mm_segment_t fs;
++ int nodeid;
++ int prim_len, ret;
++ int addr_len;
++ struct nodeinfo *ni;
++
++ /* This seems to happen when we received a connection
++ * too early... or something... anyway, it happens but
++ * we always seem to get a real message too, see
++ * receive_from_sock */
++
++ if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {
++ log_print("COMM_UP for invalid assoc ID %d",
++ (int)sn->sn_assoc_change.sac_assoc_id);
++ init_failed();
++ return;
++ }
++ memset(&prim, 0, sizeof(struct sctp_prim));
++ prim_len = sizeof(struct sctp_prim);
++ prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;
++
++ fs = get_fs();
++ set_fs(get_ds());
++ ret = sctp_con.sock->ops->getsockopt(sctp_con.sock,
++ IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
++ (char*)&prim, &prim_len);
++ set_fs(fs);
++ if (ret < 0) {
++ struct nodeinfo *ni;
++
++ log_print("getsockopt/sctp_primary_addr on "
++ "new assoc %d failed : %d",
++ (int)sn->sn_assoc_change.sac_assoc_id, ret);
++
++ /* Retry INIT later */
++ ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
++ if (ni)
++ clear_bit(NI_INIT_PENDING, &ni->flags);
++ return;
++ }
++ make_sockaddr(&prim.ssp_addr, 0, &addr_len);
++ if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
++ log_print("reject connect from unknown addr");
++ send_shutdown(prim.ssp_assoc_id);
++ return;
++ }
++
++ ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
++ if (!ni)
++ return;
++
++ /* Save the assoc ID */
++ spin_lock(&ni->lock);
++ ni->assoc_id = sn->sn_assoc_change.sac_assoc_id;
++ spin_unlock(&ni->lock);
++
++ log_print("got new/restarted association %d nodeid %d",
++ (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
++
++ /* Send any pending writes */
++ clear_bit(NI_INIT_PENDING, &ni->flags);
++ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
++ spin_lock_bh(&write_nodes_lock);
++ list_add_tail(&ni->write_list, &write_nodes);
++ spin_unlock_bh(&write_nodes_lock);
++ }
++ wake_up_process(send_task);
++ }
++ break;
++
++ case SCTP_COMM_LOST:
++ case SCTP_SHUTDOWN_COMP:
++ {
++ struct nodeinfo *ni;
++
++ ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
++ if (ni) {
++ spin_lock(&ni->lock);
++ ni->assoc_id = 0;
++ spin_unlock(&ni->lock);
++ }
++ }
++ break;
++
++ /* We don't know which INIT failed, so clear the PENDING flags
++ * on them all. if assoc_id is zero then it will then try
++ * again */
++
++ case SCTP_CANT_STR_ASSOC:
++ {
++ log_print("Can't start SCTP association - retrying");
++ init_failed();
++ }
++ break;
++
++ default:
++ log_print("unexpected SCTP assoc change id=%d state=%d",
++ (int)sn->sn_assoc_change.sac_assoc_id,
++ sn->sn_assoc_change.sac_state);
++ }
++ }
++}
++
++/* Data received from remote end */
++static int receive_from_sock(void)
++{
++ int ret = 0;
++ struct msghdr msg;
++ struct kvec iov[2];
++ unsigned len;
++ int r;
++ struct sctp_sndrcvinfo *sinfo;
++ struct cmsghdr *cmsg;
++ struct nodeinfo *ni;
++
++ /* These two are marginally too big for stack allocation, but this
++ * function is (currently) only called by dlm_recvd so static should be
++ * OK.
++ */
++ static struct sockaddr_storage msgname;
++ static char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
++
++ if (sctp_con.sock == NULL)
++ goto out;
++
++ if (sctp_con.rx_page == NULL) {
++ /*
++ * This doesn't need to be atomic, but I think it should
++ * improve performance if it is.
++ */
++ sctp_con.rx_page = alloc_page(GFP_ATOMIC);
++ if (sctp_con.rx_page == NULL)
++ goto out_resched;
++ CBUF_INIT(&sctp_con.cb, PAGE_CACHE_SIZE);
++ }
++
++ memset(&incmsg, 0, sizeof(incmsg));
++ memset(&msgname, 0, sizeof(msgname));
++
++ memset(incmsg, 0, sizeof(incmsg));
++ msg.msg_name = &msgname;
++ msg.msg_namelen = sizeof(msgname);
++ msg.msg_flags = 0;
++ msg.msg_control = incmsg;
++ msg.msg_controllen = sizeof(incmsg);
++ msg.msg_iovlen = 1;
++
++ /* I don't see why this circular buffer stuff is necessary for SCTP
++ * which is a packet-based protocol, but the whole thing breaks under
++ * load without it! The overhead is minimal (and is in the TCP lowcomms
++ * anyway, of course) so I'll leave it in until I can figure out what's
++ * really happening.
++ */
++
++ /*
++ * iov[0] is the bit of the circular buffer between the current end
++ * point (cb.base + cb.len) and the end of the buffer.
++ */
++ iov[0].iov_len = sctp_con.cb.base - CBUF_DATA(&sctp_con.cb);
++ iov[0].iov_base = page_address(sctp_con.rx_page) +
++ CBUF_DATA(&sctp_con.cb);
++ iov[1].iov_len = 0;
++
++ /*
++ * iov[1] is the bit of the circular buffer between the start of the
++ * buffer and the start of the currently used section (cb.base)
++ */
++ if (CBUF_DATA(&sctp_con.cb) >= sctp_con.cb.base) {
++ iov[0].iov_len = PAGE_CACHE_SIZE - CBUF_DATA(&sctp_con.cb);
++ iov[1].iov_len = sctp_con.cb.base;
++ iov[1].iov_base = page_address(sctp_con.rx_page);
++ msg.msg_iovlen = 2;
++ }
++ len = iov[0].iov_len + iov[1].iov_len;
++
++ r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, msg.msg_iovlen, len,
++ MSG_NOSIGNAL | MSG_DONTWAIT);
++ if (ret <= 0)
++ goto out_close;
++
++ msg.msg_control = incmsg;
++ msg.msg_controllen = sizeof(incmsg);
++ cmsg = CMSG_FIRSTHDR(&msg);
++ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
++
++ if (msg.msg_flags & MSG_NOTIFICATION) {
++ process_sctp_notification(&msg, page_address(sctp_con.rx_page));
++ return 0;
++ }
++
++ /* Is this a new association ? */
++ ni = nodeid2nodeinfo(le32_to_cpu(sinfo->sinfo_ppid), GFP_KERNEL);
++ if (ni) {
++ ni->assoc_id = sinfo->sinfo_assoc_id;
++ if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
++
++ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
++ spin_lock_bh(&write_nodes_lock);
++ list_add_tail(&ni->write_list, &write_nodes);
++ spin_unlock_bh(&write_nodes_lock);
++ }
++ wake_up_process(send_task);
++ }
++ }
++
++ /* INIT sends a message with length of 1 - ignore it */
++ if (r == 1)
++ return 0;
++
++ CBUF_ADD(&sctp_con.cb, ret);
++ ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
++ page_address(sctp_con.rx_page),
++ sctp_con.cb.base, sctp_con.cb.len,
++ PAGE_CACHE_SIZE);
++ if (ret < 0)
++ goto out_close;
++ CBUF_EAT(&sctp_con.cb, ret);
++
++ out:
++ ret = 0;
++ goto out_ret;
++
++ out_resched:
++ lowcomms_data_ready(sctp_con.sock->sk, 0);
++ ret = 0;
++ schedule();
++ goto out_ret;
++
++ out_close:
++ if (ret != -EAGAIN)
++ log_print("error reading from sctp socket: %d", ret);
++ out_ret:
++ return ret;
++}
++
++/* Bind to an IP address. SCTP allows multiple address so it can do multi-homing */
++static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
++{
++ mm_segment_t fs;
++ int result = 0;
++
++ fs = get_fs();
++ set_fs(get_ds());
++ if (num == 1)
++ result = sctp_con.sock->ops->bind(sctp_con.sock,
++ (struct sockaddr *) addr, addr_len);
++ else
++ result = sctp_con.sock->ops->setsockopt(sctp_con.sock, SOL_SCTP,
++ SCTP_SOCKOPT_BINDX_ADD, (char *)addr, addr_len);
++ set_fs(fs);
++
++ if (result < 0)
++ log_print("Can't bind to port %d addr number %d",
++ dlm_config.tcp_port, num);
++
++ return result;
++}
++
++static void init_local(void)
++{
++ struct sockaddr_storage sas, *addr;
++ int i;
++
++ dlm_local_nodeid = dlm_our_nodeid();
++
++ for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
++ if (dlm_our_addr(&sas, i))
++ break;
++
++ addr = kmalloc(sizeof(*addr), GFP_KERNEL);
++ if (!addr)
++ break;
++ memcpy(addr, &sas, sizeof(*addr));
++ dlm_local_addr[dlm_local_count++] = addr;
++ }
++}
++
++/* Initialise SCTP socket and bind to all interfaces */
++static int init_sock(void)
++{
++ mm_segment_t fs;
++ struct socket *sock = NULL;
++ struct sockaddr_storage localaddr;
++ struct sctp_event_subscribe subscribe;
++ int result = -EINVAL, num = 1, i, addr_len;
++
++ if (!dlm_local_count) {
++ init_local();
++ if (!dlm_local_count) {
++ log_print("no local IP address has been set");
++ goto out;
++ }
++ }
++
++ result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET,
++ IPPROTO_SCTP, &sock);
++ if (result < 0) {
++ log_print("Can't create comms socket, check SCTP is loaded");
++ goto out;
++ }
++
++ /* Listen for events */
++ memset(&subscribe, 0, sizeof(subscribe));
++ subscribe.sctp_data_io_event = 1;
++ subscribe.sctp_association_event = 1;
++ subscribe.sctp_send_failure_event = 1;
++ subscribe.sctp_shutdown_event = 1;
++ subscribe.sctp_partial_delivery_event = 1;
++
++ fs = get_fs();
++ set_fs(get_ds());
++ result = sock->ops->setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
++ (char *)&subscribe, sizeof(subscribe));
++ set_fs(fs);
++
++ if (result < 0) {
++ log_print("Failed to set SCTP_EVENTS on socket: result=%d",
++ result);
++ goto create_delsock;
++ }
++
++ /* Init con struct */
++ sock->sk->sk_user_data = &sctp_con;
++ sctp_con.sock = sock;
++ sctp_con.sock->sk->sk_data_ready = lowcomms_data_ready;
++
++ /* Bind to all interfaces. */
++ for (i = 0; i < dlm_local_count; i++) {
++ memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
++ make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len);
++
++ result = add_bind_addr(&localaddr, addr_len, num);
++ if (result)
++ goto create_delsock;
++ ++num;
++ }
++
++ result = sock->ops->listen(sock, 5);
++ if (result < 0) {
++ log_print("Can't set socket listening");
++ goto create_delsock;
++ }
++
++ return 0;
++
++ create_delsock:
++ sock_release(sock);
++ sctp_con.sock = NULL;
++ out:
++ return result;
++}
++
++
++static struct writequeue_entry *new_writequeue_entry(gfp_t allocation)
++{
++ struct writequeue_entry *entry;
++
++ entry = kmalloc(sizeof(struct writequeue_entry), allocation);
++ if (!entry)
++ return NULL;
++
++ entry->page = alloc_page(allocation);
++ if (!entry->page) {
++ kfree(entry);
++ return NULL;
++ }
++
++ entry->offset = 0;
++ entry->len = 0;
++ entry->end = 0;
++ entry->users = 0;
++
++ return entry;
++}
++
++void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
++{
++ struct writequeue_entry *e;
++ int offset = 0;
++ int users = 0;
++ struct nodeinfo *ni;
++
++ if (!atomic_read(&accepting))
++ return NULL;
++
++ ni = nodeid2nodeinfo(nodeid, allocation);
++ if (!ni)
++ return NULL;
++
++ spin_lock(&ni->writequeue_lock);
++ e = list_entry(ni->writequeue.prev, struct writequeue_entry, list);
++ if (((struct list_head *) e == &ni->writequeue) ||
++ (PAGE_CACHE_SIZE - e->end < len)) {
++ e = NULL;
++ } else {
++ offset = e->end;
++ e->end += len;
++ users = e->users++;
++ }
++ spin_unlock(&ni->writequeue_lock);
++
++ if (e) {
++ got_one:
++ if (users == 0)
++ kmap(e->page);
++ *ppc = page_address(e->page) + offset;
++ return e;
++ }
++
++ e = new_writequeue_entry(allocation);
++ if (e) {
++ spin_lock(&ni->writequeue_lock);
++ offset = e->end;
++ e->end += len;
++ e->ni = ni;
++ users = e->users++;
++ list_add_tail(&e->list, &ni->writequeue);
++ spin_unlock(&ni->writequeue_lock);
++ goto got_one;
++ }
++ return NULL;
++}
++
++void dlm_lowcomms_commit_buffer(void *arg)
++{
++ struct writequeue_entry *e = (struct writequeue_entry *) arg;
++ int users;
++ struct nodeinfo *ni = e->ni;
++
++ if (!atomic_read(&accepting))
++ return;
++
++ spin_lock(&ni->writequeue_lock);
++ users = --e->users;
++ if (users)
++ goto out;
++ e->len = e->end - e->offset;
++ kunmap(e->page);
++ spin_unlock(&ni->writequeue_lock);
++
++ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
++ spin_lock_bh(&write_nodes_lock);
++ list_add_tail(&ni->write_list, &write_nodes);
++ spin_unlock_bh(&write_nodes_lock);
++ wake_up_process(send_task);
++ }
++ return;
++
++ out:
++ spin_unlock(&ni->writequeue_lock);
++ return;
++}
++
++static void free_entry(struct writequeue_entry *e)
++{
++ __free_page(e->page);
++ kfree(e);
++}
++
++/* Initiate an SCTP association. In theory we could just use sendmsg() on
++ the first IP address and it should work, but this allows us to set up the
++ association before sending any valuable data that we can't afford to lose.
++ It also keeps the send path clean as it can now always use the association ID */
++static void initiate_association(int nodeid)
++{
++ struct sockaddr_storage rem_addr;
++ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
++ struct msghdr outmessage;
++ struct cmsghdr *cmsg;
++ struct sctp_sndrcvinfo *sinfo;
++ int ret;
++ int addrlen;
++ char buf[1];
++ struct kvec iov[1];
++ struct nodeinfo *ni;
++
++ log_print("Initiating association with node %d", nodeid);
++
++ ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
++ if (!ni)
++ return;
++
++ if (nodeid_to_addr(nodeid, (struct sockaddr *)&rem_addr)) {
++ log_print("no address for nodeid %d", nodeid);
++ return;
++ }
++
++ make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
++
++ outmessage.msg_name = &rem_addr;
++ outmessage.msg_namelen = addrlen;
++ outmessage.msg_control = outcmsg;
++ outmessage.msg_controllen = sizeof(outcmsg);
++ outmessage.msg_flags = MSG_EOR;
++
++ iov[0].iov_base = buf;
++ iov[0].iov_len = 1;
++
++ /* Real INIT messages seem to cause trouble. Just send a 1 byte message
++ we can afford to lose */
++ cmsg = CMSG_FIRSTHDR(&outmessage);
++ cmsg->cmsg_level = IPPROTO_SCTP;
++ cmsg->cmsg_type = SCTP_SNDRCV;
++ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
++ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
++ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
++ sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
++
++ outmessage.msg_controllen = cmsg->cmsg_len;
++ ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1);
++ if (ret < 0) {
++ log_print("send INIT to node failed: %d", ret);
++ /* Try again later */
++ clear_bit(NI_INIT_PENDING, &ni->flags);
++ }
++}
++
++/* Send a message */
++static int send_to_sock(struct nodeinfo *ni)
++{
++ int ret = 0;
++ struct writequeue_entry *e;
++ int len, offset;
++ struct msghdr outmsg;
++ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
++ struct cmsghdr *cmsg;
++ struct sctp_sndrcvinfo *sinfo;
++ struct kvec iov;
++
++ /* See if we need to init an association before we start
++ sending precious messages */
++ spin_lock(&ni->lock);
++ if (!ni->assoc_id && !test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
++ spin_unlock(&ni->lock);
++ initiate_association(ni->nodeid);
++ return 0;
++ }
++ spin_unlock(&ni->lock);
++
++ outmsg.msg_name = NULL; /* We use assoc_id */
++ outmsg.msg_namelen = 0;
++ outmsg.msg_control = outcmsg;
++ outmsg.msg_controllen = sizeof(outcmsg);
++ outmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | MSG_EOR;
++
++ cmsg = CMSG_FIRSTHDR(&outmsg);
++ cmsg->cmsg_level = IPPROTO_SCTP;
++ cmsg->cmsg_type = SCTP_SNDRCV;
++ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
++ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
++ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
++ sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
++ sinfo->sinfo_assoc_id = ni->assoc_id;
++ outmsg.msg_controllen = cmsg->cmsg_len;
++
++ spin_lock(&ni->writequeue_lock);
++ for (;;) {
++ if (list_empty(&ni->writequeue))
++ break;
++ e = list_entry(ni->writequeue.next, struct writequeue_entry,
++ list);
++ len = e->len;
++ offset = e->offset;
++ BUG_ON(len == 0 && e->users == 0);
++ spin_unlock(&ni->writequeue_lock);
++ kmap(e->page);
++
++ ret = 0;
++ if (len) {
++ iov.iov_base = page_address(e->page)+offset;
++ iov.iov_len = len;
++
++ ret = kernel_sendmsg(sctp_con.sock, &outmsg, &iov, 1,
++ len);
++ if (ret == -EAGAIN) {
++ sctp_con.eagain_flag = 1;
++ goto out;
++ } else if (ret < 0)
++ goto send_error;
++ } else {
++ /* Don't starve people filling buffers */
++ schedule();
++ }
++
++ spin_lock(&ni->writequeue_lock);
++ e->offset += ret;
++ e->len -= ret;
++
++ if (e->len == 0 && e->users == 0) {
++ list_del(&e->list);
++ free_entry(e);
++ continue;
++ }
++ }
++ spin_unlock(&ni->writequeue_lock);
++ out:
++ return ret;
++
++ send_error:
++ log_print("Error sending to node %d %d", ni->nodeid, ret);
++ spin_lock(&ni->lock);
++ if (!test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
++ ni->assoc_id = 0;
++ spin_unlock(&ni->lock);
++ initiate_association(ni->nodeid);
++ } else
++ spin_unlock(&ni->lock);
++
++ return ret;
++}
++
++/* Try to send any messages that are pending */
++static void process_output_queue(void)
++{
++ struct list_head *list;
++ struct list_head *temp;
++
++ spin_lock_bh(&write_nodes_lock);
++ list_for_each_safe(list, temp, &write_nodes) {
++ struct nodeinfo *ni =
++ list_entry(list, struct nodeinfo, write_list);
++ clear_bit(NI_WRITE_PENDING, &ni->flags);
++ list_del(&ni->write_list);
++
++ spin_unlock_bh(&write_nodes_lock);
++
++ send_to_sock(ni);
++ spin_lock_bh(&write_nodes_lock);
++ }
++ spin_unlock_bh(&write_nodes_lock);
++}
++
++/* Called after we've had -EAGAIN and been woken up */
++static void refill_write_queue(void)
++{
++ int i;
++
++ for (i=1; i<=max_nodeid; i++) {
++ struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
++
++ if (ni) {
++ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
++ spin_lock_bh(&write_nodes_lock);
++ list_add_tail(&ni->write_list, &write_nodes);
++ spin_unlock_bh(&write_nodes_lock);
++ }
++ }
++ }
++}
++
++static void clean_one_writequeue(struct nodeinfo *ni)
++{
++ struct list_head *list;
++ struct list_head *temp;
++
++ spin_lock(&ni->writequeue_lock);
++ list_for_each_safe(list, temp, &ni->writequeue) {
++ struct writequeue_entry *e =
++ list_entry(list, struct writequeue_entry, list);
++ list_del(&e->list);
++ free_entry(e);
++ }
++ spin_unlock(&ni->writequeue_lock);
++}
++
++static void clean_writequeues(void)
++{
++ int i;
++
++ for (i=1; i<=max_nodeid; i++) {
++ struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
++ if (ni)
++ clean_one_writequeue(ni);
++ }
++}
++
++
++static void dealloc_nodeinfo(void)
++{
++ int i;
++
++ for (i=1; i<=max_nodeid; i++) {
++ struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
++ if (ni) {
++ idr_remove(&nodeinfo_idr, i);
++ kfree(ni);
++ }
++ }
++}
++
++int dlm_lowcomms_close(int nodeid)
++{
++ struct nodeinfo *ni;
++
++ ni = nodeid2nodeinfo(nodeid, 0);
++ if (!ni)
++ return -1;
++
++ spin_lock(&ni->lock);
++ if (ni->assoc_id) {
++ ni->assoc_id = 0;
++ /* Don't send shutdown here, sctp will just queue it
++ till the node comes back up! */
++ }
++ spin_unlock(&ni->lock);
++
++ clean_one_writequeue(ni);
++ clear_bit(NI_INIT_PENDING, &ni->flags);
++ return 0;
++}
++
++static int write_list_empty(void)
++{
++ int status;
++
++ spin_lock_bh(&write_nodes_lock);
++ status = list_empty(&write_nodes);
++ spin_unlock_bh(&write_nodes_lock);
++
++ return status;
++}
++
++static int dlm_recvd(void *data)
++{
++ DECLARE_WAITQUEUE(wait, current);
++
++ while (!kthread_should_stop()) {
++ int count = 0;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&lowcomms_recv_wait, &wait);
++ if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
++ schedule();
++ remove_wait_queue(&lowcomms_recv_wait, &wait);
++ set_current_state(TASK_RUNNING);
++
++ if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
++ int ret;
++
++ do {
++ ret = receive_from_sock();
++
++ /* Don't starve out everyone else */
++ if (++count >= MAX_RX_MSG_COUNT) {
++ schedule();
++ count = 0;
++ }
++ } while (!kthread_should_stop() && ret >=0);
++ }
++ schedule();
++ }
++
++ return 0;
++}
++
++static int dlm_sendd(void *data)
++{
++ DECLARE_WAITQUEUE(wait, current);
++
++ add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
++
++ while (!kthread_should_stop()) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (write_list_empty())
++ schedule();
++ set_current_state(TASK_RUNNING);
++
++ if (sctp_con.eagain_flag) {
++ sctp_con.eagain_flag = 0;
++ refill_write_queue();
++ }
++ process_output_queue();
++ }
++
++ remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
++
++ return 0;
++}
++
++static void daemons_stop(void)
++{
++ kthread_stop(recv_task);
++ kthread_stop(send_task);
++}
++
++static int daemons_start(void)
++{
++ struct task_struct *p;
++ int error;
++
++ p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
++ error = IS_ERR(p);
++ if (error) {
++ log_print("can't start dlm_recvd %d", error);
++ return error;
++ }
++ recv_task = p;
++
++ p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
++ error = IS_ERR(p);
++ if (error) {
++ log_print("can't start dlm_sendd %d", error);
++ kthread_stop(recv_task);
++ return error;
++ }
++ send_task = p;
++
++ return 0;
++}
++
++/*
++ * This is quite likely to sleep...
++ */
++int dlm_lowcomms_start(void)
++{
++ int error;
++
++ error = init_sock();
++ if (error)
++ goto fail_sock;
++ error = daemons_start();
++ if (error)
++ goto fail_sock;
++ atomic_set(&accepting, 1);
++ return 0;
++
++ fail_sock:
++ close_connection();
++ return error;
++}
++
++/* Set all the activity flags to prevent any socket activity. */
++
++void dlm_lowcomms_stop(void)
++{
++ atomic_set(&accepting, 0);
++ sctp_con.flags = 0x7;
++ daemons_stop();
++ clean_writequeues();
++ close_connection();
++ dealloc_nodeinfo();
++ max_nodeid = 0;
++}
++
++int dlm_lowcomms_init(void)
++{
++ init_waitqueue_head(&lowcomms_recv_wait);
++ spin_lock_init(&write_nodes_lock);
++ INIT_LIST_HEAD(&write_nodes);
++ init_rwsem(&nodeinfo_lock);
++ return 0;
++}
++
++void dlm_lowcomms_exit(void)
++{
++ int i;
++
++ for (i = 0; i < dlm_local_count; i++)
++ kfree(dlm_local_addr[i]);
++ dlm_local_count = 0;
++ dlm_local_nodeid = 0;
++}
++
+diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h
+new file mode 100644
+index 0000000..2d045e0
+--- /dev/null
++++ b/fs/dlm/lowcomms.h
+@@ -0,0 +1,26 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __LOWCOMMS_DOT_H__
++#define __LOWCOMMS_DOT_H__
++
++int dlm_lowcomms_init(void);
++void dlm_lowcomms_exit(void);
++int dlm_lowcomms_start(void);
++void dlm_lowcomms_stop(void);
++int dlm_lowcomms_close(int nodeid);
++void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);
++void dlm_lowcomms_commit_buffer(void *mh);
++
++#endif /* __LOWCOMMS_DOT_H__ */
++
+diff --git a/fs/dlm/lvb_table.h b/fs/dlm/lvb_table.h
+new file mode 100644
+index 0000000..cc3e92f
+--- /dev/null
++++ b/fs/dlm/lvb_table.h
+@@ -0,0 +1,18 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __LVB_TABLE_DOT_H__
++#define __LVB_TABLE_DOT_H__
++
++extern const int dlm_lvb_operations[8][8];
++
++#endif
+diff --git a/fs/dlm/main.c b/fs/dlm/main.c
+new file mode 100644
+index 0000000..a8da8dc
+--- /dev/null
++++ b/fs/dlm/main.c
+@@ -0,0 +1,97 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "lock.h"
++#include "user.h"
++#include "memory.h"
++#include "lowcomms.h"
++#include "config.h"
++
++#ifdef CONFIG_DLM_DEBUG
++int dlm_register_debugfs(void);
++void dlm_unregister_debugfs(void);
++#else
++static inline int dlm_register_debugfs(void) { return 0; }
++static inline void dlm_unregister_debugfs(void) { }
++#endif
++
++static int __init init_dlm(void)
++{
++ int error;
++
++ error = dlm_memory_init();
++ if (error)
++ goto out;
++
++ error = dlm_lockspace_init();
++ if (error)
++ goto out_mem;
++
++ error = dlm_config_init();
++ if (error)
++ goto out_lockspace;
++
++ error = dlm_register_debugfs();
++ if (error)
++ goto out_config;
++
++ error = dlm_lowcomms_init();
++ if (error)
++ goto out_debug;
++
++ error = dlm_user_init();
++ if (error)
++ goto out_lowcomms;
++
++ printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
++
++ return 0;
++
++ out_lowcomms:
++ dlm_lowcomms_exit();
++ out_debug:
++ dlm_unregister_debugfs();
++ out_config:
++ dlm_config_exit();
++ out_lockspace:
++ dlm_lockspace_exit();
++ out_mem:
++ dlm_memory_exit();
++ out:
++ return error;
++}
++
++static void __exit exit_dlm(void)
++{
++ dlm_user_exit();
++ dlm_lowcomms_exit();
++ dlm_config_exit();
++ dlm_memory_exit();
++ dlm_lockspace_exit();
++ dlm_unregister_debugfs();
++}
++
++module_init(init_dlm);
++module_exit(exit_dlm);
++
++MODULE_DESCRIPTION("Distributed Lock Manager");
++MODULE_AUTHOR("Red Hat, Inc.");
++MODULE_LICENSE("GPL");
++
++EXPORT_SYMBOL_GPL(dlm_new_lockspace);
++EXPORT_SYMBOL_GPL(dlm_release_lockspace);
++EXPORT_SYMBOL_GPL(dlm_lock);
++EXPORT_SYMBOL_GPL(dlm_unlock);
++
+diff --git a/fs/dlm/member.c b/fs/dlm/member.c
+new file mode 100644
+index 0000000..a3f7de7
+--- /dev/null
++++ b/fs/dlm/member.c
+@@ -0,0 +1,327 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "member.h"
++#include "recoverd.h"
++#include "recover.h"
++#include "rcom.h"
++#include "config.h"
++
++/*
++ * Following called by dlm_recoverd thread
++ */
++
++static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
++{
++ struct dlm_member *memb = NULL;
++ struct list_head *tmp;
++ struct list_head *newlist = &new->list;
++ struct list_head *head = &ls->ls_nodes;
++
++ list_for_each(tmp, head) {
++ memb = list_entry(tmp, struct dlm_member, list);
++ if (new->nodeid < memb->nodeid)
++ break;
++ }
++
++ if (!memb)
++ list_add_tail(newlist, head);
++ else {
++ /* FIXME: can use list macro here */
++ newlist->prev = tmp->prev;
++ newlist->next = tmp;
++ tmp->prev->next = newlist;
++ tmp->prev = newlist;
++ }
++}
++
++static int dlm_add_member(struct dlm_ls *ls, int nodeid)
++{
++ struct dlm_member *memb;
++ int w;
++
++ memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
++ if (!memb)
++ return -ENOMEM;
++
++ w = dlm_node_weight(ls->ls_name, nodeid);
++ if (w < 0)
++ return w;
++
++ memb->nodeid = nodeid;
++ memb->weight = w;
++ add_ordered_member(ls, memb);
++ ls->ls_num_nodes++;
++ return 0;
++}
++
++static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb)
++{
++ list_move(&memb->list, &ls->ls_nodes_gone);
++ ls->ls_num_nodes--;
++}
++
++static int dlm_is_member(struct dlm_ls *ls, int nodeid)
++{
++ struct dlm_member *memb;
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ if (memb->nodeid == nodeid)
++ return 1;
++ }
++ return 0;
++}
++
++int dlm_is_removed(struct dlm_ls *ls, int nodeid)
++{
++ struct dlm_member *memb;
++
++ list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
++ if (memb->nodeid == nodeid)
++ return 1;
++ }
++ return 0;
++}
++
++static void clear_memb_list(struct list_head *head)
++{
++ struct dlm_member *memb;
++
++ while (!list_empty(head)) {
++ memb = list_entry(head->next, struct dlm_member, list);
++ list_del(&memb->list);
++ kfree(memb);
++ }
++}
++
++void dlm_clear_members(struct dlm_ls *ls)
++{
++ clear_memb_list(&ls->ls_nodes);
++ ls->ls_num_nodes = 0;
++}
++
++void dlm_clear_members_gone(struct dlm_ls *ls)
++{
++ clear_memb_list(&ls->ls_nodes_gone);
++}
++
++static void make_member_array(struct dlm_ls *ls)
++{
++ struct dlm_member *memb;
++ int i, w, x = 0, total = 0, all_zero = 0, *array;
++
++ kfree(ls->ls_node_array);
++ ls->ls_node_array = NULL;
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ if (memb->weight)
++ total += memb->weight;
++ }
++
++ /* all nodes revert to weight of 1 if all have weight 0 */
++
++ if (!total) {
++ total = ls->ls_num_nodes;
++ all_zero = 1;
++ }
++
++ ls->ls_total_weight = total;
++
++ array = kmalloc(sizeof(int) * total, GFP_KERNEL);
++ if (!array)
++ return;
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ if (!all_zero && !memb->weight)
++ continue;
++
++ if (all_zero)
++ w = 1;
++ else
++ w = memb->weight;
++
++ DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););
++
++ for (i = 0; i < w; i++)
++ array[x++] = memb->nodeid;
++ }
++
++ ls->ls_node_array = array;
++}
++
++/* send a status request to all members just to establish comms connections */
++
++static int ping_members(struct dlm_ls *ls)
++{
++ struct dlm_member *memb;
++ int error = 0;
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ error = dlm_recovery_stopped(ls);
++ if (error)
++ break;
++ error = dlm_rcom_status(ls, memb->nodeid);
++ if (error)
++ break;
++ }
++ if (error)
++ log_debug(ls, "ping_members aborted %d last nodeid %d",
++ error, ls->ls_recover_nodeid);
++ return error;
++}
++
++int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
++{
++ struct dlm_member *memb, *safe;
++ int i, error, found, pos = 0, neg = 0, low = -1;
++
++ /* move departed members from ls_nodes to ls_nodes_gone */
++
++ list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
++ found = 0;
++ for (i = 0; i < rv->node_count; i++) {
++ if (memb->nodeid == rv->nodeids[i]) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found) {
++ neg++;
++ dlm_remove_member(ls, memb);
++ log_debug(ls, "remove member %d", memb->nodeid);
++ }
++ }
++
++ /* add new members to ls_nodes */
++
++ for (i = 0; i < rv->node_count; i++) {
++ if (dlm_is_member(ls, rv->nodeids[i]))
++ continue;
++ dlm_add_member(ls, rv->nodeids[i]);
++ pos++;
++ log_debug(ls, "add member %d", rv->nodeids[i]);
++ }
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ if (low == -1 || memb->nodeid < low)
++ low = memb->nodeid;
++ }
++ ls->ls_low_nodeid = low;
++
++ make_member_array(ls);
++ dlm_set_recover_status(ls, DLM_RS_NODES);
++ *neg_out = neg;
++
++ error = ping_members(ls);
++ if (error)
++ goto out;
++
++ error = dlm_recover_members_wait(ls);
++ out:
++ log_debug(ls, "total members %d error %d", ls->ls_num_nodes, error);
++ return error;
++}
++
++/*
++ * Following called from lockspace.c
++ */
++
++int dlm_ls_stop(struct dlm_ls *ls)
++{
++ int new;
++
++ /*
++ * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
++ * dlm_recovery_stopped()) and prevents any new locks from being
++ * processed (see RUNNING, dlm_locking_stopped()).
++ */
++
++ spin_lock(&ls->ls_recover_lock);
++ set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
++ new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
++ ls->ls_recover_seq++;
++ spin_unlock(&ls->ls_recover_lock);
++
++ /*
++ * This in_recovery lock does two things:
++ *
++ * 1) Keeps this function from returning until all threads are out
++ * of locking routines and locking is truely stopped.
++ * 2) Keeps any new requests from being processed until it's unlocked
++ * when recovery is complete.
++ */
++
++ if (new)
++ down_write(&ls->ls_in_recovery);
++
++ /*
++ * The recoverd suspend/resume makes sure that dlm_recoverd (if
++ * running) has noticed the clearing of RUNNING above and quit
++ * processing the previous recovery. This will be true for all nodes
++ * before any nodes start the new recovery.
++ */
++
++ dlm_recoverd_suspend(ls);
++ ls->ls_recover_status = 0;
++ dlm_recoverd_resume(ls);
++ return 0;
++}
++
++int dlm_ls_start(struct dlm_ls *ls)
++{
++ struct dlm_recover *rv = NULL, *rv_old;
++ int *ids = NULL;
++ int error, count;
++
++ rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
++ if (!rv)
++ return -ENOMEM;
++
++ error = count = dlm_nodeid_list(ls->ls_name, &ids);
++ if (error <= 0)
++ goto fail;
++
++ spin_lock(&ls->ls_recover_lock);
++
++ /* the lockspace needs to be stopped before it can be started */
++
++ if (!dlm_locking_stopped(ls)) {
++ spin_unlock(&ls->ls_recover_lock);
++ log_error(ls, "start ignored: lockspace running");
++ error = -EINVAL;
++ goto fail;
++ }
++
++ rv->nodeids = ids;
++ rv->node_count = count;
++ rv->seq = ++ls->ls_recover_seq;
++ rv_old = ls->ls_recover_args;
++ ls->ls_recover_args = rv;
++ spin_unlock(&ls->ls_recover_lock);
++
++ if (rv_old) {
++ kfree(rv_old->nodeids);
++ kfree(rv_old);
++ }
++
++ dlm_recoverd_kick(ls);
++ return 0;
++
++ fail:
++ kfree(rv);
++ kfree(ids);
++ return error;
++}
++
+diff --git a/fs/dlm/member.h b/fs/dlm/member.h
+new file mode 100644
+index 0000000..927c08c
+--- /dev/null
++++ b/fs/dlm/member.h
+@@ -0,0 +1,24 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __MEMBER_DOT_H__
++#define __MEMBER_DOT_H__
++
++int dlm_ls_stop(struct dlm_ls *ls);
++int dlm_ls_start(struct dlm_ls *ls);
++void dlm_clear_members(struct dlm_ls *ls);
++void dlm_clear_members_gone(struct dlm_ls *ls);
++int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out);
++int dlm_is_removed(struct dlm_ls *ls, int nodeid);
++
++#endif /* __MEMBER_DOT_H__ */
++
+diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
+new file mode 100644
+index 0000000..989b608
+--- /dev/null
++++ b/fs/dlm/memory.c
+@@ -0,0 +1,116 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "config.h"
++#include "memory.h"
++
++static kmem_cache_t *lkb_cache;
++
++
++int dlm_memory_init(void)
++{
++ int ret = 0;
++
++ lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
++ __alignof__(struct dlm_lkb), 0, NULL, NULL);
++ if (!lkb_cache)
++ ret = -ENOMEM;
++ return ret;
++}
++
++void dlm_memory_exit(void)
++{
++ if (lkb_cache)
++ kmem_cache_destroy(lkb_cache);
++}
++
++char *allocate_lvb(struct dlm_ls *ls)
++{
++ char *p;
++
++ p = kmalloc(ls->ls_lvblen, GFP_KERNEL);
++ if (p)
++ memset(p, 0, ls->ls_lvblen);
++ return p;
++}
++
++void free_lvb(char *p)
++{
++ kfree(p);
++}
++
++/* FIXME: have some minimal space built-in to rsb for the name and
++ kmalloc a separate name if needed, like dentries are done */
++
++struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen)
++{
++ struct dlm_rsb *r;
++
++ DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
++
++ r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL);
++ if (r)
++ memset(r, 0, sizeof(*r) + namelen);
++ return r;
++}
++
++void free_rsb(struct dlm_rsb *r)
++{
++ if (r->res_lvbptr)
++ free_lvb(r->res_lvbptr);
++ kfree(r);
++}
++
++struct dlm_lkb *allocate_lkb(struct dlm_ls *ls)
++{
++ struct dlm_lkb *lkb;
++
++ lkb = kmem_cache_alloc(lkb_cache, GFP_KERNEL);
++ if (lkb)
++ memset(lkb, 0, sizeof(*lkb));
++ return lkb;
++}
++
++void free_lkb(struct dlm_lkb *lkb)
++{
++ if (lkb->lkb_flags & DLM_IFL_USER) {
++ struct dlm_user_args *ua;
++ ua = (struct dlm_user_args *)lkb->lkb_astparam;
++ if (ua) {
++ if (ua->lksb.sb_lvbptr)
++ kfree(ua->lksb.sb_lvbptr);
++ kfree(ua);
++ }
++ }
++ kmem_cache_free(lkb_cache, lkb);
++}
++
++struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen)
++{
++ struct dlm_direntry *de;
++
++ DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,
++ printk("namelen = %d\n", namelen););
++
++ de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL);
++ if (de)
++ memset(de, 0, sizeof(*de) + namelen);
++ return de;
++}
++
++void free_direntry(struct dlm_direntry *de)
++{
++ kfree(de);
++}
++
+diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h
+new file mode 100644
+index 0000000..6ead158
+--- /dev/null
++++ b/fs/dlm/memory.h
+@@ -0,0 +1,29 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __MEMORY_DOT_H__
++#define __MEMORY_DOT_H__
++
++int dlm_memory_init(void);
++void dlm_memory_exit(void);
++struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen);
++void free_rsb(struct dlm_rsb *r);
++struct dlm_lkb *allocate_lkb(struct dlm_ls *ls);
++void free_lkb(struct dlm_lkb *l);
++struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen);
++void free_direntry(struct dlm_direntry *de);
++char *allocate_lvb(struct dlm_ls *ls);
++void free_lvb(char *l);
++
++#endif /* __MEMORY_DOT_H__ */
++
+diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
+new file mode 100644
+index 0000000..c9b1c3d
+--- /dev/null
++++ b/fs/dlm/midcomms.c
+@@ -0,0 +1,140 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++/*
++ * midcomms.c
++ *
++ * This is the appallingly named "mid-level" comms layer.
++ *
++ * Its purpose is to take packets from the "real" comms layer,
++ * split them up into packets and pass them to the interested
++ * part of the locking mechanism.
++ *
++ * It also takes messages from the locking layer, formats them
++ * into packets and sends them to the comms layer.
++ */
++
++#include "dlm_internal.h"
++#include "lowcomms.h"
++#include "config.h"
++#include "rcom.h"
++#include "lock.h"
++#include "midcomms.h"
++
++
++static void copy_from_cb(void *dst, const void *base, unsigned offset,
++ unsigned len, unsigned limit)
++{
++ unsigned copy = len;
++
++ if ((copy + offset) > limit)
++ copy = limit - offset;
++ memcpy(dst, base + offset, copy);
++ len -= copy;
++ if (len)
++ memcpy(dst + copy, base, len);
++}
++
++/*
++ * Called from the low-level comms layer to process a buffer of
++ * commands.
++ *
++ * Only complete messages are processed here, any "spare" bytes from
++ * the end of a buffer are saved and tacked onto the front of the next
++ * message that comes in. I doubt this will happen very often but we
++ * need to be able to cope with it and I don't want the task to be waiting
++ * for packets to come in when there is useful work to be done.
++ */
++
++int dlm_process_incoming_buffer(int nodeid, const void *base,
++ unsigned offset, unsigned len, unsigned limit)
++{
++ unsigned char __tmp[DLM_INBUF_LEN];
++ struct dlm_header *msg = (struct dlm_header *) __tmp;
++ int ret = 0;
++ int err = 0;
++ uint16_t msglen;
++ uint32_t lockspace;
++
++ while (len > sizeof(struct dlm_header)) {
++
++ /* Copy just the header to check the total length. The
++ message may wrap around the end of the buffer back to the
++ start, so we need to use a temp buffer and copy_from_cb. */
++
++ copy_from_cb(msg, base, offset, sizeof(struct dlm_header),
++ limit);
++
++ msglen = le16_to_cpu(msg->h_length);
++ lockspace = msg->h_lockspace;
++
++ err = -EINVAL;
++ if (msglen < sizeof(struct dlm_header))
++ break;
++ err = -E2BIG;
++ if (msglen > dlm_config.buffer_size) {
++ log_print("message size %d from %d too big, buf len %d",
++ msglen, nodeid, len);
++ break;
++ }
++ err = 0;
++
++ /* If only part of the full message is contained in this
++ buffer, then do nothing and wait for lowcomms to call
++ us again later with more data. We return 0 meaning
++ we've consumed none of the input buffer. */
++
++ if (msglen > len)
++ break;
++
++ /* Allocate a larger temp buffer if the full message won't fit
++ in the buffer on the stack (which should work for most
++ ordinary messages). */
++
++ if (msglen > sizeof(__tmp) &&
++ msg == (struct dlm_header *) __tmp) {
++ msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
++ if (msg == NULL)
++ return ret;
++ }
++
++ copy_from_cb(msg, base, offset, msglen, limit);
++
++ BUG_ON(lockspace != msg->h_lockspace);
++
++ ret += msglen;
++ offset += msglen;
++ offset &= (limit - 1);
++ len -= msglen;
++
++ switch (msg->h_cmd) {
++ case DLM_MSG:
++ dlm_receive_message(msg, nodeid, 0);
++ break;
++
++ case DLM_RCOM:
++ dlm_receive_rcom(msg, nodeid);
++ break;
++
++ default:
++ log_print("unknown msg type %x from %u: %u %u %u %u",
++ msg->h_cmd, nodeid, msglen, len, offset, ret);
++ }
++ }
++
++ if (msg != (struct dlm_header *) __tmp)
++ kfree(msg);
++
++ return err ? err : ret;
++}
++
+diff --git a/fs/dlm/midcomms.h b/fs/dlm/midcomms.h
+new file mode 100644
+index 0000000..95852a5
+--- /dev/null
++++ b/fs/dlm/midcomms.h
+@@ -0,0 +1,21 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __MIDCOMMS_DOT_H__
++#define __MIDCOMMS_DOT_H__
++
++int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset,
++ unsigned len, unsigned limit);
++
++#endif /* __MIDCOMMS_DOT_H__ */
++
+diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
+new file mode 100644
+index 0000000..518239a
+--- /dev/null
++++ b/fs/dlm/rcom.c
+@@ -0,0 +1,472 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "member.h"
++#include "lowcomms.h"
++#include "midcomms.h"
++#include "rcom.h"
++#include "recover.h"
++#include "dir.h"
++#include "config.h"
++#include "memory.h"
++#include "lock.h"
++#include "util.h"
++
++
++static int rcom_response(struct dlm_ls *ls)
++{
++ return test_bit(LSFL_RCOM_READY, &ls->ls_flags);
++}
++
++static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len,
++ struct dlm_rcom **rc_ret, struct dlm_mhandle **mh_ret)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ char *mb;
++ int mb_len = sizeof(struct dlm_rcom) + len;
++
++ mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
++ if (!mh) {
++ log_print("create_rcom to %d type %d len %d ENOBUFS",
++ to_nodeid, type, len);
++ return -ENOBUFS;
++ }
++ memset(mb, 0, mb_len);
++
++ rc = (struct dlm_rcom *) mb;
++
++ rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
++ rc->rc_header.h_lockspace = ls->ls_global_id;
++ rc->rc_header.h_nodeid = dlm_our_nodeid();
++ rc->rc_header.h_length = mb_len;
++ rc->rc_header.h_cmd = DLM_RCOM;
++
++ rc->rc_type = type;
++
++ *mh_ret = mh;
++ *rc_ret = rc;
++ return 0;
++}
++
++static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh,
++ struct dlm_rcom *rc)
++{
++ dlm_rcom_out(rc);
++ dlm_lowcomms_commit_buffer(mh);
++}
++
++/* When replying to a status request, a node also sends back its
++ configuration values. The requesting node then checks that the remote
++ node is configured the same way as itself. */
++
++static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
++{
++ rf->rf_lvblen = ls->ls_lvblen;
++ rf->rf_lsflags = ls->ls_exflags;
++}
++
++static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
++{
++ if (rf->rf_lvblen != ls->ls_lvblen ||
++ rf->rf_lsflags != ls->ls_exflags) {
++ log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
++ ls->ls_lvblen, ls->ls_exflags,
++ nodeid, rf->rf_lvblen, rf->rf_lsflags);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ int error = 0;
++
++ memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
++ ls->ls_recover_nodeid = nodeid;
++
++ if (nodeid == dlm_our_nodeid()) {
++ rc = (struct dlm_rcom *) ls->ls_recover_buf;
++ rc->rc_result = dlm_recover_status(ls);
++ goto out;
++ }
++
++ error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh);
++ if (error)
++ goto out;
++ rc->rc_id = ++ls->ls_rcom_seq;
++
++ send_rcom(ls, mh, rc);
++
++ error = dlm_wait_function(ls, &rcom_response);
++ clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
++ if (error)
++ goto out;
++
++ rc = (struct dlm_rcom *) ls->ls_recover_buf;
++
++ if (rc->rc_result == -ESRCH) {
++ /* we pretend the remote lockspace exists with 0 status */
++ log_debug(ls, "remote node %d not ready", nodeid);
++ rc->rc_result = 0;
++ } else
++ error = check_config(ls, (struct rcom_config *) rc->rc_buf,
++ nodeid);
++ /* the caller looks at rc_result for the remote recovery status */
++ out:
++ return error;
++}
++
++static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ int error, nodeid = rc_in->rc_header.h_nodeid;
++
++ error = create_rcom(ls, nodeid, DLM_RCOM_STATUS_REPLY,
++ sizeof(struct rcom_config), &rc, &mh);
++ if (error)
++ return;
++ rc->rc_id = rc_in->rc_id;
++ rc->rc_result = dlm_recover_status(ls);
++ make_config(ls, (struct rcom_config *) rc->rc_buf);
++
++ send_rcom(ls, mh, rc);
++}
++
++static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ if (rc_in->rc_id != ls->ls_rcom_seq) {
++ log_debug(ls, "reject old reply %d got %llx wanted %llx",
++ rc_in->rc_type, rc_in->rc_id, ls->ls_rcom_seq);
++ return;
++ }
++ memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length);
++ set_bit(LSFL_RCOM_READY, &ls->ls_flags);
++ wake_up(&ls->ls_wait_general);
++}
++
++static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ receive_sync_reply(ls, rc_in);
++}
++
++int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ int error = 0, len = sizeof(struct dlm_rcom);
++
++ memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
++ ls->ls_recover_nodeid = nodeid;
++
++ if (nodeid == dlm_our_nodeid()) {
++ dlm_copy_master_names(ls, last_name, last_len,
++ ls->ls_recover_buf + len,
++ dlm_config.buffer_size - len, nodeid);
++ goto out;
++ }
++
++ error = create_rcom(ls, nodeid, DLM_RCOM_NAMES, last_len, &rc, &mh);
++ if (error)
++ goto out;
++ memcpy(rc->rc_buf, last_name, last_len);
++ rc->rc_id = ++ls->ls_rcom_seq;
++
++ send_rcom(ls, mh, rc);
++
++ error = dlm_wait_function(ls, &rcom_response);
++ clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
++ out:
++ return error;
++}
++
++static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ int error, inlen, outlen;
++ int nodeid = rc_in->rc_header.h_nodeid;
++ uint32_t status = dlm_recover_status(ls);
++
++ /*
++ * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while
++ * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes).
++ * It could only happen in rare cases where we get a late NAMES
++ * message from a previous instance of recovery.
++ */
++
++ if (!(status & DLM_RS_NODES)) {
++ log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid);
++ return;
++ }
++
++ nodeid = rc_in->rc_header.h_nodeid;
++ inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
++ outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom);
++
++ error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh);
++ if (error)
++ return;
++ rc->rc_id = rc_in->rc_id;
++
++ dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
++ nodeid);
++ send_rcom(ls, mh, rc);
++}
++
++static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ receive_sync_reply(ls, rc_in);
++}
++
++int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ struct dlm_ls *ls = r->res_ls;
++ int error;
++
++ error = create_rcom(ls, dir_nodeid, DLM_RCOM_LOOKUP, r->res_length,
++ &rc, &mh);
++ if (error)
++ goto out;
++ memcpy(rc->rc_buf, r->res_name, r->res_length);
++ rc->rc_id = (unsigned long) r;
++
++ send_rcom(ls, mh, rc);
++ out:
++ return error;
++}
++
++static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ int error, ret_nodeid, nodeid = rc_in->rc_header.h_nodeid;
++ int len = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
++
++ error = create_rcom(ls, nodeid, DLM_RCOM_LOOKUP_REPLY, 0, &rc, &mh);
++ if (error)
++ return;
++
++ error = dlm_dir_lookup(ls, nodeid, rc_in->rc_buf, len, &ret_nodeid);
++ if (error)
++ ret_nodeid = error;
++ rc->rc_result = ret_nodeid;
++ rc->rc_id = rc_in->rc_id;
++
++ send_rcom(ls, mh, rc);
++}
++
++static void receive_rcom_lookup_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ dlm_recover_master_reply(ls, rc_in);
++}
++
++static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb,
++ struct rcom_lock *rl)
++{
++ memset(rl, 0, sizeof(*rl));
++
++ rl->rl_ownpid = lkb->lkb_ownpid;
++ rl->rl_lkid = lkb->lkb_id;
++ rl->rl_exflags = lkb->lkb_exflags;
++ rl->rl_flags = lkb->lkb_flags;
++ rl->rl_lvbseq = lkb->lkb_lvbseq;
++ rl->rl_rqmode = lkb->lkb_rqmode;
++ rl->rl_grmode = lkb->lkb_grmode;
++ rl->rl_status = lkb->lkb_status;
++ rl->rl_wait_type = lkb->lkb_wait_type;
++
++ if (lkb->lkb_bastaddr)
++ rl->rl_asts |= AST_BAST;
++ if (lkb->lkb_astaddr)
++ rl->rl_asts |= AST_COMP;
++
++ rl->rl_namelen = r->res_length;
++ memcpy(rl->rl_name, r->res_name, r->res_length);
++
++ /* FIXME: might we have an lvb without DLM_LKF_VALBLK set ?
++ If so, receive_rcom_lock_args() won't take this copy. */
++
++ if (lkb->lkb_lvbptr)
++ memcpy(rl->rl_lvb, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
++}
++
++int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
++{
++ struct dlm_ls *ls = r->res_ls;
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ struct rcom_lock *rl;
++ int error, len = sizeof(struct rcom_lock);
++
++ if (lkb->lkb_lvbptr)
++ len += ls->ls_lvblen;
++
++ error = create_rcom(ls, r->res_nodeid, DLM_RCOM_LOCK, len, &rc, &mh);
++ if (error)
++ goto out;
++
++ rl = (struct rcom_lock *) rc->rc_buf;
++ pack_rcom_lock(r, lkb, rl);
++ rc->rc_id = (unsigned long) r;
++
++ send_rcom(ls, mh, rc);
++ out:
++ return error;
++}
++
++static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ int error, nodeid = rc_in->rc_header.h_nodeid;
++
++ dlm_recover_master_copy(ls, rc_in);
++
++ error = create_rcom(ls, nodeid, DLM_RCOM_LOCK_REPLY,
++ sizeof(struct rcom_lock), &rc, &mh);
++ if (error)
++ return;
++
++ /* We send back the same rcom_lock struct we received, but
++ dlm_recover_master_copy() has filled in rl_remid and rl_result */
++
++ memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
++ rc->rc_id = rc_in->rc_id;
++
++ send_rcom(ls, mh, rc);
++}
++
++static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
++{
++ uint32_t status = dlm_recover_status(ls);
++
++ if (!(status & DLM_RS_DIR)) {
++ log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u",
++ rc_in->rc_header.h_nodeid);
++ return;
++ }
++
++ dlm_recover_process_copy(ls, rc_in);
++}
++
++static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
++{
++ struct dlm_rcom *rc;
++ struct dlm_mhandle *mh;
++ char *mb;
++ int mb_len = sizeof(struct dlm_rcom);
++
++ mh = dlm_lowcomms_get_buffer(nodeid, mb_len, GFP_KERNEL, &mb);
++ if (!mh)
++ return -ENOBUFS;
++ memset(mb, 0, mb_len);
++
++ rc = (struct dlm_rcom *) mb;
++
++ rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
++ rc->rc_header.h_lockspace = rc_in->rc_header.h_lockspace;
++ rc->rc_header.h_nodeid = dlm_our_nodeid();
++ rc->rc_header.h_length = mb_len;
++ rc->rc_header.h_cmd = DLM_RCOM;
++
++ rc->rc_type = DLM_RCOM_STATUS_REPLY;
++ rc->rc_id = rc_in->rc_id;
++ rc->rc_result = -ESRCH;
++
++ dlm_rcom_out(rc);
++ dlm_lowcomms_commit_buffer(mh);
++
++ return 0;
++}
++
++/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
++ recovery-only comms are sent through here. */
++
++void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
++{
++ struct dlm_rcom *rc = (struct dlm_rcom *) hd;
++ struct dlm_ls *ls;
++
++ dlm_rcom_in(rc);
++
++ /* If the lockspace doesn't exist then still send a status message
++ back; it's possible that it just doesn't have its global_id yet. */
++
++ ls = dlm_find_lockspace_global(hd->h_lockspace);
++ if (!ls) {
++ log_print("lockspace %x from %d not found",
++ hd->h_lockspace, nodeid);
++ send_ls_not_ready(nodeid, rc);
++ return;
++ }
++
++ if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
++ log_error(ls, "ignoring recovery message %x from %d",
++ rc->rc_type, nodeid);
++ goto out;
++ }
++
++ if (nodeid != rc->rc_header.h_nodeid) {
++ log_error(ls, "bad rcom nodeid %d from %d",
++ rc->rc_header.h_nodeid, nodeid);
++ goto out;
++ }
++
++ switch (rc->rc_type) {
++ case DLM_RCOM_STATUS:
++ receive_rcom_status(ls, rc);
++ break;
++
++ case DLM_RCOM_NAMES:
++ receive_rcom_names(ls, rc);
++ break;
++
++ case DLM_RCOM_LOOKUP:
++ receive_rcom_lookup(ls, rc);
++ break;
++
++ case DLM_RCOM_LOCK:
++ receive_rcom_lock(ls, rc);
++ break;
++
++ case DLM_RCOM_STATUS_REPLY:
++ receive_rcom_status_reply(ls, rc);
++ break;
++
++ case DLM_RCOM_NAMES_REPLY:
++ receive_rcom_names_reply(ls, rc);
++ break;
++
++ case DLM_RCOM_LOOKUP_REPLY:
++ receive_rcom_lookup_reply(ls, rc);
++ break;
++
++ case DLM_RCOM_LOCK_REPLY:
++ receive_rcom_lock_reply(ls, rc);
++ break;
++
++ default:
++ DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
++ }
++ out:
++ dlm_put_lockspace(ls);
++}
++
+diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h
+new file mode 100644
+index 0000000..d798432
+--- /dev/null
++++ b/fs/dlm/rcom.h
+@@ -0,0 +1,24 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __RCOM_DOT_H__
++#define __RCOM_DOT_H__
++
++int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
++int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
++int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
++int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
++void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
++
++#endif
++
+diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
+new file mode 100644
+index 0000000..a5e6d18
+--- /dev/null
++++ b/fs/dlm/recover.c
+@@ -0,0 +1,765 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "dir.h"
++#include "config.h"
++#include "ast.h"
++#include "memory.h"
++#include "rcom.h"
++#include "lock.h"
++#include "lowcomms.h"
++#include "member.h"
++#include "recover.h"
++
++
++/*
++ * Recovery waiting routines: these functions wait for a particular reply from
++ * a remote node, or for the remote node to report a certain status. They need
++ * to abort if the lockspace is stopped indicating a node has failed (perhaps
++ * the one being waited for).
++ */
++
++/*
++ * Wait until given function returns non-zero or lockspace is stopped
++ * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes). When another
++ * function thinks it could have completed the waited-on task, they should wake
++ * up ls_wait_general to get an immediate response rather than waiting for the
++ * timer to detect the result. A timer wakes us up periodically while waiting
++ * to see if we should abort due to a node failure. This should only be called
++ * by the dlm_recoverd thread.
++ */
++
++static void dlm_wait_timer_fn(unsigned long data)
++{
++ struct dlm_ls *ls = (struct dlm_ls *) data;
++ mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ));
++ wake_up(&ls->ls_wait_general);
++}
++
++int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
++{
++ int error = 0;
++
++ init_timer(&ls->ls_timer);
++ ls->ls_timer.function = dlm_wait_timer_fn;
++ ls->ls_timer.data = (long) ls;
++ ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ);
++ add_timer(&ls->ls_timer);
++
++ wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
++ del_timer_sync(&ls->ls_timer);
++
++ if (dlm_recovery_stopped(ls)) {
++ log_debug(ls, "dlm_wait_function aborted");
++ error = -EINTR;
++ }
++ return error;
++}
++
++/*
++ * An efficient way for all nodes to wait for all others to have a certain
++ * status. The node with the lowest nodeid polls all the others for their
++ * status (wait_status_all) and all the others poll the node with the low id
++ * for its accumulated result (wait_status_low). When all nodes have set
++ * status flag X, then status flag X_ALL will be set on the low nodeid.
++ */
++
++uint32_t dlm_recover_status(struct dlm_ls *ls)
++{
++ uint32_t status;
++ spin_lock(&ls->ls_recover_lock);
++ status = ls->ls_recover_status;
++ spin_unlock(&ls->ls_recover_lock);
++ return status;
++}
++
++void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status)
++{
++ spin_lock(&ls->ls_recover_lock);
++ ls->ls_recover_status |= status;
++ spin_unlock(&ls->ls_recover_lock);
++}
++
++static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
++{
++ struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
++ struct dlm_member *memb;
++ int error = 0, delay;
++
++ list_for_each_entry(memb, &ls->ls_nodes, list) {
++ delay = 0;
++ for (;;) {
++ if (dlm_recovery_stopped(ls)) {
++ error = -EINTR;
++ goto out;
++ }
++
++ error = dlm_rcom_status(ls, memb->nodeid);
++ if (error)
++ goto out;
++
++ if (rc->rc_result & wait_status)
++ break;
++ if (delay < 1000)
++ delay += 20;
++ msleep(delay);
++ }
++ }
++ out:
++ return error;
++}
++
++static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)
++{
++ struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
++ int error = 0, delay = 0, nodeid = ls->ls_low_nodeid;
++
++ for (;;) {
++ if (dlm_recovery_stopped(ls)) {
++ error = -EINTR;
++ goto out;
++ }
++
++ error = dlm_rcom_status(ls, nodeid);
++ if (error)
++ break;
++
++ if (rc->rc_result & wait_status)
++ break;
++ if (delay < 1000)
++ delay += 20;
++ msleep(delay);
++ }
++ out:
++ return error;
++}
++
++static int wait_status(struct dlm_ls *ls, uint32_t status)
++{
++ uint32_t status_all = status << 1;
++ int error;
++
++ if (ls->ls_low_nodeid == dlm_our_nodeid()) {
++ error = wait_status_all(ls, status);
++ if (!error)
++ dlm_set_recover_status(ls, status_all);
++ } else
++ error = wait_status_low(ls, status_all);
++
++ return error;
++}
++
++int dlm_recover_members_wait(struct dlm_ls *ls)
++{
++ return wait_status(ls, DLM_RS_NODES);
++}
++
++int dlm_recover_directory_wait(struct dlm_ls *ls)
++{
++ return wait_status(ls, DLM_RS_DIR);
++}
++
++int dlm_recover_locks_wait(struct dlm_ls *ls)
++{
++ return wait_status(ls, DLM_RS_LOCKS);
++}
++
++int dlm_recover_done_wait(struct dlm_ls *ls)
++{
++ return wait_status(ls, DLM_RS_DONE);
++}
++
++/*
++ * The recover_list contains all the rsb's for which we've requested the new
++ * master nodeid. As replies are returned from the resource directories the
++ * rsb's are removed from the list. When the list is empty we're done.
++ *
++ * The recover_list is later similarly used for all rsb's for which we've sent
++ * new lkb's and need to receive new corresponding lkid's.
++ *
++ * We use the address of the rsb struct as a simple local identifier for the
++ * rsb so we can match an rcom reply with the rsb it was sent for.
++ */
++
++static int recover_list_empty(struct dlm_ls *ls)
++{
++ int empty;
++
++ spin_lock(&ls->ls_recover_list_lock);
++ empty = list_empty(&ls->ls_recover_list);
++ spin_unlock(&ls->ls_recover_list_lock);
++
++ return empty;
++}
++
++static void recover_list_add(struct dlm_rsb *r)
++{
++ struct dlm_ls *ls = r->res_ls;
++
++ spin_lock(&ls->ls_recover_list_lock);
++ if (list_empty(&r->res_recover_list)) {
++ list_add_tail(&r->res_recover_list, &ls->ls_recover_list);
++ ls->ls_recover_list_count++;
++ dlm_hold_rsb(r);
++ }
++ spin_unlock(&ls->ls_recover_list_lock);
++}
++
++static void recover_list_del(struct dlm_rsb *r)
++{
++ struct dlm_ls *ls = r->res_ls;
++
++ spin_lock(&ls->ls_recover_list_lock);
++ list_del_init(&r->res_recover_list);
++ ls->ls_recover_list_count--;
++ spin_unlock(&ls->ls_recover_list_lock);
++
++ dlm_put_rsb(r);
++}
++
++static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id)
++{
++ struct dlm_rsb *r = NULL;
++
++ spin_lock(&ls->ls_recover_list_lock);
++
++ list_for_each_entry(r, &ls->ls_recover_list, res_recover_list) {
++ if (id == (unsigned long) r)
++ goto out;
++ }
++ r = NULL;
++ out:
++ spin_unlock(&ls->ls_recover_list_lock);
++ return r;
++}
++
++static void recover_list_clear(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r, *s;
++
++ spin_lock(&ls->ls_recover_list_lock);
++ list_for_each_entry_safe(r, s, &ls->ls_recover_list, res_recover_list) {
++ list_del_init(&r->res_recover_list);
++ dlm_put_rsb(r);
++ ls->ls_recover_list_count--;
++ }
++
++ if (ls->ls_recover_list_count != 0) {
++ log_error(ls, "warning: recover_list_count %d",
++ ls->ls_recover_list_count);
++ ls->ls_recover_list_count = 0;
++ }
++ spin_unlock(&ls->ls_recover_list_lock);
++}
++
++
++/* Master recovery: find new master node for rsb's that were
++ mastered on nodes that have been removed.
++
++ dlm_recover_masters
++ recover_master
++ dlm_send_rcom_lookup -> receive_rcom_lookup
++ dlm_dir_lookup
++ receive_rcom_lookup_reply <-
++ dlm_recover_master_reply
++ set_new_master
++ set_master_lkbs
++ set_lock_master
++*/
++
++/*
++ * Set the lock master for all LKBs in a lock queue
++ * If we are the new master of the rsb, we may have received new
++ * MSTCPY locks from other nodes already which we need to ignore
++ * when setting the new nodeid.
++ */
++
++static void set_lock_master(struct list_head *queue, int nodeid)
++{
++ struct dlm_lkb *lkb;
++
++ list_for_each_entry(lkb, queue, lkb_statequeue)
++ if (!(lkb->lkb_flags & DLM_IFL_MSTCPY))
++ lkb->lkb_nodeid = nodeid;
++}
++
++static void set_master_lkbs(struct dlm_rsb *r)
++{
++ set_lock_master(&r->res_grantqueue, r->res_nodeid);
++ set_lock_master(&r->res_convertqueue, r->res_nodeid);
++ set_lock_master(&r->res_waitqueue, r->res_nodeid);
++}
++
++/*
++ * Propogate the new master nodeid to locks
++ * The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider.
++ * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which
++ * rsb's to consider.
++ */
++
++static void set_new_master(struct dlm_rsb *r, int nodeid)
++{
++ lock_rsb(r);
++ r->res_nodeid = nodeid;
++ set_master_lkbs(r);
++ rsb_set_flag(r, RSB_NEW_MASTER);
++ rsb_set_flag(r, RSB_NEW_MASTER2);
++ unlock_rsb(r);
++}
++
++/*
++ * We do async lookups on rsb's that need new masters. The rsb's
++ * waiting for a lookup reply are kept on the recover_list.
++ */
++
++static int recover_master(struct dlm_rsb *r)
++{
++ struct dlm_ls *ls = r->res_ls;
++ int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
++
++ dir_nodeid = dlm_dir_nodeid(r);
++
++ if (dir_nodeid == our_nodeid) {
++ error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
++ r->res_length, &ret_nodeid);
++ if (error)
++ log_error(ls, "recover dir lookup error %d", error);
++
++ if (ret_nodeid == our_nodeid)
++ ret_nodeid = 0;
++ set_new_master(r, ret_nodeid);
++ } else {
++ recover_list_add(r);
++ error = dlm_send_rcom_lookup(r, dir_nodeid);
++ }
++
++ return error;
++}
++
++/*
++ * When not using a directory, most resource names will hash to a new static
++ * master nodeid and the resource will need to be remastered.
++ */
++
++static int recover_master_static(struct dlm_rsb *r)
++{
++ int master = dlm_dir_nodeid(r);
++
++ if (master == dlm_our_nodeid())
++ master = 0;
++
++ if (r->res_nodeid != master) {
++ if (is_master(r))
++ dlm_purge_mstcpy_locks(r);
++ set_new_master(r, master);
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * Go through local root resources and for each rsb which has a master which
++ * has departed, get the new master nodeid from the directory. The dir will
++ * assign mastery to the first node to look up the new master. That means
++ * we'll discover in this lookup if we're the new master of any rsb's.
++ *
++ * We fire off all the dir lookup requests individually and asynchronously to
++ * the correct dir node.
++ */
++
++int dlm_recover_masters(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r;
++ int error = 0, count = 0;
++
++ log_debug(ls, "dlm_recover_masters");
++
++ down_read(&ls->ls_root_sem);
++ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
++ if (dlm_recovery_stopped(ls)) {
++ up_read(&ls->ls_root_sem);
++ error = -EINTR;
++ goto out;
++ }
++
++ if (dlm_no_directory(ls))
++ count += recover_master_static(r);
++ else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
++ recover_master(r);
++ count++;
++ }
++
++ schedule();
++ }
++ up_read(&ls->ls_root_sem);
++
++ log_debug(ls, "dlm_recover_masters %d resources", count);
++
++ error = dlm_wait_function(ls, &recover_list_empty);
++ out:
++ if (error)
++ recover_list_clear(ls);
++ return error;
++}
++
++int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
++{
++ struct dlm_rsb *r;
++ int nodeid;
++
++ r = recover_list_find(ls, rc->rc_id);
++ if (!r) {
++ log_error(ls, "dlm_recover_master_reply no id %llx",
++ (unsigned long long)rc->rc_id);
++ goto out;
++ }
++
++ nodeid = rc->rc_result;
++ if (nodeid == dlm_our_nodeid())
++ nodeid = 0;
++
++ set_new_master(r, nodeid);
++ recover_list_del(r);
++
++ if (recover_list_empty(ls))
++ wake_up(&ls->ls_wait_general);
++ out:
++ return 0;
++}
++
++
++/* Lock recovery: rebuild the process-copy locks we hold on a
++ remastered rsb on the new rsb master.
++
++ dlm_recover_locks
++ recover_locks
++ recover_locks_queue
++ dlm_send_rcom_lock -> receive_rcom_lock
++ dlm_recover_master_copy
++ receive_rcom_lock_reply <-
++ dlm_recover_process_copy
++*/
++
++
++/*
++ * keep a count of the number of lkb's we send to the new master; when we get
++ * an equal number of replies then recovery for the rsb is done
++ */
++
++static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head)
++{
++ struct dlm_lkb *lkb;
++ int error = 0;
++
++ list_for_each_entry(lkb, head, lkb_statequeue) {
++ error = dlm_send_rcom_lock(r, lkb);
++ if (error)
++ break;
++ r->res_recover_locks_count++;
++ }
++
++ return error;
++}
++
++static int recover_locks(struct dlm_rsb *r)
++{
++ int error = 0;
++
++ lock_rsb(r);
++
++ DLM_ASSERT(!r->res_recover_locks_count, dlm_dump_rsb(r););
++
++ error = recover_locks_queue(r, &r->res_grantqueue);
++ if (error)
++ goto out;
++ error = recover_locks_queue(r, &r->res_convertqueue);
++ if (error)
++ goto out;
++ error = recover_locks_queue(r, &r->res_waitqueue);
++ if (error)
++ goto out;
++
++ if (r->res_recover_locks_count)
++ recover_list_add(r);
++ else
++ rsb_clear_flag(r, RSB_NEW_MASTER);
++ out:
++ unlock_rsb(r);
++ return error;
++}
++
++int dlm_recover_locks(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r;
++ int error, count = 0;
++
++ log_debug(ls, "dlm_recover_locks");
++
++ down_read(&ls->ls_root_sem);
++ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
++ if (is_master(r)) {
++ rsb_clear_flag(r, RSB_NEW_MASTER);
++ continue;
++ }
++
++ if (!rsb_flag(r, RSB_NEW_MASTER))
++ continue;
++
++ if (dlm_recovery_stopped(ls)) {
++ error = -EINTR;
++ up_read(&ls->ls_root_sem);
++ goto out;
++ }
++
++ error = recover_locks(r);
++ if (error) {
++ up_read(&ls->ls_root_sem);
++ goto out;
++ }
++
++ count += r->res_recover_locks_count;
++ }
++ up_read(&ls->ls_root_sem);
++
++ log_debug(ls, "dlm_recover_locks %d locks", count);
++
++ error = dlm_wait_function(ls, &recover_list_empty);
++ out:
++ if (error)
++ recover_list_clear(ls);
++ else
++ dlm_set_recover_status(ls, DLM_RS_LOCKS);
++ return error;
++}
++
++void dlm_recovered_lock(struct dlm_rsb *r)
++{
++ DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_dump_rsb(r););
++
++ r->res_recover_locks_count--;
++ if (!r->res_recover_locks_count) {
++ rsb_clear_flag(r, RSB_NEW_MASTER);
++ recover_list_del(r);
++ }
++
++ if (recover_list_empty(r->res_ls))
++ wake_up(&r->res_ls->ls_wait_general);
++}
++
++/*
++ * The lvb needs to be recovered on all master rsb's. This includes setting
++ * the VALNOTVALID flag if necessary, and determining the correct lvb contents
++ * based on the lvb's of the locks held on the rsb.
++ *
++ * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb. If it
++ * was already set prior to recovery, it's not cleared, regardless of locks.
++ *
++ * The LVB contents are only considered for changing when this is a new master
++ * of the rsb (NEW_MASTER2). Then, the rsb's lvb is taken from any lkb with
++ * mode > CR. If no lkb's exist with mode above CR, the lvb contents are taken
++ * from the lkb with the largest lvb sequence number.
++ */
++
++static void recover_lvb(struct dlm_rsb *r)
++{
++ struct dlm_lkb *lkb, *high_lkb = NULL;
++ uint32_t high_seq = 0;
++ int lock_lvb_exists = 0;
++ int big_lock_exists = 0;
++ int lvblen = r->res_ls->ls_lvblen;
++
++ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
++ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
++ continue;
++
++ lock_lvb_exists = 1;
++
++ if (lkb->lkb_grmode > DLM_LOCK_CR) {
++ big_lock_exists = 1;
++ goto setflag;
++ }
++
++ if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
++ high_lkb = lkb;
++ high_seq = lkb->lkb_lvbseq;
++ }
++ }
++
++ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
++ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
++ continue;
++
++ lock_lvb_exists = 1;
++
++ if (lkb->lkb_grmode > DLM_LOCK_CR) {
++ big_lock_exists = 1;
++ goto setflag;
++ }
++
++ if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
++ high_lkb = lkb;
++ high_seq = lkb->lkb_lvbseq;
++ }
++ }
++
++ setflag:
++ if (!lock_lvb_exists)
++ goto out;
++
++ if (!big_lock_exists)
++ rsb_set_flag(r, RSB_VALNOTVALID);
++
++ /* don't mess with the lvb unless we're the new master */
++ if (!rsb_flag(r, RSB_NEW_MASTER2))
++ goto out;
++
++ if (!r->res_lvbptr) {
++ r->res_lvbptr = allocate_lvb(r->res_ls);
++ if (!r->res_lvbptr)
++ goto out;
++ }
++
++ if (big_lock_exists) {
++ r->res_lvbseq = lkb->lkb_lvbseq;
++ memcpy(r->res_lvbptr, lkb->lkb_lvbptr, lvblen);
++ } else if (high_lkb) {
++ r->res_lvbseq = high_lkb->lkb_lvbseq;
++ memcpy(r->res_lvbptr, high_lkb->lkb_lvbptr, lvblen);
++ } else {
++ r->res_lvbseq = 0;
++ memset(r->res_lvbptr, 0, lvblen);
++ }
++ out:
++ return;
++}
++
++/* All master rsb's flagged RECOVER_CONVERT need to be looked at. The locks
++ converting PR->CW or CW->PR need to have their lkb_grmode set. */
++
++static void recover_conversion(struct dlm_rsb *r)
++{
++ struct dlm_lkb *lkb;
++ int grmode = -1;
++
++ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
++ if (lkb->lkb_grmode == DLM_LOCK_PR ||
++ lkb->lkb_grmode == DLM_LOCK_CW) {
++ grmode = lkb->lkb_grmode;
++ break;
++ }
++ }
++
++ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
++ if (lkb->lkb_grmode != DLM_LOCK_IV)
++ continue;
++ if (grmode == -1)
++ lkb->lkb_grmode = lkb->lkb_rqmode;
++ else
++ lkb->lkb_grmode = grmode;
++ }
++}
++
++/* We've become the new master for this rsb and waiting/converting locks may
++ need to be granted in dlm_grant_after_purge() due to locks that may have
++ existed from a removed node. */
++
++static void set_locks_purged(struct dlm_rsb *r)
++{
++ if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
++ rsb_set_flag(r, RSB_LOCKS_PURGED);
++}
++
++void dlm_recover_rsbs(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r;
++ int count = 0;
++
++ log_debug(ls, "dlm_recover_rsbs");
++
++ down_read(&ls->ls_root_sem);
++ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
++ lock_rsb(r);
++ if (is_master(r)) {
++ if (rsb_flag(r, RSB_RECOVER_CONVERT))
++ recover_conversion(r);
++ if (rsb_flag(r, RSB_NEW_MASTER2))
++ set_locks_purged(r);
++ recover_lvb(r);
++ count++;
++ }
++ rsb_clear_flag(r, RSB_RECOVER_CONVERT);
++ rsb_clear_flag(r, RSB_NEW_MASTER2);
++ unlock_rsb(r);
++ }
++ up_read(&ls->ls_root_sem);
++
++ log_debug(ls, "dlm_recover_rsbs %d rsbs", count);
++}
++
++/* Create a single list of all root rsb's to be used during recovery */
++
++int dlm_create_root_list(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r;
++ int i, error = 0;
++
++ down_write(&ls->ls_root_sem);
++ if (!list_empty(&ls->ls_root_list)) {
++ log_error(ls, "root list not empty");
++ error = -EINVAL;
++ goto out;
++ }
++
++ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
++ read_lock(&ls->ls_rsbtbl[i].lock);
++ list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
++ list_add(&r->res_root_list, &ls->ls_root_list);
++ dlm_hold_rsb(r);
++ }
++ read_unlock(&ls->ls_rsbtbl[i].lock);
++ }
++ out:
++ up_write(&ls->ls_root_sem);
++ return error;
++}
++
++void dlm_release_root_list(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r, *safe;
++
++ down_write(&ls->ls_root_sem);
++ list_for_each_entry_safe(r, safe, &ls->ls_root_list, res_root_list) {
++ list_del_init(&r->res_root_list);
++ dlm_put_rsb(r);
++ }
++ up_write(&ls->ls_root_sem);
++}
++
++void dlm_clear_toss_list(struct dlm_ls *ls)
++{
++ struct dlm_rsb *r, *safe;
++ int i;
++
++ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
++ write_lock(&ls->ls_rsbtbl[i].lock);
++ list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss,
++ res_hashchain) {
++ list_del(&r->res_hashchain);
++ free_rsb(r);
++ }
++ write_unlock(&ls->ls_rsbtbl[i].lock);
++ }
++}
++
+diff --git a/fs/dlm/recover.h b/fs/dlm/recover.h
+new file mode 100644
+index 0000000..ebd0363
+--- /dev/null
++++ b/fs/dlm/recover.h
+@@ -0,0 +1,34 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __RECOVER_DOT_H__
++#define __RECOVER_DOT_H__
++
++int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls));
++uint32_t dlm_recover_status(struct dlm_ls *ls);
++void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status);
++int dlm_recover_members_wait(struct dlm_ls *ls);
++int dlm_recover_directory_wait(struct dlm_ls *ls);
++int dlm_recover_locks_wait(struct dlm_ls *ls);
++int dlm_recover_done_wait(struct dlm_ls *ls);
++int dlm_recover_masters(struct dlm_ls *ls);
++int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc);
++int dlm_recover_locks(struct dlm_ls *ls);
++void dlm_recovered_lock(struct dlm_rsb *r);
++int dlm_create_root_list(struct dlm_ls *ls);
++void dlm_release_root_list(struct dlm_ls *ls);
++void dlm_clear_toss_list(struct dlm_ls *ls);
++void dlm_recover_rsbs(struct dlm_ls *ls);
++
++#endif /* __RECOVER_DOT_H__ */
++
+diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
+new file mode 100644
+index 0000000..362e3ef
+--- /dev/null
++++ b/fs/dlm/recoverd.c
+@@ -0,0 +1,290 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "member.h"
++#include "dir.h"
++#include "ast.h"
++#include "recover.h"
++#include "lowcomms.h"
++#include "lock.h"
++#include "requestqueue.h"
++#include "recoverd.h"
++
++
++/* If the start for which we're re-enabling locking (seq) has been superseded
++ by a newer stop (ls_recover_seq), we need to leave locking disabled. */
++
++static int enable_locking(struct dlm_ls *ls, uint64_t seq)
++{
++ int error = -EINTR;
++
++ spin_lock(&ls->ls_recover_lock);
++ if (ls->ls_recover_seq == seq) {
++ set_bit(LSFL_RUNNING, &ls->ls_flags);
++ up_write(&ls->ls_in_recovery);
++ error = 0;
++ }
++ spin_unlock(&ls->ls_recover_lock);
++ return error;
++}
++
++static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
++{
++ unsigned long start;
++ int error, neg = 0;
++
++ log_debug(ls, "recover %llx", rv->seq);
++
++ mutex_lock(&ls->ls_recoverd_active);
++
++ /*
++ * Suspending and resuming dlm_astd ensures that no lkb's from this ls
++ * will be processed by dlm_astd during recovery.
++ */
++
++ dlm_astd_suspend();
++ dlm_astd_resume();
++
++ /*
++ * This list of root rsb's will be the basis of most of the recovery
++ * routines.
++ */
++
++ dlm_create_root_list(ls);
++
++ /*
++ * Free all the tossed rsb's so we don't have to recover them.
++ */
++
++ dlm_clear_toss_list(ls);
++
++ /*
++ * Add or remove nodes from the lockspace's ls_nodes list.
++ * Also waits for all nodes to complete dlm_recover_members.
++ */
++
++ error = dlm_recover_members(ls, rv, &neg);
++ if (error) {
++ log_error(ls, "recover_members failed %d", error);
++ goto fail;
++ }
++ start = jiffies;
++
++ /*
++ * Rebuild our own share of the directory by collecting from all other
++ * nodes their master rsb names that hash to us.
++ */
++
++ error = dlm_recover_directory(ls);
++ if (error) {
++ log_error(ls, "recover_directory failed %d", error);
++ goto fail;
++ }
++
++ /*
++ * Purge directory-related requests that are saved in requestqueue.
++ * All dir requests from before recovery are invalid now due to the dir
++ * rebuild and will be resent by the requesting nodes.
++ */
++
++ dlm_purge_requestqueue(ls);
++
++ /*
++ * Wait for all nodes to complete directory rebuild.
++ */
++
++ error = dlm_recover_directory_wait(ls);
++ if (error) {
++ log_error(ls, "recover_directory_wait failed %d", error);
++ goto fail;
++ }
++
++ /*
++ * We may have outstanding operations that are waiting for a reply from
++ * a failed node. Mark these to be resent after recovery. Unlock and
++ * cancel ops can just be completed.
++ */
++
++ dlm_recover_waiters_pre(ls);
++
++ error = dlm_recovery_stopped(ls);
++ if (error)
++ goto fail;
++
++ if (neg || dlm_no_directory(ls)) {
++ /*
++ * Clear lkb's for departed nodes.
++ */
++
++ dlm_purge_locks(ls);
++
++ /*
++ * Get new master nodeid's for rsb's that were mastered on
++ * departed nodes.
++ */
++
++ error = dlm_recover_masters(ls);
++ if (error) {
++ log_error(ls, "recover_masters failed %d", error);
++ goto fail;
++ }
++
++ /*
++ * Send our locks on remastered rsb's to the new masters.
++ */
++
++ error = dlm_recover_locks(ls);
++ if (error) {
++ log_error(ls, "recover_locks failed %d", error);
++ goto fail;
++ }
++
++ error = dlm_recover_locks_wait(ls);
++ if (error) {
++ log_error(ls, "recover_locks_wait failed %d", error);
++ goto fail;
++ }
++
++ /*
++ * Finalize state in master rsb's now that all locks can be
++ * checked. This includes conversion resolution and lvb
++ * settings.
++ */
++
++ dlm_recover_rsbs(ls);
++ }
++
++ dlm_release_root_list(ls);
++
++ dlm_set_recover_status(ls, DLM_RS_DONE);
++ error = dlm_recover_done_wait(ls);
++ if (error) {
++ log_error(ls, "recover_done_wait failed %d", error);
++ goto fail;
++ }
++
++ dlm_clear_members_gone(ls);
++
++ error = enable_locking(ls, rv->seq);
++ if (error) {
++ log_error(ls, "enable_locking failed %d", error);
++ goto fail;
++ }
++
++ error = dlm_process_requestqueue(ls);
++ if (error) {
++ log_error(ls, "process_requestqueue failed %d", error);
++ goto fail;
++ }
++
++ error = dlm_recover_waiters_post(ls);
++ if (error) {
++ log_error(ls, "recover_waiters_post failed %d", error);
++ goto fail;
++ }
++
++ dlm_grant_after_purge(ls);
++
++ dlm_astd_wake();
++
++ log_debug(ls, "recover %llx done: %u ms", rv->seq,
++ jiffies_to_msecs(jiffies - start));
++ mutex_unlock(&ls->ls_recoverd_active);
++
++ return 0;
++
++ fail:
++ dlm_release_root_list(ls);
++ log_debug(ls, "recover %llx error %d", rv->seq, error);
++ mutex_unlock(&ls->ls_recoverd_active);
++ return error;
++}
++
++static void do_ls_recovery(struct dlm_ls *ls)
++{
++ struct dlm_recover *rv = NULL;
++
++ spin_lock(&ls->ls_recover_lock);
++ rv = ls->ls_recover_args;
++ ls->ls_recover_args = NULL;
++ clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
++ spin_unlock(&ls->ls_recover_lock);
++
++ if (rv) {
++ ls_recover(ls, rv);
++ kfree(rv->nodeids);
++ kfree(rv);
++ }
++}
++
++static int dlm_recoverd(void *arg)
++{
++ struct dlm_ls *ls;
++
++ ls = dlm_find_lockspace_local(arg);
++ if (!ls) {
++ log_print("dlm_recoverd: no lockspace %p", arg);
++ return -1;
++ }
++
++ while (!kthread_should_stop()) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (!test_bit(LSFL_WORK, &ls->ls_flags))
++ schedule();
++ set_current_state(TASK_RUNNING);
++
++ if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags))
++ do_ls_recovery(ls);
++ }
++
++ dlm_put_lockspace(ls);
++ return 0;
++}
++
++void dlm_recoverd_kick(struct dlm_ls *ls)
++{
++ set_bit(LSFL_WORK, &ls->ls_flags);
++ wake_up_process(ls->ls_recoverd_task);
++}
++
++int dlm_recoverd_start(struct dlm_ls *ls)
++{
++ struct task_struct *p;
++ int error = 0;
++
++ p = kthread_run(dlm_recoverd, ls, "dlm_recoverd");
++ if (IS_ERR(p))
++ error = PTR_ERR(p);
++ else
++ ls->ls_recoverd_task = p;
++ return error;
++}
++
++void dlm_recoverd_stop(struct dlm_ls *ls)
++{
++ kthread_stop(ls->ls_recoverd_task);
++}
++
++void dlm_recoverd_suspend(struct dlm_ls *ls)
++{
++ wake_up(&ls->ls_wait_general);
++ mutex_lock(&ls->ls_recoverd_active);
++}
++
++void dlm_recoverd_resume(struct dlm_ls *ls)
++{
++ mutex_unlock(&ls->ls_recoverd_active);
++}
++
+diff --git a/fs/dlm/recoverd.h b/fs/dlm/recoverd.h
+new file mode 100644
+index 0000000..866657c
+--- /dev/null
++++ b/fs/dlm/recoverd.h
+@@ -0,0 +1,24 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __RECOVERD_DOT_H__
++#define __RECOVERD_DOT_H__
++
++void dlm_recoverd_kick(struct dlm_ls *ls);
++void dlm_recoverd_stop(struct dlm_ls *ls);
++int dlm_recoverd_start(struct dlm_ls *ls);
++void dlm_recoverd_suspend(struct dlm_ls *ls);
++void dlm_recoverd_resume(struct dlm_ls *ls);
++
++#endif /* __RECOVERD_DOT_H__ */
++
+diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
+new file mode 100644
+index 0000000..7b2b089
+--- /dev/null
++++ b/fs/dlm/requestqueue.c
+@@ -0,0 +1,184 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "member.h"
++#include "lock.h"
++#include "dir.h"
++#include "config.h"
++#include "requestqueue.h"
++
++struct rq_entry {
++ struct list_head list;
++ int nodeid;
++ char request[1];
++};
++
++/*
++ * Requests received while the lockspace is in recovery get added to the
++ * request queue and processed when recovery is complete. This happens when
++ * the lockspace is suspended on some nodes before it is on others, or the
++ * lockspace is enabled on some while still suspended on others.
++ */
++
++void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
++{
++ struct rq_entry *e;
++ int length = hd->h_length;
++
++ if (dlm_is_removed(ls, nodeid))
++ return;
++
++ e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
++ if (!e) {
++ log_print("dlm_add_requestqueue: out of memory\n");
++ return;
++ }
++
++ e->nodeid = nodeid;
++ memcpy(e->request, hd, length);
++
++ mutex_lock(&ls->ls_requestqueue_mutex);
++ list_add_tail(&e->list, &ls->ls_requestqueue);
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++}
++
++int dlm_process_requestqueue(struct dlm_ls *ls)
++{
++ struct rq_entry *e;
++ struct dlm_header *hd;
++ int error = 0;
++
++ mutex_lock(&ls->ls_requestqueue_mutex);
++
++ for (;;) {
++ if (list_empty(&ls->ls_requestqueue)) {
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++ error = 0;
++ break;
++ }
++ e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++
++ hd = (struct dlm_header *) e->request;
++ error = dlm_receive_message(hd, e->nodeid, 1);
++
++ if (error == -EINTR) {
++ /* entry is left on requestqueue */
++ log_debug(ls, "process_requestqueue abort eintr");
++ break;
++ }
++
++ mutex_lock(&ls->ls_requestqueue_mutex);
++ list_del(&e->list);
++ kfree(e);
++
++ if (dlm_locking_stopped(ls)) {
++ log_debug(ls, "process_requestqueue abort running");
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++ error = -EINTR;
++ break;
++ }
++ schedule();
++ }
++
++ return error;
++}
++
++/*
++ * After recovery is done, locking is resumed and dlm_recoverd takes all the
++ * saved requests and processes them as they would have been by dlm_recvd. At
++ * the same time, dlm_recvd will start receiving new requests from remote
++ * nodes. We want to delay dlm_recvd processing new requests until
++ * dlm_recoverd has finished processing the old saved requests.
++ */
++
++void dlm_wait_requestqueue(struct dlm_ls *ls)
++{
++ for (;;) {
++ mutex_lock(&ls->ls_requestqueue_mutex);
++ if (list_empty(&ls->ls_requestqueue))
++ break;
++ if (dlm_locking_stopped(ls))
++ break;
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++ schedule();
++ }
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++}
++
++static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)
++{
++ uint32_t type = ms->m_type;
++
++ if (dlm_is_removed(ls, nodeid))
++ return 1;
++
++ /* directory operations are always purged because the directory is
++ always rebuilt during recovery and the lookups resent */
++
++ if (type == DLM_MSG_REMOVE ||
++ type == DLM_MSG_LOOKUP ||
++ type == DLM_MSG_LOOKUP_REPLY)
++ return 1;
++
++ if (!dlm_no_directory(ls))
++ return 0;
++
++ /* with no directory, the master is likely to change as a part of
++ recovery; requests to/from the defunct master need to be purged */
++
++ switch (type) {
++ case DLM_MSG_REQUEST:
++ case DLM_MSG_CONVERT:
++ case DLM_MSG_UNLOCK:
++ case DLM_MSG_CANCEL:
++ /* we're no longer the master of this resource, the sender
++ will resend to the new master (see waiter_needs_recovery) */
++
++ if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
++ return 1;
++ break;
++
++ case DLM_MSG_REQUEST_REPLY:
++ case DLM_MSG_CONVERT_REPLY:
++ case DLM_MSG_UNLOCK_REPLY:
++ case DLM_MSG_CANCEL_REPLY:
++ case DLM_MSG_GRANT:
++ /* this reply is from the former master of the resource,
++ we'll resend to the new master if needed */
++
++ if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
++ return 1;
++ break;
++ }
++
++ return 0;
++}
++
++void dlm_purge_requestqueue(struct dlm_ls *ls)
++{
++ struct dlm_message *ms;
++ struct rq_entry *e, *safe;
++
++ mutex_lock(&ls->ls_requestqueue_mutex);
++ list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) {
++ ms = (struct dlm_message *) e->request;
++
++ if (purge_request(ls, ms, e->nodeid)) {
++ list_del(&e->list);
++ kfree(e);
++ }
++ }
++ mutex_unlock(&ls->ls_requestqueue_mutex);
++}
++
+diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h
+new file mode 100644
+index 0000000..349f0d2
+--- /dev/null
++++ b/fs/dlm/requestqueue.h
+@@ -0,0 +1,22 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __REQUESTQUEUE_DOT_H__
++#define __REQUESTQUEUE_DOT_H__
++
++void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
++int dlm_process_requestqueue(struct dlm_ls *ls);
++void dlm_wait_requestqueue(struct dlm_ls *ls);
++void dlm_purge_requestqueue(struct dlm_ls *ls);
++
++#endif
++
+diff --git a/fs/dlm/user.c b/fs/dlm/user.c
+new file mode 100644
+index 0000000..c37e93e
+--- /dev/null
++++ b/fs/dlm/user.c
+@@ -0,0 +1,788 @@
++/*
++ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License v.2.
++ */
++
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/wait.h>
++#include <linux/module.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/poll.h>
++#include <linux/signal.h>
++#include <linux/spinlock.h>
++#include <linux/dlm.h>
++#include <linux/dlm_device.h>
++
++#include "dlm_internal.h"
++#include "lockspace.h"
++#include "lock.h"
++#include "lvb_table.h"
++
++static const char *name_prefix="dlm";
++static struct miscdevice ctl_device;
++static struct file_operations device_fops;
++
++#ifdef CONFIG_COMPAT
++
++struct dlm_lock_params32 {
++ __u8 mode;
++ __u8 namelen;
++ __u16 flags;
++ __u32 lkid;
++ __u32 parent;
++
++ __u32 castparam;
++ __u32 castaddr;
++ __u32 bastparam;
++ __u32 bastaddr;
++ __u32 lksb;
++
++ char lvb[DLM_USER_LVB_LEN];
++ char name[0];
++};
++
++struct dlm_write_request32 {
++ __u32 version[3];
++ __u8 cmd;
++ __u8 is64bit;
++ __u8 unused[2];
++
++ union {
++ struct dlm_lock_params32 lock;
++ struct dlm_lspace_params lspace;
++ } i;
++};
++
++struct dlm_lksb32 {
++ __u32 sb_status;
++ __u32 sb_lkid;
++ __u8 sb_flags;
++ __u32 sb_lvbptr;
++};
++
++struct dlm_lock_result32 {
++ __u32 length;
++ __u32 user_astaddr;
++ __u32 user_astparam;
++ __u32 user_lksb;
++ struct dlm_lksb32 lksb;
++ __u8 bast_mode;
++ __u8 unused[3];
++ /* Offsets may be zero if no data is present */
++ __u32 lvb_offset;
++};
++
++static void compat_input(struct dlm_write_request *kb,
++ struct dlm_write_request32 *kb32)
++{
++ kb->version[0] = kb32->version[0];
++ kb->version[1] = kb32->version[1];
++ kb->version[2] = kb32->version[2];
++
++ kb->cmd = kb32->cmd;
++ kb->is64bit = kb32->is64bit;
++ if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
++ kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
++ kb->i.lspace.flags = kb32->i.lspace.flags;
++ kb->i.lspace.minor = kb32->i.lspace.minor;
++ strcpy(kb->i.lspace.name, kb32->i.lspace.name);
++ } else {
++ kb->i.lock.mode = kb32->i.lock.mode;
++ kb->i.lock.namelen = kb32->i.lock.namelen;
++ kb->i.lock.flags = kb32->i.lock.flags;
++ kb->i.lock.lkid = kb32->i.lock.lkid;
++ kb->i.lock.parent = kb32->i.lock.parent;
++ kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
++ kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
++ kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
++ kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
++ kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
++ memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
++ memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen);
++ }
++}
++
++static void compat_output(struct dlm_lock_result *res,
++ struct dlm_lock_result32 *res32)
++{
++ res32->length = res->length - (sizeof(struct dlm_lock_result) -
++ sizeof(struct dlm_lock_result32));
++ res32->user_astaddr = (__u32)(long)res->user_astaddr;
++ res32->user_astparam = (__u32)(long)res->user_astparam;
++ res32->user_lksb = (__u32)(long)res->user_lksb;
++ res32->bast_mode = res->bast_mode;
++
++ res32->lvb_offset = res->lvb_offset;
++ res32->length = res->length;
++
++ res32->lksb.sb_status = res->lksb.sb_status;
++ res32->lksb.sb_flags = res->lksb.sb_flags;
++ res32->lksb.sb_lkid = res->lksb.sb_lkid;
++ res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
++}
++#endif
++
++
++void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
++{
++ struct dlm_ls *ls;
++ struct dlm_user_args *ua;
++ struct dlm_user_proc *proc;
++ int remove_ownqueue = 0;
++
++ /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
++ lkb before dealing with it. We need to check this
++ flag before taking ls_clear_proc_locks mutex because if
++ it's set, dlm_clear_proc_locks() holds the mutex. */
++
++ if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
++ /* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */
++ return;
++ }
++
++ ls = lkb->lkb_resource->res_ls;
++ mutex_lock(&ls->ls_clear_proc_locks);
++
++ /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
++ can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
++ lkb->ua so we can't try to use it. */
++
++ if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
++ /* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
++ goto out;
++ }
++
++ DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
++ ua = (struct dlm_user_args *)lkb->lkb_astparam;
++ proc = ua->proc;
++
++ if (type == AST_BAST && ua->bastaddr == NULL)
++ goto out;
++
++ spin_lock(&proc->asts_spin);
++ if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
++ kref_get(&lkb->lkb_ref);
++ list_add_tail(&lkb->lkb_astqueue, &proc->asts);
++ lkb->lkb_ast_type |= type;
++ wake_up_interruptible(&proc->wait);
++ }
++
++ /* noqueue requests that fail may need to be removed from the
++ proc's locks list, there should be a better way of detecting
++ this situation than checking all these things... */
++
++ if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
++ ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
++ remove_ownqueue = 1;
++
++ /* We want to copy the lvb to userspace when the completion
++ ast is read if the status is 0, the lock has an lvb and
++ lvb_ops says we should. We could probably have set_lvb_lock()
++ set update_user_lvb instead and not need old_mode */
++
++ if ((lkb->lkb_ast_type & AST_COMP) &&
++ (lkb->lkb_lksb->sb_status == 0) &&
++ lkb->lkb_lksb->sb_lvbptr &&
++ dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
++ ua->update_user_lvb = 1;
++ else
++ ua->update_user_lvb = 0;
++
++ spin_unlock(&proc->asts_spin);
++
++ if (remove_ownqueue) {
++ spin_lock(&ua->proc->locks_spin);
++ list_del_init(&lkb->lkb_ownqueue);
++ spin_unlock(&ua->proc->locks_spin);
++ dlm_put_lkb(lkb);
++ }
++ out:
++ mutex_unlock(&ls->ls_clear_proc_locks);
++}
++
++static int device_user_lock(struct dlm_user_proc *proc,
++ struct dlm_lock_params *params)
++{
++ struct dlm_ls *ls;
++ struct dlm_user_args *ua;
++ int error = -ENOMEM;
++
++ ls = dlm_find_lockspace_local(proc->lockspace);
++ if (!ls)
++ return -ENOENT;
++
++ if (!params->castaddr || !params->lksb) {
++ error = -EINVAL;
++ goto out;
++ }
++
++ ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
++ if (!ua)
++ goto out;
++ ua->proc = proc;
++ ua->user_lksb = params->lksb;
++ ua->castparam = params->castparam;
++ ua->castaddr = params->castaddr;
++ ua->bastparam = params->bastparam;
++ ua->bastaddr = params->bastaddr;
++
++ if (params->flags & DLM_LKF_CONVERT)
++ error = dlm_user_convert(ls, ua,
++ params->mode, params->flags,
++ params->lkid, params->lvb);
++ else {
++ error = dlm_user_request(ls, ua,
++ params->mode, params->flags,
++ params->name, params->namelen,
++ params->parent);
++ if (!error)
++ error = ua->lksb.sb_lkid;
++ }
++ out:
++ dlm_put_lockspace(ls);
++ return error;
++}
++
++static int device_user_unlock(struct dlm_user_proc *proc,
++ struct dlm_lock_params *params)
++{
++ struct dlm_ls *ls;
++ struct dlm_user_args *ua;
++ int error = -ENOMEM;
++
++ ls = dlm_find_lockspace_local(proc->lockspace);
++ if (!ls)
++ return -ENOENT;
++
++ ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
++ if (!ua)
++ goto out;
++ ua->proc = proc;
++ ua->user_lksb = params->lksb;
++ ua->castparam = params->castparam;
++ ua->castaddr = params->castaddr;
++
++ if (params->flags & DLM_LKF_CANCEL)
++ error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
++ else
++ error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
++ params->lvb);
++ out:
++ dlm_put_lockspace(ls);
++ return error;
++}
++
++static int device_create_lockspace(struct dlm_lspace_params *params)
++{
++ dlm_lockspace_t *lockspace;
++ struct dlm_ls *ls;
++ int error, len;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ error = dlm_new_lockspace(params->name, strlen(params->name),
++ &lockspace, 0, DLM_USER_LVB_LEN);
++ if (error)
++ return error;
++
++ ls = dlm_find_lockspace_local(lockspace);
++ if (!ls)
++ return -ENOENT;
++
++ error = -ENOMEM;
++ len = strlen(params->name) + strlen(name_prefix) + 2;
++ ls->ls_device.name = kzalloc(len, GFP_KERNEL);
++ if (!ls->ls_device.name)
++ goto fail;
++ snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
++ params->name);
++ ls->ls_device.fops = &device_fops;
++ ls->ls_device.minor = MISC_DYNAMIC_MINOR;
++
++ error = misc_register(&ls->ls_device);
++ if (error) {
++ kfree(ls->ls_device.name);
++ goto fail;
++ }
++
++ error = ls->ls_device.minor;
++ dlm_put_lockspace(ls);
++ return error;
++
++ fail:
++ dlm_put_lockspace(ls);
++ dlm_release_lockspace(lockspace, 0);
++ return error;
++}
++
++static int device_remove_lockspace(struct dlm_lspace_params *params)
++{
++ dlm_lockspace_t *lockspace;
++ struct dlm_ls *ls;
++ int error, force = 0;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ ls = dlm_find_lockspace_device(params->minor);
++ if (!ls)
++ return -ENOENT;
++
++ error = misc_deregister(&ls->ls_device);
++ if (error) {
++ dlm_put_lockspace(ls);
++ goto out;
++ }
++ kfree(ls->ls_device.name);
++
++ if (params->flags & DLM_USER_LSFLG_FORCEFREE)
++ force = 2;
++
++ lockspace = ls->ls_local_handle;
++
++ /* dlm_release_lockspace waits for references to go to zero,
++ so all processes will need to close their device for the ls
++ before the release will procede */
++
++ dlm_put_lockspace(ls);
++ error = dlm_release_lockspace(lockspace, force);
++ out:
++ return error;
++}
++
++/* Check the user's version matches ours */
++static int check_version(struct dlm_write_request *req)
++{
++ if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
++ (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
++ req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
++
++ printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
++ "user (%d.%d.%d) kernel (%d.%d.%d)\n",
++ current->comm,
++ current->pid,
++ req->version[0],
++ req->version[1],
++ req->version[2],
++ DLM_DEVICE_VERSION_MAJOR,
++ DLM_DEVICE_VERSION_MINOR,
++ DLM_DEVICE_VERSION_PATCH);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*
++ * device_write
++ *
++ * device_user_lock
++ * dlm_user_request -> request_lock
++ * dlm_user_convert -> convert_lock
++ *
++ * device_user_unlock
++ * dlm_user_unlock -> unlock_lock
++ * dlm_user_cancel -> cancel_lock
++ *
++ * device_create_lockspace
++ * dlm_new_lockspace
++ *
++ * device_remove_lockspace
++ * dlm_release_lockspace
++ */
++
++/* a write to a lockspace device is a lock or unlock request, a write
++ to the control device is to create/remove a lockspace */
++
++static ssize_t device_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct dlm_user_proc *proc = file->private_data;
++ struct dlm_write_request *kbuf;
++ sigset_t tmpsig, allsigs;
++ int error;
++
++#ifdef CONFIG_COMPAT
++ if (count < sizeof(struct dlm_write_request32))
++#else
++ if (count < sizeof(struct dlm_write_request))
++#endif
++ return -EINVAL;
++
++ kbuf = kmalloc(count, GFP_KERNEL);
++ if (!kbuf)
++ return -ENOMEM;
++
++ if (copy_from_user(kbuf, buf, count)) {
++ error = -EFAULT;
++ goto out_free;
++ }
++
++ if (check_version(kbuf)) {
++ error = -EBADE;
++ goto out_free;
++ }
++
++#ifdef CONFIG_COMPAT
++ if (!kbuf->is64bit) {
++ struct dlm_write_request32 *k32buf;
++ k32buf = (struct dlm_write_request32 *)kbuf;
++ kbuf = kmalloc(count + (sizeof(struct dlm_write_request) -
++ sizeof(struct dlm_write_request32)), GFP_KERNEL);
++ if (!kbuf)
++ return -ENOMEM;
++
++ if (proc)
++ set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
++ compat_input(kbuf, k32buf);
++ kfree(k32buf);
++ }
++#endif
++
++ /* do we really need this? can a write happen after a close? */
++ if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
++ test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
++ return -EINVAL;
++
++ sigfillset(&allsigs);
++ sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
++
++ error = -EINVAL;
++
++ switch (kbuf->cmd)
++ {
++ case DLM_USER_LOCK:
++ if (!proc) {
++ log_print("no locking on control device");
++ goto out_sig;
++ }
++ error = device_user_lock(proc, &kbuf->i.lock);
++ break;
++
++ case DLM_USER_UNLOCK:
++ if (!proc) {
++ log_print("no locking on control device");
++ goto out_sig;
++ }
++ error = device_user_unlock(proc, &kbuf->i.lock);
++ break;
++
++ case DLM_USER_CREATE_LOCKSPACE:
++ if (proc) {
++ log_print("create/remove only on control device");
++ goto out_sig;
++ }
++ error = device_create_lockspace(&kbuf->i.lspace);
++ break;
++
++ case DLM_USER_REMOVE_LOCKSPACE:
++ if (proc) {
++ log_print("create/remove only on control device");
++ goto out_sig;
++ }
++ error = device_remove_lockspace(&kbuf->i.lspace);
++ break;
++
++ default:
++ log_print("Unknown command passed to DLM device : %d\n",
++ kbuf->cmd);
++ }
++
++ out_sig:
++ sigprocmask(SIG_SETMASK, &tmpsig, NULL);
++ recalc_sigpending();
++ out_free:
++ kfree(kbuf);
++ return error;
++}
++
++/* Every process that opens the lockspace device has its own "proc" structure
++ hanging off the open file that's used to keep track of locks owned by the
++ process and asts that need to be delivered to the process. */
++
++static int device_open(struct inode *inode, struct file *file)
++{
++ struct dlm_user_proc *proc;
++ struct dlm_ls *ls;
++
++ ls = dlm_find_lockspace_device(iminor(inode));
++ if (!ls)
++ return -ENOENT;
++
++ proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
++ if (!proc) {
++ dlm_put_lockspace(ls);
++ return -ENOMEM;
++ }
++
++ proc->lockspace = ls->ls_local_handle;
++ INIT_LIST_HEAD(&proc->asts);
++ INIT_LIST_HEAD(&proc->locks);
++ spin_lock_init(&proc->asts_spin);
++ spin_lock_init(&proc->locks_spin);
++ init_waitqueue_head(&proc->wait);
++ file->private_data = proc;
++
++ return 0;
++}
++
++static int device_close(struct inode *inode, struct file *file)
++{
++ struct dlm_user_proc *proc = file->private_data;
++ struct dlm_ls *ls;
++ sigset_t tmpsig, allsigs;
++
++ ls = dlm_find_lockspace_local(proc->lockspace);
++ if (!ls)
++ return -ENOENT;
++
++ sigfillset(&allsigs);
++ sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
++
++ set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
++
++ dlm_clear_proc_locks(ls, proc);
++
++ /* at this point no more lkb's should exist for this lockspace,
++ so there's no chance of dlm_user_add_ast() being called and
++ looking for lkb->ua->proc */
++
++ kfree(proc);
++ file->private_data = NULL;
++
++ dlm_put_lockspace(ls);
++ dlm_put_lockspace(ls); /* for the find in device_open() */
++
++ /* FIXME: AUTOFREE: if this ls is no longer used do
++ device_remove_lockspace() */
++
++ sigprocmask(SIG_SETMASK, &tmpsig, NULL);
++ recalc_sigpending();
++
++ return 0;
++}
++
++static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
++ int bmode, char __user *buf, size_t count)
++{
++#ifdef CONFIG_COMPAT
++ struct dlm_lock_result32 result32;
++#endif
++ struct dlm_lock_result result;
++ void *resultptr;
++ int error=0;
++ int len;
++ int struct_len;
++
++ memset(&result, 0, sizeof(struct dlm_lock_result));
++ memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
++ result.user_lksb = ua->user_lksb;
++
++ /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
++ in a conversion unless the conversion is successful. See code
++ in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though,
++ notes that a new blocking AST address and parameter are set even if
++ the conversion fails, so maybe we should just do that. */
++
++ if (type == AST_BAST) {
++ result.user_astaddr = ua->bastaddr;
++ result.user_astparam = ua->bastparam;
++ result.bast_mode = bmode;
++ } else {
++ result.user_astaddr = ua->castaddr;
++ result.user_astparam = ua->castparam;
++ }
++
++#ifdef CONFIG_COMPAT
++ if (compat)
++ len = sizeof(struct dlm_lock_result32);
++ else
++#endif
++ len = sizeof(struct dlm_lock_result);
++ struct_len = len;
++
++ /* copy lvb to userspace if there is one, it's been updated, and
++ the user buffer has space for it */
++
++ if (ua->update_user_lvb && ua->lksb.sb_lvbptr &&
++ count >= len + DLM_USER_LVB_LEN) {
++ if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
++ DLM_USER_LVB_LEN)) {
++ error = -EFAULT;
++ goto out;
++ }
++
++ result.lvb_offset = len;
++ len += DLM_USER_LVB_LEN;
++ }
++
++ result.length = len;
++ resultptr = &result;
++#ifdef CONFIG_COMPAT
++ if (compat) {
++ compat_output(&result, &result32);
++ resultptr = &result32;
++ }
++#endif
++
++ if (copy_to_user(buf, resultptr, struct_len))
++ error = -EFAULT;
++ else
++ error = len;
++ out:
++ return error;
++}
++
++/* a read returns a single ast described in a struct dlm_lock_result */
++
++static ssize_t device_read(struct file *file, char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ struct dlm_user_proc *proc = file->private_data;
++ struct dlm_lkb *lkb;
++ struct dlm_user_args *ua;
++ DECLARE_WAITQUEUE(wait, current);
++ int error, type=0, bmode=0, removed = 0;
++
++#ifdef CONFIG_COMPAT
++ if (count < sizeof(struct dlm_lock_result32))
++#else
++ if (count < sizeof(struct dlm_lock_result))
++#endif
++ return -EINVAL;
++
++ /* do we really need this? can a read happen after a close? */
++ if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
++ return -EINVAL;
++
++ spin_lock(&proc->asts_spin);
++ if (list_empty(&proc->asts)) {
++ if (file->f_flags & O_NONBLOCK) {
++ spin_unlock(&proc->asts_spin);
++ return -EAGAIN;
++ }
++
++ add_wait_queue(&proc->wait, &wait);
++
++ repeat:
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (list_empty(&proc->asts) && !signal_pending(current)) {
++ spin_unlock(&proc->asts_spin);
++ schedule();
++ spin_lock(&proc->asts_spin);
++ goto repeat;
++ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&proc->wait, &wait);
++
++ if (signal_pending(current)) {
++ spin_unlock(&proc->asts_spin);
++ return -ERESTARTSYS;
++ }
++ }
++
++ if (list_empty(&proc->asts)) {
++ spin_unlock(&proc->asts_spin);
++ return -EAGAIN;
++ }
++
++ /* there may be both completion and blocking asts to return for
++ the lkb, don't remove lkb from asts list unless no asts remain */
++
++ lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
++
++ if (lkb->lkb_ast_type & AST_COMP) {
++ lkb->lkb_ast_type &= ~AST_COMP;
++ type = AST_COMP;
++ } else if (lkb->lkb_ast_type & AST_BAST) {
++ lkb->lkb_ast_type &= ~AST_BAST;
++ type = AST_BAST;
++ bmode = lkb->lkb_bastmode;
++ }
++
++ if (!lkb->lkb_ast_type) {
++ list_del(&lkb->lkb_astqueue);
++ removed = 1;
++ }
++ spin_unlock(&proc->asts_spin);
++
++ ua = (struct dlm_user_args *)lkb->lkb_astparam;
++ error = copy_result_to_user(ua,
++ test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
++ type, bmode, buf, count);
++
++ /* removes reference for the proc->asts lists added by
++ dlm_user_add_ast() and may result in the lkb being freed */
++ if (removed)
++ dlm_put_lkb(lkb);
++
++ return error;
++}
++
++static unsigned int device_poll(struct file *file, poll_table *wait)
++{
++ struct dlm_user_proc *proc = file->private_data;
++
++ poll_wait(file, &proc->wait, wait);
++
++ spin_lock(&proc->asts_spin);
++ if (!list_empty(&proc->asts)) {
++ spin_unlock(&proc->asts_spin);
++ return POLLIN | POLLRDNORM;
++ }
++ spin_unlock(&proc->asts_spin);
++ return 0;
++}
++
++static int ctl_device_open(struct inode *inode, struct file *file)
++{
++ file->private_data = NULL;
++ return 0;
++}
++
++static int ctl_device_close(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static struct file_operations device_fops = {
++ .open = device_open,
++ .release = device_close,
++ .read = device_read,
++ .write = device_write,
++ .poll = device_poll,
++ .owner = THIS_MODULE,
++};
++
++static struct file_operations ctl_device_fops = {
++ .open = ctl_device_open,
++ .release = ctl_device_close,
++ .write = device_write,
++ .owner = THIS_MODULE,
++};
++
++int dlm_user_init(void)
++{
++ int error;
++
++ ctl_device.name = "dlm-control";
++ ctl_device.fops = &ctl_device_fops;
++ ctl_device.minor = MISC_DYNAMIC_MINOR;
++
++ error = misc_register(&ctl_device);
++ if (error)
++ log_print("misc_register failed for control device");
++
++ return error;
++}
++
++void dlm_user_exit(void)
++{
++ misc_deregister(&ctl_device);
++}
++
+diff --git a/fs/dlm/user.h b/fs/dlm/user.h
+new file mode 100644
+index 0000000..d38e9f3
+--- /dev/null
++++ b/fs/dlm/user.h
+@@ -0,0 +1,16 @@
++/*
++ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License v.2.
++ */
++
++#ifndef __USER_DOT_H__
++#define __USER_DOT_H__
++
++void dlm_user_add_ast(struct dlm_lkb *lkb, int type);
++int dlm_user_init(void);
++void dlm_user_exit(void);
++
++#endif
+diff --git a/fs/dlm/util.c b/fs/dlm/util.c
+new file mode 100644
+index 0000000..767197d
+--- /dev/null
++++ b/fs/dlm/util.c
+@@ -0,0 +1,161 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#include "dlm_internal.h"
++#include "rcom.h"
++#include "util.h"
++
++static void header_out(struct dlm_header *hd)
++{
++ hd->h_version = cpu_to_le32(hd->h_version);
++ hd->h_lockspace = cpu_to_le32(hd->h_lockspace);
++ hd->h_nodeid = cpu_to_le32(hd->h_nodeid);
++ hd->h_length = cpu_to_le16(hd->h_length);
++}
++
++static void header_in(struct dlm_header *hd)
++{
++ hd->h_version = le32_to_cpu(hd->h_version);
++ hd->h_lockspace = le32_to_cpu(hd->h_lockspace);
++ hd->h_nodeid = le32_to_cpu(hd->h_nodeid);
++ hd->h_length = le16_to_cpu(hd->h_length);
++}
++
++void dlm_message_out(struct dlm_message *ms)
++{
++ struct dlm_header *hd = (struct dlm_header *) ms;
++
++ header_out(hd);
++
++ ms->m_type = cpu_to_le32(ms->m_type);
++ ms->m_nodeid = cpu_to_le32(ms->m_nodeid);
++ ms->m_pid = cpu_to_le32(ms->m_pid);
++ ms->m_lkid = cpu_to_le32(ms->m_lkid);
++ ms->m_remid = cpu_to_le32(ms->m_remid);
++ ms->m_parent_lkid = cpu_to_le32(ms->m_parent_lkid);
++ ms->m_parent_remid = cpu_to_le32(ms->m_parent_remid);
++ ms->m_exflags = cpu_to_le32(ms->m_exflags);
++ ms->m_sbflags = cpu_to_le32(ms->m_sbflags);
++ ms->m_flags = cpu_to_le32(ms->m_flags);
++ ms->m_lvbseq = cpu_to_le32(ms->m_lvbseq);
++ ms->m_hash = cpu_to_le32(ms->m_hash);
++ ms->m_status = cpu_to_le32(ms->m_status);
++ ms->m_grmode = cpu_to_le32(ms->m_grmode);
++ ms->m_rqmode = cpu_to_le32(ms->m_rqmode);
++ ms->m_bastmode = cpu_to_le32(ms->m_bastmode);
++ ms->m_asts = cpu_to_le32(ms->m_asts);
++ ms->m_result = cpu_to_le32(ms->m_result);
++}
++
++void dlm_message_in(struct dlm_message *ms)
++{
++ struct dlm_header *hd = (struct dlm_header *) ms;
++
++ header_in(hd);
++
++ ms->m_type = le32_to_cpu(ms->m_type);
++ ms->m_nodeid = le32_to_cpu(ms->m_nodeid);
++ ms->m_pid = le32_to_cpu(ms->m_pid);
++ ms->m_lkid = le32_to_cpu(ms->m_lkid);
++ ms->m_remid = le32_to_cpu(ms->m_remid);
++ ms->m_parent_lkid = le32_to_cpu(ms->m_parent_lkid);
++ ms->m_parent_remid = le32_to_cpu(ms->m_parent_remid);
++ ms->m_exflags = le32_to_cpu(ms->m_exflags);
++ ms->m_sbflags = le32_to_cpu(ms->m_sbflags);
++ ms->m_flags = le32_to_cpu(ms->m_flags);
++ ms->m_lvbseq = le32_to_cpu(ms->m_lvbseq);
++ ms->m_hash = le32_to_cpu(ms->m_hash);
++ ms->m_status = le32_to_cpu(ms->m_status);
++ ms->m_grmode = le32_to_cpu(ms->m_grmode);
++ ms->m_rqmode = le32_to_cpu(ms->m_rqmode);
++ ms->m_bastmode = le32_to_cpu(ms->m_bastmode);
++ ms->m_asts = le32_to_cpu(ms->m_asts);
++ ms->m_result = le32_to_cpu(ms->m_result);
++}
++
++static void rcom_lock_out(struct rcom_lock *rl)
++{
++ rl->rl_ownpid = cpu_to_le32(rl->rl_ownpid);
++ rl->rl_lkid = cpu_to_le32(rl->rl_lkid);
++ rl->rl_remid = cpu_to_le32(rl->rl_remid);
++ rl->rl_parent_lkid = cpu_to_le32(rl->rl_parent_lkid);
++ rl->rl_parent_remid = cpu_to_le32(rl->rl_parent_remid);
++ rl->rl_exflags = cpu_to_le32(rl->rl_exflags);
++ rl->rl_flags = cpu_to_le32(rl->rl_flags);
++ rl->rl_lvbseq = cpu_to_le32(rl->rl_lvbseq);
++ rl->rl_result = cpu_to_le32(rl->rl_result);
++ rl->rl_wait_type = cpu_to_le16(rl->rl_wait_type);
++ rl->rl_namelen = cpu_to_le16(rl->rl_namelen);
++}
++
++static void rcom_lock_in(struct rcom_lock *rl)
++{
++ rl->rl_ownpid = le32_to_cpu(rl->rl_ownpid);
++ rl->rl_lkid = le32_to_cpu(rl->rl_lkid);
++ rl->rl_remid = le32_to_cpu(rl->rl_remid);
++ rl->rl_parent_lkid = le32_to_cpu(rl->rl_parent_lkid);
++ rl->rl_parent_remid = le32_to_cpu(rl->rl_parent_remid);
++ rl->rl_exflags = le32_to_cpu(rl->rl_exflags);
++ rl->rl_flags = le32_to_cpu(rl->rl_flags);
++ rl->rl_lvbseq = le32_to_cpu(rl->rl_lvbseq);
++ rl->rl_result = le32_to_cpu(rl->rl_result);
++ rl->rl_wait_type = le16_to_cpu(rl->rl_wait_type);
++ rl->rl_namelen = le16_to_cpu(rl->rl_namelen);
++}
++
++static void rcom_config_out(struct rcom_config *rf)
++{
++ rf->rf_lvblen = cpu_to_le32(rf->rf_lvblen);
++ rf->rf_lsflags = cpu_to_le32(rf->rf_lsflags);
++}
++
++static void rcom_config_in(struct rcom_config *rf)
++{
++ rf->rf_lvblen = le32_to_cpu(rf->rf_lvblen);
++ rf->rf_lsflags = le32_to_cpu(rf->rf_lsflags);
++}
++
++void dlm_rcom_out(struct dlm_rcom *rc)
++{
++ struct dlm_header *hd = (struct dlm_header *) rc;
++ int type = rc->rc_type;
++
++ header_out(hd);
++
++ rc->rc_type = cpu_to_le32(rc->rc_type);
++ rc->rc_result = cpu_to_le32(rc->rc_result);
++ rc->rc_id = cpu_to_le64(rc->rc_id);
++
++ if (type == DLM_RCOM_LOCK)
++ rcom_lock_out((struct rcom_lock *) rc->rc_buf);
++
++ else if (type == DLM_RCOM_STATUS_REPLY)
++ rcom_config_out((struct rcom_config *) rc->rc_buf);
++}
++
++void dlm_rcom_in(struct dlm_rcom *rc)
++{
++ struct dlm_header *hd = (struct dlm_header *) rc;
++
++ header_in(hd);
++
++ rc->rc_type = le32_to_cpu(rc->rc_type);
++ rc->rc_result = le32_to_cpu(rc->rc_result);
++ rc->rc_id = le64_to_cpu(rc->rc_id);
++
++ if (rc->rc_type == DLM_RCOM_LOCK)
++ rcom_lock_in((struct rcom_lock *) rc->rc_buf);
++
++ else if (rc->rc_type == DLM_RCOM_STATUS_REPLY)
++ rcom_config_in((struct rcom_config *) rc->rc_buf);
++}
++
+diff --git a/fs/dlm/util.h b/fs/dlm/util.h
+new file mode 100644
+index 0000000..2b25915
+--- /dev/null
++++ b/fs/dlm/util.h
+@@ -0,0 +1,22 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __UTIL_DOT_H__
++#define __UTIL_DOT_H__
++
++void dlm_message_out(struct dlm_message *ms);
++void dlm_message_in(struct dlm_message *ms);
++void dlm_rcom_out(struct dlm_rcom *rc);
++void dlm_rcom_in(struct dlm_rcom *rc);
++
++#endif
++
+diff --git a/fs/dnotify.c b/fs/dnotify.c
+index f932591..2b0442d 100644
+--- a/fs/dnotify.c
++++ b/fs/dnotify.c
+@@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file
+ prev = &odn->dn_next;
+ }
+
+- error = f_setown(filp, current->pid, 0);
++ error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
+ if (error)
+ goto out_free;
+
+diff --git a/fs/dquot.c b/fs/dquot.c
+index 0122a27..9af7895 100644
+--- a/fs/dquot.c
++++ b/fs/dquot.c
+@@ -834,6 +834,9 @@ static void print_warning(struct dquot *
+ if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
+ return;
+
++ mutex_lock(&tty_mutex);
++ if (!current->signal->tty)
++ goto out_lock;
+ tty_write_message(current->signal->tty, dquot->dq_sb->s_id);
+ if (warntype == ISOFTWARN || warntype == BSOFTWARN)
+ tty_write_message(current->signal->tty, ": warning, ");
+@@ -861,6 +864,8 @@ static void print_warning(struct dquot *
+ break;
+ }
+ tty_write_message(current->signal->tty, msg);
++out_lock:
++ mutex_unlock(&tty_mutex);
+ }
+
+ static inline void flush_warnings(struct dquot **dquots, char *warntype)
+diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
+new file mode 100644
+index 0000000..ca65624
+--- /dev/null
++++ b/fs/ecryptfs/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the Linux 2.6 eCryptfs
++#
++
++obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
++
++ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o debug.o
+diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
+new file mode 100644
+index 0000000..136175a
+--- /dev/null
++++ b/fs/ecryptfs/crypto.c
+@@ -0,0 +1,1673 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ *
++ * Copyright (C) 1997-2004 Erez Zadok
++ * Copyright (C) 2001-2004 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at us.ibm.com>
++ * Michael C. Thompson <mcthomps at 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/fs.h>
++#include <linux/mount.h>
++#include <linux/pagemap.h>
++#include <linux/random.h>
++#include <linux/compiler.h>
++#include <linux/key.h>
++#include <linux/namei.h>
++#include <linux/crypto.h>
++#include <linux/file.h>
++#include <linux/scatterlist.h>
++#include "ecryptfs_kernel.h"
++
++static int
++ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
++ struct page *dst_page, int dst_offset,
++ struct page *src_page, int src_offset, int size,
++ unsigned char *iv);
++static int
++ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
++ struct page *dst_page, int dst_offset,
++ struct page *src_page, int src_offset, int size,
++ unsigned char *iv);
++
++/**
++ * ecryptfs_to_hex
++ * @dst: Buffer to take hex character representation of contents of
++ * src; must be at least of size (src_size * 2)
++ * @src: Buffer to be converted to a hex string respresentation
++ * @src_size: number of bytes to convert
++ */
++void ecryptfs_to_hex(char *dst, char *src, size_t src_size)
++{
++ int x;
++
++ for (x = 0; x < src_size; x++)
++ sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
++}
++
++/**
++ * ecryptfs_from_hex
++ * @dst: Buffer to take the bytes from src hex; must be at least of
++ * size (src_size / 2)
++ * @src: Buffer to be converted from a hex string respresentation to raw value
++ * @dst_size: size of dst buffer, or number of hex characters pairs to convert
++ */
++void ecryptfs_from_hex(char *dst, char *src, int dst_size)
++{
++ int x;
++ char tmp[3] = { 0, };
++
++ for (x = 0; x < dst_size; x++) {
++ tmp[0] = src[x * 2];
++ tmp[1] = src[x * 2 + 1];
++ dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);
++ }
++}
++
++/**
++ * ecryptfs_calculate_md5 - calculates the md5 of @src
++ * @dst: Pointer to 16 bytes of allocated memory
++ * @crypt_stat: Pointer to crypt_stat struct for the current inode
++ * @src: Data to be md5'd
++ * @len: Length of @src
++ *
++ * Uses the allocated crypto context that crypt_stat references to
++ * generate the MD5 sum of the contents of src.
++ */
++static int ecryptfs_calculate_md5(char *dst,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ char *src, int len)
++{
++ struct scatterlist sg;
++ struct hash_desc desc = {
++ .tfm = crypt_stat->hash_tfm,
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP
++ };
++ int rc = 0;
++
++ mutex_lock(&crypt_stat->cs_hash_tfm_mutex);
++ sg_init_one(&sg, (u8 *)src, len);
++ if (!desc.tfm) {
++ desc.tfm = crypto_alloc_hash(ECRYPTFS_DEFAULT_HASH, 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(desc.tfm)) {
++ rc = PTR_ERR(desc.tfm);
++ ecryptfs_printk(KERN_ERR, "Error attempting to "
++ "allocate crypto context; rc = [%d]\n",
++ rc);
++ goto out;
++ }
++ crypt_stat->hash_tfm = desc.tfm;
++ }
++ crypto_hash_init(&desc);
++ crypto_hash_update(&desc, &sg, len);
++ crypto_hash_final(&desc, dst);
++ mutex_unlock(&crypt_stat->cs_hash_tfm_mutex);
++out:
++ return rc;
++}
++
++int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,
++ char *cipher_name,
++ char *chaining_modifier)
++{
++ int cipher_name_len = strlen(cipher_name);
++ int chaining_modifier_len = strlen(chaining_modifier);
++ int algified_name_len;
++ int rc;
++
++ algified_name_len = (chaining_modifier_len + cipher_name_len + 3);
++ (*algified_name) = kmalloc(algified_name_len, GFP_KERNEL);
++ if (!(*algified_name)) {
++ rc = -ENOMEM;
++ goto out;
++ }
++ snprintf((*algified_name), algified_name_len, "%s(%s)",
++ chaining_modifier, cipher_name);
++ rc = 0;
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_derive_iv
++ * @iv: destination for the derived iv vale
++ * @crypt_stat: Pointer to crypt_stat struct for the current inode
++ * @offset: Offset of the page whose's iv we are to derive
++ *
++ * Generate the initialization vector from the given root IV and page
++ * offset.
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
++ pgoff_t offset)
++{
++ int rc = 0;
++ char dst[MD5_DIGEST_SIZE];
++ char src[ECRYPTFS_MAX_IV_BYTES + 16];
++
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "root iv:\n");
++ ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes);
++ }
++ /* TODO: It is probably secure to just cast the least
++ * significant bits of the root IV into an unsigned long and
++ * add the offset to that rather than go through all this
++ * hashing business. -Halcrow */
++ memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);
++ memset((src + crypt_stat->iv_bytes), 0, 16);
++ snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset);
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "source:\n");
++ ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));
++ }
++ rc = ecryptfs_calculate_md5(dst, crypt_stat, src,
++ (crypt_stat->iv_bytes + 16));
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
++ "MD5 while generating IV for a page\n");
++ goto out;
++ }
++ memcpy(iv, dst, crypt_stat->iv_bytes);
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "derived iv:\n");
++ ecryptfs_dump_hex(iv, crypt_stat->iv_bytes);
++ }
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_init_crypt_stat
++ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
++ *
++ * Initialize the crypt_stat structure.
++ */
++void
++ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
++ mutex_init(&crypt_stat->cs_mutex);
++ mutex_init(&crypt_stat->cs_tfm_mutex);
++ mutex_init(&crypt_stat->cs_hash_tfm_mutex);
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED);
++}
++
++/**
++ * ecryptfs_destruct_crypt_stat
++ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
++ *
++ * Releases all memory associated with a crypt_stat struct.
++ */
++void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ if (crypt_stat->tfm)
++ crypto_free_blkcipher(crypt_stat->tfm);
++ if (crypt_stat->hash_tfm)
++ crypto_free_hash(crypt_stat->hash_tfm);
++ memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
++}
++
++void ecryptfs_destruct_mount_crypt_stat(
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
++{
++ if (mount_crypt_stat->global_auth_tok_key)
++ key_put(mount_crypt_stat->global_auth_tok_key);
++ if (mount_crypt_stat->global_key_tfm)
++ crypto_free_blkcipher(mount_crypt_stat->global_key_tfm);
++ memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
++}
++
++/**
++ * virt_to_scatterlist
++ * @addr: Virtual address
++ * @size: Size of data; should be an even multiple of the block size
++ * @sg: Pointer to scatterlist array; set to NULL to obtain only
++ * the number of scatterlist structs required in array
++ * @sg_size: Max array size
++ *
++ * Fills in a scatterlist array with page references for a passed
++ * virtual address.
++ *
++ * Returns the number of scatterlist structs in array used
++ */
++int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
++ int sg_size)
++{
++ int i = 0;
++ struct page *pg;
++ int offset;
++ int remainder_of_page;
++
++ while (size > 0 && i < sg_size) {
++ pg = virt_to_page(addr);
++ offset = offset_in_page(addr);
++ if (sg) {
++ sg[i].page = pg;
++ sg[i].offset = offset;
++ }
++ remainder_of_page = PAGE_CACHE_SIZE - offset;
++ if (size >= remainder_of_page) {
++ if (sg)
++ sg[i].length = remainder_of_page;
++ addr += remainder_of_page;
++ size -= remainder_of_page;
++ } else {
++ if (sg)
++ sg[i].length = size;
++ addr += size;
++ size = 0;
++ }
++ i++;
++ }
++ if (size > 0)
++ return -ENOMEM;
++ return i;
++}
++
++/**
++ * encrypt_scatterlist
++ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
++ * @dest_sg: Destination of encrypted data
++ * @src_sg: Data to be encrypted
++ * @size: Length of data to be encrypted
++ * @iv: iv to use during encryption
++ *
++ * Returns the number of bytes encrypted; negative value on error
++ */
++static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
++ struct scatterlist *dest_sg,
++ struct scatterlist *src_sg, int size,
++ unsigned char *iv)
++{
++ struct blkcipher_desc desc = {
++ .tfm = crypt_stat->tfm,
++ .info = iv,
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP
++ };
++ int rc = 0;
++
++ BUG_ON(!crypt_stat || !crypt_stat->tfm
++ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
++ ECRYPTFS_STRUCT_INITIALIZED));
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n",
++ crypt_stat->key_size);
++ ecryptfs_dump_hex(crypt_stat->key,
++ crypt_stat->key_size);
++ }
++ /* Consider doing this once, when the file is opened */
++ mutex_lock(&crypt_stat->cs_tfm_mutex);
++ rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
++ crypt_stat->key_size);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
++ rc);
++ mutex_unlock(&crypt_stat->cs_tfm_mutex);
++ rc = -EINVAL;
++ goto out;
++ }
++ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
++ crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size);
++ mutex_unlock(&crypt_stat->cs_tfm_mutex);
++out:
++ return rc;
++}
++
++static void
++ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
++ int *byte_offset,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ unsigned long extent_num)
++{
++ unsigned long lower_extent_num;
++ int extents_occupied_by_headers_at_front;
++ int bytes_occupied_by_headers_at_front;
++ int extent_offset;
++ int extents_per_page;
++
++ bytes_occupied_by_headers_at_front =
++ ( crypt_stat->header_extent_size
++ * crypt_stat->num_header_extents_at_front );
++ extents_occupied_by_headers_at_front =
++ ( bytes_occupied_by_headers_at_front
++ / crypt_stat->extent_size );
++ lower_extent_num = extents_occupied_by_headers_at_front + extent_num;
++ extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
++ (*lower_page_idx) = lower_extent_num / extents_per_page;
++ extent_offset = lower_extent_num % extents_per_page;
++ (*byte_offset) = extent_offset * crypt_stat->extent_size;
++ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = "
++ "[%d]\n", crypt_stat->header_extent_size);
++ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->"
++ "num_header_extents_at_front = [%d]\n",
++ crypt_stat->num_header_extents_at_front);
++ ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_"
++ "front = [%d]\n", extents_occupied_by_headers_at_front);
++ ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n",
++ lower_extent_num);
++ ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n",
++ extents_per_page);
++ ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n",
++ (*lower_page_idx));
++ ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n",
++ extent_offset);
++ ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n",
++ (*byte_offset));
++}
++
++static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx,
++ struct page *lower_page,
++ struct inode *lower_inode,
++ int byte_offset_in_page, int bytes_to_write)
++{
++ int rc = 0;
++
++ if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
++ rc = ecryptfs_commit_lower_page(lower_page, lower_inode,
++ ctx->param.lower_file,
++ byte_offset_in_page,
++ bytes_to_write);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error calling lower "
++ "commit; rc = [%d]\n", rc);
++ goto out;
++ }
++ } else {
++ rc = ecryptfs_writepage_and_release_lower_page(lower_page,
++ lower_inode,
++ ctx->param.wbc);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error calling lower "
++ "writepage(); rc = [%d]\n", rc);
++ goto out;
++ }
++ }
++out:
++ return rc;
++}
++
++static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx,
++ struct page **lower_page,
++ struct inode *lower_inode,
++ unsigned long lower_page_idx,
++ int byte_offset_in_page)
++{
++ int rc = 0;
++
++ if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
++ /* TODO: Limit this to only the data extents that are
++ * needed */
++ rc = ecryptfs_get_lower_page(lower_page, lower_inode,
++ ctx->param.lower_file,
++ lower_page_idx,
++ byte_offset_in_page,
++ (PAGE_CACHE_SIZE
++ - byte_offset_in_page));
++ if (rc) {
++ ecryptfs_printk(
++ KERN_ERR, "Error attempting to grab, map, "
++ "and prepare_write lower page with index "
++ "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc);
++ goto out;
++ }
++ } else {
++ rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL,
++ lower_inode,
++ lower_page_idx);
++ if (rc) {
++ ecryptfs_printk(
++ KERN_ERR, "Error attempting to grab and map "
++ "lower page with index [0x%.16x]; rc = [%d]\n",
++ lower_page_idx, rc);
++ goto out;
++ }
++ }
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_encrypt_page
++ * @ctx: The context of the page
++ *
++ * Encrypt an eCryptfs page. This is done on a per-extent basis. Note
++ * that eCryptfs pages may straddle the lower pages -- for instance,
++ * if the file was created on a machine with an 8K page size
++ * (resulting in an 8K header), and then the file is copied onto a
++ * host with a 32K page size, then when reading page 0 of the eCryptfs
++ * file, 24K of page 0 of the lower file will be read and decrypted,
++ * and then 8K of page 1 of the lower file will be read and decrypted.
++ *
++ * The actual operations performed on each page depends on the
++ * contents of the ecryptfs_page_crypt_context struct.
++ *
++ * Returns zero on success; negative on error
++ */
++int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx)
++{
++ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
++ unsigned long base_extent;
++ unsigned long extent_offset = 0;
++ unsigned long lower_page_idx = 0;
++ unsigned long prior_lower_page_idx = 0;
++ struct page *lower_page;
++ struct inode *lower_inode;
++ struct ecryptfs_inode_info *inode_info;
++ struct ecryptfs_crypt_stat *crypt_stat;
++ int rc = 0;
++ int lower_byte_offset = 0;
++ int orig_byte_offset = 0;
++ int num_extents_per_page;
++#define ECRYPTFS_PAGE_STATE_UNREAD 0
++#define ECRYPTFS_PAGE_STATE_READ 1
++#define ECRYPTFS_PAGE_STATE_MODIFIED 2
++#define ECRYPTFS_PAGE_STATE_WRITTEN 3
++ int page_state;
++
++ lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host);
++ inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host);
++ crypt_stat = &inode_info->crypt_stat;
++ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
++ rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode,
++ ctx->param.lower_file);
++ if (rc)
++ ecryptfs_printk(KERN_ERR, "Error attempting to copy "
++ "page at index [0x%.16x]\n",
++ ctx->page->index);
++ goto out;
++ }
++ num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
++ base_extent = (ctx->page->index * num_extents_per_page);
++ page_state = ECRYPTFS_PAGE_STATE_UNREAD;
++ while (extent_offset < num_extents_per_page) {
++ ecryptfs_extent_to_lwr_pg_idx_and_offset(
++ &lower_page_idx, &lower_byte_offset, crypt_stat,
++ (base_extent + extent_offset));
++ if (prior_lower_page_idx != lower_page_idx
++ && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
++ rc = ecryptfs_write_out_page(ctx, lower_page,
++ lower_inode,
++ orig_byte_offset,
++ (PAGE_CACHE_SIZE
++ - orig_byte_offset));
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting "
++ "to write out page; rc = [%d]"
++ "\n", rc);
++ goto out;
++ }
++ page_state = ECRYPTFS_PAGE_STATE_WRITTEN;
++ }
++ if (page_state == ECRYPTFS_PAGE_STATE_UNREAD
++ || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
++ rc = ecryptfs_read_in_page(ctx, &lower_page,
++ lower_inode, lower_page_idx,
++ lower_byte_offset);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting "
++ "to read in lower page with "
++ "index [0x%.16x]; rc = [%d]\n",
++ lower_page_idx, rc);
++ goto out;
++ }
++ orig_byte_offset = lower_byte_offset;
++ prior_lower_page_idx = lower_page_idx;
++ page_state = ECRYPTFS_PAGE_STATE_READ;
++ }
++ BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED
++ || page_state == ECRYPTFS_PAGE_STATE_READ));
++ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
++ (base_extent + extent_offset));
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to "
++ "derive IV for extent [0x%.16x]; "
++ "rc = [%d]\n",
++ (base_extent + extent_offset), rc);
++ goto out;
++ }
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
++ "with iv:\n");
++ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
++ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
++ "encryption:\n");
++ ecryptfs_dump_hex((char *)
++ (page_address(ctx->page)
++ + (extent_offset
++ * crypt_stat->extent_size)), 8);
++ }
++ rc = ecryptfs_encrypt_page_offset(
++ crypt_stat, lower_page, lower_byte_offset, ctx->page,
++ (extent_offset * crypt_stat->extent_size),
++ crypt_stat->extent_size, extent_iv);
++ ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
++ "rc = [%d]\n",
++ (base_extent + extent_offset), rc);
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
++ "encryption:\n");
++ ecryptfs_dump_hex((char *)(page_address(lower_page)
++ + lower_byte_offset), 8);
++ }
++ page_state = ECRYPTFS_PAGE_STATE_MODIFIED;
++ extent_offset++;
++ }
++ BUG_ON(orig_byte_offset != 0);
++ rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
++ (lower_byte_offset
++ + crypt_stat->extent_size));
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to write out "
++ "page; rc = [%d]\n", rc);
++ goto out;
++ }
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_decrypt_page
++ * @file: The ecryptfs file
++ * @page: The page in ecryptfs to decrypt
++ *
++ * Decrypt an eCryptfs page. This is done on a per-extent basis. Note
++ * that eCryptfs pages may straddle the lower pages -- for instance,
++ * if the file was created on a machine with an 8K page size
++ * (resulting in an 8K header), and then the file is copied onto a
++ * host with a 32K page size, then when reading page 0 of the eCryptfs
++ * file, 24K of page 0 of the lower file will be read and decrypted,
++ * and then 8K of page 1 of the lower file will be read and decrypted.
++ *
++ * Returns zero on success; negative on error
++ */
++int ecryptfs_decrypt_page(struct file *file, struct page *page)
++{
++ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
++ unsigned long base_extent;
++ unsigned long extent_offset = 0;
++ unsigned long lower_page_idx = 0;
++ unsigned long prior_lower_page_idx = 0;
++ struct page *lower_page;
++ char *lower_page_virt = NULL;
++ struct inode *lower_inode;
++ struct ecryptfs_crypt_stat *crypt_stat;
++ int rc = 0;
++ int byte_offset;
++ int num_extents_per_page;
++ int page_state;
++
++ crypt_stat = &(ecryptfs_inode_to_private(
++ page->mapping->host)->crypt_stat);
++ lower_inode = ecryptfs_inode_to_lower(page->mapping->host);
++ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
++ rc = ecryptfs_do_readpage(file, page, page->index);
++ if (rc)
++ ecryptfs_printk(KERN_ERR, "Error attempting to copy "
++ "page at index [0x%.16x]\n",
++ page->index);
++ goto out;
++ }
++ num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
++ base_extent = (page->index * num_extents_per_page);
++ lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache,
++ SLAB_KERNEL);
++ if (!lower_page_virt) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_ERR, "Error getting page for encrypted "
++ "lower page(s)\n");
++ goto out;
++ }
++ lower_page = virt_to_page(lower_page_virt);
++ page_state = ECRYPTFS_PAGE_STATE_UNREAD;
++ while (extent_offset < num_extents_per_page) {
++ ecryptfs_extent_to_lwr_pg_idx_and_offset(
++ &lower_page_idx, &byte_offset, crypt_stat,
++ (base_extent + extent_offset));
++ if (prior_lower_page_idx != lower_page_idx
++ || page_state == ECRYPTFS_PAGE_STATE_UNREAD) {
++ rc = ecryptfs_do_readpage(file, lower_page,
++ lower_page_idx);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error reading "
++ "lower encrypted page; rc = "
++ "[%d]\n", rc);
++ goto out;
++ }
++ prior_lower_page_idx = lower_page_idx;
++ page_state = ECRYPTFS_PAGE_STATE_READ;
++ }
++ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
++ (base_extent + extent_offset));
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to "
++ "derive IV for extent [0x%.16x]; rc = "
++ "[%d]\n",
++ (base_extent + extent_offset), rc);
++ goto out;
++ }
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
++ "with iv:\n");
++ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
++ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
++ "decryption:\n");
++ ecryptfs_dump_hex((lower_page_virt + byte_offset), 8);
++ }
++ rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
++ (extent_offset
++ * crypt_stat->extent_size),
++ lower_page, byte_offset,
++ crypt_stat->extent_size,
++ extent_iv);
++ if (rc != crypt_stat->extent_size) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to "
++ "decrypt extent [0x%.16x]\n",
++ (base_extent + extent_offset));
++ goto out;
++ }
++ rc = 0;
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
++ "decryption:\n");
++ ecryptfs_dump_hex((char *)(page_address(page)
++ + byte_offset), 8);
++ }
++ extent_offset++;
++ }
++out:
++ if (lower_page_virt)
++ kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt);
++ return rc;
++}
++
++/**
++ * decrypt_scatterlist
++ *
++ * Returns the number of bytes decrypted; negative value on error
++ */
++static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
++ struct scatterlist *dest_sg,
++ struct scatterlist *src_sg, int size,
++ unsigned char *iv)
++{
++ struct blkcipher_desc desc = {
++ .tfm = crypt_stat->tfm,
++ .info = iv,
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP
++ };
++ int rc = 0;
++
++ /* Consider doing this once, when the file is opened */
++ mutex_lock(&crypt_stat->cs_tfm_mutex);
++ rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
++ crypt_stat->key_size);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
++ rc);
++ mutex_unlock(&crypt_stat->cs_tfm_mutex);
++ rc = -EINVAL;
++ goto out;
++ }
++ ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
++ rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size);
++ mutex_unlock(&crypt_stat->cs_tfm_mutex);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n",
++ rc);
++ goto out;
++ }
++ rc = size;
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_encrypt_page_offset
++ *
++ * Returns the number of bytes encrypted
++ */
++static int
++ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
++ struct page *dst_page, int dst_offset,
++ struct page *src_page, int src_offset, int size,
++ unsigned char *iv)
++{
++ struct scatterlist src_sg, dst_sg;
++
++ src_sg.page = src_page;
++ src_sg.offset = src_offset;
++ src_sg.length = size;
++ dst_sg.page = dst_page;
++ dst_sg.offset = dst_offset;
++ dst_sg.length = size;
++ return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
++}
++
++/**
++ * ecryptfs_decrypt_page_offset
++ *
++ * Returns the number of bytes decrypted
++ */
++static int
++ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
++ struct page *dst_page, int dst_offset,
++ struct page *src_page, int src_offset, int size,
++ unsigned char *iv)
++{
++ struct scatterlist src_sg, dst_sg;
++
++ src_sg.page = src_page;
++ src_sg.offset = src_offset;
++ src_sg.length = size;
++ dst_sg.page = dst_page;
++ dst_sg.offset = dst_offset;
++ dst_sg.length = size;
++ return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
++}
++
++#define ECRYPTFS_MAX_SCATTERLIST_LEN 4
++
++/**
++ * ecryptfs_init_crypt_ctx
++ * @crypt_stat: Uninitilized crypt stats structure
++ *
++ * Initialize the crypto context.
++ *
++ * TODO: Performance: Keep a cache of initialized cipher contexts;
++ * only init if needed
++ */
++int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ char *full_alg_name;
++ int rc = -EINVAL;
++
++ if (!crypt_stat->cipher) {
++ ecryptfs_printk(KERN_ERR, "No cipher specified\n");
++ goto out;
++ }
++ ecryptfs_printk(KERN_DEBUG,
++ "Initializing cipher [%s]; strlen = [%d]; "
++ "key_size_bits = [%d]\n",
++ crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
++ crypt_stat->key_size << 3);
++ if (crypt_stat->tfm) {
++ rc = 0;
++ goto out;
++ }
++ mutex_lock(&crypt_stat->cs_tfm_mutex);
++ rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
++ crypt_stat->cipher, "cbc");
++ if (rc)
++ goto out;
++ crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0,
++ CRYPTO_ALG_ASYNC);
++ kfree(full_alg_name);
++ if (!crypt_stat->tfm) {
++ ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
++ "Error initializing cipher [%s]\n",
++ crypt_stat->cipher);
++ mutex_unlock(&crypt_stat->cs_tfm_mutex);
++ goto out;
++ }
++ crypto_blkcipher_set_flags(crypt_stat->tfm,
++ (ECRYPTFS_DEFAULT_CHAINING_MODE
++ | CRYPTO_TFM_REQ_WEAK_KEY));
++ mutex_unlock(&crypt_stat->cs_tfm_mutex);
++ rc = 0;
++out:
++ return rc;
++}
++
++static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ int extent_size_tmp;
++
++ crypt_stat->extent_mask = 0xFFFFFFFF;
++ crypt_stat->extent_shift = 0;
++ if (crypt_stat->extent_size == 0)
++ return;
++ extent_size_tmp = crypt_stat->extent_size;
++ while ((extent_size_tmp & 0x01) == 0) {
++ extent_size_tmp >>= 1;
++ crypt_stat->extent_mask <<= 1;
++ crypt_stat->extent_shift++;
++ }
++}
++
++void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ /* Default values; may be overwritten as we are parsing the
++ * packets. */
++ crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;
++ set_extent_mask_and_shift(crypt_stat);
++ crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
++ if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
++ crypt_stat->header_extent_size =
++ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
++ } else
++ crypt_stat->header_extent_size = PAGE_CACHE_SIZE;
++ crypt_stat->num_header_extents_at_front = 1;
++}
++
++/**
++ * ecryptfs_compute_root_iv
++ * @crypt_stats
++ *
++ * On error, sets the root IV to all 0's.
++ */
++int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ int rc = 0;
++ char dst[MD5_DIGEST_SIZE];
++
++ BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE);
++ BUG_ON(crypt_stat->iv_bytes <= 0);
++ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_WARNING, "Session key not valid; "
++ "cannot generate root IV\n");
++ goto out;
++ }
++ rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,
++ crypt_stat->key_size);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
++ "MD5 while generating root IV\n");
++ goto out;
++ }
++ memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes);
++out:
++ if (rc) {
++ memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes);
++ ECRYPTFS_SET_FLAG(crypt_stat->flags,
++ ECRYPTFS_SECURITY_WARNING);
++ }
++ return rc;
++}
++
++static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ get_random_bytes(crypt_stat->key, crypt_stat->key_size);
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
++ ecryptfs_compute_root_iv(crypt_stat);
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n");
++ ecryptfs_dump_hex(crypt_stat->key,
++ crypt_stat->key_size);
++ }
++}
++
++/**
++ * ecryptfs_set_default_crypt_stat_vals
++ * @crypt_stat
++ *
++ * Default values in the event that policy does not override them.
++ */
++static void ecryptfs_set_default_crypt_stat_vals(
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
++{
++ ecryptfs_set_default_sizes(crypt_stat);
++ strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER);
++ crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES;
++ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
++ crypt_stat->file_version = ECRYPTFS_FILE_VERSION;
++ crypt_stat->mount_crypt_stat = mount_crypt_stat;
++}
++
++/**
++ * ecryptfs_new_file_context
++ * @ecryptfs_dentry
++ *
++ * If the crypto context for the file has not yet been established,
++ * this is where we do that. Establishing a new crypto context
++ * involves the following decisions:
++ * - What cipher to use?
++ * - What set of authentication tokens to use?
++ * Here we just worry about getting enough information into the
++ * authentication tokens so that we know that they are available.
++ * We associate the available authentication tokens with the new file
++ * via the set of signatures in the crypt_stat struct. Later, when
++ * the headers are actually written out, we may again defer to
++ * userspace to perform the encryption of the session key; for the
++ * foreseeable future, this will be the case with public key packets.
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++/* Associate an authentication token(s) with the file */
++int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)
++{
++ int rc = 0;
++ struct ecryptfs_crypt_stat *crypt_stat =
++ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
++ &ecryptfs_superblock_to_private(
++ ecryptfs_dentry->d_sb)->mount_crypt_stat;
++ int cipher_name_len;
++
++ ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);
++ /* See if there are mount crypt options */
++ if (mount_crypt_stat->global_auth_tok) {
++ ecryptfs_printk(KERN_DEBUG, "Initializing context for new "
++ "file using mount_crypt_stat\n");
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
++ memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++],
++ mount_crypt_stat->global_auth_tok_sig,
++ ECRYPTFS_SIG_SIZE_HEX);
++ cipher_name_len =
++ strlen(mount_crypt_stat->global_default_cipher_name);
++ memcpy(crypt_stat->cipher,
++ mount_crypt_stat->global_default_cipher_name,
++ cipher_name_len);
++ crypt_stat->cipher[cipher_name_len] = '\0';
++ crypt_stat->key_size =
++ mount_crypt_stat->global_default_cipher_key_size;
++ ecryptfs_generate_new_key(crypt_stat);
++ } else
++ /* We should not encounter this scenario since we
++ * should detect lack of global_auth_tok at mount time
++ * TODO: Applies to 0.1 release only; remove in future
++ * release */
++ BUG();
++ rc = ecryptfs_init_crypt_ctx(crypt_stat);
++ if (rc)
++ ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
++ "context for cipher [%s]: rc = [%d]\n",
++ crypt_stat->cipher, rc);
++ return rc;
++}
++
++/**
++ * contains_ecryptfs_marker - check for the ecryptfs marker
++ * @data: The data block in which to check
++ *
++ * Returns one if marker found; zero if not found
++ */
++int contains_ecryptfs_marker(char *data)
++{
++ u32 m_1, m_2;
++
++ memcpy(&m_1, data, 4);
++ m_1 = be32_to_cpu(m_1);
++ memcpy(&m_2, (data + 4), 4);
++ m_2 = be32_to_cpu(m_2);
++ if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)
++ return 1;
++ ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; "
++ "MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2,
++ MAGIC_ECRYPTFS_MARKER);
++ ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = "
++ "[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER));
++ return 0;
++}
++
++struct ecryptfs_flag_map_elem {
++ u32 file_flag;
++ u32 local_flag;
++};
++
++/* Add support for additional flags by adding elements here. */
++static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {
++ {0x00000001, ECRYPTFS_ENABLE_HMAC},
++ {0x00000002, ECRYPTFS_ENCRYPTED}
++};
++
++/**
++ * ecryptfs_process_flags
++ * @crypt_stat
++ * @page_virt: Source data to be parsed
++ * @bytes_read: Updated with the number of bytes read
++ *
++ * Returns zero on success; non-zero if the flag set is invalid
++ */
++static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat,
++ char *page_virt, int *bytes_read)
++{
++ int rc = 0;
++ int i;
++ u32 flags;
++
++ memcpy(&flags, page_virt, 4);
++ flags = be32_to_cpu(flags);
++ for (i = 0; i < ((sizeof(ecryptfs_flag_map)
++ / sizeof(struct ecryptfs_flag_map_elem))); i++)
++ if (flags & ecryptfs_flag_map[i].file_flag) {
++ ECRYPTFS_SET_FLAG(crypt_stat->flags,
++ ecryptfs_flag_map[i].local_flag);
++ } else
++ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
++ ecryptfs_flag_map[i].local_flag);
++ /* Version is in top 8 bits of the 32-bit flag vector */
++ crypt_stat->file_version = ((flags >> 24) & 0xFF);
++ (*bytes_read) = 4;
++ return rc;
++}
++
++/**
++ * write_ecryptfs_marker
++ * @page_virt: The pointer to in a page to begin writing the marker
++ * @written: Number of bytes written
++ *
++ * Marker = 0x3c81b7f5
++ */
++static void write_ecryptfs_marker(char *page_virt, size_t *written)
++{
++ u32 m_1, m_2;
++
++ get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
++ m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER);
++ m_1 = cpu_to_be32(m_1);
++ memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
++ m_2 = cpu_to_be32(m_2);
++ memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2,
++ (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
++ (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
++}
++
++static void
++write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
++ size_t *written)
++{
++ u32 flags = 0;
++ int i;
++
++ for (i = 0; i < ((sizeof(ecryptfs_flag_map)
++ / sizeof(struct ecryptfs_flag_map_elem))); i++)
++ if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
++ ecryptfs_flag_map[i].local_flag))
++ flags |= ecryptfs_flag_map[i].file_flag;
++ /* Version is in top 8 bits of the 32-bit flag vector */
++ flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000);
++ flags = cpu_to_be32(flags);
++ memcpy(page_virt, &flags, 4);
++ (*written) = 4;
++}
++
++struct ecryptfs_cipher_code_str_map_elem {
++ char cipher_str[16];
++ u16 cipher_code;
++};
++
++/* Add support for additional ciphers by adding elements here. The
++ * cipher_code is whatever OpenPGP applicatoins use to identify the
++ * ciphers. List in order of probability. */
++static struct ecryptfs_cipher_code_str_map_elem
++ecryptfs_cipher_code_str_map[] = {
++ {"aes",RFC2440_CIPHER_AES_128 },
++ {"blowfish", RFC2440_CIPHER_BLOWFISH},
++ {"des3_ede", RFC2440_CIPHER_DES3_EDE},
++ {"cast5", RFC2440_CIPHER_CAST_5},
++ {"twofish", RFC2440_CIPHER_TWOFISH},
++ {"cast6", RFC2440_CIPHER_CAST_6},
++ {"aes", RFC2440_CIPHER_AES_192},
++ {"aes", RFC2440_CIPHER_AES_256}
++};
++
++/**
++ * ecryptfs_code_for_cipher_string
++ * @str: The string representing the cipher name
++ *
++ * Returns zero on no match, or the cipher code on match
++ */
++u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ int i;
++ u16 code = 0;
++ struct ecryptfs_cipher_code_str_map_elem *map =
++ ecryptfs_cipher_code_str_map;
++
++ if (strcmp(crypt_stat->cipher, "aes") == 0) {
++ switch (crypt_stat->key_size) {
++ case 16:
++ code = RFC2440_CIPHER_AES_128;
++ break;
++ case 24:
++ code = RFC2440_CIPHER_AES_192;
++ break;
++ case 32:
++ code = RFC2440_CIPHER_AES_256;
++ }
++ } else {
++ for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
++ if (strcmp(crypt_stat->cipher, map[i].cipher_str) == 0){
++ code = map[i].cipher_code;
++ break;
++ }
++ }
++ return code;
++}
++
++/**
++ * ecryptfs_cipher_code_to_string
++ * @str: Destination to write out the cipher name
++ * @cipher_code: The code to convert to cipher name string
++ *
++ * Returns zero on success
++ */
++int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
++{
++ int rc = 0;
++ int i;
++
++ str[0] = '\0';
++ for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
++ if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)
++ strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);
++ if (str[0] == '\0') {
++ ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: "
++ "[%d]\n", cipher_code);
++ rc = -EINVAL;
++ }
++ return rc;
++}
++
++/**
++ * ecryptfs_read_header_region
++ * @data
++ * @dentry
++ * @nd
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++int ecryptfs_read_header_region(char *data, struct dentry *dentry,
++ struct vfsmount *mnt)
++{
++ struct file *lower_file;
++ mm_segment_t oldfs;
++ int rc;
++
++ if ((rc = ecryptfs_open_lower_file(&lower_file, dentry, mnt,
++ O_RDONLY))) {
++ printk(KERN_ERR
++ "Error opening lower_file to read header region\n");
++ goto out;
++ }
++ lower_file->f_pos = 0;
++ oldfs = get_fs();
++ set_fs(get_ds());
++ /* For releases 0.1 and 0.2, all of the header information
++ * fits in the first data extent-sized region. */
++ rc = lower_file->f_op->read(lower_file, (char __user *)data,
++ ECRYPTFS_DEFAULT_EXTENT_SIZE, &lower_file->f_pos);
++ set_fs(oldfs);
++ if ((rc = ecryptfs_close_lower_file(lower_file))) {
++ printk(KERN_ERR "Error closing lower_file\n");
++ goto out;
++ }
++ rc = 0;
++out:
++ return rc;
++}
++
++static void
++write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat,
++ size_t *written)
++{
++ u32 header_extent_size;
++ u16 num_header_extents_at_front;
++
++ header_extent_size = (u32)crypt_stat->header_extent_size;
++ num_header_extents_at_front =
++ (u16)crypt_stat->num_header_extents_at_front;
++ header_extent_size = cpu_to_be32(header_extent_size);
++ memcpy(virt, &header_extent_size, 4);
++ virt += 4;
++ num_header_extents_at_front = cpu_to_be16(num_header_extents_at_front);
++ memcpy(virt, &num_header_extents_at_front, 2);
++ (*written) = 6;
++}
++
++struct kmem_cache *ecryptfs_header_cache_0;
++struct kmem_cache *ecryptfs_header_cache_1;
++struct kmem_cache *ecryptfs_header_cache_2;
++
++/**
++ * ecryptfs_write_headers_virt
++ * @page_virt
++ * @crypt_stat
++ * @ecryptfs_dentry
++ *
++ * Format version: 1
++ *
++ * Header Extent:
++ * Octets 0-7: Unencrypted file size (big-endian)
++ * Octets 8-15: eCryptfs special marker
++ * Octets 16-19: Flags
++ * Octet 16: File format version number (between 0 and 255)
++ * Octets 17-18: Reserved
++ * Octet 19: Bit 1 (lsb): Reserved
++ * Bit 2: Encrypted?
++ * Bits 3-8: Reserved
++ * Octets 20-23: Header extent size (big-endian)
++ * Octets 24-25: Number of header extents at front of file
++ * (big-endian)
++ * Octet 26: Begin RFC 2440 authentication token packet set
++ * Data Extent 0:
++ * Lower data (CBC encrypted)
++ * Data Extent 1:
++ * Lower data (CBC encrypted)
++ * ...
++ *
++ * Returns zero on success
++ */
++int ecryptfs_write_headers_virt(char *page_virt,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct dentry *ecryptfs_dentry)
++{
++ int rc;
++ size_t written;
++ size_t offset;
++
++ offset = ECRYPTFS_FILE_SIZE_BYTES;
++ write_ecryptfs_marker((page_virt + offset), &written);
++ offset += written;
++ write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
++ offset += written;
++ write_header_metadata((page_virt + offset), crypt_stat, &written);
++ offset += written;
++ rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,
++ ecryptfs_dentry, &written,
++ PAGE_CACHE_SIZE - offset);
++ if (rc)
++ ecryptfs_printk(KERN_WARNING, "Error generating key packet "
++ "set; rc = [%d]\n", rc);
++ return rc;
++}
++
++/**
++ * ecryptfs_write_headers
++ * @lower_file: The lower file struct, which was returned from dentry_open
++ *
++ * Write the file headers out. This will likely involve a userspace
++ * callout, in which the session key is encrypted with one or more
++ * public keys and/or the passphrase necessary to do the encryption is
++ * retrieved via a prompt. Exactly what happens at this point should
++ * be policy-dependent.
++ *
++ * Returns zero on success; non-zero on error
++ */
++int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
++ struct file *lower_file)
++{
++ mm_segment_t oldfs;
++ struct ecryptfs_crypt_stat *crypt_stat;
++ char *page_virt;
++ int current_header_page;
++ int header_pages;
++ int rc = 0;
++
++ crypt_stat = &ecryptfs_inode_to_private(
++ ecryptfs_dentry->d_inode)->crypt_stat;
++ if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
++ ECRYPTFS_ENCRYPTED))) {
++ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
++ ECRYPTFS_KEY_VALID)) {
++ ecryptfs_printk(KERN_DEBUG, "Key is "
++ "invalid; bailing out\n");
++ rc = -EINVAL;
++ goto out;
++ }
++ } else {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_WARNING,
++ "Called with crypt_stat->encrypted == 0\n");
++ goto out;
++ }
++ /* Released in this function */
++ page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER);
++ if (!page_virt) {
++ ecryptfs_printk(KERN_ERR, "Out of memory\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ memset(page_virt, 0, PAGE_CACHE_SIZE);
++ rc = ecryptfs_write_headers_virt(page_virt, crypt_stat,
++ ecryptfs_dentry);
++ if (unlikely(rc)) {
++ ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
++ memset(page_virt, 0, PAGE_CACHE_SIZE);
++ goto out_free;
++ }
++ ecryptfs_printk(KERN_DEBUG,
++ "Writing key packet set to underlying file\n");
++ lower_file->f_pos = 0;
++ oldfs = get_fs();
++ set_fs(get_ds());
++ ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
++ "write() w/ header page; lower_file->f_pos = "
++ "[0x%.16x]\n", lower_file->f_pos);
++ lower_file->f_op->write(lower_file, (char __user *)page_virt,
++ PAGE_CACHE_SIZE, &lower_file->f_pos);
++ header_pages = ((crypt_stat->header_extent_size
++ * crypt_stat->num_header_extents_at_front)
++ / PAGE_CACHE_SIZE);
++ memset(page_virt, 0, PAGE_CACHE_SIZE);
++ current_header_page = 1;
++ while (current_header_page < header_pages) {
++ ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
++ "write() w/ zero'd page; lower_file->f_pos = "
++ "[0x%.16x]\n", lower_file->f_pos);
++ lower_file->f_op->write(lower_file, (char __user *)page_virt,
++ PAGE_CACHE_SIZE, &lower_file->f_pos);
++ current_header_page++;
++ }
++ set_fs(oldfs);
++ ecryptfs_printk(KERN_DEBUG,
++ "Done writing key packet set to underlying file.\n");
++out_free:
++ kmem_cache_free(ecryptfs_header_cache_0, page_virt);
++out:
++ return rc;
++}
++
++static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
++ char *virt, int *bytes_read)
++{
++ int rc = 0;
++ u32 header_extent_size;
++ u16 num_header_extents_at_front;
++
++ memcpy(&header_extent_size, virt, 4);
++ header_extent_size = be32_to_cpu(header_extent_size);
++ virt += 4;
++ memcpy(&num_header_extents_at_front, virt, 2);
++ num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
++ crypt_stat->header_extent_size = (int)header_extent_size;
++ crypt_stat->num_header_extents_at_front =
++ (int)num_header_extents_at_front;
++ (*bytes_read) = 6;
++ if ((crypt_stat->header_extent_size
++ * crypt_stat->num_header_extents_at_front)
++ < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_WARNING, "Invalid header extent size: "
++ "[%d]\n", crypt_stat->header_extent_size);
++ }
++ return rc;
++}
++
++/**
++ * set_default_header_data
++ *
++ * For version 0 file format; this function is only for backwards
++ * compatibility for files created with the prior versions of
++ * eCryptfs.
++ */
++static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
++{
++ crypt_stat->header_extent_size = 4096;
++ crypt_stat->num_header_extents_at_front = 1;
++}
++
++/**
++ * ecryptfs_read_headers_virt
++ *
++ * Read/parse the header data. The header format is detailed in the
++ * comment block for the ecryptfs_write_headers_virt() function.
++ *
++ * Returns zero on success
++ */
++static int ecryptfs_read_headers_virt(char *page_virt,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct dentry *ecryptfs_dentry)
++{
++ int rc = 0;
++ int offset;
++ int bytes_read;
++
++ ecryptfs_set_default_sizes(crypt_stat);
++ crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private(
++ ecryptfs_dentry->d_sb)->mount_crypt_stat;
++ offset = ECRYPTFS_FILE_SIZE_BYTES;
++ rc = contains_ecryptfs_marker(page_virt + offset);
++ if (rc == 0) {
++ rc = -EINVAL;
++ goto out;
++ }
++ offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
++ rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
++ &bytes_read);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error processing flags\n");
++ goto out;
++ }
++ if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) {
++ ecryptfs_printk(KERN_WARNING, "File version is [%d]; only "
++ "file version [%d] is supported by this "
++ "version of eCryptfs\n",
++ crypt_stat->file_version,
++ ECRYPTFS_SUPPORTED_FILE_VERSION);
++ rc = -EINVAL;
++ goto out;
++ }
++ offset += bytes_read;
++ if (crypt_stat->file_version >= 1) {
++ rc = parse_header_metadata(crypt_stat, (page_virt + offset),
++ &bytes_read);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error reading header "
++ "metadata; rc = [%d]\n", rc);
++ }
++ offset += bytes_read;
++ } else
++ set_default_header_data(crypt_stat);
++ rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),
++ ecryptfs_dentry);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_read_headers
++ *
++ * Returns zero if valid headers found and parsed; non-zero otherwise
++ */
++int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
++ struct file *lower_file)
++{
++ int rc = 0;
++ char *page_virt = NULL;
++ mm_segment_t oldfs;
++ ssize_t bytes_read;
++ struct ecryptfs_crypt_stat *crypt_stat =
++ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
++
++ /* Read the first page from the underlying file */
++ page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER);
++ if (!page_virt) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n");
++ goto out;
++ }
++ lower_file->f_pos = 0;
++ oldfs = get_fs();
++ set_fs(get_ds());
++ bytes_read = lower_file->f_op->read(lower_file,
++ (char __user *)page_virt,
++ ECRYPTFS_DEFAULT_EXTENT_SIZE,
++ &lower_file->f_pos);
++ set_fs(oldfs);
++ if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) {
++ rc = -EINVAL;
++ goto out;
++ }
++ rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,
++ ecryptfs_dentry);
++ if (rc) {
++ ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not "
++ "found\n");
++ rc = -EINVAL;
++ }
++out:
++ if (page_virt) {
++ memset(page_virt, 0, PAGE_CACHE_SIZE);
++ kmem_cache_free(ecryptfs_header_cache_1, page_virt);
++ }
++ return rc;
++}
++
++/**
++ * ecryptfs_encode_filename - converts a plaintext file name to cipher text
++ * @crypt_stat: The crypt_stat struct associated with the file anem to encode
++ * @name: The plaintext name
++ * @length: The length of the plaintext
++ * @encoded_name: The encypted name
++ *
++ * Encrypts and encodes a filename into something that constitutes a
++ * valid filename for a filesystem, with printable characters.
++ *
++ * We assume that we have a properly initialized crypto context,
++ * pointed to by crypt_stat->tfm.
++ *
++ * TODO: Implement filename decoding and decryption here, in place of
++ * memcpy. We are keeping the framework around for now to (1)
++ * facilitate testing of the components needed to implement filename
++ * encryption and (2) to provide a code base from which other
++ * developers in the community can easily implement this feature.
++ *
++ * Returns the length of encoded filename; negative if error
++ */
++int
++ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
++ const char *name, int length, char **encoded_name)
++{
++ int error = 0;
++
++ (*encoded_name) = kmalloc(length + 2, GFP_KERNEL);
++ if (!(*encoded_name)) {
++ error = -ENOMEM;
++ goto out;
++ }
++ /* TODO: Filename encryption is a scheduled feature for a
++ * future version of eCryptfs. This function is here only for
++ * the purpose of providing a framework for other developers
++ * to easily implement filename encryption. Hint: Replace this
++ * memcpy() with a call to encrypt and encode the
++ * filename, the set the length accordingly. */
++ memcpy((void *)(*encoded_name), (void *)name, length);
++ (*encoded_name)[length] = '\0';
++ error = length + 1;
++out:
++ return error;
++}
++
++/**
++ * ecryptfs_decode_filename - converts the cipher text name to plaintext
++ * @crypt_stat: The crypt_stat struct associated with the file
++ * @name: The filename in cipher text
++ * @length: The length of the cipher text name
++ * @decrypted_name: The plaintext name
++ *
++ * Decodes and decrypts the filename.
++ *
++ * We assume that we have a properly initialized crypto context,
++ * pointed to by crypt_stat->tfm.
++ *
++ * TODO: Implement filename decoding and decryption here, in place of
++ * memcpy. We are keeping the framework around for now to (1)
++ * facilitate testing of the components needed to implement filename
++ * encryption and (2) to provide a code base from which other
++ * developers in the community can easily implement this feature.
++ *
++ * Returns the length of decoded filename; negative if error
++ */
++int
++ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
++ const char *name, int length, char **decrypted_name)
++{
++ int error = 0;
++
++ (*decrypted_name) = kmalloc(length + 2, GFP_KERNEL);
++ if (!(*decrypted_name)) {
++ error = -ENOMEM;
++ goto out;
++ }
++ /* TODO: Filename encryption is a scheduled feature for a
++ * future version of eCryptfs. This function is here only for
++ * the purpose of providing a framework for other developers
++ * to easily implement filename encryption. Hint: Replace this
++ * memcpy() with a call to decode and decrypt the
++ * filename, the set the length accordingly. */
++ memcpy((void *)(*decrypted_name), (void *)name, length);
++ (*decrypted_name)[length + 1] = '\0'; /* Only for convenience
++ * in printing out the
++ * string in debug
++ * messages */
++ error = length;
++out:
++ return error;
++}
++
++/**
++ * ecryptfs_process_cipher - Perform cipher initialization.
++ * @key_tfm: Crypto context for key material, set by this function
++ * @cipher_name: Name of the cipher
++ * @key_size: Size of the key in bytes
++ *
++ * Returns zero on success. Any crypto_tfm structs allocated here
++ * should be released by other functions, such as on a superblock put
++ * event, regardless of whether this function succeeds for fails.
++ */
++int
++ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name,
++ size_t *key_size)
++{
++ char dummy_key[ECRYPTFS_MAX_KEY_BYTES];
++ char *full_alg_name;
++ int rc;
++
++ *key_tfm = NULL;
++ if (*key_size > ECRYPTFS_MAX_KEY_BYTES) {
++ rc = -EINVAL;
++ printk(KERN_ERR "Requested key size is [%Zd] bytes; maximum "
++ "allowable is [%d]\n", *key_size, ECRYPTFS_MAX_KEY_BYTES);
++ goto out;
++ }
++ rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, cipher_name,
++ "ecb");
++ if (rc)
++ goto out;
++ *key_tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC);
++ kfree(full_alg_name);
++ if (IS_ERR(*key_tfm)) {
++ rc = PTR_ERR(*key_tfm);
++ printk(KERN_ERR "Unable to allocate crypto cipher with name "
++ "[%s]; rc = [%d]\n", cipher_name, rc);
++ goto out;
++ }
++ crypto_blkcipher_set_flags(*key_tfm, CRYPTO_TFM_REQ_WEAK_KEY);
++ if (*key_size == 0) {
++ struct blkcipher_alg *alg = crypto_blkcipher_alg(*key_tfm);
++
++ *key_size = alg->max_keysize;
++ }
++ get_random_bytes(dummy_key, *key_size);
++ rc = crypto_blkcipher_setkey(*key_tfm, dummy_key, *key_size);
++ if (rc) {
++ printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
++ "cipher [%s]; rc = [%d]\n", *key_size, cipher_name, rc);
++ rc = -EINVAL;
++ goto out;
++ }
++out:
++ return rc;
++}
+diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c
+new file mode 100644
+index 0000000..61f8e89
+--- /dev/null
++++ b/fs/ecryptfs/debug.c
+@@ -0,0 +1,123 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ * Functions only useful for debugging.
++ *
++ * Copyright (C) 2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at 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 "ecryptfs_kernel.h"
++
++/**
++ * ecryptfs_dump_auth_tok - debug function to print auth toks
++ *
++ * This function will print the contents of an ecryptfs authentication
++ * token.
++ */
++void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)
++{
++ char salt[ECRYPTFS_SALT_SIZE * 2 + 1];
++ char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
++
++ ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n",
++ auth_tok);
++ if (ECRYPTFS_CHECK_FLAG(auth_tok->flags, ECRYPTFS_PRIVATE_KEY)) {
++ ecryptfs_printk(KERN_DEBUG, " * private key type\n");
++ ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT "
++ "IN ECRYPTFS VERSION 0.1)\n");
++ } else {
++ ecryptfs_printk(KERN_DEBUG, " * passphrase type\n");
++ ecryptfs_to_hex(salt, auth_tok->token.password.salt,
++ ECRYPTFS_SALT_SIZE);
++ salt[ECRYPTFS_SALT_SIZE * 2] = '\0';
++ ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt);
++ if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
++ ECRYPTFS_PERSISTENT_PASSWORD)) {
++ ecryptfs_printk(KERN_DEBUG, " * persistent\n");
++ }
++ memcpy(sig, auth_tok->token.password.signature,
++ ECRYPTFS_SIG_SIZE_HEX);
++ sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
++ ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig);
++ }
++ ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n",
++ auth_tok->session_key.flags);
++ if (auth_tok->session_key.flags
++ & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)
++ ecryptfs_printk(KERN_DEBUG,
++ " * Userspace decrypt request set\n");
++ if (auth_tok->session_key.flags
++ & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)
++ ecryptfs_printk(KERN_DEBUG,
++ " * Userspace encrypt request set\n");
++ if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) {
++ ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n");
++ ecryptfs_printk(KERN_DEBUG,
++ " * session_key.decrypted_key_size = [0x%x]\n",
++ auth_tok->session_key.decrypted_key_size);
++ ecryptfs_printk(KERN_DEBUG, " * Decrypted session key "
++ "dump:\n");
++ if (ecryptfs_verbosity > 0)
++ ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,
++ ECRYPTFS_DEFAULT_KEY_BYTES);
++ }
++ if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {
++ ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n");
++ ecryptfs_printk(KERN_DEBUG,
++ " * session_key.encrypted_key_size = [0x%x]\n",
++ auth_tok->session_key.encrypted_key_size);
++ ecryptfs_printk(KERN_DEBUG, " * Encrypted session key "
++ "dump:\n");
++ if (ecryptfs_verbosity > 0)
++ ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,
++ auth_tok->session_key.
++ encrypted_key_size);
++ }
++}
++
++/**
++ * ecryptfs_dump_hex - debug hex printer
++ * @data: string of bytes to be printed
++ * @bytes: number of bytes to print
++ *
++ * Dump hexadecimal representation of char array
++ */
++void ecryptfs_dump_hex(char *data, int bytes)
++{
++ int i = 0;
++ int add_newline = 1;
++
++ if (ecryptfs_verbosity < 1)
++ return;
++ if (bytes != 0) {
++ printk(KERN_DEBUG "0x%.2x.", (unsigned char)data[i]);
++ i++;
++ }
++ while (i < bytes) {
++ printk("0x%.2x.", (unsigned char)data[i]);
++ i++;
++ if (i % 16 == 0) {
++ printk("\n");
++ add_newline = 0;
++ } else
++ add_newline = 1;
++ }
++ if (add_newline)
++ printk("\n");
++}
++
+diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
+new file mode 100644
+index 0000000..0b9992a
+--- /dev/null
++++ b/fs/ecryptfs/dentry.c
+@@ -0,0 +1,93 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ *
++ * Copyright (C) 1997-2003 Erez Zadok
++ * Copyright (C) 2001-2003 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at 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/dcache.h>
++#include <linux/namei.h>
++#include <linux/mount.h>
++#include "ecryptfs_kernel.h"
++
++/**
++ * ecryptfs_d_revalidate - revalidate an ecryptfs dentry
++ * @dentry: The ecryptfs dentry
++ * @nd: The associated nameidata
++ *
++ * Called when the VFS needs to revalidate a dentry. This
++ * is called whenever a name lookup finds a dentry in the
++ * dcache. Most filesystems leave this as NULL, because all their
++ * dentries in the dcache are valid.
++ *
++ * Returns 1 if valid, 0 otherwise.
++ *
++ */
++static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
++ struct dentry *dentry_save;
++ struct vfsmount *vfsmount_save;
++ int rc = 1;
++
++ if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
++ goto out;
++ dentry_save = nd->dentry;
++ vfsmount_save = nd->mnt;
++ nd->dentry = lower_dentry;
++ nd->mnt = lower_mnt;
++ rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
++ nd->dentry = dentry_save;
++ nd->mnt = vfsmount_save;
++out:
++ return rc;
++}
++
++struct kmem_cache *ecryptfs_dentry_info_cache;
++
++/**
++ * ecryptfs_d_release
++ * @dentry: The ecryptfs dentry
++ *
++ * Called when a dentry is really deallocated.
++ */
++static void ecryptfs_d_release(struct dentry *dentry)
++{
++ struct dentry *lower_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ if (ecryptfs_dentry_to_private(dentry))
++ kmem_cache_free(ecryptfs_dentry_info_cache,
++ ecryptfs_dentry_to_private(dentry));
++ if (lower_dentry) {
++ struct vfsmount *lower_mnt =
++ ecryptfs_dentry_to_lower_mnt(dentry);
++
++ mntput(lower_mnt);
++ dput(lower_dentry);
++ }
++ return;
++}
++
++struct dentry_operations ecryptfs_dops = {
++ .d_revalidate = ecryptfs_d_revalidate,
++ .d_release = ecryptfs_d_release,
++};
+diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
+new file mode 100644
+index 0000000..f992533
+--- /dev/null
++++ b/fs/ecryptfs/ecryptfs_kernel.h
+@@ -0,0 +1,490 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ * Kernel declarations.
++ *
++ * Copyright (C) 1997-2003 Erez Zadok
++ * Copyright (C) 2001-2003 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at 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.
++ */
++
++#ifndef ECRYPTFS_KERNEL_H
++#define ECRYPTFS_KERNEL_H
++
++#include <keys/user-type.h>
++#include <linux/fs.h>
++#include <linux/scatterlist.h>
++
++/* Version verification for shared data structures w/ userspace */
++#define ECRYPTFS_VERSION_MAJOR 0x00
++#define ECRYPTFS_VERSION_MINOR 0x04
++#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x01
++/* These flags indicate which features are supported by the kernel
++ * module; userspace tools such as the mount helper read
++ * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
++ * how to behave. */
++#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001
++#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002
++#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
++#define ECRYPTFS_VERSIONING_POLICY 0x00000008
++#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
++ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH)
++
++#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
++#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
++#define ECRYPTFS_SALT_SIZE 8
++#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
++/* The original signature size is only for what is stored on disk; all
++ * in-memory representations are expanded hex, so it better adapted to
++ * be passed around or referenced on the command line */
++#define ECRYPTFS_SIG_SIZE 8
++#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
++#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
++#define ECRYPTFS_MAX_KEY_BYTES 64
++#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
++#define ECRYPTFS_DEFAULT_IV_BYTES 16
++#define ECRYPTFS_FILE_VERSION 0x01
++#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192
++#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
++#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
++
++#define RFC2440_CIPHER_DES3_EDE 0x02
++#define RFC2440_CIPHER_CAST_5 0x03
++#define RFC2440_CIPHER_BLOWFISH 0x04
++#define RFC2440_CIPHER_AES_128 0x07
++#define RFC2440_CIPHER_AES_192 0x08
++#define RFC2440_CIPHER_AES_256 0x09
++#define RFC2440_CIPHER_TWOFISH 0x0a
++#define RFC2440_CIPHER_CAST_6 0x0b
++
++#define ECRYPTFS_SET_FLAG(flag_bit_vector, flag) (flag_bit_vector |= (flag))
++#define ECRYPTFS_CLEAR_FLAG(flag_bit_vector, flag) (flag_bit_vector &= ~(flag))
++#define ECRYPTFS_CHECK_FLAG(flag_bit_vector, flag) (flag_bit_vector & (flag))
++
++/**
++ * For convenience, we may need to pass around the encrypted session
++ * key between kernel and userspace because the authentication token
++ * may not be extractable. For example, the TPM may not release the
++ * private key, instead requiring the encrypted data and returning the
++ * decrypted data.
++ */
++struct ecryptfs_session_key {
++#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
++#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
++#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
++#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
++ u32 flags;
++ u32 encrypted_key_size;
++ u32 decrypted_key_size;
++ u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
++ u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
++};
++
++struct ecryptfs_password {
++ u32 password_bytes;
++ s32 hash_algo;
++ u32 hash_iterations;
++ u32 session_key_encryption_key_bytes;
++#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
++#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
++ u32 flags;
++ /* Iterated-hash concatenation of salt and passphrase */
++ u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
++ u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
++ /* Always in expanded hex */
++ u8 salt[ECRYPTFS_SALT_SIZE];
++};
++
++enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
++
++/* May be a password or a private key */
++struct ecryptfs_auth_tok {
++ u16 version; /* 8-bit major and 8-bit minor */
++ u16 token_type;
++ u32 flags;
++ struct ecryptfs_session_key session_key;
++ u8 reserved[32];
++ union {
++ struct ecryptfs_password password;
++ /* Private key is in future eCryptfs releases */
++ } token;
++} __attribute__ ((packed));
++
++void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
++extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
++extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
++
++struct ecryptfs_key_record {
++ unsigned char type;
++ size_t enc_key_size;
++ unsigned char sig[ECRYPTFS_SIG_SIZE];
++ unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
++};
++
++struct ecryptfs_auth_tok_list {
++ struct ecryptfs_auth_tok *auth_tok;
++ struct list_head list;
++};
++
++struct ecryptfs_crypt_stat;
++struct ecryptfs_mount_crypt_stat;
++
++struct ecryptfs_page_crypt_context {
++ struct page *page;
++#define ECRYPTFS_PREPARE_COMMIT_MODE 0
++#define ECRYPTFS_WRITEPAGE_MODE 1
++ unsigned int mode;
++ union {
++ struct file *lower_file;
++ struct writeback_control *wbc;
++ } param;
++};
++
++static inline struct ecryptfs_auth_tok *
++ecryptfs_get_key_payload_data(struct key *key)
++{
++ return (struct ecryptfs_auth_tok *)
++ (((struct user_key_payload*)key->payload.data)->data);
++}
++
++#define ECRYPTFS_SUPER_MAGIC 0xf15f
++#define ECRYPTFS_MAX_KEYSET_SIZE 1024
++#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
++#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
++#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */
++#define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */
++#define ECRYPTFS_SALT_BYTES 2
++#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
++#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */
++#define ECRYPTFS_FILE_SIZE_BYTES 8
++#define ECRYPTFS_DEFAULT_CIPHER "aes"
++#define ECRYPTFS_DEFAULT_KEY_BYTES 16
++#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC
++#define ECRYPTFS_DEFAULT_HASH "md5"
++#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
++#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
++#define MD5_DIGEST_SIZE 16
++
++/**
++ * This is the primary struct associated with each encrypted file.
++ *
++ * TODO: cache align/pack?
++ */
++struct ecryptfs_crypt_stat {
++#define ECRYPTFS_STRUCT_INITIALIZED 0x00000001
++#define ECRYPTFS_POLICY_APPLIED 0x00000002
++#define ECRYPTFS_NEW_FILE 0x00000004
++#define ECRYPTFS_ENCRYPTED 0x00000008
++#define ECRYPTFS_SECURITY_WARNING 0x00000010
++#define ECRYPTFS_ENABLE_HMAC 0x00000020
++#define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040
++#define ECRYPTFS_KEY_VALID 0x00000080
++ u32 flags;
++ unsigned int file_version;
++ size_t iv_bytes;
++ size_t num_keysigs;
++ size_t header_extent_size;
++ size_t num_header_extents_at_front;
++ size_t extent_size; /* Data extent size; default is 4096 */
++ size_t key_size;
++ size_t extent_shift;
++ unsigned int extent_mask;
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
++ struct crypto_blkcipher *tfm;
++ struct crypto_hash *hash_tfm; /* Crypto context for generating
++ * the initialization vectors */
++ unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
++ unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
++ unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
++ unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX];
++ struct mutex cs_tfm_mutex;
++ struct mutex cs_hash_tfm_mutex;
++ struct mutex cs_mutex;
++};
++
++/* inode private data. */
++struct ecryptfs_inode_info {
++ struct inode vfs_inode;
++ struct inode *wii_inode;
++ struct ecryptfs_crypt_stat crypt_stat;
++};
++
++/* dentry private data. Each dentry must keep track of a lower
++ * vfsmount too. */
++struct ecryptfs_dentry_info {
++ struct dentry *wdi_dentry;
++ struct vfsmount *lower_mnt;
++ struct ecryptfs_crypt_stat *crypt_stat;
++};
++
++/**
++ * This struct is to enable a mount-wide passphrase/salt combo. This
++ * is more or less a stopgap to provide similar functionality to other
++ * crypto filesystems like EncFS or CFS until full policy support is
++ * implemented in eCryptfs.
++ */
++struct ecryptfs_mount_crypt_stat {
++ /* Pointers to memory we do not own, do not free these */
++#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001
++ u32 flags;
++ struct ecryptfs_auth_tok *global_auth_tok;
++ struct key *global_auth_tok_key;
++ size_t global_default_cipher_key_size;
++ struct crypto_blkcipher *global_key_tfm;
++ struct mutex global_key_tfm_mutex;
++ unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
++ + 1];
++ unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
++};
++
++/* superblock private data. */
++struct ecryptfs_sb_info {
++ struct super_block *wsi_sb;
++ struct ecryptfs_mount_crypt_stat mount_crypt_stat;
++};
++
++/* file private data. */
++struct ecryptfs_file_info {
++ struct file *wfi_file;
++ struct ecryptfs_crypt_stat *crypt_stat;
++};
++
++/* auth_tok <=> encrypted_session_key mappings */
++struct ecryptfs_auth_tok_list_item {
++ unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];
++ struct list_head list;
++ struct ecryptfs_auth_tok auth_tok;
++};
++
++static inline struct ecryptfs_file_info *
++ecryptfs_file_to_private(struct file *file)
++{
++ return (struct ecryptfs_file_info *)file->private_data;
++}
++
++static inline void
++ecryptfs_set_file_private(struct file *file,
++ struct ecryptfs_file_info *file_info)
++{
++ file->private_data = file_info;
++}
++
++static inline struct file *ecryptfs_file_to_lower(struct file *file)
++{
++ return ((struct ecryptfs_file_info *)file->private_data)->wfi_file;
++}
++
++static inline void
++ecryptfs_set_file_lower(struct file *file, struct file *lower_file)
++{
++ ((struct ecryptfs_file_info *)file->private_data)->wfi_file =
++ lower_file;
++}
++
++static inline struct ecryptfs_inode_info *
++ecryptfs_inode_to_private(struct inode *inode)
++{
++ return container_of(inode, struct ecryptfs_inode_info, vfs_inode);
++}
++
++static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode)
++{
++ return ecryptfs_inode_to_private(inode)->wii_inode;
++}
++
++static inline void
++ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode)
++{
++ ecryptfs_inode_to_private(inode)->wii_inode = lower_inode;
++}
++
++static inline struct ecryptfs_sb_info *
++ecryptfs_superblock_to_private(struct super_block *sb)
++{
++ return (struct ecryptfs_sb_info *)sb->s_fs_info;
++}
++
++static inline void
++ecryptfs_set_superblock_private(struct super_block *sb,
++ struct ecryptfs_sb_info *sb_info)
++{
++ sb->s_fs_info = sb_info;
++}
++
++static inline struct super_block *
++ecryptfs_superblock_to_lower(struct super_block *sb)
++{
++ return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb;
++}
++
++static inline void
++ecryptfs_set_superblock_lower(struct super_block *sb,
++ struct super_block *lower_sb)
++{
++ ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb;
++}
++
++static inline struct ecryptfs_dentry_info *
++ecryptfs_dentry_to_private(struct dentry *dentry)
++{
++ return (struct ecryptfs_dentry_info *)dentry->d_fsdata;
++}
++
++static inline void
++ecryptfs_set_dentry_private(struct dentry *dentry,
++ struct ecryptfs_dentry_info *dentry_info)
++{
++ dentry->d_fsdata = dentry_info;
++}
++
++static inline struct dentry *
++ecryptfs_dentry_to_lower(struct dentry *dentry)
++{
++ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry;
++}
++
++static inline void
++ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
++{
++ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry =
++ lower_dentry;
++}
++
++static inline struct vfsmount *
++ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
++{
++ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt;
++}
++
++static inline void
++ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
++{
++ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt =
++ lower_mnt;
++}
++
++#define ecryptfs_printk(type, fmt, arg...) \
++ __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
++void __ecryptfs_printk(const char *fmt, ...);
++
++extern const struct file_operations ecryptfs_main_fops;
++extern const struct file_operations ecryptfs_dir_fops;
++extern struct inode_operations ecryptfs_main_iops;
++extern struct inode_operations ecryptfs_dir_iops;
++extern struct inode_operations ecryptfs_symlink_iops;
++extern struct super_operations ecryptfs_sops;
++extern struct dentry_operations ecryptfs_dops;
++extern struct address_space_operations ecryptfs_aops;
++extern int ecryptfs_verbosity;
++
++extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
++extern struct kmem_cache *ecryptfs_file_info_cache;
++extern struct kmem_cache *ecryptfs_dentry_info_cache;
++extern struct kmem_cache *ecryptfs_inode_info_cache;
++extern struct kmem_cache *ecryptfs_sb_info_cache;
++extern struct kmem_cache *ecryptfs_header_cache_0;
++extern struct kmem_cache *ecryptfs_header_cache_1;
++extern struct kmem_cache *ecryptfs_header_cache_2;
++extern struct kmem_cache *ecryptfs_lower_page_cache;
++
++int ecryptfs_interpose(struct dentry *hidden_dentry,
++ struct dentry *this_dentry, struct super_block *sb,
++ int flag);
++int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
++int ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
++ const char *name, int length,
++ char **decrypted_name);
++int ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
++ const char *name, int length,
++ char **encoded_name);
++struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
++void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src);
++void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src);
++void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src);
++void ecryptfs_dump_hex(char *data, int bytes);
++int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
++ int sg_size);
++int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
++void ecryptfs_rotate_iv(unsigned char *iv);
++void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
++void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
++void ecryptfs_destruct_mount_crypt_stat(
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
++int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
++int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,
++ char *cipher_name,
++ char *chaining_modifier);
++int ecryptfs_write_inode_size_to_header(struct file *lower_file,
++ struct inode *lower_inode,
++ struct inode *inode);
++int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
++ struct file *lower_file,
++ unsigned long lower_page_index, int byte_offset,
++ int region_bytes);
++int
++ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
++ struct file *lower_file, int byte_offset,
++ int region_size);
++int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
++ struct file *lower_file);
++int ecryptfs_do_readpage(struct file *file, struct page *page,
++ pgoff_t lower_page_index);
++int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
++ char **lower_virt,
++ struct inode *lower_inode,
++ unsigned long lower_page_index);
++int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
++ struct inode *lower_inode,
++ struct writeback_control *wbc);
++int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx);
++int ecryptfs_decrypt_page(struct file *file, struct page *page);
++int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
++ struct file *lower_file);
++int ecryptfs_write_headers_virt(char *page_virt,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct dentry *ecryptfs_dentry);
++int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
++ struct file *lower_file);
++int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
++int contains_ecryptfs_marker(char *data);
++int ecryptfs_read_header_region(char *data, struct dentry *dentry,
++ struct vfsmount *mnt);
++u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
++int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
++void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
++int ecryptfs_generate_key_packet_set(char *dest_base,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct dentry *ecryptfs_dentry,
++ size_t *len, size_t max);
++int process_request_key_err(long err_code);
++int
++ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
++ unsigned char *src, struct dentry *ecryptfs_dentry);
++int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
++int
++ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name,
++ size_t *key_size);
++int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
++int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
++void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
++int ecryptfs_open_lower_file(struct file **lower_file,
++ struct dentry *lower_dentry,
++ struct vfsmount *lower_mnt, int flags);
++int ecryptfs_close_lower_file(struct file *lower_file);
++
++#endif /* #ifndef ECRYPTFS_KERNEL_H */
+diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
+new file mode 100644
+index 0000000..a92ef05
+--- /dev/null
++++ b/fs/ecryptfs/file.c
+@@ -0,0 +1,468 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ *
++ * Copyright (C) 1997-2004 Erez Zadok
++ * Copyright (C) 2001-2004 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mhalcrow at us.ibm.com>
++ * Michael C. Thompson <mcthomps at 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/file.h>
++#include <linux/poll.h>
++#include <linux/mount.h>
++#include <linux/pagemap.h>
++#include <linux/security.h>
++#include <linux/smp_lock.h>
++#include <linux/compat.h>
++#include "ecryptfs_kernel.h"
++
++/**
++ * ecryptfs_llseek
++ * @file: File we are seeking in
++ * @offset: The offset to seek to
++ * @origin: 2 - offset from i_size; 1 - offset from f_pos
++ *
++ * Returns the position we have seeked to, or negative on error
++ */
++static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
++{
++ loff_t rv;
++ loff_t new_end_pos;
++ int rc;
++ int expanding_file = 0;
++ struct inode *inode = file->f_mapping->host;
++
++ /* If our offset is past the end of our file, we're going to
++ * need to grow it so we have a valid length of 0's */
++ new_end_pos = offset;
++ switch (origin) {
++ case 2:
++ new_end_pos += i_size_read(inode);
++ expanding_file = 1;
++ break;
++ case 1:
++ new_end_pos += file->f_pos;
++ if (new_end_pos > i_size_read(inode)) {
++ ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
++ "> i_size_read(inode)(=[0x%.16x])\n",
++ new_end_pos, i_size_read(inode));
++ expanding_file = 1;
++ }
++ break;
++ default:
++ if (new_end_pos > i_size_read(inode)) {
++ ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
++ "> i_size_read(inode)(=[0x%.16x])\n",
++ new_end_pos, i_size_read(inode));
++ expanding_file = 1;
++ }
++ }
++ ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
++ if (expanding_file) {
++ rc = ecryptfs_truncate(file->f_dentry, new_end_pos);
++ if (rc) {
++ rv = rc;
++ ecryptfs_printk(KERN_ERR, "Error on attempt to "
++ "truncate to (higher) offset [0x%.16x];"
++ " rc = [%d]\n", new_end_pos, rc);
++ goto out;
++ }
++ }
++ rv = generic_file_llseek(file, offset, origin);
++out:
++ return rv;
++}
++
++/**
++ * ecryptfs_read_update_atime
++ *
++ * generic_file_read updates the atime of upper layer inode. But, it
++ * doesn't give us a chance to update the atime of the lower layer
++ * inode. This function is a wrapper to generic_file_read. It
++ * updates the atime of the lower level inode if generic_file_read
++ * returns without any errors. This is to be used only for file reads.
++ * The function to be used for directory reads is ecryptfs_read.
++ */
++static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
++ const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
++{
++ int rc;
++ struct dentry *lower_dentry;
++ struct vfsmount *lower_vfsmount;
++ struct file *file = iocb->ki_filp;
++
++ rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
++ /*
++ * Even though this is a async interface, we need to wait
++ * for IO to finish to update atime
++ */
++ if (-EIOCBQUEUED == rc)
++ rc = wait_on_sync_kiocb(iocb);
++ if (rc >= 0) {
++ lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry);
++ lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry);
++ touch_atime(lower_vfsmount, lower_dentry);
++ }
++ return rc;
++}
++
++struct ecryptfs_getdents_callback {
++ void *dirent;
++ struct dentry *dentry;
++ filldir_t filldir;
++ int err;
++ int filldir_called;
++ int entries_written;
++};
++
++/* Inspired by generic filldir in fs/readir.c */
++static int
++ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
++ u64 ino, unsigned int d_type)
++{
++ struct ecryptfs_crypt_stat *crypt_stat;
++ struct ecryptfs_getdents_callback *buf =
++ (struct ecryptfs_getdents_callback *)dirent;
++ int rc;
++ int decoded_length;
++ char *decoded_name;
++
++ crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat;
++ buf->filldir_called++;
++ decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen,
++ &decoded_name);
++ if (decoded_length < 0) {
++ rc = decoded_length;
++ goto out;
++ }
++ rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
++ ino, d_type);
++ kfree(decoded_name);
++ if (rc >= 0)
++ buf->entries_written++;
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_readdir
++ * @file: The ecryptfs file struct
++ * @dirent: Directory entry
++ * @filldir: The filldir callback function
++ */
++static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ int rc;
++ struct file *lower_file;
++ struct inode *inode;
++ struct ecryptfs_getdents_callback buf;
++
++ lower_file = ecryptfs_file_to_lower(file);
++ lower_file->f_pos = file->f_pos;
++ inode = file->f_dentry->d_inode;
++ memset(&buf, 0, sizeof(buf));
++ buf.dirent = dirent;
++ buf.dentry = file->f_dentry;
++ buf.filldir = filldir;
++retry:
++ buf.filldir_called = 0;
++ buf.entries_written = 0;
++ buf.err = 0;
++ rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
++ if (buf.err)
++ rc = buf.err;
++ if (buf.filldir_called && !buf.entries_written)
++ goto retry;
++ file->f_pos = lower_file->f_pos;
++ if (rc >= 0)
++ ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
++ return rc;
++}
++
++struct kmem_cache *ecryptfs_file_info_cache;
++
++int ecryptfs_open_lower_file(struct file **lower_file,
++ struct dentry *lower_dentry,
++ struct vfsmount *lower_mnt, int flags)
++{
++ int rc = 0;
++
++ dget(lower_dentry);
++ mntget(lower_mnt);
++ *lower_file = dentry_open(lower_dentry, lower_mnt, flags);
++ if (IS_ERR(*lower_file)) {
++ printk(KERN_ERR "Error opening lower file for lower_dentry "
++ "[0x%p], lower_mnt [0x%p], and flags [0x%x]\n",
++ lower_dentry, lower_mnt, flags);
++ rc = PTR_ERR(*lower_file);
++ *lower_file = NULL;
++ goto out;
++ }
++out:
++ return rc;
++}
++
++int ecryptfs_close_lower_file(struct file *lower_file)
++{
++ fput(lower_file);
++ return 0;
++}
++
++/**
++ * ecryptfs_open
++ * @inode: inode speciying file to open
++ * @file: Structure to return filled in
++ *
++ * Opens the file specified by inode.
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++static int ecryptfs_open(struct inode *inode, struct file *file)
++{
++ int rc = 0;
++ struct ecryptfs_crypt_stat *crypt_stat = NULL;
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
++ struct dentry *ecryptfs_dentry = file->f_dentry;
++ /* Private value of ecryptfs_dentry allocated in
++ * ecryptfs_lookup() */
++ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
++ struct inode *lower_inode = NULL;
++ struct file *lower_file = NULL;
++ struct vfsmount *lower_mnt;
++ struct ecryptfs_file_info *file_info;
++ int lower_flags;
++
++ /* Released in ecryptfs_release or end of function if failure */
++ file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
++ ecryptfs_set_file_private(file, file_info);
++ if (!file_info) {
++ ecryptfs_printk(KERN_ERR,
++ "Error attempting to allocate memory\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ memset(file_info, 0, sizeof(*file_info));
++ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
++ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
++ mount_crypt_stat = &ecryptfs_superblock_to_private(
++ ecryptfs_dentry->d_sb)->mount_crypt_stat;
++ mutex_lock(&crypt_stat->cs_mutex);
++ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) {
++ ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
++ /* Policy code enabled in future release */
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED);
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
++ }
++ mutex_unlock(&crypt_stat->cs_mutex);
++ lower_flags = file->f_flags;
++ if ((lower_flags & O_ACCMODE) == O_WRONLY)
++ lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
++ if (file->f_flags & O_APPEND)
++ lower_flags &= ~O_APPEND;
++ lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
++ /* Corresponding fput() in ecryptfs_release() */
++ if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
++ lower_flags))) {
++ ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
++ goto out_puts;
++ }
++ ecryptfs_set_file_lower(file, lower_file);
++ /* Isn't this check the same as the one in lookup? */
++ lower_inode = lower_dentry->d_inode;
++ if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
++ ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
++ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
++ rc = 0;
++ goto out;
++ }
++ mutex_lock(&crypt_stat->cs_mutex);
++ if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
++ if (!(mount_crypt_stat->flags
++ & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
++ rc = -EIO;
++ printk(KERN_WARNING "Attempt to read file that is "
++ "not in a valid eCryptfs format, and plaintext "
++ "passthrough mode is not enabled; returning "
++ "-EIO\n");
++ mutex_unlock(&crypt_stat->cs_mutex);
++ goto out_puts;
++ }
++ crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
++ rc = 0;
++ mutex_unlock(&crypt_stat->cs_mutex);
++ goto out;
++ } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
++ ECRYPTFS_POLICY_APPLIED)
++ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
++ ECRYPTFS_KEY_VALID)) {
++ rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file);
++ if (rc) {
++ ecryptfs_printk(KERN_DEBUG,
++ "Valid headers not found\n");
++ if (!(mount_crypt_stat->flags
++ & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
++ rc = -EIO;
++ printk(KERN_WARNING "Attempt to read file that "
++ "is not in a valid eCryptfs format, "
++ "and plaintext passthrough mode is not "
++ "enabled; returning -EIO\n");
++ mutex_unlock(&crypt_stat->cs_mutex);
++ goto out_puts;
++ }
++ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
++ ECRYPTFS_ENCRYPTED);
++ rc = 0;
++ mutex_unlock(&crypt_stat->cs_mutex);
++ goto out;
++ }
++ }
++ mutex_unlock(&crypt_stat->cs_mutex);
++ ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
++ "size: [0x%.16x]\n", inode, inode->i_ino,
++ i_size_read(inode));
++ ecryptfs_set_file_lower(file, lower_file);
++ goto out;
++out_puts:
++ mntput(lower_mnt);
++ dput(lower_dentry);
++ kmem_cache_free(ecryptfs_file_info_cache,
++ ecryptfs_file_to_private(file));
++out:
++ return rc;
++}
++
++static int ecryptfs_flush(struct file *file, fl_owner_t td)
++{
++ int rc = 0;
++ struct file *lower_file = NULL;
++
++ lower_file = ecryptfs_file_to_lower(file);
++ if (lower_file->f_op && lower_file->f_op->flush)
++ rc = lower_file->f_op->flush(lower_file, td);
++ return rc;
++}
++
++static int ecryptfs_release(struct inode *inode, struct file *file)
++{
++ struct file *lower_file = ecryptfs_file_to_lower(file);
++ struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file);
++ struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
++ int rc;
++
++ if ((rc = ecryptfs_close_lower_file(lower_file))) {
++ printk(KERN_ERR "Error closing lower_file\n");
++ goto out;
++ }
++ inode->i_blocks = lower_inode->i_blocks;
++ kmem_cache_free(ecryptfs_file_info_cache, file_info);
++out:
++ return rc;
++}
++
++static int
++ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++ struct file *lower_file = ecryptfs_file_to_lower(file);
++ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ struct inode *lower_inode = lower_dentry->d_inode;
++ int rc = -EINVAL;
++
++ if (lower_inode->i_fop->fsync) {
++ mutex_lock(&lower_inode->i_mutex);
++ rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
++ datasync);
++ mutex_unlock(&lower_inode->i_mutex);
++ }
++ return rc;
++}
++
++static int ecryptfs_fasync(int fd, struct file *file, int flag)
++{
++ int rc = 0;
++ struct file *lower_file = NULL;
++
++ lower_file = ecryptfs_file_to_lower(file);
++ if (lower_file->f_op && lower_file->f_op->fasync)
++ rc = lower_file->f_op->fasync(fd, lower_file, flag);
++ return rc;
++}
++
++static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
++ size_t count, read_actor_t actor, void *target)
++{
++ struct file *lower_file = NULL;
++ int rc = -EINVAL;
++
++ lower_file = ecryptfs_file_to_lower(file);
++ if (lower_file->f_op && lower_file->f_op->sendfile)
++ rc = lower_file->f_op->sendfile(lower_file, ppos, count,
++ actor, target);
++
++ return rc;
++}
++
++static int ecryptfs_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg);
++
++const struct file_operations ecryptfs_dir_fops = {
++ .readdir = ecryptfs_readdir,
++ .ioctl = ecryptfs_ioctl,
++ .mmap = generic_file_mmap,
++ .open = ecryptfs_open,
++ .flush = ecryptfs_flush,
++ .release = ecryptfs_release,
++ .fsync = ecryptfs_fsync,
++ .fasync = ecryptfs_fasync,
++ .sendfile = ecryptfs_sendfile,
++};
++
++const struct file_operations ecryptfs_main_fops = {
++ .llseek = ecryptfs_llseek,
++ .read = do_sync_read,
++ .aio_read = ecryptfs_read_update_atime,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
++ .readdir = ecryptfs_readdir,
++ .ioctl = ecryptfs_ioctl,
++ .mmap = generic_file_mmap,
++ .open = ecryptfs_open,
++ .flush = ecryptfs_flush,
++ .release = ecryptfs_release,
++ .fsync = ecryptfs_fsync,
++ .fasync = ecryptfs_fasync,
++ .sendfile = ecryptfs_sendfile,
++};
++
++static int
++ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int rc = 0;
++ struct file *lower_file = NULL;
++
++ if (ecryptfs_file_to_private(file))
++ lower_file = ecryptfs_file_to_lower(file);
++ if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
++ rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),
++ lower_file, cmd, arg);
++ else
++ rc = -ENOTTY;
++ return rc;
++}
+diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
+new file mode 100644
+index 0000000..ff4865d
+--- /dev/null
++++ b/fs/ecryptfs/inode.c
+@@ -0,0 +1,1046 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ *
++ * Copyright (C) 1997-2004 Erez Zadok
++ * Copyright (C) 2001-2004 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at us.ibm.com>
++ * Michael C. Thompsion <mcthomps at 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/file.h>
++#include <linux/vmalloc.h>
++#include <linux/pagemap.h>
++#include <linux/dcache.h>
++#include <linux/namei.h>
++#include <linux/mount.h>
++#include <linux/crypto.h>
++#include "ecryptfs_kernel.h"
++
++static struct dentry *lock_parent(struct dentry *dentry)
++{
++ struct dentry *dir;
++
++ dir = dget(dentry->d_parent);
++ mutex_lock(&(dir->d_inode->i_mutex));
++ return dir;
++}
++
++static void unlock_parent(struct dentry *dentry)
++{
++ mutex_unlock(&(dentry->d_parent->d_inode->i_mutex));
++ dput(dentry->d_parent);
++}
++
++static void unlock_dir(struct dentry *dir)
++{
++ mutex_unlock(&dir->d_inode->i_mutex);
++ dput(dir);
++}
++
++void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src)
++{
++ i_size_write(dst, i_size_read((struct inode *)src));
++ dst->i_blocks = src->i_blocks;
++}
++
++void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src)
++{
++ dest->i_atime = src->i_atime;
++}
++
++static void ecryptfs_copy_attr_times(struct inode *dest,
++ const struct inode *src)
++{
++ dest->i_atime = src->i_atime;
++ dest->i_mtime = src->i_mtime;
++ dest->i_ctime = src->i_ctime;
++}
++
++static void ecryptfs_copy_attr_timesizes(struct inode *dest,
++ const struct inode *src)
++{
++ dest->i_atime = src->i_atime;
++ dest->i_mtime = src->i_mtime;
++ dest->i_ctime = src->i_ctime;
++ ecryptfs_copy_inode_size(dest, src);
++}
++
++void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src)
++{
++ dest->i_mode = src->i_mode;
++ dest->i_nlink = src->i_nlink;
++ dest->i_uid = src->i_uid;
++ dest->i_gid = src->i_gid;
++ dest->i_rdev = src->i_rdev;
++ dest->i_atime = src->i_atime;
++ dest->i_mtime = src->i_mtime;
++ dest->i_ctime = src->i_ctime;
++ dest->i_blkbits = src->i_blkbits;
++ dest->i_flags = src->i_flags;
++}
++
++/**
++ * ecryptfs_create_underlying_file
++ * @lower_dir_inode: inode of the parent in the lower fs of the new file
++ * @lower_dentry: New file's dentry in the lower fs
++ * @ecryptfs_dentry: New file's dentry in ecryptfs
++ * @mode: The mode of the new file
++ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
++ *
++ * Creates the file in the lower file system.
++ *
++ * Returns zero on success; non-zero on error condition
++ */
++static int
++ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
++ struct dentry *dentry, int mode,
++ struct nameidata *nd)
++{
++ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
++ struct dentry *dentry_save;
++ struct vfsmount *vfsmount_save;
++ int rc;
++
++ dentry_save = nd->dentry;
++ vfsmount_save = nd->mnt;
++ nd->dentry = lower_dentry;
++ nd->mnt = lower_mnt;
++ rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
++ nd->dentry = dentry_save;
++ nd->mnt = vfsmount_save;
++ return rc;
++}
++
++/**
++ * ecryptfs_do_create
++ * @directory_inode: inode of the new file's dentry's parent in ecryptfs
++ * @ecryptfs_dentry: New file's dentry in ecryptfs
++ * @mode: The mode of the new file
++ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
++ *
++ * Creates the underlying file and the eCryptfs inode which will link to
++ * it. It will also update the eCryptfs directory inode to mimic the
++ * stat of the lower directory inode.
++ *
++ * Returns zero on success; non-zero on error condition
++ */
++static int
++ecryptfs_do_create(struct inode *directory_inode,
++ struct dentry *ecryptfs_dentry, int mode,
++ struct nameidata *nd)
++{
++ int rc;
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
++ lower_dir_dentry = lock_parent(lower_dentry);
++ if (unlikely(IS_ERR(lower_dir_dentry))) {
++ ecryptfs_printk(KERN_ERR, "Error locking directory of "
++ "dentry\n");
++ rc = PTR_ERR(lower_dir_dentry);
++ goto out;
++ }
++ rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
++ ecryptfs_dentry, mode, nd);
++ if (unlikely(rc)) {
++ ecryptfs_printk(KERN_ERR,
++ "Failure to create underlying file\n");
++ goto out_lock;
++ }
++ rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
++ directory_inode->i_sb, 0);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
++ goto out_lock;
++ }
++ ecryptfs_copy_attr_timesizes(directory_inode,
++ lower_dir_dentry->d_inode);
++out_lock:
++ unlock_dir(lower_dir_dentry);
++out:
++ return rc;
++}
++
++/**
++ * grow_file
++ * @ecryptfs_dentry: the ecryptfs dentry
++ * @lower_file: The lower file
++ * @inode: The ecryptfs inode
++ * @lower_inode: The lower inode
++ *
++ * This is the code which will grow the file to its correct size.
++ */
++static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
++ struct inode *inode, struct inode *lower_inode)
++{
++ int rc = 0;
++ struct file fake_file;
++ struct ecryptfs_file_info tmp_file_info;
++
++ memset(&fake_file, 0, sizeof(fake_file));
++ fake_file.f_dentry = ecryptfs_dentry;
++ memset(&tmp_file_info, 0, sizeof(tmp_file_info));
++ ecryptfs_set_file_private(&fake_file, &tmp_file_info);
++ ecryptfs_set_file_lower(&fake_file, lower_file);
++ rc = ecryptfs_fill_zeros(&fake_file, 1);
++ if (rc) {
++ ECRYPTFS_SET_FLAG(
++ ecryptfs_inode_to_private(inode)->crypt_stat.flags,
++ ECRYPTFS_SECURITY_WARNING);
++ ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros "
++ "in file; rc = [%d]\n", rc);
++ goto out;
++ }
++ i_size_write(inode, 0);
++ ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
++ ECRYPTFS_SET_FLAG(ecryptfs_inode_to_private(inode)->crypt_stat.flags,
++ ECRYPTFS_NEW_FILE);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_initialize_file
++ *
++ * Cause the file to be changed from a basic empty file to an ecryptfs
++ * file with a header and first data page.
++ *
++ * Returns zero on success
++ */
++static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
++{
++ int rc = 0;
++ int lower_flags;
++ struct ecryptfs_crypt_stat *crypt_stat;
++ struct dentry *lower_dentry;
++ struct file *lower_file;
++ struct inode *inode, *lower_inode;
++ struct vfsmount *lower_mnt;
++
++ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
++ ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n",
++ lower_dentry->d_name.name);
++ inode = ecryptfs_dentry->d_inode;
++ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
++ lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR;
++#if BITS_PER_LONG != 32
++ lower_flags |= O_LARGEFILE;
++#endif
++ lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
++ /* Corresponding fput() at end of this function */
++ if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
++ lower_flags))) {
++ ecryptfs_printk(KERN_ERR,
++ "Error opening dentry; rc = [%i]\n", rc);
++ goto out;
++ }
++ lower_inode = lower_dentry->d_inode;
++ if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
++ ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
++ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
++ goto out_fput;
++ }
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
++ ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");
++ rc = ecryptfs_new_file_context(ecryptfs_dentry);
++ if (rc) {
++ ecryptfs_printk(KERN_DEBUG, "Error creating new file "
++ "context\n");
++ goto out_fput;
++ }
++ rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file);
++ if (rc) {
++ ecryptfs_printk(KERN_DEBUG, "Error writing headers\n");
++ goto out_fput;
++ }
++ rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
++out_fput:
++ if ((rc = ecryptfs_close_lower_file(lower_file)))
++ printk(KERN_ERR "Error closing lower_file\n");
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_create
++ * @dir: The inode of the directory in which to create the file.
++ * @dentry: The eCryptfs dentry
++ * @mode: The mode of the new file.
++ * @nd: nameidata
++ *
++ * Creates a new file.
++ *
++ * Returns zero on success; non-zero on error condition
++ */
++static int
++ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
++ int mode, struct nameidata *nd)
++{
++ int rc;
++
++ rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
++ if (unlikely(rc)) {
++ ecryptfs_printk(KERN_WARNING, "Failed to create file in"
++ "lower filesystem\n");
++ goto out;
++ }
++ /* At this point, a file exists on "disk"; we need to make sure
++ * that this on disk file is prepared to be an ecryptfs file */
++ rc = ecryptfs_initialize_file(ecryptfs_dentry);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_lookup
++ * @dir: inode
++ * @dentry: The dentry
++ * @nd: nameidata, may be NULL
++ *
++ * Find a file on disk. If the file does not exist, then we'll add it to the
++ * dentry cache and continue on to read it from the disk.
++ */
++static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ int rc = 0;
++ struct dentry *lower_dir_dentry;
++ struct dentry *lower_dentry;
++ struct vfsmount *lower_mnt;
++ char *encoded_name;
++ unsigned int encoded_namelen;
++ struct ecryptfs_crypt_stat *crypt_stat = NULL;
++ char *page_virt = NULL;
++ struct inode *lower_inode;
++ u64 file_size;
++
++ lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
++ dentry->d_op = &ecryptfs_dops;
++ if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
++ || (dentry->d_name.len == 2
++ && !strcmp(dentry->d_name.name, ".."))) {
++ d_drop(dentry);
++ goto out;
++ }
++ encoded_namelen = ecryptfs_encode_filename(crypt_stat,
++ dentry->d_name.name,
++ dentry->d_name.len,
++ &encoded_name);
++ if (encoded_namelen < 0) {
++ rc = encoded_namelen;
++ d_drop(dentry);
++ goto out;
++ }
++ ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen "
++ "= [%d]\n", encoded_name, encoded_namelen);
++ lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
++ encoded_namelen - 1);
++ kfree(encoded_name);
++ if (IS_ERR(lower_dentry)) {
++ ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n");
++ rc = PTR_ERR(lower_dentry);
++ d_drop(dentry);
++ goto out;
++ }
++ lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
++ ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->"
++ "d_name.name = [%s]\n", lower_dentry,
++ lower_dentry->d_name.name);
++ lower_inode = lower_dentry->d_inode;
++ ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode);
++ BUG_ON(!atomic_read(&lower_dentry->d_count));
++ ecryptfs_set_dentry_private(dentry,
++ kmem_cache_alloc(ecryptfs_dentry_info_cache,
++ SLAB_KERNEL));
++ if (!ecryptfs_dentry_to_private(dentry)) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting "
++ "to allocate ecryptfs_dentry_info struct\n");
++ goto out_dput;
++ }
++ ecryptfs_set_dentry_lower(dentry, lower_dentry);
++ ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt);
++ if (!lower_dentry->d_inode) {
++ /* We want to add because we couldn't find in lower */
++ d_add(dentry, NULL);
++ goto out;
++ }
++ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 1);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error interposing\n");
++ goto out_dput;
++ }
++ if (S_ISDIR(lower_inode->i_mode)) {
++ ecryptfs_printk(KERN_DEBUG, "Is a directory; returning\n");
++ goto out;
++ }
++ if (S_ISLNK(lower_inode->i_mode)) {
++ ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n");
++ goto out;
++ }
++ if (!nd) {
++ ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave"
++ "as we *think* we are about to unlink\n");
++ goto out;
++ }
++ /* Released in this function */
++ page_virt =
++ (char *)kmem_cache_alloc(ecryptfs_header_cache_2,
++ SLAB_USER);
++ if (!page_virt) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_ERR,
++ "Cannot ecryptfs_kmalloc a page\n");
++ goto out_dput;
++ }
++ memset(page_virt, 0, PAGE_CACHE_SIZE);
++ rc = ecryptfs_read_header_region(page_virt, lower_dentry, nd->mnt);
++ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
++ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED))
++ ecryptfs_set_default_sizes(crypt_stat);
++ if (rc) {
++ rc = 0;
++ ecryptfs_printk(KERN_WARNING, "Error reading header region;"
++ " assuming unencrypted\n");
++ } else {
++ if (!contains_ecryptfs_marker(page_virt
++ + ECRYPTFS_FILE_SIZE_BYTES)) {
++ kmem_cache_free(ecryptfs_header_cache_2, page_virt);
++ goto out;
++ }
++ memcpy(&file_size, page_virt, sizeof(file_size));
++ file_size = be64_to_cpu(file_size);
++ i_size_write(dentry->d_inode, (loff_t)file_size);
++ }
++ kmem_cache_free(ecryptfs_header_cache_2, page_virt);
++ goto out;
++
++out_dput:
++ dput(lower_dentry);
++ d_drop(dentry);
++out:
++ return ERR_PTR(rc);
++}
++
++static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *new_dentry)
++{
++ struct dentry *lower_old_dentry;
++ struct dentry *lower_new_dentry;
++ struct dentry *lower_dir_dentry;
++ u64 file_size_save;
++ int rc;
++
++ file_size_save = i_size_read(old_dentry->d_inode);
++ lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
++ lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
++ dget(lower_old_dentry);
++ dget(lower_new_dentry);
++ lower_dir_dentry = lock_parent(lower_new_dentry);
++ rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
++ lower_new_dentry);
++ if (rc || !lower_new_dentry->d_inode)
++ goto out_lock;
++ rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
++ if (rc)
++ goto out_lock;
++ ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode);
++ old_dentry->d_inode->i_nlink =
++ ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
++ i_size_write(new_dentry->d_inode, file_size_save);
++out_lock:
++ unlock_dir(lower_dir_dentry);
++ dput(lower_new_dentry);
++ dput(lower_old_dentry);
++ d_drop(new_dentry);
++ d_drop(old_dentry);
++ return rc;
++}
++
++static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int rc = 0;
++ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
++
++ lock_parent(lower_dentry);
++ rc = vfs_unlink(lower_dir_inode, lower_dentry);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error in vfs_unlink\n");
++ goto out_unlock;
++ }
++ ecryptfs_copy_attr_times(dir, lower_dir_inode);
++ dentry->d_inode->i_nlink =
++ ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
++ dentry->d_inode->i_ctime = dir->i_ctime;
++out_unlock:
++ unlock_parent(lower_dentry);
++ return rc;
++}
++
++static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ int rc;
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry;
++ umode_t mode;
++ char *encoded_symname;
++ unsigned int encoded_symlen;
++ struct ecryptfs_crypt_stat *crypt_stat = NULL;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ dget(lower_dentry);
++ lower_dir_dentry = lock_parent(lower_dentry);
++ mode = S_IALLUGO;
++ encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
++ strlen(symname),
++ &encoded_symname);
++ if (encoded_symlen < 0) {
++ rc = encoded_symlen;
++ goto out_lock;
++ }
++ rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
++ encoded_symname, mode);
++ kfree(encoded_symname);
++ if (rc || !lower_dentry->d_inode)
++ goto out_lock;
++ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
++ if (rc)
++ goto out_lock;
++ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
++out_lock:
++ unlock_dir(lower_dir_dentry);
++ dput(lower_dentry);
++ if (!dentry->d_inode)
++ d_drop(dentry);
++ return rc;
++}
++
++static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int rc;
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ lower_dir_dentry = lock_parent(lower_dentry);
++ rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
++ if (rc || !lower_dentry->d_inode)
++ goto out;
++ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
++ if (rc)
++ goto out;
++ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
++ dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
++out:
++ unlock_dir(lower_dir_dentry);
++ if (!dentry->d_inode)
++ d_drop(dentry);
++ return rc;
++}
++
++static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry;
++ int rc;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ dget(dentry);
++ lower_dir_dentry = lock_parent(lower_dentry);
++ dget(lower_dentry);
++ rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
++ dput(lower_dentry);
++ if (!rc)
++ d_delete(lower_dentry);
++ ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
++ dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
++ unlock_dir(lower_dir_dentry);
++ if (!rc)
++ d_drop(dentry);
++ dput(dentry);
++ return rc;
++}
++
++static int
++ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++{
++ int rc;
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ lower_dir_dentry = lock_parent(lower_dentry);
++ rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
++ if (rc || !lower_dentry->d_inode)
++ goto out;
++ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
++ if (rc)
++ goto out;
++ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
++out:
++ unlock_dir(lower_dir_dentry);
++ if (!dentry->d_inode)
++ d_drop(dentry);
++ return rc;
++}
++
++static int
++ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ int rc;
++ struct dentry *lower_old_dentry;
++ struct dentry *lower_new_dentry;
++ struct dentry *lower_old_dir_dentry;
++ struct dentry *lower_new_dir_dentry;
++
++ lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
++ lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
++ dget(lower_old_dentry);
++ dget(lower_new_dentry);
++ lower_old_dir_dentry = dget_parent(lower_old_dentry);
++ lower_new_dir_dentry = dget_parent(lower_new_dentry);
++ lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
++ rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
++ lower_new_dir_dentry->d_inode, lower_new_dentry);
++ if (rc)
++ goto out_lock;
++ ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
++ if (new_dir != old_dir)
++ ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
++out_lock:
++ unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
++ dput(lower_new_dentry);
++ dput(lower_old_dentry);
++ return rc;
++}
++
++static int
++ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz)
++{
++ int rc;
++ struct dentry *lower_dentry;
++ char *decoded_name;
++ char *lower_buf;
++ mm_segment_t old_fs;
++ struct ecryptfs_crypt_stat *crypt_stat;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ if (!lower_dentry->d_inode->i_op ||
++ !lower_dentry->d_inode->i_op->readlink) {
++ rc = -EINVAL;
++ goto out;
++ }
++ /* Released in this function */
++ lower_buf = kmalloc(bufsiz, GFP_KERNEL);
++ if (lower_buf == NULL) {
++ ecryptfs_printk(KERN_ERR, "Out of memory\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ old_fs = get_fs();
++ set_fs(get_ds());
++ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
++ "lower_dentry->d_name.name = [%s]\n",
++ lower_dentry->d_name.name);
++ rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
++ (char __user *)lower_buf,
++ bufsiz);
++ set_fs(old_fs);
++ if (rc >= 0) {
++ crypt_stat = NULL;
++ rc = ecryptfs_decode_filename(crypt_stat, lower_buf, rc,
++ &decoded_name);
++ if (rc == -ENOMEM)
++ goto out_free_lower_buf;
++ if (rc > 0) {
++ ecryptfs_printk(KERN_DEBUG, "Copying [%d] bytes "
++ "to userspace: [%*s]\n", rc,
++ decoded_name);
++ if (copy_to_user(buf, decoded_name, rc))
++ rc = -EFAULT;
++ }
++ kfree(decoded_name);
++ ecryptfs_copy_attr_atime(dentry->d_inode,
++ lower_dentry->d_inode);
++ }
++out_free_lower_buf:
++ kfree(lower_buf);
++out:
++ return rc;
++}
++
++static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ char *buf;
++ int len = PAGE_SIZE, rc;
++ mm_segment_t old_fs;
++
++ /* Released in ecryptfs_put_link(); only release here on error */
++ buf = kmalloc(len, GFP_KERNEL);
++ if (!buf) {
++ rc = -ENOMEM;
++ goto out;
++ }
++ old_fs = get_fs();
++ set_fs(get_ds());
++ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
++ "dentry->d_name.name = [%s]\n", dentry->d_name.name);
++ rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
++ buf[rc] = '\0';
++ set_fs(old_fs);
++ if (rc < 0)
++ goto out_free;
++ rc = 0;
++ nd_set_link(nd, buf);
++ goto out;
++out_free:
++ kfree(buf);
++out:
++ return ERR_PTR(rc);
++}
++
++static void
++ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
++{
++ /* Free the char* */
++ kfree(nd_get_link(nd));
++}
++
++/**
++ * upper_size_to_lower_size
++ * @crypt_stat: Crypt_stat associated with file
++ * @upper_size: Size of the upper file
++ *
++ * Calculate the requried size of the lower file based on the
++ * specified size of the upper file. This calculation is based on the
++ * number of headers in the underlying file and the extent size.
++ *
++ * Returns Calculated size of the lower file.
++ */
++static loff_t
++upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
++ loff_t upper_size)
++{
++ loff_t lower_size;
++
++ lower_size = ( crypt_stat->header_extent_size
++ * crypt_stat->num_header_extents_at_front );
++ if (upper_size != 0) {
++ loff_t num_extents;
++
++ num_extents = upper_size >> crypt_stat->extent_shift;
++ if (upper_size & ~crypt_stat->extent_mask)
++ num_extents++;
++ lower_size += (num_extents * crypt_stat->extent_size);
++ }
++ return lower_size;
++}
++
++/**
++ * ecryptfs_truncate
++ * @dentry: The ecryptfs layer dentry
++ * @new_length: The length to expand the file to
++ *
++ * Function to handle truncations modifying the size of the file. Note
++ * that the file sizes are interpolated. When expanding, we are simply
++ * writing strings of 0's out. When truncating, we need to modify the
++ * underlying file size according to the page index interpolations.
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
++{
++ int rc = 0;
++ struct inode *inode = dentry->d_inode;
++ struct dentry *lower_dentry;
++ struct vfsmount *lower_mnt;
++ struct file fake_ecryptfs_file, *lower_file = NULL;
++ struct ecryptfs_crypt_stat *crypt_stat;
++ loff_t i_size = i_size_read(inode);
++ loff_t lower_size_before_truncate;
++ loff_t lower_size_after_truncate;
++
++ if (unlikely((new_length == i_size)))
++ goto out;
++ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
++ /* Set up a fake ecryptfs file, this is used to interface with
++ * the file in the underlying filesystem so that the
++ * truncation has an effect there as well. */
++ memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));
++ fake_ecryptfs_file.f_dentry = dentry;
++ /* Released at out_free: label */
++ ecryptfs_set_file_private(&fake_ecryptfs_file,
++ kmem_cache_alloc(ecryptfs_file_info_cache,
++ SLAB_KERNEL));
++ if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) {
++ rc = -ENOMEM;
++ goto out;
++ }
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ /* This dget & mntget is released through fput at out_fput: */
++ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
++ if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
++ O_RDWR))) {
++ ecryptfs_printk(KERN_ERR,
++ "Error opening dentry; rc = [%i]\n", rc);
++ goto out_free;
++ }
++ ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file);
++ /* Switch on growing or shrinking file */
++ if (new_length > i_size) {
++ rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR,
++ "Problem with fill_zeros\n");
++ goto out_fput;
++ }
++ i_size_write(inode, new_length);
++ rc = ecryptfs_write_inode_size_to_header(lower_file,
++ lower_dentry->d_inode,
++ inode);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR,
++ "Problem with ecryptfs_write"
++ "_inode_size\n");
++ goto out_fput;
++ }
++ } else { /* new_length < i_size_read(inode) */
++ vmtruncate(inode, new_length);
++ ecryptfs_write_inode_size_to_header(lower_file,
++ lower_dentry->d_inode,
++ inode);
++ /* We are reducing the size of the ecryptfs file, and need to
++ * know if we need to reduce the size of the lower file. */
++ lower_size_before_truncate =
++ upper_size_to_lower_size(crypt_stat, i_size);
++ lower_size_after_truncate =
++ upper_size_to_lower_size(crypt_stat, new_length);
++ if (lower_size_after_truncate < lower_size_before_truncate)
++ vmtruncate(lower_dentry->d_inode,
++ lower_size_after_truncate);
++ }
++ /* Update the access times */
++ lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime
++ = CURRENT_TIME;
++ mark_inode_dirty_sync(inode);
++out_fput:
++ if ((rc = ecryptfs_close_lower_file(lower_file)))
++ printk(KERN_ERR "Error closing lower_file\n");
++out_free:
++ if (ecryptfs_file_to_private(&fake_ecryptfs_file))
++ kmem_cache_free(ecryptfs_file_info_cache,
++ ecryptfs_file_to_private(&fake_ecryptfs_file));
++out:
++ return rc;
++}
++
++static int
++ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
++{
++ int rc;
++
++ if (nd) {
++ struct vfsmount *vfsmnt_save = nd->mnt;
++ struct dentry *dentry_save = nd->dentry;
++
++ nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry);
++ nd->dentry = ecryptfs_dentry_to_lower(nd->dentry);
++ rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
++ nd->mnt = vfsmnt_save;
++ nd->dentry = dentry_save;
++ } else
++ rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
++ return rc;
++}
++
++/**
++ * ecryptfs_setattr
++ * @dentry: dentry handle to the inode to modify
++ * @ia: Structure with flags of what to change and values
++ *
++ * Updates the metadata of an inode. If the update is to the size
++ * i.e. truncation, then ecryptfs_truncate will handle the size modification
++ * of both the ecryptfs inode and the lower inode.
++ *
++ * All other metadata changes will be passed right to the lower filesystem,
++ * and we will just update our inode to look like the lower.
++ */
++static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
++{
++ int rc = 0;
++ struct dentry *lower_dentry;
++ struct inode *inode;
++ struct inode *lower_inode;
++ struct ecryptfs_crypt_stat *crypt_stat;
++
++ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ inode = dentry->d_inode;
++ lower_inode = ecryptfs_inode_to_lower(inode);
++ if (ia->ia_valid & ATTR_SIZE) {
++ ecryptfs_printk(KERN_DEBUG,
++ "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
++ ia->ia_valid, ATTR_SIZE);
++ rc = ecryptfs_truncate(dentry, ia->ia_size);
++ /* ecryptfs_truncate handles resizing of the lower file */
++ ia->ia_valid &= ~ATTR_SIZE;
++ ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n",
++ ia->ia_valid);
++ if (rc < 0)
++ goto out;
++ }
++ rc = notify_change(lower_dentry, ia);
++out:
++ ecryptfs_copy_attr_all(inode, lower_inode);
++ return rc;
++}
++
++static int
++ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
++ size_t size, int flags)
++{
++ int rc = 0;
++ struct dentry *lower_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ if (!lower_dentry->d_inode->i_op->setxattr) {
++ rc = -ENOSYS;
++ goto out;
++ }
++ mutex_lock(&lower_dentry->d_inode->i_mutex);
++ rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value,
++ size, flags);
++ mutex_unlock(&lower_dentry->d_inode->i_mutex);
++out:
++ return rc;
++}
++
++static ssize_t
++ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
++ size_t size)
++{
++ int rc = 0;
++ struct dentry *lower_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ if (!lower_dentry->d_inode->i_op->getxattr) {
++ rc = -ENOSYS;
++ goto out;
++ }
++ mutex_lock(&lower_dentry->d_inode->i_mutex);
++ rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,
++ size);
++ mutex_unlock(&lower_dentry->d_inode->i_mutex);
++out:
++ return rc;
++}
++
++static ssize_t
++ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size)
++{
++ int rc = 0;
++ struct dentry *lower_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ if (!lower_dentry->d_inode->i_op->listxattr) {
++ rc = -ENOSYS;
++ goto out;
++ }
++ mutex_lock(&lower_dentry->d_inode->i_mutex);
++ rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size);
++ mutex_unlock(&lower_dentry->d_inode->i_mutex);
++out:
++ return rc;
++}
++
++static int ecryptfs_removexattr(struct dentry *dentry, const char *name)
++{
++ int rc = 0;
++ struct dentry *lower_dentry;
++
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ if (!lower_dentry->d_inode->i_op->removexattr) {
++ rc = -ENOSYS;
++ goto out;
++ }
++ mutex_lock(&lower_dentry->d_inode->i_mutex);
++ rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name);
++ mutex_unlock(&lower_dentry->d_inode->i_mutex);
++out:
++ return rc;
++}
++
++int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode)
++{
++ if ((ecryptfs_inode_to_lower(inode)
++ == (struct inode *)candidate_lower_inode))
++ return 1;
++ else
++ return 0;
++}
++
++int ecryptfs_inode_set(struct inode *inode, void *lower_inode)
++{
++ ecryptfs_init_inode(inode, (struct inode *)lower_inode);
++ return 0;
++}
++
++struct inode_operations ecryptfs_symlink_iops = {
++ .readlink = ecryptfs_readlink,
++ .follow_link = ecryptfs_follow_link,
++ .put_link = ecryptfs_put_link,
++ .permission = ecryptfs_permission,
++ .setattr = ecryptfs_setattr,
++ .setxattr = ecryptfs_setxattr,
++ .getxattr = ecryptfs_getxattr,
++ .listxattr = ecryptfs_listxattr,
++ .removexattr = ecryptfs_removexattr
++};
++
++struct inode_operations ecryptfs_dir_iops = {
++ .create = ecryptfs_create,
++ .lookup = ecryptfs_lookup,
++ .link = ecryptfs_link,
++ .unlink = ecryptfs_unlink,
++ .symlink = ecryptfs_symlink,
++ .mkdir = ecryptfs_mkdir,
++ .rmdir = ecryptfs_rmdir,
++ .mknod = ecryptfs_mknod,
++ .rename = ecryptfs_rename,
++ .permission = ecryptfs_permission,
++ .setattr = ecryptfs_setattr,
++ .setxattr = ecryptfs_setxattr,
++ .getxattr = ecryptfs_getxattr,
++ .listxattr = ecryptfs_listxattr,
++ .removexattr = ecryptfs_removexattr
++};
++
++struct inode_operations ecryptfs_main_iops = {
++ .permission = ecryptfs_permission,
++ .setattr = ecryptfs_setattr,
++ .setxattr = ecryptfs_setxattr,
++ .getxattr = ecryptfs_getxattr,
++ .listxattr = ecryptfs_listxattr,
++ .removexattr = ecryptfs_removexattr
++};
+diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
+new file mode 100644
+index 0000000..c3746f5
+--- /dev/null
++++ b/fs/ecryptfs/keystore.c
+@@ -0,0 +1,1091 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ * In-kernel key management code. Includes functions to parse and
++ * write authentication token-related packets with the underlying
++ * file.
++ *
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mhalcrow at us.ibm.com>
++ * Michael C. Thompson <mcthomps at 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/string.h>
++#include <linux/sched.h>
++#include <linux/syscalls.h>
++#include <linux/pagemap.h>
++#include <linux/key.h>
++#include <linux/random.h>
++#include <linux/crypto.h>
++#include <linux/scatterlist.h>
++#include "ecryptfs_kernel.h"
++
++/**
++ * request_key returned an error instead of a valid key address;
++ * determine the type of error, make appropriate log entries, and
++ * return an error code.
++ */
++int process_request_key_err(long err_code)
++{
++ int rc = 0;
++
++ switch (err_code) {
++ case ENOKEY:
++ ecryptfs_printk(KERN_WARNING, "No key\n");
++ rc = -ENOENT;
++ break;
++ case EKEYEXPIRED:
++ ecryptfs_printk(KERN_WARNING, "Key expired\n");
++ rc = -ETIME;
++ break;
++ case EKEYREVOKED:
++ ecryptfs_printk(KERN_WARNING, "Key revoked\n");
++ rc = -EINVAL;
++ break;
++ default:
++ ecryptfs_printk(KERN_WARNING, "Unknown error code: "
++ "[0x%.16x]\n", err_code);
++ rc = -EINVAL;
++ }
++ return rc;
++}
++
++static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
++{
++ struct list_head *walker;
++ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
++
++ walker = auth_tok_list_head->next;
++ while (walker != auth_tok_list_head) {
++ auth_tok_list_item =
++ list_entry(walker, struct ecryptfs_auth_tok_list_item,
++ list);
++ walker = auth_tok_list_item->list.next;
++ memset(auth_tok_list_item, 0,
++ sizeof(struct ecryptfs_auth_tok_list_item));
++ kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
++ auth_tok_list_item);
++ }
++}
++
++struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
++
++/**
++ * parse_packet_length
++ * @data: Pointer to memory containing length at offset
++ * @size: This function writes the decoded size to this memory
++ * address; zero on error
++ * @length_size: The number of bytes occupied by the encoded length
++ *
++ * Returns Zero on success
++ */
++static int parse_packet_length(unsigned char *data, size_t *size,
++ size_t *length_size)
++{
++ int rc = 0;
++
++ (*length_size) = 0;
++ (*size) = 0;
++ if (data[0] < 192) {
++ /* One-byte length */
++ (*size) = data[0];
++ (*length_size) = 1;
++ } else if (data[0] < 224) {
++ /* Two-byte length */
++ (*size) = ((data[0] - 192) * 256);
++ (*size) += (data[1] + 192);
++ (*length_size) = 2;
++ } else if (data[0] == 255) {
++ /* Five-byte length; we're not supposed to see this */
++ ecryptfs_printk(KERN_ERR, "Five-byte packet length not "
++ "supported\n");
++ rc = -EINVAL;
++ goto out;
++ } else {
++ ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");
++ rc = -EINVAL;
++ goto out;
++ }
++out:
++ return rc;
++}
++
++/**
++ * write_packet_length
++ * @dest: The byte array target into which to write the
++ * length. Must have at least 5 bytes allocated.
++ * @size: The length to write.
++ * @packet_size_length: The number of bytes used to encode the
++ * packet length is written to this address.
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int write_packet_length(char *dest, size_t size,
++ size_t *packet_size_length)
++{
++ int rc = 0;
++
++ if (size < 192) {
++ dest[0] = size;
++ (*packet_size_length) = 1;
++ } else if (size < 65536) {
++ dest[0] = (((size - 192) / 256) + 192);
++ dest[1] = ((size - 192) % 256);
++ (*packet_size_length) = 2;
++ } else {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_WARNING,
++ "Unsupported packet size: [%d]\n", size);
++ }
++ return rc;
++}
++
++/**
++ * parse_tag_3_packet
++ * @crypt_stat: The cryptographic context to modify based on packet
++ * contents.
++ * @data: The raw bytes of the packet.
++ * @auth_tok_list: eCryptfs parses packets into authentication tokens;
++ * a new authentication token will be placed at the end
++ * of this list for this packet.
++ * @new_auth_tok: Pointer to a pointer to memory that this function
++ * allocates; sets the memory address of the pointer to
++ * NULL on error. This object is added to the
++ * auth_tok_list.
++ * @packet_size: This function writes the size of the parsed packet
++ * into this memory location; zero on error.
++ * @max_packet_size: maximum number of bytes to parse
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int
++parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
++ unsigned char *data, struct list_head *auth_tok_list,
++ struct ecryptfs_auth_tok **new_auth_tok,
++ size_t *packet_size, size_t max_packet_size)
++{
++ int rc = 0;
++ size_t body_size;
++ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
++ size_t length_size;
++
++ (*packet_size) = 0;
++ (*new_auth_tok) = NULL;
++
++ /* we check that:
++ * one byte for the Tag 3 ID flag
++ * two bytes for the body size
++ * do not exceed the maximum_packet_size
++ */
++ if (unlikely((*packet_size) + 3 > max_packet_size)) {
++ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* check for Tag 3 identifyer - one byte */
++ if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
++ ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n",
++ ECRYPTFS_TAG_3_PACKET_TYPE);
++ rc = -EINVAL;
++ goto out;
++ }
++ /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
++ * at end of function upon failure */
++ auth_tok_list_item =
++ kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, SLAB_KERNEL);
++ if (!auth_tok_list_item) {
++ ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ memset(auth_tok_list_item, 0,
++ sizeof(struct ecryptfs_auth_tok_list_item));
++ (*new_auth_tok) = &auth_tok_list_item->auth_tok;
++
++ /* check for body size - one to two bytes */
++ rc = parse_packet_length(&data[(*packet_size)], &body_size,
++ &length_size);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
++ "rc = [%d]\n", rc);
++ goto out_free;
++ }
++ if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) {
++ ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
++ body_size);
++ rc = -EINVAL;
++ goto out_free;
++ }
++ (*packet_size) += length_size;
++
++ /* now we know the length of the remainting Tag 3 packet size:
++ * 5 fix bytes for: version string, cipher, S2K ID, hash algo,
++ * number of hash iterations
++ * ECRYPTFS_SALT_SIZE bytes for salt
++ * body_size bytes minus the stuff above is the encrypted key size
++ */
++ if (unlikely((*packet_size) + body_size > max_packet_size)) {
++ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
++ rc = -EINVAL;
++ goto out_free;
++ }
++
++ /* There are 5 characters of additional information in the
++ * packet */
++ (*new_auth_tok)->session_key.encrypted_key_size =
++ body_size - (0x05 + ECRYPTFS_SALT_SIZE);
++ ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n",
++ (*new_auth_tok)->session_key.encrypted_key_size);
++
++ /* Version 4 (from RFC2440) - one byte */
++ if (unlikely(data[(*packet_size)++] != 0x04)) {
++ ecryptfs_printk(KERN_DEBUG, "Unknown version number "
++ "[%d]\n", data[(*packet_size) - 1]);
++ rc = -EINVAL;
++ goto out_free;
++ }
++
++ /* cipher - one byte */
++ ecryptfs_cipher_code_to_string(crypt_stat->cipher,
++ (u16)data[(*packet_size)]);
++ /* A little extra work to differentiate among the AES key
++ * sizes; see RFC2440 */
++ switch(data[(*packet_size)++]) {
++ case RFC2440_CIPHER_AES_192:
++ crypt_stat->key_size = 24;
++ break;
++ default:
++ crypt_stat->key_size =
++ (*new_auth_tok)->session_key.encrypted_key_size;
++ }
++ ecryptfs_init_crypt_ctx(crypt_stat);
++ /* S2K identifier 3 (from RFC2440) */
++ if (unlikely(data[(*packet_size)++] != 0x03)) {
++ ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently "
++ "supported\n");
++ rc = -ENOSYS;
++ goto out_free;
++ }
++
++ /* TODO: finish the hash mapping */
++ /* hash algorithm - one byte */
++ switch (data[(*packet_size)++]) {
++ case 0x01: /* See RFC2440 for these numbers and their mappings */
++ /* Choose MD5 */
++ /* salt - ECRYPTFS_SALT_SIZE bytes */
++ memcpy((*new_auth_tok)->token.password.salt,
++ &data[(*packet_size)], ECRYPTFS_SALT_SIZE);
++ (*packet_size) += ECRYPTFS_SALT_SIZE;
++
++ /* This conversion was taken straight from RFC2440 */
++ /* number of hash iterations - one byte */
++ (*new_auth_tok)->token.password.hash_iterations =
++ ((u32) 16 + (data[(*packet_size)] & 15))
++ << ((data[(*packet_size)] >> 4) + 6);
++ (*packet_size)++;
++
++ /* encrypted session key -
++ * (body_size-5-ECRYPTFS_SALT_SIZE) bytes */
++ memcpy((*new_auth_tok)->session_key.encrypted_key,
++ &data[(*packet_size)],
++ (*new_auth_tok)->session_key.encrypted_key_size);
++ (*packet_size) +=
++ (*new_auth_tok)->session_key.encrypted_key_size;
++ (*new_auth_tok)->session_key.flags &=
++ ~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
++ (*new_auth_tok)->session_key.flags |=
++ ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
++ (*new_auth_tok)->token.password.hash_algo = 0x01;
++ break;
++ default:
++ ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: "
++ "[%d]\n", data[(*packet_size) - 1]);
++ rc = -ENOSYS;
++ goto out_free;
++ }
++ (*new_auth_tok)->token_type = ECRYPTFS_PASSWORD;
++ /* TODO: Parametarize; we might actually want userspace to
++ * decrypt the session key. */
++ ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
++ ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
++ ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
++ ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
++ list_add(&auth_tok_list_item->list, auth_tok_list);
++ goto out;
++out_free:
++ (*new_auth_tok) = NULL;
++ memset(auth_tok_list_item, 0,
++ sizeof(struct ecryptfs_auth_tok_list_item));
++ kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
++ auth_tok_list_item);
++out:
++ if (rc)
++ (*packet_size) = 0;
++ return rc;
++}
++
++/**
++ * parse_tag_11_packet
++ * @data: The raw bytes of the packet
++ * @contents: This function writes the data contents of the literal
++ * packet into this memory location
++ * @max_contents_bytes: The maximum number of bytes that this function
++ * is allowed to write into contents
++ * @tag_11_contents_size: This function writes the size of the parsed
++ * contents into this memory location; zero on
++ * error
++ * @packet_size: This function writes the size of the parsed packet
++ * into this memory location; zero on error
++ * @max_packet_size: maximum number of bytes to parse
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int
++parse_tag_11_packet(unsigned char *data, unsigned char *contents,
++ size_t max_contents_bytes, size_t *tag_11_contents_size,
++ size_t *packet_size, size_t max_packet_size)
++{
++ int rc = 0;
++ size_t body_size;
++ size_t length_size;
++
++ (*packet_size) = 0;
++ (*tag_11_contents_size) = 0;
++
++ /* check that:
++ * one byte for the Tag 11 ID flag
++ * two bytes for the Tag 11 length
++ * do not exceed the maximum_packet_size
++ */
++ if (unlikely((*packet_size) + 3 > max_packet_size)) {
++ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* check for Tag 11 identifyer - one byte */
++ if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {
++ ecryptfs_printk(KERN_WARNING,
++ "Invalid tag 11 packet format\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* get Tag 11 content length - one or two bytes */
++ rc = parse_packet_length(&data[(*packet_size)], &body_size,
++ &length_size);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING,
++ "Invalid tag 11 packet format\n");
++ goto out;
++ }
++ (*packet_size) += length_size;
++
++ if (body_size < 13) {
++ ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
++ body_size);
++ rc = -EINVAL;
++ goto out;
++ }
++ /* We have 13 bytes of surrounding packet values */
++ (*tag_11_contents_size) = (body_size - 13);
++
++ /* now we know the length of the remainting Tag 11 packet size:
++ * 14 fix bytes for: special flag one, special flag two,
++ * 12 skipped bytes
++ * body_size bytes minus the stuff above is the Tag 11 content
++ */
++ /* FIXME why is the body size one byte smaller than the actual
++ * size of the body?
++ * this seems to be an error here as well as in
++ * write_tag_11_packet() */
++ if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
++ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* special flag one - one byte */
++ if (data[(*packet_size)++] != 0x62) {
++ ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* special flag two - one byte */
++ if (data[(*packet_size)++] != 0x08) {
++ ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* skip the next 12 bytes */
++ (*packet_size) += 12; /* We don't care about the filename or
++ * the timestamp */
++
++ /* get the Tag 11 contents - tag_11_contents_size bytes */
++ memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size));
++ (*packet_size) += (*tag_11_contents_size);
++
++out:
++ if (rc) {
++ (*packet_size) = 0;
++ (*tag_11_contents_size) = 0;
++ }
++ return rc;
++}
++
++/**
++ * decrypt_session_key - Decrypt the session key with the given auth_tok.
++ *
++ * Returns Zero on success; non-zero error otherwise.
++ */
++static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
++ struct ecryptfs_crypt_stat *crypt_stat)
++{
++ struct ecryptfs_password *password_s_ptr;
++ struct scatterlist src_sg[2], dst_sg[2];
++ struct mutex *tfm_mutex = NULL;
++ /* TODO: Use virt_to_scatterlist for these */
++ char *encrypted_session_key;
++ char *session_key;
++ struct blkcipher_desc desc = {
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP
++ };
++ int rc = 0;
++
++ password_s_ptr = &auth_tok->token.password;
++ if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags,
++ ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET))
++ ecryptfs_printk(KERN_DEBUG, "Session key encryption key "
++ "set; skipping key generation\n");
++ ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])"
++ ":\n",
++ password_s_ptr->session_key_encryption_key_bytes);
++ if (ecryptfs_verbosity > 0)
++ ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key,
++ password_s_ptr->
++ session_key_encryption_key_bytes);
++ if (!strcmp(crypt_stat->cipher,
++ crypt_stat->mount_crypt_stat->global_default_cipher_name)
++ && crypt_stat->mount_crypt_stat->global_key_tfm) {
++ desc.tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
++ tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
++ } else {
++ char *full_alg_name;
++
++ rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
++ crypt_stat->cipher,
++ "ecb");
++ if (rc)
++ goto out;
++ desc.tfm = crypto_alloc_blkcipher(full_alg_name, 0,
++ CRYPTO_ALG_ASYNC);
++ kfree(full_alg_name);
++ if (IS_ERR(desc.tfm)) {
++ rc = PTR_ERR(desc.tfm);
++ printk(KERN_ERR "Error allocating crypto context; "
++ "rc = [%d]\n", rc);
++ goto out;
++ }
++ crypto_blkcipher_set_flags(desc.tfm, CRYPTO_TFM_REQ_WEAK_KEY);
++ }
++ if (tfm_mutex)
++ mutex_lock(tfm_mutex);
++ rc = crypto_blkcipher_setkey(desc.tfm,
++ password_s_ptr->session_key_encryption_key,
++ crypt_stat->key_size);
++ if (rc < 0) {
++ printk(KERN_ERR "Error setting key for crypto context\n");
++ rc = -EINVAL;
++ goto out_free_tfm;
++ }
++ /* TODO: virt_to_scatterlist */
++ encrypted_session_key = (char *)__get_free_page(GFP_KERNEL);
++ if (!encrypted_session_key) {
++ ecryptfs_printk(KERN_ERR, "Out of memory\n");
++ rc = -ENOMEM;
++ goto out_free_tfm;
++ }
++ session_key = (char *)__get_free_page(GFP_KERNEL);
++ if (!session_key) {
++ kfree(encrypted_session_key);
++ ecryptfs_printk(KERN_ERR, "Out of memory\n");
++ rc = -ENOMEM;
++ goto out_free_tfm;
++ }
++ memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key,
++ auth_tok->session_key.encrypted_key_size);
++ src_sg[0].page = virt_to_page(encrypted_session_key);
++ src_sg[0].offset = 0;
++ BUG_ON(auth_tok->session_key.encrypted_key_size > PAGE_CACHE_SIZE);
++ src_sg[0].length = auth_tok->session_key.encrypted_key_size;
++ dst_sg[0].page = virt_to_page(session_key);
++ dst_sg[0].offset = 0;
++ auth_tok->session_key.decrypted_key_size =
++ auth_tok->session_key.encrypted_key_size;
++ dst_sg[0].length = auth_tok->session_key.encrypted_key_size;
++ rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg,
++ auth_tok->session_key.encrypted_key_size);
++ if (rc) {
++ printk(KERN_ERR "Error decrypting; rc = [%d]\n", rc);
++ goto out_free_memory;
++ }
++ auth_tok->session_key.decrypted_key_size =
++ auth_tok->session_key.encrypted_key_size;
++ memcpy(auth_tok->session_key.decrypted_key, session_key,
++ auth_tok->session_key.decrypted_key_size);
++ auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
++ memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
++ auth_tok->session_key.decrypted_key_size);
++ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
++ ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
++ if (ecryptfs_verbosity > 0)
++ ecryptfs_dump_hex(crypt_stat->key,
++ crypt_stat->key_size);
++out_free_memory:
++ memset(encrypted_session_key, 0, PAGE_CACHE_SIZE);
++ free_page((unsigned long)encrypted_session_key);
++ memset(session_key, 0, PAGE_CACHE_SIZE);
++ free_page((unsigned long)session_key);
++out_free_tfm:
++ if (tfm_mutex)
++ mutex_unlock(tfm_mutex);
++ else
++ crypto_free_blkcipher(desc.tfm);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_parse_packet_set
++ * @dest: The header page in memory
++ * @version: Version of file format, to guide parsing behavior
++ *
++ * Get crypt_stat to have the file's session key if the requisite key
++ * is available to decrypt the session key.
++ *
++ * Returns Zero if a valid authentication token was retrieved and
++ * processed; negative value for file not encrypted or for error
++ * conditions.
++ */
++int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
++ unsigned char *src,
++ struct dentry *ecryptfs_dentry)
++{
++ size_t i = 0;
++ int rc = 0;
++ size_t found_auth_tok = 0;
++ size_t next_packet_is_auth_tok_packet;
++ char sig[ECRYPTFS_SIG_SIZE_HEX];
++ struct list_head auth_tok_list;
++ struct list_head *walker;
++ struct ecryptfs_auth_tok *chosen_auth_tok = NULL;
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
++ &ecryptfs_superblock_to_private(
++ ecryptfs_dentry->d_sb)->mount_crypt_stat;
++ struct ecryptfs_auth_tok *candidate_auth_tok = NULL;
++ size_t packet_size;
++ struct ecryptfs_auth_tok *new_auth_tok;
++ unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE];
++ size_t tag_11_contents_size;
++ size_t tag_11_packet_size;
++
++ INIT_LIST_HEAD(&auth_tok_list);
++ /* Parse the header to find as many packets as we can, these will be
++ * added the our &auth_tok_list */
++ next_packet_is_auth_tok_packet = 1;
++ while (next_packet_is_auth_tok_packet) {
++ size_t max_packet_size = ((PAGE_CACHE_SIZE - 8) - i);
++
++ switch (src[i]) {
++ case ECRYPTFS_TAG_3_PACKET_TYPE:
++ rc = parse_tag_3_packet(crypt_stat,
++ (unsigned char *)&src[i],
++ &auth_tok_list, &new_auth_tok,
++ &packet_size, max_packet_size);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error parsing "
++ "tag 3 packet\n");
++ rc = -EIO;
++ goto out_wipe_list;
++ }
++ i += packet_size;
++ rc = parse_tag_11_packet((unsigned char *)&src[i],
++ sig_tmp_space,
++ ECRYPTFS_SIG_SIZE,
++ &tag_11_contents_size,
++ &tag_11_packet_size,
++ max_packet_size);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "No valid "
++ "(ecryptfs-specific) literal "
++ "packet containing "
++ "authentication token "
++ "signature found after "
++ "tag 3 packet\n");
++ rc = -EIO;
++ goto out_wipe_list;
++ }
++ i += tag_11_packet_size;
++ if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
++ ecryptfs_printk(KERN_ERR, "Expected "
++ "signature of size [%d]; "
++ "read size [%d]\n",
++ ECRYPTFS_SIG_SIZE,
++ tag_11_contents_size);
++ rc = -EIO;
++ goto out_wipe_list;
++ }
++ ecryptfs_to_hex(new_auth_tok->token.password.signature,
++ sig_tmp_space, tag_11_contents_size);
++ new_auth_tok->token.password.signature[
++ ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
++ ECRYPTFS_SET_FLAG(crypt_stat->flags,
++ ECRYPTFS_ENCRYPTED);
++ break;
++ case ECRYPTFS_TAG_11_PACKET_TYPE:
++ ecryptfs_printk(KERN_WARNING, "Invalid packet set "
++ "(Tag 11 not allowed by itself)\n");
++ rc = -EIO;
++ goto out_wipe_list;
++ break;
++ default:
++ ecryptfs_printk(KERN_DEBUG, "No packet at offset "
++ "[%d] of the file header; hex value of "
++ "character is [0x%.2x]\n", i, src[i]);
++ next_packet_is_auth_tok_packet = 0;
++ }
++ }
++ if (list_empty(&auth_tok_list)) {
++ rc = -EINVAL; /* Do not support non-encrypted files in
++ * the 0.1 release */
++ goto out;
++ }
++ /* If we have a global auth tok, then we should try to use
++ * it */
++ if (mount_crypt_stat->global_auth_tok) {
++ memcpy(sig, mount_crypt_stat->global_auth_tok_sig,
++ ECRYPTFS_SIG_SIZE_HEX);
++ chosen_auth_tok = mount_crypt_stat->global_auth_tok;
++ } else
++ BUG(); /* We should always have a global auth tok in
++ * the 0.1 release */
++ /* Scan list to see if our chosen_auth_tok works */
++ list_for_each(walker, &auth_tok_list) {
++ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
++ auth_tok_list_item =
++ list_entry(walker, struct ecryptfs_auth_tok_list_item,
++ list);
++ candidate_auth_tok = &auth_tok_list_item->auth_tok;
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG,
++ "Considering cadidate auth tok:\n");
++ ecryptfs_dump_auth_tok(candidate_auth_tok);
++ }
++ /* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */
++ if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD
++ && !strncmp(candidate_auth_tok->token.password.signature,
++ sig, ECRYPTFS_SIG_SIZE_HEX)) {
++ found_auth_tok = 1;
++ goto leave_list;
++ /* TODO: Transfer the common salt into the
++ * crypt_stat salt */
++ }
++ }
++leave_list:
++ if (!found_auth_tok) {
++ ecryptfs_printk(KERN_ERR, "Could not find authentication "
++ "token on temporary list for sig [%.*s]\n",
++ ECRYPTFS_SIG_SIZE_HEX, sig);
++ rc = -EIO;
++ goto out_wipe_list;
++ } else {
++ memcpy(&(candidate_auth_tok->token.password),
++ &(chosen_auth_tok->token.password),
++ sizeof(struct ecryptfs_password));
++ rc = decrypt_session_key(candidate_auth_tok, crypt_stat);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error decrypting the "
++ "session key\n");
++ goto out_wipe_list;
++ }
++ rc = ecryptfs_compute_root_iv(crypt_stat);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error computing "
++ "the root IV\n");
++ goto out_wipe_list;
++ }
++ }
++ rc = ecryptfs_init_crypt_ctx(crypt_stat);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error initializing crypto "
++ "context for cipher [%s]; rc = [%d]\n",
++ crypt_stat->cipher, rc);
++ }
++out_wipe_list:
++ wipe_auth_tok_list(&auth_tok_list);
++out:
++ return rc;
++}
++
++/**
++ * write_tag_11_packet
++ * @dest: Target into which Tag 11 packet is to be written
++ * @max: Maximum packet length
++ * @contents: Byte array of contents to copy in
++ * @contents_length: Number of bytes in contents
++ * @packet_length: Length of the Tag 11 packet written; zero on error
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int
++write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length,
++ size_t *packet_length)
++{
++ int rc = 0;
++ size_t packet_size_length;
++
++ (*packet_length) = 0;
++ if ((13 + contents_length) > max) {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_ERR, "Packet length larger than "
++ "maximum allowable\n");
++ goto out;
++ }
++ /* General packet header */
++ /* Packet tag */
++ dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
++ /* Packet length */
++ rc = write_packet_length(&dest[(*packet_length)],
++ (13 + contents_length), &packet_size_length);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error generating tag 11 packet "
++ "header; cannot generate packet length\n");
++ goto out;
++ }
++ (*packet_length) += packet_size_length;
++ /* Tag 11 specific */
++ /* One-octet field that describes how the data is formatted */
++ dest[(*packet_length)++] = 0x62; /* binary data */
++ /* One-octet filename length followed by filename */
++ dest[(*packet_length)++] = 8;
++ memcpy(&dest[(*packet_length)], "_CONSOLE", 8);
++ (*packet_length) += 8;
++ /* Four-octet number indicating modification date */
++ memset(&dest[(*packet_length)], 0x00, 4);
++ (*packet_length) += 4;
++ /* Remainder is literal data */
++ memcpy(&dest[(*packet_length)], contents, contents_length);
++ (*packet_length) += contents_length;
++ out:
++ if (rc)
++ (*packet_length) = 0;
++ return rc;
++}
++
++/**
++ * write_tag_3_packet
++ * @dest: Buffer into which to write the packet
++ * @max: Maximum number of bytes that can be written
++ * @auth_tok: Authentication token
++ * @crypt_stat: The cryptographic context
++ * @key_rec: encrypted key
++ * @packet_size: This function will write the number of bytes that end
++ * up constituting the packet; set to zero on error
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int
++write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct ecryptfs_key_record *key_rec, size_t *packet_size)
++{
++ size_t i;
++ size_t signature_is_valid = 0;
++ size_t encrypted_session_key_valid = 0;
++ char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
++ struct scatterlist dest_sg[2];
++ struct scatterlist src_sg[2];
++ struct mutex *tfm_mutex = NULL;
++ size_t key_rec_size;
++ size_t packet_size_length;
++ size_t cipher_code;
++ struct blkcipher_desc desc = {
++ .tfm = NULL,
++ .flags = CRYPTO_TFM_REQ_MAY_SLEEP
++ };
++ int rc = 0;
++
++ (*packet_size) = 0;
++ /* Check for a valid signature on the auth_tok */
++ for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++)
++ signature_is_valid |= auth_tok->token.password.signature[i];
++ if (!signature_is_valid)
++ BUG();
++ ecryptfs_from_hex((*key_rec).sig, auth_tok->token.password.signature,
++ ECRYPTFS_SIG_SIZE);
++ encrypted_session_key_valid = 0;
++ for (i = 0; i < crypt_stat->key_size; i++)
++ encrypted_session_key_valid |=
++ auth_tok->session_key.encrypted_key[i];
++ if (encrypted_session_key_valid) {
++ memcpy((*key_rec).enc_key,
++ auth_tok->session_key.encrypted_key,
++ auth_tok->session_key.encrypted_key_size);
++ goto encrypted_session_key_set;
++ }
++ if (auth_tok->session_key.encrypted_key_size == 0)
++ auth_tok->session_key.encrypted_key_size =
++ crypt_stat->key_size;
++ if (crypt_stat->key_size == 24
++ && strcmp("aes", crypt_stat->cipher) == 0) {
++ memset((crypt_stat->key + 24), 0, 8);
++ auth_tok->session_key.encrypted_key_size = 32;
++ }
++ (*key_rec).enc_key_size =
++ auth_tok->session_key.encrypted_key_size;
++ if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
++ ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) {
++ ecryptfs_printk(KERN_DEBUG, "Using previously generated "
++ "session key encryption key of size [%d]\n",
++ auth_tok->token.password.
++ session_key_encryption_key_bytes);
++ memcpy(session_key_encryption_key,
++ auth_tok->token.password.session_key_encryption_key,
++ crypt_stat->key_size);
++ ecryptfs_printk(KERN_DEBUG,
++ "Cached session key " "encryption key: \n");
++ if (ecryptfs_verbosity > 0)
++ ecryptfs_dump_hex(session_key_encryption_key, 16);
++ }
++ if (unlikely(ecryptfs_verbosity > 0)) {
++ ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
++ ecryptfs_dump_hex(session_key_encryption_key, 16);
++ }
++ rc = virt_to_scatterlist(crypt_stat->key,
++ (*key_rec).enc_key_size, src_sg, 2);
++ if (!rc) {
++ ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
++ "for crypt_stat session key\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ rc = virt_to_scatterlist((*key_rec).enc_key,
++ (*key_rec).enc_key_size, dest_sg, 2);
++ if (!rc) {
++ ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
++ "for crypt_stat encrypted session key\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ if (!strcmp(crypt_stat->cipher,
++ crypt_stat->mount_crypt_stat->global_default_cipher_name)
++ && crypt_stat->mount_crypt_stat->global_key_tfm) {
++ desc.tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
++ tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
++ } else {
++ char *full_alg_name;
++
++ rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
++ crypt_stat->cipher,
++ "ecb");
++ if (rc)
++ goto out;
++ desc.tfm = crypto_alloc_blkcipher(full_alg_name, 0,
++ CRYPTO_ALG_ASYNC);
++ kfree(full_alg_name);
++ if (IS_ERR(desc.tfm)) {
++ rc = PTR_ERR(desc.tfm);
++ ecryptfs_printk(KERN_ERR, "Could not initialize crypto "
++ "context for cipher [%s]; rc = [%d]\n",
++ crypt_stat->cipher, rc);
++ goto out;
++ }
++ crypto_blkcipher_set_flags(desc.tfm, CRYPTO_TFM_REQ_WEAK_KEY);
++ }
++ if (tfm_mutex)
++ mutex_lock(tfm_mutex);
++ rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key,
++ crypt_stat->key_size);
++ if (rc < 0) {
++ if (tfm_mutex)
++ mutex_unlock(tfm_mutex);
++ ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
++ "context; rc = [%d]\n", rc);
++ goto out;
++ }
++ rc = 0;
++ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
++ crypt_stat->key_size);
++ rc = crypto_blkcipher_encrypt(&desc, dest_sg, src_sg,
++ (*key_rec).enc_key_size);
++ if (rc) {
++ printk(KERN_ERR "Error encrypting; rc = [%d]\n", rc);
++ goto out;
++ }
++ if (tfm_mutex)
++ mutex_unlock(tfm_mutex);
++ ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
++ if (ecryptfs_verbosity > 0)
++ ecryptfs_dump_hex((*key_rec).enc_key,
++ (*key_rec).enc_key_size);
++encrypted_session_key_set:
++ /* Now we have a valid key_rec. Append it to the
++ * key_rec set. */
++ key_rec_size = (sizeof(struct ecryptfs_key_record)
++ - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES
++ + ((*key_rec).enc_key_size));
++ /* TODO: Include a packet size limit as a parameter to this
++ * function once we have multi-packet headers (for versions
++ * later than 0.1 */
++ if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) {
++ ecryptfs_printk(KERN_ERR, "Keyset too large\n");
++ rc = -EINVAL;
++ goto out;
++ }
++ /* TODO: Packet size limit */
++ /* We have 5 bytes of surrounding packet data */
++ if ((0x05 + ECRYPTFS_SALT_SIZE
++ + (*key_rec).enc_key_size) >= max) {
++ ecryptfs_printk(KERN_ERR, "Authentication token is too "
++ "large\n");
++ rc = -EINVAL;
++ goto out;
++ }
++ /* This format is inspired by OpenPGP; see RFC 2440
++ * packet tag 3 */
++ dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
++ /* ver+cipher+s2k+hash+salt+iter+enc_key */
++ rc = write_packet_length(&dest[(*packet_size)],
++ (0x05 + ECRYPTFS_SALT_SIZE
++ + (*key_rec).enc_key_size),
++ &packet_size_length);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet "
++ "header; cannot generate packet length\n");
++ goto out;
++ }
++ (*packet_size) += packet_size_length;
++ dest[(*packet_size)++] = 0x04; /* version 4 */
++ cipher_code = ecryptfs_code_for_cipher_string(crypt_stat);
++ if (cipher_code == 0) {
++ ecryptfs_printk(KERN_WARNING, "Unable to generate code for "
++ "cipher [%s]\n", crypt_stat->cipher);
++ rc = -EINVAL;
++ goto out;
++ }
++ dest[(*packet_size)++] = cipher_code;
++ dest[(*packet_size)++] = 0x03; /* S2K */
++ dest[(*packet_size)++] = 0x01; /* MD5 (TODO: parameterize) */
++ memcpy(&dest[(*packet_size)], auth_tok->token.password.salt,
++ ECRYPTFS_SALT_SIZE);
++ (*packet_size) += ECRYPTFS_SALT_SIZE; /* salt */
++ dest[(*packet_size)++] = 0x60; /* hash iterations (65536) */
++ memcpy(&dest[(*packet_size)], (*key_rec).enc_key,
++ (*key_rec).enc_key_size);
++ (*packet_size) += (*key_rec).enc_key_size;
++out:
++ if (desc.tfm && !tfm_mutex)
++ crypto_free_blkcipher(desc.tfm);
++ if (rc)
++ (*packet_size) = 0;
++ return rc;
++}
++
++/**
++ * ecryptfs_generate_key_packet_set
++ * @dest: Virtual address from which to write the key record set
++ * @crypt_stat: The cryptographic context from which the
++ * authentication tokens will be retrieved
++ * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat
++ * for the global parameters
++ * @len: The amount written
++ * @max: The maximum amount of data allowed to be written
++ *
++ * Generates a key packet set and writes it to the virtual address
++ * passed in.
++ *
++ * Returns zero on success; non-zero on error.
++ */
++int
++ecryptfs_generate_key_packet_set(char *dest_base,
++ struct ecryptfs_crypt_stat *crypt_stat,
++ struct dentry *ecryptfs_dentry, size_t *len,
++ size_t max)
++{
++ int rc = 0;
++ struct ecryptfs_auth_tok *auth_tok;
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
++ &ecryptfs_superblock_to_private(
++ ecryptfs_dentry->d_sb)->mount_crypt_stat;
++ size_t written;
++ struct ecryptfs_key_record key_rec;
++
++ (*len) = 0;
++ if (mount_crypt_stat->global_auth_tok) {
++ auth_tok = mount_crypt_stat->global_auth_tok;
++ if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
++ rc = write_tag_3_packet((dest_base + (*len)),
++ max, auth_tok,
++ crypt_stat, &key_rec,
++ &written);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error "
++ "writing tag 3 packet\n");
++ goto out;
++ }
++ (*len) += written;
++ /* Write auth tok signature packet */
++ rc = write_tag_11_packet(
++ (dest_base + (*len)),
++ (max - (*len)),
++ key_rec.sig, ECRYPTFS_SIG_SIZE, &written);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error writing "
++ "auth tok signature packet\n");
++ goto out;
++ }
++ (*len) += written;
++ } else {
++ ecryptfs_printk(KERN_WARNING, "Unsupported "
++ "authentication token type\n");
++ rc = -EINVAL;
++ goto out;
++ }
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error writing "
++ "authentication token packet with sig "
++ "= [%s]\n",
++ mount_crypt_stat->global_auth_tok_sig);
++ rc = -EIO;
++ goto out;
++ }
++ } else
++ BUG();
++ if (likely((max - (*len)) > 0)) {
++ dest_base[(*len)] = 0x00;
++ } else {
++ ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n");
++ rc = -EIO;
++ }
++out:
++ if (rc)
++ (*len) = 0;
++ return rc;
++}
+diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
+new file mode 100644
+index 0000000..a78d87d
+--- /dev/null
++++ b/fs/ecryptfs/main.c
+@@ -0,0 +1,821 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ *
++ * Copyright (C) 1997-2003 Erez Zadok
++ * Copyright (C) 2001-2003 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at us.ibm.com>
++ * Michael C. Thompson <mcthomps at 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/dcache.h>
++#include <linux/file.h>
++#include <linux/module.h>
++#include <linux/namei.h>
++#include <linux/skbuff.h>
++#include <linux/crypto.h>
++#include <linux/netlink.h>
++#include <linux/mount.h>
++#include <linux/dcache.h>
++#include <linux/pagemap.h>
++#include <linux/key.h>
++#include <linux/parser.h>
++#include "ecryptfs_kernel.h"
++
++/**
++ * Module parameter that defines the ecryptfs_verbosity level.
++ */
++int ecryptfs_verbosity = 0;
++
++module_param(ecryptfs_verbosity, int, 0);
++MODULE_PARM_DESC(ecryptfs_verbosity,
++ "Initial verbosity level (0 or 1; defaults to "
++ "0, which is Quiet)");
++
++void __ecryptfs_printk(const char *fmt, ...)
++{
++ va_list args;
++ va_start(args, fmt);
++ if (fmt[1] == '7') { /* KERN_DEBUG */
++ if (ecryptfs_verbosity >= 1)
++ vprintk(fmt, args);
++ } else
++ vprintk(fmt, args);
++ va_end(args);
++}
++
++/**
++ * ecryptfs_interpose
++ * @lower_dentry: Existing dentry in the lower filesystem
++ * @dentry: ecryptfs' dentry
++ * @sb: ecryptfs's super_block
++ * @flag: If set to true, then d_add is called, else d_instantiate is called
++ *
++ * Interposes upper and lower dentries.
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
++ struct super_block *sb, int flag)
++{
++ struct inode *lower_inode;
++ struct inode *inode;
++ int rc = 0;
++
++ lower_inode = lower_dentry->d_inode;
++ if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
++ rc = -EXDEV;
++ goto out;
++ }
++ if (!igrab(lower_inode)) {
++ rc = -ESTALE;
++ goto out;
++ }
++ inode = iget5_locked(sb, (unsigned long)lower_inode,
++ ecryptfs_inode_test, ecryptfs_inode_set,
++ lower_inode);
++ if (!inode) {
++ rc = -EACCES;
++ iput(lower_inode);
++ goto out;
++ }
++ if (inode->i_state & I_NEW)
++ unlock_new_inode(inode);
++ else
++ iput(lower_inode);
++ if (S_ISLNK(lower_inode->i_mode))
++ inode->i_op = &ecryptfs_symlink_iops;
++ else if (S_ISDIR(lower_inode->i_mode))
++ inode->i_op = &ecryptfs_dir_iops;
++ if (S_ISDIR(lower_inode->i_mode))
++ inode->i_fop = &ecryptfs_dir_fops;
++ if (special_file(lower_inode->i_mode))
++ init_special_inode(inode, lower_inode->i_mode,
++ lower_inode->i_rdev);
++ dentry->d_op = &ecryptfs_dops;
++ if (flag)
++ d_add(dentry, inode);
++ else
++ d_instantiate(dentry, inode);
++ ecryptfs_copy_attr_all(inode, lower_inode);
++ /* This size will be overwritten for real files w/ headers and
++ * other metadata */
++ ecryptfs_copy_inode_size(inode, lower_inode);
++out:
++ return rc;
++}
++
++enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
++ ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
++ ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
++ ecryptfs_opt_passthrough, ecryptfs_opt_err };
++
++static match_table_t tokens = {
++ {ecryptfs_opt_sig, "sig=%s"},
++ {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
++ {ecryptfs_opt_debug, "debug=%u"},
++ {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
++ {ecryptfs_opt_cipher, "cipher=%s"},
++ {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
++ {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
++ {ecryptfs_opt_passthrough, "ecryptfs_passthrough"},
++ {ecryptfs_opt_err, NULL}
++};
++
++/**
++ * ecryptfs_verify_version
++ * @version: The version number to confirm
++ *
++ * Returns zero on good version; non-zero otherwise
++ */
++static int ecryptfs_verify_version(u16 version)
++{
++ int rc = 0;
++ unsigned char major;
++ unsigned char minor;
++
++ major = ((version >> 8) & 0xFF);
++ minor = (version & 0xFF);
++ if (major != ECRYPTFS_VERSION_MAJOR) {
++ ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
++ "Expected [%d]; got [%d]\n",
++ ECRYPTFS_VERSION_MAJOR, major);
++ rc = -EINVAL;
++ goto out;
++ }
++ if (minor != ECRYPTFS_VERSION_MINOR) {
++ ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
++ "Expected [%d]; got [%d]\n",
++ ECRYPTFS_VERSION_MINOR, minor);
++ rc = -EINVAL;
++ goto out;
++ }
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_parse_options
++ * @sb: The ecryptfs super block
++ * @options: The options pased to the kernel
++ *
++ * Parse mount options:
++ * debug=N - ecryptfs_verbosity level for debug output
++ * sig=XXX - description(signature) of the key to use
++ *
++ * Returns the dentry object of the lower-level (lower/interposed)
++ * directory; We want to mount our stackable file system on top of
++ * that lower directory.
++ *
++ * The signature of the key to use must be the description of a key
++ * already in the keyring. Mounting will fail if the key can not be
++ * found.
++ *
++ * Returns zero on success; non-zero on error
++ */
++static int ecryptfs_parse_options(struct super_block *sb, char *options)
++{
++ char *p;
++ int rc = 0;
++ int sig_set = 0;
++ int cipher_name_set = 0;
++ int cipher_key_bytes;
++ int cipher_key_bytes_set = 0;
++ struct key *auth_tok_key = NULL;
++ struct ecryptfs_auth_tok *auth_tok = NULL;
++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
++ &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
++ substring_t args[MAX_OPT_ARGS];
++ int token;
++ char *sig_src;
++ char *sig_dst;
++ char *debug_src;
++ char *cipher_name_dst;
++ char *cipher_name_src;
++ char *cipher_key_bytes_src;
++ int cipher_name_len;
++
++ if (!options) {
++ rc = -EINVAL;
++ goto out;
++ }
++ while ((p = strsep(&options, ",")) != NULL) {
++ if (!*p)
++ continue;
++ token = match_token(p, tokens, args);
++ switch (token) {
++ case ecryptfs_opt_sig:
++ case ecryptfs_opt_ecryptfs_sig:
++ sig_src = args[0].from;
++ sig_dst =
++ mount_crypt_stat->global_auth_tok_sig;
++ memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX);
++ sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0';
++ ecryptfs_printk(KERN_DEBUG,
++ "The mount_crypt_stat "
++ "global_auth_tok_sig set to: "
++ "[%s]\n", sig_dst);
++ sig_set = 1;
++ break;
++ case ecryptfs_opt_debug:
++ case ecryptfs_opt_ecryptfs_debug:
++ debug_src = args[0].from;
++ ecryptfs_verbosity =
++ (int)simple_strtol(debug_src, &debug_src,
++ 0);
++ ecryptfs_printk(KERN_DEBUG,
++ "Verbosity set to [%d]" "\n",
++ ecryptfs_verbosity);
++ break;
++ case ecryptfs_opt_cipher:
++ case ecryptfs_opt_ecryptfs_cipher:
++ cipher_name_src = args[0].from;
++ cipher_name_dst =
++ mount_crypt_stat->
++ global_default_cipher_name;
++ strncpy(cipher_name_dst, cipher_name_src,
++ ECRYPTFS_MAX_CIPHER_NAME_SIZE);
++ ecryptfs_printk(KERN_DEBUG,
++ "The mount_crypt_stat "
++ "global_default_cipher_name set to: "
++ "[%s]\n", cipher_name_dst);
++ cipher_name_set = 1;
++ break;
++ case ecryptfs_opt_ecryptfs_key_bytes:
++ cipher_key_bytes_src = args[0].from;
++ cipher_key_bytes =
++ (int)simple_strtol(cipher_key_bytes_src,
++ &cipher_key_bytes_src, 0);
++ mount_crypt_stat->global_default_cipher_key_size =
++ cipher_key_bytes;
++ ecryptfs_printk(KERN_DEBUG,
++ "The mount_crypt_stat "
++ "global_default_cipher_key_size "
++ "set to: [%d]\n", mount_crypt_stat->
++ global_default_cipher_key_size);
++ cipher_key_bytes_set = 1;
++ break;
++ case ecryptfs_opt_passthrough:
++ mount_crypt_stat->flags |=
++ ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;
++ break;
++ case ecryptfs_opt_err:
++ default:
++ ecryptfs_printk(KERN_WARNING,
++ "eCryptfs: unrecognized option '%s'\n",
++ p);
++ }
++ }
++ /* Do not support lack of mount-wide signature in 0.1
++ * release */
++ if (!sig_set) {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_ERR, "You must supply a valid "
++ "passphrase auth tok signature as a mount "
++ "parameter; see the eCryptfs README\n");
++ goto out;
++ }
++ if (!cipher_name_set) {
++ cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
++ if (unlikely(cipher_name_len
++ >= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) {
++ rc = -EINVAL;
++ BUG();
++ goto out;
++ }
++ memcpy(mount_crypt_stat->global_default_cipher_name,
++ ECRYPTFS_DEFAULT_CIPHER, cipher_name_len);
++ mount_crypt_stat->global_default_cipher_name[cipher_name_len]
++ = '\0';
++ }
++ if (!cipher_key_bytes_set) {
++ mount_crypt_stat->global_default_cipher_key_size = 0;
++ }
++ rc = ecryptfs_process_cipher(
++ &mount_crypt_stat->global_key_tfm,
++ mount_crypt_stat->global_default_cipher_name,
++ &mount_crypt_stat->global_default_cipher_key_size);
++ if (rc) {
++ printk(KERN_ERR "Error attempting to initialize cipher [%s] "
++ "with key size [%Zd] bytes; rc = [%d]\n",
++ mount_crypt_stat->global_default_cipher_name,
++ mount_crypt_stat->global_default_cipher_key_size, rc);
++ mount_crypt_stat->global_key_tfm = NULL;
++ mount_crypt_stat->global_auth_tok_key = NULL;
++ rc = -EINVAL;
++ goto out;
++ }
++ mutex_init(&mount_crypt_stat->global_key_tfm_mutex);
++ ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: "
++ "[%s]\n", mount_crypt_stat->global_auth_tok_sig);
++ /* The reference to this key is held until umount is done The
++ * call to key_put is done in ecryptfs_put_super() */
++ auth_tok_key = request_key(&key_type_user,
++ mount_crypt_stat->global_auth_tok_sig,
++ NULL);
++ if (!auth_tok_key || IS_ERR(auth_tok_key)) {
++ ecryptfs_printk(KERN_ERR, "Could not find key with "
++ "description: [%s]\n",
++ mount_crypt_stat->global_auth_tok_sig);
++ process_request_key_err(PTR_ERR(auth_tok_key));
++ rc = -EINVAL;
++ goto out;
++ }
++ auth_tok = ecryptfs_get_key_payload_data(auth_tok_key);
++ if (ecryptfs_verify_version(auth_tok->version)) {
++ ecryptfs_printk(KERN_ERR, "Data structure version mismatch. "
++ "Userspace tools must match eCryptfs kernel "
++ "module with major version [%d] and minor "
++ "version [%d]\n", ECRYPTFS_VERSION_MAJOR,
++ ECRYPTFS_VERSION_MINOR);
++ rc = -EINVAL;
++ goto out;
++ }
++ if (auth_tok->token_type != ECRYPTFS_PASSWORD) {
++ ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure "
++ "returned from key\n");
++ rc = -EINVAL;
++ goto out;
++ }
++ mount_crypt_stat->global_auth_tok_key = auth_tok_key;
++ mount_crypt_stat->global_auth_tok = auth_tok;
++out:
++ return rc;
++}
++
++struct kmem_cache *ecryptfs_sb_info_cache;
++
++/**
++ * ecryptfs_fill_super
++ * @sb: The ecryptfs super block
++ * @raw_data: The options passed to mount
++ * @silent: Not used but required by function prototype
++ *
++ * Sets up what we can of the sb, rest is done in ecryptfs_read_super
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++static int
++ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
++{
++ int rc = 0;
++
++ /* Released in ecryptfs_put_super() */
++ ecryptfs_set_superblock_private(sb,
++ kmem_cache_alloc(ecryptfs_sb_info_cache,
++ SLAB_KERNEL));
++ if (!ecryptfs_superblock_to_private(sb)) {
++ ecryptfs_printk(KERN_WARNING, "Out of memory\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ memset(ecryptfs_superblock_to_private(sb), 0,
++ sizeof(struct ecryptfs_sb_info));
++ sb->s_op = &ecryptfs_sops;
++ /* Released through deactivate_super(sb) from get_sb_nodev */
++ sb->s_root = d_alloc(NULL, &(const struct qstr) {
++ .hash = 0,.name = "/",.len = 1});
++ if (!sb->s_root) {
++ ecryptfs_printk(KERN_ERR, "d_alloc failed\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ sb->s_root->d_op = &ecryptfs_dops;
++ sb->s_root->d_sb = sb;
++ sb->s_root->d_parent = sb->s_root;
++ /* Released in d_release when dput(sb->s_root) is called */
++ /* through deactivate_super(sb) from get_sb_nodev() */
++ ecryptfs_set_dentry_private(sb->s_root,
++ kmem_cache_alloc(ecryptfs_dentry_info_cache,
++ SLAB_KERNEL));
++ if (!ecryptfs_dentry_to_private(sb->s_root)) {
++ ecryptfs_printk(KERN_ERR,
++ "dentry_info_cache alloc failed\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++ memset(ecryptfs_dentry_to_private(sb->s_root), 0,
++ sizeof(struct ecryptfs_dentry_info));
++ rc = 0;
++out:
++ /* Should be able to rely on deactivate_super called from
++ * get_sb_nodev */
++ return rc;
++}
++
++/**
++ * ecryptfs_read_super
++ * @sb: The ecryptfs super block
++ * @dev_name: The path to mount over
++ *
++ * Read the super block of the lower filesystem, and use
++ * ecryptfs_interpose to create our initial inode and super block
++ * struct.
++ */
++static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
++{
++ int rc;
++ struct nameidata nd;
++ struct dentry *lower_root;
++ struct vfsmount *lower_mnt;
++
++ memset(&nd, 0, sizeof(struct nameidata));
++ rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
++ goto out_free;
++ }
++ lower_root = nd.dentry;
++ if (!lower_root->d_inode) {
++ ecryptfs_printk(KERN_WARNING,
++ "No directory to interpose on\n");
++ rc = -ENOENT;
++ goto out_free;
++ }
++ lower_mnt = nd.mnt;
++ ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
++ sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
++ ecryptfs_set_dentry_lower(sb->s_root, lower_root);
++ ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
++ if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
++ goto out_free;
++ rc = 0;
++ goto out;
++out_free:
++ path_release(&nd);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_get_sb
++ * @fs_type
++ * @flags
++ * @dev_name: The path to mount over
++ * @raw_data: The options passed into the kernel
++ *
++ * The whole ecryptfs_get_sb process is broken into 4 functions:
++ * ecryptfs_parse_options(): handle options passed to ecryptfs, if any
++ * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
++ * with as much information as it can before needing
++ * the lower filesystem.
++ * ecryptfs_read_super(): this accesses the lower filesystem and uses
++ * ecryptfs_interpolate to perform most of the linking
++ * ecryptfs_interpolate(): links the lower filesystem into ecryptfs
++ */
++static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *raw_data,
++ struct vfsmount *mnt)
++{
++ int rc;
++ struct super_block *sb;
++
++ rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);
++ if (rc < 0) {
++ printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);
++ goto out;
++ }
++ sb = mnt->mnt_sb;
++ rc = ecryptfs_parse_options(sb, raw_data);
++ if (rc) {
++ printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc);
++ goto out_abort;
++ }
++ rc = ecryptfs_read_super(sb, dev_name);
++ if (rc) {
++ printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc);
++ goto out_abort;
++ }
++ goto out;
++out_abort:
++ dput(sb->s_root);
++ up_write(&sb->s_umount);
++ deactivate_super(sb);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_kill_block_super
++ * @sb: The ecryptfs super block
++ *
++ * Used to bring the superblock down and free the private data.
++ * Private data is free'd in ecryptfs_put_super()
++ */
++static void ecryptfs_kill_block_super(struct super_block *sb)
++{
++ generic_shutdown_super(sb);
++}
++
++static struct file_system_type ecryptfs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "ecryptfs",
++ .get_sb = ecryptfs_get_sb,
++ .kill_sb = ecryptfs_kill_block_super,
++ .fs_flags = 0
++};
++
++/**
++ * inode_info_init_once
++ *
++ * Initializes the ecryptfs_inode_info_cache when it is created
++ */
++static void
++inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
++{
++ struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
++
++ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR)
++ inode_init_once(&ei->vfs_inode);
++}
++
++static struct ecryptfs_cache_info {
++ kmem_cache_t **cache;
++ const char *name;
++ size_t size;
++ void (*ctor)(void*, struct kmem_cache *, unsigned long);
++} ecryptfs_cache_infos[] = {
++ {
++ .cache = &ecryptfs_auth_tok_list_item_cache,
++ .name = "ecryptfs_auth_tok_list_item",
++ .size = sizeof(struct ecryptfs_auth_tok_list_item),
++ },
++ {
++ .cache = &ecryptfs_file_info_cache,
++ .name = "ecryptfs_file_cache",
++ .size = sizeof(struct ecryptfs_file_info),
++ },
++ {
++ .cache = &ecryptfs_dentry_info_cache,
++ .name = "ecryptfs_dentry_info_cache",
++ .size = sizeof(struct ecryptfs_dentry_info),
++ },
++ {
++ .cache = &ecryptfs_inode_info_cache,
++ .name = "ecryptfs_inode_cache",
++ .size = sizeof(struct ecryptfs_inode_info),
++ .ctor = inode_info_init_once,
++ },
++ {
++ .cache = &ecryptfs_sb_info_cache,
++ .name = "ecryptfs_sb_cache",
++ .size = sizeof(struct ecryptfs_sb_info),
++ },
++ {
++ .cache = &ecryptfs_header_cache_0,
++ .name = "ecryptfs_headers_0",
++ .size = PAGE_CACHE_SIZE,
++ },
++ {
++ .cache = &ecryptfs_header_cache_1,
++ .name = "ecryptfs_headers_1",
++ .size = PAGE_CACHE_SIZE,
++ },
++ {
++ .cache = &ecryptfs_header_cache_2,
++ .name = "ecryptfs_headers_2",
++ .size = PAGE_CACHE_SIZE,
++ },
++ {
++ .cache = &ecryptfs_lower_page_cache,
++ .name = "ecryptfs_lower_page_cache",
++ .size = PAGE_CACHE_SIZE,
++ },
++};
++
++static void ecryptfs_free_kmem_caches(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
++ struct ecryptfs_cache_info *info;
++
++ info = &ecryptfs_cache_infos[i];
++ if (*(info->cache))
++ kmem_cache_destroy(*(info->cache));
++ }
++}
++
++/**
++ * ecryptfs_init_kmem_caches
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++static int ecryptfs_init_kmem_caches(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
++ struct ecryptfs_cache_info *info;
++
++ info = &ecryptfs_cache_infos[i];
++ *(info->cache) = kmem_cache_create(info->name, info->size,
++ 0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
++ if (!*(info->cache)) {
++ ecryptfs_free_kmem_caches();
++ ecryptfs_printk(KERN_WARNING, "%s: "
++ "kmem_cache_create failed\n",
++ info->name);
++ return -ENOMEM;
++ }
++ }
++ return 0;
++}
++
++struct ecryptfs_obj {
++ char *name;
++ struct list_head slot_list;
++ struct kobject kobj;
++};
++
++struct ecryptfs_attribute {
++ struct attribute attr;
++ ssize_t(*show) (struct ecryptfs_obj *, char *);
++ ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
++};
++
++static ssize_t
++ecryptfs_attr_store(struct kobject *kobj,
++ struct attribute *attr, const char *buf, size_t len)
++{
++ struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
++ kobj);
++ struct ecryptfs_attribute *attribute =
++ container_of(attr, struct ecryptfs_attribute, attr);
++
++ return (attribute->store ? attribute->store(obj, buf, len) : 0);
++}
++
++static ssize_t
++ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
++{
++ struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
++ kobj);
++ struct ecryptfs_attribute *attribute =
++ container_of(attr, struct ecryptfs_attribute, attr);
++
++ return (attribute->show ? attribute->show(obj, buf) : 0);
++}
++
++static struct sysfs_ops ecryptfs_sysfs_ops = {
++ .show = ecryptfs_attr_show,
++ .store = ecryptfs_attr_store
++};
++
++static struct kobj_type ecryptfs_ktype = {
++ .sysfs_ops = &ecryptfs_sysfs_ops
++};
++
++static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
++
++static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
++{
++ return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
++}
++
++static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
++
++struct ecryptfs_version_str_map_elem {
++ u32 flag;
++ char *str;
++} ecryptfs_version_str_map[] = {
++ {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
++ {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
++ {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
++ {ECRYPTFS_VERSIONING_POLICY, "policy"}
++};
++
++static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
++{
++ int i;
++ int remaining = PAGE_SIZE;
++ int total_written = 0;
++
++ buff[0] = '\0';
++ for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
++ int entry_size;
++
++ if (!(ECRYPTFS_VERSIONING_MASK
++ & ecryptfs_version_str_map[i].flag))
++ continue;
++ entry_size = strlen(ecryptfs_version_str_map[i].str);
++ if ((entry_size + 2) > remaining)
++ goto out;
++ memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
++ buff[entry_size++] = '\n';
++ buff[entry_size] = '\0';
++ buff += entry_size;
++ total_written += entry_size;
++ remaining -= entry_size;
++ }
++out:
++ return total_written;
++}
++
++static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
++
++static int do_sysfs_registration(void)
++{
++ int rc;
++
++ if ((rc = subsystem_register(&ecryptfs_subsys))) {
++ printk(KERN_ERR
++ "Unable to register ecryptfs sysfs subsystem\n");
++ goto out;
++ }
++ rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
++ &sysfs_attr_version.attr);
++ if (rc) {
++ printk(KERN_ERR
++ "Unable to create ecryptfs version attribute\n");
++ subsystem_unregister(&ecryptfs_subsys);
++ goto out;
++ }
++ rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
++ &sysfs_attr_version_str.attr);
++ if (rc) {
++ printk(KERN_ERR
++ "Unable to create ecryptfs version_str attribute\n");
++ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
++ &sysfs_attr_version.attr);
++ subsystem_unregister(&ecryptfs_subsys);
++ goto out;
++ }
++out:
++ return rc;
++}
++
++static int __init ecryptfs_init(void)
++{
++ int rc;
++
++ if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) {
++ rc = -EINVAL;
++ ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "
++ "larger than the host's page size, and so "
++ "eCryptfs cannot run on this system. The "
++ "default eCryptfs extent size is [%d] bytes; "
++ "the page size is [%d] bytes.\n",
++ ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);
++ goto out;
++ }
++ rc = ecryptfs_init_kmem_caches();
++ if (rc) {
++ printk(KERN_ERR
++ "Failed to allocate one or more kmem_cache objects\n");
++ goto out;
++ }
++ rc = register_filesystem(&ecryptfs_fs_type);
++ if (rc) {
++ printk(KERN_ERR "Failed to register filesystem\n");
++ ecryptfs_free_kmem_caches();
++ goto out;
++ }
++ kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
++ sysfs_attr_version.attr.owner = THIS_MODULE;
++ sysfs_attr_version_str.attr.owner = THIS_MODULE;
++ rc = do_sysfs_registration();
++ if (rc) {
++ printk(KERN_ERR "sysfs registration failed\n");
++ unregister_filesystem(&ecryptfs_fs_type);
++ ecryptfs_free_kmem_caches();
++ goto out;
++ }
++out:
++ return rc;
++}
++
++static void __exit ecryptfs_exit(void)
++{
++ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
++ &sysfs_attr_version.attr);
++ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
++ &sysfs_attr_version_str.attr);
++ subsystem_unregister(&ecryptfs_subsys);
++ unregister_filesystem(&ecryptfs_fs_type);
++ ecryptfs_free_kmem_caches();
++}
++
++MODULE_AUTHOR("Michael A. Halcrow <mhalcrow at us.ibm.com>");
++MODULE_DESCRIPTION("eCryptfs");
++
++MODULE_LICENSE("GPL");
++
++module_init(ecryptfs_init)
++module_exit(ecryptfs_exit)
+diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
+new file mode 100644
+index 0000000..924dd90
+--- /dev/null
++++ b/fs/ecryptfs/mmap.c
+@@ -0,0 +1,788 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ * This is where eCryptfs coordinates the symmetric encryption and
++ * decryption of the file data as it passes between the lower
++ * encrypted file and the upper decrypted file.
++ *
++ * Copyright (C) 1997-2003 Erez Zadok
++ * Copyright (C) 2001-2003 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at 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/pagemap.h>
++#include <linux/writeback.h>
++#include <linux/page-flags.h>
++#include <linux/mount.h>
++#include <linux/file.h>
++#include <linux/crypto.h>
++#include <linux/scatterlist.h>
++#include "ecryptfs_kernel.h"
++
++struct kmem_cache *ecryptfs_lower_page_cache;
++
++/**
++ * ecryptfs_get1page
++ *
++ * Get one page from cache or lower f/s, return error otherwise.
++ *
++ * Returns unlocked and up-to-date page (if ok), with increased
++ * refcnt.
++ */
++static struct page *ecryptfs_get1page(struct file *file, int index)
++{
++ struct page *page;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct address_space *mapping;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ mapping = inode->i_mapping;
++ page = read_cache_page(mapping, index,
++ (filler_t *)mapping->a_ops->readpage,
++ (void *)file);
++ if (IS_ERR(page))
++ goto out;
++ wait_on_page_locked(page);
++out:
++ return page;
++}
++
++static
++int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
++
++/**
++ * ecryptfs_fill_zeros
++ * @file: The ecryptfs file
++ * @new_length: The new length of the data in the underlying file;
++ * everything between the prior end of the file and the
++ * new end of the file will be filled with zero's.
++ * new_length must be greater than current length
++ *
++ * Function for handling lseek-ing past the end of the file.
++ *
++ * This function does not support shrinking, only growing a file.
++ *
++ * Returns zero on success; non-zero otherwise.
++ */
++int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
++{
++ int rc = 0;
++ struct dentry *dentry = file->f_dentry;
++ struct inode *inode = dentry->d_inode;
++ pgoff_t old_end_page_index = 0;
++ pgoff_t index = old_end_page_index;
++ int old_end_pos_in_page = -1;
++ pgoff_t new_end_page_index;
++ int new_end_pos_in_page;
++ loff_t cur_length = i_size_read(inode);
++
++ if (cur_length != 0) {
++ index = old_end_page_index =
++ ((cur_length - 1) >> PAGE_CACHE_SHIFT);
++ old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
++ }
++ new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
++ new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
++ ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; "
++ "old_end_pos_in_page = [%d]; "
++ "new_end_page_index = [0x%.16x]; "
++ "new_end_pos_in_page = [%d]\n",
++ old_end_page_index, old_end_pos_in_page,
++ new_end_page_index, new_end_pos_in_page);
++ if (old_end_page_index == new_end_page_index) {
++ /* Start and end are in the same page; we just need to
++ * set a portion of the existing page to zero's */
++ rc = write_zeros(file, index, (old_end_pos_in_page + 1),
++ (new_end_pos_in_page - old_end_pos_in_page));
++ if (rc)
++ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
++ "index=[0x%.16x], "
++ "old_end_pos_in_page=[d], "
++ "(PAGE_CACHE_SIZE - new_end_pos_in_page"
++ "=[%d]"
++ ")=[d]) returned [%d]\n", file, index,
++ old_end_pos_in_page,
++ new_end_pos_in_page,
++ (PAGE_CACHE_SIZE - new_end_pos_in_page),
++ rc);
++ goto out;
++ }
++ /* Fill the remainder of the previous last page with zeros */
++ rc = write_zeros(file, index, (old_end_pos_in_page + 1),
++ ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
++ "index=[0x%.16x], old_end_pos_in_page=[d], "
++ "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
++ "returned [%d]\n", file, index,
++ old_end_pos_in_page,
++ (PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
++ goto out;
++ }
++ index++;
++ while (index < new_end_page_index) {
++ /* Fill all intermediate pages with zeros */
++ rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
++ "index=[0x%.16x], "
++ "old_end_pos_in_page=[d], "
++ "(PAGE_CACHE_SIZE - new_end_pos_in_page"
++ "=[%d]"
++ ")=[d]) returned [%d]\n", file, index,
++ old_end_pos_in_page,
++ new_end_pos_in_page,
++ (PAGE_CACHE_SIZE - new_end_pos_in_page),
++ rc);
++ goto out;
++ }
++ index++;
++ }
++ /* Fill the portion at the beginning of the last new page with
++ * zero's */
++ rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1));
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "write_zeros(file="
++ "[%p], index=[0x%.16x], 0, "
++ "new_end_pos_in_page=[%d]"
++ "returned [%d]\n", file, index,
++ new_end_pos_in_page, rc);
++ goto out;
++ }
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_writepage
++ * @page: Page that is locked before this call is made
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
++{
++ struct ecryptfs_page_crypt_context ctx;
++ int rc;
++
++ ctx.page = page;
++ ctx.mode = ECRYPTFS_WRITEPAGE_MODE;
++ ctx.param.wbc = wbc;
++ rc = ecryptfs_encrypt_page(&ctx);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error encrypting "
++ "page (upper index [0x%.16x])\n", page->index);
++ ClearPageUptodate(page);
++ goto out;
++ }
++ SetPageUptodate(page);
++ unlock_page(page);
++out:
++ return rc;
++}
++
++/**
++ * Reads the data from the lower file file at index lower_page_index
++ * and copies that data into page.
++ *
++ * @param page Page to fill
++ * @param lower_page_index Index of the page in the lower file to get
++ */
++int ecryptfs_do_readpage(struct file *file, struct page *page,
++ pgoff_t lower_page_index)
++{
++ int rc;
++ struct dentry *dentry;
++ struct file *lower_file;
++ struct dentry *lower_dentry;
++ struct inode *inode;
++ struct inode *lower_inode;
++ char *page_data;
++ struct page *lower_page = NULL;
++ char *lower_page_data;
++ const struct address_space_operations *lower_a_ops;
++
++ dentry = file->f_dentry;
++ lower_file = ecryptfs_file_to_lower(file);
++ lower_dentry = ecryptfs_dentry_to_lower(dentry);
++ inode = dentry->d_inode;
++ lower_inode = ecryptfs_inode_to_lower(inode);
++ lower_a_ops = lower_inode->i_mapping->a_ops;
++ lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
++ (filler_t *)lower_a_ops->readpage,
++ (void *)lower_file);
++ if (IS_ERR(lower_page)) {
++ rc = PTR_ERR(lower_page);
++ lower_page = NULL;
++ ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
++ goto out;
++ }
++ wait_on_page_locked(lower_page);
++ page_data = (char *)kmap(page);
++ if (!page_data) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_ERR, "Error mapping page\n");
++ goto out;
++ }
++ lower_page_data = (char *)kmap(lower_page);
++ if (!lower_page_data) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_ERR, "Error mapping page\n");
++ kunmap(page);
++ goto out;
++ }
++ memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
++ kunmap(lower_page);
++ kunmap(page);
++ rc = 0;
++out:
++ if (likely(lower_page))
++ page_cache_release(lower_page);
++ if (rc == 0)
++ SetPageUptodate(page);
++ else
++ ClearPageUptodate(page);
++ return rc;
++}
++
++/**
++ * ecryptfs_readpage
++ * @file: This is an ecryptfs file
++ * @page: ecryptfs associated page to stick the read data into
++ *
++ * Read in a page, decrypting if necessary.
++ *
++ * Returns zero on success; non-zero on error.
++ */
++static int ecryptfs_readpage(struct file *file, struct page *page)
++{
++ int rc = 0;
++ struct ecryptfs_crypt_stat *crypt_stat;
++
++ BUG_ON(!(file && file->f_dentry && file->f_dentry->d_inode));
++ crypt_stat =
++ &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
++ if (!crypt_stat
++ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)
++ || ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
++ ecryptfs_printk(KERN_DEBUG,
++ "Passing through unencrypted page\n");
++ rc = ecryptfs_do_readpage(file, page, page->index);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
++ "[%d]\n", rc);
++ goto out;
++ }
++ } else {
++ rc = ecryptfs_decrypt_page(file, page);
++ if (rc) {
++
++ ecryptfs_printk(KERN_ERR, "Error decrypting page; "
++ "rc = [%d]\n", rc);
++ goto out;
++ }
++ }
++ SetPageUptodate(page);
++out:
++ if (rc)
++ ClearPageUptodate(page);
++ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
++ page->index);
++ unlock_page(page);
++ return rc;
++}
++
++static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
++{
++ struct inode *inode = page->mapping->host;
++ int end_byte_in_page;
++ int rc = 0;
++ char *page_virt;
++
++ if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) {
++ end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
++ if (to > end_byte_in_page)
++ end_byte_in_page = to;
++ page_virt = kmap(page);
++ if (!page_virt) {
++ rc = -ENOMEM;
++ ecryptfs_printk(KERN_WARNING,
++ "Could not map page\n");
++ goto out;
++ }
++ memset((page_virt + end_byte_in_page), 0,
++ (PAGE_CACHE_SIZE - end_byte_in_page));
++ kunmap(page);
++ }
++out:
++ return rc;
++}
++
++static int ecryptfs_prepare_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ int rc = 0;
++
++ kmap(page);
++ if (from == 0 && to == PAGE_CACHE_SIZE)
++ goto out; /* If we are writing a full page, it will be
++ up to date. */
++ if (!PageUptodate(page))
++ rc = ecryptfs_do_readpage(file, page, page->index);
++out:
++ return rc;
++}
++
++int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
++ char **lower_virt,
++ struct inode *lower_inode,
++ unsigned long lower_page_index)
++{
++ int rc = 0;
++
++ (*lower_page) = grab_cache_page(lower_inode->i_mapping,
++ lower_page_index);
++ if (!(*lower_page)) {
++ ecryptfs_printk(KERN_ERR, "grab_cache_page for "
++ "lower_page_index = [0x%.16x] failed\n",
++ lower_page_index);
++ rc = -EINVAL;
++ goto out;
++ }
++ if (lower_virt)
++ (*lower_virt) = kmap((*lower_page));
++ else
++ kmap((*lower_page));
++out:
++ return rc;
++}
++
++int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
++ struct inode *lower_inode,
++ struct writeback_control *wbc)
++{
++ int rc = 0;
++
++ rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); "
++ "rc = [%d]\n", rc);
++ goto out;
++ }
++ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
++ page_cache_release(lower_page);
++out:
++ return rc;
++}
++
++static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page)
++{
++ kunmap(lower_page);
++ ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = "
++ "[0x%.16x]\n", lower_page->index);
++ unlock_page(lower_page);
++ page_cache_release(lower_page);
++}
++
++/**
++ * ecryptfs_write_inode_size_to_header
++ *
++ * Writes the lower file size to the first 8 bytes of the header.
++ *
++ * Returns zero on success; non-zero on error.
++ */
++int
++ecryptfs_write_inode_size_to_header(struct file *lower_file,
++ struct inode *lower_inode,
++ struct inode *inode)
++{
++ int rc = 0;
++ struct page *header_page;
++ char *header_virt;
++ const struct address_space_operations *lower_a_ops;
++ u64 file_size;
++
++ rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt,
++ lower_inode, 0);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "grab_cache_page for header page "
++ "failed\n");
++ goto out;
++ }
++ lower_a_ops = lower_inode->i_mapping->a_ops;
++ rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
++ file_size = (u64)i_size_read(inode);
++ ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
++ file_size = cpu_to_be64(file_size);
++ memcpy(header_virt, &file_size, sizeof(u64));
++ rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
++ if (rc < 0)
++ ecryptfs_printk(KERN_ERR, "Error commiting header page "
++ "write\n");
++ ecryptfs_unmap_and_release_lower_page(header_page);
++ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
++ mark_inode_dirty_sync(inode);
++out:
++ return rc;
++}
++
++int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
++ struct file *lower_file,
++ unsigned long lower_page_index, int byte_offset,
++ int region_bytes)
++{
++ int rc = 0;
++
++ rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, lower_inode,
++ lower_page_index);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to grab and map "
++ "lower page with index [0x%.16x]\n",
++ lower_page_index);
++ goto out;
++ }
++ rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
++ (*lower_page),
++ byte_offset,
++ region_bytes);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "prepare_write for "
++ "lower_page_index = [0x%.16x] failed; rc = "
++ "[%d]\n", lower_page_index, rc);
++ }
++out:
++ if (rc && (*lower_page)) {
++ ecryptfs_unmap_and_release_lower_page(*lower_page);
++ (*lower_page) = NULL;
++ }
++ return rc;
++}
++
++/**
++ * ecryptfs_commit_lower_page
++ *
++ * Returns zero on success; non-zero on error
++ */
++int
++ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
++ struct file *lower_file, int byte_offset,
++ int region_size)
++{
++ int rc = 0;
++
++ rc = lower_inode->i_mapping->a_ops->commit_write(
++ lower_file, lower_page, byte_offset, region_size);
++ if (rc < 0) {
++ ecryptfs_printk(KERN_ERR,
++ "Error committing write; rc = [%d]\n", rc);
++ } else
++ rc = 0;
++ ecryptfs_unmap_and_release_lower_page(lower_page);
++ return rc;
++}
++
++/**
++ * ecryptfs_copy_page_to_lower
++ *
++ * Used for plaintext pass-through; no page index interpolation
++ * required.
++ */
++int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
++ struct file *lower_file)
++{
++ int rc = 0;
++ struct page *lower_page;
++
++ rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
++ page->index, 0, PAGE_CACHE_SIZE);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to get page "
++ "at index [0x%.16x]\n", page->index);
++ goto out;
++ }
++ /* TODO: aops */
++ memcpy((char *)page_address(lower_page), page_address(page),
++ PAGE_CACHE_SIZE);
++ rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
++ 0, PAGE_CACHE_SIZE);
++ if (rc)
++ ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
++ "at index [0x%.16x]\n", page->index);
++out:
++ return rc;
++}
++
++static int
++process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
++ struct file *file, struct inode *inode)
++{
++ struct page *header_page;
++ const struct address_space_operations *lower_a_ops;
++ struct inode *lower_inode;
++ struct file *lower_file;
++ char *header_virt;
++ int rc = 0;
++ int current_header_page = 0;
++ int header_pages;
++ int more_header_data_to_be_written = 1;
++
++ lower_inode = ecryptfs_inode_to_lower(inode);
++ lower_file = ecryptfs_file_to_lower(file);
++ lower_a_ops = lower_inode->i_mapping->a_ops;
++ header_pages = ((crypt_stat->header_extent_size
++ * crypt_stat->num_header_extents_at_front)
++ / PAGE_CACHE_SIZE);
++ BUG_ON(header_pages < 1);
++ while (current_header_page < header_pages) {
++ rc = ecryptfs_grab_and_map_lower_page(&header_page,
++ &header_virt,
++ lower_inode,
++ current_header_page);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "grab_cache_page for "
++ "header page [%d] failed; rc = [%d]\n",
++ current_header_page, rc);
++ goto out;
++ }
++ rc = lower_a_ops->prepare_write(lower_file, header_page, 0,
++ PAGE_CACHE_SIZE);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error preparing to write "
++ "header page out; rc = [%d]\n", rc);
++ goto out;
++ }
++ memset(header_virt, 0, PAGE_CACHE_SIZE);
++ if (more_header_data_to_be_written) {
++ rc = ecryptfs_write_headers_virt(header_virt,
++ crypt_stat,
++ file->f_dentry);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error "
++ "generating header; rc = "
++ "[%d]\n", rc);
++ rc = -EIO;
++ memset(header_virt, 0, PAGE_CACHE_SIZE);
++ ecryptfs_unmap_and_release_lower_page(
++ header_page);
++ goto out;
++ }
++ if (current_header_page == 0)
++ memset(header_virt, 0, 8);
++ more_header_data_to_be_written = 0;
++ }
++ rc = lower_a_ops->commit_write(lower_file, header_page, 0,
++ PAGE_CACHE_SIZE);
++ ecryptfs_unmap_and_release_lower_page(header_page);
++ if (rc < 0) {
++ ecryptfs_printk(KERN_ERR,
++ "Error commiting header page write; "
++ "rc = [%d]\n", rc);
++ break;
++ }
++ current_header_page++;
++ }
++ if (rc >= 0) {
++ rc = 0;
++ ecryptfs_printk(KERN_DEBUG, "lower_inode->i_blocks = "
++ "[0x%.16x]\n", lower_inode->i_blocks);
++ i_size_write(inode, 0);
++ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
++ mark_inode_dirty_sync(inode);
++ }
++ ecryptfs_printk(KERN_DEBUG, "Clearing ECRYPTFS_NEW_FILE flag in "
++ "crypt_stat at memory location [%p]\n", crypt_stat);
++ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
++out:
++ return rc;
++}
++
++/**
++ * ecryptfs_commit_write
++ * @file: The eCryptfs file object
++ * @page: The eCryptfs page
++ * @from: Ignored (we rotate the page IV on each write)
++ * @to: Ignored
++ *
++ * This is where we encrypt the data and pass the encrypted data to
++ * the lower filesystem. In OpenPGP-compatible mode, we operate on
++ * entire underlying packets.
++ */
++static int ecryptfs_commit_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ struct ecryptfs_page_crypt_context ctx;
++ loff_t pos;
++ struct inode *inode;
++ struct inode *lower_inode;
++ struct file *lower_file;
++ struct ecryptfs_crypt_stat *crypt_stat;
++ int rc;
++
++ inode = page->mapping->host;
++ lower_inode = ecryptfs_inode_to_lower(inode);
++ lower_file = ecryptfs_file_to_lower(file);
++ mutex_lock(&lower_inode->i_mutex);
++ crypt_stat =
++ &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
++ if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
++ ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
++ "crypt_stat at memory location [%p]\n", crypt_stat);
++ rc = process_new_file(crypt_stat, file, inode);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error processing new "
++ "file; rc = [%d]\n", rc);
++ goto out;
++ }
++ } else
++ ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
++ ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
++ "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
++ to);
++ rc = fill_zeros_to_end_of_page(page, to);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
++ "zeros in page with index = [0x%.16x]\n",
++ page->index);
++ goto out;
++ }
++ ctx.page = page;
++ ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
++ ctx.param.lower_file = lower_file;
++ rc = ecryptfs_encrypt_page(&ctx);
++ if (rc) {
++ ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
++ "index [0x%.16x])\n", page->index);
++ goto out;
++ }
++ rc = 0;
++ inode->i_blocks = lower_inode->i_blocks;
++ pos = (page->index << PAGE_CACHE_SHIFT) + to;
++ if (pos > i_size_read(inode)) {
++ i_size_write(inode, pos);
++ ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
++ "[0x%.16x]\n", i_size_read(inode));
++ }
++ ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
++ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
++ mark_inode_dirty_sync(inode);
++out:
++ kunmap(page); /* mapped in prior call (prepare_write) */
++ if (rc < 0)
++ ClearPageUptodate(page);
++ else
++ SetPageUptodate(page);
++ mutex_unlock(&lower_inode->i_mutex);
++ return rc;
++}
++
++/**
++ * write_zeros
++ * @file: The ecryptfs file
++ * @index: The index in which we are writing
++ * @start: The position after the last block of data
++ * @num_zeros: The number of zeros to write
++ *
++ * Write a specified number of zero's to a page.
++ *
++ * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
++ */
++static
++int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
++{
++ int rc = 0;
++ struct page *tmp_page;
++
++ tmp_page = ecryptfs_get1page(file, index);
++ if (IS_ERR(tmp_page)) {
++ ecryptfs_printk(KERN_ERR, "Error getting page at index "
++ "[0x%.16x]\n", index);
++ rc = PTR_ERR(tmp_page);
++ goto out;
++ }
++ kmap(tmp_page);
++ rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
++ if (rc) {
++ ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
++ "to remainder of page at index [0x%.16x]\n",
++ index);
++ kunmap(tmp_page);
++ page_cache_release(tmp_page);
++ goto out;
++ }
++ memset(((char *)page_address(tmp_page) + start), 0, num_zeros);
++ rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
++ if (rc < 0) {
++ ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
++ "to remainder of page at index [0x%.16x]\n",
++ index);
++ kunmap(tmp_page);
++ page_cache_release(tmp_page);
++ goto out;
++ }
++ rc = 0;
++ kunmap(tmp_page);
++ page_cache_release(tmp_page);
++out:
++ return rc;
++}
++
++static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
++{
++ int rc = 0;
++ struct inode *inode;
++ struct inode *lower_inode;
++
++ inode = (struct inode *)mapping->host;
++ lower_inode = ecryptfs_inode_to_lower(inode);
++ if (lower_inode->i_mapping->a_ops->bmap)
++ rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
++ block);
++ return rc;
++}
++
++static void ecryptfs_sync_page(struct page *page)
++{
++ struct inode *inode;
++ struct inode *lower_inode;
++ struct page *lower_page;
++
++ inode = page->mapping->host;
++ lower_inode = ecryptfs_inode_to_lower(inode);
++ /* NOTE: Recently swapped with grab_cache_page(), since
++ * sync_page() just makes sure that pending I/O gets done. */
++ lower_page = find_lock_page(lower_inode->i_mapping, page->index);
++ if (!lower_page) {
++ ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
++ return;
++ }
++ lower_page->mapping->a_ops->sync_page(lower_page);
++ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
++ lower_page->index);
++ unlock_page(lower_page);
++ page_cache_release(lower_page);
++}
++
++struct address_space_operations ecryptfs_aops = {
++ .writepage = ecryptfs_writepage,
++ .readpage = ecryptfs_readpage,
++ .prepare_write = ecryptfs_prepare_write,
++ .commit_write = ecryptfs_commit_write,
++ .bmap = ecryptfs_bmap,
++ .sync_page = ecryptfs_sync_page,
++};
+diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
+new file mode 100644
+index 0000000..825757a
+--- /dev/null
++++ b/fs/ecryptfs/super.c
+@@ -0,0 +1,180 @@
++/**
++ * eCryptfs: Linux filesystem encryption layer
++ *
++ * Copyright (C) 1997-2003 Erez Zadok
++ * Copyright (C) 2001-2003 Stony Brook University
++ * Copyright (C) 2004-2006 International Business Machines Corp.
++ * Author(s): Michael A. Halcrow <mahalcro at us.ibm.com>
++ * Michael C. Thompson <mcthomps at 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/fs.h>
++#include <linux/mount.h>
++#include <linux/key.h>
++#include <linux/seq_file.h>
++#include <linux/crypto.h>
++#include "ecryptfs_kernel.h"
++
++struct kmem_cache *ecryptfs_inode_info_cache;
++
++/**
++ * ecryptfs_alloc_inode - allocate an ecryptfs inode
++ * @sb: Pointer to the ecryptfs super block
++ *
++ * Called to bring an inode into existence.
++ *
++ * Only handle allocation, setting up structures should be done in
++ * ecryptfs_read_inode. This is because the kernel, between now and
++ * then, will 0 out the private data pointer.
++ *
++ * Returns a pointer to a newly allocated inode, NULL otherwise
++ */
++static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
++{
++ struct ecryptfs_inode_info *ecryptfs_inode;
++ struct inode *inode = NULL;
++
++ ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
++ SLAB_KERNEL);
++ if (unlikely(!ecryptfs_inode))
++ goto out;
++ ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat);
++ inode = &ecryptfs_inode->vfs_inode;
++out:
++ return inode;
++}
++
++/**
++ * ecryptfs_destroy_inode
++ * @inode: The ecryptfs inode
++ *
++ * This is used during the final destruction of the inode.
++ * All allocation of memory related to the inode, including allocated
++ * memory in the crypt_stat struct, will be released here.
++ * There should be no chance that this deallocation will be missed.
++ */
++static void ecryptfs_destroy_inode(struct inode *inode)
++{
++ struct ecryptfs_inode_info *inode_info;
++
++ inode_info = ecryptfs_inode_to_private(inode);
++ ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat);
++ kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
++}
++
++/**
++ * ecryptfs_init_inode
++ * @inode: The ecryptfs inode
++ *
++ * Set up the ecryptfs inode.
++ */
++void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
++{
++ ecryptfs_set_inode_lower(inode, lower_inode);
++ inode->i_ino = lower_inode->i_ino;
++ inode->i_version++;
++ inode->i_op = &ecryptfs_main_iops;
++ inode->i_fop = &ecryptfs_main_fops;
++ inode->i_mapping->a_ops = &ecryptfs_aops;
++}
++
++/**
++ * ecryptfs_put_super
++ * @sb: Pointer to the ecryptfs super block
++ *
++ * Final actions when unmounting a file system.
++ * This will handle deallocation and release of our private data.
++ */
++static void ecryptfs_put_super(struct super_block *sb)
++{
++ struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
++
++ ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat);
++ kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
++ ecryptfs_set_superblock_private(sb, NULL);
++}
++
++/**
++ * ecryptfs_statfs
++ * @sb: The ecryptfs super block
++ * @buf: The struct kstatfs to fill in with stats
++ *
++ * Get the filesystem statistics. Currently, we let this pass right through
++ * to the lower filesystem and take no action ourselves.
++ */
++static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
++}
++
++/**
++ * ecryptfs_clear_inode
++ * @inode - The ecryptfs inode
++ *
++ * Called by iput() when the inode reference count reached zero
++ * and the inode is not hashed anywhere. Used to clear anything
++ * that needs to be, before the inode is completely destroyed and put
++ * on the inode free list. We use this to drop out reference to the
++ * lower inode.
++ */
++static void ecryptfs_clear_inode(struct inode *inode)
++{
++ iput(ecryptfs_inode_to_lower(inode));
++}
++
++/**
++ * ecryptfs_show_options
++ *
++ * Prints the directory we are currently mounted over.
++ * Returns zero on success; non-zero otherwise
++ */
++static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
++{
++ struct super_block *sb = mnt->mnt_sb;
++ struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
++ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
++ char *tmp_page;
++ char *path;
++ int rc = 0;
++
++ tmp_page = (char *)__get_free_page(GFP_KERNEL);
++ if (!tmp_page) {
++ rc = -ENOMEM;
++ goto out;
++ }
++ path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
++ if (IS_ERR(path)) {
++ rc = PTR_ERR(path);
++ goto out;
++ }
++ seq_printf(m, ",dir=%s", path);
++ free_page((unsigned long)tmp_page);
++out:
++ return rc;
++}
++
++struct super_operations ecryptfs_sops = {
++ .alloc_inode = ecryptfs_alloc_inode,
++ .destroy_inode = ecryptfs_destroy_inode,
++ .drop_inode = generic_delete_inode,
++ .put_super = ecryptfs_put_super,
++ .statfs = ecryptfs_statfs,
++ .remount_fs = NULL,
++ .clear_inode = ecryptfs_clear_inode,
++ .show_options = ecryptfs_show_options
++};
+diff --git a/fs/efs/super.c b/fs/efs/super.c
+index 8ac2462..b3f5065 100644
+--- a/fs/efs/super.c
++++ b/fs/efs/super.c
+@@ -90,8 +90,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(efs_inode_cachep))
+- printk(KERN_INFO "efs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(efs_inode_cachep);
+ }
+
+ static void efs_put_super(struct super_block *s)
+@@ -248,11 +247,10 @@ static int efs_fill_super(struct super_b
+ struct buffer_head *bh;
+ struct inode *root;
+
+- sb = kmalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
++ sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
+ if (!sb)
+ return -ENOMEM;
+ s->s_fs_info = sb;
+- memset(sb, 0, sizeof(struct efs_sb_info));
+
+ s->s_magic = EFS_SUPER_MAGIC;
+ if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 3a35674..ae228ec 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -105,6 +105,8 @@
+ /* Maximum msec timeout value storeable in a long int */
+ #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
+
++#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
++
+
+ struct epoll_filefd {
+ struct file *file;
+@@ -497,7 +499,7 @@ void eventpoll_release_file(struct file
+ */
+ asmlinkage long sys_epoll_create(int size)
+ {
+- int error, fd;
++ int error, fd = -1;
+ struct eventpoll *ep;
+ struct inode *inode;
+ struct file *file;
+@@ -640,7 +642,6 @@ eexit_1:
+ return error;
+ }
+
+-#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
+
+ /*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+@@ -657,7 +658,7 @@ asmlinkage long sys_epoll_wait(int epfd,
+ current, epfd, events, maxevents, timeout));
+
+ /* The maximum number of event must be greater than zero */
+- if (maxevents <= 0 || maxevents > MAX_EVENTS)
++ if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
+ return -EINVAL;
+
+ /* Verify that the area passed by the user is writeable */
+@@ -699,6 +700,55 @@ eexit_1:
+ }
+
+
++#ifdef TIF_RESTORE_SIGMASK
++
++/*
++ * Implement the event wait interface for the eventpoll file. It is the kernel
++ * part of the user space epoll_pwait(2).
++ */
++asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
++ int maxevents, int timeout, const sigset_t __user *sigmask,
++ size_t sigsetsize)
++{
++ int error;
++ sigset_t ksigmask, sigsaved;
++
++ /*
++ * If the caller wants a certain signal mask to be set during the wait,
++ * we apply it here.
++ */
++ if (sigmask) {
++ if (sigsetsize != sizeof(sigset_t))
++ return -EINVAL;
++ if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
++ return -EFAULT;
++ sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
++ sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
++ }
++
++ error = sys_epoll_wait(epfd, events, maxevents, timeout);
++
++ /*
++ * If we changed the signal mask, we need to restore the original one.
++ * In case we've got a signal while waiting, we do not restore the
++ * signal mask yet, and we allow do_signal() to deliver the signal on
++ * the way back to userspace, before the signal mask is restored.
++ */
++ if (sigmask) {
++ if (error == -EINTR) {
++ memcpy(¤t->saved_sigmask, &sigsaved,
++ sizeof(sigsaved));
++ set_thread_flag(TIF_RESTORE_SIGMASK);
++ } else
++ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
++ }
++
++ return error;
++}
++
++#endif /* #ifdef TIF_RESTORE_SIGMASK */
++
++
+ /*
+ * Creates the file descriptor to be used by the epoll interface.
+ */
+@@ -720,9 +770,10 @@ static int ep_getfd(int *efd, struct ino
+
+ /* Allocates an inode from the eventpoll file system */
+ inode = ep_eventpoll_inode();
+- error = PTR_ERR(inode);
+- if (IS_ERR(inode))
++ if (IS_ERR(inode)) {
++ error = PTR_ERR(inode);
+ goto eexit_2;
++ }
+
+ /* Allocates a free descriptor to plug the file onto */
+ error = get_unused_fd();
+@@ -1590,7 +1641,6 @@ static struct inode *ep_eventpoll_inode(
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+- inode->i_blksize = PAGE_SIZE;
+ return inode;
+
+ eexit_1:
+diff --git a/fs/exec.c b/fs/exec.c
+index 54135df..d993ea1 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -46,7 +46,7 @@
+ #include <linux/security.h>
+ #include <linux/syscalls.h>
+ #include <linux/rmap.h>
+-#include <linux/acct.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/cn_proc.h>
+ #include <linux/audit.h>
+
+@@ -58,7 +58,7 @@
+ #endif
+
+ int core_uses_pid;
+-char core_pattern[65] = "core";
++char core_pattern[128] = "core";
+ int suid_dumpable = 0;
+
+ EXPORT_SYMBOL(suid_dumpable);
+@@ -595,7 +595,7 @@ static int de_thread(struct task_struct
+ if (!newsighand)
+ return -ENOMEM;
+
+- if (thread_group_empty(current))
++ if (thread_group_empty(tsk))
+ goto no_thread_group;
+
+ /*
+@@ -620,17 +620,17 @@ static int de_thread(struct task_struct
+ * Reparenting needs write_lock on tasklist_lock,
+ * so it is safe to do it under read_lock.
+ */
+- if (unlikely(current->group_leader == child_reaper))
+- child_reaper = current;
++ if (unlikely(tsk->group_leader == child_reaper))
++ child_reaper = tsk;
+
+- zap_other_threads(current);
++ zap_other_threads(tsk);
+ read_unlock(&tasklist_lock);
+
+ /*
+ * Account for the thread group leader hanging around:
+ */
+ count = 1;
+- if (!thread_group_leader(current)) {
++ if (!thread_group_leader(tsk)) {
+ count = 2;
+ /*
+ * The SIGALRM timer survives the exec, but needs to point
+@@ -639,14 +639,14 @@ static int de_thread(struct task_struct
+ * synchronize with any firing (by calling del_timer_sync)
+ * before we can safely let the old group leader die.
+ */
+- sig->tsk = current;
++ sig->tsk = tsk;
+ spin_unlock_irq(lock);
+ if (hrtimer_cancel(&sig->real_timer))
+ hrtimer_restart(&sig->real_timer);
+ spin_lock_irq(lock);
+ }
+ while (atomic_read(&sig->count) > count) {
+- sig->group_exit_task = current;
++ sig->group_exit_task = tsk;
+ sig->notify_count = count;
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(lock);
+@@ -662,13 +662,13 @@ static int de_thread(struct task_struct
+ * do is to wait for the thread group leader to become inactive,
+ * and to assume its PID:
+ */
+- if (!thread_group_leader(current)) {
++ if (!thread_group_leader(tsk)) {
+ /*
+ * Wait for the thread group leader to be a zombie.
+ * It should already be zombie at this point, most
+ * of the time.
+ */
+- leader = current->group_leader;
++ leader = tsk->group_leader;
+ while (leader->exit_state != EXIT_ZOMBIE)
+ yield();
+
+@@ -682,12 +682,12 @@ static int de_thread(struct task_struct
+ * When we take on its identity by switching to its PID, we
+ * also take its birthdate (always earlier than our own).
+ */
+- current->start_time = leader->start_time;
++ tsk->start_time = leader->start_time;
+
+ write_lock_irq(&tasklist_lock);
+
+- BUG_ON(leader->tgid != current->tgid);
+- BUG_ON(current->pid == current->tgid);
++ BUG_ON(leader->tgid != tsk->tgid);
++ BUG_ON(tsk->pid == tsk->tgid);
+ /*
+ * An exec() starts a new thread group with the
+ * TGID of the previous thread group. Rehash the
+@@ -696,24 +696,21 @@ static int de_thread(struct task_struct
+ */
+
+ /* Become a process group leader with the old leader's pid.
+- * Note: The old leader also uses thispid until release_task
++ * The old leader becomes a thread of the this thread group.
++ * Note: The old leader also uses this pid until release_task
+ * is called. Odd but simple and correct.
+ */
+- detach_pid(current, PIDTYPE_PID);
+- current->pid = leader->pid;
+- attach_pid(current, PIDTYPE_PID, current->pid);
+- attach_pid(current, PIDTYPE_PGID, current->signal->pgrp);
+- attach_pid(current, PIDTYPE_SID, current->signal->session);
+- list_replace_rcu(&leader->tasks, ¤t->tasks);
++ detach_pid(tsk, PIDTYPE_PID);
++ tsk->pid = leader->pid;
++ attach_pid(tsk, PIDTYPE_PID, tsk->pid);
++ transfer_pid(leader, tsk, PIDTYPE_PGID);
++ transfer_pid(leader, tsk, PIDTYPE_SID);
++ list_replace_rcu(&leader->tasks, &tsk->tasks);
+
+- current->group_leader = current;
+- leader->group_leader = current;
++ tsk->group_leader = tsk;
++ leader->group_leader = tsk;
+
+- /* Reduce leader to a thread */
+- detach_pid(leader, PIDTYPE_PGID);
+- detach_pid(leader, PIDTYPE_SID);
+-
+- current->exit_signal = SIGCHLD;
++ tsk->exit_signal = SIGCHLD;
+
+ BUG_ON(leader->exit_state != EXIT_ZOMBIE);
+ leader->exit_state = EXIT_DEAD;
+@@ -753,7 +750,7 @@ no_thread_group:
+ spin_lock(&oldsighand->siglock);
+ spin_lock_nested(&newsighand->siglock, SINGLE_DEPTH_NESTING);
+
+- rcu_assign_pointer(current->sighand, newsighand);
++ rcu_assign_pointer(tsk->sighand, newsighand);
+ recalc_sigpending();
+
+ spin_unlock(&newsighand->siglock);
+@@ -764,7 +761,7 @@ no_thread_group:
+ kmem_cache_free(sighand_cachep, oldsighand);
+ }
+
+- BUG_ON(!thread_group_leader(current));
++ BUG_ON(!thread_group_leader(tsk));
+ return 0;
+ }
+
+@@ -901,8 +898,7 @@ int flush_old_exec(struct linux_binprm *
+ return 0;
+
+ mmap_failed:
+- put_files_struct(current->files);
+- current->files = files;
++ reset_files_struct(current, files);
+ out:
+ return retval;
+ }
+@@ -1322,7 +1318,7 @@ static void format_corename(char *corena
+ case 'h':
+ down_read(&uts_sem);
+ rc = snprintf(out_ptr, out_end - out_ptr,
+- "%s", system_utsname.nodename);
++ "%s", utsname()->nodename);
+ up_read(&uts_sem);
+ if (rc > out_end - out_ptr)
+ goto out;
+@@ -1467,6 +1463,7 @@ int do_coredump(long signr, int exit_cod
+ int retval = 0;
+ int fsuid = current->fsuid;
+ int flag = 0;
++ int ispipe = 0;
+
+ binfmt = current->binfmt;
+ if (!binfmt || !binfmt->core_dump)
+@@ -1508,22 +1505,34 @@ int do_coredump(long signr, int exit_cod
+ lock_kernel();
+ format_corename(corename, core_pattern, signr);
+ unlock_kernel();
+- file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600);
++ if (corename[0] == '|') {
++ /* SIGPIPE can happen, but it's just never processed */
++ if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
++ printk(KERN_INFO "Core dump to %s pipe failed\n",
++ corename);
++ goto fail_unlock;
++ }
++ ispipe = 1;
++ } else
++ file = filp_open(corename,
++ O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600);
+ if (IS_ERR(file))
+ goto fail_unlock;
+ inode = file->f_dentry->d_inode;
+ if (inode->i_nlink > 1)
+ goto close_fail; /* multiple links - don't dump */
+- if (d_unhashed(file->f_dentry))
++ if (!ispipe && d_unhashed(file->f_dentry))
+ goto close_fail;
+
+- if (!S_ISREG(inode->i_mode))
++ /* AK: actually i see no reason to not allow this for named pipes etc.,
++ but keep the previous behaviour for now. */
++ if (!ispipe && !S_ISREG(inode->i_mode))
+ goto close_fail;
+ if (!file->f_op)
+ goto close_fail;
+ if (!file->f_op->write)
+ goto close_fail;
+- if (do_truncate(file->f_dentry, 0, 0, file) != 0)
++ if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0)
+ goto close_fail;
+
+ retval = binfmt->core_dump(signr, regs, file);
+diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
+index 4c39009..93e77c3 100644
+--- a/fs/exportfs/expfs.c
++++ b/fs/exportfs/expfs.c
+@@ -315,7 +315,7 @@ struct getdents_callback {
+ * the name matching the specified inode number.
+ */
+ static int filldir_one(void * __buf, const char * name, int len,
+- loff_t pos, ino_t ino, unsigned int d_type)
++ loff_t pos, u64 ino, unsigned int d_type)
+ {
+ struct getdents_callback *buf = __buf;
+ int result = 0;
+diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
+index da52b4a..7c420b8 100644
+--- a/fs/ext2/acl.c
++++ b/fs/ext2/acl.c
+@@ -89,8 +89,8 @@ ext2_acl_to_disk(const struct posix_acl
+ size_t n;
+
+ *size = ext2_acl_size(acl->a_count);
+- ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) +
+- acl->a_count * sizeof(ext2_acl_entry), GFP_KERNEL);
++ ext_acl = kmalloc(sizeof(ext2_acl_header) + acl->a_count *
++ sizeof(ext2_acl_entry), GFP_KERNEL);
+ if (!ext_acl)
+ return ERR_PTR(-ENOMEM);
+ ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION);
+diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
+index 92ea826..3e7a84a 100644
+--- a/fs/ext2/dir.c
++++ b/fs/ext2/dir.c
+@@ -661,5 +661,8 @@ const struct file_operations ext2_dir_op
+ .read = generic_read_dir,
+ .readdir = ext2_readdir,
+ .ioctl = ext2_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext2_compat_ioctl,
++#endif
+ .fsync = ext2_sync_file,
+ };
+diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
+index e65a019..c19ac15 100644
+--- a/fs/ext2/ext2.h
++++ b/fs/ext2/ext2.h
+@@ -137,6 +137,7 @@ extern void ext2_set_inode_flags(struct
+ /* ioctl.c */
+ extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
++extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long);
+
+ /* namei.c */
+ struct dentry *ext2_get_parent(struct dentry *child);
+diff --git a/fs/ext2/file.c b/fs/ext2/file.c
+index 23e2c7c..2dba473 100644
+--- a/fs/ext2/file.c
++++ b/fs/ext2/file.c
+@@ -41,17 +41,18 @@ static int ext2_release_file (struct ino
+ */
+ const struct file_operations ext2_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .ioctl = ext2_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext2_compat_ioctl,
++#endif
+ .mmap = generic_file_mmap,
+ .open = generic_file_open,
+ .release = ext2_release_file,
+ .fsync = ext2_sync_file,
+- .readv = generic_file_readv,
+- .writev = generic_file_writev,
+ .sendfile = generic_file_sendfile,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+@@ -63,6 +64,9 @@ const struct file_operations ext2_xip_fi
+ .read = xip_file_read,
+ .write = xip_file_write,
+ .ioctl = ext2_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext2_compat_ioctl,
++#endif
+ .mmap = xip_file_mmap,
+ .open = generic_file_open,
+ .release = ext2_release_file,
+diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
+index 695f69c..2cb545b 100644
+--- a/fs/ext2/ialloc.c
++++ b/fs/ext2/ialloc.c
+@@ -574,7 +574,6 @@ got:
+ inode->i_mode = mode;
+
+ inode->i_ino = ino;
+- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ memset(ei->i_data, 0, sizeof(ei->i_data));
+diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
+index fb4d322..dd4e14c 100644
+--- a/fs/ext2/inode.c
++++ b/fs/ext2/inode.c
+@@ -1094,7 +1094,6 @@ void ext2_read_inode (struct inode * ino
+ brelse (bh);
+ goto bad_inode;
+ }
+- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
+ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
+ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
+ ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
+diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
+index 3ca9afd..1dfba77 100644
+--- a/fs/ext2/ioctl.c
++++ b/fs/ext2/ioctl.c
+@@ -11,6 +11,8 @@
+ #include <linux/capability.h>
+ #include <linux/time.h>
+ #include <linux/sched.h>
++#include <linux/compat.h>
++#include <linux/smp_lock.h>
+ #include <asm/current.h>
+ #include <asm/uaccess.h>
+
+@@ -80,3 +82,33 @@ int ext2_ioctl (struct inode * inode, st
+ return -ENOTTY;
+ }
+ }
++
++#ifdef CONFIG_COMPAT
++long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int ret;
++
++ /* These are just misnamed, they actually get/put from/to user an int */
++ switch (cmd) {
++ case EXT2_IOC32_GETFLAGS:
++ cmd = EXT2_IOC_GETFLAGS;
++ break;
++ case EXT2_IOC32_SETFLAGS:
++ cmd = EXT2_IOC_SETFLAGS;
++ break;
++ case EXT2_IOC32_GETVERSION:
++ cmd = EXT2_IOC_GETVERSION;
++ break;
++ case EXT2_IOC32_SETVERSION:
++ cmd = EXT2_IOC_SETVERSION;
++ break;
++ default:
++ return -ENOIOCTLCMD;
++ }
++ lock_kernel();
++ ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
++ unlock_kernel();
++ return ret;
++}
++#endif
+diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
+index 4ca8249..e1af5b4 100644
+--- a/fs/ext2/namei.c
++++ b/fs/ext2/namei.c
+@@ -326,7 +326,7 @@ static int ext2_rename (struct inode * o
+ ext2_set_link(new_dir, new_de, new_page, old_inode);
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+ if (dir_de)
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ inode_dec_link_count(new_inode);
+ } else {
+ if (dir_de) {
+diff --git a/fs/ext2/super.c b/fs/ext2/super.c
+index 4286ff6..d8b9abd 100644
+--- a/fs/ext2/super.c
++++ b/fs/ext2/super.c
+@@ -184,8 +184,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(ext2_inode_cachep))
+- printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(ext2_inode_cachep);
+ }
+
+ static void ext2_clear_inode(struct inode *inode)
+@@ -365,7 +364,6 @@ static int parse_options (char * options
+ {
+ char * p;
+ substring_t args[MAX_OPT_ARGS];
+- unsigned long kind = EXT2_MOUNT_ERRORS_CONT;
+ int option;
+
+ if (!options)
+@@ -405,13 +403,19 @@ static int parse_options (char * options
+ /* *sb_block = match_int(&args[0]); */
+ break;
+ case Opt_err_panic:
+- kind = EXT2_MOUNT_ERRORS_PANIC;
++ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
++ clear_opt (sbi->s_mount_opt, ERRORS_RO);
++ set_opt (sbi->s_mount_opt, ERRORS_PANIC);
+ break;
+ case Opt_err_ro:
+- kind = EXT2_MOUNT_ERRORS_RO;
++ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
++ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
++ set_opt (sbi->s_mount_opt, ERRORS_RO);
+ break;
+ case Opt_err_cont:
+- kind = EXT2_MOUNT_ERRORS_CONT;
++ clear_opt (sbi->s_mount_opt, ERRORS_RO);
++ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
++ set_opt (sbi->s_mount_opt, ERRORS_CONT);
+ break;
+ case Opt_nouid32:
+ set_opt (sbi->s_mount_opt, NO_UID32);
+@@ -490,7 +494,6 @@ static int parse_options (char * options
+ return 0;
+ }
+ }
+- sbi->s_mount_opt |= kind;
+ return 1;
+ }
+
+@@ -544,17 +547,24 @@ static int ext2_check_descriptors (struc
+ int i;
+ int desc_block = 0;
+ struct ext2_sb_info *sbi = EXT2_SB(sb);
+- unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
++ unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
++ unsigned long last_block;
+ struct ext2_group_desc * gdp = NULL;
+
+ ext2_debug ("Checking group descriptors");
+
+ for (i = 0; i < sbi->s_groups_count; i++)
+ {
++ if (i == sbi->s_groups_count - 1)
++ last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
++ else
++ last_block = first_block +
++ (EXT2_BLOCKS_PER_GROUP(sb) - 1);
++
+ if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
+ gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data;
+- if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
+- le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb))
++ if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
++ le32_to_cpu(gdp->bg_block_bitmap) > last_block)
+ {
+ ext2_error (sb, "ext2_check_descriptors",
+ "Block bitmap for group %d"
+@@ -562,8 +572,8 @@ static int ext2_check_descriptors (struc
+ i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
+ return 0;
+ }
+- if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
+- le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb))
++ if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block ||
++ le32_to_cpu(gdp->bg_inode_bitmap) > last_block)
+ {
+ ext2_error (sb, "ext2_check_descriptors",
+ "Inode bitmap for group %d"
+@@ -571,9 +581,9 @@ static int ext2_check_descriptors (struc
+ i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
+ return 0;
+ }
+- if (le32_to_cpu(gdp->bg_inode_table) < block ||
+- le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >=
+- block + EXT2_BLOCKS_PER_GROUP(sb))
++ if (le32_to_cpu(gdp->bg_inode_table) < first_block ||
++ le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >
++ last_block)
+ {
+ ext2_error (sb, "ext2_check_descriptors",
+ "Inode table for group %d"
+@@ -581,7 +591,7 @@ static int ext2_check_descriptors (struc
+ i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
+ return 0;
+ }
+- block += EXT2_BLOCKS_PER_GROUP(sb);
++ first_block += EXT2_BLOCKS_PER_GROUP(sb);
+ gdp++;
+ }
+ return 1;
+@@ -648,11 +658,10 @@ static int ext2_fill_super(struct super_
+ int i, j;
+ __le32 features;
+
+- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(*sbi));
+
+ /*
+ * See what the current blocksize for the device is, and
+@@ -710,6 +719,8 @@ static int ext2_fill_super(struct super_
+ set_opt(sbi->s_mount_opt, ERRORS_PANIC);
+ else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
+ set_opt(sbi->s_mount_opt, ERRORS_RO);
++ else
++ set_opt(sbi->s_mount_opt, ERRORS_CONT);
+
+ sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
+ sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+@@ -861,10 +872,9 @@ static int ext2_fill_super(struct super_
+
+ if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
+ goto cantfind_ext2;
+- sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
+- le32_to_cpu(es->s_first_data_block) +
+- EXT2_BLOCKS_PER_GROUP(sb) - 1) /
+- EXT2_BLOCKS_PER_GROUP(sb);
++ sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
++ le32_to_cpu(es->s_first_data_block) - 1)
++ / EXT2_BLOCKS_PER_GROUP(sb)) + 1;
+ db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
+ EXT2_DESC_PER_BLOCK(sb);
+ sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
+diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
+index 86ae8e9..af52a7f 100644
+--- a/fs/ext2/xattr.c
++++ b/fs/ext2/xattr.c
+@@ -521,11 +521,10 @@ bad_block: ext2_error(sb, "ext2_xattr_s
+ }
+ } else {
+ /* Allocate a buffer where we construct the new block. */
+- header = kmalloc(sb->s_blocksize, GFP_KERNEL);
++ header = kzalloc(sb->s_blocksize, GFP_KERNEL);
+ error = -ENOMEM;
+ if (header == NULL)
+ goto cleanup;
+- memset(header, 0, sb->s_blocksize);
+ end = (char *)header + sb->s_blocksize;
+ header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC);
+ header->h_blocks = header->h_refcount = cpu_to_le32(1);
+diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
+index 0d21d55..1e5038d 100644
+--- a/fs/ext3/acl.c
++++ b/fs/ext3/acl.c
+@@ -90,8 +90,8 @@ ext3_acl_to_disk(const struct posix_acl
+ size_t n;
+
+ *size = ext3_acl_size(acl->a_count);
+- ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
+- acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL);
++ ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count *
++ sizeof(ext3_acl_entry), GFP_KERNEL);
+ if (!ext_acl)
+ return ERR_PTR(-ENOMEM);
+ ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION);
+@@ -258,7 +258,7 @@ ext3_set_acl(handle_t *handle, struct in
+ default:
+ return -EINVAL;
+ }
+- if (acl) {
++ if (acl) {
+ value = ext3_acl_to_disk(acl, &size);
+ if (IS_ERR(value))
+ return (int)PTR_ERR(value);
+diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
+index 063d994..b41a7d7 100644
+--- a/fs/ext3/balloc.c
++++ b/fs/ext3/balloc.c
+@@ -38,6 +38,13 @@
+
+ #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
+
++/**
++ * ext3_get_group_desc() -- load group descriptor from disk
++ * @sb: super block
++ * @block_group: given block group
++ * @bh: pointer to the buffer head to store the block
++ * group descriptor
++ */
+ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh)
+@@ -73,8 +80,12 @@ struct ext3_group_desc * ext3_get_group_
+ return desc + offset;
+ }
+
+-/*
+- * Read the bitmap for a given block_group, reading into the specified
++/**
++ * read_block_bitmap()
++ * @sb: super block
++ * @block_group: given block group
++ *
++ * Read the bitmap for a given block_group, reading into the specified
+ * slot in the superblock's bitmap cache.
+ *
+ * Return buffer_head on success or NULL in case of failure.
+@@ -103,15 +114,22 @@ error_out:
+ * Operations include:
+ * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
+ *
+- * We use sorted double linked list for the per-filesystem reservation
+- * window list. (like in vm_region).
++ * We use a red-black tree to represent per-filesystem reservation
++ * windows.
++ *
++ */
++
++/**
++ * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
++ * @rb_root: root of per-filesystem reservation rb tree
++ * @verbose: verbose mode
++ * @fn: function which wishes to dump the reservation map
+ *
+- * Initially, we keep those small operations in the abstract functions,
+- * so later if we need a better searching tree than double linked-list,
+- * we could easily switch to that without changing too much
+- * code.
++ * If verbose is turned on, it will print the whole block reservation
++ * windows(start, end). Otherwise, it will only print out the "bad" windows,
++ * those windows that overlap with their immediate neighbors.
+ */
+-#if 0
++#if 1
+ static void __rsv_window_dump(struct rb_root *root, int verbose,
+ const char *fn)
+ {
+@@ -129,7 +147,7 @@ restart:
+ rsv = list_entry(n, struct ext3_reserve_window_node, rsv_node);
+ if (verbose)
+ printk("reservation window 0x%p "
+- "start: %d, end: %d\n",
++ "start: %lu, end: %lu\n",
+ rsv, rsv->rsv_start, rsv->rsv_end);
+ if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
+ printk("Bad reservation %p (start >= end)\n",
+@@ -161,6 +179,22 @@ restart:
+ #define rsv_window_dump(root, verbose) do {} while (0)
+ #endif
+
++/**
++ * goal_in_my_reservation()
++ * @rsv: inode's reservation window
++ * @grp_goal: given goal block relative to the allocation block group
++ * @group: the current allocation block group
++ * @sb: filesystem super block
++ *
++ * Test if the given goal block (group relative) is within the file's
++ * own block reservation window range.
++ *
++ * If the reservation window is outside the goal allocation group, return 0;
++ * grp_goal (given goal block) could be -1, which means no specific
++ * goal block. In this case, always return 1.
++ * If the goal block is within the reservation window, return 1;
++ * otherwise, return 0;
++ */
+ static int
+ goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
+ unsigned int group, struct super_block * sb)
+@@ -168,7 +202,7 @@ goal_in_my_reservation(struct ext3_reser
+ ext3_fsblk_t group_first_block, group_last_block;
+
+ group_first_block = ext3_group_first_block_no(sb, group);
+- group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
++ group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
+
+ if ((rsv->_rsv_start > group_last_block) ||
+ (rsv->_rsv_end < group_first_block))
+@@ -179,7 +213,11 @@ goal_in_my_reservation(struct ext3_reser
+ return 1;
+ }
+
+-/*
++/**
++ * search_reserve_window()
++ * @rb_root: root of reservation tree
++ * @goal: target allocation block
++ *
+ * Find the reserved window which includes the goal, or the previous one
+ * if the goal is not in any window.
+ * Returns NULL if there are no windows or if all windows start after the goal.
+@@ -216,6 +254,13 @@ search_reserve_window(struct rb_root *ro
+ return rsv;
+ }
+
++/**
++ * ext3_rsv_window_add() -- Insert a window to the block reservation rb tree.
++ * @sb: super block
++ * @rsv: reservation window to add
++ *
++ * Must be called with rsv_lock hold.
++ */
+ void ext3_rsv_window_add(struct super_block *sb,
+ struct ext3_reserve_window_node *rsv)
+ {
+@@ -236,14 +281,25 @@ void ext3_rsv_window_add(struct super_bl
+ p = &(*p)->rb_left;
+ else if (start > this->rsv_end)
+ p = &(*p)->rb_right;
+- else
++ else {
++ rsv_window_dump(root, 1);
+ BUG();
++ }
+ }
+
+ rb_link_node(node, parent, p);
+ rb_insert_color(node, root);
+ }
+
++/**
++ * ext3_rsv_window_remove() -- unlink a window from the reservation rb tree
++ * @sb: super block
++ * @rsv: reservation window to remove
++ *
++ * Mark the block reservation window as not allocated, and unlink it
++ * from the filesystem reservation window rb tree. Must be called with
++ * rsv_lock hold.
++ */
+ static void rsv_window_remove(struct super_block *sb,
+ struct ext3_reserve_window_node *rsv)
+ {
+@@ -253,11 +309,39 @@ static void rsv_window_remove(struct sup
+ rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root);
+ }
+
++/*
++ * rsv_is_empty() -- Check if the reservation window is allocated.
++ * @rsv: given reservation window to check
++ *
++ * returns 1 if the end block is EXT3_RESERVE_WINDOW_NOT_ALLOCATED.
++ */
+ static inline int rsv_is_empty(struct ext3_reserve_window *rsv)
+ {
+ /* a valid reservation end block could not be 0 */
+- return (rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED);
++ return rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+ }
++
++/**
++ * ext3_init_block_alloc_info()
++ * @inode: file inode structure
++ *
++ * Allocate and initialize the reservation window structure, and
++ * link the window to the ext3 inode structure at last
++ *
++ * The reservation window structure is only dynamically allocated
++ * and linked to ext3 inode the first time the open file
++ * needs a new block. So, before every ext3_new_block(s) call, for
++ * regular files, we should check whether the reservation window
++ * structure exists or not. In the latter case, this function is called.
++ * Fail to do so will result in block reservation being turned off for that
++ * open file.
++ *
++ * This function is called from ext3_get_blocks_handle(), also called
++ * when setting the reservation window size through ioctl before the file
++ * is open for write (needs block allocation).
++ *
++ * Needs truncate_mutex protection prior to call this function.
++ */
+ void ext3_init_block_alloc_info(struct inode *inode)
+ {
+ struct ext3_inode_info *ei = EXT3_I(inode);
+@@ -271,7 +355,7 @@ void ext3_init_block_alloc_info(struct i
+ rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+ rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+
+- /*
++ /*
+ * if filesystem is mounted with NORESERVATION, the goal
+ * reservation window size is set to zero to indicate
+ * block reservation is off
+@@ -287,6 +371,19 @@ void ext3_init_block_alloc_info(struct i
+ ei->i_block_alloc_info = block_i;
+ }
+
++/**
++ * ext3_discard_reservation()
++ * @inode: inode
++ *
++ * Discard(free) block reservation window on last file close, or truncate
++ * or at last iput().
++ *
++ * It is being called in three cases:
++ * ext3_release_file(): last writer close the file
++ * ext3_clear_inode(): last iput(), when nobody link to this file.
++ * ext3_truncate(): when the block indirect map is about to change.
++ *
++ */
+ void ext3_discard_reservation(struct inode *inode)
+ {
+ struct ext3_inode_info *ei = EXT3_I(inode);
+@@ -306,7 +403,14 @@ void ext3_discard_reservation(struct ino
+ }
+ }
+
+-/* Free given blocks, update quota and i_blocks field */
++/**
++ * ext3_free_blocks_sb() -- Free given blocks and update quota
++ * @handle: handle to this transaction
++ * @sb: super block
++ * @block: start physcial block to free
++ * @count: number of blocks to free
++ * @pdquot_freed_blocks: pointer to quota
++ */
+ void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
+ ext3_fsblk_t block, unsigned long count,
+ unsigned long *pdquot_freed_blocks)
+@@ -419,8 +523,8 @@ do_more:
+ }
+ /* @@@ This prevents newly-allocated data from being
+ * freed and then reallocated within the same
+- * transaction.
+- *
++ * transaction.
++ *
+ * Ideally we would want to allow that to happen, but to
+ * do so requires making journal_forget() capable of
+ * revoking the queued write of a data block, which
+@@ -433,7 +537,7 @@ do_more:
+ * safe not to set the allocation bit in the committed
+ * bitmap, because we know that there is no outstanding
+ * activity on the buffer any more and so it is safe to
+- * reallocate it.
++ * reallocate it.
+ */
+ BUFFER_TRACE(bitmap_bh, "set in b_committed_data");
+ J_ASSERT_BH(bitmap_bh,
+@@ -490,7 +594,13 @@ error_return:
+ return;
+ }
+
+-/* Free given blocks, update quota and i_blocks field */
++/**
++ * ext3_free_blocks() -- Free given blocks and update quota
++ * @handle: handle for this transaction
++ * @inode: inode
++ * @block: start physical block to free
++ * @count: number of blocks to count
++ */
+ void ext3_free_blocks(handle_t *handle, struct inode *inode,
+ ext3_fsblk_t block, unsigned long count)
+ {
+@@ -508,7 +618,11 @@ void ext3_free_blocks(handle_t *handle,
+ return;
+ }
+
+-/*
++/**
++ * ext3_test_allocatable()
++ * @nr: given allocation block group
++ * @bh: bufferhead contains the bitmap of the given block group
++ *
+ * For ext3 allocations, we must not reuse any blocks which are
+ * allocated in the bitmap buffer's "last committed data" copy. This
+ * prevents deletes from freeing up the page for reuse until we have
+@@ -518,7 +632,7 @@ void ext3_free_blocks(handle_t *handle,
+ * data would allow the old block to be overwritten before the
+ * transaction committed (because we force data to disk before commit).
+ * This would lead to corruption if we crashed between overwriting the
+- * data and committing the delete.
++ * data and committing the delete.
+ *
+ * @@@ We may want to make this allocation behaviour conditional on
+ * data-writes at some point, and disable it for metadata allocations or
+@@ -541,6 +655,16 @@ static int ext3_test_allocatable(ext3_gr
+ return ret;
+ }
+
++/**
++ * bitmap_search_next_usable_block()
++ * @start: the starting block (group relative) of the search
++ * @bh: bufferhead contains the block group bitmap
++ * @maxblocks: the ending block (group relative) of the reservation
++ *
++ * The bitmap search --- search forward alternately through the actual
++ * bitmap on disk and the last-committed copy in journal, until we find a
++ * bit free in both bitmaps.
++ */
+ static ext3_grpblk_t
+ bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+ ext3_grpblk_t maxblocks)
+@@ -548,11 +672,6 @@ bitmap_search_next_usable_block(ext3_grp
+ ext3_grpblk_t next;
+ struct journal_head *jh = bh2jh(bh);
+
+- /*
+- * The bitmap search --- search forward alternately through the actual
+- * bitmap and the last-committed copy until we find a bit free in
+- * both
+- */
+ while (start < maxblocks) {
+ next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start);
+ if (next >= maxblocks)
+@@ -562,14 +681,20 @@ bitmap_search_next_usable_block(ext3_grp
+ jbd_lock_bh_state(bh);
+ if (jh->b_committed_data)
+ start = ext3_find_next_zero_bit(jh->b_committed_data,
+- maxblocks, next);
++ maxblocks, next);
+ jbd_unlock_bh_state(bh);
+ }
+ return -1;
+ }
+
+-/*
+- * Find an allocatable block in a bitmap. We honour both the bitmap and
++/**
++ * find_next_usable_block()
++ * @start: the starting block (group relative) to find next
++ * allocatable block in bitmap.
++ * @bh: bufferhead contains the block group bitmap
++ * @maxblocks: the ending block (group relative) for the search
++ *
++ * Find an allocatable block in a bitmap. We honor both the bitmap and
+ * its last-committed copy (if that exists), and perform the "most
+ * appropriate allocation" algorithm of looking for a free block near
+ * the initial goal; then for a free byte somewhere in the bitmap; then
+@@ -584,7 +709,7 @@ find_next_usable_block(ext3_grpblk_t sta
+
+ if (start > 0) {
+ /*
+- * The goal was occupied; search forward for a free
++ * The goal was occupied; search forward for a free
+ * block within the next XX blocks.
+ *
+ * end_goal is more or less random, but it has to be
+@@ -620,7 +745,11 @@ find_next_usable_block(ext3_grpblk_t sta
+ return here;
+ }
+
+-/*
++/**
++ * claim_block()
++ * @block: the free block (group relative) to allocate
++ * @bh: the bufferhead containts the block group bitmap
++ *
+ * We think we can allocate this block in this bitmap. Try to set the bit.
+ * If that succeeds then check that nobody has allocated and then freed the
+ * block since we saw that is was not marked in b_committed_data. If it _was_
+@@ -646,7 +775,26 @@ claim_block(spinlock_t *lock, ext3_grpbl
+ return ret;
+ }
+
+-/*
++/**
++ * ext3_try_to_allocate()
++ * @sb: superblock
++ * @handle: handle to this transaction
++ * @group: given allocation block group
++ * @bitmap_bh: bufferhead holds the block bitmap
++ * @grp_goal: given target block within the group
++ * @count: target number of blocks to allocate
++ * @my_rsv: reservation window
++ *
++ * Attempt to allocate blocks within a give range. Set the range of allocation
++ * first, then find the first free bit(s) from the bitmap (within the range),
++ * and at last, allocate the blocks by claiming the found free bit as allocated.
++ *
++ * To set the range of this allocation:
++ * if there is a reservation window, only try to allocate block(s) from the
++ * file's own reservation window;
++ * Otherwise, the allocation range starts from the give goal block, ends at
++ * the block group's last block.
++ *
+ * If we failed to allocate the desired block then we may end up crossing to a
+ * new bitmap. In that case we must release write access to the old one via
+ * ext3_journal_release_buffer(), else we'll run out of credits.
+@@ -703,7 +851,8 @@ repeat:
+ }
+ start = grp_goal;
+
+- if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
++ if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group),
++ grp_goal, bitmap_bh)) {
+ /*
+ * The block was allocated by another thread, or it was
+ * allocated and then freed by another thread
+@@ -718,7 +867,8 @@ repeat:
+ grp_goal++;
+ while (num < *count && grp_goal < end
+ && ext3_test_allocatable(grp_goal, bitmap_bh)
+- && claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
++ && claim_block(sb_bgl_lock(EXT3_SB(sb), group),
++ grp_goal, bitmap_bh)) {
+ num++;
+ grp_goal++;
+ }
+@@ -730,12 +880,12 @@ fail_access:
+ }
+
+ /**
+- * find_next_reservable_window():
++ * find_next_reservable_window():
+ * find a reservable space within the given range.
+ * It does not allocate the reservation window for now:
+ * alloc_new_reservation() will do the work later.
+ *
+- * @search_head: the head of the searching list;
++ * @search_head: the head of the searching list;
+ * This is not necessarily the list head of the whole filesystem
+ *
+ * We have both head and start_block to assist the search
+@@ -743,12 +893,12 @@ fail_access:
+ * but we will shift to the place where start_block is,
+ * then start from there, when looking for a reservable space.
+ *
+- * @size: the target new reservation window size
++ * @size: the target new reservation window size
+ *
+- * @group_first_block: the first block we consider to start
++ * @group_first_block: the first block we consider to start
+ * the real search from
+ *
+- * @last_block:
++ * @last_block:
+ * the maximum block number that our goal reservable space
+ * could start from. This is normally the last block in this
+ * group. The search will end when we found the start of next
+@@ -756,10 +906,10 @@ fail_access:
+ * This could handle the cross boundary reservation window
+ * request.
+ *
+- * basically we search from the given range, rather than the whole
+- * reservation double linked list, (start_block, last_block)
+- * to find a free region that is of my size and has not
+- * been reserved.
++ * basically we search from the given range, rather than the whole
++ * reservation double linked list, (start_block, last_block)
++ * to find a free region that is of my size and has not
++ * been reserved.
+ *
+ */
+ static int find_next_reservable_window(
+@@ -812,7 +962,7 @@ static int find_next_reservable_window(
+ /*
+ * Found a reserveable space big enough. We could
+ * have a reservation across the group boundary here
+- */
++ */
+ break;
+ }
+ }
+@@ -848,7 +998,7 @@ static int find_next_reservable_window(
+ }
+
+ /**
+- * alloc_new_reservation()--allocate a new reservation window
++ * alloc_new_reservation()--allocate a new reservation window
+ *
+ * To make a new reservation, we search part of the filesystem
+ * reservation list (the list that inside the group). We try to
+@@ -897,7 +1047,7 @@ static int alloc_new_reservation(struct
+ spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
+
+ group_first_block = ext3_group_first_block_no(sb, group);
+- group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
++ group_end_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
+
+ if (grp_goal < 0)
+ start_block = group_first_block;
+@@ -929,9 +1079,10 @@ static int alloc_new_reservation(struct
+ if ((my_rsv->rsv_alloc_hit >
+ (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
+ /*
+- * if we previously allocation hit ration is greater than half
+- * we double the size of reservation window next time
+- * otherwise keep the same
++ * if the previously allocation hit ratio is
++ * greater than 1/2, then we double the size of
++ * the reservation window the next time,
++ * otherwise we keep the same size window
+ */
+ size = size * 2;
+ if (size > EXT3_MAX_RESERVE_BLOCKS)
+@@ -1010,6 +1161,23 @@ retry:
+ goto retry;
+ }
+
++/**
++ * try_to_extend_reservation()
++ * @my_rsv: given reservation window
++ * @sb: super block
++ * @size: the delta to extend
++ *
++ * Attempt to expand the reservation window large enough to have
++ * required number of free blocks
++ *
++ * Since ext3_try_to_allocate() will always allocate blocks within
++ * the reservation window range, if the window size is too small,
++ * multiple blocks allocation has to stop at the end of the reservation
++ * window. To make this more efficient, given the total number of
++ * blocks needed and the current size of the window, we try to
++ * expand the reservation window size if necessary on a best-effort
++ * basis before ext3_new_blocks() tries to allocate blocks,
++ */
+ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
+ struct super_block *sb, int size)
+ {
+@@ -1035,7 +1203,17 @@ static void try_to_extend_reservation(st
+ spin_unlock(rsv_lock);
+ }
+
+-/*
++/**
++ * ext3_try_to_allocate_with_rsv()
++ * @sb: superblock
++ * @handle: handle to this transaction
++ * @group: given allocation block group
++ * @bitmap_bh: bufferhead holds the block bitmap
++ * @grp_goal: given target block within the group
++ * @count: target number of blocks to allocate
++ * @my_rsv: reservation window
++ * @errp: pointer to store the error code
++ *
+ * This is the main function used to allocate a new block and its reservation
+ * window.
+ *
+@@ -1051,9 +1229,7 @@ static void try_to_extend_reservation(st
+ * reservation), and there are lots of free blocks, but they are all
+ * being reserved.
+ *
+- * We use a sorted double linked list for the per-filesystem reservation list.
+- * The insert, remove and find a free space(non-reserved) operations for the
+- * sorted double linked list should be fast.
++ * We use a red-black tree for the per-filesystem reservation list.
+ *
+ */
+ static ext3_grpblk_t
+@@ -1063,7 +1239,7 @@ ext3_try_to_allocate_with_rsv(struct sup
+ struct ext3_reserve_window_node * my_rsv,
+ unsigned long *count, int *errp)
+ {
+- ext3_fsblk_t group_first_block;
++ ext3_fsblk_t group_first_block, group_last_block;
+ ext3_grpblk_t ret = 0;
+ int fatal;
+ unsigned long num = *count;
+@@ -1100,6 +1276,7 @@ ext3_try_to_allocate_with_rsv(struct sup
+ * first block is the block number of the first block in this group
+ */
+ group_first_block = ext3_group_first_block_no(sb, group);
++ group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
+
+ /*
+ * Basically we will allocate a new block from inode's reservation
+@@ -1118,7 +1295,8 @@ ext3_try_to_allocate_with_rsv(struct sup
+ */
+ while (1) {
+ if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
+- !goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb)) {
++ !goal_in_my_reservation(&my_rsv->rsv_window,
++ grp_goal, group, sb)) {
+ if (my_rsv->rsv_goal_size < *count)
+ my_rsv->rsv_goal_size = *count;
+ ret = alloc_new_reservation(my_rsv, grp_goal, sb,
+@@ -1126,17 +1304,21 @@ ext3_try_to_allocate_with_rsv(struct sup
+ if (ret < 0)
+ break; /* failed */
+
+- if (!goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb))
++ if (!goal_in_my_reservation(&my_rsv->rsv_window,
++ grp_goal, group, sb))
+ grp_goal = -1;
+- } else if (grp_goal > 0 && (my_rsv->rsv_end-grp_goal+1) < *count)
++ } else if (grp_goal > 0 &&
++ (my_rsv->rsv_end-grp_goal+1) < *count)
+ try_to_extend_reservation(my_rsv, sb,
+ *count-my_rsv->rsv_end + grp_goal - 1);
+
+- if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
+- || (my_rsv->rsv_end < group_first_block))
++ if ((my_rsv->rsv_start > group_last_block) ||
++ (my_rsv->rsv_end < group_first_block)) {
++ rsv_window_dump(&EXT3_SB(sb)->s_rsv_window_root, 1);
+ BUG();
+- ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal,
+- &num, &my_rsv->rsv_window);
++ }
++ ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh,
++ grp_goal, &num, &my_rsv->rsv_window);
+ if (ret >= 0) {
+ my_rsv->rsv_alloc_hit += num;
+ *count = num;
+@@ -1161,6 +1343,12 @@ out:
+ return ret;
+ }
+
++/**
++ * ext3_has_free_blocks()
++ * @sbi: in-core super block structure.
++ *
++ * Check if filesystem has at least 1 free block available for allocation.
++ */
+ static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
+ {
+ ext3_fsblk_t free_blocks, root_blocks;
+@@ -1175,11 +1363,17 @@ static int ext3_has_free_blocks(struct e
+ return 1;
+ }
+
+-/*
++/**
++ * ext3_should_retry_alloc()
++ * @sb: super block
++ * @retries number of attemps has been made
++ *
+ * ext3_should_retry_alloc() is called when ENOSPC is returned, and if
+ * it is profitable to retry the operation, this function will wait
+ * for the current or commiting transaction to complete, and then
+ * return TRUE.
++ *
++ * if the total number of retries exceed three times, return FALSE.
+ */
+ int ext3_should_retry_alloc(struct super_block *sb, int *retries)
+ {
+@@ -1191,13 +1385,19 @@ int ext3_should_retry_alloc(struct super
+ return journal_force_commit_nested(EXT3_SB(sb)->s_journal);
+ }
+
+-/*
+- * ext3_new_block uses a goal block to assist allocation. If the goal is
+- * free, or there is a free block within 32 blocks of the goal, that block
+- * is allocated. Otherwise a forward search is made for a free block; within
+- * each block group the search first looks for an entire free byte in the block
+- * bitmap, and then for any free bit if that fails.
+- * This function also updates quota and i_blocks field.
++/**
++ * ext3_new_blocks() -- core block(s) allocation function
++ * @handle: handle to this transaction
++ * @inode: file inode
++ * @goal: given target block(filesystem wide)
++ * @count: target number of blocks to allocate
++ * @errp: error code
++ *
++ * ext3_new_blocks uses a goal block to assist allocation. It tries to
++ * allocate block(s) from the block group contains the goal block first. If that
++ * fails, it will try to allocate block(s) from other block groups without
++ * any specific goal block.
++ *
+ */
+ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
+ ext3_fsblk_t goal, unsigned long *count, int *errp)
+@@ -1303,7 +1503,7 @@ retry_alloc:
+ smp_rmb();
+
+ /*
+- * Now search the rest of the groups. We assume that
++ * Now search the rest of the groups. We assume that
+ * i and gdp correctly point to the last group visited.
+ */
+ for (bgi = 0; bgi < ngroups; bgi++) {
+@@ -1428,7 +1628,7 @@ allocated:
+
+ spin_lock(sb_bgl_lock(sbi, group_no));
+ gdp->bg_free_blocks_count =
+- cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - num);
++ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
+ spin_unlock(sb_bgl_lock(sbi, group_no));
+ percpu_counter_mod(&sbi->s_freeblocks_counter, -num);
+
+@@ -1471,6 +1671,12 @@ ext3_fsblk_t ext3_new_block(handle_t *ha
+ return ext3_new_blocks(handle, inode, goal, &count, errp);
+ }
+
++/**
++ * ext3_count_free_blocks() -- count filesystem free blocks
++ * @sb: superblock
++ *
++ * Adds up the number of free blocks from each block group.
++ */
+ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
+ {
+ ext3_fsblk_t desc_count;
+diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c
+index ce4f82b..b9176ee 100644
+--- a/fs/ext3/bitmap.c
++++ b/fs/ext3/bitmap.c
+@@ -20,7 +20,7 @@ unsigned long ext3_count_free (struct bu
+ unsigned int i;
+ unsigned long sum = 0;
+
+- if (!map)
++ if (!map)
+ return (0);
+ for (i = 0; i < numchars; i++)
+ sum += nibblemap[map->b_data[i] & 0xf] +
+diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
+index fbb0d4e..d0b54f3 100644
+--- a/fs/ext3/dir.c
++++ b/fs/ext3/dir.c
+@@ -44,6 +44,9 @@ const struct file_operations ext3_dir_op
+ .read = generic_read_dir,
+ .readdir = ext3_readdir, /* we take BKL. needed?*/
+ .ioctl = ext3_ioctl, /* BKL held */
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext3_compat_ioctl,
++#endif
+ .fsync = ext3_sync_file, /* BKL held */
+ #ifdef CONFIG_EXT3_INDEX
+ .release = ext3_release_dir,
+@@ -59,7 +62,7 @@ static unsigned char get_dtype(struct su
+
+ return (ext3_filetype_table[filetype]);
+ }
+-
++
+
+ int ext3_check_dir_entry (const char * function, struct inode * dir,
+ struct ext3_dir_entry_2 * de,
+@@ -67,7 +70,7 @@ int ext3_check_dir_entry (const char * f
+ unsigned long offset)
+ {
+ const char * error_msg = NULL;
+- const int rlen = le16_to_cpu(de->rec_len);
++ const int rlen = le16_to_cpu(de->rec_len);
+
+ if (rlen < EXT3_DIR_REC_LEN(1))
+ error_msg = "rec_len is smaller than minimal";
+@@ -162,7 +165,7 @@ revalidate:
+ * to make sure. */
+ if (filp->f_version != inode->i_version) {
+ for (i = 0; i < sb->s_blocksize && i < offset; ) {
+- de = (struct ext3_dir_entry_2 *)
++ de = (struct ext3_dir_entry_2 *)
+ (bh->b_data + i);
+ /* It's too expensive to do a full
+ * dirent test each time round this
+@@ -181,7 +184,7 @@ revalidate:
+ filp->f_version = inode->i_version;
+ }
+
+- while (!error && filp->f_pos < inode->i_size
++ while (!error && filp->f_pos < inode->i_size
+ && offset < sb->s_blocksize) {
+ de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
+ if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
+@@ -229,7 +232,7 @@ out:
+ /*
+ * These functions convert from the major/minor hash to an f_pos
+ * value.
+- *
++ *
+ * Currently we only use major hash numer. This is unfortunate, but
+ * on 32-bit machines, the same VFS interface is used for lseek and
+ * llseek, so if we use the 64 bit offset, then the 32-bit versions of
+@@ -250,7 +253,7 @@ out:
+ struct fname {
+ __u32 hash;
+ __u32 minor_hash;
+- struct rb_node rb_hash;
++ struct rb_node rb_hash;
+ struct fname *next;
+ __u32 inode;
+ __u8 name_len;
+@@ -343,10 +346,9 @@ int ext3_htree_store_dirent(struct file
+
+ /* Create and allocate the fname structure */
+ len = sizeof(struct fname) + dirent->name_len + 1;
+- new_fn = kmalloc(len, GFP_KERNEL);
++ new_fn = kzalloc(len, GFP_KERNEL);
+ if (!new_fn)
+ return -ENOMEM;
+- memset(new_fn, 0, len);
+ new_fn->hash = hash;
+ new_fn->minor_hash = minor_hash;
+ new_fn->inode = le32_to_cpu(dirent->inode);
+@@ -410,7 +412,7 @@ static int call_filldir(struct file * fi
+ curr_pos = hash2pos(fname->hash, fname->minor_hash);
+ while (fname) {
+ error = filldir(dirent, fname->name,
+- fname->name_len, curr_pos,
++ fname->name_len, curr_pos,
+ fname->inode,
+ get_dtype(sb, fname->file_type));
+ if (error) {
+@@ -465,7 +467,7 @@ static int ext3_dx_readdir(struct file *
+ /*
+ * Fill the rbtree if we have no more entries,
+ * or the inode has changed since we last read in the
+- * cached entries.
++ * cached entries.
+ */
+ if ((!info->curr_node) ||
+ (filp->f_version != inode->i_version)) {
+diff --git a/fs/ext3/file.c b/fs/ext3/file.c
+index 1efefb6..e96c388 100644
+--- a/fs/ext3/file.c
++++ b/fs/ext3/file.c
+@@ -48,14 +48,15 @@ static int ext3_release_file (struct ino
+ }
+
+ static ssize_t
+-ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
++ext3_file_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_dentry->d_inode;
+ ssize_t ret;
+ int err;
+
+- ret = generic_file_aio_write(iocb, buf, count, pos);
++ ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+ /*
+ * Skip flushing if there was an error, or if nothing was written.
+@@ -100,7 +101,7 @@ ext3_file_write(struct kiocb *iocb, cons
+
+ force_commit:
+ err = ext3_force_commit(inode->i_sb);
+- if (err)
++ if (err)
+ return err;
+ return ret;
+ }
+@@ -111,9 +112,10 @@ const struct file_operations ext3_file_o
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = ext3_file_write,
+- .readv = generic_file_readv,
+- .writev = generic_file_writev,
+ .ioctl = ext3_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext3_compat_ioctl,
++#endif
+ .mmap = generic_file_mmap,
+ .open = generic_file_open,
+ .release = ext3_release_file,
+diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c
+index 49382a2..dd1fd3c 100644
+--- a/fs/ext3/fsync.c
++++ b/fs/ext3/fsync.c
+@@ -8,14 +8,14 @@
+ * Universite Pierre et Marie Curie (Paris VI)
+ * from
+ * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
+- *
++ *
+ * ext3fs fsync primitive
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem at caip.rutgers.edu), 1995
+- *
++ *
+ * Removed unnecessary code duplication for little endian machines
+- * and excessive __inline__s.
++ * and excessive __inline__s.
+ * Andi Kleen, 1997
+ *
+ * Major simplications and cleanup - we only need to do the metadata, because
+diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c
+index 5a2d123..deeb27b 100644
+--- a/fs/ext3/hash.c
++++ b/fs/ext3/hash.c
+@@ -4,7 +4,7 @@
+ * Copyright (C) 2002 by Theodore Ts'o
+ *
+ * This file is released under the GPL v2.
+- *
++ *
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+@@ -80,11 +80,11 @@ static void str2hashbuf(const char *msg,
+ * Returns the hash of a filename. If len is 0 and name is NULL, then
+ * this function can be used to test whether or not a hash version is
+ * supported.
+- *
++ *
+ * The seed is an 4 longword (32 bits) "secret" which can be used to
+ * uniquify a hash. If the seed is all zero's, then some default seed
+ * may be used.
+- *
++ *
+ * A particular hash version specifies whether or not the seed is
+ * represented, and whether or not the returned hash is 32 bits or 64
+ * bits. 32 bit hashes will return 0 for the minor hash.
+@@ -95,7 +95,7 @@ int ext3fs_dirhash(const char *name, int
+ __u32 minor_hash = 0;
+ const char *p;
+ int i;
+- __u32 in[8], buf[4];
++ __u32 in[8], buf[4];
+
+ /* Initialize the default seed for the hash checksum functions */
+ buf[0] = 0x67452301;
+diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
+index 36546ed..e45dbd6 100644
+--- a/fs/ext3/ialloc.c
++++ b/fs/ext3/ialloc.c
+@@ -202,7 +202,7 @@ error_return:
+ static int find_group_dir(struct super_block *sb, struct inode *parent)
+ {
+ int ngroups = EXT3_SB(sb)->s_groups_count;
+- int freei, avefreei;
++ unsigned int freei, avefreei;
+ struct ext3_group_desc *desc, *best_desc = NULL;
+ struct buffer_head *bh;
+ int group, best_group = -1;
+@@ -216,7 +216,7 @@ static int find_group_dir(struct super_b
+ continue;
+ if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
+ continue;
+- if (!best_desc ||
++ if (!best_desc ||
+ (le16_to_cpu(desc->bg_free_blocks_count) >
+ le16_to_cpu(best_desc->bg_free_blocks_count))) {
+ best_group = group;
+@@ -226,30 +226,30 @@ static int find_group_dir(struct super_b
+ return best_group;
+ }
+
+-/*
+- * Orlov's allocator for directories.
+- *
++/*
++ * Orlov's allocator for directories.
++ *
+ * We always try to spread first-level directories.
+ *
+- * If there are blockgroups with both free inodes and free blocks counts
+- * not worse than average we return one with smallest directory count.
+- * Otherwise we simply return a random group.
+- *
+- * For the rest rules look so:
+- *
+- * It's OK to put directory into a group unless
+- * it has too many directories already (max_dirs) or
+- * it has too few free inodes left (min_inodes) or
+- * it has too few free blocks left (min_blocks) or
+- * it's already running too large debt (max_debt).
+- * Parent's group is prefered, if it doesn't satisfy these
+- * conditions we search cyclically through the rest. If none
+- * of the groups look good we just look for a group with more
+- * free inodes than average (starting at parent's group).
+- *
+- * Debt is incremented each time we allocate a directory and decremented
+- * when we allocate an inode, within 0--255.
+- */
++ * If there are blockgroups with both free inodes and free blocks counts
++ * not worse than average we return one with smallest directory count.
++ * Otherwise we simply return a random group.
++ *
++ * For the rest rules look so:
++ *
++ * It's OK to put directory into a group unless
++ * it has too many directories already (max_dirs) or
++ * it has too few free inodes left (min_inodes) or
++ * it has too few free blocks left (min_blocks) or
++ * it's already running too large debt (max_debt).
++ * Parent's group is prefered, if it doesn't satisfy these
++ * conditions we search cyclically through the rest. If none
++ * of the groups look good we just look for a group with more
++ * free inodes than average (starting at parent's group).
++ *
++ * Debt is incremented each time we allocate a directory and decremented
++ * when we allocate an inode, within 0--255.
++ */
+
+ #define INODE_COST 64
+ #define BLOCK_COST 256
+@@ -261,10 +261,10 @@ static int find_group_orlov(struct super
+ struct ext3_super_block *es = sbi->s_es;
+ int ngroups = sbi->s_groups_count;
+ int inodes_per_group = EXT3_INODES_PER_GROUP(sb);
+- int freei, avefreei;
++ unsigned int freei, avefreei;
+ ext3_fsblk_t freeb, avefreeb;
+ ext3_fsblk_t blocks_per_dir;
+- int ndirs;
++ unsigned int ndirs;
+ int max_debt, max_dirs, min_inodes;
+ ext3_grpblk_t min_blocks;
+ int group = -1, i;
+@@ -454,7 +454,7 @@ struct inode *ext3_new_inode(handle_t *h
+ group = find_group_dir(sb, dir);
+ else
+ group = find_group_orlov(sb, dir);
+- } else
++ } else
+ group = find_group_other(sb, dir);
+
+ err = -ENOSPC;
+@@ -559,7 +559,6 @@ got:
+
+ inode->i_ino = ino;
+ /* This is the optimal IO size (for stat), not the fs block size */
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+
+diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
+index 84be02e..03ba5bc 100644
+--- a/fs/ext3/inode.c
++++ b/fs/ext3/inode.c
+@@ -13,11 +13,11 @@
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Goal-directed block allocation by Stephen Tweedie
+- * (sct at redhat.com), 1993, 1998
++ * (sct at redhat.com), 1993, 1998
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem at caip.rutgers.edu), 1995
+ * 64-bit file support on 64-bit platforms by Jakub Jelinek
+- * (jj at sunsite.ms.mff.cuni.cz)
++ * (jj at sunsite.ms.mff.cuni.cz)
+ *
+ * Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000
+ */
+@@ -36,6 +36,7 @@
+ #include <linux/writeback.h>
+ #include <linux/mpage.h>
+ #include <linux/uio.h>
++#include <linux/bio.h>
+ #include "xattr.h"
+ #include "acl.h"
+
+@@ -55,7 +56,7 @@ static int ext3_inode_is_fast_symlink(st
+ /*
+ * The ext3 forget function must perform a revoke if we are freeing data
+ * which has been journaled. Metadata (eg. indirect blocks) must be
+- * revoked in all cases.
++ * revoked in all cases.
+ *
+ * "bh" may be NULL: a metadata block may have been freed from memory
+ * but there may still be a record of it in the journal, and that record
+@@ -105,7 +106,7 @@ int ext3_forget(handle_t *handle, int is
+ * Work out how many blocks we need to proceed with the next chunk of a
+ * truncate transaction.
+ */
+-static unsigned long blocks_for_truncate(struct inode *inode)
++static unsigned long blocks_for_truncate(struct inode *inode)
+ {
+ unsigned long needed;
+
+@@ -122,13 +123,13 @@ static unsigned long blocks_for_truncate
+
+ /* But we need to bound the transaction so we don't overflow the
+ * journal. */
+- if (needed > EXT3_MAX_TRANS_DATA)
++ if (needed > EXT3_MAX_TRANS_DATA)
+ needed = EXT3_MAX_TRANS_DATA;
+
+ return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
+ }
+
+-/*
++/*
+ * Truncate transactions can be complex and absolutely huge. So we need to
+ * be able to restart the transaction at a conventient checkpoint to make
+ * sure we don't overflow the journal.
+@@ -136,9 +137,9 @@ static unsigned long blocks_for_truncate
+ * start_transaction gets us a new handle for a truncate transaction,
+ * and extend_transaction tries to extend the existing one a bit. If
+ * extend fails, we need to propagate the failure up and restart the
+- * transaction in the top-level truncate loop. --sct
++ * transaction in the top-level truncate loop. --sct
+ */
+-static handle_t *start_transaction(struct inode *inode)
++static handle_t *start_transaction(struct inode *inode)
+ {
+ handle_t *result;
+
+@@ -215,12 +216,12 @@ void ext3_delete_inode (struct inode * i
+ ext3_orphan_del(handle, inode);
+ EXT3_I(inode)->i_dtime = get_seconds();
+
+- /*
++ /*
+ * One subtle ordering requirement: if anything has gone wrong
+ * (transaction abort, IO errors, whatever), then we can still
+ * do these next steps (the fs will already have been marked as
+ * having errors), but we can't free the inode if the mark_dirty
+- * fails.
++ * fails.
+ */
+ if (ext3_mark_inode_dirty(handle, inode))
+ /* If that failed, just do the required in-core inode clear. */
+@@ -398,7 +399,7 @@ no_block:
+ * + if there is a block to the left of our position - allocate near it.
+ * + if pointer will live in indirect block - allocate near that block.
+ * + if pointer will live in inode - allocate in the same
+- * cylinder group.
++ * cylinder group.
+ *
+ * In the latter case we colour the starting block by the callers PID to
+ * prevent it from clashing with concurrent allocations for a different inode
+@@ -470,7 +471,7 @@ static ext3_fsblk_t ext3_find_goal(struc
+ * ext3_blks_to_allocate: Look up the block map and count the number
+ * of direct blocks need to be allocated for the given branch.
+ *
+- * @branch: chain of indirect blocks
++ * @branch: chain of indirect blocks
+ * @k: number of blocks need for indirect blocks
+ * @blks: number of data blocks to be mapped.
+ * @blocks_to_boundary: the offset in the indirect block
+@@ -744,7 +745,7 @@ static int ext3_splice_branch(handle_t *
+ jbd_debug(5, "splicing indirect only\n");
+ BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata");
+ err = ext3_journal_dirty_metadata(handle, where->bh);
+- if (err)
++ if (err)
+ goto err_out;
+ } else {
+ /*
+@@ -1073,7 +1074,7 @@ struct buffer_head *ext3_bread(handle_t
+ return bh;
+ if (buffer_uptodate(bh))
+ return bh;
+- ll_rw_block(READ, 1, &bh);
++ ll_rw_block(READ_META, 1, &bh);
+ wait_on_buffer(bh);
+ if (buffer_uptodate(bh))
+ return bh;
+@@ -1098,7 +1099,7 @@ static int walk_page_buffers( handle_t *
+
+ for ( bh = head, block_start = 0;
+ ret == 0 && (bh != head || !block_start);
+- block_start = block_end, bh = next)
++ block_start = block_end, bh = next)
+ {
+ next = bh->b_this_page;
+ block_end = block_start + blocksize;
+@@ -1137,7 +1138,7 @@ static int walk_page_buffers( handle_t *
+ * So what we do is to rely on the fact that journal_stop/journal_start
+ * will _not_ run commit under these circumstances because handle->h_ref
+ * is elevated. We'll still have enough credits for the tiny quotafile
+- * write.
++ * write.
+ */
+ static int do_journal_get_write_access(handle_t *handle,
+ struct buffer_head *bh)
+@@ -1282,7 +1283,7 @@ static int ext3_journalled_commit_write(
+ if (inode->i_size > EXT3_I(inode)->i_disksize) {
+ EXT3_I(inode)->i_disksize = inode->i_size;
+ ret2 = ext3_mark_inode_dirty(handle, inode);
+- if (!ret)
++ if (!ret)
+ ret = ret2;
+ }
+ ret2 = ext3_journal_stop(handle);
+@@ -1291,7 +1292,7 @@ static int ext3_journalled_commit_write(
+ return ret;
+ }
+
+-/*
++/*
+ * bmap() is special. It gets used by applications such as lilo and by
+ * the swapper to find the on-disk block of a specific piece of data.
+ *
+@@ -1300,10 +1301,10 @@ static int ext3_journalled_commit_write(
+ * filesystem and enables swap, then they may get a nasty shock when the
+ * data getting swapped to that swapfile suddenly gets overwritten by
+ * the original zero's written out previously to the journal and
+- * awaiting writeback in the kernel's buffer cache.
++ * awaiting writeback in the kernel's buffer cache.
+ *
+ * So, if we see any bmap calls here on a modified, data-journaled file,
+- * take extra steps to flush any blocks which might be in the cache.
++ * take extra steps to flush any blocks which might be in the cache.
+ */
+ static sector_t ext3_bmap(struct address_space *mapping, sector_t block)
+ {
+@@ -1312,16 +1313,16 @@ static sector_t ext3_bmap(struct address
+ int err;
+
+ if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) {
+- /*
++ /*
+ * This is a REALLY heavyweight approach, but the use of
+ * bmap on dirty files is expected to be extremely rare:
+ * only if we run lilo or swapon on a freshly made file
+- * do we expect this to happen.
++ * do we expect this to happen.
+ *
+ * (bmap requires CAP_SYS_RAWIO so this does not
+ * represent an unprivileged user DOS attack --- we'd be
+ * in trouble if mortal users could trigger this path at
+- * will.)
++ * will.)
+ *
+ * NB. EXT3_STATE_JDATA is not set on files other than
+ * regular files. If somebody wants to bmap a directory
+@@ -1457,7 +1458,7 @@ static int ext3_ordered_writepage(struct
+ */
+
+ /*
+- * And attach them to the current transaction. But only if
++ * And attach them to the current transaction. But only if
+ * block_write_full_page() succeeded. Otherwise they are unmapped,
+ * and generally junk.
+ */
+@@ -1644,7 +1645,7 @@ static ssize_t ext3_direct_IO(int rw, st
+ }
+ }
+
+- ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
++ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ offset, nr_segs,
+ ext3_get_block, NULL);
+
+@@ -2025,7 +2026,7 @@ static void ext3_free_data(handle_t *han
+ __le32 *first, __le32 *last)
+ {
+ ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */
+- unsigned long count = 0; /* Number of blocks in the run */
++ unsigned long count = 0; /* Number of blocks in the run */
+ __le32 *block_to_free_p = NULL; /* Pointer into inode/ind
+ corresponding to
+ block_to_free */
+@@ -2054,7 +2055,7 @@ static void ext3_free_data(handle_t *han
+ } else if (nr == block_to_free + count) {
+ count++;
+ } else {
+- ext3_clear_blocks(handle, inode, this_bh,
++ ext3_clear_blocks(handle, inode, this_bh,
+ block_to_free,
+ count, block_to_free_p, p);
+ block_to_free = nr;
+@@ -2115,7 +2116,7 @@ static void ext3_free_branches(handle_t
+ */
+ if (!bh) {
+ ext3_error(inode->i_sb, "ext3_free_branches",
+- "Read failure, inode=%ld, block="E3FSBLK,
++ "Read failure, inode=%lu, block="E3FSBLK,
+ inode->i_ino, nr);
+ continue;
+ }
+@@ -2184,7 +2185,7 @@ static void ext3_free_branches(handle_t
+ *p = 0;
+ BUFFER_TRACE(parent_bh,
+ "call ext3_journal_dirty_metadata");
+- ext3_journal_dirty_metadata(handle,
++ ext3_journal_dirty_metadata(handle,
+ parent_bh);
+ }
+ }
+@@ -2540,7 +2541,7 @@ make_io:
+ */
+ get_bh(bh);
+ bh->b_end_io = end_buffer_read_sync;
+- submit_bh(READ, bh);
++ submit_bh(READ_META, bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ ext3_error(inode->i_sb, "ext3_get_inode_loc",
+@@ -2632,9 +2633,6 @@ void ext3_read_inode(struct inode * inod
+ * recovery code: that's fine, we're about to complete
+ * the process of deleting those. */
+ }
+- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size
+- * (for stat), not the fs block
+- * size */
+ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
+ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
+ #ifdef EXT3_FRAGMENTS
+@@ -2704,7 +2702,7 @@ void ext3_read_inode(struct inode * inod
+ if (raw_inode->i_block[0])
+ init_special_inode(inode, inode->i_mode,
+ old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
+- else
++ else
+ init_special_inode(inode, inode->i_mode,
+ new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
+ }
+@@ -2724,8 +2722,8 @@ bad_inode:
+ *
+ * The caller must have write access to iloc->bh.
+ */
+-static int ext3_do_update_inode(handle_t *handle,
+- struct inode *inode,
++static int ext3_do_update_inode(handle_t *handle,
++ struct inode *inode,
+ struct ext3_iloc *iloc)
+ {
+ struct ext3_inode *raw_inode = ext3_raw_inode(iloc);
+@@ -2900,7 +2898,7 @@ int ext3_write_inode(struct inode *inode
+ * commit will leave the blocks being flushed in an unused state on
+ * disk. (On recovery, the inode will get truncated and the blocks will
+ * be freed, so we have a strong guarantee that no future commit will
+- * leave these blocks visible to the user.)
++ * leave these blocks visible to the user.)
+ *
+ * Called with inode->sem down.
+ */
+@@ -3043,13 +3041,13 @@ int ext3_mark_iloc_dirty(handle_t *handl
+ return err;
+ }
+
+-/*
++/*
+ * On success, We end up with an outstanding reference count against
+- * iloc->bh. This _must_ be cleaned up later.
++ * iloc->bh. This _must_ be cleaned up later.
+ */
+
+ int
+-ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
++ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
+ struct ext3_iloc *iloc)
+ {
+ int err = 0;
+@@ -3139,7 +3137,7 @@ out:
+ }
+
+ #if 0
+-/*
++/*
+ * Bind an inode's backing buffer_head into this transaction, to prevent
+ * it from being flushed to disk early. Unlike
+ * ext3_reserve_inode_write, this leaves behind no bh reference and
+@@ -3157,7 +3155,7 @@ static int ext3_pin_inode(handle_t *hand
+ BUFFER_TRACE(iloc.bh, "get_write_access");
+ err = journal_get_write_access(handle, iloc.bh);
+ if (!err)
+- err = ext3_journal_dirty_metadata(handle,
++ err = ext3_journal_dirty_metadata(handle,
+ iloc.bh);
+ brelse(iloc.bh);
+ }
+diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
+index 3a6b012..12daa68 100644
+--- a/fs/ext3/ioctl.c
++++ b/fs/ext3/ioctl.c
+@@ -13,9 +13,10 @@
+ #include <linux/ext3_fs.h>
+ #include <linux/ext3_jbd.h>
+ #include <linux/time.h>
++#include <linux/compat.h>
++#include <linux/smp_lock.h>
+ #include <asm/uaccess.h>
+
+-
+ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
+ unsigned long arg)
+ {
+@@ -252,3 +253,55 @@ flags_err:
+ return -ENOTTY;
+ }
+ }
++
++#ifdef CONFIG_COMPAT
++long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int ret;
++
++ /* These are just misnamed, they actually get/put from/to user an int */
++ switch (cmd) {
++ case EXT3_IOC32_GETFLAGS:
++ cmd = EXT3_IOC_GETFLAGS;
++ break;
++ case EXT3_IOC32_SETFLAGS:
++ cmd = EXT3_IOC_SETFLAGS;
++ break;
++ case EXT3_IOC32_GETVERSION:
++ cmd = EXT3_IOC_GETVERSION;
++ break;
++ case EXT3_IOC32_SETVERSION:
++ cmd = EXT3_IOC_SETVERSION;
++ break;
++ case EXT3_IOC32_GROUP_EXTEND:
++ cmd = EXT3_IOC_GROUP_EXTEND;
++ break;
++ case EXT3_IOC32_GETVERSION_OLD:
++ cmd = EXT3_IOC_GETVERSION_OLD;
++ break;
++ case EXT3_IOC32_SETVERSION_OLD:
++ cmd = EXT3_IOC_SETVERSION_OLD;
++ break;
++#ifdef CONFIG_JBD_DEBUG
++ case EXT3_IOC32_WAIT_FOR_READONLY:
++ cmd = EXT3_IOC_WAIT_FOR_READONLY;
++ break;
++#endif
++ case EXT3_IOC32_GETRSVSZ:
++ cmd = EXT3_IOC_GETRSVSZ;
++ break;
++ case EXT3_IOC32_SETRSVSZ:
++ cmd = EXT3_IOC_SETRSVSZ;
++ break;
++ case EXT3_IOC_GROUP_ADD:
++ break;
++ default:
++ return -ENOIOCTLCMD;
++ }
++ lock_kernel();
++ ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
++ unlock_kernel();
++ return ret;
++}
++#endif
+diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
+index 2aa7101..906731a 100644
+--- a/fs/ext3/namei.c
++++ b/fs/ext3/namei.c
+@@ -15,13 +15,13 @@
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem at caip.rutgers.edu), 1995
+ * Directory entry file type support and forward compatibility hooks
+- * for B-tree directories by Theodore Ts'o (tytso at mit.edu), 1998
++ * for B-tree directories by Theodore Ts'o (tytso at mit.edu), 1998
+ * Hash Tree Directory indexing (c)
+- * Daniel Phillips, 2001
++ * Daniel Phillips, 2001
+ * Hash Tree Directory indexing porting
+- * Christopher Li, 2002
++ * Christopher Li, 2002
+ * Hash Tree Directory indexing cleanup
+- * Theodore Ts'o, 2002
++ * Theodore Ts'o, 2002
+ */
+
+ #include <linux/fs.h>
+@@ -35,6 +35,7 @@
+ #include <linux/string.h>
+ #include <linux/quotaops.h>
+ #include <linux/buffer_head.h>
++#include <linux/bio.h>
+ #include <linux/smp_lock.h>
+
+ #include "namei.h"
+@@ -76,7 +77,7 @@ static struct buffer_head *ext3_append(h
+ #ifdef DX_DEBUG
+ #define dxtrace(command) command
+ #else
+-#define dxtrace(command)
++#define dxtrace(command)
+ #endif
+
+ struct fake_dirent
+@@ -169,7 +170,7 @@ static struct ext3_dir_entry_2* dx_pack_
+ static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
+ static int ext3_htree_next_block(struct inode *dir, __u32 hash,
+ struct dx_frame *frame,
+- struct dx_frame *frames,
++ struct dx_frame *frames,
+ __u32 *start_hash);
+ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
+ struct ext3_dir_entry_2 **res_dir, int *err);
+@@ -250,7 +251,7 @@ static void dx_show_index (char * label,
+ }
+
+ struct stats
+-{
++{
+ unsigned names;
+ unsigned space;
+ unsigned bcount;
+@@ -278,7 +279,7 @@ static struct stats dx_show_leaf(struct
+ ((char *) de - base));
+ }
+ space += EXT3_DIR_REC_LEN(de->name_len);
+- names++;
++ names++;
+ }
+ de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+@@ -464,7 +465,7 @@ static void dx_release (struct dx_frame
+ */
+ static int ext3_htree_next_block(struct inode *dir, __u32 hash,
+ struct dx_frame *frame,
+- struct dx_frame *frames,
++ struct dx_frame *frames,
+ __u32 *start_hash)
+ {
+ struct dx_frame *p;
+@@ -632,7 +633,7 @@ int ext3_htree_fill_tree(struct file *di
+ }
+ count += ret;
+ hashval = ~0;
+- ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS,
++ ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS,
+ frame, frames, &hashval);
+ *next_hash = hashval;
+ if (ret < 0) {
+@@ -649,7 +650,7 @@ int ext3_htree_fill_tree(struct file *di
+ break;
+ }
+ dx_release(frames);
+- dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
++ dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
+ count, *next_hash));
+ return count;
+ errout:
+@@ -870,7 +871,7 @@ restart:
+ bh = ext3_getblk(NULL, dir, b++, 0, &err);
+ bh_use[ra_max] = bh;
+ if (bh)
+- ll_rw_block(READ, 1, &bh);
++ ll_rw_block(READ_META, 1, &bh);
+ }
+ }
+ if ((bh = bh_use[ra_ptr++]) == NULL)
+@@ -1050,7 +1051,7 @@ struct dentry *ext3_get_parent(struct de
+ parent = ERR_PTR(-ENOMEM);
+ }
+ return parent;
+-}
++}
+
+ #define S_SHIFT 12
+ static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = {
+@@ -1198,7 +1199,7 @@ errout:
+ * add_dirent_to_buf will attempt search the directory block for
+ * space. It will return -ENOSPC if no space is available, and -EIO
+ * and -EEXIST if directory entry already exists.
+- *
++ *
+ * NOTE! bh is NOT released in the case where ENOSPC is returned. In
+ * all other cases bh is released.
+ */
+@@ -1572,7 +1573,7 @@ cleanup:
+ * ext3_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+-static int ext3_delete_entry (handle_t *handle,
++static int ext3_delete_entry (handle_t *handle,
+ struct inode * dir,
+ struct ext3_dir_entry_2 * de_del,
+ struct buffer_head * bh)
+@@ -1615,12 +1616,12 @@ static int ext3_delete_entry (handle_t *
+ */
+ static inline void ext3_inc_count(handle_t *handle, struct inode *inode)
+ {
+- inode->i_nlink++;
++ inc_nlink(inode);
+ }
+
+ static inline void ext3_dec_count(handle_t *handle, struct inode *inode)
+ {
+- inode->i_nlink--;
++ drop_nlink(inode);
+ }
+
+ static int ext3_add_nondir(handle_t *handle,
+@@ -1643,12 +1644,12 @@ static int ext3_add_nondir(handle_t *han
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+- * with d_instantiate().
++ * with d_instantiate().
+ */
+ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode,
+ struct nameidata *nd)
+ {
+- handle_t *handle;
++ handle_t *handle;
+ struct inode * inode;
+ int err, retries = 0;
+
+@@ -1688,7 +1689,7 @@ static int ext3_mknod (struct inode * di
+
+ retry:
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+@@ -1742,7 +1743,7 @@ retry:
+ inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+ dir_block = ext3_bread (handle, inode, 0, 1, &err);
+ if (!dir_block) {
+- inode->i_nlink--; /* is this nlink == 0? */
++ drop_nlink(inode); /* is this nlink == 0? */
+ ext3_mark_inode_dirty(handle, inode);
+ iput (inode);
+ goto out_stop;
+@@ -1774,7 +1775,7 @@ retry:
+ iput (inode);
+ goto out_stop;
+ }
+- dir->i_nlink++;
++ inc_nlink(dir);
+ ext3_update_dx_flag(dir);
+ ext3_mark_inode_dirty(handle, dir);
+ d_instantiate(dentry, inode);
+@@ -1813,10 +1814,10 @@ static int empty_dir (struct inode * ino
+ de1 = (struct ext3_dir_entry_2 *)
+ ((char *) de + le16_to_cpu(de->rec_len));
+ if (le32_to_cpu(de->inode) != inode->i_ino ||
+- !le32_to_cpu(de1->inode) ||
++ !le32_to_cpu(de1->inode) ||
+ strcmp (".", de->name) ||
+ strcmp ("..", de1->name)) {
+- ext3_warning (inode->i_sb, "empty_dir",
++ ext3_warning (inode->i_sb, "empty_dir",
+ "bad directory (dir #%lu) - no `.' or `..'",
+ inode->i_ino);
+ brelse (bh);
+@@ -1883,7 +1884,7 @@ int ext3_orphan_add(handle_t *handle, st
+ * being truncated, or files being unlinked. */
+
+ /* @@@ FIXME: Observation from aviro:
+- * I think I can trigger J_ASSERT in ext3_orphan_add(). We block
++ * I think I can trigger J_ASSERT in ext3_orphan_add(). We block
+ * here (on lock_super()), so race with ext3_link() which might bump
+ * ->i_nlink. For, say it, character device. Not a regular file,
+ * not a directory, not a symlink and ->i_nlink > 0.
+@@ -1919,8 +1920,8 @@ int ext3_orphan_add(handle_t *handle, st
+ if (!err)
+ list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
+
+- jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);
+- jbd_debug(4, "orphan inode %ld will point to %d\n",
++ jbd_debug(4, "superblock will point to %lu\n", inode->i_ino);
++ jbd_debug(4, "orphan inode %lu will point to %d\n",
+ inode->i_ino, NEXT_ORPHAN(inode));
+ out_unlock:
+ unlock_super(sb);
+@@ -2044,7 +2045,7 @@ static int ext3_rmdir (struct inode * di
+ "empty directory has nlink!=2 (%d)",
+ inode->i_nlink);
+ inode->i_version++;
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ /* There's no need to set i_disksize: the fact that i_nlink is
+ * zero will ensure that the right thing happens during any
+ * recovery. */
+@@ -2052,7 +2053,7 @@ static int ext3_rmdir (struct inode * di
+ ext3_orphan_add(handle, inode);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ ext3_mark_inode_dirty(handle, inode);
+- dir->i_nlink--;
++ drop_nlink(dir);
+ ext3_update_dx_flag(dir);
+ ext3_mark_inode_dirty(handle, dir);
+
+@@ -2103,7 +2104,7 @@ static int ext3_unlink(struct inode * di
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ ext3_update_dx_flag(dir);
+ ext3_mark_inode_dirty(handle, dir);
+- inode->i_nlink--;
++ drop_nlink(inode);
+ if (!inode->i_nlink)
+ ext3_orphan_add(handle, inode);
+ inode->i_ctime = dir->i_ctime;
+@@ -2129,7 +2130,7 @@ static int ext3_symlink (struct inode *
+
+ retry:
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
++ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
+ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+@@ -2227,7 +2228,7 @@ static int ext3_rename (struct inode * o
+ DQUOT_INIT(new_dentry->d_inode);
+ handle = ext3_journal_start(old_dir, 2 *
+ EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) +
+- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
++ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+@@ -2325,7 +2326,7 @@ static int ext3_rename (struct inode * o
+ }
+
+ if (new_inode) {
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+ }
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+@@ -2336,11 +2337,11 @@ static int ext3_rename (struct inode * o
+ PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
+ BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata");
+ ext3_journal_dirty_metadata(handle, dir_bh);
+- old_dir->i_nlink--;
++ drop_nlink(old_dir);
+ if (new_inode) {
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ } else {
+- new_dir->i_nlink++;
++ inc_nlink(new_dir);
+ ext3_update_dx_flag(new_dir);
+ ext3_mark_inode_dirty(handle, new_dir);
+ }
+@@ -2393,4 +2394,4 @@ struct inode_operations ext3_special_ino
+ .removexattr = generic_removexattr,
+ #endif
+ .permission = ext3_permission,
+-};
++};
+diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
+index 5e1337f..b73cba1 100644
+--- a/fs/ext3/resize.c
++++ b/fs/ext3/resize.c
+@@ -336,7 +336,7 @@ static int verify_reserved_gdb(struct su
+ unsigned five = 5;
+ unsigned seven = 7;
+ unsigned grp;
+- __u32 *p = (__u32 *)primary->b_data;
++ __le32 *p = (__le32 *)primary->b_data;
+ int gdbackups = 0;
+
+ while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
+@@ -380,7 +380,7 @@ static int add_new_gdb(handle_t *handle,
+ struct buffer_head *dind;
+ int gdbackups;
+ struct ext3_iloc iloc;
+- __u32 *data;
++ __le32 *data;
+ int err;
+
+ if (test_opt(sb, DEBUG))
+@@ -417,7 +417,7 @@ static int add_new_gdb(handle_t *handle,
+ goto exit_bh;
+ }
+
+- data = (__u32 *)dind->b_data;
++ data = (__le32 *)dind->b_data;
+ if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
+ ext3_warning(sb, __FUNCTION__,
+ "new group %u GDT block "E3FSBLK" not reserved",
+@@ -439,8 +439,8 @@ static int add_new_gdb(handle_t *handle,
+ if ((err = ext3_reserve_inode_write(handle, inode, &iloc)))
+ goto exit_dindj;
+
+- n_group_desc = (struct buffer_head **)kmalloc((gdb_num + 1) *
+- sizeof(struct buffer_head *), GFP_KERNEL);
++ n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
++ GFP_KERNEL);
+ if (!n_group_desc) {
+ err = -ENOMEM;
+ ext3_warning (sb, __FUNCTION__,
+@@ -519,7 +519,7 @@ static int reserve_backup_gdb(handle_t *
+ struct buffer_head *dind;
+ struct ext3_iloc iloc;
+ ext3_fsblk_t blk;
+- __u32 *data, *end;
++ __le32 *data, *end;
+ int gdbackups = 0;
+ int res, i;
+ int err;
+@@ -536,8 +536,8 @@ static int reserve_backup_gdb(handle_t *
+ }
+
+ blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count;
+- data = (__u32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count;
+- end = (__u32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb);
++ data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count;
++ end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb);
+
+ /* Get each reserved primary GDT block and verify it holds backups */
+ for (res = 0; res < reserved_gdb; res++, blk++) {
+@@ -545,7 +545,8 @@ static int reserve_backup_gdb(handle_t *
+ ext3_warning(sb, __FUNCTION__,
+ "reserved block "E3FSBLK
+ " not at offset %ld",
+- blk, (long)(data - (__u32 *)dind->b_data));
++ blk,
++ (long)(data - (__le32 *)dind->b_data));
+ err = -EINVAL;
+ goto exit_bh;
+ }
+@@ -560,7 +561,7 @@ static int reserve_backup_gdb(handle_t *
+ goto exit_bh;
+ }
+ if (++data >= end)
+- data = (__u32 *)dind->b_data;
++ data = (__le32 *)dind->b_data;
+ }
+
+ for (i = 0; i < reserved_gdb; i++) {
+@@ -584,7 +585,7 @@ static int reserve_backup_gdb(handle_t *
+ blk = input->group * EXT3_BLOCKS_PER_GROUP(sb);
+ for (i = 0; i < reserved_gdb; i++) {
+ int err2;
+- data = (__u32 *)primary[i]->b_data;
++ data = (__le32 *)primary[i]->b_data;
+ /* printk("reserving backup %lu[%u] = %lu\n",
+ primary[i]->b_blocknr, gdbackups,
+ blk + primary[i]->b_blocknr); */
+@@ -689,7 +690,7 @@ exit_err:
+ "can't update backup for group %d (err %d), "
+ "forcing fsck on next reboot", group, err);
+ sbi->s_mount_state &= ~EXT3_VALID_FS;
+- sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS);
++ sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS);
+ mark_buffer_dirty(sbi->s_sbh);
+ }
+ }
+@@ -730,6 +731,18 @@ int ext3_group_add(struct super_block *s
+ return -EPERM;
+ }
+
++ if (le32_to_cpu(es->s_blocks_count) + input->blocks_count <
++ le32_to_cpu(es->s_blocks_count)) {
++ ext3_warning(sb, __FUNCTION__, "blocks_count overflow\n");
++ return -EINVAL;
++ }
++
++ if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) <
++ le32_to_cpu(es->s_inodes_count)) {
++ ext3_warning(sb, __FUNCTION__, "inodes_count overflow\n");
++ return -EINVAL;
++ }
++
+ if (reserved_gdb || gdb_off == 0) {
+ if (!EXT3_HAS_COMPAT_FEATURE(sb,
+ EXT3_FEATURE_COMPAT_RESIZE_INODE)){
+@@ -958,6 +971,11 @@ int ext3_group_extend(struct super_block
+
+ add = EXT3_BLOCKS_PER_GROUP(sb) - last;
+
++ if (o_blocks_count + add < o_blocks_count) {
++ ext3_warning(sb, __FUNCTION__, "blocks_count overflow");
++ return -EINVAL;
++ }
++
+ if (o_blocks_count + add > n_blocks_count)
+ add = n_blocks_count - o_blocks_count;
+
+diff --git a/fs/ext3/super.c b/fs/ext3/super.c
+index 3559086..afc2d4f 100644
+--- a/fs/ext3/super.c
++++ b/fs/ext3/super.c
+@@ -45,7 +45,7 @@
+ static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
+ unsigned long journal_devnum);
+ static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
+- int);
++ unsigned int);
+ static void ext3_commit_super (struct super_block * sb,
+ struct ext3_super_block * es,
+ int sync);
+@@ -62,13 +62,13 @@ static void ext3_unlockfs(struct super_b
+ static void ext3_write_super (struct super_block * sb);
+ static void ext3_write_super_lockfs(struct super_block *sb);
+
+-/*
++/*
+ * Wrappers for journal_start/end.
+ *
+ * The only special thing we need to do here is to make sure that all
+ * journal_end calls result in the superblock being marked dirty, so
+ * that sync() will call the filesystem's write_super callback if
+- * appropriate.
++ * appropriate.
+ */
+ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
+ {
+@@ -90,11 +90,11 @@ handle_t *ext3_journal_start_sb(struct s
+ return journal_start(journal, nblocks);
+ }
+
+-/*
++/*
+ * The only special thing we need to do here is to make sure that all
+ * journal_stop calls result in the superblock being marked dirty, so
+ * that sync() will call the filesystem's write_super callback if
+- * appropriate.
++ * appropriate.
+ */
+ int __ext3_journal_stop(const char *where, handle_t *handle)
+ {
+@@ -159,20 +159,21 @@ static void ext3_handle_error(struct sup
+ if (sb->s_flags & MS_RDONLY)
+ return;
+
+- if (test_opt (sb, ERRORS_RO)) {
+- printk (KERN_CRIT "Remounting filesystem read-only\n");
+- sb->s_flags |= MS_RDONLY;
+- } else {
++ if (!test_opt (sb, ERRORS_CONT)) {
+ journal_t *journal = EXT3_SB(sb)->s_journal;
+
+ EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT;
+ if (journal)
+ journal_abort(journal, -EIO);
+ }
++ if (test_opt (sb, ERRORS_RO)) {
++ printk (KERN_CRIT "Remounting filesystem read-only\n");
++ sb->s_flags |= MS_RDONLY;
++ }
++ ext3_commit_super(sb, es, 1);
+ if (test_opt(sb, ERRORS_PANIC))
+ panic("EXT3-fs (device %s): panic forced after error\n",
+ sb->s_id);
+- ext3_commit_super(sb, es, 1);
+ }
+
+ void ext3_error (struct super_block * sb, const char * function,
+@@ -369,16 +370,16 @@ static void dump_orphan_list(struct supe
+ {
+ struct list_head *l;
+
+- printk(KERN_ERR "sb orphan head is %d\n",
++ printk(KERN_ERR "sb orphan head is %d\n",
+ le32_to_cpu(sbi->s_es->s_last_orphan));
+
+ printk(KERN_ERR "sb_info orphan list:\n");
+ list_for_each(l, &sbi->s_orphan) {
+ struct inode *inode = orphan_list_entry(l);
+ printk(KERN_ERR " "
+- "inode %s:%ld at %p: mode %o, nlink %d, next %d\n",
++ "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
+ inode->i_sb->s_id, inode->i_ino, inode,
+- inode->i_mode, inode->i_nlink,
++ inode->i_mode, inode->i_nlink,
+ NEXT_ORPHAN(inode));
+ }
+ }
+@@ -475,7 +476,7 @@ static void init_once(void * foo, kmem_c
+ inode_init_once(&ei->vfs_inode);
+ }
+ }
+-
++
+ static int init_inodecache(void)
+ {
+ ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
+@@ -490,8 +491,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(ext3_inode_cachep))
+- printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(ext3_inode_cachep);
+ }
+
+ static void ext3_clear_inode(struct inode *inode)
+@@ -733,8 +733,8 @@ static match_table_t tokens = {
+
+ static ext3_fsblk_t get_sb_block(void **data)
+ {
+- ext3_fsblk_t sb_block;
+- char *options = (char *) *data;
++ ext3_fsblk_t sb_block;
++ char *options = (char *) *data;
+
+ if (!options || strncmp(options, "sb=", 3) != 0)
+ return 1; /* Default location */
+@@ -753,7 +753,7 @@ static ext3_fsblk_t get_sb_block(void **
+ }
+
+ static int parse_options (char *options, struct super_block *sb,
+- unsigned long *inum, unsigned long *journal_devnum,
++ unsigned int *inum, unsigned long *journal_devnum,
+ ext3_fsblk_t *n_blocks_count, int is_remount)
+ {
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+@@ -1174,7 +1174,8 @@ static int ext3_setup_super(struct super
+ static int ext3_check_descriptors (struct super_block * sb)
+ {
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+- ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block);
++ ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
++ ext3_fsblk_t last_block;
+ struct ext3_group_desc * gdp = NULL;
+ int desc_block = 0;
+ int i;
+@@ -1183,12 +1184,17 @@ static int ext3_check_descriptors (struc
+
+ for (i = 0; i < sbi->s_groups_count; i++)
+ {
++ if (i == sbi->s_groups_count - 1)
++ last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
++ else
++ last_block = first_block +
++ (EXT3_BLOCKS_PER_GROUP(sb) - 1);
++
+ if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
+ gdp = (struct ext3_group_desc *)
+ sbi->s_group_desc[desc_block++]->b_data;
+- if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
+- le32_to_cpu(gdp->bg_block_bitmap) >=
+- block + EXT3_BLOCKS_PER_GROUP(sb))
++ if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
++ le32_to_cpu(gdp->bg_block_bitmap) > last_block)
+ {
+ ext3_error (sb, "ext3_check_descriptors",
+ "Block bitmap for group %d"
+@@ -1197,9 +1203,8 @@ static int ext3_check_descriptors (struc
+ le32_to_cpu(gdp->bg_block_bitmap));
+ return 0;
+ }
+- if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
+- le32_to_cpu(gdp->bg_inode_bitmap) >=
+- block + EXT3_BLOCKS_PER_GROUP(sb))
++ if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block ||
++ le32_to_cpu(gdp->bg_inode_bitmap) > last_block)
+ {
+ ext3_error (sb, "ext3_check_descriptors",
+ "Inode bitmap for group %d"
+@@ -1208,9 +1213,9 @@ static int ext3_check_descriptors (struc
+ le32_to_cpu(gdp->bg_inode_bitmap));
+ return 0;
+ }
+- if (le32_to_cpu(gdp->bg_inode_table) < block ||
+- le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >=
+- block + EXT3_BLOCKS_PER_GROUP(sb))
++ if (le32_to_cpu(gdp->bg_inode_table) < first_block ||
++ le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >
++ last_block)
+ {
+ ext3_error (sb, "ext3_check_descriptors",
+ "Inode table for group %d"
+@@ -1219,7 +1224,7 @@ static int ext3_check_descriptors (struc
+ le32_to_cpu(gdp->bg_inode_table));
+ return 0;
+ }
+- block += EXT3_BLOCKS_PER_GROUP(sb);
++ first_block += EXT3_BLOCKS_PER_GROUP(sb);
+ gdp++;
+ }
+
+@@ -1301,17 +1306,17 @@ static void ext3_orphan_cleanup (struct
+ DQUOT_INIT(inode);
+ if (inode->i_nlink) {
+ printk(KERN_DEBUG
+- "%s: truncating inode %ld to %Ld bytes\n",
++ "%s: truncating inode %lu to %Ld bytes\n",
+ __FUNCTION__, inode->i_ino, inode->i_size);
+- jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
++ jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
+ inode->i_ino, inode->i_size);
+ ext3_truncate(inode);
+ nr_truncates++;
+ } else {
+ printk(KERN_DEBUG
+- "%s: deleting unreferenced inode %ld\n",
++ "%s: deleting unreferenced inode %lu\n",
+ __FUNCTION__, inode->i_ino);
+- jbd_debug(2, "deleting unreferenced inode %ld\n",
++ jbd_debug(2, "deleting unreferenced inode %lu\n",
+ inode->i_ino);
+ nr_orphans++;
+ }
+@@ -1390,7 +1395,7 @@ static int ext3_fill_super (struct super
+ ext3_fsblk_t sb_block = get_sb_block(&data);
+ ext3_fsblk_t logic_sb_block;
+ unsigned long offset = 0;
+- unsigned long journal_inum = 0;
++ unsigned int journal_inum = 0;
+ unsigned long journal_devnum = 0;
+ unsigned long def_mount_opts;
+ struct inode *root;
+@@ -1401,11 +1406,10 @@ static int ext3_fill_super (struct super
+ int needs_recovery;
+ __le32 features;
+
+- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(*sbi));
+ sbi->s_mount_opt = 0;
+ sbi->s_resuid = EXT3_DEF_RESUID;
+ sbi->s_resgid = EXT3_DEF_RESGID;
+@@ -1466,6 +1470,8 @@ static int ext3_fill_super (struct super
+ set_opt(sbi->s_mount_opt, ERRORS_PANIC);
+ else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
+ set_opt(sbi->s_mount_opt, ERRORS_RO);
++ else
++ set_opt(sbi->s_mount_opt, ERRORS_CONT);
+
+ sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
+ sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+@@ -1483,7 +1489,7 @@ static int ext3_fill_super (struct super
+ (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
+ EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
+ EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U)))
+- printk(KERN_WARNING
++ printk(KERN_WARNING
+ "EXT3-fs warning: feature flags set on rev 0 fs, "
+ "running e2fsck is recommended\n");
+ /*
+@@ -1509,7 +1515,7 @@ static int ext3_fill_super (struct super
+
+ if (blocksize < EXT3_MIN_BLOCK_SIZE ||
+ blocksize > EXT3_MAX_BLOCK_SIZE) {
+- printk(KERN_ERR
++ printk(KERN_ERR
+ "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n",
+ blocksize, sb->s_id);
+ goto failed_mount;
+@@ -1533,14 +1539,14 @@ static int ext3_fill_super (struct super
+ offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
+ bh = sb_bread(sb, logic_sb_block);
+ if (!bh) {
+- printk(KERN_ERR
++ printk(KERN_ERR
+ "EXT3-fs: Can't read superblock on 2nd try.\n");
+ goto failed_mount;
+ }
+ es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
+ sbi->s_es = es;
+ if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) {
+- printk (KERN_ERR
++ printk (KERN_ERR
+ "EXT3-fs: Magic mismatch, very weird !\n");
+ goto failed_mount;
+ }
+@@ -1622,10 +1628,9 @@ static int ext3_fill_super (struct super
+
+ if (EXT3_BLOCKS_PER_GROUP(sb) == 0)
+ goto cantfind_ext3;
+- sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
+- le32_to_cpu(es->s_first_data_block) +
+- EXT3_BLOCKS_PER_GROUP(sb) - 1) /
+- EXT3_BLOCKS_PER_GROUP(sb);
++ sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
++ le32_to_cpu(es->s_first_data_block) - 1)
++ / EXT3_BLOCKS_PER_GROUP(sb)) + 1;
+ db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
+ EXT3_DESC_PER_BLOCK(sb);
+ sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
+@@ -1820,7 +1825,7 @@ out_fail:
+ /*
+ * Setup any per-fs journal parameters now. We'll do this both on
+ * initial mount, once the journal has been initialised but before we've
+- * done any recovery; and again on any subsequent remount.
++ * done any recovery; and again on any subsequent remount.
+ */
+ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
+ {
+@@ -1840,7 +1845,8 @@ static void ext3_init_journal_params(str
+ spin_unlock(&journal->j_state_lock);
+ }
+
+-static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
++static journal_t *ext3_get_journal(struct super_block *sb,
++ unsigned int journal_inum)
+ {
+ struct inode *journal_inode;
+ journal_t *journal;
+@@ -1975,7 +1981,7 @@ static int ext3_load_journal(struct supe
+ unsigned long journal_devnum)
+ {
+ journal_t *journal;
+- int journal_inum = le32_to_cpu(es->s_journal_inum);
++ unsigned int journal_inum = le32_to_cpu(es->s_journal_inum);
+ dev_t journal_dev;
+ int err = 0;
+ int really_read_only;
+@@ -2061,7 +2067,7 @@ static int ext3_load_journal(struct supe
+
+ static int ext3_create_journal(struct super_block * sb,
+ struct ext3_super_block * es,
+- int journal_inum)
++ unsigned int journal_inum)
+ {
+ journal_t *journal;
+
+@@ -2074,7 +2080,7 @@ static int ext3_create_journal(struct su
+ if (!(journal = ext3_get_journal(sb, journal_inum)))
+ return -EINVAL;
+
+- printk(KERN_INFO "EXT3-fs: creating new journal on inode %d\n",
++ printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n",
+ journal_inum);
+
+ if (journal_create(journal)) {
+@@ -2342,10 +2348,8 @@ static int ext3_remount (struct super_bl
+ */
+ 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))) {
+- err = ret;
++ if ((err = ext3_group_extend(sb, es, n_blocks_count)))
+ goto restore_opts;
+- }
+ if (!ext3_setup_super (sb, es, 0))
+ sb->s_flags &= ~MS_RDONLY;
+ }
+@@ -2734,7 +2738,7 @@ static int __init init_ext3_fs(void)
+ out:
+ destroy_inodecache();
+ out1:
+- exit_ext3_xattr();
++ exit_ext3_xattr();
+ return err;
+ }
+
+diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
+index a44a056..f86f248 100644
+--- a/fs/ext3/xattr.c
++++ b/fs/ext3/xattr.c
+@@ -75,7 +75,7 @@
+
+ #ifdef EXT3_XATTR_DEBUG
+ # define ea_idebug(inode, f...) do { \
+- printk(KERN_DEBUG "inode %s:%ld: ", \
++ printk(KERN_DEBUG "inode %s:%lu: ", \
+ inode->i_sb->s_id, inode->i_ino); \
+ printk(f); \
+ printk("\n"); \
+@@ -233,7 +233,7 @@ ext3_xattr_block_get(struct inode *inode
+ atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
+ if (ext3_xattr_check_block(bh)) {
+ bad_block: ext3_error(inode->i_sb, __FUNCTION__,
+- "inode %ld: bad block "E3FSBLK, inode->i_ino,
++ "inode %lu: bad block "E3FSBLK, inode->i_ino,
+ EXT3_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+@@ -375,7 +375,7 @@ ext3_xattr_block_list(struct inode *inod
+ atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
+ if (ext3_xattr_check_block(bh)) {
+ ext3_error(inode->i_sb, __FUNCTION__,
+- "inode %ld: bad block "E3FSBLK, inode->i_ino,
++ "inode %lu: bad block "E3FSBLK, inode->i_ino,
+ EXT3_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+@@ -647,7 +647,7 @@ ext3_xattr_block_find(struct inode *inod
+ le32_to_cpu(BHDR(bs->bh)->h_refcount));
+ if (ext3_xattr_check_block(bs->bh)) {
+ ext3_error(sb, __FUNCTION__,
+- "inode %ld: bad block "E3FSBLK, inode->i_ino,
++ "inode %lu: bad block "E3FSBLK, inode->i_ino,
+ EXT3_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+@@ -848,7 +848,7 @@ cleanup_dquot:
+
+ bad_block:
+ ext3_error(inode->i_sb, __FUNCTION__,
+- "inode %ld: bad block "E3FSBLK, inode->i_ino,
++ "inode %lu: bad block "E3FSBLK, inode->i_ino,
+ EXT3_I(inode)->i_file_acl);
+ goto cleanup;
+
+@@ -1077,14 +1077,14 @@ ext3_xattr_delete_inode(handle_t *handle
+ bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
+ if (!bh) {
+ ext3_error(inode->i_sb, __FUNCTION__,
+- "inode %ld: block "E3FSBLK" read error", inode->i_ino,
++ "inode %lu: block "E3FSBLK" read error", inode->i_ino,
+ EXT3_I(inode)->i_file_acl);
+ goto cleanup;
+ }
+ if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
+ BHDR(bh)->h_blocks != cpu_to_le32(1)) {
+ ext3_error(inode->i_sb, __FUNCTION__,
+- "inode %ld: bad block "E3FSBLK, inode->i_ino,
++ "inode %lu: bad block "E3FSBLK, inode->i_ino,
+ EXT3_I(inode)->i_file_acl);
+ goto cleanup;
+ }
+@@ -1211,7 +1211,7 @@ again:
+ bh = sb_bread(inode->i_sb, ce->e_block);
+ if (!bh) {
+ ext3_error(inode->i_sb, __FUNCTION__,
+- "inode %ld: block %lu read error",
++ "inode %lu: block %lu read error",
+ inode->i_ino, (unsigned long) ce->e_block);
+ } else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
+ EXT3_XATTR_REFCOUNT_MAX) {
+diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
+new file mode 100644
+index 0000000..a6acb96
+--- /dev/null
++++ b/fs/ext4/Makefile
+@@ -0,0 +1,12 @@
++#
++# Makefile for the linux ext4-filesystem routines.
++#
++
++obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o
++
++ext4dev-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
++ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o
++
++ext4dev-$(CONFIG_EXT4DEV_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
++ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o
++ext4dev-$(CONFIG_EXT4DEV_FS_SECURITY) += xattr_security.o
+diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
+new file mode 100644
+index 0000000..9e88254
+--- /dev/null
++++ b/fs/ext4/acl.c
+@@ -0,0 +1,551 @@
++/*
++ * linux/fs/ext4/acl.c
++ *
++ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen at suse.de>
++ */
++
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/capability.h>
++#include <linux/fs.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/ext4_fs.h>
++#include "xattr.h"
++#include "acl.h"
++
++/*
++ * Convert from filesystem to in-memory representation.
++ */
++static struct posix_acl *
++ext4_acl_from_disk(const void *value, size_t size)
++{
++ const char *end = (char *)value + size;
++ int n, count;
++ struct posix_acl *acl;
++
++ if (!value)
++ return NULL;
++ if (size < sizeof(ext4_acl_header))
++ return ERR_PTR(-EINVAL);
++ if (((ext4_acl_header *)value)->a_version !=
++ cpu_to_le32(EXT4_ACL_VERSION))
++ return ERR_PTR(-EINVAL);
++ value = (char *)value + sizeof(ext4_acl_header);
++ count = ext4_acl_count(size);
++ if (count < 0)
++ return ERR_PTR(-EINVAL);
++ if (count == 0)
++ return NULL;
++ acl = posix_acl_alloc(count, GFP_KERNEL);
++ if (!acl)
++ return ERR_PTR(-ENOMEM);
++ for (n=0; n < count; n++) {
++ ext4_acl_entry *entry =
++ (ext4_acl_entry *)value;
++ if ((char *)value + sizeof(ext4_acl_entry_short) > end)
++ goto fail;
++ 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(ext4_acl_entry_short);
++ acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
++ break;
++
++ case ACL_USER:
++ case ACL_GROUP:
++ value = (char *)value + sizeof(ext4_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:
++ posix_acl_release(acl);
++ return ERR_PTR(-EINVAL);
++}
++
++/*
++ * Convert from in-memory to filesystem representation.
++ */
++static void *
++ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
++{
++ ext4_acl_header *ext_acl;
++ char *e;
++ size_t n;
++
++ *size = ext4_acl_size(acl->a_count);
++ ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
++ sizeof(ext4_acl_entry), GFP_KERNEL);
++ if (!ext_acl)
++ return ERR_PTR(-ENOMEM);
++ ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
++ e = (char *)ext_acl + sizeof(ext4_acl_header);
++ for (n=0; n < acl->a_count; n++) {
++ ext4_acl_entry *entry = (ext4_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(ext4_acl_entry);
++ break;
++
++ case ACL_USER_OBJ:
++ case ACL_GROUP_OBJ:
++ case ACL_MASK:
++ case ACL_OTHER:
++ e += sizeof(ext4_acl_entry_short);
++ break;
++
++ default:
++ goto fail;
++ }
++ }
++ return (char *)ext_acl;
++
++fail:
++ kfree(ext_acl);
++ return ERR_PTR(-EINVAL);
++}
++
++static inline struct posix_acl *
++ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl)
++{
++ struct posix_acl *acl = EXT4_ACL_NOT_CACHED;
++
++ spin_lock(&inode->i_lock);
++ if (*i_acl != EXT4_ACL_NOT_CACHED)
++ acl = posix_acl_dup(*i_acl);
++ spin_unlock(&inode->i_lock);
++
++ return acl;
++}
++
++static inline void
++ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl,
++ struct posix_acl *acl)
++{
++ spin_lock(&inode->i_lock);
++ if (*i_acl != EXT4_ACL_NOT_CACHED)
++ posix_acl_release(*i_acl);
++ *i_acl = posix_acl_dup(acl);
++ spin_unlock(&inode->i_lock);
++}
++
++/*
++ * Inode operation get_posix_acl().
++ *
++ * inode->i_mutex: don't care
++ */
++static struct posix_acl *
++ext4_get_acl(struct inode *inode, int type)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ int name_index;
++ char *value = NULL;
++ struct posix_acl *acl;
++ int retval;
++
++ if (!test_opt(inode->i_sb, POSIX_ACL))
++ return NULL;
++
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ acl = ext4_iget_acl(inode, &ei->i_acl);
++ if (acl != EXT4_ACL_NOT_CACHED)
++ return acl;
++ name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ acl = ext4_iget_acl(inode, &ei->i_default_acl);
++ if (acl != EXT4_ACL_NOT_CACHED)
++ return acl;
++ name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
++ break;
++
++ default:
++ return ERR_PTR(-EINVAL);
++ }
++ retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
++ if (retval > 0) {
++ value = kmalloc(retval, GFP_KERNEL);
++ if (!value)
++ return ERR_PTR(-ENOMEM);
++ retval = ext4_xattr_get(inode, name_index, "", value, retval);
++ }
++ if (retval > 0)
++ acl = ext4_acl_from_disk(value, retval);
++ else if (retval == -ENODATA || retval == -ENOSYS)
++ acl = NULL;
++ else
++ acl = ERR_PTR(retval);
++ kfree(value);
++
++ if (!IS_ERR(acl)) {
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ ext4_iset_acl(inode, &ei->i_acl, acl);
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ ext4_iset_acl(inode, &ei->i_default_acl, acl);
++ break;
++ }
++ }
++ return acl;
++}
++
++/*
++ * Set the access or default ACL of an inode.
++ *
++ * inode->i_mutex: down unless called from ext4_new_inode
++ */
++static int
++ext4_set_acl(handle_t *handle, struct inode *inode, int type,
++ struct posix_acl *acl)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ int name_index;
++ void *value = NULL;
++ size_t size = 0;
++ int error;
++
++ if (S_ISLNK(inode->i_mode))
++ return -EOPNOTSUPP;
++
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ name_index = EXT4_XATTR_INDEX_POSIX_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;
++ ext4_mark_inode_dirty(handle, inode);
++ if (error == 0)
++ acl = NULL;
++ }
++ }
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
++ if (!S_ISDIR(inode->i_mode))
++ return acl ? -EACCES : 0;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ if (acl) {
++ value = ext4_acl_to_disk(acl, &size);
++ if (IS_ERR(value))
++ return (int)PTR_ERR(value);
++ }
++
++ error = ext4_xattr_set_handle(handle, inode, name_index, "",
++ value, size, 0);
++
++ kfree(value);
++ if (!error) {
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ ext4_iset_acl(inode, &ei->i_acl, acl);
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ ext4_iset_acl(inode, &ei->i_default_acl, acl);
++ break;
++ }
++ }
++ return error;
++}
++
++static int
++ext4_check_acl(struct inode *inode, int mask)
++{
++ struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
++
++ if (IS_ERR(acl))
++ return PTR_ERR(acl);
++ if (acl) {
++ int error = posix_acl_permission(inode, acl, mask);
++ posix_acl_release(acl);
++ return error;
++ }
++
++ return -EAGAIN;
++}
++
++int
++ext4_permission(struct inode *inode, int mask, struct nameidata *nd)
++{
++ return generic_permission(inode, mask, ext4_check_acl);
++}
++
++/*
++ * Initialize the ACLs of a new inode. Called from ext4_new_inode.
++ *
++ * dir->i_mutex: down
++ * inode->i_mutex: up (access to inode is still exclusive)
++ */
++int
++ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
++{
++ struct posix_acl *acl = NULL;
++ int error = 0;
++
++ if (!S_ISLNK(inode->i_mode)) {
++ if (test_opt(dir->i_sb, POSIX_ACL)) {
++ acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT);
++ if (IS_ERR(acl))
++ return PTR_ERR(acl);
++ }
++ if (!acl)
++ inode->i_mode &= ~current->fs->umask;
++ }
++ if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
++ struct posix_acl *clone;
++ mode_t mode;
++
++ if (S_ISDIR(inode->i_mode)) {
++ error = ext4_set_acl(handle, inode,
++ ACL_TYPE_DEFAULT, acl);
++ if (error)
++ goto cleanup;
++ }
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ error = -ENOMEM;
++ if (!clone)
++ goto cleanup;
++
++ mode = inode->i_mode;
++ error = posix_acl_create_masq(clone, &mode);
++ if (error >= 0) {
++ inode->i_mode = mode;
++ if (error > 0) {
++ /* This is an extended ACL */
++ error = ext4_set_acl(handle, inode,
++ ACL_TYPE_ACCESS, clone);
++ }
++ }
++ posix_acl_release(clone);
++ }
++cleanup:
++ posix_acl_release(acl);
++ return error;
++}
++
++/*
++ * Does chmod for an inode that may have an Access Control List. The
++ * inode->i_mode field must be updated to the desired value by the caller
++ * before calling this function.
++ * Returns 0 on success, or a negative error number.
++ *
++ * We change the ACL rather than storing some ACL entries in the file
++ * mode permission bits (which would be more efficient), because that
++ * would break once additional permissions (like ACL_APPEND, ACL_DELETE
++ * for directories) are added. There are no more bits available in the
++ * file mode.
++ *
++ * inode->i_mutex: down
++ */
++int
++ext4_acl_chmod(struct inode *inode)
++{
++ struct posix_acl *acl, *clone;
++ int error;
++
++ if (S_ISLNK(inode->i_mode))
++ return -EOPNOTSUPP;
++ if (!test_opt(inode->i_sb, POSIX_ACL))
++ return 0;
++ acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
++ if (IS_ERR(acl) || !acl)
++ return PTR_ERR(acl);
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ posix_acl_release(acl);
++ if (!clone)
++ return -ENOMEM;
++ error = posix_acl_chmod_masq(clone, inode->i_mode);
++ if (!error) {
++ handle_t *handle;
++ int retries = 0;
++
++ retry:
++ handle = ext4_journal_start(inode,
++ EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
++ if (IS_ERR(handle)) {
++ error = PTR_ERR(handle);
++ ext4_std_error(inode->i_sb, error);
++ goto out;
++ }
++ error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
++ ext4_journal_stop(handle);
++ if (error == -ENOSPC &&
++ ext4_should_retry_alloc(inode->i_sb, &retries))
++ goto retry;
++ }
++out:
++ posix_acl_release(clone);
++ return error;
++}
++
++/*
++ * Extended attribute handlers
++ */
++static size_t
++ext4_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
++ const char *name, size_t name_len)
++{
++ const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
++
++ if (!test_opt(inode->i_sb, POSIX_ACL))
++ return 0;
++ if (list && size <= list_len)
++ memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
++ return size;
++}
++
++static size_t
++ext4_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
++ const char *name, size_t name_len)
++{
++ const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
++
++ if (!test_opt(inode->i_sb, POSIX_ACL))
++ return 0;
++ if (list && size <= list_len)
++ memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
++ return size;
++}
++
++static int
++ext4_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
++{
++ struct posix_acl *acl;
++ int error;
++
++ if (!test_opt(inode->i_sb, POSIX_ACL))
++ return -EOPNOTSUPP;
++
++ acl = ext4_get_acl(inode, type);
++ if (IS_ERR(acl))
++ return PTR_ERR(acl);
++ if (acl == NULL)
++ return -ENODATA;
++ error = posix_acl_to_xattr(acl, buffer, size);
++ posix_acl_release(acl);
++
++ return error;
++}
++
++static int
++ext4_xattr_get_acl_access(struct inode *inode, const char *name,
++ void *buffer, size_t size)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return ext4_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
++}
++
++static int
++ext4_xattr_get_acl_default(struct inode *inode, const char *name,
++ void *buffer, size_t size)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return ext4_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
++}
++
++static int
++ext4_xattr_set_acl(struct inode *inode, int type, const void *value,
++ size_t size)
++{
++ handle_t *handle;
++ struct posix_acl *acl;
++ int error, retries = 0;
++
++ if (!test_opt(inode->i_sb, POSIX_ACL))
++ return -EOPNOTSUPP;
++ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
++ return -EPERM;
++
++ if (value) {
++ acl = posix_acl_from_xattr(value, size);
++ if (IS_ERR(acl))
++ return PTR_ERR(acl);
++ else if (acl) {
++ error = posix_acl_valid(acl);
++ if (error)
++ goto release_and_out;
++ }
++ } else
++ acl = NULL;
++
++retry:
++ handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ error = ext4_set_acl(handle, inode, type, acl);
++ ext4_journal_stop(handle);
++ if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
++ goto retry;
++
++release_and_out:
++ posix_acl_release(acl);
++ return error;
++}
++
++static int
++ext4_xattr_set_acl_access(struct inode *inode, const char *name,
++ const void *value, size_t size, int flags)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return ext4_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
++}
++
++static int
++ext4_xattr_set_acl_default(struct inode *inode, const char *name,
++ const void *value, size_t size, int flags)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return ext4_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
++}
++
++struct xattr_handler ext4_xattr_acl_access_handler = {
++ .prefix = POSIX_ACL_XATTR_ACCESS,
++ .list = ext4_xattr_list_acl_access,
++ .get = ext4_xattr_get_acl_access,
++ .set = ext4_xattr_set_acl_access,
++};
++
++struct xattr_handler ext4_xattr_acl_default_handler = {
++ .prefix = POSIX_ACL_XATTR_DEFAULT,
++ .list = ext4_xattr_list_acl_default,
++ .get = ext4_xattr_get_acl_default,
++ .set = ext4_xattr_set_acl_default,
++};
+diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h
+new file mode 100644
+index 0000000..26a5c1a
+--- /dev/null
++++ b/fs/ext4/acl.h
+@@ -0,0 +1,81 @@
++/*
++ File: fs/ext4/acl.h
++
++ (C) 2001 Andreas Gruenbacher, <a.gruenbacher at computer.org>
++*/
++
++#include <linux/posix_acl_xattr.h>
++
++#define EXT4_ACL_VERSION 0x0001
++
++typedef struct {
++ __le16 e_tag;
++ __le16 e_perm;
++ __le32 e_id;
++} ext4_acl_entry;
++
++typedef struct {
++ __le16 e_tag;
++ __le16 e_perm;
++} ext4_acl_entry_short;
++
++typedef struct {
++ __le32 a_version;
++} ext4_acl_header;
++
++static inline size_t ext4_acl_size(int count)
++{
++ if (count <= 4) {
++ return sizeof(ext4_acl_header) +
++ count * sizeof(ext4_acl_entry_short);
++ } else {
++ return sizeof(ext4_acl_header) +
++ 4 * sizeof(ext4_acl_entry_short) +
++ (count - 4) * sizeof(ext4_acl_entry);
++ }
++}
++
++static inline int ext4_acl_count(size_t size)
++{
++ ssize_t s;
++ size -= sizeof(ext4_acl_header);
++ s = size - 4 * sizeof(ext4_acl_entry_short);
++ if (s < 0) {
++ if (size % sizeof(ext4_acl_entry_short))
++ return -1;
++ return size / sizeof(ext4_acl_entry_short);
++ } else {
++ if (s % sizeof(ext4_acl_entry))
++ return -1;
++ return s / sizeof(ext4_acl_entry) + 4;
++ }
++}
++
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++
++/* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl
++ if the ACL has not been cached */
++#define EXT4_ACL_NOT_CACHED ((void *)-1)
++
++/* acl.c */
++extern int ext4_permission (struct inode *, int, struct nameidata *);
++extern int ext4_acl_chmod (struct inode *);
++extern int ext4_init_acl (handle_t *, struct inode *, struct inode *);
++
++#else /* CONFIG_EXT4DEV_FS_POSIX_ACL */
++#include <linux/sched.h>
++#define ext4_permission NULL
++
++static inline int
++ext4_acl_chmod(struct inode *inode)
++{
++ return 0;
++}
++
++static inline int
++ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
++{
++ return 0;
++}
++#endif /* CONFIG_EXT4DEV_FS_POSIX_ACL */
++
+diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
+new file mode 100644
+index 0000000..5d45582
+--- /dev/null
++++ b/fs/ext4/balloc.c
+@@ -0,0 +1,1833 @@
++/*
++ * linux/fs/ext4/balloc.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * Enhanced block allocation by Stephen Tweedie (sct at redhat.com), 1993
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ */
++
++#include <linux/time.h>
++#include <linux/capability.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/quotaops.h>
++#include <linux/buffer_head.h>
++
++/*
++ * balloc.c contains the blocks allocation and deallocation routines
++ */
++
++/*
++ * Calculate the block group number and offset, given a block number
++ */
++void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
++ unsigned long *blockgrpp, ext4_grpblk_t *offsetp)
++{
++ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
++ ext4_grpblk_t offset;
++
++ blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
++ offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
++ if (offsetp)
++ *offsetp = offset;
++ if (blockgrpp)
++ *blockgrpp = blocknr;
++
++}
++
++/*
++ * The free blocks are managed by bitmaps. A file system contains several
++ * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
++ * block for inodes, N blocks for the inode table and data blocks.
++ *
++ * The file system contains group descriptors which are located after the
++ * super block. Each descriptor contains the number of the bitmap block and
++ * the free blocks count in the block. The descriptors are loaded in memory
++ * when a file system is mounted (see ext4_read_super).
++ */
++
++
++#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
++
++/**
++ * ext4_get_group_desc() -- load group descriptor from disk
++ * @sb: super block
++ * @block_group: given block group
++ * @bh: pointer to the buffer head to store the block
++ * group descriptor
++ */
++struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
++ unsigned int block_group,
++ struct buffer_head ** bh)
++{
++ unsigned long group_desc;
++ unsigned long offset;
++ struct ext4_group_desc * desc;
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++
++ if (block_group >= sbi->s_groups_count) {
++ ext4_error (sb, "ext4_get_group_desc",
++ "block_group >= groups_count - "
++ "block_group = %d, groups_count = %lu",
++ block_group, sbi->s_groups_count);
++
++ return NULL;
++ }
++ smp_rmb();
++
++ group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
++ offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
++ if (!sbi->s_group_desc[group_desc]) {
++ ext4_error (sb, "ext4_get_group_desc",
++ "Group descriptor not loaded - "
++ "block_group = %d, group_desc = %lu, desc = %lu",
++ block_group, group_desc, offset);
++ return NULL;
++ }
++
++ desc = (struct ext4_group_desc *)(
++ (__u8 *)sbi->s_group_desc[group_desc]->b_data +
++ offset * EXT4_DESC_SIZE(sb));
++ if (bh)
++ *bh = sbi->s_group_desc[group_desc];
++ return desc;
++}
++
++/**
++ * read_block_bitmap()
++ * @sb: super block
++ * @block_group: given block group
++ *
++ * Read the bitmap for a given block_group, reading into the specified
++ * slot in the superblock's bitmap cache.
++ *
++ * Return buffer_head on success or NULL in case of failure.
++ */
++static struct buffer_head *
++read_block_bitmap(struct super_block *sb, unsigned int block_group)
++{
++ struct ext4_group_desc * desc;
++ struct buffer_head * bh = NULL;
++
++ desc = ext4_get_group_desc (sb, block_group, NULL);
++ if (!desc)
++ goto error_out;
++ bh = sb_bread(sb, ext4_block_bitmap(sb, desc));
++ if (!bh)
++ ext4_error (sb, "read_block_bitmap",
++ "Cannot read block bitmap - "
++ "block_group = %d, block_bitmap = %llu",
++ block_group,
++ ext4_block_bitmap(sb, desc));
++error_out:
++ return bh;
++}
++/*
++ * The reservation window structure operations
++ * --------------------------------------------
++ * Operations include:
++ * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
++ *
++ * We use a red-black tree to represent per-filesystem reservation
++ * windows.
++ *
++ */
++
++/**
++ * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
++ * @rb_root: root of per-filesystem reservation rb tree
++ * @verbose: verbose mode
++ * @fn: function which wishes to dump the reservation map
++ *
++ * If verbose is turned on, it will print the whole block reservation
++ * windows(start, end). Otherwise, it will only print out the "bad" windows,
++ * those windows that overlap with their immediate neighbors.
++ */
++#if 1
++static void __rsv_window_dump(struct rb_root *root, int verbose,
++ const char *fn)
++{
++ struct rb_node *n;
++ struct ext4_reserve_window_node *rsv, *prev;
++ int bad;
++
++restart:
++ n = rb_first(root);
++ bad = 0;
++ prev = NULL;
++
++ printk("Block Allocation Reservation Windows Map (%s):\n", fn);
++ while (n) {
++ rsv = list_entry(n, struct ext4_reserve_window_node, rsv_node);
++ if (verbose)
++ printk("reservation window 0x%p "
++ "start: %llu, end: %llu\n",
++ rsv, rsv->rsv_start, rsv->rsv_end);
++ if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
++ printk("Bad reservation %p (start >= end)\n",
++ rsv);
++ bad = 1;
++ }
++ if (prev && prev->rsv_end >= rsv->rsv_start) {
++ printk("Bad reservation %p (prev->end >= start)\n",
++ rsv);
++ bad = 1;
++ }
++ if (bad) {
++ if (!verbose) {
++ printk("Restarting reservation walk in verbose mode\n");
++ verbose = 1;
++ goto restart;
++ }
++ }
++ n = rb_next(n);
++ prev = rsv;
++ }
++ printk("Window map complete.\n");
++ if (bad)
++ BUG();
++}
++#define rsv_window_dump(root, verbose) \
++ __rsv_window_dump((root), (verbose), __FUNCTION__)
++#else
++#define rsv_window_dump(root, verbose) do {} while (0)
++#endif
++
++/**
++ * goal_in_my_reservation()
++ * @rsv: inode's reservation window
++ * @grp_goal: given goal block relative to the allocation block group
++ * @group: the current allocation block group
++ * @sb: filesystem super block
++ *
++ * Test if the given goal block (group relative) is within the file's
++ * own block reservation window range.
++ *
++ * If the reservation window is outside the goal allocation group, return 0;
++ * grp_goal (given goal block) could be -1, which means no specific
++ * goal block. In this case, always return 1.
++ * If the goal block is within the reservation window, return 1;
++ * otherwise, return 0;
++ */
++static int
++goal_in_my_reservation(struct ext4_reserve_window *rsv, ext4_grpblk_t grp_goal,
++ unsigned int group, struct super_block * sb)
++{
++ ext4_fsblk_t group_first_block, group_last_block;
++
++ group_first_block = ext4_group_first_block_no(sb, group);
++ group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
++
++ if ((rsv->_rsv_start > group_last_block) ||
++ (rsv->_rsv_end < group_first_block))
++ return 0;
++ if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
++ || (grp_goal + group_first_block > rsv->_rsv_end)))
++ return 0;
++ return 1;
++}
++
++/**
++ * search_reserve_window()
++ * @rb_root: root of reservation tree
++ * @goal: target allocation block
++ *
++ * Find the reserved window which includes the goal, or the previous one
++ * if the goal is not in any window.
++ * Returns NULL if there are no windows or if all windows start after the goal.
++ */
++static struct ext4_reserve_window_node *
++search_reserve_window(struct rb_root *root, ext4_fsblk_t goal)
++{
++ struct rb_node *n = root->rb_node;
++ struct ext4_reserve_window_node *rsv;
++
++ if (!n)
++ return NULL;
++
++ do {
++ rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
++
++ if (goal < rsv->rsv_start)
++ n = n->rb_left;
++ else if (goal > rsv->rsv_end)
++ n = n->rb_right;
++ else
++ return rsv;
++ } while (n);
++ /*
++ * We've fallen off the end of the tree: the goal wasn't inside
++ * any particular node. OK, the previous node must be to one
++ * side of the interval containing the goal. If it's the RHS,
++ * we need to back up one.
++ */
++ if (rsv->rsv_start > goal) {
++ n = rb_prev(&rsv->rsv_node);
++ rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
++ }
++ return rsv;
++}
++
++/**
++ * ext4_rsv_window_add() -- Insert a window to the block reservation rb tree.
++ * @sb: super block
++ * @rsv: reservation window to add
++ *
++ * Must be called with rsv_lock hold.
++ */
++void ext4_rsv_window_add(struct super_block *sb,
++ struct ext4_reserve_window_node *rsv)
++{
++ struct rb_root *root = &EXT4_SB(sb)->s_rsv_window_root;
++ struct rb_node *node = &rsv->rsv_node;
++ ext4_fsblk_t start = rsv->rsv_start;
++
++ struct rb_node ** p = &root->rb_node;
++ struct rb_node * parent = NULL;
++ struct ext4_reserve_window_node *this;
++
++ while (*p)
++ {
++ parent = *p;
++ this = rb_entry(parent, struct ext4_reserve_window_node, rsv_node);
++
++ if (start < this->rsv_start)
++ p = &(*p)->rb_left;
++ else if (start > this->rsv_end)
++ p = &(*p)->rb_right;
++ else {
++ rsv_window_dump(root, 1);
++ BUG();
++ }
++ }
++
++ rb_link_node(node, parent, p);
++ rb_insert_color(node, root);
++}
++
++/**
++ * ext4_rsv_window_remove() -- unlink a window from the reservation rb tree
++ * @sb: super block
++ * @rsv: reservation window to remove
++ *
++ * Mark the block reservation window as not allocated, and unlink it
++ * from the filesystem reservation window rb tree. Must be called with
++ * rsv_lock hold.
++ */
++static void rsv_window_remove(struct super_block *sb,
++ struct ext4_reserve_window_node *rsv)
++{
++ rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++ rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++ rsv->rsv_alloc_hit = 0;
++ rb_erase(&rsv->rsv_node, &EXT4_SB(sb)->s_rsv_window_root);
++}
++
++/*
++ * rsv_is_empty() -- Check if the reservation window is allocated.
++ * @rsv: given reservation window to check
++ *
++ * returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED.
++ */
++static inline int rsv_is_empty(struct ext4_reserve_window *rsv)
++{
++ /* a valid reservation end block could not be 0 */
++ return rsv->_rsv_end == EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++}
++
++/**
++ * ext4_init_block_alloc_info()
++ * @inode: file inode structure
++ *
++ * Allocate and initialize the reservation window structure, and
++ * link the window to the ext4 inode structure at last
++ *
++ * The reservation window structure is only dynamically allocated
++ * and linked to ext4 inode the first time the open file
++ * needs a new block. So, before every ext4_new_block(s) call, for
++ * regular files, we should check whether the reservation window
++ * structure exists or not. In the latter case, this function is called.
++ * Fail to do so will result in block reservation being turned off for that
++ * open file.
++ *
++ * This function is called from ext4_get_blocks_handle(), also called
++ * when setting the reservation window size through ioctl before the file
++ * is open for write (needs block allocation).
++ *
++ * Needs truncate_mutex protection prior to call this function.
++ */
++void ext4_init_block_alloc_info(struct inode *inode)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
++ struct super_block *sb = inode->i_sb;
++
++ block_i = kmalloc(sizeof(*block_i), GFP_NOFS);
++ if (block_i) {
++ struct ext4_reserve_window_node *rsv = &block_i->rsv_window_node;
++
++ rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++ rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++
++ /*
++ * if filesystem is mounted with NORESERVATION, the goal
++ * reservation window size is set to zero to indicate
++ * block reservation is off
++ */
++ if (!test_opt(sb, RESERVATION))
++ rsv->rsv_goal_size = 0;
++ else
++ rsv->rsv_goal_size = EXT4_DEFAULT_RESERVE_BLOCKS;
++ rsv->rsv_alloc_hit = 0;
++ block_i->last_alloc_logical_block = 0;
++ block_i->last_alloc_physical_block = 0;
++ }
++ ei->i_block_alloc_info = block_i;
++}
++
++/**
++ * ext4_discard_reservation()
++ * @inode: inode
++ *
++ * Discard(free) block reservation window on last file close, or truncate
++ * or at last iput().
++ *
++ * It is being called in three cases:
++ * ext4_release_file(): last writer close the file
++ * ext4_clear_inode(): last iput(), when nobody link to this file.
++ * ext4_truncate(): when the block indirect map is about to change.
++ *
++ */
++void ext4_discard_reservation(struct inode *inode)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
++ struct ext4_reserve_window_node *rsv;
++ spinlock_t *rsv_lock = &EXT4_SB(inode->i_sb)->s_rsv_window_lock;
++
++ if (!block_i)
++ return;
++
++ rsv = &block_i->rsv_window_node;
++ if (!rsv_is_empty(&rsv->rsv_window)) {
++ spin_lock(rsv_lock);
++ if (!rsv_is_empty(&rsv->rsv_window))
++ rsv_window_remove(inode->i_sb, rsv);
++ spin_unlock(rsv_lock);
++ }
++}
++
++/**
++ * ext4_free_blocks_sb() -- Free given blocks and update quota
++ * @handle: handle to this transaction
++ * @sb: super block
++ * @block: start physcial block to free
++ * @count: number of blocks to free
++ * @pdquot_freed_blocks: pointer to quota
++ */
++void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
++ ext4_fsblk_t block, unsigned long count,
++ unsigned long *pdquot_freed_blocks)
++{
++ struct buffer_head *bitmap_bh = NULL;
++ struct buffer_head *gd_bh;
++ unsigned long block_group;
++ ext4_grpblk_t bit;
++ unsigned long i;
++ unsigned long overflow;
++ struct ext4_group_desc * desc;
++ struct ext4_super_block * es;
++ struct ext4_sb_info *sbi;
++ int err = 0, ret;
++ ext4_grpblk_t group_freed;
++
++ *pdquot_freed_blocks = 0;
++ sbi = EXT4_SB(sb);
++ es = sbi->s_es;
++ if (block < le32_to_cpu(es->s_first_data_block) ||
++ block + count < block ||
++ block + count > ext4_blocks_count(es)) {
++ ext4_error (sb, "ext4_free_blocks",
++ "Freeing blocks not in datazone - "
++ "block = %llu, count = %lu", block, count);
++ goto error_return;
++ }
++
++ ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1);
++
++do_more:
++ overflow = 0;
++ ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
++ /*
++ * Check to see if we are freeing blocks across a group
++ * boundary.
++ */
++ if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) {
++ overflow = bit + count - EXT4_BLOCKS_PER_GROUP(sb);
++ count -= overflow;
++ }
++ brelse(bitmap_bh);
++ bitmap_bh = read_block_bitmap(sb, block_group);
++ if (!bitmap_bh)
++ goto error_return;
++ desc = ext4_get_group_desc (sb, block_group, &gd_bh);
++ if (!desc)
++ goto error_return;
++
++ if (in_range(ext4_block_bitmap(sb, desc), block, count) ||
++ in_range(ext4_inode_bitmap(sb, desc), block, count) ||
++ in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
++ in_range(block + count - 1, ext4_inode_table(sb, desc),
++ sbi->s_itb_per_group))
++ ext4_error (sb, "ext4_free_blocks",
++ "Freeing blocks in system zones - "
++ "Block = %llu, count = %lu",
++ block, count);
++
++ /*
++ * We are about to start releasing blocks in the bitmap,
++ * so we need undo access.
++ */
++ /* @@@ check errors */
++ BUFFER_TRACE(bitmap_bh, "getting undo access");
++ err = ext4_journal_get_undo_access(handle, bitmap_bh);
++ if (err)
++ goto error_return;
++
++ /*
++ * We are about to modify some metadata. Call the journal APIs
++ * to unshare ->b_data if a currently-committing transaction is
++ * using it
++ */
++ BUFFER_TRACE(gd_bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, gd_bh);
++ if (err)
++ goto error_return;
++
++ jbd_lock_bh_state(bitmap_bh);
++
++ for (i = 0, group_freed = 0; i < count; i++) {
++ /*
++ * An HJ special. This is expensive...
++ */
++#ifdef CONFIG_JBD_DEBUG
++ jbd_unlock_bh_state(bitmap_bh);
++ {
++ struct buffer_head *debug_bh;
++ debug_bh = sb_find_get_block(sb, block + i);
++ if (debug_bh) {
++ BUFFER_TRACE(debug_bh, "Deleted!");
++ if (!bh2jh(bitmap_bh)->b_committed_data)
++ BUFFER_TRACE(debug_bh,
++ "No commited data in bitmap");
++ BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap");
++ __brelse(debug_bh);
++ }
++ }
++ jbd_lock_bh_state(bitmap_bh);
++#endif
++ if (need_resched()) {
++ jbd_unlock_bh_state(bitmap_bh);
++ cond_resched();
++ jbd_lock_bh_state(bitmap_bh);
++ }
++ /* @@@ This prevents newly-allocated data from being
++ * freed and then reallocated within the same
++ * transaction.
++ *
++ * Ideally we would want to allow that to happen, but to
++ * do so requires making jbd2_journal_forget() capable of
++ * revoking the queued write of a data block, which
++ * implies blocking on the journal lock. *forget()
++ * cannot block due to truncate races.
++ *
++ * Eventually we can fix this by making jbd2_journal_forget()
++ * return a status indicating whether or not it was able
++ * to revoke the buffer. On successful revoke, it is
++ * safe not to set the allocation bit in the committed
++ * bitmap, because we know that there is no outstanding
++ * activity on the buffer any more and so it is safe to
++ * reallocate it.
++ */
++ BUFFER_TRACE(bitmap_bh, "set in b_committed_data");
++ J_ASSERT_BH(bitmap_bh,
++ bh2jh(bitmap_bh)->b_committed_data != NULL);
++ ext4_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i,
++ bh2jh(bitmap_bh)->b_committed_data);
++
++ /*
++ * We clear the bit in the bitmap after setting the committed
++ * data bit, because this is the reverse order to that which
++ * the allocator uses.
++ */
++ BUFFER_TRACE(bitmap_bh, "clear bit");
++ if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
++ bit + i, bitmap_bh->b_data)) {
++ jbd_unlock_bh_state(bitmap_bh);
++ ext4_error(sb, __FUNCTION__,
++ "bit already cleared for block %llu",
++ (ext4_fsblk_t)(block + i));
++ jbd_lock_bh_state(bitmap_bh);
++ BUFFER_TRACE(bitmap_bh, "bit already cleared");
++ } else {
++ group_freed++;
++ }
++ }
++ jbd_unlock_bh_state(bitmap_bh);
++
++ spin_lock(sb_bgl_lock(sbi, block_group));
++ desc->bg_free_blocks_count =
++ cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
++ group_freed);
++ spin_unlock(sb_bgl_lock(sbi, block_group));
++ percpu_counter_mod(&sbi->s_freeblocks_counter, count);
++
++ /* We dirtied the bitmap block */
++ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
++ err = ext4_journal_dirty_metadata(handle, bitmap_bh);
++
++ /* And the group descriptor block */
++ BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
++ ret = ext4_journal_dirty_metadata(handle, gd_bh);
++ if (!err) err = ret;
++ *pdquot_freed_blocks += group_freed;
++
++ if (overflow && !err) {
++ block += count;
++ count = overflow;
++ goto do_more;
++ }
++ sb->s_dirt = 1;
++error_return:
++ brelse(bitmap_bh);
++ ext4_std_error(sb, err);
++ return;
++}
++
++/**
++ * ext4_free_blocks() -- Free given blocks and update quota
++ * @handle: handle for this transaction
++ * @inode: inode
++ * @block: start physical block to free
++ * @count: number of blocks to count
++ */
++void ext4_free_blocks(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t block, unsigned long count)
++{
++ struct super_block * sb;
++ unsigned long dquot_freed_blocks;
++
++ sb = inode->i_sb;
++ if (!sb) {
++ printk ("ext4_free_blocks: nonexistent device");
++ return;
++ }
++ ext4_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
++ if (dquot_freed_blocks)
++ DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
++ return;
++}
++
++/**
++ * ext4_test_allocatable()
++ * @nr: given allocation block group
++ * @bh: bufferhead contains the bitmap of the given block group
++ *
++ * For ext4 allocations, we must not reuse any blocks which are
++ * allocated in the bitmap buffer's "last committed data" copy. This
++ * prevents deletes from freeing up the page for reuse until we have
++ * committed the delete transaction.
++ *
++ * If we didn't do this, then deleting something and reallocating it as
++ * data would allow the old block to be overwritten before the
++ * transaction committed (because we force data to disk before commit).
++ * This would lead to corruption if we crashed between overwriting the
++ * data and committing the delete.
++ *
++ * @@@ We may want to make this allocation behaviour conditional on
++ * data-writes at some point, and disable it for metadata allocations or
++ * sync-data inodes.
++ */
++static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh)
++{
++ int ret;
++ struct journal_head *jh = bh2jh(bh);
++
++ if (ext4_test_bit(nr, bh->b_data))
++ return 0;
++
++ jbd_lock_bh_state(bh);
++ if (!jh->b_committed_data)
++ ret = 1;
++ else
++ ret = !ext4_test_bit(nr, jh->b_committed_data);
++ jbd_unlock_bh_state(bh);
++ return ret;
++}
++
++/**
++ * bitmap_search_next_usable_block()
++ * @start: the starting block (group relative) of the search
++ * @bh: bufferhead contains the block group bitmap
++ * @maxblocks: the ending block (group relative) of the reservation
++ *
++ * The bitmap search --- search forward alternately through the actual
++ * bitmap on disk and the last-committed copy in journal, until we find a
++ * bit free in both bitmaps.
++ */
++static ext4_grpblk_t
++bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
++ ext4_grpblk_t maxblocks)
++{
++ ext4_grpblk_t next;
++ struct journal_head *jh = bh2jh(bh);
++
++ while (start < maxblocks) {
++ next = ext4_find_next_zero_bit(bh->b_data, maxblocks, start);
++ if (next >= maxblocks)
++ return -1;
++ if (ext4_test_allocatable(next, bh))
++ return next;
++ jbd_lock_bh_state(bh);
++ if (jh->b_committed_data)
++ start = ext4_find_next_zero_bit(jh->b_committed_data,
++ maxblocks, next);
++ jbd_unlock_bh_state(bh);
++ }
++ return -1;
++}
++
++/**
++ * find_next_usable_block()
++ * @start: the starting block (group relative) to find next
++ * allocatable block in bitmap.
++ * @bh: bufferhead contains the block group bitmap
++ * @maxblocks: the ending block (group relative) for the search
++ *
++ * Find an allocatable block in a bitmap. We honor both the bitmap and
++ * its last-committed copy (if that exists), and perform the "most
++ * appropriate allocation" algorithm of looking for a free block near
++ * the initial goal; then for a free byte somewhere in the bitmap; then
++ * for any free bit in the bitmap.
++ */
++static ext4_grpblk_t
++find_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
++ ext4_grpblk_t maxblocks)
++{
++ ext4_grpblk_t here, next;
++ char *p, *r;
++
++ if (start > 0) {
++ /*
++ * The goal was occupied; search forward for a free
++ * block within the next XX blocks.
++ *
++ * end_goal is more or less random, but it has to be
++ * less than EXT4_BLOCKS_PER_GROUP. Aligning up to the
++ * next 64-bit boundary is simple..
++ */
++ ext4_grpblk_t end_goal = (start + 63) & ~63;
++ if (end_goal > maxblocks)
++ end_goal = maxblocks;
++ here = ext4_find_next_zero_bit(bh->b_data, end_goal, start);
++ if (here < end_goal && ext4_test_allocatable(here, bh))
++ return here;
++ ext4_debug("Bit not found near goal\n");
++ }
++
++ here = start;
++ if (here < 0)
++ here = 0;
++
++ p = ((char *)bh->b_data) + (here >> 3);
++ r = memscan(p, 0, (maxblocks - here + 7) >> 3);
++ next = (r - ((char *)bh->b_data)) << 3;
++
++ if (next < maxblocks && next >= start && ext4_test_allocatable(next, bh))
++ return next;
++
++ /*
++ * The bitmap search --- search forward alternately through the actual
++ * bitmap and the last-committed copy until we find a bit free in
++ * both
++ */
++ here = bitmap_search_next_usable_block(here, bh, maxblocks);
++ return here;
++}
++
++/**
++ * claim_block()
++ * @block: the free block (group relative) to allocate
++ * @bh: the bufferhead containts the block group bitmap
++ *
++ * We think we can allocate this block in this bitmap. Try to set the bit.
++ * If that succeeds then check that nobody has allocated and then freed the
++ * block since we saw that is was not marked in b_committed_data. If it _was_
++ * allocated and freed then clear the bit in the bitmap again and return
++ * zero (failure).
++ */
++static inline int
++claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh)
++{
++ struct journal_head *jh = bh2jh(bh);
++ int ret;
++
++ if (ext4_set_bit_atomic(lock, block, bh->b_data))
++ return 0;
++ jbd_lock_bh_state(bh);
++ if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) {
++ ext4_clear_bit_atomic(lock, block, bh->b_data);
++ ret = 0;
++ } else {
++ ret = 1;
++ }
++ jbd_unlock_bh_state(bh);
++ return ret;
++}
++
++/**
++ * ext4_try_to_allocate()
++ * @sb: superblock
++ * @handle: handle to this transaction
++ * @group: given allocation block group
++ * @bitmap_bh: bufferhead holds the block bitmap
++ * @grp_goal: given target block within the group
++ * @count: target number of blocks to allocate
++ * @my_rsv: reservation window
++ *
++ * Attempt to allocate blocks within a give range. Set the range of allocation
++ * first, then find the first free bit(s) from the bitmap (within the range),
++ * and at last, allocate the blocks by claiming the found free bit as allocated.
++ *
++ * To set the range of this allocation:
++ * if there is a reservation window, only try to allocate block(s) from the
++ * file's own reservation window;
++ * Otherwise, the allocation range starts from the give goal block, ends at
++ * the block group's last block.
++ *
++ * If we failed to allocate the desired block then we may end up crossing to a
++ * new bitmap. In that case we must release write access to the old one via
++ * ext4_journal_release_buffer(), else we'll run out of credits.
++ */
++static ext4_grpblk_t
++ext4_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
++ struct buffer_head *bitmap_bh, ext4_grpblk_t grp_goal,
++ unsigned long *count, struct ext4_reserve_window *my_rsv)
++{
++ ext4_fsblk_t group_first_block;
++ ext4_grpblk_t start, end;
++ unsigned long num = 0;
++
++ /* we do allocation within the reservation window if we have a window */
++ if (my_rsv) {
++ group_first_block = ext4_group_first_block_no(sb, group);
++ if (my_rsv->_rsv_start >= group_first_block)
++ start = my_rsv->_rsv_start - group_first_block;
++ else
++ /* reservation window cross group boundary */
++ start = 0;
++ end = my_rsv->_rsv_end - group_first_block + 1;
++ if (end > EXT4_BLOCKS_PER_GROUP(sb))
++ /* reservation window crosses group boundary */
++ end = EXT4_BLOCKS_PER_GROUP(sb);
++ if ((start <= grp_goal) && (grp_goal < end))
++ start = grp_goal;
++ else
++ grp_goal = -1;
++ } else {
++ if (grp_goal > 0)
++ start = grp_goal;
++ else
++ start = 0;
++ end = EXT4_BLOCKS_PER_GROUP(sb);
++ }
++
++ BUG_ON(start > EXT4_BLOCKS_PER_GROUP(sb));
++
++repeat:
++ if (grp_goal < 0 || !ext4_test_allocatable(grp_goal, bitmap_bh)) {
++ grp_goal = find_next_usable_block(start, bitmap_bh, end);
++ if (grp_goal < 0)
++ goto fail_access;
++ if (!my_rsv) {
++ int i;
++
++ for (i = 0; i < 7 && grp_goal > start &&
++ ext4_test_allocatable(grp_goal - 1,
++ bitmap_bh);
++ i++, grp_goal--)
++ ;
++ }
++ }
++ start = grp_goal;
++
++ if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group),
++ grp_goal, bitmap_bh)) {
++ /*
++ * The block was allocated by another thread, or it was
++ * allocated and then freed by another thread
++ */
++ start++;
++ grp_goal++;
++ if (start >= end)
++ goto fail_access;
++ goto repeat;
++ }
++ num++;
++ grp_goal++;
++ while (num < *count && grp_goal < end
++ && ext4_test_allocatable(grp_goal, bitmap_bh)
++ && claim_block(sb_bgl_lock(EXT4_SB(sb), group),
++ grp_goal, bitmap_bh)) {
++ num++;
++ grp_goal++;
++ }
++ *count = num;
++ return grp_goal - num;
++fail_access:
++ *count = num;
++ return -1;
++}
++
++/**
++ * find_next_reservable_window():
++ * find a reservable space within the given range.
++ * It does not allocate the reservation window for now:
++ * alloc_new_reservation() will do the work later.
++ *
++ * @search_head: the head of the searching list;
++ * This is not necessarily the list head of the whole filesystem
++ *
++ * We have both head and start_block to assist the search
++ * for the reservable space. The list starts from head,
++ * but we will shift to the place where start_block is,
++ * then start from there, when looking for a reservable space.
++ *
++ * @size: the target new reservation window size
++ *
++ * @group_first_block: the first block we consider to start
++ * the real search from
++ *
++ * @last_block:
++ * the maximum block number that our goal reservable space
++ * could start from. This is normally the last block in this
++ * group. The search will end when we found the start of next
++ * possible reservable space is out of this boundary.
++ * This could handle the cross boundary reservation window
++ * request.
++ *
++ * basically we search from the given range, rather than the whole
++ * reservation double linked list, (start_block, last_block)
++ * to find a free region that is of my size and has not
++ * been reserved.
++ *
++ */
++static int find_next_reservable_window(
++ struct ext4_reserve_window_node *search_head,
++ struct ext4_reserve_window_node *my_rsv,
++ struct super_block * sb,
++ ext4_fsblk_t start_block,
++ ext4_fsblk_t last_block)
++{
++ struct rb_node *next;
++ struct ext4_reserve_window_node *rsv, *prev;
++ ext4_fsblk_t 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;
++ rsv = search_head;
++ if (!rsv)
++ return -1;
++
++ while (1) {
++ if (cur <= rsv->rsv_end)
++ cur = rsv->rsv_end + 1;
++
++ /* TODO?
++ * in the case we could not find a reservable space
++ * that is what is expected, during the re-search, we could
++ * remember what's the largest reservable space we could have
++ * and return that one.
++ *
++ * For now it will fail if we could not find the reservable
++ * space with expected-size (or more)...
++ */
++ if (cur > last_block)
++ return -1; /* fail */
++
++ prev = rsv;
++ next = rb_next(&rsv->rsv_node);
++ rsv = list_entry(next,struct ext4_reserve_window_node,rsv_node);
++
++ /*
++ * Reached the last reservation, we can just append to the
++ * previous one.
++ */
++ if (!next)
++ break;
++
++ if (cur + size <= rsv->rsv_start) {
++ /*
++ * Found a reserveable space big enough. We could
++ * have a reservation across the group boundary here
++ */
++ break;
++ }
++ }
++ /*
++ * we come here either :
++ * when we reach the end of the whole list,
++ * and there is empty reservable space after last entry in the list.
++ * append it to the end of the list.
++ *
++ * or we found one reservable space in the middle of the list,
++ * return the reservation window that we could append to.
++ * succeed.
++ */
++
++ 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)
++ ext4_rsv_window_add(sb, my_rsv);
++
++ return 0;
++}
++
++/**
++ * alloc_new_reservation()--allocate a new reservation window
++ *
++ * To make a new reservation, we search part of the filesystem
++ * reservation list (the list that inside the group). We try to
++ * allocate a new reservation window near the allocation goal,
++ * or the beginning of the group, if there is no goal.
++ *
++ * We first find a reservable space after the goal, then from
++ * there, we check the bitmap for the first free block after
++ * it. If there is no free block until the end of group, then the
++ * whole group is full, we failed. Otherwise, check if the free
++ * block is inside the expected reservable space, if so, we
++ * succeed.
++ * If the first free block is outside the reservable space, then
++ * start from the first free block, we search for next available
++ * space, and go on.
++ *
++ * on succeed, a new reservation will be found and inserted into the list
++ * It contains at least one free block, and it does not overlap with other
++ * reservation windows.
++ *
++ * failed: we failed to find a reservation window in this group
++ *
++ * @rsv: the reservation
++ *
++ * @grp_goal: The goal (group-relative). It is where the search for a
++ * free reservable space should start from.
++ * if we have a grp_goal(grp_goal >0 ), then start from there,
++ * no grp_goal(grp_goal = -1), we start from the first block
++ * of the group.
++ *
++ * @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 ext4_reserve_window_node *my_rsv,
++ ext4_grpblk_t grp_goal, struct super_block *sb,
++ unsigned int group, struct buffer_head *bitmap_bh)
++{
++ struct ext4_reserve_window_node *search_head;
++ ext4_fsblk_t group_first_block, group_end_block, start_block;
++ ext4_grpblk_t first_free_block;
++ struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root;
++ unsigned long size;
++ int ret;
++ spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
++
++ group_first_block = ext4_group_first_block_no(sb, group);
++ group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
++
++ if (grp_goal < 0)
++ start_block = group_first_block;
++ else
++ start_block = grp_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
++ * and if the goal is inside the old reservation window,
++ * we will come here when we just failed to allocate from
++ * the first part of the window. We still have another part
++ * that belongs to the next group. In this case, there is no
++ * point to discard our window and try to allocate a new one
++ * in this group(which will fail). we should
++ * keep the reservation window, just simply move on.
++ *
++ * Maybe we could shift the start block of the reservation
++ * window to the first block of next group.
++ */
++
++ if ((my_rsv->rsv_start <= group_end_block) &&
++ (my_rsv->rsv_end > group_end_block) &&
++ (start_block >= my_rsv->rsv_start))
++ return -1;
++
++ if ((my_rsv->rsv_alloc_hit >
++ (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
++ /*
++ * if the previously allocation hit ratio is
++ * greater than 1/2, then we double the size of
++ * the reservation window the next time,
++ * otherwise we keep the same size window
++ */
++ size = size * 2;
++ if (size > EXT4_MAX_RESERVE_BLOCKS)
++ size = EXT4_MAX_RESERVE_BLOCKS;
++ my_rsv->rsv_goal_size= size;
++ }
++ }
++
++ spin_lock(rsv_lock);
++ /*
++ * shift the search start to the window near the goal block
++ */
++ search_head = search_reserve_window(fs_rsv_root, start_block);
++
++ /*
++ * find_next_reservable_window() simply finds a reservable window
++ * inside the given range(start_block, group_end_block).
++ *
++ * To make sure the reservation window has a free bit inside it, we
++ * need to check the bitmap after we found a reservable window.
++ */
++retry:
++ 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.
++ * Before we reserve this reservable space, we need
++ * to make sure there is at least a free block inside this region.
++ *
++ * searching the first free bit on the block bitmap and copy of
++ * last committed bitmap alternatively, until we found a allocatable
++ * 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(
++ my_rsv->rsv_start - group_first_block,
++ bitmap_bh, group_end_block - group_first_block + 1);
++
++ if (first_free_block < 0) {
++ /*
++ * no free block left on the bitmap, no point
++ * to reserve the space. return 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 reserved
++ */
++ 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
++ * 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 = my_rsv;
++ spin_lock(rsv_lock);
++ goto retry;
++}
++
++/**
++ * try_to_extend_reservation()
++ * @my_rsv: given reservation window
++ * @sb: super block
++ * @size: the delta to extend
++ *
++ * Attempt to expand the reservation window large enough to have
++ * required number of free blocks
++ *
++ * Since ext4_try_to_allocate() will always allocate blocks within
++ * the reservation window range, if the window size is too small,
++ * multiple blocks allocation has to stop at the end of the reservation
++ * window. To make this more efficient, given the total number of
++ * blocks needed and the current size of the window, we try to
++ * expand the reservation window size if necessary on a best-effort
++ * basis before ext4_new_blocks() tries to allocate blocks,
++ */
++static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv,
++ struct super_block *sb, int size)
++{
++ struct ext4_reserve_window_node *next_rsv;
++ struct rb_node *next;
++ spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
++
++ if (!spin_trylock(rsv_lock))
++ return;
++
++ next = rb_next(&my_rsv->rsv_node);
++
++ if (!next)
++ my_rsv->rsv_end += size;
++ else {
++ next_rsv = list_entry(next, struct ext4_reserve_window_node, rsv_node);
++
++ if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)
++ my_rsv->rsv_end += size;
++ else
++ my_rsv->rsv_end = next_rsv->rsv_start - 1;
++ }
++ spin_unlock(rsv_lock);
++}
++
++/**
++ * ext4_try_to_allocate_with_rsv()
++ * @sb: superblock
++ * @handle: handle to this transaction
++ * @group: given allocation block group
++ * @bitmap_bh: bufferhead holds the block bitmap
++ * @grp_goal: given target block within the group
++ * @count: target number of blocks to allocate
++ * @my_rsv: reservation window
++ * @errp: pointer to store the error code
++ *
++ * This is the main function used to allocate a new block and its reservation
++ * window.
++ *
++ * Each time when a new block allocation is need, first try to allocate from
++ * its own reservation. If it does not have a reservation window, instead of
++ * looking for a free bit on bitmap first, then look up the reservation list to
++ * see if it is inside somebody else's reservation window, we try to allocate a
++ * reservation window for it starting from the goal first. Then do the block
++ * allocation within the reservation window.
++ *
++ * This will avoid keeping on searching the reservation list again and
++ * again when somebody is looking for a free block (without
++ * reservation), and there are lots of free blocks, but they are all
++ * being reserved.
++ *
++ * We use a red-black tree for the per-filesystem reservation list.
++ *
++ */
++static ext4_grpblk_t
++ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
++ unsigned int group, struct buffer_head *bitmap_bh,
++ ext4_grpblk_t grp_goal,
++ struct ext4_reserve_window_node * my_rsv,
++ unsigned long *count, int *errp)
++{
++ ext4_fsblk_t group_first_block, group_last_block;
++ ext4_grpblk_t ret = 0;
++ int fatal;
++ unsigned long num = *count;
++
++ *errp = 0;
++
++ /*
++ * Make sure we use undo access for the bitmap, because it is critical
++ * that we do the frozen_data COW on bitmap buffers in all cases even
++ * if the buffer is in BJ_Forget state in the committing transaction.
++ */
++ BUFFER_TRACE(bitmap_bh, "get undo access for new block");
++ fatal = ext4_journal_get_undo_access(handle, bitmap_bh);
++ if (fatal) {
++ *errp = fatal;
++ return -1;
++ }
++
++ /*
++ * we don't deal with reservation when
++ * filesystem is mounted without reservation
++ * or the file is not a regular file
++ * or last attempt to allocate a block with reservation turned on failed
++ */
++ if (my_rsv == NULL ) {
++ ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
++ grp_goal, count, NULL);
++ goto out;
++ }
++ /*
++ * grp_goal is a group relative block number (if there is a goal)
++ * 0 < grp_goal < EXT4_BLOCKS_PER_GROUP(sb)
++ * first block is a filesystem wide block number
++ * first block is the block number of the first block in this group
++ */
++ group_first_block = ext4_group_first_block_no(sb, group);
++ group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
++
++ /*
++ * Basically we will allocate a new block from inode's reservation
++ * window.
++ *
++ * We need to allocate a new reservation window, if:
++ * a) inode does not have a reservation window; or
++ * b) last attempt to allocate a block from existing reservation
++ * failed; or
++ * c) we come here with a goal and with a reservation window
++ *
++ * We do not need to allocate a new reservation window if we come here
++ * at the beginning with a goal and the goal is inside the window, or
++ * we don't have a goal but already have a reservation window.
++ * then we could go to allocate from the reservation window directly.
++ */
++ while (1) {
++ if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
++ !goal_in_my_reservation(&my_rsv->rsv_window,
++ grp_goal, group, sb)) {
++ if (my_rsv->rsv_goal_size < *count)
++ my_rsv->rsv_goal_size = *count;
++ ret = alloc_new_reservation(my_rsv, grp_goal, sb,
++ group, bitmap_bh);
++ if (ret < 0)
++ break; /* failed */
++
++ if (!goal_in_my_reservation(&my_rsv->rsv_window,
++ grp_goal, group, sb))
++ grp_goal = -1;
++ } else if (grp_goal > 0 &&
++ (my_rsv->rsv_end-grp_goal+1) < *count)
++ try_to_extend_reservation(my_rsv, sb,
++ *count-my_rsv->rsv_end + grp_goal - 1);
++
++ if ((my_rsv->rsv_start > group_last_block) ||
++ (my_rsv->rsv_end < group_first_block)) {
++ rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1);
++ BUG();
++ }
++ ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
++ grp_goal, &num, &my_rsv->rsv_window);
++ if (ret >= 0) {
++ my_rsv->rsv_alloc_hit += num;
++ *count = num;
++ break; /* succeed */
++ }
++ num = *count;
++ }
++out:
++ if (ret >= 0) {
++ BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for "
++ "bitmap block");
++ fatal = ext4_journal_dirty_metadata(handle, bitmap_bh);
++ if (fatal) {
++ *errp = fatal;
++ return -1;
++ }
++ return ret;
++ }
++
++ BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
++ ext4_journal_release_buffer(handle, bitmap_bh);
++ return ret;
++}
++
++/**
++ * ext4_has_free_blocks()
++ * @sbi: in-core super block structure.
++ *
++ * Check if filesystem has at least 1 free block available for allocation.
++ */
++static int ext4_has_free_blocks(struct ext4_sb_info *sbi)
++{
++ ext4_fsblk_t free_blocks, root_blocks;
++
++ free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
++ root_blocks = ext4_r_blocks_count(sbi->s_es);
++ if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
++ sbi->s_resuid != current->fsuid &&
++ (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
++ return 0;
++ }
++ return 1;
++}
++
++/**
++ * ext4_should_retry_alloc()
++ * @sb: super block
++ * @retries number of attemps has been made
++ *
++ * ext4_should_retry_alloc() is called when ENOSPC is returned, and if
++ * it is profitable to retry the operation, this function will wait
++ * for the current or commiting transaction to complete, and then
++ * return TRUE.
++ *
++ * if the total number of retries exceed three times, return FALSE.
++ */
++int ext4_should_retry_alloc(struct super_block *sb, int *retries)
++{
++ if (!ext4_has_free_blocks(EXT4_SB(sb)) || (*retries)++ > 3)
++ return 0;
++
++ jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
++
++ return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
++}
++
++/**
++ * ext4_new_blocks() -- core block(s) allocation function
++ * @handle: handle to this transaction
++ * @inode: file inode
++ * @goal: given target block(filesystem wide)
++ * @count: target number of blocks to allocate
++ * @errp: error code
++ *
++ * ext4_new_blocks uses a goal block to assist allocation. It tries to
++ * allocate block(s) from the block group contains the goal block first. If that
++ * fails, it will try to allocate block(s) from other block groups without
++ * any specific goal block.
++ *
++ */
++ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t goal, unsigned long *count, int *errp)
++{
++ struct buffer_head *bitmap_bh = NULL;
++ struct buffer_head *gdp_bh;
++ unsigned long group_no;
++ int goal_group;
++ ext4_grpblk_t grp_target_blk; /* blockgroup relative goal block */
++ ext4_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/
++ ext4_fsblk_t ret_block; /* filesyetem-wide allocated block */
++ int bgi; /* blockgroup iteration index */
++ int fatal = 0, err;
++ int performed_allocation = 0;
++ ext4_grpblk_t free_blocks; /* number of free blocks in a group */
++ struct super_block *sb;
++ struct ext4_group_desc *gdp;
++ struct ext4_super_block *es;
++ struct ext4_sb_info *sbi;
++ struct ext4_reserve_window_node *my_rsv = NULL;
++ struct ext4_block_alloc_info *block_i;
++ unsigned short windowsz = 0;
++#ifdef EXT4FS_DEBUG
++ static int goal_hits, goal_attempts;
++#endif
++ unsigned long ngroups;
++ unsigned long num = *count;
++
++ *errp = -ENOSPC;
++ sb = inode->i_sb;
++ if (!sb) {
++ printk("ext4_new_block: nonexistent device");
++ return 0;
++ }
++
++ /*
++ * Check quota for allocation of this block.
++ */
++ if (DQUOT_ALLOC_BLOCK(inode, num)) {
++ *errp = -EDQUOT;
++ return 0;
++ }
++
++ sbi = EXT4_SB(sb);
++ es = EXT4_SB(sb)->s_es;
++ ext4_debug("goal=%lu.\n", goal);
++ /*
++ * Allocate a block from reservation only when
++ * filesystem is mounted with reservation(default,-o reservation), and
++ * it's a regular file, and
++ * the desired window size is greater than 0 (One could use ioctl
++ * command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off
++ * reservation on that particular file)
++ */
++ block_i = EXT4_I(inode)->i_block_alloc_info;
++ if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
++ my_rsv = &block_i->rsv_window_node;
++
++ if (!ext4_has_free_blocks(sbi)) {
++ *errp = -ENOSPC;
++ goto out;
++ }
++
++ /*
++ * First, test whether the goal block is free.
++ */
++ if (goal < le32_to_cpu(es->s_first_data_block) ||
++ goal >= ext4_blocks_count(es))
++ goal = le32_to_cpu(es->s_first_data_block);
++ ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk);
++ goal_group = group_no;
++retry_alloc:
++ gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
++ if (!gdp)
++ goto io_error;
++
++ free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
++ /*
++ * if there is not enough free blocks to make a new resevation
++ * turn off reservation for this allocation
++ */
++ if (my_rsv && (free_blocks < windowsz)
++ && (rsv_is_empty(&my_rsv->rsv_window)))
++ my_rsv = NULL;
++
++ if (free_blocks > 0) {
++ bitmap_bh = read_block_bitmap(sb, group_no);
++ if (!bitmap_bh)
++ goto io_error;
++ grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
++ group_no, bitmap_bh, grp_target_blk,
++ my_rsv, &num, &fatal);
++ if (fatal)
++ goto out;
++ if (grp_alloc_blk >= 0)
++ goto allocated;
++ }
++
++ ngroups = EXT4_SB(sb)->s_groups_count;
++ smp_rmb();
++
++ /*
++ * Now search the rest of the groups. We assume that
++ * i and gdp correctly point to the last group visited.
++ */
++ for (bgi = 0; bgi < ngroups; bgi++) {
++ group_no++;
++ if (group_no >= ngroups)
++ group_no = 0;
++ gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
++ if (!gdp) {
++ *errp = -EIO;
++ goto out;
++ }
++ free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
++ /*
++ * skip this group if the number of
++ * free blocks is less than half of the reservation
++ * window size.
++ */
++ if (free_blocks <= (windowsz/2))
++ continue;
++
++ brelse(bitmap_bh);
++ bitmap_bh = read_block_bitmap(sb, group_no);
++ if (!bitmap_bh)
++ goto io_error;
++ /*
++ * try to allocate block(s) from this group, without a goal(-1).
++ */
++ grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
++ group_no, bitmap_bh, -1, my_rsv,
++ &num, &fatal);
++ if (fatal)
++ goto out;
++ if (grp_alloc_blk >= 0)
++ goto allocated;
++ }
++ /*
++ * We may end up a bogus ealier ENOSPC error due to
++ * filesystem is "full" of reservations, but
++ * there maybe indeed free blocks avaliable on disk
++ * In this case, we just forget about the reservations
++ * just do block allocation as without reservations.
++ */
++ if (my_rsv) {
++ my_rsv = NULL;
++ group_no = goal_group;
++ goto retry_alloc;
++ }
++ /* No space left on the device */
++ *errp = -ENOSPC;
++ goto out;
++
++allocated:
++
++ ext4_debug("using block group %d(%d)\n",
++ group_no, gdp->bg_free_blocks_count);
++
++ BUFFER_TRACE(gdp_bh, "get_write_access");
++ fatal = ext4_journal_get_write_access(handle, gdp_bh);
++ if (fatal)
++ goto out;
++
++ ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
++
++ if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
++ in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
++ in_range(ret_block, ext4_inode_table(sb, gdp),
++ EXT4_SB(sb)->s_itb_per_group) ||
++ in_range(ret_block + num - 1, ext4_inode_table(sb, gdp),
++ EXT4_SB(sb)->s_itb_per_group))
++ ext4_error(sb, "ext4_new_block",
++ "Allocating block in system zone - "
++ "blocks from %llu, length %lu",
++ ret_block, num);
++
++ performed_allocation = 1;
++
++#ifdef CONFIG_JBD_DEBUG
++ {
++ struct buffer_head *debug_bh;
++
++ /* Record bitmap buffer state in the newly allocated block */
++ debug_bh = sb_find_get_block(sb, ret_block);
++ if (debug_bh) {
++ BUFFER_TRACE(debug_bh, "state when allocated");
++ BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
++ brelse(debug_bh);
++ }
++ }
++ jbd_lock_bh_state(bitmap_bh);
++ spin_lock(sb_bgl_lock(sbi, group_no));
++ if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) {
++ int i;
++
++ for (i = 0; i < num; i++) {
++ if (ext4_test_bit(grp_alloc_blk+i,
++ bh2jh(bitmap_bh)->b_committed_data)) {
++ printk("%s: block was unexpectedly set in "
++ "b_committed_data\n", __FUNCTION__);
++ }
++ }
++ }
++ ext4_debug("found bit %d\n", grp_alloc_blk);
++ spin_unlock(sb_bgl_lock(sbi, group_no));
++ jbd_unlock_bh_state(bitmap_bh);
++#endif
++
++ if (ret_block + num - 1 >= ext4_blocks_count(es)) {
++ ext4_error(sb, "ext4_new_block",
++ "block(%llu) >= blocks count(%llu) - "
++ "block_group = %lu, es == %p ", ret_block,
++ ext4_blocks_count(es), group_no, es);
++ goto out;
++ }
++
++ /*
++ * It is up to the caller to add the new buffer to a journal
++ * list of some description. We don't know in advance whether
++ * the caller wants to use it as metadata or data.
++ */
++ ext4_debug("allocating block %lu. Goal hits %d of %d.\n",
++ ret_block, goal_hits, goal_attempts);
++
++ spin_lock(sb_bgl_lock(sbi, group_no));
++ gdp->bg_free_blocks_count =
++ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
++ spin_unlock(sb_bgl_lock(sbi, group_no));
++ percpu_counter_mod(&sbi->s_freeblocks_counter, -num);
++
++ BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
++ err = ext4_journal_dirty_metadata(handle, gdp_bh);
++ if (!fatal)
++ fatal = err;
++
++ sb->s_dirt = 1;
++ if (fatal)
++ goto out;
++
++ *errp = 0;
++ brelse(bitmap_bh);
++ DQUOT_FREE_BLOCK(inode, *count-num);
++ *count = num;
++ return ret_block;
++
++io_error:
++ *errp = -EIO;
++out:
++ if (fatal) {
++ *errp = fatal;
++ ext4_std_error(sb, fatal);
++ }
++ /*
++ * Undo the block allocation
++ */
++ if (!performed_allocation)
++ DQUOT_FREE_BLOCK(inode, *count);
++ brelse(bitmap_bh);
++ return 0;
++}
++
++ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t goal, int *errp)
++{
++ unsigned long count = 1;
++
++ return ext4_new_blocks(handle, inode, goal, &count, errp);
++}
++
++/**
++ * ext4_count_free_blocks() -- count filesystem free blocks
++ * @sb: superblock
++ *
++ * Adds up the number of free blocks from each block group.
++ */
++ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
++{
++ ext4_fsblk_t desc_count;
++ struct ext4_group_desc *gdp;
++ int i;
++ unsigned long ngroups = EXT4_SB(sb)->s_groups_count;
++#ifdef EXT4FS_DEBUG
++ struct ext4_super_block *es;
++ ext4_fsblk_t bitmap_count;
++ unsigned long x;
++ struct buffer_head *bitmap_bh = NULL;
++
++ es = EXT4_SB(sb)->s_es;
++ desc_count = 0;
++ bitmap_count = 0;
++ gdp = NULL;
++
++ smp_rmb();
++ for (i = 0; i < ngroups; i++) {
++ gdp = ext4_get_group_desc(sb, i, NULL);
++ if (!gdp)
++ continue;
++ desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
++ brelse(bitmap_bh);
++ bitmap_bh = read_block_bitmap(sb, i);
++ if (bitmap_bh == NULL)
++ continue;
++
++ x = ext4_count_free(bitmap_bh, sb->s_blocksize);
++ printk("group %d: stored = %d, counted = %lu\n",
++ i, le16_to_cpu(gdp->bg_free_blocks_count), x);
++ bitmap_count += x;
++ }
++ brelse(bitmap_bh);
++ printk("ext4_count_free_blocks: stored = %llu"
++ ", computed = %llu, %llu\n",
++ EXT4_FREE_BLOCKS_COUNT(es),
++ desc_count, bitmap_count);
++ return bitmap_count;
++#else
++ desc_count = 0;
++ smp_rmb();
++ for (i = 0; i < ngroups; i++) {
++ gdp = ext4_get_group_desc(sb, i, NULL);
++ if (!gdp)
++ continue;
++ desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
++ }
++
++ return desc_count;
++#endif
++}
++
++static inline int
++block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map)
++{
++ ext4_grpblk_t offset;
++
++ ext4_get_group_no_and_offset(sb, block, NULL, &offset);
++ return ext4_test_bit (offset, map);
++}
++
++static inline int test_root(int a, int b)
++{
++ int num = b;
++
++ while (a > num)
++ num *= b;
++ return num == a;
++}
++
++static int ext4_group_sparse(int group)
++{
++ if (group <= 1)
++ return 1;
++ if (!(group & 1))
++ return 0;
++ return (test_root(group, 7) || test_root(group, 5) ||
++ test_root(group, 3));
++}
++
++/**
++ * ext4_bg_has_super - number of blocks used by the superblock in group
++ * @sb: superblock for filesystem
++ * @group: group number to check
++ *
++ * Return the number of blocks used by the superblock (primary or backup)
++ * in this group. Currently this will be only 0 or 1.
++ */
++int ext4_bg_has_super(struct super_block *sb, int group)
++{
++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
++ !ext4_group_sparse(group))
++ return 0;
++ return 1;
++}
++
++static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, int group)
++{
++ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
++ unsigned long first = metagroup * EXT4_DESC_PER_BLOCK(sb);
++ unsigned long last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
++
++ if (group == first || group == first + 1 || group == last)
++ return 1;
++ return 0;
++}
++
++static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, int group)
++{
++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
++ !ext4_group_sparse(group))
++ return 0;
++ return EXT4_SB(sb)->s_gdb_count;
++}
++
++/**
++ * ext4_bg_num_gdb - number of blocks used by the group table in group
++ * @sb: superblock for filesystem
++ * @group: group number to check
++ *
++ * Return the number of blocks used by the group descriptor table
++ * (primary or backup) in this group. In the future there may be a
++ * different number of descriptor blocks in each group.
++ */
++unsigned long ext4_bg_num_gdb(struct super_block *sb, int group)
++{
++ unsigned long first_meta_bg =
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg);
++ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
++
++ if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
++ metagroup < first_meta_bg)
++ return ext4_bg_num_gdb_nometa(sb,group);
++
++ return ext4_bg_num_gdb_meta(sb,group);
++
++}
+diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
+new file mode 100644
+index 0000000..11e93c1
+--- /dev/null
++++ b/fs/ext4/bitmap.c
+@@ -0,0 +1,32 @@
++/*
++ * linux/fs/ext4/bitmap.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ */
++
++#include <linux/buffer_head.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++
++#ifdef EXT4FS_DEBUG
++
++static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
++
++unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars)
++{
++ unsigned int i;
++ unsigned long sum = 0;
++
++ if (!map)
++ return (0);
++ for (i = 0; i < numchars; i++)
++ sum += nibblemap[map->b_data[i] & 0xf] +
++ nibblemap[(map->b_data[i] >> 4) & 0xf];
++ return (sum);
++}
++
++#endif /* EXT4FS_DEBUG */
++
+diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
+new file mode 100644
+index 0000000..f859578
+--- /dev/null
++++ b/fs/ext4/dir.c
+@@ -0,0 +1,518 @@
++/*
++ * linux/fs/ext4/dir.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/dir.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * ext4 directory handling functions
++ *
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ *
++ * Hash Tree Directory indexing (c) 2001 Daniel Phillips
++ *
++ */
++
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/buffer_head.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++#include <linux/rbtree.h>
++
++static unsigned char ext4_filetype_table[] = {
++ DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
++};
++
++static int ext4_readdir(struct file *, void *, filldir_t);
++static int ext4_dx_readdir(struct file * filp,
++ void * dirent, filldir_t filldir);
++static int ext4_release_dir (struct inode * inode,
++ struct file * filp);
++
++const struct file_operations ext4_dir_operations = {
++ .llseek = generic_file_llseek,
++ .read = generic_read_dir,
++ .readdir = ext4_readdir, /* we take BKL. needed?*/
++ .ioctl = ext4_ioctl, /* BKL held */
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext4_compat_ioctl,
++#endif
++ .fsync = ext4_sync_file, /* BKL held */
++#ifdef CONFIG_EXT4_INDEX
++ .release = ext4_release_dir,
++#endif
++};
++
++
++static unsigned char get_dtype(struct super_block *sb, int filetype)
++{
++ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
++ (filetype >= EXT4_FT_MAX))
++ return DT_UNKNOWN;
++
++ return (ext4_filetype_table[filetype]);
++}
++
++
++int ext4_check_dir_entry (const char * function, struct inode * dir,
++ struct ext4_dir_entry_2 * de,
++ struct buffer_head * bh,
++ unsigned long offset)
++{
++ const char * error_msg = NULL;
++ const int rlen = le16_to_cpu(de->rec_len);
++
++ if (rlen < EXT4_DIR_REC_LEN(1))
++ error_msg = "rec_len is smaller than minimal";
++ else if (rlen % 4 != 0)
++ error_msg = "rec_len % 4 != 0";
++ else if (rlen < EXT4_DIR_REC_LEN(de->name_len))
++ error_msg = "rec_len is too small for name_len";
++ else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
++ error_msg = "directory entry across blocks";
++ else if (le32_to_cpu(de->inode) >
++ le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))
++ error_msg = "inode out of bounds";
++
++ if (error_msg != NULL)
++ ext4_error (dir->i_sb, function,
++ "bad entry in directory #%lu: %s - "
++ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
++ dir->i_ino, error_msg, offset,
++ (unsigned long) le32_to_cpu(de->inode),
++ rlen, de->name_len);
++ return error_msg == NULL ? 1 : 0;
++}
++
++static int ext4_readdir(struct file * filp,
++ void * dirent, filldir_t filldir)
++{
++ int error = 0;
++ unsigned long offset;
++ int i, stored;
++ struct ext4_dir_entry_2 *de;
++ struct super_block *sb;
++ int err;
++ struct inode *inode = filp->f_dentry->d_inode;
++ int ret = 0;
++
++ sb = inode->i_sb;
++
++#ifdef CONFIG_EXT4_INDEX
++ if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_COMPAT_DIR_INDEX) &&
++ ((EXT4_I(inode)->i_flags & EXT4_INDEX_FL) ||
++ ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
++ err = ext4_dx_readdir(filp, dirent, filldir);
++ if (err != ERR_BAD_DX_DIR) {
++ ret = err;
++ goto out;
++ }
++ /*
++ * We don't set the inode dirty flag since it's not
++ * critical that it get flushed back to the disk.
++ */
++ EXT4_I(filp->f_dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL;
++ }
++#endif
++ stored = 0;
++ offset = filp->f_pos & (sb->s_blocksize - 1);
++
++ while (!error && !stored && filp->f_pos < inode->i_size) {
++ unsigned long blk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb);
++ struct buffer_head map_bh;
++ struct buffer_head *bh = NULL;
++
++ map_bh.b_state = 0;
++ err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh, 0, 0);
++ if (err > 0) {
++ page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
++ &filp->f_ra,
++ filp,
++ map_bh.b_blocknr >>
++ (PAGE_CACHE_SHIFT - inode->i_blkbits),
++ 1);
++ bh = ext4_bread(NULL, inode, blk, 0, &err);
++ }
++
++ /*
++ * We ignore I/O errors on directories so users have a chance
++ * of recovering data when there's a bad sector
++ */
++ if (!bh) {
++ ext4_error (sb, "ext4_readdir",
++ "directory #%lu contains a hole at offset %lu",
++ inode->i_ino, (unsigned long)filp->f_pos);
++ filp->f_pos += sb->s_blocksize - offset;
++ continue;
++ }
++
++revalidate:
++ /* If the dir block has changed since the last call to
++ * readdir(2), then we might be pointing to an invalid
++ * dirent right now. Scan from the start of the block
++ * to make sure. */
++ if (filp->f_version != inode->i_version) {
++ for (i = 0; i < sb->s_blocksize && i < offset; ) {
++ de = (struct ext4_dir_entry_2 *)
++ (bh->b_data + i);
++ /* It's too expensive to do a full
++ * dirent test each time round this
++ * loop, but we do have to test at
++ * least that it is non-zero. A
++ * failure will be detected in the
++ * dirent test below. */
++ if (le16_to_cpu(de->rec_len) <
++ EXT4_DIR_REC_LEN(1))
++ break;
++ i += le16_to_cpu(de->rec_len);
++ }
++ offset = i;
++ filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
++ | offset;
++ filp->f_version = inode->i_version;
++ }
++
++ while (!error && filp->f_pos < inode->i_size
++ && offset < sb->s_blocksize) {
++ de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
++ if (!ext4_check_dir_entry ("ext4_readdir", inode, de,
++ bh, offset)) {
++ /*
++ * On error, skip the f_pos to the next block
++ */
++ filp->f_pos = (filp->f_pos |
++ (sb->s_blocksize - 1)) + 1;
++ brelse (bh);
++ ret = stored;
++ goto out;
++ }
++ offset += le16_to_cpu(de->rec_len);
++ if (le32_to_cpu(de->inode)) {
++ /* We might block in the next section
++ * if the data destination is
++ * currently swapped out. So, use a
++ * version stamp to detect whether or
++ * not the directory has been modified
++ * during the copy operation.
++ */
++ unsigned long version = filp->f_version;
++
++ error = filldir(dirent, de->name,
++ de->name_len,
++ filp->f_pos,
++ le32_to_cpu(de->inode),
++ get_dtype(sb, de->file_type));
++ if (error)
++ break;
++ if (version != filp->f_version)
++ goto revalidate;
++ stored ++;
++ }
++ filp->f_pos += le16_to_cpu(de->rec_len);
++ }
++ offset = 0;
++ brelse (bh);
++ }
++out:
++ return ret;
++}
++
++#ifdef CONFIG_EXT4_INDEX
++/*
++ * These functions convert from the major/minor hash to an f_pos
++ * value.
++ *
++ * Currently we only use major hash numer. This is unfortunate, but
++ * on 32-bit machines, the same VFS interface is used for lseek and
++ * llseek, so if we use the 64 bit offset, then the 32-bit versions of
++ * lseek/telldir/seekdir will blow out spectacularly, and from within
++ * the ext2 low-level routine, we don't know if we're being called by
++ * a 64-bit version of the system call or the 32-bit version of the
++ * system call. Worse yet, NFSv2 only allows for a 32-bit readdir
++ * cookie. Sigh.
++ */
++#define hash2pos(major, minor) (major >> 1)
++#define pos2maj_hash(pos) ((pos << 1) & 0xffffffff)
++#define pos2min_hash(pos) (0)
++
++/*
++ * This structure holds the nodes of the red-black tree used to store
++ * the directory entry in hash order.
++ */
++struct fname {
++ __u32 hash;
++ __u32 minor_hash;
++ struct rb_node rb_hash;
++ struct fname *next;
++ __u32 inode;
++ __u8 name_len;
++ __u8 file_type;
++ char name[0];
++};
++
++/*
++ * This functoin implements a non-recursive way of freeing all of the
++ * nodes in the red-black tree.
++ */
++static void free_rb_tree_fname(struct rb_root *root)
++{
++ struct rb_node *n = root->rb_node;
++ struct rb_node *parent;
++ struct fname *fname;
++
++ while (n) {
++ /* Do the node's children first */
++ if ((n)->rb_left) {
++ n = n->rb_left;
++ continue;
++ }
++ if (n->rb_right) {
++ n = n->rb_right;
++ continue;
++ }
++ /*
++ * The node has no children; free it, and then zero
++ * out parent's link to it. Finally go to the
++ * beginning of the loop and try to free the parent
++ * node.
++ */
++ parent = rb_parent(n);
++ fname = rb_entry(n, struct fname, rb_hash);
++ while (fname) {
++ struct fname * old = fname;
++ fname = fname->next;
++ kfree (old);
++ }
++ if (!parent)
++ root->rb_node = NULL;
++ else if (parent->rb_left == n)
++ parent->rb_left = NULL;
++ else if (parent->rb_right == n)
++ parent->rb_right = NULL;
++ n = parent;
++ }
++ root->rb_node = NULL;
++}
++
++
++static struct dir_private_info *create_dir_info(loff_t pos)
++{
++ struct dir_private_info *p;
++
++ p = kmalloc(sizeof(struct dir_private_info), GFP_KERNEL);
++ if (!p)
++ return NULL;
++ p->root.rb_node = NULL;
++ p->curr_node = NULL;
++ p->extra_fname = NULL;
++ p->last_pos = 0;
++ p->curr_hash = pos2maj_hash(pos);
++ p->curr_minor_hash = pos2min_hash(pos);
++ p->next_hash = 0;
++ return p;
++}
++
++void ext4_htree_free_dir_info(struct dir_private_info *p)
++{
++ free_rb_tree_fname(&p->root);
++ kfree(p);
++}
++
++/*
++ * Given a directory entry, enter it into the fname rb tree.
++ */
++int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
++ __u32 minor_hash,
++ struct ext4_dir_entry_2 *dirent)
++{
++ struct rb_node **p, *parent = NULL;
++ struct fname * fname, *new_fn;
++ struct dir_private_info *info;
++ int len;
++
++ info = (struct dir_private_info *) dir_file->private_data;
++ p = &info->root.rb_node;
++
++ /* Create and allocate the fname structure */
++ len = sizeof(struct fname) + dirent->name_len + 1;
++ new_fn = kzalloc(len, GFP_KERNEL);
++ if (!new_fn)
++ return -ENOMEM;
++ new_fn->hash = hash;
++ new_fn->minor_hash = minor_hash;
++ new_fn->inode = le32_to_cpu(dirent->inode);
++ new_fn->name_len = dirent->name_len;
++ new_fn->file_type = dirent->file_type;
++ memcpy(new_fn->name, dirent->name, dirent->name_len);
++ new_fn->name[dirent->name_len] = 0;
++
++ while (*p) {
++ parent = *p;
++ fname = rb_entry(parent, struct fname, rb_hash);
++
++ /*
++ * If the hash and minor hash match up, then we put
++ * them on a linked list. This rarely happens...
++ */
++ if ((new_fn->hash == fname->hash) &&
++ (new_fn->minor_hash == fname->minor_hash)) {
++ new_fn->next = fname->next;
++ fname->next = new_fn;
++ return 0;
++ }
++
++ if (new_fn->hash < fname->hash)
++ p = &(*p)->rb_left;
++ else if (new_fn->hash > fname->hash)
++ p = &(*p)->rb_right;
++ else if (new_fn->minor_hash < fname->minor_hash)
++ p = &(*p)->rb_left;
++ else /* if (new_fn->minor_hash > fname->minor_hash) */
++ p = &(*p)->rb_right;
++ }
++
++ rb_link_node(&new_fn->rb_hash, parent, p);
++ rb_insert_color(&new_fn->rb_hash, &info->root);
++ return 0;
++}
++
++
++
++/*
++ * This is a helper function for ext4_dx_readdir. It calls filldir
++ * for all entres on the fname linked list. (Normally there is only
++ * one entry on the linked list, unless there are 62 bit hash collisions.)
++ */
++static int call_filldir(struct file * filp, void * dirent,
++ filldir_t filldir, struct fname *fname)
++{
++ struct dir_private_info *info = filp->private_data;
++ loff_t curr_pos;
++ struct inode *inode = filp->f_dentry->d_inode;
++ struct super_block * sb;
++ int error;
++
++ sb = inode->i_sb;
++
++ if (!fname) {
++ printk("call_filldir: called with null fname?!?\n");
++ return 0;
++ }
++ curr_pos = hash2pos(fname->hash, fname->minor_hash);
++ while (fname) {
++ error = filldir(dirent, fname->name,
++ fname->name_len, curr_pos,
++ fname->inode,
++ get_dtype(sb, fname->file_type));
++ if (error) {
++ filp->f_pos = curr_pos;
++ info->extra_fname = fname->next;
++ return error;
++ }
++ fname = fname->next;
++ }
++ return 0;
++}
++
++static int ext4_dx_readdir(struct file * filp,
++ void * dirent, filldir_t filldir)
++{
++ struct dir_private_info *info = filp->private_data;
++ struct inode *inode = filp->f_dentry->d_inode;
++ struct fname *fname;
++ int ret;
++
++ if (!info) {
++ info = create_dir_info(filp->f_pos);
++ if (!info)
++ return -ENOMEM;
++ filp->private_data = info;
++ }
++
++ if (filp->f_pos == EXT4_HTREE_EOF)
++ return 0; /* EOF */
++
++ /* Some one has messed with f_pos; reset the world */
++ if (info->last_pos != filp->f_pos) {
++ free_rb_tree_fname(&info->root);
++ info->curr_node = NULL;
++ info->extra_fname = NULL;
++ info->curr_hash = pos2maj_hash(filp->f_pos);
++ info->curr_minor_hash = pos2min_hash(filp->f_pos);
++ }
++
++ /*
++ * If there are any leftover names on the hash collision
++ * chain, return them first.
++ */
++ if (info->extra_fname &&
++ call_filldir(filp, dirent, filldir, info->extra_fname))
++ goto finished;
++
++ if (!info->curr_node)
++ info->curr_node = rb_first(&info->root);
++
++ while (1) {
++ /*
++ * Fill the rbtree if we have no more entries,
++ * or the inode has changed since we last read in the
++ * cached entries.
++ */
++ if ((!info->curr_node) ||
++ (filp->f_version != inode->i_version)) {
++ info->curr_node = NULL;
++ free_rb_tree_fname(&info->root);
++ filp->f_version = inode->i_version;
++ ret = ext4_htree_fill_tree(filp, info->curr_hash,
++ info->curr_minor_hash,
++ &info->next_hash);
++ if (ret < 0)
++ return ret;
++ if (ret == 0) {
++ filp->f_pos = EXT4_HTREE_EOF;
++ break;
++ }
++ info->curr_node = rb_first(&info->root);
++ }
++
++ fname = rb_entry(info->curr_node, struct fname, rb_hash);
++ info->curr_hash = fname->hash;
++ info->curr_minor_hash = fname->minor_hash;
++ if (call_filldir(filp, dirent, filldir, fname))
++ break;
++
++ info->curr_node = rb_next(info->curr_node);
++ if (!info->curr_node) {
++ if (info->next_hash == ~0) {
++ filp->f_pos = EXT4_HTREE_EOF;
++ break;
++ }
++ info->curr_hash = info->next_hash;
++ info->curr_minor_hash = 0;
++ }
++ }
++finished:
++ info->last_pos = filp->f_pos;
++ return 0;
++}
++
++static int ext4_release_dir (struct inode * inode, struct file * filp)
++{
++ if (filp->private_data)
++ ext4_htree_free_dir_info(filp->private_data);
++
++ return 0;
++}
++
++#endif
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+new file mode 100644
+index 0000000..2608dce
+--- /dev/null
++++ b/fs/ext4/extents.c
+@@ -0,0 +1,2152 @@
++/*
++ * Copyright (c) 2003-2006, Cluster File Systems, Inc, info at clusterfs.com
++ * Written by Alex Tomas <alex at clusterfs.com>
++ *
++ * Architecture independence:
++ * Copyright (c) 2005, Bull S.A.
++ * Written by Pierre Peiffer <pierre.peiffer at bull.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This 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 Licens
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
++ */
++
++/*
++ * Extents support for EXT4
++ *
++ * TODO:
++ * - ext4*_error() should be used in some situations
++ * - analyze all BUG()/BUG_ON(), use -EIO where appropriate
++ * - smart tree reduction
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/time.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/jbd.h>
++#include <linux/smp_lock.h>
++#include <linux/highuid.h>
++#include <linux/pagemap.h>
++#include <linux/quotaops.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/ext4_fs_extents.h>
++#include <asm/uaccess.h>
++
++
++/*
++ * ext_pblock:
++ * combine low and high parts of physical block number into ext4_fsblk_t
++ */
++static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
++{
++ ext4_fsblk_t block;
++
++ block = le32_to_cpu(ex->ee_start);
++ block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1;
++ return block;
++}
++
++/*
++ * idx_pblock:
++ * combine low and high parts of a leaf physical block number into ext4_fsblk_t
++ */
++static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix)
++{
++ ext4_fsblk_t block;
++
++ block = le32_to_cpu(ix->ei_leaf);
++ block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1;
++ return block;
++}
++
++/*
++ * ext4_ext_store_pblock:
++ * stores a large physical block number into an extent struct,
++ * breaking it into parts
++ */
++static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb)
++{
++ ex->ee_start = cpu_to_le32((unsigned long) (pb & 0xffffffff));
++ ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
++}
++
++/*
++ * ext4_idx_store_pblock:
++ * stores a large physical block number into an index struct,
++ * breaking it into parts
++ */
++static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
++{
++ ix->ei_leaf = cpu_to_le32((unsigned long) (pb & 0xffffffff));
++ ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
++}
++
++static int ext4_ext_check_header(const char *function, struct inode *inode,
++ struct ext4_extent_header *eh)
++{
++ const char *error_msg = NULL;
++
++ if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
++ error_msg = "invalid magic";
++ goto corrupted;
++ }
++ if (unlikely(eh->eh_max == 0)) {
++ error_msg = "invalid eh_max";
++ goto corrupted;
++ }
++ if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
++ error_msg = "invalid eh_entries";
++ goto corrupted;
++ }
++ return 0;
++
++corrupted:
++ ext4_error(inode->i_sb, function,
++ "bad header in inode #%lu: %s - magic %x, "
++ "entries %u, max %u, depth %u",
++ inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
++ le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
++ le16_to_cpu(eh->eh_depth));
++
++ return -EIO;
++}
++
++static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
++{
++ int err;
++
++ if (handle->h_buffer_credits > needed)
++ return handle;
++ if (!ext4_journal_extend(handle, needed))
++ return handle;
++ err = ext4_journal_restart(handle, needed);
++
++ return handle;
++}
++
++/*
++ * could return:
++ * - EROFS
++ * - ENOMEM
++ */
++static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path)
++{
++ if (path->p_bh) {
++ /* path points to block */
++ return ext4_journal_get_write_access(handle, path->p_bh);
++ }
++ /* path points to leaf/index in inode body */
++ /* we use in-core data, no need to protect them */
++ return 0;
++}
++
++/*
++ * could return:
++ * - EROFS
++ * - ENOMEM
++ * - EIO
++ */
++static int ext4_ext_dirty(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path)
++{
++ int err;
++ if (path->p_bh) {
++ /* path points to block */
++ err = ext4_journal_dirty_metadata(handle, path->p_bh);
++ } else {
++ /* path points to leaf/index in inode body */
++ err = ext4_mark_inode_dirty(handle, inode);
++ }
++ return err;
++}
++
++static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
++ struct ext4_ext_path *path,
++ ext4_fsblk_t block)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ ext4_fsblk_t bg_start;
++ ext4_grpblk_t colour;
++ int depth;
++
++ if (path) {
++ struct ext4_extent *ex;
++ depth = path->p_depth;
++
++ /* try to predict block placement */
++ if ((ex = path[depth].p_ext))
++ return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block));
++
++ /* it looks like index is empty;
++ * try to find starting block from index itself */
++ if (path[depth].p_bh)
++ return path[depth].p_bh->b_blocknr;
++ }
++
++ /* OK. use inode's group */
++ bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
++ le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);
++ colour = (current->pid % 16) *
++ (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
++ return bg_start + colour + block;
++}
++
++static ext4_fsblk_t
++ext4_ext_new_block(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path,
++ struct ext4_extent *ex, int *err)
++{
++ ext4_fsblk_t goal, newblock;
++
++ goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block));
++ newblock = ext4_new_block(handle, inode, goal, err);
++ return newblock;
++}
++
++static inline int ext4_ext_space_block(struct inode *inode)
++{
++ int size;
++
++ size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
++ / sizeof(struct ext4_extent);
++#ifdef AGRESSIVE_TEST
++ if (size > 6)
++ size = 6;
++#endif
++ return size;
++}
++
++static inline int ext4_ext_space_block_idx(struct inode *inode)
++{
++ int size;
++
++ size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
++ / sizeof(struct ext4_extent_idx);
++#ifdef AGRESSIVE_TEST
++ if (size > 5)
++ size = 5;
++#endif
++ return size;
++}
++
++static inline int ext4_ext_space_root(struct inode *inode)
++{
++ int size;
++
++ size = sizeof(EXT4_I(inode)->i_data);
++ size -= sizeof(struct ext4_extent_header);
++ size /= sizeof(struct ext4_extent);
++#ifdef AGRESSIVE_TEST
++ if (size > 3)
++ size = 3;
++#endif
++ return size;
++}
++
++static inline int ext4_ext_space_root_idx(struct inode *inode)
++{
++ int size;
++
++ size = sizeof(EXT4_I(inode)->i_data);
++ size -= sizeof(struct ext4_extent_header);
++ size /= sizeof(struct ext4_extent_idx);
++#ifdef AGRESSIVE_TEST
++ if (size > 4)
++ size = 4;
++#endif
++ return size;
++}
++
++#ifdef EXT_DEBUG
++static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
++{
++ int k, l = path->p_depth;
++
++ ext_debug("path:");
++ for (k = 0; k <= l; k++, path++) {
++ if (path->p_idx) {
++ ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block),
++ idx_pblock(path->p_idx));
++ } else if (path->p_ext) {
++ ext_debug(" %d:%d:%llu ",
++ le32_to_cpu(path->p_ext->ee_block),
++ le16_to_cpu(path->p_ext->ee_len),
++ ext_pblock(path->p_ext));
++ } else
++ ext_debug(" []");
++ }
++ ext_debug("\n");
++}
++
++static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
++{
++ int depth = ext_depth(inode);
++ struct ext4_extent_header *eh;
++ struct ext4_extent *ex;
++ int i;
++
++ if (!path)
++ return;
++
++ eh = path[depth].p_hdr;
++ ex = EXT_FIRST_EXTENT(eh);
++
++ for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
++ ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
++ le16_to_cpu(ex->ee_len), ext_pblock(ex));
++ }
++ ext_debug("\n");
++}
++#else
++#define ext4_ext_show_path(inode,path)
++#define ext4_ext_show_leaf(inode,path)
++#endif
++
++static void ext4_ext_drop_refs(struct ext4_ext_path *path)
++{
++ int depth = path->p_depth;
++ int i;
++
++ for (i = 0; i <= depth; i++, path++)
++ if (path->p_bh) {
++ brelse(path->p_bh);
++ path->p_bh = NULL;
++ }
++}
++
++/*
++ * ext4_ext_binsearch_idx:
++ * binary search for the closest index of the given block
++ */
++static void
++ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block)
++{
++ struct ext4_extent_header *eh = path->p_hdr;
++ struct ext4_extent_idx *r, *l, *m;
++
++ BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
++ BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
++ BUG_ON(le16_to_cpu(eh->eh_entries) <= 0);
++
++ ext_debug("binsearch for %d(idx): ", block);
++
++ l = EXT_FIRST_INDEX(eh) + 1;
++ r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1;
++ while (l <= r) {
++ m = l + (r - l) / 2;
++ if (block < le32_to_cpu(m->ei_block))
++ r = m - 1;
++ else
++ l = m + 1;
++ ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block,
++ m, m->ei_block, r, r->ei_block);
++ }
++
++ path->p_idx = l - 1;
++ ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
++ idx_block(path->p_idx));
++
++#ifdef CHECK_BINSEARCH
++ {
++ struct ext4_extent_idx *chix, *ix;
++ int k;
++
++ chix = ix = EXT_FIRST_INDEX(eh);
++ for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {
++ if (k != 0 &&
++ le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {
++ printk("k=%d, ix=0x%p, first=0x%p\n", k,
++ ix, EXT_FIRST_INDEX(eh));
++ printk("%u <= %u\n",
++ le32_to_cpu(ix->ei_block),
++ le32_to_cpu(ix[-1].ei_block));
++ }
++ BUG_ON(k && le32_to_cpu(ix->ei_block)
++ <= le32_to_cpu(ix[-1].ei_block));
++ if (block < le32_to_cpu(ix->ei_block))
++ break;
++ chix = ix;
++ }
++ BUG_ON(chix != path->p_idx);
++ }
++#endif
++
++}
++
++/*
++ * ext4_ext_binsearch:
++ * binary search for closest extent of the given block
++ */
++static void
++ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
++{
++ struct ext4_extent_header *eh = path->p_hdr;
++ struct ext4_extent *r, *l, *m;
++
++ BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
++ BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
++
++ if (eh->eh_entries == 0) {
++ /*
++ * this leaf is empty:
++ * we get such a leaf in split/add case
++ */
++ return;
++ }
++
++ ext_debug("binsearch for %d: ", block);
++
++ l = EXT_FIRST_EXTENT(eh) + 1;
++ r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1;
++
++ while (l <= r) {
++ m = l + (r - l) / 2;
++ if (block < le32_to_cpu(m->ee_block))
++ r = m - 1;
++ else
++ l = m + 1;
++ ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block,
++ m, m->ee_block, r, r->ee_block);
++ }
++
++ path->p_ext = l - 1;
++ ext_debug(" -> %d:%llu:%d ",
++ le32_to_cpu(path->p_ext->ee_block),
++ ext_pblock(path->p_ext),
++ le16_to_cpu(path->p_ext->ee_len));
++
++#ifdef CHECK_BINSEARCH
++ {
++ struct ext4_extent *chex, *ex;
++ int k;
++
++ chex = ex = EXT_FIRST_EXTENT(eh);
++ for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) {
++ BUG_ON(k && le32_to_cpu(ex->ee_block)
++ <= le32_to_cpu(ex[-1].ee_block));
++ if (block < le32_to_cpu(ex->ee_block))
++ break;
++ chex = ex;
++ }
++ BUG_ON(chex != path->p_ext);
++ }
++#endif
++
++}
++
++int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
++{
++ struct ext4_extent_header *eh;
++
++ eh = ext_inode_hdr(inode);
++ eh->eh_depth = 0;
++ eh->eh_entries = 0;
++ eh->eh_magic = EXT4_EXT_MAGIC;
++ eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode));
++ ext4_mark_inode_dirty(handle, inode);
++ ext4_ext_invalidate_cache(inode);
++ return 0;
++}
++
++struct ext4_ext_path *
++ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
++{
++ struct ext4_extent_header *eh;
++ struct buffer_head *bh;
++ short int depth, i, ppos = 0, alloc = 0;
++
++ eh = ext_inode_hdr(inode);
++ BUG_ON(eh == NULL);
++ if (ext4_ext_check_header(__FUNCTION__, inode, eh))
++ return ERR_PTR(-EIO);
++
++ i = depth = ext_depth(inode);
++
++ /* account possible depth increase */
++ if (!path) {
++ path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 2),
++ GFP_NOFS);
++ if (!path)
++ return ERR_PTR(-ENOMEM);
++ alloc = 1;
++ }
++ memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
++ path[0].p_hdr = eh;
++
++ /* walk through the tree */
++ while (i) {
++ ext_debug("depth %d: num %d, max %d\n",
++ ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
++ ext4_ext_binsearch_idx(inode, path + ppos, block);
++ path[ppos].p_block = idx_pblock(path[ppos].p_idx);
++ path[ppos].p_depth = i;
++ path[ppos].p_ext = NULL;
++
++ bh = sb_bread(inode->i_sb, path[ppos].p_block);
++ if (!bh)
++ goto err;
++
++ eh = ext_block_hdr(bh);
++ ppos++;
++ BUG_ON(ppos > depth);
++ path[ppos].p_bh = bh;
++ path[ppos].p_hdr = eh;
++ i--;
++
++ if (ext4_ext_check_header(__FUNCTION__, inode, eh))
++ goto err;
++ }
++
++ path[ppos].p_depth = i;
++ path[ppos].p_hdr = eh;
++ path[ppos].p_ext = NULL;
++ path[ppos].p_idx = NULL;
++
++ if (ext4_ext_check_header(__FUNCTION__, inode, eh))
++ goto err;
++
++ /* find extent */
++ ext4_ext_binsearch(inode, path + ppos, block);
++
++ ext4_ext_show_path(inode, path);
++
++ return path;
++
++err:
++ ext4_ext_drop_refs(path);
++ if (alloc)
++ kfree(path);
++ return ERR_PTR(-EIO);
++}
++
++/*
++ * ext4_ext_insert_index:
++ * insert new index [@logical;@ptr] into the block at @curp;
++ * check where to insert: before @curp or after @curp
++ */
++static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *curp,
++ int logical, ext4_fsblk_t ptr)
++{
++ struct ext4_extent_idx *ix;
++ int len, err;
++
++ if ((err = ext4_ext_get_access(handle, inode, curp)))
++ return err;
++
++ BUG_ON(logical == le32_to_cpu(curp->p_idx->ei_block));
++ len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx;
++ if (logical > le32_to_cpu(curp->p_idx->ei_block)) {
++ /* insert after */
++ if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
++ len = (len - 1) * sizeof(struct ext4_extent_idx);
++ len = len < 0 ? 0 : len;
++ ext_debug("insert new index %d after: %d. "
++ "move %d from 0x%p to 0x%p\n",
++ logical, ptr, len,
++ (curp->p_idx + 1), (curp->p_idx + 2));
++ memmove(curp->p_idx + 2, curp->p_idx + 1, len);
++ }
++ ix = curp->p_idx + 1;
++ } else {
++ /* insert before */
++ len = len * sizeof(struct ext4_extent_idx);
++ len = len < 0 ? 0 : len;
++ ext_debug("insert new index %d before: %d. "
++ "move %d from 0x%p to 0x%p\n",
++ logical, ptr, len,
++ curp->p_idx, (curp->p_idx + 1));
++ memmove(curp->p_idx + 1, curp->p_idx, len);
++ ix = curp->p_idx;
++ }
++
++ ix->ei_block = cpu_to_le32(logical);
++ ext4_idx_store_pblock(ix, ptr);
++ curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1);
++
++ BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries)
++ > le16_to_cpu(curp->p_hdr->eh_max));
++ BUG_ON(ix > EXT_LAST_INDEX(curp->p_hdr));
++
++ err = ext4_ext_dirty(handle, inode, curp);
++ ext4_std_error(inode->i_sb, err);
++
++ return err;
++}
++
++/*
++ * ext4_ext_split:
++ * inserts new subtree into the path, using free index entry
++ * at depth @at:
++ * - allocates all needed blocks (new leaf and all intermediate index blocks)
++ * - makes decision where to split
++ * - moves remaining extents and index entries (right to the split point)
++ * into the newly allocated blocks
++ * - initializes subtree
++ */
++static int ext4_ext_split(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path,
++ struct ext4_extent *newext, int at)
++{
++ struct buffer_head *bh = NULL;
++ int depth = ext_depth(inode);
++ struct ext4_extent_header *neh;
++ struct ext4_extent_idx *fidx;
++ struct ext4_extent *ex;
++ int i = at, k, m, a;
++ ext4_fsblk_t newblock, oldblock;
++ __le32 border;
++ ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
++ int err = 0;
++
++ /* make decision: where to split? */
++ /* FIXME: now decision is simplest: at current extent */
++
++ /* if current leaf will be split, then we should use
++ * border from split point */
++ BUG_ON(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr));
++ if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) {
++ border = path[depth].p_ext[1].ee_block;
++ ext_debug("leaf will be split."
++ " next leaf starts at %d\n",
++ le32_to_cpu(border));
++ } else {
++ border = newext->ee_block;
++ ext_debug("leaf will be added."
++ " next leaf starts at %d\n",
++ le32_to_cpu(border));
++ }
++
++ /*
++ * If error occurs, then we break processing
++ * and mark filesystem read-only. index won't
++ * be inserted and tree will be in consistent
++ * state. Next mount will repair buffers too.
++ */
++
++ /*
++ * Get array to track all allocated blocks.
++ * We need this to handle errors and free blocks
++ * upon them.
++ */
++ ablocks = kmalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS);
++ if (!ablocks)
++ return -ENOMEM;
++ memset(ablocks, 0, sizeof(ext4_fsblk_t) * depth);
++
++ /* allocate all needed blocks */
++ ext_debug("allocate %d blocks for indexes/leaf\n", depth - at);
++ for (a = 0; a < depth - at; a++) {
++ newblock = ext4_ext_new_block(handle, inode, path, newext, &err);
++ if (newblock == 0)
++ goto cleanup;
++ ablocks[a] = newblock;
++ }
++
++ /* initialize new leaf */
++ newblock = ablocks[--a];
++ BUG_ON(newblock == 0);
++ bh = sb_getblk(inode->i_sb, newblock);
++ if (!bh) {
++ err = -EIO;
++ goto cleanup;
++ }
++ lock_buffer(bh);
++
++ if ((err = ext4_journal_get_create_access(handle, bh)))
++ goto cleanup;
++
++ neh = ext_block_hdr(bh);
++ neh->eh_entries = 0;
++ neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode));
++ neh->eh_magic = EXT4_EXT_MAGIC;
++ neh->eh_depth = 0;
++ ex = EXT_FIRST_EXTENT(neh);
++
++ /* move remainder of path[depth] to the new leaf */
++ BUG_ON(path[depth].p_hdr->eh_entries != path[depth].p_hdr->eh_max);
++ /* start copy from next extent */
++ /* TODO: we could do it by single memmove */
++ m = 0;
++ path[depth].p_ext++;
++ while (path[depth].p_ext <=
++ EXT_MAX_EXTENT(path[depth].p_hdr)) {
++ ext_debug("move %d:%llu:%d in new leaf %llu\n",
++ le32_to_cpu(path[depth].p_ext->ee_block),
++ ext_pblock(path[depth].p_ext),
++ le16_to_cpu(path[depth].p_ext->ee_len),
++ newblock);
++ /*memmove(ex++, path[depth].p_ext++,
++ sizeof(struct ext4_extent));
++ neh->eh_entries++;*/
++ path[depth].p_ext++;
++ m++;
++ }
++ if (m) {
++ memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m);
++ neh->eh_entries = cpu_to_le16(le16_to_cpu(neh->eh_entries)+m);
++ }
++
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++
++ if ((err = ext4_journal_dirty_metadata(handle, bh)))
++ goto cleanup;
++ brelse(bh);
++ bh = NULL;
++
++ /* correct old leaf */
++ if (m) {
++ if ((err = ext4_ext_get_access(handle, inode, path + depth)))
++ goto cleanup;
++ path[depth].p_hdr->eh_entries =
++ cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m);
++ if ((err = ext4_ext_dirty(handle, inode, path + depth)))
++ goto cleanup;
++
++ }
++
++ /* create intermediate indexes */
++ k = depth - at - 1;
++ BUG_ON(k < 0);
++ if (k)
++ ext_debug("create %d intermediate indices\n", k);
++ /* insert new index into current index block */
++ /* current depth stored in i var */
++ i = depth - 1;
++ while (k--) {
++ oldblock = newblock;
++ newblock = ablocks[--a];
++ bh = sb_getblk(inode->i_sb, (ext4_fsblk_t)newblock);
++ if (!bh) {
++ err = -EIO;
++ goto cleanup;
++ }
++ lock_buffer(bh);
++
++ if ((err = ext4_journal_get_create_access(handle, bh)))
++ goto cleanup;
++
++ neh = ext_block_hdr(bh);
++ neh->eh_entries = cpu_to_le16(1);
++ neh->eh_magic = EXT4_EXT_MAGIC;
++ neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode));
++ neh->eh_depth = cpu_to_le16(depth - i);
++ fidx = EXT_FIRST_INDEX(neh);
++ fidx->ei_block = border;
++ ext4_idx_store_pblock(fidx, oldblock);
++
++ ext_debug("int.index at %d (block %llu): %lu -> %llu\n", i,
++ newblock, (unsigned long) le32_to_cpu(border),
++ oldblock);
++ /* copy indexes */
++ m = 0;
++ path[i].p_idx++;
++
++ ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx,
++ EXT_MAX_INDEX(path[i].p_hdr));
++ BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) !=
++ EXT_LAST_INDEX(path[i].p_hdr));
++ while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
++ ext_debug("%d: move %d:%d in new index %llu\n", i,
++ le32_to_cpu(path[i].p_idx->ei_block),
++ idx_pblock(path[i].p_idx),
++ newblock);
++ /*memmove(++fidx, path[i].p_idx++,
++ sizeof(struct ext4_extent_idx));
++ neh->eh_entries++;
++ BUG_ON(neh->eh_entries > neh->eh_max);*/
++ path[i].p_idx++;
++ m++;
++ }
++ if (m) {
++ memmove(++fidx, path[i].p_idx - m,
++ sizeof(struct ext4_extent_idx) * m);
++ neh->eh_entries =
++ cpu_to_le16(le16_to_cpu(neh->eh_entries) + m);
++ }
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++
++ if ((err = ext4_journal_dirty_metadata(handle, bh)))
++ goto cleanup;
++ brelse(bh);
++ bh = NULL;
++
++ /* correct old index */
++ if (m) {
++ err = ext4_ext_get_access(handle, inode, path + i);
++ if (err)
++ goto cleanup;
++ path[i].p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path[i].p_hdr->eh_entries)-m);
++ err = ext4_ext_dirty(handle, inode, path + i);
++ if (err)
++ goto cleanup;
++ }
++
++ i--;
++ }
++
++ /* insert new index */
++ if (err)
++ goto cleanup;
++
++ err = ext4_ext_insert_index(handle, inode, path + at,
++ le32_to_cpu(border), newblock);
++
++cleanup:
++ if (bh) {
++ if (buffer_locked(bh))
++ unlock_buffer(bh);
++ brelse(bh);
++ }
++
++ if (err) {
++ /* free all allocated blocks in error case */
++ for (i = 0; i < depth; i++) {
++ if (!ablocks[i])
++ continue;
++ ext4_free_blocks(handle, inode, ablocks[i], 1);
++ }
++ }
++ kfree(ablocks);
++
++ return err;
++}
++
++/*
++ * ext4_ext_grow_indepth:
++ * implements tree growing procedure:
++ * - allocates new block
++ * - moves top-level data (index block or leaf) into the new block
++ * - initializes new top-level, creating index that points to the
++ * just created block
++ */
++static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path,
++ struct ext4_extent *newext)
++{
++ struct ext4_ext_path *curp = path;
++ struct ext4_extent_header *neh;
++ struct ext4_extent_idx *fidx;
++ struct buffer_head *bh;
++ ext4_fsblk_t newblock;
++ int err = 0;
++
++ newblock = ext4_ext_new_block(handle, inode, path, newext, &err);
++ if (newblock == 0)
++ return err;
++
++ bh = sb_getblk(inode->i_sb, newblock);
++ if (!bh) {
++ err = -EIO;
++ ext4_std_error(inode->i_sb, err);
++ return err;
++ }
++ lock_buffer(bh);
++
++ if ((err = ext4_journal_get_create_access(handle, bh))) {
++ unlock_buffer(bh);
++ goto out;
++ }
++
++ /* move top-level index/leaf into new block */
++ memmove(bh->b_data, curp->p_hdr, sizeof(EXT4_I(inode)->i_data));
++
++ /* set size of new block */
++ neh = ext_block_hdr(bh);
++ /* old root could have indexes or leaves
++ * so calculate e_max right way */
++ if (ext_depth(inode))
++ neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode));
++ else
++ neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode));
++ neh->eh_magic = EXT4_EXT_MAGIC;
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++
++ if ((err = ext4_journal_dirty_metadata(handle, bh)))
++ goto out;
++
++ /* create index in new top-level index: num,max,pointer */
++ if ((err = ext4_ext_get_access(handle, inode, curp)))
++ goto out;
++
++ curp->p_hdr->eh_magic = EXT4_EXT_MAGIC;
++ curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
++ curp->p_hdr->eh_entries = cpu_to_le16(1);
++ curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
++ /* FIXME: it works, but actually path[0] can be index */
++ curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
++ ext4_idx_store_pblock(curp->p_idx, newblock);
++
++ neh = ext_inode_hdr(inode);
++ fidx = EXT_FIRST_INDEX(neh);
++ ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n",
++ le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max),
++ le32_to_cpu(fidx->ei_block), idx_pblock(fidx));
++
++ neh->eh_depth = cpu_to_le16(path->p_depth + 1);
++ err = ext4_ext_dirty(handle, inode, curp);
++out:
++ brelse(bh);
++
++ return err;
++}
++
++/*
++ * ext4_ext_create_new_leaf:
++ * finds empty index and adds new leaf.
++ * if no free index is found, then it requests in-depth growing.
++ */
++static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path,
++ struct ext4_extent *newext)
++{
++ struct ext4_ext_path *curp;
++ int depth, i, err = 0;
++
++repeat:
++ i = depth = ext_depth(inode);
++
++ /* walk up to the tree and look for free index entry */
++ curp = path + depth;
++ while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) {
++ i--;
++ curp--;
++ }
++
++ /* we use already allocated block for index block,
++ * so subsequent data blocks should be contiguous */
++ if (EXT_HAS_FREE_INDEX(curp)) {
++ /* if we found index with free entry, then use that
++ * entry: create all needed subtree and add new leaf */
++ err = ext4_ext_split(handle, inode, path, newext, i);
++
++ /* refill path */
++ ext4_ext_drop_refs(path);
++ path = ext4_ext_find_extent(inode,
++ le32_to_cpu(newext->ee_block),
++ path);
++ if (IS_ERR(path))
++ err = PTR_ERR(path);
++ } else {
++ /* tree is full, time to grow in depth */
++ err = ext4_ext_grow_indepth(handle, inode, path, newext);
++ if (err)
++ goto out;
++
++ /* refill path */
++ ext4_ext_drop_refs(path);
++ path = ext4_ext_find_extent(inode,
++ le32_to_cpu(newext->ee_block),
++ path);
++ if (IS_ERR(path)) {
++ err = PTR_ERR(path);
++ goto out;
++ }
++
++ /*
++ * only first (depth 0 -> 1) produces free space;
++ * in all other cases we have to split the grown tree
++ */
++ depth = ext_depth(inode);
++ if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {
++ /* now we need to split */
++ goto repeat;
++ }
++ }
++
++out:
++ return err;
++}
++
++/*
++ * ext4_ext_next_allocated_block:
++ * returns allocated block in subsequent extent or EXT_MAX_BLOCK.
++ * NOTE: it considers block number from index entry as
++ * allocated block. Thus, index entries have to be consistent
++ * with leaves.
++ */
++static unsigned long
++ext4_ext_next_allocated_block(struct ext4_ext_path *path)
++{
++ int depth;
++
++ BUG_ON(path == NULL);
++ depth = path->p_depth;
++
++ if (depth == 0 && path->p_ext == NULL)
++ return EXT_MAX_BLOCK;
++
++ while (depth >= 0) {
++ if (depth == path->p_depth) {
++ /* leaf */
++ if (path[depth].p_ext !=
++ EXT_LAST_EXTENT(path[depth].p_hdr))
++ return le32_to_cpu(path[depth].p_ext[1].ee_block);
++ } else {
++ /* index */
++ if (path[depth].p_idx !=
++ EXT_LAST_INDEX(path[depth].p_hdr))
++ return le32_to_cpu(path[depth].p_idx[1].ei_block);
++ }
++ depth--;
++ }
++
++ return EXT_MAX_BLOCK;
++}
++
++/*
++ * ext4_ext_next_leaf_block:
++ * returns first allocated block from next leaf or EXT_MAX_BLOCK
++ */
++static unsigned ext4_ext_next_leaf_block(struct inode *inode,
++ struct ext4_ext_path *path)
++{
++ int depth;
++
++ BUG_ON(path == NULL);
++ depth = path->p_depth;
++
++ /* zero-tree has no leaf blocks at all */
++ if (depth == 0)
++ return EXT_MAX_BLOCK;
++
++ /* go to index block */
++ depth--;
++
++ while (depth >= 0) {
++ if (path[depth].p_idx !=
++ EXT_LAST_INDEX(path[depth].p_hdr))
++ return le32_to_cpu(path[depth].p_idx[1].ei_block);
++ depth--;
++ }
++
++ return EXT_MAX_BLOCK;
++}
++
++/*
++ * ext4_ext_correct_indexes:
++ * if leaf gets modified and modified extent is first in the leaf,
++ * then we have to correct all indexes above.
++ * TODO: do we need to correct tree in all cases?
++ */
++int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path)
++{
++ struct ext4_extent_header *eh;
++ int depth = ext_depth(inode);
++ struct ext4_extent *ex;
++ __le32 border;
++ int k, err = 0;
++
++ eh = path[depth].p_hdr;
++ ex = path[depth].p_ext;
++ BUG_ON(ex == NULL);
++ BUG_ON(eh == NULL);
++
++ if (depth == 0) {
++ /* there is no tree at all */
++ return 0;
++ }
++
++ if (ex != EXT_FIRST_EXTENT(eh)) {
++ /* we correct tree if first leaf got modified only */
++ return 0;
++ }
++
++ /*
++ * TODO: we need correction if border is smaller than current one
++ */
++ k = depth - 1;
++ border = path[depth].p_ext->ee_block;
++ if ((err = ext4_ext_get_access(handle, inode, path + k)))
++ return err;
++ path[k].p_idx->ei_block = border;
++ if ((err = ext4_ext_dirty(handle, inode, path + k)))
++ return err;
++
++ while (k--) {
++ /* change all left-side indexes */
++ if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
++ break;
++ if ((err = ext4_ext_get_access(handle, inode, path + k)))
++ break;
++ path[k].p_idx->ei_block = border;
++ if ((err = ext4_ext_dirty(handle, inode, path + k)))
++ break;
++ }
++
++ return err;
++}
++
++static int inline
++ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
++ struct ext4_extent *ex2)
++{
++ if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) !=
++ le32_to_cpu(ex2->ee_block))
++ return 0;
++
++ /*
++ * To allow future support for preallocated extents to be added
++ * as an RO_COMPAT feature, refuse to merge to extents if
++ * this can result in the top bit of ee_len being set.
++ */
++ if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
++ return 0;
++#ifdef AGRESSIVE_TEST
++ if (le16_to_cpu(ex1->ee_len) >= 4)
++ return 0;
++#endif
++
++ if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2))
++ return 1;
++ return 0;
++}
++
++/*
++ * ext4_ext_insert_extent:
++ * tries to merge requsted extent into the existing extent or
++ * inserts requested extent as new one into the tree,
++ * creating new leaf in the no-space case.
++ */
++int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path,
++ struct ext4_extent *newext)
++{
++ struct ext4_extent_header * eh;
++ struct ext4_extent *ex, *fex;
++ struct ext4_extent *nearex; /* nearest extent */
++ struct ext4_ext_path *npath = NULL;
++ int depth, len, err, next;
++
++ BUG_ON(newext->ee_len == 0);
++ depth = ext_depth(inode);
++ ex = path[depth].p_ext;
++ BUG_ON(path[depth].p_hdr == NULL);
++
++ /* try to insert block into found extent and return */
++ if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
++ ext_debug("append %d block to %d:%d (from %llu)\n",
++ le16_to_cpu(newext->ee_len),
++ le32_to_cpu(ex->ee_block),
++ le16_to_cpu(ex->ee_len), ext_pblock(ex));
++ if ((err = ext4_ext_get_access(handle, inode, path + depth)))
++ return err;
++ ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
++ + le16_to_cpu(newext->ee_len));
++ eh = path[depth].p_hdr;
++ nearex = ex;
++ goto merge;
++ }
++
++repeat:
++ depth = ext_depth(inode);
++ eh = path[depth].p_hdr;
++ if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))
++ goto has_space;
++
++ /* probably next leaf has space for us? */
++ fex = EXT_LAST_EXTENT(eh);
++ next = ext4_ext_next_leaf_block(inode, path);
++ if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)
++ && next != EXT_MAX_BLOCK) {
++ ext_debug("next leaf block - %d\n", next);
++ BUG_ON(npath != NULL);
++ npath = ext4_ext_find_extent(inode, next, NULL);
++ if (IS_ERR(npath))
++ return PTR_ERR(npath);
++ BUG_ON(npath->p_depth != path->p_depth);
++ eh = npath[depth].p_hdr;
++ if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) {
++ ext_debug("next leaf isnt full(%d)\n",
++ le16_to_cpu(eh->eh_entries));
++ path = npath;
++ goto repeat;
++ }
++ ext_debug("next leaf has no free space(%d,%d)\n",
++ le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
++ }
++
++ /*
++ * There is no free space in the found leaf.
++ * We're gonna add a new leaf in the tree.
++ */
++ err = ext4_ext_create_new_leaf(handle, inode, path, newext);
++ if (err)
++ goto cleanup;
++ depth = ext_depth(inode);
++ eh = path[depth].p_hdr;
++
++has_space:
++ nearex = path[depth].p_ext;
++
++ if ((err = ext4_ext_get_access(handle, inode, path + depth)))
++ goto cleanup;
++
++ if (!nearex) {
++ /* there is no extent in this leaf, create first one */
++ ext_debug("first extent in the leaf: %d:%llu:%d\n",
++ le32_to_cpu(newext->ee_block),
++ ext_pblock(newext),
++ le16_to_cpu(newext->ee_len));
++ path[depth].p_ext = EXT_FIRST_EXTENT(eh);
++ } else if (le32_to_cpu(newext->ee_block)
++ > le32_to_cpu(nearex->ee_block)) {
++/* BUG_ON(newext->ee_block == nearex->ee_block); */
++ if (nearex != EXT_LAST_EXTENT(eh)) {
++ len = EXT_MAX_EXTENT(eh) - nearex;
++ len = (len - 1) * sizeof(struct ext4_extent);
++ len = len < 0 ? 0 : len;
++ ext_debug("insert %d:%llu:%d after: nearest 0x%p, "
++ "move %d from 0x%p to 0x%p\n",
++ le32_to_cpu(newext->ee_block),
++ ext_pblock(newext),
++ le16_to_cpu(newext->ee_len),
++ nearex, len, nearex + 1, nearex + 2);
++ memmove(nearex + 2, nearex + 1, len);
++ }
++ path[depth].p_ext = nearex + 1;
++ } else {
++ BUG_ON(newext->ee_block == nearex->ee_block);
++ len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent);
++ len = len < 0 ? 0 : len;
++ ext_debug("insert %d:%llu:%d before: nearest 0x%p, "
++ "move %d from 0x%p to 0x%p\n",
++ le32_to_cpu(newext->ee_block),
++ ext_pblock(newext),
++ le16_to_cpu(newext->ee_len),
++ nearex, len, nearex + 1, nearex + 2);
++ memmove(nearex + 1, nearex, len);
++ path[depth].p_ext = nearex;
++ }
++
++ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1);
++ nearex = path[depth].p_ext;
++ nearex->ee_block = newext->ee_block;
++ nearex->ee_start = newext->ee_start;
++ nearex->ee_start_hi = newext->ee_start_hi;
++ nearex->ee_len = newext->ee_len;
++
++merge:
++ /* try to merge extents to the right */
++ while (nearex < EXT_LAST_EXTENT(eh)) {
++ if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1))
++ break;
++ /* merge with next extent! */
++ nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len)
++ + le16_to_cpu(nearex[1].ee_len));
++ if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
++ len = (EXT_LAST_EXTENT(eh) - nearex - 1)
++ * sizeof(struct ext4_extent);
++ memmove(nearex + 1, nearex + 2, len);
++ }
++ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
++ BUG_ON(eh->eh_entries == 0);
++ }
++
++ /* try to merge extents to the left */
++
++ /* time to correct all indexes above */
++ err = ext4_ext_correct_indexes(handle, inode, path);
++ if (err)
++ goto cleanup;
++
++ err = ext4_ext_dirty(handle, inode, path + depth);
++
++cleanup:
++ if (npath) {
++ ext4_ext_drop_refs(npath);
++ kfree(npath);
++ }
++ ext4_ext_tree_changed(inode);
++ ext4_ext_invalidate_cache(inode);
++ return err;
++}
++
++int ext4_ext_walk_space(struct inode *inode, unsigned long block,
++ unsigned long num, ext_prepare_callback func,
++ void *cbdata)
++{
++ struct ext4_ext_path *path = NULL;
++ struct ext4_ext_cache cbex;
++ struct ext4_extent *ex;
++ unsigned long next, start = 0, end = 0;
++ unsigned long last = block + num;
++ int depth, exists, err = 0;
++
++ BUG_ON(func == NULL);
++ BUG_ON(inode == NULL);
++
++ while (block < last && block != EXT_MAX_BLOCK) {
++ num = last - block;
++ /* find extent for this block */
++ path = ext4_ext_find_extent(inode, block, path);
++ if (IS_ERR(path)) {
++ err = PTR_ERR(path);
++ path = NULL;
++ break;
++ }
++
++ depth = ext_depth(inode);
++ BUG_ON(path[depth].p_hdr == NULL);
++ ex = path[depth].p_ext;
++ next = ext4_ext_next_allocated_block(path);
++
++ exists = 0;
++ if (!ex) {
++ /* there is no extent yet, so try to allocate
++ * all requested space */
++ start = block;
++ end = block + num;
++ } else if (le32_to_cpu(ex->ee_block) > block) {
++ /* need to allocate space before found extent */
++ start = block;
++ end = le32_to_cpu(ex->ee_block);
++ if (block + num < end)
++ end = block + num;
++ } else if (block >=
++ le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) {
++ /* need to allocate space after found extent */
++ start = block;
++ end = block + num;
++ if (end >= next)
++ end = next;
++ } else if (block >= le32_to_cpu(ex->ee_block)) {
++ /*
++ * some part of requested space is covered
++ * by found extent
++ */
++ start = block;
++ end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len);
++ if (block + num < end)
++ end = block + num;
++ exists = 1;
++ } else {
++ BUG();
++ }
++ BUG_ON(end <= start);
++
++ if (!exists) {
++ cbex.ec_block = start;
++ cbex.ec_len = end - start;
++ cbex.ec_start = 0;
++ cbex.ec_type = EXT4_EXT_CACHE_GAP;
++ } else {
++ cbex.ec_block = le32_to_cpu(ex->ee_block);
++ cbex.ec_len = le16_to_cpu(ex->ee_len);
++ cbex.ec_start = ext_pblock(ex);
++ cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
++ }
++
++ BUG_ON(cbex.ec_len == 0);
++ err = func(inode, path, &cbex, cbdata);
++ ext4_ext_drop_refs(path);
++
++ if (err < 0)
++ break;
++ if (err == EXT_REPEAT)
++ continue;
++ else if (err == EXT_BREAK) {
++ err = 0;
++ break;
++ }
++
++ if (ext_depth(inode) != depth) {
++ /* depth was changed. we have to realloc path */
++ kfree(path);
++ path = NULL;
++ }
++
++ block = cbex.ec_block + cbex.ec_len;
++ }
++
++ if (path) {
++ ext4_ext_drop_refs(path);
++ kfree(path);
++ }
++
++ return err;
++}
++
++static inline void
++ext4_ext_put_in_cache(struct inode *inode, __u32 block,
++ __u32 len, __u32 start, int type)
++{
++ struct ext4_ext_cache *cex;
++ BUG_ON(len == 0);
++ cex = &EXT4_I(inode)->i_cached_extent;
++ cex->ec_type = type;
++ cex->ec_block = block;
++ cex->ec_len = len;
++ cex->ec_start = start;
++}
++
++/*
++ * ext4_ext_put_gap_in_cache:
++ * calculate boundaries of the gap that the requested block fits into
++ * and cache this gap
++ */
++static inline void
++ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
++ unsigned long block)
++{
++ int depth = ext_depth(inode);
++ unsigned long lblock, len;
++ struct ext4_extent *ex;
++
++ ex = path[depth].p_ext;
++ if (ex == NULL) {
++ /* there is no extent yet, so gap is [0;-] */
++ lblock = 0;
++ len = EXT_MAX_BLOCK;
++ ext_debug("cache gap(whole file):");
++ } else if (block < le32_to_cpu(ex->ee_block)) {
++ lblock = block;
++ len = le32_to_cpu(ex->ee_block) - block;
++ ext_debug("cache gap(before): %lu [%lu:%lu]",
++ (unsigned long) block,
++ (unsigned long) le32_to_cpu(ex->ee_block),
++ (unsigned long) le16_to_cpu(ex->ee_len));
++ } else if (block >= le32_to_cpu(ex->ee_block)
++ + le16_to_cpu(ex->ee_len)) {
++ lblock = le32_to_cpu(ex->ee_block)
++ + le16_to_cpu(ex->ee_len);
++ len = ext4_ext_next_allocated_block(path);
++ ext_debug("cache gap(after): [%lu:%lu] %lu",
++ (unsigned long) le32_to_cpu(ex->ee_block),
++ (unsigned long) le16_to_cpu(ex->ee_len),
++ (unsigned long) block);
++ BUG_ON(len == lblock);
++ len = len - lblock;
++ } else {
++ lblock = len = 0;
++ BUG();
++ }
++
++ ext_debug(" -> %lu:%lu\n", (unsigned long) lblock, len);
++ ext4_ext_put_in_cache(inode, lblock, len, 0, EXT4_EXT_CACHE_GAP);
++}
++
++static inline int
++ext4_ext_in_cache(struct inode *inode, unsigned long block,
++ struct ext4_extent *ex)
++{
++ struct ext4_ext_cache *cex;
++
++ cex = &EXT4_I(inode)->i_cached_extent;
++
++ /* has cache valid data? */
++ if (cex->ec_type == EXT4_EXT_CACHE_NO)
++ return EXT4_EXT_CACHE_NO;
++
++ BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
++ cex->ec_type != EXT4_EXT_CACHE_EXTENT);
++ if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) {
++ ex->ee_block = cpu_to_le32(cex->ec_block);
++ ext4_ext_store_pblock(ex, cex->ec_start);
++ ex->ee_len = cpu_to_le16(cex->ec_len);
++ ext_debug("%lu cached by %lu:%lu:%llu\n",
++ (unsigned long) block,
++ (unsigned long) cex->ec_block,
++ (unsigned long) cex->ec_len,
++ cex->ec_start);
++ return cex->ec_type;
++ }
++
++ /* not in cache */
++ return EXT4_EXT_CACHE_NO;
++}
++
++/*
++ * ext4_ext_rm_idx:
++ * removes index from the index block.
++ * It's used in truncate case only, thus all requests are for
++ * last index in the block only.
++ */
++int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path)
++{
++ struct buffer_head *bh;
++ int err;
++ ext4_fsblk_t leaf;
++
++ /* free index block */
++ path--;
++ leaf = idx_pblock(path->p_idx);
++ BUG_ON(path->p_hdr->eh_entries == 0);
++ if ((err = ext4_ext_get_access(handle, inode, path)))
++ return err;
++ path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
++ if ((err = ext4_ext_dirty(handle, inode, path)))
++ return err;
++ ext_debug("index is empty, remove it, free block %llu\n", leaf);
++ bh = sb_find_get_block(inode->i_sb, leaf);
++ ext4_forget(handle, 1, inode, bh, leaf);
++ ext4_free_blocks(handle, inode, leaf, 1);
++ return err;
++}
++
++/*
++ * ext4_ext_calc_credits_for_insert:
++ * This routine returns max. credits that the extent tree can consume.
++ * It should be OK for low-performance paths like ->writepage()
++ * To allow many writing processes to fit into a single transaction,
++ * the caller should calculate credits under truncate_mutex and
++ * pass the actual path.
++ */
++int inline ext4_ext_calc_credits_for_insert(struct inode *inode,
++ struct ext4_ext_path *path)
++{
++ int depth, needed;
++
++ if (path) {
++ /* probably there is space in leaf? */
++ depth = ext_depth(inode);
++ if (le16_to_cpu(path[depth].p_hdr->eh_entries)
++ < le16_to_cpu(path[depth].p_hdr->eh_max))
++ return 1;
++ }
++
++ /*
++ * given 32-bit logical block (4294967296 blocks), max. tree
++ * can be 4 levels in depth -- 4 * 340^4 == 53453440000.
++ * Let's also add one more level for imbalance.
++ */
++ depth = 5;
++
++ /* allocation of new data block(s) */
++ needed = 2;
++
++ /*
++ * tree can be full, so it would need to grow in depth:
++ * allocation + old root + new root
++ */
++ needed += 2 + 1 + 1;
++
++ /*
++ * Index split can happen, we would need:
++ * allocate intermediate indexes (bitmap + group)
++ * + change two blocks at each level, but root (already included)
++ */
++ needed = (depth * 2) + (depth * 2);
++
++ /* any allocation modifies superblock */
++ needed += 1;
++
++ return needed;
++}
++
++static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
++ struct ext4_extent *ex,
++ unsigned long from, unsigned long to)
++{
++ struct buffer_head *bh;
++ int i;
++
++#ifdef EXTENTS_STATS
++ {
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ unsigned short ee_len = le16_to_cpu(ex->ee_len);
++ spin_lock(&sbi->s_ext_stats_lock);
++ sbi->s_ext_blocks += ee_len;
++ sbi->s_ext_extents++;
++ if (ee_len < sbi->s_ext_min)
++ sbi->s_ext_min = ee_len;
++ if (ee_len > sbi->s_ext_max)
++ sbi->s_ext_max = ee_len;
++ if (ext_depth(inode) > sbi->s_depth_max)
++ sbi->s_depth_max = ext_depth(inode);
++ spin_unlock(&sbi->s_ext_stats_lock);
++ }
++#endif
++ if (from >= le32_to_cpu(ex->ee_block)
++ && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
++ /* tail removal */
++ unsigned long num;
++ ext4_fsblk_t start;
++ num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from;
++ start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num;
++ ext_debug("free last %lu blocks starting %llu\n", num, start);
++ for (i = 0; i < num; i++) {
++ bh = sb_find_get_block(inode->i_sb, start + i);
++ ext4_forget(handle, 0, inode, bh, start + i);
++ }
++ ext4_free_blocks(handle, inode, start, num);
++ } else if (from == le32_to_cpu(ex->ee_block)
++ && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
++ printk("strange request: removal %lu-%lu from %u:%u\n",
++ from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
++ } else {
++ printk("strange request: removal(2) %lu-%lu from %u:%u\n",
++ from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
++ }
++ return 0;
++}
++
++static int
++ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
++ struct ext4_ext_path *path, unsigned long start)
++{
++ int err = 0, correct_index = 0;
++ int depth = ext_depth(inode), credits;
++ struct ext4_extent_header *eh;
++ unsigned a, b, block, num;
++ unsigned long ex_ee_block;
++ unsigned short ex_ee_len;
++ struct ext4_extent *ex;
++
++ ext_debug("truncate since %lu in leaf\n", start);
++ if (!path[depth].p_hdr)
++ path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
++ eh = path[depth].p_hdr;
++ BUG_ON(eh == NULL);
++ BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
++ BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
++
++ /* find where to start removing */
++ ex = EXT_LAST_EXTENT(eh);
++
++ ex_ee_block = le32_to_cpu(ex->ee_block);
++ ex_ee_len = le16_to_cpu(ex->ee_len);
++
++ while (ex >= EXT_FIRST_EXTENT(eh) &&
++ ex_ee_block + ex_ee_len > start) {
++ ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len);
++ path[depth].p_ext = ex;
++
++ a = ex_ee_block > start ? ex_ee_block : start;
++ b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCK ?
++ ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCK;
++
++ ext_debug(" border %u:%u\n", a, b);
++
++ if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) {
++ block = 0;
++ num = 0;
++ BUG();
++ } else if (a != ex_ee_block) {
++ /* remove tail of the extent */
++ block = ex_ee_block;
++ num = a - block;
++ } else if (b != ex_ee_block + ex_ee_len - 1) {
++ /* remove head of the extent */
++ block = a;
++ num = b - a;
++ /* there is no "make a hole" API yet */
++ BUG();
++ } else {
++ /* remove whole extent: excellent! */
++ block = ex_ee_block;
++ num = 0;
++ BUG_ON(a != ex_ee_block);
++ BUG_ON(b != ex_ee_block + ex_ee_len - 1);
++ }
++
++ /* at present, extent can't cross block group: */
++ /* leaf + bitmap + group desc + sb + inode */
++ credits = 5;
++ if (ex == EXT_FIRST_EXTENT(eh)) {
++ correct_index = 1;
++ credits += (ext_depth(inode)) + 1;
++ }
++#ifdef CONFIG_QUOTA
++ credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
++#endif
++
++ handle = ext4_ext_journal_restart(handle, credits);
++ if (IS_ERR(handle)) {
++ err = PTR_ERR(handle);
++ goto out;
++ }
++
++ err = ext4_ext_get_access(handle, inode, path + depth);
++ if (err)
++ goto out;
++
++ err = ext4_remove_blocks(handle, inode, ex, a, b);
++ if (err)
++ goto out;
++
++ if (num == 0) {
++ /* this extent is removed; mark slot entirely unused */
++ ext4_ext_store_pblock(ex, 0);
++ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
++ }
++
++ ex->ee_block = cpu_to_le32(block);
++ ex->ee_len = cpu_to_le16(num);
++
++ err = ext4_ext_dirty(handle, inode, path + depth);
++ if (err)
++ goto out;
++
++ ext_debug("new extent: %u:%u:%llu\n", block, num,
++ ext_pblock(ex));
++ ex--;
++ ex_ee_block = le32_to_cpu(ex->ee_block);
++ ex_ee_len = le16_to_cpu(ex->ee_len);
++ }
++
++ if (correct_index && eh->eh_entries)
++ err = ext4_ext_correct_indexes(handle, inode, path);
++
++ /* if this leaf is free, then we should
++ * remove it from index block above */
++ if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
++ err = ext4_ext_rm_idx(handle, inode, path + depth);
++
++out:
++ return err;
++}
++
++/*
++ * ext4_ext_more_to_rm:
++ * returns 1 if current index has to be freed (even partial)
++ */
++static int inline
++ext4_ext_more_to_rm(struct ext4_ext_path *path)
++{
++ BUG_ON(path->p_idx == NULL);
++
++ if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr))
++ return 0;
++
++ /*
++ * if truncate on deeper level happened, it wasn't partial,
++ * so we have to consider current index for truncation
++ */
++ if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block)
++ return 0;
++ return 1;
++}
++
++int ext4_ext_remove_space(struct inode *inode, unsigned long start)
++{
++ struct super_block *sb = inode->i_sb;
++ int depth = ext_depth(inode);
++ struct ext4_ext_path *path;
++ handle_t *handle;
++ int i = 0, err = 0;
++
++ ext_debug("truncate since %lu\n", start);
++
++ /* probably first extent we're gonna free will be last in block */
++ handle = ext4_journal_start(inode, depth + 1);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ ext4_ext_invalidate_cache(inode);
++
++ /*
++ * We start scanning from right side, freeing all the blocks
++ * after i_size and walking into the tree depth-wise.
++ */
++ path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
++ if (path == NULL) {
++ ext4_journal_stop(handle);
++ return -ENOMEM;
++ }
++ memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
++ path[0].p_hdr = ext_inode_hdr(inode);
++ if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
++ err = -EIO;
++ goto out;
++ }
++ path[0].p_depth = depth;
++
++ while (i >= 0 && err == 0) {
++ if (i == depth) {
++ /* this is leaf block */
++ err = ext4_ext_rm_leaf(handle, inode, path, start);
++ /* root level has p_bh == NULL, brelse() eats this */
++ brelse(path[i].p_bh);
++ path[i].p_bh = NULL;
++ i--;
++ continue;
++ }
++
++ /* this is index block */
++ if (!path[i].p_hdr) {
++ ext_debug("initialize header\n");
++ path[i].p_hdr = ext_block_hdr(path[i].p_bh);
++ if (ext4_ext_check_header(__FUNCTION__, inode,
++ path[i].p_hdr)) {
++ err = -EIO;
++ goto out;
++ }
++ }
++
++ BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries)
++ > le16_to_cpu(path[i].p_hdr->eh_max));
++ BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC);
++
++ if (!path[i].p_idx) {
++ /* this level hasn't been touched yet */
++ path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
++ path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1;
++ ext_debug("init index ptr: hdr 0x%p, num %d\n",
++ path[i].p_hdr,
++ le16_to_cpu(path[i].p_hdr->eh_entries));
++ } else {
++ /* we were already here, see at next index */
++ path[i].p_idx--;
++ }
++
++ ext_debug("level %d - index, first 0x%p, cur 0x%p\n",
++ i, EXT_FIRST_INDEX(path[i].p_hdr),
++ path[i].p_idx);
++ if (ext4_ext_more_to_rm(path + i)) {
++ /* go to the next level */
++ ext_debug("move to level %d (block %llu)\n",
++ i + 1, idx_pblock(path[i].p_idx));
++ memset(path + i + 1, 0, sizeof(*path));
++ path[i+1].p_bh =
++ sb_bread(sb, idx_pblock(path[i].p_idx));
++ if (!path[i+1].p_bh) {
++ /* should we reset i_size? */
++ err = -EIO;
++ break;
++ }
++
++ /* save actual number of indexes since this
++ * number is changed at the next iteration */
++ path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries);
++ i++;
++ } else {
++ /* we finished processing this index, go up */
++ if (path[i].p_hdr->eh_entries == 0 && i > 0) {
++ /* index is empty, remove it;
++ * handle must be already prepared by the
++ * truncatei_leaf() */
++ err = ext4_ext_rm_idx(handle, inode, path + i);
++ }
++ /* root level has p_bh == NULL, brelse() eats this */
++ brelse(path[i].p_bh);
++ path[i].p_bh = NULL;
++ i--;
++ ext_debug("return to level %d\n", i);
++ }
++ }
++
++ /* TODO: flexible tree reduction should be here */
++ if (path->p_hdr->eh_entries == 0) {
++ /*
++ * truncate to zero freed all the tree,
++ * so we need to correct eh_depth
++ */
++ err = ext4_ext_get_access(handle, inode, path);
++ if (err == 0) {
++ ext_inode_hdr(inode)->eh_depth = 0;
++ ext_inode_hdr(inode)->eh_max =
++ cpu_to_le16(ext4_ext_space_root(inode));
++ err = ext4_ext_dirty(handle, inode, path);
++ }
++ }
++out:
++ ext4_ext_tree_changed(inode);
++ ext4_ext_drop_refs(path);
++ kfree(path);
++ ext4_journal_stop(handle);
++
++ return err;
++}
++
++/*
++ * called at mount time
++ */
++void ext4_ext_init(struct super_block *sb)
++{
++ /*
++ * possible initialization would be here
++ */
++
++ if (test_opt(sb, EXTENTS)) {
++ printk("EXT4-fs: file extents enabled");
++#ifdef AGRESSIVE_TEST
++ printk(", agressive tests");
++#endif
++#ifdef CHECK_BINSEARCH
++ printk(", check binsearch");
++#endif
++#ifdef EXTENTS_STATS
++ printk(", stats");
++#endif
++ printk("\n");
++#ifdef EXTENTS_STATS
++ spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock);
++ EXT4_SB(sb)->s_ext_min = 1 << 30;
++ EXT4_SB(sb)->s_ext_max = 0;
++#endif
++ }
++}
++
++/*
++ * called at umount time
++ */
++void ext4_ext_release(struct super_block *sb)
++{
++ if (!test_opt(sb, EXTENTS))
++ return;
++
++#ifdef EXTENTS_STATS
++ if (EXT4_SB(sb)->s_ext_blocks && EXT4_SB(sb)->s_ext_extents) {
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ printk(KERN_ERR "EXT4-fs: %lu blocks in %lu extents (%lu ave)\n",
++ sbi->s_ext_blocks, sbi->s_ext_extents,
++ sbi->s_ext_blocks / sbi->s_ext_extents);
++ printk(KERN_ERR "EXT4-fs: extents: %lu min, %lu max, max depth %lu\n",
++ sbi->s_ext_min, sbi->s_ext_max, sbi->s_depth_max);
++ }
++#endif
++}
++
++int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t iblock,
++ unsigned long max_blocks, struct buffer_head *bh_result,
++ int create, int extend_disksize)
++{
++ struct ext4_ext_path *path = NULL;
++ struct ext4_extent newex, *ex;
++ ext4_fsblk_t goal, newblock;
++ int err = 0, depth;
++ unsigned long allocated = 0;
++
++ __clear_bit(BH_New, &bh_result->b_state);
++ ext_debug("blocks %d/%lu requested for inode %u\n", (int) iblock,
++ max_blocks, (unsigned) inode->i_ino);
++ mutex_lock(&EXT4_I(inode)->truncate_mutex);
++
++ /* check in cache */
++ if ((goal = ext4_ext_in_cache(inode, iblock, &newex))) {
++ if (goal == EXT4_EXT_CACHE_GAP) {
++ if (!create) {
++ /* block isn't allocated yet and
++ * user doesn't want to allocate it */
++ goto out2;
++ }
++ /* we should allocate requested block */
++ } else if (goal == EXT4_EXT_CACHE_EXTENT) {
++ /* block is already allocated */
++ newblock = iblock
++ - le32_to_cpu(newex.ee_block)
++ + ext_pblock(&newex);
++ /* number of remaining blocks in the extent */
++ allocated = le16_to_cpu(newex.ee_len) -
++ (iblock - le32_to_cpu(newex.ee_block));
++ goto out;
++ } else {
++ BUG();
++ }
++ }
++
++ /* find extent for this block */
++ path = ext4_ext_find_extent(inode, iblock, NULL);
++ if (IS_ERR(path)) {
++ err = PTR_ERR(path);
++ path = NULL;
++ goto out2;
++ }
++
++ depth = ext_depth(inode);
++
++ /*
++ * consistent leaf must not be empty;
++ * this situation is possible, though, _during_ tree modification;
++ * this is why assert can't be put in ext4_ext_find_extent()
++ */
++ BUG_ON(path[depth].p_ext == NULL && depth != 0);
++
++ if ((ex = path[depth].p_ext)) {
++ unsigned long ee_block = le32_to_cpu(ex->ee_block);
++ ext4_fsblk_t ee_start = ext_pblock(ex);
++ unsigned short ee_len = le16_to_cpu(ex->ee_len);
++
++ /*
++ * Allow future support for preallocated extents to be added
++ * as an RO_COMPAT feature:
++ * Uninitialized extents are treated as holes, except that
++ * we avoid (fail) allocating new blocks during a write.
++ */
++ if (ee_len > EXT_MAX_LEN)
++ goto out2;
++ /* if found extent covers block, simply return it */
++ if (iblock >= ee_block && iblock < ee_block + ee_len) {
++ newblock = iblock - ee_block + ee_start;
++ /* number of remaining blocks in the extent */
++ allocated = ee_len - (iblock - ee_block);
++ ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock,
++ ee_block, ee_len, newblock);
++ ext4_ext_put_in_cache(inode, ee_block, ee_len,
++ ee_start, EXT4_EXT_CACHE_EXTENT);
++ goto out;
++ }
++ }
++
++ /*
++ * requested block isn't allocated yet;
++ * we couldn't try to create block if create flag is zero
++ */
++ if (!create) {
++ /* put just found gap into cache to speed up
++ * subsequent requests */
++ ext4_ext_put_gap_in_cache(inode, path, iblock);
++ goto out2;
++ }
++ /*
++ * Okay, we need to do block allocation. Lazily initialize the block
++ * allocation info here if necessary.
++ */
++ if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info))
++ ext4_init_block_alloc_info(inode);
++
++ /* allocate new block */
++ goal = ext4_ext_find_goal(inode, path, iblock);
++ allocated = max_blocks;
++ newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err);
++ if (!newblock)
++ goto out2;
++ ext_debug("allocate new block: goal %llu, found %llu/%lu\n",
++ goal, newblock, allocated);
++
++ /* try to insert new extent into found leaf and return */
++ newex.ee_block = cpu_to_le32(iblock);
++ ext4_ext_store_pblock(&newex, newblock);
++ newex.ee_len = cpu_to_le16(allocated);
++ err = ext4_ext_insert_extent(handle, inode, path, &newex);
++ if (err)
++ goto out2;
++
++ if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize)
++ EXT4_I(inode)->i_disksize = inode->i_size;
++
++ /* previous routine could use block we allocated */
++ newblock = ext_pblock(&newex);
++ __set_bit(BH_New, &bh_result->b_state);
++
++ ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
++ EXT4_EXT_CACHE_EXTENT);
++out:
++ if (allocated > max_blocks)
++ allocated = max_blocks;
++ ext4_ext_show_leaf(inode, path);
++ __set_bit(BH_Mapped, &bh_result->b_state);
++ bh_result->b_bdev = inode->i_sb->s_bdev;
++ bh_result->b_blocknr = newblock;
++out2:
++ if (path) {
++ ext4_ext_drop_refs(path);
++ kfree(path);
++ }
++ mutex_unlock(&EXT4_I(inode)->truncate_mutex);
++
++ return err ? err : allocated;
++}
++
++void ext4_ext_truncate(struct inode * inode, struct page *page)
++{
++ struct address_space *mapping = inode->i_mapping;
++ struct super_block *sb = inode->i_sb;
++ unsigned long last_block;
++ handle_t *handle;
++ int err = 0;
++
++ /*
++ * probably first extent we're gonna free will be last in block
++ */
++ err = ext4_writepage_trans_blocks(inode) + 3;
++ handle = ext4_journal_start(inode, err);
++ if (IS_ERR(handle)) {
++ if (page) {
++ clear_highpage(page);
++ flush_dcache_page(page);
++ unlock_page(page);
++ page_cache_release(page);
++ }
++ return;
++ }
++
++ if (page)
++ ext4_block_truncate_page(handle, page, mapping, inode->i_size);
++
++ mutex_lock(&EXT4_I(inode)->truncate_mutex);
++ ext4_ext_invalidate_cache(inode);
++
++ /*
++ * TODO: optimization is possible here.
++ * Probably we need not scan at all,
++ * because page truncation is enough.
++ */
++ if (ext4_orphan_add(handle, inode))
++ goto out_stop;
++
++ /* we have to know where to truncate from in crash case */
++ EXT4_I(inode)->i_disksize = inode->i_size;
++ ext4_mark_inode_dirty(handle, inode);
++
++ last_block = (inode->i_size + sb->s_blocksize - 1)
++ >> EXT4_BLOCK_SIZE_BITS(sb);
++ err = ext4_ext_remove_space(inode, last_block);
++
++ /* In a multi-transaction truncate, we only make the final
++ * transaction synchronous. */
++ if (IS_SYNC(inode))
++ handle->h_sync = 1;
++
++out_stop:
++ /*
++ * If this was a simple ftruncate() and the file will remain alive,
++ * then we need to clear up the orphan record which we created above.
++ * However, if this was a real unlink then we were called by
++ * ext4_delete_inode(), and we allow that function to clean up the
++ * orphan info for us.
++ */
++ if (inode->i_nlink)
++ ext4_orphan_del(handle, inode);
++
++ mutex_unlock(&EXT4_I(inode)->truncate_mutex);
++ ext4_journal_stop(handle);
++}
++
++/*
++ * ext4_ext_writepage_trans_blocks:
++ * calculate max number of blocks we could modify
++ * in order to allocate new block for an inode
++ */
++int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
++{
++ int needed;
++
++ needed = ext4_ext_calc_credits_for_insert(inode, NULL);
++
++ /* caller wants to allocate num blocks, but note it includes sb */
++ needed = needed * num - (num - 1);
++
++#ifdef CONFIG_QUOTA
++ needed += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
++#endif
++
++ return needed;
++}
++
++EXPORT_SYMBOL(ext4_mark_inode_dirty);
++EXPORT_SYMBOL(ext4_ext_invalidate_cache);
++EXPORT_SYMBOL(ext4_ext_insert_extent);
++EXPORT_SYMBOL(ext4_ext_walk_space);
++EXPORT_SYMBOL(ext4_ext_find_goal);
++EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert);
++
+diff --git a/fs/ext4/file.c b/fs/ext4/file.c
+new file mode 100644
+index 0000000..0b622c0
+--- /dev/null
++++ b/fs/ext4/file.c
+@@ -0,0 +1,139 @@
++/*
++ * linux/fs/ext4/file.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/file.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * ext4 fs regular file handling primitives
++ *
++ * 64-bit file support on 64-bit platforms by Jakub Jelinek
++ * (jj at sunsite.ms.mff.cuni.cz)
++ */
++
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++#include "xattr.h"
++#include "acl.h"
++
++/*
++ * Called when an inode is released. Note that this is different
++ * from ext4_file_open: open gets called at every open, but release
++ * gets called only when /all/ the files are closed.
++ */
++static int ext4_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))
++ {
++ mutex_lock(&EXT4_I(inode)->truncate_mutex);
++ ext4_discard_reservation(inode);
++ mutex_unlock(&EXT4_I(inode)->truncate_mutex);
++ }
++ if (is_dx(inode) && filp->private_data)
++ ext4_htree_free_dir_info(filp->private_data);
++
++ return 0;
++}
++
++static ssize_t
++ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
++{
++ struct file *file = iocb->ki_filp;
++ struct inode *inode = file->f_dentry->d_inode;
++ ssize_t ret;
++ int err;
++
++ ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
++
++ /*
++ * Skip flushing if there was an error, or if nothing was written.
++ */
++ if (ret <= 0)
++ return ret;
++
++ /*
++ * If the inode is IS_SYNC, or is O_SYNC and we are doing data
++ * journalling then we need to make sure that we force the transaction
++ * to disk to keep all metadata uptodate synchronously.
++ */
++ if (file->f_flags & O_SYNC) {
++ /*
++ * If we are non-data-journaled, then the dirty data has
++ * already been flushed to backing store by generic_osync_inode,
++ * and the inode has been flushed too if there have been any
++ * modifications other than mere timestamp updates.
++ *
++ * Open question --- do we care about flushing timestamps too
++ * if the inode is IS_SYNC?
++ */
++ if (!ext4_should_journal_data(inode))
++ return ret;
++
++ goto force_commit;
++ }
++
++ /*
++ * So we know that there has been no forced data flush. If the inode
++ * is marked IS_SYNC, we need to force one ourselves.
++ */
++ if (!IS_SYNC(inode))
++ return ret;
++
++ /*
++ * Open question #2 --- should we force data to disk here too? If we
++ * don't, the only impact is that data=writeback filesystems won't
++ * flush data to disk automatically on IS_SYNC, only metadata (but
++ * historically, that is what ext2 has done.)
++ */
++
++force_commit:
++ err = ext4_force_commit(inode->i_sb);
++ if (err)
++ return err;
++ return ret;
++}
++
++const struct file_operations ext4_file_operations = {
++ .llseek = generic_file_llseek,
++ .read = do_sync_read,
++ .write = do_sync_write,
++ .aio_read = generic_file_aio_read,
++ .aio_write = ext4_file_write,
++ .ioctl = ext4_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ext4_compat_ioctl,
++#endif
++ .mmap = generic_file_mmap,
++ .open = generic_file_open,
++ .release = ext4_release_file,
++ .fsync = ext4_sync_file,
++ .sendfile = generic_file_sendfile,
++ .splice_read = generic_file_splice_read,
++ .splice_write = generic_file_splice_write,
++};
++
++struct inode_operations ext4_file_inode_operations = {
++ .truncate = ext4_truncate,
++ .setattr = ext4_setattr,
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = ext4_listxattr,
++ .removexattr = generic_removexattr,
++#endif
++ .permission = ext4_permission,
++};
++
+diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
+new file mode 100644
+index 0000000..2a167d7
+--- /dev/null
++++ b/fs/ext4/fsync.c
+@@ -0,0 +1,88 @@
++/*
++ * linux/fs/ext4/fsync.c
++ *
++ * Copyright (C) 1993 Stephen Tweedie (sct at redhat.com)
++ * from
++ * Copyright (C) 1992 Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ * from
++ * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * ext4fs fsync primitive
++ *
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ *
++ * Removed unnecessary code duplication for little endian machines
++ * and excessive __inline__s.
++ * Andi Kleen, 1997
++ *
++ * Major simplications and cleanup - we only need to do the metadata, because
++ * we can depend on generic_block_fdatasync() to sync the data blocks.
++ */
++
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/writeback.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++
++/*
++ * akpm: A new design for ext4_sync_file().
++ *
++ * This is only called from sys_fsync(), sys_fdatasync() and sys_msync().
++ * There cannot be a transaction open by this task.
++ * Another task could have dirtied this inode. Its data can be in any
++ * state in the journalling system.
++ *
++ * What we do is just kick off a commit and wait on it. This will snapshot the
++ * inode to disk.
++ */
++
++int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync)
++{
++ struct inode *inode = dentry->d_inode;
++ int ret = 0;
++
++ J_ASSERT(ext4_journal_current_handle() == 0);
++
++ /*
++ * data=writeback:
++ * The caller's filemap_fdatawrite()/wait will sync the data.
++ * sync_inode() will sync the metadata
++ *
++ * data=ordered:
++ * The caller's filemap_fdatawrite() will write the data and
++ * sync_inode() will write the inode if it is dirty. Then the caller's
++ * filemap_fdatawait() will wait on the pages.
++ *
++ * data=journal:
++ * filemap_fdatawrite won't do anything (the buffers are clean).
++ * ext4_force_commit will write the file data into the journal and
++ * will wait on that.
++ * filemap_fdatawait() will encounter a ton of newly-dirtied pages
++ * (they were dirtied by commit). But that's OK - the blocks are
++ * safe in-journal, which is all fsync() needs to ensure.
++ */
++ if (ext4_should_journal_data(inode)) {
++ ret = ext4_force_commit(inode->i_sb);
++ goto out;
++ }
++
++ /*
++ * The VFS has written the file data. If the inode is unaltered
++ * then we need not start a commit.
++ */
++ if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) {
++ struct writeback_control wbc = {
++ .sync_mode = WB_SYNC_ALL,
++ .nr_to_write = 0, /* sys_fsync did this */
++ };
++ ret = sync_inode(inode, &wbc);
++ }
++out:
++ return ret;
++}
+diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c
+new file mode 100644
+index 0000000..a679663
+--- /dev/null
++++ b/fs/ext4/hash.c
+@@ -0,0 +1,152 @@
++/*
++ * linux/fs/ext4/hash.c
++ *
++ * Copyright (C) 2002 by Theodore Ts'o
++ *
++ * This file is released under the GPL v2.
++ *
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ */
++
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/sched.h>
++#include <linux/ext4_fs.h>
++#include <linux/cryptohash.h>
++
++#define DELTA 0x9E3779B9
++
++static void TEA_transform(__u32 buf[4], __u32 const in[])
++{
++ __u32 sum = 0;
++ __u32 b0 = buf[0], b1 = buf[1];
++ __u32 a = in[0], b = in[1], c = in[2], d = in[3];
++ int n = 16;
++
++ do {
++ sum += DELTA;
++ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
++ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
++ } while(--n);
++
++ buf[0] += b0;
++ buf[1] += b1;
++}
++
++
++/* The old legacy hash */
++static __u32 dx_hack_hash (const char *name, int len)
++{
++ __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
++ while (len--) {
++ __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
++
++ if (hash & 0x80000000) hash -= 0x7fffffff;
++ hash1 = hash0;
++ hash0 = hash;
++ }
++ return (hash0 << 1);
++}
++
++static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
++{
++ __u32 pad, val;
++ int i;
++
++ pad = (__u32)len | ((__u32)len << 8);
++ pad |= pad << 16;
++
++ val = pad;
++ if (len > num*4)
++ len = num * 4;
++ for (i=0; i < len; i++) {
++ if ((i % 4) == 0)
++ val = pad;
++ val = msg[i] + (val << 8);
++ if ((i % 4) == 3) {
++ *buf++ = val;
++ val = pad;
++ num--;
++ }
++ }
++ if (--num >= 0)
++ *buf++ = val;
++ while (--num >= 0)
++ *buf++ = pad;
++}
++
++/*
++ * Returns the hash of a filename. If len is 0 and name is NULL, then
++ * this function can be used to test whether or not a hash version is
++ * supported.
++ *
++ * The seed is an 4 longword (32 bits) "secret" which can be used to
++ * uniquify a hash. If the seed is all zero's, then some default seed
++ * may be used.
++ *
++ * A particular hash version specifies whether or not the seed is
++ * represented, and whether or not the returned hash is 32 bits or 64
++ * bits. 32 bit hashes will return 0 for the minor hash.
++ */
++int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
++{
++ __u32 hash;
++ __u32 minor_hash = 0;
++ const char *p;
++ int i;
++ __u32 in[8], buf[4];
++
++ /* Initialize the default seed for the hash checksum functions */
++ buf[0] = 0x67452301;
++ buf[1] = 0xefcdab89;
++ buf[2] = 0x98badcfe;
++ buf[3] = 0x10325476;
++
++ /* Check to see if the seed is all zero's */
++ if (hinfo->seed) {
++ for (i=0; i < 4; i++) {
++ if (hinfo->seed[i])
++ break;
++ }
++ if (i < 4)
++ memcpy(buf, hinfo->seed, sizeof(buf));
++ }
++
++ switch (hinfo->hash_version) {
++ case DX_HASH_LEGACY:
++ hash = dx_hack_hash(name, len);
++ break;
++ case DX_HASH_HALF_MD4:
++ p = name;
++ while (len > 0) {
++ str2hashbuf(p, len, in, 8);
++ half_md4_transform(buf, in);
++ len -= 32;
++ p += 32;
++ }
++ minor_hash = buf[2];
++ hash = buf[1];
++ break;
++ case DX_HASH_TEA:
++ p = name;
++ while (len > 0) {
++ str2hashbuf(p, len, in, 4);
++ TEA_transform(buf, in);
++ len -= 16;
++ p += 16;
++ }
++ hash = buf[0];
++ minor_hash = buf[1];
++ break;
++ default:
++ hinfo->hash = 0;
++ return -1;
++ }
++ hash = hash & ~1;
++ if (hash == (EXT4_HTREE_EOF << 1))
++ hash = (EXT4_HTREE_EOF-1) << 1;
++ hinfo->hash = hash;
++ hinfo->minor_hash = minor_hash;
++ return 0;
++}
+diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
+new file mode 100644
+index 0000000..c88b439
+--- /dev/null
++++ b/fs/ext4/ialloc.c
+@@ -0,0 +1,772 @@
++/*
++ * linux/fs/ext4/ialloc.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * BSD ufs-inspired inode and directory allocation by
++ * Stephen Tweedie (sct at redhat.com), 1993
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ */
++
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/quotaops.h>
++#include <linux/buffer_head.h>
++#include <linux/random.h>
++#include <linux/bitops.h>
++#include <linux/blkdev.h>
++#include <asm/byteorder.h>
++
++#include "xattr.h"
++#include "acl.h"
++
++/*
++ * ialloc.c contains the inodes allocation and deallocation routines
++ */
++
++/*
++ * The free inodes are managed by bitmaps. A file system contains several
++ * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
++ * block for inodes, N blocks for the inode table and data blocks.
++ *
++ * The file system contains group descriptors which are located after the
++ * super block. Each descriptor contains the number of the bitmap block and
++ * the free blocks count in the block.
++ */
++
++
++/*
++ * Read the inode allocation bitmap for a given block_group, reading
++ * into the specified slot in the superblock's bitmap cache.
++ *
++ * Return buffer_head of bitmap on success or NULL.
++ */
++static struct buffer_head *
++read_inode_bitmap(struct super_block * sb, unsigned long block_group)
++{
++ struct ext4_group_desc *desc;
++ struct buffer_head *bh = NULL;
++
++ desc = ext4_get_group_desc(sb, block_group, NULL);
++ if (!desc)
++ goto error_out;
++
++ bh = sb_bread(sb, ext4_inode_bitmap(sb, desc));
++ if (!bh)
++ ext4_error(sb, "read_inode_bitmap",
++ "Cannot read inode bitmap - "
++ "block_group = %lu, inode_bitmap = %llu",
++ block_group, ext4_inode_bitmap(sb, desc));
++error_out:
++ return bh;
++}
++
++/*
++ * NOTE! When we get the inode, we're the only people
++ * that have access to it, and as such there are no
++ * race conditions we have to worry about. The inode
++ * is not on the hash-lists, and it cannot be reached
++ * through the filesystem because the directory entry
++ * has been deleted earlier.
++ *
++ * HOWEVER: we must make sure that we get no aliases,
++ * which means that we have to call "clear_inode()"
++ * _before_ we mark the inode not in use in the inode
++ * bitmaps. Otherwise a newly created file might use
++ * the same inode number (not actually the same pointer
++ * though), and then we'd have two inodes sharing the
++ * same inode number and space on the harddisk.
++ */
++void ext4_free_inode (handle_t *handle, struct inode * inode)
++{
++ struct super_block * sb = inode->i_sb;
++ int is_directory;
++ unsigned long ino;
++ struct buffer_head *bitmap_bh = NULL;
++ struct buffer_head *bh2;
++ unsigned long block_group;
++ unsigned long bit;
++ struct ext4_group_desc * gdp;
++ struct ext4_super_block * es;
++ struct ext4_sb_info *sbi;
++ int fatal = 0, err;
++
++ if (atomic_read(&inode->i_count) > 1) {
++ printk ("ext4_free_inode: inode has count=%d\n",
++ atomic_read(&inode->i_count));
++ return;
++ }
++ if (inode->i_nlink) {
++ printk ("ext4_free_inode: inode has nlink=%d\n",
++ inode->i_nlink);
++ return;
++ }
++ if (!sb) {
++ printk("ext4_free_inode: inode on nonexistent device\n");
++ return;
++ }
++ sbi = EXT4_SB(sb);
++
++ ino = inode->i_ino;
++ ext4_debug ("freeing inode %lu\n", ino);
++
++ /*
++ * Note: we must free any quota before locking the superblock,
++ * as writing the quota to disk may need the lock as well.
++ */
++ DQUOT_INIT(inode);
++ ext4_xattr_delete_inode(handle, inode);
++ DQUOT_FREE_INODE(inode);
++ DQUOT_DROP(inode);
++
++ is_directory = S_ISDIR(inode->i_mode);
++
++ /* Do this BEFORE marking the inode not in use or returning an error */
++ clear_inode (inode);
++
++ es = EXT4_SB(sb)->s_es;
++ if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
++ ext4_error (sb, "ext4_free_inode",
++ "reserved or nonexistent inode %lu", ino);
++ goto error_return;
++ }
++ block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
++ bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
++ bitmap_bh = read_inode_bitmap(sb, block_group);
++ if (!bitmap_bh)
++ goto error_return;
++
++ BUFFER_TRACE(bitmap_bh, "get_write_access");
++ fatal = ext4_journal_get_write_access(handle, bitmap_bh);
++ if (fatal)
++ goto error_return;
++
++ /* Ok, now we can actually update the inode bitmaps.. */
++ if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
++ bit, bitmap_bh->b_data))
++ ext4_error (sb, "ext4_free_inode",
++ "bit already cleared for inode %lu", ino);
++ else {
++ gdp = ext4_get_group_desc (sb, block_group, &bh2);
++
++ BUFFER_TRACE(bh2, "get_write_access");
++ fatal = ext4_journal_get_write_access(handle, bh2);
++ if (fatal) goto error_return;
++
++ if (gdp) {
++ spin_lock(sb_bgl_lock(sbi, block_group));
++ gdp->bg_free_inodes_count = cpu_to_le16(
++ le16_to_cpu(gdp->bg_free_inodes_count) + 1);
++ if (is_directory)
++ gdp->bg_used_dirs_count = cpu_to_le16(
++ le16_to_cpu(gdp->bg_used_dirs_count) - 1);
++ spin_unlock(sb_bgl_lock(sbi, block_group));
++ percpu_counter_inc(&sbi->s_freeinodes_counter);
++ if (is_directory)
++ percpu_counter_dec(&sbi->s_dirs_counter);
++
++ }
++ BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, bh2);
++ if (!fatal) fatal = err;
++ }
++ BUFFER_TRACE(bitmap_bh, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, bitmap_bh);
++ if (!fatal)
++ fatal = err;
++ sb->s_dirt = 1;
++error_return:
++ brelse(bitmap_bh);
++ ext4_std_error(sb, fatal);
++}
++
++/*
++ * There are two policies for allocating an inode. If the new inode is
++ * a directory, then a forward search is made for a block group with both
++ * free space and a low directory-to-inode ratio; if that fails, then of
++ * the groups with above-average free space, that group with the fewest
++ * directories already is chosen.
++ *
++ * For other inodes, search forward from the parent directory\'s block
++ * group to find a free inode.
++ */
++static int find_group_dir(struct super_block *sb, struct inode *parent)
++{
++ int ngroups = EXT4_SB(sb)->s_groups_count;
++ unsigned int freei, avefreei;
++ struct ext4_group_desc *desc, *best_desc = NULL;
++ struct buffer_head *bh;
++ int group, best_group = -1;
++
++ freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter);
++ avefreei = freei / ngroups;
++
++ for (group = 0; group < ngroups; group++) {
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (!desc || !desc->bg_free_inodes_count)
++ continue;
++ if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
++ continue;
++ if (!best_desc ||
++ (le16_to_cpu(desc->bg_free_blocks_count) >
++ le16_to_cpu(best_desc->bg_free_blocks_count))) {
++ best_group = group;
++ best_desc = desc;
++ }
++ }
++ return best_group;
++}
++
++/*
++ * Orlov's allocator for directories.
++ *
++ * We always try to spread first-level directories.
++ *
++ * If there are blockgroups with both free inodes and free blocks counts
++ * not worse than average we return one with smallest directory count.
++ * Otherwise we simply return a random group.
++ *
++ * For the rest rules look so:
++ *
++ * It's OK to put directory into a group unless
++ * it has too many directories already (max_dirs) or
++ * it has too few free inodes left (min_inodes) or
++ * it has too few free blocks left (min_blocks) or
++ * it's already running too large debt (max_debt).
++ * Parent's group is prefered, if it doesn't satisfy these
++ * conditions we search cyclically through the rest. If none
++ * of the groups look good we just look for a group with more
++ * free inodes than average (starting at parent's group).
++ *
++ * Debt is incremented each time we allocate a directory and decremented
++ * when we allocate an inode, within 0--255.
++ */
++
++#define INODE_COST 64
++#define BLOCK_COST 256
++
++static int find_group_orlov(struct super_block *sb, struct inode *parent)
++{
++ int parent_group = EXT4_I(parent)->i_block_group;
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ struct ext4_super_block *es = sbi->s_es;
++ int ngroups = sbi->s_groups_count;
++ int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
++ unsigned int freei, avefreei;
++ ext4_fsblk_t freeb, avefreeb;
++ ext4_fsblk_t blocks_per_dir;
++ unsigned int ndirs;
++ int max_debt, max_dirs, min_inodes;
++ ext4_grpblk_t min_blocks;
++ int group = -1, i;
++ struct ext4_group_desc *desc;
++ struct buffer_head *bh;
++
++ freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter);
++ avefreei = freei / ngroups;
++ freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
++ avefreeb = freeb;
++ do_div(avefreeb, ngroups);
++ ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
++
++ if ((parent == sb->s_root->d_inode) ||
++ (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) {
++ int best_ndir = inodes_per_group;
++ int best_group = -1;
++
++ get_random_bytes(&group, sizeof(group));
++ parent_group = (unsigned)group % ngroups;
++ for (i = 0; i < ngroups; i++) {
++ group = (parent_group + i) % ngroups;
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (!desc || !desc->bg_free_inodes_count)
++ continue;
++ if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir)
++ continue;
++ if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
++ continue;
++ if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb)
++ continue;
++ best_group = group;
++ best_ndir = le16_to_cpu(desc->bg_used_dirs_count);
++ }
++ if (best_group >= 0)
++ return best_group;
++ goto fallback;
++ }
++
++ blocks_per_dir = ext4_blocks_count(es) - freeb;
++ do_div(blocks_per_dir, ndirs);
++
++ max_dirs = ndirs / ngroups + inodes_per_group / 16;
++ min_inodes = avefreei - inodes_per_group / 4;
++ min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb) / 4;
++
++ max_debt = EXT4_BLOCKS_PER_GROUP(sb);
++ max_debt /= max_t(int, blocks_per_dir, BLOCK_COST);
++ if (max_debt * INODE_COST > inodes_per_group)
++ max_debt = inodes_per_group / INODE_COST;
++ if (max_debt > 255)
++ max_debt = 255;
++ if (max_debt == 0)
++ max_debt = 1;
++
++ for (i = 0; i < ngroups; i++) {
++ group = (parent_group + i) % ngroups;
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (!desc || !desc->bg_free_inodes_count)
++ continue;
++ if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs)
++ continue;
++ if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes)
++ continue;
++ if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks)
++ continue;
++ return group;
++ }
++
++fallback:
++ for (i = 0; i < ngroups; i++) {
++ group = (parent_group + i) % ngroups;
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (!desc || !desc->bg_free_inodes_count)
++ continue;
++ if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei)
++ return group;
++ }
++
++ if (avefreei) {
++ /*
++ * The free-inodes counter is approximate, and for really small
++ * filesystems the above test can fail to find any blockgroups
++ */
++ avefreei = 0;
++ goto fallback;
++ }
++
++ return -1;
++}
++
++static int find_group_other(struct super_block *sb, struct inode *parent)
++{
++ int parent_group = EXT4_I(parent)->i_block_group;
++ int ngroups = EXT4_SB(sb)->s_groups_count;
++ struct ext4_group_desc *desc;
++ struct buffer_head *bh;
++ int group, i;
++
++ /*
++ * Try to place the inode in its parent directory
++ */
++ group = parent_group;
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
++ le16_to_cpu(desc->bg_free_blocks_count))
++ return group;
++
++ /*
++ * We're going to place this inode in a different blockgroup from its
++ * parent. We want to cause files in a common directory to all land in
++ * the same blockgroup. But we want files which are in a different
++ * directory which shares a blockgroup with our parent to land in a
++ * different blockgroup.
++ *
++ * So add our directory's i_ino into the starting point for the hash.
++ */
++ group = (group + parent->i_ino) % ngroups;
++
++ /*
++ * Use a quadratic hash to find a group with a free inode and some free
++ * blocks.
++ */
++ for (i = 1; i < ngroups; i <<= 1) {
++ group += i;
++ if (group >= ngroups)
++ group -= ngroups;
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
++ le16_to_cpu(desc->bg_free_blocks_count))
++ return group;
++ }
++
++ /*
++ * That failed: try linear search for a free inode, even if that group
++ * has no free blocks.
++ */
++ group = parent_group;
++ for (i = 0; i < ngroups; i++) {
++ if (++group >= ngroups)
++ group = 0;
++ desc = ext4_get_group_desc (sb, group, &bh);
++ if (desc && le16_to_cpu(desc->bg_free_inodes_count))
++ return group;
++ }
++
++ return -1;
++}
++
++/*
++ * There are two policies for allocating an inode. If the new inode is
++ * a directory, then a forward search is made for a block group with both
++ * free space and a low directory-to-inode ratio; if that fails, then of
++ * the groups with above-average free space, that group with the fewest
++ * directories already is chosen.
++ *
++ * For other inodes, search forward from the parent directory's block
++ * group to find a free inode.
++ */
++struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
++{
++ struct super_block *sb;
++ struct buffer_head *bitmap_bh = NULL;
++ struct buffer_head *bh2;
++ int group;
++ unsigned long ino = 0;
++ struct inode * inode;
++ struct ext4_group_desc * gdp = NULL;
++ struct ext4_super_block * es;
++ struct ext4_inode_info *ei;
++ struct ext4_sb_info *sbi;
++ int err = 0;
++ struct inode *ret;
++ int i;
++
++ /* Cannot create files in a deleted directory */
++ if (!dir || !dir->i_nlink)
++ return ERR_PTR(-EPERM);
++
++ sb = dir->i_sb;
++ inode = new_inode(sb);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ ei = EXT4_I(inode);
++
++ sbi = EXT4_SB(sb);
++ es = sbi->s_es;
++ if (S_ISDIR(mode)) {
++ if (test_opt (sb, OLDALLOC))
++ group = find_group_dir(sb, dir);
++ else
++ group = find_group_orlov(sb, dir);
++ } else
++ group = find_group_other(sb, dir);
++
++ err = -ENOSPC;
++ if (group == -1)
++ goto out;
++
++ for (i = 0; i < sbi->s_groups_count; i++) {
++ err = -EIO;
++
++ gdp = ext4_get_group_desc(sb, group, &bh2);
++ if (!gdp)
++ goto fail;
++
++ brelse(bitmap_bh);
++ bitmap_bh = read_inode_bitmap(sb, group);
++ if (!bitmap_bh)
++ goto fail;
++
++ ino = 0;
++
++repeat_in_this_group:
++ ino = ext4_find_next_zero_bit((unsigned long *)
++ bitmap_bh->b_data, EXT4_INODES_PER_GROUP(sb), ino);
++ if (ino < EXT4_INODES_PER_GROUP(sb)) {
++
++ BUFFER_TRACE(bitmap_bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, bitmap_bh);
++ if (err)
++ goto fail;
++
++ if (!ext4_set_bit_atomic(sb_bgl_lock(sbi, group),
++ ino, bitmap_bh->b_data)) {
++ /* we won it */
++ BUFFER_TRACE(bitmap_bh,
++ "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle,
++ bitmap_bh);
++ if (err)
++ goto fail;
++ goto got;
++ }
++ /* we lost it */
++ jbd2_journal_release_buffer(handle, bitmap_bh);
++
++ if (++ino < EXT4_INODES_PER_GROUP(sb))
++ goto repeat_in_this_group;
++ }
++
++ /*
++ * This case is possible in concurrent environment. It is very
++ * rare. We cannot repeat the find_group_xxx() call because
++ * that will simply return the same blockgroup, because the
++ * group descriptor metadata has not yet been updated.
++ * So we just go onto the next blockgroup.
++ */
++ if (++group == sbi->s_groups_count)
++ group = 0;
++ }
++ err = -ENOSPC;
++ goto out;
++
++got:
++ ino += group * EXT4_INODES_PER_GROUP(sb) + 1;
++ if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
++ ext4_error (sb, "ext4_new_inode",
++ "reserved inode or inode > inodes count - "
++ "block_group = %d, inode=%lu", group, ino);
++ err = -EIO;
++ goto fail;
++ }
++
++ BUFFER_TRACE(bh2, "get_write_access");
++ err = ext4_journal_get_write_access(handle, bh2);
++ if (err) goto fail;
++ spin_lock(sb_bgl_lock(sbi, group));
++ gdp->bg_free_inodes_count =
++ cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
++ if (S_ISDIR(mode)) {
++ gdp->bg_used_dirs_count =
++ cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
++ }
++ spin_unlock(sb_bgl_lock(sbi, group));
++ BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, bh2);
++ if (err) goto fail;
++
++ percpu_counter_dec(&sbi->s_freeinodes_counter);
++ if (S_ISDIR(mode))
++ percpu_counter_inc(&sbi->s_dirs_counter);
++ sb->s_dirt = 1;
++
++ inode->i_uid = current->fsuid;
++ if (test_opt (sb, GRPID))
++ inode->i_gid = dir->i_gid;
++ else if (dir->i_mode & S_ISGID) {
++ inode->i_gid = dir->i_gid;
++ if (S_ISDIR(mode))
++ mode |= S_ISGID;
++ } else
++ inode->i_gid = current->fsgid;
++ inode->i_mode = mode;
++
++ inode->i_ino = ino;
++ /* This is the optimal IO size (for stat), not the fs block size */
++ inode->i_blocks = 0;
++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
++
++ memset(ei->i_data, 0, sizeof(ei->i_data));
++ ei->i_dir_start_lookup = 0;
++ ei->i_disksize = 0;
++
++ ei->i_flags = EXT4_I(dir)->i_flags & ~EXT4_INDEX_FL;
++ if (S_ISLNK(mode))
++ ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL);
++ /* dirsync only applies to directories */
++ if (!S_ISDIR(mode))
++ ei->i_flags &= ~EXT4_DIRSYNC_FL;
++#ifdef EXT4_FRAGMENTS
++ ei->i_faddr = 0;
++ ei->i_frag_no = 0;
++ ei->i_frag_size = 0;
++#endif
++ ei->i_file_acl = 0;
++ ei->i_dir_acl = 0;
++ ei->i_dtime = 0;
++ ei->i_block_alloc_info = NULL;
++ ei->i_block_group = group;
++
++ ext4_set_inode_flags(inode);
++ if (IS_DIRSYNC(inode))
++ handle->h_sync = 1;
++ insert_inode_hash(inode);
++ spin_lock(&sbi->s_next_gen_lock);
++ inode->i_generation = sbi->s_next_generation++;
++ spin_unlock(&sbi->s_next_gen_lock);
++
++ ei->i_state = EXT4_STATE_NEW;
++ ei->i_extra_isize =
++ (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ?
++ sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
++
++ ret = inode;
++ if(DQUOT_ALLOC_INODE(inode)) {
++ err = -EDQUOT;
++ goto fail_drop;
++ }
++
++ err = ext4_init_acl(handle, inode, dir);
++ if (err)
++ goto fail_free_drop;
++
++ err = ext4_init_security(handle,inode, dir);
++ if (err)
++ goto fail_free_drop;
++
++ err = ext4_mark_inode_dirty(handle, inode);
++ if (err) {
++ ext4_std_error(sb, err);
++ goto fail_free_drop;
++ }
++ if (test_opt(sb, EXTENTS)) {
++ EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
++ ext4_ext_tree_init(handle, inode);
++ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
++ err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
++ if (err) goto fail;
++ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS);
++ BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
++ }
++ }
++
++ ext4_debug("allocating inode %lu\n", inode->i_ino);
++ goto really_out;
++fail:
++ ext4_std_error(sb, err);
++out:
++ iput(inode);
++ ret = ERR_PTR(err);
++really_out:
++ brelse(bitmap_bh);
++ return ret;
++
++fail_free_drop:
++ DQUOT_FREE_INODE(inode);
++
++fail_drop:
++ DQUOT_DROP(inode);
++ inode->i_flags |= S_NOQUOTA;
++ inode->i_nlink = 0;
++ iput(inode);
++ brelse(bitmap_bh);
++ return ERR_PTR(err);
++}
++
++/* Verify that we are loading a valid orphan from disk */
++struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
++{
++ unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
++ unsigned long block_group;
++ int bit;
++ struct buffer_head *bitmap_bh = NULL;
++ struct inode *inode = NULL;
++
++ /* Error cases - e2fsck has already cleaned up for us */
++ if (ino > max_ino) {
++ ext4_warning(sb, __FUNCTION__,
++ "bad orphan ino %lu! e2fsck was run?", ino);
++ goto out;
++ }
++
++ block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
++ bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
++ bitmap_bh = read_inode_bitmap(sb, block_group);
++ if (!bitmap_bh) {
++ ext4_warning(sb, __FUNCTION__,
++ "inode bitmap error for orphan %lu", ino);
++ goto out;
++ }
++
++ /* Having the inode bit set should be a 100% indicator that this
++ * is a valid orphan (no e2fsck run on fs). Orphans also include
++ * inodes that were being truncated, so we can't check i_nlink==0.
++ */
++ if (!ext4_test_bit(bit, bitmap_bh->b_data) ||
++ !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
++ NEXT_ORPHAN(inode) > max_ino) {
++ ext4_warning(sb, __FUNCTION__,
++ "bad orphan inode %lu! e2fsck was run?", ino);
++ printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
++ bit, (unsigned long long)bitmap_bh->b_blocknr,
++ ext4_test_bit(bit, bitmap_bh->b_data));
++ printk(KERN_NOTICE "inode=%p\n", inode);
++ if (inode) {
++ printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
++ is_bad_inode(inode));
++ printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
++ NEXT_ORPHAN(inode));
++ printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
++ }
++ /* Avoid freeing blocks if we got a bad deleted inode */
++ if (inode && inode->i_nlink == 0)
++ inode->i_blocks = 0;
++ iput(inode);
++ inode = NULL;
++ }
++out:
++ brelse(bitmap_bh);
++ return inode;
++}
++
++unsigned long ext4_count_free_inodes (struct super_block * sb)
++{
++ unsigned long desc_count;
++ struct ext4_group_desc *gdp;
++ int i;
++#ifdef EXT4FS_DEBUG
++ struct ext4_super_block *es;
++ unsigned long bitmap_count, x;
++ struct buffer_head *bitmap_bh = NULL;
++
++ es = EXT4_SB(sb)->s_es;
++ desc_count = 0;
++ bitmap_count = 0;
++ gdp = NULL;
++ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
++ gdp = ext4_get_group_desc (sb, i, NULL);
++ if (!gdp)
++ continue;
++ desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
++ brelse(bitmap_bh);
++ bitmap_bh = read_inode_bitmap(sb, i);
++ if (!bitmap_bh)
++ continue;
++
++ x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8);
++ printk("group %d: stored = %d, counted = %lu\n",
++ i, le16_to_cpu(gdp->bg_free_inodes_count), x);
++ bitmap_count += x;
++ }
++ brelse(bitmap_bh);
++ printk("ext4_count_free_inodes: stored = %u, computed = %lu, %lu\n",
++ le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
++ return desc_count;
++#else
++ desc_count = 0;
++ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
++ gdp = ext4_get_group_desc (sb, i, NULL);
++ if (!gdp)
++ continue;
++ desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
++ cond_resched();
++ }
++ return desc_count;
++#endif
++}
++
++/* Called at mount-time, super-block is locked */
++unsigned long ext4_count_dirs (struct super_block * sb)
++{
++ unsigned long count = 0;
++ int i;
++
++ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
++ struct ext4_group_desc *gdp = ext4_get_group_desc (sb, i, NULL);
++ if (!gdp)
++ continue;
++ count += le16_to_cpu(gdp->bg_used_dirs_count);
++ }
++ return count;
++}
++
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+new file mode 100644
+index 0000000..0a60ec5
+--- /dev/null
++++ b/fs/ext4/inode.c
+@@ -0,0 +1,3233 @@
++/*
++ * linux/fs/ext4/inode.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/inode.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Goal-directed block allocation by Stephen Tweedie
++ * (sct at redhat.com), 1993, 1998
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ * 64-bit file support on 64-bit platforms by Jakub Jelinek
++ * (jj at sunsite.ms.mff.cuni.cz)
++ *
++ * Assorted race fixes, rewrite of ext4_get_block() by Al Viro, 2000
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/time.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/jbd2.h>
++#include <linux/smp_lock.h>
++#include <linux/highuid.h>
++#include <linux/pagemap.h>
++#include <linux/quotaops.h>
++#include <linux/string.h>
++#include <linux/buffer_head.h>
++#include <linux/writeback.h>
++#include <linux/mpage.h>
++#include <linux/uio.h>
++#include <linux/bio.h>
++#include "xattr.h"
++#include "acl.h"
++
++/*
++ * Test whether an inode is a fast symlink.
++ */
++static int ext4_inode_is_fast_symlink(struct inode *inode)
++{
++ int ea_blocks = EXT4_I(inode)->i_file_acl ?
++ (inode->i_sb->s_blocksize >> 9) : 0;
++
++ return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
++}
++
++/*
++ * The ext4 forget function must perform a revoke if we are freeing data
++ * which has been journaled. Metadata (eg. indirect blocks) must be
++ * revoked in all cases.
++ *
++ * "bh" may be NULL: a metadata block may have been freed from memory
++ * but there may still be a record of it in the journal, and that record
++ * still needs to be revoked.
++ */
++int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
++ struct buffer_head *bh, ext4_fsblk_t blocknr)
++{
++ int err;
++
++ might_sleep();
++
++ BUFFER_TRACE(bh, "enter");
++
++ jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
++ "data mode %lx\n",
++ bh, is_metadata, inode->i_mode,
++ test_opt(inode->i_sb, DATA_FLAGS));
++
++ /* Never use the revoke function if we are doing full data
++ * journaling: there is no need to, and a V1 superblock won't
++ * support it. Otherwise, only skip the revoke on un-journaled
++ * data blocks. */
++
++ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
++ (!is_metadata && !ext4_should_journal_data(inode))) {
++ if (bh) {
++ BUFFER_TRACE(bh, "call jbd2_journal_forget");
++ return ext4_journal_forget(handle, bh);
++ }
++ return 0;
++ }
++
++ /*
++ * data!=journal && (is_metadata || should_journal_data(inode))
++ */
++ BUFFER_TRACE(bh, "call ext4_journal_revoke");
++ err = ext4_journal_revoke(handle, blocknr, bh);
++ if (err)
++ ext4_abort(inode->i_sb, __FUNCTION__,
++ "error %d when attempting revoke", err);
++ BUFFER_TRACE(bh, "exit");
++ return err;
++}
++
++/*
++ * Work out how many blocks we need to proceed with the next chunk of a
++ * truncate transaction.
++ */
++static unsigned long blocks_for_truncate(struct inode *inode)
++{
++ unsigned long needed;
++
++ needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
++
++ /* Give ourselves just enough room to cope with inodes in which
++ * i_blocks is corrupt: we've seen disk corruptions in the past
++ * which resulted in random data in an inode which looked enough
++ * like a regular file for ext4 to try to delete it. Things
++ * will go a bit crazy if that happens, but at least we should
++ * try not to panic the whole kernel. */
++ if (needed < 2)
++ needed = 2;
++
++ /* But we need to bound the transaction so we don't overflow the
++ * journal. */
++ if (needed > EXT4_MAX_TRANS_DATA)
++ needed = EXT4_MAX_TRANS_DATA;
++
++ return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
++}
++
++/*
++ * Truncate transactions can be complex and absolutely huge. So we need to
++ * be able to restart the transaction at a conventient checkpoint to make
++ * sure we don't overflow the journal.
++ *
++ * start_transaction gets us a new handle for a truncate transaction,
++ * and extend_transaction tries to extend the existing one a bit. If
++ * extend fails, we need to propagate the failure up and restart the
++ * transaction in the top-level truncate loop. --sct
++ */
++static handle_t *start_transaction(struct inode *inode)
++{
++ handle_t *result;
++
++ result = ext4_journal_start(inode, blocks_for_truncate(inode));
++ if (!IS_ERR(result))
++ return result;
++
++ ext4_std_error(inode->i_sb, PTR_ERR(result));
++ return result;
++}
++
++/*
++ * Try to extend this transaction for the purposes of truncation.
++ *
++ * Returns 0 if we managed to create more room. If we can't create more
++ * room, and the transaction must be restarted we return 1.
++ */
++static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
++{
++ if (handle->h_buffer_credits > EXT4_RESERVE_TRANS_BLOCKS)
++ return 0;
++ if (!ext4_journal_extend(handle, blocks_for_truncate(inode)))
++ return 0;
++ return 1;
++}
++
++/*
++ * Restart the transaction associated with *handle. This does a commit,
++ * so before we call here everything must be consistently dirtied against
++ * this transaction.
++ */
++static int ext4_journal_test_restart(handle_t *handle, struct inode *inode)
++{
++ jbd_debug(2, "restarting handle %p\n", handle);
++ return ext4_journal_restart(handle, blocks_for_truncate(inode));
++}
++
++/*
++ * Called at the last iput() if i_nlink is zero.
++ */
++void ext4_delete_inode (struct inode * inode)
++{
++ handle_t *handle;
++
++ truncate_inode_pages(&inode->i_data, 0);
++
++ if (is_bad_inode(inode))
++ goto no_delete;
++
++ handle = start_transaction(inode);
++ if (IS_ERR(handle)) {
++ /*
++ * If we're going to skip the normal cleanup, we still need to
++ * make sure that the in-core orphan linked list is properly
++ * cleaned up.
++ */
++ ext4_orphan_del(NULL, inode);
++ goto no_delete;
++ }
++
++ if (IS_SYNC(inode))
++ handle->h_sync = 1;
++ inode->i_size = 0;
++ if (inode->i_blocks)
++ ext4_truncate(inode);
++ /*
++ * Kill off the orphan record which ext4_truncate created.
++ * AKPM: I think this can be inside the above `if'.
++ * Note that ext4_orphan_del() has to be able to cope with the
++ * deletion of a non-existent orphan - this is because we don't
++ * know if ext4_truncate() actually created an orphan record.
++ * (Well, we could do this if we need to, but heck - it works)
++ */
++ ext4_orphan_del(handle, inode);
++ EXT4_I(inode)->i_dtime = get_seconds();
++
++ /*
++ * One subtle ordering requirement: if anything has gone wrong
++ * (transaction abort, IO errors, whatever), then we can still
++ * do these next steps (the fs will already have been marked as
++ * having errors), but we can't free the inode if the mark_dirty
++ * fails.
++ */
++ if (ext4_mark_inode_dirty(handle, inode))
++ /* If that failed, just do the required in-core inode clear. */
++ clear_inode(inode);
++ else
++ ext4_free_inode(handle, inode);
++ ext4_journal_stop(handle);
++ return;
++no_delete:
++ clear_inode(inode); /* We must guarantee clearing of inode... */
++}
++
++typedef struct {
++ __le32 *p;
++ __le32 key;
++ struct buffer_head *bh;
++} Indirect;
++
++static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
++{
++ p->key = *(p->p = v);
++ p->bh = bh;
++}
++
++static int verify_chain(Indirect *from, Indirect *to)
++{
++ while (from <= to && from->key == *from->p)
++ from++;
++ return (from > to);
++}
++
++/**
++ * ext4_block_to_path - parse the block number into array of offsets
++ * @inode: inode in question (we are only interested in its superblock)
++ * @i_block: block number to be parsed
++ * @offsets: array to store the offsets in
++ * @boundary: set this non-zero if the referred-to block is likely to be
++ * followed (on disk) by an indirect block.
++ *
++ * To store the locations of file's data ext4 uses a data structure common
++ * for UNIX filesystems - tree of pointers anchored in the inode, with
++ * data blocks at leaves and indirect blocks in intermediate nodes.
++ * This function translates the block number into path in that tree -
++ * return value is the path length and @offsets[n] is the offset of
++ * pointer to (n+1)th node in the nth one. If @block is out of range
++ * (negative or too large) warning is printed and zero returned.
++ *
++ * Note: function doesn't find node addresses, so no IO is needed. All
++ * we need to know is the capacity of indirect blocks (taken from the
++ * inode->i_sb).
++ */
++
++/*
++ * Portability note: the last comparison (check that we fit into triple
++ * indirect block) is spelled differently, because otherwise on an
++ * architecture with 32-bit longs and 8Kb pages we might get into trouble
++ * if our filesystem had 8Kb blocks. We might use long long, but that would
++ * kill us on x86. Oh, well, at least the sign propagation does not matter -
++ * i_block would have to be negative in the very beginning, so we would not
++ * get there at all.
++ */
++
++static int ext4_block_to_path(struct inode *inode,
++ long i_block, int offsets[4], int *boundary)
++{
++ int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb);
++ int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb);
++ const long direct_blocks = EXT4_NDIR_BLOCKS,
++ indirect_blocks = ptrs,
++ double_blocks = (1 << (ptrs_bits * 2));
++ int n = 0;
++ int final = 0;
++
++ if (i_block < 0) {
++ ext4_warning (inode->i_sb, "ext4_block_to_path", "block < 0");
++ } else if (i_block < direct_blocks) {
++ offsets[n++] = i_block;
++ final = direct_blocks;
++ } else if ( (i_block -= direct_blocks) < indirect_blocks) {
++ offsets[n++] = EXT4_IND_BLOCK;
++ offsets[n++] = i_block;
++ final = ptrs;
++ } else if ((i_block -= indirect_blocks) < double_blocks) {
++ offsets[n++] = EXT4_DIND_BLOCK;
++ offsets[n++] = i_block >> ptrs_bits;
++ offsets[n++] = i_block & (ptrs - 1);
++ final = ptrs;
++ } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
++ offsets[n++] = EXT4_TIND_BLOCK;
++ offsets[n++] = i_block >> (ptrs_bits * 2);
++ offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
++ offsets[n++] = i_block & (ptrs - 1);
++ final = ptrs;
++ } else {
++ ext4_warning(inode->i_sb, "ext4_block_to_path", "block > big");
++ }
++ if (boundary)
++ *boundary = final - 1 - (i_block & (ptrs - 1));
++ return n;
++}
++
++/**
++ * ext4_get_branch - read the chain of indirect blocks leading to data
++ * @inode: inode in question
++ * @depth: depth of the chain (1 - direct pointer, etc.)
++ * @offsets: offsets of pointers in inode/indirect blocks
++ * @chain: place to store the result
++ * @err: here we store the error value
++ *
++ * Function fills the array of triples <key, p, bh> and returns %NULL
++ * if everything went OK or the pointer to the last filled triple
++ * (incomplete one) otherwise. Upon the return chain[i].key contains
++ * the number of (i+1)-th block in the chain (as it is stored in memory,
++ * i.e. little-endian 32-bit), chain[i].p contains the address of that
++ * number (it points into struct inode for i==0 and into the bh->b_data
++ * for i>0) and chain[i].bh points to the buffer_head of i-th indirect
++ * block for i>0 and NULL for i==0. In other words, it holds the block
++ * numbers of the chain, addresses they were taken from (and where we can
++ * verify that chain did not change) and buffer_heads hosting these
++ * numbers.
++ *
++ * Function stops when it stumbles upon zero pointer (absent block)
++ * (pointer to last triple returned, *@err == 0)
++ * or when it gets an IO error reading an indirect block
++ * (ditto, *@err == -EIO)
++ * or when it notices that chain had been changed while it was reading
++ * (ditto, *@err == -EAGAIN)
++ * or when it reads all @depth-1 indirect blocks successfully and finds
++ * the whole chain, all way to the data (returns %NULL, *err == 0).
++ */
++static Indirect *ext4_get_branch(struct inode *inode, int depth, int *offsets,
++ Indirect chain[4], int *err)
++{
++ struct super_block *sb = inode->i_sb;
++ Indirect *p = chain;
++ struct buffer_head *bh;
++
++ *err = 0;
++ /* i_data is not going away, no lock needed */
++ add_chain (chain, NULL, EXT4_I(inode)->i_data + *offsets);
++ if (!p->key)
++ goto no_block;
++ while (--depth) {
++ bh = sb_bread(sb, le32_to_cpu(p->key));
++ if (!bh)
++ goto failure;
++ /* Reader: pointers */
++ if (!verify_chain(chain, p))
++ goto changed;
++ add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);
++ /* Reader: end */
++ if (!p->key)
++ goto no_block;
++ }
++ return NULL;
++
++changed:
++ brelse(bh);
++ *err = -EAGAIN;
++ goto no_block;
++failure:
++ *err = -EIO;
++no_block:
++ return p;
++}
++
++/**
++ * ext4_find_near - find a place for allocation with sufficient locality
++ * @inode: owner
++ * @ind: descriptor of indirect block.
++ *
++ * This function returns the prefered place for block allocation.
++ * It is used when heuristic for sequential allocation fails.
++ * Rules are:
++ * + if there is a block to the left of our position - allocate near it.
++ * + if pointer will live in indirect block - allocate near that block.
++ * + if pointer will live in inode - allocate in the same
++ * cylinder group.
++ *
++ * In the latter case we colour the starting block by the callers PID to
++ * prevent it from clashing with concurrent allocations for a different inode
++ * in the same block group. The PID is used here so that functionally related
++ * files will be close-by on-disk.
++ *
++ * Caller must make sure that @ind is valid and will stay that way.
++ */
++static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
++ __le32 *p;
++ ext4_fsblk_t bg_start;
++ ext4_grpblk_t colour;
++
++ /* Try to find previous block */
++ for (p = ind->p - 1; p >= start; p--) {
++ if (*p)
++ return le32_to_cpu(*p);
++ }
++
++ /* No such thing, so let's try location of indirect block */
++ if (ind->bh)
++ return ind->bh->b_blocknr;
++
++ /*
++ * It is going to be referred to from the inode itself? OK, just put it
++ * into the same cylinder group then.
++ */
++ bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group);
++ colour = (current->pid % 16) *
++ (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
++ return bg_start + colour;
++}
++
++/**
++ * ext4_find_goal - find a prefered place for allocation.
++ * @inode: owner
++ * @block: block we want
++ * @chain: chain of indirect blocks
++ * @partial: pointer to the last triple within a chain
++ * @goal: place to store the result.
++ *
++ * Normally this function find the prefered place for block allocation,
++ * stores it in *@goal and returns zero.
++ */
++
++static ext4_fsblk_t ext4_find_goal(struct inode *inode, long block,
++ Indirect chain[4], Indirect *partial)
++{
++ struct ext4_block_alloc_info *block_i;
++
++ block_i = EXT4_I(inode)->i_block_alloc_info;
++
++ /*
++ * try the heuristic for sequential allocation,
++ * failing that at least try to get decent locality.
++ */
++ if (block_i && (block == block_i->last_alloc_logical_block + 1)
++ && (block_i->last_alloc_physical_block != 0)) {
++ return block_i->last_alloc_physical_block + 1;
++ }
++
++ return ext4_find_near(inode, partial);
++}
++
++/**
++ * ext4_blks_to_allocate: Look up the block map and count the number
++ * of direct blocks need to be allocated for the given branch.
++ *
++ * @branch: chain of indirect blocks
++ * @k: number of blocks need for indirect blocks
++ * @blks: number of data blocks to be mapped.
++ * @blocks_to_boundary: the offset in the indirect block
++ *
++ * return the total number of blocks to be allocate, including the
++ * direct and indirect blocks.
++ */
++static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned long blks,
++ int blocks_to_boundary)
++{
++ unsigned long count = 0;
++
++ /*
++ * Simple case, [t,d]Indirect block(s) has not allocated yet
++ * then it's clear blocks on that path have not allocated
++ */
++ if (k > 0) {
++ /* right now we don't handle cross boundary allocation */
++ if (blks < blocks_to_boundary + 1)
++ count += blks;
++ else
++ count += blocks_to_boundary + 1;
++ return count;
++ }
++
++ count++;
++ while (count < blks && count <= blocks_to_boundary &&
++ le32_to_cpu(*(branch[0].p + count)) == 0) {
++ count++;
++ }
++ return count;
++}
++
++/**
++ * ext4_alloc_blocks: multiple allocate blocks needed for a branch
++ * @indirect_blks: the number of blocks need to allocate for indirect
++ * blocks
++ *
++ * @new_blocks: on return it will store the new block numbers for
++ * the indirect blocks(if needed) and the first direct block,
++ * @blks: on return it will store the total number of allocated
++ * direct blocks
++ */
++static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t goal, int indirect_blks, int blks,
++ ext4_fsblk_t new_blocks[4], int *err)
++{
++ int target, i;
++ unsigned long count = 0;
++ int index = 0;
++ ext4_fsblk_t current_block = 0;
++ int ret = 0;
++
++ /*
++ * Here we try to allocate the requested multiple blocks at once,
++ * on a best-effort basis.
++ * To build a branch, we should allocate blocks for
++ * the indirect blocks(if not allocated yet), and at least
++ * the first direct block of this branch. That's the
++ * minimum number of blocks need to allocate(required)
++ */
++ target = blks + indirect_blks;
++
++ while (1) {
++ count = target;
++ /* allocating blocks for indirect blocks and direct blocks */
++ current_block = ext4_new_blocks(handle,inode,goal,&count,err);
++ if (*err)
++ goto failed_out;
++
++ target -= count;
++ /* allocate blocks for indirect blocks */
++ while (index < indirect_blks && count) {
++ new_blocks[index++] = current_block++;
++ count--;
++ }
++
++ if (count > 0)
++ break;
++ }
++
++ /* save the new block number for the first direct block */
++ new_blocks[index] = current_block;
++
++ /* total number of blocks allocated for direct blocks */
++ ret = count;
++ *err = 0;
++ return ret;
++failed_out:
++ for (i = 0; i <index; i++)
++ ext4_free_blocks(handle, inode, new_blocks[i], 1);
++ return ret;
++}
++
++/**
++ * ext4_alloc_branch - allocate and set up a chain of blocks.
++ * @inode: owner
++ * @indirect_blks: number of allocated indirect blocks
++ * @blks: number of allocated direct blocks
++ * @offsets: offsets (in the blocks) to store the pointers to next.
++ * @branch: place to store the chain in.
++ *
++ * This function allocates blocks, zeroes out all but the last one,
++ * links them into chain and (if we are synchronous) writes them to disk.
++ * In other words, it prepares a branch that can be spliced onto the
++ * inode. It stores the information about that chain in the branch[], in
++ * the same format as ext4_get_branch() would do. We are calling it after
++ * we had read the existing part of chain and partial points to the last
++ * triple of that (one with zero ->key). Upon the exit we have the same
++ * picture as after the successful ext4_get_block(), except that in one
++ * place chain is disconnected - *branch->p is still zero (we did not
++ * set the last link), but branch->key contains the number that should
++ * be placed into *branch->p to fill that gap.
++ *
++ * If allocation fails we free all blocks we've allocated (and forget
++ * their buffer_heads) and return the error value the from failed
++ * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain
++ * as described above and return 0.
++ */
++static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
++ int indirect_blks, int *blks, ext4_fsblk_t goal,
++ int *offsets, Indirect *branch)
++{
++ int blocksize = inode->i_sb->s_blocksize;
++ int i, n = 0;
++ int err = 0;
++ struct buffer_head *bh;
++ int num;
++ ext4_fsblk_t new_blocks[4];
++ ext4_fsblk_t current_block;
++
++ num = ext4_alloc_blocks(handle, inode, goal, indirect_blks,
++ *blks, new_blocks, &err);
++ if (err)
++ return err;
++
++ branch[0].key = cpu_to_le32(new_blocks[0]);
++ /*
++ * metadata blocks and data blocks are allocated.
++ */
++ for (n = 1; n <= indirect_blks; n++) {
++ /*
++ * Get buffer_head for parent block, zero it out
++ * and set the pointer to new one, then send
++ * parent to disk.
++ */
++ bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
++ branch[n].bh = bh;
++ lock_buffer(bh);
++ BUFFER_TRACE(bh, "call get_create_access");
++ err = ext4_journal_get_create_access(handle, bh);
++ if (err) {
++ unlock_buffer(bh);
++ brelse(bh);
++ goto failed;
++ }
++
++ memset(bh->b_data, 0, blocksize);
++ branch[n].p = (__le32 *) bh->b_data + offsets[n];
++ branch[n].key = cpu_to_le32(new_blocks[n]);
++ *branch[n].p = branch[n].key;
++ if ( n == indirect_blks) {
++ current_block = new_blocks[n];
++ /*
++ * End of chain, update the last new metablock of
++ * the chain to point to the new allocated
++ * data blocks numbers
++ */
++ for (i=1; i < num; i++)
++ *(branch[n].p + i) = cpu_to_le32(++current_block);
++ }
++ BUFFER_TRACE(bh, "marking uptodate");
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++
++ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, bh);
++ if (err)
++ goto failed;
++ }
++ *blks = num;
++ return err;
++failed:
++ /* Allocation failed, free what we already allocated */
++ for (i = 1; i <= n ; i++) {
++ BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget");
++ ext4_journal_forget(handle, branch[i].bh);
++ }
++ for (i = 0; i <indirect_blks; i++)
++ ext4_free_blocks(handle, inode, new_blocks[i], 1);
++
++ ext4_free_blocks(handle, inode, new_blocks[i], num);
++
++ return err;
++}
++
++/**
++ * ext4_splice_branch - splice the allocated branch onto inode.
++ * @inode: owner
++ * @block: (logical) number of block we are adding
++ * @chain: chain of indirect blocks (with a missing link - see
++ * ext4_alloc_branch)
++ * @where: location of missing link
++ * @num: number of indirect blocks we are adding
++ * @blks: number of direct blocks we are adding
++ *
++ * This function fills the missing link and does all housekeeping needed in
++ * inode (->i_blocks, etc.). In case of success we end up with the full
++ * chain to new block and return 0.
++ */
++static int ext4_splice_branch(handle_t *handle, struct inode *inode,
++ long block, Indirect *where, int num, int blks)
++{
++ int i;
++ int err = 0;
++ struct ext4_block_alloc_info *block_i;
++ ext4_fsblk_t current_block;
++
++ block_i = EXT4_I(inode)->i_block_alloc_info;
++ /*
++ * If we're splicing into a [td]indirect block (as opposed to the
++ * inode) then we need to get write access to the [td]indirect block
++ * before the splice.
++ */
++ if (where->bh) {
++ BUFFER_TRACE(where->bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, where->bh);
++ if (err)
++ goto err_out;
++ }
++ /* That's it */
++
++ *where->p = where->key;
++
++ /*
++ * Update the host buffer_head or inode to point to more just allocated
++ * direct blocks blocks
++ */
++ if (num == 0 && blks > 1) {
++ current_block = le32_to_cpu(where->key) + 1;
++ for (i = 1; i < blks; i++)
++ *(where->p + i ) = cpu_to_le32(current_block++);
++ }
++
++ /*
++ * update the most recently allocated logical & physical block
++ * in i_block_alloc_info, to assist find the proper goal block for next
++ * allocation
++ */
++ if (block_i) {
++ block_i->last_alloc_logical_block = block + blks - 1;
++ block_i->last_alloc_physical_block =
++ le32_to_cpu(where[num].key) + blks - 1;
++ }
++
++ /* We are done with atomic stuff, now do the rest of housekeeping */
++
++ inode->i_ctime = CURRENT_TIME_SEC;
++ ext4_mark_inode_dirty(handle, inode);
++
++ /* had we spliced it onto indirect block? */
++ if (where->bh) {
++ /*
++ * If we spliced it onto an indirect block, we haven't
++ * altered the inode. Note however that if it is being spliced
++ * onto an indirect block at the very end of the file (the
++ * file is growing) then we *will* alter the inode to reflect
++ * the new i_size. But that is not done here - it is done in
++ * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode.
++ */
++ jbd_debug(5, "splicing indirect only\n");
++ BUFFER_TRACE(where->bh, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, where->bh);
++ if (err)
++ goto err_out;
++ } else {
++ /*
++ * OK, we spliced it into the inode itself on a direct block.
++ * Inode was dirtied above.
++ */
++ jbd_debug(5, "splicing direct\n");
++ }
++ return err;
++
++err_out:
++ for (i = 1; i <= num; i++) {
++ BUFFER_TRACE(where[i].bh, "call jbd2_journal_forget");
++ ext4_journal_forget(handle, where[i].bh);
++ ext4_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1);
++ }
++ ext4_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks);
++
++ return err;
++}
++
++/*
++ * Allocation strategy is simple: if we have to allocate something, we will
++ * have to go the whole way to leaf. So let's do it before attaching anything
++ * to tree, set linkage between the newborn blocks, write them if sync is
++ * required, recheck the path, free and repeat if check fails, otherwise
++ * set the last missing link (that will protect us from any truncate-generated
++ * removals - all blocks on the path are immune now) and possibly force the
++ * write on the parent block.
++ * That has a nice additional property: no special recovery from the failed
++ * allocations is needed - we simply release blocks and do not touch anything
++ * reachable from inode.
++ *
++ * `handle' can be NULL if create == 0.
++ *
++ * The BKL may not be held on entry here. Be sure to take it early.
++ * return > 0, # of blocks mapped or allocated.
++ * return = 0, if plain lookup failed.
++ * return < 0, error case.
++ */
++int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
++ sector_t iblock, unsigned long maxblocks,
++ struct buffer_head *bh_result,
++ int create, int extend_disksize)
++{
++ int err = -EIO;
++ int offsets[4];
++ Indirect chain[4];
++ Indirect *partial;
++ ext4_fsblk_t goal;
++ int indirect_blks;
++ int blocks_to_boundary = 0;
++ int depth;
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ int count = 0;
++ ext4_fsblk_t first_block = 0;
++
++
++ J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL));
++ J_ASSERT(handle != NULL || create == 0);
++ depth = ext4_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
++
++ if (depth == 0)
++ goto out;
++
++ partial = ext4_get_branch(inode, depth, offsets, chain, &err);
++
++ /* Simplest case - block found, no allocation needed */
++ if (!partial) {
++ first_block = le32_to_cpu(chain[depth - 1].key);
++ clear_buffer_new(bh_result);
++ count++;
++ /*map more blocks*/
++ while (count < maxblocks && count <= blocks_to_boundary) {
++ ext4_fsblk_t blk;
++
++ if (!verify_chain(chain, partial)) {
++ /*
++ * Indirect block might be removed by
++ * truncate while we were reading it.
++ * Handling of that case: forget what we've
++ * got now. Flag the err as EAGAIN, so it
++ * will reread.
++ */
++ err = -EAGAIN;
++ count = 0;
++ break;
++ }
++ blk = le32_to_cpu(*(chain[depth-1].p + count));
++
++ if (blk == first_block + count)
++ count++;
++ else
++ break;
++ }
++ if (err != -EAGAIN)
++ goto got_it;
++ }
++
++ /* Next simple case - plain lookup or failed read of indirect block */
++ if (!create || err == -EIO)
++ goto cleanup;
++
++ mutex_lock(&ei->truncate_mutex);
++
++ /*
++ * If the indirect block is missing while we are reading
++ * the chain(ext4_get_branch() returns -EAGAIN err), or
++ * if the chain has been changed after we grab the semaphore,
++ * (either because another process truncated this branch, or
++ * another get_block allocated this branch) re-grab the chain to see if
++ * the request block has been allocated or not.
++ *
++ * Since we already block the truncate/other get_block
++ * at this point, we will have the current copy of the chain when we
++ * splice the branch into the tree.
++ */
++ if (err == -EAGAIN || !verify_chain(chain, partial)) {
++ while (partial > chain) {
++ brelse(partial->bh);
++ partial--;
++ }
++ partial = ext4_get_branch(inode, depth, offsets, chain, &err);
++ if (!partial) {
++ count++;
++ mutex_unlock(&ei->truncate_mutex);
++ if (err)
++ goto cleanup;
++ clear_buffer_new(bh_result);
++ goto got_it;
++ }
++ }
++
++ /*
++ * Okay, we need to do block allocation. Lazily initialize the block
++ * allocation info here if necessary
++ */
++ if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
++ ext4_init_block_alloc_info(inode);
++
++ goal = ext4_find_goal(inode, iblock, chain, partial);
++
++ /* the number of blocks need to allocate for [d,t]indirect blocks */
++ indirect_blks = (chain + depth) - partial - 1;
++
++ /*
++ * Next look up the indirect map to count the totoal number of
++ * direct blocks to allocate for this branch.
++ */
++ count = ext4_blks_to_allocate(partial, indirect_blks,
++ maxblocks, blocks_to_boundary);
++ /*
++ * Block out ext4_truncate while we alter the tree
++ */
++ err = ext4_alloc_branch(handle, inode, indirect_blks, &count, goal,
++ offsets + (partial - chain), partial);
++
++ /*
++ * The ext4_splice_branch call will free and forget any buffers
++ * on the new chain if there is a failure, but that risks using
++ * up transaction credits, especially for bitmaps where the
++ * credits cannot be returned. Can we handle this somehow? We
++ * may need to return -EAGAIN upwards in the worst case. --sct
++ */
++ if (!err)
++ err = ext4_splice_branch(handle, inode, iblock,
++ partial, indirect_blks, count);
++ /*
++ * i_disksize growing is protected by truncate_mutex. Don't forget to
++ * protect it if you're about to implement concurrent
++ * ext4_get_block() -bzzz
++ */
++ if (!err && extend_disksize && inode->i_size > ei->i_disksize)
++ ei->i_disksize = inode->i_size;
++ mutex_unlock(&ei->truncate_mutex);
++ if (err)
++ goto cleanup;
++
++ set_buffer_new(bh_result);
++got_it:
++ map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
++ if (count > blocks_to_boundary)
++ set_buffer_boundary(bh_result);
++ err = count;
++ /* Clean up and exit */
++ partial = chain + depth - 1; /* the whole chain */
++cleanup:
++ while (partial > chain) {
++ BUFFER_TRACE(partial->bh, "call brelse");
++ brelse(partial->bh);
++ partial--;
++ }
++ BUFFER_TRACE(bh_result, "returned");
++out:
++ return err;
++}
++
++#define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32)
++
++static int ext4_get_block(struct inode *inode, sector_t iblock,
++ struct buffer_head *bh_result, int create)
++{
++ handle_t *handle = journal_current_handle();
++ int ret = 0;
++ unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
++
++ if (!create)
++ goto get_block; /* A read */
++
++ if (max_blocks == 1)
++ goto get_block; /* A single block get */
++
++ if (handle->h_transaction->t_state == T_LOCKED) {
++ /*
++ * Huge direct-io writes can hold off commits for long
++ * periods of time. Let this commit run.
++ */
++ ext4_journal_stop(handle);
++ handle = ext4_journal_start(inode, DIO_CREDITS);
++ if (IS_ERR(handle))
++ ret = PTR_ERR(handle);
++ goto get_block;
++ }
++
++ if (handle->h_buffer_credits <= EXT4_RESERVE_TRANS_BLOCKS) {
++ /*
++ * Getting low on buffer credits...
++ */
++ ret = ext4_journal_extend(handle, DIO_CREDITS);
++ if (ret > 0) {
++ /*
++ * Couldn't extend the transaction. Start a new one.
++ */
++ ret = ext4_journal_restart(handle, DIO_CREDITS);
++ }
++ }
++
++get_block:
++ if (ret == 0) {
++ ret = ext4_get_blocks_wrap(handle, inode, iblock,
++ max_blocks, bh_result, create, 0);
++ if (ret > 0) {
++ bh_result->b_size = (ret << inode->i_blkbits);
++ ret = 0;
++ }
++ }
++ return ret;
++}
++
++/*
++ * `handle' can be NULL if create is zero
++ */
++struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
++ long block, int create, int *errp)
++{
++ struct buffer_head dummy;
++ int fatal = 0, err;
++
++ J_ASSERT(handle != NULL || create == 0);
++
++ dummy.b_state = 0;
++ dummy.b_blocknr = -1000;
++ buffer_trace_init(&dummy.b_history);
++ err = ext4_get_blocks_wrap(handle, inode, block, 1,
++ &dummy, create, 1);
++ /*
++ * ext4_get_blocks_handle() returns number of blocks
++ * mapped. 0 in case of a HOLE.
++ */
++ if (err > 0) {
++ if (err > 1)
++ WARN_ON(1);
++ err = 0;
++ }
++ *errp = err;
++ if (!err && buffer_mapped(&dummy)) {
++ struct buffer_head *bh;
++ bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
++ if (!bh) {
++ *errp = -EIO;
++ goto err;
++ }
++ if (buffer_new(&dummy)) {
++ J_ASSERT(create != 0);
++ J_ASSERT(handle != 0);
++
++ /*
++ * Now that we do not always journal data, we should
++ * keep in mind whether this should always journal the
++ * new buffer as metadata. For now, regular file
++ * writes use ext4_get_block instead, so it's not a
++ * problem.
++ */
++ lock_buffer(bh);
++ BUFFER_TRACE(bh, "call get_create_access");
++ fatal = ext4_journal_get_create_access(handle, bh);
++ if (!fatal && !buffer_uptodate(bh)) {
++ memset(bh->b_data,0,inode->i_sb->s_blocksize);
++ set_buffer_uptodate(bh);
++ }
++ unlock_buffer(bh);
++ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, bh);
++ if (!fatal)
++ fatal = err;
++ } else {
++ BUFFER_TRACE(bh, "not a new buffer");
++ }
++ if (fatal) {
++ *errp = fatal;
++ brelse(bh);
++ bh = NULL;
++ }
++ return bh;
++ }
++err:
++ return NULL;
++}
++
++struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
++ int block, int create, int *err)
++{
++ struct buffer_head * bh;
++
++ bh = ext4_getblk(handle, inode, block, create, err);
++ if (!bh)
++ return bh;
++ if (buffer_uptodate(bh))
++ return bh;
++ ll_rw_block(READ_META, 1, &bh);
++ wait_on_buffer(bh);
++ if (buffer_uptodate(bh))
++ return bh;
++ put_bh(bh);
++ *err = -EIO;
++ return NULL;
++}
++
++static int walk_page_buffers( handle_t *handle,
++ struct buffer_head *head,
++ unsigned from,
++ unsigned to,
++ int *partial,
++ int (*fn)( handle_t *handle,
++ struct buffer_head *bh))
++{
++ struct buffer_head *bh;
++ unsigned block_start, block_end;
++ unsigned blocksize = head->b_size;
++ int err, ret = 0;
++ struct buffer_head *next;
++
++ for ( bh = head, block_start = 0;
++ ret == 0 && (bh != head || !block_start);
++ block_start = block_end, bh = next)
++ {
++ next = bh->b_this_page;
++ block_end = block_start + blocksize;
++ if (block_end <= from || block_start >= to) {
++ if (partial && !buffer_uptodate(bh))
++ *partial = 1;
++ continue;
++ }
++ err = (*fn)(handle, bh);
++ if (!ret)
++ ret = err;
++ }
++ return ret;
++}
++
++/*
++ * To preserve ordering, it is essential that the hole instantiation and
++ * the data write be encapsulated in a single transaction. We cannot
++ * close off a transaction and start a new one between the ext4_get_block()
++ * and the commit_write(). So doing the jbd2_journal_start at the start of
++ * prepare_write() is the right place.
++ *
++ * Also, this function can nest inside ext4_writepage() ->
++ * block_write_full_page(). In that case, we *know* that ext4_writepage()
++ * has generated enough buffer credits to do the whole page. So we won't
++ * block on the journal in that case, which is good, because the caller may
++ * be PF_MEMALLOC.
++ *
++ * By accident, ext4 can be reentered when a transaction is open via
++ * quota file writes. If we were to commit the transaction while thus
++ * reentered, there can be a deadlock - we would be holding a quota
++ * lock, and the commit would never complete if another thread had a
++ * transaction open and was blocking on the quota lock - a ranking
++ * violation.
++ *
++ * So what we do is to rely on the fact that jbd2_journal_stop/journal_start
++ * will _not_ run commit under these circumstances because handle->h_ref
++ * is elevated. We'll still have enough credits for the tiny quotafile
++ * write.
++ */
++static int do_journal_get_write_access(handle_t *handle,
++ struct buffer_head *bh)
++{
++ if (!buffer_mapped(bh) || buffer_freed(bh))
++ return 0;
++ return ext4_journal_get_write_access(handle, bh);
++}
++
++static int ext4_prepare_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ struct inode *inode = page->mapping->host;
++ int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
++ handle_t *handle;
++ int retries = 0;
++
++retry:
++ handle = ext4_journal_start(inode, needed_blocks);
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out;
++ }
++ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
++ ret = nobh_prepare_write(page, from, to, ext4_get_block);
++ else
++ ret = block_prepare_write(page, from, to, ext4_get_block);
++ if (ret)
++ goto prepare_write_failed;
++
++ if (ext4_should_journal_data(inode)) {
++ ret = walk_page_buffers(handle, page_buffers(page),
++ from, to, NULL, do_journal_get_write_access);
++ }
++prepare_write_failed:
++ if (ret)
++ ext4_journal_stop(handle);
++ if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
++ goto retry;
++out:
++ return ret;
++}
++
++int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
++{
++ int err = jbd2_journal_dirty_data(handle, bh);
++ if (err)
++ ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__,
++ bh, handle,err);
++ return err;
++}
++
++/* For commit_write() in data=journal mode */
++static int commit_write_fn(handle_t *handle, struct buffer_head *bh)
++{
++ if (!buffer_mapped(bh) || buffer_freed(bh))
++ return 0;
++ set_buffer_uptodate(bh);
++ return ext4_journal_dirty_metadata(handle, bh);
++}
++
++/*
++ * We need to pick up the new inode size which generic_commit_write gave us
++ * `file' can be NULL - eg, when called from page_symlink().
++ *
++ * ext4 never places buffers on inode->i_mapping->private_list. metadata
++ * buffers are managed internally.
++ */
++static int ext4_ordered_commit_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ handle_t *handle = ext4_journal_current_handle();
++ struct inode *inode = page->mapping->host;
++ int ret = 0, ret2;
++
++ ret = walk_page_buffers(handle, page_buffers(page),
++ from, to, NULL, ext4_journal_dirty_data);
++
++ if (ret == 0) {
++ /*
++ * generic_commit_write() will run mark_inode_dirty() if i_size
++ * changes. So let's piggyback the i_disksize mark_inode_dirty
++ * into that.
++ */
++ loff_t new_i_size;
++
++ new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
++ if (new_i_size > EXT4_I(inode)->i_disksize)
++ EXT4_I(inode)->i_disksize = new_i_size;
++ ret = generic_commit_write(file, page, from, to);
++ }
++ ret2 = ext4_journal_stop(handle);
++ if (!ret)
++ ret = ret2;
++ return ret;
++}
++
++static int ext4_writeback_commit_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ handle_t *handle = ext4_journal_current_handle();
++ struct inode *inode = page->mapping->host;
++ int ret = 0, ret2;
++ loff_t new_i_size;
++
++ new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
++ if (new_i_size > EXT4_I(inode)->i_disksize)
++ EXT4_I(inode)->i_disksize = new_i_size;
++
++ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
++ ret = nobh_commit_write(file, page, from, to);
++ else
++ ret = generic_commit_write(file, page, from, to);
++
++ ret2 = ext4_journal_stop(handle);
++ if (!ret)
++ ret = ret2;
++ return ret;
++}
++
++static int ext4_journalled_commit_write(struct file *file,
++ struct page *page, unsigned from, unsigned to)
++{
++ handle_t *handle = ext4_journal_current_handle();
++ struct inode *inode = page->mapping->host;
++ int ret = 0, ret2;
++ int partial = 0;
++ loff_t pos;
++
++ /*
++ * Here we duplicate the generic_commit_write() functionality
++ */
++ pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
++
++ ret = walk_page_buffers(handle, page_buffers(page), from,
++ to, &partial, commit_write_fn);
++ if (!partial)
++ SetPageUptodate(page);
++ if (pos > inode->i_size)
++ i_size_write(inode, pos);
++ EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
++ if (inode->i_size > EXT4_I(inode)->i_disksize) {
++ EXT4_I(inode)->i_disksize = inode->i_size;
++ ret2 = ext4_mark_inode_dirty(handle, inode);
++ if (!ret)
++ ret = ret2;
++ }
++ ret2 = ext4_journal_stop(handle);
++ if (!ret)
++ ret = ret2;
++ return ret;
++}
++
++/*
++ * bmap() is special. It gets used by applications such as lilo and by
++ * the swapper to find the on-disk block of a specific piece of data.
++ *
++ * Naturally, this is dangerous if the block concerned is still in the
++ * journal. If somebody makes a swapfile on an ext4 data-journaling
++ * filesystem and enables swap, then they may get a nasty shock when the
++ * data getting swapped to that swapfile suddenly gets overwritten by
++ * the original zero's written out previously to the journal and
++ * awaiting writeback in the kernel's buffer cache.
++ *
++ * So, if we see any bmap calls here on a modified, data-journaled file,
++ * take extra steps to flush any blocks which might be in the cache.
++ */
++static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
++{
++ struct inode *inode = mapping->host;
++ journal_t *journal;
++ int err;
++
++ if (EXT4_I(inode)->i_state & EXT4_STATE_JDATA) {
++ /*
++ * This is a REALLY heavyweight approach, but the use of
++ * bmap on dirty files is expected to be extremely rare:
++ * only if we run lilo or swapon on a freshly made file
++ * do we expect this to happen.
++ *
++ * (bmap requires CAP_SYS_RAWIO so this does not
++ * represent an unprivileged user DOS attack --- we'd be
++ * in trouble if mortal users could trigger this path at
++ * will.)
++ *
++ * NB. EXT4_STATE_JDATA is not set on files other than
++ * regular files. If somebody wants to bmap a directory
++ * or symlink and gets confused because the buffer
++ * hasn't yet been flushed to disk, they deserve
++ * everything they get.
++ */
++
++ EXT4_I(inode)->i_state &= ~EXT4_STATE_JDATA;
++ journal = EXT4_JOURNAL(inode);
++ jbd2_journal_lock_updates(journal);
++ err = jbd2_journal_flush(journal);
++ jbd2_journal_unlock_updates(journal);
++
++ if (err)
++ return 0;
++ }
++
++ return generic_block_bmap(mapping,block,ext4_get_block);
++}
++
++static int bget_one(handle_t *handle, struct buffer_head *bh)
++{
++ get_bh(bh);
++ return 0;
++}
++
++static int bput_one(handle_t *handle, struct buffer_head *bh)
++{
++ put_bh(bh);
++ return 0;
++}
++
++static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
++{
++ if (buffer_mapped(bh))
++ return ext4_journal_dirty_data(handle, bh);
++ return 0;
++}
++
++/*
++ * Note that we always start a transaction even if we're not journalling
++ * data. This is to preserve ordering: any hole instantiation within
++ * __block_write_full_page -> ext4_get_block() should be journalled
++ * along with the data so we don't crash and then get metadata which
++ * refers to old data.
++ *
++ * In all journalling modes block_write_full_page() will start the I/O.
++ *
++ * Problem:
++ *
++ * ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
++ * ext4_writepage()
++ *
++ * Similar for:
++ *
++ * ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ...
++ *
++ * Same applies to ext4_get_block(). We will deadlock on various things like
++ * lock_journal and i_truncate_mutex.
++ *
++ * Setting PF_MEMALLOC here doesn't work - too many internal memory
++ * allocations fail.
++ *
++ * 16May01: If we're reentered then journal_current_handle() will be
++ * non-zero. We simply *return*.
++ *
++ * 1 July 2001: @@@ FIXME:
++ * In journalled data mode, a data buffer may be metadata against the
++ * current transaction. But the same file is part of a shared mapping
++ * and someone does a writepage() on it.
++ *
++ * We will move the buffer onto the async_data list, but *after* it has
++ * been dirtied. So there's a small window where we have dirty data on
++ * BJ_Metadata.
++ *
++ * Note that this only applies to the last partial page in the file. The
++ * bit which block_write_full_page() uses prepare/commit for. (That's
++ * broken code anyway: it's wrong for msync()).
++ *
++ * It's a rare case: affects the final partial page, for journalled data
++ * where the file is subject to bith write() and writepage() in the same
++ * transction. To fix it we'll need a custom block_write_full_page().
++ * We'll probably need that anyway for journalling writepage() output.
++ *
++ * We don't honour synchronous mounts for writepage(). That would be
++ * disastrous. Any write() or metadata operation will sync the fs for
++ * us.
++ *
++ * AKPM2: if all the page's buffers are mapped to disk and !data=journal,
++ * we don't need to open a transaction here.
++ */
++static int ext4_ordered_writepage(struct page *page,
++ struct writeback_control *wbc)
++{
++ struct inode *inode = page->mapping->host;
++ struct buffer_head *page_bufs;
++ handle_t *handle = NULL;
++ int ret = 0;
++ int err;
++
++ J_ASSERT(PageLocked(page));
++
++ /*
++ * We give up here if we're reentered, because it might be for a
++ * different filesystem.
++ */
++ if (ext4_journal_current_handle())
++ goto out_fail;
++
++ handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
++
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out_fail;
++ }
++
++ if (!page_has_buffers(page)) {
++ create_empty_buffers(page, inode->i_sb->s_blocksize,
++ (1 << BH_Dirty)|(1 << BH_Uptodate));
++ }
++ page_bufs = page_buffers(page);
++ walk_page_buffers(handle, page_bufs, 0,
++ PAGE_CACHE_SIZE, NULL, bget_one);
++
++ ret = block_write_full_page(page, ext4_get_block, wbc);
++
++ /*
++ * The page can become unlocked at any point now, and
++ * truncate can then come in and change things. So we
++ * can't touch *page from now on. But *page_bufs is
++ * safe due to elevated refcount.
++ */
++
++ /*
++ * And attach them to the current transaction. But only if
++ * block_write_full_page() succeeded. Otherwise they are unmapped,
++ * and generally junk.
++ */
++ if (ret == 0) {
++ err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
++ NULL, jbd2_journal_dirty_data_fn);
++ if (!ret)
++ ret = err;
++ }
++ walk_page_buffers(handle, page_bufs, 0,
++ PAGE_CACHE_SIZE, NULL, bput_one);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++
++out_fail:
++ redirty_page_for_writepage(wbc, page);
++ unlock_page(page);
++ return ret;
++}
++
++static int ext4_writeback_writepage(struct page *page,
++ struct writeback_control *wbc)
++{
++ struct inode *inode = page->mapping->host;
++ handle_t *handle = NULL;
++ int ret = 0;
++ int err;
++
++ if (ext4_journal_current_handle())
++ goto out_fail;
++
++ handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out_fail;
++ }
++
++ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
++ ret = nobh_writepage(page, ext4_get_block, wbc);
++ else
++ ret = block_write_full_page(page, ext4_get_block, wbc);
++
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++
++out_fail:
++ redirty_page_for_writepage(wbc, page);
++ unlock_page(page);
++ return ret;
++}
++
++static int ext4_journalled_writepage(struct page *page,
++ struct writeback_control *wbc)
++{
++ struct inode *inode = page->mapping->host;
++ handle_t *handle = NULL;
++ int ret = 0;
++ int err;
++
++ if (ext4_journal_current_handle())
++ goto no_write;
++
++ handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto no_write;
++ }
++
++ if (!page_has_buffers(page) || PageChecked(page)) {
++ /*
++ * It's mmapped pagecache. Add buffers and journal it. There
++ * doesn't seem much point in redirtying the page here.
++ */
++ ClearPageChecked(page);
++ ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
++ ext4_get_block);
++ if (ret != 0) {
++ ext4_journal_stop(handle);
++ goto out_unlock;
++ }
++ ret = walk_page_buffers(handle, page_buffers(page), 0,
++ PAGE_CACHE_SIZE, NULL, do_journal_get_write_access);
++
++ err = walk_page_buffers(handle, page_buffers(page), 0,
++ PAGE_CACHE_SIZE, NULL, commit_write_fn);
++ if (ret == 0)
++ ret = err;
++ EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
++ unlock_page(page);
++ } else {
++ /*
++ * It may be a page full of checkpoint-mode buffers. We don't
++ * really know unless we go poke around in the buffer_heads.
++ * But block_write_full_page will do the right thing.
++ */
++ ret = block_write_full_page(page, ext4_get_block, wbc);
++ }
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++out:
++ return ret;
++
++no_write:
++ redirty_page_for_writepage(wbc, page);
++out_unlock:
++ unlock_page(page);
++ goto out;
++}
++
++static int ext4_readpage(struct file *file, struct page *page)
++{
++ return mpage_readpage(page, ext4_get_block);
++}
++
++static int
++ext4_readpages(struct file *file, struct address_space *mapping,
++ struct list_head *pages, unsigned nr_pages)
++{
++ return mpage_readpages(mapping, pages, nr_pages, ext4_get_block);
++}
++
++static void ext4_invalidatepage(struct page *page, unsigned long offset)
++{
++ journal_t *journal = EXT4_JOURNAL(page->mapping->host);
++
++ /*
++ * If it's a full truncate we just forget about the pending dirtying
++ */
++ if (offset == 0)
++ ClearPageChecked(page);
++
++ jbd2_journal_invalidatepage(journal, page, offset);
++}
++
++static int ext4_releasepage(struct page *page, gfp_t wait)
++{
++ journal_t *journal = EXT4_JOURNAL(page->mapping->host);
++
++ WARN_ON(PageChecked(page));
++ if (!page_has_buffers(page))
++ return 0;
++ return jbd2_journal_try_to_free_buffers(journal, page, wait);
++}
++
++/*
++ * If the O_DIRECT write will extend the file then add this inode to the
++ * orphan list. So recovery will truncate it back to the original size
++ * if the machine crashes during the write.
++ *
++ * If the O_DIRECT write is intantiating holes inside i_size and the machine
++ * crashes then stale disk data _may_ be exposed inside the file.
++ */
++static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
++ 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 ext4_inode_info *ei = EXT4_I(inode);
++ handle_t *handle = NULL;
++ ssize_t ret;
++ int orphan = 0;
++ size_t count = iov_length(iov, nr_segs);
++
++ if (rw == WRITE) {
++ loff_t final_size = offset + count;
++
++ handle = ext4_journal_start(inode, DIO_CREDITS);
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out;
++ }
++ if (final_size > inode->i_size) {
++ ret = ext4_orphan_add(handle, inode);
++ if (ret)
++ goto out_stop;
++ orphan = 1;
++ ei->i_disksize = inode->i_size;
++ }
++ }
++
++ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
++ offset, nr_segs,
++ ext4_get_block, NULL);
++
++ /*
++ * Reacquire the handle: ext4_get_block() can restart the transaction
++ */
++ handle = journal_current_handle();
++
++out_stop:
++ if (handle) {
++ int err;
++
++ if (orphan && inode->i_nlink)
++ ext4_orphan_del(handle, inode);
++ if (orphan && ret > 0) {
++ loff_t end = offset + ret;
++ if (end > inode->i_size) {
++ ei->i_disksize = end;
++ i_size_write(inode, end);
++ /*
++ * We're going to return a positive `ret'
++ * here due to non-zero-length I/O, so there's
++ * no way of reporting error returns from
++ * ext4_mark_inode_dirty() to userspace. So
++ * ignore it.
++ */
++ ext4_mark_inode_dirty(handle, inode);
++ }
++ }
++ err = ext4_journal_stop(handle);
++ if (ret == 0)
++ ret = err;
++ }
++out:
++ return ret;
++}
++
++/*
++ * Pages can be marked dirty completely asynchronously from ext4's journalling
++ * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do
++ * much here because ->set_page_dirty is called under VFS locks. The page is
++ * not necessarily locked.
++ *
++ * We cannot just dirty the page and leave attached buffers clean, because the
++ * buffers' dirty state is "definitive". We cannot just set the buffers dirty
++ * or jbddirty because all the journalling code will explode.
++ *
++ * So what we do is to mark the page "pending dirty" and next time writepage
++ * is called, propagate that into the buffers appropriately.
++ */
++static int ext4_journalled_set_page_dirty(struct page *page)
++{
++ SetPageChecked(page);
++ return __set_page_dirty_nobuffers(page);
++}
++
++static const struct address_space_operations ext4_ordered_aops = {
++ .readpage = ext4_readpage,
++ .readpages = ext4_readpages,
++ .writepage = ext4_ordered_writepage,
++ .sync_page = block_sync_page,
++ .prepare_write = ext4_prepare_write,
++ .commit_write = ext4_ordered_commit_write,
++ .bmap = ext4_bmap,
++ .invalidatepage = ext4_invalidatepage,
++ .releasepage = ext4_releasepage,
++ .direct_IO = ext4_direct_IO,
++ .migratepage = buffer_migrate_page,
++};
++
++static const struct address_space_operations ext4_writeback_aops = {
++ .readpage = ext4_readpage,
++ .readpages = ext4_readpages,
++ .writepage = ext4_writeback_writepage,
++ .sync_page = block_sync_page,
++ .prepare_write = ext4_prepare_write,
++ .commit_write = ext4_writeback_commit_write,
++ .bmap = ext4_bmap,
++ .invalidatepage = ext4_invalidatepage,
++ .releasepage = ext4_releasepage,
++ .direct_IO = ext4_direct_IO,
++ .migratepage = buffer_migrate_page,
++};
++
++static const struct address_space_operations ext4_journalled_aops = {
++ .readpage = ext4_readpage,
++ .readpages = ext4_readpages,
++ .writepage = ext4_journalled_writepage,
++ .sync_page = block_sync_page,
++ .prepare_write = ext4_prepare_write,
++ .commit_write = ext4_journalled_commit_write,
++ .set_page_dirty = ext4_journalled_set_page_dirty,
++ .bmap = ext4_bmap,
++ .invalidatepage = ext4_invalidatepage,
++ .releasepage = ext4_releasepage,
++};
++
++void ext4_set_aops(struct inode *inode)
++{
++ if (ext4_should_order_data(inode))
++ inode->i_mapping->a_ops = &ext4_ordered_aops;
++ else if (ext4_should_writeback_data(inode))
++ inode->i_mapping->a_ops = &ext4_writeback_aops;
++ else
++ inode->i_mapping->a_ops = &ext4_journalled_aops;
++}
++
++/*
++ * ext4_block_truncate_page() zeroes out a mapping from file offset `from'
++ * up to the end of the block which corresponds to `from'.
++ * This required during truncate. We need to physically zero the tail end
++ * of that block so it doesn't yield old data if the file is later grown.
++ */
++int ext4_block_truncate_page(handle_t *handle, struct page *page,
++ struct address_space *mapping, loff_t from)
++{
++ ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
++ unsigned offset = from & (PAGE_CACHE_SIZE-1);
++ unsigned blocksize, iblock, length, pos;
++ struct inode *inode = mapping->host;
++ struct buffer_head *bh;
++ int err = 0;
++ void *kaddr;
++
++ blocksize = inode->i_sb->s_blocksize;
++ length = blocksize - (offset & (blocksize - 1));
++ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
++
++ /*
++ * For "nobh" option, we can only work if we don't need to
++ * read-in the page - otherwise we create buffers to do the IO.
++ */
++ if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
++ ext4_should_writeback_data(inode) && PageUptodate(page)) {
++ kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + offset, 0, length);
++ flush_dcache_page(page);
++ kunmap_atomic(kaddr, KM_USER0);
++ set_page_dirty(page);
++ goto unlock;
++ }
++
++ if (!page_has_buffers(page))
++ create_empty_buffers(page, blocksize, 0);
++
++ /* Find the buffer that contains "offset" */
++ bh = page_buffers(page);
++ pos = blocksize;
++ while (offset >= pos) {
++ bh = bh->b_this_page;
++ iblock++;
++ pos += blocksize;
++ }
++
++ err = 0;
++ if (buffer_freed(bh)) {
++ BUFFER_TRACE(bh, "freed: skip");
++ goto unlock;
++ }
++
++ if (!buffer_mapped(bh)) {
++ BUFFER_TRACE(bh, "unmapped");
++ ext4_get_block(inode, iblock, bh, 0);
++ /* unmapped? It's a hole - nothing to do */
++ if (!buffer_mapped(bh)) {
++ BUFFER_TRACE(bh, "still unmapped");
++ goto unlock;
++ }
++ }
++
++ /* Ok, it's mapped. Make sure it's up-to-date */
++ if (PageUptodate(page))
++ set_buffer_uptodate(bh);
++
++ if (!buffer_uptodate(bh)) {
++ err = -EIO;
++ ll_rw_block(READ, 1, &bh);
++ wait_on_buffer(bh);
++ /* Uhhuh. Read error. Complain and punt. */
++ if (!buffer_uptodate(bh))
++ goto unlock;
++ }
++
++ if (ext4_should_journal_data(inode)) {
++ BUFFER_TRACE(bh, "get write access");
++ err = ext4_journal_get_write_access(handle, bh);
++ if (err)
++ goto unlock;
++ }
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + offset, 0, length);
++ flush_dcache_page(page);
++ kunmap_atomic(kaddr, KM_USER0);
++
++ BUFFER_TRACE(bh, "zeroed end of block");
++
++ err = 0;
++ if (ext4_should_journal_data(inode)) {
++ err = ext4_journal_dirty_metadata(handle, bh);
++ } else {
++ if (ext4_should_order_data(inode))
++ err = ext4_journal_dirty_data(handle, bh);
++ mark_buffer_dirty(bh);
++ }
++
++unlock:
++ unlock_page(page);
++ page_cache_release(page);
++ return err;
++}
++
++/*
++ * Probably it should be a library function... search for first non-zero word
++ * or memcmp with zero_page, whatever is better for particular architecture.
++ * Linus?
++ */
++static inline int all_zeroes(__le32 *p, __le32 *q)
++{
++ while (p < q)
++ if (*p++)
++ return 0;
++ return 1;
++}
++
++/**
++ * ext4_find_shared - find the indirect blocks for partial truncation.
++ * @inode: inode in question
++ * @depth: depth of the affected branch
++ * @offsets: offsets of pointers in that branch (see ext4_block_to_path)
++ * @chain: place to store the pointers to partial indirect blocks
++ * @top: place to the (detached) top of branch
++ *
++ * This is a helper function used by ext4_truncate().
++ *
++ * When we do truncate() we may have to clean the ends of several
++ * indirect blocks but leave the blocks themselves alive. Block is
++ * partially truncated if some data below the new i_size is refered
++ * from it (and it is on the path to the first completely truncated
++ * data block, indeed). We have to free the top of that path along
++ * with everything to the right of the path. Since no allocation
++ * past the truncation point is possible until ext4_truncate()
++ * finishes, we may safely do the latter, but top of branch may
++ * require special attention - pageout below the truncation point
++ * might try to populate it.
++ *
++ * We atomically detach the top of branch from the tree, store the
++ * block number of its root in *@top, pointers to buffer_heads of
++ * partially truncated blocks - in @chain[].bh and pointers to
++ * their last elements that should not be removed - in
++ * @chain[].p. Return value is the pointer to last filled element
++ * of @chain.
++ *
++ * The work left to caller to do the actual freeing of subtrees:
++ * a) free the subtree starting from *@top
++ * b) free the subtrees whose roots are stored in
++ * (@chain[i].p+1 .. end of @chain[i].bh->b_data)
++ * c) free the subtrees growing from the inode past the @chain[0].
++ * (no partially truncated stuff there). */
++
++static Indirect *ext4_find_shared(struct inode *inode, int depth,
++ int offsets[4], Indirect chain[4], __le32 *top)
++{
++ Indirect *partial, *p;
++ int k, err;
++
++ *top = 0;
++ /* Make k index the deepest non-null offest + 1 */
++ for (k = depth; k > 1 && !offsets[k-1]; k--)
++ ;
++ partial = ext4_get_branch(inode, k, offsets, chain, &err);
++ /* Writer: pointers */
++ if (!partial)
++ partial = chain + k-1;
++ /*
++ * If the branch acquired continuation since we've looked at it -
++ * fine, it should all survive and (new) top doesn't belong to us.
++ */
++ if (!partial->key && *partial->p)
++ /* Writer: end */
++ goto no_top;
++ for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--)
++ ;
++ /*
++ * OK, we've found the last block that must survive. The rest of our
++ * branch should be detached before unlocking. However, if that rest
++ * of branch is all ours and does not grow immediately from the inode
++ * it's easier to cheat and just decrement partial->p.
++ */
++ if (p == chain + k - 1 && p > chain) {
++ p->p--;
++ } else {
++ *top = *p->p;
++ /* Nope, don't do this in ext4. Must leave the tree intact */
++#if 0
++ *p->p = 0;
++#endif
++ }
++ /* Writer: end */
++
++ while(partial > p) {
++ brelse(partial->bh);
++ partial--;
++ }
++no_top:
++ return partial;
++}
++
++/*
++ * Zero a number of block pointers in either an inode or an indirect block.
++ * If we restart the transaction we must again get write access to the
++ * indirect block for further modification.
++ *
++ * We release `count' blocks on disk, but (last - first) may be greater
++ * than `count' because there can be holes in there.
++ */
++static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
++ struct buffer_head *bh, ext4_fsblk_t block_to_free,
++ unsigned long count, __le32 *first, __le32 *last)
++{
++ __le32 *p;
++ if (try_to_extend_transaction(handle, inode)) {
++ if (bh) {
++ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle, bh);
++ }
++ ext4_mark_inode_dirty(handle, inode);
++ ext4_journal_test_restart(handle, inode);
++ if (bh) {
++ BUFFER_TRACE(bh, "retaking write access");
++ ext4_journal_get_write_access(handle, bh);
++ }
++ }
++
++ /*
++ * Any buffers which are on the journal will be in memory. We find
++ * them on the hash table so jbd2_journal_revoke() will run jbd2_journal_forget()
++ * on them. We've already detached each block from the file, so
++ * bforget() in jbd2_journal_forget() should be safe.
++ *
++ * AKPM: turn on bforget in jbd2_journal_forget()!!!
++ */
++ for (p = first; p < last; p++) {
++ u32 nr = le32_to_cpu(*p);
++ if (nr) {
++ struct buffer_head *bh;
++
++ *p = 0;
++ bh = sb_find_get_block(inode->i_sb, nr);
++ ext4_forget(handle, 0, inode, bh, nr);
++ }
++ }
++
++ ext4_free_blocks(handle, inode, block_to_free, count);
++}
++
++/**
++ * ext4_free_data - free a list of data blocks
++ * @handle: handle for this transaction
++ * @inode: inode we are dealing with
++ * @this_bh: indirect buffer_head which contains *@first and *@last
++ * @first: array of block numbers
++ * @last: points immediately past the end of array
++ *
++ * We are freeing all blocks refered from that array (numbers are stored as
++ * little-endian 32-bit) and updating @inode->i_blocks appropriately.
++ *
++ * We accumulate contiguous runs of blocks to free. Conveniently, if these
++ * blocks are contiguous then releasing them at one time will only affect one
++ * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't
++ * actually use a lot of journal space.
++ *
++ * @this_bh will be %NULL if @first and @last point into the inode's direct
++ * block pointers.
++ */
++static void ext4_free_data(handle_t *handle, struct inode *inode,
++ struct buffer_head *this_bh,
++ __le32 *first, __le32 *last)
++{
++ ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */
++ unsigned long count = 0; /* Number of blocks in the run */
++ __le32 *block_to_free_p = NULL; /* Pointer into inode/ind
++ corresponding to
++ block_to_free */
++ ext4_fsblk_t nr; /* Current block # */
++ __le32 *p; /* Pointer into inode/ind
++ for current block */
++ int err;
++
++ if (this_bh) { /* For indirect block */
++ BUFFER_TRACE(this_bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, this_bh);
++ /* Important: if we can't update the indirect pointers
++ * to the blocks, we can't free them. */
++ if (err)
++ return;
++ }
++
++ for (p = first; p < last; p++) {
++ nr = le32_to_cpu(*p);
++ if (nr) {
++ /* accumulate blocks to free if they're contiguous */
++ if (count == 0) {
++ block_to_free = nr;
++ block_to_free_p = p;
++ count = 1;
++ } else if (nr == block_to_free + count) {
++ count++;
++ } else {
++ ext4_clear_blocks(handle, inode, this_bh,
++ block_to_free,
++ count, block_to_free_p, p);
++ block_to_free = nr;
++ block_to_free_p = p;
++ count = 1;
++ }
++ }
++ }
++
++ if (count > 0)
++ ext4_clear_blocks(handle, inode, this_bh, block_to_free,
++ count, block_to_free_p, p);
++
++ if (this_bh) {
++ BUFFER_TRACE(this_bh, "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle, this_bh);
++ }
++}
++
++/**
++ * ext4_free_branches - free an array of branches
++ * @handle: JBD handle for this transaction
++ * @inode: inode we are dealing with
++ * @parent_bh: the buffer_head which contains *@first and *@last
++ * @first: array of block numbers
++ * @last: pointer immediately past the end of array
++ * @depth: depth of the branches to free
++ *
++ * We are freeing all blocks refered from these branches (numbers are
++ * stored as little-endian 32-bit) and updating @inode->i_blocks
++ * appropriately.
++ */
++static void ext4_free_branches(handle_t *handle, struct inode *inode,
++ struct buffer_head *parent_bh,
++ __le32 *first, __le32 *last, int depth)
++{
++ ext4_fsblk_t nr;
++ __le32 *p;
++
++ if (is_handle_aborted(handle))
++ return;
++
++ if (depth--) {
++ struct buffer_head *bh;
++ int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
++ p = last;
++ while (--p >= first) {
++ nr = le32_to_cpu(*p);
++ if (!nr)
++ continue; /* A hole */
++
++ /* Go read the buffer for the next level down */
++ bh = sb_bread(inode->i_sb, nr);
++
++ /*
++ * A read failure? Report error and clear slot
++ * (should be rare).
++ */
++ if (!bh) {
++ ext4_error(inode->i_sb, "ext4_free_branches",
++ "Read failure, inode=%lu, block=%llu",
++ inode->i_ino, nr);
++ continue;
++ }
++
++ /* This zaps the entire block. Bottom up. */
++ BUFFER_TRACE(bh, "free child branches");
++ ext4_free_branches(handle, inode, bh,
++ (__le32*)bh->b_data,
++ (__le32*)bh->b_data + addr_per_block,
++ depth);
++
++ /*
++ * We've probably journalled the indirect block several
++ * times during the truncate. But it's no longer
++ * needed and we now drop it from the transaction via
++ * jbd2_journal_revoke().
++ *
++ * That's easy if it's exclusively part of this
++ * transaction. But if it's part of the committing
++ * transaction then jbd2_journal_forget() will simply
++ * brelse() it. That means that if the underlying
++ * block is reallocated in ext4_get_block(),
++ * unmap_underlying_metadata() will find this block
++ * and will try to get rid of it. damn, damn.
++ *
++ * If this block has already been committed to the
++ * journal, a revoke record will be written. And
++ * revoke records must be emitted *before* clearing
++ * this block's bit in the bitmaps.
++ */
++ ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
++
++ /*
++ * Everything below this this pointer has been
++ * released. Now let this top-of-subtree go.
++ *
++ * We want the freeing of this indirect block to be
++ * atomic in the journal with the updating of the
++ * bitmap block which owns it. So make some room in
++ * the journal.
++ *
++ * We zero the parent pointer *after* freeing its
++ * pointee in the bitmaps, so if extend_transaction()
++ * for some reason fails to put the bitmap changes and
++ * the release into the same transaction, recovery
++ * will merely complain about releasing a free block,
++ * rather than leaking blocks.
++ */
++ if (is_handle_aborted(handle))
++ return;
++ if (try_to_extend_transaction(handle, inode)) {
++ ext4_mark_inode_dirty(handle, inode);
++ ext4_journal_test_restart(handle, inode);
++ }
++
++ ext4_free_blocks(handle, inode, nr, 1);
++
++ if (parent_bh) {
++ /*
++ * The block which we have just freed is
++ * pointed to by an indirect block: journal it
++ */
++ BUFFER_TRACE(parent_bh, "get_write_access");
++ if (!ext4_journal_get_write_access(handle,
++ parent_bh)){
++ *p = 0;
++ BUFFER_TRACE(parent_bh,
++ "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle,
++ parent_bh);
++ }
++ }
++ }
++ } else {
++ /* We have reached the bottom of the tree. */
++ BUFFER_TRACE(parent_bh, "free data blocks");
++ ext4_free_data(handle, inode, parent_bh, first, last);
++ }
++}
++
++/*
++ * ext4_truncate()
++ *
++ * We block out ext4_get_block() block instantiations across the entire
++ * transaction, and VFS/VM ensures that ext4_truncate() cannot run
++ * simultaneously on behalf of the same inode.
++ *
++ * As we work through the truncate and commmit bits of it to the journal there
++ * is one core, guiding principle: the file's tree must always be consistent on
++ * disk. We must be able to restart the truncate after a crash.
++ *
++ * The file's tree may be transiently inconsistent in memory (although it
++ * probably isn't), but whenever we close off and commit a journal transaction,
++ * the contents of (the filesystem + the journal) must be consistent and
++ * restartable. It's pretty simple, really: bottom up, right to left (although
++ * left-to-right works OK too).
++ *
++ * Note that at recovery time, journal replay occurs *before* the restart of
++ * truncate against the orphan inode list.
++ *
++ * The committed inode has the new, desired i_size (which is the same as
++ * i_disksize in this case). After a crash, ext4_orphan_cleanup() will see
++ * that this inode's truncate did not complete and it will again call
++ * ext4_truncate() to have another go. So there will be instantiated blocks
++ * to the right of the truncation point in a crashed ext4 filesystem. But
++ * that's fine - as long as they are linked from the inode, the post-crash
++ * ext4_truncate() run will find them and release them.
++ */
++void ext4_truncate(struct inode *inode)
++{
++ handle_t *handle;
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ __le32 *i_data = ei->i_data;
++ int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
++ struct address_space *mapping = inode->i_mapping;
++ int offsets[4];
++ Indirect chain[4];
++ Indirect *partial;
++ __le32 nr = 0;
++ int n;
++ long last_block;
++ unsigned blocksize = inode->i_sb->s_blocksize;
++ struct page *page;
++
++ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
++ S_ISLNK(inode->i_mode)))
++ return;
++ if (ext4_inode_is_fast_symlink(inode))
++ return;
++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
++ return;
++
++ /*
++ * We have to lock the EOF page here, because lock_page() nests
++ * outside jbd2_journal_start().
++ */
++ if ((inode->i_size & (blocksize - 1)) == 0) {
++ /* Block boundary? Nothing to do */
++ page = NULL;
++ } else {
++ page = grab_cache_page(mapping,
++ inode->i_size >> PAGE_CACHE_SHIFT);
++ if (!page)
++ return;
++ }
++
++ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
++ return ext4_ext_truncate(inode, page);
++
++ handle = start_transaction(inode);
++ if (IS_ERR(handle)) {
++ if (page) {
++ clear_highpage(page);
++ flush_dcache_page(page);
++ unlock_page(page);
++ page_cache_release(page);
++ }
++ return; /* AKPM: return what? */
++ }
++
++ last_block = (inode->i_size + blocksize-1)
++ >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
++
++ if (page)
++ ext4_block_truncate_page(handle, page, mapping, inode->i_size);
++
++ n = ext4_block_to_path(inode, last_block, offsets, NULL);
++ if (n == 0)
++ goto out_stop; /* error */
++
++ /*
++ * OK. This truncate is going to happen. We add the inode to the
++ * orphan list, so that if this truncate spans multiple transactions,
++ * and we crash, we will resume the truncate when the filesystem
++ * recovers. It also marks the inode dirty, to catch the new size.
++ *
++ * Implication: the file must always be in a sane, consistent
++ * truncatable state while each transaction commits.
++ */
++ if (ext4_orphan_add(handle, inode))
++ goto out_stop;
++
++ /*
++ * The orphan list entry will now protect us from any crash which
++ * occurs before the truncate completes, so it is now safe to propagate
++ * the new, shorter inode size (held for now in i_size) into the
++ * on-disk inode. We do this via i_disksize, which is the value which
++ * ext4 *really* writes onto the disk inode.
++ */
++ ei->i_disksize = inode->i_size;
++
++ /*
++ * From here we block out all ext4_get_block() callers who want to
++ * modify the block allocation tree.
++ */
++ mutex_lock(&ei->truncate_mutex);
++
++ if (n == 1) { /* direct blocks */
++ ext4_free_data(handle, inode, NULL, i_data+offsets[0],
++ i_data + EXT4_NDIR_BLOCKS);
++ goto do_indirects;
++ }
++
++ partial = ext4_find_shared(inode, n, offsets, chain, &nr);
++ /* Kill the top of shared branch (not detached) */
++ if (nr) {
++ if (partial == chain) {
++ /* Shared branch grows from the inode */
++ ext4_free_branches(handle, inode, NULL,
++ &nr, &nr+1, (chain+n-1) - partial);
++ *partial->p = 0;
++ /*
++ * We mark the inode dirty prior to restart,
++ * and prior to stop. No need for it here.
++ */
++ } else {
++ /* Shared branch grows from an indirect block */
++ BUFFER_TRACE(partial->bh, "get_write_access");
++ ext4_free_branches(handle, inode, partial->bh,
++ partial->p,
++ partial->p+1, (chain+n-1) - partial);
++ }
++ }
++ /* Clear the ends of indirect blocks on the shared branch */
++ while (partial > chain) {
++ ext4_free_branches(handle, inode, partial->bh, partial->p + 1,
++ (__le32*)partial->bh->b_data+addr_per_block,
++ (chain+n-1) - partial);
++ BUFFER_TRACE(partial->bh, "call brelse");
++ brelse (partial->bh);
++ partial--;
++ }
++do_indirects:
++ /* Kill the remaining (whole) subtrees */
++ switch (offsets[0]) {
++ default:
++ nr = i_data[EXT4_IND_BLOCK];
++ if (nr) {
++ ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
++ i_data[EXT4_IND_BLOCK] = 0;
++ }
++ case EXT4_IND_BLOCK:
++ nr = i_data[EXT4_DIND_BLOCK];
++ if (nr) {
++ ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
++ i_data[EXT4_DIND_BLOCK] = 0;
++ }
++ case EXT4_DIND_BLOCK:
++ nr = i_data[EXT4_TIND_BLOCK];
++ if (nr) {
++ ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
++ i_data[EXT4_TIND_BLOCK] = 0;
++ }
++ case EXT4_TIND_BLOCK:
++ ;
++ }
++
++ ext4_discard_reservation(inode);
++
++ mutex_unlock(&ei->truncate_mutex);
++ inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
++ ext4_mark_inode_dirty(handle, inode);
++
++ /*
++ * In a multi-transaction truncate, we only make the final transaction
++ * synchronous
++ */
++ if (IS_SYNC(inode))
++ handle->h_sync = 1;
++out_stop:
++ /*
++ * If this was a simple ftruncate(), and the file will remain alive
++ * then we need to clear up the orphan record which we created above.
++ * However, if this was a real unlink then we were called by
++ * ext4_delete_inode(), and we allow that function to clean up the
++ * orphan info for us.
++ */
++ if (inode->i_nlink)
++ ext4_orphan_del(handle, inode);
++
++ ext4_journal_stop(handle);
++}
++
++static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
++ unsigned long ino, struct ext4_iloc *iloc)
++{
++ unsigned long desc, group_desc, block_group;
++ unsigned long offset;
++ ext4_fsblk_t block;
++ struct buffer_head *bh;
++ struct ext4_group_desc * gdp;
++
++ if (!ext4_valid_inum(sb, ino)) {
++ /*
++ * This error is already checked for in namei.c unless we are
++ * looking at an NFS filehandle, in which case no error
++ * report is needed
++ */
++ return 0;
++ }
++
++ block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
++ if (block_group >= EXT4_SB(sb)->s_groups_count) {
++ ext4_error(sb,"ext4_get_inode_block","group >= groups count");
++ return 0;
++ }
++ smp_rmb();
++ group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
++ desc = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
++ bh = EXT4_SB(sb)->s_group_desc[group_desc];
++ if (!bh) {
++ ext4_error (sb, "ext4_get_inode_block",
++ "Descriptor not loaded");
++ return 0;
++ }
++
++ gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data +
++ desc * EXT4_DESC_SIZE(sb));
++ /*
++ * Figure out the offset within the block group inode table
++ */
++ offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
++ EXT4_INODE_SIZE(sb);
++ block = ext4_inode_table(sb, gdp) +
++ (offset >> EXT4_BLOCK_SIZE_BITS(sb));
++
++ iloc->block_group = block_group;
++ iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1);
++ return block;
++}
++
++/*
++ * ext4_get_inode_loc returns with an extra refcount against the inode's
++ * underlying buffer_head on success. If 'in_mem' is true, we have all
++ * data in memory that is needed to recreate the on-disk version of this
++ * inode.
++ */
++static int __ext4_get_inode_loc(struct inode *inode,
++ struct ext4_iloc *iloc, int in_mem)
++{
++ ext4_fsblk_t block;
++ struct buffer_head *bh;
++
++ block = ext4_get_inode_block(inode->i_sb, inode->i_ino, iloc);
++ if (!block)
++ return -EIO;
++
++ bh = sb_getblk(inode->i_sb, block);
++ if (!bh) {
++ ext4_error (inode->i_sb, "ext4_get_inode_loc",
++ "unable to read inode block - "
++ "inode=%lu, block=%llu",
++ inode->i_ino, block);
++ return -EIO;
++ }
++ if (!buffer_uptodate(bh)) {
++ lock_buffer(bh);
++ if (buffer_uptodate(bh)) {
++ /* someone brought it uptodate while we waited */
++ unlock_buffer(bh);
++ goto has_buffer;
++ }
++
++ /*
++ * If we have all information of the inode in memory and this
++ * is the only valid inode in the block, we need not read the
++ * block.
++ */
++ if (in_mem) {
++ struct buffer_head *bitmap_bh;
++ struct ext4_group_desc *desc;
++ int inodes_per_buffer;
++ int inode_offset, i;
++ int block_group;
++ int start;
++
++ block_group = (inode->i_ino - 1) /
++ EXT4_INODES_PER_GROUP(inode->i_sb);
++ inodes_per_buffer = bh->b_size /
++ EXT4_INODE_SIZE(inode->i_sb);
++ inode_offset = ((inode->i_ino - 1) %
++ EXT4_INODES_PER_GROUP(inode->i_sb));
++ start = inode_offset & ~(inodes_per_buffer - 1);
++
++ /* Is the inode bitmap in cache? */
++ desc = ext4_get_group_desc(inode->i_sb,
++ block_group, NULL);
++ if (!desc)
++ goto make_io;
++
++ bitmap_bh = sb_getblk(inode->i_sb,
++ ext4_inode_bitmap(inode->i_sb, desc));
++ if (!bitmap_bh)
++ goto make_io;
++
++ /*
++ * If the inode bitmap isn't in cache then the
++ * optimisation may end up performing two reads instead
++ * of one, so skip it.
++ */
++ if (!buffer_uptodate(bitmap_bh)) {
++ brelse(bitmap_bh);
++ goto make_io;
++ }
++ for (i = start; i < start + inodes_per_buffer; i++) {
++ if (i == inode_offset)
++ continue;
++ if (ext4_test_bit(i, bitmap_bh->b_data))
++ break;
++ }
++ brelse(bitmap_bh);
++ if (i == start + inodes_per_buffer) {
++ /* all other inodes are free, so skip I/O */
++ memset(bh->b_data, 0, bh->b_size);
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++ goto has_buffer;
++ }
++ }
++
++make_io:
++ /*
++ * There are other valid inodes in the buffer, this inode
++ * has in-inode xattrs, or we don't have this inode in memory.
++ * Read the block from disk.
++ */
++ get_bh(bh);
++ bh->b_end_io = end_buffer_read_sync;
++ submit_bh(READ_META, bh);
++ wait_on_buffer(bh);
++ if (!buffer_uptodate(bh)) {
++ ext4_error(inode->i_sb, "ext4_get_inode_loc",
++ "unable to read inode block - "
++ "inode=%lu, block=%llu",
++ inode->i_ino, block);
++ brelse(bh);
++ return -EIO;
++ }
++ }
++has_buffer:
++ iloc->bh = bh;
++ return 0;
++}
++
++int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc)
++{
++ /* We have all inode data except xattrs in memory here. */
++ return __ext4_get_inode_loc(inode, iloc,
++ !(EXT4_I(inode)->i_state & EXT4_STATE_XATTR));
++}
++
++void ext4_set_inode_flags(struct inode *inode)
++{
++ unsigned int flags = EXT4_I(inode)->i_flags;
++
++ inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
++ if (flags & EXT4_SYNC_FL)
++ inode->i_flags |= S_SYNC;
++ if (flags & EXT4_APPEND_FL)
++ inode->i_flags |= S_APPEND;
++ if (flags & EXT4_IMMUTABLE_FL)
++ inode->i_flags |= S_IMMUTABLE;
++ if (flags & EXT4_NOATIME_FL)
++ inode->i_flags |= S_NOATIME;
++ if (flags & EXT4_DIRSYNC_FL)
++ inode->i_flags |= S_DIRSYNC;
++}
++
++void ext4_read_inode(struct inode * inode)
++{
++ struct ext4_iloc iloc;
++ struct ext4_inode *raw_inode;
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ struct buffer_head *bh;
++ int block;
++
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ ei->i_acl = EXT4_ACL_NOT_CACHED;
++ ei->i_default_acl = EXT4_ACL_NOT_CACHED;
++#endif
++ ei->i_block_alloc_info = NULL;
++
++ if (__ext4_get_inode_loc(inode, &iloc, 0))
++ goto bad_inode;
++ bh = iloc.bh;
++ raw_inode = ext4_raw_inode(&iloc);
++ inode->i_mode = le16_to_cpu(raw_inode->i_mode);
++ inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
++ inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
++ if(!(test_opt (inode->i_sb, NO_UID32))) {
++ inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
++ inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
++ }
++ inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
++ inode->i_size = le32_to_cpu(raw_inode->i_size);
++ inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime);
++ inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->i_ctime);
++ inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->i_mtime);
++ inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
++
++ ei->i_state = 0;
++ ei->i_dir_start_lookup = 0;
++ ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
++ /* We now have enough fields to check if the inode was active or not.
++ * This is needed because nfsd might try to access dead inodes
++ * the test is that same one that e2fsck uses
++ * NeilBrown 1999oct15
++ */
++ if (inode->i_nlink == 0) {
++ if (inode->i_mode == 0 ||
++ !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
++ /* this inode is deleted */
++ brelse (bh);
++ goto bad_inode;
++ }
++ /* The only unlinked inodes we let through here have
++ * valid i_mode and are being read by the orphan
++ * recovery code: that's fine, we're about to complete
++ * the process of deleting those. */
++ }
++ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
++ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
++#ifdef EXT4_FRAGMENTS
++ ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
++ ei->i_frag_no = raw_inode->i_frag;
++ ei->i_frag_size = raw_inode->i_fsize;
++#endif
++ ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
++ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
++ cpu_to_le32(EXT4_OS_HURD))
++ ei->i_file_acl |=
++ ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
++ if (!S_ISREG(inode->i_mode)) {
++ ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
++ } else {
++ inode->i_size |=
++ ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
++ }
++ ei->i_disksize = inode->i_size;
++ inode->i_generation = le32_to_cpu(raw_inode->i_generation);
++ ei->i_block_group = iloc.block_group;
++ /*
++ * NOTE! The in-memory inode i_data array is in little-endian order
++ * even on big-endian machines: we do NOT byteswap the block numbers!
++ */
++ for (block = 0; block < EXT4_N_BLOCKS; block++)
++ ei->i_data[block] = raw_inode->i_block[block];
++ INIT_LIST_HEAD(&ei->i_orphan);
++
++ if (inode->i_ino >= EXT4_FIRST_INO(inode->i_sb) + 1 &&
++ EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
++ /*
++ * When mke2fs creates big inodes it does not zero out
++ * the unused bytes above EXT4_GOOD_OLD_INODE_SIZE,
++ * so ignore those first few inodes.
++ */
++ ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
++ if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
++ EXT4_INODE_SIZE(inode->i_sb))
++ goto bad_inode;
++ if (ei->i_extra_isize == 0) {
++ /* The extra space is currently unused. Use it. */
++ ei->i_extra_isize = sizeof(struct ext4_inode) -
++ EXT4_GOOD_OLD_INODE_SIZE;
++ } else {
++ __le32 *magic = (void *)raw_inode +
++ EXT4_GOOD_OLD_INODE_SIZE +
++ ei->i_extra_isize;
++ if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC))
++ ei->i_state |= EXT4_STATE_XATTR;
++ }
++ } else
++ ei->i_extra_isize = 0;
++
++ if (S_ISREG(inode->i_mode)) {
++ inode->i_op = &ext4_file_inode_operations;
++ inode->i_fop = &ext4_file_operations;
++ ext4_set_aops(inode);
++ } else if (S_ISDIR(inode->i_mode)) {
++ inode->i_op = &ext4_dir_inode_operations;
++ inode->i_fop = &ext4_dir_operations;
++ } else if (S_ISLNK(inode->i_mode)) {
++ if (ext4_inode_is_fast_symlink(inode))
++ inode->i_op = &ext4_fast_symlink_inode_operations;
++ else {
++ inode->i_op = &ext4_symlink_inode_operations;
++ ext4_set_aops(inode);
++ }
++ } else {
++ inode->i_op = &ext4_special_inode_operations;
++ if (raw_inode->i_block[0])
++ init_special_inode(inode, inode->i_mode,
++ old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
++ else
++ init_special_inode(inode, inode->i_mode,
++ new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
++ }
++ brelse (iloc.bh);
++ ext4_set_inode_flags(inode);
++ return;
++
++bad_inode:
++ make_bad_inode(inode);
++ return;
++}
++
++/*
++ * Post the struct inode info into an on-disk inode location in the
++ * buffer-cache. This gobbles the caller's reference to the
++ * buffer_head in the inode location struct.
++ *
++ * The caller must have write access to iloc->bh.
++ */
++static int ext4_do_update_inode(handle_t *handle,
++ struct inode *inode,
++ struct ext4_iloc *iloc)
++{
++ struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ struct buffer_head *bh = iloc->bh;
++ int err = 0, rc, block;
++
++ /* For fields not not tracking in the in-memory inode,
++ * initialise them to zero for new inodes. */
++ if (ei->i_state & EXT4_STATE_NEW)
++ memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
++
++ raw_inode->i_mode = cpu_to_le16(inode->i_mode);
++ if(!(test_opt(inode->i_sb, NO_UID32))) {
++ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
++ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
++/*
++ * Fix up interoperability with old kernels. Otherwise, old inodes get
++ * re-used with the upper 16 bits of the uid/gid intact
++ */
++ if(!ei->i_dtime) {
++ raw_inode->i_uid_high =
++ cpu_to_le16(high_16_bits(inode->i_uid));
++ raw_inode->i_gid_high =
++ cpu_to_le16(high_16_bits(inode->i_gid));
++ } else {
++ raw_inode->i_uid_high = 0;
++ raw_inode->i_gid_high = 0;
++ }
++ } else {
++ raw_inode->i_uid_low =
++ cpu_to_le16(fs_high2lowuid(inode->i_uid));
++ raw_inode->i_gid_low =
++ cpu_to_le16(fs_high2lowgid(inode->i_gid));
++ raw_inode->i_uid_high = 0;
++ raw_inode->i_gid_high = 0;
++ }
++ raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
++ raw_inode->i_size = cpu_to_le32(ei->i_disksize);
++ raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
++ raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
++ raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
++ raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
++ raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
++ raw_inode->i_flags = cpu_to_le32(ei->i_flags);
++#ifdef EXT4_FRAGMENTS
++ raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
++ raw_inode->i_frag = ei->i_frag_no;
++ raw_inode->i_fsize = ei->i_frag_size;
++#endif
++ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
++ cpu_to_le32(EXT4_OS_HURD))
++ raw_inode->i_file_acl_high =
++ cpu_to_le16(ei->i_file_acl >> 32);
++ raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
++ if (!S_ISREG(inode->i_mode)) {
++ raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
++ } else {
++ raw_inode->i_size_high =
++ cpu_to_le32(ei->i_disksize >> 32);
++ if (ei->i_disksize > 0x7fffffffULL) {
++ struct super_block *sb = inode->i_sb;
++ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
++ EXT4_SB(sb)->s_es->s_rev_level ==
++ cpu_to_le32(EXT4_GOOD_OLD_REV)) {
++ /* If this is the first large file
++ * created, add a flag to the superblock.
++ */
++ err = ext4_journal_get_write_access(handle,
++ EXT4_SB(sb)->s_sbh);
++ if (err)
++ goto out_brelse;
++ ext4_update_dynamic_rev(sb);
++ EXT4_SET_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
++ sb->s_dirt = 1;
++ handle->h_sync = 1;
++ err = ext4_journal_dirty_metadata(handle,
++ EXT4_SB(sb)->s_sbh);
++ }
++ }
++ }
++ raw_inode->i_generation = cpu_to_le32(inode->i_generation);
++ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
++ if (old_valid_dev(inode->i_rdev)) {
++ raw_inode->i_block[0] =
++ cpu_to_le32(old_encode_dev(inode->i_rdev));
++ raw_inode->i_block[1] = 0;
++ } else {
++ raw_inode->i_block[0] = 0;
++ raw_inode->i_block[1] =
++ cpu_to_le32(new_encode_dev(inode->i_rdev));
++ raw_inode->i_block[2] = 0;
++ }
++ } else for (block = 0; block < EXT4_N_BLOCKS; block++)
++ raw_inode->i_block[block] = ei->i_data[block];
++
++ if (ei->i_extra_isize)
++ raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
++
++ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
++ rc = ext4_journal_dirty_metadata(handle, bh);
++ if (!err)
++ err = rc;
++ ei->i_state &= ~EXT4_STATE_NEW;
++
++out_brelse:
++ brelse (bh);
++ ext4_std_error(inode->i_sb, err);
++ return err;
++}
++
++/*
++ * ext4_write_inode()
++ *
++ * We are called from a few places:
++ *
++ * - Within generic_file_write() for O_SYNC files.
++ * Here, there will be no transaction running. We wait for any running
++ * trasnaction to commit.
++ *
++ * - Within sys_sync(), kupdate and such.
++ * We wait on commit, if tol to.
++ *
++ * - Within prune_icache() (PF_MEMALLOC == true)
++ * Here we simply return. We can't afford to block kswapd on the
++ * journal commit.
++ *
++ * In all cases it is actually safe for us to return without doing anything,
++ * because the inode has been copied into a raw inode buffer in
++ * ext4_mark_inode_dirty(). This is a correctness thing for O_SYNC and for
++ * knfsd.
++ *
++ * Note that we are absolutely dependent upon all inode dirtiers doing the
++ * right thing: they *must* call mark_inode_dirty() after dirtying info in
++ * which we are interested.
++ *
++ * It would be a bug for them to not do this. The code:
++ *
++ * mark_inode_dirty(inode)
++ * stuff();
++ * inode->i_size = expr;
++ *
++ * is in error because a kswapd-driven write_inode() could occur while
++ * `stuff()' is running, and the new i_size will be lost. Plus the inode
++ * will no longer be on the superblock's dirty inode list.
++ */
++int ext4_write_inode(struct inode *inode, int wait)
++{
++ if (current->flags & PF_MEMALLOC)
++ return 0;
++
++ if (ext4_journal_current_handle()) {
++ jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n");
++ dump_stack();
++ return -EIO;
++ }
++
++ if (!wait)
++ return 0;
++
++ return ext4_force_commit(inode->i_sb);
++}
++
++/*
++ * ext4_setattr()
++ *
++ * Called from notify_change.
++ *
++ * We want to trap VFS attempts to truncate the file as soon as
++ * possible. In particular, we want to make sure that when the VFS
++ * shrinks i_size, we put the inode on the orphan list and modify
++ * i_disksize immediately, so that during the subsequent flushing of
++ * dirty pages and freeing of disk blocks, we can guarantee that any
++ * commit will leave the blocks being flushed in an unused state on
++ * disk. (On recovery, the inode will get truncated and the blocks will
++ * be freed, so we have a strong guarantee that no future commit will
++ * leave these blocks visible to the user.)
++ *
++ * Called with inode->sem down.
++ */
++int ext4_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error, rc = 0;
++ const unsigned int ia_valid = attr->ia_valid;
++
++ error = inode_change_ok(inode, attr);
++ if (error)
++ return error;
++
++ if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
++ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
++ handle_t *handle;
++
++ /* (user+group)*(old+new) structure, inode write (sb,
++ * inode block, ? - but truncate inode update has it) */
++ handle = ext4_journal_start(inode, 2*(EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)+
++ EXT4_QUOTA_DEL_BLOCKS(inode->i_sb))+3);
++ if (IS_ERR(handle)) {
++ error = PTR_ERR(handle);
++ goto err_out;
++ }
++ error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
++ if (error) {
++ ext4_journal_stop(handle);
++ return error;
++ }
++ /* 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;
++ error = ext4_mark_inode_dirty(handle, inode);
++ ext4_journal_stop(handle);
++ }
++
++ if (S_ISREG(inode->i_mode) &&
++ attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
++ handle_t *handle;
++
++ handle = ext4_journal_start(inode, 3);
++ if (IS_ERR(handle)) {
++ error = PTR_ERR(handle);
++ goto err_out;
++ }
++
++ error = ext4_orphan_add(handle, inode);
++ EXT4_I(inode)->i_disksize = attr->ia_size;
++ rc = ext4_mark_inode_dirty(handle, inode);
++ if (!error)
++ error = rc;
++ ext4_journal_stop(handle);
++ }
++
++ rc = inode_setattr(inode, attr);
++
++ /* If inode_setattr's call to ext4_truncate failed to get a
++ * transaction handle at all, we need to clean up the in-core
++ * orphan list manually. */
++ if (inode->i_nlink)
++ ext4_orphan_del(NULL, inode);
++
++ if (!rc && (ia_valid & ATTR_MODE))
++ rc = ext4_acl_chmod(inode);
++
++err_out:
++ ext4_std_error(inode->i_sb, error);
++ if (!error)
++ error = rc;
++ return error;
++}
++
++
++/*
++ * How many blocks doth make a writepage()?
++ *
++ * With N blocks per page, it may be:
++ * N data blocks
++ * 2 indirect block
++ * 2 dindirect
++ * 1 tindirect
++ * N+5 bitmap blocks (from the above)
++ * N+5 group descriptor summary blocks
++ * 1 inode block
++ * 1 superblock.
++ * 2 * EXT4_SINGLEDATA_TRANS_BLOCKS for the quote files
++ *
++ * 3 * (N + 5) + 2 + 2 * EXT4_SINGLEDATA_TRANS_BLOCKS
++ *
++ * With ordered or writeback data it's the same, less the N data blocks.
++ *
++ * If the inode's direct blocks can hold an integral number of pages then a
++ * page cannot straddle two indirect blocks, and we can only touch one indirect
++ * and dindirect block, and the "5" above becomes "3".
++ *
++ * This still overestimates under most circumstances. If we were to pass the
++ * start and end offsets in here as well we could do block_to_path() on each
++ * block and work out the exact number of indirects which are touched. Pah.
++ */
++
++int ext4_writepage_trans_blocks(struct inode *inode)
++{
++ int bpp = ext4_journal_blocks_per_page(inode);
++ int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3;
++ int ret;
++
++ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
++ return ext4_ext_writepage_trans_blocks(inode, bpp);
++
++ if (ext4_should_journal_data(inode))
++ ret = 3 * (bpp + indirects) + 2;
++ else
++ ret = 2 * (bpp + indirects) + 2;
++
++#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*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
++#endif
++
++ return ret;
++}
++
++/*
++ * The caller must have previously called ext4_reserve_inode_write().
++ * Give this, we know that the caller already has write access to iloc->bh.
++ */
++int ext4_mark_iloc_dirty(handle_t *handle,
++ struct inode *inode, struct ext4_iloc *iloc)
++{
++ int err = 0;
++
++ /* the do_update_inode consumes one bh->b_count */
++ get_bh(iloc->bh);
++
++ /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */
++ err = ext4_do_update_inode(handle, inode, iloc);
++ put_bh(iloc->bh);
++ return err;
++}
++
++/*
++ * On success, We end up with an outstanding reference count against
++ * iloc->bh. This _must_ be cleaned up later.
++ */
++
++int
++ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
++ struct ext4_iloc *iloc)
++{
++ int err = 0;
++ if (handle) {
++ err = ext4_get_inode_loc(inode, iloc);
++ if (!err) {
++ BUFFER_TRACE(iloc->bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, iloc->bh);
++ if (err) {
++ brelse(iloc->bh);
++ iloc->bh = NULL;
++ }
++ }
++ }
++ ext4_std_error(inode->i_sb, err);
++ return err;
++}
++
++/*
++ * What we do here is to mark the in-core inode as clean with respect to inode
++ * dirtiness (it may still be data-dirty).
++ * This means that the in-core inode may be reaped by prune_icache
++ * without having to perform any I/O. This is a very good thing,
++ * because *any* task may call prune_icache - even ones which
++ * have a transaction open against a different journal.
++ *
++ * Is this cheating? Not really. Sure, we haven't written the
++ * inode out, but prune_icache isn't a user-visible syncing function.
++ * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
++ * we start and wait on commits.
++ *
++ * Is this efficient/effective? Well, we're being nice to the system
++ * by cleaning up our inodes proactively so they can be reaped
++ * without I/O. But we are potentially leaving up to five seconds'
++ * worth of inodes floating about which prune_icache wants us to
++ * write out. One way to fix that would be to get prune_icache()
++ * to do a write_super() to free up some memory. It has the desired
++ * effect.
++ */
++int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
++{
++ struct ext4_iloc iloc;
++ int err;
++
++ might_sleep();
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (!err)
++ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
++ return err;
++}
++
++/*
++ * ext4_dirty_inode() is called from __mark_inode_dirty()
++ *
++ * We're really interested in the case where a file is being extended.
++ * i_size has been changed by generic_commit_write() and we thus need
++ * to include the updated inode in the current transaction.
++ *
++ * Also, DQUOT_ALLOC_SPACE() will always dirty the inode when blocks
++ * are allocated to the file.
++ *
++ * If the inode is marked synchronous, we don't honour that here - doing
++ * so would cause a commit on atime updates, which we don't bother doing.
++ * We handle synchronous inodes at the highest possible level.
++ */
++void ext4_dirty_inode(struct inode *inode)
++{
++ handle_t *current_handle = ext4_journal_current_handle();
++ handle_t *handle;
++
++ handle = ext4_journal_start(inode, 2);
++ if (IS_ERR(handle))
++ goto out;
++ if (current_handle &&
++ current_handle->h_transaction != handle->h_transaction) {
++ /* This task has a transaction open against a different fs */
++ printk(KERN_EMERG "%s: transactions do not match!\n",
++ __FUNCTION__);
++ } else {
++ jbd_debug(5, "marking dirty. outer handle=%p\n",
++ current_handle);
++ ext4_mark_inode_dirty(handle, inode);
++ }
++ ext4_journal_stop(handle);
++out:
++ return;
++}
++
++#if 0
++/*
++ * Bind an inode's backing buffer_head into this transaction, to prevent
++ * it from being flushed to disk early. Unlike
++ * ext4_reserve_inode_write, this leaves behind no bh reference and
++ * returns no iloc structure, so the caller needs to repeat the iloc
++ * lookup to mark the inode dirty later.
++ */
++static int ext4_pin_inode(handle_t *handle, struct inode *inode)
++{
++ struct ext4_iloc iloc;
++
++ int err = 0;
++ if (handle) {
++ err = ext4_get_inode_loc(inode, &iloc);
++ if (!err) {
++ BUFFER_TRACE(iloc.bh, "get_write_access");
++ err = jbd2_journal_get_write_access(handle, iloc.bh);
++ if (!err)
++ err = ext4_journal_dirty_metadata(handle,
++ iloc.bh);
++ brelse(iloc.bh);
++ }
++ }
++ ext4_std_error(inode->i_sb, err);
++ return err;
++}
++#endif
++
++int ext4_change_inode_journal_flag(struct inode *inode, int val)
++{
++ journal_t *journal;
++ handle_t *handle;
++ int err;
++
++ /*
++ * We have to be very careful here: changing a data block's
++ * journaling status dynamically is dangerous. If we write a
++ * data block to the journal, change the status and then delete
++ * that block, we risk forgetting to revoke the old log record
++ * from the journal and so a subsequent replay can corrupt data.
++ * So, first we make sure that the journal is empty and that
++ * nobody is changing anything.
++ */
++
++ journal = EXT4_JOURNAL(inode);
++ if (is_journal_aborted(journal) || IS_RDONLY(inode))
++ return -EROFS;
++
++ jbd2_journal_lock_updates(journal);
++ jbd2_journal_flush(journal);
++
++ /*
++ * OK, there are no updates running now, and all cached data is
++ * synced to disk. We are now in a completely consistent state
++ * which doesn't have anything in the journal, and we know that
++ * no filesystem updates are running, so it is safe to modify
++ * the inode's in-core data-journaling state flag now.
++ */
++
++ if (val)
++ EXT4_I(inode)->i_flags |= EXT4_JOURNAL_DATA_FL;
++ else
++ EXT4_I(inode)->i_flags &= ~EXT4_JOURNAL_DATA_FL;
++ ext4_set_aops(inode);
++
++ jbd2_journal_unlock_updates(journal);
++
++ /* Finally we can mark the inode as dirty. */
++
++ handle = ext4_journal_start(inode, 1);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ err = ext4_mark_inode_dirty(handle, inode);
++ handle->h_sync = 1;
++ ext4_journal_stop(handle);
++ ext4_std_error(inode->i_sb, err);
++
++ return err;
++}
+diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
+new file mode 100644
+index 0000000..22a737c
+--- /dev/null
++++ b/fs/ext4/ioctl.c
+@@ -0,0 +1,306 @@
++/*
++ * linux/fs/ext4/ioctl.c
++ *
++ * Copyright (C) 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ */
++
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/capability.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/time.h>
++#include <linux/compat.h>
++#include <linux/smp_lock.h>
++#include <asm/uaccess.h>
++
++int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ unsigned int flags;
++ unsigned short rsv_window_size;
++
++ ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg);
++
++ switch (cmd) {
++ case EXT4_IOC_GETFLAGS:
++ flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
++ return put_user(flags, (int __user *) arg);
++ case EXT4_IOC_SETFLAGS: {
++ handle_t *handle = NULL;
++ int err;
++ struct ext4_iloc iloc;
++ unsigned int oldflags;
++ unsigned int jflag;
++
++ if (IS_RDONLY(inode))
++ return -EROFS;
++
++ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
++ return -EACCES;
++
++ if (get_user(flags, (int __user *) arg))
++ return -EFAULT;
++
++ if (!S_ISDIR(inode->i_mode))
++ flags &= ~EXT4_DIRSYNC_FL;
++
++ mutex_lock(&inode->i_mutex);
++ oldflags = ei->i_flags;
++
++ /* The JOURNAL_DATA flag is modifiable only by root */
++ jflag = flags & EXT4_JOURNAL_DATA_FL;
++
++ /*
++ * The IMMUTABLE and APPEND_ONLY flags can only be changed by
++ * the relevant capability.
++ *
++ * This test looks nicer. Thanks to Pauline Middelink
++ */
++ if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
++ if (!capable(CAP_LINUX_IMMUTABLE)) {
++ mutex_unlock(&inode->i_mutex);
++ return -EPERM;
++ }
++ }
++
++ /*
++ * The JOURNAL_DATA flag can only be changed by
++ * the relevant capability.
++ */
++ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
++ if (!capable(CAP_SYS_RESOURCE)) {
++ mutex_unlock(&inode->i_mutex);
++ return -EPERM;
++ }
++ }
++
++
++ handle = ext4_journal_start(inode, 1);
++ if (IS_ERR(handle)) {
++ mutex_unlock(&inode->i_mutex);
++ return PTR_ERR(handle);
++ }
++ if (IS_SYNC(inode))
++ handle->h_sync = 1;
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (err)
++ goto flags_err;
++
++ flags = flags & EXT4_FL_USER_MODIFIABLE;
++ flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE;
++ ei->i_flags = flags;
++
++ ext4_set_inode_flags(inode);
++ inode->i_ctime = CURRENT_TIME_SEC;
++
++ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
++flags_err:
++ ext4_journal_stop(handle);
++ if (err) {
++ mutex_unlock(&inode->i_mutex);
++ return err;
++ }
++
++ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
++ err = ext4_change_inode_journal_flag(inode, jflag);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++ }
++ case EXT4_IOC_GETVERSION:
++ case EXT4_IOC_GETVERSION_OLD:
++ return put_user(inode->i_generation, (int __user *) arg);
++ case EXT4_IOC_SETVERSION:
++ case EXT4_IOC_SETVERSION_OLD: {
++ handle_t *handle;
++ struct ext4_iloc iloc;
++ __u32 generation;
++ int err;
++
++ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
++ return -EPERM;
++ if (IS_RDONLY(inode))
++ return -EROFS;
++ if (get_user(generation, (int __user *) arg))
++ return -EFAULT;
++
++ handle = ext4_journal_start(inode, 1);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (err == 0) {
++ inode->i_ctime = CURRENT_TIME_SEC;
++ inode->i_generation = generation;
++ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
++ }
++ ext4_journal_stop(handle);
++ return err;
++ }
++#ifdef CONFIG_JBD_DEBUG
++ case EXT4_IOC_WAIT_FOR_READONLY:
++ /*
++ * This is racy - by the time we're woken up and running,
++ * the superblock could be released. And the module could
++ * have been unloaded. So sue me.
++ *
++ * Returns 1 if it slept, else zero.
++ */
++ {
++ struct super_block *sb = inode->i_sb;
++ DECLARE_WAITQUEUE(wait, current);
++ int ret = 0;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
++ if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) {
++ schedule();
++ ret = 1;
++ }
++ remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
++ return ret;
++ }
++#endif
++ case EXT4_IOC_GETRSVSZ:
++ if (test_opt(inode->i_sb, RESERVATION)
++ && S_ISREG(inode->i_mode)
++ && ei->i_block_alloc_info) {
++ rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
++ return put_user(rsv_window_size, (int __user *)arg);
++ }
++ return -ENOTTY;
++ case EXT4_IOC_SETRSVSZ: {
++
++ if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
++ return -ENOTTY;
++
++ if (IS_RDONLY(inode))
++ return -EROFS;
++
++ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
++ return -EACCES;
++
++ if (get_user(rsv_window_size, (int __user *)arg))
++ return -EFAULT;
++
++ if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS)
++ rsv_window_size = EXT4_MAX_RESERVE_BLOCKS;
++
++ /*
++ * need to allocate reservation structure for this inode
++ * before set the window size
++ */
++ mutex_lock(&ei->truncate_mutex);
++ if (!ei->i_block_alloc_info)
++ ext4_init_block_alloc_info(inode);
++
++ if (ei->i_block_alloc_info){
++ struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
++ rsv->rsv_goal_size = rsv_window_size;
++ }
++ mutex_unlock(&ei->truncate_mutex);
++ return 0;
++ }
++ case EXT4_IOC_GROUP_EXTEND: {
++ ext4_fsblk_t n_blocks_count;
++ struct super_block *sb = inode->i_sb;
++ int err;
++
++ if (!capable(CAP_SYS_RESOURCE))
++ return -EPERM;
++
++ if (IS_RDONLY(inode))
++ return -EROFS;
++
++ if (get_user(n_blocks_count, (__u32 __user *)arg))
++ return -EFAULT;
++
++ err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
++ jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
++ jbd2_journal_flush(EXT4_SB(sb)->s_journal);
++ jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
++
++ return err;
++ }
++ case EXT4_IOC_GROUP_ADD: {
++ struct ext4_new_group_data input;
++ struct super_block *sb = inode->i_sb;
++ int err;
++
++ if (!capable(CAP_SYS_RESOURCE))
++ return -EPERM;
++
++ if (IS_RDONLY(inode))
++ return -EROFS;
++
++ if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
++ sizeof(input)))
++ return -EFAULT;
++
++ err = ext4_group_add(sb, &input);
++ jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
++ jbd2_journal_flush(EXT4_SB(sb)->s_journal);
++ jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
++
++ return err;
++ }
++
++ default:
++ return -ENOTTY;
++ }
++}
++
++#ifdef CONFIG_COMPAT
++long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int ret;
++
++ /* These are just misnamed, they actually get/put from/to user an int */
++ switch (cmd) {
++ case EXT4_IOC32_GETFLAGS:
++ cmd = EXT4_IOC_GETFLAGS;
++ break;
++ case EXT4_IOC32_SETFLAGS:
++ cmd = EXT4_IOC_SETFLAGS;
++ break;
++ case EXT4_IOC32_GETVERSION:
++ cmd = EXT4_IOC_GETVERSION;
++ break;
++ case EXT4_IOC32_SETVERSION:
++ cmd = EXT4_IOC_SETVERSION;
++ break;
++ case EXT4_IOC32_GROUP_EXTEND:
++ cmd = EXT4_IOC_GROUP_EXTEND;
++ break;
++ case EXT4_IOC32_GETVERSION_OLD:
++ cmd = EXT4_IOC_GETVERSION_OLD;
++ break;
++ case EXT4_IOC32_SETVERSION_OLD:
++ cmd = EXT4_IOC_SETVERSION_OLD;
++ break;
++#ifdef CONFIG_JBD_DEBUG
++ case EXT4_IOC32_WAIT_FOR_READONLY:
++ cmd = EXT4_IOC_WAIT_FOR_READONLY;
++ break;
++#endif
++ case EXT4_IOC32_GETRSVSZ:
++ cmd = EXT4_IOC_GETRSVSZ;
++ break;
++ case EXT4_IOC32_SETRSVSZ:
++ cmd = EXT4_IOC_SETRSVSZ;
++ break;
++ case EXT4_IOC_GROUP_ADD:
++ break;
++ default:
++ return -ENOIOCTLCMD;
++ }
++ lock_kernel();
++ ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
++ unlock_kernel();
++ return ret;
++}
++#endif
+diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
+new file mode 100644
+index 0000000..8b1bd03
+--- /dev/null
++++ b/fs/ext4/namei.c
+@@ -0,0 +1,2395 @@
++/*
++ * linux/fs/ext4/namei.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/namei.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ * Directory entry file type support and forward compatibility hooks
++ * for B-tree directories by Theodore Ts'o (tytso at mit.edu), 1998
++ * Hash Tree Directory indexing (c)
++ * Daniel Phillips, 2001
++ * Hash Tree Directory indexing porting
++ * Christopher Li, 2002
++ * Hash Tree Directory indexing cleanup
++ * Theodore Ts'o, 2002
++ */
++
++#include <linux/fs.h>
++#include <linux/pagemap.h>
++#include <linux/jbd2.h>
++#include <linux/time.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/fcntl.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/quotaops.h>
++#include <linux/buffer_head.h>
++#include <linux/bio.h>
++#include <linux/smp_lock.h>
++
++#include "namei.h"
++#include "xattr.h"
++#include "acl.h"
++
++/*
++ * define how far ahead to read directories while searching them.
++ */
++#define NAMEI_RA_CHUNKS 2
++#define NAMEI_RA_BLOCKS 4
++#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
++#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
++
++static struct buffer_head *ext4_append(handle_t *handle,
++ struct inode *inode,
++ u32 *block, int *err)
++{
++ struct buffer_head *bh;
++
++ *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
++
++ if ((bh = ext4_bread(handle, inode, *block, 1, err))) {
++ inode->i_size += inode->i_sb->s_blocksize;
++ EXT4_I(inode)->i_disksize = inode->i_size;
++ ext4_journal_get_write_access(handle,bh);
++ }
++ return bh;
++}
++
++#ifndef assert
++#define assert(test) J_ASSERT(test)
++#endif
++
++#ifndef swap
++#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)
++#endif
++
++#ifdef DX_DEBUG
++#define dxtrace(command) command
++#else
++#define dxtrace(command)
++#endif
++
++struct fake_dirent
++{
++ __le32 inode;
++ __le16 rec_len;
++ u8 name_len;
++ u8 file_type;
++};
++
++struct dx_countlimit
++{
++ __le16 limit;
++ __le16 count;
++};
++
++struct dx_entry
++{
++ __le32 hash;
++ __le32 block;
++};
++
++/*
++ * dx_root_info is laid out so that if it should somehow get overlaid by a
++ * dirent the two low bits of the hash version will be zero. Therefore, the
++ * hash version mod 4 should never be 0. Sincerely, the paranoia department.
++ */
++
++struct dx_root
++{
++ struct fake_dirent dot;
++ char dot_name[4];
++ struct fake_dirent dotdot;
++ char dotdot_name[4];
++ struct dx_root_info
++ {
++ __le32 reserved_zero;
++ u8 hash_version;
++ u8 info_length; /* 8 */
++ u8 indirect_levels;
++ u8 unused_flags;
++ }
++ info;
++ struct dx_entry entries[0];
++};
++
++struct dx_node
++{
++ struct fake_dirent fake;
++ struct dx_entry entries[0];
++};
++
++
++struct dx_frame
++{
++ struct buffer_head *bh;
++ struct dx_entry *entries;
++ struct dx_entry *at;
++};
++
++struct dx_map_entry
++{
++ u32 hash;
++ u32 offs;
++};
++
++#ifdef CONFIG_EXT4_INDEX
++static inline unsigned dx_get_block (struct dx_entry *entry);
++static void dx_set_block (struct dx_entry *entry, unsigned value);
++static inline unsigned dx_get_hash (struct dx_entry *entry);
++static void dx_set_hash (struct dx_entry *entry, unsigned value);
++static unsigned dx_get_count (struct dx_entry *entries);
++static unsigned dx_get_limit (struct dx_entry *entries);
++static void dx_set_count (struct dx_entry *entries, unsigned value);
++static void dx_set_limit (struct dx_entry *entries, unsigned value);
++static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
++static unsigned dx_node_limit (struct inode *dir);
++static struct dx_frame *dx_probe(struct dentry *dentry,
++ struct inode *dir,
++ struct dx_hash_info *hinfo,
++ struct dx_frame *frame,
++ int *err);
++static void dx_release (struct dx_frame *frames);
++static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
++ struct dx_hash_info *hinfo, struct dx_map_entry map[]);
++static void dx_sort_map(struct dx_map_entry *map, unsigned count);
++static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to,
++ struct dx_map_entry *offsets, int count);
++static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size);
++static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
++static int ext4_htree_next_block(struct inode *dir, __u32 hash,
++ struct dx_frame *frame,
++ struct dx_frame *frames,
++ __u32 *start_hash);
++static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
++ struct ext4_dir_entry_2 **res_dir, int *err);
++static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
++ struct inode *inode);
++
++/*
++ * Future: use high four bits of block for coalesce-on-delete flags
++ * Mask them off for now.
++ */
++
++static inline unsigned dx_get_block (struct dx_entry *entry)
++{
++ return le32_to_cpu(entry->block) & 0x00ffffff;
++}
++
++static inline void dx_set_block (struct dx_entry *entry, unsigned value)
++{
++ entry->block = cpu_to_le32(value);
++}
++
++static inline unsigned dx_get_hash (struct dx_entry *entry)
++{
++ return le32_to_cpu(entry->hash);
++}
++
++static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
++{
++ entry->hash = cpu_to_le32(value);
++}
++
++static inline unsigned dx_get_count (struct dx_entry *entries)
++{
++ return le16_to_cpu(((struct dx_countlimit *) entries)->count);
++}
++
++static inline unsigned dx_get_limit (struct dx_entry *entries)
++{
++ return le16_to_cpu(((struct dx_countlimit *) entries)->limit);
++}
++
++static inline void dx_set_count (struct dx_entry *entries, unsigned value)
++{
++ ((struct dx_countlimit *) entries)->count = cpu_to_le16(value);
++}
++
++static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
++{
++ ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
++}
++
++static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
++{
++ unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
++ EXT4_DIR_REC_LEN(2) - infosize;
++ return 0? 20: entry_space / sizeof(struct dx_entry);
++}
++
++static inline unsigned dx_node_limit (struct inode *dir)
++{
++ unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
++ return 0? 22: entry_space / sizeof(struct dx_entry);
++}
++
++/*
++ * Debug
++ */
++#ifdef DX_DEBUG
++static void dx_show_index (char * label, struct dx_entry *entries)
++{
++ int i, n = dx_get_count (entries);
++ printk("%s index ", label);
++ for (i = 0; i < n; i++) {
++ printk("%x->%u ", i? dx_get_hash(entries + i) :
++ 0, dx_get_block(entries + i));
++ }
++ printk("\n");
++}
++
++struct stats
++{
++ unsigned names;
++ unsigned space;
++ unsigned bcount;
++};
++
++static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_entry_2 *de,
++ int size, int show_names)
++{
++ unsigned names = 0, space = 0;
++ char *base = (char *) de;
++ struct dx_hash_info h = *hinfo;
++
++ printk("names: ");
++ while ((char *) de < base + size)
++ {
++ if (de->inode)
++ {
++ if (show_names)
++ {
++ int len = de->name_len;
++ char *name = de->name;
++ while (len--) printk("%c", *name++);
++ ext4fs_dirhash(de->name, de->name_len, &h);
++ printk(":%x.%u ", h.hash,
++ ((char *) de - base));
++ }
++ space += EXT4_DIR_REC_LEN(de->name_len);
++ names++;
++ }
++ de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
++ }
++ printk("(%i)\n", names);
++ return (struct stats) { names, space, 1 };
++}
++
++struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
++ struct dx_entry *entries, int levels)
++{
++ unsigned blocksize = dir->i_sb->s_blocksize;
++ unsigned count = dx_get_count (entries), names = 0, space = 0, i;
++ unsigned bcount = 0;
++ struct buffer_head *bh;
++ int err;
++ printk("%i indexed blocks...\n", count);
++ for (i = 0; i < count; i++, entries++)
++ {
++ u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0;
++ u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;
++ struct stats stats;
++ printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range);
++ if (!(bh = ext4_bread (NULL,dir, block, 0,&err))) continue;
++ stats = levels?
++ dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):
++ dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0);
++ names += stats.names;
++ space += stats.space;
++ bcount += stats.bcount;
++ brelse (bh);
++ }
++ if (bcount)
++ printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ",
++ names, space/bcount,(space/bcount)*100/blocksize);
++ return (struct stats) { names, space, bcount};
++}
++#endif /* DX_DEBUG */
++
++/*
++ * Probe for a directory leaf block to search.
++ *
++ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
++ * error in the directory index, and the caller should fall back to
++ * searching the directory normally. The callers of dx_probe **MUST**
++ * check for this error code, and make sure it never gets reflected
++ * back to userspace.
++ */
++static struct dx_frame *
++dx_probe(struct dentry *dentry, struct inode *dir,
++ struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
++{
++ unsigned count, indirect;
++ struct dx_entry *at, *entries, *p, *q, *m;
++ struct dx_root *root;
++ struct buffer_head *bh;
++ struct dx_frame *frame = frame_in;
++ u32 hash;
++
++ frame->bh = NULL;
++ if (dentry)
++ dir = dentry->d_parent->d_inode;
++ if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))
++ goto fail;
++ root = (struct dx_root *) bh->b_data;
++ if (root->info.hash_version != DX_HASH_TEA &&
++ root->info.hash_version != DX_HASH_HALF_MD4 &&
++ root->info.hash_version != DX_HASH_LEGACY) {
++ ext4_warning(dir->i_sb, __FUNCTION__,
++ "Unrecognised inode hash code %d",
++ root->info.hash_version);
++ brelse(bh);
++ *err = ERR_BAD_DX_DIR;
++ goto fail;
++ }
++ hinfo->hash_version = root->info.hash_version;
++ hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
++ if (dentry)
++ ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
++ hash = hinfo->hash;
++
++ if (root->info.unused_flags & 1) {
++ ext4_warning(dir->i_sb, __FUNCTION__,
++ "Unimplemented inode hash flags: %#06x",
++ root->info.unused_flags);
++ brelse(bh);
++ *err = ERR_BAD_DX_DIR;
++ goto fail;
++ }
++
++ if ((indirect = root->info.indirect_levels) > 1) {
++ ext4_warning(dir->i_sb, __FUNCTION__,
++ "Unimplemented inode hash depth: %#06x",
++ root->info.indirect_levels);
++ brelse(bh);
++ *err = ERR_BAD_DX_DIR;
++ goto fail;
++ }
++
++ entries = (struct dx_entry *) (((char *)&root->info) +
++ root->info.info_length);
++ assert(dx_get_limit(entries) == dx_root_limit(dir,
++ root->info.info_length));
++ dxtrace (printk("Look up %x", hash));
++ while (1)
++ {
++ count = dx_get_count(entries);
++ assert (count && count <= dx_get_limit(entries));
++ p = entries + 1;
++ q = entries + count - 1;
++ while (p <= q)
++ {
++ m = p + (q - p)/2;
++ dxtrace(printk("."));
++ if (dx_get_hash(m) > hash)
++ q = m - 1;
++ else
++ p = m + 1;
++ }
++
++ if (0) // linear search cross check
++ {
++ unsigned n = count - 1;
++ at = entries;
++ while (n--)
++ {
++ dxtrace(printk(","));
++ if (dx_get_hash(++at) > hash)
++ {
++ at--;
++ break;
++ }
++ }
++ assert (at == p - 1);
++ }
++
++ at = p - 1;
++ dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
++ frame->bh = bh;
++ frame->entries = entries;
++ frame->at = at;
++ if (!indirect--) return frame;
++ if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err)))
++ goto fail2;
++ at = entries = ((struct dx_node *) bh->b_data)->entries;
++ assert (dx_get_limit(entries) == dx_node_limit (dir));
++ frame++;
++ }
++fail2:
++ while (frame >= frame_in) {
++ brelse(frame->bh);
++ frame--;
++ }
++fail:
++ return NULL;
++}
++
++static void dx_release (struct dx_frame *frames)
++{
++ if (frames[0].bh == NULL)
++ return;
++
++ if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
++ brelse(frames[1].bh);
++ brelse(frames[0].bh);
++}
++
++/*
++ * This function increments the frame pointer to search the next leaf
++ * block, and reads in the necessary intervening nodes if the search
++ * should be necessary. Whether or not the search is necessary is
++ * controlled by the hash parameter. If the hash value is even, then
++ * the search is only continued if the next block starts with that
++ * hash value. This is used if we are searching for a specific file.
++ *
++ * If the hash value is HASH_NB_ALWAYS, then always go to the next block.
++ *
++ * This function returns 1 if the caller should continue to search,
++ * or 0 if it should not. If there is an error reading one of the
++ * index blocks, it will a negative error code.
++ *
++ * If start_hash is non-null, it will be filled in with the starting
++ * hash of the next page.
++ */
++static int ext4_htree_next_block(struct inode *dir, __u32 hash,
++ struct dx_frame *frame,
++ struct dx_frame *frames,
++ __u32 *start_hash)
++{
++ struct dx_frame *p;
++ struct buffer_head *bh;
++ int err, num_frames = 0;
++ __u32 bhash;
++
++ p = frame;
++ /*
++ * Find the next leaf page by incrementing the frame pointer.
++ * If we run out of entries in the interior node, loop around and
++ * increment pointer in the parent node. When we break out of
++ * this loop, num_frames indicates the number of interior
++ * nodes need to be read.
++ */
++ while (1) {
++ if (++(p->at) < p->entries + dx_get_count(p->entries))
++ break;
++ if (p == frames)
++ return 0;
++ num_frames++;
++ p--;
++ }
++
++ /*
++ * If the hash is 1, then continue only if the next page has a
++ * continuation hash of any value. This is used for readdir
++ * handling. Otherwise, check to see if the hash matches the
++ * desired contiuation hash. If it doesn't, return since
++ * there's no point to read in the successive index pages.
++ */
++ bhash = dx_get_hash(p->at);
++ if (start_hash)
++ *start_hash = bhash;
++ if ((hash & 1) == 0) {
++ if ((bhash & ~1) != hash)
++ return 0;
++ }
++ /*
++ * If the hash is HASH_NB_ALWAYS, we always go to the next
++ * block so no check is necessary
++ */
++ while (num_frames--) {
++ if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at),
++ 0, &err)))
++ return err; /* Failure */
++ p++;
++ brelse (p->bh);
++ p->bh = bh;
++ p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
++ }
++ return 1;
++}
++
++
++/*
++ * p is at least 6 bytes before the end of page
++ */
++static inline struct ext4_dir_entry_2 *ext4_next_entry(struct ext4_dir_entry_2 *p)
++{
++ return (struct ext4_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len));
++}
++
++/*
++ * This function fills a red-black tree with information from a
++ * directory block. It returns the number directory entries loaded
++ * into the tree. If there is an error it is returned in err.
++ */
++static int htree_dirblock_to_tree(struct file *dir_file,
++ struct inode *dir, int block,
++ struct dx_hash_info *hinfo,
++ __u32 start_hash, __u32 start_minor_hash)
++{
++ struct buffer_head *bh;
++ struct ext4_dir_entry_2 *de, *top;
++ int err, count = 0;
++
++ dxtrace(printk("In htree dirblock_to_tree: block %d\n", block));
++ if (!(bh = ext4_bread (NULL, dir, block, 0, &err)))
++ return err;
++
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ top = (struct ext4_dir_entry_2 *) ((char *) de +
++ dir->i_sb->s_blocksize -
++ EXT4_DIR_REC_LEN(0));
++ for (; de < top; de = ext4_next_entry(de)) {
++ ext4fs_dirhash(de->name, de->name_len, hinfo);
++ if ((hinfo->hash < start_hash) ||
++ ((hinfo->hash == start_hash) &&
++ (hinfo->minor_hash < start_minor_hash)))
++ continue;
++ if (de->inode == 0)
++ continue;
++ if ((err = ext4_htree_store_dirent(dir_file,
++ hinfo->hash, hinfo->minor_hash, de)) != 0) {
++ brelse(bh);
++ return err;
++ }
++ count++;
++ }
++ brelse(bh);
++ return count;
++}
++
++
++/*
++ * This function fills a red-black tree with information from a
++ * directory. We start scanning the directory in hash order, starting
++ * at start_hash and start_minor_hash.
++ *
++ * This function returns the number of entries inserted into the tree,
++ * or a negative error code.
++ */
++int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
++ __u32 start_minor_hash, __u32 *next_hash)
++{
++ struct dx_hash_info hinfo;
++ struct ext4_dir_entry_2 *de;
++ struct dx_frame frames[2], *frame;
++ struct inode *dir;
++ int block, err;
++ int count = 0;
++ int ret;
++ __u32 hashval;
++
++ dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
++ start_minor_hash));
++ dir = dir_file->f_dentry->d_inode;
++ if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) {
++ hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
++ hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
++ count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
++ start_hash, start_minor_hash);
++ *next_hash = ~0;
++ return count;
++ }
++ hinfo.hash = start_hash;
++ hinfo.minor_hash = 0;
++ frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
++ if (!frame)
++ return err;
++
++ /* Add '.' and '..' from the htree header */
++ if (!start_hash && !start_minor_hash) {
++ de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
++ if ((err = ext4_htree_store_dirent(dir_file, 0, 0, de)) != 0)
++ goto errout;
++ count++;
++ }
++ if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) {
++ de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
++ de = ext4_next_entry(de);
++ if ((err = ext4_htree_store_dirent(dir_file, 2, 0, de)) != 0)
++ goto errout;
++ count++;
++ }
++
++ while (1) {
++ block = dx_get_block(frame->at);
++ ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo,
++ start_hash, start_minor_hash);
++ if (ret < 0) {
++ err = ret;
++ goto errout;
++ }
++ count += ret;
++ hashval = ~0;
++ ret = ext4_htree_next_block(dir, HASH_NB_ALWAYS,
++ frame, frames, &hashval);
++ *next_hash = hashval;
++ if (ret < 0) {
++ err = ret;
++ goto errout;
++ }
++ /*
++ * Stop if: (a) there are no more entries, or
++ * (b) we have inserted at least one entry and the
++ * next hash value is not a continuation
++ */
++ if ((ret == 0) ||
++ (count && ((hashval & 1) == 0)))
++ break;
++ }
++ dx_release(frames);
++ dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
++ count, *next_hash));
++ return count;
++errout:
++ dx_release(frames);
++ return (err);
++}
++
++
++/*
++ * Directory block splitting, compacting
++ */
++
++static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
++ struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
++{
++ int count = 0;
++ char *base = (char *) de;
++ struct dx_hash_info h = *hinfo;
++
++ while ((char *) de < base + size)
++ {
++ if (de->name_len && de->inode) {
++ ext4fs_dirhash(de->name, de->name_len, &h);
++ map_tail--;
++ map_tail->hash = h.hash;
++ map_tail->offs = (u32) ((char *) de - base);
++ count++;
++ cond_resched();
++ }
++ /* XXX: do we need to check rec_len == 0 case? -Chris */
++ de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
++ }
++ return count;
++}
++
++static void dx_sort_map (struct dx_map_entry *map, unsigned count)
++{
++ struct dx_map_entry *p, *q, *top = map + count - 1;
++ int more;
++ /* Combsort until bubble sort doesn't suck */
++ while (count > 2) {
++ count = count*10/13;
++ if (count - 9 < 2) /* 9, 10 -> 11 */
++ count = 11;
++ for (p = top, q = p - count; q >= map; p--, q--)
++ if (p->hash < q->hash)
++ swap(*p, *q);
++ }
++ /* Garden variety bubble sort */
++ do {
++ more = 0;
++ q = top;
++ while (q-- > map) {
++ if (q[1].hash >= q[0].hash)
++ continue;
++ swap(*(q+1), *q);
++ more = 1;
++ }
++ } while(more);
++}
++
++static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
++{
++ struct dx_entry *entries = frame->entries;
++ struct dx_entry *old = frame->at, *new = old + 1;
++ int count = dx_get_count(entries);
++
++ assert(count < dx_get_limit(entries));
++ assert(old < entries + count);
++ memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
++ dx_set_hash(new, hash);
++ dx_set_block(new, block);
++ dx_set_count(entries, count + 1);
++}
++#endif
++
++
++static void ext4_update_dx_flag(struct inode *inode)
++{
++ if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_COMPAT_DIR_INDEX))
++ EXT4_I(inode)->i_flags &= ~EXT4_INDEX_FL;
++}
++
++/*
++ * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure.
++ *
++ * `len <= EXT4_NAME_LEN' is guaranteed by caller.
++ * `de != NULL' is guaranteed by caller.
++ */
++static inline int ext4_match (int len, const char * const name,
++ struct ext4_dir_entry_2 * de)
++{
++ if (len != de->name_len)
++ return 0;
++ if (!de->inode)
++ return 0;
++ return !memcmp(name, de->name, len);
++}
++
++/*
++ * Returns 0 if not found, -1 on failure, and 1 on success
++ */
++static inline int search_dirblock(struct buffer_head * bh,
++ struct inode *dir,
++ struct dentry *dentry,
++ unsigned long offset,
++ struct ext4_dir_entry_2 ** res_dir)
++{
++ struct ext4_dir_entry_2 * de;
++ char * dlimit;
++ int de_len;
++ const char *name = dentry->d_name.name;
++ int namelen = dentry->d_name.len;
++
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ dlimit = bh->b_data + dir->i_sb->s_blocksize;
++ while ((char *) de < dlimit) {
++ /* this code is executed quadratically often */
++ /* do minimal checking `by hand' */
++
++ if ((char *) de + namelen <= dlimit &&
++ ext4_match (namelen, name, de)) {
++ /* found a match - just to be sure, do a full check */
++ if (!ext4_check_dir_entry("ext4_find_entry",
++ dir, de, bh, offset))
++ return -1;
++ *res_dir = de;
++ return 1;
++ }
++ /* prevent looping on a bad block */
++ de_len = le16_to_cpu(de->rec_len);
++ if (de_len <= 0)
++ return -1;
++ offset += de_len;
++ de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
++ }
++ return 0;
++}
++
++
++/*
++ * ext4_find_entry()
++ *
++ * finds an entry in the specified directory with the wanted name. It
++ * returns the cache buffer in which the entry was found, and the entry
++ * itself (as a parameter - res_dir). It does NOT read the inode of the
++ * entry - you'll have to do that yourself if you want to.
++ *
++ * The returned buffer_head has ->b_count elevated. The caller is expected
++ * to brelse() it when appropriate.
++ */
++static struct buffer_head * ext4_find_entry (struct dentry *dentry,
++ struct ext4_dir_entry_2 ** res_dir)
++{
++ struct super_block * sb;
++ struct buffer_head * bh_use[NAMEI_RA_SIZE];
++ struct buffer_head * bh, *ret = NULL;
++ unsigned long start, block, b;
++ int ra_max = 0; /* Number of bh's in the readahead
++ buffer, bh_use[] */
++ int ra_ptr = 0; /* Current index into readahead
++ buffer */
++ int num = 0;
++ int nblocks, i, err;
++ struct inode *dir = dentry->d_parent->d_inode;
++ int namelen;
++ const u8 *name;
++ unsigned blocksize;
++
++ *res_dir = NULL;
++ sb = dir->i_sb;
++ blocksize = sb->s_blocksize;
++ namelen = dentry->d_name.len;
++ name = dentry->d_name.name;
++ if (namelen > EXT4_NAME_LEN)
++ return NULL;
++#ifdef CONFIG_EXT4_INDEX
++ if (is_dx(dir)) {
++ bh = ext4_dx_find_entry(dentry, res_dir, &err);
++ /*
++ * On success, or if the error was file not found,
++ * return. Otherwise, fall back to doing a search the
++ * old fashioned way.
++ */
++ if (bh || (err != ERR_BAD_DX_DIR))
++ return bh;
++ dxtrace(printk("ext4_find_entry: dx failed, falling back\n"));
++ }
++#endif
++ nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
++ start = EXT4_I(dir)->i_dir_start_lookup;
++ if (start >= nblocks)
++ start = 0;
++ block = start;
++restart:
++ do {
++ /*
++ * We deal with the read-ahead logic here.
++ */
++ if (ra_ptr >= ra_max) {
++ /* Refill the readahead buffer */
++ ra_ptr = 0;
++ b = block;
++ for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
++ /*
++ * Terminate if we reach the end of the
++ * directory and must wrap, or if our
++ * search has finished at this block.
++ */
++ if (b >= nblocks || (num && block == start)) {
++ bh_use[ra_max] = NULL;
++ break;
++ }
++ num++;
++ bh = ext4_getblk(NULL, dir, b++, 0, &err);
++ bh_use[ra_max] = bh;
++ if (bh)
++ ll_rw_block(READ_META, 1, &bh);
++ }
++ }
++ if ((bh = bh_use[ra_ptr++]) == NULL)
++ goto next;
++ wait_on_buffer(bh);
++ if (!buffer_uptodate(bh)) {
++ /* read error, skip block & hope for the best */
++ ext4_error(sb, __FUNCTION__, "reading directory #%lu "
++ "offset %lu", dir->i_ino, block);
++ brelse(bh);
++ goto next;
++ }
++ i = search_dirblock(bh, dir, dentry,
++ block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
++ if (i == 1) {
++ EXT4_I(dir)->i_dir_start_lookup = block;
++ ret = bh;
++ goto cleanup_and_exit;
++ } else {
++ brelse(bh);
++ if (i < 0)
++ goto cleanup_and_exit;
++ }
++ next:
++ if (++block >= nblocks)
++ block = 0;
++ } while (block != start);
++
++ /*
++ * If the directory has grown while we were searching, then
++ * search the last part of the directory before giving up.
++ */
++ block = nblocks;
++ nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
++ if (block < nblocks) {
++ start = 0;
++ goto restart;
++ }
++
++cleanup_and_exit:
++ /* Clean up the read-ahead blocks */
++ for (; ra_ptr < ra_max; ra_ptr++)
++ brelse (bh_use[ra_ptr]);
++ return ret;
++}
++
++#ifdef CONFIG_EXT4_INDEX
++static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
++ struct ext4_dir_entry_2 **res_dir, int *err)
++{
++ struct super_block * sb;
++ struct dx_hash_info hinfo;
++ u32 hash;
++ struct dx_frame frames[2], *frame;
++ struct ext4_dir_entry_2 *de, *top;
++ struct buffer_head *bh;
++ unsigned long block;
++ int retval;
++ int namelen = dentry->d_name.len;
++ const u8 *name = dentry->d_name.name;
++ struct inode *dir = dentry->d_parent->d_inode;
++
++ sb = dir->i_sb;
++ /* NFS may look up ".." - look at dx_root directory block */
++ if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
++ if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
++ return NULL;
++ } else {
++ frame = frames;
++ frame->bh = NULL; /* for dx_release() */
++ frame->at = (struct dx_entry *)frames; /* hack for zero entry*/
++ dx_set_block(frame->at, 0); /* dx_root block is 0 */
++ }
++ hash = hinfo.hash;
++ do {
++ block = dx_get_block(frame->at);
++ if (!(bh = ext4_bread (NULL,dir, block, 0, err)))
++ goto errout;
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize -
++ EXT4_DIR_REC_LEN(0));
++ for (; de < top; de = ext4_next_entry(de))
++ if (ext4_match (namelen, name, de)) {
++ if (!ext4_check_dir_entry("ext4_find_entry",
++ dir, de, bh,
++ (block<<EXT4_BLOCK_SIZE_BITS(sb))
++ +((char *)de - bh->b_data))) {
++ brelse (bh);
++ goto errout;
++ }
++ *res_dir = de;
++ dx_release (frames);
++ return bh;
++ }
++ brelse (bh);
++ /* Check to see if we should continue to search */
++ retval = ext4_htree_next_block(dir, hash, frame,
++ frames, NULL);
++ if (retval < 0) {
++ ext4_warning(sb, __FUNCTION__,
++ "error reading index page in directory #%lu",
++ dir->i_ino);
++ *err = retval;
++ goto errout;
++ }
++ } while (retval == 1);
++
++ *err = -ENOENT;
++errout:
++ dxtrace(printk("%s not found\n", name));
++ dx_release (frames);
++ return NULL;
++}
++#endif
++
++static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
++{
++ struct inode * inode;
++ struct ext4_dir_entry_2 * de;
++ struct buffer_head * bh;
++
++ if (dentry->d_name.len > EXT4_NAME_LEN)
++ return ERR_PTR(-ENAMETOOLONG);
++
++ bh = ext4_find_entry(dentry, &de);
++ inode = NULL;
++ if (bh) {
++ unsigned long ino = le32_to_cpu(de->inode);
++ brelse (bh);
++ if (!ext4_valid_inum(dir->i_sb, ino)) {
++ ext4_error(dir->i_sb, "ext4_lookup",
++ "bad inode number: %lu", ino);
++ inode = NULL;
++ } else
++ inode = iget(dir->i_sb, ino);
++
++ if (!inode)
++ return ERR_PTR(-EACCES);
++ }
++ return d_splice_alias(inode, dentry);
++}
++
++
++struct dentry *ext4_get_parent(struct dentry *child)
++{
++ unsigned long ino;
++ struct dentry *parent;
++ struct inode *inode;
++ struct dentry dotdot;
++ struct ext4_dir_entry_2 * de;
++ struct buffer_head *bh;
++
++ dotdot.d_name.name = "..";
++ dotdot.d_name.len = 2;
++ dotdot.d_parent = child; /* confusing, isn't it! */
++
++ bh = ext4_find_entry(&dotdot, &de);
++ inode = NULL;
++ if (!bh)
++ return ERR_PTR(-ENOENT);
++ ino = le32_to_cpu(de->inode);
++ brelse(bh);
++
++ if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
++ ext4_error(child->d_inode->i_sb, "ext4_get_parent",
++ "bad inode number: %lu", ino);
++ inode = NULL;
++ } else
++ inode = iget(child->d_inode->i_sb, ino);
++
++ if (!inode)
++ return ERR_PTR(-EACCES);
++
++ parent = d_alloc_anon(inode);
++ if (!parent) {
++ iput(inode);
++ parent = ERR_PTR(-ENOMEM);
++ }
++ return parent;
++}
++
++#define S_SHIFT 12
++static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
++ [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
++ [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
++ [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
++ [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV,
++ [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO,
++ [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK,
++ [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK,
++};
++
++static inline void ext4_set_de_type(struct super_block *sb,
++ struct ext4_dir_entry_2 *de,
++ umode_t mode) {
++ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE))
++ de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
++}
++
++#ifdef CONFIG_EXT4_INDEX
++static struct ext4_dir_entry_2 *
++dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
++{
++ unsigned rec_len = 0;
++
++ while (count--) {
++ struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) (from + map->offs);
++ rec_len = EXT4_DIR_REC_LEN(de->name_len);
++ memcpy (to, de, rec_len);
++ ((struct ext4_dir_entry_2 *) to)->rec_len =
++ cpu_to_le16(rec_len);
++ de->inode = 0;
++ map++;
++ to += rec_len;
++ }
++ return (struct ext4_dir_entry_2 *) (to - rec_len);
++}
++
++static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size)
++{
++ struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
++ unsigned rec_len = 0;
++
++ prev = to = de;
++ while ((char*)de < base + size) {
++ next = (struct ext4_dir_entry_2 *) ((char *) de +
++ le16_to_cpu(de->rec_len));
++ if (de->inode && de->name_len) {
++ rec_len = EXT4_DIR_REC_LEN(de->name_len);
++ if (de > to)
++ memmove(to, de, rec_len);
++ to->rec_len = cpu_to_le16(rec_len);
++ prev = to;
++ to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len);
++ }
++ de = next;
++ }
++ return prev;
++}
++
++static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
++ struct buffer_head **bh,struct dx_frame *frame,
++ struct dx_hash_info *hinfo, int *error)
++{
++ unsigned blocksize = dir->i_sb->s_blocksize;
++ unsigned count, continued;
++ struct buffer_head *bh2;
++ u32 newblock;
++ u32 hash2;
++ struct dx_map_entry *map;
++ char *data1 = (*bh)->b_data, *data2;
++ unsigned split;
++ struct ext4_dir_entry_2 *de = NULL, *de2;
++ int err;
++
++ bh2 = ext4_append (handle, dir, &newblock, error);
++ if (!(bh2)) {
++ brelse(*bh);
++ *bh = NULL;
++ goto errout;
++ }
++
++ BUFFER_TRACE(*bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, *bh);
++ if (err) {
++ journal_error:
++ brelse(*bh);
++ brelse(bh2);
++ *bh = NULL;
++ ext4_std_error(dir->i_sb, err);
++ goto errout;
++ }
++ BUFFER_TRACE(frame->bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, frame->bh);
++ if (err)
++ goto journal_error;
++
++ data2 = bh2->b_data;
++
++ /* create map in the end of data2 block */
++ map = (struct dx_map_entry *) (data2 + blocksize);
++ count = dx_make_map ((struct ext4_dir_entry_2 *) data1,
++ blocksize, hinfo, map);
++ map -= count;
++ split = count/2; // need to adjust to actual middle
++ dx_sort_map (map, count);
++ hash2 = map[split].hash;
++ continued = hash2 == map[split - 1].hash;
++ dxtrace(printk("Split block %i at %x, %i/%i\n",
++ dx_get_block(frame->at), hash2, split, count-split));
++
++ /* Fancy dance to stay within two buffers */
++ de2 = dx_move_dirents(data1, data2, map + split, count - split);
++ de = dx_pack_dirents(data1,blocksize);
++ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
++ de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
++ dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
++ dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1));
++
++ /* Which block gets the new entry? */
++ if (hinfo->hash >= hash2)
++ {
++ swap(*bh, bh2);
++ de = de2;
++ }
++ dx_insert_block (frame, hash2 + continued, newblock);
++ err = ext4_journal_dirty_metadata (handle, bh2);
++ if (err)
++ goto journal_error;
++ err = ext4_journal_dirty_metadata (handle, frame->bh);
++ if (err)
++ goto journal_error;
++ brelse (bh2);
++ dxtrace(dx_show_index ("frame", frame->entries));
++errout:
++ return de;
++}
++#endif
++
++
++/*
++ * Add a new entry into a directory (leaf) block. If de is non-NULL,
++ * it points to a directory entry which is guaranteed to be large
++ * enough for new directory entry. If de is NULL, then
++ * add_dirent_to_buf will attempt search the directory block for
++ * space. It will return -ENOSPC if no space is available, and -EIO
++ * and -EEXIST if directory entry already exists.
++ *
++ * NOTE! bh is NOT released in the case where ENOSPC is returned. In
++ * all other cases bh is released.
++ */
++static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
++ struct inode *inode, struct ext4_dir_entry_2 *de,
++ struct buffer_head * bh)
++{
++ struct inode *dir = dentry->d_parent->d_inode;
++ const char *name = dentry->d_name.name;
++ int namelen = dentry->d_name.len;
++ unsigned long offset = 0;
++ unsigned short reclen;
++ int nlen, rlen, err;
++ char *top;
++
++ reclen = EXT4_DIR_REC_LEN(namelen);
++ if (!de) {
++ de = (struct ext4_dir_entry_2 *)bh->b_data;
++ top = bh->b_data + dir->i_sb->s_blocksize - reclen;
++ while ((char *) de <= top) {
++ if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
++ bh, offset)) {
++ brelse (bh);
++ return -EIO;
++ }
++ if (ext4_match (namelen, name, de)) {
++ brelse (bh);
++ return -EEXIST;
++ }
++ nlen = EXT4_DIR_REC_LEN(de->name_len);
++ rlen = le16_to_cpu(de->rec_len);
++ if ((de->inode? rlen - nlen: rlen) >= reclen)
++ break;
++ de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
++ offset += rlen;
++ }
++ if ((char *) de > top)
++ return -ENOSPC;
++ }
++ BUFFER_TRACE(bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, bh);
++ if (err) {
++ ext4_std_error(dir->i_sb, err);
++ brelse(bh);
++ return err;
++ }
++
++ /* By now the buffer is marked for journaling */
++ nlen = EXT4_DIR_REC_LEN(de->name_len);
++ rlen = le16_to_cpu(de->rec_len);
++ if (de->inode) {
++ struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
++ de1->rec_len = cpu_to_le16(rlen - nlen);
++ de->rec_len = cpu_to_le16(nlen);
++ de = de1;
++ }
++ de->file_type = EXT4_FT_UNKNOWN;
++ if (inode) {
++ de->inode = cpu_to_le32(inode->i_ino);
++ ext4_set_de_type(dir->i_sb, de, inode->i_mode);
++ } else
++ de->inode = 0;
++ de->name_len = namelen;
++ memcpy (de->name, name, namelen);
++ /*
++ * XXX shouldn't update any times until successful
++ * completion of syscall, but too many callers depend
++ * on this.
++ *
++ * XXX similarly, too many callers depend on
++ * ext4_new_inode() setting the times, but error
++ * recovery deletes the inode, so the worst that can
++ * happen is that the times are slightly out of date
++ * and/or different from the directory change time.
++ */
++ dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
++ ext4_update_dx_flag(dir);
++ dir->i_version++;
++ ext4_mark_inode_dirty(handle, dir);
++ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, bh);
++ if (err)
++ ext4_std_error(dir->i_sb, err);
++ brelse(bh);
++ return 0;
++}
++
++#ifdef CONFIG_EXT4_INDEX
++/*
++ * This converts a one block unindexed directory to a 3 block indexed
++ * directory, and adds the dentry to the indexed directory.
++ */
++static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
++ struct inode *inode, struct buffer_head *bh)
++{
++ struct inode *dir = dentry->d_parent->d_inode;
++ const char *name = dentry->d_name.name;
++ int namelen = dentry->d_name.len;
++ struct buffer_head *bh2;
++ struct dx_root *root;
++ struct dx_frame frames[2], *frame;
++ struct dx_entry *entries;
++ struct ext4_dir_entry_2 *de, *de2;
++ char *data1, *top;
++ unsigned len;
++ int retval;
++ unsigned blocksize;
++ struct dx_hash_info hinfo;
++ u32 block;
++ struct fake_dirent *fde;
++
++ blocksize = dir->i_sb->s_blocksize;
++ dxtrace(printk("Creating index\n"));
++ retval = ext4_journal_get_write_access(handle, bh);
++ if (retval) {
++ ext4_std_error(dir->i_sb, retval);
++ brelse(bh);
++ return retval;
++ }
++ root = (struct dx_root *) bh->b_data;
++
++ bh2 = ext4_append (handle, dir, &block, &retval);
++ if (!(bh2)) {
++ brelse(bh);
++ return retval;
++ }
++ EXT4_I(dir)->i_flags |= EXT4_INDEX_FL;
++ data1 = bh2->b_data;
++
++ /* The 0th block becomes the root, move the dirents out */
++ fde = &root->dotdot;
++ de = (struct ext4_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len));
++ len = ((char *) root) + blocksize - (char *) de;
++ memcpy (data1, de, len);
++ de = (struct ext4_dir_entry_2 *) data1;
++ top = data1 + len;
++ while ((char *)(de2=(void*)de+le16_to_cpu(de->rec_len)) < top)
++ de = de2;
++ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
++ /* Initialize the root; the dot dirents already exist */
++ de = (struct ext4_dir_entry_2 *) (&root->dotdot);
++ de->rec_len = cpu_to_le16(blocksize - EXT4_DIR_REC_LEN(2));
++ memset (&root->info, 0, sizeof(root->info));
++ root->info.info_length = sizeof(root->info);
++ root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
++ entries = root->entries;
++ dx_set_block (entries, 1);
++ dx_set_count (entries, 1);
++ dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
++
++ /* Initialize as for dx_probe */
++ hinfo.hash_version = root->info.hash_version;
++ hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
++ ext4fs_dirhash(name, namelen, &hinfo);
++ frame = frames;
++ frame->entries = entries;
++ frame->at = entries;
++ frame->bh = bh;
++ bh = bh2;
++ de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
++ dx_release (frames);
++ if (!(de))
++ return retval;
++
++ return add_dirent_to_buf(handle, dentry, inode, de, bh);
++}
++#endif
++
++/*
++ * ext4_add_entry()
++ *
++ * adds a file entry to the specified directory, using the same
++ * semantics as ext4_find_entry(). It returns NULL if it failed.
++ *
++ * NOTE!! The inode part of 'de' is left at 0 - which means you
++ * may not sleep between calling this and putting something into
++ * the entry, as someone else might have used it while you slept.
++ */
++static int ext4_add_entry (handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
++{
++ struct inode *dir = dentry->d_parent->d_inode;
++ unsigned long offset;
++ struct buffer_head * bh;
++ struct ext4_dir_entry_2 *de;
++ struct super_block * sb;
++ int retval;
++#ifdef CONFIG_EXT4_INDEX
++ int dx_fallback=0;
++#endif
++ unsigned blocksize;
++ u32 block, blocks;
++
++ sb = dir->i_sb;
++ blocksize = sb->s_blocksize;
++ if (!dentry->d_name.len)
++ return -EINVAL;
++#ifdef CONFIG_EXT4_INDEX
++ if (is_dx(dir)) {
++ retval = ext4_dx_add_entry(handle, dentry, inode);
++ if (!retval || (retval != ERR_BAD_DX_DIR))
++ return retval;
++ EXT4_I(dir)->i_flags &= ~EXT4_INDEX_FL;
++ dx_fallback++;
++ ext4_mark_inode_dirty(handle, dir);
++ }
++#endif
++ blocks = dir->i_size >> sb->s_blocksize_bits;
++ for (block = 0, offset = 0; block < blocks; block++) {
++ bh = ext4_bread(handle, dir, block, 0, &retval);
++ if(!bh)
++ return retval;
++ retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
++ if (retval != -ENOSPC)
++ return retval;
++
++#ifdef CONFIG_EXT4_INDEX
++ if (blocks == 1 && !dx_fallback &&
++ EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
++ return make_indexed_dir(handle, dentry, inode, bh);
++#endif
++ brelse(bh);
++ }
++ bh = ext4_append(handle, dir, &block, &retval);
++ if (!bh)
++ return retval;
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ de->inode = 0;
++ de->rec_len = cpu_to_le16(blocksize);
++ return add_dirent_to_buf(handle, dentry, inode, de, bh);
++}
++
++#ifdef CONFIG_EXT4_INDEX
++/*
++ * Returns 0 for success, or a negative error value
++ */
++static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
++{
++ struct dx_frame frames[2], *frame;
++ struct dx_entry *entries, *at;
++ struct dx_hash_info hinfo;
++ struct buffer_head * bh;
++ struct inode *dir = dentry->d_parent->d_inode;
++ struct super_block * sb = dir->i_sb;
++ struct ext4_dir_entry_2 *de;
++ int err;
++
++ frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
++ if (!frame)
++ return err;
++ entries = frame->entries;
++ at = frame->at;
++
++ if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
++ goto cleanup;
++
++ BUFFER_TRACE(bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, bh);
++ if (err)
++ goto journal_error;
++
++ err = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
++ if (err != -ENOSPC) {
++ bh = NULL;
++ goto cleanup;
++ }
++
++ /* Block full, should compress but for now just split */
++ dxtrace(printk("using %u of %u node entries\n",
++ dx_get_count(entries), dx_get_limit(entries)));
++ /* Need to split index? */
++ if (dx_get_count(entries) == dx_get_limit(entries)) {
++ u32 newblock;
++ unsigned icount = dx_get_count(entries);
++ int levels = frame - frames;
++ struct dx_entry *entries2;
++ struct dx_node *node2;
++ struct buffer_head *bh2;
++
++ if (levels && (dx_get_count(frames->entries) ==
++ dx_get_limit(frames->entries))) {
++ ext4_warning(sb, __FUNCTION__,
++ "Directory index full!");
++ err = -ENOSPC;
++ goto cleanup;
++ }
++ bh2 = ext4_append (handle, dir, &newblock, &err);
++ if (!(bh2))
++ goto cleanup;
++ node2 = (struct dx_node *)(bh2->b_data);
++ entries2 = node2->entries;
++ node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
++ node2->fake.inode = 0;
++ BUFFER_TRACE(frame->bh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, frame->bh);
++ if (err)
++ goto journal_error;
++ if (levels) {
++ unsigned icount1 = icount/2, icount2 = icount - icount1;
++ unsigned hash2 = dx_get_hash(entries + icount1);
++ dxtrace(printk("Split index %i/%i\n", icount1, icount2));
++
++ BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
++ err = ext4_journal_get_write_access(handle,
++ frames[0].bh);
++ if (err)
++ goto journal_error;
++
++ memcpy ((char *) entries2, (char *) (entries + icount1),
++ icount2 * sizeof(struct dx_entry));
++ dx_set_count (entries, icount1);
++ dx_set_count (entries2, icount2);
++ dx_set_limit (entries2, dx_node_limit(dir));
++
++ /* Which index block gets the new entry? */
++ if (at - entries >= icount1) {
++ frame->at = at = at - entries - icount1 + entries2;
++ frame->entries = entries = entries2;
++ swap(frame->bh, bh2);
++ }
++ dx_insert_block (frames + 0, hash2, newblock);
++ dxtrace(dx_show_index ("node", frames[1].entries));
++ dxtrace(dx_show_index ("node",
++ ((struct dx_node *) bh2->b_data)->entries));
++ err = ext4_journal_dirty_metadata(handle, bh2);
++ if (err)
++ goto journal_error;
++ brelse (bh2);
++ } else {
++ dxtrace(printk("Creating second level index...\n"));
++ memcpy((char *) entries2, (char *) entries,
++ icount * sizeof(struct dx_entry));
++ dx_set_limit(entries2, dx_node_limit(dir));
++
++ /* Set up root */
++ dx_set_count(entries, 1);
++ dx_set_block(entries + 0, newblock);
++ ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
++
++ /* Add new access path frame */
++ frame = frames + 1;
++ frame->at = at = at - entries + entries2;
++ frame->entries = entries = entries2;
++ frame->bh = bh2;
++ err = ext4_journal_get_write_access(handle,
++ frame->bh);
++ if (err)
++ goto journal_error;
++ }
++ ext4_journal_dirty_metadata(handle, frames[0].bh);
++ }
++ de = do_split(handle, dir, &bh, frame, &hinfo, &err);
++ if (!de)
++ goto cleanup;
++ err = add_dirent_to_buf(handle, dentry, inode, de, bh);
++ bh = NULL;
++ goto cleanup;
++
++journal_error:
++ ext4_std_error(dir->i_sb, err);
++cleanup:
++ if (bh)
++ brelse(bh);
++ dx_release(frames);
++ return err;
++}
++#endif
++
++/*
++ * ext4_delete_entry deletes a directory entry by merging it with the
++ * previous entry
++ */
++static int ext4_delete_entry (handle_t *handle,
++ struct inode * dir,
++ struct ext4_dir_entry_2 * de_del,
++ struct buffer_head * bh)
++{
++ struct ext4_dir_entry_2 * de, * pde;
++ int i;
++
++ i = 0;
++ pde = NULL;
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ while (i < bh->b_size) {
++ if (!ext4_check_dir_entry("ext4_delete_entry", dir, de, bh, i))
++ return -EIO;
++ if (de == de_del) {
++ BUFFER_TRACE(bh, "get_write_access");
++ ext4_journal_get_write_access(handle, bh);
++ if (pde)
++ pde->rec_len =
++ cpu_to_le16(le16_to_cpu(pde->rec_len) +
++ le16_to_cpu(de->rec_len));
++ else
++ de->inode = 0;
++ dir->i_version++;
++ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle, bh);
++ return 0;
++ }
++ i += le16_to_cpu(de->rec_len);
++ pde = de;
++ de = (struct ext4_dir_entry_2 *)
++ ((char *) de + le16_to_cpu(de->rec_len));
++ }
++ return -ENOENT;
++}
++
++/*
++ * ext4_mark_inode_dirty is somewhat expensive, so unlike ext2 we
++ * do not perform it in these functions. We perform it at the call site,
++ * if it is needed.
++ */
++static inline void ext4_inc_count(handle_t *handle, struct inode *inode)
++{
++ inc_nlink(inode);
++}
++
++static inline void ext4_dec_count(handle_t *handle, struct inode *inode)
++{
++ drop_nlink(inode);
++}
++
++static int ext4_add_nondir(handle_t *handle,
++ struct dentry *dentry, struct inode *inode)
++{
++ int err = ext4_add_entry(handle, dentry, inode);
++ if (!err) {
++ ext4_mark_inode_dirty(handle, inode);
++ d_instantiate(dentry, inode);
++ return 0;
++ }
++ ext4_dec_count(handle, inode);
++ iput(inode);
++ return err;
++}
++
++/*
++ * By the time this is called, we already have created
++ * the directory cache entry for the new file, but it
++ * is so far negative - it has no inode.
++ *
++ * If the create succeeds, we fill in the inode information
++ * with d_instantiate().
++ */
++static int ext4_create (struct inode * dir, struct dentry * dentry, int mode,
++ struct nameidata *nd)
++{
++ handle_t *handle;
++ struct inode * inode;
++ int err, retries = 0;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext4_new_inode (handle, dir, mode);
++ err = PTR_ERR(inode);
++ if (!IS_ERR(inode)) {
++ inode->i_op = &ext4_file_inode_operations;
++ inode->i_fop = &ext4_file_operations;
++ ext4_set_aops(inode);
++ err = ext4_add_nondir(handle, dentry, inode);
++ }
++ ext4_journal_stop(handle);
++ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
++ goto retry;
++ return err;
++}
++
++static int ext4_mknod (struct inode * dir, struct dentry *dentry,
++ int mode, dev_t rdev)
++{
++ handle_t *handle;
++ struct inode *inode;
++ int err, retries = 0;
++
++ if (!new_valid_dev(rdev))
++ return -EINVAL;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext4_new_inode (handle, dir, mode);
++ err = PTR_ERR(inode);
++ if (!IS_ERR(inode)) {
++ init_special_inode(inode, inode->i_mode, rdev);
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ inode->i_op = &ext4_special_inode_operations;
++#endif
++ err = ext4_add_nondir(handle, dentry, inode);
++ }
++ ext4_journal_stop(handle);
++ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
++ goto retry;
++ return err;
++}
++
++static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
++{
++ handle_t *handle;
++ struct inode * inode;
++ struct buffer_head * dir_block;
++ struct ext4_dir_entry_2 * de;
++ int err, retries = 0;
++
++ if (dir->i_nlink >= EXT4_LINK_MAX)
++ return -EMLINK;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext4_new_inode (handle, dir, S_IFDIR | mode);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out_stop;
++
++ inode->i_op = &ext4_dir_inode_operations;
++ inode->i_fop = &ext4_dir_operations;
++ inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
++ dir_block = ext4_bread (handle, inode, 0, 1, &err);
++ if (!dir_block) {
++ drop_nlink(inode); /* is this nlink == 0? */
++ ext4_mark_inode_dirty(handle, inode);
++ iput (inode);
++ goto out_stop;
++ }
++ BUFFER_TRACE(dir_block, "get_write_access");
++ ext4_journal_get_write_access(handle, dir_block);
++ de = (struct ext4_dir_entry_2 *) dir_block->b_data;
++ de->inode = cpu_to_le32(inode->i_ino);
++ de->name_len = 1;
++ de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de->name_len));
++ strcpy (de->name, ".");
++ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
++ de = (struct ext4_dir_entry_2 *)
++ ((char *) de + le16_to_cpu(de->rec_len));
++ de->inode = cpu_to_le32(dir->i_ino);
++ de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT4_DIR_REC_LEN(1));
++ de->name_len = 2;
++ strcpy (de->name, "..");
++ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
++ inode->i_nlink = 2;
++ BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle, dir_block);
++ brelse (dir_block);
++ ext4_mark_inode_dirty(handle, inode);
++ err = ext4_add_entry (handle, dentry, inode);
++ if (err) {
++ inode->i_nlink = 0;
++ ext4_mark_inode_dirty(handle, inode);
++ iput (inode);
++ goto out_stop;
++ }
++ inc_nlink(dir);
++ ext4_update_dx_flag(dir);
++ ext4_mark_inode_dirty(handle, dir);
++ d_instantiate(dentry, inode);
++out_stop:
++ ext4_journal_stop(handle);
++ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
++ goto retry;
++ return err;
++}
++
++/*
++ * routine to check that the specified directory is empty (for rmdir)
++ */
++static int empty_dir (struct inode * inode)
++{
++ unsigned long offset;
++ struct buffer_head * bh;
++ struct ext4_dir_entry_2 * de, * de1;
++ struct super_block * sb;
++ int err = 0;
++
++ sb = inode->i_sb;
++ if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
++ !(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
++ if (err)
++ ext4_error(inode->i_sb, __FUNCTION__,
++ "error %d reading directory #%lu offset 0",
++ err, inode->i_ino);
++ else
++ ext4_warning(inode->i_sb, __FUNCTION__,
++ "bad directory (dir #%lu) - no data block",
++ inode->i_ino);
++ return 1;
++ }
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ de1 = (struct ext4_dir_entry_2 *)
++ ((char *) de + le16_to_cpu(de->rec_len));
++ if (le32_to_cpu(de->inode) != inode->i_ino ||
++ !le32_to_cpu(de1->inode) ||
++ strcmp (".", de->name) ||
++ strcmp ("..", de1->name)) {
++ ext4_warning (inode->i_sb, "empty_dir",
++ "bad directory (dir #%lu) - no `.' or `..'",
++ inode->i_ino);
++ brelse (bh);
++ return 1;
++ }
++ offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
++ de = (struct ext4_dir_entry_2 *)
++ ((char *) de1 + le16_to_cpu(de1->rec_len));
++ while (offset < inode->i_size ) {
++ if (!bh ||
++ (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
++ err = 0;
++ brelse (bh);
++ bh = ext4_bread (NULL, inode,
++ offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
++ if (!bh) {
++ if (err)
++ ext4_error(sb, __FUNCTION__,
++ "error %d reading directory"
++ " #%lu offset %lu",
++ err, inode->i_ino, offset);
++ offset += sb->s_blocksize;
++ continue;
++ }
++ de = (struct ext4_dir_entry_2 *) bh->b_data;
++ }
++ if (!ext4_check_dir_entry("empty_dir", inode, de, bh, offset)) {
++ de = (struct ext4_dir_entry_2 *)(bh->b_data +
++ sb->s_blocksize);
++ offset = (offset | (sb->s_blocksize - 1)) + 1;
++ continue;
++ }
++ if (le32_to_cpu(de->inode)) {
++ brelse (bh);
++ return 0;
++ }
++ offset += le16_to_cpu(de->rec_len);
++ de = (struct ext4_dir_entry_2 *)
++ ((char *) de + le16_to_cpu(de->rec_len));
++ }
++ brelse (bh);
++ return 1;
++}
++
++/* ext4_orphan_add() links an unlinked or truncated inode into a list of
++ * such inodes, starting at the superblock, in case we crash before the
++ * file is closed/deleted, or in case the inode truncate spans multiple
++ * transactions and the last transaction is not recovered after a crash.
++ *
++ * At filesystem recovery time, we walk this list deleting unlinked
++ * inodes and truncating linked inodes in ext4_orphan_cleanup().
++ */
++int ext4_orphan_add(handle_t *handle, struct inode *inode)
++{
++ struct super_block *sb = inode->i_sb;
++ struct ext4_iloc iloc;
++ int err = 0, rc;
++
++ lock_super(sb);
++ if (!list_empty(&EXT4_I(inode)->i_orphan))
++ goto out_unlock;
++
++ /* Orphan handling is only valid for files with data blocks
++ * being truncated, or files being unlinked. */
++
++ /* @@@ FIXME: Observation from aviro:
++ * I think I can trigger J_ASSERT in ext4_orphan_add(). We block
++ * here (on lock_super()), so race with ext4_link() which might bump
++ * ->i_nlink. For, say it, character device. Not a regular file,
++ * not a directory, not a symlink and ->i_nlink > 0.
++ */
++ J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
++ S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
++
++ BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
++ if (err)
++ goto out_unlock;
++
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (err)
++ goto out_unlock;
++
++ /* Insert this inode at the head of the on-disk orphan list... */
++ NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan);
++ EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
++ err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
++ rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
++ if (!err)
++ err = rc;
++
++ /* Only add to the head of the in-memory list if all the
++ * previous operations succeeded. If the orphan_add is going to
++ * fail (possibly taking the journal offline), we can't risk
++ * leaving the inode on the orphan list: stray orphan-list
++ * entries can cause panics at unmount time.
++ *
++ * This is safe: on error we're going to ignore the orphan list
++ * anyway on the next recovery. */
++ if (!err)
++ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
++
++ jbd_debug(4, "superblock will point to %lu\n", inode->i_ino);
++ jbd_debug(4, "orphan inode %lu will point to %d\n",
++ inode->i_ino, NEXT_ORPHAN(inode));
++out_unlock:
++ unlock_super(sb);
++ ext4_std_error(inode->i_sb, err);
++ return err;
++}
++
++/*
++ * ext4_orphan_del() removes an unlinked or truncated inode from the list
++ * of such inodes stored on disk, because it is finally being cleaned up.
++ */
++int ext4_orphan_del(handle_t *handle, struct inode *inode)
++{
++ struct list_head *prev;
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ struct ext4_sb_info *sbi;
++ unsigned long ino_next;
++ struct ext4_iloc iloc;
++ int err = 0;
++
++ lock_super(inode->i_sb);
++ if (list_empty(&ei->i_orphan)) {
++ unlock_super(inode->i_sb);
++ return 0;
++ }
++
++ ino_next = NEXT_ORPHAN(inode);
++ prev = ei->i_orphan.prev;
++ sbi = EXT4_SB(inode->i_sb);
++
++ jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino);
++
++ list_del_init(&ei->i_orphan);
++
++ /* If we're on an error path, we may not have a valid
++ * transaction handle with which to update the orphan list on
++ * disk, but we still need to remove the inode from the linked
++ * list in memory. */
++ if (!handle)
++ goto out;
++
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (err)
++ goto out_err;
++
++ if (prev == &sbi->s_orphan) {
++ jbd_debug(4, "superblock will point to %lu\n", ino_next);
++ BUFFER_TRACE(sbi->s_sbh, "get_write_access");
++ err = ext4_journal_get_write_access(handle, sbi->s_sbh);
++ if (err)
++ goto out_brelse;
++ sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
++ err = ext4_journal_dirty_metadata(handle, sbi->s_sbh);
++ } else {
++ struct ext4_iloc iloc2;
++ struct inode *i_prev =
++ &list_entry(prev, struct ext4_inode_info, i_orphan)->vfs_inode;
++
++ jbd_debug(4, "orphan inode %lu will point to %lu\n",
++ i_prev->i_ino, ino_next);
++ err = ext4_reserve_inode_write(handle, i_prev, &iloc2);
++ if (err)
++ goto out_brelse;
++ NEXT_ORPHAN(i_prev) = ino_next;
++ err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2);
++ }
++ if (err)
++ goto out_brelse;
++ NEXT_ORPHAN(inode) = 0;
++ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
++
++out_err:
++ ext4_std_error(inode->i_sb, err);
++out:
++ unlock_super(inode->i_sb);
++ return err;
++
++out_brelse:
++ brelse(iloc.bh);
++ goto out_err;
++}
++
++static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
++{
++ int retval;
++ struct inode * inode;
++ struct buffer_head * bh;
++ struct ext4_dir_entry_2 * de;
++ handle_t *handle;
++
++ /* Initialize quotas before so that eventual writes go in
++ * separate transaction */
++ DQUOT_INIT(dentry->d_inode);
++ handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ retval = -ENOENT;
++ bh = ext4_find_entry (dentry, &de);
++ if (!bh)
++ goto end_rmdir;
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = dentry->d_inode;
++
++ retval = -EIO;
++ if (le32_to_cpu(de->inode) != inode->i_ino)
++ goto end_rmdir;
++
++ retval = -ENOTEMPTY;
++ if (!empty_dir (inode))
++ goto end_rmdir;
++
++ retval = ext4_delete_entry(handle, dir, de, bh);
++ if (retval)
++ goto end_rmdir;
++ if (inode->i_nlink != 2)
++ ext4_warning (inode->i_sb, "ext4_rmdir",
++ "empty directory has nlink!=2 (%d)",
++ inode->i_nlink);
++ inode->i_version++;
++ clear_nlink(inode);
++ /* There's no need to set i_disksize: the fact that i_nlink is
++ * zero will ensure that the right thing happens during any
++ * recovery. */
++ inode->i_size = 0;
++ ext4_orphan_add(handle, inode);
++ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
++ ext4_mark_inode_dirty(handle, inode);
++ drop_nlink(dir);
++ ext4_update_dx_flag(dir);
++ ext4_mark_inode_dirty(handle, dir);
++
++end_rmdir:
++ ext4_journal_stop(handle);
++ brelse (bh);
++ return retval;
++}
++
++static int ext4_unlink(struct inode * dir, struct dentry *dentry)
++{
++ int retval;
++ struct inode * inode;
++ struct buffer_head * bh;
++ struct ext4_dir_entry_2 * de;
++ handle_t *handle;
++
++ /* Initialize quotas before so that eventual writes go
++ * in separate transaction */
++ DQUOT_INIT(dentry->d_inode);
++ handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ retval = -ENOENT;
++ bh = ext4_find_entry (dentry, &de);
++ if (!bh)
++ goto end_unlink;
++
++ inode = dentry->d_inode;
++
++ retval = -EIO;
++ if (le32_to_cpu(de->inode) != inode->i_ino)
++ goto end_unlink;
++
++ if (!inode->i_nlink) {
++ ext4_warning (inode->i_sb, "ext4_unlink",
++ "Deleting nonexistent file (%lu), %d",
++ inode->i_ino, inode->i_nlink);
++ inode->i_nlink = 1;
++ }
++ retval = ext4_delete_entry(handle, dir, de, bh);
++ if (retval)
++ goto end_unlink;
++ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
++ ext4_update_dx_flag(dir);
++ ext4_mark_inode_dirty(handle, dir);
++ drop_nlink(inode);
++ if (!inode->i_nlink)
++ ext4_orphan_add(handle, inode);
++ inode->i_ctime = dir->i_ctime;
++ ext4_mark_inode_dirty(handle, inode);
++ retval = 0;
++
++end_unlink:
++ ext4_journal_stop(handle);
++ brelse (bh);
++ return retval;
++}
++
++static int ext4_symlink (struct inode * dir,
++ struct dentry *dentry, const char * symname)
++{
++ handle_t *handle;
++ struct inode * inode;
++ int l, err, retries = 0;
++
++ l = strlen(symname)+1;
++ if (l > dir->i_sb->s_blocksize)
++ return -ENAMETOOLONG;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 +
++ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext4_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out_stop;
++
++ if (l > sizeof (EXT4_I(inode)->i_data)) {
++ inode->i_op = &ext4_symlink_inode_operations;
++ ext4_set_aops(inode);
++ /*
++ * page_symlink() calls into ext4_prepare/commit_write.
++ * We have a transaction open. All is sweetness. It also sets
++ * i_size in generic_commit_write().
++ */
++ err = __page_symlink(inode, symname, l,
++ mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
++ if (err) {
++ ext4_dec_count(handle, inode);
++ ext4_mark_inode_dirty(handle, inode);
++ iput (inode);
++ goto out_stop;
++ }
++ } else {
++ inode->i_op = &ext4_fast_symlink_inode_operations;
++ memcpy((char*)&EXT4_I(inode)->i_data,symname,l);
++ inode->i_size = l-1;
++ }
++ EXT4_I(inode)->i_disksize = inode->i_size;
++ err = ext4_add_nondir(handle, dentry, inode);
++out_stop:
++ ext4_journal_stop(handle);
++ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
++ goto retry;
++ return err;
++}
++
++static int ext4_link (struct dentry * old_dentry,
++ struct inode * dir, struct dentry *dentry)
++{
++ handle_t *handle;
++ struct inode *inode = old_dentry->d_inode;
++ int err, retries = 0;
++
++ if (inode->i_nlink >= EXT4_LINK_MAX)
++ return -EMLINK;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode->i_ctime = CURRENT_TIME_SEC;
++ ext4_inc_count(handle, inode);
++ atomic_inc(&inode->i_count);
++
++ err = ext4_add_nondir(handle, dentry, inode);
++ ext4_journal_stop(handle);
++ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
++ goto retry;
++ return err;
++}
++
++#define PARENT_INO(buffer) \
++ ((struct ext4_dir_entry_2 *) ((char *) buffer + \
++ le16_to_cpu(((struct ext4_dir_entry_2 *) buffer)->rec_len)))->inode
++
++/*
++ * Anybody can rename anything with this: the permission checks are left to the
++ * higher-level routines.
++ */
++static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
++ struct inode * new_dir,struct dentry *new_dentry)
++{
++ handle_t *handle;
++ struct inode * old_inode, * new_inode;
++ struct buffer_head * old_bh, * new_bh, * dir_bh;
++ struct ext4_dir_entry_2 * old_de, * new_de;
++ int retval;
++
++ old_bh = new_bh = dir_bh = NULL;
++
++ /* Initialize quotas before so that eventual writes go
++ * in separate transaction */
++ if (new_dentry->d_inode)
++ DQUOT_INIT(new_dentry->d_inode);
++ handle = ext4_journal_start(old_dir, 2 *
++ EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
++ handle->h_sync = 1;
++
++ old_bh = ext4_find_entry (old_dentry, &old_de);
++ /*
++ * Check for inode number is _not_ due to possible IO errors.
++ * We might rmdir the source, keep it as pwd of some process
++ * and merrily kill the link to whatever was created under the
++ * same name. Goodbye sticky bit ;-<
++ */
++ old_inode = old_dentry->d_inode;
++ retval = -ENOENT;
++ if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
++ goto end_rename;
++
++ new_inode = new_dentry->d_inode;
++ new_bh = ext4_find_entry (new_dentry, &new_de);
++ if (new_bh) {
++ if (!new_inode) {
++ brelse (new_bh);
++ new_bh = NULL;
++ }
++ }
++ if (S_ISDIR(old_inode->i_mode)) {
++ if (new_inode) {
++ retval = -ENOTEMPTY;
++ if (!empty_dir (new_inode))
++ goto end_rename;
++ }
++ retval = -EIO;
++ dir_bh = ext4_bread (handle, old_inode, 0, 0, &retval);
++ if (!dir_bh)
++ goto end_rename;
++ if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
++ goto end_rename;
++ retval = -EMLINK;
++ if (!new_inode && new_dir!=old_dir &&
++ new_dir->i_nlink >= EXT4_LINK_MAX)
++ goto end_rename;
++ }
++ if (!new_bh) {
++ retval = ext4_add_entry (handle, new_dentry, old_inode);
++ if (retval)
++ goto end_rename;
++ } else {
++ BUFFER_TRACE(new_bh, "get write access");
++ ext4_journal_get_write_access(handle, new_bh);
++ new_de->inode = cpu_to_le32(old_inode->i_ino);
++ if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
++ EXT4_FEATURE_INCOMPAT_FILETYPE))
++ new_de->file_type = old_de->file_type;
++ new_dir->i_version++;
++ BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle, new_bh);
++ brelse(new_bh);
++ new_bh = NULL;
++ }
++
++ /*
++ * Like most other Unix systems, set the ctime for inodes on a
++ * rename.
++ */
++ old_inode->i_ctime = CURRENT_TIME_SEC;
++ ext4_mark_inode_dirty(handle, old_inode);
++
++ /*
++ * ok, that's it
++ */
++ if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
++ old_de->name_len != old_dentry->d_name.len ||
++ strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
++ (retval = ext4_delete_entry(handle, old_dir,
++ old_de, old_bh)) == -ENOENT) {
++ /* old_de could have moved from under us during htree split, so
++ * make sure that we are deleting the right entry. We might
++ * also be pointing to a stale entry in the unused part of
++ * old_bh so just checking inum and the name isn't enough. */
++ struct buffer_head *old_bh2;
++ struct ext4_dir_entry_2 *old_de2;
++
++ old_bh2 = ext4_find_entry(old_dentry, &old_de2);
++ if (old_bh2) {
++ retval = ext4_delete_entry(handle, old_dir,
++ old_de2, old_bh2);
++ brelse(old_bh2);
++ }
++ }
++ if (retval) {
++ ext4_warning(old_dir->i_sb, "ext4_rename",
++ "Deleting old file (%lu), %d, error=%d",
++ old_dir->i_ino, old_dir->i_nlink, retval);
++ }
++
++ if (new_inode) {
++ drop_nlink(new_inode);
++ new_inode->i_ctime = CURRENT_TIME_SEC;
++ }
++ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
++ ext4_update_dx_flag(old_dir);
++ if (dir_bh) {
++ BUFFER_TRACE(dir_bh, "get_write_access");
++ ext4_journal_get_write_access(handle, dir_bh);
++ PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
++ BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
++ ext4_journal_dirty_metadata(handle, dir_bh);
++ drop_nlink(old_dir);
++ if (new_inode) {
++ drop_nlink(new_inode);
++ } else {
++ inc_nlink(new_dir);
++ ext4_update_dx_flag(new_dir);
++ ext4_mark_inode_dirty(handle, new_dir);
++ }
++ }
++ ext4_mark_inode_dirty(handle, old_dir);
++ if (new_inode) {
++ ext4_mark_inode_dirty(handle, new_inode);
++ if (!new_inode->i_nlink)
++ ext4_orphan_add(handle, new_inode);
++ }
++ retval = 0;
++
++end_rename:
++ brelse (dir_bh);
++ brelse (old_bh);
++ brelse (new_bh);
++ ext4_journal_stop(handle);
++ return retval;
++}
++
++/*
++ * directories can handle most operations...
++ */
++struct inode_operations ext4_dir_inode_operations = {
++ .create = ext4_create,
++ .lookup = ext4_lookup,
++ .link = ext4_link,
++ .unlink = ext4_unlink,
++ .symlink = ext4_symlink,
++ .mkdir = ext4_mkdir,
++ .rmdir = ext4_rmdir,
++ .mknod = ext4_mknod,
++ .rename = ext4_rename,
++ .setattr = ext4_setattr,
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = ext4_listxattr,
++ .removexattr = generic_removexattr,
++#endif
++ .permission = ext4_permission,
++};
++
++struct inode_operations ext4_special_inode_operations = {
++ .setattr = ext4_setattr,
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = ext4_listxattr,
++ .removexattr = generic_removexattr,
++#endif
++ .permission = ext4_permission,
++};
+diff --git a/fs/ext4/namei.h b/fs/ext4/namei.h
+new file mode 100644
+index 0000000..5e4dfff
+--- /dev/null
++++ b/fs/ext4/namei.h
+@@ -0,0 +1,8 @@
++/* linux/fs/ext4/namei.h
++ *
++ * Copyright (C) 2005 Simtec Electronics
++ * Ben Dooks <ben at simtec.co.uk>
++ *
++*/
++
++extern struct dentry *ext4_get_parent(struct dentry *child);
+diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
+new file mode 100644
+index 0000000..4fe49c3
+--- /dev/null
++++ b/fs/ext4/resize.c
+@@ -0,0 +1,1050 @@
++/*
++ * linux/fs/ext4/resize.c
++ *
++ * Support for resizing an ext4 filesystem while it is mounted.
++ *
++ * Copyright (C) 2001, 2002 Andreas Dilger <adilger at clusterfs.com>
++ *
++ * This could probably be made into a module, because it is not often in use.
++ */
++
++
++#define EXT4FS_DEBUG
++
++#include <linux/sched.h>
++#include <linux/smp_lock.h>
++#include <linux/ext4_jbd2.h>
++
++#include <linux/errno.h>
++#include <linux/slab.h>
++
++
++#define outside(b, first, last) ((b) < (first) || (b) >= (last))
++#define inside(b, first, last) ((b) >= (first) && (b) < (last))
++
++static int verify_group_input(struct super_block *sb,
++ struct ext4_new_group_data *input)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ struct ext4_super_block *es = sbi->s_es;
++ ext4_fsblk_t start = ext4_blocks_count(es);
++ ext4_fsblk_t end = start + input->blocks_count;
++ unsigned group = input->group;
++ ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
++ unsigned overhead = ext4_bg_has_super(sb, group) ?
++ (1 + ext4_bg_num_gdb(sb, group) +
++ le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
++ ext4_fsblk_t metaend = start + overhead;
++ struct buffer_head *bh = NULL;
++ ext4_grpblk_t free_blocks_count, offset;
++ int err = -EINVAL;
++
++ input->free_blocks_count = free_blocks_count =
++ input->blocks_count - 2 - overhead - sbi->s_itb_per_group;
++
++ if (test_opt(sb, DEBUG))
++ printk(KERN_DEBUG "EXT4-fs: adding %s group %u: %u blocks "
++ "(%d free, %u reserved)\n",
++ ext4_bg_has_super(sb, input->group) ? "normal" :
++ "no-super", input->group, input->blocks_count,
++ free_blocks_count, input->reserved_blocks);
++
++ ext4_get_group_no_and_offset(sb, start, NULL, &offset);
++ if (group != sbi->s_groups_count)
++ ext4_warning(sb, __FUNCTION__,
++ "Cannot add at group %u (only %lu groups)",
++ input->group, sbi->s_groups_count);
++ else if (offset != 0)
++ ext4_warning(sb, __FUNCTION__, "Last group not full");
++ else if (input->reserved_blocks > input->blocks_count / 5)
++ ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",
++ input->reserved_blocks);
++ else if (free_blocks_count < 0)
++ ext4_warning(sb, __FUNCTION__, "Bad blocks count %u",
++ input->blocks_count);
++ else if (!(bh = sb_bread(sb, end - 1)))
++ ext4_warning(sb, __FUNCTION__,
++ "Cannot read last block (%llu)",
++ end - 1);
++ else if (outside(input->block_bitmap, start, end))
++ ext4_warning(sb, __FUNCTION__,
++ "Block bitmap not in group (block %llu)",
++ (unsigned long long)input->block_bitmap);
++ else if (outside(input->inode_bitmap, start, end))
++ ext4_warning(sb, __FUNCTION__,
++ "Inode bitmap not in group (block %llu)",
++ (unsigned long long)input->inode_bitmap);
++ else if (outside(input->inode_table, start, end) ||
++ outside(itend - 1, start, end))
++ ext4_warning(sb, __FUNCTION__,
++ "Inode table not in group (blocks %llu-%llu)",
++ (unsigned long long)input->inode_table, itend - 1);
++ else if (input->inode_bitmap == input->block_bitmap)
++ ext4_warning(sb, __FUNCTION__,
++ "Block bitmap same as inode bitmap (%llu)",
++ (unsigned long long)input->block_bitmap);
++ else if (inside(input->block_bitmap, input->inode_table, itend))
++ ext4_warning(sb, __FUNCTION__,
++ "Block bitmap (%llu) in inode table (%llu-%llu)",
++ (unsigned long long)input->block_bitmap,
++ (unsigned long long)input->inode_table, itend - 1);
++ else if (inside(input->inode_bitmap, input->inode_table, itend))
++ ext4_warning(sb, __FUNCTION__,
++ "Inode bitmap (%llu) in inode table (%llu-%llu)",
++ (unsigned long long)input->inode_bitmap,
++ (unsigned long long)input->inode_table, itend - 1);
++ else if (inside(input->block_bitmap, start, metaend))
++ ext4_warning(sb, __FUNCTION__,
++ "Block bitmap (%llu) in GDT table"
++ " (%llu-%llu)",
++ (unsigned long long)input->block_bitmap,
++ start, metaend - 1);
++ else if (inside(input->inode_bitmap, start, metaend))
++ ext4_warning(sb, __FUNCTION__,
++ "Inode bitmap (%llu) in GDT table"
++ " (%llu-%llu)",
++ (unsigned long long)input->inode_bitmap,
++ start, metaend - 1);
++ else if (inside(input->inode_table, start, metaend) ||
++ inside(itend - 1, start, metaend))
++ ext4_warning(sb, __FUNCTION__,
++ "Inode table (%llu-%llu) overlaps"
++ "GDT table (%llu-%llu)",
++ (unsigned long long)input->inode_table,
++ itend - 1, start, metaend - 1);
++ else
++ err = 0;
++ brelse(bh);
++
++ return err;
++}
++
++static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
++ ext4_fsblk_t blk)
++{
++ struct buffer_head *bh;
++ int err;
++
++ bh = sb_getblk(sb, blk);
++ if (!bh)
++ return ERR_PTR(-EIO);
++ if ((err = ext4_journal_get_write_access(handle, bh))) {
++ brelse(bh);
++ bh = ERR_PTR(err);
++ } else {
++ lock_buffer(bh);
++ memset(bh->b_data, 0, sb->s_blocksize);
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++ }
++
++ return bh;
++}
++
++/*
++ * To avoid calling the atomic setbit hundreds or thousands of times, we only
++ * need to use it within a single byte (to ensure we get endianness right).
++ * We can use memset for the rest of the bitmap as there are no other users.
++ */
++static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
++{
++ int i;
++
++ if (start_bit >= end_bit)
++ return;
++
++ ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
++ for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
++ ext4_set_bit(i, bitmap);
++ if (i < end_bit)
++ memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
++}
++
++/*
++ * Set up the block and inode bitmaps, and the inode table for the new group.
++ * This doesn't need to be part of the main transaction, since we are only
++ * changing blocks outside the actual filesystem. We still do journaling to
++ * ensure the recovery is correct in case of a failure just after resize.
++ * If any part of this fails, we simply abort the resize.
++ */
++static int setup_new_group_blocks(struct super_block *sb,
++ struct ext4_new_group_data *input)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ ext4_fsblk_t start = ext4_group_first_block_no(sb, input->group);
++ int reserved_gdb = ext4_bg_has_super(sb, input->group) ?
++ le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;
++ unsigned long gdblocks = ext4_bg_num_gdb(sb, input->group);
++ struct buffer_head *bh;
++ handle_t *handle;
++ ext4_fsblk_t block;
++ ext4_grpblk_t bit;
++ int i;
++ int err = 0, err2;
++
++ handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks +
++ 2 + sbi->s_itb_per_group);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ lock_super(sb);
++ if (input->group != sbi->s_groups_count) {
++ err = -EBUSY;
++ goto exit_journal;
++ }
++
++ if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) {
++ err = PTR_ERR(bh);
++ goto exit_journal;
++ }
++
++ if (ext4_bg_has_super(sb, input->group)) {
++ ext4_debug("mark backup superblock %#04lx (+0)\n", start);
++ ext4_set_bit(0, bh->b_data);
++ }
++
++ /* Copy all of the GDT blocks into the backup in this group */
++ for (i = 0, bit = 1, block = start + 1;
++ i < gdblocks; i++, block++, bit++) {
++ struct buffer_head *gdb;
++
++ ext4_debug("update backup group %#04lx (+%d)\n", block, bit);
++
++ gdb = sb_getblk(sb, block);
++ if (!gdb) {
++ err = -EIO;
++ goto exit_bh;
++ }
++ if ((err = ext4_journal_get_write_access(handle, gdb))) {
++ brelse(gdb);
++ goto exit_bh;
++ }
++ lock_buffer(bh);
++ memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size);
++ set_buffer_uptodate(gdb);
++ unlock_buffer(bh);
++ ext4_journal_dirty_metadata(handle, gdb);
++ ext4_set_bit(bit, bh->b_data);
++ brelse(gdb);
++ }
++
++ /* Zero out all of the reserved backup group descriptor table blocks */
++ for (i = 0, bit = gdblocks + 1, block = start + bit;
++ i < reserved_gdb; i++, block++, bit++) {
++ struct buffer_head *gdb;
++
++ ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit);
++
++ if (IS_ERR(gdb = bclean(handle, sb, block))) {
++ err = PTR_ERR(bh);
++ goto exit_bh;
++ }
++ ext4_journal_dirty_metadata(handle, gdb);
++ ext4_set_bit(bit, bh->b_data);
++ brelse(gdb);
++ }
++ ext4_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap,
++ input->block_bitmap - start);
++ ext4_set_bit(input->block_bitmap - start, bh->b_data);
++ ext4_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap,
++ input->inode_bitmap - start);
++ ext4_set_bit(input->inode_bitmap - start, bh->b_data);
++
++ /* Zero out all of the inode table blocks */
++ for (i = 0, block = input->inode_table, bit = block - start;
++ i < sbi->s_itb_per_group; i++, bit++, block++) {
++ struct buffer_head *it;
++
++ ext4_debug("clear inode block %#04lx (+%d)\n", block, bit);
++ if (IS_ERR(it = bclean(handle, sb, block))) {
++ err = PTR_ERR(it);
++ goto exit_bh;
++ }
++ ext4_journal_dirty_metadata(handle, it);
++ brelse(it);
++ ext4_set_bit(bit, bh->b_data);
++ }
++ mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),
++ bh->b_data);
++ ext4_journal_dirty_metadata(handle, bh);
++ brelse(bh);
++
++ /* Mark unused entries in inode bitmap used */
++ ext4_debug("clear inode bitmap %#04x (+%ld)\n",
++ input->inode_bitmap, input->inode_bitmap - start);
++ if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) {
++ err = PTR_ERR(bh);
++ goto exit_journal;
++ }
++
++ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb),
++ bh->b_data);
++ ext4_journal_dirty_metadata(handle, bh);
++exit_bh:
++ brelse(bh);
++
++exit_journal:
++ unlock_super(sb);
++ if ((err2 = ext4_journal_stop(handle)) && !err)
++ err = err2;
++
++ return err;
++}
++
++
++/*
++ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
++ * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before
++ * calling this for the first time. In a sparse filesystem it will be the
++ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
++ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
++ */
++static unsigned ext4_list_backups(struct super_block *sb, unsigned *three,
++ unsigned *five, unsigned *seven)
++{
++ unsigned *min = three;
++ int mult = 3;
++ unsigned ret;
++
++ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
++ ret = *min;
++ *min += 1;
++ return ret;
++ }
++
++ if (*five < *min) {
++ min = five;
++ mult = 5;
++ }
++ if (*seven < *min) {
++ min = seven;
++ mult = 7;
++ }
++
++ ret = *min;
++ *min *= mult;
++
++ return ret;
++}
++
++/*
++ * Check that all of the backup GDT blocks are held in the primary GDT block.
++ * It is assumed that they are stored in group order. Returns the number of
++ * groups in current filesystem that have BACKUPS, or -ve error code.
++ */
++static int verify_reserved_gdb(struct super_block *sb,
++ struct buffer_head *primary)
++{
++ const ext4_fsblk_t blk = primary->b_blocknr;
++ const unsigned long end = EXT4_SB(sb)->s_groups_count;
++ unsigned three = 1;
++ unsigned five = 5;
++ unsigned seven = 7;
++ unsigned grp;
++ __le32 *p = (__le32 *)primary->b_data;
++ int gdbackups = 0;
++
++ while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) {
++ if (le32_to_cpu(*p++) !=
++ grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){
++ ext4_warning(sb, __FUNCTION__,
++ "reserved GDT %llu"
++ " missing grp %d (%llu)",
++ blk, grp,
++ grp *
++ (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +
++ blk);
++ return -EINVAL;
++ }
++ if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb))
++ return -EFBIG;
++ }
++
++ return gdbackups;
++}
++
++/*
++ * Called when we need to bring a reserved group descriptor table block into
++ * use from the resize inode. The primary copy of the new GDT block currently
++ * is an indirect block (under the double indirect block in the resize inode).
++ * The new backup GDT blocks will be stored as leaf blocks in this indirect
++ * block, in group order. Even though we know all the block numbers we need,
++ * we check to ensure that the resize inode has actually reserved these blocks.
++ *
++ * Don't need to update the block bitmaps because the blocks are still in use.
++ *
++ * We get all of the error cases out of the way, so that we are sure to not
++ * fail once we start modifying the data on disk, because JBD has no rollback.
++ */
++static int add_new_gdb(handle_t *handle, struct inode *inode,
++ struct ext4_new_group_data *input,
++ struct buffer_head **primary)
++{
++ struct super_block *sb = inode->i_sb;
++ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
++ unsigned long gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);
++ ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
++ struct buffer_head **o_group_desc, **n_group_desc;
++ struct buffer_head *dind;
++ int gdbackups;
++ struct ext4_iloc iloc;
++ __le32 *data;
++ int err;
++
++ if (test_opt(sb, DEBUG))
++ printk(KERN_DEBUG
++ "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n",
++ gdb_num);
++
++ /*
++ * If we are not using the primary superblock/GDT copy don't resize,
++ * because the user tools have no way of handling this. Probably a
++ * bad time to do it anyways.
++ */
++ if (EXT4_SB(sb)->s_sbh->b_blocknr !=
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
++ ext4_warning(sb, __FUNCTION__,
++ "won't resize using backup superblock at %llu",
++ (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
++ return -EPERM;
++ }
++
++ *primary = sb_bread(sb, gdblock);
++ if (!*primary)
++ return -EIO;
++
++ if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) {
++ err = gdbackups;
++ goto exit_bh;
++ }
++
++ data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK;
++ dind = sb_bread(sb, le32_to_cpu(*data));
++ if (!dind) {
++ err = -EIO;
++ goto exit_bh;
++ }
++
++ data = (__le32 *)dind->b_data;
++ if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) {
++ ext4_warning(sb, __FUNCTION__,
++ "new group %u GDT block %llu not reserved",
++ input->group, gdblock);
++ err = -EINVAL;
++ goto exit_dind;
++ }
++
++ if ((err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh)))
++ goto exit_dind;
++
++ if ((err = ext4_journal_get_write_access(handle, *primary)))
++ goto exit_sbh;
++
++ if ((err = ext4_journal_get_write_access(handle, dind)))
++ goto exit_primary;
++
++ /* ext4_reserve_inode_write() gets a reference on the iloc */
++ if ((err = ext4_reserve_inode_write(handle, inode, &iloc)))
++ goto exit_dindj;
++
++ n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
++ GFP_KERNEL);
++ if (!n_group_desc) {
++ err = -ENOMEM;
++ ext4_warning (sb, __FUNCTION__,
++ "not enough memory for %lu groups", gdb_num + 1);
++ goto exit_inode;
++ }
++
++ /*
++ * Finally, we have all of the possible failures behind us...
++ *
++ * Remove new GDT block from inode double-indirect block and clear out
++ * the new GDT block for use (which also "frees" the backup GDT blocks
++ * from the reserved inode). We don't need to change the bitmaps for
++ * these blocks, because they are marked as in-use from being in the
++ * reserved inode, and will become GDT blocks (primary and backup).
++ */
++ data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0;
++ ext4_journal_dirty_metadata(handle, dind);
++ brelse(dind);
++ inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9;
++ ext4_mark_iloc_dirty(handle, inode, &iloc);
++ memset((*primary)->b_data, 0, sb->s_blocksize);
++ ext4_journal_dirty_metadata(handle, *primary);
++
++ o_group_desc = EXT4_SB(sb)->s_group_desc;
++ memcpy(n_group_desc, o_group_desc,
++ EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *));
++ n_group_desc[gdb_num] = *primary;
++ EXT4_SB(sb)->s_group_desc = n_group_desc;
++ EXT4_SB(sb)->s_gdb_count++;
++ kfree(o_group_desc);
++
++ es->s_reserved_gdt_blocks =
++ cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1);
++ ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
++
++ return 0;
++
++exit_inode:
++ //ext4_journal_release_buffer(handle, iloc.bh);
++ brelse(iloc.bh);
++exit_dindj:
++ //ext4_journal_release_buffer(handle, dind);
++exit_primary:
++ //ext4_journal_release_buffer(handle, *primary);
++exit_sbh:
++ //ext4_journal_release_buffer(handle, *primary);
++exit_dind:
++ brelse(dind);
++exit_bh:
++ brelse(*primary);
++
++ ext4_debug("leaving with error %d\n", err);
++ return err;
++}
++
++/*
++ * Called when we are adding a new group which has a backup copy of each of
++ * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks.
++ * We need to add these reserved backup GDT blocks to the resize inode, so
++ * that they are kept for future resizing and not allocated to files.
++ *
++ * Each reserved backup GDT block will go into a different indirect block.
++ * The indirect blocks are actually the primary reserved GDT blocks,
++ * so we know in advance what their block numbers are. We only get the
++ * double-indirect block to verify it is pointing to the primary reserved
++ * GDT blocks so we don't overwrite a data block by accident. The reserved
++ * backup GDT blocks are stored in their reserved primary GDT block.
++ */
++static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
++ struct ext4_new_group_data *input)
++{
++ struct super_block *sb = inode->i_sb;
++ int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks);
++ struct buffer_head **primary;
++ struct buffer_head *dind;
++ struct ext4_iloc iloc;
++ ext4_fsblk_t blk;
++ __le32 *data, *end;
++ int gdbackups = 0;
++ int res, i;
++ int err;
++
++ primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL);
++ if (!primary)
++ return -ENOMEM;
++
++ data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK;
++ dind = sb_bread(sb, le32_to_cpu(*data));
++ if (!dind) {
++ err = -EIO;
++ goto exit_free;
++ }
++
++ blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count;
++ data = (__le32 *)dind->b_data + EXT4_SB(sb)->s_gdb_count;
++ end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb);
++
++ /* Get each reserved primary GDT block and verify it holds backups */
++ for (res = 0; res < reserved_gdb; res++, blk++) {
++ if (le32_to_cpu(*data) != blk) {
++ ext4_warning(sb, __FUNCTION__,
++ "reserved block %llu"
++ " not at offset %ld",
++ blk,
++ (long)(data - (__le32 *)dind->b_data));
++ err = -EINVAL;
++ goto exit_bh;
++ }
++ primary[res] = sb_bread(sb, blk);
++ if (!primary[res]) {
++ err = -EIO;
++ goto exit_bh;
++ }
++ if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) {
++ brelse(primary[res]);
++ err = gdbackups;
++ goto exit_bh;
++ }
++ if (++data >= end)
++ data = (__le32 *)dind->b_data;
++ }
++
++ for (i = 0; i < reserved_gdb; i++) {
++ if ((err = ext4_journal_get_write_access(handle, primary[i]))) {
++ /*
++ int j;
++ for (j = 0; j < i; j++)
++ ext4_journal_release_buffer(handle, primary[j]);
++ */
++ goto exit_bh;
++ }
++ }
++
++ if ((err = ext4_reserve_inode_write(handle, inode, &iloc)))
++ goto exit_bh;
++
++ /*
++ * Finally we can add each of the reserved backup GDT blocks from
++ * the new group to its reserved primary GDT block.
++ */
++ blk = input->group * EXT4_BLOCKS_PER_GROUP(sb);
++ for (i = 0; i < reserved_gdb; i++) {
++ int err2;
++ data = (__le32 *)primary[i]->b_data;
++ /* printk("reserving backup %lu[%u] = %lu\n",
++ primary[i]->b_blocknr, gdbackups,
++ blk + primary[i]->b_blocknr); */
++ data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr);
++ err2 = ext4_journal_dirty_metadata(handle, primary[i]);
++ if (!err)
++ err = err2;
++ }
++ inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9;
++ ext4_mark_iloc_dirty(handle, inode, &iloc);
++
++exit_bh:
++ while (--res >= 0)
++ brelse(primary[res]);
++ brelse(dind);
++
++exit_free:
++ kfree(primary);
++
++ return err;
++}
++
++/*
++ * Update the backup copies of the ext4 metadata. These don't need to be part
++ * of the main resize transaction, because e2fsck will re-write them if there
++ * is a problem (basically only OOM will cause a problem). However, we
++ * _should_ update the backups if possible, in case the primary gets trashed
++ * for some reason and we need to run e2fsck from a backup superblock. The
++ * important part is that the new block and inode counts are in the backup
++ * superblocks, and the location of the new group metadata in the GDT backups.
++ *
++ * We do not need lock_super() for this, because these blocks are not
++ * otherwise touched by the filesystem code when it is mounted. We don't
++ * need to worry about last changing from sbi->s_groups_count, because the
++ * worst that can happen is that we do not copy the full number of backups
++ * at this time. The resize which changed s_groups_count will backup again.
++ */
++static void update_backups(struct super_block *sb,
++ int blk_off, char *data, int size)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ const unsigned long last = sbi->s_groups_count;
++ const int bpg = EXT4_BLOCKS_PER_GROUP(sb);
++ unsigned three = 1;
++ unsigned five = 5;
++ unsigned seven = 7;
++ unsigned group;
++ int rest = sb->s_blocksize - size;
++ handle_t *handle;
++ int err = 0, err2;
++
++ handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
++ if (IS_ERR(handle)) {
++ group = 1;
++ err = PTR_ERR(handle);
++ goto exit_err;
++ }
++
++ while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) {
++ struct buffer_head *bh;
++
++ /* Out of journal space, and can't get more - abort - so sad */
++ if (handle->h_buffer_credits == 0 &&
++ ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) &&
++ (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
++ break;
++
++ bh = sb_getblk(sb, group * bpg + blk_off);
++ if (!bh) {
++ err = -EIO;
++ break;
++ }
++ ext4_debug("update metadata backup %#04lx\n",
++ (unsigned long)bh->b_blocknr);
++ if ((err = ext4_journal_get_write_access(handle, bh)))
++ break;
++ lock_buffer(bh);
++ memcpy(bh->b_data, data, size);
++ if (rest)
++ memset(bh->b_data + size, 0, rest);
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++ ext4_journal_dirty_metadata(handle, bh);
++ brelse(bh);
++ }
++ if ((err2 = ext4_journal_stop(handle)) && !err)
++ err = err2;
++
++ /*
++ * Ugh! Need to have e2fsck write the backup copies. It is too
++ * late to revert the resize, we shouldn't fail just because of
++ * the backup copies (they are only needed in case of corruption).
++ *
++ * However, if we got here we have a journal problem too, so we
++ * can't really start a transaction to mark the superblock.
++ * Chicken out and just set the flag on the hope it will be written
++ * to disk, and if not - we will simply wait until next fsck.
++ */
++exit_err:
++ if (err) {
++ ext4_warning(sb, __FUNCTION__,
++ "can't update backup for group %d (err %d), "
++ "forcing fsck on next reboot", group, err);
++ sbi->s_mount_state &= ~EXT4_VALID_FS;
++ sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
++ mark_buffer_dirty(sbi->s_sbh);
++ }
++}
++
++/* Add group descriptor data to an existing or new group descriptor block.
++ * Ensure we handle all possible error conditions _before_ we start modifying
++ * the filesystem, because we cannot abort the transaction and not have it
++ * write the data to disk.
++ *
++ * If we are on a GDT block boundary, we need to get the reserved GDT block.
++ * Otherwise, we may need to add backup GDT blocks for a sparse group.
++ *
++ * We only need to hold the superblock lock while we are actually adding
++ * in the new group's counts to the superblock. Prior to that we have
++ * not really "added" the group at all. We re-check that we are still
++ * adding in the last group in case things have changed since verifying.
++ */
++int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ struct ext4_super_block *es = sbi->s_es;
++ int reserved_gdb = ext4_bg_has_super(sb, input->group) ?
++ le16_to_cpu(es->s_reserved_gdt_blocks) : 0;
++ struct buffer_head *primary = NULL;
++ struct ext4_group_desc *gdp;
++ struct inode *inode = NULL;
++ handle_t *handle;
++ int gdb_off, gdb_num;
++ int err, err2;
++
++ gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);
++ gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb);
++
++ if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
++ ext4_warning(sb, __FUNCTION__,
++ "Can't resize non-sparse filesystem further");
++ return -EPERM;
++ }
++
++ if (ext4_blocks_count(es) + input->blocks_count <
++ ext4_blocks_count(es)) {
++ ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n");
++ return -EINVAL;
++ }
++
++ if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) <
++ le32_to_cpu(es->s_inodes_count)) {
++ ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n");
++ return -EINVAL;
++ }
++
++ if (reserved_gdb || gdb_off == 0) {
++ if (!EXT4_HAS_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_COMPAT_RESIZE_INODE)){
++ ext4_warning(sb, __FUNCTION__,
++ "No reserved GDT blocks, can't resize");
++ return -EPERM;
++ }
++ inode = iget(sb, EXT4_RESIZE_INO);
++ if (!inode || is_bad_inode(inode)) {
++ ext4_warning(sb, __FUNCTION__,
++ "Error opening resize inode");
++ iput(inode);
++ return -ENOENT;
++ }
++ }
++
++ if ((err = verify_group_input(sb, input)))
++ goto exit_put;
++
++ if ((err = setup_new_group_blocks(sb, input)))
++ goto exit_put;
++
++ /*
++ * We will always be modifying at least the superblock and a GDT
++ * block. If we are adding a group past the last current GDT block,
++ * we will also modify the inode and the dindirect block. If we
++ * are adding a group with superblock/GDT backups we will also
++ * modify each of the reserved GDT dindirect blocks.
++ */
++ handle = ext4_journal_start_sb(sb,
++ ext4_bg_has_super(sb, input->group) ?
++ 3 + reserved_gdb : 4);
++ if (IS_ERR(handle)) {
++ err = PTR_ERR(handle);
++ goto exit_put;
++ }
++
++ lock_super(sb);
++ if (input->group != sbi->s_groups_count) {
++ ext4_warning(sb, __FUNCTION__,
++ "multiple resizers run on filesystem!");
++ err = -EBUSY;
++ goto exit_journal;
++ }
++
++ if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh)))
++ goto exit_journal;
++
++ /*
++ * We will only either add reserved group blocks to a backup group
++ * or remove reserved blocks for the first group in a new group block.
++ * Doing both would be mean more complex code, and sane people don't
++ * use non-sparse filesystems anymore. This is already checked above.
++ */
++ if (gdb_off) {
++ primary = sbi->s_group_desc[gdb_num];
++ if ((err = ext4_journal_get_write_access(handle, primary)))
++ goto exit_journal;
++
++ if (reserved_gdb && ext4_bg_num_gdb(sb, input->group) &&
++ (err = reserve_backup_gdb(handle, inode, input)))
++ goto exit_journal;
++ } else if ((err = add_new_gdb(handle, inode, input, &primary)))
++ goto exit_journal;
++
++ /*
++ * OK, now we've set up the new group. Time to make it active.
++ *
++ * Current kernels don't lock all allocations via lock_super(),
++ * so we have to be safe wrt. concurrent accesses the group
++ * data. So we need to be careful to set all of the relevant
++ * group descriptor data etc. *before* we enable the group.
++ *
++ * The key field here is sbi->s_groups_count: as long as
++ * that retains its old value, nobody is going to access the new
++ * group.
++ *
++ * So first we update all the descriptor metadata for the new
++ * group; then we update the total disk blocks count; then we
++ * update the groups count to enable the group; then finally we
++ * update the free space counts so that the system can start
++ * using the new disk blocks.
++ */
++
++ /* Update group descriptor block for new group */
++ gdp = (struct ext4_group_desc *)primary->b_data + gdb_off;
++
++ ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */
++ ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */
++ ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */
++ gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
++ gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb));
++
++ /*
++ * Make the new blocks and inodes valid next. We do this before
++ * increasing the group count so that once the group is enabled,
++ * all of its blocks and inodes are already valid.
++ *
++ * We always allocate group-by-group, then block-by-block or
++ * inode-by-inode within a group, so enabling these
++ * blocks/inodes before the group is live won't actually let us
++ * allocate the new space yet.
++ */
++ ext4_blocks_count_set(es, ext4_blocks_count(es) +
++ input->blocks_count);
++ es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +
++ EXT4_INODES_PER_GROUP(sb));
++
++ /*
++ * We need to protect s_groups_count against other CPUs seeing
++ * inconsistent state in the superblock.
++ *
++ * The precise rules we use are:
++ *
++ * * Writers of s_groups_count *must* hold lock_super
++ * AND
++ * * Writers must perform a smp_wmb() after updating all dependent
++ * data and before modifying the groups count
++ *
++ * * Readers must hold lock_super() over the access
++ * OR
++ * * Readers must perform an smp_rmb() after reading the groups count
++ * and before reading any dependent data.
++ *
++ * NB. These rules can be relaxed when checking the group count
++ * while freeing data, as we can only allocate from a block
++ * group after serialising against the group count, and we can
++ * only then free after serialising in turn against that
++ * allocation.
++ */
++ smp_wmb();
++
++ /* Update the global fs size fields */
++ sbi->s_groups_count++;
++
++ ext4_journal_dirty_metadata(handle, primary);
++
++ /* Update the reserved block counts only once the new group is
++ * active. */
++ ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
++ input->reserved_blocks);
++
++ /* Update the free space counts */
++ percpu_counter_mod(&sbi->s_freeblocks_counter,
++ input->free_blocks_count);
++ percpu_counter_mod(&sbi->s_freeinodes_counter,
++ EXT4_INODES_PER_GROUP(sb));
++
++ ext4_journal_dirty_metadata(handle, sbi->s_sbh);
++ sb->s_dirt = 1;
++
++exit_journal:
++ unlock_super(sb);
++ if ((err2 = ext4_journal_stop(handle)) && !err)
++ err = err2;
++ if (!err) {
++ update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
++ sizeof(struct ext4_super_block));
++ update_backups(sb, primary->b_blocknr, primary->b_data,
++ primary->b_size);
++ }
++exit_put:
++ iput(inode);
++ return err;
++} /* ext4_group_add */
++
++/* Extend the filesystem to the new number of blocks specified. This entry
++ * point is only used to extend the current filesystem to the end of the last
++ * existing group. It can be accessed via ioctl, or by "remount,resize=<size>"
++ * for emergencies (because it has no dependencies on reserved blocks).
++ *
++ * If we _really_ wanted, we could use default values to call ext4_group_add()
++ * allow the "remount" trick to work for arbitrary resizing, assuming enough
++ * GDT blocks are reserved to grow to the desired size.
++ */
++int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
++ ext4_fsblk_t n_blocks_count)
++{
++ ext4_fsblk_t o_blocks_count;
++ unsigned long o_groups_count;
++ ext4_grpblk_t last;
++ ext4_grpblk_t add;
++ struct buffer_head * bh;
++ handle_t *handle;
++ int err;
++ unsigned long freed_blocks;
++
++ /* We don't need to worry about locking wrt other resizers just
++ * yet: we're going to revalidate es->s_blocks_count after
++ * taking lock_super() below. */
++ o_blocks_count = ext4_blocks_count(es);
++ o_groups_count = EXT4_SB(sb)->s_groups_count;
++
++ if (test_opt(sb, DEBUG))
++ printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n",
++ o_blocks_count, n_blocks_count);
++
++ if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
++ return 0;
++
++ if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
++ printk(KERN_ERR "EXT4-fs: filesystem on %s:"
++ " too large to resize to %llu blocks safely\n",
++ sb->s_id, n_blocks_count);
++ if (sizeof(sector_t) < 8)
++ ext4_warning(sb, __FUNCTION__,
++ "CONFIG_LBD not enabled\n");
++ return -EINVAL;
++ }
++
++ if (n_blocks_count < o_blocks_count) {
++ ext4_warning(sb, __FUNCTION__,
++ "can't shrink FS - resize aborted");
++ return -EBUSY;
++ }
++
++ /* Handle the remaining blocks in the last group only. */
++ ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last);
++
++ if (last == 0) {
++ ext4_warning(sb, __FUNCTION__,
++ "need to use ext2online to resize further");
++ return -EPERM;
++ }
++
++ add = EXT4_BLOCKS_PER_GROUP(sb) - last;
++
++ if (o_blocks_count + add < o_blocks_count) {
++ ext4_warning(sb, __FUNCTION__, "blocks_count overflow");
++ return -EINVAL;
++ }
++
++ if (o_blocks_count + add > n_blocks_count)
++ add = n_blocks_count - o_blocks_count;
++
++ if (o_blocks_count + add < n_blocks_count)
++ ext4_warning(sb, __FUNCTION__,
++ "will only finish group (%llu"
++ " blocks, %u new)",
++ o_blocks_count + add, add);
++
++ /* See if the device is actually as big as what was requested */
++ bh = sb_bread(sb, o_blocks_count + add -1);
++ if (!bh) {
++ ext4_warning(sb, __FUNCTION__,
++ "can't read last block, resize aborted");
++ return -ENOSPC;
++ }
++ brelse(bh);
++
++ /* We will update the superblock, one block bitmap, and
++ * one group descriptor via ext4_free_blocks().
++ */
++ handle = ext4_journal_start_sb(sb, 3);
++ if (IS_ERR(handle)) {
++ err = PTR_ERR(handle);
++ ext4_warning(sb, __FUNCTION__, "error %d on journal start",err);
++ goto exit_put;
++ }
++
++ lock_super(sb);
++ if (o_blocks_count != ext4_blocks_count(es)) {
++ ext4_warning(sb, __FUNCTION__,
++ "multiple resizers run on filesystem!");
++ unlock_super(sb);
++ err = -EBUSY;
++ goto exit_put;
++ }
++
++ if ((err = ext4_journal_get_write_access(handle,
++ EXT4_SB(sb)->s_sbh))) {
++ ext4_warning(sb, __FUNCTION__,
++ "error %d on journal write access", err);
++ unlock_super(sb);
++ ext4_journal_stop(handle);
++ goto exit_put;
++ }
++ ext4_blocks_count_set(es, o_blocks_count + add);
++ ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
++ sb->s_dirt = 1;
++ unlock_super(sb);
++ ext4_debug("freeing blocks %lu through %llu\n", o_blocks_count,
++ o_blocks_count + add);
++ ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
++ ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
++ o_blocks_count + add);
++ if ((err = ext4_journal_stop(handle)))
++ goto exit_put;
++ if (test_opt(sb, DEBUG))
++ printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n",
++ ext4_blocks_count(es));
++ update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es,
++ sizeof(struct ext4_super_block));
++exit_put:
++ return err;
++} /* ext4_group_extend */
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+new file mode 100644
+index 0000000..b4b022a
+--- /dev/null
++++ b/fs/ext4/super.c
+@@ -0,0 +1,2829 @@
++/*
++ * linux/fs/ext4/super.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/inode.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem at caip.rutgers.edu), 1995
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/time.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/parser.h>
++#include <linux/smp_lock.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/random.h>
++#include <linux/mount.h>
++#include <linux/namei.h>
++#include <linux/quotaops.h>
++#include <linux/seq_file.h>
++
++#include <asm/uaccess.h>
++
++#include "xattr.h"
++#include "acl.h"
++#include "namei.h"
++
++static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
++ unsigned long journal_devnum);
++static int ext4_create_journal(struct super_block *, struct ext4_super_block *,
++ unsigned int);
++static void ext4_commit_super (struct super_block * sb,
++ struct ext4_super_block * es,
++ int sync);
++static void ext4_mark_recovery_complete(struct super_block * sb,
++ struct ext4_super_block * es);
++static void ext4_clear_journal_err(struct super_block * sb,
++ struct ext4_super_block * es);
++static int ext4_sync_fs(struct super_block *sb, int wait);
++static const char *ext4_decode_error(struct super_block * sb, int errno,
++ char nbuf[16]);
++static int ext4_remount (struct super_block * sb, int * flags, char * data);
++static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf);
++static void ext4_unlockfs(struct super_block *sb);
++static void ext4_write_super (struct super_block * sb);
++static void ext4_write_super_lockfs(struct super_block *sb);
++
++
++ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
++ struct ext4_group_desc *bg)
++{
++ return le32_to_cpu(bg->bg_block_bitmap) |
++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
++ (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
++}
++
++ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
++ struct ext4_group_desc *bg)
++{
++ return le32_to_cpu(bg->bg_inode_bitmap) |
++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
++ (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
++}
++
++ext4_fsblk_t ext4_inode_table(struct super_block *sb,
++ struct ext4_group_desc *bg)
++{
++ return le32_to_cpu(bg->bg_inode_table) |
++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
++ (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
++}
++
++void ext4_block_bitmap_set(struct super_block *sb,
++ struct ext4_group_desc *bg, ext4_fsblk_t blk)
++{
++ bg->bg_block_bitmap = cpu_to_le32((u32)blk);
++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
++ bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
++}
++
++void ext4_inode_bitmap_set(struct super_block *sb,
++ struct ext4_group_desc *bg, ext4_fsblk_t blk)
++{
++ bg->bg_inode_bitmap = cpu_to_le32((u32)blk);
++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
++ bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
++}
++
++void ext4_inode_table_set(struct super_block *sb,
++ struct ext4_group_desc *bg, ext4_fsblk_t blk)
++{
++ bg->bg_inode_table = cpu_to_le32((u32)blk);
++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
++ bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
++}
++
++/*
++ * Wrappers for jbd2_journal_start/end.
++ *
++ * The only special thing we need to do here is to make sure that all
++ * journal_end calls result in the superblock being marked dirty, so
++ * that sync() will call the filesystem's write_super callback if
++ * appropriate.
++ */
++handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
++{
++ journal_t *journal;
++
++ if (sb->s_flags & MS_RDONLY)
++ return ERR_PTR(-EROFS);
++
++ /* Special case here: if the journal has aborted behind our
++ * backs (eg. EIO in the commit thread), then we still need to
++ * take the FS itself readonly cleanly. */
++ journal = EXT4_SB(sb)->s_journal;
++ if (is_journal_aborted(journal)) {
++ ext4_abort(sb, __FUNCTION__,
++ "Detected aborted journal");
++ return ERR_PTR(-EROFS);
++ }
++
++ return jbd2_journal_start(journal, nblocks);
++}
++
++/*
++ * The only special thing we need to do here is to make sure that all
++ * jbd2_journal_stop calls result in the superblock being marked dirty, so
++ * that sync() will call the filesystem's write_super callback if
++ * appropriate.
++ */
++int __ext4_journal_stop(const char *where, handle_t *handle)
++{
++ struct super_block *sb;
++ int err;
++ int rc;
++
++ sb = handle->h_transaction->t_journal->j_private;
++ err = handle->h_err;
++ rc = jbd2_journal_stop(handle);
++
++ if (!err)
++ err = rc;
++ if (err)
++ __ext4_std_error(sb, where, err);
++ return err;
++}
++
++void ext4_journal_abort_handle(const char *caller, const char *err_fn,
++ struct buffer_head *bh, handle_t *handle, int err)
++{
++ char nbuf[16];
++ const char *errstr = ext4_decode_error(NULL, err, nbuf);
++
++ if (bh)
++ BUFFER_TRACE(bh, "abort");
++
++ if (!handle->h_err)
++ handle->h_err = err;
++
++ if (is_handle_aborted(handle))
++ return;
++
++ printk(KERN_ERR "%s: aborting transaction: %s in %s\n",
++ caller, errstr, err_fn);
++
++ jbd2_journal_abort_handle(handle);
++}
++
++/* Deal with the reporting of failure conditions on a filesystem such as
++ * inconsistencies detected or read IO failures.
++ *
++ * On ext2, we can store the error state of the filesystem in the
++ * superblock. That is not possible on ext4, because we may have other
++ * write ordering constraints on the superblock which prevent us from
++ * writing it out straight away; and given that the journal is about to
++ * be aborted, we can't rely on the current, or future, transactions to
++ * write out the superblock safely.
++ *
++ * We'll just use the jbd2_journal_abort() error code to record an error in
++ * the journal instead. On recovery, the journal will compain about
++ * that error until we've noted it down and cleared it.
++ */
++
++static void ext4_handle_error(struct super_block *sb)
++{
++ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
++
++ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
++ es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
++
++ if (sb->s_flags & MS_RDONLY)
++ return;
++
++ if (!test_opt (sb, ERRORS_CONT)) {
++ journal_t *journal = EXT4_SB(sb)->s_journal;
++
++ EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT;
++ if (journal)
++ jbd2_journal_abort(journal, -EIO);
++ }
++ if (test_opt (sb, ERRORS_RO)) {
++ printk (KERN_CRIT "Remounting filesystem read-only\n");
++ sb->s_flags |= MS_RDONLY;
++ }
++ ext4_commit_super(sb, es, 1);
++ if (test_opt(sb, ERRORS_PANIC))
++ panic("EXT4-fs (device %s): panic forced after error\n",
++ sb->s_id);
++}
++
++void ext4_error (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ va_start(args, fmt);
++ printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function);
++ vprintk(fmt, args);
++ printk("\n");
++ va_end(args);
++
++ ext4_handle_error(sb);
++}
++
++static const char *ext4_decode_error(struct super_block * sb, int errno,
++ char nbuf[16])
++{
++ char *errstr = NULL;
++
++ switch (errno) {
++ case -EIO:
++ errstr = "IO failure";
++ break;
++ case -ENOMEM:
++ errstr = "Out of memory";
++ break;
++ case -EROFS:
++ if (!sb || EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT)
++ errstr = "Journal has aborted";
++ else
++ errstr = "Readonly filesystem";
++ break;
++ default:
++ /* If the caller passed in an extra buffer for unknown
++ * errors, textualise them now. Else we just return
++ * NULL. */
++ if (nbuf) {
++ /* Check for truncated error codes... */
++ if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
++ errstr = nbuf;
++ }
++ break;
++ }
++
++ return errstr;
++}
++
++/* __ext4_std_error decodes expected errors from journaling functions
++ * automatically and invokes the appropriate error response. */
++
++void __ext4_std_error (struct super_block * sb, const char * function,
++ int errno)
++{
++ char nbuf[16];
++ const char *errstr;
++
++ /* Special case: if the error is EROFS, and we're not already
++ * inside a transaction, then there's really no point in logging
++ * an error. */
++ if (errno == -EROFS && journal_current_handle() == NULL &&
++ (sb->s_flags & MS_RDONLY))
++ return;
++
++ errstr = ext4_decode_error(sb, errno, nbuf);
++ printk (KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n",
++ sb->s_id, function, errstr);
++
++ ext4_handle_error(sb);
++}
++
++/*
++ * ext4_abort is a much stronger failure handler than ext4_error. The
++ * abort function may be used to deal with unrecoverable failures such
++ * as journal IO errors or ENOMEM at a critical moment in log management.
++ *
++ * We unconditionally force the filesystem into an ABORT|READONLY state,
++ * unless the error response on the fs has been set to panic in which
++ * case we take the easy way out and panic immediately.
++ */
++
++void ext4_abort (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ printk (KERN_CRIT "ext4_abort called.\n");
++
++ va_start(args, fmt);
++ printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function);
++ vprintk(fmt, args);
++ printk("\n");
++ va_end(args);
++
++ if (test_opt(sb, ERRORS_PANIC))
++ panic("EXT4-fs panic from previous error\n");
++
++ if (sb->s_flags & MS_RDONLY)
++ return;
++
++ printk(KERN_CRIT "Remounting filesystem read-only\n");
++ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
++ sb->s_flags |= MS_RDONLY;
++ EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT;
++ jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
++}
++
++void ext4_warning (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ va_start(args, fmt);
++ printk(KERN_WARNING "EXT4-fs warning (device %s): %s: ",
++ sb->s_id, function);
++ vprintk(fmt, args);
++ printk("\n");
++ va_end(args);
++}
++
++void ext4_update_dynamic_rev(struct super_block *sb)
++{
++ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
++
++ if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV)
++ return;
++
++ ext4_warning(sb, __FUNCTION__,
++ "updating to rev %d because of new feature flag, "
++ "running e2fsck is recommended",
++ EXT4_DYNAMIC_REV);
++
++ es->s_first_ino = cpu_to_le32(EXT4_GOOD_OLD_FIRST_INO);
++ es->s_inode_size = cpu_to_le16(EXT4_GOOD_OLD_INODE_SIZE);
++ es->s_rev_level = cpu_to_le32(EXT4_DYNAMIC_REV);
++ /* leave es->s_feature_*compat flags alone */
++ /* es->s_uuid will be set by e2fsck if empty */
++
++ /*
++ * The rest of the superblock fields should be zero, and if not it
++ * means they are likely already in use, so leave them alone. We
++ * can leave it up to e2fsck to clean up any inconsistencies there.
++ */
++}
++
++/*
++ * Open the external journal device
++ */
++static struct block_device *ext4_blkdev_get(dev_t dev)
++{
++ struct block_device *bdev;
++ char b[BDEVNAME_SIZE];
++
++ bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
++ if (IS_ERR(bdev))
++ goto fail;
++ return bdev;
++
++fail:
++ printk(KERN_ERR "EXT4: failed to open journal device %s: %ld\n",
++ __bdevname(dev, b), PTR_ERR(bdev));
++ return NULL;
++}
++
++/*
++ * Release the journal device
++ */
++static int ext4_blkdev_put(struct block_device *bdev)
++{
++ bd_release(bdev);
++ return blkdev_put(bdev);
++}
++
++static int ext4_blkdev_remove(struct ext4_sb_info *sbi)
++{
++ struct block_device *bdev;
++ int ret = -ENODEV;
++
++ bdev = sbi->journal_bdev;
++ if (bdev) {
++ ret = ext4_blkdev_put(bdev);
++ sbi->journal_bdev = NULL;
++ }
++ return ret;
++}
++
++static inline struct inode *orphan_list_entry(struct list_head *l)
++{
++ return &list_entry(l, struct ext4_inode_info, i_orphan)->vfs_inode;
++}
++
++static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi)
++{
++ struct list_head *l;
++
++ printk(KERN_ERR "sb orphan head is %d\n",
++ le32_to_cpu(sbi->s_es->s_last_orphan));
++
++ printk(KERN_ERR "sb_info orphan list:\n");
++ list_for_each(l, &sbi->s_orphan) {
++ struct inode *inode = orphan_list_entry(l);
++ printk(KERN_ERR " "
++ "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
++ inode->i_sb->s_id, inode->i_ino, inode,
++ inode->i_mode, inode->i_nlink,
++ NEXT_ORPHAN(inode));
++ }
++}
++
++static void ext4_put_super (struct super_block * sb)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ struct ext4_super_block *es = sbi->s_es;
++ int i;
++
++ ext4_ext_release(sb);
++ ext4_xattr_put_super(sb);
++ jbd2_journal_destroy(sbi->s_journal);
++ if (!(sb->s_flags & MS_RDONLY)) {
++ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
++ es->s_state = cpu_to_le16(sbi->s_mount_state);
++ BUFFER_TRACE(sbi->s_sbh, "marking dirty");
++ mark_buffer_dirty(sbi->s_sbh);
++ ext4_commit_super(sb, es, 1);
++ }
++
++ for (i = 0; i < sbi->s_gdb_count; i++)
++ brelse(sbi->s_group_desc[i]);
++ kfree(sbi->s_group_desc);
++ percpu_counter_destroy(&sbi->s_freeblocks_counter);
++ percpu_counter_destroy(&sbi->s_freeinodes_counter);
++ percpu_counter_destroy(&sbi->s_dirs_counter);
++ brelse(sbi->s_sbh);
++#ifdef CONFIG_QUOTA
++ for (i = 0; i < MAXQUOTAS; i++)
++ kfree(sbi->s_qf_names[i]);
++#endif
++
++ /* Debugging code just in case the in-memory inode orphan list
++ * isn't empty. The on-disk one can be non-empty if we've
++ * detected an error and taken the fs readonly, but the
++ * in-memory list had better be clean by this point. */
++ if (!list_empty(&sbi->s_orphan))
++ dump_orphan_list(sb, sbi);
++ J_ASSERT(list_empty(&sbi->s_orphan));
++
++ invalidate_bdev(sb->s_bdev, 0);
++ if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
++ /*
++ * Invalidate the journal device's buffers. We don't want them
++ * floating about in memory - the physical journal device may
++ * hotswapped, and it breaks the `ro-after' testing code.
++ */
++ sync_blockdev(sbi->journal_bdev);
++ invalidate_bdev(sbi->journal_bdev, 0);
++ ext4_blkdev_remove(sbi);
++ }
++ sb->s_fs_info = NULL;
++ kfree(sbi);
++ return;
++}
++
++static kmem_cache_t *ext4_inode_cachep;
++
++/*
++ * Called inside transaction, so use GFP_NOFS
++ */
++static struct inode *ext4_alloc_inode(struct super_block *sb)
++{
++ struct ext4_inode_info *ei;
++
++ ei = kmem_cache_alloc(ext4_inode_cachep, SLAB_NOFS);
++ if (!ei)
++ return NULL;
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ ei->i_acl = EXT4_ACL_NOT_CACHED;
++ ei->i_default_acl = EXT4_ACL_NOT_CACHED;
++#endif
++ ei->i_block_alloc_info = NULL;
++ ei->vfs_inode.i_version = 1;
++ memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
++ return &ei->vfs_inode;
++}
++
++static void ext4_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
++}
++
++static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
++{
++ struct ext4_inode_info *ei = (struct ext4_inode_info *) foo;
++
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR) {
++ INIT_LIST_HEAD(&ei->i_orphan);
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ init_rwsem(&ei->xattr_sem);
++#endif
++ mutex_init(&ei->truncate_mutex);
++ inode_init_once(&ei->vfs_inode);
++ }
++}
++
++static int init_inodecache(void)
++{
++ ext4_inode_cachep = kmem_cache_create("ext4_inode_cache",
++ sizeof(struct ext4_inode_info),
++ 0, (SLAB_RECLAIM_ACCOUNT|
++ SLAB_MEM_SPREAD),
++ init_once, NULL);
++ if (ext4_inode_cachep == NULL)
++ return -ENOMEM;
++ return 0;
++}
++
++static void destroy_inodecache(void)
++{
++ kmem_cache_destroy(ext4_inode_cachep);
++}
++
++static void ext4_clear_inode(struct inode *inode)
++{
++ struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info;
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ if (EXT4_I(inode)->i_acl &&
++ EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) {
++ posix_acl_release(EXT4_I(inode)->i_acl);
++ EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED;
++ }
++ if (EXT4_I(inode)->i_default_acl &&
++ EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) {
++ posix_acl_release(EXT4_I(inode)->i_default_acl);
++ EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED;
++ }
++#endif
++ ext4_discard_reservation(inode);
++ EXT4_I(inode)->i_block_alloc_info = NULL;
++ if (unlikely(rsv))
++ kfree(rsv);
++}
++
++static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb)
++{
++#if defined(CONFIG_QUOTA)
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++
++ if (sbi->s_jquota_fmt)
++ seq_printf(seq, ",jqfmt=%s",
++ (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
++
++ if (sbi->s_qf_names[USRQUOTA])
++ seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
++
++ if (sbi->s_qf_names[GRPQUOTA])
++ seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
++
++ if (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA)
++ seq_puts(seq, ",usrquota");
++
++ if (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)
++ seq_puts(seq, ",grpquota");
++#endif
++}
++
++static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
++{
++ struct super_block *sb = vfs->mnt_sb;
++
++ if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
++ seq_puts(seq, ",data=journal");
++ else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
++ seq_puts(seq, ",data=ordered");
++ else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
++ seq_puts(seq, ",data=writeback");
++
++ ext4_show_quota_options(seq, sb);
++
++ return 0;
++}
++
++
++static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
++{
++ __u32 *objp = vobjp;
++ unsigned long ino = objp[0];
++ __u32 generation = objp[1];
++ struct inode *inode;
++ struct dentry *result;
++
++ if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
++ return ERR_PTR(-ESTALE);
++ if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
++ return ERR_PTR(-ESTALE);
++
++ /* iget isn't really right if the inode is currently unallocated!!
++ *
++ * ext4_read_inode will return a bad_inode if the inode had been
++ * deleted, so we should be safe.
++ *
++ * Currently we don't know the generation for parent directory, so
++ * a generation of 0 means "accept any"
++ */
++ inode = iget(sb, ino);
++ if (inode == NULL)
++ return ERR_PTR(-ENOMEM);
++ if (is_bad_inode(inode) ||
++ (generation && inode->i_generation != generation)) {
++ iput(inode);
++ return ERR_PTR(-ESTALE);
++ }
++ /* now to find a dentry.
++ * If possible, get a well-connected one
++ */
++ result = d_alloc_anon(inode);
++ if (!result) {
++ iput(inode);
++ return ERR_PTR(-ENOMEM);
++ }
++ return result;
++}
++
++#ifdef CONFIG_QUOTA
++#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
++#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
++
++static int ext4_dquot_initialize(struct inode *inode, int type);
++static int ext4_dquot_drop(struct inode *inode);
++static int ext4_write_dquot(struct dquot *dquot);
++static int ext4_acquire_dquot(struct dquot *dquot);
++static int ext4_release_dquot(struct dquot *dquot);
++static int ext4_mark_dquot_dirty(struct dquot *dquot);
++static int ext4_write_info(struct super_block *sb, int type);
++static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path);
++static int ext4_quota_on_mount(struct super_block *sb, int type);
++static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
++ size_t len, loff_t off);
++static ssize_t ext4_quota_write(struct super_block *sb, int type,
++ const char *data, size_t len, loff_t off);
++
++static struct dquot_operations ext4_quota_operations = {
++ .initialize = ext4_dquot_initialize,
++ .drop = ext4_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 = ext4_write_dquot,
++ .acquire_dquot = ext4_acquire_dquot,
++ .release_dquot = ext4_release_dquot,
++ .mark_dirty = ext4_mark_dquot_dirty,
++ .write_info = ext4_write_info
++};
++
++static struct quotactl_ops ext4_qctl_operations = {
++ .quota_on = ext4_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 super_operations ext4_sops = {
++ .alloc_inode = ext4_alloc_inode,
++ .destroy_inode = ext4_destroy_inode,
++ .read_inode = ext4_read_inode,
++ .write_inode = ext4_write_inode,
++ .dirty_inode = ext4_dirty_inode,
++ .delete_inode = ext4_delete_inode,
++ .put_super = ext4_put_super,
++ .write_super = ext4_write_super,
++ .sync_fs = ext4_sync_fs,
++ .write_super_lockfs = ext4_write_super_lockfs,
++ .unlockfs = ext4_unlockfs,
++ .statfs = ext4_statfs,
++ .remount_fs = ext4_remount,
++ .clear_inode = ext4_clear_inode,
++ .show_options = ext4_show_options,
++#ifdef CONFIG_QUOTA
++ .quota_read = ext4_quota_read,
++ .quota_write = ext4_quota_write,
++#endif
++};
++
++static struct export_operations ext4_export_ops = {
++ .get_parent = ext4_get_parent,
++ .get_dentry = ext4_get_dentry,
++};
++
++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_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
++ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
++ Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
++ Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
++ 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_quota, Opt_noquota,
++ Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
++ Opt_grpquota, Opt_extents,
++};
++
++static match_table_t tokens = {
++ {Opt_bsd_df, "bsddf"},
++ {Opt_minix_df, "minixdf"},
++ {Opt_grpid, "grpid"},
++ {Opt_grpid, "bsdgroups"},
++ {Opt_nogrpid, "nogrpid"},
++ {Opt_nogrpid, "sysvgroups"},
++ {Opt_resgid, "resgid=%u"},
++ {Opt_resuid, "resuid=%u"},
++ {Opt_sb, "sb=%u"},
++ {Opt_err_cont, "errors=continue"},
++ {Opt_err_panic, "errors=panic"},
++ {Opt_err_ro, "errors=remount-ro"},
++ {Opt_nouid32, "nouid32"},
++ {Opt_nocheck, "nocheck"},
++ {Opt_nocheck, "check=none"},
++ {Opt_debug, "debug"},
++ {Opt_oldalloc, "oldalloc"},
++ {Opt_orlov, "orlov"},
++ {Opt_user_xattr, "user_xattr"},
++ {Opt_nouser_xattr, "nouser_xattr"},
++ {Opt_acl, "acl"},
++ {Opt_noacl, "noacl"},
++ {Opt_reservation, "reservation"},
++ {Opt_noreservation, "noreservation"},
++ {Opt_noload, "noload"},
++ {Opt_nobh, "nobh"},
++ {Opt_bh, "bh"},
++ {Opt_commit, "commit=%u"},
++ {Opt_journal_update, "journal=update"},
++ {Opt_journal_inum, "journal=%u"},
++ {Opt_journal_dev, "journal_dev=%u"},
++ {Opt_abort, "abort"},
++ {Opt_data_journal, "data=journal"},
++ {Opt_data_ordered, "data=ordered"},
++ {Opt_data_writeback, "data=writeback"},
++ {Opt_offusrjquota, "usrjquota="},
++ {Opt_usrjquota, "usrjquota=%s"},
++ {Opt_offgrpjquota, "grpjquota="},
++ {Opt_grpjquota, "grpjquota=%s"},
++ {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
++ {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
++ {Opt_grpquota, "grpquota"},
++ {Opt_noquota, "noquota"},
++ {Opt_quota, "quota"},
++ {Opt_usrquota, "usrquota"},
++ {Opt_barrier, "barrier=%u"},
++ {Opt_extents, "extents"},
++ {Opt_err, NULL},
++ {Opt_resize, "resize"},
++};
++
++static ext4_fsblk_t get_sb_block(void **data)
++{
++ ext4_fsblk_t sb_block;
++ char *options = (char *) *data;
++
++ if (!options || strncmp(options, "sb=", 3) != 0)
++ return 1; /* Default location */
++ options += 3;
++ /*todo: use simple_strtoll with >32bit ext4 */
++ sb_block = simple_strtoul(options, &options, 0);
++ if (*options && *options != ',') {
++ printk("EXT4-fs: Invalid sb specification: %s\n",
++ (char *) *data);
++ return 1;
++ }
++ if (*options == ',')
++ options++;
++ *data = (void *) options;
++ return sb_block;
++}
++
++static int parse_options (char *options, struct super_block *sb,
++ unsigned int *inum, unsigned long *journal_devnum,
++ ext4_fsblk_t *n_blocks_count, int is_remount)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ char * p;
++ substring_t args[MAX_OPT_ARGS];
++ int data_opt = 0;
++ int option;
++#ifdef CONFIG_QUOTA
++ int qtype;
++ char *qname;
++#endif
++
++ if (!options)
++ return 1;
++
++ while ((p = strsep (&options, ",")) != NULL) {
++ int token;
++ if (!*p)
++ continue;
++
++ token = match_token(p, tokens, args);
++ switch (token) {
++ case Opt_bsd_df:
++ clear_opt (sbi->s_mount_opt, MINIX_DF);
++ break;
++ case Opt_minix_df:
++ set_opt (sbi->s_mount_opt, MINIX_DF);
++ break;
++ case Opt_grpid:
++ set_opt (sbi->s_mount_opt, GRPID);
++ break;
++ case Opt_nogrpid:
++ clear_opt (sbi->s_mount_opt, GRPID);
++ break;
++ case Opt_resuid:
++ if (match_int(&args[0], &option))
++ return 0;
++ sbi->s_resuid = option;
++ break;
++ case Opt_resgid:
++ if (match_int(&args[0], &option))
++ return 0;
++ sbi->s_resgid = option;
++ break;
++ case Opt_sb:
++ /* handled by get_sb_block() instead of here */
++ /* *sb_block = match_int(&args[0]); */
++ break;
++ case Opt_err_panic:
++ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
++ clear_opt (sbi->s_mount_opt, ERRORS_RO);
++ set_opt (sbi->s_mount_opt, ERRORS_PANIC);
++ break;
++ case Opt_err_ro:
++ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
++ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
++ set_opt (sbi->s_mount_opt, ERRORS_RO);
++ break;
++ case Opt_err_cont:
++ clear_opt (sbi->s_mount_opt, ERRORS_RO);
++ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
++ set_opt (sbi->s_mount_opt, ERRORS_CONT);
++ break;
++ case Opt_nouid32:
++ set_opt (sbi->s_mount_opt, NO_UID32);
++ break;
++ case Opt_nocheck:
++ clear_opt (sbi->s_mount_opt, CHECK);
++ break;
++ case Opt_debug:
++ set_opt (sbi->s_mount_opt, DEBUG);
++ break;
++ case Opt_oldalloc:
++ set_opt (sbi->s_mount_opt, OLDALLOC);
++ break;
++ case Opt_orlov:
++ clear_opt (sbi->s_mount_opt, OLDALLOC);
++ break;
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ case Opt_user_xattr:
++ set_opt (sbi->s_mount_opt, XATTR_USER);
++ break;
++ case Opt_nouser_xattr:
++ clear_opt (sbi->s_mount_opt, XATTR_USER);
++ break;
++#else
++ case Opt_user_xattr:
++ case Opt_nouser_xattr:
++ printk("EXT4 (no)user_xattr options not supported\n");
++ break;
++#endif
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ case Opt_acl:
++ set_opt(sbi->s_mount_opt, POSIX_ACL);
++ break;
++ case Opt_noacl:
++ clear_opt(sbi->s_mount_opt, POSIX_ACL);
++ break;
++#else
++ case Opt_acl:
++ case Opt_noacl:
++ printk("EXT4 (no)acl options not supported\n");
++ break;
++#endif
++ case Opt_reservation:
++ set_opt(sbi->s_mount_opt, RESERVATION);
++ break;
++ case Opt_noreservation:
++ clear_opt(sbi->s_mount_opt, RESERVATION);
++ break;
++ case Opt_journal_update:
++ /* @@@ FIXME */
++ /* Eventually we will want to be able to create
++ a journal file here. For now, only allow the
++ user to specify an existing inode to be the
++ journal file. */
++ if (is_remount) {
++ printk(KERN_ERR "EXT4-fs: cannot specify "
++ "journal on remount\n");
++ return 0;
++ }
++ set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
++ break;
++ case Opt_journal_inum:
++ if (is_remount) {
++ printk(KERN_ERR "EXT4-fs: cannot specify "
++ "journal on remount\n");
++ return 0;
++ }
++ if (match_int(&args[0], &option))
++ return 0;
++ *inum = option;
++ break;
++ case Opt_journal_dev:
++ if (is_remount) {
++ printk(KERN_ERR "EXT4-fs: cannot specify "
++ "journal on remount\n");
++ return 0;
++ }
++ if (match_int(&args[0], &option))
++ return 0;
++ *journal_devnum = option;
++ break;
++ case Opt_noload:
++ set_opt (sbi->s_mount_opt, NOLOAD);
++ break;
++ case Opt_commit:
++ if (match_int(&args[0], &option))
++ return 0;
++ if (option < 0)
++ return 0;
++ if (option == 0)
++ option = JBD_DEFAULT_MAX_COMMIT_AGE;
++ sbi->s_commit_interval = HZ * option;
++ break;
++ case Opt_data_journal:
++ data_opt = EXT4_MOUNT_JOURNAL_DATA;
++ goto datacheck;
++ case Opt_data_ordered:
++ data_opt = EXT4_MOUNT_ORDERED_DATA;
++ goto datacheck;
++ case Opt_data_writeback:
++ data_opt = EXT4_MOUNT_WRITEBACK_DATA;
++ datacheck:
++ if (is_remount) {
++ if ((sbi->s_mount_opt & EXT4_MOUNT_DATA_FLAGS)
++ != data_opt) {
++ printk(KERN_ERR
++ "EXT4-fs: cannot change data "
++ "mode on remount\n");
++ return 0;
++ }
++ } else {
++ sbi->s_mount_opt &= ~EXT4_MOUNT_DATA_FLAGS;
++ sbi->s_mount_opt |= data_opt;
++ }
++ break;
++#ifdef CONFIG_QUOTA
++ case Opt_usrjquota:
++ qtype = USRQUOTA;
++ goto set_qf_name;
++ case Opt_grpjquota:
++ qtype = GRPQUOTA;
++set_qf_name:
++ if (sb_any_quota_enabled(sb)) {
++ printk(KERN_ERR
++ "EXT4-fs: Cannot change journalled "
++ "quota options when quota turned on.\n");
++ return 0;
++ }
++ qname = match_strdup(&args[0]);
++ if (!qname) {
++ printk(KERN_ERR
++ "EXT4-fs: not enough memory for "
++ "storing quotafile name.\n");
++ return 0;
++ }
++ if (sbi->s_qf_names[qtype] &&
++ strcmp(sbi->s_qf_names[qtype], qname)) {
++ printk(KERN_ERR
++ "EXT4-fs: %s quota file already "
++ "specified.\n", QTYPE2NAME(qtype));
++ kfree(qname);
++ return 0;
++ }
++ sbi->s_qf_names[qtype] = qname;
++ if (strchr(sbi->s_qf_names[qtype], '/')) {
++ printk(KERN_ERR
++ "EXT4-fs: quotafile must be on "
++ "filesystem root.\n");
++ kfree(sbi->s_qf_names[qtype]);
++ sbi->s_qf_names[qtype] = NULL;
++ return 0;
++ }
++ set_opt(sbi->s_mount_opt, QUOTA);
++ break;
++ case Opt_offusrjquota:
++ qtype = USRQUOTA;
++ goto clear_qf_name;
++ case Opt_offgrpjquota:
++ qtype = GRPQUOTA;
++clear_qf_name:
++ if (sb_any_quota_enabled(sb)) {
++ printk(KERN_ERR "EXT4-fs: Cannot change "
++ "journalled quota options when "
++ "quota turned on.\n");
++ return 0;
++ }
++ /*
++ * 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:
++ sbi->s_jquota_fmt = QFMT_VFS_OLD;
++ break;
++ case Opt_jqfmt_vfsv0:
++ sbi->s_jquota_fmt = QFMT_VFS_V0;
++ break;
++ case Opt_quota:
++ case Opt_usrquota:
++ set_opt(sbi->s_mount_opt, QUOTA);
++ set_opt(sbi->s_mount_opt, USRQUOTA);
++ break;
++ case Opt_grpquota:
++ set_opt(sbi->s_mount_opt, QUOTA);
++ set_opt(sbi->s_mount_opt, GRPQUOTA);
++ break;
++ case Opt_noquota:
++ if (sb_any_quota_enabled(sb)) {
++ printk(KERN_ERR "EXT4-fs: Cannot change quota "
++ "options when quota turned on.\n");
++ return 0;
++ }
++ clear_opt(sbi->s_mount_opt, QUOTA);
++ clear_opt(sbi->s_mount_opt, USRQUOTA);
++ clear_opt(sbi->s_mount_opt, GRPQUOTA);
++ break;
++#else
++ case Opt_quota:
++ case Opt_usrquota:
++ case Opt_grpquota:
++ case Opt_usrjquota:
++ case Opt_grpjquota:
++ case Opt_offusrjquota:
++ case Opt_offgrpjquota:
++ case Opt_jqfmt_vfsold:
++ case Opt_jqfmt_vfsv0:
++ printk(KERN_ERR
++ "EXT4-fs: journalled quota options not "
++ "supported.\n");
++ break;
++ case Opt_noquota:
++ break;
++#endif
++ case Opt_abort:
++ set_opt(sbi->s_mount_opt, ABORT);
++ break;
++ case Opt_barrier:
++ if (match_int(&args[0], &option))
++ return 0;
++ if (option)
++ set_opt(sbi->s_mount_opt, BARRIER);
++ else
++ clear_opt(sbi->s_mount_opt, BARRIER);
++ break;
++ case Opt_ignore:
++ break;
++ case Opt_resize:
++ if (!is_remount) {
++ printk("EXT4-fs: resize option only available "
++ "for remount\n");
++ return 0;
++ }
++ if (match_int(&args[0], &option) != 0)
++ return 0;
++ *n_blocks_count = option;
++ break;
++ case Opt_nobh:
++ set_opt(sbi->s_mount_opt, NOBH);
++ break;
++ case Opt_bh:
++ clear_opt(sbi->s_mount_opt, NOBH);
++ break;
++ case Opt_extents:
++ set_opt (sbi->s_mount_opt, EXTENTS);
++ break;
++ default:
++ printk (KERN_ERR
++ "EXT4-fs: Unrecognized mount option \"%s\" "
++ "or missing value\n", p);
++ return 0;
++ }
++ }
++#ifdef CONFIG_QUOTA
++ if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
++ if ((sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA) &&
++ sbi->s_qf_names[USRQUOTA])
++ clear_opt(sbi->s_mount_opt, USRQUOTA);
++
++ if ((sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA) &&
++ sbi->s_qf_names[GRPQUOTA])
++ clear_opt(sbi->s_mount_opt, GRPQUOTA);
++
++ if ((sbi->s_qf_names[USRQUOTA] &&
++ (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)) ||
++ (sbi->s_qf_names[GRPQUOTA] &&
++ (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA))) {
++ printk(KERN_ERR "EXT4-fs: old and new quota "
++ "format mixing.\n");
++ return 0;
++ }
++
++ if (!sbi->s_jquota_fmt) {
++ printk(KERN_ERR "EXT4-fs: journalled quota format "
++ "not specified.\n");
++ return 0;
++ }
++ } else {
++ if (sbi->s_jquota_fmt) {
++ printk(KERN_ERR "EXT4-fs: journalled quota format "
++ "specified with no journalling "
++ "enabled.\n");
++ return 0;
++ }
++ }
++#endif
++ return 1;
++}
++
++static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
++ int read_only)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ int res = 0;
++
++ if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) {
++ printk (KERN_ERR "EXT4-fs warning: revision level too high, "
++ "forcing read-only mode\n");
++ res = MS_RDONLY;
++ }
++ if (read_only)
++ return res;
++ if (!(sbi->s_mount_state & EXT4_VALID_FS))
++ printk (KERN_WARNING "EXT4-fs warning: mounting unchecked fs, "
++ "running e2fsck is recommended\n");
++ else if ((sbi->s_mount_state & EXT4_ERROR_FS))
++ printk (KERN_WARNING
++ "EXT4-fs warning: mounting fs with errors, "
++ "running e2fsck is recommended\n");
++ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
++ le16_to_cpu(es->s_mnt_count) >=
++ (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
++ printk (KERN_WARNING
++ "EXT4-fs warning: maximal mount count reached, "
++ "running e2fsck is recommended\n");
++ else if (le32_to_cpu(es->s_checkinterval) &&
++ (le32_to_cpu(es->s_lastcheck) +
++ le32_to_cpu(es->s_checkinterval) <= get_seconds()))
++ printk (KERN_WARNING
++ "EXT4-fs warning: checktime reached, "
++ "running e2fsck is recommended\n");
++#if 0
++ /* @@@ We _will_ want to clear the valid bit if we find
++ * inconsistencies, to force a fsck at reboot. But for
++ * a plain journaled filesystem we can keep it set as
++ * valid forever! :)
++ */
++ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT4_VALID_FS);
++#endif
++ if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
++ es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
++ es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
++ es->s_mtime = cpu_to_le32(get_seconds());
++ ext4_update_dynamic_rev(sb);
++ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
++
++ ext4_commit_super(sb, es, 1);
++ if (test_opt(sb, DEBUG))
++ printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%lu, "
++ "bpg=%lu, ipg=%lu, mo=%04lx]\n",
++ sb->s_blocksize,
++ sbi->s_groups_count,
++ EXT4_BLOCKS_PER_GROUP(sb),
++ EXT4_INODES_PER_GROUP(sb),
++ sbi->s_mount_opt);
++
++ printk(KERN_INFO "EXT4 FS on %s, ", sb->s_id);
++ if (EXT4_SB(sb)->s_journal->j_inode == NULL) {
++ char b[BDEVNAME_SIZE];
++
++ printk("external journal on %s\n",
++ bdevname(EXT4_SB(sb)->s_journal->j_dev, b));
++ } else {
++ printk("internal journal\n");
++ }
++ return res;
++}
++
++/* Called at mount-time, super-block is locked */
++static int ext4_check_descriptors (struct super_block * sb)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
++ ext4_fsblk_t last_block;
++ ext4_fsblk_t block_bitmap;
++ ext4_fsblk_t inode_bitmap;
++ ext4_fsblk_t inode_table;
++ struct ext4_group_desc * gdp = NULL;
++ int desc_block = 0;
++ int i;
++
++ ext4_debug ("Checking group descriptors");
++
++ for (i = 0; i < sbi->s_groups_count; i++)
++ {
++ if (i == sbi->s_groups_count - 1)
++ last_block = ext4_blocks_count(sbi->s_es) - 1;
++ else
++ last_block = first_block +
++ (EXT4_BLOCKS_PER_GROUP(sb) - 1);
++
++ if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
++ gdp = (struct ext4_group_desc *)
++ sbi->s_group_desc[desc_block++]->b_data;
++ block_bitmap = ext4_block_bitmap(sb, gdp);
++ if (block_bitmap < first_block || block_bitmap > last_block)
++ {
++ ext4_error (sb, "ext4_check_descriptors",
++ "Block bitmap for group %d"
++ " not in group (block %llu)!",
++ i, block_bitmap);
++ return 0;
++ }
++ inode_bitmap = ext4_inode_bitmap(sb, gdp);
++ if (inode_bitmap < first_block || inode_bitmap > last_block)
++ {
++ ext4_error (sb, "ext4_check_descriptors",
++ "Inode bitmap for group %d"
++ " not in group (block %llu)!",
++ i, inode_bitmap);
++ return 0;
++ }
++ inode_table = ext4_inode_table(sb, gdp);
++ if (inode_table < first_block ||
++ inode_table + sbi->s_itb_per_group > last_block)
++ {
++ ext4_error (sb, "ext4_check_descriptors",
++ "Inode table for group %d"
++ " not in group (block %llu)!",
++ i, inode_table);
++ return 0;
++ }
++ first_block += EXT4_BLOCKS_PER_GROUP(sb);
++ gdp = (struct ext4_group_desc *)
++ ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
++ }
++
++ ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
++ sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb));
++ return 1;
++}
++
++
++/* ext4_orphan_cleanup() walks a singly-linked list of inodes (starting at
++ * the superblock) which were deleted from all directories, but held open by
++ * a process at the time of a crash. We walk the list and try to delete these
++ * inodes at recovery time (only with a read-write filesystem).
++ *
++ * In order to keep the orphan inode chain consistent during traversal (in
++ * case of crash during recovery), we link each inode into the superblock
++ * orphan list_head and handle it the same way as an inode deletion during
++ * normal operation (which journals the operations for us).
++ *
++ * We only do an iget() and an iput() on each inode, which is very safe if we
++ * accidentally point at an in-use or already deleted inode. The worst that
++ * can happen in this case is that we get a "bit already cleared" message from
++ * ext4_free_inode(). The only reason we would point at a wrong inode is if
++ * e2fsck was run on this filesystem, and it must have already done the orphan
++ * inode cleanup for us, so we can safely abort without any further action.
++ */
++static void ext4_orphan_cleanup (struct super_block * sb,
++ struct ext4_super_block * es)
++{
++ unsigned int s_flags = sb->s_flags;
++ int nr_orphans = 0, nr_truncates = 0;
++#ifdef CONFIG_QUOTA
++ int i;
++#endif
++ if (!es->s_last_orphan) {
++ jbd_debug(4, "no orphan inodes to clean up\n");
++ return;
++ }
++
++ if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
++ if (es->s_last_orphan)
++ jbd_debug(1, "Errors on filesystem, "
++ "clearing orphan list.\n");
++ es->s_last_orphan = 0;
++ jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
++ return;
++ }
++
++ if (s_flags & MS_RDONLY) {
++ printk(KERN_INFO "EXT4-fs: %s: orphan cleanup on readonly fs\n",
++ sb->s_id);
++ sb->s_flags &= ~MS_RDONLY;
++ }
++#ifdef CONFIG_QUOTA
++ /* Needed for iput() to work correctly and not trash data */
++ sb->s_flags |= MS_ACTIVE;
++ /* Turn on quotas so that they are updated correctly */
++ for (i = 0; i < MAXQUOTAS; i++) {
++ if (EXT4_SB(sb)->s_qf_names[i]) {
++ int ret = ext4_quota_on_mount(sb, i);
++ if (ret < 0)
++ printk(KERN_ERR
++ "EXT4-fs: Cannot turn on journalled "
++ "quota: error %d\n", ret);
++ }
++ }
++#endif
++
++ while (es->s_last_orphan) {
++ struct inode *inode;
++
++ if (!(inode =
++ ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
++ es->s_last_orphan = 0;
++ break;
++ }
++
++ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
++ DQUOT_INIT(inode);
++ if (inode->i_nlink) {
++ printk(KERN_DEBUG
++ "%s: truncating inode %lu to %Ld bytes\n",
++ __FUNCTION__, inode->i_ino, inode->i_size);
++ jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
++ inode->i_ino, inode->i_size);
++ ext4_truncate(inode);
++ nr_truncates++;
++ } else {
++ printk(KERN_DEBUG
++ "%s: deleting unreferenced inode %lu\n",
++ __FUNCTION__, inode->i_ino);
++ jbd_debug(2, "deleting unreferenced inode %lu\n",
++ inode->i_ino);
++ nr_orphans++;
++ }
++ iput(inode); /* The delete magic happens here! */
++ }
++
++#define PLURAL(x) (x), ((x)==1) ? "" : "s"
++
++ if (nr_orphans)
++ printk(KERN_INFO "EXT4-fs: %s: %d orphan inode%s deleted\n",
++ sb->s_id, PLURAL(nr_orphans));
++ if (nr_truncates)
++ printk(KERN_INFO "EXT4-fs: %s: %d truncate%s cleaned up\n",
++ sb->s_id, PLURAL(nr_truncates));
++#ifdef CONFIG_QUOTA
++ /* Turn quotas off */
++ for (i = 0; i < MAXQUOTAS; i++) {
++ if (sb_dqopt(sb)->files[i])
++ vfs_quota_off(sb, i);
++ }
++#endif
++ sb->s_flags = s_flags; /* Restore MS_RDONLY status */
++}
++
++#define log2(n) ffz(~(n))
++
++/*
++ * Maximal file size. There is a direct, and {,double-,triple-}indirect
++ * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
++ * We need to be 1 filesystem block less than the 2^32 sector limit.
++ */
++static loff_t ext4_max_size(int bits)
++{
++ loff_t res = EXT4_NDIR_BLOCKS;
++ /* This constant is calculated to be the largest file size for a
++ * dense, 4k-blocksize file such that the total number of
++ * sectors in the file, including data and all indirect blocks,
++ * does not exceed 2^32. */
++ const loff_t upper_limit = 0x1ff7fffd000LL;
++
++ res += 1LL << (bits-2);
++ res += 1LL << (2*(bits-2));
++ res += 1LL << (3*(bits-2));
++ res <<= bits;
++ if (res > upper_limit)
++ res = upper_limit;
++ return res;
++}
++
++static ext4_fsblk_t descriptor_loc(struct super_block *sb,
++ ext4_fsblk_t logical_sb_block, int nr)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ unsigned long bg, first_meta_bg;
++ int has_super = 0;
++
++ first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
++
++ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
++ nr < first_meta_bg)
++ return logical_sb_block + nr + 1;
++ bg = sbi->s_desc_per_block * nr;
++ if (ext4_bg_has_super(sb, bg))
++ has_super = 1;
++ return (has_super + ext4_group_first_block_no(sb, bg));
++}
++
++
++static int ext4_fill_super (struct super_block *sb, void *data, int silent)
++{
++ struct buffer_head * bh;
++ struct ext4_super_block *es = NULL;
++ struct ext4_sb_info *sbi;
++ ext4_fsblk_t block;
++ ext4_fsblk_t sb_block = get_sb_block(&data);
++ ext4_fsblk_t logical_sb_block;
++ unsigned long offset = 0;
++ unsigned int journal_inum = 0;
++ unsigned long journal_devnum = 0;
++ unsigned long def_mount_opts;
++ struct inode *root;
++ int blocksize;
++ int hblock;
++ int db_count;
++ int i;
++ int needs_recovery;
++ __le32 features;
++ __u64 blocks_count;
++
++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
++ if (!sbi)
++ return -ENOMEM;
++ sb->s_fs_info = sbi;
++ sbi->s_mount_opt = 0;
++ sbi->s_resuid = EXT4_DEF_RESUID;
++ sbi->s_resgid = EXT4_DEF_RESGID;
++
++ unlock_kernel();
++
++ blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
++ if (!blocksize) {
++ printk(KERN_ERR "EXT4-fs: unable to set blocksize\n");
++ goto out_fail;
++ }
++
++ /*
++ * The ext4 superblock will not be buffer aligned for other than 1kB
++ * block sizes. We need to calculate the offset from buffer start.
++ */
++ if (blocksize != EXT4_MIN_BLOCK_SIZE) {
++ logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
++ offset = do_div(logical_sb_block, blocksize);
++ } else {
++ logical_sb_block = sb_block;
++ }
++
++ if (!(bh = sb_bread(sb, logical_sb_block))) {
++ printk (KERN_ERR "EXT4-fs: unable to read superblock\n");
++ goto out_fail;
++ }
++ /*
++ * Note: s_es must be initialized as soon as possible because
++ * some ext4 macro-instructions depend on its value
++ */
++ es = (struct ext4_super_block *) (((char *)bh->b_data) + offset);
++ sbi->s_es = es;
++ sb->s_magic = le16_to_cpu(es->s_magic);
++ if (sb->s_magic != EXT4_SUPER_MAGIC)
++ goto cantfind_ext4;
++
++ /* Set defaults before we parse the mount options */
++ def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
++ if (def_mount_opts & EXT4_DEFM_DEBUG)
++ set_opt(sbi->s_mount_opt, DEBUG);
++ if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
++ set_opt(sbi->s_mount_opt, GRPID);
++ if (def_mount_opts & EXT4_DEFM_UID16)
++ set_opt(sbi->s_mount_opt, NO_UID32);
++ if (def_mount_opts & EXT4_DEFM_XATTR_USER)
++ set_opt(sbi->s_mount_opt, XATTR_USER);
++ if (def_mount_opts & EXT4_DEFM_ACL)
++ set_opt(sbi->s_mount_opt, POSIX_ACL);
++ if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
++ sbi->s_mount_opt |= EXT4_MOUNT_JOURNAL_DATA;
++ else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
++ sbi->s_mount_opt |= EXT4_MOUNT_ORDERED_DATA;
++ else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK)
++ sbi->s_mount_opt |= EXT4_MOUNT_WRITEBACK_DATA;
++
++ if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC)
++ set_opt(sbi->s_mount_opt, ERRORS_PANIC);
++ else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_RO)
++ set_opt(sbi->s_mount_opt, ERRORS_RO);
++ else
++ set_opt(sbi->s_mount_opt, ERRORS_CONT);
++
++ sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
++ sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
++
++ set_opt(sbi->s_mount_opt, RESERVATION);
++
++ if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
++ NULL, 0))
++ goto failed_mount;
++
++ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
++ ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
++
++ if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
++ (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
++ EXT4_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
++ EXT4_HAS_INCOMPAT_FEATURE(sb, ~0U)))
++ printk(KERN_WARNING
++ "EXT4-fs warning: feature flags set on rev 0 fs, "
++ "running e2fsck is recommended\n");
++ /*
++ * Check feature flags regardless of the revision level, since we
++ * previously didn't change the revision level when setting the flags,
++ * so there is a chance incompat flags are set on a rev 0 filesystem.
++ */
++ features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
++ if (features) {
++ printk(KERN_ERR "EXT4-fs: %s: couldn't mount because of "
++ "unsupported optional features (%x).\n",
++ sb->s_id, le32_to_cpu(features));
++ goto failed_mount;
++ }
++ features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
++ if (!(sb->s_flags & MS_RDONLY) && features) {
++ printk(KERN_ERR "EXT4-fs: %s: couldn't mount RDWR because of "
++ "unsupported optional features (%x).\n",
++ sb->s_id, le32_to_cpu(features));
++ goto failed_mount;
++ }
++ blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
++
++ if (blocksize < EXT4_MIN_BLOCK_SIZE ||
++ blocksize > EXT4_MAX_BLOCK_SIZE) {
++ printk(KERN_ERR
++ "EXT4-fs: Unsupported filesystem blocksize %d on %s.\n",
++ blocksize, sb->s_id);
++ goto failed_mount;
++ }
++
++ hblock = bdev_hardsect_size(sb->s_bdev);
++ if (sb->s_blocksize != blocksize) {
++ /*
++ * Make sure the blocksize for the filesystem is larger
++ * than the hardware sectorsize for the machine.
++ */
++ if (blocksize < hblock) {
++ printk(KERN_ERR "EXT4-fs: blocksize %d too small for "
++ "device blocksize %d.\n", blocksize, hblock);
++ goto failed_mount;
++ }
++
++ brelse (bh);
++ sb_set_blocksize(sb, blocksize);
++ logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
++ offset = do_div(logical_sb_block, blocksize);
++ bh = sb_bread(sb, logical_sb_block);
++ if (!bh) {
++ printk(KERN_ERR
++ "EXT4-fs: Can't read superblock on 2nd try.\n");
++ goto failed_mount;
++ }
++ es = (struct ext4_super_block *)(((char *)bh->b_data) + offset);
++ sbi->s_es = es;
++ if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
++ printk (KERN_ERR
++ "EXT4-fs: Magic mismatch, very weird !\n");
++ goto failed_mount;
++ }
++ }
++
++ sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
++
++ if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
++ sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE;
++ sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
++ } else {
++ sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
++ sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
++ if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
++ (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
++ (sbi->s_inode_size > blocksize)) {
++ printk (KERN_ERR
++ "EXT4-fs: unsupported inode size: %d\n",
++ sbi->s_inode_size);
++ goto failed_mount;
++ }
++ }
++ sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
++ le32_to_cpu(es->s_log_frag_size);
++ if (blocksize != sbi->s_frag_size) {
++ printk(KERN_ERR
++ "EXT4-fs: fragsize %lu != blocksize %u (unsupported)\n",
++ sbi->s_frag_size, blocksize);
++ goto failed_mount;
++ }
++ sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
++ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
++ if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
++ sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
++ sbi->s_desc_size & (sbi->s_desc_size - 1)) {
++ printk(KERN_ERR
++ "EXT4-fs: unsupported descriptor size %lu\n",
++ sbi->s_desc_size);
++ goto failed_mount;
++ }
++ } else
++ sbi->s_desc_size = EXT4_MIN_DESC_SIZE;
++ sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
++ sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
++ sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
++ if (EXT4_INODE_SIZE(sb) == 0)
++ goto cantfind_ext4;
++ sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb);
++ if (sbi->s_inodes_per_block == 0)
++ goto cantfind_ext4;
++ sbi->s_itb_per_group = sbi->s_inodes_per_group /
++ sbi->s_inodes_per_block;
++ sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb);
++ sbi->s_sbh = bh;
++ sbi->s_mount_state = le16_to_cpu(es->s_state);
++ sbi->s_addr_per_block_bits = log2(EXT4_ADDR_PER_BLOCK(sb));
++ sbi->s_desc_per_block_bits = log2(EXT4_DESC_PER_BLOCK(sb));
++ for (i=0; i < 4; i++)
++ sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
++ sbi->s_def_hash_version = es->s_def_hash_version;
++
++ if (sbi->s_blocks_per_group > blocksize * 8) {
++ printk (KERN_ERR
++ "EXT4-fs: #blocks per group too big: %lu\n",
++ sbi->s_blocks_per_group);
++ goto failed_mount;
++ }
++ if (sbi->s_frags_per_group > blocksize * 8) {
++ printk (KERN_ERR
++ "EXT4-fs: #fragments per group too big: %lu\n",
++ sbi->s_frags_per_group);
++ goto failed_mount;
++ }
++ if (sbi->s_inodes_per_group > blocksize * 8) {
++ printk (KERN_ERR
++ "EXT4-fs: #inodes per group too big: %lu\n",
++ sbi->s_inodes_per_group);
++ goto failed_mount;
++ }
++
++ if (ext4_blocks_count(es) >
++ (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
++ printk(KERN_ERR "EXT4-fs: filesystem on %s:"
++ " too large to mount safely\n", sb->s_id);
++ if (sizeof(sector_t) < 8)
++ printk(KERN_WARNING "EXT4-fs: CONFIG_LBD not "
++ "enabled\n");
++ goto failed_mount;
++ }
++
++ if (EXT4_BLOCKS_PER_GROUP(sb) == 0)
++ goto cantfind_ext4;
++ blocks_count = (ext4_blocks_count(es) -
++ le32_to_cpu(es->s_first_data_block) +
++ EXT4_BLOCKS_PER_GROUP(sb) - 1);
++ do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
++ sbi->s_groups_count = blocks_count;
++ db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
++ EXT4_DESC_PER_BLOCK(sb);
++ sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
++ GFP_KERNEL);
++ if (sbi->s_group_desc == NULL) {
++ printk (KERN_ERR "EXT4-fs: not enough memory\n");
++ goto failed_mount;
++ }
++
++ bgl_lock_init(&sbi->s_blockgroup_lock);
++
++ for (i = 0; i < db_count; i++) {
++ block = descriptor_loc(sb, logical_sb_block, i);
++ sbi->s_group_desc[i] = sb_bread(sb, block);
++ if (!sbi->s_group_desc[i]) {
++ printk (KERN_ERR "EXT4-fs: "
++ "can't read group descriptor %d\n", i);
++ db_count = i;
++ goto failed_mount2;
++ }
++ }
++ if (!ext4_check_descriptors (sb)) {
++ printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n");
++ goto failed_mount2;
++ }
++ sbi->s_gdb_count = db_count;
++ get_random_bytes(&sbi->s_next_generation, sizeof(u32));
++ spin_lock_init(&sbi->s_next_gen_lock);
++
++ percpu_counter_init(&sbi->s_freeblocks_counter,
++ ext4_count_free_blocks(sb));
++ percpu_counter_init(&sbi->s_freeinodes_counter,
++ ext4_count_free_inodes(sb));
++ percpu_counter_init(&sbi->s_dirs_counter,
++ ext4_count_dirs(sb));
++
++ /* per fileystem reservation list head & lock */
++ spin_lock_init(&sbi->s_rsv_window_lock);
++ sbi->s_rsv_window_root = RB_ROOT;
++ /* Add a single, static dummy reservation to the start of the
++ * reservation window list --- it gives us a placeholder for
++ * append-at-start-of-list which makes the allocation logic
++ * _much_ simpler. */
++ sbi->s_rsv_window_head.rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++ sbi->s_rsv_window_head.rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
++ sbi->s_rsv_window_head.rsv_alloc_hit = 0;
++ sbi->s_rsv_window_head.rsv_goal_size = 0;
++ ext4_rsv_window_add(sb, &sbi->s_rsv_window_head);
++
++ /*
++ * set up enough so that it can read an inode
++ */
++ sb->s_op = &ext4_sops;
++ sb->s_export_op = &ext4_export_ops;
++ sb->s_xattr = ext4_xattr_handlers;
++#ifdef CONFIG_QUOTA
++ sb->s_qcop = &ext4_qctl_operations;
++ sb->dq_op = &ext4_quota_operations;
++#endif
++ INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
++
++ sb->s_root = NULL;
++
++ needs_recovery = (es->s_last_orphan != 0 ||
++ EXT4_HAS_INCOMPAT_FEATURE(sb,
++ EXT4_FEATURE_INCOMPAT_RECOVER));
++
++ /*
++ * The first inode we look at is the journal inode. Don't try
++ * root first: it may be modified in the journal!
++ */
++ if (!test_opt(sb, NOLOAD) &&
++ EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
++ if (ext4_load_journal(sb, es, journal_devnum))
++ goto failed_mount3;
++ } else if (journal_inum) {
++ if (ext4_create_journal(sb, es, journal_inum))
++ goto failed_mount3;
++ } else {
++ if (!silent)
++ printk (KERN_ERR
++ "ext4: No journal on filesystem on %s\n",
++ sb->s_id);
++ goto failed_mount3;
++ }
++
++ /* We have now updated the journal if required, so we can
++ * validate the data journaling mode. */
++ switch (test_opt(sb, DATA_FLAGS)) {
++ case 0:
++ /* No mode set, assume a default based on the journal
++ * capabilities: ORDERED_DATA if the journal can
++ * cope, else JOURNAL_DATA
++ */
++ if (jbd2_journal_check_available_features
++ (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE))
++ set_opt(sbi->s_mount_opt, ORDERED_DATA);
++ else
++ set_opt(sbi->s_mount_opt, JOURNAL_DATA);
++ break;
++
++ case EXT4_MOUNT_ORDERED_DATA:
++ case EXT4_MOUNT_WRITEBACK_DATA:
++ if (!jbd2_journal_check_available_features
++ (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
++ printk(KERN_ERR "EXT4-fs: Journal does not support "
++ "requested data journaling mode\n");
++ goto failed_mount4;
++ }
++ default:
++ break;
++ }
++
++ if (test_opt(sb, NOBH)) {
++ if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
++ printk(KERN_WARNING "EXT4-fs: Ignoring nobh option - "
++ "its supported only with writeback mode\n");
++ clear_opt(sbi->s_mount_opt, NOBH);
++ }
++ }
++ /*
++ * The jbd2_journal_load will have done any necessary log recovery,
++ * so we can safely mount the rest of the filesystem now.
++ */
++
++ root = iget(sb, EXT4_ROOT_INO);
++ sb->s_root = d_alloc_root(root);
++ if (!sb->s_root) {
++ printk(KERN_ERR "EXT4-fs: get root inode failed\n");
++ iput(root);
++ goto failed_mount4;
++ }
++ if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
++ dput(sb->s_root);
++ sb->s_root = NULL;
++ printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
++ goto failed_mount4;
++ }
++
++ ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
++ /*
++ * akpm: core read_super() calls in here with the superblock locked.
++ * That deadlocks, because orphan cleanup needs to lock the superblock
++ * in numerous places. Here we just pop the lock - it's relatively
++ * harmless, because we are now ready to accept write_super() requests,
++ * and aviro says that's the only reason for hanging onto the
++ * superblock lock.
++ */
++ EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS;
++ ext4_orphan_cleanup(sb, es);
++ EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS;
++ if (needs_recovery)
++ printk (KERN_INFO "EXT4-fs: recovery complete.\n");
++ ext4_mark_recovery_complete(sb, es);
++ printk (KERN_INFO "EXT4-fs: mounted filesystem with %s data mode.\n",
++ test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ? "journal":
++ test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered":
++ "writeback");
++
++ ext4_ext_init(sb);
++
++ lock_kernel();
++ return 0;
++
++cantfind_ext4:
++ if (!silent)
++ printk(KERN_ERR "VFS: Can't find ext4 filesystem on dev %s.\n",
++ sb->s_id);
++ goto failed_mount;
++
++failed_mount4:
++ jbd2_journal_destroy(sbi->s_journal);
++failed_mount3:
++ percpu_counter_destroy(&sbi->s_freeblocks_counter);
++ percpu_counter_destroy(&sbi->s_freeinodes_counter);
++ percpu_counter_destroy(&sbi->s_dirs_counter);
++failed_mount2:
++ for (i = 0; i < db_count; i++)
++ brelse(sbi->s_group_desc[i]);
++ kfree(sbi->s_group_desc);
++failed_mount:
++#ifdef CONFIG_QUOTA
++ for (i = 0; i < MAXQUOTAS; i++)
++ kfree(sbi->s_qf_names[i]);
++#endif
++ ext4_blkdev_remove(sbi);
++ brelse(bh);
++out_fail:
++ sb->s_fs_info = NULL;
++ kfree(sbi);
++ lock_kernel();
++ return -EINVAL;
++}
++
++/*
++ * Setup any per-fs journal parameters now. We'll do this both on
++ * initial mount, once the journal has been initialised but before we've
++ * done any recovery; and again on any subsequent remount.
++ */
++static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++
++ if (sbi->s_commit_interval)
++ journal->j_commit_interval = sbi->s_commit_interval;
++ /* We could also set up an ext4-specific default for the commit
++ * interval here, but for now we'll just fall back to the jbd
++ * default. */
++
++ spin_lock(&journal->j_state_lock);
++ if (test_opt(sb, BARRIER))
++ journal->j_flags |= JBD2_BARRIER;
++ else
++ journal->j_flags &= ~JBD2_BARRIER;
++ spin_unlock(&journal->j_state_lock);
++}
++
++static journal_t *ext4_get_journal(struct super_block *sb,
++ unsigned int journal_inum)
++{
++ struct inode *journal_inode;
++ journal_t *journal;
++
++ /* First, test for the existence of a valid inode on disk. Bad
++ * things happen if we iget() an unused inode, as the subsequent
++ * iput() will try to delete it. */
++
++ journal_inode = iget(sb, journal_inum);
++ if (!journal_inode) {
++ printk(KERN_ERR "EXT4-fs: no journal found.\n");
++ return NULL;
++ }
++ if (!journal_inode->i_nlink) {
++ make_bad_inode(journal_inode);
++ iput(journal_inode);
++ printk(KERN_ERR "EXT4-fs: journal inode is deleted.\n");
++ return NULL;
++ }
++
++ jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
++ journal_inode, journal_inode->i_size);
++ if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
++ printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
++ iput(journal_inode);
++ return NULL;
++ }
++
++ journal = jbd2_journal_init_inode(journal_inode);
++ if (!journal) {
++ printk(KERN_ERR "EXT4-fs: Could not load journal inode\n");
++ iput(journal_inode);
++ return NULL;
++ }
++ journal->j_private = sb;
++ ext4_init_journal_params(sb, journal);
++ return journal;
++}
++
++static journal_t *ext4_get_dev_journal(struct super_block *sb,
++ dev_t j_dev)
++{
++ struct buffer_head * bh;
++ journal_t *journal;
++ ext4_fsblk_t start;
++ ext4_fsblk_t len;
++ int hblock, blocksize;
++ ext4_fsblk_t sb_block;
++ unsigned long offset;
++ struct ext4_super_block * es;
++ struct block_device *bdev;
++
++ bdev = ext4_blkdev_get(j_dev);
++ if (bdev == NULL)
++ return NULL;
++
++ if (bd_claim(bdev, sb)) {
++ printk(KERN_ERR
++ "EXT4: failed to claim external journal device.\n");
++ blkdev_put(bdev);
++ return NULL;
++ }
++
++ blocksize = sb->s_blocksize;
++ hblock = bdev_hardsect_size(bdev);
++ if (blocksize < hblock) {
++ printk(KERN_ERR
++ "EXT4-fs: blocksize too small for journal device.\n");
++ goto out_bdev;
++ }
++
++ sb_block = EXT4_MIN_BLOCK_SIZE / blocksize;
++ offset = EXT4_MIN_BLOCK_SIZE % blocksize;
++ set_blocksize(bdev, blocksize);
++ if (!(bh = __bread(bdev, sb_block, blocksize))) {
++ printk(KERN_ERR "EXT4-fs: couldn't read superblock of "
++ "external journal\n");
++ goto out_bdev;
++ }
++
++ es = (struct ext4_super_block *) (((char *)bh->b_data) + offset);
++ if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) ||
++ !(le32_to_cpu(es->s_feature_incompat) &
++ EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) {
++ printk(KERN_ERR "EXT4-fs: external journal has "
++ "bad superblock\n");
++ brelse(bh);
++ goto out_bdev;
++ }
++
++ if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) {
++ printk(KERN_ERR "EXT4-fs: journal UUID does not match\n");
++ brelse(bh);
++ goto out_bdev;
++ }
++
++ len = ext4_blocks_count(es);
++ start = sb_block + 1;
++ brelse(bh); /* we're done with the superblock */
++
++ journal = jbd2_journal_init_dev(bdev, sb->s_bdev,
++ start, len, blocksize);
++ if (!journal) {
++ printk(KERN_ERR "EXT4-fs: failed to create device journal\n");
++ goto out_bdev;
++ }
++ journal->j_private = sb;
++ ll_rw_block(READ, 1, &journal->j_sb_buffer);
++ wait_on_buffer(journal->j_sb_buffer);
++ if (!buffer_uptodate(journal->j_sb_buffer)) {
++ printk(KERN_ERR "EXT4-fs: I/O error on journal device\n");
++ goto out_journal;
++ }
++ if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) {
++ printk(KERN_ERR "EXT4-fs: External journal has more than one "
++ "user (unsupported) - %d\n",
++ be32_to_cpu(journal->j_superblock->s_nr_users));
++ goto out_journal;
++ }
++ EXT4_SB(sb)->journal_bdev = bdev;
++ ext4_init_journal_params(sb, journal);
++ return journal;
++out_journal:
++ jbd2_journal_destroy(journal);
++out_bdev:
++ ext4_blkdev_put(bdev);
++ return NULL;
++}
++
++static int ext4_load_journal(struct super_block *sb,
++ struct ext4_super_block *es,
++ unsigned long journal_devnum)
++{
++ journal_t *journal;
++ unsigned int journal_inum = le32_to_cpu(es->s_journal_inum);
++ dev_t journal_dev;
++ int err = 0;
++ int really_read_only;
++
++ if (journal_devnum &&
++ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
++ printk(KERN_INFO "EXT4-fs: external journal device major/minor "
++ "numbers have changed\n");
++ journal_dev = new_decode_dev(journal_devnum);
++ } else
++ journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
++
++ really_read_only = bdev_read_only(sb->s_bdev);
++
++ /*
++ * Are we loading a blank journal or performing recovery after a
++ * crash? For recovery, we need to check in advance whether we
++ * can get read-write access to the device.
++ */
++
++ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
++ if (sb->s_flags & MS_RDONLY) {
++ printk(KERN_INFO "EXT4-fs: INFO: recovery "
++ "required on readonly filesystem.\n");
++ if (really_read_only) {
++ printk(KERN_ERR "EXT4-fs: write access "
++ "unavailable, cannot proceed.\n");
++ return -EROFS;
++ }
++ printk (KERN_INFO "EXT4-fs: write access will "
++ "be enabled during recovery.\n");
++ }
++ }
++
++ if (journal_inum && journal_dev) {
++ printk(KERN_ERR "EXT4-fs: filesystem has both journal "
++ "and inode journals!\n");
++ return -EINVAL;
++ }
++
++ if (journal_inum) {
++ if (!(journal = ext4_get_journal(sb, journal_inum)))
++ return -EINVAL;
++ } else {
++ if (!(journal = ext4_get_dev_journal(sb, journal_dev)))
++ return -EINVAL;
++ }
++
++ if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
++ err = jbd2_journal_update_format(journal);
++ if (err) {
++ printk(KERN_ERR "EXT4-fs: error updating journal.\n");
++ jbd2_journal_destroy(journal);
++ return err;
++ }
++ }
++
++ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
++ err = jbd2_journal_wipe(journal, !really_read_only);
++ if (!err)
++ err = jbd2_journal_load(journal);
++
++ if (err) {
++ printk(KERN_ERR "EXT4-fs: error loading journal.\n");
++ jbd2_journal_destroy(journal);
++ return err;
++ }
++
++ EXT4_SB(sb)->s_journal = journal;
++ ext4_clear_journal_err(sb, es);
++
++ if (journal_devnum &&
++ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
++ es->s_journal_dev = cpu_to_le32(journal_devnum);
++ sb->s_dirt = 1;
++
++ /* Make sure we flush the recovery flag to disk. */
++ ext4_commit_super(sb, es, 1);
++ }
++
++ return 0;
++}
++
++static int ext4_create_journal(struct super_block * sb,
++ struct ext4_super_block * es,
++ unsigned int journal_inum)
++{
++ journal_t *journal;
++
++ if (sb->s_flags & MS_RDONLY) {
++ printk(KERN_ERR "EXT4-fs: readonly filesystem when trying to "
++ "create journal.\n");
++ return -EROFS;
++ }
++
++ if (!(journal = ext4_get_journal(sb, journal_inum)))
++ return -EINVAL;
++
++ printk(KERN_INFO "EXT4-fs: creating new journal on inode %u\n",
++ journal_inum);
++
++ if (jbd2_journal_create(journal)) {
++ printk(KERN_ERR "EXT4-fs: error creating journal.\n");
++ jbd2_journal_destroy(journal);
++ return -EIO;
++ }
++
++ EXT4_SB(sb)->s_journal = journal;
++
++ ext4_update_dynamic_rev(sb);
++ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
++ EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL);
++
++ es->s_journal_inum = cpu_to_le32(journal_inum);
++ sb->s_dirt = 1;
++
++ /* Make sure we flush the recovery flag to disk. */
++ ext4_commit_super(sb, es, 1);
++
++ return 0;
++}
++
++static void ext4_commit_super (struct super_block * sb,
++ struct ext4_super_block * es,
++ int sync)
++{
++ struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
++
++ if (!sbh)
++ return;
++ es->s_wtime = cpu_to_le32(get_seconds());
++ ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb));
++ es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
++ BUFFER_TRACE(sbh, "marking dirty");
++ mark_buffer_dirty(sbh);
++ if (sync)
++ sync_dirty_buffer(sbh);
++}
++
++
++/*
++ * Have we just finished recovery? If so, and if we are mounting (or
++ * remounting) the filesystem readonly, then we will end up with a
++ * consistent fs on disk. Record that fact.
++ */
++static void ext4_mark_recovery_complete(struct super_block * sb,
++ struct ext4_super_block * es)
++{
++ journal_t *journal = EXT4_SB(sb)->s_journal;
++
++ jbd2_journal_lock_updates(journal);
++ jbd2_journal_flush(journal);
++ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
++ sb->s_flags & MS_RDONLY) {
++ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
++ sb->s_dirt = 0;
++ ext4_commit_super(sb, es, 1);
++ }
++ jbd2_journal_unlock_updates(journal);
++}
++
++/*
++ * If we are mounting (or read-write remounting) a filesystem whose journal
++ * has recorded an error from a previous lifetime, move that error to the
++ * main filesystem now.
++ */
++static void ext4_clear_journal_err(struct super_block * sb,
++ struct ext4_super_block * es)
++{
++ journal_t *journal;
++ int j_errno;
++ const char *errstr;
++
++ journal = EXT4_SB(sb)->s_journal;
++
++ /*
++ * Now check for any error status which may have been recorded in the
++ * journal by a prior ext4_error() or ext4_abort()
++ */
++
++ j_errno = jbd2_journal_errno(journal);
++ if (j_errno) {
++ char nbuf[16];
++
++ errstr = ext4_decode_error(sb, j_errno, nbuf);
++ ext4_warning(sb, __FUNCTION__, "Filesystem error recorded "
++ "from previous mount: %s", errstr);
++ ext4_warning(sb, __FUNCTION__, "Marking fs in need of "
++ "filesystem check.");
++
++ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
++ es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
++ ext4_commit_super (sb, es, 1);
++
++ jbd2_journal_clear_err(journal);
++ }
++}
++
++/*
++ * Force the running and committing transactions to commit,
++ * and wait on the commit.
++ */
++int ext4_force_commit(struct super_block *sb)
++{
++ journal_t *journal;
++ int ret;
++
++ if (sb->s_flags & MS_RDONLY)
++ return 0;
++
++ journal = EXT4_SB(sb)->s_journal;
++ sb->s_dirt = 0;
++ ret = ext4_journal_force_commit(journal);
++ return ret;
++}
++
++/*
++ * Ext4 always journals updates to the superblock itself, so we don't
++ * have to propagate any other updates to the superblock on disk at this
++ * point. Just start an async writeback to get the buffers on their way
++ * to the disk.
++ *
++ * This implicitly triggers the writebehind on sync().
++ */
++
++static void ext4_write_super (struct super_block * sb)
++{
++ if (mutex_trylock(&sb->s_lock) != 0)
++ BUG();
++ sb->s_dirt = 0;
++}
++
++static int ext4_sync_fs(struct super_block *sb, int wait)
++{
++ tid_t target;
++
++ sb->s_dirt = 0;
++ if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
++ if (wait)
++ jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target);
++ }
++ return 0;
++}
++
++/*
++ * LVM calls this function before a (read-only) snapshot is created. This
++ * gives us a chance to flush the journal completely and mark the fs clean.
++ */
++static void ext4_write_super_lockfs(struct super_block *sb)
++{
++ sb->s_dirt = 0;
++
++ if (!(sb->s_flags & MS_RDONLY)) {
++ journal_t *journal = EXT4_SB(sb)->s_journal;
++
++ /* Now we set up the journal barrier. */
++ jbd2_journal_lock_updates(journal);
++ jbd2_journal_flush(journal);
++
++ /* Journal blocked and flushed, clear needs_recovery flag. */
++ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
++ ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
++ }
++}
++
++/*
++ * Called by LVM after the snapshot is done. We need to reset the RECOVER
++ * flag here, even though the filesystem is not technically dirty yet.
++ */
++static void ext4_unlockfs(struct super_block *sb)
++{
++ if (!(sb->s_flags & MS_RDONLY)) {
++ lock_super(sb);
++ /* Reser the needs_recovery flag before the fs is unlocked. */
++ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
++ ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
++ unlock_super(sb);
++ jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
++ }
++}
++
++static int ext4_remount (struct super_block * sb, int * flags, char * data)
++{
++ struct ext4_super_block * es;
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ ext4_fsblk_t n_blocks_count = 0;
++ unsigned long old_sb_flags;
++ struct ext4_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, NULL, NULL, &n_blocks_count, 1)) {
++ err = -EINVAL;
++ goto restore_opts;
++ }
++
++ if (sbi->s_mount_opt & EXT4_MOUNT_ABORT)
++ ext4_abort(sb, __FUNCTION__, "Abort forced by user");
++
++ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
++ ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
++
++ es = sbi->s_es;
++
++ ext4_init_journal_params(sb, sbi->s_journal);
++
++ if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
++ n_blocks_count > ext4_blocks_count(es)) {
++ if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) {
++ err = -EROFS;
++ goto restore_opts;
++ }
++
++ if (*flags & MS_RDONLY) {
++ /*
++ * First of all, the unconditional stuff we have to do
++ * to disable replay of the journal when we next remount
++ */
++ sb->s_flags |= MS_RDONLY;
++
++ /*
++ * OK, test if we are remounting a valid rw partition
++ * readonly, and if so set the rdonly flag and then
++ * mark the partition as valid again.
++ */
++ if (!(es->s_state & cpu_to_le16(EXT4_VALID_FS)) &&
++ (sbi->s_mount_state & EXT4_VALID_FS))
++ es->s_state = cpu_to_le16(sbi->s_mount_state);
++
++ ext4_mark_recovery_complete(sb, es);
++ } else {
++ __le32 ret;
++ if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ ~EXT4_FEATURE_RO_COMPAT_SUPP))) {
++ printk(KERN_WARNING "EXT4-fs: %s: couldn't "
++ "remount RDWR because of unsupported "
++ "optional features (%x).\n",
++ sb->s_id, le32_to_cpu(ret));
++ err = -EROFS;
++ goto restore_opts;
++ }
++ /*
++ * Mounting a RDONLY partition read-write, so reread
++ * and store the current valid flag. (It may have
++ * been changed by e2fsck since we originally mounted
++ * the partition.)
++ */
++ ext4_clear_journal_err(sb, es);
++ sbi->s_mount_state = le16_to_cpu(es->s_state);
++ if ((err = ext4_group_extend(sb, es, n_blocks_count)))
++ goto restore_opts;
++ if (!ext4_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 ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
++{
++ struct super_block *sb = dentry->d_sb;
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ struct ext4_super_block *es = sbi->s_es;
++ ext4_fsblk_t overhead;
++ int i;
++
++ if (test_opt (sb, MINIX_DF))
++ overhead = 0;
++ else {
++ unsigned long ngroups;
++ ngroups = EXT4_SB(sb)->s_groups_count;
++ smp_rmb();
++
++ /*
++ * Compute the overhead (FS structures)
++ */
++
++ /*
++ * All of the blocks before first_data_block are
++ * overhead
++ */
++ overhead = le32_to_cpu(es->s_first_data_block);
++
++ /*
++ * Add the overhead attributed to the superblock and
++ * block group descriptors. If the sparse superblocks
++ * feature is turned on, then not all groups have this.
++ */
++ for (i = 0; i < ngroups; i++) {
++ overhead += ext4_bg_has_super(sb, i) +
++ ext4_bg_num_gdb(sb, i);
++ cond_resched();
++ }
++
++ /*
++ * Every block group has an inode bitmap, a block
++ * bitmap, and an inode table.
++ */
++ overhead += (ngroups * (2 + EXT4_SB(sb)->s_itb_per_group));
++ }
++
++ buf->f_type = EXT4_SUPER_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_blocks = ext4_blocks_count(es) - overhead;
++ buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
++ buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
++ if (buf->f_bfree < ext4_r_blocks_count(es))
++ buf->f_bavail = 0;
++ buf->f_files = le32_to_cpu(es->s_inodes_count);
++ buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
++ buf->f_namelen = EXT4_NAME_LEN;
++ return 0;
++}
++
++/* Helper function for writing quotas on sync - we need to start transaction before quota file
++ * is locked for write. Otherwise the are possible deadlocks:
++ * Process 1 Process 2
++ * ext4_create() quota_sync()
++ * jbd2_journal_start() write_dquot()
++ * DQUOT_INIT() down(dqio_mutex)
++ * down(dqio_mutex) jbd2_journal_start()
++ *
++ */
++
++#ifdef CONFIG_QUOTA
++
++static inline struct inode *dquot_to_inode(struct dquot *dquot)
++{
++ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
++}
++
++static int ext4_dquot_initialize(struct inode *inode, int type)
++{
++ handle_t *handle;
++ int ret, err;
++
++ /* We may create quota structure so we need to reserve enough blocks */
++ handle = ext4_journal_start(inode, 2*EXT4_QUOTA_INIT_BLOCKS(inode->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ ret = dquot_initialize(inode, type);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++static int ext4_dquot_drop(struct inode *inode)
++{
++ handle_t *handle;
++ int ret, err;
++
++ /* We may delete quota structure so we need to reserve enough blocks */
++ handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ ret = dquot_drop(inode);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++static int ext4_write_dquot(struct dquot *dquot)
++{
++ int ret, err;
++ handle_t *handle;
++ struct inode *inode;
++
++ inode = dquot_to_inode(dquot);
++ handle = ext4_journal_start(inode,
++ EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ ret = dquot_commit(dquot);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++static int ext4_acquire_dquot(struct dquot *dquot)
++{
++ int ret, err;
++ handle_t *handle;
++
++ handle = ext4_journal_start(dquot_to_inode(dquot),
++ EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ ret = dquot_acquire(dquot);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++static int ext4_release_dquot(struct dquot *dquot)
++{
++ int ret, err;
++ handle_t *handle;
++
++ handle = ext4_journal_start(dquot_to_inode(dquot),
++ EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ ret = dquot_release(dquot);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++static int ext4_mark_dquot_dirty(struct dquot *dquot)
++{
++ /* Are we journalling quotas? */
++ if (EXT4_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
++ EXT4_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
++ dquot_mark_dquot_dirty(dquot);
++ return ext4_write_dquot(dquot);
++ } else {
++ return dquot_mark_dquot_dirty(dquot);
++ }
++}
++
++static int ext4_write_info(struct super_block *sb, int type)
++{
++ int ret, err;
++ handle_t *handle;
++
++ /* Data block + inode block */
++ handle = ext4_journal_start(sb->s_root->d_inode, 2);
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++ ret = dquot_commit_info(sb, type);
++ err = ext4_journal_stop(handle);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++/*
++ * Turn on quotas during mount time - we need to find
++ * the quota file and such...
++ */
++static int ext4_quota_on_mount(struct super_block *sb, int type)
++{
++ return vfs_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
++ EXT4_SB(sb)->s_jquota_fmt, type);
++}
++
++/*
++ * Standard function to be called on quota_on
++ */
++static int ext4_quota_on(struct super_block *sb, int type, int format_id,
++ char *path)
++{
++ int err;
++ struct nameidata nd;
++
++ if (!test_opt(sb, QUOTA))
++ return -EINVAL;
++ /* Not journalling quota? */
++ if (!EXT4_SB(sb)->s_qf_names[USRQUOTA] &&
++ !EXT4_SB(sb)->s_qf_names[GRPQUOTA])
++ return vfs_quota_on(sb, type, format_id, path);
++ 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;
++ }
++ /* Quotafile not of fs root? */
++ if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
++ printk(KERN_WARNING
++ "EXT4-fs: Quota file not on filesystem root. "
++ "Journalled quota will not work.\n");
++ path_release(&nd);
++ return vfs_quota_on(sb, type, format_id, path);
++}
++
++/* Read data from quotafile - avoid pagecache and such because we cannot afford
++ * acquiring the locks... As quota files are never truncated and quota code
++ * itself serializes the operations (and noone else should touch the files)
++ * we don't have to be afraid of races */
++static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
++ size_t len, loff_t off)
++{
++ struct inode *inode = sb_dqopt(sb)->files[type];
++ sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
++ int err = 0;
++ int offset = off & (sb->s_blocksize - 1);
++ int tocopy;
++ size_t toread;
++ struct buffer_head *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;
++ bh = ext4_bread(NULL, inode, blk, 0, &err);
++ if (err)
++ return err;
++ if (!bh) /* A hole? */
++ memset(data, 0, tocopy);
++ else
++ 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
++ * enough credits) */
++static ssize_t ext4_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];
++ sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
++ int err = 0;
++ int offset = off & (sb->s_blocksize - 1);
++ int tocopy;
++ int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
++ size_t towrite = len;
++ struct buffer_head *bh;
++ handle_t *handle = journal_current_handle();
++
++ mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
++ while (towrite > 0) {
++ tocopy = sb->s_blocksize - offset < towrite ?
++ sb->s_blocksize - offset : towrite;
++ bh = ext4_bread(handle, inode, blk, 1, &err);
++ if (!bh)
++ goto out;
++ if (journal_quota) {
++ err = ext4_journal_get_write_access(handle, bh);
++ if (err) {
++ brelse(bh);
++ goto out;
++ }
++ }
++ lock_buffer(bh);
++ memcpy(bh->b_data+offset, data, tocopy);
++ flush_dcache_page(bh->b_page);
++ unlock_buffer(bh);
++ if (journal_quota)
++ err = ext4_journal_dirty_metadata(handle, bh);
++ else {
++ /* Always do at least ordered writes for quotas */
++ err = ext4_journal_dirty_data(handle, bh);
++ mark_buffer_dirty(bh);
++ }
++ brelse(bh);
++ if (err)
++ goto out;
++ 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);
++ EXT4_I(inode)->i_disksize = inode->i_size;
++ }
++ inode->i_version++;
++ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
++ ext4_mark_inode_dirty(handle, inode);
++ mutex_unlock(&inode->i_mutex);
++ return len - towrite;
++}
++
++#endif
++
++static int ext4_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
++{
++ return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
++}
++
++static struct file_system_type ext4dev_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "ext4dev",
++ .get_sb = ext4_get_sb,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++
++static int __init init_ext4_fs(void)
++{
++ int err = init_ext4_xattr();
++ if (err)
++ return err;
++ err = init_inodecache();
++ if (err)
++ goto out1;
++ err = register_filesystem(&ext4dev_fs_type);
++ if (err)
++ goto out;
++ return 0;
++out:
++ destroy_inodecache();
++out1:
++ exit_ext4_xattr();
++ return err;
++}
++
++static void __exit exit_ext4_fs(void)
++{
++ unregister_filesystem(&ext4dev_fs_type);
++ destroy_inodecache();
++ exit_ext4_xattr();
++}
++
++MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
++MODULE_DESCRIPTION("Fourth Extended Filesystem with extents");
++MODULE_LICENSE("GPL");
++module_init(init_ext4_fs)
++module_exit(exit_ext4_fs)
+diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
+new file mode 100644
+index 0000000..fcf5272
+--- /dev/null
++++ b/fs/ext4/symlink.c
+@@ -0,0 +1,54 @@
++/*
++ * linux/fs/ext4/symlink.c
++ *
++ * Only fast symlinks left here - the rest is done by generic code. AV, 1999
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/symlink.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * ext4 symlink handling code
++ */
++
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/namei.h>
++#include "xattr.h"
++
++static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
++ nd_set_link(nd, (char*)ei->i_data);
++ return NULL;
++}
++
++struct inode_operations ext4_symlink_inode_operations = {
++ .readlink = generic_readlink,
++ .follow_link = page_follow_link_light,
++ .put_link = page_put_link,
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = ext4_listxattr,
++ .removexattr = generic_removexattr,
++#endif
++};
++
++struct inode_operations ext4_fast_symlink_inode_operations = {
++ .readlink = generic_readlink,
++ .follow_link = ext4_follow_link,
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = ext4_listxattr,
++ .removexattr = generic_removexattr,
++#endif
++};
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+new file mode 100644
+index 0000000..63233cd
+--- /dev/null
++++ b/fs/ext4/xattr.c
+@@ -0,0 +1,1317 @@
++/*
++ * linux/fs/ext4/xattr.c
++ *
++ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen at suse.de>
++ *
++ * Fix by Harrison Xing <harrison at mountainviewdata.com>.
++ * Ext4 code with a lot of help from Eric Jarman <ejarman at acm.org>.
++ * Extended attributes for symlinks and special files added per
++ * suggestion of Luka Renko <luka.renko at hermes.si>.
++ * xattr consolidation Copyright (c) 2004 James Morris <jmorris at redhat.com>,
++ * Red Hat Inc.
++ * ea-in-inode support by Alex Tomas <alex at clusterfs.com> aka bzzz
++ * and Andreas Gruenbacher <agruen at suse.de>.
++ */
++
++/*
++ * Extended attributes are stored directly in inodes (on file systems with
++ * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl
++ * field contains the block number if an inode uses an additional block. All
++ * attributes must fit in the inode and one additional block. Blocks that
++ * contain the identical set of attributes may be shared among several inodes.
++ * Identical blocks are detected by keeping a cache of blocks that have
++ * recently been accessed.
++ *
++ * The attributes in inodes and on blocks have a different header; the entries
++ * are stored in the same format:
++ *
++ * +------------------+
++ * | header |
++ * | entry 1 | |
++ * | entry 2 | | growing downwards
++ * | entry 3 | v
++ * | four null bytes |
++ * | . . . |
++ * | value 1 | ^
++ * | value 3 | | growing upwards
++ * | value 2 | |
++ * +------------------+
++ *
++ * The header is followed by multiple entry descriptors. In disk blocks, the
++ * entry descriptors are kept sorted. In inodes, they are unsorted. The
++ * attribute values are aligned to the end of the block in no specific order.
++ *
++ * Locking strategy
++ * ----------------
++ * EXT4_I(inode)->i_file_acl is protected by EXT4_I(inode)->xattr_sem.
++ * EA blocks are only changed if they are exclusive to an inode, so
++ * holding xattr_sem also means that nothing but the EA block's reference
++ * count can change. Multiple writers to the same block are synchronized
++ * by the buffer lock.
++ */
++
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/mbcache.h>
++#include <linux/quotaops.h>
++#include <linux/rwsem.h>
++#include "xattr.h"
++#include "acl.h"
++
++#define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data))
++#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr))
++#define BFIRST(bh) ENTRY(BHDR(bh)+1)
++#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
++
++#define IHDR(inode, raw_inode) \
++ ((struct ext4_xattr_ibody_header *) \
++ ((void *)raw_inode + \
++ EXT4_GOOD_OLD_INODE_SIZE + \
++ EXT4_I(inode)->i_extra_isize))
++#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
++
++#ifdef EXT4_XATTR_DEBUG
++# define ea_idebug(inode, f...) do { \
++ printk(KERN_DEBUG "inode %s:%lu: ", \
++ inode->i_sb->s_id, inode->i_ino); \
++ printk(f); \
++ printk("\n"); \
++ } while (0)
++# define ea_bdebug(bh, f...) do { \
++ char b[BDEVNAME_SIZE]; \
++ printk(KERN_DEBUG "block %s:%lu: ", \
++ bdevname(bh->b_bdev, b), \
++ (unsigned long) bh->b_blocknr); \
++ printk(f); \
++ printk("\n"); \
++ } while (0)
++#else
++# define ea_idebug(f...)
++# define ea_bdebug(f...)
++#endif
++
++static void ext4_xattr_cache_insert(struct buffer_head *);
++static struct buffer_head *ext4_xattr_cache_find(struct inode *,
++ struct ext4_xattr_header *,
++ struct mb_cache_entry **);
++static void ext4_xattr_rehash(struct ext4_xattr_header *,
++ struct ext4_xattr_entry *);
++
++static struct mb_cache *ext4_xattr_cache;
++
++static struct xattr_handler *ext4_xattr_handler_map[] = {
++ [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler,
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext4_xattr_acl_access_handler,
++ [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler,
++#endif
++ [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler,
++#ifdef CONFIG_EXT4DEV_FS_SECURITY
++ [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler,
++#endif
++};
++
++struct xattr_handler *ext4_xattr_handlers[] = {
++ &ext4_xattr_user_handler,
++ &ext4_xattr_trusted_handler,
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ &ext4_xattr_acl_access_handler,
++ &ext4_xattr_acl_default_handler,
++#endif
++#ifdef CONFIG_EXT4DEV_FS_SECURITY
++ &ext4_xattr_security_handler,
++#endif
++ NULL
++};
++
++static inline struct xattr_handler *
++ext4_xattr_handler(int name_index)
++{
++ struct xattr_handler *handler = NULL;
++
++ if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map))
++ handler = ext4_xattr_handler_map[name_index];
++ return handler;
++}
++
++/*
++ * Inode operation listxattr()
++ *
++ * dentry->d_inode->i_mutex: don't care
++ */
++ssize_t
++ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
++{
++ return ext4_xattr_list(dentry->d_inode, buffer, size);
++}
++
++static int
++ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end)
++{
++ while (!IS_LAST_ENTRY(entry)) {
++ struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
++ if ((void *)next >= end)
++ return -EIO;
++ entry = next;
++ }
++ return 0;
++}
++
++static inline int
++ext4_xattr_check_block(struct buffer_head *bh)
++{
++ int error;
++
++ if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
++ BHDR(bh)->h_blocks != cpu_to_le32(1))
++ return -EIO;
++ error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
++ return error;
++}
++
++static inline int
++ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
++{
++ size_t value_size = le32_to_cpu(entry->e_value_size);
++
++ if (entry->e_value_block != 0 || value_size > size ||
++ le16_to_cpu(entry->e_value_offs) + value_size > size)
++ return -EIO;
++ return 0;
++}
++
++static int
++ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index,
++ const char *name, size_t size, int sorted)
++{
++ struct ext4_xattr_entry *entry;
++ size_t name_len;
++ int cmp = 1;
++
++ if (name == NULL)
++ return -EINVAL;
++ name_len = strlen(name);
++ entry = *pentry;
++ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
++ cmp = name_index - entry->e_name_index;
++ if (!cmp)
++ cmp = name_len - entry->e_name_len;
++ if (!cmp)
++ cmp = memcmp(name, entry->e_name, name_len);
++ if (cmp <= 0 && (sorted || cmp == 0))
++ break;
++ }
++ *pentry = entry;
++ if (!cmp && ext4_xattr_check_entry(entry, size))
++ return -EIO;
++ return cmp ? -ENODATA : 0;
++}
++
++static int
++ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
++ void *buffer, size_t buffer_size)
++{
++ struct buffer_head *bh = NULL;
++ struct ext4_xattr_entry *entry;
++ size_t size;
++ int error;
++
++ ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
++ name_index, name, buffer, (long)buffer_size);
++
++ error = -ENODATA;
++ if (!EXT4_I(inode)->i_file_acl)
++ goto cleanup;
++ ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
++ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
++ if (!bh)
++ goto cleanup;
++ ea_bdebug(bh, "b_count=%d, refcount=%d",
++ atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
++ if (ext4_xattr_check_block(bh)) {
++bad_block: ext4_error(inode->i_sb, __FUNCTION__,
++ "inode %lu: bad block %llu", inode->i_ino,
++ EXT4_I(inode)->i_file_acl);
++ error = -EIO;
++ goto cleanup;
++ }
++ ext4_xattr_cache_insert(bh);
++ entry = BFIRST(bh);
++ error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
++ if (error == -EIO)
++ goto bad_block;
++ if (error)
++ goto cleanup;
++ size = le32_to_cpu(entry->e_value_size);
++ if (buffer) {
++ error = -ERANGE;
++ if (size > buffer_size)
++ goto cleanup;
++ memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
++ size);
++ }
++ error = size;
++
++cleanup:
++ brelse(bh);
++ return error;
++}
++
++static int
++ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
++ void *buffer, size_t buffer_size)
++{
++ struct ext4_xattr_ibody_header *header;
++ struct ext4_xattr_entry *entry;
++ struct ext4_inode *raw_inode;
++ struct ext4_iloc iloc;
++ size_t size;
++ void *end;
++ int error;
++
++ if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR))
++ return -ENODATA;
++ error = ext4_get_inode_loc(inode, &iloc);
++ if (error)
++ return error;
++ raw_inode = ext4_raw_inode(&iloc);
++ header = IHDR(inode, raw_inode);
++ entry = IFIRST(header);
++ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
++ error = ext4_xattr_check_names(entry, end);
++ if (error)
++ goto cleanup;
++ error = ext4_xattr_find_entry(&entry, name_index, name,
++ end - (void *)entry, 0);
++ if (error)
++ goto cleanup;
++ size = le32_to_cpu(entry->e_value_size);
++ if (buffer) {
++ error = -ERANGE;
++ if (size > buffer_size)
++ goto cleanup;
++ memcpy(buffer, (void *)IFIRST(header) +
++ le16_to_cpu(entry->e_value_offs), size);
++ }
++ error = size;
++
++cleanup:
++ brelse(iloc.bh);
++ return error;
++}
++
++/*
++ * ext4_xattr_get()
++ *
++ * Copy an extended attribute into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext4_xattr_get(struct inode *inode, int name_index, const char *name,
++ void *buffer, size_t buffer_size)
++{
++ int error;
++
++ down_read(&EXT4_I(inode)->xattr_sem);
++ error = ext4_xattr_ibody_get(inode, name_index, name, buffer,
++ buffer_size);
++ if (error == -ENODATA)
++ error = ext4_xattr_block_get(inode, name_index, name, buffer,
++ buffer_size);
++ up_read(&EXT4_I(inode)->xattr_sem);
++ return error;
++}
++
++static int
++ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
++ char *buffer, size_t buffer_size)
++{
++ size_t rest = buffer_size;
++
++ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
++ struct xattr_handler *handler =
++ ext4_xattr_handler(entry->e_name_index);
++
++ if (handler) {
++ size_t size = handler->list(inode, buffer, rest,
++ entry->e_name,
++ entry->e_name_len);
++ if (buffer) {
++ if (size > rest)
++ return -ERANGE;
++ buffer += size;
++ }
++ rest -= size;
++ }
++ }
++ return buffer_size - rest;
++}
++
++static int
++ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++ struct buffer_head *bh = NULL;
++ int error;
++
++ ea_idebug(inode, "buffer=%p, buffer_size=%ld",
++ buffer, (long)buffer_size);
++
++ error = 0;
++ if (!EXT4_I(inode)->i_file_acl)
++ goto cleanup;
++ ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
++ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
++ error = -EIO;
++ if (!bh)
++ goto cleanup;
++ ea_bdebug(bh, "b_count=%d, refcount=%d",
++ atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
++ if (ext4_xattr_check_block(bh)) {
++ ext4_error(inode->i_sb, __FUNCTION__,
++ "inode %lu: bad block %llu", inode->i_ino,
++ EXT4_I(inode)->i_file_acl);
++ error = -EIO;
++ goto cleanup;
++ }
++ ext4_xattr_cache_insert(bh);
++ error = ext4_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size);
++
++cleanup:
++ brelse(bh);
++
++ return error;
++}
++
++static int
++ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++ struct ext4_xattr_ibody_header *header;
++ struct ext4_inode *raw_inode;
++ struct ext4_iloc iloc;
++ void *end;
++ int error;
++
++ if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR))
++ return 0;
++ error = ext4_get_inode_loc(inode, &iloc);
++ if (error)
++ return error;
++ raw_inode = ext4_raw_inode(&iloc);
++ header = IHDR(inode, raw_inode);
++ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
++ error = ext4_xattr_check_names(IFIRST(header), end);
++ if (error)
++ goto cleanup;
++ error = ext4_xattr_list_entries(inode, IFIRST(header),
++ buffer, buffer_size);
++
++cleanup:
++ brelse(iloc.bh);
++ return error;
++}
++
++/*
++ * ext4_xattr_list()
++ *
++ * Copy a list of attribute names into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++ int i_error, b_error;
++
++ down_read(&EXT4_I(inode)->xattr_sem);
++ i_error = ext4_xattr_ibody_list(inode, buffer, buffer_size);
++ if (i_error < 0) {
++ b_error = 0;
++ } else {
++ if (buffer) {
++ buffer += i_error;
++ buffer_size -= i_error;
++ }
++ b_error = ext4_xattr_block_list(inode, buffer, buffer_size);
++ if (b_error < 0)
++ i_error = 0;
++ }
++ up_read(&EXT4_I(inode)->xattr_sem);
++ return i_error + b_error;
++}
++
++/*
++ * If the EXT4_FEATURE_COMPAT_EXT_ATTR feature of this file system is
++ * not set, set it.
++ */
++static void ext4_xattr_update_super_block(handle_t *handle,
++ struct super_block *sb)
++{
++ if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR))
++ return;
++
++ lock_super(sb);
++ if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
++ EXT4_SB(sb)->s_es->s_feature_compat |=
++ cpu_to_le32(EXT4_FEATURE_COMPAT_EXT_ATTR);
++ sb->s_dirt = 1;
++ ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
++ }
++ unlock_super(sb);
++}
++
++/*
++ * Release the xattr block BH: If the reference count is > 1, decrement
++ * it; otherwise free the block.
++ */
++static void
++ext4_xattr_release_block(handle_t *handle, struct inode *inode,
++ struct buffer_head *bh)
++{
++ struct mb_cache_entry *ce = NULL;
++
++ ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr);
++ if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
++ ea_bdebug(bh, "refcount now=0; freeing");
++ if (ce)
++ mb_cache_entry_free(ce);
++ ext4_free_blocks(handle, inode, bh->b_blocknr, 1);
++ get_bh(bh);
++ ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
++ } else {
++ if (ext4_journal_get_write_access(handle, bh) == 0) {
++ lock_buffer(bh);
++ BHDR(bh)->h_refcount = cpu_to_le32(
++ le32_to_cpu(BHDR(bh)->h_refcount) - 1);
++ ext4_journal_dirty_metadata(handle, bh);
++ if (IS_SYNC(inode))
++ handle->h_sync = 1;
++ DQUOT_FREE_BLOCK(inode, 1);
++ unlock_buffer(bh);
++ ea_bdebug(bh, "refcount now=%d; releasing",
++ le32_to_cpu(BHDR(bh)->h_refcount));
++ }
++ if (ce)
++ mb_cache_entry_release(ce);
++ }
++}
++
++struct ext4_xattr_info {
++ int name_index;
++ const char *name;
++ const void *value;
++ size_t value_len;
++};
++
++struct ext4_xattr_search {
++ struct ext4_xattr_entry *first;
++ void *base;
++ void *end;
++ struct ext4_xattr_entry *here;
++ int not_found;
++};
++
++static int
++ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
++{
++ struct ext4_xattr_entry *last;
++ size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
++
++ /* Compute min_offs and last. */
++ last = s->first;
++ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
++ if (!last->e_value_block && last->e_value_size) {
++ size_t offs = le16_to_cpu(last->e_value_offs);
++ if (offs < min_offs)
++ min_offs = offs;
++ }
++ }
++ free = min_offs - ((void *)last - s->base) - sizeof(__u32);
++ if (!s->not_found) {
++ if (!s->here->e_value_block && s->here->e_value_size) {
++ size_t size = le32_to_cpu(s->here->e_value_size);
++ free += EXT4_XATTR_SIZE(size);
++ }
++ free += EXT4_XATTR_LEN(name_len);
++ }
++ if (i->value) {
++ if (free < EXT4_XATTR_SIZE(i->value_len) ||
++ free < EXT4_XATTR_LEN(name_len) +
++ EXT4_XATTR_SIZE(i->value_len))
++ return -ENOSPC;
++ }
++
++ if (i->value && s->not_found) {
++ /* Insert the new name. */
++ size_t size = EXT4_XATTR_LEN(name_len);
++ size_t rest = (void *)last - (void *)s->here + sizeof(__u32);
++ memmove((void *)s->here + size, s->here, rest);
++ memset(s->here, 0, size);
++ s->here->e_name_index = i->name_index;
++ s->here->e_name_len = name_len;
++ memcpy(s->here->e_name, i->name, name_len);
++ } else {
++ if (!s->here->e_value_block && s->here->e_value_size) {
++ void *first_val = s->base + min_offs;
++ size_t offs = le16_to_cpu(s->here->e_value_offs);
++ void *val = s->base + offs;
++ size_t size = EXT4_XATTR_SIZE(
++ le32_to_cpu(s->here->e_value_size));
++
++ if (i->value && size == EXT4_XATTR_SIZE(i->value_len)) {
++ /* The old and the new value have the same
++ size. Just replace. */
++ s->here->e_value_size =
++ cpu_to_le32(i->value_len);
++ memset(val + size - EXT4_XATTR_PAD, 0,
++ EXT4_XATTR_PAD); /* Clear pad bytes. */
++ memcpy(val, i->value, i->value_len);
++ return 0;
++ }
++
++ /* Remove the old value. */
++ memmove(first_val + size, first_val, val - first_val);
++ memset(first_val, 0, size);
++ s->here->e_value_size = 0;
++ s->here->e_value_offs = 0;
++ min_offs += size;
++
++ /* Adjust all value offsets. */
++ last = s->first;
++ while (!IS_LAST_ENTRY(last)) {
++ size_t o = le16_to_cpu(last->e_value_offs);
++ if (!last->e_value_block &&
++ last->e_value_size && o < offs)
++ last->e_value_offs =
++ cpu_to_le16(o + size);
++ last = EXT4_XATTR_NEXT(last);
++ }
++ }
++ if (!i->value) {
++ /* Remove the old name. */
++ size_t size = EXT4_XATTR_LEN(name_len);
++ last = ENTRY((void *)last - size);
++ memmove(s->here, (void *)s->here + size,
++ (void *)last - (void *)s->here + sizeof(__u32));
++ memset(last, 0, size);
++ }
++ }
++
++ if (i->value) {
++ /* Insert the new value. */
++ s->here->e_value_size = cpu_to_le32(i->value_len);
++ if (i->value_len) {
++ size_t size = EXT4_XATTR_SIZE(i->value_len);
++ void *val = s->base + min_offs - size;
++ s->here->e_value_offs = cpu_to_le16(min_offs - size);
++ memset(val + size - EXT4_XATTR_PAD, 0,
++ EXT4_XATTR_PAD); /* Clear the pad bytes. */
++ memcpy(val, i->value, i->value_len);
++ }
++ }
++ return 0;
++}
++
++struct ext4_xattr_block_find {
++ struct ext4_xattr_search s;
++ struct buffer_head *bh;
++};
++
++static int
++ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
++ struct ext4_xattr_block_find *bs)
++{
++ struct super_block *sb = inode->i_sb;
++ int error;
++
++ ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
++ i->name_index, i->name, i->value, (long)i->value_len);
++
++ if (EXT4_I(inode)->i_file_acl) {
++ /* The inode already has an extended attribute block. */
++ bs->bh = sb_bread(sb, EXT4_I(inode)->i_file_acl);
++ error = -EIO;
++ if (!bs->bh)
++ goto cleanup;
++ ea_bdebug(bs->bh, "b_count=%d, refcount=%d",
++ atomic_read(&(bs->bh->b_count)),
++ le32_to_cpu(BHDR(bs->bh)->h_refcount));
++ if (ext4_xattr_check_block(bs->bh)) {
++ ext4_error(sb, __FUNCTION__,
++ "inode %lu: bad block %llu", inode->i_ino,
++ EXT4_I(inode)->i_file_acl);
++ error = -EIO;
++ goto cleanup;
++ }
++ /* Find the named attribute. */
++ bs->s.base = BHDR(bs->bh);
++ bs->s.first = BFIRST(bs->bh);
++ bs->s.end = bs->bh->b_data + bs->bh->b_size;
++ bs->s.here = bs->s.first;
++ error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
++ i->name, bs->bh->b_size, 1);
++ if (error && error != -ENODATA)
++ goto cleanup;
++ bs->s.not_found = error;
++ }
++ error = 0;
++
++cleanup:
++ return error;
++}
++
++static int
++ext4_xattr_block_set(handle_t *handle, struct inode *inode,
++ struct ext4_xattr_info *i,
++ struct ext4_xattr_block_find *bs)
++{
++ struct super_block *sb = inode->i_sb;
++ struct buffer_head *new_bh = NULL;
++ struct ext4_xattr_search *s = &bs->s;
++ struct mb_cache_entry *ce = NULL;
++ int error;
++
++#define header(x) ((struct ext4_xattr_header *)(x))
++
++ if (i->value && i->value_len > sb->s_blocksize)
++ return -ENOSPC;
++ if (s->base) {
++ ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev,
++ bs->bh->b_blocknr);
++ if (header(s->base)->h_refcount == cpu_to_le32(1)) {
++ if (ce) {
++ mb_cache_entry_free(ce);
++ ce = NULL;
++ }
++ ea_bdebug(bs->bh, "modifying in-place");
++ error = ext4_journal_get_write_access(handle, bs->bh);
++ if (error)
++ goto cleanup;
++ lock_buffer(bs->bh);
++ error = ext4_xattr_set_entry(i, s);
++ if (!error) {
++ if (!IS_LAST_ENTRY(s->first))
++ ext4_xattr_rehash(header(s->base),
++ s->here);
++ ext4_xattr_cache_insert(bs->bh);
++ }
++ unlock_buffer(bs->bh);
++ if (error == -EIO)
++ goto bad_block;
++ if (!error)
++ error = ext4_journal_dirty_metadata(handle,
++ bs->bh);
++ if (error)
++ goto cleanup;
++ goto inserted;
++ } else {
++ int offset = (char *)s->here - bs->bh->b_data;
++
++ if (ce) {
++ mb_cache_entry_release(ce);
++ ce = NULL;
++ }
++ ea_bdebug(bs->bh, "cloning");
++ s->base = kmalloc(bs->bh->b_size, GFP_KERNEL);
++ error = -ENOMEM;
++ if (s->base == NULL)
++ goto cleanup;
++ memcpy(s->base, BHDR(bs->bh), bs->bh->b_size);
++ s->first = ENTRY(header(s->base)+1);
++ header(s->base)->h_refcount = cpu_to_le32(1);
++ s->here = ENTRY(s->base + offset);
++ s->end = s->base + bs->bh->b_size;
++ }
++ } else {
++ /* Allocate a buffer where we construct the new block. */
++ s->base = kmalloc(sb->s_blocksize, GFP_KERNEL);
++ /* assert(header == s->base) */
++ error = -ENOMEM;
++ if (s->base == NULL)
++ goto cleanup;
++ memset(s->base, 0, sb->s_blocksize);
++ header(s->base)->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
++ header(s->base)->h_blocks = cpu_to_le32(1);
++ header(s->base)->h_refcount = cpu_to_le32(1);
++ s->first = ENTRY(header(s->base)+1);
++ s->here = ENTRY(header(s->base)+1);
++ s->end = s->base + sb->s_blocksize;
++ }
++
++ error = ext4_xattr_set_entry(i, s);
++ if (error == -EIO)
++ goto bad_block;
++ if (error)
++ goto cleanup;
++ if (!IS_LAST_ENTRY(s->first))
++ ext4_xattr_rehash(header(s->base), s->here);
++
++inserted:
++ if (!IS_LAST_ENTRY(s->first)) {
++ new_bh = ext4_xattr_cache_find(inode, header(s->base), &ce);
++ if (new_bh) {
++ /* We found an identical block in the cache. */
++ if (new_bh == bs->bh)
++ ea_bdebug(new_bh, "keeping");
++ else {
++ /* The old block is released after updating
++ the inode. */
++ error = -EDQUOT;
++ if (DQUOT_ALLOC_BLOCK(inode, 1))
++ goto cleanup;
++ error = ext4_journal_get_write_access(handle,
++ new_bh);
++ if (error)
++ goto cleanup_dquot;
++ lock_buffer(new_bh);
++ BHDR(new_bh)->h_refcount = cpu_to_le32(1 +
++ le32_to_cpu(BHDR(new_bh)->h_refcount));
++ ea_bdebug(new_bh, "reusing; refcount now=%d",
++ le32_to_cpu(BHDR(new_bh)->h_refcount));
++ unlock_buffer(new_bh);
++ error = ext4_journal_dirty_metadata(handle,
++ new_bh);
++ if (error)
++ goto cleanup_dquot;
++ }
++ mb_cache_entry_release(ce);
++ ce = NULL;
++ } else if (bs->bh && s->base == bs->bh->b_data) {
++ /* We were modifying this block in-place. */
++ ea_bdebug(bs->bh, "keeping this block");
++ new_bh = bs->bh;
++ get_bh(new_bh);
++ } else {
++ /* We need to allocate a new block */
++ ext4_fsblk_t goal = le32_to_cpu(
++ EXT4_SB(sb)->s_es->s_first_data_block) +
++ (ext4_fsblk_t)EXT4_I(inode)->i_block_group *
++ EXT4_BLOCKS_PER_GROUP(sb);
++ ext4_fsblk_t block = ext4_new_block(handle, inode,
++ goal, &error);
++ if (error)
++ goto cleanup;
++ ea_idebug(inode, "creating block %d", block);
++
++ new_bh = sb_getblk(sb, block);
++ if (!new_bh) {
++getblk_failed:
++ ext4_free_blocks(handle, inode, block, 1);
++ error = -EIO;
++ goto cleanup;
++ }
++ lock_buffer(new_bh);
++ error = ext4_journal_get_create_access(handle, new_bh);
++ if (error) {
++ unlock_buffer(new_bh);
++ goto getblk_failed;
++ }
++ memcpy(new_bh->b_data, s->base, new_bh->b_size);
++ set_buffer_uptodate(new_bh);
++ unlock_buffer(new_bh);
++ ext4_xattr_cache_insert(new_bh);
++ error = ext4_journal_dirty_metadata(handle, new_bh);
++ if (error)
++ goto cleanup;
++ }
++ }
++
++ /* Update the inode. */
++ EXT4_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
++
++ /* Drop the previous xattr block. */
++ if (bs->bh && bs->bh != new_bh)
++ ext4_xattr_release_block(handle, inode, bs->bh);
++ error = 0;
++
++cleanup:
++ if (ce)
++ mb_cache_entry_release(ce);
++ brelse(new_bh);
++ if (!(bs->bh && s->base == bs->bh->b_data))
++ kfree(s->base);
++
++ return error;
++
++cleanup_dquot:
++ DQUOT_FREE_BLOCK(inode, 1);
++ goto cleanup;
++
++bad_block:
++ ext4_error(inode->i_sb, __FUNCTION__,
++ "inode %lu: bad block %llu", inode->i_ino,
++ EXT4_I(inode)->i_file_acl);
++ goto cleanup;
++
++#undef header
++}
++
++struct ext4_xattr_ibody_find {
++ struct ext4_xattr_search s;
++ struct ext4_iloc iloc;
++};
++
++static int
++ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
++ struct ext4_xattr_ibody_find *is)
++{
++ struct ext4_xattr_ibody_header *header;
++ struct ext4_inode *raw_inode;
++ int error;
++
++ if (EXT4_I(inode)->i_extra_isize == 0)
++ return 0;
++ raw_inode = ext4_raw_inode(&is->iloc);
++ header = IHDR(inode, raw_inode);
++ is->s.base = is->s.first = IFIRST(header);
++ is->s.here = is->s.first;
++ is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
++ if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) {
++ error = ext4_xattr_check_names(IFIRST(header), is->s.end);
++ if (error)
++ return error;
++ /* Find the named attribute. */
++ error = ext4_xattr_find_entry(&is->s.here, i->name_index,
++ i->name, is->s.end -
++ (void *)is->s.base, 0);
++ if (error && error != -ENODATA)
++ return error;
++ is->s.not_found = error;
++ }
++ return 0;
++}
++
++static int
++ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
++ struct ext4_xattr_info *i,
++ struct ext4_xattr_ibody_find *is)
++{
++ struct ext4_xattr_ibody_header *header;
++ struct ext4_xattr_search *s = &is->s;
++ int error;
++
++ if (EXT4_I(inode)->i_extra_isize == 0)
++ return -ENOSPC;
++ error = ext4_xattr_set_entry(i, s);
++ if (error)
++ return error;
++ header = IHDR(inode, ext4_raw_inode(&is->iloc));
++ if (!IS_LAST_ENTRY(s->first)) {
++ header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
++ EXT4_I(inode)->i_state |= EXT4_STATE_XATTR;
++ } else {
++ header->h_magic = cpu_to_le32(0);
++ EXT4_I(inode)->i_state &= ~EXT4_STATE_XATTR;
++ }
++ return 0;
++}
++
++/*
++ * ext4_xattr_set_handle()
++ *
++ * Create, replace or remove an extended attribute for this inode. Buffer
++ * is NULL to remove an existing extended attribute, and non-NULL to
++ * either replace an existing extended attribute, or create a new extended
++ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
++ * specify that an extended attribute must exist and must not exist
++ * previous to the call, respectively.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++int
++ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
++ const char *name, const void *value, size_t value_len,
++ int flags)
++{
++ struct ext4_xattr_info i = {
++ .name_index = name_index,
++ .name = name,
++ .value = value,
++ .value_len = value_len,
++
++ };
++ struct ext4_xattr_ibody_find is = {
++ .s = { .not_found = -ENODATA, },
++ };
++ struct ext4_xattr_block_find bs = {
++ .s = { .not_found = -ENODATA, },
++ };
++ int error;
++
++ if (!name)
++ return -EINVAL;
++ if (strlen(name) > 255)
++ return -ERANGE;
++ down_write(&EXT4_I(inode)->xattr_sem);
++ error = ext4_get_inode_loc(inode, &is.iloc);
++ if (error)
++ goto cleanup;
++
++ if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) {
++ struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc);
++ memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
++ EXT4_I(inode)->i_state &= ~EXT4_STATE_NEW;
++ }
++
++ error = ext4_xattr_ibody_find(inode, &i, &is);
++ if (error)
++ goto cleanup;
++ if (is.s.not_found)
++ error = ext4_xattr_block_find(inode, &i, &bs);
++ if (error)
++ goto cleanup;
++ if (is.s.not_found && bs.s.not_found) {
++ error = -ENODATA;
++ if (flags & XATTR_REPLACE)
++ goto cleanup;
++ error = 0;
++ if (!value)
++ goto cleanup;
++ } else {
++ error = -EEXIST;
++ if (flags & XATTR_CREATE)
++ goto cleanup;
++ }
++ error = ext4_journal_get_write_access(handle, is.iloc.bh);
++ if (error)
++ goto cleanup;
++ if (!value) {
++ if (!is.s.not_found)
++ error = ext4_xattr_ibody_set(handle, inode, &i, &is);
++ else if (!bs.s.not_found)
++ error = ext4_xattr_block_set(handle, inode, &i, &bs);
++ } else {
++ error = ext4_xattr_ibody_set(handle, inode, &i, &is);
++ if (!error && !bs.s.not_found) {
++ i.value = NULL;
++ error = ext4_xattr_block_set(handle, inode, &i, &bs);
++ } else if (error == -ENOSPC) {
++ error = ext4_xattr_block_set(handle, inode, &i, &bs);
++ if (error)
++ goto cleanup;
++ if (!is.s.not_found) {
++ i.value = NULL;
++ error = ext4_xattr_ibody_set(handle, inode, &i,
++ &is);
++ }
++ }
++ }
++ if (!error) {
++ ext4_xattr_update_super_block(handle, inode->i_sb);
++ inode->i_ctime = CURRENT_TIME_SEC;
++ error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
++ /*
++ * The bh is consumed by ext4_mark_iloc_dirty, even with
++ * error != 0.
++ */
++ is.iloc.bh = NULL;
++ if (IS_SYNC(inode))
++ handle->h_sync = 1;
++ }
++
++cleanup:
++ brelse(is.iloc.bh);
++ brelse(bs.bh);
++ up_write(&EXT4_I(inode)->xattr_sem);
++ return error;
++}
++
++/*
++ * ext4_xattr_set()
++ *
++ * Like ext4_xattr_set_handle, but start from an inode. This extended
++ * attribute modification is a filesystem transaction by itself.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++int
++ext4_xattr_set(struct inode *inode, int name_index, const char *name,
++ const void *value, size_t value_len, int flags)
++{
++ handle_t *handle;
++ int error, retries = 0;
++
++retry:
++ handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
++ if (IS_ERR(handle)) {
++ error = PTR_ERR(handle);
++ } else {
++ int error2;
++
++ error = ext4_xattr_set_handle(handle, inode, name_index, name,
++ value, value_len, flags);
++ error2 = ext4_journal_stop(handle);
++ if (error == -ENOSPC &&
++ ext4_should_retry_alloc(inode->i_sb, &retries))
++ goto retry;
++ if (error == 0)
++ error = error2;
++ }
++
++ return error;
++}
++
++/*
++ * ext4_xattr_delete_inode()
++ *
++ * Free extended attribute resources associated with this inode. This
++ * is called immediately before an inode is freed. We have exclusive
++ * access to the inode.
++ */
++void
++ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
++{
++ struct buffer_head *bh = NULL;
++
++ if (!EXT4_I(inode)->i_file_acl)
++ goto cleanup;
++ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
++ if (!bh) {
++ ext4_error(inode->i_sb, __FUNCTION__,
++ "inode %lu: block %llu read error", inode->i_ino,
++ EXT4_I(inode)->i_file_acl);
++ goto cleanup;
++ }
++ if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
++ BHDR(bh)->h_blocks != cpu_to_le32(1)) {
++ ext4_error(inode->i_sb, __FUNCTION__,
++ "inode %lu: bad block %llu", inode->i_ino,
++ EXT4_I(inode)->i_file_acl);
++ goto cleanup;
++ }
++ ext4_xattr_release_block(handle, inode, bh);
++ EXT4_I(inode)->i_file_acl = 0;
++
++cleanup:
++ brelse(bh);
++}
++
++/*
++ * ext4_xattr_put_super()
++ *
++ * This is called when a file system is unmounted.
++ */
++void
++ext4_xattr_put_super(struct super_block *sb)
++{
++ mb_cache_shrink(sb->s_bdev);
++}
++
++/*
++ * ext4_xattr_cache_insert()
++ *
++ * Create a new entry in the extended attribute cache, and insert
++ * it unless such an entry is already in the cache.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++static void
++ext4_xattr_cache_insert(struct buffer_head *bh)
++{
++ __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
++ struct mb_cache_entry *ce;
++ int error;
++
++ ce = mb_cache_entry_alloc(ext4_xattr_cache);
++ if (!ce) {
++ ea_bdebug(bh, "out of memory");
++ return;
++ }
++ error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
++ if (error) {
++ mb_cache_entry_free(ce);
++ if (error == -EBUSY) {
++ ea_bdebug(bh, "already in cache");
++ error = 0;
++ }
++ } else {
++ ea_bdebug(bh, "inserting [%x]", (int)hash);
++ mb_cache_entry_release(ce);
++ }
++}
++
++/*
++ * ext4_xattr_cmp()
++ *
++ * Compare two extended attribute blocks for equality.
++ *
++ * Returns 0 if the blocks are equal, 1 if they differ, and
++ * a negative error number on errors.
++ */
++static int
++ext4_xattr_cmp(struct ext4_xattr_header *header1,
++ struct ext4_xattr_header *header2)
++{
++ struct ext4_xattr_entry *entry1, *entry2;
++
++ entry1 = ENTRY(header1+1);
++ entry2 = ENTRY(header2+1);
++ while (!IS_LAST_ENTRY(entry1)) {
++ if (IS_LAST_ENTRY(entry2))
++ return 1;
++ if (entry1->e_hash != entry2->e_hash ||
++ entry1->e_name_index != entry2->e_name_index ||
++ entry1->e_name_len != entry2->e_name_len ||
++ entry1->e_value_size != entry2->e_value_size ||
++ memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
++ return 1;
++ if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
++ return -EIO;
++ if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
++ (char *)header2 + le16_to_cpu(entry2->e_value_offs),
++ le32_to_cpu(entry1->e_value_size)))
++ return 1;
++
++ entry1 = EXT4_XATTR_NEXT(entry1);
++ entry2 = EXT4_XATTR_NEXT(entry2);
++ }
++ if (!IS_LAST_ENTRY(entry2))
++ return 1;
++ return 0;
++}
++
++/*
++ * ext4_xattr_cache_find()
++ *
++ * Find an identical extended attribute block.
++ *
++ * Returns a pointer to the block found, or NULL if such a block was
++ * not found or an error occurred.
++ */
++static struct buffer_head *
++ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
++ struct mb_cache_entry **pce)
++{
++ __u32 hash = le32_to_cpu(header->h_hash);
++ struct mb_cache_entry *ce;
++
++ if (!header->h_hash)
++ return NULL; /* never share */
++ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
++again:
++ ce = mb_cache_entry_find_first(ext4_xattr_cache, 0,
++ inode->i_sb->s_bdev, hash);
++ while (ce) {
++ struct buffer_head *bh;
++
++ if (IS_ERR(ce)) {
++ if (PTR_ERR(ce) == -EAGAIN)
++ goto again;
++ break;
++ }
++ bh = sb_bread(inode->i_sb, ce->e_block);
++ if (!bh) {
++ ext4_error(inode->i_sb, __FUNCTION__,
++ "inode %lu: block %lu read error",
++ inode->i_ino, (unsigned long) ce->e_block);
++ } else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
++ EXT4_XATTR_REFCOUNT_MAX) {
++ ea_idebug(inode, "block %lu refcount %d>=%d",
++ (unsigned long) ce->e_block,
++ le32_to_cpu(BHDR(bh)->h_refcount),
++ EXT4_XATTR_REFCOUNT_MAX);
++ } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) {
++ *pce = ce;
++ return bh;
++ }
++ brelse(bh);
++ ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
++ }
++ return NULL;
++}
++
++#define NAME_HASH_SHIFT 5
++#define VALUE_HASH_SHIFT 16
++
++/*
++ * ext4_xattr_hash_entry()
++ *
++ * Compute the hash of an extended attribute.
++ */
++static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
++ struct ext4_xattr_entry *entry)
++{
++ __u32 hash = 0;
++ char *name = entry->e_name;
++ int n;
++
++ for (n=0; n < entry->e_name_len; n++) {
++ hash = (hash << NAME_HASH_SHIFT) ^
++ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
++ *name++;
++ }
++
++ if (entry->e_value_block == 0 && entry->e_value_size != 0) {
++ __le32 *value = (__le32 *)((char *)header +
++ le16_to_cpu(entry->e_value_offs));
++ for (n = (le32_to_cpu(entry->e_value_size) +
++ EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
++ hash = (hash << VALUE_HASH_SHIFT) ^
++ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
++ le32_to_cpu(*value++);
++ }
++ }
++ entry->e_hash = cpu_to_le32(hash);
++}
++
++#undef NAME_HASH_SHIFT
++#undef VALUE_HASH_SHIFT
++
++#define BLOCK_HASH_SHIFT 16
++
++/*
++ * ext4_xattr_rehash()
++ *
++ * Re-compute the extended attribute hash value after an entry has changed.
++ */
++static void ext4_xattr_rehash(struct ext4_xattr_header *header,
++ struct ext4_xattr_entry *entry)
++{
++ struct ext4_xattr_entry *here;
++ __u32 hash = 0;
++
++ ext4_xattr_hash_entry(header, entry);
++ here = ENTRY(header+1);
++ while (!IS_LAST_ENTRY(here)) {
++ if (!here->e_hash) {
++ /* Block is not shared if an entry's hash value == 0 */
++ hash = 0;
++ break;
++ }
++ hash = (hash << BLOCK_HASH_SHIFT) ^
++ (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
++ le32_to_cpu(here->e_hash);
++ here = EXT4_XATTR_NEXT(here);
++ }
++ header->h_hash = cpu_to_le32(hash);
++}
++
++#undef BLOCK_HASH_SHIFT
++
++int __init
++init_ext4_xattr(void)
++{
++ ext4_xattr_cache = mb_cache_create("ext4_xattr", NULL,
++ sizeof(struct mb_cache_entry) +
++ sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);
++ if (!ext4_xattr_cache)
++ return -ENOMEM;
++ return 0;
++}
++
++void
++exit_ext4_xattr(void)
++{
++ if (ext4_xattr_cache)
++ mb_cache_destroy(ext4_xattr_cache);
++ ext4_xattr_cache = NULL;
++}
+diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
+new file mode 100644
+index 0000000..79432b3
+--- /dev/null
++++ b/fs/ext4/xattr.h
+@@ -0,0 +1,145 @@
++/*
++ File: fs/ext4/xattr.h
++
++ On-disk format of extended attributes for the ext4 filesystem.
++
++ (C) 2001 Andreas Gruenbacher, <a.gruenbacher at computer.org>
++*/
++
++#include <linux/xattr.h>
++
++/* Magic value in attribute blocks */
++#define EXT4_XATTR_MAGIC 0xEA020000
++
++/* Maximum number of references to one attribute block */
++#define EXT4_XATTR_REFCOUNT_MAX 1024
++
++/* Name indexes */
++#define EXT4_XATTR_INDEX_USER 1
++#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2
++#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3
++#define EXT4_XATTR_INDEX_TRUSTED 4
++#define EXT4_XATTR_INDEX_LUSTRE 5
++#define EXT4_XATTR_INDEX_SECURITY 6
++
++struct ext4_xattr_header {
++ __le32 h_magic; /* magic number for identification */
++ __le32 h_refcount; /* reference count */
++ __le32 h_blocks; /* number of disk blocks used */
++ __le32 h_hash; /* hash value of all attributes */
++ __u32 h_reserved[4]; /* zero right now */
++};
++
++struct ext4_xattr_ibody_header {
++ __le32 h_magic; /* magic number for identification */
++};
++
++struct ext4_xattr_entry {
++ __u8 e_name_len; /* length of name */
++ __u8 e_name_index; /* attribute name index */
++ __le16 e_value_offs; /* offset in disk block of value */
++ __le32 e_value_block; /* disk block attribute is stored on (n/i) */
++ __le32 e_value_size; /* size of attribute value */
++ __le32 e_hash; /* hash value of name and value */
++ char e_name[0]; /* attribute name */
++};
++
++#define EXT4_XATTR_PAD_BITS 2
++#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS)
++#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1)
++#define EXT4_XATTR_LEN(name_len) \
++ (((name_len) + EXT4_XATTR_ROUND + \
++ sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
++#define EXT4_XATTR_NEXT(entry) \
++ ( (struct ext4_xattr_entry *)( \
++ (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)) )
++#define EXT4_XATTR_SIZE(size) \
++ (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
++
++# ifdef CONFIG_EXT4DEV_FS_XATTR
++
++extern struct xattr_handler ext4_xattr_user_handler;
++extern struct xattr_handler ext4_xattr_trusted_handler;
++extern struct xattr_handler ext4_xattr_acl_access_handler;
++extern struct xattr_handler ext4_xattr_acl_default_handler;
++extern struct xattr_handler ext4_xattr_security_handler;
++
++extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
++
++extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
++extern int ext4_xattr_list(struct inode *, char *, size_t);
++extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
++extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
++
++extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
++extern void ext4_xattr_put_super(struct super_block *);
++
++extern int init_ext4_xattr(void);
++extern void exit_ext4_xattr(void);
++
++extern struct xattr_handler *ext4_xattr_handlers[];
++
++# else /* CONFIG_EXT4DEV_FS_XATTR */
++
++static inline int
++ext4_xattr_get(struct inode *inode, int name_index, const char *name,
++ void *buffer, size_t size, int flags)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline int
++ext4_xattr_list(struct inode *inode, void *buffer, size_t size)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline int
++ext4_xattr_set(struct inode *inode, int name_index, const char *name,
++ const void *value, size_t size, int flags)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline int
++ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
++ const char *name, const void *value, size_t size, int flags)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline void
++ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
++{
++}
++
++static inline void
++ext4_xattr_put_super(struct super_block *sb)
++{
++}
++
++static inline int
++init_ext4_xattr(void)
++{
++ return 0;
++}
++
++static inline void
++exit_ext4_xattr(void)
++{
++}
++
++#define ext4_xattr_handlers NULL
++
++# endif /* CONFIG_EXT4DEV_FS_XATTR */
++
++#ifdef CONFIG_EXT4DEV_FS_SECURITY
++extern int ext4_init_security(handle_t *handle, struct inode *inode,
++ struct inode *dir);
++#else
++static inline int ext4_init_security(handle_t *handle, struct inode *inode,
++ struct inode *dir)
++{
++ return 0;
++}
++#endif
+diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
+new file mode 100644
+index 0000000..b6a6861
+--- /dev/null
++++ b/fs/ext4/xattr_security.c
+@@ -0,0 +1,77 @@
++/*
++ * linux/fs/ext4/xattr_security.c
++ * Handler for storing security labels as extended attributes.
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/ext4_fs.h>
++#include <linux/security.h>
++#include "xattr.h"
++
++static size_t
++ext4_xattr_security_list(struct inode *inode, char *list, size_t list_size,
++ const char *name, size_t name_len)
++{
++ const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
++ const size_t total_len = prefix_len + name_len + 1;
++
++
++ if (list && total_len <= list_size) {
++ memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
++ memcpy(list+prefix_len, name, name_len);
++ list[prefix_len + name_len] = '\0';
++ }
++ return total_len;
++}
++
++static int
++ext4_xattr_security_get(struct inode *inode, const char *name,
++ void *buffer, size_t size)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, name,
++ buffer, size);
++}
++
++static int
++ext4_xattr_security_set(struct inode *inode, const char *name,
++ const void *value, size_t size, int flags)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, name,
++ value, size, flags);
++}
++
++int
++ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
++{
++ int err;
++ size_t len;
++ void *value;
++ char *name;
++
++ err = security_inode_init_security(inode, dir, &name, &value, &len);
++ if (err) {
++ if (err == -EOPNOTSUPP)
++ return 0;
++ return err;
++ }
++ err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
++ name, value, len, 0);
++ kfree(name);
++ kfree(value);
++ return err;
++}
++
++struct xattr_handler ext4_xattr_security_handler = {
++ .prefix = XATTR_SECURITY_PREFIX,
++ .list = ext4_xattr_security_list,
++ .get = ext4_xattr_security_get,
++ .set = ext4_xattr_security_set,
++};
+diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
+new file mode 100644
+index 0000000..b76f2db
+--- /dev/null
++++ b/fs/ext4/xattr_trusted.c
+@@ -0,0 +1,62 @@
++/*
++ * linux/fs/ext4/xattr_trusted.c
++ * Handler for trusted extended attributes.
++ *
++ * Copyright (C) 2003 by Andreas Gruenbacher, <a.gruenbacher at computer.org>
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/capability.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/ext4_fs.h>
++#include "xattr.h"
++
++#define XATTR_TRUSTED_PREFIX "trusted."
++
++static size_t
++ext4_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
++ const char *name, size_t name_len)
++{
++ const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1;
++ const size_t total_len = prefix_len + name_len + 1;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return 0;
++
++ if (list && total_len <= list_size) {
++ memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
++ memcpy(list+prefix_len, name, name_len);
++ list[prefix_len + name_len] = '\0';
++ }
++ return total_len;
++}
++
++static int
++ext4_xattr_trusted_get(struct inode *inode, const char *name,
++ void *buffer, size_t size)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED, name,
++ buffer, size);
++}
++
++static int
++ext4_xattr_trusted_set(struct inode *inode, const char *name,
++ const void *value, size_t size, int flags)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ return ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED, name,
++ value, size, flags);
++}
++
++struct xattr_handler ext4_xattr_trusted_handler = {
++ .prefix = XATTR_TRUSTED_PREFIX,
++ .list = ext4_xattr_trusted_list,
++ .get = ext4_xattr_trusted_get,
++ .set = ext4_xattr_trusted_set,
++};
+diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c
+new file mode 100644
+index 0000000..c53cded
+--- /dev/null
++++ b/fs/ext4/xattr_user.c
+@@ -0,0 +1,64 @@
++/*
++ * linux/fs/ext4/xattr_user.c
++ * Handler for extended user attributes.
++ *
++ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher at computer.org>
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/ext4_jbd2.h>
++#include <linux/ext4_fs.h>
++#include "xattr.h"
++
++#define XATTR_USER_PREFIX "user."
++
++static size_t
++ext4_xattr_user_list(struct inode *inode, char *list, size_t list_size,
++ const char *name, size_t name_len)
++{
++ const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1;
++ const size_t total_len = prefix_len + name_len + 1;
++
++ if (!test_opt(inode->i_sb, XATTR_USER))
++ return 0;
++
++ if (list && total_len <= list_size) {
++ memcpy(list, XATTR_USER_PREFIX, prefix_len);
++ memcpy(list+prefix_len, name, name_len);
++ list[prefix_len + name_len] = '\0';
++ }
++ return total_len;
++}
++
++static int
++ext4_xattr_user_get(struct inode *inode, const char *name,
++ void *buffer, size_t size)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ if (!test_opt(inode->i_sb, XATTR_USER))
++ return -EOPNOTSUPP;
++ return ext4_xattr_get(inode, EXT4_XATTR_INDEX_USER, name, buffer, size);
++}
++
++static int
++ext4_xattr_user_set(struct inode *inode, const char *name,
++ const void *value, size_t size, int flags)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ if (!test_opt(inode->i_sb, XATTR_USER))
++ return -EOPNOTSUPP;
++ return ext4_xattr_set(inode, EXT4_XATTR_INDEX_USER, name,
++ value, size, flags);
++}
++
++struct xattr_handler ext4_xattr_user_handler = {
++ .prefix = XATTR_USER_PREFIX,
++ .list = ext4_xattr_user_list,
++ .get = ext4_xattr_user_get,
++ .set = ext4_xattr_user_set,
++};
+diff --git a/fs/fat/cache.c b/fs/fat/cache.c
+index 97b967b..82cc4f5 100644
+--- a/fs/fat/cache.c
++++ b/fs/fat/cache.c
+@@ -58,8 +58,7 @@ int __init fat_cache_init(void)
+
+ void fat_cache_destroy(void)
+ {
+- if (kmem_cache_destroy(fat_cache_cachep))
+- printk(KERN_INFO "fat_cache: not all structures were freed\n");
++ kmem_cache_destroy(fat_cache_cachep);
+ }
+
+ static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
+diff --git a/fs/fat/dir.c b/fs/fat/dir.c
+index 698b85b..69c439f 100644
+--- a/fs/fat/dir.c
++++ b/fs/fat/dir.c
+@@ -20,6 +20,7 @@
+ #include <linux/dirent.h>
+ #include <linux/smp_lock.h>
+ #include <linux/buffer_head.h>
++#include <linux/compat.h>
+ #include <asm/uaccess.h>
+
+ static inline loff_t fat_make_i_pos(struct super_block *sb,
+@@ -647,7 +648,7 @@ static int fat_readdir(struct file *filp
+ }
+
+ static int fat_ioctl_filldir(void *__buf, const char *name, int name_len,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct fat_ioctl_filldir_callback *buf = __buf;
+ struct dirent __user *d1 = buf->dirent;
+@@ -741,10 +742,65 @@ static int fat_dir_ioctl(struct inode *
+ return ret;
+ }
+
++#ifdef CONFIG_COMPAT
++#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
++#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
++
++static long fat_compat_put_dirent32(struct dirent *d,
++ struct compat_dirent __user *d32)
++{
++ if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
++ return -EFAULT;
++
++ __put_user(d->d_ino, &d32->d_ino);
++ __put_user(d->d_off, &d32->d_off);
++ __put_user(d->d_reclen, &d32->d_reclen);
++ if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
++ return -EFAULT;
++
++ return 0;
++}
++
++static long fat_compat_dir_ioctl(struct file *file, unsigned cmd,
++ unsigned long arg)
++{
++ struct compat_dirent __user *p = compat_ptr(arg);
++ int ret;
++ mm_segment_t oldfs = get_fs();
++ struct dirent d[2];
++
++ switch (cmd) {
++ case VFAT_IOCTL_READDIR_BOTH32:
++ cmd = VFAT_IOCTL_READDIR_BOTH;
++ break;
++ case VFAT_IOCTL_READDIR_SHORT32:
++ cmd = VFAT_IOCTL_READDIR_SHORT;
++ break;
++ default:
++ return -ENOIOCTLCMD;
++ }
++
++ set_fs(KERNEL_DS);
++ lock_kernel();
++ ret = fat_dir_ioctl(file->f_dentry->d_inode, file,
++ cmd, (unsigned long) &d);
++ unlock_kernel();
++ set_fs(oldfs);
++ if (ret >= 0) {
++ ret |= fat_compat_put_dirent32(&d[0], p);
++ ret |= fat_compat_put_dirent32(&d[1], p + 1);
++ }
++ return ret;
++}
++#endif /* CONFIG_COMPAT */
++
+ const struct file_operations fat_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = fat_readdir,
+ .ioctl = fat_dir_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = fat_compat_dir_ioctl,
++#endif
+ .fsync = file_fsync,
+ };
+
+diff --git a/fs/fat/file.c b/fs/fat/file.c
+index 1ee2523..8337451 100644
+--- a/fs/fat/file.c
++++ b/fs/fat/file.c
+@@ -13,6 +13,8 @@
+ #include <linux/smp_lock.h>
+ #include <linux/buffer_head.h>
+ #include <linux/writeback.h>
++#include <linux/backing-dev.h>
++#include <linux/blkdev.h>
+
+ int fat_generic_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+@@ -112,15 +114,24 @@ int fat_generic_ioctl(struct inode *inod
+ }
+ }
+
++static int fat_file_release(struct inode *inode, struct file *filp)
++{
++ if ((filp->f_mode & FMODE_WRITE) &&
++ MSDOS_SB(inode->i_sb)->options.flush) {
++ fat_flush_inodes(inode->i_sb, inode, NULL);
++ congestion_wait(WRITE, HZ/10);
++ }
++ return 0;
++}
++
+ const struct file_operations fat_file_operations = {
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+- .readv = generic_file_readv,
+- .writev = generic_file_writev,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
++ .release = fat_file_release,
+ .ioctl = fat_generic_ioctl,
+ .fsync = file_fsync,
+ .sendfile = generic_file_sendfile,
+@@ -289,6 +300,7 @@ void fat_truncate(struct inode *inode)
+ lock_kernel();
+ fat_free(inode, nr_clusters);
+ unlock_kernel();
++ fat_flush_inodes(inode->i_sb, inode, NULL);
+ }
+
+ struct inode_operations fat_file_inode_operations = {
+diff --git a/fs/fat/inode.c b/fs/fat/inode.c
+index 31b7174..78945b5 100644
+--- a/fs/fat/inode.c
++++ b/fs/fat/inode.c
+@@ -24,6 +24,7 @@
+ #include <linux/vfs.h>
+ #include <linux/parser.h>
+ #include <linux/uio.h>
++#include <linux/writeback.h>
+ #include <asm/unaligned.h>
+
+ #ifndef CONFIG_FAT_DEFAULT_IOCHARSET
+@@ -50,14 +51,14 @@ static int fat_add_cluster(struct inode
+ return err;
+ }
+
+-static int __fat_get_blocks(struct inode *inode, sector_t iblock,
+- unsigned long *max_blocks,
+- struct buffer_head *bh_result, int create)
++static inline int __fat_get_block(struct inode *inode, sector_t iblock,
++ unsigned long *max_blocks,
++ struct buffer_head *bh_result, int create)
+ {
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+- sector_t phys;
+ unsigned long mapped_blocks;
++ sector_t phys;
+ int err, offset;
+
+ err = fat_bmap(inode, iblock, &phys, &mapped_blocks);
+@@ -73,7 +74,7 @@ static int __fat_get_blocks(struct inode
+
+ if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
+ fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
+- MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
++ MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
+ return -EIO;
+ }
+
+@@ -93,34 +94,29 @@ static int __fat_get_blocks(struct inode
+ err = fat_bmap(inode, iblock, &phys, &mapped_blocks);
+ if (err)
+ return err;
++
+ BUG_ON(!phys);
+ BUG_ON(*max_blocks != mapped_blocks);
+ set_buffer_new(bh_result);
+ map_bh(bh_result, sb, phys);
++
+ return 0;
+ }
+
+-static int fat_get_blocks(struct inode *inode, sector_t iblock,
+- struct buffer_head *bh_result, int create)
++static int fat_get_block(struct inode *inode, sector_t iblock,
++ struct buffer_head *bh_result, int create)
+ {
+ struct super_block *sb = inode->i_sb;
+- int err;
+ unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
++ int err;
+
+- err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
++ err = __fat_get_block(inode, iblock, &max_blocks, bh_result, create);
+ if (err)
+ return err;
+ bh_result->b_size = max_blocks << sb->s_blocksize_bits;
+ return 0;
+ }
+
+-static int fat_get_block(struct inode *inode, sector_t iblock,
+- struct buffer_head *bh_result, int create)
+-{
+- unsigned long max_blocks = 1;
+- return __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
+-}
+-
+ static int fat_writepage(struct page *page, struct writeback_control *wbc)
+ {
+ return block_write_full_page(page, fat_get_block, wbc);
+@@ -188,7 +184,7 @@ static ssize_t fat_direct_IO(int rw, str
+ * condition of fat_get_block() and ->truncate().
+ */
+ return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+- offset, nr_segs, fat_get_blocks, NULL);
++ offset, nr_segs, fat_get_block, NULL);
+ }
+
+ static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
+@@ -375,8 +371,6 @@ static int fat_fill_inode(struct inode *
+ inode->i_flags |= S_IMMUTABLE;
+ }
+ MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
+- /* this is as close to the truth as we can get ... */
+- inode->i_blksize = sbi->cluster_size;
+ inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
+ & ~((loff_t)sbi->cluster_size - 1)) >> 9;
+ inode->i_mtime.tv_sec =
+@@ -390,7 +384,7 @@ static int fat_fill_inode(struct inode *
+ le16_to_cpu(de->cdate)) + secs;
+ inode->i_ctime.tv_nsec = csecs * 10000000;
+ inode->i_atime.tv_sec =
+- date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate));
++ date_dos2unix(0, le16_to_cpu(de->adate));
+ inode->i_atime.tv_nsec = 0;
+ } else
+ inode->i_ctime = inode->i_atime = inode->i_mtime;
+@@ -528,8 +522,7 @@ static int __init fat_init_inodecache(vo
+
+ static void __exit fat_destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(fat_inode_cachep))
+- printk(KERN_INFO "fat_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(fat_inode_cachep);
+ }
+
+ static int fat_remount(struct super_block *sb, int *flags, char *data)
+@@ -861,7 +854,7 @@ enum {
+ Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
+ Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
+ Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
+- Opt_obsolate, Opt_err,
++ Opt_obsolate, Opt_flush, Opt_err,
+ };
+
+ static match_table_t fat_tokens = {
+@@ -893,7 +886,8 @@ static match_table_t fat_tokens = {
+ {Opt_obsolate, "cvf_format=%20s"},
+ {Opt_obsolate, "cvf_options=%100s"},
+ {Opt_obsolate, "posix"},
+- {Opt_err, NULL}
++ {Opt_flush, "flush"},
++ {Opt_err, NULL},
+ };
+ static match_table_t msdos_tokens = {
+ {Opt_nodots, "nodots"},
+@@ -1034,6 +1028,9 @@ static int parse_options(char *options,
+ return 0;
+ opts->codepage = option;
+ break;
++ case Opt_flush:
++ opts->flush = 1;
++ break;
+
+ /* msdos specific */
+ case Opt_dots:
+@@ -1137,7 +1134,6 @@ static int fat_read_root(struct inode *i
+ MSDOS_I(inode)->i_start = 0;
+ inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
+ }
+- inode->i_blksize = sbi->cluster_size;
+ inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
+ & ~((loff_t)sbi->cluster_size - 1)) >> 9;
+ MSDOS_I(inode)->i_logstart = 0;
+@@ -1168,11 +1164,10 @@ int fat_fill_super(struct super_block *s
+ long error;
+ char buf[50];
+
+- sbi = kmalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(struct msdos_sb_info));
+
+ sb->s_flags |= MS_NODIRATIME;
+ sb->s_magic = MSDOS_SUPER_MAGIC;
+@@ -1435,6 +1430,56 @@ out_fail:
+
+ EXPORT_SYMBOL_GPL(fat_fill_super);
+
++/*
++ * helper function for fat_flush_inodes. This writes both the inode
++ * and the file data blocks, waiting for in flight data blocks before
++ * the start of the call. It does not wait for any io started
++ * during the call
++ */
++static int writeback_inode(struct inode *inode)
++{
++
++ int ret;
++ struct address_space *mapping = inode->i_mapping;
++ struct writeback_control wbc = {
++ .sync_mode = WB_SYNC_NONE,
++ .nr_to_write = 0,
++ };
++ /* if we used WB_SYNC_ALL, sync_inode waits for the io for the
++ * inode to finish. So WB_SYNC_NONE is sent down to sync_inode
++ * and filemap_fdatawrite is used for the data blocks
++ */
++ ret = sync_inode(inode, &wbc);
++ if (!ret)
++ ret = filemap_fdatawrite(mapping);
++ return ret;
++}
++
++/*
++ * write data and metadata corresponding to i1 and i2. The io is
++ * started but we do not wait for any of it to finish.
++ *
++ * filemap_flush is used for the block device, so if there is a dirty
++ * page for a block already in flight, we will not wait and start the
++ * io over again
++ */
++int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
++{
++ int ret = 0;
++ if (!MSDOS_SB(sb)->options.flush)
++ return 0;
++ if (i1)
++ ret = writeback_inode(i1);
++ if (!ret && i2)
++ ret = writeback_inode(i2);
++ if (!ret) {
++ struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
++ ret = filemap_flush(mapping);
++ }
++ return ret;
++}
++EXPORT_SYMBOL_GPL(fat_flush_inodes);
++
+ static int __init init_fat_fs(void)
+ {
+ int err;
+diff --git a/fs/fcntl.c b/fs/fcntl.c
+index d35cbc6..e4f2616 100644
+--- a/fs/fcntl.c
++++ b/fs/fcntl.c
+@@ -250,19 +250,22 @@ static int setfl(int fd, struct file * f
+ return error;
+ }
+
+-static void f_modown(struct file *filp, unsigned long pid,
++static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
+ uid_t uid, uid_t euid, int force)
+ {
+ write_lock_irq(&filp->f_owner.lock);
+ if (force || !filp->f_owner.pid) {
+- filp->f_owner.pid = pid;
++ put_pid(filp->f_owner.pid);
++ filp->f_owner.pid = get_pid(pid);
++ filp->f_owner.pid_type = type;
+ filp->f_owner.uid = uid;
+ filp->f_owner.euid = euid;
+ }
+ write_unlock_irq(&filp->f_owner.lock);
+ }
+
+-int f_setown(struct file *filp, unsigned long arg, int force)
++int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
++ int force)
+ {
+ int err;
+
+@@ -270,15 +273,44 @@ int f_setown(struct file *filp, unsigned
+ if (err)
+ return err;
+
+- f_modown(filp, arg, current->uid, current->euid, force);
++ f_modown(filp, pid, type, current->uid, current->euid, force);
+ return 0;
+ }
++EXPORT_SYMBOL(__f_setown);
+
++int f_setown(struct file *filp, unsigned long arg, int force)
++{
++ enum pid_type type;
++ struct pid *pid;
++ int who = arg;
++ int result;
++ type = PIDTYPE_PID;
++ if (who < 0) {
++ type = PIDTYPE_PGID;
++ who = -who;
++ }
++ rcu_read_lock();
++ pid = find_pid(who);
++ result = __f_setown(filp, pid, type, force);
++ rcu_read_unlock();
++ return result;
++}
+ EXPORT_SYMBOL(f_setown);
+
+ void f_delown(struct file *filp)
+ {
+- f_modown(filp, 0, 0, 0, 1);
++ f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1);
++}
++
++pid_t f_getown(struct file *filp)
++{
++ pid_t pid;
++ read_lock(&filp->f_owner.lock);
++ pid = pid_nr(filp->f_owner.pid);
++ if (filp->f_owner.pid_type == PIDTYPE_PGID)
++ pid = -pid;
++ read_unlock(&filp->f_owner.lock);
++ return pid;
+ }
+
+ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
+@@ -319,7 +351,7 @@ static long do_fcntl(int fd, unsigned in
+ * current syscall conventions, the only way
+ * to fix this will be in libc.
+ */
+- err = filp->f_owner.pid;
++ err = f_getown(filp);
+ force_successful_syscall_return();
+ break;
+ case F_SETOWN:
+@@ -470,24 +502,19 @@ static void send_sigio_to_task(struct ta
+ void send_sigio(struct fown_struct *fown, int fd, int band)
+ {
+ struct task_struct *p;
+- int pid;
++ enum pid_type type;
++ struct pid *pid;
+
+ read_lock(&fown->lock);
++ type = fown->pid_type;
+ pid = fown->pid;
+ if (!pid)
+ goto out_unlock_fown;
+
+ read_lock(&tasklist_lock);
+- if (pid > 0) {
+- p = find_task_by_pid(pid);
+- if (p) {
+- send_sigio_to_task(p, fown, fd, band);
+- }
+- } else {
+- do_each_task_pid(-pid, PIDTYPE_PGID, p) {
+- send_sigio_to_task(p, fown, fd, band);
+- } while_each_task_pid(-pid, PIDTYPE_PGID, p);
+- }
++ do_each_pid_task(pid, type, p) {
++ send_sigio_to_task(p, fown, fd, band);
++ } while_each_pid_task(pid, type, p);
+ read_unlock(&tasklist_lock);
+ out_unlock_fown:
+ read_unlock(&fown->lock);
+@@ -503,9 +530,12 @@ static void send_sigurg_to_task(struct t
+ int send_sigurg(struct fown_struct *fown)
+ {
+ struct task_struct *p;
+- int pid, ret = 0;
++ enum pid_type type;
++ struct pid *pid;
++ int ret = 0;
+
+ read_lock(&fown->lock);
++ type = fown->pid_type;
+ pid = fown->pid;
+ if (!pid)
+ goto out_unlock_fown;
+@@ -513,16 +543,9 @@ int send_sigurg(struct fown_struct *fown
+ ret = 1;
+
+ read_lock(&tasklist_lock);
+- if (pid > 0) {
+- p = find_task_by_pid(pid);
+- if (p) {
+- send_sigurg_to_task(p, fown);
+- }
+- } else {
+- do_each_task_pid(-pid, PIDTYPE_PGID, p) {
+- send_sigurg_to_task(p, fown);
+- } while_each_task_pid(-pid, PIDTYPE_PGID, p);
+- }
++ do_each_pid_task(pid, type, p) {
++ send_sigurg_to_task(p, fown);
++ } while_each_pid_task(pid, type, p);
+ read_unlock(&tasklist_lock);
+ out_unlock_fown:
+ read_unlock(&fown->lock);
+diff --git a/fs/file.c b/fs/file.c
+index b3c6b82..8e81775 100644
+--- a/fs/file.c
++++ b/fs/file.c
+@@ -281,80 +281,70 @@ static struct fdtable *alloc_fdtable(int
+ out2:
+ nfds = fdt->max_fdset;
+ out:
+- if (new_openset)
+- free_fdset(new_openset, nfds);
+- if (new_execset)
+- free_fdset(new_execset, nfds);
++ free_fdset(new_openset, nfds);
++ free_fdset(new_execset, nfds);
+ kfree(fdt);
+ return NULL;
+ }
+
+ /*
+- * Expands the file descriptor table - it will allocate a new fdtable and
+- * both fd array and fdset. It is expected to be called with the
+- * files_lock held.
++ * Expand the file descriptor table.
++ * This function will allocate a new fdtable and both fd array and fdset, of
++ * the given size.
++ * Return <0 error code on error; 1 on successful completion.
++ * The files->file_lock should be held on entry, and will be held on exit.
+ */
+ static int expand_fdtable(struct files_struct *files, int nr)
+ __releases(files->file_lock)
+ __acquires(files->file_lock)
+ {
+- int error = 0;
+- struct fdtable *fdt;
+- struct fdtable *nfdt = NULL;
++ struct fdtable *new_fdt, *cur_fdt;
+
+ spin_unlock(&files->file_lock);
+- nfdt = alloc_fdtable(nr);
+- if (!nfdt) {
+- error = -ENOMEM;
+- spin_lock(&files->file_lock);
+- goto out;
+- }
+-
++ new_fdt = alloc_fdtable(nr);
+ spin_lock(&files->file_lock);
+- fdt = files_fdtable(files);
++ if (!new_fdt)
++ return -ENOMEM;
+ /*
+- * Check again since another task may have expanded the
+- * fd table while we dropped the lock
++ * Check again since another task may have expanded the fd table while
++ * we dropped the lock
+ */
+- if (nr >= fdt->max_fds || nr >= fdt->max_fdset) {
+- copy_fdtable(nfdt, fdt);
++ cur_fdt = files_fdtable(files);
++ if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) {
++ /* Continue as planned */
++ copy_fdtable(new_fdt, cur_fdt);
++ rcu_assign_pointer(files->fdt, new_fdt);
++ free_fdtable(cur_fdt);
+ } else {
+- /* Somebody expanded while we dropped file_lock */
+- spin_unlock(&files->file_lock);
+- __free_fdtable(nfdt);
+- spin_lock(&files->file_lock);
+- goto out;
++ /* Somebody else expanded, so undo our attempt */
++ __free_fdtable(new_fdt);
+ }
+- rcu_assign_pointer(files->fdt, nfdt);
+- free_fdtable(fdt);
+-out:
+- return error;
++ return 1;
+ }
+
+ /*
+ * Expand files.
+- * Return <0 on error; 0 nothing done; 1 files expanded, we may have blocked.
+- * Should be called with the files->file_lock spinlock held for write.
++ * This function will expand the file structures, if the requested size exceeds
++ * the current capacity and there is room for expansion.
++ * Return <0 error code on error; 0 when nothing done; 1 when files were
++ * expanded and execution may have blocked.
++ * The files->file_lock should be held on entry, and will be held on exit.
+ */
+ int expand_files(struct files_struct *files, int nr)
+ {
+- int err, expand = 0;
+ struct fdtable *fdt;
+
+ fdt = files_fdtable(files);
+- if (nr >= fdt->max_fdset || nr >= fdt->max_fds) {
+- if (fdt->max_fdset >= NR_OPEN ||
+- fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) {
+- err = -EMFILE;
+- goto out;
+- }
+- expand = 1;
+- if ((err = expand_fdtable(files, nr)))
+- goto out;
+- }
+- err = expand;
+-out:
+- return err;
++ /* Do we need to expand? */
++ if (nr < fdt->max_fdset && nr < fdt->max_fds)
++ return 0;
++ /* Can we expand? */
++ if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
++ nr >= NR_OPEN)
++ return -EMFILE;
++
++ /* All good, so we try */
++ return expand_fdtable(files, nr);
+ }
+
+ static void __devinit fdtable_defer_list_init(int cpu)
+diff --git a/fs/file_table.c b/fs/file_table.c
+index 0131ba0..24f25a0 100644
+--- a/fs/file_table.c
++++ b/fs/file_table.c
+@@ -169,11 +169,12 @@ void fastcall __fput(struct file *file)
+ if (file->f_op && file->f_op->release)
+ file->f_op->release(inode, file);
+ security_file_free(file);
+- if (unlikely(inode->i_cdev != NULL))
++ if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
+ cdev_put(inode->i_cdev);
+ fops_put(file->f_op);
+ if (file->f_mode & FMODE_WRITE)
+ put_write_access(inode);
++ put_pid(file->f_owner.pid);
+ file_kill(file);
+ file->f_dentry = NULL;
+ file->f_vfsmnt = NULL;
+diff --git a/fs/filesystems.c b/fs/filesystems.c
+index 9f10728..e3fa77c 100644
+--- a/fs/filesystems.c
++++ b/fs/filesystems.c
+@@ -69,8 +69,6 @@ int register_filesystem(struct file_syst
+ int res = 0;
+ struct file_system_type ** p;
+
+- if (!fs)
+- return -EINVAL;
+ if (fs->next)
+ return -EBUSY;
+ INIT_LIST_HEAD(&fs->fs_supers);
+diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
+index d35979a..c8a9265 100644
+--- a/fs/freevxfs/vxfs.h
++++ b/fs/freevxfs/vxfs.h
+@@ -252,7 +252,7 @@ enum {
+ * Get filesystem private data from VFS inode.
+ */
+ #define VXFS_INO(ip) \
+- ((struct vxfs_inode_info *)(ip)->u.generic_ip)
++ ((struct vxfs_inode_info *)(ip)->i_private)
+
+ /*
+ * Get filesystem private data from VFS superblock.
+diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
+index ca6a397..4786d51 100644
+--- a/fs/freevxfs/vxfs_inode.c
++++ b/fs/freevxfs/vxfs_inode.c
+@@ -239,11 +239,10 @@ vxfs_iinit(struct inode *ip, struct vxfs
+ ip->i_ctime.tv_nsec = 0;
+ ip->i_mtime.tv_nsec = 0;
+
+- ip->i_blksize = PAGE_SIZE;
+ ip->i_blocks = vip->vii_blocks;
+ ip->i_generation = vip->vii_gen;
+
+- ip->u.generic_ip = (void *)vip;
++ ip->i_private = vip;
+
+ }
+
+@@ -338,5 +337,5 @@ vxfs_read_inode(struct inode *ip)
+ void
+ vxfs_clear_inode(struct inode *ip)
+ {
+- kmem_cache_free(vxfs_inode_cachep, ip->u.generic_ip);
++ kmem_cache_free(vxfs_inode_cachep, ip->i_private);
+ }
+diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
+index b74b791..ac28b08 100644
+--- a/fs/freevxfs/vxfs_super.c
++++ b/fs/freevxfs/vxfs_super.c
+@@ -260,12 +260,17 @@ static struct file_system_type vxfs_fs_t
+ static int __init
+ vxfs_init(void)
+ {
++ int rv;
++
+ vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
+ sizeof(struct vxfs_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+- if (vxfs_inode_cachep)
+- return register_filesystem(&vxfs_fs_type);
+- return -ENOMEM;
++ if (!vxfs_inode_cachep)
++ return -ENOMEM;
++ rv = register_filesystem(&vxfs_fs_type);
++ if (rv < 0)
++ kmem_cache_destroy(vxfs_inode_cachep);
++ return rv;
+ }
+
+ static void __exit
+diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
+index 892643d..c403b66 100644
+--- a/fs/fs-writeback.c
++++ b/fs/fs-writeback.c
+@@ -22,8 +22,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/backing-dev.h>
+ #include <linux/buffer_head.h>
+-
+-extern struct super_block *blockdev_superblock;
++#include "internal.h"
+
+ /**
+ * __mark_inode_dirty - internal function
+@@ -320,7 +319,7 @@ sync_sb_inodes(struct super_block *sb, s
+
+ if (!bdi_cap_writeback_dirty(bdi)) {
+ list_move(&inode->i_list, &sb->s_dirty);
+- if (sb == blockdev_superblock) {
++ if (sb_is_blkdev_sb(sb)) {
+ /*
+ * Dirty memory-backed blockdev: the ramdisk
+ * driver does this. Skip just this inode
+@@ -337,14 +336,14 @@ sync_sb_inodes(struct super_block *sb, s
+
+ if (wbc->nonblocking && bdi_write_congested(bdi)) {
+ wbc->encountered_congestion = 1;
+- if (sb != blockdev_superblock)
++ if (!sb_is_blkdev_sb(sb))
+ break; /* Skip a congested fs */
+ list_move(&inode->i_list, &sb->s_dirty);
+ continue; /* Skip a congested blockdev */
+ }
+
+ if (wbc->bdi && bdi != wbc->bdi) {
+- if (sb != blockdev_superblock)
++ if (!sb_is_blkdev_sb(sb))
+ break; /* fs has the wrong queue */
+ list_move(&inode->i_list, &sb->s_dirty);
+ continue; /* blockdev has wrong queue */
+diff --git a/fs/fuse/control.c b/fs/fuse/control.c
+index 46fe60b..16b39c0 100644
+--- a/fs/fuse/control.c
++++ b/fs/fuse/control.c
+@@ -23,7 +23,7 @@ static struct fuse_conn *fuse_ctl_file_c
+ {
+ struct fuse_conn *fc;
+ mutex_lock(&fuse_mutex);
+- fc = file->f_dentry->d_inode->u.generic_ip;
++ fc = file->f_dentry->d_inode->i_private;
+ if (fc)
+ fc = fuse_conn_get(fc);
+ mutex_unlock(&fuse_mutex);
+@@ -98,7 +98,7 @@ static struct dentry *fuse_ctl_add_dentr
+ inode->i_op = iop;
+ inode->i_fop = fop;
+ inode->i_nlink = nlink;
+- inode->u.generic_ip = fc;
++ inode->i_private = fc;
+ d_add(dentry, inode);
+ return dentry;
+ }
+@@ -116,7 +116,7 @@ int fuse_ctl_add_conn(struct fuse_conn *
+ return 0;
+
+ parent = fuse_control_sb->s_root;
+- parent->d_inode->i_nlink++;
++ inc_nlink(parent->d_inode);
+ sprintf(name, "%llu", (unsigned long long) fc->id);
+ parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
+ &simple_dir_inode_operations,
+@@ -150,7 +150,7 @@ void fuse_ctl_remove_conn(struct fuse_co
+
+ for (i = fc->ctl_ndents - 1; i >= 0; i--) {
+ struct dentry *dentry = fc->ctl_dentry[i];
+- dentry->d_inode->u.generic_ip = NULL;
++ dentry->d_inode->i_private = NULL;
+ d_drop(dentry);
+ dput(dentry);
+ }
+diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
+index 1e2006c..66571ea 100644
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -212,6 +212,7 @@ void fuse_put_request(struct fuse_conn *
+ * Called with fc->lock, unlocks it
+ */
+ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
++ __releases(fc->lock)
+ {
+ void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+ req->end = NULL;
+@@ -640,6 +641,7 @@ static void request_wait(struct fuse_con
+ */
+ static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
+ const struct iovec *iov, unsigned long nr_segs)
++ __releases(fc->lock)
+ {
+ struct fuse_copy_state cs;
+ struct fuse_in_header ih;
+@@ -678,14 +680,15 @@ static int fuse_read_interrupt(struct fu
+ * request_end(). Otherwise add it to the processing list, and set
+ * the 'sent' flag.
+ */
+-static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *off)
++static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ int err;
+ struct fuse_req *req;
+ struct fuse_in *in;
+ struct fuse_copy_state cs;
+ unsigned reqsize;
++ struct file *file = iocb->ki_filp;
+ struct fuse_conn *fc = fuse_get_conn(file);
+ if (!fc)
+ return -EPERM;
+@@ -759,15 +762,6 @@ static ssize_t fuse_dev_readv(struct fil
+ return err;
+ }
+
+-static ssize_t fuse_dev_read(struct file *file, char __user *buf,
+- size_t nbytes, loff_t *off)
+-{
+- struct iovec iov;
+- iov.iov_len = nbytes;
+- iov.iov_base = buf;
+- return fuse_dev_readv(file, &iov, 1, off);
+-}
+-
+ /* Look up request on processing list by unique ID */
+ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
+ {
+@@ -812,15 +806,15 @@ static int copy_out_args(struct fuse_cop
+ * it from the list and copy the rest of the buffer to the request.
+ * The request is finished by calling request_end()
+ */
+-static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *off)
++static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ int err;
+ unsigned nbytes = iov_length(iov, nr_segs);
+ struct fuse_req *req;
+ struct fuse_out_header oh;
+ struct fuse_copy_state cs;
+- struct fuse_conn *fc = fuse_get_conn(file);
++ struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
+ if (!fc)
+ return -EPERM;
+
+@@ -896,15 +890,6 @@ static ssize_t fuse_dev_writev(struct fi
+ return err;
+ }
+
+-static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
+- size_t nbytes, loff_t *off)
+-{
+- struct iovec iov;
+- iov.iov_len = nbytes;
+- iov.iov_base = (char __user *) buf;
+- return fuse_dev_writev(file, &iov, 1, off);
+-}
+-
+ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
+ {
+ unsigned mask = POLLOUT | POLLWRNORM;
+@@ -1039,10 +1024,10 @@ static int fuse_dev_fasync(int fd, struc
+ const struct file_operations fuse_dev_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+- .read = fuse_dev_read,
+- .readv = fuse_dev_readv,
+- .write = fuse_dev_write,
+- .writev = fuse_dev_writev,
++ .read = do_sync_read,
++ .aio_read = fuse_dev_read,
++ .write = do_sync_write,
++ .aio_write = fuse_dev_write,
+ .poll = fuse_dev_poll,
+ .release = fuse_dev_release,
+ .fasync = fuse_dev_fasync,
+diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
+index 409ce6a..cfc8f81 100644
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -138,6 +138,7 @@ static int fuse_dentry_revalidate(struct
+ struct fuse_entry_out outarg;
+ struct fuse_conn *fc;
+ struct fuse_req *req;
++ struct dentry *parent;
+
+ /* Doesn't hurt to "reset" the validity timeout */
+ fuse_invalidate_entry_cache(entry);
+@@ -151,8 +152,10 @@ static int fuse_dentry_revalidate(struct
+ if (IS_ERR(req))
+ return 0;
+
+- fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
++ parent = dget_parent(entry);
++ fuse_lookup_init(req, parent->d_inode, entry, &outarg);
+ request_send(fc, req);
++ dput(parent);
+ err = req->out.h.error;
+ /* Zero nodeid is same as -ENOENT */
+ if (!err && !outarg.nodeid)
+@@ -163,7 +166,9 @@ static int fuse_dentry_revalidate(struct
+ fuse_send_forget(fc, req, outarg.nodeid, 1);
+ return 0;
+ }
++ spin_lock(&fc->lock);
+ fi->nlookup ++;
++ spin_unlock(&fc->lock);
+ }
+ fuse_put_request(fc, req);
+ if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
+@@ -175,22 +180,6 @@ static int fuse_dentry_revalidate(struct
+ return 1;
+ }
+
+-/*
+- * Check if there's already a hashed alias of this directory inode.
+- * If yes, then lookup and mkdir must not create a new alias.
+- */
+-static int dir_alias(struct inode *inode)
+-{
+- if (S_ISDIR(inode->i_mode)) {
+- struct dentry *alias = d_find_alias(inode);
+- if (alias) {
+- dput(alias);
+- return 1;
+- }
+- }
+- return 0;
+-}
+-
+ static int invalid_nodeid(u64 nodeid)
+ {
+ return !nodeid || nodeid == FUSE_ROOT_ID;
+@@ -206,6 +195,24 @@ static int valid_mode(int m)
+ S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
+ }
+
++/*
++ * Add a directory inode to a dentry, ensuring that no other dentry
++ * refers to this inode. Called with fc->inst_mutex.
++ */
++static int fuse_d_add_directory(struct dentry *entry, struct inode *inode)
++{
++ struct dentry *alias = d_find_alias(inode);
++ if (alias) {
++ /* This tries to shrink the subtree below alias */
++ fuse_invalidate_entry(alias);
++ dput(alias);
++ if (!list_empty(&inode->i_dentry))
++ return -EBUSY;
++ }
++ d_add(entry, inode);
++ return 0;
++}
++
+ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
+ struct nameidata *nd)
+ {
+@@ -241,11 +248,17 @@ static struct dentry *fuse_lookup(struct
+ if (err && err != -ENOENT)
+ return ERR_PTR(err);
+
+- if (inode && dir_alias(inode)) {
+- iput(inode);
+- return ERR_PTR(-EIO);
+- }
+- d_add(entry, inode);
++ if (inode && S_ISDIR(inode->i_mode)) {
++ mutex_lock(&fc->inst_mutex);
++ err = fuse_d_add_directory(entry, inode);
++ mutex_unlock(&fc->inst_mutex);
++ if (err) {
++ iput(inode);
++ return ERR_PTR(err);
++ }
++ } else
++ d_add(entry, inode);
++
+ entry->d_op = &fuse_dentry_operations;
+ if (!err)
+ fuse_change_timeout(entry, &outarg);
+@@ -401,12 +414,22 @@ static int create_new_entry(struct fuse_
+ }
+ fuse_put_request(fc, req);
+
+- if (dir_alias(inode)) {
+- iput(inode);
+- return -EIO;
+- }
++ if (S_ISDIR(inode->i_mode)) {
++ struct dentry *alias;
++ mutex_lock(&fc->inst_mutex);
++ alias = d_find_alias(inode);
++ if (alias) {
++ /* New directory must have moved since mkdir */
++ mutex_unlock(&fc->inst_mutex);
++ dput(alias);
++ iput(inode);
++ return -EBUSY;
++ }
++ d_instantiate(entry, inode);
++ mutex_unlock(&fc->inst_mutex);
++ } else
++ d_instantiate(entry, inode);
+
+- d_instantiate(entry, inode);
+ fuse_change_timeout(entry, &outarg);
+ fuse_invalidate_attr(dir);
+ return 0;
+@@ -508,7 +531,7 @@ static int fuse_unlink(struct inode *dir
+ /* Set nlink to zero so the inode can be cleared, if
+ the inode does have more links this will be
+ discovered at the next lookup/getattr */
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ fuse_invalidate_attr(inode);
+ fuse_invalidate_attr(dir);
+ fuse_invalidate_entry_cache(entry);
+@@ -534,7 +557,7 @@ static int fuse_rmdir(struct inode *dir,
+ err = req->out.h.error;
+ fuse_put_request(fc, req);
+ if (!err) {
+- entry->d_inode->i_nlink = 0;
++ clear_nlink(entry->d_inode);
+ fuse_invalidate_attr(dir);
+ fuse_invalidate_entry_cache(entry);
+ } else if (err == -EINTR)
+@@ -776,7 +799,7 @@ static int fuse_permission(struct inode
+ if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
+ return -EACCES;
+
+- if (nd && (nd->flags & LOOKUP_ACCESS))
++ if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR)))
+ return fuse_access(inode, mask);
+ return 0;
+ }
+@@ -935,14 +958,30 @@ static void iattr_to_fattr(struct iattr
+ }
+ }
+
++static void fuse_vmtruncate(struct inode *inode, loff_t offset)
++{
++ struct fuse_conn *fc = get_fuse_conn(inode);
++ int need_trunc;
++
++ spin_lock(&fc->lock);
++ need_trunc = inode->i_size > offset;
++ i_size_write(inode, offset);
++ spin_unlock(&fc->lock);
++
++ if (need_trunc) {
++ struct address_space *mapping = inode->i_mapping;
++ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
++ truncate_inode_pages(mapping, offset);
++ }
++}
++
+ /*
+ * Set attributes, and at the same time refresh them.
+ *
+ * Truncation is slightly complicated, because the 'truncate' request
+ * may fail, in which case we don't want to touch the mapping.
+- * vmtruncate() doesn't allow for this case. So do the rlimit
+- * checking by hand and call vmtruncate() only after the file has
+- * actually been truncated.
++ * vmtruncate() doesn't allow for this case, so do the rlimit checking
++ * and the actual truncation by hand.
+ */
+ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
+ {
+@@ -993,12 +1032,8 @@ static int fuse_setattr(struct dentry *e
+ make_bad_inode(inode);
+ err = -EIO;
+ } else {
+- if (is_truncate) {
+- loff_t origsize = i_size_read(inode);
+- i_size_write(inode, outarg.attr.size);
+- if (origsize > outarg.attr.size)
+- vmtruncate(inode, outarg.attr.size);
+- }
++ if (is_truncate)
++ fuse_vmtruncate(inode, outarg.attr.size);
+ fuse_change_attributes(inode, &outarg.attr);
+ fi->i_time = time_to_jiffies(outarg.attr_valid,
+ outarg.attr_valid_nsec);
+diff --git a/fs/fuse/file.c b/fs/fuse/file.c
+index 5c4fcd1..763a50d 100644
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -397,14 +397,14 @@ static int fuse_readpages(struct file *f
+
+ err = -EIO;
+ if (is_bad_inode(inode))
+- goto clean_pages_up;
++ goto out;
+
+ data.file = file;
+ data.inode = inode;
+ data.req = fuse_get_req(fc);
+ err = PTR_ERR(data.req);
+ if (IS_ERR(data.req))
+- goto clean_pages_up;
++ goto out;
+
+ err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
+ if (!err) {
+@@ -413,10 +413,7 @@ static int fuse_readpages(struct file *f
+ else
+ fuse_put_request(fc, data.req);
+ }
+- return err;
+-
+-clean_pages_up:
+- put_pages_list(pages);
++out:
+ return err;
+ }
+
+@@ -481,8 +478,10 @@ static int fuse_commit_write(struct file
+ err = -EIO;
+ if (!err) {
+ pos += count;
+- if (pos > i_size_read(inode))
++ spin_lock(&fc->lock);
++ if (pos > inode->i_size)
+ i_size_write(inode, pos);
++ spin_unlock(&fc->lock);
+
+ if (offset == 0 && to == PAGE_CACHE_SIZE) {
+ clear_page_dirty(page);
+@@ -586,8 +585,12 @@ static ssize_t fuse_direct_io(struct fil
+ }
+ fuse_put_request(fc, req);
+ if (res > 0) {
+- if (write && pos > i_size_read(inode))
+- i_size_write(inode, pos);
++ if (write) {
++ spin_lock(&fc->lock);
++ if (pos > inode->i_size)
++ i_size_write(inode, pos);
++ spin_unlock(&fc->lock);
++ }
+ *ppos = pos;
+ }
+ fuse_invalidate_attr(inode);
+@@ -753,8 +756,10 @@ static int fuse_file_lock(struct file *f
+
+ static const struct file_operations fuse_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = fuse_file_mmap,
+ .open = fuse_open,
+ .flush = fuse_flush,
+diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
+index 69c7750..91edb89 100644
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -239,6 +239,9 @@ struct fuse_conn {
+ /** Lock protecting accessess to members of this structure */
+ spinlock_t lock;
+
++ /** Mutex protecting against directory alias creation */
++ struct mutex inst_mutex;
++
+ /** Refcount */
+ atomic_t count;
+
+diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
+index 7d25092..fc42035 100644
+--- a/fs/fuse/inode.c
++++ b/fs/fuse/inode.c
+@@ -109,6 +109,7 @@ static int fuse_remount_fs(struct super_
+
+ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
+ {
++ struct fuse_conn *fc = get_fuse_conn(inode);
+ if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
+ invalidate_inode_pages(inode->i_mapping);
+
+@@ -117,8 +118,9 @@ void fuse_change_attributes(struct inode
+ inode->i_nlink = attr->nlink;
+ inode->i_uid = attr->uid;
+ inode->i_gid = attr->gid;
++ spin_lock(&fc->lock);
+ i_size_write(inode, attr->size);
+- inode->i_blksize = PAGE_CACHE_SIZE;
++ spin_unlock(&fc->lock);
+ inode->i_blocks = attr->blocks;
+ inode->i_atime.tv_sec = attr->atime;
+ inode->i_atime.tv_nsec = attr->atimensec;
+@@ -131,7 +133,7 @@ void fuse_change_attributes(struct inode
+ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
+ {
+ inode->i_mode = attr->mode & S_IFMT;
+- i_size_write(inode, attr->size);
++ inode->i_size = attr->size;
+ if (S_ISREG(inode->i_mode)) {
+ fuse_init_common(inode);
+ fuse_init_file_inode(inode);
+@@ -170,7 +172,6 @@ struct inode *fuse_iget(struct super_blo
+ struct inode *inode;
+ struct fuse_inode *fi;
+ struct fuse_conn *fc = get_fuse_conn_super(sb);
+- int retried = 0;
+
+ retry:
+ inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
+@@ -184,16 +185,16 @@ struct inode *fuse_iget(struct super_blo
+ fuse_init_inode(inode, attr);
+ unlock_new_inode(inode);
+ } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
+- BUG_ON(retried);
+ /* Inode has changed type, any I/O on the old should fail */
+ make_bad_inode(inode);
+ iput(inode);
+- retried = 1;
+ goto retry;
+ }
+
+ fi = get_fuse_inode(inode);
++ spin_lock(&fc->lock);
+ fi->nlookup ++;
++ spin_unlock(&fc->lock);
+ fuse_change_attributes(inode, attr);
+ return inode;
+ }
+@@ -252,6 +253,7 @@ static int fuse_statfs(struct dentry *de
+ memset(&outarg, 0, sizeof(outarg));
+ req->in.numargs = 0;
+ req->in.h.opcode = FUSE_STATFS;
++ req->in.h.nodeid = get_node_id(dentry->d_inode);
+ req->out.numargs = 1;
+ req->out.args[0].size =
+ fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
+@@ -377,6 +379,7 @@ static struct fuse_conn *new_conn(void)
+ fc = kzalloc(sizeof(*fc), GFP_KERNEL);
+ if (fc) {
+ spin_lock_init(&fc->lock);
++ mutex_init(&fc->inst_mutex);
+ atomic_set(&fc->count, 1);
+ init_waitqueue_head(&fc->waitq);
+ init_waitqueue_head(&fc->blocked_waitq);
+@@ -396,8 +399,10 @@ static struct fuse_conn *new_conn(void)
+
+ void fuse_conn_put(struct fuse_conn *fc)
+ {
+- if (atomic_dec_and_test(&fc->count))
++ if (atomic_dec_and_test(&fc->count)) {
++ mutex_destroy(&fc->inst_mutex);
+ kfree(fc);
++ }
+ }
+
+ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
+diff --git a/fs/generic_acl.c b/fs/generic_acl.c
+new file mode 100644
+index 0000000..9ccb789
+--- /dev/null
++++ b/fs/generic_acl.c
+@@ -0,0 +1,197 @@
++/*
++ * fs/generic_acl.c
++ *
++ * (C) 2005 Andreas Gruenbacher <agruen at suse.de>
++ *
++ * This file is released under the GPL.
++ */
++
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/generic_acl.h>
++
++/**
++ * generic_acl_list - Generic xattr_handler->list() operation
++ * @ops: Filesystem specific getacl and setacl callbacks
++ */
++size_t
++generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
++ int type, char *list, size_t list_size)
++{
++ struct posix_acl *acl;
++ const char *name;
++ size_t size;
++
++ acl = ops->getacl(inode, type);
++ if (!acl)
++ return 0;
++ posix_acl_release(acl);
++
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ name = POSIX_ACL_XATTR_ACCESS;
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ name = POSIX_ACL_XATTR_DEFAULT;
++ break;
++
++ default:
++ return 0;
++ }
++ size = strlen(name) + 1;
++ if (list && size <= list_size)
++ memcpy(list, name, size);
++ return size;
++}
++
++/**
++ * generic_acl_get - Generic xattr_handler->get() operation
++ * @ops: Filesystem specific getacl and setacl callbacks
++ */
++int
++generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
++ int type, void *buffer, size_t size)
++{
++ struct posix_acl *acl;
++ int error;
++
++ acl = ops->getacl(inode, type);
++ if (!acl)
++ return -ENODATA;
++ error = posix_acl_to_xattr(acl, buffer, size);
++ posix_acl_release(acl);
++
++ return error;
++}
++
++/**
++ * generic_acl_set - Generic xattr_handler->set() operation
++ * @ops: Filesystem specific getacl and setacl callbacks
++ */
++int
++generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
++ int type, const void *value, size_t size)
++{
++ struct posix_acl *acl = NULL;
++ int error;
++
++ if (S_ISLNK(inode->i_mode))
++ return -EOPNOTSUPP;
++ if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
++ return -EPERM;
++ if (value) {
++ acl = posix_acl_from_xattr(value, size);
++ if (IS_ERR(acl))
++ return PTR_ERR(acl);
++ }
++ if (acl) {
++ mode_t mode;
++
++ error = posix_acl_valid(acl);
++ if (error)
++ goto failed;
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ mode = inode->i_mode;
++ error = posix_acl_equiv_mode(acl, &mode);
++ if (error < 0)
++ goto failed;
++ inode->i_mode = mode;
++ if (error == 0) {
++ posix_acl_release(acl);
++ acl = NULL;
++ }
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ if (!S_ISDIR(inode->i_mode)) {
++ error = -EINVAL;
++ goto failed;
++ }
++ break;
++ }
++ }
++ ops->setacl(inode, type, acl);
++ error = 0;
++failed:
++ posix_acl_release(acl);
++ return error;
++}
++
++/**
++ * generic_acl_init - Take care of acl inheritance at @inode create time
++ * @ops: Filesystem specific getacl and setacl callbacks
++ *
++ * Files created inside a directory with a default ACL inherit the
++ * directory's default ACL.
++ */
++int
++generic_acl_init(struct inode *inode, struct inode *dir,
++ struct generic_acl_operations *ops)
++{
++ struct posix_acl *acl = NULL;
++ mode_t mode = inode->i_mode;
++ int error;
++
++ inode->i_mode = mode & ~current->fs->umask;
++ if (!S_ISLNK(inode->i_mode))
++ acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
++ if (acl) {
++ struct posix_acl *clone;
++
++ if (S_ISDIR(inode->i_mode)) {
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ error = -ENOMEM;
++ if (!clone)
++ goto cleanup;
++ ops->setacl(inode, ACL_TYPE_DEFAULT, clone);
++ posix_acl_release(clone);
++ }
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ error = -ENOMEM;
++ if (!clone)
++ goto cleanup;
++ error = posix_acl_create_masq(clone, &mode);
++ if (error >= 0) {
++ inode->i_mode = mode;
++ if (error > 0)
++ ops->setacl(inode, ACL_TYPE_ACCESS, clone);
++ }
++ posix_acl_release(clone);
++ }
++ error = 0;
++
++cleanup:
++ posix_acl_release(acl);
++ return error;
++}
++
++/**
++ * generic_acl_chmod - change the access acl of @inode upon chmod()
++ * @ops: FIlesystem specific getacl and setacl callbacks
++ *
++ * A chmod also changes the permissions of the owner, group/mask, and
++ * other ACL entries.
++ */
++int
++generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
++{
++ struct posix_acl *acl, *clone;
++ int error = 0;
++
++ if (S_ISLNK(inode->i_mode))
++ return -EOPNOTSUPP;
++ acl = ops->getacl(inode, ACL_TYPE_ACCESS);
++ if (acl) {
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ posix_acl_release(acl);
++ if (!clone)
++ return -ENOMEM;
++ error = posix_acl_chmod_masq(clone, inode->i_mode);
++ if (!error)
++ ops->setacl(inode, ACL_TYPE_ACCESS, clone);
++ posix_acl_release(clone);
++ }
++ return error;
++}
+diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
+new file mode 100644
+index 0000000..8c27de8
+--- /dev/null
++++ b/fs/gfs2/Kconfig
+@@ -0,0 +1,44 @@
++config GFS2_FS
++ tristate "GFS2 file system support"
++ depends on EXPERIMENTAL
++ select FS_POSIX_ACL
++ help
++ A cluster filesystem.
++
++ Allows a cluster of computers to simultaneously use a block device
++ that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads
++ and writes to the block device like a local filesystem, but also uses
++ a lock module to allow the computers coordinate their I/O so
++ filesystem consistency is maintained. One of the nifty features of
++ GFS is perfect consistency -- changes made to the filesystem on one
++ machine show up immediately on all other machines in the cluster.
++
++ To use the GFS2 filesystem, you will need to enable one or more of
++ the below locking modules. Documentation and utilities for GFS2 can
++ be found here: http://sources.redhat.com/cluster
++
++config GFS2_FS_LOCKING_NOLOCK
++ tristate "GFS2 \"nolock\" locking module"
++ depends on GFS2_FS
++ help
++ Single node locking module for GFS2.
++
++ Use this module if you want to use GFS2 on a single node without
++ its clustering features. You can still take advantage of the
++ large file support, and upgrade to running a full cluster later on
++ if required.
++
++ If you will only be using GFS2 in cluster mode, you do not need this
++ module.
++
++config GFS2_FS_LOCKING_DLM
++ tristate "GFS2 DLM locking module"
++ depends on GFS2_FS
++ select DLM
++ help
++ Multiple node locking module for GFS2
++
++ Most users of GFS2 will require this module. It provides the locking
++ interface between GFS2 and the DLM, which is required to use GFS2
++ in a cluster environment.
++
+diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
+new file mode 100644
+index 0000000..e3f1ada
+--- /dev/null
++++ b/fs/gfs2/Makefile
+@@ -0,0 +1,10 @@
++obj-$(CONFIG_GFS2_FS) += gfs2.o
++gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
++ glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \
++ mount.o ondisk.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
++ ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \
++ recovery.o rgrp.o super.o sys.o trans.o util.o
++
++obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/
++obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/
++
+diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
+new file mode 100644
+index 0000000..5f959b8
+--- /dev/null
++++ b/fs/gfs2/acl.c
+@@ -0,0 +1,309 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/posix_acl.h>
++#include <linux/posix_acl_xattr.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "acl.h"
++#include "eaops.h"
++#include "eattr.h"
++#include "glock.h"
++#include "inode.h"
++#include "meta_io.h"
++#include "trans.h"
++#include "util.h"
++
++#define ACL_ACCESS 1
++#define ACL_DEFAULT 0
++
++int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
++ struct gfs2_ea_request *er,
++ int *remove, mode_t *mode)
++{
++ struct posix_acl *acl;
++ int error;
++
++ error = gfs2_acl_validate_remove(ip, access);
++ if (error)
++ return error;
++
++ if (!er->er_data)
++ return -EINVAL;
++
++ acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
++ if (IS_ERR(acl))
++ return PTR_ERR(acl);
++ if (!acl) {
++ *remove = 1;
++ return 0;
++ }
++
++ error = posix_acl_valid(acl);
++ if (error)
++ goto out;
++
++ if (access) {
++ error = posix_acl_equiv_mode(acl, mode);
++ if (!error)
++ *remove = 1;
++ else if (error > 0)
++ error = 0;
++ }
++
++out:
++ posix_acl_release(acl);
++ return error;
++}
++
++int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
++{
++ if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
++ return -EOPNOTSUPP;
++ if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER))
++ return -EPERM;
++ if (S_ISLNK(ip->i_di.di_mode))
++ return -EOPNOTSUPP;
++ if (!access && !S_ISDIR(ip->i_di.di_mode))
++ return -EACCES;
++
++ return 0;
++}
++
++static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
++ struct gfs2_ea_location *el, char **data, unsigned int *len)
++{
++ struct gfs2_ea_request er;
++ struct gfs2_ea_location el_this;
++ int error;
++
++ if (!ip->i_di.di_eattr)
++ return 0;
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++ if (access) {
++ er.er_name = GFS2_POSIX_ACL_ACCESS;
++ er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
++ } else {
++ er.er_name = GFS2_POSIX_ACL_DEFAULT;
++ er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
++ }
++ er.er_type = GFS2_EATYPE_SYS;
++
++ if (!el)
++ el = &el_this;
++
++ error = gfs2_ea_find(ip, &er, el);
++ if (error)
++ return error;
++ if (!el->el_ea)
++ return 0;
++ if (!GFS2_EA_DATA_LEN(el->el_ea))
++ goto out;
++
++ er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
++ er.er_data = kmalloc(er.er_data_len, GFP_KERNEL);
++ error = -ENOMEM;
++ if (!er.er_data)
++ goto out;
++
++ error = gfs2_ea_get_copy(ip, el, er.er_data);
++ if (error)
++ goto out_kfree;
++
++ if (acl) {
++ *acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
++ if (IS_ERR(*acl))
++ error = PTR_ERR(*acl);
++ }
++
++out_kfree:
++ if (error || !data)
++ kfree(er.er_data);
++ else {
++ *data = er.er_data;
++ *len = er.er_data_len;
++ }
++out:
++ if (error || el == &el_this)
++ brelse(el->el_bh);
++ return error;
++}
++
++/**
++ * gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something
++ * @inode: the file we want to do something to
++ * @mask: what we want to do
++ *
++ * Returns: errno
++ */
++
++int gfs2_check_acl_locked(struct inode *inode, int mask)
++{
++ struct posix_acl *acl = NULL;
++ int error;
++
++ error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
++ if (error)
++ return error;
++
++ if (acl) {
++ error = posix_acl_permission(inode, acl, mask);
++ posix_acl_release(acl);
++ return error;
++ }
++
++ return -EAGAIN;
++}
++
++int gfs2_check_acl(struct inode *inode, int mask)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder i_gh;
++ int error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
++ if (!error) {
++ error = gfs2_check_acl_locked(inode, mask);
++ gfs2_glock_dq_uninit(&i_gh);
++ }
++
++ return error;
++}
++
++static int munge_mode(struct gfs2_inode *ip, mode_t mode)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
++ if (error)
++ return error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ gfs2_assert_withdraw(sdp,
++ (ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT));
++ ip->i_di.di_mode = mode;
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(sdp);
++
++ return 0;
++}
++
++int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct posix_acl *acl = NULL, *clone;
++ struct gfs2_ea_request er;
++ mode_t mode = ip->i_di.di_mode;
++ int error;
++
++ if (!sdp->sd_args.ar_posix_acl)
++ return 0;
++ if (S_ISLNK(ip->i_di.di_mode))
++ return 0;
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++ er.er_type = GFS2_EATYPE_SYS;
++
++ error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
++ &er.er_data, &er.er_data_len);
++ if (error)
++ return error;
++ if (!acl) {
++ mode &= ~current->fs->umask;
++ if (mode != ip->i_di.di_mode)
++ error = munge_mode(ip, mode);
++ return error;
++ }
++
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ error = -ENOMEM;
++ if (!clone)
++ goto out;
++ posix_acl_release(acl);
++ acl = clone;
++
++ if (S_ISDIR(ip->i_di.di_mode)) {
++ er.er_name = GFS2_POSIX_ACL_DEFAULT;
++ er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
++ error = gfs2_system_eaops.eo_set(ip, &er);
++ if (error)
++ goto out;
++ }
++
++ error = posix_acl_create_masq(acl, &mode);
++ if (error < 0)
++ goto out;
++ if (error > 0) {
++ er.er_name = GFS2_POSIX_ACL_ACCESS;
++ er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
++ posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
++ er.er_mode = mode;
++ er.er_flags = GFS2_ERF_MODE;
++ error = gfs2_system_eaops.eo_set(ip, &er);
++ if (error)
++ goto out;
++ } else
++ munge_mode(ip, mode);
++
++out:
++ posix_acl_release(acl);
++ kfree(er.er_data);
++ return error;
++}
++
++int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
++{
++ struct posix_acl *acl = NULL, *clone;
++ struct gfs2_ea_location el;
++ char *data;
++ unsigned int len;
++ int error;
++
++ error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
++ if (error)
++ return error;
++ if (!acl)
++ return gfs2_setattr_simple(ip, attr);
++
++ clone = posix_acl_clone(acl, GFP_KERNEL);
++ error = -ENOMEM;
++ if (!clone)
++ goto out;
++ posix_acl_release(acl);
++ acl = clone;
++
++ error = posix_acl_chmod_masq(acl, attr->ia_mode);
++ if (!error) {
++ posix_acl_to_xattr(acl, data, len);
++ error = gfs2_ea_acl_chmod(ip, &el, attr, data);
++ }
++
++out:
++ posix_acl_release(acl);
++ brelse(el.el_bh);
++ kfree(data);
++ return error;
++}
++
+diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
+new file mode 100644
+index 0000000..05c294f
+--- /dev/null
++++ b/fs/gfs2/acl.h
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __ACL_DOT_H__
++#define __ACL_DOT_H__
++
++#include "incore.h"
++
++#define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
++#define GFS2_POSIX_ACL_ACCESS_LEN 16
++#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
++#define GFS2_POSIX_ACL_DEFAULT_LEN 17
++
++#define GFS2_ACL_IS_ACCESS(name, len) \
++ ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \
++ !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len)))
++
++#define GFS2_ACL_IS_DEFAULT(name, len) \
++ ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
++ !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
++
++struct gfs2_ea_request;
++
++int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
++ struct gfs2_ea_request *er,
++ int *remove, mode_t *mode);
++int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
++int gfs2_check_acl_locked(struct inode *inode, int mask);
++int gfs2_check_acl(struct inode *inode, int mask);
++int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
++int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
++
++#endif /* __ACL_DOT_H__ */
+diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
+new file mode 100644
+index 0000000..06e9a8c
+--- /dev/null
++++ b/fs/gfs2/bmap.c
+@@ -0,0 +1,1222 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "inode.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "dir.h"
++#include "util.h"
++#include "ops_address.h"
++
++/* This doesn't need to be that large as max 64 bit pointers in a 4k
++ * block is 512, so __u16 is fine for that. It saves stack space to
++ * keep it small.
++ */
++struct metapath {
++ __u16 mp_list[GFS2_MAX_META_HEIGHT];
++};
++
++typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
++ struct buffer_head *bh, u64 *top,
++ u64 *bottom, unsigned int height,
++ void *data);
++
++struct strip_mine {
++ int sm_first;
++ unsigned int sm_height;
++};
++
++/**
++ * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
++ * @ip: the inode
++ * @dibh: the dinode buffer
++ * @block: the block number that was allocated
++ * @private: any locked page held by the caller process
++ *
++ * Returns: errno
++ */
++
++static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
++ u64 block, struct page *page)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct inode *inode = &ip->i_inode;
++ struct buffer_head *bh;
++ int release = 0;
++
++ if (!page || page->index) {
++ page = grab_cache_page(inode->i_mapping, 0);
++ if (!page)
++ return -ENOMEM;
++ release = 1;
++ }
++
++ if (!PageUptodate(page)) {
++ void *kaddr = kmap(page);
++
++ memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
++ ip->i_di.di_size);
++ memset(kaddr + ip->i_di.di_size, 0,
++ PAGE_CACHE_SIZE - ip->i_di.di_size);
++ kunmap(page);
++
++ SetPageUptodate(page);
++ }
++
++ if (!page_has_buffers(page))
++ create_empty_buffers(page, 1 << inode->i_blkbits,
++ (1 << BH_Uptodate));
++
++ bh = page_buffers(page);
++
++ if (!buffer_mapped(bh))
++ map_bh(bh, inode->i_sb, block);
++
++ set_buffer_uptodate(bh);
++ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
++ gfs2_trans_add_bh(ip->i_gl, bh, 0);
++ mark_buffer_dirty(bh);
++
++ if (release) {
++ unlock_page(page);
++ page_cache_release(page);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
++ * @ip: The GFS2 inode to unstuff
++ * @unstuffer: the routine that handles unstuffing a non-zero length file
++ * @private: private data for the unstuffer
++ *
++ * This routine unstuffs a dinode and returns it to a "normal" state such
++ * that the height can be grown in the traditional way.
++ *
++ * Returns: errno
++ */
++
++int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
++{
++ struct buffer_head *bh, *dibh;
++ struct gfs2_dinode *di;
++ u64 block = 0;
++ int isdir = gfs2_is_dir(ip);
++ int error;
++
++ down_write(&ip->i_rw_mutex);
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out;
++
++ if (ip->i_di.di_size) {
++ /* Get a free block, fill it with the stuffed data,
++ and write it out to disk */
++
++ if (isdir) {
++ block = gfs2_alloc_meta(ip);
++
++ error = gfs2_dir_get_new_buffer(ip, block, &bh);
++ if (error)
++ goto out_brelse;
++ gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
++ dibh, sizeof(struct gfs2_dinode));
++ brelse(bh);
++ } else {
++ block = gfs2_alloc_data(ip);
++
++ error = gfs2_unstuffer_page(ip, dibh, block, page);
++ if (error)
++ goto out_brelse;
++ }
++ }
++
++ /* Set up the pointer to the new block */
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ di = (struct gfs2_dinode *)dibh->b_data;
++ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
++
++ if (ip->i_di.di_size) {
++ *(__be64 *)(di + 1) = cpu_to_be64(block);
++ ip->i_di.di_blocks++;
++ di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
++ }
++
++ ip->i_di.di_height = 1;
++ di->di_height = cpu_to_be16(1);
++
++out_brelse:
++ brelse(dibh);
++out:
++ up_write(&ip->i_rw_mutex);
++ return error;
++}
++
++/**
++ * calc_tree_height - Calculate the height of a metadata tree
++ * @ip: The GFS2 inode
++ * @size: The proposed size of the file
++ *
++ * Work out how tall a metadata tree needs to be in order to accommodate a
++ * file of a particular size. If size is less than the current size of
++ * the inode, then the current size of the inode is used instead of the
++ * supplied one.
++ *
++ * Returns: the height the tree should be
++ */
++
++static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ u64 *arr;
++ unsigned int max, height;
++
++ if (ip->i_di.di_size > size)
++ size = ip->i_di.di_size;
++
++ if (gfs2_is_dir(ip)) {
++ arr = sdp->sd_jheightsize;
++ max = sdp->sd_max_jheight;
++ } else {
++ arr = sdp->sd_heightsize;
++ max = sdp->sd_max_height;
++ }
++
++ for (height = 0; height < max; height++)
++ if (arr[height] >= size)
++ break;
++
++ return height;
++}
++
++/**
++ * build_height - Build a metadata tree of the requested height
++ * @ip: The GFS2 inode
++ * @height: The height to build to
++ *
++ *
++ * Returns: errno
++ */
++
++static int build_height(struct inode *inode, unsigned height)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ unsigned new_height = height - ip->i_di.di_height;
++ struct buffer_head *dibh;
++ struct buffer_head *blocks[GFS2_MAX_META_HEIGHT];
++ struct gfs2_dinode *di;
++ int error;
++ u64 *bp;
++ u64 bn;
++ unsigned n;
++
++ if (height <= ip->i_di.di_height)
++ return 0;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ return error;
++
++ for(n = 0; n < new_height; n++) {
++ bn = gfs2_alloc_meta(ip);
++ blocks[n] = gfs2_meta_new(ip->i_gl, bn);
++ gfs2_trans_add_bh(ip->i_gl, blocks[n], 1);
++ }
++
++ n = 0;
++ bn = blocks[0]->b_blocknr;
++ if (new_height > 1) {
++ for(; n < new_height-1; n++) {
++ gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN,
++ GFS2_FORMAT_IN);
++ gfs2_buffer_clear_tail(blocks[n],
++ sizeof(struct gfs2_meta_header));
++ bp = (u64 *)(blocks[n]->b_data +
++ sizeof(struct gfs2_meta_header));
++ *bp = cpu_to_be64(blocks[n+1]->b_blocknr);
++ brelse(blocks[n]);
++ blocks[n] = NULL;
++ }
++ }
++ gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
++ gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header),
++ dibh, sizeof(struct gfs2_dinode));
++ brelse(blocks[n]);
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ di = (struct gfs2_dinode *)dibh->b_data;
++ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
++ *(__be64 *)(di + 1) = cpu_to_be64(bn);
++ ip->i_di.di_height += new_height;
++ ip->i_di.di_blocks += new_height;
++ di->di_height = cpu_to_be16(ip->i_di.di_height);
++ di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
++ brelse(dibh);
++ return error;
++}
++
++/**
++ * find_metapath - Find path through the metadata tree
++ * @ip: The inode pointer
++ * @mp: The metapath to return the result in
++ * @block: The disk block to look up
++ *
++ * This routine returns a struct metapath structure that defines a path
++ * through the metadata of inode "ip" to get to block "block".
++ *
++ * Example:
++ * Given: "ip" is a height 3 file, "offset" is 101342453, and this is a
++ * filesystem with a blocksize of 4096.
++ *
++ * find_metapath() would return a struct metapath structure set to:
++ * mp_offset = 101342453, mp_height = 3, mp_list[0] = 0, mp_list[1] = 48,
++ * and mp_list[2] = 165.
++ *
++ * That means that in order to get to the block containing the byte at
++ * offset 101342453, we would load the indirect block pointed to by pointer
++ * 0 in the dinode. We would then load the indirect block pointed to by
++ * pointer 48 in that indirect block. We would then load the data block
++ * pointed to by pointer 165 in that indirect block.
++ *
++ * ----------------------------------------
++ * | Dinode | |
++ * | | 4|
++ * | |0 1 2 3 4 5 9|
++ * | | 6|
++ * ----------------------------------------
++ * |
++ * |
++ * V
++ * ----------------------------------------
++ * | Indirect Block |
++ * | 5|
++ * | 4 4 4 4 4 5 5 1|
++ * |0 5 6 7 8 9 0 1 2|
++ * ----------------------------------------
++ * |
++ * |
++ * V
++ * ----------------------------------------
++ * | Indirect Block |
++ * | 1 1 1 1 1 5|
++ * | 6 6 6 6 6 1|
++ * |0 3 4 5 6 7 2|
++ * ----------------------------------------
++ * |
++ * |
++ * V
++ * ----------------------------------------
++ * | Data block containing offset |
++ * | 101342453 |
++ * | |
++ * | |
++ * ----------------------------------------
++ *
++ */
++
++static void find_metapath(struct gfs2_inode *ip, u64 block,
++ struct metapath *mp)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ u64 b = block;
++ unsigned int i;
++
++ for (i = ip->i_di.di_height; i--;)
++ mp->mp_list[i] = do_div(b, sdp->sd_inptrs);
++
++}
++
++/**
++ * metapointer - Return pointer to start of metadata in a buffer
++ * @bh: The buffer
++ * @height: The metadata height (0 = dinode)
++ * @mp: The metapath
++ *
++ * Return a pointer to the block number of the next height of the metadata
++ * tree given a buffer containing the pointer to the current height of the
++ * metadata tree.
++ */
++
++static inline u64 *metapointer(struct buffer_head *bh, int *boundary,
++ unsigned int height, const struct metapath *mp)
++{
++ unsigned int head_size = (height > 0) ?
++ sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
++ u64 *ptr;
++ *boundary = 0;
++ ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height];
++ if (ptr + 1 == (u64 *)(bh->b_data + bh->b_size))
++ *boundary = 1;
++ return ptr;
++}
++
++/**
++ * lookup_block - Get the next metadata block in metadata tree
++ * @ip: The GFS2 inode
++ * @bh: Buffer containing the pointers to metadata blocks
++ * @height: The height of the tree (0 = dinode)
++ * @mp: The metapath
++ * @create: Non-zero if we may create a new meatdata block
++ * @new: Used to indicate if we did create a new metadata block
++ * @block: the returned disk block number
++ *
++ * Given a metatree, complete to a particular height, checks to see if the next
++ * height of the tree exists. If not the next height of the tree is created.
++ * The block number of the next height of the metadata tree is returned.
++ *
++ */
++
++static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
++ unsigned int height, struct metapath *mp, int create,
++ int *new, u64 *block)
++{
++ int boundary;
++ u64 *ptr = metapointer(bh, &boundary, height, mp);
++
++ if (*ptr) {
++ *block = be64_to_cpu(*ptr);
++ return boundary;
++ }
++
++ *block = 0;
++
++ if (!create)
++ return 0;
++
++ if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip))
++ *block = gfs2_alloc_data(ip);
++ else
++ *block = gfs2_alloc_meta(ip);
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++
++ *ptr = cpu_to_be64(*block);
++ ip->i_di.di_blocks++;
++
++ *new = 1;
++ return 0;
++}
++
++/**
++ * gfs2_block_pointers - Map a block from an inode to a disk block
++ * @inode: The inode
++ * @lblock: The logical block number
++ * @map_bh: The bh to be mapped
++ * @mp: metapath to use
++ *
++ * Find the block number on the current device which corresponds to an
++ * inode's block. If the block had to be created, "new" will be set.
++ *
++ * Returns: errno
++ */
++
++static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
++ struct buffer_head *bh_map, struct metapath *mp)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ struct buffer_head *bh;
++ unsigned int bsize;
++ unsigned int height;
++ unsigned int end_of_metadata;
++ unsigned int x;
++ int error = 0;
++ int new = 0;
++ u64 dblock = 0;
++ int boundary;
++ unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
++
++ BUG_ON(maxlen == 0);
++
++ if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
++ return 0;
++
++ bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize;
++
++ height = calc_tree_height(ip, (lblock + 1) * bsize);
++ if (ip->i_di.di_height < height) {
++ if (!create)
++ return 0;
++
++ error = build_height(inode, height);
++ if (error)
++ return error;
++ }
++
++ find_metapath(ip, lblock, mp);
++ end_of_metadata = ip->i_di.di_height - 1;
++
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ return error;
++
++ for (x = 0; x < end_of_metadata; x++) {
++ lookup_block(ip, bh, x, mp, create, &new, &dblock);
++ brelse(bh);
++ if (!dblock)
++ return 0;
++
++ error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
++ if (error)
++ return error;
++ }
++
++ boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock);
++ clear_buffer_mapped(bh_map);
++ clear_buffer_new(bh_map);
++ clear_buffer_boundary(bh_map);
++
++ if (dblock) {
++ map_bh(bh_map, inode->i_sb, dblock);
++ if (boundary)
++ set_buffer_boundary(bh);
++ if (new) {
++ struct buffer_head *dibh;
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++ set_buffer_new(bh_map);
++ goto out_brelse;
++ }
++ while(--maxlen && !buffer_boundary(bh_map)) {
++ u64 eblock;
++
++ mp->mp_list[end_of_metadata]++;
++ boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock);
++ if (eblock != ++dblock)
++ break;
++ bh_map->b_size += (1 << inode->i_blkbits);
++ if (boundary)
++ set_buffer_boundary(bh_map);
++ }
++ }
++out_brelse:
++ brelse(bh);
++ return 0;
++}
++
++
++static inline void bmap_lock(struct inode *inode, int create)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ if (create)
++ down_write(&ip->i_rw_mutex);
++ else
++ down_read(&ip->i_rw_mutex);
++}
++
++static inline void bmap_unlock(struct inode *inode, int create)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ if (create)
++ up_write(&ip->i_rw_mutex);
++ else
++ up_read(&ip->i_rw_mutex);
++}
++
++int gfs2_block_map(struct inode *inode, u64 lblock, int create,
++ struct buffer_head *bh)
++{
++ struct metapath mp;
++ int ret;
++
++ bmap_lock(inode, create);
++ ret = gfs2_block_pointers(inode, lblock, create, bh, &mp);
++ bmap_unlock(inode, create);
++ return ret;
++}
++
++int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
++{
++ struct metapath mp;
++ struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 };
++ int ret;
++ int create = *new;
++
++ BUG_ON(!extlen);
++ BUG_ON(!dblock);
++ BUG_ON(!new);
++
++ bh.b_size = 1 << (inode->i_blkbits + 5);
++ bmap_lock(inode, create);
++ ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp);
++ bmap_unlock(inode, create);
++ *extlen = bh.b_size >> inode->i_blkbits;
++ *dblock = bh.b_blocknr;
++ if (buffer_new(&bh))
++ *new = 1;
++ else
++ *new = 0;
++ return ret;
++}
++
++/**
++ * recursive_scan - recursively scan through the end of a file
++ * @ip: the inode
++ * @dibh: the dinode buffer
++ * @mp: the path through the metadata to the point to start
++ * @height: the height the recursion is at
++ * @block: the indirect block to look at
++ * @first: 1 if this is the first block
++ * @bc: the call to make for each piece of metadata
++ * @data: data opaque to this function to pass to @bc
++ *
++ * When this is first called @height and @block should be zero and
++ * @first should be 1.
++ *
++ * Returns: errno
++ */
++
++static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
++ struct metapath *mp, unsigned int height,
++ u64 block, int first, block_call_t bc,
++ void *data)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head *bh = NULL;
++ u64 *top, *bottom;
++ u64 bn;
++ int error;
++ int mh_size = sizeof(struct gfs2_meta_header);
++
++ if (!height) {
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ return error;
++ dibh = bh;
++
++ top = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
++ bottom = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
++ } else {
++ error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
++ if (error)
++ return error;
++
++ top = (u64 *)(bh->b_data + mh_size) +
++ (first ? mp->mp_list[height] : 0);
++
++ bottom = (u64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
++ }
++
++ error = bc(ip, dibh, bh, top, bottom, height, data);
++ if (error)
++ goto out;
++
++ if (height < ip->i_di.di_height - 1)
++ for (; top < bottom; top++, first = 0) {
++ if (!*top)
++ continue;
++
++ bn = be64_to_cpu(*top);
++
++ error = recursive_scan(ip, dibh, mp, height + 1, bn,
++ first, bc, data);
++ if (error)
++ break;
++ }
++
++out:
++ brelse(bh);
++ return error;
++}
++
++/**
++ * do_strip - Look for a layer a particular layer of the file and strip it off
++ * @ip: the inode
++ * @dibh: the dinode buffer
++ * @bh: A buffer of pointers
++ * @top: The first pointer in the buffer
++ * @bottom: One more than the last pointer
++ * @height: the height this buffer is at
++ * @data: a pointer to a struct strip_mine
++ *
++ * Returns: errno
++ */
++
++static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
++ struct buffer_head *bh, u64 *top, u64 *bottom,
++ unsigned int height, void *data)
++{
++ struct strip_mine *sm = data;
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_rgrp_list rlist;
++ u64 bn, bstart;
++ u32 blen;
++ u64 *p;
++ unsigned int rg_blocks = 0;
++ int metadata;
++ unsigned int revokes = 0;
++ int x;
++ int error;
++
++ if (!*top)
++ sm->sm_first = 0;
++
++ if (height != sm->sm_height)
++ return 0;
++
++ if (sm->sm_first) {
++ top++;
++ sm->sm_first = 0;
++ }
++
++ metadata = (height != ip->i_di.di_height - 1);
++ if (metadata)
++ revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
++
++ error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);
++ if (error)
++ return error;
++
++ memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
++ bstart = 0;
++ blen = 0;
++
++ for (p = top; p < bottom; p++) {
++ if (!*p)
++ continue;
++
++ bn = be64_to_cpu(*p);
++
++ if (bstart + blen == bn)
++ blen++;
++ else {
++ if (bstart)
++ gfs2_rlist_add(sdp, &rlist, bstart);
++
++ bstart = bn;
++ blen = 1;
++ }
++ }
++
++ if (bstart)
++ gfs2_rlist_add(sdp, &rlist, bstart);
++ else
++ goto out; /* Nothing to do */
++
++ gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
++
++ for (x = 0; x < rlist.rl_rgrps; x++) {
++ struct gfs2_rgrpd *rgd;
++ rgd = rlist.rl_ghs[x].gh_gl->gl_object;
++ rg_blocks += rgd->rd_ri.ri_length;
++ }
++
++ error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
++ if (error)
++ goto out_rlist;
++
++ error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
++ RES_INDIRECT + RES_STATFS + RES_QUOTA,
++ revokes);
++ if (error)
++ goto out_rg_gunlock;
++
++ down_write(&ip->i_rw_mutex);
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++
++ bstart = 0;
++ blen = 0;
++
++ for (p = top; p < bottom; p++) {
++ if (!*p)
++ continue;
++
++ bn = be64_to_cpu(*p);
++
++ if (bstart + blen == bn)
++ blen++;
++ else {
++ if (bstart) {
++ if (metadata)
++ gfs2_free_meta(ip, bstart, blen);
++ else
++ gfs2_free_data(ip, bstart, blen);
++ }
++
++ bstart = bn;
++ blen = 1;
++ }
++
++ *p = 0;
++ if (!ip->i_di.di_blocks)
++ gfs2_consist_inode(ip);
++ ip->i_di.di_blocks--;
++ }
++ if (bstart) {
++ if (metadata)
++ gfs2_free_meta(ip, bstart, blen);
++ else
++ gfs2_free_data(ip, bstart, blen);
++ }
++
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++
++ up_write(&ip->i_rw_mutex);
++
++ gfs2_trans_end(sdp);
++
++out_rg_gunlock:
++ gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
++out_rlist:
++ gfs2_rlist_free(&rlist);
++out:
++ gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);
++ return error;
++}
++
++/**
++ * do_grow - Make a file look bigger than it is
++ * @ip: the inode
++ * @size: the size to set the file to
++ *
++ * Called with an exclusive lock on @ip.
++ *
++ * Returns: errno
++ */
++
++static int do_grow(struct gfs2_inode *ip, u64 size)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al;
++ struct buffer_head *dibh;
++ unsigned int h;
++ int error;
++
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out;
++
++ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
++ if (error)
++ goto out_gunlock_q;
++
++ al->al_requested = sdp->sd_max_height + RES_DATA;
++
++ error = gfs2_inplace_reserve(ip);
++ if (error)
++ goto out_gunlock_q;
++
++ error = gfs2_trans_begin(sdp,
++ sdp->sd_max_height + al->al_rgd->rd_ri.ri_length +
++ RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0);
++ if (error)
++ goto out_ipres;
++
++ if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
++ if (gfs2_is_stuffed(ip)) {
++ error = gfs2_unstuff_dinode(ip, NULL);
++ if (error)
++ goto out_end_trans;
++ }
++
++ h = calc_tree_height(ip, size);
++ if (ip->i_di.di_height < h) {
++ down_write(&ip->i_rw_mutex);
++ error = build_height(&ip->i_inode, h);
++ up_write(&ip->i_rw_mutex);
++ if (error)
++ goto out_end_trans;
++ }
++ }
++
++ ip->i_di.di_size = size;
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out_end_trans;
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_ipres:
++ gfs2_inplace_release(ip);
++out_gunlock_q:
++ gfs2_quota_unlock(ip);
++out:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++
++/**
++ * gfs2_block_truncate_page - Deal with zeroing out data for truncate
++ *
++ * This is partly borrowed from ext3.
++ */
++static int gfs2_block_truncate_page(struct address_space *mapping)
++{
++ struct inode *inode = mapping->host;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ loff_t from = inode->i_size;
++ unsigned long index = from >> PAGE_CACHE_SHIFT;
++ unsigned offset = from & (PAGE_CACHE_SIZE-1);
++ unsigned blocksize, iblock, length, pos;
++ struct buffer_head *bh;
++ struct page *page;
++ void *kaddr;
++ int err;
++
++ page = grab_cache_page(mapping, index);
++ if (!page)
++ return 0;
++
++ blocksize = inode->i_sb->s_blocksize;
++ length = blocksize - (offset & (blocksize - 1));
++ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
++
++ if (!page_has_buffers(page))
++ create_empty_buffers(page, blocksize, 0);
++
++ /* Find the buffer that contains "offset" */
++ bh = page_buffers(page);
++ pos = blocksize;
++ while (offset >= pos) {
++ bh = bh->b_this_page;
++ iblock++;
++ pos += blocksize;
++ }
++
++ err = 0;
++
++ if (!buffer_mapped(bh)) {
++ gfs2_get_block(inode, iblock, bh, 0);
++ /* unmapped? It's a hole - nothing to do */
++ if (!buffer_mapped(bh))
++ goto unlock;
++ }
++
++ /* Ok, it's mapped. Make sure it's up-to-date */
++ if (PageUptodate(page))
++ set_buffer_uptodate(bh);
++
++ if (!buffer_uptodate(bh)) {
++ err = -EIO;
++ ll_rw_block(READ, 1, &bh);
++ wait_on_buffer(bh);
++ /* Uhhuh. Read error. Complain and punt. */
++ if (!buffer_uptodate(bh))
++ goto unlock;
++ }
++
++ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
++ gfs2_trans_add_bh(ip->i_gl, bh, 0);
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + offset, 0, length);
++ flush_dcache_page(page);
++ kunmap_atomic(kaddr, KM_USER0);
++
++unlock:
++ unlock_page(page);
++ page_cache_release(page);
++ return err;
++}
++
++static int trunc_start(struct gfs2_inode *ip, u64 size)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head *dibh;
++ int journaled = gfs2_is_jdata(ip);
++ int error;
++
++ error = gfs2_trans_begin(sdp,
++ RES_DINODE + (journaled ? RES_JDATA : 0), 0);
++ if (error)
++ return error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out;
++
++ if (gfs2_is_stuffed(ip)) {
++ ip->i_di.di_size = size;
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
++ error = 1;
++
++ } else {
++ if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
++ error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
++
++ if (!error) {
++ ip->i_di.di_size = size;
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++ ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ }
++ }
++
++ brelse(dibh);
++
++out:
++ gfs2_trans_end(sdp);
++ return error;
++}
++
++static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
++{
++ unsigned int height = ip->i_di.di_height;
++ u64 lblock;
++ struct metapath mp;
++ int error;
++
++ if (!size)
++ lblock = 0;
++ else
++ lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift;
++
++ find_metapath(ip, lblock, &mp);
++ gfs2_alloc_get(ip);
++
++ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out;
++
++ while (height--) {
++ struct strip_mine sm;
++ sm.sm_first = !!size;
++ sm.sm_height = height;
++
++ error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
++ if (error)
++ break;
++ }
++
++ gfs2_quota_unhold(ip);
++
++out:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++static int trunc_end(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
++ if (error)
++ return error;
++
++ down_write(&ip->i_rw_mutex);
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out;
++
++ if (!ip->i_di.di_size) {
++ ip->i_di.di_height = 0;
++ ip->i_di.di_goal_meta =
++ ip->i_di.di_goal_data =
++ ip->i_num.no_addr;
++ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
++ }
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++ ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++
++out:
++ up_write(&ip->i_rw_mutex);
++ gfs2_trans_end(sdp);
++ return error;
++}
++
++/**
++ * do_shrink - make a file smaller
++ * @ip: the inode
++ * @size: the size to make the file
++ * @truncator: function to truncate the last partial block
++ *
++ * Called with an exclusive lock on @ip.
++ *
++ * Returns: errno
++ */
++
++static int do_shrink(struct gfs2_inode *ip, u64 size)
++{
++ int error;
++
++ error = trunc_start(ip, size);
++ if (error < 0)
++ return error;
++ if (error > 0)
++ return 0;
++
++ error = trunc_dealloc(ip, size);
++ if (!error)
++ error = trunc_end(ip);
++
++ return error;
++}
++
++/**
++ * gfs2_truncatei - make a file a given size
++ * @ip: the inode
++ * @size: the size to make the file
++ * @truncator: function to truncate the last partial block
++ *
++ * The file size can grow, shrink, or stay the same size.
++ *
++ * Returns: errno
++ */
++
++int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
++{
++ int error;
++
++ if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_di.di_mode)))
++ return -EINVAL;
++
++ if (size > ip->i_di.di_size)
++ error = do_grow(ip, size);
++ else
++ error = do_shrink(ip, size);
++
++ return error;
++}
++
++int gfs2_truncatei_resume(struct gfs2_inode *ip)
++{
++ int error;
++ error = trunc_dealloc(ip, ip->i_di.di_size);
++ if (!error)
++ error = trunc_end(ip);
++ return error;
++}
++
++int gfs2_file_dealloc(struct gfs2_inode *ip)
++{
++ return trunc_dealloc(ip, 0);
++}
++
++/**
++ * gfs2_write_calc_reserv - calculate number of blocks needed to write to a file
++ * @ip: the file
++ * @len: the number of bytes to be written to the file
++ * @data_blocks: returns the number of data blocks required
++ * @ind_blocks: returns the number of indirect blocks required
++ *
++ */
++
++void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
++ unsigned int *data_blocks, unsigned int *ind_blocks)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ unsigned int tmp;
++
++ if (gfs2_is_dir(ip)) {
++ *data_blocks = DIV_ROUND_UP(len, sdp->sd_jbsize) + 2;
++ *ind_blocks = 3 * (sdp->sd_max_jheight - 1);
++ } else {
++ *data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3;
++ *ind_blocks = 3 * (sdp->sd_max_height - 1);
++ }
++
++ for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) {
++ tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
++ *ind_blocks += tmp;
++ }
++}
++
++/**
++ * gfs2_write_alloc_required - figure out if a write will require an allocation
++ * @ip: the file being written to
++ * @offset: the offset to write to
++ * @len: the number of bytes being written
++ * @alloc_required: set to 1 if an alloc is required, 0 otherwise
++ *
++ * Returns: errno
++ */
++
++int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
++ unsigned int len, int *alloc_required)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ u64 lblock, lblock_stop, dblock;
++ u32 extlen;
++ int new = 0;
++ int error = 0;
++
++ *alloc_required = 0;
++
++ if (!len)
++ return 0;
++
++ if (gfs2_is_stuffed(ip)) {
++ if (offset + len >
++ sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
++ *alloc_required = 1;
++ return 0;
++ }
++
++ if (gfs2_is_dir(ip)) {
++ unsigned int bsize = sdp->sd_jbsize;
++ lblock = offset;
++ do_div(lblock, bsize);
++ lblock_stop = offset + len + bsize - 1;
++ do_div(lblock_stop, bsize);
++ } else {
++ unsigned int shift = sdp->sd_sb.sb_bsize_shift;
++ lblock = offset >> shift;
++ lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
++ }
++
++ for (; lblock < lblock_stop; lblock += extlen) {
++ error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
++ if (error)
++ return error;
++
++ if (!dblock) {
++ *alloc_required = 1;
++ return 0;
++ }
++ }
++
++ return 0;
++}
++
+diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
+new file mode 100644
+index 0000000..ac2fd04
+--- /dev/null
++++ b/fs/gfs2/bmap.h
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __BMAP_DOT_H__
++#define __BMAP_DOT_H__
++
++struct inode;
++struct gfs2_inode;
++struct page;
++
++int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
++int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh);
++int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
++
++int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
++int gfs2_truncatei_resume(struct gfs2_inode *ip);
++int gfs2_file_dealloc(struct gfs2_inode *ip);
++
++void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
++ unsigned int *data_blocks,
++ unsigned int *ind_blocks);
++int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
++ unsigned int len, int *alloc_required);
++
++#endif /* __BMAP_DOT_H__ */
+diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
+new file mode 100644
+index 0000000..cab1f68
+--- /dev/null
++++ b/fs/gfs2/daemon.c
+@@ -0,0 +1,196 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "daemon.h"
++#include "glock.h"
++#include "log.h"
++#include "quota.h"
++#include "recovery.h"
++#include "super.h"
++#include "util.h"
++
++/* This uses schedule_timeout() instead of msleep() because it's good for
++ the daemons to wake up more often than the timeout when unmounting so
++ the user's unmount doesn't sit there forever.
++
++ The kthread functions used to start these daemons block and flush signals. */
++
++/**
++ * gfs2_scand - Look for cached glocks and inodes to toss from memory
++ * @sdp: Pointer to GFS2 superblock
++ *
++ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
++ * See gfs2_glockd()
++ */
++
++int gfs2_scand(void *data)
++{
++ struct gfs2_sbd *sdp = data;
++ unsigned long t;
++
++ while (!kthread_should_stop()) {
++ gfs2_scand_internal(sdp);
++ t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
++ schedule_timeout_interruptible(t);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_glockd - Reclaim unused glock structures
++ * @sdp: Pointer to GFS2 superblock
++ *
++ * One or more of these daemons run, reclaiming glocks on sd_reclaim_list.
++ * Number of daemons can be set by user, with num_glockd mount option.
++ */
++
++int gfs2_glockd(void *data)
++{
++ struct gfs2_sbd *sdp = data;
++
++ while (!kthread_should_stop()) {
++ while (atomic_read(&sdp->sd_reclaim_count))
++ gfs2_reclaim_glock(sdp);
++
++ wait_event_interruptible(sdp->sd_reclaim_wq,
++ (atomic_read(&sdp->sd_reclaim_count) ||
++ kthread_should_stop()));
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_recoverd - Recover dead machine's journals
++ * @sdp: Pointer to GFS2 superblock
++ *
++ */
++
++int gfs2_recoverd(void *data)
++{
++ struct gfs2_sbd *sdp = data;
++ unsigned long t;
++
++ while (!kthread_should_stop()) {
++ gfs2_check_journals(sdp);
++ t = gfs2_tune_get(sdp, gt_recoverd_secs) * HZ;
++ schedule_timeout_interruptible(t);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
++ * @sdp: Pointer to GFS2 superblock
++ *
++ * Also, periodically check to make sure that we're using the most recent
++ * journal index.
++ */
++
++int gfs2_logd(void *data)
++{
++ struct gfs2_sbd *sdp = data;
++ struct gfs2_holder ji_gh;
++ unsigned long t;
++
++ while (!kthread_should_stop()) {
++ /* Advance the log tail */
++
++ t = sdp->sd_log_flush_time +
++ gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
++
++ gfs2_ail1_empty(sdp, DIO_ALL);
++
++ if (time_after_eq(jiffies, t)) {
++ gfs2_log_flush(sdp, NULL);
++ sdp->sd_log_flush_time = jiffies;
++ }
++
++ /* Check for latest journal index */
++
++ t = sdp->sd_jindex_refresh_time +
++ gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
++
++ if (time_after_eq(jiffies, t)) {
++ if (!gfs2_jindex_hold(sdp, &ji_gh))
++ gfs2_glock_dq_uninit(&ji_gh);
++ sdp->sd_jindex_refresh_time = jiffies;
++ }
++
++ t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
++ schedule_timeout_interruptible(t);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_quotad - Write cached quota changes into the quota file
++ * @sdp: Pointer to GFS2 superblock
++ *
++ */
++
++int gfs2_quotad(void *data)
++{
++ struct gfs2_sbd *sdp = data;
++ unsigned long t;
++ int error;
++
++ while (!kthread_should_stop()) {
++ /* Update the master statfs file */
++
++ t = sdp->sd_statfs_sync_time +
++ gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
++
++ if (time_after_eq(jiffies, t)) {
++ error = gfs2_statfs_sync(sdp);
++ if (error &&
++ error != -EROFS &&
++ !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
++ fs_err(sdp, "quotad: (1) error=%d\n", error);
++ sdp->sd_statfs_sync_time = jiffies;
++ }
++
++ /* Update quota file */
++
++ t = sdp->sd_quota_sync_time +
++ gfs2_tune_get(sdp, gt_quota_quantum) * HZ;
++
++ if (time_after_eq(jiffies, t)) {
++ error = gfs2_quota_sync(sdp);
++ if (error &&
++ error != -EROFS &&
++ !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
++ fs_err(sdp, "quotad: (2) error=%d\n", error);
++ sdp->sd_quota_sync_time = jiffies;
++ }
++
++ gfs2_quota_scan(sdp);
++
++ t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ;
++ schedule_timeout_interruptible(t);
++ }
++
++ return 0;
++}
++
+diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
+new file mode 100644
+index 0000000..8010071
+--- /dev/null
++++ b/fs/gfs2/daemon.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __DAEMON_DOT_H__
++#define __DAEMON_DOT_H__
++
++int gfs2_scand(void *data);
++int gfs2_glockd(void *data);
++int gfs2_recoverd(void *data);
++int gfs2_logd(void *data);
++int gfs2_quotad(void *data);
++
++#endif /* __DAEMON_DOT_H__ */
+diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
+new file mode 100644
+index 0000000..e24af28
+--- /dev/null
++++ b/fs/gfs2/dir.c
+@@ -0,0 +1,1957 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++/*
++ * Implements Extendible Hashing as described in:
++ * "Extendible Hashing" by Fagin, et al in
++ * __ACM Trans. on Database Systems__, Sept 1979.
++ *
++ *
++ * Here's the layout of dirents which is essentially the same as that of ext2
++ * within a single block. The field de_name_len is the number of bytes
++ * actually required for the name (no null terminator). The field de_rec_len
++ * is the number of bytes allocated to the dirent. The offset of the next
++ * dirent in the block is (dirent + dirent->de_rec_len). When a dirent is
++ * deleted, the preceding dirent inherits its allocated space, ie
++ * prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained
++ * by adding de_rec_len to the current dirent, this essentially causes the
++ * deleted dirent to get jumped over when iterating through all the dirents.
++ *
++ * When deleting the first dirent in a block, there is no previous dirent so
++ * the field de_ino is set to zero to designate it as deleted. When allocating
++ * a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the
++ * first dirent has (de_ino == 0) and de_rec_len is large enough, this first
++ * dirent is allocated. Otherwise it must go through all the 'used' dirents
++ * searching for one in which the amount of total space minus the amount of
++ * used space will provide enough space for the new dirent.
++ *
++ * There are two types of blocks in which dirents reside. In a stuffed dinode,
++ * the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of
++ * the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the
++ * beginning of the leaf block. The dirents reside in leaves when
++ *
++ * dip->i_di.di_flags & GFS2_DIF_EXHASH is true
++ *
++ * Otherwise, the dirents are "linear", within a single stuffed dinode block.
++ *
++ * When the dirents are in leaves, the actual contents of the directory file are
++ * used as an array of 64-bit block pointers pointing to the leaf blocks. The
++ * dirents are NOT in the directory file itself. There can be more than one
++ * block pointer in the array that points to the same leaf. In fact, when a
++ * directory is first converted from linear to exhash, all of the pointers
++ * point to the same leaf.
++ *
++ * When a leaf is completely full, the size of the hash table can be
++ * doubled unless it is already at the maximum size which is hard coded into
++ * GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list,
++ * but never before the maximum hash table size has been reached.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/buffer_head.h>
++#include <linux/sort.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/vmalloc.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "dir.h"
++#include "glock.h"
++#include "inode.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "bmap.h"
++#include "util.h"
++
++#define IS_LEAF 1 /* Hashed (leaf) directory */
++#define IS_DINODE 2 /* Linear (stuffed dinode block) directory */
++
++#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
++#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
++
++typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len,
++ u64 leaf_no, void *data);
++typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent,
++ const struct qstr *name, void *opaque);
++
++
++int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
++ struct buffer_head **bhp)
++{
++ struct buffer_head *bh;
++
++ bh = gfs2_meta_new(ip->i_gl, block);
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
++ gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
++ *bhp = bh;
++ return 0;
++}
++
++static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block,
++ struct buffer_head **bhp)
++{
++ struct buffer_head *bh;
++ int error;
++
++ error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh);
++ if (error)
++ return error;
++ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) {
++ brelse(bh);
++ return -EIO;
++ }
++ *bhp = bh;
++ return 0;
++}
++
++static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
++ unsigned int offset, unsigned int size)
++{
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ return error;
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
++ if (ip->i_di.di_size < offset + size)
++ ip->i_di.di_size = offset + size;
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++
++ brelse(dibh);
++
++ return size;
++}
++
++
++
++/**
++ * gfs2_dir_write_data - Write directory information to the inode
++ * @ip: The GFS2 inode
++ * @buf: The buffer containing information to be written
++ * @offset: The file offset to start writing at
++ * @size: The amount of data to write
++ *
++ * Returns: The number of bytes correctly written or error code
++ */
++static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
++ u64 offset, unsigned int size)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head *dibh;
++ u64 lblock, dblock;
++ u32 extlen = 0;
++ unsigned int o;
++ int copied = 0;
++ int error = 0;
++
++ if (!size)
++ return 0;
++
++ if (gfs2_is_stuffed(ip) &&
++ offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
++ return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset,
++ size);
++
++ if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
++ return -EINVAL;
++
++ if (gfs2_is_stuffed(ip)) {
++ error = gfs2_unstuff_dinode(ip, NULL);
++ if (error)
++ return error;
++ }
++
++ lblock = offset;
++ o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
++
++ while (copied < size) {
++ unsigned int amount;
++ struct buffer_head *bh;
++ int new = 0;
++
++ amount = size - copied;
++ if (amount > sdp->sd_sb.sb_bsize - o)
++ amount = sdp->sd_sb.sb_bsize - o;
++
++ if (!extlen) {
++ new = 1;
++ error = gfs2_extent_map(&ip->i_inode, lblock, &new,
++ &dblock, &extlen);
++ if (error)
++ goto fail;
++ error = -EIO;
++ if (gfs2_assert_withdraw(sdp, dblock))
++ goto fail;
++ }
++
++ if (amount == sdp->sd_jbsize || new)
++ error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
++ else
++ error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
++
++ if (error)
++ goto fail;
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ memcpy(bh->b_data + o, buf, amount);
++ brelse(bh);
++
++ buf += amount;
++ copied += amount;
++ lblock++;
++ dblock++;
++ extlen--;
++
++ o = sizeof(struct gfs2_meta_header);
++ }
++
++out:
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ return error;
++
++ if (ip->i_di.di_size < offset + copied)
++ ip->i_di.di_size = offset + copied;
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++
++ return copied;
++fail:
++ if (copied)
++ goto out;
++ return error;
++}
++
++static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
++ u64 offset, unsigned int size)
++{
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ offset += sizeof(struct gfs2_dinode);
++ memcpy(buf, dibh->b_data + offset, size);
++ brelse(dibh);
++ }
++
++ return (error) ? error : size;
++}
++
++
++/**
++ * gfs2_dir_read_data - Read a data from a directory inode
++ * @ip: The GFS2 Inode
++ * @buf: The buffer to place result into
++ * @offset: File offset to begin jdata_readng from
++ * @size: Amount of data to transfer
++ *
++ * Returns: The amount of data actually copied or the error
++ */
++static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
++ unsigned int size, unsigned ra)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ u64 lblock, dblock;
++ u32 extlen = 0;
++ unsigned int o;
++ int copied = 0;
++ int error = 0;
++
++ if (offset >= ip->i_di.di_size)
++ return 0;
++
++ if (offset + size > ip->i_di.di_size)
++ size = ip->i_di.di_size - offset;
++
++ if (!size)
++ return 0;
++
++ if (gfs2_is_stuffed(ip))
++ return gfs2_dir_read_stuffed(ip, buf, offset, size);
++
++ if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
++ return -EINVAL;
++
++ lblock = offset;
++ o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
++
++ while (copied < size) {
++ unsigned int amount;
++ struct buffer_head *bh;
++ int new;
++
++ amount = size - copied;
++ if (amount > sdp->sd_sb.sb_bsize - o)
++ amount = sdp->sd_sb.sb_bsize - o;
++
++ if (!extlen) {
++ new = 0;
++ error = gfs2_extent_map(&ip->i_inode, lblock, &new,
++ &dblock, &extlen);
++ if (error || !dblock)
++ goto fail;
++ BUG_ON(extlen < 1);
++ if (!ra)
++ extlen = 1;
++ bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
++ } else {
++ error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
++ if (error)
++ goto fail;
++ }
++ error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD);
++ if (error) {
++ brelse(bh);
++ goto fail;
++ }
++ dblock++;
++ extlen--;
++ memcpy(buf, bh->b_data + o, amount);
++ brelse(bh);
++ buf += amount;
++ copied += amount;
++ lblock++;
++ o = sizeof(struct gfs2_meta_header);
++ }
++
++ return copied;
++fail:
++ return (copied) ? copied : error;
++}
++
++static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent,
++ const struct qstr *name, int ret)
++{
++ if (dent->de_inum.no_addr != 0 &&
++ be32_to_cpu(dent->de_hash) == name->hash &&
++ be16_to_cpu(dent->de_name_len) == name->len &&
++ memcmp(dent+1, name->name, name->len) == 0)
++ return ret;
++ return 0;
++}
++
++static int gfs2_dirent_find(const struct gfs2_dirent *dent,
++ const struct qstr *name,
++ void *opaque)
++{
++ return __gfs2_dirent_find(dent, name, 1);
++}
++
++static int gfs2_dirent_prev(const struct gfs2_dirent *dent,
++ const struct qstr *name,
++ void *opaque)
++{
++ return __gfs2_dirent_find(dent, name, 2);
++}
++
++/*
++ * name->name holds ptr to start of block.
++ * name->len holds size of block.
++ */
++static int gfs2_dirent_last(const struct gfs2_dirent *dent,
++ const struct qstr *name,
++ void *opaque)
++{
++ const char *start = name->name;
++ const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len);
++ if (name->len == (end - start))
++ return 1;
++ return 0;
++}
++
++static int gfs2_dirent_find_space(const struct gfs2_dirent *dent,
++ const struct qstr *name,
++ void *opaque)
++{
++ unsigned required = GFS2_DIRENT_SIZE(name->len);
++ unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
++ unsigned totlen = be16_to_cpu(dent->de_rec_len);
++
++ if (!dent->de_inum.no_addr)
++ actual = GFS2_DIRENT_SIZE(0);
++ if (totlen - actual >= required)
++ return 1;
++ return 0;
++}
++
++struct dirent_gather {
++ const struct gfs2_dirent **pdent;
++ unsigned offset;
++};
++
++static int gfs2_dirent_gather(const struct gfs2_dirent *dent,
++ const struct qstr *name,
++ void *opaque)
++{
++ struct dirent_gather *g = opaque;
++ if (dent->de_inum.no_addr) {
++ g->pdent[g->offset++] = dent;
++ }
++ return 0;
++}
++
++/*
++ * Other possible things to check:
++ * - Inode located within filesystem size (and on valid block)
++ * - Valid directory entry type
++ * Not sure how heavy-weight we want to make this... could also check
++ * hash is correct for example, but that would take a lot of extra time.
++ * For now the most important thing is to check that the various sizes
++ * are correct.
++ */
++static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset,
++ unsigned int size, unsigned int len, int first)
++{
++ const char *msg = "gfs2_dirent too small";
++ if (unlikely(size < sizeof(struct gfs2_dirent)))
++ goto error;
++ msg = "gfs2_dirent misaligned";
++ if (unlikely(offset & 0x7))
++ goto error;
++ msg = "gfs2_dirent points beyond end of block";
++ if (unlikely(offset + size > len))
++ goto error;
++ msg = "zero inode number";
++ if (unlikely(!first && !dent->de_inum.no_addr))
++ goto error;
++ msg = "name length is greater than space in dirent";
++ if (dent->de_inum.no_addr &&
++ unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) >
++ size))
++ goto error;
++ return 0;
++error:
++ printk(KERN_WARNING "gfs2_check_dirent: %s (%s)\n", msg,
++ first ? "first in block" : "not first in block");
++ return -EIO;
++}
++
++static int gfs2_dirent_offset(const void *buf)
++{
++ const struct gfs2_meta_header *h = buf;
++ int offset;
++
++ BUG_ON(buf == NULL);
++
++ switch(be32_to_cpu(h->mh_type)) {
++ case GFS2_METATYPE_LF:
++ offset = sizeof(struct gfs2_leaf);
++ break;
++ case GFS2_METATYPE_DI:
++ offset = sizeof(struct gfs2_dinode);
++ break;
++ default:
++ goto wrong_type;
++ }
++ return offset;
++wrong_type:
++ printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n",
++ be32_to_cpu(h->mh_type));
++ return -1;
++}
++
++static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
++ unsigned int len, gfs2_dscan_t scan,
++ const struct qstr *name,
++ void *opaque)
++{
++ struct gfs2_dirent *dent, *prev;
++ unsigned offset;
++ unsigned size;
++ int ret = 0;
++
++ ret = gfs2_dirent_offset(buf);
++ if (ret < 0)
++ goto consist_inode;
++
++ offset = ret;
++ prev = NULL;
++ dent = buf + offset;
++ size = be16_to_cpu(dent->de_rec_len);
++ if (gfs2_check_dirent(dent, offset, size, len, 1))
++ goto consist_inode;
++ do {
++ ret = scan(dent, name, opaque);
++ if (ret)
++ break;
++ offset += size;
++ if (offset == len)
++ break;
++ prev = dent;
++ dent = buf + offset;
++ size = be16_to_cpu(dent->de_rec_len);
++ if (gfs2_check_dirent(dent, offset, size, len, 0))
++ goto consist_inode;
++ } while(1);
++
++ switch(ret) {
++ case 0:
++ return NULL;
++ case 1:
++ return dent;
++ case 2:
++ return prev ? prev : dent;
++ default:
++ BUG_ON(ret > 0);
++ return ERR_PTR(ret);
++ }
++
++consist_inode:
++ gfs2_consist_inode(GFS2_I(inode));
++ return ERR_PTR(-EIO);
++}
++
++
++/**
++ * dirent_first - Return the first dirent
++ * @dip: the directory
++ * @bh: The buffer
++ * @dent: Pointer to list of dirents
++ *
++ * return first dirent whether bh points to leaf or stuffed dinode
++ *
++ * Returns: IS_LEAF, IS_DINODE, or -errno
++ */
++
++static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh,
++ struct gfs2_dirent **dent)
++{
++ struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;
++
++ if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {
++ if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh))
++ return -EIO;
++ *dent = (struct gfs2_dirent *)(bh->b_data +
++ sizeof(struct gfs2_leaf));
++ return IS_LEAF;
++ } else {
++ if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI))
++ return -EIO;
++ *dent = (struct gfs2_dirent *)(bh->b_data +
++ sizeof(struct gfs2_dinode));
++ return IS_DINODE;
++ }
++}
++
++static int dirent_check_reclen(struct gfs2_inode *dip,
++ const struct gfs2_dirent *d, const void *end_p)
++{
++ const void *ptr = d;
++ u16 rec_len = be16_to_cpu(d->de_rec_len);
++
++ if (unlikely(rec_len < sizeof(struct gfs2_dirent)))
++ goto broken;
++ ptr += rec_len;
++ if (ptr < end_p)
++ return rec_len;
++ if (ptr == end_p)
++ return -ENOENT;
++broken:
++ gfs2_consist_inode(dip);
++ return -EIO;
++}
++
++/**
++ * dirent_next - Next dirent
++ * @dip: the directory
++ * @bh: The buffer
++ * @dent: Pointer to list of dirents
++ *
++ * Returns: 0 on success, error code otherwise
++ */
++
++static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh,
++ struct gfs2_dirent **dent)
++{
++ struct gfs2_dirent *cur = *dent, *tmp;
++ char *bh_end = bh->b_data + bh->b_size;
++ int ret;
++
++ ret = dirent_check_reclen(dip, cur, bh_end);
++ if (ret < 0)
++ return ret;
++
++ tmp = (void *)cur + ret;
++ ret = dirent_check_reclen(dip, tmp, bh_end);
++ if (ret == -EIO)
++ return ret;
++
++ /* Only the first dent could ever have de_inum.no_addr == 0 */
++ if (!tmp->de_inum.no_addr) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++
++ *dent = tmp;
++ return 0;
++}
++
++/**
++ * dirent_del - Delete a dirent
++ * @dip: The GFS2 inode
++ * @bh: The buffer
++ * @prev: The previous dirent
++ * @cur: The current dirent
++ *
++ */
++
++static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh,
++ struct gfs2_dirent *prev, struct gfs2_dirent *cur)
++{
++ u16 cur_rec_len, prev_rec_len;
++
++ if (!cur->de_inum.no_addr) {
++ gfs2_consist_inode(dip);
++ return;
++ }
++
++ gfs2_trans_add_bh(dip->i_gl, bh, 1);
++
++ /* If there is no prev entry, this is the first entry in the block.
++ The de_rec_len is already as big as it needs to be. Just zero
++ out the inode number and return. */
++
++ if (!prev) {
++ cur->de_inum.no_addr = 0; /* No endianess worries */
++ return;
++ }
++
++ /* Combine this dentry with the previous one. */
++
++ prev_rec_len = be16_to_cpu(prev->de_rec_len);
++ cur_rec_len = be16_to_cpu(cur->de_rec_len);
++
++ if ((char *)prev + prev_rec_len != (char *)cur)
++ gfs2_consist_inode(dip);
++ if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size)
++ gfs2_consist_inode(dip);
++
++ prev_rec_len += cur_rec_len;
++ prev->de_rec_len = cpu_to_be16(prev_rec_len);
++}
++
++/*
++ * Takes a dent from which to grab space as an argument. Returns the
++ * newly created dent.
++ */
++static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode,
++ struct gfs2_dirent *dent,
++ const struct qstr *name,
++ struct buffer_head *bh)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_dirent *ndent;
++ unsigned offset = 0, totlen;
++
++ if (dent->de_inum.no_addr)
++ offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
++ totlen = be16_to_cpu(dent->de_rec_len);
++ BUG_ON(offset + name->len > totlen);
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ ndent = (struct gfs2_dirent *)((char *)dent + offset);
++ dent->de_rec_len = cpu_to_be16(offset);
++ gfs2_qstr2dirent(name, totlen - offset, ndent);
++ return ndent;
++}
++
++static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode,
++ struct buffer_head *bh,
++ const struct qstr *name)
++{
++ struct gfs2_dirent *dent;
++ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
++ gfs2_dirent_find_space, name, NULL);
++ if (!dent || IS_ERR(dent))
++ return dent;
++ return gfs2_init_dirent(inode, dent, name, bh);
++}
++
++static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,
++ struct buffer_head **bhp)
++{
++ int error;
++
++ error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp);
++ if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {
++ /* printk(KERN_INFO "block num=%llu\n", leaf_no); */
++ error = -EIO;
++ }
++
++ return error;
++}
++
++/**
++ * get_leaf_nr - Get a leaf number associated with the index
++ * @dip: The GFS2 inode
++ * @index:
++ * @leaf_out:
++ *
++ * Returns: 0 on success, error code otherwise
++ */
++
++static int get_leaf_nr(struct gfs2_inode *dip, u32 index,
++ u64 *leaf_out)
++{
++ u64 leaf_no;
++ int error;
++
++ error = gfs2_dir_read_data(dip, (char *)&leaf_no,
++ index * sizeof(u64),
++ sizeof(u64), 0);
++ if (error != sizeof(u64))
++ return (error < 0) ? error : -EIO;
++
++ *leaf_out = be64_to_cpu(leaf_no);
++
++ return 0;
++}
++
++static int get_first_leaf(struct gfs2_inode *dip, u32 index,
++ struct buffer_head **bh_out)
++{
++ u64 leaf_no;
++ int error;
++
++ error = get_leaf_nr(dip, index, &leaf_no);
++ if (!error)
++ error = get_leaf(dip, leaf_no, bh_out);
++
++ return error;
++}
++
++static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
++ const struct qstr *name,
++ gfs2_dscan_t scan,
++ struct buffer_head **pbh)
++{
++ struct buffer_head *bh;
++ struct gfs2_dirent *dent;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ int error;
++
++ if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
++ struct gfs2_leaf *leaf;
++ unsigned hsize = 1 << ip->i_di.di_depth;
++ unsigned index;
++ u64 ln;
++ if (hsize * sizeof(u64) != ip->i_di.di_size) {
++ gfs2_consist_inode(ip);
++ return ERR_PTR(-EIO);
++ }
++
++ index = name->hash >> (32 - ip->i_di.di_depth);
++ error = get_first_leaf(ip, index, &bh);
++ if (error)
++ return ERR_PTR(error);
++ do {
++ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
++ scan, name, NULL);
++ if (dent)
++ goto got_dent;
++ leaf = (struct gfs2_leaf *)bh->b_data;
++ ln = be64_to_cpu(leaf->lf_next);
++ brelse(bh);
++ if (!ln)
++ break;
++
++ error = get_leaf(ip, ln, &bh);
++ } while(!error);
++
++ return error ? ERR_PTR(error) : NULL;
++ }
++
++
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ return ERR_PTR(error);
++ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL);
++got_dent:
++ if (unlikely(dent == NULL || IS_ERR(dent))) {
++ brelse(bh);
++ bh = NULL;
++ }
++ *pbh = bh;
++ return dent;
++}
++
++static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ u64 bn = gfs2_alloc_meta(ip);
++ struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
++ struct gfs2_leaf *leaf;
++ struct gfs2_dirent *dent;
++ struct qstr name = { .name = "", .len = 0, .hash = 0 };
++ if (!bh)
++ return NULL;
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
++ leaf = (struct gfs2_leaf *)bh->b_data;
++ leaf->lf_depth = cpu_to_be16(depth);
++ leaf->lf_entries = 0;
++ leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
++ leaf->lf_next = 0;
++ memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved));
++ dent = (struct gfs2_dirent *)(leaf+1);
++ gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
++ *pbh = bh;
++ return leaf;
++}
++
++/**
++ * dir_make_exhash - Convert a stuffed directory into an ExHash directory
++ * @dip: The GFS2 inode
++ *
++ * Returns: 0 on success, error code otherwise
++ */
++
++static int dir_make_exhash(struct inode *inode)
++{
++ struct gfs2_inode *dip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ struct gfs2_dirent *dent;
++ struct qstr args;
++ struct buffer_head *bh, *dibh;
++ struct gfs2_leaf *leaf;
++ int y;
++ u32 x;
++ u64 *lp, bn;
++ int error;
++
++ error = gfs2_meta_inode_buffer(dip, &dibh);
++ if (error)
++ return error;
++
++ /* Turn over a new leaf */
++
++ leaf = new_leaf(inode, &bh, 0);
++ if (!leaf)
++ return -ENOSPC;
++ bn = bh->b_blocknr;
++
++ gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16));
++ leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);
++
++ /* Copy dirents */
++
++ gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh,
++ sizeof(struct gfs2_dinode));
++
++ /* Find last entry */
++
++ x = 0;
++ args.len = bh->b_size - sizeof(struct gfs2_dinode) +
++ sizeof(struct gfs2_leaf);
++ args.name = bh->b_data;
++ dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size,
++ gfs2_dirent_last, &args, NULL);
++ if (!dent) {
++ brelse(bh);
++ brelse(dibh);
++ return -EIO;
++ }
++ if (IS_ERR(dent)) {
++ brelse(bh);
++ brelse(dibh);
++ return PTR_ERR(dent);
++ }
++
++ /* Adjust the last dirent's record length
++ (Remember that dent still points to the last entry.) */
++
++ dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) +
++ sizeof(struct gfs2_dinode) -
++ sizeof(struct gfs2_leaf));
++
++ brelse(bh);
++
++ /* We're done with the new leaf block, now setup the new
++ hash table. */
++
++ gfs2_trans_add_bh(dip->i_gl, dibh, 1);
++ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
++
++ lp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode));
++
++ for (x = sdp->sd_hash_ptrs; x--; lp++)
++ *lp = cpu_to_be64(bn);
++
++ dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2;
++ dip->i_di.di_blocks++;
++ dip->i_di.di_flags |= GFS2_DIF_EXHASH;
++ dip->i_di.di_payload_format = 0;
++
++ for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
++ dip->i_di.di_depth = y;
++
++ gfs2_dinode_out(&dip->i_di, dibh->b_data);
++
++ brelse(dibh);
++
++ return 0;
++}
++
++/**
++ * dir_split_leaf - Split a leaf block into two
++ * @dip: The GFS2 inode
++ * @index:
++ * @leaf_no:
++ *
++ * Returns: 0 on success, error code on failure
++ */
++
++static int dir_split_leaf(struct inode *inode, const struct qstr *name)
++{
++ struct gfs2_inode *dip = GFS2_I(inode);
++ struct buffer_head *nbh, *obh, *dibh;
++ struct gfs2_leaf *nleaf, *oleaf;
++ struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new;
++ u32 start, len, half_len, divider;
++ u64 bn, *lp, leaf_no;
++ u32 index;
++ int x, moved = 0;
++ int error;
++
++ index = name->hash >> (32 - dip->i_di.di_depth);
++ error = get_leaf_nr(dip, index, &leaf_no);
++ if (error)
++ return error;
++
++ /* Get the old leaf block */
++ error = get_leaf(dip, leaf_no, &obh);
++ if (error)
++ return error;
++
++ oleaf = (struct gfs2_leaf *)obh->b_data;
++ if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) {
++ brelse(obh);
++ return 1; /* can't split */
++ }
++
++ gfs2_trans_add_bh(dip->i_gl, obh, 1);
++
++ nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1);
++ if (!nleaf) {
++ brelse(obh);
++ return -ENOSPC;
++ }
++ bn = nbh->b_blocknr;
++
++ /* Compute the start and len of leaf pointers in the hash table. */
++ len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));
++ half_len = len >> 1;
++ if (!half_len) {
++ printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index);
++ gfs2_consist_inode(dip);
++ error = -EIO;
++ goto fail_brelse;
++ }
++
++ start = (index & ~(len - 1));
++
++ /* Change the pointers.
++ Don't bother distinguishing stuffed from non-stuffed.
++ This code is complicated enough already. */
++ lp = kmalloc(half_len * sizeof(u64), GFP_NOFS | __GFP_NOFAIL);
++ /* Change the pointers */
++ for (x = 0; x < half_len; x++)
++ lp[x] = cpu_to_be64(bn);
++
++ error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64),
++ half_len * sizeof(u64));
++ if (error != half_len * sizeof(u64)) {
++ if (error >= 0)
++ error = -EIO;
++ goto fail_lpfree;
++ }
++
++ kfree(lp);
++
++ /* Compute the divider */
++ divider = (start + half_len) << (32 - dip->i_di.di_depth);
++
++ /* Copy the entries */
++ dirent_first(dip, obh, &dent);
++
++ do {
++ next = dent;
++ if (dirent_next(dip, obh, &next))
++ next = NULL;
++
++ if (dent->de_inum.no_addr &&
++ be32_to_cpu(dent->de_hash) < divider) {
++ struct qstr str;
++ str.name = (char*)(dent+1);
++ str.len = be16_to_cpu(dent->de_name_len);
++ str.hash = be32_to_cpu(dent->de_hash);
++ new = gfs2_dirent_alloc(inode, nbh, &str);
++ if (IS_ERR(new)) {
++ error = PTR_ERR(new);
++ break;
++ }
++
++ new->de_inum = dent->de_inum; /* No endian worries */
++ new->de_type = dent->de_type; /* No endian worries */
++ nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1);
++
++ dirent_del(dip, obh, prev, dent);
++
++ if (!oleaf->lf_entries)
++ gfs2_consist_inode(dip);
++ oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1);
++
++ if (!prev)
++ prev = dent;
++
++ moved = 1;
++ } else {
++ prev = dent;
++ }
++ dent = next;
++ } while (dent);
++
++ oleaf->lf_depth = nleaf->lf_depth;
++
++ error = gfs2_meta_inode_buffer(dip, &dibh);
++ if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
++ dip->i_di.di_blocks++;
++ gfs2_dinode_out(&dip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ brelse(obh);
++ brelse(nbh);
++
++ return error;
++
++fail_lpfree:
++ kfree(lp);
++
++fail_brelse:
++ brelse(obh);
++ brelse(nbh);
++ return error;
++}
++
++/**
++ * dir_double_exhash - Double size of ExHash table
++ * @dip: The GFS2 dinode
++ *
++ * Returns: 0 on success, error code on failure
++ */
++
++static int dir_double_exhash(struct gfs2_inode *dip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct buffer_head *dibh;
++ u32 hsize;
++ u64 *buf;
++ u64 *from, *to;
++ u64 block;
++ int x;
++ int error = 0;
++
++ hsize = 1 << dip->i_di.di_depth;
++ if (hsize * sizeof(u64) != dip->i_di.di_size) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++
++ /* Allocate both the "from" and "to" buffers in one big chunk */
++
++ buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL);
++
++ for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
++ error = gfs2_dir_read_data(dip, (char *)buf,
++ block * sdp->sd_hash_bsize,
++ sdp->sd_hash_bsize, 1);
++ if (error != sdp->sd_hash_bsize) {
++ if (error >= 0)
++ error = -EIO;
++ goto fail;
++ }
++
++ from = buf;
++ to = (u64 *)((char *)buf + sdp->sd_hash_bsize);
++
++ for (x = sdp->sd_hash_ptrs; x--; from++) {
++ *to++ = *from; /* No endianess worries */
++ *to++ = *from;
++ }
++
++ error = gfs2_dir_write_data(dip,
++ (char *)buf + sdp->sd_hash_bsize,
++ block * sdp->sd_sb.sb_bsize,
++ sdp->sd_sb.sb_bsize);
++ if (error != sdp->sd_sb.sb_bsize) {
++ if (error >= 0)
++ error = -EIO;
++ goto fail;
++ }
++ }
++
++ kfree(buf);
++
++ error = gfs2_meta_inode_buffer(dip, &dibh);
++ if (!gfs2_assert_withdraw(sdp, !error)) {
++ dip->i_di.di_depth++;
++ gfs2_dinode_out(&dip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ return error;
++
++fail:
++ kfree(buf);
++ return error;
++}
++
++/**
++ * compare_dents - compare directory entries by hash value
++ * @a: first dent
++ * @b: second dent
++ *
++ * When comparing the hash entries of @a to @b:
++ * gt: returns 1
++ * lt: returns -1
++ * eq: returns 0
++ */
++
++static int compare_dents(const void *a, const void *b)
++{
++ const struct gfs2_dirent *dent_a, *dent_b;
++ u32 hash_a, hash_b;
++ int ret = 0;
++
++ dent_a = *(const struct gfs2_dirent **)a;
++ hash_a = be32_to_cpu(dent_a->de_hash);
++
++ dent_b = *(const struct gfs2_dirent **)b;
++ hash_b = be32_to_cpu(dent_b->de_hash);
++
++ if (hash_a > hash_b)
++ ret = 1;
++ else if (hash_a < hash_b)
++ ret = -1;
++ else {
++ unsigned int len_a = be16_to_cpu(dent_a->de_name_len);
++ unsigned int len_b = be16_to_cpu(dent_b->de_name_len);
++
++ if (len_a > len_b)
++ ret = 1;
++ else if (len_a < len_b)
++ ret = -1;
++ else
++ ret = memcmp(dent_a + 1, dent_b + 1, len_a);
++ }
++
++ return ret;
++}
++
++/**
++ * do_filldir_main - read out directory entries
++ * @dip: The GFS2 inode
++ * @offset: The offset in the file to read from
++ * @opaque: opaque data to pass to filldir
++ * @filldir: The function to pass entries to
++ * @darr: an array of struct gfs2_dirent pointers to read
++ * @entries: the number of entries in darr
++ * @copied: pointer to int that's non-zero if a entry has been copied out
++ *
++ * Jump through some hoops to make sure that if there are hash collsions,
++ * they are read out at the beginning of a buffer. We want to minimize
++ * the possibility that they will fall into different readdir buffers or
++ * that someone will want to seek to that location.
++ *
++ * Returns: errno, >0 on exception from filldir
++ */
++
++static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
++ void *opaque, gfs2_filldir_t filldir,
++ const struct gfs2_dirent **darr, u32 entries,
++ int *copied)
++{
++ const struct gfs2_dirent *dent, *dent_next;
++ struct gfs2_inum inum;
++ u64 off, off_next;
++ unsigned int x, y;
++ int run = 0;
++ int error = 0;
++
++ sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL);
++
++ dent_next = darr[0];
++ off_next = be32_to_cpu(dent_next->de_hash);
++ off_next = gfs2_disk_hash2offset(off_next);
++
++ for (x = 0, y = 1; x < entries; x++, y++) {
++ dent = dent_next;
++ off = off_next;
++
++ if (y < entries) {
++ dent_next = darr[y];
++ off_next = be32_to_cpu(dent_next->de_hash);
++ off_next = gfs2_disk_hash2offset(off_next);
++
++ if (off < *offset)
++ continue;
++ *offset = off;
++
++ if (off_next == off) {
++ if (*copied && !run)
++ return 1;
++ run = 1;
++ } else
++ run = 0;
++ } else {
++ if (off < *offset)
++ continue;
++ *offset = off;
++ }
++
++ gfs2_inum_in(&inum, (char *)&dent->de_inum);
++
++ error = filldir(opaque, (const char *)(dent + 1),
++ be16_to_cpu(dent->de_name_len),
++ off, &inum,
++ be16_to_cpu(dent->de_type));
++ if (error)
++ return 1;
++
++ *copied = 1;
++ }
++
++ /* Increment the *offset by one, so the next time we come into the
++ do_filldir fxn, we get the next entry instead of the last one in the
++ current leaf */
++
++ (*offset)++;
++
++ return 0;
++}
++
++static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
++ gfs2_filldir_t filldir, int *copied,
++ unsigned *depth, u64 leaf_no)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct buffer_head *bh;
++ struct gfs2_leaf *lf;
++ unsigned entries = 0;
++ unsigned leaves = 0;
++ const struct gfs2_dirent **darr, *dent;
++ struct dirent_gather g;
++ struct buffer_head **larr;
++ int leaf = 0;
++ int error, i;
++ u64 lfn = leaf_no;
++
++ do {
++ error = get_leaf(ip, lfn, &bh);
++ if (error)
++ goto out;
++ lf = (struct gfs2_leaf *)bh->b_data;
++ if (leaves == 0)
++ *depth = be16_to_cpu(lf->lf_depth);
++ entries += be16_to_cpu(lf->lf_entries);
++ leaves++;
++ lfn = be64_to_cpu(lf->lf_next);
++ brelse(bh);
++ } while(lfn);
++
++ if (!entries)
++ return 0;
++
++ error = -ENOMEM;
++ larr = vmalloc((leaves + entries) * sizeof(void *));
++ if (!larr)
++ goto out;
++ darr = (const struct gfs2_dirent **)(larr + leaves);
++ g.pdent = darr;
++ g.offset = 0;
++ lfn = leaf_no;
++
++ do {
++ error = get_leaf(ip, lfn, &bh);
++ if (error)
++ goto out_kfree;
++ lf = (struct gfs2_leaf *)bh->b_data;
++ lfn = be64_to_cpu(lf->lf_next);
++ if (lf->lf_entries) {
++ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
++ gfs2_dirent_gather, NULL, &g);
++ error = PTR_ERR(dent);
++ if (IS_ERR(dent)) {
++ goto out_kfree;
++ }
++ error = 0;
++ larr[leaf++] = bh;
++ } else {
++ brelse(bh);
++ }
++ } while(lfn);
++
++ error = do_filldir_main(ip, offset, opaque, filldir, darr,
++ entries, copied);
++out_kfree:
++ for(i = 0; i < leaf; i++)
++ brelse(larr[i]);
++ vfree(larr);
++out:
++ return error;
++}
++
++/**
++ * dir_e_read - Reads the entries from a directory into a filldir buffer
++ * @dip: dinode pointer
++ * @offset: the hash of the last entry read shifted to the right once
++ * @opaque: buffer for the filldir function to fill
++ * @filldir: points to the filldir function to use
++ *
++ * Returns: errno
++ */
++
++static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
++ gfs2_filldir_t filldir)
++{
++ struct gfs2_inode *dip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ u32 hsize, len = 0;
++ u32 ht_offset, lp_offset, ht_offset_cur = -1;
++ u32 hash, index;
++ u64 *lp;
++ int copied = 0;
++ int error = 0;
++ unsigned depth = 0;
++
++ hsize = 1 << dip->i_di.di_depth;
++ if (hsize * sizeof(u64) != dip->i_di.di_size) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++
++ hash = gfs2_dir_offset2hash(*offset);
++ index = hash >> (32 - dip->i_di.di_depth);
++
++ lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);
++ if (!lp)
++ return -ENOMEM;
++
++ while (index < hsize) {
++ lp_offset = index & (sdp->sd_hash_ptrs - 1);
++ ht_offset = index - lp_offset;
++
++ if (ht_offset_cur != ht_offset) {
++ error = gfs2_dir_read_data(dip, (char *)lp,
++ ht_offset * sizeof(u64),
++ sdp->sd_hash_bsize, 1);
++ if (error != sdp->sd_hash_bsize) {
++ if (error >= 0)
++ error = -EIO;
++ goto out;
++ }
++ ht_offset_cur = ht_offset;
++ }
++
++ error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
++ &copied, &depth,
++ be64_to_cpu(lp[lp_offset]));
++ if (error)
++ break;
++
++ len = 1 << (dip->i_di.di_depth - depth);
++ index = (index & ~(len - 1)) + len;
++ }
++
++out:
++ kfree(lp);
++ if (error > 0)
++ error = 0;
++ return error;
++}
++
++int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
++ gfs2_filldir_t filldir)
++{
++ struct gfs2_inode *dip = GFS2_I(inode);
++ struct dirent_gather g;
++ const struct gfs2_dirent **darr, *dent;
++ struct buffer_head *dibh;
++ int copied = 0;
++ int error;
++
++ if (!dip->i_di.di_entries)
++ return 0;
++
++ if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
++ return dir_e_read(inode, offset, opaque, filldir);
++
++ if (!gfs2_is_stuffed(dip)) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++
++ error = gfs2_meta_inode_buffer(dip, &dibh);
++ if (error)
++ return error;
++
++ error = -ENOMEM;
++ darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
++ GFP_KERNEL);
++ if (darr) {
++ g.pdent = darr;
++ g.offset = 0;
++ dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,
++ gfs2_dirent_gather, NULL, &g);
++ if (IS_ERR(dent)) {
++ error = PTR_ERR(dent);
++ goto out;
++ }
++ error = do_filldir_main(dip, offset, opaque, filldir, darr,
++ dip->i_di.di_entries, &copied);
++out:
++ kfree(darr);
++ }
++
++ if (error > 0)
++ error = 0;
++
++ brelse(dibh);
++
++ return error;
++}
++
++/**
++ * gfs2_dir_search - Search a directory
++ * @dip: The GFS2 inode
++ * @filename:
++ * @inode:
++ *
++ * This routine searches a directory for a file or another directory.
++ * Assumes a glock is held on dip.
++ *
++ * Returns: errno
++ */
++
++int gfs2_dir_search(struct inode *dir, const struct qstr *name,
++ struct gfs2_inum *inum, unsigned int *type)
++{
++ struct buffer_head *bh;
++ struct gfs2_dirent *dent;
++
++ dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
++ if (dent) {
++ if (IS_ERR(dent))
++ return PTR_ERR(dent);
++ if (inum)
++ gfs2_inum_in(inum, (char *)&dent->de_inum);
++ if (type)
++ *type = be16_to_cpu(dent->de_type);
++ brelse(bh);
++ return 0;
++ }
++ return -ENOENT;
++}
++
++static int dir_new_leaf(struct inode *inode, const struct qstr *name)
++{
++ struct buffer_head *bh, *obh;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_leaf *leaf, *oleaf;
++ int error;
++ u32 index;
++ u64 bn;
++
++ index = name->hash >> (32 - ip->i_di.di_depth);
++ error = get_first_leaf(ip, index, &obh);
++ if (error)
++ return error;
++ do {
++ oleaf = (struct gfs2_leaf *)obh->b_data;
++ bn = be64_to_cpu(oleaf->lf_next);
++ if (!bn)
++ break;
++ brelse(obh);
++ error = get_leaf(ip, bn, &obh);
++ if (error)
++ return error;
++ } while(1);
++
++ gfs2_trans_add_bh(ip->i_gl, obh, 1);
++
++ leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth));
++ if (!leaf) {
++ brelse(obh);
++ return -ENOSPC;
++ }
++ oleaf->lf_next = cpu_to_be64(bh->b_blocknr);
++ brelse(bh);
++ brelse(obh);
++
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ return error;
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ ip->i_di.di_blocks++;
++ gfs2_dinode_out(&ip->i_di, bh->b_data);
++ brelse(bh);
++ return 0;
++}
++
++/**
++ * gfs2_dir_add - Add new filename into directory
++ * @dip: The GFS2 inode
++ * @filename: The new name
++ * @inode: The inode number of the entry
++ * @type: The type of the entry
++ *
++ * Returns: 0 on success, error code on failure
++ */
++
++int gfs2_dir_add(struct inode *inode, const struct qstr *name,
++ const struct gfs2_inum *inum, unsigned type)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct buffer_head *bh;
++ struct gfs2_dirent *dent;
++ struct gfs2_leaf *leaf;
++ int error;
++
++ while(1) {
++ dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space,
++ &bh);
++ if (dent) {
++ if (IS_ERR(dent))
++ return PTR_ERR(dent);
++ dent = gfs2_init_dirent(inode, dent, name, bh);
++ gfs2_inum_out(inum, (char *)&dent->de_inum);
++ dent->de_type = cpu_to_be16(type);
++ if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
++ leaf = (struct gfs2_leaf *)bh->b_data;
++ leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1);
++ }
++ brelse(bh);
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ break;
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ ip->i_di.di_entries++;
++ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
++ gfs2_dinode_out(&ip->i_di, bh->b_data);
++ brelse(bh);
++ error = 0;
++ break;
++ }
++ if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
++ error = dir_make_exhash(inode);
++ if (error)
++ break;
++ continue;
++ }
++ error = dir_split_leaf(inode, name);
++ if (error == 0)
++ continue;
++ if (error < 0)
++ break;
++ if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) {
++ error = dir_double_exhash(ip);
++ if (error)
++ break;
++ error = dir_split_leaf(inode, name);
++ if (error < 0)
++ break;
++ if (error == 0)
++ continue;
++ }
++ error = dir_new_leaf(inode, name);
++ if (!error)
++ continue;
++ error = -ENOSPC;
++ break;
++ }
++ return error;
++}
++
++
++/**
++ * gfs2_dir_del - Delete a directory entry
++ * @dip: The GFS2 inode
++ * @filename: The filename
++ *
++ * Returns: 0 on success, error code on failure
++ */
++
++int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
++{
++ struct gfs2_dirent *dent, *prev = NULL;
++ struct buffer_head *bh;
++ int error;
++
++ /* Returns _either_ the entry (if its first in block) or the
++ previous entry otherwise */
++ dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh);
++ if (!dent) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++ if (IS_ERR(dent)) {
++ gfs2_consist_inode(dip);
++ return PTR_ERR(dent);
++ }
++ /* If not first in block, adjust pointers accordingly */
++ if (gfs2_dirent_find(dent, name, NULL) == 0) {
++ prev = dent;
++ dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len));
++ }
++
++ dirent_del(dip, bh, prev, dent);
++ if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
++ struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
++ u16 entries = be16_to_cpu(leaf->lf_entries);
++ if (!entries)
++ gfs2_consist_inode(dip);
++ leaf->lf_entries = cpu_to_be16(--entries);
++ }
++ brelse(bh);
++
++ error = gfs2_meta_inode_buffer(dip, &bh);
++ if (error)
++ return error;
++
++ if (!dip->i_di.di_entries)
++ gfs2_consist_inode(dip);
++ gfs2_trans_add_bh(dip->i_gl, bh, 1);
++ dip->i_di.di_entries--;
++ dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds();
++ gfs2_dinode_out(&dip->i_di, bh->b_data);
++ brelse(bh);
++ mark_inode_dirty(&dip->i_inode);
++
++ return error;
++}
++
++/**
++ * gfs2_dir_mvino - Change inode number of directory entry
++ * @dip: The GFS2 inode
++ * @filename:
++ * @new_inode:
++ *
++ * This routine changes the inode number of a directory entry. It's used
++ * by rename to change ".." when a directory is moved.
++ * Assumes a glock is held on dvp.
++ *
++ * Returns: errno
++ */
++
++int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
++ struct gfs2_inum *inum, unsigned int new_type)
++{
++ struct buffer_head *bh;
++ struct gfs2_dirent *dent;
++ int error;
++
++ dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);
++ if (!dent) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++ if (IS_ERR(dent))
++ return PTR_ERR(dent);
++
++ gfs2_trans_add_bh(dip->i_gl, bh, 1);
++ gfs2_inum_out(inum, (char *)&dent->de_inum);
++ dent->de_type = cpu_to_be16(new_type);
++
++ if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
++ brelse(bh);
++ error = gfs2_meta_inode_buffer(dip, &bh);
++ if (error)
++ return error;
++ gfs2_trans_add_bh(dip->i_gl, bh, 1);
++ }
++
++ dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds();
++ gfs2_dinode_out(&dip->i_di, bh->b_data);
++ brelse(bh);
++ return 0;
++}
++
++/**
++ * foreach_leaf - call a function for each leaf in a directory
++ * @dip: the directory
++ * @lc: the function to call for each each
++ * @data: private data to pass to it
++ *
++ * Returns: errno
++ */
++
++static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct buffer_head *bh;
++ struct gfs2_leaf *leaf;
++ u32 hsize, len;
++ u32 ht_offset, lp_offset, ht_offset_cur = -1;
++ u32 index = 0;
++ u64 *lp;
++ u64 leaf_no;
++ int error = 0;
++
++ hsize = 1 << dip->i_di.di_depth;
++ if (hsize * sizeof(u64) != dip->i_di.di_size) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++
++ lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);
++ if (!lp)
++ return -ENOMEM;
++
++ while (index < hsize) {
++ lp_offset = index & (sdp->sd_hash_ptrs - 1);
++ ht_offset = index - lp_offset;
++
++ if (ht_offset_cur != ht_offset) {
++ error = gfs2_dir_read_data(dip, (char *)lp,
++ ht_offset * sizeof(u64),
++ sdp->sd_hash_bsize, 1);
++ if (error != sdp->sd_hash_bsize) {
++ if (error >= 0)
++ error = -EIO;
++ goto out;
++ }
++ ht_offset_cur = ht_offset;
++ }
++
++ leaf_no = be64_to_cpu(lp[lp_offset]);
++ if (leaf_no) {
++ error = get_leaf(dip, leaf_no, &bh);
++ if (error)
++ goto out;
++ leaf = (struct gfs2_leaf *)bh->b_data;
++ len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));
++ brelse(bh);
++
++ error = lc(dip, index, len, leaf_no, data);
++ if (error)
++ goto out;
++
++ index = (index & ~(len - 1)) + len;
++ } else
++ index++;
++ }
++
++ if (index != hsize) {
++ gfs2_consist_inode(dip);
++ error = -EIO;
++ }
++
++out:
++ kfree(lp);
++
++ return error;
++}
++
++/**
++ * leaf_dealloc - Deallocate a directory leaf
++ * @dip: the directory
++ * @index: the hash table offset in the directory
++ * @len: the number of pointers to this leaf
++ * @leaf_no: the leaf number
++ * @data: not used
++ *
++ * Returns: errno
++ */
++
++static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
++ u64 leaf_no, void *data)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct gfs2_leaf *tmp_leaf;
++ struct gfs2_rgrp_list rlist;
++ struct buffer_head *bh, *dibh;
++ u64 blk, nblk;
++ unsigned int rg_blocks = 0, l_blocks = 0;
++ char *ht;
++ unsigned int x, size = len * sizeof(u64);
++ int error;
++
++ memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
++
++ ht = kzalloc(size, GFP_KERNEL);
++ if (!ht)
++ return -ENOMEM;
++
++ gfs2_alloc_get(dip);
++
++ error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out;
++
++ error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);
++ if (error)
++ goto out_qs;
++
++ /* Count the number of leaves */
++
++ for (blk = leaf_no; blk; blk = nblk) {
++ error = get_leaf(dip, blk, &bh);
++ if (error)
++ goto out_rlist;
++ tmp_leaf = (struct gfs2_leaf *)bh->b_data;
++ nblk = be64_to_cpu(tmp_leaf->lf_next);
++ brelse(bh);
++
++ gfs2_rlist_add(sdp, &rlist, blk);
++ l_blocks++;
++ }
++
++ gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
++
++ for (x = 0; x < rlist.rl_rgrps; x++) {
++ struct gfs2_rgrpd *rgd;
++ rgd = rlist.rl_ghs[x].gh_gl->gl_object;
++ rg_blocks += rgd->rd_ri.ri_length;
++ }
++
++ error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
++ if (error)
++ goto out_rlist;
++
++ error = gfs2_trans_begin(sdp,
++ rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) +
++ RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks);
++ if (error)
++ goto out_rg_gunlock;
++
++ for (blk = leaf_no; blk; blk = nblk) {
++ error = get_leaf(dip, blk, &bh);
++ if (error)
++ goto out_end_trans;
++ tmp_leaf = (struct gfs2_leaf *)bh->b_data;
++ nblk = be64_to_cpu(tmp_leaf->lf_next);
++ brelse(bh);
++
++ gfs2_free_meta(dip, blk, 1);
++
++ if (!dip->i_di.di_blocks)
++ gfs2_consist_inode(dip);
++ dip->i_di.di_blocks--;
++ }
++
++ error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size);
++ if (error != size) {
++ if (error >= 0)
++ error = -EIO;
++ goto out_end_trans;
++ }
++
++ error = gfs2_meta_inode_buffer(dip, &dibh);
++ if (error)
++ goto out_end_trans;
++
++ gfs2_trans_add_bh(dip->i_gl, dibh, 1);
++ gfs2_dinode_out(&dip->i_di, dibh->b_data);
++ brelse(dibh);
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_rg_gunlock:
++ gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
++out_rlist:
++ gfs2_rlist_free(&rlist);
++ gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);
++out_qs:
++ gfs2_quota_unhold(dip);
++out:
++ gfs2_alloc_put(dip);
++ kfree(ht);
++ return error;
++}
++
++/**
++ * gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory
++ * @dip: the directory
++ *
++ * Dealloc all on-disk directory leaves to FREEMETA state
++ * Change on-disk inode type to "regular file"
++ *
++ * Returns: errno
++ */
++
++int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct buffer_head *bh;
++ int error;
++
++ /* Dealloc on-disk leaves to FREEMETA state */
++ error = foreach_leaf(dip, leaf_dealloc, NULL);
++ if (error)
++ return error;
++
++ /* Make this a regular file in case we crash.
++ (We don't want to free these blocks a second time.) */
++
++ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
++ if (error)
++ return error;
++
++ error = gfs2_meta_inode_buffer(dip, &bh);
++ if (!error) {
++ gfs2_trans_add_bh(dip->i_gl, bh, 1);
++ ((struct gfs2_dinode *)bh->b_data)->di_mode =
++ cpu_to_be32(S_IFREG);
++ brelse(bh);
++ }
++
++ gfs2_trans_end(sdp);
++
++ return error;
++}
++
++/**
++ * gfs2_diradd_alloc_required - find if adding entry will require an allocation
++ * @ip: the file being written to
++ * @filname: the filename that's going to be added
++ *
++ * Returns: 1 if alloc required, 0 if not, -ve on error
++ */
++
++int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name)
++{
++ struct gfs2_dirent *dent;
++ struct buffer_head *bh;
++
++ dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh);
++ if (!dent) {
++ return 1;
++ }
++ if (IS_ERR(dent))
++ return PTR_ERR(dent);
++ brelse(bh);
++ return 0;
++}
++
+diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
+new file mode 100644
+index 0000000..3712334
+--- /dev/null
++++ b/fs/gfs2/dir.h
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __DIR_DOT_H__
++#define __DIR_DOT_H__
++
++#include <linux/dcache.h>
++
++struct inode;
++struct gfs2_inode;
++struct gfs2_inum;
++
++/**
++ * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read()
++ * @opaque: opaque data used by the function
++ * @name: the name of the directory entry
++ * @length: the length of the name
++ * @offset: the entry's offset in the directory
++ * @inum: the inode number the entry points to
++ * @type: the type of inode the entry points to
++ *
++ * Returns: 0 on success, 1 if buffer full
++ */
++
++typedef int (*gfs2_filldir_t) (void *opaque,
++ const char *name, unsigned int length,
++ u64 offset,
++ struct gfs2_inum *inum, unsigned int type);
++
++int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
++ struct gfs2_inum *inum, unsigned int *type);
++int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
++ const struct gfs2_inum *inum, unsigned int type);
++int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
++int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque,
++ gfs2_filldir_t filldir);
++int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
++ struct gfs2_inum *new_inum, unsigned int new_type);
++
++int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
++
++int gfs2_diradd_alloc_required(struct inode *dir,
++ const struct qstr *filename);
++int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
++ struct buffer_head **bhp);
++
++static inline u32 gfs2_disk_hash(const char *data, int len)
++{
++ return crc32_le((u32)~0, data, len) ^ (u32)~0;
++}
++
++
++static inline void gfs2_str2qstr(struct qstr *name, const char *fname)
++{
++ name->name = fname;
++ name->len = strlen(fname);
++ name->hash = gfs2_disk_hash(name->name, name->len);
++}
++
++/* N.B. This probably ought to take inum & type as args as well */
++static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent)
++{
++ dent->de_inum.no_addr = cpu_to_be64(0);
++ dent->de_inum.no_formal_ino = cpu_to_be64(0);
++ dent->de_hash = cpu_to_be32(name->hash);
++ dent->de_rec_len = cpu_to_be16(reclen);
++ dent->de_name_len = cpu_to_be16(name->len);
++ dent->de_type = cpu_to_be16(0);
++ memset(dent->__pad, 0, sizeof(dent->__pad));
++ memcpy(dent + 1, name->name, name->len);
++}
++
++#endif /* __DIR_DOT_H__ */
+diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
+new file mode 100644
+index 0000000..92c54e9
+--- /dev/null
++++ b/fs/gfs2/eaops.c
+@@ -0,0 +1,230 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/xattr.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "acl.h"
++#include "eaops.h"
++#include "eattr.h"
++#include "util.h"
++
++/**
++ * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
++ * @namep: ea name, possibly with type appended
++ *
++ * Returns: GFS2_EATYPE_XXX
++ */
++
++unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
++{
++ unsigned int type;
++
++ if (strncmp(name, "system.", 7) == 0) {
++ type = GFS2_EATYPE_SYS;
++ if (truncated_name)
++ *truncated_name = name + sizeof("system.") - 1;
++ } else if (strncmp(name, "user.", 5) == 0) {
++ type = GFS2_EATYPE_USR;
++ if (truncated_name)
++ *truncated_name = name + sizeof("user.") - 1;
++ } else if (strncmp(name, "security.", 9) == 0) {
++ type = GFS2_EATYPE_SECURITY;
++ if (truncated_name)
++ *truncated_name = name + sizeof("security.") - 1;
++ } else {
++ type = GFS2_EATYPE_UNUSED;
++ if (truncated_name)
++ *truncated_name = NULL;
++ }
++
++ return type;
++}
++
++static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct inode *inode = &ip->i_inode;
++ int error = permission(inode, MAY_READ, NULL);
++ if (error)
++ return error;
++
++ return gfs2_ea_get_i(ip, er);
++}
++
++static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct inode *inode = &ip->i_inode;
++
++ if (S_ISREG(inode->i_mode) ||
++ (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
++ int error = permission(inode, MAY_WRITE, NULL);
++ if (error)
++ return error;
++ } else
++ return -EPERM;
++
++ return gfs2_ea_set_i(ip, er);
++}
++
++static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct inode *inode = &ip->i_inode;
++
++ if (S_ISREG(inode->i_mode) ||
++ (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
++ int error = permission(inode, MAY_WRITE, NULL);
++ if (error)
++ return error;
++ } else
++ return -EPERM;
++
++ return gfs2_ea_remove_i(ip, er);
++}
++
++static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
++ !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
++ !capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 &&
++ (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
++ GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
++ return -EOPNOTSUPP;
++
++
++
++ return gfs2_ea_get_i(ip, er);
++}
++
++static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ int remove = 0;
++ int error;
++
++ if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
++ if (!(er->er_flags & GFS2_ERF_MODE)) {
++ er->er_mode = ip->i_di.di_mode;
++ er->er_flags |= GFS2_ERF_MODE;
++ }
++ error = gfs2_acl_validate_set(ip, 1, er,
++ &remove, &er->er_mode);
++ if (error)
++ return error;
++ error = gfs2_ea_set_i(ip, er);
++ if (error)
++ return error;
++ if (remove)
++ gfs2_ea_remove_i(ip, er);
++ return 0;
++
++ } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
++ error = gfs2_acl_validate_set(ip, 0, er,
++ &remove, NULL);
++ if (error)
++ return error;
++ if (!remove)
++ error = gfs2_ea_set_i(ip, er);
++ else {
++ error = gfs2_ea_remove_i(ip, er);
++ if (error == -ENODATA)
++ error = 0;
++ }
++ return error;
++ }
++
++ return -EPERM;
++}
++
++static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
++ int error = gfs2_acl_validate_remove(ip, 1);
++ if (error)
++ return error;
++
++ } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
++ int error = gfs2_acl_validate_remove(ip, 0);
++ if (error)
++ return error;
++
++ } else
++ return -EPERM;
++
++ return gfs2_ea_remove_i(ip, er);
++}
++
++static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct inode *inode = &ip->i_inode;
++ int error = permission(inode, MAY_READ, NULL);
++ if (error)
++ return error;
++
++ return gfs2_ea_get_i(ip, er);
++}
++
++static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct inode *inode = &ip->i_inode;
++ int error = permission(inode, MAY_WRITE, NULL);
++ if (error)
++ return error;
++
++ return gfs2_ea_set_i(ip, er);
++}
++
++static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct inode *inode = &ip->i_inode;
++ int error = permission(inode, MAY_WRITE, NULL);
++ if (error)
++ return error;
++
++ return gfs2_ea_remove_i(ip, er);
++}
++
++static struct gfs2_eattr_operations gfs2_user_eaops = {
++ .eo_get = user_eo_get,
++ .eo_set = user_eo_set,
++ .eo_remove = user_eo_remove,
++ .eo_name = "user",
++};
++
++struct gfs2_eattr_operations gfs2_system_eaops = {
++ .eo_get = system_eo_get,
++ .eo_set = system_eo_set,
++ .eo_remove = system_eo_remove,
++ .eo_name = "system",
++};
++
++static struct gfs2_eattr_operations gfs2_security_eaops = {
++ .eo_get = security_eo_get,
++ .eo_set = security_eo_set,
++ .eo_remove = security_eo_remove,
++ .eo_name = "security",
++};
++
++struct gfs2_eattr_operations *gfs2_ea_ops[] = {
++ NULL,
++ &gfs2_user_eaops,
++ &gfs2_system_eaops,
++ &gfs2_security_eaops,
++};
++
+diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h
+new file mode 100644
+index 0000000..508b4f7
+--- /dev/null
++++ b/fs/gfs2/eaops.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __EAOPS_DOT_H__
++#define __EAOPS_DOT_H__
++
++struct gfs2_ea_request;
++struct gfs2_inode;
++
++struct gfs2_eattr_operations {
++ int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
++ int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
++ int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
++ char *eo_name;
++};
++
++unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
++
++extern struct gfs2_eattr_operations gfs2_system_eaops;
++
++extern struct gfs2_eattr_operations *gfs2_ea_ops[];
++
++#endif /* __EAOPS_DOT_H__ */
++
+diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
+new file mode 100644
+index 0000000..a65a4cc
+--- /dev/null
++++ b/fs/gfs2/eattr.c
+@@ -0,0 +1,1501 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/xattr.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "acl.h"
++#include "eaops.h"
++#include "eattr.h"
++#include "glock.h"
++#include "inode.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++
++/**
++ * ea_calc_size - returns the acutal number of bytes the request will take up
++ * (not counting any unstuffed data blocks)
++ * @sdp:
++ * @er:
++ * @size:
++ *
++ * Returns: 1 if the EA should be stuffed
++ */
++
++static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er,
++ unsigned int *size)
++{
++ *size = GFS2_EAREQ_SIZE_STUFFED(er);
++ if (*size <= sdp->sd_jbsize)
++ return 1;
++
++ *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er);
++
++ return 0;
++}
++
++static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er)
++{
++ unsigned int size;
++
++ if (er->er_data_len > GFS2_EA_MAX_DATA_LEN)
++ return -ERANGE;
++
++ ea_calc_size(sdp, er, &size);
++
++ /* This can only happen with 512 byte blocks */
++ if (size > sdp->sd_jbsize)
++ return -ERANGE;
++
++ return 0;
++}
++
++typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea,
++ struct gfs2_ea_header *prev, void *private);
++
++static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh,
++ ea_call_t ea_call, void *data)
++{
++ struct gfs2_ea_header *ea, *prev = NULL;
++ int error = 0;
++
++ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_EA))
++ return -EIO;
++
++ for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) {
++ if (!GFS2_EA_REC_LEN(ea))
++ goto fail;
++ if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <=
++ bh->b_data + bh->b_size))
++ goto fail;
++ if (!GFS2_EATYPE_VALID(ea->ea_type))
++ goto fail;
++
++ error = ea_call(ip, bh, ea, prev, data);
++ if (error)
++ return error;
++
++ if (GFS2_EA_IS_LAST(ea)) {
++ if ((char *)GFS2_EA2NEXT(ea) !=
++ bh->b_data + bh->b_size)
++ goto fail;
++ break;
++ }
++ }
++
++ return error;
++
++fail:
++ gfs2_consist_inode(ip);
++ return -EIO;
++}
++
++static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
++{
++ struct buffer_head *bh, *eabh;
++ u64 *eablk, *end;
++ int error;
++
++ error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &bh);
++ if (error)
++ return error;
++
++ if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) {
++ error = ea_foreach_i(ip, bh, ea_call, data);
++ goto out;
++ }
++
++ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_IN)) {
++ error = -EIO;
++ goto out;
++ }
++
++ eablk = (u64 *)(bh->b_data + sizeof(struct gfs2_meta_header));
++ end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs;
++
++ for (; eablk < end; eablk++) {
++ u64 bn;
++
++ if (!*eablk)
++ break;
++ bn = be64_to_cpu(*eablk);
++
++ error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh);
++ if (error)
++ break;
++ error = ea_foreach_i(ip, eabh, ea_call, data);
++ brelse(eabh);
++ if (error)
++ break;
++ }
++out:
++ brelse(bh);
++ return error;
++}
++
++struct ea_find {
++ struct gfs2_ea_request *ef_er;
++ struct gfs2_ea_location *ef_el;
++};
++
++static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
++ void *private)
++{
++ struct ea_find *ef = private;
++ struct gfs2_ea_request *er = ef->ef_er;
++
++ if (ea->ea_type == GFS2_EATYPE_UNUSED)
++ return 0;
++
++ if (ea->ea_type == er->er_type) {
++ if (ea->ea_name_len == er->er_name_len &&
++ !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) {
++ struct gfs2_ea_location *el = ef->ef_el;
++ get_bh(bh);
++ el->el_bh = bh;
++ el->el_ea = ea;
++ el->el_prev = prev;
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er,
++ struct gfs2_ea_location *el)
++{
++ struct ea_find ef;
++ int error;
++
++ ef.ef_er = er;
++ ef.ef_el = el;
++
++ memset(el, 0, sizeof(struct gfs2_ea_location));
++
++ error = ea_foreach(ip, ea_find_i, &ef);
++ if (error > 0)
++ return 0;
++
++ return error;
++}
++
++/**
++ * ea_dealloc_unstuffed -
++ * @ip:
++ * @bh:
++ * @ea:
++ * @prev:
++ * @private:
++ *
++ * Take advantage of the fact that all unstuffed blocks are
++ * allocated from the same RG. But watch, this may not always
++ * be true.
++ *
++ * Returns: errno
++ */
++
++static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea,
++ struct gfs2_ea_header *prev, void *private)
++{
++ int *leave = private;
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_rgrpd *rgd;
++ struct gfs2_holder rg_gh;
++ struct buffer_head *dibh;
++ u64 *dataptrs, bn = 0;
++ u64 bstart = 0;
++ unsigned int blen = 0;
++ unsigned int blks = 0;
++ unsigned int x;
++ int error;
++
++ if (GFS2_EA_IS_STUFFED(ea))
++ return 0;
++
++ dataptrs = GFS2_EA2DATAPTRS(ea);
++ for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
++ if (*dataptrs) {
++ blks++;
++ bn = be64_to_cpu(*dataptrs);
++ }
++ }
++ if (!blks)
++ return 0;
++
++ rgd = gfs2_blk2rgrpd(sdp, bn);
++ if (!rgd) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
++ if (error)
++ return error;
++
++ error = gfs2_trans_begin(sdp, rgd->rd_ri.ri_length + RES_DINODE +
++ RES_EATTR + RES_STATFS + RES_QUOTA, blks);
++ if (error)
++ goto out_gunlock;
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++
++ dataptrs = GFS2_EA2DATAPTRS(ea);
++ for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
++ if (!*dataptrs)
++ break;
++ bn = be64_to_cpu(*dataptrs);
++
++ if (bstart + blen == bn)
++ blen++;
++ else {
++ if (bstart)
++ gfs2_free_meta(ip, bstart, blen);
++ bstart = bn;
++ blen = 1;
++ }
++
++ *dataptrs = 0;
++ if (!ip->i_di.di_blocks)
++ gfs2_consist_inode(ip);
++ ip->i_di.di_blocks--;
++ }
++ if (bstart)
++ gfs2_free_meta(ip, bstart, blen);
++
++ if (prev && !leave) {
++ u32 len;
++
++ len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
++ prev->ea_rec_len = cpu_to_be32(len);
++
++ if (GFS2_EA_IS_LAST(ea))
++ prev->ea_flags |= GFS2_EAFLAG_LAST;
++ } else {
++ ea->ea_type = GFS2_EATYPE_UNUSED;
++ ea->ea_num_ptrs = 0;
++ }
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ ip->i_di.di_ctime = get_seconds();
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(sdp);
++
++out_gunlock:
++ gfs2_glock_dq_uninit(&rg_gh);
++ return error;
++}
++
++static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea,
++ struct gfs2_ea_header *prev, int leave)
++{
++ struct gfs2_alloc *al;
++ int error;
++
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out_alloc;
++
++ error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
++ if (error)
++ goto out_quota;
++
++ error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
++
++ gfs2_glock_dq_uninit(&al->al_ri_gh);
++
++out_quota:
++ gfs2_quota_unhold(ip);
++out_alloc:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++struct ea_list {
++ struct gfs2_ea_request *ei_er;
++ unsigned int ei_size;
++};
++
++static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
++ void *private)
++{
++ struct ea_list *ei = private;
++ struct gfs2_ea_request *er = ei->ei_er;
++ unsigned int ea_size = gfs2_ea_strlen(ea);
++
++ if (ea->ea_type == GFS2_EATYPE_UNUSED)
++ return 0;
++
++ if (er->er_data_len) {
++ char *prefix = NULL;
++ unsigned int l = 0;
++ char c = 0;
++
++ if (ei->ei_size + ea_size > er->er_data_len)
++ return -ERANGE;
++
++ switch (ea->ea_type) {
++ case GFS2_EATYPE_USR:
++ prefix = "user.";
++ l = 5;
++ break;
++ case GFS2_EATYPE_SYS:
++ prefix = "system.";
++ l = 7;
++ break;
++ case GFS2_EATYPE_SECURITY:
++ prefix = "security.";
++ l = 9;
++ break;
++ }
++
++ BUG_ON(l == 0);
++
++ memcpy(er->er_data + ei->ei_size, prefix, l);
++ memcpy(er->er_data + ei->ei_size + l, GFS2_EA2NAME(ea),
++ ea->ea_name_len);
++ memcpy(er->er_data + ei->ei_size + ea_size - 1, &c, 1);
++ }
++
++ ei->ei_size += ea_size;
++
++ return 0;
++}
++
++/**
++ * gfs2_ea_list -
++ * @ip:
++ * @er:
++ *
++ * Returns: actual size of data on success, -errno on error
++ */
++
++int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_holder i_gh;
++ int error;
++
++ if (!er->er_data || !er->er_data_len) {
++ er->er_data = NULL;
++ er->er_data_len = 0;
++ }
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
++ if (error)
++ return error;
++
++ if (ip->i_di.di_eattr) {
++ struct ea_list ei = { .ei_er = er, .ei_size = 0 };
++
++ error = ea_foreach(ip, ea_list_i, &ei);
++ if (!error)
++ error = ei.ei_size;
++ }
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return error;
++}
++
++/**
++ * ea_get_unstuffed - actually copies the unstuffed data into the
++ * request buffer
++ * @ip: The GFS2 inode
++ * @ea: The extended attribute header structure
++ * @data: The data to be copied
++ *
++ * Returns: errno
++ */
++
++static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
++ char *data)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head **bh;
++ unsigned int amount = GFS2_EA_DATA_LEN(ea);
++ unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
++ u64 *dataptrs = GFS2_EA2DATAPTRS(ea);
++ unsigned int x;
++ int error = 0;
++
++ bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL);
++ if (!bh)
++ return -ENOMEM;
++
++ for (x = 0; x < nptrs; x++) {
++ error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
++ bh + x);
++ if (error) {
++ while (x--)
++ brelse(bh[x]);
++ goto out;
++ }
++ dataptrs++;
++ }
++
++ for (x = 0; x < nptrs; x++) {
++ error = gfs2_meta_wait(sdp, bh[x]);
++ if (error) {
++ for (; x < nptrs; x++)
++ brelse(bh[x]);
++ goto out;
++ }
++ if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
++ for (; x < nptrs; x++)
++ brelse(bh[x]);
++ error = -EIO;
++ goto out;
++ }
++
++ memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header),
++ (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
++
++ amount -= sdp->sd_jbsize;
++ data += sdp->sd_jbsize;
++
++ brelse(bh[x]);
++ }
++
++out:
++ kfree(bh);
++ return error;
++}
++
++int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
++ char *data)
++{
++ if (GFS2_EA_IS_STUFFED(el->el_ea)) {
++ memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea));
++ return 0;
++ } else
++ return ea_get_unstuffed(ip, el->el_ea, data);
++}
++
++/**
++ * gfs2_ea_get_i -
++ * @ip: The GFS2 inode
++ * @er: The request structure
++ *
++ * Returns: actual size of data on success, -errno on error
++ */
++
++int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_ea_location el;
++ int error;
++
++ if (!ip->i_di.di_eattr)
++ return -ENODATA;
++
++ error = gfs2_ea_find(ip, er, &el);
++ if (error)
++ return error;
++ if (!el.el_ea)
++ return -ENODATA;
++
++ if (er->er_data_len) {
++ if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len)
++ error = -ERANGE;
++ else
++ error = gfs2_ea_get_copy(ip, &el, er->er_data);
++ }
++ if (!error)
++ error = GFS2_EA_DATA_LEN(el.el_ea);
++
++ brelse(el.el_bh);
++
++ return error;
++}
++
++/**
++ * gfs2_ea_get -
++ * @ip: The GFS2 inode
++ * @er: The request structure
++ *
++ * Returns: actual size of data on success, -errno on error
++ */
++
++int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_holder i_gh;
++ int error;
++
++ if (!er->er_name_len ||
++ er->er_name_len > GFS2_EA_MAX_NAME_LEN)
++ return -EINVAL;
++ if (!er->er_data || !er->er_data_len) {
++ er->er_data = NULL;
++ er->er_data_len = 0;
++ }
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
++ if (error)
++ return error;
++
++ error = gfs2_ea_ops[er->er_type]->eo_get(ip, er);
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return error;
++}
++
++/**
++ * ea_alloc_blk - allocates a new block for extended attributes.
++ * @ip: A pointer to the inode that's getting extended attributes
++ * @bhp: Pointer to pointer to a struct buffer_head
++ *
++ * Returns: errno
++ */
++
++static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_ea_header *ea;
++ u64 block;
++
++ block = gfs2_alloc_meta(ip);
++
++ *bhp = gfs2_meta_new(ip->i_gl, block);
++ gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
++ gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
++ gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header));
++
++ ea = GFS2_EA_BH2FIRST(*bhp);
++ ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize);
++ ea->ea_type = GFS2_EATYPE_UNUSED;
++ ea->ea_flags = GFS2_EAFLAG_LAST;
++ ea->ea_num_ptrs = 0;
++
++ ip->i_di.di_blocks++;
++
++ return 0;
++}
++
++/**
++ * ea_write - writes the request info to an ea, creating new blocks if
++ * necessary
++ * @ip: inode that is being modified
++ * @ea: the location of the new ea in a block
++ * @er: the write request
++ *
++ * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags
++ *
++ * returns : errno
++ */
++
++static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
++ struct gfs2_ea_request *er)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++
++ ea->ea_data_len = cpu_to_be32(er->er_data_len);
++ ea->ea_name_len = er->er_name_len;
++ ea->ea_type = er->er_type;
++ ea->__pad = 0;
++
++ memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len);
++
++ if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) {
++ ea->ea_num_ptrs = 0;
++ memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len);
++ } else {
++ u64 *dataptr = GFS2_EA2DATAPTRS(ea);
++ const char *data = er->er_data;
++ unsigned int data_len = er->er_data_len;
++ unsigned int copy;
++ unsigned int x;
++
++ ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize);
++ for (x = 0; x < ea->ea_num_ptrs; x++) {
++ struct buffer_head *bh;
++ u64 block;
++ int mh_size = sizeof(struct gfs2_meta_header);
++
++ block = gfs2_alloc_meta(ip);
++
++ bh = gfs2_meta_new(ip->i_gl, block);
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED);
++
++ ip->i_di.di_blocks++;
++
++ copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize :
++ data_len;
++ memcpy(bh->b_data + mh_size, data, copy);
++ if (copy < sdp->sd_jbsize)
++ memset(bh->b_data + mh_size + copy, 0,
++ sdp->sd_jbsize - copy);
++
++ *dataptr++ = cpu_to_be64(bh->b_blocknr);
++ data += copy;
++ data_len -= copy;
++
++ brelse(bh);
++ }
++
++ gfs2_assert_withdraw(sdp, !data_len);
++ }
++
++ return 0;
++}
++
++typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip,
++ struct gfs2_ea_request *er, void *private);
++
++static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
++ unsigned int blks,
++ ea_skeleton_call_t skeleton_call, void *private)
++{
++ struct gfs2_alloc *al;
++ struct buffer_head *dibh;
++ int error;
++
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out;
++
++ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
++ if (error)
++ goto out_gunlock_q;
++
++ al->al_requested = blks;
++
++ error = gfs2_inplace_reserve(ip);
++ if (error)
++ goto out_gunlock_q;
++
++ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
++ blks + al->al_rgd->rd_ri.ri_length +
++ RES_DINODE + RES_STATFS + RES_QUOTA, 0);
++ if (error)
++ goto out_ipres;
++
++ error = skeleton_call(ip, er, private);
++ if (error)
++ goto out_end_trans;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ if (er->er_flags & GFS2_ERF_MODE) {
++ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
++ (ip->i_di.di_mode & S_IFMT) ==
++ (er->er_mode & S_IFMT));
++ ip->i_di.di_mode = er->er_mode;
++ }
++ ip->i_di.di_ctime = get_seconds();
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++out_end_trans:
++ gfs2_trans_end(GFS2_SB(&ip->i_inode));
++out_ipres:
++ gfs2_inplace_release(ip);
++out_gunlock_q:
++ gfs2_quota_unlock(ip);
++out:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
++ void *private)
++{
++ struct buffer_head *bh;
++ int error;
++
++ error = ea_alloc_blk(ip, &bh);
++ if (error)
++ return error;
++
++ ip->i_di.di_eattr = bh->b_blocknr;
++ error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er);
++
++ brelse(bh);
++
++ return error;
++}
++
++/**
++ * ea_init - initializes a new eattr block
++ * @ip:
++ * @er:
++ *
++ * Returns: errno
++ */
++
++static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize;
++ unsigned int blks = 1;
++
++ if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize)
++ blks += DIV_ROUND_UP(er->er_data_len, jbsize);
++
++ return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL);
++}
++
++static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea)
++{
++ u32 ea_size = GFS2_EA_SIZE(ea);
++ struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea +
++ ea_size);
++ u32 new_size = GFS2_EA_REC_LEN(ea) - ea_size;
++ int last = ea->ea_flags & GFS2_EAFLAG_LAST;
++
++ ea->ea_rec_len = cpu_to_be32(ea_size);
++ ea->ea_flags ^= last;
++
++ new->ea_rec_len = cpu_to_be32(new_size);
++ new->ea_flags = last;
++
++ return new;
++}
++
++static void ea_set_remove_stuffed(struct gfs2_inode *ip,
++ struct gfs2_ea_location *el)
++{
++ struct gfs2_ea_header *ea = el->el_ea;
++ struct gfs2_ea_header *prev = el->el_prev;
++ u32 len;
++
++ gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
++
++ if (!prev || !GFS2_EA_IS_STUFFED(ea)) {
++ ea->ea_type = GFS2_EATYPE_UNUSED;
++ return;
++ } else if (GFS2_EA2NEXT(prev) != ea) {
++ prev = GFS2_EA2NEXT(prev);
++ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea);
++ }
++
++ len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
++ prev->ea_rec_len = cpu_to_be32(len);
++
++ if (GFS2_EA_IS_LAST(ea))
++ prev->ea_flags |= GFS2_EAFLAG_LAST;
++}
++
++struct ea_set {
++ int ea_split;
++
++ struct gfs2_ea_request *es_er;
++ struct gfs2_ea_location *es_el;
++
++ struct buffer_head *es_bh;
++ struct gfs2_ea_header *es_ea;
++};
++
++static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea, struct ea_set *es)
++{
++ struct gfs2_ea_request *er = es->es_er;
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0);
++ if (error)
++ return error;
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++
++ if (es->ea_split)
++ ea = ea_split_ea(ea);
++
++ ea_write(ip, ea, er);
++
++ if (es->es_el)
++ ea_set_remove_stuffed(ip, es->es_el);
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out;
++
++ if (er->er_flags & GFS2_ERF_MODE) {
++ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
++ (ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT));
++ ip->i_di.di_mode = er->er_mode;
++ }
++ ip->i_di.di_ctime = get_seconds();
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++out:
++ gfs2_trans_end(GFS2_SB(&ip->i_inode));
++ return error;
++}
++
++static int ea_set_simple_alloc(struct gfs2_inode *ip,
++ struct gfs2_ea_request *er, void *private)
++{
++ struct ea_set *es = private;
++ struct gfs2_ea_header *ea = es->es_ea;
++ int error;
++
++ gfs2_trans_add_bh(ip->i_gl, es->es_bh, 1);
++
++ if (es->ea_split)
++ ea = ea_split_ea(ea);
++
++ error = ea_write(ip, ea, er);
++ if (error)
++ return error;
++
++ if (es->es_el)
++ ea_set_remove_stuffed(ip, es->es_el);
++
++ return 0;
++}
++
++static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh,
++ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
++ void *private)
++{
++ struct ea_set *es = private;
++ unsigned int size;
++ int stuffed;
++ int error;
++
++ stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size);
++
++ if (ea->ea_type == GFS2_EATYPE_UNUSED) {
++ if (GFS2_EA_REC_LEN(ea) < size)
++ return 0;
++ if (!GFS2_EA_IS_STUFFED(ea)) {
++ error = ea_remove_unstuffed(ip, bh, ea, prev, 1);
++ if (error)
++ return error;
++ }
++ es->ea_split = 0;
++ } else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size)
++ es->ea_split = 1;
++ else
++ return 0;
++
++ if (stuffed) {
++ error = ea_set_simple_noalloc(ip, bh, ea, es);
++ if (error)
++ return error;
++ } else {
++ unsigned int blks;
++
++ es->es_bh = bh;
++ es->es_ea = ea;
++ blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len,
++ GFS2_SB(&ip->i_inode)->sd_jbsize);
++
++ error = ea_alloc_skeleton(ip, es->es_er, blks,
++ ea_set_simple_alloc, es);
++ if (error)
++ return error;
++ }
++
++ return 1;
++}
++
++static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
++ void *private)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head *indbh, *newbh;
++ u64 *eablk;
++ int error;
++ int mh_size = sizeof(struct gfs2_meta_header);
++
++ if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
++ u64 *end;
++
++ error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT,
++ &indbh);
++ if (error)
++ return error;
++
++ if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
++ error = -EIO;
++ goto out;
++ }
++
++ eablk = (u64 *)(indbh->b_data + mh_size);
++ end = eablk + sdp->sd_inptrs;
++
++ for (; eablk < end; eablk++)
++ if (!*eablk)
++ break;
++
++ if (eablk == end) {
++ error = -ENOSPC;
++ goto out;
++ }
++
++ gfs2_trans_add_bh(ip->i_gl, indbh, 1);
++ } else {
++ u64 blk;
++
++ blk = gfs2_alloc_meta(ip);
++
++ indbh = gfs2_meta_new(ip->i_gl, blk);
++ gfs2_trans_add_bh(ip->i_gl, indbh, 1);
++ gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
++ gfs2_buffer_clear_tail(indbh, mh_size);
++
++ eablk = (u64 *)(indbh->b_data + mh_size);
++ *eablk = cpu_to_be64(ip->i_di.di_eattr);
++ ip->i_di.di_eattr = blk;
++ ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT;
++ ip->i_di.di_blocks++;
++
++ eablk++;
++ }
++
++ error = ea_alloc_blk(ip, &newbh);
++ if (error)
++ goto out;
++
++ *eablk = cpu_to_be64((u64)newbh->b_blocknr);
++ error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er);
++ brelse(newbh);
++ if (error)
++ goto out;
++
++ if (private)
++ ea_set_remove_stuffed(ip, private);
++
++out:
++ brelse(indbh);
++ return error;
++}
++
++static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
++ struct gfs2_ea_location *el)
++{
++ struct ea_set es;
++ unsigned int blks = 2;
++ int error;
++
++ memset(&es, 0, sizeof(struct ea_set));
++ es.es_er = er;
++ es.es_el = el;
++
++ error = ea_foreach(ip, ea_set_simple, &es);
++ if (error > 0)
++ return 0;
++ if (error)
++ return error;
++
++ if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT))
++ blks++;
++ if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize)
++ blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize);
++
++ return ea_alloc_skeleton(ip, er, blks, ea_set_block, el);
++}
++
++static int ea_set_remove_unstuffed(struct gfs2_inode *ip,
++ struct gfs2_ea_location *el)
++{
++ if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) {
++ el->el_prev = GFS2_EA2NEXT(el->el_prev);
++ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
++ GFS2_EA2NEXT(el->el_prev) == el->el_ea);
++ }
++
++ return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0);
++}
++
++int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_ea_location el;
++ int error;
++
++ if (!ip->i_di.di_eattr) {
++ if (er->er_flags & XATTR_REPLACE)
++ return -ENODATA;
++ return ea_init(ip, er);
++ }
++
++ error = gfs2_ea_find(ip, er, &el);
++ if (error)
++ return error;
++
++ if (el.el_ea) {
++ if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) {
++ brelse(el.el_bh);
++ return -EPERM;
++ }
++
++ error = -EEXIST;
++ if (!(er->er_flags & XATTR_CREATE)) {
++ int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea);
++ error = ea_set_i(ip, er, &el);
++ if (!error && unstuffed)
++ ea_set_remove_unstuffed(ip, &el);
++ }
++
++ brelse(el.el_bh);
++ } else {
++ error = -ENODATA;
++ if (!(er->er_flags & XATTR_REPLACE))
++ error = ea_set_i(ip, er, NULL);
++ }
++
++ return error;
++}
++
++int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_holder i_gh;
++ int error;
++
++ if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
++ return -EINVAL;
++ if (!er->er_data || !er->er_data_len) {
++ er->er_data = NULL;
++ er->er_data_len = 0;
++ }
++ error = ea_check_size(GFS2_SB(&ip->i_inode), er);
++ if (error)
++ return error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
++ if (error)
++ return error;
++
++ if (IS_IMMUTABLE(&ip->i_inode))
++ error = -EPERM;
++ else
++ error = gfs2_ea_ops[er->er_type]->eo_set(ip, er);
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return error;
++}
++
++static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
++{
++ struct gfs2_ea_header *ea = el->el_ea;
++ struct gfs2_ea_header *prev = el->el_prev;
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
++ if (error)
++ return error;
++
++ gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
++
++ if (prev) {
++ u32 len;
++
++ len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
++ prev->ea_rec_len = cpu_to_be32(len);
++
++ if (GFS2_EA_IS_LAST(ea))
++ prev->ea_flags |= GFS2_EAFLAG_LAST;
++ } else
++ ea->ea_type = GFS2_EATYPE_UNUSED;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ ip->i_di.di_ctime = get_seconds();
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(GFS2_SB(&ip->i_inode));
++
++ return error;
++}
++
++int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_ea_location el;
++ int error;
++
++ if (!ip->i_di.di_eattr)
++ return -ENODATA;
++
++ error = gfs2_ea_find(ip, er, &el);
++ if (error)
++ return error;
++ if (!el.el_ea)
++ return -ENODATA;
++
++ if (GFS2_EA_IS_STUFFED(el.el_ea))
++ error = ea_remove_stuffed(ip, &el);
++ else
++ error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev,
++ 0);
++
++ brelse(el.el_bh);
++
++ return error;
++}
++
++/**
++ * gfs2_ea_remove - sets (or creates or replaces) an extended attribute
++ * @ip: pointer to the inode of the target file
++ * @er: request information
++ *
++ * Returns: errno
++ */
++
++int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
++{
++ struct gfs2_holder i_gh;
++ int error;
++
++ if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
++ return -EINVAL;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
++ if (error)
++ return error;
++
++ if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
++ error = -EPERM;
++ else
++ error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er);
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return error;
++}
++
++static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
++ struct gfs2_ea_header *ea, char *data)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct buffer_head **bh;
++ unsigned int amount = GFS2_EA_DATA_LEN(ea);
++ unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
++ u64 *dataptrs = GFS2_EA2DATAPTRS(ea);
++ unsigned int x;
++ int error;
++
++ bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL);
++ if (!bh)
++ return -ENOMEM;
++
++ error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
++ if (error)
++ goto out;
++
++ for (x = 0; x < nptrs; x++) {
++ error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
++ bh + x);
++ if (error) {
++ while (x--)
++ brelse(bh[x]);
++ goto fail;
++ }
++ dataptrs++;
++ }
++
++ for (x = 0; x < nptrs; x++) {
++ error = gfs2_meta_wait(sdp, bh[x]);
++ if (error) {
++ for (; x < nptrs; x++)
++ brelse(bh[x]);
++ goto fail;
++ }
++ if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
++ for (; x < nptrs; x++)
++ brelse(bh[x]);
++ error = -EIO;
++ goto fail;
++ }
++
++ gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
++
++ memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data,
++ (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
++
++ amount -= sdp->sd_jbsize;
++ data += sdp->sd_jbsize;
++
++ brelse(bh[x]);
++ }
++
++out:
++ kfree(bh);
++ return error;
++
++fail:
++ gfs2_trans_end(sdp);
++ kfree(bh);
++ return error;
++}
++
++int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
++ struct iattr *attr, char *data)
++{
++ struct buffer_head *dibh;
++ int error;
++
++ if (GFS2_EA_IS_STUFFED(el->el_ea)) {
++ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
++ if (error)
++ return error;
++
++ gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
++ memcpy(GFS2_EA2DATA(el->el_ea), data,
++ GFS2_EA_DATA_LEN(el->el_ea));
++ } else
++ error = ea_acl_chmod_unstuffed(ip, el->el_ea, data);
++
++ if (error)
++ return error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ error = inode_setattr(&ip->i_inode, attr);
++ gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
++ gfs2_inode_attr_out(ip);
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(GFS2_SB(&ip->i_inode));
++
++ return error;
++}
++
++static int ea_dealloc_indirect(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_rgrp_list rlist;
++ struct buffer_head *indbh, *dibh;
++ u64 *eablk, *end;
++ unsigned int rg_blocks = 0;
++ u64 bstart = 0;
++ unsigned int blen = 0;
++ unsigned int blks = 0;
++ unsigned int x;
++ int error;
++
++ memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
++
++ error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh);
++ if (error)
++ return error;
++
++ if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
++ error = -EIO;
++ goto out;
++ }
++
++ eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header));
++ end = eablk + sdp->sd_inptrs;
++
++ for (; eablk < end; eablk++) {
++ u64 bn;
++
++ if (!*eablk)
++ break;
++ bn = be64_to_cpu(*eablk);
++
++ if (bstart + blen == bn)
++ blen++;
++ else {
++ if (bstart)
++ gfs2_rlist_add(sdp, &rlist, bstart);
++ bstart = bn;
++ blen = 1;
++ }
++ blks++;
++ }
++ if (bstart)
++ gfs2_rlist_add(sdp, &rlist, bstart);
++ else
++ goto out;
++
++ gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
++
++ for (x = 0; x < rlist.rl_rgrps; x++) {
++ struct gfs2_rgrpd *rgd;
++ rgd = rlist.rl_ghs[x].gh_gl->gl_object;
++ rg_blocks += rgd->rd_ri.ri_length;
++ }
++
++ error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
++ if (error)
++ goto out_rlist_free;
++
++ error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + RES_INDIRECT +
++ RES_STATFS + RES_QUOTA, blks);
++ if (error)
++ goto out_gunlock;
++
++ gfs2_trans_add_bh(ip->i_gl, indbh, 1);
++
++ eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header));
++ bstart = 0;
++ blen = 0;
++
++ for (; eablk < end; eablk++) {
++ u64 bn;
++
++ if (!*eablk)
++ break;
++ bn = be64_to_cpu(*eablk);
++
++ if (bstart + blen == bn)
++ blen++;
++ else {
++ if (bstart)
++ gfs2_free_meta(ip, bstart, blen);
++ bstart = bn;
++ blen = 1;
++ }
++
++ *eablk = 0;
++ if (!ip->i_di.di_blocks)
++ gfs2_consist_inode(ip);
++ ip->i_di.di_blocks--;
++ }
++ if (bstart)
++ gfs2_free_meta(ip, bstart, blen);
++
++ ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(sdp);
++
++out_gunlock:
++ gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
++out_rlist_free:
++ gfs2_rlist_free(&rlist);
++out:
++ brelse(indbh);
++ return error;
++}
++
++static int ea_dealloc_block(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_rgrpd *rgd;
++ struct buffer_head *dibh;
++ int error;
++
++ rgd = gfs2_blk2rgrpd(sdp, ip->i_di.di_eattr);
++ if (!rgd) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
++ &al->al_rgd_gh);
++ if (error)
++ return error;
++
++ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + RES_STATFS +
++ RES_QUOTA, 1);
++ if (error)
++ goto out_gunlock;
++
++ gfs2_free_meta(ip, ip->i_di.di_eattr, 1);
++
++ ip->i_di.di_eattr = 0;
++ if (!ip->i_di.di_blocks)
++ gfs2_consist_inode(ip);
++ ip->i_di.di_blocks--;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(sdp);
++
++out_gunlock:
++ gfs2_glock_dq_uninit(&al->al_rgd_gh);
++ return error;
++}
++
++/**
++ * gfs2_ea_dealloc - deallocate the extended attribute fork
++ * @ip: the inode
++ *
++ * Returns: errno
++ */
++
++int gfs2_ea_dealloc(struct gfs2_inode *ip)
++{
++ struct gfs2_alloc *al;
++ int error;
++
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out_alloc;
++
++ error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
++ if (error)
++ goto out_quota;
++
++ error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
++ if (error)
++ goto out_rindex;
++
++ if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
++ error = ea_dealloc_indirect(ip);
++ if (error)
++ goto out_rindex;
++ }
++
++ error = ea_dealloc_block(ip);
++
++out_rindex:
++ gfs2_glock_dq_uninit(&al->al_ri_gh);
++out_quota:
++ gfs2_quota_unhold(ip);
++out_alloc:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
+diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h
+new file mode 100644
+index 0000000..ffa6594
+--- /dev/null
++++ b/fs/gfs2/eattr.h
+@@ -0,0 +1,100 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __EATTR_DOT_H__
++#define __EATTR_DOT_H__
++
++struct gfs2_inode;
++struct iattr;
++
++#define GFS2_EA_REC_LEN(ea) be32_to_cpu((ea)->ea_rec_len)
++#define GFS2_EA_DATA_LEN(ea) be32_to_cpu((ea)->ea_data_len)
++
++#define GFS2_EA_SIZE(ea) \
++ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \
++ ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \
++ (sizeof(u64) * (ea)->ea_num_ptrs)), 8)
++
++#define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs)
++#define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST)
++
++#define GFS2_EAREQ_SIZE_STUFFED(er) \
++ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8)
++
++#define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \
++ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \
++ sizeof(u64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8)
++
++#define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1))
++#define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len)
++
++#define GFS2_EA2DATAPTRS(ea) \
++((u64 *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8)))
++
++#define GFS2_EA2NEXT(ea) \
++((struct gfs2_ea_header *)((char *)(ea) + GFS2_EA_REC_LEN(ea)))
++
++#define GFS2_EA_BH2FIRST(bh) \
++((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header)))
++
++#define GFS2_ERF_MODE 0x80000000
++
++struct gfs2_ea_request {
++ const char *er_name;
++ char *er_data;
++ unsigned int er_name_len;
++ unsigned int er_data_len;
++ unsigned int er_type; /* GFS2_EATYPE_... */
++ int er_flags;
++ mode_t er_mode;
++};
++
++struct gfs2_ea_location {
++ struct buffer_head *el_bh;
++ struct gfs2_ea_header *el_ea;
++ struct gfs2_ea_header *el_prev;
++};
++
++int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++
++int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er);
++
++int gfs2_ea_dealloc(struct gfs2_inode *ip);
++
++/* Exported to acl.c */
++
++int gfs2_ea_find(struct gfs2_inode *ip,
++ struct gfs2_ea_request *er,
++ struct gfs2_ea_location *el);
++int gfs2_ea_get_copy(struct gfs2_inode *ip,
++ struct gfs2_ea_location *el,
++ char *data);
++int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
++ struct iattr *attr, char *data);
++
++static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea)
++{
++ switch (ea->ea_type) {
++ case GFS2_EATYPE_USR:
++ return 5 + ea->ea_name_len + 1;
++ case GFS2_EATYPE_SYS:
++ return 7 + ea->ea_name_len + 1;
++ case GFS2_EATYPE_SECURITY:
++ return 9 + ea->ea_name_len + 1;
++ default:
++ return 0;
++ }
++}
++
++#endif /* __EATTR_DOT_H__ */
+diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h
+new file mode 100644
+index 0000000..3bb11c0
+--- /dev/null
++++ b/fs/gfs2/gfs2.h
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __GFS2_DOT_H__
++#define __GFS2_DOT_H__
++
++enum {
++ NO_CREATE = 0,
++ CREATE = 1,
++};
++
++enum {
++ NO_WAIT = 0,
++ WAIT = 1,
++};
++
++enum {
++ NO_FORCE = 0,
++ FORCE = 1,
++};
++
++#define GFS2_FAST_NAME_SIZE 8
++
++#endif /* __GFS2_DOT_H__ */
++
+diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
+new file mode 100644
+index 0000000..78fe0fa
+--- /dev/null
++++ b/fs/gfs2/glock.c
+@@ -0,0 +1,2231 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/delay.h>
++#include <linux/sort.h>
++#include <linux/jhash.h>
++#include <linux/kallsyms.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/list.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "lm.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "super.h"
++#include "util.h"
++
++struct greedy {
++ struct gfs2_holder gr_gh;
++ struct work_struct gr_work;
++};
++
++struct gfs2_gl_hash_bucket {
++ struct hlist_head hb_list;
++};
++
++typedef void (*glock_examiner) (struct gfs2_glock * gl);
++
++static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
++static int dump_glock(struct gfs2_glock *gl);
++static int dump_inode(struct gfs2_inode *ip);
++
++#define GFS2_GL_HASH_SHIFT 15
++#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
++#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1)
++
++static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE];
++
++/*
++ * Despite what you might think, the numbers below are not arbitrary :-)
++ * They are taken from the ipv4 routing hash code, which is well tested
++ * and thus should be nearly optimal. Later on we might tweek the numbers
++ * but for now this should be fine.
++ *
++ * The reason for putting the locks in a separate array from the list heads
++ * is that we can have fewer locks than list heads and save memory. We use
++ * the same hash function for both, but with a different hash mask.
++ */
++#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
++ defined(CONFIG_PROVE_LOCKING)
++
++#ifdef CONFIG_LOCKDEP
++# define GL_HASH_LOCK_SZ 256
++#else
++# if NR_CPUS >= 32
++# define GL_HASH_LOCK_SZ 4096
++# elif NR_CPUS >= 16
++# define GL_HASH_LOCK_SZ 2048
++# elif NR_CPUS >= 8
++# define GL_HASH_LOCK_SZ 1024
++# elif NR_CPUS >= 4
++# define GL_HASH_LOCK_SZ 512
++# else
++# define GL_HASH_LOCK_SZ 256
++# endif
++#endif
++
++/* We never want more locks than chains */
++#if GFS2_GL_HASH_SIZE < GL_HASH_LOCK_SZ
++# undef GL_HASH_LOCK_SZ
++# define GL_HASH_LOCK_SZ GFS2_GL_HASH_SIZE
++#endif
++
++static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ];
++
++static inline rwlock_t *gl_lock_addr(unsigned int x)
++{
++ return &gl_hash_locks[x & (GL_HASH_LOCK_SZ-1)];
++}
++#else /* not SMP, so no spinlocks required */
++static inline rwlock_t *gl_lock_addr(x)
++{
++ return NULL;
++}
++#endif
++
++/**
++ * relaxed_state_ok - is a requested lock compatible with the current lock mode?
++ * @actual: the current state of the lock
++ * @requested: the lock state that was requested by the caller
++ * @flags: the modifier flags passed in by the caller
++ *
++ * Returns: 1 if the locks are compatible, 0 otherwise
++ */
++
++static inline int relaxed_state_ok(unsigned int actual, unsigned requested,
++ int flags)
++{
++ if (actual == requested)
++ return 1;
++
++ if (flags & GL_EXACT)
++ return 0;
++
++ if (actual == LM_ST_EXCLUSIVE && requested == LM_ST_SHARED)
++ return 1;
++
++ if (actual != LM_ST_UNLOCKED && (flags & LM_FLAG_ANY))
++ return 1;
++
++ return 0;
++}
++
++/**
++ * gl_hash() - Turn glock number into hash bucket number
++ * @lock: The glock number
++ *
++ * Returns: The number of the corresponding hash bucket
++ */
++
++static unsigned int gl_hash(const struct gfs2_sbd *sdp,
++ const struct lm_lockname *name)
++{
++ unsigned int h;
++
++ h = jhash(&name->ln_number, sizeof(u64), 0);
++ h = jhash(&name->ln_type, sizeof(unsigned int), h);
++ h = jhash(&sdp, sizeof(struct gfs2_sbd *), h);
++ h &= GFS2_GL_HASH_MASK;
++
++ return h;
++}
++
++/**
++ * glock_free() - Perform a few checks and then release struct gfs2_glock
++ * @gl: The glock to release
++ *
++ * Also calls lock module to release its internal structure for this glock.
++ *
++ */
++
++static void glock_free(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct inode *aspace = gl->gl_aspace;
++
++ gfs2_lm_put_lock(sdp, gl->gl_lock);
++
++ if (aspace)
++ gfs2_aspace_put(aspace);
++
++ kmem_cache_free(gfs2_glock_cachep, gl);
++}
++
++/**
++ * gfs2_glock_hold() - increment reference count on glock
++ * @gl: The glock to hold
++ *
++ */
++
++void gfs2_glock_hold(struct gfs2_glock *gl)
++{
++ atomic_inc(&gl->gl_ref);
++}
++
++/**
++ * gfs2_glock_put() - Decrement reference count on glock
++ * @gl: The glock to put
++ *
++ */
++
++int gfs2_glock_put(struct gfs2_glock *gl)
++{
++ int rv = 0;
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++
++ write_lock(gl_lock_addr(gl->gl_hash));
++ if (atomic_dec_and_test(&gl->gl_ref)) {
++ hlist_del(&gl->gl_list);
++ write_unlock(gl_lock_addr(gl->gl_hash));
++ BUG_ON(spin_is_locked(&gl->gl_spin));
++ gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
++ gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
++ gfs2_assert(sdp, list_empty(&gl->gl_holders));
++ gfs2_assert(sdp, list_empty(&gl->gl_waiters1));
++ gfs2_assert(sdp, list_empty(&gl->gl_waiters2));
++ gfs2_assert(sdp, list_empty(&gl->gl_waiters3));
++ glock_free(gl);
++ rv = 1;
++ goto out;
++ }
++ write_unlock(gl_lock_addr(gl->gl_hash));
++out:
++ return rv;
++}
++
++/**
++ * queue_empty - check to see if a glock's queue is empty
++ * @gl: the glock
++ * @head: the head of the queue to check
++ *
++ * This function protects the list in the event that a process already
++ * has a holder on the list and is adding a second holder for itself.
++ * The glmutex lock is what generally prevents processes from working
++ * on the same glock at once, but the special case of adding a second
++ * holder for yourself ("recursive" locking) doesn't involve locking
++ * glmutex, making the spin lock necessary.
++ *
++ * Returns: 1 if the queue is empty
++ */
++
++static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head)
++{
++ int empty;
++ spin_lock(&gl->gl_spin);
++ empty = list_empty(head);
++ spin_unlock(&gl->gl_spin);
++ return empty;
++}
++
++/**
++ * search_bucket() - Find struct gfs2_glock by lock number
++ * @bucket: the bucket to search
++ * @name: The lock name
++ *
++ * Returns: NULL, or the struct gfs2_glock with the requested number
++ */
++
++static struct gfs2_glock *search_bucket(unsigned int hash,
++ const struct gfs2_sbd *sdp,
++ const struct lm_lockname *name)
++{
++ struct gfs2_glock *gl;
++ struct hlist_node *h;
++
++ hlist_for_each_entry(gl, h, &gl_hash_table[hash].hb_list, gl_list) {
++ if (!lm_name_equal(&gl->gl_name, name))
++ continue;
++ if (gl->gl_sbd != sdp)
++ continue;
++
++ atomic_inc(&gl->gl_ref);
++
++ return gl;
++ }
++
++ return NULL;
++}
++
++/**
++ * gfs2_glock_find() - Find glock by lock number
++ * @sdp: The GFS2 superblock
++ * @name: The lock name
++ *
++ * Returns: NULL, or the struct gfs2_glock with the requested number
++ */
++
++static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
++ const struct lm_lockname *name)
++{
++ unsigned int hash = gl_hash(sdp, name);
++ struct gfs2_glock *gl;
++
++ read_lock(gl_lock_addr(hash));
++ gl = search_bucket(hash, sdp, name);
++ read_unlock(gl_lock_addr(hash));
++
++ return gl;
++}
++
++/**
++ * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
++ * @sdp: The GFS2 superblock
++ * @number: the lock number
++ * @glops: The glock_operations to use
++ * @create: If 0, don't create the glock if it doesn't exist
++ * @glp: the glock is returned here
++ *
++ * This does not lock a glock, just finds/creates structures for one.
++ *
++ * Returns: errno
++ */
++
++int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
++ const struct gfs2_glock_operations *glops, int create,
++ struct gfs2_glock **glp)
++{
++ struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type };
++ struct gfs2_glock *gl, *tmp;
++ unsigned int hash = gl_hash(sdp, &name);
++ int error;
++
++ read_lock(gl_lock_addr(hash));
++ gl = search_bucket(hash, sdp, &name);
++ read_unlock(gl_lock_addr(hash));
++
++ if (gl || !create) {
++ *glp = gl;
++ return 0;
++ }
++
++ gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
++ if (!gl)
++ return -ENOMEM;
++
++ gl->gl_flags = 0;
++ gl->gl_name = name;
++ atomic_set(&gl->gl_ref, 1);
++ gl->gl_state = LM_ST_UNLOCKED;
++ gl->gl_hash = hash;
++ gl->gl_owner = NULL;
++ gl->gl_ip = 0;
++ gl->gl_ops = glops;
++ gl->gl_req_gh = NULL;
++ gl->gl_req_bh = NULL;
++ gl->gl_vn = 0;
++ gl->gl_stamp = jiffies;
++ gl->gl_object = NULL;
++ gl->gl_sbd = sdp;
++ gl->gl_aspace = NULL;
++ lops_init_le(&gl->gl_le, &gfs2_glock_lops);
++
++ /* If this glock protects actual on-disk data or metadata blocks,
++ create a VFS inode to manage the pages/buffers holding them. */
++ if (glops == &gfs2_inode_glops || glops == &gfs2_rgrp_glops) {
++ gl->gl_aspace = gfs2_aspace_get(sdp);
++ if (!gl->gl_aspace) {
++ error = -ENOMEM;
++ goto fail;
++ }
++ }
++
++ error = gfs2_lm_get_lock(sdp, &name, &gl->gl_lock);
++ if (error)
++ goto fail_aspace;
++
++ write_lock(gl_lock_addr(hash));
++ tmp = search_bucket(hash, sdp, &name);
++ if (tmp) {
++ write_unlock(gl_lock_addr(hash));
++ glock_free(gl);
++ gl = tmp;
++ } else {
++ hlist_add_head(&gl->gl_list, &gl_hash_table[hash].hb_list);
++ write_unlock(gl_lock_addr(hash));
++ }
++
++ *glp = gl;
++
++ return 0;
++
++fail_aspace:
++ if (gl->gl_aspace)
++ gfs2_aspace_put(gl->gl_aspace);
++fail:
++ kmem_cache_free(gfs2_glock_cachep, gl);
++ return error;
++}
++
++/**
++ * gfs2_holder_init - initialize a struct gfs2_holder in the default way
++ * @gl: the glock
++ * @state: the state we're requesting
++ * @flags: the modifier flags
++ * @gh: the holder structure
++ *
++ */
++
++void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
++ struct gfs2_holder *gh)
++{
++ INIT_LIST_HEAD(&gh->gh_list);
++ gh->gh_gl = gl;
++ gh->gh_ip = (unsigned long)__builtin_return_address(0);
++ gh->gh_owner = current;
++ gh->gh_state = state;
++ gh->gh_flags = flags;
++ gh->gh_error = 0;
++ gh->gh_iflags = 0;
++ init_completion(&gh->gh_wait);
++
++ if (gh->gh_state == LM_ST_EXCLUSIVE)
++ gh->gh_flags |= GL_LOCAL_EXCL;
++
++ gfs2_glock_hold(gl);
++}
++
++/**
++ * gfs2_holder_reinit - reinitialize a struct gfs2_holder so we can requeue it
++ * @state: the state we're requesting
++ * @flags: the modifier flags
++ * @gh: the holder structure
++ *
++ * Don't mess with the glock.
++ *
++ */
++
++void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh)
++{
++ gh->gh_state = state;
++ gh->gh_flags = flags;
++ if (gh->gh_state == LM_ST_EXCLUSIVE)
++ gh->gh_flags |= GL_LOCAL_EXCL;
++
++ gh->gh_iflags &= 1 << HIF_ALLOCED;
++ gh->gh_ip = (unsigned long)__builtin_return_address(0);
++}
++
++/**
++ * gfs2_holder_uninit - uninitialize a holder structure (drop glock reference)
++ * @gh: the holder structure
++ *
++ */
++
++void gfs2_holder_uninit(struct gfs2_holder *gh)
++{
++ gfs2_glock_put(gh->gh_gl);
++ gh->gh_gl = NULL;
++ gh->gh_ip = 0;
++}
++
++/**
++ * gfs2_holder_get - get a struct gfs2_holder structure
++ * @gl: the glock
++ * @state: the state we're requesting
++ * @flags: the modifier flags
++ * @gfp_flags:
++ *
++ * Figure out how big an impact this function has. Either:
++ * 1) Replace it with a cache of structures hanging off the struct gfs2_sbd
++ * 2) Leave it like it is
++ *
++ * Returns: the holder structure, NULL on ENOMEM
++ */
++
++static struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl,
++ unsigned int state,
++ int flags, gfp_t gfp_flags)
++{
++ struct gfs2_holder *gh;
++
++ gh = kmalloc(sizeof(struct gfs2_holder), gfp_flags);
++ if (!gh)
++ return NULL;
++
++ gfs2_holder_init(gl, state, flags, gh);
++ set_bit(HIF_ALLOCED, &gh->gh_iflags);
++ gh->gh_ip = (unsigned long)__builtin_return_address(0);
++ return gh;
++}
++
++/**
++ * gfs2_holder_put - get rid of a struct gfs2_holder structure
++ * @gh: the holder structure
++ *
++ */
++
++static void gfs2_holder_put(struct gfs2_holder *gh)
++{
++ gfs2_holder_uninit(gh);
++ kfree(gh);
++}
++
++/**
++ * rq_mutex - process a mutex request in the queue
++ * @gh: the glock holder
++ *
++ * Returns: 1 if the queue is blocked
++ */
++
++static int rq_mutex(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++
++ list_del_init(&gh->gh_list);
++ /* gh->gh_error never examined. */
++ set_bit(GLF_LOCK, &gl->gl_flags);
++ complete(&gh->gh_wait);
++
++ return 1;
++}
++
++/**
++ * rq_promote - process a promote request in the queue
++ * @gh: the glock holder
++ *
++ * Acquire a new inter-node lock, or change a lock state to more restrictive.
++ *
++ * Returns: 1 if the queue is blocked
++ */
++
++static int rq_promote(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++
++ if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
++ if (list_empty(&gl->gl_holders)) {
++ gl->gl_req_gh = gh;
++ set_bit(GLF_LOCK, &gl->gl_flags);
++ spin_unlock(&gl->gl_spin);
++
++ if (atomic_read(&sdp->sd_reclaim_count) >
++ gfs2_tune_get(sdp, gt_reclaim_limit) &&
++ !(gh->gh_flags & LM_FLAG_PRIORITY)) {
++ gfs2_reclaim_glock(sdp);
++ gfs2_reclaim_glock(sdp);
++ }
++
++ glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
++ spin_lock(&gl->gl_spin);
++ }
++ return 1;
++ }
++
++ if (list_empty(&gl->gl_holders)) {
++ set_bit(HIF_FIRST, &gh->gh_iflags);
++ set_bit(GLF_LOCK, &gl->gl_flags);
++ } else {
++ struct gfs2_holder *next_gh;
++ if (gh->gh_flags & GL_LOCAL_EXCL)
++ return 1;
++ next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder,
++ gh_list);
++ if (next_gh->gh_flags & GL_LOCAL_EXCL)
++ return 1;
++ }
++
++ list_move_tail(&gh->gh_list, &gl->gl_holders);
++ gh->gh_error = 0;
++ set_bit(HIF_HOLDER, &gh->gh_iflags);
++
++ complete(&gh->gh_wait);
++
++ return 0;
++}
++
++/**
++ * rq_demote - process a demote request in the queue
++ * @gh: the glock holder
++ *
++ * Returns: 1 if the queue is blocked
++ */
++
++static int rq_demote(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++
++ if (!list_empty(&gl->gl_holders))
++ return 1;
++
++ if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) {
++ list_del_init(&gh->gh_list);
++ gh->gh_error = 0;
++ spin_unlock(&gl->gl_spin);
++ if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
++ gfs2_holder_put(gh);
++ else
++ complete(&gh->gh_wait);
++ spin_lock(&gl->gl_spin);
++ } else {
++ gl->gl_req_gh = gh;
++ set_bit(GLF_LOCK, &gl->gl_flags);
++ spin_unlock(&gl->gl_spin);
++
++ if (gh->gh_state == LM_ST_UNLOCKED ||
++ gl->gl_state != LM_ST_EXCLUSIVE)
++ glops->go_drop_th(gl);
++ else
++ glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
++
++ spin_lock(&gl->gl_spin);
++ }
++
++ return 0;
++}
++
++/**
++ * rq_greedy - process a queued request to drop greedy status
++ * @gh: the glock holder
++ *
++ * Returns: 1 if the queue is blocked
++ */
++
++static int rq_greedy(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++
++ list_del_init(&gh->gh_list);
++ /* gh->gh_error never examined. */
++ clear_bit(GLF_GREEDY, &gl->gl_flags);
++ spin_unlock(&gl->gl_spin);
++
++ gfs2_holder_uninit(gh);
++ kfree(container_of(gh, struct greedy, gr_gh));
++
++ spin_lock(&gl->gl_spin);
++
++ return 0;
++}
++
++/**
++ * run_queue - process holder structures on a glock
++ * @gl: the glock
++ *
++ */
++static void run_queue(struct gfs2_glock *gl)
++{
++ struct gfs2_holder *gh;
++ int blocked = 1;
++
++ for (;;) {
++ if (test_bit(GLF_LOCK, &gl->gl_flags))
++ break;
++
++ if (!list_empty(&gl->gl_waiters1)) {
++ gh = list_entry(gl->gl_waiters1.next,
++ struct gfs2_holder, gh_list);
++
++ if (test_bit(HIF_MUTEX, &gh->gh_iflags))
++ blocked = rq_mutex(gh);
++ else
++ gfs2_assert_warn(gl->gl_sbd, 0);
++
++ } else if (!list_empty(&gl->gl_waiters2) &&
++ !test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) {
++ gh = list_entry(gl->gl_waiters2.next,
++ struct gfs2_holder, gh_list);
++
++ if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
++ blocked = rq_demote(gh);
++ else if (test_bit(HIF_GREEDY, &gh->gh_iflags))
++ blocked = rq_greedy(gh);
++ else
++ gfs2_assert_warn(gl->gl_sbd, 0);
++
++ } else if (!list_empty(&gl->gl_waiters3)) {
++ gh = list_entry(gl->gl_waiters3.next,
++ struct gfs2_holder, gh_list);
++
++ if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
++ blocked = rq_promote(gh);
++ else
++ gfs2_assert_warn(gl->gl_sbd, 0);
++
++ } else
++ break;
++
++ if (blocked)
++ break;
++ }
++}
++
++/**
++ * gfs2_glmutex_lock - acquire a local lock on a glock
++ * @gl: the glock
++ *
++ * Gives caller exclusive access to manipulate a glock structure.
++ */
++
++static void gfs2_glmutex_lock(struct gfs2_glock *gl)
++{
++ struct gfs2_holder gh;
++
++ gfs2_holder_init(gl, 0, 0, &gh);
++ set_bit(HIF_MUTEX, &gh.gh_iflags);
++
++ spin_lock(&gl->gl_spin);
++ if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
++ list_add_tail(&gh.gh_list, &gl->gl_waiters1);
++ } else {
++ gl->gl_owner = current;
++ gl->gl_ip = (unsigned long)__builtin_return_address(0);
++ complete(&gh.gh_wait);
++ }
++ spin_unlock(&gl->gl_spin);
++
++ wait_for_completion(&gh.gh_wait);
++ gfs2_holder_uninit(&gh);
++}
++
++/**
++ * gfs2_glmutex_trylock - try to acquire a local lock on a glock
++ * @gl: the glock
++ *
++ * Returns: 1 if the glock is acquired
++ */
++
++static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
++{
++ int acquired = 1;
++
++ spin_lock(&gl->gl_spin);
++ if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
++ acquired = 0;
++ } else {
++ gl->gl_owner = current;
++ gl->gl_ip = (unsigned long)__builtin_return_address(0);
++ }
++ spin_unlock(&gl->gl_spin);
++
++ return acquired;
++}
++
++/**
++ * gfs2_glmutex_unlock - release a local lock on a glock
++ * @gl: the glock
++ *
++ */
++
++static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
++{
++ spin_lock(&gl->gl_spin);
++ clear_bit(GLF_LOCK, &gl->gl_flags);
++ gl->gl_owner = NULL;
++ gl->gl_ip = 0;
++ run_queue(gl);
++ BUG_ON(!spin_is_locked(&gl->gl_spin));
++ spin_unlock(&gl->gl_spin);
++}
++
++/**
++ * handle_callback - add a demote request to a lock's queue
++ * @gl: the glock
++ * @state: the state the caller wants us to change to
++ *
++ * Note: This may fail sliently if we are out of memory.
++ */
++
++static void handle_callback(struct gfs2_glock *gl, unsigned int state)
++{
++ struct gfs2_holder *gh, *new_gh = NULL;
++
++restart:
++ spin_lock(&gl->gl_spin);
++
++ list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
++ if (test_bit(HIF_DEMOTE, &gh->gh_iflags) &&
++ gl->gl_req_gh != gh) {
++ if (gh->gh_state != state)
++ gh->gh_state = LM_ST_UNLOCKED;
++ goto out;
++ }
++ }
++
++ if (new_gh) {
++ list_add_tail(&new_gh->gh_list, &gl->gl_waiters2);
++ new_gh = NULL;
++ } else {
++ spin_unlock(&gl->gl_spin);
++
++ new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_KERNEL);
++ if (!new_gh)
++ return;
++ set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
++ set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
++
++ goto restart;
++ }
++
++out:
++ spin_unlock(&gl->gl_spin);
++
++ if (new_gh)
++ gfs2_holder_put(new_gh);
++}
++
++void gfs2_glock_inode_squish(struct inode *inode)
++{
++ struct gfs2_holder gh;
++ struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
++ gfs2_holder_init(gl, LM_ST_UNLOCKED, 0, &gh);
++ set_bit(HIF_DEMOTE, &gh.gh_iflags);
++ spin_lock(&gl->gl_spin);
++ gfs2_assert(inode->i_sb->s_fs_info, list_empty(&gl->gl_holders));
++ list_add_tail(&gh.gh_list, &gl->gl_waiters2);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++ wait_for_completion(&gh.gh_wait);
++ gfs2_holder_uninit(&gh);
++}
++
++/**
++ * state_change - record that the glock is now in a different state
++ * @gl: the glock
++ * @new_state the new state
++ *
++ */
++
++static void state_change(struct gfs2_glock *gl, unsigned int new_state)
++{
++ int held1, held2;
++
++ held1 = (gl->gl_state != LM_ST_UNLOCKED);
++ held2 = (new_state != LM_ST_UNLOCKED);
++
++ if (held1 != held2) {
++ if (held2)
++ gfs2_glock_hold(gl);
++ else
++ gfs2_glock_put(gl);
++ }
++
++ gl->gl_state = new_state;
++}
++
++/**
++ * xmote_bh - Called after the lock module is done acquiring a lock
++ * @gl: The glock in question
++ * @ret: the int returned from the lock module
++ *
++ */
++
++static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++ struct gfs2_holder *gh = gl->gl_req_gh;
++ int prev_state = gl->gl_state;
++ int op_done = 1;
++
++ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
++ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
++ gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
++
++ state_change(gl, ret & LM_OUT_ST_MASK);
++
++ if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) {
++ if (glops->go_inval)
++ glops->go_inval(gl, DIO_METADATA | DIO_DATA);
++ } else if (gl->gl_state == LM_ST_DEFERRED) {
++ /* We might not want to do this here.
++ Look at moving to the inode glops. */
++ if (glops->go_inval)
++ glops->go_inval(gl, DIO_DATA);
++ }
++
++ /* Deal with each possible exit condition */
++
++ if (!gh)
++ gl->gl_stamp = jiffies;
++ else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++ gh->gh_error = -EIO;
++ spin_unlock(&gl->gl_spin);
++ } else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) {
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++ if (gl->gl_state == gh->gh_state ||
++ gl->gl_state == LM_ST_UNLOCKED) {
++ gh->gh_error = 0;
++ } else {
++ if (gfs2_assert_warn(sdp, gh->gh_flags &
++ (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1)
++ fs_warn(sdp, "ret = 0x%.8X\n", ret);
++ gh->gh_error = GLR_TRYFAILED;
++ }
++ spin_unlock(&gl->gl_spin);
++
++ if (ret & LM_OUT_CANCELED)
++ handle_callback(gl, LM_ST_UNLOCKED);
++
++ } else if (ret & LM_OUT_CANCELED) {
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++ gh->gh_error = GLR_CANCELED;
++ spin_unlock(&gl->gl_spin);
++
++ } else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
++ spin_lock(&gl->gl_spin);
++ list_move_tail(&gh->gh_list, &gl->gl_holders);
++ gh->gh_error = 0;
++ set_bit(HIF_HOLDER, &gh->gh_iflags);
++ spin_unlock(&gl->gl_spin);
++
++ set_bit(HIF_FIRST, &gh->gh_iflags);
++
++ op_done = 0;
++
++ } else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++ gh->gh_error = GLR_TRYFAILED;
++ spin_unlock(&gl->gl_spin);
++
++ } else {
++ if (gfs2_assert_withdraw(sdp, 0) == -1)
++ fs_err(sdp, "ret = 0x%.8X\n", ret);
++ }
++
++ if (glops->go_xmote_bh)
++ glops->go_xmote_bh(gl);
++
++ if (op_done) {
++ spin_lock(&gl->gl_spin);
++ gl->gl_req_gh = NULL;
++ gl->gl_req_bh = NULL;
++ clear_bit(GLF_LOCK, &gl->gl_flags);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++ }
++
++ gfs2_glock_put(gl);
++
++ if (gh) {
++ if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
++ gfs2_holder_put(gh);
++ else
++ complete(&gh->gh_wait);
++ }
++}
++
++/**
++ * gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock
++ * @gl: The glock in question
++ * @state: the requested state
++ * @flags: modifier flags to the lock call
++ *
++ */
++
++void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++ int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
++ LM_FLAG_NOEXP | LM_FLAG_ANY |
++ LM_FLAG_PRIORITY);
++ unsigned int lck_ret;
++
++ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
++ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
++ gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED);
++ gfs2_assert_warn(sdp, state != gl->gl_state);
++
++ if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
++ glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE);
++
++ gfs2_glock_hold(gl);
++ gl->gl_req_bh = xmote_bh;
++
++ lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, lck_flags);
++
++ if (gfs2_assert_withdraw(sdp, !(lck_ret & LM_OUT_ERROR)))
++ return;
++
++ if (lck_ret & LM_OUT_ASYNC)
++ gfs2_assert_warn(sdp, lck_ret == LM_OUT_ASYNC);
++ else
++ xmote_bh(gl, lck_ret);
++}
++
++/**
++ * drop_bh - Called after a lock module unlock completes
++ * @gl: the glock
++ * @ret: the return status
++ *
++ * Doesn't wake up the process waiting on the struct gfs2_holder (if any)
++ * Doesn't drop the reference on the glock the top half took out
++ *
++ */
++
++static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++ struct gfs2_holder *gh = gl->gl_req_gh;
++
++ clear_bit(GLF_PREFETCH, &gl->gl_flags);
++
++ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
++ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
++ gfs2_assert_warn(sdp, !ret);
++
++ state_change(gl, LM_ST_UNLOCKED);
++
++ if (glops->go_inval)
++ glops->go_inval(gl, DIO_METADATA | DIO_DATA);
++
++ if (gh) {
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++ gh->gh_error = 0;
++ spin_unlock(&gl->gl_spin);
++ }
++
++ if (glops->go_drop_bh)
++ glops->go_drop_bh(gl);
++
++ spin_lock(&gl->gl_spin);
++ gl->gl_req_gh = NULL;
++ gl->gl_req_bh = NULL;
++ clear_bit(GLF_LOCK, &gl->gl_flags);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++
++ gfs2_glock_put(gl);
++
++ if (gh) {
++ if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
++ gfs2_holder_put(gh);
++ else
++ complete(&gh->gh_wait);
++ }
++}
++
++/**
++ * gfs2_glock_drop_th - call into the lock module to unlock a lock
++ * @gl: the glock
++ *
++ */
++
++void gfs2_glock_drop_th(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++ unsigned int ret;
++
++ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
++ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
++ gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
++
++ if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
++ glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE);
++
++ gfs2_glock_hold(gl);
++ gl->gl_req_bh = drop_bh;
++
++ ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state);
++
++ if (gfs2_assert_withdraw(sdp, !(ret & LM_OUT_ERROR)))
++ return;
++
++ if (!ret)
++ drop_bh(gl, ret);
++ else
++ gfs2_assert_warn(sdp, ret == LM_OUT_ASYNC);
++}
++
++/**
++ * do_cancels - cancel requests for locks stuck waiting on an expire flag
++ * @gh: the LM_FLAG_PRIORITY holder waiting to acquire the lock
++ *
++ * Don't cancel GL_NOCANCEL requests.
++ */
++
++static void do_cancels(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++
++ spin_lock(&gl->gl_spin);
++
++ while (gl->gl_req_gh != gh &&
++ !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
++ !list_empty(&gh->gh_list)) {
++ if (gl->gl_req_bh && !(gl->gl_req_gh &&
++ (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) {
++ spin_unlock(&gl->gl_spin);
++ gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock);
++ msleep(100);
++ spin_lock(&gl->gl_spin);
++ } else {
++ spin_unlock(&gl->gl_spin);
++ msleep(100);
++ spin_lock(&gl->gl_spin);
++ }
++ }
++
++ spin_unlock(&gl->gl_spin);
++}
++
++/**
++ * glock_wait_internal - wait on a glock acquisition
++ * @gh: the glock holder
++ *
++ * Returns: 0 on success
++ */
++
++static int glock_wait_internal(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++
++ if (test_bit(HIF_ABORTED, &gh->gh_iflags))
++ return -EIO;
++
++ if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
++ spin_lock(&gl->gl_spin);
++ if (gl->gl_req_gh != gh &&
++ !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
++ !list_empty(&gh->gh_list)) {
++ list_del_init(&gh->gh_list);
++ gh->gh_error = GLR_TRYFAILED;
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++ return gh->gh_error;
++ }
++ spin_unlock(&gl->gl_spin);
++ }
++
++ if (gh->gh_flags & LM_FLAG_PRIORITY)
++ do_cancels(gh);
++
++ wait_for_completion(&gh->gh_wait);
++
++ if (gh->gh_error)
++ return gh->gh_error;
++
++ gfs2_assert_withdraw(sdp, test_bit(HIF_HOLDER, &gh->gh_iflags));
++ gfs2_assert_withdraw(sdp, relaxed_state_ok(gl->gl_state, gh->gh_state,
++ gh->gh_flags));
++
++ if (test_bit(HIF_FIRST, &gh->gh_iflags)) {
++ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
++
++ if (glops->go_lock) {
++ gh->gh_error = glops->go_lock(gh);
++ if (gh->gh_error) {
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++ spin_unlock(&gl->gl_spin);
++ }
++ }
++
++ spin_lock(&gl->gl_spin);
++ gl->gl_req_gh = NULL;
++ gl->gl_req_bh = NULL;
++ clear_bit(GLF_LOCK, &gl->gl_flags);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++ }
++
++ return gh->gh_error;
++}
++
++static inline struct gfs2_holder *
++find_holder_by_owner(struct list_head *head, struct task_struct *owner)
++{
++ struct gfs2_holder *gh;
++
++ list_for_each_entry(gh, head, gh_list) {
++ if (gh->gh_owner == owner)
++ return gh;
++ }
++
++ return NULL;
++}
++
++/**
++ * add_to_queue - Add a holder to the wait queue (but look for recursion)
++ * @gh: the holder structure to add
++ *
++ */
++
++static void add_to_queue(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_holder *existing;
++
++ BUG_ON(!gh->gh_owner);
++
++ existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
++ if (existing) {
++ print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
++ printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid);
++ printk(KERN_INFO "lock type : %d lock state : %d\n",
++ existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
++ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
++ printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid);
++ printk(KERN_INFO "lock type : %d lock state : %d\n",
++ gl->gl_name.ln_type, gl->gl_state);
++ BUG();
++ }
++
++ existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner);
++ if (existing) {
++ print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
++ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
++ BUG();
++ }
++
++ if (gh->gh_flags & LM_FLAG_PRIORITY)
++ list_add(&gh->gh_list, &gl->gl_waiters3);
++ else
++ list_add_tail(&gh->gh_list, &gl->gl_waiters3);
++}
++
++/**
++ * gfs2_glock_nq - enqueue a struct gfs2_holder onto a glock (acquire a glock)
++ * @gh: the holder structure
++ *
++ * if (gh->gh_flags & GL_ASYNC), this never returns an error
++ *
++ * Returns: 0, GLR_TRYFAILED, or errno on failure
++ */
++
++int gfs2_glock_nq(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ int error = 0;
++
++restart:
++ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
++ set_bit(HIF_ABORTED, &gh->gh_iflags);
++ return -EIO;
++ }
++
++ set_bit(HIF_PROMOTE, &gh->gh_iflags);
++
++ spin_lock(&gl->gl_spin);
++ add_to_queue(gh);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++
++ if (!(gh->gh_flags & GL_ASYNC)) {
++ error = glock_wait_internal(gh);
++ if (error == GLR_CANCELED) {
++ msleep(100);
++ goto restart;
++ }
++ }
++
++ clear_bit(GLF_PREFETCH, &gl->gl_flags);
++
++ if (error == GLR_TRYFAILED && (gh->gh_flags & GL_DUMP))
++ dump_glock(gl);
++
++ return error;
++}
++
++/**
++ * gfs2_glock_poll - poll to see if an async request has been completed
++ * @gh: the holder
++ *
++ * Returns: 1 if the request is ready to be gfs2_glock_wait()ed on
++ */
++
++int gfs2_glock_poll(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ int ready = 0;
++
++ spin_lock(&gl->gl_spin);
++
++ if (test_bit(HIF_HOLDER, &gh->gh_iflags))
++ ready = 1;
++ else if (list_empty(&gh->gh_list)) {
++ if (gh->gh_error == GLR_CANCELED) {
++ spin_unlock(&gl->gl_spin);
++ msleep(100);
++ if (gfs2_glock_nq(gh))
++ return 1;
++ return 0;
++ } else
++ ready = 1;
++ }
++
++ spin_unlock(&gl->gl_spin);
++
++ return ready;
++}
++
++/**
++ * gfs2_glock_wait - wait for a lock acquisition that ended in a GLR_ASYNC
++ * @gh: the holder structure
++ *
++ * Returns: 0, GLR_TRYFAILED, or errno on failure
++ */
++
++int gfs2_glock_wait(struct gfs2_holder *gh)
++{
++ int error;
++
++ error = glock_wait_internal(gh);
++ if (error == GLR_CANCELED) {
++ msleep(100);
++ gh->gh_flags &= ~GL_ASYNC;
++ error = gfs2_glock_nq(gh);
++ }
++
++ return error;
++}
++
++/**
++ * gfs2_glock_dq - dequeue a struct gfs2_holder from a glock (release a glock)
++ * @gh: the glock holder
++ *
++ */
++
++void gfs2_glock_dq(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++
++ if (gh->gh_flags & GL_NOCACHE)
++ handle_callback(gl, LM_ST_UNLOCKED);
++
++ gfs2_glmutex_lock(gl);
++
++ spin_lock(&gl->gl_spin);
++ list_del_init(&gh->gh_list);
++
++ if (list_empty(&gl->gl_holders)) {
++ spin_unlock(&gl->gl_spin);
++
++ if (glops->go_unlock)
++ glops->go_unlock(gh);
++
++ gl->gl_stamp = jiffies;
++
++ spin_lock(&gl->gl_spin);
++ }
++
++ clear_bit(GLF_LOCK, &gl->gl_flags);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++}
++
++/**
++ * gfs2_glock_prefetch - Try to prefetch a glock
++ * @gl: the glock
++ * @state: the state to prefetch in
++ * @flags: flags passed to go_xmote_th()
++ *
++ */
++
++static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state,
++ int flags)
++{
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++
++ spin_lock(&gl->gl_spin);
++
++ if (test_bit(GLF_LOCK, &gl->gl_flags) || !list_empty(&gl->gl_holders) ||
++ !list_empty(&gl->gl_waiters1) || !list_empty(&gl->gl_waiters2) ||
++ !list_empty(&gl->gl_waiters3) ||
++ relaxed_state_ok(gl->gl_state, state, flags)) {
++ spin_unlock(&gl->gl_spin);
++ return;
++ }
++
++ set_bit(GLF_PREFETCH, &gl->gl_flags);
++ set_bit(GLF_LOCK, &gl->gl_flags);
++ spin_unlock(&gl->gl_spin);
++
++ glops->go_xmote_th(gl, state, flags);
++}
++
++static void greedy_work(void *data)
++{
++ struct greedy *gr = data;
++ struct gfs2_holder *gh = &gr->gr_gh;
++ struct gfs2_glock *gl = gh->gh_gl;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++
++ clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
++
++ if (glops->go_greedy)
++ glops->go_greedy(gl);
++
++ spin_lock(&gl->gl_spin);
++
++ if (list_empty(&gl->gl_waiters2)) {
++ clear_bit(GLF_GREEDY, &gl->gl_flags);
++ spin_unlock(&gl->gl_spin);
++ gfs2_holder_uninit(gh);
++ kfree(gr);
++ } else {
++ gfs2_glock_hold(gl);
++ list_add_tail(&gh->gh_list, &gl->gl_waiters2);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++ gfs2_glock_put(gl);
++ }
++}
++
++/**
++ * gfs2_glock_be_greedy -
++ * @gl:
++ * @time:
++ *
++ * Returns: 0 if go_greedy will be called, 1 otherwise
++ */
++
++int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time)
++{
++ struct greedy *gr;
++ struct gfs2_holder *gh;
++
++ if (!time || gl->gl_sbd->sd_args.ar_localcaching ||
++ test_and_set_bit(GLF_GREEDY, &gl->gl_flags))
++ return 1;
++
++ gr = kmalloc(sizeof(struct greedy), GFP_KERNEL);
++ if (!gr) {
++ clear_bit(GLF_GREEDY, &gl->gl_flags);
++ return 1;
++ }
++ gh = &gr->gr_gh;
++
++ gfs2_holder_init(gl, 0, 0, gh);
++ set_bit(HIF_GREEDY, &gh->gh_iflags);
++ INIT_WORK(&gr->gr_work, greedy_work, gr);
++
++ set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
++ schedule_delayed_work(&gr->gr_work, time);
++
++ return 0;
++}
++
++/**
++ * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it
++ * @gh: the holder structure
++ *
++ */
++
++void gfs2_glock_dq_uninit(struct gfs2_holder *gh)
++{
++ gfs2_glock_dq(gh);
++ gfs2_holder_uninit(gh);
++}
++
++/**
++ * gfs2_glock_nq_num - acquire a glock based on lock number
++ * @sdp: the filesystem
++ * @number: the lock number
++ * @glops: the glock operations for the type of glock
++ * @state: the state to acquire the glock in
++ * @flags: modifier flags for the aquisition
++ * @gh: the struct gfs2_holder
++ *
++ * Returns: errno
++ */
++
++int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
++ const struct gfs2_glock_operations *glops,
++ unsigned int state, int flags, struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl;
++ int error;
++
++ error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
++ if (!error) {
++ error = gfs2_glock_nq_init(gl, state, flags, gh);
++ gfs2_glock_put(gl);
++ }
++
++ return error;
++}
++
++/**
++ * glock_compare - Compare two struct gfs2_glock structures for sorting
++ * @arg_a: the first structure
++ * @arg_b: the second structure
++ *
++ */
++
++static int glock_compare(const void *arg_a, const void *arg_b)
++{
++ const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
++ const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
++ const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
++ const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
++
++ if (a->ln_number > b->ln_number)
++ return 1;
++ if (a->ln_number < b->ln_number)
++ return -1;
++ if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
++ return 1;
++ if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL))
++ return 1;
++ return 0;
++}
++
++/**
++ * nq_m_sync - synchonously acquire more than one glock in deadlock free order
++ * @num_gh: the number of structures
++ * @ghs: an array of struct gfs2_holder structures
++ *
++ * Returns: 0 on success (all glocks acquired),
++ * errno on failure (no glocks acquired)
++ */
++
++static int nq_m_sync(unsigned int num_gh, struct gfs2_holder *ghs,
++ struct gfs2_holder **p)
++{
++ unsigned int x;
++ int error = 0;
++
++ for (x = 0; x < num_gh; x++)
++ p[x] = &ghs[x];
++
++ sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare, NULL);
++
++ for (x = 0; x < num_gh; x++) {
++ p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
++
++ error = gfs2_glock_nq(p[x]);
++ if (error) {
++ while (x--)
++ gfs2_glock_dq(p[x]);
++ break;
++ }
++ }
++
++ return error;
++}
++
++/**
++ * gfs2_glock_nq_m - acquire multiple glocks
++ * @num_gh: the number of structures
++ * @ghs: an array of struct gfs2_holder structures
++ *
++ * Figure out how big an impact this function has. Either:
++ * 1) Replace this code with code that calls gfs2_glock_prefetch()
++ * 2) Forget async stuff and just call nq_m_sync()
++ * 3) Leave it like it is
++ *
++ * Returns: 0 on success (all glocks acquired),
++ * errno on failure (no glocks acquired)
++ */
++
++int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs)
++{
++ int *e;
++ unsigned int x;
++ int borked = 0, serious = 0;
++ int error = 0;
++
++ if (!num_gh)
++ return 0;
++
++ if (num_gh == 1) {
++ ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
++ return gfs2_glock_nq(ghs);
++ }
++
++ e = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
++ if (!e)
++ return -ENOMEM;
++
++ for (x = 0; x < num_gh; x++) {
++ ghs[x].gh_flags |= LM_FLAG_TRY | GL_ASYNC;
++ error = gfs2_glock_nq(&ghs[x]);
++ if (error) {
++ borked = 1;
++ serious = error;
++ num_gh = x;
++ break;
++ }
++ }
++
++ for (x = 0; x < num_gh; x++) {
++ error = e[x] = glock_wait_internal(&ghs[x]);
++ if (error) {
++ borked = 1;
++ if (error != GLR_TRYFAILED && error != GLR_CANCELED)
++ serious = error;
++ }
++ }
++
++ if (!borked) {
++ kfree(e);
++ return 0;
++ }
++
++ for (x = 0; x < num_gh; x++)
++ if (!e[x])
++ gfs2_glock_dq(&ghs[x]);
++
++ if (serious)
++ error = serious;
++ else {
++ for (x = 0; x < num_gh; x++)
++ gfs2_holder_reinit(ghs[x].gh_state, ghs[x].gh_flags,
++ &ghs[x]);
++ error = nq_m_sync(num_gh, ghs, (struct gfs2_holder **)e);
++ }
++
++ kfree(e);
++
++ return error;
++}
++
++/**
++ * gfs2_glock_dq_m - release multiple glocks
++ * @num_gh: the number of structures
++ * @ghs: an array of struct gfs2_holder structures
++ *
++ */
++
++void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs)
++{
++ unsigned int x;
++
++ for (x = 0; x < num_gh; x++)
++ gfs2_glock_dq(&ghs[x]);
++}
++
++/**
++ * gfs2_glock_dq_uninit_m - release multiple glocks
++ * @num_gh: the number of structures
++ * @ghs: an array of struct gfs2_holder structures
++ *
++ */
++
++void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
++{
++ unsigned int x;
++
++ for (x = 0; x < num_gh; x++)
++ gfs2_glock_dq_uninit(&ghs[x]);
++}
++
++/**
++ * gfs2_glock_prefetch_num - prefetch a glock based on lock number
++ * @sdp: the filesystem
++ * @number: the lock number
++ * @glops: the glock operations for the type of glock
++ * @state: the state to acquire the glock in
++ * @flags: modifier flags for the aquisition
++ *
++ * Returns: errno
++ */
++
++void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
++ const struct gfs2_glock_operations *glops,
++ unsigned int state, int flags)
++{
++ struct gfs2_glock *gl;
++ int error;
++
++ if (atomic_read(&sdp->sd_reclaim_count) <
++ gfs2_tune_get(sdp, gt_reclaim_limit)) {
++ error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
++ if (!error) {
++ gfs2_glock_prefetch(gl, state, flags);
++ gfs2_glock_put(gl);
++ }
++ }
++}
++
++/**
++ * gfs2_lvb_hold - attach a LVB from a glock
++ * @gl: The glock in question
++ *
++ */
++
++int gfs2_lvb_hold(struct gfs2_glock *gl)
++{
++ int error;
++
++ gfs2_glmutex_lock(gl);
++
++ if (!atomic_read(&gl->gl_lvb_count)) {
++ error = gfs2_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb);
++ if (error) {
++ gfs2_glmutex_unlock(gl);
++ return error;
++ }
++ gfs2_glock_hold(gl);
++ }
++ atomic_inc(&gl->gl_lvb_count);
++
++ gfs2_glmutex_unlock(gl);
++
++ return 0;
++}
++
++/**
++ * gfs2_lvb_unhold - detach a LVB from a glock
++ * @gl: The glock in question
++ *
++ */
++
++void gfs2_lvb_unhold(struct gfs2_glock *gl)
++{
++ gfs2_glock_hold(gl);
++ gfs2_glmutex_lock(gl);
++
++ gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0);
++ if (atomic_dec_and_test(&gl->gl_lvb_count)) {
++ gfs2_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb);
++ gl->gl_lvb = NULL;
++ gfs2_glock_put(gl);
++ }
++
++ gfs2_glmutex_unlock(gl);
++ gfs2_glock_put(gl);
++}
++
++static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ unsigned int state)
++{
++ struct gfs2_glock *gl;
++
++ gl = gfs2_glock_find(sdp, name);
++ if (!gl)
++ return;
++
++ if (gl->gl_ops->go_callback)
++ gl->gl_ops->go_callback(gl, state);
++ handle_callback(gl, state);
++
++ spin_lock(&gl->gl_spin);
++ run_queue(gl);
++ spin_unlock(&gl->gl_spin);
++
++ gfs2_glock_put(gl);
++}
++
++/**
++ * gfs2_glock_cb - Callback used by locking module
++ * @sdp: Pointer to the superblock
++ * @type: Type of callback
++ * @data: Type dependent data pointer
++ *
++ * Called by the locking module when it wants to tell us something.
++ * Either we need to drop a lock, one of our ASYNC requests completed, or
++ * a journal from another client needs to be recovered.
++ */
++
++void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
++{
++ struct gfs2_sbd *sdp = cb_data;
++
++ switch (type) {
++ case LM_CB_NEED_E:
++ blocking_cb(sdp, data, LM_ST_UNLOCKED);
++ return;
++
++ case LM_CB_NEED_D:
++ blocking_cb(sdp, data, LM_ST_DEFERRED);
++ return;
++
++ case LM_CB_NEED_S:
++ blocking_cb(sdp, data, LM_ST_SHARED);
++ return;
++
++ case LM_CB_ASYNC: {
++ struct lm_async_cb *async = data;
++ struct gfs2_glock *gl;
++
++ gl = gfs2_glock_find(sdp, &async->lc_name);
++ if (gfs2_assert_warn(sdp, gl))
++ return;
++ if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
++ gl->gl_req_bh(gl, async->lc_ret);
++ gfs2_glock_put(gl);
++ return;
++ }
++
++ case LM_CB_NEED_RECOVERY:
++ gfs2_jdesc_make_dirty(sdp, *(unsigned int *)data);
++ if (sdp->sd_recoverd_process)
++ wake_up_process(sdp->sd_recoverd_process);
++ return;
++
++ case LM_CB_DROPLOCKS:
++ gfs2_gl_hash_clear(sdp, NO_WAIT);
++ gfs2_quota_scan(sdp);
++ return;
++
++ default:
++ gfs2_assert_warn(sdp, 0);
++ return;
++ }
++}
++
++/**
++ * demote_ok - Check to see if it's ok to unlock a glock
++ * @gl: the glock
++ *
++ * Returns: 1 if it's ok
++ */
++
++static int demote_ok(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ const struct gfs2_glock_operations *glops = gl->gl_ops;
++ int demote = 1;
++
++ if (test_bit(GLF_STICKY, &gl->gl_flags))
++ demote = 0;
++ else if (test_bit(GLF_PREFETCH, &gl->gl_flags))
++ demote = time_after_eq(jiffies, gl->gl_stamp +
++ gfs2_tune_get(sdp, gt_prefetch_secs) * HZ);
++ else if (glops->go_demote_ok)
++ demote = glops->go_demote_ok(gl);
++
++ return demote;
++}
++
++/**
++ * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list
++ * @gl: the glock
++ *
++ */
++
++void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++
++ spin_lock(&sdp->sd_reclaim_lock);
++ if (list_empty(&gl->gl_reclaim)) {
++ gfs2_glock_hold(gl);
++ list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list);
++ atomic_inc(&sdp->sd_reclaim_count);
++ }
++ spin_unlock(&sdp->sd_reclaim_lock);
++
++ wake_up(&sdp->sd_reclaim_wq);
++}
++
++/**
++ * gfs2_reclaim_glock - process the next glock on the filesystem's reclaim list
++ * @sdp: the filesystem
++ *
++ * Called from gfs2_glockd() glock reclaim daemon, or when promoting a
++ * different glock and we notice that there are a lot of glocks in the
++ * reclaim list.
++ *
++ */
++
++void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
++{
++ struct gfs2_glock *gl;
++
++ spin_lock(&sdp->sd_reclaim_lock);
++ if (list_empty(&sdp->sd_reclaim_list)) {
++ spin_unlock(&sdp->sd_reclaim_lock);
++ return;
++ }
++ gl = list_entry(sdp->sd_reclaim_list.next,
++ struct gfs2_glock, gl_reclaim);
++ list_del_init(&gl->gl_reclaim);
++ spin_unlock(&sdp->sd_reclaim_lock);
++
++ atomic_dec(&sdp->sd_reclaim_count);
++ atomic_inc(&sdp->sd_reclaimed);
++
++ if (gfs2_glmutex_trylock(gl)) {
++ if (queue_empty(gl, &gl->gl_holders) &&
++ gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
++ handle_callback(gl, LM_ST_UNLOCKED);
++ gfs2_glmutex_unlock(gl);
++ }
++
++ gfs2_glock_put(gl);
++}
++
++/**
++ * examine_bucket - Call a function for glock in a hash bucket
++ * @examiner: the function
++ * @sdp: the filesystem
++ * @bucket: the bucket
++ *
++ * Returns: 1 if the bucket has entries
++ */
++
++static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
++ unsigned int hash)
++{
++ struct gfs2_glock *gl, *prev = NULL;
++ int has_entries = 0;
++ struct hlist_head *head = &gl_hash_table[hash].hb_list;
++
++ read_lock(gl_lock_addr(hash));
++ /* Can't use hlist_for_each_entry - don't want prefetch here */
++ if (hlist_empty(head))
++ goto out;
++ gl = list_entry(head->first, struct gfs2_glock, gl_list);
++ while(1) {
++ if (gl->gl_sbd == sdp) {
++ gfs2_glock_hold(gl);
++ read_unlock(gl_lock_addr(hash));
++ if (prev)
++ gfs2_glock_put(prev);
++ prev = gl;
++ examiner(gl);
++ has_entries = 1;
++ read_lock(gl_lock_addr(hash));
++ }
++ if (gl->gl_list.next == NULL)
++ break;
++ gl = list_entry(gl->gl_list.next, struct gfs2_glock, gl_list);
++ }
++out:
++ read_unlock(gl_lock_addr(hash));
++ if (prev)
++ gfs2_glock_put(prev);
++ return has_entries;
++}
++
++/**
++ * scan_glock - look at a glock and see if we can reclaim it
++ * @gl: the glock to look at
++ *
++ */
++
++static void scan_glock(struct gfs2_glock *gl)
++{
++ if (gl->gl_ops == &gfs2_inode_glops)
++ return;
++
++ if (gfs2_glmutex_trylock(gl)) {
++ if (queue_empty(gl, &gl->gl_holders) &&
++ gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
++ goto out_schedule;
++ gfs2_glmutex_unlock(gl);
++ }
++ return;
++
++out_schedule:
++ gfs2_glmutex_unlock(gl);
++ gfs2_glock_schedule_for_reclaim(gl);
++}
++
++/**
++ * gfs2_scand_internal - Look for glocks and inodes to toss from memory
++ * @sdp: the filesystem
++ *
++ */
++
++void gfs2_scand_internal(struct gfs2_sbd *sdp)
++{
++ unsigned int x;
++
++ for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
++ examine_bucket(scan_glock, sdp, x);
++}
++
++/**
++ * clear_glock - look at a glock and see if we can free it from glock cache
++ * @gl: the glock to look at
++ *
++ */
++
++static void clear_glock(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ int released;
++
++ spin_lock(&sdp->sd_reclaim_lock);
++ if (!list_empty(&gl->gl_reclaim)) {
++ list_del_init(&gl->gl_reclaim);
++ atomic_dec(&sdp->sd_reclaim_count);
++ spin_unlock(&sdp->sd_reclaim_lock);
++ released = gfs2_glock_put(gl);
++ gfs2_assert(sdp, !released);
++ } else {
++ spin_unlock(&sdp->sd_reclaim_lock);
++ }
++
++ if (gfs2_glmutex_trylock(gl)) {
++ if (queue_empty(gl, &gl->gl_holders) &&
++ gl->gl_state != LM_ST_UNLOCKED)
++ handle_callback(gl, LM_ST_UNLOCKED);
++ gfs2_glmutex_unlock(gl);
++ }
++}
++
++/**
++ * gfs2_gl_hash_clear - Empty out the glock hash table
++ * @sdp: the filesystem
++ * @wait: wait until it's all gone
++ *
++ * Called when unmounting the filesystem, or when inter-node lock manager
++ * requests DROPLOCKS because it is running out of capacity.
++ */
++
++void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
++{
++ unsigned long t;
++ unsigned int x;
++ int cont;
++
++ t = jiffies;
++
++ for (;;) {
++ cont = 0;
++ for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
++ if (examine_bucket(clear_glock, sdp, x))
++ cont = 1;
++ }
++
++ if (!wait || !cont)
++ break;
++
++ if (time_after_eq(jiffies,
++ t + gfs2_tune_get(sdp, gt_stall_secs) * HZ)) {
++ fs_warn(sdp, "Unmount seems to be stalled. "
++ "Dumping lock state...\n");
++ gfs2_dump_lockstate(sdp);
++ t = jiffies;
++ }
++
++ invalidate_inodes(sdp->sd_vfs);
++ msleep(10);
++ }
++}
++
++/*
++ * Diagnostic routines to help debug distributed deadlock
++ */
++
++/**
++ * dump_holder - print information about a glock holder
++ * @str: a string naming the type of holder
++ * @gh: the glock holder
++ *
++ * Returns: 0 on success, -ENOBUFS when we run out of space
++ */
++
++static int dump_holder(char *str, struct gfs2_holder *gh)
++{
++ unsigned int x;
++ int error = -ENOBUFS;
++
++ printk(KERN_INFO " %s\n", str);
++ printk(KERN_INFO " owner = %ld\n",
++ (gh->gh_owner) ? (long)gh->gh_owner->pid : -1);
++ printk(KERN_INFO " gh_state = %u\n", gh->gh_state);
++ printk(KERN_INFO " gh_flags =");
++ for (x = 0; x < 32; x++)
++ if (gh->gh_flags & (1 << x))
++ printk(" %u", x);
++ printk(" \n");
++ printk(KERN_INFO " error = %d\n", gh->gh_error);
++ printk(KERN_INFO " gh_iflags =");
++ for (x = 0; x < 32; x++)
++ if (test_bit(x, &gh->gh_iflags))
++ printk(" %u", x);
++ printk(" \n");
++ print_symbol(KERN_INFO " initialized at: %s\n", gh->gh_ip);
++
++ error = 0;
++
++ return error;
++}
++
++/**
++ * dump_inode - print information about an inode
++ * @ip: the inode
++ *
++ * Returns: 0 on success, -ENOBUFS when we run out of space
++ */
++
++static int dump_inode(struct gfs2_inode *ip)
++{
++ unsigned int x;
++ int error = -ENOBUFS;
++
++ printk(KERN_INFO " Inode:\n");
++ printk(KERN_INFO " num = %llu %llu\n",
++ (unsigned long long)ip->i_num.no_formal_ino,
++ (unsigned long long)ip->i_num.no_addr);
++ printk(KERN_INFO " type = %u\n", IF2DT(ip->i_di.di_mode));
++ printk(KERN_INFO " i_flags =");
++ for (x = 0; x < 32; x++)
++ if (test_bit(x, &ip->i_flags))
++ printk(" %u", x);
++ printk(" \n");
++
++ error = 0;
++
++ return error;
++}
++
++/**
++ * dump_glock - print information about a glock
++ * @gl: the glock
++ * @count: where we are in the buffer
++ *
++ * Returns: 0 on success, -ENOBUFS when we run out of space
++ */
++
++static int dump_glock(struct gfs2_glock *gl)
++{
++ struct gfs2_holder *gh;
++ unsigned int x;
++ int error = -ENOBUFS;
++
++ spin_lock(&gl->gl_spin);
++
++ printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
++ (unsigned long long)gl->gl_name.ln_number);
++ printk(KERN_INFO " gl_flags =");
++ for (x = 0; x < 32; x++) {
++ if (test_bit(x, &gl->gl_flags))
++ printk(" %u", x);
++ }
++ printk(" \n");
++ printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref));
++ printk(KERN_INFO " gl_state = %u\n", gl->gl_state);
++ printk(KERN_INFO " gl_owner = %s\n", gl->gl_owner->comm);
++ print_symbol(KERN_INFO " gl_ip = %s\n", gl->gl_ip);
++ printk(KERN_INFO " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
++ printk(KERN_INFO " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
++ printk(KERN_INFO " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
++ printk(KERN_INFO " object = %s\n", (gl->gl_object) ? "yes" : "no");
++ printk(KERN_INFO " le = %s\n",
++ (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
++ printk(KERN_INFO " reclaim = %s\n",
++ (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
++ if (gl->gl_aspace)
++ printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
++ gl->gl_aspace->i_mapping->nrpages);
++ else
++ printk(KERN_INFO " aspace = no\n");
++ printk(KERN_INFO " ail = %d\n", atomic_read(&gl->gl_ail_count));
++ if (gl->gl_req_gh) {
++ error = dump_holder("Request", gl->gl_req_gh);
++ if (error)
++ goto out;
++ }
++ list_for_each_entry(gh, &gl->gl_holders, gh_list) {
++ error = dump_holder("Holder", gh);
++ if (error)
++ goto out;
++ }
++ list_for_each_entry(gh, &gl->gl_waiters1, gh_list) {
++ error = dump_holder("Waiter1", gh);
++ if (error)
++ goto out;
++ }
++ list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
++ error = dump_holder("Waiter2", gh);
++ if (error)
++ goto out;
++ }
++ list_for_each_entry(gh, &gl->gl_waiters3, gh_list) {
++ error = dump_holder("Waiter3", gh);
++ if (error)
++ goto out;
++ }
++ if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) {
++ if (!test_bit(GLF_LOCK, &gl->gl_flags) &&
++ list_empty(&gl->gl_holders)) {
++ error = dump_inode(gl->gl_object);
++ if (error)
++ goto out;
++ } else {
++ error = -ENOBUFS;
++ printk(KERN_INFO " Inode: busy\n");
++ }
++ }
++
++ error = 0;
++
++out:
++ spin_unlock(&gl->gl_spin);
++ return error;
++}
++
++/**
++ * gfs2_dump_lockstate - print out the current lockstate
++ * @sdp: the filesystem
++ * @ub: the buffer to copy the information into
++ *
++ * If @ub is NULL, dump the lockstate to the console.
++ *
++ */
++
++static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
++{
++ struct gfs2_glock *gl;
++ struct hlist_node *h;
++ unsigned int x;
++ int error = 0;
++
++ for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
++
++ read_lock(gl_lock_addr(x));
++
++ hlist_for_each_entry(gl, h, &gl_hash_table[x].hb_list, gl_list) {
++ if (gl->gl_sbd != sdp)
++ continue;
++
++ error = dump_glock(gl);
++ if (error)
++ break;
++ }
++
++ read_unlock(gl_lock_addr(x));
++
++ if (error)
++ break;
++ }
++
++
++ return error;
++}
++
++int __init gfs2_glock_init(void)
++{
++ unsigned i;
++ for(i = 0; i < GFS2_GL_HASH_SIZE; i++) {
++ INIT_HLIST_HEAD(&gl_hash_table[i].hb_list);
++ }
++#ifdef GL_HASH_LOCK_SZ
++ for(i = 0; i < GL_HASH_LOCK_SZ; i++) {
++ rwlock_init(&gl_hash_locks[i]);
++ }
++#endif
++ return 0;
++}
++
+diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
+new file mode 100644
+index 0000000..2b2a889
+--- /dev/null
++++ b/fs/gfs2/glock.h
+@@ -0,0 +1,153 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __GLOCK_DOT_H__
++#define __GLOCK_DOT_H__
++
++#include "incore.h"
++
++/* Flags for lock requests; used in gfs2_holder gh_flag field.
++ From lm_interface.h:
++#define LM_FLAG_TRY 0x00000001
++#define LM_FLAG_TRY_1CB 0x00000002
++#define LM_FLAG_NOEXP 0x00000004
++#define LM_FLAG_ANY 0x00000008
++#define LM_FLAG_PRIORITY 0x00000010 */
++
++#define GL_LOCAL_EXCL 0x00000020
++#define GL_ASYNC 0x00000040
++#define GL_EXACT 0x00000080
++#define GL_SKIP 0x00000100
++#define GL_ATIME 0x00000200
++#define GL_NOCACHE 0x00000400
++#define GL_NOCANCEL 0x00001000
++#define GL_AOP 0x00004000
++#define GL_DUMP 0x00008000
++
++#define GLR_TRYFAILED 13
++#define GLR_CANCELED 14
++
++static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
++{
++ struct gfs2_holder *gh;
++ int locked = 0;
++
++ /* Look in glock's list of holders for one with current task as owner */
++ spin_lock(&gl->gl_spin);
++ list_for_each_entry(gh, &gl->gl_holders, gh_list) {
++ if (gh->gh_owner == current) {
++ locked = 1;
++ break;
++ }
++ }
++ spin_unlock(&gl->gl_spin);
++
++ return locked;
++}
++
++static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl)
++{
++ return gl->gl_state == LM_ST_EXCLUSIVE;
++}
++
++static inline int gfs2_glock_is_held_dfrd(struct gfs2_glock *gl)
++{
++ return gl->gl_state == LM_ST_DEFERRED;
++}
++
++static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl)
++{
++ return gl->gl_state == LM_ST_SHARED;
++}
++
++static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
++{
++ int ret;
++ spin_lock(&gl->gl_spin);
++ ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
++ spin_unlock(&gl->gl_spin);
++ return ret;
++}
++
++int gfs2_glock_get(struct gfs2_sbd *sdp,
++ u64 number, const struct gfs2_glock_operations *glops,
++ int create, struct gfs2_glock **glp);
++void gfs2_glock_hold(struct gfs2_glock *gl);
++int gfs2_glock_put(struct gfs2_glock *gl);
++void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
++ struct gfs2_holder *gh);
++void gfs2_holder_reinit(unsigned int state, unsigned flags,
++ struct gfs2_holder *gh);
++void gfs2_holder_uninit(struct gfs2_holder *gh);
++
++void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags);
++void gfs2_glock_drop_th(struct gfs2_glock *gl);
++
++int gfs2_glock_nq(struct gfs2_holder *gh);
++int gfs2_glock_poll(struct gfs2_holder *gh);
++int gfs2_glock_wait(struct gfs2_holder *gh);
++void gfs2_glock_dq(struct gfs2_holder *gh);
++
++int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time);
++
++void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
++int gfs2_glock_nq_num(struct gfs2_sbd *sdp,
++ u64 number, const struct gfs2_glock_operations *glops,
++ unsigned int state, int flags, struct gfs2_holder *gh);
++
++int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
++void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
++void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
++
++void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
++ const struct gfs2_glock_operations *glops,
++ unsigned int state, int flags);
++void gfs2_glock_inode_squish(struct inode *inode);
++
++/**
++ * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
++ * @gl: the glock
++ * @state: the state we're requesting
++ * @flags: the modifier flags
++ * @gh: the holder structure
++ *
++ * Returns: 0, GLR_*, or errno
++ */
++
++static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
++ unsigned int state, int flags,
++ struct gfs2_holder *gh)
++{
++ int error;
++
++ gfs2_holder_init(gl, state, flags, gh);
++
++ error = gfs2_glock_nq(gh);
++ if (error)
++ gfs2_holder_uninit(gh);
++
++ return error;
++}
++
++/* Lock Value Block functions */
++
++int gfs2_lvb_hold(struct gfs2_glock *gl);
++void gfs2_lvb_unhold(struct gfs2_glock *gl);
++
++void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);
++
++void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
++void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
++
++void gfs2_scand_internal(struct gfs2_sbd *sdp);
++void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
++
++int __init gfs2_glock_init(void);
++
++#endif /* __GLOCK_DOT_H__ */
+diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
+new file mode 100644
+index 0000000..41a6b68
+--- /dev/null
++++ b/fs/gfs2/glops.c
+@@ -0,0 +1,615 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "log.h"
++#include "meta_io.h"
++#include "recovery.h"
++#include "rgrp.h"
++#include "util.h"
++#include "trans.h"
++
++/**
++ * ail_empty_gl - remove all buffers for a given lock from the AIL
++ * @gl: the glock
++ *
++ * None of the buffers should be dirty, locked, or pinned.
++ */
++
++static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ unsigned int blocks;
++ struct list_head *head = &gl->gl_ail_list;
++ struct gfs2_bufdata *bd;
++ struct buffer_head *bh;
++ u64 blkno;
++ int error;
++
++ blocks = atomic_read(&gl->gl_ail_count);
++ if (!blocks)
++ return;
++
++ error = gfs2_trans_begin(sdp, 0, blocks);
++ if (gfs2_assert_withdraw(sdp, !error))
++ return;
++
++ gfs2_log_lock(sdp);
++ while (!list_empty(head)) {
++ bd = list_entry(head->next, struct gfs2_bufdata,
++ bd_ail_gl_list);
++ bh = bd->bd_bh;
++ blkno = bh->b_blocknr;
++ gfs2_assert_withdraw(sdp, !buffer_busy(bh));
++
++ bd->bd_ail = NULL;
++ list_del(&bd->bd_ail_st_list);
++ list_del(&bd->bd_ail_gl_list);
++ atomic_dec(&gl->gl_ail_count);
++ brelse(bh);
++ gfs2_log_unlock(sdp);
++
++ gfs2_trans_add_revoke(sdp, blkno);
++
++ gfs2_log_lock(sdp);
++ }
++ gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
++ gfs2_log_unlock(sdp);
++
++ gfs2_trans_end(sdp);
++ gfs2_log_flush(sdp, NULL);
++}
++
++/**
++ * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
++ * @gl: the glock
++ *
++ */
++
++static void gfs2_pte_inval(struct gfs2_glock *gl)
++{
++ struct gfs2_inode *ip;
++ struct inode *inode;
++
++ ip = gl->gl_object;
++ inode = &ip->i_inode;
++ if (!ip || !S_ISREG(ip->i_di.di_mode))
++ return;
++
++ if (!test_bit(GIF_PAGED, &ip->i_flags))
++ return;
++
++ unmap_shared_mapping_range(inode->i_mapping, 0, 0);
++
++ if (test_bit(GIF_SW_PAGED, &ip->i_flags))
++ set_bit(GLF_DIRTY, &gl->gl_flags);
++
++ clear_bit(GIF_SW_PAGED, &ip->i_flags);
++}
++
++/**
++ * gfs2_page_inval - Invalidate all pages associated with a glock
++ * @gl: the glock
++ *
++ */
++
++static void gfs2_page_inval(struct gfs2_glock *gl)
++{
++ struct gfs2_inode *ip;
++ struct inode *inode;
++
++ ip = gl->gl_object;
++ inode = &ip->i_inode;
++ if (!ip || !S_ISREG(ip->i_di.di_mode))
++ return;
++
++ truncate_inode_pages(inode->i_mapping, 0);
++ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages);
++ clear_bit(GIF_PAGED, &ip->i_flags);
++}
++
++/**
++ * gfs2_page_wait - Wait for writeback of data
++ * @gl: the glock
++ *
++ * Syncs data (not metadata) for a regular file.
++ * No-op for all other types.
++ */
++
++static void gfs2_page_wait(struct gfs2_glock *gl)
++{
++ struct gfs2_inode *ip = gl->gl_object;
++ struct inode *inode = &ip->i_inode;
++ struct address_space *mapping = inode->i_mapping;
++ int error;
++
++ if (!S_ISREG(ip->i_di.di_mode))
++ return;
++
++ error = filemap_fdatawait(mapping);
++
++ /* Put back any errors cleared by filemap_fdatawait()
++ so they can be caught by someone who can pass them
++ up to user space. */
++
++ if (error == -ENOSPC)
++ set_bit(AS_ENOSPC, &mapping->flags);
++ else if (error)
++ set_bit(AS_EIO, &mapping->flags);
++
++}
++
++static void gfs2_page_writeback(struct gfs2_glock *gl)
++{
++ struct gfs2_inode *ip = gl->gl_object;
++ struct inode *inode = &ip->i_inode;
++ struct address_space *mapping = inode->i_mapping;
++
++ if (!S_ISREG(ip->i_di.di_mode))
++ return;
++
++ filemap_fdatawrite(mapping);
++}
++
++/**
++ * meta_go_sync - sync out the metadata for this glock
++ * @gl: the glock
++ * @flags: DIO_*
++ *
++ * Called when demoting or unlocking an EX glock. We must flush
++ * to disk all dirty buffers/pages relating to this glock, and must not
++ * not return to caller to demote/unlock the glock until I/O is complete.
++ */
++
++static void meta_go_sync(struct gfs2_glock *gl, int flags)
++{
++ if (!(flags & DIO_METADATA))
++ return;
++
++ if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
++ gfs2_log_flush(gl->gl_sbd, gl);
++ gfs2_meta_sync(gl);
++ if (flags & DIO_RELEASE)
++ gfs2_ail_empty_gl(gl);
++ }
++
++}
++
++/**
++ * meta_go_inval - invalidate the metadata for this glock
++ * @gl: the glock
++ * @flags:
++ *
++ */
++
++static void meta_go_inval(struct gfs2_glock *gl, int flags)
++{
++ if (!(flags & DIO_METADATA))
++ return;
++
++ gfs2_meta_inval(gl);
++ gl->gl_vn++;
++}
++
++/**
++ * inode_go_xmote_th - promote/demote a glock
++ * @gl: the glock
++ * @state: the requested state
++ * @flags:
++ *
++ */
++
++static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
++ int flags)
++{
++ if (gl->gl_state != LM_ST_UNLOCKED)
++ gfs2_pte_inval(gl);
++ gfs2_glock_xmote_th(gl, state, flags);
++}
++
++/**
++ * inode_go_xmote_bh - After promoting/demoting a glock
++ * @gl: the glock
++ *
++ */
++
++static void inode_go_xmote_bh(struct gfs2_glock *gl)
++{
++ struct gfs2_holder *gh = gl->gl_req_gh;
++ struct buffer_head *bh;
++ int error;
++
++ if (gl->gl_state != LM_ST_UNLOCKED &&
++ (!gh || !(gh->gh_flags & GL_SKIP))) {
++ error = gfs2_meta_read(gl, gl->gl_name.ln_number, 0, &bh);
++ if (!error)
++ brelse(bh);
++ }
++}
++
++/**
++ * inode_go_drop_th - unlock a glock
++ * @gl: the glock
++ *
++ * Invoked from rq_demote().
++ * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long)
++ * is being purged from our node's glock cache; we're dropping lock.
++ */
++
++static void inode_go_drop_th(struct gfs2_glock *gl)
++{
++ gfs2_pte_inval(gl);
++ gfs2_glock_drop_th(gl);
++}
++
++/**
++ * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
++ * @gl: the glock protecting the inode
++ * @flags:
++ *
++ */
++
++static void inode_go_sync(struct gfs2_glock *gl, int flags)
++{
++ int meta = (flags & DIO_METADATA);
++ int data = (flags & DIO_DATA);
++
++ if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
++ if (meta && data) {
++ gfs2_page_writeback(gl);
++ gfs2_log_flush(gl->gl_sbd, gl);
++ gfs2_meta_sync(gl);
++ gfs2_page_wait(gl);
++ clear_bit(GLF_DIRTY, &gl->gl_flags);
++ } else if (meta) {
++ gfs2_log_flush(gl->gl_sbd, gl);
++ gfs2_meta_sync(gl);
++ } else if (data) {
++ gfs2_page_writeback(gl);
++ gfs2_page_wait(gl);
++ }
++ if (flags & DIO_RELEASE)
++ gfs2_ail_empty_gl(gl);
++ }
++}
++
++/**
++ * inode_go_inval - prepare a inode glock to be released
++ * @gl: the glock
++ * @flags:
++ *
++ */
++
++static void inode_go_inval(struct gfs2_glock *gl, int flags)
++{
++ int meta = (flags & DIO_METADATA);
++ int data = (flags & DIO_DATA);
++
++ if (meta) {
++ gfs2_meta_inval(gl);
++ gl->gl_vn++;
++ }
++ if (data)
++ gfs2_page_inval(gl);
++}
++
++/**
++ * inode_go_demote_ok - Check to see if it's ok to unlock an inode glock
++ * @gl: the glock
++ *
++ * Returns: 1 if it's ok
++ */
++
++static int inode_go_demote_ok(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ int demote = 0;
++
++ if (!gl->gl_object && !gl->gl_aspace->i_mapping->nrpages)
++ demote = 1;
++ else if (!sdp->sd_args.ar_localcaching &&
++ time_after_eq(jiffies, gl->gl_stamp +
++ gfs2_tune_get(sdp, gt_demote_secs) * HZ))
++ demote = 1;
++
++ return demote;
++}
++
++/**
++ * inode_go_lock - operation done after an inode lock is locked by a process
++ * @gl: the glock
++ * @flags:
++ *
++ * Returns: errno
++ */
++
++static int inode_go_lock(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_inode *ip = gl->gl_object;
++ int error = 0;
++
++ if (!ip)
++ return 0;
++
++ if (ip->i_vn != gl->gl_vn) {
++ error = gfs2_inode_refresh(ip);
++ if (error)
++ return error;
++ gfs2_inode_attr_in(ip);
++ }
++
++ if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) &&
++ (gl->gl_state == LM_ST_EXCLUSIVE) &&
++ (gh->gh_flags & GL_LOCAL_EXCL))
++ error = gfs2_truncatei_resume(ip);
++
++ return error;
++}
++
++/**
++ * inode_go_unlock - operation done before an inode lock is unlocked by a
++ * process
++ * @gl: the glock
++ * @flags:
++ *
++ */
++
++static void inode_go_unlock(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_inode *ip = gl->gl_object;
++
++ if (ip == NULL)
++ return;
++ if (test_bit(GLF_DIRTY, &gl->gl_flags))
++ gfs2_inode_attr_in(ip);
++ gfs2_meta_cache_flush(ip);
++}
++
++/**
++ * inode_greedy -
++ * @gl: the glock
++ *
++ */
++
++static void inode_greedy(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct gfs2_inode *ip = gl->gl_object;
++ unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum);
++ unsigned int max = gfs2_tune_get(sdp, gt_greedy_max);
++ unsigned int new_time;
++
++ spin_lock(&ip->i_spin);
++
++ if (time_after(ip->i_last_pfault + quantum, jiffies)) {
++ new_time = ip->i_greedy + quantum;
++ if (new_time > max)
++ new_time = max;
++ } else {
++ new_time = ip->i_greedy - quantum;
++ if (!new_time || new_time > max)
++ new_time = 1;
++ }
++
++ ip->i_greedy = new_time;
++
++ spin_unlock(&ip->i_spin);
++
++ iput(&ip->i_inode);
++}
++
++/**
++ * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
++ * @gl: the glock
++ *
++ * Returns: 1 if it's ok
++ */
++
++static int rgrp_go_demote_ok(struct gfs2_glock *gl)
++{
++ return !gl->gl_aspace->i_mapping->nrpages;
++}
++
++/**
++ * rgrp_go_lock - operation done after an rgrp lock is locked by
++ * a first holder on this node.
++ * @gl: the glock
++ * @flags:
++ *
++ * Returns: errno
++ */
++
++static int rgrp_go_lock(struct gfs2_holder *gh)
++{
++ return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
++}
++
++/**
++ * rgrp_go_unlock - operation done before an rgrp lock is unlocked by
++ * a last holder on this node.
++ * @gl: the glock
++ * @flags:
++ *
++ */
++
++static void rgrp_go_unlock(struct gfs2_holder *gh)
++{
++ gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
++}
++
++/**
++ * trans_go_xmote_th - promote/demote the transaction glock
++ * @gl: the glock
++ * @state: the requested state
++ * @flags:
++ *
++ */
++
++static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
++ int flags)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++
++ if (gl->gl_state != LM_ST_UNLOCKED &&
++ test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
++ gfs2_meta_syncfs(sdp);
++ gfs2_log_shutdown(sdp);
++ }
++
++ gfs2_glock_xmote_th(gl, state, flags);
++}
++
++/**
++ * trans_go_xmote_bh - After promoting/demoting the transaction glock
++ * @gl: the glock
++ *
++ */
++
++static void trans_go_xmote_bh(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
++ struct gfs2_glock *j_gl = ip->i_gl;
++ struct gfs2_log_header head;
++ int error;
++
++ if (gl->gl_state != LM_ST_UNLOCKED &&
++ test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
++ gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode));
++ j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
++
++ error = gfs2_find_jhead(sdp->sd_jdesc, &head);
++ if (error)
++ gfs2_consist(sdp);
++ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT))
++ gfs2_consist(sdp);
++
++ /* Initialize some head of the log stuff */
++ if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
++ sdp->sd_log_sequence = head.lh_sequence + 1;
++ gfs2_log_pointers_init(sdp, head.lh_blkno);
++ }
++ }
++}
++
++/**
++ * trans_go_drop_th - unlock the transaction glock
++ * @gl: the glock
++ *
++ * We want to sync the device even with localcaching. Remember
++ * that localcaching journal replay only marks buffers dirty.
++ */
++
++static void trans_go_drop_th(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++
++ if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
++ gfs2_meta_syncfs(sdp);
++ gfs2_log_shutdown(sdp);
++ }
++
++ gfs2_glock_drop_th(gl);
++}
++
++/**
++ * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
++ * @gl: the glock
++ *
++ * Returns: 1 if it's ok
++ */
++
++static int quota_go_demote_ok(struct gfs2_glock *gl)
++{
++ return !atomic_read(&gl->gl_lvb_count);
++}
++
++const struct gfs2_glock_operations gfs2_meta_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_type = LM_TYPE_META,
++};
++
++const struct gfs2_glock_operations gfs2_inode_glops = {
++ .go_xmote_th = inode_go_xmote_th,
++ .go_xmote_bh = inode_go_xmote_bh,
++ .go_drop_th = inode_go_drop_th,
++ .go_sync = inode_go_sync,
++ .go_inval = inode_go_inval,
++ .go_demote_ok = inode_go_demote_ok,
++ .go_lock = inode_go_lock,
++ .go_unlock = inode_go_unlock,
++ .go_greedy = inode_greedy,
++ .go_type = LM_TYPE_INODE,
++};
++
++const struct gfs2_glock_operations gfs2_rgrp_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_sync = meta_go_sync,
++ .go_inval = meta_go_inval,
++ .go_demote_ok = rgrp_go_demote_ok,
++ .go_lock = rgrp_go_lock,
++ .go_unlock = rgrp_go_unlock,
++ .go_type = LM_TYPE_RGRP,
++};
++
++const struct gfs2_glock_operations gfs2_trans_glops = {
++ .go_xmote_th = trans_go_xmote_th,
++ .go_xmote_bh = trans_go_xmote_bh,
++ .go_drop_th = trans_go_drop_th,
++ .go_type = LM_TYPE_NONDISK,
++};
++
++const struct gfs2_glock_operations gfs2_iopen_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_type = LM_TYPE_IOPEN,
++};
++
++const struct gfs2_glock_operations gfs2_flock_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_type = LM_TYPE_FLOCK,
++};
++
++const struct gfs2_glock_operations gfs2_nondisk_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_type = LM_TYPE_NONDISK,
++};
++
++const struct gfs2_glock_operations gfs2_quota_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_demote_ok = quota_go_demote_ok,
++ .go_type = LM_TYPE_QUOTA,
++};
++
++const struct gfs2_glock_operations gfs2_journal_glops = {
++ .go_xmote_th = gfs2_glock_xmote_th,
++ .go_drop_th = gfs2_glock_drop_th,
++ .go_type = LM_TYPE_JOURNAL,
++};
++
+diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h
+new file mode 100644
+index 0000000..a1d9b5b
+--- /dev/null
++++ b/fs/gfs2/glops.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __GLOPS_DOT_H__
++#define __GLOPS_DOT_H__
++
++#include "incore.h"
++
++extern const struct gfs2_glock_operations gfs2_meta_glops;
++extern const struct gfs2_glock_operations gfs2_inode_glops;
++extern const struct gfs2_glock_operations gfs2_rgrp_glops;
++extern const struct gfs2_glock_operations gfs2_trans_glops;
++extern const struct gfs2_glock_operations gfs2_iopen_glops;
++extern const struct gfs2_glock_operations gfs2_flock_glops;
++extern const struct gfs2_glock_operations gfs2_nondisk_glops;
++extern const struct gfs2_glock_operations gfs2_quota_glops;
++extern const struct gfs2_glock_operations gfs2_journal_glops;
++
++#endif /* __GLOPS_DOT_H__ */
+diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
+new file mode 100644
+index 0000000..118dc69
+--- /dev/null
++++ b/fs/gfs2/incore.h
+@@ -0,0 +1,634 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __INCORE_DOT_H__
++#define __INCORE_DOT_H__
++
++#include <linux/fs.h>
++
++#define DIO_WAIT 0x00000010
++#define DIO_METADATA 0x00000020
++#define DIO_DATA 0x00000040
++#define DIO_RELEASE 0x00000080
++#define DIO_ALL 0x00000100
++
++struct gfs2_log_operations;
++struct gfs2_log_element;
++struct gfs2_holder;
++struct gfs2_glock;
++struct gfs2_quota_data;
++struct gfs2_trans;
++struct gfs2_ail;
++struct gfs2_jdesc;
++struct gfs2_sbd;
++
++typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret);
++
++/*
++ * Structure of operations that are associated with each
++ * type of element in the log.
++ */
++
++struct gfs2_log_operations {
++ void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le);
++ void (*lo_incore_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr);
++ void (*lo_before_commit) (struct gfs2_sbd *sdp);
++ void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai);
++ void (*lo_before_scan) (struct gfs2_jdesc *jd,
++ struct gfs2_log_header *head, int pass);
++ int (*lo_scan_elements) (struct gfs2_jdesc *jd, unsigned int start,
++ struct gfs2_log_descriptor *ld, __be64 *ptr,
++ int pass);
++ void (*lo_after_scan) (struct gfs2_jdesc *jd, int error, int pass);
++ const char *lo_name;
++};
++
++struct gfs2_log_element {
++ struct list_head le_list;
++ const struct gfs2_log_operations *le_ops;
++};
++
++struct gfs2_bitmap {
++ struct buffer_head *bi_bh;
++ char *bi_clone;
++ u32 bi_offset;
++ u32 bi_start;
++ u32 bi_len;
++};
++
++struct gfs2_rgrpd {
++ struct list_head rd_list; /* Link with superblock */
++ struct list_head rd_list_mru;
++ struct list_head rd_recent; /* Recently used rgrps */
++ struct gfs2_glock *rd_gl; /* Glock for this rgrp */
++ struct gfs2_rindex rd_ri;
++ struct gfs2_rgrp rd_rg;
++ u64 rd_rg_vn;
++ struct gfs2_bitmap *rd_bits;
++ unsigned int rd_bh_count;
++ struct mutex rd_mutex;
++ u32 rd_free_clone;
++ struct gfs2_log_element rd_le;
++ u32 rd_last_alloc_data;
++ u32 rd_last_alloc_meta;
++ struct gfs2_sbd *rd_sbd;
++};
++
++enum gfs2_state_bits {
++ BH_Pinned = BH_PrivateStart,
++ BH_Escaped = BH_PrivateStart + 1,
++};
++
++BUFFER_FNS(Pinned, pinned)
++TAS_BUFFER_FNS(Pinned, pinned)
++BUFFER_FNS(Escaped, escaped)
++TAS_BUFFER_FNS(Escaped, escaped)
++
++struct gfs2_bufdata {
++ struct buffer_head *bd_bh;
++ struct gfs2_glock *bd_gl;
++
++ struct list_head bd_list_tr;
++ struct gfs2_log_element bd_le;
++
++ struct gfs2_ail *bd_ail;
++ struct list_head bd_ail_st_list;
++ struct list_head bd_ail_gl_list;
++};
++
++struct gfs2_glock_operations {
++ void (*go_xmote_th) (struct gfs2_glock * gl, unsigned int state,
++ int flags);
++ void (*go_xmote_bh) (struct gfs2_glock * gl);
++ void (*go_drop_th) (struct gfs2_glock * gl);
++ void (*go_drop_bh) (struct gfs2_glock * gl);
++ void (*go_sync) (struct gfs2_glock * gl, int flags);
++ void (*go_inval) (struct gfs2_glock * gl, int flags);
++ int (*go_demote_ok) (struct gfs2_glock * gl);
++ int (*go_lock) (struct gfs2_holder * gh);
++ void (*go_unlock) (struct gfs2_holder * gh);
++ void (*go_callback) (struct gfs2_glock * gl, unsigned int state);
++ void (*go_greedy) (struct gfs2_glock * gl);
++ const int go_type;
++};
++
++enum {
++ /* Actions */
++ HIF_MUTEX = 0,
++ HIF_PROMOTE = 1,
++ HIF_DEMOTE = 2,
++ HIF_GREEDY = 3,
++
++ /* States */
++ HIF_ALLOCED = 4,
++ HIF_DEALLOC = 5,
++ HIF_HOLDER = 6,
++ HIF_FIRST = 7,
++ HIF_ABORTED = 9,
++};
++
++struct gfs2_holder {
++ struct list_head gh_list;
++
++ struct gfs2_glock *gh_gl;
++ struct task_struct *gh_owner;
++ unsigned int gh_state;
++ unsigned gh_flags;
++
++ int gh_error;
++ unsigned long gh_iflags;
++ struct completion gh_wait;
++ unsigned long gh_ip;
++};
++
++enum {
++ GLF_LOCK = 1,
++ GLF_STICKY = 2,
++ GLF_PREFETCH = 3,
++ GLF_DIRTY = 5,
++ GLF_SKIP_WAITERS2 = 6,
++ GLF_GREEDY = 7,
++};
++
++struct gfs2_glock {
++ struct hlist_node gl_list;
++ unsigned long gl_flags; /* GLF_... */
++ struct lm_lockname gl_name;
++ atomic_t gl_ref;
++
++ spinlock_t gl_spin;
++
++ unsigned int gl_state;
++ unsigned int gl_hash;
++ struct task_struct *gl_owner;
++ unsigned long gl_ip;
++ struct list_head gl_holders;
++ struct list_head gl_waiters1; /* HIF_MUTEX */
++ struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */
++ struct list_head gl_waiters3; /* HIF_PROMOTE */
++
++ const struct gfs2_glock_operations *gl_ops;
++
++ struct gfs2_holder *gl_req_gh;
++ gfs2_glop_bh_t gl_req_bh;
++
++ void *gl_lock;
++ char *gl_lvb;
++ atomic_t gl_lvb_count;
++
++ u64 gl_vn;
++ unsigned long gl_stamp;
++ void *gl_object;
++
++ struct list_head gl_reclaim;
++
++ struct gfs2_sbd *gl_sbd;
++
++ struct inode *gl_aspace;
++ struct gfs2_log_element gl_le;
++ struct list_head gl_ail_list;
++ atomic_t gl_ail_count;
++};
++
++struct gfs2_alloc {
++ /* Quota stuff */
++
++ struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
++ struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
++ unsigned int al_qd_num;
++
++ u32 al_requested; /* Filled in by caller of gfs2_inplace_reserve() */
++ u32 al_alloced; /* Filled in by gfs2_alloc_*() */
++
++ /* Filled in by gfs2_inplace_reserve() */
++
++ unsigned int al_line;
++ char *al_file;
++ struct gfs2_holder al_ri_gh;
++ struct gfs2_holder al_rgd_gh;
++ struct gfs2_rgrpd *al_rgd;
++
++};
++
++enum {
++ GIF_QD_LOCKED = 1,
++ GIF_PAGED = 2,
++ GIF_SW_PAGED = 3,
++};
++
++struct gfs2_inode {
++ struct inode i_inode;
++ struct gfs2_inum i_num;
++
++ unsigned long i_flags; /* GIF_... */
++
++ u64 i_vn;
++ struct gfs2_dinode i_di; /* To be replaced by ref to block */
++
++ struct gfs2_glock *i_gl; /* Move into i_gh? */
++ struct gfs2_holder i_iopen_gh;
++ struct gfs2_holder i_gh; /* for prepare/commit_write only */
++ struct gfs2_alloc i_alloc;
++ u64 i_last_rg_alloc;
++
++ spinlock_t i_spin;
++ struct rw_semaphore i_rw_mutex;
++ unsigned int i_greedy;
++ unsigned long i_last_pfault;
++
++ struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
++};
++
++/*
++ * Since i_inode is the first element of struct gfs2_inode,
++ * this is effectively a cast.
++ */
++static inline struct gfs2_inode *GFS2_I(struct inode *inode)
++{
++ return container_of(inode, struct gfs2_inode, i_inode);
++}
++
++/* To be removed? */
++static inline struct gfs2_sbd *GFS2_SB(struct inode *inode)
++{
++ return inode->i_sb->s_fs_info;
++}
++
++enum {
++ GFF_DID_DIRECT_ALLOC = 0,
++ GFF_EXLOCK = 1,
++};
++
++struct gfs2_file {
++ unsigned long f_flags; /* GFF_... */
++ struct mutex f_fl_mutex;
++ struct gfs2_holder f_fl_gh;
++};
++
++struct gfs2_revoke {
++ struct gfs2_log_element rv_le;
++ u64 rv_blkno;
++};
++
++struct gfs2_revoke_replay {
++ struct list_head rr_list;
++ u64 rr_blkno;
++ unsigned int rr_where;
++};
++
++enum {
++ QDF_USER = 0,
++ QDF_CHANGE = 1,
++ QDF_LOCKED = 2,
++};
++
++struct gfs2_quota_lvb {
++ __be32 qb_magic;
++ u32 __pad;
++ __be64 qb_limit; /* Hard limit of # blocks to alloc */
++ __be64 qb_warn; /* Warn user when alloc is above this # */
++ __be64 qb_value; /* Current # blocks allocated */
++};
++
++struct gfs2_quota_data {
++ struct list_head qd_list;
++ unsigned int qd_count;
++
++ u32 qd_id;
++ unsigned long qd_flags; /* QDF_... */
++
++ s64 qd_change;
++ s64 qd_change_sync;
++
++ unsigned int qd_slot;
++ unsigned int qd_slot_count;
++
++ struct buffer_head *qd_bh;
++ struct gfs2_quota_change *qd_bh_qc;
++ unsigned int qd_bh_count;
++
++ struct gfs2_glock *qd_gl;
++ struct gfs2_quota_lvb qd_qb;
++
++ u64 qd_sync_gen;
++ unsigned long qd_last_warn;
++ unsigned long qd_last_touched;
++};
++
++struct gfs2_log_buf {
++ struct list_head lb_list;
++ struct buffer_head *lb_bh;
++ struct buffer_head *lb_real;
++};
++
++struct gfs2_trans {
++ unsigned long tr_ip;
++
++ unsigned int tr_blocks;
++ unsigned int tr_revokes;
++ unsigned int tr_reserved;
++
++ struct gfs2_holder tr_t_gh;
++
++ int tr_touched;
++
++ unsigned int tr_num_buf;
++ unsigned int tr_num_buf_new;
++ unsigned int tr_num_buf_rm;
++ struct list_head tr_list_buf;
++
++ unsigned int tr_num_revoke;
++ unsigned int tr_num_revoke_rm;
++};
++
++struct gfs2_ail {
++ struct list_head ai_list;
++
++ unsigned int ai_first;
++ struct list_head ai_ail1_list;
++ struct list_head ai_ail2_list;
++
++ u64 ai_sync_gen;
++};
++
++struct gfs2_jdesc {
++ struct list_head jd_list;
++
++ struct inode *jd_inode;
++ unsigned int jd_jid;
++ int jd_dirty;
++
++ unsigned int jd_blocks;
++};
++
++#define GFS2_GLOCKD_DEFAULT 1
++#define GFS2_GLOCKD_MAX 16
++
++#define GFS2_QUOTA_DEFAULT GFS2_QUOTA_OFF
++#define GFS2_QUOTA_OFF 0
++#define GFS2_QUOTA_ACCOUNT 1
++#define GFS2_QUOTA_ON 2
++
++#define GFS2_DATA_DEFAULT GFS2_DATA_ORDERED
++#define GFS2_DATA_WRITEBACK 1
++#define GFS2_DATA_ORDERED 2
++
++struct gfs2_args {
++ char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */
++ char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */
++ char ar_hostdata[GFS2_LOCKNAME_LEN]; /* Host specific data */
++ int ar_spectator; /* Don't get a journal because we're always RO */
++ int ar_ignore_local_fs; /* Don't optimize even if local_fs is 1 */
++ int ar_localflocks; /* Let the VFS do flock|fcntl locks for us */
++ int ar_localcaching; /* Local-style caching (dangerous on multihost) */
++ int ar_debug; /* Oops on errors instead of trying to be graceful */
++ int ar_upgrade; /* Upgrade ondisk/multihost format */
++ unsigned int ar_num_glockd; /* Number of glockd threads */
++ int ar_posix_acl; /* Enable posix acls */
++ int ar_quota; /* off/account/on */
++ int ar_suiddir; /* suiddir support */
++ int ar_data; /* ordered/writeback */
++};
++
++struct gfs2_tune {
++ spinlock_t gt_spin;
++
++ unsigned int gt_ilimit;
++ unsigned int gt_ilimit_tries;
++ unsigned int gt_ilimit_min;
++ unsigned int gt_demote_secs; /* Cache retention for unheld glock */
++ unsigned int gt_incore_log_blocks;
++ unsigned int gt_log_flush_secs;
++ unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
++
++ unsigned int gt_scand_secs;
++ unsigned int gt_recoverd_secs;
++ unsigned int gt_logd_secs;
++ unsigned int gt_quotad_secs;
++
++ unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */
++ unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */
++ unsigned int gt_quota_scale_num; /* Numerator */
++ unsigned int gt_quota_scale_den; /* Denominator */
++ unsigned int gt_quota_cache_secs;
++ unsigned int gt_quota_quantum; /* Secs between syncs to quota file */
++ unsigned int gt_atime_quantum; /* Min secs between atime updates */
++ unsigned int gt_new_files_jdata;
++ unsigned int gt_new_files_directio;
++ unsigned int gt_max_atomic_write; /* Split big writes into this size */
++ unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
++ unsigned int gt_lockdump_size;
++ unsigned int gt_stall_secs; /* Detects trouble! */
++ unsigned int gt_complain_secs;
++ unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
++ unsigned int gt_entries_per_readdir;
++ unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */
++ unsigned int gt_greedy_default;
++ unsigned int gt_greedy_quantum;
++ unsigned int gt_greedy_max;
++ unsigned int gt_statfs_quantum;
++ unsigned int gt_statfs_slow;
++};
++
++enum {
++ SDF_JOURNAL_CHECKED = 0,
++ SDF_JOURNAL_LIVE = 1,
++ SDF_SHUTDOWN = 2,
++ SDF_NOATIME = 3,
++};
++
++#define GFS2_FSNAME_LEN 256
++
++struct gfs2_sbd {
++ struct super_block *sd_vfs;
++ struct super_block *sd_vfs_meta;
++ struct kobject sd_kobj;
++ unsigned long sd_flags; /* SDF_... */
++ struct gfs2_sb sd_sb;
++
++ /* Constants computed on mount */
++
++ u32 sd_fsb2bb;
++ u32 sd_fsb2bb_shift;
++ u32 sd_diptrs; /* Number of pointers in a dinode */
++ u32 sd_inptrs; /* Number of pointers in a indirect block */
++ u32 sd_jbsize; /* Size of a journaled data block */
++ u32 sd_hash_bsize; /* sizeof(exhash block) */
++ u32 sd_hash_bsize_shift;
++ u32 sd_hash_ptrs; /* Number of pointers in a hash block */
++ u32 sd_qc_per_block;
++ u32 sd_max_dirres; /* Max blocks needed to add a directory entry */
++ u32 sd_max_height; /* Max height of a file's metadata tree */
++ u64 sd_heightsize[GFS2_MAX_META_HEIGHT];
++ u32 sd_max_jheight; /* Max height of journaled file's meta tree */
++ u64 sd_jheightsize[GFS2_MAX_META_HEIGHT];
++
++ struct gfs2_args sd_args; /* Mount arguments */
++ struct gfs2_tune sd_tune; /* Filesystem tuning structure */
++
++ /* Lock Stuff */
++
++ struct lm_lockstruct sd_lockstruct;
++ struct list_head sd_reclaim_list;
++ spinlock_t sd_reclaim_lock;
++ wait_queue_head_t sd_reclaim_wq;
++ atomic_t sd_reclaim_count;
++ struct gfs2_holder sd_live_gh;
++ struct gfs2_glock *sd_rename_gl;
++ struct gfs2_glock *sd_trans_gl;
++
++ /* Inode Stuff */
++
++ struct inode *sd_master_dir;
++ struct inode *sd_jindex;
++ struct inode *sd_inum_inode;
++ struct inode *sd_statfs_inode;
++ struct inode *sd_ir_inode;
++ struct inode *sd_sc_inode;
++ struct inode *sd_qc_inode;
++ struct inode *sd_rindex;
++ struct inode *sd_quota_inode;
++
++ /* Inum stuff */
++
++ struct mutex sd_inum_mutex;
++
++ /* StatFS stuff */
++
++ spinlock_t sd_statfs_spin;
++ struct mutex sd_statfs_mutex;
++ struct gfs2_statfs_change sd_statfs_master;
++ struct gfs2_statfs_change sd_statfs_local;
++ unsigned long sd_statfs_sync_time;
++
++ /* Resource group stuff */
++
++ u64 sd_rindex_vn;
++ spinlock_t sd_rindex_spin;
++ struct mutex sd_rindex_mutex;
++ struct list_head sd_rindex_list;
++ struct list_head sd_rindex_mru_list;
++ struct list_head sd_rindex_recent_list;
++ struct gfs2_rgrpd *sd_rindex_forward;
++ unsigned int sd_rgrps;
++
++ /* Journal index stuff */
++
++ struct list_head sd_jindex_list;
++ spinlock_t sd_jindex_spin;
++ struct mutex sd_jindex_mutex;
++ unsigned int sd_journals;
++ unsigned long sd_jindex_refresh_time;
++
++ struct gfs2_jdesc *sd_jdesc;
++ struct gfs2_holder sd_journal_gh;
++ struct gfs2_holder sd_jinode_gh;
++
++ struct gfs2_holder sd_ir_gh;
++ struct gfs2_holder sd_sc_gh;
++ struct gfs2_holder sd_qc_gh;
++
++ /* Daemon stuff */
++
++ struct task_struct *sd_scand_process;
++ struct task_struct *sd_recoverd_process;
++ struct task_struct *sd_logd_process;
++ struct task_struct *sd_quotad_process;
++ struct task_struct *sd_glockd_process[GFS2_GLOCKD_MAX];
++ unsigned int sd_glockd_num;
++
++ /* Quota stuff */
++
++ struct list_head sd_quota_list;
++ atomic_t sd_quota_count;
++ spinlock_t sd_quota_spin;
++ struct mutex sd_quota_mutex;
++
++ unsigned int sd_quota_slots;
++ unsigned int sd_quota_chunks;
++ unsigned char **sd_quota_bitmap;
++
++ u64 sd_quota_sync_gen;
++ unsigned long sd_quota_sync_time;
++
++ /* Log stuff */
++
++ spinlock_t sd_log_lock;
++
++ unsigned int sd_log_blks_reserved;
++ unsigned int sd_log_commited_buf;
++ unsigned int sd_log_commited_revoke;
++
++ unsigned int sd_log_num_gl;
++ unsigned int sd_log_num_buf;
++ unsigned int sd_log_num_revoke;
++ unsigned int sd_log_num_rg;
++ unsigned int sd_log_num_databuf;
++ unsigned int sd_log_num_jdata;
++ unsigned int sd_log_num_hdrs;
++
++ struct list_head sd_log_le_gl;
++ struct list_head sd_log_le_buf;
++ struct list_head sd_log_le_revoke;
++ struct list_head sd_log_le_rg;
++ struct list_head sd_log_le_databuf;
++
++ unsigned int sd_log_blks_free;
++ struct mutex sd_log_reserve_mutex;
++
++ u64 sd_log_sequence;
++ unsigned int sd_log_head;
++ unsigned int sd_log_tail;
++ int sd_log_idle;
++
++ unsigned long sd_log_flush_time;
++ struct rw_semaphore sd_log_flush_lock;
++ struct list_head sd_log_flush_list;
++
++ unsigned int sd_log_flush_head;
++ u64 sd_log_flush_wrapped;
++
++ struct list_head sd_ail1_list;
++ struct list_head sd_ail2_list;
++ u64 sd_ail_sync_gen;
++
++ /* Replay stuff */
++
++ struct list_head sd_revoke_list;
++ unsigned int sd_replay_tail;
++
++ unsigned int sd_found_blocks;
++ unsigned int sd_found_revokes;
++ unsigned int sd_replayed_blocks;
++
++ /* For quiescing the filesystem */
++
++ struct gfs2_holder sd_freeze_gh;
++ struct mutex sd_freeze_lock;
++ unsigned int sd_freeze_count;
++
++ /* Counters */
++
++ atomic_t sd_glock_count;
++ atomic_t sd_glock_held_count;
++ atomic_t sd_inode_count;
++ atomic_t sd_reclaimed;
++
++ char sd_fsname[GFS2_FSNAME_LEN];
++ char sd_table_name[GFS2_FSNAME_LEN];
++ char sd_proto_name[GFS2_FSNAME_LEN];
++
++ /* Debugging crud */
++
++ unsigned long sd_last_warning;
++ struct vfsmount *sd_gfs2mnt;
++};
++
++#endif /* __INCORE_DOT_H__ */
++
+diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
+new file mode 100644
+index 0000000..d470e52
+--- /dev/null
++++ b/fs/gfs2/inode.c
+@@ -0,0 +1,1382 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/posix_acl.h>
++#include <linux/sort.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++#include <linux/security.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "acl.h"
++#include "bmap.h"
++#include "dir.h"
++#include "eattr.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "log.h"
++#include "meta_io.h"
++#include "ops_address.h"
++#include "ops_file.h"
++#include "ops_inode.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++
++/**
++ * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode
++ * @ip: The GFS2 inode (with embedded disk inode data)
++ * @inode: The Linux VFS inode
++ *
++ */
++
++void gfs2_inode_attr_in(struct gfs2_inode *ip)
++{
++ struct inode *inode = &ip->i_inode;
++ struct gfs2_dinode *di = &ip->i_di;
++
++ inode->i_ino = ip->i_num.no_addr;
++
++ switch (di->di_mode & S_IFMT) {
++ case S_IFBLK:
++ case S_IFCHR:
++ inode->i_rdev = MKDEV(di->di_major, di->di_minor);
++ break;
++ default:
++ inode->i_rdev = 0;
++ break;
++ };
++
++ inode->i_mode = di->di_mode;
++ inode->i_nlink = di->di_nlink;
++ inode->i_uid = di->di_uid;
++ inode->i_gid = di->di_gid;
++ i_size_write(inode, di->di_size);
++ inode->i_atime.tv_sec = di->di_atime;
++ inode->i_mtime.tv_sec = di->di_mtime;
++ inode->i_ctime.tv_sec = di->di_ctime;
++ inode->i_atime.tv_nsec = 0;
++ inode->i_mtime.tv_nsec = 0;
++ inode->i_ctime.tv_nsec = 0;
++ inode->i_blocks = di->di_blocks <<
++ (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT);
++
++ if (di->di_flags & GFS2_DIF_IMMUTABLE)
++ inode->i_flags |= S_IMMUTABLE;
++ else
++ inode->i_flags &= ~S_IMMUTABLE;
++
++ if (di->di_flags & GFS2_DIF_APPENDONLY)
++ inode->i_flags |= S_APPEND;
++ else
++ inode->i_flags &= ~S_APPEND;
++}
++
++/**
++ * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode
++ * @ip: The GFS2 inode
++ *
++ * Only copy out the attributes that we want the VFS layer
++ * to be able to modify.
++ */
++
++void gfs2_inode_attr_out(struct gfs2_inode *ip)
++{
++ struct inode *inode = &ip->i_inode;
++ struct gfs2_dinode *di = &ip->i_di;
++ gfs2_assert_withdraw(GFS2_SB(inode),
++ (di->di_mode & S_IFMT) == (inode->i_mode & S_IFMT));
++ di->di_mode = inode->i_mode;
++ di->di_uid = inode->i_uid;
++ di->di_gid = inode->i_gid;
++ di->di_atime = inode->i_atime.tv_sec;
++ di->di_mtime = inode->i_mtime.tv_sec;
++ di->di_ctime = inode->i_ctime.tv_sec;
++}
++
++static int iget_test(struct inode *inode, void *opaque)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_inum *inum = opaque;
++
++ if (ip && ip->i_num.no_addr == inum->no_addr)
++ return 1;
++
++ return 0;
++}
++
++static int iget_set(struct inode *inode, void *opaque)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_inum *inum = opaque;
++
++ ip->i_num = *inum;
++ return 0;
++}
++
++struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum)
++{
++ return ilookup5(sb, (unsigned long)inum->no_formal_ino,
++ iget_test, inum);
++}
++
++static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum)
++{
++ return iget5_locked(sb, (unsigned long)inum->no_formal_ino,
++ iget_test, iget_set, inum);
++}
++
++/**
++ * gfs2_inode_lookup - Lookup an inode
++ * @sb: The super block
++ * @inum: The inode number
++ * @type: The type of the inode
++ *
++ * Returns: A VFS inode, or an error
++ */
++
++struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned int type)
++{
++ struct inode *inode = gfs2_iget(sb, inum);
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_glock *io_gl;
++ int error;
++
++ if (!inode)
++ return ERR_PTR(-ENOBUFS);
++
++ if (inode->i_state & I_NEW) {
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ umode_t mode = DT2IF(type);
++ inode->i_private = ip;
++ inode->i_mode = mode;
++
++ if (S_ISREG(mode)) {
++ inode->i_op = &gfs2_file_iops;
++ inode->i_fop = &gfs2_file_fops;
++ inode->i_mapping->a_ops = &gfs2_file_aops;
++ } else if (S_ISDIR(mode)) {
++ inode->i_op = &gfs2_dir_iops;
++ inode->i_fop = &gfs2_dir_fops;
++ } else if (S_ISLNK(mode)) {
++ inode->i_op = &gfs2_symlink_iops;
++ } else {
++ inode->i_op = &gfs2_dev_iops;
++ }
++
++ error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
++ if (unlikely(error))
++ goto fail;
++ ip->i_gl->gl_object = ip;
++
++ error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
++ if (unlikely(error))
++ goto fail_put;
++
++ ip->i_vn = ip->i_gl->gl_vn - 1;
++ error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
++ if (unlikely(error))
++ goto fail_iopen;
++
++ gfs2_glock_put(io_gl);
++ unlock_new_inode(inode);
++ }
++
++ return inode;
++fail_iopen:
++ gfs2_glock_put(io_gl);
++fail_put:
++ ip->i_gl->gl_object = NULL;
++ gfs2_glock_put(ip->i_gl);
++fail:
++ iput(inode);
++ return ERR_PTR(error);
++}
++
++/**
++ * gfs2_inode_refresh - Refresh the incore copy of the dinode
++ * @ip: The GFS2 inode
++ *
++ * Returns: errno
++ */
++
++int gfs2_inode_refresh(struct gfs2_inode *ip)
++{
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ return error;
++
++ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) {
++ brelse(dibh);
++ return -EIO;
++ }
++
++ gfs2_dinode_in(&ip->i_di, dibh->b_data);
++
++ brelse(dibh);
++
++ if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) {
++ if (gfs2_consist_inode(ip))
++ gfs2_dinode_print(&ip->i_di);
++ return -EIO;
++ }
++ if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino)
++ return -ESTALE;
++
++ ip->i_vn = ip->i_gl->gl_vn;
++
++ return 0;
++}
++
++int gfs2_dinode_dealloc(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al;
++ struct gfs2_rgrpd *rgd;
++ int error;
++
++ if (ip->i_di.di_blocks != 1) {
++ if (gfs2_consist_inode(ip))
++ gfs2_dinode_print(&ip->i_di);
++ return -EIO;
++ }
++
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out;
++
++ error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
++ if (error)
++ goto out_qs;
++
++ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
++ if (!rgd) {
++ gfs2_consist_inode(ip);
++ error = -EIO;
++ goto out_rindex_relse;
++ }
++
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
++ &al->al_rgd_gh);
++ if (error)
++ goto out_rindex_relse;
++
++ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1);
++ if (error)
++ goto out_rg_gunlock;
++
++ gfs2_trans_add_gl(ip->i_gl);
++
++ gfs2_free_di(rgd, ip);
++
++ gfs2_trans_end(sdp);
++ clear_bit(GLF_STICKY, &ip->i_gl->gl_flags);
++
++out_rg_gunlock:
++ gfs2_glock_dq_uninit(&al->al_rgd_gh);
++out_rindex_relse:
++ gfs2_glock_dq_uninit(&al->al_ri_gh);
++out_qs:
++ gfs2_quota_unhold(ip);
++out:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++/**
++ * gfs2_change_nlink - Change nlink count on inode
++ * @ip: The GFS2 inode
++ * @diff: The change in the nlink count required
++ *
++ * Returns: errno
++ */
++
++int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
++{
++ struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
++ struct buffer_head *dibh;
++ u32 nlink;
++ int error;
++
++ BUG_ON(ip->i_di.di_nlink != ip->i_inode.i_nlink);
++ nlink = ip->i_di.di_nlink + diff;
++
++ /* If we are reducing the nlink count, but the new value ends up being
++ bigger than the old one, we must have underflowed. */
++ if (diff < 0 && nlink > ip->i_di.di_nlink) {
++ if (gfs2_consist_inode(ip))
++ gfs2_dinode_print(&ip->i_di);
++ return -EIO;
++ }
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ return error;
++
++ ip->i_di.di_nlink = nlink;
++ ip->i_di.di_ctime = get_seconds();
++ ip->i_inode.i_nlink = nlink;
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ mark_inode_dirty(&ip->i_inode);
++
++ if (ip->i_di.di_nlink == 0) {
++ struct gfs2_rgrpd *rgd;
++ struct gfs2_holder ri_gh, rg_gh;
++
++ error = gfs2_rindex_hold(sdp, &ri_gh);
++ if (error)
++ goto out;
++ error = -EIO;
++ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
++ if (!rgd)
++ goto out_norgrp;
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
++ if (error)
++ goto out_norgrp;
++
++ clear_nlink(&ip->i_inode);
++ gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
++ gfs2_glock_dq_uninit(&rg_gh);
++out_norgrp:
++ gfs2_glock_dq_uninit(&ri_gh);
++ }
++out:
++ return error;
++}
++
++struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
++{
++ struct qstr qstr;
++ gfs2_str2qstr(&qstr, name);
++ return gfs2_lookupi(dip, &qstr, 1, NULL);
++}
++
++
++/**
++ * gfs2_lookupi - Look up a filename in a directory and return its inode
++ * @d_gh: An initialized holder for the directory glock
++ * @name: The name of the inode to look for
++ * @is_root: If 1, ignore the caller's permissions
++ * @i_gh: An uninitialized holder for the new inode glock
++ *
++ * There will always be a vnode (Linux VFS inode) for the d_gh inode unless
++ * @is_root is true.
++ *
++ * Returns: errno
++ */
++
++struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
++ int is_root, struct nameidata *nd)
++{
++ struct super_block *sb = dir->i_sb;
++ struct gfs2_inode *dip = GFS2_I(dir);
++ struct gfs2_holder d_gh;
++ struct gfs2_inum inum;
++ unsigned int type;
++ int error = 0;
++ struct inode *inode = NULL;
++
++ if (!name->len || name->len > GFS2_FNAMESIZE)
++ return ERR_PTR(-ENAMETOOLONG);
++
++ if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) ||
++ (name->len == 2 && memcmp(name->name, "..", 2) == 0 &&
++ dir == sb->s_root->d_inode)) {
++ igrab(dir);
++ return dir;
++ }
++
++ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
++ if (error)
++ return ERR_PTR(error);
++
++ if (!is_root) {
++ error = permission(dir, MAY_EXEC, NULL);
++ if (error)
++ goto out;
++ }
++
++ error = gfs2_dir_search(dir, name, &inum, &type);
++ if (error)
++ goto out;
++
++ inode = gfs2_inode_lookup(sb, &inum, type);
++
++out:
++ gfs2_glock_dq_uninit(&d_gh);
++ if (error == -ENOENT)
++ return NULL;
++ return inode;
++}
++
++static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
++{
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
++ struct buffer_head *bh;
++ struct gfs2_inum_range ir;
++ int error;
++
++ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
++ if (error)
++ return error;
++ mutex_lock(&sdp->sd_inum_mutex);
++
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error) {
++ mutex_unlock(&sdp->sd_inum_mutex);
++ gfs2_trans_end(sdp);
++ return error;
++ }
++
++ gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
++
++ if (ir.ir_length) {
++ *formal_ino = ir.ir_start++;
++ ir.ir_length--;
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ gfs2_inum_range_out(&ir,
++ bh->b_data + sizeof(struct gfs2_dinode));
++ brelse(bh);
++ mutex_unlock(&sdp->sd_inum_mutex);
++ gfs2_trans_end(sdp);
++ return 0;
++ }
++
++ brelse(bh);
++
++ mutex_unlock(&sdp->sd_inum_mutex);
++ gfs2_trans_end(sdp);
++
++ return 1;
++}
++
++static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino)
++{
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
++ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode);
++ struct gfs2_holder gh;
++ struct buffer_head *bh;
++ struct gfs2_inum_range ir;
++ int error;
++
++ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
++ if (error)
++ return error;
++
++ error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
++ if (error)
++ goto out;
++ mutex_lock(&sdp->sd_inum_mutex);
++
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ goto out_end_trans;
++
++ gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
++
++ if (!ir.ir_length) {
++ struct buffer_head *m_bh;
++ u64 x, y;
++
++ error = gfs2_meta_inode_buffer(m_ip, &m_bh);
++ if (error)
++ goto out_brelse;
++
++ x = *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode));
++ x = y = be64_to_cpu(x);
++ ir.ir_start = x;
++ ir.ir_length = GFS2_INUM_QUANTUM;
++ x += GFS2_INUM_QUANTUM;
++ if (x < y)
++ gfs2_consist_inode(m_ip);
++ x = cpu_to_be64(x);
++ gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
++ *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x;
++
++ brelse(m_bh);
++ }
++
++ *formal_ino = ir.ir_start++;
++ ir.ir_length--;
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode));
++
++out_brelse:
++ brelse(bh);
++out_end_trans:
++ mutex_unlock(&sdp->sd_inum_mutex);
++ gfs2_trans_end(sdp);
++out:
++ gfs2_glock_dq_uninit(&gh);
++ return error;
++}
++
++static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum)
++{
++ int error;
++
++ error = pick_formal_ino_1(sdp, inum);
++ if (error <= 0)
++ return error;
++
++ error = pick_formal_ino_2(sdp, inum);
++
++ return error;
++}
++
++/**
++ * create_ok - OK to create a new on-disk inode here?
++ * @dip: Directory in which dinode is to be created
++ * @name: Name of new dinode
++ * @mode:
++ *
++ * Returns: errno
++ */
++
++static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
++ unsigned int mode)
++{
++ int error;
++
++ error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
++ if (error)
++ return error;
++
++ /* Don't create entries in an unlinked directory */
++ if (!dip->i_di.di_nlink)
++ return -EPERM;
++
++ error = gfs2_dir_search(&dip->i_inode, name, NULL, NULL);
++ switch (error) {
++ case -ENOENT:
++ error = 0;
++ break;
++ case 0:
++ return -EEXIST;
++ default:
++ return error;
++ }
++
++ if (dip->i_di.di_entries == (u32)-1)
++ return -EFBIG;
++ if (S_ISDIR(mode) && dip->i_di.di_nlink == (u32)-1)
++ return -EMLINK;
++
++ return 0;
++}
++
++static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode,
++ unsigned int *uid, unsigned int *gid)
++{
++ if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir &&
++ (dip->i_di.di_mode & S_ISUID) && dip->i_di.di_uid) {
++ if (S_ISDIR(*mode))
++ *mode |= S_ISUID;
++ else if (dip->i_di.di_uid != current->fsuid)
++ *mode &= ~07111;
++ *uid = dip->i_di.di_uid;
++ } else
++ *uid = current->fsuid;
++
++ if (dip->i_di.di_mode & S_ISGID) {
++ if (S_ISDIR(*mode))
++ *mode |= S_ISGID;
++ *gid = dip->i_di.di_gid;
++ } else
++ *gid = current->fsgid;
++}
++
++static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum,
++ u64 *generation)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ int error;
++
++ gfs2_alloc_get(dip);
++
++ dip->i_alloc.al_requested = RES_DINODE;
++ error = gfs2_inplace_reserve(dip);
++ if (error)
++ goto out;
++
++ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0);
++ if (error)
++ goto out_ipreserv;
++
++ inum->no_addr = gfs2_alloc_di(dip, generation);
++
++ gfs2_trans_end(sdp);
++
++out_ipreserv:
++ gfs2_inplace_release(dip);
++out:
++ gfs2_alloc_put(dip);
++ return error;
++}
++
++/**
++ * init_dinode - Fill in a new dinode structure
++ * @dip: the directory this inode is being created in
++ * @gl: The glock covering the new inode
++ * @inum: the inode number
++ * @mode: the file permissions
++ * @uid:
++ * @gid:
++ *
++ */
++
++static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
++ const struct gfs2_inum *inum, unsigned int mode,
++ unsigned int uid, unsigned int gid,
++ const u64 *generation)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct gfs2_dinode *di;
++ struct buffer_head *dibh;
++
++ dibh = gfs2_meta_new(gl, inum->no_addr);
++ gfs2_trans_add_bh(gl, dibh, 1);
++ gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI);
++ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
++ di = (struct gfs2_dinode *)dibh->b_data;
++
++ di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino);
++ di->di_num.no_addr = cpu_to_be64(inum->no_addr);
++ di->di_mode = cpu_to_be32(mode);
++ di->di_uid = cpu_to_be32(uid);
++ di->di_gid = cpu_to_be32(gid);
++ di->di_nlink = cpu_to_be32(0);
++ di->di_size = cpu_to_be64(0);
++ di->di_blocks = cpu_to_be64(1);
++ di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds());
++ di->di_major = di->di_minor = cpu_to_be32(0);
++ di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr);
++ di->di_generation = cpu_to_be64(*generation);
++ di->di_flags = cpu_to_be32(0);
++
++ if (S_ISREG(mode)) {
++ if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) ||
++ gfs2_tune_get(sdp, gt_new_files_jdata))
++ di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA);
++ if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO) ||
++ gfs2_tune_get(sdp, gt_new_files_directio))
++ di->di_flags |= cpu_to_be32(GFS2_DIF_DIRECTIO);
++ } else if (S_ISDIR(mode)) {
++ di->di_flags |= cpu_to_be32(dip->i_di.di_flags &
++ GFS2_DIF_INHERIT_DIRECTIO);
++ di->di_flags |= cpu_to_be32(dip->i_di.di_flags &
++ GFS2_DIF_INHERIT_JDATA);
++ }
++
++ di->__pad1 = 0;
++ di->di_payload_format = cpu_to_be32(0);
++ di->di_height = cpu_to_be32(0);
++ di->__pad2 = 0;
++ di->__pad3 = 0;
++ di->di_depth = cpu_to_be16(0);
++ di->di_entries = cpu_to_be32(0);
++ memset(&di->__pad4, 0, sizeof(di->__pad4));
++ di->di_eattr = cpu_to_be64(0);
++ memset(&di->di_reserved, 0, sizeof(di->di_reserved));
++
++ brelse(dibh);
++}
++
++static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
++ unsigned int mode, const struct gfs2_inum *inum,
++ const u64 *generation)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ unsigned int uid, gid;
++ int error;
++
++ munge_mode_uid_gid(dip, &mode, &uid, &gid);
++ gfs2_alloc_get(dip);
++
++ error = gfs2_quota_lock(dip, uid, gid);
++ if (error)
++ goto out;
++
++ error = gfs2_quota_check(dip, uid, gid);
++ if (error)
++ goto out_quota;
++
++ error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0);
++ if (error)
++ goto out_quota;
++
++ init_dinode(dip, gl, inum, mode, uid, gid, generation);
++ gfs2_quota_change(dip, +1, uid, gid);
++ gfs2_trans_end(sdp);
++
++out_quota:
++ gfs2_quota_unlock(dip);
++out:
++ gfs2_alloc_put(dip);
++ return error;
++}
++
++static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
++ struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct gfs2_alloc *al;
++ int alloc_required;
++ struct buffer_head *dibh;
++ int error;
++
++ al = gfs2_alloc_get(dip);
++
++ error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto fail;
++
++ error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
++ if (alloc_required < 0)
++ goto fail;
++ if (alloc_required) {
++ error = gfs2_quota_check(dip, dip->i_di.di_uid,
++ dip->i_di.di_gid);
++ if (error)
++ goto fail_quota_locks;
++
++ al->al_requested = sdp->sd_max_dirres;
++
++ error = gfs2_inplace_reserve(dip);
++ if (error)
++ goto fail_quota_locks;
++
++ error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
++ al->al_rgd->rd_ri.ri_length +
++ 2 * RES_DINODE +
++ RES_STATFS + RES_QUOTA, 0);
++ if (error)
++ goto fail_ipreserv;
++ } else {
++ error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0);
++ if (error)
++ goto fail_quota_locks;
++ }
++
++ error = gfs2_dir_add(&dip->i_inode, name, &ip->i_num, IF2DT(ip->i_di.di_mode));
++ if (error)
++ goto fail_end_trans;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto fail_end_trans;
++ ip->i_di.di_nlink = 1;
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ return 0;
++
++fail_end_trans:
++ gfs2_trans_end(sdp);
++
++fail_ipreserv:
++ if (dip->i_alloc.al_rgd)
++ gfs2_inplace_release(dip);
++
++fail_quota_locks:
++ gfs2_quota_unlock(dip);
++
++fail:
++ gfs2_alloc_put(dip);
++ return error;
++}
++
++static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
++{
++ int err;
++ size_t len;
++ void *value;
++ char *name;
++ struct gfs2_ea_request er;
++
++ err = security_inode_init_security(&ip->i_inode, &dip->i_inode,
++ &name, &value, &len);
++
++ if (err) {
++ if (err == -EOPNOTSUPP)
++ return 0;
++ return err;
++ }
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++
++ er.er_type = GFS2_EATYPE_SECURITY;
++ er.er_name = name;
++ er.er_data = value;
++ er.er_name_len = strlen(name);
++ er.er_data_len = len;
++
++ err = gfs2_ea_set_i(ip, &er);
++
++ kfree(value);
++ kfree(name);
++
++ return err;
++}
++
++/**
++ * gfs2_createi - Create a new inode
++ * @ghs: An array of two holders
++ * @name: The name of the new file
++ * @mode: the permissions on the new inode
++ *
++ * @ghs[0] is an initialized holder for the directory
++ * @ghs[1] is the holder for the inode lock
++ *
++ * If the return value is not NULL, the glocks on both the directory and the new
++ * file are held. A transaction has been started and an inplace reservation
++ * is held, as well.
++ *
++ * Returns: An inode
++ */
++
++struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
++ unsigned int mode)
++{
++ struct inode *inode;
++ struct gfs2_inode *dip = ghs->gh_gl->gl_object;
++ struct inode *dir = &dip->i_inode;
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct gfs2_inum inum;
++ int error;
++ u64 generation;
++
++ if (!name->len || name->len > GFS2_FNAMESIZE)
++ return ERR_PTR(-ENAMETOOLONG);
++
++ gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
++ error = gfs2_glock_nq(ghs);
++ if (error)
++ goto fail;
++
++ error = create_ok(dip, name, mode);
++ if (error)
++ goto fail_gunlock;
++
++ error = pick_formal_ino(sdp, &inum.no_formal_ino);
++ if (error)
++ goto fail_gunlock;
++
++ error = alloc_dinode(dip, &inum, &generation);
++ if (error)
++ goto fail_gunlock;
++
++ if (inum.no_addr < dip->i_num.no_addr) {
++ gfs2_glock_dq(ghs);
++
++ error = gfs2_glock_nq_num(sdp, inum.no_addr,
++ &gfs2_inode_glops, LM_ST_EXCLUSIVE,
++ GL_SKIP, ghs + 1);
++ if (error) {
++ return ERR_PTR(error);
++ }
++
++ gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
++ error = gfs2_glock_nq(ghs);
++ if (error) {
++ gfs2_glock_dq_uninit(ghs + 1);
++ return ERR_PTR(error);
++ }
++
++ error = create_ok(dip, name, mode);
++ if (error)
++ goto fail_gunlock2;
++ } else {
++ error = gfs2_glock_nq_num(sdp, inum.no_addr,
++ &gfs2_inode_glops, LM_ST_EXCLUSIVE,
++ GL_SKIP, ghs + 1);
++ if (error)
++ goto fail_gunlock;
++ }
++
++ error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation);
++ if (error)
++ goto fail_gunlock2;
++
++ inode = gfs2_inode_lookup(dir->i_sb, &inum, IF2DT(mode));
++ if (IS_ERR(inode))
++ goto fail_gunlock2;
++
++ error = gfs2_inode_refresh(GFS2_I(inode));
++ if (error)
++ goto fail_iput;
++
++ error = gfs2_acl_create(dip, GFS2_I(inode));
++ if (error)
++ goto fail_iput;
++
++ error = gfs2_security_init(dip, GFS2_I(inode));
++ if (error)
++ goto fail_iput;
++
++ error = link_dinode(dip, name, GFS2_I(inode));
++ if (error)
++ goto fail_iput;
++
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ return inode;
++
++fail_iput:
++ iput(inode);
++fail_gunlock2:
++ gfs2_glock_dq_uninit(ghs + 1);
++fail_gunlock:
++ gfs2_glock_dq(ghs);
++fail:
++ return ERR_PTR(error);
++}
++
++/**
++ * gfs2_rmdiri - Remove a directory
++ * @dip: The parent directory of the directory to be removed
++ * @name: The name of the directory to be removed
++ * @ip: The GFS2 inode of the directory to be removed
++ *
++ * Assumes Glocks on dip and ip are held
++ *
++ * Returns: errno
++ */
++
++int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
++ struct gfs2_inode *ip)
++{
++ struct qstr dotname;
++ int error;
++
++ if (ip->i_di.di_entries != 2) {
++ if (gfs2_consist_inode(ip))
++ gfs2_dinode_print(&ip->i_di);
++ return -EIO;
++ }
++
++ error = gfs2_dir_del(dip, name);
++ if (error)
++ return error;
++
++ error = gfs2_change_nlink(dip, -1);
++ if (error)
++ return error;
++
++ gfs2_str2qstr(&dotname, ".");
++ error = gfs2_dir_del(ip, &dotname);
++ if (error)
++ return error;
++
++ gfs2_str2qstr(&dotname, "..");
++ error = gfs2_dir_del(ip, &dotname);
++ if (error)
++ return error;
++
++ error = gfs2_change_nlink(ip, -2);
++ if (error)
++ return error;
++
++ return error;
++}
++
++/*
++ * gfs2_unlink_ok - check to see that a inode is still in a directory
++ * @dip: the directory
++ * @name: the name of the file
++ * @ip: the inode
++ *
++ * Assumes that the lock on (at least) @dip is held.
++ *
++ * Returns: 0 if the parent/child relationship is correct, errno if it isn't
++ */
++
++int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
++ struct gfs2_inode *ip)
++{
++ struct gfs2_inum inum;
++ unsigned int type;
++ int error;
++
++ if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
++ return -EPERM;
++
++ if ((dip->i_di.di_mode & S_ISVTX) &&
++ dip->i_di.di_uid != current->fsuid &&
++ ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER))
++ return -EPERM;
++
++ if (IS_APPEND(&dip->i_inode))
++ return -EPERM;
++
++ error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
++ if (error)
++ return error;
++
++ error = gfs2_dir_search(&dip->i_inode, name, &inum, &type);
++ if (error)
++ return error;
++
++ if (!gfs2_inum_equal(&inum, &ip->i_num))
++ return -ENOENT;
++
++ if (IF2DT(ip->i_di.di_mode) != type) {
++ gfs2_consist_inode(dip);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++/*
++ * gfs2_ok_to_move - check if it's ok to move a directory to another directory
++ * @this: move this
++ * @to: to here
++ *
++ * Follow @to back to the root and make sure we don't encounter @this
++ * Assumes we already hold the rename lock.
++ *
++ * Returns: errno
++ */
++
++int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
++{
++ struct inode *dir = &to->i_inode;
++ struct super_block *sb = dir->i_sb;
++ struct inode *tmp;
++ struct qstr dotdot;
++ int error = 0;
++
++ gfs2_str2qstr(&dotdot, "..");
++
++ igrab(dir);
++
++ for (;;) {
++ if (dir == &this->i_inode) {
++ error = -EINVAL;
++ break;
++ }
++ if (dir == sb->s_root->d_inode) {
++ error = 0;
++ break;
++ }
++
++ tmp = gfs2_lookupi(dir, &dotdot, 1, NULL);
++ if (IS_ERR(tmp)) {
++ error = PTR_ERR(tmp);
++ break;
++ }
++
++ iput(dir);
++ dir = tmp;
++ }
++
++ iput(dir);
++
++ return error;
++}
++
++/**
++ * gfs2_readlinki - return the contents of a symlink
++ * @ip: the symlink's inode
++ * @buf: a pointer to the buffer to be filled
++ * @len: a pointer to the length of @buf
++ *
++ * If @buf is too small, a piece of memory is kmalloc()ed and needs
++ * to be freed by the caller.
++ *
++ * Returns: errno
++ */
++
++int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
++{
++ struct gfs2_holder i_gh;
++ struct buffer_head *dibh;
++ unsigned int x;
++ int error;
++
++ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
++ error = gfs2_glock_nq_atime(&i_gh);
++ if (error) {
++ gfs2_holder_uninit(&i_gh);
++ return error;
++ }
++
++ if (!ip->i_di.di_size) {
++ gfs2_consist_inode(ip);
++ error = -EIO;
++ goto out;
++ }
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out;
++
++ x = ip->i_di.di_size + 1;
++ if (x > *len) {
++ *buf = kmalloc(x, GFP_KERNEL);
++ if (!*buf) {
++ error = -ENOMEM;
++ goto out_brelse;
++ }
++ }
++
++ memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
++ *len = x;
++
++out_brelse:
++ brelse(dibh);
++out:
++ gfs2_glock_dq_uninit(&i_gh);
++ return error;
++}
++
++/**
++ * gfs2_glock_nq_atime - Acquire a hold on an inode's glock, and
++ * conditionally update the inode's atime
++ * @gh: the holder to acquire
++ *
++ * Tests atime (access time) for gfs2_read, gfs2_readdir and gfs2_mmap
++ * Update if the difference between the current time and the inode's current
++ * atime is greater than an interval specified at mount.
++ *
++ * Returns: errno
++ */
++
++int gfs2_glock_nq_atime(struct gfs2_holder *gh)
++{
++ struct gfs2_glock *gl = gh->gh_gl;
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct gfs2_inode *ip = gl->gl_object;
++ s64 curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum);
++ unsigned int state;
++ int flags;
++ int error;
++
++ if (gfs2_assert_warn(sdp, gh->gh_flags & GL_ATIME) ||
++ gfs2_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) ||
++ gfs2_assert_warn(sdp, gl->gl_ops == &gfs2_inode_glops))
++ return -EINVAL;
++
++ state = gh->gh_state;
++ flags = gh->gh_flags;
++
++ error = gfs2_glock_nq(gh);
++ if (error)
++ return error;
++
++ if (test_bit(SDF_NOATIME, &sdp->sd_flags) ||
++ (sdp->sd_vfs->s_flags & MS_RDONLY))
++ return 0;
++
++ curtime = get_seconds();
++ if (curtime - ip->i_di.di_atime >= quantum) {
++ gfs2_glock_dq(gh);
++ gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
++ gh);
++ error = gfs2_glock_nq(gh);
++ if (error)
++ return error;
++
++ /* Verify that atime hasn't been updated while we were
++ trying to get exclusive lock. */
++
++ curtime = get_seconds();
++ if (curtime - ip->i_di.di_atime >= quantum) {
++ struct buffer_head *dibh;
++ struct gfs2_dinode *di;
++
++ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
++ if (error == -EROFS)
++ return 0;
++ if (error)
++ goto fail;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto fail_end_trans;
++
++ ip->i_di.di_atime = curtime;
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ di = (struct gfs2_dinode *)dibh->b_data;
++ di->di_atime = cpu_to_be64(ip->i_di.di_atime);
++ brelse(dibh);
++
++ gfs2_trans_end(sdp);
++ }
++
++ /* If someone else has asked for the glock,
++ unlock and let them have it. Then reacquire
++ in the original state. */
++ if (gfs2_glock_is_blocking(gl)) {
++ gfs2_glock_dq(gh);
++ gfs2_holder_reinit(state, flags, gh);
++ return gfs2_glock_nq(gh);
++ }
++ }
++
++ return 0;
++
++fail_end_trans:
++ gfs2_trans_end(sdp);
++fail:
++ gfs2_glock_dq(gh);
++ return error;
++}
++
++/**
++ * glock_compare_atime - Compare two struct gfs2_glock structures for sort
++ * @arg_a: the first structure
++ * @arg_b: the second structure
++ *
++ * Returns: 1 if A > B
++ * -1 if A < B
++ * 0 if A == B
++ */
++
++static int glock_compare_atime(const void *arg_a, const void *arg_b)
++{
++ const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
++ const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
++ const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
++ const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
++
++ if (a->ln_number > b->ln_number)
++ return 1;
++ if (a->ln_number < b->ln_number)
++ return -1;
++ if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
++ return 1;
++ if (gh_a->gh_state == LM_ST_SHARED && (gh_b->gh_flags & GL_ATIME))
++ return 1;
++
++ return 0;
++}
++
++/**
++ * gfs2_glock_nq_m_atime - acquire multiple glocks where one may need an
++ * atime update
++ * @num_gh: the number of structures
++ * @ghs: an array of struct gfs2_holder structures
++ *
++ * Returns: 0 on success (all glocks acquired),
++ * errno on failure (no glocks acquired)
++ */
++
++int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs)
++{
++ struct gfs2_holder **p;
++ unsigned int x;
++ int error = 0;
++
++ if (!num_gh)
++ return 0;
++
++ if (num_gh == 1) {
++ ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
++ if (ghs->gh_flags & GL_ATIME)
++ error = gfs2_glock_nq_atime(ghs);
++ else
++ error = gfs2_glock_nq(ghs);
++ return error;
++ }
++
++ p = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
++ if (!p)
++ return -ENOMEM;
++
++ for (x = 0; x < num_gh; x++)
++ p[x] = &ghs[x];
++
++ sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare_atime,NULL);
++
++ for (x = 0; x < num_gh; x++) {
++ p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
++
++ if (p[x]->gh_flags & GL_ATIME)
++ error = gfs2_glock_nq_atime(p[x]);
++ else
++ error = gfs2_glock_nq(p[x]);
++
++ if (error) {
++ while (x--)
++ gfs2_glock_dq(p[x]);
++ break;
++ }
++ }
++
++ kfree(p);
++ return error;
++}
++
++
++static int
++__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
++{
++ struct buffer_head *dibh;
++ int error;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (!error) {
++ error = inode_setattr(&ip->i_inode, attr);
++ gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
++ gfs2_inode_attr_out(ip);
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++ return error;
++}
++
++/**
++ * gfs2_setattr_simple -
++ * @ip:
++ * @attr:
++ *
++ * Called with a reference on the vnode.
++ *
++ * Returns: errno
++ */
++
++int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
++{
++ int error;
++
++ if (current->journal_info)
++ return __gfs2_setattr_simple(ip, attr);
++
++ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
++ if (error)
++ return error;
++
++ error = __gfs2_setattr_simple(ip, attr);
++ gfs2_trans_end(GFS2_SB(&ip->i_inode));
++ return error;
++}
++
+diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
+new file mode 100644
+index 0000000..f5d8617
+--- /dev/null
++++ b/fs/gfs2/inode.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __INODE_DOT_H__
++#define __INODE_DOT_H__
++
++static inline int gfs2_is_stuffed(struct gfs2_inode *ip)
++{
++ return !ip->i_di.di_height;
++}
++
++static inline int gfs2_is_jdata(struct gfs2_inode *ip)
++{
++ return ip->i_di.di_flags & GFS2_DIF_JDATA;
++}
++
++static inline int gfs2_is_dir(struct gfs2_inode *ip)
++{
++ return S_ISDIR(ip->i_di.di_mode);
++}
++
++void gfs2_inode_attr_in(struct gfs2_inode *ip);
++void gfs2_inode_attr_out(struct gfs2_inode *ip);
++struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned type);
++struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum);
++
++int gfs2_inode_refresh(struct gfs2_inode *ip);
++
++int gfs2_dinode_dealloc(struct gfs2_inode *inode);
++int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
++struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
++ int is_root, struct nameidata *nd);
++struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
++ unsigned int mode);
++int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
++ struct gfs2_inode *ip);
++int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
++ struct gfs2_inode *ip);
++int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to);
++int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len);
++
++int gfs2_glock_nq_atime(struct gfs2_holder *gh);
++int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs);
++
++int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
++
++struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
++
++#endif /* __INODE_DOT_H__ */
++
+diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c
+new file mode 100644
+index 0000000..effe4a3
+--- /dev/null
++++ b/fs/gfs2/lm.c
+@@ -0,0 +1,217 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/delay.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "lm.h"
++#include "super.h"
++#include "util.h"
++
++/**
++ * gfs2_lm_mount - mount a locking protocol
++ * @sdp: the filesystem
++ * @args: mount arguements
++ * @silent: if 1, don't complain if the FS isn't a GFS2 fs
++ *
++ * Returns: errno
++ */
++
++int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
++{
++ char *proto = sdp->sd_proto_name;
++ char *table = sdp->sd_table_name;
++ int flags = 0;
++ int error;
++
++ if (sdp->sd_args.ar_spectator)
++ flags |= LM_MFLAG_SPECTATOR;
++
++ fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
++
++ error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
++ gfs2_glock_cb, sdp,
++ GFS2_MIN_LVB_SIZE, flags,
++ &sdp->sd_lockstruct, &sdp->sd_kobj);
++ if (error) {
++ fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
++ proto, table, sdp->sd_args.ar_hostdata);
++ goto out;
++ }
++
++ if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) ||
++ gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
++ gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
++ GFS2_MIN_LVB_SIZE)) {
++ gfs2_unmount_lockproto(&sdp->sd_lockstruct);
++ goto out;
++ }
++
++ if (sdp->sd_args.ar_spectator)
++ snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
++ else
++ snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
++ sdp->sd_lockstruct.ls_jid);
++
++ fs_info(sdp, "Joined cluster. Now mounting FS...\n");
++
++ if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
++ !sdp->sd_args.ar_ignore_local_fs) {
++ sdp->sd_args.ar_localflocks = 1;
++ sdp->sd_args.ar_localcaching = 1;
++ }
++
++out:
++ return error;
++}
++
++void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
++{
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
++ sdp->sd_lockstruct.ls_lockspace);
++}
++
++void gfs2_lm_unmount(struct gfs2_sbd *sdp)
++{
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ gfs2_unmount_lockproto(&sdp->sd_lockstruct);
++}
++
++int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
++{
++ va_list args;
++
++ if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
++ return 0;
++
++ va_start(args, fmt);
++ vprintk(fmt, args);
++ va_end(args);
++
++ fs_err(sdp, "about to withdraw from the cluster\n");
++ BUG_ON(sdp->sd_args.ar_debug);
++
++
++ fs_err(sdp, "waiting for outstanding I/O\n");
++
++ /* FIXME: suspend dm device so oustanding bio's complete
++ and all further io requests fail */
++
++ fs_err(sdp, "telling LM to withdraw\n");
++ gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
++ fs_err(sdp, "withdrawn\n");
++ dump_stack();
++
++ return -1;
++}
++
++int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ void **lockp)
++{
++ int error = -EIO;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ error = sdp->sd_lockstruct.ls_ops->lm_get_lock(
++ sdp->sd_lockstruct.ls_lockspace, name, lockp);
++ return error;
++}
++
++void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock)
++{
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ sdp->sd_lockstruct.ls_ops->lm_put_lock(lock);
++}
++
++unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
++ unsigned int cur_state, unsigned int req_state,
++ unsigned int flags)
++{
++ int ret = 0;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state,
++ req_state, flags);
++ return ret;
++}
++
++unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
++ unsigned int cur_state)
++{
++ int ret = 0;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state);
++ return ret;
++}
++
++void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock)
++{
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ sdp->sd_lockstruct.ls_ops->lm_cancel(lock);
++}
++
++int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp)
++{
++ int error = -EIO;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp);
++ return error;
++}
++
++void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb)
++{
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb);
++}
++
++int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl)
++{
++ int error = -EIO;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ error = sdp->sd_lockstruct.ls_ops->lm_plock_get(
++ sdp->sd_lockstruct.ls_lockspace, name, file, fl);
++ return error;
++}
++
++int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ struct file *file, int cmd, struct file_lock *fl)
++{
++ int error = -EIO;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ error = sdp->sd_lockstruct.ls_ops->lm_plock(
++ sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl);
++ return error;
++}
++
++int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl)
++{
++ int error = -EIO;
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ error = sdp->sd_lockstruct.ls_ops->lm_punlock(
++ sdp->sd_lockstruct.ls_lockspace, name, file, fl);
++ return error;
++}
++
++void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
++ unsigned int message)
++{
++ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ sdp->sd_lockstruct.ls_ops->lm_recovery_done(
++ sdp->sd_lockstruct.ls_lockspace, jid, message);
++}
++
+diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h
+new file mode 100644
+index 0000000..21cdc30
+--- /dev/null
++++ b/fs/gfs2/lm.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __LM_DOT_H__
++#define __LM_DOT_H__
++
++struct gfs2_sbd;
++
++#define GFS2_MIN_LVB_SIZE 32
++
++int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent);
++void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp);
++void gfs2_lm_unmount(struct gfs2_sbd *sdp);
++int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
++ __attribute__ ((format(printf, 2, 3)));
++int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ void **lockp);
++void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock);
++unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
++ unsigned int cur_state, unsigned int req_state,
++ unsigned int flags);
++unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
++ unsigned int cur_state);
++void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock);
++int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp);
++void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb);
++int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl);
++int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ struct file *file, int cmd, struct file_lock *fl);
++int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl);
++void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
++ unsigned int message);
++
++#endif /* __LM_DOT_H__ */
+diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c
+new file mode 100644
+index 0000000..663fee7
+--- /dev/null
++++ b/fs/gfs2/locking.c
+@@ -0,0 +1,184 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/kmod.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/lm_interface.h>
++
++struct lmh_wrapper {
++ struct list_head lw_list;
++ const struct lm_lockops *lw_ops;
++};
++
++/* List of registered low-level locking protocols. A file system selects one
++ of them by name at mount time, e.g. lock_nolock, lock_dlm. */
++
++static LIST_HEAD(lmh_list);
++static DEFINE_MUTEX(lmh_lock);
++
++/**
++ * gfs2_register_lockproto - Register a low-level locking protocol
++ * @proto: the protocol definition
++ *
++ * Returns: 0 on success, -EXXX on failure
++ */
++
++int gfs2_register_lockproto(const struct lm_lockops *proto)
++{
++ struct lmh_wrapper *lw;
++
++ mutex_lock(&lmh_lock);
++
++ list_for_each_entry(lw, &lmh_list, lw_list) {
++ if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
++ mutex_unlock(&lmh_lock);
++ printk(KERN_INFO "GFS2: protocol %s already exists\n",
++ proto->lm_proto_name);
++ return -EEXIST;
++ }
++ }
++
++ lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL);
++ if (!lw) {
++ mutex_unlock(&lmh_lock);
++ return -ENOMEM;
++ }
++
++ lw->lw_ops = proto;
++ list_add(&lw->lw_list, &lmh_list);
++
++ mutex_unlock(&lmh_lock);
++
++ return 0;
++}
++
++/**
++ * gfs2_unregister_lockproto - Unregister a low-level locking protocol
++ * @proto: the protocol definition
++ *
++ */
++
++void gfs2_unregister_lockproto(const struct lm_lockops *proto)
++{
++ struct lmh_wrapper *lw;
++
++ mutex_lock(&lmh_lock);
++
++ list_for_each_entry(lw, &lmh_list, lw_list) {
++ if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
++ list_del(&lw->lw_list);
++ mutex_unlock(&lmh_lock);
++ kfree(lw);
++ return;
++ }
++ }
++
++ mutex_unlock(&lmh_lock);
++
++ printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n",
++ proto->lm_proto_name);
++}
++
++/**
++ * gfs2_mount_lockproto - Mount a lock protocol
++ * @proto_name - the name of the protocol
++ * @table_name - the name of the lock space
++ * @host_data - data specific to this host
++ * @cb - the callback to the code using the lock module
++ * @sdp - The GFS2 superblock
++ * @min_lvb_size - the mininum LVB size that the caller can deal with
++ * @flags - LM_MFLAG_*
++ * @lockstruct - a structure returned describing the mount
++ *
++ * Returns: 0 on success, -EXXX on failure
++ */
++
++int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
++ lm_callback_t cb, void *cb_data,
++ unsigned int min_lvb_size, int flags,
++ struct lm_lockstruct *lockstruct,
++ struct kobject *fskobj)
++{
++ struct lmh_wrapper *lw = NULL;
++ int try = 0;
++ int error, found;
++
++retry:
++ mutex_lock(&lmh_lock);
++
++ found = 0;
++ list_for_each_entry(lw, &lmh_list, lw_list) {
++ if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found) {
++ if (!try && capable(CAP_SYS_MODULE)) {
++ try = 1;
++ mutex_unlock(&lmh_lock);
++ request_module(proto_name);
++ goto retry;
++ }
++ printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name);
++ error = -ENOENT;
++ goto out;
++ }
++
++ if (!try_module_get(lw->lw_ops->lm_owner)) {
++ try = 0;
++ mutex_unlock(&lmh_lock);
++ msleep(1000);
++ goto retry;
++ }
++
++ error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data,
++ min_lvb_size, flags, lockstruct, fskobj);
++ if (error)
++ module_put(lw->lw_ops->lm_owner);
++out:
++ mutex_unlock(&lmh_lock);
++ return error;
++}
++
++void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct)
++{
++ mutex_lock(&lmh_lock);
++ lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace);
++ if (lockstruct->ls_ops->lm_owner)
++ module_put(lockstruct->ls_ops->lm_owner);
++ mutex_unlock(&lmh_lock);
++}
++
++/**
++ * gfs2_withdraw_lockproto - abnormally unmount a lock module
++ * @lockstruct: the lockstruct passed into mount
++ *
++ */
++
++void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct)
++{
++ mutex_lock(&lmh_lock);
++ lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace);
++ if (lockstruct->ls_ops->lm_owner)
++ module_put(lockstruct->ls_ops->lm_owner);
++ mutex_unlock(&lmh_lock);
++}
++
++EXPORT_SYMBOL_GPL(gfs2_register_lockproto);
++EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto);
++
+diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile
+new file mode 100644
+index 0000000..89b93b6
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
++lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o
++
+diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
+new file mode 100644
+index 0000000..b167add
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/lock.c
+@@ -0,0 +1,524 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include "lock_dlm.h"
++
++static char junk_lvb[GDLM_LVB_SIZE];
++
++static void queue_complete(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++
++ clear_bit(LFL_ACTIVE, &lp->flags);
++
++ spin_lock(&ls->async_lock);
++ list_add_tail(&lp->clist, &ls->complete);
++ spin_unlock(&ls->async_lock);
++ wake_up(&ls->thread_wait);
++}
++
++static inline void gdlm_ast(void *astarg)
++{
++ queue_complete(astarg);
++}
++
++static inline void gdlm_bast(void *astarg, int mode)
++{
++ struct gdlm_lock *lp = astarg;
++ struct gdlm_ls *ls = lp->ls;
++
++ if (!mode) {
++ printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number);
++ return;
++ }
++
++ spin_lock(&ls->async_lock);
++ if (!lp->bast_mode) {
++ list_add_tail(&lp->blist, &ls->blocking);
++ lp->bast_mode = mode;
++ } else if (lp->bast_mode < mode)
++ lp->bast_mode = mode;
++ spin_unlock(&ls->async_lock);
++ wake_up(&ls->thread_wait);
++}
++
++void gdlm_queue_delayed(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++
++ spin_lock(&ls->async_lock);
++ list_add_tail(&lp->delay_list, &ls->delayed);
++ spin_unlock(&ls->async_lock);
++}
++
++/* convert gfs lock-state to dlm lock-mode */
++
++static s16 make_mode(s16 lmstate)
++{
++ switch (lmstate) {
++ case LM_ST_UNLOCKED:
++ return DLM_LOCK_NL;
++ case LM_ST_EXCLUSIVE:
++ return DLM_LOCK_EX;
++ case LM_ST_DEFERRED:
++ return DLM_LOCK_CW;
++ case LM_ST_SHARED:
++ return DLM_LOCK_PR;
++ }
++ gdlm_assert(0, "unknown LM state %d", lmstate);
++ return -1;
++}
++
++/* convert dlm lock-mode to gfs lock-state */
++
++s16 gdlm_make_lmstate(s16 dlmmode)
++{
++ switch (dlmmode) {
++ case DLM_LOCK_IV:
++ case DLM_LOCK_NL:
++ return LM_ST_UNLOCKED;
++ case DLM_LOCK_EX:
++ return LM_ST_EXCLUSIVE;
++ case DLM_LOCK_CW:
++ return LM_ST_DEFERRED;
++ case DLM_LOCK_PR:
++ return LM_ST_SHARED;
++ }
++ gdlm_assert(0, "unknown DLM mode %d", dlmmode);
++ return -1;
++}
++
++/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and
++ DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */
++
++static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state)
++{
++ s16 cur = make_mode(cur_state);
++ if (lp->cur != DLM_LOCK_IV)
++ gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur);
++}
++
++static inline unsigned int make_flags(struct gdlm_lock *lp,
++ unsigned int gfs_flags,
++ s16 cur, s16 req)
++{
++ unsigned int lkf = 0;
++
++ if (gfs_flags & LM_FLAG_TRY)
++ lkf |= DLM_LKF_NOQUEUE;
++
++ if (gfs_flags & LM_FLAG_TRY_1CB) {
++ lkf |= DLM_LKF_NOQUEUE;
++ lkf |= DLM_LKF_NOQUEUEBAST;
++ }
++
++ if (gfs_flags & LM_FLAG_PRIORITY) {
++ lkf |= DLM_LKF_NOORDER;
++ lkf |= DLM_LKF_HEADQUE;
++ }
++
++ if (gfs_flags & LM_FLAG_ANY) {
++ if (req == DLM_LOCK_PR)
++ lkf |= DLM_LKF_ALTCW;
++ else if (req == DLM_LOCK_CW)
++ lkf |= DLM_LKF_ALTPR;
++ }
++
++ if (lp->lksb.sb_lkid != 0) {
++ lkf |= DLM_LKF_CONVERT;
++
++ /* Conversion deadlock avoidance by DLM */
++
++ if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) &&
++ !(lkf & DLM_LKF_NOQUEUE) &&
++ cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req)
++ lkf |= DLM_LKF_CONVDEADLK;
++ }
++
++ if (lp->lvb)
++ lkf |= DLM_LKF_VALBLK;
++
++ return lkf;
++}
++
++/* make_strname - convert GFS lock numbers to a string */
++
++static inline void make_strname(struct lm_lockname *lockname,
++ struct gdlm_strname *str)
++{
++ sprintf(str->name, "%8x%16llx", lockname->ln_type,
++ (unsigned long long)lockname->ln_number);
++ str->namelen = GDLM_STRNAME_BYTES;
++}
++
++static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
++ struct gdlm_lock **lpp)
++{
++ struct gdlm_lock *lp;
++
++ lp = kzalloc(sizeof(struct gdlm_lock), GFP_KERNEL);
++ if (!lp)
++ return -ENOMEM;
++
++ lp->lockname = *name;
++ lp->ls = ls;
++ lp->cur = DLM_LOCK_IV;
++ lp->lvb = NULL;
++ lp->hold_null = NULL;
++ init_completion(&lp->ast_wait);
++ INIT_LIST_HEAD(&lp->clist);
++ INIT_LIST_HEAD(&lp->blist);
++ INIT_LIST_HEAD(&lp->delay_list);
++
++ spin_lock(&ls->async_lock);
++ list_add(&lp->all_list, &ls->all_locks);
++ ls->all_locks_count++;
++ spin_unlock(&ls->async_lock);
++
++ *lpp = lp;
++ return 0;
++}
++
++void gdlm_delete_lp(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++
++ spin_lock(&ls->async_lock);
++ if (!list_empty(&lp->clist))
++ list_del_init(&lp->clist);
++ if (!list_empty(&lp->blist))
++ list_del_init(&lp->blist);
++ if (!list_empty(&lp->delay_list))
++ list_del_init(&lp->delay_list);
++ gdlm_assert(!list_empty(&lp->all_list), "%x,%llx", lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number);
++ list_del_init(&lp->all_list);
++ ls->all_locks_count--;
++ spin_unlock(&ls->async_lock);
++
++ kfree(lp);
++}
++
++int gdlm_get_lock(void *lockspace, struct lm_lockname *name,
++ void **lockp)
++{
++ struct gdlm_lock *lp;
++ int error;
++
++ error = gdlm_create_lp(lockspace, name, &lp);
++
++ *lockp = lp;
++ return error;
++}
++
++void gdlm_put_lock(void *lock)
++{
++ gdlm_delete_lp(lock);
++}
++
++unsigned int gdlm_do_lock(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++ struct gdlm_strname str;
++ int error, bast = 1;
++
++ /*
++ * When recovery is in progress, delay lock requests for submission
++ * once recovery is done. Requests for recovery (NOEXP) and unlocks
++ * can pass.
++ */
++
++ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
++ !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) {
++ gdlm_queue_delayed(lp);
++ return LM_OUT_ASYNC;
++ }
++
++ /*
++ * Submit the actual lock request.
++ */
++
++ if (test_bit(LFL_NOBAST, &lp->flags))
++ bast = 0;
++
++ make_strname(&lp->lockname, &str);
++
++ set_bit(LFL_ACTIVE, &lp->flags);
++
++ log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid,
++ lp->cur, lp->req, lp->lkf);
++
++ error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
++ str.name, str.namelen, 0, gdlm_ast, lp,
++ bast ? gdlm_bast : NULL);
++
++ if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
++ lp->lksb.sb_status = -EAGAIN;
++ queue_complete(lp);
++ error = 0;
++ }
++
++ if (error) {
++ log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
++ "flags=%lx", ls->fsname, lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number, error,
++ lp->cur, lp->req, lp->lkf, lp->flags);
++ return LM_OUT_ERROR;
++ }
++ return LM_OUT_ASYNC;
++}
++
++static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++ unsigned int lkf = 0;
++ int error;
++
++ set_bit(LFL_DLM_UNLOCK, &lp->flags);
++ set_bit(LFL_ACTIVE, &lp->flags);
++
++ if (lp->lvb)
++ lkf = DLM_LKF_VALBLK;
++
++ log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number,
++ lp->lksb.sb_lkid, lp->cur, lkf);
++
++ error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
++
++ if (error) {
++ log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
++ "flags=%lx", ls->fsname, lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number, error,
++ lp->cur, lp->req, lp->lkf, lp->flags);
++ return LM_OUT_ERROR;
++ }
++ return LM_OUT_ASYNC;
++}
++
++unsigned int gdlm_lock(void *lock, unsigned int cur_state,
++ unsigned int req_state, unsigned int flags)
++{
++ struct gdlm_lock *lp = lock;
++
++ clear_bit(LFL_DLM_CANCEL, &lp->flags);
++ if (flags & LM_FLAG_NOEXP)
++ set_bit(LFL_NOBLOCK, &lp->flags);
++
++ check_cur_state(lp, cur_state);
++ lp->req = make_mode(req_state);
++ lp->lkf = make_flags(lp, flags, lp->cur, lp->req);
++
++ return gdlm_do_lock(lp);
++}
++
++unsigned int gdlm_unlock(void *lock, unsigned int cur_state)
++{
++ struct gdlm_lock *lp = lock;
++
++ clear_bit(LFL_DLM_CANCEL, &lp->flags);
++ if (lp->cur == DLM_LOCK_IV)
++ return 0;
++ return gdlm_do_unlock(lp);
++}
++
++void gdlm_cancel(void *lock)
++{
++ struct gdlm_lock *lp = lock;
++ struct gdlm_ls *ls = lp->ls;
++ int error, delay_list = 0;
++
++ if (test_bit(LFL_DLM_CANCEL, &lp->flags))
++ return;
++
++ log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number, lp->flags);
++
++ spin_lock(&ls->async_lock);
++ if (!list_empty(&lp->delay_list)) {
++ list_del_init(&lp->delay_list);
++ delay_list = 1;
++ }
++ spin_unlock(&ls->async_lock);
++
++ if (delay_list) {
++ set_bit(LFL_CANCEL, &lp->flags);
++ set_bit(LFL_ACTIVE, &lp->flags);
++ queue_complete(lp);
++ return;
++ }
++
++ if (!test_bit(LFL_ACTIVE, &lp->flags) ||
++ test_bit(LFL_DLM_UNLOCK, &lp->flags)) {
++ log_info("gdlm_cancel skip %x,%llx flags %lx",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number, lp->flags);
++ return;
++ }
++
++ /* the lock is blocked in the dlm */
++
++ set_bit(LFL_DLM_CANCEL, &lp->flags);
++ set_bit(LFL_ACTIVE, &lp->flags);
++
++ error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL,
++ NULL, lp);
++
++ log_info("gdlm_cancel rv %d %x,%llx flags %lx", error,
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number, lp->flags);
++
++ if (error == -EBUSY)
++ clear_bit(LFL_DLM_CANCEL, &lp->flags);
++}
++
++static int gdlm_add_lvb(struct gdlm_lock *lp)
++{
++ char *lvb;
++
++ lvb = kzalloc(GDLM_LVB_SIZE, GFP_KERNEL);
++ if (!lvb)
++ return -ENOMEM;
++
++ lp->lksb.sb_lvbptr = lvb;
++ lp->lvb = lvb;
++ return 0;
++}
++
++static void gdlm_del_lvb(struct gdlm_lock *lp)
++{
++ kfree(lp->lvb);
++ lp->lvb = NULL;
++ lp->lksb.sb_lvbptr = NULL;
++}
++
++/* This can do a synchronous dlm request (requiring a lock_dlm thread to get
++ the completion) because gfs won't call hold_lvb() during a callback (from
++ the context of a lock_dlm thread). */
++
++static int hold_null_lock(struct gdlm_lock *lp)
++{
++ struct gdlm_lock *lpn = NULL;
++ int error;
++
++ if (lp->hold_null) {
++ printk(KERN_INFO "lock_dlm: lvb already held\n");
++ return 0;
++ }
++
++ error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn);
++ if (error)
++ goto out;
++
++ lpn->lksb.sb_lvbptr = junk_lvb;
++ lpn->lvb = junk_lvb;
++
++ lpn->req = DLM_LOCK_NL;
++ lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE;
++ set_bit(LFL_NOBAST, &lpn->flags);
++ set_bit(LFL_INLOCK, &lpn->flags);
++
++ init_completion(&lpn->ast_wait);
++ gdlm_do_lock(lpn);
++ wait_for_completion(&lpn->ast_wait);
++ error = lpn->lksb.sb_status;
++ if (error) {
++ printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n",
++ error);
++ gdlm_delete_lp(lpn);
++ lpn = NULL;
++ }
++out:
++ lp->hold_null = lpn;
++ return error;
++}
++
++/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get
++ the completion) because gfs may call unhold_lvb() during a callback (from
++ the context of a lock_dlm thread) which could cause a deadlock since the
++ other lock_dlm thread could be engaged in recovery. */
++
++static void unhold_null_lock(struct gdlm_lock *lp)
++{
++ struct gdlm_lock *lpn = lp->hold_null;
++
++ gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number);
++ lpn->lksb.sb_lvbptr = NULL;
++ lpn->lvb = NULL;
++ set_bit(LFL_UNLOCK_DELETE, &lpn->flags);
++ gdlm_do_unlock(lpn);
++ lp->hold_null = NULL;
++}
++
++/* Acquire a NL lock because gfs requires the value block to remain
++ intact on the resource while the lvb is "held" even if it's holding no locks
++ on the resource. */
++
++int gdlm_hold_lvb(void *lock, char **lvbp)
++{
++ struct gdlm_lock *lp = lock;
++ int error;
++
++ error = gdlm_add_lvb(lp);
++ if (error)
++ return error;
++
++ *lvbp = lp->lvb;
++
++ error = hold_null_lock(lp);
++ if (error)
++ gdlm_del_lvb(lp);
++
++ return error;
++}
++
++void gdlm_unhold_lvb(void *lock, char *lvb)
++{
++ struct gdlm_lock *lp = lock;
++
++ unhold_null_lock(lp);
++ gdlm_del_lvb(lp);
++}
++
++void gdlm_submit_delayed(struct gdlm_ls *ls)
++{
++ struct gdlm_lock *lp, *safe;
++
++ spin_lock(&ls->async_lock);
++ list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) {
++ list_del_init(&lp->delay_list);
++ list_add_tail(&lp->delay_list, &ls->submit);
++ }
++ spin_unlock(&ls->async_lock);
++ wake_up(&ls->thread_wait);
++}
++
++int gdlm_release_all_locks(struct gdlm_ls *ls)
++{
++ struct gdlm_lock *lp, *safe;
++ int count = 0;
++
++ spin_lock(&ls->async_lock);
++ list_for_each_entry_safe(lp, safe, &ls->all_locks, all_list) {
++ list_del_init(&lp->all_list);
++
++ if (lp->lvb && lp->lvb != junk_lvb)
++ kfree(lp->lvb);
++ kfree(lp);
++ count++;
++ }
++ spin_unlock(&ls->async_lock);
++
++ return count;
++}
++
+diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
+new file mode 100644
+index 0000000..33af707
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/lock_dlm.h
+@@ -0,0 +1,187 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef LOCK_DLM_DOT_H
++#define LOCK_DLM_DOT_H
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/list.h>
++#include <linux/socket.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/kobject.h>
++#include <linux/fcntl.h>
++#include <linux/wait.h>
++#include <net/sock.h>
++
++#include <linux/dlm.h>
++#include <linux/lm_interface.h>
++
++/*
++ * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a
++ * prefix of lock_dlm_ gets awkward. Externally, GFS refers to this module
++ * as "lock_dlm".
++ */
++
++#define GDLM_STRNAME_BYTES 24
++#define GDLM_LVB_SIZE 32
++#define GDLM_DROP_COUNT 50000
++#define GDLM_DROP_PERIOD 60
++#define GDLM_NAME_LEN 128
++
++/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number).
++ We sprintf these numbers into a 24 byte string of hex values to make them
++ human-readable (to make debugging simpler.) */
++
++struct gdlm_strname {
++ unsigned char name[GDLM_STRNAME_BYTES];
++ unsigned short namelen;
++};
++
++enum {
++ DFL_BLOCK_LOCKS = 0,
++ DFL_SPECTATOR = 1,
++ DFL_WITHDRAW = 2,
++};
++
++struct gdlm_ls {
++ u32 id;
++ int jid;
++ int first;
++ int first_done;
++ unsigned long flags;
++ struct kobject kobj;
++ char clustername[GDLM_NAME_LEN];
++ char fsname[GDLM_NAME_LEN];
++ int fsflags;
++ dlm_lockspace_t *dlm_lockspace;
++ lm_callback_t fscb;
++ struct gfs2_sbd *sdp;
++ int recover_jid;
++ int recover_jid_done;
++ int recover_jid_status;
++ spinlock_t async_lock;
++ struct list_head complete;
++ struct list_head blocking;
++ struct list_head delayed;
++ struct list_head submit;
++ struct list_head all_locks;
++ u32 all_locks_count;
++ wait_queue_head_t wait_control;
++ struct task_struct *thread1;
++ struct task_struct *thread2;
++ wait_queue_head_t thread_wait;
++ unsigned long drop_time;
++ int drop_locks_count;
++ int drop_locks_period;
++};
++
++enum {
++ LFL_NOBLOCK = 0,
++ LFL_NOCACHE = 1,
++ LFL_DLM_UNLOCK = 2,
++ LFL_DLM_CANCEL = 3,
++ LFL_SYNC_LVB = 4,
++ LFL_FORCE_PROMOTE = 5,
++ LFL_REREQUEST = 6,
++ LFL_ACTIVE = 7,
++ LFL_INLOCK = 8,
++ LFL_CANCEL = 9,
++ LFL_NOBAST = 10,
++ LFL_HEADQUE = 11,
++ LFL_UNLOCK_DELETE = 12,
++};
++
++struct gdlm_lock {
++ struct gdlm_ls *ls;
++ struct lm_lockname lockname;
++ char *lvb;
++ struct dlm_lksb lksb;
++
++ s16 cur;
++ s16 req;
++ s16 prev_req;
++ u32 lkf; /* dlm flags DLM_LKF_ */
++ unsigned long flags; /* lock_dlm flags LFL_ */
++
++ int bast_mode; /* protected by async_lock */
++ struct completion ast_wait;
++
++ struct list_head clist; /* complete */
++ struct list_head blist; /* blocking */
++ struct list_head delay_list; /* delayed */
++ struct list_head all_list; /* all locks for the fs */
++ struct gdlm_lock *hold_null; /* NL lock for hold_lvb */
++};
++
++#define gdlm_assert(assertion, fmt, args...) \
++do { \
++ if (unlikely(!(assertion))) { \
++ printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \
++ "lock_dlm: " fmt "\n", \
++ #assertion, ##args); \
++ BUG(); \
++ } \
++} while (0)
++
++#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg)
++#define log_info(fmt, arg...) log_print(KERN_INFO , fmt , ## arg)
++#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg)
++#ifdef LOCK_DLM_LOG_DEBUG
++#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg)
++#else
++#define log_debug(fmt, arg...)
++#endif
++
++/* sysfs.c */
++
++int gdlm_sysfs_init(void);
++void gdlm_sysfs_exit(void);
++int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *);
++void gdlm_kobject_release(struct gdlm_ls *);
++
++/* thread.c */
++
++int gdlm_init_threads(struct gdlm_ls *);
++void gdlm_release_threads(struct gdlm_ls *);
++
++/* lock.c */
++
++s16 gdlm_make_lmstate(s16);
++void gdlm_queue_delayed(struct gdlm_lock *);
++void gdlm_submit_delayed(struct gdlm_ls *);
++int gdlm_release_all_locks(struct gdlm_ls *);
++void gdlm_delete_lp(struct gdlm_lock *);
++unsigned int gdlm_do_lock(struct gdlm_lock *);
++
++int gdlm_get_lock(void *, struct lm_lockname *, void **);
++void gdlm_put_lock(void *);
++unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int);
++unsigned int gdlm_unlock(void *, unsigned int);
++void gdlm_cancel(void *);
++int gdlm_hold_lvb(void *, char **);
++void gdlm_unhold_lvb(void *, char *);
++
++/* plock.c */
++
++int gdlm_plock_init(void);
++void gdlm_plock_exit(void);
++int gdlm_plock(void *, struct lm_lockname *, struct file *, int,
++ struct file_lock *);
++int gdlm_plock_get(void *, struct lm_lockname *, struct file *,
++ struct file_lock *);
++int gdlm_punlock(void *, struct lm_lockname *, struct file *,
++ struct file_lock *);
++#endif
++
+diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c
+new file mode 100644
+index 0000000..2194b1d
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/main.c
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/init.h>
++
++#include "lock_dlm.h"
++
++extern int gdlm_drop_count;
++extern int gdlm_drop_period;
++
++extern struct lm_lockops gdlm_ops;
++
++static int __init init_lock_dlm(void)
++{
++ int error;
++
++ error = gfs2_register_lockproto(&gdlm_ops);
++ if (error) {
++ printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n",
++ error);
++ return error;
++ }
++
++ error = gdlm_sysfs_init();
++ if (error) {
++ gfs2_unregister_lockproto(&gdlm_ops);
++ return error;
++ }
++
++ error = gdlm_plock_init();
++ if (error) {
++ gdlm_sysfs_exit();
++ gfs2_unregister_lockproto(&gdlm_ops);
++ return error;
++ }
++
++ gdlm_drop_count = GDLM_DROP_COUNT;
++ gdlm_drop_period = GDLM_DROP_PERIOD;
++
++ printk(KERN_INFO
++ "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
++ return 0;
++}
++
++static void __exit exit_lock_dlm(void)
++{
++ gdlm_plock_exit();
++ gdlm_sysfs_exit();
++ gfs2_unregister_lockproto(&gdlm_ops);
++}
++
++module_init(init_lock_dlm);
++module_exit(exit_lock_dlm);
++
++MODULE_DESCRIPTION("GFS DLM Locking Module");
++MODULE_AUTHOR("Red Hat, Inc.");
++MODULE_LICENSE("GPL");
++
+diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
+new file mode 100644
+index 0000000..cdd1694
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/mount.c
+@@ -0,0 +1,255 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include "lock_dlm.h"
++
++int gdlm_drop_count;
++int gdlm_drop_period;
++const struct lm_lockops gdlm_ops;
++
++
++static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
++ int flags, char *table_name)
++{
++ struct gdlm_ls *ls;
++ char buf[256], *p;
++
++ ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
++ if (!ls)
++ return NULL;
++
++ ls->drop_locks_count = gdlm_drop_count;
++ ls->drop_locks_period = gdlm_drop_period;
++ ls->fscb = cb;
++ ls->sdp = sdp;
++ ls->fsflags = flags;
++ spin_lock_init(&ls->async_lock);
++ INIT_LIST_HEAD(&ls->complete);
++ INIT_LIST_HEAD(&ls->blocking);
++ INIT_LIST_HEAD(&ls->delayed);
++ INIT_LIST_HEAD(&ls->submit);
++ INIT_LIST_HEAD(&ls->all_locks);
++ init_waitqueue_head(&ls->thread_wait);
++ init_waitqueue_head(&ls->wait_control);
++ ls->thread1 = NULL;
++ ls->thread2 = NULL;
++ ls->drop_time = jiffies;
++ ls->jid = -1;
++
++ strncpy(buf, table_name, 256);
++ buf[255] = '\0';
++
++ p = strchr(buf, ':');
++ if (!p) {
++ log_info("invalid table_name \"%s\"", table_name);
++ kfree(ls);
++ return NULL;
++ }
++ *p = '\0';
++ p++;
++
++ strncpy(ls->clustername, buf, GDLM_NAME_LEN);
++ strncpy(ls->fsname, p, GDLM_NAME_LEN);
++
++ return ls;
++}
++
++static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
++{
++ char data[256];
++ char *options, *x, *y;
++ int error = 0;
++
++ memset(data, 0, 256);
++ strncpy(data, data_arg, 255);
++
++ for (options = data; (x = strsep(&options, ":")); ) {
++ if (!*x)
++ continue;
++
++ y = strchr(x, '=');
++ if (y)
++ *y++ = 0;
++
++ if (!strcmp(x, "jid")) {
++ if (!y) {
++ log_error("need argument to jid");
++ error = -EINVAL;
++ break;
++ }
++ sscanf(y, "%u", &ls->jid);
++
++ } else if (!strcmp(x, "first")) {
++ if (!y) {
++ log_error("need argument to first");
++ error = -EINVAL;
++ break;
++ }
++ sscanf(y, "%u", &ls->first);
++
++ } else if (!strcmp(x, "id")) {
++ if (!y) {
++ log_error("need argument to id");
++ error = -EINVAL;
++ break;
++ }
++ sscanf(y, "%u", &ls->id);
++
++ } else if (!strcmp(x, "nodir")) {
++ if (!y) {
++ log_error("need argument to nodir");
++ error = -EINVAL;
++ break;
++ }
++ sscanf(y, "%u", nodir);
++
++ } else {
++ log_error("unkonwn option: %s", x);
++ error = -EINVAL;
++ break;
++ }
++ }
++
++ return error;
++}
++
++static int gdlm_mount(char *table_name, char *host_data,
++ lm_callback_t cb, void *cb_data,
++ unsigned int min_lvb_size, int flags,
++ struct lm_lockstruct *lockstruct,
++ struct kobject *fskobj)
++{
++ struct gdlm_ls *ls;
++ int error = -ENOMEM, nodir = 0;
++
++ if (min_lvb_size > GDLM_LVB_SIZE)
++ goto out;
++
++ ls = init_gdlm(cb, cb_data, flags, table_name);
++ if (!ls)
++ goto out;
++
++ error = make_args(ls, host_data, &nodir);
++ if (error)
++ goto out;
++
++ error = gdlm_init_threads(ls);
++ if (error)
++ goto out_free;
++
++ error = gdlm_kobject_setup(ls, fskobj);
++ if (error)
++ goto out_thread;
++
++ error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
++ &ls->dlm_lockspace,
++ nodir ? DLM_LSFL_NODIR : 0,
++ GDLM_LVB_SIZE);
++ if (error) {
++ log_error("dlm_new_lockspace error %d", error);
++ goto out_kobj;
++ }
++
++ lockstruct->ls_jid = ls->jid;
++ lockstruct->ls_first = ls->first;
++ lockstruct->ls_lockspace = ls;
++ lockstruct->ls_ops = &gdlm_ops;
++ lockstruct->ls_flags = 0;
++ lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
++ return 0;
++
++out_kobj:
++ gdlm_kobject_release(ls);
++out_thread:
++ gdlm_release_threads(ls);
++out_free:
++ kfree(ls);
++out:
++ return error;
++}
++
++static void gdlm_unmount(void *lockspace)
++{
++ struct gdlm_ls *ls = lockspace;
++ int rv;
++
++ log_debug("unmount flags %lx", ls->flags);
++
++ /* FIXME: serialize unmount and withdraw in case they
++ happen at once. Also, if unmount follows withdraw,
++ wait for withdraw to finish. */
++
++ if (test_bit(DFL_WITHDRAW, &ls->flags))
++ goto out;
++
++ gdlm_kobject_release(ls);
++ dlm_release_lockspace(ls->dlm_lockspace, 2);
++ gdlm_release_threads(ls);
++ rv = gdlm_release_all_locks(ls);
++ if (rv)
++ log_info("gdlm_unmount: %d stray locks freed", rv);
++out:
++ kfree(ls);
++}
++
++static void gdlm_recovery_done(void *lockspace, unsigned int jid,
++ unsigned int message)
++{
++ struct gdlm_ls *ls = lockspace;
++ ls->recover_jid_done = jid;
++ ls->recover_jid_status = message;
++ kobject_uevent(&ls->kobj, KOBJ_CHANGE);
++}
++
++static void gdlm_others_may_mount(void *lockspace)
++{
++ struct gdlm_ls *ls = lockspace;
++ ls->first_done = 1;
++ kobject_uevent(&ls->kobj, KOBJ_CHANGE);
++}
++
++/* Userspace gets the offline uevent, blocks new gfs locks on
++ other mounters, and lets us know (sets WITHDRAW flag). Then,
++ userspace leaves the mount group while we leave the lockspace. */
++
++static void gdlm_withdraw(void *lockspace)
++{
++ struct gdlm_ls *ls = lockspace;
++
++ kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
++
++ wait_event_interruptible(ls->wait_control,
++ test_bit(DFL_WITHDRAW, &ls->flags));
++
++ dlm_release_lockspace(ls->dlm_lockspace, 2);
++ gdlm_release_threads(ls);
++ gdlm_release_all_locks(ls);
++ gdlm_kobject_release(ls);
++}
++
++const struct lm_lockops gdlm_ops = {
++ .lm_proto_name = "lock_dlm",
++ .lm_mount = gdlm_mount,
++ .lm_others_may_mount = gdlm_others_may_mount,
++ .lm_unmount = gdlm_unmount,
++ .lm_withdraw = gdlm_withdraw,
++ .lm_get_lock = gdlm_get_lock,
++ .lm_put_lock = gdlm_put_lock,
++ .lm_lock = gdlm_lock,
++ .lm_unlock = gdlm_unlock,
++ .lm_plock = gdlm_plock,
++ .lm_punlock = gdlm_punlock,
++ .lm_plock_get = gdlm_plock_get,
++ .lm_cancel = gdlm_cancel,
++ .lm_hold_lvb = gdlm_hold_lvb,
++ .lm_unhold_lvb = gdlm_unhold_lvb,
++ .lm_recovery_done = gdlm_recovery_done,
++ .lm_owner = THIS_MODULE,
++};
++
+diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
+new file mode 100644
+index 0000000..7365aec
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/plock.c
+@@ -0,0 +1,301 @@
++/*
++ * Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/miscdevice.h>
++#include <linux/lock_dlm_plock.h>
++
++#include "lock_dlm.h"
++
++
++static spinlock_t ops_lock;
++static struct list_head send_list;
++static struct list_head recv_list;
++static wait_queue_head_t send_wq;
++static wait_queue_head_t recv_wq;
++
++struct plock_op {
++ struct list_head list;
++ int done;
++ struct gdlm_plock_info info;
++};
++
++static inline void set_version(struct gdlm_plock_info *info)
++{
++ info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
++ info->version[1] = GDLM_PLOCK_VERSION_MINOR;
++ info->version[2] = GDLM_PLOCK_VERSION_PATCH;
++}
++
++static int check_version(struct gdlm_plock_info *info)
++{
++ if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
++ (GDLM_PLOCK_VERSION_MINOR < info->version[1])) {
++ log_error("plock device version mismatch: "
++ "kernel (%u.%u.%u), user (%u.%u.%u)",
++ GDLM_PLOCK_VERSION_MAJOR,
++ GDLM_PLOCK_VERSION_MINOR,
++ GDLM_PLOCK_VERSION_PATCH,
++ info->version[0],
++ info->version[1],
++ info->version[2]);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static void send_op(struct plock_op *op)
++{
++ set_version(&op->info);
++ INIT_LIST_HEAD(&op->list);
++ spin_lock(&ops_lock);
++ list_add_tail(&op->list, &send_list);
++ spin_unlock(&ops_lock);
++ wake_up(&send_wq);
++}
++
++int gdlm_plock(void *lockspace, struct lm_lockname *name,
++ struct file *file, int cmd, struct file_lock *fl)
++{
++ struct gdlm_ls *ls = lockspace;
++ struct plock_op *op;
++ int rv;
++
++ op = kzalloc(sizeof(*op), GFP_KERNEL);
++ if (!op)
++ return -ENOMEM;
++
++ op->info.optype = GDLM_PLOCK_OP_LOCK;
++ op->info.pid = fl->fl_pid;
++ op->info.ex = (fl->fl_type == F_WRLCK);
++ op->info.wait = IS_SETLKW(cmd);
++ op->info.fsid = ls->id;
++ op->info.number = name->ln_number;
++ op->info.start = fl->fl_start;
++ op->info.end = fl->fl_end;
++ op->info.owner = (__u64)(long) fl->fl_owner;
++
++ send_op(op);
++ wait_event(recv_wq, (op->done != 0));
++
++ spin_lock(&ops_lock);
++ if (!list_empty(&op->list)) {
++ printk(KERN_INFO "plock op on list\n");
++ list_del(&op->list);
++ }
++ spin_unlock(&ops_lock);
++
++ rv = op->info.rv;
++
++ if (!rv) {
++ if (posix_lock_file_wait(file, fl) < 0)
++ log_error("gdlm_plock: vfs lock error %x,%llx",
++ name->ln_type,
++ (unsigned long long)name->ln_number);
++ }
++
++ kfree(op);
++ return rv;
++}
++
++int gdlm_punlock(void *lockspace, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl)
++{
++ struct gdlm_ls *ls = lockspace;
++ struct plock_op *op;
++ int rv;
++
++ op = kzalloc(sizeof(*op), GFP_KERNEL);
++ if (!op)
++ return -ENOMEM;
++
++ if (posix_lock_file_wait(file, fl) < 0)
++ log_error("gdlm_punlock: vfs unlock error %x,%llx",
++ name->ln_type, (unsigned long long)name->ln_number);
++
++ op->info.optype = GDLM_PLOCK_OP_UNLOCK;
++ op->info.pid = fl->fl_pid;
++ op->info.fsid = ls->id;
++ op->info.number = name->ln_number;
++ op->info.start = fl->fl_start;
++ op->info.end = fl->fl_end;
++ op->info.owner = (__u64)(long) fl->fl_owner;
++
++ send_op(op);
++ wait_event(recv_wq, (op->done != 0));
++
++ spin_lock(&ops_lock);
++ if (!list_empty(&op->list)) {
++ printk(KERN_INFO "punlock op on list\n");
++ list_del(&op->list);
++ }
++ spin_unlock(&ops_lock);
++
++ rv = op->info.rv;
++
++ kfree(op);
++ return rv;
++}
++
++int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl)
++{
++ struct gdlm_ls *ls = lockspace;
++ struct plock_op *op;
++ int rv;
++
++ op = kzalloc(sizeof(*op), GFP_KERNEL);
++ if (!op)
++ return -ENOMEM;
++
++ op->info.optype = GDLM_PLOCK_OP_GET;
++ op->info.pid = fl->fl_pid;
++ op->info.ex = (fl->fl_type == F_WRLCK);
++ op->info.fsid = ls->id;
++ op->info.number = name->ln_number;
++ op->info.start = fl->fl_start;
++ op->info.end = fl->fl_end;
++
++ send_op(op);
++ wait_event(recv_wq, (op->done != 0));
++
++ spin_lock(&ops_lock);
++ if (!list_empty(&op->list)) {
++ printk(KERN_INFO "plock_get op on list\n");
++ list_del(&op->list);
++ }
++ spin_unlock(&ops_lock);
++
++ rv = op->info.rv;
++
++ if (rv == 0)
++ fl->fl_type = F_UNLCK;
++ else if (rv > 0) {
++ fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
++ fl->fl_pid = op->info.pid;
++ fl->fl_start = op->info.start;
++ fl->fl_end = op->info.end;
++ }
++
++ kfree(op);
++ return rv;
++}
++
++/* a read copies out one plock request from the send list */
++static ssize_t dev_read(struct file *file, char __user *u, size_t count,
++ loff_t *ppos)
++{
++ struct gdlm_plock_info info;
++ struct plock_op *op = NULL;
++
++ if (count < sizeof(info))
++ return -EINVAL;
++
++ spin_lock(&ops_lock);
++ if (!list_empty(&send_list)) {
++ op = list_entry(send_list.next, struct plock_op, list);
++ list_move(&op->list, &recv_list);
++ memcpy(&info, &op->info, sizeof(info));
++ }
++ spin_unlock(&ops_lock);
++
++ if (!op)
++ return -EAGAIN;
++
++ if (copy_to_user(u, &info, sizeof(info)))
++ return -EFAULT;
++ return sizeof(info);
++}
++
++/* a write copies in one plock result that should match a plock_op
++ on the recv list */
++static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
++ loff_t *ppos)
++{
++ struct gdlm_plock_info info;
++ struct plock_op *op;
++ int found = 0;
++
++ if (count != sizeof(info))
++ return -EINVAL;
++
++ if (copy_from_user(&info, u, sizeof(info)))
++ return -EFAULT;
++
++ if (check_version(&info))
++ return -EINVAL;
++
++ spin_lock(&ops_lock);
++ list_for_each_entry(op, &recv_list, list) {
++ if (op->info.fsid == info.fsid && op->info.number == info.number &&
++ op->info.owner == info.owner) {
++ list_del_init(&op->list);
++ found = 1;
++ op->done = 1;
++ memcpy(&op->info, &info, sizeof(info));
++ break;
++ }
++ }
++ spin_unlock(&ops_lock);
++
++ if (found)
++ wake_up(&recv_wq);
++ else
++ printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
++ (unsigned long long)info.number);
++ return count;
++}
++
++static unsigned int dev_poll(struct file *file, poll_table *wait)
++{
++ poll_wait(file, &send_wq, wait);
++
++ spin_lock(&ops_lock);
++ if (!list_empty(&send_list)) {
++ spin_unlock(&ops_lock);
++ return POLLIN | POLLRDNORM;
++ }
++ spin_unlock(&ops_lock);
++ return 0;
++}
++
++static struct file_operations dev_fops = {
++ .read = dev_read,
++ .write = dev_write,
++ .poll = dev_poll,
++ .owner = THIS_MODULE
++};
++
++static struct miscdevice plock_dev_misc = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = GDLM_PLOCK_MISC_NAME,
++ .fops = &dev_fops
++};
++
++int gdlm_plock_init(void)
++{
++ int rv;
++
++ spin_lock_init(&ops_lock);
++ INIT_LIST_HEAD(&send_list);
++ INIT_LIST_HEAD(&recv_list);
++ init_waitqueue_head(&send_wq);
++ init_waitqueue_head(&recv_wq);
++
++ rv = misc_register(&plock_dev_misc);
++ if (rv)
++ printk(KERN_INFO "gdlm_plock_init: misc_register failed %d",
++ rv);
++ return rv;
++}
++
++void gdlm_plock_exit(void)
++{
++ if (misc_deregister(&plock_dev_misc) < 0)
++ printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed");
++}
++
+diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
+new file mode 100644
+index 0000000..29ae06f
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/sysfs.c
+@@ -0,0 +1,226 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/ctype.h>
++#include <linux/stat.h>
++
++#include "lock_dlm.h"
++
++extern struct lm_lockops gdlm_ops;
++
++static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name);
++}
++
++static ssize_t block_show(struct gdlm_ls *ls, char *buf)
++{
++ ssize_t ret;
++ int val = 0;
++
++ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags))
++ val = 1;
++ ret = sprintf(buf, "%d\n", val);
++ return ret;
++}
++
++static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len)
++{
++ ssize_t ret = len;
++ int val;
++
++ val = simple_strtol(buf, NULL, 0);
++
++ if (val == 1)
++ set_bit(DFL_BLOCK_LOCKS, &ls->flags);
++ else if (val == 0) {
++ clear_bit(DFL_BLOCK_LOCKS, &ls->flags);
++ gdlm_submit_delayed(ls);
++ } else {
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf)
++{
++ ssize_t ret;
++ int val = 0;
++
++ if (test_bit(DFL_WITHDRAW, &ls->flags))
++ val = 1;
++ ret = sprintf(buf, "%d\n", val);
++ return ret;
++}
++
++static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len)
++{
++ ssize_t ret = len;
++ int val;
++
++ val = simple_strtol(buf, NULL, 0);
++
++ if (val == 1)
++ set_bit(DFL_WITHDRAW, &ls->flags);
++ else
++ ret = -EINVAL;
++ wake_up(&ls->wait_control);
++ return ret;
++}
++
++static ssize_t id_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%u\n", ls->id);
++}
++
++static ssize_t jid_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%d\n", ls->jid);
++}
++
++static ssize_t first_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%d\n", ls->first);
++}
++
++static ssize_t first_done_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%d\n", ls->first_done);
++}
++
++static ssize_t recover_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%d\n", ls->recover_jid);
++}
++
++static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len)
++{
++ ls->recover_jid = simple_strtol(buf, NULL, 0);
++ ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid);
++ return len;
++}
++
++static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%d\n", ls->recover_jid_done);
++}
++
++static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf)
++{
++ return sprintf(buf, "%d\n", ls->recover_jid_status);
++}
++
++struct gdlm_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct gdlm_ls *, char *);
++ ssize_t (*store)(struct gdlm_ls *, const char *, size_t);
++};
++
++#define GDLM_ATTR(_name,_mode,_show,_store) \
++static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
++
++GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
++GDLM_ATTR(block, 0644, block_show, block_store);
++GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
++GDLM_ATTR(id, 0444, id_show, NULL);
++GDLM_ATTR(jid, 0444, jid_show, NULL);
++GDLM_ATTR(first, 0444, first_show, NULL);
++GDLM_ATTR(first_done, 0444, first_done_show, NULL);
++GDLM_ATTR(recover, 0644, recover_show, recover_store);
++GDLM_ATTR(recover_done, 0444, recover_done_show, NULL);
++GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
++
++static struct attribute *gdlm_attrs[] = {
++ &gdlm_attr_proto_name.attr,
++ &gdlm_attr_block.attr,
++ &gdlm_attr_withdraw.attr,
++ &gdlm_attr_id.attr,
++ &gdlm_attr_jid.attr,
++ &gdlm_attr_first.attr,
++ &gdlm_attr_first_done.attr,
++ &gdlm_attr_recover.attr,
++ &gdlm_attr_recover_done.attr,
++ &gdlm_attr_recover_status.attr,
++ NULL,
++};
++
++static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
++ struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
++ return a->show ? a->show(ls, buf) : 0;
++}
++
++static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr,
++ const char *buf, size_t len)
++{
++ struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
++ struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
++ return a->store ? a->store(ls, buf, len) : len;
++}
++
++static struct sysfs_ops gdlm_attr_ops = {
++ .show = gdlm_attr_show,
++ .store = gdlm_attr_store,
++};
++
++static struct kobj_type gdlm_ktype = {
++ .default_attrs = gdlm_attrs,
++ .sysfs_ops = &gdlm_attr_ops,
++};
++
++static struct kset gdlm_kset = {
++ .subsys = &kernel_subsys,
++ .kobj = {.name = "lock_dlm",},
++ .ktype = &gdlm_ktype,
++};
++
++int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
++{
++ int error;
++
++ error = kobject_set_name(&ls->kobj, "%s", "lock_module");
++ if (error) {
++ log_error("can't set kobj name %d", error);
++ return error;
++ }
++
++ ls->kobj.kset = &gdlm_kset;
++ ls->kobj.ktype = &gdlm_ktype;
++ ls->kobj.parent = fskobj;
++
++ error = kobject_register(&ls->kobj);
++ if (error)
++ log_error("can't register kobj %d", error);
++
++ return error;
++}
++
++void gdlm_kobject_release(struct gdlm_ls *ls)
++{
++ kobject_unregister(&ls->kobj);
++}
++
++int gdlm_sysfs_init(void)
++{
++ int error;
++
++ error = kset_register(&gdlm_kset);
++ if (error)
++ printk("lock_dlm: cannot register kset %d\n", error);
++
++ return error;
++}
++
++void gdlm_sysfs_exit(void)
++{
++ kset_unregister(&gdlm_kset);
++}
++
+diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
+new file mode 100644
+index 0000000..9cf1f16
+--- /dev/null
++++ b/fs/gfs2/locking/dlm/thread.c
+@@ -0,0 +1,359 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include "lock_dlm.h"
++
++/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm
++ thread gets to it. */
++
++static void queue_submit(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++
++ spin_lock(&ls->async_lock);
++ list_add_tail(&lp->delay_list, &ls->submit);
++ spin_unlock(&ls->async_lock);
++ wake_up(&ls->thread_wait);
++}
++
++static void process_blocking(struct gdlm_lock *lp, int bast_mode)
++{
++ struct gdlm_ls *ls = lp->ls;
++ unsigned int cb = 0;
++
++ switch (gdlm_make_lmstate(bast_mode)) {
++ case LM_ST_EXCLUSIVE:
++ cb = LM_CB_NEED_E;
++ break;
++ case LM_ST_DEFERRED:
++ cb = LM_CB_NEED_D;
++ break;
++ case LM_ST_SHARED:
++ cb = LM_CB_NEED_S;
++ break;
++ default:
++ gdlm_assert(0, "unknown bast mode %u", lp->bast_mode);
++ }
++
++ ls->fscb(ls->sdp, cb, &lp->lockname);
++}
++
++static void process_complete(struct gdlm_lock *lp)
++{
++ struct gdlm_ls *ls = lp->ls;
++ struct lm_async_cb acb;
++ s16 prev_mode = lp->cur;
++
++ memset(&acb, 0, sizeof(acb));
++
++ if (lp->lksb.sb_status == -DLM_ECANCEL) {
++ log_info("complete dlm cancel %x,%llx flags %lx",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number,
++ lp->flags);
++
++ lp->req = lp->cur;
++ acb.lc_ret |= LM_OUT_CANCELED;
++ if (lp->cur == DLM_LOCK_IV)
++ lp->lksb.sb_lkid = 0;
++ goto out;
++ }
++
++ if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) {
++ if (lp->lksb.sb_status != -DLM_EUNLOCK) {
++ log_info("unlock sb_status %d %x,%llx flags %lx",
++ lp->lksb.sb_status, lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number,
++ lp->flags);
++ return;
++ }
++
++ lp->cur = DLM_LOCK_IV;
++ lp->req = DLM_LOCK_IV;
++ lp->lksb.sb_lkid = 0;
++
++ if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) {
++ gdlm_delete_lp(lp);
++ return;
++ }
++ goto out;
++ }
++
++ if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID)
++ memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE);
++
++ if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) {
++ if (lp->req == DLM_LOCK_PR)
++ lp->req = DLM_LOCK_CW;
++ else if (lp->req == DLM_LOCK_CW)
++ lp->req = DLM_LOCK_PR;
++ }
++
++ /*
++ * A canceled lock request. The lock was just taken off the delayed
++ * list and was never even submitted to dlm.
++ */
++
++ if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) {
++ log_info("complete internal cancel %x,%llx",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number);
++ lp->req = lp->cur;
++ acb.lc_ret |= LM_OUT_CANCELED;
++ goto out;
++ }
++
++ /*
++ * An error occured.
++ */
++
++ if (lp->lksb.sb_status) {
++ /* a "normal" error */
++ if ((lp->lksb.sb_status == -EAGAIN) &&
++ (lp->lkf & DLM_LKF_NOQUEUE)) {
++ lp->req = lp->cur;
++ if (lp->cur == DLM_LOCK_IV)
++ lp->lksb.sb_lkid = 0;
++ goto out;
++ }
++
++ /* this could only happen with cancels I think */
++ log_info("ast sb_status %d %x,%llx flags %lx",
++ lp->lksb.sb_status, lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number,
++ lp->flags);
++ return;
++ }
++
++ /*
++ * This is an AST for an EX->EX conversion for sync_lvb from GFS.
++ */
++
++ if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) {
++ complete(&lp->ast_wait);
++ return;
++ }
++
++ /*
++ * A lock has been demoted to NL because it initially completed during
++ * BLOCK_LOCKS. Now it must be requested in the originally requested
++ * mode.
++ */
++
++ if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) {
++ gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number);
++ gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number);
++
++ lp->cur = DLM_LOCK_NL;
++ lp->req = lp->prev_req;
++ lp->prev_req = DLM_LOCK_IV;
++ lp->lkf &= ~DLM_LKF_CONVDEADLK;
++
++ set_bit(LFL_NOCACHE, &lp->flags);
++
++ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
++ !test_bit(LFL_NOBLOCK, &lp->flags))
++ gdlm_queue_delayed(lp);
++ else
++ queue_submit(lp);
++ return;
++ }
++
++ /*
++ * A request is granted during dlm recovery. It may be granted
++ * because the locks of a failed node were cleared. In that case,
++ * there may be inconsistent data beneath this lock and we must wait
++ * for recovery to complete to use it. When gfs recovery is done this
++ * granted lock will be converted to NL and then reacquired in this
++ * granted state.
++ */
++
++ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
++ !test_bit(LFL_NOBLOCK, &lp->flags) &&
++ lp->req != DLM_LOCK_NL) {
++
++ lp->cur = lp->req;
++ lp->prev_req = lp->req;
++ lp->req = DLM_LOCK_NL;
++ lp->lkf |= DLM_LKF_CONVERT;
++ lp->lkf &= ~DLM_LKF_CONVDEADLK;
++
++ log_debug("rereq %x,%llx id %x %d,%d",
++ lp->lockname.ln_type,
++ (unsigned long long)lp->lockname.ln_number,
++ lp->lksb.sb_lkid, lp->cur, lp->req);
++
++ set_bit(LFL_REREQUEST, &lp->flags);
++ queue_submit(lp);
++ return;
++ }
++
++ /*
++ * DLM demoted the lock to NL before it was granted so GFS must be
++ * told it cannot cache data for this lock.
++ */
++
++ if (lp->lksb.sb_flags & DLM_SBF_DEMOTED)
++ set_bit(LFL_NOCACHE, &lp->flags);
++
++out:
++ /*
++ * This is an internal lock_dlm lock
++ */
++
++ if (test_bit(LFL_INLOCK, &lp->flags)) {
++ clear_bit(LFL_NOBLOCK, &lp->flags);
++ lp->cur = lp->req;
++ complete(&lp->ast_wait);
++ return;
++ }
++
++ /*
++ * Normal completion of a lock request. Tell GFS it now has the lock.
++ */
++
++ clear_bit(LFL_NOBLOCK, &lp->flags);
++ lp->cur = lp->req;
++
++ acb.lc_name = lp->lockname;
++ acb.lc_ret |= gdlm_make_lmstate(lp->cur);
++
++ if (!test_and_clear_bit(LFL_NOCACHE, &lp->flags) &&
++ (lp->cur > DLM_LOCK_NL) && (prev_mode > DLM_LOCK_NL))
++ acb.lc_ret |= LM_OUT_CACHEABLE;
++
++ ls->fscb(ls->sdp, LM_CB_ASYNC, &acb);
++}
++
++static inline int no_work(struct gdlm_ls *ls, int blocking)
++{
++ int ret;
++
++ spin_lock(&ls->async_lock);
++ ret = list_empty(&ls->complete) && list_empty(&ls->submit);
++ if (ret && blocking)
++ ret = list_empty(&ls->blocking);
++ spin_unlock(&ls->async_lock);
++
++ return ret;
++}
++
++static inline int check_drop(struct gdlm_ls *ls)
++{
++ if (!ls->drop_locks_count)
++ return 0;
++
++ if (time_after(jiffies, ls->drop_time + ls->drop_locks_period * HZ)) {
++ ls->drop_time = jiffies;
++ if (ls->all_locks_count >= ls->drop_locks_count)
++ return 1;
++ }
++ return 0;
++}
++
++static int gdlm_thread(void *data)
++{
++ struct gdlm_ls *ls = (struct gdlm_ls *) data;
++ struct gdlm_lock *lp = NULL;
++ int blist = 0;
++ uint8_t complete, blocking, submit, drop;
++ DECLARE_WAITQUEUE(wait, current);
++
++ /* Only thread1 is allowed to do blocking callbacks since gfs
++ may wait for a completion callback within a blocking cb. */
++
++ if (current == ls->thread1)
++ blist = 1;
++
++ while (!kthread_should_stop()) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&ls->thread_wait, &wait);
++ if (no_work(ls, blist))
++ schedule();
++ remove_wait_queue(&ls->thread_wait, &wait);
++ set_current_state(TASK_RUNNING);
++
++ complete = blocking = submit = drop = 0;
++
++ spin_lock(&ls->async_lock);
++
++ if (blist && !list_empty(&ls->blocking)) {
++ lp = list_entry(ls->blocking.next, struct gdlm_lock,
++ blist);
++ list_del_init(&lp->blist);
++ blocking = lp->bast_mode;
++ lp->bast_mode = 0;
++ } else if (!list_empty(&ls->complete)) {
++ lp = list_entry(ls->complete.next, struct gdlm_lock,
++ clist);
++ list_del_init(&lp->clist);
++ complete = 1;
++ } else if (!list_empty(&ls->submit)) {
++ lp = list_entry(ls->submit.next, struct gdlm_lock,
++ delay_list);
++ list_del_init(&lp->delay_list);
++ submit = 1;
++ }
++
++ drop = check_drop(ls);
++ spin_unlock(&ls->async_lock);
++
++ if (complete)
++ process_complete(lp);
++
++ else if (blocking)
++ process_blocking(lp, blocking);
++
++ else if (submit)
++ gdlm_do_lock(lp);
++
++ if (drop)
++ ls->fscb(ls->sdp, LM_CB_DROPLOCKS, NULL);
++
++ schedule();
++ }
++
++ return 0;
++}
++
++int gdlm_init_threads(struct gdlm_ls *ls)
++{
++ struct task_struct *p;
++ int error;
++
++ p = kthread_run(gdlm_thread, ls, "lock_dlm1");
++ error = IS_ERR(p);
++ if (error) {
++ log_error("can't start lock_dlm1 thread %d", error);
++ return error;
++ }
++ ls->thread1 = p;
++
++ p = kthread_run(gdlm_thread, ls, "lock_dlm2");
++ error = IS_ERR(p);
++ if (error) {
++ log_error("can't start lock_dlm2 thread %d", error);
++ kthread_stop(ls->thread1);
++ return error;
++ }
++ ls->thread2 = p;
++
++ return 0;
++}
++
++void gdlm_release_threads(struct gdlm_ls *ls)
++{
++ kthread_stop(ls->thread1);
++ kthread_stop(ls->thread2);
++}
++
+diff --git a/fs/gfs2/locking/nolock/Makefile b/fs/gfs2/locking/nolock/Makefile
+new file mode 100644
+index 0000000..35e9730
+--- /dev/null
++++ b/fs/gfs2/locking/nolock/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += lock_nolock.o
++lock_nolock-y := main.o
++
+diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
+new file mode 100644
+index 0000000..acfbc94
+--- /dev/null
++++ b/fs/gfs2/locking/nolock/main.c
+@@ -0,0 +1,246 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/lm_interface.h>
++
++struct nolock_lockspace {
++ unsigned int nl_lvb_size;
++};
++
++static const struct lm_lockops nolock_ops;
++
++static int nolock_mount(char *table_name, char *host_data,
++ lm_callback_t cb, void *cb_data,
++ unsigned int min_lvb_size, int flags,
++ struct lm_lockstruct *lockstruct,
++ struct kobject *fskobj)
++{
++ char *c;
++ unsigned int jid;
++ struct nolock_lockspace *nl;
++
++ c = strstr(host_data, "jid=");
++ if (!c)
++ jid = 0;
++ else {
++ c += 4;
++ sscanf(c, "%u", &jid);
++ }
++
++ nl = kzalloc(sizeof(struct nolock_lockspace), GFP_KERNEL);
++ if (!nl)
++ return -ENOMEM;
++
++ nl->nl_lvb_size = min_lvb_size;
++
++ lockstruct->ls_jid = jid;
++ lockstruct->ls_first = 1;
++ lockstruct->ls_lvb_size = min_lvb_size;
++ lockstruct->ls_lockspace = nl;
++ lockstruct->ls_ops = &nolock_ops;
++ lockstruct->ls_flags = LM_LSFLAG_LOCAL;
++
++ return 0;
++}
++
++static void nolock_others_may_mount(void *lockspace)
++{
++}
++
++static void nolock_unmount(void *lockspace)
++{
++ struct nolock_lockspace *nl = lockspace;
++ kfree(nl);
++}
++
++static void nolock_withdraw(void *lockspace)
++{
++}
++
++/**
++ * nolock_get_lock - get a lm_lock_t given a descripton of the lock
++ * @lockspace: the lockspace the lock lives in
++ * @name: the name of the lock
++ * @lockp: return the lm_lock_t here
++ *
++ * Returns: 0 on success, -EXXX on failure
++ */
++
++static int nolock_get_lock(void *lockspace, struct lm_lockname *name,
++ void **lockp)
++{
++ *lockp = lockspace;
++ return 0;
++}
++
++/**
++ * nolock_put_lock - get rid of a lock structure
++ * @lock: the lock to throw away
++ *
++ */
++
++static void nolock_put_lock(void *lock)
++{
++}
++
++/**
++ * nolock_lock - acquire a lock
++ * @lock: the lock to manipulate
++ * @cur_state: the current state
++ * @req_state: the requested state
++ * @flags: modifier flags
++ *
++ * Returns: A bitmap of LM_OUT_*
++ */
++
++static unsigned int nolock_lock(void *lock, unsigned int cur_state,
++ unsigned int req_state, unsigned int flags)
++{
++ return req_state | LM_OUT_CACHEABLE;
++}
++
++/**
++ * nolock_unlock - unlock a lock
++ * @lock: the lock to manipulate
++ * @cur_state: the current state
++ *
++ * Returns: 0
++ */
++
++static unsigned int nolock_unlock(void *lock, unsigned int cur_state)
++{
++ return 0;
++}
++
++static void nolock_cancel(void *lock)
++{
++}
++
++/**
++ * nolock_hold_lvb - hold on to a lock value block
++ * @lock: the lock the LVB is associated with
++ * @lvbp: return the lm_lvb_t here
++ *
++ * Returns: 0 on success, -EXXX on failure
++ */
++
++static int nolock_hold_lvb(void *lock, char **lvbp)
++{
++ struct nolock_lockspace *nl = lock;
++ int error = 0;
++
++ *lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL);
++ if (!*lvbp)
++ error = -ENOMEM;
++
++ return error;
++}
++
++/**
++ * nolock_unhold_lvb - release a LVB
++ * @lock: the lock the LVB is associated with
++ * @lvb: the lock value block
++ *
++ */
++
++static void nolock_unhold_lvb(void *lock, char *lvb)
++{
++ kfree(lvb);
++}
++
++static int nolock_plock_get(void *lockspace, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl)
++{
++ struct file_lock tmp;
++ int ret;
++
++ ret = posix_test_lock(file, fl, &tmp);
++ fl->fl_type = F_UNLCK;
++ if (ret)
++ memcpy(fl, &tmp, sizeof(struct file_lock));
++
++ return 0;
++}
++
++static int nolock_plock(void *lockspace, struct lm_lockname *name,
++ struct file *file, int cmd, struct file_lock *fl)
++{
++ int error;
++ error = posix_lock_file_wait(file, fl);
++ return error;
++}
++
++static int nolock_punlock(void *lockspace, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl)
++{
++ int error;
++ error = posix_lock_file_wait(file, fl);
++ return error;
++}
++
++static void nolock_recovery_done(void *lockspace, unsigned int jid,
++ unsigned int message)
++{
++}
++
++static const struct lm_lockops nolock_ops = {
++ .lm_proto_name = "lock_nolock",
++ .lm_mount = nolock_mount,
++ .lm_others_may_mount = nolock_others_may_mount,
++ .lm_unmount = nolock_unmount,
++ .lm_withdraw = nolock_withdraw,
++ .lm_get_lock = nolock_get_lock,
++ .lm_put_lock = nolock_put_lock,
++ .lm_lock = nolock_lock,
++ .lm_unlock = nolock_unlock,
++ .lm_cancel = nolock_cancel,
++ .lm_hold_lvb = nolock_hold_lvb,
++ .lm_unhold_lvb = nolock_unhold_lvb,
++ .lm_plock_get = nolock_plock_get,
++ .lm_plock = nolock_plock,
++ .lm_punlock = nolock_punlock,
++ .lm_recovery_done = nolock_recovery_done,
++ .lm_owner = THIS_MODULE,
++};
++
++static int __init init_nolock(void)
++{
++ int error;
++
++ error = gfs2_register_lockproto(&nolock_ops);
++ if (error) {
++ printk(KERN_WARNING
++ "lock_nolock: can't register protocol: %d\n", error);
++ return error;
++ }
++
++ printk(KERN_INFO
++ "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__);
++ return 0;
++}
++
++static void __exit exit_nolock(void)
++{
++ gfs2_unregister_lockproto(&nolock_ops);
++}
++
++module_init(init_nolock);
++module_exit(exit_nolock);
++
++MODULE_DESCRIPTION("GFS Nolock Locking Module");
++MODULE_AUTHOR("Red Hat, Inc.");
++MODULE_LICENSE("GPL");
++
+diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
+new file mode 100644
+index 0000000..0cace3d
+--- /dev/null
++++ b/fs/gfs2/log.c
+@@ -0,0 +1,688 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "log.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "util.h"
++#include "dir.h"
++
++#define PULL 1
++
++/**
++ * gfs2_struct2blk - compute stuff
++ * @sdp: the filesystem
++ * @nstruct: the number of structures
++ * @ssize: the size of the structures
++ *
++ * Compute the number of log descriptor blocks needed to hold a certain number
++ * of structures of a certain size.
++ *
++ * Returns: the number of blocks needed (minimum is always 1)
++ */
++
++unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
++ unsigned int ssize)
++{
++ unsigned int blks;
++ unsigned int first, second;
++
++ blks = 1;
++ first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize;
++
++ if (nstruct > first) {
++ second = (sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_meta_header)) / ssize;
++ blks += DIV_ROUND_UP(nstruct - first, second);
++ }
++
++ return blks;
++}
++
++/**
++ * gfs2_ail1_start_one - Start I/O on a part of the AIL
++ * @sdp: the filesystem
++ * @tr: the part of the AIL
++ *
++ */
++
++static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ struct gfs2_bufdata *bd, *s;
++ struct buffer_head *bh;
++ int retry;
++
++ BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
++
++ do {
++ retry = 0;
++
++ list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
++ bd_ail_st_list) {
++ bh = bd->bd_bh;
++
++ gfs2_assert(sdp, bd->bd_ail == ai);
++
++ if (!buffer_busy(bh)) {
++ if (!buffer_uptodate(bh)) {
++ gfs2_log_unlock(sdp);
++ gfs2_io_error_bh(sdp, bh);
++ gfs2_log_lock(sdp);
++ }
++ list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
++ continue;
++ }
++
++ if (!buffer_dirty(bh))
++ continue;
++
++ list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
++
++ gfs2_log_unlock(sdp);
++ wait_on_buffer(bh);
++ ll_rw_block(WRITE, 1, &bh);
++ gfs2_log_lock(sdp);
++
++ retry = 1;
++ break;
++ }
++ } while (retry);
++}
++
++/**
++ * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced
++ * @sdp: the filesystem
++ * @ai: the AIL entry
++ *
++ */
++
++static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags)
++{
++ struct gfs2_bufdata *bd, *s;
++ struct buffer_head *bh;
++
++ list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
++ bd_ail_st_list) {
++ bh = bd->bd_bh;
++
++ gfs2_assert(sdp, bd->bd_ail == ai);
++
++ if (buffer_busy(bh)) {
++ if (flags & DIO_ALL)
++ continue;
++ else
++ break;
++ }
++
++ if (!buffer_uptodate(bh))
++ gfs2_io_error_bh(sdp, bh);
++
++ list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
++ }
++
++ return list_empty(&ai->ai_ail1_list);
++}
++
++void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
++{
++ struct list_head *head = &sdp->sd_ail1_list;
++ u64 sync_gen;
++ struct list_head *first;
++ struct gfs2_ail *first_ai, *ai, *tmp;
++ int done = 0;
++
++ gfs2_log_lock(sdp);
++ if (list_empty(head)) {
++ gfs2_log_unlock(sdp);
++ return;
++ }
++ sync_gen = sdp->sd_ail_sync_gen++;
++
++ first = head->prev;
++ first_ai = list_entry(first, struct gfs2_ail, ai_list);
++ first_ai->ai_sync_gen = sync_gen;
++ gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */
++
++ if (flags & DIO_ALL)
++ first = NULL;
++
++ while(!done) {
++ if (first && (head->prev != first ||
++ gfs2_ail1_empty_one(sdp, first_ai, 0)))
++ break;
++
++ done = 1;
++ list_for_each_entry_safe_reverse(ai, tmp, head, ai_list) {
++ if (ai->ai_sync_gen >= sync_gen)
++ continue;
++ ai->ai_sync_gen = sync_gen;
++ gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */
++ done = 0;
++ break;
++ }
++ }
++
++ gfs2_log_unlock(sdp);
++}
++
++int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
++{
++ struct gfs2_ail *ai, *s;
++ int ret;
++
++ gfs2_log_lock(sdp);
++
++ list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) {
++ if (gfs2_ail1_empty_one(sdp, ai, flags))
++ list_move(&ai->ai_list, &sdp->sd_ail2_list);
++ else if (!(flags & DIO_ALL))
++ break;
++ }
++
++ ret = list_empty(&sdp->sd_ail1_list);
++
++ gfs2_log_unlock(sdp);
++
++ return ret;
++}
++
++
++/**
++ * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced
++ * @sdp: the filesystem
++ * @ai: the AIL entry
++ *
++ */
++
++static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ struct list_head *head = &ai->ai_ail2_list;
++ struct gfs2_bufdata *bd;
++
++ while (!list_empty(head)) {
++ bd = list_entry(head->prev, struct gfs2_bufdata,
++ bd_ail_st_list);
++ gfs2_assert(sdp, bd->bd_ail == ai);
++ bd->bd_ail = NULL;
++ list_del(&bd->bd_ail_st_list);
++ list_del(&bd->bd_ail_gl_list);
++ atomic_dec(&bd->bd_gl->gl_ail_count);
++ brelse(bd->bd_bh);
++ }
++}
++
++static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
++{
++ struct gfs2_ail *ai, *safe;
++ unsigned int old_tail = sdp->sd_log_tail;
++ int wrap = (new_tail < old_tail);
++ int a, b, rm;
++
++ gfs2_log_lock(sdp);
++
++ list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) {
++ a = (old_tail <= ai->ai_first);
++ b = (ai->ai_first < new_tail);
++ rm = (wrap) ? (a || b) : (a && b);
++ if (!rm)
++ continue;
++
++ gfs2_ail2_empty_one(sdp, ai);
++ list_del(&ai->ai_list);
++ gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list));
++ gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list));
++ kfree(ai);
++ }
++
++ gfs2_log_unlock(sdp);
++}
++
++/**
++ * gfs2_log_reserve - Make a log reservation
++ * @sdp: The GFS2 superblock
++ * @blks: The number of blocks to reserve
++ *
++ * Returns: errno
++ */
++
++int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
++{
++ unsigned int try = 0;
++
++ if (gfs2_assert_warn(sdp, blks) ||
++ gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
++ return -EINVAL;
++
++ mutex_lock(&sdp->sd_log_reserve_mutex);
++ gfs2_log_lock(sdp);
++ while(sdp->sd_log_blks_free <= blks) {
++ gfs2_log_unlock(sdp);
++ gfs2_ail1_empty(sdp, 0);
++ gfs2_log_flush(sdp, NULL);
++
++ if (try++)
++ gfs2_ail1_start(sdp, 0);
++ gfs2_log_lock(sdp);
++ }
++ sdp->sd_log_blks_free -= blks;
++ gfs2_log_unlock(sdp);
++ mutex_unlock(&sdp->sd_log_reserve_mutex);
++
++ down_read(&sdp->sd_log_flush_lock);
++
++ return 0;
++}
++
++/**
++ * gfs2_log_release - Release a given number of log blocks
++ * @sdp: The GFS2 superblock
++ * @blks: The number of blocks
++ *
++ */
++
++void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
++{
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_blks_free += blks;
++ gfs2_assert_withdraw(sdp,
++ sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
++ gfs2_log_unlock(sdp);
++ up_read(&sdp->sd_log_flush_lock);
++}
++
++static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
++{
++ struct inode *inode = sdp->sd_jdesc->jd_inode;
++ int error;
++ struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
++
++ bh_map.b_size = 1 << inode->i_blkbits;
++ error = gfs2_block_map(inode, lbn, 0, &bh_map);
++ if (error || !bh_map.b_blocknr)
++ printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, bh_map.b_blocknr, lbn);
++ gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
++
++ return bh_map.b_blocknr;
++}
++
++/**
++ * log_distance - Compute distance between two journal blocks
++ * @sdp: The GFS2 superblock
++ * @newer: The most recent journal block of the pair
++ * @older: The older journal block of the pair
++ *
++ * Compute the distance (in the journal direction) between two
++ * blocks in the journal
++ *
++ * Returns: the distance in blocks
++ */
++
++static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer,
++ unsigned int older)
++{
++ int dist;
++
++ dist = newer - older;
++ if (dist < 0)
++ dist += sdp->sd_jdesc->jd_blocks;
++
++ return dist;
++}
++
++static unsigned int current_tail(struct gfs2_sbd *sdp)
++{
++ struct gfs2_ail *ai;
++ unsigned int tail;
++
++ gfs2_log_lock(sdp);
++
++ if (list_empty(&sdp->sd_ail1_list)) {
++ tail = sdp->sd_log_head;
++ } else {
++ ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, ai_list);
++ tail = ai->ai_first;
++ }
++
++ gfs2_log_unlock(sdp);
++
++ return tail;
++}
++
++static inline void log_incr_head(struct gfs2_sbd *sdp)
++{
++ if (sdp->sd_log_flush_head == sdp->sd_log_tail)
++ gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head);
++
++ if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
++ sdp->sd_log_flush_head = 0;
++ sdp->sd_log_flush_wrapped = 1;
++ }
++}
++
++/**
++ * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
++ * @sdp: The GFS2 superblock
++ *
++ * Returns: the buffer_head
++ */
++
++struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
++{
++ u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
++ struct gfs2_log_buf *lb;
++ struct buffer_head *bh;
++
++ lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
++ list_add(&lb->lb_list, &sdp->sd_log_flush_list);
++
++ bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno);
++ lock_buffer(bh);
++ memset(bh->b_data, 0, bh->b_size);
++ set_buffer_uptodate(bh);
++ clear_buffer_dirty(bh);
++ unlock_buffer(bh);
++
++ log_incr_head(sdp);
++
++ return bh;
++}
++
++/**
++ * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
++ * @sdp: the filesystem
++ * @data: the data the buffer_head should point to
++ *
++ * Returns: the log buffer descriptor
++ */
++
++struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
++ struct buffer_head *real)
++{
++ u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
++ struct gfs2_log_buf *lb;
++ struct buffer_head *bh;
++
++ lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
++ list_add(&lb->lb_list, &sdp->sd_log_flush_list);
++ lb->lb_real = real;
++
++ bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
++ atomic_set(&bh->b_count, 1);
++ bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate);
++ set_bh_page(bh, real->b_page, bh_offset(real));
++ bh->b_blocknr = blkno;
++ bh->b_size = sdp->sd_sb.sb_bsize;
++ bh->b_bdev = sdp->sd_vfs->s_bdev;
++
++ log_incr_head(sdp);
++
++ return bh;
++}
++
++static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull)
++{
++ unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
++
++ ail2_empty(sdp, new_tail);
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_blks_free += dist - (pull ? 1 : 0);
++ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
++ gfs2_log_unlock(sdp);
++
++ sdp->sd_log_tail = new_tail;
++}
++
++/**
++ * log_write_header - Get and initialize a journal header buffer
++ * @sdp: The GFS2 superblock
++ *
++ * Returns: the initialized log buffer descriptor
++ */
++
++static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
++{
++ u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
++ struct buffer_head *bh;
++ struct gfs2_log_header *lh;
++ unsigned int tail;
++ u32 hash;
++
++ bh = sb_getblk(sdp->sd_vfs, blkno);
++ lock_buffer(bh);
++ memset(bh->b_data, 0, bh->b_size);
++ set_buffer_uptodate(bh);
++ clear_buffer_dirty(bh);
++ unlock_buffer(bh);
++
++ gfs2_ail1_empty(sdp, 0);
++ tail = current_tail(sdp);
++
++ lh = (struct gfs2_log_header *)bh->b_data;
++ memset(lh, 0, sizeof(struct gfs2_log_header));
++ lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
++ lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
++ lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
++ lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
++ lh->lh_flags = cpu_to_be32(flags);
++ lh->lh_tail = cpu_to_be32(tail);
++ lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
++ hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
++ lh->lh_hash = cpu_to_be32(hash);
++
++ set_buffer_dirty(bh);
++ if (sync_dirty_buffer(bh))
++ gfs2_io_error_bh(sdp, bh);
++ brelse(bh);
++
++ if (sdp->sd_log_tail != tail)
++ log_pull_tail(sdp, tail, pull);
++ else
++ gfs2_assert_withdraw(sdp, !pull);
++
++ sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
++ log_incr_head(sdp);
++}
++
++static void log_flush_commit(struct gfs2_sbd *sdp)
++{
++ struct list_head *head = &sdp->sd_log_flush_list;
++ struct gfs2_log_buf *lb;
++ struct buffer_head *bh;
++
++ while (!list_empty(head)) {
++ lb = list_entry(head->next, struct gfs2_log_buf, lb_list);
++ list_del(&lb->lb_list);
++ bh = lb->lb_bh;
++
++ wait_on_buffer(bh);
++ if (!buffer_uptodate(bh))
++ gfs2_io_error_bh(sdp, bh);
++ if (lb->lb_real) {
++ while (atomic_read(&bh->b_count) != 1) /* Grrrr... */
++ schedule();
++ free_buffer_head(bh);
++ } else
++ brelse(bh);
++ kfree(lb);
++ }
++
++ log_write_header(sdp, 0, 0);
++}
++
++/**
++ * gfs2_log_flush - flush incore transaction(s)
++ * @sdp: the filesystem
++ * @gl: The glock structure to flush. If NULL, flush the whole incore log
++ *
++ */
++
++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
++{
++ struct gfs2_ail *ai;
++
++ down_write(&sdp->sd_log_flush_lock);
++
++ if (gl) {
++ gfs2_log_lock(sdp);
++ if (list_empty(&gl->gl_le.le_list)) {
++ gfs2_log_unlock(sdp);
++ up_write(&sdp->sd_log_flush_lock);
++ return;
++ }
++ gfs2_log_unlock(sdp);
++ }
++
++ ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
++ INIT_LIST_HEAD(&ai->ai_ail1_list);
++ INIT_LIST_HEAD(&ai->ai_ail2_list);
++
++ gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf == sdp->sd_log_commited_buf);
++ gfs2_assert_withdraw(sdp,
++ sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
++
++ sdp->sd_log_flush_head = sdp->sd_log_head;
++ sdp->sd_log_flush_wrapped = 0;
++ ai->ai_first = sdp->sd_log_flush_head;
++
++ lops_before_commit(sdp);
++ if (!list_empty(&sdp->sd_log_flush_list))
++ log_flush_commit(sdp);
++ else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle)
++ log_write_header(sdp, 0, PULL);
++ lops_after_commit(sdp, ai);
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_head = sdp->sd_log_flush_head;
++ sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs;
++ sdp->sd_log_blks_reserved = 0;
++ sdp->sd_log_commited_buf = 0;
++ sdp->sd_log_num_hdrs = 0;
++ sdp->sd_log_commited_revoke = 0;
++
++ if (!list_empty(&ai->ai_ail1_list)) {
++ list_add(&ai->ai_list, &sdp->sd_ail1_list);
++ ai = NULL;
++ }
++ gfs2_log_unlock(sdp);
++
++ sdp->sd_vfs->s_dirt = 0;
++ up_write(&sdp->sd_log_flush_lock);
++
++ kfree(ai);
++}
++
++static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
++{
++ unsigned int reserved = 0;
++ unsigned int old;
++
++ gfs2_log_lock(sdp);
++
++ sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm;
++ gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0);
++ sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
++ gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
++
++ if (sdp->sd_log_commited_buf)
++ reserved += sdp->sd_log_commited_buf;
++ if (sdp->sd_log_commited_revoke)
++ reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke,
++ sizeof(u64));
++ if (reserved)
++ reserved++;
++
++ old = sdp->sd_log_blks_free;
++ sdp->sd_log_blks_free += tr->tr_reserved -
++ (reserved - sdp->sd_log_blks_reserved);
++
++ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
++ gfs2_assert_withdraw(sdp,
++ sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks +
++ sdp->sd_log_num_hdrs);
++
++ sdp->sd_log_blks_reserved = reserved;
++
++ gfs2_log_unlock(sdp);
++}
++
++/**
++ * gfs2_log_commit - Commit a transaction to the log
++ * @sdp: the filesystem
++ * @tr: the transaction
++ *
++ * Returns: errno
++ */
++
++void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
++{
++ log_refund(sdp, tr);
++ lops_incore_commit(sdp, tr);
++
++ sdp->sd_vfs->s_dirt = 1;
++ up_read(&sdp->sd_log_flush_lock);
++
++ gfs2_log_lock(sdp);
++ if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) {
++ gfs2_log_unlock(sdp);
++ gfs2_log_flush(sdp, NULL);
++ } else {
++ gfs2_log_unlock(sdp);
++ }
++}
++
++/**
++ * gfs2_log_shutdown - write a shutdown header into a journal
++ * @sdp: the filesystem
++ *
++ */
++
++void gfs2_log_shutdown(struct gfs2_sbd *sdp)
++{
++ down_write(&sdp->sd_log_flush_lock);
++
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_hdrs);
++ gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list));
++
++ sdp->sd_log_flush_head = sdp->sd_log_head;
++ sdp->sd_log_flush_wrapped = 0;
++
++ log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0);
++
++ gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
++ gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
++ gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
++
++ sdp->sd_log_head = sdp->sd_log_flush_head;
++ sdp->sd_log_tail = sdp->sd_log_head;
++
++ up_write(&sdp->sd_log_flush_lock);
++}
++
+diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
+new file mode 100644
+index 0000000..7f5737d
+--- /dev/null
++++ b/fs/gfs2/log.h
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __LOG_DOT_H__
++#define __LOG_DOT_H__
++
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include "incore.h"
++
++/**
++ * gfs2_log_lock - acquire the right to mess with the log manager
++ * @sdp: the filesystem
++ *
++ */
++
++static inline void gfs2_log_lock(struct gfs2_sbd *sdp)
++{
++ spin_lock(&sdp->sd_log_lock);
++}
++
++/**
++ * gfs2_log_unlock - release the right to mess with the log manager
++ * @sdp: the filesystem
++ *
++ */
++
++static inline void gfs2_log_unlock(struct gfs2_sbd *sdp)
++{
++ spin_unlock(&sdp->sd_log_lock);
++}
++
++static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
++ unsigned int value)
++{
++ if (++value == sdp->sd_jdesc->jd_blocks) {
++ value = 0;
++ }
++ sdp->sd_log_head = sdp->sd_log_tail = value;
++}
++
++unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
++ unsigned int ssize);
++
++void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags);
++int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
++
++int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
++void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
++
++struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
++struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
++ struct buffer_head *real);
++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
++void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
++
++void gfs2_log_shutdown(struct gfs2_sbd *sdp);
++
++#endif /* __LOG_DOT_H__ */
+diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
+new file mode 100644
+index 0000000..ab6d111
+--- /dev/null
++++ b/fs/gfs2/lops.c
+@@ -0,0 +1,809 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "log.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "recovery.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++
++static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
++{
++ struct gfs2_glock *gl;
++ struct gfs2_trans *tr = current->journal_info;
++
++ tr->tr_touched = 1;
++
++ if (!list_empty(&le->le_list))
++ return;
++
++ gl = container_of(le, struct gfs2_glock, gl_le);
++ if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
++ return;
++ gfs2_glock_hold(gl);
++ set_bit(GLF_DIRTY, &gl->gl_flags);
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_num_gl++;
++ list_add(&le->le_list, &sdp->sd_log_le_gl);
++ gfs2_log_unlock(sdp);
++}
++
++static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ struct list_head *head = &sdp->sd_log_le_gl;
++ struct gfs2_glock *gl;
++
++ while (!list_empty(head)) {
++ gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list);
++ list_del_init(&gl->gl_le.le_list);
++ sdp->sd_log_num_gl--;
++
++ gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl));
++ gfs2_glock_put(gl);
++ }
++ gfs2_assert_warn(sdp, !sdp->sd_log_num_gl);
++}
++
++static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
++{
++ struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
++ struct gfs2_trans *tr;
++
++ if (!list_empty(&bd->bd_list_tr))
++ return;
++
++ tr = current->journal_info;
++ tr->tr_touched = 1;
++ tr->tr_num_buf++;
++ list_add(&bd->bd_list_tr, &tr->tr_list_buf);
++
++ if (!list_empty(&le->le_list))
++ return;
++
++ gfs2_trans_add_gl(bd->bd_gl);
++
++ gfs2_meta_check(sdp, bd->bd_bh);
++ gfs2_pin(sdp, bd->bd_bh);
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_num_buf++;
++ list_add(&le->le_list, &sdp->sd_log_le_buf);
++ gfs2_log_unlock(sdp);
++
++ tr->tr_num_buf_new++;
++}
++
++static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
++{
++ struct list_head *head = &tr->tr_list_buf;
++ struct gfs2_bufdata *bd;
++
++ while (!list_empty(head)) {
++ bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
++ list_del_init(&bd->bd_list_tr);
++ tr->tr_num_buf--;
++ }
++ gfs2_assert_warn(sdp, !tr->tr_num_buf);
++}
++
++static void buf_lo_before_commit(struct gfs2_sbd *sdp)
++{
++ struct buffer_head *bh;
++ struct gfs2_log_descriptor *ld;
++ struct gfs2_bufdata *bd1 = NULL, *bd2;
++ unsigned int total = sdp->sd_log_num_buf;
++ unsigned int offset = sizeof(struct gfs2_log_descriptor);
++ unsigned int limit;
++ unsigned int num;
++ unsigned n;
++ __be64 *ptr;
++
++ offset += sizeof(__be64) - 1;
++ offset &= ~(sizeof(__be64) - 1);
++ limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64);
++ /* for 4k blocks, limit = 503 */
++
++ bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list);
++ while(total) {
++ num = total;
++ if (total > limit)
++ num = limit;
++ bh = gfs2_log_get_buf(sdp);
++ sdp->sd_log_num_hdrs++;
++ ld = (struct gfs2_log_descriptor *)bh->b_data;
++ ptr = (__be64 *)(bh->b_data + offset);
++ ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
++ ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
++ ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
++ ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA);
++ ld->ld_length = cpu_to_be32(num + 1);
++ ld->ld_data1 = cpu_to_be32(num);
++ ld->ld_data2 = cpu_to_be32(0);
++ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
++
++ n = 0;
++ list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf,
++ bd_le.le_list) {
++ *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
++ if (++n >= num)
++ break;
++ }
++
++ set_buffer_dirty(bh);
++ ll_rw_block(WRITE, 1, &bh);
++
++ n = 0;
++ list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf,
++ bd_le.le_list) {
++ bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
++ set_buffer_dirty(bh);
++ ll_rw_block(WRITE, 1, &bh);
++ if (++n >= num)
++ break;
++ }
++
++ total -= num;
++ }
++}
++
++static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ struct list_head *head = &sdp->sd_log_le_buf;
++ struct gfs2_bufdata *bd;
++
++ while (!list_empty(head)) {
++ bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
++ list_del_init(&bd->bd_le.le_list);
++ sdp->sd_log_num_buf--;
++
++ gfs2_unpin(sdp, bd->bd_bh, ai);
++ }
++ gfs2_assert_warn(sdp, !sdp->sd_log_num_buf);
++}
++
++static void buf_lo_before_scan(struct gfs2_jdesc *jd,
++ struct gfs2_log_header *head, int pass)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++
++ if (pass != 0)
++ return;
++
++ sdp->sd_found_blocks = 0;
++ sdp->sd_replayed_blocks = 0;
++}
++
++static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
++ struct gfs2_log_descriptor *ld, __be64 *ptr,
++ int pass)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ struct gfs2_glock *gl = ip->i_gl;
++ unsigned int blks = be32_to_cpu(ld->ld_data1);
++ struct buffer_head *bh_log, *bh_ip;
++ u64 blkno;
++ int error = 0;
++
++ if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA)
++ return 0;
++
++ gfs2_replay_incr_blk(sdp, &start);
++
++ for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
++ blkno = be64_to_cpu(*ptr++);
++
++ sdp->sd_found_blocks++;
++
++ if (gfs2_revoke_check(sdp, blkno, start))
++ continue;
++
++ error = gfs2_replay_read_block(jd, start, &bh_log);
++ if (error)
++ return error;
++
++ bh_ip = gfs2_meta_new(gl, blkno);
++ memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
++
++ if (gfs2_meta_check(sdp, bh_ip))
++ error = -EIO;
++ else
++ mark_buffer_dirty(bh_ip);
++
++ brelse(bh_log);
++ brelse(bh_ip);
++
++ if (error)
++ break;
++
++ sdp->sd_replayed_blocks++;
++ }
++
++ return error;
++}
++
++static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++
++ if (error) {
++ gfs2_meta_sync(ip->i_gl);
++ return;
++ }
++ if (pass != 1)
++ return;
++
++ gfs2_meta_sync(ip->i_gl);
++
++ fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n",
++ jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
++}
++
++static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
++{
++ struct gfs2_trans *tr;
++
++ tr = current->journal_info;
++ tr->tr_touched = 1;
++ tr->tr_num_revoke++;
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_num_revoke++;
++ list_add(&le->le_list, &sdp->sd_log_le_revoke);
++ gfs2_log_unlock(sdp);
++}
++
++static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
++{
++ struct gfs2_log_descriptor *ld;
++ struct gfs2_meta_header *mh;
++ struct buffer_head *bh;
++ unsigned int offset;
++ struct list_head *head = &sdp->sd_log_le_revoke;
++ struct gfs2_revoke *rv;
++
++ if (!sdp->sd_log_num_revoke)
++ return;
++
++ bh = gfs2_log_get_buf(sdp);
++ ld = (struct gfs2_log_descriptor *)bh->b_data;
++ ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
++ ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
++ ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
++ ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE);
++ ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke,
++ sizeof(u64)));
++ ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke);
++ ld->ld_data2 = cpu_to_be32(0);
++ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
++ offset = sizeof(struct gfs2_log_descriptor);
++
++ while (!list_empty(head)) {
++ rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list);
++ list_del_init(&rv->rv_le.le_list);
++ sdp->sd_log_num_revoke--;
++
++ if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
++ set_buffer_dirty(bh);
++ ll_rw_block(WRITE, 1, &bh);
++
++ bh = gfs2_log_get_buf(sdp);
++ mh = (struct gfs2_meta_header *)bh->b_data;
++ mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
++ mh->mh_type = cpu_to_be32(GFS2_METATYPE_LB);
++ mh->mh_format = cpu_to_be32(GFS2_FORMAT_LB);
++ offset = sizeof(struct gfs2_meta_header);
++ }
++
++ *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno);
++ kfree(rv);
++
++ offset += sizeof(u64);
++ }
++ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
++
++ set_buffer_dirty(bh);
++ ll_rw_block(WRITE, 1, &bh);
++}
++
++static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
++ struct gfs2_log_header *head, int pass)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++
++ if (pass != 0)
++ return;
++
++ sdp->sd_found_revokes = 0;
++ sdp->sd_replay_tail = head->lh_tail;
++}
++
++static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
++ struct gfs2_log_descriptor *ld, __be64 *ptr,
++ int pass)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ unsigned int blks = be32_to_cpu(ld->ld_length);
++ unsigned int revokes = be32_to_cpu(ld->ld_data1);
++ struct buffer_head *bh;
++ unsigned int offset;
++ u64 blkno;
++ int first = 1;
++ int error;
++
++ if (pass != 0 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_REVOKE)
++ return 0;
++
++ offset = sizeof(struct gfs2_log_descriptor);
++
++ for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
++ error = gfs2_replay_read_block(jd, start, &bh);
++ if (error)
++ return error;
++
++ if (!first)
++ gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LB);
++
++ while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) {
++ blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset));
++
++ error = gfs2_revoke_add(sdp, blkno, start);
++ if (error < 0)
++ return error;
++ else if (error)
++ sdp->sd_found_revokes++;
++
++ if (!--revokes)
++ break;
++ offset += sizeof(u64);
++ }
++
++ brelse(bh);
++ offset = sizeof(struct gfs2_meta_header);
++ first = 0;
++ }
++
++ return 0;
++}
++
++static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++
++ if (error) {
++ gfs2_revoke_clean(sdp);
++ return;
++ }
++ if (pass != 1)
++ return;
++
++ fs_info(sdp, "jid=%u: Found %u revoke tags\n",
++ jd->jd_jid, sdp->sd_found_revokes);
++
++ gfs2_revoke_clean(sdp);
++}
++
++static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
++{
++ struct gfs2_rgrpd *rgd;
++ struct gfs2_trans *tr = current->journal_info;
++
++ tr->tr_touched = 1;
++
++ if (!list_empty(&le->le_list))
++ return;
++
++ rgd = container_of(le, struct gfs2_rgrpd, rd_le);
++ gfs2_rgrp_bh_hold(rgd);
++
++ gfs2_log_lock(sdp);
++ sdp->sd_log_num_rg++;
++ list_add(&le->le_list, &sdp->sd_log_le_rg);
++ gfs2_log_unlock(sdp);
++}
++
++static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ struct list_head *head = &sdp->sd_log_le_rg;
++ struct gfs2_rgrpd *rgd;
++
++ while (!list_empty(head)) {
++ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list);
++ list_del_init(&rgd->rd_le.le_list);
++ sdp->sd_log_num_rg--;
++
++ gfs2_rgrp_repolish_clones(rgd);
++ gfs2_rgrp_bh_put(rgd);
++ }
++ gfs2_assert_warn(sdp, !sdp->sd_log_num_rg);
++}
++
++/**
++ * databuf_lo_add - Add a databuf to the transaction.
++ *
++ * This is used in two distinct cases:
++ * i) In ordered write mode
++ * We put the data buffer on a list so that we can ensure that its
++ * synced to disk at the right time
++ * ii) In journaled data mode
++ * We need to journal the data block in the same way as metadata in
++ * the functions above. The difference is that here we have a tag
++ * which is two __be64's being the block number (as per meta data)
++ * and a flag which says whether the data block needs escaping or
++ * not. This means we need a new log entry for each 251 or so data
++ * blocks, which isn't an enormous overhead but twice as much as
++ * for normal metadata blocks.
++ */
++static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
++{
++ struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
++ struct gfs2_trans *tr = current->journal_info;
++ struct address_space *mapping = bd->bd_bh->b_page->mapping;
++ struct gfs2_inode *ip = GFS2_I(mapping->host);
++
++ tr->tr_touched = 1;
++ if (list_empty(&bd->bd_list_tr) &&
++ (ip->i_di.di_flags & GFS2_DIF_JDATA)) {
++ tr->tr_num_buf++;
++ list_add(&bd->bd_list_tr, &tr->tr_list_buf);
++ gfs2_pin(sdp, bd->bd_bh);
++ tr->tr_num_buf_new++;
++ }
++ gfs2_trans_add_gl(bd->bd_gl);
++ gfs2_log_lock(sdp);
++ if (list_empty(&le->le_list)) {
++ if (ip->i_di.di_flags & GFS2_DIF_JDATA)
++ sdp->sd_log_num_jdata++;
++ sdp->sd_log_num_databuf++;
++ list_add(&le->le_list, &sdp->sd_log_le_databuf);
++ }
++ gfs2_log_unlock(sdp);
++}
++
++static int gfs2_check_magic(struct buffer_head *bh)
++{
++ struct page *page = bh->b_page;
++ void *kaddr;
++ __be32 *ptr;
++ int rv = 0;
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ ptr = kaddr + bh_offset(bh);
++ if (*ptr == cpu_to_be32(GFS2_MAGIC))
++ rv = 1;
++ kunmap_atomic(kaddr, KM_USER0);
++
++ return rv;
++}
++
++/**
++ * databuf_lo_before_commit - Scan the data buffers, writing as we go
++ *
++ * Here we scan through the lists of buffers and make the assumption
++ * that any buffer thats been pinned is being journaled, and that
++ * any unpinned buffer is an ordered write data buffer and therefore
++ * will be written back rather than journaled.
++ */
++static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
++{
++ LIST_HEAD(started);
++ struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
++ struct buffer_head *bh = NULL;
++ unsigned int offset = sizeof(struct gfs2_log_descriptor);
++ struct gfs2_log_descriptor *ld;
++ unsigned int limit;
++ unsigned int total_dbuf = sdp->sd_log_num_databuf;
++ unsigned int total_jdata = sdp->sd_log_num_jdata;
++ unsigned int num, n;
++ __be64 *ptr = NULL;
++
++ offset += 2*sizeof(__be64) - 1;
++ offset &= ~(2*sizeof(__be64) - 1);
++ limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64);
++
++ /*
++ * Start writing ordered buffers, write journaled buffers
++ * into the log along with a header
++ */
++ gfs2_log_lock(sdp);
++ bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf,
++ bd_le.le_list);
++ while(total_dbuf) {
++ num = total_jdata;
++ if (num > limit)
++ num = limit;
++ n = 0;
++ list_for_each_entry_safe_continue(bd1, bdt,
++ &sdp->sd_log_le_databuf,
++ bd_le.le_list) {
++ /* An ordered write buffer */
++ if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) {
++ list_move(&bd1->bd_le.le_list, &started);
++ if (bd1 == bd2) {
++ bd2 = NULL;
++ bd2 = list_prepare_entry(bd2,
++ &sdp->sd_log_le_databuf,
++ bd_le.le_list);
++ }
++ total_dbuf--;
++ if (bd1->bd_bh) {
++ get_bh(bd1->bd_bh);
++ if (buffer_dirty(bd1->bd_bh)) {
++ gfs2_log_unlock(sdp);
++ wait_on_buffer(bd1->bd_bh);
++ ll_rw_block(WRITE, 1,
++ &bd1->bd_bh);
++ gfs2_log_lock(sdp);
++ }
++ brelse(bd1->bd_bh);
++ continue;
++ }
++ continue;
++ } else if (bd1->bd_bh) { /* A journaled buffer */
++ int magic;
++ gfs2_log_unlock(sdp);
++ if (!bh) {
++ bh = gfs2_log_get_buf(sdp);
++ sdp->sd_log_num_hdrs++;
++ ld = (struct gfs2_log_descriptor *)
++ bh->b_data;
++ ptr = (__be64 *)(bh->b_data + offset);
++ ld->ld_header.mh_magic =
++ cpu_to_be32(GFS2_MAGIC);
++ ld->ld_header.mh_type =
++ cpu_to_be32(GFS2_METATYPE_LD);
++ ld->ld_header.mh_format =
++ cpu_to_be32(GFS2_FORMAT_LD);
++ ld->ld_type =
++ cpu_to_be32(GFS2_LOG_DESC_JDATA);
++ ld->ld_length = cpu_to_be32(num + 1);
++ ld->ld_data1 = cpu_to_be32(num);
++ ld->ld_data2 = cpu_to_be32(0);
++ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
++ }
++ magic = gfs2_check_magic(bd1->bd_bh);
++ *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
++ *ptr++ = cpu_to_be64((__u64)magic);
++ clear_buffer_escaped(bd1->bd_bh);
++ if (unlikely(magic != 0))
++ set_buffer_escaped(bd1->bd_bh);
++ gfs2_log_lock(sdp);
++ if (n++ > num)
++ break;
++ } else if (!bd1->bd_bh) {
++ total_dbuf--;
++ sdp->sd_log_num_databuf--;
++ list_del_init(&bd1->bd_le.le_list);
++ if (bd1 == bd2) {
++ bd2 = NULL;
++ bd2 = list_prepare_entry(bd2,
++ &sdp->sd_log_le_databuf,
++ bd_le.le_list);
++ }
++ kmem_cache_free(gfs2_bufdata_cachep, bd1);
++ }
++ }
++ gfs2_log_unlock(sdp);
++ if (bh) {
++ set_buffer_dirty(bh);
++ ll_rw_block(WRITE, 1, &bh);
++ bh = NULL;
++ }
++ n = 0;
++ gfs2_log_lock(sdp);
++ list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf,
++ bd_le.le_list) {
++ if (!bd2->bd_bh)
++ continue;
++ /* copy buffer if it needs escaping */
++ gfs2_log_unlock(sdp);
++ if (unlikely(buffer_escaped(bd2->bd_bh))) {
++ void *kaddr;
++ struct page *page = bd2->bd_bh->b_page;
++ bh = gfs2_log_get_buf(sdp);
++ kaddr = kmap_atomic(page, KM_USER0);
++ memcpy(bh->b_data,
++ kaddr + bh_offset(bd2->bd_bh),
++ sdp->sd_sb.sb_bsize);
++ kunmap_atomic(kaddr, KM_USER0);
++ *(__be32 *)bh->b_data = 0;
++ } else {
++ bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
++ }
++ set_buffer_dirty(bh);
++ ll_rw_block(WRITE, 1, &bh);
++ gfs2_log_lock(sdp);
++ if (++n >= num)
++ break;
++ }
++ bh = NULL;
++ total_dbuf -= num;
++ total_jdata -= num;
++ }
++ gfs2_log_unlock(sdp);
++
++ /* Wait on all ordered buffers */
++ while (!list_empty(&started)) {
++ gfs2_log_lock(sdp);
++ bd1 = list_entry(started.next, struct gfs2_bufdata,
++ bd_le.le_list);
++ list_del_init(&bd1->bd_le.le_list);
++ sdp->sd_log_num_databuf--;
++ bh = bd1->bd_bh;
++ if (bh) {
++ bh->b_private = NULL;
++ get_bh(bh);
++ gfs2_log_unlock(sdp);
++ wait_on_buffer(bh);
++ brelse(bh);
++ } else
++ gfs2_log_unlock(sdp);
++
++ kmem_cache_free(gfs2_bufdata_cachep, bd1);
++ }
++
++ /* We've removed all the ordered write bufs here, so only jdata left */
++ gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata);
++}
++
++static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
++ struct gfs2_log_descriptor *ld,
++ __be64 *ptr, int pass)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ struct gfs2_glock *gl = ip->i_gl;
++ unsigned int blks = be32_to_cpu(ld->ld_data1);
++ struct buffer_head *bh_log, *bh_ip;
++ u64 blkno;
++ u64 esc;
++ int error = 0;
++
++ if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA)
++ return 0;
++
++ gfs2_replay_incr_blk(sdp, &start);
++ for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
++ blkno = be64_to_cpu(*ptr++);
++ esc = be64_to_cpu(*ptr++);
++
++ sdp->sd_found_blocks++;
++
++ if (gfs2_revoke_check(sdp, blkno, start))
++ continue;
++
++ error = gfs2_replay_read_block(jd, start, &bh_log);
++ if (error)
++ return error;
++
++ bh_ip = gfs2_meta_new(gl, blkno);
++ memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
++
++ /* Unescape */
++ if (esc) {
++ __be32 *eptr = (__be32 *)bh_ip->b_data;
++ *eptr = cpu_to_be32(GFS2_MAGIC);
++ }
++ mark_buffer_dirty(bh_ip);
++
++ brelse(bh_log);
++ brelse(bh_ip);
++ if (error)
++ break;
++
++ sdp->sd_replayed_blocks++;
++ }
++
++ return error;
++}
++
++/* FIXME: sort out accounting for log blocks etc. */
++
++static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++
++ if (error) {
++ gfs2_meta_sync(ip->i_gl);
++ return;
++ }
++ if (pass != 1)
++ return;
++
++ /* data sync? */
++ gfs2_meta_sync(ip->i_gl);
++
++ fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n",
++ jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
++}
++
++static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ struct list_head *head = &sdp->sd_log_le_databuf;
++ struct gfs2_bufdata *bd;
++
++ while (!list_empty(head)) {
++ bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
++ list_del_init(&bd->bd_le.le_list);
++ sdp->sd_log_num_databuf--;
++ sdp->sd_log_num_jdata--;
++ gfs2_unpin(sdp, bd->bd_bh, ai);
++ }
++ gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
++ gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata);
++}
++
++
++const struct gfs2_log_operations gfs2_glock_lops = {
++ .lo_add = glock_lo_add,
++ .lo_after_commit = glock_lo_after_commit,
++ .lo_name = "glock",
++};
++
++const struct gfs2_log_operations gfs2_buf_lops = {
++ .lo_add = buf_lo_add,
++ .lo_incore_commit = buf_lo_incore_commit,
++ .lo_before_commit = buf_lo_before_commit,
++ .lo_after_commit = buf_lo_after_commit,
++ .lo_before_scan = buf_lo_before_scan,
++ .lo_scan_elements = buf_lo_scan_elements,
++ .lo_after_scan = buf_lo_after_scan,
++ .lo_name = "buf",
++};
++
++const struct gfs2_log_operations gfs2_revoke_lops = {
++ .lo_add = revoke_lo_add,
++ .lo_before_commit = revoke_lo_before_commit,
++ .lo_before_scan = revoke_lo_before_scan,
++ .lo_scan_elements = revoke_lo_scan_elements,
++ .lo_after_scan = revoke_lo_after_scan,
++ .lo_name = "revoke",
++};
++
++const struct gfs2_log_operations gfs2_rg_lops = {
++ .lo_add = rg_lo_add,
++ .lo_after_commit = rg_lo_after_commit,
++ .lo_name = "rg",
++};
++
++const struct gfs2_log_operations gfs2_databuf_lops = {
++ .lo_add = databuf_lo_add,
++ .lo_incore_commit = buf_lo_incore_commit,
++ .lo_before_commit = databuf_lo_before_commit,
++ .lo_after_commit = databuf_lo_after_commit,
++ .lo_scan_elements = databuf_lo_scan_elements,
++ .lo_after_scan = databuf_lo_after_scan,
++ .lo_name = "databuf",
++};
++
++const struct gfs2_log_operations *gfs2_log_ops[] = {
++ &gfs2_glock_lops,
++ &gfs2_buf_lops,
++ &gfs2_revoke_lops,
++ &gfs2_rg_lops,
++ &gfs2_databuf_lops,
++ NULL,
++};
++
+diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h
+new file mode 100644
+index 0000000..5839c05
+--- /dev/null
++++ b/fs/gfs2/lops.h
+@@ -0,0 +1,99 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __LOPS_DOT_H__
++#define __LOPS_DOT_H__
++
++#include <linux/list.h>
++#include "incore.h"
++
++extern const struct gfs2_log_operations gfs2_glock_lops;
++extern const struct gfs2_log_operations gfs2_buf_lops;
++extern const struct gfs2_log_operations gfs2_revoke_lops;
++extern const struct gfs2_log_operations gfs2_rg_lops;
++extern const struct gfs2_log_operations gfs2_databuf_lops;
++
++extern const struct gfs2_log_operations *gfs2_log_ops[];
++
++static inline void lops_init_le(struct gfs2_log_element *le,
++ const struct gfs2_log_operations *lops)
++{
++ INIT_LIST_HEAD(&le->le_list);
++ le->le_ops = lops;
++}
++
++static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
++{
++ if (le->le_ops->lo_add)
++ le->le_ops->lo_add(sdp, le);
++}
++
++static inline void lops_incore_commit(struct gfs2_sbd *sdp,
++ struct gfs2_trans *tr)
++{
++ int x;
++ for (x = 0; gfs2_log_ops[x]; x++)
++ if (gfs2_log_ops[x]->lo_incore_commit)
++ gfs2_log_ops[x]->lo_incore_commit(sdp, tr);
++}
++
++static inline void lops_before_commit(struct gfs2_sbd *sdp)
++{
++ int x;
++ for (x = 0; gfs2_log_ops[x]; x++)
++ if (gfs2_log_ops[x]->lo_before_commit)
++ gfs2_log_ops[x]->lo_before_commit(sdp);
++}
++
++static inline void lops_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
++{
++ int x;
++ for (x = 0; gfs2_log_ops[x]; x++)
++ if (gfs2_log_ops[x]->lo_after_commit)
++ gfs2_log_ops[x]->lo_after_commit(sdp, ai);
++}
++
++static inline void lops_before_scan(struct gfs2_jdesc *jd,
++ struct gfs2_log_header *head,
++ unsigned int pass)
++{
++ int x;
++ for (x = 0; gfs2_log_ops[x]; x++)
++ if (gfs2_log_ops[x]->lo_before_scan)
++ gfs2_log_ops[x]->lo_before_scan(jd, head, pass);
++}
++
++static inline int lops_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
++ struct gfs2_log_descriptor *ld,
++ __be64 *ptr,
++ unsigned int pass)
++{
++ int x, error;
++ for (x = 0; gfs2_log_ops[x]; x++)
++ if (gfs2_log_ops[x]->lo_scan_elements) {
++ error = gfs2_log_ops[x]->lo_scan_elements(jd, start,
++ ld, ptr, pass);
++ if (error)
++ return error;
++ }
++
++ return 0;
++}
++
++static inline void lops_after_scan(struct gfs2_jdesc *jd, int error,
++ unsigned int pass)
++{
++ int x;
++ for (x = 0; gfs2_log_ops[x]; x++)
++ if (gfs2_log_ops[x]->lo_before_scan)
++ gfs2_log_ops[x]->lo_after_scan(jd, error, pass);
++}
++
++#endif /* __LOPS_DOT_H__ */
++
+diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
+new file mode 100644
+index 0000000..9889c1e
+--- /dev/null
++++ b/fs/gfs2/main.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++#include <asm/atomic.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "ops_fstype.h"
++#include "sys.h"
++#include "util.h"
++#include "glock.h"
++
++static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
++{
++ struct gfs2_inode *ip = foo;
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR) {
++ inode_init_once(&ip->i_inode);
++ spin_lock_init(&ip->i_spin);
++ init_rwsem(&ip->i_rw_mutex);
++ memset(ip->i_cache, 0, sizeof(ip->i_cache));
++ }
++}
++
++static void gfs2_init_glock_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
++{
++ struct gfs2_glock *gl = foo;
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR) {
++ INIT_HLIST_NODE(&gl->gl_list);
++ spin_lock_init(&gl->gl_spin);
++ INIT_LIST_HEAD(&gl->gl_holders);
++ INIT_LIST_HEAD(&gl->gl_waiters1);
++ INIT_LIST_HEAD(&gl->gl_waiters2);
++ INIT_LIST_HEAD(&gl->gl_waiters3);
++ gl->gl_lvb = NULL;
++ atomic_set(&gl->gl_lvb_count, 0);
++ INIT_LIST_HEAD(&gl->gl_reclaim);
++ INIT_LIST_HEAD(&gl->gl_ail_list);
++ atomic_set(&gl->gl_ail_count, 0);
++ }
++}
++
++/**
++ * init_gfs2_fs - Register GFS2 as a filesystem
++ *
++ * Returns: 0 on success, error code on failure
++ */
++
++static int __init init_gfs2_fs(void)
++{
++ int error;
++
++ error = gfs2_sys_init();
++ if (error)
++ return error;
++
++ error = gfs2_glock_init();
++ if (error)
++ goto fail;
++
++ error = -ENOMEM;
++ gfs2_glock_cachep = kmem_cache_create("gfs2_glock",
++ sizeof(struct gfs2_glock),
++ 0, 0,
++ gfs2_init_glock_once, NULL);
++ if (!gfs2_glock_cachep)
++ goto fail;
++
++ gfs2_inode_cachep = kmem_cache_create("gfs2_inode",
++ sizeof(struct gfs2_inode),
++ 0, SLAB_RECLAIM_ACCOUNT|
++ SLAB_MEM_SPREAD,
++ gfs2_init_inode_once, NULL);
++ if (!gfs2_inode_cachep)
++ goto fail;
++
++ gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
++ sizeof(struct gfs2_bufdata),
++ 0, 0, NULL, NULL);
++ if (!gfs2_bufdata_cachep)
++ goto fail;
++
++ error = register_filesystem(&gfs2_fs_type);
++ if (error)
++ goto fail;
++
++ error = register_filesystem(&gfs2meta_fs_type);
++ if (error)
++ goto fail_unregister;
++
++ printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
++
++ return 0;
++
++fail_unregister:
++ unregister_filesystem(&gfs2_fs_type);
++fail:
++ if (gfs2_bufdata_cachep)
++ kmem_cache_destroy(gfs2_bufdata_cachep);
++
++ if (gfs2_inode_cachep)
++ kmem_cache_destroy(gfs2_inode_cachep);
++
++ if (gfs2_glock_cachep)
++ kmem_cache_destroy(gfs2_glock_cachep);
++
++ gfs2_sys_uninit();
++ return error;
++}
++
++/**
++ * exit_gfs2_fs - Unregister the file system
++ *
++ */
++
++static void __exit exit_gfs2_fs(void)
++{
++ unregister_filesystem(&gfs2_fs_type);
++ unregister_filesystem(&gfs2meta_fs_type);
++
++ kmem_cache_destroy(gfs2_bufdata_cachep);
++ kmem_cache_destroy(gfs2_inode_cachep);
++ kmem_cache_destroy(gfs2_glock_cachep);
++
++ gfs2_sys_uninit();
++}
++
++MODULE_DESCRIPTION("Global File System");
++MODULE_AUTHOR("Red Hat, Inc.");
++MODULE_LICENSE("GPL");
++
++module_init(init_gfs2_fs);
++module_exit(exit_gfs2_fs);
++
+diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
+new file mode 100644
+index 0000000..3912d6a
+--- /dev/null
++++ b/fs/gfs2/meta_io.c
+@@ -0,0 +1,590 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/writeback.h>
++#include <linux/swap.h>
++#include <linux/delay.h>
++#include <linux/bio.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "log.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++#include "ops_address.h"
++
++static int aspace_get_block(struct inode *inode, sector_t lblock,
++ struct buffer_head *bh_result, int create)
++{
++ gfs2_assert_warn(inode->i_sb->s_fs_info, 0);
++ return -EOPNOTSUPP;
++}
++
++static int gfs2_aspace_writepage(struct page *page,
++ struct writeback_control *wbc)
++{
++ return block_write_full_page(page, aspace_get_block, wbc);
++}
++
++static const struct address_space_operations aspace_aops = {
++ .writepage = gfs2_aspace_writepage,
++ .releasepage = gfs2_releasepage,
++};
++
++/**
++ * gfs2_aspace_get - Create and initialize a struct inode structure
++ * @sdp: the filesystem the aspace is in
++ *
++ * Right now a struct inode is just a struct inode. Maybe Linux
++ * will supply a more lightweight address space construct (that works)
++ * in the future.
++ *
++ * Make sure pages/buffers in this aspace aren't in high memory.
++ *
++ * Returns: the aspace
++ */
++
++struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp)
++{
++ struct inode *aspace;
++
++ aspace = new_inode(sdp->sd_vfs);
++ if (aspace) {
++ mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS);
++ aspace->i_mapping->a_ops = &aspace_aops;
++ aspace->i_size = ~0ULL;
++ aspace->i_private = NULL;
++ insert_inode_hash(aspace);
++ }
++ return aspace;
++}
++
++void gfs2_aspace_put(struct inode *aspace)
++{
++ remove_inode_hash(aspace);
++ iput(aspace);
++}
++
++/**
++ * gfs2_meta_inval - Invalidate all buffers associated with a glock
++ * @gl: the glock
++ *
++ */
++
++void gfs2_meta_inval(struct gfs2_glock *gl)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct inode *aspace = gl->gl_aspace;
++ struct address_space *mapping = gl->gl_aspace->i_mapping;
++
++ gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
++
++ atomic_inc(&aspace->i_writecount);
++ truncate_inode_pages(mapping, 0);
++ atomic_dec(&aspace->i_writecount);
++
++ gfs2_assert_withdraw(sdp, !mapping->nrpages);
++}
++
++/**
++ * gfs2_meta_sync - Sync all buffers associated with a glock
++ * @gl: The glock
++ *
++ */
++
++void gfs2_meta_sync(struct gfs2_glock *gl)
++{
++ struct address_space *mapping = gl->gl_aspace->i_mapping;
++ int error;
++
++ filemap_fdatawrite(mapping);
++ error = filemap_fdatawait(mapping);
++
++ if (error)
++ gfs2_io_error(gl->gl_sbd);
++}
++
++/**
++ * getbuf - Get a buffer with a given address space
++ * @sdp: the filesystem
++ * @aspace: the address space
++ * @blkno: the block number (filesystem scope)
++ * @create: 1 if the buffer should be created
++ *
++ * Returns: the buffer
++ */
++
++static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace,
++ u64 blkno, int create)
++{
++ struct page *page;
++ struct buffer_head *bh;
++ unsigned int shift;
++ unsigned long index;
++ unsigned int bufnum;
++
++ shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift;
++ index = blkno >> shift; /* convert block to page */
++ bufnum = blkno - (index << shift); /* block buf index within page */
++
++ if (create) {
++ for (;;) {
++ page = grab_cache_page(aspace->i_mapping, index);
++ if (page)
++ break;
++ yield();
++ }
++ } else {
++ page = find_lock_page(aspace->i_mapping, index);
++ if (!page)
++ return NULL;
++ }
++
++ if (!page_has_buffers(page))
++ create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0);
++
++ /* Locate header for our buffer within our page */
++ for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page)
++ /* Do nothing */;
++ get_bh(bh);
++
++ if (!buffer_mapped(bh))
++ map_bh(bh, sdp->sd_vfs, blkno);
++
++ unlock_page(page);
++ mark_page_accessed(page);
++ page_cache_release(page);
++
++ return bh;
++}
++
++static void meta_prep_new(struct buffer_head *bh)
++{
++ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
++
++ lock_buffer(bh);
++ clear_buffer_dirty(bh);
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++
++ mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
++}
++
++/**
++ * gfs2_meta_new - Get a block
++ * @gl: The glock associated with this block
++ * @blkno: The block number
++ *
++ * Returns: The buffer
++ */
++
++struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
++{
++ struct buffer_head *bh;
++ bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
++ meta_prep_new(bh);
++ return bh;
++}
++
++/**
++ * gfs2_meta_read - Read a block from disk
++ * @gl: The glock covering the block
++ * @blkno: The block number
++ * @flags: flags
++ * @bhp: the place where the buffer is returned (NULL on failure)
++ *
++ * Returns: errno
++ */
++
++int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
++ struct buffer_head **bhp)
++{
++ *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
++ if (!buffer_uptodate(*bhp))
++ ll_rw_block(READ_META, 1, bhp);
++ if (flags & DIO_WAIT) {
++ int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
++ if (error) {
++ brelse(*bhp);
++ return error;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_meta_wait - Reread a block from disk
++ * @sdp: the filesystem
++ * @bh: The block to wait for
++ *
++ * Returns: errno
++ */
++
++int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
++{
++ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ return -EIO;
++
++ wait_on_buffer(bh);
++
++ if (!buffer_uptodate(bh)) {
++ struct gfs2_trans *tr = current->journal_info;
++ if (tr && tr->tr_touched)
++ gfs2_io_error_bh(sdp, bh);
++ return -EIO;
++ }
++ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ return -EIO;
++
++ return 0;
++}
++
++/**
++ * gfs2_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer
++ * @gl: the glock the buffer belongs to
++ * @bh: The buffer to be attached to
++ * @meta: Flag to indicate whether its metadata or not
++ */
++
++void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
++ int meta)
++{
++ struct gfs2_bufdata *bd;
++
++ if (meta)
++ lock_page(bh->b_page);
++
++ if (bh->b_private) {
++ if (meta)
++ unlock_page(bh->b_page);
++ return;
++ }
++
++ bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL),
++ memset(bd, 0, sizeof(struct gfs2_bufdata));
++ bd->bd_bh = bh;
++ bd->bd_gl = gl;
++
++ INIT_LIST_HEAD(&bd->bd_list_tr);
++ if (meta)
++ lops_init_le(&bd->bd_le, &gfs2_buf_lops);
++ else
++ lops_init_le(&bd->bd_le, &gfs2_databuf_lops);
++ bh->b_private = bd;
++
++ if (meta)
++ unlock_page(bh->b_page);
++}
++
++/**
++ * gfs2_pin - Pin a buffer in memory
++ * @sdp: the filesystem the buffer belongs to
++ * @bh: The buffer to be pinned
++ *
++ */
++
++void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
++{
++ struct gfs2_bufdata *bd = bh->b_private;
++
++ gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
++
++ if (test_set_buffer_pinned(bh))
++ gfs2_assert_withdraw(sdp, 0);
++
++ wait_on_buffer(bh);
++
++ /* If this buffer is in the AIL and it has already been written
++ to in-place disk block, remove it from the AIL. */
++
++ gfs2_log_lock(sdp);
++ if (bd->bd_ail && !buffer_in_io(bh))
++ list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
++ gfs2_log_unlock(sdp);
++
++ clear_buffer_dirty(bh);
++ wait_on_buffer(bh);
++
++ if (!buffer_uptodate(bh))
++ gfs2_io_error_bh(sdp, bh);
++
++ get_bh(bh);
++}
++
++/**
++ * gfs2_unpin - Unpin a buffer
++ * @sdp: the filesystem the buffer belongs to
++ * @bh: The buffer to unpin
++ * @ai:
++ *
++ */
++
++void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ struct gfs2_ail *ai)
++{
++ struct gfs2_bufdata *bd = bh->b_private;
++
++ gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
++
++ if (!buffer_pinned(bh))
++ gfs2_assert_withdraw(sdp, 0);
++
++ mark_buffer_dirty(bh);
++ clear_buffer_pinned(bh);
++
++ gfs2_log_lock(sdp);
++ if (bd->bd_ail) {
++ list_del(&bd->bd_ail_st_list);
++ brelse(bh);
++ } else {
++ struct gfs2_glock *gl = bd->bd_gl;
++ list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
++ atomic_inc(&gl->gl_ail_count);
++ }
++ bd->bd_ail = ai;
++ list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
++ gfs2_log_unlock(sdp);
++}
++
++/**
++ * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore
++ * @ip: the inode who owns the buffers
++ * @bstart: the first buffer in the run
++ * @blen: the number of buffers in the run
++ *
++ */
++
++void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct inode *aspace = ip->i_gl->gl_aspace;
++ struct buffer_head *bh;
++
++ while (blen) {
++ bh = getbuf(sdp, aspace, bstart, NO_CREATE);
++ if (bh) {
++ struct gfs2_bufdata *bd = bh->b_private;
++
++ if (test_clear_buffer_pinned(bh)) {
++ struct gfs2_trans *tr = current->journal_info;
++ gfs2_log_lock(sdp);
++ list_del_init(&bd->bd_le.le_list);
++ gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
++ sdp->sd_log_num_buf--;
++ gfs2_log_unlock(sdp);
++ tr->tr_num_buf_rm++;
++ brelse(bh);
++ }
++ if (bd) {
++ gfs2_log_lock(sdp);
++ if (bd->bd_ail) {
++ u64 blkno = bh->b_blocknr;
++ bd->bd_ail = NULL;
++ list_del(&bd->bd_ail_st_list);
++ list_del(&bd->bd_ail_gl_list);
++ atomic_dec(&bd->bd_gl->gl_ail_count);
++ brelse(bh);
++ gfs2_log_unlock(sdp);
++ gfs2_trans_add_revoke(sdp, blkno);
++ } else
++ gfs2_log_unlock(sdp);
++ }
++
++ lock_buffer(bh);
++ clear_buffer_dirty(bh);
++ clear_buffer_uptodate(bh);
++ unlock_buffer(bh);
++
++ brelse(bh);
++ }
++
++ bstart++;
++ blen--;
++ }
++}
++
++/**
++ * gfs2_meta_cache_flush - get rid of any references on buffers for this inode
++ * @ip: The GFS2 inode
++ *
++ * This releases buffers that are in the most-recently-used array of
++ * blocks used for indirect block addressing for this inode.
++ */
++
++void gfs2_meta_cache_flush(struct gfs2_inode *ip)
++{
++ struct buffer_head **bh_slot;
++ unsigned int x;
++
++ spin_lock(&ip->i_spin);
++
++ for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
++ bh_slot = &ip->i_cache[x];
++ if (!*bh_slot)
++ break;
++ brelse(*bh_slot);
++ *bh_slot = NULL;
++ }
++
++ spin_unlock(&ip->i_spin);
++}
++
++/**
++ * gfs2_meta_indirect_buffer - Get a metadata buffer
++ * @ip: The GFS2 inode
++ * @height: The level of this buf in the metadata (indir addr) tree (if any)
++ * @num: The block number (device relative) of the buffer
++ * @new: Non-zero if we may create a new buffer
++ * @bhp: the buffer is returned here
++ *
++ * Try to use the gfs2_inode's MRU metadata tree cache.
++ *
++ * Returns: errno
++ */
++
++int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
++ int new, struct buffer_head **bhp)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_glock *gl = ip->i_gl;
++ struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
++ int in_cache = 0;
++
++ spin_lock(&ip->i_spin);
++ if (*bh_slot && (*bh_slot)->b_blocknr == num) {
++ bh = *bh_slot;
++ get_bh(bh);
++ in_cache = 1;
++ }
++ spin_unlock(&ip->i_spin);
++
++ if (!bh)
++ bh = getbuf(gl->gl_sbd, gl->gl_aspace, num, CREATE);
++
++ if (!bh)
++ return -ENOBUFS;
++
++ if (new) {
++ if (gfs2_assert_warn(sdp, height))
++ goto err;
++ meta_prep_new(bh);
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
++ gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
++ } else {
++ u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
++ if (!buffer_uptodate(bh)) {
++ ll_rw_block(READ_META, 1, &bh);
++ if (gfs2_meta_wait(sdp, bh))
++ goto err;
++ }
++ if (gfs2_metatype_check(sdp, bh, mtype))
++ goto err;
++ }
++
++ if (!in_cache) {
++ spin_lock(&ip->i_spin);
++ if (*bh_slot)
++ brelse(*bh_slot);
++ *bh_slot = bh;
++ get_bh(bh);
++ spin_unlock(&ip->i_spin);
++ }
++
++ *bhp = bh;
++ return 0;
++err:
++ brelse(bh);
++ return -EIO;
++}
++
++/**
++ * gfs2_meta_ra - start readahead on an extent of a file
++ * @gl: the glock the blocks belong to
++ * @dblock: the starting disk block
++ * @extlen: the number of blocks in the extent
++ *
++ * returns: the first buffer in the extent
++ */
++
++struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct inode *aspace = gl->gl_aspace;
++ struct buffer_head *first_bh, *bh;
++ u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >>
++ sdp->sd_sb.sb_bsize_shift;
++
++ BUG_ON(!extlen);
++
++ if (max_ra < 1)
++ max_ra = 1;
++ if (extlen > max_ra)
++ extlen = max_ra;
++
++ first_bh = getbuf(sdp, aspace, dblock, CREATE);
++
++ if (buffer_uptodate(first_bh))
++ goto out;
++ if (!buffer_locked(first_bh))
++ ll_rw_block(READ_META, 1, &first_bh);
++
++ dblock++;
++ extlen--;
++
++ while (extlen) {
++ bh = getbuf(sdp, aspace, dblock, CREATE);
++
++ if (!buffer_uptodate(bh) && !buffer_locked(bh))
++ ll_rw_block(READA, 1, &bh);
++ brelse(bh);
++ dblock++;
++ extlen--;
++ if (!buffer_locked(first_bh) && buffer_uptodate(first_bh))
++ goto out;
++ }
++
++ wait_on_buffer(first_bh);
++out:
++ return first_bh;
++}
++
++/**
++ * gfs2_meta_syncfs - sync all the buffers in a filesystem
++ * @sdp: the filesystem
++ *
++ */
++
++void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
++{
++ gfs2_log_flush(sdp, NULL);
++ for (;;) {
++ gfs2_ail1_start(sdp, DIO_ALL);
++ if (gfs2_ail1_empty(sdp, DIO_ALL))
++ break;
++ msleep(10);
++ }
++}
++
+diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
+new file mode 100644
+index 0000000..3ec939e
+--- /dev/null
++++ b/fs/gfs2/meta_io.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __DIO_DOT_H__
++#define __DIO_DOT_H__
++
++#include <linux/buffer_head.h>
++#include <linux/string.h>
++#include "incore.h"
++
++static inline void gfs2_buffer_clear(struct buffer_head *bh)
++{
++ memset(bh->b_data, 0, bh->b_size);
++}
++
++static inline void gfs2_buffer_clear_tail(struct buffer_head *bh, int head)
++{
++ BUG_ON(head > bh->b_size);
++ memset(bh->b_data + head, 0, bh->b_size - head);
++}
++
++static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh,
++ int to_head,
++ struct buffer_head *from_bh,
++ int from_head)
++{
++ BUG_ON(from_head < to_head);
++ memcpy(to_bh->b_data + to_head, from_bh->b_data + from_head,
++ from_bh->b_size - from_head);
++ memset(to_bh->b_data + to_bh->b_size + to_head - from_head,
++ 0, from_head - to_head);
++}
++
++struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp);
++void gfs2_aspace_put(struct inode *aspace);
++
++void gfs2_meta_inval(struct gfs2_glock *gl);
++void gfs2_meta_sync(struct gfs2_glock *gl);
++
++struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
++int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno,
++ int flags, struct buffer_head **bhp);
++int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
++
++void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
++ int meta);
++void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
++void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ struct gfs2_ail *ai);
++
++void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
++
++void gfs2_meta_cache_flush(struct gfs2_inode *ip);
++int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
++ int new, struct buffer_head **bhp);
++
++static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip,
++ struct buffer_head **bhp)
++{
++ return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp);
++}
++
++struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen);
++void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
++
++#define buffer_busy(bh) \
++((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned)))
++#define buffer_in_io(bh) \
++((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock)))
++
++#endif /* __DIO_DOT_H__ */
++
+diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
+new file mode 100644
+index 0000000..ef3092e
+--- /dev/null
++++ b/fs/gfs2/mount.c
+@@ -0,0 +1,214 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "mount.h"
++#include "sys.h"
++#include "util.h"
++
++/**
++ * gfs2_mount_args - Parse mount options
++ * @sdp:
++ * @data:
++ *
++ * Return: errno
++ */
++
++int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
++{
++ struct gfs2_args *args = &sdp->sd_args;
++ char *data = data_arg;
++ char *options, *o, *v;
++ int error = 0;
++
++ if (!remount) {
++ /* If someone preloaded options, use those instead */
++ spin_lock(&gfs2_sys_margs_lock);
++ if (gfs2_sys_margs) {
++ data = gfs2_sys_margs;
++ gfs2_sys_margs = NULL;
++ }
++ spin_unlock(&gfs2_sys_margs_lock);
++
++ /* Set some defaults */
++ args->ar_num_glockd = GFS2_GLOCKD_DEFAULT;
++ args->ar_quota = GFS2_QUOTA_DEFAULT;
++ args->ar_data = GFS2_DATA_DEFAULT;
++ }
++
++ /* Split the options into tokens with the "," character and
++ process them */
++
++ for (options = data; (o = strsep(&options, ",")); ) {
++ if (!*o)
++ continue;
++
++ v = strchr(o, '=');
++ if (v)
++ *v++ = 0;
++
++ if (!strcmp(o, "lockproto")) {
++ if (!v)
++ goto need_value;
++ if (remount && strcmp(v, args->ar_lockproto))
++ goto cant_remount;
++ strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
++ args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
++ }
++
++ else if (!strcmp(o, "locktable")) {
++ if (!v)
++ goto need_value;
++ if (remount && strcmp(v, args->ar_locktable))
++ goto cant_remount;
++ strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
++ args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
++ }
++
++ else if (!strcmp(o, "hostdata")) {
++ if (!v)
++ goto need_value;
++ if (remount && strcmp(v, args->ar_hostdata))
++ goto cant_remount;
++ strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
++ args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
++ }
++
++ else if (!strcmp(o, "spectator")) {
++ if (remount && !args->ar_spectator)
++ goto cant_remount;
++ args->ar_spectator = 1;
++ sdp->sd_vfs->s_flags |= MS_RDONLY;
++ }
++
++ else if (!strcmp(o, "ignore_local_fs")) {
++ if (remount && !args->ar_ignore_local_fs)
++ goto cant_remount;
++ args->ar_ignore_local_fs = 1;
++ }
++
++ else if (!strcmp(o, "localflocks")) {
++ if (remount && !args->ar_localflocks)
++ goto cant_remount;
++ args->ar_localflocks = 1;
++ }
++
++ else if (!strcmp(o, "localcaching")) {
++ if (remount && !args->ar_localcaching)
++ goto cant_remount;
++ args->ar_localcaching = 1;
++ }
++
++ else if (!strcmp(o, "debug"))
++ args->ar_debug = 1;
++
++ else if (!strcmp(o, "nodebug"))
++ args->ar_debug = 0;
++
++ else if (!strcmp(o, "upgrade")) {
++ if (remount && !args->ar_upgrade)
++ goto cant_remount;
++ args->ar_upgrade = 1;
++ }
++
++ else if (!strcmp(o, "num_glockd")) {
++ unsigned int x;
++ if (!v)
++ goto need_value;
++ sscanf(v, "%u", &x);
++ if (remount && x != args->ar_num_glockd)
++ goto cant_remount;
++ if (!x || x > GFS2_GLOCKD_MAX) {
++ fs_info(sdp, "0 < num_glockd <= %u (not %u)\n",
++ GFS2_GLOCKD_MAX, x);
++ error = -EINVAL;
++ break;
++ }
++ args->ar_num_glockd = x;
++ }
++
++ else if (!strcmp(o, "acl")) {
++ args->ar_posix_acl = 1;
++ sdp->sd_vfs->s_flags |= MS_POSIXACL;
++ }
++
++ else if (!strcmp(o, "noacl")) {
++ args->ar_posix_acl = 0;
++ sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
++ }
++
++ else if (!strcmp(o, "quota")) {
++ if (!v)
++ goto need_value;
++ if (!strcmp(v, "off"))
++ args->ar_quota = GFS2_QUOTA_OFF;
++ else if (!strcmp(v, "account"))
++ args->ar_quota = GFS2_QUOTA_ACCOUNT;
++ else if (!strcmp(v, "on"))
++ args->ar_quota = GFS2_QUOTA_ON;
++ else {
++ fs_info(sdp, "invalid value for quota\n");
++ error = -EINVAL;
++ break;
++ }
++ }
++
++ else if (!strcmp(o, "suiddir"))
++ args->ar_suiddir = 1;
++
++ else if (!strcmp(o, "nosuiddir"))
++ args->ar_suiddir = 0;
++
++ else if (!strcmp(o, "data")) {
++ if (!v)
++ goto need_value;
++ if (!strcmp(v, "writeback"))
++ args->ar_data = GFS2_DATA_WRITEBACK;
++ else if (!strcmp(v, "ordered"))
++ args->ar_data = GFS2_DATA_ORDERED;
++ else {
++ fs_info(sdp, "invalid value for data\n");
++ error = -EINVAL;
++ break;
++ }
++ }
++
++ else {
++ fs_info(sdp, "unknown option: %s\n", o);
++ error = -EINVAL;
++ break;
++ }
++ }
++
++ if (error)
++ fs_info(sdp, "invalid mount option(s)\n");
++
++ if (data != data_arg)
++ kfree(data);
++
++ return error;
++
++need_value:
++ fs_info(sdp, "need value for option %s\n", o);
++ return -EINVAL;
++
++cant_remount:
++ fs_info(sdp, "can't remount with option %s\n", o);
++ return -EINVAL;
++}
++
+diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h
+new file mode 100644
+index 0000000..401288a
+--- /dev/null
++++ b/fs/gfs2/mount.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __MOUNT_DOT_H__
++#define __MOUNT_DOT_H__
++
++struct gfs2_sbd;
++
++int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount);
++
++#endif /* __MOUNT_DOT_H__ */
+diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c
+new file mode 100644
+index 0000000..1025960
+--- /dev/null
++++ b/fs/gfs2/ondisk.c
+@@ -0,0 +1,308 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++
++#include "gfs2.h"
++#include <linux/gfs2_ondisk.h>
++
++#define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", \
++ struct->member);
++
++/*
++ * gfs2_xxx_in - read in an xxx struct
++ * first arg: the cpu-order structure
++ * buf: the disk-order buffer
++ *
++ * gfs2_xxx_out - write out an xxx struct
++ * first arg: the cpu-order structure
++ * buf: the disk-order buffer
++ *
++ * gfs2_xxx_print - print out an xxx struct
++ * first arg: the cpu-order structure
++ */
++
++void gfs2_inum_in(struct gfs2_inum *no, const void *buf)
++{
++ const struct gfs2_inum *str = buf;
++
++ no->no_formal_ino = be64_to_cpu(str->no_formal_ino);
++ no->no_addr = be64_to_cpu(str->no_addr);
++}
++
++void gfs2_inum_out(const struct gfs2_inum *no, void *buf)
++{
++ struct gfs2_inum *str = buf;
++
++ str->no_formal_ino = cpu_to_be64(no->no_formal_ino);
++ str->no_addr = cpu_to_be64(no->no_addr);
++}
++
++static void gfs2_inum_print(const struct gfs2_inum *no)
++{
++ printk(KERN_INFO " no_formal_ino = %llu\n", (unsigned long long)no->no_formal_ino);
++ printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr);
++}
++
++static void gfs2_meta_header_in(struct gfs2_meta_header *mh, const void *buf)
++{
++ const struct gfs2_meta_header *str = buf;
++
++ mh->mh_magic = be32_to_cpu(str->mh_magic);
++ mh->mh_type = be32_to_cpu(str->mh_type);
++ mh->mh_format = be32_to_cpu(str->mh_format);
++}
++
++static void gfs2_meta_header_out(const struct gfs2_meta_header *mh, void *buf)
++{
++ struct gfs2_meta_header *str = buf;
++
++ str->mh_magic = cpu_to_be32(mh->mh_magic);
++ str->mh_type = cpu_to_be32(mh->mh_type);
++ str->mh_format = cpu_to_be32(mh->mh_format);
++}
++
++static void gfs2_meta_header_print(const struct gfs2_meta_header *mh)
++{
++ pv(mh, mh_magic, "0x%.8X");
++ pv(mh, mh_type, "%u");
++ pv(mh, mh_format, "%u");
++}
++
++void gfs2_sb_in(struct gfs2_sb *sb, const void *buf)
++{
++ const struct gfs2_sb *str = buf;
++
++ gfs2_meta_header_in(&sb->sb_header, buf);
++
++ sb->sb_fs_format = be32_to_cpu(str->sb_fs_format);
++ sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format);
++ sb->sb_bsize = be32_to_cpu(str->sb_bsize);
++ sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift);
++
++ gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir);
++ gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir);
++
++ memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
++ memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
++}
++
++void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf)
++{
++ const struct gfs2_rindex *str = buf;
++
++ ri->ri_addr = be64_to_cpu(str->ri_addr);
++ ri->ri_length = be32_to_cpu(str->ri_length);
++ ri->ri_data0 = be64_to_cpu(str->ri_data0);
++ ri->ri_data = be32_to_cpu(str->ri_data);
++ ri->ri_bitbytes = be32_to_cpu(str->ri_bitbytes);
++
++}
++
++void gfs2_rindex_print(const struct gfs2_rindex *ri)
++{
++ printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)ri->ri_addr);
++ pv(ri, ri_length, "%u");
++
++ printk(KERN_INFO " ri_data0 = %llu\n", (unsigned long long)ri->ri_data0);
++ pv(ri, ri_data, "%u");
++
++ pv(ri, ri_bitbytes, "%u");
++}
++
++void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf)
++{
++ const struct gfs2_rgrp *str = buf;
++
++ gfs2_meta_header_in(&rg->rg_header, buf);
++ rg->rg_flags = be32_to_cpu(str->rg_flags);
++ rg->rg_free = be32_to_cpu(str->rg_free);
++ rg->rg_dinodes = be32_to_cpu(str->rg_dinodes);
++ rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);
++}
++
++void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf)
++{
++ struct gfs2_rgrp *str = buf;
++
++ gfs2_meta_header_out(&rg->rg_header, buf);
++ str->rg_flags = cpu_to_be32(rg->rg_flags);
++ str->rg_free = cpu_to_be32(rg->rg_free);
++ str->rg_dinodes = cpu_to_be32(rg->rg_dinodes);
++ str->__pad = cpu_to_be32(0);
++ str->rg_igeneration = cpu_to_be64(rg->rg_igeneration);
++ memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));
++}
++
++void gfs2_quota_in(struct gfs2_quota *qu, const void *buf)
++{
++ const struct gfs2_quota *str = buf;
++
++ qu->qu_limit = be64_to_cpu(str->qu_limit);
++ qu->qu_warn = be64_to_cpu(str->qu_warn);
++ qu->qu_value = be64_to_cpu(str->qu_value);
++}
++
++void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf)
++{
++ const struct gfs2_dinode *str = buf;
++
++ gfs2_meta_header_in(&di->di_header, buf);
++ gfs2_inum_in(&di->di_num, &str->di_num);
++
++ di->di_mode = be32_to_cpu(str->di_mode);
++ di->di_uid = be32_to_cpu(str->di_uid);
++ di->di_gid = be32_to_cpu(str->di_gid);
++ di->di_nlink = be32_to_cpu(str->di_nlink);
++ di->di_size = be64_to_cpu(str->di_size);
++ di->di_blocks = be64_to_cpu(str->di_blocks);
++ di->di_atime = be64_to_cpu(str->di_atime);
++ di->di_mtime = be64_to_cpu(str->di_mtime);
++ di->di_ctime = be64_to_cpu(str->di_ctime);
++ di->di_major = be32_to_cpu(str->di_major);
++ di->di_minor = be32_to_cpu(str->di_minor);
++
++ di->di_goal_meta = be64_to_cpu(str->di_goal_meta);
++ di->di_goal_data = be64_to_cpu(str->di_goal_data);
++ di->di_generation = be64_to_cpu(str->di_generation);
++
++ di->di_flags = be32_to_cpu(str->di_flags);
++ di->di_payload_format = be32_to_cpu(str->di_payload_format);
++ di->di_height = be16_to_cpu(str->di_height);
++
++ di->di_depth = be16_to_cpu(str->di_depth);
++ di->di_entries = be32_to_cpu(str->di_entries);
++
++ di->di_eattr = be64_to_cpu(str->di_eattr);
++
++}
++
++void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf)
++{
++ struct gfs2_dinode *str = buf;
++
++ gfs2_meta_header_out(&di->di_header, buf);
++ gfs2_inum_out(&di->di_num, (char *)&str->di_num);
++
++ str->di_mode = cpu_to_be32(di->di_mode);
++ str->di_uid = cpu_to_be32(di->di_uid);
++ str->di_gid = cpu_to_be32(di->di_gid);
++ str->di_nlink = cpu_to_be32(di->di_nlink);
++ str->di_size = cpu_to_be64(di->di_size);
++ str->di_blocks = cpu_to_be64(di->di_blocks);
++ str->di_atime = cpu_to_be64(di->di_atime);
++ str->di_mtime = cpu_to_be64(di->di_mtime);
++ str->di_ctime = cpu_to_be64(di->di_ctime);
++ str->di_major = cpu_to_be32(di->di_major);
++ str->di_minor = cpu_to_be32(di->di_minor);
++
++ str->di_goal_meta = cpu_to_be64(di->di_goal_meta);
++ str->di_goal_data = cpu_to_be64(di->di_goal_data);
++ str->di_generation = cpu_to_be64(di->di_generation);
++
++ str->di_flags = cpu_to_be32(di->di_flags);
++ str->di_payload_format = cpu_to_be32(di->di_payload_format);
++ str->di_height = cpu_to_be16(di->di_height);
++
++ str->di_depth = cpu_to_be16(di->di_depth);
++ str->di_entries = cpu_to_be32(di->di_entries);
++
++ str->di_eattr = cpu_to_be64(di->di_eattr);
++
++}
++
++void gfs2_dinode_print(const struct gfs2_dinode *di)
++{
++ gfs2_meta_header_print(&di->di_header);
++ gfs2_inum_print(&di->di_num);
++
++ pv(di, di_mode, "0%o");
++ pv(di, di_uid, "%u");
++ pv(di, di_gid, "%u");
++ pv(di, di_nlink, "%u");
++ printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size);
++ printk(KERN_INFO " di_blocks = %llu\n", (unsigned long long)di->di_blocks);
++ printk(KERN_INFO " di_atime = %lld\n", (long long)di->di_atime);
++ printk(KERN_INFO " di_mtime = %lld\n", (long long)di->di_mtime);
++ printk(KERN_INFO " di_ctime = %lld\n", (long long)di->di_ctime);
++ pv(di, di_major, "%u");
++ pv(di, di_minor, "%u");
++
++ printk(KERN_INFO " di_goal_meta = %llu\n", (unsigned long long)di->di_goal_meta);
++ printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data);
++
++ pv(di, di_flags, "0x%.8X");
++ pv(di, di_payload_format, "%u");
++ pv(di, di_height, "%u");
++
++ pv(di, di_depth, "%u");
++ pv(di, di_entries, "%u");
++
++ printk(KERN_INFO " di_eattr = %llu\n", (unsigned long long)di->di_eattr);
++}
++
++void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf)
++{
++ const struct gfs2_log_header *str = buf;
++
++ gfs2_meta_header_in(&lh->lh_header, buf);
++ lh->lh_sequence = be64_to_cpu(str->lh_sequence);
++ lh->lh_flags = be32_to_cpu(str->lh_flags);
++ lh->lh_tail = be32_to_cpu(str->lh_tail);
++ lh->lh_blkno = be32_to_cpu(str->lh_blkno);
++ lh->lh_hash = be32_to_cpu(str->lh_hash);
++}
++
++void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf)
++{
++ const struct gfs2_inum_range *str = buf;
++
++ ir->ir_start = be64_to_cpu(str->ir_start);
++ ir->ir_length = be64_to_cpu(str->ir_length);
++}
++
++void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf)
++{
++ struct gfs2_inum_range *str = buf;
++
++ str->ir_start = cpu_to_be64(ir->ir_start);
++ str->ir_length = cpu_to_be64(ir->ir_length);
++}
++
++void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf)
++{
++ const struct gfs2_statfs_change *str = buf;
++
++ sc->sc_total = be64_to_cpu(str->sc_total);
++ sc->sc_free = be64_to_cpu(str->sc_free);
++ sc->sc_dinodes = be64_to_cpu(str->sc_dinodes);
++}
++
++void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf)
++{
++ struct gfs2_statfs_change *str = buf;
++
++ str->sc_total = cpu_to_be64(sc->sc_total);
++ str->sc_free = cpu_to_be64(sc->sc_free);
++ str->sc_dinodes = cpu_to_be64(sc->sc_dinodes);
++}
++
++void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf)
++{
++ const struct gfs2_quota_change *str = buf;
++
++ qc->qc_change = be64_to_cpu(str->qc_change);
++ qc->qc_flags = be32_to_cpu(str->qc_flags);
++ qc->qc_id = be32_to_cpu(str->qc_id);
++}
++
+diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
+new file mode 100644
+index 0000000..015640b
+--- /dev/null
++++ b/fs/gfs2/ops_address.c
+@@ -0,0 +1,786 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/pagemap.h>
++#include <linux/pagevec.h>
++#include <linux/mpage.h>
++#include <linux/fs.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "inode.h"
++#include "log.h"
++#include "meta_io.h"
++#include "ops_address.h"
++#include "quota.h"
++#include "trans.h"
++#include "rgrp.h"
++#include "ops_file.h"
++#include "util.h"
++#include "glops.h"
++
++
++static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
++ unsigned int from, unsigned int to)
++{
++ struct buffer_head *head = page_buffers(page);
++ unsigned int bsize = head->b_size;
++ struct buffer_head *bh;
++ unsigned int start, end;
++
++ for (bh = head, start = 0; bh != head || !start;
++ bh = bh->b_this_page, start = end) {
++ end = start + bsize;
++ if (end <= from || start >= to)
++ continue;
++ gfs2_trans_add_bh(ip->i_gl, bh, 0);
++ }
++}
++
++/**
++ * gfs2_get_block - Fills in a buffer head with details about a block
++ * @inode: The inode
++ * @lblock: The block number to look up
++ * @bh_result: The buffer head to return the result in
++ * @create: Non-zero if we may add block to the file
++ *
++ * Returns: errno
++ */
++
++int gfs2_get_block(struct inode *inode, sector_t lblock,
++ struct buffer_head *bh_result, int create)
++{
++ return gfs2_block_map(inode, lblock, create, bh_result);
++}
++
++/**
++ * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
++ * @inode: The inode
++ * @lblock: The block number to look up
++ * @bh_result: The buffer head to return the result in
++ * @create: Non-zero if we may add block to the file
++ *
++ * Returns: errno
++ */
++
++static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
++ struct buffer_head *bh_result, int create)
++{
++ int error;
++
++ error = gfs2_block_map(inode, lblock, 0, bh_result);
++ if (error)
++ return error;
++ if (bh_result->b_blocknr == 0)
++ return -EIO;
++ return 0;
++}
++
++static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
++ struct buffer_head *bh_result, int create)
++{
++ return gfs2_block_map(inode, lblock, 0, bh_result);
++}
++
++/**
++ * gfs2_writepage - Write complete page
++ * @page: Page to write
++ *
++ * Returns: errno
++ *
++ * Some of this is copied from block_write_full_page() although we still
++ * call it to do most of the work.
++ */
++
++static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
++{
++ struct inode *inode = page->mapping->host;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ loff_t i_size = i_size_read(inode);
++ pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
++ unsigned offset;
++ int error;
++ int done_trans = 0;
++
++ if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
++ unlock_page(page);
++ return -EIO;
++ }
++ if (current->journal_info)
++ goto out_ignore;
++
++ /* Is the page fully outside i_size? (truncate in progress) */
++ offset = i_size & (PAGE_CACHE_SIZE-1);
++ if (page->index > end_index || (page->index == end_index && !offset)) {
++ page->mapping->a_ops->invalidatepage(page, 0);
++ unlock_page(page);
++ return 0; /* don't care */
++ }
++
++ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) {
++ error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
++ if (error)
++ goto out_ignore;
++ if (!page_has_buffers(page)) {
++ create_empty_buffers(page, inode->i_sb->s_blocksize,
++ (1 << BH_Dirty)|(1 << BH_Uptodate));
++ }
++ gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
++ done_trans = 1;
++ }
++ error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++ if (done_trans)
++ gfs2_trans_end(sdp);
++ gfs2_meta_cache_flush(ip);
++ return error;
++
++out_ignore:
++ redirty_page_for_writepage(wbc, page);
++ unlock_page(page);
++ return 0;
++}
++
++static int zero_readpage(struct page *page)
++{
++ void *kaddr;
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr, 0, PAGE_CACHE_SIZE);
++ kunmap_atomic(kaddr, KM_USER0);
++
++ SetPageUptodate(page);
++
++ return 0;
++}
++
++/**
++ * stuffed_readpage - Fill in a Linux page with stuffed file data
++ * @ip: the inode
++ * @page: the page
++ *
++ * Returns: errno
++ */
++
++static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
++{
++ struct buffer_head *dibh;
++ void *kaddr;
++ int error;
++
++ /* Only the first page of a stuffed file might contain data */
++ if (unlikely(page->index))
++ return zero_readpage(page);
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ return error;
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
++ ip->i_di.di_size);
++ memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
++ kunmap_atomic(kaddr, KM_USER0);
++
++ brelse(dibh);
++
++ SetPageUptodate(page);
++
++ return 0;
++}
++
++
++/**
++ * gfs2_readpage - readpage with locking
++ * @file: The file to read a page for. N.B. This may be NULL if we are
++ * reading an internal file.
++ * @page: The page to read
++ *
++ * Returns: errno
++ */
++
++static int gfs2_readpage(struct file *file, struct page *page)
++{
++ struct gfs2_inode *ip = GFS2_I(page->mapping->host);
++ struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
++ struct gfs2_file *gf = NULL;
++ struct gfs2_holder gh;
++ int error;
++ int do_unlock = 0;
++
++ if (likely(file != &gfs2_internal_file_sentinel)) {
++ if (file) {
++ gf = file->private_data;
++ if (test_bit(GFF_EXLOCK, &gf->f_flags))
++ /* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */
++ goto skip_lock;
++ }
++ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
++ do_unlock = 1;
++ error = gfs2_glock_nq_m_atime(1, &gh);
++ if (unlikely(error))
++ goto out_unlock;
++ }
++
++skip_lock:
++ if (gfs2_is_stuffed(ip)) {
++ error = stuffed_readpage(ip, page);
++ unlock_page(page);
++ } else
++ error = mpage_readpage(page, gfs2_get_block);
++
++ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ error = -EIO;
++
++ if (do_unlock) {
++ gfs2_glock_dq_m(1, &gh);
++ gfs2_holder_uninit(&gh);
++ }
++out:
++ return error;
++out_unlock:
++ unlock_page(page);
++ if (do_unlock)
++ gfs2_holder_uninit(&gh);
++ goto out;
++}
++
++/**
++ * gfs2_readpages - Read a bunch of pages at once
++ *
++ * Some notes:
++ * 1. This is only for readahead, so we can simply ignore any things
++ * which are slightly inconvenient (such as locking conflicts between
++ * the page lock and the glock) and return having done no I/O. Its
++ * obviously not something we'd want to do on too regular a basis.
++ * Any I/O we ignore at this time will be done via readpage later.
++ * 2. We have to handle stuffed files here too.
++ * 3. mpage_readpages() does most of the heavy lifting in the common case.
++ * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
++ * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
++ * well as read-ahead.
++ */
++static int gfs2_readpages(struct file *file, struct address_space *mapping,
++ struct list_head *pages, unsigned nr_pages)
++{
++ struct inode *inode = mapping->host;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ struct gfs2_holder gh;
++ unsigned page_idx;
++ int ret;
++ int do_unlock = 0;
++
++ if (likely(file != &gfs2_internal_file_sentinel)) {
++ if (file) {
++ struct gfs2_file *gf = file->private_data;
++ if (test_bit(GFF_EXLOCK, &gf->f_flags))
++ goto skip_lock;
++ }
++ gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
++ LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
++ do_unlock = 1;
++ ret = gfs2_glock_nq_m_atime(1, &gh);
++ if (ret == GLR_TRYFAILED)
++ goto out_noerror;
++ if (unlikely(ret))
++ goto out_unlock;
++ }
++skip_lock:
++ if (gfs2_is_stuffed(ip)) {
++ struct pagevec lru_pvec;
++ pagevec_init(&lru_pvec, 0);
++ for (page_idx = 0; page_idx < nr_pages; page_idx++) {
++ struct page *page = list_entry(pages->prev, struct page, lru);
++ prefetchw(&page->flags);
++ list_del(&page->lru);
++ if (!add_to_page_cache(page, mapping,
++ page->index, GFP_KERNEL)) {
++ ret = stuffed_readpage(ip, page);
++ unlock_page(page);
++ if (!pagevec_add(&lru_pvec, page))
++ __pagevec_lru_add(&lru_pvec);
++ } else {
++ page_cache_release(page);
++ }
++ }
++ pagevec_lru_add(&lru_pvec);
++ ret = 0;
++ } else {
++ /* What we really want to do .... */
++ ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
++ }
++
++ if (do_unlock) {
++ gfs2_glock_dq_m(1, &gh);
++ gfs2_holder_uninit(&gh);
++ }
++out:
++ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
++ ret = -EIO;
++ return ret;
++out_noerror:
++ ret = 0;
++out_unlock:
++ if (do_unlock)
++ gfs2_holder_uninit(&gh);
++ goto out;
++}
++
++/**
++ * gfs2_prepare_write - Prepare to write a page to a file
++ * @file: The file to write to
++ * @page: The page which is to be prepared for writing
++ * @from: From (byte range within page)
++ * @to: To (byte range within page)
++ *
++ * Returns: errno
++ */
++
++static int gfs2_prepare_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ struct gfs2_inode *ip = GFS2_I(page->mapping->host);
++ struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
++ unsigned int data_blocks, ind_blocks, rblocks;
++ int alloc_required;
++ int error = 0;
++ loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from;
++ loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
++ struct gfs2_alloc *al;
++ unsigned int write_len = to - from;
++
++
++ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|GL_AOP, &ip->i_gh);
++ error = gfs2_glock_nq_m_atime(1, &ip->i_gh);
++ if (error)
++ goto out_uninit;
++
++ gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks);
++
++ error = gfs2_write_alloc_required(ip, pos, write_len, &alloc_required);
++ if (error)
++ goto out_unlock;
++
++
++ ip->i_alloc.al_requested = 0;
++ if (alloc_required) {
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out_alloc_put;
++
++ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
++ if (error)
++ goto out_qunlock;
++
++ al->al_requested = data_blocks + ind_blocks;
++ error = gfs2_inplace_reserve(ip);
++ if (error)
++ goto out_qunlock;
++ }
++
++ rblocks = RES_DINODE + ind_blocks;
++ if (gfs2_is_jdata(ip))
++ rblocks += data_blocks ? data_blocks : 1;
++ if (ind_blocks || data_blocks)
++ rblocks += RES_STATFS + RES_QUOTA;
++
++ error = gfs2_trans_begin(sdp, rblocks, 0);
++ if (error)
++ goto out;
++
++ if (gfs2_is_stuffed(ip)) {
++ if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
++ error = gfs2_unstuff_dinode(ip, page);
++ if (error == 0)
++ goto prepare_write;
++ } else if (!PageUptodate(page))
++ error = stuffed_readpage(ip, page);
++ goto out;
++ }
++
++prepare_write:
++ error = block_prepare_write(page, from, to, gfs2_get_block);
++
++out:
++ if (error) {
++ gfs2_trans_end(sdp);
++ if (alloc_required) {
++ gfs2_inplace_release(ip);
++out_qunlock:
++ gfs2_quota_unlock(ip);
++out_alloc_put:
++ gfs2_alloc_put(ip);
++ }
++out_unlock:
++ gfs2_glock_dq_m(1, &ip->i_gh);
++out_uninit:
++ gfs2_holder_uninit(&ip->i_gh);
++ }
++
++ return error;
++}
++
++/**
++ * gfs2_commit_write - Commit write to a file
++ * @file: The file to write to
++ * @page: The page containing the data
++ * @from: From (byte range within page)
++ * @to: To (byte range within page)
++ *
++ * Returns: errno
++ */
++
++static int gfs2_commit_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ struct inode *inode = page->mapping->host;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ int error = -EOPNOTSUPP;
++ struct buffer_head *dibh;
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_dinode *di;
++
++ if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)))
++ goto fail_nounlock;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto fail_endtrans;
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ di = (struct gfs2_dinode *)dibh->b_data;
++
++ if (gfs2_is_stuffed(ip)) {
++ u64 file_size;
++ void *kaddr;
++
++ file_size = ((u64)page->index << PAGE_CACHE_SHIFT) + to;
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from,
++ kaddr + from, to - from);
++ kunmap_atomic(kaddr, KM_USER0);
++
++ SetPageUptodate(page);
++
++ if (inode->i_size < file_size)
++ i_size_write(inode, file_size);
++ } else {
++ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED ||
++ gfs2_is_jdata(ip))
++ gfs2_page_add_databufs(ip, page, from, to);
++ error = generic_commit_write(file, page, from, to);
++ if (error)
++ goto fail;
++ }
++
++ if (ip->i_di.di_size < inode->i_size) {
++ ip->i_di.di_size = inode->i_size;
++ di->di_size = cpu_to_be64(inode->i_size);
++ }
++
++ di->di_mode = cpu_to_be32(inode->i_mode);
++ di->di_atime = cpu_to_be64(inode->i_atime.tv_sec);
++ di->di_mtime = cpu_to_be64(inode->i_mtime.tv_sec);
++ di->di_ctime = cpu_to_be64(inode->i_ctime.tv_sec);
++
++ brelse(dibh);
++ gfs2_trans_end(sdp);
++ if (al->al_requested) {
++ gfs2_inplace_release(ip);
++ gfs2_quota_unlock(ip);
++ gfs2_alloc_put(ip);
++ }
++ gfs2_glock_dq_m(1, &ip->i_gh);
++ gfs2_holder_uninit(&ip->i_gh);
++ return 0;
++
++fail:
++ brelse(dibh);
++fail_endtrans:
++ gfs2_trans_end(sdp);
++ if (al->al_requested) {
++ gfs2_inplace_release(ip);
++ gfs2_quota_unlock(ip);
++ gfs2_alloc_put(ip);
++ }
++ gfs2_glock_dq_m(1, &ip->i_gh);
++ gfs2_holder_uninit(&ip->i_gh);
++fail_nounlock:
++ ClearPageUptodate(page);
++ return error;
++}
++
++/**
++ * gfs2_bmap - Block map function
++ * @mapping: Address space info
++ * @lblock: The block to map
++ *
++ * Returns: The disk address for the block or 0 on hole or error
++ */
++
++static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
++{
++ struct gfs2_inode *ip = GFS2_I(mapping->host);
++ struct gfs2_holder i_gh;
++ sector_t dblock = 0;
++ int error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
++ if (error)
++ return 0;
++
++ if (!gfs2_is_stuffed(ip))
++ dblock = generic_block_bmap(mapping, lblock, gfs2_get_block);
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return dblock;
++}
++
++static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
++{
++ struct gfs2_bufdata *bd;
++
++ gfs2_log_lock(sdp);
++ bd = bh->b_private;
++ if (bd) {
++ bd->bd_bh = NULL;
++ bh->b_private = NULL;
++ }
++ gfs2_log_unlock(sdp);
++
++ lock_buffer(bh);
++ clear_buffer_dirty(bh);
++ bh->b_bdev = NULL;
++ clear_buffer_mapped(bh);
++ clear_buffer_req(bh);
++ clear_buffer_new(bh);
++ clear_buffer_delay(bh);
++ unlock_buffer(bh);
++}
++
++static void gfs2_invalidatepage(struct page *page, unsigned long offset)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
++ struct buffer_head *head, *bh, *next;
++ unsigned int curr_off = 0;
++
++ BUG_ON(!PageLocked(page));
++ if (!page_has_buffers(page))
++ return;
++
++ bh = head = page_buffers(page);
++ do {
++ unsigned int next_off = curr_off + bh->b_size;
++ next = bh->b_this_page;
++
++ if (offset <= curr_off)
++ discard_buffer(sdp, bh);
++
++ curr_off = next_off;
++ bh = next;
++ } while (bh != head);
++
++ if (!offset)
++ try_to_release_page(page, 0);
++
++ return;
++}
++
++static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
++ 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 gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder gh;
++ int rv;
++
++ if (rw == READ)
++ mutex_lock(&inode->i_mutex);
++ /*
++ * Shared lock, even if its a write, since we do no allocation
++ * on this path. All we need change is atime.
++ */
++ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
++ rv = gfs2_glock_nq_m_atime(1, &gh);
++ if (rv)
++ goto out;
++
++ if (offset > i_size_read(inode))
++ goto out;
++
++ /*
++ * Should we return an error here? I can't see that O_DIRECT for
++ * a journaled file makes any sense. For now we'll silently fall
++ * back to buffered I/O, likewise we do the same for stuffed
++ * files since they are (a) small and (b) unaligned.
++ */
++ if (gfs2_is_jdata(ip))
++ goto out;
++
++ if (gfs2_is_stuffed(ip))
++ goto out;
++
++ rv = blockdev_direct_IO_own_locking(rw, iocb, inode,
++ inode->i_sb->s_bdev,
++ iov, offset, nr_segs,
++ gfs2_get_block_direct, NULL);
++out:
++ gfs2_glock_dq_m(1, &gh);
++ gfs2_holder_uninit(&gh);
++ if (rw == READ)
++ mutex_unlock(&inode->i_mutex);
++
++ return rv;
++}
++
++/**
++ * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out.
++ * @bh: the buffer we're stuck on
++ *
++ */
++
++static void stuck_releasepage(struct buffer_head *bh)
++{
++ struct inode *inode = bh->b_page->mapping->host;
++ struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
++ struct gfs2_bufdata *bd = bh->b_private;
++ struct gfs2_glock *gl;
++static unsigned limit = 0;
++
++ if (limit > 3)
++ return;
++ limit++;
++
++ fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
++ fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
++ (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
++ fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
++ fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
++
++ if (!bd)
++ return;
++
++ gl = bd->bd_gl;
++
++ fs_warn(sdp, "gl = (%u, %llu)\n",
++ gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
++
++ fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
++ (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
++ (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
++
++ if (gl->gl_ops == &gfs2_inode_glops) {
++ struct gfs2_inode *ip = gl->gl_object;
++ unsigned int x;
++
++ if (!ip)
++ return;
++
++ fs_warn(sdp, "ip = %llu %llu\n",
++ (unsigned long long)ip->i_num.no_formal_ino,
++ (unsigned long long)ip->i_num.no_addr);
++
++ for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
++ fs_warn(sdp, "ip->i_cache[%u] = %s\n",
++ x, (ip->i_cache[x]) ? "!NULL" : "NULL");
++ }
++}
++
++/**
++ * gfs2_releasepage - free the metadata associated with a page
++ * @page: the page that's being released
++ * @gfp_mask: passed from Linux VFS, ignored by us
++ *
++ * Call try_to_free_buffers() if the buffers in this page can be
++ * released.
++ *
++ * Returns: 0
++ */
++
++int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
++{
++ struct inode *aspace = page->mapping->host;
++ struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
++ struct buffer_head *bh, *head;
++ struct gfs2_bufdata *bd;
++ unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
++
++ if (!page_has_buffers(page))
++ goto out;
++
++ head = bh = page_buffers(page);
++ do {
++ while (atomic_read(&bh->b_count)) {
++ if (!atomic_read(&aspace->i_writecount))
++ return 0;
++
++ if (time_after_eq(jiffies, t)) {
++ stuck_releasepage(bh);
++ /* should we withdraw here? */
++ return 0;
++ }
++
++ yield();
++ }
++
++ gfs2_assert_warn(sdp, !buffer_pinned(bh));
++ gfs2_assert_warn(sdp, !buffer_dirty(bh));
++
++ gfs2_log_lock(sdp);
++ bd = bh->b_private;
++ if (bd) {
++ gfs2_assert_warn(sdp, bd->bd_bh == bh);
++ gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
++ gfs2_assert_warn(sdp, !bd->bd_ail);
++ bd->bd_bh = NULL;
++ if (!list_empty(&bd->bd_le.le_list))
++ bd = NULL;
++ bh->b_private = NULL;
++ }
++ gfs2_log_unlock(sdp);
++ if (bd)
++ kmem_cache_free(gfs2_bufdata_cachep, bd);
++
++ bh = bh->b_this_page;
++ } while (bh != head);
++
++out:
++ return try_to_free_buffers(page);
++}
++
++const struct address_space_operations gfs2_file_aops = {
++ .writepage = gfs2_writepage,
++ .readpage = gfs2_readpage,
++ .readpages = gfs2_readpages,
++ .sync_page = block_sync_page,
++ .prepare_write = gfs2_prepare_write,
++ .commit_write = gfs2_commit_write,
++ .bmap = gfs2_bmap,
++ .invalidatepage = gfs2_invalidatepage,
++ .releasepage = gfs2_releasepage,
++ .direct_IO = gfs2_direct_IO,
++};
++
+diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
+new file mode 100644
+index 0000000..35aaee4
+--- /dev/null
++++ b/fs/gfs2/ops_address.h
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_ADDRESS_DOT_H__
++#define __OPS_ADDRESS_DOT_H__
++
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/mm.h>
++
++extern const struct address_space_operations gfs2_file_aops;
++extern int gfs2_get_block(struct inode *inode, sector_t lblock,
++ struct buffer_head *bh_result, int create);
++extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
++
++#endif /* __OPS_ADDRESS_DOT_H__ */
+diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
+new file mode 100644
+index 0000000..00041b1
+--- /dev/null
++++ b/fs/gfs2/ops_dentry.c
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/smp_lock.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "dir.h"
++#include "glock.h"
++#include "ops_dentry.h"
++#include "util.h"
++
++/**
++ * gfs2_drevalidate - Check directory lookup consistency
++ * @dentry: the mapping to check
++ * @nd:
++ *
++ * Check to make sure the lookup necessary to arrive at this inode from its
++ * parent is still good.
++ *
++ * Returns: 1 if the dentry is ok, 0 if it isn't
++ */
++
++static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ struct dentry *parent = dget_parent(dentry);
++ struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode);
++ struct gfs2_inode *dip = GFS2_I(parent->d_inode);
++ struct inode *inode = dentry->d_inode;
++ struct gfs2_holder d_gh;
++ struct gfs2_inode *ip;
++ struct gfs2_inum inum;
++ unsigned int type;
++ int error;
++
++ if (inode && is_bad_inode(inode))
++ goto invalid;
++
++ if (sdp->sd_args.ar_localcaching)
++ goto valid;
++
++ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
++ if (error)
++ goto fail;
++
++ error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
++ switch (error) {
++ case 0:
++ if (!inode)
++ goto invalid_gunlock;
++ break;
++ case -ENOENT:
++ if (!inode)
++ goto valid_gunlock;
++ goto invalid_gunlock;
++ default:
++ goto fail_gunlock;
++ }
++
++ ip = GFS2_I(inode);
++
++ if (!gfs2_inum_equal(&ip->i_num, &inum))
++ goto invalid_gunlock;
++
++ if (IF2DT(ip->i_di.di_mode) != type) {
++ gfs2_consist_inode(dip);
++ goto fail_gunlock;
++ }
++
++valid_gunlock:
++ gfs2_glock_dq_uninit(&d_gh);
++valid:
++ dput(parent);
++ return 1;
++
++invalid_gunlock:
++ gfs2_glock_dq_uninit(&d_gh);
++invalid:
++ if (inode && S_ISDIR(inode->i_mode)) {
++ if (have_submounts(dentry))
++ goto valid;
++ shrink_dcache_parent(dentry);
++ }
++ d_drop(dentry);
++ dput(parent);
++ return 0;
++
++fail_gunlock:
++ gfs2_glock_dq_uninit(&d_gh);
++fail:
++ dput(parent);
++ return 0;
++}
++
++static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
++{
++ str->hash = gfs2_disk_hash(str->name, str->len);
++ return 0;
++}
++
++struct dentry_operations gfs2_dops = {
++ .d_revalidate = gfs2_drevalidate,
++ .d_hash = gfs2_dhash,
++};
++
+diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h
+new file mode 100644
+index 0000000..5caa3db
+--- /dev/null
++++ b/fs/gfs2/ops_dentry.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_DENTRY_DOT_H__
++#define __OPS_DENTRY_DOT_H__
++
++#include <linux/dcache.h>
++
++extern struct dentry_operations gfs2_dops;
++
++#endif /* __OPS_DENTRY_DOT_H__ */
+diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
+new file mode 100644
+index 0000000..86127d9
+--- /dev/null
++++ b/fs/gfs2/ops_export.c
+@@ -0,0 +1,298 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "dir.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "ops_export.h"
++#include "rgrp.h"
++#include "util.h"
++
++static struct dentry *gfs2_decode_fh(struct super_block *sb,
++ __u32 *fh,
++ int fh_len,
++ int fh_type,
++ int (*acceptable)(void *context,
++ struct dentry *dentry),
++ void *context)
++{
++ struct gfs2_fh_obj fh_obj;
++ struct gfs2_inum *this, parent;
++
++ if (fh_type != fh_len)
++ return NULL;
++
++ this = &fh_obj.this;
++ fh_obj.imode = DT_UNKNOWN;
++ memset(&parent, 0, sizeof(struct gfs2_inum));
++
++ switch (fh_type) {
++ case GFS2_LARGE_FH_SIZE:
++ parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
++ parent.no_formal_ino |= be32_to_cpu(fh[5]);
++ parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
++ parent.no_addr |= be32_to_cpu(fh[7]);
++ fh_obj.imode = be32_to_cpu(fh[8]);
++ case GFS2_SMALL_FH_SIZE:
++ this->no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
++ this->no_formal_ino |= be32_to_cpu(fh[1]);
++ this->no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
++ this->no_addr |= be32_to_cpu(fh[3]);
++ break;
++ default:
++ return NULL;
++ }
++
++ return gfs2_export_ops.find_exported_dentry(sb, &fh_obj, &parent,
++ acceptable, context);
++}
++
++static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
++ int connectable)
++{
++ struct inode *inode = dentry->d_inode;
++ struct super_block *sb = inode->i_sb;
++ struct gfs2_inode *ip = GFS2_I(inode);
++
++ if (*len < GFS2_SMALL_FH_SIZE ||
++ (connectable && *len < GFS2_LARGE_FH_SIZE))
++ return 255;
++
++ fh[0] = ip->i_num.no_formal_ino >> 32;
++ fh[0] = cpu_to_be32(fh[0]);
++ fh[1] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
++ fh[1] = cpu_to_be32(fh[1]);
++ fh[2] = ip->i_num.no_addr >> 32;
++ fh[2] = cpu_to_be32(fh[2]);
++ fh[3] = ip->i_num.no_addr & 0xFFFFFFFF;
++ fh[3] = cpu_to_be32(fh[3]);
++ *len = GFS2_SMALL_FH_SIZE;
++
++ if (!connectable || inode == sb->s_root->d_inode)
++ return *len;
++
++ spin_lock(&dentry->d_lock);
++ inode = dentry->d_parent->d_inode;
++ ip = GFS2_I(inode);
++ igrab(inode);
++ spin_unlock(&dentry->d_lock);
++
++ fh[4] = ip->i_num.no_formal_ino >> 32;
++ fh[4] = cpu_to_be32(fh[4]);
++ fh[5] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
++ fh[5] = cpu_to_be32(fh[5]);
++ fh[6] = ip->i_num.no_addr >> 32;
++ fh[6] = cpu_to_be32(fh[6]);
++ fh[7] = ip->i_num.no_addr & 0xFFFFFFFF;
++ fh[7] = cpu_to_be32(fh[7]);
++
++ fh[8] = cpu_to_be32(inode->i_mode);
++ fh[9] = 0; /* pad to double word */
++ *len = GFS2_LARGE_FH_SIZE;
++
++ iput(inode);
++
++ return *len;
++}
++
++struct get_name_filldir {
++ struct gfs2_inum inum;
++ char *name;
++};
++
++static int get_name_filldir(void *opaque, const char *name, unsigned int length,
++ u64 offset, struct gfs2_inum *inum,
++ unsigned int type)
++{
++ struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
++
++ if (!gfs2_inum_equal(inum, &gnfd->inum))
++ return 0;
++
++ memcpy(gnfd->name, name, length);
++ gnfd->name[length] = 0;
++
++ return 1;
++}
++
++static int gfs2_get_name(struct dentry *parent, char *name,
++ struct dentry *child)
++{
++ struct inode *dir = parent->d_inode;
++ struct inode *inode = child->d_inode;
++ struct gfs2_inode *dip, *ip;
++ struct get_name_filldir gnfd;
++ struct gfs2_holder gh;
++ u64 offset = 0;
++ int error;
++
++ if (!dir)
++ return -EINVAL;
++
++ if (!S_ISDIR(dir->i_mode) || !inode)
++ return -EINVAL;
++
++ dip = GFS2_I(dir);
++ ip = GFS2_I(inode);
++
++ *name = 0;
++ gnfd.inum = ip->i_num;
++ gnfd.name = name;
++
++ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
++ if (error)
++ return error;
++
++ error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
++
++ gfs2_glock_dq_uninit(&gh);
++
++ if (!error && !*name)
++ error = -ENOENT;
++
++ return error;
++}
++
++static struct dentry *gfs2_get_parent(struct dentry *child)
++{
++ struct qstr dotdot;
++ struct inode *inode;
++ struct dentry *dentry;
++
++ gfs2_str2qstr(&dotdot, "..");
++ inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);
++
++ if (!inode)
++ return ERR_PTR(-ENOENT);
++ /*
++ * In case of an error, @inode carries the error value, and we
++ * have to return that as a(n invalid) pointer to dentry.
++ */
++ if (IS_ERR(inode))
++ return ERR_PTR(PTR_ERR(inode));
++
++ dentry = d_alloc_anon(inode);
++ if (!dentry) {
++ iput(inode);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ return dentry;
++}
++
++static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj;
++ struct gfs2_inum *inum = &fh_obj->this;
++ struct gfs2_holder i_gh, ri_gh, rgd_gh;
++ struct gfs2_rgrpd *rgd;
++ struct inode *inode;
++ struct dentry *dentry;
++ int error;
++
++ /* System files? */
++
++ inode = gfs2_ilookup(sb, inum);
++ if (inode) {
++ if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) {
++ iput(inode);
++ return ERR_PTR(-ESTALE);
++ }
++ goto out_inode;
++ }
++
++ error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
++ LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
++ &i_gh);
++ if (error)
++ return ERR_PTR(error);
++
++ error = gfs2_rindex_hold(sdp, &ri_gh);
++ if (error)
++ goto fail;
++
++ error = -EINVAL;
++ rgd = gfs2_blk2rgrpd(sdp, inum->no_addr);
++ if (!rgd)
++ goto fail_rindex;
++
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
++ if (error)
++ goto fail_rindex;
++
++ error = -ESTALE;
++ if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE)
++ goto fail_rgd;
++
++ gfs2_glock_dq_uninit(&rgd_gh);
++ gfs2_glock_dq_uninit(&ri_gh);
++
++ inode = gfs2_inode_lookup(sb, inum, fh_obj->imode);
++ if (!inode)
++ goto fail;
++ if (IS_ERR(inode)) {
++ error = PTR_ERR(inode);
++ goto fail;
++ }
++
++ error = gfs2_inode_refresh(GFS2_I(inode));
++ if (error) {
++ iput(inode);
++ goto fail;
++ }
++
++ error = -EIO;
++ if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) {
++ iput(inode);
++ goto fail;
++ }
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++out_inode:
++ dentry = d_alloc_anon(inode);
++ if (!dentry) {
++ iput(inode);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ return dentry;
++
++fail_rgd:
++ gfs2_glock_dq_uninit(&rgd_gh);
++
++fail_rindex:
++ gfs2_glock_dq_uninit(&ri_gh);
++
++fail:
++ gfs2_glock_dq_uninit(&i_gh);
++ return ERR_PTR(error);
++}
++
++struct export_operations gfs2_export_ops = {
++ .decode_fh = gfs2_decode_fh,
++ .encode_fh = gfs2_encode_fh,
++ .get_name = gfs2_get_name,
++ .get_parent = gfs2_get_parent,
++ .get_dentry = gfs2_get_dentry,
++};
++
+diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h
+new file mode 100644
+index 0000000..09aca50
+--- /dev/null
++++ b/fs/gfs2/ops_export.h
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_EXPORT_DOT_H__
++#define __OPS_EXPORT_DOT_H__
++
++#define GFS2_SMALL_FH_SIZE 4
++#define GFS2_LARGE_FH_SIZE 10
++
++extern struct export_operations gfs2_export_ops;
++struct gfs2_fh_obj {
++ struct gfs2_inum this;
++ __u32 imode;
++};
++
++#endif /* __OPS_EXPORT_DOT_H__ */
+diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
+new file mode 100644
+index 0000000..3064f13
+--- /dev/null
++++ b/fs/gfs2/ops_file.c
+@@ -0,0 +1,661 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/pagemap.h>
++#include <linux/uio.h>
++#include <linux/blkdev.h>
++#include <linux/mm.h>
++#include <linux/smp_lock.h>
++#include <linux/fs.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/ext2_fs.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "dir.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "lm.h"
++#include "log.h"
++#include "meta_io.h"
++#include "ops_file.h"
++#include "ops_vm.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++#include "eaops.h"
++
++/* For regular, non-NFS */
++struct filldir_reg {
++ struct gfs2_sbd *fdr_sbd;
++ int fdr_prefetch;
++
++ filldir_t fdr_filldir;
++ void *fdr_opaque;
++};
++
++/*
++ * Most fields left uninitialised to catch anybody who tries to
++ * use them. f_flags set to prevent file_accessed() from touching
++ * any other part of this. Its use is purely as a flag so that we
++ * know (in readpage()) whether or not do to locking.
++ */
++struct file gfs2_internal_file_sentinel = {
++ .f_flags = O_NOATIME|O_RDONLY,
++};
++
++static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
++ unsigned long offset, unsigned long size)
++{
++ char *kaddr;
++ unsigned long count = desc->count;
++
++ if (size > count)
++ size = count;
++
++ kaddr = kmap(page);
++ memcpy(desc->arg.buf, kaddr + offset, size);
++ kunmap(page);
++
++ desc->count = count - size;
++ desc->written += size;
++ desc->arg.buf += size;
++ return size;
++}
++
++int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
++ char *buf, loff_t *pos, unsigned size)
++{
++ struct inode *inode = &ip->i_inode;
++ read_descriptor_t desc;
++ desc.written = 0;
++ desc.arg.buf = buf;
++ desc.count = size;
++ desc.error = 0;
++ do_generic_mapping_read(inode->i_mapping, ra_state,
++ &gfs2_internal_file_sentinel, pos, &desc,
++ gfs2_read_actor);
++ return desc.written ? desc.written : desc.error;
++}
++
++/**
++ * gfs2_llseek - seek to a location in a file
++ * @file: the file
++ * @offset: the offset
++ * @origin: Where to seek from (SEEK_SET, SEEK_CUR, or SEEK_END)
++ *
++ * SEEK_END requires the glock for the file because it references the
++ * file's size.
++ *
++ * Returns: The new offset, or errno
++ */
++
++static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
++{
++ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
++ struct gfs2_holder i_gh;
++ loff_t error;
++
++ if (origin == 2) {
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
++ &i_gh);
++ if (!error) {
++ error = remote_llseek(file, offset, origin);
++ gfs2_glock_dq_uninit(&i_gh);
++ }
++ } else
++ error = remote_llseek(file, offset, origin);
++
++ return error;
++}
++
++/**
++ * filldir_func - Report a directory entry to the caller of gfs2_dir_read()
++ * @opaque: opaque data used by the function
++ * @name: the name of the directory entry
++ * @length: the length of the name
++ * @offset: the entry's offset in the directory
++ * @inum: the inode number the entry points to
++ * @type: the type of inode the entry points to
++ *
++ * Returns: 0 on success, 1 if buffer full
++ */
++
++static int filldir_func(void *opaque, const char *name, unsigned int length,
++ u64 offset, struct gfs2_inum *inum,
++ unsigned int type)
++{
++ struct filldir_reg *fdr = (struct filldir_reg *)opaque;
++ struct gfs2_sbd *sdp = fdr->fdr_sbd;
++ int error;
++
++ error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset,
++ inum->no_addr, type);
++ if (error)
++ return 1;
++
++ if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) {
++ gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops,
++ LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY);
++ gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops,
++ LM_ST_SHARED, LM_FLAG_TRY);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_readdir - Read directory entries from a directory
++ * @file: The directory to read from
++ * @dirent: Buffer for dirents
++ * @filldir: Function used to do the copying
++ *
++ * Returns: errno
++ */
++
++static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ struct inode *dir = file->f_mapping->host;
++ struct gfs2_inode *dip = GFS2_I(dir);
++ struct filldir_reg fdr;
++ struct gfs2_holder d_gh;
++ u64 offset = file->f_pos;
++ int error;
++
++ fdr.fdr_sbd = GFS2_SB(dir);
++ fdr.fdr_prefetch = 1;
++ fdr.fdr_filldir = filldir;
++ fdr.fdr_opaque = dirent;
++
++ gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh);
++ error = gfs2_glock_nq_atime(&d_gh);
++ if (error) {
++ gfs2_holder_uninit(&d_gh);
++ return error;
++ }
++
++ error = gfs2_dir_read(dir, &offset, &fdr, filldir_func);
++
++ gfs2_glock_dq_uninit(&d_gh);
++
++ file->f_pos = offset;
++
++ return error;
++}
++
++/**
++ * fsflags_cvt
++ * @table: A table of 32 u32 flags
++ * @val: a 32 bit value to convert
++ *
++ * This function can be used to convert between fsflags values and
++ * GFS2's own flags values.
++ *
++ * Returns: the converted flags
++ */
++static u32 fsflags_cvt(const u32 *table, u32 val)
++{
++ u32 res = 0;
++ while(val) {
++ if (val & 1)
++ res |= *table;
++ table++;
++ val >>= 1;
++ }
++ return res;
++}
++
++static const u32 fsflags_to_gfs2[32] = {
++ [3] = GFS2_DIF_SYNC,
++ [4] = GFS2_DIF_IMMUTABLE,
++ [5] = GFS2_DIF_APPENDONLY,
++ [7] = GFS2_DIF_NOATIME,
++ [12] = GFS2_DIF_EXHASH,
++ [14] = GFS2_DIF_JDATA,
++ [20] = GFS2_DIF_DIRECTIO,
++};
++
++static const u32 gfs2_to_fsflags[32] = {
++ [gfs2fl_Sync] = FS_SYNC_FL,
++ [gfs2fl_Immutable] = FS_IMMUTABLE_FL,
++ [gfs2fl_AppendOnly] = FS_APPEND_FL,
++ [gfs2fl_NoAtime] = FS_NOATIME_FL,
++ [gfs2fl_ExHash] = FS_INDEX_FL,
++ [gfs2fl_Jdata] = FS_JOURNAL_DATA_FL,
++ [gfs2fl_Directio] = FS_DIRECTIO_FL,
++ [gfs2fl_InheritDirectio] = FS_DIRECTIO_FL,
++ [gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL,
++};
++
++static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
++{
++ struct inode *inode = filp->f_dentry->d_inode;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder gh;
++ int error;
++ u32 fsflags;
++
++ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
++ error = gfs2_glock_nq_m_atime(1, &gh);
++ if (error)
++ return error;
++
++ fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_di.di_flags);
++ if (put_user(fsflags, ptr))
++ error = -EFAULT;
++
++ gfs2_glock_dq_m(1, &gh);
++ gfs2_holder_uninit(&gh);
++ return error;
++}
++
++/* Flags that can be set by user space */
++#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \
++ GFS2_DIF_DIRECTIO| \
++ GFS2_DIF_IMMUTABLE| \
++ GFS2_DIF_APPENDONLY| \
++ GFS2_DIF_NOATIME| \
++ GFS2_DIF_SYNC| \
++ GFS2_DIF_SYSTEM| \
++ GFS2_DIF_INHERIT_DIRECTIO| \
++ GFS2_DIF_INHERIT_JDATA)
++
++/**
++ * gfs2_set_flags - set flags on an inode
++ * @inode: The inode
++ * @flags: The flags to set
++ * @mask: Indicates which flags are valid
++ *
++ */
++static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
++{
++ struct inode *inode = filp->f_dentry->d_inode;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ struct buffer_head *bh;
++ struct gfs2_holder gh;
++ int error;
++ u32 new_flags, flags;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
++ if (error)
++ return error;
++
++ flags = ip->i_di.di_flags;
++ new_flags = (flags & ~mask) | (reqflags & mask);
++ if ((new_flags ^ flags) == 0)
++ goto out;
++
++ if (S_ISDIR(inode->i_mode)) {
++ if ((new_flags ^ flags) & GFS2_DIF_JDATA)
++ new_flags ^= (GFS2_DIF_JDATA|GFS2_DIF_INHERIT_JDATA);
++ if ((new_flags ^ flags) & GFS2_DIF_DIRECTIO)
++ new_flags ^= (GFS2_DIF_DIRECTIO|GFS2_DIF_INHERIT_DIRECTIO);
++ }
++
++ error = -EINVAL;
++ if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET)
++ goto out;
++
++ error = -EPERM;
++ if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE))
++ goto out;
++ if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY))
++ goto out;
++ if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) &&
++ !capable(CAP_LINUX_IMMUTABLE))
++ goto out;
++ if (!IS_IMMUTABLE(inode)) {
++ error = permission(inode, MAY_WRITE, NULL);
++ if (error)
++ goto out;
++ }
++
++ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
++ if (error)
++ goto out;
++ error = gfs2_meta_inode_buffer(ip, &bh);
++ if (error)
++ goto out_trans_end;
++ gfs2_trans_add_bh(ip->i_gl, bh, 1);
++ ip->i_di.di_flags = new_flags;
++ gfs2_dinode_out(&ip->i_di, bh->b_data);
++ brelse(bh);
++out_trans_end:
++ gfs2_trans_end(sdp);
++out:
++ gfs2_glock_dq_uninit(&gh);
++ return error;
++}
++
++static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
++{
++ u32 fsflags, gfsflags;
++ if (get_user(fsflags, ptr))
++ return -EFAULT;
++ gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags);
++ return do_gfs2_set_flags(filp, gfsflags, ~0);
++}
++
++static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ switch(cmd) {
++ case FS_IOC_GETFLAGS:
++ return gfs2_get_flags(filp, (u32 __user *)arg);
++ case FS_IOC_SETFLAGS:
++ return gfs2_set_flags(filp, (u32 __user *)arg);
++ }
++ return -ENOTTY;
++}
++
++
++/**
++ * gfs2_mmap -
++ * @file: The file to map
++ * @vma: The VMA which described the mapping
++ *
++ * Returns: 0 or error code
++ */
++
++static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
++ struct gfs2_holder i_gh;
++ int error;
++
++ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
++ error = gfs2_glock_nq_atime(&i_gh);
++ if (error) {
++ gfs2_holder_uninit(&i_gh);
++ return error;
++ }
++
++ /* This is VM_MAYWRITE instead of VM_WRITE because a call
++ to mprotect() can turn on VM_WRITE later. */
++
++ if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
++ (VM_MAYSHARE | VM_MAYWRITE))
++ vma->vm_ops = &gfs2_vm_ops_sharewrite;
++ else
++ vma->vm_ops = &gfs2_vm_ops_private;
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return error;
++}
++
++/**
++ * gfs2_open - open a file
++ * @inode: the inode to open
++ * @file: the struct file for this opening
++ *
++ * Returns: errno
++ */
++
++static int gfs2_open(struct inode *inode, struct file *file)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder i_gh;
++ struct gfs2_file *fp;
++ int error;
++
++ fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL);
++ if (!fp)
++ return -ENOMEM;
++
++ mutex_init(&fp->f_fl_mutex);
++
++ gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
++ file->private_data = fp;
++
++ if (S_ISREG(ip->i_di.di_mode)) {
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
++ &i_gh);
++ if (error)
++ goto fail;
++
++ if (!(file->f_flags & O_LARGEFILE) &&
++ ip->i_di.di_size > MAX_NON_LFS) {
++ error = -EFBIG;
++ goto fail_gunlock;
++ }
++
++ /* Listen to the Direct I/O flag */
++
++ if (ip->i_di.di_flags & GFS2_DIF_DIRECTIO)
++ file->f_flags |= O_DIRECT;
++
++ gfs2_glock_dq_uninit(&i_gh);
++ }
++
++ return 0;
++
++fail_gunlock:
++ gfs2_glock_dq_uninit(&i_gh);
++fail:
++ file->private_data = NULL;
++ kfree(fp);
++ return error;
++}
++
++/**
++ * gfs2_close - called to close a struct file
++ * @inode: the inode the struct file belongs to
++ * @file: the struct file being closed
++ *
++ * Returns: errno
++ */
++
++static int gfs2_close(struct inode *inode, struct file *file)
++{
++ struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
++ struct gfs2_file *fp;
++
++ fp = file->private_data;
++ file->private_data = NULL;
++
++ if (gfs2_assert_warn(sdp, fp))
++ return -EIO;
++
++ kfree(fp);
++
++ return 0;
++}
++
++/**
++ * gfs2_fsync - sync the dirty data for a file (across the cluster)
++ * @file: the file that points to the dentry (we ignore this)
++ * @dentry: the dentry that points to the inode to sync
++ *
++ * Returns: errno
++ */
++
++static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
++
++ gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
++
++ return 0;
++}
++
++/**
++ * gfs2_lock - acquire/release a posix lock on a file
++ * @file: the file pointer
++ * @cmd: either modify or retrieve lock state, possibly wait
++ * @fl: type and range of lock
++ *
++ * Returns: errno
++ */
++
++static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
++{
++ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
++ struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
++ struct lm_lockname name =
++ { .ln_number = ip->i_num.no_addr,
++ .ln_type = LM_TYPE_PLOCK };
++
++ if (!(fl->fl_flags & FL_POSIX))
++ return -ENOLCK;
++ if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
++ return -ENOLCK;
++
++ if (sdp->sd_args.ar_localflocks) {
++ if (IS_GETLK(cmd)) {
++ struct file_lock tmp;
++ int ret;
++ ret = posix_test_lock(file, fl, &tmp);
++ fl->fl_type = F_UNLCK;
++ if (ret)
++ memcpy(fl, &tmp, sizeof(struct file_lock));
++ return 0;
++ } else {
++ return posix_lock_file_wait(file, fl);
++ }
++ }
++
++ if (IS_GETLK(cmd))
++ return gfs2_lm_plock_get(sdp, &name, file, fl);
++ else if (fl->fl_type == F_UNLCK)
++ return gfs2_lm_punlock(sdp, &name, file, fl);
++ else
++ return gfs2_lm_plock(sdp, &name, file, cmd, fl);
++}
++
++static int do_flock(struct file *file, int cmd, struct file_lock *fl)
++{
++ struct gfs2_file *fp = file->private_data;
++ struct gfs2_holder *fl_gh = &fp->f_fl_gh;
++ struct gfs2_inode *ip = GFS2_I(file->f_dentry->d_inode);
++ struct gfs2_glock *gl;
++ unsigned int state;
++ int flags;
++ int error = 0;
++
++ state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
++ flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE;
++
++ mutex_lock(&fp->f_fl_mutex);
++
++ gl = fl_gh->gh_gl;
++ if (gl) {
++ if (fl_gh->gh_state == state)
++ goto out;
++ gfs2_glock_hold(gl);
++ flock_lock_file_wait(file,
++ &(struct file_lock){.fl_type = F_UNLCK});
++ gfs2_glock_dq_uninit(fl_gh);
++ } else {
++ error = gfs2_glock_get(GFS2_SB(&ip->i_inode),
++ ip->i_num.no_addr, &gfs2_flock_glops,
++ CREATE, &gl);
++ if (error)
++ goto out;
++ }
++
++ gfs2_holder_init(gl, state, flags, fl_gh);
++ gfs2_glock_put(gl);
++
++ error = gfs2_glock_nq(fl_gh);
++ if (error) {
++ gfs2_holder_uninit(fl_gh);
++ if (error == GLR_TRYFAILED)
++ error = -EAGAIN;
++ } else {
++ error = flock_lock_file_wait(file, fl);
++ gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
++ }
++
++out:
++ mutex_unlock(&fp->f_fl_mutex);
++ return error;
++}
++
++static void do_unflock(struct file *file, struct file_lock *fl)
++{
++ struct gfs2_file *fp = file->private_data;
++ struct gfs2_holder *fl_gh = &fp->f_fl_gh;
++
++ mutex_lock(&fp->f_fl_mutex);
++ flock_lock_file_wait(file, fl);
++ if (fl_gh->gh_gl)
++ gfs2_glock_dq_uninit(fl_gh);
++ mutex_unlock(&fp->f_fl_mutex);
++}
++
++/**
++ * gfs2_flock - acquire/release a flock lock on a file
++ * @file: the file pointer
++ * @cmd: either modify or retrieve lock state, possibly wait
++ * @fl: type and range of lock
++ *
++ * Returns: errno
++ */
++
++static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
++{
++ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
++ struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
++
++ if (!(fl->fl_flags & FL_FLOCK))
++ return -ENOLCK;
++ if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
++ return -ENOLCK;
++
++ if (sdp->sd_args.ar_localflocks)
++ return flock_lock_file_wait(file, fl);
++
++ if (fl->fl_type == F_UNLCK) {
++ do_unflock(file, fl);
++ return 0;
++ } else {
++ return do_flock(file, cmd, fl);
++ }
++}
++
++const struct file_operations gfs2_file_fops = {
++ .llseek = gfs2_llseek,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
++ .unlocked_ioctl = gfs2_ioctl,
++ .mmap = gfs2_mmap,
++ .open = gfs2_open,
++ .release = gfs2_close,
++ .fsync = gfs2_fsync,
++ .lock = gfs2_lock,
++ .sendfile = generic_file_sendfile,
++ .flock = gfs2_flock,
++ .splice_read = generic_file_splice_read,
++ .splice_write = generic_file_splice_write,
++};
++
++const struct file_operations gfs2_dir_fops = {
++ .readdir = gfs2_readdir,
++ .unlocked_ioctl = gfs2_ioctl,
++ .open = gfs2_open,
++ .release = gfs2_close,
++ .fsync = gfs2_fsync,
++ .lock = gfs2_lock,
++ .flock = gfs2_flock,
++};
++
+diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
+new file mode 100644
+index 0000000..ce319f8
+--- /dev/null
++++ b/fs/gfs2/ops_file.h
+@@ -0,0 +1,24 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_FILE_DOT_H__
++#define __OPS_FILE_DOT_H__
++
++#include <linux/fs.h>
++struct gfs2_inode;
++
++extern struct file gfs2_internal_file_sentinel;
++extern int gfs2_internal_read(struct gfs2_inode *ip,
++ struct file_ra_state *ra_state,
++ char *buf, loff_t *pos, unsigned size);
++
++extern const struct file_operations gfs2_file_fops;
++extern const struct file_operations gfs2_dir_fops;
++
++#endif /* __OPS_FILE_DOT_H__ */
+diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
+new file mode 100644
+index 0000000..882873a
+--- /dev/null
++++ b/fs/gfs2/ops_fstype.c
+@@ -0,0 +1,925 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/blkdev.h>
++#include <linux/kthread.h>
++#include <linux/namei.h>
++#include <linux/mount.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "daemon.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "lm.h"
++#include "mount.h"
++#include "ops_export.h"
++#include "ops_fstype.h"
++#include "ops_super.h"
++#include "recovery.h"
++#include "rgrp.h"
++#include "super.h"
++#include "sys.h"
++#include "util.h"
++
++#define DO 0
++#define UNDO 1
++
++extern struct dentry_operations gfs2_dops;
++
++static struct gfs2_sbd *init_sbd(struct super_block *sb)
++{
++ struct gfs2_sbd *sdp;
++
++ sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL);
++ if (!sdp)
++ return NULL;
++
++ sb->s_fs_info = sdp;
++ sdp->sd_vfs = sb;
++
++ gfs2_tune_init(&sdp->sd_tune);
++
++ INIT_LIST_HEAD(&sdp->sd_reclaim_list);
++ spin_lock_init(&sdp->sd_reclaim_lock);
++ init_waitqueue_head(&sdp->sd_reclaim_wq);
++
++ mutex_init(&sdp->sd_inum_mutex);
++ spin_lock_init(&sdp->sd_statfs_spin);
++ mutex_init(&sdp->sd_statfs_mutex);
++
++ spin_lock_init(&sdp->sd_rindex_spin);
++ mutex_init(&sdp->sd_rindex_mutex);
++ INIT_LIST_HEAD(&sdp->sd_rindex_list);
++ INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
++ INIT_LIST_HEAD(&sdp->sd_rindex_recent_list);
++
++ INIT_LIST_HEAD(&sdp->sd_jindex_list);
++ spin_lock_init(&sdp->sd_jindex_spin);
++ mutex_init(&sdp->sd_jindex_mutex);
++
++ INIT_LIST_HEAD(&sdp->sd_quota_list);
++ spin_lock_init(&sdp->sd_quota_spin);
++ mutex_init(&sdp->sd_quota_mutex);
++
++ spin_lock_init(&sdp->sd_log_lock);
++
++ INIT_LIST_HEAD(&sdp->sd_log_le_gl);
++ INIT_LIST_HEAD(&sdp->sd_log_le_buf);
++ INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
++ INIT_LIST_HEAD(&sdp->sd_log_le_rg);
++ INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
++
++ mutex_init(&sdp->sd_log_reserve_mutex);
++ INIT_LIST_HEAD(&sdp->sd_ail1_list);
++ INIT_LIST_HEAD(&sdp->sd_ail2_list);
++
++ init_rwsem(&sdp->sd_log_flush_lock);
++ INIT_LIST_HEAD(&sdp->sd_log_flush_list);
++
++ INIT_LIST_HEAD(&sdp->sd_revoke_list);
++
++ mutex_init(&sdp->sd_freeze_lock);
++
++ return sdp;
++}
++
++static void init_vfs(struct super_block *sb, unsigned noatime)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++
++ sb->s_magic = GFS2_MAGIC;
++ sb->s_op = &gfs2_super_ops;
++ sb->s_export_op = &gfs2_export_ops;
++ sb->s_maxbytes = MAX_LFS_FILESIZE;
++
++ if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME))
++ set_bit(noatime, &sdp->sd_flags);
++
++ /* Don't let the VFS update atimes. GFS2 handles this itself. */
++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
++}
++
++static int init_names(struct gfs2_sbd *sdp, int silent)
++{
++ struct page *page;
++ char *proto, *table;
++ int error = 0;
++
++ proto = sdp->sd_args.ar_lockproto;
++ table = sdp->sd_args.ar_locktable;
++
++ /* Try to autodetect */
++
++ if (!proto[0] || !table[0]) {
++ struct gfs2_sb *sb;
++ page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
++ if (!page)
++ return -ENOBUFS;
++ sb = kmap(page);
++ gfs2_sb_in(&sdp->sd_sb, sb);
++ kunmap(page);
++ __free_page(page);
++
++ error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
++ if (error)
++ goto out;
++
++ if (!proto[0])
++ proto = sdp->sd_sb.sb_lockproto;
++ if (!table[0])
++ table = sdp->sd_sb.sb_locktable;
++ }
++
++ if (!table[0])
++ table = sdp->sd_vfs->s_id;
++
++ snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto);
++ snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table);
++
++out:
++ return error;
++}
++
++static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
++ int undo)
++{
++ struct task_struct *p;
++ int error = 0;
++
++ if (undo)
++ goto fail_trans;
++
++ p = kthread_run(gfs2_scand, sdp, "gfs2_scand");
++ error = IS_ERR(p);
++ if (error) {
++ fs_err(sdp, "can't start scand thread: %d\n", error);
++ return error;
++ }
++ sdp->sd_scand_process = p;
++
++ for (sdp->sd_glockd_num = 0;
++ sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
++ sdp->sd_glockd_num++) {
++ p = kthread_run(gfs2_glockd, sdp, "gfs2_glockd");
++ error = IS_ERR(p);
++ if (error) {
++ fs_err(sdp, "can't start glockd thread: %d\n", error);
++ goto fail;
++ }
++ sdp->sd_glockd_process[sdp->sd_glockd_num] = p;
++ }
++
++ error = gfs2_glock_nq_num(sdp,
++ GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
++ LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE,
++ mount_gh);
++ if (error) {
++ fs_err(sdp, "can't acquire mount glock: %d\n", error);
++ goto fail;
++ }
++
++ error = gfs2_glock_nq_num(sdp,
++ GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
++ LM_ST_SHARED,
++ LM_FLAG_NOEXP | GL_EXACT,
++ &sdp->sd_live_gh);
++ if (error) {
++ fs_err(sdp, "can't acquire live glock: %d\n", error);
++ goto fail_mount;
++ }
++
++ error = gfs2_glock_get(sdp, GFS2_RENAME_LOCK, &gfs2_nondisk_glops,
++ CREATE, &sdp->sd_rename_gl);
++ if (error) {
++ fs_err(sdp, "can't create rename glock: %d\n", error);
++ goto fail_live;
++ }
++
++ error = gfs2_glock_get(sdp, GFS2_TRANS_LOCK, &gfs2_trans_glops,
++ CREATE, &sdp->sd_trans_gl);
++ if (error) {
++ fs_err(sdp, "can't create transaction glock: %d\n", error);
++ goto fail_rename;
++ }
++ set_bit(GLF_STICKY, &sdp->sd_trans_gl->gl_flags);
++
++ return 0;
++
++fail_trans:
++ gfs2_glock_put(sdp->sd_trans_gl);
++fail_rename:
++ gfs2_glock_put(sdp->sd_rename_gl);
++fail_live:
++ gfs2_glock_dq_uninit(&sdp->sd_live_gh);
++fail_mount:
++ gfs2_glock_dq_uninit(mount_gh);
++fail:
++ while (sdp->sd_glockd_num--)
++ kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
++
++ kthread_stop(sdp->sd_scand_process);
++ return error;
++}
++
++static struct inode *gfs2_lookup_root(struct super_block *sb,
++ struct gfs2_inum *inum)
++{
++ return gfs2_inode_lookup(sb, inum, DT_DIR);
++}
++
++static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
++{
++ struct super_block *sb = sdp->sd_vfs;
++ struct gfs2_holder sb_gh;
++ struct gfs2_inum *inum;
++ struct inode *inode;
++ int error = 0;
++
++ if (undo) {
++ if (sb->s_root) {
++ dput(sb->s_root);
++ sb->s_root = NULL;
++ }
++ return 0;
++ }
++
++ error = gfs2_glock_nq_num(sdp, GFS2_SB_LOCK, &gfs2_meta_glops,
++ LM_ST_SHARED, 0, &sb_gh);
++ if (error) {
++ fs_err(sdp, "can't acquire superblock glock: %d\n", error);
++ return error;
++ }
++
++ error = gfs2_read_sb(sdp, sb_gh.gh_gl, silent);
++ if (error) {
++ fs_err(sdp, "can't read superblock: %d\n", error);
++ goto out;
++ }
++
++ /* Set up the buffer cache and SB for real */
++ if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) {
++ error = -EINVAL;
++ fs_err(sdp, "FS block size (%u) is too small for device "
++ "block size (%u)\n",
++ sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev));
++ goto out;
++ }
++ if (sdp->sd_sb.sb_bsize > PAGE_SIZE) {
++ error = -EINVAL;
++ fs_err(sdp, "FS block size (%u) is too big for machine "
++ "page size (%u)\n",
++ sdp->sd_sb.sb_bsize, (unsigned int)PAGE_SIZE);
++ goto out;
++ }
++ sb_set_blocksize(sb, sdp->sd_sb.sb_bsize);
++
++ /* Get the root inode */
++ inum = &sdp->sd_sb.sb_root_dir;
++ if (sb->s_type == &gfs2meta_fs_type)
++ inum = &sdp->sd_sb.sb_master_dir;
++ inode = gfs2_lookup_root(sb, inum);
++ if (IS_ERR(inode)) {
++ error = PTR_ERR(inode);
++ fs_err(sdp, "can't read in root inode: %d\n", error);
++ goto out;
++ }
++
++ sb->s_root = d_alloc_root(inode);
++ if (!sb->s_root) {
++ fs_err(sdp, "can't get root dentry\n");
++ error = -ENOMEM;
++ iput(inode);
++ }
++ sb->s_root->d_op = &gfs2_dops;
++out:
++ gfs2_glock_dq_uninit(&sb_gh);
++ return error;
++}
++
++static int init_journal(struct gfs2_sbd *sdp, int undo)
++{
++ struct gfs2_holder ji_gh;
++ struct task_struct *p;
++ struct gfs2_inode *ip;
++ int jindex = 1;
++ int error = 0;
++
++ if (undo) {
++ jindex = 0;
++ goto fail_recoverd;
++ }
++
++ sdp->sd_jindex = gfs2_lookup_simple(sdp->sd_master_dir, "jindex");
++ if (IS_ERR(sdp->sd_jindex)) {
++ fs_err(sdp, "can't lookup journal index: %d\n", error);
++ return PTR_ERR(sdp->sd_jindex);
++ }
++ ip = GFS2_I(sdp->sd_jindex);
++ set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
++
++ /* Load in the journal index special file */
++
++ error = gfs2_jindex_hold(sdp, &ji_gh);
++ if (error) {
++ fs_err(sdp, "can't read journal index: %d\n", error);
++ goto fail;
++ }
++
++ error = -EINVAL;
++ if (!gfs2_jindex_size(sdp)) {
++ fs_err(sdp, "no journals!\n");
++ goto fail_jindex;
++ }
++
++ if (sdp->sd_args.ar_spectator) {
++ sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
++ sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
++ } else {
++ if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
++ fs_err(sdp, "can't mount journal #%u\n",
++ sdp->sd_lockstruct.ls_jid);
++ fs_err(sdp, "there are only %u journals (0 - %u)\n",
++ gfs2_jindex_size(sdp),
++ gfs2_jindex_size(sdp) - 1);
++ goto fail_jindex;
++ }
++ sdp->sd_jdesc = gfs2_jdesc_find(sdp, sdp->sd_lockstruct.ls_jid);
++
++ error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
++ &gfs2_journal_glops,
++ LM_ST_EXCLUSIVE, LM_FLAG_NOEXP,
++ &sdp->sd_journal_gh);
++ if (error) {
++ fs_err(sdp, "can't acquire journal glock: %d\n", error);
++ goto fail_jindex;
++ }
++
++ ip = GFS2_I(sdp->sd_jdesc->jd_inode);
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
++ LM_FLAG_NOEXP | GL_EXACT,
++ &sdp->sd_jinode_gh);
++ if (error) {
++ fs_err(sdp, "can't acquire journal inode glock: %d\n",
++ error);
++ goto fail_journal_gh;
++ }
++
++ error = gfs2_jdesc_check(sdp->sd_jdesc);
++ if (error) {
++ fs_err(sdp, "my journal (%u) is bad: %d\n",
++ sdp->sd_jdesc->jd_jid, error);
++ goto fail_jinode_gh;
++ }
++ sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
++ }
++
++ if (sdp->sd_lockstruct.ls_first) {
++ unsigned int x;
++ for (x = 0; x < sdp->sd_journals; x++) {
++ error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x));
++ if (error) {
++ fs_err(sdp, "error recovering journal %u: %d\n",
++ x, error);
++ goto fail_jinode_gh;
++ }
++ }
++
++ gfs2_lm_others_may_mount(sdp);
++ } else if (!sdp->sd_args.ar_spectator) {
++ error = gfs2_recover_journal(sdp->sd_jdesc);
++ if (error) {
++ fs_err(sdp, "error recovering my journal: %d\n", error);
++ goto fail_jinode_gh;
++ }
++ }
++
++ set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
++ gfs2_glock_dq_uninit(&ji_gh);
++ jindex = 0;
++
++ p = kthread_run(gfs2_recoverd, sdp, "gfs2_recoverd");
++ error = IS_ERR(p);
++ if (error) {
++ fs_err(sdp, "can't start recoverd thread: %d\n", error);
++ goto fail_jinode_gh;
++ }
++ sdp->sd_recoverd_process = p;
++
++ return 0;
++
++fail_recoverd:
++ kthread_stop(sdp->sd_recoverd_process);
++fail_jinode_gh:
++ if (!sdp->sd_args.ar_spectator)
++ gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
++fail_journal_gh:
++ if (!sdp->sd_args.ar_spectator)
++ gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
++fail_jindex:
++ gfs2_jindex_free(sdp);
++ if (jindex)
++ gfs2_glock_dq_uninit(&ji_gh);
++fail:
++ iput(sdp->sd_jindex);
++ return error;
++}
++
++
++static int init_inodes(struct gfs2_sbd *sdp, int undo)
++{
++ int error = 0;
++ struct gfs2_inode *ip;
++ struct inode *inode;
++
++ if (undo)
++ goto fail_qinode;
++
++ inode = gfs2_lookup_root(sdp->sd_vfs, &sdp->sd_sb.sb_master_dir);
++ if (IS_ERR(inode)) {
++ error = PTR_ERR(inode);
++ fs_err(sdp, "can't read in master directory: %d\n", error);
++ goto fail;
++ }
++ sdp->sd_master_dir = inode;
++
++ error = init_journal(sdp, undo);
++ if (error)
++ goto fail_master;
++
++ /* Read in the master inode number inode */
++ sdp->sd_inum_inode = gfs2_lookup_simple(sdp->sd_master_dir, "inum");
++ if (IS_ERR(sdp->sd_inum_inode)) {
++ error = PTR_ERR(sdp->sd_inum_inode);
++ fs_err(sdp, "can't read in inum inode: %d\n", error);
++ goto fail_journal;
++ }
++
++
++ /* Read in the master statfs inode */
++ sdp->sd_statfs_inode = gfs2_lookup_simple(sdp->sd_master_dir, "statfs");
++ if (IS_ERR(sdp->sd_statfs_inode)) {
++ error = PTR_ERR(sdp->sd_statfs_inode);
++ fs_err(sdp, "can't read in statfs inode: %d\n", error);
++ goto fail_inum;
++ }
++
++ /* Read in the resource index inode */
++ sdp->sd_rindex = gfs2_lookup_simple(sdp->sd_master_dir, "rindex");
++ if (IS_ERR(sdp->sd_rindex)) {
++ error = PTR_ERR(sdp->sd_rindex);
++ fs_err(sdp, "can't get resource index inode: %d\n", error);
++ goto fail_statfs;
++ }
++ ip = GFS2_I(sdp->sd_rindex);
++ set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
++ sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1;
++
++ /* Read in the quota inode */
++ sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota");
++ if (IS_ERR(sdp->sd_quota_inode)) {
++ error = PTR_ERR(sdp->sd_quota_inode);
++ fs_err(sdp, "can't get quota file inode: %d\n", error);
++ goto fail_rindex;
++ }
++ return 0;
++
++fail_qinode:
++ iput(sdp->sd_quota_inode);
++fail_rindex:
++ gfs2_clear_rgrpd(sdp);
++ iput(sdp->sd_rindex);
++fail_statfs:
++ iput(sdp->sd_statfs_inode);
++fail_inum:
++ iput(sdp->sd_inum_inode);
++fail_journal:
++ init_journal(sdp, UNDO);
++fail_master:
++ iput(sdp->sd_master_dir);
++fail:
++ return error;
++}
++
++static int init_per_node(struct gfs2_sbd *sdp, int undo)
++{
++ struct inode *pn = NULL;
++ char buf[30];
++ int error = 0;
++ struct gfs2_inode *ip;
++
++ if (sdp->sd_args.ar_spectator)
++ return 0;
++
++ if (undo)
++ goto fail_qc_gh;
++
++ pn = gfs2_lookup_simple(sdp->sd_master_dir, "per_node");
++ if (IS_ERR(pn)) {
++ error = PTR_ERR(pn);
++ fs_err(sdp, "can't find per_node directory: %d\n", error);
++ return error;
++ }
++
++ sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid);
++ sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf);
++ if (IS_ERR(sdp->sd_ir_inode)) {
++ error = PTR_ERR(sdp->sd_ir_inode);
++ fs_err(sdp, "can't find local \"ir\" file: %d\n", error);
++ goto fail;
++ }
++
++ sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid);
++ sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf);
++ if (IS_ERR(sdp->sd_sc_inode)) {
++ error = PTR_ERR(sdp->sd_sc_inode);
++ fs_err(sdp, "can't find local \"sc\" file: %d\n", error);
++ goto fail_ir_i;
++ }
++
++ sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
++ sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf);
++ if (IS_ERR(sdp->sd_qc_inode)) {
++ error = PTR_ERR(sdp->sd_qc_inode);
++ fs_err(sdp, "can't find local \"qc\" file: %d\n", error);
++ goto fail_ut_i;
++ }
++
++ iput(pn);
++ pn = NULL;
++
++ ip = GFS2_I(sdp->sd_ir_inode);
++ error = gfs2_glock_nq_init(ip->i_gl,
++ LM_ST_EXCLUSIVE, 0,
++ &sdp->sd_ir_gh);
++ if (error) {
++ fs_err(sdp, "can't lock local \"ir\" file: %d\n", error);
++ goto fail_qc_i;
++ }
++
++ ip = GFS2_I(sdp->sd_sc_inode);
++ error = gfs2_glock_nq_init(ip->i_gl,
++ LM_ST_EXCLUSIVE, 0,
++ &sdp->sd_sc_gh);
++ if (error) {
++ fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
++ goto fail_ir_gh;
++ }
++
++ ip = GFS2_I(sdp->sd_qc_inode);
++ error = gfs2_glock_nq_init(ip->i_gl,
++ LM_ST_EXCLUSIVE, 0,
++ &sdp->sd_qc_gh);
++ if (error) {
++ fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
++ goto fail_ut_gh;
++ }
++
++ return 0;
++
++fail_qc_gh:
++ gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
++fail_ut_gh:
++ gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
++fail_ir_gh:
++ gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
++fail_qc_i:
++ iput(sdp->sd_qc_inode);
++fail_ut_i:
++ iput(sdp->sd_sc_inode);
++fail_ir_i:
++ iput(sdp->sd_ir_inode);
++fail:
++ if (pn)
++ iput(pn);
++ return error;
++}
++
++static int init_threads(struct gfs2_sbd *sdp, int undo)
++{
++ struct task_struct *p;
++ int error = 0;
++
++ if (undo)
++ goto fail_quotad;
++
++ sdp->sd_log_flush_time = jiffies;
++ sdp->sd_jindex_refresh_time = jiffies;
++
++ p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
++ error = IS_ERR(p);
++ if (error) {
++ fs_err(sdp, "can't start logd thread: %d\n", error);
++ return error;
++ }
++ sdp->sd_logd_process = p;
++
++ sdp->sd_statfs_sync_time = jiffies;
++ sdp->sd_quota_sync_time = jiffies;
++
++ p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
++ error = IS_ERR(p);
++ if (error) {
++ fs_err(sdp, "can't start quotad thread: %d\n", error);
++ goto fail;
++ }
++ sdp->sd_quotad_process = p;
++
++ return 0;
++
++
++fail_quotad:
++ kthread_stop(sdp->sd_quotad_process);
++fail:
++ kthread_stop(sdp->sd_logd_process);
++ return error;
++}
++
++/**
++ * fill_super - Read in superblock
++ * @sb: The VFS superblock
++ * @data: Mount options
++ * @silent: Don't complain if it's not a GFS2 filesystem
++ *
++ * Returns: errno
++ */
++
++static int fill_super(struct super_block *sb, void *data, int silent)
++{
++ struct gfs2_sbd *sdp;
++ struct gfs2_holder mount_gh;
++ int error;
++
++ sdp = init_sbd(sb);
++ if (!sdp) {
++ printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
++ return -ENOMEM;
++ }
++
++ error = gfs2_mount_args(sdp, (char *)data, 0);
++ if (error) {
++ printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
++ goto fail;
++ }
++
++ init_vfs(sb, SDF_NOATIME);
++
++ /* Set up the buffer cache and fill in some fake block size values
++ to allow us to read-in the on-disk superblock. */
++ sdp->sd_sb.sb_bsize = sb_min_blocksize(sb, GFS2_BASIC_BLOCK);
++ sdp->sd_sb.sb_bsize_shift = sb->s_blocksize_bits;
++ sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
++ GFS2_BASIC_BLOCK_SHIFT;
++ sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
++
++ error = init_names(sdp, silent);
++ if (error)
++ goto fail;
++
++ error = gfs2_sys_fs_add(sdp);
++ if (error)
++ goto fail;
++
++ error = gfs2_lm_mount(sdp, silent);
++ if (error)
++ goto fail_sys;
++
++ error = init_locking(sdp, &mount_gh, DO);
++ if (error)
++ goto fail_lm;
++
++ error = init_sb(sdp, silent, DO);
++ if (error)
++ goto fail_locking;
++
++ error = init_inodes(sdp, DO);
++ if (error)
++ goto fail_sb;
++
++ error = init_per_node(sdp, DO);
++ if (error)
++ goto fail_inodes;
++
++ error = gfs2_statfs_init(sdp);
++ if (error) {
++ fs_err(sdp, "can't initialize statfs subsystem: %d\n", error);
++ goto fail_per_node;
++ }
++
++ error = init_threads(sdp, DO);
++ if (error)
++ goto fail_per_node;
++
++ if (!(sb->s_flags & MS_RDONLY)) {
++ error = gfs2_make_fs_rw(sdp);
++ if (error) {
++ fs_err(sdp, "can't make FS RW: %d\n", error);
++ goto fail_threads;
++ }
++ }
++
++ gfs2_glock_dq_uninit(&mount_gh);
++
++ return 0;
++
++fail_threads:
++ init_threads(sdp, UNDO);
++fail_per_node:
++ init_per_node(sdp, UNDO);
++fail_inodes:
++ init_inodes(sdp, UNDO);
++fail_sb:
++ init_sb(sdp, 0, UNDO);
++fail_locking:
++ init_locking(sdp, &mount_gh, UNDO);
++fail_lm:
++ gfs2_gl_hash_clear(sdp, WAIT);
++ gfs2_lm_unmount(sdp);
++ while (invalidate_inodes(sb))
++ yield();
++fail_sys:
++ gfs2_sys_fs_del(sdp);
++fail:
++ kfree(sdp);
++ sb->s_fs_info = NULL;
++ return error;
++}
++
++static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data, struct vfsmount *mnt)
++{
++ struct super_block *sb;
++ struct gfs2_sbd *sdp;
++ int error = get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
++ if (error)
++ goto out;
++ sb = mnt->mnt_sb;
++ sdp = sb->s_fs_info;
++ sdp->sd_gfs2mnt = mnt;
++out:
++ return error;
++}
++
++static int fill_super_meta(struct super_block *sb, struct super_block *new,
++ void *data, int silent)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ struct inode *inode;
++ int error = 0;
++
++ new->s_fs_info = sdp;
++ sdp->sd_vfs_meta = sb;
++
++ init_vfs(new, SDF_NOATIME);
++
++ /* Get the master inode */
++ inode = igrab(sdp->sd_master_dir);
++
++ new->s_root = d_alloc_root(inode);
++ if (!new->s_root) {
++ fs_err(sdp, "can't get root dentry\n");
++ error = -ENOMEM;
++ iput(inode);
++ } else
++ new->s_root->d_op = &gfs2_dops;
++
++ return error;
++}
++
++static int set_bdev_super(struct super_block *s, void *data)
++{
++ s->s_bdev = data;
++ s->s_dev = s->s_bdev->bd_dev;
++ return 0;
++}
++
++static int test_bdev_super(struct super_block *s, void *data)
++{
++ return s->s_bdev == data;
++}
++
++static struct super_block* get_gfs2_sb(const char *dev_name)
++{
++ struct kstat stat;
++ struct nameidata nd;
++ struct file_system_type *fstype;
++ struct super_block *sb = NULL, *s;
++ struct list_head *l;
++ int error;
++
++ error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
++ if (error) {
++ printk(KERN_WARNING "GFS2: path_lookup on %s returned error\n",
++ dev_name);
++ goto out;
++ }
++ error = vfs_getattr(nd.mnt, nd.dentry, &stat);
++
++ fstype = get_fs_type("gfs2");
++ list_for_each(l, &fstype->fs_supers) {
++ s = list_entry(l, struct super_block, s_instances);
++ if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
++ (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) {
++ sb = s;
++ goto free_nd;
++ }
++ }
++
++ printk(KERN_WARNING "GFS2: Unrecognized block device or "
++ "mount point %s", dev_name);
++
++free_nd:
++ path_release(&nd);
++out:
++ return sb;
++}
++
++static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data, struct vfsmount *mnt)
++{
++ int error = 0;
++ struct super_block *sb = NULL, *new;
++ struct gfs2_sbd *sdp;
++
++ sb = get_gfs2_sb(dev_name);
++ if (!sb) {
++ printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
++ error = -ENOENT;
++ goto error;
++ }
++ sdp = (struct gfs2_sbd*) sb->s_fs_info;
++ if (sdp->sd_vfs_meta) {
++ printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
++ error = -EBUSY;
++ goto error;
++ }
++ mutex_lock(&sb->s_bdev->bd_mount_mutex);
++ new = sget(fs_type, test_bdev_super, set_bdev_super, sb->s_bdev);
++ mutex_unlock(&sb->s_bdev->bd_mount_mutex);
++ if (IS_ERR(new)) {
++ error = PTR_ERR(new);
++ goto error;
++ }
++ module_put(fs_type->owner);
++ new->s_flags = flags;
++ strlcpy(new->s_id, sb->s_id, sizeof(new->s_id));
++ sb_set_blocksize(new, sb->s_blocksize);
++ error = fill_super_meta(sb, new, data, flags & MS_SILENT ? 1 : 0);
++ if (error) {
++ up_write(&new->s_umount);
++ deactivate_super(new);
++ goto error;
++ }
++
++ new->s_flags |= MS_ACTIVE;
++
++ /* Grab a reference to the gfs2 mount point */
++ atomic_inc(&sdp->sd_gfs2mnt->mnt_count);
++ return simple_set_mnt(mnt, new);
++error:
++ return error;
++}
++
++static void gfs2_kill_sb(struct super_block *sb)
++{
++ kill_block_super(sb);
++}
++
++static void gfs2_kill_sb_meta(struct super_block *sb)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ generic_shutdown_super(sb);
++ sdp->sd_vfs_meta = NULL;
++ atomic_dec(&sdp->sd_gfs2mnt->mnt_count);
++}
++
++struct file_system_type gfs2_fs_type = {
++ .name = "gfs2",
++ .fs_flags = FS_REQUIRES_DEV,
++ .get_sb = gfs2_get_sb,
++ .kill_sb = gfs2_kill_sb,
++ .owner = THIS_MODULE,
++};
++
++struct file_system_type gfs2meta_fs_type = {
++ .name = "gfs2meta",
++ .fs_flags = FS_REQUIRES_DEV,
++ .get_sb = gfs2_get_sb_meta,
++ .kill_sb = gfs2_kill_sb_meta,
++ .owner = THIS_MODULE,
++};
++
+diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h
+new file mode 100644
+index 0000000..7cc2c29
+--- /dev/null
++++ b/fs/gfs2/ops_fstype.h
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_FSTYPE_DOT_H__
++#define __OPS_FSTYPE_DOT_H__
++
++#include <linux/fs.h>
++
++extern struct file_system_type gfs2_fs_type;
++extern struct file_system_type gfs2meta_fs_type;
++
++#endif /* __OPS_FSTYPE_DOT_H__ */
+diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
+new file mode 100644
+index 0000000..ef6e5ed
+--- /dev/null
++++ b/fs/gfs2/ops_inode.c
+@@ -0,0 +1,1151 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/namei.h>
++#include <linux/utsname.h>
++#include <linux/mm.h>
++#include <linux/xattr.h>
++#include <linux/posix_acl.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "acl.h"
++#include "bmap.h"
++#include "dir.h"
++#include "eaops.h"
++#include "eattr.h"
++#include "glock.h"
++#include "inode.h"
++#include "meta_io.h"
++#include "ops_dentry.h"
++#include "ops_inode.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++
++/**
++ * gfs2_create - Create a file
++ * @dir: The directory in which to create the file
++ * @dentry: The dentry of the new file
++ * @mode: The mode of the new file
++ *
++ * Returns: errno
++ */
++
++static int gfs2_create(struct inode *dir, struct dentry *dentry,
++ int mode, struct nameidata *nd)
++{
++ struct gfs2_inode *dip = GFS2_I(dir);
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct gfs2_holder ghs[2];
++ struct inode *inode;
++
++ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
++
++ for (;;) {
++ inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode);
++ if (!IS_ERR(inode)) {
++ gfs2_trans_end(sdp);
++ if (dip->i_alloc.al_rgd)
++ gfs2_inplace_release(dip);
++ gfs2_quota_unlock(dip);
++ gfs2_alloc_put(dip);
++ gfs2_glock_dq_uninit_m(2, ghs);
++ mark_inode_dirty(inode);
++ break;
++ } else if (PTR_ERR(inode) != -EEXIST ||
++ (nd->intent.open.flags & O_EXCL)) {
++ gfs2_holder_uninit(ghs);
++ return PTR_ERR(inode);
++ }
++
++ inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
++ if (inode) {
++ if (!IS_ERR(inode)) {
++ gfs2_holder_uninit(ghs);
++ break;
++ } else {
++ gfs2_holder_uninit(ghs);
++ return PTR_ERR(inode);
++ }
++ }
++ }
++
++ d_instantiate(dentry, inode);
++
++ return 0;
++}
++
++/**
++ * gfs2_lookup - Look up a filename in a directory and return its inode
++ * @dir: The directory inode
++ * @dentry: The dentry of the new inode
++ * @nd: passed from Linux VFS, ignored by us
++ *
++ * Called by the VFS layer. Lock dir and call gfs2_lookupi()
++ *
++ * Returns: errno
++ */
++
++static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ struct inode *inode = NULL;
++
++ dentry->d_op = &gfs2_dops;
++
++ inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
++ if (inode && IS_ERR(inode))
++ return ERR_PTR(PTR_ERR(inode));
++
++ if (inode)
++ return d_splice_alias(inode, dentry);
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++/**
++ * gfs2_link - Link to a file
++ * @old_dentry: The inode to link
++ * @dir: Add link to this directory
++ * @dentry: The name of the link
++ *
++ * Link the inode in "old_dentry" into the directory "dir" with the
++ * name in "dentry".
++ *
++ * Returns: errno
++ */
++
++static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct gfs2_inode *dip = GFS2_I(dir);
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct inode *inode = old_dentry->d_inode;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder ghs[2];
++ int alloc_required;
++ int error;
++
++ if (S_ISDIR(ip->i_di.di_mode))
++ return -EPERM;
++
++ gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
++ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
++
++ error = gfs2_glock_nq_m(2, ghs);
++ if (error)
++ goto out;
++
++ error = permission(dir, MAY_WRITE | MAY_EXEC, NULL);
++ if (error)
++ goto out_gunlock;
++
++ error = gfs2_dir_search(dir, &dentry->d_name, NULL, NULL);
++ switch (error) {
++ case -ENOENT:
++ break;
++ case 0:
++ error = -EEXIST;
++ default:
++ goto out_gunlock;
++ }
++
++ error = -EINVAL;
++ if (!dip->i_di.di_nlink)
++ goto out_gunlock;
++ error = -EFBIG;
++ if (dip->i_di.di_entries == (u32)-1)
++ goto out_gunlock;
++ error = -EPERM;
++ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
++ goto out_gunlock;
++ error = -EINVAL;
++ if (!ip->i_di.di_nlink)
++ goto out_gunlock;
++ error = -EMLINK;
++ if (ip->i_di.di_nlink == (u32)-1)
++ goto out_gunlock;
++
++ alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
++ if (error < 0)
++ goto out_gunlock;
++ error = 0;
++
++ if (alloc_required) {
++ struct gfs2_alloc *al = gfs2_alloc_get(dip);
++
++ error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out_alloc;
++
++ error = gfs2_quota_check(dip, dip->i_di.di_uid,
++ dip->i_di.di_gid);
++ if (error)
++ goto out_gunlock_q;
++
++ al->al_requested = sdp->sd_max_dirres;
++
++ error = gfs2_inplace_reserve(dip);
++ if (error)
++ goto out_gunlock_q;
++
++ error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
++ al->al_rgd->rd_ri.ri_length +
++ 2 * RES_DINODE + RES_STATFS +
++ RES_QUOTA, 0);
++ if (error)
++ goto out_ipres;
++ } else {
++ error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
++ if (error)
++ goto out_ipres;
++ }
++
++ error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num,
++ IF2DT(ip->i_di.di_mode));
++ if (error)
++ goto out_end_trans;
++
++ error = gfs2_change_nlink(ip, +1);
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_ipres:
++ if (alloc_required)
++ gfs2_inplace_release(dip);
++out_gunlock_q:
++ if (alloc_required)
++ gfs2_quota_unlock(dip);
++out_alloc:
++ if (alloc_required)
++ gfs2_alloc_put(dip);
++out_gunlock:
++ gfs2_glock_dq_m(2, ghs);
++out:
++ gfs2_holder_uninit(ghs);
++ gfs2_holder_uninit(ghs + 1);
++ if (!error) {
++ atomic_inc(&inode->i_count);
++ d_instantiate(dentry, inode);
++ mark_inode_dirty(inode);
++ }
++ return error;
++}
++
++/**
++ * gfs2_unlink - Unlink a file
++ * @dir: The inode of the directory containing the file to unlink
++ * @dentry: The file itself
++ *
++ * Unlink a file. Call gfs2_unlinki()
++ *
++ * Returns: errno
++ */
++
++static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
++{
++ struct gfs2_inode *dip = GFS2_I(dir);
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
++ struct gfs2_holder ghs[2];
++ int error;
++
++ gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
++ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
++
++ error = gfs2_glock_nq_m(2, ghs);
++ if (error)
++ goto out;
++
++ error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
++ if (error)
++ goto out_gunlock;
++
++ error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
++ if (error)
++ goto out_gunlock;
++
++ error = gfs2_dir_del(dip, &dentry->d_name);
++ if (error)
++ goto out_end_trans;
++
++ error = gfs2_change_nlink(ip, -1);
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_gunlock:
++ gfs2_glock_dq_m(2, ghs);
++out:
++ gfs2_holder_uninit(ghs);
++ gfs2_holder_uninit(ghs + 1);
++ return error;
++}
++
++/**
++ * gfs2_symlink - Create a symlink
++ * @dir: The directory to create the symlink in
++ * @dentry: The dentry to put the symlink in
++ * @symname: The thing which the link points to
++ *
++ * Returns: errno
++ */
++
++static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ struct gfs2_inode *dip = GFS2_I(dir), *ip;
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct gfs2_holder ghs[2];
++ struct inode *inode;
++ struct buffer_head *dibh;
++ int size;
++ int error;
++
++ /* Must be stuffed with a null terminator for gfs2_follow_link() */
++ size = strlen(symname);
++ if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
++ return -ENAMETOOLONG;
++
++ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
++
++ inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO);
++ if (IS_ERR(inode)) {
++ gfs2_holder_uninit(ghs);
++ return PTR_ERR(inode);
++ }
++
++ ip = ghs[1].gh_gl->gl_object;
++
++ ip->i_di.di_size = size;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++
++ if (!gfs2_assert_withdraw(sdp, !error)) {
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname,
++ size);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(sdp);
++ if (dip->i_alloc.al_rgd)
++ gfs2_inplace_release(dip);
++ gfs2_quota_unlock(dip);
++ gfs2_alloc_put(dip);
++
++ gfs2_glock_dq_uninit_m(2, ghs);
++
++ d_instantiate(dentry, inode);
++ mark_inode_dirty(inode);
++
++ return 0;
++}
++
++/**
++ * gfs2_mkdir - Make a directory
++ * @dir: The parent directory of the new one
++ * @dentry: The dentry of the new directory
++ * @mode: The mode of the new directory
++ *
++ * Returns: errno
++ */
++
++static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ struct gfs2_inode *dip = GFS2_I(dir), *ip;
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct gfs2_holder ghs[2];
++ struct inode *inode;
++ struct buffer_head *dibh;
++ int error;
++
++ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
++
++ inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode);
++ if (IS_ERR(inode)) {
++ gfs2_holder_uninit(ghs);
++ return PTR_ERR(inode);
++ }
++
++ ip = ghs[1].gh_gl->gl_object;
++
++ ip->i_di.di_nlink = 2;
++ ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
++ ip->i_di.di_flags |= GFS2_DIF_JDATA;
++ ip->i_di.di_payload_format = GFS2_FORMAT_DE;
++ ip->i_di.di_entries = 2;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++
++ if (!gfs2_assert_withdraw(sdp, !error)) {
++ struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
++ struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
++ struct qstr str;
++
++ gfs2_str2qstr(&str, ".");
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
++ dent->de_inum = di->di_num; /* already GFS2 endian */
++ dent->de_type = cpu_to_be16(DT_DIR);
++ di->di_entries = cpu_to_be32(1);
++
++ gfs2_str2qstr(&str, "..");
++ dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
++ gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
++
++ gfs2_inum_out(&dip->i_num, &dent->de_inum);
++ dent->de_type = cpu_to_be16(DT_DIR);
++
++ gfs2_dinode_out(&ip->i_di, di);
++
++ brelse(dibh);
++ }
++
++ error = gfs2_change_nlink(dip, +1);
++ gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
++
++ gfs2_trans_end(sdp);
++ if (dip->i_alloc.al_rgd)
++ gfs2_inplace_release(dip);
++ gfs2_quota_unlock(dip);
++ gfs2_alloc_put(dip);
++
++ gfs2_glock_dq_uninit_m(2, ghs);
++
++ d_instantiate(dentry, inode);
++ mark_inode_dirty(inode);
++
++ return 0;
++}
++
++/**
++ * gfs2_rmdir - Remove a directory
++ * @dir: The parent directory of the directory to be removed
++ * @dentry: The dentry of the directory to remove
++ *
++ * Remove a directory. Call gfs2_rmdiri()
++ *
++ * Returns: errno
++ */
++
++static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ struct gfs2_inode *dip = GFS2_I(dir);
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
++ struct gfs2_holder ghs[2];
++ int error;
++
++ gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
++ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
++
++ error = gfs2_glock_nq_m(2, ghs);
++ if (error)
++ goto out;
++
++ error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
++ if (error)
++ goto out_gunlock;
++
++ if (ip->i_di.di_entries < 2) {
++ if (gfs2_consist_inode(ip))
++ gfs2_dinode_print(&ip->i_di);
++ error = -EIO;
++ goto out_gunlock;
++ }
++ if (ip->i_di.di_entries > 2) {
++ error = -ENOTEMPTY;
++ goto out_gunlock;
++ }
++
++ error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0);
++ if (error)
++ goto out_gunlock;
++
++ error = gfs2_rmdiri(dip, &dentry->d_name, ip);
++
++ gfs2_trans_end(sdp);
++
++out_gunlock:
++ gfs2_glock_dq_m(2, ghs);
++out:
++ gfs2_holder_uninit(ghs);
++ gfs2_holder_uninit(ghs + 1);
++ return error;
++}
++
++/**
++ * gfs2_mknod - Make a special file
++ * @dir: The directory in which the special file will reside
++ * @dentry: The dentry of the special file
++ * @mode: The mode of the special file
++ * @rdev: The device specification of the special file
++ *
++ */
++
++static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ dev_t dev)
++{
++ struct gfs2_inode *dip = GFS2_I(dir), *ip;
++ struct gfs2_sbd *sdp = GFS2_SB(dir);
++ struct gfs2_holder ghs[2];
++ struct inode *inode;
++ struct buffer_head *dibh;
++ u32 major = 0, minor = 0;
++ int error;
++
++ switch (mode & S_IFMT) {
++ case S_IFBLK:
++ case S_IFCHR:
++ major = MAJOR(dev);
++ minor = MINOR(dev);
++ break;
++ case S_IFIFO:
++ case S_IFSOCK:
++ break;
++ default:
++ return -EOPNOTSUPP;
++ };
++
++ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
++
++ inode = gfs2_createi(ghs, &dentry->d_name, mode);
++ if (IS_ERR(inode)) {
++ gfs2_holder_uninit(ghs);
++ return PTR_ERR(inode);
++ }
++
++ ip = ghs[1].gh_gl->gl_object;
++
++ ip->i_di.di_major = major;
++ ip->i_di.di_minor = minor;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++
++ if (!gfs2_assert_withdraw(sdp, !error)) {
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ gfs2_trans_end(sdp);
++ if (dip->i_alloc.al_rgd)
++ gfs2_inplace_release(dip);
++ gfs2_quota_unlock(dip);
++ gfs2_alloc_put(dip);
++
++ gfs2_glock_dq_uninit_m(2, ghs);
++
++ d_instantiate(dentry, inode);
++ mark_inode_dirty(inode);
++
++ return 0;
++}
++
++/**
++ * gfs2_rename - Rename a file
++ * @odir: Parent directory of old file name
++ * @odentry: The old dentry of the file
++ * @ndir: Parent directory of new file name
++ * @ndentry: The new dentry of the file
++ *
++ * Returns: errno
++ */
++
++static int gfs2_rename(struct inode *odir, struct dentry *odentry,
++ struct inode *ndir, struct dentry *ndentry)
++{
++ struct gfs2_inode *odip = GFS2_I(odir);
++ struct gfs2_inode *ndip = GFS2_I(ndir);
++ struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
++ struct gfs2_inode *nip = NULL;
++ struct gfs2_sbd *sdp = GFS2_SB(odir);
++ struct gfs2_holder ghs[4], r_gh;
++ unsigned int num_gh;
++ int dir_rename = 0;
++ int alloc_required;
++ unsigned int x;
++ int error;
++
++ if (ndentry->d_inode) {
++ nip = GFS2_I(ndentry->d_inode);
++ if (ip == nip)
++ return 0;
++ }
++
++ /* Make sure we aren't trying to move a dirctory into it's subdir */
++
++ if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) {
++ dir_rename = 1;
++
++ error = gfs2_glock_nq_init(sdp->sd_rename_gl,
++ LM_ST_EXCLUSIVE, 0,
++ &r_gh);
++ if (error)
++ goto out;
++
++ error = gfs2_ok_to_move(ip, ndip);
++ if (error)
++ goto out_gunlock_r;
++ }
++
++ num_gh = 1;
++ gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
++ if (odip != ndip) {
++ gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
++ num_gh++;
++ }
++ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
++ num_gh++;
++
++ if (nip) {
++ gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
++ num_gh++;
++ }
++
++ error = gfs2_glock_nq_m(num_gh, ghs);
++ if (error)
++ goto out_uninit;
++
++ /* Check out the old directory */
++
++ error = gfs2_unlink_ok(odip, &odentry->d_name, ip);
++ if (error)
++ goto out_gunlock;
++
++ /* Check out the new directory */
++
++ if (nip) {
++ error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);
++ if (error)
++ goto out_gunlock;
++
++ if (S_ISDIR(nip->i_di.di_mode)) {
++ if (nip->i_di.di_entries < 2) {
++ if (gfs2_consist_inode(nip))
++ gfs2_dinode_print(&nip->i_di);
++ error = -EIO;
++ goto out_gunlock;
++ }
++ if (nip->i_di.di_entries > 2) {
++ error = -ENOTEMPTY;
++ goto out_gunlock;
++ }
++ }
++ } else {
++ error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL);
++ if (error)
++ goto out_gunlock;
++
++ error = gfs2_dir_search(ndir, &ndentry->d_name, NULL, NULL);
++ switch (error) {
++ case -ENOENT:
++ error = 0;
++ break;
++ case 0:
++ error = -EEXIST;
++ default:
++ goto out_gunlock;
++ };
++
++ if (odip != ndip) {
++ if (!ndip->i_di.di_nlink) {
++ error = -EINVAL;
++ goto out_gunlock;
++ }
++ if (ndip->i_di.di_entries == (u32)-1) {
++ error = -EFBIG;
++ goto out_gunlock;
++ }
++ if (S_ISDIR(ip->i_di.di_mode) &&
++ ndip->i_di.di_nlink == (u32)-1) {
++ error = -EMLINK;
++ goto out_gunlock;
++ }
++ }
++ }
++
++ /* Check out the dir to be renamed */
++
++ if (dir_rename) {
++ error = permission(odentry->d_inode, MAY_WRITE, NULL);
++ if (error)
++ goto out_gunlock;
++ }
++
++ alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name);
++ if (error < 0)
++ goto out_gunlock;
++ error = 0;
++
++ if (alloc_required) {
++ struct gfs2_alloc *al = gfs2_alloc_get(ndip);
++
++ error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out_alloc;
++
++ error = gfs2_quota_check(ndip, ndip->i_di.di_uid,
++ ndip->i_di.di_gid);
++ if (error)
++ goto out_gunlock_q;
++
++ al->al_requested = sdp->sd_max_dirres;
++
++ error = gfs2_inplace_reserve(ndip);
++ if (error)
++ goto out_gunlock_q;
++
++ error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
++ al->al_rgd->rd_ri.ri_length +
++ 4 * RES_DINODE + 4 * RES_LEAF +
++ RES_STATFS + RES_QUOTA, 0);
++ if (error)
++ goto out_ipreserv;
++ } else {
++ error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
++ 5 * RES_LEAF, 0);
++ if (error)
++ goto out_gunlock;
++ }
++
++ /* Remove the target file, if it exists */
++
++ if (nip) {
++ if (S_ISDIR(nip->i_di.di_mode))
++ error = gfs2_rmdiri(ndip, &ndentry->d_name, nip);
++ else {
++ error = gfs2_dir_del(ndip, &ndentry->d_name);
++ if (error)
++ goto out_end_trans;
++ error = gfs2_change_nlink(nip, -1);
++ }
++ if (error)
++ goto out_end_trans;
++ }
++
++ if (dir_rename) {
++ struct qstr name;
++ gfs2_str2qstr(&name, "..");
++
++ error = gfs2_change_nlink(ndip, +1);
++ if (error)
++ goto out_end_trans;
++ error = gfs2_change_nlink(odip, -1);
++ if (error)
++ goto out_end_trans;
++
++ error = gfs2_dir_mvino(ip, &name, &ndip->i_num, DT_DIR);
++ if (error)
++ goto out_end_trans;
++ } else {
++ struct buffer_head *dibh;
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out_end_trans;
++ ip->i_di.di_ctime = get_seconds();
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++ }
++
++ error = gfs2_dir_del(odip, &odentry->d_name);
++ if (error)
++ goto out_end_trans;
++
++ error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num,
++ IF2DT(ip->i_di.di_mode));
++ if (error)
++ goto out_end_trans;
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_ipreserv:
++ if (alloc_required)
++ gfs2_inplace_release(ndip);
++out_gunlock_q:
++ if (alloc_required)
++ gfs2_quota_unlock(ndip);
++out_alloc:
++ if (alloc_required)
++ gfs2_alloc_put(ndip);
++out_gunlock:
++ gfs2_glock_dq_m(num_gh, ghs);
++out_uninit:
++ for (x = 0; x < num_gh; x++)
++ gfs2_holder_uninit(ghs + x);
++out_gunlock_r:
++ if (dir_rename)
++ gfs2_glock_dq_uninit(&r_gh);
++out:
++ return error;
++}
++
++/**
++ * gfs2_readlink - Read the value of a symlink
++ * @dentry: the symlink
++ * @buf: the buffer to read the symlink data into
++ * @size: the size of the buffer
++ *
++ * Returns: errno
++ */
++
++static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,
++ int user_size)
++{
++ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
++ char array[GFS2_FAST_NAME_SIZE], *buf = array;
++ unsigned int len = GFS2_FAST_NAME_SIZE;
++ int error;
++
++ error = gfs2_readlinki(ip, &buf, &len);
++ if (error)
++ return error;
++
++ if (user_size > len - 1)
++ user_size = len - 1;
++
++ if (copy_to_user(user_buf, buf, user_size))
++ error = -EFAULT;
++ else
++ error = user_size;
++
++ if (buf != array)
++ kfree(buf);
++
++ return error;
++}
++
++/**
++ * gfs2_follow_link - Follow a symbolic link
++ * @dentry: The dentry of the link
++ * @nd: Data that we pass to vfs_follow_link()
++ *
++ * This can handle symlinks of any size. It is optimised for symlinks
++ * under GFS2_FAST_NAME_SIZE.
++ *
++ * Returns: 0 on success or error code
++ */
++
++static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
++ char array[GFS2_FAST_NAME_SIZE], *buf = array;
++ unsigned int len = GFS2_FAST_NAME_SIZE;
++ int error;
++
++ error = gfs2_readlinki(ip, &buf, &len);
++ if (!error) {
++ error = vfs_follow_link(nd, buf);
++ if (buf != array)
++ kfree(buf);
++ }
++
++ return ERR_PTR(error);
++}
++
++/**
++ * gfs2_permission -
++ * @inode:
++ * @mask:
++ * @nd: passed from Linux VFS, ignored by us
++ *
++ * Returns: errno
++ */
++
++static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder i_gh;
++ int error;
++
++ if (ip->i_vn == ip->i_gl->gl_vn)
++ return generic_permission(inode, mask, gfs2_check_acl);
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
++ if (!error) {
++ error = generic_permission(inode, mask, gfs2_check_acl_locked);
++ gfs2_glock_dq_uninit(&i_gh);
++ }
++
++ return error;
++}
++
++static int setattr_size(struct inode *inode, struct iattr *attr)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ int error;
++
++ if (attr->ia_size != ip->i_di.di_size) {
++ error = vmtruncate(inode, attr->ia_size);
++ if (error)
++ return error;
++ }
++
++ error = gfs2_truncatei(ip, attr->ia_size);
++ if (error)
++ return error;
++
++ return error;
++}
++
++static int setattr_chown(struct inode *inode, struct iattr *attr)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ struct buffer_head *dibh;
++ u32 ouid, ogid, nuid, ngid;
++ int error;
++
++ ouid = ip->i_di.di_uid;
++ ogid = ip->i_di.di_gid;
++ nuid = attr->ia_uid;
++ ngid = attr->ia_gid;
++
++ if (!(attr->ia_valid & ATTR_UID) || ouid == nuid)
++ ouid = nuid = NO_QUOTA_CHANGE;
++ if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)
++ ogid = ngid = NO_QUOTA_CHANGE;
++
++ gfs2_alloc_get(ip);
++
++ error = gfs2_quota_lock(ip, nuid, ngid);
++ if (error)
++ goto out_alloc;
++
++ if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
++ error = gfs2_quota_check(ip, nuid, ngid);
++ if (error)
++ goto out_gunlock_q;
++ }
++
++ error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0);
++ if (error)
++ goto out_gunlock_q;
++
++ error = gfs2_meta_inode_buffer(ip, &dibh);
++ if (error)
++ goto out_end_trans;
++
++ error = inode_setattr(inode, attr);
++ gfs2_assert_warn(sdp, !error);
++ gfs2_inode_attr_out(ip);
++
++ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++ gfs2_dinode_out(&ip->i_di, dibh->b_data);
++ brelse(dibh);
++
++ if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
++ gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid);
++ gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid);
++ }
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_gunlock_q:
++ gfs2_quota_unlock(ip);
++out_alloc:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++/**
++ * gfs2_setattr - Change attributes on an inode
++ * @dentry: The dentry which is changing
++ * @attr: The structure describing the change
++ *
++ * The VFS layer wants to change one or more of an inodes attributes. Write
++ * that change out to disk.
++ *
++ * Returns: errno
++ */
++
++static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder i_gh;
++ int error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
++ if (error)
++ return error;
++
++ error = -EPERM;
++ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
++ goto out;
++
++ error = inode_change_ok(inode, attr);
++ if (error)
++ goto out;
++
++ if (attr->ia_valid & ATTR_SIZE)
++ error = setattr_size(inode, attr);
++ else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
++ error = setattr_chown(inode, attr);
++ else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
++ error = gfs2_acl_chmod(ip, attr);
++ else
++ error = gfs2_setattr_simple(ip, attr);
++
++out:
++ gfs2_glock_dq_uninit(&i_gh);
++ if (!error)
++ mark_inode_dirty(inode);
++ return error;
++}
++
++/**
++ * gfs2_getattr - Read out an inode's attributes
++ * @mnt: The vfsmount the inode is being accessed from
++ * @dentry: The dentry to stat
++ * @stat: The inode's stats
++ *
++ * Returns: errno
++ */
++
++static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
++ struct kstat *stat)
++{
++ struct inode *inode = dentry->d_inode;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder gh;
++ int error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
++ if (!error) {
++ generic_fillattr(inode, stat);
++ gfs2_glock_dq_uninit(&gh);
++ }
++
++ return error;
++}
++
++static int gfs2_setxattr(struct dentry *dentry, const char *name,
++ const void *data, size_t size, int flags)
++{
++ struct inode *inode = dentry->d_inode;
++ struct gfs2_ea_request er;
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++ er.er_type = gfs2_ea_name2type(name, &er.er_name);
++ if (er.er_type == GFS2_EATYPE_UNUSED)
++ return -EOPNOTSUPP;
++ er.er_data = (char *)data;
++ er.er_name_len = strlen(er.er_name);
++ er.er_data_len = size;
++ er.er_flags = flags;
++
++ gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE));
++
++ return gfs2_ea_set(GFS2_I(inode), &er);
++}
++
++static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
++ void *data, size_t size)
++{
++ struct gfs2_ea_request er;
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++ er.er_type = gfs2_ea_name2type(name, &er.er_name);
++ if (er.er_type == GFS2_EATYPE_UNUSED)
++ return -EOPNOTSUPP;
++ er.er_data = data;
++ er.er_name_len = strlen(er.er_name);
++ er.er_data_len = size;
++
++ return gfs2_ea_get(GFS2_I(dentry->d_inode), &er);
++}
++
++static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
++{
++ struct gfs2_ea_request er;
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++ er.er_data = (size) ? buffer : NULL;
++ er.er_data_len = size;
++
++ return gfs2_ea_list(GFS2_I(dentry->d_inode), &er);
++}
++
++static int gfs2_removexattr(struct dentry *dentry, const char *name)
++{
++ struct gfs2_ea_request er;
++
++ memset(&er, 0, sizeof(struct gfs2_ea_request));
++ er.er_type = gfs2_ea_name2type(name, &er.er_name);
++ if (er.er_type == GFS2_EATYPE_UNUSED)
++ return -EOPNOTSUPP;
++ er.er_name_len = strlen(er.er_name);
++
++ return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);
++}
++
++struct inode_operations gfs2_file_iops = {
++ .permission = gfs2_permission,
++ .setattr = gfs2_setattr,
++ .getattr = gfs2_getattr,
++ .setxattr = gfs2_setxattr,
++ .getxattr = gfs2_getxattr,
++ .listxattr = gfs2_listxattr,
++ .removexattr = gfs2_removexattr,
++};
++
++struct inode_operations gfs2_dev_iops = {
++ .permission = gfs2_permission,
++ .setattr = gfs2_setattr,
++ .getattr = gfs2_getattr,
++ .setxattr = gfs2_setxattr,
++ .getxattr = gfs2_getxattr,
++ .listxattr = gfs2_listxattr,
++ .removexattr = gfs2_removexattr,
++};
++
++struct inode_operations gfs2_dir_iops = {
++ .create = gfs2_create,
++ .lookup = gfs2_lookup,
++ .link = gfs2_link,
++ .unlink = gfs2_unlink,
++ .symlink = gfs2_symlink,
++ .mkdir = gfs2_mkdir,
++ .rmdir = gfs2_rmdir,
++ .mknod = gfs2_mknod,
++ .rename = gfs2_rename,
++ .permission = gfs2_permission,
++ .setattr = gfs2_setattr,
++ .getattr = gfs2_getattr,
++ .setxattr = gfs2_setxattr,
++ .getxattr = gfs2_getxattr,
++ .listxattr = gfs2_listxattr,
++ .removexattr = gfs2_removexattr,
++};
++
++struct inode_operations gfs2_symlink_iops = {
++ .readlink = gfs2_readlink,
++ .follow_link = gfs2_follow_link,
++ .permission = gfs2_permission,
++ .setattr = gfs2_setattr,
++ .getattr = gfs2_getattr,
++ .setxattr = gfs2_setxattr,
++ .getxattr = gfs2_getxattr,
++ .listxattr = gfs2_listxattr,
++ .removexattr = gfs2_removexattr,
++};
++
+diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h
+new file mode 100644
+index 0000000..b15acb4
+--- /dev/null
++++ b/fs/gfs2/ops_inode.h
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_INODE_DOT_H__
++#define __OPS_INODE_DOT_H__
++
++#include <linux/fs.h>
++
++extern struct inode_operations gfs2_file_iops;
++extern struct inode_operations gfs2_dir_iops;
++extern struct inode_operations gfs2_symlink_iops;
++extern struct inode_operations gfs2_dev_iops;
++
++#endif /* __OPS_INODE_DOT_H__ */
+diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
+new file mode 100644
+index 0000000..b47d959
+--- /dev/null
++++ b/fs/gfs2/ops_super.c
+@@ -0,0 +1,480 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/statfs.h>
++#include <linux/seq_file.h>
++#include <linux/mount.h>
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "inode.h"
++#include "lm.h"
++#include "log.h"
++#include "mount.h"
++#include "ops_super.h"
++#include "quota.h"
++#include "recovery.h"
++#include "rgrp.h"
++#include "super.h"
++#include "sys.h"
++#include "util.h"
++#include "trans.h"
++#include "dir.h"
++#include "eattr.h"
++#include "bmap.h"
++
++/**
++ * gfs2_write_inode - Make sure the inode is stable on the disk
++ * @inode: The inode
++ * @sync: synchronous write flag
++ *
++ * Returns: errno
++ */
++
++static int gfs2_write_inode(struct inode *inode, int sync)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++
++ /* Check this is a "normal" inode */
++ if (inode->i_private) {
++ if (current->flags & PF_MEMALLOC)
++ return 0;
++ if (sync)
++ gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_put_super - Unmount the filesystem
++ * @sb: The VFS superblock
++ *
++ */
++
++static void gfs2_put_super(struct super_block *sb)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ int error;
++
++ if (!sdp)
++ return;
++
++ if (!strncmp(sb->s_type->name, "gfs2meta", 8))
++ return; /* Nothing to do */
++
++ /* Unfreeze the filesystem, if we need to */
++
++ mutex_lock(&sdp->sd_freeze_lock);
++ if (sdp->sd_freeze_count)
++ gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
++ mutex_unlock(&sdp->sd_freeze_lock);
++
++ kthread_stop(sdp->sd_quotad_process);
++ kthread_stop(sdp->sd_logd_process);
++ kthread_stop(sdp->sd_recoverd_process);
++ while (sdp->sd_glockd_num--)
++ kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
++ kthread_stop(sdp->sd_scand_process);
++
++ if (!(sb->s_flags & MS_RDONLY)) {
++ error = gfs2_make_fs_ro(sdp);
++ if (error)
++ gfs2_io_error(sdp);
++ }
++ /* At this point, we're through modifying the disk */
++
++ /* Release stuff */
++
++ iput(sdp->sd_master_dir);
++ iput(sdp->sd_jindex);
++ iput(sdp->sd_inum_inode);
++ iput(sdp->sd_statfs_inode);
++ iput(sdp->sd_rindex);
++ iput(sdp->sd_quota_inode);
++
++ gfs2_glock_put(sdp->sd_rename_gl);
++ gfs2_glock_put(sdp->sd_trans_gl);
++
++ if (!sdp->sd_args.ar_spectator) {
++ gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
++ gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
++ gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
++ gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
++ gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
++ iput(sdp->sd_ir_inode);
++ iput(sdp->sd_sc_inode);
++ iput(sdp->sd_qc_inode);
++ }
++
++ gfs2_glock_dq_uninit(&sdp->sd_live_gh);
++ gfs2_clear_rgrpd(sdp);
++ gfs2_jindex_free(sdp);
++ /* Take apart glock structures and buffer lists */
++ gfs2_gl_hash_clear(sdp, WAIT);
++ /* Unmount the locking protocol */
++ gfs2_lm_unmount(sdp);
++
++ /* At this point, we're through participating in the lockspace */
++ gfs2_sys_fs_del(sdp);
++ kfree(sdp);
++}
++
++/**
++ * gfs2_write_super
++ * @sb: the superblock
++ *
++ */
++
++static void gfs2_write_super(struct super_block *sb)
++{
++ sb->s_dirt = 0;
++}
++
++/**
++ * gfs2_sync_fs - sync the filesystem
++ * @sb: the superblock
++ *
++ * Flushes the log to disk.
++ */
++static int gfs2_sync_fs(struct super_block *sb, int wait)
++{
++ sb->s_dirt = 0;
++ gfs2_log_flush(sb->s_fs_info, NULL);
++ return 0;
++}
++
++/**
++ * gfs2_write_super_lockfs - prevent further writes to the filesystem
++ * @sb: the VFS structure for the filesystem
++ *
++ */
++
++static void gfs2_write_super_lockfs(struct super_block *sb)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ int error;
++
++ for (;;) {
++ error = gfs2_freeze_fs(sdp);
++ if (!error)
++ break;
++
++ switch (error) {
++ case -EBUSY:
++ fs_err(sdp, "waiting for recovery before freeze\n");
++ break;
++
++ default:
++ fs_err(sdp, "error freezing FS: %d\n", error);
++ break;
++ }
++
++ fs_err(sdp, "retrying...\n");
++ msleep(1000);
++ }
++}
++
++/**
++ * gfs2_unlockfs - reallow writes to the filesystem
++ * @sb: the VFS structure for the filesystem
++ *
++ */
++
++static void gfs2_unlockfs(struct super_block *sb)
++{
++ gfs2_unfreeze_fs(sb->s_fs_info);
++}
++
++/**
++ * gfs2_statfs - Gather and return stats about the filesystem
++ * @sb: The superblock
++ * @statfsbuf: The buffer
++ *
++ * Returns: 0 on success or error code
++ */
++
++static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct super_block *sb = dentry->d_inode->i_sb;
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ struct gfs2_statfs_change sc;
++ int error;
++
++ if (gfs2_tune_get(sdp, gt_statfs_slow))
++ error = gfs2_statfs_slow(sdp, &sc);
++ else
++ error = gfs2_statfs_i(sdp, &sc);
++
++ if (error)
++ return error;
++
++ buf->f_type = GFS2_MAGIC;
++ buf->f_bsize = sdp->sd_sb.sb_bsize;
++ buf->f_blocks = sc.sc_total;
++ buf->f_bfree = sc.sc_free;
++ buf->f_bavail = sc.sc_free;
++ buf->f_files = sc.sc_dinodes + sc.sc_free;
++ buf->f_ffree = sc.sc_free;
++ buf->f_namelen = GFS2_FNAMESIZE;
++
++ return 0;
++}
++
++/**
++ * gfs2_remount_fs - called when the FS is remounted
++ * @sb: the filesystem
++ * @flags: the remount flags
++ * @data: extra data passed in (not used right now)
++ *
++ * Returns: errno
++ */
++
++static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ int error;
++
++ error = gfs2_mount_args(sdp, data, 1);
++ if (error)
++ return error;
++
++ if (sdp->sd_args.ar_spectator)
++ *flags |= MS_RDONLY;
++ else {
++ if (*flags & MS_RDONLY) {
++ if (!(sb->s_flags & MS_RDONLY))
++ error = gfs2_make_fs_ro(sdp);
++ } else if (!(*flags & MS_RDONLY) &&
++ (sb->s_flags & MS_RDONLY)) {
++ error = gfs2_make_fs_rw(sdp);
++ }
++ }
++
++ if (*flags & (MS_NOATIME | MS_NODIRATIME))
++ set_bit(SDF_NOATIME, &sdp->sd_flags);
++ else
++ clear_bit(SDF_NOATIME, &sdp->sd_flags);
++
++ /* Don't let the VFS update atimes. GFS2 handles this itself. */
++ *flags |= MS_NOATIME | MS_NODIRATIME;
++
++ return error;
++}
++
++/**
++ * gfs2_clear_inode - Deallocate an inode when VFS is done with it
++ * @inode: The VFS inode
++ *
++ */
++
++static void gfs2_clear_inode(struct inode *inode)
++{
++ /* This tells us its a "real" inode and not one which only
++ * serves to contain an address space (see rgrp.c, meta_io.c)
++ * which therefore doesn't have its own glocks.
++ */
++ if (inode->i_private) {
++ struct gfs2_inode *ip = GFS2_I(inode);
++ gfs2_glock_inode_squish(inode);
++ gfs2_assert(inode->i_sb->s_fs_info, ip->i_gl->gl_state == LM_ST_UNLOCKED);
++ ip->i_gl->gl_object = NULL;
++ gfs2_glock_schedule_for_reclaim(ip->i_gl);
++ gfs2_glock_put(ip->i_gl);
++ ip->i_gl = NULL;
++ if (ip->i_iopen_gh.gh_gl)
++ gfs2_glock_dq_uninit(&ip->i_iopen_gh);
++ }
++}
++
++/**
++ * gfs2_show_options - Show mount options for /proc/mounts
++ * @s: seq_file structure
++ * @mnt: vfsmount
++ *
++ * Returns: 0 on success or error code
++ */
++
++static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
++{
++ struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
++ struct gfs2_args *args = &sdp->sd_args;
++
++ if (args->ar_lockproto[0])
++ seq_printf(s, ",lockproto=%s", args->ar_lockproto);
++ if (args->ar_locktable[0])
++ seq_printf(s, ",locktable=%s", args->ar_locktable);
++ if (args->ar_hostdata[0])
++ seq_printf(s, ",hostdata=%s", args->ar_hostdata);
++ if (args->ar_spectator)
++ seq_printf(s, ",spectator");
++ if (args->ar_ignore_local_fs)
++ seq_printf(s, ",ignore_local_fs");
++ if (args->ar_localflocks)
++ seq_printf(s, ",localflocks");
++ if (args->ar_localcaching)
++ seq_printf(s, ",localcaching");
++ if (args->ar_debug)
++ seq_printf(s, ",debug");
++ if (args->ar_upgrade)
++ seq_printf(s, ",upgrade");
++ if (args->ar_num_glockd != GFS2_GLOCKD_DEFAULT)
++ seq_printf(s, ",num_glockd=%u", args->ar_num_glockd);
++ if (args->ar_posix_acl)
++ seq_printf(s, ",acl");
++ if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
++ char *state;
++ switch (args->ar_quota) {
++ case GFS2_QUOTA_OFF:
++ state = "off";
++ break;
++ case GFS2_QUOTA_ACCOUNT:
++ state = "account";
++ break;
++ case GFS2_QUOTA_ON:
++ state = "on";
++ break;
++ default:
++ state = "unknown";
++ break;
++ }
++ seq_printf(s, ",quota=%s", state);
++ }
++ if (args->ar_suiddir)
++ seq_printf(s, ",suiddir");
++ if (args->ar_data != GFS2_DATA_DEFAULT) {
++ char *state;
++ switch (args->ar_data) {
++ case GFS2_DATA_WRITEBACK:
++ state = "writeback";
++ break;
++ case GFS2_DATA_ORDERED:
++ state = "ordered";
++ break;
++ default:
++ state = "unknown";
++ break;
++ }
++ seq_printf(s, ",data=%s", state);
++ }
++
++ return 0;
++}
++
++/*
++ * We have to (at the moment) hold the inodes main lock to cover
++ * the gap between unlocking the shared lock on the iopen lock and
++ * taking the exclusive lock. I'd rather do a shared -> exclusive
++ * conversion on the iopen lock, but we can change that later. This
++ * is safe, just less efficient.
++ */
++static void gfs2_delete_inode(struct inode *inode)
++{
++ struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_holder gh;
++ int error;
++
++ if (!inode->i_private)
++ goto out;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &gh);
++ if (unlikely(error)) {
++ gfs2_glock_dq_uninit(&ip->i_iopen_gh);
++ goto out;
++ }
++
++ gfs2_glock_dq(&ip->i_iopen_gh);
++ gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
++ error = gfs2_glock_nq(&ip->i_iopen_gh);
++ if (error)
++ goto out_uninit;
++
++ if (S_ISDIR(ip->i_di.di_mode) &&
++ (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
++ error = gfs2_dir_exhash_dealloc(ip);
++ if (error)
++ goto out_unlock;
++ }
++
++ if (ip->i_di.di_eattr) {
++ error = gfs2_ea_dealloc(ip);
++ if (error)
++ goto out_unlock;
++ }
++
++ if (!gfs2_is_stuffed(ip)) {
++ error = gfs2_file_dealloc(ip);
++ if (error)
++ goto out_unlock;
++ }
++
++ error = gfs2_dinode_dealloc(ip);
++
++out_unlock:
++ gfs2_glock_dq(&ip->i_iopen_gh);
++out_uninit:
++ gfs2_holder_uninit(&ip->i_iopen_gh);
++ gfs2_glock_dq_uninit(&gh);
++ if (error)
++ fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
++out:
++ truncate_inode_pages(&inode->i_data, 0);
++ clear_inode(inode);
++}
++
++
++
++static struct inode *gfs2_alloc_inode(struct super_block *sb)
++{
++ struct gfs2_sbd *sdp = sb->s_fs_info;
++ struct gfs2_inode *ip;
++
++ ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
++ if (ip) {
++ ip->i_flags = 0;
++ ip->i_gl = NULL;
++ ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default);
++ ip->i_last_pfault = jiffies;
++ }
++ return &ip->i_inode;
++}
++
++static void gfs2_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(gfs2_inode_cachep, inode);
++}
++
++struct super_operations gfs2_super_ops = {
++ .alloc_inode = gfs2_alloc_inode,
++ .destroy_inode = gfs2_destroy_inode,
++ .write_inode = gfs2_write_inode,
++ .delete_inode = gfs2_delete_inode,
++ .put_super = gfs2_put_super,
++ .write_super = gfs2_write_super,
++ .sync_fs = gfs2_sync_fs,
++ .write_super_lockfs = gfs2_write_super_lockfs,
++ .unlockfs = gfs2_unlockfs,
++ .statfs = gfs2_statfs,
++ .remount_fs = gfs2_remount_fs,
++ .clear_inode = gfs2_clear_inode,
++ .show_options = gfs2_show_options,
++};
++
+diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h
+new file mode 100644
+index 0000000..9de73f0
+--- /dev/null
++++ b/fs/gfs2/ops_super.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_SUPER_DOT_H__
++#define __OPS_SUPER_DOT_H__
++
++#include <linux/fs.h>
++
++extern struct super_operations gfs2_super_ops;
++
++#endif /* __OPS_SUPER_DOT_H__ */
+diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
+new file mode 100644
+index 0000000..5453d29
+--- /dev/null
++++ b/fs/gfs2/ops_vm.c
+@@ -0,0 +1,184 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "inode.h"
++#include "ops_vm.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "trans.h"
++#include "util.h"
++
++static void pfault_be_greedy(struct gfs2_inode *ip)
++{
++ unsigned int time;
++
++ spin_lock(&ip->i_spin);
++ time = ip->i_greedy;
++ ip->i_last_pfault = jiffies;
++ spin_unlock(&ip->i_spin);
++
++ igrab(&ip->i_inode);
++ if (gfs2_glock_be_greedy(ip->i_gl, time))
++ iput(&ip->i_inode);
++}
++
++static struct page *gfs2_private_nopage(struct vm_area_struct *area,
++ unsigned long address, int *type)
++{
++ struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
++ struct page *result;
++
++ set_bit(GIF_PAGED, &ip->i_flags);
++
++ result = filemap_nopage(area, address, type);
++
++ if (result && result != NOPAGE_OOM)
++ pfault_be_greedy(ip);
++
++ return result;
++}
++
++static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ unsigned long index = page->index;
++ u64 lblock = index << (PAGE_CACHE_SHIFT -
++ sdp->sd_sb.sb_bsize_shift);
++ unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
++ struct gfs2_alloc *al;
++ unsigned int data_blocks, ind_blocks;
++ unsigned int x;
++ int error;
++
++ al = gfs2_alloc_get(ip);
++
++ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++ if (error)
++ goto out;
++
++ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
++ if (error)
++ goto out_gunlock_q;
++
++ gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
++
++ al->al_requested = data_blocks + ind_blocks;
++
++ error = gfs2_inplace_reserve(ip);
++ if (error)
++ goto out_gunlock_q;
++
++ error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length +
++ ind_blocks + RES_DINODE +
++ RES_STATFS + RES_QUOTA, 0);
++ if (error)
++ goto out_ipres;
++
++ if (gfs2_is_stuffed(ip)) {
++ error = gfs2_unstuff_dinode(ip, NULL);
++ if (error)
++ goto out_trans;
++ }
++
++ for (x = 0; x < blocks; ) {
++ u64 dblock;
++ unsigned int extlen;
++ int new = 1;
++
++ error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
++ if (error)
++ goto out_trans;
++
++ lblock += extlen;
++ x += extlen;
++ }
++
++ gfs2_assert_warn(sdp, al->al_alloced);
++
++out_trans:
++ gfs2_trans_end(sdp);
++out_ipres:
++ gfs2_inplace_release(ip);
++out_gunlock_q:
++ gfs2_quota_unlock(ip);
++out:
++ gfs2_alloc_put(ip);
++ return error;
++}
++
++static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
++ unsigned long address, int *type)
++{
++ struct file *file = area->vm_file;
++ struct gfs2_file *gf = file->private_data;
++ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
++ struct gfs2_holder i_gh;
++ struct page *result = NULL;
++ unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
++ area->vm_pgoff;
++ int alloc_required;
++ int error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
++ if (error)
++ return NULL;
++
++ set_bit(GIF_PAGED, &ip->i_flags);
++ set_bit(GIF_SW_PAGED, &ip->i_flags);
++
++ error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT,
++ PAGE_CACHE_SIZE, &alloc_required);
++ if (error)
++ goto out;
++
++ set_bit(GFF_EXLOCK, &gf->f_flags);
++ result = filemap_nopage(area, address, type);
++ clear_bit(GFF_EXLOCK, &gf->f_flags);
++ if (!result || result == NOPAGE_OOM)
++ goto out;
++
++ if (alloc_required) {
++ error = alloc_page_backing(ip, result);
++ if (error) {
++ page_cache_release(result);
++ result = NULL;
++ goto out;
++ }
++ set_page_dirty(result);
++ }
++
++ pfault_be_greedy(ip);
++out:
++ gfs2_glock_dq_uninit(&i_gh);
++
++ return result;
++}
++
++struct vm_operations_struct gfs2_vm_ops_private = {
++ .nopage = gfs2_private_nopage,
++};
++
++struct vm_operations_struct gfs2_vm_ops_sharewrite = {
++ .nopage = gfs2_sharewrite_nopage,
++};
++
+diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h
+new file mode 100644
+index 0000000..4ae8f43
+--- /dev/null
++++ b/fs/gfs2/ops_vm.h
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __OPS_VM_DOT_H__
++#define __OPS_VM_DOT_H__
++
++#include <linux/mm.h>
++
++extern struct vm_operations_struct gfs2_vm_ops_private;
++extern struct vm_operations_struct gfs2_vm_ops_sharewrite;
++
++#endif /* __OPS_VM_DOT_H__ */
+diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
+new file mode 100644
+index 0000000..a3deae7
+--- /dev/null
++++ b/fs/gfs2/quota.c
+@@ -0,0 +1,1228 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++/*
++ * Quota change tags are associated with each transaction that allocates or
++ * deallocates space. Those changes are accumulated locally to each node (in a
++ * per-node file) and then are periodically synced to the quota file. This
++ * avoids the bottleneck of constantly touching the quota file, but introduces
++ * fuzziness in the current usage value of IDs that are being used on different
++ * nodes in the cluster simultaneously. So, it is possible for a user on
++ * multiple nodes to overrun their quota, but that overrun is controlable.
++ * Since quota tags are part of transactions, there is no need to a quota check
++ * program to be run on node crashes or anything like that.
++ *
++ * There are couple of knobs that let the administrator manage the quota
++ * fuzziness. "quota_quantum" sets the maximum time a quota change can be
++ * sitting on one node before being synced to the quota file. (The default is
++ * 60 seconds.) Another knob, "quota_scale" controls how quickly the frequency
++ * of quota file syncs increases as the user moves closer to their limit. The
++ * more frequent the syncs, the more accurate the quota enforcement, but that
++ * means that there is more contention between the nodes for the quota file.
++ * The default value is one. This sets the maximum theoretical quota overrun
++ * (with infinite node with infinite bandwidth) to twice the user's limit. (In
++ * practice, the maximum overrun you see should be much less.) A "quota_scale"
++ * number greater than one makes quota syncs more frequent and reduces the
++ * maximum overrun. Numbers less than one (but greater than zero) make quota
++ * syncs less frequent.
++ *
++ * GFS quotas also use per-ID Lock Value Blocks (LVBs) to cache the contents of
++ * the quota file, so it is not being constantly read.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/sort.h>
++#include <linux/fs.h>
++#include <linux/bio.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "glops.h"
++#include "log.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "super.h"
++#include "trans.h"
++#include "inode.h"
++#include "ops_file.h"
++#include "ops_address.h"
++#include "util.h"
++
++#define QUOTA_USER 1
++#define QUOTA_GROUP 0
++
++static u64 qd2offset(struct gfs2_quota_data *qd)
++{
++ u64 offset;
++
++ offset = 2 * (u64)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags);
++ offset *= sizeof(struct gfs2_quota);
++
++ return offset;
++}
++
++static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id,
++ struct gfs2_quota_data **qdp)
++{
++ struct gfs2_quota_data *qd;
++ int error;
++
++ qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_KERNEL);
++ if (!qd)
++ return -ENOMEM;
++
++ qd->qd_count = 1;
++ qd->qd_id = id;
++ if (user)
++ set_bit(QDF_USER, &qd->qd_flags);
++ qd->qd_slot = -1;
++
++ error = gfs2_glock_get(sdp, 2 * (u64)id + !user,
++ &gfs2_quota_glops, CREATE, &qd->qd_gl);
++ if (error)
++ goto fail;
++
++ error = gfs2_lvb_hold(qd->qd_gl);
++ gfs2_glock_put(qd->qd_gl);
++ if (error)
++ goto fail;
++
++ *qdp = qd;
++
++ return 0;
++
++fail:
++ kfree(qd);
++ return error;
++}
++
++static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
++ struct gfs2_quota_data **qdp)
++{
++ struct gfs2_quota_data *qd = NULL, *new_qd = NULL;
++ int error, found;
++
++ *qdp = NULL;
++
++ for (;;) {
++ found = 0;
++ spin_lock(&sdp->sd_quota_spin);
++ list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
++ if (qd->qd_id == id &&
++ !test_bit(QDF_USER, &qd->qd_flags) == !user) {
++ qd->qd_count++;
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found)
++ qd = NULL;
++
++ if (!qd && new_qd) {
++ qd = new_qd;
++ list_add(&qd->qd_list, &sdp->sd_quota_list);
++ atomic_inc(&sdp->sd_quota_count);
++ new_qd = NULL;
++ }
++
++ spin_unlock(&sdp->sd_quota_spin);
++
++ if (qd || !create) {
++ if (new_qd) {
++ gfs2_lvb_unhold(new_qd->qd_gl);
++ kfree(new_qd);
++ }
++ *qdp = qd;
++ return 0;
++ }
++
++ error = qd_alloc(sdp, user, id, &new_qd);
++ if (error)
++ return error;
++ }
++}
++
++static void qd_hold(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++
++ spin_lock(&sdp->sd_quota_spin);
++ gfs2_assert(sdp, qd->qd_count);
++ qd->qd_count++;
++ spin_unlock(&sdp->sd_quota_spin);
++}
++
++static void qd_put(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++ spin_lock(&sdp->sd_quota_spin);
++ gfs2_assert(sdp, qd->qd_count);
++ if (!--qd->qd_count)
++ qd->qd_last_touched = jiffies;
++ spin_unlock(&sdp->sd_quota_spin);
++}
++
++static int slot_get(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++ unsigned int c, o = 0, b;
++ unsigned char byte = 0;
++
++ spin_lock(&sdp->sd_quota_spin);
++
++ if (qd->qd_slot_count++) {
++ spin_unlock(&sdp->sd_quota_spin);
++ return 0;
++ }
++
++ for (c = 0; c < sdp->sd_quota_chunks; c++)
++ for (o = 0; o < PAGE_SIZE; o++) {
++ byte = sdp->sd_quota_bitmap[c][o];
++ if (byte != 0xFF)
++ goto found;
++ }
++
++ goto fail;
++
++found:
++ for (b = 0; b < 8; b++)
++ if (!(byte & (1 << b)))
++ break;
++ qd->qd_slot = c * (8 * PAGE_SIZE) + o * 8 + b;
++
++ if (qd->qd_slot >= sdp->sd_quota_slots)
++ goto fail;
++
++ sdp->sd_quota_bitmap[c][o] |= 1 << b;
++
++ spin_unlock(&sdp->sd_quota_spin);
++
++ return 0;
++
++fail:
++ qd->qd_slot_count--;
++ spin_unlock(&sdp->sd_quota_spin);
++ return -ENOSPC;
++}
++
++static void slot_hold(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++
++ spin_lock(&sdp->sd_quota_spin);
++ gfs2_assert(sdp, qd->qd_slot_count);
++ qd->qd_slot_count++;
++ spin_unlock(&sdp->sd_quota_spin);
++}
++
++static void slot_put(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++
++ spin_lock(&sdp->sd_quota_spin);
++ gfs2_assert(sdp, qd->qd_slot_count);
++ if (!--qd->qd_slot_count) {
++ gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0);
++ qd->qd_slot = -1;
++ }
++ spin_unlock(&sdp->sd_quota_spin);
++}
++
++static int bh_get(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
++ unsigned int block, offset;
++ struct buffer_head *bh;
++ int error;
++ struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
++
++ mutex_lock(&sdp->sd_quota_mutex);
++
++ if (qd->qd_bh_count++) {
++ mutex_unlock(&sdp->sd_quota_mutex);
++ return 0;
++ }
++
++ block = qd->qd_slot / sdp->sd_qc_per_block;
++ offset = qd->qd_slot % sdp->sd_qc_per_block;;
++
++ bh_map.b_size = 1 << ip->i_inode.i_blkbits;
++ error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map);
++ if (error)
++ goto fail;
++ error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
++ if (error)
++ goto fail;
++ error = -EIO;
++ if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC))
++ goto fail_brelse;
++
++ qd->qd_bh = bh;
++ qd->qd_bh_qc = (struct gfs2_quota_change *)
++ (bh->b_data + sizeof(struct gfs2_meta_header) +
++ offset * sizeof(struct gfs2_quota_change));
++
++ mutex_lock(&sdp->sd_quota_mutex);
++
++ return 0;
++
++fail_brelse:
++ brelse(bh);
++fail:
++ qd->qd_bh_count--;
++ mutex_unlock(&sdp->sd_quota_mutex);
++ return error;
++}
++
++static void bh_put(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++
++ mutex_lock(&sdp->sd_quota_mutex);
++ gfs2_assert(sdp, qd->qd_bh_count);
++ if (!--qd->qd_bh_count) {
++ brelse(qd->qd_bh);
++ qd->qd_bh = NULL;
++ qd->qd_bh_qc = NULL;
++ }
++ mutex_unlock(&sdp->sd_quota_mutex);
++}
++
++static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
++{
++ struct gfs2_quota_data *qd = NULL;
++ int error;
++ int found = 0;
++
++ *qdp = NULL;
++
++ if (sdp->sd_vfs->s_flags & MS_RDONLY)
++ return 0;
++
++ spin_lock(&sdp->sd_quota_spin);
++
++ list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
++ if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
++ !test_bit(QDF_CHANGE, &qd->qd_flags) ||
++ qd->qd_sync_gen >= sdp->sd_quota_sync_gen)
++ continue;
++
++ list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
++
++ set_bit(QDF_LOCKED, &qd->qd_flags);
++ gfs2_assert_warn(sdp, qd->qd_count);
++ qd->qd_count++;
++ qd->qd_change_sync = qd->qd_change;
++ gfs2_assert_warn(sdp, qd->qd_slot_count);
++ qd->qd_slot_count++;
++ found = 1;
++
++ break;
++ }
++
++ if (!found)
++ qd = NULL;
++
++ spin_unlock(&sdp->sd_quota_spin);
++
++ if (qd) {
++ gfs2_assert_warn(sdp, qd->qd_change_sync);
++ error = bh_get(qd);
++ if (error) {
++ clear_bit(QDF_LOCKED, &qd->qd_flags);
++ slot_put(qd);
++ qd_put(qd);
++ return error;
++ }
++ }
++
++ *qdp = qd;
++
++ return 0;
++}
++
++static int qd_trylock(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++
++ if (sdp->sd_vfs->s_flags & MS_RDONLY)
++ return 0;
++
++ spin_lock(&sdp->sd_quota_spin);
++
++ if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
++ !test_bit(QDF_CHANGE, &qd->qd_flags)) {
++ spin_unlock(&sdp->sd_quota_spin);
++ return 0;
++ }
++
++ list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
++
++ set_bit(QDF_LOCKED, &qd->qd_flags);
++ gfs2_assert_warn(sdp, qd->qd_count);
++ qd->qd_count++;
++ qd->qd_change_sync = qd->qd_change;
++ gfs2_assert_warn(sdp, qd->qd_slot_count);
++ qd->qd_slot_count++;
++
++ spin_unlock(&sdp->sd_quota_spin);
++
++ gfs2_assert_warn(sdp, qd->qd_change_sync);
++ if (bh_get(qd)) {
++ clear_bit(QDF_LOCKED, &qd->qd_flags);
++ slot_put(qd);
++ qd_put(qd);
++ return 0;
++ }
++
++ return 1;
++}
++
++static void qd_unlock(struct gfs2_quota_data *qd)
++{
++ gfs2_assert_warn(qd->qd_gl->gl_sbd,
++ test_bit(QDF_LOCKED, &qd->qd_flags));
++ clear_bit(QDF_LOCKED, &qd->qd_flags);
++ bh_put(qd);
++ slot_put(qd);
++ qd_put(qd);
++}
++
++static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
++ struct gfs2_quota_data **qdp)
++{
++ int error;
++
++ error = qd_get(sdp, user, id, create, qdp);
++ if (error)
++ return error;
++
++ error = slot_get(*qdp);
++ if (error)
++ goto fail;
++
++ error = bh_get(*qdp);
++ if (error)
++ goto fail_slot;
++
++ return 0;
++
++fail_slot:
++ slot_put(*qdp);
++fail:
++ qd_put(*qdp);
++ return error;
++}
++
++static void qdsb_put(struct gfs2_quota_data *qd)
++{
++ bh_put(qd);
++ slot_put(qd);
++ qd_put(qd);
++}
++
++int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_quota_data **qd = al->al_qd;
++ int error;
++
++ if (gfs2_assert_warn(sdp, !al->al_qd_num) ||
++ gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)))
++ return -EIO;
++
++ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
++ return 0;
++
++ error = qdsb_get(sdp, QUOTA_USER, ip->i_di.di_uid, CREATE, qd);
++ if (error)
++ goto out;
++ al->al_qd_num++;
++ qd++;
++
++ error = qdsb_get(sdp, QUOTA_GROUP, ip->i_di.di_gid, CREATE, qd);
++ if (error)
++ goto out;
++ al->al_qd_num++;
++ qd++;
++
++ if (uid != NO_QUOTA_CHANGE && uid != ip->i_di.di_uid) {
++ error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd);
++ if (error)
++ goto out;
++ al->al_qd_num++;
++ qd++;
++ }
++
++ if (gid != NO_QUOTA_CHANGE && gid != ip->i_di.di_gid) {
++ error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd);
++ if (error)
++ goto out;
++ al->al_qd_num++;
++ qd++;
++ }
++
++out:
++ if (error)
++ gfs2_quota_unhold(ip);
++ return error;
++}
++
++void gfs2_quota_unhold(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ unsigned int x;
++
++ gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
++
++ for (x = 0; x < al->al_qd_num; x++) {
++ qdsb_put(al->al_qd[x]);
++ al->al_qd[x] = NULL;
++ }
++ al->al_qd_num = 0;
++}
++
++static int sort_qd(const void *a, const void *b)
++{
++ const struct gfs2_quota_data *qd_a = *(const struct gfs2_quota_data **)a;
++ const struct gfs2_quota_data *qd_b = *(const struct gfs2_quota_data **)b;
++
++ if (!test_bit(QDF_USER, &qd_a->qd_flags) !=
++ !test_bit(QDF_USER, &qd_b->qd_flags)) {
++ if (test_bit(QDF_USER, &qd_a->qd_flags))
++ return -1;
++ else
++ return 1;
++ }
++ if (qd_a->qd_id < qd_b->qd_id)
++ return -1;
++ if (qd_a->qd_id > qd_b->qd_id)
++ return 1;
++
++ return 0;
++}
++
++static void do_qc(struct gfs2_quota_data *qd, s64 change)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
++ struct gfs2_quota_change *qc = qd->qd_bh_qc;
++ s64 x;
++
++ mutex_lock(&sdp->sd_quota_mutex);
++ gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1);
++
++ if (!test_bit(QDF_CHANGE, &qd->qd_flags)) {
++ qc->qc_change = 0;
++ qc->qc_flags = 0;
++ if (test_bit(QDF_USER, &qd->qd_flags))
++ qc->qc_flags = cpu_to_be32(GFS2_QCF_USER);
++ qc->qc_id = cpu_to_be32(qd->qd_id);
++ }
++
++ x = qc->qc_change;
++ x = be64_to_cpu(x) + change;
++ qc->qc_change = cpu_to_be64(x);
++
++ spin_lock(&sdp->sd_quota_spin);
++ qd->qd_change = x;
++ spin_unlock(&sdp->sd_quota_spin);
++
++ if (!x) {
++ gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags));
++ clear_bit(QDF_CHANGE, &qd->qd_flags);
++ qc->qc_flags = 0;
++ qc->qc_id = 0;
++ slot_put(qd);
++ qd_put(qd);
++ } else if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) {
++ qd_hold(qd);
++ slot_hold(qd);
++ }
++
++ mutex_unlock(&sdp->sd_quota_mutex);
++}
++
++/**
++ * gfs2_adjust_quota
++ *
++ * This function was mostly borrowed from gfs2_block_truncate_page which was
++ * in turn mostly borrowed from ext3
++ */
++static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
++ s64 change, struct gfs2_quota_data *qd)
++{
++ struct inode *inode = &ip->i_inode;
++ struct address_space *mapping = inode->i_mapping;
++ unsigned long index = loc >> PAGE_CACHE_SHIFT;
++ unsigned offset = loc & (PAGE_CACHE_SHIFT - 1);
++ unsigned blocksize, iblock, pos;
++ struct buffer_head *bh;
++ struct page *page;
++ void *kaddr;
++ __be64 *ptr;
++ s64 value;
++ int err = -EIO;
++
++ page = grab_cache_page(mapping, index);
++ if (!page)
++ return -ENOMEM;
++
++ blocksize = inode->i_sb->s_blocksize;
++ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
++
++ if (!page_has_buffers(page))
++ create_empty_buffers(page, blocksize, 0);
++
++ bh = page_buffers(page);
++ pos = blocksize;
++ while (offset >= pos) {
++ bh = bh->b_this_page;
++ iblock++;
++ pos += blocksize;
++ }
++
++ if (!buffer_mapped(bh)) {
++ gfs2_get_block(inode, iblock, bh, 1);
++ if (!buffer_mapped(bh))
++ goto unlock;
++ }
++
++ if (PageUptodate(page))
++ set_buffer_uptodate(bh);
++
++ if (!buffer_uptodate(bh)) {
++ ll_rw_block(READ_META, 1, &bh);
++ wait_on_buffer(bh);
++ if (!buffer_uptodate(bh))
++ goto unlock;
++ }
++
++ gfs2_trans_add_bh(ip->i_gl, bh, 0);
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ ptr = kaddr + offset;
++ value = (s64)be64_to_cpu(*ptr) + change;
++ *ptr = cpu_to_be64(value);
++ flush_dcache_page(page);
++ kunmap_atomic(kaddr, KM_USER0);
++ err = 0;
++ qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC);
++ qd->qd_qb.qb_value = cpu_to_be64(value);
++unlock:
++ unlock_page(page);
++ page_cache_release(page);
++ return err;
++}
++
++static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
++{
++ struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd;
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
++ unsigned int data_blocks, ind_blocks;
++ struct gfs2_holder *ghs, i_gh;
++ unsigned int qx, x;
++ struct gfs2_quota_data *qd;
++ loff_t offset;
++ unsigned int nalloc = 0;
++ struct gfs2_alloc *al = NULL;
++ int error;
++
++ gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota),
++ &data_blocks, &ind_blocks);
++
++ ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_KERNEL);
++ if (!ghs)
++ return -ENOMEM;
++
++ sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
++ for (qx = 0; qx < num_qd; qx++) {
++ error = gfs2_glock_nq_init(qda[qx]->qd_gl,
++ LM_ST_EXCLUSIVE,
++ GL_NOCACHE, &ghs[qx]);
++ if (error)
++ goto out;
++ }
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
++ if (error)
++ goto out;
++
++ for (x = 0; x < num_qd; x++) {
++ int alloc_required;
++
++ offset = qd2offset(qda[x]);
++ error = gfs2_write_alloc_required(ip, offset,
++ sizeof(struct gfs2_quota),
++ &alloc_required);
++ if (error)
++ goto out_gunlock;
++ if (alloc_required)
++ nalloc++;
++ }
++
++ if (nalloc) {
++ al = gfs2_alloc_get(ip);
++
++ al->al_requested = nalloc * (data_blocks + ind_blocks);
++
++ error = gfs2_inplace_reserve(ip);
++ if (error)
++ goto out_alloc;
++
++ error = gfs2_trans_begin(sdp,
++ al->al_rgd->rd_ri.ri_length +
++ num_qd * data_blocks +
++ nalloc * ind_blocks +
++ RES_DINODE + num_qd +
++ RES_STATFS, 0);
++ if (error)
++ goto out_ipres;
++ } else {
++ error = gfs2_trans_begin(sdp,
++ num_qd * data_blocks +
++ RES_DINODE + num_qd, 0);
++ if (error)
++ goto out_gunlock;
++ }
++
++ for (x = 0; x < num_qd; x++) {
++ qd = qda[x];
++ offset = qd2offset(qd);
++ error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync,
++ (struct gfs2_quota_data *)
++ qd->qd_gl->gl_lvb);
++ if (error)
++ goto out_end_trans;
++
++ do_qc(qd, -qd->qd_change_sync);
++ }
++
++ error = 0;
++
++out_end_trans:
++ gfs2_trans_end(sdp);
++out_ipres:
++ if (nalloc)
++ gfs2_inplace_release(ip);
++out_alloc:
++ if (nalloc)
++ gfs2_alloc_put(ip);
++out_gunlock:
++ gfs2_glock_dq_uninit(&i_gh);
++out:
++ while (qx--)
++ gfs2_glock_dq_uninit(&ghs[qx]);
++ kfree(ghs);
++ gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
++ return error;
++}
++
++static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
++ struct gfs2_holder *q_gh)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
++ struct gfs2_holder i_gh;
++ struct gfs2_quota q;
++ char buf[sizeof(struct gfs2_quota)];
++ struct file_ra_state ra_state;
++ int error;
++ struct gfs2_quota_lvb *qlvb;
++
++ file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping);
++restart:
++ error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
++ if (error)
++ return error;
++
++ qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
++
++ if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) {
++ loff_t pos;
++ gfs2_glock_dq_uninit(q_gh);
++ error = gfs2_glock_nq_init(qd->qd_gl,
++ LM_ST_EXCLUSIVE, GL_NOCACHE,
++ q_gh);
++ if (error)
++ return error;
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
++ if (error)
++ goto fail;
++
++ memset(buf, 0, sizeof(struct gfs2_quota));
++ pos = qd2offset(qd);
++ error = gfs2_internal_read(ip, &ra_state, buf,
++ &pos, sizeof(struct gfs2_quota));
++ if (error < 0)
++ goto fail_gunlock;
++
++ gfs2_glock_dq_uninit(&i_gh);
++
++
++ gfs2_quota_in(&q, buf);
++ qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
++ qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
++ qlvb->__pad = 0;
++ qlvb->qb_limit = cpu_to_be64(q.qu_limit);
++ qlvb->qb_warn = cpu_to_be64(q.qu_warn);
++ qlvb->qb_value = cpu_to_be64(q.qu_value);
++ qd->qd_qb = *qlvb;
++
++ if (gfs2_glock_is_blocking(qd->qd_gl)) {
++ gfs2_glock_dq_uninit(q_gh);
++ force_refresh = 0;
++ goto restart;
++ }
++ }
++
++ return 0;
++
++fail_gunlock:
++ gfs2_glock_dq_uninit(&i_gh);
++fail:
++ gfs2_glock_dq_uninit(q_gh);
++ return error;
++}
++
++int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ unsigned int x;
++ int error = 0;
++
++ gfs2_quota_hold(ip, uid, gid);
++
++ if (capable(CAP_SYS_RESOURCE) ||
++ sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
++ return 0;
++
++ sort(al->al_qd, al->al_qd_num, sizeof(struct gfs2_quota_data *),
++ sort_qd, NULL);
++
++ for (x = 0; x < al->al_qd_num; x++) {
++ error = do_glock(al->al_qd[x], NO_FORCE, &al->al_qd_ghs[x]);
++ if (error)
++ break;
++ }
++
++ if (!error)
++ set_bit(GIF_QD_LOCKED, &ip->i_flags);
++ else {
++ while (x--)
++ gfs2_glock_dq_uninit(&al->al_qd_ghs[x]);
++ gfs2_quota_unhold(ip);
++ }
++
++ return error;
++}
++
++static int need_sync(struct gfs2_quota_data *qd)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++ struct gfs2_tune *gt = &sdp->sd_tune;
++ s64 value;
++ unsigned int num, den;
++ int do_sync = 1;
++
++ if (!qd->qd_qb.qb_limit)
++ return 0;
++
++ spin_lock(&sdp->sd_quota_spin);
++ value = qd->qd_change;
++ spin_unlock(&sdp->sd_quota_spin);
++
++ spin_lock(>->gt_spin);
++ num = gt->gt_quota_scale_num;
++ den = gt->gt_quota_scale_den;
++ spin_unlock(>->gt_spin);
++
++ if (value < 0)
++ do_sync = 0;
++ else if ((s64)be64_to_cpu(qd->qd_qb.qb_value) >=
++ (s64)be64_to_cpu(qd->qd_qb.qb_limit))
++ do_sync = 0;
++ else {
++ value *= gfs2_jindex_size(sdp) * num;
++ do_div(value, den);
++ value += (s64)be64_to_cpu(qd->qd_qb.qb_value);
++ if (value < (s64)be64_to_cpu(qd->qd_qb.qb_limit))
++ do_sync = 0;
++ }
++
++ return do_sync;
++}
++
++void gfs2_quota_unlock(struct gfs2_inode *ip)
++{
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_quota_data *qda[4];
++ unsigned int count = 0;
++ unsigned int x;
++
++ if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags))
++ goto out;
++
++ for (x = 0; x < al->al_qd_num; x++) {
++ struct gfs2_quota_data *qd;
++ int sync;
++
++ qd = al->al_qd[x];
++ sync = need_sync(qd);
++
++ gfs2_glock_dq_uninit(&al->al_qd_ghs[x]);
++
++ if (sync && qd_trylock(qd))
++ qda[count++] = qd;
++ }
++
++ if (count) {
++ do_sync(count, qda);
++ for (x = 0; x < count; x++)
++ qd_unlock(qda[x]);
++ }
++
++out:
++ gfs2_quota_unhold(ip);
++}
++
++#define MAX_LINE 256
++
++static int print_message(struct gfs2_quota_data *qd, char *type)
++{
++ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
++
++ printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\r\n",
++ sdp->sd_fsname, type,
++ (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group",
++ qd->qd_id);
++
++ return 0;
++}
++
++int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_quota_data *qd;
++ s64 value;
++ unsigned int x;
++ int error = 0;
++
++ if (!test_bit(GIF_QD_LOCKED, &ip->i_flags))
++ return 0;
++
++ if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
++ return 0;
++
++ for (x = 0; x < al->al_qd_num; x++) {
++ qd = al->al_qd[x];
++
++ if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
++ (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))))
++ continue;
++
++ value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
++ spin_lock(&sdp->sd_quota_spin);
++ value += qd->qd_change;
++ spin_unlock(&sdp->sd_quota_spin);
++
++ if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
++ print_message(qd, "exceeded");
++ error = -EDQUOT;
++ break;
++ } else if (be64_to_cpu(qd->qd_qb.qb_warn) &&
++ (s64)be64_to_cpu(qd->qd_qb.qb_warn) < value &&
++ time_after_eq(jiffies, qd->qd_last_warn +
++ gfs2_tune_get(sdp,
++ gt_quota_warn_period) * HZ)) {
++ error = print_message(qd, "warning");
++ qd->qd_last_warn = jiffies;
++ }
++ }
++
++ return error;
++}
++
++void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
++ u32 uid, u32 gid)
++{
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_quota_data *qd;
++ unsigned int x;
++ unsigned int found = 0;
++
++ if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change))
++ return;
++ if (ip->i_di.di_flags & GFS2_DIF_SYSTEM)
++ return;
++
++ for (x = 0; x < al->al_qd_num; x++) {
++ qd = al->al_qd[x];
++
++ if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
++ (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
++ do_qc(qd, change);
++ found++;
++ }
++ }
++}
++
++int gfs2_quota_sync(struct gfs2_sbd *sdp)
++{
++ struct gfs2_quota_data **qda;
++ unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync);
++ unsigned int num_qd;
++ unsigned int x;
++ int error = 0;
++
++ sdp->sd_quota_sync_gen++;
++
++ qda = kcalloc(max_qd, sizeof(struct gfs2_quota_data *), GFP_KERNEL);
++ if (!qda)
++ return -ENOMEM;
++
++ do {
++ num_qd = 0;
++
++ for (;;) {
++ error = qd_fish(sdp, qda + num_qd);
++ if (error || !qda[num_qd])
++ break;
++ if (++num_qd == max_qd)
++ break;
++ }
++
++ if (num_qd) {
++ if (!error)
++ error = do_sync(num_qd, qda);
++ if (!error)
++ for (x = 0; x < num_qd; x++)
++ qda[x]->qd_sync_gen =
++ sdp->sd_quota_sync_gen;
++
++ for (x = 0; x < num_qd; x++)
++ qd_unlock(qda[x]);
++ }
++ } while (!error && num_qd == max_qd);
++
++ kfree(qda);
++
++ return error;
++}
++
++int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
++{
++ struct gfs2_quota_data *qd;
++ struct gfs2_holder q_gh;
++ int error;
++
++ error = qd_get(sdp, user, id, CREATE, &qd);
++ if (error)
++ return error;
++
++ error = do_glock(qd, FORCE, &q_gh);
++ if (!error)
++ gfs2_glock_dq_uninit(&q_gh);
++
++ qd_put(qd);
++
++ return error;
++}
++
++int gfs2_quota_init(struct gfs2_sbd *sdp)
++{
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
++ unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
++ unsigned int x, slot = 0;
++ unsigned int found = 0;
++ u64 dblock;
++ u32 extlen = 0;
++ int error;
++
++ if (!ip->i_di.di_size || ip->i_di.di_size > (64 << 20) ||
++ ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++ sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block;
++ sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE);
++
++ error = -ENOMEM;
++
++ sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks,
++ sizeof(unsigned char *), GFP_KERNEL);
++ if (!sdp->sd_quota_bitmap)
++ return error;
++
++ for (x = 0; x < sdp->sd_quota_chunks; x++) {
++ sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!sdp->sd_quota_bitmap[x])
++ goto fail;
++ }
++
++ for (x = 0; x < blocks; x++) {
++ struct buffer_head *bh;
++ unsigned int y;
++
++ if (!extlen) {
++ int new = 0;
++ error = gfs2_extent_map(&ip->i_inode, x, &new, &dblock, &extlen);
++ if (error)
++ goto fail;
++ }
++ error = -EIO;
++ bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
++ if (!bh)
++ goto fail;
++ if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) {
++ brelse(bh);
++ goto fail;
++ }
++
++ for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
++ y++, slot++) {
++ struct gfs2_quota_change qc;
++ struct gfs2_quota_data *qd;
++
++ gfs2_quota_change_in(&qc, bh->b_data +
++ sizeof(struct gfs2_meta_header) +
++ y * sizeof(struct gfs2_quota_change));
++ if (!qc.qc_change)
++ continue;
++
++ error = qd_alloc(sdp, (qc.qc_flags & GFS2_QCF_USER),
++ qc.qc_id, &qd);
++ if (error) {
++ brelse(bh);
++ goto fail;
++ }
++
++ set_bit(QDF_CHANGE, &qd->qd_flags);
++ qd->qd_change = qc.qc_change;
++ qd->qd_slot = slot;
++ qd->qd_slot_count = 1;
++ qd->qd_last_touched = jiffies;
++
++ spin_lock(&sdp->sd_quota_spin);
++ gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1);
++ list_add(&qd->qd_list, &sdp->sd_quota_list);
++ atomic_inc(&sdp->sd_quota_count);
++ spin_unlock(&sdp->sd_quota_spin);
++
++ found++;
++ }
++
++ brelse(bh);
++ dblock++;
++ extlen--;
++ }
++
++ if (found)
++ fs_info(sdp, "found %u quota changes\n", found);
++
++ return 0;
++
++fail:
++ gfs2_quota_cleanup(sdp);
++ return error;
++}
++
++void gfs2_quota_scan(struct gfs2_sbd *sdp)
++{
++ struct gfs2_quota_data *qd, *safe;
++ LIST_HEAD(dead);
++
++ spin_lock(&sdp->sd_quota_spin);
++ list_for_each_entry_safe(qd, safe, &sdp->sd_quota_list, qd_list) {
++ if (!qd->qd_count &&
++ time_after_eq(jiffies, qd->qd_last_touched +
++ gfs2_tune_get(sdp, gt_quota_cache_secs) * HZ)) {
++ list_move(&qd->qd_list, &dead);
++ gfs2_assert_warn(sdp,
++ atomic_read(&sdp->sd_quota_count) > 0);
++ atomic_dec(&sdp->sd_quota_count);
++ }
++ }
++ spin_unlock(&sdp->sd_quota_spin);
++
++ while (!list_empty(&dead)) {
++ qd = list_entry(dead.next, struct gfs2_quota_data, qd_list);
++ list_del(&qd->qd_list);
++
++ gfs2_assert_warn(sdp, !qd->qd_change);
++ gfs2_assert_warn(sdp, !qd->qd_slot_count);
++ gfs2_assert_warn(sdp, !qd->qd_bh_count);
++
++ gfs2_lvb_unhold(qd->qd_gl);
++ kfree(qd);
++ }
++}
++
++void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
++{
++ struct list_head *head = &sdp->sd_quota_list;
++ struct gfs2_quota_data *qd;
++ unsigned int x;
++
++ spin_lock(&sdp->sd_quota_spin);
++ while (!list_empty(head)) {
++ qd = list_entry(head->prev, struct gfs2_quota_data, qd_list);
++
++ if (qd->qd_count > 1 ||
++ (qd->qd_count && !test_bit(QDF_CHANGE, &qd->qd_flags))) {
++ list_move(&qd->qd_list, head);
++ spin_unlock(&sdp->sd_quota_spin);
++ schedule();
++ spin_lock(&sdp->sd_quota_spin);
++ continue;
++ }
++
++ list_del(&qd->qd_list);
++ atomic_dec(&sdp->sd_quota_count);
++ spin_unlock(&sdp->sd_quota_spin);
++
++ if (!qd->qd_count) {
++ gfs2_assert_warn(sdp, !qd->qd_change);
++ gfs2_assert_warn(sdp, !qd->qd_slot_count);
++ } else
++ gfs2_assert_warn(sdp, qd->qd_slot_count == 1);
++ gfs2_assert_warn(sdp, !qd->qd_bh_count);
++
++ gfs2_lvb_unhold(qd->qd_gl);
++ kfree(qd);
++
++ spin_lock(&sdp->sd_quota_spin);
++ }
++ spin_unlock(&sdp->sd_quota_spin);
++
++ gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count));
++
++ if (sdp->sd_quota_bitmap) {
++ for (x = 0; x < sdp->sd_quota_chunks; x++)
++ kfree(sdp->sd_quota_bitmap[x]);
++ kfree(sdp->sd_quota_bitmap);
++ }
++}
++
+diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
+new file mode 100644
+index 0000000..a8be141
+--- /dev/null
++++ b/fs/gfs2/quota.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __QUOTA_DOT_H__
++#define __QUOTA_DOT_H__
++
++struct gfs2_inode;
++struct gfs2_sbd;
++
++#define NO_QUOTA_CHANGE ((u32)-1)
++
++int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid);
++void gfs2_quota_unhold(struct gfs2_inode *ip);
++
++int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid);
++void gfs2_quota_unlock(struct gfs2_inode *ip);
++
++int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
++void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
++ u32 uid, u32 gid);
++
++int gfs2_quota_sync(struct gfs2_sbd *sdp);
++int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);
++
++int gfs2_quota_init(struct gfs2_sbd *sdp);
++void gfs2_quota_scan(struct gfs2_sbd *sdp);
++void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
++
++#endif /* __QUOTA_DOT_H__ */
+diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
+new file mode 100644
+index 0000000..62cd223
+--- /dev/null
++++ b/fs/gfs2/recovery.c
+@@ -0,0 +1,571 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/crc32.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "glock.h"
++#include "glops.h"
++#include "lm.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "recovery.h"
++#include "super.h"
++#include "util.h"
++#include "dir.h"
++
++int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
++ struct buffer_head **bh)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_glock *gl = ip->i_gl;
++ int new = 0;
++ u64 dblock;
++ u32 extlen;
++ int error;
++
++ error = gfs2_extent_map(&ip->i_inode, blk, &new, &dblock, &extlen);
++ if (error)
++ return error;
++ if (!dblock) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++
++ *bh = gfs2_meta_ra(gl, dblock, extlen);
++
++ return error;
++}
++
++int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
++{
++ struct list_head *head = &sdp->sd_revoke_list;
++ struct gfs2_revoke_replay *rr;
++ int found = 0;
++
++ list_for_each_entry(rr, head, rr_list) {
++ if (rr->rr_blkno == blkno) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (found) {
++ rr->rr_where = where;
++ return 0;
++ }
++
++ rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_KERNEL);
++ if (!rr)
++ return -ENOMEM;
++
++ rr->rr_blkno = blkno;
++ rr->rr_where = where;
++ list_add(&rr->rr_list, head);
++
++ return 1;
++}
++
++int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
++{
++ struct gfs2_revoke_replay *rr;
++ int wrap, a, b, revoke;
++ int found = 0;
++
++ list_for_each_entry(rr, &sdp->sd_revoke_list, rr_list) {
++ if (rr->rr_blkno == blkno) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found)
++ return 0;
++
++ wrap = (rr->rr_where < sdp->sd_replay_tail);
++ a = (sdp->sd_replay_tail < where);
++ b = (where < rr->rr_where);
++ revoke = (wrap) ? (a || b) : (a && b);
++
++ return revoke;
++}
++
++void gfs2_revoke_clean(struct gfs2_sbd *sdp)
++{
++ struct list_head *head = &sdp->sd_revoke_list;
++ struct gfs2_revoke_replay *rr;
++
++ while (!list_empty(head)) {
++ rr = list_entry(head->next, struct gfs2_revoke_replay, rr_list);
++ list_del(&rr->rr_list);
++ kfree(rr);
++ }
++}
++
++/**
++ * get_log_header - read the log header for a given segment
++ * @jd: the journal
++ * @blk: the block to look at
++ * @lh: the log header to return
++ *
++ * Read the log header for a given segement in a given journal. Do a few
++ * sanity checks on it.
++ *
++ * Returns: 0 on success,
++ * 1 if the header was invalid or incomplete,
++ * errno on error
++ */
++
++static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
++ struct gfs2_log_header *head)
++{
++ struct buffer_head *bh;
++ struct gfs2_log_header lh;
++ u32 hash;
++ int error;
++
++ error = gfs2_replay_read_block(jd, blk, &bh);
++ if (error)
++ return error;
++
++ memcpy(&lh, bh->b_data, sizeof(struct gfs2_log_header));
++ lh.lh_hash = 0;
++ hash = gfs2_disk_hash((char *)&lh, sizeof(struct gfs2_log_header));
++ gfs2_log_header_in(&lh, bh->b_data);
++
++ brelse(bh);
++
++ if (lh.lh_header.mh_magic != GFS2_MAGIC ||
++ lh.lh_header.mh_type != GFS2_METATYPE_LH ||
++ lh.lh_blkno != blk || lh.lh_hash != hash)
++ return 1;
++
++ *head = lh;
++
++ return 0;
++}
++
++/**
++ * find_good_lh - find a good log header
++ * @jd: the journal
++ * @blk: the segment to start searching from
++ * @lh: the log header to fill in
++ * @forward: if true search forward in the log, else search backward
++ *
++ * Call get_log_header() to get a log header for a segment, but if the
++ * segment is bad, either scan forward or backward until we find a good one.
++ *
++ * Returns: errno
++ */
++
++static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk,
++ struct gfs2_log_header *head)
++{
++ unsigned int orig_blk = *blk;
++ int error;
++
++ for (;;) {
++ error = get_log_header(jd, *blk, head);
++ if (error <= 0)
++ return error;
++
++ if (++*blk == jd->jd_blocks)
++ *blk = 0;
++
++ if (*blk == orig_blk) {
++ gfs2_consist_inode(GFS2_I(jd->jd_inode));
++ return -EIO;
++ }
++ }
++}
++
++/**
++ * jhead_scan - make sure we've found the head of the log
++ * @jd: the journal
++ * @head: this is filled in with the log descriptor of the head
++ *
++ * At this point, seg and lh should be either the head of the log or just
++ * before. Scan forward until we find the head.
++ *
++ * Returns: errno
++ */
++
++static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
++{
++ unsigned int blk = head->lh_blkno;
++ struct gfs2_log_header lh;
++ int error;
++
++ for (;;) {
++ if (++blk == jd->jd_blocks)
++ blk = 0;
++
++ error = get_log_header(jd, blk, &lh);
++ if (error < 0)
++ return error;
++ if (error == 1)
++ continue;
++
++ if (lh.lh_sequence == head->lh_sequence) {
++ gfs2_consist_inode(GFS2_I(jd->jd_inode));
++ return -EIO;
++ }
++ if (lh.lh_sequence < head->lh_sequence)
++ break;
++
++ *head = lh;
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_find_jhead - find the head of a log
++ * @jd: the journal
++ * @head: the log descriptor for the head of the log is returned here
++ *
++ * Do a binary search of a journal and find the valid log entry with the
++ * highest sequence number. (i.e. the log head)
++ *
++ * Returns: errno
++ */
++
++int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
++{
++ struct gfs2_log_header lh_1, lh_m;
++ u32 blk_1, blk_2, blk_m;
++ int error;
++
++ blk_1 = 0;
++ blk_2 = jd->jd_blocks - 1;
++
++ for (;;) {
++ blk_m = (blk_1 + blk_2) / 2;
++
++ error = find_good_lh(jd, &blk_1, &lh_1);
++ if (error)
++ return error;
++
++ error = find_good_lh(jd, &blk_m, &lh_m);
++ if (error)
++ return error;
++
++ if (blk_1 == blk_m || blk_m == blk_2)
++ break;
++
++ if (lh_1.lh_sequence <= lh_m.lh_sequence)
++ blk_1 = blk_m;
++ else
++ blk_2 = blk_m;
++ }
++
++ error = jhead_scan(jd, &lh_1);
++ if (error)
++ return error;
++
++ *head = lh_1;
++
++ return error;
++}
++
++/**
++ * foreach_descriptor - go through the active part of the log
++ * @jd: the journal
++ * @start: the first log header in the active region
++ * @end: the last log header (don't process the contents of this entry))
++ *
++ * Call a given function once for every log descriptor in the active
++ * portion of the log.
++ *
++ * Returns: errno
++ */
++
++static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start,
++ unsigned int end, int pass)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ struct buffer_head *bh;
++ struct gfs2_log_descriptor *ld;
++ int error = 0;
++ u32 length;
++ __be64 *ptr;
++ unsigned int offset = sizeof(struct gfs2_log_descriptor);
++ offset += sizeof(__be64) - 1;
++ offset &= ~(sizeof(__be64) - 1);
++
++ while (start != end) {
++ error = gfs2_replay_read_block(jd, start, &bh);
++ if (error)
++ return error;
++ if (gfs2_meta_check(sdp, bh)) {
++ brelse(bh);
++ return -EIO;
++ }
++ ld = (struct gfs2_log_descriptor *)bh->b_data;
++ length = be32_to_cpu(ld->ld_length);
++
++ if (be32_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) {
++ struct gfs2_log_header lh;
++ error = get_log_header(jd, start, &lh);
++ if (!error) {
++ gfs2_replay_incr_blk(sdp, &start);
++ brelse(bh);
++ continue;
++ }
++ if (error == 1) {
++ gfs2_consist_inode(GFS2_I(jd->jd_inode));
++ error = -EIO;
++ }
++ brelse(bh);
++ return error;
++ } else if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LD)) {
++ brelse(bh);
++ return -EIO;
++ }
++ ptr = (__be64 *)(bh->b_data + offset);
++ error = lops_scan_elements(jd, start, ld, ptr, pass);
++ if (error) {
++ brelse(bh);
++ return error;
++ }
++
++ while (length--)
++ gfs2_replay_incr_blk(sdp, &start);
++
++ brelse(bh);
++ }
++
++ return 0;
++}
++
++/**
++ * clean_journal - mark a dirty journal as being clean
++ * @sdp: the filesystem
++ * @jd: the journal
++ * @gl: the journal's glock
++ * @head: the head journal to start from
++ *
++ * Returns: errno
++ */
++
++static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ unsigned int lblock;
++ struct gfs2_log_header *lh;
++ u32 hash;
++ struct buffer_head *bh;
++ int error;
++ struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
++
++ lblock = head->lh_blkno;
++ gfs2_replay_incr_blk(sdp, &lblock);
++ bh_map.b_size = 1 << ip->i_inode.i_blkbits;
++ error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map);
++ if (error)
++ return error;
++ if (!bh_map.b_blocknr) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++
++ bh = sb_getblk(sdp->sd_vfs, bh_map.b_blocknr);
++ lock_buffer(bh);
++ memset(bh->b_data, 0, bh->b_size);
++ set_buffer_uptodate(bh);
++ clear_buffer_dirty(bh);
++ unlock_buffer(bh);
++
++ lh = (struct gfs2_log_header *)bh->b_data;
++ memset(lh, 0, sizeof(struct gfs2_log_header));
++ lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
++ lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
++ lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
++ lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1);
++ lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT);
++ lh->lh_blkno = cpu_to_be32(lblock);
++ hash = gfs2_disk_hash((const char *)lh, sizeof(struct gfs2_log_header));
++ lh->lh_hash = cpu_to_be32(hash);
++
++ set_buffer_dirty(bh);
++ if (sync_dirty_buffer(bh))
++ gfs2_io_error_bh(sdp, bh);
++ brelse(bh);
++
++ return error;
++}
++
++/**
++ * gfs2_recover_journal - recovery a given journal
++ * @jd: the struct gfs2_jdesc describing the journal
++ *
++ * Acquire the journal's lock, check to see if the journal is clean, and
++ * do recovery if necessary.
++ *
++ * Returns: errno
++ */
++
++int gfs2_recover_journal(struct gfs2_jdesc *jd)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ struct gfs2_log_header head;
++ struct gfs2_holder j_gh, ji_gh, t_gh;
++ unsigned long t;
++ int ro = 0;
++ unsigned int pass;
++ int error;
++
++ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
++ fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
++ jd->jd_jid);
++
++ /* Aquire the journal lock so we can do recovery */
++
++ error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
++ LM_ST_EXCLUSIVE,
++ LM_FLAG_NOEXP | LM_FLAG_TRY | GL_NOCACHE,
++ &j_gh);
++ switch (error) {
++ case 0:
++ break;
++
++ case GLR_TRYFAILED:
++ fs_info(sdp, "jid=%u: Busy\n", jd->jd_jid);
++ error = 0;
++
++ default:
++ goto fail;
++ };
++
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
++ LM_FLAG_NOEXP, &ji_gh);
++ if (error)
++ goto fail_gunlock_j;
++ } else {
++ fs_info(sdp, "jid=%u, already locked for use\n", jd->jd_jid);
++ }
++
++ fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid);
++
++ error = gfs2_jdesc_check(jd);
++ if (error)
++ goto fail_gunlock_ji;
++
++ error = gfs2_find_jhead(jd, &head);
++ if (error)
++ goto fail_gunlock_ji;
++
++ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
++ fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n",
++ jd->jd_jid);
++
++ t = jiffies;
++
++ /* Acquire a shared hold on the transaction lock */
++
++ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
++ LM_FLAG_NOEXP | LM_FLAG_PRIORITY |
++ GL_NOCANCEL | GL_NOCACHE, &t_gh);
++ if (error)
++ goto fail_gunlock_ji;
++
++ if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
++ if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
++ ro = 1;
++ } else {
++ if (sdp->sd_vfs->s_flags & MS_RDONLY)
++ ro = 1;
++ }
++
++ if (ro) {
++ fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n",
++ jd->jd_jid);
++ error = -EROFS;
++ goto fail_gunlock_tr;
++ }
++
++ fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid);
++
++ for (pass = 0; pass < 2; pass++) {
++ lops_before_scan(jd, &head, pass);
++ error = foreach_descriptor(jd, head.lh_tail,
++ head.lh_blkno, pass);
++ lops_after_scan(jd, error, pass);
++ if (error)
++ goto fail_gunlock_tr;
++ }
++
++ error = clean_journal(jd, &head);
++ if (error)
++ goto fail_gunlock_tr;
++
++ gfs2_glock_dq_uninit(&t_gh);
++ t = DIV_ROUND_UP(jiffies - t, HZ);
++ fs_info(sdp, "jid=%u: Journal replayed in %lus\n",
++ jd->jd_jid, t);
++ }
++
++ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
++ gfs2_glock_dq_uninit(&ji_gh);
++
++ gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
++
++ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
++ gfs2_glock_dq_uninit(&j_gh);
++
++ fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
++ return 0;
++
++fail_gunlock_tr:
++ gfs2_glock_dq_uninit(&t_gh);
++fail_gunlock_ji:
++ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
++ gfs2_glock_dq_uninit(&ji_gh);
++fail_gunlock_j:
++ gfs2_glock_dq_uninit(&j_gh);
++ }
++
++ fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
++
++fail:
++ gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
++ return error;
++}
++
++/**
++ * gfs2_check_journals - Recover any dirty journals
++ * @sdp: the filesystem
++ *
++ */
++
++void gfs2_check_journals(struct gfs2_sbd *sdp)
++{
++ struct gfs2_jdesc *jd;
++
++ for (;;) {
++ jd = gfs2_jdesc_find_dirty(sdp);
++ if (!jd)
++ break;
++
++ if (jd != sdp->sd_jdesc)
++ gfs2_recover_journal(jd);
++ }
++}
++
+diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h
+new file mode 100644
+index 0000000..961feed
+--- /dev/null
++++ b/fs/gfs2/recovery.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __RECOVERY_DOT_H__
++#define __RECOVERY_DOT_H__
++
++#include "incore.h"
++
++static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
++{
++ if (++*blk == sdp->sd_jdesc->jd_blocks)
++ *blk = 0;
++}
++
++int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
++ struct buffer_head **bh);
++
++int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where);
++int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where);
++void gfs2_revoke_clean(struct gfs2_sbd *sdp);
++
++int gfs2_find_jhead(struct gfs2_jdesc *jd,
++ struct gfs2_log_header *head);
++int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
++void gfs2_check_journals(struct gfs2_sbd *sdp);
++
++#endif /* __RECOVERY_DOT_H__ */
++
+diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
+new file mode 100644
+index 0000000..b261385
+--- /dev/null
++++ b/fs/gfs2/rgrp.c
+@@ -0,0 +1,1513 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/fs.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "glops.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "rgrp.h"
++#include "super.h"
++#include "trans.h"
++#include "ops_file.h"
++#include "util.h"
++
++#define BFITNOENT ((u32)~0)
++
++/*
++ * These routines are used by the resource group routines (rgrp.c)
++ * to keep track of block allocation. Each block is represented by two
++ * bits. So, each byte represents GFS2_NBBY (i.e. 4) blocks.
++ *
++ * 0 = Free
++ * 1 = Used (not metadata)
++ * 2 = Unlinked (still in use) inode
++ * 3 = Used (metadata)
++ */
++
++static const char valid_change[16] = {
++ /* current */
++ /* n */ 0, 1, 1, 1,
++ /* e */ 1, 0, 0, 0,
++ /* w */ 0, 0, 0, 1,
++ 1, 0, 0, 0
++};
++
++/**
++ * gfs2_setbit - Set a bit in the bitmaps
++ * @buffer: the buffer that holds the bitmaps
++ * @buflen: the length (in bytes) of the buffer
++ * @block: the block to set
++ * @new_state: the new state of the block
++ *
++ */
++
++static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
++ unsigned int buflen, u32 block,
++ unsigned char new_state)
++{
++ unsigned char *byte, *end, cur_state;
++ unsigned int bit;
++
++ byte = buffer + (block / GFS2_NBBY);
++ bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
++ end = buffer + buflen;
++
++ gfs2_assert(rgd->rd_sbd, byte < end);
++
++ cur_state = (*byte >> bit) & GFS2_BIT_MASK;
++
++ if (valid_change[new_state * 4 + cur_state]) {
++ *byte ^= cur_state << bit;
++ *byte |= new_state << bit;
++ } else
++ gfs2_consist_rgrpd(rgd);
++}
++
++/**
++ * gfs2_testbit - test a bit in the bitmaps
++ * @buffer: the buffer that holds the bitmaps
++ * @buflen: the length (in bytes) of the buffer
++ * @block: the block to read
++ *
++ */
++
++static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
++ unsigned int buflen, u32 block)
++{
++ unsigned char *byte, *end, cur_state;
++ unsigned int bit;
++
++ byte = buffer + (block / GFS2_NBBY);
++ bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
++ end = buffer + buflen;
++
++ gfs2_assert(rgd->rd_sbd, byte < end);
++
++ cur_state = (*byte >> bit) & GFS2_BIT_MASK;
++
++ return cur_state;
++}
++
++/**
++ * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
++ * a block in a given allocation state.
++ * @buffer: the buffer that holds the bitmaps
++ * @buflen: the length (in bytes) of the buffer
++ * @goal: start search at this block's bit-pair (within @buffer)
++ * @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
++ * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
++ *
++ * Scope of @goal and returned block number is only within this bitmap buffer,
++ * not entire rgrp or filesystem. @buffer will be offset from the actual
++ * beginning of a bitmap block buffer, skipping any header structures.
++ *
++ * Return: the block number (bitmap buffer scope) that was found
++ */
++
++static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
++ unsigned int buflen, u32 goal,
++ unsigned char old_state)
++{
++ unsigned char *byte, *end, alloc;
++ u32 blk = goal;
++ unsigned int bit;
++
++ byte = buffer + (goal / GFS2_NBBY);
++ bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
++ end = buffer + buflen;
++ alloc = (old_state & 1) ? 0 : 0x55;
++
++ while (byte < end) {
++ if ((*byte & 0x55) == alloc) {
++ blk += (8 - bit) >> 1;
++
++ bit = 0;
++ byte++;
++
++ continue;
++ }
++
++ if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
++ return blk;
++
++ bit += GFS2_BIT_SIZE;
++ if (bit >= 8) {
++ bit = 0;
++ byte++;
++ }
++
++ blk++;
++ }
++
++ return BFITNOENT;
++}
++
++/**
++ * gfs2_bitcount - count the number of bits in a certain state
++ * @buffer: the buffer that holds the bitmaps
++ * @buflen: the length (in bytes) of the buffer
++ * @state: the state of the block we're looking for
++ *
++ * Returns: The number of bits
++ */
++
++static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer,
++ unsigned int buflen, unsigned char state)
++{
++ unsigned char *byte = buffer;
++ unsigned char *end = buffer + buflen;
++ unsigned char state1 = state << 2;
++ unsigned char state2 = state << 4;
++ unsigned char state3 = state << 6;
++ u32 count = 0;
++
++ for (; byte < end; byte++) {
++ if (((*byte) & 0x03) == state)
++ count++;
++ if (((*byte) & 0x0C) == state1)
++ count++;
++ if (((*byte) & 0x30) == state2)
++ count++;
++ if (((*byte) & 0xC0) == state3)
++ count++;
++ }
++
++ return count;
++}
++
++/**
++ * gfs2_rgrp_verify - Verify that a resource group is consistent
++ * @sdp: the filesystem
++ * @rgd: the rgrp
++ *
++ */
++
++void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ struct gfs2_bitmap *bi = NULL;
++ u32 length = rgd->rd_ri.ri_length;
++ u32 count[4], tmp;
++ int buf, x;
++
++ memset(count, 0, 4 * sizeof(u32));
++
++ /* Count # blocks in each of 4 possible allocation states */
++ for (buf = 0; buf < length; buf++) {
++ bi = rgd->rd_bits + buf;
++ for (x = 0; x < 4; x++)
++ count[x] += gfs2_bitcount(rgd,
++ bi->bi_bh->b_data +
++ bi->bi_offset,
++ bi->bi_len, x);
++ }
++
++ if (count[0] != rgd->rd_rg.rg_free) {
++ if (gfs2_consist_rgrpd(rgd))
++ fs_err(sdp, "free data mismatch: %u != %u\n",
++ count[0], rgd->rd_rg.rg_free);
++ return;
++ }
++
++ tmp = rgd->rd_ri.ri_data -
++ rgd->rd_rg.rg_free -
++ rgd->rd_rg.rg_dinodes;
++ if (count[1] + count[2] != tmp) {
++ if (gfs2_consist_rgrpd(rgd))
++ fs_err(sdp, "used data mismatch: %u != %u\n",
++ count[1], tmp);
++ return;
++ }
++
++ if (count[3] != rgd->rd_rg.rg_dinodes) {
++ if (gfs2_consist_rgrpd(rgd))
++ fs_err(sdp, "used metadata mismatch: %u != %u\n",
++ count[3], rgd->rd_rg.rg_dinodes);
++ return;
++ }
++
++ if (count[2] > count[3]) {
++ if (gfs2_consist_rgrpd(rgd))
++ fs_err(sdp, "unlinked inodes > inodes: %u\n",
++ count[2]);
++ return;
++ }
++
++}
++
++static inline int rgrp_contains_block(struct gfs2_rindex *ri, u64 block)
++{
++ u64 first = ri->ri_data0;
++ u64 last = first + ri->ri_data;
++ return first <= block && block < last;
++}
++
++/**
++ * gfs2_blk2rgrpd - Find resource group for a given data/meta block number
++ * @sdp: The GFS2 superblock
++ * @n: The data block number
++ *
++ * Returns: The resource group, or NULL if not found
++ */
++
++struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
++{
++ struct gfs2_rgrpd *rgd;
++
++ spin_lock(&sdp->sd_rindex_spin);
++
++ list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) {
++ if (rgrp_contains_block(&rgd->rd_ri, blk)) {
++ list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
++ spin_unlock(&sdp->sd_rindex_spin);
++ return rgd;
++ }
++ }
++
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ return NULL;
++}
++
++/**
++ * gfs2_rgrpd_get_first - get the first Resource Group in the filesystem
++ * @sdp: The GFS2 superblock
++ *
++ * Returns: The first rgrp in the filesystem
++ */
++
++struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
++{
++ gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list));
++ return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list);
++}
++
++/**
++ * gfs2_rgrpd_get_next - get the next RG
++ * @rgd: A RG
++ *
++ * Returns: The next rgrp
++ */
++
++struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
++{
++ if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list)
++ return NULL;
++ return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list);
++}
++
++static void clear_rgrpdi(struct gfs2_sbd *sdp)
++{
++ struct list_head *head;
++ struct gfs2_rgrpd *rgd;
++ struct gfs2_glock *gl;
++
++ spin_lock(&sdp->sd_rindex_spin);
++ sdp->sd_rindex_forward = NULL;
++ head = &sdp->sd_rindex_recent_list;
++ while (!list_empty(head)) {
++ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);
++ list_del(&rgd->rd_recent);
++ }
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ head = &sdp->sd_rindex_list;
++ while (!list_empty(head)) {
++ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list);
++ gl = rgd->rd_gl;
++
++ list_del(&rgd->rd_list);
++ list_del(&rgd->rd_list_mru);
++
++ if (gl) {
++ gl->gl_object = NULL;
++ gfs2_glock_put(gl);
++ }
++
++ kfree(rgd->rd_bits);
++ kfree(rgd);
++ }
++}
++
++void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
++{
++ mutex_lock(&sdp->sd_rindex_mutex);
++ clear_rgrpdi(sdp);
++ mutex_unlock(&sdp->sd_rindex_mutex);
++}
++
++/**
++ * gfs2_compute_bitstructs - Compute the bitmap sizes
++ * @rgd: The resource group descriptor
++ *
++ * Calculates bitmap descriptors, one for each block that contains bitmap data
++ *
++ * Returns: errno
++ */
++
++static int compute_bitstructs(struct gfs2_rgrpd *rgd)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ struct gfs2_bitmap *bi;
++ u32 length = rgd->rd_ri.ri_length; /* # blocks in hdr & bitmap */
++ u32 bytes_left, bytes;
++ int x;
++
++ if (!length)
++ return -EINVAL;
++
++ rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_NOFS);
++ if (!rgd->rd_bits)
++ return -ENOMEM;
++
++ bytes_left = rgd->rd_ri.ri_bitbytes;
++
++ for (x = 0; x < length; x++) {
++ bi = rgd->rd_bits + x;
++
++ /* small rgrp; bitmap stored completely in header block */
++ if (length == 1) {
++ bytes = bytes_left;
++ bi->bi_offset = sizeof(struct gfs2_rgrp);
++ bi->bi_start = 0;
++ bi->bi_len = bytes;
++ /* header block */
++ } else if (x == 0) {
++ bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp);
++ bi->bi_offset = sizeof(struct gfs2_rgrp);
++ bi->bi_start = 0;
++ bi->bi_len = bytes;
++ /* last block */
++ } else if (x + 1 == length) {
++ bytes = bytes_left;
++ bi->bi_offset = sizeof(struct gfs2_meta_header);
++ bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left;
++ bi->bi_len = bytes;
++ /* other blocks */
++ } else {
++ bytes = sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_meta_header);
++ bi->bi_offset = sizeof(struct gfs2_meta_header);
++ bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left;
++ bi->bi_len = bytes;
++ }
++
++ bytes_left -= bytes;
++ }
++
++ if (bytes_left) {
++ gfs2_consist_rgrpd(rgd);
++ return -EIO;
++ }
++ bi = rgd->rd_bits + (length - 1);
++ if ((bi->bi_start + bi->bi_len) * GFS2_NBBY != rgd->rd_ri.ri_data) {
++ if (gfs2_consist_rgrpd(rgd)) {
++ gfs2_rindex_print(&rgd->rd_ri);
++ fs_err(sdp, "start=%u len=%u offset=%u\n",
++ bi->bi_start, bi->bi_len, bi->bi_offset);
++ }
++ return -EIO;
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_ri_update - Pull in a new resource index from the disk
++ * @gl: The glock covering the rindex inode
++ *
++ * Returns: 0 on successful update, error code otherwise
++ */
++
++static int gfs2_ri_update(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct inode *inode = &ip->i_inode;
++ struct gfs2_rgrpd *rgd;
++ char buf[sizeof(struct gfs2_rindex)];
++ struct file_ra_state ra_state;
++ u64 junk = ip->i_di.di_size;
++ int error;
++
++ if (do_div(junk, sizeof(struct gfs2_rindex))) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++
++ clear_rgrpdi(sdp);
++
++ file_ra_state_init(&ra_state, inode->i_mapping);
++ for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {
++ loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
++ error = gfs2_internal_read(ip, &ra_state, buf, &pos,
++ sizeof(struct gfs2_rindex));
++ if (!error)
++ break;
++ if (error != sizeof(struct gfs2_rindex)) {
++ if (error > 0)
++ error = -EIO;
++ goto fail;
++ }
++
++ rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS);
++ error = -ENOMEM;
++ if (!rgd)
++ goto fail;
++
++ mutex_init(&rgd->rd_mutex);
++ lops_init_le(&rgd->rd_le, &gfs2_rg_lops);
++ rgd->rd_sbd = sdp;
++
++ list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list);
++ list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
++
++ gfs2_rindex_in(&rgd->rd_ri, buf);
++ error = compute_bitstructs(rgd);
++ if (error)
++ goto fail;
++
++ error = gfs2_glock_get(sdp, rgd->rd_ri.ri_addr,
++ &gfs2_rgrp_glops, CREATE, &rgd->rd_gl);
++ if (error)
++ goto fail;
++
++ rgd->rd_gl->gl_object = rgd;
++ rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1;
++ }
++
++ sdp->sd_rindex_vn = ip->i_gl->gl_vn;
++ return 0;
++
++fail:
++ clear_rgrpdi(sdp);
++ return error;
++}
++
++/**
++ * gfs2_rindex_hold - Grab a lock on the rindex
++ * @sdp: The GFS2 superblock
++ * @ri_gh: the glock holder
++ *
++ * We grab a lock on the rindex inode to make sure that it doesn't
++ * change whilst we are performing an operation. We keep this lock
++ * for quite long periods of time compared to other locks. This
++ * doesn't matter, since it is shared and it is very, very rarely
++ * accessed in the exclusive mode (i.e. only when expanding the filesystem).
++ *
++ * This makes sure that we're using the latest copy of the resource index
++ * special file, which might have been updated if someone expanded the
++ * filesystem (via gfs2_grow utility), which adds new resource groups.
++ *
++ * Returns: 0 on success, error code otherwise
++ */
++
++int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
++{
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
++ struct gfs2_glock *gl = ip->i_gl;
++ int error;
++
++ error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
++ if (error)
++ return error;
++
++ /* Read new copy from disk if we don't have the latest */
++ if (sdp->sd_rindex_vn != gl->gl_vn) {
++ mutex_lock(&sdp->sd_rindex_mutex);
++ if (sdp->sd_rindex_vn != gl->gl_vn) {
++ error = gfs2_ri_update(ip);
++ if (error)
++ gfs2_glock_dq_uninit(ri_gh);
++ }
++ mutex_unlock(&sdp->sd_rindex_mutex);
++ }
++
++ return error;
++}
++
++/**
++ * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps
++ * @rgd: the struct gfs2_rgrpd describing the RG to read in
++ *
++ * Read in all of a Resource Group's header and bitmap blocks.
++ * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps.
++ *
++ * Returns: errno
++ */
++
++int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ struct gfs2_glock *gl = rgd->rd_gl;
++ unsigned int length = rgd->rd_ri.ri_length;
++ struct gfs2_bitmap *bi;
++ unsigned int x, y;
++ int error;
++
++ mutex_lock(&rgd->rd_mutex);
++
++ spin_lock(&sdp->sd_rindex_spin);
++ if (rgd->rd_bh_count) {
++ rgd->rd_bh_count++;
++ spin_unlock(&sdp->sd_rindex_spin);
++ mutex_unlock(&rgd->rd_mutex);
++ return 0;
++ }
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ for (x = 0; x < length; x++) {
++ bi = rgd->rd_bits + x;
++ error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, 0, &bi->bi_bh);
++ if (error)
++ goto fail;
++ }
++
++ for (y = length; y--;) {
++ bi = rgd->rd_bits + y;
++ error = gfs2_meta_wait(sdp, bi->bi_bh);
++ if (error)
++ goto fail;
++ if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB :
++ GFS2_METATYPE_RG)) {
++ error = -EIO;
++ goto fail;
++ }
++ }
++
++ if (rgd->rd_rg_vn != gl->gl_vn) {
++ gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data);
++ rgd->rd_rg_vn = gl->gl_vn;
++ }
++
++ spin_lock(&sdp->sd_rindex_spin);
++ rgd->rd_free_clone = rgd->rd_rg.rg_free;
++ rgd->rd_bh_count++;
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ mutex_unlock(&rgd->rd_mutex);
++
++ return 0;
++
++fail:
++ while (x--) {
++ bi = rgd->rd_bits + x;
++ brelse(bi->bi_bh);
++ bi->bi_bh = NULL;
++ gfs2_assert_warn(sdp, !bi->bi_clone);
++ }
++ mutex_unlock(&rgd->rd_mutex);
++
++ return error;
++}
++
++void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++
++ spin_lock(&sdp->sd_rindex_spin);
++ gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
++ rgd->rd_bh_count++;
++ spin_unlock(&sdp->sd_rindex_spin);
++}
++
++/**
++ * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get()
++ * @rgd: the struct gfs2_rgrpd describing the RG to read in
++ *
++ */
++
++void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ int x, length = rgd->rd_ri.ri_length;
++
++ spin_lock(&sdp->sd_rindex_spin);
++ gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
++ if (--rgd->rd_bh_count) {
++ spin_unlock(&sdp->sd_rindex_spin);
++ return;
++ }
++
++ for (x = 0; x < length; x++) {
++ struct gfs2_bitmap *bi = rgd->rd_bits + x;
++ kfree(bi->bi_clone);
++ bi->bi_clone = NULL;
++ brelse(bi->bi_bh);
++ bi->bi_bh = NULL;
++ }
++
++ spin_unlock(&sdp->sd_rindex_spin);
++}
++
++void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ unsigned int length = rgd->rd_ri.ri_length;
++ unsigned int x;
++
++ for (x = 0; x < length; x++) {
++ struct gfs2_bitmap *bi = rgd->rd_bits + x;
++ if (!bi->bi_clone)
++ continue;
++ memcpy(bi->bi_clone + bi->bi_offset,
++ bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
++ }
++
++ spin_lock(&sdp->sd_rindex_spin);
++ rgd->rd_free_clone = rgd->rd_rg.rg_free;
++ spin_unlock(&sdp->sd_rindex_spin);
++}
++
++/**
++ * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode
++ * @ip: the incore GFS2 inode structure
++ *
++ * Returns: the struct gfs2_alloc
++ */
++
++struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
++{
++ struct gfs2_alloc *al = &ip->i_alloc;
++
++ /* FIXME: Should assert that the correct locks are held here... */
++ memset(al, 0, sizeof(*al));
++ return al;
++}
++
++/**
++ * try_rgrp_fit - See if a given reservation will fit in a given RG
++ * @rgd: the RG data
++ * @al: the struct gfs2_alloc structure describing the reservation
++ *
++ * If there's room for the requested blocks to be allocated from the RG:
++ * Sets the $al_reserved_data field in @al.
++ * Sets the $al_reserved_meta field in @al.
++ * Sets the $al_rgd field in @al.
++ *
++ * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
++ */
++
++static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ int ret = 0;
++
++ spin_lock(&sdp->sd_rindex_spin);
++ if (rgd->rd_free_clone >= al->al_requested) {
++ al->al_rgd = rgd;
++ ret = 1;
++ }
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ return ret;
++}
++
++/**
++ * recent_rgrp_first - get first RG from "recent" list
++ * @sdp: The GFS2 superblock
++ * @rglast: address of the rgrp used last
++ *
++ * Returns: The first rgrp in the recent list
++ */
++
++static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp,
++ u64 rglast)
++{
++ struct gfs2_rgrpd *rgd = NULL;
++
++ spin_lock(&sdp->sd_rindex_spin);
++
++ if (list_empty(&sdp->sd_rindex_recent_list))
++ goto out;
++
++ if (!rglast)
++ goto first;
++
++ list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
++ if (rgd->rd_ri.ri_addr == rglast)
++ goto out;
++ }
++
++first:
++ rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd,
++ rd_recent);
++out:
++ spin_unlock(&sdp->sd_rindex_spin);
++ return rgd;
++}
++
++/**
++ * recent_rgrp_next - get next RG from "recent" list
++ * @cur_rgd: current rgrp
++ * @remove:
++ *
++ * Returns: The next rgrp in the recent list
++ */
++
++static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd,
++ int remove)
++{
++ struct gfs2_sbd *sdp = cur_rgd->rd_sbd;
++ struct list_head *head;
++ struct gfs2_rgrpd *rgd;
++
++ spin_lock(&sdp->sd_rindex_spin);
++
++ head = &sdp->sd_rindex_recent_list;
++
++ list_for_each_entry(rgd, head, rd_recent) {
++ if (rgd == cur_rgd) {
++ if (cur_rgd->rd_recent.next != head)
++ rgd = list_entry(cur_rgd->rd_recent.next,
++ struct gfs2_rgrpd, rd_recent);
++ else
++ rgd = NULL;
++
++ if (remove)
++ list_del(&cur_rgd->rd_recent);
++
++ goto out;
++ }
++ }
++
++ rgd = NULL;
++ if (!list_empty(head))
++ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);
++
++out:
++ spin_unlock(&sdp->sd_rindex_spin);
++ return rgd;
++}
++
++/**
++ * recent_rgrp_add - add an RG to tail of "recent" list
++ * @new_rgd: The rgrp to add
++ *
++ */
++
++static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd)
++{
++ struct gfs2_sbd *sdp = new_rgd->rd_sbd;
++ struct gfs2_rgrpd *rgd;
++ unsigned int count = 0;
++ unsigned int max = sdp->sd_rgrps / gfs2_jindex_size(sdp);
++
++ spin_lock(&sdp->sd_rindex_spin);
++
++ list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
++ if (rgd == new_rgd)
++ goto out;
++
++ if (++count >= max)
++ goto out;
++ }
++ list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list);
++
++out:
++ spin_unlock(&sdp->sd_rindex_spin);
++}
++
++/**
++ * forward_rgrp_get - get an rgrp to try next from full list
++ * @sdp: The GFS2 superblock
++ *
++ * Returns: The rgrp to try next
++ */
++
++static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp)
++{
++ struct gfs2_rgrpd *rgd;
++ unsigned int journals = gfs2_jindex_size(sdp);
++ unsigned int rg = 0, x;
++
++ spin_lock(&sdp->sd_rindex_spin);
++
++ rgd = sdp->sd_rindex_forward;
++ if (!rgd) {
++ if (sdp->sd_rgrps >= journals)
++ rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals;
++
++ for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg;
++ x++, rgd = gfs2_rgrpd_get_next(rgd))
++ /* Do Nothing */;
++
++ sdp->sd_rindex_forward = rgd;
++ }
++
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ return rgd;
++}
++
++/**
++ * forward_rgrp_set - set the forward rgrp pointer
++ * @sdp: the filesystem
++ * @rgd: The new forward rgrp
++ *
++ */
++
++static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
++{
++ spin_lock(&sdp->sd_rindex_spin);
++ sdp->sd_rindex_forward = rgd;
++ spin_unlock(&sdp->sd_rindex_spin);
++}
++
++/**
++ * get_local_rgrp - Choose and lock a rgrp for allocation
++ * @ip: the inode to reserve space for
++ * @rgp: the chosen and locked rgrp
++ *
++ * Try to acquire rgrp in way which avoids contending with others.
++ *
++ * Returns: errno
++ */
++
++static int get_local_rgrp(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_rgrpd *rgd, *begin = NULL;
++ struct gfs2_alloc *al = &ip->i_alloc;
++ int flags = LM_FLAG_TRY;
++ int skipped = 0;
++ int loops = 0;
++ int error;
++
++ /* Try recently successful rgrps */
++
++ rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
++
++ while (rgd) {
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
++ LM_FLAG_TRY, &al->al_rgd_gh);
++ switch (error) {
++ case 0:
++ if (try_rgrp_fit(rgd, al))
++ goto out;
++ gfs2_glock_dq_uninit(&al->al_rgd_gh);
++ rgd = recent_rgrp_next(rgd, 1);
++ break;
++
++ case GLR_TRYFAILED:
++ rgd = recent_rgrp_next(rgd, 0);
++ break;
++
++ default:
++ return error;
++ }
++ }
++
++ /* Go through full list of rgrps */
++
++ begin = rgd = forward_rgrp_get(sdp);
++
++ for (;;) {
++ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
++ &al->al_rgd_gh);
++ switch (error) {
++ case 0:
++ if (try_rgrp_fit(rgd, al))
++ goto out;
++ gfs2_glock_dq_uninit(&al->al_rgd_gh);
++ break;
++
++ case GLR_TRYFAILED:
++ skipped++;
++ break;
++
++ default:
++ return error;
++ }
++
++ rgd = gfs2_rgrpd_get_next(rgd);
++ if (!rgd)
++ rgd = gfs2_rgrpd_get_first(sdp);
++
++ if (rgd == begin) {
++ if (++loops >= 2 || !skipped)
++ return -ENOSPC;
++ flags = 0;
++ }
++ }
++
++out:
++ ip->i_last_rg_alloc = rgd->rd_ri.ri_addr;
++
++ if (begin) {
++ recent_rgrp_add(rgd);
++ rgd = gfs2_rgrpd_get_next(rgd);
++ if (!rgd)
++ rgd = gfs2_rgrpd_get_first(sdp);
++ forward_rgrp_set(sdp, rgd);
++ }
++
++ return 0;
++}
++
++/**
++ * gfs2_inplace_reserve_i - Reserve space in the filesystem
++ * @ip: the inode to reserve space for
++ *
++ * Returns: errno
++ */
++
++int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ int error;
++
++ if (gfs2_assert_warn(sdp, al->al_requested))
++ return -EINVAL;
++
++ error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
++ if (error)
++ return error;
++
++ error = get_local_rgrp(ip);
++ if (error) {
++ gfs2_glock_dq_uninit(&al->al_ri_gh);
++ return error;
++ }
++
++ al->al_file = file;
++ al->al_line = line;
++
++ return 0;
++}
++
++/**
++ * gfs2_inplace_release - release an inplace reservation
++ * @ip: the inode the reservation was taken out on
++ *
++ * Release a reservation made by gfs2_inplace_reserve().
++ */
++
++void gfs2_inplace_release(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++
++ if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
++ fs_warn(sdp, "al_alloced = %u, al_requested = %u "
++ "al_file = %s, al_line = %u\n",
++ al->al_alloced, al->al_requested, al->al_file,
++ al->al_line);
++
++ al->al_rgd = NULL;
++ gfs2_glock_dq_uninit(&al->al_rgd_gh);
++ gfs2_glock_dq_uninit(&al->al_ri_gh);
++}
++
++/**
++ * gfs2_get_block_type - Check a block in a RG is of given type
++ * @rgd: the resource group holding the block
++ * @block: the block number
++ *
++ * Returns: The block type (GFS2_BLKST_*)
++ */
++
++unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
++{
++ struct gfs2_bitmap *bi = NULL;
++ u32 length, rgrp_block, buf_block;
++ unsigned int buf;
++ unsigned char type;
++
++ length = rgd->rd_ri.ri_length;
++ rgrp_block = block - rgd->rd_ri.ri_data0;
++
++ for (buf = 0; buf < length; buf++) {
++ bi = rgd->rd_bits + buf;
++ if (rgrp_block < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
++ break;
++ }
++
++ gfs2_assert(rgd->rd_sbd, buf < length);
++ buf_block = rgrp_block - bi->bi_start * GFS2_NBBY;
++
++ type = gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
++ bi->bi_len, buf_block);
++
++ return type;
++}
++
++/**
++ * rgblk_search - find a block in @old_state, change allocation
++ * state to @new_state
++ * @rgd: the resource group descriptor
++ * @goal: the goal block within the RG (start here to search for avail block)
++ * @old_state: GFS2_BLKST_XXX the before-allocation state to find
++ * @new_state: GFS2_BLKST_XXX the after-allocation block state
++ *
++ * Walk rgrp's bitmap to find bits that represent a block in @old_state.
++ * Add the found bitmap buffer to the transaction.
++ * Set the found bits to @new_state to change block's allocation state.
++ *
++ * This function never fails, because we wouldn't call it unless we
++ * know (from reservation results, etc.) that a block is available.
++ *
++ * Scope of @goal and returned block is just within rgrp, not the whole
++ * filesystem.
++ *
++ * Returns: the block number allocated
++ */
++
++static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
++ unsigned char old_state, unsigned char new_state)
++{
++ struct gfs2_bitmap *bi = NULL;
++ u32 length = rgd->rd_ri.ri_length;
++ u32 blk = 0;
++ unsigned int buf, x;
++
++ /* Find bitmap block that contains bits for goal block */
++ for (buf = 0; buf < length; buf++) {
++ bi = rgd->rd_bits + buf;
++ if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
++ break;
++ }
++
++ gfs2_assert(rgd->rd_sbd, buf < length);
++
++ /* Convert scope of "goal" from rgrp-wide to within found bit block */
++ goal -= bi->bi_start * GFS2_NBBY;
++
++ /* Search (up to entire) bitmap in this rgrp for allocatable block.
++ "x <= length", instead of "x < length", because we typically start
++ the search in the middle of a bit block, but if we can't find an
++ allocatable block anywhere else, we want to be able wrap around and
++ search in the first part of our first-searched bit block. */
++ for (x = 0; x <= length; x++) {
++ if (bi->bi_clone)
++ blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
++ bi->bi_len, goal, old_state);
++ else
++ blk = gfs2_bitfit(rgd,
++ bi->bi_bh->b_data + bi->bi_offset,
++ bi->bi_len, goal, old_state);
++ if (blk != BFITNOENT)
++ break;
++
++ /* Try next bitmap block (wrap back to rgrp header if at end) */
++ buf = (buf + 1) % length;
++ bi = rgd->rd_bits + buf;
++ goal = 0;
++ }
++
++ if (gfs2_assert_withdraw(rgd->rd_sbd, x <= length))
++ blk = 0;
++
++ gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
++ gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
++ bi->bi_len, blk, new_state);
++ if (bi->bi_clone)
++ gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset,
++ bi->bi_len, blk, new_state);
++
++ return bi->bi_start * GFS2_NBBY + blk;
++}
++
++/**
++ * rgblk_free - Change alloc state of given block(s)
++ * @sdp: the filesystem
++ * @bstart: the start of a run of blocks to free
++ * @blen: the length of the block run (all must lie within ONE RG!)
++ * @new_state: GFS2_BLKST_XXX the after-allocation block state
++ *
++ * Returns: Resource group containing the block(s)
++ */
++
++static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
++ u32 blen, unsigned char new_state)
++{
++ struct gfs2_rgrpd *rgd;
++ struct gfs2_bitmap *bi = NULL;
++ u32 length, rgrp_blk, buf_blk;
++ unsigned int buf;
++
++ rgd = gfs2_blk2rgrpd(sdp, bstart);
++ if (!rgd) {
++ if (gfs2_consist(sdp))
++ fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
++ return NULL;
++ }
++
++ length = rgd->rd_ri.ri_length;
++
++ rgrp_blk = bstart - rgd->rd_ri.ri_data0;
++
++ while (blen--) {
++ for (buf = 0; buf < length; buf++) {
++ bi = rgd->rd_bits + buf;
++ if (rgrp_blk < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
++ break;
++ }
++
++ gfs2_assert(rgd->rd_sbd, buf < length);
++
++ buf_blk = rgrp_blk - bi->bi_start * GFS2_NBBY;
++ rgrp_blk++;
++
++ if (!bi->bi_clone) {
++ bi->bi_clone = kmalloc(bi->bi_bh->b_size,
++ GFP_NOFS | __GFP_NOFAIL);
++ memcpy(bi->bi_clone + bi->bi_offset,
++ bi->bi_bh->b_data + bi->bi_offset,
++ bi->bi_len);
++ }
++ gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
++ gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
++ bi->bi_len, buf_blk, new_state);
++ }
++
++ return rgd;
++}
++
++/**
++ * gfs2_alloc_data - Allocate a data block
++ * @ip: the inode to allocate the data block for
++ *
++ * Returns: the allocated block
++ */
++
++u64 gfs2_alloc_data(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_rgrpd *rgd = al->al_rgd;
++ u32 goal, blk;
++ u64 block;
++
++ if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_data))
++ goal = ip->i_di.di_goal_data - rgd->rd_ri.ri_data0;
++ else
++ goal = rgd->rd_last_alloc_data;
++
++ blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
++ rgd->rd_last_alloc_data = blk;
++
++ block = rgd->rd_ri.ri_data0 + blk;
++ ip->i_di.di_goal_data = block;
++
++ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
++ rgd->rd_rg.rg_free--;
++
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++
++ al->al_alloced++;
++
++ gfs2_statfs_change(sdp, 0, -1, 0);
++ gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid);
++
++ spin_lock(&sdp->sd_rindex_spin);
++ rgd->rd_free_clone--;
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ return block;
++}
++
++/**
++ * gfs2_alloc_meta - Allocate a metadata block
++ * @ip: the inode to allocate the metadata block for
++ *
++ * Returns: the allocated block
++ */
++
++u64 gfs2_alloc_meta(struct gfs2_inode *ip)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_alloc *al = &ip->i_alloc;
++ struct gfs2_rgrpd *rgd = al->al_rgd;
++ u32 goal, blk;
++ u64 block;
++
++ if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_meta))
++ goal = ip->i_di.di_goal_meta - rgd->rd_ri.ri_data0;
++ else
++ goal = rgd->rd_last_alloc_meta;
++
++ blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
++ rgd->rd_last_alloc_meta = blk;
++
++ block = rgd->rd_ri.ri_data0 + blk;
++ ip->i_di.di_goal_meta = block;
++
++ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
++ rgd->rd_rg.rg_free--;
++
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++
++ al->al_alloced++;
++
++ gfs2_statfs_change(sdp, 0, -1, 0);
++ gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid);
++ gfs2_trans_add_unrevoke(sdp, block);
++
++ spin_lock(&sdp->sd_rindex_spin);
++ rgd->rd_free_clone--;
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ return block;
++}
++
++/**
++ * gfs2_alloc_di - Allocate a dinode
++ * @dip: the directory that the inode is going in
++ *
++ * Returns: the block allocated
++ */
++
++u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
++ struct gfs2_alloc *al = &dip->i_alloc;
++ struct gfs2_rgrpd *rgd = al->al_rgd;
++ u32 blk;
++ u64 block;
++
++ blk = rgblk_search(rgd, rgd->rd_last_alloc_meta,
++ GFS2_BLKST_FREE, GFS2_BLKST_DINODE);
++
++ rgd->rd_last_alloc_meta = blk;
++
++ block = rgd->rd_ri.ri_data0 + blk;
++
++ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
++ rgd->rd_rg.rg_free--;
++ rgd->rd_rg.rg_dinodes++;
++ *generation = rgd->rd_rg.rg_igeneration++;
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++
++ al->al_alloced++;
++
++ gfs2_statfs_change(sdp, 0, -1, +1);
++ gfs2_trans_add_unrevoke(sdp, block);
++
++ spin_lock(&sdp->sd_rindex_spin);
++ rgd->rd_free_clone--;
++ spin_unlock(&sdp->sd_rindex_spin);
++
++ return block;
++}
++
++/**
++ * gfs2_free_data - free a contiguous run of data block(s)
++ * @ip: the inode these blocks are being freed from
++ * @bstart: first block of a run of contiguous blocks
++ * @blen: the length of the block run
++ *
++ */
++
++void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_rgrpd *rgd;
++
++ rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
++ if (!rgd)
++ return;
++
++ rgd->rd_rg.rg_free += blen;
++
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++
++ gfs2_trans_add_rg(rgd);
++
++ gfs2_statfs_change(sdp, 0, +blen, 0);
++ gfs2_quota_change(ip, -(s64)blen,
++ ip->i_di.di_uid, ip->i_di.di_gid);
++}
++
++/**
++ * gfs2_free_meta - free a contiguous run of data block(s)
++ * @ip: the inode these blocks are being freed from
++ * @bstart: first block of a run of contiguous blocks
++ * @blen: the length of the block run
++ *
++ */
++
++void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ struct gfs2_rgrpd *rgd;
++
++ rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
++ if (!rgd)
++ return;
++
++ rgd->rd_rg.rg_free += blen;
++
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++
++ gfs2_trans_add_rg(rgd);
++
++ gfs2_statfs_change(sdp, 0, +blen, 0);
++ gfs2_quota_change(ip, -(s64)blen, ip->i_di.di_uid, ip->i_di.di_gid);
++ gfs2_meta_wipe(ip, bstart, blen);
++}
++
++void gfs2_unlink_di(struct inode *inode)
++{
++ struct gfs2_inode *ip = GFS2_I(inode);
++ struct gfs2_sbd *sdp = GFS2_SB(inode);
++ struct gfs2_rgrpd *rgd;
++ u64 blkno = ip->i_num.no_addr;
++
++ rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED);
++ if (!rgd)
++ return;
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++ gfs2_trans_add_rg(rgd);
++}
++
++static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ struct gfs2_rgrpd *tmp_rgd;
++
++ tmp_rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_FREE);
++ if (!tmp_rgd)
++ return;
++ gfs2_assert_withdraw(sdp, rgd == tmp_rgd);
++
++ if (!rgd->rd_rg.rg_dinodes)
++ gfs2_consist_rgrpd(rgd);
++ rgd->rd_rg.rg_dinodes--;
++ rgd->rd_rg.rg_free++;
++
++ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
++ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
++
++ gfs2_statfs_change(sdp, 0, +1, -1);
++ gfs2_trans_add_rg(rgd);
++}
++
++
++void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
++{
++ gfs2_free_uninit_di(rgd, ip->i_num.no_addr);
++ gfs2_quota_change(ip, -1, ip->i_di.di_uid, ip->i_di.di_gid);
++ gfs2_meta_wipe(ip, ip->i_num.no_addr, 1);
++}
++
++/**
++ * gfs2_rlist_add - add a RG to a list of RGs
++ * @sdp: the filesystem
++ * @rlist: the list of resource groups
++ * @block: the block
++ *
++ * Figure out what RG a block belongs to and add that RG to the list
++ *
++ * FIXME: Don't use NOFAIL
++ *
++ */
++
++void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
++ u64 block)
++{
++ struct gfs2_rgrpd *rgd;
++ struct gfs2_rgrpd **tmp;
++ unsigned int new_space;
++ unsigned int x;
++
++ if (gfs2_assert_warn(sdp, !rlist->rl_ghs))
++ return;
++
++ rgd = gfs2_blk2rgrpd(sdp, block);
++ if (!rgd) {
++ if (gfs2_consist(sdp))
++ fs_err(sdp, "block = %llu\n", (unsigned long long)block);
++ return;
++ }
++
++ for (x = 0; x < rlist->rl_rgrps; x++)
++ if (rlist->rl_rgd[x] == rgd)
++ return;
++
++ if (rlist->rl_rgrps == rlist->rl_space) {
++ new_space = rlist->rl_space + 10;
++
++ tmp = kcalloc(new_space, sizeof(struct gfs2_rgrpd *),
++ GFP_NOFS | __GFP_NOFAIL);
++
++ if (rlist->rl_rgd) {
++ memcpy(tmp, rlist->rl_rgd,
++ rlist->rl_space * sizeof(struct gfs2_rgrpd *));
++ kfree(rlist->rl_rgd);
++ }
++
++ rlist->rl_space = new_space;
++ rlist->rl_rgd = tmp;
++ }
++
++ rlist->rl_rgd[rlist->rl_rgrps++] = rgd;
++}
++
++/**
++ * gfs2_rlist_alloc - all RGs have been added to the rlist, now allocate
++ * and initialize an array of glock holders for them
++ * @rlist: the list of resource groups
++ * @state: the lock state to acquire the RG lock in
++ * @flags: the modifier flags for the holder structures
++ *
++ * FIXME: Don't use NOFAIL
++ *
++ */
++
++void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
++ int flags)
++{
++ unsigned int x;
++
++ rlist->rl_ghs = kcalloc(rlist->rl_rgrps, sizeof(struct gfs2_holder),
++ GFP_NOFS | __GFP_NOFAIL);
++ for (x = 0; x < rlist->rl_rgrps; x++)
++ gfs2_holder_init(rlist->rl_rgd[x]->rd_gl,
++ state, flags,
++ &rlist->rl_ghs[x]);
++}
++
++/**
++ * gfs2_rlist_free - free a resource group list
++ * @list: the list of resource groups
++ *
++ */
++
++void gfs2_rlist_free(struct gfs2_rgrp_list *rlist)
++{
++ unsigned int x;
++
++ kfree(rlist->rl_rgd);
++
++ if (rlist->rl_ghs) {
++ for (x = 0; x < rlist->rl_rgrps; x++)
++ gfs2_holder_uninit(&rlist->rl_ghs[x]);
++ kfree(rlist->rl_ghs);
++ }
++}
++
+diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
+new file mode 100644
+index 0000000..b01e0cf
+--- /dev/null
++++ b/fs/gfs2/rgrp.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __RGRP_DOT_H__
++#define __RGRP_DOT_H__
++
++struct gfs2_rgrpd;
++struct gfs2_sbd;
++struct gfs2_holder;
++
++void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
++
++struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
++struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
++struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
++
++void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
++int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
++
++int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
++void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
++void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
++
++void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
++
++struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
++static inline void gfs2_alloc_put(struct gfs2_inode *ip)
++{
++ return; /* So we can see where ip->i_alloc is used */
++}
++
++int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
++ char *file, unsigned int line);
++#define gfs2_inplace_reserve(ip) \
++gfs2_inplace_reserve_i((ip), __FILE__, __LINE__)
++
++void gfs2_inplace_release(struct gfs2_inode *ip);
++
++unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
++
++u64 gfs2_alloc_data(struct gfs2_inode *ip);
++u64 gfs2_alloc_meta(struct gfs2_inode *ip);
++u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
++
++void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
++void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
++void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
++void gfs2_unlink_di(struct inode *inode);
++
++struct gfs2_rgrp_list {
++ unsigned int rl_rgrps;
++ unsigned int rl_space;
++ struct gfs2_rgrpd **rl_rgd;
++ struct gfs2_holder *rl_ghs;
++};
++
++void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
++ u64 block);
++void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
++ int flags);
++void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
++
++#endif /* __RGRP_DOT_H__ */
+diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
+new file mode 100644
+index 0000000..6a78b1b
+--- /dev/null
++++ b/fs/gfs2/super.c
+@@ -0,0 +1,976 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/crc32.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/bio.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "bmap.h"
++#include "dir.h"
++#include "glock.h"
++#include "glops.h"
++#include "inode.h"
++#include "log.h"
++#include "meta_io.h"
++#include "quota.h"
++#include "recovery.h"
++#include "rgrp.h"
++#include "super.h"
++#include "trans.h"
++#include "util.h"
++
++static const u32 gfs2_old_fs_formats[] = {
++ 0
++};
++
++static const u32 gfs2_old_multihost_formats[] = {
++ 0
++};
++
++/**
++ * gfs2_tune_init - Fill a gfs2_tune structure with default values
++ * @gt: tune
++ *
++ */
++
++void gfs2_tune_init(struct gfs2_tune *gt)
++{
++ spin_lock_init(>->gt_spin);
++
++ gt->gt_ilimit = 100;
++ gt->gt_ilimit_tries = 3;
++ gt->gt_ilimit_min = 1;
++ gt->gt_demote_secs = 300;
++ gt->gt_incore_log_blocks = 1024;
++ gt->gt_log_flush_secs = 60;
++ gt->gt_jindex_refresh_secs = 60;
++ gt->gt_scand_secs = 15;
++ gt->gt_recoverd_secs = 60;
++ gt->gt_logd_secs = 1;
++ gt->gt_quotad_secs = 5;
++ gt->gt_quota_simul_sync = 64;
++ gt->gt_quota_warn_period = 10;
++ gt->gt_quota_scale_num = 1;
++ gt->gt_quota_scale_den = 1;
++ gt->gt_quota_cache_secs = 300;
++ gt->gt_quota_quantum = 60;
++ gt->gt_atime_quantum = 3600;
++ gt->gt_new_files_jdata = 0;
++ gt->gt_new_files_directio = 0;
++ gt->gt_max_atomic_write = 4 << 20;
++ gt->gt_max_readahead = 1 << 18;
++ gt->gt_lockdump_size = 131072;
++ gt->gt_stall_secs = 600;
++ gt->gt_complain_secs = 10;
++ gt->gt_reclaim_limit = 5000;
++ gt->gt_entries_per_readdir = 32;
++ gt->gt_prefetch_secs = 10;
++ gt->gt_greedy_default = HZ / 10;
++ gt->gt_greedy_quantum = HZ / 40;
++ gt->gt_greedy_max = HZ / 4;
++ gt->gt_statfs_quantum = 30;
++ gt->gt_statfs_slow = 0;
++}
++
++/**
++ * gfs2_check_sb - Check superblock
++ * @sdp: the filesystem
++ * @sb: The superblock
++ * @silent: Don't print a message if the check fails
++ *
++ * Checks the version code of the FS is one that we understand how to
++ * read and that the sizes of the various on-disk structures have not
++ * changed.
++ */
++
++int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent)
++{
++ unsigned int x;
++
++ if (sb->sb_header.mh_magic != GFS2_MAGIC ||
++ sb->sb_header.mh_type != GFS2_METATYPE_SB) {
++ if (!silent)
++ printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n");
++ return -EINVAL;
++ }
++
++ /* If format numbers match exactly, we're done. */
++
++ if (sb->sb_fs_format == GFS2_FORMAT_FS &&
++ sb->sb_multihost_format == GFS2_FORMAT_MULTI)
++ return 0;
++
++ if (sb->sb_fs_format != GFS2_FORMAT_FS) {
++ for (x = 0; gfs2_old_fs_formats[x]; x++)
++ if (gfs2_old_fs_formats[x] == sb->sb_fs_format)
++ break;
++
++ if (!gfs2_old_fs_formats[x]) {
++ printk(KERN_WARNING
++ "GFS2: code version (%u, %u) is incompatible "
++ "with ondisk format (%u, %u)\n",
++ GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
++ sb->sb_fs_format, sb->sb_multihost_format);
++ printk(KERN_WARNING
++ "GFS2: I don't know how to upgrade this FS\n");
++ return -EINVAL;
++ }
++ }
++
++ if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) {
++ for (x = 0; gfs2_old_multihost_formats[x]; x++)
++ if (gfs2_old_multihost_formats[x] ==
++ sb->sb_multihost_format)
++ break;
++
++ if (!gfs2_old_multihost_formats[x]) {
++ printk(KERN_WARNING
++ "GFS2: code version (%u, %u) is incompatible "
++ "with ondisk format (%u, %u)\n",
++ GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
++ sb->sb_fs_format, sb->sb_multihost_format);
++ printk(KERN_WARNING
++ "GFS2: I don't know how to upgrade this FS\n");
++ return -EINVAL;
++ }
++ }
++
++ if (!sdp->sd_args.ar_upgrade) {
++ printk(KERN_WARNING
++ "GFS2: code version (%u, %u) is incompatible "
++ "with ondisk format (%u, %u)\n",
++ GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
++ sb->sb_fs_format, sb->sb_multihost_format);
++ printk(KERN_INFO
++ "GFS2: Use the \"upgrade\" mount option to upgrade "
++ "the FS\n");
++ printk(KERN_INFO "GFS2: See the manual for more details\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++
++static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error)
++{
++ struct page *page = bio->bi_private;
++ if (bio->bi_size)
++ return 1;
++
++ if (!error)
++ SetPageUptodate(page);
++ else
++ printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
++ unlock_page(page);
++ return 0;
++}
++
++struct page *gfs2_read_super(struct super_block *sb, sector_t sector)
++{
++ struct page *page;
++ struct bio *bio;
++
++ page = alloc_page(GFP_KERNEL);
++ if (unlikely(!page))
++ return NULL;
++
++ ClearPageUptodate(page);
++ ClearPageDirty(page);
++ lock_page(page);
++
++ bio = bio_alloc(GFP_KERNEL, 1);
++ if (unlikely(!bio)) {
++ __free_page(page);
++ return NULL;
++ }
++
++ bio->bi_sector = sector;
++ bio->bi_bdev = sb->s_bdev;
++ bio_add_page(bio, page, PAGE_SIZE, 0);
++
++ bio->bi_end_io = end_bio_io_page;
++ bio->bi_private = page;
++ submit_bio(READ_SYNC | (1 << BIO_RW_META), bio);
++ wait_on_page_locked(page);
++ bio_put(bio);
++ if (!PageUptodate(page)) {
++ __free_page(page);
++ return NULL;
++ }
++ return page;
++}
++
++/**
++ * gfs2_read_sb - Read super block
++ * @sdp: The GFS2 superblock
++ * @gl: the glock for the superblock (assumed to be held)
++ * @silent: Don't print message if mount fails
++ *
++ */
++
++int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
++{
++ u32 hash_blocks, ind_blocks, leaf_blocks;
++ u32 tmp_blocks;
++ unsigned int x;
++ int error;
++ struct page *page;
++ char *sb;
++
++ page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
++ if (!page) {
++ if (!silent)
++ fs_err(sdp, "can't read superblock\n");
++ return -EIO;
++ }
++ sb = kmap(page);
++ gfs2_sb_in(&sdp->sd_sb, sb);
++ kunmap(page);
++ __free_page(page);
++
++ error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
++ if (error)
++ return error;
++
++ sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
++ GFS2_BASIC_BLOCK_SHIFT;
++ sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
++ sdp->sd_diptrs = (sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_dinode)) / sizeof(u64);
++ sdp->sd_inptrs = (sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_meta_header)) / sizeof(u64);
++ sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
++ sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2;
++ sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1;
++ sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(u64);
++ sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_meta_header)) /
++ sizeof(struct gfs2_quota_change);
++
++ /* Compute maximum reservation required to add a entry to a directory */
++
++ hash_blocks = DIV_ROUND_UP(sizeof(u64) * (1 << GFS2_DIR_MAX_DEPTH),
++ sdp->sd_jbsize);
++
++ ind_blocks = 0;
++ for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) {
++ tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs);
++ ind_blocks += tmp_blocks;
++ }
++
++ leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH;
++
++ sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;
++
++ sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_dinode);
++ sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs;
++ for (x = 2;; x++) {
++ u64 space, d;
++ u32 m;
++
++ space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs;
++ d = space;
++ m = do_div(d, sdp->sd_inptrs);
++
++ if (d != sdp->sd_heightsize[x - 1] || m)
++ break;
++ sdp->sd_heightsize[x] = space;
++ }
++ sdp->sd_max_height = x;
++ gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);
++
++ sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
++ sizeof(struct gfs2_dinode);
++ sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
++ for (x = 2;; x++) {
++ u64 space, d;
++ u32 m;
++
++ space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
++ d = space;
++ m = do_div(d, sdp->sd_inptrs);
++
++ if (d != sdp->sd_jheightsize[x - 1] || m)
++ break;
++ sdp->sd_jheightsize[x] = space;
++ }
++ sdp->sd_max_jheight = x;
++ gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
++
++ return 0;
++}
++
++/**
++ * gfs2_jindex_hold - Grab a lock on the jindex
++ * @sdp: The GFS2 superblock
++ * @ji_gh: the holder for the jindex glock
++ *
++ * This is very similar to the gfs2_rindex_hold() function, except that
++ * in general we hold the jindex lock for longer periods of time and
++ * we grab it far less frequently (in general) then the rgrp lock.
++ *
++ * Returns: errno
++ */
++
++int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
++{
++ struct gfs2_inode *dip = GFS2_I(sdp->sd_jindex);
++ struct qstr name;
++ char buf[20];
++ struct gfs2_jdesc *jd;
++ int error;
++
++ name.name = buf;
++
++ mutex_lock(&sdp->sd_jindex_mutex);
++
++ for (;;) {
++ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
++ GL_LOCAL_EXCL, ji_gh);
++ if (error)
++ break;
++
++ name.len = sprintf(buf, "journal%u", sdp->sd_journals);
++ name.hash = gfs2_disk_hash(name.name, name.len);
++
++ error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL);
++ if (error == -ENOENT) {
++ error = 0;
++ break;
++ }
++
++ gfs2_glock_dq_uninit(ji_gh);
++
++ if (error)
++ break;
++
++ error = -ENOMEM;
++ jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL);
++ if (!jd)
++ break;
++
++ jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
++ if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
++ if (!jd->jd_inode)
++ error = -ENOENT;
++ else
++ error = PTR_ERR(jd->jd_inode);
++ kfree(jd);
++ break;
++ }
++
++ spin_lock(&sdp->sd_jindex_spin);
++ jd->jd_jid = sdp->sd_journals++;
++ list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
++ spin_unlock(&sdp->sd_jindex_spin);
++ }
++
++ mutex_unlock(&sdp->sd_jindex_mutex);
++
++ return error;
++}
++
++/**
++ * gfs2_jindex_free - Clear all the journal index information
++ * @sdp: The GFS2 superblock
++ *
++ */
++
++void gfs2_jindex_free(struct gfs2_sbd *sdp)
++{
++ struct list_head list;
++ struct gfs2_jdesc *jd;
++
++ spin_lock(&sdp->sd_jindex_spin);
++ list_add(&list, &sdp->sd_jindex_list);
++ list_del_init(&sdp->sd_jindex_list);
++ sdp->sd_journals = 0;
++ spin_unlock(&sdp->sd_jindex_spin);
++
++ while (!list_empty(&list)) {
++ jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
++ list_del(&jd->jd_list);
++ iput(jd->jd_inode);
++ kfree(jd);
++ }
++}
++
++static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid)
++{
++ struct gfs2_jdesc *jd;
++ int found = 0;
++
++ list_for_each_entry(jd, head, jd_list) {
++ if (jd->jd_jid == jid) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found)
++ jd = NULL;
++
++ return jd;
++}
++
++struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid)
++{
++ struct gfs2_jdesc *jd;
++
++ spin_lock(&sdp->sd_jindex_spin);
++ jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
++ spin_unlock(&sdp->sd_jindex_spin);
++
++ return jd;
++}
++
++void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
++{
++ struct gfs2_jdesc *jd;
++
++ spin_lock(&sdp->sd_jindex_spin);
++ jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
++ if (jd)
++ jd->jd_dirty = 1;
++ spin_unlock(&sdp->sd_jindex_spin);
++}
++
++struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp)
++{
++ struct gfs2_jdesc *jd;
++ int found = 0;
++
++ spin_lock(&sdp->sd_jindex_spin);
++
++ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
++ if (jd->jd_dirty) {
++ jd->jd_dirty = 0;
++ found = 1;
++ break;
++ }
++ }
++ spin_unlock(&sdp->sd_jindex_spin);
++
++ if (!found)
++ jd = NULL;
++
++ return jd;
++}
++
++int gfs2_jdesc_check(struct gfs2_jdesc *jd)
++{
++ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
++ int ar;
++ int error;
++
++ if (ip->i_di.di_size < (8 << 20) || ip->i_di.di_size > (1 << 30) ||
++ (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) {
++ gfs2_consist_inode(ip);
++ return -EIO;
++ }
++ jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
++
++ error = gfs2_write_alloc_required(ip, 0, ip->i_di.di_size, &ar);
++ if (!error && ar) {
++ gfs2_consist_inode(ip);
++ error = -EIO;
++ }
++
++ return error;
++}
++
++/**
++ * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one
++ * @sdp: the filesystem
++ *
++ * Returns: errno
++ */
++
++int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
++{
++ struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
++ struct gfs2_glock *j_gl = ip->i_gl;
++ struct gfs2_holder t_gh;
++ struct gfs2_log_header head;
++ int error;
++
++ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
++ GL_LOCAL_EXCL, &t_gh);
++ if (error)
++ return error;
++
++ gfs2_meta_cache_flush(ip);
++ j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
++
++ error = gfs2_find_jhead(sdp->sd_jdesc, &head);
++ if (error)
++ goto fail;
++
++ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
++ gfs2_consist(sdp);
++ error = -EIO;
++ goto fail;
++ }
++
++ /* Initialize some head of the log stuff */
++ sdp->sd_log_sequence = head.lh_sequence + 1;
++ gfs2_log_pointers_init(sdp, head.lh_blkno);
++
++ error = gfs2_quota_init(sdp);
++ if (error)
++ goto fail;
++
++ set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
++
++ gfs2_glock_dq_uninit(&t_gh);
++
++ return 0;
++
++fail:
++ t_gh.gh_flags |= GL_NOCACHE;
++ gfs2_glock_dq_uninit(&t_gh);
++
++ return error;
++}
++
++/**
++ * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
++ * @sdp: the filesystem
++ *
++ * Returns: errno
++ */
++
++int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
++{
++ struct gfs2_holder t_gh;
++ int error;
++
++ gfs2_quota_sync(sdp);
++ gfs2_statfs_sync(sdp);
++
++ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
++ GL_LOCAL_EXCL | GL_NOCACHE,
++ &t_gh);
++ if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
++ return error;
++
++ gfs2_meta_syncfs(sdp);
++ gfs2_log_shutdown(sdp);
++
++ clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
++
++ if (t_gh.gh_gl)
++ gfs2_glock_dq_uninit(&t_gh);
++
++ gfs2_quota_cleanup(sdp);
++
++ return error;
++}
++
++int gfs2_statfs_init(struct gfs2_sbd *sdp)
++{
++ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
++ struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
++ struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
++ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
++ struct buffer_head *m_bh, *l_bh;
++ struct gfs2_holder gh;
++ int error;
++
++ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
++ &gh);
++ if (error)
++ return error;
++
++ error = gfs2_meta_inode_buffer(m_ip, &m_bh);
++ if (error)
++ goto out;
++
++ if (sdp->sd_args.ar_spectator) {
++ spin_lock(&sdp->sd_statfs_spin);
++ gfs2_statfs_change_in(m_sc, m_bh->b_data +
++ sizeof(struct gfs2_dinode));
++ spin_unlock(&sdp->sd_statfs_spin);
++ } else {
++ error = gfs2_meta_inode_buffer(l_ip, &l_bh);
++ if (error)
++ goto out_m_bh;
++
++ spin_lock(&sdp->sd_statfs_spin);
++ gfs2_statfs_change_in(m_sc, m_bh->b_data +
++ sizeof(struct gfs2_dinode));
++ gfs2_statfs_change_in(l_sc, l_bh->b_data +
++ sizeof(struct gfs2_dinode));
++ spin_unlock(&sdp->sd_statfs_spin);
++
++ brelse(l_bh);
++ }
++
++out_m_bh:
++ brelse(m_bh);
++out:
++ gfs2_glock_dq_uninit(&gh);
++ return 0;
++}
++
++void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
++ s64 dinodes)
++{
++ struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
++ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
++ struct buffer_head *l_bh;
++ int error;
++
++ error = gfs2_meta_inode_buffer(l_ip, &l_bh);
++ if (error)
++ return;
++
++ mutex_lock(&sdp->sd_statfs_mutex);
++ gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
++ mutex_unlock(&sdp->sd_statfs_mutex);
++
++ spin_lock(&sdp->sd_statfs_spin);
++ l_sc->sc_total += total;
++ l_sc->sc_free += free;
++ l_sc->sc_dinodes += dinodes;
++ gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode));
++ spin_unlock(&sdp->sd_statfs_spin);
++
++ brelse(l_bh);
++}
++
++int gfs2_statfs_sync(struct gfs2_sbd *sdp)
++{
++ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
++ struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
++ struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
++ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
++ struct gfs2_holder gh;
++ struct buffer_head *m_bh, *l_bh;
++ int error;
++
++ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
++ &gh);
++ if (error)
++ return error;
++
++ error = gfs2_meta_inode_buffer(m_ip, &m_bh);
++ if (error)
++ goto out;
++
++ spin_lock(&sdp->sd_statfs_spin);
++ gfs2_statfs_change_in(m_sc, m_bh->b_data +
++ sizeof(struct gfs2_dinode));
++ if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) {
++ spin_unlock(&sdp->sd_statfs_spin);
++ goto out_bh;
++ }
++ spin_unlock(&sdp->sd_statfs_spin);
++
++ error = gfs2_meta_inode_buffer(l_ip, &l_bh);
++ if (error)
++ goto out_bh;
++
++ error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
++ if (error)
++ goto out_bh2;
++
++ mutex_lock(&sdp->sd_statfs_mutex);
++ gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
++ mutex_unlock(&sdp->sd_statfs_mutex);
++
++ spin_lock(&sdp->sd_statfs_spin);
++ m_sc->sc_total += l_sc->sc_total;
++ m_sc->sc_free += l_sc->sc_free;
++ m_sc->sc_dinodes += l_sc->sc_dinodes;
++ memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
++ memset(l_bh->b_data + sizeof(struct gfs2_dinode),
++ 0, sizeof(struct gfs2_statfs_change));
++ spin_unlock(&sdp->sd_statfs_spin);
++
++ gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
++ gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
++
++ gfs2_trans_end(sdp);
++
++out_bh2:
++ brelse(l_bh);
++out_bh:
++ brelse(m_bh);
++out:
++ gfs2_glock_dq_uninit(&gh);
++ return error;
++}
++
++/**
++ * gfs2_statfs_i - Do a statfs
++ * @sdp: the filesystem
++ * @sg: the sg structure
++ *
++ * Returns: errno
++ */
++
++int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
++{
++ struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
++ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
++
++ spin_lock(&sdp->sd_statfs_spin);
++
++ *sc = *m_sc;
++ sc->sc_total += l_sc->sc_total;
++ sc->sc_free += l_sc->sc_free;
++ sc->sc_dinodes += l_sc->sc_dinodes;
++
++ spin_unlock(&sdp->sd_statfs_spin);
++
++ if (sc->sc_free < 0)
++ sc->sc_free = 0;
++ if (sc->sc_free > sc->sc_total)
++ sc->sc_free = sc->sc_total;
++ if (sc->sc_dinodes < 0)
++ sc->sc_dinodes = 0;
++
++ return 0;
++}
++
++/**
++ * statfs_fill - fill in the sg for a given RG
++ * @rgd: the RG
++ * @sc: the sc structure
++ *
++ * Returns: 0 on success, -ESTALE if the LVB is invalid
++ */
++
++static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
++ struct gfs2_statfs_change *sc)
++{
++ gfs2_rgrp_verify(rgd);
++ sc->sc_total += rgd->rd_ri.ri_data;
++ sc->sc_free += rgd->rd_rg.rg_free;
++ sc->sc_dinodes += rgd->rd_rg.rg_dinodes;
++ return 0;
++}
++
++/**
++ * gfs2_statfs_slow - Stat a filesystem using asynchronous locking
++ * @sdp: the filesystem
++ * @sc: the sc info that will be returned
++ *
++ * Any error (other than a signal) will cause this routine to fall back
++ * to the synchronous version.
++ *
++ * FIXME: This really shouldn't busy wait like this.
++ *
++ * Returns: errno
++ */
++
++int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
++{
++ struct gfs2_holder ri_gh;
++ struct gfs2_rgrpd *rgd_next;
++ struct gfs2_holder *gha, *gh;
++ unsigned int slots = 64;
++ unsigned int x;
++ int done;
++ int error = 0, err;
++
++ memset(sc, 0, sizeof(struct gfs2_statfs_change));
++ gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL);
++ if (!gha)
++ return -ENOMEM;
++
++ error = gfs2_rindex_hold(sdp, &ri_gh);
++ if (error)
++ goto out;
++
++ rgd_next = gfs2_rgrpd_get_first(sdp);
++
++ for (;;) {
++ done = 1;
++
++ for (x = 0; x < slots; x++) {
++ gh = gha + x;
++
++ if (gh->gh_gl && gfs2_glock_poll(gh)) {
++ err = gfs2_glock_wait(gh);
++ if (err) {
++ gfs2_holder_uninit(gh);
++ error = err;
++ } else {
++ if (!error)
++ error = statfs_slow_fill(
++ gh->gh_gl->gl_object, sc);
++ gfs2_glock_dq_uninit(gh);
++ }
++ }
++
++ if (gh->gh_gl)
++ done = 0;
++ else if (rgd_next && !error) {
++ error = gfs2_glock_nq_init(rgd_next->rd_gl,
++ LM_ST_SHARED,
++ GL_ASYNC,
++ gh);
++ rgd_next = gfs2_rgrpd_get_next(rgd_next);
++ done = 0;
++ }
++
++ if (signal_pending(current))
++ error = -ERESTARTSYS;
++ }
++
++ if (done)
++ break;
++
++ yield();
++ }
++
++ gfs2_glock_dq_uninit(&ri_gh);
++
++out:
++ kfree(gha);
++ return error;
++}
++
++struct lfcc {
++ struct list_head list;
++ struct gfs2_holder gh;
++};
++
++/**
++ * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all
++ * journals are clean
++ * @sdp: the file system
++ * @state: the state to put the transaction lock into
++ * @t_gh: the hold on the transaction lock
++ *
++ * Returns: errno
++ */
++
++static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
++ struct gfs2_holder *t_gh)
++{
++ struct gfs2_inode *ip;
++ struct gfs2_holder ji_gh;
++ struct gfs2_jdesc *jd;
++ struct lfcc *lfcc;
++ LIST_HEAD(list);
++ struct gfs2_log_header lh;
++ int error;
++
++ error = gfs2_jindex_hold(sdp, &ji_gh);
++ if (error)
++ return error;
++
++ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
++ lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
++ if (!lfcc) {
++ error = -ENOMEM;
++ goto out;
++ }
++ ip = GFS2_I(jd->jd_inode);
++ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &lfcc->gh);
++ if (error) {
++ kfree(lfcc);
++ goto out;
++ }
++ list_add(&lfcc->list, &list);
++ }
++
++ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED,
++ LM_FLAG_PRIORITY | GL_NOCACHE,
++ t_gh);
++
++ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
++ error = gfs2_jdesc_check(jd);
++ if (error)
++ break;
++ error = gfs2_find_jhead(jd, &lh);
++ if (error)
++ break;
++ if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
++ error = -EBUSY;
++ break;
++ }
++ }
++
++ if (error)
++ gfs2_glock_dq_uninit(t_gh);
++
++out:
++ while (!list_empty(&list)) {
++ lfcc = list_entry(list.next, struct lfcc, list);
++ list_del(&lfcc->list);
++ gfs2_glock_dq_uninit(&lfcc->gh);
++ kfree(lfcc);
++ }
++ gfs2_glock_dq_uninit(&ji_gh);
++ return error;
++}
++
++/**
++ * gfs2_freeze_fs - freezes the file system
++ * @sdp: the file system
++ *
++ * This function flushes data and meta data for all machines by
++ * aquiring the transaction log exclusively. All journals are
++ * ensured to be in a clean state as well.
++ *
++ * Returns: errno
++ */
++
++int gfs2_freeze_fs(struct gfs2_sbd *sdp)
++{
++ int error = 0;
++
++ mutex_lock(&sdp->sd_freeze_lock);
++
++ if (!sdp->sd_freeze_count++) {
++ error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
++ if (error)
++ sdp->sd_freeze_count--;
++ }
++
++ mutex_unlock(&sdp->sd_freeze_lock);
++
++ return error;
++}
++
++/**
++ * gfs2_unfreeze_fs - unfreezes the file system
++ * @sdp: the file system
++ *
++ * This function allows the file system to proceed by unlocking
++ * the exclusively held transaction lock. Other GFS2 nodes are
++ * now free to acquire the lock shared and go on with their lives.
++ *
++ */
++
++void gfs2_unfreeze_fs(struct gfs2_sbd *sdp)
++{
++ mutex_lock(&sdp->sd_freeze_lock);
++
++ if (sdp->sd_freeze_count && !--sdp->sd_freeze_count)
++ gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
++
++ mutex_unlock(&sdp->sd_freeze_lock);
++}
++
+diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
+new file mode 100644
+index 0000000..5bb443a
+--- /dev/null
++++ b/fs/gfs2/super.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __SUPER_DOT_H__
++#define __SUPER_DOT_H__
++
++#include "incore.h"
++
++void gfs2_tune_init(struct gfs2_tune *gt);
++
++int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent);
++int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent);
++struct page *gfs2_read_super(struct super_block *sb, sector_t sector);
++
++static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
++{
++ unsigned int x;
++ spin_lock(&sdp->sd_jindex_spin);
++ x = sdp->sd_journals;
++ spin_unlock(&sdp->sd_jindex_spin);
++ return x;
++}
++
++int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh);
++void gfs2_jindex_free(struct gfs2_sbd *sdp);
++
++struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
++void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid);
++struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp);
++int gfs2_jdesc_check(struct gfs2_jdesc *jd);
++
++int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
++ struct gfs2_inode **ipp);
++
++int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
++int gfs2_make_fs_ro(struct gfs2_sbd *sdp);
++
++int gfs2_statfs_init(struct gfs2_sbd *sdp);
++void gfs2_statfs_change(struct gfs2_sbd *sdp,
++ s64 total, s64 free, s64 dinodes);
++int gfs2_statfs_sync(struct gfs2_sbd *sdp);
++int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc);
++int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc);
++
++int gfs2_freeze_fs(struct gfs2_sbd *sdp);
++void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
++
++#endif /* __SUPER_DOT_H__ */
++
+diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
+new file mode 100644
+index 0000000..0e0ec98
+--- /dev/null
++++ b/fs/gfs2/sys.c
+@@ -0,0 +1,583 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/module.h>
++#include <linux/kobject.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "lm.h"
++#include "sys.h"
++#include "super.h"
++#include "glock.h"
++#include "quota.h"
++#include "util.h"
++
++char *gfs2_sys_margs;
++spinlock_t gfs2_sys_margs_lock;
++
++static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id);
++}
++
++static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname);
++}
++
++static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
++{
++ unsigned int count;
++
++ mutex_lock(&sdp->sd_freeze_lock);
++ count = sdp->sd_freeze_count;
++ mutex_unlock(&sdp->sd_freeze_lock);
++
++ return snprintf(buf, PAGE_SIZE, "%u\n", count);
++}
++
++static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
++{
++ ssize_t ret = len;
++ int error = 0;
++ int n = simple_strtol(buf, NULL, 0);
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ switch (n) {
++ case 0:
++ gfs2_unfreeze_fs(sdp);
++ break;
++ case 1:
++ error = gfs2_freeze_fs(sdp);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++
++ if (error)
++ fs_warn(sdp, "freeze %d error %d", n, error);
++
++ return ret;
++}
++
++static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
++{
++ unsigned int b = test_bit(SDF_SHUTDOWN, &sdp->sd_flags);
++ return snprintf(buf, PAGE_SIZE, "%u\n", b);
++}
++
++static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
++{
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ if (simple_strtol(buf, NULL, 0) != 1)
++ return -EINVAL;
++
++ gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: withdrawing from cluster at user's request\n",
++ sdp->sd_fsname);
++ return len;
++}
++
++static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
++ size_t len)
++{
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ if (simple_strtol(buf, NULL, 0) != 1)
++ return -EINVAL;
++
++ gfs2_statfs_sync(sdp);
++ return len;
++}
++
++static ssize_t shrink_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
++{
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ if (simple_strtol(buf, NULL, 0) != 1)
++ return -EINVAL;
++
++ gfs2_gl_hash_clear(sdp, NO_WAIT);
++ return len;
++}
++
++static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
++ size_t len)
++{
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ if (simple_strtol(buf, NULL, 0) != 1)
++ return -EINVAL;
++
++ gfs2_quota_sync(sdp);
++ return len;
++}
++
++static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
++ size_t len)
++{
++ u32 id;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ id = simple_strtoul(buf, NULL, 0);
++
++ gfs2_quota_refresh(sdp, 1, id);
++ return len;
++}
++
++static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
++ size_t len)
++{
++ u32 id;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ id = simple_strtoul(buf, NULL, 0);
++
++ gfs2_quota_refresh(sdp, 0, id);
++ return len;
++}
++
++struct gfs2_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct gfs2_sbd *, char *);
++ ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
++};
++
++#define GFS2_ATTR(name, mode, show, store) \
++static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store)
++
++GFS2_ATTR(id, 0444, id_show, NULL);
++GFS2_ATTR(fsname, 0444, fsname_show, NULL);
++GFS2_ATTR(freeze, 0644, freeze_show, freeze_store);
++GFS2_ATTR(shrink, 0200, NULL, shrink_store);
++GFS2_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
++GFS2_ATTR(statfs_sync, 0200, NULL, statfs_sync_store);
++GFS2_ATTR(quota_sync, 0200, NULL, quota_sync_store);
++GFS2_ATTR(quota_refresh_user, 0200, NULL, quota_refresh_user_store);
++GFS2_ATTR(quota_refresh_group, 0200, NULL, quota_refresh_group_store);
++
++static struct attribute *gfs2_attrs[] = {
++ &gfs2_attr_id.attr,
++ &gfs2_attr_fsname.attr,
++ &gfs2_attr_freeze.attr,
++ &gfs2_attr_shrink.attr,
++ &gfs2_attr_withdraw.attr,
++ &gfs2_attr_statfs_sync.attr,
++ &gfs2_attr_quota_sync.attr,
++ &gfs2_attr_quota_refresh_user.attr,
++ &gfs2_attr_quota_refresh_group.attr,
++ NULL,
++};
++
++static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
++ struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
++ return a->show ? a->show(sdp, buf) : 0;
++}
++
++static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr,
++ const char *buf, size_t len)
++{
++ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
++ struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
++ return a->store ? a->store(sdp, buf, len) : len;
++}
++
++static struct sysfs_ops gfs2_attr_ops = {
++ .show = gfs2_attr_show,
++ .store = gfs2_attr_store,
++};
++
++static struct kobj_type gfs2_ktype = {
++ .default_attrs = gfs2_attrs,
++ .sysfs_ops = &gfs2_attr_ops,
++};
++
++static struct kset gfs2_kset = {
++ .subsys = &fs_subsys,
++ .kobj = {.name = "gfs2"},
++ .ktype = &gfs2_ktype,
++};
++
++/*
++ * display struct lm_lockstruct fields
++ */
++
++struct lockstruct_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct gfs2_sbd *, char *);
++};
++
++#define LOCKSTRUCT_ATTR(name, fmt) \
++static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
++{ \
++ return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_lockstruct.ls_##name); \
++} \
++static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name)
++
++LOCKSTRUCT_ATTR(jid, "%u\n");
++LOCKSTRUCT_ATTR(first, "%u\n");
++LOCKSTRUCT_ATTR(lvb_size, "%u\n");
++LOCKSTRUCT_ATTR(flags, "%d\n");
++
++static struct attribute *lockstruct_attrs[] = {
++ &lockstruct_attr_jid.attr,
++ &lockstruct_attr_first.attr,
++ &lockstruct_attr_lvb_size.attr,
++ &lockstruct_attr_flags.attr,
++ NULL,
++};
++
++/*
++ * display struct gfs2_args fields
++ */
++
++struct args_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct gfs2_sbd *, char *);
++};
++
++#define ARGS_ATTR(name, fmt) \
++static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
++{ \
++ return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_args.ar_##name); \
++} \
++static struct args_attr args_attr_##name = __ATTR_RO(name)
++
++ARGS_ATTR(lockproto, "%s\n");
++ARGS_ATTR(locktable, "%s\n");
++ARGS_ATTR(hostdata, "%s\n");
++ARGS_ATTR(spectator, "%d\n");
++ARGS_ATTR(ignore_local_fs, "%d\n");
++ARGS_ATTR(localcaching, "%d\n");
++ARGS_ATTR(localflocks, "%d\n");
++ARGS_ATTR(debug, "%d\n");
++ARGS_ATTR(upgrade, "%d\n");
++ARGS_ATTR(num_glockd, "%u\n");
++ARGS_ATTR(posix_acl, "%d\n");
++ARGS_ATTR(quota, "%u\n");
++ARGS_ATTR(suiddir, "%d\n");
++ARGS_ATTR(data, "%d\n");
++
++/* one oddball doesn't fit the macro mold */
++static ssize_t noatime_show(struct gfs2_sbd *sdp, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n",
++ !!test_bit(SDF_NOATIME, &sdp->sd_flags));
++}
++static struct args_attr args_attr_noatime = __ATTR_RO(noatime);
++
++static struct attribute *args_attrs[] = {
++ &args_attr_lockproto.attr,
++ &args_attr_locktable.attr,
++ &args_attr_hostdata.attr,
++ &args_attr_spectator.attr,
++ &args_attr_ignore_local_fs.attr,
++ &args_attr_localcaching.attr,
++ &args_attr_localflocks.attr,
++ &args_attr_debug.attr,
++ &args_attr_upgrade.attr,
++ &args_attr_num_glockd.attr,
++ &args_attr_posix_acl.attr,
++ &args_attr_quota.attr,
++ &args_attr_suiddir.attr,
++ &args_attr_data.attr,
++ &args_attr_noatime.attr,
++ NULL,
++};
++
++/*
++ * display counters from superblock
++ */
++
++struct counters_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct gfs2_sbd *, char *);
++};
++
++#define COUNTERS_ATTR(name, fmt) \
++static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
++{ \
++ return snprintf(buf, PAGE_SIZE, fmt, \
++ (unsigned int)atomic_read(&sdp->sd_##name)); \
++} \
++static struct counters_attr counters_attr_##name = __ATTR_RO(name)
++
++COUNTERS_ATTR(glock_count, "%u\n");
++COUNTERS_ATTR(glock_held_count, "%u\n");
++COUNTERS_ATTR(inode_count, "%u\n");
++COUNTERS_ATTR(reclaimed, "%u\n");
++
++static struct attribute *counters_attrs[] = {
++ &counters_attr_glock_count.attr,
++ &counters_attr_glock_held_count.attr,
++ &counters_attr_inode_count.attr,
++ &counters_attr_reclaimed.attr,
++ NULL,
++};
++
++/*
++ * get and set struct gfs2_tune fields
++ */
++
++static ssize_t quota_scale_show(struct gfs2_sbd *sdp, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%u %u\n",
++ sdp->sd_tune.gt_quota_scale_num,
++ sdp->sd_tune.gt_quota_scale_den);
++}
++
++static ssize_t quota_scale_store(struct gfs2_sbd *sdp, const char *buf,
++ size_t len)
++{
++ struct gfs2_tune *gt = &sdp->sd_tune;
++ unsigned int x, y;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ if (sscanf(buf, "%u %u", &x, &y) != 2 || !y)
++ return -EINVAL;
++
++ spin_lock(>->gt_spin);
++ gt->gt_quota_scale_num = x;
++ gt->gt_quota_scale_den = y;
++ spin_unlock(>->gt_spin);
++ return len;
++}
++
++static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,
++ int check_zero, const char *buf, size_t len)
++{
++ struct gfs2_tune *gt = &sdp->sd_tune;
++ unsigned int x;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ x = simple_strtoul(buf, NULL, 0);
++
++ if (check_zero && !x)
++ return -EINVAL;
++
++ spin_lock(>->gt_spin);
++ *field = x;
++ spin_unlock(>->gt_spin);
++ return len;
++}
++
++struct tune_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct gfs2_sbd *, char *);
++ ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
++};
++
++#define TUNE_ATTR_3(name, show, store) \
++static struct tune_attr tune_attr_##name = __ATTR(name, 0644, show, store)
++
++#define TUNE_ATTR_2(name, store) \
++static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
++{ \
++ return snprintf(buf, PAGE_SIZE, "%u\n", sdp->sd_tune.gt_##name); \
++} \
++TUNE_ATTR_3(name, name##_show, store)
++
++#define TUNE_ATTR(name, check_zero) \
++static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
++{ \
++ return tune_set(sdp, &sdp->sd_tune.gt_##name, check_zero, buf, len); \
++} \
++TUNE_ATTR_2(name, name##_store)
++
++#define TUNE_ATTR_DAEMON(name, process) \
++static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
++{ \
++ ssize_t r = tune_set(sdp, &sdp->sd_tune.gt_##name, 1, buf, len); \
++ wake_up_process(sdp->sd_##process); \
++ return r; \
++} \
++TUNE_ATTR_2(name, name##_store)
++
++TUNE_ATTR(ilimit, 0);
++TUNE_ATTR(ilimit_tries, 0);
++TUNE_ATTR(ilimit_min, 0);
++TUNE_ATTR(demote_secs, 0);
++TUNE_ATTR(incore_log_blocks, 0);
++TUNE_ATTR(log_flush_secs, 0);
++TUNE_ATTR(jindex_refresh_secs, 0);
++TUNE_ATTR(quota_warn_period, 0);
++TUNE_ATTR(quota_quantum, 0);
++TUNE_ATTR(atime_quantum, 0);
++TUNE_ATTR(max_readahead, 0);
++TUNE_ATTR(complain_secs, 0);
++TUNE_ATTR(reclaim_limit, 0);
++TUNE_ATTR(prefetch_secs, 0);
++TUNE_ATTR(statfs_slow, 0);
++TUNE_ATTR(new_files_jdata, 0);
++TUNE_ATTR(new_files_directio, 0);
++TUNE_ATTR(quota_simul_sync, 1);
++TUNE_ATTR(quota_cache_secs, 1);
++TUNE_ATTR(max_atomic_write, 1);
++TUNE_ATTR(stall_secs, 1);
++TUNE_ATTR(entries_per_readdir, 1);
++TUNE_ATTR(greedy_default, 1);
++TUNE_ATTR(greedy_quantum, 1);
++TUNE_ATTR(greedy_max, 1);
++TUNE_ATTR(statfs_quantum, 1);
++TUNE_ATTR_DAEMON(scand_secs, scand_process);
++TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
++TUNE_ATTR_DAEMON(logd_secs, logd_process);
++TUNE_ATTR_DAEMON(quotad_secs, quotad_process);
++TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
++
++static struct attribute *tune_attrs[] = {
++ &tune_attr_ilimit.attr,
++ &tune_attr_ilimit_tries.attr,
++ &tune_attr_ilimit_min.attr,
++ &tune_attr_demote_secs.attr,
++ &tune_attr_incore_log_blocks.attr,
++ &tune_attr_log_flush_secs.attr,
++ &tune_attr_jindex_refresh_secs.attr,
++ &tune_attr_quota_warn_period.attr,
++ &tune_attr_quota_quantum.attr,
++ &tune_attr_atime_quantum.attr,
++ &tune_attr_max_readahead.attr,
++ &tune_attr_complain_secs.attr,
++ &tune_attr_reclaim_limit.attr,
++ &tune_attr_prefetch_secs.attr,
++ &tune_attr_statfs_slow.attr,
++ &tune_attr_quota_simul_sync.attr,
++ &tune_attr_quota_cache_secs.attr,
++ &tune_attr_max_atomic_write.attr,
++ &tune_attr_stall_secs.attr,
++ &tune_attr_entries_per_readdir.attr,
++ &tune_attr_greedy_default.attr,
++ &tune_attr_greedy_quantum.attr,
++ &tune_attr_greedy_max.attr,
++ &tune_attr_statfs_quantum.attr,
++ &tune_attr_scand_secs.attr,
++ &tune_attr_recoverd_secs.attr,
++ &tune_attr_logd_secs.attr,
++ &tune_attr_quotad_secs.attr,
++ &tune_attr_quota_scale.attr,
++ &tune_attr_new_files_jdata.attr,
++ &tune_attr_new_files_directio.attr,
++ NULL,
++};
++
++static struct attribute_group lockstruct_group = {
++ .name = "lockstruct",
++ .attrs = lockstruct_attrs,
++};
++
++static struct attribute_group counters_group = {
++ .name = "counters",
++ .attrs = counters_attrs,
++};
++
++static struct attribute_group args_group = {
++ .name = "args",
++ .attrs = args_attrs,
++};
++
++static struct attribute_group tune_group = {
++ .name = "tune",
++ .attrs = tune_attrs,
++};
++
++int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
++{
++ int error;
++
++ sdp->sd_kobj.kset = &gfs2_kset;
++ sdp->sd_kobj.ktype = &gfs2_ktype;
++
++ error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
++ if (error)
++ goto fail;
++
++ error = kobject_register(&sdp->sd_kobj);
++ if (error)
++ goto fail;
++
++ error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group);
++ if (error)
++ goto fail_reg;
++
++ error = sysfs_create_group(&sdp->sd_kobj, &counters_group);
++ if (error)
++ goto fail_lockstruct;
++
++ error = sysfs_create_group(&sdp->sd_kobj, &args_group);
++ if (error)
++ goto fail_counters;
++
++ error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
++ if (error)
++ goto fail_args;
++
++ return 0;
++
++fail_args:
++ sysfs_remove_group(&sdp->sd_kobj, &args_group);
++fail_counters:
++ sysfs_remove_group(&sdp->sd_kobj, &counters_group);
++fail_lockstruct:
++ sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
++fail_reg:
++ kobject_unregister(&sdp->sd_kobj);
++fail:
++ fs_err(sdp, "error %d adding sysfs files", error);
++ return error;
++}
++
++void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
++{
++ sysfs_remove_group(&sdp->sd_kobj, &tune_group);
++ sysfs_remove_group(&sdp->sd_kobj, &args_group);
++ sysfs_remove_group(&sdp->sd_kobj, &counters_group);
++ sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
++ kobject_unregister(&sdp->sd_kobj);
++}
++
++int gfs2_sys_init(void)
++{
++ gfs2_sys_margs = NULL;
++ spin_lock_init(&gfs2_sys_margs_lock);
++ return kset_register(&gfs2_kset);
++}
++
++void gfs2_sys_uninit(void)
++{
++ kfree(gfs2_sys_margs);
++ kset_unregister(&gfs2_kset);
++}
++
+diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h
+new file mode 100644
+index 0000000..1ca8cda
+--- /dev/null
++++ b/fs/gfs2/sys.h
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __SYS_DOT_H__
++#define __SYS_DOT_H__
++
++#include <linux/spinlock.h>
++struct gfs2_sbd;
++
++/* Allow args to be passed to GFS2 when using an initial ram disk */
++extern char *gfs2_sys_margs;
++extern spinlock_t gfs2_sys_margs_lock;
++
++int gfs2_sys_fs_add(struct gfs2_sbd *sdp);
++void gfs2_sys_fs_del(struct gfs2_sbd *sdp);
++
++int gfs2_sys_init(void);
++void gfs2_sys_uninit(void);
++
++#endif /* __SYS_DOT_H__ */
++
+diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
+new file mode 100644
+index 0000000..f8dabf8
+--- /dev/null
++++ b/fs/gfs2/trans.c
+@@ -0,0 +1,184 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/kallsyms.h>
++#include <linux/lm_interface.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "log.h"
++#include "lops.h"
++#include "meta_io.h"
++#include "trans.h"
++#include "util.h"
++
++int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
++ unsigned int revokes)
++{
++ struct gfs2_trans *tr;
++ int error;
++
++ BUG_ON(current->journal_info);
++ BUG_ON(blocks == 0 && revokes == 0);
++
++ tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS);
++ if (!tr)
++ return -ENOMEM;
++
++ tr->tr_ip = (unsigned long)__builtin_return_address(0);
++ tr->tr_blocks = blocks;
++ tr->tr_revokes = revokes;
++ tr->tr_reserved = 1;
++ if (blocks)
++ tr->tr_reserved += 6 + blocks;
++ if (revokes)
++ tr->tr_reserved += gfs2_struct2blk(sdp, revokes,
++ sizeof(u64));
++ INIT_LIST_HEAD(&tr->tr_list_buf);
++
++ gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &tr->tr_t_gh);
++
++ error = gfs2_glock_nq(&tr->tr_t_gh);
++ if (error)
++ goto fail_holder_uninit;
++
++ if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
++ tr->tr_t_gh.gh_flags |= GL_NOCACHE;
++ error = -EROFS;
++ goto fail_gunlock;
++ }
++
++ error = gfs2_log_reserve(sdp, tr->tr_reserved);
++ if (error)
++ goto fail_gunlock;
++
++ current->journal_info = tr;
++
++ return 0;
++
++fail_gunlock:
++ gfs2_glock_dq(&tr->tr_t_gh);
++
++fail_holder_uninit:
++ gfs2_holder_uninit(&tr->tr_t_gh);
++ kfree(tr);
++
++ return error;
++}
++
++void gfs2_trans_end(struct gfs2_sbd *sdp)
++{
++ struct gfs2_trans *tr = current->journal_info;
++
++ BUG_ON(!tr);
++ current->journal_info = NULL;
++
++ if (!tr->tr_touched) {
++ gfs2_log_release(sdp, tr->tr_reserved);
++ gfs2_glock_dq(&tr->tr_t_gh);
++ gfs2_holder_uninit(&tr->tr_t_gh);
++ kfree(tr);
++ return;
++ }
++
++ if (gfs2_assert_withdraw(sdp, tr->tr_num_buf <= tr->tr_blocks)) {
++ fs_err(sdp, "tr_num_buf = %u, tr_blocks = %u ",
++ tr->tr_num_buf, tr->tr_blocks);
++ print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
++ }
++ if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) {
++ fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u ",
++ tr->tr_num_revoke, tr->tr_revokes);
++ print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
++ }
++
++ gfs2_log_commit(sdp, tr);
++ gfs2_glock_dq(&tr->tr_t_gh);
++ gfs2_holder_uninit(&tr->tr_t_gh);
++ kfree(tr);
++
++ if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
++ gfs2_log_flush(sdp, NULL);
++}
++
++void gfs2_trans_add_gl(struct gfs2_glock *gl)
++{
++ lops_add(gl->gl_sbd, &gl->gl_le);
++}
++
++/**
++ * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction
++ * @gl: the glock the buffer belongs to
++ * @bh: The buffer to add
++ * @meta: True in the case of adding metadata
++ *
++ */
++
++void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)
++{
++ struct gfs2_sbd *sdp = gl->gl_sbd;
++ struct gfs2_bufdata *bd;
++
++ bd = bh->b_private;
++ if (bd)
++ gfs2_assert(sdp, bd->bd_gl == gl);
++ else {
++ gfs2_attach_bufdata(gl, bh, meta);
++ bd = bh->b_private;
++ }
++ lops_add(sdp, &bd->bd_le);
++}
++
++void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno)
++{
++ struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke),
++ GFP_NOFS | __GFP_NOFAIL);
++ lops_init_le(&rv->rv_le, &gfs2_revoke_lops);
++ rv->rv_blkno = blkno;
++ lops_add(sdp, &rv->rv_le);
++}
++
++void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
++{
++ struct gfs2_revoke *rv;
++ int found = 0;
++
++ gfs2_log_lock(sdp);
++
++ list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) {
++ if (rv->rv_blkno == blkno) {
++ list_del(&rv->rv_le.le_list);
++ gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
++ sdp->sd_log_num_revoke--;
++ found = 1;
++ break;
++ }
++ }
++
++ gfs2_log_unlock(sdp);
++
++ if (found) {
++ struct gfs2_trans *tr = current->journal_info;
++ kfree(rv);
++ tr->tr_num_revoke_rm++;
++ }
++}
++
++void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
++{
++ lops_add(rgd->rd_sbd, &rgd->rd_le);
++}
++
+diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
+new file mode 100644
+index 0000000..23d4cbe
+--- /dev/null
++++ b/fs/gfs2/trans.h
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __TRANS_DOT_H__
++#define __TRANS_DOT_H__
++
++#include <linux/buffer_head.h>
++struct gfs2_sbd;
++struct gfs2_rgrpd;
++struct gfs2_glock;
++
++#define RES_DINODE 1
++#define RES_INDIRECT 1
++#define RES_JDATA 1
++#define RES_DATA 1
++#define RES_LEAF 1
++#define RES_RG_BIT 2
++#define RES_EATTR 1
++#define RES_STATFS 1
++#define RES_QUOTA 2
++
++int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
++ unsigned int revokes);
++
++void gfs2_trans_end(struct gfs2_sbd *sdp);
++
++void gfs2_trans_add_gl(struct gfs2_glock *gl);
++void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
++void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno);
++void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
++void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
++
++#endif /* __TRANS_DOT_H__ */
+diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
+new file mode 100644
+index 0000000..196c604
+--- /dev/null
++++ b/fs/gfs2/util.c
+@@ -0,0 +1,245 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/completion.h>
++#include <linux/buffer_head.h>
++#include <linux/crc32.h>
++#include <linux/gfs2_ondisk.h>
++#include <linux/lm_interface.h>
++#include <asm/uaccess.h>
++
++#include "gfs2.h"
++#include "incore.h"
++#include "glock.h"
++#include "lm.h"
++#include "util.h"
++
++kmem_cache_t *gfs2_glock_cachep __read_mostly;
++kmem_cache_t *gfs2_inode_cachep __read_mostly;
++kmem_cache_t *gfs2_bufdata_cachep __read_mostly;
++
++void gfs2_assert_i(struct gfs2_sbd *sdp)
++{
++ printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n",
++ sdp->sd_fsname);
++}
++
++/**
++ * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false
++ * Returns: -1 if this call withdrew the machine,
++ * -2 if it was already withdrawn
++ */
++
++int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
++ const char *function, char *file, unsigned int line)
++{
++ int me;
++ me = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: assertion \"%s\" failed\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname, assertion,
++ sdp->sd_fsname, function, file, line);
++ dump_stack();
++ return (me) ? -1 : -2;
++}
++
++/**
++ * gfs2_assert_warn_i - Print a message to the console if @assertion is false
++ * Returns: -1 if we printed something
++ * -2 if we didn't
++ */
++
++int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
++ const char *function, char *file, unsigned int line)
++{
++ if (time_before(jiffies,
++ sdp->sd_last_warning +
++ gfs2_tune_get(sdp, gt_complain_secs) * HZ))
++ return -2;
++
++ printk(KERN_WARNING
++ "GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname, assertion,
++ sdp->sd_fsname, function, file, line);
++
++ if (sdp->sd_args.ar_debug)
++ BUG();
++ else
++ dump_stack();
++
++ sdp->sd_last_warning = jiffies;
++
++ return -1;
++}
++
++/**
++ * gfs2_consist_i - Flag a filesystem consistency error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * 0 if it was already withdrawn
++ */
++
++int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, const char *function,
++ char *file, unsigned int line)
++{
++ int rv;
++ rv = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: filesystem consistency error\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, function, file, line);
++ return rv;
++}
++
++/**
++ * gfs2_consist_inode_i - Flag an inode consistency error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * 0 if it was already withdrawn
++ */
++
++int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
++ const char *function, char *file, unsigned int line)
++{
++ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++ int rv;
++ rv = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: filesystem consistency error\n"
++ "GFS2: fsid=%s: inode = %llu %llu\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, (unsigned long long)ip->i_num.no_formal_ino,
++ (unsigned long long)ip->i_num.no_addr,
++ sdp->sd_fsname, function, file, line);
++ return rv;
++}
++
++/**
++ * gfs2_consist_rgrpd_i - Flag a RG consistency error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * 0 if it was already withdrawn
++ */
++
++int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
++ const char *function, char *file, unsigned int line)
++{
++ struct gfs2_sbd *sdp = rgd->rd_sbd;
++ int rv;
++ rv = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: filesystem consistency error\n"
++ "GFS2: fsid=%s: RG = %llu\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, (unsigned long long)rgd->rd_ri.ri_addr,
++ sdp->sd_fsname, function, file, line);
++ return rv;
++}
++
++/**
++ * gfs2_meta_check_ii - Flag a magic number consistency error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * -2 if it was already withdrawn
++ */
++
++int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ const char *type, const char *function, char *file,
++ unsigned int line)
++{
++ int me;
++ me = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: invalid metadata block\n"
++ "GFS2: fsid=%s: bh = %llu (%s)\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type,
++ sdp->sd_fsname, function, file, line);
++ return (me) ? -1 : -2;
++}
++
++/**
++ * gfs2_metatype_check_ii - Flag a metadata type consistency error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * -2 if it was already withdrawn
++ */
++
++int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ u16 type, u16 t, const char *function,
++ char *file, unsigned int line)
++{
++ int me;
++ me = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: invalid metadata block\n"
++ "GFS2: fsid=%s: bh = %llu (type: exp=%u, found=%u)\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type, t,
++ sdp->sd_fsname, function, file, line);
++ return (me) ? -1 : -2;
++}
++
++/**
++ * gfs2_io_error_i - Flag an I/O error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * 0 if it was already withdrawn
++ */
++
++int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file,
++ unsigned int line)
++{
++ int rv;
++ rv = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: I/O error\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, function, file, line);
++ return rv;
++}
++
++/**
++ * gfs2_io_error_bh_i - Flag a buffer I/O error and withdraw
++ * Returns: -1 if this call withdrew the machine,
++ * 0 if it was already withdrawn
++ */
++
++int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ const char *function, char *file, unsigned int line)
++{
++ int rv;
++ rv = gfs2_lm_withdraw(sdp,
++ "GFS2: fsid=%s: fatal: I/O error\n"
++ "GFS2: fsid=%s: block = %llu\n"
++ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
++ sdp->sd_fsname,
++ sdp->sd_fsname, (unsigned long long)bh->b_blocknr,
++ sdp->sd_fsname, function, file, line);
++ return rv;
++}
++
++void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
++ unsigned int bit, int new_value)
++{
++ unsigned int c, o, b = bit;
++ int old_value;
++
++ c = b / (8 * PAGE_SIZE);
++ b %= 8 * PAGE_SIZE;
++ o = b / 8;
++ b %= 8;
++
++ old_value = (bitmap[c][o] & (1 << b));
++ gfs2_assert_withdraw(sdp, !old_value != !new_value);
++
++ if (new_value)
++ bitmap[c][o] |= 1 << b;
++ else
++ bitmap[c][o] &= ~(1 << b);
++}
++
+diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
+new file mode 100644
+index 0000000..76a5089
+--- /dev/null
++++ b/fs/gfs2/util.h
+@@ -0,0 +1,170 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __UTIL_DOT_H__
++#define __UTIL_DOT_H__
++
++#include "incore.h"
++
++#define fs_printk(level, fs, fmt, arg...) \
++ printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg)
++
++#define fs_info(fs, fmt, arg...) \
++ fs_printk(KERN_INFO , fs , fmt , ## arg)
++
++#define fs_warn(fs, fmt, arg...) \
++ fs_printk(KERN_WARNING , fs , fmt , ## arg)
++
++#define fs_err(fs, fmt, arg...) \
++ fs_printk(KERN_ERR, fs , fmt , ## arg)
++
++
++void gfs2_assert_i(struct gfs2_sbd *sdp);
++
++#define gfs2_assert(sdp, assertion) \
++do { \
++ if (unlikely(!(assertion))) { \
++ gfs2_assert_i(sdp); \
++ BUG(); \
++ } \
++} while (0)
++
++
++int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
++ const char *function, char *file, unsigned int line);
++
++#define gfs2_assert_withdraw(sdp, assertion) \
++((likely(assertion)) ? 0 : gfs2_assert_withdraw_i((sdp), #assertion, \
++ __FUNCTION__, __FILE__, __LINE__))
++
++
++int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
++ const char *function, char *file, unsigned int line);
++
++#define gfs2_assert_warn(sdp, assertion) \
++((likely(assertion)) ? 0 : gfs2_assert_warn_i((sdp), #assertion, \
++ __FUNCTION__, __FILE__, __LINE__))
++
++
++int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide,
++ const char *function, char *file, unsigned int line);
++
++#define gfs2_consist(sdp) \
++gfs2_consist_i((sdp), 0, __FUNCTION__, __FILE__, __LINE__)
++
++
++int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
++ const char *function, char *file, unsigned int line);
++
++#define gfs2_consist_inode(ip) \
++gfs2_consist_inode_i((ip), 0, __FUNCTION__, __FILE__, __LINE__)
++
++
++int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
++ const char *function, char *file, unsigned int line);
++
++#define gfs2_consist_rgrpd(rgd) \
++gfs2_consist_rgrpd_i((rgd), 0, __FUNCTION__, __FILE__, __LINE__)
++
++
++int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ const char *type, const char *function,
++ char *file, unsigned int line);
++
++static inline int gfs2_meta_check_i(struct gfs2_sbd *sdp,
++ struct buffer_head *bh,
++ const char *function,
++ char *file, unsigned int line)
++{
++ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
++ u32 magic = mh->mh_magic;
++ magic = be32_to_cpu(magic);
++ if (unlikely(magic != GFS2_MAGIC))
++ return gfs2_meta_check_ii(sdp, bh, "magic number", function,
++ file, line);
++ return 0;
++}
++
++#define gfs2_meta_check(sdp, bh) \
++gfs2_meta_check_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__)
++
++
++int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ u16 type, u16 t,
++ const char *function,
++ char *file, unsigned int line);
++
++static inline int gfs2_metatype_check_i(struct gfs2_sbd *sdp,
++ struct buffer_head *bh,
++ u16 type,
++ const char *function,
++ char *file, unsigned int line)
++{
++ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
++ u32 magic = mh->mh_magic;
++ u16 t = be32_to_cpu(mh->mh_type);
++ magic = be32_to_cpu(magic);
++ if (unlikely(magic != GFS2_MAGIC))
++ return gfs2_meta_check_ii(sdp, bh, "magic number", function,
++ file, line);
++ if (unlikely(t != type))
++ return gfs2_metatype_check_ii(sdp, bh, type, t, function,
++ file, line);
++ return 0;
++}
++
++#define gfs2_metatype_check(sdp, bh, type) \
++gfs2_metatype_check_i((sdp), (bh), (type), __FUNCTION__, __FILE__, __LINE__)
++
++static inline void gfs2_metatype_set(struct buffer_head *bh, u16 type,
++ u16 format)
++{
++ struct gfs2_meta_header *mh;
++ mh = (struct gfs2_meta_header *)bh->b_data;
++ mh->mh_type = cpu_to_be32(type);
++ mh->mh_format = cpu_to_be32(format);
++}
++
++
++int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function,
++ char *file, unsigned int line);
++
++#define gfs2_io_error(sdp) \
++gfs2_io_error_i((sdp), __FUNCTION__, __FILE__, __LINE__);
++
++
++int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
++ const char *function, char *file, unsigned int line);
++
++#define gfs2_io_error_bh(sdp, bh) \
++gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__);
++
++
++extern kmem_cache_t *gfs2_glock_cachep;
++extern kmem_cache_t *gfs2_inode_cachep;
++extern kmem_cache_t *gfs2_bufdata_cachep;
++
++static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
++ unsigned int *p)
++{
++ unsigned int x;
++ spin_lock(>->gt_spin);
++ x = *p;
++ spin_unlock(>->gt_spin);
++ return x;
++}
++
++#define gfs2_tune_get(sdp, field) \
++gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
++
++void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
++ unsigned int bit, int new_value);
++
++#endif /* __UTIL_DOT_H__ */
++
+diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
+index 13231dd..0d20006 100644
+--- a/fs/hfs/bnode.c
++++ b/fs/hfs/bnode.c
+@@ -249,10 +249,9 @@ static struct hfs_bnode *__hfs_bnode_cre
+ sb = tree->inode->i_sb;
+ size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
+ sizeof(struct page *);
+- node = kmalloc(size, GFP_KERNEL);
++ node = kzalloc(size, GFP_KERNEL);
+ if (!node)
+ return NULL;
+- memset(node, 0, size);
+ node->tree = tree;
+ node->this = cnid;
+ set_bit(HFS_BNODE_NEW, &node->flags);
+diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
+index 4003579..5fd0ed7 100644
+--- a/fs/hfs/btree.c
++++ b/fs/hfs/btree.c
+@@ -21,10 +21,9 @@ struct hfs_btree *hfs_btree_open(struct
+ struct page *page;
+ unsigned int size;
+
+- tree = kmalloc(sizeof(*tree), GFP_KERNEL);
++ tree = kzalloc(sizeof(*tree), GFP_KERNEL);
+ if (!tree)
+ return NULL;
+- memset(tree, 0, sizeof(*tree));
+
+ init_MUTEX(&tree->tree_lock);
+ spin_lock_init(&tree->hash_lock);
+diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
+index 7cd8cc0..37d681b 100644
+--- a/fs/hfs/dir.c
++++ b/fs/hfs/dir.c
+@@ -246,7 +246,7 @@ static int hfs_unlink(struct inode *dir,
+ if (res)
+ return res;
+
+- inode->i_nlink--;
++ drop_nlink(inode);
+ hfs_delete_inode(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+@@ -273,7 +273,7 @@ static int hfs_rmdir(struct inode *dir,
+ res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
+ if (res)
+ return res;
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ hfs_delete_inode(inode);
+ mark_inode_dirty(inode);
+diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
+index 315cf44..02f5573 100644
+--- a/fs/hfs/inode.c
++++ b/fs/hfs/inode.c
+@@ -154,7 +154,6 @@ struct inode *hfs_new_inode(struct inode
+ inode->i_gid = current->fsgid;
+ inode->i_nlink = 1;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+- inode->i_blksize = HFS_SB(sb)->alloc_blksz;
+ HFS_I(inode)->flags = 0;
+ HFS_I(inode)->rsrc_inode = NULL;
+ HFS_I(inode)->fs_blocks = 0;
+@@ -284,7 +283,6 @@ static int hfs_read_inode(struct inode *
+ inode->i_uid = hsb->s_uid;
+ inode->i_gid = hsb->s_gid;
+ inode->i_nlink = 1;
+- inode->i_blksize = HFS_SB(inode->i_sb)->alloc_blksz;
+
+ if (idata->key)
+ HFS_I(inode)->cat_key = *idata->key;
+@@ -603,8 +601,10 @@ int hfs_inode_setattr(struct dentry *den
+
+ static const struct file_operations hfs_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .sendfile = generic_file_sendfile,
+ .fsync = file_fsync,
+diff --git a/fs/hfs/super.c b/fs/hfs/super.c
+index 34937ee..d43b4fc 100644
+--- a/fs/hfs/super.c
++++ b/fs/hfs/super.c
+@@ -356,11 +356,10 @@ static int hfs_fill_super(struct super_b
+ struct inode *root_inode;
+ int res;
+
+- sbi = kmalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(struct hfs_sb_info));
+ INIT_HLIST_HEAD(&sbi->rsrc_inodes);
+
+ res = -EINVAL;
+@@ -455,8 +454,7 @@ static int __init init_hfs_fs(void)
+ static void __exit exit_hfs_fs(void)
+ {
+ unregister_filesystem(&hfs_fs_type);
+- if (kmem_cache_destroy(hfs_inode_cachep))
+- printk(KERN_ERR "hfs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(hfs_inode_cachep);
+ }
+
+ module_init(init_hfs_fs)
+diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
+index 77bf434..29da657 100644
+--- a/fs/hfsplus/bnode.c
++++ b/fs/hfsplus/bnode.c
+@@ -409,10 +409,9 @@ static struct hfs_bnode *__hfs_bnode_cre
+ sb = tree->inode->i_sb;
+ size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
+ sizeof(struct page *);
+- node = kmalloc(size, GFP_KERNEL);
++ node = kzalloc(size, GFP_KERNEL);
+ if (!node)
+ return NULL;
+- memset(node, 0, size);
+ node->tree = tree;
+ node->this = cnid;
+ set_bit(HFS_BNODE_NEW, &node->flags);
+diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
+index cfc852f..a9b9e87 100644
+--- a/fs/hfsplus/btree.c
++++ b/fs/hfsplus/btree.c
+@@ -24,10 +24,9 @@ struct hfs_btree *hfs_btree_open(struct
+ struct page *page;
+ unsigned int size;
+
+- tree = kmalloc(sizeof(*tree), GFP_KERNEL);
++ tree = kzalloc(sizeof(*tree), GFP_KERNEL);
+ if (!tree)
+ return NULL;
+- memset(tree, 0, sizeof(*tree));
+
+ init_MUTEX(&tree->tree_lock);
+ spin_lock_init(&tree->hash_lock);
+diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
+index 1f9ece0..7e30975 100644
+--- a/fs/hfsplus/dir.c
++++ b/fs/hfsplus/dir.c
+@@ -298,7 +298,7 @@ static int hfsplus_link(struct dentry *s
+ if (res)
+ return res;
+
+- inode->i_nlink++;
++ inc_nlink(inode);
+ hfsplus_instantiate(dst_dentry, inode, cnid);
+ atomic_inc(&inode->i_count);
+ inode->i_ctime = CURRENT_TIME_SEC;
+@@ -338,7 +338,7 @@ static int hfsplus_unlink(struct inode *
+ return res;
+
+ if (inode->i_nlink > 0)
+- inode->i_nlink--;
++ drop_nlink(inode);
+ hfsplus_delete_inode(inode);
+ if (inode->i_ino != cnid && !inode->i_nlink) {
+ if (!atomic_read(&HFSPLUS_I(inode).opencnt)) {
+@@ -348,7 +348,7 @@ static int hfsplus_unlink(struct inode *
+ } else
+ inode->i_flags |= S_DEAD;
+ } else
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+
+@@ -387,7 +387,7 @@ static int hfsplus_rmdir(struct inode *d
+ res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
+ if (res)
+ return res;
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ hfsplus_delete_inode(inode);
+ mark_inode_dirty(inode);
+diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
+index 8a1ca5e..3915635 100644
+--- a/fs/hfsplus/hfsplus_fs.h
++++ b/fs/hfsplus/hfsplus_fs.h
+@@ -246,12 +246,8 @@ struct hfsplus_readdir_data {
+
+ /* ext2 ioctls (EXT2_IOC_GETFLAGS and EXT2_IOC_SETFLAGS) to support
+ * chattr/lsattr */
+-#define HFSPLUS_IOC_EXT2_GETFLAGS _IOR('f', 1, long)
+-#define HFSPLUS_IOC_EXT2_SETFLAGS _IOW('f', 2, long)
+-
+-#define EXT2_FLAG_IMMUTABLE 0x00000010 /* Immutable file */
+-#define EXT2_FLAG_APPEND 0x00000020 /* writes to file may only append */
+-#define EXT2_FLAG_NODUMP 0x00000040 /* do not dump file */
++#define HFSPLUS_IOC_EXT2_GETFLAGS FS_IOC_GETFLAGS
++#define HFSPLUS_IOC_EXT2_SETFLAGS FS_IOC_SETFLAGS
+
+
+ /*
+diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
+index 924ecde..9e36752 100644
+--- a/fs/hfsplus/inode.c
++++ b/fs/hfsplus/inode.c
+@@ -282,8 +282,10 @@ static struct inode_operations hfsplus_f
+
+ static const struct file_operations hfsplus_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .sendfile = generic_file_sendfile,
+ .fsync = file_fsync,
+@@ -304,7 +306,6 @@ struct inode *hfsplus_new_inode(struct s
+ inode->i_gid = current->fsgid;
+ inode->i_nlink = 1;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+- inode->i_blksize = HFSPLUS_SB(sb).alloc_blksz;
+ INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
+ init_MUTEX(&HFSPLUS_I(inode).extents_lock);
+ atomic_set(&HFSPLUS_I(inode).opencnt, 0);
+@@ -407,7 +408,6 @@ int hfsplus_cat_read_inode(struct inode
+ type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
+
+ HFSPLUS_I(inode).dev = 0;
+- inode->i_blksize = HFSPLUS_SB(inode->i_sb).alloc_blksz;
+ if (type == HFSPLUS_FOLDER) {
+ struct hfsplus_cat_folder *folder = &entry.folder;
+
+diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
+index 13cf848..79fd104 100644
+--- a/fs/hfsplus/ioctl.c
++++ b/fs/hfsplus/ioctl.c
+@@ -28,11 +28,11 @@ int hfsplus_ioctl(struct inode *inode, s
+ case HFSPLUS_IOC_EXT2_GETFLAGS:
+ flags = 0;
+ if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE)
+- flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */
++ flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */
+ if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
+- flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */
++ flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */
+ if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
+- flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */
++ flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
+ return put_user(flags, (int __user *)arg);
+ case HFSPLUS_IOC_EXT2_SETFLAGS: {
+ if (IS_RDONLY(inode))
+@@ -44,32 +44,31 @@ int hfsplus_ioctl(struct inode *inode, s
+ if (get_user(flags, (int __user *)arg))
+ return -EFAULT;
+
+- if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) ||
++ if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
+ HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -EPERM;
+ }
+
+ /* don't silently ignore unsupported ext2 flags */
+- if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND|
+- EXT2_FLAG_NODUMP))
++ if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL))
+ return -EOPNOTSUPP;
+
+- if (flags & EXT2_FLAG_IMMUTABLE) { /* EXT2_IMMUTABLE_FL */
++ if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */
+ inode->i_flags |= S_IMMUTABLE;
+ HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE;
+ } else {
+ inode->i_flags &= ~S_IMMUTABLE;
+ HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
+ }
+- if (flags & EXT2_FLAG_APPEND) { /* EXT2_APPEND_FL */
++ if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */
+ inode->i_flags |= S_APPEND;
+ HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND;
+ } else {
+ inode->i_flags &= ~S_APPEND;
+ HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND;
+ }
+- if (flags & EXT2_FLAG_NODUMP) /* EXT2_NODUMP_FL */
++ if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */
+ HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
+ else
+ HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP;
+diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c
+index ae78306..1528a6f 100644
+--- a/fs/hfsplus/part_tbl.c
++++ b/fs/hfsplus/part_tbl.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/hfs/part_tbl.c
++ * linux/fs/hfsplus/part_tbl.c
+ *
+ * Copyright (C) 1996-1997 Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU General Public License.
+diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
+index d279d59..194eede 100644
+--- a/fs/hfsplus/super.c
++++ b/fs/hfsplus/super.c
+@@ -493,8 +493,7 @@ static int __init init_hfsplus_fs(void)
+ static void __exit exit_hfsplus_fs(void)
+ {
+ unregister_filesystem(&hfsplus_fs_type);
+- if (kmem_cache_destroy(hfsplus_inode_cachep))
+- printk(KERN_ERR "hfsplus_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(hfsplus_inode_cachep);
+ }
+
+ module_init(init_hfsplus_fs)
+diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
+index b82e3d9..b6bd33c 100644
+--- a/fs/hostfs/hostfs_kern.c
++++ b/fs/hostfs/hostfs_kern.c
+@@ -156,7 +156,6 @@ static int read_name(struct inode *ino,
+ ino->i_mode = i_mode;
+ ino->i_nlink = i_nlink;
+ ino->i_size = i_size;
+- ino->i_blksize = i_blksize;
+ ino->i_blocks = i_blocks;
+ return(0);
+ }
+@@ -386,13 +385,11 @@ int hostfs_fsync(struct file *file, stru
+
+ static const struct file_operations hostfs_file_fops = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
++ .read = do_sync_read,
+ .sendfile = generic_file_sendfile,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+- .readv = generic_file_readv,
+- .writev = generic_file_writev,
+- .write = generic_file_write,
++ .write = do_sync_write,
+ .mmap = generic_file_mmap,
+ .open = hostfs_file_open,
+ .release = NULL,
+diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
+index 2807aa8..b52b738 100644
+--- a/fs/hpfs/buffer.c
++++ b/fs/hpfs/buffer.c
+@@ -76,7 +76,7 @@ void *hpfs_map_4sectors(struct super_blo
+ return NULL;
+ }
+
+- qbh->data = data = (char *)kmalloc(2048, GFP_NOFS);
++ qbh->data = data = kmalloc(2048, GFP_NOFS);
+ if (!data) {
+ printk("HPFS: hpfs_map_4sectors: out of memory\n");
+ goto bail;
+diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
+index d9eb19b..8b94d24 100644
+--- a/fs/hpfs/file.c
++++ b/fs/hpfs/file.c
+@@ -113,7 +113,7 @@ static ssize_t hpfs_file_write(struct fi
+ {
+ ssize_t retval;
+
+- retval = generic_file_write(file, buf, count, ppos);
++ retval = do_sync_write(file, buf, count, ppos);
+ if (retval > 0)
+ hpfs_i(file->f_dentry->d_inode)->i_dirty = 1;
+ return retval;
+@@ -122,8 +122,10 @@ static ssize_t hpfs_file_write(struct fi
+ const struct file_operations hpfs_file_ops =
+ {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
+ .write = hpfs_file_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .release = hpfs_file_release,
+ .fsync = hpfs_file_fsync,
+diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
+index f687d54..32ab51e 100644
+--- a/fs/hpfs/hpfs_fn.h
++++ b/fs/hpfs/hpfs_fn.h
+@@ -12,7 +12,6 @@
+ #include <linux/mutex.h>
+ #include <linux/pagemap.h>
+ #include <linux/buffer_head.h>
+-#include <linux/hpfs_fs.h>
+ #include <linux/slab.h>
+ #include <linux/smp_lock.h>
+
+diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
+index 56f2c33..7faef85 100644
+--- a/fs/hpfs/inode.c
++++ b/fs/hpfs/inode.c
+@@ -17,7 +17,6 @@ void hpfs_init_inode(struct inode *i)
+ i->i_gid = hpfs_sb(sb)->sb_gid;
+ i->i_mode = hpfs_sb(sb)->sb_mode;
+ hpfs_inode->i_conv = hpfs_sb(sb)->sb_conv;
+- i->i_blksize = 512;
+ i->i_size = -1;
+ i->i_blocks = -1;
+
+@@ -61,14 +60,14 @@ void hpfs_read_inode(struct inode *i)
+ if (hpfs_sb(i->i_sb)->sb_eas) {
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) {
+ if (ea_size == 2) {
+- i->i_uid = le16_to_cpu(*(u16*)ea);
++ i->i_uid = le16_to_cpu(*(__le16*)ea);
+ hpfs_inode->i_ea_uid = 1;
+ }
+ kfree(ea);
+ }
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) {
+ if (ea_size == 2) {
+- i->i_gid = le16_to_cpu(*(u16*)ea);
++ i->i_gid = le16_to_cpu(*(__le16*)ea);
+ hpfs_inode->i_ea_gid = 1;
+ }
+ kfree(ea);
+@@ -88,7 +87,7 @@ void hpfs_read_inode(struct inode *i)
+ int rdev = 0;
+ umode_t mode = hpfs_sb(sb)->sb_mode;
+ if (ea_size == 2) {
+- mode = le16_to_cpu(*(u16*)ea);
++ mode = le16_to_cpu(*(__le16*)ea);
+ hpfs_inode->i_ea_mode = 1;
+ }
+ kfree(ea);
+@@ -96,7 +95,7 @@ void hpfs_read_inode(struct inode *i)
+ if (S_ISBLK(mode) || S_ISCHR(mode)) {
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) {
+ if (ea_size == 4)
+- rdev = le32_to_cpu(*(u32*)ea);
++ rdev = le32_to_cpu(*(__le32*)ea);
+ kfree(ea);
+ }
+ }
+@@ -149,7 +148,7 @@ static void hpfs_write_inode_ea(struct i
+ we'd better not overwrite them
+ hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
+ } else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) {
+- u32 ea;
++ __le32 ea;
+ if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) {
+ ea = cpu_to_le32(i->i_uid);
+ hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2);
+@@ -166,6 +165,7 @@ static void hpfs_write_inode_ea(struct i
+ && i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333))
+ | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) {
+ ea = cpu_to_le32(i->i_mode);
++ /* sick, but legal */
+ hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2);
+ hpfs_inode->i_ea_mode = 1;
+ }
+diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
+index 59e7dc1..2507e73 100644
+--- a/fs/hpfs/namei.c
++++ b/fs/hpfs/namei.c
+@@ -89,7 +89,7 @@ static int hpfs_mkdir(struct inode *dir,
+ brelse(bh);
+ hpfs_mark_4buffers_dirty(&qbh0);
+ hpfs_brelse4(&qbh0);
+- dir->i_nlink++;
++ inc_nlink(dir);
+ insert_inode_hash(result);
+
+ if (result->i_uid != current->fsuid ||
+@@ -434,7 +434,7 @@ again:
+ unlock_kernel();
+ return -ENOSPC;
+ default:
+- inode->i_nlink--;
++ drop_nlink(inode);
+ err = 0;
+ }
+ goto out;
+@@ -494,8 +494,8 @@ static int hpfs_rmdir(struct inode *dir,
+ err = -ENOSPC;
+ break;
+ default:
+- dir->i_nlink--;
+- inode->i_nlink = 0;
++ drop_nlink(dir);
++ clear_nlink(inode);
+ err = 0;
+ }
+ goto out;
+@@ -590,7 +590,7 @@ static int hpfs_rename(struct inode *old
+ int r;
+ if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
+ if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) {
+- new_inode->i_nlink = 0;
++ clear_nlink(new_inode);
+ copy_de(nde, &de);
+ memcpy(nde->name, new_name, new_len);
+ hpfs_mark_4buffers_dirty(&qbh1);
+@@ -635,8 +635,8 @@ static int hpfs_rename(struct inode *old
+ end:
+ hpfs_i(i)->i_parent_dir = new_dir->i_ino;
+ if (S_ISDIR(i->i_mode)) {
+- new_dir->i_nlink++;
+- old_dir->i_nlink--;
++ inc_nlink(new_dir);
++ drop_nlink(old_dir);
+ }
+ if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
+ fnode->up = new_dir->i_ino;
+diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
+index f798480..450b5e0 100644
+--- a/fs/hpfs/super.c
++++ b/fs/hpfs/super.c
+@@ -11,6 +11,7 @@
+ #include <linux/parser.h>
+ #include <linux/init.h>
+ #include <linux/statfs.h>
++#include <linux/magic.h>
+
+ /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
+
+@@ -202,8 +203,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(hpfs_inode_cachep))
+- printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(hpfs_inode_cachep);
+ }
+
+ /*
+@@ -461,11 +461,10 @@ static int hpfs_fill_super(struct super_
+
+ int o;
+
+- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ s->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(*sbi));
+
+ sbi->sb_bmp_dir = NULL;
+ sbi->sb_cp_table = NULL;
+diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
+index 3a9bdf5..642675f 100644
+--- a/fs/hppfs/hppfs_kern.c
++++ b/fs/hppfs/hppfs_kern.c
+@@ -152,7 +152,6 @@ static void hppfs_read_inode(struct inod
+ ino->i_mode = proc_ino->i_mode;
+ ino->i_nlink = proc_ino->i_nlink;
+ ino->i_size = proc_ino->i_size;
+- ino->i_blksize = proc_ino->i_blksize;
+ ino->i_blocks = proc_ino->i_blocks;
+ }
+
+@@ -573,7 +572,7 @@ struct hppfs_dirent {
+ };
+
+ static int hppfs_filldir(void *d, const char *name, int size,
+- loff_t offset, ino_t inode, unsigned int type)
++ loff_t offset, u64 inode, unsigned int type)
+ {
+ struct hppfs_dirent *dirent = d;
+
+diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
+index c3920c9..0bea6a6 100644
+--- a/fs/hugetlbfs/inode.c
++++ b/fs/hugetlbfs/inode.c
+@@ -229,7 +229,7 @@ static void hugetlbfs_delete_inode(struc
+ clear_inode(inode);
+ }
+
+-static void hugetlbfs_forget_inode(struct inode *inode)
++static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
+ {
+ struct super_block *sb = inode->i_sb;
+
+@@ -271,29 +271,27 @@ static void hugetlbfs_drop_inode(struct
+ hugetlbfs_forget_inode(inode);
+ }
+
+-/*
+- * h_pgoff is in HPAGE_SIZE units.
+- * vma->vm_pgoff is in PAGE_SIZE units.
+- */
+ static inline void
+-hugetlb_vmtruncate_list(struct prio_tree_root *root, unsigned long h_pgoff)
++hugetlb_vmtruncate_list(struct prio_tree_root *root, pgoff_t pgoff)
+ {
+ struct vm_area_struct *vma;
+ struct prio_tree_iter iter;
+
+- vma_prio_tree_foreach(vma, &iter, root, h_pgoff, ULONG_MAX) {
+- unsigned long h_vm_pgoff;
++ vma_prio_tree_foreach(vma, &iter, root, pgoff, ULONG_MAX) {
+ unsigned long v_offset;
+
+- h_vm_pgoff = vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT);
+- v_offset = (h_pgoff - h_vm_pgoff) << HPAGE_SHIFT;
+ /*
+- * Is this VMA fully outside the truncation point?
++ * Can the expression below overflow on 32-bit arches?
++ * No, because the prio_tree returns us only those vmas
++ * which overlap the truncated area starting at pgoff,
++ * and no vma on a 32-bit arch can span beyond the 4GB.
+ */
+- if (h_vm_pgoff >= h_pgoff)
++ if (vma->vm_pgoff < pgoff)
++ v_offset = (pgoff - vma->vm_pgoff) << PAGE_SHIFT;
++ else
+ v_offset = 0;
+
+- unmap_hugepage_range(vma,
++ __unmap_hugepage_range(vma,
+ vma->vm_start + v_offset, vma->vm_end);
+ }
+ }
+@@ -303,14 +301,14 @@ hugetlb_vmtruncate_list(struct prio_tree
+ */
+ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
+ {
+- unsigned long pgoff;
++ pgoff_t pgoff;
+ struct address_space *mapping = inode->i_mapping;
+
+ if (offset > inode->i_size)
+ return -EINVAL;
+
+ BUG_ON(offset & ~HPAGE_MASK);
+- pgoff = offset >> HPAGE_SHIFT;
++ pgoff = offset >> PAGE_SHIFT;
+
+ inode->i_size = offset;
+ spin_lock(&mapping->i_mmap_lock);
+@@ -357,7 +355,6 @@ static struct inode *hugetlbfs_get_inode
+ inode->i_mode = mode;
+ inode->i_uid = uid;
+ inode->i_gid = gid;
+- inode->i_blksize = HPAGE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->a_ops = &hugetlbfs_aops;
+ inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
+@@ -378,7 +375,7 @@ static struct inode *hugetlbfs_get_inode
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ break;
+ case S_IFLNK:
+ inode->i_op = &page_symlink_inode_operations;
+@@ -419,7 +416,7 @@ static int hugetlbfs_mkdir(struct inode
+ {
+ int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+ if (!retval)
+- dir->i_nlink++;
++ inc_nlink(dir);
+ return retval;
+ }
+
+@@ -625,7 +622,6 @@ hugetlbfs_parse_options(char *options, s
+ do_div(size, 100);
+ rest++;
+ }
+- size &= HPAGE_MASK;
+ pconfig->nr_blocks = (size >> HPAGE_SHIFT);
+ value = rest;
+ } else if (!strcmp(opt,"nr_inodes")) {
+diff --git a/fs/inode.c b/fs/inode.c
+index 0bf9f04..26cdb11 100644
+--- a/fs/inode.c
++++ b/fs/inode.c
+@@ -133,7 +133,6 @@ static struct inode *alloc_inode(struct
+ inode->i_bdev = NULL;
+ inode->i_cdev = NULL;
+ inode->i_rdev = 0;
+- inode->i_security = NULL;
+ inode->dirtied_when = 0;
+ if (security_inode_alloc(inode)) {
+ if (inode->i_sb->s_op->destroy_inode)
+@@ -163,7 +162,7 @@ static struct inode *alloc_inode(struct
+ bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
+ mapping->backing_dev_info = bdi;
+ }
+- memset(&inode->u, 0, sizeof(inode->u));
++ inode->i_private = NULL;
+ inode->i_mapping = mapping;
+ }
+ return inode;
+@@ -254,9 +253,9 @@ void clear_inode(struct inode *inode)
+ DQUOT_DROP(inode);
+ if (inode->i_sb && inode->i_sb->s_op->clear_inode)
+ inode->i_sb->s_op->clear_inode(inode);
+- if (inode->i_bdev)
++ if (S_ISBLK(inode->i_mode) && inode->i_bdev)
+ bd_forget(inode);
+- if (inode->i_cdev)
++ if (S_ISCHR(inode->i_mode) && inode->i_cdev)
+ cd_forget(inode);
+ inode->i_state = I_CLEAR;
+ }
+@@ -363,27 +362,6 @@ int invalidate_inodes(struct super_block
+ }
+
+ EXPORT_SYMBOL(invalidate_inodes);
+-
+-int __invalidate_device(struct block_device *bdev)
+-{
+- struct super_block *sb = get_super(bdev);
+- int res = 0;
+-
+- if (sb) {
+- /*
+- * no need to lock the super, get_super holds the
+- * read mutex so the filesystem cannot go away
+- * under us (->put_super runs with the write lock
+- * hold).
+- */
+- shrink_dcache_sb(sb);
+- res = invalidate_inodes(sb);
+- drop_super(sb);
+- }
+- invalidate_bdev(bdev, 0);
+- return res;
+-}
+-EXPORT_SYMBOL(__invalidate_device);
+
+ static int can_unuse(struct inode *inode)
+ {
+@@ -679,7 +657,7 @@ static struct inode * get_new_inode_fast
+ return inode;
+ }
+
+-static inline unsigned long hash(struct super_block *sb, unsigned long hashval)
++static unsigned long hash(struct super_block *sb, unsigned long hashval)
+ {
+ unsigned long tmp;
+
+@@ -1025,7 +1003,7 @@ void generic_delete_inode(struct inode *
+
+ list_del_init(&inode->i_list);
+ list_del_init(&inode->i_sb_list);
+- inode->i_state|=I_FREEING;
++ inode->i_state |= I_FREEING;
+ inodes_stat.nr_inodes--;
+ spin_unlock(&inode_lock);
+
+@@ -1232,13 +1210,15 @@ void file_update_time(struct file *file)
+ return;
+
+ now = current_fs_time(inode->i_sb);
+- if (!timespec_equal(&inode->i_mtime, &now))
++ if (!timespec_equal(&inode->i_mtime, &now)) {
++ inode->i_mtime = now;
+ sync_it = 1;
+- inode->i_mtime = now;
++ }
+
+- if (!timespec_equal(&inode->i_ctime, &now))
++ if (!timespec_equal(&inode->i_ctime, &now)) {
++ inode->i_ctime = now;
+ sync_it = 1;
+- inode->i_ctime = now;
++ }
+
+ if (sync_it)
+ mark_inode_dirty_sync(inode);
+@@ -1326,6 +1306,42 @@ void wake_up_inode(struct inode *inode)
+ wake_up_bit(&inode->i_state, __I_LOCK);
+ }
+
++/*
++ * We rarely want to lock two inodes that do not have a parent/child
++ * relationship (such as directory, child inode) simultaneously. The
++ * vast majority of file systems should be able to get along fine
++ * without this. Do not use these functions except as a last resort.
++ */
++void inode_double_lock(struct inode *inode1, struct inode *inode2)
++{
++ if (inode1 == NULL || inode2 == NULL || inode1 == inode2) {
++ if (inode1)
++ mutex_lock(&inode1->i_mutex);
++ else if (inode2)
++ mutex_lock(&inode2->i_mutex);
++ return;
++ }
++
++ if (inode1 < inode2) {
++ mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
++ mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
++ } else {
++ mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT);
++ mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD);
++ }
++}
++EXPORT_SYMBOL(inode_double_lock);
++
++void inode_double_unlock(struct inode *inode1, struct inode *inode2)
++{
++ if (inode1)
++ mutex_unlock(&inode1->i_mutex);
++
++ if (inode2 && inode2 != inode1)
++ mutex_unlock(&inode2->i_mutex);
++}
++EXPORT_SYMBOL(inode_double_unlock);
++
+ static __initdata unsigned long ihash_entries;
+ static int __init set_ihash_entries(char *str)
+ {
+diff --git a/fs/internal.h b/fs/internal.h
+new file mode 100644
+index 0000000..ea00126
+--- /dev/null
++++ b/fs/internal.h
+@@ -0,0 +1,55 @@
++/* fs/ internal definitions
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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/ioctl32.h>
++
++struct super_block;
++
++/*
++ * block_dev.c
++ */
++#ifdef CONFIG_BLOCK
++extern struct super_block *blockdev_superblock;
++extern void __init bdev_cache_init(void);
++
++static inline int sb_is_blkdev_sb(struct super_block *sb)
++{
++ return sb == blockdev_superblock;
++}
++
++#else
++static inline void bdev_cache_init(void)
++{
++}
++
++static inline int sb_is_blkdev_sb(struct super_block *sb)
++{
++ return 0;
++}
++#endif
++
++/*
++ * char_dev.c
++ */
++extern void __init chrdev_init(void);
++
++/*
++ * compat_ioctl.c
++ */
++#ifdef CONFIG_COMPAT
++extern struct ioctl_trans ioctl_start[];
++extern int ioctl_table_size;
++#endif
++
++/*
++ * namespace.c
++ */
++extern int copy_mount_options(const void __user *, unsigned long *);
+diff --git a/fs/ioprio.c b/fs/ioprio.c
+index 78b1dea..89e8da1 100644
+--- a/fs/ioprio.c
++++ b/fs/ioprio.c
+@@ -1,7 +1,7 @@
+ /*
+ * fs/ioprio.c
+ *
+- * Copyright (C) 2004 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2004 Jens Axboe <axboe at kernel.dk>
+ *
+ * Helper functions for setting/querying io priorities of processes. The
+ * system calls closely mimmick getpriority/setpriority, see the man page for
+@@ -47,8 +47,8 @@ static int set_task_ioprio(struct task_s
+ /* see wmb() in current_io_context() */
+ smp_read_barrier_depends();
+
+- if (ioc && ioc->set_ioprio)
+- ioc->set_ioprio(ioc, ioprio);
++ if (ioc)
++ ioc->ioprio_changed = 1;
+
+ task_unlock(task);
+ return 0;
+@@ -81,7 +81,12 @@ asmlinkage long sys_ioprio_set(int which
+ }
+
+ ret = -ESRCH;
+- read_lock_irq(&tasklist_lock);
++ /*
++ * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic",
++ * so we can't use rcu_read_lock(). See re-copy of ->ioprio
++ * in copy_process().
++ */
++ read_lock(&tasklist_lock);
+ switch (which) {
+ case IOPRIO_WHO_PROCESS:
+ if (!who)
+@@ -124,7 +129,7 @@ free_uid:
+ ret = -EINVAL;
+ }
+
+- read_unlock_irq(&tasklist_lock);
++ read_unlock(&tasklist_lock);
+ return ret;
+ }
+
+@@ -145,11 +150,6 @@ int ioprio_best(unsigned short aprio, un
+ 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)
+@@ -170,7 +170,7 @@ asmlinkage long sys_ioprio_get(int which
+ int ret = -ESRCH;
+ int tmpio;
+
+- read_lock_irq(&tasklist_lock);
++ read_lock(&tasklist_lock);
+ switch (which) {
+ case IOPRIO_WHO_PROCESS:
+ if (!who)
+@@ -221,7 +221,7 @@ asmlinkage long sys_ioprio_get(int which
+ ret = -EINVAL;
+ }
+
+- read_unlock_irq(&tasklist_lock);
++ read_unlock(&tasklist_lock);
+ return ret;
+ }
+
+diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
+index 1439136..c34b862 100644
+--- a/fs/isofs/inode.c
++++ b/fs/isofs/inode.c
+@@ -96,9 +96,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(isofs_inode_cachep))
+- printk(KERN_INFO "iso_inode_cache: not all structures were "
+- "freed\n");
++ kmem_cache_destroy(isofs_inode_cachep);
+ }
+
+ static int isofs_remount(struct super_block *sb, int *flags, char *data)
+@@ -557,11 +555,10 @@ static int isofs_fill_super(struct super
+ struct iso9660_options opt;
+ struct isofs_sb_info * sbi;
+
+- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ s->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(*sbi));
+
+ if (!parse_options((char *)data, &opt))
+ goto out_freesbi;
+@@ -963,30 +960,30 @@ int isofs_get_blocks(struct inode *inode
+ goto abort;
+ }
+
+- if (nextblk) {
+- while (b_off >= (offset + sect_size)) {
+- struct inode *ninode;
+-
+- offset += sect_size;
+- if (nextblk == 0)
+- goto abort;
+- ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
+- if (!ninode)
+- goto abort;
+- firstext = ISOFS_I(ninode)->i_first_extent;
+- sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
+- nextblk = ISOFS_I(ninode)->i_next_section_block;
+- nextoff = ISOFS_I(ninode)->i_next_section_offset;
+- iput(ninode);
+-
+- if (++section > 100) {
+- printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
+- printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
+- "nextblk=%lu nextoff=%lu\n",
+- iblock, firstext, (unsigned) sect_size,
+- nextblk, nextoff);
+- goto abort;
+- }
++ /* On the last section, nextblk == 0, section size is likely to
++ * exceed sect_size by a partial block, and access beyond the
++ * end of the file will reach beyond the section size, too.
++ */
++ while (nextblk && (b_off >= (offset + sect_size))) {
++ struct inode *ninode;
++
++ offset += sect_size;
++ ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
++ if (!ninode)
++ goto abort;
++ firstext = ISOFS_I(ninode)->i_first_extent;
++ sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
++ nextblk = ISOFS_I(ninode)->i_next_section_block;
++ nextoff = ISOFS_I(ninode)->i_next_section_offset;
++ iput(ninode);
++
++ if (++section > 100) {
++ printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
++ printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
++ "nextblk=%lu nextoff=%lu\n",
++ iblock, firstext, (unsigned) sect_size,
++ nextblk, nextoff);
++ goto abort;
+ }
+ }
+
+@@ -1238,7 +1235,7 @@ static void isofs_read_inode(struct inod
+ }
+ inode->i_uid = sbi->s_uid;
+ inode->i_gid = sbi->s_gid;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+
+ ei->i_format_parm[0] = 0;
+ ei->i_format_parm[1] = 0;
+@@ -1294,7 +1291,6 @@ static void isofs_read_inode(struct inod
+ isonum_711 (de->ext_attr_length));
+
+ /* Set the number of blocks for stat() - should be done before RR */
+- inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+
+ /*
+diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
+index 81a90e1..fb8fe7a 100644
+--- a/fs/isofs/joliet.c
++++ b/fs/isofs/joliet.c
+@@ -14,9 +14,9 @@
+ * Convert Unicode 16 to UTF-8 or ASCII.
+ */
+ static int
+-uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls)
++uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
+ {
+- wchar_t *ip, ch;
++ __be16 *ip, ch;
+ unsigned char *op;
+
+ ip = uni;
+@@ -24,8 +24,8 @@ uni16_to_x8(unsigned char *ascii, u16 *u
+
+ while ((ch = get_unaligned(ip)) && len) {
+ int llen;
+- ch = be16_to_cpu(ch);
+- if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0)
++ llen = nls->uni2char(be16_to_cpu(ch), op, NLS_MAX_CHARSET_SIZE);
++ if (llen > 0)
+ op += llen;
+ else
+ *op++ = '?';
+@@ -82,7 +82,7 @@ get_joliet_filename(struct iso_directory
+ len = wcsntombs_be(outname, de->name,
+ de->name_len[0] >> 1, PAGE_SIZE);
+ } else {
+- len = uni16_to_x8(outname, (u16 *) de->name,
++ len = uni16_to_x8(outname, (__be16 *) de->name,
+ de->name_len[0] >> 1, nls);
+ }
+ if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
+diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
+index e7ba0c3..c04b3a1 100644
+--- a/fs/isofs/namei.c
++++ b/fs/isofs/namei.c
+@@ -6,7 +6,6 @@
+ * (C) 1991 Linus Torvalds - minix filesystem
+ */
+
+-#include <linux/config.h> /* Joliet? */
+ #include <linux/smp_lock.h>
+ #include "isofs.h"
+
+diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
+index 47678a2..0208cc7 100644
+--- a/fs/jbd/checkpoint.c
++++ b/fs/jbd/checkpoint.c
+@@ -1,6 +1,6 @@
+ /*
+ * linux/fs/checkpoint.c
+- *
++ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>, 1999
+ *
+ * Copyright 1999 Red Hat Software --- All Rights Reserved
+@@ -9,8 +9,8 @@
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+- * Checkpoint routines for the generic filesystem journaling code.
+- * Part of the ext2fs journaling system.
++ * Checkpoint routines for the generic filesystem journaling code.
++ * Part of the ext2fs journaling system.
+ *
+ * Checkpointing is the process of ensuring that a section of the log is
+ * committed fully to disk, so that that portion of the log can be
+@@ -145,6 +145,7 @@ void __log_wait_for_space(journal_t *jou
+ * jbd_unlock_bh_state().
+ */
+ static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
++ __releases(journal->j_list_lock)
+ {
+ get_bh(bh);
+ spin_unlock(&journal->j_list_lock);
+@@ -225,7 +226,7 @@ __flush_batch(journal_t *journal, struct
+ * Try to flush one buffer from the checkpoint list to disk.
+ *
+ * Return 1 if something happened which requires us to abort the current
+- * scan of the checkpoint list.
++ * scan of the checkpoint list.
+ *
+ * Called with j_list_lock held and drops it if 1 is returned
+ * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
+@@ -269,7 +270,7 @@ static int __process_buffer(journal_t *j
+ * possibly block, while still holding the journal lock.
+ * We cannot afford to let the transaction logic start
+ * messing around with this buffer before we write it to
+- * disk, as that would break recoverability.
++ * disk, as that would break recoverability.
+ */
+ BUFFER_TRACE(bh, "queue");
+ get_bh(bh);
+@@ -292,7 +293,7 @@ static int __process_buffer(journal_t *j
+ * Perform an actual checkpoint. We take the first transaction on the
+ * list of transactions to be checkpointed and send all its buffers
+ * to disk. We submit larger chunks of data at once.
+- *
++ *
+ * The journal should be locked before calling this function.
+ */
+ int log_do_checkpoint(journal_t *journal)
+@@ -303,10 +304,10 @@ int log_do_checkpoint(journal_t *journal
+
+ jbd_debug(1, "Start checkpoint\n");
+
+- /*
++ /*
+ * First thing: if there are any transactions in the log which
+ * don't need checkpointing, just eliminate them from the
+- * journal straight away.
++ * journal straight away.
+ */
+ result = cleanup_journal_tail(journal);
+ jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
+@@ -384,9 +385,9 @@ out:
+ * we have already got rid of any since the last update of the log tail
+ * in the journal superblock. If so, we can instantly roll the
+ * superblock forward to remove those transactions from the log.
+- *
++ *
+ * Return <0 on error, 0 on success, 1 if there was nothing to clean up.
+- *
++ *
+ * Called with the journal lock held.
+ *
+ * This is the only part of the journaling code which really needs to be
+@@ -403,8 +404,8 @@ int cleanup_journal_tail(journal_t *jour
+ unsigned long blocknr, freed;
+
+ /* OK, work out the oldest transaction remaining in the log, and
+- * the log block it starts at.
+- *
++ * the log block it starts at.
++ *
+ * If the log is now empty, we need to work out which is the
+ * next transaction ID we will write, and where it will
+ * start. */
+@@ -479,7 +480,7 @@ static int journal_clean_one_cp_list(str
+ if (!jh)
+ return 0;
+
+- last_jh = jh->b_cpprev;
++ last_jh = jh->b_cpprev;
+ do {
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+@@ -557,7 +558,7 @@ out:
+ return ret;
+ }
+
+-/*
++/*
+ * journal_remove_checkpoint: called after a buffer has been committed
+ * to disk (either by being write-back flushed to disk, or being
+ * committed to the log).
+@@ -635,7 +636,7 @@ out:
+ * Called with the journal locked.
+ * Called with j_list_lock held.
+ */
+-void __journal_insert_checkpoint(struct journal_head *jh,
++void __journal_insert_checkpoint(struct journal_head *jh,
+ transaction_t *transaction)
+ {
+ JBUFFER_TRACE(jh, "entry");
+@@ -657,7 +658,7 @@ void __journal_insert_checkpoint(struct
+
+ /*
+ * We've finished with this transaction structure: adios...
+- *
++ *
+ * The transaction must have no links except for the checkpoint by this
+ * point.
+ *
+diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
+index 42da607..10be512 100644
+--- a/fs/jbd/commit.c
++++ b/fs/jbd/commit.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/commit.c
++ * linux/fs/jbd/commit.c
+ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>, 1998
+ *
+@@ -160,6 +160,117 @@ static int journal_write_commit_record(j
+ return (ret == -EIO);
+ }
+
++static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
++{
++ int i;
++
++ for (i = 0; i < bufs; i++) {
++ wbuf[i]->b_end_io = end_buffer_write_sync;
++ /* We use-up our safety reference in submit_bh() */
++ submit_bh(WRITE, wbuf[i]);
++ }
++}
++
++/*
++ * Submit all the data buffers to disk
++ */
++static void journal_submit_data_buffers(journal_t *journal,
++ transaction_t *commit_transaction)
++{
++ struct journal_head *jh;
++ struct buffer_head *bh;
++ int locked;
++ int bufs = 0;
++ struct buffer_head **wbuf = journal->j_wbuf;
++
++ /*
++ * Whenever we unlock the journal and sleep, things can get added
++ * onto ->t_sync_datalist, so we have to keep looping back to
++ * write_out_data until we *know* that the list is empty.
++ *
++ * Cleanup any flushed data buffers from the data list. Even in
++ * abort mode, we want to flush this out as soon as possible.
++ */
++write_out_data:
++ cond_resched();
++ spin_lock(&journal->j_list_lock);
++
++ while (commit_transaction->t_sync_datalist) {
++ jh = commit_transaction->t_sync_datalist;
++ bh = jh2bh(jh);
++ locked = 0;
++
++ /* Get reference just to make sure buffer does not disappear
++ * when we are forced to drop various locks */
++ get_bh(bh);
++ /* If the buffer is dirty, we need to submit IO and hence
++ * we need the buffer lock. We try to lock the buffer without
++ * blocking. If we fail, we need to drop j_list_lock and do
++ * blocking lock_buffer().
++ */
++ if (buffer_dirty(bh)) {
++ if (test_set_buffer_locked(bh)) {
++ BUFFER_TRACE(bh, "needs blocking lock");
++ spin_unlock(&journal->j_list_lock);
++ /* Write out all data to prevent deadlocks */
++ journal_do_submit_data(wbuf, bufs);
++ bufs = 0;
++ lock_buffer(bh);
++ spin_lock(&journal->j_list_lock);
++ }
++ locked = 1;
++ }
++ /* We have to get bh_state lock. Again out of order, sigh. */
++ if (!inverted_lock(journal, bh)) {
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++ }
++ /* Someone already cleaned up the buffer? */
++ if (!buffer_jbd(bh)
++ || jh->b_transaction != commit_transaction
++ || jh->b_jlist != BJ_SyncData) {
++ jbd_unlock_bh_state(bh);
++ if (locked)
++ unlock_buffer(bh);
++ BUFFER_TRACE(bh, "already cleaned up");
++ put_bh(bh);
++ continue;
++ }
++ if (locked && test_clear_buffer_dirty(bh)) {
++ BUFFER_TRACE(bh, "needs writeout, adding to array");
++ wbuf[bufs++] = bh;
++ __journal_file_buffer(jh, commit_transaction,
++ BJ_Locked);
++ jbd_unlock_bh_state(bh);
++ if (bufs == journal->j_wbufsize) {
++ spin_unlock(&journal->j_list_lock);
++ journal_do_submit_data(wbuf, bufs);
++ bufs = 0;
++ goto write_out_data;
++ }
++ }
++ else {
++ BUFFER_TRACE(bh, "writeout complete: unfile");
++ __journal_unfile_buffer(jh);
++ jbd_unlock_bh_state(bh);
++ if (locked)
++ unlock_buffer(bh);
++ journal_remove_journal_head(bh);
++ /* Once for our safety reference, once for
++ * journal_remove_journal_head() */
++ put_bh(bh);
++ put_bh(bh);
++ }
++
++ if (lock_need_resched(&journal->j_list_lock)) {
++ spin_unlock(&journal->j_list_lock);
++ goto write_out_data;
++ }
++ }
++ spin_unlock(&journal->j_list_lock);
++ journal_do_submit_data(wbuf, bufs);
++}
++
+ /*
+ * journal_commit_transaction
+ *
+@@ -313,80 +424,13 @@ void journal_commit_transaction(journal_
+ * Now start flushing things to disk, in the order they appear
+ * on the transaction lists. Data blocks go first.
+ */
+-
+ err = 0;
+- /*
+- * Whenever we unlock the journal and sleep, things can get added
+- * onto ->t_sync_datalist, so we have to keep looping back to
+- * write_out_data until we *know* that the list is empty.
+- */
+- bufs = 0;
+- /*
+- * Cleanup any flushed data buffers from the data list. Even in
+- * abort mode, we want to flush this out as soon as possible.
+- */
+-write_out_data:
+- cond_resched();
+- spin_lock(&journal->j_list_lock);
+-
+- while (commit_transaction->t_sync_datalist) {
+- struct buffer_head *bh;
+-
+- jh = commit_transaction->t_sync_datalist;
+- commit_transaction->t_sync_datalist = jh->b_tnext;
+- bh = jh2bh(jh);
+- if (buffer_locked(bh)) {
+- BUFFER_TRACE(bh, "locked");
+- if (!inverted_lock(journal, bh))
+- goto write_out_data;
+- __journal_temp_unlink_buffer(jh);
+- __journal_file_buffer(jh, commit_transaction,
+- BJ_Locked);
+- jbd_unlock_bh_state(bh);
+- if (lock_need_resched(&journal->j_list_lock)) {
+- spin_unlock(&journal->j_list_lock);
+- goto write_out_data;
+- }
+- } else {
+- if (buffer_dirty(bh)) {
+- BUFFER_TRACE(bh, "start journal writeout");
+- get_bh(bh);
+- wbuf[bufs++] = bh;
+- if (bufs == journal->j_wbufsize) {
+- jbd_debug(2, "submit %d writes\n",
+- bufs);
+- spin_unlock(&journal->j_list_lock);
+- ll_rw_block(SWRITE, bufs, wbuf);
+- journal_brelse_array(wbuf, bufs);
+- bufs = 0;
+- goto write_out_data;
+- }
+- } else {
+- BUFFER_TRACE(bh, "writeout complete: unfile");
+- if (!inverted_lock(journal, bh))
+- goto write_out_data;
+- __journal_unfile_buffer(jh);
+- jbd_unlock_bh_state(bh);
+- journal_remove_journal_head(bh);
+- put_bh(bh);
+- if (lock_need_resched(&journal->j_list_lock)) {
+- spin_unlock(&journal->j_list_lock);
+- goto write_out_data;
+- }
+- }
+- }
+- }
+-
+- if (bufs) {
+- spin_unlock(&journal->j_list_lock);
+- ll_rw_block(SWRITE, bufs, wbuf);
+- journal_brelse_array(wbuf, bufs);
+- spin_lock(&journal->j_list_lock);
+- }
++ journal_submit_data_buffers(journal, commit_transaction);
+
+ /*
+ * Wait for all previously submitted IO to complete.
+ */
++ spin_lock(&journal->j_list_lock);
+ while (commit_transaction->t_locked_list) {
+ struct buffer_head *bh;
+
+diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
+index f66724c..b85c686 100644
+--- a/fs/jbd/journal.c
++++ b/fs/jbd/journal.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/journal.c
++ * linux/fs/jbd/journal.c
+ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>, 1998
+ *
+@@ -181,7 +181,7 @@ loop:
+ transaction->t_expires))
+ should_sleep = 0;
+ if (journal->j_flags & JFS_UNMOUNT)
+- should_sleep = 0;
++ should_sleep = 0;
+ if (should_sleep) {
+ spin_unlock(&journal->j_state_lock);
+ schedule();
+@@ -271,7 +271,7 @@ static void journal_kill_thread(journal_
+ int journal_write_metadata_buffer(transaction_t *transaction,
+ struct journal_head *jh_in,
+ struct journal_head **jh_out,
+- int blocknr)
++ unsigned long blocknr)
+ {
+ int need_copy_out = 0;
+ int done_copy_out = 0;
+@@ -578,7 +578,7 @@ int journal_next_log_block(journal_t *jo
+ * this is a no-op. If needed, we can use j_blk_offset - everything is
+ * ready.
+ */
+-int journal_bmap(journal_t *journal, unsigned long blocknr,
++int journal_bmap(journal_t *journal, unsigned long blocknr,
+ unsigned long *retp)
+ {
+ int err = 0;
+@@ -696,13 +696,13 @@ fail:
+ * @bdev: Block device on which to create the journal
+ * @fs_dev: Device which hold journalled filesystem for this journal.
+ * @start: Block nr Start of journal.
+- * @len: Lenght of the journal in blocks.
++ * @len: Length of the journal in blocks.
+ * @blocksize: blocksize of journalling device
+ * @returns: a newly created journal_t *
+- *
++ *
+ * journal_init_dev creates a journal which maps a fixed contiguous
+ * range of blocks on an arbitrary block device.
+- *
++ *
+ */
+ journal_t * journal_init_dev(struct block_device *bdev,
+ struct block_device *fs_dev,
+@@ -715,18 +715,8 @@ journal_t * journal_init_dev(struct bloc
+ if (!journal)
+ return NULL;
+
+- journal->j_dev = bdev;
+- journal->j_fs_dev = fs_dev;
+- journal->j_blk_offset = start;
+- journal->j_maxlen = len;
+- journal->j_blocksize = blocksize;
+-
+- bh = __getblk(journal->j_dev, start, journal->j_blocksize);
+- J_ASSERT(bh != NULL);
+- journal->j_sb_buffer = bh;
+- journal->j_superblock = (journal_superblock_t *)bh->b_data;
+-
+ /* journal descriptor can store up to n blocks -bzzz */
++ journal->j_blocksize = blocksize;
+ n = journal->j_blocksize / sizeof(journal_block_tag_t);
+ journal->j_wbufsize = n;
+ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+@@ -735,15 +725,25 @@ journal_t * journal_init_dev(struct bloc
+ __FUNCTION__);
+ kfree(journal);
+ journal = NULL;
++ goto out;
+ }
++ journal->j_dev = bdev;
++ journal->j_fs_dev = fs_dev;
++ journal->j_blk_offset = start;
++ journal->j_maxlen = len;
+
++ bh = __getblk(journal->j_dev, start, journal->j_blocksize);
++ J_ASSERT(bh != NULL);
++ journal->j_sb_buffer = bh;
++ journal->j_superblock = (journal_superblock_t *)bh->b_data;
++out:
+ return journal;
+ }
+-
+-/**
++
++/**
+ * journal_t * journal_init_inode () - creates a journal which maps to a inode.
+ * @inode: An inode to create the journal in
+- *
++ *
+ * journal_init_inode creates a journal which maps an on-disk inode as
+ * the journal. The inode must exist already, must support bmap() and
+ * must have all data blocks preallocated.
+@@ -763,7 +763,7 @@ journal_t * journal_init_inode (struct i
+ journal->j_inode = inode;
+ jbd_debug(1,
+ "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
+- journal, inode->i_sb->s_id, inode->i_ino,
++ journal, inode->i_sb->s_id, inode->i_ino,
+ (long long) inode->i_size,
+ inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
+
+@@ -798,10 +798,10 @@ journal_t * journal_init_inode (struct i
+ return journal;
+ }
+
+-/*
++/*
+ * If the journal init or create aborts, we need to mark the journal
+ * superblock as being NULL to prevent the journal destroy from writing
+- * back a bogus superblock.
++ * back a bogus superblock.
+ */
+ static void journal_fail_superblock (journal_t *journal)
+ {
+@@ -820,7 +820,7 @@ static void journal_fail_superblock (jou
+ static int journal_reset(journal_t *journal)
+ {
+ journal_superblock_t *sb = journal->j_superblock;
+- unsigned int first, last;
++ unsigned long first, last;
+
+ first = be32_to_cpu(sb->s_first);
+ last = be32_to_cpu(sb->s_maxlen);
+@@ -844,13 +844,13 @@ static int journal_reset(journal_t *jour
+ return 0;
+ }
+
+-/**
++/**
+ * int journal_create() - Initialise the new journal file
+ * @journal: Journal to create. This structure must have been initialised
+- *
++ *
+ * Given a journal_t structure which tells us which disk blocks we can
+ * use, create a new journal superblock and initialise all of the
+- * journal fields from scratch.
++ * journal fields from scratch.
+ **/
+ int journal_create(journal_t *journal)
+ {
+@@ -915,7 +915,7 @@ int journal_create(journal_t *journal)
+ return journal_reset(journal);
+ }
+
+-/**
++/**
+ * void journal_update_superblock() - Update journal sb on disk.
+ * @journal: The journal to update.
+ * @wait: Set to '0' if you don't want to wait for IO completion.
+@@ -939,7 +939,7 @@ void journal_update_superblock(journal_t
+ journal->j_transaction_sequence) {
+ jbd_debug(1,"JBD: Skipping superblock update on recovered sb "
+ "(start %ld, seq %d, errno %d)\n",
+- journal->j_tail, journal->j_tail_sequence,
++ journal->j_tail, journal->j_tail_sequence,
+ journal->j_errno);
+ goto out;
+ }
+@@ -1062,7 +1062,7 @@ static int load_superblock(journal_t *jo
+ /**
+ * int journal_load() - Read journal from disk.
+ * @journal: Journal to act on.
+- *
++ *
+ * Given a journal_t structure which tells us which disk blocks contain
+ * a journal, read the journal from disk to initialise the in-memory
+ * structures.
+@@ -1094,7 +1094,7 @@ int journal_load(journal_t *journal)
+ /*
+ * Create a slab for this blocksize
+ */
+- err = journal_create_jbd_slab(cpu_to_be32(sb->s_blocksize));
++ err = journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize));
+ if (err)
+ return err;
+
+@@ -1172,9 +1172,9 @@ void journal_destroy(journal_t *journal)
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
+- *
++ *
+ * Check whether the journal uses all of a given set of
+- * features. Return true (non-zero) if it does.
++ * features. Return true (non-zero) if it does.
+ **/
+
+ int journal_check_used_features (journal_t *journal, unsigned long compat,
+@@ -1203,7 +1203,7 @@ int journal_check_used_features (journal
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
+- *
++ *
+ * Check whether the journaling code supports the use of
+ * all of a given set of features on this journal. Return true
+ * (non-zero) if it can. */
+@@ -1241,7 +1241,7 @@ int journal_check_available_features (jo
+ * @incompat: bitmask of incompatible features
+ *
+ * Mark a given journal feature as present on the
+- * superblock. Returns true if the requested features could be set.
++ * superblock. Returns true if the requested features could be set.
+ *
+ */
+
+@@ -1327,7 +1327,7 @@ static int journal_convert_superblock_v1
+ /**
+ * int journal_flush () - Flush journal
+ * @journal: Journal to act on.
+- *
++ *
+ * Flush all data for a given journal to disk and empty the journal.
+ * Filesystems can use this when remounting readonly to ensure that
+ * recovery does not need to happen on remount.
+@@ -1394,7 +1394,7 @@ int journal_flush(journal_t *journal)
+ * int journal_wipe() - Wipe journal contents
+ * @journal: Journal to act on.
+ * @write: flag (see below)
+- *
++ *
+ * Wipe out all of the contents of a journal, safely. This will produce
+ * a warning if the journal contains any valid recovery information.
+ * Must be called between journal_init_*() and journal_load().
+@@ -1449,7 +1449,7 @@ static const char *journal_dev_name(jour
+
+ /*
+ * Journal abort has very specific semantics, which we describe
+- * for journal abort.
++ * for journal abort.
+ *
+ * Two internal function, which provide abort to te jbd layer
+ * itself are here.
+@@ -1504,7 +1504,7 @@ static void __journal_abort_soft (journa
+ * Perform a complete, immediate shutdown of the ENTIRE
+ * journal (not of a single transaction). This operation cannot be
+ * undone without closing and reopening the journal.
+- *
++ *
+ * The journal_abort function is intended to support higher level error
+ * recovery mechanisms such as the ext2/ext3 remount-readonly error
+ * mode.
+@@ -1538,7 +1538,7 @@ static void __journal_abort_soft (journa
+ * supply an errno; a null errno implies that absolutely no further
+ * writes are done to the journal (unless there are any already in
+ * progress).
+- *
++ *
+ */
+
+ void journal_abort(journal_t *journal, int errno)
+@@ -1546,7 +1546,7 @@ void journal_abort(journal_t *journal, i
+ __journal_abort_soft(journal, errno);
+ }
+
+-/**
++/**
+ * int journal_errno () - returns the journal's error state.
+ * @journal: journal to examine.
+ *
+@@ -1570,7 +1570,7 @@ int journal_errno(journal_t *journal)
+ return err;
+ }
+
+-/**
++/**
+ * int journal_clear_err () - clears the journal's error state
+ * @journal: journal to act on.
+ *
+@@ -1590,7 +1590,7 @@ int journal_clear_err(journal_t *journal
+ return err;
+ }
+
+-/**
++/**
+ * void journal_ack_err() - Ack journal err.
+ * @journal: journal to act on.
+ *
+@@ -1612,7 +1612,7 @@ int journal_blocks_per_page(struct inode
+
+ /*
+ * Simple support for retrying memory allocations. Introduced to help to
+- * debug different VM deadlock avoidance strategies.
++ * debug different VM deadlock avoidance strategies.
+ */
+ void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
+ {
+@@ -2047,13 +2047,7 @@ static int __init journal_init(void)
+ {
+ int ret;
+
+-/* Static check for data structure consistency. There's no code
+- * invoked --- we'll just get a linker failure if things aren't right.
+- */
+- extern void journal_bad_superblock_size(void);
+- if (sizeof(struct journal_superblock_s) != 1024)
+- journal_bad_superblock_size();
+-
++ BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);
+
+ ret = journal_init_caches();
+ if (ret != 0)
+diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
+index de5bafb..11563fe 100644
+--- a/fs/jbd/recovery.c
++++ b/fs/jbd/recovery.c
+@@ -1,6 +1,6 @@
+ /*
+ * linux/fs/recovery.c
+- *
++ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>, 1999
+ *
+ * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
+@@ -10,7 +10,7 @@
+ * option, any later version, incorporated herein by reference.
+ *
+ * Journal recovery routines for the generic filesystem journaling code;
+- * part of the ext2fs journaling system.
++ * part of the ext2fs journaling system.
+ */
+
+ #ifndef __KERNEL__
+@@ -25,9 +25,9 @@
+
+ /*
+ * Maintain information about the progress of the recovery job, so that
+- * the different passes can carry information between them.
++ * the different passes can carry information between them.
+ */
+-struct recovery_info
++struct recovery_info
+ {
+ tid_t start_transaction;
+ tid_t end_transaction;
+@@ -46,7 +46,7 @@ static int scan_revoke_records(journal_t
+ #ifdef __KERNEL__
+
+ /* Release readahead buffers after use */
+-void journal_brelse_array(struct buffer_head *b[], int n)
++static void journal_brelse_array(struct buffer_head *b[], int n)
+ {
+ while (--n >= 0)
+ brelse (b[n]);
+@@ -116,7 +116,7 @@ static int do_readahead(journal_t *journ
+ err = 0;
+
+ failed:
+- if (nbufs)
++ if (nbufs)
+ journal_brelse_array(bufs, nbufs);
+ return err;
+ }
+@@ -128,7 +128,7 @@ failed:
+ * Read a block from the journal
+ */
+
+-static int jread(struct buffer_head **bhp, journal_t *journal,
++static int jread(struct buffer_head **bhp, journal_t *journal,
+ unsigned int offset)
+ {
+ int err;
+@@ -212,14 +212,14 @@ do { \
+ /**
+ * journal_recover - recovers a on-disk journal
+ * @journal: the journal to recover
+- *
++ *
+ * The primary function for recovering the log contents when mounting a
+- * journaled device.
++ * journaled device.
+ *
+ * Recovery is done in three passes. In the first pass, we look for the
+ * end of the log. In the second, we assemble the list of revoke
+ * blocks. In the third and final pass, we replay any un-revoked blocks
+- * in the log.
++ * in the log.
+ */
+ int journal_recover(journal_t *journal)
+ {
+@@ -231,10 +231,10 @@ int journal_recover(journal_t *journal)
+ memset(&info, 0, sizeof(info));
+ sb = journal->j_superblock;
+
+- /*
++ /*
+ * The journal superblock's s_start field (the current log head)
+ * is always zero if, and only if, the journal was cleanly
+- * unmounted.
++ * unmounted.
+ */
+
+ if (!sb->s_start) {
+@@ -253,7 +253,7 @@ int journal_recover(journal_t *journal)
+ jbd_debug(0, "JBD: recovery, exit status %d, "
+ "recovered transactions %u to %u\n",
+ err, info.start_transaction, info.end_transaction);
+- jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
++ jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
+ info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
+
+ /* Restart the log at the next transaction ID, thus invalidating
+@@ -268,15 +268,15 @@ int journal_recover(journal_t *journal)
+ /**
+ * journal_skip_recovery - Start journal and wipe exiting records
+ * @journal: journal to startup
+- *
++ *
+ * Locate any valid recovery information from the journal and set up the
+ * journal structures in memory to ignore it (presumably because the
+- * caller has evidence that it is out of date).
++ * caller has evidence that it is out of date).
+ * This function does'nt appear to be exorted..
+ *
+ * We perform one pass over the journal to allow us to tell the user how
+ * much recovery information is being erased, and to let us initialise
+- * the journal transaction sequence numbers to the next unused ID.
++ * the journal transaction sequence numbers to the next unused ID.
+ */
+ int journal_skip_recovery(journal_t *journal)
+ {
+@@ -297,7 +297,7 @@ int journal_skip_recovery(journal_t *jou
+ #ifdef CONFIG_JBD_DEBUG
+ int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
+ #endif
+- jbd_debug(0,
++ jbd_debug(0,
+ "JBD: ignoring %d transaction%s from the journal.\n",
+ dropped, (dropped == 1) ? "" : "s");
+ journal->j_transaction_sequence = ++info.end_transaction;
+@@ -314,7 +314,7 @@ static int do_one_pass(journal_t *journa
+ unsigned long next_log_block;
+ int err, success = 0;
+ journal_superblock_t * sb;
+- journal_header_t * tmp;
++ journal_header_t * tmp;
+ struct buffer_head * bh;
+ unsigned int sequence;
+ int blocktype;
+@@ -324,10 +324,10 @@ static int do_one_pass(journal_t *journa
+ MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
+ / sizeof(journal_block_tag_t));
+
+- /*
++ /*
+ * First thing is to establish what we expect to find in the log
+ * (in terms of transaction IDs), and where (in terms of log
+- * block offsets): query the superblock.
++ * block offsets): query the superblock.
+ */
+
+ sb = journal->j_superblock;
+@@ -344,7 +344,7 @@ static int do_one_pass(journal_t *journa
+ * Now we walk through the log, transaction by transaction,
+ * making sure that each transaction has a commit block in the
+ * expected place. Each complete transaction gets replayed back
+- * into the main filesystem.
++ * into the main filesystem.
+ */
+
+ while (1) {
+@@ -379,8 +379,8 @@ static int do_one_pass(journal_t *journa
+ next_log_block++;
+ wrap(journal, next_log_block);
+
+- /* What kind of buffer is it?
+- *
++ /* What kind of buffer is it?
++ *
+ * If it is a descriptor block, check that it has the
+ * expected sequence number. Otherwise, we're all done
+ * here. */
+@@ -394,7 +394,7 @@ static int do_one_pass(journal_t *journa
+
+ blocktype = be32_to_cpu(tmp->h_blocktype);
+ sequence = be32_to_cpu(tmp->h_sequence);
+- jbd_debug(3, "Found magic %d, sequence %d\n",
++ jbd_debug(3, "Found magic %d, sequence %d\n",
+ blocktype, sequence);
+
+ if (sequence != next_commit_ID) {
+@@ -438,7 +438,7 @@ static int do_one_pass(journal_t *journa
+ /* Recover what we can, but
+ * report failure at the end. */
+ success = err;
+- printk (KERN_ERR
++ printk (KERN_ERR
+ "JBD: IO error %d recovering "
+ "block %ld in log\n",
+ err, io_block);
+@@ -452,7 +452,7 @@ static int do_one_pass(journal_t *journa
+ * revoked, then we're all done
+ * here. */
+ if (journal_test_revoke
+- (journal, blocknr,
++ (journal, blocknr,
+ next_commit_ID)) {
+ brelse(obh);
+ ++info->nr_revoke_hits;
+@@ -465,7 +465,7 @@ static int do_one_pass(journal_t *journa
+ blocknr,
+ journal->j_blocksize);
+ if (nbh == NULL) {
+- printk(KERN_ERR
++ printk(KERN_ERR
+ "JBD: Out of memory "
+ "during recovery.\n");
+ err = -ENOMEM;
+@@ -537,7 +537,7 @@ static int do_one_pass(journal_t *journa
+ }
+
+ done:
+- /*
++ /*
+ * We broke out of the log scan loop: either we came to the
+ * known end of the log or we found an unexpected block in the
+ * log. If the latter happened, then we know that the "current"
+@@ -567,7 +567,7 @@ static int do_one_pass(journal_t *journa
+
+ /* Scan a revoke record, marking all blocks mentioned as revoked. */
+
+-static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
++static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+ tid_t sequence, struct recovery_info *info)
+ {
+ journal_revoke_header_t *header;
+diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
+index a561441..c532429 100644
+--- a/fs/jbd/revoke.c
++++ b/fs/jbd/revoke.c
+@@ -1,6 +1,6 @@
+ /*
+ * linux/fs/revoke.c
+- *
++ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>, 2000
+ *
+ * Copyright 2000 Red Hat corp --- All Rights Reserved
+@@ -15,10 +15,10 @@
+ * Revoke is the mechanism used to prevent old log records for deleted
+ * metadata from being replayed on top of newer data using the same
+ * blocks. The revoke mechanism is used in two separate places:
+- *
++ *
+ * + Commit: during commit we write the entire list of the current
+ * transaction's revoked blocks to the journal
+- *
++ *
+ * + Recovery: during recovery we record the transaction ID of all
+ * revoked blocks. If there are multiple revoke records in the log
+ * for a single block, only the last one counts, and if there is a log
+@@ -29,7 +29,7 @@
+ * single transaction:
+ *
+ * Block is revoked and then journaled:
+- * The desired end result is the journaling of the new block, so we
++ * The desired end result is the journaling of the new block, so we
+ * cancel the revoke before the transaction commits.
+ *
+ * Block is journaled and then revoked:
+@@ -41,7 +41,7 @@
+ * transaction must have happened after the block was journaled and so
+ * the revoke must take precedence.
+ *
+- * Block is revoked and then written as data:
++ * Block is revoked and then written as data:
+ * The data write is allowed to succeed, but the revoke is _not_
+ * cancelled. We still need to prevent old log records from
+ * overwriting the new data. We don't even need to clear the revoke
+@@ -54,7 +54,7 @@
+ * buffer has not been revoked, and cancel_revoke
+ * need do nothing.
+ * RevokeValid set, Revoked set:
+- * buffer has been revoked.
++ * buffer has been revoked.
+ */
+
+ #ifndef __KERNEL__
+@@ -77,7 +77,7 @@ static kmem_cache_t *revoke_table_cache;
+ journal replay, this involves recording the transaction ID of the
+ last transaction to revoke this block. */
+
+-struct jbd_revoke_record_s
++struct jbd_revoke_record_s
+ {
+ struct list_head hash;
+ tid_t sequence; /* Used for recovery only */
+@@ -90,8 +90,8 @@ struct jbd_revoke_table_s
+ {
+ /* It is conceivable that we might want a larger hash table
+ * for recovery. Must be a power of two. */
+- int hash_size;
+- int hash_shift;
++ int hash_size;
++ int hash_shift;
+ struct list_head *hash_table;
+ };
+
+@@ -301,22 +301,22 @@ void journal_destroy_revoke(journal_t *j
+
+ #ifdef __KERNEL__
+
+-/*
++/*
+ * journal_revoke: revoke a given buffer_head from the journal. This
+ * prevents the block from being replayed during recovery if we take a
+ * crash after this current transaction commits. Any subsequent
+ * metadata writes of the buffer in this transaction cancel the
+- * revoke.
++ * revoke.
+ *
+ * Note that this call may block --- it is up to the caller to make
+ * sure that there are no further calls to journal_write_metadata
+ * before the revoke is complete. In ext3, this implies calling the
+ * revoke before clearing the block bitmap when we are deleting
+- * metadata.
++ * metadata.
+ *
+ * Revoke performs a journal_forget on any buffer_head passed in as a
+ * parameter, but does _not_ forget the buffer_head if the bh was only
+- * found implicitly.
++ * found implicitly.
+ *
+ * bh_in may not be a journalled buffer - it may have come off
+ * the hash tables without an attached journal_head.
+@@ -325,7 +325,7 @@ void journal_destroy_revoke(journal_t *j
+ * by one.
+ */
+
+-int journal_revoke(handle_t *handle, unsigned long blocknr,
++int journal_revoke(handle_t *handle, unsigned long blocknr,
+ struct buffer_head *bh_in)
+ {
+ struct buffer_head *bh = NULL;
+@@ -487,7 +487,7 @@ void journal_switch_revoke_table(journal
+ else
+ journal->j_revoke = journal->j_revoke_table[0];
+
+- for (i = 0; i < journal->j_revoke->hash_size; i++)
++ for (i = 0; i < journal->j_revoke->hash_size; i++)
+ INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
+ }
+
+@@ -498,7 +498,7 @@ void journal_switch_revoke_table(journal
+ * Called with the journal lock held.
+ */
+
+-void journal_write_revoke_records(journal_t *journal,
++void journal_write_revoke_records(journal_t *journal,
+ transaction_t *transaction)
+ {
+ struct journal_head *descriptor;
+@@ -507,7 +507,7 @@ void journal_write_revoke_records(journa
+ struct list_head *hash_list;
+ int i, offset, count;
+
+- descriptor = NULL;
++ descriptor = NULL;
+ offset = 0;
+ count = 0;
+
+@@ -519,10 +519,10 @@ void journal_write_revoke_records(journa
+ hash_list = &revoke->hash_table[i];
+
+ while (!list_empty(hash_list)) {
+- record = (struct jbd_revoke_record_s *)
++ record = (struct jbd_revoke_record_s *)
+ hash_list->next;
+ write_one_revoke_record(journal, transaction,
+- &descriptor, &offset,
++ &descriptor, &offset,
+ record);
+ count++;
+ list_del(&record->hash);
+@@ -534,14 +534,14 @@ void journal_write_revoke_records(journa
+ jbd_debug(1, "Wrote %d revoke records\n", count);
+ }
+
+-/*
++/*
+ * Write out one revoke record. We need to create a new descriptor
+- * block if the old one is full or if we have not already created one.
++ * block if the old one is full or if we have not already created one.
+ */
+
+-static void write_one_revoke_record(journal_t *journal,
++static void write_one_revoke_record(journal_t *journal,
+ transaction_t *transaction,
+- struct journal_head **descriptorp,
++ struct journal_head **descriptorp,
+ int *offsetp,
+ struct jbd_revoke_record_s *record)
+ {
+@@ -584,21 +584,21 @@ static void write_one_revoke_record(jour
+ *descriptorp = descriptor;
+ }
+
+- * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
++ * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
+ cpu_to_be32(record->blocknr);
+ offset += 4;
+ *offsetp = offset;
+ }
+
+-/*
++/*
+ * Flush a revoke descriptor out to the journal. If we are aborting,
+ * this is a noop; otherwise we are generating a buffer which needs to
+ * be waited for during commit, so it has to go onto the appropriate
+ * journal buffer list.
+ */
+
+-static void flush_descriptor(journal_t *journal,
+- struct journal_head *descriptor,
++static void flush_descriptor(journal_t *journal,
++ struct journal_head *descriptor,
+ int offset)
+ {
+ journal_revoke_header_t *header;
+@@ -618,7 +618,7 @@ static void flush_descriptor(journal_t *
+ }
+ #endif
+
+-/*
++/*
+ * Revoke support for recovery.
+ *
+ * Recovery needs to be able to:
+@@ -629,7 +629,7 @@ static void flush_descriptor(journal_t *
+ * check whether a given block in a given transaction should be replayed
+ * (ie. has not been revoked by a revoke record in that or a subsequent
+ * transaction)
+- *
++ *
+ * empty the revoke table after recovery.
+ */
+
+@@ -637,11 +637,11 @@ static void flush_descriptor(journal_t *
+ * First, setting revoke records. We create a new revoke record for
+ * every block ever revoked in the log as we scan it for recovery, and
+ * we update the existing records if we find multiple revokes for a
+- * single block.
++ * single block.
+ */
+
+-int journal_set_revoke(journal_t *journal,
+- unsigned long blocknr,
++int journal_set_revoke(journal_t *journal,
++ unsigned long blocknr,
+ tid_t sequence)
+ {
+ struct jbd_revoke_record_s *record;
+@@ -653,18 +653,18 @@ int journal_set_revoke(journal_t *journa
+ if (tid_gt(sequence, record->sequence))
+ record->sequence = sequence;
+ return 0;
+- }
++ }
+ return insert_revoke_hash(journal, blocknr, sequence);
+ }
+
+-/*
++/*
+ * Test revoke records. For a given block referenced in the log, has
+ * that block been revoked? A revoke record with a given transaction
+ * sequence number revokes all blocks in that transaction and earlier
+ * ones, but later transactions still need replayed.
+ */
+
+-int journal_test_revoke(journal_t *journal,
++int journal_test_revoke(journal_t *journal,
+ unsigned long blocknr,
+ tid_t sequence)
+ {
+diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
+index f5169a9..4f82bcd 100644
+--- a/fs/jbd/transaction.c
++++ b/fs/jbd/transaction.c
+@@ -1,6 +1,6 @@
+ /*
+ * linux/fs/transaction.c
+- *
++ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+@@ -10,7 +10,7 @@
+ * option, any later version, incorporated herein by reference.
+ *
+ * Generic filesystem transaction handling code; part of the ext2fs
+- * journaling system.
++ * journaling system.
+ *
+ * This file manages transactions (compound commits managed by the
+ * journaling code) and handles (individual atomic operations by the
+@@ -74,7 +74,7 @@ get_transaction(journal_t *journal, tran
+ * start_this_handle: Given a handle, deal with any locking or stalling
+ * needed to make sure that there is enough journal space for the handle
+ * to begin. Attach the handle to a transaction and set up the
+- * transaction's buffer credits.
++ * transaction's buffer credits.
+ */
+
+ static int start_this_handle(journal_t *journal, handle_t *handle)
+@@ -117,7 +117,7 @@ repeat_locked:
+ if (is_journal_aborted(journal) ||
+ (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) {
+ spin_unlock(&journal->j_state_lock);
+- ret = -EROFS;
++ ret = -EROFS;
+ goto out;
+ }
+
+@@ -182,7 +182,7 @@ repeat_locked:
+ goto repeat;
+ }
+
+- /*
++ /*
+ * The commit code assumes that it can get enough log space
+ * without forcing a checkpoint. This is *critical* for
+ * correctness: a checkpoint of a buffer which is also
+@@ -191,7 +191,7 @@ repeat_locked:
+ *
+ * We must therefore ensure the necessary space in the journal
+ * *before* starting to dirty potentially checkpointed buffers
+- * in the new transaction.
++ * in the new transaction.
+ *
+ * The worst part is, any transaction currently committing can
+ * reduce the free space arbitrarily. Be careful to account for
+@@ -246,13 +246,13 @@ static handle_t *new_handle(int nblocks)
+ }
+
+ /**
+- * handle_t *journal_start() - Obtain a new handle.
++ * handle_t *journal_start() - Obtain a new handle.
+ * @journal: Journal to start transaction on.
+ * @nblocks: number of block buffer we might modify
+ *
+ * We make sure that the transaction can guarantee at least nblocks of
+ * modified buffers in the log. We block until the log can guarantee
+- * that much space.
++ * that much space.
+ *
+ * This function is visible to journal users (like ext3fs), so is not
+ * called with the journal already locked.
+@@ -292,11 +292,11 @@ handle_t *journal_start(journal_t *journ
+ * int journal_extend() - extend buffer credits.
+ * @handle: handle to 'extend'
+ * @nblocks: nr blocks to try to extend by.
+- *
++ *
+ * Some transactions, such as large extends and truncates, can be done
+ * atomically all at once or in several stages. The operation requests
+ * a credit for a number of buffer modications in advance, but can
+- * extend its credit if it needs more.
++ * extend its credit if it needs more.
+ *
+ * journal_extend tries to give the running handle more buffer credits.
+ * It does not guarantee that allocation - this is a best-effort only.
+@@ -363,7 +363,7 @@ out:
+ * int journal_restart() - restart a handle .
+ * @handle: handle to restart
+ * @nblocks: nr credits requested
+- *
++ *
+ * Restart a handle for a multi-transaction filesystem
+ * operation.
+ *
+@@ -462,7 +462,7 @@ void journal_lock_updates(journal_t *jou
+ /**
+ * void journal_unlock_updates (journal_t* journal) - release barrier
+ * @journal: Journal to release the barrier on.
+- *
++ *
+ * Release a transaction barrier obtained with journal_lock_updates().
+ *
+ * Should be called without the journal lock held.
+@@ -547,8 +547,8 @@ repeat:
+ jbd_lock_bh_state(bh);
+
+ /* We now hold the buffer lock so it is safe to query the buffer
+- * state. Is the buffer dirty?
+- *
++ * state. Is the buffer dirty?
++ *
+ * If so, there are two possibilities. The buffer may be
+ * non-journaled, and undergoing a quite legitimate writeback.
+ * Otherwise, it is journaled, and we don't expect dirty buffers
+@@ -566,7 +566,7 @@ repeat:
+ */
+ if (jh->b_transaction) {
+ J_ASSERT_JH(jh,
+- jh->b_transaction == transaction ||
++ jh->b_transaction == transaction ||
+ jh->b_transaction ==
+ journal->j_committing_transaction);
+ if (jh->b_next_transaction)
+@@ -580,7 +580,7 @@ repeat:
+ */
+ JBUFFER_TRACE(jh, "Unexpected dirty buffer");
+ jbd_unexpected_dirty_buffer(jh);
+- }
++ }
+
+ unlock_buffer(bh);
+
+@@ -653,7 +653,7 @@ repeat:
+ * buffer had better remain locked during the kmalloc,
+ * but that should be true --- we hold the journal lock
+ * still and the buffer is already on the BUF_JOURNAL
+- * list so won't be flushed.
++ * list so won't be flushed.
+ *
+ * Subtle point, though: if this is a get_undo_access,
+ * then we will be relying on the frozen_data to contain
+@@ -765,8 +765,8 @@ int journal_get_write_access(handle_t *h
+ * manually rather than reading off disk), then we need to keep the
+ * buffer_head locked until it has been completely filled with new
+ * data. In this case, we should be able to make the assertion that
+- * the bh is not already part of an existing transaction.
+- *
++ * the bh is not already part of an existing transaction.
++ *
+ * The buffer should already be locked by the caller by this point.
+ * There is no lock ranking violation: it was a newly created,
+ * unlocked buffer beforehand. */
+@@ -778,7 +778,7 @@ int journal_get_write_access(handle_t *h
+ *
+ * Call this if you create a new bh.
+ */
+-int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
++int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
+ {
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+@@ -847,13 +847,13 @@ out:
+ * do not reuse freed space until the deallocation has been committed,
+ * since if we overwrote that space we would make the delete
+ * un-rewindable in case of a crash.
+- *
++ *
+ * To deal with that, journal_get_undo_access requests write access to a
+ * buffer for parts of non-rewindable operations such as delete
+ * operations on the bitmaps. The journaling code must keep a copy of
+ * the buffer's contents prior to the undo_access call until such time
+ * as we know that the buffer has definitely been committed to disk.
+- *
++ *
+ * We never need to know which transaction the committed data is part
+ * of, buffers touched here are guaranteed to be dirtied later and so
+ * will be committed to a new transaction in due course, at which point
+@@ -911,13 +911,13 @@ out:
+ return err;
+ }
+
+-/**
++/**
+ * int journal_dirty_data() - mark a buffer as containing dirty data which
+ * needs to be flushed before we can commit the
+- * current transaction.
++ * current transaction.
+ * @handle: transaction
+ * @bh: bufferhead to mark
+- *
++ *
+ * The buffer is placed on the transaction's data list and is marked as
+ * belonging to the transaction.
+ *
+@@ -946,15 +946,15 @@ int journal_dirty_data(handle_t *handle,
+
+ /*
+ * What if the buffer is already part of a running transaction?
+- *
++ *
+ * There are two cases:
+ * 1) It is part of the current running transaction. Refile it,
+ * just in case we have allocated it as metadata, deallocated
+- * it, then reallocated it as data.
++ * it, then reallocated it as data.
+ * 2) It is part of the previous, still-committing transaction.
+ * If all we want to do is to guarantee that the buffer will be
+ * written to disk before this new transaction commits, then
+- * being sure that the *previous* transaction has this same
++ * being sure that the *previous* transaction has this same
+ * property is sufficient for us! Just leave it on its old
+ * transaction.
+ *
+@@ -967,6 +967,13 @@ int journal_dirty_data(handle_t *handle,
+ */
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
++
++ /* Now that we have bh_state locked, are we really still mapped? */
++ if (!buffer_mapped(bh)) {
++ JBUFFER_TRACE(jh, "unmapped buffer, bailing out");
++ goto no_journal;
++ }
++
+ if (jh->b_transaction) {
+ JBUFFER_TRACE(jh, "has transaction");
+ if (jh->b_transaction != handle->h_transaction) {
+@@ -1028,6 +1035,11 @@ int journal_dirty_data(handle_t *handle,
+ sync_dirty_buffer(bh);
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
++ /* Since we dropped the lock... */
++ if (!buffer_mapped(bh)) {
++ JBUFFER_TRACE(jh, "buffer got unmapped");
++ goto no_journal;
++ }
+ /* The buffer may become locked again at any
+ time if it is redirtied */
+ }
+@@ -1076,18 +1088,18 @@ no_journal:
+ return 0;
+ }
+
+-/**
++/**
+ * int journal_dirty_metadata() - mark a buffer as containing dirty metadata
+ * @handle: transaction to add buffer to.
+- * @bh: buffer to mark
+- *
++ * @bh: buffer to mark
++ *
+ * mark dirty metadata which needs to be journaled as part of the current
+ * transaction.
+ *
+ * The buffer is placed on the transaction's metadata list and is marked
+- * as belonging to the transaction.
++ * as belonging to the transaction.
+ *
+- * Returns error number or 0 on success.
++ * Returns error number or 0 on success.
+ *
+ * Special care needs to be taken if the buffer already belongs to the
+ * current committing transaction (in which case we should have frozen
+@@ -1135,11 +1147,11 @@ int journal_dirty_metadata(handle_t *han
+
+ set_buffer_jbddirty(bh);
+
+- /*
++ /*
+ * Metadata already on the current transaction list doesn't
+ * need to be filed. Metadata on another transaction's list must
+ * be committing, and will be refiled once the commit completes:
+- * leave it alone for now.
++ * leave it alone for now.
+ */
+ if (jh->b_transaction != transaction) {
+ JBUFFER_TRACE(jh, "already on other transaction");
+@@ -1165,7 +1177,7 @@ out:
+ return 0;
+ }
+
+-/*
++/*
+ * journal_release_buffer: undo a get_write_access without any buffer
+ * updates, if the update decided in the end that it didn't need access.
+ *
+@@ -1176,20 +1188,20 @@ journal_release_buffer(handle_t *handle,
+ BUFFER_TRACE(bh, "entry");
+ }
+
+-/**
++/**
+ * void journal_forget() - bforget() for potentially-journaled buffers.
+ * @handle: transaction handle
+ * @bh: bh to 'forget'
+ *
+ * We can only do the bforget if there are no commits pending against the
+ * buffer. If the buffer is dirty in the current running transaction we
+- * can safely unlink it.
++ * can safely unlink it.
+ *
+ * bh may not be a journalled buffer at all - it may be a non-JBD
+ * buffer which came off the hashtable. Check for this.
+ *
+ * Decrements bh->b_count by one.
+- *
++ *
+ * Allow this call even if the handle has aborted --- it may be part of
+ * the caller's cleanup after an abort.
+ */
+@@ -1237,7 +1249,7 @@ int journal_forget (handle_t *handle, st
+
+ drop_reserve = 1;
+
+- /*
++ /*
+ * We are no longer going to journal this buffer.
+ * However, the commit of this transaction is still
+ * important to the buffer: the delete that we are now
+@@ -1246,7 +1258,7 @@ int journal_forget (handle_t *handle, st
+ *
+ * So, if we have a checkpoint on the buffer, we should
+ * now refile the buffer on our BJ_Forget list so that
+- * we know to remove the checkpoint after we commit.
++ * we know to remove the checkpoint after we commit.
+ */
+
+ if (jh->b_cp_transaction) {
+@@ -1264,7 +1276,7 @@ int journal_forget (handle_t *handle, st
+ }
+ }
+ } else if (jh->b_transaction) {
+- J_ASSERT_JH(jh, (jh->b_transaction ==
++ J_ASSERT_JH(jh, (jh->b_transaction ==
+ journal->j_committing_transaction));
+ /* However, if the buffer is still owned by a prior
+ * (committing) transaction, we can't drop it yet... */
+@@ -1294,7 +1306,7 @@ drop:
+ /**
+ * int journal_stop() - complete a transaction
+ * @handle: tranaction to complete.
+- *
++ *
+ * All done for a particular handle.
+ *
+ * There is not much action needed here. We just return any remaining
+@@ -1303,7 +1315,7 @@ drop:
+ * filesystem is marked for synchronous update.
+ *
+ * journal_stop itself will not usually return an error, but it may
+- * do so in unusual circumstances. In particular, expect it to
++ * do so in unusual circumstances. In particular, expect it to
+ * return -EIO if a journal_abort has been executed since the
+ * transaction began.
+ */
+@@ -1314,13 +1326,14 @@ int journal_stop(handle_t *handle)
+ int old_handle_count, err;
+ pid_t pid;
+
+- J_ASSERT(transaction->t_updates > 0);
+ J_ASSERT(journal_current_handle() == handle);
+
+ if (is_handle_aborted(handle))
+ err = -EIO;
+- else
++ else {
++ J_ASSERT(transaction->t_updates > 0);
+ err = 0;
++ }
+
+ if (--handle->h_ref > 0) {
+ jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
+@@ -1373,7 +1386,7 @@ int journal_stop(handle_t *handle)
+ if (handle->h_sync ||
+ transaction->t_outstanding_credits >
+ journal->j_max_transaction_buffers ||
+- time_after_eq(jiffies, transaction->t_expires)) {
++ time_after_eq(jiffies, transaction->t_expires)) {
+ /* Do this even for aborted journals: an abort still
+ * completes the commit thread, it just doesn't write
+ * anything to disk. */
+@@ -1388,7 +1401,7 @@ int journal_stop(handle_t *handle)
+
+ /*
+ * Special case: JFS_SYNC synchronous updates require us
+- * to wait for the commit to complete.
++ * to wait for the commit to complete.
+ */
+ if (handle->h_sync && !(current->flags & PF_MEMALLOC))
+ err = log_wait_commit(journal, tid);
+@@ -1439,7 +1452,7 @@ int journal_force_commit(journal_t *jour
+ * jbd_lock_bh_state(jh2bh(jh)) is held.
+ */
+
+-static inline void
++static inline void
+ __blist_add_buffer(struct journal_head **list, struct journal_head *jh)
+ {
+ if (!*list) {
+@@ -1454,7 +1467,7 @@ __blist_add_buffer(struct journal_head *
+ }
+ }
+
+-/*
++/*
+ * Remove a buffer from a transaction list, given the transaction's list
+ * head pointer.
+ *
+@@ -1475,7 +1488,7 @@ __blist_del_buffer(struct journal_head *
+ jh->b_tnext->b_tprev = jh->b_tprev;
+ }
+
+-/*
++/*
+ * Remove a buffer from the appropriate transaction list.
+ *
+ * Note that this function can *change* the value of
+@@ -1595,17 +1608,17 @@ out:
+ }
+
+
+-/**
++/**
+ * int journal_try_to_free_buffers() - try to free page buffers.
+ * @journal: journal for operation
+ * @page: to try and free
+ * @unused_gfp_mask: unused
+ *
+- *
++ *
+ * For all the buffers on this page,
+ * if they are fully written out ordered data, move them onto BUF_CLEAN
+ * so try_to_free_buffers() can reap them.
+- *
++ *
+ * This function returns non-zero if we wish try_to_free_buffers()
+ * to be called. We do this if the page is releasable by try_to_free_buffers().
+ * We also do it if the page has locked or dirty buffers and the caller wants
+@@ -1629,7 +1642,7 @@ out:
+ * cannot happen because we never reallocate freed data as metadata
+ * while the data is part of a transaction. Yes?
+ */
+-int journal_try_to_free_buffers(journal_t *journal,
++int journal_try_to_free_buffers(journal_t *journal,
+ struct page *page, gfp_t unused_gfp_mask)
+ {
+ struct buffer_head *head;
+@@ -1697,7 +1710,7 @@ static int __dispose_buffer(struct journ
+ }
+
+ /*
+- * journal_invalidatepage
++ * journal_invalidatepage
+ *
+ * This code is tricky. It has a number of cases to deal with.
+ *
+@@ -1705,15 +1718,15 @@ static int __dispose_buffer(struct journ
+ *
+ * i_size must be updated on disk before we start calling invalidatepage on the
+ * data.
+- *
++ *
+ * This is done in ext3 by defining an ext3_setattr method which
+ * updates i_size before truncate gets going. By maintaining this
+ * invariant, we can be sure that it is safe to throw away any buffers
+ * attached to the current transaction: once the transaction commits,
+ * we know that the data will not be needed.
+- *
++ *
+ * Note however that we can *not* throw away data belonging to the
+- * previous, committing transaction!
++ * previous, committing transaction!
+ *
+ * Any disk blocks which *are* part of the previous, committing
+ * transaction (and which therefore cannot be discarded immediately) are
+@@ -1732,7 +1745,7 @@ static int __dispose_buffer(struct journ
+ * don't make guarantees about the order in which data hits disk --- in
+ * particular we don't guarantee that new dirty data is flushed before
+ * transaction commit --- so it is always safe just to discard data
+- * immediately in that mode. --sct
++ * immediately in that mode. --sct
+ */
+
+ /*
+@@ -1823,6 +1836,7 @@ static int journal_unmap_buffer(journal_
+ }
+ }
+ } else if (transaction == journal->j_committing_transaction) {
++ JBUFFER_TRACE(jh, "on committing transaction");
+ if (jh->b_jlist == BJ_Locked) {
+ /*
+ * The buffer is on the committing transaction's locked
+@@ -1837,7 +1851,6 @@ static int journal_unmap_buffer(journal_
+ * can remove it's next_transaction pointer from the
+ * running transaction if that is set, but nothing
+ * else. */
+- JBUFFER_TRACE(jh, "on committing transaction");
+ set_buffer_freed(bh);
+ if (jh->b_next_transaction) {
+ J_ASSERT(jh->b_next_transaction ==
+@@ -1857,6 +1870,7 @@ static int journal_unmap_buffer(journal_
+ * i_size already for this truncate so recovery will not
+ * expose the disk blocks we are discarding here.) */
+ J_ASSERT_JH(jh, transaction == journal->j_running_transaction);
++ JBUFFER_TRACE(jh, "on running transaction");
+ may_free = __dispose_buffer(jh, transaction);
+ }
+
+@@ -1876,9 +1890,9 @@ zap_buffer_unlocked:
+ return may_free;
+ }
+
+-/**
++/**
+ * void journal_invalidatepage()
+- * @journal: journal to use for flush...
++ * @journal: journal to use for flush...
+ * @page: page to flush
+ * @offset: length of page to invalidate.
+ *
+@@ -1886,7 +1900,7 @@ zap_buffer_unlocked:
+ *
+ */
+ void journal_invalidatepage(journal_t *journal,
+- struct page *page,
++ struct page *page,
+ unsigned long offset)
+ {
+ struct buffer_head *head, *bh, *next;
+@@ -1908,7 +1922,7 @@ void journal_invalidatepage(journal_t *j
+ next = bh->b_this_page;
+
+ if (offset <= curr_off) {
+- /* This block is wholly outside the truncation point */
++ /* This block is wholly outside the truncation point */
+ lock_buffer(bh);
+ may_free &= journal_unmap_buffer(journal, bh);
+ unlock_buffer(bh);
+@@ -1924,8 +1938,8 @@ void journal_invalidatepage(journal_t *j
+ }
+ }
+
+-/*
+- * File a buffer on the given transaction list.
++/*
++ * File a buffer on the given transaction list.
+ */
+ void __journal_file_buffer(struct journal_head *jh,
+ transaction_t *transaction, int jlist)
+@@ -1948,7 +1962,7 @@ void __journal_file_buffer(struct journa
+ * with __jbd_unexpected_dirty_buffer()'s handling of dirty
+ * state. */
+
+- if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
++ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
+ jlist == BJ_Shadow || jlist == BJ_Forget) {
+ if (test_clear_buffer_dirty(bh) ||
+ test_clear_buffer_jbddirty(bh))
+@@ -2008,7 +2022,7 @@ void journal_file_buffer(struct journal_
+ jbd_unlock_bh_state(jh2bh(jh));
+ }
+
+-/*
++/*
+ * Remove a buffer from its current buffer list in preparation for
+ * dropping it from its current transaction entirely. If the buffer has
+ * already started to be used by a subsequent transaction, refile the
+@@ -2060,7 +2074,7 @@ void __journal_refile_buffer(struct jour
+ * to the caller to remove the journal_head if necessary. For the
+ * unlocked journal_refile_buffer call, the caller isn't going to be
+ * doing anything else to the buffer so we need to do the cleanup
+- * ourselves to avoid a jh leak.
++ * ourselves to avoid a jh leak.
+ *
+ * *** The journal_head may be freed by this call! ***
+ */
+diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile
+new file mode 100644
+index 0000000..802a341
+--- /dev/null
++++ b/fs/jbd2/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the linux journaling routines.
++#
++
++obj-$(CONFIG_JBD2) += jbd2.o
++
++jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+new file mode 100644
+index 0000000..68039fa
+--- /dev/null
++++ b/fs/jbd2/checkpoint.c
+@@ -0,0 +1,697 @@
++/*
++ * linux/fs/checkpoint.c
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 1999
++ *
++ * Copyright 1999 Red Hat Software --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Checkpoint routines for the generic filesystem journaling code.
++ * Part of the ext2fs journaling system.
++ *
++ * Checkpointing is the process of ensuring that a section of the log is
++ * committed fully to disk, so that that portion of the log can be
++ * reused.
++ */
++
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++
++/*
++ * Unlink a buffer from a transaction checkpoint list.
++ *
++ * Called with j_list_lock held.
++ */
++static inline void __buffer_unlink_first(struct journal_head *jh)
++{
++ transaction_t *transaction = jh->b_cp_transaction;
++
++ jh->b_cpnext->b_cpprev = jh->b_cpprev;
++ jh->b_cpprev->b_cpnext = jh->b_cpnext;
++ if (transaction->t_checkpoint_list == jh) {
++ transaction->t_checkpoint_list = jh->b_cpnext;
++ if (transaction->t_checkpoint_list == jh)
++ transaction->t_checkpoint_list = NULL;
++ }
++}
++
++/*
++ * Unlink a buffer from a transaction checkpoint(io) list.
++ *
++ * Called with j_list_lock held.
++ */
++static inline void __buffer_unlink(struct journal_head *jh)
++{
++ transaction_t *transaction = jh->b_cp_transaction;
++
++ __buffer_unlink_first(jh);
++ if (transaction->t_checkpoint_io_list == jh) {
++ transaction->t_checkpoint_io_list = jh->b_cpnext;
++ if (transaction->t_checkpoint_io_list == jh)
++ transaction->t_checkpoint_io_list = NULL;
++ }
++}
++
++/*
++ * Move a buffer from the checkpoint list to the checkpoint io list
++ *
++ * Called with j_list_lock held
++ */
++static inline void __buffer_relink_io(struct journal_head *jh)
++{
++ transaction_t *transaction = jh->b_cp_transaction;
++
++ __buffer_unlink_first(jh);
++
++ if (!transaction->t_checkpoint_io_list) {
++ jh->b_cpnext = jh->b_cpprev = jh;
++ } else {
++ jh->b_cpnext = transaction->t_checkpoint_io_list;
++ jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev;
++ jh->b_cpprev->b_cpnext = jh;
++ jh->b_cpnext->b_cpprev = jh;
++ }
++ transaction->t_checkpoint_io_list = jh;
++}
++
++/*
++ * Try to release a checkpointed buffer from its transaction.
++ * Returns 1 if we released it and 2 if we also released the
++ * whole transaction.
++ *
++ * Requires j_list_lock
++ * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
++ */
++static int __try_to_free_cp_buf(struct journal_head *jh)
++{
++ int ret = 0;
++ struct buffer_head *bh = jh2bh(jh);
++
++ if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) {
++ JBUFFER_TRACE(jh, "remove from checkpoint list");
++ ret = __jbd2_journal_remove_checkpoint(jh) + 1;
++ jbd_unlock_bh_state(bh);
++ jbd2_journal_remove_journal_head(bh);
++ BUFFER_TRACE(bh, "release");
++ __brelse(bh);
++ } else {
++ jbd_unlock_bh_state(bh);
++ }
++ return ret;
++}
++
++/*
++ * __jbd2_log_wait_for_space: wait until there is space in the journal.
++ *
++ * Called under j-state_lock *only*. It will be unlocked if we have to wait
++ * for a checkpoint to free up some space in the log.
++ */
++void __jbd2_log_wait_for_space(journal_t *journal)
++{
++ int nblocks;
++ assert_spin_locked(&journal->j_state_lock);
++
++ nblocks = jbd_space_needed(journal);
++ while (__jbd2_log_space_left(journal) < nblocks) {
++ if (journal->j_flags & JBD2_ABORT)
++ return;
++ spin_unlock(&journal->j_state_lock);
++ mutex_lock(&journal->j_checkpoint_mutex);
++
++ /*
++ * Test again, another process may have checkpointed while we
++ * were waiting for the checkpoint lock
++ */
++ spin_lock(&journal->j_state_lock);
++ nblocks = jbd_space_needed(journal);
++ if (__jbd2_log_space_left(journal) < nblocks) {
++ spin_unlock(&journal->j_state_lock);
++ jbd2_log_do_checkpoint(journal);
++ spin_lock(&journal->j_state_lock);
++ }
++ mutex_unlock(&journal->j_checkpoint_mutex);
++ }
++}
++
++/*
++ * We were unable to perform jbd_trylock_bh_state() inside j_list_lock.
++ * The caller must restart a list walk. Wait for someone else to run
++ * jbd_unlock_bh_state().
++ */
++static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
++ __releases(journal->j_list_lock)
++{
++ get_bh(bh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_lock_bh_state(bh);
++ jbd_unlock_bh_state(bh);
++ put_bh(bh);
++}
++
++/*
++ * Clean up transaction's list of buffers submitted for io.
++ * We wait for any pending IO to complete and remove any clean
++ * buffers. Note that we take the buffers in the opposite ordering
++ * from the one in which they were submitted for IO.
++ *
++ * Called with j_list_lock held.
++ */
++static void __wait_cp_io(journal_t *journal, transaction_t *transaction)
++{
++ struct journal_head *jh;
++ struct buffer_head *bh;
++ tid_t this_tid;
++ int released = 0;
++
++ this_tid = transaction->t_tid;
++restart:
++ /* Did somebody clean up the transaction in the meanwhile? */
++ if (journal->j_checkpoint_transactions != transaction ||
++ transaction->t_tid != this_tid)
++ return;
++ while (!released && transaction->t_checkpoint_io_list) {
++ jh = transaction->t_checkpoint_io_list;
++ bh = jh2bh(jh);
++ if (!jbd_trylock_bh_state(bh)) {
++ jbd_sync_bh(journal, bh);
++ spin_lock(&journal->j_list_lock);
++ goto restart;
++ }
++ if (buffer_locked(bh)) {
++ atomic_inc(&bh->b_count);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ wait_on_buffer(bh);
++ /* the journal_head may have gone by now */
++ BUFFER_TRACE(bh, "brelse");
++ __brelse(bh);
++ spin_lock(&journal->j_list_lock);
++ goto restart;
++ }
++ /*
++ * Now in whatever state the buffer currently is, we know that
++ * it has been written out and so we can drop it from the list
++ */
++ released = __jbd2_journal_remove_checkpoint(jh);
++ jbd_unlock_bh_state(bh);
++ jbd2_journal_remove_journal_head(bh);
++ __brelse(bh);
++ }
++}
++
++#define NR_BATCH 64
++
++static void
++__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
++{
++ int i;
++
++ ll_rw_block(SWRITE, *batch_count, bhs);
++ for (i = 0; i < *batch_count; i++) {
++ struct buffer_head *bh = bhs[i];
++ clear_buffer_jwrite(bh);
++ BUFFER_TRACE(bh, "brelse");
++ __brelse(bh);
++ }
++ *batch_count = 0;
++}
++
++/*
++ * Try to flush one buffer from the checkpoint list to disk.
++ *
++ * Return 1 if something happened which requires us to abort the current
++ * scan of the checkpoint list.
++ *
++ * Called with j_list_lock held and drops it if 1 is returned
++ * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
++ */
++static int __process_buffer(journal_t *journal, struct journal_head *jh,
++ struct buffer_head **bhs, int *batch_count)
++{
++ struct buffer_head *bh = jh2bh(jh);
++ int ret = 0;
++
++ if (buffer_locked(bh)) {
++ atomic_inc(&bh->b_count);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ wait_on_buffer(bh);
++ /* the journal_head may have gone by now */
++ BUFFER_TRACE(bh, "brelse");
++ __brelse(bh);
++ ret = 1;
++ } else if (jh->b_transaction != NULL) {
++ transaction_t *t = jh->b_transaction;
++ tid_t tid = t->t_tid;
++
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ jbd2_log_start_commit(journal, tid);
++ jbd2_log_wait_commit(journal, tid);
++ ret = 1;
++ } else if (!buffer_dirty(bh)) {
++ J_ASSERT_JH(jh, !buffer_jbddirty(bh));
++ BUFFER_TRACE(bh, "remove from checkpoint");
++ __jbd2_journal_remove_checkpoint(jh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ jbd2_journal_remove_journal_head(bh);
++ __brelse(bh);
++ ret = 1;
++ } else {
++ /*
++ * Important: we are about to write the buffer, and
++ * possibly block, while still holding the journal lock.
++ * We cannot afford to let the transaction logic start
++ * messing around with this buffer before we write it to
++ * disk, as that would break recoverability.
++ */
++ BUFFER_TRACE(bh, "queue");
++ get_bh(bh);
++ J_ASSERT_BH(bh, !buffer_jwrite(bh));
++ set_buffer_jwrite(bh);
++ bhs[*batch_count] = bh;
++ __buffer_relink_io(jh);
++ jbd_unlock_bh_state(bh);
++ (*batch_count)++;
++ if (*batch_count == NR_BATCH) {
++ spin_unlock(&journal->j_list_lock);
++ __flush_batch(journal, bhs, batch_count);
++ ret = 1;
++ }
++ }
++ return ret;
++}
++
++/*
++ * Perform an actual checkpoint. We take the first transaction on the
++ * list of transactions to be checkpointed and send all its buffers
++ * to disk. We submit larger chunks of data at once.
++ *
++ * The journal should be locked before calling this function.
++ */
++int jbd2_log_do_checkpoint(journal_t *journal)
++{
++ transaction_t *transaction;
++ tid_t this_tid;
++ int result;
++
++ jbd_debug(1, "Start checkpoint\n");
++
++ /*
++ * First thing: if there are any transactions in the log which
++ * don't need checkpointing, just eliminate them from the
++ * journal straight away.
++ */
++ result = jbd2_cleanup_journal_tail(journal);
++ jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
++ if (result <= 0)
++ return result;
++
++ /*
++ * OK, we need to start writing disk blocks. Take one transaction
++ * and write it.
++ */
++ spin_lock(&journal->j_list_lock);
++ if (!journal->j_checkpoint_transactions)
++ goto out;
++ transaction = journal->j_checkpoint_transactions;
++ this_tid = transaction->t_tid;
++restart:
++ /*
++ * If someone cleaned up this transaction while we slept, we're
++ * done (maybe it's a new transaction, but it fell at the same
++ * address).
++ */
++ if (journal->j_checkpoint_transactions == transaction &&
++ transaction->t_tid == this_tid) {
++ int batch_count = 0;
++ struct buffer_head *bhs[NR_BATCH];
++ struct journal_head *jh;
++ int retry = 0;
++
++ while (!retry && transaction->t_checkpoint_list) {
++ struct buffer_head *bh;
++
++ jh = transaction->t_checkpoint_list;
++ bh = jh2bh(jh);
++ if (!jbd_trylock_bh_state(bh)) {
++ jbd_sync_bh(journal, bh);
++ retry = 1;
++ break;
++ }
++ retry = __process_buffer(journal, jh, bhs,&batch_count);
++ if (!retry && lock_need_resched(&journal->j_list_lock)){
++ spin_unlock(&journal->j_list_lock);
++ retry = 1;
++ break;
++ }
++ }
++
++ if (batch_count) {
++ if (!retry) {
++ spin_unlock(&journal->j_list_lock);
++ retry = 1;
++ }
++ __flush_batch(journal, bhs, &batch_count);
++ }
++
++ if (retry) {
++ spin_lock(&journal->j_list_lock);
++ goto restart;
++ }
++ /*
++ * Now we have cleaned up the first transaction's checkpoint
++ * list. Let's clean up the second one
++ */
++ __wait_cp_io(journal, transaction);
++ }
++out:
++ spin_unlock(&journal->j_list_lock);
++ result = jbd2_cleanup_journal_tail(journal);
++ if (result < 0)
++ return result;
++ return 0;
++}
++
++/*
++ * Check the list of checkpoint transactions for the journal to see if
++ * we have already got rid of any since the last update of the log tail
++ * in the journal superblock. If so, we can instantly roll the
++ * superblock forward to remove those transactions from the log.
++ *
++ * Return <0 on error, 0 on success, 1 if there was nothing to clean up.
++ *
++ * Called with the journal lock held.
++ *
++ * This is the only part of the journaling code which really needs to be
++ * aware of transaction aborts. Checkpointing involves writing to the
++ * main filesystem area rather than to the journal, so it can proceed
++ * even in abort state, but we must not update the journal superblock if
++ * we have an abort error outstanding.
++ */
++
++int jbd2_cleanup_journal_tail(journal_t *journal)
++{
++ transaction_t * transaction;
++ tid_t first_tid;
++ unsigned long blocknr, freed;
++
++ /* OK, work out the oldest transaction remaining in the log, and
++ * the log block it starts at.
++ *
++ * If the log is now empty, we need to work out which is the
++ * next transaction ID we will write, and where it will
++ * start. */
++
++ spin_lock(&journal->j_state_lock);
++ spin_lock(&journal->j_list_lock);
++ transaction = journal->j_checkpoint_transactions;
++ if (transaction) {
++ first_tid = transaction->t_tid;
++ blocknr = transaction->t_log_start;
++ } else if ((transaction = journal->j_committing_transaction) != NULL) {
++ first_tid = transaction->t_tid;
++ blocknr = transaction->t_log_start;
++ } else if ((transaction = journal->j_running_transaction) != NULL) {
++ first_tid = transaction->t_tid;
++ blocknr = journal->j_head;
++ } else {
++ first_tid = journal->j_transaction_sequence;
++ blocknr = journal->j_head;
++ }
++ spin_unlock(&journal->j_list_lock);
++ J_ASSERT(blocknr != 0);
++
++ /* If the oldest pinned transaction is at the tail of the log
++ already then there's not much we can do right now. */
++ if (journal->j_tail_sequence == first_tid) {
++ spin_unlock(&journal->j_state_lock);
++ return 1;
++ }
++
++ /* OK, update the superblock to recover the freed space.
++ * Physical blocks come first: have we wrapped beyond the end of
++ * the log? */
++ freed = blocknr - journal->j_tail;
++ if (blocknr < journal->j_tail)
++ freed = freed + journal->j_last - journal->j_first;
++
++ jbd_debug(1,
++ "Cleaning journal tail from %d to %d (offset %lu), "
++ "freeing %lu\n",
++ journal->j_tail_sequence, first_tid, blocknr, freed);
++
++ journal->j_free += freed;
++ journal->j_tail_sequence = first_tid;
++ journal->j_tail = blocknr;
++ spin_unlock(&journal->j_state_lock);
++ if (!(journal->j_flags & JBD2_ABORT))
++ jbd2_journal_update_superblock(journal, 1);
++ return 0;
++}
++
++
++/* Checkpoint list management */
++
++/*
++ * journal_clean_one_cp_list
++ *
++ * Find all the written-back checkpoint buffers in the given list and release them.
++ *
++ * Called with the journal locked.
++ * Called with j_list_lock held.
++ * Returns number of bufers reaped (for debug)
++ */
++
++static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
++{
++ struct journal_head *last_jh;
++ struct journal_head *next_jh = jh;
++ int ret, freed = 0;
++
++ *released = 0;
++ if (!jh)
++ return 0;
++
++ last_jh = jh->b_cpprev;
++ do {
++ jh = next_jh;
++ next_jh = jh->b_cpnext;
++ /* Use trylock because of the ranking */
++ if (jbd_trylock_bh_state(jh2bh(jh))) {
++ ret = __try_to_free_cp_buf(jh);
++ if (ret) {
++ freed++;
++ if (ret == 2) {
++ *released = 1;
++ return freed;
++ }
++ }
++ }
++ /*
++ * This function only frees up some memory
++ * if possible so we dont have an obligation
++ * to finish processing. Bail out if preemption
++ * requested:
++ */
++ if (need_resched())
++ return freed;
++ } while (jh != last_jh);
++
++ return freed;
++}
++
++/*
++ * journal_clean_checkpoint_list
++ *
++ * Find all the written-back checkpoint buffers in the journal and release them.
++ *
++ * Called with the journal locked.
++ * Called with j_list_lock held.
++ * Returns number of buffers reaped (for debug)
++ */
++
++int __jbd2_journal_clean_checkpoint_list(journal_t *journal)
++{
++ transaction_t *transaction, *last_transaction, *next_transaction;
++ int ret = 0;
++ int released;
++
++ transaction = journal->j_checkpoint_transactions;
++ if (!transaction)
++ goto out;
++
++ last_transaction = transaction->t_cpprev;
++ next_transaction = transaction;
++ do {
++ transaction = next_transaction;
++ next_transaction = transaction->t_cpnext;
++ ret += journal_clean_one_cp_list(transaction->
++ t_checkpoint_list, &released);
++ /*
++ * This function only frees up some memory if possible so we
++ * dont have an obligation to finish processing. Bail out if
++ * preemption requested:
++ */
++ if (need_resched())
++ goto out;
++ if (released)
++ continue;
++ /*
++ * It is essential that we are as careful as in the case of
++ * t_checkpoint_list with removing the buffer from the list as
++ * we can possibly see not yet submitted buffers on io_list
++ */
++ ret += journal_clean_one_cp_list(transaction->
++ t_checkpoint_io_list, &released);
++ if (need_resched())
++ goto out;
++ } while (transaction != last_transaction);
++out:
++ return ret;
++}
++
++/*
++ * journal_remove_checkpoint: called after a buffer has been committed
++ * to disk (either by being write-back flushed to disk, or being
++ * committed to the log).
++ *
++ * We cannot safely clean a transaction out of the log until all of the
++ * buffer updates committed in that transaction have safely been stored
++ * elsewhere on disk. To achieve this, all of the buffers in a
++ * transaction need to be maintained on the transaction's checkpoint
++ * lists until they have been rewritten, at which point this function is
++ * called to remove the buffer from the existing transaction's
++ * checkpoint lists.
++ *
++ * The function returns 1 if it frees the transaction, 0 otherwise.
++ *
++ * This function is called with the journal locked.
++ * This function is called with j_list_lock held.
++ * This function is called with jbd_lock_bh_state(jh2bh(jh))
++ */
++
++int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
++{
++ transaction_t *transaction;
++ journal_t *journal;
++ int ret = 0;
++
++ JBUFFER_TRACE(jh, "entry");
++
++ if ((transaction = jh->b_cp_transaction) == NULL) {
++ JBUFFER_TRACE(jh, "not on transaction");
++ goto out;
++ }
++ journal = transaction->t_journal;
++
++ __buffer_unlink(jh);
++ jh->b_cp_transaction = NULL;
++
++ if (transaction->t_checkpoint_list != NULL ||
++ transaction->t_checkpoint_io_list != NULL)
++ goto out;
++ JBUFFER_TRACE(jh, "transaction has no more buffers");
++
++ /*
++ * There is one special case to worry about: if we have just pulled the
++ * buffer off a committing transaction's forget list, then even if the
++ * checkpoint list is empty, the transaction obviously cannot be
++ * dropped!
++ *
++ * The locking here around j_committing_transaction is a bit sleazy.
++ * See the comment at the end of jbd2_journal_commit_transaction().
++ */
++ if (transaction == journal->j_committing_transaction) {
++ JBUFFER_TRACE(jh, "belongs to committing transaction");
++ goto out;
++ }
++
++ /* OK, that was the last buffer for the transaction: we can now
++ safely remove this transaction from the log */
++
++ __jbd2_journal_drop_transaction(journal, transaction);
++
++ /* Just in case anybody was waiting for more transactions to be
++ checkpointed... */
++ wake_up(&journal->j_wait_logspace);
++ ret = 1;
++out:
++ JBUFFER_TRACE(jh, "exit");
++ return ret;
++}
++
++/*
++ * journal_insert_checkpoint: put a committed buffer onto a checkpoint
++ * list so that we know when it is safe to clean the transaction out of
++ * the log.
++ *
++ * Called with the journal locked.
++ * Called with j_list_lock held.
++ */
++void __jbd2_journal_insert_checkpoint(struct journal_head *jh,
++ transaction_t *transaction)
++{
++ JBUFFER_TRACE(jh, "entry");
++ J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh)));
++ J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);
++
++ jh->b_cp_transaction = transaction;
++
++ if (!transaction->t_checkpoint_list) {
++ jh->b_cpnext = jh->b_cpprev = jh;
++ } else {
++ jh->b_cpnext = transaction->t_checkpoint_list;
++ jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev;
++ jh->b_cpprev->b_cpnext = jh;
++ jh->b_cpnext->b_cpprev = jh;
++ }
++ transaction->t_checkpoint_list = jh;
++}
++
++/*
++ * We've finished with this transaction structure: adios...
++ *
++ * The transaction must have no links except for the checkpoint by this
++ * point.
++ *
++ * Called with the journal locked.
++ * Called with j_list_lock held.
++ */
++
++void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transaction)
++{
++ assert_spin_locked(&journal->j_list_lock);
++ if (transaction->t_cpnext) {
++ transaction->t_cpnext->t_cpprev = transaction->t_cpprev;
++ transaction->t_cpprev->t_cpnext = transaction->t_cpnext;
++ if (journal->j_checkpoint_transactions == transaction)
++ journal->j_checkpoint_transactions =
++ transaction->t_cpnext;
++ if (journal->j_checkpoint_transactions == transaction)
++ journal->j_checkpoint_transactions = NULL;
++ }
++
++ J_ASSERT(transaction->t_state == T_FINISHED);
++ J_ASSERT(transaction->t_buffers == NULL);
++ J_ASSERT(transaction->t_sync_datalist == NULL);
++ J_ASSERT(transaction->t_forget == NULL);
++ J_ASSERT(transaction->t_iobuf_list == NULL);
++ J_ASSERT(transaction->t_shadow_list == NULL);
++ J_ASSERT(transaction->t_log_list == NULL);
++ J_ASSERT(transaction->t_checkpoint_list == NULL);
++ J_ASSERT(transaction->t_checkpoint_io_list == NULL);
++ J_ASSERT(transaction->t_updates == 0);
++ J_ASSERT(journal->j_committing_transaction != transaction);
++ J_ASSERT(journal->j_running_transaction != transaction);
++
++ jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
++ kfree(transaction);
++}
+diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
+new file mode 100644
+index 0000000..70b2ae1
+--- /dev/null
++++ b/fs/jbd2/commit.c
+@@ -0,0 +1,920 @@
++/*
++ * linux/fs/jbd2/commit.c
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 1998
++ *
++ * Copyright 1998 Red Hat corp --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Journal commit routines for the generic filesystem journaling code;
++ * part of the ext2fs journaling system.
++ */
++
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/smp_lock.h>
++
++/*
++ * Default IO end handler for temporary BJ_IO buffer_heads.
++ */
++static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
++{
++ BUFFER_TRACE(bh, "");
++ if (uptodate)
++ set_buffer_uptodate(bh);
++ else
++ clear_buffer_uptodate(bh);
++ unlock_buffer(bh);
++}
++
++/*
++ * When an ext3-ordered file is truncated, it is possible that many pages are
++ * not sucessfully freed, because they are attached to a committing transaction.
++ * After the transaction commits, these pages are left on the LRU, with no
++ * ->mapping, and with attached buffers. These pages are trivially reclaimable
++ * by the VM, but their apparent absence upsets the VM accounting, and it makes
++ * the numbers in /proc/meminfo look odd.
++ *
++ * So here, we have a buffer which has just come off the forget list. Look to
++ * see if we can strip all buffers from the backing page.
++ *
++ * Called under lock_journal(), and possibly under journal_datalist_lock. The
++ * caller provided us with a ref against the buffer, and we drop that here.
++ */
++static void release_buffer_page(struct buffer_head *bh)
++{
++ struct page *page;
++
++ if (buffer_dirty(bh))
++ goto nope;
++ if (atomic_read(&bh->b_count) != 1)
++ goto nope;
++ page = bh->b_page;
++ if (!page)
++ goto nope;
++ if (page->mapping)
++ goto nope;
++
++ /* OK, it's a truncated page */
++ if (TestSetPageLocked(page))
++ goto nope;
++
++ page_cache_get(page);
++ __brelse(bh);
++ try_to_free_buffers(page);
++ unlock_page(page);
++ page_cache_release(page);
++ return;
++
++nope:
++ __brelse(bh);
++}
++
++/*
++ * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is
++ * held. For ranking reasons we must trylock. If we lose, schedule away and
++ * return 0. j_list_lock is dropped in this case.
++ */
++static int inverted_lock(journal_t *journal, struct buffer_head *bh)
++{
++ if (!jbd_trylock_bh_state(bh)) {
++ spin_unlock(&journal->j_list_lock);
++ schedule();
++ return 0;
++ }
++ return 1;
++}
++
++/* Done it all: now write the commit record. We should have
++ * cleaned up our previous buffers by now, so if we are in abort
++ * mode we can now just skip the rest of the journal write
++ * entirely.
++ *
++ * Returns 1 if the journal needs to be aborted or 0 on success
++ */
++static int journal_write_commit_record(journal_t *journal,
++ transaction_t *commit_transaction)
++{
++ struct journal_head *descriptor;
++ struct buffer_head *bh;
++ int i, ret;
++ int barrier_done = 0;
++
++ if (is_journal_aborted(journal))
++ return 0;
++
++ descriptor = jbd2_journal_get_descriptor_buffer(journal);
++ if (!descriptor)
++ return 1;
++
++ bh = jh2bh(descriptor);
++
++ /* AKPM: buglet - add `i' to tmp! */
++ for (i = 0; i < bh->b_size; i += 512) {
++ journal_header_t *tmp = (journal_header_t*)bh->b_data;
++ tmp->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
++ tmp->h_blocktype = cpu_to_be32(JBD2_COMMIT_BLOCK);
++ tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid);
++ }
++
++ JBUFFER_TRACE(descriptor, "write commit block");
++ set_buffer_dirty(bh);
++ if (journal->j_flags & JBD2_BARRIER) {
++ set_buffer_ordered(bh);
++ barrier_done = 1;
++ }
++ ret = sync_dirty_buffer(bh);
++ /* is it possible for another commit to fail at roughly
++ * the same time as this one? If so, we don't want to
++ * trust the barrier flag in the super, but instead want
++ * to remember if we sent a barrier request
++ */
++ if (ret == -EOPNOTSUPP && barrier_done) {
++ char b[BDEVNAME_SIZE];
++
++ printk(KERN_WARNING
++ "JBD: barrier-based sync failed on %s - "
++ "disabling barriers\n",
++ bdevname(journal->j_dev, b));
++ spin_lock(&journal->j_state_lock);
++ journal->j_flags &= ~JBD2_BARRIER;
++ spin_unlock(&journal->j_state_lock);
++
++ /* And try again, without the barrier */
++ clear_buffer_ordered(bh);
++ set_buffer_uptodate(bh);
++ set_buffer_dirty(bh);
++ ret = sync_dirty_buffer(bh);
++ }
++ put_bh(bh); /* One for getblk() */
++ jbd2_journal_put_journal_head(descriptor);
++
++ return (ret == -EIO);
++}
++
++static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
++{
++ int i;
++
++ for (i = 0; i < bufs; i++) {
++ wbuf[i]->b_end_io = end_buffer_write_sync;
++ /* We use-up our safety reference in submit_bh() */
++ submit_bh(WRITE, wbuf[i]);
++ }
++}
++
++/*
++ * Submit all the data buffers to disk
++ */
++static void journal_submit_data_buffers(journal_t *journal,
++ transaction_t *commit_transaction)
++{
++ struct journal_head *jh;
++ struct buffer_head *bh;
++ int locked;
++ int bufs = 0;
++ struct buffer_head **wbuf = journal->j_wbuf;
++
++ /*
++ * Whenever we unlock the journal and sleep, things can get added
++ * onto ->t_sync_datalist, so we have to keep looping back to
++ * write_out_data until we *know* that the list is empty.
++ *
++ * Cleanup any flushed data buffers from the data list. Even in
++ * abort mode, we want to flush this out as soon as possible.
++ */
++write_out_data:
++ cond_resched();
++ spin_lock(&journal->j_list_lock);
++
++ while (commit_transaction->t_sync_datalist) {
++ jh = commit_transaction->t_sync_datalist;
++ bh = jh2bh(jh);
++ locked = 0;
++
++ /* Get reference just to make sure buffer does not disappear
++ * when we are forced to drop various locks */
++ get_bh(bh);
++ /* If the buffer is dirty, we need to submit IO and hence
++ * we need the buffer lock. We try to lock the buffer without
++ * blocking. If we fail, we need to drop j_list_lock and do
++ * blocking lock_buffer().
++ */
++ if (buffer_dirty(bh)) {
++ if (test_set_buffer_locked(bh)) {
++ BUFFER_TRACE(bh, "needs blocking lock");
++ spin_unlock(&journal->j_list_lock);
++ /* Write out all data to prevent deadlocks */
++ journal_do_submit_data(wbuf, bufs);
++ bufs = 0;
++ lock_buffer(bh);
++ spin_lock(&journal->j_list_lock);
++ }
++ locked = 1;
++ }
++ /* We have to get bh_state lock. Again out of order, sigh. */
++ if (!inverted_lock(journal, bh)) {
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++ }
++ /* Someone already cleaned up the buffer? */
++ if (!buffer_jbd(bh)
++ || jh->b_transaction != commit_transaction
++ || jh->b_jlist != BJ_SyncData) {
++ jbd_unlock_bh_state(bh);
++ if (locked)
++ unlock_buffer(bh);
++ BUFFER_TRACE(bh, "already cleaned up");
++ put_bh(bh);
++ continue;
++ }
++ if (locked && test_clear_buffer_dirty(bh)) {
++ BUFFER_TRACE(bh, "needs writeout, adding to array");
++ wbuf[bufs++] = bh;
++ __jbd2_journal_file_buffer(jh, commit_transaction,
++ BJ_Locked);
++ jbd_unlock_bh_state(bh);
++ if (bufs == journal->j_wbufsize) {
++ spin_unlock(&journal->j_list_lock);
++ journal_do_submit_data(wbuf, bufs);
++ bufs = 0;
++ goto write_out_data;
++ }
++ }
++ else {
++ BUFFER_TRACE(bh, "writeout complete: unfile");
++ __jbd2_journal_unfile_buffer(jh);
++ jbd_unlock_bh_state(bh);
++ if (locked)
++ unlock_buffer(bh);
++ jbd2_journal_remove_journal_head(bh);
++ /* Once for our safety reference, once for
++ * jbd2_journal_remove_journal_head() */
++ put_bh(bh);
++ put_bh(bh);
++ }
++
++ if (lock_need_resched(&journal->j_list_lock)) {
++ spin_unlock(&journal->j_list_lock);
++ goto write_out_data;
++ }
++ }
++ spin_unlock(&journal->j_list_lock);
++ journal_do_submit_data(wbuf, bufs);
++}
++
++static inline void write_tag_block(int tag_bytes, journal_block_tag_t *tag,
++ unsigned long long block)
++{
++ tag->t_blocknr = cpu_to_be32(block & (u32)~0);
++ if (tag_bytes > JBD_TAG_SIZE32)
++ tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
++}
++
++/*
++ * jbd2_journal_commit_transaction
++ *
++ * The primary function for committing a transaction to the log. This
++ * function is called by the journal thread to begin a complete commit.
++ */
++void jbd2_journal_commit_transaction(journal_t *journal)
++{
++ transaction_t *commit_transaction;
++ struct journal_head *jh, *new_jh, *descriptor;
++ struct buffer_head **wbuf = journal->j_wbuf;
++ int bufs;
++ int flags;
++ int err;
++ unsigned long long blocknr;
++ char *tagp = NULL;
++ journal_header_t *header;
++ journal_block_tag_t *tag = NULL;
++ int space_left = 0;
++ int first_tag = 0;
++ int tag_flag;
++ int i;
++ int tag_bytes = journal_tag_bytes(journal);
++
++ /*
++ * First job: lock down the current transaction and wait for
++ * all outstanding updates to complete.
++ */
++
++#ifdef COMMIT_STATS
++ spin_lock(&journal->j_list_lock);
++ summarise_journal_usage(journal);
++ spin_unlock(&journal->j_list_lock);
++#endif
++
++ /* Do we need to erase the effects of a prior jbd2_journal_flush? */
++ if (journal->j_flags & JBD2_FLUSHED) {
++ jbd_debug(3, "super block updated\n");
++ jbd2_journal_update_superblock(journal, 1);
++ } else {
++ jbd_debug(3, "superblock not updated\n");
++ }
++
++ J_ASSERT(journal->j_running_transaction != NULL);
++ J_ASSERT(journal->j_committing_transaction == NULL);
++
++ commit_transaction = journal->j_running_transaction;
++ J_ASSERT(commit_transaction->t_state == T_RUNNING);
++
++ jbd_debug(1, "JBD: starting commit of transaction %d\n",
++ commit_transaction->t_tid);
++
++ spin_lock(&journal->j_state_lock);
++ commit_transaction->t_state = T_LOCKED;
++
++ spin_lock(&commit_transaction->t_handle_lock);
++ while (commit_transaction->t_updates) {
++ DEFINE_WAIT(wait);
++
++ prepare_to_wait(&journal->j_wait_updates, &wait,
++ TASK_UNINTERRUPTIBLE);
++ if (commit_transaction->t_updates) {
++ spin_unlock(&commit_transaction->t_handle_lock);
++ spin_unlock(&journal->j_state_lock);
++ schedule();
++ spin_lock(&journal->j_state_lock);
++ spin_lock(&commit_transaction->t_handle_lock);
++ }
++ finish_wait(&journal->j_wait_updates, &wait);
++ }
++ spin_unlock(&commit_transaction->t_handle_lock);
++
++ J_ASSERT (commit_transaction->t_outstanding_credits <=
++ journal->j_max_transaction_buffers);
++
++ /*
++ * First thing we are allowed to do is to discard any remaining
++ * BJ_Reserved buffers. Note, it is _not_ permissible to assume
++ * that there are no such buffers: if a large filesystem
++ * operation like a truncate needs to split itself over multiple
++ * transactions, then it may try to do a jbd2_journal_restart() while
++ * there are still BJ_Reserved buffers outstanding. These must
++ * be released cleanly from the current transaction.
++ *
++ * In this case, the filesystem must still reserve write access
++ * again before modifying the buffer in the new transaction, but
++ * we do not require it to remember exactly which old buffers it
++ * has reserved. This is consistent with the existing behaviour
++ * that multiple jbd2_journal_get_write_access() calls to the same
++ * buffer are perfectly permissable.
++ */
++ while (commit_transaction->t_reserved_list) {
++ jh = commit_transaction->t_reserved_list;
++ JBUFFER_TRACE(jh, "reserved, unused: refile");
++ /*
++ * A jbd2_journal_get_undo_access()+jbd2_journal_release_buffer() may
++ * leave undo-committed data.
++ */
++ if (jh->b_committed_data) {
++ struct buffer_head *bh = jh2bh(jh);
++
++ jbd_lock_bh_state(bh);
++ jbd2_slab_free(jh->b_committed_data, bh->b_size);
++ jh->b_committed_data = NULL;
++ jbd_unlock_bh_state(bh);
++ }
++ jbd2_journal_refile_buffer(journal, jh);
++ }
++
++ /*
++ * Now try to drop any written-back buffers from the journal's
++ * checkpoint lists. We do this *before* commit because it potentially
++ * frees some memory
++ */
++ spin_lock(&journal->j_list_lock);
++ __jbd2_journal_clean_checkpoint_list(journal);
++ spin_unlock(&journal->j_list_lock);
++
++ jbd_debug (3, "JBD: commit phase 1\n");
++
++ /*
++ * Switch to a new revoke table.
++ */
++ jbd2_journal_switch_revoke_table(journal);
++
++ commit_transaction->t_state = T_FLUSH;
++ journal->j_committing_transaction = commit_transaction;
++ journal->j_running_transaction = NULL;
++ commit_transaction->t_log_start = journal->j_head;
++ wake_up(&journal->j_wait_transaction_locked);
++ spin_unlock(&journal->j_state_lock);
++
++ jbd_debug (3, "JBD: commit phase 2\n");
++
++ /*
++ * First, drop modified flag: all accesses to the buffers
++ * will be tracked for a new trasaction only -bzzz
++ */
++ spin_lock(&journal->j_list_lock);
++ if (commit_transaction->t_buffers) {
++ new_jh = jh = commit_transaction->t_buffers->b_tnext;
++ do {
++ J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
++ new_jh->b_modified == 0);
++ new_jh->b_modified = 0;
++ new_jh = new_jh->b_tnext;
++ } while (new_jh != jh);
++ }
++ spin_unlock(&journal->j_list_lock);
++
++ /*
++ * Now start flushing things to disk, in the order they appear
++ * on the transaction lists. Data blocks go first.
++ */
++ err = 0;
++ journal_submit_data_buffers(journal, commit_transaction);
++
++ /*
++ * Wait for all previously submitted IO to complete.
++ */
++ spin_lock(&journal->j_list_lock);
++ while (commit_transaction->t_locked_list) {
++ struct buffer_head *bh;
++
++ jh = commit_transaction->t_locked_list->b_tprev;
++ bh = jh2bh(jh);
++ get_bh(bh);
++ if (buffer_locked(bh)) {
++ spin_unlock(&journal->j_list_lock);
++ wait_on_buffer(bh);
++ if (unlikely(!buffer_uptodate(bh)))
++ err = -EIO;
++ spin_lock(&journal->j_list_lock);
++ }
++ if (!inverted_lock(journal, bh)) {
++ put_bh(bh);
++ spin_lock(&journal->j_list_lock);
++ continue;
++ }
++ if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) {
++ __jbd2_journal_unfile_buffer(jh);
++ jbd_unlock_bh_state(bh);
++ jbd2_journal_remove_journal_head(bh);
++ put_bh(bh);
++ } else {
++ jbd_unlock_bh_state(bh);
++ }
++ put_bh(bh);
++ cond_resched_lock(&journal->j_list_lock);
++ }
++ spin_unlock(&journal->j_list_lock);
++
++ if (err)
++ __jbd2_journal_abort_hard(journal);
++
++ jbd2_journal_write_revoke_records(journal, commit_transaction);
++
++ jbd_debug(3, "JBD: commit phase 2\n");
++
++ /*
++ * If we found any dirty or locked buffers, then we should have
++ * looped back up to the write_out_data label. If there weren't
++ * any then journal_clean_data_list should have wiped the list
++ * clean by now, so check that it is in fact empty.
++ */
++ J_ASSERT (commit_transaction->t_sync_datalist == NULL);
++
++ jbd_debug (3, "JBD: commit phase 3\n");
++
++ /*
++ * Way to go: we have now written out all of the data for a
++ * transaction! Now comes the tricky part: we need to write out
++ * metadata. Loop over the transaction's entire buffer list:
++ */
++ commit_transaction->t_state = T_COMMIT;
++
++ descriptor = NULL;
++ bufs = 0;
++ while (commit_transaction->t_buffers) {
++
++ /* Find the next buffer to be journaled... */
++
++ jh = commit_transaction->t_buffers;
++
++ /* If we're in abort mode, we just un-journal the buffer and
++ release it for background writing. */
++
++ if (is_journal_aborted(journal)) {
++ JBUFFER_TRACE(jh, "journal is aborting: refile");
++ jbd2_journal_refile_buffer(journal, jh);
++ /* If that was the last one, we need to clean up
++ * any descriptor buffers which may have been
++ * already allocated, even if we are now
++ * aborting. */
++ if (!commit_transaction->t_buffers)
++ goto start_journal_io;
++ continue;
++ }
++
++ /* Make sure we have a descriptor block in which to
++ record the metadata buffer. */
++
++ if (!descriptor) {
++ struct buffer_head *bh;
++
++ J_ASSERT (bufs == 0);
++
++ jbd_debug(4, "JBD: get descriptor\n");
++
++ descriptor = jbd2_journal_get_descriptor_buffer(journal);
++ if (!descriptor) {
++ __jbd2_journal_abort_hard(journal);
++ continue;
++ }
++
++ bh = jh2bh(descriptor);
++ jbd_debug(4, "JBD: got buffer %llu (%p)\n",
++ (unsigned long long)bh->b_blocknr, bh->b_data);
++ header = (journal_header_t *)&bh->b_data[0];
++ header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
++ header->h_blocktype = cpu_to_be32(JBD2_DESCRIPTOR_BLOCK);
++ header->h_sequence = cpu_to_be32(commit_transaction->t_tid);
++
++ tagp = &bh->b_data[sizeof(journal_header_t)];
++ space_left = bh->b_size - sizeof(journal_header_t);
++ first_tag = 1;
++ set_buffer_jwrite(bh);
++ set_buffer_dirty(bh);
++ wbuf[bufs++] = bh;
++
++ /* Record it so that we can wait for IO
++ completion later */
++ BUFFER_TRACE(bh, "ph3: file as descriptor");
++ jbd2_journal_file_buffer(descriptor, commit_transaction,
++ BJ_LogCtl);
++ }
++
++ /* Where is the buffer to be written? */
++
++ err = jbd2_journal_next_log_block(journal, &blocknr);
++ /* If the block mapping failed, just abandon the buffer
++ and repeat this loop: we'll fall into the
++ refile-on-abort condition above. */
++ if (err) {
++ __jbd2_journal_abort_hard(journal);
++ continue;
++ }
++
++ /*
++ * start_this_handle() uses t_outstanding_credits to determine
++ * the free space in the log, but this counter is changed
++ * by jbd2_journal_next_log_block() also.
++ */
++ commit_transaction->t_outstanding_credits--;
++
++ /* Bump b_count to prevent truncate from stumbling over
++ the shadowed buffer! @@@ This can go if we ever get
++ rid of the BJ_IO/BJ_Shadow pairing of buffers. */
++ atomic_inc(&jh2bh(jh)->b_count);
++
++ /* Make a temporary IO buffer with which to write it out
++ (this will requeue both the metadata buffer and the
++ temporary IO buffer). new_bh goes on BJ_IO*/
++
++ set_bit(BH_JWrite, &jh2bh(jh)->b_state);
++ /*
++ * akpm: jbd2_journal_write_metadata_buffer() sets
++ * new_bh->b_transaction to commit_transaction.
++ * We need to clean this up before we release new_bh
++ * (which is of type BJ_IO)
++ */
++ JBUFFER_TRACE(jh, "ph3: write metadata");
++ flags = jbd2_journal_write_metadata_buffer(commit_transaction,
++ jh, &new_jh, blocknr);
++ set_bit(BH_JWrite, &jh2bh(new_jh)->b_state);
++ wbuf[bufs++] = jh2bh(new_jh);
++
++ /* Record the new block's tag in the current descriptor
++ buffer */
++
++ tag_flag = 0;
++ if (flags & 1)
++ tag_flag |= JBD2_FLAG_ESCAPE;
++ if (!first_tag)
++ tag_flag |= JBD2_FLAG_SAME_UUID;
++
++ tag = (journal_block_tag_t *) tagp;
++ write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr);
++ tag->t_flags = cpu_to_be32(tag_flag);
++ tagp += tag_bytes;
++ space_left -= tag_bytes;
++
++ if (first_tag) {
++ memcpy (tagp, journal->j_uuid, 16);
++ tagp += 16;
++ space_left -= 16;
++ first_tag = 0;
++ }
++
++ /* If there's no more to do, or if the descriptor is full,
++ let the IO rip! */
++
++ if (bufs == journal->j_wbufsize ||
++ commit_transaction->t_buffers == NULL ||
++ space_left < tag_bytes + 16) {
++
++ jbd_debug(4, "JBD: Submit %d IOs\n", bufs);
++
++ /* Write an end-of-descriptor marker before
++ submitting the IOs. "tag" still points to
++ the last tag we set up. */
++
++ tag->t_flags |= cpu_to_be32(JBD2_FLAG_LAST_TAG);
++
++start_journal_io:
++ for (i = 0; i < bufs; i++) {
++ struct buffer_head *bh = wbuf[i];
++ lock_buffer(bh);
++ clear_buffer_dirty(bh);
++ set_buffer_uptodate(bh);
++ bh->b_end_io = journal_end_buffer_io_sync;
++ submit_bh(WRITE, bh);
++ }
++ cond_resched();
++
++ /* Force a new descriptor to be generated next
++ time round the loop. */
++ descriptor = NULL;
++ bufs = 0;
++ }
++ }
++
++ /* Lo and behold: we have just managed to send a transaction to
++ the log. Before we can commit it, wait for the IO so far to
++ complete. Control buffers being written are on the
++ transaction's t_log_list queue, and metadata buffers are on
++ the t_iobuf_list queue.
++
++ Wait for the buffers in reverse order. That way we are
++ less likely to be woken up until all IOs have completed, and
++ so we incur less scheduling load.
++ */
++
++ jbd_debug(3, "JBD: commit phase 4\n");
++
++ /*
++ * akpm: these are BJ_IO, and j_list_lock is not needed.
++ * See __journal_try_to_free_buffer.
++ */
++wait_for_iobuf:
++ while (commit_transaction->t_iobuf_list != NULL) {
++ struct buffer_head *bh;
++
++ jh = commit_transaction->t_iobuf_list->b_tprev;
++ bh = jh2bh(jh);
++ if (buffer_locked(bh)) {
++ wait_on_buffer(bh);
++ goto wait_for_iobuf;
++ }
++ if (cond_resched())
++ goto wait_for_iobuf;
++
++ if (unlikely(!buffer_uptodate(bh)))
++ err = -EIO;
++
++ clear_buffer_jwrite(bh);
++
++ JBUFFER_TRACE(jh, "ph4: unfile after journal write");
++ jbd2_journal_unfile_buffer(journal, jh);
++
++ /*
++ * ->t_iobuf_list should contain only dummy buffer_heads
++ * which were created by jbd2_journal_write_metadata_buffer().
++ */
++ BUFFER_TRACE(bh, "dumping temporary bh");
++ jbd2_journal_put_journal_head(jh);
++ __brelse(bh);
++ J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0);
++ free_buffer_head(bh);
++
++ /* We also have to unlock and free the corresponding
++ shadowed buffer */
++ jh = commit_transaction->t_shadow_list->b_tprev;
++ bh = jh2bh(jh);
++ clear_bit(BH_JWrite, &bh->b_state);
++ J_ASSERT_BH(bh, buffer_jbddirty(bh));
++
++ /* The metadata is now released for reuse, but we need
++ to remember it against this transaction so that when
++ we finally commit, we can do any checkpointing
++ required. */
++ JBUFFER_TRACE(jh, "file as BJ_Forget");
++ jbd2_journal_file_buffer(jh, commit_transaction, BJ_Forget);
++ /* Wake up any transactions which were waiting for this
++ IO to complete */
++ wake_up_bit(&bh->b_state, BH_Unshadow);
++ JBUFFER_TRACE(jh, "brelse shadowed buffer");
++ __brelse(bh);
++ }
++
++ J_ASSERT (commit_transaction->t_shadow_list == NULL);
++
++ jbd_debug(3, "JBD: commit phase 5\n");
++
++ /* Here we wait for the revoke record and descriptor record buffers */
++ wait_for_ctlbuf:
++ while (commit_transaction->t_log_list != NULL) {
++ struct buffer_head *bh;
++
++ jh = commit_transaction->t_log_list->b_tprev;
++ bh = jh2bh(jh);
++ if (buffer_locked(bh)) {
++ wait_on_buffer(bh);
++ goto wait_for_ctlbuf;
++ }
++ if (cond_resched())
++ goto wait_for_ctlbuf;
++
++ if (unlikely(!buffer_uptodate(bh)))
++ err = -EIO;
++
++ BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile");
++ clear_buffer_jwrite(bh);
++ jbd2_journal_unfile_buffer(journal, jh);
++ jbd2_journal_put_journal_head(jh);
++ __brelse(bh); /* One for getblk */
++ /* AKPM: bforget here */
++ }
++
++ jbd_debug(3, "JBD: commit phase 6\n");
++
++ if (journal_write_commit_record(journal, commit_transaction))
++ err = -EIO;
++
++ if (err)
++ __jbd2_journal_abort_hard(journal);
++
++ /* End of a transaction! Finally, we can do checkpoint
++ processing: any buffers committed as a result of this
++ transaction can be removed from any checkpoint list it was on
++ before. */
++
++ jbd_debug(3, "JBD: commit phase 7\n");
++
++ J_ASSERT(commit_transaction->t_sync_datalist == NULL);
++ J_ASSERT(commit_transaction->t_buffers == NULL);
++ J_ASSERT(commit_transaction->t_checkpoint_list == NULL);
++ J_ASSERT(commit_transaction->t_iobuf_list == NULL);
++ J_ASSERT(commit_transaction->t_shadow_list == NULL);
++ J_ASSERT(commit_transaction->t_log_list == NULL);
++
++restart_loop:
++ /*
++ * As there are other places (journal_unmap_buffer()) adding buffers
++ * to this list we have to be careful and hold the j_list_lock.
++ */
++ spin_lock(&journal->j_list_lock);
++ while (commit_transaction->t_forget) {
++ transaction_t *cp_transaction;
++ struct buffer_head *bh;
++
++ jh = commit_transaction->t_forget;
++ spin_unlock(&journal->j_list_lock);
++ bh = jh2bh(jh);
++ jbd_lock_bh_state(bh);
++ J_ASSERT_JH(jh, jh->b_transaction == commit_transaction ||
++ jh->b_transaction == journal->j_running_transaction);
++
++ /*
++ * If there is undo-protected committed data against
++ * this buffer, then we can remove it now. If it is a
++ * buffer needing such protection, the old frozen_data
++ * field now points to a committed version of the
++ * buffer, so rotate that field to the new committed
++ * data.
++ *
++ * Otherwise, we can just throw away the frozen data now.
++ */
++ if (jh->b_committed_data) {
++ jbd2_slab_free(jh->b_committed_data, bh->b_size);
++ jh->b_committed_data = NULL;
++ if (jh->b_frozen_data) {
++ jh->b_committed_data = jh->b_frozen_data;
++ jh->b_frozen_data = NULL;
++ }
++ } else if (jh->b_frozen_data) {
++ jbd2_slab_free(jh->b_frozen_data, bh->b_size);
++ jh->b_frozen_data = NULL;
++ }
++
++ spin_lock(&journal->j_list_lock);
++ cp_transaction = jh->b_cp_transaction;
++ if (cp_transaction) {
++ JBUFFER_TRACE(jh, "remove from old cp transaction");
++ __jbd2_journal_remove_checkpoint(jh);
++ }
++
++ /* Only re-checkpoint the buffer_head if it is marked
++ * dirty. If the buffer was added to the BJ_Forget list
++ * by jbd2_journal_forget, it may no longer be dirty and
++ * there's no point in keeping a checkpoint record for
++ * it. */
++
++ /* A buffer which has been freed while still being
++ * journaled by a previous transaction may end up still
++ * being dirty here, but we want to avoid writing back
++ * that buffer in the future now that the last use has
++ * been committed. That's not only a performance gain,
++ * it also stops aliasing problems if the buffer is left
++ * behind for writeback and gets reallocated for another
++ * use in a different page. */
++ if (buffer_freed(bh)) {
++ clear_buffer_freed(bh);
++ clear_buffer_jbddirty(bh);
++ }
++
++ if (buffer_jbddirty(bh)) {
++ JBUFFER_TRACE(jh, "add to new checkpointing trans");
++ __jbd2_journal_insert_checkpoint(jh, commit_transaction);
++ JBUFFER_TRACE(jh, "refile for checkpoint writeback");
++ __jbd2_journal_refile_buffer(jh);
++ jbd_unlock_bh_state(bh);
++ } else {
++ J_ASSERT_BH(bh, !buffer_dirty(bh));
++ /* The buffer on BJ_Forget list and not jbddirty means
++ * it has been freed by this transaction and hence it
++ * could not have been reallocated until this
++ * transaction has committed. *BUT* it could be
++ * reallocated once we have written all the data to
++ * disk and before we process the buffer on BJ_Forget
++ * list. */
++ JBUFFER_TRACE(jh, "refile or unfile freed buffer");
++ __jbd2_journal_refile_buffer(jh);
++ if (!jh->b_transaction) {
++ jbd_unlock_bh_state(bh);
++ /* needs a brelse */
++ jbd2_journal_remove_journal_head(bh);
++ release_buffer_page(bh);
++ } else
++ jbd_unlock_bh_state(bh);
++ }
++ cond_resched_lock(&journal->j_list_lock);
++ }
++ spin_unlock(&journal->j_list_lock);
++ /*
++ * This is a bit sleazy. We borrow j_list_lock to protect
++ * journal->j_committing_transaction in __jbd2_journal_remove_checkpoint.
++ * Really, __jbd2_journal_remove_checkpoint should be using j_state_lock but
++ * it's a bit hassle to hold that across __jbd2_journal_remove_checkpoint
++ */
++ spin_lock(&journal->j_state_lock);
++ spin_lock(&journal->j_list_lock);
++ /*
++ * Now recheck if some buffers did not get attached to the transaction
++ * while the lock was dropped...
++ */
++ if (commit_transaction->t_forget) {
++ spin_unlock(&journal->j_list_lock);
++ spin_unlock(&journal->j_state_lock);
++ goto restart_loop;
++ }
++
++ /* Done with this transaction! */
++
++ jbd_debug(3, "JBD: commit phase 8\n");
++
++ J_ASSERT(commit_transaction->t_state == T_COMMIT);
++
++ commit_transaction->t_state = T_FINISHED;
++ J_ASSERT(commit_transaction == journal->j_committing_transaction);
++ journal->j_commit_sequence = commit_transaction->t_tid;
++ journal->j_committing_transaction = NULL;
++ spin_unlock(&journal->j_state_lock);
++
++ if (commit_transaction->t_checkpoint_list == NULL) {
++ __jbd2_journal_drop_transaction(journal, commit_transaction);
++ } else {
++ if (journal->j_checkpoint_transactions == NULL) {
++ journal->j_checkpoint_transactions = commit_transaction;
++ commit_transaction->t_cpnext = commit_transaction;
++ commit_transaction->t_cpprev = commit_transaction;
++ } else {
++ commit_transaction->t_cpnext =
++ journal->j_checkpoint_transactions;
++ commit_transaction->t_cpprev =
++ commit_transaction->t_cpnext->t_cpprev;
++ commit_transaction->t_cpnext->t_cpprev =
++ commit_transaction;
++ commit_transaction->t_cpprev->t_cpnext =
++ commit_transaction;
++ }
++ }
++ spin_unlock(&journal->j_list_lock);
++
++ jbd_debug(1, "JBD: commit %d complete, head %d\n",
++ journal->j_commit_sequence, journal->j_tail_sequence);
++
++ wake_up(&journal->j_wait_done_commit);
++}
+diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
+new file mode 100644
+index 0000000..c60f378
+--- /dev/null
++++ b/fs/jbd2/journal.c
+@@ -0,0 +1,2084 @@
++/*
++ * linux/fs/jbd2/journal.c
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 1998
++ *
++ * Copyright 1998 Red Hat corp --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Generic filesystem journal-writing code; part of the ext2fs
++ * journaling system.
++ *
++ * This file manages journals: areas of disk reserved for logging
++ * transactional updates. This includes the kernel journaling thread
++ * which is responsible for scheduling updates to the log.
++ *
++ * We do not actually manage the physical storage of the journal in this
++ * file: that is left to a per-journal policy function, which allows us
++ * to store the journal within a filesystem-specified area for ext2
++ * journaling (ext2 can use a reserved inode for storing the log).
++ */
++
++#include <linux/module.h>
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/suspend.h>
++#include <linux/pagemap.h>
++#include <linux/kthread.h>
++#include <linux/poison.h>
++#include <linux/proc_fs.h>
++
++#include <asm/uaccess.h>
++#include <asm/page.h>
++
++EXPORT_SYMBOL(jbd2_journal_start);
++EXPORT_SYMBOL(jbd2_journal_restart);
++EXPORT_SYMBOL(jbd2_journal_extend);
++EXPORT_SYMBOL(jbd2_journal_stop);
++EXPORT_SYMBOL(jbd2_journal_lock_updates);
++EXPORT_SYMBOL(jbd2_journal_unlock_updates);
++EXPORT_SYMBOL(jbd2_journal_get_write_access);
++EXPORT_SYMBOL(jbd2_journal_get_create_access);
++EXPORT_SYMBOL(jbd2_journal_get_undo_access);
++EXPORT_SYMBOL(jbd2_journal_dirty_data);
++EXPORT_SYMBOL(jbd2_journal_dirty_metadata);
++EXPORT_SYMBOL(jbd2_journal_release_buffer);
++EXPORT_SYMBOL(jbd2_journal_forget);
++#if 0
++EXPORT_SYMBOL(journal_sync_buffer);
++#endif
++EXPORT_SYMBOL(jbd2_journal_flush);
++EXPORT_SYMBOL(jbd2_journal_revoke);
++
++EXPORT_SYMBOL(jbd2_journal_init_dev);
++EXPORT_SYMBOL(jbd2_journal_init_inode);
++EXPORT_SYMBOL(jbd2_journal_update_format);
++EXPORT_SYMBOL(jbd2_journal_check_used_features);
++EXPORT_SYMBOL(jbd2_journal_check_available_features);
++EXPORT_SYMBOL(jbd2_journal_set_features);
++EXPORT_SYMBOL(jbd2_journal_create);
++EXPORT_SYMBOL(jbd2_journal_load);
++EXPORT_SYMBOL(jbd2_journal_destroy);
++EXPORT_SYMBOL(jbd2_journal_update_superblock);
++EXPORT_SYMBOL(jbd2_journal_abort);
++EXPORT_SYMBOL(jbd2_journal_errno);
++EXPORT_SYMBOL(jbd2_journal_ack_err);
++EXPORT_SYMBOL(jbd2_journal_clear_err);
++EXPORT_SYMBOL(jbd2_log_wait_commit);
++EXPORT_SYMBOL(jbd2_journal_start_commit);
++EXPORT_SYMBOL(jbd2_journal_force_commit_nested);
++EXPORT_SYMBOL(jbd2_journal_wipe);
++EXPORT_SYMBOL(jbd2_journal_blocks_per_page);
++EXPORT_SYMBOL(jbd2_journal_invalidatepage);
++EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
++EXPORT_SYMBOL(jbd2_journal_force_commit);
++
++static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
++static void __journal_abort_soft (journal_t *journal, int errno);
++static int jbd2_journal_create_jbd_slab(size_t slab_size);
++
++/*
++ * Helper function used to manage commit timeouts
++ */
++
++static void commit_timeout(unsigned long __data)
++{
++ struct task_struct * p = (struct task_struct *) __data;
++
++ wake_up_process(p);
++}
++
++/*
++ * kjournald2: The main thread function used to manage a logging device
++ * journal.
++ *
++ * This kernel thread is responsible for two things:
++ *
++ * 1) COMMIT: Every so often we need to commit the current state of the
++ * filesystem to disk. The journal thread is responsible for writing
++ * all of the metadata buffers to disk.
++ *
++ * 2) CHECKPOINT: We cannot reuse a used section of the log file until all
++ * of the data in that part of the log has been rewritten elsewhere on
++ * the disk. Flushing these old buffers to reclaim space in the log is
++ * known as checkpointing, and this thread is responsible for that job.
++ */
++
++static int kjournald2(void *arg)
++{
++ journal_t *journal = arg;
++ transaction_t *transaction;
++
++ /*
++ * Set up an interval timer which can be used to trigger a commit wakeup
++ * after the commit interval expires
++ */
++ setup_timer(&journal->j_commit_timer, commit_timeout,
++ (unsigned long)current);
++
++ /* Record that the journal thread is running */
++ journal->j_task = current;
++ wake_up(&journal->j_wait_done_commit);
++
++ printk(KERN_INFO "kjournald2 starting. Commit interval %ld seconds\n",
++ journal->j_commit_interval / HZ);
++
++ /*
++ * And now, wait forever for commit wakeup events.
++ */
++ spin_lock(&journal->j_state_lock);
++
++loop:
++ if (journal->j_flags & JBD2_UNMOUNT)
++ goto end_loop;
++
++ jbd_debug(1, "commit_sequence=%d, commit_request=%d\n",
++ journal->j_commit_sequence, journal->j_commit_request);
++
++ if (journal->j_commit_sequence != journal->j_commit_request) {
++ jbd_debug(1, "OK, requests differ\n");
++ spin_unlock(&journal->j_state_lock);
++ del_timer_sync(&journal->j_commit_timer);
++ jbd2_journal_commit_transaction(journal);
++ spin_lock(&journal->j_state_lock);
++ goto loop;
++ }
++
++ wake_up(&journal->j_wait_done_commit);
++ if (freezing(current)) {
++ /*
++ * The simpler the better. Flushing journal isn't a
++ * good idea, because that depends on threads that may
++ * be already stopped.
++ */
++ jbd_debug(1, "Now suspending kjournald2\n");
++ spin_unlock(&journal->j_state_lock);
++ refrigerator();
++ spin_lock(&journal->j_state_lock);
++ } else {
++ /*
++ * We assume on resume that commits are already there,
++ * so we don't sleep
++ */
++ DEFINE_WAIT(wait);
++ int should_sleep = 1;
++
++ prepare_to_wait(&journal->j_wait_commit, &wait,
++ TASK_INTERRUPTIBLE);
++ if (journal->j_commit_sequence != journal->j_commit_request)
++ should_sleep = 0;
++ transaction = journal->j_running_transaction;
++ if (transaction && time_after_eq(jiffies,
++ transaction->t_expires))
++ should_sleep = 0;
++ if (journal->j_flags & JBD2_UNMOUNT)
++ should_sleep = 0;
++ if (should_sleep) {
++ spin_unlock(&journal->j_state_lock);
++ schedule();
++ spin_lock(&journal->j_state_lock);
++ }
++ finish_wait(&journal->j_wait_commit, &wait);
++ }
++
++ jbd_debug(1, "kjournald2 wakes\n");
++
++ /*
++ * Were we woken up by a commit wakeup event?
++ */
++ transaction = journal->j_running_transaction;
++ if (transaction && time_after_eq(jiffies, transaction->t_expires)) {
++ journal->j_commit_request = transaction->t_tid;
++ jbd_debug(1, "woke because of timeout\n");
++ }
++ goto loop;
++
++end_loop:
++ spin_unlock(&journal->j_state_lock);
++ del_timer_sync(&journal->j_commit_timer);
++ journal->j_task = NULL;
++ wake_up(&journal->j_wait_done_commit);
++ jbd_debug(1, "Journal thread exiting.\n");
++ return 0;
++}
++
++static void jbd2_journal_start_thread(journal_t *journal)
++{
++ kthread_run(kjournald2, journal, "kjournald2");
++ wait_event(journal->j_wait_done_commit, journal->j_task != 0);
++}
++
++static void journal_kill_thread(journal_t *journal)
++{
++ spin_lock(&journal->j_state_lock);
++ journal->j_flags |= JBD2_UNMOUNT;
++
++ while (journal->j_task) {
++ wake_up(&journal->j_wait_commit);
++ spin_unlock(&journal->j_state_lock);
++ wait_event(journal->j_wait_done_commit, journal->j_task == 0);
++ spin_lock(&journal->j_state_lock);
++ }
++ spin_unlock(&journal->j_state_lock);
++}
++
++/*
++ * jbd2_journal_write_metadata_buffer: write a metadata buffer to the journal.
++ *
++ * Writes a metadata buffer to a given disk block. The actual IO is not
++ * performed but a new buffer_head is constructed which labels the data
++ * to be written with the correct destination disk block.
++ *
++ * Any magic-number escaping which needs to be done will cause a
++ * copy-out here. If the buffer happens to start with the
++ * JBD2_MAGIC_NUMBER, then we can't write it to the log directly: the
++ * magic number is only written to the log for descripter blocks. In
++ * this case, we copy the data and replace the first word with 0, and we
++ * return a result code which indicates that this buffer needs to be
++ * marked as an escaped buffer in the corresponding log descriptor
++ * block. The missing word can then be restored when the block is read
++ * during recovery.
++ *
++ * If the source buffer has already been modified by a new transaction
++ * since we took the last commit snapshot, we use the frozen copy of
++ * that data for IO. If we end up using the existing buffer_head's data
++ * for the write, then we *have* to lock the buffer to prevent anyone
++ * else from using and possibly modifying it while the IO is in
++ * progress.
++ *
++ * The function returns a pointer to the buffer_heads to be used for IO.
++ *
++ * We assume that the journal has already been locked in this function.
++ *
++ * Return value:
++ * <0: Error
++ * >=0: Finished OK
++ *
++ * On success:
++ * Bit 0 set == escape performed on the data
++ * Bit 1 set == buffer copy-out performed (kfree the data after IO)
++ */
++
++int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
++ struct journal_head *jh_in,
++ struct journal_head **jh_out,
++ unsigned long long blocknr)
++{
++ int need_copy_out = 0;
++ int done_copy_out = 0;
++ int do_escape = 0;
++ char *mapped_data;
++ struct buffer_head *new_bh;
++ struct journal_head *new_jh;
++ struct page *new_page;
++ unsigned int new_offset;
++ struct buffer_head *bh_in = jh2bh(jh_in);
++
++ /*
++ * The buffer really shouldn't be locked: only the current committing
++ * transaction is allowed to write it, so nobody else is allowed
++ * to do any IO.
++ *
++ * akpm: except if we're journalling data, and write() output is
++ * also part of a shared mapping, and another thread has
++ * decided to launch a writepage() against this buffer.
++ */
++ J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
++
++ new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
++
++ /*
++ * If a new transaction has already done a buffer copy-out, then
++ * we use that version of the data for the commit.
++ */
++ jbd_lock_bh_state(bh_in);
++repeat:
++ if (jh_in->b_frozen_data) {
++ done_copy_out = 1;
++ new_page = virt_to_page(jh_in->b_frozen_data);
++ new_offset = offset_in_page(jh_in->b_frozen_data);
++ } else {
++ new_page = jh2bh(jh_in)->b_page;
++ new_offset = offset_in_page(jh2bh(jh_in)->b_data);
++ }
++
++ mapped_data = kmap_atomic(new_page, KM_USER0);
++ /*
++ * Check for escaping
++ */
++ if (*((__be32 *)(mapped_data + new_offset)) ==
++ cpu_to_be32(JBD2_MAGIC_NUMBER)) {
++ need_copy_out = 1;
++ do_escape = 1;
++ }
++ kunmap_atomic(mapped_data, KM_USER0);
++
++ /*
++ * Do we need to do a data copy?
++ */
++ if (need_copy_out && !done_copy_out) {
++ char *tmp;
++
++ jbd_unlock_bh_state(bh_in);
++ tmp = jbd2_slab_alloc(bh_in->b_size, GFP_NOFS);
++ jbd_lock_bh_state(bh_in);
++ if (jh_in->b_frozen_data) {
++ jbd2_slab_free(tmp, bh_in->b_size);
++ goto repeat;
++ }
++
++ jh_in->b_frozen_data = tmp;
++ mapped_data = kmap_atomic(new_page, KM_USER0);
++ memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size);
++ kunmap_atomic(mapped_data, KM_USER0);
++
++ new_page = virt_to_page(tmp);
++ new_offset = offset_in_page(tmp);
++ done_copy_out = 1;
++ }
++
++ /*
++ * Did we need to do an escaping? Now we've done all the
++ * copying, we can finally do so.
++ */
++ if (do_escape) {
++ mapped_data = kmap_atomic(new_page, KM_USER0);
++ *((unsigned int *)(mapped_data + new_offset)) = 0;
++ kunmap_atomic(mapped_data, KM_USER0);
++ }
++
++ /* keep subsequent assertions sane */
++ new_bh->b_state = 0;
++ init_buffer(new_bh, NULL, NULL);
++ atomic_set(&new_bh->b_count, 1);
++ jbd_unlock_bh_state(bh_in);
++
++ new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
++
++ set_bh_page(new_bh, new_page, new_offset);
++ new_jh->b_transaction = NULL;
++ new_bh->b_size = jh2bh(jh_in)->b_size;
++ new_bh->b_bdev = transaction->t_journal->j_dev;
++ new_bh->b_blocknr = blocknr;
++ set_buffer_mapped(new_bh);
++ set_buffer_dirty(new_bh);
++
++ *jh_out = new_jh;
++
++ /*
++ * The to-be-written buffer needs to get moved to the io queue,
++ * and the original buffer whose contents we are shadowing or
++ * copying is moved to the transaction's shadow queue.
++ */
++ JBUFFER_TRACE(jh_in, "file as BJ_Shadow");
++ jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
++ JBUFFER_TRACE(new_jh, "file as BJ_IO");
++ jbd2_journal_file_buffer(new_jh, transaction, BJ_IO);
++
++ return do_escape | (done_copy_out << 1);
++}
++
++/*
++ * Allocation code for the journal file. Manage the space left in the
++ * journal, so that we can begin checkpointing when appropriate.
++ */
++
++/*
++ * __jbd2_log_space_left: Return the number of free blocks left in the journal.
++ *
++ * Called with the journal already locked.
++ *
++ * Called under j_state_lock
++ */
++
++int __jbd2_log_space_left(journal_t *journal)
++{
++ int left = journal->j_free;
++
++ assert_spin_locked(&journal->j_state_lock);
++
++ /*
++ * Be pessimistic here about the number of those free blocks which
++ * might be required for log descriptor control blocks.
++ */
++
++#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */
++
++ left -= MIN_LOG_RESERVED_BLOCKS;
++
++ if (left <= 0)
++ return 0;
++ left -= (left >> 3);
++ return left;
++}
++
++/*
++ * Called under j_state_lock. Returns true if a transaction was started.
++ */
++int __jbd2_log_start_commit(journal_t *journal, tid_t target)
++{
++ /*
++ * Are we already doing a recent enough commit?
++ */
++ if (!tid_geq(journal->j_commit_request, target)) {
++ /*
++ * We want a new commit: OK, mark the request and wakup the
++ * commit thread. We do _not_ do the commit ourselves.
++ */
++
++ journal->j_commit_request = target;
++ jbd_debug(1, "JBD: requesting commit %d/%d\n",
++ journal->j_commit_request,
++ journal->j_commit_sequence);
++ wake_up(&journal->j_wait_commit);
++ return 1;
++ }
++ return 0;
++}
++
++int jbd2_log_start_commit(journal_t *journal, tid_t tid)
++{
++ int ret;
++
++ spin_lock(&journal->j_state_lock);
++ ret = __jbd2_log_start_commit(journal, tid);
++ spin_unlock(&journal->j_state_lock);
++ return ret;
++}
++
++/*
++ * Force and wait upon a commit if the calling process is not within
++ * transaction. This is used for forcing out undo-protected data which contains
++ * bitmaps, when the fs is running out of space.
++ *
++ * We can only force the running transaction if we don't have an active handle;
++ * otherwise, we will deadlock.
++ *
++ * Returns true if a transaction was started.
++ */
++int jbd2_journal_force_commit_nested(journal_t *journal)
++{
++ transaction_t *transaction = NULL;
++ tid_t tid;
++
++ spin_lock(&journal->j_state_lock);
++ if (journal->j_running_transaction && !current->journal_info) {
++ transaction = journal->j_running_transaction;
++ __jbd2_log_start_commit(journal, transaction->t_tid);
++ } else if (journal->j_committing_transaction)
++ transaction = journal->j_committing_transaction;
++
++ if (!transaction) {
++ spin_unlock(&journal->j_state_lock);
++ return 0; /* Nothing to retry */
++ }
++
++ tid = transaction->t_tid;
++ spin_unlock(&journal->j_state_lock);
++ jbd2_log_wait_commit(journal, tid);
++ return 1;
++}
++
++/*
++ * Start a commit of the current running transaction (if any). Returns true
++ * if a transaction was started, and fills its tid in at *ptid
++ */
++int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
++{
++ int ret = 0;
++
++ spin_lock(&journal->j_state_lock);
++ if (journal->j_running_transaction) {
++ tid_t tid = journal->j_running_transaction->t_tid;
++
++ ret = __jbd2_log_start_commit(journal, tid);
++ if (ret && ptid)
++ *ptid = tid;
++ } else if (journal->j_committing_transaction && ptid) {
++ /*
++ * If ext3_write_super() recently started a commit, then we
++ * have to wait for completion of that transaction
++ */
++ *ptid = journal->j_committing_transaction->t_tid;
++ ret = 1;
++ }
++ spin_unlock(&journal->j_state_lock);
++ return ret;
++}
++
++/*
++ * Wait for a specified commit to complete.
++ * The caller may not hold the journal lock.
++ */
++int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
++{
++ int err = 0;
++
++#ifdef CONFIG_JBD_DEBUG
++ spin_lock(&journal->j_state_lock);
++ if (!tid_geq(journal->j_commit_request, tid)) {
++ printk(KERN_EMERG
++ "%s: error: j_commit_request=%d, tid=%d\n",
++ __FUNCTION__, journal->j_commit_request, tid);
++ }
++ spin_unlock(&journal->j_state_lock);
++#endif
++ spin_lock(&journal->j_state_lock);
++ while (tid_gt(tid, journal->j_commit_sequence)) {
++ jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n",
++ tid, journal->j_commit_sequence);
++ wake_up(&journal->j_wait_commit);
++ spin_unlock(&journal->j_state_lock);
++ wait_event(journal->j_wait_done_commit,
++ !tid_gt(tid, journal->j_commit_sequence));
++ spin_lock(&journal->j_state_lock);
++ }
++ spin_unlock(&journal->j_state_lock);
++
++ if (unlikely(is_journal_aborted(journal))) {
++ printk(KERN_EMERG "journal commit I/O error\n");
++ err = -EIO;
++ }
++ return err;
++}
++
++/*
++ * Log buffer allocation routines:
++ */
++
++int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp)
++{
++ unsigned long blocknr;
++
++ spin_lock(&journal->j_state_lock);
++ J_ASSERT(journal->j_free > 1);
++
++ blocknr = journal->j_head;
++ journal->j_head++;
++ journal->j_free--;
++ if (journal->j_head == journal->j_last)
++ journal->j_head = journal->j_first;
++ spin_unlock(&journal->j_state_lock);
++ return jbd2_journal_bmap(journal, blocknr, retp);
++}
++
++/*
++ * Conversion of logical to physical block numbers for the journal
++ *
++ * On external journals the journal blocks are identity-mapped, so
++ * this is a no-op. If needed, we can use j_blk_offset - everything is
++ * ready.
++ */
++int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
++ unsigned long long *retp)
++{
++ int err = 0;
++ unsigned long long ret;
++
++ if (journal->j_inode) {
++ ret = bmap(journal->j_inode, blocknr);
++ if (ret)
++ *retp = ret;
++ else {
++ char b[BDEVNAME_SIZE];
++
++ printk(KERN_ALERT "%s: journal block not found "
++ "at offset %lu on %s\n",
++ __FUNCTION__,
++ blocknr,
++ bdevname(journal->j_dev, b));
++ err = -EIO;
++ __journal_abort_soft(journal, err);
++ }
++ } else {
++ *retp = blocknr; /* +journal->j_blk_offset */
++ }
++ return err;
++}
++
++/*
++ * We play buffer_head aliasing tricks to write data/metadata blocks to
++ * the journal without copying their contents, but for journal
++ * descriptor blocks we do need to generate bona fide buffers.
++ *
++ * After the caller of jbd2_journal_get_descriptor_buffer() has finished modifying
++ * the buffer's contents they really should run flush_dcache_page(bh->b_page).
++ * But we don't bother doing that, so there will be coherency problems with
++ * mmaps of blockdevs which hold live JBD-controlled filesystems.
++ */
++struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
++{
++ struct buffer_head *bh;
++ unsigned long long blocknr;
++ int err;
++
++ err = jbd2_journal_next_log_block(journal, &blocknr);
++
++ if (err)
++ return NULL;
++
++ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
++ lock_buffer(bh);
++ memset(bh->b_data, 0, journal->j_blocksize);
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++ BUFFER_TRACE(bh, "return this buffer");
++ return jbd2_journal_add_journal_head(bh);
++}
++
++/*
++ * Management for journal control blocks: functions to create and
++ * destroy journal_t structures, and to initialise and read existing
++ * journal blocks from disk. */
++
++/* First: create and setup a journal_t object in memory. We initialise
++ * very few fields yet: that has to wait until we have created the
++ * journal structures from from scratch, or loaded them from disk. */
++
++static journal_t * journal_init_common (void)
++{
++ journal_t *journal;
++ int err;
++
++ journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL);
++ if (!journal)
++ goto fail;
++ memset(journal, 0, sizeof(*journal));
++
++ init_waitqueue_head(&journal->j_wait_transaction_locked);
++ init_waitqueue_head(&journal->j_wait_logspace);
++ init_waitqueue_head(&journal->j_wait_done_commit);
++ init_waitqueue_head(&journal->j_wait_checkpoint);
++ init_waitqueue_head(&journal->j_wait_commit);
++ init_waitqueue_head(&journal->j_wait_updates);
++ mutex_init(&journal->j_barrier);
++ mutex_init(&journal->j_checkpoint_mutex);
++ spin_lock_init(&journal->j_revoke_lock);
++ spin_lock_init(&journal->j_list_lock);
++ spin_lock_init(&journal->j_state_lock);
++
++ journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE);
++
++ /* The journal is marked for error until we succeed with recovery! */
++ journal->j_flags = JBD2_ABORT;
++
++ /* Set up a default-sized revoke table for the new mount. */
++ err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH);
++ if (err) {
++ kfree(journal);
++ goto fail;
++ }
++ return journal;
++fail:
++ return NULL;
++}
++
++/* jbd2_journal_init_dev and jbd2_journal_init_inode:
++ *
++ * Create a journal structure assigned some fixed set of disk blocks to
++ * the journal. We don't actually touch those disk blocks yet, but we
++ * need to set up all of the mapping information to tell the journaling
++ * system where the journal blocks are.
++ *
++ */
++
++/**
++ * journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure
++ * @bdev: Block device on which to create the journal
++ * @fs_dev: Device which hold journalled filesystem for this journal.
++ * @start: Block nr Start of journal.
++ * @len: Length of the journal in blocks.
++ * @blocksize: blocksize of journalling device
++ * @returns: a newly created journal_t *
++ *
++ * jbd2_journal_init_dev creates a journal which maps a fixed contiguous
++ * range of blocks on an arbitrary block device.
++ *
++ */
++journal_t * jbd2_journal_init_dev(struct block_device *bdev,
++ struct block_device *fs_dev,
++ unsigned long long start, int len, int blocksize)
++{
++ journal_t *journal = journal_init_common();
++ struct buffer_head *bh;
++ int n;
++
++ if (!journal)
++ return NULL;
++
++ /* journal descriptor can store up to n blocks -bzzz */
++ journal->j_blocksize = blocksize;
++ n = journal->j_blocksize / sizeof(journal_block_tag_t);
++ journal->j_wbufsize = n;
++ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
++ if (!journal->j_wbuf) {
++ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
++ __FUNCTION__);
++ kfree(journal);
++ journal = NULL;
++ goto out;
++ }
++ journal->j_dev = bdev;
++ journal->j_fs_dev = fs_dev;
++ journal->j_blk_offset = start;
++ journal->j_maxlen = len;
++
++ bh = __getblk(journal->j_dev, start, journal->j_blocksize);
++ J_ASSERT(bh != NULL);
++ journal->j_sb_buffer = bh;
++ journal->j_superblock = (journal_superblock_t *)bh->b_data;
++out:
++ return journal;
++}
++
++/**
++ * journal_t * jbd2_journal_init_inode () - creates a journal which maps to a inode.
++ * @inode: An inode to create the journal in
++ *
++ * jbd2_journal_init_inode creates a journal which maps an on-disk inode as
++ * the journal. The inode must exist already, must support bmap() and
++ * must have all data blocks preallocated.
++ */
++journal_t * jbd2_journal_init_inode (struct inode *inode)
++{
++ struct buffer_head *bh;
++ journal_t *journal = journal_init_common();
++ int err;
++ int n;
++ unsigned long long blocknr;
++
++ if (!journal)
++ return NULL;
++
++ journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
++ journal->j_inode = inode;
++ jbd_debug(1,
++ "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
++ journal, inode->i_sb->s_id, inode->i_ino,
++ (long long) inode->i_size,
++ inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
++
++ journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
++ journal->j_blocksize = inode->i_sb->s_blocksize;
++
++ /* journal descriptor can store up to n blocks -bzzz */
++ n = journal->j_blocksize / sizeof(journal_block_tag_t);
++ journal->j_wbufsize = n;
++ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
++ if (!journal->j_wbuf) {
++ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
++ __FUNCTION__);
++ kfree(journal);
++ return NULL;
++ }
++
++ err = jbd2_journal_bmap(journal, 0, &blocknr);
++ /* If that failed, give up */
++ if (err) {
++ printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
++ __FUNCTION__);
++ kfree(journal);
++ return NULL;
++ }
++
++ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
++ J_ASSERT(bh != NULL);
++ journal->j_sb_buffer = bh;
++ journal->j_superblock = (journal_superblock_t *)bh->b_data;
++
++ return journal;
++}
++
++/*
++ * If the journal init or create aborts, we need to mark the journal
++ * superblock as being NULL to prevent the journal destroy from writing
++ * back a bogus superblock.
++ */
++static void journal_fail_superblock (journal_t *journal)
++{
++ struct buffer_head *bh = journal->j_sb_buffer;
++ brelse(bh);
++ journal->j_sb_buffer = NULL;
++}
++
++/*
++ * Given a journal_t structure, initialise the various fields for
++ * startup of a new journaling session. We use this both when creating
++ * a journal, and after recovering an old journal to reset it for
++ * subsequent use.
++ */
++
++static int journal_reset(journal_t *journal)
++{
++ journal_superblock_t *sb = journal->j_superblock;
++ unsigned long long first, last;
++
++ first = be32_to_cpu(sb->s_first);
++ last = be32_to_cpu(sb->s_maxlen);
++
++ journal->j_first = first;
++ journal->j_last = last;
++
++ journal->j_head = first;
++ journal->j_tail = first;
++ journal->j_free = last - first;
++
++ journal->j_tail_sequence = journal->j_transaction_sequence;
++ journal->j_commit_sequence = journal->j_transaction_sequence - 1;
++ journal->j_commit_request = journal->j_commit_sequence;
++
++ journal->j_max_transaction_buffers = journal->j_maxlen / 4;
++
++ /* Add the dynamic fields and write it to disk. */
++ jbd2_journal_update_superblock(journal, 1);
++ jbd2_journal_start_thread(journal);
++ return 0;
++}
++
++/**
++ * int jbd2_journal_create() - Initialise the new journal file
++ * @journal: Journal to create. This structure must have been initialised
++ *
++ * Given a journal_t structure which tells us which disk blocks we can
++ * use, create a new journal superblock and initialise all of the
++ * journal fields from scratch.
++ **/
++int jbd2_journal_create(journal_t *journal)
++{
++ unsigned long long blocknr;
++ struct buffer_head *bh;
++ journal_superblock_t *sb;
++ int i, err;
++
++ if (journal->j_maxlen < JBD2_MIN_JOURNAL_BLOCKS) {
++ printk (KERN_ERR "Journal length (%d blocks) too short.\n",
++ journal->j_maxlen);
++ journal_fail_superblock(journal);
++ return -EINVAL;
++ }
++
++ if (journal->j_inode == NULL) {
++ /*
++ * We don't know what block to start at!
++ */
++ printk(KERN_EMERG
++ "%s: creation of journal on external device!\n",
++ __FUNCTION__);
++ BUG();
++ }
++
++ /* Zero out the entire journal on disk. We cannot afford to
++ have any blocks on disk beginning with JBD2_MAGIC_NUMBER. */
++ jbd_debug(1, "JBD: Zeroing out journal blocks...\n");
++ for (i = 0; i < journal->j_maxlen; i++) {
++ err = jbd2_journal_bmap(journal, i, &blocknr);
++ if (err)
++ return err;
++ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
++ lock_buffer(bh);
++ memset (bh->b_data, 0, journal->j_blocksize);
++ BUFFER_TRACE(bh, "marking dirty");
++ mark_buffer_dirty(bh);
++ BUFFER_TRACE(bh, "marking uptodate");
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++ __brelse(bh);
++ }
++
++ sync_blockdev(journal->j_dev);
++ jbd_debug(1, "JBD: journal cleared.\n");
++
++ /* OK, fill in the initial static fields in the new superblock */
++ sb = journal->j_superblock;
++
++ sb->s_header.h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
++ sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);
++
++ sb->s_blocksize = cpu_to_be32(journal->j_blocksize);
++ sb->s_maxlen = cpu_to_be32(journal->j_maxlen);
++ sb->s_first = cpu_to_be32(1);
++
++ journal->j_transaction_sequence = 1;
++
++ journal->j_flags &= ~JBD2_ABORT;
++ journal->j_format_version = 2;
++
++ return journal_reset(journal);
++}
++
++/**
++ * void jbd2_journal_update_superblock() - Update journal sb on disk.
++ * @journal: The journal to update.
++ * @wait: Set to '0' if you don't want to wait for IO completion.
++ *
++ * Update a journal's dynamic superblock fields and write it to disk,
++ * optionally waiting for the IO to complete.
++ */
++void jbd2_journal_update_superblock(journal_t *journal, int wait)
++{
++ journal_superblock_t *sb = journal->j_superblock;
++ struct buffer_head *bh = journal->j_sb_buffer;
++
++ /*
++ * As a special case, if the on-disk copy is already marked as needing
++ * no recovery (s_start == 0) and there are no outstanding transactions
++ * in the filesystem, then we can safely defer the superblock update
++ * until the next commit by setting JBD2_FLUSHED. This avoids
++ * attempting a write to a potential-readonly device.
++ */
++ if (sb->s_start == 0 && journal->j_tail_sequence ==
++ journal->j_transaction_sequence) {
++ jbd_debug(1,"JBD: Skipping superblock update on recovered sb "
++ "(start %ld, seq %d, errno %d)\n",
++ journal->j_tail, journal->j_tail_sequence,
++ journal->j_errno);
++ goto out;
++ }
++
++ spin_lock(&journal->j_state_lock);
++ jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
++ journal->j_tail, journal->j_tail_sequence, journal->j_errno);
++
++ sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
++ sb->s_start = cpu_to_be32(journal->j_tail);
++ sb->s_errno = cpu_to_be32(journal->j_errno);
++ spin_unlock(&journal->j_state_lock);
++
++ BUFFER_TRACE(bh, "marking dirty");
++ mark_buffer_dirty(bh);
++ if (wait)
++ sync_dirty_buffer(bh);
++ else
++ ll_rw_block(SWRITE, 1, &bh);
++
++out:
++ /* If we have just flushed the log (by marking s_start==0), then
++ * any future commit will have to be careful to update the
++ * superblock again to re-record the true start of the log. */
++
++ spin_lock(&journal->j_state_lock);
++ if (sb->s_start)
++ journal->j_flags &= ~JBD2_FLUSHED;
++ else
++ journal->j_flags |= JBD2_FLUSHED;
++ spin_unlock(&journal->j_state_lock);
++}
++
++/*
++ * Read the superblock for a given journal, performing initial
++ * validation of the format.
++ */
++
++static int journal_get_superblock(journal_t *journal)
++{
++ struct buffer_head *bh;
++ journal_superblock_t *sb;
++ int err = -EIO;
++
++ bh = journal->j_sb_buffer;
++
++ J_ASSERT(bh != NULL);
++ if (!buffer_uptodate(bh)) {
++ ll_rw_block(READ, 1, &bh);
++ wait_on_buffer(bh);
++ if (!buffer_uptodate(bh)) {
++ printk (KERN_ERR
++ "JBD: IO error reading journal superblock\n");
++ goto out;
++ }
++ }
++
++ sb = journal->j_superblock;
++
++ err = -EINVAL;
++
++ if (sb->s_header.h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER) ||
++ sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) {
++ printk(KERN_WARNING "JBD: no valid journal superblock found\n");
++ goto out;
++ }
++
++ switch(be32_to_cpu(sb->s_header.h_blocktype)) {
++ case JBD2_SUPERBLOCK_V1:
++ journal->j_format_version = 1;
++ break;
++ case JBD2_SUPERBLOCK_V2:
++ journal->j_format_version = 2;
++ break;
++ default:
++ printk(KERN_WARNING "JBD: unrecognised superblock format ID\n");
++ goto out;
++ }
++
++ if (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen)
++ journal->j_maxlen = be32_to_cpu(sb->s_maxlen);
++ else if (be32_to_cpu(sb->s_maxlen) > journal->j_maxlen) {
++ printk (KERN_WARNING "JBD: journal file too short\n");
++ goto out;
++ }
++
++ return 0;
++
++out:
++ journal_fail_superblock(journal);
++ return err;
++}
++
++/*
++ * Load the on-disk journal superblock and read the key fields into the
++ * journal_t.
++ */
++
++static int load_superblock(journal_t *journal)
++{
++ int err;
++ journal_superblock_t *sb;
++
++ err = journal_get_superblock(journal);
++ if (err)
++ return err;
++
++ sb = journal->j_superblock;
++
++ journal->j_tail_sequence = be32_to_cpu(sb->s_sequence);
++ journal->j_tail = be32_to_cpu(sb->s_start);
++ journal->j_first = be32_to_cpu(sb->s_first);
++ journal->j_last = be32_to_cpu(sb->s_maxlen);
++ journal->j_errno = be32_to_cpu(sb->s_errno);
++
++ return 0;
++}
++
++
++/**
++ * int jbd2_journal_load() - Read journal from disk.
++ * @journal: Journal to act on.
++ *
++ * Given a journal_t structure which tells us which disk blocks contain
++ * a journal, read the journal from disk to initialise the in-memory
++ * structures.
++ */
++int jbd2_journal_load(journal_t *journal)
++{
++ int err;
++ journal_superblock_t *sb;
++
++ err = load_superblock(journal);
++ if (err)
++ return err;
++
++ sb = journal->j_superblock;
++ /* If this is a V2 superblock, then we have to check the
++ * features flags on it. */
++
++ if (journal->j_format_version >= 2) {
++ if ((sb->s_feature_ro_compat &
++ ~cpu_to_be32(JBD2_KNOWN_ROCOMPAT_FEATURES)) ||
++ (sb->s_feature_incompat &
++ ~cpu_to_be32(JBD2_KNOWN_INCOMPAT_FEATURES))) {
++ printk (KERN_WARNING
++ "JBD: Unrecognised features on journal\n");
++ return -EINVAL;
++ }
++ }
++
++ /*
++ * Create a slab for this blocksize
++ */
++ err = jbd2_journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize));
++ if (err)
++ return err;
++
++ /* Let the recovery code check whether it needs to recover any
++ * data from the journal. */
++ if (jbd2_journal_recover(journal))
++ goto recovery_error;
++
++ /* OK, we've finished with the dynamic journal bits:
++ * reinitialise the dynamic contents of the superblock in memory
++ * and reset them on disk. */
++ if (journal_reset(journal))
++ goto recovery_error;
++
++ journal->j_flags &= ~JBD2_ABORT;
++ journal->j_flags |= JBD2_LOADED;
++ return 0;
++
++recovery_error:
++ printk (KERN_WARNING "JBD: recovery failed\n");
++ return -EIO;
++}
++
++/**
++ * void jbd2_journal_destroy() - Release a journal_t structure.
++ * @journal: Journal to act on.
++ *
++ * Release a journal_t structure once it is no longer in use by the
++ * journaled object.
++ */
++void jbd2_journal_destroy(journal_t *journal)
++{
++ /* Wait for the commit thread to wake up and die. */
++ journal_kill_thread(journal);
++
++ /* Force a final log commit */
++ if (journal->j_running_transaction)
++ jbd2_journal_commit_transaction(journal);
++
++ /* Force any old transactions to disk */
++
++ /* Totally anal locking here... */
++ spin_lock(&journal->j_list_lock);
++ while (journal->j_checkpoint_transactions != NULL) {
++ spin_unlock(&journal->j_list_lock);
++ jbd2_log_do_checkpoint(journal);
++ spin_lock(&journal->j_list_lock);
++ }
++
++ J_ASSERT(journal->j_running_transaction == NULL);
++ J_ASSERT(journal->j_committing_transaction == NULL);
++ J_ASSERT(journal->j_checkpoint_transactions == NULL);
++ spin_unlock(&journal->j_list_lock);
++
++ /* We can now mark the journal as empty. */
++ journal->j_tail = 0;
++ journal->j_tail_sequence = ++journal->j_transaction_sequence;
++ if (journal->j_sb_buffer) {
++ jbd2_journal_update_superblock(journal, 1);
++ brelse(journal->j_sb_buffer);
++ }
++
++ if (journal->j_inode)
++ iput(journal->j_inode);
++ if (journal->j_revoke)
++ jbd2_journal_destroy_revoke(journal);
++ kfree(journal->j_wbuf);
++ kfree(journal);
++}
++
++
++/**
++ *int jbd2_journal_check_used_features () - Check if features specified are used.
++ * @journal: Journal to check.
++ * @compat: bitmask of compatible features
++ * @ro: bitmask of features that force read-only mount
++ * @incompat: bitmask of incompatible features
++ *
++ * Check whether the journal uses all of a given set of
++ * features. Return true (non-zero) if it does.
++ **/
++
++int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat,
++ unsigned long ro, unsigned long incompat)
++{
++ journal_superblock_t *sb;
++
++ if (!compat && !ro && !incompat)
++ return 1;
++ if (journal->j_format_version == 1)
++ return 0;
++
++ sb = journal->j_superblock;
++
++ if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) &&
++ ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) &&
++ ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat))
++ return 1;
++
++ return 0;
++}
++
++/**
++ * int jbd2_journal_check_available_features() - Check feature set in journalling layer
++ * @journal: Journal to check.
++ * @compat: bitmask of compatible features
++ * @ro: bitmask of features that force read-only mount
++ * @incompat: bitmask of incompatible features
++ *
++ * Check whether the journaling code supports the use of
++ * all of a given set of features on this journal. Return true
++ * (non-zero) if it can. */
++
++int jbd2_journal_check_available_features (journal_t *journal, unsigned long compat,
++ unsigned long ro, unsigned long incompat)
++{
++ journal_superblock_t *sb;
++
++ if (!compat && !ro && !incompat)
++ return 1;
++
++ sb = journal->j_superblock;
++
++ /* We can support any known requested features iff the
++ * superblock is in version 2. Otherwise we fail to support any
++ * extended sb features. */
++
++ if (journal->j_format_version != 2)
++ return 0;
++
++ if ((compat & JBD2_KNOWN_COMPAT_FEATURES) == compat &&
++ (ro & JBD2_KNOWN_ROCOMPAT_FEATURES) == ro &&
++ (incompat & JBD2_KNOWN_INCOMPAT_FEATURES) == incompat)
++ return 1;
++
++ return 0;
++}
++
++/**
++ * int jbd2_journal_set_features () - Mark a given journal feature in the superblock
++ * @journal: Journal to act on.
++ * @compat: bitmask of compatible features
++ * @ro: bitmask of features that force read-only mount
++ * @incompat: bitmask of incompatible features
++ *
++ * Mark a given journal feature as present on the
++ * superblock. Returns true if the requested features could be set.
++ *
++ */
++
++int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
++ unsigned long ro, unsigned long incompat)
++{
++ journal_superblock_t *sb;
++
++ if (jbd2_journal_check_used_features(journal, compat, ro, incompat))
++ return 1;
++
++ if (!jbd2_journal_check_available_features(journal, compat, ro, incompat))
++ return 0;
++
++ jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n",
++ compat, ro, incompat);
++
++ sb = journal->j_superblock;
++
++ sb->s_feature_compat |= cpu_to_be32(compat);
++ sb->s_feature_ro_compat |= cpu_to_be32(ro);
++ sb->s_feature_incompat |= cpu_to_be32(incompat);
++
++ return 1;
++}
++
++
++/**
++ * int jbd2_journal_update_format () - Update on-disk journal structure.
++ * @journal: Journal to act on.
++ *
++ * Given an initialised but unloaded journal struct, poke about in the
++ * on-disk structure to update it to the most recent supported version.
++ */
++int jbd2_journal_update_format (journal_t *journal)
++{
++ journal_superblock_t *sb;
++ int err;
++
++ err = journal_get_superblock(journal);
++ if (err)
++ return err;
++
++ sb = journal->j_superblock;
++
++ switch (be32_to_cpu(sb->s_header.h_blocktype)) {
++ case JBD2_SUPERBLOCK_V2:
++ return 0;
++ case JBD2_SUPERBLOCK_V1:
++ return journal_convert_superblock_v1(journal, sb);
++ default:
++ break;
++ }
++ return -EINVAL;
++}
++
++static int journal_convert_superblock_v1(journal_t *journal,
++ journal_superblock_t *sb)
++{
++ int offset, blocksize;
++ struct buffer_head *bh;
++
++ printk(KERN_WARNING
++ "JBD: Converting superblock from version 1 to 2.\n");
++
++ /* Pre-initialise new fields to zero */
++ offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb);
++ blocksize = be32_to_cpu(sb->s_blocksize);
++ memset(&sb->s_feature_compat, 0, blocksize-offset);
++
++ sb->s_nr_users = cpu_to_be32(1);
++ sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);
++ journal->j_format_version = 2;
++
++ bh = journal->j_sb_buffer;
++ BUFFER_TRACE(bh, "marking dirty");
++ mark_buffer_dirty(bh);
++ sync_dirty_buffer(bh);
++ return 0;
++}
++
++
++/**
++ * int jbd2_journal_flush () - Flush journal
++ * @journal: Journal to act on.
++ *
++ * Flush all data for a given journal to disk and empty the journal.
++ * Filesystems can use this when remounting readonly to ensure that
++ * recovery does not need to happen on remount.
++ */
++
++int jbd2_journal_flush(journal_t *journal)
++{
++ int err = 0;
++ transaction_t *transaction = NULL;
++ unsigned long old_tail;
++
++ spin_lock(&journal->j_state_lock);
++
++ /* Force everything buffered to the log... */
++ if (journal->j_running_transaction) {
++ transaction = journal->j_running_transaction;
++ __jbd2_log_start_commit(journal, transaction->t_tid);
++ } else if (journal->j_committing_transaction)
++ transaction = journal->j_committing_transaction;
++
++ /* Wait for the log commit to complete... */
++ if (transaction) {
++ tid_t tid = transaction->t_tid;
++
++ spin_unlock(&journal->j_state_lock);
++ jbd2_log_wait_commit(journal, tid);
++ } else {
++ spin_unlock(&journal->j_state_lock);
++ }
++
++ /* ...and flush everything in the log out to disk. */
++ spin_lock(&journal->j_list_lock);
++ while (!err && journal->j_checkpoint_transactions != NULL) {
++ spin_unlock(&journal->j_list_lock);
++ err = jbd2_log_do_checkpoint(journal);
++ spin_lock(&journal->j_list_lock);
++ }
++ spin_unlock(&journal->j_list_lock);
++ jbd2_cleanup_journal_tail(journal);
++
++ /* Finally, mark the journal as really needing no recovery.
++ * This sets s_start==0 in the underlying superblock, which is
++ * the magic code for a fully-recovered superblock. Any future
++ * commits of data to the journal will restore the current
++ * s_start value. */
++ spin_lock(&journal->j_state_lock);
++ old_tail = journal->j_tail;
++ journal->j_tail = 0;
++ spin_unlock(&journal->j_state_lock);
++ jbd2_journal_update_superblock(journal, 1);
++ spin_lock(&journal->j_state_lock);
++ journal->j_tail = old_tail;
++
++ J_ASSERT(!journal->j_running_transaction);
++ J_ASSERT(!journal->j_committing_transaction);
++ J_ASSERT(!journal->j_checkpoint_transactions);
++ J_ASSERT(journal->j_head == journal->j_tail);
++ J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
++ spin_unlock(&journal->j_state_lock);
++ return err;
++}
++
++/**
++ * int jbd2_journal_wipe() - Wipe journal contents
++ * @journal: Journal to act on.
++ * @write: flag (see below)
++ *
++ * Wipe out all of the contents of a journal, safely. This will produce
++ * a warning if the journal contains any valid recovery information.
++ * Must be called between journal_init_*() and jbd2_journal_load().
++ *
++ * If 'write' is non-zero, then we wipe out the journal on disk; otherwise
++ * we merely suppress recovery.
++ */
++
++int jbd2_journal_wipe(journal_t *journal, int write)
++{
++ journal_superblock_t *sb;
++ int err = 0;
++
++ J_ASSERT (!(journal->j_flags & JBD2_LOADED));
++
++ err = load_superblock(journal);
++ if (err)
++ return err;
++
++ sb = journal->j_superblock;
++
++ if (!journal->j_tail)
++ goto no_recovery;
++
++ printk (KERN_WARNING "JBD: %s recovery information on journal\n",
++ write ? "Clearing" : "Ignoring");
++
++ err = jbd2_journal_skip_recovery(journal);
++ if (write)
++ jbd2_journal_update_superblock(journal, 1);
++
++ no_recovery:
++ return err;
++}
++
++/*
++ * journal_dev_name: format a character string to describe on what
++ * device this journal is present.
++ */
++
++static const char *journal_dev_name(journal_t *journal, char *buffer)
++{
++ struct block_device *bdev;
++
++ if (journal->j_inode)
++ bdev = journal->j_inode->i_sb->s_bdev;
++ else
++ bdev = journal->j_dev;
++
++ return bdevname(bdev, buffer);
++}
++
++/*
++ * Journal abort has very specific semantics, which we describe
++ * for journal abort.
++ *
++ * Two internal function, which provide abort to te jbd layer
++ * itself are here.
++ */
++
++/*
++ * Quick version for internal journal use (doesn't lock the journal).
++ * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
++ * and don't attempt to make any other journal updates.
++ */
++void __jbd2_journal_abort_hard(journal_t *journal)
++{
++ transaction_t *transaction;
++ char b[BDEVNAME_SIZE];
++
++ if (journal->j_flags & JBD2_ABORT)
++ return;
++
++ printk(KERN_ERR "Aborting journal on device %s.\n",
++ journal_dev_name(journal, b));
++
++ spin_lock(&journal->j_state_lock);
++ journal->j_flags |= JBD2_ABORT;
++ transaction = journal->j_running_transaction;
++ if (transaction)
++ __jbd2_log_start_commit(journal, transaction->t_tid);
++ spin_unlock(&journal->j_state_lock);
++}
++
++/* Soft abort: record the abort error status in the journal superblock,
++ * but don't do any other IO. */
++static void __journal_abort_soft (journal_t *journal, int errno)
++{
++ if (journal->j_flags & JBD2_ABORT)
++ return;
++
++ if (!journal->j_errno)
++ journal->j_errno = errno;
++
++ __jbd2_journal_abort_hard(journal);
++
++ if (errno)
++ jbd2_journal_update_superblock(journal, 1);
++}
++
++/**
++ * void jbd2_journal_abort () - Shutdown the journal immediately.
++ * @journal: the journal to shutdown.
++ * @errno: an error number to record in the journal indicating
++ * the reason for the shutdown.
++ *
++ * Perform a complete, immediate shutdown of the ENTIRE
++ * journal (not of a single transaction). This operation cannot be
++ * undone without closing and reopening the journal.
++ *
++ * The jbd2_journal_abort function is intended to support higher level error
++ * recovery mechanisms such as the ext2/ext3 remount-readonly error
++ * mode.
++ *
++ * Journal abort has very specific semantics. Any existing dirty,
++ * unjournaled buffers in the main filesystem will still be written to
++ * disk by bdflush, but the journaling mechanism will be suspended
++ * immediately and no further transaction commits will be honoured.
++ *
++ * Any dirty, journaled buffers will be written back to disk without
++ * hitting the journal. Atomicity cannot be guaranteed on an aborted
++ * filesystem, but we _do_ attempt to leave as much data as possible
++ * behind for fsck to use for cleanup.
++ *
++ * Any attempt to get a new transaction handle on a journal which is in
++ * ABORT state will just result in an -EROFS error return. A
++ * jbd2_journal_stop on an existing handle will return -EIO if we have
++ * entered abort state during the update.
++ *
++ * Recursive transactions are not disturbed by journal abort until the
++ * final jbd2_journal_stop, which will receive the -EIO error.
++ *
++ * Finally, the jbd2_journal_abort call allows the caller to supply an errno
++ * which will be recorded (if possible) in the journal superblock. This
++ * allows a client to record failure conditions in the middle of a
++ * transaction without having to complete the transaction to record the
++ * failure to disk. ext3_error, for example, now uses this
++ * functionality.
++ *
++ * Errors which originate from within the journaling layer will NOT
++ * supply an errno; a null errno implies that absolutely no further
++ * writes are done to the journal (unless there are any already in
++ * progress).
++ *
++ */
++
++void jbd2_journal_abort(journal_t *journal, int errno)
++{
++ __journal_abort_soft(journal, errno);
++}
++
++/**
++ * int jbd2_journal_errno () - returns the journal's error state.
++ * @journal: journal to examine.
++ *
++ * This is the errno numbet set with jbd2_journal_abort(), the last
++ * time the journal was mounted - if the journal was stopped
++ * without calling abort this will be 0.
++ *
++ * If the journal has been aborted on this mount time -EROFS will
++ * be returned.
++ */
++int jbd2_journal_errno(journal_t *journal)
++{
++ int err;
++
++ spin_lock(&journal->j_state_lock);
++ if (journal->j_flags & JBD2_ABORT)
++ err = -EROFS;
++ else
++ err = journal->j_errno;
++ spin_unlock(&journal->j_state_lock);
++ return err;
++}
++
++/**
++ * int jbd2_journal_clear_err () - clears the journal's error state
++ * @journal: journal to act on.
++ *
++ * An error must be cleared or Acked to take a FS out of readonly
++ * mode.
++ */
++int jbd2_journal_clear_err(journal_t *journal)
++{
++ int err = 0;
++
++ spin_lock(&journal->j_state_lock);
++ if (journal->j_flags & JBD2_ABORT)
++ err = -EROFS;
++ else
++ journal->j_errno = 0;
++ spin_unlock(&journal->j_state_lock);
++ return err;
++}
++
++/**
++ * void jbd2_journal_ack_err() - Ack journal err.
++ * @journal: journal to act on.
++ *
++ * An error must be cleared or Acked to take a FS out of readonly
++ * mode.
++ */
++void jbd2_journal_ack_err(journal_t *journal)
++{
++ spin_lock(&journal->j_state_lock);
++ if (journal->j_errno)
++ journal->j_flags |= JBD2_ACK_ERR;
++ spin_unlock(&journal->j_state_lock);
++}
++
++int jbd2_journal_blocks_per_page(struct inode *inode)
++{
++ return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
++}
++
++/*
++ * helper functions to deal with 32 or 64bit block numbers.
++ */
++size_t journal_tag_bytes(journal_t *journal)
++{
++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
++ return JBD_TAG_SIZE64;
++ else
++ return JBD_TAG_SIZE32;
++}
++
++/*
++ * Simple support for retrying memory allocations. Introduced to help to
++ * debug different VM deadlock avoidance strategies.
++ */
++void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
++{
++ return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0));
++}
++
++/*
++ * jbd slab management: create 1k, 2k, 4k, 8k slabs as needed
++ * and allocate frozen and commit buffers from these slabs.
++ *
++ * Reason for doing this is to avoid, SLAB_DEBUG - since it could
++ * cause bh to cross page boundary.
++ */
++
++#define JBD_MAX_SLABS 5
++#define JBD_SLAB_INDEX(size) (size >> 11)
++
++static kmem_cache_t *jbd_slab[JBD_MAX_SLABS];
++static const char *jbd_slab_names[JBD_MAX_SLABS] = {
++ "jbd2_1k", "jbd2_2k", "jbd2_4k", NULL, "jbd2_8k"
++};
++
++static void jbd2_journal_destroy_jbd_slabs(void)
++{
++ int i;
++
++ for (i = 0; i < JBD_MAX_SLABS; i++) {
++ if (jbd_slab[i])
++ kmem_cache_destroy(jbd_slab[i]);
++ jbd_slab[i] = NULL;
++ }
++}
++
++static int jbd2_journal_create_jbd_slab(size_t slab_size)
++{
++ int i = JBD_SLAB_INDEX(slab_size);
++
++ BUG_ON(i >= JBD_MAX_SLABS);
++
++ /*
++ * Check if we already have a slab created for this size
++ */
++ if (jbd_slab[i])
++ return 0;
++
++ /*
++ * Create a slab and force alignment to be same as slabsize -
++ * this will make sure that allocations won't cross the page
++ * boundary.
++ */
++ jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
++ slab_size, slab_size, 0, NULL, NULL);
++ if (!jbd_slab[i]) {
++ printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++void * jbd2_slab_alloc(size_t size, gfp_t flags)
++{
++ int idx;
++
++ idx = JBD_SLAB_INDEX(size);
++ BUG_ON(jbd_slab[idx] == NULL);
++ return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL);
++}
++
++void jbd2_slab_free(void *ptr, size_t size)
++{
++ int idx;
++
++ idx = JBD_SLAB_INDEX(size);
++ BUG_ON(jbd_slab[idx] == NULL);
++ kmem_cache_free(jbd_slab[idx], ptr);
++}
++
++/*
++ * Journal_head storage management
++ */
++static kmem_cache_t *jbd2_journal_head_cache;
++#ifdef CONFIG_JBD_DEBUG
++static atomic_t nr_journal_heads = ATOMIC_INIT(0);
++#endif
++
++static int journal_init_jbd2_journal_head_cache(void)
++{
++ int retval;
++
++ J_ASSERT(jbd2_journal_head_cache == 0);
++ jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head",
++ sizeof(struct journal_head),
++ 0, /* offset */
++ 0, /* flags */
++ NULL, /* ctor */
++ NULL); /* dtor */
++ retval = 0;
++ if (jbd2_journal_head_cache == 0) {
++ retval = -ENOMEM;
++ printk(KERN_EMERG "JBD: no memory for journal_head cache\n");
++ }
++ return retval;
++}
++
++static void jbd2_journal_destroy_jbd2_journal_head_cache(void)
++{
++ J_ASSERT(jbd2_journal_head_cache != NULL);
++ kmem_cache_destroy(jbd2_journal_head_cache);
++ jbd2_journal_head_cache = NULL;
++}
++
++/*
++ * journal_head splicing and dicing
++ */
++static struct journal_head *journal_alloc_journal_head(void)
++{
++ struct journal_head *ret;
++ static unsigned long last_warning;
++
++#ifdef CONFIG_JBD_DEBUG
++ atomic_inc(&nr_journal_heads);
++#endif
++ ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
++ if (ret == 0) {
++ jbd_debug(1, "out of memory for journal_head\n");
++ if (time_after(jiffies, last_warning + 5*HZ)) {
++ printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
++ __FUNCTION__);
++ last_warning = jiffies;
++ }
++ while (ret == 0) {
++ yield();
++ ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
++ }
++ }
++ return ret;
++}
++
++static void journal_free_journal_head(struct journal_head *jh)
++{
++#ifdef CONFIG_JBD_DEBUG
++ atomic_dec(&nr_journal_heads);
++ memset(jh, JBD_POISON_FREE, sizeof(*jh));
++#endif
++ kmem_cache_free(jbd2_journal_head_cache, jh);
++}
++
++/*
++ * A journal_head is attached to a buffer_head whenever JBD has an
++ * interest in the buffer.
++ *
++ * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit
++ * is set. This bit is tested in core kernel code where we need to take
++ * JBD-specific actions. Testing the zeroness of ->b_private is not reliable
++ * there.
++ *
++ * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one.
++ *
++ * When a buffer has its BH_JBD bit set it is immune from being released by
++ * core kernel code, mainly via ->b_count.
++ *
++ * A journal_head may be detached from its buffer_head when the journal_head's
++ * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL.
++ * Various places in JBD call jbd2_journal_remove_journal_head() to indicate that the
++ * journal_head can be dropped if needed.
++ *
++ * Various places in the kernel want to attach a journal_head to a buffer_head
++ * _before_ attaching the journal_head to a transaction. To protect the
++ * journal_head in this situation, jbd2_journal_add_journal_head elevates the
++ * journal_head's b_jcount refcount by one. The caller must call
++ * jbd2_journal_put_journal_head() to undo this.
++ *
++ * So the typical usage would be:
++ *
++ * (Attach a journal_head if needed. Increments b_jcount)
++ * struct journal_head *jh = jbd2_journal_add_journal_head(bh);
++ * ...
++ * jh->b_transaction = xxx;
++ * jbd2_journal_put_journal_head(jh);
++ *
++ * Now, the journal_head's b_jcount is zero, but it is safe from being released
++ * because it has a non-zero b_transaction.
++ */
++
++/*
++ * Give a buffer_head a journal_head.
++ *
++ * Doesn't need the journal lock.
++ * May sleep.
++ */
++struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh)
++{
++ struct journal_head *jh;
++ struct journal_head *new_jh = NULL;
++
++repeat:
++ if (!buffer_jbd(bh)) {
++ new_jh = journal_alloc_journal_head();
++ memset(new_jh, 0, sizeof(*new_jh));
++ }
++
++ jbd_lock_bh_journal_head(bh);
++ if (buffer_jbd(bh)) {
++ jh = bh2jh(bh);
++ } else {
++ J_ASSERT_BH(bh,
++ (atomic_read(&bh->b_count) > 0) ||
++ (bh->b_page && bh->b_page->mapping));
++
++ if (!new_jh) {
++ jbd_unlock_bh_journal_head(bh);
++ goto repeat;
++ }
++
++ jh = new_jh;
++ new_jh = NULL; /* We consumed it */
++ set_buffer_jbd(bh);
++ bh->b_private = jh;
++ jh->b_bh = bh;
++ get_bh(bh);
++ BUFFER_TRACE(bh, "added journal_head");
++ }
++ jh->b_jcount++;
++ jbd_unlock_bh_journal_head(bh);
++ if (new_jh)
++ journal_free_journal_head(new_jh);
++ return bh->b_private;
++}
++
++/*
++ * Grab a ref against this buffer_head's journal_head. If it ended up not
++ * having a journal_head, return NULL
++ */
++struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh)
++{
++ struct journal_head *jh = NULL;
++
++ jbd_lock_bh_journal_head(bh);
++ if (buffer_jbd(bh)) {
++ jh = bh2jh(bh);
++ jh->b_jcount++;
++ }
++ jbd_unlock_bh_journal_head(bh);
++ return jh;
++}
++
++static void __journal_remove_journal_head(struct buffer_head *bh)
++{
++ struct journal_head *jh = bh2jh(bh);
++
++ J_ASSERT_JH(jh, jh->b_jcount >= 0);
++
++ get_bh(bh);
++ if (jh->b_jcount == 0) {
++ if (jh->b_transaction == NULL &&
++ jh->b_next_transaction == NULL &&
++ jh->b_cp_transaction == NULL) {
++ J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
++ J_ASSERT_BH(bh, buffer_jbd(bh));
++ J_ASSERT_BH(bh, jh2bh(jh) == bh);
++ BUFFER_TRACE(bh, "remove journal_head");
++ if (jh->b_frozen_data) {
++ printk(KERN_WARNING "%s: freeing "
++ "b_frozen_data\n",
++ __FUNCTION__);
++ jbd2_slab_free(jh->b_frozen_data, bh->b_size);
++ }
++ if (jh->b_committed_data) {
++ printk(KERN_WARNING "%s: freeing "
++ "b_committed_data\n",
++ __FUNCTION__);
++ jbd2_slab_free(jh->b_committed_data, bh->b_size);
++ }
++ bh->b_private = NULL;
++ jh->b_bh = NULL; /* debug, really */
++ clear_buffer_jbd(bh);
++ __brelse(bh);
++ journal_free_journal_head(jh);
++ } else {
++ BUFFER_TRACE(bh, "journal_head was locked");
++ }
++ }
++}
++
++/*
++ * jbd2_journal_remove_journal_head(): if the buffer isn't attached to a transaction
++ * and has a zero b_jcount then remove and release its journal_head. If we did
++ * see that the buffer is not used by any transaction we also "logically"
++ * decrement ->b_count.
++ *
++ * We in fact take an additional increment on ->b_count as a convenience,
++ * because the caller usually wants to do additional things with the bh
++ * after calling here.
++ * The caller of jbd2_journal_remove_journal_head() *must* run __brelse(bh) at some
++ * time. Once the caller has run __brelse(), the buffer is eligible for
++ * reaping by try_to_free_buffers().
++ */
++void jbd2_journal_remove_journal_head(struct buffer_head *bh)
++{
++ jbd_lock_bh_journal_head(bh);
++ __journal_remove_journal_head(bh);
++ jbd_unlock_bh_journal_head(bh);
++}
++
++/*
++ * Drop a reference on the passed journal_head. If it fell to zero then try to
++ * release the journal_head from the buffer_head.
++ */
++void jbd2_journal_put_journal_head(struct journal_head *jh)
++{
++ struct buffer_head *bh = jh2bh(jh);
++
++ jbd_lock_bh_journal_head(bh);
++ J_ASSERT_JH(jh, jh->b_jcount > 0);
++ --jh->b_jcount;
++ if (!jh->b_jcount && !jh->b_transaction) {
++ __journal_remove_journal_head(bh);
++ __brelse(bh);
++ }
++ jbd_unlock_bh_journal_head(bh);
++}
++
++/*
++ * /proc tunables
++ */
++#if defined(CONFIG_JBD_DEBUG)
++int jbd2_journal_enable_debug;
++EXPORT_SYMBOL(jbd2_journal_enable_debug);
++#endif
++
++#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)
++
++static struct proc_dir_entry *proc_jbd_debug;
++
++static int read_jbd_debug(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int ret;
++
++ ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug);
++ *eof = 1;
++ return ret;
++}
++
++static int write_jbd_debug(struct file *file, const char __user *buffer,
++ unsigned long count, void *data)
++{
++ char buf[32];
++
++ if (count > ARRAY_SIZE(buf) - 1)
++ count = ARRAY_SIZE(buf) - 1;
++ if (copy_from_user(buf, buffer, count))
++ return -EFAULT;
++ buf[ARRAY_SIZE(buf) - 1] = '\0';
++ jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10);
++ return count;
++}
++
++#define JBD_PROC_NAME "sys/fs/jbd2-debug"
++
++static void __init create_jbd_proc_entry(void)
++{
++ proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);
++ if (proc_jbd_debug) {
++ /* Why is this so hard? */
++ proc_jbd_debug->read_proc = read_jbd_debug;
++ proc_jbd_debug->write_proc = write_jbd_debug;
++ }
++}
++
++static void __exit jbd2_remove_jbd_proc_entry(void)
++{
++ if (proc_jbd_debug)
++ remove_proc_entry(JBD_PROC_NAME, NULL);
++}
++
++#else
++
++#define create_jbd_proc_entry() do {} while (0)
++#define jbd2_remove_jbd_proc_entry() do {} while (0)
++
++#endif
++
++kmem_cache_t *jbd2_handle_cache;
++
++static int __init journal_init_handle_cache(void)
++{
++ jbd2_handle_cache = kmem_cache_create("jbd2_journal_handle",
++ sizeof(handle_t),
++ 0, /* offset */
++ 0, /* flags */
++ NULL, /* ctor */
++ NULL); /* dtor */
++ if (jbd2_handle_cache == NULL) {
++ printk(KERN_EMERG "JBD: failed to create handle cache\n");
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++static void jbd2_journal_destroy_handle_cache(void)
++{
++ if (jbd2_handle_cache)
++ kmem_cache_destroy(jbd2_handle_cache);
++}
++
++/*
++ * Module startup and shutdown
++ */
++
++static int __init journal_init_caches(void)
++{
++ int ret;
++
++ ret = jbd2_journal_init_revoke_caches();
++ if (ret == 0)
++ ret = journal_init_jbd2_journal_head_cache();
++ if (ret == 0)
++ ret = journal_init_handle_cache();
++ return ret;
++}
++
++static void jbd2_journal_destroy_caches(void)
++{
++ jbd2_journal_destroy_revoke_caches();
++ jbd2_journal_destroy_jbd2_journal_head_cache();
++ jbd2_journal_destroy_handle_cache();
++ jbd2_journal_destroy_jbd_slabs();
++}
++
++static int __init journal_init(void)
++{
++ int ret;
++
++ BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);
++
++ ret = journal_init_caches();
++ if (ret != 0)
++ jbd2_journal_destroy_caches();
++ create_jbd_proc_entry();
++ return ret;
++}
++
++static void __exit journal_exit(void)
++{
++#ifdef CONFIG_JBD_DEBUG
++ int n = atomic_read(&nr_journal_heads);
++ if (n)
++ printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
++#endif
++ jbd2_remove_jbd_proc_entry();
++ jbd2_journal_destroy_caches();
++}
++
++MODULE_LICENSE("GPL");
++module_init(journal_init);
++module_exit(journal_exit);
++
+diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
+new file mode 100644
+index 0000000..9f10aca
+--- /dev/null
++++ b/fs/jbd2/recovery.c
+@@ -0,0 +1,609 @@
++/*
++ * linux/fs/recovery.c
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 1999
++ *
++ * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Journal recovery routines for the generic filesystem journaling code;
++ * part of the ext2fs journaling system.
++ */
++
++#ifndef __KERNEL__
++#include "jfs_user.h"
++#else
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#endif
++
++/*
++ * Maintain information about the progress of the recovery job, so that
++ * the different passes can carry information between them.
++ */
++struct recovery_info
++{
++ tid_t start_transaction;
++ tid_t end_transaction;
++
++ int nr_replays;
++ int nr_revokes;
++ int nr_revoke_hits;
++};
++
++enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
++static int do_one_pass(journal_t *journal,
++ struct recovery_info *info, enum passtype pass);
++static int scan_revoke_records(journal_t *, struct buffer_head *,
++ tid_t, struct recovery_info *);
++
++#ifdef __KERNEL__
++
++/* Release readahead buffers after use */
++static void journal_brelse_array(struct buffer_head *b[], int n)
++{
++ while (--n >= 0)
++ brelse (b[n]);
++}
++
++
++/*
++ * When reading from the journal, we are going through the block device
++ * layer directly and so there is no readahead being done for us. We
++ * need to implement any readahead ourselves if we want it to happen at
++ * all. Recovery is basically one long sequential read, so make sure we
++ * do the IO in reasonably large chunks.
++ *
++ * This is not so critical that we need to be enormously clever about
++ * the readahead size, though. 128K is a purely arbitrary, good-enough
++ * fixed value.
++ */
++
++#define MAXBUF 8
++static int do_readahead(journal_t *journal, unsigned int start)
++{
++ int err;
++ unsigned int max, nbufs, next;
++ unsigned long long blocknr;
++ struct buffer_head *bh;
++
++ struct buffer_head * bufs[MAXBUF];
++
++ /* Do up to 128K of readahead */
++ max = start + (128 * 1024 / journal->j_blocksize);
++ if (max > journal->j_maxlen)
++ max = journal->j_maxlen;
++
++ /* Do the readahead itself. We'll submit MAXBUF buffer_heads at
++ * a time to the block device IO layer. */
++
++ nbufs = 0;
++
++ for (next = start; next < max; next++) {
++ err = jbd2_journal_bmap(journal, next, &blocknr);
++
++ if (err) {
++ printk (KERN_ERR "JBD: bad block at offset %u\n",
++ next);
++ goto failed;
++ }
++
++ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
++ if (!bh) {
++ err = -ENOMEM;
++ goto failed;
++ }
++
++ if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
++ bufs[nbufs++] = bh;
++ if (nbufs == MAXBUF) {
++ ll_rw_block(READ, nbufs, bufs);
++ journal_brelse_array(bufs, nbufs);
++ nbufs = 0;
++ }
++ } else
++ brelse(bh);
++ }
++
++ if (nbufs)
++ ll_rw_block(READ, nbufs, bufs);
++ err = 0;
++
++failed:
++ if (nbufs)
++ journal_brelse_array(bufs, nbufs);
++ return err;
++}
++
++#endif /* __KERNEL__ */
++
++
++/*
++ * Read a block from the journal
++ */
++
++static int jread(struct buffer_head **bhp, journal_t *journal,
++ unsigned int offset)
++{
++ int err;
++ unsigned long long blocknr;
++ struct buffer_head *bh;
++
++ *bhp = NULL;
++
++ if (offset >= journal->j_maxlen) {
++ printk(KERN_ERR "JBD: corrupted journal superblock\n");
++ return -EIO;
++ }
++
++ err = jbd2_journal_bmap(journal, offset, &blocknr);
++
++ if (err) {
++ printk (KERN_ERR "JBD: bad block at offset %u\n",
++ offset);
++ return err;
++ }
++
++ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
++ if (!bh)
++ return -ENOMEM;
++
++ if (!buffer_uptodate(bh)) {
++ /* If this is a brand new buffer, start readahead.
++ Otherwise, we assume we are already reading it. */
++ if (!buffer_req(bh))
++ do_readahead(journal, offset);
++ wait_on_buffer(bh);
++ }
++
++ if (!buffer_uptodate(bh)) {
++ printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
++ offset);
++ brelse(bh);
++ return -EIO;
++ }
++
++ *bhp = bh;
++ return 0;
++}
++
++
++/*
++ * Count the number of in-use tags in a journal descriptor block.
++ */
++
++static int count_tags(journal_t *journal, struct buffer_head *bh)
++{
++ char * tagp;
++ journal_block_tag_t * tag;
++ int nr = 0, size = journal->j_blocksize;
++ int tag_bytes = journal_tag_bytes(journal);
++
++ tagp = &bh->b_data[sizeof(journal_header_t)];
++
++ while ((tagp - bh->b_data + tag_bytes) <= size) {
++ tag = (journal_block_tag_t *) tagp;
++
++ nr++;
++ tagp += tag_bytes;
++ if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID)))
++ tagp += 16;
++
++ if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG))
++ break;
++ }
++
++ return nr;
++}
++
++
++/* Make sure we wrap around the log correctly! */
++#define wrap(journal, var) \
++do { \
++ if (var >= (journal)->j_last) \
++ var -= ((journal)->j_last - (journal)->j_first); \
++} while (0)
++
++/**
++ * jbd2_journal_recover - recovers a on-disk journal
++ * @journal: the journal to recover
++ *
++ * The primary function for recovering the log contents when mounting a
++ * journaled device.
++ *
++ * Recovery is done in three passes. In the first pass, we look for the
++ * end of the log. In the second, we assemble the list of revoke
++ * blocks. In the third and final pass, we replay any un-revoked blocks
++ * in the log.
++ */
++int jbd2_journal_recover(journal_t *journal)
++{
++ int err;
++ journal_superblock_t * sb;
++
++ struct recovery_info info;
++
++ memset(&info, 0, sizeof(info));
++ sb = journal->j_superblock;
++
++ /*
++ * The journal superblock's s_start field (the current log head)
++ * is always zero if, and only if, the journal was cleanly
++ * unmounted.
++ */
++
++ if (!sb->s_start) {
++ jbd_debug(1, "No recovery required, last transaction %d\n",
++ be32_to_cpu(sb->s_sequence));
++ journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;
++ return 0;
++ }
++
++ err = do_one_pass(journal, &info, PASS_SCAN);
++ if (!err)
++ err = do_one_pass(journal, &info, PASS_REVOKE);
++ if (!err)
++ err = do_one_pass(journal, &info, PASS_REPLAY);
++
++ jbd_debug(0, "JBD: recovery, exit status %d, "
++ "recovered transactions %u to %u\n",
++ err, info.start_transaction, info.end_transaction);
++ jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
++ info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
++
++ /* Restart the log at the next transaction ID, thus invalidating
++ * any existing commit records in the log. */
++ journal->j_transaction_sequence = ++info.end_transaction;
++
++ jbd2_journal_clear_revoke(journal);
++ sync_blockdev(journal->j_fs_dev);
++ return err;
++}
++
++/**
++ * jbd2_journal_skip_recovery - Start journal and wipe exiting records
++ * @journal: journal to startup
++ *
++ * Locate any valid recovery information from the journal and set up the
++ * journal structures in memory to ignore it (presumably because the
++ * caller has evidence that it is out of date).
++ * This function does'nt appear to be exorted..
++ *
++ * We perform one pass over the journal to allow us to tell the user how
++ * much recovery information is being erased, and to let us initialise
++ * the journal transaction sequence numbers to the next unused ID.
++ */
++int jbd2_journal_skip_recovery(journal_t *journal)
++{
++ int err;
++ journal_superblock_t * sb;
++
++ struct recovery_info info;
++
++ memset (&info, 0, sizeof(info));
++ sb = journal->j_superblock;
++
++ err = do_one_pass(journal, &info, PASS_SCAN);
++
++ if (err) {
++ printk(KERN_ERR "JBD: error %d scanning journal\n", err);
++ ++journal->j_transaction_sequence;
++ } else {
++#ifdef CONFIG_JBD_DEBUG
++ int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
++#endif
++ jbd_debug(0,
++ "JBD: ignoring %d transaction%s from the journal.\n",
++ dropped, (dropped == 1) ? "" : "s");
++ journal->j_transaction_sequence = ++info.end_transaction;
++ }
++
++ journal->j_tail = 0;
++ return err;
++}
++
++static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag)
++{
++ unsigned long long block = be32_to_cpu(tag->t_blocknr);
++ if (tag_bytes > JBD_TAG_SIZE32)
++ block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32;
++ return block;
++}
++
++static int do_one_pass(journal_t *journal,
++ struct recovery_info *info, enum passtype pass)
++{
++ unsigned int first_commit_ID, next_commit_ID;
++ unsigned long next_log_block;
++ int err, success = 0;
++ journal_superblock_t * sb;
++ journal_header_t * tmp;
++ struct buffer_head * bh;
++ unsigned int sequence;
++ int blocktype;
++ int tag_bytes = journal_tag_bytes(journal);
++
++ /* Precompute the maximum metadata descriptors in a descriptor block */
++ int MAX_BLOCKS_PER_DESC;
++ MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
++ / tag_bytes);
++
++ /*
++ * First thing is to establish what we expect to find in the log
++ * (in terms of transaction IDs), and where (in terms of log
++ * block offsets): query the superblock.
++ */
++
++ sb = journal->j_superblock;
++ next_commit_ID = be32_to_cpu(sb->s_sequence);
++ next_log_block = be32_to_cpu(sb->s_start);
++
++ first_commit_ID = next_commit_ID;
++ if (pass == PASS_SCAN)
++ info->start_transaction = first_commit_ID;
++
++ jbd_debug(1, "Starting recovery pass %d\n", pass);
++
++ /*
++ * Now we walk through the log, transaction by transaction,
++ * making sure that each transaction has a commit block in the
++ * expected place. Each complete transaction gets replayed back
++ * into the main filesystem.
++ */
++
++ while (1) {
++ int flags;
++ char * tagp;
++ journal_block_tag_t * tag;
++ struct buffer_head * obh;
++ struct buffer_head * nbh;
++
++ cond_resched(); /* We're under lock_kernel() */
++
++ /* If we already know where to stop the log traversal,
++ * check right now that we haven't gone past the end of
++ * the log. */
++
++ if (pass != PASS_SCAN)
++ if (tid_geq(next_commit_ID, info->end_transaction))
++ break;
++
++ jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
++ next_commit_ID, next_log_block, journal->j_last);
++
++ /* Skip over each chunk of the transaction looking
++ * either the next descriptor block or the final commit
++ * record. */
++
++ jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
++ err = jread(&bh, journal, next_log_block);
++ if (err)
++ goto failed;
++
++ next_log_block++;
++ wrap(journal, next_log_block);
++
++ /* What kind of buffer is it?
++ *
++ * If it is a descriptor block, check that it has the
++ * expected sequence number. Otherwise, we're all done
++ * here. */
++
++ tmp = (journal_header_t *)bh->b_data;
++
++ if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {
++ brelse(bh);
++ break;
++ }
++
++ blocktype = be32_to_cpu(tmp->h_blocktype);
++ sequence = be32_to_cpu(tmp->h_sequence);
++ jbd_debug(3, "Found magic %d, sequence %d\n",
++ blocktype, sequence);
++
++ if (sequence != next_commit_ID) {
++ brelse(bh);
++ break;
++ }
++
++ /* OK, we have a valid descriptor block which matches
++ * all of the sequence number checks. What are we going
++ * to do with it? That depends on the pass... */
++
++ switch(blocktype) {
++ case JBD2_DESCRIPTOR_BLOCK:
++ /* If it is a valid descriptor block, replay it
++ * in pass REPLAY; otherwise, just skip over the
++ * blocks it describes. */
++ if (pass != PASS_REPLAY) {
++ next_log_block += count_tags(journal, bh);
++ wrap(journal, next_log_block);
++ brelse(bh);
++ continue;
++ }
++
++ /* A descriptor block: we can now write all of
++ * the data blocks. Yay, useful work is finally
++ * getting done here! */
++
++ tagp = &bh->b_data[sizeof(journal_header_t)];
++ while ((tagp - bh->b_data + tag_bytes)
++ <= journal->j_blocksize) {
++ unsigned long io_block;
++
++ tag = (journal_block_tag_t *) tagp;
++ flags = be32_to_cpu(tag->t_flags);
++
++ io_block = next_log_block++;
++ wrap(journal, next_log_block);
++ err = jread(&obh, journal, io_block);
++ if (err) {
++ /* Recover what we can, but
++ * report failure at the end. */
++ success = err;
++ printk (KERN_ERR
++ "JBD: IO error %d recovering "
++ "block %ld in log\n",
++ err, io_block);
++ } else {
++ unsigned long long blocknr;
++
++ J_ASSERT(obh != NULL);
++ blocknr = read_tag_block(tag_bytes,
++ tag);
++
++ /* If the block has been
++ * revoked, then we're all done
++ * here. */
++ if (jbd2_journal_test_revoke
++ (journal, blocknr,
++ next_commit_ID)) {
++ brelse(obh);
++ ++info->nr_revoke_hits;
++ goto skip_write;
++ }
++
++ /* Find a buffer for the new
++ * data being restored */
++ nbh = __getblk(journal->j_fs_dev,
++ blocknr,
++ journal->j_blocksize);
++ if (nbh == NULL) {
++ printk(KERN_ERR
++ "JBD: Out of memory "
++ "during recovery.\n");
++ err = -ENOMEM;
++ brelse(bh);
++ brelse(obh);
++ goto failed;
++ }
++
++ lock_buffer(nbh);
++ memcpy(nbh->b_data, obh->b_data,
++ journal->j_blocksize);
++ if (flags & JBD2_FLAG_ESCAPE) {
++ *((__be32 *)bh->b_data) =
++ cpu_to_be32(JBD2_MAGIC_NUMBER);
++ }
++
++ BUFFER_TRACE(nbh, "marking dirty");
++ set_buffer_uptodate(nbh);
++ mark_buffer_dirty(nbh);
++ BUFFER_TRACE(nbh, "marking uptodate");
++ ++info->nr_replays;
++ /* ll_rw_block(WRITE, 1, &nbh); */
++ unlock_buffer(nbh);
++ brelse(obh);
++ brelse(nbh);
++ }
++
++ skip_write:
++ tagp += tag_bytes;
++ if (!(flags & JBD2_FLAG_SAME_UUID))
++ tagp += 16;
++
++ if (flags & JBD2_FLAG_LAST_TAG)
++ break;
++ }
++
++ brelse(bh);
++ continue;
++
++ case JBD2_COMMIT_BLOCK:
++ /* Found an expected commit block: not much to
++ * do other than move on to the next sequence
++ * number. */
++ brelse(bh);
++ next_commit_ID++;
++ continue;
++
++ case JBD2_REVOKE_BLOCK:
++ /* If we aren't in the REVOKE pass, then we can
++ * just skip over this block. */
++ if (pass != PASS_REVOKE) {
++ brelse(bh);
++ continue;
++ }
++
++ err = scan_revoke_records(journal, bh,
++ next_commit_ID, info);
++ brelse(bh);
++ if (err)
++ goto failed;
++ continue;
++
++ default:
++ jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
++ blocktype);
++ brelse(bh);
++ goto done;
++ }
++ }
++
++ done:
++ /*
++ * We broke out of the log scan loop: either we came to the
++ * known end of the log or we found an unexpected block in the
++ * log. If the latter happened, then we know that the "current"
++ * transaction marks the end of the valid log.
++ */
++
++ if (pass == PASS_SCAN)
++ info->end_transaction = next_commit_ID;
++ else {
++ /* It's really bad news if different passes end up at
++ * different places (but possible due to IO errors). */
++ if (info->end_transaction != next_commit_ID) {
++ printk (KERN_ERR "JBD: recovery pass %d ended at "
++ "transaction %u, expected %u\n",
++ pass, next_commit_ID, info->end_transaction);
++ if (!success)
++ success = -EIO;
++ }
++ }
++
++ return success;
++
++ failed:
++ return err;
++}
++
++
++/* Scan a revoke record, marking all blocks mentioned as revoked. */
++
++static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
++ tid_t sequence, struct recovery_info *info)
++{
++ jbd2_journal_revoke_header_t *header;
++ int offset, max;
++ int record_len = 4;
++
++ header = (jbd2_journal_revoke_header_t *) bh->b_data;
++ offset = sizeof(jbd2_journal_revoke_header_t);
++ max = be32_to_cpu(header->r_count);
++
++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
++ record_len = 8;
++
++ while (offset + record_len <= max) {
++ unsigned long long blocknr;
++ int err;
++
++ if (record_len == 4)
++ blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));
++ else
++ blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset)));
++ offset += record_len;
++ err = jbd2_journal_set_revoke(journal, blocknr, sequence);
++ if (err)
++ return err;
++ ++info->nr_revokes;
++ }
++ return 0;
++}
+diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
+new file mode 100644
+index 0000000..380d199
+--- /dev/null
++++ b/fs/jbd2/revoke.c
+@@ -0,0 +1,712 @@
++/*
++ * linux/fs/revoke.c
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 2000
++ *
++ * Copyright 2000 Red Hat corp --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Journal revoke routines for the generic filesystem journaling code;
++ * part of the ext2fs journaling system.
++ *
++ * Revoke is the mechanism used to prevent old log records for deleted
++ * metadata from being replayed on top of newer data using the same
++ * blocks. The revoke mechanism is used in two separate places:
++ *
++ * + Commit: during commit we write the entire list of the current
++ * transaction's revoked blocks to the journal
++ *
++ * + Recovery: during recovery we record the transaction ID of all
++ * revoked blocks. If there are multiple revoke records in the log
++ * for a single block, only the last one counts, and if there is a log
++ * entry for a block beyond the last revoke, then that log entry still
++ * gets replayed.
++ *
++ * We can get interactions between revokes and new log data within a
++ * single transaction:
++ *
++ * Block is revoked and then journaled:
++ * The desired end result is the journaling of the new block, so we
++ * cancel the revoke before the transaction commits.
++ *
++ * Block is journaled and then revoked:
++ * The revoke must take precedence over the write of the block, so we
++ * need either to cancel the journal entry or to write the revoke
++ * later in the log than the log block. In this case, we choose the
++ * latter: journaling a block cancels any revoke record for that block
++ * in the current transaction, so any revoke for that block in the
++ * transaction must have happened after the block was journaled and so
++ * the revoke must take precedence.
++ *
++ * Block is revoked and then written as data:
++ * The data write is allowed to succeed, but the revoke is _not_
++ * cancelled. We still need to prevent old log records from
++ * overwriting the new data. We don't even need to clear the revoke
++ * bit here.
++ *
++ * Revoke information on buffers is a tri-state value:
++ *
++ * RevokeValid clear: no cached revoke status, need to look it up
++ * RevokeValid set, Revoked clear:
++ * buffer has not been revoked, and cancel_revoke
++ * need do nothing.
++ * RevokeValid set, Revoked set:
++ * buffer has been revoked.
++ */
++
++#ifndef __KERNEL__
++#include "jfs_user.h"
++#else
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#endif
++
++static kmem_cache_t *jbd2_revoke_record_cache;
++static kmem_cache_t *jbd2_revoke_table_cache;
++
++/* Each revoke record represents one single revoked block. During
++ journal replay, this involves recording the transaction ID of the
++ last transaction to revoke this block. */
++
++struct jbd2_revoke_record_s
++{
++ struct list_head hash;
++ tid_t sequence; /* Used for recovery only */
++ unsigned long long blocknr;
++};
++
++
++/* The revoke table is just a simple hash table of revoke records. */
++struct jbd2_revoke_table_s
++{
++ /* It is conceivable that we might want a larger hash table
++ * for recovery. Must be a power of two. */
++ int hash_size;
++ int hash_shift;
++ struct list_head *hash_table;
++};
++
++
++#ifdef __KERNEL__
++static void write_one_revoke_record(journal_t *, transaction_t *,
++ struct journal_head **, int *,
++ struct jbd2_revoke_record_s *);
++static void flush_descriptor(journal_t *, struct journal_head *, int);
++#endif
++
++/* Utility functions to maintain the revoke table */
++
++/* Borrowed from buffer.c: this is a tried and tested block hash function */
++static inline int hash(journal_t *journal, unsigned long long block)
++{
++ struct jbd2_revoke_table_s *table = journal->j_revoke;
++ int hash_shift = table->hash_shift;
++ int hash = (int)block ^ (int)((block >> 31) >> 1);
++
++ return ((hash << (hash_shift - 6)) ^
++ (hash >> 13) ^
++ (hash << (hash_shift - 12))) & (table->hash_size - 1);
++}
++
++static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
++ tid_t seq)
++{
++ struct list_head *hash_list;
++ struct jbd2_revoke_record_s *record;
++
++repeat:
++ record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS);
++ if (!record)
++ goto oom;
++
++ record->sequence = seq;
++ record->blocknr = blocknr;
++ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
++ spin_lock(&journal->j_revoke_lock);
++ list_add(&record->hash, hash_list);
++ spin_unlock(&journal->j_revoke_lock);
++ return 0;
++
++oom:
++ if (!journal_oom_retry)
++ return -ENOMEM;
++ jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__);
++ yield();
++ goto repeat;
++}
++
++/* Find a revoke record in the journal's hash table. */
++
++static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,
++ unsigned long long blocknr)
++{
++ struct list_head *hash_list;
++ struct jbd2_revoke_record_s *record;
++
++ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
++
++ spin_lock(&journal->j_revoke_lock);
++ record = (struct jbd2_revoke_record_s *) hash_list->next;
++ while (&(record->hash) != hash_list) {
++ if (record->blocknr == blocknr) {
++ spin_unlock(&journal->j_revoke_lock);
++ return record;
++ }
++ record = (struct jbd2_revoke_record_s *) record->hash.next;
++ }
++ spin_unlock(&journal->j_revoke_lock);
++ return NULL;
++}
++
++int __init jbd2_journal_init_revoke_caches(void)
++{
++ jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
++ sizeof(struct jbd2_revoke_record_s),
++ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (jbd2_revoke_record_cache == 0)
++ return -ENOMEM;
++
++ jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
++ sizeof(struct jbd2_revoke_table_s),
++ 0, 0, NULL, NULL);
++ if (jbd2_revoke_table_cache == 0) {
++ kmem_cache_destroy(jbd2_revoke_record_cache);
++ jbd2_revoke_record_cache = NULL;
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++void jbd2_journal_destroy_revoke_caches(void)
++{
++ kmem_cache_destroy(jbd2_revoke_record_cache);
++ jbd2_revoke_record_cache = NULL;
++ kmem_cache_destroy(jbd2_revoke_table_cache);
++ jbd2_revoke_table_cache = NULL;
++}
++
++/* Initialise the revoke table for a given journal to a given size. */
++
++int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
++{
++ int shift, tmp;
++
++ J_ASSERT (journal->j_revoke_table[0] == NULL);
++
++ shift = 0;
++ tmp = hash_size;
++ while((tmp >>= 1UL) != 0UL)
++ shift++;
++
++ journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
++ if (!journal->j_revoke_table[0])
++ return -ENOMEM;
++ journal->j_revoke = journal->j_revoke_table[0];
++
++ /* Check that the hash_size is a power of two */
++ J_ASSERT ((hash_size & (hash_size-1)) == 0);
++
++ journal->j_revoke->hash_size = hash_size;
++
++ journal->j_revoke->hash_shift = shift;
++
++ journal->j_revoke->hash_table =
++ kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
++ if (!journal->j_revoke->hash_table) {
++ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
++ journal->j_revoke = NULL;
++ return -ENOMEM;
++ }
++
++ for (tmp = 0; tmp < hash_size; tmp++)
++ INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
++
++ journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
++ if (!journal->j_revoke_table[1]) {
++ kfree(journal->j_revoke_table[0]->hash_table);
++ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
++ return -ENOMEM;
++ }
++
++ journal->j_revoke = journal->j_revoke_table[1];
++
++ /* Check that the hash_size is a power of two */
++ J_ASSERT ((hash_size & (hash_size-1)) == 0);
++
++ journal->j_revoke->hash_size = hash_size;
++
++ journal->j_revoke->hash_shift = shift;
++
++ journal->j_revoke->hash_table =
++ kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
++ if (!journal->j_revoke->hash_table) {
++ kfree(journal->j_revoke_table[0]->hash_table);
++ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
++ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]);
++ journal->j_revoke = NULL;
++ return -ENOMEM;
++ }
++
++ for (tmp = 0; tmp < hash_size; tmp++)
++ INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
++
++ spin_lock_init(&journal->j_revoke_lock);
++
++ return 0;
++}
++
++/* Destoy a journal's revoke table. The table must already be empty! */
++
++void jbd2_journal_destroy_revoke(journal_t *journal)
++{
++ struct jbd2_revoke_table_s *table;
++ struct list_head *hash_list;
++ int i;
++
++ table = journal->j_revoke_table[0];
++ if (!table)
++ return;
++
++ for (i=0; i<table->hash_size; i++) {
++ hash_list = &table->hash_table[i];
++ J_ASSERT (list_empty(hash_list));
++ }
++
++ kfree(table->hash_table);
++ kmem_cache_free(jbd2_revoke_table_cache, table);
++ journal->j_revoke = NULL;
++
++ table = journal->j_revoke_table[1];
++ if (!table)
++ return;
++
++ for (i=0; i<table->hash_size; i++) {
++ hash_list = &table->hash_table[i];
++ J_ASSERT (list_empty(hash_list));
++ }
++
++ kfree(table->hash_table);
++ kmem_cache_free(jbd2_revoke_table_cache, table);
++ journal->j_revoke = NULL;
++}
++
++
++#ifdef __KERNEL__
++
++/*
++ * jbd2_journal_revoke: revoke a given buffer_head from the journal. This
++ * prevents the block from being replayed during recovery if we take a
++ * crash after this current transaction commits. Any subsequent
++ * metadata writes of the buffer in this transaction cancel the
++ * revoke.
++ *
++ * Note that this call may block --- it is up to the caller to make
++ * sure that there are no further calls to journal_write_metadata
++ * before the revoke is complete. In ext3, this implies calling the
++ * revoke before clearing the block bitmap when we are deleting
++ * metadata.
++ *
++ * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a
++ * parameter, but does _not_ forget the buffer_head if the bh was only
++ * found implicitly.
++ *
++ * bh_in may not be a journalled buffer - it may have come off
++ * the hash tables without an attached journal_head.
++ *
++ * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count
++ * by one.
++ */
++
++int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
++ struct buffer_head *bh_in)
++{
++ struct buffer_head *bh = NULL;
++ journal_t *journal;
++ struct block_device *bdev;
++ int err;
++
++ might_sleep();
++ if (bh_in)
++ BUFFER_TRACE(bh_in, "enter");
++
++ journal = handle->h_transaction->t_journal;
++ if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){
++ J_ASSERT (!"Cannot set revoke feature!");
++ return -EINVAL;
++ }
++
++ bdev = journal->j_fs_dev;
++ bh = bh_in;
++
++ if (!bh) {
++ bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
++ if (bh)
++ BUFFER_TRACE(bh, "found on hash");
++ }
++#ifdef JBD_EXPENSIVE_CHECKING
++ else {
++ struct buffer_head *bh2;
++
++ /* If there is a different buffer_head lying around in
++ * memory anywhere... */
++ bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
++ if (bh2) {
++ /* ... and it has RevokeValid status... */
++ if (bh2 != bh && buffer_revokevalid(bh2))
++ /* ...then it better be revoked too,
++ * since it's illegal to create a revoke
++ * record against a buffer_head which is
++ * not marked revoked --- that would
++ * risk missing a subsequent revoke
++ * cancel. */
++ J_ASSERT_BH(bh2, buffer_revoked(bh2));
++ put_bh(bh2);
++ }
++ }
++#endif
++
++ /* We really ought not ever to revoke twice in a row without
++ first having the revoke cancelled: it's illegal to free a
++ block twice without allocating it in between! */
++ if (bh) {
++ if (!J_EXPECT_BH(bh, !buffer_revoked(bh),
++ "inconsistent data on disk")) {
++ if (!bh_in)
++ brelse(bh);
++ return -EIO;
++ }
++ set_buffer_revoked(bh);
++ set_buffer_revokevalid(bh);
++ if (bh_in) {
++ BUFFER_TRACE(bh_in, "call jbd2_journal_forget");
++ jbd2_journal_forget(handle, bh_in);
++ } else {
++ BUFFER_TRACE(bh, "call brelse");
++ __brelse(bh);
++ }
++ }
++
++ jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in);
++ err = insert_revoke_hash(journal, blocknr,
++ handle->h_transaction->t_tid);
++ BUFFER_TRACE(bh_in, "exit");
++ return err;
++}
++
++/*
++ * Cancel an outstanding revoke. For use only internally by the
++ * journaling code (called from jbd2_journal_get_write_access).
++ *
++ * We trust buffer_revoked() on the buffer if the buffer is already
++ * being journaled: if there is no revoke pending on the buffer, then we
++ * don't do anything here.
++ *
++ * This would break if it were possible for a buffer to be revoked and
++ * discarded, and then reallocated within the same transaction. In such
++ * a case we would have lost the revoked bit, but when we arrived here
++ * the second time we would still have a pending revoke to cancel. So,
++ * do not trust the Revoked bit on buffers unless RevokeValid is also
++ * set.
++ *
++ * The caller must have the journal locked.
++ */
++int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
++{
++ struct jbd2_revoke_record_s *record;
++ journal_t *journal = handle->h_transaction->t_journal;
++ int need_cancel;
++ int did_revoke = 0; /* akpm: debug */
++ struct buffer_head *bh = jh2bh(jh);
++
++ jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
++
++ /* Is the existing Revoke bit valid? If so, we trust it, and
++ * only perform the full cancel if the revoke bit is set. If
++ * not, we can't trust the revoke bit, and we need to do the
++ * full search for a revoke record. */
++ if (test_set_buffer_revokevalid(bh)) {
++ need_cancel = test_clear_buffer_revoked(bh);
++ } else {
++ need_cancel = 1;
++ clear_buffer_revoked(bh);
++ }
++
++ if (need_cancel) {
++ record = find_revoke_record(journal, bh->b_blocknr);
++ if (record) {
++ jbd_debug(4, "cancelled existing revoke on "
++ "blocknr %llu\n", (unsigned long long)bh->b_blocknr);
++ spin_lock(&journal->j_revoke_lock);
++ list_del(&record->hash);
++ spin_unlock(&journal->j_revoke_lock);
++ kmem_cache_free(jbd2_revoke_record_cache, record);
++ did_revoke = 1;
++ }
++ }
++
++#ifdef JBD_EXPENSIVE_CHECKING
++ /* There better not be one left behind by now! */
++ record = find_revoke_record(journal, bh->b_blocknr);
++ J_ASSERT_JH(jh, record == NULL);
++#endif
++
++ /* Finally, have we just cleared revoke on an unhashed
++ * buffer_head? If so, we'd better make sure we clear the
++ * revoked status on any hashed alias too, otherwise the revoke
++ * state machine will get very upset later on. */
++ if (need_cancel) {
++ struct buffer_head *bh2;
++ bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
++ if (bh2) {
++ if (bh2 != bh)
++ clear_buffer_revoked(bh2);
++ __brelse(bh2);
++ }
++ }
++ return did_revoke;
++}
++
++/* journal_switch_revoke table select j_revoke for next transaction
++ * we do not want to suspend any processing until all revokes are
++ * written -bzzz
++ */
++void jbd2_journal_switch_revoke_table(journal_t *journal)
++{
++ int i;
++
++ if (journal->j_revoke == journal->j_revoke_table[0])
++ journal->j_revoke = journal->j_revoke_table[1];
++ else
++ journal->j_revoke = journal->j_revoke_table[0];
++
++ for (i = 0; i < journal->j_revoke->hash_size; i++)
++ INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
++}
++
++/*
++ * Write revoke records to the journal for all entries in the current
++ * revoke hash, deleting the entries as we go.
++ *
++ * Called with the journal lock held.
++ */
++
++void jbd2_journal_write_revoke_records(journal_t *journal,
++ transaction_t *transaction)
++{
++ struct journal_head *descriptor;
++ struct jbd2_revoke_record_s *record;
++ struct jbd2_revoke_table_s *revoke;
++ struct list_head *hash_list;
++ int i, offset, count;
++
++ descriptor = NULL;
++ offset = 0;
++ count = 0;
++
++ /* select revoke table for committing transaction */
++ revoke = journal->j_revoke == journal->j_revoke_table[0] ?
++ journal->j_revoke_table[1] : journal->j_revoke_table[0];
++
++ for (i = 0; i < revoke->hash_size; i++) {
++ hash_list = &revoke->hash_table[i];
++
++ while (!list_empty(hash_list)) {
++ record = (struct jbd2_revoke_record_s *)
++ hash_list->next;
++ write_one_revoke_record(journal, transaction,
++ &descriptor, &offset,
++ record);
++ count++;
++ list_del(&record->hash);
++ kmem_cache_free(jbd2_revoke_record_cache, record);
++ }
++ }
++ if (descriptor)
++ flush_descriptor(journal, descriptor, offset);
++ jbd_debug(1, "Wrote %d revoke records\n", count);
++}
++
++/*
++ * Write out one revoke record. We need to create a new descriptor
++ * block if the old one is full or if we have not already created one.
++ */
++
++static void write_one_revoke_record(journal_t *journal,
++ transaction_t *transaction,
++ struct journal_head **descriptorp,
++ int *offsetp,
++ struct jbd2_revoke_record_s *record)
++{
++ struct journal_head *descriptor;
++ int offset;
++ journal_header_t *header;
++
++ /* If we are already aborting, this all becomes a noop. We
++ still need to go round the loop in
++ jbd2_journal_write_revoke_records in order to free all of the
++ revoke records: only the IO to the journal is omitted. */
++ if (is_journal_aborted(journal))
++ return;
++
++ descriptor = *descriptorp;
++ offset = *offsetp;
++
++ /* Make sure we have a descriptor with space left for the record */
++ if (descriptor) {
++ if (offset == journal->j_blocksize) {
++ flush_descriptor(journal, descriptor, offset);
++ descriptor = NULL;
++ }
++ }
++
++ if (!descriptor) {
++ descriptor = jbd2_journal_get_descriptor_buffer(journal);
++ if (!descriptor)
++ return;
++ header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
++ header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
++ header->h_blocktype = cpu_to_be32(JBD2_REVOKE_BLOCK);
++ header->h_sequence = cpu_to_be32(transaction->t_tid);
++
++ /* Record it so that we can wait for IO completion later */
++ JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");
++ jbd2_journal_file_buffer(descriptor, transaction, BJ_LogCtl);
++
++ offset = sizeof(jbd2_journal_revoke_header_t);
++ *descriptorp = descriptor;
++ }
++
++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) {
++ * ((__be64 *)(&jh2bh(descriptor)->b_data[offset])) =
++ cpu_to_be64(record->blocknr);
++ offset += 8;
++
++ } else {
++ * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
++ cpu_to_be32(record->blocknr);
++ offset += 4;
++ }
++
++ *offsetp = offset;
++}
++
++/*
++ * Flush a revoke descriptor out to the journal. If we are aborting,
++ * this is a noop; otherwise we are generating a buffer which needs to
++ * be waited for during commit, so it has to go onto the appropriate
++ * journal buffer list.
++ */
++
++static void flush_descriptor(journal_t *journal,
++ struct journal_head *descriptor,
++ int offset)
++{
++ jbd2_journal_revoke_header_t *header;
++ struct buffer_head *bh = jh2bh(descriptor);
++
++ if (is_journal_aborted(journal)) {
++ put_bh(bh);
++ return;
++ }
++
++ header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data;
++ header->r_count = cpu_to_be32(offset);
++ set_buffer_jwrite(bh);
++ BUFFER_TRACE(bh, "write");
++ set_buffer_dirty(bh);
++ ll_rw_block(SWRITE, 1, &bh);
++}
++#endif
++
++/*
++ * Revoke support for recovery.
++ *
++ * Recovery needs to be able to:
++ *
++ * record all revoke records, including the tid of the latest instance
++ * of each revoke in the journal
++ *
++ * check whether a given block in a given transaction should be replayed
++ * (ie. has not been revoked by a revoke record in that or a subsequent
++ * transaction)
++ *
++ * empty the revoke table after recovery.
++ */
++
++/*
++ * First, setting revoke records. We create a new revoke record for
++ * every block ever revoked in the log as we scan it for recovery, and
++ * we update the existing records if we find multiple revokes for a
++ * single block.
++ */
++
++int jbd2_journal_set_revoke(journal_t *journal,
++ unsigned long long blocknr,
++ tid_t sequence)
++{
++ struct jbd2_revoke_record_s *record;
++
++ record = find_revoke_record(journal, blocknr);
++ if (record) {
++ /* If we have multiple occurrences, only record the
++ * latest sequence number in the hashed record */
++ if (tid_gt(sequence, record->sequence))
++ record->sequence = sequence;
++ return 0;
++ }
++ return insert_revoke_hash(journal, blocknr, sequence);
++}
++
++/*
++ * Test revoke records. For a given block referenced in the log, has
++ * that block been revoked? A revoke record with a given transaction
++ * sequence number revokes all blocks in that transaction and earlier
++ * ones, but later transactions still need replayed.
++ */
++
++int jbd2_journal_test_revoke(journal_t *journal,
++ unsigned long long blocknr,
++ tid_t sequence)
++{
++ struct jbd2_revoke_record_s *record;
++
++ record = find_revoke_record(journal, blocknr);
++ if (!record)
++ return 0;
++ if (tid_gt(sequence, record->sequence))
++ return 0;
++ return 1;
++}
++
++/*
++ * Finally, once recovery is over, we need to clear the revoke table so
++ * that it can be reused by the running filesystem.
++ */
++
++void jbd2_journal_clear_revoke(journal_t *journal)
++{
++ int i;
++ struct list_head *hash_list;
++ struct jbd2_revoke_record_s *record;
++ struct jbd2_revoke_table_s *revoke;
++
++ revoke = journal->j_revoke;
++
++ for (i = 0; i < revoke->hash_size; i++) {
++ hash_list = &revoke->hash_table[i];
++ while (!list_empty(hash_list)) {
++ record = (struct jbd2_revoke_record_s*) hash_list->next;
++ list_del(&record->hash);
++ kmem_cache_free(jbd2_revoke_record_cache, record);
++ }
++ }
++}
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+new file mode 100644
+index 0000000..c051a94
+--- /dev/null
++++ b/fs/jbd2/transaction.c
+@@ -0,0 +1,2094 @@
++/*
++ * linux/fs/transaction.c
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 1998
++ *
++ * Copyright 1998 Red Hat corp --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Generic filesystem transaction handling code; part of the ext2fs
++ * journaling system.
++ *
++ * This file manages transactions (compound commits managed by the
++ * journaling code) and handles (individual atomic operations by the
++ * filesystem).
++ */
++
++#include <linux/time.h>
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/timer.h>
++#include <linux/smp_lock.h>
++#include <linux/mm.h>
++#include <linux/highmem.h>
++
++/*
++ * jbd2_get_transaction: obtain a new transaction_t object.
++ *
++ * Simply allocate and initialise a new transaction. Create it in
++ * RUNNING state and add it to the current journal (which should not
++ * have an existing running transaction: we only make a new transaction
++ * once we have started to commit the old one).
++ *
++ * Preconditions:
++ * The journal MUST be locked. We don't perform atomic mallocs on the
++ * new transaction and we can't block without protecting against other
++ * processes trying to touch the journal while it is in transition.
++ *
++ * Called under j_state_lock
++ */
++
++static transaction_t *
++jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
++{
++ transaction->t_journal = journal;
++ transaction->t_state = T_RUNNING;
++ transaction->t_tid = journal->j_transaction_sequence++;
++ transaction->t_expires = jiffies + journal->j_commit_interval;
++ spin_lock_init(&transaction->t_handle_lock);
++
++ /* Set up the commit timer for the new transaction. */
++ journal->j_commit_timer.expires = transaction->t_expires;
++ add_timer(&journal->j_commit_timer);
++
++ J_ASSERT(journal->j_running_transaction == NULL);
++ journal->j_running_transaction = transaction;
++
++ return transaction;
++}
++
++/*
++ * Handle management.
++ *
++ * A handle_t is an object which represents a single atomic update to a
++ * filesystem, and which tracks all of the modifications which form part
++ * of that one update.
++ */
++
++/*
++ * start_this_handle: Given a handle, deal with any locking or stalling
++ * needed to make sure that there is enough journal space for the handle
++ * to begin. Attach the handle to a transaction and set up the
++ * transaction's buffer credits.
++ */
++
++static int start_this_handle(journal_t *journal, handle_t *handle)
++{
++ transaction_t *transaction;
++ int needed;
++ int nblocks = handle->h_buffer_credits;
++ transaction_t *new_transaction = NULL;
++ int ret = 0;
++
++ if (nblocks > journal->j_max_transaction_buffers) {
++ printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
++ current->comm, nblocks,
++ journal->j_max_transaction_buffers);
++ ret = -ENOSPC;
++ goto out;
++ }
++
++alloc_transaction:
++ if (!journal->j_running_transaction) {
++ new_transaction = jbd_kmalloc(sizeof(*new_transaction),
++ GFP_NOFS);
++ if (!new_transaction) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ memset(new_transaction, 0, sizeof(*new_transaction));
++ }
++
++ jbd_debug(3, "New handle %p going live.\n", handle);
++
++repeat:
++
++ /*
++ * We need to hold j_state_lock until t_updates has been incremented,
++ * for proper journal barrier handling
++ */
++ spin_lock(&journal->j_state_lock);
++repeat_locked:
++ if (is_journal_aborted(journal) ||
++ (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
++ spin_unlock(&journal->j_state_lock);
++ ret = -EROFS;
++ goto out;
++ }
++
++ /* Wait on the journal's transaction barrier if necessary */
++ if (journal->j_barrier_count) {
++ spin_unlock(&journal->j_state_lock);
++ wait_event(journal->j_wait_transaction_locked,
++ journal->j_barrier_count == 0);
++ goto repeat;
++ }
++
++ if (!journal->j_running_transaction) {
++ if (!new_transaction) {
++ spin_unlock(&journal->j_state_lock);
++ goto alloc_transaction;
++ }
++ jbd2_get_transaction(journal, new_transaction);
++ new_transaction = NULL;
++ }
++
++ transaction = journal->j_running_transaction;
++
++ /*
++ * If the current transaction is locked down for commit, wait for the
++ * lock to be released.
++ */
++ if (transaction->t_state == T_LOCKED) {
++ DEFINE_WAIT(wait);
++
++ prepare_to_wait(&journal->j_wait_transaction_locked,
++ &wait, TASK_UNINTERRUPTIBLE);
++ spin_unlock(&journal->j_state_lock);
++ schedule();
++ finish_wait(&journal->j_wait_transaction_locked, &wait);
++ goto repeat;
++ }
++
++ /*
++ * If there is not enough space left in the log to write all potential
++ * buffers requested by this operation, we need to stall pending a log
++ * checkpoint to free some more log space.
++ */
++ spin_lock(&transaction->t_handle_lock);
++ needed = transaction->t_outstanding_credits + nblocks;
++
++ if (needed > journal->j_max_transaction_buffers) {
++ /*
++ * If the current transaction is already too large, then start
++ * to commit it: we can then go back and attach this handle to
++ * a new transaction.
++ */
++ DEFINE_WAIT(wait);
++
++ jbd_debug(2, "Handle %p starting new commit...\n", handle);
++ spin_unlock(&transaction->t_handle_lock);
++ prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
++ TASK_UNINTERRUPTIBLE);
++ __jbd2_log_start_commit(journal, transaction->t_tid);
++ spin_unlock(&journal->j_state_lock);
++ schedule();
++ finish_wait(&journal->j_wait_transaction_locked, &wait);
++ goto repeat;
++ }
++
++ /*
++ * The commit code assumes that it can get enough log space
++ * without forcing a checkpoint. This is *critical* for
++ * correctness: a checkpoint of a buffer which is also
++ * associated with a committing transaction creates a deadlock,
++ * so commit simply cannot force through checkpoints.
++ *
++ * We must therefore ensure the necessary space in the journal
++ * *before* starting to dirty potentially checkpointed buffers
++ * in the new transaction.
++ *
++ * The worst part is, any transaction currently committing can
++ * reduce the free space arbitrarily. Be careful to account for
++ * those buffers when checkpointing.
++ */
++
++ /*
++ * @@@ AKPM: This seems rather over-defensive. We're giving commit
++ * a _lot_ of headroom: 1/4 of the journal plus the size of
++ * the committing transaction. Really, we only need to give it
++ * committing_transaction->t_outstanding_credits plus "enough" for
++ * the log control blocks.
++ * Also, this test is inconsitent with the matching one in
++ * jbd2_journal_extend().
++ */
++ if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) {
++ jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
++ spin_unlock(&transaction->t_handle_lock);
++ __jbd2_log_wait_for_space(journal);
++ goto repeat_locked;
++ }
++
++ /* OK, account for the buffers that this operation expects to
++ * use and add the handle to the running transaction. */
++
++ handle->h_transaction = transaction;
++ transaction->t_outstanding_credits += nblocks;
++ transaction->t_updates++;
++ transaction->t_handle_count++;
++ jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
++ handle, nblocks, transaction->t_outstanding_credits,
++ __jbd2_log_space_left(journal));
++ spin_unlock(&transaction->t_handle_lock);
++ spin_unlock(&journal->j_state_lock);
++out:
++ if (unlikely(new_transaction)) /* It's usually NULL */
++ kfree(new_transaction);
++ return ret;
++}
++
++/* Allocate a new handle. This should probably be in a slab... */
++static handle_t *new_handle(int nblocks)
++{
++ handle_t *handle = jbd_alloc_handle(GFP_NOFS);
++ if (!handle)
++ return NULL;
++ memset(handle, 0, sizeof(*handle));
++ handle->h_buffer_credits = nblocks;
++ handle->h_ref = 1;
++
++ return handle;
++}
++
++/**
++ * handle_t *jbd2_journal_start() - Obtain a new handle.
++ * @journal: Journal to start transaction on.
++ * @nblocks: number of block buffer we might modify
++ *
++ * We make sure that the transaction can guarantee at least nblocks of
++ * modified buffers in the log. We block until the log can guarantee
++ * that much space.
++ *
++ * This function is visible to journal users (like ext3fs), so is not
++ * called with the journal already locked.
++ *
++ * Return a pointer to a newly allocated handle, or NULL on failure
++ */
++handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
++{
++ handle_t *handle = journal_current_handle();
++ int err;
++
++ if (!journal)
++ return ERR_PTR(-EROFS);
++
++ if (handle) {
++ J_ASSERT(handle->h_transaction->t_journal == journal);
++ handle->h_ref++;
++ return handle;
++ }
++
++ handle = new_handle(nblocks);
++ if (!handle)
++ return ERR_PTR(-ENOMEM);
++
++ current->journal_info = handle;
++
++ err = start_this_handle(journal, handle);
++ if (err < 0) {
++ jbd_free_handle(handle);
++ current->journal_info = NULL;
++ handle = ERR_PTR(err);
++ }
++ return handle;
++}
++
++/**
++ * int jbd2_journal_extend() - extend buffer credits.
++ * @handle: handle to 'extend'
++ * @nblocks: nr blocks to try to extend by.
++ *
++ * Some transactions, such as large extends and truncates, can be done
++ * atomically all at once or in several stages. The operation requests
++ * a credit for a number of buffer modications in advance, but can
++ * extend its credit if it needs more.
++ *
++ * jbd2_journal_extend tries to give the running handle more buffer credits.
++ * It does not guarantee that allocation - this is a best-effort only.
++ * The calling process MUST be able to deal cleanly with a failure to
++ * extend here.
++ *
++ * Return 0 on success, non-zero on failure.
++ *
++ * return code < 0 implies an error
++ * return code > 0 implies normal transaction-full status.
++ */
++int jbd2_journal_extend(handle_t *handle, int nblocks)
++{
++ transaction_t *transaction = handle->h_transaction;
++ journal_t *journal = transaction->t_journal;
++ int result;
++ int wanted;
++
++ result = -EIO;
++ if (is_handle_aborted(handle))
++ goto out;
++
++ result = 1;
++
++ spin_lock(&journal->j_state_lock);
++
++ /* Don't extend a locked-down transaction! */
++ if (handle->h_transaction->t_state != T_RUNNING) {
++ jbd_debug(3, "denied handle %p %d blocks: "
++ "transaction not running\n", handle, nblocks);
++ goto error_out;
++ }
++
++ spin_lock(&transaction->t_handle_lock);
++ wanted = transaction->t_outstanding_credits + nblocks;
++
++ if (wanted > journal->j_max_transaction_buffers) {
++ jbd_debug(3, "denied handle %p %d blocks: "
++ "transaction too large\n", handle, nblocks);
++ goto unlock;
++ }
++
++ if (wanted > __jbd2_log_space_left(journal)) {
++ jbd_debug(3, "denied handle %p %d blocks: "
++ "insufficient log space\n", handle, nblocks);
++ goto unlock;
++ }
++
++ handle->h_buffer_credits += nblocks;
++ transaction->t_outstanding_credits += nblocks;
++ result = 0;
++
++ jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);
++unlock:
++ spin_unlock(&transaction->t_handle_lock);
++error_out:
++ spin_unlock(&journal->j_state_lock);
++out:
++ return result;
++}
++
++
++/**
++ * int jbd2_journal_restart() - restart a handle .
++ * @handle: handle to restart
++ * @nblocks: nr credits requested
++ *
++ * Restart a handle for a multi-transaction filesystem
++ * operation.
++ *
++ * If the jbd2_journal_extend() call above fails to grant new buffer credits
++ * to a running handle, a call to jbd2_journal_restart will commit the
++ * handle's transaction so far and reattach the handle to a new
++ * transaction capabable of guaranteeing the requested number of
++ * credits.
++ */
++
++int jbd2_journal_restart(handle_t *handle, int nblocks)
++{
++ transaction_t *transaction = handle->h_transaction;
++ journal_t *journal = transaction->t_journal;
++ int ret;
++
++ /* If we've had an abort of any type, don't even think about
++ * actually doing the restart! */
++ if (is_handle_aborted(handle))
++ return 0;
++
++ /*
++ * First unlink the handle from its current transaction, and start the
++ * commit on that.
++ */
++ J_ASSERT(transaction->t_updates > 0);
++ J_ASSERT(journal_current_handle() == handle);
++
++ spin_lock(&journal->j_state_lock);
++ spin_lock(&transaction->t_handle_lock);
++ transaction->t_outstanding_credits -= handle->h_buffer_credits;
++ transaction->t_updates--;
++
++ if (!transaction->t_updates)
++ wake_up(&journal->j_wait_updates);
++ spin_unlock(&transaction->t_handle_lock);
++
++ jbd_debug(2, "restarting handle %p\n", handle);
++ __jbd2_log_start_commit(journal, transaction->t_tid);
++ spin_unlock(&journal->j_state_lock);
++
++ handle->h_buffer_credits = nblocks;
++ ret = start_this_handle(journal, handle);
++ return ret;
++}
++
++
++/**
++ * void jbd2_journal_lock_updates () - establish a transaction barrier.
++ * @journal: Journal to establish a barrier on.
++ *
++ * This locks out any further updates from being started, and blocks
++ * until all existing updates have completed, returning only once the
++ * journal is in a quiescent state with no updates running.
++ *
++ * The journal lock should not be held on entry.
++ */
++void jbd2_journal_lock_updates(journal_t *journal)
++{
++ DEFINE_WAIT(wait);
++
++ spin_lock(&journal->j_state_lock);
++ ++journal->j_barrier_count;
++
++ /* Wait until there are no running updates */
++ while (1) {
++ transaction_t *transaction = journal->j_running_transaction;
++
++ if (!transaction)
++ break;
++
++ spin_lock(&transaction->t_handle_lock);
++ if (!transaction->t_updates) {
++ spin_unlock(&transaction->t_handle_lock);
++ break;
++ }
++ prepare_to_wait(&journal->j_wait_updates, &wait,
++ TASK_UNINTERRUPTIBLE);
++ spin_unlock(&transaction->t_handle_lock);
++ spin_unlock(&journal->j_state_lock);
++ schedule();
++ finish_wait(&journal->j_wait_updates, &wait);
++ spin_lock(&journal->j_state_lock);
++ }
++ spin_unlock(&journal->j_state_lock);
++
++ /*
++ * We have now established a barrier against other normal updates, but
++ * we also need to barrier against other jbd2_journal_lock_updates() calls
++ * to make sure that we serialise special journal-locked operations
++ * too.
++ */
++ mutex_lock(&journal->j_barrier);
++}
++
++/**
++ * void jbd2_journal_unlock_updates (journal_t* journal) - release barrier
++ * @journal: Journal to release the barrier on.
++ *
++ * Release a transaction barrier obtained with jbd2_journal_lock_updates().
++ *
++ * Should be called without the journal lock held.
++ */
++void jbd2_journal_unlock_updates (journal_t *journal)
++{
++ J_ASSERT(journal->j_barrier_count != 0);
++
++ mutex_unlock(&journal->j_barrier);
++ spin_lock(&journal->j_state_lock);
++ --journal->j_barrier_count;
++ spin_unlock(&journal->j_state_lock);
++ wake_up(&journal->j_wait_transaction_locked);
++}
++
++/*
++ * Report any unexpected dirty buffers which turn up. Normally those
++ * indicate an error, but they can occur if the user is running (say)
++ * tune2fs to modify the live filesystem, so we need the option of
++ * continuing as gracefully as possible. #
++ *
++ * The caller should already hold the journal lock and
++ * j_list_lock spinlock: most callers will need those anyway
++ * in order to probe the buffer's journaling state safely.
++ */
++static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
++{
++ int jlist;
++
++ /* If this buffer is one which might reasonably be dirty
++ * --- ie. data, or not part of this journal --- then
++ * we're OK to leave it alone, but otherwise we need to
++ * move the dirty bit to the journal's own internal
++ * JBDDirty bit. */
++ jlist = jh->b_jlist;
++
++ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
++ jlist == BJ_Shadow || jlist == BJ_Forget) {
++ struct buffer_head *bh = jh2bh(jh);
++
++ if (test_clear_buffer_dirty(bh))
++ set_buffer_jbddirty(bh);
++ }
++}
++
++/*
++ * If the buffer is already part of the current transaction, then there
++ * is nothing we need to do. If it is already part of a prior
++ * transaction which we are still committing to disk, then we need to
++ * make sure that we do not overwrite the old copy: we do copy-out to
++ * preserve the copy going to disk. We also account the buffer against
++ * the handle's metadata buffer credits (unless the buffer is already
++ * part of the transaction, that is).
++ *
++ */
++static int
++do_get_write_access(handle_t *handle, struct journal_head *jh,
++ int force_copy)
++{
++ struct buffer_head *bh;
++ transaction_t *transaction;
++ journal_t *journal;
++ int error;
++ char *frozen_buffer = NULL;
++ int need_copy = 0;
++
++ if (is_handle_aborted(handle))
++ return -EROFS;
++
++ transaction = handle->h_transaction;
++ journal = transaction->t_journal;
++
++ jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy);
++
++ JBUFFER_TRACE(jh, "entry");
++repeat:
++ bh = jh2bh(jh);
++
++ /* @@@ Need to check for errors here at some point. */
++
++ lock_buffer(bh);
++ jbd_lock_bh_state(bh);
++
++ /* We now hold the buffer lock so it is safe to query the buffer
++ * state. Is the buffer dirty?
++ *
++ * If so, there are two possibilities. The buffer may be
++ * non-journaled, and undergoing a quite legitimate writeback.
++ * Otherwise, it is journaled, and we don't expect dirty buffers
++ * in that state (the buffers should be marked JBD_Dirty
++ * instead.) So either the IO is being done under our own
++ * control and this is a bug, or it's a third party IO such as
++ * dump(8) (which may leave the buffer scheduled for read ---
++ * ie. locked but not dirty) or tune2fs (which may actually have
++ * the buffer dirtied, ugh.) */
++
++ if (buffer_dirty(bh)) {
++ /*
++ * First question: is this buffer already part of the current
++ * transaction or the existing committing transaction?
++ */
++ if (jh->b_transaction) {
++ J_ASSERT_JH(jh,
++ jh->b_transaction == transaction ||
++ jh->b_transaction ==
++ journal->j_committing_transaction);
++ if (jh->b_next_transaction)
++ J_ASSERT_JH(jh, jh->b_next_transaction ==
++ transaction);
++ }
++ /*
++ * In any case we need to clean the dirty flag and we must
++ * do it under the buffer lock to be sure we don't race
++ * with running write-out.
++ */
++ JBUFFER_TRACE(jh, "Unexpected dirty buffer");
++ jbd_unexpected_dirty_buffer(jh);
++ }
++
++ unlock_buffer(bh);
++
++ error = -EROFS;
++ if (is_handle_aborted(handle)) {
++ jbd_unlock_bh_state(bh);
++ goto out;
++ }
++ error = 0;
++
++ /*
++ * The buffer is already part of this transaction if b_transaction or
++ * b_next_transaction points to it
++ */
++ if (jh->b_transaction == transaction ||
++ jh->b_next_transaction == transaction)
++ goto done;
++
++ /*
++ * If there is already a copy-out version of this buffer, then we don't
++ * need to make another one
++ */
++ if (jh->b_frozen_data) {
++ JBUFFER_TRACE(jh, "has frozen data");
++ J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
++ jh->b_next_transaction = transaction;
++ goto done;
++ }
++
++ /* Is there data here we need to preserve? */
++
++ if (jh->b_transaction && jh->b_transaction != transaction) {
++ JBUFFER_TRACE(jh, "owned by older transaction");
++ J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
++ J_ASSERT_JH(jh, jh->b_transaction ==
++ journal->j_committing_transaction);
++
++ /* There is one case we have to be very careful about.
++ * If the committing transaction is currently writing
++ * this buffer out to disk and has NOT made a copy-out,
++ * then we cannot modify the buffer contents at all
++ * right now. The essence of copy-out is that it is the
++ * extra copy, not the primary copy, which gets
++ * journaled. If the primary copy is already going to
++ * disk then we cannot do copy-out here. */
++
++ if (jh->b_jlist == BJ_Shadow) {
++ DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Unshadow);
++ wait_queue_head_t *wqh;
++
++ wqh = bit_waitqueue(&bh->b_state, BH_Unshadow);
++
++ JBUFFER_TRACE(jh, "on shadow: sleep");
++ jbd_unlock_bh_state(bh);
++ /* commit wakes up all shadow buffers after IO */
++ for ( ; ; ) {
++ prepare_to_wait(wqh, &wait.wait,
++ TASK_UNINTERRUPTIBLE);
++ if (jh->b_jlist != BJ_Shadow)
++ break;
++ schedule();
++ }
++ finish_wait(wqh, &wait.wait);
++ goto repeat;
++ }
++
++ /* Only do the copy if the currently-owning transaction
++ * still needs it. If it is on the Forget list, the
++ * committing transaction is past that stage. The
++ * buffer had better remain locked during the kmalloc,
++ * but that should be true --- we hold the journal lock
++ * still and the buffer is already on the BUF_JOURNAL
++ * list so won't be flushed.
++ *
++ * Subtle point, though: if this is a get_undo_access,
++ * then we will be relying on the frozen_data to contain
++ * the new value of the committed_data record after the
++ * transaction, so we HAVE to force the frozen_data copy
++ * in that case. */
++
++ if (jh->b_jlist != BJ_Forget || force_copy) {
++ JBUFFER_TRACE(jh, "generate frozen data");
++ if (!frozen_buffer) {
++ JBUFFER_TRACE(jh, "allocate memory for buffer");
++ jbd_unlock_bh_state(bh);
++ frozen_buffer =
++ jbd2_slab_alloc(jh2bh(jh)->b_size,
++ GFP_NOFS);
++ if (!frozen_buffer) {
++ printk(KERN_EMERG
++ "%s: OOM for frozen_buffer\n",
++ __FUNCTION__);
++ JBUFFER_TRACE(jh, "oom!");
++ error = -ENOMEM;
++ jbd_lock_bh_state(bh);
++ goto done;
++ }
++ goto repeat;
++ }
++ jh->b_frozen_data = frozen_buffer;
++ frozen_buffer = NULL;
++ need_copy = 1;
++ }
++ jh->b_next_transaction = transaction;
++ }
++
++
++ /*
++ * Finally, if the buffer is not journaled right now, we need to make
++ * sure it doesn't get written to disk before the caller actually
++ * commits the new data
++ */
++ if (!jh->b_transaction) {
++ JBUFFER_TRACE(jh, "no transaction");
++ J_ASSERT_JH(jh, !jh->b_next_transaction);
++ jh->b_transaction = transaction;
++ JBUFFER_TRACE(jh, "file as BJ_Reserved");
++ spin_lock(&journal->j_list_lock);
++ __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
++ spin_unlock(&journal->j_list_lock);
++ }
++
++done:
++ if (need_copy) {
++ struct page *page;
++ int offset;
++ char *source;
++
++ J_EXPECT_JH(jh, buffer_uptodate(jh2bh(jh)),
++ "Possible IO failure.\n");
++ page = jh2bh(jh)->b_page;
++ offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK;
++ source = kmap_atomic(page, KM_USER0);
++ memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
++ kunmap_atomic(source, KM_USER0);
++ }
++ jbd_unlock_bh_state(bh);
++
++ /*
++ * If we are about to journal a buffer, then any revoke pending on it is
++ * no longer valid
++ */
++ jbd2_journal_cancel_revoke(handle, jh);
++
++out:
++ if (unlikely(frozen_buffer)) /* It's usually NULL */
++ jbd2_slab_free(frozen_buffer, bh->b_size);
++
++ JBUFFER_TRACE(jh, "exit");
++ return error;
++}
++
++/**
++ * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update.
++ * @handle: transaction to add buffer modifications to
++ * @bh: bh to be used for metadata writes
++ * @credits: variable that will receive credits for the buffer
++ *
++ * Returns an error code or 0 on success.
++ *
++ * In full data journalling mode the buffer may be of type BJ_AsyncData,
++ * because we're write()ing a buffer which is also part of a shared mapping.
++ */
++
++int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh)
++{
++ struct journal_head *jh = jbd2_journal_add_journal_head(bh);
++ int rc;
++
++ /* We do not want to get caught playing with fields which the
++ * log thread also manipulates. Make sure that the buffer
++ * completes any outstanding IO before proceeding. */
++ rc = do_get_write_access(handle, jh, 0);
++ jbd2_journal_put_journal_head(jh);
++ return rc;
++}
++
++
++/*
++ * When the user wants to journal a newly created buffer_head
++ * (ie. getblk() returned a new buffer and we are going to populate it
++ * manually rather than reading off disk), then we need to keep the
++ * buffer_head locked until it has been completely filled with new
++ * data. In this case, we should be able to make the assertion that
++ * the bh is not already part of an existing transaction.
++ *
++ * The buffer should already be locked by the caller by this point.
++ * There is no lock ranking violation: it was a newly created,
++ * unlocked buffer beforehand. */
++
++/**
++ * int jbd2_journal_get_create_access () - notify intent to use newly created bh
++ * @handle: transaction to new buffer to
++ * @bh: new buffer.
++ *
++ * Call this if you create a new bh.
++ */
++int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
++{
++ transaction_t *transaction = handle->h_transaction;
++ journal_t *journal = transaction->t_journal;
++ struct journal_head *jh = jbd2_journal_add_journal_head(bh);
++ int err;
++
++ jbd_debug(5, "journal_head %p\n", jh);
++ err = -EROFS;
++ if (is_handle_aborted(handle))
++ goto out;
++ err = 0;
++
++ JBUFFER_TRACE(jh, "entry");
++ /*
++ * The buffer may already belong to this transaction due to pre-zeroing
++ * in the filesystem's new_block code. It may also be on the previous,
++ * committing transaction's lists, but it HAS to be in Forget state in
++ * that case: the transaction must have deleted the buffer for it to be
++ * reused here.
++ */
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++ J_ASSERT_JH(jh, (jh->b_transaction == transaction ||
++ jh->b_transaction == NULL ||
++ (jh->b_transaction == journal->j_committing_transaction &&
++ jh->b_jlist == BJ_Forget)));
++
++ J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
++ J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
++
++ if (jh->b_transaction == NULL) {
++ jh->b_transaction = transaction;
++ JBUFFER_TRACE(jh, "file as BJ_Reserved");
++ __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
++ } else if (jh->b_transaction == journal->j_committing_transaction) {
++ JBUFFER_TRACE(jh, "set next transaction");
++ jh->b_next_transaction = transaction;
++ }
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++
++ /*
++ * akpm: I added this. ext3_alloc_branch can pick up new indirect
++ * blocks which contain freed but then revoked metadata. We need
++ * to cancel the revoke in case we end up freeing it yet again
++ * and the reallocating as data - this would cause a second revoke,
++ * which hits an assertion error.
++ */
++ JBUFFER_TRACE(jh, "cancelling revoke");
++ jbd2_journal_cancel_revoke(handle, jh);
++ jbd2_journal_put_journal_head(jh);
++out:
++ return err;
++}
++
++/**
++ * int jbd2_journal_get_undo_access() - Notify intent to modify metadata with
++ * non-rewindable consequences
++ * @handle: transaction
++ * @bh: buffer to undo
++ * @credits: store the number of taken credits here (if not NULL)
++ *
++ * Sometimes there is a need to distinguish between metadata which has
++ * been committed to disk and that which has not. The ext3fs code uses
++ * this for freeing and allocating space, we have to make sure that we
++ * do not reuse freed space until the deallocation has been committed,
++ * since if we overwrote that space we would make the delete
++ * un-rewindable in case of a crash.
++ *
++ * To deal with that, jbd2_journal_get_undo_access requests write access to a
++ * buffer for parts of non-rewindable operations such as delete
++ * operations on the bitmaps. The journaling code must keep a copy of
++ * the buffer's contents prior to the undo_access call until such time
++ * as we know that the buffer has definitely been committed to disk.
++ *
++ * We never need to know which transaction the committed data is part
++ * of, buffers touched here are guaranteed to be dirtied later and so
++ * will be committed to a new transaction in due course, at which point
++ * we can discard the old committed data pointer.
++ *
++ * Returns error number or 0 on success.
++ */
++int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
++{
++ int err;
++ struct journal_head *jh = jbd2_journal_add_journal_head(bh);
++ char *committed_data = NULL;
++
++ JBUFFER_TRACE(jh, "entry");
++
++ /*
++ * Do this first --- it can drop the journal lock, so we want to
++ * make sure that obtaining the committed_data is done
++ * atomically wrt. completion of any outstanding commits.
++ */
++ err = do_get_write_access(handle, jh, 1);
++ if (err)
++ goto out;
++
++repeat:
++ if (!jh->b_committed_data) {
++ committed_data = jbd2_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS);
++ if (!committed_data) {
++ printk(KERN_EMERG "%s: No memory for committed data\n",
++ __FUNCTION__);
++ err = -ENOMEM;
++ goto out;
++ }
++ }
++
++ jbd_lock_bh_state(bh);
++ if (!jh->b_committed_data) {
++ /* Copy out the current buffer contents into the
++ * preserved, committed copy. */
++ JBUFFER_TRACE(jh, "generate b_committed data");
++ if (!committed_data) {
++ jbd_unlock_bh_state(bh);
++ goto repeat;
++ }
++
++ jh->b_committed_data = committed_data;
++ committed_data = NULL;
++ memcpy(jh->b_committed_data, bh->b_data, bh->b_size);
++ }
++ jbd_unlock_bh_state(bh);
++out:
++ jbd2_journal_put_journal_head(jh);
++ if (unlikely(committed_data))
++ jbd2_slab_free(committed_data, bh->b_size);
++ return err;
++}
++
++/**
++ * int jbd2_journal_dirty_data() - mark a buffer as containing dirty data which
++ * needs to be flushed before we can commit the
++ * current transaction.
++ * @handle: transaction
++ * @bh: bufferhead to mark
++ *
++ * The buffer is placed on the transaction's data list and is marked as
++ * belonging to the transaction.
++ *
++ * Returns error number or 0 on success.
++ *
++ * jbd2_journal_dirty_data() can be called via page_launder->ext3_writepage
++ * by kswapd.
++ */
++int jbd2_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
++{
++ journal_t *journal = handle->h_transaction->t_journal;
++ int need_brelse = 0;
++ struct journal_head *jh;
++
++ if (is_handle_aborted(handle))
++ return 0;
++
++ jh = jbd2_journal_add_journal_head(bh);
++ JBUFFER_TRACE(jh, "entry");
++
++ /*
++ * The buffer could *already* be dirty. Writeout can start
++ * at any time.
++ */
++ jbd_debug(4, "jh: %p, tid:%d\n", jh, handle->h_transaction->t_tid);
++
++ /*
++ * What if the buffer is already part of a running transaction?
++ *
++ * There are two cases:
++ * 1) It is part of the current running transaction. Refile it,
++ * just in case we have allocated it as metadata, deallocated
++ * it, then reallocated it as data.
++ * 2) It is part of the previous, still-committing transaction.
++ * If all we want to do is to guarantee that the buffer will be
++ * written to disk before this new transaction commits, then
++ * being sure that the *previous* transaction has this same
++ * property is sufficient for us! Just leave it on its old
++ * transaction.
++ *
++ * In case (2), the buffer must not already exist as metadata
++ * --- that would violate write ordering (a transaction is free
++ * to write its data at any point, even before the previous
++ * committing transaction has committed). The caller must
++ * never, ever allow this to happen: there's nothing we can do
++ * about it in this layer.
++ */
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++
++ /* Now that we have bh_state locked, are we really still mapped? */
++ if (!buffer_mapped(bh)) {
++ JBUFFER_TRACE(jh, "unmapped buffer, bailing out");
++ goto no_journal;
++ }
++
++ if (jh->b_transaction) {
++ JBUFFER_TRACE(jh, "has transaction");
++ if (jh->b_transaction != handle->h_transaction) {
++ JBUFFER_TRACE(jh, "belongs to older transaction");
++ J_ASSERT_JH(jh, jh->b_transaction ==
++ journal->j_committing_transaction);
++
++ /* @@@ IS THIS TRUE ? */
++ /*
++ * Not any more. Scenario: someone does a write()
++ * in data=journal mode. The buffer's transaction has
++ * moved into commit. Then someone does another
++ * write() to the file. We do the frozen data copyout
++ * and set b_next_transaction to point to j_running_t.
++ * And while we're in that state, someone does a
++ * writepage() in an attempt to pageout the same area
++ * of the file via a shared mapping. At present that
++ * calls jbd2_journal_dirty_data(), and we get right here.
++ * It may be too late to journal the data. Simply
++ * falling through to the next test will suffice: the
++ * data will be dirty and wil be checkpointed. The
++ * ordering comments in the next comment block still
++ * apply.
++ */
++ //J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
++
++ /*
++ * If we're journalling data, and this buffer was
++ * subject to a write(), it could be metadata, forget
++ * or shadow against the committing transaction. Now,
++ * someone has dirtied the same darn page via a mapping
++ * and it is being writepage()'d.
++ * We *could* just steal the page from commit, with some
++ * fancy locking there. Instead, we just skip it -
++ * don't tie the page's buffers to the new transaction
++ * at all.
++ * Implication: if we crash before the writepage() data
++ * is written into the filesystem, recovery will replay
++ * the write() data.
++ */
++ if (jh->b_jlist != BJ_None &&
++ jh->b_jlist != BJ_SyncData &&
++ jh->b_jlist != BJ_Locked) {
++ JBUFFER_TRACE(jh, "Not stealing");
++ goto no_journal;
++ }
++
++ /*
++ * This buffer may be undergoing writeout in commit. We
++ * can't return from here and let the caller dirty it
++ * again because that can cause the write-out loop in
++ * commit to never terminate.
++ */
++ if (buffer_dirty(bh)) {
++ get_bh(bh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ need_brelse = 1;
++ sync_dirty_buffer(bh);
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++ /* Since we dropped the lock... */
++ if (!buffer_mapped(bh)) {
++ JBUFFER_TRACE(jh, "buffer got unmapped");
++ goto no_journal;
++ }
++ /* The buffer may become locked again at any
++ time if it is redirtied */
++ }
++
++ /* journal_clean_data_list() may have got there first */
++ if (jh->b_transaction != NULL) {
++ JBUFFER_TRACE(jh, "unfile from commit");
++ __jbd2_journal_temp_unlink_buffer(jh);
++ /* It still points to the committing
++ * transaction; move it to this one so
++ * that the refile assert checks are
++ * happy. */
++ jh->b_transaction = handle->h_transaction;
++ }
++ /* The buffer will be refiled below */
++
++ }
++ /*
++ * Special case --- the buffer might actually have been
++ * allocated and then immediately deallocated in the previous,
++ * committing transaction, so might still be left on that
++ * transaction's metadata lists.
++ */
++ if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) {
++ JBUFFER_TRACE(jh, "not on correct data list: unfile");
++ J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow);
++ __jbd2_journal_temp_unlink_buffer(jh);
++ jh->b_transaction = handle->h_transaction;
++ JBUFFER_TRACE(jh, "file as data");
++ __jbd2_journal_file_buffer(jh, handle->h_transaction,
++ BJ_SyncData);
++ }
++ } else {
++ JBUFFER_TRACE(jh, "not on a transaction");
++ __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_SyncData);
++ }
++no_journal:
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ if (need_brelse) {
++ BUFFER_TRACE(bh, "brelse");
++ __brelse(bh);
++ }
++ JBUFFER_TRACE(jh, "exit");
++ jbd2_journal_put_journal_head(jh);
++ return 0;
++}
++
++/**
++ * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata
++ * @handle: transaction to add buffer to.
++ * @bh: buffer to mark
++ *
++ * mark dirty metadata which needs to be journaled as part of the current
++ * transaction.
++ *
++ * The buffer is placed on the transaction's metadata list and is marked
++ * as belonging to the transaction.
++ *
++ * Returns error number or 0 on success.
++ *
++ * Special care needs to be taken if the buffer already belongs to the
++ * current committing transaction (in which case we should have frozen
++ * data present for that commit). In that case, we don't relink the
++ * buffer: that only gets done when the old transaction finally
++ * completes its commit.
++ */
++int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
++{
++ transaction_t *transaction = handle->h_transaction;
++ journal_t *journal = transaction->t_journal;
++ struct journal_head *jh = bh2jh(bh);
++
++ jbd_debug(5, "journal_head %p\n", jh);
++ JBUFFER_TRACE(jh, "entry");
++ if (is_handle_aborted(handle))
++ goto out;
++
++ jbd_lock_bh_state(bh);
++
++ if (jh->b_modified == 0) {
++ /*
++ * This buffer's got modified and becoming part
++ * of the transaction. This needs to be done
++ * once a transaction -bzzz
++ */
++ jh->b_modified = 1;
++ J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
++ handle->h_buffer_credits--;
++ }
++
++ /*
++ * fastpath, to avoid expensive locking. If this buffer is already
++ * on the running transaction's metadata list there is nothing to do.
++ * Nobody can take it off again because there is a handle open.
++ * I _think_ we're OK here with SMP barriers - a mistaken decision will
++ * result in this test being false, so we go in and take the locks.
++ */
++ if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) {
++ JBUFFER_TRACE(jh, "fastpath");
++ J_ASSERT_JH(jh, jh->b_transaction ==
++ journal->j_running_transaction);
++ goto out_unlock_bh;
++ }
++
++ set_buffer_jbddirty(bh);
++
++ /*
++ * Metadata already on the current transaction list doesn't
++ * need to be filed. Metadata on another transaction's list must
++ * be committing, and will be refiled once the commit completes:
++ * leave it alone for now.
++ */
++ if (jh->b_transaction != transaction) {
++ JBUFFER_TRACE(jh, "already on other transaction");
++ J_ASSERT_JH(jh, jh->b_transaction ==
++ journal->j_committing_transaction);
++ J_ASSERT_JH(jh, jh->b_next_transaction == transaction);
++ /* And this case is illegal: we can't reuse another
++ * transaction's data buffer, ever. */
++ goto out_unlock_bh;
++ }
++
++ /* That test should have eliminated the following case: */
++ J_ASSERT_JH(jh, jh->b_frozen_data == 0);
++
++ JBUFFER_TRACE(jh, "file as BJ_Metadata");
++ spin_lock(&journal->j_list_lock);
++ __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_Metadata);
++ spin_unlock(&journal->j_list_lock);
++out_unlock_bh:
++ jbd_unlock_bh_state(bh);
++out:
++ JBUFFER_TRACE(jh, "exit");
++ return 0;
++}
++
++/*
++ * jbd2_journal_release_buffer: undo a get_write_access without any buffer
++ * updates, if the update decided in the end that it didn't need access.
++ *
++ */
++void
++jbd2_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
++{
++ BUFFER_TRACE(bh, "entry");
++}
++
++/**
++ * void jbd2_journal_forget() - bforget() for potentially-journaled buffers.
++ * @handle: transaction handle
++ * @bh: bh to 'forget'
++ *
++ * We can only do the bforget if there are no commits pending against the
++ * buffer. If the buffer is dirty in the current running transaction we
++ * can safely unlink it.
++ *
++ * bh may not be a journalled buffer at all - it may be a non-JBD
++ * buffer which came off the hashtable. Check for this.
++ *
++ * Decrements bh->b_count by one.
++ *
++ * Allow this call even if the handle has aborted --- it may be part of
++ * the caller's cleanup after an abort.
++ */
++int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
++{
++ transaction_t *transaction = handle->h_transaction;
++ journal_t *journal = transaction->t_journal;
++ struct journal_head *jh;
++ int drop_reserve = 0;
++ int err = 0;
++
++ BUFFER_TRACE(bh, "entry");
++
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++
++ if (!buffer_jbd(bh))
++ goto not_jbd;
++ jh = bh2jh(bh);
++
++ /* Critical error: attempting to delete a bitmap buffer, maybe?
++ * Don't do any jbd operations, and return an error. */
++ if (!J_EXPECT_JH(jh, !jh->b_committed_data,
++ "inconsistent data on disk")) {
++ err = -EIO;
++ goto not_jbd;
++ }
++
++ /*
++ * The buffer's going from the transaction, we must drop
++ * all references -bzzz
++ */
++ jh->b_modified = 0;
++
++ if (jh->b_transaction == handle->h_transaction) {
++ J_ASSERT_JH(jh, !jh->b_frozen_data);
++
++ /* If we are forgetting a buffer which is already part
++ * of this transaction, then we can just drop it from
++ * the transaction immediately. */
++ clear_buffer_dirty(bh);
++ clear_buffer_jbddirty(bh);
++
++ JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
++
++ drop_reserve = 1;
++
++ /*
++ * We are no longer going to journal this buffer.
++ * However, the commit of this transaction is still
++ * important to the buffer: the delete that we are now
++ * processing might obsolete an old log entry, so by
++ * committing, we can satisfy the buffer's checkpoint.
++ *
++ * So, if we have a checkpoint on the buffer, we should
++ * now refile the buffer on our BJ_Forget list so that
++ * we know to remove the checkpoint after we commit.
++ */
++
++ if (jh->b_cp_transaction) {
++ __jbd2_journal_temp_unlink_buffer(jh);
++ __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
++ } else {
++ __jbd2_journal_unfile_buffer(jh);
++ jbd2_journal_remove_journal_head(bh);
++ __brelse(bh);
++ if (!buffer_jbd(bh)) {
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ __bforget(bh);
++ goto drop;
++ }
++ }
++ } else if (jh->b_transaction) {
++ J_ASSERT_JH(jh, (jh->b_transaction ==
++ journal->j_committing_transaction));
++ /* However, if the buffer is still owned by a prior
++ * (committing) transaction, we can't drop it yet... */
++ JBUFFER_TRACE(jh, "belongs to older transaction");
++ /* ... but we CAN drop it from the new transaction if we
++ * have also modified it since the original commit. */
++
++ if (jh->b_next_transaction) {
++ J_ASSERT(jh->b_next_transaction == transaction);
++ jh->b_next_transaction = NULL;
++ drop_reserve = 1;
++ }
++ }
++
++not_jbd:
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ __brelse(bh);
++drop:
++ if (drop_reserve) {
++ /* no need to reserve log space for this block -bzzz */
++ handle->h_buffer_credits++;
++ }
++ return err;
++}
++
++/**
++ * int jbd2_journal_stop() - complete a transaction
++ * @handle: tranaction to complete.
++ *
++ * All done for a particular handle.
++ *
++ * There is not much action needed here. We just return any remaining
++ * buffer credits to the transaction and remove the handle. The only
++ * complication is that we need to start a commit operation if the
++ * filesystem is marked for synchronous update.
++ *
++ * jbd2_journal_stop itself will not usually return an error, but it may
++ * do so in unusual circumstances. In particular, expect it to
++ * return -EIO if a jbd2_journal_abort has been executed since the
++ * transaction began.
++ */
++int jbd2_journal_stop(handle_t *handle)
++{
++ transaction_t *transaction = handle->h_transaction;
++ journal_t *journal = transaction->t_journal;
++ int old_handle_count, err;
++ pid_t pid;
++
++ J_ASSERT(journal_current_handle() == handle);
++
++ if (is_handle_aborted(handle))
++ err = -EIO;
++ else {
++ J_ASSERT(transaction->t_updates > 0);
++ err = 0;
++ }
++
++ if (--handle->h_ref > 0) {
++ jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
++ handle->h_ref);
++ return err;
++ }
++
++ jbd_debug(4, "Handle %p going down\n", handle);
++
++ /*
++ * Implement synchronous transaction batching. If the handle
++ * was synchronous, don't force a commit immediately. Let's
++ * yield and let another thread piggyback onto this transaction.
++ * Keep doing that while new threads continue to arrive.
++ * It doesn't cost much - we're about to run a commit and sleep
++ * on IO anyway. Speeds up many-threaded, many-dir operations
++ * by 30x or more...
++ *
++ * But don't do this if this process was the most recent one to
++ * perform a synchronous write. We do this to detect the case where a
++ * single process is doing a stream of sync writes. No point in waiting
++ * for joiners in that case.
++ */
++ pid = current->pid;
++ if (handle->h_sync && journal->j_last_sync_writer != pid) {
++ journal->j_last_sync_writer = pid;
++ do {
++ old_handle_count = transaction->t_handle_count;
++ schedule_timeout_uninterruptible(1);
++ } while (old_handle_count != transaction->t_handle_count);
++ }
++
++ current->journal_info = NULL;
++ spin_lock(&journal->j_state_lock);
++ spin_lock(&transaction->t_handle_lock);
++ transaction->t_outstanding_credits -= handle->h_buffer_credits;
++ transaction->t_updates--;
++ if (!transaction->t_updates) {
++ wake_up(&journal->j_wait_updates);
++ if (journal->j_barrier_count)
++ wake_up(&journal->j_wait_transaction_locked);
++ }
++
++ /*
++ * If the handle is marked SYNC, we need to set another commit
++ * going! We also want to force a commit if the current
++ * transaction is occupying too much of the log, or if the
++ * transaction is too old now.
++ */
++ if (handle->h_sync ||
++ transaction->t_outstanding_credits >
++ journal->j_max_transaction_buffers ||
++ time_after_eq(jiffies, transaction->t_expires)) {
++ /* Do this even for aborted journals: an abort still
++ * completes the commit thread, it just doesn't write
++ * anything to disk. */
++ tid_t tid = transaction->t_tid;
++
++ spin_unlock(&transaction->t_handle_lock);
++ jbd_debug(2, "transaction too old, requesting commit for "
++ "handle %p\n", handle);
++ /* This is non-blocking */
++ __jbd2_log_start_commit(journal, transaction->t_tid);
++ spin_unlock(&journal->j_state_lock);
++
++ /*
++ * Special case: JBD2_SYNC synchronous updates require us
++ * to wait for the commit to complete.
++ */
++ if (handle->h_sync && !(current->flags & PF_MEMALLOC))
++ err = jbd2_log_wait_commit(journal, tid);
++ } else {
++ spin_unlock(&transaction->t_handle_lock);
++ spin_unlock(&journal->j_state_lock);
++ }
++
++ jbd_free_handle(handle);
++ return err;
++}
++
++/**int jbd2_journal_force_commit() - force any uncommitted transactions
++ * @journal: journal to force
++ *
++ * For synchronous operations: force any uncommitted transactions
++ * to disk. May seem kludgy, but it reuses all the handle batching
++ * code in a very simple manner.
++ */
++int jbd2_journal_force_commit(journal_t *journal)
++{
++ handle_t *handle;
++ int ret;
++
++ handle = jbd2_journal_start(journal, 1);
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ } else {
++ handle->h_sync = 1;
++ ret = jbd2_journal_stop(handle);
++ }
++ return ret;
++}
++
++/*
++ *
++ * List management code snippets: various functions for manipulating the
++ * transaction buffer lists.
++ *
++ */
++
++/*
++ * Append a buffer to a transaction list, given the transaction's list head
++ * pointer.
++ *
++ * j_list_lock is held.
++ *
++ * jbd_lock_bh_state(jh2bh(jh)) is held.
++ */
++
++static inline void
++__blist_add_buffer(struct journal_head **list, struct journal_head *jh)
++{
++ if (!*list) {
++ jh->b_tnext = jh->b_tprev = jh;
++ *list = jh;
++ } else {
++ /* Insert at the tail of the list to preserve order */
++ struct journal_head *first = *list, *last = first->b_tprev;
++ jh->b_tprev = last;
++ jh->b_tnext = first;
++ last->b_tnext = first->b_tprev = jh;
++ }
++}
++
++/*
++ * Remove a buffer from a transaction list, given the transaction's list
++ * head pointer.
++ *
++ * Called with j_list_lock held, and the journal may not be locked.
++ *
++ * jbd_lock_bh_state(jh2bh(jh)) is held.
++ */
++
++static inline void
++__blist_del_buffer(struct journal_head **list, struct journal_head *jh)
++{
++ if (*list == jh) {
++ *list = jh->b_tnext;
++ if (*list == jh)
++ *list = NULL;
++ }
++ jh->b_tprev->b_tnext = jh->b_tnext;
++ jh->b_tnext->b_tprev = jh->b_tprev;
++}
++
++/*
++ * Remove a buffer from the appropriate transaction list.
++ *
++ * Note that this function can *change* the value of
++ * bh->b_transaction->t_sync_datalist, t_buffers, t_forget,
++ * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list. If the caller
++ * is holding onto a copy of one of thee pointers, it could go bad.
++ * Generally the caller needs to re-read the pointer from the transaction_t.
++ *
++ * Called under j_list_lock. The journal may not be locked.
++ */
++void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
++{
++ struct journal_head **list = NULL;
++ transaction_t *transaction;
++ struct buffer_head *bh = jh2bh(jh);
++
++ J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
++ transaction = jh->b_transaction;
++ if (transaction)
++ assert_spin_locked(&transaction->t_journal->j_list_lock);
++
++ J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
++ if (jh->b_jlist != BJ_None)
++ J_ASSERT_JH(jh, transaction != 0);
++
++ switch (jh->b_jlist) {
++ case BJ_None:
++ return;
++ case BJ_SyncData:
++ list = &transaction->t_sync_datalist;
++ break;
++ case BJ_Metadata:
++ transaction->t_nr_buffers--;
++ J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0);
++ list = &transaction->t_buffers;
++ break;
++ case BJ_Forget:
++ list = &transaction->t_forget;
++ break;
++ case BJ_IO:
++ list = &transaction->t_iobuf_list;
++ break;
++ case BJ_Shadow:
++ list = &transaction->t_shadow_list;
++ break;
++ case BJ_LogCtl:
++ list = &transaction->t_log_list;
++ break;
++ case BJ_Reserved:
++ list = &transaction->t_reserved_list;
++ break;
++ case BJ_Locked:
++ list = &transaction->t_locked_list;
++ break;
++ }
++
++ __blist_del_buffer(list, jh);
++ jh->b_jlist = BJ_None;
++ if (test_clear_buffer_jbddirty(bh))
++ mark_buffer_dirty(bh); /* Expose it to the VM */
++}
++
++void __jbd2_journal_unfile_buffer(struct journal_head *jh)
++{
++ __jbd2_journal_temp_unlink_buffer(jh);
++ jh->b_transaction = NULL;
++}
++
++void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
++{
++ jbd_lock_bh_state(jh2bh(jh));
++ spin_lock(&journal->j_list_lock);
++ __jbd2_journal_unfile_buffer(jh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(jh2bh(jh));
++}
++
++/*
++ * Called from jbd2_journal_try_to_free_buffers().
++ *
++ * Called under jbd_lock_bh_state(bh)
++ */
++static void
++__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
++{
++ struct journal_head *jh;
++
++ jh = bh2jh(bh);
++
++ if (buffer_locked(bh) || buffer_dirty(bh))
++ goto out;
++
++ if (jh->b_next_transaction != 0)
++ goto out;
++
++ spin_lock(&journal->j_list_lock);
++ if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) {
++ if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) {
++ /* A written-back ordered data buffer */
++ JBUFFER_TRACE(jh, "release data");
++ __jbd2_journal_unfile_buffer(jh);
++ jbd2_journal_remove_journal_head(bh);
++ __brelse(bh);
++ }
++ } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) {
++ /* written-back checkpointed metadata buffer */
++ if (jh->b_jlist == BJ_None) {
++ JBUFFER_TRACE(jh, "remove from checkpoint list");
++ __jbd2_journal_remove_checkpoint(jh);
++ jbd2_journal_remove_journal_head(bh);
++ __brelse(bh);
++ }
++ }
++ spin_unlock(&journal->j_list_lock);
++out:
++ return;
++}
++
++
++/**
++ * int jbd2_journal_try_to_free_buffers() - try to free page buffers.
++ * @journal: journal for operation
++ * @page: to try and free
++ * @unused_gfp_mask: unused
++ *
++ *
++ * For all the buffers on this page,
++ * if they are fully written out ordered data, move them onto BUF_CLEAN
++ * so try_to_free_buffers() can reap them.
++ *
++ * This function returns non-zero if we wish try_to_free_buffers()
++ * to be called. We do this if the page is releasable by try_to_free_buffers().
++ * We also do it if the page has locked or dirty buffers and the caller wants
++ * us to perform sync or async writeout.
++ *
++ * This complicates JBD locking somewhat. We aren't protected by the
++ * BKL here. We wish to remove the buffer from its committing or
++ * running transaction's ->t_datalist via __jbd2_journal_unfile_buffer.
++ *
++ * This may *change* the value of transaction_t->t_datalist, so anyone
++ * who looks at t_datalist needs to lock against this function.
++ *
++ * Even worse, someone may be doing a jbd2_journal_dirty_data on this
++ * buffer. So we need to lock against that. jbd2_journal_dirty_data()
++ * will come out of the lock with the buffer dirty, which makes it
++ * ineligible for release here.
++ *
++ * Who else is affected by this? hmm... Really the only contender
++ * is do_get_write_access() - it could be looking at the buffer while
++ * journal_try_to_free_buffer() is changing its state. But that
++ * cannot happen because we never reallocate freed data as metadata
++ * while the data is part of a transaction. Yes?
++ */
++int jbd2_journal_try_to_free_buffers(journal_t *journal,
++ struct page *page, gfp_t unused_gfp_mask)
++{
++ struct buffer_head *head;
++ struct buffer_head *bh;
++ int ret = 0;
++
++ J_ASSERT(PageLocked(page));
++
++ head = page_buffers(page);
++ bh = head;
++ do {
++ struct journal_head *jh;
++
++ /*
++ * We take our own ref against the journal_head here to avoid
++ * having to add tons of locking around each instance of
++ * jbd2_journal_remove_journal_head() and jbd2_journal_put_journal_head().
++ */
++ jh = jbd2_journal_grab_journal_head(bh);
++ if (!jh)
++ continue;
++
++ jbd_lock_bh_state(bh);
++ __journal_try_to_free_buffer(journal, bh);
++ jbd2_journal_put_journal_head(jh);
++ jbd_unlock_bh_state(bh);
++ if (buffer_jbd(bh))
++ goto busy;
++ } while ((bh = bh->b_this_page) != head);
++ ret = try_to_free_buffers(page);
++busy:
++ return ret;
++}
++
++/*
++ * This buffer is no longer needed. If it is on an older transaction's
++ * checkpoint list we need to record it on this transaction's forget list
++ * to pin this buffer (and hence its checkpointing transaction) down until
++ * this transaction commits. If the buffer isn't on a checkpoint list, we
++ * release it.
++ * Returns non-zero if JBD no longer has an interest in the buffer.
++ *
++ * Called under j_list_lock.
++ *
++ * Called under jbd_lock_bh_state(bh).
++ */
++static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
++{
++ int may_free = 1;
++ struct buffer_head *bh = jh2bh(jh);
++
++ __jbd2_journal_unfile_buffer(jh);
++
++ if (jh->b_cp_transaction) {
++ JBUFFER_TRACE(jh, "on running+cp transaction");
++ __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
++ clear_buffer_jbddirty(bh);
++ may_free = 0;
++ } else {
++ JBUFFER_TRACE(jh, "on running transaction");
++ jbd2_journal_remove_journal_head(bh);
++ __brelse(bh);
++ }
++ return may_free;
++}
++
++/*
++ * jbd2_journal_invalidatepage
++ *
++ * This code is tricky. It has a number of cases to deal with.
++ *
++ * There are two invariants which this code relies on:
++ *
++ * i_size must be updated on disk before we start calling invalidatepage on the
++ * data.
++ *
++ * This is done in ext3 by defining an ext3_setattr method which
++ * updates i_size before truncate gets going. By maintaining this
++ * invariant, we can be sure that it is safe to throw away any buffers
++ * attached to the current transaction: once the transaction commits,
++ * we know that the data will not be needed.
++ *
++ * Note however that we can *not* throw away data belonging to the
++ * previous, committing transaction!
++ *
++ * Any disk blocks which *are* part of the previous, committing
++ * transaction (and which therefore cannot be discarded immediately) are
++ * not going to be reused in the new running transaction
++ *
++ * The bitmap committed_data images guarantee this: any block which is
++ * allocated in one transaction and removed in the next will be marked
++ * as in-use in the committed_data bitmap, so cannot be reused until
++ * the next transaction to delete the block commits. This means that
++ * leaving committing buffers dirty is quite safe: the disk blocks
++ * cannot be reallocated to a different file and so buffer aliasing is
++ * not possible.
++ *
++ *
++ * The above applies mainly to ordered data mode. In writeback mode we
++ * don't make guarantees about the order in which data hits disk --- in
++ * particular we don't guarantee that new dirty data is flushed before
++ * transaction commit --- so it is always safe just to discard data
++ * immediately in that mode. --sct
++ */
++
++/*
++ * The journal_unmap_buffer helper function returns zero if the buffer
++ * concerned remains pinned as an anonymous buffer belonging to an older
++ * transaction.
++ *
++ * We're outside-transaction here. Either or both of j_running_transaction
++ * and j_committing_transaction may be NULL.
++ */
++static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
++{
++ transaction_t *transaction;
++ struct journal_head *jh;
++ int may_free = 1;
++ int ret;
++
++ BUFFER_TRACE(bh, "entry");
++
++ /*
++ * It is safe to proceed here without the j_list_lock because the
++ * buffers cannot be stolen by try_to_free_buffers as long as we are
++ * holding the page lock. --sct
++ */
++
++ if (!buffer_jbd(bh))
++ goto zap_buffer_unlocked;
++
++ spin_lock(&journal->j_state_lock);
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++
++ jh = jbd2_journal_grab_journal_head(bh);
++ if (!jh)
++ goto zap_buffer_no_jh;
++
++ transaction = jh->b_transaction;
++ if (transaction == NULL) {
++ /* First case: not on any transaction. If it
++ * has no checkpoint link, then we can zap it:
++ * it's a writeback-mode buffer so we don't care
++ * if it hits disk safely. */
++ if (!jh->b_cp_transaction) {
++ JBUFFER_TRACE(jh, "not on any transaction: zap");
++ goto zap_buffer;
++ }
++
++ if (!buffer_dirty(bh)) {
++ /* bdflush has written it. We can drop it now */
++ goto zap_buffer;
++ }
++
++ /* OK, it must be in the journal but still not
++ * written fully to disk: it's metadata or
++ * journaled data... */
++
++ if (journal->j_running_transaction) {
++ /* ... and once the current transaction has
++ * committed, the buffer won't be needed any
++ * longer. */
++ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget");
++ ret = __dispose_buffer(jh,
++ journal->j_running_transaction);
++ jbd2_journal_put_journal_head(jh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ spin_unlock(&journal->j_state_lock);
++ return ret;
++ } else {
++ /* There is no currently-running transaction. So the
++ * orphan record which we wrote for this file must have
++ * passed into commit. We must attach this buffer to
++ * the committing transaction, if it exists. */
++ if (journal->j_committing_transaction) {
++ JBUFFER_TRACE(jh, "give to committing trans");
++ ret = __dispose_buffer(jh,
++ journal->j_committing_transaction);
++ jbd2_journal_put_journal_head(jh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ spin_unlock(&journal->j_state_lock);
++ return ret;
++ } else {
++ /* The orphan record's transaction has
++ * committed. We can cleanse this buffer */
++ clear_buffer_jbddirty(bh);
++ goto zap_buffer;
++ }
++ }
++ } else if (transaction == journal->j_committing_transaction) {
++ JBUFFER_TRACE(jh, "on committing transaction");
++ if (jh->b_jlist == BJ_Locked) {
++ /*
++ * The buffer is on the committing transaction's locked
++ * list. We have the buffer locked, so I/O has
++ * completed. So we can nail the buffer now.
++ */
++ may_free = __dispose_buffer(jh, transaction);
++ goto zap_buffer;
++ }
++ /*
++ * If it is committing, we simply cannot touch it. We
++ * can remove it's next_transaction pointer from the
++ * running transaction if that is set, but nothing
++ * else. */
++ set_buffer_freed(bh);
++ if (jh->b_next_transaction) {
++ J_ASSERT(jh->b_next_transaction ==
++ journal->j_running_transaction);
++ jh->b_next_transaction = NULL;
++ }
++ jbd2_journal_put_journal_head(jh);
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ spin_unlock(&journal->j_state_lock);
++ return 0;
++ } else {
++ /* Good, the buffer belongs to the running transaction.
++ * We are writing our own transaction's data, not any
++ * previous one's, so it is safe to throw it away
++ * (remember that we expect the filesystem to have set
++ * i_size already for this truncate so recovery will not
++ * expose the disk blocks we are discarding here.) */
++ J_ASSERT_JH(jh, transaction == journal->j_running_transaction);
++ JBUFFER_TRACE(jh, "on running transaction");
++ may_free = __dispose_buffer(jh, transaction);
++ }
++
++zap_buffer:
++ jbd2_journal_put_journal_head(jh);
++zap_buffer_no_jh:
++ spin_unlock(&journal->j_list_lock);
++ jbd_unlock_bh_state(bh);
++ spin_unlock(&journal->j_state_lock);
++zap_buffer_unlocked:
++ clear_buffer_dirty(bh);
++ J_ASSERT_BH(bh, !buffer_jbddirty(bh));
++ clear_buffer_mapped(bh);
++ clear_buffer_req(bh);
++ clear_buffer_new(bh);
++ bh->b_bdev = NULL;
++ return may_free;
++}
++
++/**
++ * void jbd2_journal_invalidatepage()
++ * @journal: journal to use for flush...
++ * @page: page to flush
++ * @offset: length of page to invalidate.
++ *
++ * Reap page buffers containing data after offset in page.
++ *
++ */
++void jbd2_journal_invalidatepage(journal_t *journal,
++ struct page *page,
++ unsigned long offset)
++{
++ struct buffer_head *head, *bh, *next;
++ unsigned int curr_off = 0;
++ int may_free = 1;
++
++ if (!PageLocked(page))
++ BUG();
++ if (!page_has_buffers(page))
++ return;
++
++ /* We will potentially be playing with lists other than just the
++ * data lists (especially for journaled data mode), so be
++ * cautious in our locking. */
++
++ head = bh = page_buffers(page);
++ do {
++ unsigned int next_off = curr_off + bh->b_size;
++ next = bh->b_this_page;
++
++ if (offset <= curr_off) {
++ /* This block is wholly outside the truncation point */
++ lock_buffer(bh);
++ may_free &= journal_unmap_buffer(journal, bh);
++ unlock_buffer(bh);
++ }
++ curr_off = next_off;
++ bh = next;
++
++ } while (bh != head);
++
++ if (!offset) {
++ if (may_free && try_to_free_buffers(page))
++ J_ASSERT(!page_has_buffers(page));
++ }
++}
++
++/*
++ * File a buffer on the given transaction list.
++ */
++void __jbd2_journal_file_buffer(struct journal_head *jh,
++ transaction_t *transaction, int jlist)
++{
++ struct journal_head **list = NULL;
++ int was_dirty = 0;
++ struct buffer_head *bh = jh2bh(jh);
++
++ J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
++ assert_spin_locked(&transaction->t_journal->j_list_lock);
++
++ J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
++ J_ASSERT_JH(jh, jh->b_transaction == transaction ||
++ jh->b_transaction == 0);
++
++ if (jh->b_transaction && jh->b_jlist == jlist)
++ return;
++
++ /* The following list of buffer states needs to be consistent
++ * with __jbd_unexpected_dirty_buffer()'s handling of dirty
++ * state. */
++
++ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
++ jlist == BJ_Shadow || jlist == BJ_Forget) {
++ if (test_clear_buffer_dirty(bh) ||
++ test_clear_buffer_jbddirty(bh))
++ was_dirty = 1;
++ }
++
++ if (jh->b_transaction)
++ __jbd2_journal_temp_unlink_buffer(jh);
++ jh->b_transaction = transaction;
++
++ switch (jlist) {
++ case BJ_None:
++ J_ASSERT_JH(jh, !jh->b_committed_data);
++ J_ASSERT_JH(jh, !jh->b_frozen_data);
++ return;
++ case BJ_SyncData:
++ list = &transaction->t_sync_datalist;
++ break;
++ case BJ_Metadata:
++ transaction->t_nr_buffers++;
++ list = &transaction->t_buffers;
++ break;
++ case BJ_Forget:
++ list = &transaction->t_forget;
++ break;
++ case BJ_IO:
++ list = &transaction->t_iobuf_list;
++ break;
++ case BJ_Shadow:
++ list = &transaction->t_shadow_list;
++ break;
++ case BJ_LogCtl:
++ list = &transaction->t_log_list;
++ break;
++ case BJ_Reserved:
++ list = &transaction->t_reserved_list;
++ break;
++ case BJ_Locked:
++ list = &transaction->t_locked_list;
++ break;
++ }
++
++ __blist_add_buffer(list, jh);
++ jh->b_jlist = jlist;
++
++ if (was_dirty)
++ set_buffer_jbddirty(bh);
++}
++
++void jbd2_journal_file_buffer(struct journal_head *jh,
++ transaction_t *transaction, int jlist)
++{
++ jbd_lock_bh_state(jh2bh(jh));
++ spin_lock(&transaction->t_journal->j_list_lock);
++ __jbd2_journal_file_buffer(jh, transaction, jlist);
++ spin_unlock(&transaction->t_journal->j_list_lock);
++ jbd_unlock_bh_state(jh2bh(jh));
++}
++
++/*
++ * Remove a buffer from its current buffer list in preparation for
++ * dropping it from its current transaction entirely. If the buffer has
++ * already started to be used by a subsequent transaction, refile the
++ * buffer on that transaction's metadata list.
++ *
++ * Called under journal->j_list_lock
++ *
++ * Called under jbd_lock_bh_state(jh2bh(jh))
++ */
++void __jbd2_journal_refile_buffer(struct journal_head *jh)
++{
++ int was_dirty;
++ struct buffer_head *bh = jh2bh(jh);
++
++ J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
++ if (jh->b_transaction)
++ assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock);
++
++ /* If the buffer is now unused, just drop it. */
++ if (jh->b_next_transaction == NULL) {
++ __jbd2_journal_unfile_buffer(jh);
++ return;
++ }
++
++ /*
++ * It has been modified by a later transaction: add it to the new
++ * transaction's metadata list.
++ */
++
++ was_dirty = test_clear_buffer_jbddirty(bh);
++ __jbd2_journal_temp_unlink_buffer(jh);
++ jh->b_transaction = jh->b_next_transaction;
++ jh->b_next_transaction = NULL;
++ __jbd2_journal_file_buffer(jh, jh->b_transaction,
++ was_dirty ? BJ_Metadata : BJ_Reserved);
++ J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
++
++ if (was_dirty)
++ set_buffer_jbddirty(bh);
++}
++
++/*
++ * For the unlocked version of this call, also make sure that any
++ * hanging journal_head is cleaned up if necessary.
++ *
++ * __jbd2_journal_refile_buffer is usually called as part of a single locked
++ * operation on a buffer_head, in which the caller is probably going to
++ * be hooking the journal_head onto other lists. In that case it is up
++ * to the caller to remove the journal_head if necessary. For the
++ * unlocked jbd2_journal_refile_buffer call, the caller isn't going to be
++ * doing anything else to the buffer so we need to do the cleanup
++ * ourselves to avoid a jh leak.
++ *
++ * *** The journal_head may be freed by this call! ***
++ */
++void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
++{
++ struct buffer_head *bh = jh2bh(jh);
++
++ jbd_lock_bh_state(bh);
++ spin_lock(&journal->j_list_lock);
++
++ __jbd2_journal_refile_buffer(jh);
++ jbd_unlock_bh_state(bh);
++ jbd2_journal_remove_journal_head(bh);
++
++ spin_unlock(&journal->j_list_lock);
++ __brelse(bh);
++}
+diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
+index 9306869..3f7899e 100644
+--- a/fs/jffs/inode-v23.c
++++ b/fs/jffs/inode-v23.c
+@@ -364,12 +364,11 @@ jffs_new_inode(const struct inode * dir,
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_atime.tv_nsec = 0;
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+
+ f = jffs_find_file(c, raw_inode->ino);
+
+- inode->u.generic_ip = (void *)f;
++ inode->i_private = (void *)f;
+ insert_inode_hash(inode);
+
+ return inode;
+@@ -442,7 +441,7 @@ jffs_rename(struct inode *old_dir, struc
+ });
+
+ result = -ENOTDIR;
+- if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) {
++ if (!(old_dir_f = old_dir->i_private)) {
+ D(printk("jffs_rename(): Old dir invalid.\n"));
+ goto jffs_rename_end;
+ }
+@@ -456,7 +455,7 @@ jffs_rename(struct inode *old_dir, struc
+
+ /* Find the new directory. */
+ result = -ENOTDIR;
+- if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) {
++ if (!(new_dir_f = new_dir->i_private)) {
+ D(printk("jffs_rename(): New dir invalid.\n"));
+ goto jffs_rename_end;
+ }
+@@ -593,7 +592,7 @@ jffs_readdir(struct file *filp, void *di
+ }
+ else {
+ ddino = ((struct jffs_file *)
+- inode->u.generic_ip)->pino;
++ inode->i_private)->pino;
+ }
+ D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
+ if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) {
+@@ -604,7 +603,7 @@ jffs_readdir(struct file *filp, void *di
+ }
+ filp->f_pos++;
+ }
+- f = ((struct jffs_file *)inode->u.generic_ip)->children;
++ f = ((struct jffs_file *)inode->i_private)->children;
+
+ j = 2;
+ while(f && (f->deleted || j++ < filp->f_pos )) {
+@@ -652,7 +651,7 @@ jffs_lookup(struct inode *dir, struct de
+ lock_kernel();
+
+ D3({
+- char *s = (char *)kmalloc(len + 1, GFP_KERNEL);
++ char *s = kmalloc(len + 1, GFP_KERNEL);
+ memcpy(s, name, len);
+ s[len] = '\0';
+ printk("jffs_lookup(): dir: 0x%p, name: \"%s\"\n", dir, s);
+@@ -668,7 +667,7 @@ jffs_lookup(struct inode *dir, struct de
+ }
+
+ r = -EACCES;
+- if (!(d = (struct jffs_file *)dir->u.generic_ip)) {
++ if (!(d = (struct jffs_file *)dir->i_private)) {
+ D(printk("jffs_lookup(): No such inode! (%lu)\n",
+ dir->i_ino));
+ goto jffs_lookup_end;
+@@ -739,7 +738,7 @@ jffs_do_readpage_nolock(struct file *fil
+ unsigned long read_len;
+ int result;
+ struct inode *inode = (struct inode*)page->mapping->host;
+- struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip;
++ struct jffs_file *f = (struct jffs_file *)inode->i_private;
+ struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info;
+ int r;
+ loff_t offset;
+@@ -828,7 +827,7 @@ jffs_mkdir(struct inode *dir, struct den
+ });
+
+ lock_kernel();
+- dir_f = (struct jffs_file *)dir->u.generic_ip;
++ dir_f = dir->i_private;
+
+ ASSERT(if (!dir_f) {
+ printk(KERN_ERR "jffs_mkdir(): No reference to a "
+@@ -972,7 +971,7 @@ jffs_remove(struct inode *dir, struct de
+ kfree(_name);
+ });
+
+- dir_f = (struct jffs_file *) dir->u.generic_ip;
++ dir_f = dir->i_private;
+ c = dir_f->c;
+
+ result = -ENOENT;
+@@ -1053,9 +1052,8 @@ jffs_remove(struct inode *dir, struct de
+
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ mark_inode_dirty(dir);
+- inode->i_nlink--;
+ inode->i_ctime = dir->i_ctime;
+- mark_inode_dirty(inode);
++ inode_dec_link_count(inode);
+
+ d_delete(dentry); /* This also frees the inode */
+
+@@ -1082,7 +1080,7 @@ jffs_mknod(struct inode *dir, struct den
+ if (!old_valid_dev(rdev))
+ return -EINVAL;
+ lock_kernel();
+- dir_f = (struct jffs_file *)dir->u.generic_ip;
++ dir_f = dir->i_private;
+ c = dir_f->c;
+
+ D3(printk (KERN_NOTICE "mknod(): down biglock\n"));
+@@ -1173,8 +1171,8 @@ jffs_symlink(struct inode *dir, struct d
+ lock_kernel();
+ D1({
+ int len = dentry->d_name.len;
+- char *_name = (char *)kmalloc(len + 1, GFP_KERNEL);
+- char *_symname = (char *)kmalloc(symname_len + 1, GFP_KERNEL);
++ char *_name = kmalloc(len + 1, GFP_KERNEL);
++ char *_symname = kmalloc(symname_len + 1, GFP_KERNEL);
+ memcpy(_name, dentry->d_name.name, len);
+ _name[len] = '\0';
+ memcpy(_symname, symname, symname_len);
+@@ -1186,7 +1184,7 @@ jffs_symlink(struct inode *dir, struct d
+ kfree(_symname);
+ });
+
+- dir_f = (struct jffs_file *)dir->u.generic_ip;
++ dir_f = dir->i_private;
+ ASSERT(if (!dir_f) {
+ printk(KERN_ERR "jffs_symlink(): No reference to a "
+ "jffs_file struct in inode.\n");
+@@ -1282,14 +1280,14 @@ jffs_create(struct inode *dir, struct de
+ lock_kernel();
+ D1({
+ int len = dentry->d_name.len;
+- char *s = (char *)kmalloc(len + 1, GFP_KERNEL);
++ char *s = kmalloc(len + 1, GFP_KERNEL);
+ memcpy(s, dentry->d_name.name, len);
+ s[len] = '\0';
+ printk("jffs_create(): dir: 0x%p, name: \"%s\"\n", dir, s);
+ kfree(s);
+ });
+
+- dir_f = (struct jffs_file *)dir->u.generic_ip;
++ dir_f = dir->i_private;
+ ASSERT(if (!dir_f) {
+ printk(KERN_ERR "jffs_create(): No reference to a "
+ "jffs_file struct in inode.\n");
+@@ -1403,9 +1401,9 @@ jffs_file_write(struct file *filp, const
+ goto out_isem;
+ }
+
+- if (!(f = (struct jffs_file *)inode->u.generic_ip)) {
+- D(printk("jffs_file_write(): inode->u.generic_ip = 0x%p\n",
+- inode->u.generic_ip));
++ if (!(f = inode->i_private)) {
++ D(printk("jffs_file_write(): inode->i_private = 0x%p\n",
++ inode->i_private));
+ goto out_isem;
+ }
+
+@@ -1633,8 +1631,10 @@ static const struct file_operations jffs
+ {
+ .open = generic_file_open,
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .ioctl = jffs_ioctl,
+ .mmap = generic_file_readonly_mmap,
+ .fsync = jffs_fsync,
+@@ -1693,7 +1693,7 @@ jffs_read_inode(struct inode *inode)
+ mutex_unlock(&c->fmc->biglock);
+ return;
+ }
+- inode->u.generic_ip = (void *)f;
++ inode->i_private = f;
+ inode->i_mode = f->mode;
+ inode->i_nlink = f->nlink;
+ inode->i_uid = f->uid;
+@@ -1706,7 +1706,6 @@ jffs_read_inode(struct inode *inode)
+ inode->i_mtime.tv_nsec =
+ inode->i_ctime.tv_nsec = 0;
+
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &jffs_file_inode_operations;
+@@ -1748,7 +1747,7 @@ jffs_delete_inode(struct inode *inode)
+ lock_kernel();
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+- inode->u.generic_ip = NULL;
++ inode->i_private = NULL;
+ clear_inode(inode);
+ if (inode->i_nlink == 0) {
+ c = (struct jffs_control *) inode->i_sb->s_fs_info;
+diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
+index 9000f1e..4a543e1 100644
+--- a/fs/jffs/intrep.c
++++ b/fs/jffs/intrep.c
+@@ -488,13 +488,11 @@ jffs_create_file(struct jffs_control *c,
+ {
+ struct jffs_file *f;
+
+- if (!(f = (struct jffs_file *)kmalloc(sizeof(struct jffs_file),
+- GFP_KERNEL))) {
++ if (!(f = kzalloc(sizeof(*f), GFP_KERNEL))) {
+ D(printk("jffs_create_file(): Failed!\n"));
+ return NULL;
+ }
+ no_jffs_file++;
+- memset(f, 0, sizeof(struct jffs_file));
+ f->ino = raw_inode->ino;
+ f->pino = raw_inode->pino;
+ f->nlink = raw_inode->nlink;
+@@ -516,7 +514,7 @@ jffs_create_control(struct super_block *
+
+ D2(printk("jffs_create_control()\n"));
+
+- if (!(c = (struct jffs_control *)kmalloc(s, GFP_KERNEL))) {
++ if (!(c = kmalloc(s, GFP_KERNEL))) {
+ goto fail_control;
+ }
+ DJM(no_jffs_control++);
+@@ -524,7 +522,7 @@ jffs_create_control(struct super_block *
+ c->gc_task = NULL;
+ c->hash_len = JFFS_HASH_SIZE;
+ s = sizeof(struct list_head) * c->hash_len;
+- if (!(c->hash = (struct list_head *)kmalloc(s, GFP_KERNEL))) {
++ if (!(c->hash = kmalloc(s, GFP_KERNEL))) {
+ goto fail_hash;
+ }
+ DJM(no_hash++);
+@@ -593,8 +591,7 @@ jffs_add_virtual_root(struct jffs_contro
+ D2(printk("jffs_add_virtual_root(): "
+ "Creating a virtual root directory.\n"));
+
+- if (!(root = (struct jffs_file *)kmalloc(sizeof(struct jffs_file),
+- GFP_KERNEL))) {
++ if (!(root = kmalloc(sizeof(struct jffs_file), GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+ no_jffs_file++;
+diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
+index 7d8ca1a..29b68d9 100644
+--- a/fs/jffs/jffs_fm.c
++++ b/fs/jffs/jffs_fm.c
+@@ -94,8 +94,7 @@ jffs_build_begin(struct jffs_control *c,
+ struct mtd_info *mtd;
+
+ D3(printk("jffs_build_begin()\n"));
+- fmc = (struct jffs_fmcontrol *)kmalloc(sizeof(struct jffs_fmcontrol),
+- GFP_KERNEL);
++ fmc = kmalloc(sizeof(*fmc), GFP_KERNEL);
+ if (!fmc) {
+ D(printk("jffs_build_begin(): Allocation of "
+ "struct jffs_fmcontrol failed!\n"));
+@@ -486,8 +485,7 @@ jffs_add_node(struct jffs_node *node)
+
+ D3(printk("jffs_add_node(): ino = %u\n", node->ino));
+
+- ref = (struct jffs_node_ref *)kmalloc(sizeof(struct jffs_node_ref),
+- GFP_KERNEL);
++ ref = kmalloc(sizeof(*ref), GFP_KERNEL);
+ if (!ref)
+ return -ENOMEM;
+
+diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
+index edd8371..9def6ad 100644
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -588,7 +588,7 @@ static int jffs2_mkdir (struct inode *di
+ }
+
+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
+- dir_i->i_nlink++;
++ inc_nlink(dir_i);
+
+ jffs2_free_raw_dirent(rd);
+
+@@ -615,7 +615,7 @@ static int jffs2_rmdir (struct inode *di
+ }
+ ret = jffs2_unlink(dir_i, dentry);
+ if (!ret)
+- dir_i->i_nlink--;
++ drop_nlink(dir_i);
+ return ret;
+ }
+
+@@ -823,7 +823,7 @@ static int jffs2_rename (struct inode *o
+
+ if (victim_f) {
+ /* There was a victim. Kill it off nicely */
+- new_dentry->d_inode->i_nlink--;
++ drop_nlink(new_dentry->d_inode);
+ /* Don't oops if the victim was a dirent pointing to an
+ inode which didn't exist. */
+ if (victim_f->inocache) {
+@@ -836,7 +836,7 @@ static int jffs2_rename (struct inode *o
+ /* If it was a directory we moved, and there was no victim,
+ increase i_nlink on its new parent */
+ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
+- new_dir_i->i_nlink++;
++ inc_nlink(new_dir_i);
+
+ /* Unlink the original */
+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+@@ -848,7 +848,7 @@ static int jffs2_rename (struct inode *o
+ /* Oh shit. We really ought to make a single node which can do both atomically */
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
+ down(&f->sem);
+- old_dentry->d_inode->i_nlink++;
++ inc_nlink(old_dentry->d_inode);
+ if (f->inocache)
+ f->inocache->nlink++;
+ up(&f->sem);
+@@ -862,7 +862,7 @@ static int jffs2_rename (struct inode *o
+ }
+
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
+- old_dir_i->i_nlink--;
++ drop_nlink(old_dir_i);
+
+ new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
+
+diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
+index 3ed6e3e..242875f 100644
+--- a/fs/jffs2/file.c
++++ b/fs/jffs2/file.c
+@@ -42,8 +42,10 @@ const struct file_operations jffs2_file_
+ {
+ .llseek = generic_file_llseek,
+ .open = generic_file_open,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .ioctl = jffs2_ioctl,
+ .mmap = generic_file_readonly_mmap,
+ .fsync = jffs2_fsync,
+diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
+index 4780f82..7bc1a42 100644
+--- a/fs/jffs2/fs.c
++++ b/fs/jffs2/fs.c
+@@ -263,7 +263,6 @@ void jffs2_read_inode (struct inode *ino
+
+ inode->i_nlink = f->inocache->nlink;
+
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+
+ switch (inode->i_mode & S_IFMT) {
+@@ -278,13 +277,13 @@ void jffs2_read_inode (struct inode *ino
+
+ for (fd=f->dents; fd; fd = fd->next) {
+ if (fd->type == DT_DIR && fd->ino)
+- inode->i_nlink++;
++ inc_nlink(inode);
+ }
+ /* and '..' */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ /* Root dir gets i_nlink 3 for some reason */
+ if (inode->i_ino == 1)
+- inode->i_nlink++;
++ inc_nlink(inode);
+
+ inode->i_op = &jffs2_dir_inode_operations;
+ inode->i_fop = &jffs2_dir_operations;
+@@ -449,7 +448,6 @@ struct inode *jffs2_new_inode (struct in
+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
+
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_size = 0;
+
+diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h
+index 2e0cc8e..3a56607 100644
+--- a/fs/jffs2/jffs2_fs_i.h
++++ b/fs/jffs2/jffs2_fs_i.h
+@@ -41,11 +41,7 @@ struct jffs2_inode_info {
+
+ uint16_t flags;
+ uint8_t usercompr;
+-#if !defined (__ECOS)
+-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
+ struct inode vfs_inode;
+-#endif
+-#endif
+ #ifdef CONFIG_JFFS2_FS_POSIX_ACL
+ struct posix_acl *i_acl_access;
+ struct posix_acl *i_acl_default;
+diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
+index 68e3953..bc4b810 100644
+--- a/fs/jffs2/super.c
++++ b/fs/jffs2/super.c
+@@ -119,10 +119,9 @@ static int jffs2_get_sb_mtd(struct file_
+ struct jffs2_sb_info *c;
+ int ret;
+
+- c = kmalloc(sizeof(*c), GFP_KERNEL);
++ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+- memset(c, 0, sizeof(*c));
+ c->mtd = mtd;
+
+ sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
+@@ -335,10 +334,10 @@ static int __init init_jffs2_fs(void)
+ which means just 'no padding', without the alignment
+ thing. But GCC doesn't have that -- we have to just
+ hope the structs are the right sizes, instead. */
+- BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
+- BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
+- BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+- BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
++ BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
++ BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
++ BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
++ BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
+
+ printk(KERN_INFO "JFFS2 version 2.2."
+ #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
+index e228130..4d84bdc 100644
+--- a/fs/jfs/acl.c
++++ b/fs/jfs/acl.c
+@@ -5,16 +5,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -183,7 +183,7 @@ cleanup:
+ posix_acl_release(acl);
+ } else
+ inode->i_mode &= ~current->fs->umask;
+-
++
+ JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
+ inode->i_mode;
+
+diff --git a/fs/jfs/endian24.h b/fs/jfs/endian24.h
+index ab7cd05..79494c4 100644
+--- a/fs/jfs/endian24.h
++++ b/fs/jfs/endian24.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2001
++ * Copyright (C) International Business Machines Corp., 2001
+ *
+ * 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
+diff --git a/fs/jfs/file.c b/fs/jfs/file.c
+index 1c9745b..aa9132d 100644
+--- a/fs/jfs/file.c
++++ b/fs/jfs/file.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -103,14 +103,14 @@ struct inode_operations jfs_file_inode_o
+ const struct file_operations jfs_file_operations = {
+ .open = jfs_open,
+ .llseek = generic_file_llseek,
+- .write = generic_file_write,
+- .read = generic_file_read,
++ .write = do_sync_write,
++ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+- .readv = generic_file_readv,
+- .writev = generic_file_writev,
+- .sendfile = generic_file_sendfile,
++ .sendfile = generic_file_sendfile,
++ .splice_read = generic_file_splice_read,
++ .splice_write = generic_file_splice_write,
+ .fsync = jfs_fsync,
+ .release = jfs_release,
+ .ioctl = jfs_ioctl,
+diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
+index a223cf4..f571911 100644
+--- a/fs/jfs/inode.c
++++ b/fs/jfs/inode.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -33,7 +33,7 @@
+
+ void jfs_read_inode(struct inode *inode)
+ {
+- if (diRead(inode)) {
++ if (diRead(inode)) {
+ make_bad_inode(inode);
+ return;
+ }
+@@ -227,7 +227,7 @@ int jfs_get_block(struct inode *ip, sect
+ #ifdef _JFS_4K
+ if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
+ goto unlock;
+- rc = extAlloc(ip, xlen, lblock64, &xad, FALSE);
++ rc = extAlloc(ip, xlen, lblock64, &xad, false);
+ if (rc)
+ goto unlock;
+
+diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
+index 67b3774..37db524 100644
+--- a/fs/jfs/ioctl.c
++++ b/fs/jfs/ioctl.c
+@@ -6,7 +6,6 @@
+ */
+
+ #include <linux/fs.h>
+-#include <linux/ext2_fs.h>
+ #include <linux/ctype.h>
+ #include <linux/capability.h>
+ #include <linux/time.h>
+@@ -22,13 +21,13 @@ static struct {
+ long jfs_flag;
+ long ext2_flag;
+ } jfs_map[] = {
+- {JFS_NOATIME_FL, EXT2_NOATIME_FL},
+- {JFS_DIRSYNC_FL, EXT2_DIRSYNC_FL},
+- {JFS_SYNC_FL, EXT2_SYNC_FL},
+- {JFS_SECRM_FL, EXT2_SECRM_FL},
+- {JFS_UNRM_FL, EXT2_UNRM_FL},
+- {JFS_APPEND_FL, EXT2_APPEND_FL},
+- {JFS_IMMUTABLE_FL, EXT2_IMMUTABLE_FL},
++ {JFS_NOATIME_FL, FS_NOATIME_FL},
++ {JFS_DIRSYNC_FL, FS_DIRSYNC_FL},
++ {JFS_SYNC_FL, FS_SYNC_FL},
++ {JFS_SECRM_FL, FS_SECRM_FL},
++ {JFS_UNRM_FL, FS_UNRM_FL},
++ {JFS_APPEND_FL, FS_APPEND_FL},
++ {JFS_IMMUTABLE_FL, FS_IMMUTABLE_FL},
+ {0, 0},
+ };
+
+diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
+index a762937..455fa42 100644
+--- a/fs/jfs/jfs_acl.h
++++ b/fs/jfs/jfs_acl.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2002
++ * Copyright (C) International Business Machines Corp., 2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_ACL
+diff --git a/fs/jfs/jfs_btree.h b/fs/jfs/jfs_btree.h
+index 7f3e9ac..79c6180 100644
+--- a/fs/jfs/jfs_btree.h
++++ b/fs/jfs/jfs_btree.h
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_BTREE
+diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
+index 81f0e51..9c5d596 100644
+--- a/fs/jfs/jfs_debug.c
++++ b/fs/jfs/jfs_debug.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h
+index 9f2572a..40b2011 100644
+--- a/fs/jfs/jfs_dinode.h
++++ b/fs/jfs/jfs_dinode.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2001
++ * Copyright (C) International Business Machines Corp., 2000-2001
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_DINODE
+diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
+index c161c98..23546c8 100644
+--- a/fs/jfs/jfs_dmap.c
++++ b/fs/jfs/jfs_dmap.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -30,28 +30,28 @@
+ *
+ * the working state of the block allocation map is accessed in
+ * two directions:
+- *
++ *
+ * 1) allocation and free requests that start at the dmap
+ * level and move up through the dmap control pages (i.e.
+ * the vast majority of requests).
+- *
+- * 2) allocation requests that start at dmap control page
++ *
++ * 2) allocation requests that start at dmap control page
+ * level and work down towards the dmaps.
+- *
+- * the serialization scheme used here is as follows.
+ *
+- * requests which start at the bottom are serialized against each
+- * other through buffers and each requests holds onto its buffers
+- * as it works it way up from a single dmap to the required level
++ * the serialization scheme used here is as follows.
++ *
++ * requests which start at the bottom are serialized against each
++ * other through buffers and each requests holds onto its buffers
++ * as it works it way up from a single dmap to the required level
+ * of dmap control page.
+ * requests that start at the top are serialized against each other
+ * and request that start from the bottom by the multiple read/single
+ * write inode lock of the bmap inode. requests starting at the top
+ * take this lock in write mode while request starting at the bottom
+ * take the lock in read mode. a single top-down request may proceed
+- * exclusively while multiple bottoms-up requests may proceed
+- * simultaneously (under the protection of busy buffers).
+- *
++ * exclusively while multiple bottoms-up requests may proceed
++ * simultaneously (under the protection of busy buffers).
++ *
+ * in addition to information found in dmaps and dmap control pages,
+ * the working state of the block allocation map also includes read/
+ * write information maintained in the bmap descriptor (i.e. total
+@@ -59,7 +59,7 @@
+ * a single exclusive lock (BMAP_LOCK) is used to guard this information
+ * in the face of multiple-bottoms up requests.
+ * (lock ordering: IREAD_LOCK, BMAP_LOCK);
+- *
++ *
+ * accesses to the persistent state of the block allocation map (limited
+ * to the persistent bitmaps in dmaps) is guarded by (busy) buffers.
+ */
+@@ -120,7 +120,7 @@ static int dbGetL2AGSize(s64 nblocks);
+ /*
+ * buddy table
+ *
+- * table used for determining buddy sizes within characters of
++ * table used for determining buddy sizes within characters of
+ * dmap bitmap words. the characters themselves serve as indexes
+ * into the table, with the table elements yielding the maximum
+ * binary buddy of free bits within the character.
+@@ -146,7 +146,7 @@ static const s8 budtab[256] = {
+
+
+ /*
+- * NAME: dbMount()
++ * NAME: dbMount()
+ *
+ * FUNCTION: initializate the block allocation map.
+ *
+@@ -223,12 +223,12 @@ int dbMount(struct inode *ipbmap)
+
+
+ /*
+- * NAME: dbUnmount()
++ * NAME: dbUnmount()
+ *
+ * FUNCTION: terminate the block allocation map in preparation for
+ * file system unmount.
+ *
+- * the in-core bmap descriptor is written to disk and
++ * the in-core bmap descriptor is written to disk and
+ * the memory for this descriptor is freed.
+ *
+ * PARAMETERS:
+@@ -311,7 +311,7 @@ int dbSync(struct inode *ipbmap)
+
+
+ /*
+- * NAME: dbFree()
++ * NAME: dbFree()
+ *
+ * FUNCTION: free the specified block range from the working block
+ * allocation map.
+@@ -397,14 +397,14 @@ int dbFree(struct inode *ip, s64 blkno,
+ *
+ * FUNCTION: update the allocation state (free or allocate) of the
+ * specified block range in the persistent block allocation map.
+- *
++ *
+ * the blocks will be updated in the persistent map one
+ * dmap at a time.
+ *
+ * PARAMETERS:
+ * ipbmap - pointer to in-core inode for the block map.
+- * free - TRUE if block range is to be freed from the persistent
+- * map; FALSE if it is to be allocated.
++ * free - 'true' if block range is to be freed from the persistent
++ * map; 'false' if it is to be allocated.
+ * blkno - starting block number of the range.
+ * nblocks - number of contiguous blocks in the range.
+ * tblk - transaction block;
+@@ -475,7 +475,7 @@ dbUpdatePMap(struct inode *ipbmap,
+ /* update the bits of the dmap words. the first and last
+ * words may only have a subset of their bits updated. if
+ * this is the case, we'll work against that word (i.e.
+- * partial first and/or last) only in a single pass. a
++ * partial first and/or last) only in a single pass. a
+ * single pass will also be used to update all words that
+ * are to have all their bits updated.
+ */
+@@ -662,11 +662,11 @@ unlock:
+ * the block allocation policy uses hints and a multi-step
+ * approach.
+ *
+- * for allocation requests smaller than the number of blocks
++ * for allocation requests smaller than the number of blocks
+ * per dmap, we first try to allocate the new blocks
+ * immediately following the hint. if these blocks are not
+ * available, we try to allocate blocks near the hint. if
+- * no blocks near the hint are available, we next try to
++ * no blocks near the hint are available, we next try to
+ * allocate within the same dmap as contains the hint.
+ *
+ * if no blocks are available in the dmap or the allocation
+@@ -713,7 +713,7 @@ int dbAlloc(struct inode *ip, s64 hint,
+ #endif /* _STILL_TO_PORT */
+
+ /* get the log2 number of blocks to be allocated.
+- * if the number of blocks is not a log2 multiple,
++ * if the number of blocks is not a log2 multiple,
+ * it will be rounded up to the next log2 multiple.
+ */
+ l2nb = BLKSTOL2(nblocks);
+@@ -906,7 +906,7 @@ int dbAllocExact(struct inode *ip, s64 b
+ * validate extent request:
+ *
+ * note: defragfs policy:
+- * max 64 blocks will be moved.
++ * max 64 blocks will be moved.
+ * allocation request size must be satisfied from a single dmap.
+ */
+ if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) {
+@@ -1333,7 +1333,7 @@ dbAllocNear(struct bmap * bmp,
+ * or two sub-trees, depending on the allocation group size.
+ * we search the top nodes of these subtrees left to right for
+ * sufficient free space. if sufficient free space is found,
+- * the subtree is searched to find the leftmost leaf that
++ * the subtree is searched to find the leftmost leaf that
+ * has free space. once we have made it to the leaf, we
+ * move the search to the next lower level dmap control page
+ * corresponding to this leaf. we continue down the dmap control
+@@ -1398,7 +1398,7 @@ dbAllocAG(struct bmap * bmp, int agno, s
+ * that fully describes the allocation group since the allocation
+ * group is already fully described by a dmap. in this case, we
+ * just call dbAllocCtl() to search the dmap tree and allocate the
+- * required space if available.
++ * required space if available.
+ *
+ * if the allocation group is completely free, dbAllocCtl() is
+ * also called to allocate the required space. this is done for
+@@ -1450,7 +1450,7 @@ dbAllocAG(struct bmap * bmp, int agno, s
+ (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth;
+ ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1));
+
+- /* dmap control page trees fan-out by 4 and a single allocation
++ /* dmap control page trees fan-out by 4 and a single allocation
+ * group may be described by 1 or 2 subtrees within the ag level
+ * dmap control page, depending upon the ag size. examine the ag's
+ * subtrees for sufficient free space, starting with the leftmost
+@@ -1633,7 +1633,7 @@ static int dbFindCtl(struct bmap * bmp,
+
+ /* starting at the specified dmap control page level and block
+ * number, search down the dmap control levels for the starting
+- * block number of a dmap page that contains or starts off
++ * block number of a dmap page that contains or starts off
+ * sufficient free blocks.
+ */
+ for (lev = level, b = *blkno; lev >= 0; lev--) {
+@@ -1677,7 +1677,7 @@ static int dbFindCtl(struct bmap * bmp,
+ }
+
+ /* adjust the block number to reflect the location within
+- * the dmap control page (i.e. the leaf) at which free
++ * the dmap control page (i.e. the leaf) at which free
+ * space was found.
+ */
+ b += (((s64) leafidx) << budmin);
+@@ -1700,12 +1700,12 @@ static int dbFindCtl(struct bmap * bmp,
+ * NAME: dbAllocCtl()
+ *
+ * FUNCTION: attempt to allocate a specified number of contiguous
+- * blocks starting within a specific dmap.
+- *
++ * blocks starting within a specific dmap.
++ *
+ * this routine is called by higher level routines that search
+ * the dmap control pages above the actual dmaps for contiguous
+ * free space. the result of successful searches by these
+- * routines are the starting block numbers within dmaps, with
++ * routines are the starting block numbers within dmaps, with
+ * the dmaps themselves containing the desired contiguous free
+ * space or starting a contiguous free space of desired size
+ * that is made up of the blocks of one or more dmaps. these
+@@ -1872,14 +1872,14 @@ dbAllocCtl(struct bmap * bmp, s64 nblock
+ *
+ * FUNCTION: attempt to allocate a specified number of contiguous blocks
+ * from a specified dmap.
+- *
++ *
+ * this routine checks if the contiguous blocks are available.
+ * if so, nblocks of blocks are allocated; otherwise, ENOSPC is
+ * returned.
+ *
+ * PARAMETERS:
+ * mp - pointer to bmap descriptor
+- * dp - pointer to dmap to attempt to allocate blocks from.
++ * dp - pointer to dmap to attempt to allocate blocks from.
+ * l2nb - log2 number of contiguous block desired.
+ * nblocks - actual number of contiguous block desired.
+ * results - on successful return, set to the starting block number
+@@ -1890,7 +1890,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblock
+ * -ENOSPC - insufficient disk resources
+ * -EIO - i/o error
+ *
+- * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or
++ * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or
+ * IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
+ */
+ static int
+@@ -2032,7 +2032,7 @@ static int dbFreeDmap(struct bmap * bmp,
+
+ /* root changed. bubble the change up to the dmap control pages.
+ * if the adjustment of the upper level control pages fails,
+- * backout the deallocation.
++ * backout the deallocation.
+ */
+ if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 0, 0))) {
+ word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;
+@@ -2245,7 +2245,7 @@ static int dbFreeBits(struct bmap * bmp,
+ * words (i.e. partial first and/or last) on an individual basis
+ * (a single pass), freeing the bits of interest by hand and updating
+ * the leaf corresponding to the dmap word. a single pass will be used
+- * for all dmap words fully contained within the specified range.
++ * for all dmap words fully contained within the specified range.
+ * within this pass, the bits of all fully contained dmap words will
+ * be marked as free in a single shot and the leaves will be updated. a
+ * single leaf may describe the free space of multiple dmap words,
+@@ -2267,7 +2267,7 @@ static int dbFreeBits(struct bmap * bmp,
+ */
+ if (nb < DBWORD) {
+ /* free (zero) the appropriate bits within this
+- * dmap word.
++ * dmap word.
+ */
+ dp->wmap[word] &=
+ cpu_to_le32(~(ONES << (DBWORD - nb)
+@@ -2327,7 +2327,7 @@ static int dbFreeBits(struct bmap * bmp,
+
+ BMAP_LOCK(bmp);
+
+- /* update the free count for the allocation group and
++ /* update the free count for the allocation group and
+ * map.
+ */
+ agno = blkno >> bmp->db_agl2size;
+@@ -2378,7 +2378,7 @@ static int dbFreeBits(struct bmap * bmp,
+ * or deallocation resulted in the root change. this range
+ * is respresented by a single leaf of the current dmapctl
+ * and the leaf will be updated with this value, possibly
+- * causing a binary buddy system within the leaves to be
++ * causing a binary buddy system within the leaves to be
+ * split or joined. the update may also cause the dmapctl's
+ * dmtree to be updated.
+ *
+@@ -2394,7 +2394,7 @@ static int dbFreeBits(struct bmap * bmp,
+ * requires the dmap control page to be adjusted.
+ * newval - the new value of the lower level dmap or dmap control
+ * page root.
+- * alloc - TRUE if adjustment is due to an allocation.
++ * alloc - 'true' if adjustment is due to an allocation.
+ * level - current level of dmap control page (i.e. L0, L1, L2) to
+ * be adjusted.
+ *
+@@ -2590,7 +2590,7 @@ static void dbSplit(dmtree_t * tp, int l
+ }
+ }
+
+- /* adjust the dmap tree to reflect the specified leaf's new
++ /* adjust the dmap tree to reflect the specified leaf's new
+ * value.
+ */
+ dbAdjTree(tp, leafno, newval);
+@@ -2638,7 +2638,7 @@ static int dbBackSplit(dmtree_t * tp, in
+ /* the back split is accomplished by iteratively finding the leaf
+ * that starts the buddy system that contains the specified leaf and
+ * splitting that system in two. this iteration continues until
+- * the specified leaf becomes the start of a buddy system.
++ * the specified leaf becomes the start of a buddy system.
+ *
+ * determine maximum possible l2 size for the specified leaf.
+ */
+@@ -2853,7 +2853,7 @@ static void dbAdjTree(dmtree_t * tp, int
+ * NAME: dbFindLeaf()
+ *
+ * FUNCTION: search a dmtree_t for sufficient free blocks, returning
+- * the index of a leaf describing the free blocks if
++ * the index of a leaf describing the free blocks if
+ * sufficient free blocks are found.
+ *
+ * the search starts at the top of the dmtree_t tree and
+@@ -2869,7 +2869,7 @@ static void dbAdjTree(dmtree_t * tp, int
+ *
+ * RETURN VALUES:
+ * 0 - success
+- * -ENOSPC - insufficient free blocks.
++ * -ENOSPC - insufficient free blocks.
+ */
+ static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
+ {
+@@ -3090,7 +3090,7 @@ static int blkstol2(s64 nb)
+
+
+ /*
+- * NAME: dbAllocBottomUp()
++ * NAME: dbAllocBottomUp()
+ *
+ * FUNCTION: alloc the specified block range from the working block
+ * allocation map.
+@@ -3241,7 +3241,7 @@ static int dbAllocDmapBU(struct bmap * b
+ BMAP_LOCK(bmp);
+
+ /* if this allocation group is completely free,
+- * update the highest active allocation group number
++ * update the highest active allocation group number
+ * if this allocation group is the new max.
+ */
+ agno = blkno >> bmp->db_agl2size;
+@@ -3273,7 +3273,7 @@ static int dbAllocDmapBU(struct bmap * b
+ * NAME: dbExtendFS()
+ *
+ * FUNCTION: extend bmap from blkno for nblocks;
+- * dbExtendFS() updates bmap ready for dbAllocBottomUp();
++ * dbExtendFS() updates bmap ready for dbAllocBottomUp();
+ *
+ * L2
+ * |
+@@ -3284,13 +3284,13 @@ static int dbAllocDmapBU(struct bmap * b
+ * d0,...,dn d0,...,dn d0,...,dn d0,...,dn d0,...,dn d0,.,dm;
+ * L2L1L0d0,...,dnL0d0,...,dnL0d0,...,dnL1L0d0,...,dnL0d0,...,dnL0d0,..dm
+ *
+- * <---old---><----------------------------extend----------------------->
++ * <---old---><----------------------------extend----------------------->
+ */
+ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
+ {
+ struct jfs_sb_info *sbi = JFS_SBI(ipbmap->i_sb);
+ int nbperpage = sbi->nbperpage;
+- int i, i0 = TRUE, j, j0 = TRUE, k, n;
++ int i, i0 = true, j, j0 = true, k, n;
+ s64 newsize;
+ s64 p;
+ struct metapage *mp, *l2mp, *l1mp = NULL, *l0mp = NULL;
+@@ -3330,7 +3330,7 @@ int dbExtendFS(struct inode *ipbmap, s64
+ bmp->db_numag += ((u32) newsize % (u32) bmp->db_agsize) ? 1 : 0;
+
+ /*
+- * reconfigure db_agfree[]
++ * reconfigure db_agfree[]
+ * from old AG configuration to new AG configuration;
+ *
+ * coalesce contiguous k (newAGSize/oldAGSize) AGs;
+@@ -3398,7 +3398,7 @@ int dbExtendFS(struct inode *ipbmap, s64
+ j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE;
+ l1leaf = l1dcp->stree + CTLLEAFIND + j;
+ p = BLKTOL0(blkno, sbi->l2nbperpage);
+- j0 = FALSE;
++ j0 = false;
+ } else {
+ /* assign/init L1 page */
+ l1mp = get_metapage(ipbmap, p, PSIZE, 0);
+@@ -3432,7 +3432,7 @@ int dbExtendFS(struct inode *ipbmap, s64
+ l0leaf = l0dcp->stree + CTLLEAFIND + i;
+ p = BLKTODMAP(blkno,
+ sbi->l2nbperpage);
+- i0 = FALSE;
++ i0 = false;
+ } else {
+ /* assign/init L0 page */
+ l0mp = get_metapage(ipbmap, p, PSIZE, 0);
+@@ -3491,7 +3491,7 @@ int dbExtendFS(struct inode *ipbmap, s64
+ } /* for each dmap in a L0 */
+
+ /*
+- * build current L0 page from its leaves, and
++ * build current L0 page from its leaves, and
+ * initialize corresponding parent L1 leaf
+ */
+ *l1leaf = dbInitDmapCtl(l0dcp, 0, ++i);
+@@ -3515,7 +3515,7 @@ int dbExtendFS(struct inode *ipbmap, s64
+ } /* for each L0 in a L1 */
+
+ /*
+- * build current L1 page from its leaves, and
++ * build current L1 page from its leaves, and
+ * initialize corresponding parent L2 leaf
+ */
+ *l2leaf = dbInitDmapCtl(l1dcp, 1, ++j);
+@@ -3570,7 +3570,7 @@ void dbFinalizeBmap(struct inode *ipbmap
+ * finalize bmap control page
+ */
+ //finalize:
+- /*
++ /*
+ * compute db_agpref: preferred ag to allocate from
+ * (the leftmost ag with average free space in it);
+ */
+@@ -3614,9 +3614,9 @@ void dbFinalizeBmap(struct inode *ipbmap
+
+ /*
+ * compute db_aglevel, db_agheigth, db_width, db_agstart:
+- * an ag is covered in aglevel dmapctl summary tree,
+- * at agheight level height (from leaf) with agwidth number of nodes
+- * each, which starts at agstart index node of the smmary tree node
++ * an ag is covered in aglevel dmapctl summary tree,
++ * at agheight level height (from leaf) with agwidth number of nodes
++ * each, which starts at agstart index node of the smmary tree node
+ * array;
+ */
+ bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize);
+@@ -3635,13 +3635,13 @@ void dbFinalizeBmap(struct inode *ipbmap
+
+ /*
+ * NAME: dbInitDmap()/ujfs_idmap_page()
+- *
++ *
+ * FUNCTION: initialize working/persistent bitmap of the dmap page
+ * for the specified number of blocks:
+- *
++ *
+ * at entry, the bitmaps had been initialized as free (ZEROS);
+- * The number of blocks will only account for the actually
+- * existing blocks. Blocks which don't actually exist in
++ * The number of blocks will only account for the actually
++ * existing blocks. Blocks which don't actually exist in
+ * the aggregate will be marked as allocated (ONES);
+ *
+ * PARAMETERS:
+@@ -3677,7 +3677,7 @@ static int dbInitDmap(struct dmap * dp,
+
+ /*
+ * free the bits corresponding to the block range (ZEROS):
+- * note: not all bits of the first and last words may be contained
++ * note: not all bits of the first and last words may be contained
+ * within the block range.
+ */
+ for (r = nblocks; r > 0; r -= nb, blkno += nb) {
+@@ -3709,7 +3709,7 @@ static int dbInitDmap(struct dmap * dp,
+ }
+
+ /*
+- * mark bits following the range to be freed (non-existing
++ * mark bits following the range to be freed (non-existing
+ * blocks) as allocated (ONES)
+ */
+
+@@ -3741,11 +3741,11 @@ static int dbInitDmap(struct dmap * dp,
+
+ /*
+ * NAME: dbInitDmapTree()/ujfs_complete_dmap()
+- *
++ *
+ * FUNCTION: initialize summary tree of the specified dmap:
+ *
+ * at entry, bitmap of the dmap has been initialized;
+- *
++ *
+ * PARAMETERS:
+ * dp - dmap to complete
+ * blkno - starting block number for this dmap
+@@ -3769,7 +3769,7 @@ static int dbInitDmapTree(struct dmap *
+
+ /* init each leaf from corresponding wmap word:
+ * note: leaf is set to NOFREE(-1) if all blocks of corresponding
+- * bitmap word are allocated.
++ * bitmap word are allocated.
+ */
+ cp = tp->stree + le32_to_cpu(tp->leafidx);
+ for (i = 0; i < LPERDMAP; i++)
+@@ -3782,10 +3782,10 @@ static int dbInitDmapTree(struct dmap *
+
+ /*
+ * NAME: dbInitTree()/ujfs_adjtree()
+- *
++ *
+ * FUNCTION: initialize binary buddy summary tree of a dmap or dmapctl.
+ *
+- * at entry, the leaves of the tree has been initialized
++ * at entry, the leaves of the tree has been initialized
+ * from corresponding bitmap word or root of summary tree
+ * of the child control page;
+ * configure binary buddy system at the leaf level, then
+@@ -3813,15 +3813,15 @@ static int dbInitTree(struct dmaptree *
+ /*
+ * configure the leaf levevl into binary buddy system
+ *
+- * Try to combine buddies starting with a buddy size of 1
+- * (i.e. two leaves). At a buddy size of 1 two buddy leaves
+- * can be combined if both buddies have a maximum free of l2min;
+- * the combination will result in the left-most buddy leaf having
+- * a maximum free of l2min+1.
+- * After processing all buddies for a given size, process buddies
+- * at the next higher buddy size (i.e. current size * 2) and
+- * the next maximum free (current free + 1).
+- * This continues until the maximum possible buddy combination
++ * Try to combine buddies starting with a buddy size of 1
++ * (i.e. two leaves). At a buddy size of 1 two buddy leaves
++ * can be combined if both buddies have a maximum free of l2min;
++ * the combination will result in the left-most buddy leaf having
++ * a maximum free of l2min+1.
++ * After processing all buddies for a given size, process buddies
++ * at the next higher buddy size (i.e. current size * 2) and
++ * the next maximum free (current free + 1).
++ * This continues until the maximum possible buddy combination
+ * yields maximum free.
+ */
+ for (l2free = dtp->budmin, bsize = 1; l2free < l2max;
+@@ -3845,10 +3845,10 @@ static int dbInitTree(struct dmaptree *
+ * bubble summary information of leaves up the tree.
+ *
+ * Starting at the leaf node level, the four nodes described by
+- * the higher level parent node are compared for a maximum free and
+- * this maximum becomes the value of the parent node.
+- * when all lower level nodes are processed in this fashion then
+- * move up to the next level (parent becomes a lower level node) and
++ * the higher level parent node are compared for a maximum free and
++ * this maximum becomes the value of the parent node.
++ * when all lower level nodes are processed in this fashion then
++ * move up to the next level (parent becomes a lower level node) and
+ * continue the process for that level.
+ */
+ for (child = le32_to_cpu(dtp->leafidx),
+@@ -3857,7 +3857,7 @@ static int dbInitTree(struct dmaptree *
+ /* get index of 1st node of parent level */
+ parent = (child - 1) >> 2;
+
+- /* set the value of the parent node as the maximum
++ /* set the value of the parent node as the maximum
+ * of the four nodes of the current level.
+ */
+ for (i = 0, cp = tp + child, cp1 = tp + parent;
+@@ -3885,8 +3885,8 @@ static int dbInitDmapCtl(struct dmapctl
+ dcp->budmin = L2BPERDMAP + L2LPERCTL * level;
+
+ /*
+- * initialize the leaves of current level that were not covered
+- * by the specified input block range (i.e. the leaves have no
++ * initialize the leaves of current level that were not covered
++ * by the specified input block range (i.e. the leaves have no
+ * low level dmapctl or dmap).
+ */
+ cp = &dcp->stree[CTLLEAFIND + i];
+@@ -3900,9 +3900,9 @@ static int dbInitDmapCtl(struct dmapctl
+
+ /*
+ * NAME: dbGetL2AGSize()/ujfs_getagl2size()
+- *
++ *
+ * FUNCTION: Determine log2(allocation group size) from aggregate size
+- *
++ *
+ * PARAMETERS:
+ * nblocks - Number of blocks in aggregate
+ *
+@@ -3935,8 +3935,8 @@ static int dbGetL2AGSize(s64 nblocks)
+
+ /*
+ * NAME: dbMapFileSizeToMapSize()
+- *
+- * FUNCTION: compute number of blocks the block allocation map file
++ *
++ * FUNCTION: compute number of blocks the block allocation map file
+ * can cover from the map file size;
+ *
+ * RETURNS: Number of blocks which can be covered by this block map file;
+@@ -3968,7 +3968,7 @@ s64 dbMapFileSizeToMapSize(struct inode
+ npages = nblocks >> JFS_SBI(sb)->l2nbperpage;
+ level = BMAPPGTOLEV(npages);
+
+- /* At each level, accumulate the number of dmap pages covered by
++ /* At each level, accumulate the number of dmap pages covered by
+ * the number of full child levels below it;
+ * repeat for the last incomplete child level.
+ */
+@@ -3990,7 +3990,7 @@ s64 dbMapFileSizeToMapSize(struct inode
+ npages--;
+ }
+
+- /* convert the number of dmaps into the number of blocks
++ /* convert the number of dmaps into the number of blocks
+ * which can be covered by the dmaps;
+ */
+ nblocks = ndmaps << L2BPERDMAP;
+diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h
+index 8b14cc8..45ea454 100644
+--- a/fs/jfs/jfs_dmap.h
++++ b/fs/jfs/jfs_dmap.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_DMAP
+@@ -27,7 +27,7 @@
+ #define L2LPERDMAP 8 /* l2 number of leaves per dmap tree */
+ #define DBWORD 32 /* # of blks covered by a map word */
+ #define L2DBWORD 5 /* l2 # of blks covered by a mword */
+-#define BUDMIN L2DBWORD /* max free string in a map word */
++#define BUDMIN L2DBWORD /* max free string in a map word */
+ #define BPERDMAP (LPERDMAP * DBWORD) /* num of blks per dmap */
+ #define L2BPERDMAP 13 /* l2 num of blks per dmap */
+ #define CTLTREESIZE (1024+256+64+16+4+1) /* size of a dmapctl tree */
+@@ -57,7 +57,7 @@
+
+ #define MAXMAPSIZE MAXL2SIZE /* maximum aggregate map size */
+
+-/*
++/*
+ * determine the maximum free string for four (lower level) nodes
+ * of the tree.
+ */
+@@ -122,7 +122,7 @@ static __inline signed char TREEMAX(sign
+ #define BLKTOCTL(b,s,l) \
+ (((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))
+
+-/*
++/*
+ * convert aggregate map size to the zero origin dmapctl level of the
+ * top dmapctl.
+ */
+@@ -192,13 +192,13 @@ typedef union dmtree {
+
+ /* macros for accessing fields within dmtree */
+ #define dmt_nleafs t1.nleafs
+-#define dmt_l2nleafs t1.l2nleafs
+-#define dmt_leafidx t1.leafidx
+-#define dmt_height t1.height
+-#define dmt_budmin t1.budmin
+-#define dmt_stree t1.stree
++#define dmt_l2nleafs t1.l2nleafs
++#define dmt_leafidx t1.leafidx
++#define dmt_height t1.height
++#define dmt_budmin t1.budmin
++#define dmt_stree t1.stree
+
+-/*
++/*
+ * on-disk aggregate disk allocation map descriptor.
+ */
+ struct dbmap_disk {
+@@ -237,7 +237,7 @@ struct dbmap {
+ s64 dn_agsize; /* num of blks per alloc group */
+ signed char dn_maxfreebud; /* max free buddy system */
+ }; /* - 4096 - */
+-/*
++/*
+ * in-memory aggregate disk allocation map descriptor.
+ */
+ struct bmap {
+diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
+index 6c3f083..ecb2216 100644
+--- a/fs/jfs/jfs_dtree.c
++++ b/fs/jfs/jfs_dtree.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -78,7 +78,7 @@
+ *
+ * case-insensitive search:
+ *
+- * fold search key;
++ * fold search key;
+ *
+ * case-insensitive search of B-tree:
+ * for internal entry, router key is already folded;
+@@ -93,7 +93,7 @@
+ * else
+ * return no match;
+ *
+- * serialization:
++ * serialization:
+ * target directory inode lock is being held on entry/exit
+ * of all main directory service routines.
+ *
+@@ -925,7 +925,7 @@ int dtInsert(tid_t tid, struct inode *ip
+ *
+ * return: 0 - success;
+ * errno - failure;
+- * leaf page unpinned;
++ * leaf page unpinned;
+ */
+ static int dtSplitUp(tid_t tid,
+ struct inode *ip, struct dtsplit * split, struct btstack * btstack)
+@@ -3767,7 +3767,7 @@ static int ciCompare(struct component_na
+ * across page boundary
+ *
+ * return: non-zero on error
+- *
++ *
+ */
+ static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+ int ri, struct component_name * key, int flag)
+@@ -3780,13 +3780,13 @@ static int ciGetLeafPrefixKey(dtpage_t *
+ lkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+ GFP_KERNEL);
+ if (lkey.name == NULL)
+- return -ENOSPC;
++ return -ENOMEM;
+
+ rkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+ GFP_KERNEL);
+ if (rkey.name == NULL) {
+ kfree(lkey.name);
+- return -ENOSPC;
++ return -ENOMEM;
+ }
+
+ /* get left and right key */
+diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
+index 13e4fdf..af8513f 100644
+--- a/fs/jfs/jfs_dtree.h
++++ b/fs/jfs/jfs_dtree.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_DTREE
+@@ -80,7 +80,7 @@ struct idtentry {
+ /*
+ * leaf node entry head/only segment
+ *
+- * For legacy filesystems, name contains 13 wchars -- no index field
++ * For legacy filesystems, name contains 13 wchars -- no index field
+ */
+ struct ldtentry {
+ __le32 inumber; /* 4: 4-byte aligned */
+diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
+index 4d52593..a35bdca 100644
+--- a/fs/jfs/jfs_extent.c
++++ b/fs/jfs/jfs_extent.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -74,7 +74,7 @@ static s64 extRoundDown(s64 nb);
+ * extent that is used as an allocation hint if the
+ * xaddr of the xad is non-zero. on successful exit,
+ * the xad describes the newly allocated extent.
+- * abnr - boolean_t indicating whether the newly allocated extent
++ * abnr - bool indicating whether the newly allocated extent
+ * should be marked as allocated but not recorded.
+ *
+ * RETURN VALUES:
+@@ -83,7 +83,7 @@ static s64 extRoundDown(s64 nb);
+ * -ENOSPC - insufficient disk resources.
+ */
+ int
+-extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
++extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
+ {
+ struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+ s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
+@@ -117,7 +117,7 @@ extAlloc(struct inode *ip, s64 xlen, s64
+ * following the hint extent.
+ */
+ if (offsetXAD(xp) + nxlen == xoff &&
+- abnr == ((xp->flag & XAD_NOTRECORDED) ? TRUE : FALSE))
++ abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false))
+ xaddr = hint + nxlen;
+
+ /* adjust the hint to the last block of the extent */
+@@ -125,7 +125,7 @@ extAlloc(struct inode *ip, s64 xlen, s64
+ }
+
+ /* allocate the disk blocks for the extent. initially, extBalloc()
+- * will try to allocate disk blocks for the requested size (xlen).
++ * will try to allocate disk blocks for the requested size (xlen).
+ * if this fails (xlen contiguous free blocks not avaliable), it'll
+ * try to allocate a smaller number of blocks (producing a smaller
+ * extent), with this smaller number of blocks consisting of the
+@@ -148,9 +148,9 @@ extAlloc(struct inode *ip, s64 xlen, s64
+ }
+
+ /* determine the value of the extent flag */
+- xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0;
++ xflag = abnr ? XAD_NOTRECORDED : 0;
+
+- /* if we can extend the hint extent to cover the current request,
++ /* if we can extend the hint extent to cover the current request,
+ * extend it. otherwise, insert a new extent to
+ * cover the current request.
+ */
+@@ -159,7 +159,7 @@ extAlloc(struct inode *ip, s64 xlen, s64
+ else
+ rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
+
+- /* if the extend or insert failed,
++ /* if the extend or insert failed,
+ * free the newly allocated blocks and return the error.
+ */
+ if (rc) {
+@@ -203,7 +203,7 @@ extAlloc(struct inode *ip, s64 xlen, s64
+ * xlen - request size of the resulting extent.
+ * xp - pointer to an xad. on successful exit, the xad
+ * describes the newly allocated extent.
+- * abnr - boolean_t indicating whether the newly allocated extent
++ * abnr - bool indicating whether the newly allocated extent
+ * should be marked as allocated but not recorded.
+ *
+ * RETURN VALUES:
+@@ -211,7 +211,7 @@ extAlloc(struct inode *ip, s64 xlen, s64
+ * -EIO - i/o error.
+ * -ENOSPC - insufficient disk resources.
+ */
+-int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
++int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
+ {
+ struct super_block *sb = ip->i_sb;
+ s64 xaddr, xlen, nxaddr, delta, xoff;
+@@ -235,7 +235,7 @@ int extRealloc(struct inode *ip, s64 nxl
+ xoff = offsetXAD(xp);
+
+ /* if the extend page is abnr and if the request is for
+- * the extent to be allocated and recorded,
++ * the extent to be allocated and recorded,
+ * make the page allocated and recorded.
+ */
+ if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
+@@ -397,7 +397,7 @@ int extHint(struct inode *ip, s64 offset
+ if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
+ return (rc);
+
+- /* check if not extent exists for the previous page.
++ /* check if not extent exists for the previous page.
+ * this is possible for sparse files.
+ */
+ if (xadl.nxad == 0) {
+@@ -410,7 +410,7 @@ int extHint(struct inode *ip, s64 offset
+ */
+ xp->flag &= XAD_NOTRECORDED;
+
+- if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
++ if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
+ jfs_error(ip->i_sb, "extHint: corrupt xtree");
+ return -EIO;
+ }
+@@ -468,7 +468,7 @@ int extRecord(struct inode *ip, xad_t *
+ int extFill(struct inode *ip, xad_t * xp)
+ {
+ int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
+- s64 blkno = offsetXAD(xp) >> ip->i_blksize;
++ s64 blkno = offsetXAD(xp) >> ip->i_blkbits;
+
+ // assert(ISSPARSE(ip));
+
+@@ -476,7 +476,7 @@ int extFill(struct inode *ip, xad_t * xp
+ XADaddress(xp, 0);
+
+ /* allocate an extent to fill the hole */
+- if ((rc = extAlloc(ip, nbperpage, blkno, xp, FALSE)))
++ if ((rc = extAlloc(ip, nbperpage, blkno, xp, false)))
+ return (rc);
+
+ assert(lengthPXD(xp) == nbperpage);
+@@ -492,7 +492,7 @@ int extFill(struct inode *ip, xad_t * xp
+ * FUNCTION: allocate disk blocks to form an extent.
+ *
+ * initially, we will try to allocate disk blocks for the
+- * requested size (nblocks). if this fails (nblocks
++ * requested size (nblocks). if this fails (nblocks
+ * contiguous free blocks not avaliable), we'll try to allocate
+ * a smaller number of blocks (producing a smaller extent), with
+ * this smaller number of blocks consisting of the requested
+@@ -500,7 +500,7 @@ int extFill(struct inode *ip, xad_t * xp
+ * number (i.e. 16 -> 8). we'll continue to round down and
+ * retry the allocation until the number of blocks to allocate
+ * is smaller than the number of blocks per page.
+- *
++ *
+ * PARAMETERS:
+ * ip - the inode of the file.
+ * hint - disk block number to be used as an allocation hint.
+@@ -509,7 +509,7 @@ int extFill(struct inode *ip, xad_t * xp
+ * exit, this value is set to the number of blocks actually
+ * allocated.
+ * blkno - pointer to a block address that is filled in on successful
+- * return with the starting block number of the newly
++ * return with the starting block number of the newly
+ * allocated block range.
+ *
+ * RETURN VALUES:
+@@ -530,7 +530,7 @@ extBalloc(struct inode *ip, s64 hint, s6
+ /* get the number of blocks to initially attempt to allocate.
+ * we'll first try the number of blocks requested unless this
+ * number is greater than the maximum number of contiguous free
+- * blocks in the map. in that case, we'll start off with the
++ * blocks in the map. in that case, we'll start off with the
+ * maximum free.
+ */
+ max = (s64) 1 << bmp->db_maxfreebud;
+@@ -582,19 +582,19 @@ extBalloc(struct inode *ip, s64 hint, s6
+ *
+ * FUNCTION: attempt to extend an extent's allocation.
+ *
+- * initially, we will try to extend the extent's allocation
+- * in place. if this fails, we'll try to move the extent
+- * to a new set of blocks. if moving the extent, we initially
++ * Initially, we will try to extend the extent's allocation
++ * in place. If this fails, we'll try to move the extent
++ * to a new set of blocks. If moving the extent, we initially
+ * will try to allocate disk blocks for the requested size
+- * (nnew). if this fails (new contiguous free blocks not
+- * avaliable), we'll try to allocate a smaller number of
++ * (newnblks). if this fails (new contiguous free blocks not
++ * avaliable), we'll try to allocate a smaller number of
+ * blocks (producing a smaller extent), with this smaller
+ * number of blocks consisting of the requested number of
+ * blocks rounded down to the next smaller power of 2
+- * number (i.e. 16 -> 8). we'll continue to round down and
++ * number (i.e. 16 -> 8). We'll continue to round down and
+ * retry the allocation until the number of blocks to allocate
+ * is smaller than the number of blocks per page.
+- *
++ *
+ * PARAMETERS:
+ * ip - the inode of the file.
+ * blkno - starting block number of the extents current allocation.
+@@ -625,7 +625,7 @@ extBrealloc(struct inode *ip,
+ return (rc);
+ }
+
+- /* in place extension not possible.
++ /* in place extension not possible.
+ * try to move the extent to a new set of blocks.
+ */
+ return (extBalloc(ip, blkno, newnblks, newblkno));
+diff --git a/fs/jfs/jfs_extent.h b/fs/jfs/jfs_extent.h
+index e80fc7c..b567e12 100644
+--- a/fs/jfs/jfs_extent.h
++++ b/fs/jfs/jfs_extent.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2001
++ * Copyright (C) International Business Machines Corp., 2000-2001
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_EXTENT
+@@ -22,10 +22,10 @@
+ #define INOHINT(ip) \
+ (addressPXD(&(JFS_IP(ip)->ixpxd)) + lengthPXD(&(JFS_IP(ip)->ixpxd)) - 1)
+
+-extern int extAlloc(struct inode *, s64, s64, xad_t *, boolean_t);
++extern int extAlloc(struct inode *, s64, s64, xad_t *, bool);
+ extern int extFill(struct inode *, xad_t *);
+ extern int extHint(struct inode *, s64, xad_t *);
+-extern int extRealloc(struct inode *, s64, xad_t *, boolean_t);
++extern int extRealloc(struct inode *, s64, xad_t *, bool);
+ extern int extRecord(struct inode *, xad_t *);
+
+ #endif /* _H_JFS_EXTENT */
+diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
+index 72a5588..9901928 100644
+--- a/fs/jfs/jfs_filsys.h
++++ b/fs/jfs/jfs_filsys.h
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_FILSYS
+@@ -21,9 +21,9 @@
+ /*
+ * jfs_filsys.h
+ *
+- * file system (implementation-dependent) constants
++ * file system (implementation-dependent) constants
+ *
+- * refer to <limits.h> for system wide implementation-dependent constants
++ * refer to <limits.h> for system wide implementation-dependent constants
+ */
+
+ /*
+@@ -49,7 +49,7 @@
+
+ #define JFS_DFS 0x20000000 /* DCE DFS LFS support */
+
+-#define JFS_LINUX 0x10000000 /* Linux support */
++#define JFS_LINUX 0x10000000 /* Linux support */
+ /* case-sensitive name/directory support */
+
+ /* directory option */
+@@ -59,7 +59,7 @@
+ #define JFS_COMMIT 0x00000f00 /* commit option mask */
+ #define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */
+ #define JFS_LAZYCOMMIT 0x00000200 /* lazy commit */
+-#define JFS_TMPFS 0x00000400 /* temporary file system -
++#define JFS_TMPFS 0x00000400 /* temporary file system -
+ * do not log/commit:
+ */
+
+@@ -196,7 +196,7 @@
+ * followed by 1st extent of map
+ */
+ #define AITBL_OFF (AIMAP_OFF + (SIZE_OF_MAP_PAGE << 1))
+- /*
++ /*
+ * 1st extent of aggregate inode table
+ */
+ #define SUPER2_OFF (AITBL_OFF + INODE_EXTENT_SIZE)
+@@ -270,13 +270,13 @@
+ */
+ #define FM_CLEAN 0x00000000 /* file system is unmounted and clean */
+ #define FM_MOUNT 0x00000001 /* file system is mounted cleanly */
+-#define FM_DIRTY 0x00000002 /* file system was not unmounted and clean
+- * when mounted or
++#define FM_DIRTY 0x00000002 /* file system was not unmounted and clean
++ * when mounted or
+ * commit failure occurred while being mounted:
+- * fsck() must be run to repair
++ * fsck() must be run to repair
+ */
+ #define FM_LOGREDO 0x00000004 /* log based recovery (logredo()) failed:
+- * fsck() must be run to repair
++ * fsck() must be run to repair
+ */
+ #define FM_EXTENDFS 0x00000008 /* file system extendfs() in progress */
+
+diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
+index ccbe60a..ee9b473 100644
+--- a/fs/jfs/jfs_imap.c
++++ b/fs/jfs/jfs_imap.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -78,8 +78,8 @@ static HLIST_HEAD(aggregate_hash);
+ /*
+ * forward references
+ */
+-static int diAllocAG(struct inomap *, int, boolean_t, struct inode *);
+-static int diAllocAny(struct inomap *, int, boolean_t, struct inode *);
++static int diAllocAG(struct inomap *, int, bool, struct inode *);
++static int diAllocAny(struct inomap *, int, bool, struct inode *);
+ static int diAllocBit(struct inomap *, struct iag *, int);
+ static int diAllocExt(struct inomap *, int, struct inode *);
+ static int diAllocIno(struct inomap *, int, struct inode *);
+@@ -98,7 +98,7 @@ static void copy_to_dinode(struct dinode
+ * FUNCTION: initialize the incore inode map control structures for
+ * a fileset or aggregate init time.
+ *
+- * the inode map's control structure (dinomap) is
++ * the inode map's control structure (dinomap) is
+ * brought in from disk and placed in virtual memory.
+ *
+ * PARAMETERS:
+@@ -107,7 +107,7 @@ static void copy_to_dinode(struct dinode
+ * RETURN VALUES:
+ * 0 - success
+ * -ENOMEM - insufficient free virtual memory.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ int diMount(struct inode *ipimap)
+ {
+@@ -191,7 +191,7 @@ int diMount(struct inode *ipimap)
+ * RETURN VALUES:
+ * 0 - success
+ * -ENOMEM - insufficient free virtual memory.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ int diUnmount(struct inode *ipimap, int mounterror)
+ {
+@@ -281,7 +281,7 @@ int diSync(struct inode *ipimap)
+ * on entry, the specifed incore inode should itself
+ * specify the disk inode number corresponding to the
+ * incore inode (i.e. i_number should be initialized).
+- *
++ *
+ * this routine handles incore inode initialization for
+ * both "special" and "regular" inodes. special inodes
+ * are those required early in the mount process and
+@@ -289,7 +289,7 @@ int diSync(struct inode *ipimap)
+ * is not yet initialized. these "special" inodes are
+ * identified by a NULL inode map inode pointer and are
+ * actually initialized by a call to diReadSpecial().
+- *
++ *
+ * for regular inodes, the iag describing the disk inode
+ * is read from disk to determine the inode extent address
+ * for the disk inode. with the inode extent address in
+@@ -302,9 +302,9 @@ int diSync(struct inode *ipimap)
+ *
+ * RETURN VALUES:
+ * 0 - success
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ * -ENOMEM - insufficient memory
+- *
++ *
+ */
+ int diRead(struct inode *ip)
+ {
+@@ -318,7 +318,7 @@ int diRead(struct inode *ip)
+ struct inomap *imap;
+ int block_offset;
+ int inodes_left;
+- uint pageno;
++ unsigned long pageno;
+ int rel_inode;
+
+ jfs_info("diRead: ino = %ld", ip->i_ino);
+@@ -586,14 +586,14 @@ void diFreeSpecial(struct inode *ip)
+ * page of the extent that contains the disk inode is
+ * read and the disk inode portion of the incore inode
+ * is copied to the disk inode.
+- *
++ *
+ * PARAMETERS:
+ * tid - transacation id
+ * ip - pointer to incore inode to be written to the inode extent.
+ *
+ * RETURN VALUES:
+ * 0 - success
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ int diWrite(tid_t tid, struct inode *ip)
+ {
+@@ -606,7 +606,7 @@ int diWrite(tid_t tid, struct inode *ip)
+ int block_offset;
+ int inodes_left;
+ struct metapage *mp;
+- uint pageno;
++ unsigned long pageno;
+ int rel_inode;
+ int dioffset;
+ struct inode *ipimap;
+@@ -676,11 +676,11 @@ int diWrite(tid_t tid, struct inode *ip)
+ * copy btree root from in-memory inode to on-disk inode
+ *
+ * (tlock is taken from inline B+-tree root in in-memory
+- * inode when the B+-tree root is updated, which is pointed
++ * inode when the B+-tree root is updated, which is pointed
+ * by jfs_ip->blid as well as being on tx tlock list)
+ *
+- * further processing of btree root is based on the copy
+- * in in-memory inode, where txLog() will log from, and,
++ * further processing of btree root is based on the copy
++ * in in-memory inode, where txLog() will log from, and,
+ * for xtree root, txUpdateMap() will update map and reset
+ * XAD_NEW bit;
+ */
+@@ -824,7 +824,7 @@ int diWrite(tid_t tid, struct inode *ip)
+ memcpy(&dp->di_DASD, &ip->i_DASD, sizeof(struct dasd));
+ #endif /* _JFS_FASTDASD */
+
+- /* release the buffer holding the updated on-disk inode.
++ /* release the buffer holding the updated on-disk inode.
+ * the buffer will be later written by commit processing.
+ */
+ write_metapage(mp);
+@@ -842,7 +842,7 @@ int diWrite(tid_t tid, struct inode *ip)
+ * if the inode to be freed represents the first (only)
+ * free inode within the iag, the iag will be placed on
+ * the ag free inode list.
+- *
++ *
+ * freeing the inode will cause the inode extent to be
+ * freed if the inode is the only allocated inode within
+ * the extent. in this case all the disk resource backing
+@@ -865,11 +865,11 @@ int diWrite(tid_t tid, struct inode *ip)
+ * any updates and are held until all updates are complete.
+ *
+ * PARAMETERS:
+- * ip - inode to be freed.
++ * ip - inode to be freed.
+ *
+ * RETURN VALUES:
+ * 0 - success
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ int diFree(struct inode *ip)
+ {
+@@ -898,7 +898,7 @@ int diFree(struct inode *ip)
+ */
+ iagno = INOTOIAG(inum);
+
+- /* make sure that the iag is contained within
++ /* make sure that the iag is contained within
+ * the map.
+ */
+ if (iagno >= imap->im_nextiag) {
+@@ -1013,7 +1013,7 @@ int diFree(struct inode *ip)
+
+ /* update the free inode summary map for the extent if
+ * freeing the inode means the extent will now have free
+- * inodes (i.e., the inode being freed is the first free
++ * inodes (i.e., the inode being freed is the first free
+ * inode of extent),
+ */
+ if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
+@@ -1204,9 +1204,9 @@ int diFree(struct inode *ip)
+ iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
+ }
+
+- /* update the inode extent address and working map
++ /* update the inode extent address and working map
+ * to reflect the free extent.
+- * the permanent map should have been updated already
++ * the permanent map should have been updated already
+ * for the inode being freed.
+ */
+ if (iagp->pmap[extno] != 0) {
+@@ -1218,7 +1218,7 @@ int diFree(struct inode *ip)
+
+ /* update the free extent and free inode summary maps
+ * to reflect the freed extent.
+- * the inode summary map is marked to indicate no inodes
++ * the inode summary map is marked to indicate no inodes
+ * available for the freed extent.
+ */
+ sword = extno >> L2EXTSPERSUM;
+@@ -1255,17 +1255,17 @@ int diFree(struct inode *ip)
+ * start transaction to update block allocation map
+ * for the inode extent freed;
+ *
+- * N.B. AG_LOCK is released and iag will be released below, and
++ * N.B. AG_LOCK is released and iag will be released below, and
+ * other thread may allocate inode from/reusing the ixad freed
+- * BUT with new/different backing inode extent from the extent
+- * to be freed by the transaction;
++ * BUT with new/different backing inode extent from the extent
++ * to be freed by the transaction;
+ */
+ tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
+ mutex_lock(&JFS_IP(ipimap)->commit_mutex);
+
+- /* acquire tlock of the iag page of the freed ixad
++ /* acquire tlock of the iag page of the freed ixad
+ * to force the page NOHOMEOK (even though no data is
+- * logged from the iag page) until NOREDOPAGE|FREEXTENT log
++ * logged from the iag page) until NOREDOPAGE|FREEXTENT log
+ * for the free of the extent is committed;
+ * write FREEXTENT|NOREDOPAGE log record
+ * N.B. linelock is overlaid as freed extent descriptor;
+@@ -1284,8 +1284,8 @@ int diFree(struct inode *ip)
+ * logredo needs the IAG number and IAG extent index in order
+ * to ensure that the IMap is consistent. The least disruptive
+ * way to pass these values through to the transaction manager
+- * is in the iplist array.
+- *
++ * is in the iplist array.
++ *
+ * It's not pretty, but it works.
+ */
+ iplist[1] = (struct inode *) (size_t)iagno;
+@@ -1340,20 +1340,20 @@ diInitInode(struct inode *ip, int iagno,
+ /*
+ * NAME: diAlloc(pip,dir,ip)
+ *
+- * FUNCTION: allocate a disk inode from the inode working map
++ * FUNCTION: allocate a disk inode from the inode working map
+ * for a fileset or aggregate.
+ *
+ * PARAMETERS:
+- * pip - pointer to incore inode for the parent inode.
+- * dir - TRUE if the new disk inode is for a directory.
+- * ip - pointer to a new inode
++ * pip - pointer to incore inode for the parent inode.
++ * dir - 'true' if the new disk inode is for a directory.
++ * ip - pointer to a new inode
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+-int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
++int diAlloc(struct inode *pip, bool dir, struct inode *ip)
+ {
+ int rc, ino, iagno, addext, extno, bitno, sword;
+ int nwords, rem, i, agno;
+@@ -1372,10 +1372,10 @@ int diAlloc(struct inode *pip, boolean_t
+ JFS_IP(ip)->ipimap = ipimap;
+ JFS_IP(ip)->fileset = FILESYSTEM_I;
+
+- /* for a directory, the allocation policy is to start
++ /* for a directory, the allocation policy is to start
+ * at the ag level using the preferred ag.
+ */
+- if (dir == TRUE) {
++ if (dir) {
+ agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
+ AG_LOCK(imap, agno);
+ goto tryag;
+@@ -1435,7 +1435,7 @@ int diAlloc(struct inode *pip, boolean_t
+ /*
+ * try to allocate from the IAG
+ */
+- /* check if the inode may be allocated from the iag
++ /* check if the inode may be allocated from the iag
+ * (i.e. the inode has free inodes or new extent can be added).
+ */
+ if (iagp->nfreeinos || addext) {
+@@ -1490,7 +1490,7 @@ int diAlloc(struct inode *pip, boolean_t
+ * hint or, if appropriate (i.e. addext is true), allocate
+ * an extent of free inodes at or following the extent
+ * containing the hint.
+- *
++ *
+ * the free inode and free extent summary maps are used
+ * here, so determine the starting summary map position
+ * and the number of words we'll have to examine. again,
+@@ -1641,7 +1641,7 @@ int diAlloc(struct inode *pip, boolean_t
+ * inodes should be added for the allocation group, with
+ * the current request satisfied from this extent. if this
+ * is the case, an attempt will be made to do just that. if
+- * this attempt fails or it has been determined that a new
++ * this attempt fails or it has been determined that a new
+ * extent should not be added, an attempt is made to satisfy
+ * the request by allocating an existing (backed) free inode
+ * from the allocation group.
+@@ -1649,24 +1649,24 @@ int diAlloc(struct inode *pip, boolean_t
+ * PRE CONDITION: Already have the AG lock for this AG.
+ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * agno - allocation group to allocate from.
+- * dir - TRUE if the new disk inode is for a directory.
+- * ip - pointer to the new inode to be filled in on successful return
++ * imap - pointer to inode map control structure.
++ * agno - allocation group to allocate from.
++ * dir - 'true' if the new disk inode is for a directory.
++ * ip - pointer to the new inode to be filled in on successful return
+ * with the disk inode number allocated, its extent address
+ * and the start of the ag.
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int
+-diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
++diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
+ {
+ int rc, addext, numfree, numinos;
+
+- /* get the number of free and the number of backed disk
++ /* get the number of free and the number of backed disk
+ * inodes currently within the ag.
+ */
+ numfree = imap->im_agctl[agno].numfree;
+@@ -1682,7 +1682,7 @@ diAllocAG(struct inomap * imap, int agno
+ * if there are a small number of free inodes or number of free
+ * inodes is a small percentage of the number of backed inodes.
+ */
+- if (dir == TRUE)
++ if (dir)
+ addext = (numfree < 64 ||
+ (numfree < 256
+ && ((numfree * 100) / numinos) <= 20));
+@@ -1719,26 +1719,26 @@ diAllocAG(struct inomap * imap, int agno
+ * specified primary group.
+ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * agno - primary allocation group (to avoid).
+- * dir - TRUE if the new disk inode is for a directory.
+- * ip - pointer to a new inode to be filled in on successful return
++ * imap - pointer to inode map control structure.
++ * agno - primary allocation group (to avoid).
++ * dir - 'true' if the new disk inode is for a directory.
++ * ip - pointer to a new inode to be filled in on successful return
+ * with the disk inode number allocated, its extent address
+ * and the start of the ag.
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int
+-diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
++diAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip)
+ {
+ int ag, rc;
+ int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag;
+
+
+- /* try to allocate from the ags following agno up to
++ /* try to allocate from the ags following agno up to
+ * the maximum ag number.
+ */
+ for (ag = agno + 1; ag <= maxag; ag++) {
+@@ -1780,21 +1780,21 @@ diAllocAny(struct inomap * imap, int agn
+ *
+ * allocation occurs from the first iag on the list using
+ * the iag's free inode summary map to find the leftmost
+- * free inode in the iag.
+- *
++ * free inode in the iag.
++ *
+ * PRE CONDITION: Already have AG lock for this AG.
+- *
++ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * agno - allocation group.
+- * ip - pointer to new inode to be filled in on successful return
++ * imap - pointer to inode map control structure.
++ * agno - allocation group.
++ * ip - pointer to new inode to be filled in on successful return
+ * with the disk inode number allocated, its extent address
+ * and the start of the ag.
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
+ {
+@@ -1867,7 +1867,7 @@ static int diAllocIno(struct inomap * im
+ return -EIO;
+ }
+
+- /* compute the inode number within the iag.
++ /* compute the inode number within the iag.
+ */
+ ino = (extno << L2INOSPEREXT) + rem;
+
+@@ -1892,17 +1892,17 @@ static int diAllocIno(struct inomap * im
+ /*
+ * NAME: diAllocExt(imap,agno,ip)
+ *
+- * FUNCTION: add a new extent of free inodes to an iag, allocating
+- * an inode from this extent to satisfy the current allocation
+- * request.
+- *
++ * FUNCTION: add a new extent of free inodes to an iag, allocating
++ * an inode from this extent to satisfy the current allocation
++ * request.
++ *
+ * this routine first tries to find an existing iag with free
+ * extents through the ag free extent list. if list is not
+ * empty, the head of the list will be selected as the home
+ * of the new extent of free inodes. otherwise (the list is
+ * empty), a new iag will be allocated for the ag to contain
+ * the extent.
+- *
++ *
+ * once an iag has been selected, the free extent summary map
+ * is used to locate a free extent within the iag and diNewExt()
+ * is called to initialize the extent, with initialization
+@@ -1910,16 +1910,16 @@ static int diAllocIno(struct inomap * im
+ * for the purpose of satisfying this request.
+ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * agno - allocation group number.
+- * ip - pointer to new inode to be filled in on successful return
++ * imap - pointer to inode map control structure.
++ * agno - allocation group number.
++ * ip - pointer to new inode to be filled in on successful return
+ * with the disk inode number allocated, its extent address
+ * and the start of the ag.
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
+ {
+@@ -2012,7 +2012,7 @@ static int diAllocExt(struct inomap * im
+ /*
+ * NAME: diAllocBit(imap,iagp,ino)
+ *
+- * FUNCTION: allocate a backed inode from an iag.
++ * FUNCTION: allocate a backed inode from an iag.
+ *
+ * this routine performs the mechanics of allocating a
+ * specified inode from a backed extent.
+@@ -2025,19 +2025,19 @@ static int diAllocExt(struct inomap * im
+ * in the face of updates to multiple buffers. under this
+ * approach, all required buffers are obtained before making
+ * any updates and are held all are updates are complete.
+- *
++ *
+ * PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on
+ * this AG. Must have read lock on imap inode.
+ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * iagp - pointer to iag.
+- * ino - inode number to be allocated within the iag.
++ * imap - pointer to inode map control structure.
++ * iagp - pointer to iag.
++ * ino - inode number to be allocated within the iag.
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
+ {
+@@ -2172,19 +2172,19 @@ static int diAllocBit(struct inomap * im
+ * buffers. under this approach, all required buffers are
+ * obtained before making any updates and are held until all
+ * updates are complete.
+- *
++ *
+ * PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on
+ * this AG. Must have read lock on imap inode.
+ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * iagp - pointer to iag.
+- * extno - extent number.
++ * imap - pointer to inode map control structure.
++ * iagp - pointer to iag.
++ * extno - extent number.
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
+ {
+@@ -2432,34 +2432,34 @@ static int diNewExt(struct inomap * imap
+ /*
+ * NAME: diNewIAG(imap,iagnop,agno)
+ *
+- * FUNCTION: allocate a new iag for an allocation group.
+- *
+- * first tries to allocate the iag from the inode map
+- * iagfree list:
+- * if the list has free iags, the head of the list is removed
++ * FUNCTION: allocate a new iag for an allocation group.
++ *
++ * first tries to allocate the iag from the inode map
++ * iagfree list:
++ * if the list has free iags, the head of the list is removed
+ * and returned to satisfy the request.
+ * if the inode map's iag free list is empty, the inode map
+ * is extended to hold a new iag. this new iag is initialized
+ * and returned to satisfy the request.
+ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * iagnop - pointer to an iag number set with the number of the
++ * imap - pointer to inode map control structure.
++ * iagnop - pointer to an iag number set with the number of the
+ * newly allocated iag upon successful return.
+- * agno - allocation group number.
++ * agno - allocation group number.
+ * bpp - Buffer pointer to be filled in with new IAG's buffer
+ *
+ * RETURN VALUES:
+ * 0 - success.
+ * -ENOSPC - insufficient disk resources.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ *
+- * serialization:
++ * serialization:
+ * AG lock held on entry/exit;
+ * write lock on the map is held inside;
+ * read lock on the map is held on successful completion;
+ *
+- * note: new iag transaction:
++ * note: new iag transaction:
+ * . synchronously write iag;
+ * . write log of xtree and inode of imap;
+ * . commit;
+@@ -2494,7 +2494,7 @@ diNewIAG(struct inomap * imap, int *iagn
+ /* acquire the free iag lock */
+ IAGFREE_LOCK(imap);
+
+- /* if there are any iags on the inode map free iag list,
++ /* if there are any iags on the inode map free iag list,
+ * allocate the iag from the head of the list.
+ */
+ if (imap->im_freeiag >= 0) {
+@@ -2618,8 +2618,8 @@ diNewIAG(struct inomap * imap, int *iagn
+ flush_metapage(mp);
+
+ /*
+- * txCommit(COMMIT_FORCE) will synchronously write address
+- * index pages and inode after commit in careful update order
++ * txCommit(COMMIT_FORCE) will synchronously write address
++ * index pages and inode after commit in careful update order
+ * of address index pages (right to left, bottom up);
+ */
+ iplist[0] = ipimap;
+@@ -2678,11 +2678,11 @@ diNewIAG(struct inomap * imap, int *iagn
+ *
+ * FUNCTION: get the buffer for the specified iag within a fileset
+ * or aggregate inode map.
+- *
++ *
+ * PARAMETERS:
+- * imap - pointer to inode map control structure.
+- * iagno - iag number.
+- * bpp - point to buffer pointer to be filled in on successful
++ * imap - pointer to inode map control structure.
++ * iagno - iag number.
++ * bpp - point to buffer pointer to be filled in on successful
+ * exit.
+ *
+ * SERIALIZATION:
+@@ -2692,7 +2692,7 @@ diNewIAG(struct inomap * imap, int *iagn
+ *
+ * RETURN VALUES:
+ * 0 - success.
+- * -EIO - i/o error.
++ * -EIO - i/o error.
+ */
+ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
+ {
+@@ -2718,8 +2718,8 @@ static int diIAGRead(struct inomap * ima
+ * the specified bit position.
+ *
+ * PARAMETERS:
+- * word - word to be examined.
+- * start - starting bit position.
++ * word - word to be examined.
++ * start - starting bit position.
+ *
+ * RETURN VALUES:
+ * bit position of first free bit in the word or 32 if
+@@ -2740,24 +2740,24 @@ static int diFindFree(u32 word, int star
+
+ /*
+ * NAME: diUpdatePMap()
+- *
+- * FUNCTION: Update the persistent map in an IAG for the allocation or
++ *
++ * FUNCTION: Update the persistent map in an IAG for the allocation or
+ * freeing of the specified inode.
+- *
++ *
+ * PRE CONDITIONS: Working map has already been updated for allocate.
+ *
+ * PARAMETERS:
+ * ipimap - Incore inode map inode
+ * inum - Number of inode to mark in permanent map
+- * is_free - If TRUE indicates inode should be marked freed, otherwise
++ * is_free - If 'true' indicates inode should be marked freed, otherwise
+ * indicates inode should be marked allocated.
+ *
+- * RETURN VALUES:
++ * RETURN VALUES:
+ * 0 for success
+ */
+ int
+ diUpdatePMap(struct inode *ipimap,
+- unsigned long inum, boolean_t is_free, struct tblock * tblk)
++ unsigned long inum, bool is_free, struct tblock * tblk)
+ {
+ int rc;
+ struct iag *iagp;
+@@ -2793,17 +2793,17 @@ diUpdatePMap(struct inode *ipimap,
+ extno = ino >> L2INOSPEREXT;
+ bitno = ino & (INOSPEREXT - 1);
+ mask = HIGHORDER >> bitno;
+- /*
++ /*
+ * mark the inode free in persistent map:
+ */
+- if (is_free == TRUE) {
++ if (is_free) {
+ /* The inode should have been allocated both in working
+ * map and in persistent map;
+ * the inode will be freed from working map at the release
+ * of last reference release;
+ */
+ if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
+- jfs_error(ipimap->i_sb,
++ jfs_error(ipimap->i_sb,
+ "diUpdatePMap: inode %ld not marked as "
+ "allocated in wmap!", inum);
+ }
+@@ -2877,8 +2877,8 @@ diUpdatePMap(struct inode *ipimap,
+ * diExtendFS()
+ *
+ * function: update imap for extendfs();
+- *
+- * note: AG size has been increased s.t. each k old contiguous AGs are
++ *
++ * note: AG size has been increased s.t. each k old contiguous AGs are
+ * coalesced into a new AG;
+ */
+ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
+@@ -2897,7 +2897,7 @@ int diExtendFS(struct inode *ipimap, str
+ atomic_read(&imap->im_numfree));
+
+ /*
+- * reconstruct imap
++ * reconstruct imap
+ *
+ * coalesce contiguous k (newAGSize/oldAGSize) AGs;
+ * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
+@@ -2931,7 +2931,7 @@ int diExtendFS(struct inode *ipimap, str
+ }
+
+ /* leave free iag in the free iag list */
+- if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
++ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+ release_metapage(bp);
+ continue;
+ }
+@@ -3115,7 +3115,6 @@ static int copy_from_dinode(struct dinod
+ ip->i_mtime.tv_nsec = le32_to_cpu(dip->di_mtime.tv_nsec);
+ ip->i_ctime.tv_sec = le32_to_cpu(dip->di_ctime.tv_sec);
+ ip->i_ctime.tv_nsec = le32_to_cpu(dip->di_ctime.tv_nsec);
+- ip->i_blksize = ip->i_sb->s_blocksize;
+ ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks));
+ ip->i_generation = le32_to_cpu(dip->di_gen);
+
+diff --git a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h
+index 6e24465..4f9c346 100644
+--- a/fs/jfs/jfs_imap.h
++++ b/fs/jfs/jfs_imap.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_IMAP
+@@ -45,13 +45,13 @@
+ /* get the starting block number of the 4K page of an inode extent
+ * that contains ino.
+ */
+-#define INOPBLK(pxd,ino,l2nbperpg) (addressPXD((pxd)) + \
++#define INOPBLK(pxd,ino,l2nbperpg) (addressPXD((pxd)) + \
+ ((((ino) & (INOSPEREXT-1)) >> L2INOSPERPAGE) << (l2nbperpg)))
+
+ /*
+ * inode allocation map:
+- *
+- * inode allocation map consists of
++ *
++ * inode allocation map consists of
+ * . the inode map control page and
+ * . inode allocation group pages (per 4096 inodes)
+ * which are addressed by standard JFS xtree.
+@@ -159,11 +159,11 @@ struct inomap {
+ #define im_maxag im_imap.in_maxag
+
+ extern int diFree(struct inode *);
+-extern int diAlloc(struct inode *, boolean_t, struct inode *);
++extern int diAlloc(struct inode *, bool, struct inode *);
+ extern int diSync(struct inode *);
+ /* external references */
+ extern int diUpdatePMap(struct inode *ipimap, unsigned long inum,
+- boolean_t is_free, struct tblock * tblk);
++ bool is_free, struct tblock * tblk);
+ extern int diExtendFS(struct inode *ipimap, struct inode *ipbmap);
+ extern int diMount(struct inode *);
+ extern int diUnmount(struct inode *, int);
+diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
+index 54d7371..9400558 100644
+--- a/fs/jfs/jfs_incore.h
++++ b/fs/jfs/jfs_incore.h
+@@ -4,18 +4,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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- */
++ */
+ #ifndef _H_JFS_INCORE
+ #define _H_JFS_INCORE
+
+diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
+index 495df40..4c67ed9 100644
+--- a/fs/jfs/jfs_inode.c
++++ b/fs/jfs/jfs_inode.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -61,7 +61,7 @@ struct inode *ialloc(struct inode *paren
+ inode = new_inode(sb);
+ if (!inode) {
+ jfs_warn("ialloc: new_inode returned NULL!");
+- return inode;
++ return ERR_PTR(-ENOMEM);
+ }
+
+ jfs_inode = JFS_IP(inode);
+@@ -69,9 +69,10 @@ struct inode *ialloc(struct inode *paren
+ rc = diAlloc(parent, S_ISDIR(mode), inode);
+ if (rc) {
+ jfs_warn("ialloc: diAlloc returned %d!", rc);
+- make_bad_inode(inode);
++ if (rc == -EIO)
++ make_bad_inode(inode);
+ iput(inode);
+- return NULL;
++ return ERR_PTR(rc);
+ }
+
+ inode->i_uid = current->fsuid;
+@@ -97,7 +98,7 @@ struct inode *ialloc(struct inode *paren
+ inode->i_flags |= S_NOQUOTA;
+ inode->i_nlink = 0;
+ iput(inode);
+- return NULL;
++ return ERR_PTR(-EDQUOT);
+ }
+
+ inode->i_mode = mode;
+@@ -115,7 +116,6 @@ struct inode *ialloc(struct inode *paren
+ }
+ jfs_inode->mode2 |= mode;
+
+- inode->i_blksize = sb->s_blocksize;
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ jfs_inode->otime = inode->i_ctime.tv_sec;
+diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
+index 1fc48df..0d06ccf 100644
+--- a/fs/jfs/jfs_inode.h
++++ b/fs/jfs/jfs_inode.h
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_INODE
+diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
+index 70ac9f7..7d78e83 100644
+--- a/fs/jfs/jfs_lock.h
++++ b/fs/jfs/jfs_lock.h
+@@ -1,19 +1,19 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2001
+- * Portions Copyright (c) Christoph Hellwig, 2001-2002
++ * Copyright (C) International Business Machines Corp., 2000-2001
++ * Portions Copyright (C) Christoph Hellwig, 2001-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_LOCK
+diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
+index 3315f0b..b89c9ab 100644
+--- a/fs/jfs/jfs_logmgr.c
++++ b/fs/jfs/jfs_logmgr.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -337,7 +337,7 @@ int lmLog(struct jfs_log * log, struct t
+ * PARAMETER: cd - commit descriptor
+ *
+ * RETURN: end-of-log address
+- *
++ *
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+ static int
+@@ -554,7 +554,7 @@ lmWriteRecord(struct jfs_log * log, stru
+ * PARAMETER: log
+ *
+ * RETURN: 0
+- *
++ *
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+ static int lmNextPage(struct jfs_log * log)
+@@ -656,7 +656,7 @@ static int lmNextPage(struct jfs_log * l
+ * page number - redrive pageout of the page at the head of
+ * pageout queue until full page has been written.
+ *
+- * RETURN:
++ * RETURN:
+ *
+ * NOTE:
+ * LOGGC_LOCK serializes log group commit queue, and
+@@ -920,10 +920,10 @@ static void lmPostGC(struct lbuf * bp)
+ * this code is called again.
+ *
+ * PARAMETERS: log - log structure
+- * hard_sync - 1 to force all metadata to be written
++ * hard_sync - 1 to force all metadata to be written
+ *
+ * RETURN: 0
+- *
++ *
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+ static int lmLogSync(struct jfs_log * log, int hard_sync)
+@@ -1052,7 +1052,7 @@ static int lmLogSync(struct jfs_log * lo
+ * FUNCTION: write log SYNCPT record for specified log
+ *
+ * PARAMETERS: log - log structure
+- * hard_sync - set to 1 to force metadata to be written
++ * hard_sync - set to 1 to force metadata to be written
+ */
+ void jfs_syncpt(struct jfs_log *log, int hard_sync)
+ { LOG_LOCK(log);
+@@ -1067,7 +1067,7 @@ void jfs_syncpt(struct jfs_log *log, int
+ * insert filesystem in the active list of the log.
+ *
+ * PARAMETER: ipmnt - file system mount inode
+- * iplog - log inode (out)
++ * iplog - log inode (out)
+ *
+ * RETURN:
+ *
+@@ -1082,7 +1082,7 @@ int lmLogOpen(struct super_block *sb)
+
+ if (sbi->flag & JFS_NOINTEGRITY)
+ return open_dummy_log(sb);
+-
++
+ if (sbi->mntflag & JFS_INLINELOG)
+ return open_inline_log(sb);
+
+@@ -1131,7 +1131,7 @@ int lmLogOpen(struct super_block *sb)
+
+ log->bdev = bdev;
+ memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid));
+-
++
+ /*
+ * initialize log:
+ */
+@@ -1253,13 +1253,13 @@ static int open_dummy_log(struct super_b
+ * initialize the log from log superblock.
+ * set the log state in the superblock to LOGMOUNT and
+ * write SYNCPT log record.
+- *
++ *
+ * PARAMETER: log - log structure
+ *
+ * RETURN: 0 - if ok
+ * -EINVAL - bad log magic number or superblock dirty
+ * error returned from logwait()
+- *
++ *
+ * serialization: single first open thread
+ */
+ int lmLogInit(struct jfs_log * log)
+@@ -1297,7 +1297,7 @@ int lmLogInit(struct jfs_log * log)
+
+ if (!test_bit(log_INLINELOG, &log->flag))
+ log->l2bsize = L2LOGPSIZE;
+-
++
+ /* check for disabled journaling to disk */
+ if (log->no_integrity) {
+ /*
+@@ -1651,7 +1651,7 @@ void jfs_flush_journal(struct jfs_log *l
+ * PARAMETER: log - log inode
+ *
+ * RETURN: 0 - success
+- *
++ *
+ * serialization: single last close thread
+ */
+ int lmLogShutdown(struct jfs_log * log)
+@@ -1677,7 +1677,7 @@ int lmLogShutdown(struct jfs_log * log)
+ lrd.type = cpu_to_le16(LOG_SYNCPT);
+ lrd.length = 0;
+ lrd.log.syncpt.sync = 0;
+-
++
+ lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+ bp = log->bp;
+ lp = (struct logpage *) bp->l_ldata;
+@@ -1703,7 +1703,7 @@ int lmLogShutdown(struct jfs_log * log)
+ jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
+ lsn, log->page, log->eor);
+
+- out:
++ out:
+ /*
+ * shutdown per log i/o
+ */
+@@ -1769,7 +1769,7 @@ static int lmLogFileSystem(struct jfs_lo
+ lbmFree(bpsuper);
+ return -EIO;
+ }
+-
++
+ }
+
+ /*
+diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
+index 8c6909b..a53fb17 100644
+--- a/fs/jfs/jfs_logmgr.h
++++ b/fs/jfs/jfs_logmgr.h
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_LOGMGR
+@@ -35,19 +35,19 @@
+ /*
+ * log logical volume
+ *
+- * a log is used to make the commit operation on journalled
++ * a log is used to make the commit operation on journalled
+ * files within the same logical volume group atomic.
+ * a log is implemented with a logical volume.
+- * there is one log per logical volume group.
++ * there is one log per logical volume group.
+ *
+ * block 0 of the log logical volume is not used (ipl etc).
+ * block 1 contains a log "superblock" and is used by logFormat(),
+- * lmLogInit(), lmLogShutdown(), and logRedo() to record status
+- * of the log but is not otherwise used during normal processing.
++ * lmLogInit(), lmLogShutdown(), and logRedo() to record status
++ * of the log but is not otherwise used during normal processing.
+ * blocks 2 - (N-1) are used to contain log records.
+ *
+- * when a volume group is varied-on-line, logRedo() must have
+- * been executed before the file systems (logical volumes) in
++ * when a volume group is varied-on-line, logRedo() must have
++ * been executed before the file systems (logical volumes) in
+ * the volume group can be mounted.
+ */
+ /*
+@@ -97,26 +97,26 @@ struct logsuper {
+ * log logical page
+ *
+ * (this comment should be rewritten !)
+- * the header and trailer structures (h,t) will normally have
++ * the header and trailer structures (h,t) will normally have
+ * the same page and eor value.
+- * An exception to this occurs when a complete page write is not
++ * An exception to this occurs when a complete page write is not
+ * accomplished on a power failure. Since the hardware may "split write"
+- * sectors in the page, any out of order sequence may occur during powerfail
++ * sectors in the page, any out of order sequence may occur during powerfail
+ * and needs to be recognized during log replay. The xor value is
+ * an "exclusive or" of all log words in the page up to eor. This
+ * 32 bit eor is stored with the top 16 bits in the header and the
+ * bottom 16 bits in the trailer. logredo can easily recognize pages
+- * that were not completed by reconstructing this eor and checking
++ * that were not completed by reconstructing this eor and checking
+ * the log page.
+ *
+- * Previous versions of the operating system did not allow split
+- * writes and detected partially written records in logredo by
+- * ordering the updates to the header, trailer, and the move of data
+- * into the logdata area. The order: (1) data is moved (2) header
+- * is updated (3) trailer is updated. In logredo, when the header
+- * differed from the trailer, the header and trailer were reconciled
+- * as follows: if h.page != t.page they were set to the smaller of
+- * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only)
++ * Previous versions of the operating system did not allow split
++ * writes and detected partially written records in logredo by
++ * ordering the updates to the header, trailer, and the move of data
++ * into the logdata area. The order: (1) data is moved (2) header
++ * is updated (3) trailer is updated. In logredo, when the header
++ * differed from the trailer, the header and trailer were reconciled
++ * as follows: if h.page != t.page they were set to the smaller of
++ * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only)
+ * h.eor != t.eor they were set to the smaller of their two values.
+ */
+ struct logpage {
+@@ -147,20 +147,20 @@ struct logpage {
+ * in a page, pages are written to temporary paging space if
+ * if they must be written to disk before commit, and i/o is
+ * scheduled for modified pages to their home location after
+- * the log records containing the after values and the commit
++ * the log records containing the after values and the commit
+ * record is written to the log on disk, undo discards the copy
+ * in main-memory.)
+ *
+- * a log record consists of a data area of variable length followed by
++ * a log record consists of a data area of variable length followed by
+ * a descriptor of fixed size LOGRDSIZE bytes.
+- * the data area is rounded up to an integral number of 4-bytes and
++ * the data area is rounded up to an integral number of 4-bytes and
+ * must be no longer than LOGPSIZE.
+- * the descriptor is of size of multiple of 4-bytes and aligned on a
+- * 4-byte boundary.
++ * the descriptor is of size of multiple of 4-bytes and aligned on a
++ * 4-byte boundary.
+ * records are packed one after the other in the data area of log pages.
+- * (sometimes a DUMMY record is inserted so that at least one record ends
++ * (sometimes a DUMMY record is inserted so that at least one record ends
+ * on every page or the longest record is placed on at most two pages).
+- * the field eor in page header/trailer points to the byte following
++ * the field eor in page header/trailer points to the byte following
+ * the last record on a page.
+ */
+
+@@ -270,11 +270,11 @@ struct lrd {
+ /*
+ * NOREDOINOEXT: the inode extent is freed
+ *
+- * do not apply after-image records which precede this
+- * record in the log with the any of the 4 page block
+- * numbers in this inode extent.
+- *
+- * NOTE: The fileset and pxd fields MUST remain in
++ * do not apply after-image records which precede this
++ * record in the log with the any of the 4 page block
++ * numbers in this inode extent.
++ *
++ * NOTE: The fileset and pxd fields MUST remain in
+ * the same fields in the REDOPAGE record format.
+ *
+ */
+@@ -319,12 +319,10 @@ struct lrd {
+ * do not apply records which precede this record in the log
+ * with the same inode number.
+ *
+- * NOREDILE must be the first to be written at commit
++ * NOREDOFILE must be the first to be written at commit
+ * (last to be read in logredo()) - it prevents
+ * replay of preceding updates of all preceding generations
+- * of the inumber esp. the on-disk inode itself,
+- * but does NOT prevent
+- * replay of the
++ * of the inumber esp. the on-disk inode itself.
+ */
+ struct {
+ __le32 fileset; /* 4: fileset number */
+@@ -332,7 +330,7 @@ struct lrd {
+ } noredofile;
+
+ /*
+- * ? NEWPAGE:
++ * ? NEWPAGE:
+ *
+ * metadata type dependent
+ */
+@@ -464,7 +462,7 @@ struct lbuf {
+ s64 l_blkno; /* 8: log page block number */
+ caddr_t l_ldata; /* 4: data page */
+ struct page *l_page; /* The page itself */
+- uint l_offset; /* Offset of l_ldata within the page */
++ uint l_offset; /* Offset of l_ldata within the page */
+
+ wait_queue_head_t l_ioevent; /* 4: i/o done event */
+ };
+diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
+index e1e0a6e..0cccd1c 100644
+--- a/fs/jfs/jfs_metapage.c
++++ b/fs/jfs/jfs_metapage.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -257,7 +257,7 @@ static sector_t metapage_get_blocks(stru
+ int rc = 0;
+ int xflag;
+ s64 xaddr;
+- sector_t file_blocks = (inode->i_size + inode->i_blksize - 1) >>
++ sector_t file_blocks = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+ inode->i_blkbits;
+
+ if (lblock >= file_blocks)
+@@ -461,7 +461,7 @@ static int metapage_writepage(struct pag
+ goto add_failed;
+ if (!bio->bi_size)
+ goto dump_bio;
+-
++
+ submit_bio(WRITE, bio);
+ }
+ if (redirty)
+@@ -648,7 +648,7 @@ struct metapage *__get_metapage(struct i
+ jfs_err("logical_size = %d, size = %d",
+ mp->logical_size, size);
+ dump_stack();
+- goto unlock;
++ goto unlock;
+ }
+ mp->count++;
+ lock_metapage(mp);
+@@ -658,7 +658,7 @@ struct metapage *__get_metapage(struct i
+ "__get_metapage: using a "
+ "discarded metapage");
+ discard_metapage(mp);
+- goto unlock;
++ goto unlock;
+ }
+ clear_bit(META_discard, &mp->flag);
+ }
+diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
+index d17a329..d94f8d9 100644
+--- a/fs/jfs/jfs_metapage.h
++++ b/fs/jfs/jfs_metapage.h
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_METAPAGE
+@@ -33,7 +33,7 @@ struct metapage {
+ unsigned long flag; /* See Below */
+ unsigned long count; /* Reference count */
+ void *data; /* Data pointer */
+- sector_t index; /* block address of page */
++ sector_t index; /* block address of page */
+ wait_queue_head_t wait;
+
+ /* implementation */
+@@ -65,10 +65,10 @@ extern struct metapage *__get_metapage(s
+ int absolute, unsigned long new);
+
+ #define read_metapage(inode, lblock, size, absolute)\
+- __get_metapage(inode, lblock, size, absolute, FALSE)
++ __get_metapage(inode, lblock, size, absolute, false)
+
+ #define get_metapage(inode, lblock, size, absolute)\
+- __get_metapage(inode, lblock, size, absolute, TRUE)
++ __get_metapage(inode, lblock, size, absolute, true)
+
+ extern void release_metapage(struct metapage *);
+ extern void grab_metapage(struct metapage *);
+diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
+index 032d111..4dd4798 100644
+--- a/fs/jfs/jfs_mount.c
++++ b/fs/jfs/jfs_mount.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -21,18 +21,18 @@
+ *
+ * note: file system in transition to aggregate/fileset:
+ *
+- * file system mount is interpreted as the mount of aggregate,
+- * if not already mounted, and mount of the single/only fileset in
++ * file system mount is interpreted as the mount of aggregate,
++ * if not already mounted, and mount of the single/only fileset in
+ * the aggregate;
+ *
+ * a file system/aggregate is represented by an internal inode
+ * (aka mount inode) initialized with aggregate superblock;
+- * each vfs represents a fileset, and points to its "fileset inode
++ * each vfs represents a fileset, and points to its "fileset inode
+ * allocation map inode" (aka fileset inode):
+- * (an aggregate itself is structured recursively as a filset:
+- * an internal vfs is constructed and points to its "fileset inode
+- * allocation map inode" (aka aggregate inode) where each inode
+- * represents a fileset inode) so that inode number is mapped to
++ * (an aggregate itself is structured recursively as a filset:
++ * an internal vfs is constructed and points to its "fileset inode
++ * allocation map inode" (aka aggregate inode) where each inode
++ * represents a fileset inode) so that inode number is mapped to
+ * on-disk inode in uniform way at both aggregate and fileset level;
+ *
+ * each vnode/inode of a fileset is linked to its vfs (to facilitate
+@@ -41,7 +41,7 @@
+ * per aggregate information, e.g., block size, etc.) as well as
+ * its file set inode.
+ *
+- * aggregate
++ * aggregate
+ * ipmnt
+ * mntvfs -> fileset ipimap+ -> aggregate ipbmap -> aggregate ipaimap;
+ * fileset vfs -> vp(1) <-> ... <-> vp(n) <->vproot;
+@@ -88,7 +88,7 @@ int jfs_mount(struct super_block *sb)
+ struct inode *ipbmap = NULL;
+
+ /*
+- * read/validate superblock
++ * read/validate superblock
+ * (initialize mount inode from the superblock)
+ */
+ if ((rc = chkSuper(sb))) {
+@@ -238,7 +238,7 @@ int jfs_mount(struct super_block *sb)
+ */
+ int jfs_mount_rw(struct super_block *sb, int remount)
+ {
+- struct jfs_sb_info *sbi = JFS_SBI(sb);
++ struct jfs_sb_info *sbi = JFS_SBI(sb);
+ int rc;
+
+ /*
+@@ -291,7 +291,7 @@ int jfs_mount_rw(struct super_block *sb,
+ /*
+ * chkSuper()
+ *
+- * validate the superblock of the file system to be mounted and
++ * validate the superblock of the file system to be mounted and
+ * get the file system parameters.
+ *
+ * returns
+@@ -426,7 +426,7 @@ int updateSuper(struct super_block *sb,
+ jfs_err("updateSuper: bad state");
+ } else if (sbi->state == FM_DIRTY)
+ return 0;
+-
++
+ if ((rc = readSuper(sb, &bh)))
+ return rc;
+
+@@ -486,9 +486,9 @@ int readSuper(struct super_block *sb, st
+ * for this file system past this point in log.
+ * it is harmless if mount fails.
+ *
+- * note: MOUNT record is at aggregate level, not at fileset level,
++ * note: MOUNT record is at aggregate level, not at fileset level,
+ * since log records of previous mounts of a fileset
+- * (e.g., AFTER record of extent allocation) have to be processed
++ * (e.g., AFTER record of extent allocation) have to be processed
+ * to update block allocation map at aggregate level.
+ */
+ static int logMOUNT(struct super_block *sb)
+diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h
+index 682cf1a..884fc21 100644
+--- a/fs/jfs/jfs_superblock.h
++++ b/fs/jfs/jfs_superblock.h
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_SUPERBLOCK
+@@ -21,14 +21,14 @@
+ /*
+ * make the magic number something a human could read
+ */
+-#define JFS_MAGIC "JFS1" /* Magic word */
++#define JFS_MAGIC "JFS1" /* Magic word */
+
+ #define JFS_VERSION 2 /* Version number: Version 2 */
+
+ #define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */
+
+-/*
+- * aggregate superblock
++/*
++ * aggregate superblock
+ *
+ * The name superblock is too close to super_block, so the name has been
+ * changed to jfs_superblock. The utilities are still using the old name.
+@@ -40,7 +40,7 @@ struct jfs_superblock {
+ __le64 s_size; /* 8: aggregate size in hardware/LVM blocks;
+ * VFS: number of blocks
+ */
+- __le32 s_bsize; /* 4: aggregate block size in bytes;
++ __le32 s_bsize; /* 4: aggregate block size in bytes;
+ * VFS: fragment size
+ */
+ __le16 s_l2bsize; /* 2: log2 of s_bsize */
+@@ -54,7 +54,7 @@ struct jfs_superblock {
+ __le32 s_flag; /* 4: aggregate attributes:
+ * see jfs_filsys.h
+ */
+- __le32 s_state; /* 4: mount/unmount/recovery state:
++ __le32 s_state; /* 4: mount/unmount/recovery state:
+ * see jfs_filsys.h
+ */
+ __le32 s_compress; /* 4: > 0 if data compression */
+@@ -75,11 +75,11 @@ struct jfs_superblock {
+ struct timestruc_t s_time; /* 8: time last updated */
+
+ __le32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for
+- * the fsck service log.
++ * the fsck service log.
+ * N.B. These blocks are divided among the
+ * versions kept. This is not a per
+ * version size.
+- * N.B. These blocks are included in the
++ * N.B. These blocks are included in the
+ * length field of s_fsckpxd.
+ */
+ s8 s_fscklog; /* 1: which fsck service log is most recent
+@@ -87,7 +87,7 @@ struct jfs_superblock {
+ * 1 => the first one
+ * 2 => the 2nd one
+ */
+- char s_fpack[11]; /* 11: file system volume name
++ char s_fpack[11]; /* 11: file system volume name
+ * N.B. This must be 11 bytes to
+ * conform with the OS/2 BootSector
+ * requirements
+diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
+index efbb586..81f6f04 100644
+--- a/fs/jfs/jfs_txnmgr.c
++++ b/fs/jfs/jfs_txnmgr.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -282,7 +282,7 @@ int txInit(void)
+ TxLockVHWM = (nTxLock * 8) / 10;
+
+ size = sizeof(struct tblock) * nTxBlock;
+- TxBlock = (struct tblock *) vmalloc(size);
++ TxBlock = vmalloc(size);
+ if (TxBlock == NULL)
+ return -ENOMEM;
+
+@@ -307,7 +307,7 @@ int txInit(void)
+ * tlock id = 0 is reserved.
+ */
+ size = sizeof(struct tlock) * nTxLock;
+- TxLock = (struct tlock *) vmalloc(size);
++ TxLock = vmalloc(size);
+ if (TxLock == NULL) {
+ vfree(TxBlock);
+ return -ENOMEM;
+@@ -2026,8 +2026,6 @@ static void xtLog(struct jfs_log * log,
+ * truncate entry XAD[twm == next - 1]:
+ */
+ if (twm == next - 1) {
+- struct pxd_lock *pxdlock;
+-
+ /* format a maplock for txUpdateMap() to update bmap
+ * to free truncated delta extent of the truncated
+ * entry XAD[next - 1];
+@@ -2393,7 +2391,7 @@ static void txUpdateMap(struct tblock *
+ * unlock mapper/write lock
+ */
+ if (tblk->xflag & COMMIT_CREATE) {
+- diUpdatePMap(ipimap, tblk->ino, FALSE, tblk);
++ diUpdatePMap(ipimap, tblk->ino, false, tblk);
+ /* update persistent block allocation map
+ * for the allocation of inode extent;
+ */
+@@ -2403,7 +2401,7 @@ static void txUpdateMap(struct tblock *
+ txAllocPMap(ipimap, (struct maplock *) & pxdlock, tblk);
+ } else if (tblk->xflag & COMMIT_DELETE) {
+ ip = tblk->u.ip;
+- diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk);
++ diUpdatePMap(ipimap, ip->i_ino, true, tblk);
+ iput(ip);
+ }
+ }
+@@ -2451,7 +2449,7 @@ static void txAllocPMap(struct inode *ip
+ if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
+ xaddr = addressXAD(xad);
+ xlen = lengthXAD(xad);
+- dbUpdatePMap(ipbmap, FALSE, xaddr,
++ dbUpdatePMap(ipbmap, false, xaddr,
+ (s64) xlen, tblk);
+ xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+ jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
+@@ -2462,7 +2460,7 @@ static void txAllocPMap(struct inode *ip
+ pxdlock = (struct pxd_lock *) maplock;
+ xaddr = addressPXD(&pxdlock->pxd);
+ xlen = lengthPXD(&pxdlock->pxd);
+- dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk);
++ dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen, tblk);
+ jfs_info("allocPMap: xaddr:0x%lx xlen:%d", (ulong) xaddr, xlen);
+ } else { /* (maplock->flag & mlckALLOCPXDLIST) */
+
+@@ -2471,7 +2469,7 @@ static void txAllocPMap(struct inode *ip
+ for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+ xaddr = addressPXD(pxd);
+ xlen = lengthPXD(pxd);
+- dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen,
++ dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen,
+ tblk);
+ jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
+ (ulong) xaddr, xlen);
+@@ -2513,7 +2511,7 @@ void txFreeMap(struct inode *ip,
+ if (!(xad->flag & XAD_NEW)) {
+ xaddr = addressXAD(xad);
+ xlen = lengthXAD(xad);
+- dbUpdatePMap(ipbmap, TRUE, xaddr,
++ dbUpdatePMap(ipbmap, true, xaddr,
+ (s64) xlen, tblk);
+ jfs_info("freePMap: xaddr:0x%lx "
+ "xlen:%d",
+@@ -2524,7 +2522,7 @@ void txFreeMap(struct inode *ip,
+ pxdlock = (struct pxd_lock *) maplock;
+ xaddr = addressPXD(&pxdlock->pxd);
+ xlen = lengthPXD(&pxdlock->pxd);
+- dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen,
++ dbUpdatePMap(ipbmap, true, xaddr, (s64) xlen,
+ tblk);
+ jfs_info("freePMap: xaddr:0x%lx xlen:%d",
+ (ulong) xaddr, xlen);
+@@ -2535,7 +2533,7 @@ void txFreeMap(struct inode *ip,
+ for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+ xaddr = addressPXD(pxd);
+ xlen = lengthPXD(pxd);
+- dbUpdatePMap(ipbmap, TRUE, xaddr,
++ dbUpdatePMap(ipbmap, true, xaddr,
+ (s64) xlen, tblk);
+ jfs_info("freePMap: xaddr:0x%lx xlen:%d",
+ (ulong) xaddr, xlen);
+diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
+index 0e4dc45..7863cf2 100644
+--- a/fs/jfs/jfs_txnmgr.h
++++ b/fs/jfs/jfs_txnmgr.h
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_TXNMGR
+@@ -179,7 +179,7 @@ struct linelock {
+ /* (8) */
+
+ struct lv lv[20]; /* 40: */
+-}; /* (48) */
++}; /* (48) */
+
+ #define dt_lock linelock
+
+@@ -211,8 +211,8 @@ struct xtlock {
+ * at tlock.lock/linelock: watch for alignment;
+ * N.B. next field may be set by linelock, and should not
+ * be modified by maplock;
+- * N.B. index of the first pxdlock specifies index of next
+- * free maplock (i.e., number of maplock) in the tlock;
++ * N.B. index of the first pxdlock specifies index of next
++ * free maplock (i.e., number of maplock) in the tlock;
+ */
+ struct maplock {
+ lid_t next; /* 2: */
+diff --git a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h
+index 5bfad39..09b2529 100644
+--- a/fs/jfs/jfs_types.h
++++ b/fs/jfs/jfs_types.h
+@@ -57,10 +57,6 @@ struct timestruc_t {
+ #define HIGHORDER 0x80000000u /* high order bit on */
+ #define ONES 0xffffffffu /* all bit on */
+
+-typedef int boolean_t;
+-#define TRUE 1
+-#define FALSE 0
+-
+ /*
+ * logical xd (lxd)
+ */
+diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
+index 21eaf7a..a386f48 100644
+--- a/fs/jfs/jfs_umount.c
++++ b/fs/jfs/jfs_umount.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -22,8 +22,8 @@
+ * note: file system in transition to aggregate/fileset:
+ * (ref. jfs_mount.c)
+ *
+- * file system unmount is interpreted as mount of the single/only
+- * fileset in the aggregate and, if unmount of the last fileset,
++ * file system unmount is interpreted as mount of the single/only
++ * fileset in the aggregate and, if unmount of the last fileset,
+ * as unmount of the aggerate;
+ */
+
+@@ -60,13 +60,13 @@ int jfs_umount(struct super_block *sb)
+ jfs_info("UnMount JFS: sb:0x%p", sb);
+
+ /*
+- * update superblock and close log
++ * update superblock and close log
+ *
+ * if mounted read-write and log based recovery was enabled
+ */
+ if ((log = sbi->log))
+ /*
+- * Wait for outstanding transactions to be written to log:
++ * Wait for outstanding transactions to be written to log:
+ */
+ jfs_flush_journal(log, 2);
+
+@@ -112,17 +112,17 @@ int jfs_umount(struct super_block *sb)
+
+ /*
+ * ensure all file system file pages are propagated to their
+- * home blocks on disk (and their in-memory buffer pages are
++ * home blocks on disk (and their in-memory buffer pages are
+ * invalidated) BEFORE updating file system superblock state
+- * (to signify file system is unmounted cleanly, and thus in
+- * consistent state) and log superblock active file system
++ * (to signify file system is unmounted cleanly, and thus in
++ * consistent state) and log superblock active file system
+ * list (to signify skip logredo()).
+ */
+ if (log) { /* log = NULL if read-only mount */
+ updateSuper(sb, FM_CLEAN);
+
+ /*
+- * close log:
++ * close log:
+ *
+ * remove file system from log active file system list.
+ */
+@@ -142,7 +142,7 @@ int jfs_umount_rw(struct super_block *sb
+ return 0;
+
+ /*
+- * close log:
++ * close log:
+ *
+ * remove file system from log active file system list.
+ */
+diff --git a/fs/jfs/jfs_unicode.c b/fs/jfs/jfs_unicode.c
+index f327dec..c7de6f5 100644
+--- a/fs/jfs/jfs_unicode.c
++++ b/fs/jfs/jfs_unicode.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -57,8 +57,8 @@ int jfs_strfromUCS_le(char *to, const __
+ warn--;
+ warn_again--;
+ printk(KERN_ERR
+- "non-latin1 character 0x%x found in JFS file name\n",
+- le16_to_cpu(from[i]));
++ "non-latin1 character 0x%x found in JFS file name\n",
++ le16_to_cpu(from[i]));
+ printk(KERN_ERR
+ "mount with iocharset=utf8 to access\n");
+ }
+@@ -124,7 +124,7 @@ int get_UCSname(struct component_name *
+ kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS);
+
+ if (uniName->name == NULL)
+- return -ENOSPC;
++ return -ENOMEM;
+
+ uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
+ length, nls_tab);
+diff --git a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h
+index 69e25eb..3fbb3a2 100644
+--- a/fs/jfs/jfs_unicode.h
++++ b/fs/jfs/jfs_unicode.h
+@@ -1,19 +1,19 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
+- * Portions Copyright (c) Christoph Hellwig, 2001-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
++ * Portions Copyright (C) Christoph Hellwig, 2001-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_UNICODE
+diff --git a/fs/jfs/jfs_uniupr.c b/fs/jfs/jfs_uniupr.c
+index 4ab185d..cfe5066 100644
+--- a/fs/jfs/jfs_uniupr.c
++++ b/fs/jfs/jfs_uniupr.c
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h
+index 25e9990..88b6cc5 100644
+--- a/fs/jfs/jfs_xattr.h
++++ b/fs/jfs/jfs_xattr.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
+ *
+ * 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
+diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
+index e72f4eb..e98eb03 100644
+--- a/fs/jfs/jfs_xtree.c
++++ b/fs/jfs/jfs_xtree.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ /*
+@@ -2428,7 +2428,7 @@ printf("xtUpdate.updateLeft.split p:0x%p
+ * return:
+ */
+ int xtAppend(tid_t tid, /* transaction id */
+- struct inode *ip, int xflag, s64 xoff, s32 maxblocks,
++ struct inode *ip, int xflag, s64 xoff, s32 maxblocks,
+ s32 * xlenp, /* (in/out) */
+ s64 * xaddrp, /* (in/out) */
+ int flag)
+@@ -2499,7 +2499,7 @@ int xtAppend(tid_t tid, /* transaction
+ pxdlist.maxnpxd = pxdlist.npxd = 0;
+ pxd = &pxdlist.pxd[0];
+ nblocks = JFS_SBI(ip->i_sb)->nbperpage;
+- for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {
++ for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {
+ if ((rc = dbAllocBottomUp(ip, xaddr, (s64) nblocks)) == 0) {
+ PXDaddress(pxd, xaddr);
+ PXDlength(pxd, nblocks);
+@@ -2514,7 +2514,7 @@ int xtAppend(tid_t tid, /* transaction
+ goto out;
+ }
+
+- xlen = min(xlen, maxblocks);
++ xlen = min(xlen, maxblocks);
+
+ /*
+ * allocate data extent requested
+@@ -2964,7 +2964,7 @@ xtRelocate(tid_t tid, struct inode * ip,
+ cmSetXD(ip, cp, pno, dxaddr, nblks);
+
+ /* release the cbuf, mark it as modified */
+- cmPut(cp, TRUE);
++ cmPut(cp, true);
+
+ dxaddr += nblks;
+ sxaddr += nblks;
+diff --git a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h
+index af668a8..164f6f2 100644
+--- a/fs/jfs/jfs_xtree.h
++++ b/fs/jfs/jfs_xtree.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (c) International Business Machines Corp., 2000-2002
++ * Copyright (C) International Business Machines Corp., 2000-2002
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #ifndef _H_JFS_XTREE
+diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
+index 295268a..a6a8c16 100644
+--- a/fs/jfs/namei.c
++++ b/fs/jfs/namei.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -41,7 +41,7 @@ static s64 commitZeroLink(tid_t, struct
+ /*
+ * NAME: free_ea_wmap(inode)
+ *
+- * FUNCTION: free uncommitted extended attributes from working map
++ * FUNCTION: free uncommitted extended attributes from working map
+ *
+ */
+ static inline void free_ea_wmap(struct inode *inode)
+@@ -62,7 +62,7 @@ static inline void free_ea_wmap(struct i
+ * FUNCTION: create a regular file in the parent directory <dip>
+ * with name = <from dentry> and mode = <mode>
+ *
+- * PARAMETER: dip - parent directory vnode
++ * PARAMETER: dip - parent directory vnode
+ * dentry - dentry of new file
+ * mode - create mode (rwxrwxrwx).
+ * nd- nd struct
+@@ -97,8 +97,8 @@ static int jfs_create(struct inode *dip,
+ * begin the transaction before we search the directory.
+ */
+ ip = ialloc(dip, mode);
+- if (ip == NULL) {
+- rc = -ENOSPC;
++ if (IS_ERR(ip)) {
++ rc = PTR_ERR(ip);
+ goto out2;
+ }
+
+@@ -190,7 +190,7 @@ static int jfs_create(struct inode *dip,
+ * FUNCTION: create a child directory in the parent directory <dip>
+ * with name = <from dentry> and mode = <mode>
+ *
+- * PARAMETER: dip - parent directory vnode
++ * PARAMETER: dip - parent directory vnode
+ * dentry - dentry of child directory
+ * mode - create mode (rwxrwxrwx).
+ *
+@@ -231,8 +231,8 @@ static int jfs_mkdir(struct inode *dip,
+ * begin the transaction before we search the directory.
+ */
+ ip = ialloc(dip, S_IFDIR | mode);
+- if (ip == NULL) {
+- rc = -ENOSPC;
++ if (IS_ERR(ip)) {
++ rc = PTR_ERR(ip);
+ goto out2;
+ }
+
+@@ -292,7 +292,7 @@ static int jfs_mkdir(struct inode *dip,
+ mark_inode_dirty(ip);
+
+ /* update parent directory inode */
+- dip->i_nlink++; /* for '..' from child directory */
++ inc_nlink(dip); /* for '..' from child directory */
+ dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dip);
+
+@@ -324,7 +324,7 @@ static int jfs_mkdir(struct inode *dip,
+ *
+ * FUNCTION: remove a link to child directory
+ *
+- * PARAMETER: dip - parent inode
++ * PARAMETER: dip - parent inode
+ * dentry - child directory dentry
+ *
+ * RETURN: -EINVAL - if name is . or ..
+@@ -332,10 +332,10 @@ static int jfs_mkdir(struct inode *dip,
+ * errors from subroutines
+ *
+ * note:
+- * if other threads have the directory open when the last link
+- * is removed, the "." and ".." entries, if present, are removed before
+- * rmdir() returns and no new entries may be created in the directory,
+- * but the directory is not removed until the last reference to
++ * if other threads have the directory open when the last link
++ * is removed, the "." and ".." entries, if present, are removed before
++ * rmdir() returns and no new entries may be created in the directory,
++ * but the directory is not removed until the last reference to
+ * the directory is released (cf.unlink() of regular file).
+ */
+ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
+@@ -393,9 +393,8 @@ static int jfs_rmdir(struct inode *dip,
+ /* update parent directory's link count corresponding
+ * to ".." entry of the target directory deleted
+ */
+- dip->i_nlink--;
+ dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+- mark_inode_dirty(dip);
++ inode_dec_link_count(dip);
+
+ /*
+ * OS/2 could have created EA and/or ACL
+@@ -415,7 +414,7 @@ static int jfs_rmdir(struct inode *dip,
+ JFS_IP(ip)->acl.flag = 0;
+
+ /* mark the target directory as deleted */
+- ip->i_nlink = 0;
++ clear_nlink(ip);
+ mark_inode_dirty(ip);
+
+ rc = txCommit(tid, 2, &iplist[0], 0);
+@@ -447,11 +446,11 @@ static int jfs_rmdir(struct inode *dip,
+ /*
+ * NAME: jfs_unlink(dip, dentry)
+ *
+- * FUNCTION: remove a link to object <vp> named by <name>
++ * FUNCTION: remove a link to object <vp> named by <name>
+ * from parent directory <dvp>
+ *
+- * PARAMETER: dip - inode of parent directory
+- * dentry - dentry of object to be removed
++ * PARAMETER: dip - inode of parent directory
++ * dentry - dentry of object to be removed
+ *
+ * RETURN: errors from subroutines
+ *
+@@ -515,8 +514,7 @@ static int jfs_unlink(struct inode *dip,
+ mark_inode_dirty(dip);
+
+ /* update target's inode */
+- ip->i_nlink--;
+- mark_inode_dirty(ip);
++ inode_dec_link_count(ip);
+
+ /*
+ * commit zero link count object
+@@ -600,7 +598,7 @@ static int jfs_unlink(struct inode *dip,
+ *
+ * FUNCTION: for non-directory, called by jfs_remove(),
+ * truncate a regular file, directory or symbolic
+- * link to zero length. return 0 if type is not
++ * link to zero length. return 0 if type is not
+ * one of these.
+ *
+ * if the file is currently associated with a VM segment
+@@ -610,7 +608,7 @@ static int jfs_unlink(struct inode *dip,
+ * map by ctrunc1.
+ * if there is no VM segment on entry, the resources are
+ * freed in both work and permanent map.
+- * (? for temporary file - memory object is cached even
++ * (? for temporary file - memory object is cached even
+ * after no reference:
+ * reference count > 0 - )
+ *
+@@ -664,7 +662,7 @@ static s64 commitZeroLink(tid_t tid, str
+
+ /*
+ * free xtree/data (truncate to zero length):
+- * free xtree/data pages from cache if COMMIT_PWMAP,
++ * free xtree/data pages from cache if COMMIT_PWMAP,
+ * free xtree/data blocks from persistent block map, and
+ * free xtree/data blocks from working block map if COMMIT_PWMAP;
+ */
+@@ -679,7 +677,7 @@ static s64 commitZeroLink(tid_t tid, str
+ * NAME: jfs_free_zero_link()
+ *
+ * FUNCTION: for non-directory, called by iClose(),
+- * free resources of a file from cache and WORKING map
++ * free resources of a file from cache and WORKING map
+ * for a file previously committed with zero link count
+ * while associated with a pager object,
+ *
+@@ -764,7 +762,7 @@ void jfs_free_zero_link(struct inode *ip
+ * FUNCTION: create a link to <vp> by the name = <name>
+ * in the parent directory <dvp>
+ *
+- * PARAMETER: vp - target object
++ * PARAMETER: vp - target object
+ * dvp - parent directory of new link
+ * name - name of new link to target object
+ * crp - credential
+@@ -824,7 +822,7 @@ static int jfs_link(struct dentry *old_d
+ goto free_dname;
+
+ /* update object inode */
+- ip->i_nlink++; /* for new link */
++ inc_nlink(ip); /* for new link */
+ ip->i_ctime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+@@ -835,7 +833,7 @@ static int jfs_link(struct dentry *old_d
+ rc = txCommit(tid, 2, &iplist[0], 0);
+
+ if (rc) {
+- ip->i_nlink--;
++ ip->i_nlink--; /* never instantiated */
+ iput(ip);
+ } else
+ d_instantiate(dentry, ip);
+@@ -860,8 +858,8 @@ static int jfs_link(struct dentry *old_d
+ * in directory <dip>
+ *
+ * PARAMETER: dip - parent directory vnode
+- * dentry - dentry of symbolic link
+- * name - the path name of the existing object
++ * dentry - dentry of symbolic link
++ * name - the path name of the existing object
+ * that will be the source of the link
+ *
+ * RETURN: errors from subroutines
+@@ -908,8 +906,8 @@ static int jfs_symlink(struct inode *dip
+ * (iAlloc() returns new, locked inode)
+ */
+ ip = ialloc(dip, S_IFLNK | 0777);
+- if (ip == NULL) {
+- rc = -ENOSPC;
++ if (IS_ERR(ip)) {
++ rc = PTR_ERR(ip);
+ goto out2;
+ }
+
+@@ -928,7 +926,7 @@ static int jfs_symlink(struct inode *dip
+ tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
+
+ /* fix symlink access permission
+- * (dir_create() ANDs in the u.u_cmask,
++ * (dir_create() ANDs in the u.u_cmask,
+ * but symlinks really need to be 777 access)
+ */
+ ip->i_mode |= 0777;
+@@ -969,7 +967,7 @@ static int jfs_symlink(struct inode *dip
+ ip->i_mapping->a_ops = &jfs_aops;
+
+ /*
+- * even though the data of symlink object (source
++ * even though the data of symlink object (source
+ * path name) is treated as non-journaled user data,
+ * it is read/written thru buffer cache for performance.
+ */
+@@ -980,7 +978,6 @@ static int jfs_symlink(struct inode *dip
+ xlen = xsize >> JFS_SBI(sb)->l2bsize;
+ if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
+ txAbort(tid, 0);
+- rc = -ENOSPC;
+ goto out3;
+ }
+ extent = xaddr;
+@@ -1155,9 +1152,9 @@ static int jfs_rename(struct inode *old_
+ old_ip->i_ino, JFS_RENAME);
+ if (rc)
+ goto out4;
+- new_ip->i_nlink--;
++ drop_nlink(new_ip);
+ if (S_ISDIR(new_ip->i_mode)) {
+- new_ip->i_nlink--;
++ drop_nlink(new_ip);
+ if (new_ip->i_nlink) {
+ mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
+ if (old_dir != new_dir)
+@@ -1178,7 +1175,7 @@ static int jfs_rename(struct inode *old_
+ /* free block resources */
+ if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
+ txAbort(tid, 1); /* Marks FS Dirty */
+- rc = new_size;
++ rc = new_size;
+ goto out4;
+ }
+ tblk = tid_to_tblock(tid);
+@@ -1208,7 +1205,7 @@ static int jfs_rename(struct inode *old_
+ goto out4;
+ }
+ if (S_ISDIR(old_ip->i_mode))
+- new_dir->i_nlink++;
++ inc_nlink(new_dir);
+ }
+ /*
+ * Remove old directory entry
+@@ -1223,7 +1220,7 @@ static int jfs_rename(struct inode *old_
+ goto out4;
+ }
+ if (S_ISDIR(old_ip->i_mode)) {
+- old_dir->i_nlink--;
++ drop_nlink(old_dir);
+ if (old_dir != new_dir) {
+ /*
+ * Change inode number of parent for moved directory
+@@ -1294,7 +1291,7 @@ static int jfs_rename(struct inode *old_
+ new_size = xtTruncate_pmap(tid, new_ip, new_size);
+ if (new_size < 0) {
+ txAbort(tid, 1);
+- rc = new_size;
++ rc = new_size;
+ } else
+ rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
+ txEnd(tid);
+@@ -1352,8 +1349,8 @@ static int jfs_mknod(struct inode *dir,
+ goto out;
+
+ ip = ialloc(dir, mode);
+- if (ip == NULL) {
+- rc = -ENOSPC;
++ if (IS_ERR(ip)) {
++ rc = PTR_ERR(ip);
+ goto out1;
+ }
+ jfs_ip = JFS_IP(ip);
+diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
+index 4518036..79d625f 100644
+--- a/fs/jfs/resize.c
++++ b/fs/jfs/resize.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+diff --git a/fs/jfs/super.c b/fs/jfs/super.c
+index 143bcd1..9c1c6e0 100644
+--- a/fs/jfs/super.c
++++ b/fs/jfs/super.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -82,7 +82,7 @@ static void jfs_handle_error(struct supe
+ "as read-only\n",
+ sb->s_id);
+ sb->s_flags |= MS_RDONLY;
+- }
++ }
+
+ /* nothing is done for continue beyond marking the superblock dirty */
+ }
+@@ -422,7 +422,7 @@ static int jfs_fill_super(struct super_b
+
+ sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
+ if (!sbi)
+- return -ENOSPC;
++ return -ENOMEM;
+ sb->s_fs_info = sbi;
+ sbi->sb = sb;
+ sbi->uid = sbi->gid = sbi->umask = -1;
+@@ -775,7 +775,7 @@ static int __init init_jfs_fs(void)
+ int rc;
+
+ jfs_inode_cachep =
+- kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
++ kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
+ init_once, NULL);
+ if (jfs_inode_cachep == NULL)
+diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
+index 16477b3..cee43f3 100644
+--- a/fs/jfs/symlink.c
++++ b/fs/jfs/symlink.c
+@@ -3,16 +3,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
+index 9bc5b7c..b753ba2 100644
+--- a/fs/jfs/xattr.c
++++ b/fs/jfs/xattr.c
+@@ -4,16 +4,16 @@
+ *
+ * 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
++ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@@ -57,7 +57,7 @@
+ *
+ * 0 4 4 + EA_SIZE(ea1)
+ * +------------+-------------------+--------------------+-----
+- * | Overall EA | First FEA Element | Second FEA Element | .....
++ * | Overall EA | First FEA Element | Second FEA Element | .....
+ * | List Size | | |
+ * +------------+-------------------+--------------------+-----
+ *
+@@ -97,26 +97,26 @@ static inline int is_os2_xattr(struct jf
+ */
+ if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) &&
+ !strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+- return FALSE;
++ return false;
+ /*
+ * Check for "user."
+ */
+ if ((ea->namelen >= XATTR_USER_PREFIX_LEN) &&
+ !strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
+- return FALSE;
++ return false;
+ /*
+ * Check for "security."
+ */
+ if ((ea->namelen >= XATTR_SECURITY_PREFIX_LEN) &&
+ !strncmp(ea->name, XATTR_SECURITY_PREFIX,
+ XATTR_SECURITY_PREFIX_LEN))
+- return FALSE;
++ return false;
+ /*
+ * Check for "trusted."
+ */
+ if ((ea->namelen >= XATTR_TRUSTED_PREFIX_LEN) &&
+ !strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
+- return FALSE;
++ return false;
+ /*
+ * Add any other valid namespace prefixes here
+ */
+@@ -124,7 +124,7 @@ static inline int is_os2_xattr(struct jf
+ /*
+ * We assume it's OS/2's flat namespace
+ */
+- return TRUE;
++ return true;
+ }
+
+ static inline int name_size(struct jfs_ea *ea)
+@@ -155,9 +155,9 @@ static void ea_release(struct inode *ino
+
+ /*
+ * NAME: ea_write_inline
+- *
++ *
+ * FUNCTION: Attempt to write an EA inline if area is available
+- *
++ *
+ * PRE CONDITIONS:
+ * Already verified that the specified EA is small enough to fit inline
+ *
+@@ -216,10 +216,10 @@ static int ea_write_inline(struct inode
+
+ /*
+ * NAME: ea_write
+- *
++ *
+ * FUNCTION: Write an EA for an inode
+- *
+- * PRE CONDITIONS: EA has been verified
++ *
++ * PRE CONDITIONS: EA has been verified
+ *
+ * PARAMETERS:
+ * ip - Inode pointer
+@@ -340,9 +340,9 @@ static int ea_write(struct inode *ip, st
+
+ /*
+ * NAME: ea_read_inline
+- *
++ *
+ * FUNCTION: Read an inlined EA into user's buffer
+- *
++ *
+ * PARAMETERS:
+ * ip - Inode pointer
+ * ealist - Pointer to buffer to fill in with EA
+@@ -372,9 +372,9 @@ static int ea_read_inline(struct inode *
+
+ /*
+ * NAME: ea_read
+- *
++ *
+ * FUNCTION: copy EA data into user's buffer
+- *
++ *
+ * PARAMETERS:
+ * ip - Inode pointer
+ * ealist - Pointer to buffer to fill in with EA
+@@ -406,7 +406,7 @@ static int ea_read(struct inode *ip, str
+ return -EIO;
+ }
+
+- /*
++ /*
+ * Figure out how many blocks were allocated when this EA list was
+ * originally written to disk.
+ */
+@@ -443,14 +443,14 @@ static int ea_read(struct inode *ip, str
+
+ /*
+ * NAME: ea_get
+- *
++ *
+ * FUNCTION: Returns buffer containing existing extended attributes.
+ * The size of the buffer will be the larger of the existing
+ * attributes size, or min_size.
+ *
+ * The buffer, which may be inlined in the inode or in the
+- * page cache must be release by calling ea_release or ea_put
+- *
++ * page cache must be release by calling ea_release or ea_put
++ *
+ * PARAMETERS:
+ * inode - Inode pointer
+ * ea_buf - Structure to be populated with ealist and its metadata
+@@ -756,6 +756,11 @@ static int can_set_system_xattr(struct i
+ return -EOPNOTSUPP;
+ }
+
++/*
++ * Most of the permission checking is done by xattr_permission in the vfs.
++ * The local file system is responsible for handling the system.* namespace.
++ * We also need to verify that this is a namespace that we recognize.
++ */
+ static int can_set_xattr(struct inode *inode, const char *name,
+ const void *value, size_t value_len)
+ {
+@@ -771,10 +776,6 @@ static int can_set_xattr(struct inode *i
+ strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))
+ return -EOPNOTSUPP;
+
+- if (!S_ISREG(inode->i_mode) &&
+- (!S_ISDIR(inode->i_mode) || inode->i_mode &S_ISVTX))
+- return -EPERM;
+-
+ return 0;
+ }
+
+@@ -1054,7 +1055,7 @@ ssize_t jfs_listxattr(struct dentry * de
+
+ /* compute required size of list */
+ for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {
+- if (can_list(ea))
++ if (can_list(ea))
+ size += name_size(ea) + 1;
+ }
+
+@@ -1069,7 +1070,7 @@ ssize_t jfs_listxattr(struct dentry * de
+ /* Copy attribute names to buffer */
+ buffer = data;
+ for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {
+- if (can_list(ea)) {
++ if (can_list(ea)) {
+ int namelen = copy_name(buffer, ea);
+ buffer += namelen + 1;
+ }
+diff --git a/fs/libfs.c b/fs/libfs.c
+index ac02ea6..bd08e0e 100644
+--- a/fs/libfs.c
++++ b/fs/libfs.c
+@@ -243,7 +243,7 @@ int simple_link(struct dentry *old_dentr
+ struct inode *inode = old_dentry->d_inode;
+
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+- inode->i_nlink++;
++ inc_nlink(inode);
+ atomic_inc(&inode->i_count);
+ dget(dentry);
+ d_instantiate(dentry, inode);
+@@ -275,7 +275,7 @@ int simple_unlink(struct inode *dir, str
+ struct inode *inode = dentry->d_inode;
+
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+- inode->i_nlink--;
++ drop_nlink(inode);
+ dput(dentry);
+ return 0;
+ }
+@@ -285,9 +285,9 @@ int simple_rmdir(struct inode *dir, stru
+ if (!simple_empty(dentry))
+ return -ENOTEMPTY;
+
+- dentry->d_inode->i_nlink--;
++ drop_nlink(dentry->d_inode);
+ simple_unlink(dir, dentry);
+- dir->i_nlink--;
++ drop_nlink(dir);
+ return 0;
+ }
+
+@@ -303,10 +303,10 @@ int simple_rename(struct inode *old_dir,
+ if (new_dentry->d_inode) {
+ simple_unlink(new_dir, new_dentry);
+ if (they_are_dirs)
+- old_dir->i_nlink--;
++ drop_nlink(old_dir);
+ } else if (they_are_dirs) {
+- old_dir->i_nlink--;
+- new_dir->i_nlink++;
++ drop_nlink(old_dir);
++ inc_nlink(new_dir);
+ }
+
+ old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
+@@ -317,17 +317,9 @@ int simple_rename(struct inode *old_dir,
+
+ int simple_readpage(struct file *file, struct page *page)
+ {
+- void *kaddr;
+-
+- if (PageUptodate(page))
+- goto out;
+-
+- kaddr = kmap_atomic(page, KM_USER0);
+- memset(kaddr, 0, PAGE_CACHE_SIZE);
+- kunmap_atomic(kaddr, KM_USER0);
++ clear_highpage(page);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+-out:
+ unlock_page(page);
+ return 0;
+ }
+@@ -383,7 +375,6 @@ int simple_fill_super(struct super_block
+ return -ENOMEM;
+ inode->i_mode = S_IFDIR | 0755;
+ inode->i_uid = inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = &simple_dir_inode_operations;
+@@ -405,7 +396,6 @@ int simple_fill_super(struct super_block
+ goto out;
+ inode->i_mode = S_IFREG | files->mode;
+ inode->i_uid = inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_fop = files->ops;
+@@ -547,7 +537,7 @@ int simple_attr_open(struct inode *inode
+
+ attr->get = get;
+ attr->set = set;
+- attr->data = inode->u.generic_ip;
++ attr->data = inode->i_private;
+ attr->fmt = fmt;
+ mutex_init(&attr->mutex);
+
+diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
+index 52774fe..b85a0ad 100644
+--- a/fs/lockd/clntlock.c
++++ b/fs/lockd/clntlock.c
+@@ -100,12 +100,12 @@ int nlmclnt_block(struct nlm_wait *block
+ /*
+ * The server lockd has called us back to tell us the lock was granted
+ */
+-u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
++__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
+ {
+ const struct file_lock *fl = &lock->fl;
+ const struct nfs_fh *fh = &lock->fh;
+ struct nlm_wait *block;
+- u32 res = nlm_lck_denied;
++ __be32 res = nlm_lck_denied;
+
+ /*
+ * Look up blocked request based on arguments.
+@@ -144,42 +144,12 @@ u32 nlmclnt_grant(const struct sockaddr_
+ */
+
+ /*
+- * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
+- * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
+- */
+-static void nlmclnt_prepare_reclaim(struct nlm_host *host)
+-{
+- down_write(&host->h_rwsem);
+- host->h_monitored = 0;
+- host->h_state++;
+- host->h_nextrebind = 0;
+- nlm_rebind_host(host);
+-
+- /*
+- * Mark the locks for reclaiming.
+- */
+- list_splice_init(&host->h_granted, &host->h_reclaim);
+-
+- dprintk("NLM: reclaiming locks for host %s", host->h_name);
+-}
+-
+-static void nlmclnt_finish_reclaim(struct nlm_host *host)
+-{
+- host->h_reclaiming = 0;
+- up_write(&host->h_rwsem);
+- dprintk("NLM: done reclaiming locks for host %s", host->h_name);
+-}
+-
+-/*
+ * Reclaim all locks on server host. We do this by spawning a separate
+ * reclaimer thread.
+ */
+ void
+-nlmclnt_recovery(struct nlm_host *host, u32 newstate)
++nlmclnt_recovery(struct nlm_host *host)
+ {
+- if (host->h_nsmstate == newstate)
+- return;
+- host->h_nsmstate = newstate;
+ if (!host->h_reclaiming++) {
+ nlm_get_host(host);
+ __module_get(THIS_MODULE);
+@@ -199,18 +169,30 @@ reclaimer(void *ptr)
+ daemonize("%s-reclaim", host->h_name);
+ allow_signal(SIGKILL);
+
++ down_write(&host->h_rwsem);
++
+ /* This one ensures that our parent doesn't terminate while the
+ * reclaim is in progress */
+ lock_kernel();
+- lockd_up();
++ lockd_up(0); /* note: this cannot fail as lockd is already running */
++
++ dprintk("lockd: reclaiming locks for host %s", host->h_name);
+
+- nlmclnt_prepare_reclaim(host);
+- /* First, reclaim all locks that have been marked. */
+ restart:
+ nsmstate = host->h_nsmstate;
++
++ /* Force a portmap getport - the peer's lockd will
++ * most likely end up on a different port.
++ */
++ host->h_nextrebind = jiffies;
++ nlm_rebind_host(host);
++
++ /* First, reclaim all locks that have been granted. */
++ list_splice_init(&host->h_granted, &host->h_reclaim);
+ list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
+ list_del_init(&fl->fl_u.nfs_fl.list);
+
++ /* Why are we leaking memory here? --okir */
+ if (signalled())
+ continue;
+ if (nlmclnt_reclaim(host, fl) != 0)
+@@ -218,11 +200,13 @@ restart:
+ list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
+ if (host->h_nsmstate != nsmstate) {
+ /* Argh! The server rebooted again! */
+- list_splice_init(&host->h_granted, &host->h_reclaim);
+ goto restart;
+ }
+ }
+- nlmclnt_finish_reclaim(host);
++
++ host->h_reclaiming = 0;
++ up_write(&host->h_rwsem);
++ dprintk("NLM: done reclaiming locks for host %s", host->h_name);
+
+ /* Now, wake up all processes that sleep on a blocked lock */
+ list_for_each_entry(block, &nlm_blocked, b_list) {
+diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
+index 89ba0df..3d84f60 100644
+--- a/fs/lockd/clntproc.c
++++ b/fs/lockd/clntproc.c
+@@ -36,14 +36,14 @@ static const struct rpc_call_ops nlmclnt
+ /*
+ * Cookie counter for NLM requests
+ */
+-static u32 nlm_cookie = 0x1234;
++static atomic_t nlm_cookie = ATOMIC_INIT(0x1234);
+
+-static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
++void nlmclnt_next_cookie(struct nlm_cookie *c)
+ {
+- memcpy(c->data, &nlm_cookie, 4);
+- memset(c->data+4, 0, 4);
++ u32 cookie = atomic_inc_return(&nlm_cookie);
++
++ memcpy(c->data, &cookie, 4);
+ c->len=4;
+- nlm_cookie++;
+ }
+
+ static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
+@@ -100,7 +100,7 @@ static struct nlm_lockowner *nlm_find_lo
+ res = __nlm_find_lockowner(host, owner);
+ if (res == NULL) {
+ spin_unlock(&host->h_lock);
+- new = (struct nlm_lockowner *)kmalloc(sizeof(*new), GFP_KERNEL);
++ new = kmalloc(sizeof(*new), GFP_KERNEL);
+ spin_lock(&host->h_lock);
+ res = __nlm_find_lockowner(host, owner);
+ if (res == NULL && new != NULL) {
+@@ -129,11 +129,11 @@ static void nlmclnt_setlockargs(struct n
+ nlmclnt_next_cookie(&argp->cookie);
+ argp->state = nsm_local_state;
+ memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
+- lock->caller = system_utsname.nodename;
++ lock->caller = utsname()->nodename;
+ lock->oh.data = req->a_owner;
+ lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
+ (unsigned int)fl->fl_u.nfs_fl.owner->pid,
+- system_utsname.nodename);
++ utsname()->nodename);
+ lock->svid = fl->fl_u.nfs_fl.owner->pid;
+ lock->fl.fl_start = fl->fl_start;
+ lock->fl.fl_end = fl->fl_end;
+@@ -151,11 +151,14 @@ static void nlmclnt_release_lockargs(str
+ int
+ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
+ {
++ struct rpc_clnt *client = NFS_CLIENT(inode);
++ struct sockaddr_in addr;
++ struct nfs_server *nfssrv = NFS_SERVER(inode);
+ struct nlm_host *host;
+ struct nlm_rqst *call;
+ sigset_t oldset;
+ unsigned long flags;
+- int status, proto, vers;
++ int status, vers;
+
+ vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
+ if (NFS_PROTO(inode)->version > 3) {
+@@ -163,10 +166,10 @@ nlmclnt_proc(struct inode *inode, int cm
+ return -ENOLCK;
+ }
+
+- /* Retrieve transport protocol from NFS client */
+- proto = NFS_CLIENT(inode)->cl_xprt->prot;
+-
+- host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers);
++ rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
++ host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers,
++ nfssrv->nfs_client->cl_hostname,
++ strlen(nfssrv->nfs_client->cl_hostname));
+ if (host == NULL)
+ return -ENOLCK;
+
+@@ -499,7 +502,7 @@ nlmclnt_lock(struct nlm_rqst *req, struc
+ unsigned char fl_flags = fl->fl_flags;
+ int status = -ENOLCK;
+
+- if (!host->h_monitored && nsm_monitor(host) < 0) {
++ if (nsm_monitor(host) < 0) {
+ printk(KERN_NOTICE "lockd: failed to monitor %s\n",
+ host->h_name);
+ goto out;
+diff --git a/fs/lockd/host.c b/fs/lockd/host.c
+index 38b0e8a..fb24a97 100644
+--- a/fs/lockd/host.c
++++ b/fs/lockd/host.c
+@@ -26,48 +26,61 @@
+ #define NLM_HOST_REBIND (60 * HZ)
+ #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
+ #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
+-#define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr)
+
+-static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH];
++static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
+ static unsigned long next_gc;
+ static int nrhosts;
+ static DEFINE_MUTEX(nlm_host_mutex);
+
+
+ static void nlm_gc_hosts(void);
++static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
++ const char *, int, int);
+
+ /*
+ * Find an NLM server handle in the cache. If there is none, create it.
+ */
+ struct nlm_host *
+-nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
++nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
++ const char *hostname, int hostname_len)
+ {
+- return nlm_lookup_host(0, sin, proto, version);
++ return nlm_lookup_host(0, sin, proto, version,
++ hostname, hostname_len);
+ }
+
+ /*
+ * Find an NLM client handle in the cache. If there is none, create it.
+ */
+ struct nlm_host *
+-nlmsvc_lookup_host(struct svc_rqst *rqstp)
++nlmsvc_lookup_host(struct svc_rqst *rqstp,
++ const char *hostname, int hostname_len)
+ {
+ return nlm_lookup_host(1, &rqstp->rq_addr,
+- rqstp->rq_prot, rqstp->rq_vers);
++ rqstp->rq_prot, rqstp->rq_vers,
++ hostname, hostname_len);
+ }
+
+ /*
+ * Common host lookup routine for server & client
+ */
+ struct nlm_host *
+-nlm_lookup_host(int server, struct sockaddr_in *sin,
+- int proto, int version)
++nlm_lookup_host(int server, const struct sockaddr_in *sin,
++ int proto, int version,
++ const char *hostname,
++ int hostname_len)
+ {
+- struct nlm_host *host, **hp;
+- u32 addr;
++ struct hlist_head *chain;
++ struct hlist_node *pos;
++ struct nlm_host *host;
++ struct nsm_handle *nsm = NULL;
+ int hash;
+
+- dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
+- (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
++ dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n",
++ NIPQUAD(sin->sin_addr.s_addr), proto, version,
++ server? "server" : "client",
++ hostname_len,
++ hostname? hostname : "<none>");
++
+
+ hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
+
+@@ -77,7 +90,22 @@ nlm_lookup_host(int server, struct socka
+ if (time_after_eq(jiffies, next_gc))
+ nlm_gc_hosts();
+
+- for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
++ /* We may keep several nlm_host objects for a peer, because each
++ * nlm_host is identified by
++ * (address, protocol, version, server/client)
++ * We could probably simplify this a little by putting all those
++ * different NLM rpc_clients into one single nlm_host object.
++ * This would allow us to have one nlm_host per address.
++ */
++ chain = &nlm_hosts[hash];
++ hlist_for_each_entry(host, pos, chain, h_hash) {
++ if (!nlm_cmp_addr(&host->h_addr, sin))
++ continue;
++
++ /* See if we have an NSM handle for this client */
++ if (!nsm)
++ nsm = host->h_nsmhandle;
++
+ if (host->h_proto != proto)
+ continue;
+ if (host->h_version != version)
+@@ -85,28 +113,30 @@ nlm_lookup_host(int server, struct socka
+ if (host->h_server != server)
+ continue;
+
+- if (nlm_cmp_addr(&host->h_addr, sin)) {
+- if (hp != nlm_hosts + hash) {
+- *hp = host->h_next;
+- host->h_next = nlm_hosts[hash];
+- nlm_hosts[hash] = host;
+- }
+- nlm_get_host(host);
+- mutex_unlock(&nlm_host_mutex);
+- return host;
+- }
+- }
++ /* Move to head of hash chain. */
++ hlist_del(&host->h_hash);
++ hlist_add_head(&host->h_hash, chain);
+
+- /* Ooops, no host found, create it */
+- dprintk("lockd: creating host entry\n");
++ nlm_get_host(host);
++ goto out;
++ }
++ if (nsm)
++ atomic_inc(&nsm->sm_count);
+
+- if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL)))
+- goto nohost;
+- memset(host, 0, sizeof(*host));
++ host = NULL;
+
+- addr = sin->sin_addr.s_addr;
+- sprintf(host->h_name, "%u.%u.%u.%u", NIPQUAD(addr));
++ /* Sadly, the host isn't in our hash table yet. See if
++ * we have an NSM handle for it. If not, create one.
++ */
++ if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
++ goto out;
+
++ host = kzalloc(sizeof(*host), GFP_KERNEL);
++ if (!host) {
++ nsm_release(nsm);
++ goto out;
++ }
++ host->h_name = nsm->sm_name;
+ host->h_addr = *sin;
+ host->h_addr.sin_port = 0; /* ouch! */
+ host->h_version = version;
+@@ -120,9 +150,9 @@ nlm_lookup_host(int server, struct socka
+ init_rwsem(&host->h_rwsem);
+ host->h_state = 0; /* pseudo NSM state */
+ host->h_nsmstate = 0; /* real NSM state */
++ host->h_nsmhandle = nsm;
+ host->h_server = server;
+- host->h_next = nlm_hosts[hash];
+- nlm_hosts[hash] = host;
++ hlist_add_head(&host->h_hash, chain);
+ INIT_LIST_HEAD(&host->h_lockowners);
+ spin_lock_init(&host->h_lock);
+ INIT_LIST_HEAD(&host->h_granted);
+@@ -131,35 +161,39 @@ nlm_lookup_host(int server, struct socka
+ if (++nrhosts > NLM_HOST_MAX)
+ next_gc = 0;
+
+-nohost:
++out:
+ mutex_unlock(&nlm_host_mutex);
+ return host;
+ }
+
+-struct nlm_host *
+-nlm_find_client(void)
++/*
++ * Destroy a host
++ */
++static void
++nlm_destroy_host(struct nlm_host *host)
+ {
+- /* find a nlm_host for a client for which h_killed == 0.
+- * and return it
++ struct rpc_clnt *clnt;
++
++ BUG_ON(!list_empty(&host->h_lockowners));
++ BUG_ON(atomic_read(&host->h_count));
++
++ /*
++ * Release NSM handle and unmonitor host.
+ */
+- int hash;
+- mutex_lock(&nlm_host_mutex);
+- for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
+- struct nlm_host *host, **hp;
+- for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
+- if (host->h_server &&
+- host->h_killed == 0) {
+- nlm_get_host(host);
+- mutex_unlock(&nlm_host_mutex);
+- return host;
+- }
++ nsm_unmonitor(host);
++
++ if ((clnt = host->h_rpcclnt) != NULL) {
++ if (atomic_read(&clnt->cl_users)) {
++ printk(KERN_WARNING
++ "lockd: active RPC handle\n");
++ clnt->cl_dead = 1;
++ } else {
++ rpc_destroy_client(host->h_rpcclnt);
+ }
+ }
+- mutex_unlock(&nlm_host_mutex);
+- return NULL;
++ kfree(host);
+ }
+
+-
+ /*
+ * Create the NLM RPC client for an NLM peer
+ */
+@@ -167,7 +201,6 @@ struct rpc_clnt *
+ nlm_bind_host(struct nlm_host *host)
+ {
+ struct rpc_clnt *clnt;
+- struct rpc_xprt *xprt;
+
+ dprintk("lockd: nlm_bind_host(%08x)\n",
+ (unsigned)ntohl(host->h_addr.sin_addr.s_addr));
+@@ -179,7 +212,6 @@ nlm_bind_host(struct nlm_host *host)
+ * RPC rebind is required
+ */
+ if ((clnt = host->h_rpcclnt) != NULL) {
+- xprt = clnt->cl_xprt;
+ if (time_after_eq(jiffies, host->h_nextrebind)) {
+ rpc_force_rebind(clnt);
+ host->h_nextrebind = jiffies + NLM_HOST_REBIND;
+@@ -187,31 +219,37 @@ nlm_bind_host(struct nlm_host *host)
+ host->h_nextrebind - jiffies);
+ }
+ } else {
+- xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
+- if (IS_ERR(xprt))
+- goto forgetit;
+-
+- xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
+- xprt->resvport = 1; /* NLM requires a reserved port */
+-
+- /* Existing NLM servers accept AUTH_UNIX only */
+- clnt = rpc_new_client(xprt, host->h_name, &nlm_program,
+- host->h_version, RPC_AUTH_UNIX);
+- if (IS_ERR(clnt))
+- goto forgetit;
+- clnt->cl_autobind = 1; /* turn on pmap queries */
+- clnt->cl_softrtry = 1; /* All queries are soft */
+-
+- host->h_rpcclnt = clnt;
++ unsigned long increment = nlmsvc_timeout * HZ;
++ struct rpc_timeout timeparms = {
++ .to_initval = increment,
++ .to_increment = increment,
++ .to_maxval = increment * 6UL,
++ .to_retries = 5U,
++ };
++ struct rpc_create_args args = {
++ .protocol = host->h_proto,
++ .address = (struct sockaddr *)&host->h_addr,
++ .addrsize = sizeof(host->h_addr),
++ .timeout = &timeparms,
++ .servername = host->h_name,
++ .program = &nlm_program,
++ .version = host->h_version,
++ .authflavor = RPC_AUTH_UNIX,
++ .flags = (RPC_CLNT_CREATE_HARDRTRY |
++ RPC_CLNT_CREATE_AUTOBIND),
++ };
++
++ clnt = rpc_create(&args);
++ if (!IS_ERR(clnt))
++ host->h_rpcclnt = clnt;
++ else {
++ printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
++ clnt = NULL;
++ }
+ }
+
+ mutex_unlock(&host->h_mutex);
+ return clnt;
+-
+-forgetit:
+- printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
+- mutex_unlock(&host->h_mutex);
+- return NULL;
+ }
+
+ /*
+@@ -257,22 +295,82 @@ void nlm_release_host(struct nlm_host *h
+ }
+
+ /*
++ * We were notified that the host indicated by address &sin
++ * has rebooted.
++ * Release all resources held by that peer.
++ */
++void nlm_host_rebooted(const struct sockaddr_in *sin,
++ const char *hostname, int hostname_len,
++ u32 new_state)
++{
++ struct hlist_head *chain;
++ struct hlist_node *pos;
++ struct nsm_handle *nsm;
++ struct nlm_host *host;
++
++ dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
++ hostname, NIPQUAD(sin->sin_addr));
++
++ /* Find the NSM handle for this peer */
++ if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
++ return;
++
++ /* When reclaiming locks on this peer, make sure that
++ * we set up a new notification */
++ nsm->sm_monitored = 0;
++
++ /* Mark all hosts tied to this NSM state as having rebooted.
++ * We run the loop repeatedly, because we drop the host table
++ * lock for this.
++ * To avoid processing a host several times, we match the nsmstate.
++ */
++again: mutex_lock(&nlm_host_mutex);
++ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
++ hlist_for_each_entry(host, pos, chain, h_hash) {
++ if (host->h_nsmhandle == nsm
++ && host->h_nsmstate != new_state) {
++ host->h_nsmstate = new_state;
++ host->h_state++;
++
++ nlm_get_host(host);
++ mutex_unlock(&nlm_host_mutex);
++
++ if (host->h_server) {
++ /* We're server for this guy, just ditch
++ * all the locks he held. */
++ nlmsvc_free_host_resources(host);
++ } else {
++ /* He's the server, initiate lock recovery. */
++ nlmclnt_recovery(host);
++ }
++
++ nlm_release_host(host);
++ goto again;
++ }
++ }
++ }
++
++ mutex_unlock(&nlm_host_mutex);
++}
++
++/*
+ * Shut down the hosts module.
+ * Note that this routine is called only at server shutdown time.
+ */
+ void
+ nlm_shutdown_hosts(void)
+ {
++ struct hlist_head *chain;
++ struct hlist_node *pos;
+ struct nlm_host *host;
+- int i;
+
+ dprintk("lockd: shutting down host module\n");
+ mutex_lock(&nlm_host_mutex);
+
+ /* First, make all hosts eligible for gc */
+ dprintk("lockd: nuking all hosts...\n");
+- for (i = 0; i < NLM_HOST_NRHASH; i++) {
+- for (host = nlm_hosts[i]; host; host = host->h_next)
++ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
++ hlist_for_each_entry(host, pos, chain, h_hash)
+ host->h_expires = jiffies - 1;
+ }
+
+@@ -284,8 +382,8 @@ nlm_shutdown_hosts(void)
+ if (nrhosts) {
+ printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
+ dprintk("lockd: %d hosts left:\n", nrhosts);
+- for (i = 0; i < NLM_HOST_NRHASH; i++) {
+- for (host = nlm_hosts[i]; host; host = host->h_next) {
++ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
++ hlist_for_each_entry(host, pos, chain, h_hash) {
+ dprintk(" %s (cnt %d use %d exp %ld)\n",
+ host->h_name, atomic_read(&host->h_count),
+ host->h_inuse, host->h_expires);
+@@ -302,45 +400,32 @@ nlm_shutdown_hosts(void)
+ static void
+ nlm_gc_hosts(void)
+ {
+- struct nlm_host **q, *host;
+- struct rpc_clnt *clnt;
+- int i;
++ struct hlist_head *chain;
++ struct hlist_node *pos, *next;
++ struct nlm_host *host;
+
+ dprintk("lockd: host garbage collection\n");
+- for (i = 0; i < NLM_HOST_NRHASH; i++) {
+- for (host = nlm_hosts[i]; host; host = host->h_next)
++ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
++ hlist_for_each_entry(host, pos, chain, h_hash)
+ host->h_inuse = 0;
+ }
+
+ /* Mark all hosts that hold locks, blocks or shares */
+ nlmsvc_mark_resources();
+
+- for (i = 0; i < NLM_HOST_NRHASH; i++) {
+- q = &nlm_hosts[i];
+- while ((host = *q) != NULL) {
++ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
++ hlist_for_each_entry_safe(host, pos, next, chain, h_hash) {
+ if (atomic_read(&host->h_count) || host->h_inuse
+ || time_before(jiffies, host->h_expires)) {
+ dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n",
+ host->h_name, atomic_read(&host->h_count),
+ host->h_inuse, host->h_expires);
+- q = &host->h_next;
+ continue;
+ }
+ dprintk("lockd: delete host %s\n", host->h_name);
+- *q = host->h_next;
+- /* Don't unmonitor hosts that have been invalidated */
+- if (host->h_monitored && !host->h_killed)
+- nsm_unmonitor(host);
+- if ((clnt = host->h_rpcclnt) != NULL) {
+- if (atomic_read(&clnt->cl_users)) {
+- printk(KERN_WARNING
+- "lockd: active RPC handle\n");
+- clnt->cl_dead = 1;
+- } else {
+- rpc_destroy_client(host->h_rpcclnt);
+- }
+- }
+- kfree(host);
++ hlist_del_init(&host->h_hash);
++
++ nlm_destroy_host(host);
+ nrhosts--;
+ }
+ }
+@@ -348,3 +433,88 @@ nlm_gc_hosts(void)
+ next_gc = jiffies + NLM_HOST_COLLECT;
+ }
+
++
++/*
++ * Manage NSM handles
++ */
++static LIST_HEAD(nsm_handles);
++static DEFINE_MUTEX(nsm_mutex);
++
++static struct nsm_handle *
++__nsm_find(const struct sockaddr_in *sin,
++ const char *hostname, int hostname_len,
++ int create)
++{
++ struct nsm_handle *nsm = NULL;
++ struct list_head *pos;
++
++ if (!sin)
++ return NULL;
++
++ if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
++ if (printk_ratelimit()) {
++ printk(KERN_WARNING "Invalid hostname \"%.*s\" "
++ "in NFS lock request\n",
++ hostname_len, hostname);
++ }
++ return NULL;
++ }
++
++ mutex_lock(&nsm_mutex);
++ list_for_each(pos, &nsm_handles) {
++ nsm = list_entry(pos, struct nsm_handle, sm_link);
++
++ if (hostname && nsm_use_hostnames) {
++ if (strlen(nsm->sm_name) != hostname_len
++ || memcmp(nsm->sm_name, hostname, hostname_len))
++ continue;
++ } else if (!nlm_cmp_addr(&nsm->sm_addr, sin))
++ continue;
++ atomic_inc(&nsm->sm_count);
++ goto out;
++ }
++
++ if (!create) {
++ nsm = NULL;
++ goto out;
++ }
++
++ nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
++ if (nsm != NULL) {
++ nsm->sm_addr = *sin;
++ nsm->sm_name = (char *) (nsm + 1);
++ memcpy(nsm->sm_name, hostname, hostname_len);
++ nsm->sm_name[hostname_len] = '\0';
++ atomic_set(&nsm->sm_count, 1);
++
++ list_add(&nsm->sm_link, &nsm_handles);
++ }
++
++out:
++ mutex_unlock(&nsm_mutex);
++ return nsm;
++}
++
++struct nsm_handle *
++nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
++{
++ return __nsm_find(sin, hostname, hostname_len, 1);
++}
++
++/*
++ * Release an NSM handle
++ */
++void
++nsm_release(struct nsm_handle *nsm)
++{
++ if (!nsm)
++ return;
++ if (atomic_dec_and_test(&nsm->sm_count)) {
++ mutex_lock(&nsm_mutex);
++ if (atomic_read(&nsm->sm_count) == 0) {
++ list_del(&nsm->sm_link);
++ kfree(nsm);
++ }
++ mutex_unlock(&nsm_mutex);
++ }
++}
+diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
+index 3fc683f..eb243ed 100644
+--- a/fs/lockd/mon.c
++++ b/fs/lockd/mon.c
+@@ -24,13 +24,13 @@ static struct rpc_program nsm_program;
+ /*
+ * Local NSM state
+ */
+-u32 nsm_local_state;
++int nsm_local_state;
+
+ /*
+ * Common procedure for SM_MON/SM_UNMON calls
+ */
+ static int
+-nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
++nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
+ {
+ struct rpc_clnt *clnt;
+ int status;
+@@ -46,10 +46,11 @@ nsm_mon_unmon(struct nlm_host *host, u32
+ goto out;
+ }
+
+- args.addr = host->h_addr.sin_addr.s_addr;
+- args.proto= (host->h_proto<<1) | host->h_server;
++ memset(&args, 0, sizeof(args));
++ args.mon_name = nsm->sm_name;
++ args.addr = nsm->sm_addr.sin_addr.s_addr;
+ args.prog = NLM_PROGRAM;
+- args.vers = host->h_version;
++ args.vers = 3;
+ args.proc = NLMPROC_NSM_NOTIFY;
+ memset(res, 0, sizeof(*res));
+
+@@ -70,17 +71,22 @@ nsm_mon_unmon(struct nlm_host *host, u32
+ int
+ nsm_monitor(struct nlm_host *host)
+ {
++ struct nsm_handle *nsm = host->h_nsmhandle;
+ struct nsm_res res;
+ int status;
+
+ dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
++ BUG_ON(nsm == NULL);
+
+- status = nsm_mon_unmon(host, SM_MON, &res);
++ if (nsm->sm_monitored)
++ return 0;
++
++ status = nsm_mon_unmon(nsm, SM_MON, &res);
+
+ if (status < 0 || res.status != 0)
+ printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
+ else
+- host->h_monitored = 1;
++ nsm->sm_monitored = 1;
+ return status;
+ }
+
+@@ -90,16 +96,26 @@ nsm_monitor(struct nlm_host *host)
+ int
+ nsm_unmonitor(struct nlm_host *host)
+ {
++ struct nsm_handle *nsm = host->h_nsmhandle;
+ struct nsm_res res;
+- int status;
+-
+- dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+-
+- status = nsm_mon_unmon(host, SM_UNMON, &res);
+- if (status < 0)
+- printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
+- else
+- host->h_monitored = 0;
++ int status = 0;
++
++ if (nsm == NULL)
++ return 0;
++ host->h_nsmhandle = NULL;
++
++ if (atomic_read(&nsm->sm_count) == 1
++ && nsm->sm_monitored && !nsm->sm_sticky) {
++ dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
++
++ status = nsm_mon_unmon(nsm, SM_UNMON, &res);
++ if (status < 0)
++ printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
++ host->h_name);
++ else
++ nsm->sm_monitored = 0;
++ }
++ nsm_release(nsm);
+ return status;
+ }
+
+@@ -109,40 +125,33 @@ nsm_unmonitor(struct nlm_host *host)
+ static struct rpc_clnt *
+ nsm_create(void)
+ {
+- struct rpc_xprt *xprt;
+- struct rpc_clnt *clnt;
+- struct sockaddr_in sin;
+-
+- sin.sin_family = AF_INET;
+- sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+- sin.sin_port = 0;
+-
+- xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
+- if (IS_ERR(xprt))
+- return (struct rpc_clnt *)xprt;
+- xprt->resvport = 1; /* NSM requires a reserved port */
+-
+- clnt = rpc_create_client(xprt, "localhost",
+- &nsm_program, SM_VERSION,
+- RPC_AUTH_NULL);
+- if (IS_ERR(clnt))
+- goto out_err;
+- clnt->cl_softrtry = 1;
+- clnt->cl_oneshot = 1;
+- return clnt;
+-
+-out_err:
+- return clnt;
++ struct sockaddr_in sin = {
++ .sin_family = AF_INET,
++ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
++ .sin_port = 0,
++ };
++ struct rpc_create_args args = {
++ .protocol = IPPROTO_UDP,
++ .address = (struct sockaddr *)&sin,
++ .addrsize = sizeof(sin),
++ .servername = "localhost",
++ .program = &nsm_program,
++ .version = SM_VERSION,
++ .authflavor = RPC_AUTH_NULL,
++ .flags = (RPC_CLNT_CREATE_ONESHOT),
++ };
++
++ return rpc_create(&args);
+ }
+
+ /*
+ * XDR functions for NSM.
+ */
+
+-static u32 *
+-xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
++static __be32 *
++xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
+ {
+- char buffer[20];
++ char buffer[20], *name;
+
+ /*
+ * Use the dotted-quad IP address of the remote host as
+@@ -150,9 +159,14 @@ xdr_encode_common(struct rpc_rqst *rqstp
+ * hostname first for whatever remote hostname it receives,
+ * so this works alright.
+ */
+- sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
+- if (!(p = xdr_encode_string(p, buffer))
+- || !(p = xdr_encode_string(p, system_utsname.nodename)))
++ if (nsm_use_hostnames) {
++ name = argp->mon_name;
++ } else {
++ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
++ name = buffer;
++ }
++ if (!(p = xdr_encode_string(p, name))
++ || !(p = xdr_encode_string(p, utsname()->nodename)))
+ return ERR_PTR(-EIO);
+ *p++ = htonl(argp->prog);
+ *p++ = htonl(argp->vers);
+@@ -162,21 +176,23 @@ xdr_encode_common(struct rpc_rqst *rqstp
+ }
+
+ static int
+-xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
++xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
+ {
+ p = xdr_encode_common(rqstp, p, argp);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
++
++ /* Surprise - there may even be room for an IPv6 address now */
+ *p++ = argp->addr;
+- *p++ = argp->vers;
+- *p++ = argp->proto;
++ *p++ = 0;
++ *p++ = 0;
+ *p++ = 0;
+ rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
+ return 0;
+ }
+
+ static int
+-xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
++xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
+ {
+ p = xdr_encode_common(rqstp, p, argp);
+ if (IS_ERR(p))
+@@ -186,7 +202,7 @@ xdr_encode_unmon(struct rpc_rqst *rqstp,
+ }
+
+ static int
+-xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
++xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
+ {
+ resp->status = ntohl(*p++);
+ resp->state = ntohl(*p++);
+@@ -196,7 +212,7 @@ xdr_decode_stat_res(struct rpc_rqst *rqs
+ }
+
+ static int
+-xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
++xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
+ {
+ resp->state = ntohl(*p++);
+ return 0;
+diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
+index 9a991b5..8ca1808 100644
+--- a/fs/lockd/svc.c
++++ b/fs/lockd/svc.c
+@@ -31,7 +31,9 @@
+ #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/svc.h>
+ #include <linux/sunrpc/svcsock.h>
++#include <net/ip.h>
+ #include <linux/lockd/lockd.h>
++#include <linux/lockd/sm_inter.h>
+ #include <linux/nfs.h>
+
+ #define NLMDBG_FACILITY NLMDBG_SVC
+@@ -46,6 +48,7 @@ EXPORT_SYMBOL(nlmsvc_ops);
+ static DEFINE_MUTEX(nlmsvc_mutex);
+ static unsigned int nlmsvc_users;
+ static pid_t nlmsvc_pid;
++static struct svc_serv *nlmsvc_serv;
+ int nlmsvc_grace_period;
+ unsigned long nlmsvc_timeout;
+
+@@ -59,6 +62,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lockd_exi
+ static unsigned long nlm_grace_period;
+ static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
+ static int nlm_udpport, nlm_tcpport;
++int nsm_use_hostnames = 0;
+
+ /*
+ * Constants needed for the sysctl interface.
+@@ -96,7 +100,6 @@ static inline void clear_grace_period(vo
+ static void
+ lockd(struct svc_rqst *rqstp)
+ {
+- struct svc_serv *serv = rqstp->rq_server;
+ int err = 0;
+ unsigned long grace_period_expire;
+
+@@ -112,6 +115,7 @@ lockd(struct svc_rqst *rqstp)
+ * Let our maker know we're running.
+ */
+ nlmsvc_pid = current->pid;
++ nlmsvc_serv = rqstp->rq_server;
+ complete(&lockd_start_done);
+
+ daemonize("lockd");
+@@ -161,7 +165,7 @@ lockd(struct svc_rqst *rqstp)
+ * Find a socket with data available and call its
+ * recvfrom routine.
+ */
+- err = svc_recv(serv, rqstp, timeout);
++ err = svc_recv(rqstp, timeout);
+ if (err == -EAGAIN || err == -EINTR)
+ continue;
+ if (err < 0) {
+@@ -174,7 +178,7 @@ lockd(struct svc_rqst *rqstp)
+ dprintk("lockd: request from %08x\n",
+ (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
+
+- svc_process(serv, rqstp);
++ svc_process(rqstp);
+
+ }
+
+@@ -189,6 +193,7 @@ lockd(struct svc_rqst *rqstp)
+ nlmsvc_invalidate_all();
+ nlm_shutdown_hosts();
+ nlmsvc_pid = 0;
++ nlmsvc_serv = NULL;
+ } else
+ printk(KERN_DEBUG
+ "lockd: new process, skipping host shutdown\n");
+@@ -205,54 +210,77 @@ lockd(struct svc_rqst *rqstp)
+ module_put_and_exit(0);
+ }
+
++
++static int find_socket(struct svc_serv *serv, int proto)
++{
++ struct svc_sock *svsk;
++ int found = 0;
++ list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
++ if (svsk->sk_sk->sk_protocol == proto) {
++ found = 1;
++ break;
++ }
++ return found;
++}
++
++static int make_socks(struct svc_serv *serv, int proto)
++{
++ /* Make any sockets that are needed but not present.
++ * If nlm_udpport or nlm_tcpport were set as module
++ * options, make those sockets unconditionally
++ */
++ static int warned;
++ int err = 0;
++ if (proto == IPPROTO_UDP || nlm_udpport)
++ if (!find_socket(serv, IPPROTO_UDP))
++ err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport);
++ if (err == 0 && (proto == IPPROTO_TCP || nlm_tcpport))
++ if (!find_socket(serv, IPPROTO_TCP))
++ err= svc_makesock(serv, IPPROTO_TCP, nlm_tcpport);
++ if (!err)
++ warned = 0;
++ else if (warned++ == 0)
++ printk(KERN_WARNING
++ "lockd_up: makesock failed, error=%d\n", err);
++ return err;
++}
++
+ /*
+ * Bring up the lockd process if it's not already up.
+ */
+ int
+-lockd_up(void)
++lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
+ {
+- static int warned;
+ struct svc_serv * serv;
+ int error = 0;
+
+ mutex_lock(&nlmsvc_mutex);
+ /*
+- * Unconditionally increment the user count ... this is
+- * the number of clients who _want_ a lockd process.
+- */
+- nlmsvc_users++;
+- /*
+ * Check whether we're already up and running.
+ */
+- if (nlmsvc_pid)
++ if (nlmsvc_pid) {
++ if (proto)
++ error = make_socks(nlmsvc_serv, proto);
+ goto out;
++ }
+
+ /*
+ * Sanity check: if there's no pid,
+ * we should be the first user ...
+ */
+- if (nlmsvc_users > 1)
++ if (nlmsvc_users)
+ printk(KERN_WARNING
+ "lockd_up: no pid, %d users??\n", nlmsvc_users);
+
+ error = -ENOMEM;
+- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE);
++ serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
+ if (!serv) {
+ printk(KERN_WARNING "lockd_up: create service failed\n");
+ goto out;
+ }
+
+- if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0
+-#ifdef CONFIG_NFSD_TCP
+- || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0
+-#endif
+- ) {
+- if (warned++ == 0)
+- printk(KERN_WARNING
+- "lockd_up: makesock failed, error=%d\n", error);
++ if ((error = make_socks(serv, proto)) < 0)
+ goto destroy_and_out;
+- }
+- warned = 0;
+
+ /*
+ * Create the kernel thread and wait for it to start.
+@@ -272,6 +300,8 @@ lockd_up(void)
+ destroy_and_out:
+ svc_destroy(serv);
+ out:
++ if (!error)
++ nlmsvc_users++;
+ mutex_unlock(&nlmsvc_mutex);
+ return error;
+ }
+@@ -323,9 +353,6 @@ EXPORT_SYMBOL(lockd_down);
+ * Sysctl parameters (same as module parameters, different interface).
+ */
+
+-/* Something that isn't CTL_ANY, CTL_NONE or a value that may clash. */
+-#define CTL_UNNUMBERED -2
+-
+ static ctl_table nlm_sysctls[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+@@ -367,6 +394,22 @@ static ctl_table nlm_sysctls[] = {
+ .extra1 = (int *) &nlm_port_min,
+ .extra2 = (int *) &nlm_port_max,
+ },
++ {
++ .ctl_name = CTL_UNNUMBERED,
++ .procname = "nsm_use_hostnames",
++ .data = &nsm_use_hostnames,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = CTL_UNNUMBERED,
++ .procname = "nsm_local_state",
++ .data = &nsm_local_state,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
+ { .ctl_name = 0 }
+ };
+
+@@ -455,6 +498,7 @@ module_param_call(nlm_udpport, param_set
+ &nlm_udpport, 0644);
+ module_param_call(nlm_tcpport, param_set_port, param_get_int,
+ &nlm_tcpport, 0644);
++module_param(nsm_use_hostnames, bool, 0644);
+
+ /*
+ * Initialising and terminating the module.
+diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
+index a2dd9cc..0ce5c81 100644
+--- a/fs/lockd/svc4proc.c
++++ b/fs/lockd/svc4proc.c
+@@ -24,22 +24,22 @@
+ /*
+ * Obtain client and file from arguments
+ */
+-static u32
++static __be32
+ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_host **hostp, struct nlm_file **filp)
+ {
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
+ struct nlm_lock *lock = &argp->lock;
+- u32 error = 0;
++ __be32 error = 0;
+
+ /* nfsd callbacks must have been installed for this procedure */
+ if (!nlmsvc_ops)
+ return nlm_lck_denied_nolocks;
+
+ /* Obtain host handle */
+- if (!(host = nlmsvc_lookup_host(rqstp))
+- || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
++ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
++ || (argp->monitor && nsm_monitor(host) < 0))
+ goto no_locks;
+ *hostp = host;
+
+@@ -68,7 +68,7 @@ no_locks:
+ /*
+ * NULL: Test for presence of service
+ */
+-static int
++static __be32
+ nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ dprintk("lockd: NULL called\n");
+@@ -78,7 +78,7 @@ nlm4svc_proc_null(struct svc_rqst *rqstp
+ /*
+ * TEST: Check for conflicting lock
+ */
+-static int
++static __be32
+ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -96,7 +96,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now check for conflicting locks */
+ resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+@@ -107,7 +107,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp
+ return rpc_success;
+ }
+
+-static int
++static __be32
+ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -126,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ #if 0
+ /* If supplied state doesn't match current state, we assume it's
+@@ -150,7 +150,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp
+ return rpc_success;
+ }
+
+-static int
++static __be32
+ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -169,7 +169,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqs
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Try to cancel request. */
+ resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+@@ -183,7 +183,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqs
+ /*
+ * UNLOCK: release a lock
+ */
+-static int
++static __be32
+ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -202,7 +202,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqs
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now try to remove the lock */
+ resp->status = nlmsvc_unlock(file, &argp->lock);
+@@ -217,7 +217,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqs
+ * GRANTED: A server calls us to tell that a process' lock request
+ * was granted
+ */
+-static int
++static __be32
+ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -253,14 +253,16 @@ static const struct rpc_call_ops nlm4svc
+ * because we send the callback before the reply proper. I hope this
+ * doesn't break any clients.
+ */
+-static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
+- int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
++static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
++ __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
+ {
+ struct nlm_host *host;
+ struct nlm_rqst *call;
+- int stat;
++ __be32 stat;
+
+- host = nlmsvc_lookup_host(rqstp);
++ host = nlmsvc_lookup_host(rqstp,
++ argp->lock.caller,
++ argp->lock.len);
+ if (host == NULL)
+ return rpc_system_err;
+
+@@ -280,35 +282,35 @@ static int nlm4svc_callback(struct svc_r
+ return rpc_success;
+ }
+
+-static int nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: TEST_MSG called\n");
+ return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test);
+ }
+
+-static int nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: LOCK_MSG called\n");
+ return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock);
+ }
+
+-static int nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: CANCEL_MSG called\n");
+ return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel);
+ }
+
+-static int nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: UNLOCK_MSG called\n");
+ return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock);
+ }
+
+-static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: GRANTED_MSG called\n");
+@@ -318,7 +320,7 @@ static int nlm4svc_proc_granted_msg(stru
+ /*
+ * SHARE: create a DOS share or alter existing share.
+ */
+-static int
++static __be32
+ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -337,7 +339,7 @@ nlm4svc_proc_share(struct svc_rqst *rqst
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now try to create the share */
+ resp->status = nlmsvc_share_file(host, file, argp);
+@@ -351,7 +353,7 @@ nlm4svc_proc_share(struct svc_rqst *rqst
+ /*
+ * UNSHARE: Release a DOS share.
+ */
+-static int
++static __be32
+ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -370,7 +372,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rq
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now try to lock the file */
+ resp->status = nlmsvc_unshare_file(host, file, argp);
+@@ -384,7 +386,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rq
+ /*
+ * NM_LOCK: Create an unmonitored lock
+ */
+-static int
++static __be32
+ nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -397,7 +399,7 @@ nlm4svc_proc_nm_lock(struct svc_rqst *rq
+ /*
+ * FREE_ALL: Release all locks and shares held by client
+ */
+-static int
++static __be32
+ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+@@ -415,15 +417,11 @@ nlm4svc_proc_free_all(struct svc_rqst *r
+ /*
+ * SM_NOTIFY: private callback from statd (not part of official NLM proto)
+ */
+-static int
++static __be32
+ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
+ void *resp)
+ {
+ struct sockaddr_in saddr = rqstp->rq_addr;
+- int vers = argp->vers;
+- int prot = argp->proto >> 1;
+-
+- struct nlm_host *host;
+
+ dprintk("lockd: SM_NOTIFY called\n");
+ if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
+@@ -438,28 +436,17 @@ nlm4svc_proc_sm_notify(struct svc_rqst *
+ /* Obtain the host pointer for this NFS server and try to
+ * reclaim all locks we hold on this server.
+ */
++ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_addr.s_addr = argp->addr;
++ nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
+
+- if ((argp->proto & 1)==0) {
+- if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
+- nlmclnt_recovery(host, argp->state);
+- nlm_release_host(host);
+- }
+- } else {
+- /* If we run on an NFS server, delete all locks held by the client */
+-
+- if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
+- nlmsvc_free_host_resources(host);
+- nlm_release_host(host);
+- }
+- }
+ return rpc_success;
+ }
+
+ /*
+ * client sent a GRANTED_RES, let's remove the associated block
+ */
+-static int
++static __be32
+ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
+ void *resp)
+ {
+@@ -468,7 +455,7 @@ nlm4svc_proc_granted_res(struct svc_rqst
+
+ dprintk("lockd: GRANTED_RES called\n");
+
+- nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
++ nlmsvc_grant_reply(&argp->cookie, argp->status);
+ return rpc_success;
+ }
+
+diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
+index c9d4197..7e219b9 100644
+--- a/fs/lockd/svclock.c
++++ b/fs/lockd/svclock.c
+@@ -40,7 +40,7 @@
+
+ static void nlmsvc_release_block(struct nlm_block *block);
+ static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
+-static int nlmsvc_remove_block(struct nlm_block *block);
++static void nlmsvc_remove_block(struct nlm_block *block);
+
+ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
+ static void nlmsvc_freegrantargs(struct nlm_rqst *call);
+@@ -49,7 +49,7 @@ static const struct rpc_call_ops nlmsvc_
+ /*
+ * The list of blocked locks to retry
+ */
+-static struct nlm_block * nlm_blocked;
++static LIST_HEAD(nlm_blocked);
+
+ /*
+ * Insert a blocked lock into the global list
+@@ -57,48 +57,44 @@ static struct nlm_block * nlm_blocked;
+ static void
+ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
+ {
+- struct nlm_block **bp, *b;
++ struct nlm_block *b;
++ struct list_head *pos;
+
+ dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
+- kref_get(&block->b_count);
+- if (block->b_queued)
+- nlmsvc_remove_block(block);
+- bp = &nlm_blocked;
++ if (list_empty(&block->b_list)) {
++ kref_get(&block->b_count);
++ } else {
++ list_del_init(&block->b_list);
++ }
++
++ pos = &nlm_blocked;
+ if (when != NLM_NEVER) {
+ if ((when += jiffies) == NLM_NEVER)
+ when ++;
+- while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
+- bp = &b->b_next;
+- } else
+- while ((b = *bp) != 0)
+- bp = &b->b_next;
++ list_for_each(pos, &nlm_blocked) {
++ b = list_entry(pos, struct nlm_block, b_list);
++ if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
++ break;
++ }
++ /* On normal exit from the loop, pos == &nlm_blocked,
++ * so we will be adding to the end of the list - good
++ */
++ }
+
+- block->b_queued = 1;
++ list_add_tail(&block->b_list, pos);
+ block->b_when = when;
+- block->b_next = b;
+- *bp = block;
+ }
+
+ /*
+ * Remove a block from the global list
+ */
+-static int
++static inline void
+ nlmsvc_remove_block(struct nlm_block *block)
+ {
+- struct nlm_block **bp, *b;
+-
+- if (!block->b_queued)
+- return 1;
+- for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) {
+- if (b == block) {
+- *bp = block->b_next;
+- block->b_queued = 0;
+- nlmsvc_release_block(block);
+- return 1;
+- }
++ if (!list_empty(&block->b_list)) {
++ list_del_init(&block->b_list);
++ nlmsvc_release_block(block);
+ }
+-
+- return 0;
+ }
+
+ /*
+@@ -107,14 +103,14 @@ nlmsvc_remove_block(struct nlm_block *bl
+ static struct nlm_block *
+ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
+ {
+- struct nlm_block **head, *block;
++ struct nlm_block *block;
+ struct file_lock *fl;
+
+ dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
+ file, lock->fl.fl_pid,
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end, lock->fl.fl_type);
+- for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
++ list_for_each_entry(block, &nlm_blocked, b_list) {
+ fl = &block->b_call->a_args.lock.fl;
+ dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
+ block->b_file, fl->fl_pid,
+@@ -143,20 +139,20 @@ static inline int nlm_cookie_match(struc
+ * Find a block with a given NLM cookie.
+ */
+ static inline struct nlm_block *
+-nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
++nlmsvc_find_block(struct nlm_cookie *cookie)
+ {
+ struct nlm_block *block;
+
+- for (block = nlm_blocked; block; block = block->b_next) {
+- dprintk("cookie: head of blocked queue %p, block %p\n",
+- nlm_blocked, block);
+- if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
+- && nlm_cmp_addr(sin, &block->b_host->h_addr))
+- break;
++ list_for_each_entry(block, &nlm_blocked, b_list) {
++ if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
++ goto found;
+ }
+
+- if (block != NULL)
+- kref_get(&block->b_count);
++ return NULL;
++
++found:
++ dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
++ kref_get(&block->b_count);
+ return block;
+ }
+
+@@ -169,6 +165,11 @@ nlmsvc_find_block(struct nlm_cookie *coo
+ * request, but (as I found out later) that's because some implementations
+ * do just this. Never mind the standards comittees, they support our
+ * logging industries.
++ *
++ * 10 years later: I hope we can safely ignore these old and broken
++ * clients by now. Let's fix this so we can uniquely identify an incoming
++ * GRANTED_RES message by cookie, without having to rely on the client's IP
++ * address. --okir
+ */
+ static inline struct nlm_block *
+ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
+@@ -179,7 +180,7 @@ nlmsvc_create_block(struct svc_rqst *rqs
+ struct nlm_rqst *call = NULL;
+
+ /* Create host handle for callback */
+- host = nlmsvc_lookup_host(rqstp);
++ host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len);
+ if (host == NULL)
+ return NULL;
+
+@@ -192,6 +193,8 @@ nlmsvc_create_block(struct svc_rqst *rqs
+ if (block == NULL)
+ goto failed;
+ kref_init(&block->b_count);
++ INIT_LIST_HEAD(&block->b_list);
++ INIT_LIST_HEAD(&block->b_flist);
+
+ if (!nlmsvc_setgrantargs(call, lock))
+ goto failed_free;
+@@ -199,7 +202,7 @@ nlmsvc_create_block(struct svc_rqst *rqs
+ /* Set notifier function for VFS, and init args */
+ call->a_args.lock.fl.fl_flags |= FL_SLEEP;
+ call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
+- call->a_args.cookie = *cookie; /* see above */
++ nlmclnt_next_cookie(&call->a_args.cookie);
+
+ dprintk("lockd: created block %p...\n", block);
+
+@@ -210,8 +213,7 @@ nlmsvc_create_block(struct svc_rqst *rqs
+ file->f_count++;
+
+ /* Add to file's list of blocks */
+- block->b_fnext = file->f_blocks;
+- file->f_blocks = block;
++ list_add(&block->b_flist, &file->f_blocks);
+
+ /* Set up RPC arguments for callback */
+ block->b_call = call;
+@@ -248,19 +250,13 @@ static void nlmsvc_free_block(struct kre
+ {
+ struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
+ struct nlm_file *file = block->b_file;
+- struct nlm_block **bp;
+
+ dprintk("lockd: freeing block %p...\n", block);
+
+- down(&file->f_sema);
+ /* Remove block from file's list of blocks */
+- for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
+- if (*bp == block) {
+- *bp = block->b_fnext;
+- break;
+- }
+- }
+- up(&file->f_sema);
++ mutex_lock(&file->f_mutex);
++ list_del_init(&block->b_flist);
++ mutex_unlock(&file->f_mutex);
+
+ nlmsvc_freegrantargs(block->b_call);
+ nlm_release_call(block->b_call);
+@@ -274,47 +270,32 @@ static void nlmsvc_release_block(struct
+ kref_put(&block->b_count, nlmsvc_free_block);
+ }
+
+-static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
+-{
+- struct nlm_block *block;
+-
+- down(&file->f_sema);
+- for (block = file->f_blocks; block != NULL; block = block->b_fnext)
+- block->b_host->h_inuse = 1;
+- up(&file->f_sema);
+-}
+-
+-static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
++/*
++ * Loop over all blocks and delete blocks held by
++ * a matching host.
++ */
++void nlmsvc_traverse_blocks(struct nlm_host *host,
++ struct nlm_file *file,
++ nlm_host_match_fn_t match)
+ {
+- struct nlm_block *block;
++ struct nlm_block *block, *next;
+
+ restart:
+- down(&file->f_sema);
+- for (block = file->f_blocks; block != NULL; block = block->b_fnext) {
+- if (host != NULL && host != block->b_host)
++ mutex_lock(&file->f_mutex);
++ list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
++ if (!match(block->b_host, host))
+ continue;
+- if (!block->b_queued)
++ /* Do not destroy blocks that are not on
++ * the global retry list - why? */
++ if (list_empty(&block->b_list))
+ continue;
+ kref_get(&block->b_count);
+- up(&file->f_sema);
++ mutex_unlock(&file->f_mutex);
+ nlmsvc_unlink_block(block);
+ nlmsvc_release_block(block);
+ goto restart;
+ }
+- up(&file->f_sema);
+-}
+-
+-/*
+- * Loop over all blocks and perform the action specified.
+- * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
+- */
+-void
+-nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
+-{
+- if (action == NLM_ACT_MARK)
+- nlmsvc_act_mark(host, file);
+- else
+- nlmsvc_act_unlock(host, file);
++ mutex_unlock(&file->f_mutex);
+ }
+
+ /*
+@@ -325,7 +306,7 @@ static int nlmsvc_setgrantargs(struct nl
+ {
+ locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
+ memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
+- call->a_args.lock.caller = system_utsname.nodename;
++ call->a_args.lock.caller = utsname()->nodename;
+ call->a_args.lock.oh.len = lock->oh.len;
+
+ /* set default data area */
+@@ -353,13 +334,13 @@ static void nlmsvc_freegrantargs(struct
+ * Attempt to establish a lock, and if it can't be granted, block it
+ * if required.
+ */
+-u32
++__be32
+ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
+ struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
+ {
+ struct nlm_block *block, *newblock = NULL;
+ int error;
+- u32 ret;
++ __be32 ret;
+
+ dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
+ file->f_file->f_dentry->d_inode->i_sb->s_id,
+@@ -373,7 +354,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, stru
+ lock->fl.fl_flags &= ~FL_SLEEP;
+ again:
+ /* Lock file against concurrent access */
+- down(&file->f_sema);
++ mutex_lock(&file->f_mutex);
+ /* Get existing block (in case client is busy-waiting) */
+ block = nlmsvc_lookup_block(file, lock);
+ if (block == NULL) {
+@@ -411,10 +392,10 @@ again:
+
+ /* If we don't have a block, create and initialize it. Then
+ * retry because we may have slept in kmalloc. */
+- /* We have to release f_sema as nlmsvc_create_block may try to
++ /* We have to release f_mutex as nlmsvc_create_block may try to
+ * to claim it while doing host garbage collection */
+ if (newblock == NULL) {
+- up(&file->f_sema);
++ mutex_unlock(&file->f_mutex);
+ dprintk("lockd: blocking on this lock (allocating).\n");
+ if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
+ return nlm_lck_denied_nolocks;
+@@ -424,7 +405,7 @@ again:
+ /* Append to list of blocked */
+ nlmsvc_insert_block(newblock, NLM_NEVER);
+ out:
+- up(&file->f_sema);
++ mutex_unlock(&file->f_mutex);
+ nlmsvc_release_block(newblock);
+ nlmsvc_release_block(block);
+ dprintk("lockd: nlmsvc_lock returned %u\n", ret);
+@@ -434,7 +415,7 @@ out:
+ /*
+ * Test for presence of a conflicting lock.
+ */
+-u32
++__be32
+ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
+ struct nlm_lock *conflock)
+ {
+@@ -451,6 +432,7 @@ nlmsvc_testlock(struct nlm_file *file, s
+ (long long)conflock->fl.fl_start,
+ (long long)conflock->fl.fl_end);
+ conflock->caller = "somehost"; /* FIXME */
++ conflock->len = strlen(conflock->caller);
+ conflock->oh.len = 0; /* don't return OH info */
+ conflock->svid = conflock->fl.fl_pid;
+ return nlm_lck_denied;
+@@ -466,7 +448,7 @@ nlmsvc_testlock(struct nlm_file *file, s
+ * afterwards. In this case the block will still be there, and hence
+ * must be removed.
+ */
+-u32
++__be32
+ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
+ {
+ int error;
+@@ -494,7 +476,7 @@ nlmsvc_unlock(struct nlm_file *file, str
+ * be in progress.
+ * The calling procedure must check whether the file can be closed.
+ */
+-u32
++__be32
+ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
+ {
+ struct nlm_block *block;
+@@ -507,9 +489,9 @@ nlmsvc_cancel_blocked(struct nlm_file *f
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
+
+- down(&file->f_sema);
++ mutex_lock(&file->f_mutex);
+ block = nlmsvc_lookup_block(file, lock);
+- up(&file->f_sema);
++ mutex_unlock(&file->f_mutex);
+ if (block != NULL) {
+ status = nlmsvc_unlink_block(block);
+ nlmsvc_release_block(block);
+@@ -527,10 +509,10 @@ nlmsvc_cancel_blocked(struct nlm_file *f
+ static void
+ nlmsvc_notify_blocked(struct file_lock *fl)
+ {
+- struct nlm_block **bp, *block;
++ struct nlm_block *block;
+
+ dprintk("lockd: VFS unblock notification for block %p\n", fl);
+- for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
++ list_for_each_entry(block, &nlm_blocked, b_list) {
+ if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
+ nlmsvc_insert_block(block, 0);
+ svc_wake_up(block->b_daemon);
+@@ -663,17 +645,14 @@ static const struct rpc_call_ops nlmsvc_
+ * block.
+ */
+ void
+-nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status)
++nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
+ {
+ struct nlm_block *block;
+- struct nlm_file *file;
+
+- dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n",
+- *(unsigned int *)(cookie->data),
+- ntohl(rqstp->rq_addr.sin_addr.s_addr), status);
+- if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr)))
++ dprintk("grant_reply: looking for cookie %x, s=%d \n",
++ *(unsigned int *)(cookie->data), status);
++ if (!(block = nlmsvc_find_block(cookie)))
+ return;
+- file = block->b_file;
+
+ if (block) {
+ if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
+@@ -696,16 +675,19 @@ nlmsvc_grant_reply(struct svc_rqst *rqst
+ unsigned long
+ nlmsvc_retry_blocked(void)
+ {
+- struct nlm_block *block;
++ unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
++ struct nlm_block *block;
++
++ while (!list_empty(&nlm_blocked)) {
++ block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
+
+- dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
+- nlm_blocked,
+- nlm_blocked? nlm_blocked->b_when : 0);
+- while ((block = nlm_blocked) != 0) {
+ if (block->b_when == NLM_NEVER)
+ break;
+- if (time_after(block->b_when,jiffies))
++ if (time_after(block->b_when,jiffies)) {
++ timeout = block->b_when - jiffies;
+ break;
++ }
++
+ dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
+ block, block->b_when);
+ kref_get(&block->b_count);
+@@ -713,8 +695,5 @@ nlmsvc_retry_blocked(void)
+ nlmsvc_release_block(block);
+ }
+
+- if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
+- return (block->b_when - jiffies);
+-
+- return MAX_SCHEDULE_TIMEOUT;
++ return timeout;
+ }
+diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
+index dbb66a3..32e99a6 100644
+--- a/fs/lockd/svcproc.c
++++ b/fs/lockd/svcproc.c
+@@ -22,8 +22,8 @@
+ #define NLMDBG_FACILITY NLMDBG_CLIENT
+
+ #ifdef CONFIG_LOCKD_V4
+-static u32
+-cast_to_nlm(u32 status, u32 vers)
++static __be32
++cast_to_nlm(__be32 status, u32 vers)
+ {
+ /* Note: status is assumed to be in network byte order !!! */
+ if (vers != 4){
+@@ -52,22 +52,22 @@ cast_to_nlm(u32 status, u32 vers)
+ /*
+ * Obtain client and file from arguments
+ */
+-static u32
++static __be32
+ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_host **hostp, struct nlm_file **filp)
+ {
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
+ struct nlm_lock *lock = &argp->lock;
+- u32 error;
++ __be32 error = 0;
+
+ /* nfsd callbacks must have been installed for this procedure */
+ if (!nlmsvc_ops)
+ return nlm_lck_denied_nolocks;
+
+ /* Obtain host handle */
+- if (!(host = nlmsvc_lookup_host(rqstp))
+- || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
++ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
++ || (argp->monitor && nsm_monitor(host) < 0))
+ goto no_locks;
+ *hostp = host;
+
+@@ -88,13 +88,15 @@ nlmsvc_retrieve_args(struct svc_rqst *rq
+ no_locks:
+ if (host)
+ nlm_release_host(host);
++ if (error)
++ return error;
+ return nlm_lck_denied_nolocks;
+ }
+
+ /*
+ * NULL: Test for presence of service
+ */
+-static int
++static __be32
+ nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ dprintk("lockd: NULL called\n");
+@@ -104,7 +106,7 @@ nlmsvc_proc_null(struct svc_rqst *rqstp,
+ /*
+ * TEST: Check for conflicting lock
+ */
+-static int
++static __be32
+ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -122,7 +124,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp,
+
+ /* Obtain client and file */
+ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now check for conflicting locks */
+ resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
+@@ -134,7 +136,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp,
+ return rpc_success;
+ }
+
+-static int
++static __be32
+ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -153,7 +155,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp,
+
+ /* Obtain client and file */
+ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ #if 0
+ /* If supplied state doesn't match current state, we assume it's
+@@ -177,7 +179,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp,
+ return rpc_success;
+ }
+
+-static int
++static __be32
+ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -196,7 +198,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqst
+
+ /* Obtain client and file */
+ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Try to cancel request. */
+ resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
+@@ -210,7 +212,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqst
+ /*
+ * UNLOCK: release a lock
+ */
+-static int
++static __be32
+ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -229,7 +231,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqst
+
+ /* Obtain client and file */
+ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now try to remove the lock */
+ resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
+@@ -244,7 +246,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqst
+ * GRANTED: A server calls us to tell that a process' lock request
+ * was granted
+ */
+-static int
++static __be32
+ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -280,14 +282,16 @@ static const struct rpc_call_ops nlmsvc_
+ * because we send the callback before the reply proper. I hope this
+ * doesn't break any clients.
+ */
+-static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
+- int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
++static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
++ __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
+ {
+ struct nlm_host *host;
+ struct nlm_rqst *call;
+- int stat;
++ __be32 stat;
+
+- host = nlmsvc_lookup_host(rqstp);
++ host = nlmsvc_lookup_host(rqstp,
++ argp->lock.caller,
++ argp->lock.len);
+ if (host == NULL)
+ return rpc_system_err;
+
+@@ -307,28 +311,28 @@ static int nlmsvc_callback(struct svc_rq
+ return rpc_success;
+ }
+
+-static int nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: TEST_MSG called\n");
+ return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test);
+ }
+
+-static int nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: LOCK_MSG called\n");
+ return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock);
+ }
+
+-static int nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
++static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+ dprintk("lockd: CANCEL_MSG called\n");
+ return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel);
+ }
+
+-static int
++static __be32
+ nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+@@ -336,7 +340,7 @@ nlmsvc_proc_unlock_msg(struct svc_rqst *
+ return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock);
+ }
+
+-static int
++static __be32
+ nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+@@ -347,7 +351,7 @@ nlmsvc_proc_granted_msg(struct svc_rqst
+ /*
+ * SHARE: create a DOS share or alter existing share.
+ */
+-static int
++static __be32
+ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -366,7 +370,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp
+
+ /* Obtain client and file */
+ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now try to create the share */
+ resp->status = cast_status(nlmsvc_share_file(host, file, argp));
+@@ -380,7 +384,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp
+ /*
+ * UNSHARE: Release a DOS share.
+ */
+-static int
++static __be32
+ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -399,7 +403,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqs
+
+ /* Obtain client and file */
+ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
+- return rpc_success;
++ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+
+ /* Now try to unshare the file */
+ resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
+@@ -413,7 +417,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqs
+ /*
+ * NM_LOCK: Create an unmonitored lock
+ */
+-static int
++static __be32
+ nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+ {
+@@ -426,7 +430,7 @@ nlmsvc_proc_nm_lock(struct svc_rqst *rqs
+ /*
+ * FREE_ALL: Release all locks and shares held by client
+ */
+-static int
++static __be32
+ nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+ {
+@@ -444,14 +448,11 @@ nlmsvc_proc_free_all(struct svc_rqst *rq
+ /*
+ * SM_NOTIFY: private callback from statd (not part of official NLM proto)
+ */
+-static int
++static __be32
+ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
+ void *resp)
+ {
+ struct sockaddr_in saddr = rqstp->rq_addr;
+- int vers = argp->vers;
+- int prot = argp->proto >> 1;
+- struct nlm_host *host;
+
+ dprintk("lockd: SM_NOTIFY called\n");
+ if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
+@@ -466,19 +467,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *r
+ /* Obtain the host pointer for this NFS server and try to
+ * reclaim all locks we hold on this server.
+ */
++ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_addr.s_addr = argp->addr;
+- if ((argp->proto & 1)==0) {
+- if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
+- nlmclnt_recovery(host, argp->state);
+- nlm_release_host(host);
+- }
+- } else {
+- /* If we run on an NFS server, delete all locks held by the client */
+- if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
+- nlmsvc_free_host_resources(host);
+- nlm_release_host(host);
+- }
+- }
++ nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
+
+ return rpc_success;
+ }
+@@ -486,7 +477,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *r
+ /*
+ * client sent a GRANTED_RES, let's remove the associated block
+ */
+-static int
++static __be32
+ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
+ void *resp)
+ {
+@@ -495,7 +486,7 @@ nlmsvc_proc_granted_res(struct svc_rqst
+
+ dprintk("lockd: GRANTED_RES called\n");
+
+- nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
++ nlmsvc_grant_reply(&argp->cookie, argp->status);
+ return rpc_success;
+ }
+
+diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
+index 27288c8..6220dc2 100644
+--- a/fs/lockd/svcshare.c
++++ b/fs/lockd/svcshare.c
+@@ -23,7 +23,7 @@ nlm_cmp_owner(struct nlm_share *share, s
+ && !memcmp(share->s_owner.data, oh->data, oh->len);
+ }
+
+-u32
++__be32
+ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
+ struct nlm_args *argp)
+ {
+@@ -64,7 +64,7 @@ update:
+ /*
+ * Delete a share.
+ */
+-u32
++__be32
+ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
+ struct nlm_args *argp)
+ {
+@@ -85,24 +85,20 @@ nlmsvc_unshare_file(struct nlm_host *hos
+ }
+
+ /*
+- * Traverse all shares for a given file (and host).
+- * NLM_ACT_CHECK is handled by nlmsvc_inspect_file.
++ * Traverse all shares for a given file, and delete
++ * those owned by the given (type of) host
+ */
+-void
+-nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
++void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
++ nlm_host_match_fn_t match)
+ {
+ struct nlm_share *share, **shpp;
+
+ shpp = &file->f_shares;
+ while ((share = *shpp) != NULL) {
+- if (action == NLM_ACT_MARK)
+- share->s_host->h_inuse = 1;
+- else if (action == NLM_ACT_UNLOCK) {
+- if (host == NULL || host == share->s_host) {
+- *shpp = share->s_next;
+- kfree(share);
+- continue;
+- }
++ if (match(share->s_host, host)) {
++ *shpp = share->s_next;
++ kfree(share);
++ continue;
+ }
+ shpp = &share->s_next;
+ }
+diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
+index 01b4db9..e83024e 100644
+--- a/fs/lockd/svcsubs.c
++++ b/fs/lockd/svcsubs.c
+@@ -25,9 +25,9 @@
+ /*
+ * Global file hash table
+ */
+-#define FILE_HASH_BITS 5
++#define FILE_HASH_BITS 7
+ #define FILE_NRHASH (1<<FILE_HASH_BITS)
+-static struct nlm_file * nlm_files[FILE_NRHASH];
++static struct hlist_head nlm_files[FILE_NRHASH];
+ static DEFINE_MUTEX(nlm_file_mutex);
+
+ #ifdef NFSD_DEBUG
+@@ -78,13 +78,14 @@ static inline unsigned int file_hash(str
+ * This is not quite right, but for now, we assume the client performs
+ * the proper R/W checking.
+ */
+-u32
++__be32
+ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
+ struct nfs_fh *f)
+ {
++ struct hlist_node *pos;
+ struct nlm_file *file;
+ unsigned int hash;
+- u32 nfserr;
++ __be32 nfserr;
+
+ nlm_debug_print_fh("nlm_file_lookup", f);
+
+@@ -93,21 +94,21 @@ nlm_lookup_file(struct svc_rqst *rqstp,
+ /* Lock file table */
+ mutex_lock(&nlm_file_mutex);
+
+- for (file = nlm_files[hash]; file; file = file->f_next)
++ hlist_for_each_entry(file, pos, &nlm_files[hash], f_list)
+ if (!nfs_compare_fh(&file->f_handle, f))
+ goto found;
+
+ nlm_debug_print_fh("creating file for", f);
+
+ nfserr = nlm_lck_denied_nolocks;
+- file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
++ file = kzalloc(sizeof(*file), GFP_KERNEL);
+ if (!file)
+ goto out_unlock;
+
+- memset(file, 0, sizeof(*file));
+ memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
+- file->f_hash = hash;
+- init_MUTEX(&file->f_sema);
++ mutex_init(&file->f_mutex);
++ INIT_HLIST_NODE(&file->f_list);
++ INIT_LIST_HEAD(&file->f_blocks);
+
+ /* Open the file. Note that this must not sleep for too long, else
+ * we would lock up lockd:-) So no NFS re-exports, folks.
+@@ -116,12 +117,11 @@ nlm_lookup_file(struct svc_rqst *rqstp,
+ * the file.
+ */
+ if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
+- dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr));
++ dprintk("lockd: open failed (error %d)\n", nfserr);
+ goto out_free;
+ }
+
+- file->f_next = nlm_files[hash];
+- nlm_files[hash] = file;
++ hlist_add_head(&file->f_list, &nlm_files[hash]);
+
+ found:
+ dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
+@@ -135,12 +135,6 @@ out_unlock:
+
+ out_free:
+ kfree(file);
+-#ifdef CONFIG_LOCKD_V4
+- if (nfserr == 1)
+- nfserr = nlm4_stale_fh;
+- else
+-#endif
+- nfserr = nlm_lck_denied;
+ goto out_unlock;
+ }
+
+@@ -150,22 +144,14 @@ out_free:
+ static inline void
+ nlm_delete_file(struct nlm_file *file)
+ {
+- struct nlm_file **fp, *f;
+-
+ nlm_debug_print_file("closing file", file);
+-
+- fp = nlm_files + file->f_hash;
+- while ((f = *fp) != NULL) {
+- if (f == file) {
+- *fp = file->f_next;
+- nlmsvc_ops->fclose(file->f_file);
+- kfree(file);
+- return;
+- }
+- fp = &f->f_next;
++ if (!hlist_unhashed(&file->f_list)) {
++ hlist_del(&file->f_list);
++ nlmsvc_ops->fclose(file->f_file);
++ kfree(file);
++ } else {
++ printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
+ }
+-
+- printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
+ }
+
+ /*
+@@ -173,7 +159,8 @@ nlm_delete_file(struct nlm_file *file)
+ * action.
+ */
+ static int
+-nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
++nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
++ nlm_host_match_fn_t match)
+ {
+ struct inode *inode = nlmsvc_file_inode(file);
+ struct file_lock *fl;
+@@ -187,17 +174,11 @@ again:
+
+ /* update current lock count */
+ file->f_locks++;
++
+ lockhost = (struct nlm_host *) fl->fl_owner;
+- if (action == NLM_ACT_MARK)
+- lockhost->h_inuse = 1;
+- else if (action == NLM_ACT_CHECK)
+- return 1;
+- else if (action == NLM_ACT_UNLOCK) {
++ if (match(lockhost, host)) {
+ struct file_lock lock = *fl;
+
+- if (host && lockhost != host)
+- continue;
+-
+ lock.fl_type = F_UNLCK;
+ lock.fl_start = 0;
+ lock.fl_end = OFFSET_MAX;
+@@ -214,53 +195,66 @@ again:
+ }
+
+ /*
+- * Operate on a single file
++ * Inspect a single file
++ */
++static inline int
++nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
++{
++ nlmsvc_traverse_blocks(host, file, match);
++ nlmsvc_traverse_shares(host, file, match);
++ return nlm_traverse_locks(host, file, match);
++}
++
++/*
++ * Quick check whether there are still any locks, blocks or
++ * shares on a given file.
+ */
+ static inline int
+-nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
++nlm_file_inuse(struct nlm_file *file)
+ {
+- if (action == NLM_ACT_CHECK) {
+- /* Fast path for mark and sweep garbage collection */
+- if (file->f_count || file->f_blocks || file->f_shares)
++ struct inode *inode = nlmsvc_file_inode(file);
++ struct file_lock *fl;
++
++ if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
++ return 1;
++
++ for (fl = inode->i_flock; fl; fl = fl->fl_next) {
++ if (fl->fl_lmops == &nlmsvc_lock_operations)
+ return 1;
+- } else {
+- nlmsvc_traverse_blocks(host, file, action);
+- nlmsvc_traverse_shares(host, file, action);
+ }
+- return nlm_traverse_locks(host, file, action);
++ file->f_locks = 0;
++ return 0;
+ }
+
+ /*
+ * Loop over all files in the file table.
+ */
+ static int
+-nlm_traverse_files(struct nlm_host *host, int action)
++nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
+ {
+- struct nlm_file *file, **fp;
++ struct hlist_node *pos, *next;
++ struct nlm_file *file;
+ int i, ret = 0;
+
+ mutex_lock(&nlm_file_mutex);
+ for (i = 0; i < FILE_NRHASH; i++) {
+- fp = nlm_files + i;
+- while ((file = *fp) != NULL) {
++ hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
+ file->f_count++;
+ mutex_unlock(&nlm_file_mutex);
+
+ /* Traverse locks, blocks and shares of this file
+ * and update file->f_locks count */
+- if (nlm_inspect_file(host, file, action))
++ if (nlm_inspect_file(host, file, match))
+ ret = 1;
+
+ mutex_lock(&nlm_file_mutex);
+ file->f_count--;
+ /* No more references to this file. Let go of it. */
+- if (!file->f_blocks && !file->f_locks
++ if (list_empty(&file->f_blocks) && !file->f_locks
+ && !file->f_shares && !file->f_count) {
+- *fp = file->f_next;
++ hlist_del(&file->f_list);
+ nlmsvc_ops->fclose(file->f_file);
+ kfree(file);
+- } else {
+- fp = &file->f_next;
+ }
+ }
+ }
+@@ -287,23 +281,63 @@ nlm_release_file(struct nlm_file *file)
+ mutex_lock(&nlm_file_mutex);
+
+ /* If there are no more locks etc, delete the file */
+- if(--file->f_count == 0) {
+- if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
+- nlm_delete_file(file);
+- }
++ if (--file->f_count == 0 && !nlm_file_inuse(file))
++ nlm_delete_file(file);
+
+ mutex_unlock(&nlm_file_mutex);
+ }
+
+ /*
++ * Helpers function for resource traversal
++ *
++ * nlmsvc_mark_host:
++ * used by the garbage collector; simply sets h_inuse.
++ * Always returns 0.
++ *
++ * nlmsvc_same_host:
++ * returns 1 iff the two hosts match. Used to release
++ * all resources bound to a specific host.
++ *
++ * nlmsvc_is_client:
++ * returns 1 iff the host is a client.
++ * Used by nlmsvc_invalidate_all
++ */
++static int
++nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
++{
++ host->h_inuse = 1;
++ return 0;
++}
++
++static int
++nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
++{
++ return host == other;
++}
++
++static int
++nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
++{
++ if (host->h_server) {
++ /* we are destroying locks even though the client
++ * hasn't asked us too, so don't unmonitor the
++ * client
++ */
++ if (host->h_nsmhandle)
++ host->h_nsmhandle->sm_sticky = 1;
++ return 1;
++ } else
++ return 0;
++}
++
++/*
+ * Mark all hosts that still hold resources
+ */
+ void
+ nlmsvc_mark_resources(void)
+ {
+ dprintk("lockd: nlmsvc_mark_resources\n");
+-
+- nlm_traverse_files(NULL, NLM_ACT_MARK);
++ nlm_traverse_files(NULL, nlmsvc_mark_host);
+ }
+
+ /*
+@@ -314,23 +348,25 @@ nlmsvc_free_host_resources(struct nlm_ho
+ {
+ dprintk("lockd: nlmsvc_free_host_resources\n");
+
+- if (nlm_traverse_files(host, NLM_ACT_UNLOCK))
++ if (nlm_traverse_files(host, nlmsvc_same_host)) {
+ printk(KERN_WARNING
+- "lockd: couldn't remove all locks held by %s",
++ "lockd: couldn't remove all locks held by %s\n",
+ host->h_name);
++ BUG();
++ }
+ }
+
+ /*
+- * delete all hosts structs for clients
++ * Remove all locks held for clients
+ */
+ void
+ nlmsvc_invalidate_all(void)
+ {
+- struct nlm_host *host;
+- while ((host = nlm_find_client()) != NULL) {
+- nlmsvc_free_host_resources(host);
+- host->h_expires = 0;
+- host->h_killed = 1;
+- nlm_release_host(host);
+- }
++ /* Release all locks held by NFS clients.
++ * Previously, the code would call
++ * nlmsvc_free_host_resources for each client in
++ * turn, which is about as inefficient as it gets.
++ * Now we just do it once in nlm_traverse_files.
++ */
++ nlm_traverse_files(NULL, nlmsvc_is_client);
+ }
+diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
+index 033ea4a..b7c9492 100644
+--- a/fs/lockd/xdr.c
++++ b/fs/lockd/xdr.c
+@@ -43,7 +43,7 @@ loff_t_to_s32(loff_t offset)
+ /*
+ * XDR functions for basic NLM types
+ */
+-static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
++static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
+ {
+ unsigned int len;
+
+@@ -69,8 +69,8 @@ static u32 *nlm_decode_cookie(u32 *p, st
+ return p;
+ }
+
+-static inline u32 *
+-nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
++static inline __be32 *
++nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
+ {
+ *p++ = htonl(c->len);
+ memcpy(p, c->data, c->len);
+@@ -78,8 +78,8 @@ nlm_encode_cookie(u32 *p, struct nlm_coo
+ return p;
+ }
+
+-static u32 *
+-nlm_decode_fh(u32 *p, struct nfs_fh *f)
++static __be32 *
++nlm_decode_fh(__be32 *p, struct nfs_fh *f)
+ {
+ unsigned int len;
+
+@@ -95,8 +95,8 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f)
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
+ }
+
+-static inline u32 *
+-nlm_encode_fh(u32 *p, struct nfs_fh *f)
++static inline __be32 *
++nlm_encode_fh(__be32 *p, struct nfs_fh *f)
+ {
+ *p++ = htonl(NFS2_FHSIZE);
+ memcpy(p, f->data, NFS2_FHSIZE);
+@@ -106,20 +106,20 @@ nlm_encode_fh(u32 *p, struct nfs_fh *f)
+ /*
+ * Encode and decode owner handle
+ */
+-static inline u32 *
+-nlm_decode_oh(u32 *p, struct xdr_netobj *oh)
++static inline __be32 *
++nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
+ {
+ return xdr_decode_netobj(p, oh);
+ }
+
+-static inline u32 *
+-nlm_encode_oh(u32 *p, struct xdr_netobj *oh)
++static inline __be32 *
++nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
+ {
+ return xdr_encode_netobj(p, oh);
+ }
+
+-static u32 *
+-nlm_decode_lock(u32 *p, struct nlm_lock *lock)
++static __be32 *
++nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
+ {
+ struct file_lock *fl = &lock->fl;
+ s32 start, len, end;
+@@ -153,8 +153,8 @@ nlm_decode_lock(u32 *p, struct nlm_lock
+ /*
+ * Encode a lock as part of an NLM call
+ */
+-static u32 *
+-nlm_encode_lock(u32 *p, struct nlm_lock *lock)
++static __be32 *
++nlm_encode_lock(__be32 *p, struct nlm_lock *lock)
+ {
+ struct file_lock *fl = &lock->fl;
+ __s32 start, len;
+@@ -184,8 +184,8 @@ nlm_encode_lock(u32 *p, struct nlm_lock
+ /*
+ * Encode result of a TEST/TEST_MSG call
+ */
+-static u32 *
+-nlm_encode_testres(u32 *p, struct nlm_res *resp)
++static __be32 *
++nlm_encode_testres(__be32 *p, struct nlm_res *resp)
+ {
+ s32 start, len;
+
+@@ -221,7 +221,7 @@ nlm_encode_testres(u32 *p, struct nlm_re
+ * First, the server side XDR functions
+ */
+ int
+-nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ u32 exclusive;
+
+@@ -238,7 +238,7 @@ nlmsvc_decode_testargs(struct svc_rqst *
+ }
+
+ int
+-nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_encode_testres(p, resp)))
+ return 0;
+@@ -246,7 +246,7 @@ nlmsvc_encode_testres(struct svc_rqst *r
+ }
+
+ int
+-nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ u32 exclusive;
+
+@@ -266,7 +266,7 @@ nlmsvc_decode_lockargs(struct svc_rqst *
+ }
+
+ int
+-nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ u32 exclusive;
+
+@@ -282,7 +282,7 @@ nlmsvc_decode_cancargs(struct svc_rqst *
+ }
+
+ int
+-nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ if (!(p = nlm_decode_cookie(p, &argp->cookie))
+ || !(p = nlm_decode_lock(p, &argp->lock)))
+@@ -292,7 +292,7 @@ nlmsvc_decode_unlockargs(struct svc_rqst
+ }
+
+ int
+-nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -313,7 +313,7 @@ nlmsvc_decode_shareargs(struct svc_rqst
+ }
+
+ int
+-nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
+ return 0;
+@@ -323,7 +323,7 @@ nlmsvc_encode_shareres(struct svc_rqst *
+ }
+
+ int
+-nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
+ return 0;
+@@ -332,7 +332,7 @@ nlmsvc_encode_res(struct svc_rqst *rqstp
+ }
+
+ int
+-nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
++nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -344,7 +344,7 @@ nlmsvc_decode_notify(struct svc_rqst *rq
+ }
+
+ int
+-nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
++nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
+ {
+ if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
+ return 0;
+@@ -357,7 +357,7 @@ nlmsvc_decode_reboot(struct svc_rqst *rq
+ }
+
+ int
+-nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_decode_cookie(p, &resp->cookie)))
+ return 0;
+@@ -366,13 +366,13 @@ nlmsvc_decode_res(struct svc_rqst *rqstp
+ }
+
+ int
+-nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_argsize_check(rqstp, p);
+ }
+
+ int
+-nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_ressize_check(rqstp, p);
+ }
+@@ -389,7 +389,7 @@ nlmclt_decode_void(struct rpc_rqst *req,
+ #endif
+
+ static int
+-nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -403,7 +403,7 @@ nlmclt_encode_testargs(struct rpc_rqst *
+ }
+
+ static int
+-nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_decode_cookie(p, &resp->cookie)))
+ return -EIO;
+@@ -438,7 +438,7 @@ nlmclt_decode_testres(struct rpc_rqst *r
+
+
+ static int
+-nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -455,7 +455,7 @@ nlmclt_encode_lockargs(struct rpc_rqst *
+ }
+
+ static int
+-nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -470,7 +470,7 @@ nlmclt_encode_cancargs(struct rpc_rqst *
+ }
+
+ static int
+-nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -483,7 +483,7 @@ nlmclt_encode_unlockargs(struct rpc_rqst
+ }
+
+ static int
+-nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
+ return -EIO;
+@@ -493,7 +493,7 @@ nlmclt_encode_res(struct rpc_rqst *req,
+ }
+
+ static int
+-nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_encode_testres(p, resp)))
+ return -EIO;
+@@ -502,7 +502,7 @@ nlmclt_encode_testres(struct rpc_rqst *r
+ }
+
+ static int
+-nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm_decode_cookie(p, &resp->cookie)))
+ return -EIO;
+@@ -515,7 +515,7 @@ nlmclt_decode_res(struct rpc_rqst *req,
+ */
+ #define NLM_void_sz 0
+ #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
+-#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(system_utsname.nodename))
++#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(utsname()->nodename))
+ #define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ)
+ /* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */
+ #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE)
+diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
+index 36eb175..f4c0b2b 100644
+--- a/fs/lockd/xdr4.c
++++ b/fs/lockd/xdr4.c
+@@ -44,8 +44,8 @@ loff_t_to_s64(loff_t offset)
+ /*
+ * XDR functions for basic NLM types
+ */
+-static u32 *
+-nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
++static __be32 *
++nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
+ {
+ unsigned int len;
+
+@@ -71,8 +71,8 @@ nlm4_decode_cookie(u32 *p, struct nlm_co
+ return p;
+ }
+
+-static u32 *
+-nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
++static __be32 *
++nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
+ {
+ *p++ = htonl(c->len);
+ memcpy(p, c->data, c->len);
+@@ -80,8 +80,8 @@ nlm4_encode_cookie(u32 *p, struct nlm_co
+ return p;
+ }
+
+-static u32 *
+-nlm4_decode_fh(u32 *p, struct nfs_fh *f)
++static __be32 *
++nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
+ {
+ memset(f->data, 0, sizeof(f->data));
+ f->size = ntohl(*p++);
+@@ -95,8 +95,8 @@ nlm4_decode_fh(u32 *p, struct nfs_fh *f)
+ return p + XDR_QUADLEN(f->size);
+ }
+
+-static u32 *
+-nlm4_encode_fh(u32 *p, struct nfs_fh *f)
++static __be32 *
++nlm4_encode_fh(__be32 *p, struct nfs_fh *f)
+ {
+ *p++ = htonl(f->size);
+ if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
+@@ -107,20 +107,20 @@ nlm4_encode_fh(u32 *p, struct nfs_fh *f)
+ /*
+ * Encode and decode owner handle
+ */
+-static u32 *
+-nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
++static __be32 *
++nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
+ {
+ return xdr_decode_netobj(p, oh);
+ }
+
+-static u32 *
+-nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
++static __be32 *
++nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh)
+ {
+ return xdr_encode_netobj(p, oh);
+ }
+
+-static u32 *
+-nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
++static __be32 *
++nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
+ {
+ struct file_lock *fl = &lock->fl;
+ __s64 len, start, end;
+@@ -153,8 +153,8 @@ nlm4_decode_lock(u32 *p, struct nlm_lock
+ /*
+ * Encode a lock as part of an NLM call
+ */
+-static u32 *
+-nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
++static __be32 *
++nlm4_encode_lock(__be32 *p, struct nlm_lock *lock)
+ {
+ struct file_lock *fl = &lock->fl;
+ __s64 start, len;
+@@ -185,8 +185,8 @@ nlm4_encode_lock(u32 *p, struct nlm_lock
+ /*
+ * Encode result of a TEST/TEST_MSG call
+ */
+-static u32 *
+-nlm4_encode_testres(u32 *p, struct nlm_res *resp)
++static __be32 *
++nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
+ {
+ s64 start, len;
+
+@@ -227,7 +227,7 @@ nlm4_encode_testres(u32 *p, struct nlm_r
+ * First, the server side XDR functions
+ */
+ int
+-nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ u32 exclusive;
+
+@@ -244,7 +244,7 @@ nlm4svc_decode_testargs(struct svc_rqst
+ }
+
+ int
+-nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_encode_testres(p, resp)))
+ return 0;
+@@ -252,7 +252,7 @@ nlm4svc_encode_testres(struct svc_rqst *
+ }
+
+ int
+-nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ u32 exclusive;
+
+@@ -272,7 +272,7 @@ nlm4svc_decode_lockargs(struct svc_rqst
+ }
+
+ int
+-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ u32 exclusive;
+
+@@ -288,7 +288,7 @@ nlm4svc_decode_cancargs(struct svc_rqst
+ }
+
+ int
+-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+ || !(p = nlm4_decode_lock(p, &argp->lock)))
+@@ -298,7 +298,7 @@ nlm4svc_decode_unlockargs(struct svc_rqs
+ }
+
+ int
+-nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
++nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -319,7 +319,7 @@ nlm4svc_decode_shareargs(struct svc_rqst
+ }
+
+ int
+-nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return 0;
+@@ -329,7 +329,7 @@ nlm4svc_encode_shareres(struct svc_rqst
+ }
+
+ int
+-nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return 0;
+@@ -338,7 +338,7 @@ nlm4svc_encode_res(struct svc_rqst *rqst
+ }
+
+ int
+-nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
++nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -350,7 +350,7 @@ nlm4svc_decode_notify(struct svc_rqst *r
+ }
+
+ int
+-nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
++nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
+ {
+ if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
+ return 0;
+@@ -363,7 +363,7 @@ nlm4svc_decode_reboot(struct svc_rqst *r
+ }
+
+ int
+-nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
++nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+ return 0;
+@@ -372,13 +372,13 @@ nlm4svc_decode_res(struct svc_rqst *rqst
+ }
+
+ int
+-nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_argsize_check(rqstp, p);
+ }
+
+ int
+-nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_ressize_check(rqstp, p);
+ }
+@@ -388,14 +388,14 @@ nlm4svc_encode_void(struct svc_rqst *rqs
+ */
+ #ifdef NLMCLNT_SUPPORT_SHARES
+ static int
+-nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
++nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr)
+ {
+ return 0;
+ }
+ #endif
+
+ static int
+-nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -409,7 +409,7 @@ nlm4clt_encode_testargs(struct rpc_rqst
+ }
+
+ static int
+-nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+ return -EIO;
+@@ -444,7 +444,7 @@ nlm4clt_decode_testres(struct rpc_rqst *
+
+
+ static int
+-nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -461,7 +461,7 @@ nlm4clt_encode_lockargs(struct rpc_rqst
+ }
+
+ static int
+-nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -476,7 +476,7 @@ nlm4clt_encode_cancargs(struct rpc_rqst
+ }
+
+ static int
+-nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
++nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
+ {
+ struct nlm_lock *lock = &argp->lock;
+
+@@ -489,7 +489,7 @@ nlm4clt_encode_unlockargs(struct rpc_rqs
+ }
+
+ static int
+-nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return -EIO;
+@@ -499,7 +499,7 @@ nlm4clt_encode_res(struct rpc_rqst *req,
+ }
+
+ static int
+-nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_encode_testres(p, resp)))
+ return -EIO;
+@@ -508,7 +508,7 @@ nlm4clt_encode_testres(struct rpc_rqst *
+ }
+
+ static int
+-nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
++nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
+ {
+ if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+ return -EIO;
+diff --git a/fs/locks.c b/fs/locks.c
+index d7c5339..e0b6a80 100644
+--- a/fs/locks.c
++++ b/fs/locks.c
+@@ -314,13 +314,13 @@ static int flock_to_posix_lock(struct fi
+ off_t start, end;
+
+ switch (l->l_whence) {
+- case 0: /*SEEK_SET*/
++ case SEEK_SET:
+ start = 0;
+ break;
+- case 1: /*SEEK_CUR*/
++ case SEEK_CUR:
+ start = filp->f_pos;
+ break;
+- case 2: /*SEEK_END*/
++ case SEEK_END:
+ start = i_size_read(filp->f_dentry->d_inode);
+ break;
+ default:
+@@ -364,13 +364,13 @@ static int flock64_to_posix_lock(struct
+ loff_t start;
+
+ switch (l->l_whence) {
+- case 0: /*SEEK_SET*/
++ case SEEK_SET:
+ start = 0;
+ break;
+- case 1: /*SEEK_CUR*/
++ case SEEK_CUR:
+ start = filp->f_pos;
+ break;
+- case 2: /*SEEK_END*/
++ case SEEK_END:
+ start = i_size_read(filp->f_dentry->d_inode);
+ break;
+ default:
+@@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, stru
+ goto out_unlock;
+ }
+
+- error = f_setown(filp, current->pid, 0);
++ error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
+ out_unlock:
+ unlock_kernel();
+ return error;
+diff --git a/fs/mbcache.c b/fs/mbcache.c
+index e4fde1a..0ff7125 100644
+--- a/fs/mbcache.c
++++ b/fs/mbcache.c
+@@ -160,6 +160,7 @@ __mb_cache_entry_forget(struct mb_cache_
+
+ static void
+ __mb_cache_entry_release_unlock(struct mb_cache_entry *ce)
++ __releases(mb_cache_spinlock)
+ {
+ /* Wake up all processes queuing for this cache entry. */
+ if (ce->e_queued)
+diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
+index 4a6abc4..df6b107 100644
+--- a/fs/minix/bitmap.c
++++ b/fs/minix/bitmap.c
+@@ -254,7 +254,7 @@ struct inode * minix_new_inode(const str
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_ino = j;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+ memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
+ insert_inode_hash(inode);
+ mark_inode_dirty(inode);
+diff --git a/fs/minix/file.c b/fs/minix/file.c
+index 420b328..40eac2e 100644
+--- a/fs/minix/file.c
++++ b/fs/minix/file.c
+@@ -17,8 +17,10 @@ int minix_sync_file(struct file *, struc
+
+ const struct file_operations minix_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .fsync = minix_sync_file,
+ .sendfile = generic_file_sendfile,
+diff --git a/fs/minix/inode.c b/fs/minix/inode.c
+index 330ff9f..1e36bae 100644
+--- a/fs/minix/inode.c
++++ b/fs/minix/inode.c
+@@ -90,8 +90,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(minix_inode_cachep))
+- printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(minix_inode_cachep);
+ }
+
+ static struct super_operations minix_sops = {
+@@ -145,18 +144,13 @@ static int minix_fill_super(struct super
+ struct inode *root_inode;
+ struct minix_sb_info *sbi;
+
+- sbi = kmalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ s->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(struct minix_sb_info));
+
+- /* N.B. These should be compile-time tests.
+- Unfortunately that is impossible. */
+- if (32 != sizeof (struct minix_inode))
+- panic("bad V1 i-node size");
+- if (64 != sizeof(struct minix2_inode))
+- panic("bad V2 i-node size");
++ BUILD_BUG_ON(32 != sizeof (struct minix_inode));
++ BUILD_BUG_ON(64 != sizeof(struct minix2_inode));
+
+ if (!sb_set_blocksize(s, BLOCK_SIZE))
+ goto out_bad_hblock;
+@@ -207,10 +201,9 @@ static int minix_fill_super(struct super
+ if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
+ goto out_illegal_sb;
+ i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
+- map = kmalloc(i, GFP_KERNEL);
++ map = kzalloc(i, GFP_KERNEL);
+ if (!map)
+ goto out_no_map;
+- memset(map, 0, i);
+ sbi->s_imap = &map[0];
+ sbi->s_zmap = &map[sbi->s_imap_blocks];
+
+@@ -399,7 +392,7 @@ static void V1_minix_read_inode(struct i
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_atime.tv_nsec = 0;
+ inode->i_ctime.tv_nsec = 0;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+ for (i = 0; i < 9; i++)
+ minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
+ minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
+@@ -432,7 +425,7 @@ static void V2_minix_read_inode(struct i
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_atime.tv_nsec = 0;
+ inode->i_ctime.tv_nsec = 0;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+ for (i = 0; i < 10; i++)
+ minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
+ minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
+diff --git a/fs/minix/namei.c b/fs/minix/namei.c
+index 5b6a454..299bb66 100644
+--- a/fs/minix/namei.c
++++ b/fs/minix/namei.c
+@@ -249,7 +249,7 @@ static int minix_rename(struct inode * o
+ minix_set_link(new_de, new_page, old_inode);
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+ if (dir_de)
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ inode_dec_link_count(new_inode);
+ } else {
+ if (dir_de) {
+diff --git a/fs/mpage.c b/fs/mpage.c
+index 1e45982..692a3e5 100644
+--- a/fs/mpage.c
++++ b/fs/mpage.c
+@@ -693,6 +693,8 @@ out:
+ * the call was made get new I/O started against them. If wbc->sync_mode is
+ * WB_SYNC_ALL then we were called for data integrity and we must wait for
+ * existing IO to complete.
++ *
++ * If you fix this you should check generic_writepages() also!
+ */
+ int
+ mpage_writepages(struct address_space *mapping,
+diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
+index 9e44158..b0f01b3 100644
+--- a/fs/msdos/namei.c
++++ b/fs/msdos/namei.c
+@@ -280,7 +280,7 @@ static int msdos_create(struct inode *di
+ struct nameidata *nd)
+ {
+ struct super_block *sb = dir->i_sb;
+- struct inode *inode;
++ struct inode *inode = NULL;
+ struct fat_slot_info sinfo;
+ struct timespec ts;
+ unsigned char msdos_name[MSDOS_NAME];
+@@ -316,6 +316,8 @@ static int msdos_create(struct inode *di
+ d_instantiate(dentry, inode);
+ out:
+ unlock_kernel();
++ if (!err)
++ err = fat_flush_inodes(sb, dir, inode);
+ return err;
+ }
+
+@@ -341,13 +343,15 @@ static int msdos_rmdir(struct inode *dir
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+- dir->i_nlink--;
++ drop_nlink(dir);
+
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ fat_detach(inode);
+ out:
+ unlock_kernel();
++ if (!err)
++ err = fat_flush_inodes(inode->i_sb, dir, inode);
+
+ return err;
+ }
+@@ -385,7 +389,7 @@ static int msdos_mkdir(struct inode *dir
+ err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
+ if (err)
+ goto out_free;
+- dir->i_nlink++;
++ inc_nlink(dir);
+
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ brelse(sinfo.bh);
+@@ -401,6 +405,7 @@ static int msdos_mkdir(struct inode *dir
+ d_instantiate(dentry, inode);
+
+ unlock_kernel();
++ fat_flush_inodes(sb, dir, inode);
+ return 0;
+
+ out_free:
+@@ -425,11 +430,13 @@ static int msdos_unlink(struct inode *di
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ fat_detach(inode);
+ out:
+ unlock_kernel();
++ if (!err)
++ err = fat_flush_inodes(inode->i_sb, dir, inode);
+
+ return err;
+ }
+@@ -542,9 +549,9 @@ static int do_msdos_rename(struct inode
+ if (err)
+ goto error_dotdot;
+ }
+- old_dir->i_nlink--;
++ drop_nlink(old_dir);
+ if (!new_inode)
+- new_dir->i_nlink++;
++ inc_nlink(new_dir);
+ }
+
+ err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
+@@ -559,10 +566,9 @@ static int do_msdos_rename(struct inode
+ mark_inode_dirty(old_dir);
+
+ if (new_inode) {
++ drop_nlink(new_inode);
+ if (is_dir)
+- new_inode->i_nlink -= 2;
+- else
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ new_inode->i_ctime = ts;
+ }
+ out:
+@@ -635,6 +641,8 @@ static int msdos_rename(struct inode *ol
+ new_dir, new_msdos_name, new_dentry, is_hid);
+ out:
+ unlock_kernel();
++ if (!err)
++ err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir);
+ return err;
+ }
+
+diff --git a/fs/namei.c b/fs/namei.c
+index 432d6bc..28d49b3 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -372,6 +372,30 @@ void release_open_intent(struct nameidat
+ fput(nd->intent.open.file);
+ }
+
++static inline struct dentry *
++do_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ int status = dentry->d_op->d_revalidate(dentry, nd);
++ if (unlikely(status <= 0)) {
++ /*
++ * The dentry failed validation.
++ * If d_revalidate returned 0 attempt to invalidate
++ * the dentry otherwise d_revalidate is asking us
++ * to return a fail status.
++ */
++ if (!status) {
++ if (!d_invalidate(dentry)) {
++ dput(dentry);
++ dentry = NULL;
++ }
++ } else {
++ dput(dentry);
++ dentry = ERR_PTR(status);
++ }
++ }
++ return dentry;
++}
++
+ /*
+ * Internal lookup() using the new generic dcache.
+ * SMP-safe
+@@ -386,12 +410,9 @@ static struct dentry * cached_lookup(str
+ if (!dentry)
+ dentry = d_lookup(parent, name);
+
+- if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
+- if (!dentry->d_op->d_revalidate(dentry, nd) && !d_invalidate(dentry)) {
+- dput(dentry);
+- dentry = NULL;
+- }
+- }
++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
++ dentry = do_revalidate(dentry, nd);
++
+ return dentry;
+ }
+
+@@ -484,10 +505,9 @@ static struct dentry * real_lookup(struc
+ */
+ mutex_unlock(&dir->i_mutex);
+ if (result->d_op && result->d_op->d_revalidate) {
+- if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) {
+- dput(result);
++ result = do_revalidate(result, nd);
++ if (!result)
+ result = ERR_PTR(-ENOENT);
+- }
+ }
+ return result;
+ }
+@@ -498,18 +518,20 @@ static int __emul_lookup_dentry(const ch
+ static __always_inline int
+ walk_init_root(const char *name, struct nameidata *nd)
+ {
+- read_lock(¤t->fs->lock);
+- if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+- nd->mnt = mntget(current->fs->altrootmnt);
+- nd->dentry = dget(current->fs->altroot);
+- read_unlock(¤t->fs->lock);
++ struct fs_struct *fs = current->fs;
++
++ read_lock(&fs->lock);
++ if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
++ nd->mnt = mntget(fs->altrootmnt);
++ nd->dentry = dget(fs->altroot);
++ read_unlock(&fs->lock);
+ if (__emul_lookup_dentry(name,nd))
+ return 0;
+- read_lock(¤t->fs->lock);
++ read_lock(&fs->lock);
+ }
+- nd->mnt = mntget(current->fs->rootmnt);
+- nd->dentry = dget(current->fs->root);
+- read_unlock(¤t->fs->lock);
++ nd->mnt = mntget(fs->rootmnt);
++ nd->dentry = dget(fs->root);
++ read_unlock(&fs->lock);
+ return 1;
+ }
+
+@@ -704,17 +726,19 @@ int follow_down(struct vfsmount **mnt, s
+
+ static __always_inline void follow_dotdot(struct nameidata *nd)
+ {
++ struct fs_struct *fs = current->fs;
++
+ while(1) {
+ struct vfsmount *parent;
+ struct dentry *old = nd->dentry;
+
+- read_lock(¤t->fs->lock);
+- if (nd->dentry == current->fs->root &&
+- nd->mnt == current->fs->rootmnt) {
+- read_unlock(¤t->fs->lock);
++ read_lock(&fs->lock);
++ if (nd->dentry == fs->root &&
++ nd->mnt == fs->rootmnt) {
++ read_unlock(&fs->lock);
+ break;
+ }
+- read_unlock(¤t->fs->lock);
++ read_unlock(&fs->lock);
+ spin_lock(&dcache_lock);
+ if (nd->dentry != nd->mnt->mnt_root) {
+ nd->dentry = dget(nd->dentry->d_parent);
+@@ -767,12 +791,12 @@ need_lookup:
+ goto done;
+
+ need_revalidate:
+- if (dentry->d_op->d_revalidate(dentry, nd))
+- goto done;
+- if (d_invalidate(dentry))
+- goto done;
+- dput(dentry);
+- goto need_lookup;
++ dentry = do_revalidate(dentry, nd);
++ if (!dentry)
++ goto need_lookup;
++ if (IS_ERR(dentry))
++ goto fail;
++ goto done;
+
+ fail:
+ return PTR_ERR(dentry);
+@@ -1022,15 +1046,17 @@ static int __emul_lookup_dentry(const ch
+ struct vfsmount *old_mnt = nd->mnt;
+ struct qstr last = nd->last;
+ int last_type = nd->last_type;
++ struct fs_struct *fs = current->fs;
++
+ /*
+- * NAME was not found in alternate root or it's a directory. Try to find
+- * it in the normal root:
++ * NAME was not found in alternate root or it's a directory.
++ * Try to find it in the normal root:
+ */
+ nd->last_type = LAST_ROOT;
+- read_lock(¤t->fs->lock);
+- nd->mnt = mntget(current->fs->rootmnt);
+- nd->dentry = dget(current->fs->root);
+- read_unlock(¤t->fs->lock);
++ read_lock(&fs->lock);
++ nd->mnt = mntget(fs->rootmnt);
++ nd->dentry = dget(fs->root);
++ read_unlock(&fs->lock);
+ if (path_walk(name, nd) == 0) {
+ if (nd->dentry->d_inode) {
+ dput(old_dentry);
+@@ -1054,6 +1080,7 @@ void set_fs_altroot(void)
+ struct vfsmount *mnt = NULL, *oldmnt;
+ struct dentry *dentry = NULL, *olddentry;
+ int err;
++ struct fs_struct *fs = current->fs;
+
+ if (!emul)
+ goto set_it;
+@@ -1063,12 +1090,12 @@ void set_fs_altroot(void)
+ dentry = nd.dentry;
+ }
+ set_it:
+- write_lock(¤t->fs->lock);
+- oldmnt = current->fs->altrootmnt;
+- olddentry = current->fs->altroot;
+- current->fs->altrootmnt = mnt;
+- current->fs->altroot = dentry;
+- write_unlock(¤t->fs->lock);
++ write_lock(&fs->lock);
++ oldmnt = fs->altrootmnt;
++ olddentry = fs->altroot;
++ fs->altrootmnt = mnt;
++ fs->altroot = dentry;
++ write_unlock(&fs->lock);
+ if (olddentry) {
+ dput(olddentry);
+ mntput(oldmnt);
+@@ -1082,29 +1109,30 @@ static int fastcall do_path_lookup(int d
+ int retval = 0;
+ int fput_needed;
+ struct file *file;
++ struct fs_struct *fs = current->fs;
+
+ nd->last_type = LAST_ROOT; /* if there are only slashes... */
+ nd->flags = flags;
+ nd->depth = 0;
+
+ if (*name=='/') {
+- read_lock(¤t->fs->lock);
+- if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+- nd->mnt = mntget(current->fs->altrootmnt);
+- nd->dentry = dget(current->fs->altroot);
+- read_unlock(¤t->fs->lock);
++ read_lock(&fs->lock);
++ if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
++ nd->mnt = mntget(fs->altrootmnt);
++ nd->dentry = dget(fs->altroot);
++ read_unlock(&fs->lock);
+ if (__emul_lookup_dentry(name,nd))
+ goto out; /* found in altroot */
+- read_lock(¤t->fs->lock);
++ read_lock(&fs->lock);
+ }
+- nd->mnt = mntget(current->fs->rootmnt);
+- nd->dentry = dget(current->fs->root);
+- read_unlock(¤t->fs->lock);
++ nd->mnt = mntget(fs->rootmnt);
++ nd->dentry = dget(fs->root);
++ read_unlock(&fs->lock);
+ } else if (dfd == AT_FDCWD) {
+- read_lock(¤t->fs->lock);
+- nd->mnt = mntget(current->fs->pwdmnt);
+- nd->dentry = dget(current->fs->pwd);
+- read_unlock(¤t->fs->lock);
++ read_lock(&fs->lock);
++ nd->mnt = mntget(fs->pwdmnt);
++ nd->dentry = dget(fs->pwd);
++ read_unlock(&fs->lock);
+ } else {
+ struct dentry *dentry;
+
+@@ -1567,6 +1595,24 @@ int may_open(struct nameidata *nd, int a
+ return 0;
+ }
+
++static int open_namei_create(struct nameidata *nd, struct path *path,
++ int flag, int mode)
++{
++ int error;
++ struct dentry *dir = nd->dentry;
++
++ if (!IS_POSIXACL(dir->d_inode))
++ mode &= ~current->fs->umask;
++ error = vfs_create(dir->d_inode, path->dentry, mode, nd);
++ mutex_unlock(&dir->d_inode->i_mutex);
++ dput(nd->dentry);
++ nd->dentry = path->dentry;
++ if (error)
++ return error;
++ /* Don't check for write permission, don't truncate */
++ return may_open(nd, 0, flag & ~O_TRUNC);
++}
++
+ /*
+ * open_namei()
+ *
+@@ -1648,18 +1694,10 @@ do_last:
+
+ /* Negative dentry, just create the file */
+ if (!path.dentry->d_inode) {
+- if (!IS_POSIXACL(dir->d_inode))
+- mode &= ~current->fs->umask;
+- error = vfs_create(dir->d_inode, path.dentry, mode, nd);
+- mutex_unlock(&dir->d_inode->i_mutex);
+- dput(nd->dentry);
+- nd->dentry = path.dentry;
++ error = open_namei_create(nd, &path, flag, mode);
+ if (error)
+ goto exit;
+- /* Don't check for write permission, don't truncate */
+- acc_mode = 0;
+- flag &= ~O_TRUNC;
+- goto ok;
++ return 0;
+ }
+
+ /*
+@@ -1906,30 +1944,32 @@ asmlinkage long sys_mkdirat(int dfd, con
+ {
+ int error = 0;
+ char * tmp;
++ struct dentry *dentry;
++ struct nameidata nd;
+
+ tmp = getname(pathname);
+ error = PTR_ERR(tmp);
+- if (!IS_ERR(tmp)) {
+- struct dentry *dentry;
+- struct nameidata nd;
++ if (IS_ERR(tmp))
++ goto out_err;
+
+- error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
+- if (error)
+- goto out;
+- dentry = lookup_create(&nd, 1);
+- error = PTR_ERR(dentry);
+- if (!IS_ERR(dentry)) {
+- if (!IS_POSIXACL(nd.dentry->d_inode))
+- mode &= ~current->fs->umask;
+- error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
+- dput(dentry);
+- }
+- mutex_unlock(&nd.dentry->d_inode->i_mutex);
+- path_release(&nd);
+-out:
+- putname(tmp);
+- }
++ error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
++ if (error)
++ goto out;
++ dentry = lookup_create(&nd, 1);
++ error = PTR_ERR(dentry);
++ if (IS_ERR(dentry))
++ goto out_unlock;
+
++ if (!IS_POSIXACL(nd.dentry->d_inode))
++ mode &= ~current->fs->umask;
++ error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
++ dput(dentry);
++out_unlock:
++ mutex_unlock(&nd.dentry->d_inode->i_mutex);
++ path_release(&nd);
++out:
++ putname(tmp);
++out_err:
+ return error;
+ }
+
+@@ -2028,10 +2068,11 @@ static long do_rmdir(int dfd, const char
+ mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_hash(&nd);
+ error = PTR_ERR(dentry);
+- if (!IS_ERR(dentry)) {
+- error = vfs_rmdir(nd.dentry->d_inode, dentry);
+- dput(dentry);
+- }
++ if (IS_ERR(dentry))
++ goto exit2;
++ error = vfs_rmdir(nd.dentry->d_inode, dentry);
++ dput(dentry);
++exit2:
+ mutex_unlock(&nd.dentry->d_inode->i_mutex);
+ exit1:
+ path_release(&nd);
+@@ -2171,30 +2212,33 @@ asmlinkage long sys_symlinkat(const char
+ int error = 0;
+ char * from;
+ char * to;
++ struct dentry *dentry;
++ struct nameidata nd;
+
+ from = getname(oldname);
+ if(IS_ERR(from))
+ return PTR_ERR(from);
+ to = getname(newname);
+ error = PTR_ERR(to);
+- if (!IS_ERR(to)) {
+- struct dentry *dentry;
+- struct nameidata nd;
++ if (IS_ERR(to))
++ goto out_putname;
+
+- error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
+- if (error)
+- goto out;
+- dentry = lookup_create(&nd, 0);
+- error = PTR_ERR(dentry);
+- if (!IS_ERR(dentry)) {
+- error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
+- dput(dentry);
+- }
+- mutex_unlock(&nd.dentry->d_inode->i_mutex);
+- path_release(&nd);
++ error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
++ if (error)
++ goto out;
++ dentry = lookup_create(&nd, 0);
++ error = PTR_ERR(dentry);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++
++ error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
++ dput(dentry);
++out_unlock:
++ mutex_unlock(&nd.dentry->d_inode->i_mutex);
++ path_release(&nd);
+ out:
+- putname(to);
+- }
++ putname(to);
++out_putname:
+ putname(from);
+ return error;
+ }
+@@ -2280,10 +2324,11 @@ asmlinkage long sys_linkat(int olddfd, c
+ goto out_release;
+ new_dentry = lookup_create(&nd, 0);
+ error = PTR_ERR(new_dentry);
+- if (!IS_ERR(new_dentry)) {
+- error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+- dput(new_dentry);
+- }
++ if (IS_ERR(new_dentry))
++ goto out_unlock;
++ error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
++ dput(new_dentry);
++out_unlock:
+ mutex_unlock(&nd.dentry->d_inode->i_mutex);
+ out_release:
+ path_release(&nd);
+@@ -2370,7 +2415,8 @@ static int vfs_rename_dir(struct inode *
+ dput(new_dentry);
+ }
+ if (!error)
+- d_move(old_dentry,new_dentry);
++ if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
++ d_move(old_dentry,new_dentry);
+ return error;
+ }
+
+@@ -2393,8 +2439,7 @@ static int vfs_rename_other(struct inode
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (!error) {
+- /* The following d_move() should become unconditional */
+- if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
++ if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
+ d_move(old_dentry, new_dentry);
+ }
+ if (target)
+diff --git a/fs/namespace.c b/fs/namespace.c
+index fa7ed6a..55442a6 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -13,30 +13,22 @@
+ #include <linux/sched.h>
+ #include <linux/smp_lock.h>
+ #include <linux/init.h>
++#include <linux/kernel.h>
+ #include <linux/quotaops.h>
+ #include <linux/acct.h>
+ #include <linux/capability.h>
+ #include <linux/module.h>
++#include <linux/sysfs.h>
+ #include <linux/seq_file.h>
+ #include <linux/namespace.h>
+ #include <linux/namei.h>
+ #include <linux/security.h>
+ #include <linux/mount.h>
++#include <linux/ramfs.h>
+ #include <asm/uaccess.h>
+ #include <asm/unistd.h>
+ #include "pnode.h"
+
+-extern int __init init_rootfs(void);
+-
+-#ifdef CONFIG_SYSFS
+-extern int __init sysfs_init(void);
+-#else
+-static inline int sysfs_init(void)
+-{
+- return 0;
+-}
+-#endif
+-
+ /* spinlock for vfsmount related operations, inplace of dcache_lock */
+ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
+
+@@ -141,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmo
+
+ static inline int check_mnt(struct vfsmount *mnt)
+ {
+- return mnt->mnt_namespace == current->namespace;
++ return mnt->mnt_namespace == current->nsproxy->namespace;
+ }
+
+ static void touch_namespace(struct namespace *ns)
+@@ -838,7 +830,7 @@ static int attach_recursive_mnt(struct v
+ if (parent_nd) {
+ detach_mnt(source_mnt, parent_nd);
+ attach_mnt(source_mnt, nd);
+- touch_namespace(current->namespace);
++ touch_namespace(current->nsproxy->namespace);
+ } else {
+ mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
+ commit_tree(source_mnt);
+@@ -1449,7 +1441,7 @@ dput_out:
+ */
+ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
+ {
+- struct namespace *namespace = tsk->namespace;
++ struct namespace *namespace = tsk->nsproxy->namespace;
+ struct namespace *new_ns;
+ struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
+ struct vfsmount *p, *q;
+@@ -1516,7 +1508,7 @@ struct namespace *dup_namespace(struct t
+
+ int copy_namespace(int flags, struct task_struct *tsk)
+ {
+- struct namespace *namespace = tsk->namespace;
++ struct namespace *namespace = tsk->nsproxy->namespace;
+ struct namespace *new_ns;
+ int err = 0;
+
+@@ -1539,7 +1531,7 @@ int copy_namespace(int flags, struct tas
+ goto out;
+ }
+
+- tsk->namespace = new_ns;
++ tsk->nsproxy->namespace = new_ns;
+
+ out:
+ put_namespace(namespace);
+@@ -1762,7 +1754,7 @@ asmlinkage long sys_pivot_root(const cha
+ detach_mnt(user_nd.mnt, &root_parent);
+ attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */
+ attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
+- touch_namespace(current->namespace);
++ touch_namespace(current->nsproxy->namespace);
+ spin_unlock(&vfsmount_lock);
+ chroot_fs_refs(&user_nd, &new_nd);
+ security_sb_post_pivotroot(&user_nd, &new_nd);
+@@ -1788,7 +1780,6 @@ static void __init init_mount_tree(void)
+ {
+ struct vfsmount *mnt;
+ struct namespace *namespace;
+- struct task_struct *g, *p;
+
+ mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
+ if (IS_ERR(mnt))
+@@ -1804,13 +1795,8 @@ static void __init init_mount_tree(void)
+ namespace->root = mnt;
+ mnt->mnt_namespace = namespace;
+
+- init_task.namespace = namespace;
+- read_lock(&tasklist_lock);
+- do_each_thread(g, p) {
+- get_namespace(namespace);
+- p->namespace = namespace;
+- } while_each_thread(g, p);
+- read_unlock(&tasklist_lock);
++ init_task.nsproxy->namespace = namespace;
++ get_namespace(namespace);
+
+ set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
+ set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
+@@ -1821,6 +1807,7 @@ void __init mnt_init(unsigned long mempa
+ struct list_head *d;
+ unsigned int nr_hash;
+ int i;
++ int err;
+
+ init_rwsem(&namespace_sem);
+
+@@ -1861,8 +1848,14 @@ void __init mnt_init(unsigned long mempa
+ d++;
+ i--;
+ } while (i);
+- sysfs_init();
+- subsystem_register(&fs_subsys);
++ err = sysfs_init();
++ if (err)
++ printk(KERN_WARNING "%s: sysfs_init error: %d\n",
++ __FUNCTION__, err);
++ err = subsystem_register(&fs_subsys);
++ if (err)
++ printk(KERN_WARNING "%s: subsystem_register error: %d\n",
++ __FUNCTION__, err);
+ init_rootfs();
+ init_mount_tree();
+ }
+diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
+index b4ee892..458b3b7 100644
+--- a/fs/ncpfs/dir.c
++++ b/fs/ncpfs/dir.c
+@@ -53,6 +53,9 @@ const struct file_operations ncp_dir_ope
+ .read = generic_read_dir,
+ .readdir = ncp_readdir,
+ .ioctl = ncp_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ncp_compat_ioctl,
++#endif
+ };
+
+ struct inode_operations ncp_dir_inode_operations =
+diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
+index e6b7c67..df37524 100644
+--- a/fs/ncpfs/file.c
++++ b/fs/ncpfs/file.c
+@@ -289,6 +289,9 @@ const struct file_operations ncp_file_op
+ .read = ncp_file_read,
+ .write = ncp_file_write,
+ .ioctl = ncp_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = ncp_compat_ioctl,
++#endif
+ .mmap = ncp_mmap,
+ .release = ncp_release,
+ .fsync = ncp_fsync,
+diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
+index 1ddf77b..42e3bef 100644
+--- a/fs/ncpfs/inode.c
++++ b/fs/ncpfs/inode.c
+@@ -81,8 +81,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(ncp_inode_cachep))
+- printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(ncp_inode_cachep);
+ }
+
+ static int ncp_remount(struct super_block *sb, int *flags, char* data)
+@@ -224,7 +223,6 @@ static void ncp_set_attr(struct inode *i
+ inode->i_nlink = 1;
+ inode->i_uid = server->m.uid;
+ inode->i_gid = server->m.gid;
+- inode->i_blksize = NCP_BLOCK_SIZE;
+
+ ncp_update_dates(inode, &nwinfo->i);
+ ncp_update_inode(inode, nwinfo);
+@@ -411,11 +409,10 @@ static int ncp_fill_super(struct super_b
+ #endif
+ struct ncp_entry_info finfo;
+
+- server = kmalloc(sizeof(struct ncp_server), GFP_KERNEL);
++ server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
+ if (!server)
+ return -ENOMEM;
+ sb->s_fs_info = server;
+- memset(server, 0, sizeof(struct ncp_server));
+
+ error = -EFAULT;
+ if (raw_data == NULL)
+diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
+index 42039fe..589d1ea 100644
+--- a/fs/ncpfs/ioctl.c
++++ b/fs/ncpfs/ioctl.c
+@@ -7,19 +7,21 @@
+ *
+ */
+
+-
+-#include <asm/uaccess.h>
+ #include <linux/capability.h>
++#include <linux/compat.h>
+ #include <linux/errno.h>
+ #include <linux/fs.h>
+ #include <linux/ioctl.h>
+ #include <linux/time.h>
+ #include <linux/mm.h>
+ #include <linux/highuid.h>
++#include <linux/smp_lock.h>
+ #include <linux/vmalloc.h>
+
+ #include <linux/ncp_fs.h>
+
++#include <asm/uaccess.h>
++
+ #include "ncplib_kernel.h"
+
+ /* maximum limit for ncp_objectname_ioctl */
+@@ -89,6 +91,82 @@ ncp_get_fs_info_v2(struct ncp_server * s
+ return 0;
+ }
+
++#ifdef CONFIG_COMPAT
++struct compat_ncp_objectname_ioctl
++{
++ s32 auth_type;
++ u32 object_name_len;
++ compat_caddr_t object_name; /* an userspace data, in most cases user name */
++};
++
++struct compat_ncp_fs_info_v2 {
++ s32 version;
++ u32 mounted_uid;
++ u32 connection;
++ u32 buffer_size;
++
++ u32 volume_number;
++ u32 directory_id;
++
++ u32 dummy1;
++ u32 dummy2;
++ u32 dummy3;
++};
++
++struct compat_ncp_ioctl_request {
++ u32 function;
++ u32 size;
++ compat_caddr_t data;
++};
++
++struct compat_ncp_privatedata_ioctl
++{
++ u32 len;
++ compat_caddr_t data; /* ~1000 for NDS */
++};
++
++#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2)
++#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request)
++#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl)
++#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl)
++#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
++#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
++
++static int
++ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
++ struct compat_ncp_fs_info_v2 __user * arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ struct compat_ncp_fs_info_v2 info2;
++
++ if ((file_permission(file, MAY_WRITE) != 0)
++ && (current->uid != server->m.mounted_uid)) {
++ return -EACCES;
++ }
++ if (copy_from_user(&info2, arg, sizeof(info2)))
++ return -EFAULT;
++
++ if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
++ DPRINTK("info.version invalid: %d\n", info2.version);
++ return -EINVAL;
++ }
++ info2.mounted_uid = server->m.mounted_uid;
++ info2.connection = server->connection;
++ info2.buffer_size = server->buffer_size;
++ info2.volume_number = NCP_FINFO(inode)->volNumber;
++ info2.directory_id = NCP_FINFO(inode)->DosDirNum;
++ info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
++
++ if (copy_to_user(arg, &info2, sizeof(info2)))
++ return -EFAULT;
++ return 0;
++}
++#endif
++
++#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16)
++#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32)
++#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64)
++
+ #ifdef CONFIG_NCPFS_NLS
+ /* Here we are select the iocharset and the codepage for NLS.
+ * Thanks Petr Vandrovec for idea and many hints.
+@@ -192,12 +270,24 @@ int ncp_ioctl(struct inode *inode, struc
+ void __user *argp = (void __user *)arg;
+
+ switch (cmd) {
++#ifdef CONFIG_COMPAT
++ case NCP_IOC_NCPREQUEST_32:
++#endif
+ case NCP_IOC_NCPREQUEST:
+-
+ if ((file_permission(filp, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid)) {
+ return -EACCES;
+ }
++#ifdef CONFIG_COMPAT
++ if (cmd == NCP_IOC_NCPREQUEST_32) {
++ struct compat_ncp_ioctl_request request32;
++ if (copy_from_user(&request32, argp, sizeof(request32)))
++ return -EFAULT;
++ request.function = request32.function;
++ request.size = request32.size;
++ request.data = compat_ptr(request32.data);
++ } else
++#endif
+ if (copy_from_user(&request, argp, sizeof(request)))
+ return -EFAULT;
+
+@@ -254,19 +344,35 @@ int ncp_ioctl(struct inode *inode, struc
+ case NCP_IOC_GET_FS_INFO_V2:
+ return ncp_get_fs_info_v2(server, filp, argp);
+
+- case NCP_IOC_GETMOUNTUID2:
+- {
+- unsigned long tmp = server->m.mounted_uid;
+-
+- if ((file_permission(filp, MAY_READ) != 0)
+- && (current->uid != server->m.mounted_uid))
+- {
+- return -EACCES;
+- }
+- if (put_user(tmp, (unsigned long __user *)argp))
++#ifdef CONFIG_COMPAT
++ case NCP_IOC_GET_FS_INFO_V2_32:
++ return ncp_get_compat_fs_info_v2(server, filp, argp);
++#endif
++ /* we have too many combinations of CONFIG_COMPAT,
++ * CONFIG_64BIT and CONFIG_UID16, so just handle
++ * any of the possible ioctls */
++ case NCP_IOC_GETMOUNTUID16:
++ case NCP_IOC_GETMOUNTUID32:
++ case NCP_IOC_GETMOUNTUID64:
++ if ((file_permission(filp, MAY_READ) != 0)
++ && (current->uid != server->m.mounted_uid)) {
++ return -EACCES;
++ }
++ if (cmd == NCP_IOC_GETMOUNTUID16) {
++ u16 uid;
++ SET_UID(uid, server->m.mounted_uid);
++ if (put_user(uid, (u16 __user *)argp))
++ return -EFAULT;
++ } else if (cmd == NCP_IOC_GETMOUNTUID32) {
++ if (put_user(server->m.mounted_uid,
++ (u32 __user *)argp))
++ return -EFAULT;
++ } else {
++ if (put_user(server->m.mounted_uid,
++ (u64 __user *)argp))
+ return -EFAULT;
+- return 0;
+ }
++ return 0;
+
+ case NCP_IOC_GETROOT:
+ {
+@@ -476,6 +582,32 @@ outrel:
+ }
+ #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
+
++#ifdef CONFIG_COMPAT
++ case NCP_IOC_GETOBJECTNAME_32:
++ if (current->uid != server->m.mounted_uid) {
++ return -EACCES;
++ }
++ {
++ struct compat_ncp_objectname_ioctl user;
++ size_t outl;
++
++ if (copy_from_user(&user, argp, sizeof(user)))
++ return -EFAULT;
++ user.auth_type = server->auth.auth_type;
++ outl = user.object_name_len;
++ user.object_name_len = server->auth.object_name_len;
++ if (outl > user.object_name_len)
++ outl = user.object_name_len;
++ if (outl) {
++ if (copy_to_user(compat_ptr(user.object_name),
++ server->auth.object_name,
++ outl)) return -EFAULT;
++ }
++ if (copy_to_user(argp, &user, sizeof(user)))
++ return -EFAULT;
++ return 0;
++ }
++#endif
+ case NCP_IOC_GETOBJECTNAME:
+ if (current->uid != server->m.mounted_uid) {
+ return -EACCES;
+@@ -500,6 +632,9 @@ outrel:
+ return -EFAULT;
+ return 0;
+ }
++#ifdef CONFIG_COMPAT
++ case NCP_IOC_SETOBJECTNAME_32:
++#endif
+ case NCP_IOC_SETOBJECTNAME:
+ if (current->uid != server->m.mounted_uid) {
+ return -EACCES;
+@@ -512,8 +647,19 @@ outrel:
+ void* oldprivate;
+ size_t oldprivatelen;
+
++#ifdef CONFIG_COMPAT
++ if (cmd == NCP_IOC_SETOBJECTNAME_32) {
++ struct compat_ncp_objectname_ioctl user32;
++ if (copy_from_user(&user32, argp, sizeof(user32)))
++ return -EFAULT;
++ user.auth_type = user32.auth_type;
++ user.object_name_len = user32.object_name_len;
++ user.object_name = compat_ptr(user32.object_name);
++ } else
++#endif
+ if (copy_from_user(&user, argp, sizeof(user)))
+ return -EFAULT;
++
+ if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
+ return -ENOMEM;
+ if (user.object_name_len) {
+@@ -544,6 +690,9 @@ outrel:
+ kfree(oldname);
+ return 0;
+ }
++#ifdef CONFIG_COMPAT
++ case NCP_IOC_GETPRIVATEDATA_32:
++#endif
+ case NCP_IOC_GETPRIVATEDATA:
+ if (current->uid != server->m.mounted_uid) {
+ return -EACCES;
+@@ -552,8 +701,18 @@ outrel:
+ struct ncp_privatedata_ioctl user;
+ size_t outl;
+
++#ifdef CONFIG_COMPAT
++ if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
++ struct compat_ncp_privatedata_ioctl user32;
++ if (copy_from_user(&user32, argp, sizeof(user32)))
++ return -EFAULT;
++ user.len = user32.len;
++ user.data = compat_ptr(user32.data);
++ } else
++#endif
+ if (copy_from_user(&user, argp, sizeof(user)))
+ return -EFAULT;
++
+ outl = user.len;
+ user.len = server->priv.len;
+ if (outl > user.len) outl = user.len;
+@@ -562,10 +721,23 @@ outrel:
+ server->priv.data,
+ outl)) return -EFAULT;
+ }
++#ifdef CONFIG_COMPAT
++ if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
++ struct compat_ncp_privatedata_ioctl user32;
++ user32.len = user.len;
++ user32.data = (unsigned long) user.data;
++ if (copy_to_user(argp, &user32, sizeof(user32)))
++ return -EFAULT;
++ } else
++#endif
+ if (copy_to_user(argp, &user, sizeof(user)))
+ return -EFAULT;
++
+ return 0;
+ }
++#ifdef CONFIG_COMPAT
++ case NCP_IOC_SETPRIVATEDATA_32:
++#endif
+ case NCP_IOC_SETPRIVATEDATA:
+ if (current->uid != server->m.mounted_uid) {
+ return -EACCES;
+@@ -576,8 +748,18 @@ outrel:
+ void* old;
+ size_t oldlen;
+
++#ifdef CONFIG_COMPAT
++ if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
++ struct compat_ncp_privatedata_ioctl user32;
++ if (copy_from_user(&user32, argp, sizeof(user32)))
++ return -EFAULT;
++ user.len = user32.len;
++ user.data = compat_ptr(user32.data);
++ } else
++#endif
+ if (copy_from_user(&user, argp, sizeof(user)))
+ return -EFAULT;
++
+ if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
+ return -ENOMEM;
+ if (user.len) {
+@@ -636,20 +818,19 @@ outrel:
+ }
+
+ }
+-/* #ifdef CONFIG_UID16 */
+- /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
+- so we have this out of switch */
+- if (cmd == NCP_IOC_GETMOUNTUID) {
+- __kernel_uid_t uid = 0;
+- if ((file_permission(filp, MAY_READ) != 0)
+- && (current->uid != server->m.mounted_uid)) {
+- return -EACCES;
+- }
+- SET_UID(uid, server->m.mounted_uid);
+- if (put_user(uid, (__kernel_uid_t __user *)argp))
+- return -EFAULT;
+- return 0;
+- }
+-/* #endif */
+ return -EINVAL;
+ }
++
++#ifdef CONFIG_COMPAT
++long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int ret;
++
++ lock_kernel();
++ arg = (unsigned long) compat_ptr(arg);
++ ret = ncp_ioctl(inode, file, cmd, arg);
++ unlock_kernel();
++ return ret;
++}
++#endif
+diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
+index ca92c24..e3d26c1 100644
+--- a/fs/ncpfs/symlink.c
++++ b/fs/ncpfs/symlink.c
+@@ -48,7 +48,7 @@ static int ncp_symlink_readpage(struct f
+ char *buf = kmap(page);
+
+ error = -ENOMEM;
+- rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
++ rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
+ if (!rawlink)
+ goto fail;
+
+@@ -126,7 +126,7 @@ int ncp_symlink(struct inode *dir, struc
+ /* EPERM is returned by VFS if symlink procedure does not exist */
+ return -EPERM;
+
+- rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
++ rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
+ if (!rawlink)
+ return -ENOMEM;
+
+diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
+index 0b572a0..f4580b4 100644
+--- a/fs/nfs/Makefile
++++ b/fs/nfs/Makefile
+@@ -4,9 +4,9 @@
+
+ obj-$(CONFIG_NFS_FS) += nfs.o
+
+-nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
+- proc.o read.o symlink.o unlink.o write.o \
+- namespace.o
++nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
++ pagelist.o proc.o read.o symlink.o unlink.o \
++ write.o namespace.o
+ nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
+ nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
+ nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
+diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
+index fe0a6b8..7933e2e 100644
+--- a/fs/nfs/callback.c
++++ b/fs/nfs/callback.c
+@@ -19,6 +19,7 @@
+
+ #include "nfs4_fs.h"
+ #include "callback.h"
++#include "internal.h"
+
+ #define NFSDBG_FACILITY NFSDBG_CALLBACK
+
+@@ -36,13 +37,27 @@ static struct svc_program nfs4_callback_
+
+ unsigned int nfs_callback_set_tcpport;
+ unsigned short nfs_callback_tcpport;
++static const int nfs_set_port_min = 0;
++static const int nfs_set_port_max = 65535;
++
++static int param_set_port(const char *val, struct kernel_param *kp)
++{
++ char *endp;
++ int num = simple_strtol(val, &endp, 0);
++ if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
++ return -EINVAL;
++ *((int *)kp->arg) = num;
++ return 0;
++}
++
++module_param_call(callback_tcpport, param_set_port, param_get_int,
++ &nfs_callback_set_tcpport, 0644);
+
+ /*
+ * This is the callback kernel thread.
+ */
+ static void nfs_callback_svc(struct svc_rqst *rqstp)
+ {
+- struct svc_serv *serv = rqstp->rq_server;
+ int err;
+
+ __module_get(THIS_MODULE);
+@@ -64,7 +79,7 @@ static void nfs_callback_svc(struct svc_
+ /*
+ * Listen for a request on the socket
+ */
+- err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT);
++ err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
+ if (err == -EAGAIN || err == -EINTR)
+ continue;
+ if (err < 0) {
+@@ -75,7 +90,7 @@ static void nfs_callback_svc(struct svc_
+ }
+ dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
+ NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
+- svc_process(serv, rqstp);
++ svc_process(rqstp);
+ }
+
+ svc_exit_thread(rqstp);
+@@ -100,7 +115,7 @@ int nfs_callback_up(void)
+ goto out;
+ init_completion(&nfs_callback_info.started);
+ init_completion(&nfs_callback_info.stopped);
+- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
++ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+ ret = -ENOMEM;
+ if (!serv)
+ goto out_err;
+@@ -134,10 +149,8 @@ out_err:
+ /*
+ * Kill the server process if it is not already up.
+ */
+-int nfs_callback_down(void)
++void nfs_callback_down(void)
+ {
+- int ret = 0;
+-
+ lock_kernel();
+ mutex_lock(&nfs_callback_mutex);
+ nfs_callback_info.users--;
+@@ -149,20 +162,19 @@ int nfs_callback_down(void)
+ } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
+ mutex_unlock(&nfs_callback_mutex);
+ unlock_kernel();
+- return ret;
+ }
+
+ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
+ {
+- struct in_addr *addr = &rqstp->rq_addr.sin_addr;
+- struct nfs4_client *clp;
++ struct sockaddr_in *addr = &rqstp->rq_addr;
++ struct nfs_client *clp;
+
+ /* Don't talk to strangers */
+- clp = nfs4_find_client(addr);
++ clp = nfs_find_client(addr, 4);
+ if (clp == NULL)
+ return SVC_DROP;
+- dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
+- nfs4_put_client(clp);
++ dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr));
++ nfs_put_client(clp);
+ switch (rqstp->rq_authop->flavour) {
+ case RPC_AUTH_NULL:
+ if (rqstp->rq_proc != CB_NULL)
+diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
+index b252e7f..db3d791 100644
+--- a/fs/nfs/callback.h
++++ b/fs/nfs/callback.h
+@@ -31,10 +31,10 @@ struct cb_compound_hdr_arg {
+ };
+
+ struct cb_compound_hdr_res {
+- uint32_t *status;
++ __be32 *status;
+ int taglen;
+ const char *tag;
+- uint32_t *nops;
++ __be32 *nops;
+ };
+
+ struct cb_getattrargs {
+@@ -44,7 +44,7 @@ struct cb_getattrargs {
+ };
+
+ struct cb_getattrres {
+- uint32_t status;
++ __be32 status;
+ uint32_t bitmap[2];
+ uint64_t size;
+ uint64_t change_attr;
+@@ -59,11 +59,16 @@ struct cb_recallargs {
+ uint32_t truncate;
+ };
+
+-extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
+-extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
++extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
++extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
+
++#ifdef CONFIG_NFS_V4
+ extern int nfs_callback_up(void);
+-extern int nfs_callback_down(void);
++extern void nfs_callback_down(void);
++#else
++#define nfs_callback_up() (0)
++#define nfs_callback_down() do {} while(0)
++#endif
+
+ extern unsigned int nfs_callback_set_tcpport;
+ extern unsigned short nfs_callback_tcpport;
+diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
+index 7719483..72e55d8 100644
+--- a/fs/nfs/callback_proc.c
++++ b/fs/nfs/callback_proc.c
+@@ -10,19 +10,20 @@
+ #include "nfs4_fs.h"
+ #include "callback.h"
+ #include "delegation.h"
++#include "internal.h"
+
+ #define NFSDBG_FACILITY NFSDBG_CALLBACK
+
+-unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
++__be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
+ {
+- struct nfs4_client *clp;
++ struct nfs_client *clp;
+ struct nfs_delegation *delegation;
+ struct nfs_inode *nfsi;
+ struct inode *inode;
+
+ res->bitmap[0] = res->bitmap[1] = 0;
+ res->status = htonl(NFS4ERR_BADHANDLE);
+- clp = nfs4_find_client(&args->addr->sin_addr);
++ clp = nfs_find_client(args->addr, 4);
+ if (clp == NULL)
+ goto out;
+ inode = nfs_delegation_find_inode(clp, &args->fh);
+@@ -48,20 +49,20 @@ out_iput:
+ up_read(&nfsi->rwsem);
+ iput(inode);
+ out_putclient:
+- nfs4_put_client(clp);
++ nfs_put_client(clp);
+ out:
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
+ return res->status;
+ }
+
+-unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
++__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
+ {
+- struct nfs4_client *clp;
++ struct nfs_client *clp;
+ struct inode *inode;
+- unsigned res;
++ __be32 res;
+
+ res = htonl(NFS4ERR_BADHANDLE);
+- clp = nfs4_find_client(&args->addr->sin_addr);
++ clp = nfs_find_client(args->addr, 4);
+ if (clp == NULL)
+ goto out;
+ inode = nfs_delegation_find_inode(clp, &args->fh);
+@@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_
+ }
+ iput(inode);
+ out_putclient:
+- nfs4_put_client(clp);
++ nfs_put_client(clp);
+ out:
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
+ return res;
+diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
+index 29f9321..f8ea1f5 100644
+--- a/fs/nfs/callback_xdr.c
++++ b/fs/nfs/callback_xdr.c
+@@ -22,9 +22,9 @@
+
+ #define NFSDBG_FACILITY NFSDBG_CALLBACK
+
+-typedef unsigned (*callback_process_op_t)(void *, void *);
+-typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
+-typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
++typedef __be32 (*callback_process_op_t)(void *, void *);
++typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
++typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
+
+
+ struct callback_op {
+@@ -36,24 +36,24 @@ struct callback_op {
+
+ static struct callback_op callback_ops[];
+
+-static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
++static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ return htonl(NFS4_OK);
+ }
+
+-static int nfs4_decode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
++static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_argsize_check(rqstp, p);
+ }
+
+-static int nfs4_encode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
++static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_ressize_check(rqstp, p);
+ }
+
+-static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes)
++static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = xdr_inline_decode(xdr, nbytes);
+ if (unlikely(p == NULL))
+@@ -61,9 +61,9 @@ static uint32_t *read_buf(struct xdr_str
+ return p;
+ }
+
+-static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
++static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = read_buf(xdr, 4);
+ if (unlikely(p == NULL))
+@@ -81,9 +81,9 @@ static unsigned decode_string(struct xdr
+ return 0;
+ }
+
+-static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
++static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = read_buf(xdr, 4);
+ if (unlikely(p == NULL))
+@@ -99,9 +99,9 @@ static unsigned decode_fh(struct xdr_str
+ return 0;
+ }
+
+-static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
++static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+ {
+- uint32_t *p;
++ __be32 *p;
+ unsigned int attrlen;
+
+ p = read_buf(xdr, 4);
+@@ -118,9 +118,9 @@ static unsigned decode_bitmap(struct xdr
+ return 0;
+ }
+
+-static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
++static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = read_buf(xdr, 16);
+ if (unlikely(p == NULL))
+@@ -129,11 +129,11 @@ static unsigned decode_stateid(struct xd
+ return 0;
+ }
+
+-static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
++static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+ unsigned int minor_version;
+- unsigned status;
++ __be32 status;
+
+ status = decode_string(xdr, &hdr->taglen, &hdr->tag);
+ if (unlikely(status != 0))
+@@ -159,9 +159,9 @@ static unsigned decode_compound_hdr_arg(
+ return 0;
+ }
+
+-static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
++static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
+ {
+- uint32_t *p;
++ __be32 *p;
+ p = read_buf(xdr, 4);
+ if (unlikely(p == NULL))
+ return htonl(NFS4ERR_RESOURCE);
+@@ -169,9 +169,9 @@ static unsigned decode_op_hdr(struct xdr
+ return 0;
+ }
+
+-static unsigned decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
++static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
+ {
+- unsigned status;
++ __be32 status;
+
+ status = decode_fh(xdr, &args->fh);
+ if (unlikely(status != 0))
+@@ -183,10 +183,10 @@ out:
+ return status;
+ }
+
+-static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
++static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
+ {
+- uint32_t *p;
+- unsigned status;
++ __be32 *p;
++ __be32 status;
+
+ args->addr = &rqstp->rq_addr;
+ status = decode_stateid(xdr, &args->stateid);
+@@ -204,9 +204,9 @@ out:
+ return status;
+ }
+
+-static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
++static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = xdr_reserve_space(xdr, 4 + len);
+ if (unlikely(p == NULL))
+@@ -217,10 +217,10 @@ static unsigned encode_string(struct xdr
+
+ #define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
+ #define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
+-static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep)
++static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep)
+ {
+- uint32_t bm[2];
+- uint32_t *p;
++ __be32 bm[2];
++ __be32 *p;
+
+ bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
+ bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
+@@ -247,9 +247,9 @@ static unsigned encode_attr_bitmap(struc
+ return 0;
+ }
+
+-static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
++static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
+ return 0;
+@@ -260,9 +260,9 @@ static unsigned encode_attr_change(struc
+ return 0;
+ }
+
+-static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
++static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ if (!(bitmap[0] & FATTR4_WORD0_SIZE))
+ return 0;
+@@ -273,9 +273,9 @@ static unsigned encode_attr_size(struct
+ return 0;
+ }
+
+-static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
++static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = xdr_reserve_space(xdr, 12);
+ if (unlikely(p == 0))
+@@ -285,23 +285,23 @@ static unsigned encode_attr_time(struct
+ return 0;
+ }
+
+-static unsigned encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
++static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+ {
+ if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
+ return 0;
+ return encode_attr_time(xdr,time);
+ }
+
+-static unsigned encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
++static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+ {
+ if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
+ return 0;
+ return encode_attr_time(xdr,time);
+ }
+
+-static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
++static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
+ {
+- unsigned status;
++ __be32 status;
+
+ hdr->status = xdr_reserve_space(xdr, 4);
+ if (unlikely(hdr->status == NULL))
+@@ -315,9 +315,9 @@ static unsigned encode_compound_hdr_res(
+ return 0;
+ }
+
+-static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
++static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = xdr_reserve_space(xdr, 8);
+ if (unlikely(p == NULL))
+@@ -327,10 +327,10 @@ static unsigned encode_op_hdr(struct xdr
+ return 0;
+ }
+
+-static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
++static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
+ {
+- uint32_t *savep = NULL;
+- unsigned status = res->status;
++ __be32 *savep = NULL;
++ __be32 status = res->status;
+
+ if (unlikely(status != 0))
+ goto out;
+@@ -353,15 +353,15 @@ out:
+ return status;
+ }
+
+-static unsigned process_op(struct svc_rqst *rqstp,
++static __be32 process_op(struct svc_rqst *rqstp,
+ struct xdr_stream *xdr_in, void *argp,
+ struct xdr_stream *xdr_out, void *resp)
+ {
+ struct callback_op *op = &callback_ops[0];
+ unsigned int op_nr = OP_CB_ILLEGAL;
+- unsigned int status = 0;
++ __be32 status = 0;
+ long maxlen;
+- unsigned res;
++ __be32 res;
+
+ dprintk("%s: start\n", __FUNCTION__);
+ status = decode_op_hdr(xdr_in, &op_nr);
+@@ -399,20 +399,20 @@ static unsigned process_op(struct svc_rq
+ /*
+ * Decode, process and encode a COMPOUND
+ */
+-static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
++static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ struct cb_compound_hdr_arg hdr_arg;
+ struct cb_compound_hdr_res hdr_res;
+ struct xdr_stream xdr_in, xdr_out;
+- uint32_t *p;
+- unsigned int status;
++ __be32 *p;
++ __be32 status;
+ unsigned int nops = 1;
+
+ dprintk("%s: start\n", __FUNCTION__);
+
+ xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
+
+- p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
++ p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
+ xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
+
+ decode_compound_hdr_arg(&xdr_in, &hdr_arg);
+diff --git a/fs/nfs/client.c b/fs/nfs/client.c
+new file mode 100644
+index 0000000..5fea638
+--- /dev/null
++++ b/fs/nfs/client.c
+@@ -0,0 +1,1443 @@
++/* client.c: NFS client sharing and management code
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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/init.h>
++
++#include <linux/time.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/stat.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/sunrpc/clnt.h>
++#include <linux/sunrpc/stats.h>
++#include <linux/sunrpc/metrics.h>
++#include <linux/nfs_fs.h>
++#include <linux/nfs_mount.h>
++#include <linux/nfs4_mount.h>
++#include <linux/lockd/bind.h>
++#include <linux/smp_lock.h>
++#include <linux/seq_file.h>
++#include <linux/mount.h>
++#include <linux/nfs_idmap.h>
++#include <linux/vfs.h>
++#include <linux/inet.h>
++#include <linux/nfs_xdr.h>
++
++#include <asm/system.h>
++
++#include "nfs4_fs.h"
++#include "callback.h"
++#include "delegation.h"
++#include "iostat.h"
++#include "internal.h"
++
++#define NFSDBG_FACILITY NFSDBG_CLIENT
++
++static DEFINE_SPINLOCK(nfs_client_lock);
++static LIST_HEAD(nfs_client_list);
++static LIST_HEAD(nfs_volume_list);
++static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
++
++/*
++ * RPC cruft for NFS
++ */
++static struct rpc_version *nfs_version[5] = {
++ [2] = &nfs_version2,
++#ifdef CONFIG_NFS_V3
++ [3] = &nfs_version3,
++#endif
++#ifdef CONFIG_NFS_V4
++ [4] = &nfs_version4,
++#endif
++};
++
++struct rpc_program nfs_program = {
++ .name = "nfs",
++ .number = NFS_PROGRAM,
++ .nrvers = ARRAY_SIZE(nfs_version),
++ .version = nfs_version,
++ .stats = &nfs_rpcstat,
++ .pipe_dir_name = "/nfs",
++};
++
++struct rpc_stat nfs_rpcstat = {
++ .program = &nfs_program
++};
++
++
++#ifdef CONFIG_NFS_V3_ACL
++static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
++static struct rpc_version * nfsacl_version[] = {
++ [3] = &nfsacl_version3,
++};
++
++struct rpc_program nfsacl_program = {
++ .name = "nfsacl",
++ .number = NFS_ACL_PROGRAM,
++ .nrvers = ARRAY_SIZE(nfsacl_version),
++ .version = nfsacl_version,
++ .stats = &nfsacl_rpcstat,
++};
++#endif /* CONFIG_NFS_V3_ACL */
++
++/*
++ * Allocate a shared client record
++ *
++ * Since these are allocated/deallocated very rarely, we don't
++ * bother putting them in a slab cache...
++ */
++static struct nfs_client *nfs_alloc_client(const char *hostname,
++ const struct sockaddr_in *addr,
++ int nfsversion)
++{
++ struct nfs_client *clp;
++ int error;
++
++ if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
++ goto error_0;
++
++ error = rpciod_up();
++ if (error < 0) {
++ dprintk("%s: couldn't start rpciod! Error = %d\n",
++ __FUNCTION__, error);
++ goto error_1;
++ }
++ __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
++
++ if (nfsversion == 4) {
++ if (nfs_callback_up() < 0)
++ goto error_2;
++ __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
++ }
++
++ atomic_set(&clp->cl_count, 1);
++ clp->cl_cons_state = NFS_CS_INITING;
++
++ clp->cl_nfsversion = nfsversion;
++ memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
++
++ if (hostname) {
++ clp->cl_hostname = kstrdup(hostname, GFP_KERNEL);
++ if (!clp->cl_hostname)
++ goto error_3;
++ }
++
++ INIT_LIST_HEAD(&clp->cl_superblocks);
++ clp->cl_rpcclient = ERR_PTR(-EINVAL);
++
++#ifdef CONFIG_NFS_V4
++ init_rwsem(&clp->cl_sem);
++ INIT_LIST_HEAD(&clp->cl_delegations);
++ INIT_LIST_HEAD(&clp->cl_state_owners);
++ INIT_LIST_HEAD(&clp->cl_unused);
++ spin_lock_init(&clp->cl_lock);
++ INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
++ rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
++ clp->cl_boot_time = CURRENT_TIME;
++ clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
++#endif
++
++ return clp;
++
++error_3:
++ if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
++ nfs_callback_down();
++error_2:
++ rpciod_down();
++ __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
++error_1:
++ kfree(clp);
++error_0:
++ return NULL;
++}
++
++static void nfs4_shutdown_client(struct nfs_client *clp)
++{
++#ifdef CONFIG_NFS_V4
++ if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
++ nfs4_kill_renewd(clp);
++ while (!list_empty(&clp->cl_unused)) {
++ struct nfs4_state_owner *sp;
++
++ sp = list_entry(clp->cl_unused.next,
++ struct nfs4_state_owner,
++ so_list);
++ list_del(&sp->so_list);
++ kfree(sp);
++ }
++ BUG_ON(!list_empty(&clp->cl_state_owners));
++ if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
++ nfs_idmap_delete(clp);
++#endif
++}
++
++/*
++ * Destroy a shared client record
++ */
++static void nfs_free_client(struct nfs_client *clp)
++{
++ dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);
++
++ nfs4_shutdown_client(clp);
++
++ /* -EIO all pending I/O */
++ if (!IS_ERR(clp->cl_rpcclient))
++ rpc_shutdown_client(clp->cl_rpcclient);
++
++ if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
++ nfs_callback_down();
++
++ if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state))
++ rpciod_down();
++
++ kfree(clp->cl_hostname);
++ kfree(clp);
++
++ dprintk("<-- nfs_free_client()\n");
++}
++
++/*
++ * Release a reference to a shared client record
++ */
++void nfs_put_client(struct nfs_client *clp)
++{
++ if (!clp)
++ return;
++
++ dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
++
++ if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
++ list_del(&clp->cl_share_link);
++ spin_unlock(&nfs_client_lock);
++
++ BUG_ON(!list_empty(&clp->cl_superblocks));
++
++ nfs_free_client(clp);
++ }
++}
++
++/*
++ * Find a client by address
++ * - caller must hold nfs_client_lock
++ */
++static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port)
++{
++ struct nfs_client *clp;
++
++ list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
++ /* Don't match clients that failed to initialise properly */
++ if (clp->cl_cons_state < 0)
++ continue;
++
++ /* Different NFS versions cannot share the same nfs_client */
++ if (clp->cl_nfsversion != nfsversion)
++ continue;
++
++ if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr,
++ sizeof(clp->cl_addr.sin_addr)) != 0)
++ continue;
++
++ if (!match_port || clp->cl_addr.sin_port == addr->sin_port)
++ goto found;
++ }
++
++ return NULL;
++
++found:
++ atomic_inc(&clp->cl_count);
++ return clp;
++}
++
++/*
++ * Find a client by IP address and protocol version
++ * - returns NULL if no such client
++ */
++struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
++{
++ struct nfs_client *clp;
++
++ spin_lock(&nfs_client_lock);
++ clp = __nfs_find_client(addr, nfsversion, 0);
++ spin_unlock(&nfs_client_lock);
++ if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) {
++ nfs_put_client(clp);
++ clp = NULL;
++ }
++ return clp;
++}
++
++/*
++ * Look up a client by IP address and protocol version
++ * - creates a new record if one doesn't yet exist
++ */
++static struct nfs_client *nfs_get_client(const char *hostname,
++ const struct sockaddr_in *addr,
++ int nfsversion)
++{
++ struct nfs_client *clp, *new = NULL;
++ int error;
++
++ dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n",
++ hostname ?: "", NIPQUAD(addr->sin_addr),
++ addr->sin_port, nfsversion);
++
++ /* see if the client already exists */
++ do {
++ spin_lock(&nfs_client_lock);
++
++ clp = __nfs_find_client(addr, nfsversion, 1);
++ if (clp)
++ goto found_client;
++ if (new)
++ goto install_client;
++
++ spin_unlock(&nfs_client_lock);
++
++ new = nfs_alloc_client(hostname, addr, nfsversion);
++ } while (new);
++
++ return ERR_PTR(-ENOMEM);
++
++ /* install a new client and return with it unready */
++install_client:
++ clp = new;
++ list_add(&clp->cl_share_link, &nfs_client_list);
++ spin_unlock(&nfs_client_lock);
++ dprintk("--> nfs_get_client() = %p [new]\n", clp);
++ return clp;
++
++ /* found an existing client
++ * - make sure it's ready before returning
++ */
++found_client:
++ spin_unlock(&nfs_client_lock);
++
++ if (new)
++ nfs_free_client(new);
++
++ error = wait_event_interruptible(nfs_client_active_wq,
++ clp->cl_cons_state != NFS_CS_INITING);
++ if (error < 0) {
++ nfs_put_client(clp);
++ return ERR_PTR(-ERESTARTSYS);
++ }
++
++ if (clp->cl_cons_state < NFS_CS_READY) {
++ error = clp->cl_cons_state;
++ nfs_put_client(clp);
++ return ERR_PTR(error);
++ }
++
++ BUG_ON(clp->cl_cons_state != NFS_CS_READY);
++
++ dprintk("--> nfs_get_client() = %p [share]\n", clp);
++ return clp;
++}
++
++/*
++ * Mark a server as ready or failed
++ */
++static void nfs_mark_client_ready(struct nfs_client *clp, int state)
++{
++ clp->cl_cons_state = state;
++ wake_up_all(&nfs_client_active_wq);
++}
++
++/*
++ * Initialise the timeout values for a connection
++ */
++static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
++ unsigned int timeo, unsigned int retrans)
++{
++ to->to_initval = timeo * HZ / 10;
++ to->to_retries = retrans;
++ if (!to->to_retries)
++ to->to_retries = 2;
++
++ switch (proto) {
++ case IPPROTO_TCP:
++ if (!to->to_initval)
++ to->to_initval = 60 * HZ;
++ if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
++ to->to_initval = NFS_MAX_TCP_TIMEOUT;
++ to->to_increment = to->to_initval;
++ to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
++ to->to_exponential = 0;
++ break;
++ case IPPROTO_UDP:
++ default:
++ if (!to->to_initval)
++ to->to_initval = 11 * HZ / 10;
++ if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
++ to->to_initval = NFS_MAX_UDP_TIMEOUT;
++ to->to_maxval = NFS_MAX_UDP_TIMEOUT;
++ to->to_exponential = 1;
++ break;
++ }
++}
++
++/*
++ * Create an RPC client handle
++ */
++static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
++ unsigned int timeo,
++ unsigned int retrans,
++ rpc_authflavor_t flavor)
++{
++ struct rpc_timeout timeparms;
++ struct rpc_clnt *clnt = NULL;
++ struct rpc_create_args args = {
++ .protocol = proto,
++ .address = (struct sockaddr *)&clp->cl_addr,
++ .addrsize = sizeof(clp->cl_addr),
++ .timeout = &timeparms,
++ .servername = clp->cl_hostname,
++ .program = &nfs_program,
++ .version = clp->rpc_ops->version,
++ .authflavor = flavor,
++ };
++
++ if (!IS_ERR(clp->cl_rpcclient))
++ return 0;
++
++ nfs_init_timeout_values(&timeparms, proto, timeo, retrans);
++ clp->retrans_timeo = timeparms.to_initval;
++ clp->retrans_count = timeparms.to_retries;
++
++ clnt = rpc_create(&args);
++ if (IS_ERR(clnt)) {
++ dprintk("%s: cannot create RPC client. Error = %ld\n",
++ __FUNCTION__, PTR_ERR(clnt));
++ return PTR_ERR(clnt);
++ }
++
++ clp->cl_rpcclient = clnt;
++ return 0;
++}
++
++/*
++ * Version 2 or 3 client destruction
++ */
++static void nfs_destroy_server(struct nfs_server *server)
++{
++ if (!IS_ERR(server->client_acl))
++ rpc_shutdown_client(server->client_acl);
++
++ if (!(server->flags & NFS_MOUNT_NONLM))
++ lockd_down(); /* release rpc.lockd */
++}
++
++/*
++ * Version 2 or 3 lockd setup
++ */
++static int nfs_start_lockd(struct nfs_server *server)
++{
++ int error = 0;
++
++ if (server->nfs_client->cl_nfsversion > 3)
++ goto out;
++ if (server->flags & NFS_MOUNT_NONLM)
++ goto out;
++ error = lockd_up((server->flags & NFS_MOUNT_TCP) ?
++ IPPROTO_TCP : IPPROTO_UDP);
++ if (error < 0)
++ server->flags |= NFS_MOUNT_NONLM;
++ else
++ server->destroy = nfs_destroy_server;
++out:
++ return error;
++}
++
++/*
++ * Initialise an NFSv3 ACL client connection
++ */
++#ifdef CONFIG_NFS_V3_ACL
++static void nfs_init_server_aclclient(struct nfs_server *server)
++{
++ if (server->nfs_client->cl_nfsversion != 3)
++ goto out_noacl;
++ if (server->flags & NFS_MOUNT_NOACL)
++ goto out_noacl;
++
++ server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
++ if (IS_ERR(server->client_acl))
++ goto out_noacl;
++
++ /* No errors! Assume that Sun nfsacls are supported */
++ server->caps |= NFS_CAP_ACLS;
++ return;
++
++out_noacl:
++ server->caps &= ~NFS_CAP_ACLS;
++}
++#else
++static inline void nfs_init_server_aclclient(struct nfs_server *server)
++{
++ server->flags &= ~NFS_MOUNT_NOACL;
++ server->caps &= ~NFS_CAP_ACLS;
++}
++#endif
++
++/*
++ * Create a general RPC client
++ */
++static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour)
++{
++ struct nfs_client *clp = server->nfs_client;
++
++ server->client = rpc_clone_client(clp->cl_rpcclient);
++ if (IS_ERR(server->client)) {
++ dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
++ return PTR_ERR(server->client);
++ }
++
++ if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
++ struct rpc_auth *auth;
++
++ auth = rpcauth_create(pseudoflavour, server->client);
++ if (IS_ERR(auth)) {
++ dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
++ return PTR_ERR(auth);
++ }
++ }
++ server->client->cl_softrtry = 0;
++ if (server->flags & NFS_MOUNT_SOFT)
++ server->client->cl_softrtry = 1;
++
++ server->client->cl_intr = 0;
++ if (server->flags & NFS4_MOUNT_INTR)
++ server->client->cl_intr = 1;
++
++ return 0;
++}
++
++/*
++ * Initialise an NFS2 or NFS3 client
++ */
++static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data)
++{
++ int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
++ int error;
++
++ if (clp->cl_cons_state == NFS_CS_READY) {
++ /* the client is already initialised */
++ dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp);
++ return 0;
++ }
++
++ /* Check NFS protocol revision and initialize RPC op vector */
++ clp->rpc_ops = &nfs_v2_clientops;
++#ifdef CONFIG_NFS_V3
++ if (clp->cl_nfsversion == 3)
++ clp->rpc_ops = &nfs_v3_clientops;
++#endif
++ /*
++ * Create a client RPC handle for doing FSSTAT with UNIX auth only
++ * - RFC 2623, sec 2.3.2
++ */
++ error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
++ RPC_AUTH_UNIX);
++ if (error < 0)
++ goto error;
++ nfs_mark_client_ready(clp, NFS_CS_READY);
++ return 0;
++
++error:
++ nfs_mark_client_ready(clp, error);
++ dprintk("<-- nfs_init_client() = xerror %d\n", error);
++ return error;
++}
++
++/*
++ * Create a version 2 or 3 client
++ */
++static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data)
++{
++ struct nfs_client *clp;
++ int error, nfsvers = 2;
++
++ dprintk("--> nfs_init_server()\n");
++
++#ifdef CONFIG_NFS_V3
++ if (data->flags & NFS_MOUNT_VER3)
++ nfsvers = 3;
++#endif
++
++ /* Allocate or find a client reference we can use */
++ clp = nfs_get_client(data->hostname, &data->addr, nfsvers);
++ if (IS_ERR(clp)) {
++ dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
++ return PTR_ERR(clp);
++ }
++
++ error = nfs_init_client(clp, data);
++ if (error < 0)
++ goto error;
++
++ server->nfs_client = clp;
++
++ /* Initialise the client representation from the mount data */
++ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
++
++ if (data->rsize)
++ server->rsize = nfs_block_size(data->rsize, NULL);
++ if (data->wsize)
++ server->wsize = nfs_block_size(data->wsize, NULL);
++
++ server->acregmin = data->acregmin * HZ;
++ server->acregmax = data->acregmax * HZ;
++ server->acdirmin = data->acdirmin * HZ;
++ server->acdirmax = data->acdirmax * HZ;
++
++ /* Start lockd here, before we might error out */
++ error = nfs_start_lockd(server);
++ if (error < 0)
++ goto error;
++
++ error = nfs_init_server_rpcclient(server, data->pseudoflavor);
++ if (error < 0)
++ goto error;
++
++ server->namelen = data->namlen;
++ /* Create a client RPC handle for the NFSv3 ACL management interface */
++ nfs_init_server_aclclient(server);
++ if (clp->cl_nfsversion == 3) {
++ if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
++ server->namelen = NFS3_MAXNAMLEN;
++ server->caps |= NFS_CAP_READDIRPLUS;
++ } else {
++ if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
++ server->namelen = NFS2_MAXNAMLEN;
++ }
++
++ dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
++ return 0;
++
++error:
++ server->nfs_client = NULL;
++ nfs_put_client(clp);
++ dprintk("<-- nfs_init_server() = xerror %d\n", error);
++ return error;
++}
++
++/*
++ * Load up the server record from information gained in an fsinfo record
++ */
++static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo)
++{
++ unsigned long max_rpc_payload;
++
++ /* Work out a lot of parameters */
++ if (server->rsize == 0)
++ server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
++ if (server->wsize == 0)
++ server->wsize = nfs_block_size(fsinfo->wtpref, NULL);
++
++ if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
++ server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
++ if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
++ server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
++
++ max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
++ if (server->rsize > max_rpc_payload)
++ server->rsize = max_rpc_payload;
++ if (server->rsize > NFS_MAX_FILE_IO_SIZE)
++ server->rsize = NFS_MAX_FILE_IO_SIZE;
++ server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++ server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
++
++ if (server->wsize > max_rpc_payload)
++ server->wsize = max_rpc_payload;
++ if (server->wsize > NFS_MAX_FILE_IO_SIZE)
++ server->wsize = NFS_MAX_FILE_IO_SIZE;
++ server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++ server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
++
++ server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
++ if (server->dtsize > PAGE_CACHE_SIZE)
++ server->dtsize = PAGE_CACHE_SIZE;
++ if (server->dtsize > server->rsize)
++ server->dtsize = server->rsize;
++
++ if (server->flags & NFS_MOUNT_NOAC) {
++ server->acregmin = server->acregmax = 0;
++ server->acdirmin = server->acdirmax = 0;
++ }
++
++ server->maxfilesize = fsinfo->maxfilesize;
++
++ /* We're airborne Set socket buffersize */
++ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
++}
++
++/*
++ * Probe filesystem information, including the FSID on v2/v3
++ */
++static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
++{
++ struct nfs_fsinfo fsinfo;
++ struct nfs_client *clp = server->nfs_client;
++ int error;
++
++ dprintk("--> nfs_probe_fsinfo()\n");
++
++ if (clp->rpc_ops->set_capabilities != NULL) {
++ error = clp->rpc_ops->set_capabilities(server, mntfh);
++ if (error < 0)
++ goto out_error;
++ }
++
++ fsinfo.fattr = fattr;
++ nfs_fattr_init(fattr);
++ error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
++ if (error < 0)
++ goto out_error;
++
++ nfs_server_set_fsinfo(server, &fsinfo);
++
++ /* Get some general file system info */
++ if (server->namelen == 0) {
++ struct nfs_pathconf pathinfo;
++
++ pathinfo.fattr = fattr;
++ nfs_fattr_init(fattr);
++
++ if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
++ server->namelen = pathinfo.max_namelen;
++ }
++
++ dprintk("<-- nfs_probe_fsinfo() = 0\n");
++ return 0;
++
++out_error:
++ dprintk("nfs_probe_fsinfo: error = %d\n", -error);
++ return error;
++}
++
++/*
++ * Copy useful information when duplicating a server record
++ */
++static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
++{
++ target->flags = source->flags;
++ target->acregmin = source->acregmin;
++ target->acregmax = source->acregmax;
++ target->acdirmin = source->acdirmin;
++ target->acdirmax = source->acdirmax;
++ target->caps = source->caps;
++}
++
++/*
++ * Allocate and initialise a server record
++ */
++static struct nfs_server *nfs_alloc_server(void)
++{
++ struct nfs_server *server;
++
++ server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
++ if (!server)
++ return NULL;
++
++ server->client = server->client_acl = ERR_PTR(-EINVAL);
++
++ /* Zero out the NFS state stuff */
++ INIT_LIST_HEAD(&server->client_link);
++ INIT_LIST_HEAD(&server->master_link);
++
++ server->io_stats = nfs_alloc_iostats();
++ if (!server->io_stats) {
++ kfree(server);
++ return NULL;
++ }
++
++ return server;
++}
++
++/*
++ * Free up a server record
++ */
++void nfs_free_server(struct nfs_server *server)
++{
++ dprintk("--> nfs_free_server()\n");
++
++ spin_lock(&nfs_client_lock);
++ list_del(&server->client_link);
++ list_del(&server->master_link);
++ spin_unlock(&nfs_client_lock);
++
++ if (server->destroy != NULL)
++ server->destroy(server);
++ if (!IS_ERR(server->client))
++ rpc_shutdown_client(server->client);
++
++ nfs_put_client(server->nfs_client);
++
++ nfs_free_iostats(server->io_stats);
++ kfree(server);
++ nfs_release_automount_timer();
++ dprintk("<-- nfs_free_server()\n");
++}
++
++/*
++ * Create a version 2 or 3 volume record
++ * - keyed on server and FSID
++ */
++struct nfs_server *nfs_create_server(const struct nfs_mount_data *data,
++ struct nfs_fh *mntfh)
++{
++ struct nfs_server *server;
++ struct nfs_fattr fattr;
++ int error;
++
++ server = nfs_alloc_server();
++ if (!server)
++ return ERR_PTR(-ENOMEM);
++
++ /* Get a client representation */
++ error = nfs_init_server(server, data);
++ if (error < 0)
++ goto error;
++
++ BUG_ON(!server->nfs_client);
++ BUG_ON(!server->nfs_client->rpc_ops);
++ BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
++
++ /* Probe the root fh to retrieve its FSID */
++ error = nfs_probe_fsinfo(server, mntfh, &fattr);
++ if (error < 0)
++ goto error;
++ if (!(fattr.valid & NFS_ATTR_FATTR)) {
++ error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
++ if (error < 0) {
++ dprintk("nfs_create_server: getattr error = %d\n", -error);
++ goto error;
++ }
++ }
++ memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
++
++ dprintk("Server FSID: %llx:%llx\n",
++ (unsigned long long) server->fsid.major,
++ (unsigned long long) server->fsid.minor);
++
++ BUG_ON(!server->nfs_client);
++ BUG_ON(!server->nfs_client->rpc_ops);
++ BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
++
++ spin_lock(&nfs_client_lock);
++ list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
++ list_add_tail(&server->master_link, &nfs_volume_list);
++ spin_unlock(&nfs_client_lock);
++
++ server->mount_time = jiffies;
++ return server;
++
++error:
++ nfs_free_server(server);
++ return ERR_PTR(error);
++}
++
++#ifdef CONFIG_NFS_V4
++/*
++ * Initialise an NFS4 client record
++ */
++static int nfs4_init_client(struct nfs_client *clp,
++ int proto, int timeo, int retrans,
++ const char *ip_addr,
++ rpc_authflavor_t authflavour)
++{
++ int error;
++
++ if (clp->cl_cons_state == NFS_CS_READY) {
++ /* the client is initialised already */
++ dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
++ return 0;
++ }
++
++ /* Check NFS protocol revision and initialize RPC op vector */
++ clp->rpc_ops = &nfs_v4_clientops;
++
++ error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour);
++ if (error < 0)
++ goto error;
++ memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
++
++ error = nfs_idmap_new(clp);
++ if (error < 0) {
++ dprintk("%s: failed to create idmapper. Error = %d\n",
++ __FUNCTION__, error);
++ goto error;
++ }
++ __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
++
++ nfs_mark_client_ready(clp, NFS_CS_READY);
++ return 0;
++
++error:
++ nfs_mark_client_ready(clp, error);
++ dprintk("<-- nfs4_init_client() = xerror %d\n", error);
++ return error;
++}
++
++/*
++ * Set up an NFS4 client
++ */
++static int nfs4_set_client(struct nfs_server *server,
++ const char *hostname, const struct sockaddr_in *addr,
++ const char *ip_addr,
++ rpc_authflavor_t authflavour,
++ int proto, int timeo, int retrans)
++{
++ struct nfs_client *clp;
++ int error;
++
++ dprintk("--> nfs4_set_client()\n");
++
++ /* Allocate or find a client reference we can use */
++ clp = nfs_get_client(hostname, addr, 4);
++ if (IS_ERR(clp)) {
++ error = PTR_ERR(clp);
++ goto error;
++ }
++ error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour);
++ if (error < 0)
++ goto error_put;
++
++ server->nfs_client = clp;
++ dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
++ return 0;
++
++error_put:
++ nfs_put_client(clp);
++error:
++ dprintk("<-- nfs4_set_client() = xerror %d\n", error);
++ return error;
++}
++
++/*
++ * Create a version 4 volume record
++ */
++static int nfs4_init_server(struct nfs_server *server,
++ const struct nfs4_mount_data *data, rpc_authflavor_t authflavour)
++{
++ int error;
++
++ dprintk("--> nfs4_init_server()\n");
++
++ /* Initialise the client representation from the mount data */
++ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
++ server->caps |= NFS_CAP_ATOMIC_OPEN;
++
++ if (data->rsize)
++ server->rsize = nfs_block_size(data->rsize, NULL);
++ if (data->wsize)
++ server->wsize = nfs_block_size(data->wsize, NULL);
++
++ server->acregmin = data->acregmin * HZ;
++ server->acregmax = data->acregmax * HZ;
++ server->acdirmin = data->acdirmin * HZ;
++ server->acdirmax = data->acdirmax * HZ;
++
++ error = nfs_init_server_rpcclient(server, authflavour);
++
++ /* Done */
++ dprintk("<-- nfs4_init_server() = %d\n", error);
++ return error;
++}
++
++/*
++ * Create a version 4 volume record
++ * - keyed on server and FSID
++ */
++struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
++ const char *hostname,
++ const struct sockaddr_in *addr,
++ const char *mntpath,
++ const char *ip_addr,
++ rpc_authflavor_t authflavour,
++ struct nfs_fh *mntfh)
++{
++ struct nfs_fattr fattr;
++ struct nfs_server *server;
++ int error;
++
++ dprintk("--> nfs4_create_server()\n");
++
++ server = nfs_alloc_server();
++ if (!server)
++ return ERR_PTR(-ENOMEM);
++
++ /* Get a client record */
++ error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour,
++ data->proto, data->timeo, data->retrans);
++ if (error < 0)
++ goto error;
++
++ /* set up the general RPC client */
++ error = nfs4_init_server(server, data, authflavour);
++ if (error < 0)
++ goto error;
++
++ BUG_ON(!server->nfs_client);
++ BUG_ON(!server->nfs_client->rpc_ops);
++ BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
++
++ /* Probe the root fh to retrieve its FSID */
++ error = nfs4_path_walk(server, mntfh, mntpath);
++ if (error < 0)
++ goto error;
++
++ dprintk("Server FSID: %llx:%llx\n",
++ (unsigned long long) server->fsid.major,
++ (unsigned long long) server->fsid.minor);
++ dprintk("Mount FH: %d\n", mntfh->size);
++
++ error = nfs_probe_fsinfo(server, mntfh, &fattr);
++ if (error < 0)
++ goto error;
++
++ BUG_ON(!server->nfs_client);
++ BUG_ON(!server->nfs_client->rpc_ops);
++ BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
++
++ spin_lock(&nfs_client_lock);
++ list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
++ list_add_tail(&server->master_link, &nfs_volume_list);
++ spin_unlock(&nfs_client_lock);
++
++ server->mount_time = jiffies;
++ dprintk("<-- nfs4_create_server() = %p\n", server);
++ return server;
++
++error:
++ nfs_free_server(server);
++ dprintk("<-- nfs4_create_server() = error %d\n", error);
++ return ERR_PTR(error);
++}
++
++/*
++ * Create an NFS4 referral server record
++ */
++struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
++ struct nfs_fh *fh)
++{
++ struct nfs_client *parent_client;
++ struct nfs_server *server, *parent_server;
++ struct nfs_fattr fattr;
++ int error;
++
++ dprintk("--> nfs4_create_referral_server()\n");
++
++ server = nfs_alloc_server();
++ if (!server)
++ return ERR_PTR(-ENOMEM);
++
++ parent_server = NFS_SB(data->sb);
++ parent_client = parent_server->nfs_client;
++
++ /* Get a client representation.
++ * Note: NFSv4 always uses TCP, */
++ error = nfs4_set_client(server, data->hostname, data->addr,
++ parent_client->cl_ipaddr,
++ data->authflavor,
++ parent_server->client->cl_xprt->prot,
++ parent_client->retrans_timeo,
++ parent_client->retrans_count);
++ if (error < 0)
++ goto error;
++
++ /* Initialise the client representation from the parent server */
++ nfs_server_copy_userdata(server, parent_server);
++ server->caps |= NFS_CAP_ATOMIC_OPEN;
++
++ error = nfs_init_server_rpcclient(server, data->authflavor);
++ if (error < 0)
++ goto error;
++
++ BUG_ON(!server->nfs_client);
++ BUG_ON(!server->nfs_client->rpc_ops);
++ BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
++
++ /* probe the filesystem info for this server filesystem */
++ error = nfs_probe_fsinfo(server, fh, &fattr);
++ if (error < 0)
++ goto error;
++
++ dprintk("Referral FSID: %llx:%llx\n",
++ (unsigned long long) server->fsid.major,
++ (unsigned long long) server->fsid.minor);
++
++ spin_lock(&nfs_client_lock);
++ list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
++ list_add_tail(&server->master_link, &nfs_volume_list);
++ spin_unlock(&nfs_client_lock);
++
++ server->mount_time = jiffies;
++
++ dprintk("<-- nfs_create_referral_server() = %p\n", server);
++ return server;
++
++error:
++ nfs_free_server(server);
++ dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
++ return ERR_PTR(error);
++}
++
++#endif /* CONFIG_NFS_V4 */
++
++/*
++ * Clone an NFS2, NFS3 or NFS4 server record
++ */
++struct nfs_server *nfs_clone_server(struct nfs_server *source,
++ struct nfs_fh *fh,
++ struct nfs_fattr *fattr)
++{
++ struct nfs_server *server;
++ struct nfs_fattr fattr_fsinfo;
++ int error;
++
++ dprintk("--> nfs_clone_server(,%llx:%llx,)\n",
++ (unsigned long long) fattr->fsid.major,
++ (unsigned long long) fattr->fsid.minor);
++
++ server = nfs_alloc_server();
++ if (!server)
++ return ERR_PTR(-ENOMEM);
++
++ /* Copy data from the source */
++ server->nfs_client = source->nfs_client;
++ atomic_inc(&server->nfs_client->cl_count);
++ nfs_server_copy_userdata(server, source);
++
++ server->fsid = fattr->fsid;
++
++ error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor);
++ if (error < 0)
++ goto out_free_server;
++ if (!IS_ERR(source->client_acl))
++ nfs_init_server_aclclient(server);
++
++ /* probe the filesystem info for this server filesystem */
++ error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo);
++ if (error < 0)
++ goto out_free_server;
++
++ dprintk("Cloned FSID: %llx:%llx\n",
++ (unsigned long long) server->fsid.major,
++ (unsigned long long) server->fsid.minor);
++
++ error = nfs_start_lockd(server);
++ if (error < 0)
++ goto out_free_server;
++
++ spin_lock(&nfs_client_lock);
++ list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
++ list_add_tail(&server->master_link, &nfs_volume_list);
++ spin_unlock(&nfs_client_lock);
++
++ server->mount_time = jiffies;
++
++ dprintk("<-- nfs_clone_server() = %p\n", server);
++ return server;
++
++out_free_server:
++ nfs_free_server(server);
++ dprintk("<-- nfs_clone_server() = error %d\n", error);
++ return ERR_PTR(error);
++}
++
++#ifdef CONFIG_PROC_FS
++static struct proc_dir_entry *proc_fs_nfs;
++
++static int nfs_server_list_open(struct inode *inode, struct file *file);
++static void *nfs_server_list_start(struct seq_file *p, loff_t *pos);
++static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos);
++static void nfs_server_list_stop(struct seq_file *p, void *v);
++static int nfs_server_list_show(struct seq_file *m, void *v);
++
++static struct seq_operations nfs_server_list_ops = {
++ .start = nfs_server_list_start,
++ .next = nfs_server_list_next,
++ .stop = nfs_server_list_stop,
++ .show = nfs_server_list_show,
++};
++
++static struct file_operations nfs_server_list_fops = {
++ .open = nfs_server_list_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++static int nfs_volume_list_open(struct inode *inode, struct file *file);
++static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos);
++static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos);
++static void nfs_volume_list_stop(struct seq_file *p, void *v);
++static int nfs_volume_list_show(struct seq_file *m, void *v);
++
++static struct seq_operations nfs_volume_list_ops = {
++ .start = nfs_volume_list_start,
++ .next = nfs_volume_list_next,
++ .stop = nfs_volume_list_stop,
++ .show = nfs_volume_list_show,
++};
++
++static struct file_operations nfs_volume_list_fops = {
++ .open = nfs_volume_list_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++/*
++ * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which
++ * we're dealing
++ */
++static int nfs_server_list_open(struct inode *inode, struct file *file)
++{
++ struct seq_file *m;
++ int ret;
++
++ ret = seq_open(file, &nfs_server_list_ops);
++ if (ret < 0)
++ return ret;
++
++ m = file->private_data;
++ m->private = PDE(inode)->data;
++
++ return 0;
++}
++
++/*
++ * set up the iterator to start reading from the server list and return the first item
++ */
++static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
++{
++ struct list_head *_p;
++ loff_t pos = *_pos;
++
++ /* lock the list against modification */
++ spin_lock(&nfs_client_lock);
++
++ /* allow for the header line */
++ if (!pos)
++ return SEQ_START_TOKEN;
++ pos--;
++
++ /* find the n'th element in the list */
++ list_for_each(_p, &nfs_client_list)
++ if (!pos--)
++ break;
++
++ return _p != &nfs_client_list ? _p : NULL;
++}
++
++/*
++ * move to next server
++ */
++static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
++{
++ struct list_head *_p;
++
++ (*pos)++;
++
++ _p = v;
++ _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next;
++
++ return _p != &nfs_client_list ? _p : NULL;
++}
++
++/*
++ * clean up after reading from the transports list
++ */
++static void nfs_server_list_stop(struct seq_file *p, void *v)
++{
++ spin_unlock(&nfs_client_lock);
++}
++
++/*
++ * display a header line followed by a load of call lines
++ */
++static int nfs_server_list_show(struct seq_file *m, void *v)
++{
++ struct nfs_client *clp;
++
++ /* display header on line 1 */
++ if (v == SEQ_START_TOKEN) {
++ seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
++ return 0;
++ }
++
++ /* display one transport per line on subsequent lines */
++ clp = list_entry(v, struct nfs_client, cl_share_link);
++
++ seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n",
++ clp->cl_nfsversion,
++ NIPQUAD(clp->cl_addr.sin_addr),
++ ntohs(clp->cl_addr.sin_port),
++ atomic_read(&clp->cl_count),
++ clp->cl_hostname);
++
++ return 0;
++}
++
++/*
++ * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes
++ */
++static int nfs_volume_list_open(struct inode *inode, struct file *file)
++{
++ struct seq_file *m;
++ int ret;
++
++ ret = seq_open(file, &nfs_volume_list_ops);
++ if (ret < 0)
++ return ret;
++
++ m = file->private_data;
++ m->private = PDE(inode)->data;
++
++ return 0;
++}
++
++/*
++ * set up the iterator to start reading from the volume list and return the first item
++ */
++static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
++{
++ struct list_head *_p;
++ loff_t pos = *_pos;
++
++ /* lock the list against modification */
++ spin_lock(&nfs_client_lock);
++
++ /* allow for the header line */
++ if (!pos)
++ return SEQ_START_TOKEN;
++ pos--;
++
++ /* find the n'th element in the list */
++ list_for_each(_p, &nfs_volume_list)
++ if (!pos--)
++ break;
++
++ return _p != &nfs_volume_list ? _p : NULL;
++}
++
++/*
++ * move to next volume
++ */
++static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
++{
++ struct list_head *_p;
++
++ (*pos)++;
++
++ _p = v;
++ _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next;
++
++ return _p != &nfs_volume_list ? _p : NULL;
++}
++
++/*
++ * clean up after reading from the transports list
++ */
++static void nfs_volume_list_stop(struct seq_file *p, void *v)
++{
++ spin_unlock(&nfs_client_lock);
++}
++
++/*
++ * display a header line followed by a load of call lines
++ */
++static int nfs_volume_list_show(struct seq_file *m, void *v)
++{
++ struct nfs_server *server;
++ struct nfs_client *clp;
++ char dev[8], fsid[17];
++
++ /* display header on line 1 */
++ if (v == SEQ_START_TOKEN) {
++ seq_puts(m, "NV SERVER PORT DEV FSID\n");
++ return 0;
++ }
++ /* display one transport per line on subsequent lines */
++ server = list_entry(v, struct nfs_server, master_link);
++ clp = server->nfs_client;
++
++ snprintf(dev, 8, "%u:%u",
++ MAJOR(server->s_dev), MINOR(server->s_dev));
++
++ snprintf(fsid, 17, "%llx:%llx",
++ (unsigned long long) server->fsid.major,
++ (unsigned long long) server->fsid.minor);
++
++ seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n",
++ clp->cl_nfsversion,
++ NIPQUAD(clp->cl_addr.sin_addr),
++ ntohs(clp->cl_addr.sin_port),
++ dev,
++ fsid);
++
++ return 0;
++}
++
++/*
++ * initialise the /proc/fs/nfsfs/ directory
++ */
++int __init nfs_fs_proc_init(void)
++{
++ struct proc_dir_entry *p;
++
++ proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs);
++ if (!proc_fs_nfs)
++ goto error_0;
++
++ proc_fs_nfs->owner = THIS_MODULE;
++
++ /* a file of servers with which we're dealing */
++ p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs);
++ if (!p)
++ goto error_1;
++
++ p->proc_fops = &nfs_server_list_fops;
++ p->owner = THIS_MODULE;
++
++ /* a file of volumes that we have mounted */
++ p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs);
++ if (!p)
++ goto error_2;
++
++ p->proc_fops = &nfs_volume_list_fops;
++ p->owner = THIS_MODULE;
++ return 0;
++
++error_2:
++ remove_proc_entry("servers", proc_fs_nfs);
++error_1:
++ remove_proc_entry("nfsfs", proc_root_fs);
++error_0:
++ return -ENOMEM;
++}
++
++/*
++ * clean up the /proc/fs/nfsfs/ directory
++ */
++void nfs_fs_proc_exit(void)
++{
++ remove_proc_entry("volumes", proc_fs_nfs);
++ remove_proc_entry("servers", proc_fs_nfs);
++ remove_proc_entry("nfsfs", proc_root_fs);
++}
++
++#endif /* CONFIG_PROC_FS */
+diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
+index 9540a31..841c99a 100644
+--- a/fs/nfs/delegation.c
++++ b/fs/nfs/delegation.c
+@@ -18,11 +18,7 @@
+
+ #include "nfs4_fs.h"
+ #include "delegation.h"
+-
+-static struct nfs_delegation *nfs_alloc_delegation(void)
+-{
+- return (struct nfs_delegation *)kmalloc(sizeof(struct nfs_delegation), GFP_KERNEL);
+-}
++#include "internal.h"
+
+ static void nfs_free_delegation(struct nfs_delegation *delegation)
+ {
+@@ -52,7 +48,7 @@ static int nfs_delegation_claim_locks(st
+ case -NFS4ERR_EXPIRED:
+ /* kill_proc(fl->fl_pid, SIGLOST, 1); */
+ case -NFS4ERR_STALE_CLIENTID:
+- nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs4_state);
++ nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client);
+ goto out_err;
+ }
+ }
+@@ -114,7 +110,7 @@ void nfs_inode_reclaim_delegation(struct
+ */
+ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
+ {
+- struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
++ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_delegation *delegation;
+ int status = 0;
+@@ -123,7 +119,7 @@ int nfs_inode_set_delegation(struct inod
+ if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR)))
+ __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+
+- delegation = nfs_alloc_delegation();
++ delegation = kmalloc(sizeof(*delegation), GFP_KERNEL);
+ if (delegation == NULL)
+ return -ENOMEM;
+ memcpy(delegation->stateid.data, res->delegation.data,
+@@ -145,7 +141,7 @@ int nfs_inode_set_delegation(struct inod
+ sizeof(delegation->stateid)) != 0 ||
+ delegation->type != nfsi->delegation->type) {
+ printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n",
+- __FUNCTION__, NIPQUAD(clp->cl_addr));
++ __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr));
+ status = -EIO;
+ }
+ }
+@@ -176,7 +172,7 @@ static void nfs_msync_inode(struct inode
+ */
+ int __nfs_inode_return_delegation(struct inode *inode)
+ {
+- struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
++ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_delegation *delegation;
+ int res = 0;
+@@ -208,7 +204,7 @@ int __nfs_inode_return_delegation(struct
+ */
+ void nfs_return_all_delegations(struct super_block *sb)
+ {
+- struct nfs4_client *clp = NFS_SB(sb)->nfs4_state;
++ struct nfs_client *clp = NFS_SB(sb)->nfs_client;
+ struct nfs_delegation *delegation;
+ struct inode *inode;
+
+@@ -232,7 +228,7 @@ restart:
+
+ int nfs_do_expire_all_delegations(void *ptr)
+ {
+- struct nfs4_client *clp = ptr;
++ struct nfs_client *clp = ptr;
+ struct nfs_delegation *delegation;
+ struct inode *inode;
+
+@@ -254,11 +250,11 @@ restart:
+ }
+ out:
+ spin_unlock(&clp->cl_lock);
+- nfs4_put_client(clp);
++ nfs_put_client(clp);
+ module_put_and_exit(0);
+ }
+
+-void nfs_expire_all_delegations(struct nfs4_client *clp)
++void nfs_expire_all_delegations(struct nfs_client *clp)
+ {
+ struct task_struct *task;
+
+@@ -266,17 +262,17 @@ void nfs_expire_all_delegations(struct n
+ atomic_inc(&clp->cl_count);
+ task = kthread_run(nfs_do_expire_all_delegations, clp,
+ "%u.%u.%u.%u-delegreturn",
+- NIPQUAD(clp->cl_addr));
++ NIPQUAD(clp->cl_addr.sin_addr));
+ if (!IS_ERR(task))
+ return;
+- nfs4_put_client(clp);
++ nfs_put_client(clp);
+ module_put(THIS_MODULE);
+ }
+
+ /*
+ * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
+ */
+-void nfs_handle_cb_pathdown(struct nfs4_client *clp)
++void nfs_handle_cb_pathdown(struct nfs_client *clp)
+ {
+ struct nfs_delegation *delegation;
+ struct inode *inode;
+@@ -299,7 +295,7 @@ restart:
+
+ struct recall_threadargs {
+ struct inode *inode;
+- struct nfs4_client *clp;
++ struct nfs_client *clp;
+ const nfs4_stateid *stateid;
+
+ struct completion started;
+@@ -310,7 +306,7 @@ static int recall_thread(void *data)
+ {
+ struct recall_threadargs *args = (struct recall_threadargs *)data;
+ struct inode *inode = igrab(args->inode);
+- struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
++ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_delegation *delegation;
+
+@@ -371,7 +367,7 @@ out_module_put:
+ /*
+ * Retrieve the inode associated with a delegation
+ */
+-struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle)
++struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle)
+ {
+ struct nfs_delegation *delegation;
+ struct inode *res = NULL;
+@@ -389,7 +385,7 @@ struct inode *nfs_delegation_find_inode(
+ /*
+ * Mark all delegations as needing to be reclaimed
+ */
+-void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
++void nfs_delegation_mark_reclaim(struct nfs_client *clp)
+ {
+ struct nfs_delegation *delegation;
+ spin_lock(&clp->cl_lock);
+@@ -401,7 +397,7 @@ void nfs_delegation_mark_reclaim(struct
+ /*
+ * Reap all unclaimed delegations after reboot recovery is done
+ */
+-void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
++void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
+ {
+ struct nfs_delegation *delegation, *n;
+ LIST_HEAD(head);
+@@ -423,7 +419,7 @@ void nfs_delegation_reap_unclaimed(struc
+
+ int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
+ {
+- struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
++ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_delegation *delegation;
+ int res = 0;
+diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
+index 3858694..2cfd4b2 100644
+--- a/fs/nfs/delegation.h
++++ b/fs/nfs/delegation.h
+@@ -29,13 +29,13 @@ void nfs_inode_reclaim_delegation(struct
+ int __nfs_inode_return_delegation(struct inode *inode);
+ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
+
+-struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
++struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
+ void nfs_return_all_delegations(struct super_block *sb);
+-void nfs_expire_all_delegations(struct nfs4_client *clp);
+-void nfs_handle_cb_pathdown(struct nfs4_client *clp);
++void nfs_expire_all_delegations(struct nfs_client *clp);
++void nfs_handle_cb_pathdown(struct nfs_client *clp);
+
+-void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
+-void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
++void nfs_delegation_mark_reclaim(struct nfs_client *clp);
++void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
+
+ /* NFSv4 delegation-related procedures */
+ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
+diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
+index e7ffb4d..b34cd16 100644
+--- a/fs/nfs/dir.c
++++ b/fs/nfs/dir.c
+@@ -30,7 +30,9 @@
+ #include <linux/nfs_mount.h>
+ #include <linux/pagemap.h>
+ #include <linux/smp_lock.h>
++#include <linux/pagevec.h>
+ #include <linux/namei.h>
++#include <linux/mount.h>
+
+ #include "nfs4_fs.h"
+ #include "delegation.h"
+@@ -140,12 +142,12 @@ nfs_opendir(struct inode *inode, struct
+ return res;
+ }
+
+-typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
++typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int);
+ typedef struct {
+ struct file *file;
+ struct page *page;
+ unsigned long page_index;
+- u32 *ptr;
++ __be32 *ptr;
+ u64 *dir_cookie;
+ loff_t current_index;
+ struct nfs_entry *entry;
+@@ -201,8 +203,10 @@ int nfs_readdir_filler(nfs_readdir_descr
+ * Note: assumes we have exclusive access to this mapping either
+ * through inode->i_mutex or some other mechanism.
+ */
+- if (page->index == 0)
+- invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1);
++ if (page->index == 0 && invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1) < 0) {
++ /* Should never happen */
++ nfs_zap_mapping(inode, inode->i_mapping);
++ }
+ unlock_page(page);
+ return 0;
+ error:
+@@ -216,7 +220,7 @@ int nfs_readdir_filler(nfs_readdir_descr
+ static inline
+ int dir_decode(nfs_readdir_descriptor_t *desc)
+ {
+- u32 *p = desc->ptr;
++ __be32 *p = desc->ptr;
+ p = desc->decode(p, desc->entry, desc->plus);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+@@ -841,7 +845,7 @@ static void nfs_dentry_iput(struct dentr
+ nfs_inode_return_delegation(inode);
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ lock_kernel();
+- inode->i_nlink--;
++ drop_nlink(inode);
+ nfs_complete_unlink(dentry);
+ unlock_kernel();
+ }
+@@ -870,14 +874,14 @@ int nfs_is_exclusive_create(struct inode
+ return (nd->intent.open.flags & O_EXCL) != 0;
+ }
+
+-static inline int nfs_reval_fsid(struct inode *dir,
+- struct nfs_fh *fh, struct nfs_fattr *fattr)
++static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir,
++ struct nfs_fh *fh, struct nfs_fattr *fattr)
+ {
+ struct nfs_server *server = NFS_SERVER(dir);
+
+ if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
+ /* Revalidate fsid on root dir */
+- return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
++ return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode);
+ return 0;
+ }
+
+@@ -902,9 +906,15 @@ static struct dentry *nfs_lookup(struct
+
+ lock_kernel();
+
+- /* If we're doing an exclusive create, optimize away the lookup */
+- if (nfs_is_exclusive_create(dir, nd))
+- goto no_entry;
++ /*
++ * If we're doing an exclusive create, optimize away the lookup
++ * but don't hash the dentry.
++ */
++ if (nfs_is_exclusive_create(dir, nd)) {
++ d_instantiate(dentry, NULL);
++ res = NULL;
++ goto out_unlock;
++ }
+
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
+ if (error == -ENOENT)
+@@ -913,7 +923,7 @@ static struct dentry *nfs_lookup(struct
+ res = ERR_PTR(error);
+ goto out_unlock;
+ }
+- error = nfs_reval_fsid(dir, &fhandle, &fattr);
++ error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr);
+ if (error < 0) {
+ res = ERR_PTR(error);
+ goto out_unlock;
+@@ -922,10 +932,20 @@ static struct dentry *nfs_lookup(struct
+ res = (struct dentry *)inode;
+ if (IS_ERR(res))
+ goto out_unlock;
++
+ no_entry:
+- res = d_add_unique(dentry, inode);
+- if (res != NULL)
++ res = d_materialise_unique(dentry, inode);
++ if (res != NULL) {
++ struct dentry *parent;
++ if (IS_ERR(res))
++ goto out_unlock;
++ /* Was a directory renamed! */
++ parent = dget_parent(res);
++ if (!IS_ROOT(parent))
++ nfs_mark_for_revalidate(parent->d_inode);
++ dput(parent);
+ dentry = res;
++ }
+ nfs_renew_times(dentry);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ out_unlock:
+@@ -1117,11 +1137,15 @@ static struct dentry *nfs_readdir_lookup
+ dput(dentry);
+ return NULL;
+ }
+- alias = d_add_unique(dentry, inode);
++
++ alias = d_materialise_unique(dentry, inode);
+ if (alias != NULL) {
+ dput(dentry);
++ if (IS_ERR(alias))
++ return NULL;
+ dentry = alias;
+ }
++
+ nfs_renew_times(dentry);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ return dentry;
+@@ -1143,23 +1167,22 @@ int nfs_instantiate(struct dentry *dentr
+ struct inode *dir = dentry->d_parent->d_inode;
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+ if (error)
+- goto out_err;
++ return error;
+ }
+ if (!(fattr->valid & NFS_ATTR_FATTR)) {
+ struct nfs_server *server = NFS_SB(dentry->d_sb);
+- error = server->rpc_ops->getattr(server, fhandle, fattr);
++ error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
+ if (error < 0)
+- goto out_err;
++ return error;
+ }
+ inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
+ error = PTR_ERR(inode);
+ if (IS_ERR(inode))
+- goto out_err;
++ return error;
+ d_instantiate(dentry, inode);
++ if (d_unhashed(dentry))
++ d_rehash(dentry);
+ return 0;
+-out_err:
+- d_drop(dentry);
+- return error;
+ }
+
+ /*
+@@ -1276,7 +1299,7 @@ static int nfs_rmdir(struct inode *dir,
+ error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+ /* Ensure the VFS deletes this inode */
+ if (error == 0 && dentry->d_inode != NULL)
+- dentry->d_inode->i_nlink = 0;
++ clear_nlink(dentry->d_inode);
+ nfs_end_data_update(dir);
+ unlock_kernel();
+
+@@ -1391,7 +1414,7 @@ static int nfs_safe_remove(struct dentry
+ error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+ /* The VFS may want to delete this inode */
+ if (error == 0)
+- inode->i_nlink--;
++ drop_nlink(inode);
+ nfs_mark_for_revalidate(inode);
+ nfs_end_data_update(inode);
+ } else
+@@ -1440,48 +1463,82 @@ static int nfs_unlink(struct inode *dir,
+ return error;
+ }
+
+-static int
+-nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
++/*
++ * To create a symbolic link, most file systems instantiate a new inode,
++ * add a page to it containing the path, then write it out to the disk
++ * using prepare_write/commit_write.
++ *
++ * Unfortunately the NFS client can't create the in-core inode first
++ * because it needs a file handle to create an in-core inode (see
++ * fs/nfs/inode.c:nfs_fhget). We only have a file handle *after* the
++ * symlink request has completed on the server.
++ *
++ * So instead we allocate a raw page, copy the symname into it, then do
++ * the SYMLINK request with the page as the buffer. If it succeeds, we
++ * now have a new file handle and can instantiate an in-core NFS inode
++ * and move the raw page into its mapping.
++ */
++static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+ {
++ struct pagevec lru_pvec;
++ struct page *page;
++ char *kaddr;
+ struct iattr attr;
+- struct nfs_fattr sym_attr;
+- struct nfs_fh sym_fh;
+- struct qstr qsymname;
++ unsigned int pathlen = strlen(symname);
+ int error;
+
+ dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
+ dir->i_ino, dentry->d_name.name, symname);
+
+-#ifdef NFS_PARANOIA
+-if (dentry->d_inode)
+-printk("nfs_proc_symlink: %s/%s not negative!\n",
+-dentry->d_parent->d_name.name, dentry->d_name.name);
+-#endif
+- /*
+- * Fill in the sattr for the call.
+- * Note: SunOS 4.1.2 crashes if the mode isn't initialized!
+- */
+- attr.ia_valid = ATTR_MODE;
+- attr.ia_mode = S_IFLNK | S_IRWXUGO;
++ if (pathlen > PAGE_SIZE)
++ return -ENAMETOOLONG;
+
+- qsymname.name = symname;
+- qsymname.len = strlen(symname);
++ attr.ia_mode = S_IFLNK | S_IRWXUGO;
++ attr.ia_valid = ATTR_MODE;
+
+ lock_kernel();
++
++ page = alloc_page(GFP_KERNEL);
++ if (!page) {
++ unlock_kernel();
++ return -ENOMEM;
++ }
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memcpy(kaddr, symname, pathlen);
++ if (pathlen < PAGE_SIZE)
++ memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
++ kunmap_atomic(kaddr, KM_USER0);
++
+ nfs_begin_data_update(dir);
+- error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
+- &attr, &sym_fh, &sym_attr);
++ error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
+ nfs_end_data_update(dir);
+- if (!error) {
+- error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
+- } else {
+- if (error == -EEXIST)
+- printk("nfs_proc_symlink: %s/%s already exists??\n",
+- dentry->d_parent->d_name.name, dentry->d_name.name);
++ if (error != 0) {
++ dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
++ dir->i_sb->s_id, dir->i_ino,
++ dentry->d_name.name, symname, error);
+ d_drop(dentry);
++ __free_page(page);
++ unlock_kernel();
++ return error;
+ }
++
++ /*
++ * No big deal if we can't add this page to the page cache here.
++ * READLINK will get the missing page from the server if needed.
++ */
++ pagevec_init(&lru_pvec, 0);
++ if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0,
++ GFP_KERNEL)) {
++ pagevec_add(&lru_pvec, page);
++ pagevec_lru_add(&lru_pvec);
++ SetPageUptodate(page);
++ unlock_page(page);
++ } else
++ __free_page(page);
++
+ unlock_kernel();
+- return error;
++ return 0;
+ }
+
+ static int
+@@ -1595,7 +1652,7 @@ static int nfs_rename(struct inode *old_
+ goto out;
+ }
+ } else
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+
+ go_ahead:
+ /*
+@@ -1625,8 +1682,7 @@ out:
+ if (rehash)
+ d_rehash(rehash);
+ if (!error) {
+- if (!S_ISDIR(old_inode->i_mode))
+- d_move(old_dentry, new_dentry);
++ d_move(old_dentry, new_dentry);
+ nfs_renew_times(new_dentry);
+ nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+ }
+@@ -1638,35 +1694,211 @@ out:
+ return error;
+ }
+
++static DEFINE_SPINLOCK(nfs_access_lru_lock);
++static LIST_HEAD(nfs_access_lru_list);
++static atomic_long_t nfs_access_nr_entries;
++
++static void nfs_access_free_entry(struct nfs_access_entry *entry)
++{
++ put_rpccred(entry->cred);
++ kfree(entry);
++ smp_mb__before_atomic_dec();
++ atomic_long_dec(&nfs_access_nr_entries);
++ smp_mb__after_atomic_dec();
++}
++
++int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
++{
++ LIST_HEAD(head);
++ struct nfs_inode *nfsi;
++ struct nfs_access_entry *cache;
++
++ spin_lock(&nfs_access_lru_lock);
++restart:
++ list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
++ struct inode *inode;
++
++ if (nr_to_scan-- == 0)
++ break;
++ inode = igrab(&nfsi->vfs_inode);
++ if (inode == NULL)
++ continue;
++ spin_lock(&inode->i_lock);
++ if (list_empty(&nfsi->access_cache_entry_lru))
++ goto remove_lru_entry;
++ cache = list_entry(nfsi->access_cache_entry_lru.next,
++ struct nfs_access_entry, lru);
++ list_move(&cache->lru, &head);
++ rb_erase(&cache->rb_node, &nfsi->access_cache);
++ if (!list_empty(&nfsi->access_cache_entry_lru))
++ list_move_tail(&nfsi->access_cache_inode_lru,
++ &nfs_access_lru_list);
++ else {
++remove_lru_entry:
++ list_del_init(&nfsi->access_cache_inode_lru);
++ clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
++ }
++ spin_unlock(&inode->i_lock);
++ iput(inode);
++ goto restart;
++ }
++ spin_unlock(&nfs_access_lru_lock);
++ while (!list_empty(&head)) {
++ cache = list_entry(head.next, struct nfs_access_entry, lru);
++ list_del(&cache->lru);
++ nfs_access_free_entry(cache);
++ }
++ return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure;
++}
++
++static void __nfs_access_zap_cache(struct inode *inode)
++{
++ struct nfs_inode *nfsi = NFS_I(inode);
++ struct rb_root *root_node = &nfsi->access_cache;
++ struct rb_node *n, *dispose = NULL;
++ struct nfs_access_entry *entry;
++
++ /* Unhook entries from the cache */
++ while ((n = rb_first(root_node)) != NULL) {
++ entry = rb_entry(n, struct nfs_access_entry, rb_node);
++ rb_erase(n, root_node);
++ list_del(&entry->lru);
++ n->rb_left = dispose;
++ dispose = n;
++ }
++ nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS;
++ spin_unlock(&inode->i_lock);
++
++ /* Now kill them all! */
++ while (dispose != NULL) {
++ n = dispose;
++ dispose = n->rb_left;
++ nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node));
++ }
++}
++
++void nfs_access_zap_cache(struct inode *inode)
++{
++ /* Remove from global LRU init */
++ if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) {
++ spin_lock(&nfs_access_lru_lock);
++ list_del_init(&NFS_I(inode)->access_cache_inode_lru);
++ spin_unlock(&nfs_access_lru_lock);
++ }
++
++ spin_lock(&inode->i_lock);
++ /* This will release the spinlock */
++ __nfs_access_zap_cache(inode);
++}
++
++static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred)
++{
++ struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
++ struct nfs_access_entry *entry;
++
++ while (n != NULL) {
++ entry = rb_entry(n, struct nfs_access_entry, rb_node);
++
++ if (cred < entry->cred)
++ n = n->rb_left;
++ else if (cred > entry->cred)
++ n = n->rb_right;
++ else
++ return entry;
++ }
++ return NULL;
++}
++
+ int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
+ {
+ struct nfs_inode *nfsi = NFS_I(inode);
+- struct nfs_access_entry *cache = &nfsi->cache_access;
++ struct nfs_access_entry *cache;
++ int err = -ENOENT;
+
+- if (cache->cred != cred
+- || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
+- || (nfsi->cache_validity & NFS_INO_INVALID_ACCESS))
+- return -ENOENT;
+- memcpy(res, cache, sizeof(*res));
+- return 0;
++ spin_lock(&inode->i_lock);
++ if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
++ goto out_zap;
++ cache = nfs_access_search_rbtree(inode, cred);
++ if (cache == NULL)
++ goto out;
++ if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)))
++ goto out_stale;
++ res->jiffies = cache->jiffies;
++ res->cred = cache->cred;
++ res->mask = cache->mask;
++ list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru);
++ err = 0;
++out:
++ spin_unlock(&inode->i_lock);
++ return err;
++out_stale:
++ rb_erase(&cache->rb_node, &nfsi->access_cache);
++ list_del(&cache->lru);
++ spin_unlock(&inode->i_lock);
++ nfs_access_free_entry(cache);
++ return -ENOENT;
++out_zap:
++ /* This will release the spinlock */
++ __nfs_access_zap_cache(inode);
++ return -ENOENT;
+ }
+
+-void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
++static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set)
+ {
+ struct nfs_inode *nfsi = NFS_I(inode);
+- struct nfs_access_entry *cache = &nfsi->cache_access;
++ struct rb_root *root_node = &nfsi->access_cache;
++ struct rb_node **p = &root_node->rb_node;
++ struct rb_node *parent = NULL;
++ struct nfs_access_entry *entry;
+
+- if (cache->cred != set->cred) {
+- if (cache->cred)
+- put_rpccred(cache->cred);
+- cache->cred = get_rpccred(set->cred);
+- }
+- /* FIXME: replace current access_cache BKL reliance with inode->i_lock */
+ spin_lock(&inode->i_lock);
+- nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS;
++ while (*p != NULL) {
++ parent = *p;
++ entry = rb_entry(parent, struct nfs_access_entry, rb_node);
++
++ if (set->cred < entry->cred)
++ p = &parent->rb_left;
++ else if (set->cred > entry->cred)
++ p = &parent->rb_right;
++ else
++ goto found;
++ }
++ rb_link_node(&set->rb_node, parent, p);
++ rb_insert_color(&set->rb_node, root_node);
++ list_add_tail(&set->lru, &nfsi->access_cache_entry_lru);
+ spin_unlock(&inode->i_lock);
++ return;
++found:
++ rb_replace_node(parent, &set->rb_node, root_node);
++ list_add_tail(&set->lru, &nfsi->access_cache_entry_lru);
++ list_del(&entry->lru);
++ spin_unlock(&inode->i_lock);
++ nfs_access_free_entry(entry);
++}
++
++void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
++{
++ struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
++ if (cache == NULL)
++ return;
++ RB_CLEAR_NODE(&cache->rb_node);
+ cache->jiffies = set->jiffies;
++ cache->cred = get_rpccred(set->cred);
+ cache->mask = set->mask;
++
++ nfs_access_add_rbtree(inode, cache);
++
++ /* Update accounting */
++ smp_mb__before_atomic_inc();
++ atomic_long_inc(&nfs_access_nr_entries);
++ smp_mb__after_atomic_inc();
++
++ /* Add inode to global LRU list */
++ if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) {
++ spin_lock(&nfs_access_lru_lock);
++ list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list);
++ spin_unlock(&nfs_access_lru_lock);
++ }
+ }
+
+ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
+diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
+index 76ca1cb..bdfabf8 100644
+--- a/fs/nfs/direct.c
++++ b/fs/nfs/direct.c
+@@ -497,6 +497,7 @@ static void nfs_direct_write_complete(st
+ if (dreq->commit_data != NULL)
+ nfs_commit_free(dreq->commit_data);
+ nfs_direct_free_writedata(dreq);
++ nfs_zap_mapping(inode, inode->i_mapping);
+ nfs_direct_complete(dreq);
+ }
+ }
+@@ -517,6 +518,7 @@ static void nfs_direct_write_complete(st
+ {
+ nfs_end_data_update(inode);
+ nfs_direct_free_writedata(dreq);
++ nfs_zap_mapping(inode, inode->i_mapping);
+ nfs_direct_complete(dreq);
+ }
+ #endif
+@@ -532,10 +534,12 @@ static void nfs_direct_write_result(stru
+
+ spin_lock(&dreq->lock);
+
+- if (likely(status >= 0))
+- dreq->count += data->res.count;
+- else
+- dreq->error = task->tk_status;
++ if (unlikely(status < 0)) {
++ dreq->error = status;
++ goto out_unlock;
++ }
++
++ dreq->count += data->res.count;
+
+ if (data->res.verf->committed != NFS_FILE_SYNC) {
+ switch (dreq->flags) {
+@@ -550,7 +554,7 @@ static void nfs_direct_write_result(stru
+ }
+ }
+ }
+-
++out_unlock:
+ spin_unlock(&dreq->lock);
+ }
+
+@@ -707,8 +711,8 @@ static ssize_t nfs_direct_write(struct k
+ /**
+ * nfs_file_direct_read - file direct read operation for NFS files
+ * @iocb: target I/O control block
+- * @buf: user's buffer into which to read data
+- * @count: number of bytes to read
++ * @iov: vector of user buffers into which to read data
++ * @nr_segs: size of iov vector
+ * @pos: byte offset in file where reading starts
+ *
+ * We use this function for direct reads instead of calling
+@@ -725,17 +729,24 @@ static ssize_t nfs_direct_write(struct k
+ * client must read the updated atime from the server back into its
+ * cache.
+ */
+-ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
++ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ ssize_t retval = -EINVAL;
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
++ /* XXX: temporary */
++ const char __user *buf = iov[0].iov_base;
++ size_t count = iov[0].iov_len;
+
+ dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
+ file->f_dentry->d_parent->d_name.name,
+ file->f_dentry->d_name.name,
+ (unsigned long) count, (long long) pos);
+
++ if (nr_segs != 1)
++ return -EINVAL;
++
+ if (count < 0)
+ goto out;
+ retval = -EFAULT;
+@@ -760,8 +771,8 @@ out:
+ /**
+ * nfs_file_direct_write - file direct write operation for NFS files
+ * @iocb: target I/O control block
+- * @buf: user's buffer from which to write data
+- * @count: number of bytes to write
++ * @iov: vector of user buffers from which to write data
++ * @nr_segs: size of iov vector
+ * @pos: byte offset in file where writing starts
+ *
+ * We use this function for direct writes instead of calling
+@@ -782,17 +793,24 @@ out:
+ * Note that O_APPEND is not supported for NFS direct writes, as there
+ * is no atomic O_APPEND write facility in the NFS protocol.
+ */
+-ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
++ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ ssize_t retval;
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
++ /* XXX: temporary */
++ const char __user *buf = iov[0].iov_base;
++ size_t count = iov[0].iov_len;
+
+ dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
+ file->f_dentry->d_parent->d_name.name,
+ file->f_dentry->d_name.name,
+ (unsigned long) count, (long long) pos);
+
++ if (nr_segs != 1)
++ return -EINVAL;
++
+ retval = generic_write_checks(file, &pos, &count, 0);
+ if (retval)
+ goto out;
+@@ -814,17 +832,6 @@ ssize_t nfs_file_direct_write(struct kio
+
+ retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
+
+- /*
+- * XXX: nfs_end_data_update() already ensures this file's
+- * cached data is subsequently invalidated. Do we really
+- * need to call invalidate_inode_pages2() again here?
+- *
+- * For aio writes, this invalidation will almost certainly
+- * occur before the writes complete. Kind of racey.
+- */
+- if (mapping->nrpages)
+- invalidate_inode_pages2(mapping);
+-
+ if (retval > 0)
+ iocb->ki_pos = pos + retval;
+
+@@ -855,6 +862,5 @@ int __init nfs_init_directcache(void)
+ */
+ void nfs_destroy_directcache(void)
+ {
+- if (kmem_cache_destroy(nfs_direct_cachep))
+- printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
++ kmem_cache_destroy(nfs_direct_cachep);
+ }
+diff --git a/fs/nfs/file.c b/fs/nfs/file.c
+index 48e8928..cc93865 100644
+--- a/fs/nfs/file.c
++++ b/fs/nfs/file.c
+@@ -41,8 +41,10 @@ static int nfs_file_release(struct inode
+ static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
+ static int nfs_file_mmap(struct file *, struct vm_area_struct *);
+ static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
+-static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t);
+-static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t);
++static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos);
++static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos);
+ static int nfs_file_flush(struct file *, fl_owner_t id);
+ static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
+ static int nfs_check_flags(int flags);
+@@ -53,8 +55,8 @@ const struct file_operations nfs_file_op
+ .llseek = nfs_file_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+- .aio_read = nfs_file_read,
+- .aio_write = nfs_file_write,
++ .aio_read = nfs_file_read,
++ .aio_write = nfs_file_write,
+ .mmap = nfs_file_mmap,
+ .open = nfs_file_open,
+ .flush = nfs_file_flush,
+@@ -111,7 +113,7 @@ nfs_file_open(struct inode *inode, struc
+
+ nfs_inc_stats(inode, NFSIOS_VFSOPEN);
+ lock_kernel();
+- res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp);
++ res = NFS_PROTO(inode)->file_open(inode, filp);
+ unlock_kernel();
+ return res;
+ }
+@@ -157,7 +159,7 @@ force_reval:
+ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
+ {
+ /* origin == SEEK_END => we must revalidate the cached file length */
+- if (origin == 2) {
++ if (origin == SEEK_END) {
+ struct inode *inode = filp->f_mapping->host;
+ int retval = nfs_revalidate_file_size(inode, filp);
+ if (retval < 0)
+@@ -196,15 +198,17 @@ nfs_file_flush(struct file *file, fl_own
+ }
+
+ static ssize_t
+-nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
++nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct dentry * dentry = iocb->ki_filp->f_dentry;
+ struct inode * inode = dentry->d_inode;
+ ssize_t result;
++ size_t count = iov_length(iov, nr_segs);
+
+ #ifdef CONFIG_NFS_DIRECTIO
+ if (iocb->ki_filp->f_flags & O_DIRECT)
+- return nfs_file_direct_read(iocb, buf, count, pos);
++ return nfs_file_direct_read(iocb, iov, nr_segs, pos);
+ #endif
+
+ dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
+@@ -214,7 +218,7 @@ nfs_file_read(struct kiocb *iocb, char _
+ result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
+ nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
+ if (!result)
+- result = generic_file_aio_read(iocb, buf, count, pos);
++ result = generic_file_aio_read(iocb, iov, nr_segs, pos);
+ return result;
+ }
+
+@@ -336,24 +340,22 @@ const struct address_space_operations nf
+ #endif
+ };
+
+-/*
+- * Write to a file (through the page cache).
+- */
+-static ssize_t
+-nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
++static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct dentry * dentry = iocb->ki_filp->f_dentry;
+ struct inode * inode = dentry->d_inode;
+ ssize_t result;
++ size_t count = iov_length(iov, nr_segs);
+
+ #ifdef CONFIG_NFS_DIRECTIO
+ if (iocb->ki_filp->f_flags & O_DIRECT)
+- return nfs_file_direct_write(iocb, buf, count, pos);
++ return nfs_file_direct_write(iocb, iov, nr_segs, pos);
+ #endif
+
+- dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n",
++ dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+- inode->i_ino, (unsigned long) count, (unsigned long) pos);
++ inode->i_ino, (unsigned long) count, (long long) pos);
+
+ result = -EBUSY;
+ if (IS_SWAPFILE(inode))
+@@ -372,7 +374,7 @@ nfs_file_write(struct kiocb *iocb, const
+ goto out;
+
+ nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
+- result = generic_file_aio_write(iocb, buf, count, pos);
++ result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+ out:
+ return result;
+
+diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
+new file mode 100644
+index 0000000..20c6f39
+--- /dev/null
++++ b/fs/nfs/getroot.c
+@@ -0,0 +1,310 @@
++/* getroot.c: get the root dentry for an NFS mount
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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/init.h>
++
++#include <linux/time.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/stat.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/sunrpc/clnt.h>
++#include <linux/sunrpc/stats.h>
++#include <linux/nfs_fs.h>
++#include <linux/nfs_mount.h>
++#include <linux/nfs4_mount.h>
++#include <linux/lockd/bind.h>
++#include <linux/smp_lock.h>
++#include <linux/seq_file.h>
++#include <linux/mount.h>
++#include <linux/nfs_idmap.h>
++#include <linux/vfs.h>
++#include <linux/namei.h>
++#include <linux/namespace.h>
++#include <linux/security.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include "nfs4_fs.h"
++#include "delegation.h"
++#include "internal.h"
++
++#define NFSDBG_FACILITY NFSDBG_CLIENT
++#define NFS_PARANOIA 1
++
++/*
++ * get an NFS2/NFS3 root dentry from the root filehandle
++ */
++struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
++{
++ struct nfs_server *server = NFS_SB(sb);
++ struct nfs_fsinfo fsinfo;
++ struct nfs_fattr fattr;
++ struct dentry *mntroot;
++ struct inode *inode;
++ int error;
++
++ /* create a dummy root dentry with dummy inode for this superblock */
++ if (!sb->s_root) {
++ struct nfs_fh dummyfh;
++ struct dentry *root;
++ struct inode *iroot;
++
++ memset(&dummyfh, 0, sizeof(dummyfh));
++ memset(&fattr, 0, sizeof(fattr));
++ nfs_fattr_init(&fattr);
++ fattr.valid = NFS_ATTR_FATTR;
++ fattr.type = NFDIR;
++ fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
++ fattr.nlink = 2;
++
++ iroot = nfs_fhget(sb, &dummyfh, &fattr);
++ if (IS_ERR(iroot))
++ return ERR_PTR(PTR_ERR(iroot));
++
++ root = d_alloc_root(iroot);
++ if (!root) {
++ iput(iroot);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ sb->s_root = root;
++ }
++
++ /* get the actual root for this mount */
++ fsinfo.fattr = &fattr;
++
++ error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
++ if (error < 0) {
++ dprintk("nfs_get_root: getattr error = %d\n", -error);
++ return ERR_PTR(error);
++ }
++
++ inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
++ if (IS_ERR(inode)) {
++ dprintk("nfs_get_root: get root inode failed\n");
++ return ERR_PTR(PTR_ERR(inode));
++ }
++
++ /* root dentries normally start off anonymous and get spliced in later
++ * if the dentry tree reaches them; however if the dentry already
++ * exists, we'll pick it up at this point and use it as the root
++ */
++ mntroot = d_alloc_anon(inode);
++ if (!mntroot) {
++ iput(inode);
++ dprintk("nfs_get_root: get root dentry failed\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ security_d_instantiate(mntroot, inode);
++
++ if (!mntroot->d_op)
++ mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
++
++ return mntroot;
++}
++
++#ifdef CONFIG_NFS_V4
++
++/*
++ * Do a simple pathwalk from the root FH of the server to the nominated target
++ * of the mountpoint
++ * - give error on symlinks
++ * - give error on ".." occurring in the path
++ * - follow traversals
++ */
++int nfs4_path_walk(struct nfs_server *server,
++ struct nfs_fh *mntfh,
++ const char *path)
++{
++ struct nfs_fsinfo fsinfo;
++ struct nfs_fattr fattr;
++ struct nfs_fh lastfh;
++ struct qstr name;
++ int ret;
++ //int referral_count = 0;
++
++ dprintk("--> nfs4_path_walk(,,%s)\n", path);
++
++ fsinfo.fattr = &fattr;
++ nfs_fattr_init(&fattr);
++
++ if (*path++ != '/') {
++ dprintk("nfs4_get_root: Path does not begin with a slash\n");
++ return -EINVAL;
++ }
++
++ /* Start by getting the root filehandle from the server */
++ ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
++ if (ret < 0) {
++ dprintk("nfs4_get_root: getroot error = %d\n", -ret);
++ return ret;
++ }
++
++ if (fattr.type != NFDIR) {
++ printk(KERN_ERR "nfs4_get_root:"
++ " getroot encountered non-directory\n");
++ return -ENOTDIR;
++ }
++
++ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
++ printk(KERN_ERR "nfs4_get_root:"
++ " getroot obtained referral\n");
++ return -EREMOTE;
++ }
++
++next_component:
++ dprintk("Next: %s\n", path);
++
++ /* extract the next bit of the path */
++ if (!*path)
++ goto path_walk_complete;
++
++ name.name = path;
++ while (*path && *path != '/')
++ path++;
++ name.len = path - (const char *) name.name;
++
++eat_dot_dir:
++ while (*path == '/')
++ path++;
++
++ if (path[0] == '.' && (path[1] == '/' || !path[1])) {
++ path += 2;
++ goto eat_dot_dir;
++ }
++
++ if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2])
++ ) {
++ printk(KERN_ERR "nfs4_get_root:"
++ " Mount path contains reference to \"..\"\n");
++ return -EINVAL;
++ }
++
++ /* lookup the next FH in the sequence */
++ memcpy(&lastfh, mntfh, sizeof(lastfh));
++
++ dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
++
++ ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
++ mntfh, &fattr);
++ if (ret < 0) {
++ dprintk("nfs4_get_root: getroot error = %d\n", -ret);
++ return ret;
++ }
++
++ if (fattr.type != NFDIR) {
++ printk(KERN_ERR "nfs4_get_root:"
++ " lookupfh encountered non-directory\n");
++ return -ENOTDIR;
++ }
++
++ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
++ printk(KERN_ERR "nfs4_get_root:"
++ " lookupfh obtained referral\n");
++ return -EREMOTE;
++ }
++
++ goto next_component;
++
++path_walk_complete:
++ memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
++ dprintk("<-- nfs4_path_walk() = 0\n");
++ return 0;
++}
++
++/*
++ * get an NFS4 root dentry from the root filehandle
++ */
++struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
++{
++ struct nfs_server *server = NFS_SB(sb);
++ struct nfs_fattr fattr;
++ struct dentry *mntroot;
++ struct inode *inode;
++ int error;
++
++ dprintk("--> nfs4_get_root()\n");
++
++ /* create a dummy root dentry with dummy inode for this superblock */
++ if (!sb->s_root) {
++ struct nfs_fh dummyfh;
++ struct dentry *root;
++ struct inode *iroot;
++
++ memset(&dummyfh, 0, sizeof(dummyfh));
++ memset(&fattr, 0, sizeof(fattr));
++ nfs_fattr_init(&fattr);
++ fattr.valid = NFS_ATTR_FATTR;
++ fattr.type = NFDIR;
++ fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
++ fattr.nlink = 2;
++
++ iroot = nfs_fhget(sb, &dummyfh, &fattr);
++ if (IS_ERR(iroot))
++ return ERR_PTR(PTR_ERR(iroot));
++
++ root = d_alloc_root(iroot);
++ if (!root) {
++ iput(iroot);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ sb->s_root = root;
++ }
++
++ /* get the info about the server and filesystem */
++ error = nfs4_server_capabilities(server, mntfh);
++ if (error < 0) {
++ dprintk("nfs_get_root: getcaps error = %d\n",
++ -error);
++ return ERR_PTR(error);
++ }
++
++ /* get the actual root for this mount */
++ error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
++ if (error < 0) {
++ dprintk("nfs_get_root: getattr error = %d\n", -error);
++ return ERR_PTR(error);
++ }
++
++ inode = nfs_fhget(sb, mntfh, &fattr);
++ if (IS_ERR(inode)) {
++ dprintk("nfs_get_root: get root inode failed\n");
++ return ERR_PTR(PTR_ERR(inode));
++ }
++
++ /* root dentries normally start off anonymous and get spliced in later
++ * if the dentry tree reaches them; however if the dentry already
++ * exists, we'll pick it up at this point and use it as the root
++ */
++ mntroot = d_alloc_anon(inode);
++ if (!mntroot) {
++ iput(inode);
++ dprintk("nfs_get_root: get root dentry failed\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ security_d_instantiate(mntroot, inode);
++
++ if (!mntroot->d_op)
++ mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
++
++ dprintk("<-- nfs4_get_root()\n");
++ return mntroot;
++}
++
++#endif /* CONFIG_NFS_V4 */
+diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
+index 07a5dd5..82ad711 100644
+--- a/fs/nfs/idmap.c
++++ b/fs/nfs/idmap.c
+@@ -57,6 +57,20 @@
+ /* Default cache timeout is 10 minutes */
+ unsigned int nfs_idmap_cache_timeout = 600 * HZ;
+
++static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
++{
++ char *endp;
++ int num = simple_strtol(val, &endp, 0);
++ int jif = num * HZ;
++ if (endp == val || *endp || num < 0 || jif < num)
++ return -EINVAL;
++ *((int *)kp->arg) = jif;
++ return 0;
++}
++
++module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
++ &nfs_idmap_cache_timeout, 0644);
++
+ struct idmap_hashent {
+ unsigned long ih_expires;
+ __u32 ih_id;
+@@ -70,7 +84,6 @@ struct idmap_hashtable {
+ };
+
+ struct idmap {
+- char idmap_path[48];
+ struct dentry *idmap_dentry;
+ wait_queue_head_t idmap_wq;
+ struct idmap_msg idmap_im;
+@@ -94,24 +107,23 @@ static struct rpc_pipe_ops idmap_upcall_
+ .destroy_msg = idmap_pipe_destroy_msg,
+ };
+
+-void
+-nfs_idmap_new(struct nfs4_client *clp)
++int
++nfs_idmap_new(struct nfs_client *clp)
+ {
+ struct idmap *idmap;
++ int error;
+
+- if (clp->cl_idmap != NULL)
+- return;
+- if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
+- return;
++ BUG_ON(clp->cl_idmap != NULL);
+
+- snprintf(idmap->idmap_path, sizeof(idmap->idmap_path),
+- "%s/idmap", clp->cl_rpcclient->cl_pathname);
++ if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
++ return -ENOMEM;
+
+- idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path,
++ idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap",
+ idmap, &idmap_upcall_ops, 0);
+ if (IS_ERR(idmap->idmap_dentry)) {
++ error = PTR_ERR(idmap->idmap_dentry);
+ kfree(idmap);
+- return;
++ return error;
+ }
+
+ mutex_init(&idmap->idmap_lock);
+@@ -121,10 +133,11 @@ nfs_idmap_new(struct nfs4_client *clp)
+ idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
+
+ clp->cl_idmap = idmap;
++ return 0;
+ }
+
+ void
+-nfs_idmap_delete(struct nfs4_client *clp)
++nfs_idmap_delete(struct nfs_client *clp)
+ {
+ struct idmap *idmap = clp->cl_idmap;
+
+@@ -477,27 +490,27 @@ static unsigned int fnvhash32(const void
+ return (hash);
+ }
+
+-int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
++int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+ {
+ struct idmap *idmap = clp->cl_idmap;
+
+ return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
+ }
+
+-int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
++int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+ {
+ struct idmap *idmap = clp->cl_idmap;
+
+ return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
+ }
+
+-int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf)
++int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf)
+ {
+ struct idmap *idmap = clp->cl_idmap;
+
+ return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
+ }
+-int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf)
++int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf)
+ {
+ struct idmap *idmap = clp->cl_idmap;
+
+diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
+index d349fb2..08cc4c5 100644
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode,
+
+ void nfs_clear_inode(struct inode *inode)
+ {
+- struct nfs_inode *nfsi = NFS_I(inode);
+- struct rpc_cred *cred;
+-
+ /*
+ * The following should never happen...
+ */
+ BUG_ON(nfs_have_writebacks(inode));
+- BUG_ON (!list_empty(&nfsi->open_files));
++ BUG_ON(!list_empty(&NFS_I(inode)->open_files));
++ BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
+ nfs_zap_acl_cache(inode);
+- cred = nfsi->cache_access.cred;
+- if (cred)
+- put_rpccred(cred);
+- BUG_ON(atomic_read(&nfsi->data_updates) != 0);
++ nfs_access_zap_cache(inode);
+ }
+
+ /**
+@@ -136,6 +131,15 @@ void nfs_zap_caches(struct inode *inode)
+ spin_unlock(&inode->i_lock);
+ }
+
++void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
++{
++ if (mapping->nrpages != 0) {
++ spin_lock(&inode->i_lock);
++ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
++ spin_unlock(&inode->i_lock);
++ }
++}
++
+ static void nfs_zap_acl_cache(struct inode *inode)
+ {
+ void (*clear_acl_cache)(struct inode *);
+@@ -242,13 +246,13 @@ nfs_fhget(struct super_block *sb, struct
+ /* Why so? Because we want revalidate for devices/FIFOs, and
+ * that's precisely what we have in nfs_file_inode_operations.
+ */
+- inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops;
++ inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_fop = &nfs_file_operations;
+ inode->i_data.a_ops = &nfs_file_aops;
+ inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
+ } else if (S_ISDIR(inode->i_mode)) {
+- inode->i_op = NFS_SB(sb)->rpc_ops->dir_inode_ops;
++ inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
+ inode->i_fop = &nfs_dir_operations;
+ if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
+ && fattr->size <= NFS_LIMIT_READDIRPLUS)
+@@ -282,15 +286,13 @@ nfs_fhget(struct super_block *sb, struct
+ * report the blocks in 512byte units
+ */
+ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+- inode->i_blksize = inode->i_sb->s_blocksize;
+ } else {
+ inode->i_blocks = fattr->du.nfs2.blocks;
+- inode->i_blksize = fattr->du.nfs2.blocksize;
+ }
+ nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+ nfsi->attrtimeo_timestamp = jiffies;
+ memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
+- nfsi->cache_access.cred = NULL;
++ nfsi->access_cache = RB_ROOT;
+
+ unlock_new_inode(inode);
+ } else
+@@ -448,7 +450,7 @@ static struct nfs_open_context *alloc_nf
+ {
+ struct nfs_open_context *ctx;
+
+- ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
++ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (ctx != NULL) {
+ atomic_set(&ctx->count, 1);
+ ctx->dentry = dget(dentry);
+@@ -581,7 +583,7 @@ __nfs_revalidate_inode(struct nfs_server
+
+ nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
+ lock_kernel();
+- if (!inode || is_bad_inode(inode))
++ if (is_bad_inode(inode))
+ goto out_nowait;
+ if (NFS_STALE(inode))
+ goto out_nowait;
+@@ -678,13 +680,20 @@ int nfs_revalidate_mapping(struct inode
+ if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
+ || nfs_attribute_timeout(inode))
+ ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
++ if (ret < 0)
++ goto out;
+
+ if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
+- nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
+- if (S_ISREG(inode->i_mode))
+- nfs_sync_mapping(mapping);
+- invalidate_inode_pages2(mapping);
+-
++ if (mapping->nrpages != 0) {
++ if (S_ISREG(inode->i_mode)) {
++ ret = nfs_sync_mapping(mapping);
++ if (ret < 0)
++ goto out;
++ }
++ ret = invalidate_inode_pages2(mapping);
++ if (ret < 0)
++ goto out;
++ }
+ spin_lock(&inode->i_lock);
+ nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
+ if (S_ISDIR(inode->i_mode)) {
+@@ -694,10 +703,12 @@ int nfs_revalidate_mapping(struct inode
+ }
+ spin_unlock(&inode->i_lock);
+
++ nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
+ dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
+ inode->i_sb->s_id,
+ (long long)NFS_FILEID(inode));
+ }
++out:
+ return ret;
+ }
+
+@@ -722,13 +733,11 @@ void nfs_end_data_update(struct inode *i
+ {
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+- if (!nfs_have_delegation(inode, FMODE_READ)) {
+- /* Directories and symlinks: invalidate page cache */
+- if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
+- spin_lock(&inode->i_lock);
+- nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+- spin_unlock(&inode->i_lock);
+- }
++ /* Directories: invalidate page cache */
++ if (S_ISDIR(inode->i_mode)) {
++ spin_lock(&inode->i_lock);
++ nfsi->cache_validity |= NFS_INO_INVALID_DATA;
++ spin_unlock(&inode->i_lock);
+ }
+ nfsi->cache_change_attribute = jiffies;
+ atomic_dec(&nfsi->data_updates);
+@@ -847,6 +856,12 @@ int nfs_refresh_inode(struct inode *inod
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it.
++ *
++ * NB: if the server didn't return any post op attributes, this
++ * function will force the retrieval of attributes before the next
++ * NFS request. Thus it should be used only for operations that
++ * are expected to change one or more attributes, to avoid
++ * unnecessary NFS requests and trips through nfs_update_inode().
+ */
+ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+ {
+@@ -970,10 +985,8 @@ static int nfs_update_inode(struct inode
+ * report the blocks in 512byte units
+ */
+ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+- inode->i_blksize = inode->i_sb->s_blocksize;
+ } else {
+ inode->i_blocks = fattr->du.nfs2.blocks;
+- inode->i_blksize = fattr->du.nfs2.blocksize;
+ }
+
+ if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+@@ -1025,7 +1038,7 @@ static int nfs_update_inode(struct inode
+ out_fileid:
+ printk(KERN_ERR "NFS: server %s error: fileid changed\n"
+ "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
+- NFS_SERVER(inode)->hostname, inode->i_sb->s_id,
++ NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
+ (long long)nfsi->fileid, (long long)fattr->fileid);
+ goto out_err;
+ }
+@@ -1109,6 +1122,8 @@ static void init_once(void * foo, kmem_c
+ INIT_LIST_HEAD(&nfsi->dirty);
+ INIT_LIST_HEAD(&nfsi->commit);
+ INIT_LIST_HEAD(&nfsi->open_files);
++ INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
++ INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
+ INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
+ atomic_set(&nfsi->data_updates, 0);
+ nfsi->ndirty = 0;
+@@ -1133,8 +1148,7 @@ static int __init nfs_init_inodecache(vo
+
+ static void nfs_destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(nfs_inode_cachep))
+- printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(nfs_inode_cachep);
+ }
+
+ /*
+@@ -1144,6 +1158,10 @@ static int __init init_nfs_fs(void)
+ {
+ int err;
+
++ err = nfs_fs_proc_init();
++ if (err)
++ goto out5;
++
+ err = nfs_init_nfspagecache();
+ if (err)
+ goto out4;
+@@ -1184,6 +1202,8 @@ out2:
+ out3:
+ nfs_destroy_nfspagecache();
+ out4:
++ nfs_fs_proc_exit();
++out5:
+ return err;
+ }
+
+@@ -1198,6 +1218,7 @@ static void __exit exit_nfs_fs(void)
+ rpc_proc_unregister("nfs");
+ #endif
+ unregister_nfs_fs();
++ nfs_fs_proc_exit();
+ }
+
+ /* Not quite true; I just maintain it */
+diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
+index e4f4e5d..d205466 100644
+--- a/fs/nfs/internal.h
++++ b/fs/nfs/internal.h
+@@ -4,6 +4,18 @@
+
+ #include <linux/mount.h>
+
++struct nfs_string;
++struct nfs_mount_data;
++struct nfs4_mount_data;
++
++/* Maximum number of readahead requests
++ * FIXME: this should really be a sysctl so that users may tune it to suit
++ * their needs. People that do NFS over a slow network, might for
++ * instance want to reduce it to something closer to 1 for improved
++ * interactive response.
++ */
++#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
++
+ struct nfs_clone_mount {
+ const struct super_block *sb;
+ const struct dentry *dentry;
+@@ -15,7 +27,40 @@ struct nfs_clone_mount {
+ rpc_authflavor_t authflavor;
+ };
+
+-/* namespace-nfs4.c */
++/* client.c */
++extern struct rpc_program nfs_program;
++
++extern void nfs_put_client(struct nfs_client *);
++extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
++extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
++ struct nfs_fh *);
++extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
++ const char *,
++ const struct sockaddr_in *,
++ const char *,
++ const char *,
++ rpc_authflavor_t,
++ struct nfs_fh *);
++extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
++ struct nfs_fh *);
++extern void nfs_free_server(struct nfs_server *server);
++extern struct nfs_server *nfs_clone_server(struct nfs_server *,
++ struct nfs_fh *,
++ struct nfs_fattr *);
++#ifdef CONFIG_PROC_FS
++extern int __init nfs_fs_proc_init(void);
++extern void nfs_fs_proc_exit(void);
++#else
++static inline int nfs_fs_proc_init(void)
++{
++ return 0;
++}
++static inline void nfs_fs_proc_exit(void)
++{
++}
++#endif
++
++/* nfs4namespace.c */
+ #ifdef CONFIG_NFS_V4
+ extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
+ #else
+@@ -46,16 +91,18 @@ extern void nfs_destroy_directcache(void
+ #endif
+
+ /* nfs2xdr.c */
++extern int nfs_stat_to_errno(int);
+ extern struct rpc_procinfo nfs_procedures[];
+-extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
++extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
+
+ /* nfs3xdr.c */
+ extern struct rpc_procinfo nfs3_procedures[];
+-extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
++extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int);
+
+ /* nfs4xdr.c */
+-extern int nfs_stat_to_errno(int);
+-extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
++#ifdef CONFIG_NFS_V4
++extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
++#endif
+
+ /* nfs4proc.c */
+ #ifdef CONFIG_NFS_V4
+@@ -66,6 +113,9 @@ extern int nfs4_proc_fs_locations(struct
+ struct page *page);
+ #endif
+
++/* dir.c */
++extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
++
+ /* inode.c */
+ extern struct inode *nfs_alloc_inode(struct super_block *sb);
+ extern void nfs_destroy_inode(struct inode *);
+@@ -76,10 +126,10 @@ extern void nfs4_clear_inode(struct inod
+ #endif
+
+ /* super.c */
+-extern struct file_system_type nfs_referral_nfs4_fs_type;
+-extern struct file_system_type clone_nfs_fs_type;
++extern struct file_system_type nfs_xdev_fs_type;
+ #ifdef CONFIG_NFS_V4
+-extern struct file_system_type clone_nfs4_fs_type;
++extern struct file_system_type nfs4_xdev_fs_type;
++extern struct file_system_type nfs4_referral_fs_type;
+ #endif
+
+ extern struct rpc_stat nfs_rpcstat;
+@@ -88,30 +138,30 @@ extern int __init register_nfs_fs(void);
+ extern void __exit unregister_nfs_fs(void);
+
+ /* namespace.c */
+-extern char *nfs_path(const char *base, const struct dentry *dentry,
++extern char *nfs_path(const char *base,
++ const struct dentry *droot,
++ const struct dentry *dentry,
+ char *buffer, ssize_t buflen);
+
+-/*
+- * Determine the mount path as a string
+- */
+-static inline char *
+-nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
+-{
++/* getroot.c */
++extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
+ #ifdef CONFIG_NFS_V4
+- return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
+-#else
+- return NULL;
++extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *);
++
++extern int nfs4_path_walk(struct nfs_server *server,
++ struct nfs_fh *mntfh,
++ const char *path);
+ #endif
+-}
+
+ /*
+ * Determine the device name as a string
+ */
+ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
+- const struct dentry *dentry,
+- char *buffer, ssize_t buflen)
++ const struct dentry *dentry,
++ char *buffer, ssize_t buflen)
+ {
+- return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
++ return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
++ dentry, buffer, buflen);
+ }
+
+ /*
+@@ -167,20 +217,3 @@ void nfs_super_set_maxbytes(struct super
+ if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+ }
+-
+-/*
+- * Check if the string represents a "valid" IPv4 address
+- */
+-static inline int valid_ipaddr4(const char *buf)
+-{
+- int rc, count, in[4];
+-
+- rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
+- if (rc != 4)
+- return -EINVAL;
+- for (count = 0; count < 4; count++) {
+- if (in[count] > 255)
+- return -EINVAL;
+- }
+- return 0;
+-}
+diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
+index 445abb4..f75fe72 100644
+--- a/fs/nfs/mount_clnt.c
++++ b/fs/nfs/mount_clnt.c
+@@ -14,7 +14,6 @@
+ #include <linux/net.h>
+ #include <linux/in.h>
+ #include <linux/sunrpc/clnt.h>
+-#include <linux/sunrpc/xprt.h>
+ #include <linux/sunrpc/sched.h>
+ #include <linux/nfs_fs.h>
+
+@@ -77,29 +76,26 @@ static struct rpc_clnt *
+ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
+ int protocol)
+ {
+- struct rpc_xprt *xprt;
+- struct rpc_clnt *clnt;
+-
+- xprt = xprt_create_proto(protocol, srvaddr, NULL);
+- if (IS_ERR(xprt))
+- return (struct rpc_clnt *)xprt;
+-
+- clnt = rpc_create_client(xprt, hostname,
+- &mnt_program, version,
+- RPC_AUTH_UNIX);
+- if (!IS_ERR(clnt)) {
+- clnt->cl_softrtry = 1;
+- clnt->cl_oneshot = 1;
+- clnt->cl_intr = 1;
+- }
+- return clnt;
++ struct rpc_create_args args = {
++ .protocol = protocol,
++ .address = (struct sockaddr *)srvaddr,
++ .addrsize = sizeof(*srvaddr),
++ .servername = hostname,
++ .program = &mnt_program,
++ .version = version,
++ .authflavor = RPC_AUTH_UNIX,
++ .flags = (RPC_CLNT_CREATE_ONESHOT |
++ RPC_CLNT_CREATE_INTR),
++ };
++
++ return rpc_create(&args);
+ }
+
+ /*
+ * XDR encode/decode functions for MOUNT
+ */
+ static int
+-xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
++xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
+ {
+ p = xdr_encode_string(p, path);
+
+@@ -108,7 +104,7 @@ xdr_encode_dirpath(struct rpc_rqst *req,
+ }
+
+ static int
+-xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
++xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
+ {
+ struct nfs_fh *fh = res->fh;
+
+@@ -120,7 +116,7 @@ xdr_decode_fhstatus(struct rpc_rqst *req
+ }
+
+ static int
+-xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
++xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
+ {
+ struct nfs_fh *fh = res->fh;
+
+diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
+index 86b3169..ec1114b 100644
+--- a/fs/nfs/namespace.c
++++ b/fs/nfs/namespace.c
+@@ -2,12 +2,11 @@
+ * linux/fs/nfs/namespace.c
+ *
+ * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust at netapp.com>
++ * - Modified by David Howells <dhowells at redhat.com>
+ *
+ * NFS namespace
+ */
+
+-#include <linux/config.h>
+-
+ #include <linux/dcache.h>
+ #include <linux/mount.h>
+ #include <linux/namei.h>
+@@ -25,9 +24,15 @@ LIST_HEAD(nfs_automount_list);
+ static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
+ int nfs_mountpoint_expiry_timeout = 500 * HZ;
+
++static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
++ const struct dentry *dentry,
++ struct nfs_fh *fh,
++ struct nfs_fattr *fattr);
++
+ /*
+ * nfs_path - reconstruct the path given an arbitrary dentry
+ * @base - arbitrary string to prepend to the path
++ * @droot - pointer to root dentry for mountpoint
+ * @dentry - pointer to dentry
+ * @buffer - result buffer
+ * @buflen - length of buffer
+@@ -38,7 +43,9 @@ int nfs_mountpoint_expiry_timeout = 500
+ * This is mainly for use in figuring out the path on the
+ * server side when automounting on top of an existing partition.
+ */
+-char *nfs_path(const char *base, const struct dentry *dentry,
++char *nfs_path(const char *base,
++ const struct dentry *droot,
++ const struct dentry *dentry,
+ char *buffer, ssize_t buflen)
+ {
+ char *end = buffer+buflen;
+@@ -47,7 +54,7 @@ char *nfs_path(const char *base, const s
+ *--end = '\0';
+ buflen--;
+ spin_lock(&dcache_lock);
+- while (!IS_ROOT(dentry)) {
++ while (!IS_ROOT(dentry) && dentry != droot) {
+ namelen = dentry->d_name.len;
+ buflen -= namelen + 1;
+ if (buflen < 0)
+@@ -96,15 +103,18 @@ static void * nfs_follow_mountpoint(stru
+ struct nfs_fattr fattr;
+ int err;
+
++ dprintk("--> nfs_follow_mountpoint()\n");
++
+ BUG_ON(IS_ROOT(dentry));
+ dprintk("%s: enter\n", __FUNCTION__);
+ dput(nd->dentry);
+ nd->dentry = dget(dentry);
+- if (d_mountpoint(nd->dentry))
+- goto out_follow;
++
+ /* Look it up again */
+ parent = dget_parent(nd->dentry);
+- err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr);
++ err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
++ &nd->dentry->d_name,
++ &fh, &fattr);
+ dput(parent);
+ if (err != 0)
+ goto out_err;
+@@ -132,6 +142,8 @@ static void * nfs_follow_mountpoint(stru
+ schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+ out:
+ dprintk("%s: done, returned %d\n", __FUNCTION__, err);
++
++ dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
+ return ERR_PTR(err);
+ out_err:
+ path_release(nd);
+@@ -172,22 +184,23 @@ void nfs_release_automount_timer(void)
+ /*
+ * Clone a mountpoint of the appropriate type
+ */
+-static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname,
++static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
++ const char *devname,
+ struct nfs_clone_mount *mountdata)
+ {
+ #ifdef CONFIG_NFS_V4
+ struct vfsmount *mnt = NULL;
+- switch (server->rpc_ops->version) {
++ switch (server->nfs_client->cl_nfsversion) {
+ case 2:
+ case 3:
+- mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
++ mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
+ break;
+ case 4:
+- mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
++ mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata);
+ }
+ return mnt;
+ #else
+- return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
++ return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
+ #endif
+ }
+
+@@ -199,9 +212,10 @@ static struct vfsmount *nfs_do_clone_mou
+ * @fattr - attributes for new root inode
+ *
+ */
+-struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+- const struct dentry *dentry, struct nfs_fh *fh,
+- struct nfs_fattr *fattr)
++static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
++ const struct dentry *dentry,
++ struct nfs_fh *fh,
++ struct nfs_fattr *fattr)
+ {
+ struct nfs_clone_mount mountdata = {
+ .sb = mnt_parent->mnt_sb,
+@@ -213,6 +227,8 @@ struct vfsmount *nfs_do_submount(const s
+ char *page = (char *) __get_free_page(GFP_USER);
+ char *devname;
+
++ dprintk("--> nfs_do_submount()\n");
++
+ dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+@@ -227,5 +243,7 @@ free_page:
+ free_page((unsigned long)page);
+ out:
+ dprintk("%s: done\n", __FUNCTION__);
++
++ dprintk("<-- nfs_do_submount() = %p\n", mnt);
+ return mnt;
+ }
+diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
+index 67391ee..3be4e72 100644
+--- a/fs/nfs/nfs2xdr.c
++++ b/fs/nfs/nfs2xdr.c
+@@ -51,7 +51,7 @@
+ #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
+ #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
+ #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
+-#define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
++#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
+ #define NFS_readdirargs_sz (NFS_fhandle_sz+2)
+
+ #define NFS_attrstat_sz (1+NFS_fattr_sz)
+@@ -66,15 +66,15 @@
+ /*
+ * Common NFS XDR functions as inlines
+ */
+-static inline u32 *
+-xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
++static inline __be32 *
++xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
+ {
+ memcpy(p, fhandle->data, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
+ }
+
+-static inline u32 *
+-xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
++static inline __be32 *
++xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
+ {
+ /* NFSv2 handles have a fixed length */
+ fhandle->size = NFS2_FHSIZE;
+@@ -82,8 +82,8 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
+ }
+
+-static inline u32*
+-xdr_encode_time(u32 *p, struct timespec *timep)
++static inline __be32*
++xdr_encode_time(__be32 *p, struct timespec *timep)
+ {
+ *p++ = htonl(timep->tv_sec);
+ /* Convert nanoseconds into microseconds */
+@@ -91,8 +91,8 @@ xdr_encode_time(u32 *p, struct timespec
+ return p;
+ }
+
+-static inline u32*
+-xdr_encode_current_server_time(u32 *p, struct timespec *timep)
++static inline __be32*
++xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
+ {
+ /*
+ * Passing the invalid value useconds=1000000 is a
+@@ -108,8 +108,8 @@ xdr_encode_current_server_time(u32 *p, s
+ return p;
+ }
+
+-static inline u32*
+-xdr_decode_time(u32 *p, struct timespec *timep)
++static inline __be32*
++xdr_decode_time(__be32 *p, struct timespec *timep)
+ {
+ timep->tv_sec = ntohl(*p++);
+ /* Convert microseconds into nanoseconds */
+@@ -117,8 +117,8 @@ xdr_decode_time(u32 *p, struct timespec
+ return p;
+ }
+
+-static u32 *
+-xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
++static __be32 *
++xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
+ {
+ u32 rdev;
+ fattr->type = (enum nfs_ftype) ntohl(*p++);
+@@ -146,10 +146,10 @@ xdr_decode_fattr(u32 *p, struct nfs_fatt
+ return p;
+ }
+
+-static inline u32 *
+-xdr_encode_sattr(u32 *p, struct iattr *attr)
++static inline __be32 *
++xdr_encode_sattr(__be32 *p, struct iattr *attr)
+ {
+- const u32 not_set = __constant_htonl(0xFFFFFFFF);
++ const __be32 not_set = __constant_htonl(0xFFFFFFFF);
+
+ *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
+ *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
+@@ -184,7 +184,7 @@ xdr_encode_sattr(u32 *p, struct iattr *a
+ * GETATTR, READLINK, STATFS
+ */
+ static int
+-nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
++nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
+ {
+ p = xdr_encode_fhandle(p, fh);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+@@ -195,7 +195,7 @@ nfs_xdr_fhandle(struct rpc_rqst *req, u3
+ * Encode SETATTR arguments
+ */
+ static int
+-nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
++nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_sattr(p, args->sattr);
+@@ -208,7 +208,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req,
+ * LOOKUP, REMOVE, RMDIR
+ */
+ static int
+-nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
++nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+@@ -222,7 +222,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req,
+ * exactly to the page we want to fetch.
+ */
+ static int
+-nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
++nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+@@ -246,7 +246,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u
+ * Decode READ reply
+ */
+ static int
+-nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
++nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
+ {
+ struct kvec *iov = req->rq_rcv_buf.head;
+ int status, count, recvd, hdrlen;
+@@ -286,7 +286,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u3
+ * Write arguments. Splice the buffer to be written into the iovec.
+ */
+ static int
+-nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
++nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
+ {
+ struct xdr_buf *sndbuf = &req->rq_snd_buf;
+ u32 offset = (u32)args->offset;
+@@ -309,7 +309,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req,
+ * CREATE, MKDIR
+ */
+ static int
+-nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
++nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+@@ -322,7 +322,7 @@ nfs_xdr_createargs(struct rpc_rqst *req,
+ * Encode RENAME arguments
+ */
+ static int
+-nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
++nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
+@@ -336,7 +336,7 @@ nfs_xdr_renameargs(struct rpc_rqst *req,
+ * Encode LINK arguments
+ */
+ static int
+-nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
++nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_fhandle(p, args->tofh);
+@@ -349,13 +349,28 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u
+ * Encode SYMLINK arguments
+ */
+ static int
+-nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
++nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
+ {
++ struct xdr_buf *sndbuf = &req->rq_snd_buf;
++ size_t pad;
++
+ p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
+- p = xdr_encode_array(p, args->topath, args->tolen);
++ *p++ = htonl(args->pathlen);
++ sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
++
++ xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
++
++ /*
++ * xdr_encode_pages may have added a few bytes to ensure the
++ * pathname ends on a 4-byte boundary. Start encoding the
++ * attributes after the pad bytes.
++ */
++ pad = sndbuf->tail->iov_len;
++ if (pad > 0)
++ p++;
+ p = xdr_encode_sattr(p, args->sattr);
+- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
++ sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
+ return 0;
+ }
+
+@@ -363,7 +378,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req
+ * Encode arguments to readdir call
+ */
+ static int
+-nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
++nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
+ {
+ struct rpc_task *task = req->rq_task;
+ struct rpc_auth *auth = task->tk_auth;
+@@ -389,7 +404,7 @@ nfs_xdr_readdirargs(struct rpc_rqst *req
+ * from nfs_readdir for each entry.
+ */
+ static int
+-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
++nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
+ {
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct kvec *iov = rcvbuf->head;
+@@ -397,7 +412,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req,
+ int hdrlen, recvd;
+ int status, nr;
+ unsigned int len, pglen;
+- u32 *end, *entry, *kaddr;
++ __be32 *end, *entry, *kaddr;
+
+ if ((status = ntohl(*p++)))
+ return -nfs_stat_to_errno(status);
+@@ -417,8 +432,8 @@ nfs_xdr_readdirres(struct rpc_rqst *req,
+ if (pglen > recvd)
+ pglen = recvd;
+ page = rcvbuf->pages;
+- kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
+- end = (u32 *)((char *)p + pglen);
++ kaddr = p = kmap_atomic(*page, KM_USER0);
++ end = (__be32 *)((char *)p + pglen);
+ entry = p;
+ for (nr = 0; *p++; nr++) {
+ if (p + 2 > end)
+@@ -453,8 +468,8 @@ err_unmap:
+ goto out;
+ }
+
+-u32 *
+-nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
++__be32 *
++nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+ {
+ if (!*p++) {
+ if (!*p)
+@@ -481,7 +496,7 @@ nfs_decode_dirent(u32 *p, struct nfs_ent
+ * Decode simple status reply
+ */
+ static int
+-nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
++nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
+ {
+ int status;
+
+@@ -495,7 +510,7 @@ nfs_xdr_stat(struct rpc_rqst *req, u32 *
+ * GETATTR, SETATTR, WRITE
+ */
+ static int
+-nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
++nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
+ {
+ int status;
+
+@@ -510,7 +525,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, u
+ * LOOKUP, CREATE, MKDIR
+ */
+ static int
+-nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
++nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
+ {
+ int status;
+
+@@ -525,7 +540,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, u
+ * Encode READLINK args
+ */
+ static int
+-nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
++nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+@@ -543,7 +558,7 @@ nfs_xdr_readlinkargs(struct rpc_rqst *re
+ * Decode READLINK reply
+ */
+ static int
+-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
++nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
+ {
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct kvec *iov = rcvbuf->head;
+@@ -586,7 +601,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req
+ * Decode WRITE reply
+ */
+ static int
+-nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
++nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
+ {
+ res->verf->committed = NFS_FILE_SYNC;
+ return nfs_xdr_attrstat(req, p, res->fattr);
+@@ -596,7 +611,7 @@ nfs_xdr_writeres(struct rpc_rqst *req, u
+ * Decode STATFS reply
+ */
+ static int
+-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
++nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
+ {
+ int status;
+
+diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
+index 7143b1f..e5f128f 100644
+--- a/fs/nfs/nfs3proc.c
++++ b/fs/nfs/nfs3proc.c
+@@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client
+ }
+
+ /*
+- * Bare-bones access to getattr: this is for nfs_read_super.
++ * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
+ */
+ static int
+ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+@@ -90,8 +90,8 @@ nfs3_proc_get_root(struct nfs_server *se
+ int status;
+
+ status = do_proc_get_root(server->client, fhandle, info);
+- if (status && server->client_sys != server->client)
+- status = do_proc_get_root(server->client_sys, fhandle, info);
++ if (status && server->nfs_client->cl_rpcclient != server->client)
++ status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info);
+ return status;
+ }
+
+@@ -449,7 +449,7 @@ nfs3_proc_unlink_setup(struct rpc_messag
+ struct nfs_fattr res;
+ } *ptr;
+
+- ptr = (struct unlinkxdr *)kmalloc(sizeof(*ptr), GFP_KERNEL);
++ ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+ ptr->arg.fh = NFS_FH(dir->d_inode);
+@@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, stru
+ }
+
+ static int
+-nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
+- struct iattr *sattr, struct nfs_fh *fhandle,
+- struct nfs_fattr *fattr)
++nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
++ unsigned int len, struct iattr *sattr)
+ {
+- struct nfs_fattr dir_attr;
++ struct nfs_fh fhandle;
++ struct nfs_fattr fattr, dir_attr;
+ struct nfs3_symlinkargs arg = {
+ .fromfh = NFS_FH(dir),
+- .fromname = name->name,
+- .fromlen = name->len,
+- .topath = path->name,
+- .tolen = path->len,
++ .fromname = dentry->d_name.name,
++ .fromlen = dentry->d_name.len,
++ .pages = &page,
++ .pathlen = len,
+ .sattr = sattr
+ };
+ struct nfs3_diropres res = {
+ .dir_attr = &dir_attr,
+- .fh = fhandle,
+- .fattr = fattr
++ .fh = &fhandle,
++ .fattr = &fattr
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
+@@ -569,13 +569,19 @@ nfs3_proc_symlink(struct inode *dir, str
+ };
+ int status;
+
+- if (path->len > NFS3_MAXPATHLEN)
++ if (len > NFS3_MAXPATHLEN)
+ return -ENAMETOOLONG;
+- dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
++
++ dprintk("NFS call symlink %s\n", dentry->d_name.name);
++
+ nfs_fattr_init(&dir_attr);
+- nfs_fattr_init(fattr);
++ nfs_fattr_init(&fattr);
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ nfs_post_op_update_inode(dir, &dir_attr);
++ if (status != 0)
++ goto out;
++ status = nfs_instantiate(dentry, &fhandle, &fattr);
++out:
+ dprintk("NFS reply symlink: %d\n", status);
+ return status;
+ }
+@@ -662,7 +668,7 @@ nfs3_proc_readdir(struct dentry *dentry,
+ {
+ struct inode *dir = dentry->d_inode;
+ struct nfs_fattr dir_attr;
+- u32 *verf = NFS_COOKIEVERF(dir);
++ __be32 *verf = NFS_COOKIEVERF(dir);
+ struct nfs3_readdirargs arg = {
+ .fh = NFS_FH(dir),
+ .cookie = cookie,
+@@ -785,7 +791,7 @@ nfs3_proc_fsinfo(struct nfs_server *serv
+
+ dprintk("NFS call fsinfo\n");
+ nfs_fattr_init(info->fattr);
+- status = rpc_call_sync(server->client_sys, &msg, 0);
++ status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
+ dprintk("NFS reply fsinfo: %d\n", status);
+ return status;
+ }
+@@ -886,7 +892,7 @@ nfs3_proc_lock(struct file *filp, int cm
+ return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
+ }
+
+-struct nfs_rpc_ops nfs_v3_clientops = {
++const struct nfs_rpc_ops nfs_v3_clientops = {
+ .version = 3, /* protocol version */
+ .dentry_ops = &nfs_dentry_operations,
+ .dir_inode_ops = &nfs3_dir_inode_operations,
+diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
+index 0250269..0ace092 100644
+--- a/fs/nfs/nfs3xdr.c
++++ b/fs/nfs/nfs3xdr.c
+@@ -56,7 +56,7 @@
+ #define NFS3_writeargs_sz (NFS3_fh_sz+5)
+ #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
+ #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
+-#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz)
++#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
+ #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
+ #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
+ #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
+@@ -105,14 +105,14 @@ static struct {
+ /*
+ * Common NFS XDR functions as inlines
+ */
+-static inline u32 *
+-xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
++static inline __be32 *
++xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
+ {
+ return xdr_encode_array(p, fh->data, fh->size);
+ }
+
+-static inline u32 *
+-xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
++static inline __be32 *
++xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
+ {
+ if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
+ memcpy(fh->data, p, fh->size);
+@@ -124,24 +124,24 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh
+ /*
+ * Encode/decode time.
+ */
+-static inline u32 *
+-xdr_encode_time3(u32 *p, struct timespec *timep)
++static inline __be32 *
++xdr_encode_time3(__be32 *p, struct timespec *timep)
+ {
+ *p++ = htonl(timep->tv_sec);
+ *p++ = htonl(timep->tv_nsec);
+ return p;
+ }
+
+-static inline u32 *
+-xdr_decode_time3(u32 *p, struct timespec *timep)
++static inline __be32 *
++xdr_decode_time3(__be32 *p, struct timespec *timep)
+ {
+ timep->tv_sec = ntohl(*p++);
+ timep->tv_nsec = ntohl(*p++);
+ return p;
+ }
+
+-static u32 *
+-xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
++static __be32 *
++xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
+ {
+ unsigned int type, major, minor;
+ int fmode;
+@@ -177,8 +177,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fatt
+ return p;
+ }
+
+-static inline u32 *
+-xdr_encode_sattr(u32 *p, struct iattr *attr)
++static inline __be32 *
++xdr_encode_sattr(__be32 *p, struct iattr *attr)
+ {
+ if (attr->ia_valid & ATTR_MODE) {
+ *p++ = xdr_one;
+@@ -223,8 +223,8 @@ xdr_encode_sattr(u32 *p, struct iattr *a
+ return p;
+ }
+
+-static inline u32 *
+-xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
++static inline __be32 *
++xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
+ {
+ p = xdr_decode_hyper(p, &fattr->pre_size);
+ p = xdr_decode_time3(p, &fattr->pre_mtime);
+@@ -233,16 +233,16 @@ xdr_decode_wcc_attr(u32 *p, struct nfs_f
+ return p;
+ }
+
+-static inline u32 *
+-xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
++static inline __be32 *
++xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
+ {
+ if (*p++)
+ p = xdr_decode_fattr(p, fattr);
+ return p;
+ }
+
+-static inline u32 *
+-xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
++static inline __be32 *
++xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
+ {
+ if (*p++)
+ return xdr_decode_wcc_attr(p, fattr);
+@@ -250,8 +250,8 @@ xdr_decode_pre_op_attr(u32 *p, struct nf
+ }
+
+
+-static inline u32 *
+-xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
++static inline __be32 *
++xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
+ {
+ p = xdr_decode_pre_op_attr(p, fattr);
+ return xdr_decode_post_op_attr(p, fattr);
+@@ -265,7 +265,7 @@ xdr_decode_wcc_data(u32 *p, struct nfs_f
+ * Encode file handle argument
+ */
+ static int
+-nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
++nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
+ {
+ p = xdr_encode_fhandle(p, fh);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+@@ -276,7 +276,7 @@ nfs3_xdr_fhandle(struct rpc_rqst *req, u
+ * Encode SETATTR arguments
+ */
+ static int
+-nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
++nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_sattr(p, args->sattr);
+@@ -291,7 +291,7 @@ nfs3_xdr_sattrargs(struct rpc_rqst *req,
+ * Encode directory ops argument
+ */
+ static int
+-nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
++nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+@@ -303,7 +303,7 @@ nfs3_xdr_diropargs(struct rpc_rqst *req,
+ * Encode access() argument
+ */
+ static int
+-nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
++nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ *p++ = htonl(args->access);
+@@ -317,7 +317,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req
+ * exactly to the page we want to fetch.
+ */
+ static int
+-nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
++nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+@@ -339,7 +339,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req,
+ * Write arguments. Splice the buffer to be written into the iovec.
+ */
+ static int
+-nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
++nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
+ {
+ struct xdr_buf *sndbuf = &req->rq_snd_buf;
+ u32 count = args->count;
+@@ -360,7 +360,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req,
+ * Encode CREATE arguments
+ */
+ static int
+-nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
++nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+@@ -380,7 +380,7 @@ nfs3_xdr_createargs(struct rpc_rqst *req
+ * Encode MKDIR arguments
+ */
+ static int
+-nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
++nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+@@ -393,13 +393,16 @@ nfs3_xdr_mkdirargs(struct rpc_rqst *req,
+ * Encode SYMLINK arguments
+ */
+ static int
+-nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
++nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
+ p = xdr_encode_sattr(p, args->sattr);
+- p = xdr_encode_array(p, args->topath, args->tolen);
++ *p++ = htonl(args->pathlen);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
++
++ /* Copy the page */
++ xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
+ return 0;
+ }
+
+@@ -407,7 +410,7 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *re
+ * Encode MKNOD arguments
+ */
+ static int
+-nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
++nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+@@ -426,7 +429,7 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req,
+ * Encode RENAME arguments
+ */
+ static int
+-nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
++nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
+@@ -440,7 +443,7 @@ nfs3_xdr_renameargs(struct rpc_rqst *req
+ * Encode LINK arguments
+ */
+ static int
+-nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
++nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_fhandle(p, args->tofh);
+@@ -453,7 +456,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req,
+ * Encode arguments to readdir call
+ */
+ static int
+-nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
++nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+@@ -482,7 +485,7 @@ nfs3_xdr_readdirargs(struct rpc_rqst *re
+ * We just check for syntactical correctness.
+ */
+ static int
+-nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
++nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
+ {
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct kvec *iov = rcvbuf->head;
+@@ -490,7 +493,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req
+ int hdrlen, recvd;
+ int status, nr;
+ unsigned int len, pglen;
+- u32 *entry, *end, *kaddr;
++ __be32 *entry, *end, *kaddr;
+
+ status = ntohl(*p++);
+ /* Decode post_op_attrs */
+@@ -520,8 +523,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req
+ if (pglen > recvd)
+ pglen = recvd;
+ page = rcvbuf->pages;
+- kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
+- end = (u32 *)((char *)p + pglen);
++ kaddr = p = kmap_atomic(*page, KM_USER0);
++ end = (__be32 *)((char *)p + pglen);
+ entry = p;
+ for (nr = 0; *p++; nr++) {
+ if (p + 3 > end)
+@@ -580,8 +583,8 @@ err_unmap:
+ goto out;
+ }
+
+-u32 *
+-nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
++__be32 *
++nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+ {
+ struct nfs_entry old = *entry;
+
+@@ -623,7 +626,7 @@ nfs3_decode_dirent(u32 *p, struct nfs_en
+ * Encode COMMIT arguments
+ */
+ static int
+-nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
++nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
+ {
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_hyper(p, args->offset);
+@@ -637,7 +640,7 @@ nfs3_xdr_commitargs(struct rpc_rqst *req
+ * Encode GETACL arguments
+ */
+ static int
+-nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
++nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
+ struct nfs3_getaclargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+@@ -661,7 +664,7 @@ nfs3_xdr_getaclargs(struct rpc_rqst *req
+ * Encode SETACL arguments
+ */
+ static int
+-nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
++nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
+ struct nfs3_setaclargs *args)
+ {
+ struct xdr_buf *buf = &req->rq_snd_buf;
+@@ -708,7 +711,7 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req
+ * Decode attrstat reply.
+ */
+ static int
+-nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
++nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
+ {
+ int status;
+
+@@ -723,7 +726,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req,
+ * SATTR, REMOVE, RMDIR
+ */
+ static int
+-nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
++nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
+ {
+ int status;
+
+@@ -737,7 +740,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, u
+ * Decode LOOKUP reply
+ */
+ static int
+-nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
++nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
+ {
+ int status;
+
+@@ -756,7 +759,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req,
+ * Decode ACCESS reply
+ */
+ static int
+-nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
++nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
+ {
+ int status = ntohl(*p++);
+
+@@ -768,7 +771,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req,
+ }
+
+ static int
+-nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
++nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+@@ -786,7 +789,7 @@ nfs3_xdr_readlinkargs(struct rpc_rqst *r
+ * Decode READLINK reply
+ */
+ static int
+-nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
++nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
+ {
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct kvec *iov = rcvbuf->head;
+@@ -834,7 +837,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *re
+ * Decode READ reply
+ */
+ static int
+-nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
++nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
+ {
+ struct kvec *iov = req->rq_rcv_buf.head;
+ int status, count, ocount, recvd, hdrlen;
+@@ -885,7 +888,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u
+ * Decode WRITE response
+ */
+ static int
+-nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
++nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
+ {
+ int status;
+
+@@ -907,7 +910,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req,
+ * Decode a CREATE response
+ */
+ static int
+-nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
++nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
+ {
+ int status;
+
+@@ -934,7 +937,7 @@ nfs3_xdr_createres(struct rpc_rqst *req,
+ * Decode RENAME reply
+ */
+ static int
+-nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
++nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
+ {
+ int status;
+
+@@ -949,7 +952,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req,
+ * Decode LINK reply
+ */
+ static int
+-nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
++nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
+ {
+ int status;
+
+@@ -964,7 +967,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u
+ * Decode FSSTAT reply
+ */
+ static int
+-nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
++nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
+ {
+ int status;
+
+@@ -989,7 +992,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req,
+ * Decode FSINFO reply
+ */
+ static int
+-nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
++nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
+ {
+ int status;
+
+@@ -1017,7 +1020,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req,
+ * Decode PATHCONF reply
+ */
+ static int
+-nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
++nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
+ {
+ int status;
+
+@@ -1037,7 +1040,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *re
+ * Decode COMMIT reply
+ */
+ static int
+-nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
++nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
+ {
+ int status;
+
+@@ -1056,7 +1059,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req,
+ * Decode GETACL reply
+ */
+ static int
+-nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
++nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
+ struct nfs3_getaclres *res)
+ {
+ struct xdr_buf *buf = &req->rq_rcv_buf;
+@@ -1088,7 +1091,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req,
+ * Decode setacl reply.
+ */
+ static int
+-nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
++nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
+ {
+ int status = ntohl(*p++);
+
+diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
+index 9a10286..6f34667 100644
+--- a/fs/nfs/nfs4_fs.h
++++ b/fs/nfs/nfs4_fs.h
+@@ -43,55 +43,6 @@ enum nfs4_client_state {
+ };
+
+ /*
+- * The nfs4_client identifies our client state to the server.
+- */
+-struct nfs4_client {
+- struct list_head cl_servers; /* Global list of servers */
+- struct in_addr cl_addr; /* Server identifier */
+- u64 cl_clientid; /* constant */
+- nfs4_verifier cl_confirm;
+- unsigned long cl_state;
+-
+- u32 cl_lockowner_id;
+-
+- /*
+- * The following rwsem ensures exclusive access to the server
+- * while we recover the state following a lease expiration.
+- */
+- struct rw_semaphore cl_sem;
+-
+- struct list_head cl_delegations;
+- struct list_head cl_state_owners;
+- struct list_head cl_unused;
+- int cl_nunused;
+- spinlock_t cl_lock;
+- atomic_t cl_count;
+-
+- struct rpc_clnt * cl_rpcclient;
+-
+- struct list_head cl_superblocks; /* List of nfs_server structs */
+-
+- unsigned long cl_lease_time;
+- unsigned long cl_last_renewal;
+- struct work_struct cl_renewd;
+- struct work_struct cl_recoverd;
+-
+- struct rpc_wait_queue cl_rpcwaitq;
+-
+- /* used for the setclientid verifier */
+- struct timespec cl_boot_time;
+-
+- /* idmapper */
+- struct idmap * cl_idmap;
+-
+- /* Our own IP address, as a null-terminated string.
+- * This is used to generate the clientid, and the callback address.
+- */
+- char cl_ipaddr[16];
+- unsigned char cl_id_uniquifier;
+-};
+-
+-/*
+ * struct rpc_sequence ensures that RPC calls are sent in the exact
+ * order that they appear on the list.
+ */
+@@ -127,7 +78,7 @@ static inline void nfs_confirm_seqid(str
+ struct nfs4_state_owner {
+ spinlock_t so_lock;
+ struct list_head so_list; /* per-clientid list of state_owners */
+- struct nfs4_client *so_client;
++ struct nfs_client *so_client;
+ u32 so_id; /* 32-bit identifier, unique */
+ atomic_t so_count;
+
+@@ -210,10 +161,10 @@ extern ssize_t nfs4_listxattr(struct den
+
+ /* nfs4proc.c */
+ extern int nfs4_map_errors(int err);
+-extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *);
+-extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *);
+-extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *);
+-extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
++extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *);
++extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
++extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
++extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
+ extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
+ extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
+ extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
+@@ -231,19 +182,14 @@ extern const u32 nfs4_fsinfo_bitmap[2];
+ extern const u32 nfs4_fs_locations_bitmap[2];
+
+ /* nfs4renewd.c */
+-extern void nfs4_schedule_state_renewal(struct nfs4_client *);
++extern void nfs4_schedule_state_renewal(struct nfs_client *);
+ extern void nfs4_renewd_prepare_shutdown(struct nfs_server *);
+-extern void nfs4_kill_renewd(struct nfs4_client *);
++extern void nfs4_kill_renewd(struct nfs_client *);
+ extern void nfs4_renew_state(void *);
+
+ /* nfs4state.c */
+-extern void init_nfsv4_state(struct nfs_server *);
+-extern void destroy_nfsv4_state(struct nfs_server *);
+-extern struct nfs4_client *nfs4_get_client(struct in_addr *);
+-extern void nfs4_put_client(struct nfs4_client *clp);
+-extern struct nfs4_client *nfs4_find_client(struct in_addr *);
+-struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp);
+-extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
++struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
++extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
+
+ extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
+ extern void nfs4_put_state_owner(struct nfs4_state_owner *);
+@@ -252,7 +198,7 @@ extern struct nfs4_state * nfs4_get_open
+ extern void nfs4_put_open_state(struct nfs4_state *);
+ extern void nfs4_close_state(struct nfs4_state *, mode_t);
+ extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
+-extern void nfs4_schedule_state_recovery(struct nfs4_client *);
++extern void nfs4_schedule_state_recovery(struct nfs_client *);
+ extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
+ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
+ extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
+@@ -266,7 +212,7 @@ extern void nfs_free_seqid(struct nfs_se
+ extern const nfs4_stateid zero_stateid;
+
+ /* nfs4xdr.c */
+-extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus);
++extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
+ extern struct rpc_procinfo nfs4_procedures[];
+
+ struct nfs4_mount_data;
+@@ -276,10 +222,6 @@ extern struct svc_version nfs4_callback_
+
+ #else
+
+-#define init_nfsv4_state(server) do { } while (0)
+-#define destroy_nfsv4_state(server) do { } while (0)
+-#define nfs4_put_state_owner(inode, owner) do { } while (0)
+-#define nfs4_put_open_state(state) do { } while (0)
+ #define nfs4_close_state(a, b) do { } while (0)
+
+ #endif /* CONFIG_NFS_V4 */
+diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
+index ea38d27..b872779 100644
+--- a/fs/nfs/nfs4namespace.c
++++ b/fs/nfs/nfs4namespace.c
+@@ -2,12 +2,11 @@
+ * linux/fs/nfs/nfs4namespace.c
+ *
+ * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust at netapp.com>
++ * - Modified by David Howells <dhowells at redhat.com>
+ *
+ * NFSv4 namespace
+ */
+
+-#include <linux/config.h>
+-
+ #include <linux/dcache.h>
+ #include <linux/mount.h>
+ #include <linux/namei.h>
+@@ -23,7 +22,7 @@
+ /*
+ * Check if fs_root is valid
+ */
+-static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
++static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
+ char *buffer, ssize_t buflen)
+ {
+ char *end = buffer + buflen;
+@@ -34,7 +33,7 @@ static inline char *nfs4_pathname_string
+
+ n = pathname->ncomponents;
+ while (--n >= 0) {
+- struct nfs4_string *component = &pathname->components[n];
++ const struct nfs4_string *component = &pathname->components[n];
+ buflen -= component->len + 1;
+ if (buflen < 0)
+ goto Elong;
+@@ -47,6 +46,68 @@ Elong:
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+
++/*
++ * Determine the mount path as a string
++ */
++static char *nfs4_path(const struct vfsmount *mnt_parent,
++ const struct dentry *dentry,
++ char *buffer, ssize_t buflen)
++{
++ const char *srvpath;
++
++ srvpath = strchr(mnt_parent->mnt_devname, ':');
++ if (srvpath)
++ srvpath++;
++ else
++ srvpath = mnt_parent->mnt_devname;
++
++ return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
++}
++
++/*
++ * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
++ * believe to be the server path to this dentry
++ */
++static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
++ const struct dentry *dentry,
++ const struct nfs4_fs_locations *locations,
++ char *page, char *page2)
++{
++ const char *path, *fs_path;
++
++ path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE);
++ if (IS_ERR(path))
++ return PTR_ERR(path);
++
++ fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
++ if (IS_ERR(fs_path))
++ return PTR_ERR(fs_path);
++
++ if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
++ dprintk("%s: path %s does not begin with fsroot %s\n",
++ __FUNCTION__, path, fs_path);
++ return -ENOENT;
++ }
++
++ return 0;
++}
++
++/*
++ * Check if the string represents a "valid" IPv4 address
++ */
++static inline int valid_ipaddr4(const char *buf)
++{
++ int rc, count, in[4];
++
++ rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
++ if (rc != 4)
++ return -EINVAL;
++ for (count = 0; count < 4; count++) {
++ if (in[count] > 255)
++ return -EINVAL;
++ }
++ return 0;
++}
+
+ /**
+ * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
+@@ -60,7 +121,7 @@ Elong:
+ */
+ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry,
+- struct nfs4_fs_locations *locations)
++ const struct nfs4_fs_locations *locations)
+ {
+ struct vfsmount *mnt = ERR_PTR(-ENOENT);
+ struct nfs_clone_mount mountdata = {
+@@ -68,10 +129,9 @@ static struct vfsmount *nfs_follow_refer
+ .dentry = dentry,
+ .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
+ };
+- char *page, *page2;
+- char *path, *fs_path;
++ char *page = NULL, *page2 = NULL;
+ char *devname;
+- int loc, s;
++ int loc, s, error;
+
+ if (locations == NULL || locations->nlocations <= 0)
+ goto out;
+@@ -79,36 +139,30 @@ static struct vfsmount *nfs_follow_refer
+ dprintk("%s: referral at %s/%s\n", __FUNCTION__,
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+
+- /* Ensure fs path is a prefix of current dentry path */
+ page = (char *) __get_free_page(GFP_USER);
+- if (page == NULL)
++ if (!page)
+ goto out;
++
+ page2 = (char *) __get_free_page(GFP_USER);
+- if (page2 == NULL)
++ if (!page2)
+ goto out;
+
+- path = nfs4_path(dentry, page, PAGE_SIZE);
+- if (IS_ERR(path))
+- goto out_free;
+-
+- fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
+- if (IS_ERR(fs_path))
+- goto out_free;
+-
+- if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
+- dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
+- goto out_free;
++ /* Ensure fs path is a prefix of current dentry path */
++ error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2);
++ if (error < 0) {
++ mnt = ERR_PTR(error);
++ goto out;
+ }
+
+ devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
+ if (IS_ERR(devname)) {
+ mnt = (struct vfsmount *)devname;
+- goto out_free;
++ goto out;
+ }
+
+ loc = 0;
+ while (loc < locations->nlocations && IS_ERR(mnt)) {
+- struct nfs4_fs_location *location = &locations->locations[loc];
++ const struct nfs4_fs_location *location = &locations->locations[loc];
+ char *mnt_path;
+
+ if (location == NULL || location->nservers <= 0 ||
+@@ -140,7 +194,7 @@ static struct vfsmount *nfs_follow_refer
+ addr.sin_port = htons(NFS_PORT);
+ mountdata.addr = &addr;
+
+- mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
++ mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata);
+ if (!IS_ERR(mnt)) {
+ break;
+ }
+@@ -149,10 +203,9 @@ static struct vfsmount *nfs_follow_refer
+ loc++;
+ }
+
+-out_free:
+- free_page((unsigned long)page);
+- free_page((unsigned long)page2);
+ out:
++ free_page((unsigned long) page);
++ free_page((unsigned long) page2);
+ dprintk("%s: done\n", __FUNCTION__);
+ return mnt;
+ }
+@@ -165,7 +218,7 @@ out:
+ */
+ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
+ {
+- struct vfsmount *mnt = ERR_PTR(-ENOENT);
++ struct vfsmount *mnt = ERR_PTR(-ENOMEM);
+ struct dentry *parent;
+ struct nfs4_fs_locations *fs_locations = NULL;
+ struct page *page;
+@@ -183,11 +236,16 @@ struct vfsmount *nfs_do_refmount(const s
+ goto out_free;
+
+ /* Get locations */
++ mnt = ERR_PTR(-ENOENT);
++
+ parent = dget_parent(dentry);
+- dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
++ dprintk("%s: getting locations for %s/%s\n",
++ __FUNCTION__, parent->d_name.name, dentry->d_name.name);
++
+ err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
+ dput(parent);
+- if (err != 0 || fs_locations->nlocations <= 0 ||
++ if (err != 0 ||
++ fs_locations->nlocations <= 0 ||
+ fs_locations->fs_path.ncomponents <= 0)
+ goto out_free;
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index b14145b..8118036 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -55,7 +55,7 @@
+
+ #define NFSDBG_FACILITY NFSDBG_PROC
+
+-#define NFS4_POLL_RETRY_MIN (1*HZ)
++#define NFS4_POLL_RETRY_MIN (HZ/10)
+ #define NFS4_POLL_RETRY_MAX (15*HZ)
+
+ struct nfs4_opendata;
+@@ -64,7 +64,7 @@ static int nfs4_do_fsinfo(struct nfs_ser
+ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
+ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
+ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
+-static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
++static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
+
+ /* Prevent leaks of NFSv4 errors into userland */
+ int nfs4_map_errors(int err)
+@@ -138,10 +138,10 @@ const u32 nfs4_fs_locations_bitmap[2] =
+ | FATTR4_WORD1_MOUNTED_ON_FILEID
+ };
+
+-static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
++static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
+ struct nfs4_readdir_arg *readdir)
+ {
+- u32 *start, *p;
++ __be32 *start, *p;
+
+ BUG_ON(readdir->count < 80);
+ if (cookie > 2) {
+@@ -162,7 +162,7 @@ static void nfs4_setup_readdir(u64 cooki
+ * when talking to the server, we always send cookie 0
+ * instead of 1 or 2.
+ */
+- start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
++ start = p = kmap_atomic(*readdir->pages, KM_USER0);
+
+ if (cookie == 0) {
+ *p++ = xdr_one; /* next */
+@@ -195,7 +195,7 @@ static void nfs4_setup_readdir(u64 cooki
+
+ static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
+ {
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+ spin_lock(&clp->cl_lock);
+ if (time_before(clp->cl_last_renewal,timestamp))
+ clp->cl_last_renewal = timestamp;
+@@ -252,7 +252,7 @@ static struct nfs4_opendata *nfs4_openda
+ atomic_inc(&sp->so_count);
+ p->o_arg.fh = NFS_FH(dir);
+ p->o_arg.open_flags = flags,
+- p->o_arg.clientid = server->nfs4_state->cl_clientid;
++ p->o_arg.clientid = server->nfs_client->cl_clientid;
+ p->o_arg.id = sp->so_id;
+ p->o_arg.name = &dentry->d_name;
+ p->o_arg.server = server;
+@@ -550,7 +550,7 @@ int nfs4_open_delegation_recall(struct d
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_EXPIRED:
+ /* Don't recall a delegation if it was lost */
+- nfs4_schedule_state_recovery(server->nfs4_state);
++ nfs4_schedule_state_recovery(server->nfs_client);
+ return err;
+ }
+ err = nfs4_handle_exception(server, err, &exception);
+@@ -758,7 +758,7 @@ static int _nfs4_proc_open(struct nfs4_o
+ }
+ nfs_confirm_seqid(&data->owner->so_seqid, 0);
+ if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
+- return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
++ return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
+ return 0;
+ }
+
+@@ -792,11 +792,18 @@ out:
+
+ int nfs4_recover_expired_lease(struct nfs_server *server)
+ {
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
++ int ret;
+
+- if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
++ for (;;) {
++ ret = nfs4_wait_clnt_recover(server->client, clp);
++ if (ret != 0)
++ return ret;
++ if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
++ break;
+ nfs4_schedule_state_recovery(clp);
+- return nfs4_wait_clnt_recover(server->client, clp);
++ }
++ return 0;
+ }
+
+ /*
+@@ -867,7 +874,7 @@ static int _nfs4_open_delegated(struct i
+ {
+ struct nfs_delegation *delegation;
+ struct nfs_server *server = NFS_SERVER(inode);
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs4_state_owner *sp = NULL;
+ struct nfs4_state *state = NULL;
+@@ -953,7 +960,7 @@ static int _nfs4_do_open(struct inode *d
+ struct nfs4_state_owner *sp;
+ struct nfs4_state *state = NULL;
+ struct nfs_server *server = NFS_SERVER(dir);
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+ struct nfs4_opendata *opendata;
+ int status;
+
+@@ -1133,7 +1140,7 @@ static void nfs4_close_done(struct rpc_t
+ break;
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_EXPIRED:
+- nfs4_schedule_state_recovery(server->nfs4_state);
++ nfs4_schedule_state_recovery(server->nfs_client);
+ break;
+ default:
+ if (nfs4_async_handle_error(task, server) == -EAGAIN) {
+@@ -1268,7 +1275,7 @@ nfs4_atomic_open(struct inode *dir, stru
+ BUG_ON(nd->intent.open.flags & O_CREAT);
+ }
+
+- cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
++ cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
+ if (IS_ERR(cred))
+ return (struct dentry *)cred;
+ state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred);
+@@ -1291,7 +1298,7 @@ nfs4_open_revalidate(struct inode *dir,
+ struct rpc_cred *cred;
+ struct nfs4_state *state;
+
+- cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
++ cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
+ if (IS_ERR(cred))
+ return PTR_ERR(cred);
+ state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
+@@ -1307,11 +1314,9 @@ nfs4_open_revalidate(struct inode *dir,
+ case -EROFS:
+ lookup_instantiate_filp(nd, (struct dentry *)state, NULL);
+ return 1;
+- case -ENOENT:
+- if (dentry->d_inode == NULL)
+- return 1;
++ default:
++ goto out_drop;
+ }
+- goto out_drop;
+ }
+ if (state->inode == dentry->d_inode) {
+ nfs4_intent_set_file(nd, dentry, state);
+@@ -1393,70 +1398,19 @@ static int nfs4_lookup_root(struct nfs_s
+ return err;
+ }
+
++/*
++ * get the file handle for the "/" directory on the server
++ */
+ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+- struct nfs_fsinfo *info)
++ struct nfs_fsinfo *info)
+ {
+- struct nfs_fattr * fattr = info->fattr;
+- unsigned char * p;
+- struct qstr q;
+- struct nfs4_lookup_arg args = {
+- .dir_fh = fhandle,
+- .name = &q,
+- .bitmask = nfs4_fattr_bitmap,
+- };
+- struct nfs4_lookup_res res = {
+- .server = server,
+- .fattr = fattr,
+- .fh = fhandle,
+- };
+- struct rpc_message msg = {
+- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
+- .rpc_argp = &args,
+- .rpc_resp = &res,
+- };
+ int status;
+
+- /*
+- * Now we do a separate LOOKUP for each component of the mount path.
+- * The LOOKUPs are done separately so that we can conveniently
+- * catch an ERR_WRONGSEC if it occurs along the way...
+- */
+ status = nfs4_lookup_root(server, fhandle, info);
+- if (status)
+- goto out;
+-
+- p = server->mnt_path;
+- for (;;) {
+- struct nfs4_exception exception = { };
+-
+- while (*p == '/')
+- p++;
+- if (!*p)
+- break;
+- q.name = p;
+- while (*p && (*p != '/'))
+- p++;
+- q.len = p - q.name;
+-
+- do {
+- nfs_fattr_init(fattr);
+- status = nfs4_handle_exception(server,
+- rpc_call_sync(server->client, &msg, 0),
+- &exception);
+- } while (exception.retry);
+- if (status == 0)
+- continue;
+- if (status == -ENOENT) {
+- printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
+- printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
+- }
+- break;
+- }
+ if (status == 0)
+ status = nfs4_server_capabilities(server, fhandle);
+ if (status == 0)
+ status = nfs4_do_fsinfo(server, fhandle, info);
+-out:
+ return nfs4_map_errors(status);
+ }
+
+@@ -1565,7 +1519,7 @@ nfs4_proc_setattr(struct dentry *dentry,
+
+ nfs_fattr_init(fattr);
+
+- cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
++ cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ if (IS_ERR(cred))
+ return PTR_ERR(cred);
+
+@@ -1583,6 +1537,52 @@ nfs4_proc_setattr(struct dentry *dentry,
+ return status;
+ }
+
++static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
++ struct qstr *name, struct nfs_fh *fhandle,
++ struct nfs_fattr *fattr)
++{
++ int status;
++ struct nfs4_lookup_arg args = {
++ .bitmask = server->attr_bitmask,
++ .dir_fh = dirfh,
++ .name = name,
++ };
++ struct nfs4_lookup_res res = {
++ .server = server,
++ .fattr = fattr,
++ .fh = fhandle,
++ };
++ struct rpc_message msg = {
++ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
++ .rpc_argp = &args,
++ .rpc_resp = &res,
++ };
++
++ nfs_fattr_init(fattr);
++
++ dprintk("NFS call lookupfh %s\n", name->name);
++ status = rpc_call_sync(server->client, &msg, 0);
++ dprintk("NFS reply lookupfh: %d\n", status);
++ if (status == -NFS4ERR_MOVED)
++ status = -EREMOTE;
++ return status;
++}
++
++static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
++ struct qstr *name, struct nfs_fh *fhandle,
++ struct nfs_fattr *fattr)
++{
++ struct nfs4_exception exception = { };
++ int err;
++ do {
++ err = nfs4_handle_exception(server,
++ _nfs4_proc_lookupfh(server, dirfh, name,
++ fhandle, fattr),
++ &exception);
++ } while (exception.retry);
++ return err;
++}
++
+ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+ {
+@@ -1881,7 +1881,7 @@ nfs4_proc_create(struct inode *dir, stru
+ struct rpc_cred *cred;
+ int status = 0;
+
+- cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
++ cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
+ if (IS_ERR(cred)) {
+ status = PTR_ERR(cred);
+ goto out;
+@@ -2089,24 +2089,24 @@ static int nfs4_proc_link(struct inode *
+ return err;
+ }
+
+-static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
+- struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
+- struct nfs_fattr *fattr)
++static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
++ struct page *page, unsigned int len, struct iattr *sattr)
+ {
+ struct nfs_server *server = NFS_SERVER(dir);
+- struct nfs_fattr dir_fattr;
++ struct nfs_fh fhandle;
++ struct nfs_fattr fattr, dir_fattr;
+ struct nfs4_create_arg arg = {
+ .dir_fh = NFS_FH(dir),
+ .server = server,
+- .name = name,
++ .name = &dentry->d_name,
+ .attrs = sattr,
+ .ftype = NF4LNK,
+ .bitmask = server->attr_bitmask,
+ };
+ struct nfs4_create_res res = {
+ .server = server,
+- .fh = fhandle,
+- .fattr = fattr,
++ .fh = &fhandle,
++ .fattr = &fattr,
+ .dir_fattr = &dir_fattr,
+ };
+ struct rpc_message msg = {
+@@ -2116,29 +2116,32 @@ static int _nfs4_proc_symlink(struct ino
+ };
+ int status;
+
+- if (path->len > NFS4_MAXPATHLEN)
++ if (len > NFS4_MAXPATHLEN)
+ return -ENAMETOOLONG;
+- arg.u.symlink = path;
+- nfs_fattr_init(fattr);
++
++ arg.u.symlink.pages = &page;
++ arg.u.symlink.len = len;
++ nfs_fattr_init(&fattr);
+ nfs_fattr_init(&dir_fattr);
+
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+- if (!status)
++ if (!status) {
+ update_changeattr(dir, &res.dir_cinfo);
+- nfs_post_op_update_inode(dir, res.dir_fattr);
++ nfs_post_op_update_inode(dir, res.dir_fattr);
++ status = nfs_instantiate(dentry, &fhandle, &fattr);
++ }
+ return status;
+ }
+
+-static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
+- struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
+- struct nfs_fattr *fattr)
++static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
++ struct page *page, unsigned int len, struct iattr *sattr)
+ {
+ struct nfs4_exception exception = { };
+ int err;
+ do {
+ err = nfs4_handle_exception(NFS_SERVER(dir),
+- _nfs4_proc_symlink(dir, name, path, sattr,
+- fhandle, fattr),
++ _nfs4_proc_symlink(dir, dentry, page,
++ len, sattr),
+ &exception);
+ } while (exception.retry);
+ return err;
+@@ -2521,7 +2524,7 @@ static void nfs4_proc_commit_setup(struc
+ */
+ static void nfs4_renew_done(struct rpc_task *task, void *data)
+ {
+- struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
++ struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp;
+ unsigned long timestamp = (unsigned long)data;
+
+ if (task->tk_status < 0) {
+@@ -2543,7 +2546,7 @@ static const struct rpc_call_ops nfs4_re
+ .rpc_call_done = nfs4_renew_done,
+ };
+
+-int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred)
++int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
+@@ -2555,7 +2558,7 @@ int nfs4_proc_async_renew(struct nfs4_cl
+ &nfs4_renew_ops, (void *)jiffies);
+ }
+
+-int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred)
++int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
+@@ -2770,7 +2773,7 @@ static int __nfs4_proc_set_acl(struct in
+ return -EOPNOTSUPP;
+ nfs_inode_return_delegation(inode);
+ buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
+- ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
++ ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+ if (ret == 0)
+ nfs4_write_cached_acl(inode, buf, buflen);
+ return ret;
+@@ -2791,7 +2794,7 @@ static int nfs4_proc_set_acl(struct inod
+ static int
+ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
+ {
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+
+ if (!clp || task->tk_status >= 0)
+ return 0;
+@@ -2828,7 +2831,7 @@ static int nfs4_wait_bit_interruptible(v
+ return 0;
+ }
+
+-static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
++static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp)
+ {
+ sigset_t oldset;
+ int res;
+@@ -2871,7 +2874,7 @@ static int nfs4_delay(struct rpc_clnt *c
+ */
+ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
+ {
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+ int ret = errorcode;
+
+ exception->retry = 0;
+@@ -2886,6 +2889,7 @@ int nfs4_handle_exception(const struct n
+ if (ret == 0)
+ exception->retry = 1;
+ break;
++ case -NFS4ERR_FILE_OPEN:
+ case -NFS4ERR_GRACE:
+ case -NFS4ERR_DELAY:
+ ret = nfs4_delay(server->client, &exception->timeout);
+@@ -2898,7 +2902,7 @@ int nfs4_handle_exception(const struct n
+ return nfs4_map_errors(ret);
+ }
+
+-int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred)
++int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred)
+ {
+ nfs4_verifier sc_verifier;
+ struct nfs4_setclientid setclientid = {
+@@ -2911,18 +2915,18 @@ int nfs4_proc_setclientid(struct nfs4_cl
+ .rpc_resp = clp,
+ .rpc_cred = cred,
+ };
+- u32 *p;
++ __be32 *p;
+ int loop = 0;
+ int status;
+
+- p = (u32*)sc_verifier.data;
++ p = (__be32*)sc_verifier.data;
+ *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
+ *p = htonl((u32)clp->cl_boot_time.tv_nsec);
+
+ for(;;) {
+ setclientid.sc_name_len = scnprintf(setclientid.sc_name,
+ sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u",
+- clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr),
++ clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr),
+ cred->cr_ops->cr_name,
+ clp->cl_id_uniquifier);
+ setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
+@@ -2945,7 +2949,7 @@ int nfs4_proc_setclientid(struct nfs4_cl
+ return status;
+ }
+
+-static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
++static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ struct nfs_fsinfo fsinfo;
+ struct rpc_message msg = {
+@@ -2969,7 +2973,7 @@ static int _nfs4_proc_setclientid_confir
+ return status;
+ }
+
+-int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
++int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ long timeout;
+ int err;
+@@ -3077,7 +3081,7 @@ int nfs4_proc_delegreturn(struct inode *
+ switch (err) {
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_EXPIRED:
+- nfs4_schedule_state_recovery(server->nfs4_state);
++ nfs4_schedule_state_recovery(server->nfs_client);
+ case 0:
+ return 0;
+ }
+@@ -3106,7 +3110,7 @@ static int _nfs4_proc_getlk(struct nfs4_
+ {
+ struct inode *inode = state->inode;
+ struct nfs_server *server = NFS_SERVER(inode);
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+ struct nfs_lockt_args arg = {
+ .fh = NFS_FH(inode),
+ .fl = request,
+@@ -3231,7 +3235,7 @@ static void nfs4_locku_done(struct rpc_t
+ break;
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_EXPIRED:
+- nfs4_schedule_state_recovery(calldata->server->nfs4_state);
++ nfs4_schedule_state_recovery(calldata->server->nfs_client);
+ break;
+ default:
+ if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) {
+@@ -3343,7 +3347,7 @@ static struct nfs4_lockdata *nfs4_alloc_
+ if (p->arg.lock_seqid == NULL)
+ goto out_free;
+ p->arg.lock_stateid = &lsp->ls_stateid;
+- p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid;
++ p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
+ p->arg.lock_owner.id = lsp->ls_id;
+ p->lsp = lsp;
+ atomic_inc(&lsp->ls_count);
+@@ -3513,7 +3517,7 @@ static int nfs4_lock_expired(struct nfs4
+
+ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
+ {
+- struct nfs4_client *clp = state->owner->so_client;
++ struct nfs_client *clp = state->owner->so_client;
+ unsigned char fl_flags = request->fl_flags;
+ int status;
+
+@@ -3715,7 +3719,7 @@ static struct inode_operations nfs4_file
+ .listxattr = nfs4_listxattr,
+ };
+
+-struct nfs_rpc_ops nfs_v4_clientops = {
++const struct nfs_rpc_ops nfs_v4_clientops = {
+ .version = 4, /* protocol version */
+ .dentry_ops = &nfs4_dentry_operations,
+ .dir_inode_ops = &nfs4_dir_inode_operations,
+@@ -3723,6 +3727,7 @@ struct nfs_rpc_ops nfs_v4_clientops = {
+ .getroot = nfs4_proc_get_root,
+ .getattr = nfs4_proc_getattr,
+ .setattr = nfs4_proc_setattr,
++ .lookupfh = nfs4_proc_lookupfh,
+ .lookup = nfs4_proc_lookup,
+ .access = nfs4_proc_access,
+ .readlink = nfs4_proc_readlink,
+@@ -3743,6 +3748,7 @@ struct nfs_rpc_ops nfs_v4_clientops = {
+ .statfs = nfs4_proc_statfs,
+ .fsinfo = nfs4_proc_fsinfo,
+ .pathconf = nfs4_proc_pathconf,
++ .set_capabilities = nfs4_server_capabilities,
+ .decode_dirent = nfs4_decode_dirent,
+ .read_setup = nfs4_proc_read_setup,
+ .read_done = nfs4_read_done,
+diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
+index 5d764d8..7b6df18 100644
+--- a/fs/nfs/nfs4renewd.c
++++ b/fs/nfs/nfs4renewd.c
+@@ -61,7 +61,7 @@
+ void
+ nfs4_renew_state(void *data)
+ {
+- struct nfs4_client *clp = (struct nfs4_client *)data;
++ struct nfs_client *clp = (struct nfs_client *)data;
+ struct rpc_cred *cred;
+ long lease, timeout;
+ unsigned long last, now;
+@@ -108,7 +108,7 @@ out:
+
+ /* Must be called with clp->cl_sem locked for writes */
+ void
+-nfs4_schedule_state_renewal(struct nfs4_client *clp)
++nfs4_schedule_state_renewal(struct nfs_client *clp)
+ {
+ long timeout;
+
+@@ -121,32 +121,20 @@ nfs4_schedule_state_renewal(struct nfs4_
+ __FUNCTION__, (timeout + HZ - 1) / HZ);
+ cancel_delayed_work(&clp->cl_renewd);
+ schedule_delayed_work(&clp->cl_renewd, timeout);
++ set_bit(NFS_CS_RENEWD, &clp->cl_res_state);
+ spin_unlock(&clp->cl_lock);
+ }
+
+ void
+ nfs4_renewd_prepare_shutdown(struct nfs_server *server)
+ {
+- struct nfs4_client *clp = server->nfs4_state;
+-
+- if (!clp)
+- return;
+ flush_scheduled_work();
+- down_write(&clp->cl_sem);
+- if (!list_empty(&server->nfs4_siblings))
+- list_del_init(&server->nfs4_siblings);
+- up_write(&clp->cl_sem);
+ }
+
+-/* Must be called with clp->cl_sem locked for writes */
+ void
+-nfs4_kill_renewd(struct nfs4_client *clp)
++nfs4_kill_renewd(struct nfs_client *clp)
+ {
+ down_read(&clp->cl_sem);
+- if (!list_empty(&clp->cl_superblocks)) {
+- up_read(&clp->cl_sem);
+- return;
+- }
+ cancel_delayed_work(&clp->cl_renewd);
+ up_read(&clp->cl_sem);
+ flush_scheduled_work();
+diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
+index 090a36b..5fffbdf 100644
+--- a/fs/nfs/nfs4state.c
++++ b/fs/nfs/nfs4state.c
+@@ -50,149 +50,15 @@
+ #include "nfs4_fs.h"
+ #include "callback.h"
+ #include "delegation.h"
++#include "internal.h"
+
+ #define OPENOWNER_POOL_SIZE 8
+
+ const nfs4_stateid zero_stateid;
+
+-static DEFINE_SPINLOCK(state_spinlock);
+ static LIST_HEAD(nfs4_clientid_list);
+
+-void
+-init_nfsv4_state(struct nfs_server *server)
+-{
+- server->nfs4_state = NULL;
+- INIT_LIST_HEAD(&server->nfs4_siblings);
+-}
+-
+-void
+-destroy_nfsv4_state(struct nfs_server *server)
+-{
+- kfree(server->mnt_path);
+- server->mnt_path = NULL;
+- if (server->nfs4_state) {
+- nfs4_put_client(server->nfs4_state);
+- server->nfs4_state = NULL;
+- }
+-}
+-
+-/*
+- * nfs4_get_client(): returns an empty client structure
+- * nfs4_put_client(): drops reference to client structure
+- *
+- * Since these are allocated/deallocated very rarely, we don't
+- * bother putting them in a slab cache...
+- */
+-static struct nfs4_client *
+-nfs4_alloc_client(struct in_addr *addr)
+-{
+- struct nfs4_client *clp;
+-
+- if (nfs_callback_up() < 0)
+- return NULL;
+- if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
+- nfs_callback_down();
+- return NULL;
+- }
+- memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
+- init_rwsem(&clp->cl_sem);
+- INIT_LIST_HEAD(&clp->cl_delegations);
+- INIT_LIST_HEAD(&clp->cl_state_owners);
+- INIT_LIST_HEAD(&clp->cl_unused);
+- spin_lock_init(&clp->cl_lock);
+- atomic_set(&clp->cl_count, 1);
+- INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
+- INIT_LIST_HEAD(&clp->cl_superblocks);
+- rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
+- clp->cl_rpcclient = ERR_PTR(-EINVAL);
+- clp->cl_boot_time = CURRENT_TIME;
+- clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
+- return clp;
+-}
+-
+-static void
+-nfs4_free_client(struct nfs4_client *clp)
+-{
+- struct nfs4_state_owner *sp;
+-
+- while (!list_empty(&clp->cl_unused)) {
+- sp = list_entry(clp->cl_unused.next,
+- struct nfs4_state_owner,
+- so_list);
+- list_del(&sp->so_list);
+- kfree(sp);
+- }
+- BUG_ON(!list_empty(&clp->cl_state_owners));
+- nfs_idmap_delete(clp);
+- if (!IS_ERR(clp->cl_rpcclient))
+- rpc_shutdown_client(clp->cl_rpcclient);
+- kfree(clp);
+- nfs_callback_down();
+-}
+-
+-static struct nfs4_client *__nfs4_find_client(struct in_addr *addr)
+-{
+- struct nfs4_client *clp;
+- list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
+- if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) {
+- atomic_inc(&clp->cl_count);
+- return clp;
+- }
+- }
+- return NULL;
+-}
+-
+-struct nfs4_client *nfs4_find_client(struct in_addr *addr)
+-{
+- struct nfs4_client *clp;
+- spin_lock(&state_spinlock);
+- clp = __nfs4_find_client(addr);
+- spin_unlock(&state_spinlock);
+- return clp;
+-}
+-
+-struct nfs4_client *
+-nfs4_get_client(struct in_addr *addr)
+-{
+- struct nfs4_client *clp, *new = NULL;
+-
+- spin_lock(&state_spinlock);
+- for (;;) {
+- clp = __nfs4_find_client(addr);
+- if (clp != NULL)
+- break;
+- clp = new;
+- if (clp != NULL) {
+- list_add(&clp->cl_servers, &nfs4_clientid_list);
+- new = NULL;
+- break;
+- }
+- spin_unlock(&state_spinlock);
+- new = nfs4_alloc_client(addr);
+- spin_lock(&state_spinlock);
+- if (new == NULL)
+- break;
+- }
+- spin_unlock(&state_spinlock);
+- if (new)
+- nfs4_free_client(new);
+- return clp;
+-}
+-
+-void
+-nfs4_put_client(struct nfs4_client *clp)
+-{
+- if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock))
+- return;
+- list_del(&clp->cl_servers);
+- spin_unlock(&state_spinlock);
+- BUG_ON(!list_empty(&clp->cl_superblocks));
+- rpc_wake_up(&clp->cl_rpcwaitq);
+- nfs4_kill_renewd(clp);
+- nfs4_free_client(clp);
+-}
+-
+-static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
++static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
+ nfs_callback_tcpport, cred);
+@@ -204,13 +70,13 @@ static int nfs4_init_client(struct nfs4_
+ }
+
+ u32
+-nfs4_alloc_lockowner_id(struct nfs4_client *clp)
++nfs4_alloc_lockowner_id(struct nfs_client *clp)
+ {
+ return clp->cl_lockowner_id ++;
+ }
+
+ static struct nfs4_state_owner *
+-nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
++nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ struct nfs4_state_owner *sp = NULL;
+
+@@ -224,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_clie
+ return sp;
+ }
+
+-struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
++struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
+ {
+ struct nfs4_state_owner *sp;
+ struct rpc_cred *cred = NULL;
+@@ -238,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(str
+ return cred;
+ }
+
+-struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp)
++struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
+ {
+ struct nfs4_state_owner *sp;
+
+@@ -251,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cr
+ }
+
+ static struct nfs4_state_owner *
+-nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred)
++nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred)
+ {
+ struct nfs4_state_owner *sp, *res = NULL;
+
+@@ -294,7 +160,7 @@ nfs4_alloc_state_owner(void)
+ void
+ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
+ {
+- struct nfs4_client *clp = sp->so_client;
++ struct nfs_client *clp = sp->so_client;
+ spin_lock(&clp->cl_lock);
+ list_del_init(&sp->so_list);
+ spin_unlock(&clp->cl_lock);
+@@ -306,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_
+ */
+ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
+ {
+- struct nfs4_client *clp = server->nfs4_state;
++ struct nfs_client *clp = server->nfs_client;
+ struct nfs4_state_owner *sp, *new;
+
+ get_rpccred(cred);
+@@ -337,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_
+ */
+ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
+ {
+- struct nfs4_client *clp = sp->so_client;
++ struct nfs_client *clp = sp->so_client;
+ struct rpc_cred *cred = sp->so_cred;
+
+ if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
+@@ -540,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state
+ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
+ {
+ struct nfs4_lock_state *lsp;
+- struct nfs4_client *clp = state->owner->so_client;
++ struct nfs_client *clp = state->owner->so_client;
+
+ lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
+ if (lsp == NULL)
+@@ -752,7 +618,7 @@ out:
+
+ static int reclaimer(void *);
+
+-static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
++static inline void nfs4_clear_recover_bit(struct nfs_client *clp)
+ {
+ smp_mb__before_clear_bit();
+ clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
+@@ -764,25 +630,25 @@ static inline void nfs4_clear_recover_bi
+ /*
+ * State recovery routine
+ */
+-static void nfs4_recover_state(struct nfs4_client *clp)
++static void nfs4_recover_state(struct nfs_client *clp)
+ {
+ struct task_struct *task;
+
+ __module_get(THIS_MODULE);
+ atomic_inc(&clp->cl_count);
+ task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
+- NIPQUAD(clp->cl_addr));
++ NIPQUAD(clp->cl_addr.sin_addr));
+ if (!IS_ERR(task))
+ return;
+ nfs4_clear_recover_bit(clp);
+- nfs4_put_client(clp);
++ nfs_put_client(clp);
+ module_put(THIS_MODULE);
+ }
+
+ /*
+ * Schedule a state recovery attempt
+ */
+-void nfs4_schedule_state_recovery(struct nfs4_client *clp)
++void nfs4_schedule_state_recovery(struct nfs_client *clp)
+ {
+ if (!clp)
+ return;
+@@ -879,7 +745,7 @@ out_err:
+ return status;
+ }
+
+-static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
++static void nfs4_state_mark_reclaim(struct nfs_client *clp)
+ {
+ struct nfs4_state_owner *sp;
+ struct nfs4_state *state;
+@@ -903,7 +769,7 @@ static void nfs4_state_mark_reclaim(stru
+
+ static int reclaimer(void *ptr)
+ {
+- struct nfs4_client *clp = ptr;
++ struct nfs_client *clp = ptr;
+ struct nfs4_state_owner *sp;
+ struct nfs4_state_recovery_ops *ops;
+ struct rpc_cred *cred;
+@@ -970,12 +836,12 @@ out:
+ if (status == -NFS4ERR_CB_PATH_DOWN)
+ nfs_handle_cb_pathdown(clp);
+ nfs4_clear_recover_bit(clp);
+- nfs4_put_client(clp);
++ nfs_put_client(clp);
+ module_put_and_exit(0);
+ return 0;
+ out_error:
+ printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
+- NIPQUAD(clp->cl_addr.s_addr), -status);
++ NIPQUAD(clp->cl_addr.sin_addr), -status);
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ goto out;
+ }
+diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
+index 730ec8f..0cf3fa3 100644
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -58,7 +58,7 @@
+ /* Mapping from NFS error code to "errno" error code. */
+ #define errno_NFSERR_IO EIO
+
+-static int nfs_stat_to_errno(int);
++static int nfs4_stat_to_errno(int);
+
+ /* NFSv4 COMPOUND tags are only wanted for debugging purposes */
+ #ifdef DEBUG
+@@ -128,7 +128,7 @@ static int nfs_stat_to_errno(int);
+ #define decode_link_maxsz (op_decode_hdr_maxsz + 5)
+ #define encode_symlink_maxsz (op_encode_hdr_maxsz + \
+ 1 + nfs4_name_maxsz + \
+- nfs4_path_maxsz + \
++ 1 + \
+ nfs4_fattr_maxsz)
+ #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
+ #define encode_create_maxsz (op_encode_hdr_maxsz + \
+@@ -471,7 +471,7 @@ struct compound_hdr {
+
+ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = xdr_reserve_space(xdr, 4 + len);
+ BUG_ON(p == NULL);
+@@ -480,7 +480,7 @@ static void encode_string(struct xdr_str
+
+ static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
+ BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
+@@ -494,7 +494,7 @@ static int encode_compound_hdr(struct xd
+
+ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
+ BUG_ON(p == NULL);
+@@ -507,8 +507,8 @@ static int encode_attrs(struct xdr_strea
+ char owner_group[IDMAP_NAMESZ];
+ int owner_namelen = 0;
+ int owner_grouplen = 0;
+- uint32_t *p;
+- uint32_t *q;
++ __be32 *p;
++ __be32 *q;
+ int len;
+ uint32_t bmval0 = 0;
+ uint32_t bmval1 = 0;
+@@ -529,7 +529,7 @@ static int encode_attrs(struct xdr_strea
+ if (iap->ia_valid & ATTR_MODE)
+ len += 4;
+ if (iap->ia_valid & ATTR_UID) {
+- owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name);
++ owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
+ if (owner_namelen < 0) {
+ printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
+ iap->ia_uid);
+@@ -541,7 +541,7 @@ static int encode_attrs(struct xdr_strea
+ len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
+ }
+ if (iap->ia_valid & ATTR_GID) {
+- owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group);
++ owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
+ if (owner_grouplen < 0) {
+ printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
+ iap->ia_gid);
+@@ -630,7 +630,7 @@ static int encode_attrs(struct xdr_strea
+
+ static int encode_access(struct xdr_stream *xdr, u32 access)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8);
+ WRITE32(OP_ACCESS);
+@@ -641,7 +641,7 @@ static int encode_access(struct xdr_stre
+
+ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8+sizeof(arg->stateid->data));
+ WRITE32(OP_CLOSE);
+@@ -653,7 +653,7 @@ static int encode_close(struct xdr_strea
+
+ static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(16);
+ WRITE32(OP_COMMIT);
+@@ -665,7 +665,7 @@ static int encode_commit(struct xdr_stre
+
+ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8);
+ WRITE32(OP_CREATE);
+@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stre
+
+ switch (create->ftype) {
+ case NF4LNK:
+- RESERVE_SPACE(4 + create->u.symlink->len);
+- WRITE32(create->u.symlink->len);
+- WRITEMEM(create->u.symlink->name, create->u.symlink->len);
++ RESERVE_SPACE(4);
++ WRITE32(create->u.symlink.len);
++ xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
+ break;
+
+ case NF4BLK: case NF4CHR:
+@@ -697,7 +697,7 @@ static int encode_create(struct xdr_stre
+
+ static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(12);
+ WRITE32(OP_GETATTR);
+@@ -708,7 +708,7 @@ static int encode_getattr_one(struct xdr
+
+ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(16);
+ WRITE32(OP_GETATTR);
+@@ -740,7 +740,7 @@ static int encode_fs_locations(struct xd
+
+ static int encode_getfh(struct xdr_stream *xdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_GETFH);
+@@ -750,7 +750,7 @@ static int encode_getfh(struct xdr_strea
+
+ static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8 + name->len);
+ WRITE32(OP_LINK);
+@@ -780,7 +780,7 @@ static inline uint64_t nfs4_lock_length(
+ */
+ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(32);
+ WRITE32(OP_LOCK);
+@@ -809,7 +809,7 @@ static int encode_lock(struct xdr_stream
+
+ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(40);
+ WRITE32(OP_LOCKT);
+@@ -825,7 +825,7 @@ static int encode_lockt(struct xdr_strea
+
+ static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(44);
+ WRITE32(OP_LOCKU);
+@@ -841,7 +841,7 @@ static int encode_locku(struct xdr_strea
+ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
+ {
+ int len = name->len;
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8 + len);
+ WRITE32(OP_LOOKUP);
+@@ -853,7 +853,7 @@ static int encode_lookup(struct xdr_stre
+
+ static void encode_share_access(struct xdr_stream *xdr, int open_flags)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8);
+ switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
+@@ -874,7 +874,7 @@ static void encode_share_access(struct x
+
+ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+ /*
+ * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
+ * owner 4 = 32
+@@ -891,7 +891,7 @@ static inline void encode_openhdr(struct
+
+ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ switch(arg->open_flags & O_EXCL) {
+@@ -907,7 +907,7 @@ static inline void encode_createmode(str
+
+ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ switch (arg->open_flags & O_CREAT) {
+@@ -923,7 +923,7 @@ static void encode_opentype(struct xdr_s
+
+ static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ switch (delegation_type) {
+@@ -943,7 +943,7 @@ static inline void encode_delegation_typ
+
+ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(NFS4_OPEN_CLAIM_NULL);
+@@ -952,7 +952,7 @@ static inline void encode_claim_null(str
+
+ static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
+@@ -961,7 +961,7 @@ static inline void encode_claim_previous
+
+ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4+sizeof(stateid->data));
+ WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
+@@ -991,7 +991,7 @@ static int encode_open(struct xdr_stream
+
+ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8+sizeof(arg->stateid->data));
+ WRITE32(OP_OPEN_CONFIRM);
+@@ -1003,7 +1003,7 @@ static int encode_open_confirm(struct xd
+
+ static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8+sizeof(arg->stateid->data));
+ WRITE32(OP_OPEN_DOWNGRADE);
+@@ -1017,7 +1017,7 @@ static int
+ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
+ {
+ int len = fh->size;
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8 + len);
+ WRITE32(OP_PUTFH);
+@@ -1029,7 +1029,7 @@ encode_putfh(struct xdr_stream *xdr, con
+
+ static int encode_putrootfh(struct xdr_stream *xdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_PUTROOTFH);
+@@ -1040,7 +1040,7 @@ static int encode_putrootfh(struct xdr_s
+ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
+ {
+ nfs4_stateid stateid;
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(16);
+ if (ctx->state != NULL) {
+@@ -1052,7 +1052,7 @@ static void encode_stateid(struct xdr_st
+
+ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_READ);
+@@ -1074,7 +1074,7 @@ static int encode_readdir(struct xdr_str
+ FATTR4_WORD1_MOUNTED_ON_FILEID,
+ };
+ int replen;
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(32+sizeof(nfs4_verifier));
+ WRITE32(OP_READDIR);
+@@ -1116,7 +1116,7 @@ static int encode_readlink(struct xdr_st
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_READLINK);
+@@ -1134,7 +1134,7 @@ static int encode_readlink(struct xdr_st
+
+ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8 + name->len);
+ WRITE32(OP_REMOVE);
+@@ -1146,7 +1146,7 @@ static int encode_remove(struct xdr_stre
+
+ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(8 + oldname->len);
+ WRITE32(OP_RENAME);
+@@ -1160,9 +1160,9 @@ static int encode_rename(struct xdr_stre
+ return 0;
+ }
+
+-static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid)
++static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(12);
+ WRITE32(OP_RENEW);
+@@ -1174,7 +1174,7 @@ static int encode_renew(struct xdr_strea
+ static int
+ encode_restorefh(struct xdr_stream *xdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_RESTOREFH);
+@@ -1185,7 +1185,7 @@ encode_restorefh(struct xdr_stream *xdr)
+ static int
+ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4+sizeof(zero_stateid.data));
+ WRITE32(OP_SETATTR);
+@@ -1204,7 +1204,7 @@ encode_setacl(struct xdr_stream *xdr, st
+ static int
+ encode_savefh(struct xdr_stream *xdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_SAVEFH);
+@@ -1215,7 +1215,7 @@ encode_savefh(struct xdr_stream *xdr)
+ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
+ {
+ int status;
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4+sizeof(arg->stateid.data));
+ WRITE32(OP_SETATTR);
+@@ -1229,7 +1229,7 @@ static int encode_setattr(struct xdr_str
+
+ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
+ WRITE32(OP_SETCLIENTID);
+@@ -1246,9 +1246,9 @@ static int encode_setclientid(struct xdr
+ return 0;
+ }
+
+-static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state)
++static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data));
+ WRITE32(OP_SETCLIENTID_CONFIRM);
+@@ -1260,7 +1260,7 @@ static int encode_setclientid_confirm(st
+
+ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_WRITE);
+@@ -1279,7 +1279,7 @@ static int encode_write(struct xdr_strea
+
+ static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ RESERVE_SPACE(20);
+
+@@ -1295,7 +1295,7 @@ static int encode_delegreturn(struct xdr
+ /*
+ * Encode an ACCESS request
+ */
+-static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
++static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1313,7 +1313,7 @@ static int nfs4_xdr_enc_access(struct rp
+ /*
+ * Encode LOOKUP request
+ */
+-static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
++static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1337,7 +1337,7 @@ out:
+ /*
+ * Encode LOOKUP_ROOT request
+ */
+-static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
++static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1358,7 +1358,7 @@ out:
+ /*
+ * Encode REMOVE request
+ */
+-static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
++static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1380,7 +1380,7 @@ out:
+ /*
+ * Encode RENAME request
+ */
+-static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
++static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1410,7 +1410,7 @@ out:
+ /*
+ * Encode LINK request
+ */
+-static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
++static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1440,7 +1440,7 @@ out:
+ /*
+ * Encode CREATE request
+ */
+-static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
++static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1470,7 +1470,7 @@ out:
+ /*
+ * Encode SYMLINK request
+ */
+-static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
++static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
+ {
+ return nfs4_xdr_enc_create(req, p, args);
+ }
+@@ -1478,7 +1478,7 @@ static int nfs4_xdr_enc_symlink(struct r
+ /*
+ * Encode GETATTR request
+ */
+-static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
++static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1496,7 +1496,7 @@ static int nfs4_xdr_enc_getattr(struct r
+ /*
+ * Encode a CLOSE request
+ */
+-static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
++static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1520,7 +1520,7 @@ out:
+ /*
+ * Encode an OPEN request
+ */
+-static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
++static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1556,7 +1556,7 @@ out:
+ /*
+ * Encode an OPEN_CONFIRM request
+ */
+-static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
++static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1577,7 +1577,7 @@ out:
+ /*
+ * Encode an OPEN request with no attributes.
+ */
+-static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
++static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1601,7 +1601,7 @@ out:
+ /*
+ * Encode an OPEN_DOWNGRADE request
+ */
+-static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
++static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1625,7 +1625,7 @@ out:
+ /*
+ * Encode a LOCK request
+ */
+-static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args)
++static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1646,7 +1646,7 @@ out:
+ /*
+ * Encode a LOCKT request
+ */
+-static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args)
++static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1667,7 +1667,7 @@ out:
+ /*
+ * Encode a LOCKU request
+ */
+-static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args)
++static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1688,7 +1688,7 @@ out:
+ /*
+ * Encode a READLINK request
+ */
+-static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
++static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1709,7 +1709,7 @@ out:
+ /*
+ * Encode a READDIR request
+ */
+-static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
++static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1730,7 +1730,7 @@ out:
+ /*
+ * Encode a READ request
+ */
+-static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
++static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
+ {
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct xdr_stream xdr;
+@@ -1762,7 +1762,7 @@ out:
+ /*
+ * Encode an SETATTR request
+ */
+-static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
++static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
+
+ {
+ struct xdr_stream xdr;
+@@ -1788,7 +1788,7 @@ out:
+ * Encode a GETACL request
+ */
+ static int
+-nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,
++nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
+ struct nfs_getaclargs *args)
+ {
+ struct xdr_stream xdr;
+@@ -1815,7 +1815,7 @@ out:
+ /*
+ * Encode a WRITE request
+ */
+-static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
++static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1839,7 +1839,7 @@ out:
+ /*
+ * a COMMIT request
+ */
+-static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
++static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1863,7 +1863,7 @@ out:
+ /*
+ * FSINFO request
+ */
+-static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
++static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1882,7 +1882,7 @@ static int nfs4_xdr_enc_fsinfo(struct rp
+ /*
+ * a PATHCONF request
+ */
+-static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
++static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1902,7 +1902,7 @@ static int nfs4_xdr_enc_pathconf(struct
+ /*
+ * a STATFS request
+ */
+-static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
++static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1923,7 +1923,7 @@ static int nfs4_xdr_enc_statfs(struct rp
+ /*
+ * GETATTR_BITMAP request
+ */
+-static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
++static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(stru
+ /*
+ * a RENEW request
+ */
+-static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
++static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1960,7 +1960,7 @@ static int nfs4_xdr_enc_renew(struct rpc
+ /*
+ * a SETCLIENTID request
+ */
+-static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
++static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(stru
+ /*
+ * a SETCLIENTID_CONFIRM request
+ */
+-static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
++static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -1997,7 +1997,7 @@ static int nfs4_xdr_enc_setclientid_conf
+ /*
+ * DELEGRETURN request
+ */
+-static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args)
++static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -2021,7 +2021,7 @@ out:
+ /*
+ * Encode FS_LOCATIONS request
+ */
+-static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
++static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -2086,7 +2086,7 @@ out:
+
+ static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ READ_BUF(4);
+ READ32(*len);
+@@ -2097,7 +2097,7 @@ static int decode_opaque_inline(struct x
+
+ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ READ_BUF(8);
+ READ32(hdr->status);
+@@ -2112,7 +2112,7 @@ static int decode_compound_hdr(struct xd
+
+ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t opnum;
+ int32_t nfserr;
+
+@@ -2127,14 +2127,14 @@ static int decode_op_hdr(struct xdr_stre
+ }
+ READ32(nfserr);
+ if (nfserr != NFS_OK)
+- return -nfs_stat_to_errno(nfserr);
++ return -nfs4_stat_to_errno(nfserr);
+ return 0;
+ }
+
+ /* Dummy routine */
+-static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
++static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
+ {
+- uint32_t *p;
++ __be32 *p;
+ unsigned int strlen;
+ char *str;
+
+@@ -2144,7 +2144,8 @@ static int decode_ace(struct xdr_stream
+
+ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+ {
+- uint32_t bmlen, *p;
++ uint32_t bmlen;
++ __be32 *p;
+
+ READ_BUF(4);
+ READ32(bmlen);
+@@ -2159,9 +2160,9 @@ static int decode_attr_bitmap(struct xdr
+ return 0;
+ }
+
+-static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep)
++static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ READ_BUF(4);
+ READ32(*attrlen);
+@@ -2182,7 +2183,7 @@ static int decode_attr_supported(struct
+
+ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *type = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
+@@ -2202,7 +2203,7 @@ static int decode_attr_type(struct xdr_s
+
+ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *change = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
+@@ -2219,7 +2220,7 @@ static int decode_attr_change(struct xdr
+
+ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *size = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
+@@ -2235,7 +2236,7 @@ static int decode_attr_size(struct xdr_s
+
+ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
+@@ -2251,7 +2252,7 @@ static int decode_attr_link_support(stru
+
+ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
+@@ -2267,7 +2268,7 @@ static int decode_attr_symlink_support(s
+
+ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ fsid->major = 0;
+ fsid->minor = 0;
+@@ -2287,7 +2288,7 @@ static int decode_attr_fsid(struct xdr_s
+
+ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *res = 60;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
+@@ -2303,7 +2304,7 @@ static int decode_attr_lease_time(struct
+
+ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
+@@ -2319,7 +2320,7 @@ static int decode_attr_aclsupport(struct
+
+ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *fileid = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
+@@ -2335,7 +2336,7 @@ static int decode_attr_fileid(struct xdr
+
+ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *fileid = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
+@@ -2351,7 +2352,7 @@ static int decode_attr_mounted_on_fileid
+
+ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2368,7 +2369,7 @@ static int decode_attr_files_avail(struc
+
+ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2385,7 +2386,7 @@ static int decode_attr_files_free(struct
+
+ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2403,7 +2404,7 @@ static int decode_attr_files_total(struc
+ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
+ {
+ int n;
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ READ_BUF(4);
+@@ -2448,7 +2449,7 @@ out_eio:
+ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
+ {
+ int n;
+- uint32_t *p;
++ __be32 *p;
+ int status = -EIO;
+
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
+@@ -2512,7 +2513,7 @@ out_eio:
+
+ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2529,7 +2530,7 @@ static int decode_attr_maxfilesize(struc
+
+ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *maxlink = 1;
+@@ -2546,7 +2547,7 @@ static int decode_attr_maxlink(struct xd
+
+ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *maxname = 1024;
+@@ -2563,7 +2564,7 @@ static int decode_attr_maxname(struct xd
+
+ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 1024;
+@@ -2584,7 +2585,7 @@ static int decode_attr_maxread(struct xd
+
+ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 1024;
+@@ -2605,7 +2606,7 @@ static int decode_attr_maxwrite(struct x
+
+ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *mode = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
+@@ -2622,7 +2623,7 @@ static int decode_attr_mode(struct xdr_s
+
+ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *nlink = 1;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
+@@ -2636,9 +2637,10 @@ static int decode_attr_nlink(struct xdr_
+ return 0;
+ }
+
+-static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid)
++static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid)
+ {
+- uint32_t len, *p;
++ uint32_t len;
++ __be32 *p;
+
+ *uid = -2;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
+@@ -2660,9 +2662,10 @@ static int decode_attr_owner(struct xdr_
+ return 0;
+ }
+
+-static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid)
++static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid)
+ {
+- uint32_t len, *p;
++ uint32_t len;
++ __be32 *p;
+
+ *gid = -2;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
+@@ -2686,7 +2689,8 @@ static int decode_attr_group(struct xdr_
+
+ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
+ {
+- uint32_t major = 0, minor = 0, *p;
++ uint32_t major = 0, minor = 0;
++ __be32 *p;
+
+ *rdev = MKDEV(0,0);
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
+@@ -2708,7 +2712,7 @@ static int decode_attr_rdev(struct xdr_s
+
+ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2725,7 +2729,7 @@ static int decode_attr_space_avail(struc
+
+ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2742,7 +2746,7 @@ static int decode_attr_space_free(struct
+
+ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status = 0;
+
+ *res = 0;
+@@ -2759,7 +2763,7 @@ static int decode_attr_space_total(struc
+
+ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ *used = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
+@@ -2776,7 +2780,7 @@ static int decode_attr_space_used(struct
+
+ static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint64_t sec;
+ uint32_t nsec;
+
+@@ -2836,7 +2840,7 @@ static int decode_attr_time_modify(struc
+ return status;
+ }
+
+-static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen)
++static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
+ {
+ unsigned int attrwords = XDR_QUADLEN(attrlen);
+ unsigned int nwords = xdr->p - savep;
+@@ -2854,7 +2858,7 @@ static int verify_attr_len(struct xdr_st
+
+ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
+ {
+- uint32_t *p;
++ __be32 *p;
+
+ READ_BUF(20);
+ READ32(cinfo->atomic);
+@@ -2865,7 +2869,7 @@ static int decode_change_info(struct xdr
+
+ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t supp, acc;
+ int status;
+
+@@ -2882,7 +2886,7 @@ static int decode_access(struct xdr_stre
+
+ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_CLOSE);
+@@ -2895,7 +2899,7 @@ static int decode_close(struct xdr_strea
+
+ static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_COMMIT);
+@@ -2908,7 +2912,7 @@ static int decode_commit(struct xdr_stre
+
+ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t bmlen;
+ int status;
+
+@@ -2925,7 +2929,7 @@ static int decode_create(struct xdr_stre
+
+ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
+ {
+- uint32_t *savep;
++ __be32 *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+@@ -2952,7 +2956,7 @@ xdr_error:
+
+ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
+ {
+- uint32_t *savep;
++ __be32 *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+@@ -2985,7 +2989,7 @@ xdr_error:
+
+ static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
+ {
+- uint32_t *savep;
++ __be32 *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+@@ -3010,7 +3014,7 @@ xdr_error:
+
+ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
+ {
+- uint32_t *savep;
++ __be32 *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0},
+ type;
+@@ -3051,9 +3055,9 @@ static int decode_getfattr(struct xdr_st
+ fattr->mode |= fmode;
+ if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
+ goto xdr_error;
+- if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0)
++ if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
+ goto xdr_error;
+- if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0)
++ if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
+ goto xdr_error;
+@@ -3079,7 +3083,7 @@ xdr_error:
+
+ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
+ {
+- uint32_t *savep;
++ __be32 *savep;
+ uint32_t attrlen, bitmap[2];
+ int status;
+
+@@ -3111,7 +3115,7 @@ xdr_error:
+
+ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t len;
+ int status;
+
+@@ -3147,7 +3151,7 @@ static int decode_link(struct xdr_stream
+ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
+ {
+ uint64_t offset, length, clientid;
+- uint32_t *p;
++ __be32 *p;
+ uint32_t namelen, type;
+
+ READ_BUF(32);
+@@ -3172,7 +3176,7 @@ static int decode_lock_denied (struct xd
+
+ static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_LOCK);
+@@ -3195,7 +3199,7 @@ static int decode_lockt(struct xdr_strea
+
+ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_LOCKU);
+@@ -3214,7 +3218,7 @@ static int decode_lookup(struct xdr_stre
+ /* This is too sick! */
+ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t limit_type, nblocks, blocksize;
+
+ READ_BUF(12);
+@@ -3233,7 +3237,7 @@ static int decode_space_limit(struct xdr
+
+ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t delegation_type;
+
+ READ_BUF(4);
+@@ -3254,12 +3258,12 @@ static int decode_delegation(struct xdr_
+ if (decode_space_limit(xdr, &res->maxsize) < 0)
+ return -EIO;
+ }
+- return decode_ace(xdr, NULL, res->server->nfs4_state);
++ return decode_ace(xdr, NULL, res->server->nfs_client);
+ }
+
+ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t bmlen;
+ int status;
+
+@@ -3287,7 +3291,7 @@ xdr_error:
+
+ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
+@@ -3300,7 +3304,7 @@ static int decode_open_confirm(struct xd
+
+ static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
+@@ -3324,7 +3328,7 @@ static int decode_putrootfh(struct xdr_s
+ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
+ {
+ struct kvec *iov = req->rq_rcv_buf.head;
+- uint32_t *p;
++ __be32 *p;
+ uint32_t count, eof, recvd, hdrlen;
+ int status;
+
+@@ -3354,7 +3358,7 @@ static int decode_readdir(struct xdr_str
+ struct page *page = *rcvbuf->pages;
+ struct kvec *iov = rcvbuf->head;
+ unsigned int nr, pglen = rcvbuf->page_len;
+- uint32_t *end, *entry, *p, *kaddr;
++ __be32 *end, *entry, *p, *kaddr;
+ uint32_t len, attrlen, xlen;
+ int hdrlen, recvd, status;
+
+@@ -3376,7 +3380,7 @@ static int decode_readdir(struct xdr_str
+ xdr_read_pages(xdr, pglen);
+
+ BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
+- kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
++ kaddr = p = kmap_atomic(page, KM_USER0);
+ end = p + ((pglen + readdir->pgbase) >> 2);
+ entry = p;
+ for (nr = 0; *p++; nr++) {
+@@ -3428,7 +3432,7 @@ static int decode_readlink(struct xdr_st
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct kvec *iov = rcvbuf->head;
+ int hdrlen, len, recvd;
+- uint32_t *p;
++ __be32 *p;
+ char *kaddr;
+ int status;
+
+@@ -3505,7 +3509,7 @@ decode_restorefh(struct xdr_stream *xdr)
+ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
+ size_t *acl_len)
+ {
+- uint32_t *savep;
++ __be32 *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ struct kvec *iov = req->rq_rcv_buf.head;
+@@ -3551,7 +3555,7 @@ decode_savefh(struct xdr_stream *xdr)
+
+ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t bmlen;
+ int status;
+
+@@ -3565,9 +3569,9 @@ static int decode_setattr(struct xdr_str
+ return 0;
+ }
+
+-static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
++static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
+ {
+- uint32_t *p;
++ __be32 *p;
+ uint32_t opnum;
+ int32_t nfserr;
+
+@@ -3598,7 +3602,7 @@ static int decode_setclientid(struct xdr
+ READ_BUF(len);
+ return -NFSERR_CLID_INUSE;
+ } else
+- return -nfs_stat_to_errno(nfserr);
++ return -nfs4_stat_to_errno(nfserr);
+
+ return 0;
+ }
+@@ -3610,7 +3614,7 @@ static int decode_setclientid_confirm(st
+
+ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
+ {
+- uint32_t *p;
++ __be32 *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_WRITE);
+@@ -3632,7 +3636,7 @@ static int decode_delegreturn(struct xdr
+ /*
+ * Decode OPEN_DOWNGRADE response
+ */
+-static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
++static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3660,7 +3664,7 @@ out:
+ /*
+ * Decode ACCESS response
+ */
+-static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
++static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3678,7 +3682,7 @@ out:
+ /*
+ * Decode LOOKUP response
+ */
+-static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
++static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3701,7 +3705,7 @@ out:
+ /*
+ * Decode LOOKUP_ROOT response
+ */
+-static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
++static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3721,7 +3725,7 @@ out:
+ /*
+ * Decode REMOVE response
+ */
+-static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res)
++static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3742,7 +3746,7 @@ out:
+ /*
+ * Decode RENAME response
+ */
+-static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
++static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3772,7 +3776,7 @@ out:
+ /*
+ * Decode LINK response
+ */
+-static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res)
++static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3805,7 +3809,7 @@ out:
+ /*
+ * Decode CREATE response
+ */
+-static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
++static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3834,7 +3838,7 @@ out:
+ /*
+ * Decode SYMLINK response
+ */
+-static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
++static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
+ {
+ return nfs4_xdr_dec_create(rqstp, p, res);
+ }
+@@ -3842,7 +3846,7 @@ static int nfs4_xdr_dec_symlink(struct r
+ /*
+ * Decode GETATTR response
+ */
+-static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
++static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3865,7 +3869,7 @@ out:
+ * Encode an SETACL request
+ */
+ static int
+-nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args)
++nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+@@ -3886,7 +3890,7 @@ out:
+ * Decode SETACL response
+ */
+ static int
+-nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res)
++nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3908,7 +3912,7 @@ out:
+ * Decode GETACL response
+ */
+ static int
+-nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len)
++nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3930,7 +3934,7 @@ out:
+ /*
+ * Decode CLOSE response
+ */
+-static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
++static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3960,7 +3964,7 @@ out:
+ /*
+ * Decode OPEN response
+ */
+-static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
++static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -3994,7 +3998,7 @@ out:
+ /*
+ * Decode OPEN_CONFIRM response
+ */
+-static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
++static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4015,7 +4019,7 @@ out:
+ /*
+ * Decode OPEN response
+ */
+-static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
++static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4039,7 +4043,7 @@ out:
+ /*
+ * Decode SETATTR response
+ */
+-static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
++static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4065,7 +4069,7 @@ out:
+ /*
+ * Decode LOCK response
+ */
+-static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res)
++static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4086,7 +4090,7 @@ out:
+ /*
+ * Decode LOCKT response
+ */
+-static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res)
++static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4107,7 +4111,7 @@ out:
+ /*
+ * Decode LOCKU response
+ */
+-static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res)
++static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4128,7 +4132,7 @@ out:
+ /*
+ * Decode READLINK response
+ */
+-static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
++static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4149,7 +4153,7 @@ out:
+ /*
+ * Decode READDIR response
+ */
+-static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
++static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4170,7 +4174,7 @@ out:
+ /*
+ * Decode Read response
+ */
+-static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
++static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4193,7 +4197,7 @@ out:
+ /*
+ * Decode WRITE response
+ */
+-static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
++static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4219,7 +4223,7 @@ out:
+ /*
+ * Decode COMMIT response
+ */
+-static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
++static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4243,7 +4247,7 @@ out:
+ /*
+ * FSINFO request
+ */
+-static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
++static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4256,14 +4260,14 @@ static int nfs4_xdr_dec_fsinfo(struct rp
+ if (!status)
+ status = decode_fsinfo(&xdr, fsinfo);
+ if (!status)
+- status = -nfs_stat_to_errno(hdr.status);
++ status = -nfs4_stat_to_errno(hdr.status);
+ return status;
+ }
+
+ /*
+ * PATHCONF request
+ */
+-static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
++static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4281,7 +4285,7 @@ static int nfs4_xdr_dec_pathconf(struct
+ /*
+ * STATFS request
+ */
+-static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
++static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4299,7 +4303,7 @@ static int nfs4_xdr_dec_statfs(struct rp
+ /*
+ * GETATTR_BITMAP request
+ */
+-static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res)
++static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4318,7 +4322,7 @@ out:
+ /*
+ * Decode RENEW response
+ */
+-static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
++static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4334,8 +4338,8 @@ static int nfs4_xdr_dec_renew(struct rpc
+ /*
+ * a SETCLIENTID request
+ */
+-static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
+- struct nfs4_client *clp)
++static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
++ struct nfs_client *clp)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4346,14 +4350,14 @@ static int nfs4_xdr_dec_setclientid(stru
+ if (!status)
+ status = decode_setclientid(&xdr, clp);
+ if (!status)
+- status = -nfs_stat_to_errno(hdr.status);
++ status = -nfs4_stat_to_errno(hdr.status);
+ return status;
+ }
+
+ /*
+ * a SETCLIENTID_CONFIRM request
+ */
+-static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
++static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4368,14 +4372,14 @@ static int nfs4_xdr_dec_setclientid_conf
+ if (!status)
+ status = decode_fsinfo(&xdr, fsinfo);
+ if (!status)
+- status = -nfs_stat_to_errno(hdr.status);
++ status = -nfs4_stat_to_errno(hdr.status);
+ return status;
+ }
+
+ /*
+ * DELEGRETURN request
+ */
+-static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res)
++static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4397,7 +4401,7 @@ out:
+ /*
+ * FS_LOCATIONS request
+ */
+-static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res)
++static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res)
+ {
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+@@ -4417,7 +4421,7 @@ out:
+ return status;
+ }
+
+-uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
++__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+ {
+ uint32_t bitmap[2] = {0};
+ uint32_t len;
+@@ -4521,7 +4525,7 @@ static struct {
+ * This one is used jointly by NFSv2 and NFSv3.
+ */
+ static int
+-nfs_stat_to_errno(int stat)
++nfs4_stat_to_errno(int stat)
+ {
+ int i;
+ for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
+index c0a754e..8dfefe4 100644
+--- a/fs/nfs/nfsroot.c
++++ b/fs/nfs/nfsroot.c
+@@ -69,7 +69,6 @@
+ * Fabian Frederick: Option parser rebuilt (using parser lib)
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+@@ -312,7 +311,7 @@ static int __init root_nfs_name(char *na
+ /* Override them by options set on kernel command-line */
+ root_nfs_parse(name, buf);
+
+- cp = system_utsname.nodename;
++ cp = utsname()->nodename;
+ if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
+ printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
+ return -1;
+diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
+index 36e902a..829af32 100644
+--- a/fs/nfs/pagelist.c
++++ b/fs/nfs/pagelist.c
+@@ -392,7 +392,6 @@ int __init nfs_init_nfspagecache(void)
+
+ void nfs_destroy_nfspagecache(void)
+ {
+- if (kmem_cache_destroy(nfs_page_cachep))
+- printk(KERN_INFO "nfs_page: not all structures were freed\n");
++ kmem_cache_destroy(nfs_page_cachep);
+ }
+
+diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
+index b3899ea..4529cc4 100644
+--- a/fs/nfs/proc.c
++++ b/fs/nfs/proc.c
+@@ -66,14 +66,14 @@ nfs_proc_get_root(struct nfs_server *ser
+
+ dprintk("%s: call getattr\n", __FUNCTION__);
+ nfs_fattr_init(fattr);
+- status = rpc_call_sync(server->client_sys, &msg, 0);
++ status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
+ dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
+ if (status)
+ return status;
+ dprintk("%s: call statfs\n", __FUNCTION__);
+ msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS];
+ msg.rpc_resp = &fsinfo;
+- status = rpc_call_sync(server->client_sys, &msg, 0);
++ status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
+ dprintk("%s: reply statfs: %d\n", __FUNCTION__, status);
+ if (status)
+ return status;
+@@ -352,7 +352,7 @@ nfs_proc_unlink_setup(struct rpc_message
+ {
+ struct nfs_diropargs *arg;
+
+- arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL);
++ arg = kmalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg)
+ return -ENOMEM;
+ arg->fh = NFS_FH(dir->d_inode);
+@@ -425,16 +425,17 @@ nfs_proc_link(struct inode *inode, struc
+ }
+
+ static int
+-nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
+- struct iattr *sattr, struct nfs_fh *fhandle,
+- struct nfs_fattr *fattr)
++nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
++ unsigned int len, struct iattr *sattr)
+ {
++ struct nfs_fh fhandle;
++ struct nfs_fattr fattr;
+ struct nfs_symlinkargs arg = {
+ .fromfh = NFS_FH(dir),
+- .fromname = name->name,
+- .fromlen = name->len,
+- .topath = path->name,
+- .tolen = path->len,
++ .fromname = dentry->d_name.name,
++ .fromlen = dentry->d_name.len,
++ .pages = &page,
++ .pathlen = len,
+ .sattr = sattr
+ };
+ struct rpc_message msg = {
+@@ -443,13 +444,25 @@ nfs_proc_symlink(struct inode *dir, stru
+ };
+ int status;
+
+- if (path->len > NFS2_MAXPATHLEN)
++ if (len > NFS2_MAXPATHLEN)
+ return -ENAMETOOLONG;
+- dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
+- nfs_fattr_init(fattr);
+- fhandle->size = 0;
++
++ dprintk("NFS call symlink %s\n", dentry->d_name.name);
++
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ nfs_mark_for_revalidate(dir);
++
++ /*
++ * V2 SYMLINK requests don't return any attributes. Setting the
++ * filehandle size to zero indicates to nfs_instantiate that it
++ * should fill in the data with a LOOKUP call on the wire.
++ */
++ if (status == 0) {
++ nfs_fattr_init(&fattr);
++ fhandle.size = 0;
++ status = nfs_instantiate(dentry, &fhandle, &fattr);
++ }
++
+ dprintk("NFS reply symlink: %d\n", status);
+ return status;
+ }
+@@ -671,7 +684,7 @@ nfs_proc_lock(struct file *filp, int cmd
+ }
+
+
+-struct nfs_rpc_ops nfs_v2_clientops = {
++const struct nfs_rpc_ops nfs_v2_clientops = {
+ .version = 2, /* protocol version */
+ .dentry_ops = &nfs_dentry_operations,
+ .dir_inode_ops = &nfs_dir_inode_operations,
+diff --git a/fs/nfs/read.c b/fs/nfs/read.c
+index f0aff82..c2e49c3 100644
+--- a/fs/nfs/read.c
++++ b/fs/nfs/read.c
+@@ -171,7 +171,7 @@ static int nfs_readpage_sync(struct nfs_
+ rdata->args.offset = page_offset(page) + rdata->args.pgbase;
+
+ dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
+- NFS_SERVER(inode)->hostname,
++ NFS_SERVER(inode)->nfs_client->cl_hostname,
+ inode->i_sb->s_id,
+ (long long)NFS_FILEID(inode),
+ (unsigned long long)rdata->args.pgbase,
+@@ -568,8 +568,13 @@ int nfs_readpage_result(struct rpc_task
+
+ nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count);
+
+- /* Is this a short read? */
+- if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) {
++ if (task->tk_status < 0) {
++ if (task->tk_status == -ESTALE) {
++ set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode));
++ nfs_mark_for_revalidate(data->inode);
++ }
++ } else if (resp->count < argp->count && !resp->eof) {
++ /* This is a short read! */
+ nfs_inc_stats(data->inode, NFSIOS_SHORTREAD);
+ /* Has the server at least made some progress? */
+ if (resp->count != 0) {
+@@ -616,6 +621,10 @@ int nfs_readpage(struct file *file, stru
+ if (error)
+ goto out_error;
+
++ error = -ESTALE;
++ if (NFS_STALE(inode))
++ goto out_error;
++
+ if (file == NULL) {
+ ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
+ if (ctx == NULL)
+@@ -678,7 +687,7 @@ int nfs_readpages(struct file *filp, str
+ };
+ struct inode *inode = mapping->host;
+ struct nfs_server *server = NFS_SERVER(inode);
+- int ret;
++ int ret = -ESTALE;
+
+ dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
+ inode->i_sb->s_id,
+@@ -686,6 +695,9 @@ int nfs_readpages(struct file *filp, str
+ nr_pages);
+ nfs_inc_stats(inode, NFSIOS_VFSREADPAGES);
+
++ if (NFS_STALE(inode))
++ goto out;
++
+ if (filp == NULL) {
+ desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
+ if (desc.ctx == NULL)
+@@ -701,6 +713,7 @@ int nfs_readpages(struct file *filp, str
+ ret = err;
+ }
+ put_nfs_open_context(desc.ctx);
++out:
+ return ret;
+ }
+
+@@ -724,6 +737,5 @@ int __init nfs_init_readpagecache(void)
+ void nfs_destroy_readpagecache(void)
+ {
+ mempool_destroy(nfs_rdata_mempool);
+- if (kmem_cache_destroy(nfs_rdata_cachep))
+- printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
++ kmem_cache_destroy(nfs_rdata_cachep);
+ }
+diff --git a/fs/nfs/super.c b/fs/nfs/super.c
+index e8a9bee..28108c8 100644
+--- a/fs/nfs/super.c
++++ b/fs/nfs/super.c
+@@ -13,9 +13,13 @@
+ *
+ * Split from inode.c by David Howells <dhowells at redhat.com>
+ *
++ * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a
++ * particular server are held in the same superblock
++ * - NFS superblocks can have several effective roots to the dentry tree
++ * - directory type roots are spliced into the tree when a path from one root reaches the root
++ * of another (see nfs_lookup())
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+
+@@ -52,66 +56,12 @@
+
+ #define NFSDBG_FACILITY NFSDBG_VFS
+
+-/* Maximum number of readahead requests
+- * FIXME: this should really be a sysctl so that users may tune it to suit
+- * their needs. People that do NFS over a slow network, might for
+- * instance want to reduce it to something closer to 1 for improved
+- * interactive response.
+- */
+-#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
+-
+-/*
+- * RPC cruft for NFS
+- */
+-static struct rpc_version * nfs_version[] = {
+- NULL,
+- NULL,
+- &nfs_version2,
+-#if defined(CONFIG_NFS_V3)
+- &nfs_version3,
+-#elif defined(CONFIG_NFS_V4)
+- NULL,
+-#endif
+-#if defined(CONFIG_NFS_V4)
+- &nfs_version4,
+-#endif
+-};
+-
+-static struct rpc_program nfs_program = {
+- .name = "nfs",
+- .number = NFS_PROGRAM,
+- .nrvers = ARRAY_SIZE(nfs_version),
+- .version = nfs_version,
+- .stats = &nfs_rpcstat,
+- .pipe_dir_name = "/nfs",
+-};
+-
+-struct rpc_stat nfs_rpcstat = {
+- .program = &nfs_program
+-};
+-
+-
+-#ifdef CONFIG_NFS_V3_ACL
+-static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
+-static struct rpc_version * nfsacl_version[] = {
+- [3] = &nfsacl_version3,
+-};
+-
+-struct rpc_program nfsacl_program = {
+- .name = "nfsacl",
+- .number = NFS_ACL_PROGRAM,
+- .nrvers = ARRAY_SIZE(nfsacl_version),
+- .version = nfsacl_version,
+- .stats = &nfsacl_rpcstat,
+-};
+-#endif /* CONFIG_NFS_V3_ACL */
+-
+ static void nfs_umount_begin(struct vfsmount *, int);
+ static int nfs_statfs(struct dentry *, struct kstatfs *);
+ static int nfs_show_options(struct seq_file *, struct vfsmount *);
+ static int nfs_show_stats(struct seq_file *, struct vfsmount *);
+ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
+-static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
++static int nfs_xdev_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+ static void nfs_kill_super(struct super_block *);
+
+@@ -120,15 +70,15 @@ static struct file_system_type nfs_fs_ty
+ .name = "nfs",
+ .get_sb = nfs_get_sb,
+ .kill_sb = nfs_kill_super,
+- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+ };
+
+-struct file_system_type clone_nfs_fs_type = {
++struct file_system_type nfs_xdev_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs",
+- .get_sb = nfs_clone_nfs_sb,
++ .get_sb = nfs_xdev_get_sb,
+ .kill_sb = nfs_kill_super,
+- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+ };
+
+ static struct super_operations nfs_sops = {
+@@ -145,10 +95,10 @@ static struct super_operations nfs_sops
+ #ifdef CONFIG_NFS_V4
+ static int nfs4_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+-static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
+- int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+-static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
+- int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
++static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
++static int nfs4_referral_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+ static void nfs4_kill_super(struct super_block *sb);
+
+ static struct file_system_type nfs4_fs_type = {
+@@ -156,23 +106,23 @@ static struct file_system_type nfs4_fs_t
+ .name = "nfs4",
+ .get_sb = nfs4_get_sb,
+ .kill_sb = nfs4_kill_super,
+- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+ };
+
+-struct file_system_type clone_nfs4_fs_type = {
++struct file_system_type nfs4_xdev_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+- .get_sb = nfs_clone_nfs4_sb,
++ .get_sb = nfs4_xdev_get_sb,
+ .kill_sb = nfs4_kill_super,
+- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+ };
+
+-struct file_system_type nfs_referral_nfs4_fs_type = {
++struct file_system_type nfs4_referral_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+- .get_sb = nfs_referral_nfs4_sb,
++ .get_sb = nfs4_referral_get_sb,
+ .kill_sb = nfs4_kill_super,
+- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+ };
+
+ static struct super_operations nfs4_sops = {
+@@ -187,39 +137,7 @@ static struct super_operations nfs4_sops
+ };
+ #endif
+
+-#ifdef CONFIG_NFS_V4
+-static const int nfs_set_port_min = 0;
+-static const int nfs_set_port_max = 65535;
+-
+-static int param_set_port(const char *val, struct kernel_param *kp)
+-{
+- char *endp;
+- int num = simple_strtol(val, &endp, 0);
+- if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
+- return -EINVAL;
+- *((int *)kp->arg) = num;
+- return 0;
+-}
+-
+-module_param_call(callback_tcpport, param_set_port, param_get_int,
+- &nfs_callback_set_tcpport, 0644);
+-#endif
+-
+-#ifdef CONFIG_NFS_V4
+-static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
+-{
+- char *endp;
+- int num = simple_strtol(val, &endp, 0);
+- int jif = num * HZ;
+- if (endp == val || *endp || num < 0 || jif < num)
+- return -EINVAL;
+- *((int *)kp->arg) = jif;
+- return 0;
+-}
+-
+-module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
+- &nfs_idmap_cache_timeout, 0644);
+-#endif
++static struct shrinker *acl_shrinker;
+
+ /*
+ * Register the NFS filesystems
+@@ -240,6 +158,7 @@ int __init register_nfs_fs(void)
+ if (ret < 0)
+ goto error_2;
+ #endif
++ acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker);
+ return 0;
+
+ #ifdef CONFIG_NFS_V4
+@@ -257,6 +176,8 @@ error_0:
+ */
+ void __exit unregister_nfs_fs(void)
+ {
++ if (acl_shrinker != NULL)
++ remove_shrinker(acl_shrinker);
+ #ifdef CONFIG_NFS_V4
+ unregister_filesystem(&nfs4_fs_type);
+ nfs_unregister_sysctl();
+@@ -269,11 +190,10 @@ void __exit unregister_nfs_fs(void)
+ */
+ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ {
+- struct super_block *sb = dentry->d_sb;
+- struct nfs_server *server = NFS_SB(sb);
++ struct nfs_server *server = NFS_SB(dentry->d_sb);
+ unsigned char blockbits;
+ unsigned long blockres;
+- struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
++ struct nfs_fh *fh = NFS_FH(dentry->d_inode);
+ struct nfs_fattr fattr;
+ struct nfs_fsstat res = {
+ .fattr = &fattr,
+@@ -282,7 +202,7 @@ static int nfs_statfs(struct dentry *den
+
+ lock_kernel();
+
+- error = server->rpc_ops->statfs(server, rootfh, &res);
++ error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
+ buf->f_type = NFS_SUPER_MAGIC;
+ if (error < 0)
+ goto out_err;
+@@ -292,7 +212,7 @@ static int nfs_statfs(struct dentry *den
+ * case where f_frsize != f_bsize. Eventually we want to
+ * report the value of wtmult in this field.
+ */
+- buf->f_frsize = sb->s_blocksize;
++ buf->f_frsize = dentry->d_sb->s_blocksize;
+
+ /*
+ * On most *nix systems, f_blocks, f_bfree, and f_bavail
+@@ -301,8 +221,8 @@ static int nfs_statfs(struct dentry *den
+ * thus historically Linux's sys_statfs reports these
+ * fields in units of f_bsize.
+ */
+- buf->f_bsize = sb->s_blocksize;
+- blockbits = sb->s_blocksize_bits;
++ buf->f_bsize = dentry->d_sb->s_blocksize;
++ blockbits = dentry->d_sb->s_blocksize_bits;
+ blockres = (1 << blockbits) - 1;
+ buf->f_blocks = (res.tbytes + blockres) >> blockbits;
+ buf->f_bfree = (res.fbytes + blockres) >> blockbits;
+@@ -323,9 +243,12 @@ static int nfs_statfs(struct dentry *den
+
+ }
+
++/*
++ * Map the security flavour number to a name
++ */
+ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
+ {
+- static struct {
++ static const struct {
+ rpc_authflavor_t flavour;
+ const char *str;
+ } sec_flavours[] = {
+@@ -356,10 +279,10 @@ static const char *nfs_pseudoflavour_to_
+ */
+ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
+ {
+- static struct proc_nfs_info {
++ static const struct proc_nfs_info {
+ int flag;
+- char *str;
+- char *nostr;
++ const char *str;
++ const char *nostr;
+ } nfs_info[] = {
+ { NFS_MOUNT_SOFT, ",soft", ",hard" },
+ { NFS_MOUNT_INTR, ",intr", "" },
+@@ -369,11 +292,12 @@ static void nfs_show_mount_options(struc
+ { NFS_MOUNT_NOACL, ",noacl", "" },
+ { 0, NULL, NULL }
+ };
+- struct proc_nfs_info *nfs_infop;
++ const struct proc_nfs_info *nfs_infop;
++ struct nfs_client *clp = nfss->nfs_client;
+ char buf[12];
+- char *proto;
++ const char *proto;
+
+- seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
++ seq_printf(m, ",vers=%d", clp->rpc_ops->version);
+ seq_printf(m, ",rsize=%d", nfss->rsize);
+ seq_printf(m, ",wsize=%d", nfss->wsize);
+ if (nfss->acregmin != 3*HZ || showdefaults)
+@@ -402,8 +326,8 @@ static void nfs_show_mount_options(struc
+ proto = buf;
+ }
+ seq_printf(m, ",proto=%s", proto);
+- seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
+- seq_printf(m, ",retrans=%u", nfss->retrans_count);
++ seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ);
++ seq_printf(m, ",retrans=%u", clp->retrans_count);
+ seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+ }
+
+@@ -417,7 +341,7 @@ static int nfs_show_options(struct seq_f
+ nfs_show_mount_options(m, nfss, 0);
+
+ seq_puts(m, ",addr=");
+- seq_escape(m, nfss->hostname, " \t\n\\");
++ seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\");
+
+ return 0;
+ }
+@@ -454,7 +378,7 @@ static int nfs_show_stats(struct seq_fil
+ seq_printf(m, ",namelen=%d", nfss->namelen);
+
+ #ifdef CONFIG_NFS_V4
+- if (nfss->rpc_ops->version == 4) {
++ if (nfss->nfs_client->cl_nfsversion == 4) {
+ seq_printf(m, "\n\tnfsv4:\t");
+ seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
+ seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
+@@ -501,782 +425,353 @@ static int nfs_show_stats(struct seq_fil
+
+ /*
+ * Begin unmount by attempting to remove all automounted mountpoints we added
+- * in response to traversals
++ * in response to xdev traversals and referrals
+ */
+ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+ {
+- struct nfs_server *server;
+- struct rpc_clnt *rpc;
+-
+ shrink_submounts(vfsmnt, &nfs_automount_list);
+- if (!(flags & MNT_FORCE))
+- return;
+- /* -EIO all pending I/O */
+- server = NFS_SB(vfsmnt->mnt_sb);
+- rpc = server->client;
+- if (!IS_ERR(rpc))
+- rpc_killall_tasks(rpc);
+- rpc = server->client_acl;
+- if (!IS_ERR(rpc))
+- rpc_killall_tasks(rpc);
+ }
+
+ /*
+- * Obtain the root inode of the file system.
++ * Validate the NFS2/NFS3 mount data
++ * - fills in the mount root filehandle
+ */
+-static struct inode *
+-nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
++static int nfs_validate_mount_data(struct nfs_mount_data *data,
++ struct nfs_fh *mntfh)
+ {
+- struct nfs_server *server = NFS_SB(sb);
+- int error;
+-
+- error = server->rpc_ops->getroot(server, rootfh, fsinfo);
+- if (error < 0) {
+- dprintk("nfs_get_root: getattr error = %d\n", -error);
+- return ERR_PTR(error);
++ if (data == NULL) {
++ dprintk("%s: missing data argument\n", __FUNCTION__);
++ return -EINVAL;
+ }
+
+- server->fsid = fsinfo->fattr->fsid;
+- return nfs_fhget(sb, rootfh, fsinfo->fattr);
+-}
+-
+-/*
+- * Do NFS version-independent mount processing, and sanity checking
+- */
+-static int
+-nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
+-{
+- struct nfs_server *server;
+- struct inode *root_inode;
+- struct nfs_fattr fattr;
+- struct nfs_fsinfo fsinfo = {
+- .fattr = &fattr,
+- };
+- struct nfs_pathconf pathinfo = {
+- .fattr = &fattr,
+- };
+- int no_root_error = 0;
+- unsigned long max_rpc_payload;
+-
+- /* We probably want something more informative here */
+- snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+-
+- server = NFS_SB(sb);
++ if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
++ dprintk("%s: bad mount version\n", __FUNCTION__);
++ return -EINVAL;
++ }
+
+- sb->s_magic = NFS_SUPER_MAGIC;
++ switch (data->version) {
++ case 1:
++ data->namlen = 0;
++ case 2:
++ data->bsize = 0;
++ case 3:
++ if (data->flags & NFS_MOUNT_VER3) {
++ dprintk("%s: mount structure version %d does not support NFSv3\n",
++ __FUNCTION__,
++ data->version);
++ return -EINVAL;
++ }
++ data->root.size = NFS2_FHSIZE;
++ memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
++ case 4:
++ if (data->flags & NFS_MOUNT_SECFLAVOUR) {
++ dprintk("%s: mount structure version %d does not support strong security\n",
++ __FUNCTION__,
++ data->version);
++ return -EINVAL;
++ }
++ case 5:
++ memset(data->context, 0, sizeof(data->context));
++ }
+
+- server->io_stats = nfs_alloc_iostats();
+- if (server->io_stats == NULL)
+- return -ENOMEM;
++ /* Set the pseudoflavor */
++ if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
++ data->pseudoflavor = RPC_AUTH_UNIX;
+
+- root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
+- /* Did getting the root inode fail? */
+- if (IS_ERR(root_inode)) {
+- no_root_error = PTR_ERR(root_inode);
+- goto out_no_root;
+- }
+- sb->s_root = d_alloc_root(root_inode);
+- if (!sb->s_root) {
+- no_root_error = -ENOMEM;
+- goto out_no_root;
++#ifndef CONFIG_NFS_V3
++ /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
++ if (data->flags & NFS_MOUNT_VER3) {
++ dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
++ return -EPROTONOSUPPORT;
+ }
+- sb->s_root->d_op = server->rpc_ops->dentry_ops;
+-
+- /* mount time stamp, in seconds */
+- server->mount_time = jiffies;
+-
+- /* Get some general file system info */
+- if (server->namelen == 0 &&
+- server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
+- server->namelen = pathinfo.max_namelen;
+- /* Work out a lot of parameters */
+- if (server->rsize == 0)
+- server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+- if (server->wsize == 0)
+- server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+-
+- if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
+- server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
+- if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
+- server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
+-
+- max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
+- if (server->rsize > max_rpc_payload)
+- server->rsize = max_rpc_payload;
+- if (server->rsize > NFS_MAX_FILE_IO_SIZE)
+- server->rsize = NFS_MAX_FILE_IO_SIZE;
+- server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+-
+- if (server->wsize > max_rpc_payload)
+- server->wsize = max_rpc_payload;
+- if (server->wsize > NFS_MAX_FILE_IO_SIZE)
+- server->wsize = NFS_MAX_FILE_IO_SIZE;
+- server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++#endif /* CONFIG_NFS_V3 */
+
+- if (sb->s_blocksize == 0)
+- sb->s_blocksize = nfs_block_bits(server->wsize,
+- &sb->s_blocksize_bits);
+- server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
+-
+- server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+- if (server->dtsize > PAGE_CACHE_SIZE)
+- server->dtsize = PAGE_CACHE_SIZE;
+- if (server->dtsize > server->rsize)
+- server->dtsize = server->rsize;
+-
+- if (server->flags & NFS_MOUNT_NOAC) {
+- server->acregmin = server->acregmax = 0;
+- server->acdirmin = server->acdirmax = 0;
+- sb->s_flags |= MS_SYNCHRONOUS;
++ /* We now require that the mount process passes the remote address */
++ if (data->addr.sin_addr.s_addr == INADDR_ANY) {
++ dprintk("%s: mount program didn't pass remote address!\n",
++ __FUNCTION__);
++ return -EINVAL;
+ }
+- server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
+
+- nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
++ /* Prepare the root filehandle */
++ if (data->flags & NFS_MOUNT_VER3)
++ mntfh->size = data->root.size;
++ else
++ mntfh->size = NFS2_FHSIZE;
++
++ if (mntfh->size > sizeof(mntfh->data)) {
++ dprintk("%s: invalid root filehandle\n", __FUNCTION__);
++ return -EINVAL;
++ }
+
+- server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
+- server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
++ memcpy(mntfh->data, data->root.data, mntfh->size);
++ if (mntfh->size < sizeof(mntfh->data))
++ memset(mntfh->data + mntfh->size, 0,
++ sizeof(mntfh->data) - mntfh->size);
+
+- /* We're airborne Set socket buffersize */
+- rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
+ return 0;
+- /* Yargs. It didn't work out. */
+-out_no_root:
+- dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
+- if (!IS_ERR(root_inode))
+- iput(root_inode);
+- return no_root_error;
+ }
+
+ /*
+- * Initialise the timeout values for a connection
++ * Initialise the common bits of the superblock
+ */
+-static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
++static inline void nfs_initialise_sb(struct super_block *sb)
+ {
+- to->to_initval = timeo * HZ / 10;
+- to->to_retries = retrans;
+- if (!to->to_retries)
+- to->to_retries = 2;
+-
+- switch (proto) {
+- case IPPROTO_TCP:
+- if (!to->to_initval)
+- to->to_initval = 60 * HZ;
+- if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
+- to->to_initval = NFS_MAX_TCP_TIMEOUT;
+- to->to_increment = to->to_initval;
+- to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
+- to->to_exponential = 0;
+- break;
+- case IPPROTO_UDP:
+- default:
+- if (!to->to_initval)
+- to->to_initval = 11 * HZ / 10;
+- if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
+- to->to_initval = NFS_MAX_UDP_TIMEOUT;
+- to->to_maxval = NFS_MAX_UDP_TIMEOUT;
+- to->to_exponential = 1;
+- break;
+- }
+-}
++ struct nfs_server *server = NFS_SB(sb);
+
+-/*
+- * Create an RPC client handle.
+- */
+-static struct rpc_clnt *
+-nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
+-{
+- struct rpc_timeout timeparms;
+- struct rpc_xprt *xprt = NULL;
+- struct rpc_clnt *clnt = NULL;
+- int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
+-
+- nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
+-
+- server->retrans_timeo = timeparms.to_initval;
+- server->retrans_count = timeparms.to_retries;
+-
+- /* create transport and client */
+- xprt = xprt_create_proto(proto, &server->addr, &timeparms);
+- if (IS_ERR(xprt)) {
+- dprintk("%s: cannot create RPC transport. Error = %ld\n",
+- __FUNCTION__, PTR_ERR(xprt));
+- return (struct rpc_clnt *)xprt;
+- }
+- clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+- server->rpc_ops->version, data->pseudoflavor);
+- if (IS_ERR(clnt)) {
+- dprintk("%s: cannot create RPC client. Error = %ld\n",
+- __FUNCTION__, PTR_ERR(xprt));
+- goto out_fail;
+- }
++ sb->s_magic = NFS_SUPER_MAGIC;
+
+- clnt->cl_intr = 1;
+- clnt->cl_softrtry = 1;
++ /* We probably want something more informative here */
++ snprintf(sb->s_id, sizeof(sb->s_id),
++ "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
++
++ if (sb->s_blocksize == 0)
++ sb->s_blocksize = nfs_block_bits(server->wsize,
++ &sb->s_blocksize_bits);
+
+- return clnt;
++ if (server->flags & NFS_MOUNT_NOAC)
++ sb->s_flags |= MS_SYNCHRONOUS;
+
+-out_fail:
+- return clnt;
++ nfs_super_set_maxbytes(sb, server->maxfilesize);
+ }
+
+ /*
+- * Clone a server record
++ * Finish setting up an NFS2/3 superblock
+ */
+-static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data)
++static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
+ {
+ struct nfs_server *server = NFS_SB(sb);
+- struct nfs_server *parent = NFS_SB(data->sb);
+- struct inode *root_inode;
+- struct nfs_fsinfo fsinfo;
+- void *err = ERR_PTR(-ENOMEM);
+-
+- sb->s_op = data->sb->s_op;
+- sb->s_blocksize = data->sb->s_blocksize;
+- sb->s_blocksize_bits = data->sb->s_blocksize_bits;
+- sb->s_maxbytes = data->sb->s_maxbytes;
+-
+- server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+- server->io_stats = nfs_alloc_iostats();
+- if (server->io_stats == NULL)
+- goto out;
+-
+- server->client = rpc_clone_client(parent->client);
+- if (IS_ERR((err = server->client)))
+- goto out;
+-
+- if (!IS_ERR(parent->client_sys)) {
+- server->client_sys = rpc_clone_client(parent->client_sys);
+- if (IS_ERR((err = server->client_sys)))
+- goto out;
+- }
+- if (!IS_ERR(parent->client_acl)) {
+- server->client_acl = rpc_clone_client(parent->client_acl);
+- if (IS_ERR((err = server->client_acl)))
+- goto out;
+- }
+- root_inode = nfs_fhget(sb, data->fh, data->fattr);
+- if (!root_inode)
+- goto out;
+- sb->s_root = d_alloc_root(root_inode);
+- if (!sb->s_root)
+- goto out_put_root;
+- fsinfo.fattr = data->fattr;
+- if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0)
+- nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
+- sb->s_root->d_op = server->rpc_ops->dentry_ops;
+- sb->s_flags |= MS_ACTIVE;
+- return server;
+-out_put_root:
+- iput(root_inode);
+-out:
+- return err;
+-}
+
+-/*
+- * Copy an existing superblock and attach revised data
+- */
+-static int nfs_clone_generic_sb(struct nfs_clone_mount *data,
+- struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *),
+- struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *),
+- struct vfsmount *mnt)
+-{
+- struct nfs_server *server;
+- struct nfs_server *parent = NFS_SB(data->sb);
+- struct super_block *sb = ERR_PTR(-EINVAL);
+- char *hostname;
+- int error = -ENOMEM;
+- int len;
+-
+- server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
+- if (server == NULL)
+- goto out_err;
+- memcpy(server, parent, sizeof(*server));
+- hostname = (data->hostname != NULL) ? data->hostname : parent->hostname;
+- len = strlen(hostname) + 1;
+- server->hostname = kmalloc(len, GFP_KERNEL);
+- if (server->hostname == NULL)
+- goto free_server;
+- memcpy(server->hostname, hostname, len);
+- error = rpciod_up();
+- if (error != 0)
+- goto free_hostname;
+-
+- sb = fill_sb(server, data);
+- if (IS_ERR(sb)) {
+- error = PTR_ERR(sb);
+- goto kill_rpciod;
+- }
+-
+- if (sb->s_root)
+- goto out_rpciod_down;
++ sb->s_blocksize_bits = 0;
++ sb->s_blocksize = 0;
++ if (data->bsize)
++ sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+
+- server = fill_server(sb, data);
+- if (IS_ERR(server)) {
+- error = PTR_ERR(server);
+- goto out_deactivate;
++ if (server->flags & NFS_MOUNT_VER3) {
++ /* The VFS shouldn't apply the umask to mode bits. We will do
++ * so ourselves when necessary.
++ */
++ sb->s_flags |= MS_POSIXACL;
++ sb->s_time_gran = 1;
+ }
+- return simple_set_mnt(mnt, sb);
+-out_deactivate:
+- up_write(&sb->s_umount);
+- deactivate_super(sb);
+- return error;
+-out_rpciod_down:
+- rpciod_down();
+- kfree(server->hostname);
+- kfree(server);
+- return simple_set_mnt(mnt, sb);
+-kill_rpciod:
+- rpciod_down();
+-free_hostname:
+- kfree(server->hostname);
+-free_server:
+- kfree(server);
+-out_err:
+- return error;
++
++ sb->s_op = &nfs_sops;
++ nfs_initialise_sb(sb);
+ }
+
+ /*
+- * Set up an NFS2/3 superblock
+- *
+- * The way this works is that the mount process passes a structure
+- * in the data argument which contains the server's IP address
+- * and the root file handle obtained from the server's mount
+- * daemon. We stash these away in the private superblock fields.
++ * Finish setting up a cloned NFS2/3 superblock
+ */
+-static int
+-nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
++static void nfs_clone_super(struct super_block *sb,
++ const struct super_block *old_sb)
+ {
+- struct nfs_server *server;
+- rpc_authflavor_t authflavor;
++ struct nfs_server *server = NFS_SB(sb);
+
+- server = NFS_SB(sb);
+- sb->s_blocksize_bits = 0;
+- sb->s_blocksize = 0;
+- if (data->bsize)
+- sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+- if (data->rsize)
+- server->rsize = nfs_block_size(data->rsize, NULL);
+- if (data->wsize)
+- server->wsize = nfs_block_size(data->wsize, NULL);
+- server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+-
+- server->acregmin = data->acregmin*HZ;
+- server->acregmax = data->acregmax*HZ;
+- server->acdirmin = data->acdirmin*HZ;
+- server->acdirmax = data->acdirmax*HZ;
+-
+- /* Start lockd here, before we might error out */
+- if (!(server->flags & NFS_MOUNT_NONLM))
+- lockd_up();
+-
+- server->namelen = data->namlen;
+- server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
+- if (!server->hostname)
+- return -ENOMEM;
+- strcpy(server->hostname, data->hostname);
+-
+- /* Check NFS protocol revision and initialize RPC op vector
+- * and file handle pool. */
+-#ifdef CONFIG_NFS_V3
+- if (server->flags & NFS_MOUNT_VER3) {
+- server->rpc_ops = &nfs_v3_clientops;
+- server->caps |= NFS_CAP_READDIRPLUS;
+- } else {
+- server->rpc_ops = &nfs_v2_clientops;
+- }
+-#else
+- server->rpc_ops = &nfs_v2_clientops;
+-#endif
++ sb->s_blocksize_bits = old_sb->s_blocksize_bits;
++ sb->s_blocksize = old_sb->s_blocksize;
++ sb->s_maxbytes = old_sb->s_maxbytes;
+
+- /* Fill in pseudoflavor for mount version < 5 */
+- if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
+- data->pseudoflavor = RPC_AUTH_UNIX;
+- authflavor = data->pseudoflavor; /* save for sb_init() */
+- /* XXX maybe we want to add a server->pseudoflavor field */
+-
+- /* Create RPC client handles */
+- server->client = nfs_create_client(server, data);
+- if (IS_ERR(server->client))
+- return PTR_ERR(server->client);
+- /* RFC 2623, sec 2.3.2 */
+- if (authflavor != RPC_AUTH_UNIX) {
+- struct rpc_auth *auth;
+-
+- server->client_sys = rpc_clone_client(server->client);
+- if (IS_ERR(server->client_sys))
+- return PTR_ERR(server->client_sys);
+- auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys);
+- if (IS_ERR(auth))
+- return PTR_ERR(auth);
+- } else {
+- atomic_inc(&server->client->cl_count);
+- server->client_sys = server->client;
+- }
+ if (server->flags & NFS_MOUNT_VER3) {
+-#ifdef CONFIG_NFS_V3_ACL
+- if (!(server->flags & NFS_MOUNT_NOACL)) {
+- server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
+- /* No errors! Assume that Sun nfsacls are supported */
+- if (!IS_ERR(server->client_acl))
+- server->caps |= NFS_CAP_ACLS;
+- }
+-#else
+- server->flags &= ~NFS_MOUNT_NOACL;
+-#endif /* CONFIG_NFS_V3_ACL */
+- /*
+- * The VFS shouldn't apply the umask to mode bits. We will
+- * do so ourselves when necessary.
++ /* The VFS shouldn't apply the umask to mode bits. We will do
++ * so ourselves when necessary.
+ */
+ sb->s_flags |= MS_POSIXACL;
+- if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
+- server->namelen = NFS3_MAXNAMLEN;
+ sb->s_time_gran = 1;
+- } else {
+- if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
+- server->namelen = NFS2_MAXNAMLEN;
+ }
+
+- sb->s_op = &nfs_sops;
+- return nfs_sb_init(sb, authflavor);
++ sb->s_op = old_sb->s_op;
++ nfs_initialise_sb(sb);
+ }
+
+-static int nfs_set_super(struct super_block *s, void *data)
++static int nfs_set_super(struct super_block *s, void *_server)
+ {
+- s->s_fs_info = data;
+- return set_anon_super(s, data);
++ struct nfs_server *server = _server;
++ int ret;
++
++ s->s_fs_info = server;
++ ret = set_anon_super(s, server);
++ if (ret == 0)
++ server->s_dev = s->s_dev;
++ return ret;
+ }
+
+ static int nfs_compare_super(struct super_block *sb, void *data)
+ {
+- struct nfs_server *server = data;
+- struct nfs_server *old = NFS_SB(sb);
++ struct nfs_server *server = data, *old = NFS_SB(sb);
+
+- if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
++ if (old->nfs_client != server->nfs_client)
+ return 0;
+- if (old->addr.sin_port != server->addr.sin_port)
++ if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
+ return 0;
+- return !nfs_compare_fh(&old->fh, &server->fh);
++ return 1;
+ }
+
+ static int nfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+ {
+- int error;
+ struct nfs_server *server = NULL;
+ struct super_block *s;
+- struct nfs_fh *root;
++ struct nfs_fh mntfh;
+ struct nfs_mount_data *data = raw_data;
++ struct dentry *mntroot;
++ int error;
+
+- error = -EINVAL;
+- if (data == NULL) {
+- dprintk("%s: missing data argument\n", __FUNCTION__);
+- goto out_err_noserver;
+- }
+- if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
+- dprintk("%s: bad mount version\n", __FUNCTION__);
+- goto out_err_noserver;
+- }
+- switch (data->version) {
+- case 1:
+- data->namlen = 0;
+- case 2:
+- data->bsize = 0;
+- case 3:
+- if (data->flags & NFS_MOUNT_VER3) {
+- dprintk("%s: mount structure version %d does not support NFSv3\n",
+- __FUNCTION__,
+- data->version);
+- goto out_err_noserver;
+- }
+- data->root.size = NFS2_FHSIZE;
+- memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+- case 4:
+- if (data->flags & NFS_MOUNT_SECFLAVOUR) {
+- dprintk("%s: mount structure version %d does not support strong security\n",
+- __FUNCTION__,
+- data->version);
+- goto out_err_noserver;
+- }
+- case 5:
+- memset(data->context, 0, sizeof(data->context));
+- }
+-#ifndef CONFIG_NFS_V3
+- /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
+- error = -EPROTONOSUPPORT;
+- if (data->flags & NFS_MOUNT_VER3) {
+- dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
+- goto out_err_noserver;
+- }
+-#endif /* CONFIG_NFS_V3 */
++ /* Validate the mount data */
++ error = nfs_validate_mount_data(data, &mntfh);
++ if (error < 0)
++ return error;
+
+- error = -ENOMEM;
+- server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
+- if (!server)
++ /* Get a volume representation */
++ server = nfs_create_server(data, &mntfh);
++ if (IS_ERR(server)) {
++ error = PTR_ERR(server);
+ goto out_err_noserver;
+- /* Zero out the NFS state stuff */
+- init_nfsv4_state(server);
+- server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+-
+- root = &server->fh;
+- if (data->flags & NFS_MOUNT_VER3)
+- root->size = data->root.size;
+- else
+- root->size = NFS2_FHSIZE;
+- error = -EINVAL;
+- if (root->size > sizeof(root->data)) {
+- dprintk("%s: invalid root filehandle\n", __FUNCTION__);
+- goto out_err;
+- }
+- memcpy(root->data, data->root.data, root->size);
+-
+- /* We now require that the mount process passes the remote address */
+- memcpy(&server->addr, &data->addr, sizeof(server->addr));
+- if (server->addr.sin_addr.s_addr == INADDR_ANY) {
+- dprintk("%s: mount program didn't pass remote address!\n",
+- __FUNCTION__);
+- goto out_err;
+- }
+-
+- /* Fire up rpciod if not yet running */
+- error = rpciod_up();
+- if (error < 0) {
+- dprintk("%s: couldn't start rpciod! Error = %d\n",
+- __FUNCTION__, error);
+- goto out_err;
+ }
+
++ /* Get a superblock - note that we may end up sharing one that already exists */
+ s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
+ if (IS_ERR(s)) {
+ error = PTR_ERR(s);
+- goto out_err_rpciod;
++ goto out_err_nosb;
+ }
+
+- if (s->s_root)
+- goto out_rpciod_down;
++ if (s->s_fs_info != server) {
++ nfs_free_server(server);
++ server = NULL;
++ }
+
+- s->s_flags = flags;
++ if (!s->s_root) {
++ /* initial superblock/root creation */
++ s->s_flags = flags;
++ nfs_fill_super(s, data);
++ }
+
+- error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+- if (error) {
+- up_write(&s->s_umount);
+- deactivate_super(s);
+- return error;
++ mntroot = nfs_get_root(s, &mntfh);
++ if (IS_ERR(mntroot)) {
++ error = PTR_ERR(mntroot);
++ goto error_splat_super;
+ }
+- s->s_flags |= MS_ACTIVE;
+- return simple_set_mnt(mnt, s);
+
+-out_rpciod_down:
+- rpciod_down();
+- kfree(server);
+- return simple_set_mnt(mnt, s);
++ s->s_flags |= MS_ACTIVE;
++ mnt->mnt_sb = s;
++ mnt->mnt_root = mntroot;
++ return 0;
+
+-out_err_rpciod:
+- rpciod_down();
+-out_err:
+- kfree(server);
++out_err_nosb:
++ nfs_free_server(server);
+ out_err_noserver:
+ return error;
++
++error_splat_super:
++ up_write(&s->s_umount);
++ deactivate_super(s);
++ return error;
+ }
+
++/*
++ * Destroy an NFS2/3 superblock
++ */
+ static void nfs_kill_super(struct super_block *s)
+ {
+ struct nfs_server *server = NFS_SB(s);
+
+ kill_anon_super(s);
+-
+- if (!IS_ERR(server->client))
+- rpc_shutdown_client(server->client);
+- if (!IS_ERR(server->client_sys))
+- rpc_shutdown_client(server->client_sys);
+- if (!IS_ERR(server->client_acl))
+- rpc_shutdown_client(server->client_acl);
+-
+- if (!(server->flags & NFS_MOUNT_NONLM))
+- lockd_down(); /* release rpc.lockd */
+-
+- rpciod_down(); /* release rpciod */
+-
+- nfs_free_iostats(server->io_stats);
+- kfree(server->hostname);
+- kfree(server);
+- nfs_release_automount_timer();
+-}
+-
+-static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+-{
+- struct super_block *sb;
+-
+- server->fsid = data->fattr->fsid;
+- nfs_copy_fh(&server->fh, data->fh);
+- sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+- if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM))
+- lockd_up();
+- return sb;
++ nfs_free_server(server);
+ }
+
+-static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
+- int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
++/*
++ * Clone an NFS2/3 server record on xdev traversal (FSID-change)
++ */
++static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *raw_data,
++ struct vfsmount *mnt)
+ {
+ struct nfs_clone_mount *data = raw_data;
+- return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt);
+-}
++ struct super_block *s;
++ struct nfs_server *server;
++ struct dentry *mntroot;
++ int error;
+
+-#ifdef CONFIG_NFS_V4
+-static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
+- struct rpc_timeout *timeparms, int proto, rpc_authflavor_t flavor)
+-{
+- struct nfs4_client *clp;
+- struct rpc_xprt *xprt = NULL;
+- struct rpc_clnt *clnt = NULL;
+- int err = -EIO;
+-
+- clp = nfs4_get_client(&server->addr.sin_addr);
+- if (!clp) {
+- dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
+- return ERR_PTR(err);
+- }
++ dprintk("--> nfs_xdev_get_sb()\n");
+
+- /* Now create transport and client */
+- down_write(&clp->cl_sem);
+- if (IS_ERR(clp->cl_rpcclient)) {
+- xprt = xprt_create_proto(proto, &server->addr, timeparms);
+- if (IS_ERR(xprt)) {
+- up_write(&clp->cl_sem);
+- err = PTR_ERR(xprt);
+- dprintk("%s: cannot create RPC transport. Error = %d\n",
+- __FUNCTION__, err);
+- goto out_fail;
+- }
+- /* Bind to a reserved port! */
+- xprt->resvport = 1;
+- clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+- server->rpc_ops->version, flavor);
+- if (IS_ERR(clnt)) {
+- up_write(&clp->cl_sem);
+- err = PTR_ERR(clnt);
+- dprintk("%s: cannot create RPC client. Error = %d\n",
+- __FUNCTION__, err);
+- goto out_fail;
+- }
+- clnt->cl_intr = 1;
+- clnt->cl_softrtry = 1;
+- clp->cl_rpcclient = clnt;
+- memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
+- nfs_idmap_new(clp);
+- }
+- list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
+- clnt = rpc_clone_client(clp->cl_rpcclient);
+- if (!IS_ERR(clnt))
+- server->nfs4_state = clp;
+- up_write(&clp->cl_sem);
+- clp = NULL;
+-
+- if (IS_ERR(clnt)) {
+- dprintk("%s: cannot create RPC client. Error = %d\n",
+- __FUNCTION__, err);
+- return clnt;
++ /* create a new volume representation */
++ server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
++ if (IS_ERR(server)) {
++ error = PTR_ERR(server);
++ goto out_err_noserver;
+ }
+
+- if (server->nfs4_state->cl_idmap == NULL) {
+- dprintk("%s: failed to create idmapper.\n", __FUNCTION__);
+- return ERR_PTR(-ENOMEM);
++ /* Get a superblock - note that we may end up sharing one that already exists */
++ s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
++ if (IS_ERR(s)) {
++ error = PTR_ERR(s);
++ goto out_err_nosb;
+ }
+
+- if (clnt->cl_auth->au_flavor != flavor) {
+- struct rpc_auth *auth;
+-
+- auth = rpcauth_create(flavor, clnt);
+- if (IS_ERR(auth)) {
+- dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
+- return (struct rpc_clnt *)auth;
+- }
++ if (s->s_fs_info != server) {
++ nfs_free_server(server);
++ server = NULL;
+ }
+- return clnt;
+-
+- out_fail:
+- if (clp)
+- nfs4_put_client(clp);
+- return ERR_PTR(err);
+-}
+-
+-/*
+- * Set up an NFS4 superblock
+- */
+-static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
+-{
+- struct nfs_server *server;
+- struct rpc_timeout timeparms;
+- rpc_authflavor_t authflavour;
+- int err = -EIO;
+
+- sb->s_blocksize_bits = 0;
+- sb->s_blocksize = 0;
+- server = NFS_SB(sb);
+- if (data->rsize != 0)
+- server->rsize = nfs_block_size(data->rsize, NULL);
+- if (data->wsize != 0)
+- server->wsize = nfs_block_size(data->wsize, NULL);
+- server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+- server->caps = NFS_CAP_ATOMIC_OPEN;
++ if (!s->s_root) {
++ /* initial superblock/root creation */
++ s->s_flags = flags;
++ nfs_clone_super(s, data->sb);
++ }
+
+- server->acregmin = data->acregmin*HZ;
+- server->acregmax = data->acregmax*HZ;
+- server->acdirmin = data->acdirmin*HZ;
+- server->acdirmax = data->acdirmax*HZ;
++ mntroot = nfs_get_root(s, data->fh);
++ if (IS_ERR(mntroot)) {
++ error = PTR_ERR(mntroot);
++ goto error_splat_super;
++ }
+
+- server->rpc_ops = &nfs_v4_clientops;
++ s->s_flags |= MS_ACTIVE;
++ mnt->mnt_sb = s;
++ mnt->mnt_root = mntroot;
+
+- nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
++ dprintk("<-- nfs_xdev_get_sb() = 0\n");
++ return 0;
+
+- server->retrans_timeo = timeparms.to_initval;
+- server->retrans_count = timeparms.to_retries;
++out_err_nosb:
++ nfs_free_server(server);
++out_err_noserver:
++ dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error);
++ return error;
+
+- /* Now create transport and client */
+- authflavour = RPC_AUTH_UNIX;
+- if (data->auth_flavourlen != 0) {
+- if (data->auth_flavourlen != 1) {
+- dprintk("%s: Invalid number of RPC auth flavours %d.\n",
+- __FUNCTION__, data->auth_flavourlen);
+- err = -EINVAL;
+- goto out_fail;
+- }
+- if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
+- err = -EFAULT;
+- goto out_fail;
+- }
+- }
++error_splat_super:
++ up_write(&s->s_umount);
++ deactivate_super(s);
++ dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error);
++ return error;
++}
+
+- server->client = nfs4_create_client(server, &timeparms, data->proto, authflavour);
+- if (IS_ERR(server->client)) {
+- err = PTR_ERR(server->client);
+- dprintk("%s: cannot create RPC client. Error = %d\n",
+- __FUNCTION__, err);
+- goto out_fail;
+- }
++#ifdef CONFIG_NFS_V4
+
++/*
++ * Finish setting up a cloned NFS4 superblock
++ */
++static void nfs4_clone_super(struct super_block *sb,
++ const struct super_block *old_sb)
++{
++ sb->s_blocksize_bits = old_sb->s_blocksize_bits;
++ sb->s_blocksize = old_sb->s_blocksize;
++ sb->s_maxbytes = old_sb->s_maxbytes;
+ sb->s_time_gran = 1;
+-
+- sb->s_op = &nfs4_sops;
+- err = nfs_sb_init(sb, authflavour);
+-
+- out_fail:
+- return err;
++ sb->s_op = old_sb->s_op;
++ nfs_initialise_sb(sb);
+ }
+
+-static int nfs4_compare_super(struct super_block *sb, void *data)
++/*
++ * Set up an NFS4 superblock
++ */
++static void nfs4_fill_super(struct super_block *sb)
+ {
+- struct nfs_server *server = data;
+- struct nfs_server *old = NFS_SB(sb);
+-
+- if (strcmp(server->hostname, old->hostname) != 0)
+- return 0;
+- if (strcmp(server->mnt_path, old->mnt_path) != 0)
+- return 0;
+- return 1;
++ sb->s_time_gran = 1;
++ sb->s_op = &nfs4_sops;
++ nfs_initialise_sb(sb);
+ }
+
+-static void *
+-nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
++static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
+ {
+ void *p = NULL;
+
+@@ -1297,14 +792,22 @@ nfs_copy_user_string(char *dst, struct n
+ return dst;
+ }
+
++/*
++ * Get the superblock for an NFS4 mountpoint
++ */
+ static int nfs4_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+ {
+- int error;
+- struct nfs_server *server;
+- struct super_block *s;
+ struct nfs4_mount_data *data = raw_data;
++ struct super_block *s;
++ struct nfs_server *server;
++ struct sockaddr_in addr;
++ rpc_authflavor_t authflavour;
++ struct nfs_fh mntfh;
++ struct dentry *mntroot;
++ char *mntpath = NULL, *hostname = NULL, ip_addr[16];
+ void *p;
++ int error;
+
+ if (data == NULL) {
+ dprintk("%s: missing data argument\n", __FUNCTION__);
+@@ -1315,84 +818,112 @@ static int nfs4_get_sb(struct file_syste
+ return -EINVAL;
+ }
+
+- server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
+- if (!server)
+- return -ENOMEM;
+- /* Zero out the NFS state stuff */
+- init_nfsv4_state(server);
+- server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
++ /* We now require that the mount process passes the remote address */
++ if (data->host_addrlen != sizeof(addr))
++ return -EINVAL;
++
++ if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
++ return -EFAULT;
++
++ if (addr.sin_family != AF_INET ||
++ addr.sin_addr.s_addr == INADDR_ANY
++ ) {
++ dprintk("%s: mount program didn't pass remote IP address!\n",
++ __FUNCTION__);
++ return -EINVAL;
++ }
++ /* RFC3530: The default port for NFS is 2049 */
++ if (addr.sin_port == 0)
++ addr.sin_port = htons(NFS_PORT);
++
++ /* Grab the authentication type */
++ authflavour = RPC_AUTH_UNIX;
++ if (data->auth_flavourlen != 0) {
++ if (data->auth_flavourlen != 1) {
++ dprintk("%s: Invalid number of RPC auth flavours %d.\n",
++ __FUNCTION__, data->auth_flavourlen);
++ error = -EINVAL;
++ goto out_err_noserver;
++ }
++
++ if (copy_from_user(&authflavour, data->auth_flavours,
++ sizeof(authflavour))) {
++ error = -EFAULT;
++ goto out_err_noserver;
++ }
++ }
+
+ p = nfs_copy_user_string(NULL, &data->hostname, 256);
+ if (IS_ERR(p))
+ goto out_err;
+- server->hostname = p;
++ hostname = p;
+
+ p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
+ if (IS_ERR(p))
+ goto out_err;
+- server->mnt_path = p;
++ mntpath = p;
++
++ dprintk("MNTPATH: %s\n", mntpath);
+
+- p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
+- sizeof(server->ip_addr) - 1);
++ p = nfs_copy_user_string(ip_addr, &data->client_addr,
++ sizeof(ip_addr) - 1);
+ if (IS_ERR(p))
+ goto out_err;
+
+- /* We now require that the mount process passes the remote address */
+- if (data->host_addrlen != sizeof(server->addr)) {
+- error = -EINVAL;
+- goto out_free;
+- }
+- if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
+- error = -EFAULT;
+- goto out_free;
+- }
+- if (server->addr.sin_family != AF_INET ||
+- server->addr.sin_addr.s_addr == INADDR_ANY) {
+- dprintk("%s: mount program didn't pass remote IP address!\n",
+- __FUNCTION__);
+- error = -EINVAL;
+- goto out_free;
+- }
+-
+- /* Fire up rpciod if not yet running */
+- error = rpciod_up();
+- if (error < 0) {
+- dprintk("%s: couldn't start rpciod! Error = %d\n",
+- __FUNCTION__, error);
+- goto out_free;
++ /* Get a volume representation */
++ server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
++ authflavour, &mntfh);
++ if (IS_ERR(server)) {
++ error = PTR_ERR(server);
++ goto out_err_noserver;
+ }
+
+- s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
+-
++ /* Get a superblock - note that we may end up sharing one that already exists */
++ s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
+ if (IS_ERR(s)) {
+ error = PTR_ERR(s);
+ goto out_free;
+ }
+
+- if (s->s_root) {
+- kfree(server->mnt_path);
+- kfree(server->hostname);
+- kfree(server);
+- return simple_set_mnt(mnt, s);
++ if (s->s_fs_info != server) {
++ nfs_free_server(server);
++ server = NULL;
+ }
+
+- s->s_flags = flags;
++ if (!s->s_root) {
++ /* initial superblock/root creation */
++ s->s_flags = flags;
++ nfs4_fill_super(s);
++ }
+
+- error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+- if (error) {
+- up_write(&s->s_umount);
+- deactivate_super(s);
+- return error;
++ mntroot = nfs4_get_root(s, &mntfh);
++ if (IS_ERR(mntroot)) {
++ error = PTR_ERR(mntroot);
++ goto error_splat_super;
+ }
++
+ s->s_flags |= MS_ACTIVE;
+- return simple_set_mnt(mnt, s);
++ mnt->mnt_sb = s;
++ mnt->mnt_root = mntroot;
++ kfree(mntpath);
++ kfree(hostname);
++ return 0;
++
+ out_err:
+ error = PTR_ERR(p);
++ goto out_err_noserver;
++
+ out_free:
+- kfree(server->mnt_path);
+- kfree(server->hostname);
+- kfree(server);
++ nfs_free_server(server);
++out_err_noserver:
++ kfree(mntpath);
++ kfree(hostname);
+ return error;
++
++error_splat_super:
++ up_write(&s->s_umount);
++ deactivate_super(s);
++ goto out_err_noserver;
+ }
+
+ static void nfs4_kill_super(struct super_block *sb)
+@@ -1403,135 +934,140 @@ static void nfs4_kill_super(struct super
+ kill_anon_super(sb);
+
+ nfs4_renewd_prepare_shutdown(server);
++ nfs_free_server(server);
++}
++
++/*
++ * Clone an NFS4 server record on xdev traversal (FSID-change)
++ */
++static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *raw_data,
++ struct vfsmount *mnt)
++{
++ struct nfs_clone_mount *data = raw_data;
++ struct super_block *s;
++ struct nfs_server *server;
++ struct dentry *mntroot;
++ int error;
++
++ dprintk("--> nfs4_xdev_get_sb()\n");
++
++ /* create a new volume representation */
++ server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
++ if (IS_ERR(server)) {
++ error = PTR_ERR(server);
++ goto out_err_noserver;
++ }
++
++ /* Get a superblock - note that we may end up sharing one that already exists */
++ s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
++ if (IS_ERR(s)) {
++ error = PTR_ERR(s);
++ goto out_err_nosb;
++ }
+
+- if (server->client != NULL && !IS_ERR(server->client))
+- rpc_shutdown_client(server->client);
++ if (s->s_fs_info != server) {
++ nfs_free_server(server);
++ server = NULL;
++ }
+
+- destroy_nfsv4_state(server);
++ if (!s->s_root) {
++ /* initial superblock/root creation */
++ s->s_flags = flags;
++ nfs4_clone_super(s, data->sb);
++ }
++
++ mntroot = nfs4_get_root(s, data->fh);
++ if (IS_ERR(mntroot)) {
++ error = PTR_ERR(mntroot);
++ goto error_splat_super;
++ }
+
+- rpciod_down();
++ s->s_flags |= MS_ACTIVE;
++ mnt->mnt_sb = s;
++ mnt->mnt_root = mntroot;
++
++ dprintk("<-- nfs4_xdev_get_sb() = 0\n");
++ return 0;
++
++out_err_nosb:
++ nfs_free_server(server);
++out_err_noserver:
++ dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error);
++ return error;
+
+- nfs_free_iostats(server->io_stats);
+- kfree(server->hostname);
+- kfree(server);
+- nfs_release_automount_timer();
++error_splat_super:
++ up_write(&s->s_umount);
++ deactivate_super(s);
++ dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error);
++ return error;
+ }
+
+ /*
+- * Constructs the SERVER-side path
++ * Create an NFS4 server record on referral traversal
+ */
+-static inline char *nfs4_dup_path(const struct dentry *dentry)
++static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *raw_data,
++ struct vfsmount *mnt)
+ {
+- char *page = (char *) __get_free_page(GFP_USER);
+- char *path;
++ struct nfs_clone_mount *data = raw_data;
++ struct super_block *s;
++ struct nfs_server *server;
++ struct dentry *mntroot;
++ struct nfs_fh mntfh;
++ int error;
+
+- path = nfs4_path(dentry, page, PAGE_SIZE);
+- if (!IS_ERR(path)) {
+- int len = PAGE_SIZE + page - path;
+- char *tmp = path;
++ dprintk("--> nfs4_referral_get_sb()\n");
+
+- path = kmalloc(len, GFP_KERNEL);
+- if (path)
+- memcpy(path, tmp, len);
+- else
+- path = ERR_PTR(-ENOMEM);
++ /* create a new volume representation */
++ server = nfs4_create_referral_server(data, &mntfh);
++ if (IS_ERR(server)) {
++ error = PTR_ERR(server);
++ goto out_err_noserver;
+ }
+- free_page((unsigned long)page);
+- return path;
+-}
+
+-static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+-{
+- const struct dentry *dentry = data->dentry;
+- struct nfs4_client *clp = server->nfs4_state;
+- struct super_block *sb;
+-
+- server->fsid = data->fattr->fsid;
+- nfs_copy_fh(&server->fh, data->fh);
+- server->mnt_path = nfs4_dup_path(dentry);
+- if (IS_ERR(server->mnt_path)) {
+- sb = (struct super_block *)server->mnt_path;
+- goto err;
++ /* Get a superblock - note that we may end up sharing one that already exists */
++ s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
++ if (IS_ERR(s)) {
++ error = PTR_ERR(s);
++ goto out_err_nosb;
+ }
+- sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
+- if (IS_ERR(sb) || sb->s_root)
+- goto free_path;
+- nfs4_server_capabilities(server, &server->fh);
+-
+- down_write(&clp->cl_sem);
+- atomic_inc(&clp->cl_count);
+- list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
+- up_write(&clp->cl_sem);
+- return sb;
+-free_path:
+- kfree(server->mnt_path);
+-err:
+- server->mnt_path = NULL;
+- return sb;
+-}
+
+-static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
+- int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+-{
+- struct nfs_clone_mount *data = raw_data;
+- return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
+-}
++ if (s->s_fs_info != server) {
++ nfs_free_server(server);
++ server = NULL;
++ }
+
+-static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+-{
+- struct super_block *sb = ERR_PTR(-ENOMEM);
+- int len;
+-
+- len = strlen(data->mnt_path) + 1;
+- server->mnt_path = kmalloc(len, GFP_KERNEL);
+- if (server->mnt_path == NULL)
+- goto err;
+- memcpy(server->mnt_path, data->mnt_path, len);
+- memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in));
+-
+- sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
+- if (IS_ERR(sb) || sb->s_root)
+- goto free_path;
+- return sb;
+-free_path:
+- kfree(server->mnt_path);
+-err:
+- server->mnt_path = NULL;
+- return sb;
+-}
++ if (!s->s_root) {
++ /* initial superblock/root creation */
++ s->s_flags = flags;
++ nfs4_fill_super(s);
++ }
+
+-static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data)
+-{
+- struct nfs_server *server = NFS_SB(sb);
+- struct rpc_timeout timeparms;
+- int proto, timeo, retrans;
+- void *err;
+-
+- proto = IPPROTO_TCP;
+- /* Since we are following a referral and there may be alternatives,
+- set the timeouts and retries to low values */
+- timeo = 2;
+- retrans = 1;
+- nfs_init_timeout_values(&timeparms, proto, timeo, retrans);
+-
+- server->client = nfs4_create_client(server, &timeparms, proto, data->authflavor);
+- if (IS_ERR((err = server->client)))
+- goto out_err;
++ mntroot = nfs4_get_root(s, data->fh);
++ if (IS_ERR(mntroot)) {
++ error = PTR_ERR(mntroot);
++ goto error_splat_super;
++ }
+
+- sb->s_time_gran = 1;
+- sb->s_op = &nfs4_sops;
+- err = ERR_PTR(nfs_sb_init(sb, data->authflavor));
+- if (!IS_ERR(err))
+- return server;
+-out_err:
+- return (struct nfs_server *)err;
+-}
++ s->s_flags |= MS_ACTIVE;
++ mnt->mnt_sb = s;
++ mnt->mnt_root = mntroot;
+
+-static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
+- int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+-{
+- struct nfs_clone_mount *data = raw_data;
+- return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt);
++ dprintk("<-- nfs4_referral_get_sb() = 0\n");
++ return 0;
++
++out_err_nosb:
++ nfs_free_server(server);
++out_err_noserver:
++ dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error);
++ return error;
++
++error_splat_super:
++ up_write(&s->s_umount);
++ deactivate_super(s);
++ dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
++ return error;
+ }
+
+-#endif
++#endif /* CONFIG_NFS_V4 */
+diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c
+index 2fe3403..3ea50ac 100644
+--- a/fs/nfs/sysctl.c
++++ b/fs/nfs/sysctl.c
+@@ -18,11 +18,6 @@
+ static const int nfs_set_port_min = 0;
+ static const int nfs_set_port_max = 65535;
+ static struct ctl_table_header *nfs_callback_sysctl_table;
+-/*
+- * Something that isn't CTL_ANY, CTL_NONE or a value that may clash.
+- * Use the same values as fs/lockd/svc.c
+- */
+-#define CTL_UNNUMBERED -2
+
+ static ctl_table nfs_cb_sysctls[] = {
+ #ifdef CONFIG_NFS_V4
+diff --git a/fs/nfs/write.c b/fs/nfs/write.c
+index 7084ac9..883dd4a 100644
+--- a/fs/nfs/write.c
++++ b/fs/nfs/write.c
+@@ -51,13 +51,14 @@
+ #include <linux/mm.h>
+ #include <linux/pagemap.h>
+ #include <linux/file.h>
+-#include <linux/mpage.h>
+ #include <linux/writeback.h>
+
+ #include <linux/sunrpc/clnt.h>
+ #include <linux/nfs_fs.h>
+ #include <linux/nfs_mount.h>
+ #include <linux/nfs_page.h>
++#include <linux/backing-dev.h>
++
+ #include <asm/uaccess.h>
+ #include <linux/smp_lock.h>
+
+@@ -396,6 +397,7 @@ int nfs_writepages(struct address_space
+ out:
+ clear_bit(BDI_write_congested, &bdi->state);
+ wake_up_all(&nfs_write_congestion);
++ congestion_end(WRITE);
+ return err;
+ }
+
+@@ -588,10 +590,10 @@ static void nfs_cancel_commit_list(struc
+
+ while(!list_empty(head)) {
+ req = nfs_list_entry(head->next);
++ dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+ nfs_list_remove_request(req);
+ nfs_inode_remove_request(req);
+- dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+- nfs_clear_page_writeback(req);
++ nfs_unlock_request(req);
+ }
+ }
+
+@@ -1252,7 +1254,13 @@ int nfs_writeback_done(struct rpc_task *
+ dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
+ task->tk_pid, task->tk_status);
+
+- /* Call the NFS version-specific code */
++ /*
++ * ->write_done will attempt to use post-op attributes to detect
++ * conflicting writes by other clients. A strict interpretation
++ * of close-to-open would allow us to continue caching even if
++ * another writer had changed the file, but some applications
++ * depend on tighter cache coherency when writing.
++ */
+ status = NFS_PROTO(data->inode)->write_done(task, data);
+ if (status != 0)
+ return status;
+@@ -1273,7 +1281,7 @@ int nfs_writeback_done(struct rpc_task *
+ if (time_before(complain, jiffies)) {
+ dprintk("NFS: faulty NFS server %s:"
+ " (committed = %d) != (stable = %d)\n",
+- NFS_SERVER(data->inode)->hostname,
++ NFS_SERVER(data->inode)->nfs_client->cl_hostname,
+ resp->verf->committed, argp->stable);
+ complain = jiffies + 300 * HZ;
+ }
+@@ -1558,7 +1566,6 @@ void nfs_destroy_writepagecache(void)
+ {
+ mempool_destroy(nfs_commit_mempool);
+ mempool_destroy(nfs_wdata_mempool);
+- if (kmem_cache_destroy(nfs_wdata_cachep))
+- printk(KERN_INFO "nfs_write_data: not all structures were freed\n");
++ kmem_cache_destroy(nfs_wdata_cachep);
+ }
+
+diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
+index 0c2be8c..c11f537 100644
+--- a/fs/nfs_common/nfsacl.c
++++ b/fs/nfs_common/nfsacl.c
+@@ -46,7 +46,7 @@ xdr_nfsace_encode(struct xdr_array2_desc
+ {
+ struct nfsacl_encode_desc *nfsacl_desc =
+ (struct nfsacl_encode_desc *) desc;
+- u32 *p = (u32 *) elem;
++ __be32 *p = elem;
+
+ struct posix_acl_entry *entry =
+ &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
+@@ -127,7 +127,7 @@ xdr_nfsace_decode(struct xdr_array2_desc
+ {
+ struct nfsacl_decode_desc *nfsacl_desc =
+ (struct nfsacl_decode_desc *) desc;
+- u32 *p = (u32 *) elem;
++ __be32 *p = elem;
+ struct posix_acl_entry *entry;
+
+ if (!nfsacl_desc->acl) {
+diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
+index 01bc68c..f37df46 100644
+--- a/fs/nfsd/export.c
++++ b/fs/nfsd/export.c
+@@ -319,12 +319,25 @@ svc_expkey_update(struct svc_expkey *new
+
+ static struct cache_head *export_table[EXPORT_HASHMAX];
+
++static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
++{
++ int i;
++
++ for (i = 0; i < fsloc->locations_count; i++) {
++ kfree(fsloc->locations[i].path);
++ kfree(fsloc->locations[i].hosts);
++ }
++ kfree(fsloc->locations);
++}
++
+ static void svc_export_put(struct kref *ref)
+ {
+ struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
+ dput(exp->ex_dentry);
+ mntput(exp->ex_mnt);
+ auth_domain_put(exp->ex_client);
++ kfree(exp->ex_path);
++ nfsd4_fslocs_free(&exp->ex_fslocs);
+ kfree(exp);
+ }
+
+@@ -370,7 +383,7 @@ static int check_export(struct inode *in
+ */
+ if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
+ !(flags & NFSEXP_FSID)) {
+- dprintk("exp_export: export of non-dev fs without fsid");
++ dprintk("exp_export: export of non-dev fs without fsid\n");
+ return -EINVAL;
+ }
+ if (!inode->i_sb->s_export_op) {
+@@ -386,6 +399,69 @@ static int check_export(struct inode *in
+
+ }
+
++#ifdef CONFIG_NFSD_V4
++
++static int
++fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
++{
++ int len;
++ int migrated, i, err;
++
++ len = qword_get(mesg, buf, PAGE_SIZE);
++ if (len != 5 || memcmp(buf, "fsloc", 5))
++ return 0;
++
++ /* listsize */
++ err = get_int(mesg, &fsloc->locations_count);
++ if (err)
++ return err;
++ if (fsloc->locations_count > MAX_FS_LOCATIONS)
++ return -EINVAL;
++ if (fsloc->locations_count == 0)
++ return 0;
++
++ fsloc->locations = kzalloc(fsloc->locations_count
++ * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
++ if (!fsloc->locations)
++ return -ENOMEM;
++ for (i=0; i < fsloc->locations_count; i++) {
++ /* colon separated host list */
++ err = -EINVAL;
++ len = qword_get(mesg, buf, PAGE_SIZE);
++ if (len <= 0)
++ goto out_free_all;
++ err = -ENOMEM;
++ fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
++ if (!fsloc->locations[i].hosts)
++ goto out_free_all;
++ err = -EINVAL;
++ /* slash separated path component list */
++ len = qword_get(mesg, buf, PAGE_SIZE);
++ if (len <= 0)
++ goto out_free_all;
++ err = -ENOMEM;
++ fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
++ if (!fsloc->locations[i].path)
++ goto out_free_all;
++ }
++ /* migrated */
++ err = get_int(mesg, &migrated);
++ if (err)
++ goto out_free_all;
++ err = -EINVAL;
++ if (migrated < 0 || migrated > 1)
++ goto out_free_all;
++ fsloc->migrated = migrated;
++ return 0;
++out_free_all:
++ nfsd4_fslocs_free(fsloc);
++ return err;
++}
++
++#else /* CONFIG_NFSD_V4 */
++static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; }
++#endif
++
+ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
+ {
+ /* client path expiry [flags anonuid anongid fsid] */
+@@ -398,6 +474,7 @@ static int svc_export_parse(struct cache
+ int an_int;
+
+ nd.dentry = NULL;
++ exp.ex_path = NULL;
+
+ if (mesg[mlen-1] != '\n')
+ return -EINVAL;
+@@ -428,6 +505,10 @@ static int svc_export_parse(struct cache
+ exp.ex_client = dom;
+ exp.ex_mnt = nd.mnt;
+ exp.ex_dentry = nd.dentry;
++ exp.ex_path = kstrdup(buf, GFP_KERNEL);
++ err = -ENOMEM;
++ if (!exp.ex_path)
++ goto out;
+
+ /* expiry */
+ err = -EINVAL;
+@@ -435,6 +516,11 @@ static int svc_export_parse(struct cache
+ if (exp.h.expiry_time == 0)
+ goto out;
+
++ /* fs locations */
++ exp.ex_fslocs.locations = NULL;
++ exp.ex_fslocs.locations_count = 0;
++ exp.ex_fslocs.migrated = 0;
++
+ /* flags */
+ err = get_int(&mesg, &an_int);
+ if (err == -ENOENT)
+@@ -460,6 +546,10 @@ static int svc_export_parse(struct cache
+
+ err = check_export(nd.dentry->d_inode, exp.ex_flags);
+ if (err) goto out;
++
++ err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
++ if (err)
++ goto out;
+ }
+
+ expp = svc_export_lookup(&exp);
+@@ -473,6 +563,7 @@ static int svc_export_parse(struct cache
+ else
+ exp_put(expp);
+ out:
++ kfree(exp.ex_path);
+ if (nd.dentry)
+ path_release(&nd);
+ out_no_path:
+@@ -482,7 +573,8 @@ static int svc_export_parse(struct cache
+ return err;
+ }
+
+-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong);
++static void exp_flags(struct seq_file *m, int flag, int fsid,
++ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
+
+ static int svc_export_show(struct seq_file *m,
+ struct cache_detail *cd,
+@@ -501,8 +593,8 @@ static int svc_export_show(struct seq_fi
+ seq_putc(m, '(');
+ if (test_bit(CACHE_VALID, &h->flags) &&
+ !test_bit(CACHE_NEGATIVE, &h->flags))
+- exp_flags(m, exp->ex_flags, exp->ex_fsid,
+- exp->ex_anon_uid, exp->ex_anon_gid);
++ exp_flags(m, exp->ex_flags, exp->ex_fsid,
++ exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
+ seq_puts(m, ")\n");
+ return 0;
+ }
+@@ -524,6 +616,10 @@ static void svc_export_init(struct cache
+ new->ex_client = item->ex_client;
+ new->ex_dentry = dget(item->ex_dentry);
+ new->ex_mnt = mntget(item->ex_mnt);
++ new->ex_path = NULL;
++ new->ex_fslocs.locations = NULL;
++ new->ex_fslocs.locations_count = 0;
++ new->ex_fslocs.migrated = 0;
+ }
+
+ static void export_update(struct cache_head *cnew, struct cache_head *citem)
+@@ -535,6 +631,14 @@ static void export_update(struct cache_h
+ new->ex_anon_uid = item->ex_anon_uid;
+ new->ex_anon_gid = item->ex_anon_gid;
+ new->ex_fsid = item->ex_fsid;
++ new->ex_path = item->ex_path;
++ item->ex_path = NULL;
++ new->ex_fslocs.locations = item->ex_fslocs.locations;
++ item->ex_fslocs.locations = NULL;
++ new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
++ item->ex_fslocs.locations_count = 0;
++ new->ex_fslocs.migrated = item->ex_fslocs.migrated;
++ item->ex_fslocs.migrated = 0;
+ }
+
+ static struct cache_head *svc_export_alloc(void)
+@@ -1044,40 +1148,32 @@ exp_find(struct auth_domain *clp, int fs
+ * for a given NFSv4 client. The root is defined to be the
+ * export point with fsid==0
+ */
+-int
++__be32
+ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
+ struct cache_req *creq)
+ {
+- struct svc_expkey *fsid_key;
+ struct svc_export *exp;
+- int rv;
++ __be32 rv;
+ u32 fsidv[2];
+
+ mk_fsid_v1(fsidv, 0);
+
+- fsid_key = exp_find_key(clp, 1, fsidv, creq);
+- if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)
++ exp = exp_find(clp, 1, fsidv, creq);
++ if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
+ return nfserr_dropit;
+- if (!fsid_key || IS_ERR(fsid_key))
+- return nfserr_perm;
+-
+- exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
+ if (exp == NULL)
+- rv = nfserr_perm;
++ return nfserr_perm;
+ else if (IS_ERR(exp))
+- rv = nfserrno(PTR_ERR(exp));
+- else {
+- rv = fh_compose(fhp, exp,
+- fsid_key->ek_dentry, NULL);
+- exp_put(exp);
+- }
+- cache_put(&fsid_key->h, &svc_expkey_cache);
++ return nfserrno(PTR_ERR(exp));
++ rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
++ exp_put(exp);
+ return rv;
+ }
+
+ /* Iterator */
+
+ static void *e_start(struct seq_file *m, loff_t *pos)
++ __acquires(svc_export_cache.hash_lock)
+ {
+ loff_t n = *pos;
+ unsigned hash, export;
+@@ -1086,7 +1182,7 @@ static void *e_start(struct seq_file *m,
+ exp_readlock();
+ read_lock(&svc_export_cache.hash_lock);
+ if (!n--)
+- return (void *)1;
++ return SEQ_START_TOKEN;
+ hash = n >> 32;
+ export = n & ((1LL<<32) - 1);
+
+@@ -1110,7 +1206,7 @@ static void *e_next(struct seq_file *m,
+ struct cache_head *ch = p;
+ int hash = (*pos >> 32);
+
+- if (p == (void *)1)
++ if (p == SEQ_START_TOKEN)
+ hash = 0;
+ else if (ch->next == NULL) {
+ hash++;
+@@ -1131,6 +1227,7 @@ static void *e_next(struct seq_file *m,
+ }
+
+ static void e_stop(struct seq_file *m, void *p)
++ __releases(svc_export_cache.hash_lock)
+ {
+ read_unlock(&svc_export_cache.hash_lock);
+ exp_readunlock();
+@@ -1156,7 +1253,8 @@ static struct flags {
+ { 0, {"", ""}}
+ };
+
+-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
++static void exp_flags(struct seq_file *m, int flag, int fsid,
++ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
+ {
+ int first = 0;
+ struct flags *flg;
+@@ -1172,21 +1270,34 @@ static void exp_flags(struct seq_file *m
+ seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
+ if (anong != (gid_t)-2 && anong != (0x10000-2))
+ seq_printf(m, "%sanongid=%d", first++?",":"", anong);
++ if (fsloc && fsloc->locations_count > 0) {
++ char *loctype = (fsloc->migrated) ? "refer" : "replicas";
++ int i;
++
++ seq_printf(m, "%s%s=", first++?",":"", loctype);
++ seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
++ seq_putc(m, '@');
++ seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
++ for (i = 1; i < fsloc->locations_count; i++) {
++ seq_putc(m, ';');
++ seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
++ seq_putc(m, '@');
++ seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
++ }
++ }
+ }
+
+ static int e_show(struct seq_file *m, void *p)
+ {
+ struct cache_head *cp = p;
+ struct svc_export *exp = container_of(cp, struct svc_export, h);
+- svc_client *clp;
+
+- if (p == (void *)1) {
++ if (p == SEQ_START_TOKEN) {
+ seq_puts(m, "# Version 1.1\n");
+ seq_puts(m, "# Path Client(Flags) # IPs\n");
+ return 0;
+ }
+
+- clp = exp->ex_client;
+ cache_get(&exp->h);
+ if (cache_check(&svc_export_cache, &exp->h, NULL))
+ return 0;
+diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
+index 7b889ff..11fdaf7 100644
+--- a/fs/nfsd/lockd.c
++++ b/fs/nfsd/lockd.c
+@@ -25,7 +25,7 @@
+ static u32
+ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
+ {
+- u32 nfserr;
++ __be32 nfserr;
+ struct svc_fh fh;
+
+ /* must initialize before using! but maxsize doesn't matter */
+@@ -39,18 +39,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct
+ fh_put(&fh);
+ rqstp->rq_client = NULL;
+ exp_readunlock();
+- /* nlm and nfsd don't share error codes.
+- * we invent: 0 = no error
+- * 1 = stale file handle
+- * 2 = other error
++ /* We return nlm error codes as nlm doesn't know
++ * about nfsd, but nfsd does know about nlm..
+ */
+ switch (nfserr) {
+ case nfs_ok:
+ return 0;
++ case nfserr_dropit:
++ return nlm_drop_reply;
++#ifdef CONFIG_LOCKD_V4
+ case nfserr_stale:
+- return 1;
++ return nlm4_stale_fh;
++#endif
+ default:
+- return 2;
++ return nlm_lck_denied;
+ }
+ }
+
+diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
+index fc95c4d..e3eca08 100644
+--- a/fs/nfsd/nfs2acl.c
++++ b/fs/nfsd/nfs2acl.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nfsd/nfsacl.c
++ * linux/fs/nfsd/nfs2acl.c
+ *
+ * Process version 2 NFSACL requests.
+ *
+@@ -21,7 +21,7 @@
+ /*
+ * NULL call.
+ */
+-static int
++static __be32
+ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ return nfs_ok;
+@@ -30,12 +30,12 @@ nfsacld_proc_null(struct svc_rqst *rqstp
+ /*
+ * Get the Access and/or Default ACL of a file.
+ */
+-static int nfsacld_proc_getacl(struct svc_rqst * rqstp,
++static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
+ struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
+ {
+ svc_fh *fh;
+ struct posix_acl *acl;
+- int nfserr = 0;
++ __be32 nfserr = 0;
+
+ dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
+
+@@ -97,12 +97,12 @@ fail:
+ /*
+ * Set the Access and/or Default ACL of a file.
+ */
+-static int nfsacld_proc_setacl(struct svc_rqst * rqstp,
++static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
+ struct nfsd3_setaclargs *argp,
+ struct nfsd_attrstat *resp)
+ {
+ svc_fh *fh;
+- int nfserr = 0;
++ __be32 nfserr = 0;
+
+ dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
+
+@@ -128,7 +128,7 @@ static int nfsacld_proc_setacl(struct sv
+ /*
+ * Check file attributes
+ */
+-static int nfsacld_proc_getattr(struct svc_rqst * rqstp,
++static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
+ struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
+ {
+ dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
+@@ -140,10 +140,10 @@ static int nfsacld_proc_getattr(struct s
+ /*
+ * Check file access
+ */
+-static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
++static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
+ struct nfsd3_accessres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
+ SVCFH_fmt(&argp->fh),
+@@ -158,7 +158,7 @@ static int nfsacld_proc_access(struct sv
+ /*
+ * XDR decode functions
+ */
+-static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_getaclargs *argp)
+ {
+ if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
+@@ -169,7 +169,7 @@ static int nfsaclsvc_decode_getaclargs(s
+ }
+
+
+-static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_setaclargs *argp)
+ {
+ struct kvec *head = rqstp->rq_arg.head;
+@@ -194,7 +194,7 @@ static int nfsaclsvc_decode_setaclargs(s
+ return (n > 0);
+ }
+
+-static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_fhandle *argp)
+ {
+ if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
+@@ -202,7 +202,7 @@ static int nfsaclsvc_decode_fhandleargs(
+ return xdr_argsize_check(rqstp, p);
+ }
+
+-static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_accessargs *argp)
+ {
+ if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
+@@ -217,7 +217,7 @@ static int nfsaclsvc_decode_accessargs(s
+ */
+
+ /* GETACL */
+-static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_getaclres *resp)
+ {
+ struct dentry *dentry = resp->fh.fh_dentry;
+@@ -241,7 +241,7 @@ static int nfsaclsvc_encode_getaclres(st
+
+ rqstp->rq_res.page_len = w;
+ while (w > 0) {
+- if (!svc_take_res_page(rqstp))
++ if (!rqstp->rq_respages[rqstp->rq_resused++])
+ return 0;
+ w -= PAGE_SIZE;
+ }
+@@ -259,7 +259,7 @@ static int nfsaclsvc_encode_getaclres(st
+ return 1;
+ }
+
+-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_attrstat *resp)
+ {
+ p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
+@@ -267,7 +267,7 @@ static int nfsaclsvc_encode_attrstatres(
+ }
+
+ /* ACCESS */
+-static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_accessres *resp)
+ {
+ p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
+@@ -278,7 +278,7 @@ static int nfsaclsvc_encode_accessres(st
+ /*
+ * XDR release functions
+ */
+-static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_getaclres *resp)
+ {
+ fh_put(&resp->fh);
+@@ -287,7 +287,7 @@ static int nfsaclsvc_release_getacl(stru
+ return 1;
+ }
+
+-static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
++static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_fhandle *resp)
+ {
+ fh_put(&resp->fh);
+@@ -333,4 +333,5 @@ struct svc_version nfsd_acl_version2 = {
+ .vs_proc = nfsd_acl_procedures2,
+ .vs_dispatch = nfsd_dispatch,
+ .vs_xdrsize = NFS3_SVC_XDRSIZE,
++ .vs_hidden = 1,
+ };
+diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
+index 16e10c1..fcad289 100644
+--- a/fs/nfsd/nfs3acl.c
++++ b/fs/nfsd/nfs3acl.c
+@@ -19,7 +19,7 @@
+ /*
+ * NULL call.
+ */
+-static int
++static __be32
+ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ return nfs_ok;
+@@ -28,12 +28,12 @@ nfsd3_proc_null(struct svc_rqst *rqstp,
+ /*
+ * Get the Access and/or Default ACL of a file.
+ */
+-static int nfsd3_proc_getacl(struct svc_rqst * rqstp,
++static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
+ struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
+ {
+ svc_fh *fh;
+ struct posix_acl *acl;
+- int nfserr = 0;
++ __be32 nfserr = 0;
+
+ fh = fh_copy(&resp->fh, &argp->fh);
+ if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
+@@ -93,12 +93,12 @@ fail:
+ /*
+ * Set the Access and/or Default ACL of a file.
+ */
+-static int nfsd3_proc_setacl(struct svc_rqst * rqstp,
++static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
+ struct nfsd3_setaclargs *argp,
+ struct nfsd3_attrstat *resp)
+ {
+ svc_fh *fh;
+- int nfserr = 0;
++ __be32 nfserr = 0;
+
+ fh = fh_copy(&resp->fh, &argp->fh);
+ nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR);
+@@ -122,7 +122,7 @@ static int nfsd3_proc_setacl(struct svc_
+ /*
+ * XDR decode functions
+ */
+-static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
++static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_getaclargs *args)
+ {
+ if (!(p = nfs3svc_decode_fh(p, &args->fh)))
+@@ -133,7 +133,7 @@ static int nfs3svc_decode_getaclargs(str
+ }
+
+
+-static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
++static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_setaclargs *args)
+ {
+ struct kvec *head = rqstp->rq_arg.head;
+@@ -163,7 +163,7 @@ static int nfs3svc_decode_setaclargs(str
+ */
+
+ /* GETACL */
+-static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
++static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_getaclres *resp)
+ {
+ struct dentry *dentry = resp->fh.fh_dentry;
+@@ -185,7 +185,7 @@ static int nfs3svc_encode_getaclres(stru
+
+ rqstp->rq_res.page_len = w;
+ while (w > 0) {
+- if (!svc_take_res_page(rqstp))
++ if (!rqstp->rq_respages[rqstp->rq_resused++])
+ return 0;
+ w -= PAGE_SIZE;
+ }
+@@ -208,7 +208,7 @@ static int nfs3svc_encode_getaclres(stru
+ }
+
+ /* SETACL */
+-static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
++static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_attrstat *resp)
+ {
+ p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+@@ -219,7 +219,7 @@ static int nfs3svc_encode_setaclres(stru
+ /*
+ * XDR release functions
+ */
+-static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
++static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_getaclres *resp)
+ {
+ fh_put(&resp->fh);
+@@ -263,5 +263,6 @@ struct svc_version nfsd_acl_version3 = {
+ .vs_proc = nfsd_acl_procedures3,
+ .vs_dispatch = nfsd_dispatch,
+ .vs_xdrsize = NFS3_SVC_XDRSIZE,
++ .vs_hidden = 1,
+ };
+
+diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
+index f61142a..64db601 100644
+--- a/fs/nfsd/nfs3proc.c
++++ b/fs/nfsd/nfs3proc.c
+@@ -43,7 +43,7 @@ static int nfs3_ftypes[] = {
+ /*
+ * NULL call.
+ */
+-static int
++static __be32
+ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ return nfs_ok;
+@@ -52,11 +52,12 @@ nfsd3_proc_null(struct svc_rqst *rqstp,
+ /*
+ * Get a file's attributes
+ */
+-static int
++static __be32
+ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
+ struct nfsd3_attrstat *resp)
+ {
+- int err, nfserr;
++ int err;
++ __be32 nfserr;
+
+ dprintk("nfsd: GETATTR(3) %s\n",
+ SVCFH_fmt(&argp->fh));
+@@ -76,11 +77,11 @@ nfsd3_proc_getattr(struct svc_rqst *rqst
+ /*
+ * Set a file's attributes
+ */
+-static int
++static __be32
+ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
+ struct nfsd3_attrstat *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: SETATTR(3) %s\n",
+ SVCFH_fmt(&argp->fh));
+@@ -94,11 +95,11 @@ nfsd3_proc_setattr(struct svc_rqst *rqst
+ /*
+ * Look up a path name component
+ */
+-static int
++static __be32
+ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
+ struct nfsd3_diropres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: LOOKUP(3) %s %.*s\n",
+ SVCFH_fmt(&argp->fh),
+@@ -118,11 +119,11 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp
+ /*
+ * Check file access
+ */
+-static int
++static __be32
+ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
+ struct nfsd3_accessres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: ACCESS(3) %s 0x%x\n",
+ SVCFH_fmt(&argp->fh),
+@@ -137,11 +138,11 @@ nfsd3_proc_access(struct svc_rqst *rqstp
+ /*
+ * Read a symlink.
+ */
+-static int
++static __be32
+ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
+ struct nfsd3_readlinkres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
+
+@@ -155,11 +156,12 @@ nfsd3_proc_readlink(struct svc_rqst *rqs
+ /*
+ * Read a portion of a file.
+ */
+-static int
++static __be32
+ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
+ struct nfsd3_readres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
++ u32 max_blocksize = svc_max_payload(rqstp);
+
+ dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
+ SVCFH_fmt(&argp->fh),
+@@ -172,15 +174,15 @@ nfsd3_proc_read(struct svc_rqst *rqstp,
+ */
+
+ resp->count = argp->count;
+- if (NFSSVC_MAXBLKSIZE < resp->count)
+- resp->count = NFSSVC_MAXBLKSIZE;
++ if (max_blocksize < resp->count)
++ resp->count = max_blocksize;
+
+ svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
+
+ fh_copy(&resp->fh, &argp->fh);
+ nfserr = nfsd_read(rqstp, &resp->fh, NULL,
+ argp->offset,
+- argp->vec, argp->vlen,
++ rqstp->rq_vec, argp->vlen,
+ &resp->count);
+ if (nfserr == 0) {
+ struct inode *inode = resp->fh.fh_dentry->d_inode;
+@@ -194,11 +196,11 @@ nfsd3_proc_read(struct svc_rqst *rqstp,
+ /*
+ * Write data to a file
+ */
+-static int
++static __be32
+ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
+ struct nfsd3_writeres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
+ SVCFH_fmt(&argp->fh),
+@@ -210,7 +212,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp,
+ resp->committed = argp->stable;
+ nfserr = nfsd_write(rqstp, &resp->fh, NULL,
+ argp->offset,
+- argp->vec, argp->vlen,
++ rqstp->rq_vec, argp->vlen,
+ argp->len,
+ &resp->committed);
+ resp->count = argp->count;
+@@ -222,13 +224,13 @@ nfsd3_proc_write(struct svc_rqst *rqstp,
+ * At least in theory; we'll see how it fares in practice when the
+ * first reports about SunOS compatibility problems start to pour in...
+ */
+-static int
++static __be32
+ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
+ struct nfsd3_diropres *resp)
+ {
+ svc_fh *dirfhp, *newfhp = NULL;
+ struct iattr *attr;
+- u32 nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: CREATE(3) %s %.*s\n",
+ SVCFH_fmt(&argp->fh),
+@@ -264,11 +266,11 @@ nfsd3_proc_create(struct svc_rqst *rqstp
+ /*
+ * Make directory. This operation is not idempotent.
+ */
+-static int
++static __be32
+ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
+ struct nfsd3_diropres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: MKDIR(3) %s %.*s\n",
+ SVCFH_fmt(&argp->fh),
+@@ -284,11 +286,11 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp,
+ RETURN_STATUS(nfserr);
+ }
+
+-static int
++static __be32
+ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
+ struct nfsd3_diropres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
+ SVCFH_fmt(&argp->ffh),
+@@ -306,11 +308,12 @@ nfsd3_proc_symlink(struct svc_rqst *rqst
+ /*
+ * Make socket/fifo/device.
+ */
+-static int
++static __be32
+ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
+ struct nfsd3_diropres *resp)
+ {
+- int nfserr, type;
++ __be32 nfserr;
++ int type;
+ dev_t rdev = 0;
+
+ dprintk("nfsd: MKNOD(3) %s %.*s\n",
+@@ -342,11 +345,11 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp,
+ /*
+ * Remove file/fifo/socket etc.
+ */
+-static int
++static __be32
+ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
+ struct nfsd3_attrstat *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: REMOVE(3) %s %.*s\n",
+ SVCFH_fmt(&argp->fh),
+@@ -362,11 +365,11 @@ nfsd3_proc_remove(struct svc_rqst *rqstp
+ /*
+ * Remove a directory
+ */
+-static int
++static __be32
+ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
+ struct nfsd3_attrstat *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: RMDIR(3) %s %.*s\n",
+ SVCFH_fmt(&argp->fh),
+@@ -378,11 +381,11 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp,
+ RETURN_STATUS(nfserr);
+ }
+
+-static int
++static __be32
+ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
+ struct nfsd3_renameres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: RENAME(3) %s %.*s ->\n",
+ SVCFH_fmt(&argp->ffh),
+@@ -400,11 +403,11 @@ nfsd3_proc_rename(struct svc_rqst *rqstp
+ RETURN_STATUS(nfserr);
+ }
+
+-static int
++static __be32
+ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
+ struct nfsd3_linkres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: LINK(3) %s ->\n",
+ SVCFH_fmt(&argp->ffh));
+@@ -423,11 +426,12 @@ nfsd3_proc_link(struct svc_rqst *rqstp,
+ /*
+ * Read a portion of a directory.
+ */
+-static int
++static __be32
+ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
+ struct nfsd3_readdirres *resp)
+ {
+- int nfserr, count;
++ __be32 nfserr;
++ int count;
+
+ dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
+@@ -458,11 +462,12 @@ nfsd3_proc_readdir(struct svc_rqst *rqst
+ * Read a portion of a directory, including file handles and attrs.
+ * For now, we choose to ignore the dircount parameter.
+ */
+-static int
++static __be32
+ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
+ struct nfsd3_readdirres *resp)
+ {
+- int nfserr, count = 0;
++ __be32 nfserr;
++ int count = 0;
+ loff_t offset;
+ int i;
+ caddr_t page_addr = NULL;
+@@ -516,11 +521,11 @@ nfsd3_proc_readdirplus(struct svc_rqst *
+ /*
+ * Get file system stats
+ */
+-static int
++static __be32
+ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
+ struct nfsd3_fsstatres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: FSSTAT(3) %s\n",
+ SVCFH_fmt(&argp->fh));
+@@ -533,20 +538,21 @@ nfsd3_proc_fsstat(struct svc_rqst * rqst
+ /*
+ * Get file system info
+ */
+-static int
++static __be32
+ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
+ struct nfsd3_fsinfores *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
++ u32 max_blocksize = svc_max_payload(rqstp);
+
+ dprintk("nfsd: FSINFO(3) %s\n",
+ SVCFH_fmt(&argp->fh));
+
+- resp->f_rtmax = NFSSVC_MAXBLKSIZE;
+- resp->f_rtpref = NFSSVC_MAXBLKSIZE;
++ resp->f_rtmax = max_blocksize;
++ resp->f_rtpref = max_blocksize;
+ resp->f_rtmult = PAGE_SIZE;
+- resp->f_wtmax = NFSSVC_MAXBLKSIZE;
+- resp->f_wtpref = NFSSVC_MAXBLKSIZE;
++ resp->f_wtmax = max_blocksize;
++ resp->f_wtpref = max_blocksize;
+ resp->f_wtmult = PAGE_SIZE;
+ resp->f_dtpref = PAGE_SIZE;
+ resp->f_maxfilesize = ~(u32) 0;
+@@ -574,11 +580,11 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqst
+ /*
+ * Get pathconf info for the specified file
+ */
+-static int
++static __be32
+ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
+ struct nfsd3_pathconfres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: PATHCONF(3) %s\n",
+ SVCFH_fmt(&argp->fh));
+@@ -617,11 +623,11 @@ nfsd3_proc_pathconf(struct svc_rqst * rq
+ /*
+ * Commit a file (range) to stable storage.
+ */
+-static int
++static __be32
+ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
+ struct nfsd3_commitres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
+ SVCFH_fmt(&argp->fh),
+diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
+index 243d94b..b4baca3 100644
+--- a/fs/nfsd/nfs3xdr.c
++++ b/fs/nfsd/nfs3xdr.c
+@@ -42,23 +42,23 @@ static u32 nfs3_ftypes[] = {
+ /*
+ * XDR functions for basic NFS types
+ */
+-static inline u32 *
+-encode_time3(u32 *p, struct timespec *time)
++static inline __be32 *
++encode_time3(__be32 *p, struct timespec *time)
+ {
+ *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
+ return p;
+ }
+
+-static inline u32 *
+-decode_time3(u32 *p, struct timespec *time)
++static inline __be32 *
++decode_time3(__be32 *p, struct timespec *time)
+ {
+ time->tv_sec = ntohl(*p++);
+ time->tv_nsec = ntohl(*p++);
+ return p;
+ }
+
+-static inline u32 *
+-decode_fh(u32 *p, struct svc_fh *fhp)
++static inline __be32 *
++decode_fh(__be32 *p, struct svc_fh *fhp)
+ {
+ unsigned int size;
+ fh_init(fhp, NFS3_FHSIZE);
+@@ -72,13 +72,13 @@ decode_fh(u32 *p, struct svc_fh *fhp)
+ }
+
+ /* Helper function for NFSv3 ACL code */
+-u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp)
++__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
+ {
+ return decode_fh(p, fhp);
+ }
+
+-static inline u32 *
+-encode_fh(u32 *p, struct svc_fh *fhp)
++static inline __be32 *
++encode_fh(__be32 *p, struct svc_fh *fhp)
+ {
+ unsigned int size = fhp->fh_handle.fh_size;
+ *p++ = htonl(size);
+@@ -91,8 +91,8 @@ encode_fh(u32 *p, struct svc_fh *fhp)
+ * Decode a file name and make sure that the path contains
+ * no slashes or null bytes.
+ */
+-static inline u32 *
+-decode_filename(u32 *p, char **namp, int *lenp)
++static inline __be32 *
++decode_filename(__be32 *p, char **namp, int *lenp)
+ {
+ char *name;
+ int i;
+@@ -107,8 +107,8 @@ decode_filename(u32 *p, char **namp, int
+ return p;
+ }
+
+-static inline u32 *
+-decode_sattr3(u32 *p, struct iattr *iap)
++static inline __be32 *
++decode_sattr3(__be32 *p, struct iattr *iap)
+ {
+ u32 tmp;
+
+@@ -153,8 +153,8 @@ decode_sattr3(u32 *p, struct iattr *iap)
+ return p;
+ }
+
+-static inline u32 *
+-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
++static inline __be32 *
++encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
+ struct kstat *stat)
+ {
+ struct dentry *dentry = fhp->fh_dentry;
+@@ -186,8 +186,8 @@ encode_fattr3(struct svc_rqst *rqstp, u3
+ return p;
+ }
+
+-static inline u32 *
+-encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
++static inline __be32 *
++encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
+ {
+ struct inode *inode = fhp->fh_dentry->d_inode;
+
+@@ -224,8 +224,8 @@ encode_saved_post_attr(struct svc_rqst *
+ * The inode may be NULL if the call failed because of a stale file
+ * handle. In this case, no attributes are returned.
+ */
+-static u32 *
+-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
++static __be32 *
++encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
+ {
+ struct dentry *dentry = fhp->fh_dentry;
+ if (dentry && dentry->d_inode != NULL) {
+@@ -243,8 +243,8 @@ encode_post_op_attr(struct svc_rqst *rqs
+ }
+
+ /* Helper for NFSv3 ACLs */
+-u32 *
+-nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
++__be32 *
++nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
+ {
+ return encode_post_op_attr(rqstp, p, fhp);
+ }
+@@ -252,8 +252,8 @@ nfs3svc_encode_post_op_attr(struct svc_r
+ /*
+ * Enocde weak cache consistency data
+ */
+-static u32 *
+-encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
++static __be32 *
++encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
+ {
+ struct dentry *dentry = fhp->fh_dentry;
+
+@@ -278,7 +278,7 @@ encode_wcc_data(struct svc_rqst *rqstp,
+ * XDR decode functions
+ */
+ int
+-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
++nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+@@ -286,7 +286,7 @@ nfs3svc_decode_fhandle(struct svc_rqst *
+ }
+
+ int
+-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_sattrargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -303,7 +303,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst
+ }
+
+ int
+-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_diropargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -314,7 +314,7 @@ nfs3svc_decode_diropargs(struct svc_rqst
+ }
+
+ int
+-nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_accessargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+@@ -325,11 +325,12 @@ nfs3svc_decode_accessargs(struct svc_rqs
+ }
+
+ int
+-nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readargs *args)
+ {
+ unsigned int len;
+ int v,pn;
++ u32 max_blocksize = svc_max_payload(rqstp);
+
+ if (!(p = decode_fh(p, &args->fh))
+ || !(p = xdr_decode_hyper(p, &args->offset)))
+@@ -337,17 +338,16 @@ nfs3svc_decode_readargs(struct svc_rqst
+
+ len = args->count = ntohl(*p++);
+
+- if (len > NFSSVC_MAXBLKSIZE)
+- len = NFSSVC_MAXBLKSIZE;
++ if (len > max_blocksize)
++ len = max_blocksize;
+
+ /* set up the kvec */
+ v=0;
+ while (len > 0) {
+- pn = rqstp->rq_resused;
+- svc_take_page(rqstp);
+- args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+- args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
+- len -= args->vec[v].iov_len;
++ pn = rqstp->rq_resused++;
++ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
++ rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
++ len -= rqstp->rq_vec[v].iov_len;
+ v++;
+ }
+ args->vlen = v;
+@@ -355,10 +355,11 @@ nfs3svc_decode_readargs(struct svc_rqst
+ }
+
+ int
+-nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_writeargs *args)
+ {
+ unsigned int len, v, hdr;
++ u32 max_blocksize = svc_max_payload(rqstp);
+
+ if (!(p = decode_fh(p, &args->fh))
+ || !(p = xdr_decode_hyper(p, &args->offset)))
+@@ -373,26 +374,26 @@ nfs3svc_decode_writeargs(struct svc_rqst
+ rqstp->rq_arg.len - hdr < len)
+ return 0;
+
+- args->vec[0].iov_base = (void*)p;
+- args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
++ rqstp->rq_vec[0].iov_base = (void*)p;
++ rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+
+- if (len > NFSSVC_MAXBLKSIZE)
+- len = NFSSVC_MAXBLKSIZE;
++ if (len > max_blocksize)
++ len = max_blocksize;
+ v= 0;
+- while (len > args->vec[v].iov_len) {
+- len -= args->vec[v].iov_len;
++ while (len > rqstp->rq_vec[v].iov_len) {
++ len -= rqstp->rq_vec[v].iov_len;
+ v++;
+- args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
+- args->vec[v].iov_len = PAGE_SIZE;
++ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
++ rqstp->rq_vec[v].iov_len = PAGE_SIZE;
+ }
+- args->vec[v].iov_len = len;
++ rqstp->rq_vec[v].iov_len = len;
+ args->vlen = v+1;
+
+- return args->count == args->len && args->vec[0].iov_len > 0;
++ return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
+ }
+
+ int
+-nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_createargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -416,7 +417,7 @@ nfs3svc_decode_createargs(struct svc_rqs
+ return xdr_argsize_check(rqstp, p);
+ }
+ int
+-nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_createargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -428,7 +429,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst
+ }
+
+ int
+-nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_symlinkargs *args)
+ {
+ unsigned int len;
+@@ -446,11 +447,11 @@ nfs3svc_decode_symlinkargs(struct svc_rq
+ * This page appears in the rq_res.pages list, but as pages_len is always
+ * 0, it won't get in the way
+ */
+- svc_take_page(rqstp);
+ len = ntohl(*p++);
+ if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
+ return 0;
+- args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
++ args->tname = new =
++ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+ args->tlen = len;
+ /* first copy and check from the first page */
+ old = (char*)p;
+@@ -480,7 +481,7 @@ nfs3svc_decode_symlinkargs(struct svc_rq
+ }
+
+ int
+-nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_mknodargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -504,7 +505,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst
+ }
+
+ int
+-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_renameargs *args)
+ {
+ if (!(p = decode_fh(p, &args->ffh))
+@@ -517,19 +518,19 @@ nfs3svc_decode_renameargs(struct svc_rqs
+ }
+
+ int
+-nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readlinkargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+- svc_take_page(rqstp);
+- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
++ args->buffer =
++ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+
+ return xdr_argsize_check(rqstp, p);
+ }
+
+ int
+-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_linkargs *args)
+ {
+ if (!(p = decode_fh(p, &args->ffh))
+@@ -541,7 +542,7 @@ nfs3svc_decode_linkargs(struct svc_rqst
+ }
+
+ int
+-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readdirargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+@@ -554,17 +555,18 @@ nfs3svc_decode_readdirargs(struct svc_rq
+ if (args->count > PAGE_SIZE)
+ args->count = PAGE_SIZE;
+
+- svc_take_page(rqstp);
+- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
++ args->buffer =
++ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+
+ return xdr_argsize_check(rqstp, p);
+ }
+
+ int
+-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readdirargs *args)
+ {
+ int len, pn;
++ u32 max_blocksize = svc_max_payload(rqstp);
+
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+@@ -573,13 +575,12 @@ nfs3svc_decode_readdirplusargs(struct sv
+ args->dircount = ntohl(*p++);
+ args->count = ntohl(*p++);
+
+- len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE :
++ len = (args->count > max_blocksize) ? max_blocksize :
+ args->count;
+ args->count = len;
+
+ while (len > 0) {
+- pn = rqstp->rq_resused;
+- svc_take_page(rqstp);
++ pn = rqstp->rq_resused++;
+ if (!args->buffer)
+ args->buffer = page_address(rqstp->rq_respages[pn]);
+ len -= PAGE_SIZE;
+@@ -589,7 +590,7 @@ nfs3svc_decode_readdirplusargs(struct sv
+ }
+
+ int
+-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_commitargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+@@ -608,14 +609,14 @@ nfs3svc_decode_commitargs(struct svc_rqs
+ * will work properly.
+ */
+ int
+-nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_ressize_check(rqstp, p);
+ }
+
+ /* GETATTR */
+ int
+-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_attrstat *resp)
+ {
+ if (resp->status == 0)
+@@ -625,7 +626,7 @@ nfs3svc_encode_attrstat(struct svc_rqst
+
+ /* SETATTR, REMOVE, RMDIR */
+ int
+-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_attrstat *resp)
+ {
+ p = encode_wcc_data(rqstp, p, &resp->fh);
+@@ -634,7 +635,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *
+
+ /* LOOKUP */
+ int
+-nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_diropres *resp)
+ {
+ if (resp->status == 0) {
+@@ -647,7 +648,7 @@ nfs3svc_encode_diropres(struct svc_rqst
+
+ /* ACCESS */
+ int
+-nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_accessres *resp)
+ {
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+@@ -658,7 +659,7 @@ nfs3svc_encode_accessres(struct svc_rqst
+
+ /* READLINK */
+ int
+-nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readlinkres *resp)
+ {
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+@@ -668,7 +669,6 @@ nfs3svc_encode_readlinkres(struct svc_rq
+ rqstp->rq_res.page_len = resp->len;
+ if (resp->len & 3) {
+ /* need to pad the tail */
+- rqstp->rq_restailpage = 0;
+ rqstp->rq_res.tail[0].iov_base = p;
+ *p = 0;
+ rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
+@@ -680,7 +680,7 @@ nfs3svc_encode_readlinkres(struct svc_rq
+
+ /* READ */
+ int
+-nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readres *resp)
+ {
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+@@ -693,7 +693,6 @@ nfs3svc_encode_readres(struct svc_rqst *
+ rqstp->rq_res.page_len = resp->count;
+ if (resp->count & 3) {
+ /* need to pad the tail */
+- rqstp->rq_restailpage = 0;
+ rqstp->rq_res.tail[0].iov_base = p;
+ *p = 0;
+ rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
+@@ -705,7 +704,7 @@ nfs3svc_encode_readres(struct svc_rqst *
+
+ /* WRITE */
+ int
+-nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_writeres *resp)
+ {
+ p = encode_wcc_data(rqstp, p, &resp->fh);
+@@ -720,7 +719,7 @@ nfs3svc_encode_writeres(struct svc_rqst
+
+ /* CREATE, MKDIR, SYMLINK, MKNOD */
+ int
+-nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_diropres *resp)
+ {
+ if (resp->status == 0) {
+@@ -734,7 +733,7 @@ nfs3svc_encode_createres(struct svc_rqst
+
+ /* RENAME */
+ int
+-nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_renameres *resp)
+ {
+ p = encode_wcc_data(rqstp, p, &resp->ffh);
+@@ -744,7 +743,7 @@ nfs3svc_encode_renameres(struct svc_rqst
+
+ /* LINK */
+ int
+-nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_linkres *resp)
+ {
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+@@ -754,7 +753,7 @@ nfs3svc_encode_linkres(struct svc_rqst *
+
+ /* READDIR */
+ int
+-nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_readdirres *resp)
+ {
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+@@ -768,7 +767,6 @@ nfs3svc_encode_readdirres(struct svc_rqs
+ rqstp->rq_res.page_len = (resp->count) << 2;
+
+ /* add the 'tail' to the end of the 'head' page - page 0. */
+- rqstp->rq_restailpage = 0;
+ rqstp->rq_res.tail[0].iov_base = p;
+ *p++ = 0; /* no more entries */
+ *p++ = htonl(resp->common.err == nfserr_eof);
+@@ -778,8 +776,8 @@ nfs3svc_encode_readdirres(struct svc_rqs
+ return xdr_ressize_check(rqstp, p);
+ }
+
+-static inline u32 *
+-encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name,
++static inline __be32 *
++encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
+ int namlen, ino_t ino)
+ {
+ *p++ = xdr_one; /* mark entry present */
+@@ -792,8 +790,8 @@ encode_entry_baggage(struct nfsd3_readdi
+ return p;
+ }
+
+-static inline u32 *
+-encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p,
++static inline __be32 *
++encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
+ struct svc_fh *fhp)
+ {
+ p = encode_post_op_attr(cd->rqstp, p, fhp);
+@@ -855,7 +853,7 @@ encode_entry(struct readdir_cd *ccd, con
+ {
+ struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
+ common);
+- u32 *p = cd->buffer;
++ __be32 *p = cd->buffer;
+ caddr_t curr_page_addr = NULL;
+ int pn; /* current page number */
+ int slen; /* string (name) length */
+@@ -921,7 +919,7 @@ encode_entry(struct readdir_cd *ccd, con
+ } else if (cd->rqstp->rq_respages[pn+1] != NULL) {
+ /* temporarily encode entry into next page, then move back to
+ * current and next page in rq_respages[] */
+- u32 *p1, *tmp;
++ __be32 *p1, *tmp;
+ int len1, len2;
+
+ /* grab next page for temporary storage of entry */
+@@ -1011,7 +1009,7 @@ nfs3svc_encode_entry_plus(struct readdir
+
+ /* FSSTAT */
+ int
+-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_fsstatres *resp)
+ {
+ struct kstatfs *s = &resp->stats;
+@@ -1033,7 +1031,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst
+
+ /* FSINFO */
+ int
+-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_fsinfores *resp)
+ {
+ *p++ = xdr_zero; /* no post_op_attr */
+@@ -1057,7 +1055,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst
+
+ /* PATHCONF */
+ int
+-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_pathconfres *resp)
+ {
+ *p++ = xdr_zero; /* no post_op_attr */
+@@ -1076,7 +1074,7 @@ nfs3svc_encode_pathconfres(struct svc_rq
+
+ /* COMMIT */
+ int
+-nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_commitres *resp)
+ {
+ p = encode_wcc_data(rqstp, p, &resp->fh);
+@@ -1092,7 +1090,7 @@ nfs3svc_encode_commitres(struct svc_rqst
+ * XDR release functions
+ */
+ int
+-nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_attrstat *resp)
+ {
+ fh_put(&resp->fh);
+@@ -1100,7 +1098,7 @@ nfs3svc_release_fhandle(struct svc_rqst
+ }
+
+ int
+-nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
++nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd3_fhandle_pair *resp)
+ {
+ fh_put(&resp->fh1);
+diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
+index edb107e..5d94555 100644
+--- a/fs/nfsd/nfs4acl.c
++++ b/fs/nfsd/nfs4acl.c
+@@ -63,6 +63,8 @@
+ #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
+ | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
+
++#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP)
++
+ #define MASK_EQUAL(mask1, mask2) \
+ ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
+
+@@ -96,24 +98,26 @@ deny_mask(u32 allow_mask, unsigned int f
+ /* XXX: modify functions to return NFS errors; they're only ever
+ * used by nfs code, after all.... */
+
+-static int
+-mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
++/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
++ * side of being more restrictive, so the mode bit mapping below is
++ * pessimistic. An optimistic version would be needed to handle DENY's,
++ * but we espect to coalesce all ALLOWs and DENYs before mapping to mode
++ * bits. */
++
++static void
++low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
+ {
+- u32 ignore = 0;
++ u32 write_mode = NFS4_WRITE_MODE;
+
+- if (!(flags & NFS4_ACL_DIR))
+- ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */
+- perm |= ignore;
++ if (flags & NFS4_ACL_DIR)
++ write_mode |= NFS4_ACE_DELETE_CHILD;
+ *mode = 0;
+ if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
+ *mode |= ACL_READ;
+- if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
++ if ((perm & write_mode) == write_mode)
+ *mode |= ACL_WRITE;
+ if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
+ *mode |= ACL_EXECUTE;
+- if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
+- return -EINVAL;
+- return 0;
+ }
+
+ struct ace_container {
+@@ -338,38 +342,6 @@ sort_pacl(struct posix_acl *pacl)
+ return;
+ }
+
+-static int
+-write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
+- struct posix_acl_entry **pace, short tag, unsigned int flags)
+-{
+- struct posix_acl_entry *this = *pace;
+-
+- if (*pace == pacl->a_entries + pacl->a_count)
+- return -EINVAL; /* fell off the end */
+- (*pace)++;
+- this->e_tag = tag;
+- if (tag == ACL_USER_OBJ)
+- flags |= NFS4_ACL_OWNER;
+- if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
+- return -EINVAL;
+- this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
+- ace->who : ACL_UNDEFINED_ID);
+- return 0;
+-}
+-
+-static struct nfs4_ace *
+-get_next_v4_ace(struct list_head **p, struct list_head *head)
+-{
+- struct nfs4_ace *ace;
+-
+- *p = (*p)->next;
+- if (*p == head)
+- return NULL;
+- ace = list_entry(*p, struct nfs4_ace, l_ace);
+-
+- return ace;
+-}
+-
+ int
+ nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
+ struct posix_acl **dpacl, unsigned int flags)
+@@ -385,42 +357,23 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl
+ goto out;
+
+ error = nfs4_acl_split(acl, dacl);
+- if (error < 0)
++ if (error)
+ goto out_acl;
+
+- if (pacl != NULL) {
+- if (acl->naces == 0) {
+- error = -ENODATA;
+- goto try_dpacl;
+- }
+-
+- *pacl = _nfsv4_to_posix_one(acl, flags);
+- if (IS_ERR(*pacl)) {
+- error = PTR_ERR(*pacl);
+- *pacl = NULL;
+- goto out_acl;
+- }
++ *pacl = _nfsv4_to_posix_one(acl, flags);
++ if (IS_ERR(*pacl)) {
++ error = PTR_ERR(*pacl);
++ *pacl = NULL;
++ goto out_acl;
+ }
+
+-try_dpacl:
+- if (dpacl != NULL) {
+- if (dacl->naces == 0) {
+- if (pacl == NULL || *pacl == NULL)
+- error = -ENODATA;
+- goto out_acl;
+- }
+-
+- error = 0;
+- *dpacl = _nfsv4_to_posix_one(dacl, flags);
+- if (IS_ERR(*dpacl)) {
+- error = PTR_ERR(*dpacl);
+- *dpacl = NULL;
+- goto out_acl;
+- }
++ *dpacl = _nfsv4_to_posix_one(dacl, flags);
++ if (IS_ERR(*dpacl)) {
++ error = PTR_ERR(*dpacl);
++ *dpacl = NULL;
+ }
+-
+ out_acl:
+- if (error && pacl) {
++ if (error) {
+ posix_acl_release(*pacl);
+ *pacl = NULL;
+ }
+@@ -429,349 +382,311 @@ out:
+ return error;
+ }
+
++/*
++ * While processing the NFSv4 ACE, this maintains bitmasks representing
++ * which permission bits have been allowed and which denied to a given
++ * entity: */
++struct posix_ace_state {
++ u32 allow;
++ u32 deny;
++};
++
++struct posix_user_ace_state {
++ uid_t uid;
++ struct posix_ace_state perms;
++};
++
++struct posix_ace_state_array {
++ int n;
++ struct posix_user_ace_state aces[];
++};
++
++/*
++ * While processing the NFSv4 ACE, this maintains the partial permissions
++ * calculated so far: */
++
++struct posix_acl_state {
++ struct posix_ace_state owner;
++ struct posix_ace_state group;
++ struct posix_ace_state other;
++ struct posix_ace_state everyone;
++ struct posix_ace_state mask; /* Deny unused in this case */
++ struct posix_ace_state_array *users;
++ struct posix_ace_state_array *groups;
++};
++
+ static int
+-same_who(struct nfs4_ace *a, struct nfs4_ace *b)
++init_state(struct posix_acl_state *state, int cnt)
+ {
+- return a->whotype == b->whotype &&
+- (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
++ int alloc;
++
++ memset(state, 0, sizeof(struct posix_acl_state));
++ /*
++ * In the worst case, each individual acl could be for a distinct
++ * named user or group, but we don't no which, so we allocate
++ * enough space for either:
++ */
++ alloc = sizeof(struct posix_ace_state_array)
++ + cnt*sizeof(struct posix_ace_state);
++ state->users = kzalloc(alloc, GFP_KERNEL);
++ if (!state->users)
++ return -ENOMEM;
++ state->groups = kzalloc(alloc, GFP_KERNEL);
++ if (!state->groups) {
++ kfree(state->users);
++ return -ENOMEM;
++ }
++ return 0;
+ }
+
+-static int
+-complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny,
+- unsigned int flags)
+-{
+- int ignore = 0;
+- if (!(flags & NFS4_ACL_DIR))
+- ignore |= NFS4_ACE_DELETE_CHILD;
+- return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
+- ignore|deny->access_mask) &&
+- allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
+- deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
+- allow->flag == deny->flag &&
+- same_who(allow, deny);
++static void
++free_state(struct posix_acl_state *state) {
++ kfree(state->users);
++ kfree(state->groups);
+ }
+
+-static inline int
+-user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+- struct posix_acl *pacl, struct posix_acl_entry **pace,
+- unsigned int flags)
++static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
+ {
+- int error = -EINVAL;
+- struct nfs4_ace *ace, *ace2;
+-
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- if (ace2type(ace) != ACL_USER_OBJ)
+- goto out;
+- error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
+- if (error < 0)
+- goto out;
+- error = -EINVAL;
+- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace2 == NULL)
+- goto out;
+- if (!complementary_ace_pair(ace, ace2, flags))
+- goto out;
+- error = 0;
+-out:
+- return error;
++ state->mask.allow |= astate->allow;
+ }
+
+-static inline int
+-users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+- struct nfs4_ace **mask_ace,
+- struct posix_acl *pacl, struct posix_acl_entry **pace,
+- unsigned int flags)
+-{
+- int error = -EINVAL;
+- struct nfs4_ace *ace, *ace2;
++/*
++ * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS,
++ * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate
++ * to traditional read/write/execute permissions.
++ *
++ * It's problematic to reject acls that use certain mode bits, because it
++ * places the burden on users to learn the rules about which bits one
++ * particular server sets, without giving the user a lot of help--we return an
++ * error that could mean any number of different things. To make matters
++ * worse, the problematic bits might be introduced by some application that's
++ * automatically mapping from some other acl model.
++ *
++ * So wherever possible we accept anything, possibly erring on the side of
++ * denying more permissions than necessary.
++ *
++ * However we do reject *explicit* DENY's of a few bits representing
++ * permissions we could never deny:
++ */
+
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- while (ace2type(ace) == ACL_USER) {
+- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+- goto out;
+- if (*mask_ace &&
+- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
+- goto out;
+- *mask_ace = ace;
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+- goto out;
+- error = write_pace(ace, pacl, pace, ACL_USER, flags);
+- if (error < 0)
+- goto out;
+- error = -EINVAL;
+- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace2 == NULL)
+- goto out;
+- if (!complementary_ace_pair(ace, ace2, flags))
+- goto out;
+- if ((*mask_ace)->flag != ace2->flag ||
+- !same_who(*mask_ace, ace2))
+- goto out;
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- }
+- error = 0;
+-out:
+- return error;
++static inline int check_deny(u32 mask, int isowner)
++{
++ if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL))
++ return -EINVAL;
++ if (!isowner)
++ return 0;
++ if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL))
++ return -EINVAL;
++ return 0;
+ }
+
+-static inline int
+-group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+- struct nfs4_ace **mask_ace,
+- struct posix_acl *pacl, struct posix_acl_entry **pace,
+- unsigned int flags)
++static struct posix_acl *
++posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
+ {
+- int error = -EINVAL;
+- struct nfs4_ace *ace, *ace2;
+- struct ace_container *ac;
+- struct list_head group_l;
+-
+- INIT_LIST_HEAD(&group_l);
+- ace = list_entry(*p, struct nfs4_ace, l_ace);
+-
+- /* group owner (mask and allow aces) */
++ struct posix_acl_entry *pace;
++ struct posix_acl *pacl;
++ int nace;
++ int i, error = 0;
+
+- if (pacl->a_count != 3) {
+- /* then the group owner should be preceded by mask */
+- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+- goto out;
+- if (*mask_ace &&
+- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
+- goto out;
+- *mask_ace = ace;
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
++ nace = 4 + state->users->n + state->groups->n;
++ pacl = posix_acl_alloc(nace, GFP_KERNEL);
++ if (!pacl)
++ return ERR_PTR(-ENOMEM);
+
+- if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace))
+- goto out;
++ pace = pacl->a_entries;
++ pace->e_tag = ACL_USER_OBJ;
++ error = check_deny(state->owner.deny, 1);
++ if (error)
++ goto out_err;
++ low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
++ pace->e_id = ACL_UNDEFINED_ID;
++
++ for (i=0; i < state->users->n; i++) {
++ pace++;
++ pace->e_tag = ACL_USER;
++ error = check_deny(state->users->aces[i].perms.deny, 0);
++ if (error)
++ goto out_err;
++ low_mode_from_nfs4(state->users->aces[i].perms.allow,
++ &pace->e_perm, flags);
++ pace->e_id = state->users->aces[i].uid;
++ add_to_mask(state, &state->users->aces[i].perms);
+ }
+
+- if (ace2type(ace) != ACL_GROUP_OBJ)
+- goto out;
+-
+- ac = kmalloc(sizeof(*ac), GFP_KERNEL);
+- error = -ENOMEM;
+- if (ac == NULL)
+- goto out;
+- ac->ace = ace;
+- list_add_tail(&ac->ace_l, &group_l);
+-
+- error = -EINVAL;
+- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+- goto out;
+-
+- error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags);
+- if (error < 0)
+- goto out;
+-
+- error = -EINVAL;
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+-
+- /* groups (mask and allow aces) */
+-
+- while (ace2type(ace) == ACL_GROUP) {
+- if (*mask_ace == NULL)
+- goto out;
+-
+- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
+- goto out;
+- *mask_ace = ace;
++ pace++;
++ pace->e_tag = ACL_GROUP_OBJ;
++ error = check_deny(state->group.deny, 0);
++ if (error)
++ goto out_err;
++ low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
++ pace->e_id = ACL_UNDEFINED_ID;
++ add_to_mask(state, &state->group);
++
++ for (i=0; i < state->groups->n; i++) {
++ pace++;
++ pace->e_tag = ACL_GROUP;
++ error = check_deny(state->groups->aces[i].perms.deny, 0);
++ if (error)
++ goto out_err;
++ low_mode_from_nfs4(state->groups->aces[i].perms.allow,
++ &pace->e_perm, flags);
++ pace->e_id = state->groups->aces[i].uid;
++ add_to_mask(state, &state->groups->aces[i].perms);
++ }
+
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- ac = kmalloc(sizeof(*ac), GFP_KERNEL);
+- error = -ENOMEM;
+- if (ac == NULL)
+- goto out;
+- error = -EINVAL;
+- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
+- !same_who(ace, *mask_ace))
+- goto out;
++ pace++;
++ pace->e_tag = ACL_MASK;
++ low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
++ pace->e_id = ACL_UNDEFINED_ID;
+
+- ac->ace = ace;
+- list_add_tail(&ac->ace_l, &group_l);
++ pace++;
++ pace->e_tag = ACL_OTHER;
++ error = check_deny(state->other.deny, 0);
++ if (error)
++ goto out_err;
++ low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
++ pace->e_id = ACL_UNDEFINED_ID;
+
+- error = write_pace(ace, pacl, pace, ACL_GROUP, flags);
+- if (error < 0)
+- goto out;
+- error = -EINVAL;
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- }
++ return pacl;
++out_err:
++ posix_acl_release(pacl);
++ return ERR_PTR(error);
++}
+
+- /* group owner (deny ace) */
++static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
++{
++ /* Allow all bits in the mask not already denied: */
++ astate->allow |= mask & ~astate->deny;
++}
+
+- if (ace2type(ace) != ACL_GROUP_OBJ)
+- goto out;
+- ac = list_entry(group_l.next, struct ace_container, ace_l);
+- ace2 = ac->ace;
+- if (!complementary_ace_pair(ace2, ace, flags))
+- goto out;
+- list_del(group_l.next);
+- kfree(ac);
++static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
++{
++ /* Deny all bits in the mask not already allowed: */
++ astate->deny |= mask & ~astate->allow;
++}
+
+- /* groups (deny aces) */
++static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid)
++{
++ int i;
+
+- while (!list_empty(&group_l)) {
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- if (ace2type(ace) != ACL_GROUP)
+- goto out;
+- ac = list_entry(group_l.next, struct ace_container, ace_l);
+- ace2 = ac->ace;
+- if (!complementary_ace_pair(ace2, ace, flags))
+- goto out;
+- list_del(group_l.next);
+- kfree(ac);
+- }
++ for (i = 0; i < a->n; i++)
++ if (a->aces[i].uid == uid)
++ return i;
++ /* Not found: */
++ a->n++;
++ a->aces[i].uid = uid;
++ a->aces[i].perms.allow = state->everyone.allow;
++ a->aces[i].perms.deny = state->everyone.deny;
+
+- ace = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace == NULL)
+- goto out;
+- if (ace2type(ace) != ACL_OTHER)
+- goto out;
+- error = 0;
+-out:
+- while (!list_empty(&group_l)) {
+- ac = list_entry(group_l.next, struct ace_container, ace_l);
+- list_del(group_l.next);
+- kfree(ac);
+- }
+- return error;
++ return i;
+ }
+
+-static inline int
+-mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+- struct nfs4_ace **mask_ace,
+- struct posix_acl *pacl, struct posix_acl_entry **pace,
+- unsigned int flags)
++static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
+ {
+- int error = -EINVAL;
+- struct nfs4_ace *ace;
++ int i;
+
+- ace = list_entry(*p, struct nfs4_ace, l_ace);
+- if (pacl->a_count != 3) {
+- if (*mask_ace == NULL)
+- goto out;
+- (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
+- write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
+- }
+- error = 0;
+-out:
+- return error;
++ for (i=0; i < a->n; i++)
++ deny_bits(&a->aces[i].perms, mask);
+ }
+
+-static inline int
+-other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+- struct posix_acl *pacl, struct posix_acl_entry **pace,
+- unsigned int flags)
++static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
+ {
+- int error = -EINVAL;
+- struct nfs4_ace *ace, *ace2;
++ int i;
+
+- ace = list_entry(*p, struct nfs4_ace, l_ace);
+- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+- goto out;
+- error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
+- if (error < 0)
+- goto out;
+- error = -EINVAL;
+- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
+- if (ace2 == NULL)
+- goto out;
+- if (!complementary_ace_pair(ace, ace2, flags))
+- goto out;
+- error = 0;
+-out:
+- return error;
++ for (i=0; i < a->n; i++)
++ allow_bits(&a->aces[i].perms, mask);
+ }
+
+-static int
+-calculate_posix_ace_count(struct nfs4_acl *n4acl)
++static void process_one_v4_ace(struct posix_acl_state *state,
++ struct nfs4_ace *ace)
+ {
+- if (n4acl->naces == 6) /* owner, owner group, and other only */
+- return 3;
+- else { /* Otherwise there must be a mask entry. */
+- /* Also, the remaining entries are for named users and
+- * groups, and come in threes (mask, allow, deny): */
+- if (n4acl->naces < 7)
+- return -EINVAL;
+- if ((n4acl->naces - 7) % 3)
+- return -EINVAL;
+- return 4 + (n4acl->naces - 7)/3;
++ u32 mask = ace->access_mask;
++ int i;
++
++ switch (ace2type(ace)) {
++ case ACL_USER_OBJ:
++ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
++ allow_bits(&state->owner, mask);
++ } else {
++ deny_bits(&state->owner, mask);
++ }
++ break;
++ case ACL_USER:
++ i = find_uid(state, state->users, ace->who);
++ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
++ allow_bits(&state->users->aces[i].perms, mask);
++ } else {
++ deny_bits(&state->users->aces[i].perms, mask);
++ mask = state->users->aces[i].perms.deny;
++ deny_bits(&state->owner, mask);
++ }
++ break;
++ case ACL_GROUP_OBJ:
++ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
++ allow_bits(&state->group, mask);
++ } else {
++ deny_bits(&state->group, mask);
++ mask = state->group.deny;
++ deny_bits(&state->owner, mask);
++ deny_bits(&state->everyone, mask);
++ deny_bits_array(state->users, mask);
++ deny_bits_array(state->groups, mask);
++ }
++ break;
++ case ACL_GROUP:
++ i = find_uid(state, state->groups, ace->who);
++ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
++ allow_bits(&state->groups->aces[i].perms, mask);
++ } else {
++ deny_bits(&state->groups->aces[i].perms, mask);
++ mask = state->groups->aces[i].perms.deny;
++ deny_bits(&state->owner, mask);
++ deny_bits(&state->group, mask);
++ deny_bits(&state->everyone, mask);
++ deny_bits_array(state->users, mask);
++ deny_bits_array(state->groups, mask);
++ }
++ break;
++ case ACL_OTHER:
++ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
++ allow_bits(&state->owner, mask);
++ allow_bits(&state->group, mask);
++ allow_bits(&state->other, mask);
++ allow_bits(&state->everyone, mask);
++ allow_bits_array(state->users, mask);
++ allow_bits_array(state->groups, mask);
++ } else {
++ deny_bits(&state->owner, mask);
++ deny_bits(&state->group, mask);
++ deny_bits(&state->other, mask);
++ deny_bits(&state->everyone, mask);
++ deny_bits_array(state->users, mask);
++ deny_bits_array(state->groups, mask);
++ }
+ }
+ }
+
+-
+ static struct posix_acl *
+ _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
+ {
++ struct posix_acl_state state;
+ struct posix_acl *pacl;
+- int error = -EINVAL, nace = 0;
+- struct list_head *p;
+- struct nfs4_ace *mask_ace = NULL;
+- struct posix_acl_entry *pace;
+-
+- nace = calculate_posix_ace_count(n4acl);
+- if (nace < 0)
+- goto out_err;
+-
+- pacl = posix_acl_alloc(nace, GFP_KERNEL);
+- error = -ENOMEM;
+- if (pacl == NULL)
+- goto out_err;
+-
+- pace = &pacl->a_entries[0];
+- p = &n4acl->ace_head;
+-
+- error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
+- if (error)
+- goto out_acl;
+-
+- error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
+- if (error)
+- goto out_acl;
++ struct nfs4_ace *ace;
++ int ret;
+
+- error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
+- flags);
+- if (error)
+- goto out_acl;
++ ret = init_state(&state, n4acl->naces);
++ if (ret)
++ return ERR_PTR(ret);
+
+- error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
+- if (error)
+- goto out_acl;
+- error = other_from_v4(n4acl, &p, pacl, &pace, flags);
+- if (error)
+- goto out_acl;
++ list_for_each_entry(ace, &n4acl->ace_head, l_ace)
++ process_one_v4_ace(&state, ace);
+
+- error = -EINVAL;
+- if (p->next != &n4acl->ace_head)
+- goto out_acl;
+- if (pace != pacl->a_entries + pacl->a_count)
+- goto out_acl;
++ pacl = posix_state_to_acl(&state, flags);
+
+- sort_pacl(pacl);
++ free_state(&state);
+
+- return pacl;
+-out_acl:
+- posix_acl_release(pacl);
+-out_err:
+- pacl = ERR_PTR(error);
++ if (!IS_ERR(pacl))
++ sort_pacl(pacl);
+ return pacl;
+ }
+
+@@ -785,22 +700,41 @@ nfs4_acl_split(struct nfs4_acl *acl, str
+ list_for_each_safe(h, n, &acl->ace_head) {
+ ace = list_entry(h, struct nfs4_ace, l_ace);
+
+- if ((ace->flag & NFS4_INHERITANCE_FLAGS)
+- != NFS4_INHERITANCE_FLAGS)
+- continue;
++ if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
++ ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
++ return -EINVAL;
+
+- error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+- ace->access_mask, ace->whotype, ace->who);
+- if (error < 0)
+- goto out;
++ if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
++ return -EINVAL;
+
+- list_del(h);
+- kfree(ace);
+- acl->naces--;
++ switch (ace->flag & NFS4_INHERITANCE_FLAGS) {
++ case 0:
++ /* Leave this ace in the effective acl: */
++ continue;
++ case NFS4_INHERITANCE_FLAGS:
++ /* Add this ace to the default acl and remove it
++ * from the effective acl: */
++ error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
++ ace->access_mask, ace->whotype, ace->who);
++ if (error)
++ return error;
++ list_del(h);
++ kfree(ace);
++ acl->naces--;
++ break;
++ case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE:
++ /* Add this ace to the default, but leave it in
++ * the effective acl as well: */
++ error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
++ ace->access_mask, ace->whotype, ace->who);
++ if (error)
++ return error;
++ break;
++ default:
++ return -EINVAL;
++ }
+ }
+-
+-out:
+- return error;
++ return 0;
+ }
+
+ static short
+@@ -930,23 +864,6 @@ nfs4_acl_write_who(int who, char *p)
+ return -1;
+ }
+
+-static inline int
+-match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
+-{
+- switch (ace->whotype) {
+- case NFS4_ACL_WHO_NAMED:
+- return who == ace->who;
+- case NFS4_ACL_WHO_OWNER:
+- return who == owner;
+- case NFS4_ACL_WHO_GROUP:
+- return who == group;
+- case NFS4_ACL_WHO_EVERYONE:
+- return 1;
+- default:
+- return 0;
+- }
+-}
+-
+ EXPORT_SYMBOL(nfs4_acl_new);
+ EXPORT_SYMBOL(nfs4_acl_free);
+ EXPORT_SYMBOL(nfs4_acl_add_ace);
+diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
+index 54b37b1..f57655a 100644
+--- a/fs/nfsd/nfs4callback.c
++++ b/fs/nfsd/nfs4callback.c
+@@ -85,8 +85,8 @@ enum nfs_cb_opnum4 {
+ /*
+ * Generic encode routines from fs/nfs/nfs4xdr.c
+ */
+-static inline u32 *
+-xdr_writemem(u32 *p, const void *ptr, int nbytes)
++static inline __be32 *
++xdr_writemem(__be32 *p, const void *ptr, int nbytes)
+ {
+ int tmp = XDR_QUADLEN(nbytes);
+ if (!tmp)
+@@ -131,7 +131,7 @@ xdr_error:
+ #define READ_BUF(nbytes) do { \
+ p = xdr_inline_decode(xdr, nbytes); \
+ if (!p) { \
+- dprintk("NFSD: %s: reply buffer overflowed in line %d.", \
++ dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \
+ __FUNCTION__, __LINE__); \
+ return -EIO; \
+ } \
+@@ -205,7 +205,7 @@ nfs_cb_stat_to_errno(int stat)
+ static int
+ encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
+ {
+- u32 * p;
++ __be32 * p;
+
+ RESERVE_SPACE(16);
+ WRITE32(0); /* tag length is always 0 */
+@@ -218,7 +218,7 @@ encode_cb_compound_hdr(struct xdr_stream
+ static int
+ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
+ {
+- u32 *p;
++ __be32 *p;
+ int len = cb_rec->cbr_fhlen;
+
+ RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
+@@ -231,7 +231,7 @@ encode_cb_recall(struct xdr_stream *xdr,
+ }
+
+ static int
+-nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p)
++nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
+ {
+ struct xdr_stream xdrs, *xdr = &xdrs;
+
+@@ -241,7 +241,7 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *re
+ }
+
+ static int
+-nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args)
++nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args)
+ {
+ struct xdr_stream xdr;
+ struct nfs4_cb_compound_hdr hdr = {
+@@ -257,7 +257,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *
+
+ static int
+ decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
+- u32 *p;
++ __be32 *p;
+
+ READ_BUF(8);
+ READ32(hdr->status);
+@@ -272,7 +272,7 @@ decode_cb_compound_hdr(struct xdr_stream
+ static int
+ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+ {
+- u32 *p;
++ __be32 *p;
+ u32 op;
+ int32_t nfserr;
+
+@@ -291,13 +291,13 @@ decode_cb_op_hdr(struct xdr_stream *xdr,
+ }
+
+ static int
+-nfs4_xdr_dec_cb_null(struct rpc_rqst *req, u32 *p)
++nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
+ {
+ return 0;
+ }
+
+ static int
+-nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
++nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p)
+ {
+ struct xdr_stream xdr;
+ struct nfs4_cb_compound_hdr hdr;
+@@ -375,16 +375,28 @@ nfsd4_probe_callback(struct nfs4_client
+ {
+ struct sockaddr_in addr;
+ struct nfs4_callback *cb = &clp->cl_callback;
+- struct rpc_timeout timeparms;
+- struct rpc_xprt * xprt;
++ struct rpc_timeout timeparms = {
++ .to_initval = (NFSD_LEASE_TIME/4) * HZ,
++ .to_retries = 5,
++ .to_maxval = (NFSD_LEASE_TIME/2) * HZ,
++ .to_exponential = 1,
++ };
+ struct rpc_program * program = &cb->cb_program;
+- struct rpc_stat * stat = &cb->cb_stat;
+- struct rpc_clnt * clnt;
++ struct rpc_create_args args = {
++ .protocol = IPPROTO_TCP,
++ .address = (struct sockaddr *)&addr,
++ .addrsize = sizeof(addr),
++ .timeout = &timeparms,
++ .servername = clp->cl_name.data,
++ .program = program,
++ .version = nfs_cb_version[1]->number,
++ .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
++ .flags = (RPC_CLNT_CREATE_NOPING),
++ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+ .rpc_argp = clp,
+ };
+- char hostname[32];
+ int status;
+
+ if (atomic_read(&cb->cb_set))
+@@ -396,51 +408,27 @@ nfsd4_probe_callback(struct nfs4_client
+ addr.sin_port = htons(cb->cb_port);
+ addr.sin_addr.s_addr = htonl(cb->cb_addr);
+
+- /* Initialize timeout */
+- timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ;
+- timeparms.to_retries = 0;
+- timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ;
+- timeparms.to_exponential = 1;
+-
+- /* Create RPC transport */
+- xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms);
+- if (IS_ERR(xprt)) {
+- dprintk("NFSD: couldn't create callback transport!\n");
+- goto out_err;
+- }
+-
+ /* Initialize rpc_program */
+ program->name = "nfs4_cb";
+ program->number = cb->cb_prog;
+ program->nrvers = ARRAY_SIZE(nfs_cb_version);
+ program->version = nfs_cb_version;
+- program->stats = stat;
++ program->stats = &cb->cb_stat;
+
+ /* Initialize rpc_stat */
+- memset(stat, 0, sizeof(struct rpc_stat));
+- stat->program = program;
+-
+- /* Create RPC client
+- *
+- * XXX AUTH_UNIX only - need AUTH_GSS....
+- */
+- sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
+- clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
+- if (IS_ERR(clnt)) {
++ memset(program->stats, 0, sizeof(cb->cb_stat));
++ program->stats->program = program;
++
++ /* Create RPC client */
++ cb->cb_client = rpc_create(&args);
++ if (IS_ERR(cb->cb_client)) {
+ dprintk("NFSD: couldn't create callback client\n");
+ goto out_err;
+ }
+- clnt->cl_intr = 0;
+- clnt->cl_softrtry = 1;
+
+ /* Kick rpciod, put the call on the wire. */
+-
+- if (rpciod_up() != 0) {
+- dprintk("nfsd: couldn't start rpciod for callbacks!\n");
++ if (rpciod_up() != 0)
+ goto out_clnt;
+- }
+-
+- cb->cb_client = clnt;
+
+ /* the task holds a reference to the nfs4_client struct */
+ atomic_inc(&clp->cl_count);
+@@ -448,7 +436,7 @@ nfsd4_probe_callback(struct nfs4_client
+ msg.rpc_cred = nfsd4_lookupcred(clp,0);
+ if (IS_ERR(msg.rpc_cred))
+ goto out_rpciod;
+- status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
++ status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
+ put_rpccred(msg.rpc_cred);
+
+ if (status != 0) {
+@@ -460,10 +448,10 @@ nfsd4_probe_callback(struct nfs4_client
+ out_rpciod:
+ atomic_dec(&clp->cl_count);
+ rpciod_down();
+- cb->cb_client = NULL;
+ out_clnt:
+- rpc_shutdown_client(clnt);
++ rpc_shutdown_client(cb->cb_client);
+ out_err:
++ cb->cb_client = NULL;
+ dprintk("NFSD: warning: no callback path to client %.*s\n",
+ (int)clp->cl_name.len, clp->cl_name.data);
+ }
+@@ -473,7 +461,7 @@ nfs4_cb_null(struct rpc_task *task, void
+ {
+ struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
+ struct nfs4_callback *cb = &clp->cl_callback;
+- u32 addr = htonl(cb->cb_addr);
++ __be32 addr = htonl(cb->cb_addr);
+
+ dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
+
+diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
+index bea6b94..b1902eb 100644
+--- a/fs/nfsd/nfs4idmap.c
++++ b/fs/nfsd/nfs4idmap.c
+@@ -573,10 +573,9 @@ idmap_lookup(struct svc_rqst *rqstp,
+ struct idmap_defer_req *mdr;
+ int ret;
+
+- mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
++ mdr = kzalloc(sizeof(*mdr), GFP_KERNEL);
+ if (!mdr)
+ return -ENOMEM;
+- memset(mdr, 0, sizeof(*mdr));
+ atomic_set(&mdr->count, 1);
+ init_waitqueue_head(&mdr->waitq);
+ mdr->req.defer = idmap_defer;
+diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
+index ee4eff2..0a7bbdc 100644
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -67,32 +67,32 @@ fh_dup2(struct svc_fh *dst, struct svc_f
+ *dst = *src;
+ }
+
+-static int
+-do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
++static __be32
++do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
+ {
+- int accmode, status;
++ __be32 status;
+
+ if (open->op_truncate &&
+ !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
+ return nfserr_inval;
+
+- accmode = MAY_NOP;
+ if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
+- accmode = MAY_READ;
+- if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
++ accmode |= MAY_READ;
++ if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
+ accmode |= (MAY_WRITE | MAY_TRUNC);
+- accmode |= MAY_OWNER_OVERRIDE;
++ if (open->op_share_deny & NFS4_SHARE_DENY_WRITE)
++ accmode |= MAY_WRITE;
+
+ status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
+
+ return status;
+ }
+
+-static int
++static __be32
+ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+ {
+ struct svc_fh resfh;
+- int status;
++ __be32 status;
+
+ fh_init(&resfh, NFS4_FHSIZE);
+ open->op_truncate = 0;
+@@ -124,17 +124,17 @@ do_open_lookup(struct svc_rqst *rqstp, s
+ &resfh.fh_handle.fh_base,
+ resfh.fh_handle.fh_size);
+
+- status = do_open_permission(rqstp, current_fh, open);
++ status = do_open_permission(rqstp, current_fh, open, MAY_NOP);
+ }
+
+ fh_put(&resfh);
+ return status;
+ }
+
+-static int
++static __be32
+ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+ {
+- int status;
++ __be32 status;
+
+ /* Only reclaims from previously confirmed clients are valid */
+ if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
+@@ -155,16 +155,16 @@ do_open_fhandle(struct svc_rqst *rqstp,
+ open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
+ (open->op_iattr.ia_size == 0);
+
+- status = do_open_permission(rqstp, current_fh, open);
++ status = do_open_permission(rqstp, current_fh, open, MAY_OWNER_OVERRIDE);
+
+ return status;
+ }
+
+
+-static inline int
++static inline __be32
+ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner)
+ {
+- int status;
++ __be32 status;
+ dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
+ (int)open->op_fname.len, open->op_fname.data,
+ open->op_stateowner);
+@@ -177,7 +177,7 @@ nfsd4_open(struct svc_rqst *rqstp, struc
+
+ /* check seqid for replay. set nfs4_owner */
+ status = nfsd4_process_open1(open);
+- if (status == NFSERR_REPLAY_ME) {
++ if (status == nfserr_replay_me) {
+ struct nfs4_replay *rp = &open->op_stateowner->so_replay;
+ fh_put(current_fh);
+ current_fh->fh_handle.fh_size = rp->rp_openfh_len;
+@@ -188,7 +188,7 @@ nfsd4_open(struct svc_rqst *rqstp, struc
+ dprintk("nfsd4_open: replay failed"
+ " restoring previous filehandle\n");
+ else
+- status = NFSERR_REPLAY_ME;
++ status = nfserr_replay_me;
+ }
+ if (status)
+ goto out;
+@@ -261,7 +261,7 @@ out:
+ /*
+ * filehandle-manipulating ops.
+ */
+-static inline int
++static inline __be32
+ nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
+ {
+ if (!current_fh->fh_dentry)
+@@ -271,7 +271,7 @@ nfsd4_getfh(struct svc_fh *current_fh, s
+ return nfs_ok;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh)
+ {
+ fh_put(current_fh);
+@@ -280,10 +280,10 @@ nfsd4_putfh(struct svc_rqst *rqstp, stru
+ return fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
+ {
+- int status;
++ __be32 status;
+
+ fh_put(current_fh);
+ status = exp_pseudoroot(rqstp->rq_client, current_fh,
+@@ -291,7 +291,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp,
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
+ {
+ if (!save_fh->fh_dentry)
+@@ -301,7 +301,7 @@ nfsd4_restorefh(struct svc_fh *current_f
+ return nfs_ok;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
+ {
+ if (!current_fh->fh_dentry)
+@@ -314,7 +314,7 @@ nfsd4_savefh(struct svc_fh *current_fh,
+ /*
+ * misc nfsv4 ops
+ */
+-static inline int
++static inline __be32
+ nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access)
+ {
+ if (access->ac_req_access & ~NFS3_ACCESS_FULL)
+@@ -324,10 +324,10 @@ nfsd4_access(struct svc_rqst *rqstp, str
+ return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported);
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
+ {
+- int status;
++ __be32 status;
+
+ u32 *p = (u32 *)commit->co_verf.data;
+ *p++ = nfssvc_boot.tv_sec;
+@@ -339,11 +339,11 @@ nfsd4_commit(struct svc_rqst *rqstp, str
+ return status;
+ }
+
+-static int
++static __be32
+ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
+ {
+ struct svc_fh resfh;
+- int status;
++ __be32 status;
+ dev_t rdev;
+
+ fh_init(&resfh, NFS4_FHSIZE);
+@@ -423,10 +423,10 @@ nfsd4_create(struct svc_rqst *rqstp, str
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr)
+ {
+- int status;
++ __be32 status;
+
+ status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ if (status)
+@@ -442,11 +442,11 @@ nfsd4_getattr(struct svc_rqst *rqstp, st
+ return nfs_ok;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct svc_fh *save_fh, struct nfsd4_link *link)
+ {
+- int status = nfserr_nofilehandle;
++ __be32 status = nfserr_nofilehandle;
+
+ if (!save_fh->fh_dentry)
+ return status;
+@@ -456,11 +456,11 @@ nfsd4_link(struct svc_rqst *rqstp, struc
+ return status;
+ }
+
+-static int
++static __be32
+ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
+ {
+ struct svc_fh tmp_fh;
+- int ret;
++ __be32 ret;
+
+ fh_init(&tmp_fh, NFS4_FHSIZE);
+ if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
+@@ -474,16 +474,16 @@ nfsd4_lookupp(struct svc_rqst *rqstp, st
+ return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup)
+ {
+ return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
+ {
+- int status;
++ __be32 status;
+
+ /* no need to check permission - this will be done in nfsd_read() */
+
+@@ -508,7 +508,7 @@ out:
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
+ {
+ u64 cookie = readdir->rd_cookie;
+@@ -531,7 +531,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, st
+ return nfs_ok;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink)
+ {
+ readlink->rl_rqstp = rqstp;
+@@ -539,10 +539,10 @@ nfsd4_readlink(struct svc_rqst *rqstp, s
+ return nfs_ok;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove)
+ {
+- int status;
++ __be32 status;
+
+ if (nfs4_in_grace())
+ return nfserr_grace;
+@@ -556,11 +556,11 @@ nfsd4_remove(struct svc_rqst *rqstp, str
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct svc_fh *save_fh, struct nfsd4_rename *rename)
+ {
+- int status = nfserr_nofilehandle;
++ __be32 status = nfserr_nofilehandle;
+
+ if (!save_fh->fh_dentry)
+ return status;
+@@ -589,10 +589,10 @@ nfsd4_rename(struct svc_rqst *rqstp, str
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
+ {
+- int status = nfs_ok;
++ __be32 status = nfs_ok;
+
+ if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
+ nfs4_lock_state();
+@@ -600,7 +600,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
+ &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL);
+ nfs4_unlock_state();
+ if (status) {
+- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!");
++ dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
+ return status;
+ }
+ }
+@@ -614,13 +614,13 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
+ {
+ stateid_t *stateid = &write->wr_stateid;
+ struct file *filp = NULL;
+ u32 *p;
+- int status = nfs_ok;
++ __be32 status = nfs_ok;
+
+ /* no need to check permission - this will be done in nfsd_write() */
+
+@@ -646,7 +646,7 @@ nfsd4_write(struct svc_rqst *rqstp, stru
+ *p++ = nfssvc_boot.tv_usec;
+
+ status = nfsd_write(rqstp, current_fh, filp, write->wr_offset,
+- write->wr_vec, write->wr_vlen, write->wr_buflen,
++ rqstp->rq_vec, write->wr_vlen, write->wr_buflen,
+ &write->wr_how_written);
+ if (filp)
+ fput(filp);
+@@ -661,12 +661,12 @@ nfsd4_write(struct svc_rqst *rqstp, stru
+ * attributes matched. VERIFY is implemented by mapping NFSERR_SAME
+ * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
+ */
+-static int
++static __be32
+ nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify)
+ {
+- u32 *buf, *p;
++ __be32 *buf, *p;
+ int count;
+- int status;
++ __be32 status;
+
+ status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ if (status)
+@@ -715,7 +715,7 @@ out_kfree:
+ /*
+ * NULL call.
+ */
+-static int
++static __be32
+ nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ return nfs_ok;
+@@ -731,7 +731,7 @@ static inline void nfsd4_increment_op_st
+ /*
+ * COMPOUND call.
+ */
+-static int
++static __be32
+ nfsd4_proc_compound(struct svc_rqst *rqstp,
+ struct nfsd4_compoundargs *args,
+ struct nfsd4_compoundres *resp)
+@@ -741,7 +741,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
+ struct svc_fh *save_fh = NULL;
+ struct nfs4_stateowner *replay_owner = NULL;
+ int slack_space; /* in words, not bytes! */
+- int status;
++ __be32 status;
+
+ status = nfserr_resource;
+ current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
+@@ -802,13 +802,29 @@ nfsd4_proc_compound(struct svc_rqst *rqs
+ * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
+ * require a valid current filehandle
+ */
+- if ((!current_fh->fh_dentry) &&
+- !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
+- (op->opnum == OP_SETCLIENTID) ||
+- (op->opnum == OP_SETCLIENTID_CONFIRM) ||
+- (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
+- (op->opnum == OP_RELEASE_LOCKOWNER))) {
+- op->status = nfserr_nofilehandle;
++ if (!current_fh->fh_dentry) {
++ if (!((op->opnum == OP_PUTFH) ||
++ (op->opnum == OP_PUTROOTFH) ||
++ (op->opnum == OP_SETCLIENTID) ||
++ (op->opnum == OP_SETCLIENTID_CONFIRM) ||
++ (op->opnum == OP_RENEW) ||
++ (op->opnum == OP_RESTOREFH) ||
++ (op->opnum == OP_RELEASE_LOCKOWNER))) {
++ op->status = nfserr_nofilehandle;
++ goto encode_op;
++ }
++ }
++ /* Check must be done at start of each operation, except
++ * for GETATTR and ops not listed as returning NFS4ERR_MOVED
++ */
++ else if (current_fh->fh_export->ex_fslocs.migrated &&
++ !((op->opnum == OP_GETATTR) ||
++ (op->opnum == OP_PUTROOTFH) ||
++ (op->opnum == OP_PUTPUBFH) ||
++ (op->opnum == OP_RENEW) ||
++ (op->opnum == OP_SETCLIENTID) ||
++ (op->opnum == OP_RELEASE_LOCKOWNER))) {
++ op->status = nfserr_moved;
+ goto encode_op;
+ }
+ switch (op->opnum) {
+@@ -921,7 +937,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
+ }
+
+ encode_op:
+- if (op->status == NFSERR_REPLAY_ME) {
++ if (op->status == nfserr_replay_me) {
+ op->replay = &replay_owner->so_replay;
+ nfsd4_encode_replay(resp, op);
+ status = op->status = op->replay->rp_status;
+diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
+index 06da750..81b8565 100644
+--- a/fs/nfsd/nfs4recover.c
++++ b/fs/nfsd/nfs4recover.c
+@@ -33,7 +33,7 @@
+ *
+ */
+
+-
++#include <linux/err.h>
+ #include <linux/sunrpc/svc.h>
+ #include <linux/nfsd/nfsd.h>
+ #include <linux/nfs4.h>
+@@ -83,38 +83,39 @@ md5_to_hex(char *out, char *md5)
+ *out = '\0';
+ }
+
+-int
++__be32
+ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
+ {
+ struct xdr_netobj cksum;
+- struct crypto_tfm *tfm;
++ struct hash_desc desc;
+ struct scatterlist sg[1];
+- int status = nfserr_resource;
++ __be32 status = nfserr_resource;
+
+ dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
+ clname->len, clname->data);
+- tfm = crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
+- if (tfm == NULL)
+- goto out;
+- cksum.len = crypto_tfm_alg_digestsize(tfm);
++ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++ desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(desc.tfm))
++ goto out_no_tfm;
++ cksum.len = crypto_hash_digestsize(desc.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);
++ if (crypto_hash_digest(&desc, sg, sg->length, cksum.data))
++ goto out;
+
+ md5_to_hex(dname, cksum.data);
+
+ kfree(cksum.data);
+ status = nfs_ok;
+ out:
+- crypto_free_tfm(tfm);
++ crypto_free_hash(desc.tfm);
++out_no_tfm:
+ return status;
+ }
+
+@@ -183,7 +184,7 @@ struct dentry_list_arg {
+
+ static int
+ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct dentry_list_arg *dla = arg;
+ struct list_head *dentries = &dla->dentries;
+@@ -192,7 +193,7 @@ nfsd4_build_dentrylist(void *arg, const
+ struct dentry_list *child;
+
+ if (name && isdotent(name, namlen))
+- return nfs_ok;
++ return 0;
+ dentry = lookup_one_len(name, parent, namlen);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+@@ -273,7 +274,7 @@ nfsd4_clear_clid_dir(struct dentry *dir,
+ * 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);
+- mutex_lock(&dir->d_inode->i_mutex);
++ mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
+ status = vfs_rmdir(dir->d_inode, dentry);
+ mutex_unlock(&dir->d_inode->i_mutex);
+ return status;
+@@ -332,14 +333,14 @@ purge_old(struct dentry *parent, struct
+ int status;
+
+ if (nfs4_has_reclaimed_state(child->d_name.name))
+- return nfs_ok;
++ return 0;
+
+ 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;
++ return 0;
+ }
+
+ void
+@@ -364,10 +365,10 @@ load_recdir(struct dentry *parent, struc
+ printk("nfsd4: illegal name %s in recovery directory\n",
+ child->d_name.name);
+ /* Keep trying; maybe the others are OK: */
+- return nfs_ok;
++ return 0;
+ }
+ nfs4_client_to_reclaim(child->d_name.name);
+- return nfs_ok;
++ return 0;
+ }
+
+ int
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 9daa0b9..293b649 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -339,8 +339,7 @@ alloc_client(struct xdr_netobj name)
+ {
+ struct nfs4_client *clp;
+
+- if ((clp = kmalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
+- memset(clp, 0, sizeof(*clp));
++ if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
+ if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
+ memcpy(clp->cl_name.data, name.data, name.len);
+ clp->cl_name.len = name.len;
+@@ -711,10 +710,10 @@ out_err:
+ * as described above.
+ *
+ */
+-int
++__be32
+ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
+ {
+- u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
++ __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+ struct xdr_netobj clname = {
+ .len = setclid->se_namelen,
+ .data = setclid->se_name,
+@@ -722,7 +721,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
+ nfs4_verifier clverifier = setclid->se_verf;
+ unsigned int strhashval;
+ struct nfs4_client *conf, *unconf, *new;
+- int status;
++ __be32 status;
+ char dname[HEXDIR_LEN];
+
+ if (!check_name(clname))
+@@ -876,14 +875,14 @@ out:
+ *
+ * NOTE: callback information will be processed here in a future patch
+ */
+-int
++__be32
+ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
+ {
+- u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
++ __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+ struct nfs4_client *conf, *unconf;
+ nfs4_verifier confirm = setclientid_confirm->sc_confirm;
+ clientid_t * clid = &setclientid_confirm->sc_clientid;
+- int status;
++ __be32 status;
+
+ if (STALE_CLIENTID(clid))
+ return nfserr_stale_clientid;
+@@ -1006,13 +1005,10 @@ alloc_init_file(struct inode *ino)
+ static void
+ nfsd4_free_slab(kmem_cache_t **slab)
+ {
+- int status;
+-
+ if (*slab == NULL)
+ return;
+- status = kmem_cache_destroy(*slab);
++ kmem_cache_destroy(*slab);
+ *slab = NULL;
+- WARN_ON(status);
+ }
+
+ static void
+@@ -1284,13 +1280,13 @@ test_share(struct nfs4_stateid *stp, str
+ * Called to check deny when READ with all zero stateid or
+ * WRITE with all zero or all one stateid
+ */
+-static int
++static __be32
+ 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;
++ __be32 ret;
+
+ dprintk("NFSD: nfs4_share_conflict\n");
+
+@@ -1448,7 +1444,7 @@ static struct lock_manager_operations nf
+ };
+
+
+-int
++__be32
+ nfsd4_process_open1(struct nfsd4_open *open)
+ {
+ clientid_t *clientid = &open->op_clientid;
+@@ -1481,7 +1477,7 @@ nfsd4_process_open1(struct nfsd4_open *o
+ }
+ if (open->op_seqid == sop->so_seqid - 1) {
+ if (sop->so_replay.rp_buflen)
+- return NFSERR_REPLAY_ME;
++ return nfserr_replay_me;
+ /* The original OPEN failed so spectacularly
+ * that we don't even have replay data saved!
+ * Therefore, we have no choice but to continue
+@@ -1505,7 +1501,7 @@ renew:
+ return nfs_ok;
+ }
+
+-static inline int
++static inline __be32
+ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
+ {
+ if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
+@@ -1526,12 +1522,12 @@ find_delegation_file(struct nfs4_file *f
+ return NULL;
+ }
+
+-static int
++static __be32
+ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
+ struct nfs4_delegation **dp)
+ {
+ int flags;
+- int status = nfserr_bad_stateid;
++ __be32 status = nfserr_bad_stateid;
+
+ *dp = find_delegation_file(fp, &open->op_delegate_stateid);
+ if (*dp == NULL)
+@@ -1550,11 +1546,11 @@ out:
+ return nfs_ok;
+ }
+
+-static int
++static __be32
+ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
+ {
+ struct nfs4_stateid *local;
+- int status = nfserr_share_denied;
++ __be32 status = nfserr_share_denied;
+ struct nfs4_stateowner *sop = open->op_stateowner;
+
+ list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
+@@ -1579,7 +1575,7 @@ nfs4_alloc_stateid(void)
+ return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
+ }
+
+-static int
++static __be32
+ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
+ struct nfs4_delegation *dp,
+ struct svc_fh *cur_fh, int flags)
+@@ -1594,7 +1590,7 @@ nfs4_new_open(struct svc_rqst *rqstp, st
+ get_file(dp->dl_vfs_file);
+ stp->st_vfs_file = dp->dl_vfs_file;
+ } else {
+- int status;
++ __be32 status;
+ status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
+ &stp->st_vfs_file);
+ if (status) {
+@@ -1608,7 +1604,7 @@ nfs4_new_open(struct svc_rqst *rqstp, st
+ return 0;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
+ struct nfsd4_open *open)
+ {
+@@ -1623,22 +1619,22 @@ nfsd4_truncate(struct svc_rqst *rqstp, s
+ return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
+ }
+
+-static int
++static __be32
+ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
+ {
+ struct file *filp = stp->st_vfs_file;
+ struct inode *inode = filp->f_dentry->d_inode;
+ unsigned int share_access, new_writer;
+- int status;
++ __be32 status;
+
+ set_access(&share_access, stp->st_access_bmap);
+ new_writer = (~share_access) & open->op_share_access
+ & NFS4_SHARE_ACCESS_WRITE;
+
+ if (new_writer) {
+- status = get_write_access(inode);
+- if (status)
+- return nfserrno(status);
++ int err = get_write_access(inode);
++ if (err)
++ return nfserrno(err);
+ }
+ status = nfsd4_truncate(rqstp, cur_fh, open);
+ if (status) {
+@@ -1742,14 +1738,14 @@ out:
+ /*
+ * called with nfs4_lock_state() held.
+ */
+-int
++__be32
+ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+ {
+ 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;
++ __be32 status;
+
+ status = nfserr_inval;
+ if (!access_valid(open->op_share_access)
+@@ -1837,11 +1833,11 @@ static struct work_struct laundromat_wor
+ static void laundromat_main(void *);
+ static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
+
+-int
++__be32
+ nfsd4_renew(clientid_t *clid)
+ {
+ struct nfs4_client *clp;
+- int status;
++ __be32 status;
+
+ nfs4_lock_state();
+ dprintk("process_renew(%08x/%08x): starting\n",
+@@ -2000,9 +1996,9 @@ access_permit_write(unsigned long access
+ }
+
+ static
+-int nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
++__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
+ {
+- int status = nfserr_openmode;
++ __be32 status = nfserr_openmode;
+
+ if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
+ goto out;
+@@ -2013,7 +2009,7 @@ out:
+ return status;
+ }
+
+-static inline int
++static inline __be32
+ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
+ {
+ /* Trying to call delegreturn with a special stateid? Yuch: */
+@@ -2047,14 +2043,14 @@ io_during_grace_disallowed(struct inode
+ /*
+ * Checks for stateid operations
+ */
+-int
++__be32
+ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp)
+ {
+ struct nfs4_stateid *stp = NULL;
+ struct nfs4_delegation *dp = NULL;
+ stateid_t *stidp;
+ struct inode *ino = current_fh->fh_dentry->d_inode;
+- int status;
++ __be32 status;
+
+ dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
+ stateid->si_boot, stateid->si_stateownerid,
+@@ -2129,7 +2125,7 @@ setlkflg (int type)
+ /*
+ * Checks for sequence id mutating operations.
+ */
+-static int
++static __be32
+ 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)
+ {
+ struct nfs4_stateid *stp;
+@@ -2173,7 +2169,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *
+ clientid_t *lockclid = &lock->v.new.clientid;
+ struct nfs4_client *clp = sop->so_client;
+ int lkflg = 0;
+- int status;
++ __be32 status;
+
+ lkflg = setlkflg(lock->lk_type);
+
+@@ -2237,7 +2233,7 @@ check_replay:
+ if (seqid == sop->so_seqid - 1) {
+ dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
+ /* indicate replay to calling function */
+- return NFSERR_REPLAY_ME;
++ return nfserr_replay_me;
+ }
+ printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+ sop->so_seqid, seqid);
+@@ -2245,10 +2241,10 @@ check_replay:
+ return nfserr_bad_seqid;
+ }
+
+-int
++__be32
+ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
+ {
+- int status;
++ __be32 status;
+ struct nfs4_stateowner *sop;
+ struct nfs4_stateid *stp;
+
+@@ -2314,10 +2310,10 @@ reset_union_bmap_deny(unsigned long deny
+ }
+ }
+
+-int
++__be32
+ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
+ {
+- int status;
++ __be32 status;
+ struct nfs4_stateid *stp;
+ unsigned int share_access;
+
+@@ -2369,10 +2365,10 @@ out:
+ /*
+ * nfs4_unlock_state() called after encode
+ */
+-int
++__be32
+ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
+ {
+- int status;
++ __be32 status;
+ struct nfs4_stateid *stp;
+
+ dprintk("NFSD: nfsd4_close on file %.*s\n",
+@@ -2408,10 +2404,10 @@ out:
+ return status;
+ }
+
+-int
++__be32
+ nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr)
+ {
+- int status;
++ __be32 status;
+
+ if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
+ goto out;
+@@ -2639,7 +2635,7 @@ check_lock_length(u64 offset, u64 length
+ /*
+ * LOCK operation
+ */
+-int
++__be32
+ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
+ {
+ struct nfs4_stateowner *open_sop = NULL;
+@@ -2648,8 +2644,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
+ struct file *filp;
+ struct file_lock file_lock;
+ struct file_lock conflock;
+- int status = 0;
++ __be32 status = 0;
+ unsigned int strhashval;
++ int err;
+
+ dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
+ (long long) lock->lk_offset,
+@@ -2762,13 +2759,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
+ * locks_copy_lock: */
+ conflock.fl_ops = NULL;
+ conflock.fl_lmops = NULL;
+- status = posix_lock_file_conf(filp, &file_lock, &conflock);
++ err = posix_lock_file_conf(filp, &file_lock, &conflock);
+ dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status);
+- switch (-status) {
++ switch (-err) {
+ case 0: /* success! */
+ update_stateid(&lock_stp->st_stateid);
+ memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid,
+ sizeof(stateid_t));
++ status = 0;
+ break;
+ case (EAGAIN): /* conflock holds conflicting lock */
+ status = nfserr_denied;
+@@ -2779,7 +2777,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
+ status = nfserr_deadlock;
+ break;
+ default:
+- dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",status);
++ dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err);
+ status = nfserr_resource;
+ break;
+ }
+@@ -2797,14 +2795,14 @@ out:
+ /*
+ * LOCKT operation
+ */
+-int
++__be32
+ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt)
+ {
+ struct inode *inode;
+ struct file file;
+ struct file_lock file_lock;
+ struct file_lock conflock;
+- int status;
++ __be32 status;
+
+ if (nfs4_in_grace())
+ return nfserr_grace;
+@@ -2877,13 +2875,14 @@ out:
+ return status;
+ }
+
+-int
++__be32
+ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
+ {
+ struct nfs4_stateid *stp;
+ struct file *filp = NULL;
+ struct file_lock file_lock;
+- int status;
++ __be32 status;
++ int err;
+
+ dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
+ (long long) locku->lu_offset,
+@@ -2921,8 +2920,8 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
+ /*
+ * Try to unlock the file in the VFS.
+ */
+- status = posix_lock_file(filp, &file_lock);
+- if (status) {
++ err = posix_lock_file(filp, &file_lock);
++ if (err) {
+ dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+ goto out_nfserr;
+ }
+@@ -2941,7 +2940,7 @@ out:
+ return status;
+
+ out_nfserr:
+- status = nfserrno(status);
++ status = nfserrno(err);
+ goto out;
+ }
+
+@@ -2969,7 +2968,7 @@ out:
+ return status;
+ }
+
+-int
++__be32
+ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
+ {
+ clientid_t *clid = &rlockowner->rl_clientid;
+@@ -2978,7 +2977,7 @@ nfsd4_release_lockowner(struct svc_rqst
+ struct xdr_netobj *owner = &rlockowner->rl_owner;
+ struct list_head matches;
+ int i;
+- int status;
++ __be32 status;
+
+ dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
+ clid->cl_boot, clid->cl_id);
+@@ -3115,7 +3114,7 @@ nfs4_find_reclaim_client(clientid_t *cli
+ /*
+ * Called from OPEN. Look for clientid in reclaim list.
+ */
+-int
++__be32
+ nfs4_check_open_reclaim(clientid_t *clid)
+ {
+ return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
+diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
+index 5446a08..f3f239d 100644
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -60,8 +60,16 @@
+
+ #define NFSDDBG_FACILITY NFSDDBG_XDR
+
+-static int
+-check_filename(char *str, int len, int err)
++/*
++ * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
++ * directory in order to indicate to the client that a filesystem boundary is present
++ * We use a fixed fsid for a referral
++ */
++#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
++#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
++
++static __be32
++check_filename(char *str, int len, __be32 err)
+ {
+ int i;
+
+@@ -86,8 +94,8 @@ check_filename(char *str, int len, int e
+ * consistent with the style used in NFSv2/v3...
+ */
+ #define DECODE_HEAD \
+- u32 *p; \
+- int status
++ __be32 *p; \
++ __be32 status
+ #define DECODE_TAIL \
+ status = 0; \
+ out: \
+@@ -136,13 +144,13 @@ xdr_error: \
+ } \
+ } while (0)
+
+-static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
++static __be32 *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
+ */
+ int avail = (char*)argp->end - (char*)argp->p;
+- u32 *p;
++ __be32 *p;
+ if (avail + argp->pagelen < nbytes)
+ return NULL;
+ if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
+@@ -189,7 +197,7 @@ defer_free(struct nfsd4_compoundargs *ar
+ return 0;
+ }
+
+-static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
++static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
+ {
+ void *new = NULL;
+ if (p == argp->tmp) {
+@@ -198,8 +206,7 @@ static char *savemem(struct nfsd4_compou
+ p = new;
+ memcpy(p, argp->tmp, nbytes);
+ } else {
+- if (p != argp->tmpp)
+- BUG();
++ BUG_ON(p != argp->tmpp);
+ argp->tmpp = NULL;
+ }
+ if (defer_free(argp, kfree, p)) {
+@@ -210,7 +217,7 @@ static char *savemem(struct nfsd4_compou
+ }
+
+
+-static int
++static __be32
+ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
+ {
+ u32 bmlen;
+@@ -233,13 +240,14 @@ nfsd4_decode_bitmap(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
+ struct nfs4_acl **acl)
+ {
+ int expected_len, len = 0;
+ u32 dummy32;
+ char *buf;
++ int host_err;
+
+ DECODE_HEAD;
+ iattr->ia_valid = 0;
+@@ -273,7 +281,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
+
+ *acl = nfs4_acl_new();
+ if (*acl == NULL) {
+- status = -ENOMEM;
++ host_err = -ENOMEM;
+ goto out_nfserr;
+ }
+ defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
+@@ -288,20 +296,20 @@ nfsd4_decode_fattr(struct nfsd4_compound
+ len += XDR_QUADLEN(dummy32) << 2;
+ READMEM(buf, dummy32);
+ ace.whotype = nfs4_acl_get_whotype(buf, dummy32);
+- status = 0;
++ host_err = 0;
+ if (ace.whotype != NFS4_ACL_WHO_NAMED)
+ ace.who = 0;
+ else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP)
+- status = nfsd_map_name_to_gid(argp->rqstp,
++ host_err = nfsd_map_name_to_gid(argp->rqstp,
+ buf, dummy32, &ace.who);
+ else
+- status = nfsd_map_name_to_uid(argp->rqstp,
++ host_err = nfsd_map_name_to_uid(argp->rqstp,
+ buf, dummy32, &ace.who);
+- if (status)
++ if (host_err)
+ goto out_nfserr;
+- status = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
++ host_err = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
+ ace.access_mask, ace.whotype, ace.who);
+- if (status)
++ if (host_err)
+ goto out_nfserr;
+ }
+ } else
+@@ -320,7 +328,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ READMEM(buf, dummy32);
+- if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
++ if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
+ goto out_nfserr;
+ iattr->ia_valid |= ATTR_UID;
+ }
+@@ -331,7 +339,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ READMEM(buf, dummy32);
+- if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
++ if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
+ goto out_nfserr;
+ iattr->ia_valid |= ATTR_GID;
+ }
+@@ -407,11 +415,11 @@ nfsd4_decode_fattr(struct nfsd4_compound
+ DECODE_TAIL;
+
+ out_nfserr:
+- status = nfserrno(status);
++ status = nfserrno(host_err);
+ goto out;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
+ {
+ DECODE_HEAD;
+@@ -422,7 +430,7 @@ nfsd4_decode_access(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
+ {
+ DECODE_HEAD;
+@@ -437,7 +445,7 @@ nfsd4_decode_close(struct nfsd4_compound
+ }
+
+
+-static int
++static __be32
+ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
+ {
+ DECODE_HEAD;
+@@ -449,7 +457,7 @@ nfsd4_decode_commit(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
+ {
+ DECODE_HEAD;
+@@ -489,7 +497,7 @@ nfsd4_decode_create(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
+ {
+ DECODE_HEAD;
+@@ -501,13 +509,13 @@ nfsd4_decode_delegreturn(struct nfsd4_co
+ DECODE_TAIL;
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
+ {
+ return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
+ }
+
+-static int
++static __be32
+ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
+ {
+ DECODE_HEAD;
+@@ -522,7 +530,7 @@ nfsd4_decode_link(struct nfsd4_compounda
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
+ {
+ DECODE_HEAD;
+@@ -561,7 +569,7 @@ nfsd4_decode_lock(struct nfsd4_compounda
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
+ {
+ DECODE_HEAD;
+@@ -580,7 +588,7 @@ nfsd4_decode_lockt(struct nfsd4_compound
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
+ {
+ DECODE_HEAD;
+@@ -599,7 +607,7 @@ nfsd4_decode_locku(struct nfsd4_compound
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
+ {
+ DECODE_HEAD;
+@@ -614,7 +622,7 @@ nfsd4_decode_lookup(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
+ {
+ DECODE_HEAD;
+@@ -692,7 +700,7 @@ nfsd4_decode_open(struct nfsd4_compounda
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
+ {
+ DECODE_HEAD;
+@@ -706,7 +714,7 @@ nfsd4_decode_open_confirm(struct nfsd4_c
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
+ {
+ DECODE_HEAD;
+@@ -722,7 +730,7 @@ nfsd4_decode_open_downgrade(struct nfsd4
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
+ {
+ DECODE_HEAD;
+@@ -737,7 +745,7 @@ nfsd4_decode_putfh(struct nfsd4_compound
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
+ {
+ DECODE_HEAD;
+@@ -751,7 +759,7 @@ nfsd4_decode_read(struct nfsd4_compounda
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
+ {
+ DECODE_HEAD;
+@@ -767,7 +775,7 @@ nfsd4_decode_readdir(struct nfsd4_compou
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
+ {
+ DECODE_HEAD;
+@@ -782,7 +790,7 @@ nfsd4_decode_remove(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
+ {
+ DECODE_HEAD;
+@@ -802,7 +810,7 @@ nfsd4_decode_rename(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
+ {
+ DECODE_HEAD;
+@@ -813,7 +821,7 @@ nfsd4_decode_renew(struct nfsd4_compound
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
+ {
+ DECODE_HEAD;
+@@ -827,7 +835,7 @@ nfsd4_decode_setattr(struct nfsd4_compou
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
+ {
+ DECODE_HEAD;
+@@ -852,7 +860,7 @@ nfsd4_decode_setclientid(struct nfsd4_co
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
+ {
+ DECODE_HEAD;
+@@ -865,7 +873,7 @@ nfsd4_decode_setclientid_confirm(struct
+ }
+
+ /* Also used for NVERIFY */
+-static int
++static __be32
+ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
+ {
+ #if 0
+@@ -901,7 +909,7 @@ nfsd4_decode_verify(struct nfsd4_compoun
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
+ {
+ int avail;
+@@ -927,32 +935,32 @@ nfsd4_decode_write(struct nfsd4_compound
+ printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);
+ goto xdr_error;
+ }
+- write->wr_vec[0].iov_base = p;
+- write->wr_vec[0].iov_len = avail;
++ argp->rqstp->rq_vec[0].iov_base = p;
++ argp->rqstp->rq_vec[0].iov_len = avail;
+ v = 0;
+ len = write->wr_buflen;
+- while (len > write->wr_vec[v].iov_len) {
+- len -= write->wr_vec[v].iov_len;
++ while (len > argp->rqstp->rq_vec[v].iov_len) {
++ len -= argp->rqstp->rq_vec[v].iov_len;
+ v++;
+- write->wr_vec[v].iov_base = page_address(argp->pagelist[0]);
++ argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
+ argp->pagelist++;
+ if (argp->pagelen >= PAGE_SIZE) {
+- write->wr_vec[v].iov_len = PAGE_SIZE;
++ argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
+ argp->pagelen -= PAGE_SIZE;
+ } else {
+- write->wr_vec[v].iov_len = argp->pagelen;
++ argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
+ argp->pagelen -= len;
+ }
+ }
+- argp->end = (u32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len);
+- argp->p = (u32*) (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
+- write->wr_vec[v].iov_len = len;
++ argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
++ argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
++ argp->rqstp->rq_vec[v].iov_len = len;
+ write->wr_vlen = v+1;
+
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
+ {
+ DECODE_HEAD;
+@@ -966,7 +974,7 @@ nfsd4_decode_release_lockowner(struct nf
+ DECODE_TAIL;
+ }
+
+-static int
++static __be32
+ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
+ {
+ DECODE_HEAD;
+@@ -1172,7 +1180,7 @@ nfsd4_decode_compound(struct nfsd4_compo
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+-#define ENCODE_HEAD u32 *p
++#define ENCODE_HEAD __be32 *p
+
+ #define WRITE32(n) *p++ = htonl(n)
+ #define WRITE64(n) do { \
+@@ -1202,8 +1210,8 @@ nfsd4_decode_compound(struct nfsd4_compo
+ * Header routine to setup seqid operation replay cache
+ */
+ #define ENCODE_SEQID_OP_HEAD \
+- u32 *p; \
+- u32 *save; \
++ __be32 *p; \
++ __be32 *save; \
+ \
+ save = resp->p;
+
+@@ -1224,6 +1232,120 @@ nfsd4_decode_compound(struct nfsd4_compo
+ stateowner->so_replay.rp_buflen); \
+ } } while (0);
+
++/* Encode as an array of strings the string given with components
++ * seperated @sep.
++ */
++static __be32 nfsd4_encode_components(char sep, char *components,
++ __be32 **pp, int *buflen)
++{
++ __be32 *p = *pp;
++ __be32 *countp = p;
++ int strlen, count=0;
++ char *str, *end;
++
++ dprintk("nfsd4_encode_components(%s)\n", components);
++ if ((*buflen -= 4) < 0)
++ return nfserr_resource;
++ WRITE32(0); /* We will fill this in with @count later */
++ end = str = components;
++ while (*end) {
++ for (; *end && (*end != sep); end++)
++ ; /* Point to end of component */
++ strlen = end - str;
++ if (strlen) {
++ if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
++ return nfserr_resource;
++ WRITE32(strlen);
++ WRITEMEM(str, strlen);
++ count++;
++ }
++ else
++ end++;
++ str = end;
++ }
++ *pp = p;
++ p = countp;
++ WRITE32(count);
++ return 0;
++}
++
++/*
++ * encode a location element of a fs_locations structure
++ */
++static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
++ __be32 **pp, int *buflen)
++{
++ __be32 status;
++ __be32 *p = *pp;
++
++ status = nfsd4_encode_components(':', location->hosts, &p, buflen);
++ if (status)
++ return status;
++ status = nfsd4_encode_components('/', location->path, &p, buflen);
++ if (status)
++ return status;
++ *pp = p;
++ return 0;
++}
++
++/*
++ * Return the path to an export point in the pseudo filesystem namespace
++ * Returned string is safe to use as long as the caller holds a reference
++ * to @exp.
++ */
++static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
++{
++ struct svc_fh tmp_fh;
++ char *path, *rootpath;
++
++ fh_init(&tmp_fh, NFS4_FHSIZE);
++ *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
++ if (*stat)
++ return NULL;
++ rootpath = tmp_fh.fh_export->ex_path;
++
++ path = exp->ex_path;
++
++ if (strncmp(path, rootpath, strlen(rootpath))) {
++ printk("nfsd: fs_locations failed;"
++ "%s is not contained in %s\n", path, rootpath);
++ *stat = nfserr_notsupp;
++ return NULL;
++ }
++
++ return path + strlen(rootpath);
++}
++
++/*
++ * encode a fs_locations structure
++ */
++static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
++ struct svc_export *exp,
++ __be32 **pp, int *buflen)
++{
++ __be32 status;
++ int i;
++ __be32 *p = *pp;
++ struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
++ char *root = nfsd4_path(rqstp, exp, &status);
++
++ if (status)
++ return status;
++ status = nfsd4_encode_components('/', root, &p, buflen);
++ if (status)
++ return status;
++ if ((*buflen -= 4) < 0)
++ return nfserr_resource;
++ WRITE32(fslocs->locations_count);
++ for (i=0; i<fslocs->locations_count; i++) {
++ status = nfsd4_encode_fs_location4(&fslocs->locations[i],
++ &p, buflen);
++ if (status)
++ return status;
++ }
++ *pp = p;
++ return 0;
++}
+
+ static u32 nfs4_ftypes[16] = {
+ NF4BAD, NF4FIFO, NF4CHR, NF4BAD,
+@@ -1232,9 +1354,9 @@ static u32 nfs4_ftypes[16] = {
+ NF4SOCK, NF4BAD, NF4LNK, NF4BAD,
+ };
+
+-static int
++static __be32
+ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
+- u32 **p, int *buflen)
++ __be32 **p, int *buflen)
+ {
+ int status;
+
+@@ -1254,25 +1376,44 @@ nfsd4_encode_name(struct svc_rqst *rqstp
+ return 0;
+ }
+
+-static inline int
+-nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen)
++static inline __be32
++nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen)
+ {
+ return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
+ }
+
+-static inline int
+-nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen)
++static inline __be32
++nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen)
+ {
+ return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
+ }
+
+-static inline int
++static inline __be32
+ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
+- u32 **p, int *buflen)
++ __be32 **p, int *buflen)
+ {
+ return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
+ }
+
++#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
++ FATTR4_WORD0_RDATTR_ERROR)
++#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
++
++static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
++{
++ /* As per referral draft: */
++ if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
++ *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
++ if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
++ *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
++ *rdattr_err = NFSERR_MOVED;
++ else
++ return nfserr_moved;
++ }
++ *bmval0 &= WORD0_ABSENT_FS_ATTRS;
++ *bmval1 &= WORD1_ABSENT_FS_ATTRS;
++ return 0;
++}
+
+ /*
+ * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
+@@ -1281,9 +1422,9 @@ nfsd4_encode_aclname(struct svc_rqst *rq
+ * @countp is the buffer size in _words_; upon successful return this becomes
+ * replaced with the number of words written.
+ */
+-int
++__be32
+ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+- struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval,
++ struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
+ struct svc_rqst *rqstp)
+ {
+ u32 bmval0 = bmval[0];
+@@ -1292,11 +1433,13 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
+ struct svc_fh tempfh;
+ struct kstatfs statfs;
+ int buflen = *countp << 2;
+- u32 *attrlenp;
++ __be32 *attrlenp;
+ u32 dummy;
+ u64 dummy64;
+- u32 *p = buffer;
+- int status;
++ u32 rdattr_err = 0;
++ __be32 *p = buffer;
++ __be32 status;
++ int err;
+ int aclsupport = 0;
+ struct nfs4_acl *acl = NULL;
+
+@@ -1304,14 +1447,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
+ BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
+ BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
+
+- status = vfs_getattr(exp->ex_mnt, dentry, &stat);
+- if (status)
++ if (exp->ex_fslocs.migrated) {
++ status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
++ if (status)
++ goto out;
++ }
++
++ err = vfs_getattr(exp->ex_mnt, dentry, &stat);
++ if (err)
+ goto out_nfserr;
+ if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
+ (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
+ FATTR4_WORD1_SPACE_TOTAL))) {
+- status = vfs_statfs(dentry, &statfs);
+- if (status)
++ err = vfs_statfs(dentry, &statfs);
++ if (err)
+ goto out_nfserr;
+ }
+ if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
+@@ -1323,18 +1472,23 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
+ }
+ if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
+ | FATTR4_WORD0_SUPPORTED_ATTRS)) {
+- status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
+- aclsupport = (status == 0);
++ err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
++ aclsupport = (err == 0);
+ if (bmval0 & FATTR4_WORD0_ACL) {
+- if (status == -EOPNOTSUPP)
++ if (err == -EOPNOTSUPP)
+ bmval0 &= ~FATTR4_WORD0_ACL;
+- else if (status == -EINVAL) {
++ else if (err == -EINVAL) {
+ status = nfserr_attrnotsupp;
+ goto out;
+- } else if (status != 0)
++ } else if (err != 0)
+ goto out_nfserr;
+ }
+ }
++ if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
++ if (exp->ex_fslocs.locations == NULL) {
++ bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
++ }
++ }
+ if ((buflen -= 16) < 0)
+ goto out_resource;
+
+@@ -1344,12 +1498,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
+ attrlenp = p++; /* to be backfilled later */
+
+ if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
++ u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
+ if ((buflen -= 12) < 0)
+ goto out_resource;
++ if (!aclsupport)
++ word0 &= ~FATTR4_WORD0_ACL;
++ if (!exp->ex_fslocs.locations)
++ word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
+ WRITE32(2);
+- WRITE32(aclsupport ?
+- NFSD_SUPPORTED_ATTRS_WORD0 :
+- NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL);
++ WRITE32(word0);
+ WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
+ }
+ if (bmval0 & FATTR4_WORD0_TYPE) {
+@@ -1403,7 +1560,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
+ if (bmval0 & FATTR4_WORD0_FSID) {
+ if ((buflen -= 16) < 0)
+ goto out_resource;
+- if (is_fsid(fhp, rqstp->rq_reffh)) {
++ if (exp->ex_fslocs.migrated) {
++ WRITE64(NFS4_REFERRAL_FSID_MAJOR);
++ WRITE64(NFS4_REFERRAL_FSID_MINOR);
++ } else if (is_fsid(fhp, rqstp->rq_reffh)) {
+ WRITE64((u64)exp->ex_fsid);
+ WRITE64((u64)0);
+ } else {
+@@ -1426,7 +1586,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
+ if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
+ if ((buflen -= 4) < 0)
+ goto out_resource;
+- WRITE32(0);
++ WRITE32(rdattr_err);
+ }
+ if (bmval0 & FATTR4_WORD0_ACL) {
+ struct nfs4_ace *ace;
+@@ -1514,6 +1674,13 @@ out_acl:
+ goto out_resource;
+ WRITE64((u64) statfs.f_files);
+ }
++ if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
++ status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
++ if (status == nfserr_resource)
++ goto out_resource;
++ if (status)
++ goto out;
++ }
+ if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
+ if ((buflen -= 4) < 0)
+ goto out_resource;
+@@ -1537,12 +1704,12 @@ out_acl:
+ if (bmval0 & FATTR4_WORD0_MAXREAD) {
+ if ((buflen -= 8) < 0)
+ goto out_resource;
+- WRITE64((u64) NFSSVC_MAXBLKSIZE);
++ WRITE64((u64) svc_max_payload(rqstp));
+ }
+ if (bmval0 & FATTR4_WORD0_MAXWRITE) {
+ if ((buflen -= 8) < 0)
+ goto out_resource;
+- WRITE64((u64) NFSSVC_MAXBLKSIZE);
++ WRITE64((u64) svc_max_payload(rqstp));
+ }
+ if (bmval1 & FATTR4_WORD1_MODE) {
+ if ((buflen -= 4) < 0)
+@@ -1653,7 +1820,7 @@ out:
+ fh_put(&tempfh);
+ return status;
+ out_nfserr:
+- status = nfserrno(status);
++ status = nfserrno(err);
+ goto out;
+ out_resource:
+ *countp = 0;
+@@ -1664,13 +1831,13 @@ out_serverfault:
+ goto out;
+ }
+
+-static int
++static __be32
+ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
+- const char *name, int namlen, u32 *p, int *buflen)
++ const char *name, int namlen, __be32 *p, int *buflen)
+ {
+ struct svc_export *exp = cd->rd_fhp->fh_export;
+ struct dentry *dentry;
+- int nfserr;
++ __be32 nfserr;
+
+ dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
+ if (IS_ERR(dentry))
+@@ -1699,10 +1866,10 @@ out_put:
+ return nfserr;
+ }
+
+-static u32 *
+-nfsd4_encode_rdattr_error(u32 *p, int buflen, int nfserr)
++static __be32 *
++nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
+ {
+- u32 *attrlenp;
++ __be32 *attrlenp;
+
+ if (buflen < 6)
+ return NULL;
+@@ -1722,8 +1889,8 @@ nfsd4_encode_dirent(struct readdir_cd *c
+ {
+ struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
+ int buflen;
+- u32 *p = cd->buffer;
+- int nfserr = nfserr_toosmall;
++ __be32 *p = cd->buffer;
++ __be32 nfserr = nfserr_toosmall;
+
+ /* In nfsv4, "." and ".." never make it onto the wire.. */
+ if (name && isdotent(name, namlen)) {
+@@ -1779,7 +1946,7 @@ fail:
+ }
+
+ static void
+-nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_access *access)
++nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
+ {
+ ENCODE_HEAD;
+
+@@ -1792,7 +1959,7 @@ nfsd4_encode_access(struct nfsd4_compoun
+ }
+
+ static void
+-nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_close *close)
++nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
+ {
+ ENCODE_SEQID_OP_HEAD;
+
+@@ -1807,7 +1974,7 @@ nfsd4_encode_close(struct nfsd4_compound
+
+
+ static void
+-nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_commit *commit)
++nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
+ {
+ ENCODE_HEAD;
+
+@@ -1819,7 +1986,7 @@ nfsd4_encode_commit(struct nfsd4_compoun
+ }
+
+ static void
+-nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_create *create)
++nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
+ {
+ ENCODE_HEAD;
+
+@@ -1833,8 +2000,8 @@ nfsd4_encode_create(struct nfsd4_compoun
+ }
+ }
+
+-static int
+-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_getattr *getattr)
++static __be32
++nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
+ {
+ struct svc_fh *fhp = getattr->ga_fhp;
+ int buflen;
+@@ -1846,14 +2013,13 @@ nfsd4_encode_getattr(struct nfsd4_compou
+ nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
+ resp->p, &buflen, getattr->ga_bmval,
+ resp->rqstp);
+-
+ if (!nfserr)
+ resp->p += buflen;
+ return nfserr;
+ }
+
+ static void
+-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fhp)
++nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp)
+ {
+ unsigned int len;
+ ENCODE_HEAD;
+@@ -1893,7 +2059,7 @@ nfsd4_encode_lock_denied(struct nfsd4_co
+ }
+
+ static void
+-nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock)
++nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
+ {
+ ENCODE_SEQID_OP_HEAD;
+
+@@ -1909,14 +2075,14 @@ nfsd4_encode_lock(struct nfsd4_compoundr
+ }
+
+ static void
+-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lockt *lockt)
++nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
+ {
+ if (nfserr == nfserr_denied)
+ nfsd4_encode_lock_denied(resp, &lockt->lt_denied);
+ }
+
+ static void
+-nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_locku *locku)
++nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
+ {
+ ENCODE_SEQID_OP_HEAD;
+
+@@ -1932,7 +2098,7 @@ nfsd4_encode_locku(struct nfsd4_compound
+
+
+ static void
+-nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link)
++nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
+ {
+ ENCODE_HEAD;
+
+@@ -1945,7 +2111,7 @@ nfsd4_encode_link(struct nfsd4_compoundr
+
+
+ static void
+-nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open *open)
++nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
+ {
+ ENCODE_SEQID_OP_HEAD;
+
+@@ -2010,7 +2176,7 @@ out:
+ }
+
+ static void
+-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_confirm *oc)
++nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
+ {
+ ENCODE_SEQID_OP_HEAD;
+
+@@ -2025,7 +2191,7 @@ nfsd4_encode_open_confirm(struct nfsd4_c
+ }
+
+ static void
+-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od)
++nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
+ {
+ ENCODE_SEQID_OP_HEAD;
+
+@@ -2039,8 +2205,9 @@ nfsd4_encode_open_downgrade(struct nfsd4
+ ENCODE_SEQID_OP_TAIL(od->od_stateowner);
+ }
+
+-static int
+-nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
++static __be32
++nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
++ struct nfsd4_read *read)
+ {
+ u32 eof;
+ int v, pn;
+@@ -2055,31 +2222,33 @@ nfsd4_encode_read(struct nfsd4_compoundr
+
+ RESERVE_SPACE(8); /* eof flag and byte count */
+
+- maxcount = NFSSVC_MAXBLKSIZE;
++ maxcount = svc_max_payload(resp->rqstp);
+ if (maxcount > read->rd_length)
+ maxcount = read->rd_length;
+
+ len = maxcount;
+ v = 0;
+ while (len > 0) {
+- pn = resp->rqstp->rq_resused;
+- svc_take_page(resp->rqstp);
+- read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]);
+- read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE;
++ pn = resp->rqstp->rq_resused++;
++ resp->rqstp->rq_vec[v].iov_base =
++ page_address(resp->rqstp->rq_respages[pn]);
++ resp->rqstp->rq_vec[v].iov_len =
++ len < PAGE_SIZE ? len : PAGE_SIZE;
+ v++;
+ len -= PAGE_SIZE;
+ }
+ read->rd_vlen = v;
+
+ nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
+- read->rd_offset, read->rd_iov, read->rd_vlen,
++ read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
+ &maxcount);
+
+ if (nfserr == nfserr_symlink)
+ nfserr = nfserr_inval;
+ if (nfserr)
+ return nfserr;
+- eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
++ eof = (read->rd_offset + maxcount >=
++ read->rd_fhp->fh_dentry->d_inode->i_size);
+
+ WRITE32(eof);
+ WRITE32(maxcount);
+@@ -2089,7 +2258,6 @@ nfsd4_encode_read(struct nfsd4_compoundr
+ resp->xbuf->page_len = maxcount;
+
+ /* Use rest of head for padding and remaining ops: */
+- resp->rqstp->rq_restailpage = 0;
+ resp->xbuf->tail[0].iov_base = p;
+ resp->xbuf->tail[0].iov_len = 0;
+ if (maxcount&3) {
+@@ -2102,8 +2270,8 @@ nfsd4_encode_read(struct nfsd4_compoundr
+ return 0;
+ }
+
+-static int
+-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readlink *readlink)
++static __be32
++nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
+ {
+ int maxcount;
+ char *page;
+@@ -2114,8 +2282,7 @@ nfsd4_encode_readlink(struct nfsd4_compo
+ if (resp->xbuf->page_len)
+ return nfserr_resource;
+
+- svc_take_page(resp->rqstp);
+- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
++ page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
+
+ maxcount = PAGE_SIZE;
+ RESERVE_SPACE(4);
+@@ -2139,7 +2306,6 @@ nfsd4_encode_readlink(struct nfsd4_compo
+ resp->xbuf->page_len = maxcount;
+
+ /* Use rest of head for padding and remaining ops: */
+- resp->rqstp->rq_restailpage = 0;
+ resp->xbuf->tail[0].iov_base = p;
+ resp->xbuf->tail[0].iov_len = 0;
+ if (maxcount&3) {
+@@ -2152,12 +2318,12 @@ nfsd4_encode_readlink(struct nfsd4_compo
+ return 0;
+ }
+
+-static int
+-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir)
++static __be32
++nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
+ {
+ int maxcount;
+ loff_t offset;
+- u32 *page, *savep, *tailbase;
++ __be32 *page, *savep, *tailbase;
+ ENCODE_HEAD;
+
+ if (nfserr)
+@@ -2190,8 +2356,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
+ goto err_no_verf;
+ }
+
+- svc_take_page(resp->rqstp);
+- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
++ page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
+ readdir->common.err = 0;
+ readdir->buflen = maxcount;
+ readdir->buffer = page;
+@@ -2216,10 +2381,10 @@ nfsd4_encode_readdir(struct nfsd4_compou
+ p = readdir->buffer;
+ *p++ = 0; /* no more entries */
+ *p++ = htonl(readdir->common.err == nfserr_eof);
+- resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
++ resp->xbuf->page_len = ((char*)p) - (char*)page_address(
++ resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+
+ /* Use rest of head for padding and remaining ops: */
+- resp->rqstp->rq_restailpage = 0;
+ resp->xbuf->tail[0].iov_base = tailbase;
+ resp->xbuf->tail[0].iov_len = 0;
+ resp->p = resp->xbuf->tail[0].iov_base;
+@@ -2233,7 +2398,7 @@ err_no_verf:
+ }
+
+ static void
+-nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_remove *remove)
++nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
+ {
+ ENCODE_HEAD;
+
+@@ -2245,7 +2410,7 @@ nfsd4_encode_remove(struct nfsd4_compoun
+ }
+
+ static void
+-nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rename *rename)
++nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
+ {
+ ENCODE_HEAD;
+
+@@ -2262,7 +2427,7 @@ nfsd4_encode_rename(struct nfsd4_compoun
+ * regardless of the error status.
+ */
+ static void
+-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setattr *setattr)
++nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
+ {
+ ENCODE_HEAD;
+
+@@ -2281,7 +2446,7 @@ nfsd4_encode_setattr(struct nfsd4_compou
+ }
+
+ static void
+-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setclientid *scd)
++nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
+ {
+ ENCODE_HEAD;
+
+@@ -2300,7 +2465,7 @@ nfsd4_encode_setclientid(struct nfsd4_co
+ }
+
+ static void
+-nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_write *write)
++nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
+ {
+ ENCODE_HEAD;
+
+@@ -2316,7 +2481,7 @@ nfsd4_encode_write(struct nfsd4_compound
+ void
+ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
+ {
+- u32 *statp;
++ __be32 *statp;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8);
+@@ -2454,7 +2619,7 @@ nfsd4_encode_replay(struct nfsd4_compoun
+ */
+
+ int
+-nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_ressize_check(rqstp, p);
+ }
+@@ -2476,9 +2641,9 @@ void nfsd4_release_compoundargs(struct n
+ }
+
+ int
+-nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
++nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
+ {
+- int status;
++ __be32 status;
+
+ args->p = p;
+ args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
+@@ -2497,7 +2662,7 @@ nfs4svc_decode_compoundargs(struct svc_r
+ }
+
+ int
+-nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundres *resp)
++nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
+ {
+ /*
+ * All that remains is to write the tag and operation count...
+diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
+index fdf7cf3..6100bbe 100644
+--- a/fs/nfsd/nfscache.c
++++ b/fs/nfsd/nfscache.c
+@@ -29,7 +29,7 @@
+ */
+ #define CACHESIZE 1024
+ #define HASHSIZE 64
+-#define REQHASH(xid) ((((xid) >> 24) ^ (xid)) & (HASHSIZE-1))
++#define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1))
+
+ static struct hlist_head * hash_list;
+ static struct list_head lru_head;
+@@ -127,8 +127,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp
+ struct hlist_node *hn;
+ struct hlist_head *rh;
+ struct svc_cacherep *rp;
+- u32 xid = rqstp->rq_xid,
+- proto = rqstp->rq_prot,
++ __be32 xid = rqstp->rq_xid;
++ u32 proto = rqstp->rq_prot,
+ vers = rqstp->rq_vers,
+ proc = rqstp->rq_proc;
+ unsigned long age;
+@@ -258,7 +258,7 @@ found_entry:
+ * In this case, nfsd_cache_update is called with statp == NULL.
+ */
+ void
+-nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp)
++nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
+ {
+ struct svc_cacherep *rp;
+ struct kvec *resv = &rqstp->rq_res.head[0], *cachv;
+diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
+index 7046ac9..39aed90 100644
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -23,10 +23,14 @@
+ #include <linux/pagemap.h>
+ #include <linux/init.h>
+ #include <linux/string.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
+
+ #include <linux/nfs.h>
+ #include <linux/nfsd_idmap.h>
++#include <linux/lockd/bind.h>
+ #include <linux/sunrpc/svc.h>
++#include <linux/sunrpc/svcsock.h>
+ #include <linux/nfsd/nfsd.h>
+ #include <linux/nfsd/cache.h>
+ #include <linux/nfsd/xdr.h>
+@@ -35,8 +39,6 @@
+
+ #include <asm/uaccess.h>
+
+-unsigned int nfsd_versbits = ~0;
+-
+ /*
+ * We have a single directory with 9 nodes in it.
+ */
+@@ -52,7 +54,10 @@ enum {
+ NFSD_List,
+ NFSD_Fh,
+ NFSD_Threads,
++ NFSD_Pool_Threads,
+ NFSD_Versions,
++ NFSD_Ports,
++ NFSD_MaxBlkSize,
+ /*
+ * The below MUST come last. Otherwise we leave a hole in nfsd_files[]
+ * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
+@@ -75,7 +80,10 @@ static ssize_t write_getfd(struct file *
+ 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_pool_threads(struct file *file, char *buf, size_t size);
+ static ssize_t write_versions(struct file *file, char *buf, size_t size);
++static ssize_t write_ports(struct file *file, char *buf, size_t size);
++static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
+ #ifdef CONFIG_NFSD_V4
+ 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);
+@@ -91,7 +99,10 @@ static ssize_t (*write_op[])(struct file
+ [NFSD_Getfs] = write_getfs,
+ [NFSD_Fh] = write_filehandle,
+ [NFSD_Threads] = write_threads,
++ [NFSD_Pool_Threads] = write_pool_threads,
+ [NFSD_Versions] = write_versions,
++ [NFSD_Ports] = write_ports,
++ [NFSD_MaxBlkSize] = write_maxblksize,
+ #ifdef CONFIG_NFSD_V4
+ [NFSD_Leasetime] = write_leasetime,
+ [NFSD_RecoveryDir] = write_recoverydir,
+@@ -358,6 +369,72 @@ static ssize_t write_threads(struct file
+ return strlen(buf);
+ }
+
++extern int nfsd_nrpools(void);
++extern int nfsd_get_nrthreads(int n, int *);
++extern int nfsd_set_nrthreads(int n, int *);
++
++static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
++{
++ /* if size > 0, look for an array of number of threads per node
++ * and apply them then write out number of threads per node as reply
++ */
++ char *mesg = buf;
++ int i;
++ int rv;
++ int len;
++ int npools = nfsd_nrpools();
++ int *nthreads;
++
++ if (npools == 0) {
++ /*
++ * NFS is shut down. The admin can start it by
++ * writing to the threads file but NOT the pool_threads
++ * file, sorry. Report zero threads.
++ */
++ strcpy(buf, "0\n");
++ return strlen(buf);
++ }
++
++ nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
++ if (nthreads == NULL)
++ return -ENOMEM;
++
++ if (size > 0) {
++ for (i = 0; i < npools; i++) {
++ rv = get_int(&mesg, &nthreads[i]);
++ if (rv == -ENOENT)
++ break; /* fewer numbers than pools */
++ if (rv)
++ goto out_free; /* syntax error */
++ rv = -EINVAL;
++ if (nthreads[i] < 0)
++ goto out_free;
++ }
++ rv = nfsd_set_nrthreads(i, nthreads);
++ if (rv)
++ goto out_free;
++ }
++
++ rv = nfsd_get_nrthreads(npools, nthreads);
++ if (rv)
++ goto out_free;
++
++ mesg = buf;
++ size = SIMPLE_TRANSACTION_LIMIT;
++ for (i = 0; i < npools && size > 0; i++) {
++ snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
++ len = strlen(mesg);
++ size -= len;
++ mesg += len;
++ }
++
++ return (mesg-buf);
++
++out_free:
++ kfree(nthreads);
++ return rv;
++}
++
+ static ssize_t write_versions(struct file *file, char *buf, size_t size)
+ {
+ /*
+@@ -372,6 +449,10 @@ static ssize_t write_versions(struct fil
+
+ if (size>0) {
+ if (nfsd_serv)
++ /* Cannot change versions without updating
++ * nfsd_serv->sv_xdrsize, and reallocing
++ * rq_argp and rq_resp
++ */
+ return -EBUSY;
+ if (buf[size-1] != '\n')
+ return -EINVAL;
+@@ -390,10 +471,7 @@ static ssize_t write_versions(struct fil
+ case 2:
+ case 3:
+ case 4:
+- if (sign != '-')
+- NFSCTL_VERSET(nfsd_versbits, num);
+- else
+- NFSCTL_VERUNSET(nfsd_versbits, num);
++ nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
+ break;
+ default:
+ return -EINVAL;
+@@ -404,16 +482,15 @@ static ssize_t write_versions(struct fil
+ /* If all get turned off, turn them back on, as
+ * having no versions is BAD
+ */
+- if ((nfsd_versbits & NFSCTL_VERALL)==0)
+- nfsd_versbits = NFSCTL_VERALL;
++ nfsd_reset_versions();
+ }
+ /* Now write current state into reply buffer */
+ len = 0;
+ sep = "";
+ for (num=2 ; num <= 4 ; num++)
+- if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) {
++ if (nfsd_vers(num, NFSD_AVAIL)) {
+ len += sprintf(buf+len, "%s%c%d", sep,
+- NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-',
++ nfsd_vers(num, NFSD_TEST)?'+':'-',
+ num);
+ sep = " ";
+ }
+@@ -421,6 +498,95 @@ static ssize_t write_versions(struct fil
+ return len;
+ }
+
++static ssize_t write_ports(struct file *file, char *buf, size_t size)
++{
++ if (size == 0) {
++ int len = 0;
++ lock_kernel();
++ if (nfsd_serv)
++ len = svc_sock_names(buf, nfsd_serv, NULL);
++ unlock_kernel();
++ return len;
++ }
++ /* Either a single 'fd' number is written, in which
++ * case it must be for a socket of a supported family/protocol,
++ * and we use it as an nfsd socket, or
++ * A '-' followed by the 'name' of a socket in which case
++ * we close the socket.
++ */
++ if (isdigit(buf[0])) {
++ char *mesg = buf;
++ int fd;
++ int err;
++ err = get_int(&mesg, &fd);
++ if (err)
++ return -EINVAL;
++ if (fd < 0)
++ return -EINVAL;
++ err = nfsd_create_serv();
++ if (!err) {
++ int proto = 0;
++ err = svc_addsock(nfsd_serv, fd, buf, &proto);
++ if (err >= 0) {
++ err = lockd_up(proto);
++ if (err < 0)
++ svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
++ }
++ /* Decrease the count, but don't shutdown the
++ * the service
++ */
++ lock_kernel();
++ nfsd_serv->sv_nrthreads--;
++ unlock_kernel();
++ }
++ return err < 0 ? err : 0;
++ }
++ if (buf[0] == '-') {
++ char *toclose = kstrdup(buf+1, GFP_KERNEL);
++ int len = 0;
++ if (!toclose)
++ return -ENOMEM;
++ lock_kernel();
++ if (nfsd_serv)
++ len = svc_sock_names(buf, nfsd_serv, toclose);
++ unlock_kernel();
++ if (len >= 0)
++ lockd_down();
++ kfree(toclose);
++ return len;
++ }
++ return -EINVAL;
++}
++
++int nfsd_max_blksize;
++
++static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
++{
++ char *mesg = buf;
++ if (size > 0) {
++ int bsize;
++ int rv = get_int(&mesg, &bsize);
++ if (rv)
++ return rv;
++ /* force bsize into allowed range and
++ * required alignment.
++ */
++ if (bsize < 1024)
++ bsize = 1024;
++ if (bsize > NFSSVC_MAXBLKSIZE)
++ bsize = NFSSVC_MAXBLKSIZE;
++ bsize &= ~(1024-1);
++ lock_kernel();
++ if (nfsd_serv && nfsd_serv->sv_nrthreads) {
++ unlock_kernel();
++ return -EBUSY;
++ }
++ nfsd_max_blksize = bsize;
++ unlock_kernel();
++ }
++ return sprintf(buf, "%d\n", nfsd_max_blksize);
++}
++
+ #ifdef CONFIG_NFSD_V4
+ extern time_t nfs4_leasetime(void);
+
+@@ -483,7 +649,10 @@ static int nfsd_fill_super(struct super_
+ [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
+ [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
++ [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
++ [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
++ [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
+ #ifdef CONFIG_NFSD_V4
+ [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
+diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
+index 501d838..727ab3b 100644
+--- a/fs/nfsd/nfsfh.c
++++ b/fs/nfsd/nfsfh.c
+@@ -76,7 +76,7 @@ static int nfsd_acceptable(void *expv, s
+ * comment in the NFSv3 spec says this is incorrect (implementation notes for
+ * the write call).
+ */
+-static inline int
++static inline __be32
+ nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
+ {
+ /* Type can be negative when creating hardlinks - not to a dir */
+@@ -110,13 +110,13 @@ nfsd_mode_check(struct svc_rqst *rqstp,
+ * This is only called at the start of an nfsproc call, so fhp points to
+ * a svc_fh which is all 0 except for the over-the-wire file handle.
+ */
+-u32
++__be32
+ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
+ {
+ struct knfsd_fh *fh = &fhp->fh_handle;
+ struct svc_export *exp = NULL;
+ struct dentry *dentry;
+- u32 error = 0;
++ __be32 error = 0;
+
+ dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
+
+@@ -315,7 +315,7 @@ static inline void _fh_update_old(struct
+ fh->ofh_dirino = 0;
+ }
+
+-int
++__be32
+ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh)
+ {
+ /* ref_fh is a reference file handle.
+@@ -451,7 +451,7 @@ fh_compose(struct svc_fh *fhp, struct sv
+ * Update file handle information after changing a dentry.
+ * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
+ */
+-int
++__be32
+ fh_update(struct svc_fh *fhp)
+ {
+ struct dentry *dentry;
+diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
+index 06cd0db..ec983b7 100644
+--- a/fs/nfsd/nfsproc.c
++++ b/fs/nfsd/nfsproc.c
+@@ -30,22 +30,22 @@ typedef struct svc_buf svc_buf;
+ #define NFSDDBG_FACILITY NFSDDBG_PROC
+
+
+-static int
++static __be32
+ nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+ {
+ return nfs_ok;
+ }
+
+-static int
+-nfsd_return_attrs(int err, struct nfsd_attrstat *resp)
++static __be32
++nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
+ {
+ if (err) return err;
+ return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
+ resp->fh.fh_dentry,
+ &resp->stat));
+ }
+-static int
+-nfsd_return_dirop(int err, struct nfsd_diropres *resp)
++static __be32
++nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
+ {
+ if (err) return err;
+ return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
+@@ -56,11 +56,11 @@ nfsd_return_dirop(int err, struct nfsd_d
+ * Get a file's attributes
+ * N.B. After this call resp->fh needs an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
+ struct nfsd_attrstat *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+ dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
+
+ fh_copy(&resp->fh, &argp->fh);
+@@ -72,11 +72,11 @@ nfsd_proc_getattr(struct svc_rqst *rqstp
+ * Set a file's attributes
+ * N.B. After this call resp->fh needs an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
+ struct nfsd_attrstat *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+ dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
+ SVCFH_fmt(&argp->fh),
+ argp->attrs.ia_valid, (long) argp->attrs.ia_size);
+@@ -92,11 +92,11 @@ nfsd_proc_setattr(struct svc_rqst *rqstp
+ * doesn't exist yet.
+ * N.B. After this call resp->fh needs an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
+ struct nfsd_diropres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: LOOKUP %s %.*s\n",
+ SVCFH_fmt(&argp->fh), argp->len, argp->name);
+@@ -112,11 +112,11 @@ nfsd_proc_lookup(struct svc_rqst *rqstp,
+ /*
+ * Read a symlink.
+ */
+-static int
++static __be32
+ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
+ struct nfsd_readlinkres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
+
+@@ -132,11 +132,11 @@ nfsd_proc_readlink(struct svc_rqst *rqst
+ * Read a portion of a file.
+ * N.B. After this call resp->fh needs an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
+ struct nfsd_readres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: READ %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
+@@ -146,20 +146,20 @@ nfsd_proc_read(struct svc_rqst *rqstp, s
+ * status, 17 words for fattr, and 1 word for the byte count.
+ */
+
+- if (NFSSVC_MAXBLKSIZE < argp->count) {
++ if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
+ printk(KERN_NOTICE
+ "oversized read request from %u.%u.%u.%u:%d (%d bytes)\n",
+ NIPQUAD(rqstp->rq_addr.sin_addr.s_addr),
+ ntohs(rqstp->rq_addr.sin_port),
+ argp->count);
+- argp->count = NFSSVC_MAXBLKSIZE;
++ argp->count = NFSSVC_MAXBLKSIZE_V2;
+ }
+ svc_reserve(rqstp, (19<<2) + argp->count + 4);
+
+ resp->count = argp->count;
+ nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
+ argp->offset,
+- argp->vec, argp->vlen,
++ rqstp->rq_vec, argp->vlen,
+ &resp->count);
+
+ if (nfserr) return nfserr;
+@@ -172,11 +172,11 @@ nfsd_proc_read(struct svc_rqst *rqstp, s
+ * Write data to a file
+ * N.B. After this call resp->fh needs an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
+ struct nfsd_attrstat *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+ int stable = 1;
+
+ dprintk("nfsd: WRITE %s %d bytes at %d\n",
+@@ -185,7 +185,7 @@ nfsd_proc_write(struct svc_rqst *rqstp,
+
+ nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
+ argp->offset,
+- argp->vec, argp->vlen,
++ rqstp->rq_vec, argp->vlen,
+ argp->len,
+ &stable);
+ return nfsd_return_attrs(nfserr, resp);
+@@ -197,7 +197,7 @@ nfsd_proc_write(struct svc_rqst *rqstp,
+ * and the actual create() call in compliance with VFS protocols.
+ * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
+ struct nfsd_diropres *resp)
+ {
+@@ -206,7 +206,8 @@ nfsd_proc_create(struct svc_rqst *rqstp,
+ struct iattr *attr = &argp->attrs;
+ struct inode *inode;
+ struct dentry *dchild;
+- int nfserr, type, mode;
++ int type, mode;
++ __be32 nfserr;
+ dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
+
+ dprintk("nfsd: CREATE %s %.*s\n",
+@@ -225,7 +226,7 @@ nfsd_proc_create(struct svc_rqst *rqstp,
+ nfserr = nfserr_exist;
+ if (isdotent(argp->name, argp->len))
+ goto done;
+- fh_lock(dirfhp);
++ fh_lock_nested(dirfhp, I_MUTEX_PARENT);
+ dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
+ if (IS_ERR(dchild)) {
+ nfserr = nfserrno(PTR_ERR(dchild));
+@@ -348,11 +349,11 @@ done:
+ return nfsd_return_dirop(nfserr, resp);
+ }
+
+-static int
++static __be32
+ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
+ void *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
+ argp->len, argp->name);
+@@ -363,11 +364,11 @@ nfsd_proc_remove(struct svc_rqst *rqstp,
+ return nfserr;
+ }
+
+-static int
++static __be32
+ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
+ void *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: RENAME %s %.*s -> \n",
+ SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
+@@ -381,11 +382,11 @@ nfsd_proc_rename(struct svc_rqst *rqstp,
+ return nfserr;
+ }
+
+-static int
++static __be32
+ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
+ void *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: LINK %s ->\n",
+ SVCFH_fmt(&argp->ffh));
+@@ -401,12 +402,12 @@ nfsd_proc_link(struct svc_rqst *rqstp, s
+ return nfserr;
+ }
+
+-static int
++static __be32
+ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
+ void *resp)
+ {
+ struct svc_fh newfh;
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
+ SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
+@@ -430,11 +431,11 @@ nfsd_proc_symlink(struct svc_rqst *rqstp
+ * Make directory. This operation is not idempotent.
+ * N.B. After this call resp->fh needs an fh_put
+ */
+-static int
++static __be32
+ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
+ struct nfsd_diropres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
+
+@@ -454,11 +455,11 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp,
+ /*
+ * Remove a directory
+ */
+-static int
++static __be32
+ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
+ void *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
+
+@@ -470,11 +471,12 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp,
+ /*
+ * Read a portion of a directory.
+ */
+-static int
++static __be32
+ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
+ struct nfsd_readdirres *resp)
+ {
+- int nfserr, count;
++ int count;
++ __be32 nfserr;
+ loff_t offset;
+
+ dprintk("nfsd: READDIR %s %d bytes at %d\n",
+@@ -509,11 +511,11 @@ nfsd_proc_readdir(struct svc_rqst *rqstp
+ /*
+ * Get file system info
+ */
+-static int
++static __be32
+ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
+ struct nfsd_statfsres *resp)
+ {
+- int nfserr;
++ __be32 nfserr;
+
+ dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
+
+@@ -553,7 +555,7 @@ static struct svc_procedure nfsd_proced
+ PROC(none, void, void, none, RC_NOCACHE, ST),
+ PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT),
+ PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
+- PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4),
++ PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4),
+ PROC(none, void, void, none, RC_NOCACHE, ST),
+ PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT),
+ PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT),
+@@ -579,11 +581,11 @@ struct svc_version nfsd_version2 = {
+ /*
+ * Map errnos to NFS errnos.
+ */
+-int
++__be32
+ nfserrno (int errno)
+ {
+ static struct {
+- int nfserr;
++ __be32 nfserr;
+ int syserr;
+ } nfs_errtbl[] = {
+ { nfs_ok, 0 },
+@@ -615,11 +617,10 @@ nfserrno (int errno)
+ { nfserr_badname, -ESRCH },
+ { nfserr_io, -ETXTBSY },
+ { nfserr_notsupp, -EOPNOTSUPP },
+- { -1, -EIO }
+ };
+ int i;
+
+- for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
++ for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
+ if (nfs_errtbl[i].syserr == errno)
+ return nfs_errtbl[i].nfserr;
+ }
+diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
+index ec1decf..0aaccb0 100644
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -57,12 +57,6 @@ static atomic_t nfsd_busy;
+ static unsigned long nfsd_last_call;
+ static DEFINE_SPINLOCK(nfsd_call_lock);
+
+-struct nfsd_list {
+- struct list_head list;
+- struct task_struct *task;
+-};
+-static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
+-
+ #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+ static struct svc_stat nfsd_acl_svcstats;
+ static struct svc_version * nfsd_acl_version[] = {
+@@ -117,6 +111,32 @@ struct svc_program nfsd_program = {
+
+ };
+
++int nfsd_vers(int vers, enum vers_op change)
++{
++ if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
++ return -1;
++ switch(change) {
++ case NFSD_SET:
++ nfsd_versions[vers] = nfsd_version[vers];
++ break;
++#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
++ if (vers < NFSD_ACL_NRVERS)
++ nfsd_acl_version[vers] = nfsd_acl_version[vers];
++#endif
++ case NFSD_CLEAR:
++ nfsd_versions[vers] = NULL;
++#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
++ if (vers < NFSD_ACL_NRVERS)
++ nfsd_acl_version[vers] = NULL;
++#endif
++ break;
++ case NFSD_TEST:
++ return nfsd_versions[vers] != NULL;
++ case NFSD_AVAIL:
++ return nfsd_version[vers] != NULL;
++ }
++ return 0;
++}
+ /*
+ * Maximum number of nfsd processes
+ */
+@@ -130,16 +150,192 @@ int nfsd_nrthreads(void)
+ return nfsd_serv->sv_nrthreads;
+ }
+
++static int killsig; /* signal that was used to kill last nfsd */
++static void nfsd_last_thread(struct svc_serv *serv)
++{
++ /* When last nfsd thread exits we need to do some clean-up */
++ struct svc_sock *svsk;
++ list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
++ lockd_down();
++ nfsd_serv = NULL;
++ nfsd_racache_shutdown();
++ nfs4_state_shutdown();
++
++ printk(KERN_WARNING "nfsd: last server has exited\n");
++ if (killsig != SIG_NOCLEAN) {
++ printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
++ nfsd_export_flush();
++ }
++}
++
++void nfsd_reset_versions(void)
++{
++ int found_one = 0;
++ int i;
++
++ for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
++ if (nfsd_program.pg_vers[i])
++ found_one = 1;
++ }
++
++ if (!found_one) {
++ for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
++ nfsd_program.pg_vers[i] = nfsd_version[i];
++#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
++ for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
++ nfsd_acl_program.pg_vers[i] =
++ nfsd_acl_version[i];
++#endif
++ }
++}
++
++int nfsd_create_serv(void)
++{
++ int err = 0;
++ lock_kernel();
++ if (nfsd_serv) {
++ svc_get(nfsd_serv);
++ unlock_kernel();
++ return 0;
++ }
++ if (nfsd_max_blksize == 0) {
++ /* choose a suitable default */
++ struct sysinfo i;
++ si_meminfo(&i);
++ /* Aim for 1/4096 of memory per thread
++ * This gives 1MB on 4Gig machines
++ * But only uses 32K on 128M machines.
++ * Bottom out at 8K on 32M and smaller.
++ * Of course, this is only a default.
++ */
++ nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
++ i.totalram <<= PAGE_SHIFT - 12;
++ while (nfsd_max_blksize > i.totalram &&
++ nfsd_max_blksize >= 8*1024*2)
++ nfsd_max_blksize /= 2;
++ }
++
++ atomic_set(&nfsd_busy, 0);
++ nfsd_serv = svc_create_pooled(&nfsd_program,
++ nfsd_max_blksize,
++ nfsd_last_thread,
++ nfsd, SIG_NOCLEAN, THIS_MODULE);
++ if (nfsd_serv == NULL)
++ err = -ENOMEM;
++ unlock_kernel();
++ do_gettimeofday(&nfssvc_boot); /* record boot time */
++ return err;
++}
++
++static int nfsd_init_socks(int port)
++{
++ int error;
++ if (!list_empty(&nfsd_serv->sv_permsocks))
++ return 0;
++
++ error = lockd_up(IPPROTO_UDP);
++ if (error >= 0) {
++ error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
++ if (error < 0)
++ lockd_down();
++ }
++ if (error < 0)
++ return error;
++
++#ifdef CONFIG_NFSD_TCP
++ error = lockd_up(IPPROTO_TCP);
++ if (error >= 0) {
++ error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
++ if (error < 0)
++ lockd_down();
++ }
++ if (error < 0)
++ return error;
++#endif
++ return 0;
++}
++
++int nfsd_nrpools(void)
++{
++ if (nfsd_serv == NULL)
++ return 0;
++ else
++ return nfsd_serv->sv_nrpools;
++}
++
++int nfsd_get_nrthreads(int n, int *nthreads)
++{
++ int i = 0;
++
++ if (nfsd_serv != NULL) {
++ for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
++ nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
++ }
++
++ return 0;
++}
++
++int nfsd_set_nrthreads(int n, int *nthreads)
++{
++ int i = 0;
++ int tot = 0;
++ int err = 0;
++
++ if (nfsd_serv == NULL || n <= 0)
++ return 0;
++
++ if (n > nfsd_serv->sv_nrpools)
++ n = nfsd_serv->sv_nrpools;
++
++ /* enforce a global maximum number of threads */
++ tot = 0;
++ for (i = 0; i < n; i++) {
++ if (nthreads[i] > NFSD_MAXSERVS)
++ nthreads[i] = NFSD_MAXSERVS;
++ tot += nthreads[i];
++ }
++ if (tot > NFSD_MAXSERVS) {
++ /* total too large: scale down requested numbers */
++ for (i = 0; i < n && tot > 0; i++) {
++ int new = nthreads[i] * NFSD_MAXSERVS / tot;
++ tot -= (nthreads[i] - new);
++ nthreads[i] = new;
++ }
++ for (i = 0; i < n && tot > 0; i++) {
++ nthreads[i]--;
++ tot--;
++ }
++ }
++
++ /*
++ * There must always be a thread in pool 0; the admin
++ * can't shut down NFS completely using pool_threads.
++ */
++ if (nthreads[0] == 0)
++ nthreads[0] = 1;
++
++ /* apply the new numbers */
++ lock_kernel();
++ svc_get(nfsd_serv);
++ for (i = 0; i < n; i++) {
++ err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
++ nthreads[i]);
++ if (err)
++ break;
++ }
++ svc_destroy(nfsd_serv);
++ unlock_kernel();
++
++ return err;
++}
++
+ int
+ nfsd_svc(unsigned short port, int nrservs)
+ {
+ int error;
+- int none_left, found_one, i;
+- struct list_head *victim;
+
+ lock_kernel();
+- dprintk("nfsd: creating service: vers 0x%x\n",
+- nfsd_versbits);
++ dprintk("nfsd: creating service\n");
+ error = -EINVAL;
+ if (nrservs <= 0)
+ nrservs = 0;
+@@ -153,91 +349,20 @@ nfsd_svc(unsigned short port, int nrserv
+ error = nfs4_state_start();
+ if (error<0)
+ goto out;
+- if (!nfsd_serv) {
+- /*
+- * Use the nfsd_ctlbits to define which
+- * versions that will be advertised.
+- * If nfsd_ctlbits doesn't list any version,
+- * export them all.
+- */
+- found_one = 0;
+-
+- for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
+- if (NFSCTL_VERISSET(nfsd_versbits, i)) {
+- nfsd_program.pg_vers[i] = nfsd_version[i];
+- found_one = 1;
+- } else
+- nfsd_program.pg_vers[i] = NULL;
+- }
+
+- if (!found_one) {
+- for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
+- nfsd_program.pg_vers[i] = nfsd_version[i];
+- }
++ nfsd_reset_versions();
+
++ error = nfsd_create_serv();
+
+-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+- found_one = 0;
+-
+- for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
+- if (NFSCTL_VERISSET(nfsd_versbits, i)) {
+- nfsd_acl_program.pg_vers[i] =
+- nfsd_acl_version[i];
+- found_one = 1;
+- } else
+- nfsd_acl_program.pg_vers[i] = NULL;
+- }
+-
+- if (!found_one) {
+- for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
+- nfsd_acl_program.pg_vers[i] =
+- nfsd_acl_version[i];
+- }
+-#endif
+-
+- atomic_set(&nfsd_busy, 0);
+- error = -ENOMEM;
+- nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE);
+- if (nfsd_serv == NULL)
+- goto out;
+- error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
+- if (error < 0)
+- goto failure;
++ if (error)
++ goto out;
++ error = nfsd_init_socks(port);
++ if (error)
++ goto failure;
+
+-#ifdef CONFIG_NFSD_TCP
+- error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
+- if (error < 0)
+- goto failure;
+-#endif
+- do_gettimeofday(&nfssvc_boot); /* record boot time */
+- } else
+- nfsd_serv->sv_nrthreads++;
+- nrservs -= (nfsd_serv->sv_nrthreads-1);
+- while (nrservs > 0) {
+- nrservs--;
+- __module_get(THIS_MODULE);
+- error = svc_create_thread(nfsd, nfsd_serv);
+- if (error < 0) {
+- module_put(THIS_MODULE);
+- break;
+- }
+- }
+- victim = nfsd_list.next;
+- while (nrservs < 0 && victim != &nfsd_list) {
+- struct nfsd_list *nl =
+- list_entry(victim,struct nfsd_list, list);
+- victim = victim->next;
+- send_sig(SIG_NOCLEAN, nl->task, 1);
+- nrservs++;
+- }
++ error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
+ failure:
+- none_left = (nfsd_serv->sv_nrthreads == 1);
+ svc_destroy(nfsd_serv); /* Release server */
+- if (none_left) {
+- nfsd_serv = NULL;
+- nfsd_racache_shutdown();
+- nfs4_state_shutdown();
+- }
+ out:
+ unlock_kernel();
+ return error;
+@@ -270,10 +395,8 @@ update_thread_usage(int busy_threads)
+ static void
+ nfsd(struct svc_rqst *rqstp)
+ {
+- struct svc_serv *serv = rqstp->rq_server;
+ struct fs_struct *fsp;
+ int err;
+- struct nfsd_list me;
+ sigset_t shutdown_mask, allowed_mask;
+
+ /* Lock module and set up kernel thread */
+@@ -297,10 +420,7 @@ nfsd(struct svc_rqst *rqstp)
+
+ nfsdstats.th_cnt++;
+
+- lockd_up(); /* start lockd */
+-
+- me.task = current;
+- list_add(&me.list, &nfsd_list);
++ rqstp->rq_task = current;
+
+ unlock_kernel();
+
+@@ -322,8 +442,7 @@ nfsd(struct svc_rqst *rqstp)
+ * Find a socket with data available and call its
+ * recvfrom routine.
+ */
+- while ((err = svc_recv(serv, rqstp,
+- 60*60*HZ)) == -EAGAIN)
++ while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
+ ;
+ if (err < 0)
+ break;
+@@ -336,7 +455,7 @@ nfsd(struct svc_rqst *rqstp)
+ /* Process request with signals blocked. */
+ sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
+
+- svc_process(serv, rqstp);
++ svc_process(rqstp);
+
+ /* Unlock export hash tables */
+ exp_readunlock();
+@@ -353,29 +472,13 @@ nfsd(struct svc_rqst *rqstp)
+ if (sigismember(¤t->pending.signal, signo) &&
+ !sigismember(¤t->blocked, signo))
+ break;
+- err = signo;
++ killsig = signo;
+ }
+- /* Clear signals before calling lockd_down() and svc_exit_thread() */
++ /* Clear signals before calling svc_exit_thread() */
+ flush_signals(current);
+
+ lock_kernel();
+
+- /* Release lockd */
+- lockd_down();
+-
+- /* Check if this is last thread */
+- if (serv->sv_nrthreads==1) {
+-
+- printk(KERN_WARNING "nfsd: last server has exited\n");
+- if (err != SIG_NOCLEAN) {
+- printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
+- nfsd_export_flush();
+- }
+- nfsd_serv = NULL;
+- nfsd_racache_shutdown(); /* release read-ahead cache */
+- nfs4_state_shutdown();
+- }
+- list_del(&me.list);
+ nfsdstats.th_cnt --;
+
+ out:
+@@ -388,12 +491,12 @@ out:
+ }
+
+ int
+-nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
++nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
+ {
+ struct svc_procedure *proc;
+ kxdrproc_t xdr;
+- u32 nfserr;
+- u32 *nfserrp;
++ __be32 nfserr;
++ __be32 *nfserrp;
+
+ dprintk("nfsd_dispatch: vers %d proc %d\n",
+ rqstp->rq_vers, rqstp->rq_proc);
+@@ -412,7 +515,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u3
+
+ /* Decode arguments */
+ xdr = proc->pc_decode;
+- if (xdr && !xdr(rqstp, (u32*)rqstp->rq_arg.head[0].iov_base,
++ if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
+ rqstp->rq_argp)) {
+ dprintk("nfsd: failed to decode arguments!\n");
+ nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
+@@ -425,7 +528,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u3
+ */
+ nfserrp = rqstp->rq_res.head[0].iov_base
+ + rqstp->rq_res.head[0].iov_len;
+- rqstp->rq_res.head[0].iov_len += sizeof(u32);
++ rqstp->rq_res.head[0].iov_len += sizeof(__be32);
+
+ /* Now call the procedure handler, and encode NFS status. */
+ nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
+index e3a0797..56ebb14 100644
+--- a/fs/nfsd/nfsxdr.c
++++ b/fs/nfsd/nfsxdr.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nfsd/xdr.c
++ * linux/fs/nfsd/nfsxdr.c
+ *
+ * XDR support for nfsd
+ *
+@@ -37,8 +37,8 @@ static u32 nfs_ftypes[] = {
+ /*
+ * XDR functions for basic NFS types
+ */
+-static u32 *
+-decode_fh(u32 *p, struct svc_fh *fhp)
++static __be32 *
++decode_fh(__be32 *p, struct svc_fh *fhp)
+ {
+ fh_init(fhp, NFS_FHSIZE);
+ memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
+@@ -50,13 +50,13 @@ decode_fh(u32 *p, struct svc_fh *fhp)
+ }
+
+ /* Helper function for NFSv2 ACL code */
+-u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp)
++__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
+ {
+ return decode_fh(p, fhp);
+ }
+
+-static inline u32 *
+-encode_fh(u32 *p, struct svc_fh *fhp)
++static inline __be32 *
++encode_fh(__be32 *p, struct svc_fh *fhp)
+ {
+ memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
+ return p + (NFS_FHSIZE>> 2);
+@@ -66,8 +66,8 @@ encode_fh(u32 *p, struct svc_fh *fhp)
+ * Decode a file name and make sure that the path contains
+ * no slashes or null bytes.
+ */
+-static inline u32 *
+-decode_filename(u32 *p, char **namp, int *lenp)
++static inline __be32 *
++decode_filename(__be32 *p, char **namp, int *lenp)
+ {
+ char *name;
+ int i;
+@@ -82,8 +82,8 @@ decode_filename(u32 *p, char **namp, int
+ return p;
+ }
+
+-static inline u32 *
+-decode_pathname(u32 *p, char **namp, int *lenp)
++static inline __be32 *
++decode_pathname(__be32 *p, char **namp, int *lenp)
+ {
+ char *name;
+ int i;
+@@ -98,8 +98,8 @@ decode_pathname(u32 *p, char **namp, int
+ return p;
+ }
+
+-static inline u32 *
+-decode_sattr(u32 *p, struct iattr *iap)
++static inline __be32 *
++decode_sattr(__be32 *p, struct iattr *iap)
+ {
+ u32 tmp, tmp1;
+
+@@ -151,8 +151,8 @@ decode_sattr(u32 *p, struct iattr *iap)
+ return p;
+ }
+
+-static u32 *
+-encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
++static __be32 *
++encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
+ struct kstat *stat)
+ {
+ struct dentry *dentry = fhp->fh_dentry;
+@@ -195,7 +195,7 @@ encode_fattr(struct svc_rqst *rqstp, u32
+ }
+
+ /* Helper function for NFSv2 ACL code */
+-u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
++__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
+ {
+ struct kstat stat;
+ vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat);
+@@ -206,13 +206,13 @@ u32 *nfs2svc_encode_fattr(struct svc_rqs
+ * XDR decode functions
+ */
+ int
+-nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_argsize_check(rqstp, p);
+ }
+
+ int
+-nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
++nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+@@ -220,7 +220,7 @@ nfssvc_decode_fhandle(struct svc_rqst *r
+ }
+
+ int
+-nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_sattrargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -231,7 +231,7 @@ nfssvc_decode_sattrargs(struct svc_rqst
+ }
+
+ int
+-nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_diropargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -242,7 +242,7 @@ nfssvc_decode_diropargs(struct svc_rqst
+ }
+
+ int
+-nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_readargs *args)
+ {
+ unsigned int len;
+@@ -254,19 +254,18 @@ nfssvc_decode_readargs(struct svc_rqst *
+ len = args->count = ntohl(*p++);
+ p++; /* totalcount - unused */
+
+- if (len > NFSSVC_MAXBLKSIZE)
+- len = NFSSVC_MAXBLKSIZE;
++ if (len > NFSSVC_MAXBLKSIZE_V2)
++ len = NFSSVC_MAXBLKSIZE_V2;
+
+ /* set up somewhere to store response.
+ * We take pages, put them on reslist and include in iovec
+ */
+ v=0;
+ while (len > 0) {
+- pn=rqstp->rq_resused;
+- svc_take_page(rqstp);
+- args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+- args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
+- len -= args->vec[v].iov_len;
++ pn = rqstp->rq_resused++;
++ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
++ rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
++ len -= rqstp->rq_vec[v].iov_len;
+ v++;
+ }
+ args->vlen = v;
+@@ -274,7 +273,7 @@ nfssvc_decode_readargs(struct svc_rqst *
+ }
+
+ int
+-nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_writeargs *args)
+ {
+ unsigned int len;
+@@ -286,25 +285,25 @@ nfssvc_decode_writeargs(struct svc_rqst
+ args->offset = ntohl(*p++); /* offset */
+ p++; /* totalcount */
+ len = args->len = ntohl(*p++);
+- args->vec[0].iov_base = (void*)p;
+- args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
++ rqstp->rq_vec[0].iov_base = (void*)p;
++ rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
+ (((void*)p) - rqstp->rq_arg.head[0].iov_base);
+- if (len > NFSSVC_MAXBLKSIZE)
+- len = NFSSVC_MAXBLKSIZE;
++ if (len > NFSSVC_MAXBLKSIZE_V2)
++ len = NFSSVC_MAXBLKSIZE_V2;
+ v = 0;
+- while (len > args->vec[v].iov_len) {
+- len -= args->vec[v].iov_len;
++ while (len > rqstp->rq_vec[v].iov_len) {
++ len -= rqstp->rq_vec[v].iov_len;
+ v++;
+- args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
+- args->vec[v].iov_len = PAGE_SIZE;
++ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
++ rqstp->rq_vec[v].iov_len = PAGE_SIZE;
+ }
+- args->vec[v].iov_len = len;
++ rqstp->rq_vec[v].iov_len = len;
+ args->vlen = v+1;
+- return args->vec[0].iov_len > 0;
++ return rqstp->rq_vec[0].iov_len > 0;
+ }
+
+ int
+-nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_createargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh))
+@@ -316,7 +315,7 @@ nfssvc_decode_createargs(struct svc_rqst
+ }
+
+ int
+-nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_renameargs *args)
+ {
+ if (!(p = decode_fh(p, &args->ffh))
+@@ -329,18 +328,17 @@ nfssvc_decode_renameargs(struct svc_rqst
+ }
+
+ int
+-nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args)
++nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+- svc_take_page(rqstp);
+- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
++ args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+
+ return xdr_argsize_check(rqstp, p);
+ }
+
+ int
+-nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_linkargs *args)
+ {
+ if (!(p = decode_fh(p, &args->ffh))
+@@ -352,7 +350,7 @@ nfssvc_decode_linkargs(struct svc_rqst *
+ }
+
+ int
+-nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_symlinkargs *args)
+ {
+ if (!(p = decode_fh(p, &args->ffh))
+@@ -365,7 +363,7 @@ nfssvc_decode_symlinkargs(struct svc_rqs
+ }
+
+ int
+-nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
++nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_readdirargs *args)
+ {
+ if (!(p = decode_fh(p, &args->fh)))
+@@ -375,8 +373,7 @@ nfssvc_decode_readdirargs(struct svc_rqs
+ if (args->count > PAGE_SIZE)
+ args->count = PAGE_SIZE;
+
+- svc_take_page(rqstp);
+- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
++ args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+
+ return xdr_argsize_check(rqstp, p);
+ }
+@@ -385,13 +382,13 @@ nfssvc_decode_readdirargs(struct svc_rqs
+ * XDR encode functions
+ */
+ int
+-nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
++nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+ {
+ return xdr_ressize_check(rqstp, p);
+ }
+
+ int
+-nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
++nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_attrstat *resp)
+ {
+ p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
+@@ -399,7 +396,7 @@ nfssvc_encode_attrstat(struct svc_rqst *
+ }
+
+ int
+-nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
++nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_diropres *resp)
+ {
+ p = encode_fh(p, &resp->fh);
+@@ -408,7 +405,7 @@ nfssvc_encode_diropres(struct svc_rqst *
+ }
+
+ int
+-nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
++nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_readlinkres *resp)
+ {
+ *p++ = htonl(resp->len);
+@@ -416,7 +413,6 @@ nfssvc_encode_readlinkres(struct svc_rqs
+ rqstp->rq_res.page_len = resp->len;
+ if (resp->len & 3) {
+ /* need to pad the tail */
+- rqstp->rq_restailpage = 0;
+ rqstp->rq_res.tail[0].iov_base = p;
+ *p = 0;
+ rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
+@@ -425,7 +421,7 @@ nfssvc_encode_readlinkres(struct svc_rqs
+ }
+
+ int
+-nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
++nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_readres *resp)
+ {
+ p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
+@@ -436,7 +432,6 @@ nfssvc_encode_readres(struct svc_rqst *r
+ rqstp->rq_res.page_len = resp->count;
+ if (resp->count & 3) {
+ /* need to pad the tail */
+- rqstp->rq_restailpage = 0;
+ rqstp->rq_res.tail[0].iov_base = p;
+ *p = 0;
+ rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
+@@ -445,7 +440,7 @@ nfssvc_encode_readres(struct svc_rqst *r
+ }
+
+ int
+-nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
++nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_readdirres *resp)
+ {
+ xdr_ressize_check(rqstp, p);
+@@ -458,12 +453,12 @@ nfssvc_encode_readdirres(struct svc_rqst
+ }
+
+ int
+-nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
++nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_statfsres *resp)
+ {
+ struct kstatfs *stat = &resp->stats;
+
+- *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */
++ *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
+ *p++ = htonl(stat->f_bsize);
+ *p++ = htonl(stat->f_blocks);
+ *p++ = htonl(stat->f_bfree);
+@@ -476,7 +471,7 @@ nfssvc_encode_entry(struct readdir_cd *c
+ int namlen, loff_t offset, ino_t ino, unsigned int d_type)
+ {
+ struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
+- u32 *p = cd->buffer;
++ __be32 *p = cd->buffer;
+ int buflen, slen;
+
+ /*
+@@ -502,7 +497,7 @@ nfssvc_encode_entry(struct readdir_cd *c
+ *p++ = htonl((u32) ino); /* file id */
+ p = xdr_encode_array(p, name, namlen);/* name length & name */
+ cd->offset = p; /* remember pointer */
+- *p++ = ~(u32) 0; /* offset of next entry */
++ *p++ = htonl(~0U); /* offset of next entry */
+
+ cd->buflen = buflen;
+ cd->buffer = p;
+@@ -514,7 +509,7 @@ nfssvc_encode_entry(struct readdir_cd *c
+ * XDR release functions
+ */
+ int
+-nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
++nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
+ struct nfsd_fhandle *resp)
+ {
+ fh_put(&resp->fh);
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index c9e3b5a..f21e917 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -54,6 +54,7 @@
+ #include <linux/nfsd_idmap.h>
+ #include <linux/security.h>
+ #endif /* CONFIG_NFSD_V4 */
++#include <linux/jhash.h>
+
+ #include <asm/uaccess.h>
+
+@@ -81,10 +82,19 @@ struct raparms {
+ dev_t p_dev;
+ int p_set;
+ struct file_ra_state p_ra;
++ unsigned int p_hindex;
+ };
+
++struct raparm_hbucket {
++ struct raparms *pb_head;
++ spinlock_t pb_lock;
++} ____cacheline_aligned_in_smp;
++
+ static struct raparms * raparml;
+-static struct raparms * raparm_cache;
++#define RAPARM_HASH_BITS 4
++#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
++#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
++static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
+
+ /*
+ * Called from nfsd_lookup and encode_dirent. Check if we have crossed
+@@ -100,7 +110,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, s
+ struct dentry *dentry = *dpp;
+ struct vfsmount *mnt = mntget(exp->ex_mnt);
+ struct dentry *mounts = dget(dentry);
+- int err = nfs_ok;
++ int err = 0;
+
+ while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
+
+@@ -138,14 +148,15 @@ out:
+ * clients and is explicitly disallowed for NFSv3
+ * NeilBrown <neilb at cse.unsw.edu.au>
+ */
+-int
++__be32
+ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
+ int len, struct svc_fh *resfh)
+ {
+ struct svc_export *exp;
+ struct dentry *dparent;
+ struct dentry *dentry;
+- int err;
++ __be32 err;
++ int host_err;
+
+ dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
+
+@@ -183,7 +194,7 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
+ exp2 = exp_parent(exp->ex_client, mnt, dentry,
+ &rqstp->rq_chandle);
+ if (IS_ERR(exp2)) {
+- err = PTR_ERR(exp2);
++ host_err = PTR_ERR(exp2);
+ dput(dentry);
+ mntput(mnt);
+ goto out_nfserr;
+@@ -200,14 +211,14 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
+ } else {
+ fh_lock(fhp);
+ dentry = lookup_one_len(name, dparent, len);
+- err = PTR_ERR(dentry);
++ host_err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out_nfserr;
+ /*
+ * check if we have crossed a mount point ...
+ */
+ if (d_mountpoint(dentry)) {
+- if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
++ if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
+ dput(dentry);
+ goto out_nfserr;
+ }
+@@ -226,7 +237,7 @@ out:
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out;
+ }
+
+@@ -234,7 +245,7 @@ out_nfserr:
+ * Set various file attributes.
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+ int check_guard, time_t guardtime)
+ {
+@@ -243,7 +254,8 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+ int accmode = MAY_SATTR;
+ int ftype = 0;
+ int imode;
+- int err;
++ __be32 err;
++ int host_err;
+ int size_change = 0;
+
+ if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
+@@ -309,19 +321,19 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+ * If we are changing the size of the file, then
+ * we need to break all leases.
+ */
+- err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
+- if (err == -EWOULDBLOCK)
+- err = -ETIMEDOUT;
+- if (err) /* ENOMEM or EWOULDBLOCK */
++ host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
++ if (host_err == -EWOULDBLOCK)
++ host_err = -ETIMEDOUT;
++ if (host_err) /* ENOMEM or EWOULDBLOCK */
+ goto out_nfserr;
+
+- err = get_write_access(inode);
+- if (err)
++ host_err = get_write_access(inode);
++ if (host_err)
+ goto out_nfserr;
+
+ size_change = 1;
+- err = locks_verify_truncate(inode, NULL, iap->ia_size);
+- if (err) {
++ host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
++ if (host_err) {
+ put_write_access(inode);
+ goto out_nfserr;
+ }
+@@ -347,8 +359,8 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+ err = nfserr_notsync;
+ if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
+ fh_lock(fhp);
+- err = notify_change(dentry, iap);
+- err = nfserrno(err);
++ host_err = notify_change(dentry, iap);
++ err = nfserrno(host_err);
+ fh_unlock(fhp);
+ }
+ if (size_change)
+@@ -360,7 +372,7 @@ out:
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out;
+ }
+
+@@ -410,11 +422,12 @@ out:
+ return error;
+ }
+
+-int
++__be32
+ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfs4_acl *acl)
+ {
+- int error;
++ __be32 error;
++ int host_error;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct posix_acl *pacl = NULL, *dpacl = NULL;
+@@ -430,22 +443,20 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
+ if (S_ISDIR(inode->i_mode))
+ flags = NFS4_ACL_DIR;
+
+- error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+- if (error == -EINVAL) {
++ host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
++ if (host_error == -EINVAL) {
+ error = nfserr_attrnotsupp;
+ goto out;
+- } else if (error < 0)
++ } else if (host_error < 0)
+ goto out_nfserr;
+
+- if (pacl) {
+- error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+- if (error < 0)
+- goto out_nfserr;
+- }
++ host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
++ if (host_error < 0)
++ goto out_nfserr;
+
+- if (dpacl) {
+- error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
+- if (error < 0)
++ if (S_ISDIR(inode->i_mode)) {
++ host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
++ if (host_error < 0)
+ goto out_nfserr;
+ }
+
+@@ -456,7 +467,7 @@ out:
+ posix_acl_release(dpacl);
+ return (error);
+ out_nfserr:
+- error = nfserrno(error);
++ error = nfserrno(host_error);
+ goto out;
+ }
+
+@@ -563,14 +574,14 @@ static struct accessmap nfs3_anyaccess[]
+ { 0, 0 }
+ };
+
+-int
++__be32
+ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported)
+ {
+ struct accessmap *map;
+ struct svc_export *export;
+ struct dentry *dentry;
+ u32 query, result = 0, sresult = 0;
+- unsigned int error;
++ __be32 error;
+
+ error = fh_verify(rqstp, fhp, 0, MAY_NOP);
+ if (error)
+@@ -590,7 +601,7 @@ nfsd_access(struct svc_rqst *rqstp, stru
+ query = *access;
+ for (; map->access; map++) {
+ if (map->access & query) {
+- unsigned int err2;
++ __be32 err2;
+
+ sresult |= map->access;
+
+@@ -629,13 +640,15 @@ nfsd_access(struct svc_rqst *rqstp, stru
+ * The access argument indicates the type of open (read/write/lock)
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
+ int access, struct file **filp)
+ {
+ struct dentry *dentry;
+ struct inode *inode;
+- int flags = O_RDONLY|O_LARGEFILE, err;
++ int flags = O_RDONLY|O_LARGEFILE;
++ __be32 err;
++ int host_err;
+
+ /*
+ * If we get here, then the client has already done an "open",
+@@ -665,10 +678,10 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ * Check to see if there are any leases on this file.
+ * This may block while leases are broken.
+ */
+- err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
+- if (err == -EWOULDBLOCK)
+- err = -ETIMEDOUT;
+- if (err) /* NOMEM or WOULDBLOCK */
++ host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
++ if (host_err == -EWOULDBLOCK)
++ host_err = -ETIMEDOUT;
++ if (host_err) /* NOMEM or WOULDBLOCK */
+ goto out_nfserr;
+
+ if (access & MAY_WRITE) {
+@@ -681,10 +694,9 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ }
+ *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags);
+ if (IS_ERR(*filp))
+- err = PTR_ERR(*filp);
++ host_err = PTR_ERR(*filp);
+ out_nfserr:
+- if (err)
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ out:
+ return err;
+ }
+@@ -743,16 +755,20 @@ nfsd_sync_dir(struct dentry *dp)
+ * Obtain the readahead parameters for the file
+ * specified by (dev, ino).
+ */
+-static DEFINE_SPINLOCK(ra_lock);
+
+ static inline struct raparms *
+ nfsd_get_raparms(dev_t dev, ino_t ino)
+ {
+ struct raparms *ra, **rap, **frap = NULL;
+ int depth = 0;
++ unsigned int hash;
++ struct raparm_hbucket *rab;
++
++ hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
++ rab = &raparm_hash[hash];
+
+- spin_lock(&ra_lock);
+- for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
++ spin_lock(&rab->pb_lock);
++ for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
+ if (ra->p_ino == ino && ra->p_dev == dev)
+ goto found;
+ depth++;
+@@ -761,7 +777,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
+ }
+ depth = nfsdstats.ra_size*11/10;
+ if (!frap) {
+- spin_unlock(&ra_lock);
++ spin_unlock(&rab->pb_lock);
+ return NULL;
+ }
+ rap = frap;
+@@ -769,15 +785,16 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
+ ra->p_dev = dev;
+ ra->p_ino = ino;
+ ra->p_set = 0;
++ ra->p_hindex = hash;
+ found:
+- if (rap != &raparm_cache) {
++ if (rap != &rab->pb_head) {
+ *rap = ra->p_next;
+- ra->p_next = raparm_cache;
+- raparm_cache = ra;
++ ra->p_next = rab->pb_head;
++ rab->pb_head = ra;
+ }
+ ra->p_count++;
+ nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
+- spin_unlock(&ra_lock);
++ spin_unlock(&rab->pb_lock);
+ return ra;
+ }
+
+@@ -791,36 +808,41 @@ nfsd_read_actor(read_descriptor_t *desc,
+ {
+ unsigned long count = desc->count;
+ struct svc_rqst *rqstp = desc->arg.data;
++ struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
+
+ if (size > count)
+ size = count;
+
+ if (rqstp->rq_res.page_len == 0) {
+ get_page(page);
+- rqstp->rq_respages[rqstp->rq_resused++] = page;
++ put_page(*pp);
++ *pp = page;
++ rqstp->rq_resused++;
+ rqstp->rq_res.page_base = offset;
+ rqstp->rq_res.page_len = size;
+- } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
++ } else if (page != pp[-1]) {
+ get_page(page);
+- rqstp->rq_respages[rqstp->rq_resused++] = page;
++ put_page(*pp);
++ *pp = page;
++ rqstp->rq_resused++;
+ rqstp->rq_res.page_len += size;
+- } else {
++ } else
+ rqstp->rq_res.page_len += size;
+- }
+
+ desc->count = count - size;
+ desc->written += size;
+ return size;
+ }
+
+-static int
++static __be32
+ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+ loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+ {
+ struct inode *inode;
+ struct raparms *ra;
+ mm_segment_t oldfs;
+- int err;
++ __be32 err;
++ int host_err;
+
+ err = nfserr_perm;
+ inode = file->f_dentry->d_inode;
+@@ -837,32 +859,33 @@ nfsd_vfs_read(struct svc_rqst *rqstp, st
+ file->f_ra = ra->p_ra;
+
+ if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
+- svc_pushback_unused_pages(rqstp);
+- err = file->f_op->sendfile(file, &offset, *count,
++ rqstp->rq_resused = 1;
++ host_err = file->f_op->sendfile(file, &offset, *count,
+ nfsd_read_actor, rqstp);
+ } else {
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+- err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
++ host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
+ set_fs(oldfs);
+ }
+
+ /* Write back readahead params */
+ if (ra) {
+- spin_lock(&ra_lock);
++ struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
++ spin_lock(&rab->pb_lock);
+ ra->p_ra = file->f_ra;
+ ra->p_set = 1;
+ ra->p_count--;
+- spin_unlock(&ra_lock);
++ spin_unlock(&rab->pb_lock);
+ }
+
+- if (err >= 0) {
+- nfsdstats.io_read += err;
+- *count = err;
++ if (host_err >= 0) {
++ nfsdstats.io_read += host_err;
++ *count = host_err;
+ err = 0;
+ fsnotify_access(file->f_dentry);
+ } else
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ out:
+ return err;
+ }
+@@ -877,7 +900,7 @@ static void kill_suid(struct dentry *den
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ }
+
+-static int
++static __be32
+ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+ loff_t offset, struct kvec *vec, int vlen,
+ unsigned long cnt, int *stablep)
+@@ -886,7 +909,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
+ struct dentry *dentry;
+ struct inode *inode;
+ mm_segment_t oldfs;
+- int err = 0;
++ __be32 err = 0;
++ int host_err;
+ int stable = *stablep;
+
+ #ifdef MSNFS
+@@ -922,18 +946,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
+
+ /* Write the data. */
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+- err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
++ host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
+ set_fs(oldfs);
+- if (err >= 0) {
++ if (host_err >= 0) {
+ nfsdstats.io_write += cnt;
+ fsnotify_modify(file->f_dentry);
+ }
+
+ /* clear setuid/setgid flag after write */
+- if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
++ if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
+ kill_suid(dentry);
+
+- if (err >= 0 && stable) {
++ if (host_err >= 0 && stable) {
+ static ino_t last_ino;
+ static dev_t last_dev;
+
+@@ -959,7 +983,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
+
+ if (inode->i_state & I_DIRTY) {
+ dprintk("nfsd: write sync %d\n", current->pid);
+- err=nfsd_sync(file);
++ host_err=nfsd_sync(file);
+ }
+ #if 0
+ wake_up(&inode->i_wait);
+@@ -969,11 +993,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
+ last_dev = inode->i_sb->s_dev;
+ }
+
+- dprintk("nfsd: write complete err=%d\n", err);
+- if (err >= 0)
++ dprintk("nfsd: write complete host_err=%d\n", host_err);
++ if (host_err >= 0)
+ err = 0;
+ else
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ out:
+ return err;
+ }
+@@ -983,12 +1007,12 @@ out:
+ * on entry. On return, *count contains the number of bytes actually read.
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+ loff_t offset, struct kvec *vec, int vlen,
+ unsigned long *count)
+ {
+- int err;
++ __be32 err;
+
+ if (file) {
+ err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+@@ -1012,12 +1036,12 @@ out:
+ * The stable flag requests synchronous writes.
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+ loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
+ int *stablep)
+ {
+- int err = 0;
++ __be32 err = 0;
+
+ if (file) {
+ err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+@@ -1049,12 +1073,12 @@ out:
+ * Unfortunately we cannot lock the file to make sure we return full WCC
+ * data to the client, as locking happens lower down in the filesystem.
+ */
+-int
++__be32
+ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ loff_t offset, unsigned long count)
+ {
+ struct file *file;
+- int err;
++ __be32 err;
+
+ if ((u64)count > ~(u64)offset)
+ return nfserr_inval;
+@@ -1082,14 +1106,15 @@ nfsd_commit(struct svc_rqst *rqstp, stru
+ *
+ * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
+ */
+-int
++__be32
+ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ char *fname, int flen, struct iattr *iap,
+ int type, dev_t rdev, struct svc_fh *resfhp)
+ {
+ struct dentry *dentry, *dchild = NULL;
+ struct inode *dirp;
+- int err;
++ __be32 err;
++ int host_err;
+
+ err = nfserr_perm;
+ if (!flen)
+@@ -1114,9 +1139,9 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ */
+ if (!resfhp->fh_dentry) {
+ /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+- fh_lock(fhp);
++ fh_lock_nested(fhp, I_MUTEX_PARENT);
+ dchild = lookup_one_len(fname, dentry, flen);
+- err = PTR_ERR(dchild);
++ host_err = PTR_ERR(dchild);
+ if (IS_ERR(dchild))
+ goto out_nfserr;
+ err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+@@ -1155,22 +1180,22 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ err = nfserr_perm;
+ switch (type) {
+ case S_IFREG:
+- err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
++ host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+ break;
+ case S_IFDIR:
+- err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++ host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+ break;
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK:
+- err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++ host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+ break;
+ default:
+ printk("nfsd: bad file type %o in nfsd_create\n", type);
+- err = -EINVAL;
++ host_err = -EINVAL;
+ }
+- if (err < 0)
++ if (host_err < 0)
+ goto out_nfserr;
+
+ if (EX_ISSYNC(fhp->fh_export)) {
+@@ -1185,7 +1210,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ * directories via NFS.
+ */
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
+- int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
++ __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if (err2)
+ err = err2;
+ }
+@@ -1200,7 +1225,7 @@ out:
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out;
+ }
+
+@@ -1208,7 +1233,7 @@ out_nfserr:
+ /*
+ * NFSv3 version of nfsd_create
+ */
+-int
++__be32
+ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ char *fname, int flen, struct iattr *iap,
+ struct svc_fh *resfhp, int createmode, u32 *verifier,
+@@ -1216,7 +1241,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+ {
+ struct dentry *dentry, *dchild = NULL;
+ struct inode *dirp;
+- int err;
++ __be32 err;
++ int host_err;
+ __u32 v_mtime=0, v_atime=0;
+ int v_mode=0;
+
+@@ -1240,13 +1266,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+ err = nfserr_notdir;
+ if(!dirp->i_op || !dirp->i_op->lookup)
+ goto out;
+- fh_lock(fhp);
++ fh_lock_nested(fhp, I_MUTEX_PARENT);
+
+ /*
+ * Compose the response file handle.
+ */
+ dchild = lookup_one_len(fname, dentry, flen);
+- err = PTR_ERR(dchild);
++ host_err = PTR_ERR(dchild);
+ if (IS_ERR(dchild))
+ goto out_nfserr;
+
+@@ -1302,8 +1328,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+ goto out;
+ }
+
+- err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+- if (err < 0)
++ host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
++ if (host_err < 0)
+ goto out_nfserr;
+
+ if (EX_ISSYNC(fhp->fh_export)) {
+@@ -1332,7 +1358,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+ */
+ set_attr:
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) {
+- int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
++ __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if (err2)
+ err = err2;
+ }
+@@ -1350,7 +1376,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out;
+ }
+ #endif /* CONFIG_NFSD_V3 */
+@@ -1360,13 +1386,14 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+ * fits into the buffer. On return, it contains the true length.
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
+ {
+ struct dentry *dentry;
+ struct inode *inode;
+ mm_segment_t oldfs;
+- int err;
++ __be32 err;
++ int host_err;
+
+ err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP);
+ if (err)
+@@ -1385,18 +1412,18 @@ nfsd_readlink(struct svc_rqst *rqstp, st
+ */
+
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+- err = inode->i_op->readlink(dentry, buf, *lenp);
++ host_err = inode->i_op->readlink(dentry, buf, *lenp);
+ set_fs(oldfs);
+
+- if (err < 0)
++ if (host_err < 0)
+ goto out_nfserr;
+- *lenp = err;
++ *lenp = host_err;
+ err = 0;
+ out:
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out;
+ }
+
+@@ -1404,7 +1431,7 @@ out_nfserr:
+ * Create a symlink and look up its inode
+ * N.B. After this call _both_ fhp and resfhp need an fh_put
+ */
+-int
++__be32
+ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ char *fname, int flen,
+ char *path, int plen,
+@@ -1412,7 +1439,8 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+ struct iattr *iap)
+ {
+ struct dentry *dentry, *dnew;
+- int err, cerr;
++ __be32 err, cerr;
++ int host_err;
+ umode_t mode;
+
+ err = nfserr_noent;
+@@ -1428,7 +1456,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+ fh_lock(fhp);
+ dentry = fhp->fh_dentry;
+ dnew = lookup_one_len(fname, dentry, flen);
+- err = PTR_ERR(dnew);
++ host_err = PTR_ERR(dnew);
+ if (IS_ERR(dnew))
+ goto out_nfserr;
+
+@@ -1440,21 +1468,21 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+ if (unlikely(path[plen] != 0)) {
+ char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
+ if (path_alloced == NULL)
+- err = -ENOMEM;
++ host_err = -ENOMEM;
+ else {
+ strncpy(path_alloced, path, plen);
+ path_alloced[plen] = 0;
+- err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
++ host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
+ kfree(path_alloced);
+ }
+ } else
+- err = vfs_symlink(dentry->d_inode, dnew, path, mode);
++ host_err = vfs_symlink(dentry->d_inode, dnew, path, mode);
+
+- if (!err)
++ if (!host_err) {
+ if (EX_ISSYNC(fhp->fh_export))
+- err = nfsd_sync_dir(dentry);
+- if (err)
+- err = nfserrno(err);
++ host_err = nfsd_sync_dir(dentry);
++ }
++ err = nfserrno(host_err);
+ fh_unlock(fhp);
+
+ cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
+@@ -1464,7 +1492,7 @@ out:
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out;
+ }
+
+@@ -1472,13 +1500,14 @@ out_nfserr:
+ * Create a hardlink
+ * N.B. After this call _both_ ffhp and tfhp need an fh_put
+ */
+-int
++__be32
+ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
+ char *name, int len, struct svc_fh *tfhp)
+ {
+ struct dentry *ddir, *dnew, *dold;
+ struct inode *dirp, *dest;
+- int err;
++ __be32 err;
++ int host_err;
+
+ err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
+ if (err)
+@@ -1494,29 +1523,30 @@ nfsd_link(struct svc_rqst *rqstp, struct
+ if (isdotent(name, len))
+ goto out;
+
+- fh_lock(ffhp);
++ fh_lock_nested(ffhp, I_MUTEX_PARENT);
+ ddir = ffhp->fh_dentry;
+ dirp = ddir->d_inode;
+
+ dnew = lookup_one_len(name, ddir, len);
+- err = PTR_ERR(dnew);
++ host_err = PTR_ERR(dnew);
+ if (IS_ERR(dnew))
+ goto out_nfserr;
+
+ dold = tfhp->fh_dentry;
+ dest = dold->d_inode;
+
+- err = vfs_link(dold, dirp, dnew);
+- if (!err) {
++ host_err = vfs_link(dold, dirp, dnew);
++ if (!host_err) {
+ if (EX_ISSYNC(ffhp->fh_export)) {
+ err = nfserrno(nfsd_sync_dir(ddir));
+ write_inode_now(dest, 1);
+ }
++ err = 0;
+ } else {
+- if (err == -EXDEV && rqstp->rq_vers == 2)
++ if (host_err == -EXDEV && rqstp->rq_vers == 2)
+ err = nfserr_acces;
+ else
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ }
+
+ dput(dnew);
+@@ -1526,7 +1556,7 @@ out:
+ return err;
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ goto out_unlock;
+ }
+
+@@ -1534,13 +1564,14 @@ out_nfserr:
+ * Rename a file
+ * N.B. After this call _both_ ffhp and tfhp need an fh_put
+ */
+-int
++__be32
+ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
+ struct svc_fh *tfhp, char *tname, int tlen)
+ {
+ struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap;
+ struct inode *fdir, *tdir;
+- int err;
++ __be32 err;
++ int host_err;
+
+ err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE);
+ if (err)
+@@ -1571,22 +1602,22 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+ fill_pre_wcc(tfhp);
+
+ odentry = lookup_one_len(fname, fdentry, flen);
+- err = PTR_ERR(odentry);
++ host_err = PTR_ERR(odentry);
+ if (IS_ERR(odentry))
+ goto out_nfserr;
+
+- err = -ENOENT;
++ host_err = -ENOENT;
+ if (!odentry->d_inode)
+ goto out_dput_old;
+- err = -EINVAL;
++ host_err = -EINVAL;
+ if (odentry == trap)
+ goto out_dput_old;
+
+ ndentry = lookup_one_len(tname, tdentry, tlen);
+- err = PTR_ERR(ndentry);
++ host_err = PTR_ERR(ndentry);
+ if (IS_ERR(ndentry))
+ goto out_dput_old;
+- err = -ENOTEMPTY;
++ host_err = -ENOTEMPTY;
+ if (ndentry == trap)
+ goto out_dput_new;
+
+@@ -1594,14 +1625,14 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+ if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
+ ((atomic_read(&odentry->d_count) > 1)
+ || (atomic_read(&ndentry->d_count) > 1))) {
+- err = -EPERM;
++ host_err = -EPERM;
+ } else
+ #endif
+- err = vfs_rename(fdir, odentry, tdir, ndentry);
+- if (!err && EX_ISSYNC(tfhp->fh_export)) {
+- err = nfsd_sync_dir(tdentry);
+- if (!err)
+- err = nfsd_sync_dir(fdentry);
++ host_err = vfs_rename(fdir, odentry, tdir, ndentry);
++ if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
++ host_err = nfsd_sync_dir(tdentry);
++ if (!host_err)
++ host_err = nfsd_sync_dir(fdentry);
+ }
+
+ out_dput_new:
+@@ -1609,8 +1640,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+ out_dput_old:
+ dput(odentry);
+ out_nfserr:
+- if (err)
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+
+ /* we cannot reply on fh_unlock on the two filehandles,
+ * as that would do the wrong thing if the two directories
+@@ -1629,13 +1659,14 @@ out:
+ * Unlink a file or directory
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
+ char *fname, int flen)
+ {
+ struct dentry *dentry, *rdentry;
+ struct inode *dirp;
+- int err;
++ __be32 err;
++ int host_err;
+
+ err = nfserr_acces;
+ if (!flen || isdotent(fname, flen))
+@@ -1644,12 +1675,12 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+ if (err)
+ goto out;
+
+- fh_lock(fhp);
++ fh_lock_nested(fhp, I_MUTEX_PARENT);
+ dentry = fhp->fh_dentry;
+ dirp = dentry->d_inode;
+
+ rdentry = lookup_one_len(fname, dentry, flen);
+- err = PTR_ERR(rdentry);
++ host_err = PTR_ERR(rdentry);
+ if (IS_ERR(rdentry))
+ goto out_nfserr;
+
+@@ -1666,22 +1697,23 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+ #ifdef MSNFS
+ if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
+ (atomic_read(&rdentry->d_count) > 1)) {
+- err = -EPERM;
++ host_err = -EPERM;
+ } else
+ #endif
+- err = vfs_unlink(dirp, rdentry);
++ host_err = vfs_unlink(dirp, rdentry);
+ } else { /* It's RMDIR */
+- err = vfs_rmdir(dirp, rdentry);
++ host_err = vfs_rmdir(dirp, rdentry);
+ }
+
+ dput(rdentry);
+
+- if (err == 0 &&
+- EX_ISSYNC(fhp->fh_export))
+- err = nfsd_sync_dir(dentry);
++ if (host_err)
++ goto out_nfserr;
++ if (EX_ISSYNC(fhp->fh_export))
++ host_err = nfsd_sync_dir(dentry);
+
+ out_nfserr:
+- err = nfserrno(err);
++ err = nfserrno(host_err);
+ out:
+ return err;
+ }
+@@ -1690,11 +1722,12 @@ out:
+ * Read entries from a directory.
+ * The NFSv3/4 verifier we ignore for now.
+ */
+-int
++__be32
+ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
+ struct readdir_cd *cdp, encode_dent_fn func)
+ {
+- int err;
++ __be32 err;
++ int host_err;
+ struct file *file;
+ loff_t offset = *offsetp;
+
+@@ -1716,10 +1749,10 @@ nfsd_readdir(struct svc_rqst *rqstp, str
+
+ do {
+ cdp->err = nfserr_eof; /* will be cleared on successful read */
+- err = vfs_readdir(file, (filldir_t) func, cdp);
+- } while (err >=0 && cdp->err == nfs_ok);
+- if (err)
+- err = nfserrno(err);
++ host_err = vfs_readdir(file, (filldir_t) func, cdp);
++ } while (host_err >=0 && cdp->err == nfs_ok);
++ if (host_err)
++ err = nfserrno(host_err);
+ else
+ err = cdp->err;
+ *offsetp = vfs_llseek(file, 0, 1);
+@@ -1736,10 +1769,10 @@ out:
+ * Get file system stats
+ * N.B. After this call fhp needs an fh_put
+ */
+-int
++__be32
+ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
+ {
+- int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
++ __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+ if (!err && vfs_statfs(fhp->fh_dentry,stat))
+ err = nfserr_io;
+ return err;
+@@ -1748,7 +1781,7 @@ nfsd_statfs(struct svc_rqst *rqstp, stru
+ /*
+ * Check for a user's access permissions to this inode.
+ */
+-int
++__be32
+ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
+ {
+ struct inode *inode = dentry->d_inode;
+@@ -1829,11 +1862,11 @@ nfsd_permission(struct svc_export *exp,
+ void
+ nfsd_racache_shutdown(void)
+ {
+- if (!raparm_cache)
++ if (!raparml)
+ return;
+ dprintk("nfsd: freeing readahead buffers.\n");
+ kfree(raparml);
+- raparm_cache = raparml = NULL;
++ raparml = NULL;
+ }
+ /*
+ * Initialize readahead param cache
+@@ -1842,19 +1875,31 @@ int
+ nfsd_racache_init(int cache_size)
+ {
+ int i;
++ int j = 0;
++ int nperbucket;
++
+
+- if (raparm_cache)
++ if (raparml)
+ return 0;
++ if (cache_size < 2*RAPARM_HASH_SIZE)
++ cache_size = 2*RAPARM_HASH_SIZE;
+ raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);
+
+ if (raparml != NULL) {
+ dprintk("nfsd: allocating %d readahead buffers.\n",
+ cache_size);
++ for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
++ raparm_hash[i].pb_head = NULL;
++ spin_lock_init(&raparm_hash[i].pb_lock);
++ }
++ nperbucket = cache_size >> RAPARM_HASH_BITS;
+ memset(raparml, 0, sizeof(struct raparms) * cache_size);
+ for (i = 0; i < cache_size - 1; i++) {
+- raparml[i].p_next = raparml + i + 1;
++ if (i % nperbucket == 0)
++ raparm_hash[j++].pb_head = raparml + i;
++ if (i % nperbucket < nperbucket-1)
++ raparml[i].p_next = raparml + i + 1;
+ }
+- raparm_cache = raparml;
+ } else {
+ printk(KERN_WARNING
+ "nfsd: Could not allocate memory read-ahead cache.\n");
+diff --git a/fs/nls/nls_ascii.c b/fs/nls/nls_ascii.c
+index b83381c..6993fae 100644
+--- a/fs/nls/nls_ascii.c
++++ b/fs/nls/nls_ascii.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_ascii.c
++ * linux/fs/nls/nls_ascii.c
+ *
+ * Charset ascii translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
+index 9de6b49..7dfdab9 100644
+--- a/fs/nls/nls_base.c
++++ b/fs/nls/nls_base.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_base.c
++ * linux/fs/nls/nls_base.c
+ *
+ * Native language support--charsets and unicode translations.
+ * By Gordon Chaffee 1996, 1997
+@@ -163,8 +163,6 @@ int register_nls(struct nls_table * nls)
+ {
+ struct nls_table ** tmp = &tables;
+
+- if (!nls)
+- return -EINVAL;
+ if (nls->next)
+ return -EBUSY;
+
+diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c
+index 32e78cf..570aa69 100644
+--- a/fs/nls/nls_cp1250.c
++++ b/fs/nls/nls_cp1250.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp1250.c
++ * linux/fs/nls/nls_cp1250.c
+ *
+ * Charset cp1250 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c
+index cb41c8a..f114afa 100644
+--- a/fs/nls/nls_cp1251.c
++++ b/fs/nls/nls_cp1251.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp1251.c
++ * linux/fs/nls/nls_cp1251.c
+ *
+ * Charset cp1251 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c
+index efdeefe..e57f2cb 100644
+--- a/fs/nls/nls_cp1255.c
++++ b/fs/nls/nls_cp1255.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp1255.c
++ * linux/fs/nls/nls_cp1255.c
+ *
+ * Charset cp1255 translation tables.
+ * The Unicode to charset table has only exact mappings.
+diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c
+index 5c4a1cd..d41930c 100644
+--- a/fs/nls/nls_cp437.c
++++ b/fs/nls/nls_cp437.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp437.c
++ * linux/fs/nls/nls_cp437.c
+ *
+ * Charset cp437 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c
+index e8b3ca8..d21f879 100644
+--- a/fs/nls/nls_cp737.c
++++ b/fs/nls/nls_cp737.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp737.c
++ * linux/fs/nls/nls_cp737.c
+ *
+ * Charset cp737 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c
+index bdb290e..c97714c 100644
+--- a/fs/nls/nls_cp775.c
++++ b/fs/nls/nls_cp775.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp775.c
++ * linux/fs/nls/nls_cp775.c
+ *
+ * Charset cp775 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c
+index 25deaa4..843b7d9 100644
+--- a/fs/nls/nls_cp850.c
++++ b/fs/nls/nls_cp850.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp850.c
++ * linux/fs/nls/nls_cp850.c
+ *
+ * Charset cp850 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c
+index b822a7b..83cfd84 100644
+--- a/fs/nls/nls_cp852.c
++++ b/fs/nls/nls_cp852.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp852.c
++ * linux/fs/nls/nls_cp852.c
+ *
+ * Charset cp852 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c
+index e8641b7..9190b7b 100644
+--- a/fs/nls/nls_cp855.c
++++ b/fs/nls/nls_cp855.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp855.c
++ * linux/fs/nls/nls_cp855.c
+ *
+ * Charset cp855 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c
+index 7ba589e..ef3d36d 100644
+--- a/fs/nls/nls_cp857.c
++++ b/fs/nls/nls_cp857.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp857.c
++ * linux/fs/nls/nls_cp857.c
+ *
+ * Charset cp857 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c
+index 3b9e49c..7e2fb66 100644
+--- a/fs/nls/nls_cp860.c
++++ b/fs/nls/nls_cp860.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp860.c
++ * linux/fs/nls/nls_cp860.c
+ *
+ * Charset cp860 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c
+index 959ff64..66d8d80 100644
+--- a/fs/nls/nls_cp861.c
++++ b/fs/nls/nls_cp861.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp861.c
++ * linux/fs/nls/nls_cp861.c
+ *
+ * Charset cp861 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c
+index b96928f..360ba38 100644
+--- a/fs/nls/nls_cp862.c
++++ b/fs/nls/nls_cp862.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp862.c
++ * linux/fs/nls/nls_cp862.c
+ *
+ * Charset cp862 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c
+index baa6e0e..656a931 100644
+--- a/fs/nls/nls_cp863.c
++++ b/fs/nls/nls_cp863.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp863.c
++ * linux/fs/nls/nls_cp863.c
+ *
+ * Charset cp863 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c
+index f4dabb0..01ca730 100644
+--- a/fs/nls/nls_cp864.c
++++ b/fs/nls/nls_cp864.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp864.c
++ * linux/fs/nls/nls_cp864.c
+ *
+ * Charset cp864 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c
+index 4caeafa..5ba6ee1 100644
+--- a/fs/nls/nls_cp865.c
++++ b/fs/nls/nls_cp865.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp865.c
++ * linux/fs/nls/nls_cp865.c
+ *
+ * Charset cp865 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c
+index f2b4a9a..c5f8222 100644
+--- a/fs/nls/nls_cp866.c
++++ b/fs/nls/nls_cp866.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp866.c
++ * linux/fs/nls/nls_cp866.c
+ *
+ * Charset cp866 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c
+index 12b436f..8d40151 100644
+--- a/fs/nls/nls_cp869.c
++++ b/fs/nls/nls_cp869.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp869.c
++ * linux/fs/nls/nls_cp869.c
+ *
+ * Charset cp869 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c
+index b5766a0..df04205 100644
+--- a/fs/nls/nls_cp874.c
++++ b/fs/nls/nls_cp874.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp874.c
++ * linux/fs/nls/nls_cp874.c
+ *
+ * Charset cp874 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c
+index 2c1a17c..2a9ccf3 100644
+--- a/fs/nls/nls_cp932.c
++++ b/fs/nls/nls_cp932.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp932.c
++ * linux/fs/nls/nls_cp932.c
+ *
+ * Charset cp932 translation tables.
+ * This translation table was generated automatically, the
+diff --git a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c
+index ef4cef4..046fde8 100644
+--- a/fs/nls/nls_cp936.c
++++ b/fs/nls/nls_cp936.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp936.c
++ * linux/fs/nls/nls_cp936.c
+ *
+ * Charset cp936 translation tables.
+ * This translation table was generated automatically, the
+diff --git a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c
+index 4351ae2..92ae193 100644
+--- a/fs/nls/nls_cp949.c
++++ b/fs/nls/nls_cp949.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp949.c
++ * linux/fs/nls/nls_cp949.c
+ *
+ * Charset cp949 translation tables.
+ * This translation table was generated automatically, the
+diff --git a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c
+index 8167a28..5665945 100644
+--- a/fs/nls/nls_cp950.c
++++ b/fs/nls/nls_cp950.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_cp950.c
++ * linux/fs/nls/nls_cp950.c
+ *
+ * Charset cp950 translation tables.
+ * This translation table was generated automatically, the
+diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c
+index 06640c3..7329351 100644
+--- a/fs/nls/nls_euc-jp.c
++++ b/fs/nls/nls_euc-jp.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_euc-jp.c
++ * linux/fs/nls/nls_euc-jp.c
+ *
+ * Added `OSF/JVC Recommended Code Set Conversion Specification
+ * between Japanese EUC and Shift-JIS' support: <hirofumi at mail.parknet.co.jp>
+diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c
+index 70a2c19..2483c3c 100644
+--- a/fs/nls/nls_iso8859-1.c
++++ b/fs/nls/nls_iso8859-1.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-1.c
++ * linux/fs/nls/nls_iso8859-1.c
+ *
+ * Charset iso8859-1 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c
+index 4547035..7b8721d 100644
+--- a/fs/nls/nls_iso8859-13.c
++++ b/fs/nls/nls_iso8859-13.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-13.c
++ * linux/fs/nls/nls_iso8859-13.c
+ *
+ * Charset iso8859-13 translation tables.
+ * The Unicode to charset table has only exact mappings.
+diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c
+index 13628d0..2e895e6 100644
+--- a/fs/nls/nls_iso8859-14.c
++++ b/fs/nls/nls_iso8859-14.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-14.c
++ * linux/fs/nls/nls_iso8859-14.c
+ *
+ * Charset iso8859-14 translation tables.
+ *
+diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c
+index 88b924b..5c91592 100644
+--- a/fs/nls/nls_iso8859-15.c
++++ b/fs/nls/nls_iso8859-15.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-15.c
++ * linux/fs/nls/nls_iso8859-15.c
+ *
+ * Charset iso8859-15 translation tables.
+ * The Unicode to charset table has only exact mappings.
+diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c
+index 372528a..892d38f 100644
+--- a/fs/nls/nls_iso8859-2.c
++++ b/fs/nls/nls_iso8859-2.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-2.c
++ * linux/fs/nls/nls_iso8859-2.c
+ *
+ * Charset iso8859-2 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c
+index 81b45a2..49317bc 100644
+--- a/fs/nls/nls_iso8859-3.c
++++ b/fs/nls/nls_iso8859-3.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-3.c
++ * linux/fs/nls/nls_iso8859-3.c
+ *
+ * Charset iso8859-3 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c
+index 101b87f..9f3b936 100644
+--- a/fs/nls/nls_iso8859-4.c
++++ b/fs/nls/nls_iso8859-4.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-4.c
++ * linux/fs/nls/nls_iso8859-4.c
+ *
+ * Charset iso8859-4 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c
+index 83b0084..001a2bb 100644
+--- a/fs/nls/nls_iso8859-5.c
++++ b/fs/nls/nls_iso8859-5.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-5.c
++ * linux/fs/nls/nls_iso8859-5.c
+ *
+ * Charset iso8859-5 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c
+index 0c519d6..8cec03d 100644
+--- a/fs/nls/nls_iso8859-6.c
++++ b/fs/nls/nls_iso8859-6.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-6.c
++ * linux/fs/nls/nls_iso8859-6.c
+ *
+ * Charset iso8859-6 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c
+index bd08546..1be707d 100644
+--- a/fs/nls/nls_iso8859-7.c
++++ b/fs/nls/nls_iso8859-7.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-7.c
++ * linux/fs/nls/nls_iso8859-7.c
+ *
+ * Charset iso8859-7 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c
+index 988eff7..8c0146f 100644
+--- a/fs/nls/nls_iso8859-9.c
++++ b/fs/nls/nls_iso8859-9.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_iso8859-9.c
++ * linux/fs/nls/nls_iso8859-9.c
+ *
+ * Charset iso8859-9 translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c
+index 0ad22c2..fefbe08 100644
+--- a/fs/nls/nls_koi8-r.c
++++ b/fs/nls/nls_koi8-r.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_koi8-r.c
++ * linux/fs/nls/nls_koi8-r.c
+ *
+ * Charset koi8-r translation tables.
+ * Generated automatically from the Unicode and charset
+diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c
+index 5db83ef..e7bc1d7 100644
+--- a/fs/nls/nls_koi8-ru.c
++++ b/fs/nls/nls_koi8-ru.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_koi8-ru.c
++ * linux/fs/nls/nls_koi8-ru.c
+ *
+ * Charset koi8-ru translation based on charset koi8-u.
+ * The Unicode to charset table has only exact mappings.
+diff --git a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c
+index 9d30fd6..0150702 100644
+--- a/fs/nls/nls_koi8-u.c
++++ b/fs/nls/nls_koi8-u.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/fs/nls_koi8-u.c
++ * linux/fs/nls/nls_koi8-u.c
+ *
+ * Charset koi8-u translation tables.
+ * The Unicode to charset table has only exact mappings.
+diff --git a/fs/no-block.c b/fs/no-block.c
+new file mode 100644
+index 0000000..d269a93
+--- /dev/null
++++ b/fs/no-block.c
+@@ -0,0 +1,22 @@
++/* no-block.c: implementation of routines required for non-BLOCK configuration
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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/kernel.h>
++#include <linux/fs.h>
++
++static int no_blkdev_open(struct inode * inode, struct file * filp)
++{
++ return -ENODEV;
++}
++
++const struct file_operations def_blk_fops = {
++ .open = no_blkdev_open,
++};
+diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
+index bc579bf..7b2c8f4 100644
+--- a/fs/ntfs/aops.c
++++ b/fs/ntfs/aops.c
+@@ -254,7 +254,7 @@ static int ntfs_read_block(struct page *
+ bh->b_bdev = vol->sb->s_bdev;
+ /* Is the block within the allowed limits? */
+ if (iblock < lblock) {
+- BOOL is_retry = FALSE;
++ bool is_retry = false;
+
+ /* Convert iblock into corresponding vcn and offset. */
+ vcn = (VCN)iblock << blocksize_bits >>
+@@ -292,7 +292,7 @@ lock_retry_remap:
+ goto handle_hole;
+ /* If first try and runlist unmapped, map and retry. */
+ if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
+- is_retry = TRUE;
++ is_retry = true;
+ /*
+ * Attempt to map runlist, dropping lock for
+ * the duration.
+@@ -558,7 +558,7 @@ static int ntfs_write_block(struct page
+ unsigned long flags;
+ unsigned int blocksize, vcn_ofs;
+ int err;
+- BOOL need_end_writeback;
++ bool need_end_writeback;
+ unsigned char blocksize_bits;
+
+ vi = page->mapping->host;
+@@ -626,7 +626,7 @@ static int ntfs_write_block(struct page
+ rl = NULL;
+ err = 0;
+ do {
+- BOOL is_retry = FALSE;
++ bool is_retry = false;
+
+ if (unlikely(block >= dblock)) {
+ /*
+@@ -768,7 +768,7 @@ lock_retry_remap:
+ }
+ /* If first try and runlist unmapped, map and retry. */
+ if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
+- is_retry = TRUE;
++ is_retry = true;
+ /*
+ * Attempt to map runlist, dropping lock for
+ * the duration.
+@@ -874,12 +874,12 @@ lock_retry_remap:
+ set_page_writeback(page); /* Keeps try_to_free_buffers() away. */
+
+ /* Submit the prepared buffers for i/o. */
+- need_end_writeback = TRUE;
++ need_end_writeback = true;
+ do {
+ struct buffer_head *next = bh->b_this_page;
+ if (buffer_async_write(bh)) {
+ submit_bh(WRITE, bh);
+- need_end_writeback = FALSE;
++ need_end_writeback = false;
+ }
+ bh = next;
+ } while (bh != head);
+@@ -932,7 +932,7 @@ static int ntfs_write_mst_block(struct p
+ runlist_element *rl;
+ int i, nr_locked_nis, nr_recs, nr_bhs, max_bhs, bhs_per_rec, err, err2;
+ unsigned bh_size, rec_size_bits;
+- BOOL sync, is_mft, page_is_dirty, rec_is_dirty;
++ bool sync, is_mft, page_is_dirty, rec_is_dirty;
+ unsigned char bh_size_bits;
+
+ ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
+@@ -975,10 +975,10 @@ static int ntfs_write_mst_block(struct p
+
+ rl = NULL;
+ err = err2 = nr_bhs = nr_recs = nr_locked_nis = 0;
+- page_is_dirty = rec_is_dirty = FALSE;
++ page_is_dirty = rec_is_dirty = false;
+ rec_start_bh = NULL;
+ do {
+- BOOL is_retry = FALSE;
++ bool is_retry = false;
+
+ if (likely(block < rec_block)) {
+ if (unlikely(block >= dblock)) {
+@@ -1009,10 +1009,10 @@ static int ntfs_write_mst_block(struct p
+ }
+ if (!buffer_dirty(bh)) {
+ /* Clean records are not written out. */
+- rec_is_dirty = FALSE;
++ rec_is_dirty = false;
+ continue;
+ }
+- rec_is_dirty = TRUE;
++ rec_is_dirty = true;
+ rec_start_bh = bh;
+ }
+ /* Need to map the buffer if it is not mapped already. */
+@@ -1053,7 +1053,7 @@ lock_retry_remap:
+ */
+ if (!is_mft && !is_retry &&
+ lcn == LCN_RL_NOT_MAPPED) {
+- is_retry = TRUE;
++ is_retry = true;
+ /*
+ * Attempt to map runlist, dropping
+ * lock for the duration.
+@@ -1063,7 +1063,7 @@ lock_retry_remap:
+ if (likely(!err2))
+ goto lock_retry_remap;
+ if (err2 == -ENOMEM)
+- page_is_dirty = TRUE;
++ page_is_dirty = true;
+ lcn = err2;
+ } else {
+ err2 = -EIO;
+@@ -1145,7 +1145,7 @@ lock_retry_remap:
+ * means we need to redirty the page before
+ * returning.
+ */
+- page_is_dirty = TRUE;
++ page_is_dirty = true;
+ /*
+ * Remove the buffers in this mft record from
+ * the list of buffers to write.
+diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
+index 325ce26..9393f4b 100644
+--- a/fs/ntfs/aops.h
++++ b/fs/ntfs/aops.h
+@@ -80,7 +80,7 @@ static inline void ntfs_unmap_page(struc
+ *
+ * The unlocked and uptodate page is returned on success or an encoded error
+ * on failure. Caller has to test for error using the IS_ERR() macro on the
+- * return value. If that evaluates to TRUE, the negative error code can be
++ * return value. If that evaluates to 'true', the negative error code can be
+ * obtained using PTR_ERR() on the return value of ntfs_map_page().
+ */
+ static inline struct page *ntfs_map_page(struct address_space *mapping,
+diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
+index 6708e1d..9f08e85 100644
+--- a/fs/ntfs/attrib.c
++++ b/fs/ntfs/attrib.c
+@@ -67,7 +67,7 @@
+ * the attribute has zero allocated size, i.e. there simply is no runlist.
+ *
+ * WARNING: If @ctx is supplied, regardless of whether success or failure is
+- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
++ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
+ * is no longer valid, i.e. you need to either call
+ * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
+ * In that case PTR_ERR(@ctx->mrec) will give you the error code for
+@@ -90,7 +90,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *
+ runlist_element *rl;
+ struct page *put_this_page = NULL;
+ int err = 0;
+- BOOL ctx_is_temporary, ctx_needs_reset;
++ bool ctx_is_temporary, ctx_needs_reset;
+ ntfs_attr_search_ctx old_ctx = { NULL, };
+
+ ntfs_debug("Mapping runlist part containing vcn 0x%llx.",
+@@ -100,7 +100,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *
+ else
+ base_ni = ni->ext.base_ntfs_ino;
+ if (!ctx) {
+- ctx_is_temporary = ctx_needs_reset = TRUE;
++ ctx_is_temporary = ctx_needs_reset = true;
+ m = map_mft_record(base_ni);
+ if (IS_ERR(m))
+ return PTR_ERR(m);
+@@ -115,7 +115,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *
+ BUG_ON(IS_ERR(ctx->mrec));
+ a = ctx->attr;
+ BUG_ON(!a->non_resident);
+- ctx_is_temporary = FALSE;
++ ctx_is_temporary = false;
+ end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
+ read_lock_irqsave(&ni->size_lock, flags);
+ allocated_size_vcn = ni->allocated_size >>
+@@ -136,7 +136,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *
+ ni->name, ni->name_len) &&
+ sle64_to_cpu(a->data.non_resident.lowest_vcn)
+ <= vcn && end_vcn >= vcn))
+- ctx_needs_reset = FALSE;
++ ctx_needs_reset = false;
+ else {
+ /* Save the old search context. */
+ old_ctx = *ctx;
+@@ -158,7 +158,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *
+ * needed attribute extent.
+ */
+ ntfs_attr_reinit_search_ctx(ctx);
+- ctx_needs_reset = TRUE;
++ ctx_needs_reset = true;
+ }
+ }
+ if (ctx_needs_reset) {
+@@ -336,16 +336,16 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN
+ * LCN_EIO Critical error (runlist/file is corrupt, i/o error, etc).
+ *
+ * Locking: - The runlist must be locked on entry and is left locked on return.
+- * - If @write_locked is FALSE, i.e. the runlist is locked for reading,
++ * - If @write_locked is 'false', i.e. the runlist is locked for reading,
+ * the lock may be dropped inside the function so you cannot rely on
+ * the runlist still being the same when this function returns.
+ */
+ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
+- const BOOL write_locked)
++ const bool write_locked)
+ {
+ LCN lcn;
+ unsigned long flags;
+- BOOL is_retry = FALSE;
++ bool is_retry = false;
+
+ ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
+ ni->mft_no, (unsigned long long)vcn,
+@@ -390,7 +390,7 @@ retry_remap:
+ down_read(&ni->runlist.lock);
+ }
+ if (likely(!err)) {
+- is_retry = TRUE;
++ is_retry = true;
+ goto retry_remap;
+ }
+ if (err == -ENOENT)
+@@ -449,7 +449,7 @@ retry_remap:
+ * -EIO - Critical error (runlist/file is corrupt, i/o error, etc).
+ *
+ * WARNING: If @ctx is supplied, regardless of whether success or failure is
+- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
++ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
+ * is no longer valid, i.e. you need to either call
+ * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
+ * In that case PTR_ERR(@ctx->mrec) will give you the error code for
+@@ -469,7 +469,7 @@ runlist_element *ntfs_attr_find_vcn_nolo
+ unsigned long flags;
+ runlist_element *rl;
+ int err = 0;
+- BOOL is_retry = FALSE;
++ bool is_retry = false;
+
+ ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
+ ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
+@@ -518,7 +518,7 @@ retry_remap:
+ */
+ err = ntfs_map_runlist_nolock(ni, vcn, ctx);
+ if (likely(!err)) {
+- is_retry = TRUE;
++ is_retry = true;
+ goto retry_remap;
+ }
+ }
+@@ -558,8 +558,8 @@ retry_remap:
+ * On actual error, ntfs_attr_find() returns -EIO. In this case @ctx->attr is
+ * undefined and in particular do not rely on it not changing.
+ *
+- * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it
+- * is FALSE, the search begins after @ctx->attr.
++ * If @ctx->is_first is 'true', the search begins with @ctx->attr itself. If it
++ * is 'false', the search begins after @ctx->attr.
+ *
+ * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and
+ * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
+@@ -599,11 +599,11 @@ static int ntfs_attr_find(const ATTR_TYP
+
+ /*
+ * Iterate over attributes in mft record starting at @ctx->attr, or the
+- * attribute following that, if @ctx->is_first is TRUE.
++ * attribute following that, if @ctx->is_first is 'true'.
+ */
+ if (ctx->is_first) {
+ a = ctx->attr;
+- ctx->is_first = FALSE;
++ ctx->is_first = false;
+ } else
+ a = (ATTR_RECORD*)((u8*)ctx->attr +
+ le32_to_cpu(ctx->attr->length));
+@@ -890,11 +890,11 @@ static int ntfs_external_attr_find(const
+ ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
+ /*
+ * Iterate over entries in attribute list starting at @ctx->al_entry,
+- * or the entry following that, if @ctx->is_first is TRUE.
++ * or the entry following that, if @ctx->is_first is 'true'.
+ */
+ if (ctx->is_first) {
+ al_entry = ctx->al_entry;
+- ctx->is_first = FALSE;
++ ctx->is_first = false;
+ } else
+ al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
+ le16_to_cpu(ctx->al_entry->length));
+@@ -1127,7 +1127,7 @@ not_found:
+ ctx->mrec = ctx->base_mrec;
+ ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
+ le16_to_cpu(ctx->mrec->attrs_offset));
+- ctx->is_first = TRUE;
++ ctx->is_first = true;
+ ctx->ntfs_ino = base_ni;
+ ctx->base_ntfs_ino = NULL;
+ ctx->base_mrec = NULL;
+@@ -1224,7 +1224,7 @@ static inline void ntfs_attr_init_search
+ /* Sanity checks are performed elsewhere. */
+ .attr = (ATTR_RECORD*)((u8*)mrec +
+ le16_to_cpu(mrec->attrs_offset)),
+- .is_first = TRUE,
++ .is_first = true,
+ .ntfs_ino = ni,
+ };
+ }
+@@ -1243,7 +1243,7 @@ void ntfs_attr_reinit_search_ctx(ntfs_at
+ {
+ if (likely(!ctx->base_ntfs_ino)) {
+ /* No attribute list. */
+- ctx->is_first = TRUE;
++ ctx->is_first = true;
+ /* Sanity checks are performed elsewhere. */
+ ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
+ le16_to_cpu(ctx->mrec->attrs_offset));
+@@ -1585,7 +1585,7 @@ int ntfs_attr_make_non_resident(ntfs_ino
+ return -ENOMEM;
+ /* Start by allocating clusters to hold the attribute value. */
+ rl = ntfs_cluster_alloc(vol, 0, new_size >>
+- vol->cluster_size_bits, -1, DATA_ZONE, TRUE);
++ vol->cluster_size_bits, -1, DATA_ZONE, true);
+ if (IS_ERR(rl)) {
+ err = PTR_ERR(rl);
+ ntfs_debug("Failed to allocate cluster%s, error code "
+@@ -1919,7 +1919,7 @@ s64 ntfs_attr_extend_allocation(ntfs_ino
+ unsigned long flags;
+ int err, mp_size;
+ u32 attr_len = 0; /* Silence stupid gcc warning. */
+- BOOL mp_rebuilt;
++ bool mp_rebuilt;
+
+ #ifdef NTFS_DEBUG
+ read_lock_irqsave(&ni->size_lock, flags);
+@@ -2222,7 +2222,7 @@ first_alloc:
+ rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits,
+ (new_alloc_size - allocated_size) >>
+ vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ?
+- rl->lcn + rl->length : -1, DATA_ZONE, TRUE);
++ rl->lcn + rl->length : -1, DATA_ZONE, true);
+ if (IS_ERR(rl2)) {
+ err = PTR_ERR(rl2);
+ if (start < 0 || start >= allocated_size)
+@@ -2265,7 +2265,7 @@ first_alloc:
+ BUG_ON(!rl2);
+ BUG_ON(!rl2->length);
+ BUG_ON(rl2->lcn < LCN_HOLE);
+- mp_rebuilt = FALSE;
++ mp_rebuilt = false;
+ /* Get the size for the new mapping pairs array for this extent. */
+ mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
+ if (unlikely(mp_size <= 0)) {
+@@ -2300,7 +2300,7 @@ first_alloc:
+ err = -EOPNOTSUPP;
+ goto undo_alloc;
+ }
+- mp_rebuilt = TRUE;
++ mp_rebuilt = true;
+ /* Generate the mapping pairs array directly into the attr record. */
+ err = ntfs_mapping_pairs_build(vol, (u8*)a +
+ le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
+diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h
+index 9074886..3c8b74c 100644
+--- a/fs/ntfs/attrib.h
++++ b/fs/ntfs/attrib.h
+@@ -40,10 +40,10 @@
+ * Structure must be initialized to zero before the first call to one of the
+ * attribute search functions. Initialize @mrec to point to the mft record to
+ * search, and @attr to point to the first attribute within @mrec (not necessary
+- * if calling the _first() functions), and set @is_first to TRUE (not necessary
++ * if calling the _first() functions), and set @is_first to 'true' (not necessary
+ * if calling the _first() functions).
+ *
+- * If @is_first is TRUE, the search begins with @attr. If @is_first is FALSE,
++ * If @is_first is 'true', the search begins with @attr. If @is_first is 'false',
+ * the search begins after @attr. This is so that, after the first call to one
+ * of the search attribute functions, we can call the function again, without
+ * any modification of the search context, to automagically get the next
+@@ -52,7 +52,7 @@
+ typedef struct {
+ MFT_RECORD *mrec;
+ ATTR_RECORD *attr;
+- BOOL is_first;
++ bool is_first;
+ ntfs_inode *ntfs_ino;
+ ATTR_LIST_ENTRY *al_entry;
+ ntfs_inode *base_ntfs_ino;
+@@ -65,7 +65,7 @@ extern int ntfs_map_runlist_nolock(ntfs_
+ extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
+
+ extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
+- const BOOL write_locked);
++ const bool write_locked);
+
+ extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
+ const VCN vcn, ntfs_attr_search_ctx *ctx);
+diff --git a/fs/ntfs/bitmap.c b/fs/ntfs/bitmap.c
+index 7a190cd..0809cf8 100644
+--- a/fs/ntfs/bitmap.c
++++ b/fs/ntfs/bitmap.c
+@@ -34,18 +34,18 @@
+ * @start_bit: first bit to set
+ * @count: number of bits to set
+ * @value: value to set the bits to (i.e. 0 or 1)
+- * @is_rollback: if TRUE this is a rollback operation
++ * @is_rollback: if 'true' this is a rollback operation
+ *
+ * Set @count bits starting at bit @start_bit in the bitmap described by the
+ * vfs inode @vi to @value, where @value is either 0 or 1.
+ *
+- * @is_rollback should always be FALSE, it is for internal use to rollback
++ * @is_rollback should always be 'false', it is for internal use to rollback
+ * errors. You probably want to use ntfs_bitmap_set_bits_in_run() instead.
+ *
+ * Return 0 on success and -errno on error.
+ */
+ int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
+- const s64 count, const u8 value, const BOOL is_rollback)
++ const s64 count, const u8 value, const bool is_rollback)
+ {
+ s64 cnt = count;
+ pgoff_t index, end_index;
+@@ -172,7 +172,7 @@ rollback:
+ return PTR_ERR(page);
+ if (count != cnt)
+ pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt,
+- value ? 0 : 1, TRUE);
++ value ? 0 : 1, true);
+ else
+ pos = 0;
+ if (!pos) {
+diff --git a/fs/ntfs/bitmap.h b/fs/ntfs/bitmap.h
+index bb50d6b..72c9ad8 100644
+--- a/fs/ntfs/bitmap.h
++++ b/fs/ntfs/bitmap.h
+@@ -30,7 +30,7 @@
+ #include "types.h"
+
+ extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
+- const s64 count, const u8 value, const BOOL is_rollback);
++ const s64 count, const u8 value, const bool is_rollback);
+
+ /**
+ * ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
+@@ -48,7 +48,7 @@ static inline int ntfs_bitmap_set_bits_i
+ const s64 start_bit, const s64 count, const u8 value)
+ {
+ return __ntfs_bitmap_set_bits_in_run(vi, start_bit, count, value,
+- FALSE);
++ false);
+ }
+
+ /**
+diff --git a/fs/ntfs/collate.h b/fs/ntfs/collate.h
+index e027f36..aba8334 100644
+--- a/fs/ntfs/collate.h
++++ b/fs/ntfs/collate.h
+@@ -26,7 +26,7 @@
+ #include "types.h"
+ #include "volume.h"
+
+-static inline BOOL ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
++static inline bool ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
+ int i;
+
+ /*
+@@ -35,12 +35,12 @@ static inline BOOL ntfs_is_collation_rul
+ * now.
+ */
+ if (unlikely(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG))
+- return FALSE;
++ return false;
+ i = le32_to_cpu(cr);
+ if (likely(((i >= 0) && (i <= 0x02)) ||
+ ((i >= 0x10) && (i <= 0x13))))
+- return TRUE;
+- return FALSE;
++ return true;
++ return false;
+ }
+
+ extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
+diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
+index 68a607f..d98daf5 100644
+--- a/fs/ntfs/compress.c
++++ b/fs/ntfs/compress.c
+@@ -600,7 +600,7 @@ do_next_cb:
+ rl = NULL;
+ for (vcn = start_vcn, start_vcn += cb_clusters; vcn < start_vcn;
+ vcn++) {
+- BOOL is_retry = FALSE;
++ bool is_retry = false;
+
+ if (!rl) {
+ lock_retry_remap:
+@@ -626,7 +626,7 @@ lock_retry_remap:
+ break;
+ if (is_retry || lcn != LCN_RL_NOT_MAPPED)
+ goto rl_err;
+- is_retry = TRUE;
++ is_retry = true;
+ /*
+ * Attempt to map runlist, dropping lock for the
+ * duration.
+diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
+index d1e2c6f..85c36b8 100644
+--- a/fs/ntfs/dir.c
++++ b/fs/ntfs/dir.c
+@@ -1149,8 +1149,7 @@ static int ntfs_readdir(struct file *fil
+ * Allocate a buffer to store the current name being processed
+ * converted to format determined by current NLS.
+ */
+- name = (u8*)kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1,
+- GFP_NOFS);
++ name = kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1, GFP_NOFS);
+ if (unlikely(!name)) {
+ err = -ENOMEM;
+ goto err_out;
+@@ -1191,7 +1190,7 @@ static int ntfs_readdir(struct file *fil
+ * map the mft record without deadlocking.
+ */
+ rc = le32_to_cpu(ctx->attr->data.resident.value_length);
+- ir = (INDEX_ROOT*)kmalloc(rc, GFP_NOFS);
++ ir = kmalloc(rc, GFP_NOFS);
+ if (unlikely(!ir)) {
+ err = -ENOMEM;
+ goto err_out;
+diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
+index 2e42c2d..ae2fe00 100644
+--- a/fs/ntfs/file.c
++++ b/fs/ntfs/file.c
+@@ -509,7 +509,7 @@ static int ntfs_prepare_pages_for_non_re
+ u32 attr_rec_len = 0;
+ unsigned blocksize, u;
+ int err, mp_size;
+- BOOL rl_write_locked, was_hole, is_retry;
++ bool rl_write_locked, was_hole, is_retry;
+ unsigned char blocksize_bits;
+ struct {
+ u8 runlist_merged:1;
+@@ -543,13 +543,13 @@ static int ntfs_prepare_pages_for_non_re
+ return -ENOMEM;
+ }
+ } while (++u < nr_pages);
+- rl_write_locked = FALSE;
++ rl_write_locked = false;
+ rl = NULL;
+ err = 0;
+ vcn = lcn = -1;
+ vcn_len = 0;
+ lcn_block = -1;
+- was_hole = FALSE;
++ was_hole = false;
+ cpos = pos >> vol->cluster_size_bits;
+ end = pos + bytes;
+ cend = (end + vol->cluster_size - 1) >> vol->cluster_size_bits;
+@@ -760,7 +760,7 @@ map_buffer_cached:
+ }
+ continue;
+ }
+- is_retry = FALSE;
++ is_retry = false;
+ if (!rl) {
+ down_read(&ni->runlist.lock);
+ retry_remap:
+@@ -776,7 +776,7 @@ retry_remap:
+ * Successful remap, setup the map cache and
+ * use that to deal with the buffer.
+ */
+- was_hole = FALSE;
++ was_hole = false;
+ vcn = bh_cpos;
+ vcn_len = rl[1].vcn - vcn;
+ lcn_block = lcn << (vol->cluster_size_bits -
+@@ -792,7 +792,7 @@ retry_remap:
+ if (likely(vcn + vcn_len >= cend)) {
+ if (rl_write_locked) {
+ up_write(&ni->runlist.lock);
+- rl_write_locked = FALSE;
++ rl_write_locked = false;
+ } else
+ up_read(&ni->runlist.lock);
+ rl = NULL;
+@@ -818,13 +818,13 @@ retry_remap:
+ */
+ up_read(&ni->runlist.lock);
+ down_write(&ni->runlist.lock);
+- rl_write_locked = TRUE;
++ rl_write_locked = true;
+ goto retry_remap;
+ }
+ err = ntfs_map_runlist_nolock(ni, bh_cpos,
+ NULL);
+ if (likely(!err)) {
+- is_retry = TRUE;
++ is_retry = true;
+ goto retry_remap;
+ }
+ /*
+@@ -903,7 +903,7 @@ rl_not_mapped_enoent:
+ if (!rl_write_locked) {
+ up_read(&ni->runlist.lock);
+ down_write(&ni->runlist.lock);
+- rl_write_locked = TRUE;
++ rl_write_locked = true;
+ goto retry_remap;
+ }
+ /* Find the previous last allocated cluster. */
+@@ -917,7 +917,7 @@ rl_not_mapped_enoent:
+ }
+ }
+ rl2 = ntfs_cluster_alloc(vol, bh_cpos, 1, lcn, DATA_ZONE,
+- FALSE);
++ false);
+ if (IS_ERR(rl2)) {
+ err = PTR_ERR(rl2);
+ ntfs_debug("Failed to allocate cluster, error code %i.",
+@@ -1093,7 +1093,7 @@ rl_not_mapped_enoent:
+ status.mft_attr_mapped = 0;
+ status.mp_rebuilt = 0;
+ /* Setup the map cache and use that to deal with the buffer. */
+- was_hole = TRUE;
++ was_hole = true;
+ vcn = bh_cpos;
+ vcn_len = 1;
+ lcn_block = lcn << (vol->cluster_size_bits - blocksize_bits);
+@@ -1105,7 +1105,7 @@ rl_not_mapped_enoent:
+ */
+ if (likely(vcn + vcn_len >= cend)) {
+ up_write(&ni->runlist.lock);
+- rl_write_locked = FALSE;
++ rl_write_locked = false;
+ rl = NULL;
+ }
+ goto map_buffer_cached;
+@@ -1117,7 +1117,7 @@ rl_not_mapped_enoent:
+ if (likely(!err)) {
+ if (unlikely(rl_write_locked)) {
+ up_write(&ni->runlist.lock);
+- rl_write_locked = FALSE;
++ rl_write_locked = false;
+ } else if (unlikely(rl))
+ up_read(&ni->runlist.lock);
+ rl = NULL;
+@@ -1528,19 +1528,19 @@ static inline int ntfs_commit_pages_afte
+ do {
+ s64 bh_pos;
+ struct page *page;
+- BOOL partial;
++ bool partial;
+
+ page = pages[u];
+ bh_pos = (s64)page->index << PAGE_CACHE_SHIFT;
+ bh = head = page_buffers(page);
+- partial = FALSE;
++ partial = false;
+ do {
+ s64 bh_end;
+
+ bh_end = bh_pos + blocksize;
+ if (bh_end <= pos || bh_pos >= end) {
+ if (!buffer_uptodate(bh))
+- partial = TRUE;
++ partial = true;
+ } else {
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+@@ -1997,7 +1997,7 @@ static ssize_t ntfs_file_buffered_write(
+ */
+ down_read(&ni->runlist.lock);
+ lcn = ntfs_attr_vcn_to_lcn_nolock(ni, pos >>
+- vol->cluster_size_bits, FALSE);
++ vol->cluster_size_bits, false);
+ up_read(&ni->runlist.lock);
+ if (unlikely(lcn < LCN_HOLE)) {
+ status = -EIO;
+@@ -2176,20 +2176,18 @@ out:
+ /**
+ * ntfs_file_aio_write -
+ */
+-static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos)
++static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ ssize_t ret;
+- struct iovec local_iov = { .iov_base = (void __user *)buf,
+- .iov_len = count };
+
+ BUG_ON(iocb->ki_pos != pos);
+
+ mutex_lock(&inode->i_mutex);
+- ret = ntfs_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
++ ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos);
+ mutex_unlock(&inode->i_mutex);
+ if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+ int err = sync_page_range(inode, mapping, pos, ret);
+@@ -2298,13 +2296,11 @@ static int ntfs_file_fsync(struct file *
+
+ const struct file_operations ntfs_file_ops = {
+ .llseek = generic_file_llseek, /* Seek inside file. */
+- .read = generic_file_read, /* Read from file. */
++ .read = do_sync_read, /* Read from file. */
+ .aio_read = generic_file_aio_read, /* Async read from file. */
+- .readv = generic_file_readv, /* Read from file. */
+ #ifdef NTFS_RW
+ .write = ntfs_file_write, /* Write to file. */
+ .aio_write = ntfs_file_aio_write, /* Async write to file. */
+- .writev = ntfs_file_writev, /* Write to file. */
+ /*.release = ,*/ /* Last file is closed. See
+ fs/ext2/file.c::
+ ext2_release_file() for
+diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
+index 9f5427c..e32cde4 100644
+--- a/fs/ntfs/index.c
++++ b/fs/ntfs/index.c
+@@ -204,7 +204,7 @@ int ntfs_index_lookup(const void *key, c
+ if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
+ &ie->key, key_len)) {
+ ir_done:
+- ictx->is_in_root = TRUE;
++ ictx->is_in_root = true;
+ ictx->ir = ir;
+ ictx->actx = actx;
+ ictx->base_ni = base_ni;
+@@ -374,7 +374,7 @@ fast_descend_into_child_node:
+ if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
+ &ie->key, key_len)) {
+ ia_done:
+- ictx->is_in_root = FALSE;
++ ictx->is_in_root = false;
+ ictx->actx = NULL;
+ ictx->base_ni = NULL;
+ ictx->ia = ia;
+diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
+index 846a489..8745469 100644
+--- a/fs/ntfs/index.h
++++ b/fs/ntfs/index.h
+@@ -37,12 +37,12 @@
+ * @entry: index entry (points into @ir or @ia)
+ * @data: index entry data (points into @entry)
+ * @data_len: length in bytes of @data
+- * @is_in_root: TRUE if @entry is in @ir and FALSE if it is in @ia
++ * @is_in_root: 'true' if @entry is in @ir and 'false' if it is in @ia
+ * @ir: index root if @is_in_root and NULL otherwise
+ * @actx: attribute search context if @is_in_root and NULL otherwise
+ * @base_ni: base inode if @is_in_root and NULL otherwise
+- * @ia: index block if @is_in_root is FALSE and NULL otherwise
+- * @page: page if @is_in_root is FALSE and NULL otherwise
++ * @ia: index block if @is_in_root is 'false' and NULL otherwise
++ * @page: page if @is_in_root is 'false' and NULL otherwise
+ *
+ * @idx_ni is the index inode this context belongs to.
+ *
+@@ -50,11 +50,11 @@
+ * are the index entry data and its length in bytes, respectively. @data
+ * simply points into @entry. This is probably what the user is interested in.
+ *
+- * If @is_in_root is TRUE, @entry is in the index root attribute @ir described
++ * If @is_in_root is 'true', @entry is in the index root attribute @ir described
+ * by the attribute search context @actx and the base inode @base_ni. @ia and
+ * @page are NULL in this case.
+ *
+- * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia
++ * If @is_in_root is 'false', @entry is in the index allocation attribute and @ia
+ * and @page point to the index allocation block and the mapped, locked page it
+ * is in, respectively. @ir, @actx and @base_ni are NULL in this case.
+ *
+@@ -77,7 +77,7 @@ typedef struct {
+ INDEX_ENTRY *entry;
+ void *data;
+ u16 data_len;
+- BOOL is_in_root;
++ bool is_in_root;
+ INDEX_ROOT *ir;
+ ntfs_attr_search_ctx *actx;
+ ntfs_inode *base_ni;
+diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
+index d313f35..2d3de9c 100644
+--- a/fs/ntfs/inode.c
++++ b/fs/ntfs/inode.c
+@@ -137,7 +137,7 @@ static int ntfs_init_locked_inode(struct
+
+ BUG_ON(!na->name);
+ i = na->name_len * sizeof(ntfschar);
+- ni->name = (ntfschar*)kmalloc(i + sizeof(ntfschar), GFP_ATOMIC);
++ ni->name = kmalloc(i + sizeof(ntfschar), GFP_ATOMIC);
+ if (!ni->name)
+ return -ENOMEM;
+ memcpy(ni->name, na->name, i);
+@@ -556,8 +556,6 @@ static int ntfs_read_locked_inode(struct
+
+ /* Setup the generic vfs inode parts now. */
+
+- /* This is the optimal IO size (for stat), not the fs block size. */
+- vi->i_blksize = PAGE_CACHE_SIZE;
+ /*
+ * This is for checking whether an inode has changed w.r.t. a file so
+ * that the file can be updated if necessary (compare with f_version).
+@@ -1234,7 +1232,6 @@ static int ntfs_read_locked_attr_inode(s
+ base_ni = NTFS_I(base_vi);
+
+ /* Just mirror the values from the base inode. */
+- vi->i_blksize = base_vi->i_blksize;
+ vi->i_version = base_vi->i_version;
+ vi->i_uid = base_vi->i_uid;
+ vi->i_gid = base_vi->i_gid;
+@@ -1504,7 +1501,6 @@ static int ntfs_read_locked_index_inode(
+ ni = NTFS_I(vi);
+ base_ni = NTFS_I(base_vi);
+ /* Just mirror the values from the base inode. */
+- vi->i_blksize = base_vi->i_blksize;
+ vi->i_version = base_vi->i_version;
+ vi->i_uid = base_vi->i_uid;
+ vi->i_gid = base_vi->i_gid;
+@@ -2305,7 +2301,7 @@ void ntfs_clear_big_inode(struct inode *
+ }
+ #ifdef NTFS_RW
+ if (NInoDirty(ni)) {
+- BOOL was_bad = (is_bad_inode(vi));
++ bool was_bad = (is_bad_inode(vi));
+
+ /* Committing the inode also commits all extent inodes. */
+ ntfs_commit_inode(vi);
+@@ -3019,7 +3015,7 @@ int ntfs_write_inode(struct inode *vi, i
+ MFT_RECORD *m;
+ STANDARD_INFORMATION *si;
+ int err = 0;
+- BOOL modified = FALSE;
++ bool modified = false;
+
+ ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "",
+ vi->i_ino);
+@@ -3061,7 +3057,7 @@ int ntfs_write_inode(struct inode *vi, i
+ sle64_to_cpu(si->last_data_change_time),
+ (long long)sle64_to_cpu(nt));
+ si->last_data_change_time = nt;
+- modified = TRUE;
++ modified = true;
+ }
+ nt = utc2ntfs(vi->i_ctime);
+ if (si->last_mft_change_time != nt) {
+@@ -3070,7 +3066,7 @@ int ntfs_write_inode(struct inode *vi, i
+ sle64_to_cpu(si->last_mft_change_time),
+ (long long)sle64_to_cpu(nt));
+ si->last_mft_change_time = nt;
+- modified = TRUE;
++ modified = true;
+ }
+ nt = utc2ntfs(vi->i_atime);
+ if (si->last_access_time != nt) {
+@@ -3079,7 +3075,7 @@ int ntfs_write_inode(struct inode *vi, i
+ (long long)sle64_to_cpu(si->last_access_time),
+ (long long)sle64_to_cpu(nt));
+ si->last_access_time = nt;
+- modified = TRUE;
++ modified = true;
+ }
+ /*
+ * If we just modified the standard information attribute we need to
+diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
+index d34b93c..1e38332 100644
+--- a/fs/ntfs/layout.h
++++ b/fs/ntfs/layout.h
+@@ -142,13 +142,13 @@ typedef le32 NTFS_RECORD_TYPE;
+ * operator! (-8
+ */
+
+-static inline BOOL __ntfs_is_magic(le32 x, NTFS_RECORD_TYPE r)
++static inline bool __ntfs_is_magic(le32 x, NTFS_RECORD_TYPE r)
+ {
+ return (x == r);
+ }
+ #define ntfs_is_magic(x, m) __ntfs_is_magic(x, magic_##m)
+
+-static inline BOOL __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
++static inline bool __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
+ {
+ return (*p == r);
+ }
+@@ -323,7 +323,7 @@ typedef le64 leMFT_REF;
+ #define MREF_LE(x) ((unsigned long)(le64_to_cpu(x) & MFT_REF_MASK_CPU))
+ #define MSEQNO_LE(x) ((u16)((le64_to_cpu(x) >> 48) & 0xffff))
+
+-#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? 1 : 0)
++#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? true : false)
+ #define ERR_MREF(x) ((u64)((s64)(x)))
+ #define MREF_ERR(x) ((int)((s64)(x)))
+
+diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c
+index 29cabf9..1711b71 100644
+--- a/fs/ntfs/lcnalloc.c
++++ b/fs/ntfs/lcnalloc.c
+@@ -76,7 +76,7 @@ int ntfs_cluster_free_from_rl_nolock(ntf
+ * @count: number of clusters to allocate
+ * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
+ * @zone: zone from which to allocate the clusters
+- * @is_extension: if TRUE, this is an attribute extension
++ * @is_extension: if 'true', this is an attribute extension
+ *
+ * Allocate @count clusters preferably starting at cluster @start_lcn or at the
+ * current allocator position if @start_lcn is -1, on the mounted ntfs volume
+@@ -87,11 +87,11 @@ int ntfs_cluster_free_from_rl_nolock(ntf
+ * @start_vcn specifies the vcn of the first allocated cluster. This makes
+ * merging the resulting runlist with the old runlist easier.
+ *
+- * If @is_extension is TRUE, the caller is allocating clusters to extend an
+- * attribute and if it is FALSE, the caller is allocating clusters to fill a
++ * If @is_extension is 'true', the caller is allocating clusters to extend an
++ * attribute and if it is 'false', the caller is allocating clusters to fill a
+ * hole in an attribute. Practically the difference is that if @is_extension
+- * is TRUE the returned runlist will be terminated with LCN_ENOENT and if
+- * @is_extension is FALSE the runlist will be terminated with
++ * is 'true' the returned runlist will be terminated with LCN_ENOENT and if
++ * @is_extension is 'false' the runlist will be terminated with
+ * LCN_RL_NOT_MAPPED.
+ *
+ * You need to check the return value with IS_ERR(). If this is false, the
+@@ -146,7 +146,7 @@ int ntfs_cluster_free_from_rl_nolock(ntf
+ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
+ const s64 count, const LCN start_lcn,
+ const NTFS_CLUSTER_ALLOCATION_ZONES zone,
+- const BOOL is_extension)
++ const bool is_extension)
+ {
+ LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
+ LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
+@@ -818,7 +818,7 @@ out:
+ * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
+ * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
+ *
+- * @is_rollback should always be FALSE, it is for internal use to rollback
++ * @is_rollback should always be 'false', it is for internal use to rollback
+ * errors. You probably want to use ntfs_cluster_free() instead.
+ *
+ * Note, __ntfs_cluster_free() does not modify the runlist, so you have to
+@@ -828,7 +828,7 @@ out:
+ * success and -errno on error.
+ *
+ * WARNING: If @ctx is supplied, regardless of whether success or failure is
+- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
++ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
+ * is no longer valid, i.e. you need to either call
+ * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
+ * In that case PTR_ERR(@ctx->mrec) will give you the error code for
+@@ -847,7 +847,7 @@ out:
+ * and it will be left mapped on return.
+ */
+ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,
+- ntfs_attr_search_ctx *ctx, const BOOL is_rollback)
++ ntfs_attr_search_ctx *ctx, const bool is_rollback)
+ {
+ s64 delta, to_free, total_freed, real_freed;
+ ntfs_volume *vol;
+@@ -999,7 +999,7 @@ err_out:
+ * If rollback fails, set the volume errors flag, emit an error
+ * message, and return the error code.
+ */
+- delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, TRUE);
++ delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, true);
+ if (delta < 0) {
+ ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving "
+ "inconsistent metadata! Unmount and run "
+diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
+index 72cbca7..2adb043 100644
+--- a/fs/ntfs/lcnalloc.h
++++ b/fs/ntfs/lcnalloc.h
+@@ -43,10 +43,10 @@ typedef enum {
+ extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
+ const VCN start_vcn, const s64 count, const LCN start_lcn,
+ const NTFS_CLUSTER_ALLOCATION_ZONES zone,
+- const BOOL is_extension);
++ const bool is_extension);
+
+ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
+- s64 count, ntfs_attr_search_ctx *ctx, const BOOL is_rollback);
++ s64 count, ntfs_attr_search_ctx *ctx, const bool is_rollback);
+
+ /**
+ * ntfs_cluster_free - free clusters on an ntfs volume
+@@ -86,7 +86,7 @@ extern s64 __ntfs_cluster_free(ntfs_inod
+ * success and -errno on error.
+ *
+ * WARNING: If @ctx is supplied, regardless of whether success or failure is
+- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
++ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
+ * is no longer valid, i.e. you need to either call
+ * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
+ * In that case PTR_ERR(@ctx->mrec) will give you the error code for
+@@ -107,7 +107,7 @@ extern s64 __ntfs_cluster_free(ntfs_inod
+ static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
+ s64 count, ntfs_attr_search_ctx *ctx)
+ {
+- return __ntfs_cluster_free(ni, start_vcn, count, ctx, FALSE);
++ return __ntfs_cluster_free(ni, start_vcn, count, ctx, false);
+ }
+
+ extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
+diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
+index 4af2ad1..acfed32 100644
+--- a/fs/ntfs/logfile.c
++++ b/fs/ntfs/logfile.c
+@@ -41,18 +41,18 @@
+ * @rp: restart page header to check
+ * @pos: position in @vi at which the restart page header resides
+ *
+- * Check the restart page header @rp for consistency and return TRUE if it is
+- * consistent and FALSE otherwise.
++ * Check the restart page header @rp for consistency and return 'true' if it is
++ * consistent and 'false' otherwise.
+ *
+ * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
+ * require the full restart page.
+ */
+-static BOOL ntfs_check_restart_page_header(struct inode *vi,
++static bool ntfs_check_restart_page_header(struct inode *vi,
+ RESTART_PAGE_HEADER *rp, s64 pos)
+ {
+ u32 logfile_system_page_size, logfile_log_page_size;
+ u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
+- BOOL have_usa = TRUE;
++ bool have_usa = true;
+
+ ntfs_debug("Entering.");
+ /*
+@@ -67,7 +67,7 @@ static BOOL ntfs_check_restart_page_head
+ (logfile_system_page_size - 1) ||
+ logfile_log_page_size & (logfile_log_page_size - 1)) {
+ ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * We must be either at !pos (1st restart page) or at pos = system page
+@@ -76,7 +76,7 @@ static BOOL ntfs_check_restart_page_head
+ if (pos && pos != logfile_system_page_size) {
+ ntfs_error(vi->i_sb, "Found restart area in incorrect "
+ "position in $LogFile.");
+- return FALSE;
++ return false;
+ }
+ /* We only know how to handle version 1.1. */
+ if (sle16_to_cpu(rp->major_ver) != 1 ||
+@@ -85,14 +85,14 @@ static BOOL ntfs_check_restart_page_head
+ "supported. (This driver supports version "
+ "1.1 only.)", (int)sle16_to_cpu(rp->major_ver),
+ (int)sle16_to_cpu(rp->minor_ver));
+- return FALSE;
++ return false;
+ }
+ /*
+ * If chkdsk has been run the restart page may not be protected by an
+ * update sequence array.
+ */
+ if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
+- have_usa = FALSE;
++ have_usa = false;
+ goto skip_usa_checks;
+ }
+ /* Verify the size of the update sequence array. */
+@@ -100,7 +100,7 @@ static BOOL ntfs_check_restart_page_head
+ if (usa_count != le16_to_cpu(rp->usa_count)) {
+ ntfs_error(vi->i_sb, "$LogFile restart page specifies "
+ "inconsistent update sequence array count.");
+- return FALSE;
++ return false;
+ }
+ /* Verify the position of the update sequence array. */
+ usa_ofs = le16_to_cpu(rp->usa_ofs);
+@@ -109,7 +109,7 @@ static BOOL ntfs_check_restart_page_head
+ usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
+ ntfs_error(vi->i_sb, "$LogFile restart page specifies "
+ "inconsistent update sequence array offset.");
+- return FALSE;
++ return false;
+ }
+ skip_usa_checks:
+ /*
+@@ -124,7 +124,7 @@ skip_usa_checks:
+ ra_ofs > logfile_system_page_size) {
+ ntfs_error(vi->i_sb, "$LogFile restart page specifies "
+ "inconsistent restart area offset.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
+@@ -133,10 +133,10 @@ skip_usa_checks:
+ if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
+ ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
+ "by chkdsk but a chkdsk LSN is specified.");
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -145,7 +145,7 @@ skip_usa_checks:
+ * @rp: restart page whose restart area to check
+ *
+ * Check the restart area of the restart page @rp for consistency and return
+- * TRUE if it is consistent and FALSE otherwise.
++ * 'true' if it is consistent and 'false' otherwise.
+ *
+ * This function assumes that the restart page header has already been
+ * consistency checked.
+@@ -153,7 +153,7 @@ skip_usa_checks:
+ * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
+ * require the full restart page.
+ */
+-static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
++static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
+ {
+ u64 file_size;
+ RESTART_AREA *ra;
+@@ -172,7 +172,7 @@ static BOOL ntfs_check_restart_area(stru
+ NTFS_BLOCK_SIZE - sizeof(u16)) {
+ ntfs_error(vi->i_sb, "$LogFile restart area specifies "
+ "inconsistent file offset.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * Now that we can access ra->client_array_offset, make sure everything
+@@ -186,7 +186,7 @@ static BOOL ntfs_check_restart_area(stru
+ ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) {
+ ntfs_error(vi->i_sb, "$LogFile restart area specifies "
+ "inconsistent client array offset.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * The restart area must end within the system page size both when
+@@ -203,7 +203,7 @@ static BOOL ntfs_check_restart_area(stru
+ "of the system page size specified by the "
+ "restart page header and/or the specified "
+ "restart area length is inconsistent.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * The ra->client_free_list and ra->client_in_use_list must be either
+@@ -218,7 +218,7 @@ static BOOL ntfs_check_restart_area(stru
+ le16_to_cpu(ra->log_clients))) {
+ ntfs_error(vi->i_sb, "$LogFile restart area specifies "
+ "overflowing client free and/or in use lists.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * Check ra->seq_number_bits against ra->file_size for consistency.
+@@ -233,24 +233,24 @@ static BOOL ntfs_check_restart_area(stru
+ if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) {
+ ntfs_error(vi->i_sb, "$LogFile restart area specifies "
+ "inconsistent sequence number bits.");
+- return FALSE;
++ return false;
+ }
+ /* The log record header length must be a multiple of 8. */
+ if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
+ le16_to_cpu(ra->log_record_header_length)) {
+ ntfs_error(vi->i_sb, "$LogFile restart area specifies "
+ "inconsistent log record header length.");
+- return FALSE;
++ return false;
+ }
+ /* Dito for the log page data offset. */
+ if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
+ le16_to_cpu(ra->log_page_data_offset)) {
+ ntfs_error(vi->i_sb, "$LogFile restart area specifies "
+ "inconsistent log page data offset.");
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -259,7 +259,7 @@ static BOOL ntfs_check_restart_area(stru
+ * @rp: restart page whose log client array to check
+ *
+ * Check the log client array of the restart page @rp for consistency and
+- * return TRUE if it is consistent and FALSE otherwise.
++ * return 'true' if it is consistent and 'false' otherwise.
+ *
+ * This function assumes that the restart page header and the restart area have
+ * already been consistency checked.
+@@ -268,13 +268,13 @@ static BOOL ntfs_check_restart_area(stru
+ * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
+ * restart page and the page must be multi sector transfer deprotected.
+ */
+-static BOOL ntfs_check_log_client_array(struct inode *vi,
++static bool ntfs_check_log_client_array(struct inode *vi,
+ RESTART_PAGE_HEADER *rp)
+ {
+ RESTART_AREA *ra;
+ LOG_CLIENT_RECORD *ca, *cr;
+ u16 nr_clients, idx;
+- BOOL in_free_list, idx_is_first;
++ bool in_free_list, idx_is_first;
+
+ ntfs_debug("Entering.");
+ ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
+@@ -290,9 +290,9 @@ static BOOL ntfs_check_log_client_array(
+ */
+ nr_clients = le16_to_cpu(ra->log_clients);
+ idx = le16_to_cpu(ra->client_free_list);
+- in_free_list = TRUE;
++ in_free_list = true;
+ check_list:
+- for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
++ for (idx_is_first = true; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
+ idx = le16_to_cpu(cr->next_client)) {
+ if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
+ goto err_out;
+@@ -302,20 +302,20 @@ check_list:
+ if (idx_is_first) {
+ if (cr->prev_client != LOGFILE_NO_CLIENT)
+ goto err_out;
+- idx_is_first = FALSE;
++ idx_is_first = false;
+ }
+ }
+ /* Switch to and check the in use list if we just did the free list. */
+ if (in_free_list) {
+- in_free_list = FALSE;
++ in_free_list = false;
+ idx = le16_to_cpu(ra->client_in_use_list);
+ goto check_list;
+ }
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ err_out:
+ ntfs_error(vi->i_sb, "$LogFile log client array is corrupt.");
+- return FALSE;
++ return false;
+ }
+
+ /**
+@@ -468,8 +468,8 @@ err_out:
+ * @log_vi: struct inode of loaded journal $LogFile to check
+ * @rp: [OUT] on success this is a copy of the current restart page
+ *
+- * Check the $LogFile journal for consistency and return TRUE if it is
+- * consistent and FALSE if not. On success, the current restart page is
++ * Check the $LogFile journal for consistency and return 'true' if it is
++ * consistent and 'false' if not. On success, the current restart page is
+ * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it.
+ *
+ * At present we only check the two restart pages and ignore the log record
+@@ -480,7 +480,7 @@ err_out:
+ * if the $LogFile was created on a system with a different page size to ours
+ * yet and mst deprotection would fail if our page size is smaller.
+ */
+-BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
++bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
+ {
+ s64 size, pos;
+ LSN rstr1_lsn, rstr2_lsn;
+@@ -491,7 +491,7 @@ BOOL ntfs_check_logfile(struct inode *lo
+ RESTART_PAGE_HEADER *rstr1_ph = NULL;
+ RESTART_PAGE_HEADER *rstr2_ph = NULL;
+ int log_page_size, log_page_mask, err;
+- BOOL logfile_is_empty = TRUE;
++ bool logfile_is_empty = true;
+ u8 log_page_bits;
+
+ ntfs_debug("Entering.");
+@@ -527,7 +527,7 @@ BOOL ntfs_check_logfile(struct inode *lo
+ if (size < log_page_size * 2 || (size - log_page_size * 2) >>
+ log_page_bits < MinLogRecordPages) {
+ ntfs_error(vol->sb, "$LogFile is too small.");
+- return FALSE;
++ return false;
+ }
+ /*
+ * Read through the file looking for a restart page. Since the restart
+@@ -556,7 +556,7 @@ BOOL ntfs_check_logfile(struct inode *lo
+ * means we are done.
+ */
+ if (!ntfs_is_empty_recordp((le32*)kaddr))
+- logfile_is_empty = FALSE;
++ logfile_is_empty = false;
+ else if (!logfile_is_empty)
+ break;
+ /*
+@@ -615,13 +615,13 @@ BOOL ntfs_check_logfile(struct inode *lo
+ NVolSetLogFileEmpty(vol);
+ is_empty:
+ ntfs_debug("Done. ($LogFile is empty.)");
+- return TRUE;
++ return true;
+ }
+ if (!rstr1_ph) {
+ BUG_ON(rstr2_ph);
+ ntfs_error(vol->sb, "Did not find any restart pages in "
+ "$LogFile and it was not empty.");
+- return FALSE;
++ return false;
+ }
+ /* If both restart pages were found, use the more recent one. */
+ if (rstr2_ph) {
+@@ -648,11 +648,11 @@ is_empty:
+ else
+ ntfs_free(rstr1_ph);
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ err_out:
+ if (rstr1_ph)
+ ntfs_free(rstr1_ph);
+- return FALSE;
++ return false;
+ }
+
+ /**
+@@ -660,8 +660,8 @@ err_out:
+ * @log_vi: struct inode of loaded journal $LogFile to check
+ * @rp: copy of the current restart page
+ *
+- * Analyze the $LogFile journal and return TRUE if it indicates the volume was
+- * shutdown cleanly and FALSE if not.
++ * Analyze the $LogFile journal and return 'true' if it indicates the volume was
++ * shutdown cleanly and 'false' if not.
+ *
+ * At present we only look at the two restart pages and ignore the log record
+ * pages. This is a little bit crude in that there will be a very small number
+@@ -675,7 +675,7 @@ err_out:
+ * is empty this function requires that NVolLogFileEmpty() is true otherwise an
+ * empty volume will be reported as dirty.
+ */
+-BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
++bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
+ {
+ ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+ RESTART_AREA *ra;
+@@ -684,7 +684,7 @@ BOOL ntfs_is_logfile_clean(struct inode
+ /* An empty $LogFile must have been clean before it got emptied. */
+ if (NVolLogFileEmpty(vol)) {
+ ntfs_debug("Done. ($LogFile is empty.)");
+- return TRUE;
++ return true;
+ }
+ BUG_ON(!rp);
+ if (!ntfs_is_rstr_record(rp->magic) &&
+@@ -693,7 +693,7 @@ BOOL ntfs_is_logfile_clean(struct inode
+ "probably a bug in that the $LogFile should "
+ "have been consistency checked before calling "
+ "this function.");
+- return FALSE;
++ return false;
+ }
+ ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
+ /*
+@@ -704,25 +704,25 @@ BOOL ntfs_is_logfile_clean(struct inode
+ if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
+ !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
+ ntfs_debug("Done. $LogFile indicates a dirty shutdown.");
+- return FALSE;
++ return false;
+ }
+ /* $LogFile indicates a clean shutdown. */
+ ntfs_debug("Done. $LogFile indicates a clean shutdown.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+ * ntfs_empty_logfile - empty the contents of the $LogFile journal
+ * @log_vi: struct inode of loaded journal $LogFile to empty
+ *
+- * Empty the contents of the $LogFile journal @log_vi and return TRUE on
+- * success and FALSE on error.
++ * Empty the contents of the $LogFile journal @log_vi and return 'true' on
++ * success and 'false' on error.
+ *
+ * This function assumes that the $LogFile journal has already been consistency
+ * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
+ * has been used to ensure that the $LogFile is clean.
+ */
+-BOOL ntfs_empty_logfile(struct inode *log_vi)
++bool ntfs_empty_logfile(struct inode *log_vi)
+ {
+ ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+
+@@ -735,13 +735,13 @@ BOOL ntfs_empty_logfile(struct inode *lo
+ if (unlikely(err)) {
+ ntfs_error(vol->sb, "Failed to fill $LogFile with "
+ "0xff bytes (error code %i).", err);
+- return FALSE;
++ return false;
+ }
+ /* Set the flag so we do not have to do it again on remount. */
+ NVolSetLogFileEmpty(vol);
+ }
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ #endif /* NTFS_RW */
+diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h
+index a51f3dd..9468e1c 100644
+--- a/fs/ntfs/logfile.h
++++ b/fs/ntfs/logfile.h
+@@ -296,13 +296,13 @@ typedef struct {
+ /* sizeof() = 160 (0xa0) bytes */
+ } __attribute__ ((__packed__)) LOG_CLIENT_RECORD;
+
+-extern BOOL ntfs_check_logfile(struct inode *log_vi,
++extern bool ntfs_check_logfile(struct inode *log_vi,
+ RESTART_PAGE_HEADER **rp);
+
+-extern BOOL ntfs_is_logfile_clean(struct inode *log_vi,
++extern bool ntfs_is_logfile_clean(struct inode *log_vi,
+ const RESTART_PAGE_HEADER *rp);
+
+-extern BOOL ntfs_empty_logfile(struct inode *log_vi);
++extern bool ntfs_empty_logfile(struct inode *log_vi);
+
+ #endif /* NTFS_RW */
+
+diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
+index 2438c00..2ad5c8b 100644
+--- a/fs/ntfs/mft.c
++++ b/fs/ntfs/mft.c
+@@ -251,7 +251,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_i
+ int i;
+ unsigned long mft_no = MREF(mref);
+ u16 seq_no = MSEQNO(mref);
+- BOOL destroy_ni = FALSE;
++ bool destroy_ni = false;
+
+ ntfs_debug("Mapping extent mft record 0x%lx (base mft record 0x%lx).",
+ mft_no, base_ni->mft_no);
+@@ -322,7 +322,7 @@ map_err_out:
+ if (seq_no && (le16_to_cpu(m->sequence_number) != seq_no)) {
+ ntfs_error(base_ni->vol->sb, "Found stale extent mft "
+ "reference! Corrupt filesystem. Run chkdsk.");
+- destroy_ni = TRUE;
++ destroy_ni = true;
+ m = ERR_PTR(-EIO);
+ goto unm_err_out;
+ }
+@@ -331,11 +331,11 @@ map_err_out:
+ ntfs_inode **tmp;
+ int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
+
+- tmp = (ntfs_inode **)kmalloc(new_size, GFP_NOFS);
++ tmp = kmalloc(new_size, GFP_NOFS);
+ if (unlikely(!tmp)) {
+ ntfs_error(base_ni->vol->sb, "Failed to allocate "
+ "internal buffer.");
+- destroy_ni = TRUE;
++ destroy_ni = true;
+ m = ERR_PTR(-ENOMEM);
+ goto unm_err_out;
+ }
+@@ -857,7 +857,7 @@ err_out:
+ * caller is responsible for unlocking the ntfs inode and unpinning the base
+ * vfs inode.
+ *
+- * Return TRUE if the mft record may be written out and FALSE if not.
++ * Return 'true' if the mft record may be written out and 'false' if not.
+ *
+ * The caller has locked the page and cleared the uptodate flag on it which
+ * means that we can safely write out any dirty mft records that do not have
+@@ -868,7 +868,7 @@ err_out:
+ * Here is a description of the tests we perform:
+ *
+ * If the inode is found in icache we know the mft record must be a base mft
+- * record. If it is dirty, we do not write it and return FALSE as the vfs
++ * record. If it is dirty, we do not write it and return 'false' as the vfs
+ * inode write paths will result in the access times being updated which would
+ * cause the base mft record to be redirtied and written out again. (We know
+ * the access time update will modify the base mft record because Windows
+@@ -877,11 +877,11 @@ err_out:
+ *
+ * If the inode is in icache and not dirty, we attempt to lock the mft record
+ * and if we find the lock was already taken, it is not safe to write the mft
+- * record and we return FALSE.
++ * record and we return 'false'.
+ *
+ * If we manage to obtain the lock we have exclusive access to the mft record,
+ * which also allows us safe writeout of the mft record. We then set
+- * @locked_ni to the locked ntfs inode and return TRUE.
++ * @locked_ni to the locked ntfs inode and return 'true'.
+ *
+ * Note we cannot just lock the mft record and sleep while waiting for the lock
+ * because this would deadlock due to lock reversal (normally the mft record is
+@@ -891,24 +891,24 @@ err_out:
+ * If the inode is not in icache we need to perform further checks.
+ *
+ * If the mft record is not a FILE record or it is a base mft record, we can
+- * safely write it and return TRUE.
++ * safely write it and return 'true'.
+ *
+ * We now know the mft record is an extent mft record. We check if the inode
+ * corresponding to its base mft record is in icache and obtain a reference to
+- * it if it is. If it is not, we can safely write it and return TRUE.
++ * it if it is. If it is not, we can safely write it and return 'true'.
+ *
+ * We now have the base inode for the extent mft record. We check if it has an
+ * ntfs inode for the extent mft record attached and if not it is safe to write
+- * the extent mft record and we return TRUE.
++ * the extent mft record and we return 'true'.
+ *
+ * The ntfs inode for the extent mft record is attached to the base inode so we
+ * attempt to lock the extent mft record and if we find the lock was already
+- * taken, it is not safe to write the extent mft record and we return FALSE.
++ * taken, it is not safe to write the extent mft record and we return 'false'.
+ *
+ * If we manage to obtain the lock we have exclusive access to the extent mft
+ * record, which also allows us safe writeout of the extent mft record. We
+ * set the ntfs inode of the extent mft record clean and then set @locked_ni to
+- * the now locked ntfs inode and return TRUE.
++ * the now locked ntfs inode and return 'true'.
+ *
+ * Note, the reason for actually writing dirty mft records here and not just
+ * relying on the vfs inode dirty code paths is that we can have mft records
+@@ -922,7 +922,7 @@ err_out:
+ * appear if the mft record is reused for a new inode before it got written
+ * out.
+ */
+-BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
++bool ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
+ const MFT_RECORD *m, ntfs_inode **locked_ni)
+ {
+ struct super_block *sb = vol->sb;
+@@ -977,7 +977,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ mft_no);
+ atomic_dec(&ni->count);
+ iput(vi);
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
+ /* The inode is not dirty, try to take the mft record lock. */
+@@ -986,7 +986,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ "not write it.", mft_no);
+ atomic_dec(&ni->count);
+ iput(vi);
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("Managed to lock mft record 0x%lx, write it.",
+ mft_no);
+@@ -995,7 +995,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ * return the locked ntfs inode.
+ */
+ *locked_ni = ni;
+- return TRUE;
++ return true;
+ }
+ ntfs_debug("Inode 0x%lx is not in icache.", mft_no);
+ /* The inode is not in icache. */
+@@ -1003,13 +1003,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ if (!ntfs_is_mft_record(m->magic)) {
+ ntfs_debug("Mft record 0x%lx is not a FILE record, write it.",
+ mft_no);
+- return TRUE;
++ return true;
+ }
+ /* Write the mft record if it is a base inode. */
+ if (!m->base_mft_record) {
+ ntfs_debug("Mft record 0x%lx is a base record, write it.",
+ mft_no);
+- return TRUE;
++ return true;
+ }
+ /*
+ * This is an extent mft record. Check if the inode corresponding to
+@@ -1033,7 +1033,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ */
+ ntfs_debug("Base inode 0x%lx is not in icache, write the "
+ "extent record.", na.mft_no);
+- return TRUE;
++ return true;
+ }
+ ntfs_debug("Base inode 0x%lx is in icache.", na.mft_no);
+ /*
+@@ -1051,7 +1051,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ iput(vi);
+ ntfs_debug("Base inode 0x%lx has no attached extent inodes, "
+ "write the extent record.", na.mft_no);
+- return TRUE;
++ return true;
+ }
+ /* Iterate over the attached extent inodes. */
+ extent_nis = ni->ext.extent_ntfs_inos;
+@@ -1075,7 +1075,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ ntfs_debug("Extent inode 0x%lx is not attached to its base "
+ "inode 0x%lx, write the extent record.",
+ mft_no, na.mft_no);
+- return TRUE;
++ return true;
+ }
+ ntfs_debug("Extent inode 0x%lx is attached to its base inode 0x%lx.",
+ mft_no, na.mft_no);
+@@ -1091,7 +1091,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ iput(vi);
+ ntfs_debug("Extent mft record 0x%lx is already locked, do "
+ "not write it.", mft_no);
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("Managed to lock extent mft record 0x%lx, write it.",
+ mft_no);
+@@ -1103,7 +1103,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volu
+ * the locked extent ntfs inode.
+ */
+ *locked_ni = eni;
+- return TRUE;
++ return true;
+ }
+
+ static const char *es = " Leaving inconsistent metadata. Unmount and run "
+@@ -1354,7 +1354,7 @@ static int ntfs_mft_bitmap_extend_alloca
+ ntfs_unmap_page(page);
+ /* Allocate a cluster from the DATA_ZONE. */
+ rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE,
+- TRUE);
++ true);
+ if (IS_ERR(rl2)) {
+ up_write(&mftbmp_ni->runlist.lock);
+ ntfs_error(vol->sb, "Failed to allocate a cluster for "
+@@ -1724,7 +1724,7 @@ static int ntfs_mft_data_extend_allocati
+ ATTR_RECORD *a = NULL;
+ int ret, mp_size;
+ u32 old_alen = 0;
+- BOOL mp_rebuilt = FALSE;
++ bool mp_rebuilt = false;
+
+ ntfs_debug("Extending mft data allocation.");
+ mft_ni = NTFS_I(vol->mft_ino);
+@@ -1780,7 +1780,7 @@ static int ntfs_mft_data_extend_allocati
+ old_last_vcn = rl[1].vcn;
+ do {
+ rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE,
+- TRUE);
++ true);
+ if (likely(!IS_ERR(rl2)))
+ break;
+ if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) {
+@@ -1884,7 +1884,7 @@ static int ntfs_mft_data_extend_allocati
+ ret = -EOPNOTSUPP;
+ goto undo_alloc;
+ }
+- mp_rebuilt = TRUE;
++ mp_rebuilt = true;
+ /* Generate the mapping pairs array directly into the attr record. */
+ ret = ntfs_mapping_pairs_build(vol, (u8*)a +
+ le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
+@@ -2255,7 +2255,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_v
+ unsigned int ofs;
+ int err;
+ le16 seq_no, usn;
+- BOOL record_formatted = FALSE;
++ bool record_formatted = false;
+
+ if (base_ni) {
+ ntfs_debug("Entering (allocating an extent mft record for "
+@@ -2454,7 +2454,7 @@ have_alloc_rec:
+ mft_ni->initialized_size = new_initialized_size;
+ }
+ write_unlock_irqrestore(&mft_ni->size_lock, flags);
+- record_formatted = TRUE;
++ record_formatted = true;
+ /* Update the mft data attribute record to reflect the new sizes. */
+ m = map_mft_record(mft_ni);
+ if (IS_ERR(m)) {
+@@ -2638,11 +2638,6 @@ mft_rec_already_initialized:
+ }
+ vi->i_ino = bit;
+ /*
+- * This is the optimal IO size (for stat), not the fs block
+- * size.
+- */
+- vi->i_blksize = PAGE_CACHE_SIZE;
+- /*
+ * This is for checking whether an inode has changed w.r.t. a
+ * file so that the file can be updated if necessary (compare
+ * with f_version).
+@@ -2893,7 +2888,7 @@ rollback:
+ if (!(base_ni->nr_extents & 3)) {
+ int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*);
+
+- extent_nis = (ntfs_inode**)kmalloc(new_size, GFP_NOFS);
++ extent_nis = kmalloc(new_size, GFP_NOFS);
+ if (unlikely(!extent_nis)) {
+ ntfs_error(vol->sb, "Failed to allocate internal "
+ "buffer during rollback.%s", es);
+diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
+index 639cd1b..b52bf87 100644
+--- a/fs/ntfs/mft.h
++++ b/fs/ntfs/mft.h
+@@ -111,7 +111,7 @@ static inline int write_mft_record(ntfs_
+ return err;
+ }
+
+-extern BOOL ntfs_may_write_mft_record(ntfs_volume *vol,
++extern bool ntfs_may_write_mft_record(ntfs_volume *vol,
+ const unsigned long mft_no, const MFT_RECORD *m,
+ ntfs_inode **locked_ni);
+
+diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
+index ddd3d50..a12847a 100644
+--- a/fs/ntfs/ntfs.h
++++ b/fs/ntfs/ntfs.h
+@@ -105,7 +105,7 @@ extern int pre_write_mst_fixup(NTFS_RECO
+ extern void post_write_mst_fixup(NTFS_RECORD *b);
+
+ /* From fs/ntfs/unistr.c */
+-extern BOOL ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
++extern bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
+ const ntfschar *s2, size_t s2_len,
+ const IGNORE_CASE_BOOL ic,
+ const ntfschar *upcase, const u32 upcase_size);
+diff --git a/fs/ntfs/quota.c b/fs/ntfs/quota.c
+index d0ef418..d80e331 100644
+--- a/fs/ntfs/quota.c
++++ b/fs/ntfs/quota.c
+@@ -31,10 +31,10 @@
+ * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume
+ * @vol: ntfs volume on which to mark the quotas out of date
+ *
+- * Mark the quotas out of date on the ntfs volume @vol and return TRUE on
+- * success and FALSE on error.
++ * Mark the quotas out of date on the ntfs volume @vol and return 'true' on
++ * success and 'false' on error.
+ */
+-BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
++bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
+ {
+ ntfs_index_context *ictx;
+ QUOTA_CONTROL_ENTRY *qce;
+@@ -46,7 +46,7 @@ BOOL ntfs_mark_quotas_out_of_date(ntfs_v
+ goto done;
+ if (!vol->quota_ino || !vol->quota_q_ino) {
+ ntfs_error(vol->sb, "Quota inodes are not open.");
+- return FALSE;
++ return false;
+ }
+ mutex_lock(&vol->quota_q_ino->i_mutex);
+ ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino));
+@@ -106,12 +106,12 @@ set_done:
+ NVolSetQuotaOutOfDate(vol);
+ done:
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ err_out:
+ if (ictx)
+ ntfs_index_ctx_put(ictx);
+ mutex_unlock(&vol->quota_q_ino->i_mutex);
+- return FALSE;
++ return false;
+ }
+
+ #endif /* NTFS_RW */
+diff --git a/fs/ntfs/quota.h b/fs/ntfs/quota.h
+index 40e4763..4cbe559 100644
+--- a/fs/ntfs/quota.h
++++ b/fs/ntfs/quota.h
+@@ -28,7 +28,7 @@
+ #include "types.h"
+ #include "volume.h"
+
+-extern BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol);
++extern bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol);
+
+ #endif /* NTFS_RW */
+
+diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
+index eb52b80..9afd72c 100644
+--- a/fs/ntfs/runlist.c
++++ b/fs/ntfs/runlist.c
+@@ -149,10 +149,10 @@ static inline runlist_element *ntfs_rl_r
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ *
+- * Return: TRUE Success, the runlists can be merged.
+- * FALSE Failure, the runlists cannot be merged.
++ * Return: true Success, the runlists can be merged.
++ * false Failure, the runlists cannot be merged.
+ */
+-static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst,
++static inline bool ntfs_are_rl_mergeable(runlist_element *dst,
+ runlist_element *src)
+ {
+ BUG_ON(!dst);
+@@ -160,19 +160,19 @@ static inline BOOL ntfs_are_rl_mergeable
+
+ /* We can merge unmapped regions even if they are misaligned. */
+ if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED))
+- return TRUE;
++ return true;
+ /* If the runs are misaligned, we cannot merge them. */
+ if ((dst->vcn + dst->length) != src->vcn)
+- return FALSE;
++ return false;
+ /* If both runs are non-sparse and contiguous, we can merge them. */
+ if ((dst->lcn >= 0) && (src->lcn >= 0) &&
+ ((dst->lcn + dst->length) == src->lcn))
+- return TRUE;
++ return true;
+ /* If we are merging two holes, we can merge them. */
+ if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE))
+- return TRUE;
++ return true;
+ /* Cannot merge. */
+- return FALSE;
++ return false;
+ }
+
+ /**
+@@ -218,7 +218,7 @@ static inline void __ntfs_rl_merge(runli
+ static inline runlist_element *ntfs_rl_append(runlist_element *dst,
+ int dsize, runlist_element *src, int ssize, int loc)
+ {
+- BOOL right = FALSE; /* Right end of @src needs merging. */
++ bool right = false; /* Right end of @src needs merging. */
+ int marker; /* End of the inserted runs. */
+
+ BUG_ON(!dst);
+@@ -285,8 +285,8 @@ static inline runlist_element *ntfs_rl_a
+ static inline runlist_element *ntfs_rl_insert(runlist_element *dst,
+ int dsize, runlist_element *src, int ssize, int loc)
+ {
+- BOOL left = FALSE; /* Left end of @src needs merging. */
+- BOOL disc = FALSE; /* Discontinuity between @dst and @src. */
++ bool left = false; /* Left end of @src needs merging. */
++ bool disc = false; /* Discontinuity between @dst and @src. */
+ int marker; /* End of the inserted runs. */
+
+ BUG_ON(!dst);
+@@ -382,8 +382,8 @@ static inline runlist_element *ntfs_rl_r
+ int dsize, runlist_element *src, int ssize, int loc)
+ {
+ signed delta;
+- BOOL left = FALSE; /* Left end of @src needs merging. */
+- BOOL right = FALSE; /* Right end of @src needs merging. */
++ bool left = false; /* Left end of @src needs merging. */
++ bool right = false; /* Right end of @src needs merging. */
+ int tail; /* Start of tail of @dst. */
+ int marker; /* End of the inserted runs. */
+
+@@ -620,8 +620,8 @@ runlist_element *ntfs_runlists_merge(run
+ ;
+
+ {
+- BOOL start;
+- BOOL finish;
++ bool start;
++ bool finish;
+ int ds = dend + 1; /* Number of elements in drl & srl */
+ int ss = sfinal - sstart + 1;
+
+@@ -635,7 +635,7 @@ runlist_element *ntfs_runlists_merge(run
+ if (finish && !drl[dins].length)
+ ss++;
+ if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
+- finish = FALSE;
++ finish = false;
+ #if 0
+ ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
+ ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
+@@ -1134,7 +1134,7 @@ int ntfs_get_size_for_mapping_pairs(cons
+ {
+ LCN prev_lcn;
+ int rls;
+- BOOL the_end = FALSE;
++ bool the_end = false;
+
+ BUG_ON(first_vcn < 0);
+ BUG_ON(last_vcn < -1);
+@@ -1168,7 +1168,7 @@ int ntfs_get_size_for_mapping_pairs(cons
+ s64 s1 = last_vcn + 1;
+ if (unlikely(rl[1].vcn > s1))
+ length = s1 - rl->vcn;
+- the_end = TRUE;
++ the_end = true;
+ }
+ delta = first_vcn - rl->vcn;
+ /* Header byte + length. */
+@@ -1204,7 +1204,7 @@ int ntfs_get_size_for_mapping_pairs(cons
+ s64 s1 = last_vcn + 1;
+ if (unlikely(rl[1].vcn > s1))
+ length = s1 - rl->vcn;
+- the_end = TRUE;
++ the_end = true;
+ }
+ /* Header byte + length. */
+ rls += 1 + ntfs_get_nr_significant_bytes(length);
+@@ -1327,7 +1327,7 @@ int ntfs_mapping_pairs_build(const ntfs_
+ LCN prev_lcn;
+ s8 *dst_max, *dst_next;
+ int err = -ENOSPC;
+- BOOL the_end = FALSE;
++ bool the_end = false;
+ s8 len_len, lcn_len;
+
+ BUG_ON(first_vcn < 0);
+@@ -1370,7 +1370,7 @@ int ntfs_mapping_pairs_build(const ntfs_
+ s64 s1 = last_vcn + 1;
+ if (unlikely(rl[1].vcn > s1))
+ length = s1 - rl->vcn;
+- the_end = TRUE;
++ the_end = true;
+ }
+ delta = first_vcn - rl->vcn;
+ /* Write length. */
+@@ -1422,7 +1422,7 @@ int ntfs_mapping_pairs_build(const ntfs_
+ s64 s1 = last_vcn + 1;
+ if (unlikely(rl[1].vcn > s1))
+ length = s1 - rl->vcn;
+- the_end = TRUE;
++ the_end = true;
+ }
+ /* Write length. */
+ len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
+@@ -1541,7 +1541,7 @@ int ntfs_rl_truncate_nolock(const ntfs_v
+ */
+ if (rl->length) {
+ runlist_element *trl;
+- BOOL is_end;
++ bool is_end;
+
+ ntfs_debug("Shrinking runlist.");
+ /* Determine the runlist size. */
+@@ -1555,11 +1555,11 @@ int ntfs_rl_truncate_nolock(const ntfs_v
+ * If a run was partially truncated, make the following runlist
+ * element a terminator.
+ */
+- is_end = FALSE;
++ is_end = false;
+ if (rl->length) {
+ rl++;
+ if (!rl->length)
+- is_end = TRUE;
++ is_end = true;
+ rl->vcn = new_length;
+ rl->length = 0;
+ }
+@@ -1648,7 +1648,7 @@ int ntfs_rl_punch_nolock(const ntfs_volu
+ s64 delta;
+ runlist_element *rl, *rl_end, *rl_real_end, *trl;
+ int old_size;
+- BOOL lcn_fixup = FALSE;
++ bool lcn_fixup = false;
+
+ ntfs_debug("Entering for start 0x%llx, length 0x%llx.",
+ (long long)start, (long long)length);
+@@ -1862,7 +1862,7 @@ split_end:
+ if (rl->lcn >= 0) {
+ rl->lcn -= delta;
+ /* Need this in case the lcn just became negative. */
+- lcn_fixup = TRUE;
++ lcn_fixup = true;
+ }
+ rl->length += delta;
+ goto split_end;
+diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
+index 74e0ee8..03a391a 100644
+--- a/fs/ntfs/super.c
++++ b/fs/ntfs/super.c
+@@ -74,18 +74,18 @@ const option_t on_errors_arr[] = {
+ *
+ * Copied from old ntfs driver (which copied from vfat driver).
+ */
+-static int simple_getbool(char *s, BOOL *setval)
++static int simple_getbool(char *s, bool *setval)
+ {
+ if (s) {
+ if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true"))
+- *setval = TRUE;
++ *setval = true;
+ else if (!strcmp(s, "0") || !strcmp(s, "no") ||
+ !strcmp(s, "false"))
+- *setval = FALSE;
++ *setval = false;
+ else
+ return 0;
+ } else
+- *setval = TRUE;
++ *setval = true;
+ return 1;
+ }
+
+@@ -96,7 +96,7 @@ static int simple_getbool(char *s, BOOL
+ *
+ * Parse the recognized options in @opt for the ntfs volume described by @vol.
+ */
+-static BOOL parse_options(ntfs_volume *vol, char *opt)
++static bool parse_options(ntfs_volume *vol, char *opt)
+ {
+ char *p, *v, *ov;
+ static char *utf8 = "utf8";
+@@ -137,7 +137,7 @@ static BOOL parse_options(ntfs_volume *v
+ }
+ #define NTFS_GETOPT_BOOL(option, variable) \
+ if (!strcmp(p, option)) { \
+- BOOL val; \
++ bool val; \
+ if (!simple_getbool(v, &val)) \
+ goto needs_bool; \
+ variable = val; \
+@@ -170,7 +170,7 @@ static BOOL parse_options(ntfs_volume *v
+ else NTFS_GETOPT_OCTAL("fmask", fmask)
+ else NTFS_GETOPT_OCTAL("dmask", dmask)
+ else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier)
+- else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, TRUE)
++ else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, true)
+ else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files)
+ else NTFS_GETOPT_BOOL("case_sensitive", case_sensitive)
+ else NTFS_GETOPT_BOOL("disable_sparse", disable_sparse)
+@@ -194,7 +194,7 @@ use_utf8:
+ if (!old_nls) {
+ ntfs_error(vol->sb, "NLS character set "
+ "%s not found.", v);
+- return FALSE;
++ return false;
+ }
+ ntfs_error(vol->sb, "NLS character set %s not "
+ "found. Using previous one %s.",
+@@ -205,14 +205,14 @@ use_utf8:
+ unload_nls(old_nls);
+ }
+ } else if (!strcmp(p, "utf8")) {
+- BOOL val = FALSE;
++ bool val = false;
+ ntfs_warning(vol->sb, "Option utf8 is no longer "
+ "supported, using option nls=utf8. Please "
+ "use option nls=utf8 in the future and "
+ "make sure utf8 is compiled either as a "
+ "module or into the kernel.");
+ if (!v || !*v)
+- val = TRUE;
++ val = true;
+ else if (!simple_getbool(v, &val))
+ goto needs_bool;
+ if (val) {
+@@ -231,7 +231,7 @@ use_utf8:
+ }
+ no_mount_options:
+ if (errors && !sloppy)
+- return FALSE;
++ return false;
+ if (sloppy)
+ ntfs_warning(vol->sb, "Sloppy option given. Ignoring "
+ "unrecognized mount option(s) and continuing.");
+@@ -240,14 +240,14 @@ no_mount_options:
+ if (!on_errors) {
+ ntfs_error(vol->sb, "Invalid errors option argument "
+ "or bug in options parser.");
+- return FALSE;
++ return false;
+ }
+ }
+ if (nls_map) {
+ if (vol->nls_map && vol->nls_map != nls_map) {
+ ntfs_error(vol->sb, "Cannot change NLS character set "
+ "on remount.");
+- return FALSE;
++ return false;
+ } /* else (!vol->nls_map) */
+ ntfs_debug("Using NLS character set %s.", nls_map->charset);
+ vol->nls_map = nls_map;
+@@ -257,7 +257,7 @@ no_mount_options:
+ if (!vol->nls_map) {
+ ntfs_error(vol->sb, "Failed to load default "
+ "NLS character set.");
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("Using default NLS character set (%s).",
+ vol->nls_map->charset);
+@@ -268,7 +268,7 @@ no_mount_options:
+ mft_zone_multiplier) {
+ ntfs_error(vol->sb, "Cannot change mft_zone_multiplier "
+ "on remount.");
+- return FALSE;
++ return false;
+ }
+ if (mft_zone_multiplier < 1 || mft_zone_multiplier > 4) {
+ ntfs_error(vol->sb, "Invalid mft_zone_multiplier. "
+@@ -318,16 +318,16 @@ no_mount_options:
+ NVolSetSparseEnabled(vol);
+ }
+ }
+- return TRUE;
++ return true;
+ needs_arg:
+ ntfs_error(vol->sb, "The %s option requires an argument.", p);
+- return FALSE;
++ return false;
+ needs_bool:
+ ntfs_error(vol->sb, "The %s option requires a boolean argument.", p);
+- return FALSE;
++ return false;
+ needs_val:
+ ntfs_error(vol->sb, "Invalid %s option argument: %s", p, ov);
+- return FALSE;
++ return false;
+ }
+
+ #ifdef NTFS_RW
+@@ -543,16 +543,16 @@ static int ntfs_remount(struct super_blo
+ * is_boot_sector_ntfs - check whether a boot sector is a valid NTFS boot sector
+ * @sb: Super block of the device to which @b belongs.
+ * @b: Boot sector of device @sb to check.
+- * @silent: If TRUE, all output will be silenced.
++ * @silent: If 'true', all output will be silenced.
+ *
+ * is_boot_sector_ntfs() checks whether the boot sector @b is a valid NTFS boot
+- * sector. Returns TRUE if it is valid and FALSE if not.
++ * sector. Returns 'true' if it is valid and 'false' if not.
+ *
+ * @sb is only needed for warning/error output, i.e. it can be NULL when silent
+- * is TRUE.
++ * is 'true'.
+ */
+-static BOOL is_boot_sector_ntfs(const struct super_block *sb,
+- const NTFS_BOOT_SECTOR *b, const BOOL silent)
++static bool is_boot_sector_ntfs(const struct super_block *sb,
++ const NTFS_BOOT_SECTOR *b, const bool silent)
+ {
+ /*
+ * Check that checksum == sum of u32 values from b to the checksum
+@@ -620,9 +620,9 @@ static BOOL is_boot_sector_ntfs(const st
+ */
+ if (!silent && b->end_of_sector_marker != const_cpu_to_le16(0xaa55))
+ ntfs_warning(sb, "Invalid end of sector marker.");
+- return TRUE;
++ return true;
+ not_ntfs:
+- return FALSE;
++ return false;
+ }
+
+ /**
+@@ -732,9 +732,9 @@ hotfix_primary_boot_sector:
+ * @b: boot sector to parse
+ *
+ * Parse the ntfs boot sector @b and store all imporant information therein in
+- * the ntfs super block @vol. Return TRUE on success and FALSE on error.
++ * the ntfs super block @vol. Return 'true' on success and 'false' on error.
+ */
+-static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
++static bool parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
+ {
+ unsigned int sectors_per_cluster_bits, nr_hidden_sects;
+ int clusters_per_mft_record, clusters_per_index_record;
+@@ -751,7 +751,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ "device block size (%lu). This is not "
+ "supported. Sorry.", vol->sector_size,
+ vol->sb->s_blocksize);
+- return FALSE;
++ return false;
+ }
+ ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster);
+ sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1;
+@@ -770,7 +770,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ ntfs_error(vol->sb, "Cluster size (%i) is smaller than the "
+ "sector size (%i). This is not supported. "
+ "Sorry.", vol->cluster_size, vol->sector_size);
+- return FALSE;
++ return false;
+ }
+ clusters_per_mft_record = b->clusters_per_mft_record;
+ ntfs_debug("clusters_per_mft_record = %i (0x%x)",
+@@ -802,7 +802,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ "PAGE_CACHE_SIZE on your system (%lu). "
+ "This is not supported. Sorry.",
+ vol->mft_record_size, PAGE_CACHE_SIZE);
+- return FALSE;
++ return false;
+ }
+ /* We cannot support mft record sizes below the sector size. */
+ if (vol->mft_record_size < vol->sector_size) {
+@@ -810,7 +810,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ "sector size (%i). This is not supported. "
+ "Sorry.", vol->mft_record_size,
+ vol->sector_size);
+- return FALSE;
++ return false;
+ }
+ clusters_per_index_record = b->clusters_per_index_record;
+ ntfs_debug("clusters_per_index_record = %i (0x%x)",
+@@ -841,7 +841,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ "the sector size (%i). This is not "
+ "supported. Sorry.", vol->index_record_size,
+ vol->sector_size);
+- return FALSE;
++ return false;
+ }
+ /*
+ * Get the size of the volume in clusters and check for 64-bit-ness.
+@@ -851,7 +851,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits;
+ if ((u64)ll >= 1ULL << 32) {
+ ntfs_error(vol->sb, "Cannot handle 64-bit clusters. Sorry.");
+- return FALSE;
++ return false;
+ }
+ vol->nr_clusters = ll;
+ ntfs_debug("vol->nr_clusters = 0x%llx", (long long)vol->nr_clusters);
+@@ -867,7 +867,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ "Maximum supported is 2TiB. Sorry.",
+ (unsigned long long)ll >> (40 -
+ vol->cluster_size_bits));
+- return FALSE;
++ return false;
+ }
+ }
+ ll = sle64_to_cpu(b->mft_lcn);
+@@ -875,7 +875,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of "
+ "volume. Weird.", (unsigned long long)ll,
+ (unsigned long long)ll);
+- return FALSE;
++ return false;
+ }
+ vol->mft_lcn = ll;
+ ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn);
+@@ -884,7 +884,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end "
+ "of volume. Weird.", (unsigned long long)ll,
+ (unsigned long long)ll);
+- return FALSE;
++ return false;
+ }
+ vol->mftmirr_lcn = ll;
+ ntfs_debug("vol->mftmirr_lcn = 0x%llx", (long long)vol->mftmirr_lcn);
+@@ -907,7 +907,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_
+ vol->serial_no = le64_to_cpu(b->volume_serial_number);
+ ntfs_debug("vol->serial_no = 0x%llx",
+ (unsigned long long)vol->serial_no);
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -1000,9 +1000,9 @@ static void ntfs_setup_allocators(ntfs_v
+ * load_and_init_mft_mirror - load and setup the mft mirror inode for a volume
+ * @vol: ntfs super block describing device whose mft mirror to load
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ */
+-static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
++static bool load_and_init_mft_mirror(ntfs_volume *vol)
+ {
+ struct inode *tmp_ino;
+ ntfs_inode *tmp_ni;
+@@ -1014,7 +1014,7 @@ static BOOL load_and_init_mft_mirror(ntf
+ if (!IS_ERR(tmp_ino))
+ iput(tmp_ino);
+ /* Caller will display error message. */
+- return FALSE;
++ return false;
+ }
+ /*
+ * Re-initialize some specifics about $MFTMirr's inode as
+@@ -1041,20 +1041,20 @@ static BOOL load_and_init_mft_mirror(ntf
+ tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits;
+ vol->mftmirr_ino = tmp_ino;
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+ * check_mft_mirror - compare contents of the mft mirror with the mft
+ * @vol: ntfs super block describing device whose mft mirror to check
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ *
+ * Note, this function also results in the mft mirror runlist being completely
+ * mapped into memory. The mft mirror write code requires this and will BUG()
+ * should it find an unmapped runlist element.
+ */
+-static BOOL check_mft_mirror(ntfs_volume *vol)
++static bool check_mft_mirror(ntfs_volume *vol)
+ {
+ struct super_block *sb = vol->sb;
+ ntfs_inode *mirr_ni;
+@@ -1086,7 +1086,7 @@ static BOOL check_mft_mirror(ntfs_volume
+ index);
+ if (IS_ERR(mft_page)) {
+ ntfs_error(sb, "Failed to read $MFT.");
+- return FALSE;
++ return false;
+ }
+ kmft = page_address(mft_page);
+ /* Get the $MFTMirr page. */
+@@ -1110,7 +1110,7 @@ mm_unmap_out:
+ ntfs_unmap_page(mirr_page);
+ mft_unmap_out:
+ ntfs_unmap_page(mft_page);
+- return FALSE;
++ return false;
+ }
+ }
+ /* Do not check the mirror record if it is not in use. */
+@@ -1169,21 +1169,21 @@ mft_unmap_out:
+ ntfs_error(sb, "$MFTMirr location mismatch. "
+ "Run chkdsk.");
+ up_read(&mirr_ni->runlist.lock);
+- return FALSE;
++ return false;
+ }
+ } while (rl2[i++].length);
+ up_read(&mirr_ni->runlist.lock);
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+ * load_and_check_logfile - load and check the logfile inode for a volume
+ * @vol: ntfs super block describing device whose logfile to load
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ */
+-static BOOL load_and_check_logfile(ntfs_volume *vol,
++static bool load_and_check_logfile(ntfs_volume *vol,
+ RESTART_PAGE_HEADER **rp)
+ {
+ struct inode *tmp_ino;
+@@ -1194,17 +1194,17 @@ static BOOL load_and_check_logfile(ntfs_
+ if (!IS_ERR(tmp_ino))
+ iput(tmp_ino);
+ /* Caller will display error message. */
+- return FALSE;
++ return false;
+ }
+ if (!ntfs_check_logfile(tmp_ino, rp)) {
+ iput(tmp_ino);
+ /* ntfs_check_logfile() will have displayed error output. */
+- return FALSE;
++ return false;
+ }
+ NInoSetSparseDisabled(NTFS_I(tmp_ino));
+ vol->logfile_ino = tmp_ino;
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ #define NTFS_HIBERFIL_HEADER_SIZE 4096
+@@ -1329,10 +1329,10 @@ iput_out:
+ * load_and_init_quota - load and setup the quota file for a volume if present
+ * @vol: ntfs super block describing device whose quota file to load
+ *
+- * Return TRUE on success or FALSE on error. If $Quota is not present, we
++ * Return 'true' on success or 'false' on error. If $Quota is not present, we
+ * leave vol->quota_ino as NULL and return success.
+ */
+-static BOOL load_and_init_quota(ntfs_volume *vol)
++static bool load_and_init_quota(ntfs_volume *vol)
+ {
+ MFT_REF mref;
+ struct inode *tmp_ino;
+@@ -1366,11 +1366,11 @@ static BOOL load_and_init_quota(ntfs_vol
+ * not enabled.
+ */
+ NVolSetQuotaOutOfDate(vol);
+- return TRUE;
++ return true;
+ }
+ /* A real error occured. */
+ ntfs_error(vol->sb, "Failed to find inode number for $Quota.");
+- return FALSE;
++ return false;
+ }
+ /* We do not care for the type of match that was found. */
+ kfree(name);
+@@ -1380,25 +1380,25 @@ static BOOL load_and_init_quota(ntfs_vol
+ if (!IS_ERR(tmp_ino))
+ iput(tmp_ino);
+ ntfs_error(vol->sb, "Failed to load $Quota.");
+- return FALSE;
++ return false;
+ }
+ vol->quota_ino = tmp_ino;
+ /* Get the $Q index allocation attribute. */
+ tmp_ino = ntfs_index_iget(vol->quota_ino, Q, 2);
+ if (IS_ERR(tmp_ino)) {
+ ntfs_error(vol->sb, "Failed to load $Quota/$Q index.");
+- return FALSE;
++ return false;
+ }
+ vol->quota_q_ino = tmp_ino;
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+ * load_and_init_usnjrnl - load and setup the transaction log if present
+ * @vol: ntfs super block describing device whose usnjrnl file to load
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ *
+ * If $UsnJrnl is not present or in the process of being disabled, we set
+ * NVolUsnJrnlStamped() and return success.
+@@ -1408,7 +1408,7 @@ static BOOL load_and_init_quota(ntfs_vol
+ * stamped and nothing has been logged since, we also set NVolUsnJrnlStamped()
+ * and return success.
+ */
+-static BOOL load_and_init_usnjrnl(ntfs_volume *vol)
++static bool load_and_init_usnjrnl(ntfs_volume *vol)
+ {
+ MFT_REF mref;
+ struct inode *tmp_ino;
+@@ -1450,12 +1450,12 @@ not_enabled:
+ * transaction logging is not enabled.
+ */
+ NVolSetUsnJrnlStamped(vol);
+- return TRUE;
++ return true;
+ }
+ /* A real error occured. */
+ ntfs_error(vol->sb, "Failed to find inode number for "
+ "$UsnJrnl.");
+- return FALSE;
++ return false;
+ }
+ /* We do not care for the type of match that was found. */
+ kfree(name);
+@@ -1465,7 +1465,7 @@ not_enabled:
+ if (!IS_ERR(tmp_ino))
+ iput(tmp_ino);
+ ntfs_error(vol->sb, "Failed to load $UsnJrnl.");
+- return FALSE;
++ return false;
+ }
+ vol->usnjrnl_ino = tmp_ino;
+ /*
+@@ -1483,7 +1483,7 @@ not_enabled:
+ if (IS_ERR(tmp_ino)) {
+ ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$Max "
+ "attribute.");
+- return FALSE;
++ return false;
+ }
+ vol->usnjrnl_max_ino = tmp_ino;
+ if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) {
+@@ -1491,14 +1491,14 @@ not_enabled:
+ "attribute (size is 0x%llx but should be at "
+ "least 0x%zx bytes).", i_size_read(tmp_ino),
+ sizeof(USN_HEADER));
+- return FALSE;
++ return false;
+ }
+ /* Get the $DATA/$J attribute. */
+ tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, J, 2);
+ if (IS_ERR(tmp_ino)) {
+ ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$J "
+ "attribute.");
+- return FALSE;
++ return false;
+ }
+ vol->usnjrnl_j_ino = tmp_ino;
+ /* Verify $J is non-resident and sparse. */
+@@ -1506,14 +1506,14 @@ not_enabled:
+ if (unlikely(!NInoNonResident(tmp_ni) || !NInoSparse(tmp_ni))) {
+ ntfs_error(vol->sb, "$UsnJrnl/$DATA/$J attribute is resident "
+ "and/or not sparse.");
+- return FALSE;
++ return false;
+ }
+ /* Read the USN_HEADER from $DATA/$Max. */
+ page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
+ if (IS_ERR(page)) {
+ ntfs_error(vol->sb, "Failed to read from $UsnJrnl/$DATA/$Max "
+ "attribute.");
+- return FALSE;
++ return false;
+ }
+ uh = (USN_HEADER*)page_address(page);
+ /* Sanity check the $Max. */
+@@ -1524,7 +1524,7 @@ not_enabled:
+ (long long)sle64_to_cpu(uh->allocation_delta),
+ (long long)sle64_to_cpu(uh->maximum_size));
+ ntfs_unmap_page(page);
+- return FALSE;
++ return false;
+ }
+ /*
+ * If the transaction log has been stamped and nothing has been written
+@@ -1548,20 +1548,20 @@ not_enabled:
+ (long long)sle64_to_cpu(uh->lowest_valid_usn),
+ i_size_read(vol->usnjrnl_j_ino));
+ ntfs_unmap_page(page);
+- return FALSE;
++ return false;
+ }
+ ntfs_unmap_page(page);
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+ * load_and_init_attrdef - load the attribute definitions table for a volume
+ * @vol: ntfs super block describing device whose attrdef to load
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ */
+-static BOOL load_and_init_attrdef(ntfs_volume *vol)
++static bool load_and_init_attrdef(ntfs_volume *vol)
+ {
+ loff_t i_size;
+ struct super_block *sb = vol->sb;
+@@ -1607,7 +1607,7 @@ read_partial_attrdef_page:
+ vol->attrdef_size = i_size;
+ ntfs_debug("Read %llu bytes from $AttrDef.", i_size);
+ iput(ino);
+- return TRUE;
++ return true;
+ free_iput_failed:
+ ntfs_free(vol->attrdef);
+ vol->attrdef = NULL;
+@@ -1615,7 +1615,7 @@ iput_failed:
+ iput(ino);
+ failed:
+ ntfs_error(sb, "Failed to initialize attribute definition table.");
+- return FALSE;
++ return false;
+ }
+
+ #endif /* NTFS_RW */
+@@ -1624,9 +1624,9 @@ failed:
+ * load_and_init_upcase - load the upcase table for an ntfs volume
+ * @vol: ntfs super block describing device whose upcase to load
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ */
+-static BOOL load_and_init_upcase(ntfs_volume *vol)
++static bool load_and_init_upcase(ntfs_volume *vol)
+ {
+ loff_t i_size;
+ struct super_block *sb = vol->sb;
+@@ -1682,7 +1682,7 @@ read_partial_upcase_page:
+ ntfs_debug("Using volume specified $UpCase since default is "
+ "not present.");
+ mutex_unlock(&ntfs_lock);
+- return TRUE;
++ return true;
+ }
+ max = default_upcase_len;
+ if (max > vol->upcase_len)
+@@ -1698,12 +1698,12 @@ read_partial_upcase_page:
+ mutex_unlock(&ntfs_lock);
+ ntfs_debug("Volume specified $UpCase matches default. Using "
+ "default.");
+- return TRUE;
++ return true;
+ }
+ mutex_unlock(&ntfs_lock);
+ ntfs_debug("Using volume specified $UpCase since it does not match "
+ "the default.");
+- return TRUE;
++ return true;
+ iput_upcase_failed:
+ iput(ino);
+ ntfs_free(vol->upcase);
+@@ -1717,11 +1717,11 @@ upcase_failed:
+ mutex_unlock(&ntfs_lock);
+ ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
+ "default.");
+- return TRUE;
++ return true;
+ }
+ mutex_unlock(&ntfs_lock);
+ ntfs_error(sb, "Failed to initialize upcase table.");
+- return FALSE;
++ return false;
+ }
+
+ /*
+@@ -1739,9 +1739,9 @@ static struct lock_class_key
+ * Open the system files with normal access functions and complete setting up
+ * the ntfs super block @vol.
+ *
+- * Return TRUE on success or FALSE on error.
++ * Return 'true' on success or 'false' on error.
+ */
+-static BOOL load_system_files(ntfs_volume *vol)
++static bool load_system_files(ntfs_volume *vol)
+ {
+ struct super_block *sb = vol->sb;
+ MFT_RECORD *m;
+@@ -2067,7 +2067,7 @@ get_ctx_vol_failed:
+ #endif /* NTFS_RW */
+ /* If on NTFS versions before 3.0, we are done. */
+ if (unlikely(vol->major_ver < 3))
+- return TRUE;
++ return true;
+ /* NTFS 3.0+ specific initialization. */
+ /* Get the security descriptors inode. */
+ vol->secure_ino = ntfs_iget(sb, FILE_Secure);
+@@ -2173,7 +2173,7 @@ get_ctx_vol_failed:
+ NVolSetErrors(vol);
+ }
+ #endif /* NTFS_RW */
+- return TRUE;
++ return true;
+ #ifdef NTFS_RW
+ iput_usnjrnl_err_out:
+ if (vol->usnjrnl_j_ino)
+@@ -2229,7 +2229,7 @@ iput_mirr_err_out:
+ if (vol->mftmirr_ino)
+ iput(vol->mftmirr_ino);
+ #endif /* NTFS_RW */
+- return FALSE;
++ return false;
+ }
+
+ /**
+@@ -3248,32 +3248,14 @@ ictx_err_out:
+
+ static void __exit exit_ntfs_fs(void)
+ {
+- int err = 0;
+-
+ ntfs_debug("Unregistering NTFS driver.");
+
+ unregister_filesystem(&ntfs_fs_type);
+-
+- if (kmem_cache_destroy(ntfs_big_inode_cache) && (err = 1))
+- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
+- ntfs_big_inode_cache_name);
+- if (kmem_cache_destroy(ntfs_inode_cache) && (err = 1))
+- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
+- ntfs_inode_cache_name);
+- if (kmem_cache_destroy(ntfs_name_cache) && (err = 1))
+- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
+- ntfs_name_cache_name);
+- if (kmem_cache_destroy(ntfs_attr_ctx_cache) && (err = 1))
+- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
+- ntfs_attr_ctx_cache_name);
+- if (kmem_cache_destroy(ntfs_index_ctx_cache) && (err = 1))
+- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
+- ntfs_index_ctx_cache_name);
+- if (err)
+- printk(KERN_CRIT "NTFS: This causes memory to leak! There is "
+- "probably a BUG in the driver! Please report "
+- "you saw this message to "
+- "linux-ntfs-dev at lists.sourceforge.net\n");
++ kmem_cache_destroy(ntfs_big_inode_cache);
++ kmem_cache_destroy(ntfs_inode_cache);
++ kmem_cache_destroy(ntfs_name_cache);
++ kmem_cache_destroy(ntfs_attr_ctx_cache);
++ kmem_cache_destroy(ntfs_index_ctx_cache);
+ /* Unregister the ntfs sysctls. */
+ ntfs_sysctl(0);
+ }
+diff --git a/fs/ntfs/types.h b/fs/ntfs/types.h
+index 6e4a7e3..8c8053b 100644
+--- a/fs/ntfs/types.h
++++ b/fs/ntfs/types.h
+@@ -62,11 +62,6 @@ typedef s64 USN;
+ typedef sle64 leUSN;
+
+ typedef enum {
+- FALSE = 0,
+- TRUE = 1
+-} BOOL;
+-
+-typedef enum {
+ CASE_SENSITIVE = 0,
+ IGNORE_CASE = 1,
+ } IGNORE_CASE_BOOL;
+diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c
+index b123c0f..6a495f7 100644
+--- a/fs/ntfs/unistr.c
++++ b/fs/ntfs/unistr.c
+@@ -61,16 +61,16 @@ static const u8 legal_ansi_char_array[0x
+ * @upcase: upcase table (only if @ic == IGNORE_CASE)
+ * @upcase_size: length in Unicode characters of @upcase (if present)
+ *
+- * Compare the names @s1 and @s2 and return TRUE (1) if the names are
+- * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
++ * Compare the names @s1 and @s2 and return 'true' (1) if the names are
++ * identical, or 'false' (0) if they are not identical. If @ic is IGNORE_CASE,
+ * the @upcase table is used to performa a case insensitive comparison.
+ */
+-BOOL ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
++bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
+ const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
+ const ntfschar *upcase, const u32 upcase_size)
+ {
+ if (s1_len != s2_len)
+- return FALSE;
++ return false;
+ if (ic == CASE_SENSITIVE)
+ return !ntfs_ucsncmp(s1, s2, s1_len);
+ return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
+@@ -350,7 +350,7 @@ int ntfs_ucstonls(const ntfs_volume *vol
+ }
+ if (!ns) {
+ ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
+- ns = (unsigned char*)kmalloc(ns_len + 1, GFP_NOFS);
++ ns = kmalloc(ns_len + 1, GFP_NOFS);
+ if (!ns)
+ goto mem_err_out;
+ }
+@@ -365,7 +365,7 @@ retry: wc = nls->uni2char(le16_to_cpu(
+ else if (wc == -ENAMETOOLONG && ns != *outs) {
+ unsigned char *tc;
+ /* Grow in multiples of 64 bytes. */
+- tc = (unsigned char*)kmalloc((ns_len + 64) &
++ tc = kmalloc((ns_len + 64) &
+ ~63, GFP_NOFS);
+ if (tc) {
+ memcpy(tc, ns, ns_len);
+diff --git a/fs/ntfs/usnjrnl.c b/fs/ntfs/usnjrnl.c
+index 7777324..b2bc0d5 100644
+--- a/fs/ntfs/usnjrnl.c
++++ b/fs/ntfs/usnjrnl.c
+@@ -39,12 +39,12 @@
+ * @vol: ntfs volume on which to stamp the transaction log
+ *
+ * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
+- * TRUE on success and FALSE on error.
++ * 'true' on success and 'false' on error.
+ *
+ * This function assumes that the transaction log has already been loaded and
+ * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
+ */
+-BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol)
++bool ntfs_stamp_usnjrnl(ntfs_volume *vol)
+ {
+ ntfs_debug("Entering.");
+ if (likely(!NVolUsnJrnlStamped(vol))) {
+@@ -56,7 +56,7 @@ BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol
+ if (IS_ERR(page)) {
+ ntfs_error(vol->sb, "Failed to read from "
+ "$UsnJrnl/$DATA/$Max attribute.");
+- return FALSE;
++ return false;
+ }
+ uh = (USN_HEADER*)page_address(page);
+ stamp = get_current_ntfs_time();
+@@ -78,7 +78,7 @@ BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol
+ NVolSetUsnJrnlStamped(vol);
+ }
+ ntfs_debug("Done.");
+- return TRUE;
++ return true;
+ }
+
+ #endif /* NTFS_RW */
+diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h
+index ff988b0..3a8af75 100644
+--- a/fs/ntfs/usnjrnl.h
++++ b/fs/ntfs/usnjrnl.h
+@@ -198,7 +198,7 @@ typedef struct {
+ /* sizeof() = 60 (0x3c) bytes */
+ } __attribute__ ((__packed__)) USN_RECORD;
+
+-extern BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol);
++extern bool ntfs_stamp_usnjrnl(ntfs_volume *vol);
+
+ #endif /* NTFS_RW */
+
+diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
+index 7d3be84..9fb8132 100644
+--- a/fs/ocfs2/Makefile
++++ b/fs/ocfs2/Makefile
+@@ -16,6 +16,7 @@ ocfs2-objs := \
+ file.o \
+ heartbeat.o \
+ inode.o \
++ ioctl.o \
+ journal.o \
+ localalloc.o \
+ mmap.o \
+diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
+index edaab05..f43bc5f 100644
+--- a/fs/ocfs2/alloc.c
++++ b/fs/ocfs2/alloc.c
+@@ -1717,17 +1717,29 @@ static int ocfs2_do_truncate(struct ocfs
+
+ ocfs2_remove_from_cache(inode, eb_bh);
+
+- BUG_ON(eb->h_suballoc_slot);
+ BUG_ON(el->l_recs[0].e_clusters);
+ BUG_ON(el->l_recs[0].e_cpos);
+ BUG_ON(el->l_recs[0].e_blkno);
+- status = ocfs2_free_extent_block(handle,
+- tc->tc_ext_alloc_inode,
+- tc->tc_ext_alloc_bh,
+- eb);
+- if (status < 0) {
+- mlog_errno(status);
+- goto bail;
++ if (eb->h_suballoc_slot == 0) {
++ /*
++ * This code only understands how to
++ * lock the suballocator in slot 0,
++ * which is fine because allocation is
++ * only ever done out of that
++ * suballocator too. A future version
++ * might change that however, so avoid
++ * a free if we don't know how to
++ * handle it. This way an fs incompat
++ * bit will not be necessary.
++ */
++ status = ocfs2_free_extent_block(handle,
++ tc->tc_ext_alloc_inode,
++ tc->tc_ext_alloc_bh,
++ eb);
++ if (status < 0) {
++ mlog_errno(status);
++ goto bail;
++ }
+ }
+ }
+ brelse(eb_bh);
+diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
+index f1d1c34..3d7c082 100644
+--- a/fs/ocfs2/aops.c
++++ b/fs/ocfs2/aops.c
+@@ -391,31 +391,28 @@ out:
+ static int ocfs2_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+ {
+- int ret, extending = 0, locklevel = 0;
+- loff_t new_i_size;
++ int ret;
+ struct buffer_head *di_bh = NULL;
+ struct inode *inode = page->mapping->host;
+ struct ocfs2_journal_handle *handle = NULL;
++ struct ocfs2_dinode *di;
+
+ mlog_entry("(0x%p, 0x%p, %u, %u)\n", file, page, from, to);
+
+ /* NOTE: ocfs2_file_aio_write has ensured that it's safe for
+- * us to sample inode->i_size here without the metadata lock:
++ * us to continue here without rechecking the I/O against
++ * changed inode values.
+ *
+ * 1) We're currently holding the inode alloc lock, so no
+ * nodes can change it underneath us.
+ *
+ * 2) We've had to take the metadata lock at least once
+- * already to check for extending writes, hence insuring
+- * that our current copy is also up to date.
++ * already to check for extending writes, suid removal, etc.
++ * The meta data update code then ensures that we don't get a
++ * stale inode allocation image (i_size, i_clusters, etc).
+ */
+- new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+- if (new_i_size > i_size_read(inode)) {
+- extending = 1;
+- locklevel = 1;
+- }
+
+- ret = ocfs2_meta_lock_with_page(inode, NULL, &di_bh, locklevel, page);
++ ret = ocfs2_meta_lock_with_page(inode, NULL, &di_bh, 1, page);
+ if (ret != 0) {
+ mlog_errno(ret);
+ goto out;
+@@ -427,23 +424,20 @@ static int ocfs2_commit_write(struct fil
+ goto out_unlock_meta;
+ }
+
+- if (extending) {
+- handle = ocfs2_start_walk_page_trans(inode, page, from, to);
+- if (IS_ERR(handle)) {
+- ret = PTR_ERR(handle);
+- handle = NULL;
+- goto out_unlock_data;
+- }
++ handle = ocfs2_start_walk_page_trans(inode, page, from, to);
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out_unlock_data;
++ }
+
+- /* Mark our buffer early. We'd rather catch this error up here
+- * as opposed to after a successful commit_write which would
+- * require us to set back inode->i_size. */
+- ret = ocfs2_journal_access(handle, inode, di_bh,
+- OCFS2_JOURNAL_ACCESS_WRITE);
+- if (ret < 0) {
+- mlog_errno(ret);
+- goto out_commit;
+- }
++ /* Mark our buffer early. We'd rather catch this error up here
++ * as opposed to after a successful commit_write which would
++ * require us to set back inode->i_size. */
++ ret = ocfs2_journal_access(handle, inode, di_bh,
++ OCFS2_JOURNAL_ACCESS_WRITE);
++ if (ret < 0) {
++ mlog_errno(ret);
++ goto out_commit;
+ }
+
+ /* might update i_size */
+@@ -453,37 +447,28 @@ static int ocfs2_commit_write(struct fil
+ goto out_commit;
+ }
+
+- if (extending) {
+- loff_t size = (u64) i_size_read(inode);
+- struct ocfs2_dinode *di =
+- (struct ocfs2_dinode *)di_bh->b_data;
++ di = (struct ocfs2_dinode *)di_bh->b_data;
+
+- /* ocfs2_mark_inode_dirty is too heavy to use here. */
+- inode->i_blocks = ocfs2_align_bytes_to_sectors(size);
+- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
++ /* ocfs2_mark_inode_dirty() is too heavy to use here. */
++ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
++ di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
++ di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
+
+- di->i_size = cpu_to_le64(size);
+- di->i_ctime = di->i_mtime =
+- cpu_to_le64(inode->i_mtime.tv_sec);
+- di->i_ctime_nsec = di->i_mtime_nsec =
+- cpu_to_le32(inode->i_mtime.tv_nsec);
++ inode->i_blocks = ocfs2_align_bytes_to_sectors((u64)(i_size_read(inode)));
++ di->i_size = cpu_to_le64((u64)i_size_read(inode));
+
+- ret = ocfs2_journal_dirty(handle, di_bh);
+- if (ret < 0) {
+- mlog_errno(ret);
+- goto out_commit;
+- }
++ ret = ocfs2_journal_dirty(handle, di_bh);
++ if (ret < 0) {
++ mlog_errno(ret);
++ goto out_commit;
+ }
+
+- BUG_ON(extending && (i_size_read(inode) != new_i_size));
+-
+ out_commit:
+- if (handle)
+- ocfs2_commit_trans(handle);
++ ocfs2_commit_trans(handle);
+ out_unlock_data:
+ ocfs2_data_unlock(inode, 1);
+ out_unlock_meta:
+- ocfs2_meta_unlock(inode, locklevel);
++ ocfs2_meta_unlock(inode, 1);
+ out:
+ if (di_bh)
+ brelse(di_bh);
+diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
+index 9a24adf..c903741 100644
+--- a/fs/ocfs2/buffer_head_io.c
++++ b/fs/ocfs2/buffer_head_io.c
+@@ -100,6 +100,9 @@ int ocfs2_read_blocks(struct ocfs2_super
+ mlog_entry("(block=(%llu), nr=(%d), flags=%d, inode=%p)\n",
+ (unsigned long long)block, nr, flags, inode);
+
++ BUG_ON((flags & OCFS2_BH_READAHEAD) &&
++ (!inode || !(flags & OCFS2_BH_CACHED)));
++
+ if (osb == NULL || osb->sb == NULL || bhs == NULL) {
+ status = -EINVAL;
+ mlog_errno(status);
+@@ -140,6 +143,30 @@ int ocfs2_read_blocks(struct ocfs2_super
+ bh = bhs[i];
+ ignore_cache = 0;
+
++ /* There are three read-ahead cases here which we need to
++ * be concerned with. All three assume a buffer has
++ * previously been submitted with OCFS2_BH_READAHEAD
++ * and it hasn't yet completed I/O.
++ *
++ * 1) The current request is sync to disk. This rarely
++ * happens these days, and never when performance
++ * matters - the code can just wait on the buffer
++ * lock and re-submit.
++ *
++ * 2) The current request is cached, but not
++ * readahead. ocfs2_buffer_uptodate() will return
++ * false anyway, so we'll wind up waiting on the
++ * buffer lock to do I/O. We re-check the request
++ * with after getting the lock to avoid a re-submit.
++ *
++ * 3) The current request is readahead (and so must
++ * also be a caching one). We short circuit if the
++ * buffer is locked (under I/O) and if it's in the
++ * uptodate cache. The re-check from #2 catches the
++ * case that the previous read-ahead completes just
++ * before our is-it-in-flight check.
++ */
++
+ if (flags & OCFS2_BH_CACHED &&
+ !ocfs2_buffer_uptodate(inode, bh)) {
+ mlog(ML_UPTODATE,
+@@ -169,6 +196,14 @@ int ocfs2_read_blocks(struct ocfs2_super
+ continue;
+ }
+
++ /* A read-ahead request was made - if the
++ * buffer is already under read-ahead from a
++ * previously submitted request than we are
++ * done here. */
++ if ((flags & OCFS2_BH_READAHEAD)
++ && ocfs2_buffer_read_ahead(inode, bh))
++ continue;
++
+ lock_buffer(bh);
+ if (buffer_jbd(bh)) {
+ #ifdef CATCH_BH_JBD_RACES
+@@ -181,13 +216,22 @@ int ocfs2_read_blocks(struct ocfs2_super
+ continue;
+ #endif
+ }
++
++ /* Re-check ocfs2_buffer_uptodate() as a
++ * previously read-ahead buffer may have
++ * completed I/O while we were waiting for the
++ * buffer lock. */
++ if ((flags & OCFS2_BH_CACHED)
++ && !(flags & OCFS2_BH_READAHEAD)
++ && ocfs2_buffer_uptodate(inode, bh)) {
++ unlock_buffer(bh);
++ continue;
++ }
++
+ clear_buffer_uptodate(bh);
+ get_bh(bh); /* for end_buffer_read_sync() */
+ bh->b_end_io = end_buffer_read_sync;
+- if (flags & OCFS2_BH_READAHEAD)
+- submit_bh(READA, bh);
+- else
+- submit_bh(READ, bh);
++ submit_bh(READ, bh);
+ continue;
+ }
+ }
+@@ -197,34 +241,39 @@ int ocfs2_read_blocks(struct ocfs2_super
+ for (i = (nr - 1); i >= 0; i--) {
+ bh = bhs[i];
+
+- /* We know this can't have changed as we hold the
+- * inode sem. Avoid doing any work on the bh if the
+- * journal has it. */
+- if (!buffer_jbd(bh))
+- wait_on_buffer(bh);
+-
+- if (!buffer_uptodate(bh)) {
+- /* Status won't be cleared from here on out,
+- * so we can safely record this and loop back
+- * to cleanup the other buffers. Don't need to
+- * remove the clustered uptodate information
+- * for this bh as it's not marked locally
+- * uptodate. */
+- status = -EIO;
+- brelse(bh);
+- bhs[i] = NULL;
+- continue;
++ if (!(flags & OCFS2_BH_READAHEAD)) {
++ /* We know this can't have changed as we hold the
++ * inode sem. Avoid doing any work on the bh if the
++ * journal has it. */
++ if (!buffer_jbd(bh))
++ wait_on_buffer(bh);
++
++ if (!buffer_uptodate(bh)) {
++ /* Status won't be cleared from here on out,
++ * so we can safely record this and loop back
++ * to cleanup the other buffers. Don't need to
++ * remove the clustered uptodate information
++ * for this bh as it's not marked locally
++ * uptodate. */
++ status = -EIO;
++ brelse(bh);
++ bhs[i] = NULL;
++ continue;
++ }
+ }
+
++ /* Always set the buffer in the cache, even if it was
++ * a forced read, or read-ahead which hasn't yet
++ * completed. */
+ if (inode)
+ ocfs2_set_buffer_uptodate(inode, bh);
+ }
+ if (inode)
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+
+- mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s\n",
++ mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n",
+ (unsigned long long)block, nr,
+- (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes");
++ (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes", flags);
+
+ bail:
+
+diff --git a/fs/ocfs2/buffer_head_io.h b/fs/ocfs2/buffer_head_io.h
+index 6ecb909..6cc2093 100644
+--- a/fs/ocfs2/buffer_head_io.h
++++ b/fs/ocfs2/buffer_head_io.h
+@@ -49,7 +49,7 @@ int ocfs2_read_blocks(struct ocfs2_super
+
+
+ #define OCFS2_BH_CACHED 1
+-#define OCFS2_BH_READAHEAD 8 /* use this to pass READA down to submit_bh */
++#define OCFS2_BH_READAHEAD 8
+
+ static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off,
+ struct buffer_head **bh, int flags,
+diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
+index 504595d..305cba3 100644
+--- a/fs/ocfs2/cluster/heartbeat.c
++++ b/fs/ocfs2/cluster/heartbeat.c
+@@ -320,8 +320,12 @@ static int compute_max_sectors(struct bl
+ max_pages = q->max_hw_segments;
+ max_pages--; /* Handle I/Os that straddle a page */
+
+- max_sectors = max_pages << (PAGE_SHIFT - 9);
+-
++ if (max_pages) {
++ max_sectors = max_pages << (PAGE_SHIFT - 9);
++ } else {
++ /* If BIO contains 1 or less than 1 page. */
++ max_sectors = q->max_sectors;
++ }
+ /* Why is fls() 1-based???? */
+ pow_two_sectors = 1 << (fls(max_sectors) - 1);
+
+diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
+index e1fceb8..d11753c 100644
+--- a/fs/ocfs2/cluster/nodemanager.c
++++ b/fs/ocfs2/cluster/nodemanager.c
+@@ -152,14 +152,16 @@ static struct o2nm_node *o2nm_node_ip_tr
+ struct o2nm_node *node, *ret = NULL;
+
+ while (*p) {
++ int cmp;
++
+ parent = *p;
+ node = rb_entry(parent, struct o2nm_node, nd_ip_node);
+
+- if (memcmp(&ip_needle, &node->nd_ipv4_address,
+- sizeof(ip_needle)) < 0)
++ cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
++ sizeof(ip_needle));
++ if (cmp < 0)
+ p = &(*p)->rb_left;
+- else if (memcmp(&ip_needle, &node->nd_ipv4_address,
+- sizeof(ip_needle)) > 0)
++ else if (cmp > 0)
+ p = &(*p)->rb_right;
+ else {
+ ret = node;
+diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
+index ff9e2e2..4b46aac 100644
+--- a/fs/ocfs2/cluster/tcp_internal.h
++++ b/fs/ocfs2/cluster/tcp_internal.h
+@@ -44,11 +44,17 @@
+ * locking semantics of the file system using the protocol. It should
+ * be somewhere else, I'm sure, but right now it isn't.
+ *
++ * New in version 4:
++ * - Remove i_generation from lock names for better stat performance.
++ *
++ * New in version 3:
++ * - Replace dentry votes with a cluster lock
++ *
+ * New in version 2:
+ * - full 64 bit i_size in the metadata lock lvbs
+ * - introduction of "rw" lock and pushing meta/data locking down
+ */
+-#define O2NET_PROTOCOL_VERSION 2ULL
++#define O2NET_PROTOCOL_VERSION 4ULL
+ struct o2net_handshake {
+ __be64 protocol_version;
+ __be64 connector_id;
+diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
+index 1a01380..014e739 100644
+--- a/fs/ocfs2/dcache.c
++++ b/fs/ocfs2/dcache.c
+@@ -35,15 +35,17 @@
+
+ #include "alloc.h"
+ #include "dcache.h"
++#include "dlmglue.h"
+ #include "file.h"
+ #include "inode.h"
+
++
+ static int ocfs2_dentry_revalidate(struct dentry *dentry,
+ struct nameidata *nd)
+ {
+ struct inode *inode = dentry->d_inode;
+ int ret = 0; /* if all else fails, just return false */
+- struct ocfs2_super *osb;
++ struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
+
+ mlog_entry("(0x%p, '%.*s')\n", dentry,
+ dentry->d_name.len, dentry->d_name.name);
+@@ -55,28 +57,31 @@ static int ocfs2_dentry_revalidate(struc
+ goto bail;
+ }
+
+- osb = OCFS2_SB(inode->i_sb);
+-
+ BUG_ON(!osb);
+
+- if (inode != osb->root_inode) {
+- spin_lock(&OCFS2_I(inode)->ip_lock);
+- /* did we or someone else delete this inode? */
+- if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_DELETED) {
+- spin_unlock(&OCFS2_I(inode)->ip_lock);
+- mlog(0, "inode (%llu) deleted, returning false\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno);
+- goto bail;
+- }
++ if (inode == osb->root_inode || is_bad_inode(inode))
++ goto bail;
++
++ spin_lock(&OCFS2_I(inode)->ip_lock);
++ /* did we or someone else delete this inode? */
++ if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_DELETED) {
+ spin_unlock(&OCFS2_I(inode)->ip_lock);
++ mlog(0, "inode (%llu) deleted, returning false\n",
++ (unsigned long long)OCFS2_I(inode)->ip_blkno);
++ goto bail;
++ }
++ spin_unlock(&OCFS2_I(inode)->ip_lock);
+
+- if (!inode->i_nlink) {
+- mlog(0, "Inode %llu orphaned, returning false "
+- "dir = %d\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno,
+- S_ISDIR(inode->i_mode));
+- goto bail;
+- }
++ /*
++ * We don't need a cluster lock to test this because once an
++ * inode nlink hits zero, it never goes back.
++ */
++ if (inode->i_nlink == 0) {
++ mlog(0, "Inode %llu orphaned, returning false "
++ "dir = %d\n",
++ (unsigned long long)OCFS2_I(inode)->ip_blkno,
++ S_ISDIR(inode->i_mode));
++ goto bail;
+ }
+
+ ret = 1;
+@@ -87,6 +92,322 @@ bail:
+ return ret;
+ }
+
++static int ocfs2_match_dentry(struct dentry *dentry,
++ u64 parent_blkno,
++ int skip_unhashed)
++{
++ struct inode *parent;
++
++ /*
++ * ocfs2_lookup() does a d_splice_alias() _before_ attaching
++ * to the lock data, so we skip those here, otherwise
++ * ocfs2_dentry_attach_lock() will get its original dentry
++ * back.
++ */
++ if (!dentry->d_fsdata)
++ return 0;
++
++ if (!dentry->d_parent)
++ return 0;
++
++ if (skip_unhashed && d_unhashed(dentry))
++ return 0;
++
++ parent = dentry->d_parent->d_inode;
++ /* Negative parent dentry? */
++ if (!parent)
++ return 0;
++
++ /* Name is in a different directory. */
++ if (OCFS2_I(parent)->ip_blkno != parent_blkno)
++ return 0;
++
++ return 1;
++}
++
++/*
++ * Walk the inode alias list, and find a dentry which has a given
++ * parent. ocfs2_dentry_attach_lock() wants to find _any_ alias as it
++ * is looking for a dentry_lock reference. The vote thread is looking
++ * to unhash aliases, so we allow it to skip any that already have
++ * that property.
++ */
++struct dentry *ocfs2_find_local_alias(struct inode *inode,
++ u64 parent_blkno,
++ int skip_unhashed)
++{
++ struct list_head *p;
++ struct dentry *dentry = NULL;
++
++ spin_lock(&dcache_lock);
++
++ list_for_each(p, &inode->i_dentry) {
++ dentry = list_entry(p, struct dentry, d_alias);
++
++ if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
++ mlog(0, "dentry found: %.*s\n",
++ dentry->d_name.len, dentry->d_name.name);
++
++ dget_locked(dentry);
++ break;
++ }
++
++ dentry = NULL;
++ }
++
++ spin_unlock(&dcache_lock);
++
++ return dentry;
++}
++
++DEFINE_SPINLOCK(dentry_attach_lock);
++
++/*
++ * Attach this dentry to a cluster lock.
++ *
++ * Dentry locks cover all links in a given directory to a particular
++ * inode. We do this so that ocfs2 can build a lock name which all
++ * nodes in the cluster can agree on at all times. Shoving full names
++ * in the cluster lock won't work due to size restrictions. Covering
++ * links inside of a directory is a good compromise because it still
++ * allows us to use the parent directory lock to synchronize
++ * operations.
++ *
++ * Call this function with the parent dir semaphore and the parent dir
++ * cluster lock held.
++ *
++ * The dir semaphore will protect us from having to worry about
++ * concurrent processes on our node trying to attach a lock at the
++ * same time.
++ *
++ * The dir cluster lock (held at either PR or EX mode) protects us
++ * from unlink and rename on other nodes.
++ *
++ * A dput() can happen asynchronously due to pruning, so we cover
++ * attaching and detaching the dentry lock with a
++ * dentry_attach_lock.
++ *
++ * A node which has done lookup on a name retains a protected read
++ * lock until final dput. If the user requests and unlink or rename,
++ * the protected read is upgraded to an exclusive lock. Other nodes
++ * who have seen the dentry will then be informed that they need to
++ * downgrade their lock, which will involve d_delete on the
++ * dentry. This happens in ocfs2_dentry_convert_worker().
++ */
++int ocfs2_dentry_attach_lock(struct dentry *dentry,
++ struct inode *inode,
++ u64 parent_blkno)
++{
++ int ret;
++ struct dentry *alias;
++ struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
++
++ mlog(0, "Attach \"%.*s\", parent %llu, fsdata: %p\n",
++ dentry->d_name.len, dentry->d_name.name,
++ (unsigned long long)parent_blkno, dl);
++
++ /*
++ * Negative dentry. We ignore these for now.
++ *
++ * XXX: Could we can improve ocfs2_dentry_revalidate() by
++ * tracking these?
++ */
++ if (!inode)
++ return 0;
++
++ if (dl) {
++ mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno,
++ " \"%.*s\": old parent: %llu, new: %llu\n",
++ dentry->d_name.len, dentry->d_name.name,
++ (unsigned long long)parent_blkno,
++ (unsigned long long)dl->dl_parent_blkno);
++ return 0;
++ }
++
++ alias = ocfs2_find_local_alias(inode, parent_blkno, 0);
++ if (alias) {
++ /*
++ * Great, an alias exists, which means we must have a
++ * dentry lock already. We can just grab the lock off
++ * the alias and add it to the list.
++ *
++ * We're depending here on the fact that this dentry
++ * was found and exists in the dcache and so must have
++ * a reference to the dentry_lock because we can't
++ * race creates. Final dput() cannot happen on it
++ * since we have it pinned, so our reference is safe.
++ */
++ dl = alias->d_fsdata;
++ mlog_bug_on_msg(!dl, "parent %llu, ino %llu\n",
++ (unsigned long long)parent_blkno,
++ (unsigned long long)OCFS2_I(inode)->ip_blkno);
++
++ mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno,
++ " \"%.*s\": old parent: %llu, new: %llu\n",
++ dentry->d_name.len, dentry->d_name.name,
++ (unsigned long long)parent_blkno,
++ (unsigned long long)dl->dl_parent_blkno);
++
++ mlog(0, "Found: %s\n", dl->dl_lockres.l_name);
++
++ goto out_attach;
++ }
++
++ /*
++ * There are no other aliases
++ */
++ dl = kmalloc(sizeof(*dl), GFP_NOFS);
++ if (!dl) {
++ ret = -ENOMEM;
++ mlog_errno(ret);
++ return ret;
++ }
++
++ dl->dl_count = 0;
++ /*
++ * Does this have to happen below, for all attaches, in case
++ * the struct inode gets blown away by votes?
++ */
++ dl->dl_inode = igrab(inode);
++ dl->dl_parent_blkno = parent_blkno;
++ ocfs2_dentry_lock_res_init(dl, parent_blkno, inode);
++
++out_attach:
++ spin_lock(&dentry_attach_lock);
++ dentry->d_fsdata = dl;
++ dl->dl_count++;
++ spin_unlock(&dentry_attach_lock);
++
++ /*
++ * This actually gets us our PRMODE level lock. From now on,
++ * we'll have a notification if one of these names is
++ * destroyed on another node.
++ */
++ ret = ocfs2_dentry_lock(dentry, 0);
++ if (!ret)
++ ocfs2_dentry_unlock(dentry, 0);
++ else
++ mlog_errno(ret);
++
++ dput(alias);
++
++ return ret;
++}
++
++/*
++ * ocfs2_dentry_iput() and friends.
++ *
++ * At this point, our particular dentry is detached from the inodes
++ * alias list, so there's no way that the locking code can find it.
++ *
++ * The interesting stuff happens when we determine that our lock needs
++ * to go away because this is the last subdir alias in the
++ * system. This function needs to handle a couple things:
++ *
++ * 1) Synchronizing lock shutdown with the downconvert threads. This
++ * is already handled for us via the lockres release drop function
++ * called in ocfs2_release_dentry_lock()
++ *
++ * 2) A race may occur when we're doing our lock shutdown and
++ * another process wants to create a new dentry lock. Right now we
++ * let them race, which means that for a very short while, this
++ * node might have two locks on a lock resource. This should be a
++ * problem though because one of them is in the process of being
++ * thrown out.
++ */
++static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb,
++ struct ocfs2_dentry_lock *dl)
++{
++ ocfs2_simple_drop_lockres(osb, &dl->dl_lockres);
++ ocfs2_lock_res_free(&dl->dl_lockres);
++ iput(dl->dl_inode);
++ kfree(dl);
++}
++
++void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
++ struct ocfs2_dentry_lock *dl)
++{
++ int unlock = 0;
++
++ BUG_ON(dl->dl_count == 0);
++
++ spin_lock(&dentry_attach_lock);
++ dl->dl_count--;
++ unlock = !dl->dl_count;
++ spin_unlock(&dentry_attach_lock);
++
++ if (unlock)
++ ocfs2_drop_dentry_lock(osb, dl);
++}
++
++static void ocfs2_dentry_iput(struct dentry *dentry, struct inode *inode)
++{
++ struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
++
++ mlog_bug_on_msg(!dl && !(dentry->d_flags & DCACHE_DISCONNECTED),
++ "dentry: %.*s\n", dentry->d_name.len,
++ dentry->d_name.name);
++
++ if (!dl)
++ goto out;
++
++ mlog_bug_on_msg(dl->dl_count == 0, "dentry: %.*s, count: %u\n",
++ dentry->d_name.len, dentry->d_name.name,
++ dl->dl_count);
++
++ ocfs2_dentry_lock_put(OCFS2_SB(dentry->d_sb), dl);
++
++out:
++ iput(inode);
++}
++
++/*
++ * d_move(), but keep the locks in sync.
++ *
++ * When we are done, "dentry" will have the parent dir and name of
++ * "target", which will be thrown away.
++ *
++ * We manually update the lock of "dentry" if need be.
++ *
++ * "target" doesn't have it's dentry lock touched - we allow the later
++ * dput() to handle this for us.
++ *
++ * This is called during ocfs2_rename(), while holding parent
++ * directory locks. The dentries have already been deleted on other
++ * nodes via ocfs2_remote_dentry_delete().
++ *
++ * Normally, the VFS handles the d_move() for the file sytem, after
++ * the ->rename() callback. OCFS2 wants to handle this internally, so
++ * the new lock can be created atomically with respect to the cluster.
++ */
++void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target,
++ struct inode *old_dir, struct inode *new_dir)
++{
++ int ret;
++ struct ocfs2_super *osb = OCFS2_SB(old_dir->i_sb);
++ struct inode *inode = dentry->d_inode;
++
++ /*
++ * Move within the same directory, so the actual lock info won't
++ * change.
++ *
++ * XXX: Is there any advantage to dropping the lock here?
++ */
++ if (old_dir == new_dir)
++ goto out_move;
++
++ ocfs2_dentry_lock_put(osb, dentry->d_fsdata);
++
++ dentry->d_fsdata = NULL;
++ ret = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(new_dir)->ip_blkno);
++ if (ret)
++ mlog_errno(ret);
++
++out_move:
++ d_move(dentry, target);
++}
++
+ struct dentry_operations ocfs2_dentry_ops = {
+ .d_revalidate = ocfs2_dentry_revalidate,
++ .d_iput = ocfs2_dentry_iput,
+ };
+diff --git a/fs/ocfs2/dcache.h b/fs/ocfs2/dcache.h
+index 9007277..c091c34 100644
+--- a/fs/ocfs2/dcache.h
++++ b/fs/ocfs2/dcache.h
+@@ -28,4 +28,31 @@
+
+ extern struct dentry_operations ocfs2_dentry_ops;
+
++struct ocfs2_dentry_lock {
++ unsigned int dl_count;
++ u64 dl_parent_blkno;
++
++ /*
++ * The ocfs2_dentry_lock keeps an inode reference until
++ * dl_lockres has been destroyed. This is usually done in
++ * ->d_iput() anyway, so there should be minimal impact.
++ */
++ struct inode *dl_inode;
++ struct ocfs2_lock_res dl_lockres;
++};
++
++int ocfs2_dentry_attach_lock(struct dentry *dentry, struct inode *inode,
++ u64 parent_blkno);
++
++void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
++ struct ocfs2_dentry_lock *dl);
++
++struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno,
++ int skip_unhashed);
++
++void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target,
++ struct inode *old_dir, struct inode *new_dir);
++
++extern spinlock_t dentry_attach_lock;
++
+ #endif /* OCFS2_DCACHE_H */
+diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
+index 3d494d1..04e0191 100644
+--- a/fs/ocfs2/dir.c
++++ b/fs/ocfs2/dir.c
+@@ -74,14 +74,14 @@ static int ocfs2_extend_dir(struct ocfs2
+ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+ {
+ int error = 0;
+- unsigned long offset, blk;
+- int i, num, stored;
++ unsigned long offset, blk, last_ra_blk = 0;
++ int i, stored;
+ struct buffer_head * bh, * tmp;
+ struct ocfs2_dir_entry * de;
+ int err;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block * sb = inode->i_sb;
+- int have_disk_lock = 0;
++ unsigned int ra_sectors = 16;
+
+ mlog_entry("dirino=%llu\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+@@ -95,9 +95,8 @@ int ocfs2_readdir(struct file * filp, vo
+ mlog_errno(error);
+ /* we haven't got any yet, so propagate the error. */
+ stored = error;
+- goto bail;
++ goto bail_nolock;
+ }
+- have_disk_lock = 1;
+
+ offset = filp->f_pos & (sb->s_blocksize - 1);
+
+@@ -113,16 +112,21 @@ int ocfs2_readdir(struct file * filp, vo
+ continue;
+ }
+
+- /*
+- * Do the readahead (8k)
+- */
+- if (!offset) {
+- for (i = 16 >> (sb->s_blocksize_bits - 9), num = 0;
++ /* The idea here is to begin with 8k read-ahead and to stay
++ * 4k ahead of our current position.
++ *
++ * TODO: Use the pagecache for this. We just need to
++ * make sure it's cluster-safe... */
++ if (!last_ra_blk
++ || (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) {
++ for (i = ra_sectors >> (sb->s_blocksize_bits - 9);
+ i > 0; i--) {
+ tmp = ocfs2_bread(inode, ++blk, &err, 1);
+ if (tmp)
+ brelse(tmp);
+ }
++ last_ra_blk = blk;
++ ra_sectors = 8;
+ }
+
+ revalidate:
+@@ -194,9 +198,9 @@ revalidate:
+
+ stored = 0;
+ bail:
+- if (have_disk_lock)
+- ocfs2_meta_unlock(inode, 0);
++ ocfs2_meta_unlock(inode, 0);
+
++bail_nolock:
+ mlog_exit(stored);
+
+ return stored;
+diff --git a/fs/ocfs2/dlm/dlmapi.h b/fs/ocfs2/dlm/dlmapi.h
+index 53652f5..cfd5cb6 100644
+--- a/fs/ocfs2/dlm/dlmapi.h
++++ b/fs/ocfs2/dlm/dlmapi.h
+@@ -182,6 +182,7 @@ enum dlm_status dlmlock(struct dlm_ctxt
+ struct dlm_lockstatus *lksb,
+ int flags,
+ const char *name,
++ int namelen,
+ dlm_astlockfunc_t *ast,
+ void *data,
+ dlm_bastlockfunc_t *bast);
+diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
+index 42775e2..681046d 100644
+--- a/fs/ocfs2/dlm/dlmast.c
++++ b/fs/ocfs2/dlm/dlmast.c
+@@ -320,8 +320,8 @@ int dlm_proxy_ast_handler(struct o2net_m
+
+ res = dlm_lookup_lockres(dlm, name, locklen);
+ if (!res) {
+- mlog(ML_ERROR, "got %sast for unknown lockres! "
+- "cookie=%u:%llu, name=%.*s, namelen=%u\n",
++ mlog(0, "got %sast for unknown lockres! "
++ "cookie=%u:%llu, name=%.*s, namelen=%u\n",
+ past->type == DLM_AST ? "" : "b",
+ dlm_get_lock_cookie_node(cookie),
+ dlm_get_lock_cookie_seq(cookie),
+@@ -367,12 +367,10 @@ int dlm_proxy_ast_handler(struct o2net_m
+ goto do_ast;
+ }
+
+- mlog(ML_ERROR, "got %sast for unknown lock! cookie=%u:%llu, "
+- "name=%.*s, namelen=%u\n",
+- past->type == DLM_AST ? "" : "b",
+- dlm_get_lock_cookie_node(cookie),
+- dlm_get_lock_cookie_seq(cookie),
+- locklen, name, locklen);
++ mlog(0, "got %sast for unknown lock! cookie=%u:%llu, "
++ "name=%.*s, namelen=%u\n", past->type == DLM_AST ? "" : "b",
++ dlm_get_lock_cookie_node(cookie), dlm_get_lock_cookie_seq(cookie),
++ locklen, name, locklen);
+
+ ret = DLM_NORMAL;
+ unlock_out:
+@@ -464,7 +462,7 @@ int dlm_send_proxy_ast_msg(struct dlm_ct
+ mlog(ML_ERROR, "sent AST to node %u, it returned "
+ "DLM_MIGRATING!\n", lock->ml.node);
+ BUG();
+- } else if (status != DLM_NORMAL) {
++ } else if (status != DLM_NORMAL && status != DLM_IVLOCKID) {
+ mlog(ML_ERROR, "AST to node %u returned %d!\n",
+ lock->ml.node, status);
+ /* ignore it */
+diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
+index 14530ee..fa96818 100644
+--- a/fs/ocfs2/dlm/dlmcommon.h
++++ b/fs/ocfs2/dlm/dlmcommon.h
+@@ -747,6 +747,7 @@ void dlm_change_lockres_owner(struct dlm
+ u8 owner);
+ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
+ const char *lockid,
++ int namelen,
+ int flags);
+ struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm,
+ const char *name,
+diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
+index 033ad17..16b8d1b 100644
+--- a/fs/ocfs2/dlm/dlmfs.c
++++ b/fs/ocfs2/dlm/dlmfs.c
+@@ -335,11 +335,10 @@ static struct inode *dlmfs_get_root_inod
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+- inode->i_nlink++;
++ inc_nlink(inode);
+
+ inode->i_fop = &simple_dir_operations;
+ inode->i_op = &dlmfs_root_inode_operations;
+@@ -362,7 +361,6 @@ static struct inode *dlmfs_get_inode(str
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+@@ -397,7 +395,7 @@ static struct inode *dlmfs_get_inode(str
+
+ /* directory inodes start off with i_nlink ==
+ * 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ break;
+ }
+
+@@ -451,7 +449,7 @@ static int dlmfs_mkdir(struct inode * di
+ }
+ ip->ip_dlm = dlm;
+
+- dir->i_nlink++;
++ inc_nlink(dir);
+ d_instantiate(dentry, inode);
+ dget(dentry); /* Extra count - pin the dentry in core */
+
+@@ -629,9 +627,7 @@ static void __exit exit_dlmfs_fs(void)
+ flush_workqueue(user_dlm_worker);
+ destroy_workqueue(user_dlm_worker);
+
+- if (kmem_cache_destroy(dlmfs_inode_cache))
+- printk(KERN_INFO "dlmfs_inode_cache: not all structures "
+- "were freed\n");
++ kmem_cache_destroy(dlmfs_inode_cache);
+ }
+
+ MODULE_AUTHOR("Oracle");
+diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c
+index 5ca57ec..42a1b91 100644
+--- a/fs/ocfs2/dlm/dlmlock.c
++++ b/fs/ocfs2/dlm/dlmlock.c
+@@ -540,8 +540,8 @@ static inline void dlm_get_next_cookie(u
+
+ enum dlm_status dlmlock(struct dlm_ctxt *dlm, int mode,
+ struct dlm_lockstatus *lksb, int flags,
+- const char *name, dlm_astlockfunc_t *ast, void *data,
+- dlm_bastlockfunc_t *bast)
++ const char *name, int namelen, dlm_astlockfunc_t *ast,
++ void *data, dlm_bastlockfunc_t *bast)
+ {
+ enum dlm_status status;
+ struct dlm_lock_resource *res = NULL;
+@@ -571,7 +571,7 @@ enum dlm_status dlmlock(struct dlm_ctxt
+ recovery = (flags & LKM_RECOVERY);
+
+ if (recovery &&
+- (!dlm_is_recovery_lock(name, strlen(name)) || convert) ) {
++ (!dlm_is_recovery_lock(name, namelen) || convert) ) {
+ dlm_error(status);
+ goto error;
+ }
+@@ -643,7 +643,7 @@ retry_convert:
+ }
+
+ status = DLM_IVBUFLEN;
+- if (strlen(name) > DLM_LOCKID_NAME_MAX || strlen(name) < 1) {
++ if (namelen > DLM_LOCKID_NAME_MAX || namelen < 1) {
+ dlm_error(status);
+ goto error;
+ }
+@@ -659,7 +659,7 @@ retry_convert:
+ dlm_wait_for_recovery(dlm);
+
+ /* find or create the lock resource */
+- res = dlm_get_lock_resource(dlm, name, flags);
++ res = dlm_get_lock_resource(dlm, name, namelen, flags);
+ if (!res) {
+ status = DLM_IVLOCKID;
+ dlm_error(status);
+diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
+index 9503240..f784177 100644
+--- a/fs/ocfs2/dlm/dlmmaster.c
++++ b/fs/ocfs2/dlm/dlmmaster.c
+@@ -740,6 +740,7 @@ struct dlm_lock_resource *dlm_new_lockre
+ */
+ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
+ const char *lockid,
++ int namelen,
+ int flags)
+ {
+ struct dlm_lock_resource *tmpres=NULL, *res=NULL;
+@@ -748,13 +749,12 @@ struct dlm_lock_resource * dlm_get_lock_
+ int blocked = 0;
+ int ret, nodenum;
+ struct dlm_node_iter iter;
+- unsigned int namelen, hash;
++ unsigned int hash;
+ int tries = 0;
+ int bit, wait_on_recovery = 0;
+
+ BUG_ON(!lockid);
+
+- namelen = strlen(lockid);
+ hash = dlm_lockid_hash(lockid, namelen);
+
+ mlog(0, "get lockres %s (len %d)\n", lockid, namelen);
+diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
+index 594745f..9d950d7 100644
+--- a/fs/ocfs2/dlm/dlmrecovery.c
++++ b/fs/ocfs2/dlm/dlmrecovery.c
+@@ -2285,7 +2285,8 @@ again:
+ memset(&lksb, 0, sizeof(lksb));
+
+ ret = dlmlock(dlm, LKM_EXMODE, &lksb, LKM_NOQUEUE|LKM_RECOVERY,
+- DLM_RECOVERY_LOCK_NAME, dlm_reco_ast, dlm, dlm_reco_bast);
++ DLM_RECOVERY_LOCK_NAME, DLM_RECOVERY_LOCK_NAME_LEN,
++ dlm_reco_ast, dlm, dlm_reco_bast);
+
+ mlog(0, "%s: dlmlock($RECOVERY) returned %d, lksb=%d\n",
+ dlm->name, ret, lksb.status);
+diff --git a/fs/ocfs2/dlm/userdlm.c b/fs/ocfs2/dlm/userdlm.c
+index e641b08..eead48b 100644
+--- a/fs/ocfs2/dlm/userdlm.c
++++ b/fs/ocfs2/dlm/userdlm.c
+@@ -102,10 +102,10 @@ static inline void user_recover_from_dlm
+ spin_unlock(&lockres->l_lock);
+ }
+
+-#define user_log_dlm_error(_func, _stat, _lockres) do { \
+- mlog(ML_ERROR, "Dlm error \"%s\" while calling %s on " \
+- "resource %s: %s\n", dlm_errname(_stat), _func, \
+- _lockres->l_name, dlm_errmsg(_stat)); \
++#define user_log_dlm_error(_func, _stat, _lockres) do { \
++ mlog(ML_ERROR, "Dlm error \"%s\" while calling %s on " \
++ "resource %.*s: %s\n", dlm_errname(_stat), _func, \
++ _lockres->l_namelen, _lockres->l_name, dlm_errmsg(_stat)); \
+ } while (0)
+
+ /* WARNING: This function lives in a world where the only three lock
+@@ -127,21 +127,22 @@ static void user_ast(void *opaque)
+ struct user_lock_res *lockres = opaque;
+ struct dlm_lockstatus *lksb;
+
+- mlog(0, "AST fired for lockres %s\n", lockres->l_name);
++ mlog(0, "AST fired for lockres %.*s\n", lockres->l_namelen,
++ lockres->l_name);
+
+ spin_lock(&lockres->l_lock);
+
+ lksb = &(lockres->l_lksb);
+ if (lksb->status != DLM_NORMAL) {
+- mlog(ML_ERROR, "lksb status value of %u on lockres %s\n",
+- lksb->status, lockres->l_name);
++ mlog(ML_ERROR, "lksb status value of %u on lockres %.*s\n",
++ lksb->status, lockres->l_namelen, lockres->l_name);
+ spin_unlock(&lockres->l_lock);
+ return;
+ }
+
+ mlog_bug_on_msg(lockres->l_requested == LKM_IVMODE,
+- "Lockres %s, requested ivmode. flags 0x%x\n",
+- lockres->l_name, lockres->l_flags);
++ "Lockres %.*s, requested ivmode. flags 0x%x\n",
++ lockres->l_namelen, lockres->l_name, lockres->l_flags);
+
+ /* we're downconverting. */
+ if (lockres->l_requested < lockres->l_level) {
+@@ -213,8 +214,8 @@ static void user_bast(void *opaque, int
+ {
+ struct user_lock_res *lockres = opaque;
+
+- mlog(0, "Blocking AST fired for lockres %s. Blocking level %d\n",
+- lockres->l_name, level);
++ mlog(0, "Blocking AST fired for lockres %.*s. Blocking level %d\n",
++ lockres->l_namelen, lockres->l_name, level);
+
+ spin_lock(&lockres->l_lock);
+ lockres->l_flags |= USER_LOCK_BLOCKED;
+@@ -231,7 +232,8 @@ static void user_unlock_ast(void *opaque
+ {
+ struct user_lock_res *lockres = opaque;
+
+- mlog(0, "UNLOCK AST called on lock %s\n", lockres->l_name);
++ mlog(0, "UNLOCK AST called on lock %.*s\n", lockres->l_namelen,
++ lockres->l_name);
+
+ if (status != DLM_NORMAL && status != DLM_CANCELGRANT)
+ mlog(ML_ERROR, "Dlm returns status %d\n", status);
+@@ -244,8 +246,6 @@ static void user_unlock_ast(void *opaque
+ && !(lockres->l_flags & USER_LOCK_IN_CANCEL)) {
+ lockres->l_level = LKM_IVMODE;
+ } else if (status == DLM_CANCELGRANT) {
+- mlog(0, "Lock %s, cancel fails, flags 0x%x\n",
+- lockres->l_name, lockres->l_flags);
+ /* We tried to cancel a convert request, but it was
+ * already granted. Don't clear the busy flag - the
+ * ast should've done this already. */
+@@ -255,8 +255,6 @@ static void user_unlock_ast(void *opaque
+ } else {
+ BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
+ /* Cancel succeeded, we want to re-queue */
+- mlog(0, "Lock %s, cancel succeeds, flags 0x%x\n",
+- lockres->l_name, lockres->l_flags);
+ lockres->l_requested = LKM_IVMODE; /* cancel an
+ * upconvert
+ * request. */
+@@ -287,13 +285,14 @@ static void user_dlm_unblock_lock(void *
+ struct user_lock_res *lockres = (struct user_lock_res *) opaque;
+ struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres);
+
+- mlog(0, "processing lockres %s\n", lockres->l_name);
++ mlog(0, "processing lockres %.*s\n", lockres->l_namelen,
++ lockres->l_name);
+
+ spin_lock(&lockres->l_lock);
+
+ mlog_bug_on_msg(!(lockres->l_flags & USER_LOCK_QUEUED),
+- "Lockres %s, flags 0x%x\n",
+- lockres->l_name, lockres->l_flags);
++ "Lockres %.*s, flags 0x%x\n",
++ lockres->l_namelen, lockres->l_name, lockres->l_flags);
+
+ /* notice that we don't clear USER_LOCK_BLOCKED here. If it's
+ * set, we want user_ast clear it. */
+@@ -305,22 +304,16 @@ static void user_dlm_unblock_lock(void *
+ * flag, and finally we might get another bast which re-queues
+ * us before our ast for the downconvert is called. */
+ if (!(lockres->l_flags & USER_LOCK_BLOCKED)) {
+- mlog(0, "Lockres %s, flags 0x%x: queued but not blocking\n",
+- lockres->l_name, lockres->l_flags);
+ spin_unlock(&lockres->l_lock);
+ goto drop_ref;
+ }
+
+ if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
+- mlog(0, "lock is in teardown so we do nothing\n");
+ spin_unlock(&lockres->l_lock);
+ goto drop_ref;
+ }
+
+ if (lockres->l_flags & USER_LOCK_BUSY) {
+- mlog(0, "Cancel lock %s, flags 0x%x\n",
+- lockres->l_name, lockres->l_flags);
+-
+ if (lockres->l_flags & USER_LOCK_IN_CANCEL) {
+ spin_unlock(&lockres->l_lock);
+ goto drop_ref;
+@@ -372,6 +365,7 @@ static void user_dlm_unblock_lock(void *
+ &lockres->l_lksb,
+ LKM_CONVERT|LKM_VALBLK,
+ lockres->l_name,
++ lockres->l_namelen,
+ user_ast,
+ lockres,
+ user_bast);
+@@ -420,16 +414,16 @@ int user_dlm_cluster_lock(struct user_lo
+
+ if (level != LKM_EXMODE &&
+ level != LKM_PRMODE) {
+- mlog(ML_ERROR, "lockres %s: invalid request!\n",
+- lockres->l_name);
++ mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
++ lockres->l_namelen, lockres->l_name);
+ status = -EINVAL;
+ goto bail;
+ }
+
+- mlog(0, "lockres %s: asking for %s lock, passed flags = 0x%x\n",
+- lockres->l_name,
+- (level == LKM_EXMODE) ? "LKM_EXMODE" : "LKM_PRMODE",
+- lkm_flags);
++ mlog(0, "lockres %.*s: asking for %s lock, passed flags = 0x%x\n",
++ lockres->l_namelen, lockres->l_name,
++ (level == LKM_EXMODE) ? "LKM_EXMODE" : "LKM_PRMODE",
++ lkm_flags);
+
+ again:
+ if (signal_pending(current)) {
+@@ -474,15 +468,13 @@ again:
+ BUG_ON(level == LKM_IVMODE);
+ BUG_ON(level == LKM_NLMODE);
+
+- mlog(0, "lock %s, get lock from %d to level = %d\n",
+- lockres->l_name, lockres->l_level, level);
+-
+ /* call dlm_lock to upgrade lock now */
+ status = dlmlock(dlm,
+ level,
+ &lockres->l_lksb,
+ local_flags,
+ lockres->l_name,
++ lockres->l_namelen,
+ user_ast,
+ lockres,
+ user_bast);
+@@ -498,9 +490,6 @@ again:
+ goto bail;
+ }
+
+- mlog(0, "lock %s, successfull return from dlmlock\n",
+- lockres->l_name);
+-
+ user_wait_on_busy_lock(lockres);
+ goto again;
+ }
+@@ -508,9 +497,6 @@ again:
+ user_dlm_inc_holders(lockres, level);
+ spin_unlock(&lockres->l_lock);
+
+- mlog(0, "lockres %s: Got %s lock!\n", lockres->l_name,
+- (level == LKM_EXMODE) ? "LKM_EXMODE" : "LKM_PRMODE");
+-
+ status = 0;
+ bail:
+ return status;
+@@ -538,13 +524,11 @@ void user_dlm_cluster_unlock(struct user
+ {
+ if (level != LKM_EXMODE &&
+ level != LKM_PRMODE) {
+- mlog(ML_ERROR, "lockres %s: invalid request!\n", lockres->l_name);
++ mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
++ lockres->l_namelen, lockres->l_name);
+ return;
+ }
+
+- mlog(0, "lockres %s: dropping %s lock\n", lockres->l_name,
+- (level == LKM_EXMODE) ? "LKM_EXMODE" : "LKM_PRMODE");
+-
+ spin_lock(&lockres->l_lock);
+ user_dlm_dec_holders(lockres, level);
+ __user_dlm_cond_queue_lockres(lockres);
+@@ -602,6 +586,7 @@ void user_dlm_lock_res_init(struct user_
+ memcpy(lockres->l_name,
+ dentry->d_name.name,
+ dentry->d_name.len);
++ lockres->l_namelen = dentry->d_name.len;
+ }
+
+ int user_dlm_destroy_lock(struct user_lock_res *lockres)
+@@ -609,11 +594,10 @@ int user_dlm_destroy_lock(struct user_lo
+ int status = -EBUSY;
+ struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres);
+
+- mlog(0, "asked to destroy %s\n", lockres->l_name);
++ mlog(0, "asked to destroy %.*s\n", lockres->l_namelen, lockres->l_name);
+
+ spin_lock(&lockres->l_lock);
+ if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
+- mlog(0, "Lock is already torn down\n");
+ spin_unlock(&lockres->l_lock);
+ return 0;
+ }
+@@ -623,8 +607,6 @@ int user_dlm_destroy_lock(struct user_lo
+ while (lockres->l_flags & USER_LOCK_BUSY) {
+ spin_unlock(&lockres->l_lock);
+
+- mlog(0, "lock %s is busy\n", lockres->l_name);
+-
+ user_wait_on_busy_lock(lockres);
+
+ spin_lock(&lockres->l_lock);
+@@ -632,14 +614,12 @@ int user_dlm_destroy_lock(struct user_lo
+
+ if (lockres->l_ro_holders || lockres->l_ex_holders) {
+ spin_unlock(&lockres->l_lock);
+- mlog(0, "lock %s has holders\n", lockres->l_name);
+ goto bail;
+ }
+
+ status = 0;
+ if (!(lockres->l_flags & USER_LOCK_ATTACHED)) {
+ spin_unlock(&lockres->l_lock);
+- mlog(0, "lock %s is not attached\n", lockres->l_name);
+ goto bail;
+ }
+
+@@ -647,7 +627,6 @@ int user_dlm_destroy_lock(struct user_lo
+ lockres->l_flags |= USER_LOCK_BUSY;
+ spin_unlock(&lockres->l_lock);
+
+- mlog(0, "unlocking lockres %s\n", lockres->l_name);
+ status = dlmunlock(dlm,
+ &lockres->l_lksb,
+ LKM_VALBLK,
+diff --git a/fs/ocfs2/dlm/userdlm.h b/fs/ocfs2/dlm/userdlm.h
+index 04178bc..c400e93 100644
+--- a/fs/ocfs2/dlm/userdlm.h
++++ b/fs/ocfs2/dlm/userdlm.h
+@@ -53,6 +53,7 @@ struct user_lock_res {
+
+ #define USER_DLM_LOCK_ID_MAX_LEN 32
+ char l_name[USER_DLM_LOCK_ID_MAX_LEN];
++ int l_namelen;
+ int l_level;
+ unsigned int l_ro_holders;
+ unsigned int l_ex_holders;
+diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
+index 762eb1f..8801e41 100644
+--- a/fs/ocfs2/dlmglue.c
++++ b/fs/ocfs2/dlmglue.c
+@@ -46,6 +46,7 @@
+ #include "ocfs2.h"
+
+ #include "alloc.h"
++#include "dcache.h"
+ #include "dlmglue.h"
+ #include "extent_map.h"
+ #include "heartbeat.h"
+@@ -66,78 +67,161 @@ struct ocfs2_mask_waiter {
+ unsigned long mw_goal;
+ };
+
+-static void ocfs2_inode_ast_func(void *opaque);
+-static void ocfs2_inode_bast_func(void *opaque,
+- int level);
+-static void ocfs2_super_ast_func(void *opaque);
+-static void ocfs2_super_bast_func(void *opaque,
+- int level);
+-static void ocfs2_rename_ast_func(void *opaque);
+-static void ocfs2_rename_bast_func(void *opaque,
+- int level);
+-
+-/* so far, all locks have gotten along with the same unlock ast */
+-static void ocfs2_unlock_ast_func(void *opaque,
+- enum dlm_status status);
+-static int ocfs2_do_unblock_meta(struct inode *inode,
+- int *requeue);
+-static int ocfs2_unblock_meta(struct ocfs2_lock_res *lockres,
+- int *requeue);
+-static int ocfs2_unblock_data(struct ocfs2_lock_res *lockres,
+- int *requeue);
+-static int ocfs2_unblock_inode_lock(struct ocfs2_lock_res *lockres,
+- int *requeue);
+-static int ocfs2_unblock_osb_lock(struct ocfs2_lock_res *lockres,
+- int *requeue);
+-typedef void (ocfs2_convert_worker_t)(struct ocfs2_lock_res *, int);
+-static int ocfs2_generic_unblock_lock(struct ocfs2_super *osb,
+- struct ocfs2_lock_res *lockres,
+- int *requeue,
+- ocfs2_convert_worker_t *worker);
++static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
++static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
+
++/*
++ * Return value from ->downconvert_worker functions.
++ *
++ * These control the precise actions of ocfs2_unblock_lock()
++ * and ocfs2_process_blocked_lock()
++ *
++ */
++enum ocfs2_unblock_action {
++ UNBLOCK_CONTINUE = 0, /* Continue downconvert */
++ UNBLOCK_CONTINUE_POST = 1, /* Continue downconvert, fire
++ * ->post_unlock callback */
++ UNBLOCK_STOP_POST = 2, /* Do not downconvert, fire
++ * ->post_unlock() callback. */
++};
++
++struct ocfs2_unblock_ctl {
++ int requeue;
++ enum ocfs2_unblock_action unblock_action;
++};
++
++static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
++ int new_level);
++static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres);
++
++static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
++ int blocking);
++
++static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
++ int blocking);
++
++static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres);
++
++/*
++ * OCFS2 Lock Resource Operations
++ *
++ * These fine tune the behavior of the generic dlmglue locking infrastructure.
++ *
++ * The most basic of lock types can point ->l_priv to their respective
++ * struct ocfs2_super and allow the default actions to manage things.
++ *
++ * Right now, each lock type also needs to implement an init function,
++ * and trivial lock/unlock wrappers. ocfs2_simple_drop_lockres()
++ * should be called when the lock is no longer needed (i.e., object
++ * destruction time).
++ */
+ struct ocfs2_lock_res_ops {
+- void (*ast)(void *);
+- void (*bast)(void *, int);
+- void (*unlock_ast)(void *, enum dlm_status);
+- int (*unblock)(struct ocfs2_lock_res *, int *);
++ /*
++ * Translate an ocfs2_lock_res * into an ocfs2_super *. Define
++ * this callback if ->l_priv is not an ocfs2_super pointer
++ */
++ struct ocfs2_super * (*get_osb)(struct ocfs2_lock_res *);
++
++ /*
++ * Optionally called in the downconvert (or "vote") thread
++ * after a successful downconvert. The lockres will not be
++ * referenced after this callback is called, so it is safe to
++ * free memory, etc.
++ *
++ * The exact semantics of when this is called are controlled
++ * by ->downconvert_worker()
++ */
++ void (*post_unlock)(struct ocfs2_super *, struct ocfs2_lock_res *);
++
++ /*
++ * Allow a lock type to add checks to determine whether it is
++ * safe to downconvert a lock. Return 0 to re-queue the
++ * downconvert at a later time, nonzero to continue.
++ *
++ * For most locks, the default checks that there are no
++ * incompatible holders are sufficient.
++ *
++ * Called with the lockres spinlock held.
++ */
++ int (*check_downconvert)(struct ocfs2_lock_res *, int);
++
++ /*
++ * Allows a lock type to populate the lock value block. This
++ * is called on downconvert, and when we drop a lock.
++ *
++ * Locks that want to use this should set LOCK_TYPE_USES_LVB
++ * in the flags field.
++ *
++ * Called with the lockres spinlock held.
++ */
++ void (*set_lvb)(struct ocfs2_lock_res *);
++
++ /*
++ * Called from the downconvert thread when it is determined
++ * that a lock will be downconverted. This is called without
++ * any locks held so the function can do work that might
++ * schedule (syncing out data, etc).
++ *
++ * This should return any one of the ocfs2_unblock_action
++ * values, depending on what it wants the thread to do.
++ */
++ int (*downconvert_worker)(struct ocfs2_lock_res *, int);
++
++ /*
++ * LOCK_TYPE_* flags which describe the specific requirements
++ * of a lock type. Descriptions of each individual flag follow.
++ */
++ int flags;
+ };
+
++/*
++ * Some locks want to "refresh" potentially stale data when a
++ * meaningful (PRMODE or EXMODE) lock level is first obtained. If this
++ * flag is set, the OCFS2_LOCK_NEEDS_REFRESH flag will be set on the
++ * individual lockres l_flags member from the ast function. It is
++ * expected that the locking wrapper will clear the
++ * OCFS2_LOCK_NEEDS_REFRESH flag when done.
++ */
++#define LOCK_TYPE_REQUIRES_REFRESH 0x1
++
++/*
++ * Indicate that a lock type makes use of the lock value block. The
++ * ->set_lvb lock type callback must be defined.
++ */
++#define LOCK_TYPE_USES_LVB 0x2
++
+ static struct ocfs2_lock_res_ops ocfs2_inode_rw_lops = {
+- .ast = ocfs2_inode_ast_func,
+- .bast = ocfs2_inode_bast_func,
+- .unlock_ast = ocfs2_unlock_ast_func,
+- .unblock = ocfs2_unblock_inode_lock,
++ .get_osb = ocfs2_get_inode_osb,
++ .flags = 0,
+ };
+
+ static struct ocfs2_lock_res_ops ocfs2_inode_meta_lops = {
+- .ast = ocfs2_inode_ast_func,
+- .bast = ocfs2_inode_bast_func,
+- .unlock_ast = ocfs2_unlock_ast_func,
+- .unblock = ocfs2_unblock_meta,
++ .get_osb = ocfs2_get_inode_osb,
++ .check_downconvert = ocfs2_check_meta_downconvert,
++ .set_lvb = ocfs2_set_meta_lvb,
++ .flags = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
+ };
+
+-static void ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
+- int blocking);
+-
+ static struct ocfs2_lock_res_ops ocfs2_inode_data_lops = {
+- .ast = ocfs2_inode_ast_func,
+- .bast = ocfs2_inode_bast_func,
+- .unlock_ast = ocfs2_unlock_ast_func,
+- .unblock = ocfs2_unblock_data,
++ .get_osb = ocfs2_get_inode_osb,
++ .downconvert_worker = ocfs2_data_convert_worker,
++ .flags = 0,
+ };
+
+ static struct ocfs2_lock_res_ops ocfs2_super_lops = {
+- .ast = ocfs2_super_ast_func,
+- .bast = ocfs2_super_bast_func,
+- .unlock_ast = ocfs2_unlock_ast_func,
+- .unblock = ocfs2_unblock_osb_lock,
++ .flags = LOCK_TYPE_REQUIRES_REFRESH,
+ };
+
+ static struct ocfs2_lock_res_ops ocfs2_rename_lops = {
+- .ast = ocfs2_rename_ast_func,
+- .bast = ocfs2_rename_bast_func,
+- .unlock_ast = ocfs2_unlock_ast_func,
+- .unblock = ocfs2_unblock_osb_lock,
++ .flags = 0,
++};
++
++static struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
++ .get_osb = ocfs2_get_dentry_osb,
++ .post_unlock = ocfs2_dentry_post_unlock,
++ .downconvert_worker = ocfs2_dentry_convert_worker,
++ .flags = 0,
+ };
+
+ static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
+@@ -147,29 +231,26 @@ static inline int ocfs2_is_inode_lock(st
+ lockres->l_type == OCFS2_LOCK_TYPE_RW;
+ }
+
+-static inline int ocfs2_is_super_lock(struct ocfs2_lock_res *lockres)
++static inline struct inode *ocfs2_lock_res_inode(struct ocfs2_lock_res *lockres)
+ {
+- return lockres->l_type == OCFS2_LOCK_TYPE_SUPER;
+-}
++ BUG_ON(!ocfs2_is_inode_lock(lockres));
+
+-static inline int ocfs2_is_rename_lock(struct ocfs2_lock_res *lockres)
+-{
+- return lockres->l_type == OCFS2_LOCK_TYPE_RENAME;
++ return (struct inode *) lockres->l_priv;
+ }
+
+-static inline struct ocfs2_super *ocfs2_lock_res_super(struct ocfs2_lock_res *lockres)
++static inline struct ocfs2_dentry_lock *ocfs2_lock_res_dl(struct ocfs2_lock_res *lockres)
+ {
+- BUG_ON(!ocfs2_is_super_lock(lockres)
+- && !ocfs2_is_rename_lock(lockres));
++ BUG_ON(lockres->l_type != OCFS2_LOCK_TYPE_DENTRY);
+
+- return (struct ocfs2_super *) lockres->l_priv;
++ return (struct ocfs2_dentry_lock *)lockres->l_priv;
+ }
+
+-static inline struct inode *ocfs2_lock_res_inode(struct ocfs2_lock_res *lockres)
++static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
+ {
+- BUG_ON(!ocfs2_is_inode_lock(lockres));
++ if (lockres->l_ops->get_osb)
++ return lockres->l_ops->get_osb(lockres);
+
+- return (struct inode *) lockres->l_priv;
++ return (struct ocfs2_super *)lockres->l_priv;
+ }
+
+ static int ocfs2_lock_create(struct ocfs2_super *osb,
+@@ -200,25 +281,6 @@ static int ocfs2_meta_lock_update(struct
+ struct buffer_head **bh);
+ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb);
+ static inline int ocfs2_highest_compat_lock_level(int level);
+-static inline int ocfs2_can_downconvert_meta_lock(struct inode *inode,
+- struct ocfs2_lock_res *lockres,
+- int new_level);
+-
+-static char *ocfs2_lock_type_strings[] = {
+- [OCFS2_LOCK_TYPE_META] = "Meta",
+- [OCFS2_LOCK_TYPE_DATA] = "Data",
+- [OCFS2_LOCK_TYPE_SUPER] = "Super",
+- [OCFS2_LOCK_TYPE_RENAME] = "Rename",
+- /* Need to differntiate from [R]ename.. serializing writes is the
+- * important job it does, anyway. */
+- [OCFS2_LOCK_TYPE_RW] = "Write/Read",
+-};
+-
+-static char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
+-{
+- mlog_bug_on_msg(type >= OCFS2_NUM_LOCK_TYPES, "%d\n", type);
+- return ocfs2_lock_type_strings[type];
+-}
+
+ static void ocfs2_build_lock_name(enum ocfs2_lock_type type,
+ u64 blkno,
+@@ -265,13 +327,9 @@ static void ocfs2_remove_lockres_trackin
+ static void ocfs2_lock_res_init_common(struct ocfs2_super *osb,
+ struct ocfs2_lock_res *res,
+ enum ocfs2_lock_type type,
+- u64 blkno,
+- u32 generation,
+ struct ocfs2_lock_res_ops *ops,
+ void *priv)
+ {
+- ocfs2_build_lock_name(type, blkno, generation, res->l_name);
+-
+ res->l_type = type;
+ res->l_ops = ops;
+ res->l_priv = priv;
+@@ -299,6 +357,7 @@ void ocfs2_lock_res_init_once(struct ocf
+
+ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
+ enum ocfs2_lock_type type,
++ unsigned int generation,
+ struct inode *inode)
+ {
+ struct ocfs2_lock_res_ops *ops;
+@@ -319,9 +378,73 @@ void ocfs2_inode_lock_res_init(struct oc
+ break;
+ };
+
+- ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), res, type,
+- OCFS2_I(inode)->ip_blkno,
+- inode->i_generation, ops, inode);
++ ocfs2_build_lock_name(type, OCFS2_I(inode)->ip_blkno,
++ generation, res->l_name);
++ ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), res, type, ops, inode);
++}
++
++static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres)
++{
++ struct inode *inode = ocfs2_lock_res_inode(lockres);
++
++ return OCFS2_SB(inode->i_sb);
++}
++
++static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres)
++{
++ __be64 inode_blkno_be;
++
++ memcpy(&inode_blkno_be, &lockres->l_name[OCFS2_DENTRY_LOCK_INO_START],
++ sizeof(__be64));
++
++ return be64_to_cpu(inode_blkno_be);
++}
++
++static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres)
++{
++ struct ocfs2_dentry_lock *dl = lockres->l_priv;
++
++ return OCFS2_SB(dl->dl_inode->i_sb);
++}
++
++void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
++ u64 parent, struct inode *inode)
++{
++ int len;
++ u64 inode_blkno = OCFS2_I(inode)->ip_blkno;
++ __be64 inode_blkno_be = cpu_to_be64(inode_blkno);
++ struct ocfs2_lock_res *lockres = &dl->dl_lockres;
++
++ ocfs2_lock_res_init_once(lockres);
++
++ /*
++ * Unfortunately, the standard lock naming scheme won't work
++ * here because we have two 16 byte values to use. Instead,
++ * we'll stuff the inode number as a binary value. We still
++ * want error prints to show something without garbling the
++ * display, so drop a null byte in there before the inode
++ * number. A future version of OCFS2 will likely use all
++ * binary lock names. The stringified names have been a
++ * tremendous aid in debugging, but now that the debugfs
++ * interface exists, we can mangle things there if need be.
++ *
++ * NOTE: We also drop the standard "pad" value (the total lock
++ * name size stays the same though - the last part is all
++ * zeros due to the memset in ocfs2_lock_res_init_once()
++ */
++ len = snprintf(lockres->l_name, OCFS2_DENTRY_LOCK_INO_START,
++ "%c%016llx",
++ ocfs2_lock_type_char(OCFS2_LOCK_TYPE_DENTRY),
++ (long long)parent);
++
++ BUG_ON(len != (OCFS2_DENTRY_LOCK_INO_START - 1));
++
++ memcpy(&lockres->l_name[OCFS2_DENTRY_LOCK_INO_START], &inode_blkno_be,
++ sizeof(__be64));
++
++ ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres,
++ OCFS2_LOCK_TYPE_DENTRY, &ocfs2_dentry_lops,
++ dl);
+ }
+
+ static void ocfs2_super_lock_res_init(struct ocfs2_lock_res *res,
+@@ -330,8 +453,9 @@ static void ocfs2_super_lock_res_init(st
+ /* Superblock lockres doesn't come from a slab so we call init
+ * once on it manually. */
+ ocfs2_lock_res_init_once(res);
++ ocfs2_build_lock_name(OCFS2_LOCK_TYPE_SUPER, OCFS2_SUPER_BLOCK_BLKNO,
++ 0, res->l_name);
+ ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_SUPER,
+- OCFS2_SUPER_BLOCK_BLKNO, 0,
+ &ocfs2_super_lops, osb);
+ }
+
+@@ -341,7 +465,8 @@ static void ocfs2_rename_lock_res_init(s
+ /* Rename lockres doesn't come from a slab so we call init
+ * once on it manually. */
+ ocfs2_lock_res_init_once(res);
+- ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_RENAME, 0, 0,
++ ocfs2_build_lock_name(OCFS2_LOCK_TYPE_RENAME, 0, 0, res->l_name);
++ ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_RENAME,
+ &ocfs2_rename_lops, osb);
+ }
+
+@@ -495,7 +620,8 @@ static inline void ocfs2_generic_handle_
+ * information is already up to data. Convert from NL to
+ * *anything* however should mark ourselves as needing an
+ * update */
+- if (lockres->l_level == LKM_NLMODE)
++ if (lockres->l_level == LKM_NLMODE &&
++ lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH)
+ lockres_or_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
+
+ lockres->l_level = lockres->l_requested;
+@@ -512,7 +638,8 @@ static inline void ocfs2_generic_handle_
+ BUG_ON(lockres->l_flags & OCFS2_LOCK_ATTACHED);
+
+ if (lockres->l_requested > LKM_NLMODE &&
+- !(lockres->l_flags & OCFS2_LOCK_LOCAL))
++ !(lockres->l_flags & OCFS2_LOCK_LOCAL) &&
++ lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH)
+ lockres_or_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
+
+ lockres->l_level = lockres->l_requested;
+@@ -522,68 +649,6 @@ static inline void ocfs2_generic_handle_
+ mlog_exit_void();
+ }
+
+-static void ocfs2_inode_ast_func(void *opaque)
+-{
+- struct ocfs2_lock_res *lockres = opaque;
+- struct inode *inode;
+- struct dlm_lockstatus *lksb;
+- unsigned long flags;
+-
+- mlog_entry_void();
+-
+- inode = ocfs2_lock_res_inode(lockres);
+-
+- mlog(0, "AST fired for inode %llu, l_action = %u, type = %s\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno, lockres->l_action,
+- ocfs2_lock_type_string(lockres->l_type));
+-
+- BUG_ON(!ocfs2_is_inode_lock(lockres));
+-
+- spin_lock_irqsave(&lockres->l_lock, flags);
+-
+- lksb = &(lockres->l_lksb);
+- if (lksb->status != DLM_NORMAL) {
+- mlog(ML_ERROR, "ocfs2_inode_ast_func: lksb status value of %u "
+- "on inode %llu\n", lksb->status,
+- (unsigned long long)OCFS2_I(inode)->ip_blkno);
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- mlog_exit_void();
+- return;
+- }
+-
+- switch(lockres->l_action) {
+- case OCFS2_AST_ATTACH:
+- ocfs2_generic_handle_attach_action(lockres);
+- lockres_clear_flags(lockres, OCFS2_LOCK_LOCAL);
+- break;
+- case OCFS2_AST_CONVERT:
+- ocfs2_generic_handle_convert_action(lockres);
+- break;
+- case OCFS2_AST_DOWNCONVERT:
+- ocfs2_generic_handle_downconvert_action(lockres);
+- break;
+- default:
+- mlog(ML_ERROR, "lockres %s: ast fired with invalid action: %u "
+- "lockres flags = 0x%lx, unlock action: %u\n",
+- lockres->l_name, lockres->l_action, lockres->l_flags,
+- lockres->l_unlock_action);
+-
+- BUG();
+- }
+-
+- /* data and rw locking ignores refresh flag for now. */
+- if (lockres->l_type != OCFS2_LOCK_TYPE_META)
+- lockres_clear_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
+-
+- /* set it to something invalid so if we get called again we
+- * can catch it. */
+- lockres->l_action = OCFS2_AST_INVALID;
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- wake_up(&lockres->l_event);
+-
+- mlog_exit_void();
+-}
+-
+ static int ocfs2_generic_handle_bast(struct ocfs2_lock_res *lockres,
+ int level)
+ {
+@@ -610,54 +675,33 @@ static int ocfs2_generic_handle_bast(str
+ return needs_downconvert;
+ }
+
+-static void ocfs2_generic_bast_func(struct ocfs2_super *osb,
+- struct ocfs2_lock_res *lockres,
+- int level)
++static void ocfs2_blocking_ast(void *opaque, int level)
+ {
++ struct ocfs2_lock_res *lockres = opaque;
++ struct ocfs2_super *osb = ocfs2_get_lockres_osb(lockres);
+ int needs_downconvert;
+ unsigned long flags;
+
+- mlog_entry_void();
+-
+ BUG_ON(level <= LKM_NLMODE);
+
++ mlog(0, "BAST fired for lockres %s, blocking %d, level %d type %s\n",
++ lockres->l_name, level, lockres->l_level,
++ ocfs2_lock_type_string(lockres->l_type));
++
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ needs_downconvert = ocfs2_generic_handle_bast(lockres, level);
+ if (needs_downconvert)
+ ocfs2_schedule_blocked_lock(osb, lockres);
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+- ocfs2_kick_vote_thread(osb);
+-
+ wake_up(&lockres->l_event);
+- mlog_exit_void();
+-}
+-
+-static void ocfs2_inode_bast_func(void *opaque, int level)
+-{
+- struct ocfs2_lock_res *lockres = opaque;
+- struct inode *inode;
+- struct ocfs2_super *osb;
+-
+- mlog_entry_void();
+-
+- BUG_ON(!ocfs2_is_inode_lock(lockres));
+
+- inode = ocfs2_lock_res_inode(lockres);
+- osb = OCFS2_SB(inode->i_sb);
+-
+- mlog(0, "BAST fired for inode %llu, blocking %d, level %d type %s\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno, level,
+- lockres->l_level, ocfs2_lock_type_string(lockres->l_type));
+-
+- ocfs2_generic_bast_func(osb, lockres, level);
+-
+- mlog_exit_void();
++ ocfs2_kick_vote_thread(osb);
+ }
+
+-static void ocfs2_generic_ast_func(struct ocfs2_lock_res *lockres,
+- int ignore_refresh)
++static void ocfs2_locking_ast(void *opaque)
+ {
++ struct ocfs2_lock_res *lockres = opaque;
+ struct dlm_lockstatus *lksb = &lockres->l_lksb;
+ unsigned long flags;
+
+@@ -673,6 +717,7 @@ static void ocfs2_generic_ast_func(struc
+ switch(lockres->l_action) {
+ case OCFS2_AST_ATTACH:
+ ocfs2_generic_handle_attach_action(lockres);
++ lockres_clear_flags(lockres, OCFS2_LOCK_LOCAL);
+ break;
+ case OCFS2_AST_CONVERT:
+ ocfs2_generic_handle_convert_action(lockres);
+@@ -681,80 +726,19 @@ static void ocfs2_generic_ast_func(struc
+ ocfs2_generic_handle_downconvert_action(lockres);
+ break;
+ default:
++ mlog(ML_ERROR, "lockres %s: ast fired with invalid action: %u "
++ "lockres flags = 0x%lx, unlock action: %u\n",
++ lockres->l_name, lockres->l_action, lockres->l_flags,
++ lockres->l_unlock_action);
+ BUG();
+ }
+
+- if (ignore_refresh)
+- lockres_clear_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
+-
+ /* set it to something invalid so if we get called again we
+ * can catch it. */
+ lockres->l_action = OCFS2_AST_INVALID;
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+ wake_up(&lockres->l_event);
+-}
+-
+-static void ocfs2_super_ast_func(void *opaque)
+-{
+- struct ocfs2_lock_res *lockres = opaque;
+-
+- mlog_entry_void();
+- mlog(0, "Superblock AST fired\n");
+-
+- BUG_ON(!ocfs2_is_super_lock(lockres));
+- ocfs2_generic_ast_func(lockres, 0);
+-
+- mlog_exit_void();
+-}
+-
+-static void ocfs2_super_bast_func(void *opaque,
+- int level)
+-{
+- struct ocfs2_lock_res *lockres = opaque;
+- struct ocfs2_super *osb;
+-
+- mlog_entry_void();
+- mlog(0, "Superblock BAST fired\n");
+-
+- BUG_ON(!ocfs2_is_super_lock(lockres));
+- osb = ocfs2_lock_res_super(lockres);
+- ocfs2_generic_bast_func(osb, lockres, level);
+-
+- mlog_exit_void();
+-}
+-
+-static void ocfs2_rename_ast_func(void *opaque)
+-{
+- struct ocfs2_lock_res *lockres = opaque;
+-
+- mlog_entry_void();
+-
+- mlog(0, "Rename AST fired\n");
+-
+- BUG_ON(!ocfs2_is_rename_lock(lockres));
+-
+- ocfs2_generic_ast_func(lockres, 1);
+-
+- mlog_exit_void();
+-}
+-
+-static void ocfs2_rename_bast_func(void *opaque,
+- int level)
+-{
+- struct ocfs2_lock_res *lockres = opaque;
+- struct ocfs2_super *osb;
+-
+- mlog_entry_void();
+-
+- mlog(0, "Rename BAST fired\n");
+-
+- BUG_ON(!ocfs2_is_rename_lock(lockres));
+-
+- osb = ocfs2_lock_res_super(lockres);
+- ocfs2_generic_bast_func(osb, lockres, level);
+-
+- mlog_exit_void();
++ spin_unlock_irqrestore(&lockres->l_lock, flags);
+ }
+
+ static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres,
+@@ -810,9 +794,10 @@ static int ocfs2_lock_create(struct ocfs
+ &lockres->l_lksb,
+ dlm_flags,
+ lockres->l_name,
+- lockres->l_ops->ast,
++ OCFS2_LOCK_ID_MAX_LEN - 1,
++ ocfs2_locking_ast,
+ lockres,
+- lockres->l_ops->bast);
++ ocfs2_blocking_ast);
+ if (status != DLM_NORMAL) {
+ ocfs2_log_dlm_error("dlmlock", status, lockres);
+ ret = -EINVAL;
+@@ -930,6 +915,9 @@ static int ocfs2_cluster_lock(struct ocf
+
+ ocfs2_init_mask_waiter(&mw);
+
++ if (lockres->l_ops->flags & LOCK_TYPE_USES_LVB)
++ lkm_flags |= LKM_VALBLK;
++
+ again:
+ wait = 0;
+
+@@ -997,11 +985,12 @@ again:
+ status = dlmlock(osb->dlm,
+ level,
+ &lockres->l_lksb,
+- lkm_flags|LKM_CONVERT|LKM_VALBLK,
++ lkm_flags|LKM_CONVERT,
+ lockres->l_name,
+- lockres->l_ops->ast,
++ OCFS2_LOCK_ID_MAX_LEN - 1,
++ ocfs2_locking_ast,
+ lockres,
+- lockres->l_ops->bast);
++ ocfs2_blocking_ast);
+ if (status != DLM_NORMAL) {
+ if ((lkm_flags & LKM_NOQUEUE) &&
+ (status == DLM_NOTQUEUED))
+@@ -1074,18 +1063,21 @@ static void ocfs2_cluster_unlock(struct
+ mlog_exit_void();
+ }
+
+-static int ocfs2_create_new_inode_lock(struct inode *inode,
+- struct ocfs2_lock_res *lockres)
++int ocfs2_create_new_lock(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres,
++ int ex,
++ int local)
+ {
+- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++ int level = ex ? LKM_EXMODE : LKM_PRMODE;
+ unsigned long flags;
++ int lkm_flags = local ? LKM_LOCAL : 0;
+
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ BUG_ON(lockres->l_flags & OCFS2_LOCK_ATTACHED);
+ lockres_or_flags(lockres, OCFS2_LOCK_LOCAL);
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+- return ocfs2_lock_create(osb, lockres, LKM_EXMODE, LKM_LOCAL);
++ return ocfs2_lock_create(osb, lockres, level, lkm_flags);
+ }
+
+ /* Grants us an EX lock on the data and metadata resources, skipping
+@@ -1097,6 +1089,7 @@ static int ocfs2_create_new_inode_lock(s
+ int ocfs2_create_new_inode_locks(struct inode *inode)
+ {
+ int ret;
++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ BUG_ON(!inode);
+ BUG_ON(!ocfs2_inode_is_new(inode));
+@@ -1113,22 +1106,23 @@ int ocfs2_create_new_inode_locks(struct
+ * on a resource which has an invalid one -- we'll set it
+ * valid when we release the EX. */
+
+- ret = ocfs2_create_new_inode_lock(inode,
+- &OCFS2_I(inode)->ip_rw_lockres);
++ ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_rw_lockres, 1, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto bail;
+ }
+
+- ret = ocfs2_create_new_inode_lock(inode,
+- &OCFS2_I(inode)->ip_meta_lockres);
++ /*
++ * We don't want to use LKM_LOCAL on a meta data lock as they
++ * don't use a generation in their lock names.
++ */
++ ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1, 0);
+ if (ret) {
+ mlog_errno(ret);
+ goto bail;
+ }
+
+- ret = ocfs2_create_new_inode_lock(inode,
+- &OCFS2_I(inode)->ip_data_lockres);
++ ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto bail;
+@@ -1317,7 +1311,17 @@ static void __ocfs2_stuff_meta_lvb(struc
+
+ lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
+
+- lvb->lvb_version = cpu_to_be32(OCFS2_LVB_VERSION);
++ /*
++ * Invalidate the LVB of a deleted inode - this way other
++ * nodes are forced to go to disk and discover the new inode
++ * status.
++ */
++ if (oi->ip_flags & OCFS2_INODE_DELETED) {
++ lvb->lvb_version = 0;
++ goto out;
++ }
++
++ lvb->lvb_version = OCFS2_LVB_VERSION;
+ lvb->lvb_isize = cpu_to_be64(i_size_read(inode));
+ lvb->lvb_iclusters = cpu_to_be32(oi->ip_clusters);
+ lvb->lvb_iuid = cpu_to_be32(inode->i_uid);
+@@ -1330,7 +1334,10 @@ static void __ocfs2_stuff_meta_lvb(struc
+ cpu_to_be64(ocfs2_pack_timespec(&inode->i_ctime));
+ lvb->lvb_imtime_packed =
+ cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
++ lvb->lvb_iattr = cpu_to_be32(oi->ip_attr);
++ lvb->lvb_igeneration = cpu_to_be32(inode->i_generation);
+
++out:
+ mlog_meta_lvb(0, lockres);
+
+ mlog_exit_void();
+@@ -1360,6 +1367,9 @@ static void ocfs2_refresh_inode_from_lvb
+ oi->ip_clusters = be32_to_cpu(lvb->lvb_iclusters);
+ i_size_write(inode, be64_to_cpu(lvb->lvb_isize));
+
++ oi->ip_attr = be32_to_cpu(lvb->lvb_iattr);
++ ocfs2_set_inode_flags(inode);
++
+ /* fast-symlinks are a special case */
+ if (S_ISLNK(inode->i_mode) && !oi->ip_clusters)
+ inode->i_blocks = 0;
+@@ -1382,11 +1392,13 @@ static void ocfs2_refresh_inode_from_lvb
+ mlog_exit_void();
+ }
+
+-static inline int ocfs2_meta_lvb_is_trustable(struct ocfs2_lock_res *lockres)
++static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode,
++ struct ocfs2_lock_res *lockres)
+ {
+ struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
+
+- if (be32_to_cpu(lvb->lvb_version) == OCFS2_LVB_VERSION)
++ if (lvb->lvb_version == OCFS2_LVB_VERSION
++ && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation)
+ return 1;
+ return 0;
+ }
+@@ -1483,7 +1495,7 @@ static int ocfs2_meta_lock_update(struct
+ * map (directories, bitmap files, etc) */
+ ocfs2_extent_map_trunc(inode, 0);
+
+- if (ocfs2_meta_lvb_is_trustable(lockres)) {
++ if (ocfs2_meta_lvb_is_trustable(inode, lockres)) {
+ mlog(0, "Trusting LVB on inode %llu\n",
+ (unsigned long long)oi->ip_blkno);
+ ocfs2_refresh_inode_from_lvb(inode);
+@@ -1624,6 +1636,18 @@ int ocfs2_meta_lock_full(struct inode *i
+ wait_event(osb->recovery_event,
+ ocfs2_node_map_is_empty(osb, &osb->recovery_map));
+
++ /*
++ * We only see this flag if we're being called from
++ * ocfs2_read_locked_inode(). It means we're locking an inode
++ * which hasn't been populated yet, so clear the refresh flag
++ * and let the caller handle it.
++ */
++ if (inode->i_state & I_NEW) {
++ status = 0;
++ ocfs2_complete_lock_res_refresh(lockres, 0);
++ goto bail;
++ }
++
+ /* This is fun. The caller may want a bh back, or it may
+ * not. ocfs2_meta_lock_update definitely wants one in, but
+ * may or may not read one, depending on what's in the
+@@ -1803,6 +1827,34 @@ void ocfs2_rename_unlock(struct ocfs2_su
+ ocfs2_cluster_unlock(osb, lockres, LKM_EXMODE);
+ }
+
++int ocfs2_dentry_lock(struct dentry *dentry, int ex)
++{
++ int ret;
++ int level = ex ? LKM_EXMODE : LKM_PRMODE;
++ struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
++ struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
++
++ BUG_ON(!dl);
++
++ if (ocfs2_is_hard_readonly(osb))
++ return -EROFS;
++
++ ret = ocfs2_cluster_lock(osb, &dl->dl_lockres, level, 0, 0);
++ if (ret < 0)
++ mlog_errno(ret);
++
++ return ret;
++}
++
++void ocfs2_dentry_unlock(struct dentry *dentry, int ex)
++{
++ int level = ex ? LKM_EXMODE : LKM_PRMODE;
++ struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
++ struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
++
++ ocfs2_cluster_unlock(osb, &dl->dl_lockres, level);
++}
++
+ /* Reference counting of the dlm debug structure. We want this because
+ * open references on the debug inodes can live on after a mount, so
+ * we can't rely on the ocfs2_super to always exist. */
+@@ -1933,9 +1985,16 @@ static int ocfs2_dlm_seq_show(struct seq
+ if (!lockres)
+ return -EINVAL;
+
+- seq_printf(m, "0x%x\t"
+- "%.*s\t"
+- "%d\t"
++ seq_printf(m, "0x%x\t", OCFS2_DLM_DEBUG_STR_VERSION);
++
++ if (lockres->l_type == OCFS2_LOCK_TYPE_DENTRY)
++ seq_printf(m, "%.*s%08x\t", OCFS2_DENTRY_LOCK_INO_START - 1,
++ lockres->l_name,
++ (unsigned int)ocfs2_get_dentry_lock_ino(lockres));
++ else
++ seq_printf(m, "%.*s\t", OCFS2_LOCK_ID_MAX_LEN, lockres->l_name);
++
++ seq_printf(m, "%d\t"
+ "0x%lx\t"
+ "0x%x\t"
+ "0x%x\t"
+@@ -1943,8 +2002,6 @@ static int ocfs2_dlm_seq_show(struct seq
+ "%u\t"
+ "%d\t"
+ "%d\t",
+- OCFS2_DLM_DEBUG_STR_VERSION,
+- OCFS2_LOCK_ID_MAX_LEN, lockres->l_name,
+ lockres->l_level,
+ lockres->l_flags,
+ lockres->l_action,
+@@ -1995,7 +2052,7 @@ static int ocfs2_dlm_debug_open(struct i
+ mlog_errno(ret);
+ goto out;
+ }
+- osb = (struct ocfs2_super *) inode->u.generic_ip;
++ osb = inode->i_private;
+ ocfs2_get_dlm_debug(osb->osb_dlm_debug);
+ priv->p_dlm_debug = osb->osb_dlm_debug;
+ INIT_LIST_HEAD(&priv->p_iter_res.l_debug_list);
+@@ -2134,7 +2191,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_sup
+ mlog_exit_void();
+ }
+
+-static void ocfs2_unlock_ast_func(void *opaque, enum dlm_status status)
++static void ocfs2_unlock_ast(void *opaque, enum dlm_status status)
+ {
+ struct ocfs2_lock_res *lockres = opaque;
+ unsigned long flags;
+@@ -2190,24 +2247,20 @@ complete_unlock:
+ mlog_exit_void();
+ }
+
+-typedef void (ocfs2_pre_drop_cb_t)(struct ocfs2_lock_res *, void *);
+-
+-struct drop_lock_cb {
+- ocfs2_pre_drop_cb_t *drop_func;
+- void *drop_data;
+-};
+-
+ static int ocfs2_drop_lock(struct ocfs2_super *osb,
+- struct ocfs2_lock_res *lockres,
+- struct drop_lock_cb *dcb)
++ struct ocfs2_lock_res *lockres)
+ {
+ enum dlm_status status;
+ unsigned long flags;
++ int lkm_flags = 0;
+
+ /* We didn't get anywhere near actually using this lockres. */
+ if (!(lockres->l_flags & OCFS2_LOCK_INITIALIZED))
+ goto out;
+
++ if (lockres->l_ops->flags & LOCK_TYPE_USES_LVB)
++ lkm_flags |= LKM_VALBLK;
++
+ spin_lock_irqsave(&lockres->l_lock, flags);
+
+ mlog_bug_on_msg(!(lockres->l_flags & OCFS2_LOCK_FREEING),
+@@ -2230,8 +2283,12 @@ static int ocfs2_drop_lock(struct ocfs2_
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ }
+
+- if (dcb)
+- dcb->drop_func(lockres, dcb->drop_data);
++ if (lockres->l_ops->flags & LOCK_TYPE_USES_LVB) {
++ if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
++ lockres->l_level == LKM_EXMODE &&
++ !(lockres->l_flags & OCFS2_LOCK_NEEDS_REFRESH))
++ lockres->l_ops->set_lvb(lockres);
++ }
+
+ if (lockres->l_flags & OCFS2_LOCK_BUSY)
+ mlog(ML_ERROR, "destroying busy lock: \"%s\"\n",
+@@ -2257,8 +2314,8 @@ static int ocfs2_drop_lock(struct ocfs2_
+
+ mlog(0, "lock %s\n", lockres->l_name);
+
+- status = dlmunlock(osb->dlm, &lockres->l_lksb, LKM_VALBLK,
+- lockres->l_ops->unlock_ast, lockres);
++ status = dlmunlock(osb->dlm, &lockres->l_lksb, lkm_flags,
++ ocfs2_unlock_ast, lockres);
+ if (status != DLM_NORMAL) {
+ ocfs2_log_dlm_error("dlmunlock", status, lockres);
+ mlog(ML_ERROR, "lockres flags: %lu\n", lockres->l_flags);
+@@ -2305,43 +2362,26 @@ void ocfs2_mark_lockres_freeing(struct o
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+ }
+
+-static void ocfs2_drop_osb_locks(struct ocfs2_super *osb)
++void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres)
+ {
+- int status;
+-
+- mlog_entry_void();
+-
+- ocfs2_mark_lockres_freeing(&osb->osb_super_lockres);
+-
+- status = ocfs2_drop_lock(osb, &osb->osb_super_lockres, NULL);
+- if (status < 0)
+- mlog_errno(status);
+-
+- ocfs2_mark_lockres_freeing(&osb->osb_rename_lockres);
+-
+- status = ocfs2_drop_lock(osb, &osb->osb_rename_lockres, NULL);
+- if (status < 0)
+- mlog_errno(status);
++ int ret;
+
+- mlog_exit(status);
++ ocfs2_mark_lockres_freeing(lockres);
++ ret = ocfs2_drop_lock(osb, lockres);
++ if (ret)
++ mlog_errno(ret);
+ }
+
+-static void ocfs2_meta_pre_drop(struct ocfs2_lock_res *lockres, void *data)
++static void ocfs2_drop_osb_locks(struct ocfs2_super *osb)
+ {
+- struct inode *inode = data;
+-
+- /* the metadata lock requires a bit more work as we have an
+- * LVB to worry about. */
+- if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
+- lockres->l_level == LKM_EXMODE &&
+- !(lockres->l_flags & OCFS2_LOCK_NEEDS_REFRESH))
+- __ocfs2_stuff_meta_lvb(inode);
++ ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres);
++ ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres);
+ }
+
+ int ocfs2_drop_inode_locks(struct inode *inode)
+ {
+ int status, err;
+- struct drop_lock_cb meta_dcb = { ocfs2_meta_pre_drop, inode, };
+
+ mlog_entry_void();
+
+@@ -2349,24 +2389,21 @@ int ocfs2_drop_inode_locks(struct inode
+ * ocfs2_clear_inode has done it for us. */
+
+ err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
+- &OCFS2_I(inode)->ip_data_lockres,
+- NULL);
++ &OCFS2_I(inode)->ip_data_lockres);
+ if (err < 0)
+ mlog_errno(err);
+
+ status = err;
+
+ err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
+- &OCFS2_I(inode)->ip_meta_lockres,
+- &meta_dcb);
++ &OCFS2_I(inode)->ip_meta_lockres);
+ if (err < 0)
+ mlog_errno(err);
+ if (err < 0 && !status)
+ status = err;
+
+ err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
+- &OCFS2_I(inode)->ip_rw_lockres,
+- NULL);
++ &OCFS2_I(inode)->ip_rw_lockres);
+ if (err < 0)
+ mlog_errno(err);
+ if (err < 0 && !status)
+@@ -2415,9 +2452,10 @@ static int ocfs2_downconvert_lock(struct
+ &lockres->l_lksb,
+ dlm_flags,
+ lockres->l_name,
+- lockres->l_ops->ast,
++ OCFS2_LOCK_ID_MAX_LEN - 1,
++ ocfs2_locking_ast,
+ lockres,
+- lockres->l_ops->bast);
++ ocfs2_blocking_ast);
+ if (status != DLM_NORMAL) {
+ ocfs2_log_dlm_error("dlmlock", status, lockres);
+ ret = -EINVAL;
+@@ -2476,7 +2514,7 @@ static int ocfs2_cancel_convert(struct o
+ status = dlmunlock(osb->dlm,
+ &lockres->l_lksb,
+ LKM_CANCEL,
+- lockres->l_ops->unlock_ast,
++ ocfs2_unlock_ast,
+ lockres);
+ if (status != DLM_NORMAL) {
+ ocfs2_log_dlm_error("dlmunlock", status, lockres);
+@@ -2490,115 +2528,15 @@ static int ocfs2_cancel_convert(struct o
+ return ret;
+ }
+
+-static inline int ocfs2_can_downconvert_meta_lock(struct inode *inode,
+- struct ocfs2_lock_res *lockres,
+- int new_level)
+-{
+- int ret;
+-
+- mlog_entry_void();
+-
+- BUG_ON(new_level != LKM_NLMODE && new_level != LKM_PRMODE);
+-
+- if (lockres->l_flags & OCFS2_LOCK_REFRESHING) {
+- ret = 0;
+- mlog(0, "lockres %s currently being refreshed -- backing "
+- "off!\n", lockres->l_name);
+- } else if (new_level == LKM_PRMODE)
+- ret = !lockres->l_ex_holders &&
+- ocfs2_inode_fully_checkpointed(inode);
+- else /* Must be NLMODE we're converting to. */
+- ret = !lockres->l_ro_holders && !lockres->l_ex_holders &&
+- ocfs2_inode_fully_checkpointed(inode);
+-
+- mlog_exit(ret);
+- return ret;
+-}
+-
+-static int ocfs2_do_unblock_meta(struct inode *inode,
+- int *requeue)
+-{
+- int new_level;
+- int set_lvb = 0;
+- int ret = 0;
+- struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres;
+- unsigned long flags;
+-
+- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+-
+- mlog_entry_void();
+-
+- spin_lock_irqsave(&lockres->l_lock, flags);
+-
+- BUG_ON(!(lockres->l_flags & OCFS2_LOCK_BLOCKED));
+-
+- mlog(0, "l_level=%d, l_blocking=%d\n", lockres->l_level,
+- lockres->l_blocking);
+-
+- BUG_ON(lockres->l_level != LKM_EXMODE &&
+- lockres->l_level != LKM_PRMODE);
+-
+- if (lockres->l_flags & OCFS2_LOCK_BUSY) {
+- *requeue = 1;
+- ret = ocfs2_prepare_cancel_convert(osb, lockres);
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- if (ret) {
+- ret = ocfs2_cancel_convert(osb, lockres);
+- if (ret < 0)
+- mlog_errno(ret);
+- }
+- goto leave;
+- }
+-
+- new_level = ocfs2_highest_compat_lock_level(lockres->l_blocking);
+-
+- mlog(0, "l_level=%d, l_blocking=%d, new_level=%d\n",
+- lockres->l_level, lockres->l_blocking, new_level);
+-
+- if (ocfs2_can_downconvert_meta_lock(inode, lockres, new_level)) {
+- if (lockres->l_level == LKM_EXMODE)
+- set_lvb = 1;
+-
+- /* If the lock hasn't been refreshed yet (rare), then
+- * our memory inode values are old and we skip
+- * stuffing the lvb. There's no need to actually clear
+- * out the lvb here as it's value is still valid. */
+- if (!(lockres->l_flags & OCFS2_LOCK_NEEDS_REFRESH)) {
+- if (set_lvb)
+- __ocfs2_stuff_meta_lvb(inode);
+- } else
+- mlog(0, "lockres %s: downconverting stale lock!\n",
+- lockres->l_name);
+-
+- mlog(0, "calling ocfs2_downconvert_lock with l_level=%d, "
+- "l_blocking=%d, new_level=%d\n",
+- lockres->l_level, lockres->l_blocking, new_level);
+-
+- ocfs2_prepare_downconvert(lockres, new_level);
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- ret = ocfs2_downconvert_lock(osb, lockres, new_level, set_lvb);
+- goto leave;
+- }
+- if (!ocfs2_inode_fully_checkpointed(inode))
+- ocfs2_start_checkpoint(osb);
+-
+- *requeue = 1;
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- ret = 0;
+-leave:
+- mlog_exit(ret);
+- return ret;
+-}
+-
+-static int ocfs2_generic_unblock_lock(struct ocfs2_super *osb,
+- struct ocfs2_lock_res *lockres,
+- int *requeue,
+- ocfs2_convert_worker_t *worker)
++static int ocfs2_unblock_lock(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres,
++ struct ocfs2_unblock_ctl *ctl)
+ {
+ unsigned long flags;
+ int blocking;
+ int new_level;
+ int ret = 0;
++ int set_lvb = 0;
+
+ mlog_entry_void();
+
+@@ -2608,7 +2546,7 @@ static int ocfs2_generic_unblock_lock(st
+
+ recheck:
+ if (lockres->l_flags & OCFS2_LOCK_BUSY) {
+- *requeue = 1;
++ ctl->requeue = 1;
+ ret = ocfs2_prepare_cancel_convert(osb, lockres);
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+ if (ret) {
+@@ -2622,27 +2560,33 @@ recheck:
+ /* if we're blocking an exclusive and we have *any* holders,
+ * then requeue. */
+ if ((lockres->l_blocking == LKM_EXMODE)
+- && (lockres->l_ex_holders || lockres->l_ro_holders)) {
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- *requeue = 1;
+- ret = 0;
+- goto leave;
+- }
++ && (lockres->l_ex_holders || lockres->l_ro_holders))
++ goto leave_requeue;
+
+ /* If it's a PR we're blocking, then only
+ * requeue if we've got any EX holders */
+ if (lockres->l_blocking == LKM_PRMODE &&
+- lockres->l_ex_holders) {
+- spin_unlock_irqrestore(&lockres->l_lock, flags);
+- *requeue = 1;
+- ret = 0;
+- goto leave;
+- }
++ lockres->l_ex_holders)
++ goto leave_requeue;
++
++ /*
++ * Can we get a lock in this state if the holder counts are
++ * zero? The meta data unblock code used to check this.
++ */
++ if ((lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH)
++ && (lockres->l_flags & OCFS2_LOCK_REFRESHING))
++ goto leave_requeue;
++
++ new_level = ocfs2_highest_compat_lock_level(lockres->l_blocking);
++
++ if (lockres->l_ops->check_downconvert
++ && !lockres->l_ops->check_downconvert(lockres, new_level))
++ goto leave_requeue;
+
+ /* If we get here, then we know that there are no more
+ * incompatible holders (and anyone asking for an incompatible
+ * lock is blocked). We can now downconvert the lock */
+- if (!worker)
++ if (!lockres->l_ops->downconvert_worker)
+ goto downconvert;
+
+ /* Some lockres types want to do a bit of work before
+@@ -2652,7 +2596,10 @@ recheck:
+ blocking = lockres->l_blocking;
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+- worker(lockres, blocking);
++ ctl->unblock_action = lockres->l_ops->downconvert_worker(lockres, blocking);
++
++ if (ctl->unblock_action == UNBLOCK_STOP_POST)
++ goto leave;
+
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ if (blocking != lockres->l_blocking) {
+@@ -2662,25 +2609,43 @@ recheck:
+ }
+
+ downconvert:
+- *requeue = 0;
+- new_level = ocfs2_highest_compat_lock_level(lockres->l_blocking);
++ ctl->requeue = 0;
++
++ if (lockres->l_ops->flags & LOCK_TYPE_USES_LVB) {
++ if (lockres->l_level == LKM_EXMODE)
++ set_lvb = 1;
++
++ /*
++ * We only set the lvb if the lock has been fully
++ * refreshed - otherwise we risk setting stale
++ * data. Otherwise, there's no need to actually clear
++ * out the lvb here as it's value is still valid.
++ */
++ if (set_lvb && !(lockres->l_flags & OCFS2_LOCK_NEEDS_REFRESH))
++ lockres->l_ops->set_lvb(lockres);
++ }
+
+ ocfs2_prepare_downconvert(lockres, new_level);
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+- ret = ocfs2_downconvert_lock(osb, lockres, new_level, 0);
++ ret = ocfs2_downconvert_lock(osb, lockres, new_level, set_lvb);
+ leave:
+ mlog_exit(ret);
+ return ret;
++
++leave_requeue:
++ spin_unlock_irqrestore(&lockres->l_lock, flags);
++ ctl->requeue = 1;
++
++ mlog_exit(0);
++ return 0;
+ }
+
+-static void ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
+- int blocking)
++static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
++ int blocking)
+ {
+ struct inode *inode;
+ struct address_space *mapping;
+
+- mlog_entry_void();
+-
+ inode = ocfs2_lock_res_inode(lockres);
+ mapping = inode->i_mapping;
+
+@@ -2701,116 +2666,159 @@ static void ocfs2_data_convert_worker(st
+ filemap_fdatawait(mapping);
+ }
+
+- mlog_exit_void();
++ return UNBLOCK_CONTINUE;
+ }
+
+-int ocfs2_unblock_data(struct ocfs2_lock_res *lockres,
+- int *requeue)
++static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
++ int new_level)
+ {
+- int status;
+- struct inode *inode;
+- struct ocfs2_super *osb;
+-
+- mlog_entry_void();
+-
+- inode = ocfs2_lock_res_inode(lockres);
+- osb = OCFS2_SB(inode->i_sb);
+-
+- mlog(0, "unblock inode %llu\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno);
++ struct inode *inode = ocfs2_lock_res_inode(lockres);
++ int checkpointed = ocfs2_inode_fully_checkpointed(inode);
+
+- status = ocfs2_generic_unblock_lock(osb,
+- lockres,
+- requeue,
+- ocfs2_data_convert_worker);
+- if (status < 0)
+- mlog_errno(status);
++ BUG_ON(new_level != LKM_NLMODE && new_level != LKM_PRMODE);
++ BUG_ON(lockres->l_level != LKM_EXMODE && !checkpointed);
+
+- mlog(0, "inode %llu, requeue = %d\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno, *requeue);
++ if (checkpointed)
++ return 1;
+
+- mlog_exit(status);
+- return status;
++ ocfs2_start_checkpoint(OCFS2_SB(inode->i_sb));
++ return 0;
+ }
+
+-static int ocfs2_unblock_inode_lock(struct ocfs2_lock_res *lockres,
+- int *requeue)
++static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres)
+ {
+- int status;
+- struct inode *inode;
+-
+- mlog_entry_void();
+-
+- mlog(0, "Unblock lockres %s\n", lockres->l_name);
+-
+- inode = ocfs2_lock_res_inode(lockres);
++ struct inode *inode = ocfs2_lock_res_inode(lockres);
+
+- status = ocfs2_generic_unblock_lock(OCFS2_SB(inode->i_sb),
+- lockres,
+- requeue,
+- NULL);
+- if (status < 0)
+- mlog_errno(status);
+-
+- mlog_exit(status);
+- return status;
++ __ocfs2_stuff_meta_lvb(inode);
+ }
+
+-
+-int ocfs2_unblock_meta(struct ocfs2_lock_res *lockres,
+- int *requeue)
++/*
++ * Does the final reference drop on our dentry lock. Right now this
++ * happens in the vote thread, but we could choose to simplify the
++ * dlmglue API and push these off to the ocfs2_wq in the future.
++ */
++static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres)
+ {
+- int status;
+- struct inode *inode;
+-
+- mlog_entry_void();
++ struct ocfs2_dentry_lock *dl = ocfs2_lock_res_dl(lockres);
++ ocfs2_dentry_lock_put(osb, dl);
++}
+
+- inode = ocfs2_lock_res_inode(lockres);
++/*
++ * d_delete() matching dentries before the lock downconvert.
++ *
++ * At this point, any process waiting to destroy the
++ * dentry_lock due to last ref count is stopped by the
++ * OCFS2_LOCK_QUEUED flag.
++ *
++ * We have two potential problems
++ *
++ * 1) If we do the last reference drop on our dentry_lock (via dput)
++ * we'll wind up in ocfs2_release_dentry_lock(), waiting on
++ * the downconvert to finish. Instead we take an elevated
++ * reference and push the drop until after we've completed our
++ * unblock processing.
++ *
++ * 2) There might be another process with a final reference,
++ * waiting on us to finish processing. If this is the case, we
++ * detect it and exit out - there's no more dentries anyway.
++ */
++static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
++ int blocking)
++{
++ struct ocfs2_dentry_lock *dl = ocfs2_lock_res_dl(lockres);
++ struct ocfs2_inode_info *oi = OCFS2_I(dl->dl_inode);
++ struct dentry *dentry;
++ unsigned long flags;
++ int extra_ref = 0;
+
+- mlog(0, "unblock inode %llu\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno);
++ /*
++ * This node is blocking another node from getting a read
++ * lock. This happens when we've renamed within a
++ * directory. We've forced the other nodes to d_delete(), but
++ * we never actually dropped our lock because it's still
++ * valid. The downconvert code will retain a PR for this node,
++ * so there's no further work to do.
++ */
++ if (blocking == LKM_PRMODE)
++ return UNBLOCK_CONTINUE;
+
+- status = ocfs2_do_unblock_meta(inode, requeue);
+- if (status < 0)
+- mlog_errno(status);
++ /*
++ * Mark this inode as potentially orphaned. The code in
++ * ocfs2_delete_inode() will figure out whether it actually
++ * needs to be freed or not.
++ */
++ spin_lock(&oi->ip_lock);
++ oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED;
++ spin_unlock(&oi->ip_lock);
+
+- mlog(0, "inode %llu, requeue = %d\n",
+- (unsigned long long)OCFS2_I(inode)->ip_blkno, *requeue);
++ /*
++ * Yuck. We need to make sure however that the check of
++ * OCFS2_LOCK_FREEING and the extra reference are atomic with
++ * respect to a reference decrement or the setting of that
++ * flag.
++ */
++ spin_lock_irqsave(&lockres->l_lock, flags);
++ spin_lock(&dentry_attach_lock);
++ if (!(lockres->l_flags & OCFS2_LOCK_FREEING)
++ && dl->dl_count) {
++ dl->dl_count++;
++ extra_ref = 1;
++ }
++ spin_unlock(&dentry_attach_lock);
++ spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+- mlog_exit(status);
+- return status;
+-}
++ mlog(0, "extra_ref = %d\n", extra_ref);
+
+-/* Generic unblock function for any lockres whose private data is an
+- * ocfs2_super pointer. */
+-static int ocfs2_unblock_osb_lock(struct ocfs2_lock_res *lockres,
+- int *requeue)
+-{
+- int status;
+- struct ocfs2_super *osb;
++ /*
++ * We have a process waiting on us in ocfs2_dentry_iput(),
++ * which means we can't have any more outstanding
++ * aliases. There's no need to do any more work.
++ */
++ if (!extra_ref)
++ return UNBLOCK_CONTINUE;
++
++ spin_lock(&dentry_attach_lock);
++ while (1) {
++ dentry = ocfs2_find_local_alias(dl->dl_inode,
++ dl->dl_parent_blkno, 1);
++ if (!dentry)
++ break;
++ spin_unlock(&dentry_attach_lock);
+
+- mlog_entry_void();
++ mlog(0, "d_delete(%.*s);\n", dentry->d_name.len,
++ dentry->d_name.name);
+
+- mlog(0, "Unblock lockres %s\n", lockres->l_name);
++ /*
++ * The following dcache calls may do an
++ * iput(). Normally we don't want that from the
++ * downconverting thread, but in this case it's ok
++ * because the requesting node already has an
++ * exclusive lock on the inode, so it can't be queued
++ * for a downconvert.
++ */
++ d_delete(dentry);
++ dput(dentry);
+
+- osb = ocfs2_lock_res_super(lockres);
++ spin_lock(&dentry_attach_lock);
++ }
++ spin_unlock(&dentry_attach_lock);
+
+- status = ocfs2_generic_unblock_lock(osb,
+- lockres,
+- requeue,
+- NULL);
+- if (status < 0)
+- mlog_errno(status);
++ /*
++ * If we are the last holder of this dentry lock, there is no
++ * reason to downconvert so skip straight to the unlock.
++ */
++ if (dl->dl_count == 1)
++ return UNBLOCK_STOP_POST;
+
+- mlog_exit(status);
+- return status;
++ return UNBLOCK_CONTINUE_POST;
+ }
+
+ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
+ struct ocfs2_lock_res *lockres)
+ {
+ int status;
+- int requeue = 0;
++ struct ocfs2_unblock_ctl ctl = {0, 0,};
+ unsigned long flags;
+
+ /* Our reference to the lockres in this function can be
+@@ -2821,7 +2829,6 @@ void ocfs2_process_blocked_lock(struct o
+
+ BUG_ON(!lockres);
+ BUG_ON(!lockres->l_ops);
+- BUG_ON(!lockres->l_ops->unblock);
+
+ mlog(0, "lockres %s blocked.\n", lockres->l_name);
+
+@@ -2835,21 +2842,25 @@ void ocfs2_process_blocked_lock(struct o
+ goto unqueue;
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+- status = lockres->l_ops->unblock(lockres, &requeue);
++ status = ocfs2_unblock_lock(osb, lockres, &ctl);
+ if (status < 0)
+ mlog_errno(status);
+
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ unqueue:
+- if (lockres->l_flags & OCFS2_LOCK_FREEING || !requeue) {
++ if (lockres->l_flags & OCFS2_LOCK_FREEING || !ctl.requeue) {
+ lockres_clear_flags(lockres, OCFS2_LOCK_QUEUED);
+ } else
+ ocfs2_schedule_blocked_lock(osb, lockres);
+
+ mlog(0, "lockres %s, requeue = %s.\n", lockres->l_name,
+- requeue ? "yes" : "no");
++ ctl.requeue ? "yes" : "no");
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
+
++ if (ctl.unblock_action != UNBLOCK_CONTINUE
++ && lockres->l_ops->post_unlock)
++ lockres->l_ops->post_unlock(osb, lockres);
++
+ mlog_exit_void();
+ }
+
+@@ -2892,15 +2903,17 @@ void ocfs2_dump_meta_lvb_info(u64 level,
+
+ mlog(level, "LVB information for %s (called from %s:%u):\n",
+ lockres->l_name, function, line);
+- mlog(level, "version: %u, clusters: %u\n",
+- be32_to_cpu(lvb->lvb_version), be32_to_cpu(lvb->lvb_iclusters));
++ mlog(level, "version: %u, clusters: %u, generation: 0x%x\n",
++ lvb->lvb_version, be32_to_cpu(lvb->lvb_iclusters),
++ be32_to_cpu(lvb->lvb_igeneration));
+ mlog(level, "size: %llu, uid %u, gid %u, mode 0x%x\n",
+ (unsigned long long)be64_to_cpu(lvb->lvb_isize),
+ be32_to_cpu(lvb->lvb_iuid), be32_to_cpu(lvb->lvb_igid),
+ be16_to_cpu(lvb->lvb_imode));
+ mlog(level, "nlink %u, atime_packed 0x%llx, ctime_packed 0x%llx, "
+- "mtime_packed 0x%llx\n", be16_to_cpu(lvb->lvb_inlink),
++ "mtime_packed 0x%llx iattr 0x%x\n", be16_to_cpu(lvb->lvb_inlink),
+ (long long)be64_to_cpu(lvb->lvb_iatime_packed),
+ (long long)be64_to_cpu(lvb->lvb_ictime_packed),
+- (long long)be64_to_cpu(lvb->lvb_imtime_packed));
++ (long long)be64_to_cpu(lvb->lvb_imtime_packed),
++ be32_to_cpu(lvb->lvb_iattr));
+ }
+diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
+index 8f2d1db..4a27693 100644
+--- a/fs/ocfs2/dlmglue.h
++++ b/fs/ocfs2/dlmglue.h
+@@ -27,10 +27,14 @@
+ #ifndef DLMGLUE_H
+ #define DLMGLUE_H
+
+-#define OCFS2_LVB_VERSION 2
++#include "dcache.h"
++
++#define OCFS2_LVB_VERSION 4
+
+ struct ocfs2_meta_lvb {
+- __be32 lvb_version;
++ __u8 lvb_version;
++ __u8 lvb_reserved0;
++ __be16 lvb_reserved1;
+ __be32 lvb_iclusters;
+ __be32 lvb_iuid;
+ __be32 lvb_igid;
+@@ -40,7 +44,9 @@ struct ocfs2_meta_lvb {
+ __be64 lvb_isize;
+ __be16 lvb_imode;
+ __be16 lvb_inlink;
+- __be32 lvb_reserved[3];
++ __be32 lvb_iattr;
++ __be32 lvb_igeneration;
++ __be32 lvb_reserved2;
+ };
+
+ /* ocfs2_meta_lock_full() and ocfs2_data_lock_full() 'arg_flags' flags */
+@@ -56,9 +62,14 @@ void ocfs2_dlm_shutdown(struct ocfs2_sup
+ void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res);
+ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
+ enum ocfs2_lock_type type,
++ unsigned int generation,
+ struct inode *inode);
++void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
++ u64 parent, struct inode *inode);
+ void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
+ int ocfs2_create_new_inode_locks(struct inode *inode);
++int ocfs2_create_new_lock(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres, int ex, int local);
+ int ocfs2_drop_inode_locks(struct inode *inode);
+ int ocfs2_data_lock_full(struct inode *inode,
+ int write,
+@@ -92,7 +103,12 @@ void ocfs2_super_unlock(struct ocfs2_sup
+ int ex);
+ int ocfs2_rename_lock(struct ocfs2_super *osb);
+ void ocfs2_rename_unlock(struct ocfs2_super *osb);
++int ocfs2_dentry_lock(struct dentry *dentry, int ex);
++void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
++
+ void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
++void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
++ struct ocfs2_lock_res *lockres);
+
+ /* for the vote thread */
+ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
+diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
+index ec55ab3..fb91089 100644
+--- a/fs/ocfs2/export.c
++++ b/fs/ocfs2/export.c
+@@ -33,6 +33,7 @@
+
+ #include "dir.h"
+ #include "dlmglue.h"
++#include "dcache.h"
+ #include "export.h"
+ #include "inode.h"
+
+@@ -57,7 +58,7 @@ static struct dentry *ocfs2_get_dentry(s
+ return ERR_PTR(-ESTALE);
+ }
+
+- inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno);
++ inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0);
+
+ if (IS_ERR(inode)) {
+ mlog_errno(PTR_ERR(inode));
+@@ -77,6 +78,7 @@ static struct dentry *ocfs2_get_dentry(s
+ mlog_errno(-ENOMEM);
+ return ERR_PTR(-ENOMEM);
+ }
++ result->d_op = &ocfs2_dentry_ops;
+
+ mlog_exit_ptr(result);
+ return result;
+@@ -113,7 +115,7 @@ static struct dentry *ocfs2_get_parent(s
+ goto bail_unlock;
+ }
+
+- inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno);
++ inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
+ if (IS_ERR(inode)) {
+ mlog(ML_ERROR, "Unable to create inode %llu\n",
+ (unsigned long long)blkno);
+@@ -127,6 +129,8 @@ static struct dentry *ocfs2_get_parent(s
+ parent = ERR_PTR(-ENOMEM);
+ }
+
++ parent->d_op = &ocfs2_dentry_ops;
++
+ bail_unlock:
+ ocfs2_meta_unlock(dir, 0);
+
+diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
+index a9559c8..1be74c4 100644
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -30,6 +30,7 @@
+ #include <linux/highmem.h>
+ #include <linux/pagemap.h>
+ #include <linux/uio.h>
++#include <linux/sched.h>
+
+ #define MLOG_MASK_PREFIX ML_INODE
+ #include <cluster/masklog.h>
+@@ -44,6 +45,7 @@
+ #include "file.h"
+ #include "sysfile.h"
+ #include "inode.h"
++#include "ioctl.h"
+ #include "journal.h"
+ #include "mmap.h"
+ #include "suballoc.h"
+@@ -690,6 +692,12 @@ static int ocfs2_zero_extend(struct inod
+ }
+
+ start_off += sb->s_blocksize;
++
++ /*
++ * Very large extends have the potential to lock up
++ * the cpu for extended periods of time.
++ */
++ cond_resched();
+ }
+
+ out:
+@@ -727,31 +735,36 @@ static int ocfs2_extend_file(struct inod
+ clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) -
+ OCFS2_I(inode)->ip_clusters;
+
+- if (clusters_to_add) {
+- /*
+- * protect the pages that ocfs2_zero_extend is going to
+- * be pulling into the page cache.. we do this before the
+- * metadata extend so that we don't get into the situation
+- * where we've extended the metadata but can't get the data
+- * lock to zero.
+- */
+- ret = ocfs2_data_lock(inode, 1);
+- if (ret < 0) {
+- mlog_errno(ret);
+- goto out;
+- }
++ /*
++ * protect the pages that ocfs2_zero_extend is going to be
++ * pulling into the page cache.. we do this before the
++ * metadata extend so that we don't get into the situation
++ * where we've extended the metadata but can't get the data
++ * lock to zero.
++ */
++ ret = ocfs2_data_lock(inode, 1);
++ if (ret < 0) {
++ mlog_errno(ret);
++ goto out;
++ }
+
++ if (clusters_to_add) {
+ ret = ocfs2_extend_allocation(inode, clusters_to_add);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_unlock;
+ }
++ }
+
+- ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
+- if (ret < 0) {
+- mlog_errno(ret);
+- goto out_unlock;
+- }
++ /*
++ * Call this even if we don't add any clusters to the tree. We
++ * still need to zero the area between the old i_size and the
++ * new i_size.
++ */
++ ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
++ if (ret < 0) {
++ mlog_errno(ret);
++ goto out_unlock;
+ }
+
+ if (!tail_to_skip) {
+@@ -763,8 +776,7 @@ static int ocfs2_extend_file(struct inod
+ }
+
+ out_unlock:
+- if (clusters_to_add) /* this is the only case in which we lock */
+- ocfs2_data_unlock(inode, 1);
++ ocfs2_data_unlock(inode, 1);
+
+ out:
+ return ret;
+@@ -960,25 +972,23 @@ static inline int ocfs2_write_should_rem
+ }
+
+ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
+- const char __user *buf,
+- size_t count,
++ const struct iovec *iov,
++ unsigned long nr_segs,
+ loff_t pos)
+ {
+- struct iovec local_iov = { .iov_base = (void __user *)buf,
+- .iov_len = count };
+ int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0;
+ u32 clusters;
+ struct file *filp = iocb->ki_filp;
+ struct inode *inode = filp->f_dentry->d_inode;
+ loff_t newsize, saved_pos;
+
+- mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
+- (unsigned int)count,
++ mlog_entry("(0x%p, %u, '%.*s')\n", filp,
++ (unsigned int)nr_segs,
+ filp->f_dentry->d_name.len,
+ filp->f_dentry->d_name.name);
+
+ /* happy write of zero bytes */
+- if (count == 0)
++ if (iocb->ki_left == 0)
+ return 0;
+
+ if (!inode) {
+@@ -1047,7 +1057,7 @@ static ssize_t ocfs2_file_aio_write(stru
+ } else {
+ saved_pos = iocb->ki_pos;
+ }
+- newsize = count + saved_pos;
++ newsize = iocb->ki_left + saved_pos;
+
+ mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
+ (long long) saved_pos, (long long) newsize,
+@@ -1080,7 +1090,7 @@ static ssize_t ocfs2_file_aio_write(stru
+ if (!clusters)
+ break;
+
+- ret = ocfs2_extend_file(inode, NULL, newsize, count);
++ ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left);
+ if (ret < 0) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+@@ -1097,7 +1107,7 @@ static ssize_t ocfs2_file_aio_write(stru
+ /* communicate with ocfs2_dio_end_io */
+ ocfs2_iocb_set_rw_locked(iocb);
+
+- ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
++ ret = generic_file_aio_write_nolock(iocb, iov, nr_segs, iocb->ki_pos);
+
+ /* buffered aio wouldn't have proper lock coverage today */
+ BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
+@@ -1131,16 +1141,16 @@ out:
+ }
+
+ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
+- char __user *buf,
+- size_t count,
++ const struct iovec *iov,
++ unsigned long nr_segs,
+ loff_t pos)
+ {
+ int ret = 0, rw_level = -1, have_alloc_sem = 0;
+ struct file *filp = iocb->ki_filp;
+ struct inode *inode = filp->f_dentry->d_inode;
+
+- mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
+- (unsigned int)count,
++ mlog_entry("(0x%p, %u, '%.*s')\n", filp,
++ (unsigned int)nr_segs,
+ filp->f_dentry->d_name.len,
+ filp->f_dentry->d_name.name);
+
+@@ -1184,7 +1194,7 @@ static ssize_t ocfs2_file_aio_read(struc
+ }
+ ocfs2_meta_unlock(inode, 0);
+
+- ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos);
++ ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
+ if (ret == -EINVAL)
+ mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n");
+
+@@ -1227,10 +1237,12 @@ const struct file_operations ocfs2_fops
+ .open = ocfs2_file_open,
+ .aio_read = ocfs2_file_aio_read,
+ .aio_write = ocfs2_file_aio_write,
++ .ioctl = ocfs2_ioctl,
+ };
+
+ const struct file_operations ocfs2_dops = {
+ .read = generic_read_dir,
+ .readdir = ocfs2_readdir,
+ .fsync = ocfs2_sync_file,
++ .ioctl = ocfs2_ioctl,
+ };
+diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
+index 327a5b7..16e8e74 100644
+--- a/fs/ocfs2/inode.c
++++ b/fs/ocfs2/inode.c
+@@ -54,8 +54,6 @@
+
+ #include "buffer_head_io.h"
+
+-#define OCFS2_FI_FLAG_NOWAIT 0x1
+-#define OCFS2_FI_FLAG_DELETE 0x2
+ struct ocfs2_find_inode_args
+ {
+ u64 fi_blkno;
+@@ -71,6 +69,26 @@ static int ocfs2_truncate_for_delete(str
+ struct inode *inode,
+ struct buffer_head *fe_bh);
+
++void ocfs2_set_inode_flags(struct inode *inode)
++{
++ unsigned int flags = OCFS2_I(inode)->ip_attr;
++
++ inode->i_flags &= ~(S_IMMUTABLE |
++ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC);
++
++ if (flags & OCFS2_IMMUTABLE_FL)
++ inode->i_flags |= S_IMMUTABLE;
++
++ if (flags & OCFS2_SYNC_FL)
++ inode->i_flags |= S_SYNC;
++ if (flags & OCFS2_APPEND_FL)
++ inode->i_flags |= S_APPEND;
++ if (flags & OCFS2_NOATIME_FL)
++ inode->i_flags |= S_NOATIME;
++ if (flags & OCFS2_DIRSYNC_FL)
++ inode->i_flags |= S_DIRSYNC;
++}
++
+ struct inode *ocfs2_ilookup_for_vote(struct ocfs2_super *osb,
+ u64 blkno,
+ int delete_vote)
+@@ -89,7 +107,7 @@ struct inode *ocfs2_ilookup_for_vote(str
+ return ilookup5(osb->sb, args.fi_ino, ocfs2_find_actor, &args);
+ }
+
+-struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno)
++struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
+ {
+ struct inode *inode = NULL;
+ struct super_block *sb = osb->sb;
+@@ -107,7 +125,7 @@ struct inode *ocfs2_iget(struct ocfs2_su
+ }
+
+ args.fi_blkno = blkno;
+- args.fi_flags = 0;
++ args.fi_flags = flags;
+ args.fi_ino = ino_from_blkno(sb, blkno);
+
+ inode = iget5_locked(sb, args.fi_ino, ocfs2_find_actor,
+@@ -251,7 +269,6 @@ int ocfs2_populate_inode(struct inode *i
+ inode->i_mode = le16_to_cpu(fe->i_mode);
+ inode->i_uid = le32_to_cpu(fe->i_uid);
+ inode->i_gid = le32_to_cpu(fe->i_gid);
+- inode->i_blksize = (u32)osb->s_clustersize;
+
+ /* Fast symlinks will have i_size but no allocated clusters. */
+ if (S_ISLNK(inode->i_mode) && !fe->i_clusters)
+@@ -260,7 +277,6 @@ int ocfs2_populate_inode(struct inode *i
+ inode->i_blocks =
+ ocfs2_align_bytes_to_sectors(le64_to_cpu(fe->i_size));
+ inode->i_mapping->a_ops = &ocfs2_aops;
+- inode->i_flags |= S_NOATIME;
+ inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime);
+ inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec);
+ inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime);
+@@ -276,16 +292,13 @@ int ocfs2_populate_inode(struct inode *i
+
+ OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
+ OCFS2_I(inode)->ip_orphaned_slot = OCFS2_INVALID_SLOT;
+-
+- if (create_ino)
+- inode->i_ino = ino_from_blkno(inode->i_sb,
+- le64_to_cpu(fe->i_blkno));
+-
+- mlog(0, "blkno = %llu, ino = %lu, create_ino = %s\n",
+- (unsigned long long)fe->i_blkno, inode->i_ino, create_ino ? "true" : "false");
++ OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+
+ inode->i_nlink = le16_to_cpu(fe->i_links_count);
+
++ if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL))
++ OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE;
++
+ if (fe->i_flags & cpu_to_le32(OCFS2_LOCAL_ALLOC_FL)) {
+ OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP;
+ mlog(0, "local alloc inode: i_ino=%lu\n", inode->i_ino);
+@@ -323,12 +336,31 @@ int ocfs2_populate_inode(struct inode *i
+ break;
+ }
+
++ if (create_ino) {
++ inode->i_ino = ino_from_blkno(inode->i_sb,
++ le64_to_cpu(fe->i_blkno));
++
++ /*
++ * If we ever want to create system files from kernel,
++ * the generation argument to
++ * ocfs2_inode_lock_res_init() will have to change.
++ */
++ BUG_ON(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL));
++
++ ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
++ OCFS2_LOCK_TYPE_META, 0, inode);
++ }
++
+ ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_rw_lockres,
+- OCFS2_LOCK_TYPE_RW, inode);
+- ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
+- OCFS2_LOCK_TYPE_META, inode);
++ OCFS2_LOCK_TYPE_RW, inode->i_generation,
++ inode);
++
+ ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres,
+- OCFS2_LOCK_TYPE_DATA, inode);
++ OCFS2_LOCK_TYPE_DATA, inode->i_generation,
++ inode);
++
++ ocfs2_set_inode_flags(inode);
++ inode->i_flags |= S_NOATIME;
+
+ status = 0;
+ bail:
+@@ -343,15 +375,15 @@ static int ocfs2_read_locked_inode(struc
+ struct ocfs2_super *osb;
+ struct ocfs2_dinode *fe;
+ struct buffer_head *bh = NULL;
+- int status;
+- int sysfile = 0;
++ int status, can_lock;
++ u32 generation = 0;
+
+ mlog_entry("(0x%p, 0x%p)\n", inode, args);
+
+ status = -EINVAL;
+ if (inode == NULL || inode->i_sb == NULL) {
+ mlog(ML_ERROR, "bad inode\n");
+- goto bail;
++ return status;
+ }
+ sb = inode->i_sb;
+ osb = OCFS2_SB(sb);
+@@ -359,50 +391,110 @@ static int ocfs2_read_locked_inode(struc
+ if (!args) {
+ mlog(ML_ERROR, "bad inode args\n");
+ make_bad_inode(inode);
+- goto bail;
++ return status;
++ }
++
++ /*
++ * To improve performance of cold-cache inode stats, we take
++ * the cluster lock here if possible.
++ *
++ * Generally, OCFS2 never trusts the contents of an inode
++ * unless it's holding a cluster lock, so taking it here isn't
++ * a correctness issue as much as it is a performance
++ * improvement.
++ *
++ * There are three times when taking the lock is not a good idea:
++ *
++ * 1) During startup, before we have initialized the DLM.
++ *
++ * 2) If we are reading certain system files which never get
++ * cluster locks (local alloc, truncate log).
++ *
++ * 3) If the process doing the iget() is responsible for
++ * orphan dir recovery. We're holding the orphan dir lock and
++ * can get into a deadlock with another process on another
++ * node in ->delete_inode().
++ *
++ * #1 and #2 can be simply solved by never taking the lock
++ * here for system files (which are the only type we read
++ * during mount). It's a heavier approach, but our main
++ * concern is user-accesible files anyway.
++ *
++ * #3 works itself out because we'll eventually take the
++ * cluster lock before trusting anything anyway.
++ */
++ can_lock = !(args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
++ && !(args->fi_flags & OCFS2_FI_FLAG_NOLOCK);
++
++ /*
++ * To maintain backwards compatibility with older versions of
++ * ocfs2-tools, we still store the generation value for system
++ * files. The only ones that actually matter to userspace are
++ * the journals, but it's easier and inexpensive to just flag
++ * all system files similarly.
++ */
++ if (args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
++ generation = osb->fs_generation;
++
++ ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
++ OCFS2_LOCK_TYPE_META,
++ generation, inode);
++
++ if (can_lock) {
++ status = ocfs2_meta_lock(inode, NULL, NULL, 0);
++ if (status) {
++ make_bad_inode(inode);
++ mlog_errno(status);
++ return status;
++ }
+ }
+
+- /* Read the FE off disk. This is safe because the kernel only
+- * does one read_inode2 for a new inode, and if it doesn't
+- * exist yet then nobody can be working on it! */
+- status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0, NULL);
++ status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0,
++ can_lock ? inode : NULL);
+ if (status < 0) {
+ mlog_errno(status);
+- make_bad_inode(inode);
+ goto bail;
+ }
+
++ status = -EINVAL;
+ fe = (struct ocfs2_dinode *) bh->b_data;
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ mlog(ML_ERROR, "Invalid dinode #%llu: signature = %.*s\n",
+ (unsigned long long)fe->i_blkno, 7, fe->i_signature);
+- make_bad_inode(inode);
+ goto bail;
+ }
+
+- if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL))
+- sysfile = 1;
++ /*
++ * This is a code bug. Right now the caller needs to
++ * understand whether it is asking for a system file inode or
++ * not so the proper lock names can be built.
++ */
++ mlog_bug_on_msg(!!(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) !=
++ !!(args->fi_flags & OCFS2_FI_FLAG_SYSFILE),
++ "Inode %llu: system file state is ambigous\n",
++ (unsigned long long)args->fi_blkno);
+
+ if (S_ISCHR(le16_to_cpu(fe->i_mode)) ||
+ S_ISBLK(le16_to_cpu(fe->i_mode)))
+ inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev));
+
+- status = -EINVAL;
+ if (ocfs2_populate_inode(inode, fe, 0) < 0) {
+ mlog(ML_ERROR, "populate failed! i_blkno=%llu, i_ino=%lu\n",
+ (unsigned long long)fe->i_blkno, inode->i_ino);
+- make_bad_inode(inode);
+ goto bail;
+ }
+
+ BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno));
+
+- if (sysfile)
+- OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE;
+-
+ status = 0;
+
+ bail:
++ if (can_lock)
++ ocfs2_meta_unlock(inode, 0);
++
++ if (status < 0)
++ make_bad_inode(inode);
++
+ if (args && bh)
+ brelse(bh);
+
+@@ -875,9 +967,15 @@ void ocfs2_delete_inode(struct inode *in
+ goto bail_unlock_inode;
+ }
+
+- /* Mark the inode as successfully deleted. This is important
+- * for ocfs2_clear_inode as it will check this flag and skip
+- * any checkpointing work */
++ /*
++ * Mark the inode as successfully deleted.
++ *
++ * This is important for ocfs2_clear_inode() as it will check
++ * this flag and skip any checkpointing work
++ *
++ * ocfs2_stuff_meta_lvb() also uses this flag to invalidate
++ * the LVB for other nodes.
++ */
+ OCFS2_I(inode)->ip_flags |= OCFS2_INODE_DELETED;
+
+ bail_unlock_inode:
+@@ -1002,12 +1100,10 @@ void ocfs2_drop_inode(struct inode *inod
+ /* Testing ip_orphaned_slot here wouldn't work because we may
+ * not have gotten a delete_inode vote from any other nodes
+ * yet. */
+- if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED) {
+- mlog(0, "Inode was orphaned on another node, clearing nlink.\n");
+- inode->i_nlink = 0;
+- }
+-
+- generic_drop_inode(inode);
++ if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED)
++ generic_delete_inode(inode);
++ else
++ generic_drop_inode(inode);
+
+ mlog_exit_void();
+ }
+@@ -1027,12 +1123,8 @@ struct buffer_head *ocfs2_bread(struct i
+ u64 p_blkno;
+ int readflags = OCFS2_BH_CACHED;
+
+-#if 0
+- /* only turn this on if we know we can deal with read_block
+- * returning nothing */
+ if (reada)
+ readflags |= OCFS2_BH_READAHEAD;
+-#endif
+
+ if (((u64)block << inode->i_sb->s_blocksize_bits) >=
+ i_size_read(inode)) {
+@@ -1131,6 +1223,7 @@ int ocfs2_mark_inode_dirty(struct ocfs2_
+
+ spin_lock(&OCFS2_I(inode)->ip_lock);
+ fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
++ fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
+ spin_unlock(&OCFS2_I(inode)->ip_lock);
+
+ fe->i_size = cpu_to_le64(i_size_read(inode));
+@@ -1164,17 +1257,16 @@ leave:
+ void ocfs2_refresh_inode(struct inode *inode,
+ struct ocfs2_dinode *fe)
+ {
+- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+-
+ spin_lock(&OCFS2_I(inode)->ip_lock);
+
+ OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
++ OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
++ ocfs2_set_inode_flags(inode);
+ i_size_write(inode, le64_to_cpu(fe->i_size));
+ inode->i_nlink = le16_to_cpu(fe->i_links_count);
+ inode->i_uid = le32_to_cpu(fe->i_uid);
+ inode->i_gid = le32_to_cpu(fe->i_gid);
+ inode->i_mode = le16_to_cpu(fe->i_mode);
+- inode->i_blksize = (u32) osb->s_clustersize;
+ if (S_ISLNK(inode->i_mode) && le32_to_cpu(fe->i_clusters) == 0)
+ inode->i_blocks = 0;
+ else
+diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
+index 35140f6..9957810 100644
+--- a/fs/ocfs2/inode.h
++++ b/fs/ocfs2/inode.h
+@@ -56,6 +56,7 @@ struct ocfs2_inode_info
+ struct ocfs2_journal_handle *ip_handle;
+
+ u32 ip_flags; /* see below */
++ u32 ip_attr; /* inode attributes */
+
+ /* protected by recovery_lock. */
+ struct inode *ip_next_orphan;
+@@ -121,7 +122,13 @@ struct buffer_head *ocfs2_bread(struct i
+ void ocfs2_clear_inode(struct inode *inode);
+ void ocfs2_delete_inode(struct inode *inode);
+ void ocfs2_drop_inode(struct inode *inode);
+-struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff);
++
++/* Flags for ocfs2_iget() */
++#define OCFS2_FI_FLAG_NOWAIT 0x1
++#define OCFS2_FI_FLAG_DELETE 0x2
++#define OCFS2_FI_FLAG_SYSFILE 0x4
++#define OCFS2_FI_FLAG_NOLOCK 0x8
++struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, int flags);
+ struct inode *ocfs2_ilookup_for_vote(struct ocfs2_super *osb,
+ u64 blkno,
+ int delete_vote);
+@@ -142,4 +149,6 @@ int ocfs2_mark_inode_dirty(struct ocfs2_
+ int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb);
+ int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb);
+
++void ocfs2_set_inode_flags(struct inode *inode);
++
+ #endif /* OCFS2_INODE_H */
+diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
+new file mode 100644
+index 0000000..3663cef
+--- /dev/null
++++ b/fs/ocfs2/ioctl.c
+@@ -0,0 +1,136 @@
++/*
++ * linux/fs/ocfs2/ioctl.c
++ *
++ * Copyright (C) 2006 Herbert Poetzl
++ * adapted from Remy Card's ext2/ioctl.c
++ */
++
++#include <linux/fs.h>
++#include <linux/mount.h>
++
++#define MLOG_MASK_PREFIX ML_INODE
++#include <cluster/masklog.h>
++
++#include "ocfs2.h"
++#include "alloc.h"
++#include "dlmglue.h"
++#include "inode.h"
++#include "journal.h"
++
++#include "ocfs2_fs.h"
++#include "ioctl.h"
++
++#include <linux/ext2_fs.h>
++
++static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
++{
++ int status;
++
++ status = ocfs2_meta_lock(inode, NULL, NULL, 0);
++ if (status < 0) {
++ mlog_errno(status);
++ return status;
++ }
++ *flags = OCFS2_I(inode)->ip_attr;
++ ocfs2_meta_unlock(inode, 0);
++
++ mlog_exit(status);
++ return status;
++}
++
++static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
++ unsigned mask)
++{
++ struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode);
++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++ struct ocfs2_journal_handle *handle = NULL;
++ struct buffer_head *bh = NULL;
++ unsigned oldflags;
++ int status;
++
++ mutex_lock(&inode->i_mutex);
++
++ status = ocfs2_meta_lock(inode, NULL, &bh, 1);
++ if (status < 0) {
++ mlog_errno(status);
++ goto bail;
++ }
++
++ status = -EROFS;
++ if (IS_RDONLY(inode))
++ goto bail_unlock;
++
++ status = -EACCES;
++ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
++ goto bail_unlock;
++
++ if (!S_ISDIR(inode->i_mode))
++ flags &= ~OCFS2_DIRSYNC_FL;
++
++ handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
++ if (IS_ERR(handle)) {
++ status = PTR_ERR(handle);
++ mlog_errno(status);
++ goto bail_unlock;
++ }
++
++ oldflags = ocfs2_inode->ip_attr;
++ flags = flags & mask;
++ flags |= oldflags & ~mask;
++
++ /*
++ * The IMMUTABLE and APPEND_ONLY flags can only be changed by
++ * the relevant capability.
++ */
++ status = -EPERM;
++ if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
++ (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
++ if (!capable(CAP_LINUX_IMMUTABLE))
++ goto bail_unlock;
++ }
++
++ ocfs2_inode->ip_attr = flags;
++ ocfs2_set_inode_flags(inode);
++
++ status = ocfs2_mark_inode_dirty(handle, inode, bh);
++ if (status < 0)
++ mlog_errno(status);
++
++ ocfs2_commit_trans(handle);
++bail_unlock:
++ ocfs2_meta_unlock(inode, 1);
++bail:
++ mutex_unlock(&inode->i_mutex);
++
++ if (bh)
++ brelse(bh);
++
++ mlog_exit(status);
++ return status;
++}
++
++int ocfs2_ioctl(struct inode * inode, struct file * filp,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned int flags;
++ int status;
++
++ switch (cmd) {
++ case OCFS2_IOC_GETFLAGS:
++ status = ocfs2_get_inode_attr(inode, &flags);
++ if (status < 0)
++ return status;
++
++ flags &= OCFS2_FL_VISIBLE;
++ return put_user(flags, (int __user *) arg);
++ case OCFS2_IOC_SETFLAGS:
++ if (get_user(flags, (int __user *) arg))
++ return -EFAULT;
++
++ return ocfs2_set_inode_attr(inode, flags,
++ OCFS2_FL_MODIFIABLE);
++ default:
++ return -ENOTTY;
++ }
++}
++
+diff --git a/fs/ocfs2/ioctl.h b/fs/ocfs2/ioctl.h
+new file mode 100644
+index 0000000..4a7c829
+--- /dev/null
++++ b/fs/ocfs2/ioctl.h
+@@ -0,0 +1,16 @@
++/*
++ * ioctl.h
++ *
++ * Function prototypes
++ *
++ * Copyright (C) 2006 Herbert Poetzl
++ *
++ */
++
++#ifndef OCFS2_IOCTL_H
++#define OCFS2_IOCTL_H
++
++int ocfs2_ioctl(struct inode * inode, struct file * filp,
++ unsigned int cmd, unsigned long arg);
++
++#endif /* OCFS2_IOCTL_H */
+diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
+index f92bf1d..fd9734d 100644
+--- a/fs/ocfs2/journal.c
++++ b/fs/ocfs2/journal.c
+@@ -1493,7 +1493,8 @@ static int ocfs2_queue_orphans(struct oc
+ if (de->name_len == 2 && !strncmp("..", de->name, 2))
+ continue;
+
+- iter = ocfs2_iget(osb, le64_to_cpu(de->inode));
++ iter = ocfs2_iget(osb, le64_to_cpu(de->inode),
++ OCFS2_FI_FLAG_NOLOCK);
+ if (IS_ERR(iter))
+ continue;
+
+diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
+index 0673862..a57b751 100644
+--- a/fs/ocfs2/namei.c
++++ b/fs/ocfs2/namei.c
+@@ -56,6 +56,7 @@
+ #include "journal.h"
+ #include "namei.h"
+ #include "suballoc.h"
++#include "super.h"
+ #include "symlink.h"
+ #include "sysfile.h"
+ #include "uptodate.h"
+@@ -178,7 +179,7 @@ static struct dentry *ocfs2_lookup(struc
+ if (status < 0)
+ goto bail_add;
+
+- inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno);
++ inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
+ if (IS_ERR(inode)) {
+ mlog(ML_ERROR, "Unable to create inode %llu\n",
+ (unsigned long long)blkno);
+@@ -198,10 +199,32 @@ static struct dentry *ocfs2_lookup(struc
+ spin_unlock(&oi->ip_lock);
+
+ bail_add:
+-
+ dentry->d_op = &ocfs2_dentry_ops;
+ ret = d_splice_alias(inode, dentry);
+
++ if (inode) {
++ /*
++ * If d_splice_alias() finds a DCACHE_DISCONNECTED
++ * dentry, it will d_move() it on top of ourse. The
++ * return value will indicate this however, so in
++ * those cases, we switch them around for the locking
++ * code.
++ *
++ * NOTE: This dentry already has ->d_op set from
++ * ocfs2_get_parent() and ocfs2_get_dentry()
++ */
++ if (ret)
++ dentry = ret;
++
++ status = ocfs2_dentry_attach_lock(dentry, inode,
++ OCFS2_I(dir)->ip_blkno);
++ if (status) {
++ mlog_errno(status);
++ ret = ERR_PTR(status);
++ goto bail_unlock;
++ }
++ }
++
+ bail_unlock:
+ /* Don't drop the cluster lock until *after* the d_add --
+ * unlink on another node will message us to remove that
+@@ -310,13 +333,6 @@ static int ocfs2_mknod(struct inode *dir
+ /* get our super block */
+ osb = OCFS2_SB(dir->i_sb);
+
+- if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) {
+- mlog(ML_ERROR, "inode %llu has i_nlink of %u\n",
+- (unsigned long long)OCFS2_I(dir)->ip_blkno, dir->i_nlink);
+- status = -EMLINK;
+- goto leave;
+- }
+-
+ handle = ocfs2_alloc_handle(osb);
+ if (handle == NULL) {
+ status = -ENOMEM;
+@@ -331,6 +347,11 @@ static int ocfs2_mknod(struct inode *dir
+ goto leave;
+ }
+
++ if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) {
++ status = -EMLINK;
++ goto leave;
++ }
++
+ dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
+ if (!dirfe->i_links_count) {
+ /* can't make a file in a deleted directory. */
+@@ -408,7 +429,7 @@ static int ocfs2_mknod(struct inode *dir
+ mlog_errno(status);
+ goto leave;
+ }
+- dir->i_nlink++;
++ inc_nlink(dir);
+ }
+
+ status = ocfs2_add_entry(handle, dentry, inode,
+@@ -419,6 +440,13 @@ static int ocfs2_mknod(struct inode *dir
+ goto leave;
+ }
+
++ status = ocfs2_dentry_attach_lock(dentry, inode,
++ OCFS2_I(dir)->ip_blkno);
++ if (status) {
++ mlog_errno(status);
++ goto leave;
++ }
++
+ insert_inode_hash(inode);
+ dentry->d_op = &ocfs2_dentry_ops;
+ d_instantiate(dentry, inode);
+@@ -643,11 +671,6 @@ static int ocfs2_link(struct dentry *old
+ goto bail;
+ }
+
+- if (inode->i_nlink >= OCFS2_LINK_MAX) {
+- err = -EMLINK;
+- goto bail;
+- }
+-
+ handle = ocfs2_alloc_handle(osb);
+ if (handle == NULL) {
+ err = -ENOMEM;
+@@ -661,6 +684,11 @@ static int ocfs2_link(struct dentry *old
+ goto bail;
+ }
+
++ if (!dir->i_nlink) {
++ err = -ENOENT;
++ goto bail;
++ }
++
+ err = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,
+ dentry->d_name.len);
+ if (err)
+@@ -702,7 +730,7 @@ static int ocfs2_link(struct dentry *old
+ goto bail;
+ }
+
+- inode->i_nlink++;
++ inc_nlink(inode);
+ inode->i_ctime = CURRENT_TIME;
+ fe->i_links_count = cpu_to_le16(inode->i_nlink);
+ fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+@@ -711,7 +739,7 @@ static int ocfs2_link(struct dentry *old
+ err = ocfs2_journal_dirty(handle, fe_bh);
+ if (err < 0) {
+ le16_add_cpu(&fe->i_links_count, -1);
+- inode->i_nlink--;
++ drop_nlink(inode);
+ mlog_errno(err);
+ goto bail;
+ }
+@@ -721,7 +749,13 @@ static int ocfs2_link(struct dentry *old
+ parent_fe_bh, de_bh);
+ if (err) {
+ le16_add_cpu(&fe->i_links_count, -1);
+- inode->i_nlink--;
++ drop_nlink(inode);
++ mlog_errno(err);
++ goto bail;
++ }
++
++ err = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno);
++ if (err) {
+ mlog_errno(err);
+ goto bail;
+ }
+@@ -744,11 +778,40 @@ bail:
+ return err;
+ }
+
++/*
++ * Takes and drops an exclusive lock on the given dentry. This will
++ * force other nodes to drop it.
++ */
++static int ocfs2_remote_dentry_delete(struct dentry *dentry)
++{
++ int ret;
++
++ ret = ocfs2_dentry_lock(dentry, 1);
++ if (ret)
++ mlog_errno(ret);
++ else
++ ocfs2_dentry_unlock(dentry, 1);
++
++ return ret;
++}
++
++static inline int inode_is_unlinkable(struct inode *inode)
++{
++ if (S_ISDIR(inode->i_mode)) {
++ if (inode->i_nlink == 2)
++ return 1;
++ return 0;
++ }
++
++ if (inode->i_nlink == 1)
++ return 1;
++ return 0;
++}
++
+ static int ocfs2_unlink(struct inode *dir,
+ struct dentry *dentry)
+ {
+ int status;
+- unsigned int saved_nlink = 0;
+ struct inode *inode = dentry->d_inode;
+ struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+ u64 blkno;
+@@ -823,18 +886,7 @@ static int ocfs2_unlink(struct inode *di
+ }
+ }
+
+- /* There are still a few steps left until we can consider the
+- * unlink to have succeeded. Save off nlink here before
+- * modification so we can set it back in case we hit an issue
+- * before commit. */
+- saved_nlink = inode->i_nlink;
+- if (S_ISDIR(inode->i_mode))
+- inode->i_nlink = 0;
+- else
+- inode->i_nlink--;
+-
+- status = ocfs2_request_unlink_vote(inode, dentry,
+- (unsigned int) inode->i_nlink);
++ status = ocfs2_remote_dentry_delete(dentry);
+ if (status < 0) {
+ /* This vote should succeed under all normal
+ * circumstances. */
+@@ -842,7 +894,7 @@ static int ocfs2_unlink(struct inode *di
+ goto leave;
+ }
+
+- if (!inode->i_nlink) {
++ if (inode_is_unlinkable(inode)) {
+ status = ocfs2_prepare_orphan_dir(osb, handle, inode,
+ orphan_name,
+ &orphan_entry_bh);
+@@ -869,7 +921,7 @@ static int ocfs2_unlink(struct inode *di
+
+ fe = (struct ocfs2_dinode *) fe_bh->b_data;
+
+- if (!inode->i_nlink) {
++ if (inode_is_unlinkable(inode)) {
+ status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name,
+ orphan_entry_bh);
+ if (status < 0) {
+@@ -885,10 +937,10 @@ static int ocfs2_unlink(struct inode *di
+ goto leave;
+ }
+
+- /* We can set nlink on the dinode now. clear the saved version
+- * so that it doesn't get set later. */
++ if (S_ISDIR(inode->i_mode))
++ drop_nlink(inode);
++ drop_nlink(inode);
+ fe->i_links_count = cpu_to_le16(inode->i_nlink);
+- saved_nlink = 0;
+
+ status = ocfs2_journal_dirty(handle, fe_bh);
+ if (status < 0) {
+@@ -897,19 +949,16 @@ static int ocfs2_unlink(struct inode *di
+ }
+
+ if (S_ISDIR(inode->i_mode)) {
+- dir->i_nlink--;
++ drop_nlink(dir);
+ status = ocfs2_mark_inode_dirty(handle, dir,
+ parent_node_bh);
+ if (status < 0) {
+ mlog_errno(status);
+- dir->i_nlink++;
++ inc_nlink(dir);
+ }
+ }
+
+ leave:
+- if (status < 0 && saved_nlink)
+- inode->i_nlink = saved_nlink;
+-
+ if (handle)
+ ocfs2_commit_trans(handle);
+
+@@ -1020,7 +1069,6 @@ static int ocfs2_rename(struct inode *ol
+ struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
+ // this is the 1st dirent bh
+ nlink_t old_dir_nlink = old_dir->i_nlink, new_dir_nlink = new_dir->i_nlink;
+- unsigned int links_count;
+
+ /* At some point it might be nice to break this function up a
+ * bit. */
+@@ -1037,14 +1085,6 @@ static int ocfs2_rename(struct inode *ol
+ BUG();
+ }
+
+- if (atomic_read(&old_dentry->d_count) > 2) {
+- shrink_dcache_parent(old_dentry);
+- if (atomic_read(&old_dentry->d_count) > 2) {
+- status = -EBUSY;
+- goto bail;
+- }
+- }
+-
+ /* Assume a directory heirarchy thusly:
+ * a/b/c
+ * a/d
+@@ -1094,23 +1134,26 @@ static int ocfs2_rename(struct inode *ol
+ }
+ }
+
+- if (S_ISDIR(old_inode->i_mode)) {
+- /* Directories actually require metadata updates to
+- * the directory info so we can't get away with not
+- * doing node locking on it. */
+- status = ocfs2_meta_lock(old_inode, handle, NULL, 1);
+- if (status < 0) {
+- if (status != -ENOENT)
+- mlog_errno(status);
+- goto bail;
+- }
+-
+- status = ocfs2_request_rename_vote(old_inode, old_dentry);
+- if (status < 0) {
++ /*
++ * Though we don't require an inode meta data update if
++ * old_inode is not a directory, we lock anyway here to ensure
++ * the vote thread on other nodes won't have to concurrently
++ * downconvert the inode and the dentry locks.
++ */
++ status = ocfs2_meta_lock(old_inode, handle, NULL, 1);
++ if (status < 0) {
++ if (status != -ENOENT)
+ mlog_errno(status);
+- goto bail;
+- }
++ goto bail;
++ }
++
++ status = ocfs2_remote_dentry_delete(old_dentry);
++ if (status < 0) {
++ mlog_errno(status);
++ goto bail;
++ }
+
++ if (S_ISDIR(old_inode->i_mode)) {
+ status = -EIO;
+ old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0);
+ if (!old_inode_de_bh)
+@@ -1124,14 +1167,6 @@ static int ocfs2_rename(struct inode *ol
+ if (!new_inode && new_dir!=old_dir &&
+ new_dir->i_nlink >= OCFS2_LINK_MAX)
+ goto bail;
+- } else {
+- /* Ah, the simple case - we're a file so just send a
+- * message. */
+- status = ocfs2_request_rename_vote(old_inode, old_dentry);
+- if (status < 0) {
+- mlog_errno(status);
+- goto bail;
+- }
+ }
+
+ status = -ENOENT;
+@@ -1203,13 +1238,7 @@ static int ocfs2_rename(struct inode *ol
+ goto bail;
+ }
+
+- if (S_ISDIR(new_inode->i_mode))
+- links_count = 0;
+- else
+- links_count = (unsigned int) (new_inode->i_nlink - 1);
+-
+- status = ocfs2_request_unlink_vote(new_inode, new_dentry,
+- links_count);
++ status = ocfs2_remote_dentry_delete(new_dentry);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+@@ -1344,7 +1373,7 @@ static int ocfs2_rename(struct inode *ol
+ if (new_inode) {
+ new_inode->i_nlink--;
+ } else {
+- new_dir->i_nlink++;
++ inc_nlink(new_dir);
+ mark_inode_dirty(new_dir);
+ }
+ }
+@@ -1388,6 +1417,7 @@ static int ocfs2_rename(struct inode *ol
+ }
+ }
+
++ ocfs2_dentry_move(old_dentry, new_dentry, old_dir, new_dir);
+ status = 0;
+ bail:
+ if (rename_lock)
+@@ -1676,6 +1706,12 @@ static int ocfs2_symlink(struct inode *d
+ goto bail;
+ }
+
++ status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno);
++ if (status) {
++ mlog_errno(status);
++ goto bail;
++ }
++
+ insert_inode_hash(inode);
+ dentry->d_op = &ocfs2_dentry_ops;
+ d_instantiate(dentry, inode);
+@@ -1964,13 +2000,8 @@ restart:
+ }
+ num++;
+
+- /* XXX: questionable readahead stuff here */
+ bh = ocfs2_bread(dir, b++, &err, 1);
+ bh_use[ra_max] = bh;
+-#if 0 // ???
+- if (bh)
+- ll_rw_block(READ, 1, &bh);
+-#endif
+ }
+ }
+ if ((bh = bh_use[ra_ptr++]) == NULL)
+@@ -1978,6 +2009,10 @@ restart:
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ /* read error, skip block & hope for the best */
++ ocfs2_error(dir->i_sb, "reading directory %llu, "
++ "offset %lu\n",
++ (unsigned long long)OCFS2_I(dir)->ip_blkno,
++ block);
+ brelse(bh);
+ goto next;
+ }
+diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
+index c5b1ac5..3330a5d 100644
+--- a/fs/ocfs2/ocfs2_fs.h
++++ b/fs/ocfs2/ocfs2_fs.h
+@@ -114,6 +114,26 @@
+ #define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */
+ #define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */
+
++/* Inode attributes, keep in sync with EXT2 */
++#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */
++#define OCFS2_UNRM_FL (0x00000002) /* Undelete */
++#define OCFS2_COMPR_FL (0x00000004) /* Compress file */
++#define OCFS2_SYNC_FL (0x00000008) /* Synchronous updates */
++#define OCFS2_IMMUTABLE_FL (0x00000010) /* Immutable file */
++#define OCFS2_APPEND_FL (0x00000020) /* writes to file may only append */
++#define OCFS2_NODUMP_FL (0x00000040) /* do not dump file */
++#define OCFS2_NOATIME_FL (0x00000080) /* do not update atime */
++#define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */
++
++#define OCFS2_FL_VISIBLE (0x000100FF) /* User visible flags */
++#define OCFS2_FL_MODIFIABLE (0x000100FF) /* User modifiable flags */
++
++/*
++ * ioctl commands
++ */
++#define OCFS2_IOC_GETFLAGS _IOR('f', 1, long)
++#define OCFS2_IOC_SETFLAGS _IOW('f', 2, long)
++
+ /*
+ * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
+ */
+@@ -399,7 +419,9 @@ struct ocfs2_dinode {
+ __le32 i_atime_nsec;
+ __le32 i_ctime_nsec;
+ __le32 i_mtime_nsec;
+-/*70*/ __le64 i_reserved1[9];
++ __le32 i_attr;
++ __le32 i_reserved1;
++/*70*/ __le64 i_reserved2[8];
+ /*B8*/ union {
+ __le64 i_pad1; /* Generic way to refer to this
+ 64bit union */
+diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h
+index 7dd9e1e..4d5d565 100644
+--- a/fs/ocfs2/ocfs2_lockid.h
++++ b/fs/ocfs2/ocfs2_lockid.h
+@@ -35,12 +35,15 @@
+ #define OCFS2_LOCK_ID_MAX_LEN 32
+ #define OCFS2_LOCK_ID_PAD "000000"
+
++#define OCFS2_DENTRY_LOCK_INO_START 18
++
+ enum ocfs2_lock_type {
+ OCFS2_LOCK_TYPE_META = 0,
+ OCFS2_LOCK_TYPE_DATA,
+ OCFS2_LOCK_TYPE_SUPER,
+ OCFS2_LOCK_TYPE_RENAME,
+ OCFS2_LOCK_TYPE_RW,
++ OCFS2_LOCK_TYPE_DENTRY,
+ OCFS2_NUM_LOCK_TYPES
+ };
+
+@@ -63,6 +66,9 @@ static inline char ocfs2_lock_type_char(
+ case OCFS2_LOCK_TYPE_RW:
+ c = 'W';
+ break;
++ case OCFS2_LOCK_TYPE_DENTRY:
++ c = 'N';
++ break;
+ default:
+ c = '\0';
+ }
+@@ -70,4 +76,23 @@ static inline char ocfs2_lock_type_char(
+ return c;
+ }
+
++static char *ocfs2_lock_type_strings[] = {
++ [OCFS2_LOCK_TYPE_META] = "Meta",
++ [OCFS2_LOCK_TYPE_DATA] = "Data",
++ [OCFS2_LOCK_TYPE_SUPER] = "Super",
++ [OCFS2_LOCK_TYPE_RENAME] = "Rename",
++ /* Need to differntiate from [R]ename.. serializing writes is the
++ * important job it does, anyway. */
++ [OCFS2_LOCK_TYPE_RW] = "Write/Read",
++ [OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
++};
++
++static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
++{
++#ifdef __KERNEL__
++ mlog_bug_on_msg(type >= OCFS2_NUM_LOCK_TYPES, "%d\n", type);
++#endif
++ return ocfs2_lock_type_strings[type];
++}
++
+ #endif /* OCFS2_LOCKID_H */
+diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
+index d17e33e..76b46eb 100644
+--- a/fs/ocfs2/super.c
++++ b/fs/ocfs2/super.c
+@@ -202,7 +202,7 @@ static int ocfs2_init_global_system_inod
+
+ mlog_entry_void();
+
+- new = ocfs2_iget(osb, osb->root_blkno);
++ new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE);
+ if (IS_ERR(new)) {
+ status = PTR_ERR(new);
+ mlog_errno(status);
+@@ -210,7 +210,7 @@ static int ocfs2_init_global_system_inod
+ }
+ osb->root_inode = new;
+
+- new = ocfs2_iget(osb, osb->system_dir_blkno);
++ new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE);
+ if (IS_ERR(new)) {
+ status = PTR_ERR(new);
+ mlog_errno(status);
+@@ -339,7 +339,7 @@ static unsigned long long ocfs2_max_file
+
+ #if BITS_PER_LONG == 32
+ # if defined(CONFIG_LBD)
+- BUG_ON(sizeof(sector_t) != 8);
++ BUILD_BUG_ON(sizeof(sector_t) != 8);
+ pagefactor = PAGE_CACHE_SIZE;
+ bitshift = BITS_PER_LONG;
+ # else
+@@ -682,7 +682,7 @@ static struct file_system_type ocfs2_fs_
+ .kill_sb = kill_block_super, /* set to the generic one
+ * right now, but do we
+ * need to change that? */
+- .fs_flags = FS_REQUIRES_DEV,
++ .fs_flags = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
+ .next = NULL
+ };
+
+diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
+index fc29cb7..5df6e35 100644
+--- a/fs/ocfs2/sysfile.c
++++ b/fs/ocfs2/sysfile.c
+@@ -28,11 +28,11 @@
+ #include <linux/slab.h>
+ #include <linux/highmem.h>
+
+-#include "ocfs2.h"
+-
+ #define MLOG_MASK_PREFIX ML_INODE
+ #include <cluster/masklog.h>
+
++#include "ocfs2.h"
++
+ #include "alloc.h"
+ #include "dir.h"
+ #include "inode.h"
+@@ -115,7 +115,7 @@ static struct inode * _ocfs2_get_system_
+ goto bail;
+ }
+
+- inode = ocfs2_iget(osb, blkno);
++ inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE);
+ if (IS_ERR(inode)) {
+ mlog_errno(PTR_ERR(inode));
+ inode = NULL;
+diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c
+index b8a00a7..9707ed7 100644
+--- a/fs/ocfs2/uptodate.c
++++ b/fs/ocfs2/uptodate.c
+@@ -206,7 +206,10 @@ static int ocfs2_buffer_cached(struct oc
+ }
+
+ /* Warning: even if it returns true, this does *not* guarantee that
+- * the block is stored in our inode metadata cache. */
++ * the block is stored in our inode metadata cache.
++ *
++ * This can be called under lock_buffer()
++ */
+ int ocfs2_buffer_uptodate(struct inode *inode,
+ struct buffer_head *bh)
+ {
+@@ -226,6 +229,16 @@ int ocfs2_buffer_uptodate(struct inode *
+ return ocfs2_buffer_cached(OCFS2_I(inode), bh);
+ }
+
++/*
++ * Determine whether a buffer is currently out on a read-ahead request.
++ * ip_io_sem should be held to serialize submitters with the logic here.
++ */
++int ocfs2_buffer_read_ahead(struct inode *inode,
++ struct buffer_head *bh)
++{
++ return buffer_locked(bh) && ocfs2_buffer_cached(OCFS2_I(inode), bh);
++}
++
+ /* Requires ip_lock */
+ static void ocfs2_append_cache_array(struct ocfs2_caching_info *ci,
+ sector_t block)
+@@ -403,7 +416,11 @@ out_free:
+ *
+ * Note that this function may actually fail to insert the block if
+ * memory cannot be allocated. This is not fatal however (but may
+- * result in a performance penalty) */
++ * result in a performance penalty)
++ *
++ * Readahead buffers can be passed in here before the I/O request is
++ * completed.
++ */
+ void ocfs2_set_buffer_uptodate(struct inode *inode,
+ struct buffer_head *bh)
+ {
+diff --git a/fs/ocfs2/uptodate.h b/fs/ocfs2/uptodate.h
+index 01cd32d..2e73206 100644
+--- a/fs/ocfs2/uptodate.h
++++ b/fs/ocfs2/uptodate.h
+@@ -40,5 +40,7 @@ void ocfs2_set_new_buffer_uptodate(struc
+ struct buffer_head *bh);
+ void ocfs2_remove_from_cache(struct inode *inode,
+ struct buffer_head *bh);
++int ocfs2_buffer_read_ahead(struct inode *inode,
++ struct buffer_head *bh);
+
+ #endif /* OCFS2_UPTODATE_H */
+diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
+index cf70fe2..5b4dca7 100644
+--- a/fs/ocfs2/vote.c
++++ b/fs/ocfs2/vote.c
+@@ -74,9 +74,6 @@ struct ocfs2_vote_msg
+ __be32 v_orphaned_slot; /* Used during delete votes */
+ __be32 v_nlink; /* Used during unlink votes */
+ } md1; /* Message type dependant 1 */
+- __be32 v_unlink_namelen;
+- __be64 v_unlink_parent;
+- u8 v_unlink_dirent[OCFS2_VOTE_FILENAME_LEN];
+ };
+
+ /* Responses are given these values to maintain backwards
+@@ -100,8 +97,6 @@ struct ocfs2_vote_work {
+ enum ocfs2_vote_request {
+ OCFS2_VOTE_REQ_INVALID = 0,
+ OCFS2_VOTE_REQ_DELETE,
+- OCFS2_VOTE_REQ_UNLINK,
+- OCFS2_VOTE_REQ_RENAME,
+ OCFS2_VOTE_REQ_MOUNT,
+ OCFS2_VOTE_REQ_UMOUNT,
+ OCFS2_VOTE_REQ_LAST
+@@ -261,103 +256,13 @@ done:
+ return response;
+ }
+
+-static int ocfs2_match_dentry(struct dentry *dentry,
+- u64 parent_blkno,
+- unsigned int namelen,
+- const char *name)
+-{
+- struct inode *parent;
+-
+- if (!dentry->d_parent) {
+- mlog(0, "Detached from parent.\n");
+- return 0;
+- }
+-
+- parent = dentry->d_parent->d_inode;
+- /* Negative parent dentry? */
+- if (!parent)
+- return 0;
+-
+- /* Name is in a different directory. */
+- if (OCFS2_I(parent)->ip_blkno != parent_blkno)
+- return 0;
+-
+- if (dentry->d_name.len != namelen)
+- return 0;
+-
+- /* comparison above guarantees this is safe. */
+- if (memcmp(dentry->d_name.name, name, namelen))
+- return 0;
+-
+- return 1;
+-}
+-
+-static void ocfs2_process_dentry_request(struct inode *inode,
+- int rename,
+- unsigned int new_nlink,
+- u64 parent_blkno,
+- unsigned int namelen,
+- const char *name)
+-{
+- struct dentry *dentry = NULL;
+- struct list_head *p;
+- struct ocfs2_inode_info *oi = OCFS2_I(inode);
+-
+- mlog(0, "parent %llu, namelen = %u, name = %.*s\n",
+- (unsigned long long)parent_blkno, namelen, namelen, name);
+-
+- spin_lock(&dcache_lock);
+-
+- /* Another node is removing this name from the system. It is
+- * up to us to find the corresponding dentry and if it exists,
+- * unhash it from the dcache. */
+- list_for_each(p, &inode->i_dentry) {
+- dentry = list_entry(p, struct dentry, d_alias);
+-
+- if (ocfs2_match_dentry(dentry, parent_blkno, namelen, name)) {
+- mlog(0, "dentry found: %.*s\n",
+- dentry->d_name.len, dentry->d_name.name);
+-
+- dget_locked(dentry);
+- break;
+- }
+-
+- dentry = NULL;
+- }
+-
+- spin_unlock(&dcache_lock);
+-
+- if (dentry) {
+- d_delete(dentry);
+- dput(dentry);
+- }
+-
+- /* rename votes don't send link counts */
+- if (!rename) {
+- mlog(0, "new_nlink = %u\n", new_nlink);
+-
+- /* We don't have the proper locks here to directly
+- * change i_nlink and besides, the vote is sent
+- * *before* the operation so it may have failed on the
+- * other node. This passes a hint to ocfs2_drop_inode
+- * to force ocfs2_delete_inode, who will take the
+- * proper cluster locks to sort things out. */
+- if (new_nlink == 0) {
+- spin_lock(&oi->ip_lock);
+- oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED;
+- spin_unlock(&OCFS2_I(inode)->ip_lock);
+- }
+- }
+-}
+-
+ static void ocfs2_process_vote(struct ocfs2_super *osb,
+ struct ocfs2_vote_msg *msg)
+ {
+ int net_status, vote_response;
+ int orphaned_slot = 0;
+- int rename = 0;
+- unsigned int node_num, generation, new_nlink, namelen;
+- u64 blkno, parent_blkno;
++ unsigned int node_num, generation;
++ u64 blkno;
+ enum ocfs2_vote_request request;
+ struct inode *inode = NULL;
+ struct ocfs2_msg_hdr *hdr = &msg->v_hdr;
+@@ -437,18 +342,6 @@ static void ocfs2_process_vote(struct oc
+ vote_response = ocfs2_process_delete_request(inode,
+ &orphaned_slot);
+ break;
+- case OCFS2_VOTE_REQ_RENAME:
+- rename = 1;
+- /* fall through */
+- case OCFS2_VOTE_REQ_UNLINK:
+- parent_blkno = be64_to_cpu(msg->v_unlink_parent);
+- namelen = be32_to_cpu(msg->v_unlink_namelen);
+- /* new_nlink will be ignored in case of a rename vote */
+- new_nlink = be32_to_cpu(msg->md1.v_nlink);
+- ocfs2_process_dentry_request(inode, rename, new_nlink,
+- parent_blkno, namelen,
+- msg->v_unlink_dirent);
+- break;
+ default:
+ mlog(ML_ERROR, "node %u, invalid request: %u\n",
+ node_num, request);
+@@ -889,75 +782,6 @@ int ocfs2_request_delete_vote(struct ino
+ return status;
+ }
+
+-static void ocfs2_setup_unlink_vote(struct ocfs2_vote_msg *request,
+- struct dentry *dentry)
+-{
+- struct inode *parent = dentry->d_parent->d_inode;
+-
+- /* We need some values which will uniquely identify a dentry
+- * on the other nodes so that they can find it and run
+- * d_delete against it. Parent directory block and full name
+- * should suffice. */
+-
+- mlog(0, "unlink/rename request: parent: %llu name: %.*s\n",
+- (unsigned long long)OCFS2_I(parent)->ip_blkno, dentry->d_name.len,
+- dentry->d_name.name);
+-
+- request->v_unlink_parent = cpu_to_be64(OCFS2_I(parent)->ip_blkno);
+- request->v_unlink_namelen = cpu_to_be32(dentry->d_name.len);
+- memcpy(request->v_unlink_dirent, dentry->d_name.name,
+- dentry->d_name.len);
+-}
+-
+-int ocfs2_request_unlink_vote(struct inode *inode,
+- struct dentry *dentry,
+- unsigned int nlink)
+-{
+- int status;
+- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+- struct ocfs2_vote_msg *request;
+-
+- if (dentry->d_name.len > OCFS2_VOTE_FILENAME_LEN)
+- return -ENAMETOOLONG;
+-
+- status = -ENOMEM;
+- request = ocfs2_new_vote_request(osb, OCFS2_I(inode)->ip_blkno,
+- inode->i_generation,
+- OCFS2_VOTE_REQ_UNLINK, nlink);
+- if (request) {
+- ocfs2_setup_unlink_vote(request, dentry);
+-
+- status = ocfs2_request_vote(inode, request, NULL);
+-
+- kfree(request);
+- }
+- return status;
+-}
+-
+-int ocfs2_request_rename_vote(struct inode *inode,
+- struct dentry *dentry)
+-{
+- int status;
+- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+- struct ocfs2_vote_msg *request;
+-
+- if (dentry->d_name.len > OCFS2_VOTE_FILENAME_LEN)
+- return -ENAMETOOLONG;
+-
+- status = -ENOMEM;
+- request = ocfs2_new_vote_request(osb, OCFS2_I(inode)->ip_blkno,
+- inode->i_generation,
+- OCFS2_VOTE_REQ_RENAME, 0);
+- if (request) {
+- ocfs2_setup_unlink_vote(request, dentry);
+-
+- status = ocfs2_request_vote(inode, request, NULL);
+-
+- kfree(request);
+- }
+- return status;
+-}
+-
+ int ocfs2_request_mount_vote(struct ocfs2_super *osb)
+ {
+ int status;
+diff --git a/fs/ocfs2/vote.h b/fs/ocfs2/vote.h
+index 9cce607..53ebc1c 100644
+--- a/fs/ocfs2/vote.h
++++ b/fs/ocfs2/vote.h
+@@ -39,11 +39,6 @@ static inline void ocfs2_kick_vote_threa
+ }
+
+ int ocfs2_request_delete_vote(struct inode *inode);
+-int ocfs2_request_unlink_vote(struct inode *inode,
+- struct dentry *dentry,
+- unsigned int nlink);
+-int ocfs2_request_rename_vote(struct inode *inode,
+- struct dentry *dentry);
+ int ocfs2_request_mount_vote(struct ocfs2_super *osb);
+ int ocfs2_request_umount_vote(struct ocfs2_super *osb);
+ int ocfs2_register_net_handlers(struct ocfs2_super *osb);
+diff --git a/fs/open.c b/fs/open.c
+index 303f06d..89e0c23 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -6,7 +6,6 @@
+
+ #include <linux/string.h>
+ #include <linux/mm.h>
+-#include <linux/utime.h>
+ #include <linux/file.h>
+ #include <linux/smp_lock.h>
+ #include <linux/quotaops.h>
+@@ -29,8 +28,6 @@
+ #include <linux/rcupdate.h>
+ #include <linux/audit.h>
+
+-#include <asm/unistd.h>
+-
+ int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ {
+ int retval = -ENODEV;
+@@ -353,137 +350,6 @@ asmlinkage long sys_ftruncate64(unsigned
+ }
+ #endif
+
+-#ifdef __ARCH_WANT_SYS_UTIME
+-
+-/*
+- * sys_utime() can be implemented in user-level using sys_utimes().
+- * Is this for backwards compatibility? If so, why not move it
+- * into the appropriate arch directory (for those architectures that
+- * need it).
+- */
+-
+-/* If times==NULL, set access and modification to current time,
+- * must be owner or have write permission.
+- * Else, update from *times, must be owner or super user.
+- */
+-asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
+-{
+- int error;
+- struct nameidata nd;
+- struct inode * inode;
+- struct iattr newattrs;
+-
+- error = user_path_walk(filename, &nd);
+- if (error)
+- goto out;
+- inode = nd.dentry->d_inode;
+-
+- error = -EROFS;
+- if (IS_RDONLY(inode))
+- goto dput_and_out;
+-
+- /* Don't worry, the checks are done in inode_change_ok() */
+- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
+- if (times) {
+- error = -EPERM;
+- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+- goto dput_and_out;
+-
+- error = get_user(newattrs.ia_atime.tv_sec, ×->actime);
+- newattrs.ia_atime.tv_nsec = 0;
+- if (!error)
+- error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime);
+- newattrs.ia_mtime.tv_nsec = 0;
+- if (error)
+- goto dput_and_out;
+-
+- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+- } else {
+- error = -EACCES;
+- if (IS_IMMUTABLE(inode))
+- goto dput_and_out;
+-
+- if (current->fsuid != inode->i_uid &&
+- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
+- goto dput_and_out;
+- }
+- mutex_lock(&inode->i_mutex);
+- error = notify_change(nd.dentry, &newattrs);
+- mutex_unlock(&inode->i_mutex);
+-dput_and_out:
+- path_release(&nd);
+-out:
+- return error;
+-}
+-
+-#endif
+-
+-/* If times==NULL, set access and modification to current time,
+- * must be owner or have write permission.
+- * Else, update from *times, must be owner or super user.
+- */
+-long do_utimes(int dfd, char __user *filename, struct timeval *times)
+-{
+- int error;
+- struct nameidata nd;
+- struct inode * inode;
+- struct iattr newattrs;
+-
+- error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
+-
+- if (error)
+- goto out;
+- inode = nd.dentry->d_inode;
+-
+- error = -EROFS;
+- if (IS_RDONLY(inode))
+- goto dput_and_out;
+-
+- /* Don't worry, the checks are done in inode_change_ok() */
+- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
+- if (times) {
+- error = -EPERM;
+- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+- goto dput_and_out;
+-
+- newattrs.ia_atime.tv_sec = times[0].tv_sec;
+- newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
+- newattrs.ia_mtime.tv_sec = times[1].tv_sec;
+- newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
+- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+- } else {
+- error = -EACCES;
+- if (IS_IMMUTABLE(inode))
+- goto dput_and_out;
+-
+- if (current->fsuid != inode->i_uid &&
+- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
+- goto dput_and_out;
+- }
+- mutex_lock(&inode->i_mutex);
+- error = notify_change(nd.dentry, &newattrs);
+- mutex_unlock(&inode->i_mutex);
+-dput_and_out:
+- path_release(&nd);
+-out:
+- return error;
+-}
+-
+-asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
+-{
+- struct timeval times[2];
+-
+- if (utimes && copy_from_user(×, utimes, sizeof(times)))
+- return -EFAULT;
+- return do_utimes(dfd, filename, utimes ? times : NULL);
+-}
+-
+-asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
+-{
+- return sys_futimesat(AT_FDCWD, filename, utimes);
+-}
+-
+-
+ /*
+ * access() needs to use the real uid/gid, not the effective uid/gid.
+ * We do this by temporarily clearing all FS-related capabilities and
+@@ -520,15 +386,21 @@ asmlinkage long sys_faccessat(int dfd, c
+ current->cap_effective = current->cap_permitted;
+
+ res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
+- if (!res) {
+- res = vfs_permission(&nd, mode);
+- /* SuS v2 requires we report a read only fs too */
+- if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
+- && !special_file(nd.dentry->d_inode->i_mode))
+- res = -EROFS;
+- path_release(&nd);
+- }
++ if (res)
++ goto out;
++
++ res = vfs_permission(&nd, mode);
++ /* SuS v2 requires we report a read only fs too */
++ if(res || !(mode & S_IWOTH) ||
++ special_file(nd.dentry->d_inode->i_mode))
++ goto out_path_release;
++
++ if(IS_RDONLY(nd.dentry->d_inode))
++ res = -EROFS;
+
++out_path_release:
++ path_release(&nd);
++out:
+ current->fsuid = old_fsuid;
+ current->fsgid = old_fsgid;
+ current->cap_effective = old_cap;
+@@ -546,7 +418,8 @@ asmlinkage long sys_chdir(const char __u
+ struct nameidata nd;
+ int error;
+
+- error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
++ error = __user_walk(filename,
++ LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
+ if (error)
+ goto out;
+
+@@ -736,10 +609,11 @@ asmlinkage long sys_chown(const char __u
+ int error;
+
+ error = user_path_walk(filename, &nd);
+- if (!error) {
+- error = chown_common(nd.dentry, user, group);
+- path_release(&nd);
+- }
++ if (error)
++ goto out;
++ error = chown_common(nd.dentry, user, group);
++ path_release(&nd);
++out:
+ return error;
+ }
+
+@@ -755,10 +629,10 @@ asmlinkage long sys_fchownat(int dfd, co
+
+ follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
+ error = __user_walk_fd(dfd, filename, follow, &nd);
+- if (!error) {
+- error = chown_common(nd.dentry, user, group);
+- path_release(&nd);
+- }
++ if (error)
++ goto out;
++ error = chown_common(nd.dentry, user, group);
++ path_release(&nd);
+ out:
+ return error;
+ }
+@@ -769,10 +643,11 @@ asmlinkage long sys_lchown(const char __
+ int error;
+
+ error = user_path_walk_link(filename, &nd);
+- if (!error) {
+- error = chown_common(nd.dentry, user, group);
+- path_release(&nd);
+- }
++ if (error)
++ goto out;
++ error = chown_common(nd.dentry, user, group);
++ path_release(&nd);
++out:
+ return error;
+ }
+
+@@ -781,15 +656,17 @@ asmlinkage long sys_fchown(unsigned int
+ {
+ struct file * file;
+ int error = -EBADF;
++ struct dentry * dentry;
+
+ file = fget(fd);
+- if (file) {
+- struct dentry * dentry;
+- dentry = file->f_dentry;
+- audit_inode(NULL, dentry->d_inode);
+- error = chown_common(dentry, user, group);
+- fput(file);
+- }
++ if (!file)
++ goto out;
++
++ dentry = file->f_dentry;
++ audit_inode(NULL, dentry->d_inode);
++ error = chown_common(dentry, user, group);
++ fput(file);
++out:
+ return error;
+ }
+
+@@ -1172,6 +1049,7 @@ asmlinkage long sys_close(unsigned int f
+ struct file * filp;
+ struct files_struct *files = current->files;
+ struct fdtable *fdt;
++ int retval;
+
+ spin_lock(&files->file_lock);
+ fdt = files_fdtable(files);
+@@ -1184,7 +1062,16 @@ asmlinkage long sys_close(unsigned int f
+ FD_CLR(fd, fdt->close_on_exec);
+ __put_unused_fd(files, fd);
+ spin_unlock(&files->file_lock);
+- return filp_close(filp, files);
++ retval = filp_close(filp, files);
++
++ /* can't restart close syscall because file table entry was cleared */
++ if (unlikely(retval == -ERESTARTSYS ||
++ retval == -ERESTARTNOINTR ||
++ retval == -ERESTARTNOHAND ||
++ retval == -ERESTART_RESTARTBLOCK))
++ retval = -EINTR;
++
++ return retval;
+
+ out_unlock:
+ spin_unlock(&files->file_lock);
+diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
+index 93a56bd..592a640 100644
+--- a/fs/openpromfs/inode.c
++++ b/fs/openpromfs/inode.c
+@@ -8,10 +8,10 @@
+ #include <linux/types.h>
+ #include <linux/string.h>
+ #include <linux/fs.h>
+-#include <linux/openprom_fs.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/seq_file.h>
++#include <linux/magic.h>
+
+ #include <asm/openprom.h>
+ #include <asm/oplib.h>
+diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
+index d713ce6..67e665f 100644
+--- a/fs/partitions/Makefile
++++ b/fs/partitions/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the linux kernel.
+ #
+
+-obj-y := check.o
++obj-$(CONFIG_BLOCK) := check.o
+
+ obj-$(CONFIG_ACORN_PARTITION) += acorn.o
+ obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
+diff --git a/fs/partitions/check.c b/fs/partitions/check.c
+index 51c6a74..6fb4b61 100644
+--- a/fs/partitions/check.c
++++ b/fs/partitions/check.c
+@@ -376,18 +376,48 @@ static char *make_block_name(struct gend
+ return name;
+ }
+
+-static void disk_sysfs_symlinks(struct gendisk *disk)
++static int disk_sysfs_symlinks(struct gendisk *disk)
+ {
+ struct device *target = get_device(disk->driverfs_dev);
++ int err;
++ char *disk_name = NULL;
++
+ if (target) {
+- char *disk_name = make_block_name(disk);
+- sysfs_create_link(&disk->kobj,&target->kobj,"device");
+- if (disk_name) {
+- sysfs_create_link(&target->kobj,&disk->kobj,disk_name);
+- kfree(disk_name);
++ disk_name = make_block_name(disk);
++ if (!disk_name) {
++ err = -ENOMEM;
++ goto err_out;
+ }
++
++ err = sysfs_create_link(&disk->kobj, &target->kobj, "device");
++ if (err)
++ goto err_out_disk_name;
++
++ err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);
++ if (err)
++ goto err_out_dev_link;
+ }
+- sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, "subsystem");
++
++ err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj,
++ "subsystem");
++ if (err)
++ goto err_out_disk_name_lnk;
++
++ kfree(disk_name);
++
++ return 0;
++
++err_out_disk_name_lnk:
++ if (target) {
++ sysfs_remove_link(&target->kobj, disk_name);
++err_out_dev_link:
++ sysfs_remove_link(&disk->kobj, "device");
++err_out_disk_name:
++ kfree(disk_name);
++err_out:
++ put_device(target);
++ }
++ return err;
+ }
+
+ /* Not exported, helper to add_disk(). */
+@@ -406,7 +436,11 @@ void register_disk(struct gendisk *disk)
+ *s = '!';
+ if ((err = kobject_add(&disk->kobj)))
+ return;
+- disk_sysfs_symlinks(disk);
++ err = disk_sysfs_symlinks(disk);
++ if (err) {
++ kobject_del(&disk->kobj);
++ return;
++ }
+ disk_sysfs_add_subdirs(disk);
+
+ /* No minors to use for partitions */
+diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
+index 6373028..1bea610 100644
+--- a/fs/partitions/efi.c
++++ b/fs/partitions/efi.c
+@@ -238,10 +238,9 @@ alloc_read_gpt_entries(struct block_devi
+ le32_to_cpu(gpt->sizeof_partition_entry);
+ if (!count)
+ return NULL;
+- pte = kmalloc(count, GFP_KERNEL);
++ pte = kzalloc(count, GFP_KERNEL);
+ if (!pte)
+ return NULL;
+- memset(pte, 0, count);
+
+ if (read_lba(bdev, le64_to_cpu(gpt->partition_entry_lba),
+ (u8 *) pte,
+@@ -269,10 +268,9 @@ alloc_read_gpt_header(struct block_devic
+ if (!bdev)
+ return NULL;
+
+- gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL);
++ gpt = kzalloc(sizeof (gpt_header), GFP_KERNEL);
+ if (!gpt)
+ return NULL;
+- memset(gpt, 0, sizeof (gpt_header));
+
+ if (read_lba(bdev, lba, (u8 *) gpt,
+ sizeof (gpt_header)) < sizeof (gpt_header)) {
+@@ -526,9 +524,8 @@ find_valid_gpt(struct block_device *bdev
+ lastlba = last_lba(bdev);
+ if (!force_gpt) {
+ /* This will be added to the EFI Spec. per Intel after v1.02. */
+- legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
++ legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
+ if (legacymbr) {
+- memset(legacymbr, 0, sizeof (*legacymbr));
+ read_lba(bdev, 0, (u8 *) legacymbr,
+ sizeof (*legacymbr));
+ good_pmbr = is_pmbr_valid(legacymbr, lastlba);
+diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
+index 7ab1c11..1a60926 100644
+--- a/fs/partitions/ldm.c
++++ b/fs/partitions/ldm.c
+@@ -30,11 +30,6 @@
+ #include "check.h"
+ #include "msdos.h"
+
+-typedef enum {
+- FALSE = 0,
+- TRUE = 1
+-} BOOL;
+-
+ /**
+ * ldm_debug/info/error/crit - Output an error message
+ * @f: A printf format string containing the message
+@@ -103,24 +98,24 @@ static int ldm_parse_hexbyte (const u8 *
+ *
+ * N.B. The GUID need not be NULL terminated.
+ *
+- * Return: TRUE @dest contains binary GUID
+- * FALSE @dest contents are undefined
++ * Return: 'true' @dest contains binary GUID
++ * 'false' @dest contents are undefined
+ */
+-static BOOL ldm_parse_guid (const u8 *src, u8 *dest)
++static bool ldm_parse_guid (const u8 *src, u8 *dest)
+ {
+ static const int size[] = { 4, 2, 2, 2, 6 };
+ int i, j, v;
+
+ if (src[8] != '-' || src[13] != '-' ||
+ src[18] != '-' || src[23] != '-')
+- return FALSE;
++ return false;
+
+ for (j = 0; j < 5; j++, src++)
+ for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
+ if ((v = ldm_parse_hexbyte (src)) < 0)
+- return FALSE;
++ return false;
+
+- return TRUE;
++ return true;
+ }
+
+
+@@ -132,17 +127,17 @@ static BOOL ldm_parse_guid (const u8 *sr
+ * This parses the LDM database PRIVHEAD structure supplied in @data and
+ * sets up the in-memory privhead structure @ph with the obtained information.
+ *
+- * Return: TRUE @ph contains the PRIVHEAD data
+- * FALSE @ph contents are undefined
++ * Return: 'true' @ph contains the PRIVHEAD data
++ * 'false' @ph contents are undefined
+ */
+-static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
++static bool ldm_parse_privhead (const u8 *data, struct privhead *ph)
+ {
+ BUG_ON (!data || !ph);
+
+ if (MAGIC_PRIVHEAD != BE64 (data)) {
+ ldm_error ("Cannot find PRIVHEAD structure. LDM database is"
+ " corrupt. Aborting.");
+- return FALSE;
++ return false;
+ }
+
+ ph->ver_major = BE16 (data + 0x000C);
+@@ -155,7 +150,7 @@ static BOOL ldm_parse_privhead (const u8
+ if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
+ ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d."
+ " Aborting.", 2, 11, ph->ver_major, ph->ver_minor);
+- return FALSE;
++ return false;
+ }
+ if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
+ /* Warn the user and continue, carefully */
+@@ -166,16 +161,16 @@ static BOOL ldm_parse_privhead (const u8
+ if ((ph->logical_disk_size == 0) ||
+ (ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) {
+ ldm_error ("PRIVHEAD disk size doesn't match real disk size");
+- return FALSE;
++ return false;
+ }
+
+ if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) {
+ ldm_error ("PRIVHEAD contains an invalid GUID.");
+- return FALSE;
++ return false;
+ }
+
+ ldm_debug ("Parsed PRIVHEAD successfully.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -189,16 +184,16 @@ static BOOL ldm_parse_privhead (const u8
+ *
+ * N.B. The *_start and *_size values returned in @toc are not range-checked.
+ *
+- * Return: TRUE @toc contains the TOCBLOCK data
+- * FALSE @toc contents are undefined
++ * Return: 'true' @toc contains the TOCBLOCK data
++ * 'false' @toc contents are undefined
+ */
+-static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
++static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
+ {
+ BUG_ON (!data || !toc);
+
+ if (MAGIC_TOCBLOCK != BE64 (data)) {
+ ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
+- return FALSE;
++ return false;
+ }
+ strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
+ toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
+@@ -209,7 +204,7 @@ static BOOL ldm_parse_tocblock (const u8
+ sizeof (toc->bitmap1_name)) != 0) {
+ ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
+ TOC_BITMAP1, toc->bitmap1_name);
+- return FALSE;
++ return false;
+ }
+ strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
+ toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
+@@ -219,10 +214,10 @@ static BOOL ldm_parse_tocblock (const u8
+ sizeof (toc->bitmap2_name)) != 0) {
+ ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
+ TOC_BITMAP2, toc->bitmap2_name);
+- return FALSE;
++ return false;
+ }
+ ldm_debug ("Parsed TOCBLOCK successfully.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -235,16 +230,16 @@ static BOOL ldm_parse_tocblock (const u8
+ *
+ * N.B. The *_start, *_size and *_seq values will be range-checked later.
+ *
+- * Return: TRUE @vm contains VMDB info
+- * FALSE @vm contents are undefined
++ * Return: 'true' @vm contains VMDB info
++ * 'false' @vm contents are undefined
+ */
+-static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
++static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
+ {
+ BUG_ON (!data || !vm);
+
+ if (MAGIC_VMDB != BE32 (data)) {
+ ldm_crit ("Cannot find the VMDB, database may be corrupt.");
+- return FALSE;
++ return false;
+ }
+
+ vm->ver_major = BE16 (data + 0x12);
+@@ -252,7 +247,7 @@ static BOOL ldm_parse_vmdb (const u8 *da
+ if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
+ ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
+ "Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
+- return FALSE;
++ return false;
+ }
+
+ vm->vblk_size = BE32 (data + 0x08);
+@@ -260,7 +255,7 @@ static BOOL ldm_parse_vmdb (const u8 *da
+ vm->last_vblk_seq = BE32 (data + 0x04);
+
+ ldm_debug ("Parsed VMDB successfully.");
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -270,10 +265,10 @@ static BOOL ldm_parse_vmdb (const u8 *da
+ *
+ * This compares the two privhead structures @ph1 and @ph2.
+ *
+- * Return: TRUE Identical
+- * FALSE Different
++ * Return: 'true' Identical
++ * 'false' Different
+ */
+-static BOOL ldm_compare_privheads (const struct privhead *ph1,
++static bool ldm_compare_privheads (const struct privhead *ph1,
+ const struct privhead *ph2)
+ {
+ BUG_ON (!ph1 || !ph2);
+@@ -294,10 +289,10 @@ static BOOL ldm_compare_privheads (const
+ *
+ * This compares the two tocblock structures @toc1 and @toc2.
+ *
+- * Return: TRUE Identical
+- * FALSE Different
++ * Return: 'true' Identical
++ * 'false' Different
+ */
+-static BOOL ldm_compare_tocblocks (const struct tocblock *toc1,
++static bool ldm_compare_tocblocks (const struct tocblock *toc1,
+ const struct tocblock *toc2)
+ {
+ BUG_ON (!toc1 || !toc2);
+@@ -323,17 +318,17 @@ static BOOL ldm_compare_tocblocks (const
+ * the configuration area (the database). The values are range-checked against
+ * @hd, which contains the real size of the disk.
+ *
+- * Return: TRUE Success
+- * FALSE Error
++ * Return: 'true' Success
++ * 'false' Error
+ */
+-static BOOL ldm_validate_privheads (struct block_device *bdev,
++static bool ldm_validate_privheads (struct block_device *bdev,
+ struct privhead *ph1)
+ {
+ static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
+ struct privhead *ph[3] = { ph1 };
+ Sector sect;
+ u8 *data;
+- BOOL result = FALSE;
++ bool result = false;
+ long num_sects;
+ int i;
+
+@@ -393,7 +388,7 @@ static BOOL ldm_validate_privheads (stru
+ goto out;
+ }*/
+ ldm_debug ("Validated PRIVHEADs successfully.");
+- result = TRUE;
++ result = true;
+ out:
+ kfree (ph[1]);
+ kfree (ph[2]);
+@@ -411,10 +406,10 @@ out:
+ *
+ * The offsets and sizes of the configs are range-checked against a privhead.
+ *
+- * Return: TRUE @toc1 contains validated TOCBLOCK info
+- * FALSE @toc1 contents are undefined
++ * Return: 'true' @toc1 contains validated TOCBLOCK info
++ * 'false' @toc1 contents are undefined
+ */
+-static BOOL ldm_validate_tocblocks (struct block_device *bdev,
++static bool ldm_validate_tocblocks (struct block_device *bdev,
+ unsigned long base, struct ldmdb *ldb)
+ {
+ static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
+@@ -422,7 +417,7 @@ static BOOL ldm_validate_tocblocks (stru
+ struct privhead *ph;
+ Sector sect;
+ u8 *data;
+- BOOL result = FALSE;
++ bool result = false;
+ int i;
+
+ BUG_ON (!bdev || !ldb);
+@@ -465,7 +460,7 @@ static BOOL ldm_validate_tocblocks (stru
+ }
+
+ ldm_debug ("Validated TOCBLOCKs successfully.");
+- result = TRUE;
++ result = true;
+ out:
+ kfree (tb[1]);
+ kfree (tb[2]);
+@@ -482,15 +477,15 @@ out:
+ * Find the vmdb of the LDM Database stored on @bdev and return the parsed
+ * information in @ldb.
+ *
+- * Return: TRUE @ldb contains validated VBDB info
+- * FALSE @ldb contents are undefined
++ * Return: 'true' @ldb contains validated VBDB info
++ * 'false' @ldb contents are undefined
+ */
+-static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
++static bool ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
+ struct ldmdb *ldb)
+ {
+ Sector sect;
+ u8 *data;
+- BOOL result = FALSE;
++ bool result = false;
+ struct vmdb *vm;
+ struct tocblock *toc;
+
+@@ -502,7 +497,7 @@ static BOOL ldm_validate_vmdb (struct bl
+ data = read_dev_sector (bdev, base + OFF_VMDB, §);
+ if (!data) {
+ ldm_crit ("Disk read failed.");
+- return FALSE;
++ return false;
+ }
+
+ if (!ldm_parse_vmdb (data, vm))
+@@ -527,7 +522,7 @@ static BOOL ldm_validate_vmdb (struct bl
+ goto out;
+ }
+
+- result = TRUE;
++ result = true;
+ out:
+ put_dev_sector (sect);
+ return result;
+@@ -547,23 +542,23 @@ out:
+ * only likely to happen if the underlying device is strange. If that IS
+ * the case we should return zero to let someone else try.
+ *
+- * Return: TRUE @bdev is a dynamic disk
+- * FALSE @bdev is not a dynamic disk, or an error occurred
++ * Return: 'true' @bdev is a dynamic disk
++ * 'false' @bdev is not a dynamic disk, or an error occurred
+ */
+-static BOOL ldm_validate_partition_table (struct block_device *bdev)
++static bool ldm_validate_partition_table (struct block_device *bdev)
+ {
+ Sector sect;
+ u8 *data;
+ struct partition *p;
+ int i;
+- BOOL result = FALSE;
++ bool result = false;
+
+ BUG_ON (!bdev);
+
+ data = read_dev_sector (bdev, 0, §);
+ if (!data) {
+ ldm_crit ("Disk read failed.");
+- return FALSE;
++ return false;
+ }
+
+ if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
+@@ -572,7 +567,7 @@ static BOOL ldm_validate_partition_table
+ p = (struct partition*)(data + 0x01BE);
+ for (i = 0; i < 4; i++, p++)
+ if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) {
+- result = TRUE;
++ result = true;
+ break;
+ }
+
+@@ -625,10 +620,10 @@ static struct vblk * ldm_get_disk_objid
+ * N.B. This function creates the partitions in the order it finds partition
+ * objects in the linked list.
+ *
+- * Return: TRUE Partition created
+- * FALSE Error, probably a range checking problem
++ * Return: 'true' Partition created
++ * 'false' Error, probably a range checking problem
+ */
+-static BOOL ldm_create_data_partitions (struct parsed_partitions *pp,
++static bool ldm_create_data_partitions (struct parsed_partitions *pp,
+ const struct ldmdb *ldb)
+ {
+ struct list_head *item;
+@@ -642,7 +637,7 @@ static BOOL ldm_create_data_partitions (
+ disk = ldm_get_disk_objid (ldb);
+ if (!disk) {
+ ldm_crit ("Can't find the ID of this disk in the database.");
+- return FALSE;
++ return false;
+ }
+
+ printk (" [LDM]");
+@@ -661,7 +656,7 @@ static BOOL ldm_create_data_partitions (
+ }
+
+ printk ("\n");
+- return TRUE;
++ return true;
+ }
+
+
+@@ -766,10 +761,10 @@ static int ldm_get_vstr (const u8 *block
+ *
+ * Read a raw VBLK Component object (version 3) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Component VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Component VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
++static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+ int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
+ struct vblk_comp *comp;
+@@ -792,11 +787,11 @@ static BOOL ldm_parse_cmp3 (const u8 *bu
+ len = r_parent;
+ }
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_CMP3;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ comp = &vb->vblk.comp;
+ ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
+@@ -806,7 +801,7 @@ static BOOL ldm_parse_cmp3 (const u8 *bu
+ comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
+ comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
+
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -817,8 +812,8 @@ static BOOL ldm_parse_cmp3 (const u8 *bu
+ *
+ * Read a raw VBLK Disk Group object (version 3) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Disk Group VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Disk Group VBLK
++ * 'false' @vb contents are not defined
+ */
+ static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+@@ -841,16 +836,16 @@ static int ldm_parse_dgr3 (const u8 *buf
+ len = r_diskid;
+ }
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_DGR3;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ dgrp = &vb->vblk.dgrp;
+ ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
+ sizeof (dgrp->disk_id));
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -861,10 +856,10 @@ static int ldm_parse_dgr3 (const u8 *buf
+ *
+ * Read a raw VBLK Disk Group object (version 4) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Disk Group VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Disk Group VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
++static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+ char buf[64];
+ int r_objid, r_name, r_id1, r_id2, len;
+@@ -885,16 +880,16 @@ static BOOL ldm_parse_dgr4 (const u8 *bu
+ len = r_name;
+ }
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_DGR4;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ dgrp = &vb->vblk.dgrp;
+
+ ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -905,10 +900,10 @@ static BOOL ldm_parse_dgr4 (const u8 *bu
+ *
+ * Read a raw VBLK Disk object (version 3) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Disk VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Disk VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
++static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+ int r_objid, r_name, r_diskid, r_altname, len;
+ struct vblk_disk *disk;
+@@ -921,19 +916,19 @@ static BOOL ldm_parse_dsk3 (const u8 *bu
+ r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
+ len = r_altname;
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_DSK3;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ disk = &vb->vblk.disk;
+ ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
+ sizeof (disk->alt_name));
+ if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
+- return FALSE;
++ return false;
+
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -944,10 +939,10 @@ static BOOL ldm_parse_dsk3 (const u8 *bu
+ *
+ * Read a raw VBLK Disk object (version 4) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Disk VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Disk VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
++static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+ int r_objid, r_name, len;
+ struct vblk_disk *disk;
+@@ -958,15 +953,15 @@ static BOOL ldm_parse_dsk4 (const u8 *bu
+ r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
+ len = r_name;
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_DSK4;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ disk = &vb->vblk.disk;
+ memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -977,10 +972,10 @@ static BOOL ldm_parse_dsk4 (const u8 *bu
+ *
+ * Read a raw VBLK Partition object (version 3) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Partition VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Partition VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
++static bool ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+ int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
+ struct vblk_part *part;
+@@ -1001,11 +996,11 @@ static BOOL ldm_parse_prt3 (const u8 *bu
+ len = r_diskid;
+ }
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_PRT3;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ part = &vb->vblk.part;
+ part->start = BE64 (buffer + 0x24 + r_name);
+@@ -1018,7 +1013,7 @@ static BOOL ldm_parse_prt3 (const u8 *bu
+ else
+ part->partnum = 0;
+
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -1029,10 +1024,10 @@ static BOOL ldm_parse_prt3 (const u8 *bu
+ *
+ * Read a raw VBLK Volume object (version 5) into a vblk structure.
+ *
+- * Return: TRUE @vb contains a Volume VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a Volume VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
++static bool ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
+ {
+ int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2;
+ int r_drive, len;
+@@ -1068,11 +1063,11 @@ static BOOL ldm_parse_vol5 (const u8 *bu
+
+ len = r_drive;
+ if (len < 0)
+- return FALSE;
++ return false;
+
+ len += VBLK_SIZE_VOL5;
+ if (len != BE32 (buffer + 0x14))
+- return FALSE;
++ return false;
+
+ volu = &vb->vblk.volu;
+
+@@ -1087,7 +1082,7 @@ static BOOL ldm_parse_vol5 (const u8 *bu
+ ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint,
+ sizeof (volu->drive_hint));
+ }
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -1100,12 +1095,12 @@ static BOOL ldm_parse_vol5 (const u8 *bu
+ * information common to all VBLK types, then delegates the rest of the work to
+ * helper functions: ldm_parse_*.
+ *
+- * Return: TRUE @vb contains a VBLK
+- * FALSE @vb contents are not defined
++ * Return: 'true' @vb contains a VBLK
++ * 'false' @vb contents are not defined
+ */
+-static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
++static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
+ {
+- BOOL result = FALSE;
++ bool result = false;
+ int r_objid;
+
+ BUG_ON (!buf || !vb);
+@@ -1113,7 +1108,7 @@ static BOOL ldm_parse_vblk (const u8 *bu
+ r_objid = ldm_relative (buf, len, 0x18, 0);
+ if (r_objid < 0) {
+ ldm_error ("VBLK header is corrupt.");
+- return FALSE;
++ return false;
+ }
+
+ vb->flags = buf[0x12];
+@@ -1152,10 +1147,10 @@ static BOOL ldm_parse_vblk (const u8 *bu
+ *
+ * N.B. This function does not check the validity of the VBLKs.
+ *
+- * Return: TRUE The VBLK was added
+- * FALSE An error occurred
++ * Return: 'true' The VBLK was added
++ * 'false' An error occurred
+ */
+-static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
++static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
+ {
+ struct vblk *vb;
+ struct list_head *item;
+@@ -1165,12 +1160,12 @@ static BOOL ldm_ldmdb_add (u8 *data, int
+ vb = kmalloc (sizeof (*vb), GFP_KERNEL);
+ if (!vb) {
+ ldm_crit ("Out of memory.");
+- return FALSE;
++ return false;
+ }
+
+ if (!ldm_parse_vblk (data, len, vb)) {
+ kfree(vb);
+- return FALSE; /* Already logged */
++ return false; /* Already logged */
+ }
+
+ /* Put vblk into the correct list. */
+@@ -1196,13 +1191,13 @@ static BOOL ldm_ldmdb_add (u8 *data, int
+ if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
+ (v->vblk.part.start > vb->vblk.part.start)) {
+ list_add_tail (&vb->list, &v->list);
+- return TRUE;
++ return true;
+ }
+ }
+ list_add_tail (&vb->list, &ldb->v_part);
+ break;
+ }
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -1214,10 +1209,10 @@ static BOOL ldm_ldmdb_add (u8 *data, int
+ * Fragmented VBLKs may not be consecutive in the database, so they are placed
+ * in a list so they can be pieced together later.
+ *
+- * Return: TRUE Success, the VBLK was added to the list
+- * FALSE Error, a problem occurred
++ * Return: 'true' Success, the VBLK was added to the list
++ * 'false' Error, a problem occurred
+ */
+-static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
++static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
+ {
+ struct frag *f;
+ struct list_head *item;
+@@ -1230,7 +1225,7 @@ static BOOL ldm_frag_add (const u8 *data
+ num = BE16 (data + 0x0E);
+ if ((num < 1) || (num > 4)) {
+ ldm_error ("A VBLK claims to have %d parts.", num);
+- return FALSE;
++ return false;
+ }
+
+ list_for_each (item, frags) {
+@@ -1242,7 +1237,7 @@ static BOOL ldm_frag_add (const u8 *data
+ f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
+ if (!f) {
+ ldm_crit ("Out of memory.");
+- return FALSE;
++ return false;
+ }
+
+ f->group = group;
+@@ -1255,7 +1250,7 @@ found:
+ if (f->map & (1 << rec)) {
+ ldm_error ("Duplicate VBLK, part %d.", rec);
+ f->map &= 0x7F; /* Mark the group as broken */
+- return FALSE;
++ return false;
+ }
+
+ f->map |= (1 << rec);
+@@ -1266,7 +1261,7 @@ found:
+ }
+ memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
+
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -1295,10 +1290,10 @@ static void ldm_frag_free (struct list_h
+ * Now that all the fragmented VBLKs have been collected, they must be added to
+ * the database for later use.
+ *
+- * Return: TRUE All the fragments we added successfully
+- * FALSE One or more of the fragments we invalid
++ * Return: 'true' All the fragments we added successfully
++ * 'false' One or more of the fragments we invalid
+ */
+-static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
++static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
+ {
+ struct frag *f;
+ struct list_head *item;
+@@ -1311,13 +1306,13 @@ static BOOL ldm_frag_commit (struct list
+ if (f->map != 0xFF) {
+ ldm_error ("VBLK group %d is incomplete (0x%02x).",
+ f->group, f->map);
+- return FALSE;
++ return false;
+ }
+
+ if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
+- return FALSE; /* Already logged */
++ return false; /* Already logged */
+ }
+- return TRUE;
++ return true;
+ }
+
+ /**
+@@ -1329,16 +1324,16 @@ static BOOL ldm_frag_commit (struct list
+ * To use the information from the VBLKs, they need to be read from the disk,
+ * unpacked and validated. We cache them in @ldb according to their type.
+ *
+- * Return: TRUE All the VBLKs were read successfully
+- * FALSE An error occurred
++ * Return: 'true' All the VBLKs were read successfully
++ * 'false' An error occurred
+ */
+-static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base,
++static bool ldm_get_vblks (struct block_device *bdev, unsigned long base,
+ struct ldmdb *ldb)
+ {
+ int size, perbuf, skip, finish, s, v, recs;
+ u8 *data = NULL;
+ Sector sect;
+- BOOL result = FALSE;
++ bool result = false;
+ LIST_HEAD (frags);
+
+ BUG_ON (!bdev || !ldb);
+diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
+index 8f12587..8c7af17 100644
+--- a/fs/partitions/msdos.c
++++ b/fs/partitions/msdos.c
+@@ -32,13 +32,11 @@
+ #include <asm/unaligned.h>
+
+ #define SYS_IND(p) (get_unaligned(&p->sys_ind))
+-#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
+- get_unaligned(&p->nr_sects); \
++#define NR_SECTS(p) ({ __le32 __a = get_unaligned(&p->nr_sects); \
+ le32_to_cpu(__a); \
+ })
+
+-#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
+- get_unaligned(&p->start_sect); \
++#define START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \
+ le32_to_cpu(__a); \
+ })
+
+@@ -58,6 +56,31 @@ msdos_magic_present(unsigned char *p)
+ return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
+ }
+
++/* Value is EBCDIC 'IBMA' */
++#define AIX_LABEL_MAGIC1 0xC9
++#define AIX_LABEL_MAGIC2 0xC2
++#define AIX_LABEL_MAGIC3 0xD4
++#define AIX_LABEL_MAGIC4 0xC1
++static int aix_magic_present(unsigned char *p, struct block_device *bdev)
++{
++ Sector sect;
++ unsigned char *d;
++ int ret = 0;
++
++ if (p[0] != AIX_LABEL_MAGIC1 &&
++ p[1] != AIX_LABEL_MAGIC2 &&
++ p[2] != AIX_LABEL_MAGIC3 &&
++ p[3] != AIX_LABEL_MAGIC4)
++ return 0;
++ d = read_dev_sector(bdev, 7, §);
++ if (d) {
++ if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
++ ret = 1;
++ put_dev_sector(sect);
++ };
++ return ret;
++}
++
+ /*
+ * Create devices for each logical partition in an extended partition.
+ * The logical partitions form a linked list, with each entry being
+@@ -393,6 +416,12 @@ int msdos_partition(struct parsed_partit
+ return 0;
+ }
+
++ if (aix_magic_present(data, bdev)) {
++ put_dev_sector(sect);
++ printk( " [AIX]");
++ return 0;
++ }
++
+ /*
+ * Now that the 55aa signature is present, this is probably
+ * either the boot sector of a FAT filesystem or a DOS-type
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 2035257..b1626f2 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -218,9 +218,10 @@ static struct pipe_buf_operations anon_p
+ };
+
+ static ssize_t
+-pipe_readv(struct file *filp, const struct iovec *_iov,
+- unsigned long nr_segs, loff_t *ppos)
++pipe_read(struct kiocb *iocb, const struct iovec *_iov,
++ unsigned long nr_segs, loff_t pos)
+ {
++ struct file *filp = iocb->ki_filp;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct pipe_inode_info *pipe;
+ int do_wakeup;
+@@ -330,17 +331,10 @@ redo:
+ }
+
+ static ssize_t
+-pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
+-{
+- struct iovec iov = { .iov_base = buf, .iov_len = count };
+-
+- return pipe_readv(filp, &iov, 1, ppos);
+-}
+-
+-static ssize_t
+-pipe_writev(struct file *filp, const struct iovec *_iov,
+- unsigned long nr_segs, loff_t *ppos)
++pipe_write(struct kiocb *iocb, const struct iovec *_iov,
++ unsigned long nr_segs, loff_t ppos)
+ {
++ struct file *filp = iocb->ki_filp;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct pipe_inode_info *pipe;
+ ssize_t ret;
+@@ -510,15 +504,6 @@ out:
+ }
+
+ static ssize_t
+-pipe_write(struct file *filp, const char __user *buf,
+- size_t count, loff_t *ppos)
+-{
+- struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
+-
+- return pipe_writev(filp, &iov, 1, ppos);
+-}
+-
+-static ssize_t
+ bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
+ {
+ return -EBADF;
+@@ -736,8 +721,8 @@ pipe_rdwr_open(struct inode *inode, stru
+ */
+ const struct file_operations read_fifo_fops = {
+ .llseek = no_llseek,
+- .read = pipe_read,
+- .readv = pipe_readv,
++ .read = do_sync_read,
++ .aio_read = pipe_read,
+ .write = bad_pipe_w,
+ .poll = pipe_poll,
+ .ioctl = pipe_ioctl,
+@@ -749,8 +734,8 @@ const struct file_operations read_fifo_f
+ const struct file_operations write_fifo_fops = {
+ .llseek = no_llseek,
+ .read = bad_pipe_r,
+- .write = pipe_write,
+- .writev = pipe_writev,
++ .write = do_sync_write,
++ .aio_write = pipe_write,
+ .poll = pipe_poll,
+ .ioctl = pipe_ioctl,
+ .open = pipe_write_open,
+@@ -760,10 +745,10 @@ const struct file_operations write_fifo_
+
+ const struct file_operations rdwr_fifo_fops = {
+ .llseek = no_llseek,
+- .read = pipe_read,
+- .readv = pipe_readv,
+- .write = pipe_write,
+- .writev = pipe_writev,
++ .read = do_sync_read,
++ .aio_read = pipe_read,
++ .write = do_sync_write,
++ .aio_write = pipe_write,
+ .poll = pipe_poll,
+ .ioctl = pipe_ioctl,
+ .open = pipe_rdwr_open,
+@@ -773,8 +758,8 @@ const struct file_operations rdwr_fifo_f
+
+ static struct file_operations read_pipe_fops = {
+ .llseek = no_llseek,
+- .read = pipe_read,
+- .readv = pipe_readv,
++ .read = do_sync_read,
++ .aio_read = pipe_read,
+ .write = bad_pipe_w,
+ .poll = pipe_poll,
+ .ioctl = pipe_ioctl,
+@@ -786,8 +771,8 @@ static struct file_operations read_pipe_
+ static struct file_operations write_pipe_fops = {
+ .llseek = no_llseek,
+ .read = bad_pipe_r,
+- .write = pipe_write,
+- .writev = pipe_writev,
++ .write = do_sync_write,
++ .aio_write = pipe_write,
+ .poll = pipe_poll,
+ .ioctl = pipe_ioctl,
+ .open = pipe_write_open,
+@@ -797,10 +782,10 @@ static struct file_operations write_pipe
+
+ static struct file_operations rdwr_pipe_fops = {
+ .llseek = no_llseek,
+- .read = pipe_read,
+- .readv = pipe_readv,
+- .write = pipe_write,
+- .writev = pipe_writev,
++ .read = do_sync_read,
++ .aio_read = pipe_read,
++ .write = do_sync_write,
++ .aio_write = pipe_write,
+ .poll = pipe_poll,
+ .ioctl = pipe_ioctl,
+ .open = pipe_rdwr_open,
+@@ -879,7 +864,6 @@ static struct inode * get_pipe_inode(voi
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+- inode->i_blksize = PAGE_SIZE;
+
+ return inode;
+
+@@ -890,87 +874,118 @@ fail_inode:
+ return NULL;
+ }
+
+-int do_pipe(int *fd)
++struct file *create_write_pipe(void)
+ {
+- struct qstr this;
+- char name[32];
++ int err;
++ struct inode *inode;
++ struct file *f;
+ struct dentry *dentry;
+- struct inode * inode;
+- struct file *f1, *f2;
+- int error;
+- int i, j;
+-
+- error = -ENFILE;
+- f1 = get_empty_filp();
+- if (!f1)
+- goto no_files;
+-
+- f2 = get_empty_filp();
+- if (!f2)
+- goto close_f1;
++ char name[32];
++ struct qstr this;
+
++ f = get_empty_filp();
++ if (!f)
++ return ERR_PTR(-ENFILE);
++ err = -ENFILE;
+ inode = get_pipe_inode();
+ if (!inode)
+- goto close_f12;
+-
+- error = get_unused_fd();
+- if (error < 0)
+- goto close_f12_inode;
+- i = error;
+-
+- error = get_unused_fd();
+- if (error < 0)
+- goto close_f12_inode_i;
+- j = error;
++ goto err_file;
+
+- error = -ENOMEM;
+ sprintf(name, "[%lu]", inode->i_ino);
+ this.name = name;
+ this.len = strlen(name);
+ this.hash = inode->i_ino; /* will go */
++ err = -ENOMEM;
+ dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
+ if (!dentry)
+- goto close_f12_inode_i_j;
++ goto err_inode;
+
+ dentry->d_op = &pipefs_dentry_operations;
+ d_add(dentry, inode);
+- f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
+- f1->f_dentry = f2->f_dentry = dget(dentry);
+- f1->f_mapping = f2->f_mapping = inode->i_mapping;
+-
+- /* read file */
+- f1->f_pos = f2->f_pos = 0;
+- f1->f_flags = O_RDONLY;
+- f1->f_op = &read_pipe_fops;
+- f1->f_mode = FMODE_READ;
+- f1->f_version = 0;
+-
+- /* write file */
+- f2->f_flags = O_WRONLY;
+- f2->f_op = &write_pipe_fops;
+- f2->f_mode = FMODE_WRITE;
+- f2->f_version = 0;
+-
+- fd_install(i, f1);
+- fd_install(j, f2);
+- fd[0] = i;
+- fd[1] = j;
++ f->f_vfsmnt = mntget(pipe_mnt);
++ f->f_dentry = dentry;
++ f->f_mapping = inode->i_mapping;
+
+- return 0;
++ f->f_flags = O_WRONLY;
++ f->f_op = &write_pipe_fops;
++ f->f_mode = FMODE_WRITE;
++ f->f_version = 0;
++
++ return f;
+
+-close_f12_inode_i_j:
+- put_unused_fd(j);
+-close_f12_inode_i:
+- put_unused_fd(i);
+-close_f12_inode:
++ err_inode:
+ free_pipe_info(inode);
+ iput(inode);
+-close_f12:
+- put_filp(f2);
+-close_f1:
+- put_filp(f1);
+-no_files:
+- return error;
++ err_file:
++ put_filp(f);
++ return ERR_PTR(err);
++}
++
++void free_write_pipe(struct file *f)
++{
++ mntput(f->f_vfsmnt);
++ dput(f->f_dentry);
++ put_filp(f);
++}
++
++struct file *create_read_pipe(struct file *wrf)
++{
++ struct file *f = get_empty_filp();
++ if (!f)
++ return ERR_PTR(-ENFILE);
++
++ /* Grab pipe from the writer */
++ f->f_vfsmnt = mntget(wrf->f_vfsmnt);
++ f->f_dentry = dget(wrf->f_dentry);
++ f->f_mapping = wrf->f_dentry->d_inode->i_mapping;
++
++ f->f_pos = 0;
++ f->f_flags = O_RDONLY;
++ f->f_op = &read_pipe_fops;
++ f->f_mode = FMODE_READ;
++ f->f_version = 0;
++
++ return f;
++}
++
++int do_pipe(int *fd)
++{
++ struct file *fw, *fr;
++ int error;
++ int fdw, fdr;
++
++ fw = create_write_pipe();
++ if (IS_ERR(fw))
++ return PTR_ERR(fw);
++ fr = create_read_pipe(fw);
++ error = PTR_ERR(fr);
++ if (IS_ERR(fr))
++ goto err_write_pipe;
++
++ error = get_unused_fd();
++ if (error < 0)
++ goto err_read_pipe;
++ fdr = error;
++
++ error = get_unused_fd();
++ if (error < 0)
++ goto err_fdr;
++ fdw = error;
++
++ fd_install(fdr, fr);
++ fd_install(fdw, fw);
++ fd[0] = fdr;
++ fd[1] = fdw;
++
++ return 0;
++
++ err_fdr:
++ put_unused_fd(fdr);
++ err_read_pipe:
++ put_filp(fr);
++ err_write_pipe:
++ free_write_pipe(fw);
++ return error;
+ }
+
+ /*
+diff --git a/fs/posix_acl.c b/fs/posix_acl.c
+index 6c8dcf7..aec931e 100644
+--- a/fs/posix_acl.c
++++ b/fs/posix_acl.c
+@@ -58,11 +58,9 @@ posix_acl_clone(const struct posix_acl *
+ if (acl) {
+ int size = sizeof(struct posix_acl) + acl->a_count *
+ sizeof(struct posix_acl_entry);
+- clone = kmalloc(size, flags);
+- if (clone) {
+- memcpy(clone, acl, size);
++ clone = kmemdup(acl, size, flags);
++ if (clone)
+ atomic_set(&clone->a_refcount, 1);
+- }
+ }
+ return clone;
+ }
+diff --git a/fs/proc/array.c b/fs/proc/array.c
+index 0b615d6..25e917f 100644
+--- a/fs/proc/array.c
++++ b/fs/proc/array.c
+@@ -162,7 +162,7 @@ static inline char * task_state(struct t
+ int g;
+ struct fdtable *fdt = NULL;
+
+- read_lock(&tasklist_lock);
++ rcu_read_lock();
+ buffer += sprintf(buffer,
+ "State:\t%s\n"
+ "SleepAVG:\t%lu%%\n"
+@@ -174,14 +174,13 @@ static inline char * task_state(struct t
+ "Gid:\t%d\t%d\t%d\t%d\n",
+ get_task_state(p),
+ (p->sleep_avg/1024)*100/(1020000000/1024),
+- p->tgid,
+- p->pid, pid_alive(p) ? p->group_leader->real_parent->tgid : 0,
+- pid_alive(p) && p->ptrace ? p->parent->pid : 0,
++ p->tgid, p->pid,
++ pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0,
++ pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0,
+ p->uid, p->euid, p->suid, p->fsuid,
+ p->gid, p->egid, p->sgid, p->fsgid);
+- read_unlock(&tasklist_lock);
++
+ task_lock(p);
+- rcu_read_lock();
+ if (p->files)
+ fdt = files_fdtable(p->files);
+ buffer += sprintf(buffer,
+@@ -244,6 +243,7 @@ static void collect_sigign_sigcatch(stru
+
+ static inline char * task_sig(struct task_struct *p, char *buffer)
+ {
++ unsigned long flags;
+ sigset_t pending, shpending, blocked, ignored, caught;
+ int num_threads = 0;
+ unsigned long qsize = 0;
+@@ -255,10 +255,8 @@ static inline char * task_sig(struct tas
+ sigemptyset(&ignored);
+ sigemptyset(&caught);
+
+- /* Gather all the data with the appropriate locks held */
+- read_lock(&tasklist_lock);
+- if (p->sighand) {
+- spin_lock_irq(&p->sighand->siglock);
++ rcu_read_lock();
++ if (lock_task_sighand(p, &flags)) {
+ pending = p->pending.signal;
+ shpending = p->signal->shared_pending.signal;
+ blocked = p->blocked;
+@@ -266,9 +264,9 @@ static inline char * task_sig(struct tas
+ num_threads = atomic_read(&p->signal->count);
+ qsize = atomic_read(&p->user->sigpending);
+ qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
+- spin_unlock_irq(&p->sighand->siglock);
++ unlock_task_sighand(p, &flags);
+ }
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+
+ buffer += sprintf(buffer, "Threads:\t%d\n", num_threads);
+ buffer += sprintf(buffer, "SigQ:\t%lu/%lu\n", qsize, qlim);
+@@ -322,7 +320,7 @@ static int do_task_stat(struct task_stru
+ sigset_t sigign, sigcatch;
+ char state;
+ int res;
+- pid_t ppid, pgid = -1, sid = -1;
++ pid_t ppid = 0, pgid = -1, sid = -1;
+ int num_threads = 0;
+ struct mm_struct *mm;
+ unsigned long long start_time;
+@@ -330,8 +328,8 @@ static int do_task_stat(struct task_stru
+ unsigned long min_flt = 0, maj_flt = 0;
+ cputime_t cutime, cstime, utime, stime;
+ unsigned long rsslim = 0;
+- struct task_struct *t;
+ char tcomm[sizeof(task->comm)];
++ unsigned long flags;
+
+ state = *get_task_state(task);
+ vsize = eip = esp = 0;
+@@ -347,15 +345,35 @@ static int do_task_stat(struct task_stru
+ sigemptyset(&sigign);
+ sigemptyset(&sigcatch);
+ cutime = cstime = utime = stime = cputime_zero;
+- read_lock(&tasklist_lock);
+- if (task->sighand) {
+- spin_lock_irq(&task->sighand->siglock);
+- num_threads = atomic_read(&task->signal->count);
++
++ mutex_lock(&tty_mutex);
++ rcu_read_lock();
++ if (lock_task_sighand(task, &flags)) {
++ struct signal_struct *sig = task->signal;
++ struct tty_struct *tty = sig->tty;
++
++ if (tty) {
++ /*
++ * sig->tty is not stable, but tty_mutex
++ * protects us from release_dev(tty)
++ */
++ barrier();
++ tty_pgrp = tty->pgrp;
++ tty_nr = new_encode_dev(tty_devnum(tty));
++ }
++
++ num_threads = atomic_read(&sig->count);
+ collect_sigign_sigcatch(task, &sigign, &sigcatch);
+
++ cmin_flt = sig->cmin_flt;
++ cmaj_flt = sig->cmaj_flt;
++ cutime = sig->cutime;
++ cstime = sig->cstime;
++ rsslim = sig->rlim[RLIMIT_RSS].rlim_cur;
++
+ /* add up live thread stats at the group level */
+ if (whole) {
+- t = task;
++ struct task_struct *t = task;
+ do {
+ min_flt += t->min_flt;
+ maj_flt += t->maj_flt;
+@@ -363,31 +381,21 @@ static int do_task_stat(struct task_stru
+ stime = cputime_add(stime, t->stime);
+ t = next_thread(t);
+ } while (t != task);
+- }
+
+- spin_unlock_irq(&task->sighand->siglock);
+- }
+- if (task->signal) {
+- if (task->signal->tty) {
+- tty_pgrp = task->signal->tty->pgrp;
+- tty_nr = new_encode_dev(tty_devnum(task->signal->tty));
++ min_flt += sig->min_flt;
++ maj_flt += sig->maj_flt;
++ utime = cputime_add(utime, sig->utime);
++ stime = cputime_add(stime, sig->stime);
+ }
++
++ sid = sig->session;
+ pgid = process_group(task);
+- sid = task->signal->session;
+- cmin_flt = task->signal->cmin_flt;
+- cmaj_flt = task->signal->cmaj_flt;
+- cutime = task->signal->cutime;
+- cstime = task->signal->cstime;
+- rsslim = task->signal->rlim[RLIMIT_RSS].rlim_cur;
+- if (whole) {
+- min_flt += task->signal->min_flt;
+- maj_flt += task->signal->maj_flt;
+- utime = cputime_add(utime, task->signal->utime);
+- stime = cputime_add(stime, task->signal->stime);
+- }
++ ppid = rcu_dereference(task->real_parent)->tgid;
++
++ unlock_task_sighand(task, &flags);
+ }
+- ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0;
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
++ mutex_unlock(&tty_mutex);
+
+ if (!whole || num_threads<2)
+ wchan = get_wchan(task);
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index fe8d55f..8df2740 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -71,6 +71,8 @@
+ #include <linux/cpuset.h>
+ #include <linux/audit.h>
+ #include <linux/poll.h>
++#include <linux/nsproxy.h>
++#include <linux/oom.h>
+ #include "internal.h"
+
+ /* NOTE:
+@@ -83,262 +85,44 @@
+ * in /proc for a task before it execs a suid executable.
+ */
+
+-/*
+- * For hysterical raisins we keep the same inumbers as in the old procfs.
+- * Feel free to change the macro below - just keep the range distinct from
+- * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
+- * As soon as we'll get a separate superblock we will be able to forget
+- * about magical ranges too.
+- */
+-
+-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
+-
+-enum pid_directory_inos {
+- PROC_TGID_INO = 2,
+- PROC_TGID_TASK,
+- PROC_TGID_STATUS,
+- PROC_TGID_MEM,
+-#ifdef CONFIG_SECCOMP
+- PROC_TGID_SECCOMP,
+-#endif
+- PROC_TGID_CWD,
+- PROC_TGID_ROOT,
+- PROC_TGID_EXE,
+- PROC_TGID_FD,
+- PROC_TGID_ENVIRON,
+- PROC_TGID_AUXV,
+- PROC_TGID_CMDLINE,
+- PROC_TGID_STAT,
+- PROC_TGID_STATM,
+- PROC_TGID_MAPS,
+- PROC_TGID_NUMA_MAPS,
+- PROC_TGID_MOUNTS,
+- PROC_TGID_MOUNTSTATS,
+- PROC_TGID_WCHAN,
+-#ifdef CONFIG_MMU
+- PROC_TGID_SMAPS,
+-#endif
+-#ifdef CONFIG_SCHEDSTATS
+- PROC_TGID_SCHEDSTAT,
+-#endif
+-#ifdef CONFIG_CPUSETS
+- PROC_TGID_CPUSET,
+-#endif
+-#ifdef CONFIG_SECURITY
+- PROC_TGID_ATTR,
+- PROC_TGID_ATTR_CURRENT,
+- PROC_TGID_ATTR_PREV,
+- PROC_TGID_ATTR_EXEC,
+- PROC_TGID_ATTR_FSCREATE,
+- PROC_TGID_ATTR_KEYCREATE,
+- PROC_TGID_ATTR_SOCKCREATE,
+-#endif
+-#ifdef CONFIG_AUDITSYSCALL
+- PROC_TGID_LOGINUID,
+-#endif
+- PROC_TGID_OOM_SCORE,
+- PROC_TGID_OOM_ADJUST,
+- PROC_TID_INO,
+- PROC_TID_STATUS,
+- PROC_TID_MEM,
+-#ifdef CONFIG_SECCOMP
+- PROC_TID_SECCOMP,
+-#endif
+- PROC_TID_CWD,
+- PROC_TID_ROOT,
+- PROC_TID_EXE,
+- PROC_TID_FD,
+- PROC_TID_ENVIRON,
+- PROC_TID_AUXV,
+- PROC_TID_CMDLINE,
+- PROC_TID_STAT,
+- PROC_TID_STATM,
+- PROC_TID_MAPS,
+- PROC_TID_NUMA_MAPS,
+- PROC_TID_MOUNTS,
+- PROC_TID_MOUNTSTATS,
+- PROC_TID_WCHAN,
+-#ifdef CONFIG_MMU
+- PROC_TID_SMAPS,
+-#endif
+-#ifdef CONFIG_SCHEDSTATS
+- PROC_TID_SCHEDSTAT,
+-#endif
+-#ifdef CONFIG_CPUSETS
+- PROC_TID_CPUSET,
+-#endif
+-#ifdef CONFIG_SECURITY
+- PROC_TID_ATTR,
+- PROC_TID_ATTR_CURRENT,
+- PROC_TID_ATTR_PREV,
+- PROC_TID_ATTR_EXEC,
+- PROC_TID_ATTR_FSCREATE,
+- PROC_TID_ATTR_KEYCREATE,
+- PROC_TID_ATTR_SOCKCREATE,
+-#endif
+-#ifdef CONFIG_AUDITSYSCALL
+- PROC_TID_LOGINUID,
+-#endif
+- PROC_TID_OOM_SCORE,
+- PROC_TID_OOM_ADJUST,
+-
+- /* Add new entries before this */
+- PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
+-};
+
+ /* Worst case buffer size needed for holding an integer. */
+-#define PROC_NUMBUF 10
++#define PROC_NUMBUF 13
+
+ struct pid_entry {
+- int type;
+ int len;
+ char *name;
+ mode_t mode;
++ struct inode_operations *iop;
++ struct file_operations *fop;
++ union proc_op op;
+ };
+
+-#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
+-
+-static struct pid_entry tgid_base_stuff[] = {
+- E(PROC_TGID_TASK, "task", S_IFDIR|S_IRUGO|S_IXUGO),
+- E(PROC_TGID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR),
+- E(PROC_TGID_ENVIRON, "environ", S_IFREG|S_IRUSR),
+- E(PROC_TGID_AUXV, "auxv", S_IFREG|S_IRUSR),
+- E(PROC_TGID_STATUS, "status", S_IFREG|S_IRUGO),
+- E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
+- E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO),
+- E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO),
+- E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO),
+-#ifdef CONFIG_NUMA
+- E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+-#endif
+- E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
+-#ifdef CONFIG_SECCOMP
+- E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
+-#endif
+- E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO),
+- E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO),
+- E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO),
+- E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
+- E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR),
+-#ifdef CONFIG_MMU
+- E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO),
+-#endif
+-#ifdef CONFIG_SECURITY
+- E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
+-#endif
+-#ifdef CONFIG_KALLSYMS
+- E(PROC_TGID_WCHAN, "wchan", S_IFREG|S_IRUGO),
+-#endif
+-#ifdef CONFIG_SCHEDSTATS
+- E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO),
+-#endif
+-#ifdef CONFIG_CPUSETS
+- E(PROC_TGID_CPUSET, "cpuset", S_IFREG|S_IRUGO),
+-#endif
+- E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
+- E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
+-#ifdef CONFIG_AUDITSYSCALL
+- E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
+-#endif
+- {0,0,NULL,0}
+-};
+-static struct pid_entry tid_base_stuff[] = {
+- E(PROC_TID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR),
+- E(PROC_TID_ENVIRON, "environ", S_IFREG|S_IRUSR),
+- E(PROC_TID_AUXV, "auxv", S_IFREG|S_IRUSR),
+- E(PROC_TID_STATUS, "status", S_IFREG|S_IRUGO),
+- E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
+- E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO),
+- E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO),
+- E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO),
+-#ifdef CONFIG_NUMA
+- E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+-#endif
+- E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
+-#ifdef CONFIG_SECCOMP
+- E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
+-#endif
+- E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO),
+- E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO),
+- E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO),
+- E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
+-#ifdef CONFIG_MMU
+- E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO),
+-#endif
+-#ifdef CONFIG_SECURITY
+- E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
+-#endif
+-#ifdef CONFIG_KALLSYMS
+- E(PROC_TID_WCHAN, "wchan", S_IFREG|S_IRUGO),
+-#endif
+-#ifdef CONFIG_SCHEDSTATS
+- E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO),
+-#endif
+-#ifdef CONFIG_CPUSETS
+- E(PROC_TID_CPUSET, "cpuset", S_IFREG|S_IRUGO),
+-#endif
+- E(PROC_TID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
+- E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
+-#ifdef CONFIG_AUDITSYSCALL
+- E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
+-#endif
+- {0,0,NULL,0}
+-};
+-
+-#ifdef CONFIG_SECURITY
+-static struct pid_entry tgid_attr_stuff[] = {
+- E(PROC_TGID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TGID_ATTR_PREV, "prev", S_IFREG|S_IRUGO),
+- E(PROC_TGID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
+- {0,0,NULL,0}
+-};
+-static struct pid_entry tid_attr_stuff[] = {
+- E(PROC_TID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TID_ATTR_PREV, "prev", S_IFREG|S_IRUGO),
+- E(PROC_TID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
+- E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
+- {0,0,NULL,0}
+-};
+-#endif
+-
+-#undef E
+-
+-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+-{
+- struct task_struct *task = get_proc_task(inode);
+- struct files_struct *files = NULL;
+- struct file *file;
+- int fd = proc_fd(inode);
+-
+- if (task) {
+- files = get_files_struct(task);
+- put_task_struct(task);
+- }
+- if (files) {
+- /*
+- * We are not taking a ref to the file structure, so we must
+- * hold ->file_lock.
+- */
+- spin_lock(&files->file_lock);
+- file = fcheck_files(files, fd);
+- if (file) {
+- *mnt = mntget(file->f_vfsmnt);
+- *dentry = dget(file->f_dentry);
+- spin_unlock(&files->file_lock);
+- put_files_struct(files);
+- return 0;
+- }
+- spin_unlock(&files->file_lock);
+- put_files_struct(files);
+- }
+- return -ENOENT;
++#define NOD(NAME, MODE, IOP, FOP, OP) { \
++ .len = sizeof(NAME) - 1, \
++ .name = (NAME), \
++ .mode = MODE, \
++ .iop = IOP, \
++ .fop = FOP, \
++ .op = OP, \
+ }
+
++#define DIR(NAME, MODE, OTYPE) \
++ NOD(NAME, (S_IFDIR|(MODE)), \
++ &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations, \
++ {} )
++#define LNK(NAME, OTYPE) \
++ NOD(NAME, (S_IFLNK|S_IRWXUGO), \
++ &proc_pid_link_inode_operations, NULL, \
++ { .proc_get_link = &proc_##OTYPE##_link } )
++#define REG(NAME, MODE, OTYPE) \
++ NOD(NAME, (S_IFREG|(MODE)), NULL, \
++ &proc_##OTYPE##_operations, {})
++#define INF(NAME, MODE, OTYPE) \
++ NOD(NAME, (S_IFREG|(MODE)), \
++ NULL, &proc_info_file_operations, \
++ { .proc_read = &proc_##OTYPE } )
++
+ static struct fs_struct *get_fs_struct(struct task_struct *task)
+ {
+ struct fs_struct *fs;
+@@ -587,7 +371,7 @@ static int mounts_open(struct inode *ino
+
+ if (task) {
+ task_lock(task);
+- namespace = task->namespace;
++ namespace = task->nsproxy->namespace;
+ if (namespace)
+ get_namespace(namespace);
+ task_unlock(task);
+@@ -658,7 +442,7 @@ static int mountstats_open(struct inode
+
+ if (task) {
+ task_lock(task);
+- namespace = task->namespace;
++ namespace = task->nsproxy->namespace;
+ if (namespace)
+ get_namespace(namespace);
+ task_unlock(task);
+@@ -797,7 +581,7 @@ out_no_task:
+ static ssize_t mem_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+ {
+- int copied = 0;
++ int copied;
+ char *page;
+ struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ unsigned long dst = *ppos;
+@@ -814,6 +598,7 @@ static ssize_t mem_write(struct file * f
+ if (!page)
+ goto out;
+
++ copied = 0;
+ while (count > 0) {
+ int this_len, retval;
+
+@@ -905,7 +690,8 @@ static ssize_t oom_adjust_write(struct f
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ oom_adjust = simple_strtol(buffer, &end, 0);
+- if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
++ if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
++ oom_adjust != OOM_DISABLE)
+ return -EINVAL;
+ if (*end == '\n')
+ end++;
+@@ -1136,143 +922,6 @@ static struct inode_operations proc_pid_
+ .setattr = proc_setattr,
+ };
+
+-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+-{
+- struct dentry *dentry = filp->f_dentry;
+- struct inode *inode = dentry->d_inode;
+- struct task_struct *p = get_proc_task(inode);
+- unsigned int fd, tid, ino;
+- int retval;
+- char buf[PROC_NUMBUF];
+- struct files_struct * files;
+- struct fdtable *fdt;
+-
+- retval = -ENOENT;
+- if (!p)
+- goto out_no_task;
+- retval = 0;
+- tid = p->pid;
+-
+- fd = filp->f_pos;
+- switch (fd) {
+- case 0:
+- if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
+- goto out;
+- filp->f_pos++;
+- case 1:
+- ino = parent_ino(dentry);
+- if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
+- goto out;
+- filp->f_pos++;
+- default:
+- files = get_files_struct(p);
+- if (!files)
+- goto out;
+- rcu_read_lock();
+- fdt = files_fdtable(files);
+- for (fd = filp->f_pos-2;
+- fd < fdt->max_fds;
+- fd++, filp->f_pos++) {
+- unsigned int i,j;
+-
+- if (!fcheck_files(files, fd))
+- continue;
+- rcu_read_unlock();
+-
+- j = PROC_NUMBUF;
+- i = fd;
+- do {
+- j--;
+- buf[j] = '0' + (i % 10);
+- i /= 10;
+- } while (i);
+-
+- ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
+- if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
+- rcu_read_lock();
+- break;
+- }
+- rcu_read_lock();
+- }
+- rcu_read_unlock();
+- put_files_struct(files);
+- }
+-out:
+- put_task_struct(p);
+-out_no_task:
+- return retval;
+-}
+-
+-static int proc_pident_readdir(struct file *filp,
+- void *dirent, filldir_t filldir,
+- struct pid_entry *ents, unsigned int nents)
+-{
+- int i;
+- int pid;
+- struct dentry *dentry = filp->f_dentry;
+- struct inode *inode = dentry->d_inode;
+- struct task_struct *task = get_proc_task(inode);
+- struct pid_entry *p;
+- ino_t ino;
+- int ret;
+-
+- ret = -ENOENT;
+- if (!task)
+- goto out;
+-
+- ret = 0;
+- pid = task->pid;
+- put_task_struct(task);
+- i = filp->f_pos;
+- switch (i) {
+- case 0:
+- ino = inode->i_ino;
+- if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+- goto out;
+- i++;
+- filp->f_pos++;
+- /* fall through */
+- case 1:
+- ino = parent_ino(dentry);
+- if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+- goto out;
+- i++;
+- filp->f_pos++;
+- /* fall through */
+- default:
+- i -= 2;
+- if (i >= nents) {
+- ret = 1;
+- goto out;
+- }
+- p = ents + i;
+- while (p->name) {
+- if (filldir(dirent, p->name, p->len, filp->f_pos,
+- fake_ino(pid, p->type), p->mode >> 12) < 0)
+- goto out;
+- filp->f_pos++;
+- p++;
+- }
+- }
+-
+- ret = 1;
+-out:
+- return ret;
+-}
+-
+-static int proc_tgid_base_readdir(struct file * filp,
+- void * dirent, filldir_t filldir)
+-{
+- return proc_pident_readdir(filp,dirent,filldir,
+- tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
+-}
+-
+-static int proc_tid_base_readdir(struct file * filp,
+- void * dirent, filldir_t filldir)
+-{
+- return proc_pident_readdir(filp,dirent,filldir,
+- tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
+-}
+
+ /* building an inode */
+
+@@ -1292,13 +941,13 @@ static int task_dumpable(struct task_str
+ }
+
+
+-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
++static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
+ {
+ struct inode * inode;
+ struct proc_inode *ei;
+
+ /* We need a new inode */
+-
++
+ inode = new_inode(sb);
+ if (!inode)
+ goto out;
+@@ -1306,13 +955,12 @@ static struct inode *proc_pid_make_inode
+ /* Common stuff */
+ ei = PROC_I(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+- inode->i_ino = fake_ino(task->pid, ino);
+ inode->i_op = &proc_def_inode_operations;
+
+ /*
+ * grab the reference to task.
+ */
+- ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
++ ei->pid = get_task_pid(task, PIDTYPE_PID);
+ if (!ei->pid)
+ goto out_unlock;
+
+@@ -1332,6 +980,27 @@ out_unlock:
+ return NULL;
+ }
+
++static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
++{
++ struct inode *inode = dentry->d_inode;
++ struct task_struct *task;
++ generic_fillattr(inode, stat);
++
++ rcu_read_lock();
++ stat->uid = 0;
++ stat->gid = 0;
++ task = pid_task(proc_pid(inode), PIDTYPE_PID);
++ if (task) {
++ if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
++ task_dumpable(task)) {
++ stat->uid = task->euid;
++ stat->gid = task->egid;
++ }
++ }
++ rcu_read_unlock();
++ return 0;
++}
++
+ /* dentry stuff */
+
+ /*
+@@ -1371,25 +1040,130 @@ static int pid_revalidate(struct dentry
+ return 0;
+ }
+
+-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
++static int pid_delete_dentry(struct dentry * dentry)
+ {
+- struct inode *inode = dentry->d_inode;
+- struct task_struct *task;
+- generic_fillattr(inode, stat);
++ /* Is the task we represent dead?
++ * If so, then don't put the dentry on the lru list,
++ * kill it immediately.
++ */
++ return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
++}
++
++static struct dentry_operations pid_dentry_operations =
++{
++ .d_revalidate = pid_revalidate,
++ .d_delete = pid_delete_dentry,
++};
++
++/* Lookups */
++
++typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
++
++/*
++ * Fill a directory entry.
++ *
++ * If possible create the dcache entry and derive our inode number and
++ * file type from dcache entry.
++ *
++ * Since all of the proc inode numbers are dynamically generated, the inode
++ * numbers do not exist until the inode is cache. This means creating the
++ * the dcache entry in readdir is necessary to keep the inode numbers
++ * reported by readdir in sync with the inode numbers reported
++ * by stat.
++ */
++static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
++ char *name, int len,
++ instantiate_t instantiate, struct task_struct *task, void *ptr)
++{
++ struct dentry *child, *dir = filp->f_dentry;
++ struct inode *inode;
++ struct qstr qname;
++ ino_t ino = 0;
++ unsigned type = DT_UNKNOWN;
++
++ qname.name = name;
++ qname.len = len;
++ qname.hash = full_name_hash(name, len);
++
++ child = d_lookup(dir, &qname);
++ if (!child) {
++ struct dentry *new;
++ new = d_alloc(dir, &qname);
++ if (new) {
++ child = instantiate(dir->d_inode, new, task, ptr);
++ if (child)
++ dput(new);
++ else
++ child = new;
++ }
++ }
++ if (!child || IS_ERR(child) || !child->d_inode)
++ goto end_instantiate;
++ inode = child->d_inode;
++ if (inode) {
++ ino = inode->i_ino;
++ type = inode->i_mode >> 12;
++ }
++ dput(child);
++end_instantiate:
++ if (!ino)
++ ino = find_inode_number(dir, &qname);
++ if (!ino)
++ ino = 1;
++ return filldir(dirent, name, len, filp->f_pos, ino, type);
++}
++
++static unsigned name_to_int(struct dentry *dentry)
++{
++ const char *name = dentry->d_name.name;
++ int len = dentry->d_name.len;
++ unsigned n = 0;
++
++ if (len > 1 && *name == '0')
++ goto out;
++ while (len-- > 0) {
++ unsigned c = *name++ - '0';
++ if (c > 9)
++ goto out;
++ if (n >= (~0U-9)/10)
++ goto out;
++ n *= 10;
++ n += c;
++ }
++ return n;
++out:
++ return ~0U;
++}
++
++static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
++{
++ struct task_struct *task = get_proc_task(inode);
++ struct files_struct *files = NULL;
++ struct file *file;
++ int fd = proc_fd(inode);
+
+- rcu_read_lock();
+- stat->uid = 0;
+- stat->gid = 0;
+- task = pid_task(proc_pid(inode), PIDTYPE_PID);
+ if (task) {
+- if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+- task_dumpable(task)) {
+- stat->uid = task->euid;
+- stat->gid = task->egid;
++ files = get_files_struct(task);
++ put_task_struct(task);
++ }
++ if (files) {
++ /*
++ * We are not taking a ref to the file structure, so we must
++ * hold ->file_lock.
++ */
++ spin_lock(&files->file_lock);
++ file = fcheck_files(files, fd);
++ if (file) {
++ *mnt = mntget(file->f_vfsmnt);
++ *dentry = dget(file->f_dentry);
++ spin_unlock(&files->file_lock);
++ put_files_struct(files);
++ return 0;
+ }
++ spin_unlock(&files->file_lock);
++ put_files_struct(files);
+ }
+- rcu_read_unlock();
+- return 0;
++ return -ENOENT;
+ }
+
+ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
+@@ -1427,75 +1201,30 @@ static int tid_fd_revalidate(struct dent
+ return 0;
+ }
+
+-static int pid_delete_dentry(struct dentry * dentry)
+-{
+- /* Is the task we represent dead?
+- * If so, then don't put the dentry on the lru list,
+- * kill it immediately.
+- */
+- return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
+-}
+-
+ static struct dentry_operations tid_fd_dentry_operations =
+ {
+ .d_revalidate = tid_fd_revalidate,
+ .d_delete = pid_delete_dentry,
+ };
+
+-static struct dentry_operations pid_dentry_operations =
+-{
+- .d_revalidate = pid_revalidate,
+- .d_delete = pid_delete_dentry,
+-};
+-
+-/* Lookups */
+-
+-static unsigned name_to_int(struct dentry *dentry)
+-{
+- const char *name = dentry->d_name.name;
+- int len = dentry->d_name.len;
+- unsigned n = 0;
+-
+- if (len > 1 && *name == '0')
+- goto out;
+- while (len-- > 0) {
+- unsigned c = *name++ - '0';
+- if (c > 9)
+- goto out;
+- if (n >= (~0U-9)/10)
+- goto out;
+- n *= 10;
+- n += c;
+- }
+- return n;
+-out:
+- return ~0U;
+-}
+-
+-/* SMP-safe */
+-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
++static struct dentry *proc_fd_instantiate(struct inode *dir,
++ struct dentry *dentry, struct task_struct *task, void *ptr)
+ {
+- struct task_struct *task = get_proc_task(dir);
+- unsigned fd = name_to_int(dentry);
+- struct dentry *result = ERR_PTR(-ENOENT);
+- struct file * file;
+- struct files_struct * files;
+- struct inode *inode;
+- struct proc_inode *ei;
+-
+- if (!task)
+- goto out_no_task;
+- if (fd == ~0U)
+- goto out;
++ unsigned fd = *(unsigned *)ptr;
++ struct file *file;
++ struct files_struct *files;
++ struct inode *inode;
++ struct proc_inode *ei;
++ struct dentry *error = ERR_PTR(-ENOENT);
+
+- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
++ inode = proc_pid_make_inode(dir->i_sb, task);
+ if (!inode)
+ goto out;
+ ei = PROC_I(inode);
+ ei->fd = fd;
+ files = get_files_struct(task);
+ if (!files)
+- goto out_unlock;
++ goto out_iput;
+ inode->i_mode = S_IFLNK;
+
+ /*
+@@ -1505,13 +1234,14 @@ static struct dentry *proc_lookupfd(stru
+ spin_lock(&files->file_lock);
+ file = fcheck_files(files, fd);
+ if (!file)
+- goto out_unlock2;
++ goto out_unlock;
+ if (file->f_mode & 1)
+ inode->i_mode |= S_IRUSR | S_IXUSR;
+ if (file->f_mode & 2)
+ inode->i_mode |= S_IWUSR | S_IXUSR;
+ spin_unlock(&files->file_lock);
+ put_files_struct(files);
++
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->i_size = 64;
+ ei->op.proc_get_link = proc_fd_link;
+@@ -1519,34 +1249,106 @@ static struct dentry *proc_lookupfd(stru
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (tid_fd_revalidate(dentry, NULL))
+- result = NULL;
+-out:
+- put_task_struct(task);
+-out_no_task:
+- return result;
++ error = NULL;
+
+-out_unlock2:
++ out:
++ return error;
++out_unlock:
+ spin_unlock(&files->file_lock);
+ put_files_struct(files);
+-out_unlock:
++out_iput:
+ iput(inode);
+ goto out;
+ }
+
+-static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir);
+-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd);
+-static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
++static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
++{
++ struct task_struct *task = get_proc_task(dir);
++ unsigned fd = name_to_int(dentry);
++ struct dentry *result = ERR_PTR(-ENOENT);
++
++ if (!task)
++ goto out_no_task;
++ if (fd == ~0U)
++ goto out;
++
++ result = proc_fd_instantiate(dir, dentry, task, &fd);
++out:
++ put_task_struct(task);
++out_no_task:
++ return result;
++}
++
++static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
++ struct task_struct *task, int fd)
++{
++ char name[PROC_NUMBUF];
++ int len = snprintf(name, sizeof(name), "%d", fd);
++ return proc_fill_cache(filp, dirent, filldir, name, len,
++ proc_fd_instantiate, task, &fd);
++}
++
++static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
++{
++ struct dentry *dentry = filp->f_dentry;
++ struct inode *inode = dentry->d_inode;
++ struct task_struct *p = get_proc_task(inode);
++ unsigned int fd, tid, ino;
++ int retval;
++ struct files_struct * files;
++ struct fdtable *fdt;
++
++ retval = -ENOENT;
++ if (!p)
++ goto out_no_task;
++ retval = 0;
++ tid = p->pid;
++
++ fd = filp->f_pos;
++ switch (fd) {
++ case 0:
++ if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
++ goto out;
++ filp->f_pos++;
++ case 1:
++ ino = parent_ino(dentry);
++ if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
++ goto out;
++ filp->f_pos++;
++ default:
++ files = get_files_struct(p);
++ if (!files)
++ goto out;
++ rcu_read_lock();
++ fdt = files_fdtable(files);
++ for (fd = filp->f_pos-2;
++ fd < fdt->max_fds;
++ fd++, filp->f_pos++) {
++
++ if (!fcheck_files(files, fd))
++ continue;
++ rcu_read_unlock();
++
++ if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
++ rcu_read_lock();
++ break;
++ }
++ rcu_read_lock();
++ }
++ rcu_read_unlock();
++ put_files_struct(files);
++ }
++out:
++ put_task_struct(p);
++out_no_task:
++ return retval;
++}
+
+ static struct file_operations proc_fd_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_readfd,
+ };
+
+-static struct file_operations proc_task_operations = {
+- .read = generic_read_dir,
+- .readdir = proc_task_readdir,
+-};
+-
+ /*
+ * proc directories can do almost nothing..
+ */
+@@ -1555,11 +1357,137 @@ static struct inode_operations proc_fd_i
+ .setattr = proc_setattr,
+ };
+
+-static struct inode_operations proc_task_inode_operations = {
+- .lookup = proc_task_lookup,
+- .getattr = proc_task_getattr,
+- .setattr = proc_setattr,
+-};
++static struct dentry *proc_pident_instantiate(struct inode *dir,
++ struct dentry *dentry, struct task_struct *task, void *ptr)
++{
++ struct pid_entry *p = ptr;
++ struct inode *inode;
++ struct proc_inode *ei;
++ struct dentry *error = ERR_PTR(-EINVAL);
++
++ inode = proc_pid_make_inode(dir->i_sb, task);
++ if (!inode)
++ goto out;
++
++ ei = PROC_I(inode);
++ inode->i_mode = p->mode;
++ if (S_ISDIR(inode->i_mode))
++ inode->i_nlink = 2; /* Use getattr to fix if necessary */
++ if (p->iop)
++ inode->i_op = p->iop;
++ if (p->fop)
++ inode->i_fop = p->fop;
++ ei->op = p->op;
++ dentry->d_op = &pid_dentry_operations;
++ d_add(dentry, inode);
++ /* Close the race of the process dying before we return the dentry */
++ if (pid_revalidate(dentry, NULL))
++ error = NULL;
++out:
++ return error;
++}
++
++static struct dentry *proc_pident_lookup(struct inode *dir,
++ struct dentry *dentry,
++ struct pid_entry *ents,
++ unsigned int nents)
++{
++ struct inode *inode;
++ struct dentry *error;
++ struct task_struct *task = get_proc_task(dir);
++ struct pid_entry *p, *last;
++
++ error = ERR_PTR(-ENOENT);
++ inode = NULL;
++
++ if (!task)
++ goto out_no_task;
++
++ /*
++ * Yes, it does not scale. And it should not. Don't add
++ * new entries into /proc/<tgid>/ without very good reasons.
++ */
++ last = &ents[nents - 1];
++ for (p = ents; p <= last; p++) {
++ if (p->len != dentry->d_name.len)
++ continue;
++ if (!memcmp(dentry->d_name.name, p->name, p->len))
++ break;
++ }
++ if (p > last)
++ goto out;
++
++ error = proc_pident_instantiate(dir, dentry, task, p);
++out:
++ put_task_struct(task);
++out_no_task:
++ return error;
++}
++
++static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
++ struct task_struct *task, struct pid_entry *p)
++{
++ return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
++ proc_pident_instantiate, task, p);
++}
++
++static int proc_pident_readdir(struct file *filp,
++ void *dirent, filldir_t filldir,
++ struct pid_entry *ents, unsigned int nents)
++{
++ int i;
++ int pid;
++ struct dentry *dentry = filp->f_dentry;
++ struct inode *inode = dentry->d_inode;
++ struct task_struct *task = get_proc_task(inode);
++ struct pid_entry *p, *last;
++ ino_t ino;
++ int ret;
++
++ ret = -ENOENT;
++ if (!task)
++ goto out_no_task;
++
++ ret = 0;
++ pid = task->pid;
++ i = filp->f_pos;
++ switch (i) {
++ case 0:
++ ino = inode->i_ino;
++ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
++ goto out;
++ i++;
++ filp->f_pos++;
++ /* fall through */
++ case 1:
++ ino = parent_ino(dentry);
++ if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
++ goto out;
++ i++;
++ filp->f_pos++;
++ /* fall through */
++ default:
++ i -= 2;
++ if (i >= nents) {
++ ret = 1;
++ goto out;
++ }
++ p = ents + i;
++ last = &ents[nents - 1];
++ while (p <= last) {
++ if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
++ goto out;
++ filp->f_pos++;
++ p++;
++ }
++ }
++
++ ret = 1;
++out:
++ put_task_struct(task);
++out_no_task:
++ return ret;
++}
+
+ #ifdef CONFIG_SECURITY
+ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
+@@ -1580,8 +1508,8 @@ static ssize_t proc_pid_attr_read(struct
+ if (!(page = __get_free_page(GFP_KERNEL)))
+ goto out;
+
+- length = security_getprocattr(task,
+- (char*)file->f_dentry->d_name.name,
++ length = security_getprocattr(task,
++ (char*)file->f_dentry->d_name.name,
+ (void*)page, count);
+ if (length >= 0)
+ length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
+@@ -1594,17 +1522,17 @@ out_no_task:
+
+ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
+ size_t count, loff_t *ppos)
+-{
++{
+ struct inode * inode = file->f_dentry->d_inode;
+- char *page;
+- ssize_t length;
++ char *page;
++ ssize_t length;
+ struct task_struct *task = get_proc_task(inode);
+
+ length = -ESRCH;
+ if (!task)
+ goto out_no_task;
+- if (count > PAGE_SIZE)
+- count = PAGE_SIZE;
++ if (count > PAGE_SIZE)
++ count = PAGE_SIZE;
+
+ /* No partial writes. */
+ length = -EINVAL;
+@@ -1612,16 +1540,16 @@ static ssize_t proc_pid_attr_write(struc
+ goto out;
+
+ length = -ENOMEM;
+- page = (char*)__get_free_page(GFP_USER);
+- if (!page)
++ page = (char*)__get_free_page(GFP_USER);
++ if (!page)
+ goto out;
+
+- length = -EFAULT;
+- if (copy_from_user(page, buf, count))
++ length = -EFAULT;
++ if (copy_from_user(page, buf, count))
+ goto out_free;
+
+- length = security_setprocattr(task,
+- (char*)file->f_dentry->d_name.name,
++ length = security_setprocattr(task,
++ (char*)file->f_dentry->d_name.name,
+ (void*)page, count);
+ out_free:
+ free_page((unsigned long) page);
+@@ -1629,330 +1557,263 @@ out:
+ put_task_struct(task);
+ out_no_task:
+ return length;
+-}
++}
+
+ static struct file_operations proc_pid_attr_operations = {
+ .read = proc_pid_attr_read,
+ .write = proc_pid_attr_write,
+ };
+
+-static struct file_operations proc_tid_attr_operations;
+-static struct inode_operations proc_tid_attr_inode_operations;
+-static struct file_operations proc_tgid_attr_operations;
+-static struct inode_operations proc_tgid_attr_inode_operations;
++static struct pid_entry attr_dir_stuff[] = {
++ REG("current", S_IRUGO|S_IWUGO, pid_attr),
++ REG("prev", S_IRUGO, pid_attr),
++ REG("exec", S_IRUGO|S_IWUGO, pid_attr),
++ REG("fscreate", S_IRUGO|S_IWUGO, pid_attr),
++ REG("keycreate", S_IRUGO|S_IWUGO, pid_attr),
++ REG("sockcreate", S_IRUGO|S_IWUGO, pid_attr),
++};
++
++static int proc_attr_dir_readdir(struct file * filp,
++ void * dirent, filldir_t filldir)
++{
++ return proc_pident_readdir(filp,dirent,filldir,
++ attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
++}
++
++static struct file_operations proc_attr_dir_operations = {
++ .read = generic_read_dir,
++ .readdir = proc_attr_dir_readdir,
++};
++
++static struct dentry *proc_attr_dir_lookup(struct inode *dir,
++ struct dentry *dentry, struct nameidata *nd)
++{
++ return proc_pident_lookup(dir, dentry,
++ attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
++}
++
++static struct inode_operations proc_attr_dir_inode_operations = {
++ .lookup = proc_attr_dir_lookup,
++ .getattr = pid_getattr,
++ .setattr = proc_setattr,
++};
++
+ #endif
+
+-/* SMP-safe */
+-static struct dentry *proc_pident_lookup(struct inode *dir,
+- struct dentry *dentry,
+- struct pid_entry *ents)
++/*
++ * /proc/self:
++ */
++static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
++ int buflen)
++{
++ char tmp[PROC_NUMBUF];
++ sprintf(tmp, "%d", current->tgid);
++ return vfs_readlink(dentry,buffer,buflen,tmp);
++}
++
++static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
+ {
++ char tmp[PROC_NUMBUF];
++ sprintf(tmp, "%d", current->tgid);
++ return ERR_PTR(vfs_follow_link(nd,tmp));
++}
++
++static struct inode_operations proc_self_inode_operations = {
++ .readlink = proc_self_readlink,
++ .follow_link = proc_self_follow_link,
++};
++
++/*
++ * proc base
++ *
++ * These are the directory entries in the root directory of /proc
++ * that properly belong to the /proc filesystem, as they describe
++ * describe something that is process related.
++ */
++static struct pid_entry proc_base_stuff[] = {
++ NOD("self", S_IFLNK|S_IRWXUGO,
++ &proc_self_inode_operations, NULL, {}),
++};
++
++/*
++ * Exceptional case: normally we are not allowed to unhash a busy
++ * directory. In this case, however, we can do it - no aliasing problems
++ * due to the way we treat inodes.
++ */
++static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ struct inode *inode = dentry->d_inode;
++ struct task_struct *task = get_proc_task(inode);
++ if (task) {
++ put_task_struct(task);
++ return 1;
++ }
++ d_drop(dentry);
++ return 0;
++}
++
++static struct dentry_operations proc_base_dentry_operations =
++{
++ .d_revalidate = proc_base_revalidate,
++ .d_delete = pid_delete_dentry,
++};
++
++static struct dentry *proc_base_instantiate(struct inode *dir,
++ struct dentry *dentry, struct task_struct *task, void *ptr)
++{
++ struct pid_entry *p = ptr;
+ struct inode *inode;
++ struct proc_inode *ei;
++ struct dentry *error = ERR_PTR(-EINVAL);
++
++ /* Allocate the inode */
++ error = ERR_PTR(-ENOMEM);
++ inode = new_inode(dir->i_sb);
++ if (!inode)
++ goto out;
++
++ /* Initialize the inode */
++ ei = PROC_I(inode);
++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
++
++ /*
++ * grab the reference to the task.
++ */
++ ei->pid = get_task_pid(task, PIDTYPE_PID);
++ if (!ei->pid)
++ goto out_iput;
++
++ inode->i_uid = 0;
++ inode->i_gid = 0;
++ inode->i_mode = p->mode;
++ if (S_ISDIR(inode->i_mode))
++ inode->i_nlink = 2;
++ if (S_ISLNK(inode->i_mode))
++ inode->i_size = 64;
++ if (p->iop)
++ inode->i_op = p->iop;
++ if (p->fop)
++ inode->i_fop = p->fop;
++ ei->op = p->op;
++ dentry->d_op = &proc_base_dentry_operations;
++ d_add(dentry, inode);
++ error = NULL;
++out:
++ return error;
++out_iput:
++ iput(inode);
++ goto out;
++}
++
++static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
++{
+ struct dentry *error;
+ struct task_struct *task = get_proc_task(dir);
+- struct pid_entry *p;
+- struct proc_inode *ei;
++ struct pid_entry *p, *last;
+
+ error = ERR_PTR(-ENOENT);
+- inode = NULL;
+
+ if (!task)
+ goto out_no_task;
+
+- for (p = ents; p->name; p++) {
++ /* Lookup the directory entry */
++ last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1];
++ for (p = proc_base_stuff; p <= last; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+- if (!p->name)
++ if (p > last)
+ goto out;
+
+- error = ERR_PTR(-EINVAL);
+- inode = proc_pid_make_inode(dir->i_sb, task, p->type);
+- if (!inode)
+- goto out;
++ error = proc_base_instantiate(dir, dentry, task, p);
+
+- ei = PROC_I(inode);
+- inode->i_mode = p->mode;
+- /*
+- * Yes, it does not scale. And it should not. Don't add
+- * new entries into /proc/<tgid>/ without very good reasons.
+- */
+- switch(p->type) {
+- case PROC_TGID_TASK:
+- inode->i_nlink = 2;
+- inode->i_op = &proc_task_inode_operations;
+- inode->i_fop = &proc_task_operations;
+- break;
+- case PROC_TID_FD:
+- case PROC_TGID_FD:
+- inode->i_nlink = 2;
+- inode->i_op = &proc_fd_inode_operations;
+- inode->i_fop = &proc_fd_operations;
+- break;
+- case PROC_TID_EXE:
+- case PROC_TGID_EXE:
+- inode->i_op = &proc_pid_link_inode_operations;
+- ei->op.proc_get_link = proc_exe_link;
+- break;
+- case PROC_TID_CWD:
+- case PROC_TGID_CWD:
+- inode->i_op = &proc_pid_link_inode_operations;
+- ei->op.proc_get_link = proc_cwd_link;
+- break;
+- case PROC_TID_ROOT:
+- case PROC_TGID_ROOT:
+- inode->i_op = &proc_pid_link_inode_operations;
+- ei->op.proc_get_link = proc_root_link;
+- break;
+- case PROC_TID_ENVIRON:
+- case PROC_TGID_ENVIRON:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_environ;
+- break;
+- case PROC_TID_AUXV:
+- case PROC_TGID_AUXV:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_auxv;
+- break;
+- case PROC_TID_STATUS:
+- case PROC_TGID_STATUS:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_status;
+- break;
+- case PROC_TID_STAT:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_tid_stat;
+- break;
+- case PROC_TGID_STAT:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_tgid_stat;
+- break;
+- case PROC_TID_CMDLINE:
+- case PROC_TGID_CMDLINE:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_cmdline;
+- break;
+- case PROC_TID_STATM:
+- case PROC_TGID_STATM:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_statm;
+- break;
+- case PROC_TID_MAPS:
+- case PROC_TGID_MAPS:
+- inode->i_fop = &proc_maps_operations;
+- break;
++out:
++ put_task_struct(task);
++out_no_task:
++ return error;
++}
++
++static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
++ struct task_struct *task, struct pid_entry *p)
++{
++ return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
++ proc_base_instantiate, task, p);
++}
++
++/*
++ * Thread groups
++ */
++static struct file_operations proc_task_operations;
++static struct inode_operations proc_task_inode_operations;
++
++static struct pid_entry tgid_base_stuff[] = {
++ DIR("task", S_IRUGO|S_IXUGO, task),
++ DIR("fd", S_IRUSR|S_IXUSR, fd),
++ INF("environ", S_IRUSR, pid_environ),
++ INF("auxv", S_IRUSR, pid_auxv),
++ INF("status", S_IRUGO, pid_status),
++ INF("cmdline", S_IRUGO, pid_cmdline),
++ INF("stat", S_IRUGO, tgid_stat),
++ INF("statm", S_IRUGO, pid_statm),
++ REG("maps", S_IRUGO, maps),
+ #ifdef CONFIG_NUMA
+- case PROC_TID_NUMA_MAPS:
+- case PROC_TGID_NUMA_MAPS:
+- inode->i_fop = &proc_numa_maps_operations;
+- break;
++ REG("numa_maps", S_IRUGO, numa_maps),
+ #endif
+- case PROC_TID_MEM:
+- case PROC_TGID_MEM:
+- inode->i_fop = &proc_mem_operations;
+- break;
++ REG("mem", S_IRUSR|S_IWUSR, mem),
+ #ifdef CONFIG_SECCOMP
+- case PROC_TID_SECCOMP:
+- case PROC_TGID_SECCOMP:
+- inode->i_fop = &proc_seccomp_operations;
+- break;
+-#endif /* CONFIG_SECCOMP */
+- case PROC_TID_MOUNTS:
+- case PROC_TGID_MOUNTS:
+- inode->i_fop = &proc_mounts_operations;
+- break;
++ REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
++#endif
++ LNK("cwd", cwd),
++ LNK("root", root),
++ LNK("exe", exe),
++ REG("mounts", S_IRUGO, mounts),
++ REG("mountstats", S_IRUSR, mountstats),
+ #ifdef CONFIG_MMU
+- case PROC_TID_SMAPS:
+- case PROC_TGID_SMAPS:
+- inode->i_fop = &proc_smaps_operations;
+- break;
++ REG("smaps", S_IRUGO, smaps),
+ #endif
+- case PROC_TID_MOUNTSTATS:
+- case PROC_TGID_MOUNTSTATS:
+- inode->i_fop = &proc_mountstats_operations;
+- break;
+ #ifdef CONFIG_SECURITY
+- case PROC_TID_ATTR:
+- inode->i_nlink = 2;
+- inode->i_op = &proc_tid_attr_inode_operations;
+- inode->i_fop = &proc_tid_attr_operations;
+- break;
+- case PROC_TGID_ATTR:
+- inode->i_nlink = 2;
+- inode->i_op = &proc_tgid_attr_inode_operations;
+- inode->i_fop = &proc_tgid_attr_operations;
+- break;
+- case PROC_TID_ATTR_CURRENT:
+- case PROC_TGID_ATTR_CURRENT:
+- case PROC_TID_ATTR_PREV:
+- case PROC_TGID_ATTR_PREV:
+- case PROC_TID_ATTR_EXEC:
+- case PROC_TGID_ATTR_EXEC:
+- case PROC_TID_ATTR_FSCREATE:
+- case PROC_TGID_ATTR_FSCREATE:
+- case PROC_TID_ATTR_KEYCREATE:
+- case PROC_TGID_ATTR_KEYCREATE:
+- case PROC_TID_ATTR_SOCKCREATE:
+- case PROC_TGID_ATTR_SOCKCREATE:
+- inode->i_fop = &proc_pid_attr_operations;
+- break;
++ DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
+ #endif
+ #ifdef CONFIG_KALLSYMS
+- case PROC_TID_WCHAN:
+- case PROC_TGID_WCHAN:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_wchan;
+- break;
++ INF("wchan", S_IRUGO, pid_wchan),
+ #endif
+ #ifdef CONFIG_SCHEDSTATS
+- case PROC_TID_SCHEDSTAT:
+- case PROC_TGID_SCHEDSTAT:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_pid_schedstat;
+- break;
++ INF("schedstat", S_IRUGO, pid_schedstat),
+ #endif
+ #ifdef CONFIG_CPUSETS
+- case PROC_TID_CPUSET:
+- case PROC_TGID_CPUSET:
+- inode->i_fop = &proc_cpuset_operations;
+- break;
++ REG("cpuset", S_IRUGO, cpuset),
+ #endif
+- case PROC_TID_OOM_SCORE:
+- case PROC_TGID_OOM_SCORE:
+- inode->i_fop = &proc_info_file_operations;
+- ei->op.proc_read = proc_oom_score;
+- break;
+- case PROC_TID_OOM_ADJUST:
+- case PROC_TGID_OOM_ADJUST:
+- inode->i_fop = &proc_oom_adjust_operations;
+- break;
++ INF("oom_score", S_IRUGO, oom_score),
++ REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
+ #ifdef CONFIG_AUDITSYSCALL
+- case PROC_TID_LOGINUID:
+- case PROC_TGID_LOGINUID:
+- inode->i_fop = &proc_loginuid_operations;
+- break;
++ REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
+ #endif
+- default:
+- printk("procfs: impossible type (%d)",p->type);
+- iput(inode);
+- error = ERR_PTR(-EINVAL);
+- goto out;
+- }
+- dentry->d_op = &pid_dentry_operations;
+- d_add(dentry, inode);
+- /* Close the race of the process dying before we return the dentry */
+- if (pid_revalidate(dentry, NULL))
+- error = NULL;
+-out:
+- put_task_struct(task);
+-out_no_task:
+- return error;
+-}
+-
+-static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+- return proc_pident_lookup(dir, dentry, tgid_base_stuff);
+-}
+-
+-static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+- return proc_pident_lookup(dir, dentry, tid_base_stuff);
+-}
+-
+-static struct file_operations proc_tgid_base_operations = {
+- .read = generic_read_dir,
+- .readdir = proc_tgid_base_readdir,
+ };
+
+-static struct file_operations proc_tid_base_operations = {
+- .read = generic_read_dir,
+- .readdir = proc_tid_base_readdir,
+-};
+-
+-static struct inode_operations proc_tgid_base_inode_operations = {
+- .lookup = proc_tgid_base_lookup,
+- .getattr = pid_getattr,
+- .setattr = proc_setattr,
+-};
+-
+-static struct inode_operations proc_tid_base_inode_operations = {
+- .lookup = proc_tid_base_lookup,
+- .getattr = pid_getattr,
+- .setattr = proc_setattr,
+-};
+-
+-#ifdef CONFIG_SECURITY
+-static int proc_tgid_attr_readdir(struct file * filp,
+- void * dirent, filldir_t filldir)
+-{
+- return proc_pident_readdir(filp,dirent,filldir,
+- tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
+-}
+-
+-static int proc_tid_attr_readdir(struct file * filp,
++static int proc_tgid_base_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+ {
+ return proc_pident_readdir(filp,dirent,filldir,
+- tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
++ tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
+ }
+
+-static struct file_operations proc_tgid_attr_operations = {
+- .read = generic_read_dir,
+- .readdir = proc_tgid_attr_readdir,
+-};
+-
+-static struct file_operations proc_tid_attr_operations = {
++static struct file_operations proc_tgid_base_operations = {
+ .read = generic_read_dir,
+- .readdir = proc_tid_attr_readdir,
++ .readdir = proc_tgid_base_readdir,
+ };
+
+-static struct dentry *proc_tgid_attr_lookup(struct inode *dir,
+- struct dentry *dentry, struct nameidata *nd)
+-{
+- return proc_pident_lookup(dir, dentry, tgid_attr_stuff);
+-}
+-
+-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
+- struct dentry *dentry, struct nameidata *nd)
+-{
+- return proc_pident_lookup(dir, dentry, tid_attr_stuff);
++static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
++ return proc_pident_lookup(dir, dentry,
++ tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
+ }
+
+-static struct inode_operations proc_tgid_attr_inode_operations = {
+- .lookup = proc_tgid_attr_lookup,
+- .getattr = pid_getattr,
+- .setattr = proc_setattr,
+-};
+-
+-static struct inode_operations proc_tid_attr_inode_operations = {
+- .lookup = proc_tid_attr_lookup,
++static struct inode_operations proc_tgid_base_inode_operations = {
++ .lookup = proc_tgid_base_lookup,
+ .getattr = pid_getattr,
+ .setattr = proc_setattr,
+ };
+-#endif
+-
+-/*
+- * /proc/self:
+- */
+-static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
+- int buflen)
+-{
+- char tmp[PROC_NUMBUF];
+- sprintf(tmp, "%d", current->tgid);
+- return vfs_readlink(dentry,buffer,buflen,tmp);
+-}
+-
+-static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
+-{
+- char tmp[PROC_NUMBUF];
+- sprintf(tmp, "%d", current->tgid);
+- return ERR_PTR(vfs_follow_link(nd,tmp));
+-}
+-
+-static struct inode_operations proc_self_inode_operations = {
+- .readlink = proc_self_readlink,
+- .follow_link = proc_self_follow_link,
+-};
+
+ /**
+ * proc_flush_task - Remove dcache entries for @task from the /proc dcache.
+@@ -2021,54 +1882,23 @@ out:
+ return;
+ }
+
+-/* SMP-safe */
+-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
++struct dentry *proc_pid_instantiate(struct inode *dir,
++ struct dentry * dentry, struct task_struct *task, void *ptr)
+ {
+- struct dentry *result = ERR_PTR(-ENOENT);
+- struct task_struct *task;
++ struct dentry *error = ERR_PTR(-ENOENT);
+ struct inode *inode;
+- struct proc_inode *ei;
+- unsigned tgid;
+-
+- if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) {
+- inode = new_inode(dir->i_sb);
+- if (!inode)
+- return ERR_PTR(-ENOMEM);
+- ei = PROC_I(inode);
+- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+- inode->i_ino = fake_ino(0, PROC_TGID_INO);
+- ei->pde = NULL;
+- inode->i_mode = S_IFLNK|S_IRWXUGO;
+- inode->i_uid = inode->i_gid = 0;
+- inode->i_size = 64;
+- inode->i_op = &proc_self_inode_operations;
+- d_add(dentry, inode);
+- return NULL;
+- }
+- tgid = name_to_int(dentry);
+- if (tgid == ~0U)
+- goto out;
+
+- rcu_read_lock();
+- task = find_task_by_pid(tgid);
+- if (task)
+- get_task_struct(task);
+- rcu_read_unlock();
+- if (!task)
+- goto out;
+-
+- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
++ inode = proc_pid_make_inode(dir->i_sb, task);
+ if (!inode)
+- goto out_put_task;
++ goto out;
+
+ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+ inode->i_op = &proc_tgid_base_inode_operations;
+ inode->i_fop = &proc_tgid_base_operations;
+ inode->i_flags|=S_IMMUTABLE;
+-#ifdef CONFIG_SECURITY
+- inode->i_nlink = 5;
+-#else
+ inode->i_nlink = 4;
++#ifdef CONFIG_SECURITY
++ inode->i_nlink += 1;
+ #endif
+
+ dentry->d_op = &pid_dentry_operations;
+@@ -2076,179 +1906,251 @@ struct dentry *proc_pid_lookup(struct in
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (pid_revalidate(dentry, NULL))
+- result = NULL;
+-
+-out_put_task:
+- put_task_struct(task);
++ error = NULL;
+ out:
+- return result;
++ return error;
+ }
+
+-/* SMP-safe */
+-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
++struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+ {
+ struct dentry *result = ERR_PTR(-ENOENT);
+ struct task_struct *task;
+- struct task_struct *leader = get_proc_task(dir);
+- struct inode *inode;
+- unsigned tid;
++ unsigned tgid;
+
+- if (!leader)
+- goto out_no_task;
++ result = proc_base_lookup(dir, dentry);
++ if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
++ goto out;
+
+- tid = name_to_int(dentry);
+- if (tid == ~0U)
++ tgid = name_to_int(dentry);
++ if (tgid == ~0U)
+ goto out;
+
+ rcu_read_lock();
+- task = find_task_by_pid(tid);
++ task = find_task_by_pid(tgid);
+ if (task)
+ get_task_struct(task);
+ rcu_read_unlock();
+ if (!task)
+ goto out;
+- if (leader->tgid != task->tgid)
+- goto out_drop_task;
+-
+- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
+-
+-
+- if (!inode)
+- goto out_drop_task;
+- inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+- inode->i_op = &proc_tid_base_inode_operations;
+- inode->i_fop = &proc_tid_base_operations;
+- inode->i_flags|=S_IMMUTABLE;
+-#ifdef CONFIG_SECURITY
+- inode->i_nlink = 4;
+-#else
+- inode->i_nlink = 3;
+-#endif
+-
+- dentry->d_op = &pid_dentry_operations;
+-
+- d_add(dentry, inode);
+- /* Close the race of the process dying before we return the dentry */
+- if (pid_revalidate(dentry, NULL))
+- result = NULL;
+
+-out_drop_task:
++ result = proc_pid_instantiate(dir, dentry, task, NULL);
+ put_task_struct(task);
+ out:
+- put_task_struct(leader);
+-out_no_task:
+ return result;
+ }
+
+ /*
+- * Find the first tgid to return to user space.
+- *
+- * Usually this is just whatever follows &init_task, but if the users
+- * buffer was too small to hold the full list or there was a seek into
+- * the middle of the directory we have more work to do.
+- *
+- * In the case of a short read we start with find_task_by_pid.
++ * Find the first task with tgid >= tgid
+ *
+- * In the case of a seek we start with &init_task and walk nr
+- * threads past it.
+ */
+-static struct task_struct *first_tgid(int tgid, unsigned int nr)
++static struct task_struct *next_tgid(unsigned int tgid)
+ {
+- struct task_struct *pos;
+- rcu_read_lock();
+- if (tgid && nr) {
+- pos = find_task_by_pid(tgid);
+- if (pos && thread_group_leader(pos))
+- goto found;
+- }
+- /* If nr exceeds the number of processes get out quickly */
+- pos = NULL;
+- if (nr && nr >= nr_processes())
+- goto done;
++ struct task_struct *task;
++ struct pid *pid;
+
+- /* If we haven't found our starting place yet start with
+- * the init_task and walk nr tasks forward.
+- */
+- for (pos = next_task(&init_task); nr > 0; --nr) {
+- pos = next_task(pos);
+- if (pos == &init_task) {
+- pos = NULL;
+- goto done;
+- }
++ rcu_read_lock();
++retry:
++ task = NULL;
++ pid = find_ge_pid(tgid);
++ if (pid) {
++ tgid = pid->nr + 1;
++ task = pid_task(pid, PIDTYPE_PID);
++ /* What we to know is if the pid we have find is the
++ * pid of a thread_group_leader. Testing for task
++ * being a thread_group_leader is the obvious thing
++ * todo but there is a window when it fails, due to
++ * the pid transfer logic in de_thread.
++ *
++ * So we perform the straight forward test of seeing
++ * if the pid we have found is the pid of a thread
++ * group leader, and don't worry if the task we have
++ * found doesn't happen to be a thread group leader.
++ * As we don't care in the case of readdir.
++ */
++ if (!task || !has_group_leader_pid(task))
++ goto retry;
++ get_task_struct(task);
+ }
+-found:
+- get_task_struct(pos);
+-done:
+ rcu_read_unlock();
+- return pos;
++ return task;
+ }
+
+-/*
+- * Find the next task in the task list.
+- * Return NULL if we loop or there is any error.
+- *
+- * The reference to the input task_struct is released.
+- */
+-static struct task_struct *next_tgid(struct task_struct *start)
++#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
++
++static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
++ struct task_struct *task, int tgid)
+ {
+- struct task_struct *pos;
+- rcu_read_lock();
+- pos = start;
+- if (pid_alive(start))
+- pos = next_task(start);
+- if (pid_alive(pos) && (pos != &init_task)) {
+- get_task_struct(pos);
+- goto done;
+- }
+- pos = NULL;
+-done:
+- rcu_read_unlock();
+- put_task_struct(start);
+- return pos;
++ char name[PROC_NUMBUF];
++ int len = snprintf(name, sizeof(name), "%d", tgid);
++ return proc_fill_cache(filp, dirent, filldir, name, len,
++ proc_pid_instantiate, task, NULL);
+ }
+
+ /* for the /proc/ directory itself, after non-process stuff has been done */
+ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
+ {
+- char buf[PROC_NUMBUF];
+ unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
++ struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode);
+ struct task_struct *task;
+ int tgid;
+
+- if (!nr) {
+- ino_t ino = fake_ino(0,PROC_TGID_INO);
+- if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
+- return 0;
+- filp->f_pos++;
+- nr++;
++ if (!reaper)
++ goto out_no_task;
++
++ for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
++ struct pid_entry *p = &proc_base_stuff[nr];
++ if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
++ goto out;
+ }
+- nr -= 1;
+
+- /* f_version caches the tgid value that the last readdir call couldn't
+- * return. lseek aka telldir automagically resets f_version to 0.
+- */
+- tgid = filp->f_version;
+- filp->f_version = 0;
+- for (task = first_tgid(tgid, nr);
++ tgid = filp->f_pos - TGID_OFFSET;
++ for (task = next_tgid(tgid);
+ task;
+- task = next_tgid(task), filp->f_pos++) {
+- int len;
+- ino_t ino;
++ put_task_struct(task), task = next_tgid(tgid + 1)) {
+ tgid = task->pid;
+- len = snprintf(buf, sizeof(buf), "%d", tgid);
+- ino = fake_ino(tgid, PROC_TGID_INO);
+- if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
+- /* returning this tgid failed, save it as the first
+- * pid for the next readir call */
+- filp->f_version = tgid;
++ filp->f_pos = tgid + TGID_OFFSET;
++ if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) {
+ put_task_struct(task);
+- break;
++ goto out;
+ }
+ }
++ filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
++out:
++ put_task_struct(reaper);
++out_no_task:
+ return 0;
+ }
+
+ /*
++ * Tasks
++ */
++static struct pid_entry tid_base_stuff[] = {
++ DIR("fd", S_IRUSR|S_IXUSR, fd),
++ INF("environ", S_IRUSR, pid_environ),
++ INF("auxv", S_IRUSR, pid_auxv),
++ INF("status", S_IRUGO, pid_status),
++ INF("cmdline", S_IRUGO, pid_cmdline),
++ INF("stat", S_IRUGO, tid_stat),
++ INF("statm", S_IRUGO, pid_statm),
++ REG("maps", S_IRUGO, maps),
++#ifdef CONFIG_NUMA
++ REG("numa_maps", S_IRUGO, numa_maps),
++#endif
++ REG("mem", S_IRUSR|S_IWUSR, mem),
++#ifdef CONFIG_SECCOMP
++ REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
++#endif
++ LNK("cwd", cwd),
++ LNK("root", root),
++ LNK("exe", exe),
++ REG("mounts", S_IRUGO, mounts),
++#ifdef CONFIG_MMU
++ REG("smaps", S_IRUGO, smaps),
++#endif
++#ifdef CONFIG_SECURITY
++ DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
++#endif
++#ifdef CONFIG_KALLSYMS
++ INF("wchan", S_IRUGO, pid_wchan),
++#endif
++#ifdef CONFIG_SCHEDSTATS
++ INF("schedstat", S_IRUGO, pid_schedstat),
++#endif
++#ifdef CONFIG_CPUSETS
++ REG("cpuset", S_IRUGO, cpuset),
++#endif
++ INF("oom_score", S_IRUGO, oom_score),
++ REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
++#ifdef CONFIG_AUDITSYSCALL
++ REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
++#endif
++};
++
++static int proc_tid_base_readdir(struct file * filp,
++ void * dirent, filldir_t filldir)
++{
++ return proc_pident_readdir(filp,dirent,filldir,
++ tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
++}
++
++static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
++ return proc_pident_lookup(dir, dentry,
++ tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
++}
++
++static struct file_operations proc_tid_base_operations = {
++ .read = generic_read_dir,
++ .readdir = proc_tid_base_readdir,
++};
++
++static struct inode_operations proc_tid_base_inode_operations = {
++ .lookup = proc_tid_base_lookup,
++ .getattr = pid_getattr,
++ .setattr = proc_setattr,
++};
++
++static struct dentry *proc_task_instantiate(struct inode *dir,
++ struct dentry *dentry, struct task_struct *task, void *ptr)
++{
++ struct dentry *error = ERR_PTR(-ENOENT);
++ struct inode *inode;
++ inode = proc_pid_make_inode(dir->i_sb, task);
++
++ if (!inode)
++ goto out;
++ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
++ inode->i_op = &proc_tid_base_inode_operations;
++ inode->i_fop = &proc_tid_base_operations;
++ inode->i_flags|=S_IMMUTABLE;
++ inode->i_nlink = 3;
++#ifdef CONFIG_SECURITY
++ inode->i_nlink += 1;
++#endif
++
++ dentry->d_op = &pid_dentry_operations;
++
++ d_add(dentry, inode);
++ /* Close the race of the process dying before we return the dentry */
++ if (pid_revalidate(dentry, NULL))
++ error = NULL;
++out:
++ return error;
++}
++
++static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
++{
++ struct dentry *result = ERR_PTR(-ENOENT);
++ struct task_struct *task;
++ struct task_struct *leader = get_proc_task(dir);
++ unsigned tid;
++
++ if (!leader)
++ goto out_no_task;
++
++ tid = name_to_int(dentry);
++ if (tid == ~0U)
++ goto out;
++
++ rcu_read_lock();
++ task = find_task_by_pid(tid);
++ if (task)
++ get_task_struct(task);
++ rcu_read_unlock();
++ if (!task)
++ goto out;
++ if (leader->tgid != task->tgid)
++ goto out_drop_task;
++
++ result = proc_task_instantiate(dir, dentry, task, NULL);
++out_drop_task:
++ put_task_struct(task);
++out:
++ put_task_struct(leader);
++out_no_task:
++ return result;
++}
++
++/*
+ * Find the first tid of a thread group to return to user space.
+ *
+ * Usually this is just the thread group leader, but if the users
+@@ -2317,10 +2219,18 @@ static struct task_struct *next_tid(stru
+ return pos;
+ }
+
++static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
++ struct task_struct *task, int tid)
++{
++ char name[PROC_NUMBUF];
++ int len = snprintf(name, sizeof(name), "%d", tid);
++ return proc_fill_cache(filp, dirent, filldir, name, len,
++ proc_task_instantiate, task, NULL);
++}
++
+ /* for the /proc/TGID/task/ directories */
+ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
+ {
+- char buf[PROC_NUMBUF];
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct task_struct *leader = get_proc_task(inode);
+@@ -2357,11 +2267,8 @@ static int proc_task_readdir(struct file
+ for (task = first_tid(leader, tid, pos - 2);
+ task;
+ task = next_tid(task), pos++) {
+- int len;
+ tid = task->pid;
+- len = snprintf(buf, sizeof(buf), "%d", tid);
+- ino = fake_ino(tid, PROC_TID_INO);
+- if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
++ if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
+ /* returning this tgid failed, save it as the first
+ * pid for the next readir call */
+ filp->f_version = tid;
+@@ -2391,3 +2298,14 @@ static int proc_task_getattr(struct vfsm
+
+ return 0;
+ }
++
++static struct inode_operations proc_task_inode_operations = {
++ .lookup = proc_task_lookup,
++ .getattr = proc_task_getattr,
++ .setattr = proc_setattr,
++};
++
++static struct file_operations proc_task_operations = {
++ .read = generic_read_dir,
++ .readdir = proc_task_readdir,
++};
+diff --git a/fs/proc/internal.h b/fs/proc/internal.h
+index 146a434..987c773 100644
+--- a/fs/proc/internal.h
++++ b/fs/proc/internal.h
+@@ -28,6 +28,7 @@ do { \
+ (vmi)->largest_chunk = 0; \
+ } while(0)
+
++extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
+ #endif
+
+ extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
+diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
+index 6a984f6..1294eda 100644
+--- a/fs/proc/kcore.c
++++ b/fs/proc/kcore.c
+@@ -100,7 +100,7 @@ static int notesize(struct memelfnote *e
+ int sz;
+
+ sz = sizeof(struct elf_note);
+- sz += roundup(strlen(en->name), 4);
++ sz += roundup((strlen(en->name) + 1), 4);
+ sz += roundup(en->datasz, 4);
+
+ return sz;
+@@ -116,7 +116,7 @@ static char *storenote(struct memelfnote
+
+ #define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
+
+- en.n_namesz = strlen(men->name);
++ en.n_namesz = strlen(men->name) + 1;
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+@@ -279,12 +279,11 @@ read_kcore(struct file *file, char __use
+ tsz = elf_buflen - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+- elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
++ elf_buf = kzalloc(elf_buflen, GFP_ATOMIC);
+ if (!elf_buf) {
+ read_unlock(&kclist_lock);
+ return -ENOMEM;
+ }
+- memset(elf_buf, 0, elf_buflen);
+ elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
+ read_unlock(&kclist_lock);
+ if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
+@@ -330,10 +329,9 @@ read_kcore(struct file *file, char __use
+ unsigned long curstart = start;
+ unsigned long cursize = tsz;
+
+- elf_buf = kmalloc(tsz, GFP_KERNEL);
++ elf_buf = kzalloc(tsz, GFP_KERNEL);
+ if (!elf_buf)
+ return -ENOMEM;
+- memset(elf_buf, 0, tsz);
+
+ read_lock(&vmlist_lock);
+ for (m=vmlist; m && cursize; m=m->next) {
+diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
+index cff10ab..d7dbdf9 100644
+--- a/fs/proc/nommu.c
++++ b/fs/proc/nommu.c
+@@ -33,19 +33,15 @@
+ #include "internal.h"
+
+ /*
+- * display a list of all the VMAs the kernel knows about
+- * - nommu kernals have a single flat list
++ * display a single VMA to a sequenced file
+ */
+-static int nommu_vma_list_show(struct seq_file *m, void *v)
++int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
+ {
+- struct vm_area_struct *vma;
+ unsigned long ino = 0;
+ struct file *file;
+ dev_t dev = 0;
+ int flags, len;
+
+- vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
+-
+ flags = vma->vm_flags;
+ file = vma->vm_file;
+
+@@ -78,6 +74,18 @@ static int nommu_vma_list_show(struct se
+ return 0;
+ }
+
++/*
++ * display a list of all the VMAs the kernel knows about
++ * - nommu kernals have a single flat list
++ */
++static int nommu_vma_list_show(struct seq_file *m, void *v)
++{
++ struct vm_area_struct *vma;
++
++ vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
++ return nommu_vma_show(m, vma);
++}
++
+ static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos)
+ {
+ struct rb_node *_rb;
+diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
+index 9421562..93c43b6 100644
+--- a/fs/proc/proc_misc.c
++++ b/fs/proc/proc_misc.c
+@@ -45,6 +45,7 @@
+ #include <linux/sysrq.h>
+ #include <linux/vmalloc.h>
+ #include <linux/crash_dump.h>
++#include <linux/pspace.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+ #include <asm/io.h>
+@@ -91,7 +92,7 @@ static int loadavg_read_proc(char *page,
+ LOAD_INT(a), LOAD_FRAC(a),
+ LOAD_INT(b), LOAD_FRAC(b),
+ LOAD_INT(c), LOAD_FRAC(c),
+- nr_running(), nr_threads, last_pid);
++ nr_running(), nr_threads, init_pspace.last_pid);
+ return proc_calc_metrics(page, start, off, count, eof, len);
+ }
+
+@@ -157,10 +158,12 @@ static int meminfo_read_proc(char *page,
+ "SwapCached: %8lu kB\n"
+ "Active: %8lu kB\n"
+ "Inactive: %8lu kB\n"
++#ifdef CONFIG_HIGHMEM
+ "HighTotal: %8lu kB\n"
+ "HighFree: %8lu kB\n"
+ "LowTotal: %8lu kB\n"
+ "LowFree: %8lu kB\n"
++#endif
+ "SwapTotal: %8lu kB\n"
+ "SwapFree: %8lu kB\n"
+ "Dirty: %8lu kB\n"
+@@ -168,6 +171,8 @@ static int meminfo_read_proc(char *page,
+ "AnonPages: %8lu kB\n"
+ "Mapped: %8lu kB\n"
+ "Slab: %8lu kB\n"
++ "SReclaimable: %8lu kB\n"
++ "SUnreclaim: %8lu kB\n"
+ "PageTables: %8lu kB\n"
+ "NFS_Unstable: %8lu kB\n"
+ "Bounce: %8lu kB\n"
+@@ -183,17 +188,22 @@ static int meminfo_read_proc(char *page,
+ K(total_swapcache_pages),
+ K(active),
+ K(inactive),
++#ifdef CONFIG_HIGHMEM
+ K(i.totalhigh),
+ K(i.freehigh),
+ K(i.totalram-i.totalhigh),
+ K(i.freeram-i.freehigh),
++#endif
+ K(i.totalswap),
+ K(i.freeswap),
+ K(global_page_state(NR_FILE_DIRTY)),
+ K(global_page_state(NR_WRITEBACK)),
+ K(global_page_state(NR_ANON_PAGES)),
+ K(global_page_state(NR_FILE_MAPPED)),
+- K(global_page_state(NR_SLAB)),
++ K(global_page_state(NR_SLAB_RECLAIMABLE) +
++ global_page_state(NR_SLAB_UNRECLAIMABLE)),
++ K(global_page_state(NR_SLAB_RECLAIMABLE)),
++ K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
+ K(global_page_state(NR_PAGETABLE)),
+ K(global_page_state(NR_UNSTABLE_NFS)),
+ K(global_page_state(NR_BOUNCE)),
+@@ -268,12 +278,15 @@ static int devinfo_show(struct seq_file
+ if (i == 0)
+ seq_printf(f, "Character devices:\n");
+ chrdev_show(f, i);
+- } else {
++ }
++#ifdef CONFIG_BLOCK
++ else {
+ i -= CHRDEV_MAJOR_HASH_SIZE;
+ if (i == 0)
+ seq_printf(f, "\nBlock devices:\n");
+ blkdev_show(f, i);
+ }
++#endif
+ return 0;
+ }
+
+@@ -346,6 +359,7 @@ static int stram_read_proc(char *page, c
+ }
+ #endif
+
++#ifdef CONFIG_BLOCK
+ extern struct seq_operations partitions_op;
+ static int partitions_open(struct inode *inode, struct file *file)
+ {
+@@ -369,6 +383,7 @@ static struct file_operations proc_disks
+ .llseek = seq_lseek,
+ .release = seq_release,
+ };
++#endif
+
+ #ifdef CONFIG_MODULES
+ extern struct seq_operations modules_op;
+@@ -632,7 +647,7 @@ static ssize_t write_sysrq_trigger(struc
+
+ if (get_user(c, buf))
+ return -EFAULT;
+- __handle_sysrq(c, NULL, NULL, 0);
++ __handle_sysrq(c, NULL, 0);
+ }
+ return count;
+ }
+@@ -686,7 +701,9 @@ void __init proc_misc_init(void)
+ entry->proc_fops = &proc_kmsg_operations;
+ create_seq_entry("devices", 0, &proc_devinfo_operations);
+ create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
++#ifdef CONFIG_BLOCK
+ create_seq_entry("partitions", 0, &proc_partitions_operations);
++#endif
+ create_seq_entry("stat", 0, &proc_stat_operations);
+ create_seq_entry("interrupts", 0, &proc_interrupts_operations);
+ #ifdef CONFIG_SLAB
+@@ -698,7 +715,9 @@ void __init proc_misc_init(void)
+ create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
+ create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
+ create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
++#ifdef CONFIG_BLOCK
+ create_seq_entry("diskstats", 0, &proc_diskstats_operations);
++#endif
+ #ifdef CONFIG_MODULES
+ create_seq_entry("modules", 0, &proc_modules_operations);
+ #endif
+diff --git a/fs/proc/root.c b/fs/proc/root.c
+index 8901c65..ffe66c3 100644
+--- a/fs/proc/root.c
++++ b/fs/proc/root.c
+@@ -16,6 +16,7 @@
+ #include <linux/module.h>
+ #include <linux/bitops.h>
+ #include <linux/smp_lock.h>
++#include <linux/mount.h>
+
+ #include "internal.h"
+
+@@ -28,6 +29,17 @@ struct proc_dir_entry *proc_sys_root;
+ static int proc_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+ {
++ if (proc_mnt) {
++ /* Seed the root directory with a pid so it doesn't need
++ * to be special in base.c. I would do this earlier but
++ * the only task alive when /proc is mounted the first time
++ * is the init_task and it doesn't have any pids.
++ */
++ struct proc_inode *ei;
++ ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode);
++ if (!ei->pid)
++ ei->pid = find_get_pid(1);
++ }
+ return get_sb_single(fs_type, flags, data, proc_fill_super, mnt);
+ }
+
+diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
+index 0a163a4..6b769af 100644
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -122,11 +122,6 @@ struct mem_size_stats
+ unsigned long private_dirty;
+ };
+
+-__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
+-{
+- return NULL;
+-}
+-
+ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
+ {
+ struct proc_maps_private *priv = m->private;
+diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
+index 4616ed5..091aa8e 100644
+--- a/fs/proc/task_nommu.c
++++ b/fs/proc/task_nommu.c
+@@ -138,25 +138,63 @@ out:
+ }
+
+ /*
+- * Albert D. Cahalan suggested to fake entries for the traditional
+- * sections here. This might be worth investigating.
++ * display mapping lines for a particular process's /proc/pid/maps
+ */
+-static int show_map(struct seq_file *m, void *v)
++static int show_map(struct seq_file *m, void *_vml)
+ {
+- return 0;
++ struct vm_list_struct *vml = _vml;
++ return nommu_vma_show(m, vml->vma);
+ }
++
+ static void *m_start(struct seq_file *m, loff_t *pos)
+ {
++ struct proc_maps_private *priv = m->private;
++ struct vm_list_struct *vml;
++ struct mm_struct *mm;
++ loff_t n = *pos;
++
++ /* pin the task and mm whilst we play with them */
++ priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
++ if (!priv->task)
++ return NULL;
++
++ mm = get_task_mm(priv->task);
++ if (!mm) {
++ put_task_struct(priv->task);
++ priv->task = NULL;
++ return NULL;
++ }
++
++ down_read(&mm->mmap_sem);
++
++ /* start from the Nth VMA */
++ for (vml = mm->context.vmlist; vml; vml = vml->next)
++ if (n-- == 0)
++ return vml;
+ return NULL;
+ }
+-static void m_stop(struct seq_file *m, void *v)
++
++static void m_stop(struct seq_file *m, void *_vml)
+ {
++ struct proc_maps_private *priv = m->private;
++
++ if (priv->task) {
++ struct mm_struct *mm = priv->task->mm;
++ up_read(&mm->mmap_sem);
++ mmput(mm);
++ put_task_struct(priv->task);
++ }
+ }
+-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
++
++static void *m_next(struct seq_file *m, void *_vml, loff_t *pos)
+ {
+- return NULL;
++ struct vm_list_struct *vml = _vml;
++
++ (*pos)++;
++ return vml ? vml->next : NULL;
+ }
+-static struct seq_operations proc_pid_maps_op = {
++
++static struct seq_operations proc_pid_maps_ops = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+@@ -165,11 +203,19 @@ static struct seq_operations proc_pid_ma
+
+ static int maps_open(struct inode *inode, struct file *file)
+ {
+- int ret;
+- ret = seq_open(file, &proc_pid_maps_op);
+- if (!ret) {
+- struct seq_file *m = file->private_data;
+- m->private = NULL;
++ struct proc_maps_private *priv;
++ int ret = -ENOMEM;
++
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (priv) {
++ priv->pid = proc_pid(inode);
++ ret = seq_open(file, &proc_pid_maps_ops);
++ if (!ret) {
++ struct seq_file *m = file->private_data;
++ m->private = priv;
++ } else {
++ kfree(priv);
++ }
+ }
+ return ret;
+ }
+@@ -178,6 +224,6 @@ struct file_operations proc_maps_operati
+ .open = maps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+- .release = seq_release,
++ .release = seq_release_private,
+ };
+
+diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
+index 62af4b1..467e5ac 100644
+--- a/fs/qnx4/file.c
++++ b/fs/qnx4/file.c
+@@ -22,11 +22,13 @@
+ const struct file_operations qnx4_file_operations =
+ {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
+ .mmap = generic_file_mmap,
+ .sendfile = generic_file_sendfile,
+ #ifdef CONFIG_QNX4FS_RW
+- .write = generic_file_write,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .fsync = qnx4_sync_file,
+ #endif
+ };
+diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
+index 5a90349..5a41db2 100644
+--- a/fs/qnx4/inode.c
++++ b/fs/qnx4/inode.c
+@@ -358,11 +358,10 @@ static int qnx4_fill_super(struct super_
+ const char *errmsg;
+ struct qnx4_sb_info *qs;
+
+- qs = kmalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
++ qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
+ if (!qs)
+ return -ENOMEM;
+ s->s_fs_info = qs;
+- memset(qs, 0, sizeof(struct qnx4_sb_info));
+
+ sb_set_blocksize(s, QNX4_BLOCK_SIZE);
+
+@@ -497,7 +496,6 @@ static void qnx4_read_inode(struct inode
+ inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->di_ctime);
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);
+- inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
+
+ memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE);
+ if (S_ISREG(inode->i_mode)) {
+@@ -557,9 +555,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(qnx4_inode_cachep))
+- printk(KERN_INFO
+- "qnx4_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(qnx4_inode_cachep);
+ }
+
+ static int qnx4_get_sb(struct file_system_type *fs_type,
+diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
+index c3d83f6..733cdf0 100644
+--- a/fs/qnx4/namei.c
++++ b/fs/qnx4/namei.c
+@@ -186,11 +186,10 @@ int qnx4_rmdir(struct inode *dir, struct
+ memset(de->di_fname, 0, sizeof de->di_fname);
+ de->di_mode = 0;
+ mark_buffer_dirty(bh);
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ mark_inode_dirty(inode);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+- dir->i_nlink--;
+- mark_inode_dirty(dir);
++ inode_dec_link_count(dir);
+ retval = 0;
+
+ end_rmdir:
+@@ -234,9 +233,8 @@ int qnx4_unlink(struct inode *dir, struc
+ mark_buffer_dirty(bh);
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ mark_inode_dirty(dir);
+- inode->i_nlink--;
+ inode->i_ctime = dir->i_ctime;
+- mark_inode_dirty(inode);
++ inode_dec_link_count(inode);
+ retval = 0;
+
+ end_unlink:
+diff --git a/fs/quota.c b/fs/quota.c
+index d6a2be8..b9dae76 100644
+--- a/fs/quota.c
++++ b/fs/quota.c
+@@ -338,6 +338,34 @@ static int do_quotactl(struct super_bloc
+ }
+
+ /*
++ * look up a superblock on which quota ops will be performed
++ * - use the name of a block device to find the superblock thereon
++ */
++static inline struct super_block *quotactl_block(const char __user *special)
++{
++#ifdef CONFIG_BLOCK
++ struct block_device *bdev;
++ struct super_block *sb;
++ char *tmp = getname(special);
++
++ if (IS_ERR(tmp))
++ return ERR_PTR(PTR_ERR(tmp));
++ bdev = lookup_bdev(tmp);
++ putname(tmp);
++ if (IS_ERR(bdev))
++ return ERR_PTR(PTR_ERR(bdev));
++ sb = get_super(bdev);
++ bdput(bdev);
++ if (!sb)
++ return ERR_PTR(-ENODEV);
++
++ return sb;
++#else
++ return ERR_PTR(-ENODEV);
++#endif
++}
++
++/*
+ * This is the system call interface. This communicates with
+ * the user-level programs. Currently this only supports diskquota
+ * calls. Maybe we need to add the process quotas etc. in the future,
+@@ -347,25 +375,15 @@ asmlinkage long sys_quotactl(unsigned in
+ {
+ uint cmds, type;
+ struct super_block *sb = NULL;
+- struct block_device *bdev;
+- char *tmp;
+ int ret;
+
+ cmds = cmd >> SUBCMDSHIFT;
+ type = cmd & SUBCMDMASK;
+
+ if (cmds != Q_SYNC || special) {
+- tmp = getname(special);
+- if (IS_ERR(tmp))
+- return PTR_ERR(tmp);
+- bdev = lookup_bdev(tmp);
+- putname(tmp);
+- if (IS_ERR(bdev))
+- return PTR_ERR(bdev);
+- sb = get_super(bdev);
+- bdput(bdev);
+- if (!sb)
+- return -ENODEV;
++ sb = quotactl_block(special);
++ if (IS_ERR(sb))
++ return PTR_ERR(sb);
+ }
+
+ ret = check_quotactl_valid(sb, type, cmds, id);
+diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
+index 86f14ca..0947fb5 100644
+--- a/fs/ramfs/file-mmu.c
++++ b/fs/ramfs/file-mmu.c
+@@ -33,8 +33,10 @@ const struct address_space_operations ra
+ };
+
+ const struct file_operations ramfs_file_operations = {
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .fsync = simple_sync_file,
+ .sendfile = generic_file_sendfile,
+diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
+index 677139b..bfe5dbf 100644
+--- a/fs/ramfs/file-nommu.c
++++ b/fs/ramfs/file-nommu.c
+@@ -36,8 +36,10 @@ const struct address_space_operations ra
+ const struct file_operations ramfs_file_operations = {
+ .mmap = ramfs_nommu_mmap,
+ .get_unmapped_area = ramfs_nommu_get_unmapped_area,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .fsync = simple_sync_file,
+ .sendfile = generic_file_sendfile,
+ .llseek = generic_file_llseek,
+diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
+index b967733..2faf4cd 100644
+--- a/fs/ramfs/inode.c
++++ b/fs/ramfs/inode.c
+@@ -58,7 +58,6 @@ struct inode *ramfs_get_inode(struct sup
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->a_ops = &ramfs_aops;
+ inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
+@@ -76,7 +75,7 @@ struct inode *ramfs_get_inode(struct sup
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ break;
+ case S_IFLNK:
+ inode->i_op = &page_symlink_inode_operations;
+@@ -114,7 +113,7 @@ static int ramfs_mkdir(struct inode * di
+ {
+ int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+ if (!retval)
+- dir->i_nlink++;
++ inc_nlink(dir);
+ return retval;
+ }
+
+diff --git a/fs/read_write.c b/fs/read_write.c
+index d4cb318..f792000 100644
+--- a/fs/read_write.c
++++ b/fs/read_write.c
+@@ -15,13 +15,15 @@
+ #include <linux/module.h>
+ #include <linux/syscalls.h>
+ #include <linux/pagemap.h>
++#include "read_write.h"
+
+ #include <asm/uaccess.h>
+ #include <asm/unistd.h>
+
+ const struct file_operations generic_ro_fops = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
+ .mmap = generic_file_readonly_mmap,
+ .sendfile = generic_file_sendfile,
+ };
+@@ -227,14 +229,20 @@ static void wait_on_retry_sync_kiocb(str
+
+ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+ {
++ struct iovec iov = { .iov_base = buf, .iov_len = len };
+ struct kiocb kiocb;
+ ssize_t ret;
+
+ init_sync_kiocb(&kiocb, filp);
+ kiocb.ki_pos = *ppos;
+- while (-EIOCBRETRY ==
+- (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos)))
++ kiocb.ki_left = len;
++
++ for (;;) {
++ ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
++ if (ret != -EIOCBRETRY)
++ break;
+ wait_on_retry_sync_kiocb(&kiocb);
++ }
+
+ if (-EIOCBQUEUED == ret)
+ ret = wait_on_sync_kiocb(&kiocb);
+@@ -279,14 +287,20 @@ EXPORT_SYMBOL(vfs_read);
+
+ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
+ {
++ struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
+ struct kiocb kiocb;
+ ssize_t ret;
+
+ init_sync_kiocb(&kiocb, filp);
+ kiocb.ki_pos = *ppos;
+- while (-EIOCBRETRY ==
+- (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos)))
++ kiocb.ki_left = len;
++
++ for (;;) {
++ ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
++ if (ret != -EIOCBRETRY)
++ break;
+ wait_on_retry_sync_kiocb(&kiocb);
++ }
+
+ if (-EIOCBQUEUED == ret)
+ ret = wait_on_sync_kiocb(&kiocb);
+@@ -438,78 +452,155 @@ unsigned long iov_shorten(struct iovec *
+
+ EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */
+
++ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
++ unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
++{
++ struct kiocb kiocb;
++ ssize_t ret;
++
++ init_sync_kiocb(&kiocb, filp);
++ kiocb.ki_pos = *ppos;
++ kiocb.ki_left = len;
++ kiocb.ki_nbytes = len;
++
++ for (;;) {
++ ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
++ if (ret != -EIOCBRETRY)
++ break;
++ wait_on_retry_sync_kiocb(&kiocb);
++ }
++
++ if (ret == -EIOCBQUEUED)
++ ret = wait_on_sync_kiocb(&kiocb);
++ *ppos = kiocb.ki_pos;
++ return ret;
++}
++
++/* Do it by hand, with file-ops */
++ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
++ unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
++{
++ struct iovec *vector = iov;
++ ssize_t ret = 0;
++
++ while (nr_segs > 0) {
++ void __user *base;
++ size_t len;
++ ssize_t nr;
++
++ base = vector->iov_base;
++ len = vector->iov_len;
++ vector++;
++ nr_segs--;
++
++ nr = fn(filp, base, len, ppos);
++
++ if (nr < 0) {
++ if (!ret)
++ ret = nr;
++ break;
++ }
++ ret += nr;
++ if (nr != len)
++ break;
++ }
++
++ return ret;
++}
++
+ /* A write operation does a read from user space and vice versa */
+ #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
+
++ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
++ unsigned long nr_segs, unsigned long fast_segs,
++ struct iovec *fast_pointer,
++ struct iovec **ret_pointer)
++ {
++ unsigned long seg;
++ ssize_t ret;
++ struct iovec *iov = fast_pointer;
++
++ /*
++ * SuS says "The readv() function *may* fail if the iovcnt argument
++ * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
++ * traditionally returned zero for zero segments, so...
++ */
++ if (nr_segs == 0) {
++ ret = 0;
++ goto out;
++ }
++
++ /*
++ * First get the "struct iovec" from user memory and
++ * verify all the pointers
++ */
++ if (nr_segs > UIO_MAXIOV) {
++ ret = -EINVAL;
++ goto out;
++ }
++ if (nr_segs > fast_segs) {
++ iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
++ if (iov == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ }
++ if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /*
++ * According to the Single Unix Specification we should return EINVAL
++ * if an element length is < 0 when cast to ssize_t or if the
++ * total length would overflow the ssize_t return value of the
++ * system call.
++ */
++ ret = 0;
++ for (seg = 0; seg < nr_segs; seg++) {
++ void __user *buf = iov[seg].iov_base;
++ ssize_t len = (ssize_t)iov[seg].iov_len;
++
++ /* see if we we're about to use an invalid len or if
++ * it's about to overflow ssize_t */
++ if (len < 0 || (ret + len < ret)) {
++ ret = -EINVAL;
++ goto out;
++ }
++ if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret += len;
++ }
++out:
++ *ret_pointer = iov;
++ return ret;
++}
++
+ static ssize_t do_readv_writev(int type, struct file *file,
+ const struct iovec __user * uvector,
+ unsigned long nr_segs, loff_t *pos)
+ {
+- typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
+- typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
+-
+ size_t tot_len;
+ struct iovec iovstack[UIO_FASTIOV];
+- struct iovec *iov=iovstack, *vector;
++ struct iovec *iov = iovstack;
+ ssize_t ret;
+- int seg;
+ io_fn_t fn;
+ iov_fn_t fnv;
+
+- /*
+- * SuS says "The readv() function *may* fail if the iovcnt argument
+- * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
+- * traditionally returned zero for zero segments, so...
+- */
+- ret = 0;
+- if (nr_segs == 0)
++ if (!file->f_op) {
++ ret = -EINVAL;
+ goto out;
++ }
+
+- /*
+- * First get the "struct iovec" from user memory and
+- * verify all the pointers
+- */
+- ret = -EINVAL;
+- if (nr_segs > UIO_MAXIOV)
+- goto out;
+- if (!file->f_op)
+- goto out;
+- if (nr_segs > UIO_FASTIOV) {
+- ret = -ENOMEM;
+- iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+- if (!iov)
+- goto out;
+- }
+- ret = -EFAULT;
+- if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))
++ ret = rw_copy_check_uvector(type, uvector, nr_segs,
++ ARRAY_SIZE(iovstack), iovstack, &iov);
++ if (ret <= 0)
+ goto out;
+
+- /*
+- * Single unix specification:
+- * We should -EINVAL if an element length is not >= 0 and fitting an
+- * ssize_t. The total length is fitting an ssize_t
+- *
+- * Be careful here because iov_len is a size_t not an ssize_t
+- */
+- tot_len = 0;
+- ret = -EINVAL;
+- for (seg = 0; seg < nr_segs; seg++) {
+- void __user *buf = iov[seg].iov_base;
+- ssize_t len = (ssize_t)iov[seg].iov_len;
+-
+- if (len < 0) /* size_t not fitting an ssize_t .. */
+- goto out;
+- if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
+- goto Efault;
+- tot_len += len;
+- if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
+- goto out;
+- }
+- if (tot_len == 0) {
+- ret = 0;
+- goto out;
+- }
+-
++ tot_len = ret;
+ ret = rw_verify_area(type, file, pos, tot_len);
+ if (ret < 0)
+ goto out;
+@@ -520,39 +611,18 @@ static ssize_t do_readv_writev(int type,
+ fnv = NULL;
+ if (type == READ) {
+ fn = file->f_op->read;
+- fnv = file->f_op->readv;
++ fnv = file->f_op->aio_read;
+ } else {
+ fn = (io_fn_t)file->f_op->write;
+- fnv = file->f_op->writev;
++ fnv = file->f_op->aio_write;
+ }
+- if (fnv) {
+- ret = fnv(file, iov, nr_segs, pos);
+- goto out;
+- }
+-
+- /* Do it by hand, with file-ops */
+- ret = 0;
+- vector = iov;
+- while (nr_segs > 0) {
+- void __user * base;
+- size_t len;
+- ssize_t nr;
+
+- base = vector->iov_base;
+- len = vector->iov_len;
+- vector++;
+- nr_segs--;
+-
+- nr = fn(file, base, len, pos);
++ if (fnv)
++ ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
++ pos, fnv);
++ else
++ ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
+
+- if (nr < 0) {
+- if (!ret) ret = nr;
+- break;
+- }
+- ret += nr;
+- if (nr != len)
+- break;
+- }
+ out:
+ if (iov != iovstack)
+ kfree(iov);
+@@ -563,9 +633,6 @@ out:
+ fsnotify_modify(file->f_dentry);
+ }
+ return ret;
+-Efault:
+- ret = -EFAULT;
+- goto out;
+ }
+
+ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
+@@ -573,7 +640,7 @@ ssize_t vfs_readv(struct file *file, con
+ {
+ if (!(file->f_mode & FMODE_READ))
+ return -EBADF;
+- if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
++ if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
+ return -EINVAL;
+
+ return do_readv_writev(READ, file, vec, vlen, pos);
+@@ -586,7 +653,7 @@ ssize_t vfs_writev(struct file *file, co
+ {
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EBADF;
+- if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
++ if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
+ return -EINVAL;
+
+ return do_readv_writev(WRITE, file, vec, vlen, pos);
+diff --git a/fs/read_write.h b/fs/read_write.h
+new file mode 100644
+index 0000000..d07b954
+--- /dev/null
++++ b/fs/read_write.h
+@@ -0,0 +1,14 @@
++/*
++ * This file is only for sharing some helpers from read_write.c with compat.c.
++ * Don't use anywhere else.
++ */
++
++
++typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
++typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
++ unsigned long, loff_t);
++
++ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
++ unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn);
++ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
++ unsigned long nr_segs, loff_t *ppos, io_fn_t fn);
+diff --git a/fs/readdir.c b/fs/readdir.c
+index b610932..bff3ee5 100644
+--- a/fs/readdir.c
++++ b/fs/readdir.c
+@@ -69,20 +69,24 @@ struct readdir_callback {
+ };
+
+ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
+- ino_t ino, unsigned int d_type)
++ u64 ino, unsigned int d_type)
+ {
+ struct readdir_callback * buf = (struct readdir_callback *) __buf;
+ struct old_linux_dirent __user * dirent;
++ unsigned long d_ino;
+
+ if (buf->result)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ buf->result++;
+ dirent = buf->dirent;
+ if (!access_ok(VERIFY_WRITE, dirent,
+ (unsigned long)(dirent->d_name + namlen + 1) -
+ (unsigned long)dirent))
+ goto efault;
+- if ( __put_user(ino, &dirent->d_ino) ||
++ if ( __put_user(d_ino, &dirent->d_ino) ||
+ __put_user(offset, &dirent->d_offset) ||
+ __put_user(namlen, &dirent->d_namlen) ||
+ __copy_to_user(dirent->d_name, name, namlen) ||
+@@ -138,22 +142,26 @@ struct getdents_callback {
+ };
+
+ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
+- ino_t ino, unsigned int d_type)
++ u64 ino, unsigned int d_type)
+ {
+ struct linux_dirent __user * dirent;
+ struct getdents_callback * buf = (struct getdents_callback *) __buf;
++ unsigned long d_ino;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
++ d_ino = ino;
++ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
++ return -EOVERFLOW;
+ dirent = buf->previous;
+ if (dirent) {
+ if (__put_user(offset, &dirent->d_off))
+ goto efault;
+ }
+ dirent = buf->current_dir;
+- if (__put_user(ino, &dirent->d_ino))
++ if (__put_user(d_ino, &dirent->d_ino))
+ goto efault;
+ if (__put_user(reclen, &dirent->d_reclen))
+ goto efault;
+@@ -222,7 +230,7 @@ struct getdents_callback64 {
+ };
+
+ static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
+- ino_t ino, unsigned int d_type)
++ u64 ino, unsigned int d_type)
+ {
+ struct linux_dirent64 __user *dirent;
+ struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
+diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile
+index 3a59309..0eb7ac0 100644
+--- a/fs/reiserfs/Makefile
++++ b/fs/reiserfs/Makefile
+@@ -28,7 +28,7 @@ endif
+ # will work around it. If any other architecture displays this behavior,
+ # add it here.
+ ifeq ($(CONFIG_PPC32),y)
+-EXTRA_CFLAGS := -O1
++EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0400, -O1)
+ endif
+
+ TAGS:
+diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
+index 4a7dbde..e3d466a 100644
+--- a/fs/reiserfs/bitmap.c
++++ b/fs/reiserfs/bitmap.c
+@@ -9,6 +9,7 @@
+ #include <linux/buffer_head.h>
+ #include <linux/kernel.h>
+ #include <linux/pagemap.h>
++#include <linux/vmalloc.h>
+ #include <linux/reiserfs_fs_sb.h>
+ #include <linux/reiserfs_fs_i.h>
+ #include <linux/quotaops.h>
+@@ -50,16 +51,15 @@ static inline void get_bit_address(struc
+ {
+ /* 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);
++ *bmap_nr = block >> (s->s_blocksize_bits + 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 i, j;
++ int bmap, offset;
+
+ if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
+ reiserfs_warning(s,
+@@ -68,36 +68,32 @@ int is_reusable(struct super_block *s, b
+ 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) {
++ get_bit_address(s, block, &bmap, &offset);
++
++ /* Old format filesystem? Unlikely, but the bitmaps are all up front so
++ * we need to account for it. */
++ if (unlikely(test_bit(REISERFS_OLD_FORMAT,
++ &(REISERFS_SB(s)->s_properties)))) {
++ b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
++ if (block >= bmap1 && block <= bmap1 + SB_BMAP_NR(s)) {
++ reiserfs_warning(s, "vs: 4019: is_reusable: "
++ "bitmap block %lu(%u) can't be freed or reused",
++ block, SB_BMAP_NR(s));
++ return 0;
++ }
++ } else {
++ if (offset == 0) {
+ reiserfs_warning(s, "vs: 4020: is_reusable: "
+ "bitmap block %lu(%u) can't be freed or reused",
+ block, SB_BMAP_NR(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;
+ }
+
+- 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)) {
++ if (bmap >= SB_BMAP_NR(s)) {
+ 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));
+-
++ "vs-4030: is_reusable: there is no so many bitmap blocks: "
++ "block=%lu, bitmap_nr=%d", block, bmap);
+ return 0;
+ }
+
+@@ -141,6 +137,7 @@ static int scan_bitmap_block(struct reis
+ {
+ struct super_block *s = th->t_super;
+ struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n];
++ struct buffer_head *bh;
+ int end, next;
+ int org = *beg;
+
+@@ -159,22 +156,25 @@ static int scan_bitmap_block(struct reis
+ bmap_n);
+ return 0;
+ }
+- if (buffer_locked(bi->bh)) {
+- PROC_INFO_INC(s, scan_bitmap.wait);
+- __wait_on_buffer(bi->bh);
+- }
++
++ bh = reiserfs_read_bitmap_block(s, bmap_n);
++ if (bh == NULL)
++ return 0;
+
+ while (1) {
+ cont:
+- if (bi->free_count < min)
++ if (bi->free_count < min) {
++ brelse(bh);
+ 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);
++ ((unsigned long *)(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 */
++ brelse(bh);
+ return 0;
+ }
+
+@@ -183,7 +183,7 @@ static int scan_bitmap_block(struct reis
+ /* 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)) {
++ || reiserfs_test_le_bit(end, bh->b_data)) {
+ next = end;
+ break;
+ }
+@@ -197,12 +197,12 @@ static int scan_bitmap_block(struct reis
+ * (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);
++ reiserfs_prepare_for_journal(s, 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)) {
++ (i, bh->b_data)) {
+ /* bit was set by another process
+ * while we slept in prepare_for_journal() */
+ PROC_INFO_INC(s, scan_bitmap.stolen);
+@@ -214,17 +214,16 @@ static int scan_bitmap_block(struct reis
+ /* 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);
++ (i, bh->b_data);
++ reiserfs_restore_prepared_buffer(s, 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);
++ journal_mark_dirty(th, s, bh);
++ brelse(bh);
+
+ /* free block count calculation */
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
+@@ -266,9 +265,20 @@ static int bmap_hash_id(struct super_blo
+ */
+ 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)) {
++ int bm = bmap_hash_id(s, id);
++ struct reiserfs_bitmap_info *info = &SB_AP_BITMAP(s)[bm];
++
++ /* If we don't have cached information on this bitmap block, we're
++ * going to have to load it later anyway. Loading it here allows us
++ * to make a better decision. This favors long-term performace gain
++ * with a better on-disk layout vs. a short term gain of skipping the
++ * read and potentially having a bad placement. */
++ if (info->first_zero_hint == 0) {
++ struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm);
++ brelse(bh);
++ }
++
++ if (info->free_count > ((s->s_blocksize << 3) * 60 / 100)) {
+ return 0;
+ }
+ return 1;
+@@ -373,7 +383,7 @@ static void _reiserfs_free_block(struct
+ {
+ struct super_block *s = th->t_super;
+ struct reiserfs_super_block *rs;
+- struct buffer_head *sbh;
++ struct buffer_head *sbh, *bmbh;
+ struct reiserfs_bitmap_info *apbi;
+ int nr, offset;
+
+@@ -394,16 +404,21 @@ static void _reiserfs_free_block(struct
+ return;
+ }
+
+- reiserfs_prepare_for_journal(s, apbi[nr].bh, 1);
++ bmbh = reiserfs_read_bitmap_block(s, nr);
++ if (!bmbh)
++ return;
++
++ reiserfs_prepare_for_journal(s, bmbh, 1);
+
+ /* clear bit for the given block in bit map */
+- if (!reiserfs_test_and_clear_le_bit(offset, apbi[nr].bh->b_data)) {
++ if (!reiserfs_test_and_clear_le_bit(offset, bmbh->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);
++ journal_mark_dirty(th, s, bmbh);
++ brelse(bmbh);
+
+ reiserfs_prepare_for_journal(s, sbh, 1);
+ /* update super block */
+@@ -1019,7 +1034,6 @@ static inline int blocknrs_and_prealloc_
+ 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) {
+@@ -1046,28 +1060,9 @@ static inline int blocknrs_and_prealloc_
+ hint->preallocate = hint->prealloc_size = 0;
+ }
+ /* 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;
+@@ -1105,8 +1100,7 @@ static inline int blocknrs_and_prealloc_
+ new_blocknrs +
+ nr_allocated,
+ start, finish,
+- bigalloc ?
+- bigalloc : 1,
++ 1,
+ amount_needed -
+ nr_allocated,
+ hint->
+@@ -1263,3 +1257,89 @@ int reiserfs_can_fit_pages(struct super_
+
+ return space > 0 ? space : 0;
+ }
++
++void reiserfs_cache_bitmap_metadata(struct super_block *sb,
++ struct buffer_head *bh,
++ struct reiserfs_bitmap_info *info)
++{
++ unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size);
++
++ info->first_zero_hint = 1 << (sb->s_blocksize_bits + 3);
++
++ while (--cur >= (unsigned long *)bh->b_data) {
++ int base = ((char *)cur - bh->b_data) << 3;
++
++ /* 0 and ~0 are special, we can optimize for them */
++ if (*cur == 0) {
++ info->first_zero_hint = base;
++ info->free_count += BITS_PER_LONG;
++ } else if (*cur != ~0L) { /* A mix, investigate */
++ int b;
++ for (b = BITS_PER_LONG - 1; b >= 0; b--) {
++ if (!reiserfs_test_le_bit(b, cur)) {
++ info->first_zero_hint = base + b;
++ info->free_count++;
++ }
++ }
++ }
++ }
++ /* The first bit must ALWAYS be 1 */
++ BUG_ON(info->first_zero_hint == 0);
++}
++
++struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
++ unsigned int bitmap)
++{
++ b_blocknr_t block = (sb->s_blocksize << 3) * bitmap;
++ struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap;
++ struct buffer_head *bh;
++
++ /* Way old format filesystems had the bitmaps packed up front.
++ * I doubt there are any of these left, but just in case... */
++ if (unlikely(test_bit(REISERFS_OLD_FORMAT,
++ &(REISERFS_SB(sb)->s_properties))))
++ block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap;
++ else if (bitmap == 0)
++ block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
++
++ bh = sb_bread(sb, block);
++ if (bh == NULL)
++ reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
++ "reading failed", __FUNCTION__, block);
++ else {
++ if (buffer_locked(bh)) {
++ PROC_INFO_INC(sb, scan_bitmap.wait);
++ __wait_on_buffer(bh);
++ }
++ BUG_ON(!buffer_uptodate(bh));
++ BUG_ON(atomic_read(&bh->b_count) == 0);
++
++ if (info->first_zero_hint == 0)
++ reiserfs_cache_bitmap_metadata(sb, bh, info);
++ }
++
++ return bh;
++}
++
++int reiserfs_init_bitmap_cache(struct super_block *sb)
++{
++ struct reiserfs_bitmap_info *bitmap;
++
++ bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb));
++ if (bitmap == NULL)
++ return -ENOMEM;
++
++ memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb));
++
++ SB_AP_BITMAP(sb) = bitmap;
++
++ return 0;
++}
++
++void reiserfs_free_bitmap_cache(struct super_block *sb)
++{
++ if (SB_AP_BITMAP(sb)) {
++ vfree(SB_AP_BITMAP(sb));
++ SB_AP_BITMAP(sb) = NULL;
++ }
++}
+diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
+index 9aabcc0..657050a 100644
+--- a/fs/reiserfs/dir.c
++++ b/fs/reiserfs/dir.c
+@@ -22,6 +22,9 @@ const struct file_operations reiserfs_di
+ .readdir = reiserfs_readdir,
+ .fsync = reiserfs_dir_fsync,
+ .ioctl = reiserfs_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = reiserfs_compat_ioctl,
++#endif
+ };
+
+ static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
+diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
+index 1627edd..b67ce93 100644
+--- a/fs/reiserfs/file.c
++++ b/fs/reiserfs/file.c
+@@ -37,8 +37,7 @@ static int reiserfs_file_release(struct
+ int err;
+ int jbegin_failure = 0;
+
+- if (!S_ISREG(inode->i_mode))
+- BUG();
++ BUG_ON(!S_ISREG(inode->i_mode));
+
+ /* fast out for when nothing needs to be done */
+ if ((atomic_read(&inode->i_count) > 1 ||
+@@ -124,13 +123,12 @@ static int reiserfs_sync_file(struct fil
+ int n_err;
+ int barrier_done;
+
+- if (!S_ISREG(p_s_inode->i_mode))
+- BUG();
++ BUG_ON(!S_ISREG(p_s_inode->i_mode));
+ 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)
++ if (barrier_done != 1 && reiserfs_barrier_flush(p_s_inode->i_sb))
+ blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
+ if (barrier_done < 0)
+ return barrier_done;
+@@ -1333,7 +1331,7 @@ static ssize_t reiserfs_file_write(struc
+ if (err)
+ return err;
+ }
+- result = generic_file_write(file, buf, count, ppos);
++ result = do_sync_write(file, buf, count, ppos);
+
+ if (after_file_end) { /* Now update i_size and remove the savelink */
+ struct reiserfs_transaction_handle th;
+@@ -1565,10 +1563,14 @@ static ssize_t reiserfs_file_write(struc
+ }
+
+ const struct file_operations reiserfs_file_operations = {
+- .read = generic_file_read,
++ .read = do_sync_read,
+ .write = reiserfs_file_write,
+ .ioctl = reiserfs_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = reiserfs_compat_ioctl,
++#endif
+ .mmap = generic_file_mmap,
++ .open = generic_file_open,
+ .release = reiserfs_file_release,
+ .fsync = reiserfs_sync_file,
+ .sendfile = generic_file_sendfile,
+diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
+index 52f1e21..9c69bca 100644
+--- a/fs/reiserfs/inode.c
++++ b/fs/reiserfs/inode.c
+@@ -17,8 +17,6 @@
+ #include <linux/writeback.h>
+ #include <linux/quotaops.h>
+
+-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);
+ static int reiserfs_prepare_write(struct file *f, struct page *page,
+@@ -1122,7 +1120,6 @@ static void init_inode(struct inode *ino
+ 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;
+@@ -1130,9 +1127,9 @@ static void init_inode(struct inode *ino
+ 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);
++ reiserfs_init_acl_access(inode);
++ reiserfs_init_acl_default(inode);
++ reiserfs_init_xattr_rwsem(inode);
+
+ if (stat_data_v1(ih)) {
+ struct stat_data_v1 *sd =
+@@ -1783,7 +1780,7 @@ int reiserfs_new_inode(struct reiserfs_t
+ err = -EDQUOT;
+ goto out_end_trans;
+ }
+- if (!dir || !dir->i_nlink) {
++ if (!dir->i_nlink) {
+ err = -EPERM;
+ goto out_bad_inode;
+ }
+@@ -1837,9 +1834,9 @@ int reiserfs_new_inode(struct reiserfs_t
+ 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);
++ reiserfs_init_acl_access(inode);
++ reiserfs_init_acl_default(inode);
++ reiserfs_init_xattr_rwsem(inode);
+
+ if (old_format_only(sb))
+ make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET,
+@@ -1877,7 +1874,6 @@ int reiserfs_new_inode(struct reiserfs_t
+ }
+ // 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
+@@ -1978,11 +1974,13 @@ int reiserfs_new_inode(struct reiserfs_t
+ * iput doesn't deadlock in reiserfs_delete_xattrs. The locking
+ * code really needs to be reworked, but this will take care of it
+ * for now. -jeffm */
++#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+ if (REISERFS_I(dir)->i_acl_default && !IS_ERR(REISERFS_I(dir)->i_acl_default)) {
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ iput(inode);
+ reiserfs_write_lock_xattrs(dir->i_sb);
+ } else
++#endif
+ iput(inode);
+ return err;
+ }
+diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
+index a986b5e..9c57578 100644
+--- a/fs/reiserfs/ioctl.c
++++ b/fs/reiserfs/ioctl.c
+@@ -9,6 +9,7 @@
+ #include <asm/uaccess.h>
+ #include <linux/pagemap.h>
+ #include <linux/smp_lock.h>
++#include <linux/compat.h>
+
+ static int reiserfs_unpack(struct inode *inode, struct file *filp);
+
+@@ -94,6 +95,40 @@ int reiserfs_ioctl(struct inode *inode,
+ }
+ }
+
++#ifdef CONFIG_COMPAT
++long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int ret;
++
++ /* These are just misnamed, they actually get/put from/to user an int */
++ switch (cmd) {
++ case REISERFS_IOC32_UNPACK:
++ cmd = REISERFS_IOC_UNPACK;
++ break;
++ case REISERFS_IOC32_GETFLAGS:
++ cmd = REISERFS_IOC_GETFLAGS;
++ break;
++ case REISERFS_IOC32_SETFLAGS:
++ cmd = REISERFS_IOC_SETFLAGS;
++ break;
++ case REISERFS_IOC32_GETVERSION:
++ cmd = REISERFS_IOC_GETVERSION;
++ break;
++ case REISERFS_IOC32_SETVERSION:
++ cmd = REISERFS_IOC_SETVERSION;
++ break;
++ default:
++ return -ENOIOCTLCMD;
++ }
++ lock_kernel();
++ ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
++ unlock_kernel();
++ return ret;
++}
++#endif
++
+ /*
+ ** reiserfs_unpack
+ ** Function try to convert tail from direct item into indirect.
+diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c
+index 7a88adb..b9b423b 100644
+--- a/fs/reiserfs/item_ops.c
++++ b/fs/reiserfs/item_ops.c
+@@ -75,8 +75,7 @@ static int sd_create_vi(struct virtual_n
+ static int sd_check_left(struct virtual_item *vi, int free,
+ int start_skip, int end_skip)
+ {
+- if (start_skip || end_skip)
+- BUG();
++ BUG_ON(start_skip || end_skip);
+ return -1;
+ }
+
+@@ -87,8 +86,7 @@ static int sd_check_right(struct virtual
+
+ static int sd_part_size(struct virtual_item *vi, int first, int count)
+ {
+- if (count)
+- BUG();
++ BUG_ON(count);
+ return 0;
+ }
+
+@@ -476,8 +474,7 @@ static int direntry_create_vi(struct vir
+
+ vi->vi_index = TYPE_DIRENTRY;
+
+- if (!(vi->vi_ih) || !vi->vi_item)
+- BUG();
++ BUG_ON(!(vi->vi_ih) || !vi->vi_item);
+
+ dir_u->flags = 0;
+ if (le_ih_k_offset(vi->vi_ih) == DOT_OFFSET)
+@@ -575,8 +572,7 @@ static int direntry_check_right(struct v
+ free -= dir_u->entry_sizes[i];
+ entries++;
+ }
+- if (entries == dir_u->entry_count)
+- BUG();
++ BUG_ON(entries == dir_u->entry_count);
+
+ /* "." and ".." can not be separated from each other */
+ if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
+diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
+index 9b3672d..85ce232 100644
+--- a/fs/reiserfs/journal.c
++++ b/fs/reiserfs/journal.c
+@@ -53,6 +53,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/writeback.h>
+ #include <linux/blkdev.h>
++#include <linux/backing-dev.h>
+
+ /* gets a struct reiserfs_journal_list * from a list head */
+ #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \
+@@ -718,8 +719,7 @@ static int add_to_chunk(struct buffer_ch
+ spinlock_t * lock, void (fn) (struct buffer_chunk *))
+ {
+ int ret = 0;
+- if (chunk->nr >= CHUNK_SIZE)
+- BUG();
++ BUG_ON(chunk->nr >= CHUNK_SIZE);
+ chunk->bh[chunk->nr++] = bh;
+ if (chunk->nr >= CHUNK_SIZE) {
+ ret = 1;
+@@ -788,8 +788,7 @@ static inline int __add_jh(struct reiser
+ /* buffer must be locked for __add_jh, should be able to have
+ * two adds at the same time
+ */
+- if (bh->b_private)
+- BUG();
++ BUG_ON(bh->b_private);
+ jh->bh = bh;
+ bh->b_private = jh;
+ }
+@@ -972,7 +971,7 @@ int reiserfs_async_progress_wait(struct
+ DEFINE_WAIT(wait);
+ struct reiserfs_journal *j = SB_JOURNAL(s);
+ if (atomic_read(&j->j_async_throttle))
+- blk_congestion_wait(WRITE, HZ / 10);
++ congestion_wait(WRITE, HZ / 10);
+ return 0;
+ }
+
+@@ -1186,6 +1185,21 @@ static struct reiserfs_journal_list *fin
+ return NULL;
+ }
+
++static int newer_jl_done(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 &&
++ atomic_read(&cn->jlist->j_commit_left) != 0)
++ return 0;
++ cn = cn->hprev;
++ }
++ return 1;
++}
++
+ static void remove_journal_hash(struct super_block *,
+ struct reiserfs_journal_cnode **,
+ struct reiserfs_journal_list *, unsigned long,
+@@ -1604,6 +1618,31 @@ static int flush_journal_list(struct sup
+ return err;
+ }
+
++static int test_transaction(struct super_block *s,
++ struct reiserfs_journal_list *jl)
++{
++ struct reiserfs_journal_cnode *cn;
++
++ if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0)
++ return 1;
++
++ 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 && !newer_jl_done(cn))
++ return 0;
++ next:
++ cn = cn->next;
++ cond_resched();
++ }
++ return 0;
++}
++
+ static int write_one_transaction(struct super_block *s,
+ struct reiserfs_journal_list *jl,
+ struct buffer_chunk *chunk)
+@@ -2927,8 +2966,7 @@ static int do_journal_begin_r(struct rei
+ int retval;
+
+ reiserfs_check_lock_depth(p_s_sb, "journal_begin");
+- if (nblocks > journal->j_trans_max)
+- BUG();
++ BUG_ON(nblocks > journal->j_trans_max);
+
+ PROC_INFO_INC(p_s_sb, journal.journal_being);
+ /* set here for journal_join */
+@@ -3044,9 +3082,8 @@ struct reiserfs_transaction_handle *reis
+ if (reiserfs_transaction_running(s)) {
+ th = current->journal_info;
+ th->t_refcount++;
+- if (th->t_refcount < 2) {
+- BUG();
+- }
++ BUG_ON(th->t_refcount < 2);
++
+ return th;
+ }
+ th = kmalloc(sizeof(struct reiserfs_transaction_handle), GFP_NOFS);
+@@ -3086,9 +3123,7 @@ static int journal_join(struct reiserfs_
+ ** pointer
+ */
+ th->t_handle_save = cur_th;
+- if (cur_th && cur_th->t_refcount > 1) {
+- BUG();
+- }
++ BUG_ON(cur_th && cur_th->t_refcount > 1);
+ return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN);
+ }
+
+@@ -3101,9 +3136,7 @@ int journal_join_abort(struct reiserfs_t
+ ** pointer
+ */
+ th->t_handle_save = cur_th;
+- if (cur_th && cur_th->t_refcount > 1) {
+- BUG();
+- }
++ BUG_ON(cur_th && cur_th->t_refcount > 1);
+ return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT);
+ }
+
+@@ -3138,8 +3171,7 @@ int journal_begin(struct reiserfs_transa
+ current->journal_info = th;
+ }
+ ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG);
+- if (current->journal_info != th)
+- BUG();
++ BUG_ON(current->journal_info != th);
+
+ /* 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
+@@ -3284,8 +3316,7 @@ int journal_end(struct reiserfs_transact
+ /* 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();
++ BUG_ON(cur_th->t_super != th->t_super);
+
+ if (th != cur_th) {
+ memcpy(current->journal_info, th, sizeof(*th));
+@@ -3404,9 +3435,7 @@ int journal_end_sync(struct reiserfs_tra
+
+ BUG_ON(!th->t_trans_id);
+ /* you can sync while nested, very, very bad */
+- if (th->t_refcount > 1) {
+- BUG();
+- }
++ BUG_ON(th->t_refcount > 1);
+ if (journal->j_len == 0) {
+ reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb),
+ 1);
+@@ -3433,16 +3462,6 @@ static void flush_async_commits(void *p)
+ 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);
+- }
+ }
+
+ /*
+@@ -3526,9 +3545,8 @@ static int check_journal_end(struct reis
+ ** 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();
+- }
++ BUG_ON(journal->j_len == 0);
++
+ /* 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.
+@@ -3562,9 +3580,8 @@ static int check_journal_end(struct reis
+ unlock_journal(p_s_sb);
+ }
+ }
+- if (journal->j_trans_id == trans_id) {
+- BUG();
+- }
++ BUG_ON(journal->j_trans_id == trans_id);
++
+ if (commit_now
+ && journal_list_still_alive(p_s_sb, trans_id)
+ && wait_on_commit) {
+@@ -3844,7 +3861,9 @@ static void flush_old_journal_lists(stru
+ 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))) {
++ if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4)) &&
++ atomic_read(&jl->j_commit_left) == 0 &&
++ test_transaction(s, jl)) {
+ flush_used_journal_lists(s, jl);
+ } else {
+ break;
+@@ -4042,9 +4061,7 @@ static int do_journal_end(struct reiserf
+ 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();
+- }
++ BUG_ON(journal->j_len == 0);
+
+ /* 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
+@@ -4141,8 +4158,7 @@ static int do_journal_end(struct reiserf
+ journal, jl, &jl->j_tail_bh_list);
+ lock_kernel();
+ }
+- if (!list_empty(&jl->j_tail_bh_list))
+- BUG();
++ BUG_ON(!list_empty(&jl->j_tail_bh_list));
+ up(&jl->j_commit_lock);
+
+ /* honor the flush wishes from the caller, simple commits can
+diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
+index c61710e..abde1ed 100644
+--- a/fs/reiserfs/namei.c
++++ b/fs/reiserfs/namei.c
+@@ -19,8 +19,8 @@
+ #include <linux/smp_lock.h>
+ #include <linux/quotaops.h>
+
+-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
+-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
++#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
++#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i);
+
+ // directory item contains array of entry headers. This performs
+ // binary search through that array
+@@ -67,8 +67,7 @@ inline void set_de_name_and_namelen(stru
+ {
+ struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
+
+- if (de->de_entry_num >= ih_entry_count(de->de_ih))
+- BUG();
++ BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));
+
+ 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);
+@@ -80,8 +79,7 @@ inline void set_de_name_and_namelen(stru
+ // what entry points to
+ static inline void set_de_object_key(struct reiserfs_dir_entry *de)
+ {
+- if (de->de_entry_num >= ih_entry_count(de->de_ih))
+- BUG();
++ BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));
+ 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]));
+ }
+@@ -90,8 +88,7 @@ static inline void store_de_entry_key(st
+ {
+ struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
+
+- if (de->de_entry_num >= ih_entry_count(de->de_ih))
+- BUG();
++ BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));
+
+ /* store key of the found entry */
+ de->de_entry_key.version = KEY_FORMAT_3_5;
+@@ -913,7 +910,7 @@ static int reiserfs_rmdir(struct inode *
+ reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
+ "!= 2 (%d)", __FUNCTION__, inode->i_nlink);
+
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ reiserfs_update_sd(&th, inode);
+
+@@ -994,7 +991,7 @@ static int reiserfs_unlink(struct inode
+ inode->i_nlink = 1;
+ }
+
+- inode->i_nlink--;
++ drop_nlink(inode);
+
+ /*
+ * we schedule before doing the add_save_link call, save the link
+@@ -1006,7 +1003,7 @@ static int reiserfs_unlink(struct inode
+ reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL,
+ 0);
+ if (retval < 0) {
+- inode->i_nlink++;
++ inc_nlink(inode);
+ goto end_unlink;
+ }
+ inode->i_ctime = CURRENT_TIME_SEC;
+@@ -1143,7 +1140,7 @@ static int reiserfs_link(struct dentry *
+ }
+
+ /* inc before scheduling so reiserfs_unlink knows we are here */
+- inode->i_nlink++;
++ inc_nlink(inode);
+
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval) {
+@@ -1473,9 +1470,9 @@ static int reiserfs_rename(struct inode
+ if (new_dentry_inode) {
+ // adjust link number of the victim
+ if (S_ISDIR(new_dentry_inode->i_mode)) {
+- new_dentry_inode->i_nlink = 0;
++ clear_nlink(new_dentry_inode);
+ } else {
+- new_dentry_inode->i_nlink--;
++ drop_nlink(new_dentry_inode);
+ }
+ new_dentry_inode->i_ctime = ctime;
+ savelink = new_dentry_inode->i_nlink;
+diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
+index 39cc7f4..3156847 100644
+--- a/fs/reiserfs/resize.c
++++ b/fs/reiserfs/resize.c
+@@ -22,6 +22,7 @@ int reiserfs_resize(struct super_block *
+ int err = 0;
+ struct reiserfs_super_block *sb;
+ struct reiserfs_bitmap_info *bitmap;
++ struct reiserfs_bitmap_info *info;
+ struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
+ struct buffer_head *bh;
+ struct reiserfs_transaction_handle th;
+@@ -127,16 +128,20 @@ int reiserfs_resize(struct super_block *
+ * 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);
++ /* don't use read_bitmap_block since it will cache
++ * the uninitialized bitmap */
++ bh = sb_bread(s, i * s->s_blocksize * 8);
++ memset(bh->b_data, 0, sb_blocksize(sb));
++ reiserfs_test_and_set_le_bit(0, bh->b_data);
++ reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
++
++ set_buffer_uptodate(bh);
++ mark_buffer_dirty(bh);
++ sync_dirty_buffer(bh);
+ // update bitmap_info stuff
+ bitmap[i].first_zero_hint = 1;
+ bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
++ brelse(bh);
+ }
+ /* free old bitmap blocks array */
+ SB_AP_BITMAP(s) = bitmap;
+@@ -150,30 +155,46 @@ int reiserfs_resize(struct super_block *
+ if (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);
++ /* Extend old last bitmap block - new blocks have been made available */
++ info = SB_AP_BITMAP(s) + bmap_nr - 1;
++ bh = reiserfs_read_bitmap_block(s, bmap_nr - 1);
++ if (!bh) {
++ int jerr = journal_end(&th, s, 10);
++ if (jerr)
++ return jerr;
++ return -EIO;
++ }
++
++ reiserfs_prepare_for_journal(s, 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);
+- 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;
++ reiserfs_test_and_clear_le_bit(i, bh->b_data);
++ info->free_count += s->s_blocksize * 8 - block_r;
++ if (!info->first_zero_hint)
++ info->first_zero_hint = block_r;
+
+- journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
++ journal_mark_dirty(&th, s, bh);
++ brelse(bh);
++
++ /* Correct new last bitmap block - It may not be full */
++ info = SB_AP_BITMAP(s) + bmap_nr_new - 1;
++ bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1);
++ if (!bh) {
++ int jerr = journal_end(&th, s, 10);
++ if (jerr)
++ return jerr;
++ return -EIO;
++ }
+
+- reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
++ reiserfs_prepare_for_journal(s, 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);
+- journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
++ reiserfs_test_and_set_le_bit(i, bh->b_data);
++ journal_mark_dirty(&th, s, bh);
++ brelse(bh);
+
+- SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -=
+- s->s_blocksize * 8 - block_r_new;
++ info->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;
++ if (!info->free_count)
++ info->first_zero_hint = 0;
+ /* update super */
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+ free_blocks = SB_FREE_BLOCKS(s);
+diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
+index 8b9b131..5240abe 100644
+--- a/fs/reiserfs/stree.c
++++ b/fs/reiserfs/stree.c
+@@ -1476,9 +1476,7 @@ static int maybe_indirect_to_direct(stru
+ 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();
++ BUG_ON(n_new_file_size != p_s_inode->i_size);
+
+ /* 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
+diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
+index 5567328..1724999 100644
+--- a/fs/reiserfs/super.c
++++ b/fs/reiserfs/super.c
+@@ -430,21 +430,29 @@ int remove_save_link(struct inode *inode
+ return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+ }
+
+-static void reiserfs_put_super(struct super_block *s)
++static void reiserfs_kill_sb(struct super_block *s)
+ {
+- int i;
+- struct reiserfs_transaction_handle th;
+- th.t_trans_id = 0;
++ if (REISERFS_SB(s)) {
++ if (REISERFS_SB(s)->xattr_root) {
++ d_invalidate(REISERFS_SB(s)->xattr_root);
++ dput(REISERFS_SB(s)->xattr_root);
++ REISERFS_SB(s)->xattr_root = NULL;
++ }
+
+- 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);
++ REISERFS_SB(s)->priv_root = NULL;
++ }
+ }
+
+- if (REISERFS_SB(s)->priv_root) {
+- d_invalidate(REISERFS_SB(s)->priv_root);
+- dput(REISERFS_SB(s)->priv_root);
+- }
++ kill_block_super(s);
++}
++
++static void reiserfs_put_super(struct super_block *s)
++{
++ struct reiserfs_transaction_handle th;
++ th.t_trans_id = 0;
+
+ /* change file system state to current state if it was mounted with read-write permissions */
+ if (!(s->s_flags & MS_RDONLY)) {
+@@ -462,10 +470,7 @@ static void reiserfs_put_super(struct su
+ */
+ 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));
++ reiserfs_free_bitmap_cache(s);
+
+ brelse(SB_BUFFER_WITH_SB(s));
+
+@@ -510,8 +515,10 @@ static void init_once(void *foo, kmem_ca
+ SLAB_CTOR_CONSTRUCTOR) {
+ INIT_LIST_HEAD(&ei->i_prealloc_list);
+ inode_init_once(&ei->vfs_inode);
++#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+ ei->i_acl_access = NULL;
+ ei->i_acl_default = NULL;
++#endif
+ }
+ }
+
+@@ -530,9 +537,7 @@ 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");
++ kmem_cache_destroy(reiserfs_inode_cachep);
+ }
+
+ /* we don't mark inodes dirty, we just log them */
+@@ -562,6 +567,7 @@ static void reiserfs_dirty_inode(struct
+ reiserfs_write_unlock(inode->i_sb);
+ }
+
++#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+ static void reiserfs_clear_inode(struct inode *inode)
+ {
+ struct posix_acl *acl;
+@@ -576,6 +582,9 @@ static void reiserfs_clear_inode(struct
+ posix_acl_release(acl);
+ REISERFS_I(inode)->i_acl_default = NULL;
+ }
++#else
++#define reiserfs_clear_inode NULL
++#endif
+
+ #ifdef CONFIG_QUOTA
+ static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
+@@ -725,12 +734,6 @@ static const arg_desc_t error_actions[]
+ {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.
+- */
+-
+ /* proceed only one option from a list *cur - string containing of mount options
+ opts - array of options which are accepted
+ opt_arg - if option is found and requires an argument and if it is specifed
+@@ -959,19 +962,8 @@ static int reiserfs_parse_options(struct
+ }
+
+ 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;
++ reiserfs_warning(s, "reiserfs: nolargeio option is no longer supported");
++ return 0;
+ }
+
+ if (c == 'j') {
+@@ -1256,118 +1248,6 @@ static int reiserfs_remount(struct super
+ return 0;
+ }
+
+-/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
+- * @sb - superblock for this filesystem
+- * @bi - the bitmap info to be loaded. Requires that bi->bh is valid.
+- *
+- * This routine counts how many free bits there are, finding the first zero
+- * as a side effect. Could also be implemented as a loop of test_bit() calls, or
+- * a loop of find_first_zero_bit() calls. This implementation is similar to
+- * find_first_zero_bit(), but doesn't return after it finds the first bit.
+- * Should only be called on fs mount, but should be fairly efficient anyways.
+- *
+- * bi->first_zero_hint is considered unset if it == 0, since the bitmap itself
+- * will * invariably occupt block 0 represented in the bitmap. The only
+- * exception to this is when free_count also == 0, since there will be no
+- * free blocks at all.
+- */
+-
+-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;
+- }
+- }
+- }
+- 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);
+-#endif
+-}
+-
+-static int read_bitmaps(struct super_block *s)
+-{
+- 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;
+-}
+-
+-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);
+- }
+-
+- return 0;
+-}
+-
+ static int read_super_block(struct super_block *s, int offset)
+ {
+ struct buffer_head *bh;
+@@ -1469,7 +1349,6 @@ static int read_super_block(struct super
+ /* 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))) {
+@@ -1478,20 +1357,7 @@ static int reread_meta_blocks(struct sup
+ 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;
+-
+ }
+
+ /////////////////////////////////////////////////////
+@@ -1672,7 +1538,6 @@ static int function2code(hashf_t func)
+ 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;
+@@ -1749,11 +1614,12 @@ static int reiserfs_fill_super(struct su
+ 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)) {
++ if ((errval = reiserfs_init_bitmap_cache(s))) {
+ SWARN(silent, s,
+ "jmacd-8: reiserfs_fill_super: unable to read bitmap");
+ goto error;
+ }
++ errval = -EINVAL;
+ #ifdef CONFIG_REISERFS_CHECK
+ SWARN(silent, s, "CONFIG_REISERFS_CHECK is set ON");
+ SWARN(silent, s, "- it is slow mode for debugging.");
+@@ -1831,6 +1697,8 @@ static int reiserfs_fill_super(struct su
+ 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 if (old_format)
++ set_bit(REISERFS_OLD_FORMAT, &(sbi->s_properties));
+ else
+ set_bit(REISERFS_3_6, &(sbi->s_properties));
+
+@@ -1916,19 +1784,17 @@ static int reiserfs_fill_super(struct su
+ 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);
+- }
+- vfree(SB_AP_BITMAP(s));
+- }
++
++ reiserfs_free_bitmap_cache(s);
+ if (SB_BUFFER_WITH_SB(s))
+ brelse(SB_BUFFER_WITH_SB(s));
+ #ifdef CONFIG_QUOTA
+- for (j = 0; j < MAXQUOTAS; j++) {
+- kfree(sbi->s_qf_names[j]);
+- sbi->s_qf_names[j] = NULL;
++ {
++ int j;
++ for (j = 0; j < MAXQUOTAS; j++) {
++ kfree(sbi->s_qf_names[j]);
++ sbi->s_qf_names[j] = NULL;
++ }
+ }
+ #endif
+ kfree(sbi);
+@@ -2300,7 +2166,7 @@ struct file_system_type reiserfs_fs_type
+ .owner = THIS_MODULE,
+ .name = "reiserfs",
+ .get_sb = get_super_block,
+- .kill_sb = kill_block_super,
++ .kill_sb = reiserfs_kill_sb,
+ .fs_flags = FS_REQUIRES_DEV,
+ };
+
+diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
+index d935fb9..7bdb0ed 100644
+--- a/fs/reiserfs/xattr.c
++++ b/fs/reiserfs/xattr.c
+@@ -773,7 +773,7 @@ int reiserfs_xattr_del(struct inode *ino
+
+ static int
+ reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct dentry *xadir = (struct dentry *)buf;
+
+@@ -851,7 +851,7 @@ struct reiserfs_chown_buf {
+ /* 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)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
+ struct dentry *xafile, *xadir = chown_buf->xadir;
+@@ -1036,7 +1036,7 @@ struct reiserfs_listxattr_buf {
+
+ static int
+ reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
+- loff_t offset, ino_t ino, unsigned int d_type)
++ loff_t offset, u64 ino, unsigned int d_type)
+ {
+ struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
+ int len = 0;
+diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
+index 22eed61..ddcd9e1 100644
+--- a/fs/romfs/inode.c
++++ b/fs/romfs/inode.c
+@@ -589,8 +589,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(romfs_inode_cachep))
+- printk(KERN_INFO "romfs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(romfs_inode_cachep);
+ }
+
+ static int romfs_remount(struct super_block *sb, int *flags, char *data)
+diff --git a/fs/select.c b/fs/select.c
+index 33b72ba..dcbc111 100644
+--- a/fs/select.c
++++ b/fs/select.c
+@@ -658,8 +658,6 @@ int do_sys_poll(struct pollfd __user *uf
+ unsigned int i;
+ struct poll_list *head;
+ struct poll_list *walk;
+- struct fdtable *fdt;
+- int max_fdset;
+ /* Allocate small arguments on the stack to save memory and be
+ faster - use long to make sure the buffer is aligned properly
+ on 64 bit archs to avoid unaligned access */
+@@ -667,11 +665,7 @@ int do_sys_poll(struct pollfd __user *uf
+ struct poll_list *stack_pp = NULL;
+
+ /* Do a sanity check on nfds ... */
+- rcu_read_lock();
+- fdt = files_fdtable(current->files);
+- max_fdset = fdt->max_fdset;
+- rcu_read_unlock();
+- if (nfds > max_fdset && nfds > OPEN_MAX)
++ if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
+ return -EINVAL;
+
+ poll_initwait(&table);
+diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
+index dae6704..50784d1 100644
+--- a/fs/smbfs/file.c
++++ b/fs/smbfs/file.c
+@@ -214,13 +214,15 @@ smb_updatepage(struct file *file, struct
+ }
+
+ static ssize_t
+-smb_file_read(struct file * file, char __user * buf, size_t count, loff_t *ppos)
++smb_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
++ struct file * file = iocb->ki_filp;
+ struct dentry * dentry = file->f_dentry;
+ ssize_t status;
+
+ VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
+- (unsigned long) count, (unsigned long) *ppos);
++ (unsigned long) iocb->ki_left, (unsigned long) pos);
+
+ status = smb_revalidate_inode(dentry);
+ if (status) {
+@@ -233,7 +235,7 @@ smb_file_read(struct file * file, char _
+ (long)dentry->d_inode->i_size,
+ dentry->d_inode->i_flags, dentry->d_inode->i_atime);
+
+- status = generic_file_read(file, buf, count, ppos);
++ status = generic_file_aio_read(iocb, iov, nr_segs, pos);
+ out:
+ return status;
+ }
+@@ -317,14 +319,16 @@ const struct address_space_operations sm
+ * Write to a file (through the page cache).
+ */
+ static ssize_t
+-smb_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
++smb_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
++ struct file * file = iocb->ki_filp;
+ struct dentry * dentry = file->f_dentry;
+ ssize_t result;
+
+ VERBOSE("file %s/%s, count=%lu@%lu\n",
+ DENTRY_PATH(dentry),
+- (unsigned long) count, (unsigned long) *ppos);
++ (unsigned long) iocb->ki_left, (unsigned long) pos);
+
+ result = smb_revalidate_inode(dentry);
+ if (result) {
+@@ -337,8 +341,8 @@ smb_file_write(struct file *file, const
+ if (result)
+ goto out;
+
+- if (count > 0) {
+- result = generic_file_write(file, buf, count, ppos);
++ if (iocb->ki_left > 0) {
++ result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+ VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
+ (long) file->f_pos, (long) dentry->d_inode->i_size,
+ dentry->d_inode->i_mtime, dentry->d_inode->i_atime);
+@@ -402,8 +406,10 @@ smb_file_permission(struct inode *inode,
+ const struct file_operations smb_file_operations =
+ {
+ .llseek = remote_llseek,
+- .read = smb_file_read,
+- .write = smb_file_write,
++ .read = do_sync_read,
++ .aio_read = smb_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = smb_file_aio_write,
+ .ioctl = smb_ioctl,
+ .mmap = smb_file_mmap,
+ .open = smb_file_open,
+diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
+index a1ed657..2c122ee 100644
+--- a/fs/smbfs/inode.c
++++ b/fs/smbfs/inode.c
+@@ -89,8 +89,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(smb_inode_cachep))
+- printk(KERN_INFO "smb_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(smb_inode_cachep);
+ }
+
+ static int smb_remount(struct super_block *sb, int *flags, char *data)
+@@ -167,7 +166,6 @@ smb_get_inode_attr(struct inode *inode,
+ fattr->f_mtime = inode->i_mtime;
+ fattr->f_ctime = inode->i_ctime;
+ fattr->f_atime = inode->i_atime;
+- fattr->f_blksize= inode->i_blksize;
+ fattr->f_blocks = inode->i_blocks;
+
+ fattr->attr = SMB_I(inode)->attr;
+@@ -201,7 +199,6 @@ smb_set_inode_attr(struct inode *inode,
+ inode->i_uid = fattr->f_uid;
+ inode->i_gid = fattr->f_gid;
+ inode->i_ctime = fattr->f_ctime;
+- inode->i_blksize= fattr->f_blksize;
+ inode->i_blocks = fattr->f_blocks;
+ inode->i_size = fattr->f_size;
+ inode->i_mtime = fattr->f_mtime;
+diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
+index c349505..40e174d 100644
+--- a/fs/smbfs/proc.c
++++ b/fs/smbfs/proc.c
+@@ -1826,7 +1826,6 @@ smb_init_dirent(struct smb_sb_info *serv
+ fattr->f_nlink = 1;
+ fattr->f_uid = server->mnt->uid;
+ fattr->f_gid = server->mnt->gid;
+- fattr->f_blksize = SMB_ST_BLKSIZE;
+ fattr->f_unix = 0;
+ }
+
+diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
+index c8e9619..0fb7469 100644
+--- a/fs/smbfs/request.c
++++ b/fs/smbfs/request.c
+@@ -49,8 +49,7 @@ int smb_init_request_cache(void)
+
+ void smb_destroy_request_cache(void)
+ {
+- if (kmem_cache_destroy(req_cachep))
+- printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n");
++ kmem_cache_destroy(req_cachep);
+ }
+
+ /*
+diff --git a/fs/splice.c b/fs/splice.c
+index 684bca3..da74583 100644
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -12,7 +12,7 @@
+ * Jens to support splicing to files, network, direct splicing, etc and
+ * fixing lots of bugs.
+ *
+- * Copyright (C) 2005-2006 Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2005-2006 Jens Axboe <axboe at kernel.dk>
+ * Copyright (C) 2005-2006 Linus Torvalds <torvalds at osdl.org>
+ * Copyright (C) 2006 Ingo Molnar <mingo at elte.hu>
+ *
+@@ -74,7 +74,7 @@ static int page_cache_pipe_buf_steal(str
+ wait_on_page_writeback(page);
+
+ if (PagePrivate(page))
+- try_to_release_page(page, mapping_gfp_mask(mapping));
++ try_to_release_page(page, GFP_KERNEL);
+
+ /*
+ * If we succeeded in removing the mapping, set LRU flag
+@@ -333,7 +333,7 @@ __generic_file_splice_read(struct file *
+ break;
+
+ error = add_to_page_cache_lru(page, mapping, index,
+- mapping_gfp_mask(mapping));
++ GFP_KERNEL);
+ if (unlikely(error)) {
+ page_cache_release(page);
+ if (error == -EEXIST)
+@@ -557,7 +557,6 @@ static int pipe_to_file(struct pipe_inod
+ {
+ struct file *file = sd->file;
+ struct address_space *mapping = file->f_mapping;
+- gfp_t gfp_mask = mapping_gfp_mask(mapping);
+ unsigned int offset, this_len;
+ struct page *page;
+ pgoff_t index;
+@@ -591,7 +590,7 @@ static int pipe_to_file(struct pipe_inod
+ goto find_page;
+
+ page = buf->page;
+- if (add_to_page_cache(page, mapping, index, gfp_mask)) {
++ if (add_to_page_cache(page, mapping, index, GFP_KERNEL)) {
+ unlock_page(page);
+ goto find_page;
+ }
+@@ -607,13 +606,13 @@ find_page:
+ ret = -ENOMEM;
+ page = page_cache_alloc_cold(mapping);
+ if (unlikely(!page))
+- goto out_nomem;
++ goto out_ret;
+
+ /*
+ * This will also lock the page
+ */
+ ret = add_to_page_cache_lru(page, mapping, index,
+- gfp_mask);
++ GFP_KERNEL);
+ if (unlikely(ret))
+ goto out;
+ }
+@@ -666,7 +665,7 @@ find_page:
+ if (sd->pos + this_len > isize)
+ vmtruncate(mapping->host, isize);
+
+- goto out;
++ goto out_ret;
+ }
+
+ if (buf->page != page) {
+@@ -698,7 +697,7 @@ find_page:
+ out:
+ page_cache_release(page);
+ unlock_page(page);
+-out_nomem:
++out_ret:
+ return ret;
+ }
+
+@@ -707,9 +706,9 @@ out_nomem:
+ * key here is the 'actor' worker passed in that actually moves the data
+ * to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
+ */
+-ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
+- loff_t *ppos, size_t len, unsigned int flags,
+- splice_actor *actor)
++static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
++ struct file *out, loff_t *ppos, size_t len,
++ unsigned int flags, splice_actor *actor)
+ {
+ int ret, do_wakeup, err;
+ struct splice_desc sd;
+@@ -722,9 +721,6 @@ ssize_t splice_from_pipe(struct pipe_ino
+ sd.file = out;
+ sd.pos = *ppos;
+
+- if (pipe->inode)
+- mutex_lock(&pipe->inode->i_mutex);
+-
+ for (;;) {
+ if (pipe->nrbufs) {
+ struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
+@@ -797,9 +793,6 @@ ssize_t splice_from_pipe(struct pipe_ino
+ pipe_wait(pipe);
+ }
+
+- if (pipe->inode)
+- mutex_unlock(&pipe->inode->i_mutex);
+-
+ if (do_wakeup) {
+ smp_mb();
+ if (waitqueue_active(&pipe->wait))
+@@ -810,6 +803,73 @@ ssize_t splice_from_pipe(struct pipe_ino
+ return ret;
+ }
+
++ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags,
++ splice_actor *actor)
++{
++ ssize_t ret;
++ struct inode *inode = out->f_mapping->host;
++
++ /*
++ * The actor worker might be calling ->prepare_write and
++ * ->commit_write. Most of the time, these expect i_mutex to
++ * be held. Since this may result in an ABBA deadlock with
++ * pipe->inode, we have to order lock acquiry here.
++ */
++ inode_double_lock(inode, pipe->inode);
++ ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor);
++ inode_double_unlock(inode, pipe->inode);
++
++ return ret;
++}
++
++/**
++ * generic_file_splice_write_nolock - generic_file_splice_write without mutexes
++ * @pipe: pipe info
++ * @out: file to write to
++ * @len: number of bytes to splice
++ * @flags: splice modifier flags
++ *
++ * Will either move or copy pages (determined by @flags options) from
++ * the given pipe inode to the given file. The caller is responsible
++ * for acquiring i_mutex on both inodes.
++ *
++ */
++ssize_t
++generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ struct address_space *mapping = out->f_mapping;
++ struct inode *inode = mapping->host;
++ ssize_t ret;
++ int err;
++
++ err = remove_suid(out->f_dentry);
++ if (unlikely(err))
++ return err;
++
++ ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
++ if (ret > 0) {
++ *ppos += ret;
++
++ /*
++ * If file or inode is SYNC and we actually wrote some data,
++ * sync it.
++ */
++ if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
++ err = generic_osync_inode(inode, mapping,
++ OSYNC_METADATA|OSYNC_DATA);
++
++ if (err)
++ ret = err;
++ }
++ }
++
++ return ret;
++}
++
++EXPORT_SYMBOL(generic_file_splice_write_nolock);
++
+ /**
+ * generic_file_splice_write - splice data from a pipe to a file
+ * @pipe: pipe info
+@@ -826,12 +886,21 @@ generic_file_splice_write(struct pipe_in
+ loff_t *ppos, size_t len, unsigned int flags)
+ {
+ struct address_space *mapping = out->f_mapping;
++ struct inode *inode = mapping->host;
+ ssize_t ret;
++ int err;
++
++ err = should_remove_suid(out->f_dentry);
++ if (unlikely(err)) {
++ mutex_lock(&inode->i_mutex);
++ err = __remove_suid(out->f_dentry, err);
++ mutex_unlock(&inode->i_mutex);
++ if (err)
++ return err;
++ }
+
+ ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
+ if (ret > 0) {
+- struct inode *inode = mapping->host;
+-
+ *ppos += ret;
+
+ /*
+@@ -839,8 +908,6 @@ generic_file_splice_write(struct pipe_in
+ * sync it.
+ */
+ if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
+- int err;
+-
+ mutex_lock(&inode->i_mutex);
+ err = generic_osync_inode(inode, mapping,
+ OSYNC_METADATA|OSYNC_DATA);
+@@ -1042,6 +1109,19 @@ out_release:
+ EXPORT_SYMBOL(do_splice_direct);
+
+ /*
++ * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
++ * location, so checking ->i_pipe is not enough to verify that this is a
++ * pipe.
++ */
++static inline struct pipe_inode_info *pipe_info(struct inode *inode)
++{
++ if (S_ISFIFO(inode->i_mode))
++ return inode->i_pipe;
++
++ return NULL;
++}
++
++/*
+ * Determine where to splice to/from.
+ */
+ static long do_splice(struct file *in, loff_t __user *off_in,
+@@ -1052,7 +1132,7 @@ static long do_splice(struct file *in, l
+ loff_t offset, *off;
+ long ret;
+
+- pipe = in->f_dentry->d_inode->i_pipe;
++ pipe = pipe_info(in->f_dentry->d_inode);
+ if (pipe) {
+ if (off_in)
+ return -ESPIPE;
+@@ -1073,7 +1153,7 @@ static long do_splice(struct file *in, l
+ return ret;
+ }
+
+- pipe = out->f_dentry->d_inode->i_pipe;
++ pipe = pipe_info(out->f_dentry->d_inode);
+ if (pipe) {
+ if (off_out)
+ return -ESPIPE;
+@@ -1231,7 +1311,7 @@ static int get_iovec_page_array(const st
+ static long do_vmsplice(struct file *file, const struct iovec __user *iov,
+ unsigned long nr_segs, unsigned int flags)
+ {
+- struct pipe_inode_info *pipe = file->f_dentry->d_inode->i_pipe;
++ struct pipe_inode_info *pipe;
+ struct page *pages[PIPE_BUFFERS];
+ struct partial_page partial[PIPE_BUFFERS];
+ struct splice_pipe_desc spd = {
+@@ -1241,7 +1321,8 @@ static long do_vmsplice(struct file *fil
+ .ops = &user_page_pipe_buf_ops,
+ };
+
+- if (unlikely(!pipe))
++ pipe = pipe_info(file->f_dentry->d_inode);
++ if (!pipe)
+ return -EBADF;
+ if (unlikely(nr_segs > UIO_MAXIOV))
+ return -EINVAL;
+@@ -1400,13 +1481,7 @@ static int link_pipe(struct pipe_inode_i
+ * grabbing by inode address. Otherwise two different processes
+ * could deadlock (one doing tee from A -> B, the other from B -> A).
+ */
+- if (ipipe->inode < opipe->inode) {
+- mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT);
+- mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD);
+- } else {
+- mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT);
+- mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD);
+- }
++ inode_double_lock(ipipe->inode, opipe->inode);
+
+ do {
+ if (!opipe->readers) {
+@@ -1450,8 +1525,7 @@ static int link_pipe(struct pipe_inode_i
+ i++;
+ } while (len);
+
+- mutex_unlock(&ipipe->inode->i_mutex);
+- mutex_unlock(&opipe->inode->i_mutex);
++ inode_double_unlock(ipipe->inode, opipe->inode);
+
+ /*
+ * If we put data in the output pipe, wakeup any potential readers.
+@@ -1475,8 +1549,8 @@ static int link_pipe(struct pipe_inode_i
+ static long do_tee(struct file *in, struct file *out, size_t len,
+ unsigned int flags)
+ {
+- struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe;
+- struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe;
++ struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode);
++ struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode);
+ int ret = -EINVAL;
+
+ /*
+diff --git a/fs/stat.c b/fs/stat.c
+index 3a44dcf..bca07eb 100644
+--- a/fs/stat.c
++++ b/fs/stat.c
+@@ -14,6 +14,7 @@
+ #include <linux/namei.h>
+ #include <linux/security.h>
+ #include <linux/syscalls.h>
++#include <linux/pagemap.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/unistd.h>
+@@ -32,7 +33,7 @@ void generic_fillattr(struct inode *inod
+ stat->ctime = inode->i_ctime;
+ stat->size = i_size_read(inode);
+ stat->blocks = inode->i_blocks;
+- stat->blksize = inode->i_blksize;
++ stat->blksize = (1 << inode->i_blkbits);
+ }
+
+ EXPORT_SYMBOL(generic_fillattr);
+@@ -139,6 +140,8 @@ static int cp_old_stat(struct kstat *sta
+ memset(&tmp, 0, sizeof(struct __old_kernel_stat));
+ tmp.st_dev = old_encode_dev(stat->dev);
+ tmp.st_ino = stat->ino;
++ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
++ return -EOVERFLOW;
+ tmp.st_mode = stat->mode;
+ tmp.st_nlink = stat->nlink;
+ if (tmp.st_nlink != stat->nlink)
+@@ -209,6 +212,8 @@ static int cp_new_stat(struct kstat *sta
+ tmp.st_dev = new_encode_dev(stat->dev);
+ #endif
+ tmp.st_ino = stat->ino;
++ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
++ return -EOVERFLOW;
+ tmp.st_mode = stat->mode;
+ tmp.st_nlink = stat->nlink;
+ if (tmp.st_nlink != stat->nlink)
+@@ -346,6 +351,8 @@ static long cp_new_stat64(struct kstat *
+ tmp.st_rdev = huge_encode_dev(stat->rdev);
+ #endif
+ tmp.st_ino = stat->ino;
++ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
++ return -EOVERFLOW;
+ #ifdef STAT64_HAS_BROKEN_ST_INO
+ tmp.__st_ino = stat->ino;
+ #endif
+diff --git a/fs/super.c b/fs/super.c
+index 5c4c94d..47e554c 100644
+--- a/fs/super.c
++++ b/fs/super.c
+@@ -199,7 +199,7 @@ EXPORT_SYMBOL(deactivate_super);
+ * success, 0 if we had failed (superblock contents was already dead or
+ * dying when grab_super() had been called).
+ */
+-static int grab_super(struct super_block *s)
++static int grab_super(struct super_block *s) __releases(sb_lock)
+ {
+ s->s_count++;
+ spin_unlock(&sb_lock);
+@@ -220,6 +220,37 @@ static int grab_super(struct super_block
+ return 0;
+ }
+
++/*
++ * Write out and wait upon all dirty data associated with this
++ * superblock. Filesystem data as well as the underlying block
++ * device. Takes the superblock lock. Requires a second blkdev
++ * flush by the caller to complete the operation.
++ */
++void __fsync_super(struct super_block *sb)
++{
++ sync_inodes_sb(sb, 0);
++ DQUOT_SYNC(sb);
++ lock_super(sb);
++ if (sb->s_dirt && sb->s_op->write_super)
++ sb->s_op->write_super(sb);
++ unlock_super(sb);
++ if (sb->s_op->sync_fs)
++ sb->s_op->sync_fs(sb, 1);
++ sync_blockdev(sb->s_bdev);
++ sync_inodes_sb(sb, 1);
++}
++
++/*
++ * Write out and wait upon all dirty data associated with this
++ * superblock. Filesystem data as well as the underlying block
++ * device. Takes the superblock lock.
++ */
++int fsync_super(struct super_block *sb)
++{
++ __fsync_super(sb);
++ return sync_blockdev(sb->s_bdev);
++}
++
+ /**
+ * generic_shutdown_super - common helper for ->kill_sb()
+ * @sb: superblock to kill
+@@ -229,17 +260,17 @@ static int grab_super(struct super_block
+ * that need destruction out of superblock, call generic_shutdown_super()
+ * and release aforementioned objects. Note: dentries and inodes _are_
+ * taken care of and do not need specific handling.
++ *
++ * Upon calling this function, the filesystem may no longer alter or
++ * rearrange the set of dentries belonging to this super_block, nor may it
++ * change the attachments of dentries to inodes.
+ */
+ void generic_shutdown_super(struct super_block *sb)
+ {
+- struct dentry *root = sb->s_root;
+ struct super_operations *sop = sb->s_op;
+
+- if (root) {
+- sb->s_root = NULL;
+- shrink_dcache_parent(root);
+- shrink_dcache_sb(sb);
+- dput(root);
++ if (sb->s_root) {
++ shrink_dcache_for_umount(sb);
+ fsync_super(sb);
+ lock_super(sb);
+ sb->s_flags &= ~MS_ACTIVE;
+@@ -540,8 +571,10 @@ int do_remount_sb(struct super_block *sb
+ {
+ int retval;
+
++#ifdef CONFIG_BLOCK
+ if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
+ return -EACCES;
++#endif
+ if (flags & MS_RDONLY)
+ acct_auto_close(sb);
+ shrink_dcache_sb(sb);
+@@ -661,6 +694,7 @@ void kill_litter_super(struct super_bloc
+
+ EXPORT_SYMBOL(kill_litter_super);
+
++#ifdef CONFIG_BLOCK
+ static int set_bdev_super(struct super_block *s, void *data)
+ {
+ s->s_bdev = data;
+@@ -756,6 +790,7 @@ void kill_block_super(struct super_block
+ }
+
+ EXPORT_SYMBOL(kill_block_super);
++#endif
+
+ int get_sb_nodev(struct file_system_type *fs_type,
+ int flags, void *data,
+diff --git a/fs/sync.c b/fs/sync.c
+index 955aef0..1de747b 100644
+--- a/fs/sync.c
++++ b/fs/sync.c
+@@ -10,11 +10,124 @@
+ #include <linux/syscalls.h>
+ #include <linux/linkage.h>
+ #include <linux/pagemap.h>
++#include <linux/quotaops.h>
++#include <linux/buffer_head.h>
+
+ #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
+ SYNC_FILE_RANGE_WAIT_AFTER)
+
+ /*
++ * sync everything. Start out by waking pdflush, because that writes back
++ * all queues in parallel.
++ */
++static void do_sync(unsigned long wait)
++{
++ wakeup_pdflush(0);
++ sync_inodes(0); /* All mappings, inodes and their blockdevs */
++ DQUOT_SYNC(NULL);
++ sync_supers(); /* Write the superblocks */
++ sync_filesystems(0); /* Start syncing the filesystems */
++ sync_filesystems(wait); /* Waitingly sync the filesystems */
++ sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
++ if (!wait)
++ printk("Emergency Sync complete\n");
++ if (unlikely(laptop_mode))
++ laptop_sync_completion();
++}
++
++asmlinkage long sys_sync(void)
++{
++ do_sync(1);
++ return 0;
++}
++
++void emergency_sync(void)
++{
++ pdflush_operation(do_sync, 0);
++}
++
++/*
++ * Generic function to fsync a file.
++ *
++ * filp may be NULL if called via the msync of a vma.
++ */
++int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
++{
++ struct inode * inode = dentry->d_inode;
++ struct super_block * sb;
++ int ret, err;
++
++ /* sync the inode to buffers */
++ ret = write_inode_now(inode, 0);
++
++ /* sync the superblock to buffers */
++ sb = inode->i_sb;
++ lock_super(sb);
++ if (sb->s_op->write_super)
++ sb->s_op->write_super(sb);
++ unlock_super(sb);
++
++ /* .. finally sync the buffers to disk */
++ err = sync_blockdev(sb->s_bdev);
++ if (!ret)
++ ret = err;
++ return ret;
++}
++
++long do_fsync(struct file *file, int datasync)
++{
++ int ret;
++ int err;
++ struct address_space *mapping = file->f_mapping;
++
++ if (!file->f_op || !file->f_op->fsync) {
++ /* Why? We can still call filemap_fdatawrite */
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = filemap_fdatawrite(mapping);
++
++ /*
++ * We need to protect against concurrent writers, which could cause
++ * livelocks in fsync_buffers_list().
++ */
++ mutex_lock(&mapping->host->i_mutex);
++ err = file->f_op->fsync(file, file->f_dentry, datasync);
++ if (!ret)
++ ret = err;
++ mutex_unlock(&mapping->host->i_mutex);
++ err = filemap_fdatawait(mapping);
++ if (!ret)
++ ret = err;
++out:
++ return ret;
++}
++
++static long __do_fsync(unsigned int fd, int datasync)
++{
++ struct file *file;
++ int ret = -EBADF;
++
++ file = fget(fd);
++ if (file) {
++ ret = do_fsync(file, datasync);
++ fput(file);
++ }
++ return ret;
++}
++
++asmlinkage long sys_fsync(unsigned int fd)
++{
++ return __do_fsync(fd, 0);
++}
++
++asmlinkage long sys_fdatasync(unsigned int fd)
++{
++ return __do_fsync(fd, 1);
++}
++
++/*
+ * sys_sync_file_range() permits finely controlled syncing over a segment of
+ * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is
+ * zero then sys_sync_file_range() will operate from offset out to EOF.
+diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
+index c16a93c..98022e4 100644
+--- a/fs/sysfs/bin.c
++++ b/fs/sysfs/bin.c
+@@ -10,6 +10,7 @@
+
+ #include <linux/errno.h>
+ #include <linux/fs.h>
++#include <linux/kernel.h>
+ #include <linux/kobject.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+@@ -176,7 +177,6 @@ const struct file_operations bin_fops =
+ * sysfs_create_bin_file - create binary file for object.
+ * @kobj: object.
+ * @attr: attribute descriptor.
+- *
+ */
+
+ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
+@@ -191,13 +191,16 @@ int sysfs_create_bin_file(struct kobject
+ * sysfs_remove_bin_file - remove binary file for object.
+ * @kobj: object.
+ * @attr: attribute descriptor.
+- *
+ */
+
+-int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
++void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
+ {
+- sysfs_hash_and_remove(kobj->dentry,attr->attr.name);
+- return 0;
++ if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) {
++ printk(KERN_ERR "%s: "
++ "bad dentry or inode or no such file: \"%s\"\n",
++ __FUNCTION__, attr->attr.name);
++ dump_stack();
++ }
+ }
+
+ EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
+diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
+index 61c4243..3aa3434 100644
+--- a/fs/sysfs/dir.c
++++ b/fs/sysfs/dir.c
+@@ -43,7 +43,7 @@ static struct sysfs_dirent * sysfs_new_d
+
+ memset(sd, 0, sizeof(*sd));
+ atomic_set(&sd->s_count, 1);
+- atomic_set(&sd->s_event, 0);
++ atomic_set(&sd->s_event, 1);
+ INIT_LIST_HEAD(&sd->s_children);
+ list_add(&sd->s_sibling, &parent_sd->s_children);
+ sd->s_element = element;
+@@ -103,7 +103,7 @@ static int init_dir(struct inode * inode
+ inode->i_fop = &sysfs_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ return 0;
+ }
+
+@@ -137,7 +137,7 @@ static int create_dir(struct kobject * k
+ if (!error) {
+ error = sysfs_create(*d, mode, init_dir);
+ if (!error) {
+- p->d_inode->i_nlink++;
++ inc_nlink(p->d_inode);
+ (*d)->d_op = &sysfs_dentry_ops;
+ d_rehash(*d);
+ }
+diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
+index cf37866..298303b 100644
+--- a/fs/sysfs/file.c
++++ b/fs/sysfs/file.c
+@@ -157,8 +157,8 @@ sysfs_read_file(struct file *file, char
+ if ((retval = fill_read_buffer(file->f_dentry,buffer)))
+ goto out;
+ }
+- pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
+- __FUNCTION__,count,*ppos,buffer->page);
++ pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
++ __FUNCTION__, count, *ppos, buffer->page);
+ retval = flush_read_buffer(buffer,buf,count,ppos);
+ out:
+ up(&buffer->sem);
+@@ -483,17 +483,12 @@ int sysfs_update_file(struct kobject * k
+ (victim->d_parent->d_inode == dir->d_inode)) {
+ victim->d_inode->i_mtime = CURRENT_TIME;
+ fsnotify_modify(victim);
+-
+- /**
+- * Drop reference from initial sysfs_get_dentry().
+- */
+- dput(victim);
+ res = 0;
+ } else
+ d_drop(victim);
+
+ /**
+- * Drop the reference acquired from sysfs_get_dentry() above.
++ * Drop the reference acquired from lookup_one_len() above.
+ */
+ dput(victim);
+ }
+diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
+index 9889e54..e79e38d 100644
+--- a/fs/sysfs/inode.c
++++ b/fs/sysfs/inode.c
+@@ -12,6 +12,7 @@
+ #include <linux/namei.h>
+ #include <linux/backing-dev.h>
+ #include <linux/capability.h>
++#include <linux/errno.h>
+ #include "sysfs.h"
+
+ extern struct super_block * sysfs_sb;
+@@ -124,7 +125,6 @@ struct inode * sysfs_new_inode(mode_t mo
+ {
+ struct inode * inode = new_inode(sysfs_sb);
+ if (inode) {
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->a_ops = &sysfs_aops;
+ inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
+@@ -234,17 +234,18 @@ void sysfs_drop_dentry(struct sysfs_dire
+ }
+ }
+
+-void sysfs_hash_and_remove(struct dentry * dir, const char * name)
++int sysfs_hash_and_remove(struct dentry * dir, const char * name)
+ {
+ struct sysfs_dirent * sd;
+ struct sysfs_dirent * parent_sd;
++ int found = 0;
+
+ if (!dir)
+- return;
++ return -ENOENT;
+
+ if (dir->d_inode == NULL)
+ /* no inode means this hasn't been made visible yet */
+- return;
++ return -ENOENT;
+
+ parent_sd = dir->d_fsdata;
+ mutex_lock(&dir->d_inode->i_mutex);
+@@ -255,8 +256,11 @@ void sysfs_hash_and_remove(struct dentry
+ list_del_init(&sd->s_sibling);
+ sysfs_drop_dentry(sd, dir);
+ sysfs_put(sd);
++ found = 1;
+ break;
+ }
+ }
+ mutex_unlock(&dir->d_inode->i_mutex);
++
++ return found ? 0 : -ENOENT;
+ }
+diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
+index 40190c4..20551a1 100644
+--- a/fs/sysfs/mount.c
++++ b/fs/sysfs/mount.c
+@@ -49,7 +49,7 @@ static int sysfs_fill_super(struct super
+ inode->i_op = &sysfs_dir_inode_operations;
+ inode->i_fop = &sysfs_dir_operations;
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ } else {
+ pr_debug("sysfs: could not get root inode\n");
+ return -ENOMEM;
+diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
+index d2eac3c..f50e3cc 100644
+--- a/fs/sysfs/symlink.c
++++ b/fs/sysfs/symlink.c
+@@ -3,6 +3,7 @@
+ */
+
+ #include <linux/fs.h>
++#include <linux/mount.h>
+ #include <linux/module.h>
+ #include <linux/kobject.h>
+ #include <linux/namei.h>
+@@ -82,10 +83,19 @@ exit1:
+ */
+ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
+ {
+- struct dentry * dentry = kobj->dentry;
++ struct dentry *dentry = NULL;
+ int error = -EEXIST;
+
+- BUG_ON(!kobj || !kobj->dentry || !name);
++ BUG_ON(!name);
++
++ if (!kobj) {
++ if (sysfs_mount && sysfs_mount->mnt_sb)
++ dentry = sysfs_mount->mnt_sb->s_root;
++ } else
++ dentry = kobj->dentry;
++
++ if (!dentry)
++ return -EFAULT;
+
+ mutex_lock(&dentry->d_inode->i_mutex);
+ if (!sysfs_dirent_exist(dentry->d_fsdata, name))
+diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
+index 3651ffb..6f3d6bd 100644
+--- a/fs/sysfs/sysfs.h
++++ b/fs/sysfs/sysfs.h
+@@ -10,7 +10,7 @@ extern int sysfs_make_dirent(struct sysf
+ umode_t, int);
+
+ extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
+-extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
++extern int sysfs_hash_and_remove(struct dentry * dir, const char * name);
+ extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
+
+ extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
+diff --git a/fs/sysv/file.c b/fs/sysv/file.c
+index a59e303..47a4b72 100644
+--- a/fs/sysv/file.c
++++ b/fs/sysv/file.c
+@@ -21,8 +21,10 @@
+ */
+ const struct file_operations sysv_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .fsync = sysv_sync_file,
+ .sendfile = generic_file_sendfile,
+diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
+index 9b585d1..115ab0d 100644
+--- a/fs/sysv/ialloc.c
++++ b/fs/sysv/ialloc.c
+@@ -170,7 +170,7 @@ struct inode * sysv_new_inode(const stru
+ inode->i_uid = current->fsuid;
+ inode->i_ino = fs16_to_cpu(sbi, ino);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+ memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
+ SYSV_I(inode)->i_dir_start_lookup = 0;
+ insert_inode_hash(inode);
+diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
+index 58b2d22..d63c5e4 100644
+--- a/fs/sysv/inode.c
++++ b/fs/sysv/inode.c
+@@ -201,7 +201,7 @@ static void sysv_read_inode(struct inode
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_atime.tv_nsec = 0;
+ inode->i_mtime.tv_nsec = 0;
+- inode->i_blocks = inode->i_blksize = 0;
++ inode->i_blocks = 0;
+
+ si = SYSV_I(inode);
+ for (block = 0; block < 10+1+1+1; block++)
+diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
+index b8a73f7..f7c08db 100644
+--- a/fs/sysv/namei.c
++++ b/fs/sysv/namei.c
+@@ -250,7 +250,7 @@ static int sysv_rename(struct inode * ol
+ sysv_set_link(new_de, new_page, old_inode);
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+ if (dir_de)
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ inode_dec_link_count(new_inode);
+ } else {
+ if (dir_de) {
+diff --git a/fs/sysv/super.c b/fs/sysv/super.c
+index 876639b..dc9e7dc 100644
+--- a/fs/sysv/super.c
++++ b/fs/sysv/super.c
+@@ -358,21 +358,15 @@ static int sysv_fill_super(struct super_
+ unsigned long blocknr;
+ int size = 0, i;
+
+- if (1024 != sizeof (struct xenix_super_block))
+- panic("Xenix FS: bad superblock size");
+- if (512 != sizeof (struct sysv4_super_block))
+- panic("SystemV FS: bad superblock size");
+- if (512 != sizeof (struct sysv2_super_block))
+- panic("SystemV FS: bad superblock size");
+- if (500 != sizeof (struct coh_super_block))
+- panic("Coherent FS: bad superblock size");
+- if (64 != sizeof (struct sysv_inode))
+- panic("sysv fs: bad inode size");
++ BUILD_BUG_ON(1024 != sizeof (struct xenix_super_block));
++ BUILD_BUG_ON(512 != sizeof (struct sysv4_super_block));
++ BUILD_BUG_ON(512 != sizeof (struct sysv2_super_block));
++ BUILD_BUG_ON(500 != sizeof (struct coh_super_block));
++ BUILD_BUG_ON(64 != sizeof (struct sysv_inode));
+
+- sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+- memset(sbi, 0, sizeof(struct sysv_sb_info));
+
+ sbi->s_sb = sb;
+ sbi->s_block_base = 0;
+@@ -453,10 +447,9 @@ static int v7_fill_super(struct super_bl
+ if (64 != sizeof (struct sysv_inode))
+ panic("sysv fs: bad i-node size");
+
+- sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+- memset(sbi, 0, sizeof(struct sysv_sb_info));
+
+ sbi->s_sb = sb;
+ sbi->s_block_base = 0;
+diff --git a/fs/udf/file.c b/fs/udf/file.c
+index a59e5f3..7aedd55 100644
+--- a/fs/udf/file.c
++++ b/fs/udf/file.c
+@@ -103,19 +103,21 @@ const struct address_space_operations ud
+ .commit_write = udf_adinicb_commit_write,
+ };
+
+-static ssize_t udf_file_write(struct file * file, const char __user * buf,
+- size_t count, loff_t *ppos)
++static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t ppos)
+ {
+ ssize_t retval;
++ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_dentry->d_inode;
+ int err, pos;
++ size_t count = iocb->ki_left;
+
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+ {
+ if (file->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else
+- pos = *ppos;
++ pos = ppos;
+
+ if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
+ pos + count))
+@@ -136,7 +138,7 @@ static ssize_t udf_file_write(struct fil
+ }
+ }
+
+- retval = generic_file_write(file, buf, count, ppos);
++ retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
+
+ if (retval > 0)
+ mark_inode_dirty(inode);
+@@ -249,11 +251,13 @@ static int udf_release_file(struct inode
+ }
+
+ const struct file_operations udf_file_operations = {
+- .read = generic_file_read,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
+ .ioctl = udf_ioctl,
+ .open = generic_file_open,
+ .mmap = generic_file_mmap,
+- .write = udf_file_write,
++ .write = do_sync_write,
++ .aio_write = udf_file_aio_write,
+ .release = udf_release_file,
+ .fsync = udf_fsync_file,
+ .sendfile = generic_file_sendfile,
+diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
+index 3332347..8206983 100644
+--- a/fs/udf/ialloc.c
++++ b/fs/udf/ialloc.c
+@@ -121,7 +121,6 @@ struct inode * udf_new_inode (struct ino
+ UDF_I_LOCATION(inode).logicalBlockNum = block;
+ UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
+ inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
+- inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = 0;
+ UDF_I_LENEATTR(inode) = 0;
+ UDF_I_LENALLOC(inode) = 0;
+@@ -130,14 +129,12 @@ struct inode * udf_new_inode (struct ino
+ {
+ UDF_I_EFE(inode) = 1;
+ UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
+- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
+- memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
++ UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
+ }
+ else
+ {
+ UDF_I_EFE(inode) = 0;
+- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
+- memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct fileEntry));
++ UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
+ }
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
+ UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
+diff --git a/fs/udf/inode.c b/fs/udf/inode.c
+index 605f511..ae21a0e 100644
+--- a/fs/udf/inode.c
++++ b/fs/udf/inode.c
+@@ -916,8 +916,6 @@ __udf_read_inode(struct inode *inode)
+ * i_nlink = 1
+ * i_op = NULL;
+ */
+- inode->i_blksize = PAGE_SIZE;
+-
+ bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
+
+ if (!bh)
+@@ -1167,7 +1165,7 @@ static void udf_fill_inode(struct inode
+ inode->i_op = &udf_dir_inode_operations;
+ inode->i_fop = &udf_dir_operations;
+ inode->i_mode |= S_IFDIR;
+- inode->i_nlink ++;
++ inc_nlink(inode);
+ break;
+ }
+ case ICBTAG_FILE_TYPE_REALTIME:
+diff --git a/fs/udf/namei.c b/fs/udf/namei.c
+index ab9a762..7316332 100644
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -762,7 +762,7 @@ static int udf_mkdir(struct inode * dir,
+ cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
+ udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
+- dir->i_nlink++;
++ inc_nlink(dir);
+ mark_inode_dirty(dir);
+ d_instantiate(dentry, inode);
+ if (fibh.sbh != fibh.ebh)
+@@ -876,10 +876,9 @@ static int udf_rmdir(struct inode * dir,
+ udf_warning(inode->i_sb, "udf_rmdir",
+ "empty directory has nlink != 2 (%d)",
+ inode->i_nlink);
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_size = 0;
+- mark_inode_dirty(inode);
+- dir->i_nlink --;
++ inode_dec_link_count(inode);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ mark_inode_dirty(dir);
+
+@@ -923,8 +922,7 @@ static int udf_unlink(struct inode * dir
+ goto end_unlink;
+ dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ mark_inode_dirty(dir);
+- inode->i_nlink--;
+- mark_inode_dirty(inode);
++ inode_dec_link_count(inode);
+ inode->i_ctime = dir->i_ctime;
+ retval = 0;
+
+@@ -1101,8 +1099,7 @@ out:
+ return err;
+
+ out_no_entry:
+- inode->i_nlink--;
+- mark_inode_dirty(inode);
++ inode_dec_link_count(inode);
+ iput(inode);
+ goto out;
+ }
+@@ -1150,7 +1147,7 @@ static int udf_link(struct dentry * old_
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+- inode->i_nlink ++;
++ inc_nlink(inode);
+ inode->i_ctime = current_fs_time(inode->i_sb);
+ mark_inode_dirty(inode);
+ atomic_inc(&inode->i_count);
+@@ -1261,9 +1258,8 @@ static int udf_rename (struct inode * ol
+
+ if (new_inode)
+ {
+- new_inode->i_nlink--;
+ new_inode->i_ctime = current_fs_time(new_inode->i_sb);
+- mark_inode_dirty(new_inode);
++ inode_dec_link_count(new_inode);
+ }
+ old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
+ mark_inode_dirty(old_dir);
+@@ -1279,16 +1275,14 @@ static int udf_rename (struct inode * ol
+ }
+ else
+ mark_buffer_dirty_inode(dir_bh, old_inode);
+- old_dir->i_nlink --;
+- mark_inode_dirty(old_dir);
++ inode_dec_link_count(old_dir);
+ if (new_inode)
+ {
+- new_inode->i_nlink --;
+- mark_inode_dirty(new_inode);
++ inode_dec_link_count(new_inode);
+ }
+ else
+ {
+- new_dir->i_nlink ++;
++ inc_nlink(new_dir);
+ mark_inode_dirty(new_dir);
+ }
+ }
+diff --git a/fs/udf/super.c b/fs/udf/super.c
+index fcce1a2..1aea6a4 100644
+--- a/fs/udf/super.c
++++ b/fs/udf/super.c
+@@ -156,8 +156,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(udf_inode_cachep))
+- printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(udf_inode_cachep);
+ }
+
+ /* Superblock operations */
+@@ -1622,6 +1621,11 @@ static int udf_fill_super(struct super_b
+ goto error_out;
+ }
+
++ if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_READ_ONLY) {
++ printk("UDF-fs: Partition marked readonly; forcing readonly mount\n");
++ sb->s_flags |= MS_RDONLY;
++ }
++
+ if ( udf_find_fileset(sb, &fileset, &rootdir) )
+ {
+ printk("UDF-fs: No fileset found\n");
+diff --git a/fs/ufs/file.c b/fs/ufs/file.c
+index a9c6e5f..1e09632 100644
+--- a/fs/ufs/file.c
++++ b/fs/ufs/file.c
+@@ -53,8 +53,10 @@ static int ufs_sync_file(struct file *fi
+
+ const struct file_operations ufs_file_operations = {
+ .llseek = generic_file_llseek,
+- .read = generic_file_read,
+- .write = generic_file_write,
++ .read = do_sync_read,
++ .aio_read = generic_file_aio_read,
++ .write = do_sync_write,
++ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .open = generic_file_open,
+ .fsync = ufs_sync_file,
+diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
+index 9501dcd..2ad1259 100644
+--- a/fs/ufs/ialloc.c
++++ b/fs/ufs/ialloc.c
+@@ -255,7 +255,6 @@ cg_found:
+ inode->i_gid = current->fsgid;
+
+ inode->i_ino = cg * uspi->s_ipg + bit;
+- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ ufsi->i_flags = UFS_I(dir)->i_flags;
+diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
+index 30c6e8a..ee1eaa6 100644
+--- a/fs/ufs/inode.c
++++ b/fs/ufs/inode.c
+@@ -741,7 +741,6 @@ void ufs_read_inode(struct inode * inode
+ ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino));
+ }
+
+- inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/
+ inode->i_version++;
+ ufsi->i_lastfrag =
+ (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
+index d344b41..e84c0ec 100644
+--- a/fs/ufs/namei.c
++++ b/fs/ufs/namei.c
+@@ -308,7 +308,7 @@ static int ufs_rename(struct inode *old_
+ ufs_set_link(new_dir, new_de, new_page, old_inode);
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+ if (dir_de)
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ inode_dec_link_count(new_inode);
+ } else {
+ if (dir_de) {
+diff --git a/fs/ufs/super.c b/fs/ufs/super.c
+index 992ee0b..ec79e30 100644
+--- a/fs/ufs/super.c
++++ b/fs/ufs/super.c
+@@ -611,11 +611,10 @@ static int ufs_fill_super(struct super_b
+
+ UFSD("ENTER\n");
+
+- sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
++ sbi = kzalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
+ if (!sbi)
+ goto failed_nomem;
+ sb->s_fs_info = sbi;
+- memset(sbi, 0, sizeof(struct ufs_sb_info));
+
+ UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
+
+@@ -1245,8 +1244,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(ufs_inode_cachep))
+- printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(ufs_inode_cachep);
+ }
+
+ #ifdef CONFIG_QUOTA
+diff --git a/fs/ufs/util.c b/fs/ufs/util.c
+index 22f820a..1743757 100644
+--- a/fs/ufs/util.c
++++ b/fs/ufs/util.c
+@@ -184,14 +184,13 @@ void _ubh_memcpyubh_(struct ufs_sb_priva
+ dev_t
+ ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
+ {
+- __fs32 fs32;
++ __u32 fs32;
+ dev_t dev;
+
+ if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+- fs32 = ufsi->i_u1.i_data[1];
++ fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[1]);
+ else
+- fs32 = ufsi->i_u1.i_data[0];
+- fs32 = fs32_to_cpu(sb, fs32);
++ fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[0]);
+ switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
+ case UFS_ST_SUNx86:
+ case UFS_ST_SUN:
+@@ -212,7 +211,7 @@ ufs_get_inode_dev(struct super_block *sb
+ void
+ ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev)
+ {
+- __fs32 fs32;
++ __u32 fs32;
+
+ switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
+ case UFS_ST_SUNx86:
+@@ -227,11 +226,10 @@ ufs_set_inode_dev(struct super_block *sb
+ fs32 = old_encode_dev(dev);
+ break;
+ }
+- fs32 = cpu_to_fs32(sb, fs32);
+ if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+- ufsi->i_u1.i_data[1] = fs32;
++ ufsi->i_u1.i_data[1] = cpu_to_fs32(sb, fs32);
+ else
+- ufsi->i_u1.i_data[0] = fs32;
++ ufsi->i_u1.i_data[0] = cpu_to_fs32(sb, fs32);
+ }
+
+ /**
+diff --git a/fs/utimes.c b/fs/utimes.c
+new file mode 100644
+index 0000000..1bcd852
+--- /dev/null
++++ b/fs/utimes.c
+@@ -0,0 +1,137 @@
++#include <linux/compiler.h>
++#include <linux/fs.h>
++#include <linux/linkage.h>
++#include <linux/namei.h>
++#include <linux/utime.h>
++#include <asm/uaccess.h>
++#include <asm/unistd.h>
++
++#ifdef __ARCH_WANT_SYS_UTIME
++
++/*
++ * sys_utime() can be implemented in user-level using sys_utimes().
++ * Is this for backwards compatibility? If so, why not move it
++ * into the appropriate arch directory (for those architectures that
++ * need it).
++ */
++
++/* If times==NULL, set access and modification to current time,
++ * must be owner or have write permission.
++ * Else, update from *times, must be owner or super user.
++ */
++asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
++{
++ int error;
++ struct nameidata nd;
++ struct inode * inode;
++ struct iattr newattrs;
++
++ error = user_path_walk(filename, &nd);
++ if (error)
++ goto out;
++ inode = nd.dentry->d_inode;
++
++ error = -EROFS;
++ if (IS_RDONLY(inode))
++ goto dput_and_out;
++
++ /* Don't worry, the checks are done in inode_change_ok() */
++ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
++ if (times) {
++ error = -EPERM;
++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
++ goto dput_and_out;
++
++ error = get_user(newattrs.ia_atime.tv_sec, ×->actime);
++ newattrs.ia_atime.tv_nsec = 0;
++ if (!error)
++ error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime);
++ newattrs.ia_mtime.tv_nsec = 0;
++ if (error)
++ goto dput_and_out;
++
++ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
++ } else {
++ error = -EACCES;
++ if (IS_IMMUTABLE(inode))
++ goto dput_and_out;
++
++ if (current->fsuid != inode->i_uid &&
++ (error = vfs_permission(&nd, MAY_WRITE)) != 0)
++ goto dput_and_out;
++ }
++ mutex_lock(&inode->i_mutex);
++ error = notify_change(nd.dentry, &newattrs);
++ mutex_unlock(&inode->i_mutex);
++dput_and_out:
++ path_release(&nd);
++out:
++ return error;
++}
++
++#endif
++
++/* If times==NULL, set access and modification to current time,
++ * must be owner or have write permission.
++ * Else, update from *times, must be owner or super user.
++ */
++long do_utimes(int dfd, char __user *filename, struct timeval *times)
++{
++ int error;
++ struct nameidata nd;
++ struct inode * inode;
++ struct iattr newattrs;
++
++ error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
++
++ if (error)
++ goto out;
++ inode = nd.dentry->d_inode;
++
++ error = -EROFS;
++ if (IS_RDONLY(inode))
++ goto dput_and_out;
++
++ /* Don't worry, the checks are done in inode_change_ok() */
++ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
++ if (times) {
++ error = -EPERM;
++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
++ goto dput_and_out;
++
++ newattrs.ia_atime.tv_sec = times[0].tv_sec;
++ newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
++ newattrs.ia_mtime.tv_sec = times[1].tv_sec;
++ newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
++ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
++ } else {
++ error = -EACCES;
++ if (IS_IMMUTABLE(inode))
++ goto dput_and_out;
++
++ if (current->fsuid != inode->i_uid &&
++ (error = vfs_permission(&nd, MAY_WRITE)) != 0)
++ goto dput_and_out;
++ }
++ mutex_lock(&inode->i_mutex);
++ error = notify_change(nd.dentry, &newattrs);
++ mutex_unlock(&inode->i_mutex);
++dput_and_out:
++ path_release(&nd);
++out:
++ return error;
++}
++
++asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
++{
++ struct timeval times[2];
++
++ if (utimes && copy_from_user(×, utimes, sizeof(times)))
++ return -EFAULT;
++ return do_utimes(dfd, filename, utimes ? times : NULL);
++}
++
++asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
++{
++ return sys_futimesat(AT_FDCWD, filename, utimes);
++}
+diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
+index 9a8f48b..edb711f 100644
+--- a/fs/vfat/namei.c
++++ b/fs/vfat/namei.c
+@@ -782,9 +782,9 @@ static int vfat_rmdir(struct inode *dir,
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+- dir->i_nlink--;
++ drop_nlink(dir);
+
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
+ fat_detach(inode);
+ out:
+@@ -808,7 +808,7 @@ static int vfat_unlink(struct inode *dir
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+- inode->i_nlink = 0;
++ clear_nlink(inode);
+ inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
+ fat_detach(inode);
+ out:
+@@ -837,7 +837,7 @@ static int vfat_mkdir(struct inode *dir,
+ if (err)
+ goto out_free;
+ dir->i_version++;
+- dir->i_nlink++;
++ inc_nlink(dir);
+
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ brelse(sinfo.bh);
+@@ -930,9 +930,9 @@ static int vfat_rename(struct inode *old
+ if (err)
+ goto error_dotdot;
+ }
+- old_dir->i_nlink--;
++ drop_nlink(old_dir);
+ if (!new_inode)
+- new_dir->i_nlink++;
++ inc_nlink(new_dir);
+ }
+
+ err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
+@@ -947,10 +947,9 @@ static int vfat_rename(struct inode *old
+ mark_inode_dirty(old_dir);
+
+ if (new_inode) {
++ drop_nlink(new_inode);
+ if (is_dir)
+- new_inode->i_nlink -= 2;
+- else
+- new_inode->i_nlink--;
++ drop_nlink(new_inode);
+ new_inode->i_ctime = ts;
+ }
+ out:
+diff --git a/fs/xattr.c b/fs/xattr.c
+index c32f15b..0901bdc 100644
+--- a/fs/xattr.c
++++ b/fs/xattr.c
+@@ -48,14 +48,21 @@ xattr_permission(struct inode *inode, co
+ return 0;
+
+ /*
+- * The trusted.* namespace can only accessed by a privilegued user.
++ * The trusted.* namespace can only be accessed by a privileged user.
+ */
+ if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
+ return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
+
++ /* In user.* namespace, only regular files and directories can have
++ * extended attributes. For sticky directories, only the owner and
++ * privileged user can write attributes.
++ */
+ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+- if (!S_ISREG(inode->i_mode) &&
+- (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
++ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
++ return -EPERM;
++ if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
++ (mask & MAY_WRITE) && (current->fsuid != inode->i_uid) &&
++ !capable(CAP_FOWNER))
+ return -EPERM;
+ }
+
+@@ -135,6 +142,26 @@ vfs_getxattr(struct dentry *dentry, char
+ }
+ EXPORT_SYMBOL_GPL(vfs_getxattr);
+
++ssize_t
++vfs_listxattr(struct dentry *d, char *list, size_t size)
++{
++ ssize_t error;
++
++ error = security_inode_listxattr(d);
++ if (error)
++ return error;
++ error = -EOPNOTSUPP;
++ if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
++ error = d->d_inode->i_op->listxattr(d, list, size);
++ } else {
++ error = security_inode_listsecurity(d->d_inode, list, size);
++ if (size && error > size)
++ error = -ERANGE;
++ }
++ return error;
++}
++EXPORT_SYMBOL_GPL(vfs_listxattr);
++
+ int
+ vfs_removexattr(struct dentry *dentry, char *name)
+ {
+@@ -346,17 +373,7 @@ listxattr(struct dentry *d, char __user
+ return -ENOMEM;
+ }
+
+- error = security_inode_listxattr(d);
+- if (error)
+- goto out;
+- error = -EOPNOTSUPP;
+- if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
+- error = d->d_inode->i_op->listxattr(d, klist, size);
+- } else {
+- error = security_inode_listsecurity(d->d_inode, klist, size);
+- if (size && error > size)
+- error = -ERANGE;
+- }
++ error = vfs_listxattr(d, klist, size);
+ if (error > 0) {
+ if (size && copy_to_user(list, klist, error))
+ error = -EFAULT;
+@@ -365,7 +382,6 @@ listxattr(struct dentry *d, char __user
+ than XATTR_LIST_MAX bytes. Not possible. */
+ error = -E2BIG;
+ }
+-out:
+ kfree(klist);
+ return error;
+ }
+diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
+index 26b364c..35115bc 100644
+--- a/fs/xfs/Kconfig
++++ b/fs/xfs/Kconfig
+@@ -1,5 +1,6 @@
+ config XFS_FS
+ tristate "XFS filesystem support"
++ depends on BLOCK
+ help
+ XFS is a high performance journaling filesystem which originated
+ on the SGI IRIX platform. It is completely multi-threaded, can
+diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6
+index 9e7f859..291948d 100644
+--- a/fs/xfs/Makefile-linux-2.6
++++ b/fs/xfs/Makefile-linux-2.6
+@@ -30,7 +30,6 @@ ifeq ($(CONFIG_XFS_TRACE),y)
+ EXTRA_CFLAGS += -DXFS_BLI_TRACE
+ EXTRA_CFLAGS += -DXFS_BMAP_TRACE
+ EXTRA_CFLAGS += -DXFS_BMBT_TRACE
+- EXTRA_CFLAGS += -DXFS_DIR_TRACE
+ EXTRA_CFLAGS += -DXFS_DIR2_TRACE
+ EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
+ EXTRA_CFLAGS += -DXFS_ILOCK_TRACE
+diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c
+index aba7fcf..004baf6 100644
+--- a/fs/xfs/linux-2.6/kmem.c
++++ b/fs/xfs/linux-2.6/kmem.c
+@@ -21,6 +21,7 @@
+ #include <linux/highmem.h>
+ #include <linux/swap.h>
+ #include <linux/blkdev.h>
++#include <linux/backing-dev.h>
+ #include "time.h"
+ #include "kmem.h"
+
+@@ -34,6 +35,14 @@ kmem_alloc(size_t size, unsigned int __n
+ gfp_t lflags = kmem_flags_convert(flags);
+ void *ptr;
+
++#ifdef DEBUG
++ if (unlikely(!(flags & KM_LARGE) && (size > PAGE_SIZE))) {
++ printk(KERN_WARNING "Large %s attempt, size=%ld\n",
++ __FUNCTION__, (long)size);
++ dump_stack();
++ }
++#endif
++
+ do {
+ if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS)
+ ptr = kmalloc(size, lflags);
+@@ -45,7 +54,7 @@ kmem_alloc(size_t size, unsigned int __n
+ printk(KERN_ERR "XFS: possible memory allocation "
+ "deadlock in %s (mode:0x%x)\n",
+ __FUNCTION__, lflags);
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ } while (1);
+ }
+
+@@ -60,6 +69,27 @@ kmem_zalloc(size_t size, unsigned int __
+ return ptr;
+ }
+
++void *
++kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize,
++ unsigned int __nocast flags)
++{
++ void *ptr;
++ size_t kmsize = maxsize;
++ unsigned int kmflags = (flags & ~KM_SLEEP) | KM_NOSLEEP;
++
++ while (!(ptr = kmem_zalloc(kmsize, kmflags))) {
++ if ((kmsize <= minsize) && (flags & KM_NOSLEEP))
++ break;
++ if ((kmsize >>= 1) <= minsize) {
++ kmsize = minsize;
++ kmflags = flags;
++ }
++ }
++ if (ptr)
++ *size = kmsize;
++ return ptr;
++}
++
+ void
+ kmem_free(void *ptr, size_t size)
+ {
+@@ -102,7 +132,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsig
+ printk(KERN_ERR "XFS: possible memory allocation "
+ "deadlock in %s (mode:0x%x)\n",
+ __FUNCTION__, lflags);
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ } while (1);
+ }
+
+diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
+index 939bd84..9ebabdf 100644
+--- a/fs/xfs/linux-2.6/kmem.h
++++ b/fs/xfs/linux-2.6/kmem.h
+@@ -30,6 +30,7 @@
+ #define KM_NOSLEEP 0x0002u
+ #define KM_NOFS 0x0004u
+ #define KM_MAYFAIL 0x0008u
++#define KM_LARGE 0x0010u
+
+ /*
+ * We use a special process flag to avoid recursive callbacks into
+@@ -41,7 +42,7 @@ kmem_flags_convert(unsigned int __nocast
+ {
+ gfp_t lflags;
+
+- BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL));
++ BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL|KM_LARGE));
+
+ if (flags & KM_NOSLEEP) {
+ lflags = GFP_ATOMIC | __GFP_NOWARN;
+@@ -54,8 +55,9 @@ kmem_flags_convert(unsigned int __nocast
+ }
+
+ extern void *kmem_alloc(size_t, unsigned int __nocast);
+-extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
+ extern void *kmem_zalloc(size_t, unsigned int __nocast);
++extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast);
++extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
+ extern void kmem_free(void *, size_t);
+
+ /*
+@@ -91,8 +93,8 @@ kmem_zone_free(kmem_zone_t *zone, void *
+ static inline void
+ kmem_zone_destroy(kmem_zone_t *zone)
+ {
+- if (zone && kmem_cache_destroy(zone))
+- BUG();
++ if (zone)
++ kmem_cache_destroy(zone);
+ }
+
+ extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
+diff --git a/fs/xfs/linux-2.6/sema.h b/fs/xfs/linux-2.6/sema.h
+index b250900..2009e6d 100644
+--- a/fs/xfs/linux-2.6/sema.h
++++ b/fs/xfs/linux-2.6/sema.h
+@@ -29,8 +29,6 @@
+
+ typedef struct semaphore sema_t;
+
+-#define init_sema(sp, val, c, d) sema_init(sp, val)
+-#define initsema(sp, val) sema_init(sp, val)
+ #define initnsema(sp, val, name) sema_init(sp, val)
+ #define psema(sp, b) down(sp)
+ #define vsema(sp) up(sp)
+diff --git a/fs/xfs/linux-2.6/sv.h b/fs/xfs/linux-2.6/sv.h
+index 9a8ad48..351a8f4 100644
+--- a/fs/xfs/linux-2.6/sv.h
++++ b/fs/xfs/linux-2.6/sv.h
+@@ -53,8 +53,6 @@ static inline void _sv_wait(sv_t *sv, sp
+ remove_wait_queue(&sv->waiters, &wait);
+ }
+
+-#define init_sv(sv,type,name,flag) \
+- init_waitqueue_head(&(sv)->waiters)
+ #define sv_init(sv,flag,name) \
+ init_waitqueue_head(&(sv)->waiters)
+ #define sv_destroy(sv) \
+diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
+index 34dcb43..09360cf 100644
+--- a/fs/xfs/linux-2.6/xfs_aops.c
++++ b/fs/xfs/linux-2.6/xfs_aops.c
+@@ -71,7 +71,7 @@ xfs_page_trace(
+ int tag,
+ struct inode *inode,
+ struct page *page,
+- int mask)
++ unsigned long pgoff)
+ {
+ xfs_inode_t *ip;
+ bhv_vnode_t *vp = vn_from_inode(inode);
+@@ -91,7 +91,7 @@ xfs_page_trace(
+ (void *)ip,
+ (void *)inode,
+ (void *)page,
+- (void *)((unsigned long)mask),
++ (void *)pgoff,
+ (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
+ (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
+ (void *)((unsigned long)((isize >> 32) & 0xffffffff)),
+@@ -105,7 +105,7 @@ xfs_page_trace(
+ (void *)NULL);
+ }
+ #else
+-#define xfs_page_trace(tag, inode, page, mask)
++#define xfs_page_trace(tag, inode, page, pgoff)
+ #endif
+
+ /*
+@@ -1197,7 +1197,7 @@ xfs_vm_releasepage(
+ .nr_to_write = 1,
+ };
+
+- xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask);
++ xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, 0);
+
+ if (!page_has_buffers(page))
+ return 0;
+@@ -1356,7 +1356,6 @@ xfs_end_io_direct(
+ ioend->io_size = size;
+ xfs_finish_ioend(ioend);
+ } else {
+- ASSERT(size >= 0);
+ xfs_destroy_ioend(ioend);
+ }
+
+diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
+index 2af528d..db5f5a3 100644
+--- a/fs/xfs/linux-2.6/xfs_buf.c
++++ b/fs/xfs/linux-2.6/xfs_buf.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
++ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -30,6 +30,7 @@
+ #include <linux/hash.h>
+ #include <linux/kthread.h>
+ #include <linux/migrate.h>
++#include <linux/backing-dev.h>
+ #include "xfs_linux.h"
+
+ STATIC kmem_zone_t *xfs_buf_zone;
+@@ -318,8 +319,12 @@ xfs_buf_free(
+ if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1))
+ free_address(bp->b_addr - bp->b_offset);
+
+- for (i = 0; i < bp->b_page_count; i++)
+- page_cache_release(bp->b_pages[i]);
++ for (i = 0; i < bp->b_page_count; i++) {
++ struct page *page = bp->b_pages[i];
++
++ ASSERT(!PagePrivate(page));
++ page_cache_release(page);
++ }
+ _xfs_buf_free_pages(bp);
+ } else if (bp->b_flags & _XBF_KMEM_ALLOC) {
+ /*
+@@ -391,7 +396,7 @@ _xfs_buf_lookup_pages(
+
+ XFS_STATS_INC(xb_page_retries);
+ xfsbufd_wakeup(0, gfp_mask);
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ goto retry;
+ }
+
+@@ -400,6 +405,7 @@ _xfs_buf_lookup_pages(
+ nbytes = min_t(size_t, size, PAGE_CACHE_SIZE - offset);
+ size -= nbytes;
+
++ ASSERT(!PagePrivate(page));
+ if (!PageUptodate(page)) {
+ page_count--;
+ if (blocksize >= PAGE_CACHE_SIZE) {
+@@ -768,7 +774,7 @@ xfs_buf_get_noaddr(
+ _xfs_buf_initialize(bp, target, 0, len, 0);
+
+ try_again:
+- data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL);
++ data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL | KM_LARGE);
+ if (unlikely(data == NULL))
+ goto fail_free_buf;
+
+@@ -1117,10 +1123,10 @@ xfs_buf_bio_end_io(
+ do {
+ struct page *page = bvec->bv_page;
+
++ ASSERT(!PagePrivate(page));
+ if (unlikely(bp->b_error)) {
+ if (bp->b_flags & XBF_READ)
+ ClearPageUptodate(page);
+- SetPageError(page);
+ } else if (blocksize >= PAGE_CACHE_SIZE) {
+ SetPageUptodate(page);
+ } else if (!PagePrivate(page) &&
+@@ -1156,16 +1162,16 @@ _xfs_buf_ioapply(
+ total_nr_pages = bp->b_page_count;
+ map_i = 0;
+
+- if (bp->b_flags & _XBF_RUN_QUEUES) {
+- bp->b_flags &= ~_XBF_RUN_QUEUES;
+- rw = (bp->b_flags & XBF_READ) ? READ_SYNC : WRITE_SYNC;
+- } else {
+- rw = (bp->b_flags & XBF_READ) ? READ : WRITE;
+- }
+-
+ if (bp->b_flags & XBF_ORDERED) {
+ ASSERT(!(bp->b_flags & XBF_READ));
+ rw = WRITE_BARRIER;
++ } else if (bp->b_flags & _XBF_RUN_QUEUES) {
++ ASSERT(!(bp->b_flags & XBF_READ_AHEAD));
++ bp->b_flags &= ~_XBF_RUN_QUEUES;
++ rw = (bp->b_flags & XBF_WRITE) ? WRITE_SYNC : READ_SYNC;
++ } else {
++ rw = (bp->b_flags & XBF_WRITE) ? WRITE :
++ (bp->b_flags & XBF_READ_AHEAD) ? READA : READ;
+ }
+
+ /* Special code path for reading a sub page size buffer in --
+@@ -1681,6 +1687,7 @@ xfsbufd(
+ xfs_buf_t *bp, *n;
+ struct list_head *dwq = &target->bt_delwrite_queue;
+ spinlock_t *dwlk = &target->bt_delwrite_lock;
++ int count;
+
+ current->flags |= PF_MEMALLOC;
+
+@@ -1696,6 +1703,7 @@ xfsbufd(
+ schedule_timeout_interruptible(
+ xfs_buf_timer_centisecs * msecs_to_jiffies(10));
+
++ count = 0;
+ age = xfs_buf_age_centisecs * msecs_to_jiffies(10);
+ spin_lock(dwlk);
+ list_for_each_entry_safe(bp, n, dwq, b_list) {
+@@ -1711,9 +1719,11 @@ xfsbufd(
+ break;
+ }
+
+- bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
++ bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q|
++ _XBF_RUN_QUEUES);
+ bp->b_flags |= XBF_WRITE;
+- list_move(&bp->b_list, &tmp);
++ list_move_tail(&bp->b_list, &tmp);
++ count++;
+ }
+ }
+ spin_unlock(dwlk);
+@@ -1724,12 +1734,12 @@ xfsbufd(
+
+ list_del_init(&bp->b_list);
+ xfs_buf_iostrategy(bp);
+-
+- blk_run_address_space(target->bt_mapping);
+ }
+
+ if (as_list_len > 0)
+ purge_addresses();
++ if (count)
++ blk_run_address_space(target->bt_mapping);
+
+ clear_bit(XBT_FORCE_FLUSH, &target->bt_flags);
+ } while (!kthread_should_stop());
+@@ -1767,7 +1777,7 @@ xfs_flush_buftarg(
+ continue;
+ }
+
+- list_move(&bp->b_list, &tmp);
++ list_move_tail(&bp->b_list, &tmp);
+ }
+ spin_unlock(dwlk);
+
+@@ -1776,7 +1786,7 @@ xfs_flush_buftarg(
+ */
+ list_for_each_entry_safe(bp, n, &tmp, b_list) {
+ xfs_buf_lock(bp);
+- bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
++ bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q|_XBF_RUN_QUEUES);
+ bp->b_flags |= XBF_WRITE;
+ if (wait)
+ bp->b_flags &= ~XBF_ASYNC;
+@@ -1786,6 +1796,9 @@ xfs_flush_buftarg(
+ xfs_buf_iostrategy(bp);
+ }
+
++ if (wait)
++ blk_run_address_space(target->bt_mapping);
++
+ /*
+ * Remaining list items must be flushed before returning
+ */
+@@ -1797,9 +1810,6 @@ xfs_flush_buftarg(
+ xfs_buf_relse(bp);
+ }
+
+- if (wait)
+- blk_run_address_space(target->bt_mapping);
+-
+ return pincount;
+ }
+
+diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
+index 7858703..9dd235c 100644
+--- a/fs/xfs/linux-2.6/xfs_buf.h
++++ b/fs/xfs/linux-2.6/xfs_buf.h
+@@ -298,11 +298,6 @@ extern void xfs_buf_trace(xfs_buf_t *, c
+ #define XFS_BUF_UNWRITE(bp) ((bp)->b_flags &= ~XBF_WRITE)
+ #define XFS_BUF_ISWRITE(bp) ((bp)->b_flags & XBF_WRITE)
+
+-#define XFS_BUF_ISUNINITIAL(bp) (0)
+-#define XFS_BUF_UNUNINITIAL(bp) (0)
+-
+-#define XFS_BUF_BP_ISMAPPED(bp) (1)
+-
+ #define XFS_BUF_IODONE_FUNC(bp) ((bp)->b_iodone)
+ #define XFS_BUF_SET_IODONE_FUNC(bp, func) ((bp)->b_iodone = (func))
+ #define XFS_BUF_CLR_IODONE_FUNC(bp) ((bp)->b_iodone = NULL)
+@@ -393,8 +388,6 @@ static inline int XFS_bwrite(xfs_buf_t *
+ return error;
+ }
+
+-#define XFS_bdwrite(bp) xfs_buf_iostart(bp, XBF_DELWRI | XBF_ASYNC)
+-
+ static inline int xfs_bdwrite(void *mp, xfs_buf_t *bp)
+ {
+ bp->b_strat = xfs_bdstrat_cb;
+diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
+index 3d4f6df..d93d8dd 100644
+--- a/fs/xfs/linux-2.6/xfs_file.c
++++ b/fs/xfs/linux-2.6/xfs_file.c
+@@ -49,50 +49,49 @@ static struct vm_operations_struct xfs_d
+ STATIC inline ssize_t
+ __xfs_file_read(
+ struct kiocb *iocb,
+- char __user *buf,
++ const struct iovec *iov,
++ unsigned long nr_segs,
+ int ioflags,
+- size_t count,
+ loff_t pos)
+ {
+- struct iovec iov = {buf, count};
+ struct file *file = iocb->ki_filp;
+ bhv_vnode_t *vp = vn_from_inode(file->f_dentry->d_inode);
+
+ BUG_ON(iocb->ki_pos != pos);
+ if (unlikely(file->f_flags & O_DIRECT))
+ ioflags |= IO_ISDIRECT;
+- return bhv_vop_read(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
++ return bhv_vop_read(vp, iocb, iov, nr_segs, &iocb->ki_pos,
++ ioflags, NULL);
+ }
+
+ STATIC ssize_t
+ xfs_file_aio_read(
+ struct kiocb *iocb,
+- char __user *buf,
+- size_t count,
++ const struct iovec *iov,
++ unsigned long nr_segs,
+ loff_t pos)
+ {
+- return __xfs_file_read(iocb, buf, IO_ISAIO, count, pos);
++ return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos);
+ }
+
+ STATIC ssize_t
+ xfs_file_aio_read_invis(
+ struct kiocb *iocb,
+- char __user *buf,
+- size_t count,
++ const struct iovec *iov,
++ unsigned long nr_segs,
+ loff_t pos)
+ {
+- return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
++ return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
+ }
+
+ STATIC inline ssize_t
+ __xfs_file_write(
+- struct kiocb *iocb,
+- const char __user *buf,
+- int ioflags,
+- size_t count,
+- loff_t pos)
++ struct kiocb *iocb,
++ const struct iovec *iov,
++ unsigned long nr_segs,
++ int ioflags,
++ loff_t pos)
+ {
+- struct iovec iov = {(void __user *)buf, count};
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_mapping->host;
+ bhv_vnode_t *vp = vn_from_inode(inode);
+@@ -100,117 +99,28 @@ __xfs_file_write(
+ BUG_ON(iocb->ki_pos != pos);
+ if (unlikely(file->f_flags & O_DIRECT))
+ ioflags |= IO_ISDIRECT;
+- return bhv_vop_write(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
++ return bhv_vop_write(vp, iocb, iov, nr_segs, &iocb->ki_pos,
++ ioflags, NULL);
+ }
+
+ STATIC ssize_t
+ xfs_file_aio_write(
+ struct kiocb *iocb,
+- const char __user *buf,
+- size_t count,
++ const struct iovec *iov,
++ unsigned long nr_segs,
+ loff_t pos)
+ {
+- return __xfs_file_write(iocb, buf, IO_ISAIO, count, pos);
++ return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos);
+ }
+
+ STATIC ssize_t
+ xfs_file_aio_write_invis(
+ struct kiocb *iocb,
+- const char __user *buf,
+- size_t count,
+- loff_t pos)
+-{
+- return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
+-}
+-
+-STATIC inline ssize_t
+-__xfs_file_readv(
+- struct file *file,
+- const struct iovec *iov,
+- int ioflags,
+- unsigned long nr_segs,
+- loff_t *ppos)
+-{
+- struct inode *inode = file->f_mapping->host;
+- bhv_vnode_t *vp = vn_from_inode(inode);
+- struct kiocb kiocb;
+- ssize_t rval;
+-
+- init_sync_kiocb(&kiocb, file);
+- kiocb.ki_pos = *ppos;
+-
+- if (unlikely(file->f_flags & O_DIRECT))
+- ioflags |= IO_ISDIRECT;
+- rval = bhv_vop_read(vp, &kiocb, iov, nr_segs,
+- &kiocb.ki_pos, ioflags, NULL);
+-
+- *ppos = kiocb.ki_pos;
+- return rval;
+-}
+-
+-STATIC ssize_t
+-xfs_file_readv(
+- struct file *file,
+- const struct iovec *iov,
+- unsigned long nr_segs,
+- loff_t *ppos)
+-{
+- return __xfs_file_readv(file, iov, 0, nr_segs, ppos);
+-}
+-
+-STATIC ssize_t
+-xfs_file_readv_invis(
+- struct file *file,
+- const struct iovec *iov,
+- unsigned long nr_segs,
+- loff_t *ppos)
+-{
+- return __xfs_file_readv(file, iov, IO_INVIS, nr_segs, ppos);
+-}
+-
+-STATIC inline ssize_t
+-__xfs_file_writev(
+- struct file *file,
+- const struct iovec *iov,
+- int ioflags,
+- unsigned long nr_segs,
+- loff_t *ppos)
+-{
+- struct inode *inode = file->f_mapping->host;
+- bhv_vnode_t *vp = vn_from_inode(inode);
+- struct kiocb kiocb;
+- ssize_t rval;
+-
+- init_sync_kiocb(&kiocb, file);
+- kiocb.ki_pos = *ppos;
+- if (unlikely(file->f_flags & O_DIRECT))
+- ioflags |= IO_ISDIRECT;
+-
+- rval = bhv_vop_write(vp, &kiocb, iov, nr_segs,
+- &kiocb.ki_pos, ioflags, NULL);
+-
+- *ppos = kiocb.ki_pos;
+- return rval;
+-}
+-
+-STATIC ssize_t
+-xfs_file_writev(
+- struct file *file,
+- const struct iovec *iov,
++ const struct iovec *iov,
+ unsigned long nr_segs,
+- loff_t *ppos)
+-{
+- return __xfs_file_writev(file, iov, 0, nr_segs, ppos);
+-}
+-
+-STATIC ssize_t
+-xfs_file_writev_invis(
+- struct file *file,
+- const struct iovec *iov,
+- unsigned long nr_segs,
+- loff_t *ppos)
++ loff_t pos)
+ {
+- return __xfs_file_writev(file, iov, IO_INVIS, nr_segs, ppos);
++ return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
+ }
+
+ STATIC ssize_t
+@@ -370,7 +280,7 @@ xfs_file_readdir(
+
+ /* Try fairly hard to get memory */
+ do {
+- if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL)))
++ if ((read_buf = kmalloc(rlen, GFP_KERNEL)))
+ break;
+ rlen >>= 1;
+ } while (rlen >= 1024);
+@@ -540,8 +450,6 @@ const struct file_operations xfs_file_op
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+- .readv = xfs_file_readv,
+- .writev = xfs_file_writev,
+ .aio_read = xfs_file_aio_read,
+ .aio_write = xfs_file_aio_write,
+ .sendfile = xfs_file_sendfile,
+@@ -565,8 +473,6 @@ const struct file_operations xfs_invis_f
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+- .readv = xfs_file_readv_invis,
+- .writev = xfs_file_writev_invis,
+ .aio_read = xfs_file_aio_read_invis,
+ .aio_write = xfs_file_aio_write_invis,
+ .sendfile = xfs_file_sendfile_invis,
+diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c
+index 6c162c3..ed3a5e1 100644
+--- a/fs/xfs/linux-2.6/xfs_globals.c
++++ b/fs/xfs/linux-2.6/xfs_globals.c
+@@ -34,7 +34,7 @@ xfs_param_t xfs_params = {
+ .restrict_chown = { 0, 1, 1 },
+ .sgid_inherit = { 0, 0, 1 },
+ .symlink_mode = { 0, 0, 1 },
+- .panic_mask = { 0, 0, 127 },
++ .panic_mask = { 0, 0, 255 },
+ .error_level = { 0, 3, 11 },
+ .syncd_timer = { 1*100, 30*100, 7200*100},
+ .stats_clear = { 0, 0, 1 },
+diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
+index 6e52a5d..a74f854 100644
+--- a/fs/xfs/linux-2.6/xfs_ioctl.c
++++ b/fs/xfs/linux-2.6/xfs_ioctl.c
+@@ -653,7 +653,7 @@ xfs_attrmulti_by_handle(
+ STATIC int
+ xfs_ioc_space(
+ bhv_desc_t *bdp,
+- bhv_vnode_t *vp,
++ struct inode *inode,
+ struct file *filp,
+ int flags,
+ unsigned int cmd,
+@@ -735,7 +735,7 @@ xfs_ioctl(
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+- return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
++ return xfs_ioc_space(bdp, inode, filp, ioflags, cmd, arg);
+
+ case XFS_IOC_DIOINFO: {
+ struct dioattr da;
+@@ -763,6 +763,8 @@ xfs_ioctl(
+ return xfs_ioc_fsgeometry(mp, arg);
+
+ case XFS_IOC_GETVERSION:
++ return put_user(inode->i_generation, (int __user *)arg);
++
+ case XFS_IOC_GETXFLAGS:
+ case XFS_IOC_SETXFLAGS:
+ case XFS_IOC_FSGETXATTR:
+@@ -957,7 +959,7 @@ xfs_ioctl(
+ STATIC int
+ xfs_ioc_space(
+ bhv_desc_t *bdp,
+- bhv_vnode_t *vp,
++ struct inode *inode,
+ struct file *filp,
+ int ioflags,
+ unsigned int cmd,
+@@ -967,13 +969,13 @@ xfs_ioc_space(
+ int attr_flags = 0;
+ int error;
+
+- if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
++ if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
+ return -XFS_ERROR(EPERM);
+
+ if (!(filp->f_mode & FMODE_WRITE))
+ return -XFS_ERROR(EBADF);
+
+- if (!VN_ISREG(vp))
++ if (!S_ISREG(inode->i_mode))
+ return -XFS_ERROR(EINVAL);
+
+ if (copy_from_user(&bf, arg, sizeof(bf)))
+@@ -1264,13 +1266,6 @@ xfs_ioc_xattr(
+ break;
+ }
+
+- case XFS_IOC_GETVERSION: {
+- flags = vn_to_inode(vp)->i_generation;
+- if (copy_to_user(arg, &flags, sizeof(flags)))
+- error = -EFAULT;
+- break;
+- }
+-
+ default:
+ error = -ENOTTY;
+ break;
+diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
+index d918002..3ba814a 100644
+--- a/fs/xfs/linux-2.6/xfs_iops.c
++++ b/fs/xfs/linux-2.6/xfs_iops.c
+@@ -553,13 +553,13 @@ xfs_vn_follow_link(
+ ASSERT(dentry);
+ ASSERT(nd);
+
+- link = (char *)kmalloc(MAXPATHLEN+1, GFP_KERNEL);
++ link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
+ if (!link) {
+ nd_set_link(nd, ERR_PTR(-ENOMEM));
+ return NULL;
+ }
+
+- uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
++ uio = kmalloc(sizeof(uio_t), GFP_KERNEL);
+ if (!uio) {
+ kfree(link);
+ nd_set_link(nd, ERR_PTR(-ENOMEM));
+@@ -623,12 +623,27 @@ xfs_vn_getattr(
+ {
+ struct inode *inode = dentry->d_inode;
+ bhv_vnode_t *vp = vn_from_inode(inode);
+- int error = 0;
++ bhv_vattr_t vattr = { .va_mask = XFS_AT_STAT };
++ int error;
+
+- if (unlikely(vp->v_flag & VMODIFIED))
+- error = vn_revalidate(vp);
+- if (!error)
+- generic_fillattr(inode, stat);
++ error = bhv_vop_getattr(vp, &vattr, ATTR_LAZY, NULL);
++ if (likely(!error)) {
++ stat->size = i_size_read(inode);
++ stat->dev = inode->i_sb->s_dev;
++ stat->rdev = (vattr.va_rdev == 0) ? 0 :
++ MKDEV(sysv_major(vattr.va_rdev) & 0x1ff,
++ sysv_minor(vattr.va_rdev));
++ stat->mode = vattr.va_mode;
++ stat->nlink = vattr.va_nlink;
++ stat->uid = vattr.va_uid;
++ stat->gid = vattr.va_gid;
++ stat->ino = vattr.va_nodeid;
++ stat->atime = vattr.va_atime;
++ stat->mtime = vattr.va_mtime;
++ stat->ctime = vattr.va_ctime;
++ stat->blocks = vattr.va_nblocks;
++ stat->blksize = vattr.va_blocksize;
++ }
+ return -error;
+ }
+
+diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
+index a13f75c..2b0e001 100644
+--- a/fs/xfs/linux-2.6/xfs_linux.h
++++ b/fs/xfs/linux-2.6/xfs_linux.h
+@@ -148,11 +148,7 @@ BUFFER_FNS(PrivateStart, unwritten);
+ (current->flags = ((current->flags & ~(f)) | (*(sp) & (f))))
+
+ #define NBPP PAGE_SIZE
+-#define DPPSHFT (PAGE_SHIFT - 9)
+ #define NDPP (1 << (PAGE_SHIFT - 9))
+-#define dtop(DD) (((DD) + NDPP - 1) >> DPPSHFT)
+-#define dtopt(DD) ((DD) >> DPPSHFT)
+-#define dpoff(DD) ((DD) & (NDPP-1))
+
+ #define NBBY 8 /* number of bits per byte */
+ #define NBPC PAGE_SIZE /* Number of bytes per click */
+@@ -172,8 +168,6 @@ BUFFER_FNS(PrivateStart, unwritten);
+ #define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT)
+ #define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT)
+ #define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT)
+-#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))>>IO_BPCSHIFT)
+-#define io_btoct(x) ((__psunsigned_t)(x)>>IO_BPCSHIFT)
+
+ /* off_t bytes to clicks */
+ #define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT)
+@@ -186,7 +180,6 @@ BUFFER_FNS(PrivateStart, unwritten);
+ #define ctob(x) ((__psunsigned_t)(x)<<BPCSHIFT)
+ #define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT)
+ #define ctob64(x) ((__uint64_t)(x)<<BPCSHIFT)
+-#define io_ctob(x) ((__psunsigned_t)(x)<<IO_BPCSHIFT)
+
+ /* bytes to clicks */
+ #define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))>>BPCSHIFT)
+@@ -339,4 +332,11 @@ static inline __uint64_t roundup_64(__ui
+ return(x * y);
+ }
+
++static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
++{
++ x += y - 1;
++ do_div(x, y);
++ return x;
++}
++
+ #endif /* __XFS_LINUX__ */
+diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
+index ee788b1..fa842f1 100644
+--- a/fs/xfs/linux-2.6/xfs_lrw.c
++++ b/fs/xfs/linux-2.6/xfs_lrw.c
+@@ -270,16 +270,18 @@ xfs_read(
+ }
+ }
+
+- if (unlikely((ioflags & IO_ISDIRECT) && VN_CACHED(vp)))
+- bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
+- -1, FI_REMAPF_LOCKED);
+-
+- if (unlikely(ioflags & IO_ISDIRECT))
++ if (unlikely(ioflags & IO_ISDIRECT)) {
++ if (VN_CACHED(vp))
++ bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
++ -1, FI_REMAPF_LOCKED);
+ mutex_unlock(&inode->i_mutex);
++ }
+
+ xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
+ (void *)iovp, segs, *offset, ioflags);
+- ret = __generic_file_aio_read(iocb, iovp, segs, offset);
++
++ iocb->ki_pos = *offset;
++ ret = generic_file_aio_read(iocb, iovp, segs, *offset);
+ if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO))
+ ret = wait_on_sync_kiocb(iocb);
+ if (ret > 0)
+diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
+index 4754f34..38c4d12 100644
+--- a/fs/xfs/linux-2.6/xfs_super.c
++++ b/fs/xfs/linux-2.6/xfs_super.c
+@@ -171,7 +171,6 @@ xfs_revalidate_inode(
+ break;
+ }
+
+- inode->i_blksize = xfs_preferred_iosize(mp);
+ inode->i_generation = ip->i_d.di_gen;
+ i_size_write(inode, ip->i_d.di_size);
+ inode->i_blocks =
+@@ -228,7 +227,9 @@ xfs_initialize_vnode(
+ xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+ xfs_set_inodeops(inode);
+
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags &= ~XFS_INEW;
++ spin_unlock(&ip->i_flags_lock);
+ barrier();
+
+ unlock_new_inode(inode);
+diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
+index 91fc2c4..da255bd 100644
+--- a/fs/xfs/linux-2.6/xfs_vfs.h
++++ b/fs/xfs/linux-2.6/xfs_vfs.h
+@@ -79,7 +79,7 @@ typedef enum {
+ #define VFS_RDONLY 0x0001 /* read-only vfs */
+ #define VFS_GRPID 0x0002 /* group-ID assigned from directory */
+ #define VFS_DMI 0x0004 /* filesystem has the DMI enabled */
+-#define VFS_UMOUNT 0x0008 /* unmount in progress */
++/* ---- VFS_UMOUNT ---- 0x0008 -- unneeded, fixed via kthread APIs */
+ #define VFS_32BITINODES 0x0010 /* do not use inums above 32 bits */
+ #define VFS_END 0x0010 /* max flag */
+
+diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c
+index 6628d96..553fa73 100644
+--- a/fs/xfs/linux-2.6/xfs_vnode.c
++++ b/fs/xfs/linux-2.6/xfs_vnode.c
+@@ -122,7 +122,6 @@ vn_revalidate_core(
+ inode->i_blocks = vap->va_nblocks;
+ inode->i_mtime = vap->va_mtime;
+ inode->i_ctime = vap->va_ctime;
+- inode->i_blksize = vap->va_blocksize;
+ if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
+ inode->i_flags |= S_IMMUTABLE;
+ else
+diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
+index c42b322..515f5fd 100644
+--- a/fs/xfs/linux-2.6/xfs_vnode.h
++++ b/fs/xfs/linux-2.6/xfs_vnode.h
+@@ -85,8 +85,6 @@ typedef enum {
+ #define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh)))
+ #define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name)
+ #define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp)
+-#define vn_bhv_lookup(bhp,ops) bhv_lookup(bhp,ops)
+-#define vn_bhv_lookup_unlocked(bhp,ops) bhv_lookup_unlocked(bhp,ops)
+
+ /*
+ * Vnode to Linux inode mapping.
+diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
+index 5b2dcc5..33ad5af 100644
+--- a/fs/xfs/quota/xfs_dquot_item.c
++++ b/fs/xfs/quota/xfs_dquot_item.c
+@@ -382,18 +382,6 @@ xfs_qm_dquot_logitem_unlock(
+
+
+ /*
+- * The transaction with the dquot locked has aborted. The dquot
+- * must not be dirty within the transaction. We simply unlock just
+- * as if the transaction had been cancelled.
+- */
+-STATIC void
+-xfs_qm_dquot_logitem_abort(
+- xfs_dq_logitem_t *ql)
+-{
+- xfs_qm_dquot_logitem_unlock(ql);
+-}
+-
+-/*
+ * this needs to stamp an lsn into the dquot, I think.
+ * rpc's that look at user dquot's would then have to
+ * push on the dependency recorded in the dquot
+@@ -426,7 +414,6 @@ STATIC struct xfs_item_ops xfs_dquot_ite
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_qm_dquot_logitem_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
+ .iop_pushbuf = (void(*)(xfs_log_item_t*))
+ xfs_qm_dquot_logitem_pushbuf,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+@@ -559,17 +546,6 @@ xfs_qm_qoff_logitem_committed(xfs_qoff_l
+ }
+
+ /*
+- * The transaction of which this QUOTAOFF is a part has been aborted.
+- * Just clean up after ourselves.
+- * Shouldn't this never happen in the case of qoffend logitems? XXX
+- */
+-STATIC void
+-xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
+-{
+- kmem_free(qf, sizeof(xfs_qoff_logitem_t));
+-}
+-
+-/*
+ * There isn't much you can do to push on an quotaoff item. It is simply
+ * stuck waiting for the log to be flushed to disk.
+ */
+@@ -644,7 +620,6 @@ STATIC struct xfs_item_ops xfs_qm_qoffen
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_qm_qoffend_logitem_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
+ .iop_pushbuf = NULL,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_qm_qoffend_logitem_committing
+@@ -667,7 +642,6 @@ STATIC struct xfs_item_ops xfs_qm_qoff_l
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_qm_qoff_logitem_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
+ .iop_pushbuf = NULL,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_qm_qoff_logitem_committing
+diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
+index e23e455..7c6a3a5 100644
+--- a/fs/xfs/quota/xfs_qm.c
++++ b/fs/xfs/quota/xfs_qm.c
+@@ -112,17 +112,17 @@ xfs_Gqm_init(void)
+ {
+ xfs_dqhash_t *udqhash, *gdqhash;
+ xfs_qm_t *xqm;
+- uint i, hsize, flags = KM_SLEEP | KM_MAYFAIL;
++ size_t hsize;
++ uint i;
+
+ /*
+ * Initialize the dquot hash tables.
+ */
+- hsize = XFS_QM_HASHSIZE_HIGH;
+- while (!(udqhash = kmem_zalloc(hsize * sizeof(xfs_dqhash_t), flags))) {
+- if ((hsize >>= 1) <= XFS_QM_HASHSIZE_LOW)
+- flags = KM_SLEEP;
+- }
+- gdqhash = kmem_zalloc(hsize * sizeof(xfs_dqhash_t), KM_SLEEP);
++ udqhash = kmem_zalloc_greedy(&hsize,
++ XFS_QM_HASHSIZE_LOW, XFS_QM_HASHSIZE_HIGH,
++ KM_SLEEP | KM_MAYFAIL | KM_LARGE);
++ gdqhash = kmem_zalloc(hsize, KM_SLEEP | KM_LARGE);
++ hsize /= sizeof(xfs_dqhash_t);
+ ndquot = hsize << 8;
+
+ xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
+diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h
+index 4568deb..689407d 100644
+--- a/fs/xfs/quota/xfs_qm.h
++++ b/fs/xfs/quota/xfs_qm.h
+@@ -56,12 +56,6 @@ extern kmem_zone_t *qm_dqtrxzone;
+ #define XFS_QM_HASHSIZE_HIGH ((NBPP * 4) / sizeof(xfs_dqhash_t))
+
+ /*
+- * We output a cmn_err when quotachecking a quota file with more than
+- * this many fsbs.
+- */
+-#define XFS_QM_BIG_QCHECK_NBLKS 500
+-
+-/*
+ * This defines the unit of allocation of dquots.
+ * Currently, it is just one file system block, and a 4K blk contains 30
+ * (136 * 30 = 4080) dquots. It's probably not worth trying to make
+diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h
+index b7ddd04..a8b85e2 100644
+--- a/fs/xfs/quota/xfs_quota_priv.h
++++ b/fs/xfs/quota/xfs_quota_priv.h
+@@ -75,7 +75,6 @@ static inline int XQMISLCKD(struct xfs_d
+
+ #define xfs_qm_freelist_lock(qm) XQMLCK(&((qm)->qm_dqfreelist))
+ #define xfs_qm_freelist_unlock(qm) XQMUNLCK(&((qm)->qm_dqfreelist))
+-#define XFS_QM_IS_FREELIST_LOCKED(qm) XQMISLCKD(&((qm)->qm_dqfreelist))
+
+ /*
+ * Hash into a bucket in the dquot hash table, based on <mp, id>.
+@@ -170,6 +169,5 @@ for ((dqp) = (qlist)->qh_next; (dqp) !=
+ #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
+ (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \
+ (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???")))
+-#define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
+
+ #endif /* __XFS_QUOTA_PRIV_H__ */
+diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
+index 36fbecc..c75f683 100644
+--- a/fs/xfs/support/debug.c
++++ b/fs/xfs/support/debug.c
+@@ -53,8 +53,7 @@ cmn_err(register int level, char *fmt, .
+ va_end(ap);
+ spin_unlock_irqrestore(&xfs_err_lock,flags);
+
+- if (level == CE_PANIC)
+- BUG();
++ BUG_ON(level == CE_PANIC);
+ }
+
+ void
+@@ -72,8 +71,7 @@ icmn_err(register int level, char *fmt,
+ strcat(message, "\n");
+ spin_unlock_irqrestore(&xfs_err_lock,flags);
+ printk("%s%s", err_level[level], message);
+- if (level == CE_PANIC)
+- BUG();
++ BUG_ON(level == CE_PANIC);
+ }
+
+ void
+diff --git a/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c
+index addf5a7..5cf2e86 100644
+--- a/fs/xfs/support/ktrace.c
++++ b/fs/xfs/support/ktrace.c
+@@ -75,7 +75,7 @@ ktrace_alloc(int nentries, unsigned int
+ sleep);
+ } else {
+ ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)),
+- sleep);
++ sleep | KM_LARGE);
+ }
+
+ if (ktep == NULL) {
+diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
+index dc2361d..9ece7f8 100644
+--- a/fs/xfs/xfs_ag.h
++++ b/fs/xfs/xfs_ag.h
+@@ -150,7 +150,7 @@ typedef struct xfs_agi {
+ #define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)XFS_BUF_PTR(bp))
+
+ typedef struct xfs_agfl {
+- xfs_agblock_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
++ __be32 agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
+ } xfs_agfl_t;
+
+ /*
+diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
+index d2bbcd8..e80dda3 100644
+--- a/fs/xfs/xfs_alloc.c
++++ b/fs/xfs/xfs_alloc.c
+@@ -1477,8 +1477,10 @@ xfs_alloc_ag_vextent_small(
+ /*
+ * Can't allocate from the freelist for some reason.
+ */
+- else
++ else {
++ fbno = NULLAGBLOCK;
+ flen = 0;
++ }
+ /*
+ * Can't do the allocation, give up.
+ */
+@@ -2021,7 +2023,7 @@ xfs_alloc_get_freelist(
+ /*
+ * Get the block number and update the data structures.
+ */
+- bno = INT_GET(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)], ARCH_CONVERT);
++ bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
+ be32_add(&agf->agf_flfirst, 1);
+ xfs_trans_brelse(tp, agflbp);
+ if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
+@@ -2108,7 +2110,7 @@ xfs_alloc_put_freelist(
+ {
+ xfs_agf_t *agf; /* a.g. freespace structure */
+ xfs_agfl_t *agfl; /* a.g. free block array */
+- xfs_agblock_t *blockp;/* pointer to array entry */
++ __be32 *blockp;/* pointer to array entry */
+ int error;
+ #ifdef XFS_ALLOC_TRACE
+ static char fname[] = "xfs_alloc_put_freelist";
+@@ -2132,7 +2134,7 @@ xfs_alloc_put_freelist(
+ pag->pagf_flcount++;
+ ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
+ blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
+- INT_SET(*blockp, ARCH_CONVERT, bno);
++ *blockp = cpu_to_be32(bno);
+ TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
+ xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
+ xfs_trans_log_buf(tp, agflbp,
+diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
+index 7446556..74cadf9 100644
+--- a/fs/xfs/xfs_alloc_btree.c
++++ b/fs/xfs/xfs_alloc_btree.c
+@@ -92,6 +92,7 @@ xfs_alloc_delrec(
+ xfs_alloc_key_t *rkp; /* right block key pointer */
+ xfs_alloc_ptr_t *rpp; /* right block address pointer */
+ int rrecs=0; /* number of records in right block */
++ int numrecs;
+ xfs_alloc_rec_t *rrp; /* right block record pointer */
+ xfs_btree_cur_t *tcur; /* temporary btree cursor */
+
+@@ -115,7 +116,8 @@ xfs_alloc_delrec(
+ /*
+ * Fail if we're off the end of the block.
+ */
+- if (ptr > be16_to_cpu(block->bb_numrecs)) {
++ numrecs = be16_to_cpu(block->bb_numrecs);
++ if (ptr > numrecs) {
+ *stat = 0;
+ return 0;
+ }
+@@ -129,18 +131,18 @@ xfs_alloc_delrec(
+ lkp = XFS_ALLOC_KEY_ADDR(block, 1, cur);
+ lpp = XFS_ALLOC_PTR_ADDR(block, 1, cur);
+ #ifdef DEBUG
+- for (i = ptr; i < be16_to_cpu(block->bb_numrecs); i++) {
++ for (i = ptr; i < numrecs; i++) {
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(lpp[i]), level)))
+ return error;
+ }
+ #endif
+- if (ptr < be16_to_cpu(block->bb_numrecs)) {
++ if (ptr < numrecs) {
+ memmove(&lkp[ptr - 1], &lkp[ptr],
+- (be16_to_cpu(block->bb_numrecs) - ptr) * sizeof(*lkp));
++ (numrecs - ptr) * sizeof(*lkp));
+ memmove(&lpp[ptr - 1], &lpp[ptr],
+- (be16_to_cpu(block->bb_numrecs) - ptr) * sizeof(*lpp));
+- xfs_alloc_log_ptrs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs) - 1);
+- xfs_alloc_log_keys(cur, bp, ptr, be16_to_cpu(block->bb_numrecs) - 1);
++ (numrecs - ptr) * sizeof(*lpp));
++ xfs_alloc_log_ptrs(cur, bp, ptr, numrecs - 1);
++ xfs_alloc_log_keys(cur, bp, ptr, numrecs - 1);
+ }
+ }
+ /*
+@@ -149,10 +151,10 @@ xfs_alloc_delrec(
+ */
+ else {
+ lrp = XFS_ALLOC_REC_ADDR(block, 1, cur);
+- if (ptr < be16_to_cpu(block->bb_numrecs)) {
++ if (ptr < numrecs) {
+ memmove(&lrp[ptr - 1], &lrp[ptr],
+- (be16_to_cpu(block->bb_numrecs) - ptr) * sizeof(*lrp));
+- xfs_alloc_log_recs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs) - 1);
++ (numrecs - ptr) * sizeof(*lrp));
++ xfs_alloc_log_recs(cur, bp, ptr, numrecs - 1);
+ }
+ /*
+ * If it's the first record in the block, we'll need a key
+@@ -167,7 +169,8 @@ xfs_alloc_delrec(
+ /*
+ * Decrement and log the number of entries in the block.
+ */
+- be16_add(&block->bb_numrecs, -1);
++ numrecs--;
++ block->bb_numrecs = cpu_to_be16(numrecs);
+ xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
+ /*
+ * See if the longest free extent in the allocation group was
+@@ -181,14 +184,14 @@ xfs_alloc_delrec(
+ if (level == 0 &&
+ cur->bc_btnum == XFS_BTNUM_CNT &&
+ be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK &&
+- ptr > be16_to_cpu(block->bb_numrecs)) {
+- ASSERT(ptr == be16_to_cpu(block->bb_numrecs) + 1);
++ ptr > numrecs) {
++ ASSERT(ptr == numrecs + 1);
+ /*
+ * There are still records in the block. Grab the size
+ * from the last one.
+ */
+- if (be16_to_cpu(block->bb_numrecs)) {
+- rrp = XFS_ALLOC_REC_ADDR(block, be16_to_cpu(block->bb_numrecs), cur);
++ if (numrecs) {
++ rrp = XFS_ALLOC_REC_ADDR(block, numrecs, cur);
+ agf->agf_longest = rrp->ar_blockcount;
+ }
+ /*
+@@ -211,7 +214,7 @@ xfs_alloc_delrec(
+ * and it's NOT the leaf level,
+ * then we can get rid of this level.
+ */
+- if (be16_to_cpu(block->bb_numrecs) == 1 && level > 0) {
++ if (numrecs == 1 && level > 0) {
+ /*
+ * lpp is still set to the first pointer in the block.
+ * Make it the new root of the btree.
+@@ -267,7 +270,7 @@ xfs_alloc_delrec(
+ * If the number of records remaining in the block is at least
+ * the minimum, we're done.
+ */
+- if (be16_to_cpu(block->bb_numrecs) >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) {
++ if (numrecs >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) {
+ if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i)))
+ return error;
+ *stat = 1;
+@@ -419,19 +422,21 @@ xfs_alloc_delrec(
+ * See if we can join with the left neighbor block.
+ */
+ if (lbno != NULLAGBLOCK &&
+- lrecs + be16_to_cpu(block->bb_numrecs) <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
++ lrecs + numrecs <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
+ /*
+ * Set "right" to be the starting block,
+ * "left" to be the left neighbor.
+ */
+ rbno = bno;
+ right = block;
++ rrecs = be16_to_cpu(right->bb_numrecs);
+ rbp = bp;
+ if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
+ cur->bc_private.a.agno, lbno, 0, &lbp,
+ XFS_ALLOC_BTREE_REF)))
+ return error;
+ left = XFS_BUF_TO_ALLOC_BLOCK(lbp);
++ lrecs = be16_to_cpu(left->bb_numrecs);
+ if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
+ return error;
+ }
+@@ -439,20 +444,21 @@ xfs_alloc_delrec(
+ * If that won't work, see if we can join with the right neighbor block.
+ */
+ else if (rbno != NULLAGBLOCK &&
+- rrecs + be16_to_cpu(block->bb_numrecs) <=
+- XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
++ rrecs + numrecs <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
+ /*
+ * Set "left" to be the starting block,
+ * "right" to be the right neighbor.
+ */
+ lbno = bno;
+ left = block;
++ lrecs = be16_to_cpu(left->bb_numrecs);
+ lbp = bp;
+ if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
+ cur->bc_private.a.agno, rbno, 0, &rbp,
+ XFS_ALLOC_BTREE_REF)))
+ return error;
+ right = XFS_BUF_TO_ALLOC_BLOCK(rbp);
++ rrecs = be16_to_cpu(right->bb_numrecs);
+ if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
+ return error;
+ }
+@@ -474,34 +480,28 @@ xfs_alloc_delrec(
+ /*
+ * It's a non-leaf. Move keys and pointers.
+ */
+- lkp = XFS_ALLOC_KEY_ADDR(left, be16_to_cpu(left->bb_numrecs) + 1, cur);
+- lpp = XFS_ALLOC_PTR_ADDR(left, be16_to_cpu(left->bb_numrecs) + 1, cur);
++ lkp = XFS_ALLOC_KEY_ADDR(left, lrecs + 1, cur);
++ lpp = XFS_ALLOC_PTR_ADDR(left, lrecs + 1, cur);
+ rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur);
+ rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur);
+ #ifdef DEBUG
+- for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {
++ for (i = 0; i < rrecs; i++) {
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i]), level)))
+ return error;
+ }
+ #endif
+- memcpy(lkp, rkp, be16_to_cpu(right->bb_numrecs) * sizeof(*lkp));
+- memcpy(lpp, rpp, be16_to_cpu(right->bb_numrecs) * sizeof(*lpp));
+- xfs_alloc_log_keys(cur, lbp, be16_to_cpu(left->bb_numrecs) + 1,
+- be16_to_cpu(left->bb_numrecs) +
+- be16_to_cpu(right->bb_numrecs));
+- xfs_alloc_log_ptrs(cur, lbp, be16_to_cpu(left->bb_numrecs) + 1,
+- be16_to_cpu(left->bb_numrecs) +
+- be16_to_cpu(right->bb_numrecs));
++ memcpy(lkp, rkp, rrecs * sizeof(*lkp));
++ memcpy(lpp, rpp, rrecs * sizeof(*lpp));
++ xfs_alloc_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs);
++ xfs_alloc_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs);
+ } else {
+ /*
+ * It's a leaf. Move records.
+ */
+- lrp = XFS_ALLOC_REC_ADDR(left, be16_to_cpu(left->bb_numrecs) + 1, cur);
++ lrp = XFS_ALLOC_REC_ADDR(left, lrecs + 1, cur);
+ rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
+- memcpy(lrp, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*lrp));
+- xfs_alloc_log_recs(cur, lbp, be16_to_cpu(left->bb_numrecs) + 1,
+- be16_to_cpu(left->bb_numrecs) +
+- be16_to_cpu(right->bb_numrecs));
++ memcpy(lrp, rrp, rrecs * sizeof(*lrp));
++ xfs_alloc_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs);
+ }
+ /*
+ * If we joined with the left neighbor, set the buffer in the
+@@ -509,7 +509,7 @@ xfs_alloc_delrec(
+ */
+ if (bp != lbp) {
+ xfs_btree_setbuf(cur, level, lbp);
+- cur->bc_ptrs[level] += be16_to_cpu(left->bb_numrecs);
++ cur->bc_ptrs[level] += lrecs;
+ }
+ /*
+ * If we joined with the right neighbor and there's a level above
+@@ -521,7 +521,8 @@ xfs_alloc_delrec(
+ /*
+ * Fix up the number of records in the surviving block.
+ */
+- be16_add(&left->bb_numrecs, be16_to_cpu(right->bb_numrecs));
++ lrecs += rrecs;
++ left->bb_numrecs = cpu_to_be16(lrecs);
+ /*
+ * Fix up the right block pointer in the surviving block, and log it.
+ */
+@@ -608,6 +609,7 @@ xfs_alloc_insrec(
+ xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */
+ xfs_alloc_key_t nkey; /* new key value, from split */
+ xfs_alloc_rec_t nrec; /* new record value, for caller */
++ int numrecs;
+ int optr; /* old ptr value */
+ xfs_alloc_ptr_t *pp; /* pointer to btree addresses */
+ int ptr; /* index in btree block for this rec */
+@@ -653,13 +655,14 @@ xfs_alloc_insrec(
+ */
+ bp = cur->bc_bufs[level];
+ block = XFS_BUF_TO_ALLOC_BLOCK(bp);
++ numrecs = be16_to_cpu(block->bb_numrecs);
+ #ifdef DEBUG
+ if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
+ return error;
+ /*
+ * Check that the new entry is being inserted in the right place.
+ */
+- if (ptr <= be16_to_cpu(block->bb_numrecs)) {
++ if (ptr <= numrecs) {
+ if (level == 0) {
+ rp = XFS_ALLOC_REC_ADDR(block, ptr, cur);
+ xfs_btree_check_rec(cur->bc_btnum, recp, rp);
+@@ -670,12 +673,12 @@ xfs_alloc_insrec(
+ }
+ #endif
+ nbno = NULLAGBLOCK;
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ /*
+ * If the block is full, we can't insert the new entry until we
+ * make the block un-full.
+ */
+- if (be16_to_cpu(block->bb_numrecs) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
++ if (numrecs == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
+ /*
+ * First, try shifting an entry to the right neighbor.
+ */
+@@ -729,6 +732,7 @@ xfs_alloc_insrec(
+ * At this point we know there's room for our new entry in the block
+ * we're pointing at.
+ */
++ numrecs = be16_to_cpu(block->bb_numrecs);
+ if (level > 0) {
+ /*
+ * It's a non-leaf entry. Make a hole for the new data
+@@ -737,15 +741,15 @@ xfs_alloc_insrec(
+ kp = XFS_ALLOC_KEY_ADDR(block, 1, cur);
+ pp = XFS_ALLOC_PTR_ADDR(block, 1, cur);
+ #ifdef DEBUG
+- for (i = be16_to_cpu(block->bb_numrecs); i >= ptr; i--) {
++ for (i = numrecs; i >= ptr; i--) {
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level)))
+ return error;
+ }
+ #endif
+ memmove(&kp[ptr], &kp[ptr - 1],
+- (be16_to_cpu(block->bb_numrecs) - ptr + 1) * sizeof(*kp));
++ (numrecs - ptr + 1) * sizeof(*kp));
+ memmove(&pp[ptr], &pp[ptr - 1],
+- (be16_to_cpu(block->bb_numrecs) - ptr + 1) * sizeof(*pp));
++ (numrecs - ptr + 1) * sizeof(*pp));
+ #ifdef DEBUG
+ if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
+ return error;
+@@ -755,11 +759,12 @@ xfs_alloc_insrec(
+ */
+ kp[ptr - 1] = key;
+ pp[ptr - 1] = cpu_to_be32(*bnop);
+- be16_add(&block->bb_numrecs, 1);
+- xfs_alloc_log_keys(cur, bp, ptr, be16_to_cpu(block->bb_numrecs));
+- xfs_alloc_log_ptrs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs));
++ numrecs++;
++ block->bb_numrecs = cpu_to_be16(numrecs);
++ xfs_alloc_log_keys(cur, bp, ptr, numrecs);
++ xfs_alloc_log_ptrs(cur, bp, ptr, numrecs);
+ #ifdef DEBUG
+- if (ptr < be16_to_cpu(block->bb_numrecs))
++ if (ptr < numrecs)
+ xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,
+ kp + ptr);
+ #endif
+@@ -769,16 +774,17 @@ xfs_alloc_insrec(
+ */
+ rp = XFS_ALLOC_REC_ADDR(block, 1, cur);
+ memmove(&rp[ptr], &rp[ptr - 1],
+- (be16_to_cpu(block->bb_numrecs) - ptr + 1) * sizeof(*rp));
++ (numrecs - ptr + 1) * sizeof(*rp));
+ /*
+ * Now stuff the new record in, bump numrecs
+ * and log the new data.
+ */
+- rp[ptr - 1] = *recp; /* INT_: struct copy */
+- be16_add(&block->bb_numrecs, 1);
+- xfs_alloc_log_recs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs));
++ rp[ptr - 1] = *recp;
++ numrecs++;
++ block->bb_numrecs = cpu_to_be16(numrecs);
++ xfs_alloc_log_recs(cur, bp, ptr, numrecs);
+ #ifdef DEBUG
+- if (ptr < be16_to_cpu(block->bb_numrecs))
++ if (ptr < numrecs)
+ xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,
+ rp + ptr);
+ #endif
+@@ -819,8 +825,8 @@ xfs_alloc_insrec(
+ */
+ *bnop = nbno;
+ if (nbno != NULLAGBLOCK) {
+- *recp = nrec; /* INT_: struct copy */
+- *curp = ncur; /* INT_: struct copy */
++ *recp = nrec;
++ *curp = ncur;
+ }
+ *stat = 1;
+ return 0;
+@@ -981,7 +987,7 @@ xfs_alloc_lookup(
+ */
+ bp = cur->bc_bufs[level];
+ if (bp && XFS_BUF_ADDR(bp) != d)
+- bp = (xfs_buf_t *)0;
++ bp = NULL;
+ if (!bp) {
+ /*
+ * Need to get a new buffer. Read it, then
+@@ -1229,7 +1235,7 @@ xfs_alloc_lshift(
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*rpp), level)))
+ return error;
+ #endif
+- *lpp = *rpp; /* INT_: copy */
++ *lpp = *rpp;
+ xfs_alloc_log_ptrs(cur, lbp, nrec, nrec);
+ xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp);
+ }
+@@ -1406,8 +1412,8 @@ xfs_alloc_newroot(
+
+ kp = XFS_ALLOC_KEY_ADDR(new, 1, cur);
+ if (be16_to_cpu(left->bb_level) > 0) {
+- kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur); /* INT_: structure copy */
+- kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);/* INT_: structure copy */
++ kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur);
++ kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);
+ } else {
+ xfs_alloc_rec_t *rp; /* btree record pointer */
+
+@@ -1527,8 +1533,8 @@ xfs_alloc_rshift(
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*lpp), level)))
+ return error;
+ #endif
+- *rkp = *lkp; /* INT_: copy */
+- *rpp = *lpp; /* INT_: copy */
++ *rkp = *lkp;
++ *rpp = *lpp;
+ xfs_alloc_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
+ xfs_alloc_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
+ xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1);
+@@ -2044,7 +2050,7 @@ xfs_alloc_insert(
+ nbno = NULLAGBLOCK;
+ nrec.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock);
+ nrec.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount);
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ pcur = cur;
+ /*
+ * Loop going up the tree, starting at the leaf level.
+@@ -2076,7 +2082,7 @@ xfs_alloc_insert(
+ */
+ if (ncur) {
+ pcur = ncur;
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ }
+ } while (nbno != NULLAGBLOCK);
+ *stat = i;
+diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
+index 1a21010..9ada7bd 100644
+--- a/fs/xfs/xfs_attr.c
++++ b/fs/xfs/xfs_attr.c
+@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_s
+ /*
+ * Routines to manipulate out-of-line attribute values.
+ */
+-STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
+ STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
+ STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
+
+@@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char
+ return(error);
+ }
+
+-STATIC int
++int
+ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
+ char *value, int valuelen, int flags)
+ {
+@@ -440,7 +439,7 @@ xfs_attr_set(bhv_desc_t *bdp, const char
+ * Generic handler routine to remove a name from an attribute list.
+ * Transitions attribute list from Btree to shortform as necessary.
+ */
+-STATIC int
++int
+ xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
+ {
+ xfs_da_args_t args;
+@@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const c
+ return xfs_attr_remove_int(dp, name, namelen, flags);
+ }
+
++int /* error */
++xfs_attr_list_int(xfs_attr_list_context_t *context)
++{
++ int error;
++ xfs_inode_t *dp = context->dp;
++
++ /*
++ * Decide on what work routines to call based on the inode size.
++ */
++ if (XFS_IFORK_Q(dp) == 0 ||
++ (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
++ dp->i_d.di_anextents == 0)) {
++ error = 0;
++ } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
++ error = xfs_attr_shortform_list(context);
++ } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
++ error = xfs_attr_leaf_list(context);
++ } else {
++ error = xfs_attr_node_list(context);
++ }
++ return error;
++}
++
++#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
++ (((struct attrlist_ent *) 0)->a_name - (char *) 0)
++#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
++ ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
++ & ~(sizeof(u_int32_t)-1))
++
++/*
++ * Format an attribute and copy it out to the user's buffer.
++ * Take care to check values and protect against them changing later,
++ * we may be reading them directly out of a user buffer.
++ */
++/*ARGSUSED*/
++STATIC int
++xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp,
++ char *name, int namelen,
++ int valuelen, char *value)
++{
++ attrlist_ent_t *aep;
++ int arraytop;
++
++ ASSERT(!(context->flags & ATTR_KERNOVAL));
++ ASSERT(context->count >= 0);
++ ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
++ ASSERT(context->firstu >= sizeof(*context->alist));
++ ASSERT(context->firstu <= context->bufsize);
++
++ arraytop = sizeof(*context->alist) +
++ context->count * sizeof(context->alist->al_offset[0]);
++ context->firstu -= ATTR_ENTSIZE(namelen);
++ if (context->firstu < arraytop) {
++ xfs_attr_trace_l_c("buffer full", context);
++ context->alist->al_more = 1;
++ context->seen_enough = 1;
++ return 1;
++ }
++
++ aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
++ aep->a_valuelen = valuelen;
++ memcpy(aep->a_name, name, namelen);
++ aep->a_name[ namelen ] = 0;
++ context->alist->al_offset[ context->count++ ] = context->firstu;
++ context->alist->al_count = context->count;
++ xfs_attr_trace_l_c("add", context);
++ return 0;
++}
++
++STATIC int
++xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp,
++ char *name, int namelen,
++ int valuelen, char *value)
++{
++ char *offset;
++ int arraytop;
++
++ ASSERT(context->count >= 0);
++
++ arraytop = context->count + namesp->attr_namelen + namelen + 1;
++ if (arraytop > context->firstu) {
++ context->count = -1; /* insufficient space */
++ return 1;
++ }
++ offset = (char *)context->alist + context->count;
++ strncpy(offset, namesp->attr_name, namesp->attr_namelen);
++ offset += namesp->attr_namelen;
++ strncpy(offset, name, namelen); /* real name */
++ offset += namelen;
++ *offset = '\0';
++ context->count += namesp->attr_namelen + namelen + 1;
++ return 0;
++}
++
++/*ARGSUSED*/
++STATIC int
++xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp,
++ char *name, int namelen,
++ int valuelen, char *value)
++{
++ context->count += namesp->attr_namelen + namelen + 1;
++ return 0;
++}
++
+ /*
+ * Generate a list of extended attribute names and optionally
+ * also value lengths. Positive return value follows the XFS
+@@ -615,13 +718,13 @@ xfs_attr_list(bhv_desc_t *bdp, char *buf
+ return(XFS_ERROR(EINVAL));
+ if ((cursor->initted == 0) &&
+ (cursor->hashval || cursor->blkno || cursor->offset))
+- return(XFS_ERROR(EINVAL));
++ return XFS_ERROR(EINVAL);
+
+ /*
+ * Check for a properly aligned buffer.
+ */
+ if (((long)buffer) & (sizeof(int)-1))
+- return(XFS_ERROR(EFAULT));
++ return XFS_ERROR(EFAULT);
+ if (flags & ATTR_KERNOVAL)
+ bufsize = 0;
+
+@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buf
+ context.dupcnt = 0;
+ context.resynch = 1;
+ context.flags = flags;
+- if (!(flags & ATTR_KERNAMELS)) {
++ context.seen_enough = 0;
++ context.alist = (attrlist_t *)buffer;
++ context.put_value = 0;
++
++ if (flags & ATTR_KERNAMELS) {
++ context.bufsize = bufsize;
++ context.firstu = context.bufsize;
++ if (flags & ATTR_KERNOVAL)
++ context.put_listent = xfs_attr_kern_list_sizes;
++ else
++ context.put_listent = xfs_attr_kern_list;
++ } else {
+ context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
+ context.firstu = context.bufsize;
+- context.alist = (attrlist_t *)buffer;
+ context.alist->al_count = 0;
+ context.alist->al_more = 0;
+ context.alist->al_offset[0] = context.bufsize;
+- }
+- else {
+- context.bufsize = bufsize;
+- context.firstu = context.bufsize;
+- context.alist = (attrlist_t *)buffer;
++ context.put_listent = xfs_attr_put_listent;
+ }
+
+ if (XFS_FORCED_SHUTDOWN(dp->i_mount))
+- return (EIO);
++ return EIO;
+
+ xfs_ilock(dp, XFS_ILOCK_SHARED);
+- /*
+- * Decide on what work routines to call based on the inode size.
+- */
+ xfs_attr_trace_l_c("syscall start", &context);
+- if (XFS_IFORK_Q(dp) == 0 ||
+- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+- dp->i_d.di_anextents == 0)) {
+- error = 0;
+- } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+- error = xfs_attr_shortform_list(&context);
+- } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+- error = xfs_attr_leaf_list(&context);
+- } else {
+- error = xfs_attr_node_list(&context);
+- }
++
++ error = xfs_attr_list_int(&context);
++
+ xfs_iunlock(dp, XFS_ILOCK_SHARED);
+ xfs_attr_trace_l_c("syscall end", &context);
+
+- if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
+- ASSERT(error >= 0);
+- }
+- else { /* must return negated buffer size or the error */
++ if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {
++ /* must return negated buffer size or the error */
+ if (context.count < 0)
+ error = XFS_ERROR(ERANGE);
+ else
+ error = -context.count;
+- }
++ } else
++ ASSERT(error >= 0);
+
+- return(error);
++ return error;
+ }
+
+ int /* error */
+@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context
+ context->cursor->blkno = 0;
+ error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
+ if (error)
+- return(error);
++ return XFS_ERROR(error);
+ ASSERT(bp != NULL);
+ leaf = bp->data;
+ if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
+ XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
+ context->dp->i_mount, leaf);
+ xfs_da_brelse(NULL, bp);
+- return(XFS_ERROR(EFSCORRUPTED));
++ return XFS_ERROR(EFSCORRUPTED);
+ }
+
+- (void)xfs_attr_leaf_list_int(bp, context);
++ error = xfs_attr_leaf_list_int(bp, context);
+ xfs_da_brelse(NULL, bp);
+- return(0);
++ return XFS_ERROR(error);
+ }
+
+
+@@ -1858,8 +1955,12 @@ xfs_attr_node_list(xfs_attr_list_context
+ return(XFS_ERROR(EFSCORRUPTED));
+ }
+ error = xfs_attr_leaf_list_int(bp, context);
+- if (error || !leaf->hdr.info.forw)
+- break; /* not really an error, buffer full or EOF */
++ if (error) {
++ xfs_da_brelse(NULL, bp);
++ return error;
++ }
++ if (context->seen_enough || leaf->hdr.info.forw == 0)
++ break;
+ cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
+ xfs_da_brelse(NULL, bp);
+ error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
+@@ -1886,7 +1987,7 @@ xfs_attr_node_list(xfs_attr_list_context
+ * Read the value associated with an attribute from the out-of-line buffer
+ * that we stored it in.
+ */
+-STATIC int
++int
+ xfs_attr_rmtval_get(xfs_da_args_t *args)
+ {
+ xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
+diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
+index 981633f..783977d 100644
+--- a/fs/xfs/xfs_attr.h
++++ b/fs/xfs/xfs_attr.h
+@@ -37,6 +37,7 @@
+
+ struct cred;
+ struct bhv_vnode;
++struct xfs_attr_list_context;
+
+ typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int);
+ typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int);
+@@ -160,13 +161,16 @@ struct xfs_da_args;
+ */
+ int xfs_attr_get(bhv_desc_t *, const char *, char *, int *, int, struct cred *);
+ int xfs_attr_set(bhv_desc_t *, const char *, char *, int, int, struct cred *);
++int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int);
+ int xfs_attr_remove(bhv_desc_t *, const char *, int, struct cred *);
+-int xfs_attr_list(bhv_desc_t *, char *, int, int,
+- struct attrlist_cursor_kern *, struct cred *);
++int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int);
++int xfs_attr_list(bhv_desc_t *, char *, int, int, struct attrlist_cursor_kern *, struct cred *);
++int xfs_attr_list_int(struct xfs_attr_list_context *);
+ int xfs_attr_inactive(struct xfs_inode *dp);
+
+ int xfs_attr_shortform_getvalue(struct xfs_da_args *);
+ int xfs_attr_fetch(struct xfs_inode *, const char *, int,
+ char *, int *, int, struct cred *);
++int xfs_attr_rmtval_get(struct xfs_da_args *args);
+
+ #endif /* __XFS_ATTR_H__ */
+diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
+index 9455051..9719bbe 100644
+--- a/fs/xfs/xfs_attr_leaf.c
++++ b/fs/xfs/xfs_attr_leaf.c
+@@ -89,9 +89,46 @@ STATIC void xfs_attr_leaf_moveents(xfs_a
+ int dst_start, int move_count,
+ xfs_mount_t *mp);
+ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
+-STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
+- attrnames_t *, char *name, int namelen,
+- int valuelen);
++
++/*========================================================================
++ * Namespace helper routines
++ *========================================================================*/
++
++STATIC inline attrnames_t *
++xfs_attr_flags_namesp(int flags)
++{
++ return ((flags & XFS_ATTR_SECURE) ? &attr_secure:
++ ((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user));
++}
++
++/*
++ * If namespace bits don't match return 0.
++ * If all match then return 1.
++ */
++STATIC inline int
++xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
++{
++ return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);
++}
++
++/*
++ * If namespace bits don't match and we don't have an override for it
++ * then return 0.
++ * If all match or are overridable then return 1.
++ */
++STATIC inline int
++xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags)
++{
++ if (((arg_flags & ATTR_SECURE) == 0) !=
++ ((ondisk_flags & XFS_ATTR_SECURE) == 0) &&
++ !(arg_flags & ATTR_KERNORMALS))
++ return 0;
++ if (((arg_flags & ATTR_ROOT) == 0) !=
++ ((ondisk_flags & XFS_ATTR_ROOT) == 0) &&
++ !(arg_flags & ATTR_KERNROOTLS))
++ return 0;
++ return 1;
++}
+
+
+ /*========================================================================
+@@ -228,11 +265,7 @@ xfs_attr_shortform_add(xfs_da_args_t *ar
+ continue;
+ if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
+ continue;
+- if (((args->flags & ATTR_SECURE) != 0) !=
+- ((sfe->flags & XFS_ATTR_SECURE) != 0))
+- continue;
+- if (((args->flags & ATTR_ROOT) != 0) !=
+- ((sfe->flags & XFS_ATTR_ROOT) != 0))
++ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+ continue;
+ ASSERT(0);
+ #endif
+@@ -246,8 +279,7 @@ xfs_attr_shortform_add(xfs_da_args_t *ar
+
+ sfe->namelen = args->namelen;
+ sfe->valuelen = args->valuelen;
+- sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
+- ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
++ sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
+ memcpy(sfe->nameval, args->name, args->namelen);
+ memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
+ sf->hdr.count++;
+@@ -282,11 +314,7 @@ xfs_attr_shortform_remove(xfs_da_args_t
+ continue;
+ if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
+ continue;
+- if (((args->flags & ATTR_SECURE) != 0) !=
+- ((sfe->flags & XFS_ATTR_SECURE) != 0))
+- continue;
+- if (((args->flags & ATTR_ROOT) != 0) !=
+- ((sfe->flags & XFS_ATTR_ROOT) != 0))
++ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+ continue;
+ break;
+ }
+@@ -363,11 +391,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t
+ continue;
+ if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
+ continue;
+- if (((args->flags & ATTR_SECURE) != 0) !=
+- ((sfe->flags & XFS_ATTR_SECURE) != 0))
+- continue;
+- if (((args->flags & ATTR_ROOT) != 0) !=
+- ((sfe->flags & XFS_ATTR_ROOT) != 0))
++ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+ continue;
+ return(XFS_ERROR(EEXIST));
+ }
+@@ -394,11 +418,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_
+ continue;
+ if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
+ continue;
+- if (((args->flags & ATTR_SECURE) != 0) !=
+- ((sfe->flags & XFS_ATTR_SECURE) != 0))
+- continue;
+- if (((args->flags & ATTR_ROOT) != 0) !=
+- ((sfe->flags & XFS_ATTR_ROOT) != 0))
++ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+ continue;
+ if (args->flags & ATTR_KERNOVAL) {
+ args->valuelen = sfe->valuelen;
+@@ -485,8 +505,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t
+ nargs.valuelen = sfe->valuelen;
+ nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
+ sfe->namelen);
+- nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
+- ((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
++ nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
+ error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
+ ASSERT(error == ENOATTR);
+ error = xfs_attr_leaf_add(bp, &nargs);
+@@ -520,6 +539,10 @@ xfs_attr_shortform_compare(const void *a
+ }
+ }
+
++
++#define XFS_ISRESET_CURSOR(cursor) \
++ (!((cursor)->initted) && !((cursor)->hashval) && \
++ !((cursor)->blkno) && !((cursor)->offset))
+ /*
+ * Copy out entries of shortform attribute lists for attr_list().
+ * Shortform attribute lists are not stored in hashval sorted order.
+@@ -537,6 +560,7 @@ xfs_attr_shortform_list(xfs_attr_list_co
+ xfs_attr_sf_entry_t *sfe;
+ xfs_inode_t *dp;
+ int sbsize, nsbuf, count, i;
++ int error;
+
+ ASSERT(context != NULL);
+ dp = context->dp;
+@@ -552,46 +576,51 @@ xfs_attr_shortform_list(xfs_attr_list_co
+ xfs_attr_trace_l_c("sf start", context);
+
+ /*
+- * If the buffer is large enough, do not bother with sorting.
++ * If the buffer is large enough and the cursor is at the start,
++ * do not bother with sorting since we will return everything in
++ * one buffer and another call using the cursor won't need to be
++ * made.
+ * Note the generous fudge factor of 16 overhead bytes per entry.
++ * If bufsize is zero then put_listent must be a search function
++ * and can just scan through what we have.
+ */
+- if ((dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize) {
++ if (context->bufsize == 0 ||
++ (XFS_ISRESET_CURSOR(cursor) &&
++ (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
+ for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
+ attrnames_t *namesp;
+
+- if (((context->flags & ATTR_SECURE) != 0) !=
+- ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
+- !(context->flags & ATTR_KERNORMALS)) {
+- sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+- continue;
+- }
+- if (((context->flags & ATTR_ROOT) != 0) !=
+- ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
+- !(context->flags & ATTR_KERNROOTLS)) {
++ if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
+ sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+ continue;
+ }
+- namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure:
+- ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
+- &attr_user);
+- if (context->flags & ATTR_KERNOVAL) {
+- ASSERT(context->flags & ATTR_KERNAMELS);
+- context->count += namesp->attr_namelen +
+- sfe->namelen + 1;
+- }
+- else {
+- if (xfs_attr_put_listent(context, namesp,
+- (char *)sfe->nameval,
+- (int)sfe->namelen,
+- (int)sfe->valuelen))
+- break;
+- }
++ namesp = xfs_attr_flags_namesp(sfe->flags);
++ error = context->put_listent(context,
++ namesp,
++ (char *)sfe->nameval,
++ (int)sfe->namelen,
++ (int)sfe->valuelen,
++ (char*)&sfe->nameval[sfe->namelen]);
++
++ /*
++ * Either search callback finished early or
++ * didn't fit it all in the buffer after all.
++ */
++ if (context->seen_enough)
++ break;
++
++ if (error)
++ return error;
+ sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+ }
+ xfs_attr_trace_l_c("sf big-gulp", context);
+ return(0);
+ }
+
++ /* do no more for a search callback */
++ if (context->bufsize == 0)
++ return 0;
++
+ /*
+ * It didn't all fit, so we have to sort everything on hashval.
+ */
+@@ -614,15 +643,7 @@ xfs_attr_shortform_list(xfs_attr_list_co
+ kmem_free(sbuf, sbsize);
+ return XFS_ERROR(EFSCORRUPTED);
+ }
+- if (((context->flags & ATTR_SECURE) != 0) !=
+- ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
+- !(context->flags & ATTR_KERNORMALS)) {
+- sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+- continue;
+- }
+- if (((context->flags & ATTR_ROOT) != 0) !=
+- ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
+- !(context->flags & ATTR_KERNROOTLS)) {
++ if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
+ sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+ continue;
+ }
+@@ -671,24 +692,22 @@ xfs_attr_shortform_list(xfs_attr_list_co
+ for ( ; i < nsbuf; i++, sbp++) {
+ attrnames_t *namesp;
+
+- namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure :
+- ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
+- &attr_user);
++ namesp = xfs_attr_flags_namesp(sbp->flags);
+
+ if (cursor->hashval != sbp->hash) {
+ cursor->hashval = sbp->hash;
+ cursor->offset = 0;
+ }
+- if (context->flags & ATTR_KERNOVAL) {
+- ASSERT(context->flags & ATTR_KERNAMELS);
+- context->count += namesp->attr_namelen +
+- sbp->namelen + 1;
+- } else {
+- if (xfs_attr_put_listent(context, namesp,
+- sbp->name, sbp->namelen,
+- sbp->valuelen))
+- break;
+- }
++ error = context->put_listent(context,
++ namesp,
++ sbp->name,
++ sbp->namelen,
++ sbp->valuelen,
++ &sbp->name[sbp->namelen]);
++ if (error)
++ return error;
++ if (context->seen_enough)
++ break;
+ cursor->offset++;
+ }
+
+@@ -810,8 +829,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *
+ nargs.value = (char *)&name_loc->nameval[nargs.namelen];
+ nargs.valuelen = be16_to_cpu(name_loc->valuelen);
+ nargs.hashval = be32_to_cpu(entry->hashval);
+- nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
+- ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
++ nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
+ xfs_attr_shortform_add(&nargs, forkoff);
+ }
+ error = 0;
+@@ -1098,8 +1116,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp,
+ be16_to_cpu(map->size));
+ entry->hashval = cpu_to_be32(args->hashval);
+ entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
+- entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
+- ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
++ entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
+ if (args->rename) {
+ entry->flags |= XFS_ATTR_INCOMPLETE;
+ if ((args->blkno2 == args->blkno) &&
+@@ -1926,7 +1943,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp
+ else
+ break;
+ }
+- ASSERT((probe >= 0) &&
++ ASSERT((probe >= 0) &&
+ (!leaf->hdr.count
+ || (probe < be16_to_cpu(leaf->hdr.count))));
+ ASSERT((span <= 4) || (be32_to_cpu(entry->hashval) == hashval));
+@@ -1971,14 +1988,9 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp
+ name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
+ if (name_loc->namelen != args->namelen)
+ continue;
+- if (memcmp(args->name, (char *)name_loc->nameval,
+- args->namelen) != 0)
++ if (memcmp(args->name, (char *)name_loc->nameval, args->namelen) != 0)
+ continue;
+- if (((args->flags & ATTR_SECURE) != 0) !=
+- ((entry->flags & XFS_ATTR_SECURE) != 0))
+- continue;
+- if (((args->flags & ATTR_ROOT) != 0) !=
+- ((entry->flags & XFS_ATTR_ROOT) != 0))
++ if (!xfs_attr_namesp_match(args->flags, entry->flags))
+ continue;
+ args->index = probe;
+ return(XFS_ERROR(EEXIST));
+@@ -1989,11 +2001,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp
+ if (memcmp(args->name, (char *)name_rmt->name,
+ args->namelen) != 0)
+ continue;
+- if (((args->flags & ATTR_SECURE) != 0) !=
+- ((entry->flags & XFS_ATTR_SECURE) != 0))
+- continue;
+- if (((args->flags & ATTR_ROOT) != 0) !=
+- ((entry->flags & XFS_ATTR_ROOT) != 0))
++ if (!xfs_attr_namesp_match(args->flags, entry->flags))
+ continue;
+ args->index = probe;
+ args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
+@@ -2312,8 +2320,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp,
+ attrlist_cursor_kern_t *cursor;
+ xfs_attr_leafblock_t *leaf;
+ xfs_attr_leaf_entry_t *entry;
+- xfs_attr_leaf_name_local_t *name_loc;
+- xfs_attr_leaf_name_remote_t *name_rmt;
+ int retval, i;
+
+ ASSERT(bp != NULL);
+@@ -2355,9 +2361,8 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp,
+ * We have found our place, start copying out the new attributes.
+ */
+ retval = 0;
+- for ( ; (i < be16_to_cpu(leaf->hdr.count))
+- && (retval == 0); entry++, i++) {
+- attrnames_t *namesp;
++ for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
++ attrnames_t *namesp;
+
+ if (be32_to_cpu(entry->hashval) != cursor->hashval) {
+ cursor->hashval = be32_to_cpu(entry->hashval);
+@@ -2366,115 +2371,69 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp,
+
+ if (entry->flags & XFS_ATTR_INCOMPLETE)
+ continue; /* skip incomplete entries */
+- if (((context->flags & ATTR_SECURE) != 0) !=
+- ((entry->flags & XFS_ATTR_SECURE) != 0) &&
+- !(context->flags & ATTR_KERNORMALS))
+- continue; /* skip non-matching entries */
+- if (((context->flags & ATTR_ROOT) != 0) !=
+- ((entry->flags & XFS_ATTR_ROOT) != 0) &&
+- !(context->flags & ATTR_KERNROOTLS))
+- continue; /* skip non-matching entries */
+-
+- namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure :
+- ((entry->flags & XFS_ATTR_ROOT) ? &attr_trusted :
+- &attr_user);
++ if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags))
++ continue;
++
++ namesp = xfs_attr_flags_namesp(entry->flags);
+
+ if (entry->flags & XFS_ATTR_LOCAL) {
+- name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
+- if (context->flags & ATTR_KERNOVAL) {
+- ASSERT(context->flags & ATTR_KERNAMELS);
+- context->count += namesp->attr_namelen +
+- (int)name_loc->namelen + 1;
+- } else {
+- retval = xfs_attr_put_listent(context, namesp,
+- (char *)name_loc->nameval,
+- (int)name_loc->namelen,
+- be16_to_cpu(name_loc->valuelen));
+- }
++ xfs_attr_leaf_name_local_t *name_loc =
++ XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
++
++ retval = context->put_listent(context,
++ namesp,
++ (char *)name_loc->nameval,
++ (int)name_loc->namelen,
++ be16_to_cpu(name_loc->valuelen),
++ (char *)&name_loc->nameval[name_loc->namelen]);
++ if (retval)
++ return retval;
+ } else {
+- name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
+- if (context->flags & ATTR_KERNOVAL) {
+- ASSERT(context->flags & ATTR_KERNAMELS);
+- context->count += namesp->attr_namelen +
+- (int)name_rmt->namelen + 1;
+- } else {
+- retval = xfs_attr_put_listent(context, namesp,
+- (char *)name_rmt->name,
+- (int)name_rmt->namelen,
+- be32_to_cpu(name_rmt->valuelen));
++ xfs_attr_leaf_name_remote_t *name_rmt =
++ XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
++
++ int valuelen = be32_to_cpu(name_rmt->valuelen);
++
++ if (context->put_value) {
++ xfs_da_args_t args;
++
++ memset((char *)&args, 0, sizeof(args));
++ args.dp = context->dp;
++ args.whichfork = XFS_ATTR_FORK;
++ args.valuelen = valuelen;
++ args.value = kmem_alloc(valuelen, KM_SLEEP);
++ args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
++ args.rmtblkcnt = XFS_B_TO_FSB(args.dp->i_mount, valuelen);
++ retval = xfs_attr_rmtval_get(&args);
++ if (retval)
++ return retval;
++ retval = context->put_listent(context,
++ namesp,
++ (char *)name_rmt->name,
++ (int)name_rmt->namelen,
++ valuelen,
++ (char*)args.value);
++ kmem_free(args.value, valuelen);
+ }
++ else {
++ retval = context->put_listent(context,
++ namesp,
++ (char *)name_rmt->name,
++ (int)name_rmt->namelen,
++ valuelen,
++ NULL);
++ }
++ if (retval)
++ return retval;
+ }
+- if (retval == 0) {
+- cursor->offset++;
+- }
++ if (context->seen_enough)
++ break;
++ cursor->offset++;
+ }
+ xfs_attr_trace_l_cl("blk end", context, leaf);
+ return(retval);
+ }
+
+-#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
+- (((struct attrlist_ent *) 0)->a_name - (char *) 0)
+-#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
+- ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
+- & ~(sizeof(u_int32_t)-1))
+-
+-/*
+- * Format an attribute and copy it out to the user's buffer.
+- * Take care to check values and protect against them changing later,
+- * we may be reading them directly out of a user buffer.
+- */
+-/*ARGSUSED*/
+-STATIC int
+-xfs_attr_put_listent(xfs_attr_list_context_t *context,
+- attrnames_t *namesp, char *name, int namelen, int valuelen)
+-{
+- attrlist_ent_t *aep;
+- int arraytop;
+-
+- ASSERT(!(context->flags & ATTR_KERNOVAL));
+- if (context->flags & ATTR_KERNAMELS) {
+- char *offset;
+-
+- ASSERT(context->count >= 0);
+-
+- arraytop = context->count + namesp->attr_namelen + namelen + 1;
+- if (arraytop > context->firstu) {
+- context->count = -1; /* insufficient space */
+- return(1);
+- }
+- offset = (char *)context->alist + context->count;
+- strncpy(offset, namesp->attr_name, namesp->attr_namelen);
+- offset += namesp->attr_namelen;
+- strncpy(offset, name, namelen); /* real name */
+- offset += namelen;
+- *offset = '\0';
+- context->count += namesp->attr_namelen + namelen + 1;
+- return(0);
+- }
+-
+- ASSERT(context->count >= 0);
+- ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
+- ASSERT(context->firstu >= sizeof(*context->alist));
+- ASSERT(context->firstu <= context->bufsize);
+-
+- arraytop = sizeof(*context->alist) +
+- context->count * sizeof(context->alist->al_offset[0]);
+- context->firstu -= ATTR_ENTSIZE(namelen);
+- if (context->firstu < arraytop) {
+- xfs_attr_trace_l_c("buffer full", context);
+- context->alist->al_more = 1;
+- return(1);
+- }
+-
+- aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
+- aep->a_valuelen = valuelen;
+- memcpy(aep->a_name, name, namelen);
+- aep->a_name[ namelen ] = 0;
+- context->alist->al_offset[ context->count++ ] = context->firstu;
+- context->alist->al_count = context->count;
+- xfs_attr_trace_l_c("add", context);
+- return(0);
+-}
+
+ /*========================================================================
+ * Manage the INCOMPLETE flag in a leaf entry
+diff --git a/fs/xfs/xfs_attr_leaf.h b/fs/xfs/xfs_attr_leaf.h
+index 51c3ee1..040f732 100644
+--- a/fs/xfs/xfs_attr_leaf.h
++++ b/fs/xfs/xfs_attr_leaf.h
+@@ -130,6 +130,19 @@ typedef struct xfs_attr_leafblock {
+ #define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT)
+
+ /*
++ * Conversion macros for converting namespace bits from argument flags
++ * to ondisk flags.
++ */
++#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE)
++#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
++#define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK)
++#define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK)
++#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
++ ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
++#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
++ ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
++
++/*
+ * Alignment for namelist and valuelist entries (since they are mixed
+ * there can be only one alignment value)
+ */
+@@ -196,16 +209,26 @@ static inline int xfs_attr_leaf_entsize_
+ * Structure used to pass context around among the routines.
+ *========================================================================*/
+
++
++struct xfs_attr_list_context;
++
++typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, struct attrnames *,
++ char *, int, int, char *);
++
+ typedef struct xfs_attr_list_context {
+- struct xfs_inode *dp; /* inode */
+- struct attrlist_cursor_kern *cursor;/* position in list */
+- struct attrlist *alist; /* output buffer */
+- int count; /* num used entries */
+- int dupcnt; /* count dup hashvals seen */
+- int bufsize;/* total buffer size */
+- int firstu; /* first used byte in buffer */
+- int flags; /* from VOP call */
+- int resynch;/* T/F: resynch with cursor */
++ struct xfs_inode *dp; /* inode */
++ struct attrlist_cursor_kern *cursor; /* position in list */
++ struct attrlist *alist; /* output buffer */
++ int seen_enough; /* T/F: seen enough of list? */
++ int count; /* num used entries */
++ int dupcnt; /* count dup hashvals seen */
++ int bufsize; /* total buffer size */
++ int firstu; /* first used byte in buffer */
++ int flags; /* from VOP call */
++ int resynch; /* T/F: resynch with cursor */
++ int put_value; /* T/F: need value for listent */
++ put_listent_func_t put_listent; /* list output fmt function */
++ int index; /* index into output buffer */
+ } xfs_attr_list_context_t;
+
+ /*
+diff --git a/fs/xfs/xfs_behavior.c b/fs/xfs/xfs_behavior.c
+index f4fe371..0dc1721 100644
+--- a/fs/xfs/xfs_behavior.c
++++ b/fs/xfs/xfs_behavior.c
+@@ -110,26 +110,6 @@ bhv_remove_not_first(bhv_head_t *bhp, bh
+ }
+
+ /*
+- * Look for a specific ops vector on the specified behavior chain.
+- * Return the associated behavior descriptor. Or NULL, if not found.
+- */
+-bhv_desc_t *
+-bhv_lookup(bhv_head_t *bhp, void *ops)
+-{
+- bhv_desc_t *curdesc;
+-
+- for (curdesc = bhp->bh_first;
+- curdesc != NULL;
+- curdesc = curdesc->bd_next) {
+-
+- if (curdesc->bd_ops == ops)
+- return curdesc;
+- }
+-
+- return NULL;
+-}
+-
+-/*
+ * Looks for the first behavior within a specified range of positions.
+ * Return the associated behavior descriptor. Or NULL, if none found.
+ */
+diff --git a/fs/xfs/xfs_behavior.h b/fs/xfs/xfs_behavior.h
+index 6e6e56f..e7ca1fe 100644
+--- a/fs/xfs/xfs_behavior.h
++++ b/fs/xfs/xfs_behavior.h
+@@ -176,12 +176,10 @@ extern void bhv_insert_initial(bhv_head_
+ * Behavior module prototypes.
+ */
+ extern void bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp);
+-extern bhv_desc_t * bhv_lookup(bhv_head_t *bhp, void *ops);
+ extern bhv_desc_t * bhv_lookup_range(bhv_head_t *bhp, int low, int high);
+ extern bhv_desc_t * bhv_base(bhv_head_t *bhp);
+
+ /* No bhv locking on Linux */
+-#define bhv_lookup_unlocked bhv_lookup
+ #define bhv_base_unlocked bhv_base
+
+ #endif /* __XFS_BEHAVIOR_H__ */
+diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
+index bf46fae..5b050c0 100644
+--- a/fs/xfs/xfs_bmap.c
++++ b/fs/xfs/xfs_bmap.c
+@@ -2999,7 +2999,7 @@ xfs_bmap_btree_to_extents(
+ int error; /* error return value */
+ xfs_ifork_t *ifp; /* inode fork data */
+ xfs_mount_t *mp; /* mount point structure */
+- xfs_bmbt_ptr_t *pp; /* ptr to block address */
++ __be64 *pp; /* ptr to block address */
+ xfs_bmbt_block_t *rblock;/* root btree block */
+
+ ifp = XFS_IFORK_PTR(ip, whichfork);
+@@ -3011,12 +3011,12 @@ xfs_bmap_btree_to_extents(
+ ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1);
+ mp = ip->i_mount;
+ pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes);
++ cbno = be64_to_cpu(*pp);
+ *logflagsp = 0;
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), 1)))
++ if ((error = xfs_btree_check_lptr(cur, cbno, 1)))
+ return error;
+ #endif
+- cbno = INT_GET(*pp, ARCH_CONVERT);
+ if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp,
+ XFS_BMAP_BTREE_REF)))
+ return error;
+@@ -3512,9 +3512,9 @@ xfs_bmap_extents_to_btree(
+ */
+ kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
+ arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
+- INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(arp));
++ kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp));
+ pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
+- INT_SET(*pp, ARCH_CONVERT, args.fsbno);
++ *pp = cpu_to_be64(args.fsbno);
+ /*
+ * Do all this logging at the end so that
+ * the root is at the right level.
+@@ -3705,7 +3705,7 @@ STATIC xfs_bmbt_rec_t *
+ xfs_bmap_search_extents(
+ xfs_inode_t *ip, /* incore inode pointer */
+ xfs_fileoff_t bno, /* block number searched for */
+- int whichfork, /* data or attr fork */
++ int fork, /* data or attr fork */
+ int *eofp, /* out: end of file found */
+ xfs_extnum_t *lastxp, /* out: last extent index */
+ xfs_bmbt_irec_t *gotp, /* out: extent entry found */
+@@ -3713,25 +3713,28 @@ xfs_bmap_search_extents(
+ {
+ xfs_ifork_t *ifp; /* inode fork pointer */
+ xfs_bmbt_rec_t *ep; /* extent record pointer */
+- int rt; /* realtime flag */
+
+ XFS_STATS_INC(xs_look_exlist);
+- ifp = XFS_IFORK_PTR(ip, whichfork);
++ ifp = XFS_IFORK_PTR(ip, fork);
+
+ ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
+
+- rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
+- if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) {
+- cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld "
+- "start_block : %llx start_off : %llx blkcnt : %llx "
+- "extent-state : %x \n",
+- (ip->i_mount)->m_fsname, (long long)ip->i_ino,
++ if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) &&
++ !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) {
++ xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
++ "Access to block zero in inode %llu "
++ "start_block: %llx start_off: %llx "
++ "blkcnt: %llx extent-state: %x lastx: %x\n",
++ (unsigned long long)ip->i_ino,
+ (unsigned long long)gotp->br_startblock,
+ (unsigned long long)gotp->br_startoff,
+ (unsigned long long)gotp->br_blockcount,
+- gotp->br_state);
+- }
+- return ep;
++ gotp->br_state, *lastxp);
++ *lastxp = NULLEXTNUM;
++ *eofp = 1;
++ return NULL;
++ }
++ return ep;
+ }
+
+
+@@ -4494,7 +4497,7 @@ xfs_bmap_read_extents(
+ xfs_ifork_t *ifp; /* fork structure */
+ int level; /* btree level, for checking */
+ xfs_mount_t *mp; /* file system mount structure */
+- xfs_bmbt_ptr_t *pp; /* pointer to block address */
++ __be64 *pp; /* pointer to block address */
+ /* REFERENCED */
+ xfs_extnum_t room; /* number of entries there's room for */
+
+@@ -4510,10 +4513,10 @@ xfs_bmap_read_extents(
+ level = be16_to_cpu(block->bb_level);
+ ASSERT(level > 0);
+ pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
+- ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
+- ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
+- ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
+- bno = INT_GET(*pp, ARCH_CONVERT);
++ bno = be64_to_cpu(*pp);
++ ASSERT(bno != NULLDFSBNO);
++ ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
++ ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
+ /*
+ * Go down the tree until leaf level is reached, following the first
+ * pointer (leftmost) at each level.
+@@ -4530,10 +4533,8 @@ xfs_bmap_read_extents(
+ break;
+ pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
+ 1, mp->m_bmap_dmxr[1]);
+- XFS_WANT_CORRUPTED_GOTO(
+- XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)),
+- error0);
+- bno = INT_GET(*pp, ARCH_CONVERT);
++ bno = be64_to_cpu(*pp);
++ XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0);
+ xfs_trans_brelse(tp, bp);
+ }
+ /*
+@@ -6141,7 +6142,7 @@ xfs_check_block(
+ short sz)
+ {
+ int i, j, dmxr;
+- xfs_bmbt_ptr_t *pp, *thispa; /* pointer to block address */
++ __be64 *pp, *thispa; /* pointer to block address */
+ xfs_bmbt_key_t *prevp, *keyp;
+
+ ASSERT(be16_to_cpu(block->bb_level) > 0);
+@@ -6179,11 +6180,10 @@ xfs_check_block(
+ thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
+ xfs_bmbt, block, j, dmxr);
+ }
+- if (INT_GET(*thispa, ARCH_CONVERT) ==
+- INT_GET(*pp, ARCH_CONVERT)) {
++ if (*thispa == *pp) {
+ cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
+ __FUNCTION__, j, i,
+- INT_GET(*thispa, ARCH_CONVERT));
++ (unsigned long long)be64_to_cpu(*thispa));
+ panic("%s: ptrs are equal in node\n",
+ __FUNCTION__);
+ }
+@@ -6210,7 +6210,7 @@ xfs_bmap_check_leaf_extents(
+ xfs_ifork_t *ifp; /* fork structure */
+ int level; /* btree level, for checking */
+ xfs_mount_t *mp; /* file system mount structure */
+- xfs_bmbt_ptr_t *pp; /* pointer to block address */
++ __be64 *pp; /* pointer to block address */
+ xfs_bmbt_rec_t *ep; /* pointer to current extent */
+ xfs_bmbt_rec_t *lastp; /* pointer to previous extent */
+ xfs_bmbt_rec_t *nextp; /* pointer to next extent */
+@@ -6231,10 +6231,12 @@ xfs_bmap_check_leaf_extents(
+ ASSERT(level > 0);
+ xfs_check_block(block, mp, 1, ifp->if_broot_bytes);
+ pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
+- ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
+- ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
+- ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
+- bno = INT_GET(*pp, ARCH_CONVERT);
++ bno = be64_to_cpu(*pp);
++
++ ASSERT(bno != NULLDFSBNO);
++ ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
++ ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
++
+ /*
+ * Go down the tree until leaf level is reached, following the first
+ * pointer (leftmost) at each level.
+@@ -6265,8 +6267,8 @@ xfs_bmap_check_leaf_extents(
+ xfs_check_block(block, mp, 0, 0);
+ pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
+ 1, mp->m_bmap_dmxr[1]);
+- XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0);
+- bno = INT_GET(*pp, ARCH_CONVERT);
++ bno = be64_to_cpu(*pp);
++ XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0);
+ if (bp_release) {
+ bp_release = 0;
+ xfs_trans_brelse(NULL, bp);
+@@ -6372,7 +6374,7 @@ xfs_bmap_count_blocks(
+ xfs_ifork_t *ifp; /* fork structure */
+ int level; /* btree level, for checking */
+ xfs_mount_t *mp; /* file system mount structure */
+- xfs_bmbt_ptr_t *pp; /* pointer to block address */
++ __be64 *pp; /* pointer to block address */
+
+ bno = NULLFSBLOCK;
+ mp = ip->i_mount;
+@@ -6395,10 +6397,10 @@ xfs_bmap_count_blocks(
+ level = be16_to_cpu(block->bb_level);
+ ASSERT(level > 0);
+ pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
+- ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
+- ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
+- ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
+- bno = INT_GET(*pp, ARCH_CONVERT);
++ bno = be64_to_cpu(*pp);
++ ASSERT(bno != NULLDFSBNO);
++ ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
++ ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
+
+ if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
+ XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
+@@ -6425,7 +6427,7 @@ xfs_bmap_count_tree(
+ int error;
+ xfs_buf_t *bp, *nbp;
+ int level = levelin;
+- xfs_bmbt_ptr_t *pp;
++ __be64 *pp;
+ xfs_fsblock_t bno = blockno;
+ xfs_fsblock_t nextbno;
+ xfs_bmbt_block_t *block, *nextblock;
+@@ -6452,7 +6454,7 @@ xfs_bmap_count_tree(
+ /* Dive to the next level */
+ pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
+ xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
+- bno = INT_GET(*pp, ARCH_CONVERT);
++ bno = be64_to_cpu(*pp);
+ if (unlikely((error =
+ xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
+ xfs_trans_brelse(tp, bp);
+diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
+index 18fb738..a7b835b 100644
+--- a/fs/xfs/xfs_bmap_btree.c
++++ b/fs/xfs/xfs_bmap_btree.c
+@@ -58,7 +58,7 @@ STATIC void xfs_bmbt_log_ptrs(xfs_btree_
+ STATIC int xfs_bmbt_lshift(xfs_btree_cur_t *, int, int *);
+ STATIC int xfs_bmbt_rshift(xfs_btree_cur_t *, int, int *);
+ STATIC int xfs_bmbt_split(xfs_btree_cur_t *, int, xfs_fsblock_t *,
+- xfs_bmbt_key_t *, xfs_btree_cur_t **, int *);
++ __uint64_t *, xfs_btree_cur_t **, int *);
+ STATIC int xfs_bmbt_updkey(xfs_btree_cur_t *, xfs_bmbt_key_t *, int);
+
+
+@@ -192,16 +192,11 @@ xfs_bmbt_trace_argifk(
+ xfs_btree_cur_t *cur,
+ int i,
+ xfs_fsblock_t f,
+- xfs_bmbt_key_t *k,
++ xfs_dfiloff_t o,
+ int line)
+ {
+- xfs_dfsbno_t d;
+- xfs_dfiloff_t o;
+-
+- d = (xfs_dfsbno_t)f;
+- o = INT_GET(k->br_startoff, ARCH_CONVERT);
+ xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line,
+- i, d >> 32, (int)d, o >> 32,
++ i, (xfs_dfsbno_t)f >> 32, (int)f, o >> 32,
+ (int)o, 0, 0, 0,
+ 0, 0, 0);
+ }
+@@ -248,7 +243,7 @@ xfs_bmbt_trace_argik(
+ {
+ xfs_dfiloff_t o;
+
+- o = INT_GET(k->br_startoff, ARCH_CONVERT);
++ o = be64_to_cpu(k->br_startoff);
+ xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line,
+ i, o >> 32, (int)o, 0,
+ 0, 0, 0, 0,
+@@ -286,8 +281,8 @@ xfs_bmbt_trace_cursor(
+ xfs_bmbt_trace_argfffi(fname, c, o, b, i, j, __LINE__)
+ #define XFS_BMBT_TRACE_ARGI(c,i) \
+ xfs_bmbt_trace_argi(fname, c, i, __LINE__)
+-#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) \
+- xfs_bmbt_trace_argifk(fname, c, i, f, k, __LINE__)
++#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s) \
++ xfs_bmbt_trace_argifk(fname, c, i, f, s, __LINE__)
+ #define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \
+ xfs_bmbt_trace_argifr(fname, c, i, f, r, __LINE__)
+ #define XFS_BMBT_TRACE_ARGIK(c,i,k) \
+@@ -299,7 +294,7 @@ xfs_bmbt_trace_cursor(
+ #define XFS_BMBT_TRACE_ARGBII(c,b,i,j)
+ #define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j)
+ #define XFS_BMBT_TRACE_ARGI(c,i)
+-#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k)
++#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s)
+ #define XFS_BMBT_TRACE_ARGIFR(c,i,f,r)
+ #define XFS_BMBT_TRACE_ARGIK(c,i,k)
+ #define XFS_BMBT_TRACE_CURSOR(c,s)
+@@ -357,7 +352,7 @@ xfs_bmbt_delrec(
+ XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
+ XFS_BMBT_TRACE_ARGI(cur, level);
+ ptr = cur->bc_ptrs[level];
+- tcur = (xfs_btree_cur_t *)0;
++ tcur = NULL;
+ if (ptr == 0) {
+ XFS_BMBT_TRACE_CURSOR(cur, EXIT);
+ *stat = 0;
+@@ -382,7 +377,7 @@ xfs_bmbt_delrec(
+ pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
+ #ifdef DEBUG
+ for (i = ptr; i < numrecs; i++) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, pp[i], level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ goto error0;
+ }
+@@ -404,7 +399,8 @@ xfs_bmbt_delrec(
+ xfs_bmbt_log_recs(cur, bp, ptr, numrecs - 1);
+ }
+ if (ptr == 1) {
+- INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(rp));
++ key.br_startoff =
++ cpu_to_be64(xfs_bmbt_disk_get_startoff(rp));
+ kp = &key;
+ }
+ }
+@@ -621,7 +617,7 @@ xfs_bmbt_delrec(
+ rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
+ #ifdef DEBUG
+ for (i = 0; i < numrrecs; i++) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, rpp[i], level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ goto error0;
+ }
+@@ -748,7 +744,7 @@ xfs_bmbt_insrec(
+ int logflags; /* inode logging flags */
+ xfs_fsblock_t nbno; /* new block number */
+ struct xfs_btree_cur *ncur; /* new btree cursor */
+- xfs_bmbt_key_t nkey; /* new btree key value */
++ __uint64_t startoff; /* new btree key value */
+ xfs_bmbt_rec_t nrec; /* new record count */
+ int optr; /* old key/record index */
+ xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */
+@@ -759,9 +755,8 @@ xfs_bmbt_insrec(
+ ASSERT(level < cur->bc_nlevels);
+ XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
+ XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp);
+- ncur = (xfs_btree_cur_t *)0;
+- INT_SET(key.br_startoff, ARCH_CONVERT,
+- xfs_bmbt_disk_get_startoff(recp));
++ ncur = NULL;
++ key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(recp));
+ optr = ptr = cur->bc_ptrs[level];
+ if (ptr == 0) {
+ XFS_BMBT_TRACE_CURSOR(cur, EXIT);
+@@ -820,7 +815,7 @@ xfs_bmbt_insrec(
+ optr = ptr = cur->bc_ptrs[level];
+ } else {
+ if ((error = xfs_bmbt_split(cur, level,
+- &nbno, &nkey, &ncur,
++ &nbno, &startoff, &ncur,
+ &i))) {
+ XFS_BMBT_TRACE_CURSOR(cur,
+ ERROR);
+@@ -840,7 +835,7 @@ xfs_bmbt_insrec(
+ #endif
+ ptr = cur->bc_ptrs[level];
+ xfs_bmbt_disk_set_allf(&nrec,
+- nkey.br_startoff, 0, 0,
++ startoff, 0, 0,
+ XFS_EXT_NORM);
+ } else {
+ XFS_BMBT_TRACE_CURSOR(cur,
+@@ -858,7 +853,7 @@ xfs_bmbt_insrec(
+ pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
+ #ifdef DEBUG
+ for (i = numrecs; i >= ptr; i--) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT),
++ if ((error = xfs_btree_check_lptr_disk(cur, pp[i - 1],
+ level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+@@ -870,14 +865,13 @@ xfs_bmbt_insrec(
+ memmove(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */
+ (numrecs - ptr + 1) * sizeof(*pp));
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop,
+- level))) {
++ if ((error = xfs_btree_check_lptr(cur, *bnop, level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+ #endif
+ kp[ptr - 1] = key;
+- INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop);
++ pp[ptr - 1] = cpu_to_be64(*bnop);
+ numrecs++;
+ block->bb_numrecs = cpu_to_be16(numrecs);
+ xfs_bmbt_log_keys(cur, bp, ptr, numrecs);
+@@ -988,7 +982,7 @@ xfs_bmbt_killroot(
+ cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
+ #ifdef DEBUG
+ for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(cpp[i], ARCH_CONVERT), level - 1))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, cpp[i], level - 1))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+@@ -1132,7 +1126,7 @@ xfs_bmbt_lookup(
+ d = XFS_FSB_TO_DADDR(mp, fsbno);
+ bp = cur->bc_bufs[level];
+ if (bp && XFS_BUF_ADDR(bp) != d)
+- bp = (xfs_buf_t *)0;
++ bp = NULL;
+ if (!bp) {
+ if ((error = xfs_btree_read_bufl(mp, tp, fsbno,
+ 0, &bp, XFS_BMAP_BTREE_REF))) {
+@@ -1170,7 +1164,7 @@ xfs_bmbt_lookup(
+ keyno = (low + high) >> 1;
+ if (level > 0) {
+ kkp = kkbase + keyno - 1;
+- startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT);
++ startoff = be64_to_cpu(kkp->br_startoff);
+ } else {
+ krp = krbase + keyno - 1;
+ startoff = xfs_bmbt_disk_get_startoff(krp);
+@@ -1189,13 +1183,13 @@ xfs_bmbt_lookup(
+ if (diff > 0 && --keyno < 1)
+ keyno = 1;
+ pp = XFS_BMAP_PTR_IADDR(block, keyno, cur);
++ fsbno = be64_to_cpu(*pp);
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr(cur, fsbno, level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+ #endif
+- fsbno = INT_GET(*pp, ARCH_CONVERT);
+ cur->bc_ptrs[level] = keyno;
+ }
+ }
+@@ -1313,7 +1307,7 @@ xfs_bmbt_lshift(
+ lpp = XFS_BMAP_PTR_IADDR(left, lrecs, cur);
+ rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, *rpp, level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+@@ -1340,7 +1334,7 @@ xfs_bmbt_lshift(
+ if (level > 0) {
+ #ifdef DEBUG
+ for (i = 0; i < rrecs; i++) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT),
++ if ((error = xfs_btree_check_lptr_disk(cur, rpp[i + 1],
+ level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+@@ -1354,8 +1348,7 @@ xfs_bmbt_lshift(
+ } else {
+ memmove(rrp, rrp + 1, rrecs * sizeof(*rrp));
+ xfs_bmbt_log_recs(cur, rbp, 1, rrecs);
+- INT_SET(key.br_startoff, ARCH_CONVERT,
+- xfs_bmbt_disk_get_startoff(rrp));
++ key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(rrp));
+ rkp = &key;
+ }
+ if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) {
+@@ -1445,7 +1438,7 @@ xfs_bmbt_rshift(
+ rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
+ #ifdef DEBUG
+ for (i = be16_to_cpu(right->bb_numrecs) - 1; i >= 0; i--) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, rpp[i], level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+@@ -1454,7 +1447,7 @@ xfs_bmbt_rshift(
+ memmove(rkp + 1, rkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp));
+ memmove(rpp + 1, rpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, *lpp, level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+@@ -1469,8 +1462,7 @@ xfs_bmbt_rshift(
+ memmove(rrp + 1, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
+ *rrp = *lrp;
+ xfs_bmbt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
+- INT_SET(key.br_startoff, ARCH_CONVERT,
+- xfs_bmbt_disk_get_startoff(rrp));
++ key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(rrp));
+ rkp = &key;
+ }
+ be16_add(&left->bb_numrecs, -1);
+@@ -1535,7 +1527,7 @@ xfs_bmbt_split(
+ xfs_btree_cur_t *cur,
+ int level,
+ xfs_fsblock_t *bnop,
+- xfs_bmbt_key_t *keyp,
++ __uint64_t *startoff,
+ xfs_btree_cur_t **curp,
+ int *stat) /* success/failure */
+ {
+@@ -1560,7 +1552,7 @@ xfs_bmbt_split(
+ xfs_bmbt_rec_t *rrp; /* right record pointer */
+
+ XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
+- XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, keyp);
++ XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, *startoff);
+ args.tp = cur->bc_tp;
+ args.mp = cur->bc_mp;
+ lbp = cur->bc_bufs[level];
+@@ -1619,7 +1611,7 @@ xfs_bmbt_split(
+ rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
+ #ifdef DEBUG
+ for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, lpp[i], level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+@@ -1629,13 +1621,13 @@ xfs_bmbt_split(
+ memcpy(rpp, lpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
+ xfs_bmbt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
+ xfs_bmbt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
+- keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT);
++ *startoff = be64_to_cpu(rkp->br_startoff);
+ } else {
+ lrp = XFS_BMAP_REC_IADDR(left, i, cur);
+ rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
+ memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
+ xfs_bmbt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
+- keyp->br_startoff = xfs_bmbt_disk_get_startoff(rrp);
++ *startoff = xfs_bmbt_disk_get_startoff(rrp);
+ }
+ be16_add(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs)));
+ right->bb_rightsib = left->bb_rightsib;
+@@ -1728,9 +1720,9 @@ xfs_bmdr_to_bmbt(
+ {
+ int dmxr;
+ xfs_bmbt_key_t *fkp;
+- xfs_bmbt_ptr_t *fpp;
++ __be64 *fpp;
+ xfs_bmbt_key_t *tkp;
+- xfs_bmbt_ptr_t *tpp;
++ __be64 *tpp;
+
+ rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
+ rblock->bb_level = dblock->bb_level;
+@@ -1745,7 +1737,7 @@ xfs_bmdr_to_bmbt(
+ tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
+ dmxr = be16_to_cpu(dblock->bb_numrecs);
+ memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
+- memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
++ memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
+ }
+
+ /*
+@@ -1805,7 +1797,7 @@ xfs_bmbt_decrement(
+ tp = cur->bc_tp;
+ mp = cur->bc_mp;
+ for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) {
+- fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT);
++ fsbno = be64_to_cpu(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur));
+ if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp,
+ XFS_BMAP_BTREE_REF))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+@@ -2135,7 +2127,7 @@ xfs_bmbt_increment(
+ tp = cur->bc_tp;
+ mp = cur->bc_mp;
+ for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) {
+- fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT);
++ fsbno = be64_to_cpu(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur));
+ if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp,
+ XFS_BMAP_BTREE_REF))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+@@ -2178,7 +2170,7 @@ xfs_bmbt_insert(
+ level = 0;
+ nbno = NULLFSBLOCK;
+ xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ pcur = cur;
+ do {
+ if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur,
+@@ -2205,7 +2197,7 @@ xfs_bmbt_insert(
+ }
+ if (ncur) {
+ pcur = ncur;
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ }
+ } while (nbno != NULLFSBLOCK);
+ XFS_BMBT_TRACE_CURSOR(cur, EXIT);
+@@ -2356,12 +2348,12 @@ xfs_bmbt_newroot(
+ args.firstblock = args.fsbno;
+ if (args.fsbno == NULLFSBLOCK) {
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, *pp, level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+ #endif
+- args.fsbno = INT_GET(*pp, ARCH_CONVERT);
++ args.fsbno = be64_to_cpu(*pp);
+ args.type = XFS_ALLOCTYPE_START_BNO;
+ } else
+ args.type = XFS_ALLOCTYPE_NEAR_BNO;
+@@ -2393,7 +2385,7 @@ xfs_bmbt_newroot(
+ cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
+ #ifdef DEBUG
+ for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
+- if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) {
++ if ((error = xfs_btree_check_lptr_disk(cur, pp[i], level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+@@ -2401,13 +2393,12 @@ xfs_bmbt_newroot(
+ #endif
+ memcpy(cpp, pp, be16_to_cpu(cblock->bb_numrecs) * sizeof(*pp));
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno,
+- level))) {
++ if ((error = xfs_btree_check_lptr(cur, args.fsbno, level))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+ }
+ #endif
+- INT_SET(*pp, ARCH_CONVERT, args.fsbno);
++ *pp = cpu_to_be64(args.fsbno);
+ xfs_iroot_realloc(cur->bc_private.b.ip, 1 - be16_to_cpu(cblock->bb_numrecs),
+ cur->bc_private.b.whichfork);
+ xfs_btree_setbuf(cur, level, bp);
+@@ -2681,9 +2672,9 @@ xfs_bmbt_to_bmdr(
+ {
+ int dmxr;
+ xfs_bmbt_key_t *fkp;
+- xfs_bmbt_ptr_t *fpp;
++ __be64 *fpp;
+ xfs_bmbt_key_t *tkp;
+- xfs_bmbt_ptr_t *tpp;
++ __be64 *tpp;
+
+ ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_MAGIC);
+ ASSERT(be64_to_cpu(rblock->bb_leftsib) == NULLDFSBNO);
+@@ -2698,7 +2689,7 @@ xfs_bmbt_to_bmdr(
+ tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);
+ dmxr = be16_to_cpu(dblock->bb_numrecs);
+ memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
+- memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
++ memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
+ }
+
+ /*
+@@ -2740,7 +2731,7 @@ xfs_bmbt_update(
+ XFS_BMBT_TRACE_CURSOR(cur, EXIT);
+ return 0;
+ }
+- INT_SET(key.br_startoff, ARCH_CONVERT, off);
++ key.br_startoff = cpu_to_be64(off);
+ if ((error = xfs_bmbt_updkey(cur, &key, 1))) {
+ XFS_BMBT_TRACE_CURSOR(cur, ERROR);
+ return error;
+diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
+index 6478cfa..49539de 100644
+--- a/fs/xfs/xfs_bmap_btree.h
++++ b/fs/xfs/xfs_bmap_btree.h
+@@ -163,13 +163,14 @@ typedef struct xfs_bmbt_irec
+ /*
+ * Key structure for non-leaf levels of the tree.
+ */
+-typedef struct xfs_bmbt_key
+-{
+- xfs_dfiloff_t br_startoff; /* starting file offset */
++typedef struct xfs_bmbt_key {
++ __be64 br_startoff; /* starting file offset */
+ } xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+-typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */
+- /* btree block header type */
++/* btree pointer type */
++typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
++
++/* btree block header type */
+ typedef struct xfs_btree_lblock xfs_bmbt_block_t;
+
+ #define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)XFS_BUF_PTR(bp))
+diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
+index ee2255b..aeb87ca 100644
+--- a/fs/xfs/xfs_btree.c
++++ b/fs/xfs/xfs_btree.c
+@@ -161,7 +161,7 @@ xfs_btree_check_key(
+
+ k1 = ak1;
+ k2 = ak2;
+- ASSERT(INT_GET(k1->br_startoff, ARCH_CONVERT) < INT_GET(k2->br_startoff, ARCH_CONVERT));
++ ASSERT(be64_to_cpu(k1->br_startoff) < be64_to_cpu(k2->br_startoff));
+ break;
+ }
+ case XFS_BTNUM_INO: {
+@@ -170,7 +170,7 @@ xfs_btree_check_key(
+
+ k1 = ak1;
+ k2 = ak2;
+- ASSERT(INT_GET(k1->ir_startino, ARCH_CONVERT) < INT_GET(k2->ir_startino, ARCH_CONVERT));
++ ASSERT(be32_to_cpu(k1->ir_startino) < be32_to_cpu(k2->ir_startino));
+ break;
+ }
+ default:
+@@ -285,8 +285,8 @@ xfs_btree_check_rec(
+
+ r1 = ar1;
+ r2 = ar2;
+- ASSERT(INT_GET(r1->ir_startino, ARCH_CONVERT) + XFS_INODES_PER_CHUNK <=
+- INT_GET(r2->ir_startino, ARCH_CONVERT));
++ ASSERT(be32_to_cpu(r1->ir_startino) + XFS_INODES_PER_CHUNK <=
++ be32_to_cpu(r2->ir_startino));
+ break;
+ }
+ default:
+diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h
+index 44f1bd9..892b06c 100644
+--- a/fs/xfs/xfs_btree.h
++++ b/fs/xfs/xfs_btree.h
+@@ -145,7 +145,7 @@ typedef struct xfs_btree_cur
+ union {
+ xfs_alloc_rec_incore_t a;
+ xfs_bmbt_irec_t b;
+- xfs_inobt_rec_t i;
++ xfs_inobt_rec_incore_t i;
+ } bc_rec; /* current insert/search record value */
+ struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */
+ int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */
+@@ -243,6 +243,9 @@ xfs_btree_check_lptr(
+ xfs_dfsbno_t ptr, /* btree block disk address */
+ int level); /* btree block level */
+
++#define xfs_btree_check_lptr_disk(cur, ptr, level) \
++ xfs_btree_check_lptr(cur, be64_to_cpu(ptr), level)
++
+ /*
+ * Checking routine: check that short form block header is ok.
+ */
+diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
+index a4aa539..7a55c24 100644
+--- a/fs/xfs/xfs_buf_item.c
++++ b/fs/xfs/xfs_buf_item.c
+@@ -234,7 +234,6 @@ xfs_buf_item_format(
+ ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
+ (bip->bli_flags & XFS_BLI_STALE));
+ bp = bip->bli_buf;
+- ASSERT(XFS_BUF_BP_ISMAPPED(bp));
+ vecp = log_vector;
+
+ /*
+@@ -628,25 +627,6 @@ xfs_buf_item_committed(
+ }
+
+ /*
+- * This is called when the transaction holding the buffer is aborted.
+- * Just behave as if the transaction had been cancelled. If we're shutting down
+- * and have aborted this transaction, we'll trap this buffer when it tries to
+- * get written out.
+- */
+-STATIC void
+-xfs_buf_item_abort(
+- xfs_buf_log_item_t *bip)
+-{
+- xfs_buf_t *bp;
+-
+- bp = bip->bli_buf;
+- xfs_buftrace("XFS_ABORT", bp);
+- XFS_BUF_SUPER_STALE(bp);
+- xfs_buf_item_unlock(bip);
+- return;
+-}
+-
+-/*
+ * This is called to asynchronously write the buffer associated with this
+ * buf log item out to disk. The buffer will already have been locked by
+ * a successful call to xfs_buf_item_trylock(). If the buffer still has
+@@ -693,7 +673,6 @@ STATIC struct xfs_item_ops xfs_buf_item_
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_buf_item_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_buf_item_abort,
+ .iop_pushbuf = NULL,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_buf_item_committing
+@@ -901,7 +880,6 @@ xfs_buf_item_relse(
+ XFS_BUF_SET_FSPRIVATE(bp, bip->bli_item.li_bio_list);
+ if ((XFS_BUF_FSPRIVATE(bp, void *) == NULL) &&
+ (XFS_BUF_IODONE_FUNC(bp) != NULL)) {
+- ASSERT((XFS_BUF_ISUNINITIAL(bp)) == 0);
+ XFS_BUF_CLR_IODONE_FUNC(bp);
+ }
+
+diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
+index 32ab61d..a68bc1f 100644
+--- a/fs/xfs/xfs_da_btree.c
++++ b/fs/xfs/xfs_da_btree.c
+@@ -1054,7 +1054,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *s
+ xfs_da_node_entry_t *btree;
+ xfs_dablk_t blkno;
+ int probe, span, max, error, retval;
+- xfs_dahash_t hashval;
++ xfs_dahash_t hashval, btreehashval;
+ xfs_da_args_t *args;
+
+ args = state->args;
+@@ -1079,30 +1079,32 @@ xfs_da_node_lookup_int(xfs_da_state_t *s
+ return(error);
+ }
+ curr = blk->bp->data;
+- ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC ||
+- be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC ||
+- be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC);
++ blk->magic = be16_to_cpu(curr->magic);
++ ASSERT(blk->magic == XFS_DA_NODE_MAGIC ||
++ blk->magic == XFS_DIR2_LEAFN_MAGIC ||
++ blk->magic == XFS_ATTR_LEAF_MAGIC);
+
+ /*
+ * Search an intermediate node for a match.
+ */
+- blk->magic = be16_to_cpu(curr->magic);
+ if (blk->magic == XFS_DA_NODE_MAGIC) {
+ node = blk->bp->data;
+- blk->hashval = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
++ max = be16_to_cpu(node->hdr.count);
++ btreehashval = node->btree[max-1].hashval;
++ blk->hashval = be32_to_cpu(btreehashval);
+
+ /*
+ * Binary search. (note: small blocks will skip loop)
+ */
+- max = be16_to_cpu(node->hdr.count);
+ probe = span = max / 2;
+ hashval = args->hashval;
+ for (btree = &node->btree[probe]; span > 4;
+ btree = &node->btree[probe]) {
+ span /= 2;
+- if (be32_to_cpu(btree->hashval) < hashval)
++ btreehashval = be32_to_cpu(btree->hashval);
++ if (btreehashval < hashval)
+ probe += span;
+- else if (be32_to_cpu(btree->hashval) > hashval)
++ else if (btreehashval > hashval)
+ probe -= span;
+ else
+ break;
+@@ -1133,10 +1135,10 @@ xfs_da_node_lookup_int(xfs_da_state_t *s
+ blk->index = probe;
+ blkno = be32_to_cpu(btree->before);
+ }
+- } else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
++ } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
+ blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
+ break;
+- } else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
++ } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
+ blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL);
+ break;
+ }
+@@ -1152,11 +1154,13 @@ xfs_da_node_lookup_int(xfs_da_state_t *s
+ if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
+ retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
+ &blk->index, state);
+- }
+- else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
++ } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
+ retval = xfs_attr_leaf_lookup_int(blk->bp, args);
+ blk->index = args->index;
+ args->blkno = blk->blkno;
++ } else {
++ ASSERT(0);
++ return XFS_ERROR(EFSCORRUPTED);
+ }
+ if (((retval == ENOENT) || (retval == ENOATTR)) &&
+ (blk->hashval == args->hashval)) {
+@@ -1166,8 +1170,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *s
+ return(error);
+ if (retval == 0) {
+ continue;
+- }
+- else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
++ } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
+ /* path_shift() gives ENOENT */
+ retval = XFS_ERROR(ENOATTR);
+ }
+diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
+index bc43163..0893e16 100644
+--- a/fs/xfs/xfs_error.h
++++ b/fs/xfs/xfs_error.h
+@@ -18,14 +18,6 @@
+ #ifndef __XFS_ERROR_H__
+ #define __XFS_ERROR_H__
+
+-#define XFS_ERECOVER 1 /* Failure to recover log */
+-#define XFS_ELOGSTAT 2 /* Failure to stat log in user space */
+-#define XFS_ENOLOGSPACE 3 /* Reservation too large */
+-#define XFS_ENOTSUP 4 /* Operation not supported */
+-#define XFS_ENOLSN 5 /* Can't find the lsn you asked for */
+-#define XFS_ENOTFOUND 6
+-#define XFS_ENOTXFS 7 /* Not XFS filesystem */
+-
+ #ifdef DEBUG
+ #define XFS_ERROR_NTRAP 10
+ extern int xfs_etrap[XFS_ERROR_NTRAP];
+@@ -175,6 +167,7 @@ extern int xfs_errortag_clearall_umount(
+ #define XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010
+ #define XFS_PTAG_SHUTDOWN_IOERROR 0x00000020
+ #define XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040
++#define XFS_PTAG_FSBLOCK_ZERO 0x00000080
+
+ struct xfs_mount;
+ /* PRINTFLIKE4 */
+diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
+index 6cf6d87..6dba781 100644
+--- a/fs/xfs/xfs_extfree_item.c
++++ b/fs/xfs/xfs_extfree_item.c
+@@ -33,9 +33,6 @@ kmem_zone_t *xfs_efi_zone;
+ kmem_zone_t *xfs_efd_zone;
+
+ STATIC void xfs_efi_item_unlock(xfs_efi_log_item_t *);
+-STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *);
+-STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *);
+-
+
+ void
+ xfs_efi_item_free(xfs_efi_log_item_t *efip)
+@@ -184,7 +181,7 @@ STATIC void
+ xfs_efi_item_unlock(xfs_efi_log_item_t *efip)
+ {
+ if (efip->efi_item.li_flags & XFS_LI_ABORTED)
+- xfs_efi_item_abort(efip);
++ xfs_efi_item_free(efip);
+ return;
+ }
+
+@@ -202,18 +199,6 @@ xfs_efi_item_committed(xfs_efi_log_item_
+ }
+
+ /*
+- * This is called when the transaction logging the EFI is aborted.
+- * Free up the EFI and return. No need to clean up the slot for
+- * the item in the transaction. That was done by the unpin code
+- * which is called prior to this routine in the abort/fs-shutdown path.
+- */
+-STATIC void
+-xfs_efi_item_abort(xfs_efi_log_item_t *efip)
+-{
+- xfs_efi_item_free(efip);
+-}
+-
+-/*
+ * There isn't much you can do to push on an efi item. It is simply
+ * stuck waiting for all of its corresponding efd items to be
+ * committed to disk.
+@@ -255,7 +240,6 @@ STATIC struct xfs_item_ops xfs_efi_item_
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_efi_item_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_efi_item_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_efi_item_abort,
+ .iop_pushbuf = NULL,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_efi_item_committing
+@@ -386,33 +370,6 @@ xfs_efi_release(xfs_efi_log_item_t *efip
+ }
+ }
+
+-/*
+- * This is called when the transaction that should be committing the
+- * EFD corresponding to the given EFI is aborted. The committed and
+- * canceled flags are used to coordinate the freeing of the EFI and
+- * the references by the transaction that committed it.
+- */
+-STATIC void
+-xfs_efi_cancel(
+- xfs_efi_log_item_t *efip)
+-{
+- xfs_mount_t *mp;
+- SPLDECL(s);
+-
+- mp = efip->efi_item.li_mountp;
+- AIL_LOCK(mp, s);
+- if (efip->efi_flags & XFS_EFI_COMMITTED) {
+- /*
+- * xfs_trans_delete_ail() drops the AIL lock.
+- */
+- xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s);
+- xfs_efi_item_free(efip);
+- } else {
+- efip->efi_flags |= XFS_EFI_CANCELED;
+- AIL_UNLOCK(mp, s);
+- }
+-}
+-
+ STATIC void
+ xfs_efd_item_free(xfs_efd_log_item_t *efdp)
+ {
+@@ -514,7 +471,7 @@ STATIC void
+ xfs_efd_item_unlock(xfs_efd_log_item_t *efdp)
+ {
+ if (efdp->efd_item.li_flags & XFS_LI_ABORTED)
+- xfs_efd_item_abort(efdp);
++ xfs_efd_item_free(efdp);
+ return;
+ }
+
+@@ -541,27 +498,6 @@ xfs_efd_item_committed(xfs_efd_log_item_
+ }
+
+ /*
+- * The transaction of which this EFD is a part has been aborted.
+- * Inform its companion EFI of this fact and then clean up after
+- * ourselves. No need to clean up the slot for the item in the
+- * transaction. That was done by the unpin code which is called
+- * prior to this routine in the abort/fs-shutdown path.
+- */
+-STATIC void
+-xfs_efd_item_abort(xfs_efd_log_item_t *efdp)
+-{
+- /*
+- * If we got a log I/O error, it's always the case that the LR with the
+- * EFI got unpinned and freed before the EFD got aborted. So don't
+- * reference the EFI at all in that case.
+- */
+- if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0)
+- xfs_efi_cancel(efdp->efd_efip);
+-
+- xfs_efd_item_free(efdp);
+-}
+-
+-/*
+ * There isn't much you can do to push on an efd item. It is simply
+ * stuck waiting for the log to be flushed to disk.
+ */
+@@ -602,7 +538,6 @@ STATIC struct xfs_item_ops xfs_efd_item_
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_efd_item_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_efd_item_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_efd_item_abort,
+ .iop_pushbuf = NULL,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_efd_item_committing
+diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h
+index 0ea45ed..2f049f6 100644
+--- a/fs/xfs/xfs_extfree_item.h
++++ b/fs/xfs/xfs_extfree_item.h
+@@ -33,14 +33,16 @@ typedef struct xfs_extent {
+ * conversion routine.
+ */
+
++#ifndef HAVE_FORMAT32
+ typedef struct xfs_extent_32 {
+- xfs_dfsbno_t ext_start;
+- xfs_extlen_t ext_len;
++ __uint64_t ext_start;
++ __uint32_t ext_len;
+ } __attribute__((packed)) xfs_extent_32_t;
++#endif
+
+ typedef struct xfs_extent_64 {
+- xfs_dfsbno_t ext_start;
+- xfs_extlen_t ext_len;
++ __uint64_t ext_start;
++ __uint32_t ext_len;
+ __uint32_t ext_pad;
+ } xfs_extent_64_t;
+
+@@ -50,25 +52,27 @@ typedef struct xfs_extent_64 {
+ * size is given by efi_nextents.
+ */
+ typedef struct xfs_efi_log_format {
+- unsigned short efi_type; /* efi log item type */
+- unsigned short efi_size; /* size of this item */
+- uint efi_nextents; /* # extents to free */
++ __uint16_t efi_type; /* efi log item type */
++ __uint16_t efi_size; /* size of this item */
++ __uint32_t efi_nextents; /* # extents to free */
+ __uint64_t efi_id; /* efi identifier */
+ xfs_extent_t efi_extents[1]; /* array of extents to free */
+ } xfs_efi_log_format_t;
+
++#ifndef HAVE_FORMAT32
+ typedef struct xfs_efi_log_format_32 {
+- unsigned short efi_type; /* efi log item type */
+- unsigned short efi_size; /* size of this item */
+- uint efi_nextents; /* # extents to free */
++ __uint16_t efi_type; /* efi log item type */
++ __uint16_t efi_size; /* size of this item */
++ __uint32_t efi_nextents; /* # extents to free */
+ __uint64_t efi_id; /* efi identifier */
+ xfs_extent_32_t efi_extents[1]; /* array of extents to free */
+ } __attribute__((packed)) xfs_efi_log_format_32_t;
++#endif
+
+ typedef struct xfs_efi_log_format_64 {
+- unsigned short efi_type; /* efi log item type */
+- unsigned short efi_size; /* size of this item */
+- uint efi_nextents; /* # extents to free */
++ __uint16_t efi_type; /* efi log item type */
++ __uint16_t efi_size; /* size of this item */
++ __uint32_t efi_nextents; /* # extents to free */
+ __uint64_t efi_id; /* efi identifier */
+ xfs_extent_64_t efi_extents[1]; /* array of extents to free */
+ } xfs_efi_log_format_64_t;
+@@ -79,25 +83,27 @@ typedef struct xfs_efi_log_format_64 {
+ * size is given by efd_nextents;
+ */
+ typedef struct xfs_efd_log_format {
+- unsigned short efd_type; /* efd log item type */
+- unsigned short efd_size; /* size of this item */
+- uint efd_nextents; /* # of extents freed */
++ __uint16_t efd_type; /* efd log item type */
++ __uint16_t efd_size; /* size of this item */
++ __uint32_t efd_nextents; /* # of extents freed */
+ __uint64_t efd_efi_id; /* id of corresponding efi */
+ xfs_extent_t efd_extents[1]; /* array of extents freed */
+ } xfs_efd_log_format_t;
+
++#ifndef HAVE_FORMAT32
+ typedef struct xfs_efd_log_format_32 {
+- unsigned short efd_type; /* efd log item type */
+- unsigned short efd_size; /* size of this item */
+- uint efd_nextents; /* # of extents freed */
++ __uint16_t efd_type; /* efd log item type */
++ __uint16_t efd_size; /* size of this item */
++ __uint32_t efd_nextents; /* # of extents freed */
+ __uint64_t efd_efi_id; /* id of corresponding efi */
+ xfs_extent_32_t efd_extents[1]; /* array of extents freed */
+ } __attribute__((packed)) xfs_efd_log_format_32_t;
++#endif
+
+ typedef struct xfs_efd_log_format_64 {
+- unsigned short efd_type; /* efd log item type */
+- unsigned short efd_size; /* size of this item */
+- uint efd_nextents; /* # of extents freed */
++ __uint16_t efd_type; /* efd log item type */
++ __uint16_t efd_size; /* size of this item */
++ __uint32_t efd_nextents; /* # of extents freed */
+ __uint64_t efd_efi_id; /* id of corresponding efi */
+ xfs_extent_64_t efd_extents[1]; /* array of extents freed */
+ } xfs_efd_log_format_64_t;
+diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
+index 0f0ad15..1335449 100644
+--- a/fs/xfs/xfs_fs.h
++++ b/fs/xfs/xfs_fs.h
+@@ -22,8 +22,6 @@
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+-#define XFS_NAME "xfs"
+-
+ /*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+@@ -426,11 +424,7 @@ typedef struct xfs_handle {
+ - (char *) &(handle)) \
+ + (handle).ha_fid.xfs_fid_len)
+
+-#define XFS_HANDLE_CMP(h1, h2) memcmp(h1, h2, sizeof(xfs_handle_t))
+-
+-#define FSHSIZE sizeof(fsid_t)
+-
+-/*
++/*
+ * Flags for going down operation
+ */
+ #define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
+diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
+index 33164a8..a446e5a 100644
+--- a/fs/xfs/xfs_ialloc.c
++++ b/fs/xfs/xfs_ialloc.c
+@@ -458,7 +458,7 @@ nextag:
+ */
+ if (XFS_FORCED_SHUTDOWN(mp)) {
+ up_read(&mp->m_peraglock);
+- return (xfs_buf_t *)0;
++ return NULL;
+ }
+ agno++;
+ if (agno >= agcount)
+@@ -466,7 +466,7 @@ nextag:
+ if (agno == pagno) {
+ if (flags == 0) {
+ up_read(&mp->m_peraglock);
+- return (xfs_buf_t *)0;
++ return NULL;
+ }
+ flags = 0;
+ }
+@@ -529,10 +529,10 @@ xfs_dialloc(
+ int offset; /* index of inode in chunk */
+ xfs_agino_t pagino; /* parent's a.g. relative inode # */
+ xfs_agnumber_t pagno; /* parent's allocation group number */
+- xfs_inobt_rec_t rec; /* inode allocation record */
++ xfs_inobt_rec_incore_t rec; /* inode allocation record */
+ xfs_agnumber_t tagno; /* testing allocation group number */
+ xfs_btree_cur_t *tcur; /* temp cursor */
+- xfs_inobt_rec_t trec; /* temp inode allocation record */
++ xfs_inobt_rec_incore_t trec; /* temp inode allocation record */
+
+
+ if (*IO_agbp == NULL) {
+@@ -945,7 +945,7 @@ xfs_difree(
+ int ilen; /* inodes in an inode cluster */
+ xfs_mount_t *mp; /* mount structure for filesystem */
+ int off; /* offset of inode in inode chunk */
+- xfs_inobt_rec_t rec; /* btree record */
++ xfs_inobt_rec_incore_t rec; /* btree record */
+
+ mp = tp->t_mountp;
+
+@@ -1195,6 +1195,7 @@ xfs_dilocate(
+ "(0x%llx)",
+ ino, XFS_AGINO_TO_INO(mp, agno, agino));
+ }
++ xfs_stack_trace();
+ #endif /* DEBUG */
+ return XFS_ERROR(EINVAL);
+ }
+diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
+index 616eeeb..8cdeeaf 100644
+--- a/fs/xfs/xfs_ialloc_btree.c
++++ b/fs/xfs/xfs_ialloc_btree.c
+@@ -568,7 +568,7 @@ xfs_inobt_insrec(
+ /*
+ * Make a key out of the record data to be inserted, and save it.
+ */
+- key.ir_startino = recp->ir_startino; /* INT_: direct copy */
++ key.ir_startino = recp->ir_startino;
+ optr = ptr = cur->bc_ptrs[level];
+ /*
+ * If we're off the left edge, return failure.
+@@ -600,7 +600,7 @@ xfs_inobt_insrec(
+ }
+ #endif
+ nbno = NULLAGBLOCK;
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ /*
+ * If the block is full, we can't insert the new entry until we
+ * make the block un-full.
+@@ -641,7 +641,7 @@ xfs_inobt_insrec(
+ return error;
+ #endif
+ ptr = cur->bc_ptrs[level];
+- nrec.ir_startino = nkey.ir_startino; /* INT_: direct copy */
++ nrec.ir_startino = nkey.ir_startino;
+ } else {
+ /*
+ * Otherwise the insert fails.
+@@ -681,7 +681,7 @@ xfs_inobt_insrec(
+ if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
+ return error;
+ #endif
+- kp[ptr - 1] = key; /* INT_: struct copy */
++ kp[ptr - 1] = key;
+ pp[ptr - 1] = cpu_to_be32(*bnop);
+ numrecs++;
+ block->bb_numrecs = cpu_to_be16(numrecs);
+@@ -698,7 +698,7 @@ xfs_inobt_insrec(
+ * Now stuff the new record in, bump numrecs
+ * and log the new data.
+ */
+- rp[ptr - 1] = *recp; /* INT_: struct copy */
++ rp[ptr - 1] = *recp;
+ numrecs++;
+ block->bb_numrecs = cpu_to_be16(numrecs);
+ xfs_inobt_log_recs(cur, bp, ptr, numrecs);
+@@ -731,7 +731,7 @@ xfs_inobt_insrec(
+ */
+ *bnop = nbno;
+ if (nbno != NULLAGBLOCK) {
+- *recp = nrec; /* INT_: struct copy */
++ *recp = nrec;
+ *curp = ncur;
+ }
+ *stat = 1;
+@@ -878,7 +878,7 @@ xfs_inobt_lookup(
+ */
+ bp = cur->bc_bufs[level];
+ if (bp && XFS_BUF_ADDR(bp) != d)
+- bp = (xfs_buf_t *)0;
++ bp = NULL;
+ if (!bp) {
+ /*
+ * Need to get a new buffer. Read it, then
+@@ -950,12 +950,12 @@ xfs_inobt_lookup(
+ xfs_inobt_key_t *kkp;
+
+ kkp = kkbase + keyno - 1;
+- startino = INT_GET(kkp->ir_startino, ARCH_CONVERT);
++ startino = be32_to_cpu(kkp->ir_startino);
+ } else {
+ xfs_inobt_rec_t *krp;
+
+ krp = krbase + keyno - 1;
+- startino = INT_GET(krp->ir_startino, ARCH_CONVERT);
++ startino = be32_to_cpu(krp->ir_startino);
+ }
+ /*
+ * Compute difference to get next direction.
+@@ -1117,7 +1117,7 @@ xfs_inobt_lshift(
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*rpp), level)))
+ return error;
+ #endif
+- *lpp = *rpp; /* INT_: no-change copy */
++ *lpp = *rpp;
+ xfs_inobt_log_ptrs(cur, lbp, nrec, nrec);
+ }
+ /*
+@@ -1160,7 +1160,7 @@ xfs_inobt_lshift(
+ } else {
+ memmove(rrp, rrp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
+ xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
+- key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
++ key.ir_startino = rrp->ir_startino;
+ rkp = &key;
+ }
+ /*
+@@ -1297,13 +1297,13 @@ xfs_inobt_newroot(
+ */
+ kp = XFS_INOBT_KEY_ADDR(new, 1, cur);
+ if (be16_to_cpu(left->bb_level) > 0) {
+- kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur); /* INT_: struct copy */
+- kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur); /* INT_: struct copy */
++ kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur);
++ kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur);
+ } else {
+ rp = XFS_INOBT_REC_ADDR(left, 1, cur);
+- INT_COPY(kp[0].ir_startino, rp->ir_startino, ARCH_CONVERT);
++ kp[0].ir_startino = rp->ir_startino;
+ rp = XFS_INOBT_REC_ADDR(right, 1, cur);
+- INT_COPY(kp[1].ir_startino, rp->ir_startino, ARCH_CONVERT);
++ kp[1].ir_startino = rp->ir_startino;
+ }
+ xfs_inobt_log_keys(cur, nbp, 1, 2);
+ /*
+@@ -1410,8 +1410,8 @@ xfs_inobt_rshift(
+ if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*lpp), level)))
+ return error;
+ #endif
+- *rkp = *lkp; /* INT_: no change copy */
+- *rpp = *lpp; /* INT_: no change copy */
++ *rkp = *lkp;
++ *rpp = *lpp;
+ xfs_inobt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
+ xfs_inobt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
+ } else {
+@@ -1420,7 +1420,7 @@ xfs_inobt_rshift(
+ memmove(rrp + 1, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
+ *rrp = *lrp;
+ xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
+- key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
++ key.ir_startino = rrp->ir_startino;
+ rkp = &key;
+ }
+ /*
+@@ -1559,7 +1559,7 @@ xfs_inobt_split(
+ rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
+ memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
+ xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
+- keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */
++ keyp->ir_startino = rrp->ir_startino;
+ }
+ /*
+ * Find the left block number by looking in the buffer.
+@@ -1813,9 +1813,9 @@ xfs_inobt_get_rec(
+ * Point to the record and extract its data.
+ */
+ rec = XFS_INOBT_REC_ADDR(block, ptr, cur);
+- *ino = INT_GET(rec->ir_startino, ARCH_CONVERT);
+- *fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT);
+- *free = INT_GET(rec->ir_free, ARCH_CONVERT);
++ *ino = be32_to_cpu(rec->ir_startino);
++ *fcnt = be32_to_cpu(rec->ir_freecount);
++ *free = be64_to_cpu(rec->ir_free);
+ *stat = 1;
+ return 0;
+ }
+@@ -1930,10 +1930,10 @@ xfs_inobt_insert(
+
+ level = 0;
+ nbno = NULLAGBLOCK;
+- INT_SET(nrec.ir_startino, ARCH_CONVERT, cur->bc_rec.i.ir_startino);
+- INT_SET(nrec.ir_freecount, ARCH_CONVERT, cur->bc_rec.i.ir_freecount);
+- INT_SET(nrec.ir_free, ARCH_CONVERT, cur->bc_rec.i.ir_free);
+- ncur = (xfs_btree_cur_t *)0;
++ nrec.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
++ nrec.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
++ nrec.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
++ ncur = NULL;
+ pcur = cur;
+ /*
+ * Loop going up the tree, starting at the leaf level.
+@@ -1965,7 +1965,7 @@ xfs_inobt_insert(
+ */
+ if (ncur) {
+ pcur = ncur;
+- ncur = (xfs_btree_cur_t *)0;
++ ncur = NULL;
+ }
+ } while (nbno != NULLAGBLOCK);
+ *stat = i;
+@@ -2060,9 +2060,9 @@ xfs_inobt_update(
+ /*
+ * Fill in the new contents and log them.
+ */
+- INT_SET(rp->ir_startino, ARCH_CONVERT, ino);
+- INT_SET(rp->ir_freecount, ARCH_CONVERT, fcnt);
+- INT_SET(rp->ir_free, ARCH_CONVERT, free);
++ rp->ir_startino = cpu_to_be32(ino);
++ rp->ir_freecount = cpu_to_be32(fcnt);
++ rp->ir_free = cpu_to_be64(free);
+ xfs_inobt_log_recs(cur, bp, ptr, ptr);
+ /*
+ * Updating first record in leaf. Pass new key value up to our parent.
+@@ -2070,7 +2070,7 @@ xfs_inobt_update(
+ if (ptr == 1) {
+ xfs_inobt_key_t key; /* key containing [ino] */
+
+- INT_SET(key.ir_startino, ARCH_CONVERT, ino);
++ key.ir_startino = cpu_to_be32(ino);
+ if ((error = xfs_inobt_updkey(cur, &key, 1)))
+ return error;
+ }
+diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h
+index ae3904c..2c0e498 100644
+--- a/fs/xfs/xfs_ialloc_btree.h
++++ b/fs/xfs/xfs_ialloc_btree.h
+@@ -47,19 +47,24 @@ static inline xfs_inofree_t xfs_inobt_ma
+ /*
+ * Data record structure
+ */
+-typedef struct xfs_inobt_rec
+-{
++typedef struct xfs_inobt_rec {
++ __be32 ir_startino; /* starting inode number */
++ __be32 ir_freecount; /* count of free inodes (set bits) */
++ __be64 ir_free; /* free inode mask */
++} xfs_inobt_rec_t;
++
++typedef struct xfs_inobt_rec_incore {
+ xfs_agino_t ir_startino; /* starting inode number */
+ __int32_t ir_freecount; /* count of free inodes (set bits) */
+ xfs_inofree_t ir_free; /* free inode mask */
+-} xfs_inobt_rec_t;
++} xfs_inobt_rec_incore_t;
++
+
+ /*
+ * Key structure
+ */
+-typedef struct xfs_inobt_key
+-{
+- xfs_agino_t ir_startino; /* starting inode number */
++typedef struct xfs_inobt_key {
++ __be32 ir_startino; /* starting inode number */
+ } xfs_inobt_key_t;
+
+ /* btree pointer type */
+@@ -77,7 +82,7 @@ typedef struct xfs_btree_sblock xfs_inob
+ #define XFS_INOBT_IS_FREE(rp,i) \
+ (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0)
+ #define XFS_INOBT_IS_FREE_DISK(rp,i) \
+- ((INT_GET((rp)->ir_free,ARCH_CONVERT) & XFS_INOBT_MASK(i)) != 0)
++ ((be64_to_cpu((rp)->ir_free) & XFS_INOBT_MASK(i)) != 0)
+ #define XFS_INOBT_SET_FREE(rp,i) ((rp)->ir_free |= XFS_INOBT_MASK(i))
+ #define XFS_INOBT_CLR_FREE(rp,i) ((rp)->ir_free &= ~XFS_INOBT_MASK(i))
+
+diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
+index 0724df7..b73d216 100644
+--- a/fs/xfs/xfs_iget.c
++++ b/fs/xfs/xfs_iget.c
+@@ -50,7 +50,7 @@ void
+ xfs_ihash_init(xfs_mount_t *mp)
+ {
+ __uint64_t icount;
+- uint i, flags = KM_SLEEP | KM_MAYFAIL;
++ uint i;
+
+ if (!mp->m_ihsize) {
+ icount = mp->m_maxicount ? mp->m_maxicount :
+@@ -61,14 +61,13 @@ xfs_ihash_init(xfs_mount_t *mp)
+ (64 * NBPP) / sizeof(xfs_ihash_t));
+ }
+
+- while (!(mp->m_ihash = (xfs_ihash_t *)kmem_zalloc(mp->m_ihsize *
+- sizeof(xfs_ihash_t), flags))) {
+- if ((mp->m_ihsize >>= 1) <= NBPP)
+- flags = KM_SLEEP;
+- }
+- for (i = 0; i < mp->m_ihsize; i++) {
++ mp->m_ihash = kmem_zalloc_greedy(&mp->m_ihsize,
++ NBPC * sizeof(xfs_ihash_t),
++ mp->m_ihsize * sizeof(xfs_ihash_t),
++ KM_SLEEP | KM_MAYFAIL | KM_LARGE);
++ mp->m_ihsize /= sizeof(xfs_ihash_t);
++ for (i = 0; i < mp->m_ihsize; i++)
+ rwlock_init(&(mp->m_ihash[i].ih_lock));
+- }
+ }
+
+ /*
+@@ -77,7 +76,7 @@ xfs_ihash_init(xfs_mount_t *mp)
+ void
+ xfs_ihash_free(xfs_mount_t *mp)
+ {
+- kmem_free(mp->m_ihash, mp->m_ihsize*sizeof(xfs_ihash_t));
++ kmem_free(mp->m_ihash, mp->m_ihsize * sizeof(xfs_ihash_t));
+ mp->m_ihash = NULL;
+ }
+
+@@ -95,7 +94,7 @@ xfs_chash_init(xfs_mount_t *mp)
+ mp->m_chsize = min_t(uint, mp->m_chsize, mp->m_ihsize);
+ mp->m_chash = (xfs_chash_t *)kmem_zalloc(mp->m_chsize
+ * sizeof(xfs_chash_t),
+- KM_SLEEP);
++ KM_SLEEP | KM_LARGE);
+ for (i = 0; i < mp->m_chsize; i++) {
+ spinlock_init(&mp->m_chash[i].ch_lock,"xfshash");
+ }
+@@ -244,7 +243,9 @@ again:
+
+ XFS_STATS_INC(xs_ig_found);
+
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags &= ~XFS_IRECLAIMABLE;
++ spin_unlock(&ip->i_flags_lock);
+ version = ih->ih_version;
+ read_unlock(&ih->ih_lock);
+ xfs_ihash_promote(ih, ip, version);
+@@ -290,15 +291,17 @@ again:
+
+ finish_inode:
+ if (ip->i_d.di_mode == 0) {
+- if (!(flags & IGET_CREATE))
++ if (!(flags & XFS_IGET_CREATE))
+ return ENOENT;
+ xfs_iocore_inode_reinit(ip);
+ }
+-
++
+ if (lock_flags != 0)
+ xfs_ilock(ip, lock_flags);
+
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags &= ~XFS_ISTALE;
++ spin_unlock(&ip->i_flags_lock);
+
+ vn_trace_exit(vp, "xfs_iget.found",
+ (inst_t *)__return_address);
+@@ -320,21 +323,20 @@ finish_inode:
+ * Read the disk inode attributes into a new inode structure and get
+ * a new vnode for it. This should also initialize i_ino and i_mount.
+ */
+- error = xfs_iread(mp, tp, ino, &ip, bno);
+- if (error) {
++ error = xfs_iread(mp, tp, ino, &ip, bno,
++ (flags & XFS_IGET_BULKSTAT) ? XFS_IMAP_BULKSTAT : 0);
++ if (error)
+ return error;
+- }
+
+ vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address);
+
+ xfs_inode_lock_init(ip, vp);
+ xfs_iocore_inode_init(ip);
+
+- if (lock_flags != 0) {
++ if (lock_flags)
+ xfs_ilock(ip, lock_flags);
+- }
+-
+- if ((ip->i_d.di_mode == 0) && !(flags & IGET_CREATE)) {
++
++ if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
+ xfs_idestroy(ip);
+ return ENOENT;
+ }
+@@ -369,7 +371,9 @@ finish_inode:
+ ih->ih_next = ip;
+ ip->i_udquot = ip->i_gdquot = NULL;
+ ih->ih_version++;
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags |= XFS_INEW;
++ spin_unlock(&ip->i_flags_lock);
+
+ write_unlock(&ih->ih_lock);
+
+@@ -548,7 +552,7 @@ xfs_inode_lock_init(
+ mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", vp->v_number);
+ init_waitqueue_head(&ip->i_ipin_wait);
+ atomic_set(&ip->i_pincount, 0);
+- init_sema(&ip->i_flock, 1, "xfsfino", vp->v_number);
++ initnsema(&ip->i_flock, 1, "xfsfino");
+ }
+
+ /*
+diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
+index 1f8ecff..c27d7d4 100644
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -854,7 +854,8 @@ xfs_iread(
+ xfs_trans_t *tp,
+ xfs_ino_t ino,
+ xfs_inode_t **ipp,
+- xfs_daddr_t bno)
++ xfs_daddr_t bno,
++ uint imap_flags)
+ {
+ xfs_buf_t *bp;
+ xfs_dinode_t *dip;
+@@ -866,6 +867,7 @@ xfs_iread(
+ ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP);
+ ip->i_ino = ino;
+ ip->i_mount = mp;
++ spin_lock_init(&ip->i_flags_lock);
+
+ /*
+ * Get pointer's to the on-disk inode and the buffer containing it.
+@@ -874,7 +876,7 @@ xfs_iread(
+ * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will
+ * know that this is a new incore inode.
+ */
+- error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, 0);
++ error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, imap_flags);
+ if (error) {
+ kmem_zone_free(xfs_inode_zone, ip);
+ return error;
+@@ -1113,7 +1115,7 @@ xfs_ialloc(
+ * to prevent others from looking at until we're done.
+ */
+ error = xfs_trans_iget(tp->t_mountp, tp, ino,
+- IGET_CREATE, XFS_ILOCK_EXCL, &ip);
++ XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip);
+ if (error != 0) {
+ return error;
+ }
+@@ -2213,7 +2215,9 @@ xfs_ifree_cluster(
+
+ if (ip == free_ip) {
+ if (xfs_iflock_nowait(ip)) {
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags |= XFS_ISTALE;
++ spin_unlock(&ip->i_flags_lock);
+
+ if (xfs_inode_clean(ip)) {
+ xfs_ifunlock(ip);
+@@ -2227,7 +2231,9 @@ xfs_ifree_cluster(
+
+ if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
+ if (xfs_iflock_nowait(ip)) {
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags |= XFS_ISTALE;
++ spin_unlock(&ip->i_flags_lock);
+
+ if (xfs_inode_clean(ip)) {
+ xfs_ifunlock(ip);
+@@ -2257,7 +2263,9 @@ xfs_ifree_cluster(
+ AIL_LOCK(mp,s);
+ iip->ili_flush_lsn = iip->ili_item.li_lsn;
+ AIL_UNLOCK(mp, s);
++ spin_lock(&iip->ili_inode->i_flags_lock);
+ iip->ili_inode->i_flags |= XFS_ISTALE;
++ spin_unlock(&iip->ili_inode->i_flags_lock);
+ pre_flushed++;
+ }
+ lip = lip->li_bio_list;
+@@ -2753,19 +2761,29 @@ xfs_iunpin(
+ * call as the inode reclaim may be blocked waiting for
+ * the inode to become unpinned.
+ */
++ struct inode *inode = NULL;
++
++ spin_lock(&ip->i_flags_lock);
+ if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) {
+ bhv_vnode_t *vp = XFS_ITOV_NULL(ip);
+
+ /* make sync come back and flush this inode */
+ if (vp) {
+- struct inode *inode = vn_to_inode(vp);
++ inode = vn_to_inode(vp);
+
+ if (!(inode->i_state &
+- (I_NEW|I_FREEING|I_CLEAR)))
+- mark_inode_dirty_sync(inode);
++ (I_NEW|I_FREEING|I_CLEAR))) {
++ inode = igrab(inode);
++ if (inode)
++ mark_inode_dirty_sync(inode);
++ } else
++ inode = NULL;
+ }
+ }
++ spin_unlock(&ip->i_flags_lock);
+ wake_up(&ip->i_ipin_wait);
++ if (inode)
++ iput(inode);
+ }
+ }
+
+diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
+index d10b76e..e96eb08 100644
+--- a/fs/xfs/xfs_inode.h
++++ b/fs/xfs/xfs_inode.h
+@@ -267,6 +267,7 @@ typedef struct xfs_inode {
+ sema_t i_flock; /* inode flush lock */
+ atomic_t i_pincount; /* inode pin count */
+ wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */
++ spinlock_t i_flags_lock; /* inode i_flags lock */
+ #ifdef HAVE_REFCACHE
+ struct xfs_inode **i_refcache; /* ptr to entry in ref cache */
+ struct xfs_inode *i_release; /* inode to unref */
+@@ -389,11 +390,14 @@ typedef struct xfs_inode {
+ (((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & S_ISGID))
+
+ /*
+- * xfs_iget.c prototypes.
++ * Flags for xfs_iget()
+ */
++#define XFS_IGET_CREATE 0x1
++#define XFS_IGET_BULKSTAT 0x2
+
+-#define IGET_CREATE 1
+-
++/*
++ * xfs_iget.c prototypes.
++ */
+ void xfs_ihash_init(struct xfs_mount *);
+ void xfs_ihash_free(struct xfs_mount *);
+ void xfs_chash_init(struct xfs_mount *);
+@@ -425,7 +429,7 @@ int xfs_itobp(struct xfs_mount *, struc
+ xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **,
+ xfs_daddr_t, uint);
+ int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
+- xfs_inode_t **, xfs_daddr_t);
++ xfs_inode_t **, xfs_daddr_t, uint);
+ int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
+ int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t,
+ xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t,
+diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
+index f8e80d8..a7a9225 100644
+--- a/fs/xfs/xfs_inode_item.c
++++ b/fs/xfs/xfs_inode_item.c
+@@ -743,21 +743,6 @@ xfs_inode_item_committed(
+ }
+
+ /*
+- * The transaction with the inode locked has aborted. The inode
+- * must not be dirty within the transaction (unless we're forcibly
+- * shutting down). We simply unlock just as if the transaction
+- * had been cancelled.
+- */
+-STATIC void
+-xfs_inode_item_abort(
+- xfs_inode_log_item_t *iip)
+-{
+- xfs_inode_item_unlock(iip);
+- return;
+-}
+-
+-
+-/*
+ * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK
+ * failed to get the inode flush lock but did get the inode locked SHARED.
+ * Here we're trying to see if the inode buffer is incore, and if so whether it's
+@@ -915,7 +900,6 @@ STATIC struct xfs_item_ops xfs_inode_ite
+ .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_inode_item_committed,
+ .iop_push = (void(*)(xfs_log_item_t*))xfs_inode_item_push,
+- .iop_abort = (void(*)(xfs_log_item_t*))xfs_inode_item_abort,
+ .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf,
+ .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+ xfs_inode_item_committing
+diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
+index 5db6cd1..bfe92ea 100644
+--- a/fs/xfs/xfs_inode_item.h
++++ b/fs/xfs/xfs_inode_item.h
+@@ -25,52 +25,54 @@
+ * must be added on to the end.
+ */
+ typedef struct xfs_inode_log_format {
+- unsigned short ilf_type; /* inode log item type */
+- unsigned short ilf_size; /* size of this item */
+- uint ilf_fields; /* flags for fields logged */
+- ushort ilf_asize; /* size of attr d/ext/root */
+- ushort ilf_dsize; /* size of data/ext/root */
+- xfs_ino_t ilf_ino; /* inode number */
++ __uint16_t ilf_type; /* inode log item type */
++ __uint16_t ilf_size; /* size of this item */
++ __uint32_t ilf_fields; /* flags for fields logged */
++ __uint16_t ilf_asize; /* size of attr d/ext/root */
++ __uint16_t ilf_dsize; /* size of data/ext/root */
++ __uint64_t ilf_ino; /* inode number */
+ union {
+- xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/
++ __uint32_t ilfu_rdev; /* rdev value for dev inode*/
+ uuid_t ilfu_uuid; /* mount point value */
+ } ilf_u;
+ __int64_t ilf_blkno; /* blkno of inode buffer */
+- int ilf_len; /* len of inode buffer */
+- int ilf_boffset; /* off of inode in buffer */
++ __int32_t ilf_len; /* len of inode buffer */
++ __int32_t ilf_boffset; /* off of inode in buffer */
+ } xfs_inode_log_format_t;
+
++#ifndef HAVE_FORMAT32
+ typedef struct xfs_inode_log_format_32 {
+- unsigned short ilf_type; /* 16: inode log item type */
+- unsigned short ilf_size; /* 16: size of this item */
+- uint ilf_fields; /* 32: flags for fields logged */
+- ushort ilf_asize; /* 32: size of attr d/ext/root */
+- ushort ilf_dsize; /* 32: size of data/ext/root */
+- xfs_ino_t ilf_ino; /* 64: inode number */
++ __uint16_t ilf_type; /* inode log item type */
++ __uint16_t ilf_size; /* size of this item */
++ __uint32_t ilf_fields; /* flags for fields logged */
++ __uint16_t ilf_asize; /* size of attr d/ext/root */
++ __uint16_t ilf_dsize; /* size of data/ext/root */
++ __uint64_t ilf_ino; /* inode number */
+ union {
+- xfs_dev_t ilfu_rdev; /* 32: rdev value for dev inode*/
+- uuid_t ilfu_uuid; /* 128: mount point value */
++ __uint32_t ilfu_rdev; /* rdev value for dev inode*/
++ uuid_t ilfu_uuid; /* mount point value */
+ } ilf_u;
+- __int64_t ilf_blkno; /* 64: blkno of inode buffer */
+- int ilf_len; /* 32: len of inode buffer */
+- int ilf_boffset; /* 32: off of inode in buffer */
++ __int64_t ilf_blkno; /* blkno of inode buffer */
++ __int32_t ilf_len; /* len of inode buffer */
++ __int32_t ilf_boffset; /* off of inode in buffer */
+ } __attribute__((packed)) xfs_inode_log_format_32_t;
++#endif
+
+ typedef struct xfs_inode_log_format_64 {
+- unsigned short ilf_type; /* 16: inode log item type */
+- unsigned short ilf_size; /* 16: size of this item */
+- uint ilf_fields; /* 32: flags for fields logged */
+- ushort ilf_asize; /* 32: size of attr d/ext/root */
+- ushort ilf_dsize; /* 32: size of data/ext/root */
+- __uint32_t ilf_pad; /* 32: pad for 64 bit boundary */
+- xfs_ino_t ilf_ino; /* 64: inode number */
++ __uint16_t ilf_type; /* inode log item type */
++ __uint16_t ilf_size; /* size of this item */
++ __uint32_t ilf_fields; /* flags for fields logged */
++ __uint16_t ilf_asize; /* size of attr d/ext/root */
++ __uint16_t ilf_dsize; /* size of data/ext/root */
++ __uint32_t ilf_pad; /* pad for 64 bit boundary */
++ __uint64_t ilf_ino; /* inode number */
+ union {
+- xfs_dev_t ilfu_rdev; /* 32: rdev value for dev inode*/
+- uuid_t ilfu_uuid; /* 128: mount point value */
++ __uint32_t ilfu_rdev; /* rdev value for dev inode*/
++ uuid_t ilfu_uuid; /* mount point value */
+ } ilf_u;
+- __int64_t ilf_blkno; /* 64: blkno of inode buffer */
+- int ilf_len; /* 32: len of inode buffer */
+- int ilf_boffset; /* 32: off of inode in buffer */
++ __int64_t ilf_blkno; /* blkno of inode buffer */
++ __int32_t ilf_len; /* len of inode buffer */
++ __int32_t ilf_boffset; /* off of inode in buffer */
+ } xfs_inode_log_format_64_t;
+
+ /*
+diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
+index f1949c1..1965512 100644
+--- a/fs/xfs/xfs_iomap.c
++++ b/fs/xfs/xfs_iomap.c
+@@ -398,6 +398,23 @@ xfs_flush_space(
+ return 1;
+ }
+
++STATIC int
++xfs_cmn_err_fsblock_zero(
++ xfs_inode_t *ip,
++ xfs_bmbt_irec_t *imap)
++{
++ xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
++ "Access to block zero in inode %llu "
++ "start_block: %llx start_off: %llx "
++ "blkcnt: %llx extent-state: %x\n",
++ (unsigned long long)ip->i_ino,
++ (unsigned long long)imap->br_startblock,
++ (unsigned long long)imap->br_startoff,
++ (unsigned long long)imap->br_blockcount,
++ imap->br_state);
++ return EFSCORRUPTED;
++}
++
+ int
+ xfs_iomap_write_direct(
+ xfs_inode_t *ip,
+@@ -536,23 +553,17 @@ xfs_iomap_write_direct(
+ * Copy any maps to caller's array and return any error.
+ */
+ if (nimaps == 0) {
+- error = (ENOSPC);
++ error = ENOSPC;
++ goto error_out;
++ }
++
++ if (unlikely(!imap.br_startblock && !(io->io_flags & XFS_IOCORE_RT))) {
++ error = xfs_cmn_err_fsblock_zero(ip, &imap);
+ goto error_out;
+ }
+
+ *ret_imap = imap;
+ *nmaps = 1;
+- if ( !(io->io_flags & XFS_IOCORE_RT) && !ret_imap->br_startblock) {
+- cmn_err(CE_PANIC,"Access to block zero: fs <%s> inode: %lld "
+- "start_block : %llx start_off : %llx blkcnt : %llx "
+- "extent-state : %x \n",
+- (ip->i_mount)->m_fsname,
+- (long long)ip->i_ino,
+- (unsigned long long)ret_imap->br_startblock,
+- (unsigned long long)ret_imap->br_startoff,
+- (unsigned long long)ret_imap->br_blockcount,
+- ret_imap->br_state);
+- }
+ return 0;
+
+ error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
+@@ -715,17 +726,8 @@ retry:
+ goto retry;
+ }
+
+- if (!(io->io_flags & XFS_IOCORE_RT) && !ret_imap->br_startblock) {
+- cmn_err(CE_PANIC,"Access to block zero: fs <%s> inode: %lld "
+- "start_block : %llx start_off : %llx blkcnt : %llx "
+- "extent-state : %x \n",
+- (ip->i_mount)->m_fsname,
+- (long long)ip->i_ino,
+- (unsigned long long)ret_imap->br_startblock,
+- (unsigned long long)ret_imap->br_startoff,
+- (unsigned long long)ret_imap->br_blockcount,
+- ret_imap->br_state);
+- }
++ if (unlikely(!imap[0].br_startblock && !(io->io_flags & XFS_IOCORE_RT)))
++ return xfs_cmn_err_fsblock_zero(ip, &imap[0]);
+
+ *ret_imap = imap[0];
+ *nmaps = 1;
+@@ -853,24 +855,10 @@ xfs_iomap_write_allocate(
+ * See if we were able to allocate an extent that
+ * covers at least part of the callers request
+ */
+-
+ for (i = 0; i < nimaps; i++) {
+- if (!(io->io_flags & XFS_IOCORE_RT) &&
+- !imap[i].br_startblock) {
+- cmn_err(CE_PANIC,"Access to block zero: "
+- "fs <%s> inode: %lld "
+- "start_block : %llx start_off : %llx "
+- "blkcnt : %llx extent-state : %x \n",
+- (ip->i_mount)->m_fsname,
+- (long long)ip->i_ino,
+- (unsigned long long)
+- imap[i].br_startblock,
+- (unsigned long long)
+- imap[i].br_startoff,
+- (unsigned long long)
+- imap[i].br_blockcount,
+- imap[i].br_state);
+- }
++ if (unlikely(!imap[i].br_startblock &&
++ !(io->io_flags & XFS_IOCORE_RT)))
++ return xfs_cmn_err_fsblock_zero(ip, &imap[i]);
+ if ((offset_fsb >= imap[i].br_startoff) &&
+ (offset_fsb < (imap[i].br_startoff +
+ imap[i].br_blockcount))) {
+@@ -941,7 +929,7 @@ xfs_iomap_write_unwritten(
+ XFS_WRITE_LOG_COUNT);
+ if (error) {
+ xfs_trans_cancel(tp, 0);
+- goto error0;
++ return XFS_ERROR(error);
+ }
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+@@ -967,19 +955,11 @@ xfs_iomap_write_unwritten(
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ if (error)
+- goto error0;
+-
+- if ( !(io->io_flags & XFS_IOCORE_RT) && !imap.br_startblock) {
+- cmn_err(CE_PANIC,"Access to block zero: fs <%s> "
+- "inode: %lld start_block : %llx start_off : "
+- "%llx blkcnt : %llx extent-state : %x \n",
+- (ip->i_mount)->m_fsname,
+- (long long)ip->i_ino,
+- (unsigned long long)imap.br_startblock,
+- (unsigned long long)imap.br_startoff,
+- (unsigned long long)imap.br_blockcount,
+- imap.br_state);
+- }
++ return XFS_ERROR(error);
++
++ if (unlikely(!imap.br_startblock &&
++ !(io->io_flags & XFS_IOCORE_RT)))
++ return xfs_cmn_err_fsblock_zero(ip, &imap);
+
+ if ((numblks_fsb = imap.br_blockcount) == 0) {
+ /*
+@@ -999,6 +979,5 @@ error_on_bmapi_transaction:
+ xfs_bmap_cancel(&free_list);
+ xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT));
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+-error0:
+ return XFS_ERROR(error);
+ }
+diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
+index 46249e4..7775ddc 100644
+--- a/fs/xfs/xfs_itable.c
++++ b/fs/xfs/xfs_itable.c
+@@ -39,6 +39,16 @@
+ #include "xfs_error.h"
+ #include "xfs_btree.h"
+
++int
++xfs_internal_inum(
++ xfs_mount_t *mp,
++ xfs_ino_t ino)
++{
++ return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
++ (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
++ (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
++}
++
+ STATIC int
+ xfs_bulkstat_one_iget(
+ xfs_mount_t *mp, /* mount point for filesystem */
+@@ -52,7 +62,8 @@ xfs_bulkstat_one_iget(
+ bhv_vnode_t *vp;
+ int error;
+
+- error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
++ error = xfs_iget(mp, NULL, ino,
++ XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);
+ if (error) {
+ *stat = BULKSTAT_RV_NOTHING;
+ return error;
+@@ -212,17 +223,12 @@ xfs_bulkstat_one(
+ xfs_dinode_t *dip; /* dinode inode pointer */
+
+ dip = (xfs_dinode_t *)dibuff;
++ *stat = BULKSTAT_RV_NOTHING;
+
+- if (!buffer || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
+- (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
+- (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) {
+- *stat = BULKSTAT_RV_NOTHING;
++ if (!buffer || xfs_internal_inum(mp, ino))
+ return XFS_ERROR(EINVAL);
+- }
+- if (ubsize < sizeof(*buf)) {
+- *stat = BULKSTAT_RV_NOTHING;
++ if (ubsize < sizeof(*buf))
+ return XFS_ERROR(ENOMEM);
+- }
+
+ buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
+
+@@ -238,8 +244,7 @@ xfs_bulkstat_one(
+ }
+
+ if (copy_to_user(buffer, buf, sizeof(*buf))) {
+- *stat = BULKSTAT_RV_NOTHING;
+- error = EFAULT;
++ error = EFAULT;
+ goto out_free;
+ }
+
+@@ -253,6 +258,46 @@ xfs_bulkstat_one(
+ }
+
+ /*
++ * Test to see whether we can use the ondisk inode directly, based
++ * on the given bulkstat flags, filling in dipp accordingly.
++ * Returns zero if the inode is dodgey.
++ */
++STATIC int
++xfs_bulkstat_use_dinode(
++ xfs_mount_t *mp,
++ int flags,
++ xfs_buf_t *bp,
++ int clustidx,
++ xfs_dinode_t **dipp)
++{
++ xfs_dinode_t *dip;
++ unsigned int aformat;
++
++ *dipp = NULL;
++ if (!bp || (flags & BULKSTAT_FG_IGET))
++ return 1;
++ dip = (xfs_dinode_t *)
++ xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog);
++ if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC ||
++ !XFS_DINODE_GOOD_VERSION(
++ INT_GET(dip->di_core.di_version, ARCH_CONVERT)))
++ return 0;
++ if (flags & BULKSTAT_FG_QUICK) {
++ *dipp = dip;
++ return 1;
++ }
++ /* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */
++ aformat = INT_GET(dip->di_core.di_aformat, ARCH_CONVERT);
++ if ((XFS_CFORK_Q(&dip->di_core) == 0) ||
++ (aformat == XFS_DINODE_FMT_LOCAL) ||
++ (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) {
++ *dipp = dip;
++ return 1;
++ }
++ return 1;
++}
++
++/*
+ * Return stat information in bulk (by-inode) for the filesystem.
+ */
+ int /* error status */
+@@ -284,10 +329,11 @@ xfs_bulkstat(
+ xfs_agino_t gino; /* current btree rec's start inode */
+ int i; /* loop index */
+ int icount; /* count of inodes good in irbuf */
++ size_t irbsize; /* size of irec buffer in bytes */
+ xfs_ino_t ino; /* inode number (filesystem) */
+- xfs_inobt_rec_t *irbp; /* current irec buffer pointer */
+- xfs_inobt_rec_t *irbuf; /* start of irec buffer */
+- xfs_inobt_rec_t *irbufend; /* end of good irec buffer entries */
++ xfs_inobt_rec_incore_t *irbp; /* current irec buffer pointer */
++ xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */
++ xfs_inobt_rec_incore_t *irbufend; /* end of good irec buffer entries */
+ xfs_ino_t lastino=0; /* last inode number returned */
+ int nbcluster; /* # of blocks in a cluster */
+ int nicluster; /* # of inodes in a cluster */
+@@ -328,13 +374,10 @@ xfs_bulkstat(
+ (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
+ nimask = ~(nicluster - 1);
+ nbcluster = nicluster >> mp->m_sb.sb_inopblog;
+- /*
+- * Allocate a page-sized buffer for inode btree records.
+- * We could try allocating something smaller, but for normal
+- * calls we'll always (potentially) need the whole page.
+- */
+- irbuf = kmem_alloc(NBPC, KM_SLEEP);
+- nirbuf = NBPC / sizeof(*irbuf);
++ irbuf = kmem_zalloc_greedy(&irbsize, NBPC, NBPC * 4,
++ KM_SLEEP | KM_MAYFAIL | KM_LARGE);
++ nirbuf = irbsize / sizeof(*irbuf);
++
+ /*
+ * Loop over the allocation groups, starting from the last
+ * inode returned; 0 means start of the allocation group.
+@@ -358,7 +401,7 @@ xfs_bulkstat(
+ * Allocate and initialize a btree cursor for ialloc btree.
+ */
+ cur = xfs_btree_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_INO,
+- (xfs_inode_t *)0, 0);
++ (xfs_inode_t *)0, 0);
+ irbp = irbuf;
+ irbufend = irbuf + nirbuf;
+ end_of_ag = 0;
+@@ -395,9 +438,9 @@ xfs_bulkstat(
+ gcnt++;
+ }
+ gfree |= XFS_INOBT_MASKN(0, chunkidx);
+- INT_SET(irbp->ir_startino, ARCH_CONVERT, gino);
+- INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt);
+- INT_SET(irbp->ir_free, ARCH_CONVERT, gfree);
++ irbp->ir_startino = gino;
++ irbp->ir_freecount = gcnt;
++ irbp->ir_free = gfree;
+ irbp++;
+ agino = gino + XFS_INODES_PER_CHUNK;
+ icount = XFS_INODES_PER_CHUNK - gcnt;
+@@ -451,11 +494,27 @@ xfs_bulkstat(
+ }
+ /*
+ * If this chunk has any allocated inodes, save it.
++ * Also start read-ahead now for this chunk.
+ */
+ if (gcnt < XFS_INODES_PER_CHUNK) {
+- INT_SET(irbp->ir_startino, ARCH_CONVERT, gino);
+- INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt);
+- INT_SET(irbp->ir_free, ARCH_CONVERT, gfree);
++ /*
++ * Loop over all clusters in the next chunk.
++ * Do a readahead if there are any allocated
++ * inodes in that cluster.
++ */
++ for (agbno = XFS_AGINO_TO_AGBNO(mp, gino),
++ chunkidx = 0;
++ chunkidx < XFS_INODES_PER_CHUNK;
++ chunkidx += nicluster,
++ agbno += nbcluster) {
++ if (XFS_INOBT_MASKN(chunkidx,
++ nicluster) & ~gfree)
++ xfs_btree_reada_bufs(mp, agno,
++ agbno, nbcluster);
++ }
++ irbp->ir_startino = gino;
++ irbp->ir_freecount = gcnt;
++ irbp->ir_free = gfree;
+ irbp++;
+ icount += XFS_INODES_PER_CHUNK - gcnt;
+ }
+@@ -479,33 +538,11 @@ xfs_bulkstat(
+ for (irbp = irbuf;
+ irbp < irbufend && ubleft >= statstruct_size; irbp++) {
+ /*
+- * Read-ahead the next chunk's worth of inodes.
+- */
+- if (&irbp[1] < irbufend) {
+- /*
+- * Loop over all clusters in the next chunk.
+- * Do a readahead if there are any allocated
+- * inodes in that cluster.
+- */
+- for (agbno = XFS_AGINO_TO_AGBNO(mp,
+- INT_GET(irbp[1].ir_startino, ARCH_CONVERT)),
+- chunkidx = 0;
+- chunkidx < XFS_INODES_PER_CHUNK;
+- chunkidx += nicluster,
+- agbno += nbcluster) {
+- if (XFS_INOBT_MASKN(chunkidx,
+- nicluster) &
+- ~(INT_GET(irbp[1].ir_free, ARCH_CONVERT)))
+- xfs_btree_reada_bufs(mp, agno,
+- agbno, nbcluster);
+- }
+- }
+- /*
+ * Now process this chunk of inodes.
+ */
+- for (agino = INT_GET(irbp->ir_startino, ARCH_CONVERT), chunkidx = 0, clustidx = 0;
++ for (agino = irbp->ir_startino, chunkidx = clustidx = 0;
+ ubleft > 0 &&
+- INT_GET(irbp->ir_freecount, ARCH_CONVERT) < XFS_INODES_PER_CHUNK;
++ irbp->ir_freecount < XFS_INODES_PER_CHUNK;
+ chunkidx++, clustidx++, agino++) {
+ ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
+ /*
+@@ -525,11 +562,12 @@ xfs_bulkstat(
+ */
+ if ((chunkidx & (nicluster - 1)) == 0) {
+ agbno = XFS_AGINO_TO_AGBNO(mp,
+- INT_GET(irbp->ir_startino, ARCH_CONVERT)) +
++ irbp->ir_startino) +
+ ((chunkidx & nimask) >>
+ mp->m_sb.sb_inopblog);
+
+- if (flags & BULKSTAT_FG_QUICK) {
++ if (flags & (BULKSTAT_FG_QUICK |
++ BULKSTAT_FG_INLINE)) {
+ ino = XFS_AGINO_TO_INO(mp, agno,
+ agino);
+ bno = XFS_AGB_TO_DADDR(mp, agno,
+@@ -543,6 +581,7 @@ xfs_bulkstat(
+ KM_SLEEP);
+ ip->i_ino = ino;
+ ip->i_mount = mp;
++ spin_lock_init(&ip->i_flags_lock);
+ if (bp)
+ xfs_buf_relse(bp);
+ error = xfs_itobp(mp, NULL, ip,
+@@ -564,30 +603,34 @@ xfs_bulkstat(
+ /*
+ * Skip if this inode is free.
+ */
+- if (XFS_INOBT_MASK(chunkidx) & INT_GET(irbp->ir_free, ARCH_CONVERT))
++ if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free)
+ continue;
+ /*
+ * Count used inodes as free so we can tell
+ * when the chunk is used up.
+ */
+- INT_MOD(irbp->ir_freecount, ARCH_CONVERT, +1);
++ irbp->ir_freecount++;
+ ino = XFS_AGINO_TO_INO(mp, agno, agino);
+ bno = XFS_AGB_TO_DADDR(mp, agno, agbno);
+- if (flags & BULKSTAT_FG_QUICK) {
+- dip = (xfs_dinode_t *)xfs_buf_offset(bp,
+- (clustidx << mp->m_sb.sb_inodelog));
+-
+- if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT)
+- != XFS_DINODE_MAGIC
+- || !XFS_DINODE_GOOD_VERSION(
+- INT_GET(dip->di_core.di_version, ARCH_CONVERT)))
+- continue;
++ if (!xfs_bulkstat_use_dinode(mp, flags, bp,
++ clustidx, &dip))
++ continue;
++ /*
++ * If we need to do an iget, cannot hold bp.
++ * Drop it, until starting the next cluster.
++ */
++ if ((flags & BULKSTAT_FG_INLINE) && !dip) {
++ if (bp)
++ xfs_buf_relse(bp);
++ bp = NULL;
+ }
+
+ /*
+ * Get the inode and fill in a single buffer.
+ * BULKSTAT_FG_QUICK uses dip to fill it in.
+ * BULKSTAT_FG_IGET uses igets.
++ * BULKSTAT_FG_INLINE uses dip if we have an
++ * inline attr fork, else igets.
+ * See: xfs_bulkstat_one & xfs_dm_bulkstat_one.
+ * This is also used to count inodes/blks, etc
+ * in xfs_qm_quotacheck.
+@@ -597,8 +640,15 @@ xfs_bulkstat(
+ ubleft, private_data,
+ bno, &ubused, dip, &fmterror);
+ if (fmterror == BULKSTAT_RV_NOTHING) {
+- if (error == ENOMEM)
++ if (error == EFAULT) {
++ ubleft = 0;
++ rval = error;
++ break;
++ }
++ else if (error == ENOMEM)
+ ubleft = 0;
++ else
++ lastino = ino;
+ continue;
+ }
+ if (fmterror == BULKSTAT_RV_GIVEUP) {
+@@ -633,7 +683,7 @@ xfs_bulkstat(
+ /*
+ * Done, we're either out of filesystem or space to put the data.
+ */
+- kmem_free(irbuf, NBPC);
++ kmem_free(irbuf, irbsize);
+ *ubcountp = ubelem;
+ if (agno >= mp->m_sb.sb_agcount) {
+ /*
+diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
+index be5f12e..f25a288 100644
+--- a/fs/xfs/xfs_itable.h
++++ b/fs/xfs/xfs_itable.h
+@@ -36,15 +36,16 @@ typedef int (*bulkstat_one_pf)(struct xf
+ /*
+ * Values for stat return value.
+ */
+-#define BULKSTAT_RV_NOTHING 0
+-#define BULKSTAT_RV_DIDONE 1
+-#define BULKSTAT_RV_GIVEUP 2
++#define BULKSTAT_RV_NOTHING 0
++#define BULKSTAT_RV_DIDONE 1
++#define BULKSTAT_RV_GIVEUP 2
+
+ /*
+ * Values for bulkstat flag argument.
+ */
+-#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */
+-#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */
++#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */
++#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */
++#define BULKSTAT_FG_INLINE 0x4 /* No iget if inline attrs */
+
+ /*
+ * Return stat information in bulk (by-inode) for the filesystem.
+@@ -80,6 +81,11 @@ xfs_bulkstat_one(
+ void *dibuff,
+ int *stat);
+
++int
++xfs_internal_inum(
++ xfs_mount_t *mp,
++ xfs_ino_t ino);
++
+ int /* error status */
+ xfs_inumbers(
+ xfs_mount_t *mp, /* mount point for filesystem */
+diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
+index 21ac1a6..c48bf61 100644
+--- a/fs/xfs/xfs_log.c
++++ b/fs/xfs/xfs_log.c
+@@ -617,7 +617,8 @@ xfs_log_unmount_write(xfs_mount_t *mp)
+ reg[0].i_len = sizeof(magic);
+ XLOG_VEC_SET_TYPE(®[0], XLOG_REG_TYPE_UNMOUNT);
+
+- error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0, 0);
++ error = xfs_log_reserve(mp, 600, 1, &tic,
++ XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE);
+ if (!error) {
+ /* remove inited flag */
+ ((xlog_ticket_t *)tic)->t_flags = 0;
+@@ -655,8 +656,11 @@ xfs_log_unmount_write(xfs_mount_t *mp)
+ } else {
+ LOG_UNLOCK(log, s);
+ }
+- if (tic)
++ if (tic) {
++ xlog_trace_loggrant(log, tic, "unmount rec");
++ xlog_ungrant_log_space(log, tic);
+ xlog_state_put_ticket(log, tic);
++ }
+ } else {
+ /*
+ * We're already in forced_shutdown mode, couldn't
+@@ -1196,7 +1200,7 @@ xlog_alloc_log(xfs_mount_t *mp,
+ kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP);
+ iclog = *iclogp;
+ iclog->hic_data = (xlog_in_core_2_t *)
+- kmem_zalloc(iclogsize, KM_SLEEP);
++ kmem_zalloc(iclogsize, KM_SLEEP | KM_LARGE);
+
+ iclog->ic_prev = prev_iclog;
+ prev_iclog = iclog;
+@@ -2212,9 +2216,13 @@ xlog_state_do_callback(
+
+ iclog = iclog->ic_next;
+ } while (first_iclog != iclog);
+- if (repeats && (repeats % 10) == 0) {
++
++ if (repeats > 5000) {
++ flushcnt += repeats;
++ repeats = 0;
+ xfs_fs_cmn_err(CE_WARN, log->l_mp,
+- "xlog_state_do_callback: looping %d", repeats);
++ "%s: possible infinite loop (%d iterations)",
++ __FUNCTION__, flushcnt);
+ }
+ } while (!ioerrors && loopdidcallbacks);
+
+@@ -2246,6 +2254,7 @@ xlog_state_do_callback(
+ }
+ #endif
+
++ flushcnt = 0;
+ if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) {
+ flushcnt = log->l_flushcnt;
+ log->l_flushcnt = 0;
+diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
+index eacb3d4..ebbe93f 100644
+--- a/fs/xfs/xfs_log.h
++++ b/fs/xfs/xfs_log.h
+@@ -48,16 +48,10 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn
+ */
+
+ /*
+- * Flags to xfs_log_mount
+- */
+-#define XFS_LOG_RECOVER 0x1
+-
+-/*
+ * Flags to xfs_log_done()
+ */
+ #define XFS_LOG_REL_PERM_RESERV 0x1
+
+-
+ /*
+ * Flags to xfs_log_reserve()
+ *
+@@ -70,8 +64,6 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn
+ #define XFS_LOG_SLEEP 0x0
+ #define XFS_LOG_NOSLEEP 0x1
+ #define XFS_LOG_PERM_RESERV 0x2
+-#define XFS_LOG_RESV_ALL (XFS_LOG_NOSLEEP|XFS_LOG_PERM_RESERV)
+-
+
+ /*
+ * Flags to xfs_log_force()
+diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
+index 34bcbf5..9bd3cdf 100644
+--- a/fs/xfs/xfs_log_priv.h
++++ b/fs/xfs/xfs_log_priv.h
+@@ -32,7 +32,6 @@ struct xfs_mount;
+ #define XLOG_MIN_ICLOGS 2
+ #define XLOG_MED_ICLOGS 4
+ #define XLOG_MAX_ICLOGS 8
+-#define XLOG_CALLBACK_SIZE 10
+ #define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */
+ #define XLOG_VERSION_1 1
+ #define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */
+@@ -149,9 +148,6 @@ struct xfs_mount;
+ #define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */
+ #define XLOG_END_TRANS 0x10 /* End a continued transaction */
+ #define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */
+-#define XLOG_SKIP_TRANS (XLOG_COMMIT_TRANS | XLOG_CONTINUE_TRANS | \
+- XLOG_WAS_CONT_TRANS | XLOG_END_TRANS | \
+- XLOG_UNMOUNT_TRANS)
+
+ #ifdef __KERNEL__
+ /*
+@@ -506,6 +502,12 @@ extern int xlog_bread(xlog_t *, xfs_dad
+ #define XLOG_TRACE_SLEEP_FLUSH 3
+ #define XLOG_TRACE_WAKE_FLUSH 4
+
++/*
++ * Unmount record type is used as a pseudo transaction type for the ticket.
++ * It's value must be outside the range of XFS_TRANS_* values.
++ */
++#define XLOG_UNMOUNT_REC_TYPE (-1U)
++
+ #endif /* __KERNEL__ */
+
+ #endif /* __XFS_LOG_PRIV_H__ */
+diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
+index b2bd4be..e5f396f 100644
+--- a/fs/xfs/xfs_mount.h
++++ b/fs/xfs/xfs_mount.h
+@@ -331,7 +331,7 @@ typedef struct xfs_mount {
+ xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */
+ lock_t m_agirotor_lock;/* .. and lock protecting it */
+ xfs_agnumber_t m_maxagi; /* highest inode alloc group */
+- uint m_ihsize; /* size of next field */
++ size_t m_ihsize; /* size of next field */
+ struct xfs_ihash *m_ihash; /* fs private inode hash table*/
+ struct xfs_inode *m_inodes; /* active inode list */
+ struct list_head m_del_inodes; /* inodes to reclaim */
+@@ -541,7 +541,8 @@ static inline xfs_mount_t *xfs_bhvtom(bh
+ #define XFS_VFSTOM(vfs) xfs_vfstom(vfs)
+ static inline xfs_mount_t *xfs_vfstom(bhv_vfs_t *vfs)
+ {
+- return XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops));
++ return XFS_BHVTOM(bhv_lookup_range(VFS_BHVHEAD(vfs),
++ VFS_POSITION_XFS, VFS_POSITION_XFS));
+ }
+
+ #define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d)
+diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
+index acb853b..9dcb32a 100644
+--- a/fs/xfs/xfs_quota.h
++++ b/fs/xfs/xfs_quota.h
+@@ -281,8 +281,6 @@ typedef struct xfs_qoff_logformat {
+ XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
+ XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\
+ XFS_GQUOTA_ACCT)
+-#define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \
+- XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE)
+
+
+ /*
+diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
+index 5a0b678..880c732 100644
+--- a/fs/xfs/xfs_rtalloc.c
++++ b/fs/xfs/xfs_rtalloc.c
+@@ -1948,7 +1948,7 @@ xfs_growfs_rt(
+ */
+ nrextents = nrblocks;
+ do_div(nrextents, in->extsize);
+- nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize);
++ nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
+ nrextslog = xfs_highbit32(nrextents);
+ nrsumlevels = nrextslog + 1;
+ nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
+@@ -1976,7 +1976,10 @@ xfs_growfs_rt(
+ if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks,
+ mp->m_sb.sb_rsumino)))
+ return error;
+- nmp = NULL;
++ /*
++ * Allocate a new (fake) mount/sb.
++ */
++ nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);
+ /*
+ * Loop over the bitmap blocks.
+ * We will do everything one bitmap block at a time.
+@@ -1987,10 +1990,6 @@ xfs_growfs_rt(
+ ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
+ bmbno < nrbmblocks;
+ bmbno++) {
+- /*
+- * Allocate a new (fake) mount/sb.
+- */
+- nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);
+ *nmp = *mp;
+ nsbp = &nmp->m_sb;
+ /*
+@@ -2018,13 +2017,13 @@ xfs_growfs_rt(
+ cancelflags = 0;
+ if ((error = xfs_trans_reserve(tp, 0,
+ XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0)))
+- goto error_exit;
++ break;
+ /*
+ * Lock out other callers by grabbing the bitmap inode lock.
+ */
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
+- goto error_exit;
++ break;
+ ASSERT(ip == mp->m_rbmip);
+ /*
+ * Update the bitmap inode's size.
+@@ -2038,7 +2037,7 @@ xfs_growfs_rt(
+ */
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,
+ XFS_ILOCK_EXCL, &ip)))
+- goto error_exit;
++ break;
+ ASSERT(ip == mp->m_rsumip);
+ /*
+ * Update the summary inode's size.
+@@ -2053,7 +2052,7 @@ xfs_growfs_rt(
+ mp->m_rsumlevels != nmp->m_rsumlevels) {
+ error = xfs_rtcopy_summary(mp, nmp, tp);
+ if (error)
+- goto error_exit;
++ break;
+ }
+ /*
+ * Update superblock fields.
+@@ -2080,18 +2079,13 @@ xfs_growfs_rt(
+ error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
+ nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
+ if (error)
+- goto error_exit;
++ break;
+ /*
+ * Mark more blocks free in the superblock.
+ */
+ xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
+ nsbp->sb_rextents - sbp->sb_rextents);
+ /*
+- * Free the fake mp structure.
+- */
+- kmem_free(nmp, sizeof(*nmp));
+- nmp = NULL;
+- /*
+ * Update mp values into the real mp structure.
+ */
+ mp->m_rsumlevels = nrsumlevels;
+@@ -2101,15 +2095,15 @@ xfs_growfs_rt(
+ */
+ xfs_trans_commit(tp, 0, NULL);
+ }
+- return 0;
++
++ if (error)
++ xfs_trans_cancel(tp, cancelflags);
+
+ /*
+- * Error paths come here.
++ * Free the fake mp structure.
+ */
+-error_exit:
+- if (nmp)
+- kmem_free(nmp, sizeof(*nmp));
+- xfs_trans_cancel(tp, cancelflags);
++ kmem_free(nmp, sizeof(*nmp));
++
+ return error;
+ }
+
+diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
+index bf168a9..467854b 100644
+--- a/fs/xfs/xfs_sb.h
++++ b/fs/xfs/xfs_sb.h
+@@ -60,10 +60,6 @@ struct xfs_mount;
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+-#define XFS_SB_VERSION_OKSASHBITS \
+- (XFS_SB_VERSION_NUMBITS | \
+- XFS_SB_VERSION_REALFBITS | \
+- XFS_SB_VERSION_OKSASHFBITS)
+ #define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+@@ -81,9 +77,6 @@ struct xfs_mount;
+ #define XFS_SB_VERSION2_RESERVED2BIT 0x00000002
+ #define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
+ #define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+-#define XFS_SB_VERSION2_SASHFBITS 0xff000000 /* Mask: features that
+- require changing
+- PROM and SASH */
+
+ #define XFS_SB_VERSION2_OKREALFBITS \
+ (XFS_SB_VERSION2_ATTR2BIT)
+@@ -238,12 +231,6 @@ static inline int xfs_sb_good_version(xf
+ }
+ #endif /* __KERNEL__ */
+
+-#define XFS_SB_GOOD_SASH_VERSION(sbp) \
+- ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
+- ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
+- ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+- !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS)))
+-
+ #define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v)
+ static inline unsigned xfs_sb_version_tonew(unsigned v)
+ {
+@@ -461,15 +448,6 @@ static inline void xfs_sb_version_addatt
+ * File system sector to basic block conversions.
+ */
+ #define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
+-#define XFS_BB_TO_FSS(mp,bb) \
+- (((bb) + (XFS_FSS_TO_BB(mp,1) - 1)) >> (mp)->m_sectbb_log)
+-#define XFS_BB_TO_FSST(mp,bb) ((bb) >> (mp)->m_sectbb_log)
+-
+-/*
+- * File system sector to byte conversions.
+- */
+-#define XFS_FSS_TO_B(mp,sectno) ((xfs_fsize_t)(sectno) << (mp)->m_sb.sb_sectlog)
+-#define XFS_B_TO_FSST(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_sectlog)
+
+ /*
+ * File system block to basic block conversions.
+diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
+index 9dc88b3..c68e001 100644
+--- a/fs/xfs/xfs_trans.h
++++ b/fs/xfs/xfs_trans.h
+@@ -149,7 +149,6 @@ typedef struct xfs_item_ops {
+ void (*iop_unlock)(xfs_log_item_t *);
+ xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
+ void (*iop_push)(xfs_log_item_t *);
+- void (*iop_abort)(xfs_log_item_t *);
+ void (*iop_pushbuf)(xfs_log_item_t *);
+ void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
+ } xfs_item_ops_t;
+@@ -163,7 +162,6 @@ typedef struct xfs_item_ops {
+ #define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
+ #define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
+ #define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip)
+-#define IOP_ABORT(ip) (*(ip)->li_ops->iop_abort)(ip)
+ #define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip)
+ #define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
+
+diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
+index 558c87f..fc39b16 100644
+--- a/fs/xfs/xfs_trans_ail.c
++++ b/fs/xfs/xfs_trans_ail.c
+@@ -276,7 +276,7 @@ xfs_trans_update_ail(
+ xfs_mount_t *mp,
+ xfs_log_item_t *lip,
+ xfs_lsn_t lsn,
+- unsigned long s)
++ unsigned long s) __releases(mp->m_ail_lock)
+ {
+ xfs_ail_entry_t *ailp;
+ xfs_log_item_t *dlip=NULL;
+@@ -328,7 +328,7 @@ void
+ xfs_trans_delete_ail(
+ xfs_mount_t *mp,
+ xfs_log_item_t *lip,
+- unsigned long s)
++ unsigned long s) __releases(mp->m_ail_lock)
+ {
+ xfs_ail_entry_t *ailp;
+ xfs_log_item_t *dlip;
+diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
+index 13edab8..447ac43 100644
+--- a/fs/xfs/xfs_trans_priv.h
++++ b/fs/xfs/xfs_trans_priv.h
+@@ -46,11 +46,13 @@ xfs_log_busy_slot_t *xfs_trans_add_busy
+ /*
+ * From xfs_trans_ail.c
+ */
+-void xfs_trans_update_ail(struct xfs_mount *,
+- struct xfs_log_item *, xfs_lsn_t,
+- unsigned long);
+-void xfs_trans_delete_ail(struct xfs_mount *,
+- struct xfs_log_item *, unsigned long);
++void xfs_trans_update_ail(struct xfs_mount *mp,
++ struct xfs_log_item *lip, xfs_lsn_t lsn,
++ unsigned long s)
++ __releases(mp->m_ail_lock);
++void xfs_trans_delete_ail(struct xfs_mount *mp,
++ struct xfs_log_item *lip, unsigned long s)
++ __releases(mp->m_ail_lock);
+ struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *);
+ struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *,
+ struct xfs_log_item *, int *, int *);
+diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
+index a34796e..62336a4 100644
+--- a/fs/xfs/xfs_vfsops.c
++++ b/fs/xfs/xfs_vfsops.c
+@@ -1922,7 +1922,7 @@ xfs_showargs(
+ }
+
+ if (mp->m_flags & XFS_MOUNT_IHASHSIZE)
+- seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", mp->m_ihsize);
++ seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", (int)mp->m_ihsize);
+
+ if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
+ seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk",
+diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
+index 23cfa58..061e2ff 100644
+--- a/fs/xfs/xfs_vnodeops.c
++++ b/fs/xfs/xfs_vnodeops.c
+@@ -2366,10 +2366,15 @@ xfs_remove(
+
+ namelen = VNAMELEN(dentry);
+
++ if (!xfs_get_dir_entry(dentry, &ip)) {
++ dm_di_mode = ip->i_d.di_mode;
++ IRELE(ip);
++ }
++
+ if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
+ error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_vp,
+ DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
+- name, NULL, 0, 0, 0);
++ name, NULL, dm_di_mode, 0, 0);
+ if (error)
+ return error;
+ }
+@@ -2995,7 +3000,7 @@ xfs_rmdir(
+ int cancel_flags;
+ int committed;
+ bhv_vnode_t *dir_vp;
+- int dm_di_mode = 0;
++ int dm_di_mode = S_IFDIR;
+ int last_cdp_link;
+ int namelen;
+ uint resblks;
+@@ -3010,11 +3015,16 @@ xfs_rmdir(
+ return XFS_ERROR(EIO);
+ namelen = VNAMELEN(dentry);
+
++ if (!xfs_get_dir_entry(dentry, &cdp)) {
++ dm_di_mode = cdp->i_d.di_mode;
++ IRELE(cdp);
++ }
++
+ if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
+ error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
+ dir_vp, DM_RIGHT_NULL,
+ NULL, DM_RIGHT_NULL,
+- name, NULL, 0, 0, 0);
++ name, NULL, dm_di_mode, 0, 0);
+ if (error)
+ return XFS_ERROR(error);
+ }
+@@ -3834,7 +3844,9 @@ xfs_reclaim(
+ XFS_MOUNT_ILOCK(mp);
+ vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
+ list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
++ spin_lock(&ip->i_flags_lock);
+ ip->i_flags |= XFS_IRECLAIMABLE;
++ spin_unlock(&ip->i_flags_lock);
+ XFS_MOUNT_IUNLOCK(mp);
+ }
+ return 0;
+@@ -3859,8 +3871,10 @@ xfs_finish_reclaim(
+ * us.
+ */
+ write_lock(&ih->ih_lock);
++ spin_lock(&ip->i_flags_lock);
+ if ((ip->i_flags & XFS_IRECLAIM) ||
+ (!(ip->i_flags & XFS_IRECLAIMABLE) && vp == NULL)) {
++ spin_unlock(&ip->i_flags_lock);
+ write_unlock(&ih->ih_lock);
+ if (locked) {
+ xfs_ifunlock(ip);
+@@ -3869,6 +3883,7 @@ xfs_finish_reclaim(
+ return 1;
+ }
+ ip->i_flags |= XFS_IRECLAIM;
++ spin_unlock(&ip->i_flags_lock);
+ write_unlock(&ih->ih_lock);
+
+ /*
+@@ -4272,7 +4287,7 @@ xfs_free_file_space(
+ xfs_mount_t *mp;
+ int nimap;
+ uint resblks;
+- int rounding;
++ uint rounding;
+ int rt;
+ xfs_fileoff_t startoffset_fsb;
+ xfs_trans_t *tp;
+@@ -4313,8 +4328,7 @@ xfs_free_file_space(
+ vn_iowait(vp); /* wait for the completion of any pending DIOs */
+ }
+
+- rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog),
+- (__uint8_t)NBPP);
++ rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP);
+ ilen = len + (offset & (rounding - 1));
+ ioffset = offset & ~(rounding - 1);
+ if (ilen & (rounding - 1))
+diff --git a/include/Kbuild b/include/Kbuild
+index cb25348..2d03f99 100644
+--- a/include/Kbuild
++++ b/include/Kbuild
+@@ -1,2 +1,9 @@
+-header-y += asm-generic/ linux/ scsi/ sound/ mtd/ rdma/ video/
+-header-y += asm-$(ARCH)/
++header-y += asm-generic/
++header-y += linux/
++header-y += scsi/
++header-y += sound/
++header-y += mtd/
++header-y += rdma/
++header-y += video/
++
++header-y += asm-$(ARCH)/
+diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
+index a4d0e73..063c4b5 100644
+--- a/include/acpi/aclocal.h
++++ b/include/acpi/aclocal.h
+@@ -708,7 +708,7 @@ struct acpi_bit_register_info {
+ * must be preserved.
+ */
+ #define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */
+-#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0201 /* Bit 9, Bit 0 (SCI_EN) */
++#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0200 /* Bit 9 (whatever) */
+
+ /*
+ * Register IDs
+diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
+index c5472be..e72bfdd 100644
+--- a/include/acpi/pdc_intel.h
++++ b/include/acpi/pdc_intel.h
+@@ -13,6 +13,7 @@
+ #define ACPI_PDC_SMP_C_SWCOORD (0x0040)
+ #define ACPI_PDC_SMP_T_SWCOORD (0x0080)
+ #define ACPI_PDC_C_C1_FFH (0x0100)
++#define ACPI_PDC_C_C2C3_FFH (0x0200)
+
+ #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
+ ACPI_PDC_C_C1_HALT | \
+@@ -23,8 +24,10 @@
+ ACPI_PDC_SMP_P_SWCOORD | \
+ ACPI_PDC_P_FFH)
+
+-#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
+- ACPI_PDC_SMP_C1PT | \
+- ACPI_PDC_C_C1_HALT)
++#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
++ ACPI_PDC_SMP_C1PT | \
++ ACPI_PDC_C_C1_HALT | \
++ ACPI_PDC_C_C1_FFH | \
++ ACPI_PDC_C_C2C3_FFH)
+
+ #endif /* __PDC_INTEL_H__ */
+diff --git a/include/acpi/processor.h b/include/acpi/processor.h
+index 9dd5b75..7798d2a 100644
+--- a/include/acpi/processor.h
++++ b/include/acpi/processor.h
+@@ -29,6 +29,9 @@
+ #define DOMAIN_COORD_TYPE_SW_ANY 0xfd
+ #define DOMAIN_COORD_TYPE_HW_ALL 0xfe
+
++#define ACPI_CSTATE_SYSTEMIO (0)
++#define ACPI_CSTATE_FFH (1)
++
+ /* Power Management */
+
+ struct acpi_processor_cx;
+@@ -58,6 +61,8 @@ struct acpi_processor_cx {
+ u8 valid;
+ u8 type;
+ u32 address;
++ u8 space_id;
++ u8 index;
+ u32 latency;
+ u32 latency_ticks;
+ u32 power;
+@@ -206,6 +211,9 @@ void arch_acpi_processor_init_pdc(struct
+ #ifdef ARCH_HAS_POWER_INIT
+ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
+ unsigned int cpu);
++int acpi_processor_ffh_cstate_probe(unsigned int cpu,
++ struct acpi_processor_cx *cx, struct acpi_power_register *reg);
++void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
+ #else
+ static inline void acpi_processor_power_init_bm_check(struct
+ acpi_processor_flags
+@@ -214,6 +222,16 @@ static inline void acpi_processor_power_
+ flags->bm_check = 1;
+ return;
+ }
++static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
++ struct acpi_processor_cx *cx, struct acpi_power_register *reg)
++{
++ return -1;
++}
++static inline void acpi_processor_ffh_cstate_enter(
++ struct acpi_processor_cx *cstate)
++{
++ return;
++}
+ #endif
+
+ /* in processor_perflib.c */
+diff --git a/include/asm-alpha/Kbuild b/include/asm-alpha/Kbuild
+index 2b06b3b..b7c8f18 100644
+--- a/include/asm-alpha/Kbuild
++++ b/include/asm-alpha/Kbuild
+@@ -1,5 +1,11 @@
+ include include/asm-generic/Kbuild.asm
+
+-unifdef-y += console.h fpu.h sysinfo.h compiler.h
++header-y += gentrap.h
++header-y += regdef.h
++header-y += pal.h
++header-y += reg.h
+
+-header-y += gentrap.h regdef.h pal.h reg.h
++unifdef-y += console.h
++unifdef-y += fpu.h
++unifdef-y += sysinfo.h
++unifdef-y += compiler.h
+diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
+index f5ae98c..5d15af2 100644
+--- a/include/asm-alpha/io.h
++++ b/include/asm-alpha/io.h
+@@ -533,19 +533,6 @@ extern void outsl (unsigned long port, c
+ #define eth_io_copy_and_sum(skb,src,len,unused) \
+ memcpy_fromio((skb)->data,src,len)
+
+-static inline int
+-check_signature(const volatile void __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- do {
+- if (readb(io_addr) != *signature)
+- return 0;
+- io_addr++;
+- signature++;
+- } while (--length);
+- return 1;
+-}
+-
+ /*
+ * The Alpha Jensen hardware for some rather strange reason puts
+ * the RTC clock at 0x170 instead of 0x70. Probably due to some
+diff --git a/include/asm-alpha/irq_regs.h b/include/asm-alpha/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-alpha/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-alpha/machvec.h b/include/asm-alpha/machvec.h
+index aced22f..a86c083 100644
+--- a/include/asm-alpha/machvec.h
++++ b/include/asm-alpha/machvec.h
+@@ -15,7 +15,6 @@
+
+ struct task_struct;
+ struct mm_struct;
+-struct pt_regs;
+ struct vm_area_struct;
+ struct linux_hose_info;
+ struct pci_dev;
+@@ -79,8 +78,8 @@ struct alpha_machine_vector
+
+ void (*update_irq_hw)(unsigned long, unsigned long, int);
+ void (*ack_irq)(unsigned long);
+- void (*device_interrupt)(unsigned long vector, struct pt_regs *regs);
+- void (*machine_check)(u64 vector, u64 la, struct pt_regs *regs);
++ void (*device_interrupt)(unsigned long vector);
++ void (*machine_check)(u64 vector, u64 la);
+
+ void (*smp_callin)(void);
+ void (*init_arch)(void);
+diff --git a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h
+index 64d0ab9..8af56ce 100644
+--- a/include/asm-alpha/mmzone.h
++++ b/include/asm-alpha/mmzone.h
+@@ -75,6 +75,7 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p,
+ #define VALID_PAGE(page) (((page) - mem_map) < max_mapnr)
+
+ #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> 32))
++#define pgd_page(pgd) (pfn_to_page(pgd_val(pgd) >> 32))
+ #define pte_pfn(pte) (pte_val(pte) >> 32)
+
+ #define mk_pte(page, pgprot) \
+diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
+index 93eaa58..49ac9be 100644
+--- a/include/asm-alpha/pgtable.h
++++ b/include/asm-alpha/pgtable.h
+@@ -230,16 +230,17 @@ extern inline void pgd_set(pgd_t * pgdp,
+
+
+ extern inline unsigned long
+-pmd_page_kernel(pmd_t pmd)
++pmd_page_vaddr(pmd_t pmd)
+ {
+ return ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT)) + PAGE_OFFSET;
+ }
+
+ #ifndef CONFIG_DISCONTIGMEM
+ #define pmd_page(pmd) (mem_map + ((pmd_val(pmd) & _PFN_MASK) >> 32))
++#define pgd_page(pgd) (mem_map + ((pgd_val(pgd) & _PFN_MASK) >> 32))
+ #endif
+
+-extern inline unsigned long pgd_page(pgd_t pgd)
++extern inline unsigned long pgd_page_vaddr(pgd_t pgd)
+ { return PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
+
+ extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
+@@ -293,13 +294,13 @@ extern inline pte_t pte_mkyoung(pte_t pt
+ /* Find an entry in the second-level page table.. */
+ extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+ {
+- return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
++ return (pmd_t *) pgd_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
+ }
+
+ /* Find an entry in the third-level page table.. */
+ extern inline pte_t * pte_offset_kernel(pmd_t * dir, unsigned long address)
+ {
+- return (pte_t *) pmd_page_kernel(*dir)
++ return (pte_t *) pmd_page_vaddr(*dir)
+ + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1));
+ }
+
+diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
+index 0c294c9..aeeb125 100644
+--- a/include/asm-alpha/spinlock.h
++++ b/include/asm-alpha/spinlock.h
+@@ -166,4 +166,8 @@ static inline void __raw_write_unlock(ra
+ lock->lock = 0;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* _ALPHA_SPINLOCK_H */
+diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
+index bc6e6a9..2cabbd4 100644
+--- a/include/asm-alpha/unistd.h
++++ b/include/asm-alpha/unistd.h
+@@ -580,75 +580,6 @@ type name (type1 arg1,type2 arg2,type3 a
+ #define __ARCH_WANT_SYS_OLDUMOUNT
+ #define __ARCH_WANT_SYS_SIGPENDING
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/string.h>
+-#include <linux/signal.h>
+-#include <linux/syscalls.h>
+-#include <asm/ptrace.h>
+-
+-static inline long open(const char * name, int mode, int flags)
+-{
+- return sys_open(name, mode, flags);
+-}
+-
+-static inline long dup(int fd)
+-{
+- return sys_dup(fd);
+-}
+-
+-static inline long close(int fd)
+-{
+- return sys_close(fd);
+-}
+-
+-static inline off_t lseek(int fd, off_t off, int whence)
+-{
+- return sys_lseek(fd, off, whence);
+-}
+-
+-static inline void _exit(int value)
+-{
+- sys_exit(value);
+-}
+-
+-#define exit(x) _exit(x)
+-
+-static inline long write(int fd, const char * buf, size_t nr)
+-{
+- return sys_write(fd, buf, nr);
+-}
+-
+-static inline long read(int fd, char * buf, size_t nr)
+-{
+- return sys_read(fd, buf, nr);
+-}
+-
+-extern int execve(char *, char **, char **);
+-
+-static inline long setsid(void)
+-{
+- return sys_setsid();
+-}
+-
+-static inline pid_t waitpid(int pid, int * wait_stat, int flags)
+-{
+- return sys_wait4(pid, wait_stat, flags, NULL);
+-}
+-
+-asmlinkage int sys_execve(char *ufilename, char **argv, char **envp,
+- unsigned long a3, unsigned long a4, unsigned long a5,
+- struct pt_regs regs);
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize,
+- void *restorer);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /* "Conditional" syscalls. What we want is
+
+ __attribute__((weak,alias("sys_ni_syscall")))
+diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200.h b/include/asm-arm/arch-at91rm9200/at91rm9200.h
+index 58f4093..a5a86b1 100644
+--- a/include/asm-arm/arch-at91rm9200/at91rm9200.h
++++ b/include/asm-arm/arch-at91rm9200/at91rm9200.h
+@@ -19,67 +19,80 @@
+ /*
+ * Peripheral identifiers/interrupts.
+ */
+-#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
+-#define AT91_ID_SYS 1 /* System Peripheral */
+-#define AT91_ID_PIOA 2 /* Parallel IO Controller A */
+-#define AT91_ID_PIOB 3 /* Parallel IO Controller B */
+-#define AT91_ID_PIOC 4 /* Parallel IO Controller C */
+-#define AT91_ID_PIOD 5 /* Parallel IO Controller D */
+-#define AT91_ID_US0 6 /* USART 0 */
+-#define AT91_ID_US1 7 /* USART 1 */
+-#define AT91_ID_US2 8 /* USART 2 */
+-#define AT91_ID_US3 9 /* USART 3 */
+-#define AT91_ID_MCI 10 /* Multimedia Card Interface */
+-#define AT91_ID_UDP 11 /* USB Device Port */
+-#define AT91_ID_TWI 12 /* Two-Wire Interface */
+-#define AT91_ID_SPI 13 /* Serial Peripheral Interface */
+-#define AT91_ID_SSC0 14 /* Serial Synchronous Controller 0 */
+-#define AT91_ID_SSC1 15 /* Serial Synchronous Controller 1 */
+-#define AT91_ID_SSC2 16 /* Serial Synchronous Controller 2 */
+-#define AT91_ID_TC0 17 /* Timer Counter 0 */
+-#define AT91_ID_TC1 18 /* Timer Counter 1 */
+-#define AT91_ID_TC2 19 /* Timer Counter 2 */
+-#define AT91_ID_TC3 20 /* Timer Counter 3 */
+-#define AT91_ID_TC4 21 /* Timer Counter 4 */
+-#define AT91_ID_TC5 22 /* Timer Counter 5 */
+-#define AT91_ID_UHP 23 /* USB Host port */
+-#define AT91_ID_EMAC 24 /* Ethernet MAC */
+-#define AT91_ID_IRQ0 25 /* Advanced Interrupt Controller (IRQ0) */
+-#define AT91_ID_IRQ1 26 /* Advanced Interrupt Controller (IRQ1) */
+-#define AT91_ID_IRQ2 27 /* Advanced Interrupt Controller (IRQ2) */
+-#define AT91_ID_IRQ3 28 /* Advanced Interrupt Controller (IRQ3) */
+-#define AT91_ID_IRQ4 29 /* Advanced Interrupt Controller (IRQ4) */
+-#define AT91_ID_IRQ5 30 /* Advanced Interrupt Controller (IRQ5) */
+-#define AT91_ID_IRQ6 31 /* Advanced Interrupt Controller (IRQ6) */
++#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
++#define AT91_ID_SYS 1 /* System Peripheral */
++#define AT91RM9200_ID_PIOA 2 /* Parallel IO Controller A */
++#define AT91RM9200_ID_PIOB 3 /* Parallel IO Controller B */
++#define AT91RM9200_ID_PIOC 4 /* Parallel IO Controller C */
++#define AT91RM9200_ID_PIOD 5 /* Parallel IO Controller D */
++#define AT91RM9200_ID_US0 6 /* USART 0 */
++#define AT91RM9200_ID_US1 7 /* USART 1 */
++#define AT91RM9200_ID_US2 8 /* USART 2 */
++#define AT91RM9200_ID_US3 9 /* USART 3 */
++#define AT91RM9200_ID_MCI 10 /* Multimedia Card Interface */
++#define AT91RM9200_ID_UDP 11 /* USB Device Port */
++#define AT91RM9200_ID_TWI 12 /* Two-Wire Interface */
++#define AT91RM9200_ID_SPI 13 /* Serial Peripheral Interface */
++#define AT91RM9200_ID_SSC0 14 /* Serial Synchronous Controller 0 */
++#define AT91RM9200_ID_SSC1 15 /* Serial Synchronous Controller 1 */
++#define AT91RM9200_ID_SSC2 16 /* Serial Synchronous Controller 2 */
++#define AT91RM9200_ID_TC0 17 /* Timer Counter 0 */
++#define AT91RM9200_ID_TC1 18 /* Timer Counter 1 */
++#define AT91RM9200_ID_TC2 19 /* Timer Counter 2 */
++#define AT91RM9200_ID_TC3 20 /* Timer Counter 3 */
++#define AT91RM9200_ID_TC4 21 /* Timer Counter 4 */
++#define AT91RM9200_ID_TC5 22 /* Timer Counter 5 */
++#define AT91RM9200_ID_UHP 23 /* USB Host port */
++#define AT91RM9200_ID_EMAC 24 /* Ethernet MAC */
++#define AT91RM9200_ID_IRQ0 25 /* Advanced Interrupt Controller (IRQ0) */
++#define AT91RM9200_ID_IRQ1 26 /* Advanced Interrupt Controller (IRQ1) */
++#define AT91RM9200_ID_IRQ2 27 /* Advanced Interrupt Controller (IRQ2) */
++#define AT91RM9200_ID_IRQ3 28 /* Advanced Interrupt Controller (IRQ3) */
++#define AT91RM9200_ID_IRQ4 29 /* Advanced Interrupt Controller (IRQ4) */
++#define AT91RM9200_ID_IRQ5 30 /* Advanced Interrupt Controller (IRQ5) */
++#define AT91RM9200_ID_IRQ6 31 /* Advanced Interrupt Controller (IRQ6) */
+
+
+ /*
+ * Peripheral physical base addresses.
+ */
+-#define AT91_BASE_TCB0 0xfffa0000
+-#define AT91_BASE_TC0 0xfffa0000
+-#define AT91_BASE_TC1 0xfffa0040
+-#define AT91_BASE_TC2 0xfffa0080
+-#define AT91_BASE_TCB1 0xfffa4000
+-#define AT91_BASE_TC3 0xfffa4000
+-#define AT91_BASE_TC4 0xfffa4040
+-#define AT91_BASE_TC5 0xfffa4080
+-#define AT91_BASE_UDP 0xfffb0000
+-#define AT91_BASE_MCI 0xfffb4000
+-#define AT91_BASE_TWI 0xfffb8000
+-#define AT91_BASE_EMAC 0xfffbc000
+-#define AT91_BASE_US0 0xfffc0000
+-#define AT91_BASE_US1 0xfffc4000
+-#define AT91_BASE_US2 0xfffc8000
+-#define AT91_BASE_US3 0xfffcc000
+-#define AT91_BASE_SSC0 0xfffd0000
+-#define AT91_BASE_SSC1 0xfffd4000
+-#define AT91_BASE_SSC2 0xfffd8000
+-#define AT91_BASE_SPI 0xfffe0000
++#define AT91RM9200_BASE_TCB0 0xfffa0000
++#define AT91RM9200_BASE_TC0 0xfffa0000
++#define AT91RM9200_BASE_TC1 0xfffa0040
++#define AT91RM9200_BASE_TC2 0xfffa0080
++#define AT91RM9200_BASE_TCB1 0xfffa4000
++#define AT91RM9200_BASE_TC3 0xfffa4000
++#define AT91RM9200_BASE_TC4 0xfffa4040
++#define AT91RM9200_BASE_TC5 0xfffa4080
++#define AT91RM9200_BASE_UDP 0xfffb0000
++#define AT91RM9200_BASE_MCI 0xfffb4000
++#define AT91RM9200_BASE_TWI 0xfffb8000
++#define AT91RM9200_BASE_EMAC 0xfffbc000
++#define AT91RM9200_BASE_US0 0xfffc0000
++#define AT91RM9200_BASE_US1 0xfffc4000
++#define AT91RM9200_BASE_US2 0xfffc8000
++#define AT91RM9200_BASE_US3 0xfffcc000
++#define AT91RM9200_BASE_SSC0 0xfffd0000
++#define AT91RM9200_BASE_SSC1 0xfffd4000
++#define AT91RM9200_BASE_SSC2 0xfffd8000
++#define AT91RM9200_BASE_SPI 0xfffe0000
+ #define AT91_BASE_SYS 0xfffff000
+
+
+ /*
++ * Internal Memory.
++ */
++#define AT91RM9200_ROM_BASE 0x00100000 /* Internal ROM base address */
++#define AT91RM9200_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */
++
++#define AT91RM9200_SRAM_BASE 0x00200000 /* Internal SRAM base address */
++#define AT91RM9200_SRAM_SIZE SZ_16K /* Internal SRAM size (16Kb) */
++
++#define AT91RM9200_UHP_BASE 0x00300000 /* USB Host controller */
++
++
++#if 0
++/*
+ * PIO pin definitions (peripheral A/B multiplexing).
+ */
+ #define AT91_PA0_MISO (1 << 0) /* A: SPI Master-In Slave-Out */
+@@ -257,5 +270,6 @@
+ #define AT91_PD25_TPK13 (1 << 25) /* B: ETM Trace Packet Port 13 */
+ #define AT91_PD26_TPK14 (1 << 26) /* B: ETM Trace Packet Port 14 */
+ #define AT91_PD27_TPK15 (1 << 27) /* B: ETM Trace Packet Port 15 */
++#endif
+
+ #endif
+diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h
+index 0f4c12d..73693fe 100644
+--- a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h
++++ b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h
+@@ -80,6 +80,9 @@
+ #define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */
+ #define AT91_CIDR_EXT (1 << 31) /* Extension Flag */
+
++#define AT91_AIC_FFER (AT91_AIC + 0x140) /* Fast Forcing Enable Register [SAM9 only] */
++#define AT91_AIC_FFDR (AT91_AIC + 0x144) /* Fast Forcing Disable Register [SAM9 only] */
++#define AT91_AIC_FFSR (AT91_AIC + 0x148) /* Fast Forcing Status Register [SAM9 only] */
+
+ /*
+ * PIO Controllers.
+diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_twi.h b/include/asm-arm/arch-at91rm9200/at91rm9200_twi.h
+new file mode 100644
+index 0000000..93547d7
+--- /dev/null
++++ b/include/asm-arm/arch-at91rm9200/at91rm9200_twi.h
+@@ -0,0 +1,57 @@
++/*
++ * include/asm-arm/arch-at91rm9200/at91rm9200_twi.h
++ *
++ * Copyright (C) 2005 Ivan Kokshaysky
++ * Copyright (C) SAN People
++ *
++ * Two-wire Interface (TWI) registers.
++ * Based on AT91RM9200 datasheet revision E.
++ *
++ * 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.
++ */
++
++#ifndef AT91RM9200_TWI_H
++#define AT91RM9200_TWI_H
++
++#define AT91_TWI_CR 0x00 /* Control Register */
++#define AT91_TWI_START (1 << 0) /* Send a Start Condition */
++#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */
++#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */
++#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */
++#define AT91_TWI_SWRST (1 << 7) /* Software Reset */
++
++#define AT91_TWI_MMR 0x04 /* Master Mode Register */
++#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */
++#define AT91_TWI_IADRSZ_NO (0 << 8)
++#define AT91_TWI_IADRSZ_1 (1 << 8)
++#define AT91_TWI_IADRSZ_2 (2 << 8)
++#define AT91_TWI_IADRSZ_3 (3 << 8)
++#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */
++#define AT91_TWI_DADR (0x7f << 16) /* Device Address */
++
++#define AT91_TWI_IADR 0x0c /* Internal Address Register */
++
++#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */
++#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */
++#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */
++#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */
++
++#define AT91_TWI_SR 0x20 /* Status Register */
++#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */
++#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */
++#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */
++#define AT91_TWI_OVRE (1 << 6) /* Overrun Error */
++#define AT91_TWI_UNRE (1 << 7) /* Underrun Error */
++#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */
++
++#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */
++#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */
++#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */
++#define AT91_TWI_RHR 0x30 /* Receive Holding Register */
++#define AT91_TWI_THR 0x34 /* Transmit Holding Register */
++
++#endif
++
+diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h b/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
+deleted file mode 100644
+index 79f851e..0000000
+--- a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
++++ /dev/null
+@@ -1,123 +0,0 @@
+-/*
+- * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
+- *
+- * Copyright (C) 2005 Ivan Kokshaysky
+- * Copyright (C) SAN People
+- *
+- * USART registers.
+- * Based on AT91RM9200 datasheet revision E.
+- *
+- * 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.
+- */
+-
+-#ifndef AT91RM9200_USART_H
+-#define AT91RM9200_USART_H
+-
+-#define AT91_US_CR 0x00 /* Control Register */
+-#define AT91_US_RSTRX (1 << 2) /* Reset Receiver */
+-#define AT91_US_RSTTX (1 << 3) /* Reset Transmitter */
+-#define AT91_US_RXEN (1 << 4) /* Receiver Enable */
+-#define AT91_US_RXDIS (1 << 5) /* Receiver Disable */
+-#define AT91_US_TXEN (1 << 6) /* Transmitter Enable */
+-#define AT91_US_TXDIS (1 << 7) /* Transmitter Disable */
+-#define AT91_US_RSTSTA (1 << 8) /* Reset Status Bits */
+-#define AT91_US_STTBRK (1 << 9) /* Start Break */
+-#define AT91_US_STPBRK (1 << 10) /* Stop Break */
+-#define AT91_US_STTTO (1 << 11) /* Start Time-out */
+-#define AT91_US_SENDA (1 << 12) /* Send Address */
+-#define AT91_US_RSTIT (1 << 13) /* Reset Iterations */
+-#define AT91_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */
+-#define AT91_US_RETTO (1 << 15) /* Rearm Time-out */
+-#define AT91_US_DTREN (1 << 16) /* Data Terminal Ready Enable */
+-#define AT91_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */
+-#define AT91_US_RTSEN (1 << 18) /* Request To Send Enable */
+-#define AT91_US_RTSDIS (1 << 19) /* Request To Send Disable */
+-
+-#define AT91_US_MR 0x04 /* Mode Register */
+-#define AT91_US_USMODE (0xf << 0) /* Mode of the USART */
+-#define AT91_US_USMODE_NORMAL 0
+-#define AT91_US_USMODE_RS485 1
+-#define AT91_US_USMODE_HWHS 2
+-#define AT91_US_USMODE_MODEM 3
+-#define AT91_US_USMODE_ISO7816_T0 4
+-#define AT91_US_USMODE_ISO7816_T1 6
+-#define AT91_US_USMODE_IRDA 8
+-#define AT91_US_USCLKS (3 << 4) /* Clock Selection */
+-#define AT91_US_CHRL (3 << 6) /* Character Length */
+-#define AT91_US_CHRL_5 (0 << 6)
+-#define AT91_US_CHRL_6 (1 << 6)
+-#define AT91_US_CHRL_7 (2 << 6)
+-#define AT91_US_CHRL_8 (3 << 6)
+-#define AT91_US_SYNC (1 << 8) /* Synchronous Mode Select */
+-#define AT91_US_PAR (7 << 9) /* Parity Type */
+-#define AT91_US_PAR_EVEN (0 << 9)
+-#define AT91_US_PAR_ODD (1 << 9)
+-#define AT91_US_PAR_SPACE (2 << 9)
+-#define AT91_US_PAR_MARK (3 << 9)
+-#define AT91_US_PAR_NONE (4 << 9)
+-#define AT91_US_PAR_MULTI_DROP (6 << 9)
+-#define AT91_US_NBSTOP (3 << 12) /* Number of Stop Bits */
+-#define AT91_US_NBSTOP_1 (0 << 12)
+-#define AT91_US_NBSTOP_1_5 (1 << 12)
+-#define AT91_US_NBSTOP_2 (2 << 12)
+-#define AT91_US_CHMODE (3 << 14) /* Channel Mode */
+-#define AT91_US_CHMODE_NORMAL (0 << 14)
+-#define AT91_US_CHMODE_ECHO (1 << 14)
+-#define AT91_US_CHMODE_LOC_LOOP (2 << 14)
+-#define AT91_US_CHMODE_REM_LOOP (3 << 14)
+-#define AT91_US_MSBF (1 << 16) /* Bit Order */
+-#define AT91_US_MODE9 (1 << 17) /* 9-bit Character Length */
+-#define AT91_US_CLKO (1 << 18) /* Clock Output Select */
+-#define AT91_US_OVER (1 << 19) /* Oversampling Mode */
+-#define AT91_US_INACK (1 << 20) /* Inhibit Non Acknowledge */
+-#define AT91_US_DSNACK (1 << 21) /* Disable Successive NACK */
+-#define AT91_US_MAX_ITER (7 << 24) /* Max Iterations */
+-#define AT91_US_FILTER (1 << 28) /* Infrared Receive Line Filter */
+-
+-#define AT91_US_IER 0x08 /* Interrupt Enable Register */
+-#define AT91_US_RXRDY (1 << 0) /* Receiver Ready */
+-#define AT91_US_TXRDY (1 << 1) /* Transmitter Ready */
+-#define AT91_US_RXBRK (1 << 2) /* Break Received / End of Break */
+-#define AT91_US_ENDRX (1 << 3) /* End of Receiver Transfer */
+-#define AT91_US_ENDTX (1 << 4) /* End of Transmitter Transfer */
+-#define AT91_US_OVRE (1 << 5) /* Overrun Error */
+-#define AT91_US_FRAME (1 << 6) /* Framing Error */
+-#define AT91_US_PARE (1 << 7) /* Parity Error */
+-#define AT91_US_TIMEOUT (1 << 8) /* Receiver Time-out */
+-#define AT91_US_TXEMPTY (1 << 9) /* Transmitter Empty */
+-#define AT91_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */
+-#define AT91_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */
+-#define AT91_US_RXBUFF (1 << 12) /* Reception Buffer Full */
+-#define AT91_US_NACK (1 << 13) /* Non Acknowledge */
+-#define AT91_US_RIIC (1 << 16) /* Ring Indicator Input Change */
+-#define AT91_US_DSRIC (1 << 17) /* Data Set Ready Input Change */
+-#define AT91_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */
+-#define AT91_US_CTSIC (1 << 19) /* Clear to Send Input Change */
+-#define AT91_US_RI (1 << 20) /* RI */
+-#define AT91_US_DSR (1 << 21) /* DSR */
+-#define AT91_US_DCD (1 << 22) /* DCD */
+-#define AT91_US_CTS (1 << 23) /* CTS */
+-
+-#define AT91_US_IDR 0x0c /* Interrupt Disable Register */
+-#define AT91_US_IMR 0x10 /* Interrupt Mask Register */
+-#define AT91_US_CSR 0x14 /* Channel Status Register */
+-#define AT91_US_RHR 0x18 /* Receiver Holding Register */
+-#define AT91_US_THR 0x1c /* Transmitter Holding Register */
+-
+-#define AT91_US_BRGR 0x20 /* Baud Rate Generator Register */
+-#define AT91_US_CD (0xffff << 0) /* Clock Divider */
+-
+-#define AT91_US_RTOR 0x24 /* Receiver Time-out Register */
+-#define AT91_US_TO (0xffff << 0) /* Time-out Value */
+-
+-#define AT91_US_TTGR 0x28 /* Transmitter Timeguard Register */
+-#define AT91_US_TG (0xff << 0) /* Timeguard Value */
+-
+-#define AT91_US_FIDI 0x40 /* FI DI Ratio Register */
+-#define AT91_US_NER 0x44 /* Number of Errors Register */
+-#define AT91_US_IF 0x4c /* IrDA Filter Register */
+-
+-#endif
+diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h
+index c1ca9a4..3cc9aec 100644
+--- a/include/asm-arm/arch-at91rm9200/board.h
++++ b/include/asm-arm/arch-at91rm9200/board.h
+@@ -97,12 +97,13 @@ struct at91_uart_config {
+ unsigned short nr_tty; /* number of serial tty's */
+ short tty_map[]; /* map UART to tty number */
+ };
+-extern struct platform_device *at91_default_console_device;
++extern struct platform_device *atmel_default_console_device;
+ extern void __init at91_init_serial(struct at91_uart_config *config);
+
+-struct at91_uart_data {
++struct atmel_uart_data {
+ short use_dma_tx; /* use transmit DMA? */
+ short use_dma_rx; /* use receive DMA? */
++ void __iomem *regs; /* virtual base address, if any */
+ };
+ extern void __init at91_add_device_serial(void);
+
+diff --git a/include/asm-arm/arch-at91rm9200/gpio.h b/include/asm-arm/arch-at91rm9200/gpio.h
+index dbde1ba..a011d27 100644
+--- a/include/asm-arm/arch-at91rm9200/gpio.h
++++ b/include/asm-arm/arch-at91rm9200/gpio.h
+@@ -17,10 +17,9 @@
+
+ #define PIN_BASE NR_AIC_IRQS
+
+-#define PQFP_GPIO_BANKS 3 /* PQFP package has 3 banks */
+-#define BGA_GPIO_BANKS 4 /* BGA package has 4 banks */
++#define MAX_GPIO_BANKS 4
+
+-/* these pin numbers double as IRQ numbers, like AT91_ID_* values */
++/* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */
+
+ #define AT91_PIN_PA0 (PIN_BASE + 0x00 + 0)
+ #define AT91_PIN_PA1 (PIN_BASE + 0x00 + 1)
+@@ -180,17 +179,18 @@
+
+ #ifndef __ASSEMBLY__
+ /* setup setup routines, called from board init or driver probe() */
+-extern int at91_set_A_periph(unsigned pin, int use_pullup);
+-extern int at91_set_B_periph(unsigned pin, int use_pullup);
+-extern int at91_set_gpio_input(unsigned pin, int use_pullup);
+-extern int at91_set_gpio_output(unsigned pin, int value);
+-extern int at91_set_deglitch(unsigned pin, int is_on);
+-extern int at91_set_multi_drive(unsigned pin, int is_on);
++extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
++extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
++extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
++extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
++extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
++extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
+
+ /* callable at any time */
+ extern int at91_set_gpio_value(unsigned pin, int value);
+ extern int at91_get_gpio_value(unsigned pin);
+
++/* callable only from core power-management code */
+ extern void at91_gpio_suspend(void);
+ extern void at91_gpio_resume(void);
+ #endif
+diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h
+index 235d39d..9ca4cc9 100644
+--- a/include/asm-arm/arch-at91rm9200/hardware.h
++++ b/include/asm-arm/arch-at91rm9200/hardware.h
+@@ -34,30 +34,17 @@
+ * Virtual to Physical Address mapping for IO devices.
+ */
+ #define AT91_VA_BASE_SYS AT91_IO_P2V(AT91_BASE_SYS)
+-#define AT91_VA_BASE_SPI AT91_IO_P2V(AT91_BASE_SPI)
+-#define AT91_VA_BASE_SSC2 AT91_IO_P2V(AT91_BASE_SSC2)
+-#define AT91_VA_BASE_SSC1 AT91_IO_P2V(AT91_BASE_SSC1)
+-#define AT91_VA_BASE_SSC0 AT91_IO_P2V(AT91_BASE_SSC0)
+-#define AT91_VA_BASE_US3 AT91_IO_P2V(AT91_BASE_US3)
+-#define AT91_VA_BASE_US2 AT91_IO_P2V(AT91_BASE_US2)
+-#define AT91_VA_BASE_US1 AT91_IO_P2V(AT91_BASE_US1)
+-#define AT91_VA_BASE_US0 AT91_IO_P2V(AT91_BASE_US0)
+-#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91_BASE_EMAC)
+-#define AT91_VA_BASE_TWI AT91_IO_P2V(AT91_BASE_TWI)
+-#define AT91_VA_BASE_MCI AT91_IO_P2V(AT91_BASE_MCI)
+-#define AT91_VA_BASE_UDP AT91_IO_P2V(AT91_BASE_UDP)
+-#define AT91_VA_BASE_TCB1 AT91_IO_P2V(AT91_BASE_TCB1)
+-#define AT91_VA_BASE_TCB0 AT91_IO_P2V(AT91_BASE_TCB0)
+-
+-/* Internal SRAM */
+-#define AT91_SRAM_BASE 0x00200000 /* Internal SRAM base address */
+-#define AT91_SRAM_SIZE 0x00004000 /* Internal SRAM SIZE (16Kb) */
++#define AT91_VA_BASE_SPI AT91_IO_P2V(AT91RM9200_BASE_SPI)
++#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91RM9200_BASE_EMAC)
++#define AT91_VA_BASE_TWI AT91_IO_P2V(AT91RM9200_BASE_TWI)
++#define AT91_VA_BASE_MCI AT91_IO_P2V(AT91RM9200_BASE_MCI)
++#define AT91_VA_BASE_UDP AT91_IO_P2V(AT91RM9200_BASE_UDP)
+
+ /* Internal SRAM is mapped below the IO devices */
+-#define AT91_SRAM_VIRT_BASE (AT91_IO_VIRT_BASE - AT91_SRAM_SIZE)
++#define AT91_SRAM_VIRT_BASE (AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE)
+
+ /* Serial ports */
+-#define AT91_NR_UART 5 /* 4 USART3's and one DBGU port */
++#define ATMEL_MAX_UART 5 /* 4 USART3's and one DBGU port */
+
+ /* FLASH */
+ #define AT91_FLASH_BASE 0x10000000 /* NCS0: Flash physical base address */
+@@ -71,9 +58,6 @@
+ /* Compact Flash */
+ #define AT91_CF_BASE 0x50000000 /* NCS4-NCS6: Compact Flash physical base address */
+
+-/* Multi-Master Memory controller */
+-#define AT91_UHP_BASE 0x00300000 /* USB Host controller */
+-
+ /* Clocks */
+ #define AT91_SLOW_CLOCK 32768 /* slow clock */
+
+diff --git a/include/asm-arm/arch-at91rm9200/irqs.h b/include/asm-arm/arch-at91rm9200/irqs.h
+index f63842c..763cb96 100644
+--- a/include/asm-arm/arch-at91rm9200/irqs.h
++++ b/include/asm-arm/arch-at91rm9200/irqs.h
+@@ -32,7 +32,7 @@
+
+
+ /*
+- * IRQ interrupt symbols are the AT91_ID_* symbols in at91rm9200.h
++ * IRQ interrupt symbols are the AT91xxx_ID_* symbols
+ * for IRQs handled directly through the AIC, or else the AT91_PIN_*
+ * symbols in gpio.h for ones handled indirectly as GPIOs.
+ * We make provision for 4 banks of GPIO.
+diff --git a/include/asm-arm/arch-clps711x/entry-macro.S b/include/asm-arm/arch-clps711x/entry-macro.S
+index 21f6ee4..de4481d 100644
+--- a/include/asm-arm/arch-clps711x/entry-macro.S
++++ b/include/asm-arm/arch-clps711x/entry-macro.S
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-arm/arch-CLPS711x/entry-macro.S
++ * include/asm-arm/arch-clps711x/entry-macro.S
+ *
+ * Low-level IRQ helper macros for CLPS711X-based platforms
+ *
+diff --git a/include/asm-arm/arch-clps711x/time.h b/include/asm-arm/arch-clps711x/time.h
+index 9cb27cd..5edaae1 100644
+--- a/include/asm-arm/arch-clps711x/time.h
++++ b/include/asm-arm/arch-clps711x/time.h
+@@ -26,10 +26,11 @@ extern void clps711x_setup_timer(void);
+ * IRQ handler for the timer
+ */
+ static irqreturn_t
+-p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++p720t_timer_interrupt(int irq, void *dev_id)
+ {
++ struct pt_regs *regs = get_irq_regs();
+ do_leds();
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+diff --git a/include/asm-arm/arch-ebsa285/entry-macro.S b/include/asm-arm/arch-ebsa285/entry-macro.S
+index cf10ac9..ce812d4 100644
+--- a/include/asm-arm/arch-ebsa285/entry-macro.S
++++ b/include/asm-arm/arch-ebsa285/entry-macro.S
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-arm/arch-footbridge/entry-macro.S
++ * include/asm-arm/arch-ebsa285/entry-macro.S
+ *
+ * Low-level IRQ helper macros for footbridge-based platforms
+ *
+diff --git a/include/asm-arm/arch-ep93xx/ep93xx-regs.h b/include/asm-arm/arch-ep93xx/ep93xx-regs.h
+index 8c32297..593f562 100644
+--- a/include/asm-arm/arch-ep93xx/ep93xx-regs.h
++++ b/include/asm-arm/arch-ep93xx/ep93xx-regs.h
+@@ -27,6 +27,7 @@
+ #define EP93XX_DMA_BASE (EP93XX_AHB_VIRT_BASE + 0x00000000)
+
+ #define EP93XX_ETHERNET_BASE (EP93XX_AHB_VIRT_BASE + 0x00010000)
++#define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000)
+
+ #define EP93XX_USB_BASE (EP93XX_AHB_VIRT_BASE + 0x00020000)
+ #define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000)
+diff --git a/include/asm-arm/arch-ep93xx/platform.h b/include/asm-arm/arch-ep93xx/platform.h
+index d7a34ce..b4a8deb 100644
+--- a/include/asm-arm/arch-ep93xx/platform.h
++++ b/include/asm-arm/arch-ep93xx/platform.h
+@@ -11,5 +11,11 @@ void ep93xx_init_devices(void);
+ void ep93xx_clock_init(void);
+ extern struct sys_timer ep93xx_timer;
+
++struct ep93xx_eth_data
++{
++ unsigned char dev_addr[6];
++ unsigned char phy_id;
++};
++
+
+ #endif
+diff --git a/include/asm-arm/arch-h720x/system.h b/include/asm-arm/arch-h720x/system.h
+index 09eda84..8dc1460 100644
+--- a/include/asm-arm/arch-h720x/system.h
++++ b/include/asm-arm/arch-h720x/system.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/arch/arm/mach-h720x/system.h
++ * linux/include/asm-arm/arch-h720x/system.h
+ *
+ * Copyright (C) 2001-2002 Jungjun Kim, Hynix Semiconductor Inc.
+ *
+diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h
+index 599f03e..5b1066d 100644
+--- a/include/asm-arm/arch-imx/imx-dma.h
++++ b/include/asm-arm/arch-imx/imx-dma.h
+@@ -45,8 +45,8 @@
+
+ struct imx_dma_channel {
+ const char *name;
+- void (*irq_handler) (int, void *, struct pt_regs *);
+- void (*err_handler) (int, void *, struct pt_regs *, int errcode);
++ void (*irq_handler) (int, void *);
++ void (*err_handler) (int, void *, int errcode);
+ void *data;
+ dmamode_t dma_mode;
+ struct scatterlist *sg;
+@@ -77,8 +77,8 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
+
+ int
+ imx_dma_setup_handlers(imx_dmach_t dma_ch,
+- void (*irq_handler) (int, void *, struct pt_regs *),
+- void (*err_handler) (int, void *, struct pt_regs *, int), void *data);
++ void (*irq_handler) (int, void *),
++ void (*err_handler) (int, void *, int), void *data);
+
+ void imx_dma_enable(imx_dmach_t dma_ch);
+
+diff --git a/include/asm-arm/arch-iop32x/debug-macro.S b/include/asm-arm/arch-iop32x/debug-macro.S
+new file mode 100644
+index 0000000..9022b68
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/debug-macro.S
+@@ -0,0 +1,20 @@
++/*
++ * include/asm-arm/arch-iop32x/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ * Copyright (C) 1994-1999 Russell King
++ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++ .macro addruart, rx
++ mov \rx, #0xfe000000 @ physical as well as virtual
++ orr \rx, \rx, #0x00800000 @ location of the UART
++ .endm
++
++#define UART_SHIFT 0
++#include <asm/hardware/debug-8250.S>
+diff --git a/include/asm-arm/arch-iop32x/dma.h b/include/asm-arm/arch-iop32x/dma.h
+new file mode 100644
+index 0000000..e977a9e
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/dma.h
+@@ -0,0 +1,9 @@
++/*
++ * include/asm-arm/arch-iop32x/dma.h
++ *
++ * Copyright (C) 2004 Intel Corp.
++ *
++ * 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.
++ */
+diff --git a/include/asm-arm/arch-iop32x/entry-macro.S b/include/asm-arm/arch-iop32x/entry-macro.S
+new file mode 100644
+index 0000000..1500cbb
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/entry-macro.S
+@@ -0,0 +1,21 @@
++/*
++ * include/asm-arm/arch-iop32x/entry-macro.S
++ *
++ * Low-level IRQ helper macros for IOP32x-based platforms
++ *
++ * 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 <asm/arch/iop32x.h>
++
++ .macro disable_fiq
++ .endm
++
++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
++ ldr \base, =IOP3XX_REG_ADDR(0x07D8)
++ ldr \irqstat, [\base] @ Read IINTSRC
++ cmp \irqstat, #0
++ clzne \irqnr, \irqstat
++ rsbne \irqnr, \irqnr, #31
++ .endm
+diff --git a/include/asm-arm/arch-iop32x/glantank.h b/include/asm-arm/arch-iop32x/glantank.h
+new file mode 100644
+index 0000000..3b06561
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/glantank.h
+@@ -0,0 +1,13 @@
++/*
++ * include/asm/arch-iop32x/glantank.h
++ *
++ * IO-Data GLAN Tank board registers
++ */
++
++#ifndef __GLANTANK_H
++#define __GLANTANK_H
++
++#define GLANTANK_UART 0xfe800000 /* UART */
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/hardware.h b/include/asm-arm/arch-iop32x/hardware.h
+new file mode 100644
+index 0000000..6556ed5
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/hardware.h
+@@ -0,0 +1,44 @@
++/*
++ * include/asm-arm/arch-iop32x/hardware.h
++ */
++
++#ifndef __HARDWARE_H
++#define __HARDWARE_H
++
++#include <asm/types.h>
++
++/*
++ * Note about PCI IO space mappings
++ *
++ * To make IO space accesses efficient, we store virtual addresses in
++ * the IO resources.
++ *
++ * The PCI IO space is located at virtual 0xfe000000 from physical
++ * 0x90000000. The PCI BARs must be programmed with physical addresses,
++ * but when we read them, we convert them to virtual addresses. See
++ * arch/arm/plat-iop/pci.c.
++ */
++#define pcibios_assign_all_busses() 1
++#define PCIBIOS_MIN_IO 0x00000000
++#define PCIBIOS_MIN_MEM 0x00000000
++
++#ifndef __ASSEMBLY__
++void iop32x_init_irq(void);
++#endif
++
++
++/*
++ * Generic chipset bits
++ */
++#include "iop32x.h"
++
++/*
++ * Board specific bits
++ */
++#include "glantank.h"
++#include "iq80321.h"
++#include "iq31244.h"
++#include "n2100.h"
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/io.h b/include/asm-arm/arch-iop32x/io.h
+new file mode 100644
+index 0000000..12d9ee0
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/io.h
+@@ -0,0 +1,22 @@
++/*
++ * include/asm-arm/arch-iop32x/io.h
++ *
++ * 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.
++ */
++
++#ifndef __IO_H
++#define __IO_H
++
++#include <asm/hardware.h>
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++#define __io(p) ((void __iomem *)(p))
++#define __mem_pci(a) (a)
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h
+new file mode 100644
+index 0000000..4bbd85f
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/iop32x.h
+@@ -0,0 +1,28 @@
++/*
++ * include/asm-arm/arch-iop32x/iop32x.h
++ *
++ * Intel IOP32X Chip definitions
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ * Copyright (C) 2004 Intel Corp.
++ *
++ * 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 __IOP32X_H
++#define __IOP32X_H
++
++/*
++ * Peripherals that are shared between the iop32x and iop33x but
++ * located at different addresses.
++ */
++#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c0 + (reg))
++#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg))
++
++#include <asm/hardware/iop3xx.h>
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/iq31244.h b/include/asm-arm/arch-iop32x/iq31244.h
+new file mode 100644
+index 0000000..fff4eaf
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/iq31244.h
+@@ -0,0 +1,17 @@
++/*
++ * include/asm-arm/arch-iop32x/iq31244.h
++ *
++ * Intel IQ31244 evaluation board registers
++ */
++
++#ifndef __IQ31244_H
++#define __IQ31244_H
++
++#define IQ31244_UART 0xfe800000 /* UART #1 */
++#define IQ31244_7SEG_1 0xfe840000 /* 7-Segment MSB */
++#define IQ31244_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */
++#define IQ31244_ROTARY_SW 0xfe8d0000 /* Rotary Switch */
++#define IQ31244_BATT_STAT 0xfe8f0000 /* Battery Status */
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/iq80321.h b/include/asm-arm/arch-iop32x/iq80321.h
+new file mode 100644
+index 0000000..eb69db9
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/iq80321.h
+@@ -0,0 +1,17 @@
++/*
++ * include/asm-arm/arch-iop32x/iq80321.h
++ *
++ * Intel IQ80321 evaluation board registers
++ */
++
++#ifndef __IQ80321_H
++#define __IQ80321_H
++
++#define IQ80321_UART 0xfe800000 /* UART #1 */
++#define IQ80321_7SEG_1 0xfe840000 /* 7-Segment MSB */
++#define IQ80321_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */
++#define IQ80321_ROTARY_SW 0xfe8d0000 /* Rotary Switch */
++#define IQ80321_BATT_STAT 0xfe8f0000 /* Battery Status */
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/irqs.h b/include/asm-arm/arch-iop32x/irqs.h
+new file mode 100644
+index 0000000..bbaef87
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/irqs.h
+@@ -0,0 +1,50 @@
++/*
++ * include/asm-arm/arch-iop32x/irqs.h
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright: (C) 2002 Rory Bolt
++ *
++ * 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 __IRQS_H
++#define __IRQS_H
++
++/*
++ * IOP80321 chipset interrupts
++ */
++#define IRQ_IOP32X_DMA0_EOT 0
++#define IRQ_IOP32X_DMA0_EOC 1
++#define IRQ_IOP32X_DMA1_EOT 2
++#define IRQ_IOP32X_DMA1_EOC 3
++#define IRQ_IOP32X_AA_EOT 6
++#define IRQ_IOP32X_AA_EOC 7
++#define IRQ_IOP32X_CORE_PMON 8
++#define IRQ_IOP32X_TIMER0 9
++#define IRQ_IOP32X_TIMER1 10
++#define IRQ_IOP32X_I2C_0 11
++#define IRQ_IOP32X_I2C_1 12
++#define IRQ_IOP32X_MESSAGING 13
++#define IRQ_IOP32X_ATU_BIST 14
++#define IRQ_IOP32X_PERFMON 15
++#define IRQ_IOP32X_CORE_PMU 16
++#define IRQ_IOP32X_BIU_ERR 17
++#define IRQ_IOP32X_ATU_ERR 18
++#define IRQ_IOP32X_MCU_ERR 19
++#define IRQ_IOP32X_DMA0_ERR 20
++#define IRQ_IOP32X_DMA1_ERR 21
++#define IRQ_IOP32X_AA_ERR 23
++#define IRQ_IOP32X_MSG_ERR 24
++#define IRQ_IOP32X_SSP 25
++#define IRQ_IOP32X_XINT0 27
++#define IRQ_IOP32X_XINT1 28
++#define IRQ_IOP32X_XINT2 29
++#define IRQ_IOP32X_XINT3 30
++#define IRQ_IOP32X_HPI 31
++
++#define NR_IRQS 32
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/memory.h b/include/asm-arm/arch-iop32x/memory.h
+new file mode 100644
+index 0000000..764cd3f
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/memory.h
+@@ -0,0 +1,26 @@
++/*
++ * include/asm-arm/arch-iop32x/memory.h
++ */
++
++#ifndef __MEMORY_H
++#define __MEMORY_H
++
++#include <asm/hardware.h>
++
++/*
++ * Physical DRAM offset.
++ */
++#define PHYS_OFFSET UL(0xa0000000)
++
++/*
++ * Virtual view <-> PCI DMA view memory address translations
++ * virt_to_bus: Used to translate the virtual address to an
++ * address suitable to be passed to set_dma_addr
++ * bus_to_virt: Used to convert an address for DMA operations
++ * to an address that the kernel can use.
++ */
++#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0))
++#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2)))
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/n2100.h b/include/asm-arm/arch-iop32x/n2100.h
+new file mode 100644
+index 0000000..fed31a6
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/n2100.h
+@@ -0,0 +1,19 @@
++/*
++ * include/asm/arch-iop32x/n2100.h
++ *
++ * Thecus N2100 board registers
++ */
++
++#ifndef __N2100_H
++#define __N2100_H
++
++#define N2100_UART 0xfe800000 /* UART */
++
++#define N2100_COPY_BUTTON IOP3XX_GPIO_LINE(0)
++#define N2100_PCA9532_RESET IOP3XX_GPIO_LINE(2)
++#define N2100_RESET_BUTTON IOP3XX_GPIO_LINE(3)
++#define N2100_HARDWARE_RESET IOP3XX_GPIO_LINE(4)
++#define N2100_POWER_BUTTON IOP3XX_GPIO_LINE(5)
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop32x/system.h b/include/asm-arm/arch-iop32x/system.h
+new file mode 100644
+index 0000000..17b7eb7
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/system.h
+@@ -0,0 +1,33 @@
++/*
++ * include/asm-arm/arch-iop32x/system.h
++ *
++ * 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 <asm/mach-types.h>
++
++static inline void arch_idle(void)
++{
++ cpu_do_idle();
++}
++
++static inline void arch_reset(char mode)
++{
++ local_irq_disable();
++
++ if (machine_is_n2100()) {
++ gpio_line_set(N2100_HARDWARE_RESET, GPIO_LOW);
++ gpio_line_config(N2100_HARDWARE_RESET, GPIO_OUT);
++ while (1)
++ ;
++ }
++
++ *IOP3XX_PCSR = 0x30;
++
++ /* Jump into ROM at address 0 */
++ cpu_reset(0);
++}
+diff --git a/include/asm-arm/arch-iop32x/timex.h b/include/asm-arm/arch-iop32x/timex.h
+new file mode 100644
+index 0000000..9934b08
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/timex.h
+@@ -0,0 +1,9 @@
++/*
++ * include/asm-arm/arch-iop32x/timex.h
++ *
++ * IOP32x architecture timex specifications
++ */
++
++#include <asm/hardware.h>
++
++#define CLOCK_TICK_RATE (100 * HZ)
+diff --git a/include/asm-arm/arch-iop32x/uncompress.h b/include/asm-arm/arch-iop32x/uncompress.h
+new file mode 100644
+index 0000000..e64f52b
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/uncompress.h
+@@ -0,0 +1,39 @@
++/*
++ * include/asm-arm/arch-iop32x/uncompress.h
++ */
++
++#include <asm/types.h>
++#include <asm/mach-types.h>
++#include <linux/serial_reg.h>
++#include <asm/hardware.h>
++
++static volatile u8 *uart_base;
++
++#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
++
++static inline void putc(char c)
++{
++ while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
++ barrier();
++ uart_base[UART_TX] = c;
++}
++
++static inline void flush(void)
++{
++}
++
++static __inline__ void __arch_decomp_setup(unsigned long arch_id)
++{
++ if (machine_is_iq80321())
++ uart_base = (volatile u8 *)IQ80321_UART;
++ else if (machine_is_iq31244())
++ uart_base = (volatile u8 *)IQ31244_UART;
++ else
++ uart_base = (volatile u8 *)0xfe800000;
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup() __arch_decomp_setup(arch_id)
++#define arch_decomp_wdog()
+diff --git a/include/asm-arm/arch-iop32x/vmalloc.h b/include/asm-arm/arch-iop32x/vmalloc.h
+new file mode 100644
+index 0000000..0a70baa
+--- /dev/null
++++ b/include/asm-arm/arch-iop32x/vmalloc.h
+@@ -0,0 +1,5 @@
++/*
++ * include/asm-arm/arch-iop32x/vmalloc.h
++ */
++
++#define VMALLOC_END 0xfe000000
+diff --git a/include/asm-arm/arch-iop33x/debug-macro.S b/include/asm-arm/arch-iop33x/debug-macro.S
+new file mode 100644
+index 0000000..9e7132e
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/debug-macro.S
+@@ -0,0 +1,24 @@
++/*
++ * include/asm-arm/arch-iop33x/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ * Copyright (C) 1994-1999 Russell King
++ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++ .macro addruart, rx
++ mrc p15, 0, \rx, c1, c0
++ tst \rx, #1 @ mmu enabled?
++ moveq \rx, #0xff000000 @ physical
++ movne \rx, #0xfe000000 @ virtual
++ orr \rx, \rx, #0x00ff0000
++ orr \rx, \rx, #0x0000f700
++ .endm
++
++#define UART_SHIFT 2
++#include <asm/hardware/debug-8250.S>
+diff --git a/include/asm-arm/arch-iop33x/dma.h b/include/asm-arm/arch-iop33x/dma.h
+new file mode 100644
+index 0000000..b7775fd
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/dma.h
+@@ -0,0 +1,9 @@
++/*
++ * include/asm-arm/arch-iop33x/dma.h
++ *
++ * Copyright (C) 2004 Intel Corp.
++ *
++ * 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.
++ */
+diff --git a/include/asm-arm/arch-iop33x/entry-macro.S b/include/asm-arm/arch-iop33x/entry-macro.S
+new file mode 100644
+index 0000000..92b7917
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/entry-macro.S
+@@ -0,0 +1,22 @@
++/*
++ * include/asm-arm/arch-iop33x/entry-macro.S
++ *
++ * Low-level IRQ helper macros for IOP33x-based platforms
++ *
++ * 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 <asm/arch/iop33x.h>
++
++ .macro disable_fiq
++ .endm
++
++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
++ ldr \base, =IOP3XX_REG_ADDR(0x07C8)
++ ldr \irqstat, [\base] @ Read IINTVEC
++ cmp \irqstat, #0
++ ldreq \irqstat, [\base] @ erratum 63 workaround
++ adds \irqnr, \irqstat, #1
++ movne \irqnr, \irqstat, lsr #2
++ .endm
+diff --git a/include/asm-arm/arch-iop33x/hardware.h b/include/asm-arm/arch-iop33x/hardware.h
+new file mode 100644
+index 0000000..0659cf9
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/hardware.h
+@@ -0,0 +1,46 @@
++/*
++ * include/asm-arm/arch-iop33x/hardware.h
++ */
++
++#ifndef __HARDWARE_H
++#define __HARDWARE_H
++
++#include <asm/types.h>
++
++/*
++ * Note about PCI IO space mappings
++ *
++ * To make IO space accesses efficient, we store virtual addresses in
++ * the IO resources.
++ *
++ * The PCI IO space is located at virtual 0xfe000000 from physical
++ * 0x90000000. The PCI BARs must be programmed with physical addresses,
++ * but when we read them, we convert them to virtual addresses. See
++ * arch/arm/mach-iop3xx/iop3xx-pci.c
++ */
++#define pcibios_assign_all_busses() 1
++#define PCIBIOS_MIN_IO 0x00000000
++#define PCIBIOS_MIN_MEM 0x00000000
++
++#ifndef __ASSEMBLY__
++void iop33x_init_irq(void);
++
++extern struct platform_device iop33x_uart0_device;
++extern struct platform_device iop33x_uart1_device;
++#endif
++
++
++/*
++ * Generic chipset bits
++ *
++ */
++#include "iop33x.h"
++
++/*
++ * Board specific bits
++ */
++#include "iq80331.h"
++#include "iq80332.h"
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/io.h b/include/asm-arm/arch-iop33x/io.h
+new file mode 100644
+index 0000000..c017402
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/io.h
+@@ -0,0 +1,21 @@
++/*
++ * include/asm-arm/arch-iop33x/io.h
++ *
++ * 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.
++ */
++
++#ifndef __IO_H
++#define __IO_H
++
++#include <asm/hardware.h>
++
++#define IO_SPACE_LIMIT 0xffffffff
++#define __io(p) ((void __iomem *)(p))
++#define __mem_pci(a) (a)
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/iop33x.h b/include/asm-arm/arch-iop33x/iop33x.h
+new file mode 100644
+index 0000000..7ac6e93
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/iop33x.h
+@@ -0,0 +1,33 @@
++/*
++ * include/asm-arm/arch-iop33x/iop33x.h
++ *
++ * Intel IOP33X Chip definitions
++ *
++ * Author: Dave Jiang (dave.jiang at intel.com)
++ * Copyright (C) 2003, 2004 Intel Corp.
++ *
++ * 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 __IOP33X_H
++#define __IOP33X_H
++
++/*
++ * Peripherals that are shared between the iop32x and iop33x but
++ * located at different addresses.
++ */
++#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1780 + (reg))
++#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07d0 + (reg))
++
++#include <asm/hardware/iop3xx.h>
++
++/* UARTs */
++#define IOP33X_UART0_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1700)
++#define IOP33X_UART0_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1700)
++#define IOP33X_UART1_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740)
++#define IOP33X_UART1_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740)
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/iq80331.h b/include/asm-arm/arch-iop33x/iq80331.h
+new file mode 100644
+index 0000000..79b9302
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/iq80331.h
+@@ -0,0 +1,16 @@
++/*
++ * include/asm-arm/arch-iop33x/iq80331.h
++ *
++ * Intel IQ80331 evaluation board registers
++ */
++
++#ifndef __IQ80331_H
++#define __IQ80331_H
++
++#define IQ80331_7SEG_1 0xce840000 /* 7-Segment MSB */
++#define IQ80331_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */
++#define IQ80331_ROTARY_SW 0xce8d0000 /* Rotary Switch */
++#define IQ80331_BATT_STAT 0xce8f0000 /* Battery Status */
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/iq80332.h b/include/asm-arm/arch-iop33x/iq80332.h
+new file mode 100644
+index 0000000..0531656
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/iq80332.h
+@@ -0,0 +1,16 @@
++/*
++ * include/asm-arm/arch-iop33x/iq80332.h
++ *
++ * Intel IQ80332 evaluation board registers
++ */
++
++#ifndef __IQ80332_H
++#define __IQ80332_H
++
++#define IQ80332_7SEG_1 0xce840000 /* 7-Segment MSB */
++#define IQ80332_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */
++#define IQ80332_ROTARY_SW 0xce8d0000 /* Rotary Switch */
++#define IQ80332_BATT_STAT 0xce8f0000 /* Battery Status */
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/irqs.h b/include/asm-arm/arch-iop33x/irqs.h
+new file mode 100644
+index 0000000..d045f84
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/irqs.h
+@@ -0,0 +1,60 @@
++/*
++ * include/asm-arm/arch-iop33x/irqs.h
++ *
++ * Author: Dave Jiang (dave.jiang at intel.com)
++ * Copyright: (C) 2003 Intel Corp.
++ *
++ * 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 __IRQS_H
++#define __IRQS_H
++
++/*
++ * IOP80331 chipset interrupts
++ */
++#define IRQ_IOP33X_DMA0_EOT 0
++#define IRQ_IOP33X_DMA0_EOC 1
++#define IRQ_IOP33X_DMA1_EOT 2
++#define IRQ_IOP33X_DMA1_EOC 3
++#define IRQ_IOP33X_AA_EOT 6
++#define IRQ_IOP33X_AA_EOC 7
++#define IRQ_IOP33X_TIMER0 8
++#define IRQ_IOP33X_TIMER1 9
++#define IRQ_IOP33X_I2C_0 10
++#define IRQ_IOP33X_I2C_1 11
++#define IRQ_IOP33X_MSG 12
++#define IRQ_IOP33X_MSGIBQ 13
++#define IRQ_IOP33X_ATU_BIST 14
++#define IRQ_IOP33X_PERFMON 15
++#define IRQ_IOP33X_CORE_PMU 16
++#define IRQ_IOP33X_XINT0 24
++#define IRQ_IOP33X_XINT1 25
++#define IRQ_IOP33X_XINT2 26
++#define IRQ_IOP33X_XINT3 27
++#define IRQ_IOP33X_XINT8 32
++#define IRQ_IOP33X_XINT9 33
++#define IRQ_IOP33X_XINT10 34
++#define IRQ_IOP33X_XINT11 35
++#define IRQ_IOP33X_XINT12 36
++#define IRQ_IOP33X_XINT13 37
++#define IRQ_IOP33X_XINT14 38
++#define IRQ_IOP33X_XINT15 39
++#define IRQ_IOP33X_UART0 51
++#define IRQ_IOP33X_UART1 52
++#define IRQ_IOP33X_PBIE 53
++#define IRQ_IOP33X_ATU_CRW 54
++#define IRQ_IOP33X_ATU_ERR 55
++#define IRQ_IOP33X_MCU_ERR 56
++#define IRQ_IOP33X_DMA0_ERR 57
++#define IRQ_IOP33X_DMA1_ERR 58
++#define IRQ_IOP33X_AA_ERR 60
++#define IRQ_IOP33X_MSG_ERR 62
++#define IRQ_IOP33X_HPI 63
++
++#define NR_IRQS 64
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/memory.h b/include/asm-arm/arch-iop33x/memory.h
+new file mode 100644
+index 0000000..0d39139
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/memory.h
+@@ -0,0 +1,26 @@
++/*
++ * include/asm-arm/arch-iop33x/memory.h
++ */
++
++#ifndef __MEMORY_H
++#define __MEMORY_H
++
++#include <asm/hardware.h>
++
++/*
++ * Physical DRAM offset.
++ */
++#define PHYS_OFFSET UL(0x00000000)
++
++/*
++ * Virtual view <-> PCI DMA view memory address translations
++ * virt_to_bus: Used to translate the virtual address to an
++ * address suitable to be passed to set_dma_addr
++ * bus_to_virt: Used to convert an address for DMA operations
++ * to an address that the kernel can use.
++ */
++#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0))
++#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2)))
++
++
++#endif
+diff --git a/include/asm-arm/arch-iop33x/system.h b/include/asm-arm/arch-iop33x/system.h
+new file mode 100644
+index 0000000..00dd07e
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/system.h
+@@ -0,0 +1,22 @@
++/*
++ * include/asm-arm/arch-iop33x/system.h
++ *
++ * 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.
++ */
++
++static inline void arch_idle(void)
++{
++ cpu_do_idle();
++}
++
++static inline void arch_reset(char mode)
++{
++ *IOP3XX_PCSR = 0x30;
++
++ /* Jump into ROM at address 0 */
++ cpu_reset(0);
++}
+diff --git a/include/asm-arm/arch-iop33x/timex.h b/include/asm-arm/arch-iop33x/timex.h
+new file mode 100644
+index 0000000..fe3e1e3
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/timex.h
+@@ -0,0 +1,9 @@
++/*
++ * include/asm-arm/arch-iop33x/timex.h
++ *
++ * IOP3xx architecture timex specifications
++ */
++
++#include <asm/hardware.h>
++
++#define CLOCK_TICK_RATE (100 * HZ)
+diff --git a/include/asm-arm/arch-iop33x/uncompress.h b/include/asm-arm/arch-iop33x/uncompress.h
+new file mode 100644
+index 0000000..e17fbc0
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/uncompress.h
+@@ -0,0 +1,37 @@
++/*
++ * include/asm-arm/arch-iop33x/uncompress.h
++ */
++
++#include <asm/types.h>
++#include <asm/mach-types.h>
++#include <linux/serial_reg.h>
++#include <asm/hardware.h>
++
++static volatile u32 *uart_base;
++
++#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
++
++static inline void putc(char c)
++{
++ while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
++ barrier();
++ uart_base[UART_TX] = c;
++}
++
++static inline void flush(void)
++{
++}
++
++static __inline__ void __arch_decomp_setup(unsigned long arch_id)
++{
++ if (machine_is_iq80331() || machine_is_iq80332())
++ uart_base = (volatile u32 *)IOP33X_UART0_PHYS;
++ else
++ uart_base = (volatile u32 *)0xfe800000;
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup() __arch_decomp_setup(arch_id)
++#define arch_decomp_wdog()
+diff --git a/include/asm-arm/arch-iop33x/vmalloc.h b/include/asm-arm/arch-iop33x/vmalloc.h
+new file mode 100644
+index 0000000..66f545a
+--- /dev/null
++++ b/include/asm-arm/arch-iop33x/vmalloc.h
+@@ -0,0 +1,5 @@
++/*
++ * include/asm-arm/arch-iop33x/vmalloc.h
++ */
++
++#define VMALLOC_END 0xfe000000
+diff --git a/include/asm-arm/arch-iop3xx/debug-macro.S b/include/asm-arm/arch-iop3xx/debug-macro.S
+deleted file mode 100644
+index ce007e5..0000000
+--- a/include/asm-arm/arch-iop3xx/debug-macro.S
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/* linux/include/asm-arm/arch-iop3xx/debug-macro.S
+- *
+- * Debugging macro include header
+- *
+- * Copyright (C) 1994-1999 Russell King
+- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- *
+-*/
+-
+- .macro addruart,rx
+- mov \rx, #0xfe000000 @ physical
+-#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244)
+- orr \rx, \rx, #0x00800000 @ location of the UART
+-#elif defined(CONFIG_ARCH_IOP331)
+- mrc p15, 0, \rx, c1, c0
+- tst \rx, #1 @ MMU enabled?
+- moveq \rx, #0x000fe000 @ Physical Base
+- movne \rx, #0
+- orr \rx, \rx, #0xfe000000
+- orr \rx, \rx, #0x00f00000 @ Virtual Base
+- orr \rx, \rx, #0x00001700 @ location of the UART
+-#else
+-#error Unknown IOP3XX implementation
+-#endif
+- .endm
+-
+-#if !defined(CONFIG_ARCH_IQ80321) || !defined(CONFIG_ARCH_IQ31244) || !defined(CONFIG_ARCH_IQ80331)
+-#define FLOW_CONTROL
+-#endif
+-#define UART_SHIFT 0
+-#include <asm/hardware/debug-8250.S>
+diff --git a/include/asm-arm/arch-iop3xx/dma.h b/include/asm-arm/arch-iop3xx/dma.h
+deleted file mode 100644
+index 1e808db..0000000
+--- a/include/asm-arm/arch-iop3xx/dma.h
++++ /dev/null
+@@ -1,9 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/dma.h
+- *
+- * Copyright (C) 2004 Intel Corp.
+- *
+- * 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.
+- */
+diff --git a/include/asm-arm/arch-iop3xx/entry-macro.S b/include/asm-arm/arch-iop3xx/entry-macro.S
+deleted file mode 100644
+index 926668c..0000000
+--- a/include/asm-arm/arch-iop3xx/entry-macro.S
++++ /dev/null
+@@ -1,57 +0,0 @@
+-/*
+- * include/asm-arm/arch-iop3xx/entry-macro.S
+- *
+- * Low-level IRQ helper macros for IOP3xx-based platforms
+- *
+- * 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 <asm/arch/irqs.h>
+-
+-#if defined(CONFIG_ARCH_IOP321)
+- .macro disable_fiq
+- .endm
+-
+- /*
+- * Note: only deal with normal interrupts, not FIQ
+- */
+- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+- mov \irqnr, #0
+- mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC
+- cmp \irqstat, #0
+- beq 1001f
+- clz \irqnr, \irqstat
+- mov \base, #31
+- subs \irqnr,\base,\irqnr
+- add \irqnr,\irqnr,#IRQ_IOP321_DMA0_EOT
+-1001:
+- .endm
+-
+-#elif defined(CONFIG_ARCH_IOP331)
+- .macro disable_fiq
+- .endm
+-
+- /*
+- * Note: only deal with normal interrupts, not FIQ
+- */
+- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+- mov \irqnr, #0
+- mrc p6, 0, \irqstat, c4, c0, 0 @ Read IINTSRC0
+- cmp \irqstat, #0
+- bne 1002f
+- mrc p6, 0, \irqstat, c5, c0, 0 @ Read IINTSRC1
+- cmp \irqstat, #0
+- beq 1001f
+- clz \irqnr, \irqstat
+- rsbs \irqnr,\irqnr,#31 @ recommend by RMK
+- add \irqnr,\irqnr,#IRQ_IOP331_XINT8
+- b 1001f
+-1002: clz \irqnr, \irqstat
+- rsbs \irqnr,\irqnr,#31 @ recommend by RMK
+- add \irqnr,\irqnr,#IRQ_IOP331_DMA0_EOT
+-1001:
+- .endm
+-
+-#endif
+-
+diff --git a/include/asm-arm/arch-iop3xx/hardware.h b/include/asm-arm/arch-iop3xx/hardware.h
+deleted file mode 100644
+index 3b13817..0000000
+--- a/include/asm-arm/arch-iop3xx/hardware.h
++++ /dev/null
+@@ -1,57 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/hardware.h
+- */
+-#ifndef __ASM_ARCH_HARDWARE_H
+-#define __ASM_ARCH_HARDWARE_H
+-
+-#include <asm/types.h>
+-
+-/*
+- * Note about PCI IO space mappings
+- *
+- * To make IO space accesses efficient, we store virtual addresses in
+- * the IO resources.
+- *
+- * The PCI IO space is located at virtual 0xfe000000 from physical
+- * 0x90000000. The PCI BARs must be programmed with physical addresses,
+- * but when we read them, we convert them to virtual addresses. See
+- * arch/arm/mach-iop3xx/iop3xx-pci.c
+- */
+-
+-#define pcibios_assign_all_busses() 1
+-
+-
+-/*
+- * The min PCI I/O and MEM space are dependent on what specific
+- * chipset/platform we are running on, so instead of hardcoding with
+- * #ifdefs, we just fill these in the platform level PCI init code.
+- */
+-#ifndef __ASSEMBLY__
+-extern unsigned long iop3xx_pcibios_min_io;
+-extern unsigned long iop3xx_pcibios_min_mem;
+-
+-extern unsigned int processor_id;
+-#endif
+-
+-/*
+- * We just set these to zero since they are really bogus anyways
+- */
+-#define PCIBIOS_MIN_IO (iop3xx_pcibios_min_io)
+-#define PCIBIOS_MIN_MEM (iop3xx_pcibios_min_mem)
+-
+-/*
+- * Generic chipset bits
+- *
+- */
+-#include "iop321.h"
+-#include "iop331.h"
+-
+-/*
+- * Board specific bits
+- */
+-#include "iq80321.h"
+-#include "iq31244.h"
+-#include "iq80331.h"
+-#include "iq80332.h"
+-
+-#endif /* _ASM_ARCH_HARDWARE_H */
+diff --git a/include/asm-arm/arch-iop3xx/io.h b/include/asm-arm/arch-iop3xx/io.h
+deleted file mode 100644
+index 36adbdf..0000000
+--- a/include/asm-arm/arch-iop3xx/io.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/io.h
+- *
+- * 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.
+- */
+-
+-#ifndef __ASM_ARM_ARCH_IO_H
+-#define __ASM_ARM_ARCH_IO_H
+-
+-#include <asm/hardware.h>
+-
+-#define IO_SPACE_LIMIT 0xffffffff
+-
+-#define __io(p) ((void __iomem *)(p))
+-#define __mem_pci(a) (a)
+-
+-#endif
+diff --git a/include/asm-arm/arch-iop3xx/iop321-irqs.h b/include/asm-arm/arch-iop3xx/iop321-irqs.h
+deleted file mode 100644
+index 2fcc165..0000000
+--- a/include/asm-arm/arch-iop3xx/iop321-irqs.h
++++ /dev/null
+@@ -1,100 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/irqs.h
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright: (C) 2002 Rory Bolt
+- *
+- * 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 _IOP321_IRQS_H_
+-#define _IOP321_IRQS_H_
+-
+-/*
+- * IOP80321 chipset interrupts
+- */
+-#define IOP321_IRQ_OFS 0
+-#define IOP321_IRQ(x) (IOP321_IRQ_OFS + (x))
+-
+-/*
+- * On IRQ or FIQ register
+- */
+-#define IRQ_IOP321_DMA0_EOT IOP321_IRQ(0)
+-#define IRQ_IOP321_DMA0_EOC IOP321_IRQ(1)
+-#define IRQ_IOP321_DMA1_EOT IOP321_IRQ(2)
+-#define IRQ_IOP321_DMA1_EOC IOP321_IRQ(3)
+-#define IRQ_IOP321_RSVD_4 IOP321_IRQ(4)
+-#define IRQ_IOP321_RSVD_5 IOP321_IRQ(5)
+-#define IRQ_IOP321_AA_EOT IOP321_IRQ(6)
+-#define IRQ_IOP321_AA_EOC IOP321_IRQ(7)
+-#define IRQ_IOP321_CORE_PMON IOP321_IRQ(8)
+-#define IRQ_IOP321_TIMER0 IOP321_IRQ(9)
+-#define IRQ_IOP321_TIMER1 IOP321_IRQ(10)
+-#define IRQ_IOP321_I2C_0 IOP321_IRQ(11)
+-#define IRQ_IOP321_I2C_1 IOP321_IRQ(12)
+-#define IRQ_IOP321_MESSAGING IOP321_IRQ(13)
+-#define IRQ_IOP321_ATU_BIST IOP321_IRQ(14)
+-#define IRQ_IOP321_PERFMON IOP321_IRQ(15)
+-#define IRQ_IOP321_CORE_PMU IOP321_IRQ(16)
+-#define IRQ_IOP321_BIU_ERR IOP321_IRQ(17)
+-#define IRQ_IOP321_ATU_ERR IOP321_IRQ(18)
+-#define IRQ_IOP321_MCU_ERR IOP321_IRQ(19)
+-#define IRQ_IOP321_DMA0_ERR IOP321_IRQ(20)
+-#define IRQ_IOP321_DMA1_ERR IOP321_IRQ(21)
+-#define IRQ_IOP321_RSVD_22 IOP321_IRQ(22)
+-#define IRQ_IOP321_AA_ERR IOP321_IRQ(23)
+-#define IRQ_IOP321_MSG_ERR IOP321_IRQ(24)
+-#define IRQ_IOP321_SSP IOP321_IRQ(25)
+-#define IRQ_IOP321_RSVD_26 IOP321_IRQ(26)
+-#define IRQ_IOP321_XINT0 IOP321_IRQ(27)
+-#define IRQ_IOP321_XINT1 IOP321_IRQ(28)
+-#define IRQ_IOP321_XINT2 IOP321_IRQ(29)
+-#define IRQ_IOP321_XINT3 IOP321_IRQ(30)
+-#define IRQ_IOP321_HPI IOP321_IRQ(31)
+-
+-#define NR_IOP321_IRQS (IOP321_IRQ(31) + 1)
+-
+-#define NR_IRQS NR_IOP321_IRQS
+-
+-
+-/*
+- * Interrupts available on the IQ80321 board
+- */
+-
+-/*
+- * On board devices
+- */
+-#define IRQ_IQ80321_I82544 IRQ_IOP321_XINT0
+-#define IRQ_IQ80321_UART IRQ_IOP321_XINT1
+-
+-/*
+- * PCI interrupts
+- */
+-#define IRQ_IQ80321_INTA IRQ_IOP321_XINT0
+-#define IRQ_IQ80321_INTB IRQ_IOP321_XINT1
+-#define IRQ_IQ80321_INTC IRQ_IOP321_XINT2
+-#define IRQ_IQ80321_INTD IRQ_IOP321_XINT3
+-
+-/*
+- * Interrupts on the IQ31244 board
+- */
+-
+-/*
+- * On board devices
+- */
+-#define IRQ_IQ31244_UART IRQ_IOP321_XINT1
+-#define IRQ_IQ31244_I82546 IRQ_IOP321_XINT0
+-#define IRQ_IQ31244_SATA IRQ_IOP321_XINT2
+-#define IRQ_IQ31244_PCIX_SLOT IRQ_IOP321_XINT3
+-
+-/*
+- * PCI interrupts
+- */
+-#define IRQ_IQ31244_INTA IRQ_IOP321_XINT0
+-#define IRQ_IQ31244_INTB IRQ_IOP321_XINT1
+-#define IRQ_IQ31244_INTC IRQ_IOP321_XINT2
+-#define IRQ_IQ31244_INTD IRQ_IOP321_XINT3
+-
+-#endif // _IOP321_IRQ_H_
+diff --git a/include/asm-arm/arch-iop3xx/iop321.h b/include/asm-arm/arch-iop3xx/iop321.h
+deleted file mode 100644
+index f8df778..0000000
+--- a/include/asm-arm/arch-iop3xx/iop321.h
++++ /dev/null
+@@ -1,345 +0,0 @@
+-/*
+- * linux/include/asm/arch-iop3xx/iop321.h
+- *
+- * Intel IOP321 Chip definitions
+- *
+- * Author: Rory Bolt <rorybolt at pacbell.net>
+- * Copyright (C) 2002 Rory Bolt
+- * Copyright (C) 2004 Intel Corp.
+- *
+- * 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 _IOP321_HW_H_
+-#define _IOP321_HW_H_
+-
+-
+-/*
+- * This is needed for mixed drivers that need to work on all
+- * IOP3xx variants but behave slightly differently on each.
+- */
+-#ifndef __ASSEMBLY__
+-#ifdef CONFIG_ARCH_IOP321
+-#define iop_is_321() (((processor_id & 0xfffff5e0) == 0x69052420))
+-#else
+-#define iop_is_321() 0
+-#endif
+-#endif
+-
+-/*
+- * IOP321 I/O and Mem space regions for PCI autoconfiguration
+- */
+-#define IOP321_PCI_IO_WINDOW_SIZE 0x00010000
+-#define IOP321_PCI_LOWER_IO_PA 0x90000000
+-#define IOP321_PCI_LOWER_IO_VA 0xfe000000
+-#define IOP321_PCI_LOWER_IO_BA (*IOP321_OIOWTVR)
+-#define IOP321_PCI_UPPER_IO_PA (IOP321_PCI_LOWER_IO_PA + IOP321_PCI_IO_WINDOW_SIZE - 1)
+-#define IOP321_PCI_UPPER_IO_VA (IOP321_PCI_LOWER_IO_VA + IOP321_PCI_IO_WINDOW_SIZE - 1)
+-#define IOP321_PCI_UPPER_IO_BA (IOP321_PCI_LOWER_IO_BA + IOP321_PCI_IO_WINDOW_SIZE - 1)
+-#define IOP321_PCI_IO_OFFSET (IOP321_PCI_LOWER_IO_VA - IOP321_PCI_LOWER_IO_BA)
+-
+-/* #define IOP321_PCI_MEM_WINDOW_SIZE (~*IOP321_IALR1 + 1) */
+-#define IOP321_PCI_MEM_WINDOW_SIZE 0x04000000 /* 64M outbound window */
+-#define IOP321_PCI_LOWER_MEM_PA 0x80000000
+-#define IOP321_PCI_LOWER_MEM_BA (*IOP321_OMWTVR0)
+-#define IOP321_PCI_UPPER_MEM_PA (IOP321_PCI_LOWER_MEM_PA + IOP321_PCI_MEM_WINDOW_SIZE - 1)
+-#define IOP321_PCI_UPPER_MEM_BA (IOP321_PCI_LOWER_MEM_BA + IOP321_PCI_MEM_WINDOW_SIZE - 1)
+-#define IOP321_PCI_MEM_OFFSET (IOP321_PCI_LOWER_MEM_PA - IOP321_PCI_LOWER_MEM_BA)
+-
+-
+-/*
+- * IOP321 chipset registers
+- */
+-#define IOP321_VIRT_MEM_BASE 0xfeffe000 /* chip virtual mem address*/
+-#define IOP321_PHYS_MEM_BASE 0xffffe000 /* chip physical memory address */
+-#define IOP321_REG_ADDR(reg) (IOP321_VIRT_MEM_BASE | (reg))
+-
+-/* Reserved 0x00000000 through 0x000000FF */
+-
+-/* Address Translation Unit 0x00000100 through 0x000001FF */
+-#define IOP321_ATUVID (volatile u16 *)IOP321_REG_ADDR(0x00000100)
+-#define IOP321_ATUDID (volatile u16 *)IOP321_REG_ADDR(0x00000102)
+-#define IOP321_ATUCMD (volatile u16 *)IOP321_REG_ADDR(0x00000104)
+-#define IOP321_ATUSR (volatile u16 *)IOP321_REG_ADDR(0x00000106)
+-#define IOP321_ATURID (volatile u8 *)IOP321_REG_ADDR(0x00000108)
+-#define IOP321_ATUCCR (volatile u32 *)IOP321_REG_ADDR(0x00000109)
+-#define IOP321_ATUCLSR (volatile u8 *)IOP321_REG_ADDR(0x0000010C)
+-#define IOP321_ATULT (volatile u8 *)IOP321_REG_ADDR(0x0000010D)
+-#define IOP321_ATUHTR (volatile u8 *)IOP321_REG_ADDR(0x0000010E)
+-#define IOP321_ATUBIST (volatile u8 *)IOP321_REG_ADDR(0x0000010F)
+-#define IOP321_IABAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000110)
+-#define IOP321_IAUBAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000114)
+-#define IOP321_IABAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000118)
+-#define IOP321_IAUBAR1 (volatile u32 *)IOP321_REG_ADDR(0x0000011C)
+-#define IOP321_IABAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000120)
+-#define IOP321_IAUBAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000124)
+-#define IOP321_ASVIR (volatile u16 *)IOP321_REG_ADDR(0x0000012C)
+-#define IOP321_ASIR (volatile u16 *)IOP321_REG_ADDR(0x0000012E)
+-#define IOP321_ERBAR (volatile u32 *)IOP321_REG_ADDR(0x00000130)
+-/* Reserved 0x00000134 through 0x0000013B */
+-#define IOP321_ATUILR (volatile u8 *)IOP321_REG_ADDR(0x0000013C)
+-#define IOP321_ATUIPR (volatile u8 *)IOP321_REG_ADDR(0x0000013D)
+-#define IOP321_ATUMGNT (volatile u8 *)IOP321_REG_ADDR(0x0000013E)
+-#define IOP321_ATUMLAT (volatile u8 *)IOP321_REG_ADDR(0x0000013F)
+-#define IOP321_IALR0 (volatile u32 *)IOP321_REG_ADDR(0x00000140)
+-#define IOP321_IATVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000144)
+-#define IOP321_ERLR (volatile u32 *)IOP321_REG_ADDR(0x00000148)
+-#define IOP321_ERTVR (volatile u32 *)IOP321_REG_ADDR(0x0000014C)
+-#define IOP321_IALR1 (volatile u32 *)IOP321_REG_ADDR(0x00000150)
+-#define IOP321_IALR2 (volatile u32 *)IOP321_REG_ADDR(0x00000154)
+-#define IOP321_IATVR2 (volatile u32 *)IOP321_REG_ADDR(0x00000158)
+-#define IOP321_OIOWTVR (volatile u32 *)IOP321_REG_ADDR(0x0000015C)
+-#define IOP321_OMWTVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000160)
+-#define IOP321_OUMWTVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000164)
+-#define IOP321_OMWTVR1 (volatile u32 *)IOP321_REG_ADDR(0x00000168)
+-#define IOP321_OUMWTVR1 (volatile u32 *)IOP321_REG_ADDR(0x0000016C)
+-/* Reserved 0x00000170 through 0x00000177*/
+-#define IOP321_OUDWTVR (volatile u32 *)IOP321_REG_ADDR(0x00000178)
+-/* Reserved 0x0000017C through 0x0000017F*/
+-#define IOP321_ATUCR (volatile u32 *)IOP321_REG_ADDR(0x00000180)
+-#define IOP321_PCSR (volatile u32 *)IOP321_REG_ADDR(0x00000184)
+-#define IOP321_ATUISR (volatile u32 *)IOP321_REG_ADDR(0x00000188)
+-#define IOP321_ATUIMR (volatile u32 *)IOP321_REG_ADDR(0x0000018C)
+-#define IOP321_IABAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000190)
+-#define IOP321_IAUBAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000194)
+-#define IOP321_IALR3 (volatile u32 *)IOP321_REG_ADDR(0x00000198)
+-#define IOP321_IATVR3 (volatile u32 *)IOP321_REG_ADDR(0x0000019C)
+-/* Reserved 0x000001A0 through 0x000001A3*/
+-#define IOP321_OCCAR (volatile u32 *)IOP321_REG_ADDR(0x000001A4)
+-/* Reserved 0x000001A8 through 0x000001AB*/
+-#define IOP321_OCCDR (volatile u32 *)IOP321_REG_ADDR(0x000001AC)
+-/* Reserved 0x000001B0 through 0x000001BB*/
+-#define IOP321_PDSCR (volatile u32 *)IOP321_REG_ADDR(0x000001BC)
+-#define IOP321_PMCAPID (volatile u8 *)IOP321_REG_ADDR(0x000001C0)
+-#define IOP321_PMNEXT (volatile u8 *)IOP321_REG_ADDR(0x000001C1)
+-#define IOP321_APMCR (volatile u16 *)IOP321_REG_ADDR(0x000001C2)
+-#define IOP321_APMCSR (volatile u16 *)IOP321_REG_ADDR(0x000001C4)
+-/* Reserved 0x000001C6 through 0x000001DF */
+-#define IOP321_PCIXCAPID (volatile u8 *)IOP321_REG_ADDR(0x000001E0)
+-#define IOP321_PCIXNEXT (volatile u8 *)IOP321_REG_ADDR(0x000001E1)
+-#define IOP321_PCIXCMD (volatile u16 *)IOP321_REG_ADDR(0x000001E2)
+-#define IOP321_PCIXSR (volatile u32 *)IOP321_REG_ADDR(0x000001E4)
+-#define IOP321_PCIIRSR (volatile u32 *)IOP321_REG_ADDR(0x000001EC)
+-
+-/* Messaging Unit 0x00000300 through 0x000003FF */
+-
+-/* Reserved 0x00000300 through 0x0000030c */
+-#define IOP321_IMR0 (volatile u32 *)IOP321_REG_ADDR(0x00000310)
+-#define IOP321_IMR1 (volatile u32 *)IOP321_REG_ADDR(0x00000314)
+-#define IOP321_OMR0 (volatile u32 *)IOP321_REG_ADDR(0x00000318)
+-#define IOP321_OMR1 (volatile u32 *)IOP321_REG_ADDR(0x0000031C)
+-#define IOP321_IDR (volatile u32 *)IOP321_REG_ADDR(0x00000320)
+-#define IOP321_IISR (volatile u32 *)IOP321_REG_ADDR(0x00000324)
+-#define IOP321_IIMR (volatile u32 *)IOP321_REG_ADDR(0x00000328)
+-#define IOP321_ODR (volatile u32 *)IOP321_REG_ADDR(0x0000032C)
+-#define IOP321_OISR (volatile u32 *)IOP321_REG_ADDR(0x00000330)
+-#define IOP321_OIMR (volatile u32 *)IOP321_REG_ADDR(0x00000334)
+-/* Reserved 0x00000338 through 0x0000034F */
+-#define IOP321_MUCR (volatile u32 *)IOP321_REG_ADDR(0x00000350)
+-#define IOP321_QBAR (volatile u32 *)IOP321_REG_ADDR(0x00000354)
+-/* Reserved 0x00000358 through 0x0000035C */
+-#define IOP321_IFHPR (volatile u32 *)IOP321_REG_ADDR(0x00000360)
+-#define IOP321_IFTPR (volatile u32 *)IOP321_REG_ADDR(0x00000364)
+-#define IOP321_IPHPR (volatile u32 *)IOP321_REG_ADDR(0x00000368)
+-#define IOP321_IPTPR (volatile u32 *)IOP321_REG_ADDR(0x0000036C)
+-#define IOP321_OFHPR (volatile u32 *)IOP321_REG_ADDR(0x00000370)
+-#define IOP321_OFTPR (volatile u32 *)IOP321_REG_ADDR(0x00000374)
+-#define IOP321_OPHPR (volatile u32 *)IOP321_REG_ADDR(0x00000378)
+-#define IOP321_OPTPR (volatile u32 *)IOP321_REG_ADDR(0x0000037C)
+-#define IOP321_IAR (volatile u32 *)IOP321_REG_ADDR(0x00000380)
+-
+-#define IOP321_IIxR_MASK 0x7f /* masks all */
+-#define IOP321_IIxR_IRI 0x40 /* RC Index Register Interrupt */
+-#define IOP321_IIxR_OFQF 0x20 /* RC Output Free Q Full (ERROR) */
+-#define IOP321_IIxR_ipq 0x10 /* RC Inbound Post Q (post) */
+-#define IOP321_IIxR_ERRDI 0x08 /* RO Error Doorbell Interrupt */
+-#define IOP321_IIxR_IDI 0x04 /* RO Inbound Doorbell Interrupt */
+-#define IOP321_IIxR_IM1 0x02 /* RC Inbound Message 1 Interrupt */
+-#define IOP321_IIxR_IM0 0x01 /* RC Inbound Message 0 Interrupt */
+-
+-/* Reserved 0x00000384 through 0x000003FF */
+-
+-/* DMA Controller 0x00000400 through 0x000004FF */
+-#define IOP321_DMA0_CCR (volatile u32 *)IOP321_REG_ADDR(0x00000400)
+-#define IOP321_DMA0_CSR (volatile u32 *)IOP321_REG_ADDR(0x00000404)
+-#define IOP321_DMA0_DAR (volatile u32 *)IOP321_REG_ADDR(0x0000040C)
+-#define IOP321_DMA0_NDAR (volatile u32 *)IOP321_REG_ADDR(0x00000410)
+-#define IOP321_DMA0_PADR (volatile u32 *)IOP321_REG_ADDR(0x00000414)
+-#define IOP321_DMA0_PUADR (volatile u32 *)IOP321_REG_ADDR(0x00000418)
+-#define IOP321_DMA0_LADR (volatile u32 *)IOP321_REG_ADDR(0X0000041C)
+-#define IOP321_DMA0_BCR (volatile u32 *)IOP321_REG_ADDR(0x00000420)
+-#define IOP321_DMA0_DCR (volatile u32 *)IOP321_REG_ADDR(0x00000424)
+-/* Reserved 0x00000428 through 0x0000043C */
+-#define IOP321_DMA1_CCR (volatile u32 *)IOP321_REG_ADDR(0x00000440)
+-#define IOP321_DMA1_CSR (volatile u32 *)IOP321_REG_ADDR(0x00000444)
+-#define IOP321_DMA1_DAR (volatile u32 *)IOP321_REG_ADDR(0x0000044C)
+-#define IOP321_DMA1_NDAR (volatile u32 *)IOP321_REG_ADDR(0x00000450)
+-#define IOP321_DMA1_PADR (volatile u32 *)IOP321_REG_ADDR(0x00000454)
+-#define IOP321_DMA1_PUADR (volatile u32 *)IOP321_REG_ADDR(0x00000458)
+-#define IOP321_DMA1_LADR (volatile u32 *)IOP321_REG_ADDR(0x0000045C)
+-#define IOP321_DMA1_BCR (volatile u32 *)IOP321_REG_ADDR(0x00000460)
+-#define IOP321_DMA1_DCR (volatile u32 *)IOP321_REG_ADDR(0x00000464)
+-/* Reserved 0x00000468 through 0x000004FF */
+-
+-/* Memory controller 0x00000500 through 0x0005FF */
+-
+-/* Peripheral bus interface unit 0x00000680 through 0x0006FF */
+-#define IOP321_PBCR (volatile u32 *)IOP321_REG_ADDR(0x00000680)
+-#define IOP321_PBISR (volatile u32 *)IOP321_REG_ADDR(0x00000684)
+-#define IOP321_PBBAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000688)
+-#define IOP321_PBLR0 (volatile u32 *)IOP321_REG_ADDR(0x0000068C)
+-#define IOP321_PBBAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000690)
+-#define IOP321_PBLR1 (volatile u32 *)IOP321_REG_ADDR(0x00000694)
+-#define IOP321_PBBAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000698)
+-#define IOP321_PBLR2 (volatile u32 *)IOP321_REG_ADDR(0x0000069C)
+-#define IOP321_PBBAR3 (volatile u32 *)IOP321_REG_ADDR(0x000006A0)
+-#define IOP321_PBLR3 (volatile u32 *)IOP321_REG_ADDR(0x000006A4)
+-#define IOP321_PBBAR4 (volatile u32 *)IOP321_REG_ADDR(0x000006A8)
+-#define IOP321_PBLR4 (volatile u32 *)IOP321_REG_ADDR(0x000006AC)
+-#define IOP321_PBBAR5 (volatile u32 *)IOP321_REG_ADDR(0x000006B0)
+-#define IOP321_PBLR5 (volatile u32 *)IOP321_REG_ADDR(0x000006B4)
+-#define IOP321_PBDSCR (volatile u32 *)IOP321_REG_ADDR(0x000006B8)
+-/* Reserved 0x000006BC */
+-#define IOP321_PMBR0 (volatile u32 *)IOP321_REG_ADDR(0x000006C0)
+-/* Reserved 0x000006C4 through 0x000006DC */
+-#define IOP321_PMBR1 (volatile u32 *)IOP321_REG_ADDR(0x000006E0)
+-#define IOP321_PMBR2 (volatile u32 *)IOP321_REG_ADDR(0x000006E4)
+-
+-#define IOP321_PBCR_EN 0x1
+-
+-#define IOP321_PBISR_BOOR_ERR 0x1
+-
+-/* Peripheral performance monitoring unit 0x00000700 through 0x00077F */
+-#define IOP321_GTMR (volatile u32 *)IOP321_REG_ADDR(0x00000700)
+-#define IOP321_ESR (volatile u32 *)IOP321_REG_ADDR(0x00000704)
+-#define IOP321_EMISR (volatile u32 *)IOP321_REG_ADDR(0x00000708)
+-/* reserved 0x00000070c */
+-#define IOP321_GTSR (volatile u32 *)IOP321_REG_ADDR(0x00000710)
+-/* PERC0 DOESN'T EXIST - index from 1! */
+-#define IOP321_PERCR0 (volatile u32 *)IOP321_REG_ADDR(0x00000710)
+-
+-#define IOP321_GTMR_NGCE 0x04 /* (Not) Global Counter Enable */
+-
+-/* Internal arbitration unit 0x00000780 through 0x0007BF */
+-#define IOP321_IACR (volatile u32 *)IOP321_REG_ADDR(0x00000780)
+-#define IOP321_MTTR1 (volatile u32 *)IOP321_REG_ADDR(0x00000784)
+-#define IOP321_MTTR2 (volatile u32 *)IOP321_REG_ADDR(0x00000788)
+-
+-/* General Purpose I/O Registers */
+-#define IOP321_GPOE (volatile u32 *)IOP321_REG_ADDR(0x000007C4)
+-#define IOP321_GPID (volatile u32 *)IOP321_REG_ADDR(0x000007C8)
+-#define IOP321_GPOD (volatile u32 *)IOP321_REG_ADDR(0x000007CC)
+-
+-/* Interrupt Controller */
+-#define IOP321_INTCTL (volatile u32 *)IOP321_REG_ADDR(0x000007D0)
+-#define IOP321_INTSTR (volatile u32 *)IOP321_REG_ADDR(0x000007D4)
+-#define IOP321_IINTSRC (volatile u32 *)IOP321_REG_ADDR(0x000007D8)
+-#define IOP321_FINTSRC (volatile u32 *)IOP321_REG_ADDR(0x000007DC)
+-
+-/* Timers */
+-
+-#define IOP321_TU_TMR0 (volatile u32 *)IOP321_REG_ADDR(0x000007E0)
+-#define IOP321_TU_TMR1 (volatile u32 *)IOP321_REG_ADDR(0x000007E4)
+-
+-#ifdef CONFIG_ARCH_IQ80321
+-#define IOP321_TICK_RATE 200000000 /* 200 MHz clock */
+-#elif defined(CONFIG_ARCH_IQ31244)
+-#define IOP321_TICK_RATE 198000000 /* 33.000 MHz crystal */
+-#endif
+-
+-#ifdef CONFIG_ARCH_EP80219
+-#undef IOP321_TICK_RATE
+-#define IOP321_TICK_RATE 200000000 /* 33.333333 Mhz crystal */
+-#endif
+-
+-#define IOP321_TMR_TC 0x01
+-#define IOP321_TMR_EN 0x02
+-#define IOP321_TMR_RELOAD 0x04
+-#define IOP321_TMR_PRIVILEGED 0x09
+-
+-#define IOP321_TMR_RATIO_1_1 0x00
+-#define IOP321_TMR_RATIO_4_1 0x10
+-#define IOP321_TMR_RATIO_8_1 0x20
+-#define IOP321_TMR_RATIO_16_1 0x30
+-
+-#define IOP321_TU_TCR0 (volatile u32 *)IOP321_REG_ADDR(0x000007E8)
+-#define IOP321_TU_TCR1 (volatile u32 *)IOP321_REG_ADDR(0x000007EC)
+-#define IOP321_TU_TRR0 (volatile u32 *)IOP321_REG_ADDR(0x000007F0)
+-#define IOP321_TU_TRR1 (volatile u32 *)IOP321_REG_ADDR(0x000007F4)
+-#define IOP321_TU_TISR (volatile u32 *)IOP321_REG_ADDR(0x000007F8)
+-#define IOP321_TU_WDTCR (volatile u32 *)IOP321_REG_ADDR(0x000007FC)
+-
+-/* Application accelerator unit 0x00000800 - 0x000008FF */
+-#define IOP321_AAU_ACR (volatile u32 *)IOP321_REG_ADDR(0x00000800)
+-#define IOP321_AAU_ASR (volatile u32 *)IOP321_REG_ADDR(0x00000804)
+-#define IOP321_AAU_ADAR (volatile u32 *)IOP321_REG_ADDR(0x00000808)
+-#define IOP321_AAU_ANDAR (volatile u32 *)IOP321_REG_ADDR(0x0000080C)
+-#define IOP321_AAU_SAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000810)
+-#define IOP321_AAU_SAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000814)
+-#define IOP321_AAU_SAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000818)
+-#define IOP321_AAU_SAR4 (volatile u32 *)IOP321_REG_ADDR(0x0000081C)
+-#define IOP321_AAU_SAR5 (volatile u32 *)IOP321_REG_ADDR(0x0000082C)
+-#define IOP321_AAU_SAR6 (volatile u32 *)IOP321_REG_ADDR(0x00000830)
+-#define IOP321_AAU_SAR7 (volatile u32 *)IOP321_REG_ADDR(0x00000834)
+-#define IOP321_AAU_SAR8 (volatile u32 *)IOP321_REG_ADDR(0x00000838)
+-#define IOP321_AAU_SAR9 (volatile u32 *)IOP321_REG_ADDR(0x00000840)
+-#define IOP321_AAU_SAR10 (volatile u32 *)IOP321_REG_ADDR(0x00000844)
+-#define IOP321_AAU_SAR11 (volatile u32 *)IOP321_REG_ADDR(0x00000848)
+-#define IOP321_AAU_SAR12 (volatile u32 *)IOP321_REG_ADDR(0x0000084C)
+-#define IOP321_AAU_SAR13 (volatile u32 *)IOP321_REG_ADDR(0x00000850)
+-#define IOP321_AAU_SAR14 (volatile u32 *)IOP321_REG_ADDR(0x00000854)
+-#define IOP321_AAU_SAR15 (volatile u32 *)IOP321_REG_ADDR(0x00000858)
+-#define IOP321_AAU_SAR16 (volatile u32 *)IOP321_REG_ADDR(0x0000085C)
+-#define IOP321_AAU_SAR17 (volatile u32 *)IOP321_REG_ADDR(0x00000864)
+-#define IOP321_AAU_SAR18 (volatile u32 *)IOP321_REG_ADDR(0x00000868)
+-#define IOP321_AAU_SAR19 (volatile u32 *)IOP321_REG_ADDR(0x0000086C)
+-#define IOP321_AAU_SAR20 (volatile u32 *)IOP321_REG_ADDR(0x00000870)
+-#define IOP321_AAU_SAR21 (volatile u32 *)IOP321_REG_ADDR(0x00000874)
+-#define IOP321_AAU_SAR22 (volatile u32 *)IOP321_REG_ADDR(0x00000878)
+-#define IOP321_AAU_SAR23 (volatile u32 *)IOP321_REG_ADDR(0x0000087C)
+-#define IOP321_AAU_SAR24 (volatile u32 *)IOP321_REG_ADDR(0x00000880)
+-#define IOP321_AAU_SAR25 (volatile u32 *)IOP321_REG_ADDR(0x00000888)
+-#define IOP321_AAU_SAR26 (volatile u32 *)IOP321_REG_ADDR(0x0000088C)
+-#define IOP321_AAU_SAR27 (volatile u32 *)IOP321_REG_ADDR(0x00000890)
+-#define IOP321_AAU_SAR28 (volatile u32 *)IOP321_REG_ADDR(0x00000894)
+-#define IOP321_AAU_SAR29 (volatile u32 *)IOP321_REG_ADDR(0x00000898)
+-#define IOP321_AAU_SAR30 (volatile u32 *)IOP321_REG_ADDR(0x0000089C)
+-#define IOP321_AAU_SAR31 (volatile u32 *)IOP321_REG_ADDR(0x000008A0)
+-#define IOP321_AAU_SAR32 (volatile u32 *)IOP321_REG_ADDR(0x000008A4)
+-#define IOP321_AAU_DAR (volatile u32 *)IOP321_REG_ADDR(0x00000820)
+-#define IOP321_AAU_ABCR (volatile u32 *)IOP321_REG_ADDR(0x00000824)
+-#define IOP321_AAU_ADCR (volatile u32 *)IOP321_REG_ADDR(0x00000828)
+-#define IOP321_AAU_EDCR0 (volatile u32 *)IOP321_REG_ADDR(0x0000083c)
+-#define IOP321_AAU_EDCR1 (volatile u32 *)IOP321_REG_ADDR(0x00000860)
+-#define IOP321_AAU_EDCR2 (volatile u32 *)IOP321_REG_ADDR(0x00000884)
+-
+-
+-/* SSP serial port unit 0x00001600 - 0x0000167F */
+-/* I2C bus interface unit 0x00001680 - 0x000016FF */
+-#define IOP321_ICR0 (volatile u32 *)IOP321_REG_ADDR(0x00001680)
+-#define IOP321_ISR0 (volatile u32 *)IOP321_REG_ADDR(0x00001684)
+-#define IOP321_ISAR0 (volatile u32 *)IOP321_REG_ADDR(0x00001688)
+-#define IOP321_IDBR0 (volatile u32 *)IOP321_REG_ADDR(0x0000168C)
+-/* Reserved 0x00001690 */
+-#define IOP321_IBMR0 (volatile u32 *)IOP321_REG_ADDR(0x00001694)
+-/* Reserved 0x00001698 */
+-/* Reserved 0x0000169C */
+-#define IOP321_ICR1 (volatile u32 *)IOP321_REG_ADDR(0x000016A0)
+-#define IOP321_ISR1 (volatile u32 *)IOP321_REG_ADDR(0x000016A4)
+-#define IOP321_ISAR1 (volatile u32 *)IOP321_REG_ADDR(0x000016A8)
+-#define IOP321_IDBR1 (volatile u32 *)IOP321_REG_ADDR(0x000016AC)
+-#define IOP321_IBMR1 (volatile u32 *)IOP321_REG_ADDR(0x000016B4)
+-/* Reserved 0x000016B8 through 0x000016FC */
+-
+-/* for I2C bit defs see drivers/i2c/i2c-iop3xx.h */
+-
+-
+-#ifndef __ASSEMBLY__
+-extern void iop321_map_io(void);
+-extern void iop321_init_irq(void);
+-extern void iop321_time_init(void);
+-#endif
+-
+-#endif // _IOP321_HW_H_
+diff --git a/include/asm-arm/arch-iop3xx/iop331-irqs.h b/include/asm-arm/arch-iop3xx/iop331-irqs.h
+deleted file mode 100644
+index 7135ad7..0000000
+--- a/include/asm-arm/arch-iop3xx/iop331-irqs.h
++++ /dev/null
+@@ -1,132 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/irqs.h
+- *
+- * Author: Dave Jiang (dave.jiang at intel.com)
+- * Copyright: (C) 2003 Intel Corp.
+- *
+- * 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 _IOP331_IRQS_H_
+-#define _IOP331_IRQS_H_
+-
+-/*
+- * IOP80331 chipset interrupts
+- */
+-#define IOP331_IRQ_OFS 0
+-#define IOP331_IRQ(x) (IOP331_IRQ_OFS + (x))
+-
+-/*
+- * On IRQ or FIQ register
+- */
+-#define IRQ_IOP331_DMA0_EOT IOP331_IRQ(0)
+-#define IRQ_IOP331_DMA0_EOC IOP331_IRQ(1)
+-#define IRQ_IOP331_DMA1_EOT IOP331_IRQ(2)
+-#define IRQ_IOP331_DMA1_EOC IOP331_IRQ(3)
+-#define IRQ_IOP331_RSVD_4 IOP331_IRQ(4)
+-#define IRQ_IOP331_RSVD_5 IOP331_IRQ(5)
+-#define IRQ_IOP331_AA_EOT IOP331_IRQ(6)
+-#define IRQ_IOP331_AA_EOC IOP331_IRQ(7)
+-#define IRQ_IOP331_TIMER0 IOP331_IRQ(8)
+-#define IRQ_IOP331_TIMER1 IOP331_IRQ(9)
+-#define IRQ_IOP331_I2C_0 IOP331_IRQ(10)
+-#define IRQ_IOP331_I2C_1 IOP331_IRQ(11)
+-#define IRQ_IOP331_MSG IOP331_IRQ(12)
+-#define IRQ_IOP331_MSGIBQ IOP331_IRQ(13)
+-#define IRQ_IOP331_ATU_BIST IOP331_IRQ(14)
+-#define IRQ_IOP331_PERFMON IOP331_IRQ(15)
+-#define IRQ_IOP331_CORE_PMU IOP331_IRQ(16)
+-#define IRQ_IOP331_RSVD_17 IOP331_IRQ(17)
+-#define IRQ_IOP331_RSVD_18 IOP331_IRQ(18)
+-#define IRQ_IOP331_RSVD_19 IOP331_IRQ(19)
+-#define IRQ_IOP331_RSVD_20 IOP331_IRQ(20)
+-#define IRQ_IOP331_RSVD_21 IOP331_IRQ(21)
+-#define IRQ_IOP331_RSVD_22 IOP331_IRQ(22)
+-#define IRQ_IOP331_RSVD_23 IOP331_IRQ(23)
+-#define IRQ_IOP331_XINT0 IOP331_IRQ(24)
+-#define IRQ_IOP331_XINT1 IOP331_IRQ(25)
+-#define IRQ_IOP331_XINT2 IOP331_IRQ(26)
+-#define IRQ_IOP331_XINT3 IOP331_IRQ(27)
+-#define IRQ_IOP331_RSVD_28 IOP331_IRQ(28)
+-#define IRQ_IOP331_RSVD_29 IOP331_IRQ(29)
+-#define IRQ_IOP331_RSVD_30 IOP331_IRQ(30)
+-#define IRQ_IOP331_RSVD_31 IOP331_IRQ(31)
+-#define IRQ_IOP331_XINT8 IOP331_IRQ(32) // 0
+-#define IRQ_IOP331_XINT9 IOP331_IRQ(33) // 1
+-#define IRQ_IOP331_XINT10 IOP331_IRQ(34) // 2
+-#define IRQ_IOP331_XINT11 IOP331_IRQ(35) // 3
+-#define IRQ_IOP331_XINT12 IOP331_IRQ(36) // 4
+-#define IRQ_IOP331_XINT13 IOP331_IRQ(37) // 5
+-#define IRQ_IOP331_XINT14 IOP331_IRQ(38) // 6
+-#define IRQ_IOP331_XINT15 IOP331_IRQ(39) // 7
+-#define IRQ_IOP331_RSVD_40 IOP331_IRQ(40) // 8
+-#define IRQ_IOP331_RSVD_41 IOP331_IRQ(41) // 9
+-#define IRQ_IOP331_RSVD_42 IOP331_IRQ(42) // 10
+-#define IRQ_IOP331_RSVD_43 IOP331_IRQ(43) // 11
+-#define IRQ_IOP331_RSVD_44 IOP331_IRQ(44) // 12
+-#define IRQ_IOP331_RSVD_45 IOP331_IRQ(45) // 13
+-#define IRQ_IOP331_RSVD_46 IOP331_IRQ(46) // 14
+-#define IRQ_IOP331_RSVD_47 IOP331_IRQ(47) // 15
+-#define IRQ_IOP331_RSVD_48 IOP331_IRQ(48) // 16
+-#define IRQ_IOP331_RSVD_49 IOP331_IRQ(49) // 17
+-#define IRQ_IOP331_RSVD_50 IOP331_IRQ(50) // 18
+-#define IRQ_IOP331_UART0 IOP331_IRQ(51) // 19
+-#define IRQ_IOP331_UART1 IOP331_IRQ(52) // 20
+-#define IRQ_IOP331_PBIE IOP331_IRQ(53) // 21
+-#define IRQ_IOP331_ATU_CRW IOP331_IRQ(54) // 22
+-#define IRQ_IOP331_ATU_ERR IOP331_IRQ(55) // 23
+-#define IRQ_IOP331_MCU_ERR IOP331_IRQ(56) // 24
+-#define IRQ_IOP331_DMA0_ERR IOP331_IRQ(57) // 25
+-#define IRQ_IOP331_DMA1_ERR IOP331_IRQ(58) // 26
+-#define IRQ_IOP331_RSVD_59 IOP331_IRQ(59) // 27
+-#define IRQ_IOP331_AA_ERR IOP331_IRQ(60) // 28
+-#define IRQ_IOP331_RSVD_61 IOP331_IRQ(61) // 29
+-#define IRQ_IOP331_MSG_ERR IOP331_IRQ(62) // 30
+-#define IRQ_IOP331_HPI IOP331_IRQ(63) // 31
+-
+-#define NR_IOP331_IRQS (IOP331_IRQ(63) + 1)
+-
+-#define NR_IRQS NR_IOP331_IRQS
+-
+-
+-/*
+- * Interrupts available on the IQ80331 board
+- */
+-
+-/*
+- * On board devices
+- */
+-#define IRQ_IQ80331_I82544 IRQ_IOP331_XINT0
+-#define IRQ_IQ80331_UART0 IRQ_IOP331_UART0
+-#define IRQ_IQ80331_UART1 IRQ_IOP331_UART1
+-
+-/*
+- * PCI interrupts
+- */
+-#define IRQ_IQ80331_INTA IRQ_IOP331_XINT0
+-#define IRQ_IQ80331_INTB IRQ_IOP331_XINT1
+-#define IRQ_IQ80331_INTC IRQ_IOP331_XINT2
+-#define IRQ_IQ80331_INTD IRQ_IOP331_XINT3
+-
+-/*
+- * Interrupts available on the IQ80332 board
+- */
+-
+-/*
+- * On board devices
+- */
+-#define IRQ_IQ80332_I82544 IRQ_IOP331_XINT0
+-#define IRQ_IQ80332_UART0 IRQ_IOP331_UART0
+-#define IRQ_IQ80332_UART1 IRQ_IOP331_UART1
+-
+-/*
+- * PCI interrupts
+- */
+-#define IRQ_IQ80332_INTA IRQ_IOP331_XINT0
+-#define IRQ_IQ80332_INTB IRQ_IOP331_XINT1
+-#define IRQ_IQ80332_INTC IRQ_IOP331_XINT2
+-#define IRQ_IQ80332_INTD IRQ_IOP331_XINT3
+-
+-#endif // _IOP331_IRQ_H_
+diff --git a/include/asm-arm/arch-iop3xx/iop331.h b/include/asm-arm/arch-iop3xx/iop331.h
+deleted file mode 100644
+index fbf0cc1..0000000
+--- a/include/asm-arm/arch-iop3xx/iop331.h
++++ /dev/null
+@@ -1,363 +0,0 @@
+-/*
+- * linux/include/asm/arch-iop3xx/iop331.h
+- *
+- * Intel IOP331 Chip definitions
+- *
+- * Author: Dave Jiang (dave.jiang at intel.com)
+- * Copyright (C) 2003, 2004 Intel Corp.
+- *
+- * 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 _IOP331_HW_H_
+-#define _IOP331_HW_H_
+-
+-
+-/*
+- * This is needed for mixed drivers that need to work on all
+- * IOP3xx variants but behave slightly differently on each.
+- */
+-#ifndef __ASSEMBLY__
+-#ifdef CONFIG_ARCH_IOP331
+-/*#define iop_is_331() ((processor_id & 0xffffffb0) == 0x69054090) */
+-#define iop_is_331() ((processor_id & 0xffffff30) == 0x69054010)
+-#else
+-#define iop_is_331() 0
+-#endif
+-#endif
+-
+-/*
+- * IOP331 I/O and Mem space regions for PCI autoconfiguration
+- */
+-#define IOP331_PCI_IO_WINDOW_SIZE 0x00010000
+-#define IOP331_PCI_LOWER_IO_PA 0x90000000
+-#define IOP331_PCI_LOWER_IO_VA 0xfe000000
+-#define IOP331_PCI_LOWER_IO_BA (*IOP331_OIOWTVR)
+-#define IOP331_PCI_UPPER_IO_PA (IOP331_PCI_LOWER_IO_PA + IOP331_PCI_IO_WINDOW_SIZE - 1)
+-#define IOP331_PCI_UPPER_IO_VA (IOP331_PCI_LOWER_IO_VA + IOP331_PCI_IO_WINDOW_SIZE - 1)
+-#define IOP331_PCI_UPPER_IO_BA (IOP331_PCI_LOWER_IO_BA + IOP331_PCI_IO_WINDOW_SIZE - 1)
+-#define IOP331_PCI_IO_OFFSET (IOP331_PCI_LOWER_IO_VA - IOP331_PCI_LOWER_IO_BA)
+-
+-/* this can be 128M if OMWTVR1 is set */
+-#define IOP331_PCI_MEM_WINDOW_SIZE 0x04000000 /* 64M outbound window */
+-/* #define IOP331_PCI_MEM_WINDOW_SIZE (~*IOP331_IALR1 + 1) */
+-#define IOP331_PCI_LOWER_MEM_PA 0x80000000
+-#define IOP331_PCI_LOWER_MEM_BA (*IOP331_OMWTVR0)
+-#define IOP331_PCI_UPPER_MEM_PA (IOP331_PCI_LOWER_MEM_PA + IOP331_PCI_MEM_WINDOW_SIZE - 1)
+-#define IOP331_PCI_UPPER_MEM_BA (IOP331_PCI_LOWER_MEM_BA + IOP331_PCI_MEM_WINDOW_SIZE - 1)
+-#define IOP331_PCI_MEM_OFFSET (IOP331_PCI_LOWER_MEM_PA - IOP331_PCI_LOWER_MEM_BA)
+-
+-/*
+- * IOP331 chipset registers
+- */
+-#define IOP331_VIRT_MEM_BASE 0xfeffe000 /* chip virtual mem address*/
+-#define IOP331_PHYS_MEM_BASE 0xffffe000 /* chip physical memory address */
+-#define IOP331_REG_ADDR(reg) (IOP331_VIRT_MEM_BASE | (reg))
+-
+-/* Reserved 0x00000000 through 0x000000FF */
+-
+-/* Address Translation Unit 0x00000100 through 0x000001FF */
+-#define IOP331_ATUVID (volatile u16 *)IOP331_REG_ADDR(0x00000100)
+-#define IOP331_ATUDID (volatile u16 *)IOP331_REG_ADDR(0x00000102)
+-#define IOP331_ATUCMD (volatile u16 *)IOP331_REG_ADDR(0x00000104)
+-#define IOP331_ATUSR (volatile u16 *)IOP331_REG_ADDR(0x00000106)
+-#define IOP331_ATURID (volatile u8 *)IOP331_REG_ADDR(0x00000108)
+-#define IOP331_ATUCCR (volatile u32 *)IOP331_REG_ADDR(0x00000109)
+-#define IOP331_ATUCLSR (volatile u8 *)IOP331_REG_ADDR(0x0000010C)
+-#define IOP331_ATULT (volatile u8 *)IOP331_REG_ADDR(0x0000010D)
+-#define IOP331_ATUHTR (volatile u8 *)IOP331_REG_ADDR(0x0000010E)
+-#define IOP331_ATUBIST (volatile u8 *)IOP331_REG_ADDR(0x0000010F)
+-#define IOP331_IABAR0 (volatile u32 *)IOP331_REG_ADDR(0x00000110)
+-#define IOP331_IAUBAR0 (volatile u32 *)IOP331_REG_ADDR(0x00000114)
+-#define IOP331_IABAR1 (volatile u32 *)IOP331_REG_ADDR(0x00000118)
+-#define IOP331_IAUBAR1 (volatile u32 *)IOP331_REG_ADDR(0x0000011C)
+-#define IOP331_IABAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000120)
+-#define IOP331_IAUBAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000124)
+-#define IOP331_ASVIR (volatile u16 *)IOP331_REG_ADDR(0x0000012C)
+-#define IOP331_ASIR (volatile u16 *)IOP331_REG_ADDR(0x0000012E)
+-#define IOP331_ERBAR (volatile u32 *)IOP331_REG_ADDR(0x00000130)
+-#define IOP331_ATU_CAPPTR (volatile u32 *)IOP331_REG_ADDR(0x00000134)
+-/* Reserved 0x00000138 through 0x0000013B */
+-#define IOP331_ATUILR (volatile u8 *)IOP331_REG_ADDR(0x0000013C)
+-#define IOP331_ATUIPR (volatile u8 *)IOP331_REG_ADDR(0x0000013D)
+-#define IOP331_ATUMGNT (volatile u8 *)IOP331_REG_ADDR(0x0000013E)
+-#define IOP331_ATUMLAT (volatile u8 *)IOP331_REG_ADDR(0x0000013F)
+-#define IOP331_IALR0 (volatile u32 *)IOP331_REG_ADDR(0x00000140)
+-#define IOP331_IATVR0 (volatile u32 *)IOP331_REG_ADDR(0x00000144)
+-#define IOP331_ERLR (volatile u32 *)IOP331_REG_ADDR(0x00000148)
+-#define IOP331_ERTVR (volatile u32 *)IOP331_REG_ADDR(0x0000014C)
+-#define IOP331_IALR1 (volatile u32 *)IOP331_REG_ADDR(0x00000150)
+-#define IOP331_IALR2 (volatile u32 *)IOP331_REG_ADDR(0x00000154)
+-#define IOP331_IATVR2 (volatile u32 *)IOP331_REG_ADDR(0x00000158)
+-#define IOP331_OIOWTVR (volatile u32 *)IOP331_REG_ADDR(0x0000015C)
+-#define IOP331_OMWTVR0 (volatile u32 *)IOP331_REG_ADDR(0x00000160)
+-#define IOP331_OUMWTVR0 (volatile u32 *)IOP331_REG_ADDR(0x00000164)
+-#define IOP331_OMWTVR1 (volatile u32 *)IOP331_REG_ADDR(0x00000168)
+-#define IOP331_OUMWTVR1 (volatile u32 *)IOP331_REG_ADDR(0x0000016C)
+-/* Reserved 0x00000170 through 0x00000177*/
+-#define IOP331_OUDWTVR (volatile u32 *)IOP331_REG_ADDR(0x00000178)
+-/* Reserved 0x0000017C through 0x0000017F*/
+-#define IOP331_ATUCR (volatile u32 *)IOP331_REG_ADDR(0x00000180)
+-#define IOP331_PCSR (volatile u32 *)IOP331_REG_ADDR(0x00000184)
+-#define IOP331_ATUISR (volatile u32 *)IOP331_REG_ADDR(0x00000188)
+-#define IOP331_ATUIMR (volatile u32 *)IOP331_REG_ADDR(0x0000018C)
+-#define IOP331_IABAR3 (volatile u32 *)IOP331_REG_ADDR(0x00000190)
+-#define IOP331_IAUBAR3 (volatile u32 *)IOP331_REG_ADDR(0x00000194)
+-#define IOP331_IALR3 (volatile u32 *)IOP331_REG_ADDR(0x00000198)
+-#define IOP331_IATVR3 (volatile u32 *)IOP331_REG_ADDR(0x0000019C)
+-/* Reserved 0x000001A0 through 0x000001A3*/
+-#define IOP331_OCCAR (volatile u32 *)IOP331_REG_ADDR(0x000001A4)
+-/* Reserved 0x000001A8 through 0x000001AB*/
+-#define IOP331_OCCDR (volatile u32 *)IOP331_REG_ADDR(0x000001AC)
+-/* Reserved 0x000001B0 through 0x000001BB*/
+-#define IOP331_VPDCAPID (volatile u8 *)IOP331_REG_ADDR(0x000001B8)
+-#define IOP331_VPDNXTP (volatile u8 *)IOP331_REG_ADDR(0x000001B9)
+-#define IOP331_VPDAR (volatile u16 *)IOP331_REG_ADDR(0x000001BA)
+-#define IOP331_VPDDR (volatile u32 *)IOP331_REG_ADDR(0x000001BC)
+-#define IOP331_PMCAPID (volatile u8 *)IOP331_REG_ADDR(0x000001C0)
+-#define IOP331_PMNEXT (volatile u8 *)IOP331_REG_ADDR(0x000001C1)
+-#define IOP331_APMCR (volatile u16 *)IOP331_REG_ADDR(0x000001C2)
+-#define IOP331_APMCSR (volatile u16 *)IOP331_REG_ADDR(0x000001C4)
+-/* Reserved 0x000001C6 through 0x000001CF */
+-#define IOP331_MSICAPID (volatile u8 *)IOP331_REG_ADDR(0x000001D0)
+-#define IOP331_MSINXTP (volatile u8 *)IOP331_REG_ADDR(0x000001D1)
+-#define IOP331_MSIMCR (volatile u16 *)IOP331_REG_ADDR(0x000001D2)
+-#define IOP331_MSIMAR (volatile u32 *)IOP331_REG_ADDR(0x000001D4)
+-#define IOP331_MSIMUAR (volatile u32 *)IOP331_REG_ADDR(0x000001D8)
+-#define IOP331_MSIMDR (volatile u32 *)IOP331_REG_ADDR(0x000001DC)
+-#define IOP331_PCIXCAPID (volatile u8 *)IOP331_REG_ADDR(0x000001E0)
+-#define IOP331_PCIXNEXT (volatile u8 *)IOP331_REG_ADDR(0x000001E1)
+-#define IOP331_PCIXCMD (volatile u16 *)IOP331_REG_ADDR(0x000001E2)
+-#define IOP331_PCIXSR (volatile u32 *)IOP331_REG_ADDR(0x000001E4)
+-#define IOP331_PCIIRSR (volatile u32 *)IOP331_REG_ADDR(0x000001EC)
+-
+-/* Messaging Unit 0x00000300 through 0x000003FF */
+-
+-/* Reserved 0x00000300 through 0x0000030c */
+-#define IOP331_IMR0 (volatile u32 *)IOP331_REG_ADDR(0x00000310)
+-#define IOP331_IMR1 (volatile u32 *)IOP331_REG_ADDR(0x00000314)
+-#define IOP331_OMR0 (volatile u32 *)IOP331_REG_ADDR(0x00000318)
+-#define IOP331_OMR1 (volatile u32 *)IOP331_REG_ADDR(0x0000031C)
+-#define IOP331_IDR (volatile u32 *)IOP331_REG_ADDR(0x00000320)
+-#define IOP331_IISR (volatile u32 *)IOP331_REG_ADDR(0x00000324)
+-#define IOP331_IIMR (volatile u32 *)IOP331_REG_ADDR(0x00000328)
+-#define IOP331_ODR (volatile u32 *)IOP331_REG_ADDR(0x0000032C)
+-#define IOP331_OISR (volatile u32 *)IOP331_REG_ADDR(0x00000330)
+-#define IOP331_OIMR (volatile u32 *)IOP331_REG_ADDR(0x00000334)
+-/* Reserved 0x00000338 through 0x0000034F */
+-#define IOP331_MUCR (volatile u32 *)IOP331_REG_ADDR(0x00000350)
+-#define IOP331_QBAR (volatile u32 *)IOP331_REG_ADDR(0x00000354)
+-/* Reserved 0x00000358 through 0x0000035C */
+-#define IOP331_IFHPR (volatile u32 *)IOP331_REG_ADDR(0x00000360)
+-#define IOP331_IFTPR (volatile u32 *)IOP331_REG_ADDR(0x00000364)
+-#define IOP331_IPHPR (volatile u32 *)IOP331_REG_ADDR(0x00000368)
+-#define IOP331_IPTPR (volatile u32 *)IOP331_REG_ADDR(0x0000036C)
+-#define IOP331_OFHPR (volatile u32 *)IOP331_REG_ADDR(0x00000370)
+-#define IOP331_OFTPR (volatile u32 *)IOP331_REG_ADDR(0x00000374)
+-#define IOP331_OPHPR (volatile u32 *)IOP331_REG_ADDR(0x00000378)
+-#define IOP331_OPTPR (volatile u32 *)IOP331_REG_ADDR(0x0000037C)
+-#define IOP331_IAR (volatile u32 *)IOP331_REG_ADDR(0x00000380)
+-/* Reserved 0x00000384 through 0x000003FF */
+-
+-/* DMA Controller 0x00000400 through 0x000004FF */
+-#define IOP331_DMA0_CCR (volatile u32 *)IOP331_REG_ADDR(0x00000400)
+-#define IOP331_DMA0_CSR (volatile u32 *)IOP331_REG_ADDR(0x00000404)
+-#define IOP331_DMA0_DAR (volatile u32 *)IOP331_REG_ADDR(0x0000040C)
+-#define IOP331_DMA0_NDAR (volatile u32 *)IOP331_REG_ADDR(0x00000410)
+-#define IOP331_DMA0_PADR (volatile u32 *)IOP331_REG_ADDR(0x00000414)
+-#define IOP331_DMA0_PUADR (volatile u32 *)IOP331_REG_ADDR(0x00000418)
+-#define IOP331_DMA0_LADR (volatile u32 *)IOP331_REG_ADDR(0X0000041C)
+-#define IOP331_DMA0_BCR (volatile u32 *)IOP331_REG_ADDR(0x00000420)
+-#define IOP331_DMA0_DCR (volatile u32 *)IOP331_REG_ADDR(0x00000424)
+-/* Reserved 0x00000428 through 0x0000043C */
+-#define IOP331_DMA1_CCR (volatile u32 *)IOP331_REG_ADDR(0x00000440)
+-#define IOP331_DMA1_CSR (volatile u32 *)IOP331_REG_ADDR(0x00000444)
+-#define IOP331_DMA1_DAR (volatile u32 *)IOP331_REG_ADDR(0x0000044C)
+-#define IOP331_DMA1_NDAR (volatile u32 *)IOP331_REG_ADDR(0x00000450)
+-#define IOP331_DMA1_PADR (volatile u32 *)IOP331_REG_ADDR(0x00000454)
+-#define IOP331_DMA1_PUADR (volatile u32 *)IOP331_REG_ADDR(0x00000458)
+-#define IOP331_DMA1_LADR (volatile u32 *)IOP331_REG_ADDR(0x0000045C)
+-#define IOP331_DMA1_BCR (volatile u32 *)IOP331_REG_ADDR(0x00000460)
+-#define IOP331_DMA1_DCR (volatile u32 *)IOP331_REG_ADDR(0x00000464)
+-/* Reserved 0x00000468 through 0x000004FF */
+-
+-/* Memory controller 0x00000500 through 0x0005FF */
+-
+-/* Peripheral bus interface unit 0x00000680 through 0x0006FF */
+-#define IOP331_PBCR (volatile u32 *)IOP331_REG_ADDR(0x00000680)
+-#define IOP331_PBISR (volatile u32 *)IOP331_REG_ADDR(0x00000684)
+-#define IOP331_PBBAR0 (volatile u32 *)IOP331_REG_ADDR(0x00000688)
+-#define IOP331_PBLR0 (volatile u32 *)IOP331_REG_ADDR(0x0000068C)
+-#define IOP331_PBBAR1 (volatile u32 *)IOP331_REG_ADDR(0x00000690)
+-#define IOP331_PBLR1 (volatile u32 *)IOP331_REG_ADDR(0x00000694)
+-#define IOP331_PBBAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000698)
+-#define IOP331_PBLR2 (volatile u32 *)IOP331_REG_ADDR(0x0000069C)
+-#define IOP331_PBBAR3 (volatile u32 *)IOP331_REG_ADDR(0x000006A0)
+-#define IOP331_PBLR3 (volatile u32 *)IOP331_REG_ADDR(0x000006A4)
+-#define IOP331_PBBAR4 (volatile u32 *)IOP331_REG_ADDR(0x000006A8)
+-#define IOP331_PBLR4 (volatile u32 *)IOP331_REG_ADDR(0x000006AC)
+-#define IOP331_PBBAR5 (volatile u32 *)IOP331_REG_ADDR(0x000006B0)
+-#define IOP331_PBLR5 (volatile u32 *)IOP331_REG_ADDR(0x000006B4)
+-#define IOP331_PBDSCR (volatile u32 *)IOP331_REG_ADDR(0x000006B8)
+-/* Reserved 0x000006BC */
+-#define IOP331_PMBR0 (volatile u32 *)IOP331_REG_ADDR(0x000006C0)
+-/* Reserved 0x000006C4 through 0x000006DC */
+-#define IOP331_PMBR1 (volatile u32 *)IOP331_REG_ADDR(0x000006E0)
+-#define IOP331_PMBR2 (volatile u32 *)IOP331_REG_ADDR(0x000006E4)
+-
+-#define IOP331_PBCR_EN 0x1
+-
+-#define IOP331_PBISR_BOOR_ERR 0x1
+-
+-
+-
+-/* Peripheral performance monitoring unit 0x00000700 through 0x00077F */
+-/* Internal arbitration unit 0x00000780 through 0x0007BF */
+-
+-/* Interrupt Controller */
+-#define IOP331_INTCTL0 (volatile u32 *)IOP331_REG_ADDR(0x00000790)
+-#define IOP331_INTCTL1 (volatile u32 *)IOP331_REG_ADDR(0x00000794)
+-#define IOP331_INTSTR0 (volatile u32 *)IOP331_REG_ADDR(0x00000798)
+-#define IOP331_INTSTR1 (volatile u32 *)IOP331_REG_ADDR(0x0000079C)
+-#define IOP331_IINTSRC0 (volatile u32 *)IOP331_REG_ADDR(0x000007A0)
+-#define IOP331_IINTSRC1 (volatile u32 *)IOP331_REG_ADDR(0x000007A4)
+-#define IOP331_FINTSRC0 (volatile u32 *)IOP331_REG_ADDR(0x000007A8)
+-#define IOP331_FINTSRC1 (volatile u32 *)IOP331_REG_ADDR(0x000007AC)
+-#define IOP331_IPR0 (volatile u32 *)IOP331_REG_ADDR(0x000007B0)
+-#define IOP331_IPR1 (volatile u32 *)IOP331_REG_ADDR(0x000007B4)
+-#define IOP331_IPR2 (volatile u32 *)IOP331_REG_ADDR(0x000007B8)
+-#define IOP331_IPR3 (volatile u32 *)IOP331_REG_ADDR(0x000007BC)
+-#define IOP331_INTBASE (volatile u32 *)IOP331_REG_ADDR(0x000007C0)
+-#define IOP331_INTSIZE (volatile u32 *)IOP331_REG_ADDR(0x000007C4)
+-#define IOP331_IINTVEC (volatile u32 *)IOP331_REG_ADDR(0x000007C8)
+-#define IOP331_FINTVEC (volatile u32 *)IOP331_REG_ADDR(0x000007CC)
+-
+-
+-/* Timers */
+-
+-#define IOP331_TU_TMR0 (volatile u32 *)IOP331_REG_ADDR(0x000007D0)
+-#define IOP331_TU_TMR1 (volatile u32 *)IOP331_REG_ADDR(0x000007D4)
+-
+-#define IOP331_TMR_TC 0x01
+-#define IOP331_TMR_EN 0x02
+-#define IOP331_TMR_RELOAD 0x04
+-#define IOP331_TMR_PRIVILEGED 0x09
+-
+-#define IOP331_TMR_RATIO_1_1 0x00
+-#define IOP331_TMR_RATIO_4_1 0x10
+-#define IOP331_TMR_RATIO_8_1 0x20
+-#define IOP331_TMR_RATIO_16_1 0x30
+-
+-#define IOP331_TU_TCR0 (volatile u32 *)IOP331_REG_ADDR(0x000007D8)
+-#define IOP331_TU_TCR1 (volatile u32 *)IOP331_REG_ADDR(0x000007DC)
+-#define IOP331_TU_TRR0 (volatile u32 *)IOP331_REG_ADDR(0x000007E0)
+-#define IOP331_TU_TRR1 (volatile u32 *)IOP331_REG_ADDR(0x000007E4)
+-#define IOP331_TU_TISR (volatile u32 *)IOP331_REG_ADDR(0x000007E8)
+-#define IOP331_TU_WDTCR (volatile u32 *)IOP331_REG_ADDR(0x000007EC)
+-
+-#if defined(CONFIG_ARCH_IOP331)
+-#define IOP331_TICK_RATE 266000000 /* 266 MHz IB clock */
+-#endif
+-
+-#if defined(CONFIG_IOP331_STEPD) || defined(CONFIG_ARCH_IQ80333)
+-#undef IOP331_TICK_RATE
+-#define IOP331_TICK_RATE 333000000 /* 333 Mhz IB clock */
+-#endif
+-
+-/* Application accelerator unit 0x00000800 - 0x000008FF */
+-#define IOP331_AAU_ACR (volatile u32 *)IOP331_REG_ADDR(0x00000800)
+-#define IOP331_AAU_ASR (volatile u32 *)IOP331_REG_ADDR(0x00000804)
+-#define IOP331_AAU_ADAR (volatile u32 *)IOP331_REG_ADDR(0x00000808)
+-#define IOP331_AAU_ANDAR (volatile u32 *)IOP331_REG_ADDR(0x0000080C)
+-#define IOP331_AAU_SAR1 (volatile u32 *)IOP331_REG_ADDR(0x00000810)
+-#define IOP331_AAU_SAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000814)
+-#define IOP331_AAU_SAR3 (volatile u32 *)IOP331_REG_ADDR(0x00000818)
+-#define IOP331_AAU_SAR4 (volatile u32 *)IOP331_REG_ADDR(0x0000081C)
+-#define IOP331_AAU_SAR5 (volatile u32 *)IOP331_REG_ADDR(0x0000082C)
+-#define IOP331_AAU_SAR6 (volatile u32 *)IOP331_REG_ADDR(0x00000830)
+-#define IOP331_AAU_SAR7 (volatile u32 *)IOP331_REG_ADDR(0x00000834)
+-#define IOP331_AAU_SAR8 (volatile u32 *)IOP331_REG_ADDR(0x00000838)
+-#define IOP331_AAU_SAR9 (volatile u32 *)IOP331_REG_ADDR(0x00000840)
+-#define IOP331_AAU_SAR10 (volatile u32 *)IOP331_REG_ADDR(0x00000844)
+-#define IOP331_AAU_SAR11 (volatile u32 *)IOP331_REG_ADDR(0x00000848)
+-#define IOP331_AAU_SAR12 (volatile u32 *)IOP331_REG_ADDR(0x0000084C)
+-#define IOP331_AAU_SAR13 (volatile u32 *)IOP331_REG_ADDR(0x00000850)
+-#define IOP331_AAU_SAR14 (volatile u32 *)IOP331_REG_ADDR(0x00000854)
+-#define IOP331_AAU_SAR15 (volatile u32 *)IOP331_REG_ADDR(0x00000858)
+-#define IOP331_AAU_SAR16 (volatile u32 *)IOP331_REG_ADDR(0x0000085C)
+-#define IOP331_AAU_SAR17 (volatile u32 *)IOP331_REG_ADDR(0x00000864)
+-#define IOP331_AAU_SAR18 (volatile u32 *)IOP331_REG_ADDR(0x00000868)
+-#define IOP331_AAU_SAR19 (volatile u32 *)IOP331_REG_ADDR(0x0000086C)
+-#define IOP331_AAU_SAR20 (volatile u32 *)IOP331_REG_ADDR(0x00000870)
+-#define IOP331_AAU_SAR21 (volatile u32 *)IOP331_REG_ADDR(0x00000874)
+-#define IOP331_AAU_SAR22 (volatile u32 *)IOP331_REG_ADDR(0x00000878)
+-#define IOP331_AAU_SAR23 (volatile u32 *)IOP331_REG_ADDR(0x0000087C)
+-#define IOP331_AAU_SAR24 (volatile u32 *)IOP331_REG_ADDR(0x00000880)
+-#define IOP331_AAU_SAR25 (volatile u32 *)IOP331_REG_ADDR(0x00000888)
+-#define IOP331_AAU_SAR26 (volatile u32 *)IOP331_REG_ADDR(0x0000088C)
+-#define IOP331_AAU_SAR27 (volatile u32 *)IOP331_REG_ADDR(0x00000890)
+-#define IOP331_AAU_SAR28 (volatile u32 *)IOP331_REG_ADDR(0x00000894)
+-#define IOP331_AAU_SAR29 (volatile u32 *)IOP331_REG_ADDR(0x00000898)
+-#define IOP331_AAU_SAR30 (volatile u32 *)IOP331_REG_ADDR(0x0000089C)
+-#define IOP331_AAU_SAR31 (volatile u32 *)IOP331_REG_ADDR(0x000008A0)
+-#define IOP331_AAU_SAR32 (volatile u32 *)IOP331_REG_ADDR(0x000008A4)
+-#define IOP331_AAU_DAR (volatile u32 *)IOP331_REG_ADDR(0x00000820)
+-#define IOP331_AAU_ABCR (volatile u32 *)IOP331_REG_ADDR(0x00000824)
+-#define IOP331_AAU_ADCR (volatile u32 *)IOP331_REG_ADDR(0x00000828)
+-#define IOP331_AAU_EDCR0 (volatile u32 *)IOP331_REG_ADDR(0x0000083c)
+-#define IOP331_AAU_EDCR1 (volatile u32 *)IOP331_REG_ADDR(0x00000860)
+-#define IOP331_AAU_EDCR2 (volatile u32 *)IOP331_REG_ADDR(0x00000884)
+-
+-
+-#define IOP331_SPDSCR (volatile u32 *)IOP331_REG_ADDR(0x000015C0)
+-#define IOP331_PPDSCR (volatile u32 *)IOP331_REG_ADDR(0x000015C8)
+-/* SSP serial port unit 0x00001600 - 0x0000167F */
+-
+-/* I2C bus interface unit 0x00001680 - 0x000016FF */
+-/* for I2C bit defs see drivers/i2c/i2c-iop3xx.h */
+-
+-#define IOP331_ICR0 (volatile u32 *)IOP331_REG_ADDR(0x00001680)
+-#define IOP331_ISR0 (volatile u32 *)IOP331_REG_ADDR(0x00001684)
+-#define IOP331_ISAR0 (volatile u32 *)IOP331_REG_ADDR(0x00001688)
+-#define IOP331_IDBR0 (volatile u32 *)IOP331_REG_ADDR(0x0000168C)
+-/* Reserved 0x00001690 */
+-#define IOP331_IBMR0 (volatile u32 *)IOP331_REG_ADDR(0x00001694)
+-/* Reserved 0x00001698 */
+-/* Reserved 0x0000169C */
+-#define IOP331_ICR1 (volatile u32 *)IOP331_REG_ADDR(0x000016A0)
+-#define IOP331_ISR1 (volatile u32 *)IOP331_REG_ADDR(0x000016A4)
+-#define IOP331_ISAR1 (volatile u32 *)IOP331_REG_ADDR(0x000016A8)
+-#define IOP331_IDBR1 (volatile u32 *)IOP331_REG_ADDR(0x000016AC)
+-#define IOP331_IBMR1 (volatile u32 *)IOP331_REG_ADDR(0x000016B4)
+-/* Reserved 0x000016B8 through 0x000016FF */
+-
+-/* 0x00001700 through 0x0000172C UART 0 */
+-
+-/* Reserved 0x00001730 through 0x0000173F */
+-
+-/* 0x00001740 through 0x0000176C UART 1 */
+-
+-#define IOP331_UART0_PHYS (IOP331_PHYS_MEM_BASE | 0x00001700) /* UART #1 physical */
+-#define IOP331_UART1_PHYS (IOP331_PHYS_MEM_BASE | 0x00001740) /* UART #2 physical */
+-#define IOP331_UART0_VIRT (IOP331_VIRT_MEM_BASE | 0x00001700) /* UART #1 virtual addr */
+-#define IOP331_UART1_VIRT (IOP331_VIRT_MEM_BASE | 0x00001740) /* UART #2 virtual addr */
+-
+-/* Reserved 0x00001770 through 0x0000177F */
+-
+-/* General Purpose I/O Registers */
+-#define IOP331_GPOE (volatile u32 *)IOP331_REG_ADDR(0x00001780)
+-#define IOP331_GPID (volatile u32 *)IOP331_REG_ADDR(0x00001784)
+-#define IOP331_GPOD (volatile u32 *)IOP331_REG_ADDR(0x00001788)
+-
+-/* Reserved 0x0000178c through 0x000019ff */
+-
+-
+-#ifndef __ASSEMBLY__
+-extern void iop331_map_io(void);
+-extern void iop331_init_irq(void);
+-extern void iop331_time_init(void);
+-#endif
+-
+-#endif // _IOP331_HW_H_
+diff --git a/include/asm-arm/arch-iop3xx/iq31244.h b/include/asm-arm/arch-iop3xx/iq31244.h
+deleted file mode 100644
+index 4177cfa..0000000
+--- a/include/asm-arm/arch-iop3xx/iq31244.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-/*
+- * linux/include/asm/arch-iop3xx/iq31244.h
+- *
+- * Intel IQ31244 evaluation board registers
+- */
+-
+-#ifndef _IQ31244_H_
+-#define _IQ31244_H_
+-
+-#define IQ31244_FLASHBASE 0xf0000000 /* Flash */
+-#define IQ31244_FLASHSIZE 0x00800000
+-#define IQ31244_FLASHWIDTH 2
+-
+-#define IQ31244_UART 0xfe800000 /* UART #1 */
+-#define IQ31244_7SEG_1 0xfe840000 /* 7-Segment MSB */
+-#define IQ31244_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */
+-#define IQ31244_ROTARY_SW 0xfe8d0000 /* Rotary Switch */
+-#define IQ31244_BATT_STAT 0xfe8f0000 /* Battery Status */
+-
+-#ifndef __ASSEMBLY__
+-extern void iq31244_map_io(void);
+-#endif
+-
+-#endif // _IQ31244_H_
+diff --git a/include/asm-arm/arch-iop3xx/iq80321.h b/include/asm-arm/arch-iop3xx/iq80321.h
+deleted file mode 100644
+index cb87259..0000000
+--- a/include/asm-arm/arch-iop3xx/iq80321.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-/*
+- * linux/include/asm/arch-iop3xx/iq80321.h
+- *
+- * Intel IQ80321 evaluation board registers
+- */
+-
+-#ifndef _IQ80321_H_
+-#define _IQ80321_H_
+-
+-#define IQ80321_FLASHBASE 0xf0000000 /* Flash */
+-#define IQ80321_FLASHSIZE 0x00800000
+-#define IQ80321_FLASHWIDTH 1
+-
+-#define IQ80321_UART 0xfe800000 /* UART #1 */
+-#define IQ80321_7SEG_1 0xfe840000 /* 7-Segment MSB */
+-#define IQ80321_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */
+-#define IQ80321_ROTARY_SW 0xfe8d0000 /* Rotary Switch */
+-#define IQ80321_BATT_STAT 0xfe8f0000 /* Battery Status */
+-
+-#ifndef __ASSEMBLY__
+-extern void iq80321_map_io(void);
+-#endif
+-
+-#endif // _IQ80321_H_
+diff --git a/include/asm-arm/arch-iop3xx/iq80331.h b/include/asm-arm/arch-iop3xx/iq80331.h
+deleted file mode 100644
+index 0668e78..0000000
+--- a/include/asm-arm/arch-iop3xx/iq80331.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * linux/include/asm/arch-iop3xx/iq80331.h
+- *
+- * Intel IQ80331 evaluation board registers
+- */
+-
+-#ifndef _IQ80331_H_
+-#define _IQ80331_H_
+-
+-#define IQ80331_FLASHBASE 0xc0000000 /* Flash */
+-#define IQ80331_FLASHSIZE 0x00800000
+-#define IQ80331_FLASHWIDTH 1
+-
+-#define IQ80331_7SEG_1 0xce840000 /* 7-Segment MSB */
+-#define IQ80331_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */
+-#define IQ80331_ROTARY_SW 0xce8d0000 /* Rotary Switch */
+-#define IQ80331_BATT_STAT 0xce8f0000 /* Battery Status */
+-
+-#ifndef __ASSEMBLY__
+-extern void iq80331_map_io(void);
+-#endif
+-
+-#endif // _IQ80331_H_
+diff --git a/include/asm-arm/arch-iop3xx/iq80332.h b/include/asm-arm/arch-iop3xx/iq80332.h
+deleted file mode 100644
+index e5fff17..0000000
+--- a/include/asm-arm/arch-iop3xx/iq80332.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * linux/include/asm/arch-iop3xx/iq80332.h
+- *
+- * Intel IQ80332 evaluation board registers
+- */
+-
+-#ifndef _IQ80332_H_
+-#define _IQ80332_H_
+-
+-#define IQ80332_FLASHBASE 0xc0000000 /* Flash */
+-#define IQ80332_FLASHSIZE 0x00800000
+-#define IQ80332_FLASHWIDTH 1
+-
+-#define IQ80332_7SEG_1 0xce840000 /* 7-Segment MSB */
+-#define IQ80332_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */
+-#define IQ80332_ROTARY_SW 0xce8d0000 /* Rotary Switch */
+-#define IQ80332_BATT_STAT 0xce8f0000 /* Battery Status */
+-
+-#ifndef __ASSEMBLY__
+-extern void iq80332_map_io(void);
+-#endif
+-
+-#endif // _IQ80332_H_
+diff --git a/include/asm-arm/arch-iop3xx/irqs.h b/include/asm-arm/arch-iop3xx/irqs.h
+deleted file mode 100644
+index b2c03f4..0000000
+--- a/include/asm-arm/arch-iop3xx/irqs.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/irqs.h
+- *
+- * Copyright: (C) 2001-2003 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.
+- *
+- */
+-
+-/*
+- * Chipset-specific bits
+- */
+-#ifdef CONFIG_ARCH_IOP321
+-#include "iop321-irqs.h"
+-#endif
+-
+-#ifdef CONFIG_ARCH_IOP331
+-#include "iop331-irqs.h"
+-#endif
+diff --git a/include/asm-arm/arch-iop3xx/memory.h b/include/asm-arm/arch-iop3xx/memory.h
+deleted file mode 100644
+index e43ebd9..0000000
+--- a/include/asm-arm/arch-iop3xx/memory.h
++++ /dev/null
+@@ -1,38 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/memory.h
+- */
+-
+-#ifndef __ASM_ARCH_MEMORY_H
+-#define __ASM_ARCH_MEMORY_H
+-
+-#include <asm/hardware.h>
+-
+-/*
+- * Physical DRAM offset.
+- */
+-#ifndef CONFIG_ARCH_IOP331
+-#define PHYS_OFFSET UL(0xa0000000)
+-#else
+-#define PHYS_OFFSET UL(0x00000000)
+-#endif
+-
+-/*
+- * Virtual view <-> PCI DMA view memory address translations
+- * virt_to_bus: Used to translate the virtual address to an
+- * address suitable to be passed to set_dma_addr
+- * bus_to_virt: Used to convert an address for DMA operations
+- * to an address that the kernel can use.
+- */
+-#if defined(CONFIG_ARCH_IOP321)
+-
+-#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP321_IATVR2)) | ((*IOP321_IABAR2) & 0xfffffff0))
+-#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP321_IALR2)) | ( *IOP321_IATVR2)))
+-
+-#elif defined(CONFIG_ARCH_IOP331)
+-
+-#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP331_IATVR2)) | ((*IOP331_IABAR2) & 0xfffffff0))
+-#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP331_IALR2)) | ( *IOP331_IATVR2)))
+-
+-#endif
+-
+-#endif
+diff --git a/include/asm-arm/arch-iop3xx/system.h b/include/asm-arm/arch-iop3xx/system.h
+deleted file mode 100644
+index af6ae8c..0000000
+--- a/include/asm-arm/arch-iop3xx/system.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/system.h
+- *
+- * 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.
+- */
+-
+-static inline void arch_idle(void)
+-{
+- cpu_do_idle();
+-}
+-
+-
+-static inline void arch_reset(char mode)
+-{
+-#ifdef CONFIG_ARCH_IOP321
+- *IOP321_PCSR = 0x30;
+-#endif
+-
+-#ifdef CONFIG_ARCH_IOP331
+- *IOP331_PCSR = 0x30;
+-#endif
+-
+- if ( 1 && mode == 's') {
+- /* Jump into ROM at address 0 */
+- cpu_reset(0);
+- } else {
+- /* No on-chip reset capability */
+- cpu_reset(0);
+- }
+-}
+-
+diff --git a/include/asm-arm/arch-iop3xx/timex.h b/include/asm-arm/arch-iop3xx/timex.h
+deleted file mode 100644
+index 14ca8d0..0000000
+--- a/include/asm-arm/arch-iop3xx/timex.h
++++ /dev/null
+@@ -1,20 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/timex.h
+- *
+- * IOP3xx architecture timex specifications
+- */
+-#include <asm/hardware.h>
+-
+-#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244)
+-
+-#define CLOCK_TICK_RATE IOP321_TICK_RATE
+-
+-#elif defined(CONFIG_ARCH_IQ80331) || defined(CONFIG_MACH_IQ80332)
+-
+-#define CLOCK_TICK_RATE IOP331_TICK_RATE
+-
+-#else
+-
+-#error "No IOP3xx timex information for this architecture"
+-
+-#endif
+diff --git a/include/asm-arm/arch-iop3xx/uncompress.h b/include/asm-arm/arch-iop3xx/uncompress.h
+deleted file mode 100644
+index fbdd5af..0000000
+--- a/include/asm-arm/arch-iop3xx/uncompress.h
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/uncompress.h
+- */
+-#include <asm/types.h>
+-#include <asm/mach-types.h>
+-#include <linux/serial_reg.h>
+-#include <asm/hardware.h>
+-
+-#ifdef CONFIG_ARCH_IOP321
+-#define UTYPE unsigned char *
+-#elif defined(CONFIG_ARCH_IOP331)
+-#define UTYPE u32 *
+-#else
+-#error "Missing IOP3xx arch type def"
+-#endif
+-
+-static volatile UTYPE uart_base;
+-
+-#define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE)
+-
+-static inline void putc(char c)
+-{
+- while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
+- barrier();
+- *uart_base = c;
+-}
+-
+-static inline void flush(void)
+-{
+-}
+-
+-static __inline__ void __arch_decomp_setup(unsigned long arch_id)
+-{
+- if(machine_is_iq80321())
+- uart_base = (volatile UTYPE)IQ80321_UART;
+- else if(machine_is_iq31244())
+- uart_base = (volatile UTYPE)IQ31244_UART;
+- else if(machine_is_iq80331() || machine_is_iq80332())
+- uart_base = (volatile UTYPE)IOP331_UART0_PHYS;
+- else
+- uart_base = (volatile UTYPE)0xfe800000;
+-}
+-
+-/*
+- * nothing to do
+- */
+-#define arch_decomp_setup() __arch_decomp_setup(arch_id)
+-#define arch_decomp_wdog()
+diff --git a/include/asm-arm/arch-iop3xx/vmalloc.h b/include/asm-arm/arch-iop3xx/vmalloc.h
+deleted file mode 100644
+index 0f2f684..0000000
+--- a/include/asm-arm/arch-iop3xx/vmalloc.h
++++ /dev/null
+@@ -1,16 +0,0 @@
+-/*
+- * linux/include/asm-arm/arch-iop3xx/vmalloc.h
+- */
+-
+-/*
+- * Just any arbitrary offset to the start of the vmalloc VM area: the
+- * current 8MB value just means that there will be a 8MB "hole" after the
+- * physical memory until the kernel virtual memory starts. That means that
+- * any out-of-bounds memory accesses will hopefully be caught.
+- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+- * area for the same reason. ;)
+- */
+-//#define VMALLOC_END (0xe8000000)
+-/* increase usable physical RAM to ~992M per RMK */
+-#define VMALLOC_END (0xfe000000)
+-
+diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
+index 13aee17..8d10a91 100644
+--- a/include/asm-arm/arch-ixp4xx/platform.h
++++ b/include/asm-arm/arch-ixp4xx/platform.h
+@@ -90,6 +90,11 @@ struct ixp4xx_i2c_pins {
+ struct sys_timer;
+
+ /*
++ * Frequency of clock used for primary clocksource
++ */
++extern unsigned long ixp4xx_timer_freq;
++
++/*
+ * Functions used by platform-level setup code
+ */
+ extern void ixp4xx_map_io(void);
+diff --git a/include/asm-arm/arch-ixp4xx/system.h b/include/asm-arm/arch-ixp4xx/system.h
+index 73589aa..8e1db42 100644
+--- a/include/asm-arm/arch-ixp4xx/system.h
++++ b/include/asm-arm/arch-ixp4xx/system.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-arm/arch-ixp4x//system.h
++ * include/asm-arm/arch-ixp4xx/system.h
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ *
+diff --git a/include/asm-arm/arch-l7200/io.h b/include/asm-arm/arch-l7200/io.h
+index cd080d8..d744d97 100644
+--- a/include/asm-arm/arch-l7200/io.h
++++ b/include/asm-arm/arch-l7200/io.h
+@@ -31,9 +31,9 @@
+ static inline unsigned int __arch_getw(unsigned long a)
+ {
+ unsigned int value;
+- __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw"
++ __asm__ __volatile__("ldrh %0, [%1, #0] @ getw"
+ : "=&r" (value)
+- : "r" (a));
++ : "r" (a) : "cc");
+ return value;
+ }
+
+@@ -42,8 +42,8 @@ static inline unsigned int __arch_getw(u
+
+ static inline void __arch_putw(unsigned int value, unsigned long a)
+ {
+- __asm__ __volatile__("str%?h %0, [%1, #0] @ putw"
+- : : "r" (value), "r" (a));
++ __asm__ __volatile__("strh %0, [%1, #0] @ putw"
++ : : "r" (value), "r" (a) : "cc");
+ }
+
+ /*
+diff --git a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h
+index 7b98b53..ea22f7f 100644
+--- a/include/asm-arm/arch-l7200/time.h
++++ b/include/asm-arm/arch-l7200/time.h
+@@ -43,9 +43,10 @@
+ * Handler for RTC timer interrupt
+ */
+ static irqreturn_t
+-timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++timer_interrupt(int irq, void *dev_id)
+ {
+- do_timer(regs);
++ struct pt_regs *regs = get_irq_regs();
++ do_timer(1);
+ #ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+ #endif
+diff --git a/include/asm-arm/arch-lh7a40x/clocks.h b/include/asm-arm/arch-lh7a40x/clocks.h
+index bee02fd..7d0ba18 100644
+--- a/include/asm-arm/arch-lh7a40x/clocks.h
++++ b/include/asm-arm/arch-lh7a40x/clocks.h
+@@ -8,8 +8,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+-
+ #ifndef __ASM_ARCH_CLOCKS_H
+ #define __ASM_ARCH_CLOCKS_H
+
+diff --git a/include/asm-arm/arch-omap/board-ams-delta.h b/include/asm-arm/arch-omap/board-ams-delta.h
+index 0070f6d..9aee15d 100644
+--- a/include/asm-arm/arch-omap/board-ams-delta.h
++++ b/include/asm-arm/arch-omap/board-ams-delta.h
+@@ -50,9 +50,20 @@
+ #define AMS_DELTA_LATCH2_NAND_NWE 0x0020
+ #define AMS_DELTA_LATCH2_NAND_ALE 0x0040
+ #define AMS_DELTA_LATCH2_NAND_CLE 0x0080
++#define AMD_DELTA_LATCH2_KEYBRD_PWR 0x0100
++#define AMD_DELTA_LATCH2_KEYBRD_DATA 0x0200
++#define AMD_DELTA_LATCH2_SCARD_RSTIN 0x0400
++#define AMD_DELTA_LATCH2_SCARD_CMDVCC 0x0800
+ #define AMS_DELTA_LATCH2_MODEM_NRESET 0x1000
+ #define AMS_DELTA_LATCH2_MODEM_CODEC 0x2000
+
++#define AMS_DELTA_GPIO_PIN_KEYBRD_DATA 0
++#define AMS_DELTA_GPIO_PIN_KEYBRD_CLK 1
++#define AMS_DELTA_GPIO_PIN_MODEM_IRQ 2
++#define AMS_DELTA_GPIO_PIN_HOOK_SWITCH 4
++#define AMS_DELTA_GPIO_PIN_SCARD_NOFF 6
++#define AMS_DELTA_GPIO_PIN_SCARD_IO 7
++#define AMS_DELTA_GPIO_PIN_CONFIG 11
+ #define AMS_DELTA_GPIO_PIN_NAND_RB 12
+
+ #ifndef __ASSEMBLY__
+diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h
+index f83003f..fa68810 100644
+--- a/include/asm-arm/arch-omap/clock.h
++++ b/include/asm-arm/arch-omap/clock.h
+@@ -45,6 +45,7 @@ struct clk_functions {
+ struct clk * (*clk_get_parent)(struct clk *clk);
+ void (*clk_allow_idle)(struct clk *clk);
+ void (*clk_deny_idle)(struct clk *clk);
++ void (*clk_disable_unused)(struct clk *clk);
+ };
+
+ extern unsigned int mpurate;
+diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
+index 1b1b023..d591d05 100644
+--- a/include/asm-arm/arch-omap/dma.h
++++ b/include/asm-arm/arch-omap/dma.h
+@@ -331,6 +331,12 @@ enum omap_dma_color_mode {
+ OMAP_DMA_TRANSPARENT_COPY
+ };
+
++enum omap_dma_write_mode {
++ OMAP_DMA_WRITE_NON_POSTED = 0,
++ OMAP_DMA_WRITE_POSTED,
++ OMAP_DMA_WRITE_LAST_NON_POSTED
++};
++
+ struct omap_dma_channel_params {
+ int data_type; /* data type 8,16,32 */
+ int elem_count; /* number of elements in a frame */
+@@ -338,13 +344,13 @@ struct omap_dma_channel_params {
+
+ int src_port; /* Only on OMAP1 REVISIT: Is this needed? */
+ int src_amode; /* constant , post increment, indexed , double indexed */
+- int src_start; /* source address : physical */
++ unsigned long src_start; /* source address : physical */
+ int src_ei; /* source element index */
+ int src_fi; /* source frame index */
+
+ int dst_port; /* Only on OMAP1 REVISIT: Is this needed? */
+ int dst_amode; /* constant , post increment, indexed , double indexed */
+- int dst_start; /* source address : physical */
++ unsigned long dst_start; /* source address : physical */
+ int dst_ei; /* source element index */
+ int dst_fi; /* source frame index */
+
+@@ -356,7 +362,7 @@ struct omap_dma_channel_params {
+ };
+
+
+-extern void omap_set_dma_priority(int dst_port, int priority);
++extern void omap_set_dma_priority(int lch, int dst_port, int priority);
+ extern int omap_request_dma(int dev_id, const char *dev_name,
+ void (* callback)(int lch, u16 ch_status, void *data),
+ void *data, int *dma_ch);
+@@ -371,6 +377,7 @@ extern void omap_set_dma_transfer_params
+ int dma_trigger, int src_or_dst_synch);
+ extern void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode,
+ u32 color);
++extern void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode);
+
+ extern void omap_set_dma_src_params(int lch, int src_port, int src_amode,
+ unsigned long src_start,
+@@ -394,6 +401,9 @@ extern void omap_set_dma_params(int lch,
+ extern void omap_dma_link_lch (int lch_head, int lch_queue);
+ extern void omap_dma_unlink_lch (int lch_head, int lch_queue);
+
++extern int omap_set_dma_callback(int lch,
++ void (* callback)(int lch, u16 ch_status, void *data),
++ void *data);
+ extern dma_addr_t omap_get_dma_src_pos(int lch);
+ extern dma_addr_t omap_get_dma_dst_pos(int lch);
+ extern int omap_get_dma_src_addr_counter(int lch);
+diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h
+index 7a289ff..fefb276 100644
+--- a/include/asm-arm/arch-omap/dmtimer.h
++++ b/include/asm-arm/arch-omap/dmtimer.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/arm/arch-omap/dmtimer.h
++ * linux/include/asm-arm/arch-omap/dmtimer.h
+ *
+ * OMAP Dual-Mode Timers
+ *
+@@ -52,6 +52,8 @@ int omap_dm_timer_init(void);
+ struct omap_dm_timer *omap_dm_timer_request(void);
+ struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
+ void omap_dm_timer_free(struct omap_dm_timer *timer);
++void omap_dm_timer_enable(struct omap_dm_timer *timer);
++void omap_dm_timer_disable(struct omap_dm_timer *timer);
+
+ int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
+
+diff --git a/include/asm-arm/arch-omap/gpmc.h b/include/asm-arm/arch-omap/gpmc.h
+index 1a0a520..7c03ef6 100644
+--- a/include/asm-arm/arch-omap/gpmc.h
++++ b/include/asm-arm/arch-omap/gpmc.h
+@@ -85,7 +85,7 @@ extern void gpmc_cs_write_reg(int cs, in
+ extern u32 gpmc_cs_read_reg(int cs, int idx);
+ extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
+ extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
+-extern unsigned long gpmc_cs_get_base_addr(int cs);
+-
++extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
++extern void gpmc_cs_free(int cs);
+
+ #endif
+diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
+index 2542495..c5bb05a 100644
+--- a/include/asm-arm/arch-omap/irqs.h
++++ b/include/asm-arm/arch-omap/irqs.h
+@@ -237,6 +237,7 @@
+ #define INT_24XX_SDMA_IRQ1 13
+ #define INT_24XX_SDMA_IRQ2 14
+ #define INT_24XX_SDMA_IRQ3 15
++#define INT_24XX_CAM_IRQ 24
+ #define INT_24XX_DSS_IRQ 25
+ #define INT_24XX_GPIO_BANK1 29
+ #define INT_24XX_GPIO_BANK2 30
+@@ -261,6 +262,7 @@
+ #define INT_24XX_UART1_IRQ 72
+ #define INT_24XX_UART2_IRQ 73
+ #define INT_24XX_UART3_IRQ 74
++#define INT_24XX_MMC_IRQ 83
+
+ /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
+ * 16 MPUIO lines */
+diff --git a/include/asm-arm/arch-omap/keypad.h b/include/asm-arm/arch-omap/keypad.h
+index 8a023a9..b7f8307 100644
+--- a/include/asm-arm/arch-omap/keypad.h
++++ b/include/asm-arm/arch-omap/keypad.h
+@@ -14,7 +14,10 @@ struct omap_kp_platform_data {
+ int rows;
+ int cols;
+ int *keymap;
++ unsigned int keymapsize;
+ unsigned int rep:1;
++ unsigned long delay;
++ unsigned int dbounce:1;
+ /* specific to OMAP242x*/
+ unsigned int *row_gpios;
+ unsigned int *col_gpios;
+diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h
+index ed0dde4..c7a0cc1 100644
+--- a/include/asm-arm/arch-omap/mcbsp.h
++++ b/include/asm-arm/arch-omap/mcbsp.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/arch-omap/gpio.h
++ * linux/include/asm-arm/arch-omap/mcbsp.h
+ *
+ * Defines for Multi-Channel Buffered Serial Port
+ *
+diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
+index 679869c..828cc5c 100644
+--- a/include/asm-arm/arch-omap/mux.h
++++ b/include/asm-arm/arch-omap/mux.h
+@@ -320,6 +320,17 @@ enum omap1xxx_index {
+ P15_1610_UWIRE_CS3,
+ N15_1610_UWIRE_CS1,
+
++ /* OMAP-1610 SPI */
++ U19_1610_SPIF_SCK,
++ U18_1610_SPIF_DIN,
++ P20_1610_SPIF_DIN,
++ W21_1610_SPIF_DOUT,
++ R18_1610_SPIF_DOUT,
++ N14_1610_SPIF_CS0,
++ N15_1610_SPIF_CS1,
++ T19_1610_SPIF_CS2,
++ P15_1610_SPIF_CS3,
++
+ /* OMAP-1610 Flash */
+ L3_1610_FLASH_CS2B_OE,
+ M8_1610_FLASH_CS2B_WE,
+@@ -461,6 +472,20 @@ enum omap24xx_index {
+ K15_24XX_UART3_TX,
+ K14_24XX_UART3_RX,
+
++ /* MMC/SDIO */
++ G19_24XX_MMC_CLKO,
++ H18_24XX_MMC_CMD,
++ F20_24XX_MMC_DAT0,
++ H14_24XX_MMC_DAT1,
++ E19_24XX_MMC_DAT2,
++ D19_24XX_MMC_DAT3,
++ F19_24XX_MMC_DAT_DIR0,
++ E20_24XX_MMC_DAT_DIR1,
++ F18_24XX_MMC_DAT_DIR2,
++ E18_24XX_MMC_DAT_DIR3,
++ G18_24XX_MMC_CMD_DIR,
++ H15_24XX_MMC_CLKI,
++
+ /* Keypad GPIO*/
+ T19_24XX_KBR0,
+ R19_24XX_KBR1,
+diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h
+index e46623c..1458805 100644
+--- a/include/asm-arm/arch-omap/pm.h
++++ b/include/asm-arm/arch-omap/pm.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm/arch-omap/pm.h
++ * linux/include/asm-arm/arch-omap/pm.h
+ *
+ * Header file for OMAP Power Management Routines
+ *
+diff --git a/include/asm-arm/arch-pnx4008/clock.h b/include/asm-arm/arch-pnx4008/clock.h
+index 91ae003..ce155e1 100644
+--- a/include/asm-arm/arch-pnx4008/clock.h
++++ b/include/asm-arm/arch-pnx4008/clock.h
+@@ -32,6 +32,7 @@ struct clk;
+ #define KEYCLKCTRL_REG (PWRMAN_VA_BASE + 0xb0)
+ #define TSCLKCTRL_REG (PWRMAN_VA_BASE + 0xb4)
+ #define PWMCLKCTRL_REG (PWRMAN_VA_BASE + 0xb8)
++#define TIMCLKCTRL_REG (PWRMAN_VA_BASE + 0xbc)
+ #define SPICTRL_REG (PWRMAN_VA_BASE + 0xc4)
+ #define FLASHCLKCTRL_REG (PWRMAN_VA_BASE + 0xc8)
+ #define UART3CLK_REG (PWRMAN_VA_BASE + 0xd0)
+diff --git a/include/asm-arm/arch-pnx4008/dma.h b/include/asm-arm/arch-pnx4008/dma.h
+index 3aee120..418f152 100644
+--- a/include/asm-arm/arch-pnx4008/dma.h
++++ b/include/asm-arm/arch-pnx4008/dma.h
+@@ -137,7 +137,7 @@ extern void pnx4008_free_ll_entry(struct
+ extern void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll *);
+
+ extern int pnx4008_request_channel(char *, int,
+- void (*)(int, int, void *, struct pt_regs *),
++ void (*)(int, int, void *),
+ void *);
+ extern void pnx4008_free_channel(int);
+ extern int pnx4008_config_dma(int, int, int);
+diff --git a/include/asm-arm/arch-pnx4008/platform.h b/include/asm-arm/arch-pnx4008/platform.h
+index 485a365..2613c7c 100644
+--- a/include/asm-arm/arch-pnx4008/platform.h
++++ b/include/asm-arm/arch-pnx4008/platform.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-arm/arch-pnx4008/platfrom.h
++ * include/asm-arm/arch-pnx4008/platform.h
+ *
+ * PNX4008 Base addresses - header file
+ *
+diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h
+index a008150..bed042d 100644
+--- a/include/asm-arm/arch-pxa/dma.h
++++ b/include/asm-arm/arch-pxa/dma.h
+@@ -56,7 +56,7 @@ for ( \
+
+ int pxa_request_dma (char *name,
+ pxa_dma_prio prio,
+- void (*irq_handler)(int, void *, struct pt_regs *),
++ void (*irq_handler)(int, void *),
+ void *data);
+
+ void pxa_free_dma (int dma_ch);
+diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
+index f3bc70e..67ed436 100644
+--- a/include/asm-arm/arch-pxa/irqs.h
++++ b/include/asm-arm/arch-pxa/irqs.h
+@@ -73,7 +73,7 @@
+ #define IRQ_TO_GPIO(i) (((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
+
+ #if defined(CONFIG_PXA25x)
+-#define PXA_LAST_GPIO 80
++#define PXA_LAST_GPIO 84
+ #elif defined(CONFIG_PXA27x)
+ #define PXA_LAST_GPIO 127
+ #endif
+diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
+index 88c17dd..a38a28c 100644
+--- a/include/asm-arm/arch-pxa/mmc.h
++++ b/include/asm-arm/arch-pxa/mmc.h
+@@ -10,7 +10,7 @@ struct mmc_host;
+ struct pxamci_platform_data {
+ unsigned int ocr_mask; /* available voltages */
+ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */
+- int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *);
++ int (*init)(struct device *, irq_handler_t , void *);
+ int (*get_ro)(struct device *);
+ void (*setpower)(struct device *, unsigned int);
+ void (*exit)(struct device *, void *);
+diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
+index f5cc65d..cff752f 100644
+--- a/include/asm-arm/arch-pxa/pxa-regs.h
++++ b/include/asm-arm/arch-pxa/pxa-regs.h
+@@ -1681,6 +1681,7 @@
+ #define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */
+ #define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
+
++#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
+ #define SSPSP_DMYSTOP(x) (x << 23) /* Dummy Stop */
+ #define SSPSP_SFRMWDTH(x) (x << 16) /* Serial Frame Width */
+ #define SSPSP_SFRMDLY(x) (x << 9) /* Serial Frame Delay */
+@@ -2241,7 +2242,7 @@
+
+ #define CICR1_TBIT (1 << 31) /* Transparency bit */
+ #define CICR1_RGBT_CONV (0x3 << 30) /* RGBT conversion mask */
+-#define CICR1_PPL (0x3f << 15) /* Pixels per line mask */
++#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */
+ #define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */
+ #define CICR1_RGB_F (1 << 11) /* RGB format */
+ #define CICR1_YCBCR_F (1 << 10) /* YCbCr format */
+@@ -2267,7 +2268,7 @@
+ #define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */
+ #define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock
+ wait count mask */
+-#define CICR3_LPF (0x3ff << 0) /* Lines per frame mask */
++#define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */
+
+ #define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */
+ #define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */
+@@ -2288,8 +2289,8 @@
+ #define CISR_EOL (1 << 8) /* End of line */
+ #define CISR_PAR_ERR (1 << 7) /* Parity error */
+ #define CISR_CQD (1 << 6) /* Camera interface quick disable */
+-#define CISR_SOF (1 << 5) /* Start of frame */
+-#define CISR_CDD (1 << 4) /* Camera interface disable done */
++#define CISR_CDD (1 << 5) /* Camera interface disable done */
++#define CISR_SOF (1 << 4) /* Start of frame */
+ #define CISR_EOF (1 << 3) /* End of frame */
+ #define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */
+ #define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */
+diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h
+index aba9b30..81c3928 100644
+--- a/include/asm-arm/arch-pxa/pxafb.h
++++ b/include/asm-arm/arch-pxa/pxafb.h
+@@ -12,12 +12,14 @@
+ * published by the Free Software Foundation.
+ */
+
++#include <linux/fb.h>
++
+ /*
+ * This structure describes the machine which we are running on.
+ * It is set in linux/arch/arm/mach-pxa/machine_name.c and used in the probe routine
+ * of linux/drivers/video/pxafb.c
+ */
+-struct pxafb_mach_info {
++struct pxafb_mode_info {
+ u_long pixclock;
+
+ u_short xres;
+@@ -34,6 +36,14 @@ struct pxafb_mach_info {
+ u_char sync;
+
+ u_int cmap_greyscale:1,
++ unused:31;
++};
++
++struct pxafb_mach_info {
++ struct pxafb_mode_info *modes;
++ unsigned int num_modes;
++
++ u_int fixed_modes:1,
+ cmap_inverse:1,
+ cmap_static:1,
+ unused:29;
+@@ -62,7 +72,7 @@ struct pxafb_mach_info {
+ u_int lccr3;
+
+ void (*pxafb_backlight_power)(int);
+- void (*pxafb_lcd_power)(int);
++ void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
+
+ };
+ void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info);
+diff --git a/include/asm-arm/arch-pxa/spitz.h b/include/asm-arm/arch-pxa/spitz.h
+index 62e1fe4..4953dd3 100644
+--- a/include/asm-arm/arch-pxa/spitz.h
++++ b/include/asm-arm/arch-pxa/spitz.h
+@@ -15,6 +15,8 @@
+ #define __ASM_ARCH_SPITZ_H 1
+ #endif
+
++#include <linux/fb.h>
++
+ /* Spitz/Akita GPIOs */
+
+ #define SPITZ_GPIO_KEY_INT (0) /* Key Interrupt */
+@@ -155,4 +157,4 @@ extern struct platform_device spitzscoop
+ extern struct platform_device spitzssp_device;
+ extern struct sharpsl_charger_machinfo spitz_pm_machinfo;
+
+-extern void spitz_lcd_power(int on);
++extern void spitz_lcd_power(int on, struct fb_var_screeninfo *var);
+diff --git a/include/asm-arm/arch-pxa/udc.h b/include/asm-arm/arch-pxa/udc.h
+index 30548a3..121cd24 100644
+--- a/include/asm-arm/arch-pxa/udc.h
++++ b/include/asm-arm/arch-pxa/udc.h
+@@ -12,6 +12,14 @@ struct pxa2xx_udc_mach_info {
+ void (*udc_command)(int cmd);
+ #define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */
+ #define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */
++
++ /* Boards following the design guidelines in the developer's manual,
++ * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
++ * VBUS IRQ and omit the methods above. Store the GPIO number
++ * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
++ */
++ u16 gpio_vbus; /* high == vbus present */
++ u16 gpio_pullup; /* high == pullup activated */
+ };
+
+ extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);
+diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
+index 3661e46..7ac2248 100644
+--- a/include/asm-arm/arch-s3c2410/dma.h
++++ b/include/asm-arm/arch-s3c2410/dma.h
+@@ -23,6 +23,39 @@
+ #define MAX_DMA_ADDRESS 0x40000000
+ #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
+
++/* We use `virtual` dma channels to hide the fact we have only a limited
++ * number of DMA channels, and not of all of them (dependant on the device)
++ * can be attached to any DMA source. We therefore let the DMA core handle
++ * the allocation of hardware channels to clients.
++*/
++
++enum dma_ch {
++ DMACH_XD0,
++ DMACH_XD1,
++ DMACH_SDI,
++ DMACH_SPI0,
++ DMACH_SPI1,
++ DMACH_UART0,
++ DMACH_UART1,
++ DMACH_UART2,
++ DMACH_TIMER,
++ DMACH_I2S_IN,
++ DMACH_I2S_OUT,
++ DMACH_PCM_IN,
++ DMACH_PCM_OUT,
++ DMACH_MIC_IN,
++ DMACH_USB_EP1,
++ DMACH_USB_EP2,
++ DMACH_USB_EP3,
++ DMACH_USB_EP4,
++ DMACH_UART0_SRC2, /* s3c2412 second uart sources */
++ DMACH_UART1_SRC2,
++ DMACH_UART2_SRC2,
++ DMACH_MAX, /* the end entry */
++};
++
++#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
++
+ /* we have 4 dma channels */
+ #define S3C2410_DMA_CHANNELS (4)
+
+@@ -149,6 +182,8 @@ struct s3c2410_dma_stats {
+ unsigned long timeout_failed;
+ };
+
++struct s3c2410_dma_map;
++
+ /* struct s3c2410_dma_chan
+ *
+ * full state information for each DMA channel
+@@ -174,6 +209,8 @@ struct s3c2410_dma_chan {
+ unsigned long load_timeout;
+ unsigned int flags; /* channel flags */
+
++ struct s3c24xx_dma_map *map; /* channel hw maps */
++
+ /* channel's hardware position and configuration */
+ void __iomem *regs; /* channels registers */
+ void __iomem *addr_reg; /* data address register */
+@@ -283,6 +320,7 @@ extern int s3c2410_dma_set_buffdone_fn(d
+ #define S3C2410_DMA_DCSRC (0x18)
+ #define S3C2410_DMA_DCDST (0x1C)
+ #define S3C2410_DMA_DMASKTRIG (0x20)
++#define S3C2412_DMA_DMAREQSEL (0x24)
+
+ #define S3C2410_DISRCC_INC (1<<0)
+ #define S3C2410_DISRCC_APB (1<<1)
+@@ -349,4 +387,32 @@ extern int s3c2410_dma_set_buffdone_fn(d
+ #define S3C2440_DCON_CH3_PCMOUT (6<<24)
+ #endif
+
++#ifdef CONFIG_CPU_S3C2412
++
++#define S3C2412_DMAREQSEL_SRC(x) ((x)<<1)
++
++#define S3C2412_DMAREQSEL_HW (1)
++
++#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0)
++#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1)
++#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2)
++#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3)
++#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4)
++#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5)
++#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9)
++#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10)
++#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13)
++#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14)
++#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15)
++#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16)
++#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17)
++#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18)
++#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19)
++#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20)
++#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21)
++#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22)
++#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23)
++#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
++
++#endif
+ #endif /* __ASM_ARCH_DMA_H */
+diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h
+index 7116179..9089421 100644
+--- a/include/asm-arm/arch-s3c2410/fb.h
++++ b/include/asm-arm/arch-s3c2410/fb.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/fb.h
++/* linux/include/asm-arm/arch-s3c2410/fb.h
+ *
+ * Copyright (c) 2004 Arnaud Patard <arnaud.patard at rtp-net.org>
+ *
+diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h
+index 27ba0ac..7895042 100644
+--- a/include/asm-arm/arch-s3c2410/map.h
++++ b/include/asm-arm/arch-s3c2410/map.h
+@@ -160,6 +160,11 @@
+ #define S3C2440_PA_CAMIF (0x4F000000)
+ #define S3C2440_SZ_CAMIF SZ_1M
+
++/* AC97 */
++
++#define S3C2440_PA_AC97 (0x5B000000)
++#define S3C2440_SZ_AC97 SZ_1M
++
+ /* ISA style IO, for each machine to sort out mappings for, if it
+ * implements it. We reserve two 16M regions for ISA.
+ */
+diff --git a/include/asm-arm/arch-s3c2410/osiris-map.h b/include/asm-arm/arch-s3c2410/osiris-map.h
+index e2d4062..a14164d 100644
+--- a/include/asm-arm/arch-s3c2410/osiris-map.h
++++ b/include/asm-arm/arch-s3c2410/osiris-map.h
+@@ -18,22 +18,22 @@
+
+ /* start peripherals off after the S3C2410 */
+
+-#define OSIRIS_IOADDR(x) (S3C2410_ADDR((x) + 0x05000000))
++#define OSIRIS_IOADDR(x) (S3C2410_ADDR((x) + 0x04000000))
+
+-#define OSIRIS_PA_CPLD (S3C2410_CS1 | (3<<25))
++#define OSIRIS_PA_CPLD (S3C2410_CS1 | (1<<26))
+
+ /* we put the CPLD registers next, to get them out of the way */
+
+-#define OSIRIS_VA_CTRL1 OSIRIS_IOADDR(0x00000000) /* 0x01300000 */
++#define OSIRIS_VA_CTRL1 OSIRIS_IOADDR(0x00000000)
+ #define OSIRIS_PA_CTRL1 (OSIRIS_PA_CPLD)
+
+-#define OSIRIS_VA_CTRL2 OSIRIS_IOADDR(0x00100000) /* 0x01400000 */
+-#define OSIRIS_PA_CTRL2 (OSIRIS_PA_CPLD + (1<<24))
++#define OSIRIS_VA_CTRL2 OSIRIS_IOADDR(0x00100000)
++#define OSIRIS_PA_CTRL2 (OSIRIS_PA_CPLD + (1<<23))
+
+-#define OSIRIS_VA_CTRL3 OSIRIS_IOADDR(0x00200000) /* 0x01500000 */
+-#define OSIRIS_PA_CTRL3 (OSIRIS_PA_CPLD + (2<<24))
++#define OSIRIS_VA_CTRL3 OSIRIS_IOADDR(0x00200000)
++#define OSIRIS_PA_CTRL3 (OSIRIS_PA_CPLD + (2<<23))
+
+-#define OSIRIS_VA_CTRL4 OSIRIS_IOADDR(0x00300000) /* 0x01600000 */
+-#define OSIRIS_PA_CTRL4 (OSIRIS_PA_CPLD + (3<<24))
++#define OSIRIS_VA_CTRL4 OSIRIS_IOADDR(0x00300000)
++#define OSIRIS_PA_CTRL4 (OSIRIS_PA_CPLD + (3<<23))
+
+ #endif /* __ASM_ARCH_OSIRISMAP_H */
+diff --git a/include/asm-arm/arch-s3c2410/regs-ac97.h b/include/asm-arm/arch-s3c2410/regs-ac97.h
+new file mode 100644
+index 0000000..bdd6a4f
+--- /dev/null
++++ b/include/asm-arm/arch-s3c2410/regs-ac97.h
+@@ -0,0 +1,23 @@
++/* linux/include/asm-arm/arch-s3c2410/regs-ac97.h
++ *
++ * Copyright (c) 2006 Simtec Electronics <linux at simtec.co.uk>
++ * http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * 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.
++ *
++ * S3C2440 AC97 Controller
++*/
++
++#ifndef __ASM_ARCH_REGS_AC97_H
++#define __ASM_ARCH_REGS_AC97_H __FILE__
++
++#define S3C_AC97_GLBCTRL (0x00)
++#define S3C_AC97_GLBSTAT (0x04)
++#define S3C_AC97_CODEC_CMD (0x08)
++#define S3C_AC97_PCM_ADDR (0x10)
++#define S3C_AC97_PCM_DATA (0x18)
++#define S3C_AC97_MIC_DATA (0x1C)
++
++#endif /* __ASM_ARCH_REGS_AC97_H */
+diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h
+index c7b90b3..3196a28 100644
+--- a/include/asm-arm/arch-s3c2410/regs-adc.h
++++ b/include/asm-arm/arch-s3c2410/regs-adc.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-adc.h
++/* linux/include/asm-arm/arch-s3c2410/regs-adc.h
+ *
+ * Copyright (c) 2004 Shannon Holland <holland at loser.net>
+ *
+diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
+index b2f4690..e39656b 100644
+--- a/include/asm-arm/arch-s3c2410/regs-clock.h
++++ b/include/asm-arm/arch-s3c2410/regs-clock.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-clock.h
++/* linux/include/asm-arm/arch-s3c2410/regs-clock.h
+ *
+ * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux at simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h
+index a0a1248..c074851 100644
+--- a/include/asm-arm/arch-s3c2410/regs-dsc.h
++++ b/include/asm-arm/arch-s3c2410/regs-dsc.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/hardware/s3c2410/regs-dsc.h
++/* linux/include/asm-arm/arch-s3c2410/regs-dsc.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
+index 93c4943..b2893e3 100644
+--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
++++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/hardware/s3c2410/regs-gpio.h
++/* linux/include/asm-arm/arch-s3c2410/regs-gpio.h
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h
+index 91cefa2..02131a5 100644
+--- a/include/asm-arm/arch-s3c2410/regs-gpioj.h
++++ b/include/asm-arm/arch-s3c2410/regs-gpioj.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/hardware/s3c2410/regs-gpioj.h
++/* linux/include/asm-arm/arch-s3c2410/regs-gpioj.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h
+index 72cd250..eaf7791 100644
+--- a/include/asm-arm/arch-s3c2410/regs-iis.h
++++ b/include/asm-arm/arch-s3c2410/regs-iis.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-iis.h
++/* linux/include/asm-arm/arch-s3c2410/regs-iis.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h
+index 29fb8ef..498184c 100644
+--- a/include/asm-arm/arch-s3c2410/regs-irq.h
++++ b/include/asm-arm/arch-s3c2410/regs-irq.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-irq.h
++/* linux/include/asm-arm/arch-s3c2410/regs-irq.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h
+index b306d6e..b7faeb0 100644
+--- a/include/asm-arm/arch-s3c2410/regs-lcd.h
++++ b/include/asm-arm/arch-s3c2410/regs-lcd.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-lcd.h
++/* linux/include/asm-arm/arch-s3c2410/regs-lcd.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+@@ -63,6 +63,8 @@
+ #define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F)
+ #define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >> 0) & 0xFF)
+
++/* LDCCON4 changes for STN mode on the S3C2412 */
++
+ #define S3C2410_LCDCON4_MVAL(x) ((x) << 8)
+ #define S3C2410_LCDCON4_HSPW(x) ((x) << 0)
+ #define S3C2410_LCDCON4_WLH(x) ((x) << 0)
+@@ -113,10 +115,38 @@
+ #define S3C2410_LCDINT_FRSYNC (1<<1)
+ #define S3C2410_LCDINT_FICNT (1<<0)
+
++/* s3c2442 extra stn registers */
++
++#define S3C2442_REDLUT S3C2410_LCDREG(0x20)
++#define S3C2442_GREENLUT S3C2410_LCDREG(0x24)
++#define S3C2442_BLUELUT S3C2410_LCDREG(0x28)
++#define S3C2442_DITHMODE S3C2410_LCDREG(0x20)
++
+ #define S3C2410_LPCSEL S3C2410_LCDREG(0x60)
+
+ #define S3C2410_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4))
+
++/* S3C2412 registers */
++
++#define S3C2412_TPAL S3C2410_LCDREG(0x20)
++
++#define S3C2412_LCDINTPND S3C2410_LCDREG(0x24)
++#define S3C2412_LCDSRCPND S3C2410_LCDREG(0x28)
++#define S3C2412_LCDINTMSK S3C2410_LCDREG(0x2C)
++
++#define S3C2412_TCONSEL S3C2410_LCDREG(0x30)
++
++#define S3C2412_LCDCON6 S3C2410_LCDREG(0x34)
++#define S3C2412_LCDCON7 S3C2410_LCDREG(0x38)
++#define S3C2412_LCDCON8 S3C2410_LCDREG(0x3C)
++#define S3C2412_LCDCON9 S3C2410_LCDREG(0x40)
++
++#define S3C2412_REDLUT(x) S3C2410_LCDREG(0x44 + ((x)*4))
++#define S3C2412_GREENLUT(x) S3C2410_LCDREG(0x60 + ((x)*4))
++#define S3C2412_BLUELUT(x) S3C2410_LCDREG(0x98 + ((x)*4))
++
++#define S3C2412_FRCPAT(x) S3C2410_LCDREG(0xB4 + ((x)*4))
++
+ #endif /* ___ASM_ARCH_REGS_LCD_H */
+
+
+diff --git a/include/asm-arm/arch-s3c2410/regs-rtc.h b/include/asm-arm/arch-s3c2410/regs-rtc.h
+index cd88fd6..93b03c4 100644
+--- a/include/asm-arm/arch-s3c2410/regs-rtc.h
++++ b/include/asm-arm/arch-s3c2410/regs-rtc.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-rtc.h
++/* linux/include/asm-arm/arch-s3c2410/regs-rtc.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h
+index 06e716e..bb9d30b 100644
+--- a/include/asm-arm/arch-s3c2410/regs-sdi.h
++++ b/include/asm-arm/arch-s3c2410/regs-sdi.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-sdi.h
++/* linux/include/asm-arm/arch-s3c2410/regs-sdi.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/arch-s3c2410/regs-timer.h
+index 731918e..6f8fe43 100644
+--- a/include/asm-arm/arch-s3c2410/regs-timer.h
++++ b/include/asm-arm/arch-s3c2410/regs-timer.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-timer.h
++/* linux/include/asm-arm/arch-s3c2410/regs-timer.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux at simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
+index 3aa31a2..487861d 100644
+--- a/include/asm-arm/arch-s3c2410/regs-udc.h
++++ b/include/asm-arm/arch-s3c2410/regs-udc.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm/arch-s3c2410/regs-udc.h
++/* linux/include/asm-arm/arch-s3c2410/regs-udc.h
+ *
+ * Copyright (C) 2004 Herbert Poetzl <herbert at 13thfloor.at>
+ *
+diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h
+index 258c00b..c1e4db7 100644
+--- a/include/asm-arm/arch-s3c2410/spi-gpio.h
++++ b/include/asm-arm/arch-s3c2410/spi-gpio.h
+@@ -1,4 +1,4 @@
+-/* linux/include/asm-arm/arch-s3c2410/spi.h
++/* linux/include/asm-arm/arch-s3c2410/spi-gpio.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben at simtec.co.uk>
+diff --git a/include/asm-arm/arch-sa1100/jornada720.h b/include/asm-arm/arch-sa1100/jornada720.h
+index 1b8e8a3..3f37ca0 100644
+--- a/include/asm-arm/arch-sa1100/jornada720.h
++++ b/include/asm-arm/arch-sa1100/jornada720.h
+@@ -19,6 +19,20 @@
+ #define GPIO_JORNADA720_KEYBOARD_IRQ IRQ_GPIO0
+ #define GPIO_JORNADA720_MOUSE_IRQ IRQ_GPIO9
+
++/* MCU COMMANDS */
++#define MCU_GetBatteryData 0xc0
++#define MCU_GetScanKeyCode 0x90
++#define MCU_GetTouchSamples 0xa0
++#define MCU_GetContrast 0xD0
++#define MCU_SetContrast 0xD1
++#define MCU_GetBrightness 0xD2
++#define MCU_SetBrightness 0xD3
++#define MCU_ContrastOff 0xD8
++#define MCU_BrightnessOff 0xD9
++#define MCU_PWMOFF 0xDF
++#define MCU_TxDummy 0x11
++#define MCU_ErrorCode 0x00
++
+ #ifndef __ASSEMBLY__
+
+ void jornada720_mcu_init(void);
+diff --git a/include/asm-arm/arch-sa1100/neponset.h b/include/asm-arm/arch-sa1100/neponset.h
+index 8051fd7..09ec9e2 100644
+--- a/include/asm-arm/arch-sa1100/neponset.h
++++ b/include/asm-arm/arch-sa1100/neponset.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/arch-sa1100/assabet.h
++ * linux/include/asm-arm/arch-sa1100/neponset.h
+ *
+ * Created 2000/06/05 by Nicolas Pitre <nico at cam.org>
+ *
+diff --git a/include/asm-arm/arch-sa1100/uncompress.h b/include/asm-arm/arch-sa1100/uncompress.h
+index 2601a77..17e64d2 100644
+--- a/include/asm-arm/arch-sa1100/uncompress.h
++++ b/include/asm-arm/arch-sa1100/uncompress.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/arch-brutus/uncompress.h
++ * linux/include/asm-arm/arch-sa1100/uncompress.h
+ *
+ * (C) 1999 Nicolas Pitre <nico at cam.org>
+ *
+diff --git a/include/asm-arm/arch-shark/vmalloc.h b/include/asm-arm/arch-shark/vmalloc.h
+index 10db5d1..fac37c6 100644
+--- a/include/asm-arm/arch-shark/vmalloc.h
++++ b/include/asm-arm/arch-shark/vmalloc.h
+@@ -1,4 +1,4 @@
+ /*
+- * linux/include/asm-arm/arch-rpc/vmalloc.h
++ * linux/include/asm-arm/arch-shark/vmalloc.h
+ */
+ #define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+diff --git a/include/asm-arm/arch-versatile/hardware.h b/include/asm-arm/arch-versatile/hardware.h
+index 41c1bee..edc0659 100644
+--- a/include/asm-arm/arch-versatile/hardware.h
++++ b/include/asm-arm/arch-versatile/hardware.h
+@@ -28,8 +28,8 @@
+ /*
+ * PCI space virtual addresses
+ */
+-#define VERSATILE_PCI_VIRT_BASE 0xe8000000
+-#define VERSATILE_PCI_CFG_VIRT_BASE 0xe9000000
++#define VERSATILE_PCI_VIRT_BASE (void __iomem *)0xe8000000ul
++#define VERSATILE_PCI_CFG_VIRT_BASE (void __iomem *)0xe9000000ul
+
+ #if 0
+ #define VERSATILE_PCI_VIRT_MEM_BASE0 0xf4000000
+diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
+index 4b0ce3e..ea88aa6 100644
+--- a/include/asm-arm/atomic.h
++++ b/include/asm-arm/atomic.h
+@@ -128,10 +128,10 @@ static inline int atomic_add_return(int
+ unsigned long flags;
+ int val;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ val = v->counter;
+ v->counter = val += i;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+
+ return val;
+ }
+@@ -141,10 +141,10 @@ static inline int atomic_sub_return(int
+ unsigned long flags;
+ int val;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ val = v->counter;
+ v->counter = val -= i;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+
+ return val;
+ }
+@@ -154,11 +154,11 @@ static inline int atomic_cmpxchg(atomic_
+ int ret;
+ unsigned long flags;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+
+ return ret;
+ }
+@@ -167,9 +167,9 @@ static inline void atomic_clear_mask(uns
+ {
+ unsigned long flags;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ *addr &= ~mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+ }
+
+ #endif /* __LINUX_ARM_ARCH__ */
+diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h
+index 0ac54b1..b41831b 100644
+--- a/include/asm-arm/bitops.h
++++ b/include/asm-arm/bitops.h
+@@ -37,9 +37,9 @@ static inline void ____atomic_set_bit(un
+
+ p += bit >> 5;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ *p |= mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+ }
+
+ static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
+@@ -49,9 +49,9 @@ static inline void ____atomic_clear_bit(
+
+ p += bit >> 5;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ *p &= ~mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+ }
+
+ static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
+@@ -61,9 +61,9 @@ static inline void ____atomic_change_bit
+
+ p += bit >> 5;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ *p ^= mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+ }
+
+ static inline int
+@@ -75,10 +75,10 @@ ____atomic_test_and_set_bit(unsigned int
+
+ p += bit >> 5;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ res = *p;
+ *p = res | mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+
+ return res & mask;
+ }
+@@ -92,10 +92,10 @@ ____atomic_test_and_clear_bit(unsigned i
+
+ p += bit >> 5;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ res = *p;
+ *p = res & ~mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+
+ return res & mask;
+ }
+@@ -109,10 +109,10 @@ ____atomic_test_and_change_bit(unsigned
+
+ p += bit >> 5;
+
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ res = *p;
+ *p = res ^ mask;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+
+ return res & mask;
+ }
+diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
+index e4a2569..f084564 100644
+--- a/include/asm-arm/cacheflush.h
++++ b/include/asm-arm/cacheflush.h
+@@ -25,7 +25,7 @@
+ #undef _CACHE
+ #undef MULTI_CACHE
+
+-#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
++#if defined(CONFIG_CPU_CACHE_V3)
+ # ifdef _CACHE
+ # define MULTI_CACHE 1
+ # else
+@@ -33,7 +33,7 @@
+ # endif
+ #endif
+
+-#if defined(CONFIG_CPU_ARM720T)
++#if defined(CONFIG_CPU_CACHE_V4)
+ # ifdef _CACHE
+ # define MULTI_CACHE 1
+ # else
+@@ -54,7 +54,23 @@
+ # endif
+ #endif
+
+-#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
++#if defined(CONFIG_CPU_ARM940T)
++# ifdef _CACHE
++# define MULTI_CACHE 1
++# else
++# define _CACHE arm940
++# endif
++#endif
++
++#if defined(CONFIG_CPU_ARM946E)
++# ifdef _CACHE
++# define MULTI_CACHE 1
++# else
++# define _CACHE arm946
++# endif
++#endif
++
++#if defined(CONFIG_CPU_CACHE_V4WB)
+ # ifdef _CACHE
+ # define MULTI_CACHE 1
+ # else
+diff --git a/include/asm-arm/elf.h b/include/asm-arm/elf.h
+index ae7baa6..17f0c65 100644
+--- a/include/asm-arm/elf.h
++++ b/include/asm-arm/elf.h
+@@ -8,9 +8,6 @@
+
+ #include <asm/ptrace.h>
+ #include <asm/user.h>
+-#ifdef __KERNEL
+-#include <asm/procinfo.h>
+-#endif
+
+ typedef unsigned long elf_greg_t;
+ typedef unsigned long elf_freg_t[3];
+@@ -32,11 +29,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGR
+ typedef struct user_fp elf_fpregset_t;
+
+ /*
+- * This is used to ensure we don't load something for the wrong architecture.
+- */
+-#define elf_check_arch(x) ( ((x)->e_machine == EM_ARM) && (ELF_PROC_OK((x))) )
+-
+-/*
+ * These are used to set parameters in the core dumps.
+ */
+ #define ELF_CLASS ELFCLASS32
+@@ -47,6 +39,14 @@ typedef struct user_fp elf_fpregset_t;
+ #endif
+ #define ELF_ARCH EM_ARM
+
++#ifdef __KERNEL__
++#include <asm/procinfo.h>
++
++/*
++ * This is used to ensure we don't load something for the wrong architecture.
++ */
++#define elf_check_arch(x) ( ((x)->e_machine == EM_ARM) && (ELF_PROC_OK((x))) )
++
+ #define USE_ELF_CORE_DUMP
+ #define ELF_EXEC_PAGESIZE 4096
+
+@@ -83,8 +83,6 @@ typedef struct user_fp elf_fpregset_t;
+ extern char elf_platform[];
+ #define ELF_PLATFORM (elf_platform)
+
+-#ifdef __KERNEL__
+-
+ /*
+ * 32-bit code is always OK. Some cpus can do 26-bit, some can't.
+ */
+diff --git a/include/asm-arm/flat.h b/include/asm-arm/flat.h
+new file mode 100644
+index 0000000..9669464
+--- /dev/null
++++ b/include/asm-arm/flat.h
+@@ -0,0 +1,16 @@
++/*
++ * include/asm-arm/flat.h -- uClinux flat-format executables
++ */
++
++#ifndef __ARM_FLAT_H__
++#define __ARM_FLAT_H__
++
++#define flat_stack_align(sp) /* nothing needed */
++#define flat_argvp_envp_on_stack() 1
++#define flat_old_ram_flag(flags) (flags)
++#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
++#define flat_get_addr_from_rp(rp, relval, flags) get_unaligned(rp)
++#define flat_put_addr_at_rp(rp, val, relval) put_unaligned(val,rp)
++#define flat_get_relocate_addr(rel) (rel)
++
++#endif /* __ARM_FLAT_H__ */
+diff --git a/include/asm-arm/hardware/debug-8250.S b/include/asm-arm/hardware/debug-8250.S
+index 4594fea..07c97fb 100644
+--- a/include/asm-arm/hardware/debug-8250.S
++++ b/include/asm-arm/hardware/debug-8250.S
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/hardware/debug-8250.h
++ * linux/include/asm-arm/hardware/debug-8250.S
+ *
+ * Copyright (C) 1994-1999 Russell King
+ *
+diff --git a/include/asm-arm/hardware/debug-pl01x.S b/include/asm-arm/hardware/debug-pl01x.S
+index db0d0f7..23c541a 100644
+--- a/include/asm-arm/hardware/debug-pl01x.S
++++ b/include/asm-arm/hardware/debug-pl01x.S
+@@ -1,4 +1,4 @@
+-/* linux/include/asm-arm/arch-integrator/debug-macro.S
++/* linux/include/asm-arm/hardware/debug-pl01x.S
+ *
+ * Debugging macro include header
+ *
+diff --git a/include/asm-arm/hardware/entry-macro-iomd.S b/include/asm-arm/hardware/entry-macro-iomd.S
+index 30c7b92..fbed08f 100644
+--- a/include/asm-arm/hardware/entry-macro-iomd.S
++++ b/include/asm-arm/hardware/entry-macro-iomd.S
+@@ -1,5 +1,5 @@
+ /*
+- * arch/arm/commond/entry-macro-iomd.S
++ * include/asm-arm/hardware/entry-macro-iomd.S
+ *
+ * Low-level IRQ helper macros for IOC/IOMD based platforms
+ *
+diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
+new file mode 100644
+index 0000000..1018a74
+--- /dev/null
++++ b/include/asm-arm/hardware/iop3xx.h
+@@ -0,0 +1,301 @@
++/*
++ * include/asm-arm/hardware/iop3xx.h
++ *
++ * Intel IOP32X and IOP33X register definitions
++ *
++ * Author: Rory Bolt <rorybolt at pacbell.net>
++ * Copyright (C) 2002 Rory Bolt
++ * Copyright (C) 2004 Intel Corp.
++ *
++ * 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 __IOP3XX_H
++#define __IOP3XX_H
++
++/*
++ * IOP3XX GPIO handling
++ */
++#define GPIO_IN 0
++#define GPIO_OUT 1
++#define GPIO_LOW 0
++#define GPIO_HIGH 1
++#define IOP3XX_GPIO_LINE(x) (x)
++
++#ifndef __ASSEMBLY__
++extern void gpio_line_config(int line, int direction);
++extern int gpio_line_get(int line);
++extern void gpio_line_set(int line, int value);
++#endif
++
++
++/*
++ * IOP3XX processor registers
++ */
++#define IOP3XX_PERIPHERAL_PHYS_BASE 0xffffe000
++#define IOP3XX_PERIPHERAL_VIRT_BASE 0xfeffe000
++#define IOP3XX_PERIPHERAL_SIZE 0x00002000
++#define IOP3XX_REG_ADDR(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + (reg))
++
++/* Address Translation Unit */
++#define IOP3XX_ATUVID (volatile u16 *)IOP3XX_REG_ADDR(0x0100)
++#define IOP3XX_ATUDID (volatile u16 *)IOP3XX_REG_ADDR(0x0102)
++#define IOP3XX_ATUCMD (volatile u16 *)IOP3XX_REG_ADDR(0x0104)
++#define IOP3XX_ATUSR (volatile u16 *)IOP3XX_REG_ADDR(0x0106)
++#define IOP3XX_ATURID (volatile u8 *)IOP3XX_REG_ADDR(0x0108)
++#define IOP3XX_ATUCCR (volatile u32 *)IOP3XX_REG_ADDR(0x0109)
++#define IOP3XX_ATUCLSR (volatile u8 *)IOP3XX_REG_ADDR(0x010c)
++#define IOP3XX_ATULT (volatile u8 *)IOP3XX_REG_ADDR(0x010d)
++#define IOP3XX_ATUHTR (volatile u8 *)IOP3XX_REG_ADDR(0x010e)
++#define IOP3XX_ATUBIST (volatile u8 *)IOP3XX_REG_ADDR(0x010f)
++#define IOP3XX_IABAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0110)
++#define IOP3XX_IAUBAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0114)
++#define IOP3XX_IABAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0118)
++#define IOP3XX_IAUBAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x011c)
++#define IOP3XX_IABAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0120)
++#define IOP3XX_IAUBAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0124)
++#define IOP3XX_ASVIR (volatile u16 *)IOP3XX_REG_ADDR(0x012c)
++#define IOP3XX_ASIR (volatile u16 *)IOP3XX_REG_ADDR(0x012e)
++#define IOP3XX_ERBAR (volatile u32 *)IOP3XX_REG_ADDR(0x0130)
++#define IOP3XX_ATUILR (volatile u8 *)IOP3XX_REG_ADDR(0x013c)
++#define IOP3XX_ATUIPR (volatile u8 *)IOP3XX_REG_ADDR(0x013d)
++#define IOP3XX_ATUMGNT (volatile u8 *)IOP3XX_REG_ADDR(0x013e)
++#define IOP3XX_ATUMLAT (volatile u8 *)IOP3XX_REG_ADDR(0x013f)
++#define IOP3XX_IALR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0140)
++#define IOP3XX_IATVR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0144)
++#define IOP3XX_ERLR (volatile u32 *)IOP3XX_REG_ADDR(0x0148)
++#define IOP3XX_ERTVR (volatile u32 *)IOP3XX_REG_ADDR(0x014c)
++#define IOP3XX_IALR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0150)
++#define IOP3XX_IALR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0154)
++#define IOP3XX_IATVR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0158)
++#define IOP3XX_OIOWTVR (volatile u32 *)IOP3XX_REG_ADDR(0x015c)
++#define IOP3XX_OMWTVR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0160)
++#define IOP3XX_OUMWTVR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0164)
++#define IOP3XX_OMWTVR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0168)
++#define IOP3XX_OUMWTVR1 (volatile u32 *)IOP3XX_REG_ADDR(0x016c)
++#define IOP3XX_OUDWTVR (volatile u32 *)IOP3XX_REG_ADDR(0x0178)
++#define IOP3XX_ATUCR (volatile u32 *)IOP3XX_REG_ADDR(0x0180)
++#define IOP3XX_PCSR (volatile u32 *)IOP3XX_REG_ADDR(0x0184)
++#define IOP3XX_ATUISR (volatile u32 *)IOP3XX_REG_ADDR(0x0188)
++#define IOP3XX_ATUIMR (volatile u32 *)IOP3XX_REG_ADDR(0x018c)
++#define IOP3XX_IABAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0190)
++#define IOP3XX_IAUBAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0194)
++#define IOP3XX_IALR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0198)
++#define IOP3XX_IATVR3 (volatile u32 *)IOP3XX_REG_ADDR(0x019c)
++#define IOP3XX_OCCAR (volatile u32 *)IOP3XX_REG_ADDR(0x01a4)
++#define IOP3XX_OCCDR (volatile u32 *)IOP3XX_REG_ADDR(0x01ac)
++#define IOP3XX_PDSCR (volatile u32 *)IOP3XX_REG_ADDR(0x01bc)
++#define IOP3XX_PMCAPID (volatile u8 *)IOP3XX_REG_ADDR(0x01c0)
++#define IOP3XX_PMNEXT (volatile u8 *)IOP3XX_REG_ADDR(0x01c1)
++#define IOP3XX_APMCR (volatile u16 *)IOP3XX_REG_ADDR(0x01c2)
++#define IOP3XX_APMCSR (volatile u16 *)IOP3XX_REG_ADDR(0x01c4)
++#define IOP3XX_PCIXCAPID (volatile u8 *)IOP3XX_REG_ADDR(0x01e0)
++#define IOP3XX_PCIXNEXT (volatile u8 *)IOP3XX_REG_ADDR(0x01e1)
++#define IOP3XX_PCIXCMD (volatile u16 *)IOP3XX_REG_ADDR(0x01e2)
++#define IOP3XX_PCIXSR (volatile u32 *)IOP3XX_REG_ADDR(0x01e4)
++#define IOP3XX_PCIIRSR (volatile u32 *)IOP3XX_REG_ADDR(0x01ec)
++
++/* Messaging Unit */
++#define IOP3XX_IMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0310)
++#define IOP3XX_IMR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0314)
++#define IOP3XX_OMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0318)
++#define IOP3XX_OMR1 (volatile u32 *)IOP3XX_REG_ADDR(0x031c)
++#define IOP3XX_IDR (volatile u32 *)IOP3XX_REG_ADDR(0x0320)
++#define IOP3XX_IISR (volatile u32 *)IOP3XX_REG_ADDR(0x0324)
++#define IOP3XX_IIMR (volatile u32 *)IOP3XX_REG_ADDR(0x0328)
++#define IOP3XX_ODR (volatile u32 *)IOP3XX_REG_ADDR(0x032c)
++#define IOP3XX_OISR (volatile u32 *)IOP3XX_REG_ADDR(0x0330)
++#define IOP3XX_OIMR (volatile u32 *)IOP3XX_REG_ADDR(0x0334)
++#define IOP3XX_MUCR (volatile u32 *)IOP3XX_REG_ADDR(0x0350)
++#define IOP3XX_QBAR (volatile u32 *)IOP3XX_REG_ADDR(0x0354)
++#define IOP3XX_IFHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0360)
++#define IOP3XX_IFTPR (volatile u32 *)IOP3XX_REG_ADDR(0x0364)
++#define IOP3XX_IPHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0368)
++#define IOP3XX_IPTPR (volatile u32 *)IOP3XX_REG_ADDR(0x036c)
++#define IOP3XX_OFHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0370)
++#define IOP3XX_OFTPR (volatile u32 *)IOP3XX_REG_ADDR(0x0374)
++#define IOP3XX_OPHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0378)
++#define IOP3XX_OPTPR (volatile u32 *)IOP3XX_REG_ADDR(0x037c)
++#define IOP3XX_IAR (volatile u32 *)IOP3XX_REG_ADDR(0x0380)
++
++/* DMA Controller */
++#define IOP3XX_DMA0_CCR (volatile u32 *)IOP3XX_REG_ADDR(0x0400)
++#define IOP3XX_DMA0_CSR (volatile u32 *)IOP3XX_REG_ADDR(0x0404)
++#define IOP3XX_DMA0_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x040c)
++#define IOP3XX_DMA0_NDAR (volatile u32 *)IOP3XX_REG_ADDR(0x0410)
++#define IOP3XX_DMA0_PADR (volatile u32 *)IOP3XX_REG_ADDR(0x0414)
++#define IOP3XX_DMA0_PUADR (volatile u32 *)IOP3XX_REG_ADDR(0x0418)
++#define IOP3XX_DMA0_LADR (volatile u32 *)IOP3XX_REG_ADDR(0x041c)
++#define IOP3XX_DMA0_BCR (volatile u32 *)IOP3XX_REG_ADDR(0x0420)
++#define IOP3XX_DMA0_DCR (volatile u32 *)IOP3XX_REG_ADDR(0x0424)
++#define IOP3XX_DMA1_CCR (volatile u32 *)IOP3XX_REG_ADDR(0x0440)
++#define IOP3XX_DMA1_CSR (volatile u32 *)IOP3XX_REG_ADDR(0x0444)
++#define IOP3XX_DMA1_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x044c)
++#define IOP3XX_DMA1_NDAR (volatile u32 *)IOP3XX_REG_ADDR(0x0450)
++#define IOP3XX_DMA1_PADR (volatile u32 *)IOP3XX_REG_ADDR(0x0454)
++#define IOP3XX_DMA1_PUADR (volatile u32 *)IOP3XX_REG_ADDR(0x0458)
++#define IOP3XX_DMA1_LADR (volatile u32 *)IOP3XX_REG_ADDR(0x045c)
++#define IOP3XX_DMA1_BCR (volatile u32 *)IOP3XX_REG_ADDR(0x0460)
++#define IOP3XX_DMA1_DCR (volatile u32 *)IOP3XX_REG_ADDR(0x0464)
++
++/* Peripheral bus interface */
++#define IOP3XX_PBCR (volatile u32 *)IOP3XX_REG_ADDR(0x0680)
++#define IOP3XX_PBISR (volatile u32 *)IOP3XX_REG_ADDR(0x0684)
++#define IOP3XX_PBBAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0688)
++#define IOP3XX_PBLR0 (volatile u32 *)IOP3XX_REG_ADDR(0x068c)
++#define IOP3XX_PBBAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0690)
++#define IOP3XX_PBLR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0694)
++#define IOP3XX_PBBAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0698)
++#define IOP3XX_PBLR2 (volatile u32 *)IOP3XX_REG_ADDR(0x069c)
++#define IOP3XX_PBBAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x06a0)
++#define IOP3XX_PBLR3 (volatile u32 *)IOP3XX_REG_ADDR(0x06a4)
++#define IOP3XX_PBBAR4 (volatile u32 *)IOP3XX_REG_ADDR(0x06a8)
++#define IOP3XX_PBLR4 (volatile u32 *)IOP3XX_REG_ADDR(0x06ac)
++#define IOP3XX_PBBAR5 (volatile u32 *)IOP3XX_REG_ADDR(0x06b0)
++#define IOP3XX_PBLR5 (volatile u32 *)IOP3XX_REG_ADDR(0x06b4)
++#define IOP3XX_PMBR0 (volatile u32 *)IOP3XX_REG_ADDR(0x06c0)
++#define IOP3XX_PMBR1 (volatile u32 *)IOP3XX_REG_ADDR(0x06e0)
++#define IOP3XX_PMBR2 (volatile u32 *)IOP3XX_REG_ADDR(0x06e4)
++
++/* Peripheral performance monitoring unit */
++#define IOP3XX_GTMR (volatile u32 *)IOP3XX_REG_ADDR(0x0700)
++#define IOP3XX_ESR (volatile u32 *)IOP3XX_REG_ADDR(0x0704)
++#define IOP3XX_EMISR (volatile u32 *)IOP3XX_REG_ADDR(0x0708)
++#define IOP3XX_GTSR (volatile u32 *)IOP3XX_REG_ADDR(0x0710)
++/* PERCR0 DOESN'T EXIST - index from 1! */
++#define IOP3XX_PERCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0710)
++
++/* General Purpose I/O */
++#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0004)
++#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0008)
++#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x000c)
++
++/* Timers */
++#define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000)
++#define IOP3XX_TU_TMR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0004)
++#define IOP3XX_TU_TCR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0008)
++#define IOP3XX_TU_TCR1 (volatile u32 *)IOP3XX_TIMER_REG(0x000c)
++#define IOP3XX_TU_TRR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0010)
++#define IOP3XX_TU_TRR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0014)
++#define IOP3XX_TU_TISR (volatile u32 *)IOP3XX_TIMER_REG(0x0018)
++#define IOP3XX_TU_WDTCR (volatile u32 *)IOP3XX_TIMER_REG(0x001c)
++#define IOP3XX_TMR_TC 0x01
++#define IOP3XX_TMR_EN 0x02
++#define IOP3XX_TMR_RELOAD 0x04
++#define IOP3XX_TMR_PRIVILEGED 0x09
++#define IOP3XX_TMR_RATIO_1_1 0x00
++#define IOP3XX_TMR_RATIO_4_1 0x10
++#define IOP3XX_TMR_RATIO_8_1 0x20
++#define IOP3XX_TMR_RATIO_16_1 0x30
++
++/* Application accelerator unit */
++#define IOP3XX_AAU_ACR (volatile u32 *)IOP3XX_REG_ADDR(0x0800)
++#define IOP3XX_AAU_ASR (volatile u32 *)IOP3XX_REG_ADDR(0x0804)
++#define IOP3XX_AAU_ADAR (volatile u32 *)IOP3XX_REG_ADDR(0x0808)
++#define IOP3XX_AAU_ANDAR (volatile u32 *)IOP3XX_REG_ADDR(0x080c)
++#define IOP3XX_AAU_SAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0810)
++#define IOP3XX_AAU_SAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0814)
++#define IOP3XX_AAU_SAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0818)
++#define IOP3XX_AAU_SAR4 (volatile u32 *)IOP3XX_REG_ADDR(0x081c)
++#define IOP3XX_AAU_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x0820)
++#define IOP3XX_AAU_ABCR (volatile u32 *)IOP3XX_REG_ADDR(0x0824)
++#define IOP3XX_AAU_ADCR (volatile u32 *)IOP3XX_REG_ADDR(0x0828)
++#define IOP3XX_AAU_SAR5 (volatile u32 *)IOP3XX_REG_ADDR(0x082c)
++#define IOP3XX_AAU_SAR6 (volatile u32 *)IOP3XX_REG_ADDR(0x0830)
++#define IOP3XX_AAU_SAR7 (volatile u32 *)IOP3XX_REG_ADDR(0x0834)
++#define IOP3XX_AAU_SAR8 (volatile u32 *)IOP3XX_REG_ADDR(0x0838)
++#define IOP3XX_AAU_EDCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x083c)
++#define IOP3XX_AAU_SAR9 (volatile u32 *)IOP3XX_REG_ADDR(0x0840)
++#define IOP3XX_AAU_SAR10 (volatile u32 *)IOP3XX_REG_ADDR(0x0844)
++#define IOP3XX_AAU_SAR11 (volatile u32 *)IOP3XX_REG_ADDR(0x0848)
++#define IOP3XX_AAU_SAR12 (volatile u32 *)IOP3XX_REG_ADDR(0x084c)
++#define IOP3XX_AAU_SAR13 (volatile u32 *)IOP3XX_REG_ADDR(0x0850)
++#define IOP3XX_AAU_SAR14 (volatile u32 *)IOP3XX_REG_ADDR(0x0854)
++#define IOP3XX_AAU_SAR15 (volatile u32 *)IOP3XX_REG_ADDR(0x0858)
++#define IOP3XX_AAU_SAR16 (volatile u32 *)IOP3XX_REG_ADDR(0x085c)
++#define IOP3XX_AAU_EDCR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0860)
++#define IOP3XX_AAU_SAR17 (volatile u32 *)IOP3XX_REG_ADDR(0x0864)
++#define IOP3XX_AAU_SAR18 (volatile u32 *)IOP3XX_REG_ADDR(0x0868)
++#define IOP3XX_AAU_SAR19 (volatile u32 *)IOP3XX_REG_ADDR(0x086c)
++#define IOP3XX_AAU_SAR20 (volatile u32 *)IOP3XX_REG_ADDR(0x0870)
++#define IOP3XX_AAU_SAR21 (volatile u32 *)IOP3XX_REG_ADDR(0x0874)
++#define IOP3XX_AAU_SAR22 (volatile u32 *)IOP3XX_REG_ADDR(0x0878)
++#define IOP3XX_AAU_SAR23 (volatile u32 *)IOP3XX_REG_ADDR(0x087c)
++#define IOP3XX_AAU_SAR24 (volatile u32 *)IOP3XX_REG_ADDR(0x0880)
++#define IOP3XX_AAU_EDCR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0884)
++#define IOP3XX_AAU_SAR25 (volatile u32 *)IOP3XX_REG_ADDR(0x0888)
++#define IOP3XX_AAU_SAR26 (volatile u32 *)IOP3XX_REG_ADDR(0x088c)
++#define IOP3XX_AAU_SAR27 (volatile u32 *)IOP3XX_REG_ADDR(0x0890)
++#define IOP3XX_AAU_SAR28 (volatile u32 *)IOP3XX_REG_ADDR(0x0894)
++#define IOP3XX_AAU_SAR29 (volatile u32 *)IOP3XX_REG_ADDR(0x0898)
++#define IOP3XX_AAU_SAR30 (volatile u32 *)IOP3XX_REG_ADDR(0x089c)
++#define IOP3XX_AAU_SAR31 (volatile u32 *)IOP3XX_REG_ADDR(0x08a0)
++#define IOP3XX_AAU_SAR32 (volatile u32 *)IOP3XX_REG_ADDR(0x08a4)
++
++/* I2C bus interface unit */
++#define IOP3XX_ICR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1680)
++#define IOP3XX_ISR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1684)
++#define IOP3XX_ISAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1688)
++#define IOP3XX_IDBR0 (volatile u32 *)IOP3XX_REG_ADDR(0x168c)
++#define IOP3XX_IBMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1694)
++#define IOP3XX_ICR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16a0)
++#define IOP3XX_ISR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16a4)
++#define IOP3XX_ISAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16a8)
++#define IOP3XX_IDBR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16ac)
++#define IOP3XX_IBMR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16b4)
++
++
++/*
++ * IOP3XX I/O and Mem space regions for PCI autoconfiguration
++ */
++#define IOP3XX_PCI_MEM_WINDOW_SIZE 0x04000000
++#define IOP3XX_PCI_LOWER_MEM_PA 0x80000000
++#define IOP3XX_PCI_LOWER_MEM_BA (*IOP3XX_OMWTVR0)
++
++#define IOP3XX_PCI_IO_WINDOW_SIZE 0x00010000
++#define IOP3XX_PCI_LOWER_IO_PA 0x90000000
++#define IOP3XX_PCI_LOWER_IO_VA 0xfe000000
++#define IOP3XX_PCI_LOWER_IO_BA (*IOP3XX_OIOWTVR)
++
++
++#ifndef __ASSEMBLY__
++void iop3xx_map_io(void);
++void iop3xx_init_time(unsigned long);
++unsigned long iop3xx_gettimeoffset(void);
++
++extern struct platform_device iop3xx_i2c0_device;
++extern struct platform_device iop3xx_i2c1_device;
++
++extern inline void iop3xx_cp6_enable(void)
++{
++ u32 temp;
++
++ asm volatile (
++ "mrc p15, 0, %0, c15, c1, 0\n\t"
++ "orr %0, %0, #(1 << 6)\n\t"
++ "mcr p15, 0, %0, c15, c1, 0\n\t"
++ "mrc p15, 0, %0, c15, c1, 0\n\t"
++ "mov %0, %0\n\t"
++ "sub pc, pc, #4\n\t"
++ : "=r" (temp) );
++}
++
++extern inline void iop3xx_cp6_disable(void)
++{
++ u32 temp;
++
++ asm volatile (
++ "mrc p15, 0, %0, c15, c1, 0\n\t"
++ "bic %0, %0, #(1 << 6)\n\t"
++ "mcr p15, 0, %0, c15, c1, 0\n\t"
++ "mrc p15, 0, %0, c15, c1, 0\n\t"
++ "mov %0, %0\n\t"
++ "sub pc, pc, #4\n\t"
++ : "=r" (temp) );
++}
++#endif
++
++
++#endif
+diff --git a/include/asm-arm/hardware/locomo.h b/include/asm-arm/hardware/locomo.h
+index 22dfb17..adab777 100644
+--- a/include/asm-arm/hardware/locomo.h
++++ b/include/asm-arm/hardware/locomo.h
+@@ -54,17 +54,18 @@
+ #define LOCOMO_DAC_SDAOEB 0x01 /* SDA pin output data */
+
+ /* SPI interface */
+-#define LOCOMO_SPIMD 0x60 /* SPI mode setting */
+-#define LOCOMO_SPICT 0x64 /* SPI mode control */
+-#define LOCOMO_SPIST 0x68 /* SPI status */
+-#define LOCOMO_SPIIS 0x70 /* SPI interrupt status */
+-#define LOCOMO_SPIWE 0x74 /* SPI interrupt status write enable */
+-#define LOCOMO_SPIIE 0x78 /* SPI interrupt enable */
+-#define LOCOMO_SPIIR 0x7c /* SPI interrupt request */
+-#define LOCOMO_SPITD 0x80 /* SPI transfer data write */
+-#define LOCOMO_SPIRD 0x84 /* SPI receive data read */
+-#define LOCOMO_SPITS 0x88 /* SPI transfer data shift */
+-#define LOCOMO_SPIRS 0x8C /* SPI receive data shift */
++#define LOCOMO_SPI 0x60
++#define LOCOMO_SPIMD 0x00 /* SPI mode setting */
++#define LOCOMO_SPICT 0x04 /* SPI mode control */
++#define LOCOMO_SPIST 0x08 /* SPI status */
++#define LOCOMO_SPIIS 0x10 /* SPI interrupt status */
++#define LOCOMO_SPIWE 0x14 /* SPI interrupt status write enable */
++#define LOCOMO_SPIIE 0x18 /* SPI interrupt enable */
++#define LOCOMO_SPIIR 0x1c /* SPI interrupt request */
++#define LOCOMO_SPITD 0x20 /* SPI transfer data write */
++#define LOCOMO_SPIRD 0x24 /* SPI receive data read */
++#define LOCOMO_SPITS 0x28 /* SPI transfer data shift */
++#define LOCOMO_SPIRS 0x2C /* SPI receive data shift */
+ #define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */
+ #define LOCOMO_SPI_OVRN (1 << 2) /* Over Run bit */
+ #define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */
+@@ -161,6 +162,7 @@ extern struct bus_type locomo_bus_type;
+ #define LOCOMO_DEVID_AUDIO 3
+ #define LOCOMO_DEVID_LED 4
+ #define LOCOMO_DEVID_UART 5
++#define LOCOMO_DEVID_SPI 6
+
+ struct locomo_dev {
+ struct device dev;
+@@ -197,10 +199,11 @@ int locomo_driver_register(struct locomo
+ void locomo_driver_unregister(struct locomo_driver *);
+
+ /* GPIO control functions */
+-void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir);
+-unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits);
+-unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits);
+-void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set);
++void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir);
++int locomo_gpio_read_level(struct device *dev, unsigned int bits);
++int locomo_gpio_read_output(struct device *dev, unsigned int bits);
++void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set);
++
+
+ /* M62332 control function */
+ void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel);
+diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
+index 319aea0..6aa0a5b 100644
+--- a/include/asm-arm/hardware/sa1111.h
++++ b/include/asm-arm/hardware/sa1111.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/hardware/SA-1111.h
++ * linux/include/asm-arm/hardware/sa1111.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+ at cs.cmu.edu>
+ *
+diff --git a/include/asm-arm/hardware/sharpsl_pm.h b/include/asm-arm/hardware/sharpsl_pm.h
+index ecf15b8..2d00db2 100644
+--- a/include/asm-arm/hardware/sharpsl_pm.h
++++ b/include/asm-arm/hardware/sharpsl_pm.h
+@@ -25,6 +25,7 @@ struct sharpsl_charger_machinfo {
+ void (*measure_temp)(int);
+ void (*presuspend)(void);
+ void (*postsuspend)(void);
++ void (*earlyresume)(void);
+ unsigned long (*read_devdata)(int);
+ #define SHARPSL_BATT_VOLT 1
+ #define SHARPSL_BATT_TEMP 2
+@@ -99,7 +100,7 @@ extern struct sharpsl_pm_status sharpsl_
+
+ void sharpsl_battery_kick(void);
+ void sharpsl_pm_led(int val);
+-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp);
+-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp);
+-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp);
++irqreturn_t sharpsl_ac_isr(int irq, void *dev_id);
++irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id);
++irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id);
+
+diff --git a/include/asm-arm/hw_irq.h b/include/asm-arm/hw_irq.h
+index ea85697..98d594a 100644
+--- a/include/asm-arm/hw_irq.h
++++ b/include/asm-arm/hw_irq.h
+@@ -12,7 +12,7 @@
+ if (!(action->flags & IRQF_TIMER) && system_timer->dyn_tick) { \
+ write_seqlock(&xtime_lock); \
+ if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) \
+- system_timer->dyn_tick->handler(irq, 0, regs); \
++ system_timer->dyn_tick->handler(irq, NULL); \
+ write_sequnlock(&xtime_lock); \
+ }
+ #endif
+diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
+index bf7b9de..ae999fd 100644
+--- a/include/asm-arm/io.h
++++ b/include/asm-arm/io.h
+@@ -63,7 +63,7 @@ extern void __raw_readsl(const void __io
+ */
+ extern void __iomem * __ioremap_pfn(unsigned long, unsigned long, size_t, unsigned long);
+ extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
+-extern void __iounmap(void __iomem *addr);
++extern void __iounmap(volatile void __iomem *addr);
+
+ /*
+ * Bad read/write accesses...
+@@ -193,23 +193,6 @@ extern void _memset_io(volatile void __i
+ #define eth_io_copy_and_sum(s,c,l,b) \
+ eth_copy_and_sum((s),__mem_pci(c),(l),(b))
+
+-static inline int
+-check_signature(void __iomem *io_addr, const unsigned char *signature,
+- int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ #elif !defined(readb)
+
+ #define readb(c) (__readwrite_bug("readb"),0)
+@@ -280,6 +263,10 @@ extern void pci_iounmap(struct pci_dev *
+ #define BIOVEC_MERGEABLE(vec1, vec2) \
+ ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2)))
+
++#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
++extern int valid_phys_addr_range(unsigned long addr, size_t size);
++extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
++
+ /*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+diff --git a/include/asm-arm/irq_regs.h b/include/asm-arm/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-arm/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-arm/irqflags.h b/include/asm-arm/irqflags.h
+new file mode 100644
+index 0000000..6d09974
+--- /dev/null
++++ b/include/asm-arm/irqflags.h
+@@ -0,0 +1,132 @@
++#ifndef __ASM_ARM_IRQFLAGS_H
++#define __ASM_ARM_IRQFLAGS_H
++
++#ifdef __KERNEL__
++
++#include <asm/ptrace.h>
++
++/*
++ * CPU interrupt mask handling.
++ */
++#if __LINUX_ARM_ARCH__ >= 6
++
++#define raw_local_irq_save(x) \
++ ({ \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ local_irq_save\n" \
++ "cpsid i" \
++ : "=r" (x) : : "memory", "cc"); \
++ })
++
++#define raw_local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc")
++#define raw_local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc")
++#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc")
++#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc")
++
++#else
++
++/*
++ * Save the current interrupt enable state & disable IRQs
++ */
++#define raw_local_irq_save(x) \
++ ({ \
++ unsigned long temp; \
++ (void) (&temp == &x); \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ local_irq_save\n" \
++" orr %1, %0, #128\n" \
++" msr cpsr_c, %1" \
++ : "=r" (x), "=r" (temp) \
++ : \
++ : "memory", "cc"); \
++ })
++
++/*
++ * Enable IRQs
++ */
++#define raw_local_irq_enable() \
++ ({ \
++ unsigned long temp; \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ local_irq_enable\n" \
++" bic %0, %0, #128\n" \
++" msr cpsr_c, %0" \
++ : "=r" (temp) \
++ : \
++ : "memory", "cc"); \
++ })
++
++/*
++ * Disable IRQs
++ */
++#define raw_local_irq_disable() \
++ ({ \
++ unsigned long temp; \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ local_irq_disable\n" \
++" orr %0, %0, #128\n" \
++" msr cpsr_c, %0" \
++ : "=r" (temp) \
++ : \
++ : "memory", "cc"); \
++ })
++
++/*
++ * Enable FIQs
++ */
++#define local_fiq_enable() \
++ ({ \
++ unsigned long temp; \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ stf\n" \
++" bic %0, %0, #64\n" \
++" msr cpsr_c, %0" \
++ : "=r" (temp) \
++ : \
++ : "memory", "cc"); \
++ })
++
++/*
++ * Disable FIQs
++ */
++#define local_fiq_disable() \
++ ({ \
++ unsigned long temp; \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ clf\n" \
++" orr %0, %0, #64\n" \
++" msr cpsr_c, %0" \
++ : "=r" (temp) \
++ : \
++ : "memory", "cc"); \
++ })
++
++#endif
++
++/*
++ * Save the current interrupt enable state.
++ */
++#define raw_local_save_flags(x) \
++ ({ \
++ __asm__ __volatile__( \
++ "mrs %0, cpsr @ local_save_flags" \
++ : "=r" (x) : : "memory", "cc"); \
++ })
++
++/*
++ * restore saved IRQ & FIQ state
++ */
++#define raw_local_irq_restore(x) \
++ __asm__ __volatile__( \
++ "msr cpsr_c, %0 @ local_irq_restore\n" \
++ : \
++ : "r" (x) \
++ : "memory", "cc")
++
++#define raw_irqs_disabled_flags(flags) \
++({ \
++ (int)((flags) & PSR_I_BIT); \
++})
++
++#endif
++#endif
+diff --git a/include/asm-arm/mach/irq.h b/include/asm-arm/mach/irq.h
+index 131f337..0e017ec 100644
+--- a/include/asm-arm/mach/irq.h
++++ b/include/asm-arm/mach/irq.h
+@@ -30,10 +30,9 @@ extern int show_fiq_list(struct seq_file
+ /*
+ * Obsolete inline function for calling irq descriptor handlers.
+ */
+-static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
+ {
+- desc->handle_irq(irq, desc, regs);
++ desc->handle_irq(irq, desc);
+ }
+
+ void set_irq_flags(unsigned int irq, unsigned int flags);
+@@ -51,10 +50,10 @@ void set_irq_flags(unsigned int irq, uns
+ #define irqdesc irq_desc
+ #define irqchip irq_chip
+
+-#define do_bad_IRQ(irq,desc,regs) \
++#define do_bad_IRQ(irq,desc) \
+ do { \
+ spin_lock(&desc->lock); \
+- handle_bad_irq(irq, desc, regs); \
++ handle_bad_irq(irq, desc); \
+ spin_unlock(&desc->lock); \
+ } while(0)
+
+diff --git a/include/asm-arm/mach/pci.h b/include/asm-arm/mach/pci.h
+index 923e0ca..24621c4 100644
+--- a/include/asm-arm/mach/pci.h
++++ b/include/asm-arm/mach/pci.h
+@@ -52,13 +52,9 @@ void pci_common_init(struct hw_pci *);
+ /*
+ * PCI controllers
+ */
+-extern int iop321_setup(int nr, struct pci_sys_data *);
+-extern struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *);
+-extern void iop321_init(void);
+-
+-extern int iop331_setup(int nr, struct pci_sys_data *);
+-extern struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *);
+-extern void iop331_init(void);
++extern int iop3xx_pci_setup(int nr, struct pci_sys_data *);
++extern struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *);
++extern void iop3xx_pci_preinit(void);
+
+ extern int dc21285_setup(int nr, struct pci_sys_data *);
+ extern struct pci_bus *dc21285_scan_bus(int nr, struct pci_sys_data *);
+diff --git a/include/asm-arm/mach/serial_at91.h b/include/asm-arm/mach/serial_at91.h
+index 1290bb3..55b317a 100644
+--- a/include/asm-arm/mach/serial_at91.h
++++ b/include/asm-arm/mach/serial_at91.h
+@@ -14,7 +14,7 @@ struct uart_port;
+ * This is a temporary structure for registering these
+ * functions; it is intended to be discarded after boot.
+ */
+-struct at91_port_fns {
++struct atmel_port_fns {
+ void (*set_mctrl)(struct uart_port *, u_int);
+ u_int (*get_mctrl)(struct uart_port *);
+ void (*enable_ms)(struct uart_port *);
+@@ -24,10 +24,10 @@ struct at91_port_fns {
+ void (*close)(struct uart_port *);
+ };
+
+-#if defined(CONFIG_SERIAL_AT91)
+-void at91_register_uart_fns(struct at91_port_fns *fns);
++#if defined(CONFIG_SERIAL_ATMEL)
++void atmel_register_uart_fns(struct atmel_port_fns *fns);
+ #else
+-#define at91_register_uart_fns(fns) do { } while (0)
++#define atmel_register_uart_fns(fns) do { } while (0)
+ #endif
+
+
+diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h
+index dee0bc3..5dc3570 100644
+--- a/include/asm-arm/mach/time.h
++++ b/include/asm-arm/mach/time.h
+@@ -38,7 +38,9 @@ struct sys_timer {
+ void (*init)(void);
+ void (*suspend)(void);
+ void (*resume)(void);
++#ifndef CONFIG_GENERIC_TIME
+ unsigned long (*offset)(void);
++#endif
+
+ #ifdef CONFIG_NO_IDLE_HZ
+ struct dyn_tick_timer *dyn_tick;
+@@ -55,7 +57,7 @@ struct dyn_tick_timer {
+ 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 *);
++ int (*handler)(int, void *);
+ };
+
+ void timer_dyn_reprogram(void);
+@@ -64,7 +66,7 @@ void timer_dyn_reprogram(void);
+ #endif
+
+ extern struct sys_timer *system_timer;
+-extern void timer_tick(struct pt_regs *);
++extern void timer_tick(void);
+
+ /*
+ * Kernel time keeping support.
+diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h
+index b721270..7e85db7 100644
+--- a/include/asm-arm/page.h
++++ b/include/asm-arm/page.h
+@@ -11,13 +11,13 @@
+ #define _ASMARM_PAGE_H
+
+
++#ifdef __KERNEL__
++
+ /* PAGE_SHIFT determines the page size */
+ #define PAGE_SHIFT 12
+ #define PAGE_SIZE (1UL << PAGE_SHIFT)
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+
+-#ifdef __KERNEL__
+-
+ /* to align the pointer to the (next) page boundary */
+ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+@@ -174,9 +174,6 @@ typedef unsigned long pgprot_t;
+
+ #endif /* STRICT_MM_TYPECHECKS */
+
+-/* the upper-most page table pointer */
+-extern pmd_t *top_pmd;
+-
+ #endif /* CONFIG_MMU */
+
+ #include <asm/memory.h>
+diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
+index b13322d..c1b264d 100644
+--- a/include/asm-arm/pgtable-nommu.h
++++ b/include/asm-arm/pgtable-nommu.h
+@@ -13,7 +13,6 @@
+
+ #ifndef __ASSEMBLY__
+
+-#include <linux/config.h>
+ #include <linux/slab.h>
+ #include <asm/processor.h>
+ #include <asm/page.h>
+diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
+index 8d3919c..ed8cb59 100644
+--- a/include/asm-arm/pgtable.h
++++ b/include/asm-arm/pgtable.h
+@@ -136,6 +136,13 @@ extern void __pgd_error(const char *file
+ #define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
+
+ /*
++ * section address mask and size definitions.
++ */
++#define SECTION_SHIFT 20
++#define SECTION_SIZE (1UL << SECTION_SHIFT)
++#define SECTION_MASK (~(SECTION_SIZE-1))
++
++/*
+ * ARMv6 supersection address mask and size definitions.
+ */
+ #define SUPERSECTION_SHIFT 24
+@@ -224,9 +231,9 @@ extern struct page *empty_zero_page;
+ #define pte_none(pte) (!pte_val(pte))
+ #define pte_clear(mm,addr,ptep) set_pte_at((mm),(addr),(ptep), __pte(0))
+ #define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
+-#define pte_offset_kernel(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr))
+-#define pte_offset_map(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr))
+-#define pte_offset_map_nested(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr))
++#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
++#define pte_offset_map(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
++#define pte_offset_map_nested(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+ #define pte_unmap(pte) do { } while (0)
+ #define pte_unmap_nested(pte) do { } while (0)
+
+@@ -291,7 +298,7 @@ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG);
+ clean_pmd_entry(pmdp); \
+ } while (0)
+
+-static inline pte_t *pmd_page_kernel(pmd_t pmd)
++static inline pte_t *pmd_page_vaddr(pmd_t pmd)
+ {
+ unsigned long ptr;
+
+diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h
+index 1bde92c..ea7e54c 100644
+--- a/include/asm-arm/proc-fns.h
++++ b/include/asm-arm/proc-fns.h
+@@ -33,6 +33,14 @@
+ # define CPU_NAME cpu_arm6
+ # endif
+ # endif
++# ifdef CONFIG_CPU_ARM7TDMI
++# ifdef CPU_NAME
++# undef MULTI_CPU
++# define MULTI_CPU
++# else
++# define CPU_NAME cpu_arm7tdmi
++# endif
++# endif
+ # ifdef CONFIG_CPU_ARM710
+ # ifdef CPU_NAME
+ # undef MULTI_CPU
+@@ -49,6 +57,22 @@
+ # define CPU_NAME cpu_arm720
+ # endif
+ # endif
++# ifdef CONFIG_CPU_ARM740T
++# ifdef CPU_NAME
++# undef MULTI_CPU
++# define MULTI_CPU
++# else
++# define CPU_NAME cpu_arm740
++# endif
++# endif
++# ifdef CONFIG_CPU_ARM9TDMI
++# ifdef CPU_NAME
++# undef MULTI_CPU
++# define MULTI_CPU
++# else
++# define CPU_NAME cpu_arm9tdmi
++# endif
++# endif
+ # ifdef CONFIG_CPU_ARM920T
+ # ifdef CPU_NAME
+ # undef MULTI_CPU
+@@ -81,6 +105,22 @@
+ # define CPU_NAME cpu_arm926
+ # endif
+ # endif
++# ifdef CONFIG_CPU_ARM940T
++# ifdef CPU_NAME
++# undef MULTI_CPU
++# define MULTI_CPU
++# else
++# define CPU_NAME cpu_arm940
++# endif
++# endif
++# ifdef CONFIG_CPU_ARM946E
++# ifdef CPU_NAME
++# undef MULTI_CPU
++# define MULTI_CPU
++# else
++# define CPU_NAME cpu_arm946
++# endif
++# endif
+ # ifdef CONFIG_CPU_SA110
+ # ifdef CPU_NAME
+ # undef MULTI_CPU
+diff --git a/include/asm-arm/setup.h b/include/asm-arm/setup.h
+index ea3ed24..aa4b578 100644
+--- a/include/asm-arm/setup.h
++++ b/include/asm-arm/setup.h
+@@ -194,13 +194,15 @@ static struct tagtable __tagtable_##fn _
+ # define NR_BANKS 8
+ #endif
+
++struct membank {
++ unsigned long start;
++ unsigned long size;
++ int node;
++};
++
+ struct meminfo {
+ int nr_banks;
+- struct {
+- unsigned long start;
+- unsigned long size;
+- int node;
+- } bank[NR_BANKS];
++ struct membank bank[NR_BANKS];
+ };
+
+ /*
+diff --git a/include/asm-arm/spinlock.h b/include/asm-arm/spinlock.h
+index 01b7c26..861092f 100644
+--- a/include/asm-arm/spinlock.h
++++ b/include/asm-arm/spinlock.h
+@@ -218,4 +218,8 @@ static inline int __raw_read_trylock(raw
+ /* read_can_lock - would read_trylock() succeed? */
+ #define __raw_read_can_lock(x) ((x)->lock < 0x80000000)
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
+index 0947cbf..f05fbe3 100644
+--- a/include/asm-arm/system.h
++++ b/include/asm-arm/system.h
+@@ -46,6 +46,7 @@
+ #define CPUID_TCM 2
+ #define CPUID_TLBTYPE 3
+
++#ifdef CONFIG_CPU_CP15
+ #define read_cpuid(reg) \
+ ({ \
+ unsigned int __val; \
+@@ -55,6 +56,9 @@
+ : "cc"); \
+ __val; \
+ })
++#else
++#define read_cpuid(reg) (processor_id)
++#endif
+
+ /*
+ * This is used to ensure the compiler did actually allocate the register we
+@@ -207,130 +211,7 @@ static inline void sched_cacheflush(void
+ {
+ }
+
+-/*
+- * CPU interrupt mask handling.
+- */
+-#if __LINUX_ARM_ARCH__ >= 6
+-
+-#define local_irq_save(x) \
+- ({ \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ local_irq_save\n" \
+- "cpsid i" \
+- : "=r" (x) : : "memory", "cc"); \
+- })
+-
+-#define local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc")
+-#define local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc")
+-#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc")
+-#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc")
+-
+-#else
+-
+-/*
+- * Save the current interrupt enable state & disable IRQs
+- */
+-#define local_irq_save(x) \
+- ({ \
+- unsigned long temp; \
+- (void) (&temp == &x); \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ local_irq_save\n" \
+-" orr %1, %0, #128\n" \
+-" msr cpsr_c, %1" \
+- : "=r" (x), "=r" (temp) \
+- : \
+- : "memory", "cc"); \
+- })
+-
+-/*
+- * Enable IRQs
+- */
+-#define local_irq_enable() \
+- ({ \
+- unsigned long temp; \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ local_irq_enable\n" \
+-" bic %0, %0, #128\n" \
+-" msr cpsr_c, %0" \
+- : "=r" (temp) \
+- : \
+- : "memory", "cc"); \
+- })
+-
+-/*
+- * Disable IRQs
+- */
+-#define local_irq_disable() \
+- ({ \
+- unsigned long temp; \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ local_irq_disable\n" \
+-" orr %0, %0, #128\n" \
+-" msr cpsr_c, %0" \
+- : "=r" (temp) \
+- : \
+- : "memory", "cc"); \
+- })
+-
+-/*
+- * Enable FIQs
+- */
+-#define local_fiq_enable() \
+- ({ \
+- unsigned long temp; \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ stf\n" \
+-" bic %0, %0, #64\n" \
+-" msr cpsr_c, %0" \
+- : "=r" (temp) \
+- : \
+- : "memory", "cc"); \
+- })
+-
+-/*
+- * Disable FIQs
+- */
+-#define local_fiq_disable() \
+- ({ \
+- unsigned long temp; \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ clf\n" \
+-" orr %0, %0, #64\n" \
+-" msr cpsr_c, %0" \
+- : "=r" (temp) \
+- : \
+- : "memory", "cc"); \
+- })
+-
+-#endif
+-
+-/*
+- * Save the current interrupt enable state.
+- */
+-#define local_save_flags(x) \
+- ({ \
+- __asm__ __volatile__( \
+- "mrs %0, cpsr @ local_save_flags" \
+- : "=r" (x) : : "memory", "cc"); \
+- })
+-
+-/*
+- * restore saved IRQ & FIQ state
+- */
+-#define local_irq_restore(x) \
+- __asm__ __volatile__( \
+- "msr cpsr_c, %0 @ local_irq_restore\n" \
+- : \
+- : "r" (x) \
+- : "memory", "cc")
+-
+-#define irqs_disabled() \
+-({ \
+- unsigned long flags; \
+- local_save_flags(flags); \
+- (int)(flags & PSR_I_BIT); \
+-})
++#include <linux/irqflags.h>
+
+ #ifdef CONFIG_SMP
+
+@@ -405,17 +286,17 @@ static inline unsigned long __xchg(unsig
+ #error SMP is not supported on this platform
+ #endif
+ case 1:
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ ret = *(volatile unsigned char *)ptr;
+ *(volatile unsigned char *)ptr = x;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+ break;
+
+ case 4:
+- local_irq_save(flags);
++ raw_local_irq_save(flags);
+ ret = *(volatile unsigned long *)ptr;
+ *(volatile unsigned long *)ptr = x;
+- local_irq_restore(flags);
++ raw_local_irq_restore(flags);
+ break;
+ #else
+ case 1:
+diff --git a/include/asm-arm/tlbflush.h b/include/asm-arm/tlbflush.h
+index d97fc76..cd10a0b 100644
+--- a/include/asm-arm/tlbflush.h
++++ b/include/asm-arm/tlbflush.h
+@@ -247,16 +247,16 @@ static inline void local_flush_tlb_all(v
+ const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+ if (tlb_flag(TLB_WB))
+- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
++ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+
+ if (tlb_flag(TLB_V3_FULL))
+- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL))
+- asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL))
+- asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
+- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+ }
+
+ static inline void local_flush_tlb_mm(struct mm_struct *mm)
+@@ -266,25 +266,25 @@ static inline void local_flush_tlb_mm(st
+ const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+ if (tlb_flag(TLB_WB))
+- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
++ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+
+ if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) {
+ if (tlb_flag(TLB_V3_FULL))
+- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V4_U_FULL))
+- asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V4_D_FULL))
+- asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V4_I_FULL))
+- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+ }
+
+ if (tlb_flag(TLB_V6_U_ASID))
+- asm("mcr%? p15, 0, %0, c8, c7, 2" : : "r" (asid));
++ asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
+ if (tlb_flag(TLB_V6_D_ASID))
+- asm("mcr%? p15, 0, %0, c8, c6, 2" : : "r" (asid));
++ asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
+ if (tlb_flag(TLB_V6_I_ASID))
+- asm("mcr%? p15, 0, %0, c8, c5, 2" : : "r" (asid));
++ asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
+ }
+
+ static inline void
+@@ -296,27 +296,27 @@ local_flush_tlb_page(struct vm_area_stru
+ uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
+
+ if (tlb_flag(TLB_WB))
+- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
++ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero));
+
+ if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+ if (tlb_flag(TLB_V3_PAGE))
+- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
+ if (tlb_flag(TLB_V4_U_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
+ if (tlb_flag(TLB_V4_D_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
+ if (tlb_flag(TLB_V4_I_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
+ if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
+- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+ }
+
+ if (tlb_flag(TLB_V6_U_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
+ if (tlb_flag(TLB_V6_D_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
+ if (tlb_flag(TLB_V6_I_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
++ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
+ }
+
+ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
+@@ -327,31 +327,31 @@ static inline void local_flush_tlb_kerne
+ kaddr &= PAGE_MASK;
+
+ if (tlb_flag(TLB_WB))
+- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
++ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+
+ if (tlb_flag(TLB_V3_PAGE))
+- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
+ if (tlb_flag(TLB_V4_U_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
+ if (tlb_flag(TLB_V4_D_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
+ if (tlb_flag(TLB_V4_I_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
+ if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
+- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
++ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+
+ if (tlb_flag(TLB_V6_U_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
+ if (tlb_flag(TLB_V6_D_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
+ if (tlb_flag(TLB_V6_I_PAGE))
+- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr));
++ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
+
+ /* The ARM ARM states that the completion of a TLB maintenance
+ * operation is only guaranteed by a DSB instruction
+ */
+ if (tlb_flag(TLB_V6_U_PAGE | TLB_V6_D_PAGE | TLB_V6_I_PAGE))
+- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
++ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+ }
+
+ /*
+@@ -373,11 +373,11 @@ static inline void flush_pmd_entry(pmd_t
+ const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+ if (tlb_flag(TLB_DCLEAN))
+- asm("mcr%? p15, 0, %0, c7, c10, 1 @ flush_pmd"
+- : : "r" (pmd));
++ asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
++ : : "r" (pmd) : "cc");
+ if (tlb_flag(TLB_WB))
+- asm("mcr%? p15, 0, %0, c7, c10, 4 @ flush_pmd"
+- : : "r" (zero));
++ asm("mcr p15, 0, %0, c7, c10, 4 @ flush_pmd"
++ : : "r" (zero) : "cc");
+ }
+
+ static inline void clean_pmd_entry(pmd_t *pmd)
+@@ -385,8 +385,8 @@ static inline void clean_pmd_entry(pmd_t
+ const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+ if (tlb_flag(TLB_DCLEAN))
+- asm("mcr%? p15, 0, %0, c7, c10, 1 @ flush_pmd"
+- : : "r" (pmd));
++ asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
++ : : "r" (pmd) : "cc");
+ }
+
+ #undef tlb_flag
+diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h
+index 87aba57..5f420a0 100644
+--- a/include/asm-arm/uaccess.h
++++ b/include/asm-arm/uaccess.h
+@@ -110,7 +110,7 @@ extern int __get_user_4(void *);
+ #define get_user(x,p) \
+ ({ \
+ const register typeof(*(p)) __user *__p asm("r0") = (p);\
+- register unsigned int __r2 asm("r2"); \
++ register unsigned long __r2 asm("r2"); \
+ register int __e asm("r0"); \
+ switch (sizeof(*(__p))) { \
+ case 1: \
+@@ -383,19 +383,19 @@ do { \
+
+
+ #ifdef CONFIG_MMU
+-extern unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n);
+-extern unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n);
+-extern unsigned long __clear_user(void __user *addr, unsigned long n);
++extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n);
++extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
++extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
+ #else
+ #define __copy_from_user(to,from,n) (memcpy(to, (void __force *)from, n), 0)
+ #define __copy_to_user(to,from,n) (memcpy((void __force *)to, from, n), 0)
+ #define __clear_user(addr,n) (memset((void __force *)addr, 0, n), 0)
+ #endif
+
+-extern unsigned long __strncpy_from_user(char *to, const char __user *from, unsigned long count);
+-extern unsigned long __strnlen_user(const char __user *s, long n);
++extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count);
++extern unsigned long __must_check __strnlen_user(const char __user *s, long n);
+
+-static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
++static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
+ if (access_ok(VERIFY_READ, from, n))
+ n = __copy_from_user(to, from, n);
+@@ -404,7 +404,7 @@ static inline unsigned long copy_from_us
+ return n;
+ }
+
+-static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
++static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
+ {
+ if (access_ok(VERIFY_WRITE, to, n))
+ n = __copy_to_user(to, from, n);
+@@ -414,14 +414,14 @@ static inline unsigned long copy_to_user
+ #define __copy_to_user_inatomic __copy_to_user
+ #define __copy_from_user_inatomic __copy_from_user
+
+-static inline unsigned long clear_user(void __user *to, unsigned long n)
++static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
+ {
+ if (access_ok(VERIFY_WRITE, to, n))
+ n = __clear_user(to, n);
+ return n;
+ }
+
+-static inline long strncpy_from_user(char *dst, const char __user *src, long count)
++static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count)
+ {
+ long res = -EFAULT;
+ if (access_ok(VERIFY_READ, src, 1))
+@@ -431,7 +431,7 @@ static inline long strncpy_from_user(cha
+
+ #define strlen_user(s) strnlen_user(s, ~0UL >> 1)
+
+-static inline long strnlen_user(const char __user *s, long n)
++static inline long __must_check strnlen_user(const char __user *s, long n)
+ {
+ unsigned long res = 0;
+
+diff --git a/include/asm-arm/unaligned.h b/include/asm-arm/unaligned.h
+index 1b39c2f..795b9e5 100644
+--- a/include/asm-arm/unaligned.h
++++ b/include/asm-arm/unaligned.h
+@@ -3,7 +3,7 @@
+
+ #include <asm/types.h>
+
+-extern int __bug_unaligned_x(void *ptr);
++extern int __bug_unaligned_x(const void *ptr);
+
+ /*
+ * What is the most efficient way of loading/storing an unaligned value?
+@@ -51,44 +51,32 @@ extern int __bug_unaligned_x(void *ptr);
+ #define __get_unaligned_4_be(__p) \
+ (__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3])
+
+-#define __get_unaligned_le(ptr) \
+- ({ \
+- __typeof__(*(ptr)) __v; \
+- __u8 *__p = (__u8 *)(ptr); \
+- switch (sizeof(*(ptr))) { \
+- case 1: __v = *(ptr); break; \
+- case 2: __v = __get_unaligned_2_le(__p); break; \
+- case 4: __v = __get_unaligned_4_le(__p); break; \
+- case 8: { \
+- unsigned int __v1, __v2; \
+- __v2 = __get_unaligned_4_le((__p+4)); \
+- __v1 = __get_unaligned_4_le(__p); \
+- __v = ((unsigned long long)__v2 << 32 | __v1); \
+- } \
+- break; \
+- default: __v = __bug_unaligned_x(__p); break; \
+- } \
+- __v; \
++#define __get_unaligned_8_le(__p) \
++ ((unsigned long long)__get_unaligned_4_le((__p+4)) << 32 | \
++ __get_unaligned_4_le(__p))
++
++#define __get_unaligned_8_be(__p) \
++ ((unsigned long long)__get_unaligned_4_be(__p) << 32 | \
++ __get_unaligned_4_be((__p+4)))
++
++#define __get_unaligned_le(ptr) \
++ ({ \
++ const __u8 *__p = (const __u8 *)(ptr); \
++ __builtin_choose_expr(sizeof(*(ptr)) == 1, *__p, \
++ __builtin_choose_expr(sizeof(*(ptr)) == 2, __get_unaligned_2_le(__p), \
++ __builtin_choose_expr(sizeof(*(ptr)) == 4, __get_unaligned_4_le(__p), \
++ __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_le(__p), \
++ (void)__bug_unaligned_x(__p))))); \
+ })
+
+-#define __get_unaligned_be(ptr) \
+- ({ \
+- __typeof__(*(ptr)) __v; \
+- __u8 *__p = (__u8 *)(ptr); \
+- switch (sizeof(*(ptr))) { \
+- case 1: __v = *(ptr); break; \
+- case 2: __v = __get_unaligned_2_be(__p); break; \
+- case 4: __v = __get_unaligned_4_be(__p); break; \
+- case 8: { \
+- unsigned int __v1, __v2; \
+- __v2 = __get_unaligned_4_be(__p); \
+- __v1 = __get_unaligned_4_be((__p+4)); \
+- __v = ((unsigned long long)__v2 << 32 | __v1); \
+- } \
+- break; \
+- default: __v = __bug_unaligned_x(__p); break; \
+- } \
+- __v; \
++#define __get_unaligned_be(ptr) \
++ ({ \
++ const __u8 *__p = (const __u8 *)(ptr); \
++ __builtin_choose_expr(sizeof(*(ptr)) == 1, *__p, \
++ __builtin_choose_expr(sizeof(*(ptr)) == 2, __get_unaligned_2_be(__p), \
++ __builtin_choose_expr(sizeof(*(ptr)) == 4, __get_unaligned_4_be(__p), \
++ __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_be(__p), \
++ (void)__bug_unaligned_x(__p))))); \
+ })
+
+
+diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
+index 1e891f8..14a87ee 100644
+--- a/include/asm-arm/unistd.h
++++ b/include/asm-arm/unistd.h
+@@ -377,6 +377,7 @@
+ #endif
+
+ #ifdef __KERNEL__
++#include <linux/err.h>
+ #include <linux/linkage.h>
+
+ #define __sys2(x) #x
+@@ -396,7 +397,7 @@
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-129)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ errno = -(res); \
+ res = -1; \
+ } \
+@@ -548,30 +549,6 @@ type name(type1 arg1, type2 arg2, type3
+ #define __ARCH_WANT_SYS_SOCKETCALL
+ #endif
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/syscalls.h>
+-
+-extern long execve(const char *file, char **argv, char **envp);
+-
+-struct pt_regs;
+-asmlinkage int sys_execve(char *filenamei, char **argv, char **envp,
+- struct pt_regs *regs);
+-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+- struct pt_regs *regs);
+-asmlinkage int sys_fork(struct pt_regs *regs);
+-asmlinkage int sys_vfork(struct pt_regs *regs);
+-asmlinkage int sys_pipe(unsigned long *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-arm26/Kbuild b/include/asm-arm26/Kbuild
+deleted file mode 100644
+index c68e168..0000000
+--- a/include/asm-arm26/Kbuild
++++ /dev/null
+@@ -1 +0,0 @@
+-include include/asm-generic/Kbuild.asm
+diff --git a/include/asm-arm26/assembler.h b/include/asm-arm26/assembler.h
+index 83f9aec..bb507a9 100644
+--- a/include/asm-arm26/assembler.h
++++ b/include/asm-arm26/assembler.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/asm/assembler.h
++ * linux/include/asm-arm26/assembler.h
+ *
+ * This file contains arm architecture specific defines
+ * for the different processors.
+diff --git a/include/asm-arm26/namei.h b/include/asm-arm26/namei.h
+index a402d3b..3f5d340 100644
+--- a/include/asm-arm26/namei.h
++++ b/include/asm-arm26/namei.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/namei.h
++ * linux/include/asm-arm26/namei.h
+ *
+ * Routines to handle famous /usr/gnemul
+ * Derived from the Sparc version of this file
+diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
+index 19ac910..63a8881 100644
+--- a/include/asm-arm26/pgtable.h
++++ b/include/asm-arm26/pgtable.h
+@@ -186,12 +186,12 @@ extern struct page *empty_zero_page;
+ * return a pointer to memory (no special alignment)
+ */
+ #define pmd_page(pmd) ((struct page *)(pmd_val((pmd)) & ~_PMD_PRESENT))
+-#define pmd_page_kernel(pmd) ((pte_t *)(pmd_val((pmd)) & ~_PMD_PRESENT))
++#define pmd_page_vaddr(pmd) ((pte_t *)(pmd_val((pmd)) & ~_PMD_PRESENT))
+
+-#define pte_offset_kernel(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr))
++#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+
+-#define pte_offset_map(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr))
+-#define pte_offset_map_nested(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr))
++#define pte_offset_map(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
++#define pte_offset_map_nested(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+ #define pte_unmap(pte) do { } while (0)
+ #define pte_unmap_nested(pte) do { } while (0)
+
+diff --git a/include/asm-arm26/semaphore.h b/include/asm-arm26/semaphore.h
+index ccf15e7..1fda543 100644
+--- a/include/asm-arm26/semaphore.h
++++ b/include/asm-arm26/semaphore.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-arm/semaphore.h
++ * linux/include/asm-arm26/semaphore.h
+ */
+ #ifndef __ASM_ARM_SEMAPHORE_H
+ #define __ASM_ARM_SEMAPHORE_H
+diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h
+index 70eb6d9..25a5eea 100644
+--- a/include/asm-arm26/unistd.h
++++ b/include/asm-arm26/unistd.h
+@@ -311,6 +311,7 @@
+ #define __ARM_NR_usr26 (__ARM_NR_BASE+3)
+
+ #ifdef __KERNEL__
++#include <linux/err.h>
+ #include <linux/linkage.h>
+
+ #define __sys2(x) #x
+@@ -322,7 +323,7 @@
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
++ if ((unsigned long)(res) >= (unsigned long)-MAX_ERRNO) { \
+ errno = -(res); \
+ res = -1; \
+ } \
+@@ -463,30 +464,6 @@ type name(type1 arg1, type2 arg2, type3
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/syscalls.h>
+-
+-extern long execve(const char *file, char **argv, char **envp);
+-
+-struct pt_regs;
+-asmlinkage int sys_execve(char *filenamei, char **argv, char **envp,
+- struct pt_regs *regs);
+-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+- struct pt_regs *regs);
+-asmlinkage int sys_fork(struct pt_regs *regs);
+-asmlinkage int sys_vfork(struct pt_regs *regs);
+-asmlinkage int sys_pipe(unsigned long *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-avr32/Kbuild b/include/asm-avr32/Kbuild
+new file mode 100644
+index 0000000..8770e73
+--- /dev/null
++++ b/include/asm-avr32/Kbuild
+@@ -0,0 +1,3 @@
++include include/asm-generic/Kbuild.asm
++
++headers-y += cachectl.h
+diff --git a/include/asm-avr32/a.out.h b/include/asm-avr32/a.out.h
+new file mode 100644
+index 0000000..50bf6e3
+--- /dev/null
++++ b/include/asm-avr32/a.out.h
+@@ -0,0 +1,26 @@
++#ifndef __ASM_AVR32_A_OUT_H
++#define __ASM_AVR32_A_OUT_H
++
++struct exec
++{
++ unsigned long a_info; /* Use macros N_MAGIC, etc for access */
++ unsigned a_text; /* length of text, in bytes */
++ unsigned a_data; /* length of data, in bytes */
++ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
++ unsigned a_syms; /* length of symbol table data in file, in bytes */
++ unsigned a_entry; /* start address */
++ unsigned a_trsize; /* length of relocation info for text, in bytes */
++ unsigned a_drsize; /* length of relocation info for data, in bytes */
++};
++
++#define N_TRSIZE(a) ((a).a_trsize)
++#define N_DRSIZE(a) ((a).a_drsize)
++#define N_SYMSIZE(a) ((a).a_syms)
++
++#ifdef __KERNEL__
++
++#define STACK_TOP TASK_SIZE
++
++#endif
++
++#endif /* __ASM_AVR32_A_OUT_H */
+diff --git a/include/asm-avr32/addrspace.h b/include/asm-avr32/addrspace.h
+new file mode 100644
+index 0000000..3667948
+--- /dev/null
++++ b/include/asm-avr32/addrspace.h
+@@ -0,0 +1,43 @@
++/*
++ * Defitions for the address spaces of the AVR32 CPUs. Heavily based on
++ * include/asm-sh/addrspace.h
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_ADDRSPACE_H
++#define __ASM_AVR32_ADDRSPACE_H
++
++#ifdef CONFIG_MMU
++
++/* Memory segments when segmentation is enabled */
++#define P0SEG 0x00000000
++#define P1SEG 0x80000000
++#define P2SEG 0xa0000000
++#define P3SEG 0xc0000000
++#define P4SEG 0xe0000000
++
++/* Returns the privileged segment base of a given address */
++#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
++
++/* Returns the physical address of a PnSEG (n=1,2) address */
++#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
++
++/*
++ * Map an address to a certain privileged segment
++ */
++#define P1SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \
++ | P1SEG))
++#define P2SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \
++ | P2SEG))
++#define P3SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \
++ | P3SEG))
++#define P4SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \
++ | P4SEG))
++
++#endif /* CONFIG_MMU */
++
++#endif /* __ASM_AVR32_ADDRSPACE_H */
+diff --git a/include/asm-avr32/arch-at32ap/at91rm9200_pdc.h b/include/asm-avr32/arch-at32ap/at91rm9200_pdc.h
+new file mode 100644
+index 0000000..ce1150d
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/at91rm9200_pdc.h
+@@ -0,0 +1,36 @@
++/*
++ * include/asm-arm/arch-at91rm9200/at91rm9200_pdc.h
++ *
++ * Copyright (C) 2005 Ivan Kokshaysky
++ * Copyright (C) SAN People
++ *
++ * Peripheral Data Controller (PDC) registers.
++ * Based on AT91RM9200 datasheet revision E.
++ *
++ * 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.
++ */
++
++#ifndef AT91RM9200_PDC_H
++#define AT91RM9200_PDC_H
++
++#define AT91_PDC_RPR 0x100 /* Receive Pointer Register */
++#define AT91_PDC_RCR 0x104 /* Receive Counter Register */
++#define AT91_PDC_TPR 0x108 /* Transmit Pointer Register */
++#define AT91_PDC_TCR 0x10c /* Transmit Counter Register */
++#define AT91_PDC_RNPR 0x110 /* Receive Next Pointer Register */
++#define AT91_PDC_RNCR 0x114 /* Receive Next Counter Register */
++#define AT91_PDC_TNPR 0x118 /* Transmit Next Pointer Register */
++#define AT91_PDC_TNCR 0x11c /* Transmit Next Counter Register */
++
++#define AT91_PDC_PTCR 0x120 /* Transfer Control Register */
++#define AT91_PDC_RXTEN (1 << 0) /* Receiver Transfer Enable */
++#define AT91_PDC_RXTDIS (1 << 1) /* Receiver Transfer Disable */
++#define AT91_PDC_TXTEN (1 << 8) /* Transmitter Transfer Enable */
++#define AT91_PDC_TXTDIS (1 << 9) /* Transmitter Transfer Disable */
++
++#define AT91_PDC_PTSR 0x124 /* Transfer Status Register */
++
++#endif
+diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
+new file mode 100644
+index 0000000..a39b3e9
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/board.h
+@@ -0,0 +1,41 @@
++/*
++ * Platform data definitions.
++ */
++#ifndef __ASM_ARCH_BOARD_H
++#define __ASM_ARCH_BOARD_H
++
++#include <linux/types.h>
++
++/* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
++void at32_add_system_devices(void);
++
++#define ATMEL_MAX_UART 4
++extern struct platform_device *atmel_default_console_device;
++
++struct atmel_uart_data {
++ short use_dma_tx; /* use transmit DMA? */
++ short use_dma_rx; /* use receive DMA? */
++ void __iomem *regs; /* virtual base address, if any */
++};
++void at32_map_usart(unsigned int hw_id, unsigned int line);
++struct platform_device *at32_add_device_usart(unsigned int id);
++
++struct eth_platform_data {
++ u8 valid;
++ u8 mii_phy_addr;
++ u8 is_rmii;
++ u8 hw_addr[6];
++};
++struct platform_device *
++at32_add_device_eth(unsigned int id, struct eth_platform_data *data);
++
++struct platform_device *at32_add_device_spi(unsigned int id);
++
++struct lcdc_platform_data {
++ unsigned long fbmem_start;
++ unsigned long fbmem_size;
++};
++struct platform_device *
++at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data);
++
++#endif /* __ASM_ARCH_BOARD_H */
+diff --git a/include/asm-avr32/arch-at32ap/init.h b/include/asm-avr32/arch-at32ap/init.h
+new file mode 100644
+index 0000000..5e75d85
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/init.h
+@@ -0,0 +1,22 @@
++/*
++ * AT32AP platform initialization calls.
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_AT32AP_INIT_H__
++#define __ASM_AVR32_AT32AP_INIT_H__
++
++void setup_platform(void);
++void setup_board(void);
++
++/* Called by setup_platform */
++void at32_clock_init(void);
++void at32_portmux_init(void);
++
++void at32_setup_serial_console(unsigned int usart_id);
++
++#endif /* __ASM_AVR32_AT32AP_INIT_H__ */
+diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h
+new file mode 100644
+index 0000000..4d50421
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/portmux.h
+@@ -0,0 +1,16 @@
++/*
++ * AT32 portmux interface.
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_AT32_PORTMUX_H__
++#define __ASM_AVR32_AT32_PORTMUX_H__
++
++void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
++ unsigned int function_id);
++
++#endif /* __ASM_AVR32_AT32_PORTMUX_H__ */
+diff --git a/include/asm-avr32/arch-at32ap/sm.h b/include/asm-avr32/arch-at32ap/sm.h
+new file mode 100644
+index 0000000..265a9ea
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/sm.h
+@@ -0,0 +1,27 @@
++/*
++ * AT32 System Manager interface.
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_AT32_SM_H__
++#define __ASM_AVR32_AT32_SM_H__
++
++struct irq_chip;
++struct platform_device;
++
++struct at32_sm {
++ spinlock_t lock;
++ void __iomem *regs;
++ struct irq_chip *eim_chip;
++ unsigned int eim_first_irq;
++ struct platform_device *pdev;
++};
++
++extern struct platform_device at32_sm_device;
++extern struct at32_sm system_manager;
++
++#endif /* __ASM_AVR32_AT32_SM_H__ */
+diff --git a/include/asm-avr32/arch-at32ap/smc.h b/include/asm-avr32/arch-at32ap/smc.h
+new file mode 100644
+index 0000000..3732b32
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/smc.h
+@@ -0,0 +1,60 @@
++/*
++ * Static Memory Controller for AT32 chips
++ *
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * Inspired by the OMAP2 General-Purpose Memory Controller interface
++ *
++ * 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 __ARCH_AT32AP_SMC_H
++#define __ARCH_AT32AP_SMC_H
++
++/*
++ * All timing parameters are in nanoseconds.
++ */
++struct smc_config {
++ /* Delay from address valid to assertion of given strobe */
++ u16 ncs_read_setup;
++ u16 nrd_setup;
++ u16 ncs_write_setup;
++ u16 nwe_setup;
++
++ /* Pulse length of given strobe */
++ u16 ncs_read_pulse;
++ u16 nrd_pulse;
++ u16 ncs_write_pulse;
++ u16 nwe_pulse;
++
++ /* Total cycle length of given operation */
++ u16 read_cycle;
++ u16 write_cycle;
++
++ /* Bus width in bytes */
++ u8 bus_width;
++
++ /*
++ * 0: Data is sampled on rising edge of NCS
++ * 1: Data is sampled on rising edge of NRD
++ */
++ unsigned int nrd_controlled:1;
++
++ /*
++ * 0: Data is driven on falling edge of NCS
++ * 1: Data is driven on falling edge of NWR
++ */
++ unsigned int nwe_controlled:1;
++
++ /*
++ * 0: Byte select access type
++ * 1: Byte write access type
++ */
++ unsigned int byte_write:1;
++};
++
++extern int smc_set_configuration(int cs, const struct smc_config *config);
++extern struct smc_config *smc_get_configuration(int cs);
++
++#endif /* __ARCH_AT32AP_SMC_H */
+diff --git a/include/asm-avr32/asm.h b/include/asm-avr32/asm.h
+new file mode 100644
+index 0000000..515c761
+--- /dev/null
++++ b/include/asm-avr32/asm.h
+@@ -0,0 +1,102 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_ASM_H__
++#define __ASM_AVR32_ASM_H__
++
++#include <asm/sysreg.h>
++#include <asm/asm-offsets.h>
++#include <asm/thread_info.h>
++
++#define mask_interrupts ssrf SR_GM_BIT
++#define mask_exceptions ssrf SR_EM_BIT
++#define unmask_interrupts csrf SR_GM_BIT
++#define unmask_exceptions csrf SR_EM_BIT
++
++#ifdef CONFIG_FRAME_POINTER
++ .macro save_fp
++ st.w --sp, r7
++ .endm
++ .macro restore_fp
++ ld.w r7, sp++
++ .endm
++ .macro zero_fp
++ mov r7, 0
++ .endm
++#else
++ .macro save_fp
++ .endm
++ .macro restore_fp
++ .endm
++ .macro zero_fp
++ .endm
++#endif
++ .macro get_thread_info reg
++ mov \reg, sp
++ andl \reg, ~(THREAD_SIZE - 1) & 0xffff
++ .endm
++
++ /* Save and restore registers */
++ .macro save_min sr, tmp=lr
++ pushm lr
++ mfsr \tmp, \sr
++ zero_fp
++ st.w --sp, \tmp
++ .endm
++
++ .macro restore_min sr, tmp=lr
++ ld.w \tmp, sp++
++ mtsr \sr, \tmp
++ popm lr
++ .endm
++
++ .macro save_half sr, tmp=lr
++ save_fp
++ pushm r8-r9,r10,r11,r12,lr
++ zero_fp
++ mfsr \tmp, \sr
++ st.w --sp, \tmp
++ .endm
++
++ .macro restore_half sr, tmp=lr
++ ld.w \tmp, sp++
++ mtsr \sr, \tmp
++ popm r8-r9,r10,r11,r12,lr
++ restore_fp
++ .endm
++
++ .macro save_full_user sr, tmp=lr
++ stmts --sp, r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,sp,lr
++ st.w --sp, lr
++ zero_fp
++ mfsr \tmp, \sr
++ st.w --sp, \tmp
++ .endm
++
++ .macro restore_full_user sr, tmp=lr
++ ld.w \tmp, sp++
++ mtsr \sr, \tmp
++ ld.w lr, sp++
++ ldmts sp++, r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,sp,lr
++ .endm
++
++ /* uaccess macros */
++ .macro branch_if_kernel scratch, label
++ get_thread_info \scratch
++ ld.w \scratch, \scratch[TI_flags]
++ bld \scratch, TIF_USERSPACE
++ brcc \label
++ .endm
++
++ .macro ret_if_privileged scratch, addr, size, ret
++ sub \scratch, \size, 1
++ add \scratch, \addr
++ retcs \ret
++ retmi \ret
++ .endm
++
++#endif /* __ASM_AVR32_ASM_H__ */
+diff --git a/include/asm-avr32/atomic.h b/include/asm-avr32/atomic.h
+new file mode 100644
+index 0000000..c40b603
+--- /dev/null
++++ b/include/asm-avr32/atomic.h
+@@ -0,0 +1,201 @@
++/*
++ * Atomic operations that C can't guarantee us. Useful for
++ * resource counting etc.
++ *
++ * But use these as seldom as possible since they are slower than
++ * regular operations.
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_ATOMIC_H
++#define __ASM_AVR32_ATOMIC_H
++
++#include <asm/system.h>
++
++typedef struct { volatile int counter; } atomic_t;
++#define ATOMIC_INIT(i) { (i) }
++
++#define atomic_read(v) ((v)->counter)
++#define atomic_set(v, i) (((v)->counter) = i)
++
++/*
++ * atomic_sub_return - subtract the atomic variable
++ * @i: integer value to subtract
++ * @v: pointer of type atomic_t
++ *
++ * Atomically subtracts @i from @v. Returns the resulting value.
++ */
++static inline int atomic_sub_return(int i, atomic_t *v)
++{
++ int result;
++
++ asm volatile(
++ "/* atomic_sub_return */\n"
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " sub %0, %3\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(result), "=o"(v->counter)
++ : "m"(v->counter), "rKs21"(i)
++ : "cc");
++
++ return result;
++}
++
++/*
++ * atomic_add_return - add integer to atomic variable
++ * @i: integer value to add
++ * @v: pointer of type atomic_t
++ *
++ * Atomically adds @i to @v. Returns the resulting value.
++ */
++static inline int atomic_add_return(int i, atomic_t *v)
++{
++ int result;
++
++ if (__builtin_constant_p(i) && (i >= -1048575) && (i <= 1048576))
++ result = atomic_sub_return(-i, v);
++ else
++ asm volatile(
++ "/* atomic_add_return */\n"
++ "1: ssrf 5\n"
++ " ld.w %0, %1\n"
++ " add %0, %3\n"
++ " stcond %2, %0\n"
++ " brne 1b"
++ : "=&r"(result), "=o"(v->counter)
++ : "m"(v->counter), "r"(i)
++ : "cc", "memory");
++
++ return result;
++}
++
++/*
++ * atomic_sub_unless - sub unless the number is a given value
++ * @v: pointer of type atomic_t
++ * @a: the amount to add to v...
++ * @u: ...unless v is equal to u.
++ *
++ * If the atomic value v is not equal to u, this function subtracts a
++ * from v, and returns non zero. If v is equal to u then it returns
++ * zero. This is done as an atomic operation.
++*/
++static inline int atomic_sub_unless(atomic_t *v, int a, int u)
++{
++ int tmp, result = 0;
++
++ asm volatile(
++ "/* atomic_sub_unless */\n"
++ "1: ssrf 5\n"
++ " ld.w %0, %3\n"
++ " cp.w %0, %5\n"
++ " breq 1f\n"
++ " sub %0, %4\n"
++ " stcond %2, %0\n"
++ " brne 1b\n"
++ " mov %1, 1\n"
++ "1:"
++ : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
++ : "m"(v->counter), "rKs21"(a), "rKs21"(u)
++ : "cc", "memory");
++
++ return result;
++}
++
++/*
++ * atomic_add_unless - add unless the number is a given value
++ * @v: pointer of type atomic_t
++ * @a: the amount to add to v...
++ * @u: ...unless v is equal to u.
++ *
++ * If the atomic value v is not equal to u, this function adds a to v,
++ * and returns non zero. If v is equal to u then it returns zero. This
++ * is done as an atomic operation.
++*/
++static inline int atomic_add_unless(atomic_t *v, int a, int u)
++{
++ int tmp, result;
++
++ if (__builtin_constant_p(a) && (a >= -1048575) && (a <= 1048576))
++ result = atomic_sub_unless(v, -a, u);
++ else {
++ result = 0;
++ asm volatile(
++ "/* atomic_add_unless */\n"
++ "1: ssrf 5\n"
++ " ld.w %0, %3\n"
++ " cp.w %0, %5\n"
++ " breq 1f\n"
++ " add %0, %4\n"
++ " stcond %2, %0\n"
++ " brne 1b\n"
++ " mov %1, 1\n"
++ "1:"
++ : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
++ : "m"(v->counter), "r"(a), "ir"(u)
++ : "cc", "memory");
++ }
++
++ return result;
++}
++
++/*
++ * atomic_sub_if_positive - conditionally subtract integer from atomic variable
++ * @i: integer value to subtract
++ * @v: pointer of type atomic_t
++ *
++ * Atomically test @v and subtract @i if @v is greater or equal than @i.
++ * The function returns the old value of @v minus @i.
++ */
++static inline int atomic_sub_if_positive(int i, atomic_t *v)
++{
++ int result;
++
++ asm volatile(
++ "/* atomic_sub_if_positive */\n"
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " sub %0, %3\n"
++ " brlt 1f\n"
++ " stcond %1, %0\n"
++ " brne 1b\n"
++ "1:"
++ : "=&r"(result), "=o"(v->counter)
++ : "m"(v->counter), "ir"(i)
++ : "cc", "memory");
++
++ return result;
++}
++
++#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
++#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
++
++#define atomic_sub(i, v) (void)atomic_sub_return(i, v)
++#define atomic_add(i, v) (void)atomic_add_return(i, v)
++#define atomic_dec(v) atomic_sub(1, (v))
++#define atomic_inc(v) atomic_add(1, (v))
++
++#define atomic_dec_return(v) atomic_sub_return(1, v)
++#define atomic_inc_return(v) atomic_add_return(1, v)
++
++#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
++#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)
++#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
++#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0)
++
++#define atomic_inc_not_zero(v) atomic_add_unless(v, 1, 0)
++#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
++
++#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()
++
++#include <asm-generic/atomic.h>
++
++#endif /* __ASM_AVR32_ATOMIC_H */
+diff --git a/include/asm-avr32/auxvec.h b/include/asm-avr32/auxvec.h
+new file mode 100644
+index 0000000..d5dd435
+--- /dev/null
++++ b/include/asm-avr32/auxvec.h
+@@ -0,0 +1,4 @@
++#ifndef __ASM_AVR32_AUXVEC_H
++#define __ASM_AVR32_AUXVEC_H
++
++#endif /* __ASM_AVR32_AUXVEC_H */
+diff --git a/include/asm-avr32/bitops.h b/include/asm-avr32/bitops.h
+new file mode 100644
+index 0000000..5299f8c
+--- /dev/null
++++ b/include/asm-avr32/bitops.h
+@@ -0,0 +1,296 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_BITOPS_H
++#define __ASM_AVR32_BITOPS_H
++
++#include <asm/byteorder.h>
++#include <asm/system.h>
++
++/*
++ * clear_bit() doesn't provide any barrier for the compiler
++ */
++#define smp_mb__before_clear_bit() barrier()
++#define smp_mb__after_clear_bit() barrier()
++
++/*
++ * set_bit - Atomically set a bit in memory
++ * @nr: the bit to set
++ * @addr: the address to start counting from
++ *
++ * This function is atomic and may not be reordered. See __set_bit()
++ * if you do not require the atomic guarantees.
++ *
++ * Note that @nr may be almost arbitrarily large; this function is not
++ * restricted to acting on a single-word quantity.
++ */
++static inline void set_bit(int nr, volatile void * addr)
++{
++ unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
++ unsigned long tmp;
++
++ if (__builtin_constant_p(nr)) {
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " sbr %0, %3\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p)
++ : "m"(*p), "i"(nr)
++ : "cc");
++ } else {
++ unsigned long mask = 1UL << (nr % BITS_PER_LONG);
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " or %0, %3\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p)
++ : "m"(*p), "r"(mask)
++ : "cc");
++ }
++}
++
++/*
++ * clear_bit - Clears a bit in memory
++ * @nr: Bit to clear
++ * @addr: Address to start counting from
++ *
++ * clear_bit() is atomic and may not be reordered. However, it does
++ * not contain a memory barrier, so if it is used for locking purposes,
++ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
++ * in order to ensure changes are visible on other processors.
++ */
++static inline void clear_bit(int nr, volatile void * addr)
++{
++ unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
++ unsigned long tmp;
++
++ if (__builtin_constant_p(nr)) {
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " cbr %0, %3\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p)
++ : "m"(*p), "i"(nr)
++ : "cc");
++ } else {
++ unsigned long mask = 1UL << (nr % BITS_PER_LONG);
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " andn %0, %3\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p)
++ : "m"(*p), "r"(mask)
++ : "cc");
++ }
++}
++
++/*
++ * change_bit - Toggle a bit in memory
++ * @nr: Bit to change
++ * @addr: Address to start counting from
++ *
++ * change_bit() is atomic and may not be reordered.
++ * Note that @nr may be almost arbitrarily large; this function is not
++ * restricted to acting on a single-word quantity.
++ */
++static inline void change_bit(int nr, volatile void * addr)
++{
++ unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
++ unsigned long mask = 1UL << (nr % BITS_PER_LONG);
++ unsigned long tmp;
++
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %2\n"
++ " eor %0, %3\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p)
++ : "m"(*p), "r"(mask)
++ : "cc");
++}
++
++/*
++ * test_and_set_bit - Set a bit and return its old value
++ * @nr: Bit to set
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It also implies a memory barrier.
++ */
++static inline int test_and_set_bit(int nr, volatile void * addr)
++{
++ unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
++ unsigned long mask = 1UL << (nr % BITS_PER_LONG);
++ unsigned long tmp, old;
++
++ if (__builtin_constant_p(nr)) {
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %3\n"
++ " mov %2, %0\n"
++ " sbr %0, %4\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p), "=&r"(old)
++ : "m"(*p), "i"(nr)
++ : "memory", "cc");
++ } else {
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %2, %3\n"
++ " or %0, %2, %4\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p), "=&r"(old)
++ : "m"(*p), "r"(mask)
++ : "memory", "cc");
++ }
++
++ return (old & mask) != 0;
++}
++
++/*
++ * test_and_clear_bit - Clear a bit and return its old value
++ * @nr: Bit to clear
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It also implies a memory barrier.
++ */
++static inline int test_and_clear_bit(int nr, volatile void * addr)
++{
++ unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
++ unsigned long mask = 1UL << (nr % BITS_PER_LONG);
++ unsigned long tmp, old;
++
++ if (__builtin_constant_p(nr)) {
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %3\n"
++ " mov %2, %0\n"
++ " cbr %0, %4\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p), "=&r"(old)
++ : "m"(*p), "i"(nr)
++ : "memory", "cc");
++ } else {
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %0, %3\n"
++ " mov %2, %0\n"
++ " andn %0, %4\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p), "=&r"(old)
++ : "m"(*p), "r"(mask)
++ : "memory", "cc");
++ }
++
++ return (old & mask) != 0;
++}
++
++/*
++ * test_and_change_bit - Change a bit and return its old value
++ * @nr: Bit to change
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It also implies a memory barrier.
++ */
++static inline int test_and_change_bit(int nr, volatile void * addr)
++{
++ unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
++ unsigned long mask = 1UL << (nr % BITS_PER_LONG);
++ unsigned long tmp, old;
++
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %2, %3\n"
++ " eor %0, %2, %4\n"
++ " stcond %1, %0\n"
++ " brne 1b"
++ : "=&r"(tmp), "=o"(*p), "=&r"(old)
++ : "m"(*p), "r"(mask)
++ : "memory", "cc");
++
++ return (old & mask) != 0;
++}
++
++#include <asm-generic/bitops/non-atomic.h>
++
++/* Find First bit Set */
++static inline unsigned long __ffs(unsigned long word)
++{
++ unsigned long result;
++
++ asm("brev %1\n\t"
++ "clz %0,%1"
++ : "=r"(result), "=&r"(word)
++ : "1"(word));
++ return result;
++}
++
++/* Find First Zero */
++static inline unsigned long ffz(unsigned long word)
++{
++ return __ffs(~word);
++}
++
++/* Find Last bit Set */
++static inline int fls(unsigned long word)
++{
++ unsigned long result;
++
++ asm("clz %0,%1" : "=r"(result) : "r"(word));
++ return 32 - result;
++}
++
++unsigned long find_first_zero_bit(const unsigned long *addr,
++ unsigned long size);
++unsigned long find_next_zero_bit(const unsigned long *addr,
++ unsigned long size,
++ unsigned long offset);
++unsigned long find_first_bit(const unsigned long *addr,
++ unsigned long size);
++unsigned long find_next_bit(const unsigned long *addr,
++ unsigned long size,
++ unsigned long offset);
++
++/*
++ * ffs: find first bit set. This is defined the same way as
++ * the libc and compiler builtin ffs routines, therefore
++ * differs in spirit from the above ffz (man ffs).
++ *
++ * The difference is that bit numbering starts at 1, and if no bit is set,
++ * the function returns 0.
++ */
++static inline int ffs(unsigned long word)
++{
++ if(word == 0)
++ return 0;
++ return __ffs(word) + 1;
++}
++
++#include <asm-generic/bitops/fls64.h>
++#include <asm-generic/bitops/sched.h>
++#include <asm-generic/bitops/hweight.h>
++
++#include <asm-generic/bitops/ext2-non-atomic.h>
++#include <asm-generic/bitops/ext2-atomic.h>
++#include <asm-generic/bitops/minix-le.h>
++
++#endif /* __ASM_AVR32_BITOPS_H */
+diff --git a/include/asm-avr32/bug.h b/include/asm-avr32/bug.h
+new file mode 100644
+index 0000000..521766b
+--- /dev/null
++++ b/include/asm-avr32/bug.h
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_BUG_H
++#define __ASM_AVR32_BUG_H
++
++#ifdef CONFIG_BUG
++
++/*
++ * According to our Chief Architect, this compact opcode is very
++ * unlikely to ever be implemented.
++ */
++#define AVR32_BUG_OPCODE 0x5df0
++
++#ifdef CONFIG_DEBUG_BUGVERBOSE
++
++#define BUG() \
++ do { \
++ asm volatile(".hword %0\n\t" \
++ ".hword %1\n\t" \
++ ".long %2" \
++ : \
++ : "n"(AVR32_BUG_OPCODE), \
++ "i"(__LINE__), "X"(__FILE__)); \
++ } while (0)
++
++#else
++
++#define BUG() \
++ do { \
++ asm volatile(".hword %0\n\t" \
++ : : "n"(AVR32_BUG_OPCODE)); \
++ } while (0)
++
++#endif /* CONFIG_DEBUG_BUGVERBOSE */
++
++#define HAVE_ARCH_BUG
++
++#endif /* CONFIG_BUG */
++
++#include <asm-generic/bug.h>
++
++#endif /* __ASM_AVR32_BUG_H */
+diff --git a/include/asm-avr32/bugs.h b/include/asm-avr32/bugs.h
+new file mode 100644
+index 0000000..7635e77
+--- /dev/null
++++ b/include/asm-avr32/bugs.h
+@@ -0,0 +1,15 @@
++/*
++ * This is included by init/main.c to check for architecture-dependent bugs.
++ *
++ * Needs:
++ * void check_bugs(void);
++ */
++#ifndef __ASM_AVR32_BUGS_H
++#define __ASM_AVR32_BUGS_H
++
++static void __init check_bugs(void)
++{
++ cpu_data->loops_per_jiffy = loops_per_jiffy;
++}
++
++#endif /* __ASM_AVR32_BUGS_H */
+diff --git a/include/asm-avr32/byteorder.h b/include/asm-avr32/byteorder.h
+new file mode 100644
+index 0000000..402ff41
+--- /dev/null
++++ b/include/asm-avr32/byteorder.h
+@@ -0,0 +1,25 @@
++/*
++ * AVR32 endian-conversion functions.
++ */
++#ifndef __ASM_AVR32_BYTEORDER_H
++#define __ASM_AVR32_BYTEORDER_H
++
++#include <asm/types.h>
++#include <linux/compiler.h>
++
++#ifdef __CHECKER__
++extern unsigned long __builtin_bswap_32(unsigned long x);
++extern unsigned short __builtin_bswap_16(unsigned short x);
++#endif
++
++#define __arch__swab32(x) __builtin_bswap_32(x)
++#define __arch__swab16(x) __builtin_bswap_16(x)
++
++#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
++# define __BYTEORDER_HAS_U64__
++# define __SWAB_64_THRU_32__
++#endif
++
++#include <linux/byteorder/big_endian.h>
++
++#endif /* __ASM_AVR32_BYTEORDER_H */
+diff --git a/include/asm-avr32/cache.h b/include/asm-avr32/cache.h
+new file mode 100644
+index 0000000..dabb955
+--- /dev/null
++++ b/include/asm-avr32/cache.h
+@@ -0,0 +1,29 @@
++#ifndef __ASM_AVR32_CACHE_H
++#define __ASM_AVR32_CACHE_H
++
++#define L1_CACHE_SHIFT 5
++#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++
++#ifndef __ASSEMBLER__
++struct cache_info {
++ unsigned int ways;
++ unsigned int sets;
++ unsigned int linesz;
++};
++#endif /* __ASSEMBLER */
++
++/* Cache operation constants */
++#define ICACHE_FLUSH 0x00
++#define ICACHE_INVALIDATE 0x01
++#define ICACHE_LOCK 0x02
++#define ICACHE_UNLOCK 0x03
++#define ICACHE_PREFETCH 0x04
++
++#define DCACHE_FLUSH 0x08
++#define DCACHE_LOCK 0x09
++#define DCACHE_UNLOCK 0x0a
++#define DCACHE_INVALIDATE 0x0b
++#define DCACHE_CLEAN 0x0c
++#define DCACHE_CLEAN_INVAL 0x0d
++
++#endif /* __ASM_AVR32_CACHE_H */
+diff --git a/include/asm-avr32/cachectl.h b/include/asm-avr32/cachectl.h
+new file mode 100644
+index 0000000..4faf1ce
+--- /dev/null
++++ b/include/asm-avr32/cachectl.h
+@@ -0,0 +1,11 @@
++#ifndef __ASM_AVR32_CACHECTL_H
++#define __ASM_AVR32_CACHECTL_H
++
++/*
++ * Operations that can be performed through the cacheflush system call
++ */
++
++/* Clean the data cache, then invalidate the icache */
++#define CACHE_IFLUSH 0
++
++#endif /* __ASM_AVR32_CACHECTL_H */
+diff --git a/include/asm-avr32/cacheflush.h b/include/asm-avr32/cacheflush.h
+new file mode 100644
+index 0000000..f1bf170
+--- /dev/null
++++ b/include/asm-avr32/cacheflush.h
+@@ -0,0 +1,129 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_CACHEFLUSH_H
++#define __ASM_AVR32_CACHEFLUSH_H
++
++/* Keep includes the same across arches. */
++#include <linux/mm.h>
++
++#define CACHE_OP_ICACHE_INVALIDATE 0x01
++#define CACHE_OP_DCACHE_INVALIDATE 0x0b
++#define CACHE_OP_DCACHE_CLEAN 0x0c
++#define CACHE_OP_DCACHE_CLEAN_INVAL 0x0d
++
++/*
++ * Invalidate any cacheline containing virtual address vaddr without
++ * writing anything back to memory.
++ *
++ * Note that this function may corrupt unrelated data structures when
++ * applied on buffers that are not cacheline aligned in both ends.
++ */
++static inline void invalidate_dcache_line(void *vaddr)
++{
++ asm volatile("cache %0[0], %1"
++ :
++ : "r"(vaddr), "n"(CACHE_OP_DCACHE_INVALIDATE)
++ : "memory");
++}
++
++/*
++ * Make sure any cacheline containing virtual address vaddr is written
++ * to memory.
++ */
++static inline void clean_dcache_line(void *vaddr)
++{
++ asm volatile("cache %0[0], %1"
++ :
++ : "r"(vaddr), "n"(CACHE_OP_DCACHE_CLEAN)
++ : "memory");
++}
++
++/*
++ * Make sure any cacheline containing virtual address vaddr is written
++ * to memory and then invalidate it.
++ */
++static inline void flush_dcache_line(void *vaddr)
++{
++ asm volatile("cache %0[0], %1"
++ :
++ : "r"(vaddr), "n"(CACHE_OP_DCACHE_CLEAN_INVAL)
++ : "memory");
++}
++
++/*
++ * Invalidate any instruction cacheline containing virtual address
++ * vaddr.
++ */
++static inline void invalidate_icache_line(void *vaddr)
++{
++ asm volatile("cache %0[0], %1"
++ :
++ : "r"(vaddr), "n"(CACHE_OP_ICACHE_INVALIDATE)
++ : "memory");
++}
++
++/*
++ * Applies the above functions on all lines that are touched by the
++ * specified virtual address range.
++ */
++void invalidate_dcache_region(void *start, size_t len);
++void clean_dcache_region(void *start, size_t len);
++void flush_dcache_region(void *start, size_t len);
++void invalidate_icache_region(void *start, size_t len);
++
++/*
++ * Make sure any pending writes are completed before continuing.
++ */
++#define flush_write_buffer() asm volatile("sync 0" : : : "memory")
++
++/*
++ * The following functions are called when a virtual mapping changes.
++ * We do not need to flush anything in this case.
++ */
++#define flush_cache_all() do { } while (0)
++#define flush_cache_mm(mm) do { } while (0)
++#define flush_cache_range(vma, start, end) do { } while (0)
++#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
++#define flush_cache_vmap(start, end) do { } while (0)
++#define flush_cache_vunmap(start, end) do { } while (0)
++
++/*
++ * I think we need to implement this one to be able to reliably
++ * execute pages from RAMDISK. However, if we implement the
++ * flush_dcache_*() functions, it might not be needed anymore.
++ *
++ * #define flush_icache_page(vma, page) do { } while (0)
++ */
++extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
++
++/*
++ * These are (I think) related to D-cache aliasing. We might need to
++ * do something here, but only for certain configurations. No such
++ * configurations exist at this time.
++ */
++#define flush_dcache_page(page) do { } while (0)
++#define flush_dcache_mmap_lock(page) do { } while (0)
++#define flush_dcache_mmap_unlock(page) do { } while (0)
++
++/*
++ * These are for I/D cache coherency. In this case, we do need to
++ * flush with all configurations.
++ */
++extern void flush_icache_range(unsigned long start, unsigned long end);
++extern void flush_icache_user_range(struct vm_area_struct *vma,
++ struct page *page,
++ unsigned long addr, int len);
++
++#define copy_to_user_page(vma, page, vaddr, dst, src, len) do { \
++ memcpy(dst, src, len); \
++ flush_icache_user_range(vma, page, vaddr, len); \
++} while(0)
++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
++ memcpy(dst, src, len)
++
++#endif /* __ASM_AVR32_CACHEFLUSH_H */
+diff --git a/include/asm-avr32/checksum.h b/include/asm-avr32/checksum.h
+new file mode 100644
+index 0000000..41b7af0
+--- /dev/null
++++ b/include/asm-avr32/checksum.h
+@@ -0,0 +1,156 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_CHECKSUM_H
++#define __ASM_AVR32_CHECKSUM_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
++ */
++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
++ */
++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().
++ */
++static 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);
++}
++
++static inline
++unsigned int csum_partial_copy_from_user (const char __user *src, char *dst,
++ int len, int sum, int *err_ptr)
++{
++ return csum_partial_copy_generic((const char __force *)src, dst, len,
++ sum, err_ptr, NULL);
++}
++
++/*
++ * 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;
++
++ __asm__ __volatile__(
++ " ld.w %0, %1++\n"
++ " ld.w %3, %1++\n"
++ " sub %2, 4\n"
++ " add %0, %3\n"
++ " ld.w %3, %1++\n"
++ " adc %0, %0, %3\n"
++ " ld.w %3, %1++\n"
++ " adc %0, %0, %3\n"
++ " acr %0\n"
++ "1: ld.w %3, %1++\n"
++ " add %0, %3\n"
++ " acr %0\n"
++ " sub %2, 1\n"
++ " brne 1b\n"
++ " lsl %3, %0, 16\n"
++ " andl %0, 0\n"
++ " mov %2, 0xffff\n"
++ " add %0, %3\n"
++ " adc %0, %0, %2\n"
++ " com %0\n"
++ " lsr %0, 16\n"
++ : "=r"(sum), "=r"(iph), "=r"(ihl), "=r"(tmp)
++ : "1"(iph), "2"(ihl)
++ : "memory", "cc");
++ return sum;
++}
++
++/*
++ * Fold a partial checksum
++ */
++
++static inline unsigned int csum_fold(unsigned int sum)
++{
++ unsigned int tmp;
++
++ asm(" bfextu %1, %0, 0, 16\n"
++ " lsr %0, 16\n"
++ " add %0, %1\n"
++ " bfextu %1, %0, 16, 16\n"
++ " add %0, %1"
++ : "=&r"(sum), "=&r"(tmp)
++ : "0"(sum));
++
++ return ~sum;
++}
++
++static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
++ unsigned long daddr,
++ unsigned short len,
++ unsigned short proto,
++ unsigned int sum)
++{
++ asm(" add %0, %1\n"
++ " adc %0, %0, %2\n"
++ " adc %0, %0, %3\n"
++ " acr %0"
++ : "=r"(sum)
++ : "r"(daddr), "r"(saddr), "r"(ntohs(len) | (proto << 16)),
++ "0"(sum)
++ : "cc");
++
++ 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));
++}
++
++#endif /* __ASM_AVR32_CHECKSUM_H */
+diff --git a/include/asm-avr32/cputime.h b/include/asm-avr32/cputime.h
+new file mode 100644
+index 0000000..e87e0f8
+--- /dev/null
++++ b/include/asm-avr32/cputime.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_CPUTIME_H
++#define __ASM_AVR32_CPUTIME_H
++
++#include <asm-generic/cputime.h>
++
++#endif /* __ASM_AVR32_CPUTIME_H */
+diff --git a/include/asm-avr32/current.h b/include/asm-avr32/current.h
+new file mode 100644
+index 0000000..c7b0549
+--- /dev/null
++++ b/include/asm-avr32/current.h
+@@ -0,0 +1,15 @@
++#ifndef __ASM_AVR32_CURRENT_H
++#define __ASM_AVR32_CURRENT_H
++
++#include <linux/thread_info.h>
++
++struct task_struct;
++
++inline static struct task_struct * get_current(void)
++{
++ return current_thread_info()->task;
++}
++
++#define current get_current()
++
++#endif /* __ASM_AVR32_CURRENT_H */
+diff --git a/include/asm-avr32/delay.h b/include/asm-avr32/delay.h
+new file mode 100644
+index 0000000..cc3b2e3
+--- /dev/null
++++ b/include/asm-avr32/delay.h
+@@ -0,0 +1,26 @@
++#ifndef __ASM_AVR32_DELAY_H
++#define __ASM_AVR32_DELAY_H
++
++/*
++ * Copyright (C) 1993 Linus Torvalds
++ *
++ * Delay routines calling functions in arch/avr32/lib/delay.c
++ */
++
++extern void __bad_udelay(void);
++extern void __bad_ndelay(void);
++
++extern void __udelay(unsigned long usecs);
++extern void __ndelay(unsigned long nsecs);
++extern void __const_udelay(unsigned long usecs);
++extern void __delay(unsigned long loops);
++
++#define udelay(n) (__builtin_constant_p(n) ? \
++ ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \
++ __udelay(n))
++
++#define ndelay(n) (__builtin_constant_p(n) ? \
++ ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
++ __ndelay(n))
++
++#endif /* __ASM_AVR32_DELAY_H */
+diff --git a/include/asm-avr32/div64.h b/include/asm-avr32/div64.h
+new file mode 100644
+index 0000000..d7ddd4f
+--- /dev/null
++++ b/include/asm-avr32/div64.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_DIV64_H
++#define __ASM_AVR32_DIV64_H
++
++#include <asm-generic/div64.h>
++
++#endif /* __ASM_AVR32_DIV64_H */
+diff --git a/include/asm-avr32/dma-mapping.h b/include/asm-avr32/dma-mapping.h
+new file mode 100644
+index 0000000..4c40cb4
+--- /dev/null
++++ b/include/asm-avr32/dma-mapping.h
+@@ -0,0 +1,320 @@
++#ifndef __ASM_AVR32_DMA_MAPPING_H
++#define __ASM_AVR32_DMA_MAPPING_H
++
++#include <linux/mm.h>
++#include <linux/device.h>
++#include <asm/scatterlist.h>
++#include <asm/processor.h>
++#include <asm/cacheflush.h>
++#include <asm/io.h>
++
++extern void dma_cache_sync(void *vaddr, size_t size, int direction);
++
++/*
++ * Return whether the given device DMA address mask can be supported
++ * properly. For example, if your device can only drive the low 24-bits
++ * during bus mastering, then you would pass 0x00ffffff as the mask
++ * to this function.
++ */
++static inline int dma_supported(struct device *dev, u64 mask)
++{
++ /* Fix when needed. I really don't know of any limitations */
++ return 1;
++}
++
++static inline int dma_set_mask(struct device *dev, u64 dma_mask)
++{
++ if (!dev->dma_mask || !dma_supported(dev, dma_mask))
++ return -EIO;
++
++ *dev->dma_mask = dma_mask;
++ return 0;
++}
++
++/**
++ * dma_alloc_coherent - allocate consistent memory for DMA
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @size: required memory size
++ * @handle: bus-specific DMA address
++ *
++ * Allocate some uncached, unbuffered memory for a device for
++ * performing DMA. This function allocates pages, and will
++ * return the CPU-viewed address, and sets @handle to be the
++ * device-viewed address.
++ */
++extern void *dma_alloc_coherent(struct device *dev, size_t size,
++ dma_addr_t *handle, gfp_t gfp);
++
++/**
++ * dma_free_coherent - free memory allocated by dma_alloc_coherent
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @size: size of memory originally requested in dma_alloc_coherent
++ * @cpu_addr: CPU-view address returned from dma_alloc_coherent
++ * @handle: device-view address returned from dma_alloc_coherent
++ *
++ * Free (and unmap) a DMA buffer previously allocated by
++ * dma_alloc_coherent().
++ *
++ * References to memory and mappings associated with cpu_addr/handle
++ * during and after this call executing are illegal.
++ */
++extern void dma_free_coherent(struct device *dev, size_t size,
++ void *cpu_addr, dma_addr_t handle);
++
++/**
++ * dma_alloc_writecombine - allocate write-combining memory for DMA
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @size: required memory size
++ * @handle: bus-specific DMA address
++ *
++ * Allocate some uncached, buffered memory for a device for
++ * performing DMA. This function allocates pages, and will
++ * return the CPU-viewed address, and sets @handle to be the
++ * device-viewed address.
++ */
++extern void *dma_alloc_writecombine(struct device *dev, size_t size,
++ dma_addr_t *handle, gfp_t gfp);
++
++/**
++ * dma_free_coherent - free memory allocated by dma_alloc_writecombine
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @size: size of memory originally requested in dma_alloc_writecombine
++ * @cpu_addr: CPU-view address returned from dma_alloc_writecombine
++ * @handle: device-view address returned from dma_alloc_writecombine
++ *
++ * Free (and unmap) a DMA buffer previously allocated by
++ * dma_alloc_writecombine().
++ *
++ * References to memory and mappings associated with cpu_addr/handle
++ * during and after this call executing are illegal.
++ */
++extern void dma_free_writecombine(struct device *dev, size_t size,
++ void *cpu_addr, dma_addr_t handle);
++
++/**
++ * dma_map_single - map a single buffer for streaming DMA
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @cpu_addr: CPU direct mapped address of buffer
++ * @size: size of buffer to map
++ * @dir: DMA transfer direction
++ *
++ * Ensure that any data held in the cache is appropriately discarded
++ * or written back.
++ *
++ * The device owns this memory once this call has completed. The CPU
++ * can regain ownership by calling dma_unmap_single() or dma_sync_single().
++ */
++static inline dma_addr_t
++dma_map_single(struct device *dev, void *cpu_addr, size_t size,
++ enum dma_data_direction direction)
++{
++ dma_cache_sync(cpu_addr, size, direction);
++ return virt_to_bus(cpu_addr);
++}
++
++/**
++ * dma_unmap_single - unmap a single buffer previously mapped
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @handle: DMA address of buffer
++ * @size: size of buffer to map
++ * @dir: DMA transfer direction
++ *
++ * Unmap a single streaming mode DMA translation. The handle and size
++ * must match what was provided in the previous dma_map_single() call.
++ * All other usages are undefined.
++ *
++ * After this call, reads by the CPU to the buffer are guaranteed to see
++ * whatever the device wrote there.
++ */
++static inline void
++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction direction)
++{
++
++}
++
++/**
++ * dma_map_page - map a portion of a page for streaming DMA
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @page: page that buffer resides in
++ * @offset: offset into page for start of buffer
++ * @size: size of buffer to map
++ * @dir: DMA transfer direction
++ *
++ * Ensure that any data held in the cache is appropriately discarded
++ * or written back.
++ *
++ * The device owns this memory once this call has completed. The CPU
++ * can regain ownership by calling dma_unmap_page() or dma_sync_single().
++ */
++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)
++{
++ return dma_map_single(dev, page_address(page) + offset,
++ size, direction);
++}
++
++/**
++ * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @handle: DMA address of buffer
++ * @size: size of buffer to map
++ * @dir: DMA transfer direction
++ *
++ * Unmap a single streaming mode DMA translation. The handle and size
++ * must match what was provided in the previous dma_map_single() call.
++ * All other usages are undefined.
++ *
++ * After this call, reads by the CPU to the buffer are guaranteed to see
++ * whatever the device wrote there.
++ */
++static inline void
++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
++ enum dma_data_direction direction)
++{
++ dma_unmap_single(dev, dma_address, size, direction);
++}
++
++/**
++ * dma_map_sg - map a set of SG buffers for streaming mode DMA
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @sg: list of buffers
++ * @nents: number of buffers to map
++ * @dir: DMA transfer direction
++ *
++ * Map a set of buffers described by scatterlist in streaming
++ * mode for DMA. This is the scatter-gather version of the
++ * above pci_map_single interface. Here the scatter gather list
++ * elements are each tagged with the appropriate dma address
++ * and length. They are obtained via sg_dma_{address,length}(SG).
++ *
++ * NOTE: An implementation may be able to use a smaller number of
++ * DMA address/length pairs than there are SG table elements.
++ * (for example via virtual mapping capabilities)
++ * The routine returns the number of addr/length pairs actually
++ * used, at most nents.
++ *
++ * Device ownership issues as mentioned above for pci_map_single are
++ * the same here.
++ */
++static inline int
++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
++ enum dma_data_direction direction)
++{
++ int i;
++
++ for (i = 0; i < nents; i++) {
++ char *virt;
++
++ sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
++ virt = page_address(sg[i].page) + sg[i].offset;
++ dma_cache_sync(virt, sg[i].length, direction);
++ }
++
++ return nents;
++}
++
++/**
++ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @sg: list of buffers
++ * @nents: number of buffers to map
++ * @dir: DMA transfer direction
++ *
++ * Unmap a set of streaming mode DMA translations.
++ * Again, CPU read rules concerning calls here are the same as for
++ * pci_unmap_single() above.
++ */
++static inline void
++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
++ enum dma_data_direction direction)
++{
++
++}
++
++/**
++ * dma_sync_single_for_cpu
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @handle: DMA address of buffer
++ * @size: size of buffer to map
++ * @dir: DMA transfer direction
++ *
++ * Make physical memory consistent for a single streaming mode DMA
++ * translation after a transfer.
++ *
++ * If you perform a dma_map_single() but wish to interrogate the
++ * buffer using the cpu, yet do not wish to teardown the DMA mapping,
++ * you must call this function before doing so. At the next point you
++ * give the DMA address back to the card, you must first perform a
++ * dma_sync_single_for_device, and then the device again owns the
++ * buffer.
++ */
++static inline void
++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
++ size_t size, enum dma_data_direction direction)
++{
++ dma_cache_sync(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)
++{
++ dma_cache_sync(bus_to_virt(dma_handle), size, direction);
++}
++
++/**
++ * dma_sync_sg_for_cpu
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @sg: list of buffers
++ * @nents: number of buffers to map
++ * @dir: DMA transfer direction
++ *
++ * Make physical memory consistent for a set of streaming
++ * mode DMA translations after a transfer.
++ *
++ * The same as dma_sync_single_for_* but for a scatter-gather list,
++ * same rules and usage.
++ */
++static inline void
++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
++ int nents, enum dma_data_direction direction)
++{
++ int i;
++
++ for (i = 0; i < nents; i++) {
++ dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
++ sg[i].length, direction);
++ }
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
++ int nents, enum dma_data_direction direction)
++{
++ int i;
++
++ for (i = 0; i < nents; i++) {
++ dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
++ sg[i].length, direction);
++ }
++}
++
++/* Now for the API extensions over the pci_ one */
++
++#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)
++
++static inline int dma_is_consistent(dma_addr_t dma_addr)
++{
++ return 1;
++}
++
++static inline int dma_get_cache_alignment(void)
++{
++ return boot_cpu_data.dcache.linesz;
++}
++
++#endif /* __ASM_AVR32_DMA_MAPPING_H */
+diff --git a/include/asm-avr32/dma.h b/include/asm-avr32/dma.h
+new file mode 100644
+index 0000000..9e91205
+--- /dev/null
++++ b/include/asm-avr32/dma.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_AVR32_DMA_H
++#define __ASM_AVR32_DMA_H
++
++/* The maximum address that we can perform a DMA transfer to on this platform.
++ * Not really applicable to AVR32, but some functions need it. */
++#define MAX_DMA_ADDRESS 0xffffffff
++
++#endif /* __ASM_AVR32_DMA_H */
+diff --git a/include/asm-avr32/elf.h b/include/asm-avr32/elf.h
+new file mode 100644
+index 0000000..d334b49
+--- /dev/null
++++ b/include/asm-avr32/elf.h
+@@ -0,0 +1,110 @@
++#ifndef __ASM_AVR32_ELF_H
++#define __ASM_AVR32_ELF_H
++
++/* AVR32 relocation numbers */
++#define R_AVR32_NONE 0
++#define R_AVR32_32 1
++#define R_AVR32_16 2
++#define R_AVR32_8 3
++#define R_AVR32_32_PCREL 4
++#define R_AVR32_16_PCREL 5
++#define R_AVR32_8_PCREL 6
++#define R_AVR32_DIFF32 7
++#define R_AVR32_DIFF16 8
++#define R_AVR32_DIFF8 9
++#define R_AVR32_GOT32 10
++#define R_AVR32_GOT16 11
++#define R_AVR32_GOT8 12
++#define R_AVR32_21S 13
++#define R_AVR32_16U 14
++#define R_AVR32_16S 15
++#define R_AVR32_8S 16
++#define R_AVR32_8S_EXT 17
++#define R_AVR32_22H_PCREL 18
++#define R_AVR32_18W_PCREL 19
++#define R_AVR32_16B_PCREL 20
++#define R_AVR32_16N_PCREL 21
++#define R_AVR32_14UW_PCREL 22
++#define R_AVR32_11H_PCREL 23
++#define R_AVR32_10UW_PCREL 24
++#define R_AVR32_9H_PCREL 25
++#define R_AVR32_9UW_PCREL 26
++#define R_AVR32_HI16 27
++#define R_AVR32_LO16 28
++#define R_AVR32_GOTPC 29
++#define R_AVR32_GOTCALL 30
++#define R_AVR32_LDA_GOT 31
++#define R_AVR32_GOT21S 32
++#define R_AVR32_GOT18SW 33
++#define R_AVR32_GOT16S 34
++#define R_AVR32_GOT7UW 35
++#define R_AVR32_32_CPENT 36
++#define R_AVR32_CPCALL 37
++#define R_AVR32_16_CP 38
++#define R_AVR32_9W_CP 39
++#define R_AVR32_RELATIVE 40
++#define R_AVR32_GLOB_DAT 41
++#define R_AVR32_JMP_SLOT 42
++#define R_AVR32_ALIGN 43
++
++/*
++ * ELF register definitions..
++ */
++
++#include <asm/ptrace.h>
++#include <asm/user.h>
++
++typedef unsigned long elf_greg_t;
++
++#define ELF_NGREG (sizeof (struct pt_regs) / sizeof (elf_greg_t))
++typedef elf_greg_t elf_gregset_t[ELF_NGREG];
++
++typedef struct user_fpu_struct elf_fpregset_t;
++
++/*
++ * This is used to ensure we don't load something for the wrong architecture.
++ */
++#define elf_check_arch(x) ( (x)->e_machine == EM_AVR32 )
++
++/*
++ * These are used to set parameters in the core dumps.
++ */
++#define ELF_CLASS ELFCLASS32
++#ifdef __LITTLE_ENDIAN__
++#define ELF_DATA ELFDATA2LSB
++#else
++#define ELF_DATA ELFDATA2MSB
++#endif
++#define ELF_ARCH EM_AVR32
++
++#define USE_ELF_CORE_DUMP
++#define ELF_EXEC_PAGESIZE 4096
++
++/* 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)
++
++#ifdef __KERNEL__
++#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
++#endif
++
++#endif /* __ASM_AVR32_ELF_H */
+diff --git a/include/asm-avr32/emergency-restart.h b/include/asm-avr32/emergency-restart.h
+new file mode 100644
+index 0000000..3e7e014
+--- /dev/null
++++ b/include/asm-avr32/emergency-restart.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_EMERGENCY_RESTART_H
++#define __ASM_AVR32_EMERGENCY_RESTART_H
++
++#include <asm-generic/emergency-restart.h>
++
++#endif /* __ASM_AVR32_EMERGENCY_RESTART_H */
+diff --git a/include/asm-avr32/errno.h b/include/asm-avr32/errno.h
+new file mode 100644
+index 0000000..558a724
+--- /dev/null
++++ b/include/asm-avr32/errno.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_ERRNO_H
++#define __ASM_AVR32_ERRNO_H
++
++#include <asm-generic/errno.h>
++
++#endif /* __ASM_AVR32_ERRNO_H */
+diff --git a/include/asm-avr32/fcntl.h b/include/asm-avr32/fcntl.h
+new file mode 100644
+index 0000000..14c0c44
+--- /dev/null
++++ b/include/asm-avr32/fcntl.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_FCNTL_H
++#define __ASM_AVR32_FCNTL_H
++
++#include <asm-generic/fcntl.h>
++
++#endif /* __ASM_AVR32_FCNTL_H */
+diff --git a/include/asm-avr32/futex.h b/include/asm-avr32/futex.h
+new file mode 100644
+index 0000000..10419f1
+--- /dev/null
++++ b/include/asm-avr32/futex.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_FUTEX_H
++#define __ASM_AVR32_FUTEX_H
++
++#include <asm-generic/futex.h>
++
++#endif /* __ASM_AVR32_FUTEX_H */
+diff --git a/include/asm-avr32/hardirq.h b/include/asm-avr32/hardirq.h
+new file mode 100644
+index 0000000..2673543
+--- /dev/null
++++ b/include/asm-avr32/hardirq.h
+@@ -0,0 +1,34 @@
++#ifndef __ASM_AVR32_HARDIRQ_H
++#define __ASM_AVR32_HARDIRQ_H
++
++#include <linux/threads.h>
++#include <asm/irq.h>
++
++#ifndef __ASSEMBLY__
++
++#include <linux/cache.h>
++
++/* entry.S is sensitive to the offsets of these fields */
++typedef struct {
++ unsigned int __softirq_pending;
++} ____cacheline_aligned irq_cpustat_t;
++
++void ack_bad_irq(unsigned int irq);
++
++/* Standard mappings for irq_cpustat_t above */
++#include <linux/irq_cpustat.h>
++
++#endif /* __ASSEMBLY__ */
++
++#define HARDIRQ_BITS 12
++
++/*
++ * The hardirq mask has to be large enough to have
++ * space for potentially all IRQ sources in the system
++ * nesting on a single CPU:
++ */
++#if (1 << HARDIRQ_BITS) < NR_IRQS
++# error HARDIRQ_BITS is too low!
++#endif
++
++#endif /* __ASM_AVR32_HARDIRQ_H */
+diff --git a/include/asm-avr32/hw_irq.h b/include/asm-avr32/hw_irq.h
+new file mode 100644
+index 0000000..218b0a6
+--- /dev/null
++++ b/include/asm-avr32/hw_irq.h
+@@ -0,0 +1,9 @@
++#ifndef __ASM_AVR32_HW_IRQ_H
++#define __ASM_AVR32_HW_IRQ_H
++
++static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
++{
++ /* Nothing to do */
++}
++
++#endif /* __ASM_AVR32_HW_IRQ_H */
+diff --git a/include/asm-avr32/intc.h b/include/asm-avr32/intc.h
+new file mode 100644
+index 0000000..1ac9ca7
+--- /dev/null
++++ b/include/asm-avr32/intc.h
+@@ -0,0 +1,128 @@
++#ifndef __ASM_AVR32_INTC_H
++#define __ASM_AVR32_INTC_H
++
++#include <linux/sysdev.h>
++#include <linux/interrupt.h>
++
++struct irq_controller;
++struct irqaction;
++struct pt_regs;
++
++struct platform_device;
++
++/* Information about the internal interrupt controller */
++struct intc_device {
++ /* ioremapped address of configuration block */
++ void __iomem *regs;
++
++ /* the physical device */
++ struct platform_device *pdev;
++
++ /* Number of interrupt lines per group. */
++ unsigned int irqs_per_group;
++
++ /* The highest group ID + 1 */
++ unsigned int nr_groups;
++
++ /*
++ * Bitfield indicating which groups are actually in use. The
++ * size of the array is
++ * ceil(group_max / (8 * sizeof(unsigned int))).
++ */
++ unsigned int group_mask[];
++};
++
++struct irq_controller_class {
++ /*
++ * A short name identifying this kind of controller.
++ */
++ const char *typename;
++ /*
++ * Handle the IRQ. Must do any necessary acking and masking.
++ */
++ irqreturn_t (*handle)(int irq, void *dev_id, struct pt_regs *regs);
++ /*
++ * Register a new IRQ handler.
++ */
++ int (*setup)(struct irq_controller *ctrl, unsigned int irq,
++ struct irqaction *action);
++ /*
++ * Unregister a IRQ handler.
++ */
++ void (*free)(struct irq_controller *ctrl, unsigned int irq,
++ void *dev_id);
++ /*
++ * Mask the IRQ in the interrupt controller.
++ */
++ void (*mask)(struct irq_controller *ctrl, unsigned int irq);
++ /*
++ * Unmask the IRQ in the interrupt controller.
++ */
++ void (*unmask)(struct irq_controller *ctrl, unsigned int irq);
++ /*
++ * Set the type of the IRQ. See below for possible types.
++ * Return -EINVAL if a given type is not supported
++ */
++ int (*set_type)(struct irq_controller *ctrl, unsigned int irq,
++ unsigned int type);
++ /*
++ * Return the IRQ type currently set
++ */
++ unsigned int (*get_type)(struct irq_controller *ctrl, unsigned int irq);
++};
++
++struct irq_controller {
++ struct irq_controller_class *class;
++ unsigned int irq_group;
++ unsigned int first_irq;
++ unsigned int nr_irqs;
++ struct list_head list;
++};
++
++struct intc_group_desc {
++ struct irq_controller *ctrl;
++ irqreturn_t (*handle)(int, void *, struct pt_regs *);
++ unsigned long flags;
++ void *dev_id;
++ const char *devname;
++};
++
++/*
++ * The internal interrupt controller. Defined in board/part-specific
++ * devices.c.
++ * TODO: Should probably be defined per-cpu.
++ */
++extern struct intc_device intc;
++
++extern int request_internal_irq(unsigned int irq,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname, void *dev_id);
++extern void free_internal_irq(unsigned int irq);
++
++/* Only used by time_init() */
++extern int setup_internal_irq(unsigned int irq, struct intc_group_desc *desc);
++
++/*
++ * Set interrupt priority for a given group. `group' can be found by
++ * using irq_to_group(irq). Priority can be from 0 (lowest) to 3
++ * (highest). Higher-priority interrupts will preempt lower-priority
++ * interrupts (unless interrupts are masked globally).
++ *
++ * This function does not check for conflicts within a group.
++ */
++extern int intc_set_priority(unsigned int group,
++ unsigned int priority);
++
++/*
++ * Returns a bitmask of pending interrupts in a group.
++ */
++extern unsigned long intc_get_pending(unsigned int group);
++
++/*
++ * Register a new external interrupt controller. Returns the first
++ * external IRQ number that is assigned to the new controller.
++ */
++extern int intc_register_controller(struct irq_controller *ctrl);
++
++#endif /* __ASM_AVR32_INTC_H */
+diff --git a/include/asm-avr32/io.h b/include/asm-avr32/io.h
+new file mode 100644
+index 0000000..eec4750
+--- /dev/null
++++ b/include/asm-avr32/io.h
+@@ -0,0 +1,286 @@
++#ifndef __ASM_AVR32_IO_H
++#define __ASM_AVR32_IO_H
++
++#include <linux/string.h>
++
++#ifdef __KERNEL__
++
++#include <asm/addrspace.h>
++#include <asm/byteorder.h>
++
++/* virt_to_phys will only work when address is in P1 or P2 */
++static __inline__ unsigned long virt_to_phys(volatile void *address)
++{
++ return PHYSADDR(address);
++}
++
++static __inline__ void * phys_to_virt(unsigned long address)
++{
++ return (void *)P1SEGADDR(address);
++}
++
++#define cached_to_phys(addr) ((unsigned long)PHYSADDR(addr))
++#define uncached_to_phys(addr) ((unsigned long)PHYSADDR(addr))
++#define phys_to_cached(addr) ((void *)P1SEGADDR(addr))
++#define phys_to_uncached(addr) ((void *)P2SEGADDR(addr))
++
++/*
++ * Generic IO read/write. These perform native-endian accesses. Note
++ * that some architectures will want to re-define __raw_{read,write}w.
++ */
++extern void __raw_writesb(unsigned int addr, const void *data, int bytelen);
++extern void __raw_writesw(unsigned int addr, const void *data, int wordlen);
++extern void __raw_writesl(unsigned int addr, const void *data, int longlen);
++
++extern void __raw_readsb(unsigned int addr, void *data, int bytelen);
++extern void __raw_readsw(unsigned int addr, void *data, int wordlen);
++extern void __raw_readsl(unsigned int addr, void *data, int longlen);
++
++static inline void writeb(unsigned char b, volatile void __iomem *addr)
++{
++ *(volatile unsigned char __force *)addr = b;
++}
++static inline void writew(unsigned short b, volatile void __iomem *addr)
++{
++ *(volatile unsigned short __force *)addr = b;
++}
++static inline void writel(unsigned int b, volatile void __iomem *addr)
++{
++ *(volatile unsigned int __force *)addr = b;
++}
++#define __raw_writeb writeb
++#define __raw_writew writew
++#define __raw_writel writel
++
++static inline unsigned char readb(const volatile void __iomem *addr)
++{
++ return *(const volatile unsigned char __force *)addr;
++}
++static inline unsigned short readw(const volatile void __iomem *addr)
++{
++ return *(const volatile unsigned short __force *)addr;
++}
++static inline unsigned int readl(const volatile void __iomem *addr)
++{
++ return *(const volatile unsigned int __force *)addr;
++}
++#define __raw_readb readb
++#define __raw_readw readw
++#define __raw_readl readl
++
++#define writesb(p, d, l) __raw_writesb((unsigned int)p, d, l)
++#define writesw(p, d, l) __raw_writesw((unsigned int)p, d, l)
++#define writesl(p, d, l) __raw_writesl((unsigned int)p, d, l)
++
++#define readsb(p, d, l) __raw_readsb((unsigned int)p, d, l)
++#define readsw(p, d, l) __raw_readsw((unsigned int)p, d, l)
++#define readsl(p, d, l) __raw_readsl((unsigned int)p, d, l)
++
++
++/*
++ * io{read,write}{8,16,32} macros in both le (for PCI style consumers) and native be
++ */
++#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 ioread16be(p) ({ unsigned int __v = be16_to_cpu(__raw_readw(p)); __v; })
++
++#define ioread32(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
++#define ioread32be(p) ({ unsigned int __v = be32_to_cpu(__raw_readl(p)); __v; })
++
++#define iowrite8(v,p) __raw_writeb(v, p)
++
++#define iowrite16(v,p) __raw_writew(cpu_to_le16(v), p)
++#define iowrite16be(v,p) __raw_writew(cpu_to_be16(v), p)
++
++#define iowrite32(v,p) __raw_writel(cpu_to_le32(v), p)
++#define iowrite32be(v,p) __raw_writel(cpu_to_be32(v), p)
++
++#define ioread8_rep(p,d,c) __raw_readsb(p,d,c)
++#define ioread16_rep(p,d,c) __raw_readsw(p,d,c)
++#define ioread32_rep(p,d,c) __raw_readsl(p,d,c)
++
++#define iowrite8_rep(p,s,c) __raw_writesb(p,s,c)
++#define iowrite16_rep(p,s,c) __raw_writesw(p,s,c)
++#define iowrite32_rep(p,s,c) __raw_writesl(p,s,c)
++
++#endif
++
++
++/*
++ * These two are only here because ALSA _thinks_ it needs them...
++ */
++static inline void memcpy_fromio(void * to, const volatile void __iomem *from,
++ unsigned long count)
++{
++ char *p = to;
++ while (count) {
++ count--;
++ *p = readb(from);
++ p++;
++ from++;
++ }
++}
++
++static inline void memcpy_toio(volatile void __iomem *to, const void * from,
++ unsigned long count)
++{
++ const char *p = from;
++ while (count) {
++ count--;
++ writeb(*p, to);
++ p++;
++ to++;
++ }
++}
++
++static inline void memset_io(volatile void __iomem *addr, unsigned char val,
++ unsigned long count)
++{
++ memset((void __force *)addr, val, count);
++}
++
++/*
++ * Bad read/write accesses...
++ */
++extern void __readwrite_bug(const char *fn);
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++/* Convert I/O port address to virtual address */
++#define __io(p) ((void __iomem *)phys_to_uncached(p))
++
++/*
++ * IO port access primitives
++ * -------------------------
++ *
++ * The AVR32 doesn't have special IO access instructions; all IO is memory
++ * mapped. Note that these are defined to perform little endian accesses
++ * 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.
++ *
++ * The machine specific io.h include defines __io to translate an "IO"
++ * address to a memory address.
++ *
++ * Note that we prevent GCC re-ordering or caching values in expressions
++ * by introducing sequence points into the in*() definitions. Note that
++ * __raw_* do not guarantee this behaviour.
++ *
++ * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
++ */
++#define outb(v, p) __raw_writeb(v, __io(p))
++#define outw(v, p) __raw_writew(cpu_to_le16(v), __io(p))
++#define outl(v, p) __raw_writel(cpu_to_le32(v), __io(p))
++
++#define inb(p) __raw_readb(__io(p))
++#define inw(p) le16_to_cpu(__raw_readw(__io(p)))
++#define inl(p) le32_to_cpu(__raw_readl(__io(p)))
++
++static inline void __outsb(unsigned long port, void *addr, unsigned int count)
++{
++ while (count--) {
++ outb(*(u8 *)addr, port);
++ addr++;
++ }
++}
++
++static inline void __insb(unsigned long port, void *addr, unsigned int count)
++{
++ while (count--) {
++ *(u8 *)addr = inb(port);
++ addr++;
++ }
++}
++
++static inline void __outsw(unsigned long port, void *addr, unsigned int count)
++{
++ while (count--) {
++ outw(*(u16 *)addr, port);
++ addr += 2;
++ }
++}
++
++static inline void __insw(unsigned long port, void *addr, unsigned int count)
++{
++ while (count--) {
++ *(u16 *)addr = inw(port);
++ addr += 2;
++ }
++}
++
++static inline void __outsl(unsigned long port, void *addr, unsigned int count)
++{
++ while (count--) {
++ outl(*(u32 *)addr, port);
++ addr += 4;
++ }
++}
++
++static inline void __insl(unsigned long port, void *addr, unsigned int count)
++{
++ while (count--) {
++ *(u32 *)addr = inl(port);
++ addr += 4;
++ }
++}
++
++#define outsb(port, addr, count) __outsb(port, addr, count)
++#define insb(port, addr, count) __insb(port, addr, count)
++#define outsw(port, addr, count) __outsw(port, addr, count)
++#define insw(port, addr, count) __insw(port, addr, count)
++#define outsl(port, addr, count) __outsl(port, addr, count)
++#define insl(port, addr, count) __insl(port, addr, count)
++
++extern void __iomem *__ioremap(unsigned long offset, size_t size,
++ unsigned long flags);
++extern void __iounmap(void __iomem *addr);
++
++/*
++ * ioremap - map bus memory into CPU space
++ * @offset bus address of the memory
++ * @size size of the resource to map
++ *
++ * ioremap performs a platform specific sequence of operations to make
++ * bus memory CPU accessible via the readb/.../writel functions and
++ * the other mmio helpers. The returned address is not guaranteed to
++ * be usable directly as a virtual address.
++ */
++#define ioremap(offset, size) \
++ __ioremap((offset), (size), 0)
++
++#define iounmap(addr) \
++ __iounmap(addr)
++
++#define cached(addr) P1SEGADDR(addr)
++#define uncached(addr) P2SEGADDR(addr)
++
++#define virt_to_bus virt_to_phys
++#define bus_to_virt phys_to_virt
++#define page_to_bus page_to_phys
++#define bus_to_page phys_to_page
++
++#define dma_cache_wback_inv(_start, _size) \
++ flush_dcache_region(_start, _size)
++#define dma_cache_inv(_start, _size) \
++ invalidate_dcache_region(_start, _size)
++#define dma_cache_wback(_start, _size) \
++ clean_dcache_region(_start, _size)
++
++/*
++ * 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 /* __ASM_AVR32_IO_H */
+diff --git a/include/asm-avr32/ioctl.h b/include/asm-avr32/ioctl.h
+new file mode 100644
+index 0000000..c8472c1
+--- /dev/null
++++ b/include/asm-avr32/ioctl.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_IOCTL_H
++#define __ASM_AVR32_IOCTL_H
++
++#include <asm-generic/ioctl.h>
++
++#endif /* __ASM_AVR32_IOCTL_H */
+diff --git a/include/asm-avr32/ioctls.h b/include/asm-avr32/ioctls.h
+new file mode 100644
+index 0000000..0500426
+--- /dev/null
++++ b/include/asm-avr32/ioctls.h
+@@ -0,0 +1,83 @@
++#ifndef __ASM_AVR32_IOCTLS_H
++#define __ASM_AVR32_IOCTLS_H
++
++#include <asm/ioctl.h>
++
++/* 0x54 is just a magic number to make these relatively unique ('T') */
++
++#define TCGETS 0x5401
++#define TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
++#define TCSETSW 0x5403
++#define TCSETSF 0x5404
++#define TCGETA 0x5405
++#define TCSETA 0x5406
++#define TCSETAW 0x5407
++#define TCSETAF 0x5408
++#define TCSBRK 0x5409
++#define TCXONC 0x540A
++#define TCFLSH 0x540B
++#define TIOCEXCL 0x540C
++#define TIOCNXCL 0x540D
++#define TIOCSCTTY 0x540E
++#define TIOCGPGRP 0x540F
++#define TIOCSPGRP 0x5410
++#define TIOCOUTQ 0x5411
++#define TIOCSTI 0x5412
++#define TIOCGWINSZ 0x5413
++#define TIOCSWINSZ 0x5414
++#define TIOCMGET 0x5415
++#define TIOCMBIS 0x5416
++#define TIOCMBIC 0x5417
++#define TIOCMSET 0x5418
++#define TIOCGSOFTCAR 0x5419
++#define TIOCSSOFTCAR 0x541A
++#define FIONREAD 0x541B
++#define TIOCINQ FIONREAD
++#define TIOCLINUX 0x541C
++#define TIOCCONS 0x541D
++#define TIOCGSERIAL 0x541E
++#define TIOCSSERIAL 0x541F
++#define TIOCPKT 0x5420
++#define FIONBIO 0x5421
++#define TIOCNOTTY 0x5422
++#define TIOCSETD 0x5423
++#define TIOCGETD 0x5424
++#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
++/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */
++#define TIOCSBRK 0x5427 /* BSD compatibility */
++#define TIOCCBRK 0x5428 /* BSD compatibility */
++#define TIOCGSID 0x5429 /* 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 FIONCLEX 0x5450
++#define FIOCLEX 0x5451
++#define FIOASYNC 0x5452
++#define TIOCSERCONFIG 0x5453
++#define TIOCSERGWILD 0x5454
++#define TIOCSERSWILD 0x5455
++#define TIOCGLCKTRMIOS 0x5456
++#define TIOCSLCKTRMIOS 0x5457
++#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
++#define TIOCSERGETLSR 0x5459 /* Get line status register */
++#define TIOCSERGETMULTI 0x545A /* Get multiport config */
++#define TIOCSERSETMULTI 0x545B /* Set multiport config */
++
++#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
++#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
++#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
++#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
++#define FIOQSIZE 0x5460
++
++/* Used for packet mode */
++#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 TIOCSER_TEMT 0x01 /* Transmitter physically empty */
++
++#endif /* __ASM_AVR32_IOCTLS_H */
+diff --git a/include/asm-avr32/ipcbuf.h b/include/asm-avr32/ipcbuf.h
+new file mode 100644
+index 0000000..1552c96
+--- /dev/null
++++ b/include/asm-avr32/ipcbuf.h
+@@ -0,0 +1,29 @@
++#ifndef __ASM_AVR32_IPCBUF_H
++#define __ASM_AVR32_IPCBUF_H
++
++/*
++* The user_ipc_perm structure for AVR32 architecture.
++* Note extra padding because this structure is passed back and forth
++* between kernel and user space.
++*
++* Pad space is left for:
++* - 32-bit mode_t and seq
++* - 2 miscellaneous 32-bit values
++*/
++
++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 short __pad1;
++ unsigned short seq;
++ unsigned short __pad2;
++ unsigned long __unused1;
++ unsigned long __unused2;
++};
++
++#endif /* __ASM_AVR32_IPCBUF_H */
+diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
+new file mode 100644
+index 0000000..f7e7257
+--- /dev/null
++++ b/include/asm-avr32/irq.h
+@@ -0,0 +1,10 @@
++#ifndef __ASM_AVR32_IRQ_H
++#define __ASM_AVR32_IRQ_H
++
++#define NR_INTERNAL_IRQS 64
++#define NR_EXTERNAL_IRQS 64
++#define NR_IRQS (NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS)
++
++#define irq_canonicalize(i) (i)
++
++#endif /* __ASM_AVR32_IOCTLS_H */
+diff --git a/include/asm-avr32/irq_regs.h b/include/asm-avr32/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-avr32/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-avr32/irqflags.h b/include/asm-avr32/irqflags.h
+new file mode 100644
+index 0000000..93570da
+--- /dev/null
++++ b/include/asm-avr32/irqflags.h
+@@ -0,0 +1,68 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_IRQFLAGS_H
++#define __ASM_AVR32_IRQFLAGS_H
++
++#include <asm/sysreg.h>
++
++static inline unsigned long __raw_local_save_flags(void)
++{
++ return sysreg_read(SR);
++}
++
++#define raw_local_save_flags(x) \
++ do { (x) = __raw_local_save_flags(); } while (0)
++
++/*
++ * This will restore ALL status register flags, not only the interrupt
++ * mask flag.
++ *
++ * The empty asm statement informs the compiler of this fact while
++ * also serving as a barrier.
++ */
++static inline void raw_local_irq_restore(unsigned long flags)
++{
++ sysreg_write(SR, flags);
++ asm volatile("" : : : "memory", "cc");
++}
++
++static inline void raw_local_irq_disable(void)
++{
++ asm volatile("ssrf %0" : : "n"(SYSREG_GM_OFFSET) : "memory");
++}
++
++static inline void raw_local_irq_enable(void)
++{
++ asm volatile("csrf %0" : : "n"(SYSREG_GM_OFFSET) : "memory");
++}
++
++static inline int raw_irqs_disabled_flags(unsigned long flags)
++{
++ return (flags & SYSREG_BIT(GM)) != 0;
++}
++
++static inline int raw_irqs_disabled(void)
++{
++ unsigned long flags = __raw_local_save_flags();
++
++ return raw_irqs_disabled_flags(flags);
++}
++
++static inline unsigned long __raw_local_irq_save(void)
++{
++ unsigned long flags = __raw_local_save_flags();
++
++ raw_local_irq_disable();
++
++ return flags;
++}
++
++#define raw_local_irq_save(flags) \
++ do { (flags) = __raw_local_irq_save(); } while (0)
++
++#endif /* __ASM_AVR32_IRQFLAGS_H */
+diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
+new file mode 100644
+index 0000000..f583b64
+--- /dev/null
++++ b/include/asm-avr32/kdebug.h
+@@ -0,0 +1,38 @@
++#ifndef __ASM_AVR32_KDEBUG_H
++#define __ASM_AVR32_KDEBUG_H
++
++#include <linux/notifier.h>
++
++struct pt_regs;
++
++struct die_args {
++ struct pt_regs *regs;
++ int trapnr;
++};
++
++int register_die_notifier(struct notifier_block *nb);
++int unregister_die_notifier(struct notifier_block *nb);
++int register_page_fault_notifier(struct notifier_block *nb);
++int unregister_page_fault_notifier(struct notifier_block *nb);
++extern struct atomic_notifier_head avr32_die_chain;
++
++/* Grossly misnamed. */
++enum die_val {
++ DIE_FAULT,
++ DIE_BREAKPOINT,
++ DIE_SSTEP,
++ DIE_PAGE_FAULT,
++};
++
++static inline int notify_die(enum die_val val, struct pt_regs *regs,
++ int trap, int sig)
++{
++ struct die_args args = {
++ .regs = regs,
++ .trapnr = trap,
++ };
++
++ return atomic_notifier_call_chain(&avr32_die_chain, val, &args);
++}
++
++#endif /* __ASM_AVR32_KDEBUG_H */
+diff --git a/include/asm-avr32/kmap_types.h b/include/asm-avr32/kmap_types.h
+new file mode 100644
+index 0000000..b7f5c68
+--- /dev/null
++++ b/include/asm-avr32/kmap_types.h
+@@ -0,0 +1,30 @@
++#ifndef __ASM_AVR32_KMAP_TYPES_H
++#define __ASM_AVR32_KMAP_TYPES_H
++
++#ifdef CONFIG_DEBUG_HIGHMEM
++# define D(n) __KM_FENCE_##n ,
++#else
++# define D(n)
++#endif
++
++enum km_type {
++D(0) KM_BOUNCE_READ,
++D(1) KM_SKB_SUNRPC_DATA,
++D(2) KM_SKB_DATA_SOFTIRQ,
++D(3) KM_USER0,
++D(4) KM_USER1,
++D(5) KM_BIO_SRC_IRQ,
++D(6) KM_BIO_DST_IRQ,
++D(7) KM_PTE0,
++D(8) KM_PTE1,
++D(9) KM_PTE2,
++D(10) KM_IRQ0,
++D(11) KM_IRQ1,
++D(12) KM_SOFTIRQ0,
++D(13) KM_SOFTIRQ1,
++D(14) KM_TYPE_NR
++};
++
++#undef D
++
++#endif /* __ASM_AVR32_KMAP_TYPES_H */
+diff --git a/include/asm-avr32/kprobes.h b/include/asm-avr32/kprobes.h
+new file mode 100644
+index 0000000..09a5cbe
+--- /dev/null
++++ b/include/asm-avr32/kprobes.h
+@@ -0,0 +1,34 @@
++/*
++ * Kernel Probes (KProbes)
++ *
++ * Copyright (C) 2005-2006 Atmel Corporation
++ * Copyright (C) IBM Corporation, 2002, 2004
++ *
++ * 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 __ASM_AVR32_KPROBES_H
++#define __ASM_AVR32_KPROBES_H
++
++#include <linux/types.h>
++
++typedef u16 kprobe_opcode_t;
++#define BREAKPOINT_INSTRUCTION 0xd673 /* breakpoint */
++#define MAX_INSN_SIZE 2
++
++#define ARCH_INACTIVE_KPROBE_COUNT 1
++
++#define arch_remove_kprobe(p) do { } while (0)
++
++/* Architecture specific copy of original instruction */
++struct arch_specific_insn {
++ kprobe_opcode_t insn[MAX_INSN_SIZE];
++};
++
++extern int kprobe_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data);
++
++#define flush_insn_slot(p) do { } while (0)
++
++#endif /* __ASM_AVR32_KPROBES_H */
+diff --git a/include/asm-avr32/linkage.h b/include/asm-avr32/linkage.h
+new file mode 100644
+index 0000000..f7b285e
+--- /dev/null
++++ b/include/asm-avr32/linkage.h
+@@ -0,0 +1,7 @@
++#ifndef __ASM_LINKAGE_H
++#define __ASM_LINKAGE_H
++
++#define __ALIGN .balign 2
++#define __ALIGN_STR ".balign 2"
++
++#endif /* __ASM_LINKAGE_H */
+diff --git a/include/asm-avr32/local.h b/include/asm-avr32/local.h
+new file mode 100644
+index 0000000..1c16196
+--- /dev/null
++++ b/include/asm-avr32/local.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_LOCAL_H
++#define __ASM_AVR32_LOCAL_H
++
++#include <asm-generic/local.h>
++
++#endif /* __ASM_AVR32_LOCAL_H */
+diff --git a/include/asm-avr32/mach/serial_at91.h b/include/asm-avr32/mach/serial_at91.h
+new file mode 100644
+index 0000000..55b317a
+--- /dev/null
++++ b/include/asm-avr32/mach/serial_at91.h
+@@ -0,0 +1,33 @@
++/*
++ * linux/include/asm-arm/mach/serial_at91.h
++ *
++ * Based on serial_sa1100.h by Nicolas Pitre
++ *
++ * Copyright (C) 2002 ATMEL Rousset
++ *
++ * Low level machine dependent UART functions.
++ */
++
++struct uart_port;
++
++/*
++ * This is a temporary structure for registering these
++ * functions; it is intended to be discarded after boot.
++ */
++struct atmel_port_fns {
++ void (*set_mctrl)(struct uart_port *, u_int);
++ u_int (*get_mctrl)(struct uart_port *);
++ void (*enable_ms)(struct uart_port *);
++ void (*pm)(struct uart_port *, u_int, u_int);
++ int (*set_wake)(struct uart_port *, u_int);
++ int (*open)(struct uart_port *);
++ void (*close)(struct uart_port *);
++};
++
++#if defined(CONFIG_SERIAL_ATMEL)
++void atmel_register_uart_fns(struct atmel_port_fns *fns);
++#else
++#define atmel_register_uart_fns(fns) do { } while (0)
++#endif
++
++
+diff --git a/include/asm-avr32/mman.h b/include/asm-avr32/mman.h
+new file mode 100644
+index 0000000..648f91e
+--- /dev/null
++++ b/include/asm-avr32/mman.h
+@@ -0,0 +1,17 @@
++#ifndef __ASM_AVR32_MMAN_H__
++#define __ASM_AVR32_MMAN_H__
++
++#include <asm-generic/mman.h>
++
++#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
++#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
++#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
++#define MAP_LOCKED 0x2000 /* pages are locked */
++#define MAP_NORESERVE 0x4000 /* don't check for reservations */
++#define MAP_POPULATE 0x8000 /* populate (prefault) page tables */
++#define MAP_NONBLOCK 0x10000 /* do not block on IO */
++
++#define MCL_CURRENT 1 /* lock all current mappings */
++#define MCL_FUTURE 2 /* lock all future mappings */
++
++#endif /* __ASM_AVR32_MMAN_H__ */
+diff --git a/include/asm-avr32/mmu.h b/include/asm-avr32/mmu.h
+new file mode 100644
+index 0000000..60c2d26
+--- /dev/null
++++ b/include/asm-avr32/mmu.h
+@@ -0,0 +1,10 @@
++#ifndef __ASM_AVR32_MMU_H
++#define __ASM_AVR32_MMU_H
++
++/* Default "unsigned long" context */
++typedef unsigned long mm_context_t;
++
++#define MMU_ITLB_ENTRIES 64
++#define MMU_DTLB_ENTRIES 64
++
++#endif /* __ASM_AVR32_MMU_H */
+diff --git a/include/asm-avr32/mmu_context.h b/include/asm-avr32/mmu_context.h
+new file mode 100644
+index 0000000..31add1a
+--- /dev/null
++++ b/include/asm-avr32/mmu_context.h
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * ASID handling taken from SH implementation.
++ * Copyright (C) 1999 Niibe Yutaka
++ * Copyright (C) 2003 Paul Mundt
++ *
++ * 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 __ASM_AVR32_MMU_CONTEXT_H
++#define __ASM_AVR32_MMU_CONTEXT_H
++
++#include <asm/tlbflush.h>
++#include <asm/pgalloc.h>
++#include <asm/sysreg.h>
++
++/*
++ * The MMU "context" consists of two things:
++ * (a) TLB cache version
++ * (b) ASID (Address Space IDentifier)
++ */
++#define MMU_CONTEXT_ASID_MASK 0x000000ff
++#define MMU_CONTEXT_VERSION_MASK 0xffffff00
++#define MMU_CONTEXT_FIRST_VERSION 0x00000100
++#define NO_CONTEXT 0
++
++#define MMU_NO_ASID 0x100
++
++/* Virtual Page Number mask */
++#define MMU_VPN_MASK 0xfffff000
++
++/* Cache of MMU context last used */
++extern unsigned long mmu_context_cache;
++
++/*
++ * Get MMU context if needed
++ */
++static inline void
++get_mmu_context(struct mm_struct *mm)
++{
++ unsigned long mc = mmu_context_cache;
++
++ if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
++ /* It's up to date, do nothing */
++ return;
++
++ /* It's old, we need to get new context with new version */
++ mc = ++mmu_context_cache;
++ if (!(mc & MMU_CONTEXT_ASID_MASK)) {
++ /*
++ * We have exhausted all ASIDs of this version.
++ * Flush the TLB and start new cycle.
++ */
++ flush_tlb_all();
++ /*
++ * Fix version. Note that we avoid version #0
++ * to distinguish NO_CONTEXT.
++ */
++ if (!mc)
++ mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
++ }
++ mm->context = mc;
++}
++
++/*
++ * Initialize the context related info for a new mm_struct
++ * instance.
++ */
++static inline int init_new_context(struct task_struct *tsk,
++ struct mm_struct *mm)
++{
++ mm->context = NO_CONTEXT;
++ return 0;
++}
++
++/*
++ * Destroy context related info for an mm_struct that is about
++ * to be put to rest.
++ */
++static inline void destroy_context(struct mm_struct *mm)
++{
++ /* Do nothing */
++}
++
++static inline void set_asid(unsigned long asid)
++{
++ /* XXX: We're destroying TLBEHI[8:31] */
++ sysreg_write(TLBEHI, asid & MMU_CONTEXT_ASID_MASK);
++ cpu_sync_pipeline();
++}
++
++static inline unsigned long get_asid(void)
++{
++ unsigned long asid;
++
++ asid = sysreg_read(TLBEHI);
++ return asid & MMU_CONTEXT_ASID_MASK;
++}
++
++static inline void activate_context(struct mm_struct *mm)
++{
++ get_mmu_context(mm);
++ set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
++}
++
++static inline void switch_mm(struct mm_struct *prev,
++ struct mm_struct *next,
++ struct task_struct *tsk)
++{
++ if (likely(prev != next)) {
++ unsigned long __pgdir = (unsigned long)next->pgd;
++
++ sysreg_write(PTBR, __pgdir);
++ activate_context(next);
++ }
++}
++
++#define deactivate_mm(tsk,mm) do { } while(0)
++
++#define activate_mm(prev, next) switch_mm((prev), (next), NULL)
++
++static inline void
++enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
++{
++}
++
++
++static inline void enable_mmu(void)
++{
++ sysreg_write(MMUCR, (SYSREG_BIT(MMUCR_S)
++ | SYSREG_BIT(E)
++ | SYSREG_BIT(MMUCR_I)));
++ nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
++
++ if (mmu_context_cache == NO_CONTEXT)
++ mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
++
++ set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
++}
++
++static inline void disable_mmu(void)
++{
++ sysreg_write(MMUCR, SYSREG_BIT(MMUCR_S));
++}
++
++#endif /* __ASM_AVR32_MMU_CONTEXT_H */
+diff --git a/include/asm-avr32/module.h b/include/asm-avr32/module.h
+new file mode 100644
+index 0000000..4514445
+--- /dev/null
++++ b/include/asm-avr32/module.h
+@@ -0,0 +1,28 @@
++#ifndef __ASM_AVR32_MODULE_H
++#define __ASM_AVR32_MODULE_H
++
++struct mod_arch_syminfo {
++ unsigned long got_offset;
++ int got_initialized;
++};
++
++struct mod_arch_specific {
++ /* Starting offset of got in the module core memory. */
++ unsigned long got_offset;
++ /* Size of the got. */
++ unsigned long got_size;
++ /* Number of symbols in syminfo. */
++ int nsyms;
++ /* Additional symbol information (got offsets). */
++ struct mod_arch_syminfo *syminfo;
++};
++
++#define Elf_Shdr Elf32_Shdr
++#define Elf_Sym Elf32_Sym
++#define Elf_Ehdr Elf32_Ehdr
++
++#define MODULE_PROC_FAMILY "AVR32v1"
++
++#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
++
++#endif /* __ASM_AVR32_MODULE_H */
+diff --git a/include/asm-avr32/msgbuf.h b/include/asm-avr32/msgbuf.h
+new file mode 100644
+index 0000000..ac18bc4
+--- /dev/null
++++ b/include/asm-avr32/msgbuf.h
+@@ -0,0 +1,31 @@
++#ifndef __ASM_AVR32_MSGBUF_H
++#define __ASM_AVR32_MSGBUF_H
++
++/*
++ * The msqid64_ds structure for i386 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
++ */
++
++struct msqid64_ds {
++ struct ipc64_perm msg_perm;
++ __kernel_time_t msg_stime; /* last msgsnd time */
++ unsigned long __unused1;
++ __kernel_time_t msg_rtime; /* last msgrcv time */
++ unsigned long __unused2;
++ __kernel_time_t msg_ctime; /* last change time */
++ unsigned long __unused3;
++ 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 /* __ASM_AVR32_MSGBUF_H */
+diff --git a/include/asm-avr32/mutex.h b/include/asm-avr32/mutex.h
+new file mode 100644
+index 0000000..458c1f7
+--- /dev/null
++++ b/include/asm-avr32/mutex.h
+@@ -0,0 +1,9 @@
++/*
++ * Pull in the generic implementation for the mutex fastpath.
++ *
++ * TODO: implement optimized primitives instead, or leave the generic
++ * implementation in place, or pick the atomic_xchg() based generic
++ * implementation. (see asm-generic/mutex-xchg.h for details)
++ */
++
++#include <asm-generic/mutex-dec.h>
+diff --git a/include/asm-avr32/namei.h b/include/asm-avr32/namei.h
+new file mode 100644
+index 0000000..f0a26de
+--- /dev/null
++++ b/include/asm-avr32/namei.h
+@@ -0,0 +1,7 @@
++#ifndef __ASM_AVR32_NAMEI_H
++#define __ASM_AVR32_NAMEI_H
++
++/* This dummy routine may be changed to something useful */
++#define __emul_prefix() NULL
++
++#endif /* __ASM_AVR32_NAMEI_H */
+diff --git a/include/asm-avr32/numnodes.h b/include/asm-avr32/numnodes.h
+new file mode 100644
+index 0000000..0b864d7
+--- /dev/null
++++ b/include/asm-avr32/numnodes.h
+@@ -0,0 +1,7 @@
++#ifndef __ASM_AVR32_NUMNODES_H
++#define __ASM_AVR32_NUMNODES_H
++
++/* Max 4 nodes */
++#define NODES_SHIFT 2
++
++#endif /* __ASM_AVR32_NUMNODES_H */
+diff --git a/include/asm-avr32/ocd.h b/include/asm-avr32/ocd.h
+new file mode 100644
+index 0000000..46f7318
+--- /dev/null
++++ b/include/asm-avr32/ocd.h
+@@ -0,0 +1,78 @@
++/*
++ * AVR32 OCD Registers
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_OCD_H
++#define __ASM_AVR32_OCD_H
++
++/* Debug Registers */
++#define DBGREG_DID 0
++#define DBGREG_DC 8
++#define DBGREG_DS 16
++#define DBGREG_RWCS 28
++#define DBGREG_RWA 36
++#define DBGREG_RWD 40
++#define DBGREG_WT 44
++#define DBGREG_DTC 52
++#define DBGREG_DTSA0 56
++#define DBGREG_DTSA1 60
++#define DBGREG_DTEA0 72
++#define DBGREG_DTEA1 76
++#define DBGREG_BWC0A 88
++#define DBGREG_BWC0B 92
++#define DBGREG_BWC1A 96
++#define DBGREG_BWC1B 100
++#define DBGREG_BWC2A 104
++#define DBGREG_BWC2B 108
++#define DBGREG_BWC3A 112
++#define DBGREG_BWC3B 116
++#define DBGREG_BWA0A 120
++#define DBGREG_BWA0B 124
++#define DBGREG_BWA1A 128
++#define DBGREG_BWA1B 132
++#define DBGREG_BWA2A 136
++#define DBGREG_BWA2B 140
++#define DBGREG_BWA3A 144
++#define DBGREG_BWA3B 148
++#define DBGREG_BWD3A 153
++#define DBGREG_BWD3B 156
++
++#define DBGREG_PID 284
++
++#define SABAH_OCD 0x01
++#define SABAH_ICACHE 0x02
++#define SABAH_MEM_CACHED 0x04
++#define SABAH_MEM_UNCACHED 0x05
++
++/* Fields in the Development Control register */
++#define DC_SS_BIT 8
++
++#define DC_SS (1 << DC_SS_BIT)
++#define DC_DBE (1 << 13)
++#define DC_RID (1 << 27)
++#define DC_ORP (1 << 28)
++#define DC_MM (1 << 29)
++#define DC_RES (1 << 30)
++
++/* Fields in the Development Status register */
++#define DS_SSS (1 << 0)
++#define DS_SWB (1 << 1)
++#define DS_HWB (1 << 2)
++#define DS_BP_SHIFT 8
++#define DS_BP_MASK (0xff << DS_BP_SHIFT)
++
++#define __mfdr(addr) \
++({ \
++ register unsigned long value; \
++ asm volatile("mfdr %0, %1" : "=r"(value) : "i"(addr)); \
++ value; \
++})
++#define __mtdr(addr, value) \
++ asm volatile("mtdr %0, %1" : : "i"(addr), "r"(value))
++
++#endif /* __ASM_AVR32_OCD_H */
+diff --git a/include/asm-avr32/page.h b/include/asm-avr32/page.h
+new file mode 100644
+index 0000000..0f630b3
+--- /dev/null
++++ b/include/asm-avr32/page.h
+@@ -0,0 +1,112 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_PAGE_H
++#define __ASM_AVR32_PAGE_H
++
++#ifdef __KERNEL__
++
++/* PAGE_SHIFT determines the page size */
++#define PAGE_SHIFT 12
++#ifdef __ASSEMBLY__
++#define PAGE_SIZE (1 << PAGE_SHIFT)
++#else
++#define PAGE_SIZE (1UL << PAGE_SHIFT)
++#endif
++#define PAGE_MASK (~(PAGE_SIZE-1))
++#define PTE_MASK PAGE_MASK
++
++#ifndef __ASSEMBLY__
++
++#include <asm/addrspace.h>
++
++extern void clear_page(void *to);
++extern void copy_page(void *to, void *from);
++
++#define clear_user_page(page, vaddr, pg) clear_page(page)
++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
++
++/*
++ * These are used to make use of C type-checking..
++ */
++typedef struct { unsigned long pte; } pte_t;
++typedef struct { unsigned long pgd; } pgd_t;
++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) })
++
++/* FIXME: These should be removed soon */
++extern unsigned long memory_start, memory_end;
++
++/* Pure 2^n version of get_order */
++static inline int get_order(unsigned long size)
++{
++ unsigned lz;
++
++ size = (size - 1) >> PAGE_SHIFT;
++ asm("clz %0, %1" : "=r"(lz) : "r"(size));
++ return 32 - lz;
++}
++
++#endif /* !__ASSEMBLY__ */
++
++/* Align the pointer to the (next) page boundary */
++#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
++
++/*
++ * The hardware maps the virtual addresses 0x80000000 -> 0x9fffffff
++ * permanently to the physical addresses 0x00000000 -> 0x1fffffff when
++ * segmentation is enabled. We want to make use of this in order to
++ * minimize TLB pressure.
++ */
++#define PAGE_OFFSET (0x80000000UL)
++
++/*
++ * ALSA uses virt_to_page() on DMA pages, which I'm not entirely sure
++ * is a good idea. Anyway, we can't simply subtract PAGE_OFFSET here
++ * in that case, so we'll have to mask out the three most significant
++ * bits of the address instead...
++ *
++ * What's the difference between __pa() and virt_to_phys() anyway?
++ */
++#define __pa(x) PHYSADDR(x)
++#define __va(x) ((void *)(P1SEGADDR(x)))
++
++#define MAP_NR(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
++
++#define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT))
++#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
++
++#ifndef CONFIG_NEED_MULTIPLE_NODES
++
++#define PHYS_PFN_OFFSET (CONFIG_PHYS_OFFSET >> PAGE_SHIFT)
++
++#define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET))
++#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET)
++#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
++#endif /* CONFIG_NEED_MULTIPLE_NODES */
++
++#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
++#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
++
++#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
++ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
++
++/*
++ * Memory above this physical address will be considered highmem.
++ */
++#define HIGHMEM_START 0x20000000UL
++
++#endif /* __KERNEL__ */
++
++#endif /* __ASM_AVR32_PAGE_H */
+diff --git a/include/asm-avr32/param.h b/include/asm-avr32/param.h
+new file mode 100644
+index 0000000..34bc8d4
+--- /dev/null
++++ b/include/asm-avr32/param.h
+@@ -0,0 +1,23 @@
++#ifndef __ASM_AVR32_PARAM_H
++#define __ASM_AVR32_PARAM_H
++
++#ifdef __KERNEL__
++# define HZ CONFIG_HZ
++# define USER_HZ 100 /* User interfaces are in "ticks" */
++# define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */
++#endif
++
++#ifndef HZ
++# define HZ 100
++#endif
++
++/* TODO: Should be configurable */
++#define EXEC_PAGESIZE 4096
++
++#ifndef NOGROUP
++# define NOGROUP (-1)
++#endif
++
++#define MAXHOSTNAMELEN 64
++
++#endif /* __ASM_AVR32_PARAM_H */
+diff --git a/include/asm-avr32/pci.h b/include/asm-avr32/pci.h
+new file mode 100644
+index 0000000..0f5f134
+--- /dev/null
++++ b/include/asm-avr32/pci.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_AVR32_PCI_H__
++#define __ASM_AVR32_PCI_H__
++
++/* We don't support PCI yet, but some drivers require this file anyway */
++
++#define PCI_DMA_BUS_IS_PHYS (1)
++
++#endif /* __ASM_AVR32_PCI_H__ */
+diff --git a/include/asm-avr32/percpu.h b/include/asm-avr32/percpu.h
+new file mode 100644
+index 0000000..69227b4
+--- /dev/null
++++ b/include/asm-avr32/percpu.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_PERCPU_H
++#define __ASM_AVR32_PERCPU_H
++
++#include <asm-generic/percpu.h>
++
++#endif /* __ASM_AVR32_PERCPU_H */
+diff --git a/include/asm-avr32/pgalloc.h b/include/asm-avr32/pgalloc.h
+new file mode 100644
+index 0000000..7492cfb
+--- /dev/null
++++ b/include/asm-avr32/pgalloc.h
+@@ -0,0 +1,96 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_PGALLOC_H
++#define __ASM_AVR32_PGALLOC_H
++
++#include <asm/processor.h>
++#include <linux/threads.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++
++#define pmd_populate_kernel(mm, pmd, pte) \
++ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
++
++static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
++ struct page *pte)
++{
++ set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
++}
++
++/*
++ * Allocate and free page tables
++ */
++static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
++{
++ unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
++ pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
++
++ if (pgd)
++ memset(pgd, 0, pgd_size);
++
++ return pgd;
++}
++
++static inline void pgd_free(pgd_t *pgd)
++{
++ kfree(pgd);
++}
++
++static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
++ unsigned long address)
++{
++ int count = 0;
++ pte_t *pte;
++
++ do {
++ pte = (pte_t *) __get_free_page(GFP_KERNEL | __GFP_REPEAT);
++ if (pte)
++ clear_page(pte);
++ else {
++ current->state = TASK_UNINTERRUPTIBLE;
++ schedule_timeout(HZ);
++ }
++ } while (!pte && (count++ < 10));
++
++ return pte;
++}
++
++static inline struct page *pte_alloc_one(struct mm_struct *mm,
++ unsigned long address)
++{
++ int count = 0;
++ struct page *pte;
++
++ do {
++ pte = alloc_pages(GFP_KERNEL, 0);
++ if (pte)
++ clear_page(page_address(pte));
++ else {
++ current->state = TASK_UNINTERRUPTIBLE;
++ schedule_timeout(HZ);
++ }
++ } while (!pte && (count++ < 10));
++
++ return pte;
++}
++
++static inline void pte_free_kernel(pte_t *pte)
++{
++ free_page((unsigned long)pte);
++}
++
++static inline void pte_free(struct page *pte)
++{
++ __free_page(pte);
++}
++
++#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
++
++#define check_pgt_cache() do { } while(0)
++
++#endif /* __ASM_AVR32_PGALLOC_H */
+diff --git a/include/asm-avr32/pgtable-2level.h b/include/asm-avr32/pgtable-2level.h
+new file mode 100644
+index 0000000..425dd56
+--- /dev/null
++++ b/include/asm-avr32/pgtable-2level.h
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_PGTABLE_2LEVEL_H
++#define __ASM_AVR32_PGTABLE_2LEVEL_H
++
++#include <asm-generic/pgtable-nopmd.h>
++
++/*
++ * Traditional 2-level paging structure
++ */
++#define PGDIR_SHIFT 22
++#define PTRS_PER_PGD 1024
++
++#define PTRS_PER_PTE 1024
++
++#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 %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++
++/*
++ * Certain architectures need to do special things when PTEs
++ * within a page table are directly modified. Thus, the following
++ * hook is made available.
++ */
++#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
++#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep, pteval)
++
++/*
++ * (pmds are folded into pgds so this doesn't get actually called,
++ * but the define is needed for a generic inline function.)
++ */
++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
++
++#define pte_pfn(x) ((unsigned long)(((x).pte >> PAGE_SHIFT)))
++#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++
++#endif /* !__ASSEMBLY__ */
++
++#endif /* __ASM_AVR32_PGTABLE_2LEVEL_H */
+diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
+new file mode 100644
+index 0000000..6b8ca9d
+--- /dev/null
++++ b/include/asm-avr32/pgtable.h
+@@ -0,0 +1,408 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_PGTABLE_H
++#define __ASM_AVR32_PGTABLE_H
++
++#include <asm/addrspace.h>
++
++#ifndef __ASSEMBLY__
++#include <linux/sched.h>
++
++#endif /* !__ASSEMBLY__ */
++
++/*
++ * Use two-level page tables just as the i386 (without PAE)
++ */
++#include <asm/pgtable-2level.h>
++
++/*
++ * The following code might need some cleanup when the values are
++ * final...
++ */
++#define PMD_SIZE (1UL << PMD_SHIFT)
++#define PMD_MASK (~(PMD_SIZE-1))
++#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
++#define PGDIR_MASK (~(PGDIR_SIZE-1))
++
++#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
++#define FIRST_USER_ADDRESS 0
++
++#define PTE_PHYS_MASK 0x1ffff000
++
++#ifndef __ASSEMBLY__
++extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
++extern void paging_init(void);
++
++/*
++ * ZERO_PAGE is a global shared page that is always zero: used for
++ * zero-mapped memory areas etc.
++ */
++extern struct page *empty_zero_page;
++#define ZERO_PAGE(vaddr) (empty_zero_page)
++
++/*
++ * Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8 MiB value just means that there will be a 8 MiB "hole"
++ * after the uncached physical memory (P2 segment) until the vmalloc
++ * area starts. That means that any out-of-bounds memory accesses will
++ * hopefully be caught; we don't know if the end of the P1/P2 segments
++ * are actually used for anything, but it is anyway safer to let the
++ * MMU catch these kinds of errors than to rely on the memory bus.
++ *
++ * A "hole" of the same size is added to the end of the P3 segment as
++ * well. It might seem wasteful to use 16 MiB of virtual address space
++ * on this, but we do have 512 MiB of it...
++ *
++ * The vmalloc() routines leave a hole of 4 KiB between each vmalloced
++ * area for the same reason.
++ */
++#define VMALLOC_OFFSET (8 * 1024 * 1024)
++#define VMALLOC_START (P3SEG + VMALLOC_OFFSET)
++#define VMALLOC_END (P4SEG - VMALLOC_OFFSET)
++#endif /* !__ASSEMBLY__ */
++
++/*
++ * Page flags. Some of these flags are not directly supported by
++ * hardware, so we have to emulate them.
++ */
++#define _TLBEHI_BIT_VALID 9
++#define _TLBEHI_VALID (1 << _TLBEHI_BIT_VALID)
++
++#define _PAGE_BIT_WT 0 /* W-bit : write-through */
++#define _PAGE_BIT_DIRTY 1 /* D-bit : page changed */
++#define _PAGE_BIT_SZ0 2 /* SZ0-bit : Size of page */
++#define _PAGE_BIT_SZ1 3 /* SZ1-bit : Size of page */
++#define _PAGE_BIT_EXECUTE 4 /* X-bit : execute access allowed */
++#define _PAGE_BIT_RW 5 /* AP0-bit : write access allowed */
++#define _PAGE_BIT_USER 6 /* AP1-bit : user space access allowed */
++#define _PAGE_BIT_BUFFER 7 /* B-bit : bufferable */
++#define _PAGE_BIT_GLOBAL 8 /* G-bit : global (ignore ASID) */
++#define _PAGE_BIT_CACHABLE 9 /* C-bit : cachable */
++
++/* If we drop support for 1K pages, we get two extra bits */
++#define _PAGE_BIT_PRESENT 10
++#define _PAGE_BIT_ACCESSED 11 /* software: page was accessed */
++
++/* The following flags are only valid when !PRESENT */
++#define _PAGE_BIT_FILE 0 /* software: pagecache or swap? */
++
++#define _PAGE_WT (1 << _PAGE_BIT_WT)
++#define _PAGE_DIRTY (1 << _PAGE_BIT_DIRTY)
++#define _PAGE_EXECUTE (1 << _PAGE_BIT_EXECUTE)
++#define _PAGE_RW (1 << _PAGE_BIT_RW)
++#define _PAGE_USER (1 << _PAGE_BIT_USER)
++#define _PAGE_BUFFER (1 << _PAGE_BIT_BUFFER)
++#define _PAGE_GLOBAL (1 << _PAGE_BIT_GLOBAL)
++#define _PAGE_CACHABLE (1 << _PAGE_BIT_CACHABLE)
++
++/* Software flags */
++#define _PAGE_ACCESSED (1 << _PAGE_BIT_ACCESSED)
++#define _PAGE_PRESENT (1 << _PAGE_BIT_PRESENT)
++#define _PAGE_FILE (1 << _PAGE_BIT_FILE)
++
++/*
++ * Page types, i.e. sizes. _PAGE_TYPE_NONE corresponds to what is
++ * usually called _PAGE_PROTNONE on other architectures.
++ *
++ * XXX: Find out if _PAGE_PROTNONE is equivalent with !_PAGE_USER. If
++ * so, we can encode all possible page sizes (although we can't really
++ * support 1K pages anyway due to the _PAGE_PRESENT and _PAGE_ACCESSED
++ * bits)
++ *
++ */
++#define _PAGE_TYPE_MASK ((1 << _PAGE_BIT_SZ0) | (1 << _PAGE_BIT_SZ1))
++#define _PAGE_TYPE_NONE (0 << _PAGE_BIT_SZ0)
++#define _PAGE_TYPE_SMALL (1 << _PAGE_BIT_SZ0)
++#define _PAGE_TYPE_MEDIUM (2 << _PAGE_BIT_SZ0)
++#define _PAGE_TYPE_LARGE (3 << _PAGE_BIT_SZ0)
++
++/*
++ * Mask which drop software flags. We currently can't handle more than
++ * 512 MiB of physical memory, so we can use bits 29-31 for other
++ * stuff. With a fixed 4K page size, we can use bits 10-11 as well as
++ * bits 2-3 (SZ)
++ */
++#define _PAGE_FLAGS_HARDWARE_MASK 0xfffff3ff
++
++#define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT)
++
++/* TODO: Check for saneness */
++/* User-mode page table flags (to be set in a pgd or pmd entry) */
++#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
++ | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
++/* Kernel-mode page table flags */
++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
++ | _PAGE_ACCESSED | _PAGE_DIRTY)
++/* Flags that may be modified by software */
++#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \
++ | _PAGE_FLAGS_CACHE_MASK)
++
++#define _PAGE_FLAGS_READ (_PAGE_CACHABLE | _PAGE_BUFFER)
++#define _PAGE_FLAGS_WRITE (_PAGE_FLAGS_READ | _PAGE_RW | _PAGE_DIRTY)
++
++#define _PAGE_NORMAL(x) __pgprot((x) | _PAGE_PRESENT | _PAGE_TYPE_SMALL \
++ | _PAGE_ACCESSED)
++
++#define PAGE_NONE (_PAGE_ACCESSED | _PAGE_TYPE_NONE)
++#define PAGE_READ (_PAGE_FLAGS_READ | _PAGE_USER)
++#define PAGE_EXEC (_PAGE_FLAGS_READ | _PAGE_EXECUTE | _PAGE_USER)
++#define PAGE_WRITE (_PAGE_FLAGS_WRITE | _PAGE_USER)
++#define PAGE_KERNEL _PAGE_NORMAL(_PAGE_FLAGS_WRITE | _PAGE_EXECUTE | _PAGE_GLOBAL)
++#define PAGE_KERNEL_RO _PAGE_NORMAL(_PAGE_FLAGS_READ | _PAGE_EXECUTE | _PAGE_GLOBAL)
++
++#define _PAGE_P(x) _PAGE_NORMAL((x) & ~(_PAGE_RW | _PAGE_DIRTY))
++#define _PAGE_S(x) _PAGE_NORMAL(x)
++
++#define PAGE_COPY _PAGE_P(PAGE_WRITE | PAGE_READ)
++
++#ifndef __ASSEMBLY__
++/*
++ * The hardware supports flags for write- and execute access. Read is
++ * always allowed if the page is loaded into the TLB, so the "-w-",
++ * "--x" and "-wx" mappings are implemented as "rw-", "r-x" and "rwx",
++ * respectively.
++ *
++ * The "---" case is handled by software; the page will simply not be
++ * loaded into the TLB if the page type is _PAGE_TYPE_NONE.
++ */
++
++#define __P000 __pgprot(PAGE_NONE)
++#define __P001 _PAGE_P(PAGE_READ)
++#define __P010 _PAGE_P(PAGE_WRITE)
++#define __P011 _PAGE_P(PAGE_WRITE | PAGE_READ)
++#define __P100 _PAGE_P(PAGE_EXEC)
++#define __P101 _PAGE_P(PAGE_EXEC | PAGE_READ)
++#define __P110 _PAGE_P(PAGE_EXEC | PAGE_WRITE)
++#define __P111 _PAGE_P(PAGE_EXEC | PAGE_WRITE | PAGE_READ)
++
++#define __S000 __pgprot(PAGE_NONE)
++#define __S001 _PAGE_S(PAGE_READ)
++#define __S010 _PAGE_S(PAGE_WRITE)
++#define __S011 _PAGE_S(PAGE_WRITE | PAGE_READ)
++#define __S100 _PAGE_S(PAGE_EXEC)
++#define __S101 _PAGE_S(PAGE_EXEC | PAGE_READ)
++#define __S110 _PAGE_S(PAGE_EXEC | PAGE_WRITE)
++#define __S111 _PAGE_S(PAGE_EXEC | PAGE_WRITE | PAGE_READ)
++
++#define pte_none(x) (!pte_val(x))
++#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
++
++#define pte_clear(mm,addr,xp) \
++ do { \
++ set_pte_at(mm, addr, xp, __pte(0)); \
++ } while (0)
++
++/*
++ * The following only work if pte_present() is true.
++ * Undefined behaviour if not..
++ */
++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_exec(pte_t pte)
++{
++ return pte_val(pte) & _PAGE_EXECUTE;
++}
++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;
++}
++
++/*
++ * The following only work if pte_present() is not true.
++ */
++static inline int pte_file(pte_t pte)
++{
++ return pte_val(pte) & _PAGE_FILE;
++}
++
++/* Mutator functions for PTE bits */
++static inline pte_t pte_rdprotect(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER));
++ return pte;
++}
++static inline pte_t pte_wrprotect(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW));
++ return pte;
++}
++static inline pte_t pte_exprotect(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_EXECUTE));
++ return pte;
++}
++static inline pte_t pte_mkclean(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY));
++ return pte;
++}
++static inline pte_t pte_mkold(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED));
++ return pte;
++}
++static inline pte_t pte_mkread(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER));
++ return pte;
++}
++static inline pte_t pte_mkwrite(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW));
++ return pte;
++}
++static inline pte_t pte_mkexec(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE));
++ return pte;
++}
++static inline pte_t pte_mkdirty(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY));
++ return pte;
++}
++static inline pte_t pte_mkyoung(pte_t pte)
++{
++ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED));
++ return pte;
++}
++
++#define pmd_none(x) (!pmd_val(x))
++#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
++#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) \
++ != _KERNPG_TABLE)
++
++/*
++ * Permanent address of a page. We don't support highmem, so this is
++ * trivial.
++ */
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++#define pte_page(x) phys_to_page(pte_val(x) & PTE_PHYS_MASK)
++
++/*
++ * Mark the prot value as uncacheable and unbufferable
++ */
++#define pgprot_noncached(prot) \
++ __pgprot(pgprot_val(prot) & ~(_PAGE_BUFFER | _PAGE_CACHABLE))
++
++/*
++ * Mark the prot value as uncacheable but bufferable
++ */
++#define pgprot_writecombine(prot) \
++ __pgprot((pgprot_val(prot) & ~_PAGE_CACHABLE) | _PAGE_BUFFER)
++
++/*
++ * Conversion functions: convert a page and protection to a page entry,
++ * and a page entry and page directory to the page they refer to.
++ *
++ * extern pte_t mk_pte(struct page *page, pgprot_t pgprot)
++ */
++#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
++
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK)
++ | pgprot_val(newprot)));
++ return pte;
++}
++
++#define page_pte(page) page_pte_prot(page, __pgprot(0))
++
++#define pmd_page_vaddr(pmd) \
++ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++
++#define pmd_page(pmd) (phys_to_page(pmd_val(pmd)))
++
++/* to find an entry in a page-table-directory. */
++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
++#define pgd_offset_current(address) \
++ ((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address))
++
++/* to find an entry in a kernel page-table-directory */
++#define pgd_offset_k(address) pgd_offset(&init_mm, address)
++
++/* Find an entry in the third-level page table.. */
++#define pte_index(address) \
++ ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
++#define pte_offset(dir, address) \
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
++#define pte_offset_kernel(dir, address) \
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
++#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
++#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
++#define pte_unmap(pte) do { } while (0)
++#define pte_unmap_nested(pte) do { } while (0)
++
++struct vm_area_struct;
++extern void update_mmu_cache(struct vm_area_struct * vma,
++ unsigned long address, pte_t pte);
++
++/*
++ * Encode and decode a swap entry
++ *
++ * Constraints:
++ * _PAGE_FILE at bit 0
++ * _PAGE_TYPE_* at bits 2-3 (for emulating _PAGE_PROTNONE)
++ * _PAGE_PRESENT at bit 10
++ *
++ * We encode the type into bits 4-9 and offset into bits 11-31. This
++ * gives us a 21 bits offset, or 2**21 * 4K = 8G usable swap space per
++ * device, and 64 possible types.
++ *
++ * NOTE: We should set ZEROs at the position of _PAGE_PRESENT
++ * and _PAGE_PROTNONE bits
++ */
++#define __swp_type(x) (((x).val >> 4) & 0x3f)
++#define __swp_offset(x) ((x).val >> 11)
++#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
++#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
++
++/*
++ * Encode and decode a nonlinear file mapping entry. We have to
++ * preserve _PAGE_FILE and _PAGE_PRESENT here. _PAGE_TYPE_* isn't
++ * necessary, since _PAGE_FILE implies !_PAGE_PROTNONE (?)
++ */
++#define PTE_FILE_MAX_BITS 30
++#define pte_to_pgoff(pte) (((pte_val(pte) >> 1) & 0x1ff) \
++ | ((pte_val(pte) >> 11) << 9))
++#define pgoff_to_pte(off) ((pte_t) { ((((off) & 0x1ff) << 1) \
++ | (((off) >> 9) << 11) \
++ | _PAGE_FILE) })
++
++typedef pte_t *pte_addr_t;
++
++#define kern_addr_valid(addr) (1)
++
++#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
++ remap_pfn_range(vma, vaddr, pfn, size, prot)
++
++#define MK_IOSPACE_PFN(space, pfn) (pfn)
++#define GET_IOSPACE(pfn) 0
++#define GET_PFN(pfn) (pfn)
++
++/* No page table caches to initialize (?) */
++#define pgtable_cache_init() do { } while(0)
++
++#include <asm-generic/pgtable.h>
++
++#endif /* !__ASSEMBLY__ */
++
++#endif /* __ASM_AVR32_PGTABLE_H */
+diff --git a/include/asm-avr32/poll.h b/include/asm-avr32/poll.h
+new file mode 100644
+index 0000000..736e297
+--- /dev/null
++++ b/include/asm-avr32/poll.h
+@@ -0,0 +1,27 @@
++#ifndef __ASM_AVR32_POLL_H
++#define __ASM_AVR32_POLL_H
++
++/* These are specified by iBCS2 */
++#define POLLIN 0x0001
++#define POLLPRI 0x0002
++#define POLLOUT 0x0004
++#define POLLERR 0x0008
++#define POLLHUP 0x0010
++#define POLLNVAL 0x0020
++
++/* The rest seem to be more-or-less nonstandard. Check them! */
++#define POLLRDNORM 0x0040
++#define POLLRDBAND 0x0080
++#define POLLWRNORM 0x0100
++#define POLLWRBAND 0x0200
++#define POLLMSG 0x0400
++#define POLLREMOVE 0x1000
++#define POLLRDHUP 0x2000
++
++struct pollfd {
++ int fd;
++ short events;
++ short revents;
++};
++
++#endif /* __ASM_AVR32_POLL_H */
+diff --git a/include/asm-avr32/posix_types.h b/include/asm-avr32/posix_types.h
+new file mode 100644
+index 0000000..2831b03
+--- /dev/null
++++ b/include/asm-avr32/posix_types.h
+@@ -0,0 +1,129 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_POSIX_TYPES_H
++#define __ASM_AVR32_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 short __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 long __kernel_size_t;
++typedef int __kernel_ssize_t;
++typedef int __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 {
++#if defined(__KERNEL__) || defined(__USE_ALL)
++ int val[2];
++#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
++ int __val[2];
++#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
++} __kernel_fsid_t;
++
++#if defined(__KERNEL__)
++
++#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, const __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 long *__tmp = __p->fds_bits;
++ int __i;
++
++ if (__builtin_constant_p(__FDSET_LONGS)) {
++ switch (__FDSET_LONGS) {
++ case 16:
++ __tmp[ 0] = 0; __tmp[ 1] = 0;
++ __tmp[ 2] = 0; __tmp[ 3] = 0;
++ __tmp[ 4] = 0; __tmp[ 5] = 0;
++ __tmp[ 6] = 0; __tmp[ 7] = 0;
++ __tmp[ 8] = 0; __tmp[ 9] = 0;
++ __tmp[10] = 0; __tmp[11] = 0;
++ __tmp[12] = 0; __tmp[13] = 0;
++ __tmp[14] = 0; __tmp[15] = 0;
++ return;
++
++ 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;
++
++ case 4:
++ __tmp[ 0] = 0; __tmp[ 1] = 0;
++ __tmp[ 2] = 0; __tmp[ 3] = 0;
++ return;
++ }
++ }
++ __i = __FDSET_LONGS;
++ while (__i) {
++ __i--;
++ *__tmp = 0;
++ __tmp++;
++ }
++}
++
++#endif /* defined(__KERNEL__) */
++
++#endif /* __ASM_AVR32_POSIX_TYPES_H */
+diff --git a/include/asm-avr32/processor.h b/include/asm-avr32/processor.h
+new file mode 100644
+index 0000000..f691377
+--- /dev/null
++++ b/include/asm-avr32/processor.h
+@@ -0,0 +1,147 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_PROCESSOR_H
++#define __ASM_AVR32_PROCESSOR_H
++
++#include <asm/page.h>
++#include <asm/cache.h>
++
++#define TASK_SIZE 0x80000000
++
++#ifndef __ASSEMBLY__
++
++static inline void *current_text_addr(void)
++{
++ register void *pc asm("pc");
++ return pc;
++}
++
++enum arch_type {
++ ARCH_AVR32A,
++ ARCH_AVR32B,
++ ARCH_MAX
++};
++
++enum cpu_type {
++ CPU_MORGAN,
++ CPU_AT32AP,
++ CPU_MAX
++};
++
++enum tlb_config {
++ TLB_NONE,
++ TLB_SPLIT,
++ TLB_UNIFIED,
++ TLB_INVALID
++};
++
++struct avr32_cpuinfo {
++ struct clk *clk;
++ unsigned long loops_per_jiffy;
++ enum arch_type arch_type;
++ enum cpu_type cpu_type;
++ unsigned short arch_revision;
++ unsigned short cpu_revision;
++ enum tlb_config tlb_config;
++
++ struct cache_info icache;
++ struct cache_info dcache;
++};
++
++extern struct avr32_cpuinfo boot_cpu_data;
++
++#ifdef CONFIG_SMP
++extern struct avr32_cpuinfo cpu_data[];
++#define current_cpu_data cpu_data[smp_processor_id()]
++#else
++#define cpu_data (&boot_cpu_data)
++#define current_cpu_data boot_cpu_data
++#endif
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's
++ */
++#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
++
++#define cpu_relax() barrier()
++#define cpu_sync_pipeline() asm volatile("sub pc, -2" : : : "memory")
++
++struct cpu_context {
++ unsigned long sr;
++ unsigned long pc;
++ unsigned long ksp; /* Kernel stack pointer */
++ unsigned long r7;
++ unsigned long r6;
++ unsigned long r5;
++ unsigned long r4;
++ unsigned long r3;
++ unsigned long r2;
++ unsigned long r1;
++ unsigned long r0;
++};
++
++/* This struct contains the CPU context as stored by switch_to() */
++struct thread_struct {
++ struct cpu_context cpu_context;
++ unsigned long single_step_addr;
++ u16 single_step_insn;
++};
++
++#define INIT_THREAD { \
++ .cpu_context = { \
++ .ksp = sizeof(init_stack) + (long)&init_stack, \
++ }, \
++}
++
++/*
++ * Do necessary setup to start up a newly executed thread.
++ */
++#define start_thread(regs, new_pc, new_sp) \
++ do { \
++ set_fs(USER_DS); \
++ memset(regs, 0, sizeof(*regs)); \
++ regs->sr = MODE_USER; \
++ regs->pc = new_pc & ~1; \
++ regs->sp = new_sp; \
++ } while(0)
++
++struct task_struct;
++
++/* Free all resources held by a thread */
++extern void release_thread(struct task_struct *);
++
++/* Create a kernel thread without removing it from tasklists */
++extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
++
++/* Prepare to copy thread state - unlazy all lazy status */
++#define prepare_to_copy(tsk) do { } while(0)
++
++/* Return saved PC of a blocked thread */
++#define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc)
++
++struct pt_regs;
++void show_trace(struct task_struct *task, unsigned long *stack,
++ struct pt_regs *regs);
++
++extern unsigned long get_wchan(struct task_struct *p);
++
++#define KSTK_EIP(tsk) ((tsk)->thread.cpu_context.pc)
++#define KSTK_ESP(tsk) ((tsk)->thread.cpu_context.ksp)
++
++#define ARCH_HAS_PREFETCH
++
++static inline void prefetch(const void *x)
++{
++ const char *c = x;
++ asm volatile("pref %0" : : "r"(c));
++}
++#define PREFETCH_STRIDE L1_CACHE_BYTES
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_AVR32_PROCESSOR_H */
+diff --git a/include/asm-avr32/ptrace.h b/include/asm-avr32/ptrace.h
+new file mode 100644
+index 0000000..60f0f19
+--- /dev/null
++++ b/include/asm-avr32/ptrace.h
+@@ -0,0 +1,154 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_PTRACE_H
++#define __ASM_AVR32_PTRACE_H
++
++#define PTRACE_GETREGS 12
++#define PTRACE_SETREGS 13
++
++/*
++ * Status Register bits
++ */
++#define SR_H 0x40000000
++#define SR_R 0x20000000
++#define SR_J 0x10000000
++#define SR_DM 0x08000000
++#define SR_D 0x04000000
++#define MODE_NMI 0x01c00000
++#define MODE_EXCEPTION 0x01800000
++#define MODE_INT3 0x01400000
++#define MODE_INT2 0x01000000
++#define MODE_INT1 0x00c00000
++#define MODE_INT0 0x00800000
++#define MODE_SUPERVISOR 0x00400000
++#define MODE_USER 0x00000000
++#define MODE_MASK 0x01c00000
++#define SR_EM 0x00200000
++#define SR_I3M 0x00100000
++#define SR_I2M 0x00080000
++#define SR_I1M 0x00040000
++#define SR_I0M 0x00020000
++#define SR_GM 0x00010000
++
++#define SR_H_BIT 30
++#define SR_R_BIT 29
++#define SR_J_BIT 28
++#define SR_DM_BIT 27
++#define SR_D_BIT 26
++#define MODE_SHIFT 22
++#define SR_EM_BIT 21
++#define SR_I3M_BIT 20
++#define SR_I2M_BIT 19
++#define SR_I1M_BIT 18
++#define SR_I0M_BIT 17
++#define SR_GM_BIT 16
++
++/* The user-visible part */
++#define SR_L 0x00000020
++#define SR_Q 0x00000010
++#define SR_V 0x00000008
++#define SR_N 0x00000004
++#define SR_Z 0x00000002
++#define SR_C 0x00000001
++
++#define SR_L_BIT 5
++#define SR_Q_BIT 4
++#define SR_V_BIT 3
++#define SR_N_BIT 2
++#define SR_Z_BIT 1
++#define SR_C_BIT 0
++
++/*
++ * The order is defined by the stmts instruction. r0 is stored first,
++ * so it gets the highest address.
++ *
++ * Registers 0-12 are general-purpose registers (r12 is normally used for
++ * the function return value).
++ * Register 13 is the stack pointer
++ * Register 14 is the link register
++ * Register 15 is the program counter (retrieved from the RAR sysreg)
++ */
++#define FRAME_SIZE_FULL 72
++#define REG_R12_ORIG 68
++#define REG_R0 64
++#define REG_R1 60
++#define REG_R2 56
++#define REG_R3 52
++#define REG_R4 48
++#define REG_R5 44
++#define REG_R6 40
++#define REG_R7 36
++#define REG_R8 32
++#define REG_R9 28
++#define REG_R10 24
++#define REG_R11 20
++#define REG_R12 16
++#define REG_SP 12
++#define REG_LR 8
++
++#define FRAME_SIZE_MIN 8
++#define REG_PC 4
++#define REG_SR 0
++
++#ifndef __ASSEMBLY__
++struct pt_regs {
++ /* These are always saved */
++ unsigned long sr;
++ unsigned long pc;
++
++ /* These are sometimes saved */
++ unsigned long lr;
++ unsigned long sp;
++ unsigned long r12;
++ unsigned long r11;
++ unsigned long r10;
++ unsigned long r9;
++ unsigned long r8;
++ unsigned long r7;
++ unsigned long r6;
++ unsigned long r5;
++ unsigned long r4;
++ unsigned long r3;
++ unsigned long r2;
++ unsigned long r1;
++ unsigned long r0;
++
++ /* Only saved on system call */
++ unsigned long r12_orig;
++};
++
++#ifdef __KERNEL__
++# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
++extern void show_regs (struct pt_regs *);
++
++static __inline__ int valid_user_regs(struct pt_regs *regs)
++{
++ /*
++ * Some of the Java bits might be acceptable if/when we
++ * implement some support for that stuff...
++ */
++ if ((regs->sr & 0xffff0000) == 0)
++ return 1;
++
++ /*
++ * Force status register flags to be sane and report this
++ * illegal behaviour...
++ */
++ regs->sr &= 0x0000ffff;
++ return 0;
++}
++
++#define instruction_pointer(regs) ((regs)->pc)
++
++#define profile_pc(regs) instruction_pointer(regs)
++
++#endif /* __KERNEL__ */
++
++#endif /* ! __ASSEMBLY__ */
++
++#endif /* __ASM_AVR32_PTRACE_H */
+diff --git a/include/asm-avr32/resource.h b/include/asm-avr32/resource.h
+new file mode 100644
+index 0000000..c6dd101
+--- /dev/null
++++ b/include/asm-avr32/resource.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_RESOURCE_H
++#define __ASM_AVR32_RESOURCE_H
++
++#include <asm-generic/resource.h>
++
++#endif /* __ASM_AVR32_RESOURCE_H */
+diff --git a/include/asm-avr32/scatterlist.h b/include/asm-avr32/scatterlist.h
+new file mode 100644
+index 0000000..bfe7d75
+--- /dev/null
++++ b/include/asm-avr32/scatterlist.h
+@@ -0,0 +1,21 @@
++#ifndef __ASM_AVR32_SCATTERLIST_H
++#define __ASM_AVR32_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.
++ */
++#define sg_dma_address(sg) ((sg)->dma_address)
++#define sg_dma_len(sg) ((sg)->length)
++
++#define ISA_DMA_THRESHOLD (0xffffffff)
++
++#endif /* __ASM_AVR32_SCATTERLIST_H */
+diff --git a/include/asm-avr32/sections.h b/include/asm-avr32/sections.h
+new file mode 100644
+index 0000000..aa14252
+--- /dev/null
++++ b/include/asm-avr32/sections.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_SECTIONS_H
++#define __ASM_AVR32_SECTIONS_H
++
++#include <asm-generic/sections.h>
++
++#endif /* __ASM_AVR32_SECTIONS_H */
+diff --git a/include/asm-avr32/semaphore.h b/include/asm-avr32/semaphore.h
+new file mode 100644
+index 0000000..ef99ddc
+--- /dev/null
++++ b/include/asm-avr32/semaphore.h
+@@ -0,0 +1,109 @@
++/*
++ * SMP- and interrupt-safe semaphores.
++ *
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * Based on include/asm-i386/semaphore.h
++ * Copyright (C) 1996 Linus Torvalds
++ *
++ * 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 __ASM_AVR32_SEMAPHORE_H
++#define __ASM_AVR32_SEMAPHORE_H
++
++#include <linux/linkage.h>
++
++#include <asm/system.h>
++#include <asm/atomic.h>
++#include <linux/wait.h>
++#include <linux/rwsem.h>
++
++struct semaphore {
++ atomic_t count;
++ int sleepers;
++ wait_queue_head_t wait;
++};
++
++#define __SEMAPHORE_INITIALIZER(name, n) \
++{ \
++ .count = ATOMIC_INIT(n), \
++ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
++}
++
++#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)
++
++static inline void sema_init (struct semaphore *sem, int val)
++{
++ atomic_set(&sem->count, val);
++ sem->sleepers = 0;
++ init_waitqueue_head(&sem->wait);
++}
++
++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);
++}
++
++void __down(struct semaphore * sem);
++int __down_interruptible(struct semaphore * sem);
++void __up(struct semaphore * sem);
++
++/*
++ * This is ugly, but we want the default case to fall through.
++ * "__down_failed" is a special asm handler that calls the C
++ * routine that actually waits. See arch/i386/kernel/semaphore.c
++ */
++static inline void down(struct semaphore * sem)
++{
++ might_sleep();
++ if (unlikely(atomic_dec_return (&sem->count) < 0))
++ __down (sem);
++}
++
++/*
++ * Interruptible try to acquire a semaphore. If we obtained
++ * it, return zero. If we were interrupted, returns -EINTR
++ */
++static inline int down_interruptible(struct semaphore * sem)
++{
++ int ret = 0;
++
++ might_sleep();
++ if (unlikely(atomic_dec_return (&sem->count) < 0))
++ ret = __down_interruptible (sem);
++ return ret;
++}
++
++/*
++ * Non-blockingly attempt to down() a semaphore.
++ * Returns zero if we acquired it
++ */
++static inline int down_trylock(struct semaphore * sem)
++{
++ return atomic_dec_if_positive(&sem->count) < 0;
++}
++
++/*
++ * Note! This is subtle. We jump to wake people up only if
++ * the semaphore was negative (== somebody was waiting on it).
++ * The default case (no contention) will result in NO
++ * jumps for both down() and up().
++ */
++static inline void up(struct semaphore * sem)
++{
++ if (unlikely(atomic_inc_return (&sem->count) <= 0))
++ __up (sem);
++}
++
++#endif /*__ASM_AVR32_SEMAPHORE_H */
+diff --git a/include/asm-avr32/sembuf.h b/include/asm-avr32/sembuf.h
+new file mode 100644
+index 0000000..e472216
+--- /dev/null
++++ b/include/asm-avr32/sembuf.h
+@@ -0,0 +1,25 @@
++#ifndef __ASM_AVR32_SEMBUF_H
++#define __ASM_AVR32_SEMBUF_H
++
++/*
++* The semid64_ds structure for AVR32 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
++ */
++
++struct semid64_ds {
++ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
++ __kernel_time_t sem_otime; /* last semop time */
++ unsigned long __unused1;
++ __kernel_time_t sem_ctime; /* last change time */
++ unsigned long __unused2;
++ unsigned long sem_nsems; /* no. of semaphores in array */
++ unsigned long __unused3;
++ unsigned long __unused4;
++};
++
++#endif /* __ASM_AVR32_SEMBUF_H */
+diff --git a/include/asm-avr32/setup.h b/include/asm-avr32/setup.h
+new file mode 100644
+index 0000000..10193da
+--- /dev/null
++++ b/include/asm-avr32/setup.h
+@@ -0,0 +1,141 @@
++/*
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * Based on linux/include/asm-arm/setup.h
++ * Copyright (C) 1997-1999 Russel 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.
++ */
++#ifndef __ASM_AVR32_SETUP_H__
++#define __ASM_AVR32_SETUP_H__
++
++#define COMMAND_LINE_SIZE 256
++
++/* Magic number indicating that a tag table is present */
++#define ATAG_MAGIC 0xa2a25441
++
++#ifndef __ASSEMBLY__
++
++/*
++ * Generic memory range, used by several tags.
++ *
++ * addr is always physical.
++ * size is measured in bytes.
++ * next is for use by the OS, e.g. for grouping regions into
++ * linked lists.
++ */
++struct tag_mem_range {
++ u32 addr;
++ u32 size;
++ struct tag_mem_range * next;
++};
++
++/* The list ends with an ATAG_NONE node. */
++#define ATAG_NONE 0x00000000
++
++struct tag_header {
++ u32 size;
++ u32 tag;
++};
++
++/* The list must start with an ATAG_CORE node */
++#define ATAG_CORE 0x54410001
++
++struct tag_core {
++ u32 flags;
++ u32 pagesize;
++ u32 rootdev;
++};
++
++/* it is allowed to have multiple ATAG_MEM nodes */
++#define ATAG_MEM 0x54410002
++/* ATAG_MEM uses tag_mem_range */
++
++/* command line: \0 terminated string */
++#define ATAG_CMDLINE 0x54410003
++
++struct tag_cmdline {
++ char cmdline[1]; /* this is the minimum size */
++};
++
++/* Ramdisk image (may be compressed) */
++#define ATAG_RDIMG 0x54410004
++/* ATAG_RDIMG uses tag_mem_range */
++
++/* Information about various clocks present in the system */
++#define ATAG_CLOCK 0x54410005
++
++struct tag_clock {
++ u32 clock_id; /* Which clock are we talking about? */
++ u32 clock_flags; /* Special features */
++ u64 clock_hz; /* Clock speed in Hz */
++};
++
++/* The clock types we know about */
++#define CLOCK_BOOTCPU 0
++
++/* Memory reserved for the system (e.g. the bootloader) */
++#define ATAG_RSVD_MEM 0x54410006
++/* ATAG_RSVD_MEM uses tag_mem_range */
++
++/* Ethernet information */
++
++#define ATAG_ETHERNET 0x54410007
++
++struct tag_ethernet {
++ u8 mac_index;
++ u8 mii_phy_addr;
++ u8 hw_address[6];
++};
++
++#define ETH_INVALID_PHY 0xff
++
++struct tag {
++ struct tag_header hdr;
++ union {
++ struct tag_core core;
++ struct tag_mem_range mem_range;
++ struct tag_cmdline cmdline;
++ struct tag_clock clock;
++ struct tag_ethernet ethernet;
++ } u;
++};
++
++struct tagtable {
++ u32 tag;
++ int (*parse)(struct tag *);
++};
++
++#define __tag __attribute_used__ __attribute__((__section__(".taglist")))
++#define __tagtable(tag, fn) \
++ static struct tagtable __tagtable_##fn __tag = { tag, fn }
++
++#define tag_member_present(tag,member) \
++ ((unsigned long)(&((struct tag *)0L)->member + 1) \
++ <= (tag)->hdr.size * 4)
++
++#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
++#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
++
++#define for_each_tag(t,base) \
++ for (t = base; t->hdr.size; t = tag_next(t))
++
++extern struct tag_mem_range *mem_phys;
++extern struct tag_mem_range *mem_reserved;
++extern struct tag_mem_range *mem_ramdisk;
++
++extern struct tag *bootloader_tags;
++
++extern void setup_bootmem(void);
++extern void setup_processor(void);
++extern void board_setup_fbmem(unsigned long fbmem_start,
++ unsigned long fbmem_size);
++
++/* Chip-specific hook to enable the use of SDRAM */
++void chip_enable_sdram(void);
++
++#endif /* !__ASSEMBLY__ */
++
++#endif /* __ASM_AVR32_SETUP_H__ */
+diff --git a/include/asm-avr32/shmbuf.h b/include/asm-avr32/shmbuf.h
+new file mode 100644
+index 0000000..c62fba4
+--- /dev/null
++++ b/include/asm-avr32/shmbuf.h
+@@ -0,0 +1,42 @@
++#ifndef __ASM_AVR32_SHMBUF_H
++#define __ASM_AVR32_SHMBUF_H
++
++/*
++ * The shmid64_ds structure for i386 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
++ */
++
++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 /* __ASM_AVR32_SHMBUF_H */
+diff --git a/include/asm-avr32/shmparam.h b/include/asm-avr32/shmparam.h
+new file mode 100644
+index 0000000..3681266
+--- /dev/null
++++ b/include/asm-avr32/shmparam.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_SHMPARAM_H
++#define __ASM_AVR32_SHMPARAM_H
++
++#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
++
++#endif /* __ASM_AVR32_SHMPARAM_H */
+diff --git a/include/asm-avr32/sigcontext.h b/include/asm-avr32/sigcontext.h
+new file mode 100644
+index 0000000..e04062b
+--- /dev/null
++++ b/include/asm-avr32/sigcontext.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_SIGCONTEXT_H
++#define __ASM_AVR32_SIGCONTEXT_H
++
++struct sigcontext {
++ unsigned long oldmask;
++
++ /* CPU registers */
++ unsigned long sr;
++ unsigned long pc;
++ unsigned long lr;
++ unsigned long sp;
++ unsigned long r12;
++ unsigned long r11;
++ unsigned long r10;
++ unsigned long r9;
++ unsigned long r8;
++ unsigned long r7;
++ unsigned long r6;
++ unsigned long r5;
++ unsigned long r4;
++ unsigned long r3;
++ unsigned long r2;
++ unsigned long r1;
++ unsigned long r0;
++};
++
++#endif /* __ASM_AVR32_SIGCONTEXT_H */
+diff --git a/include/asm-avr32/siginfo.h b/include/asm-avr32/siginfo.h
+new file mode 100644
+index 0000000..5ee93f4
+--- /dev/null
++++ b/include/asm-avr32/siginfo.h
+@@ -0,0 +1,6 @@
++#ifndef _AVR32_SIGINFO_H
++#define _AVR32_SIGINFO_H
++
++#include <asm-generic/siginfo.h>
++
++#endif
+diff --git a/include/asm-avr32/signal.h b/include/asm-avr32/signal.h
+new file mode 100644
+index 0000000..caffefe
+--- /dev/null
++++ b/include/asm-avr32/signal.h
+@@ -0,0 +1,168 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_SIGNAL_H
++#define __ASM_AVR32_SIGNAL_H
++
++#include <linux/types.h>
++
++/* Avoid too many header ordering problems. */
++struct siginfo;
++
++#ifdef __KERNEL__
++/* Most things should be clean enough to redefine this at will, if care
++ is taken to make libc match. */
++
++#define _NSIG 64
++#define _NSIG_BPW 32
++#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
++
++typedef unsigned long old_sigset_t; /* at least 32 bits */
++
++typedef struct {
++ unsigned long sig[_NSIG_WORDS];
++} sigset_t;
++
++#else
++/* Here we must cater to libcs that poke about in kernel headers. */
++
++#define NSIG 32
++typedef unsigned long sigset_t;
++
++#endif /* __KERNEL__ */
++
++#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_NOCLDSTOP flag to turn off SIGCHLD when children stop.
++ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
++ * SA_SIGINFO deliver the signal with SIGINFO structs
++ * SA_ONSTACK indicates that a registered stack_t will be used.
++ * SA_RESTART flag to get restarting signals (which were the default long ago)
++ * SA_NODEFER prevents the current signal from being masked in the handler.
++ * SA_RESETHAND clears the handler when the signal is delivered.
++ *
++ * 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
++#define SA_SIGINFO 0x00000004
++#define SA_RESTORER 0x04000000
++#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
++
++/*
++ * sigaltstack controls
++ */
++#define SS_ONSTACK 1
++#define SS_DISABLE 2
++
++#define MINSIGSTKSZ 2048
++#define SIGSTKSZ 8192
++
++#include <asm-generic/signal.h>
++
++#ifdef __KERNEL__
++struct old_sigaction {
++ __sighandler_t sa_handler;
++ old_sigset_t sa_mask;
++ unsigned long sa_flags;
++ __sigrestore_t sa_restorer;
++};
++
++struct sigaction {
++ __sighandler_t sa_handler;
++ unsigned long sa_flags;
++ __sigrestore_t sa_restorer;
++ 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 __user *ss_sp;
++ int ss_flags;
++ size_t ss_size;
++} stack_t;
++
++#ifdef __KERNEL__
++
++#include <asm/sigcontext.h>
++#undef __HAVE_ARCH_SIG_BITOPS
++
++#define ptrace_signal_deliver(regs, cookie) do { } while (0)
++
++#endif /* __KERNEL__ */
++
++#endif
+diff --git a/include/asm-avr32/socket.h b/include/asm-avr32/socket.h
+new file mode 100644
+index 0000000..543229d
+--- /dev/null
++++ b/include/asm-avr32/socket.h
+@@ -0,0 +1,53 @@
++#ifndef __ASM_AVR32_SOCKET_H
++#define __ASM_AVR32_SOCKET_H
++
++#include <asm/sockios.h>
++
++/* For setsockopt(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_SNDBUFFORCE 32
++#define SO_RCVBUFFORCE 33
++#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
++#define SO_PASSSEC 34
++
++#endif /* __ASM_AVR32_SOCKET_H */
+diff --git a/include/asm-avr32/sockios.h b/include/asm-avr32/sockios.h
+new file mode 100644
+index 0000000..84f3d65
+--- /dev/null
++++ b/include/asm-avr32/sockios.h
+@@ -0,0 +1,12 @@
++#ifndef __ASM_AVR32_SOCKIOS_H
++#define __ASM_AVR32_SOCKIOS_H
++
++/* Socket-level I/O control calls. */
++#define FIOSETOWN 0x8901
++#define SIOCSPGRP 0x8902
++#define FIOGETOWN 0x8903
++#define SIOCGPGRP 0x8904
++#define SIOCATMARK 0x8905
++#define SIOCGSTAMP 0x8906 /* Get stamp */
++
++#endif /* __ASM_AVR32_SOCKIOS_H */
+diff --git a/include/asm-avr32/stat.h b/include/asm-avr32/stat.h
+new file mode 100644
+index 0000000..e72881e
+--- /dev/null
++++ b/include/asm-avr32/stat.h
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_STAT_H
++#define __ASM_AVR32_STAT_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;
++};
++
++struct stat {
++ unsigned long st_dev;
++ unsigned long st_ino;
++ unsigned short st_mode;
++ unsigned short st_nlink;
++ unsigned short st_uid;
++ unsigned short st_gid;
++ unsigned long st_rdev;
++ 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;
++};
++
++#define STAT_HAVE_NSEC 1
++
++struct stat64 {
++ unsigned long long st_dev;
++
++ unsigned long long st_ino;
++ unsigned int st_mode;
++ unsigned int st_nlink;
++
++ unsigned long st_uid;
++ unsigned long st_gid;
++
++ unsigned long long st_rdev;
++
++ long long st_size;
++ unsigned long __pad1; /* align 64-bit st_blocks */
++ unsigned long st_blksize;
++
++ unsigned long long st_blocks; /* Number 512-byte blocks allocated. */
++
++ 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 __unused1;
++ unsigned long __unused2;
++};
++
++#endif /* __ASM_AVR32_STAT_H */
+diff --git a/include/asm-avr32/statfs.h b/include/asm-avr32/statfs.h
+new file mode 100644
+index 0000000..2961bd1
+--- /dev/null
++++ b/include/asm-avr32/statfs.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_STATFS_H
++#define __ASM_AVR32_STATFS_H
++
++#include <asm-generic/statfs.h>
++
++#endif /* __ASM_AVR32_STATFS_H */
+diff --git a/include/asm-avr32/string.h b/include/asm-avr32/string.h
+new file mode 100644
+index 0000000..c91a623
+--- /dev/null
++++ b/include/asm-avr32/string.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_STRING_H
++#define __ASM_AVR32_STRING_H
++
++#define __HAVE_ARCH_MEMSET
++extern void *memset(void *b, int c, size_t len);
++
++#define __HAVE_ARCH_MEMCPY
++extern void *memcpy(void *to, const void *from, size_t len);
++
++#endif /* __ASM_AVR32_STRING_H */
+diff --git a/include/asm-avr32/sysreg.h b/include/asm-avr32/sysreg.h
+new file mode 100644
+index 0000000..f91975f
+--- /dev/null
++++ b/include/asm-avr32/sysreg.h
+@@ -0,0 +1,332 @@
++/*
++ * AVR32 System Registers
++ *
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_SYSREG_H__
++#define __ASM_AVR32_SYSREG_H__
++
++/* sysreg register offsets */
++#define SYSREG_SR 0x0000
++#define SYSREG_EVBA 0x0004
++#define SYSREG_ACBA 0x0008
++#define SYSREG_CPUCR 0x000c
++#define SYSREG_ECR 0x0010
++#define SYSREG_RSR_SUP 0x0014
++#define SYSREG_RSR_INT0 0x0018
++#define SYSREG_RSR_INT1 0x001c
++#define SYSREG_RSR_INT2 0x0020
++#define SYSREG_RSR_INT3 0x0024
++#define SYSREG_RSR_EX 0x0028
++#define SYSREG_RSR_NMI 0x002c
++#define SYSREG_RSR_DBG 0x0030
++#define SYSREG_RAR_SUP 0x0034
++#define SYSREG_RAR_INT0 0x0038
++#define SYSREG_RAR_INT1 0x003c
++#define SYSREG_RAR_INT2 0x0040
++#define SYSREG_RAR_INT3 0x0044
++#define SYSREG_RAR_EX 0x0048
++#define SYSREG_RAR_NMI 0x004c
++#define SYSREG_RAR_DBG 0x0050
++#define SYSREG_JECR 0x0054
++#define SYSREG_JOSP 0x0058
++#define SYSREG_JAVA_LV0 0x005c
++#define SYSREG_JAVA_LV1 0x0060
++#define SYSREG_JAVA_LV2 0x0064
++#define SYSREG_JAVA_LV3 0x0068
++#define SYSREG_JAVA_LV4 0x006c
++#define SYSREG_JAVA_LV5 0x0070
++#define SYSREG_JAVA_LV6 0x0074
++#define SYSREG_JAVA_LV7 0x0078
++#define SYSREG_JTBA 0x007c
++#define SYSREG_JBCR 0x0080
++#define SYSREG_CONFIG0 0x0100
++#define SYSREG_CONFIG1 0x0104
++#define SYSREG_COUNT 0x0108
++#define SYSREG_COMPARE 0x010c
++#define SYSREG_TLBEHI 0x0110
++#define SYSREG_TLBELO 0x0114
++#define SYSREG_PTBR 0x0118
++#define SYSREG_TLBEAR 0x011c
++#define SYSREG_MMUCR 0x0120
++#define SYSREG_TLBARLO 0x0124
++#define SYSREG_TLBARHI 0x0128
++#define SYSREG_PCCNT 0x012c
++#define SYSREG_PCNT0 0x0130
++#define SYSREG_PCNT1 0x0134
++#define SYSREG_PCCR 0x0138
++#define SYSREG_BEAR 0x013c
++
++/* Bitfields in SR */
++#define SYSREG_SR_C_OFFSET 0
++#define SYSREG_SR_C_SIZE 1
++#define SYSREG_Z_OFFSET 1
++#define SYSREG_Z_SIZE 1
++#define SYSREG_SR_N_OFFSET 2
++#define SYSREG_SR_N_SIZE 1
++#define SYSREG_SR_V_OFFSET 3
++#define SYSREG_SR_V_SIZE 1
++#define SYSREG_Q_OFFSET 4
++#define SYSREG_Q_SIZE 1
++#define SYSREG_GM_OFFSET 16
++#define SYSREG_GM_SIZE 1
++#define SYSREG_I0M_OFFSET 17
++#define SYSREG_I0M_SIZE 1
++#define SYSREG_I1M_OFFSET 18
++#define SYSREG_I1M_SIZE 1
++#define SYSREG_I2M_OFFSET 19
++#define SYSREG_I2M_SIZE 1
++#define SYSREG_I3M_OFFSET 20
++#define SYSREG_I3M_SIZE 1
++#define SYSREG_EM_OFFSET 21
++#define SYSREG_EM_SIZE 1
++#define SYSREG_M0_OFFSET 22
++#define SYSREG_M0_SIZE 1
++#define SYSREG_M1_OFFSET 23
++#define SYSREG_M1_SIZE 1
++#define SYSREG_M2_OFFSET 24
++#define SYSREG_M2_SIZE 1
++#define SYSREG_SR_D_OFFSET 26
++#define SYSREG_SR_D_SIZE 1
++#define SYSREG_DM_OFFSET 27
++#define SYSREG_DM_SIZE 1
++#define SYSREG_SR_J_OFFSET 28
++#define SYSREG_SR_J_SIZE 1
++#define SYSREG_R_OFFSET 29
++#define SYSREG_R_SIZE 1
++#define SYSREG_H_OFFSET 30
++#define SYSREG_H_SIZE 1
++
++/* Bitfields in EVBA */
++
++/* Bitfields in ACBA */
++
++/* Bitfields in CPUCR */
++#define SYSREG_BI_OFFSET 0
++#define SYSREG_BI_SIZE 1
++#define SYSREG_BE_OFFSET 1
++#define SYSREG_BE_SIZE 1
++#define SYSREG_FE_OFFSET 2
++#define SYSREG_FE_SIZE 1
++#define SYSREG_RE_OFFSET 3
++#define SYSREG_RE_SIZE 1
++#define SYSREG_IBE_OFFSET 4
++#define SYSREG_IBE_SIZE 1
++#define SYSREG_IEE_OFFSET 5
++#define SYSREG_IEE_SIZE 1
++
++/* Bitfields in ECR */
++#define SYSREG_ECR_OFFSET 0
++#define SYSREG_ECR_SIZE 32
++
++/* Bitfields in RSR_SUP */
++
++/* Bitfields in RSR_INT0 */
++
++/* Bitfields in RSR_INT1 */
++
++/* Bitfields in RSR_INT2 */
++
++/* Bitfields in RSR_INT3 */
++
++/* Bitfields in RSR_EX */
++
++/* Bitfields in RSR_NMI */
++
++/* Bitfields in RSR_DBG */
++
++/* Bitfields in RAR_SUP */
++
++/* Bitfields in RAR_INT0 */
++
++/* Bitfields in RAR_INT1 */
++
++/* Bitfields in RAR_INT2 */
++
++/* Bitfields in RAR_INT3 */
++
++/* Bitfields in RAR_EX */
++
++/* Bitfields in RAR_NMI */
++
++/* Bitfields in RAR_DBG */
++
++/* Bitfields in JECR */
++
++/* Bitfields in JOSP */
++
++/* Bitfields in JAVA_LV0 */
++
++/* Bitfields in JAVA_LV1 */
++
++/* Bitfields in JAVA_LV2 */
++
++/* Bitfields in JAVA_LV3 */
++
++/* Bitfields in JAVA_LV4 */
++
++/* Bitfields in JAVA_LV5 */
++
++/* Bitfields in JAVA_LV6 */
++
++/* Bitfields in JAVA_LV7 */
++
++/* Bitfields in JTBA */
++
++/* Bitfields in JBCR */
++
++/* Bitfields in CONFIG0 */
++#define SYSREG_CONFIG0_D_OFFSET 1
++#define SYSREG_CONFIG0_D_SIZE 1
++#define SYSREG_CONFIG0_S_OFFSET 2
++#define SYSREG_CONFIG0_S_SIZE 1
++#define SYSREG_O_OFFSET 3
++#define SYSREG_O_SIZE 1
++#define SYSREG_P_OFFSET 4
++#define SYSREG_P_SIZE 1
++#define SYSREG_CONFIG0_J_OFFSET 5
++#define SYSREG_CONFIG0_J_SIZE 1
++#define SYSREG_F_OFFSET 6
++#define SYSREG_F_SIZE 1
++#define SYSREG_MMUT_OFFSET 7
++#define SYSREG_MMUT_SIZE 3
++#define SYSREG_AR_OFFSET 10
++#define SYSREG_AR_SIZE 3
++#define SYSREG_AT_OFFSET 13
++#define SYSREG_AT_SIZE 3
++#define SYSREG_PROCESSORREVISION_OFFSET 16
++#define SYSREG_PROCESSORREVISION_SIZE 8
++#define SYSREG_PROCESSORID_OFFSET 24
++#define SYSREG_PROCESSORID_SIZE 8
++
++/* Bitfields in CONFIG1 */
++#define SYSREG_DASS_OFFSET 0
++#define SYSREG_DASS_SIZE 3
++#define SYSREG_DLSZ_OFFSET 3
++#define SYSREG_DLSZ_SIZE 3
++#define SYSREG_DSET_OFFSET 6
++#define SYSREG_DSET_SIZE 4
++#define SYSREG_IASS_OFFSET 10
++#define SYSREG_IASS_SIZE 2
++#define SYSREG_ILSZ_OFFSET 13
++#define SYSREG_ILSZ_SIZE 3
++#define SYSREG_ISET_OFFSET 16
++#define SYSREG_ISET_SIZE 4
++#define SYSREG_DMMUSZ_OFFSET 20
++#define SYSREG_DMMUSZ_SIZE 6
++#define SYSREG_IMMUSZ_OFFSET 26
++#define SYSREG_IMMUSZ_SIZE 6
++
++/* Bitfields in COUNT */
++
++/* Bitfields in COMPARE */
++
++/* Bitfields in TLBEHI */
++#define SYSREG_ASID_OFFSET 0
++#define SYSREG_ASID_SIZE 8
++#define SYSREG_TLBEHI_I_OFFSET 8
++#define SYSREG_TLBEHI_I_SIZE 1
++#define SYSREG_TLBEHI_V_OFFSET 9
++#define SYSREG_TLBEHI_V_SIZE 1
++#define SYSREG_VPN_OFFSET 10
++#define SYSREG_VPN_SIZE 22
++
++/* Bitfields in TLBELO */
++#define SYSREG_W_OFFSET 0
++#define SYSREG_W_SIZE 1
++#define SYSREG_TLBELO_D_OFFSET 1
++#define SYSREG_TLBELO_D_SIZE 1
++#define SYSREG_SZ_OFFSET 2
++#define SYSREG_SZ_SIZE 2
++#define SYSREG_AP_OFFSET 4
++#define SYSREG_AP_SIZE 3
++#define SYSREG_B_OFFSET 7
++#define SYSREG_B_SIZE 1
++#define SYSREG_G_OFFSET 8
++#define SYSREG_G_SIZE 1
++#define SYSREG_TLBELO_C_OFFSET 9
++#define SYSREG_TLBELO_C_SIZE 1
++#define SYSREG_PFN_OFFSET 10
++#define SYSREG_PFN_SIZE 22
++
++/* Bitfields in PTBR */
++
++/* Bitfields in TLBEAR */
++
++/* Bitfields in MMUCR */
++#define SYSREG_E_OFFSET 0
++#define SYSREG_E_SIZE 1
++#define SYSREG_M_OFFSET 1
++#define SYSREG_M_SIZE 1
++#define SYSREG_MMUCR_I_OFFSET 2
++#define SYSREG_MMUCR_I_SIZE 1
++#define SYSREG_MMUCR_N_OFFSET 3
++#define SYSREG_MMUCR_N_SIZE 1
++#define SYSREG_MMUCR_S_OFFSET 4
++#define SYSREG_MMUCR_S_SIZE 1
++#define SYSREG_DLA_OFFSET 8
++#define SYSREG_DLA_SIZE 6
++#define SYSREG_DRP_OFFSET 14
++#define SYSREG_DRP_SIZE 6
++#define SYSREG_ILA_OFFSET 20
++#define SYSREG_ILA_SIZE 6
++#define SYSREG_IRP_OFFSET 26
++#define SYSREG_IRP_SIZE 6
++
++/* Bitfields in TLBARLO */
++
++/* Bitfields in TLBARHI */
++
++/* Bitfields in PCCNT */
++
++/* Bitfields in PCNT0 */
++
++/* Bitfields in PCNT1 */
++
++/* Bitfields in PCCR */
++
++/* Bitfields in BEAR */
++
++/* Constants for ECR */
++#define ECR_UNRECOVERABLE 0
++#define ECR_TLB_MULTIPLE 1
++#define ECR_BUS_ERROR_WRITE 2
++#define ECR_BUS_ERROR_READ 3
++#define ECR_NMI 4
++#define ECR_ADDR_ALIGN_X 5
++#define ECR_PROTECTION_X 6
++#define ECR_DEBUG 7
++#define ECR_ILLEGAL_OPCODE 8
++#define ECR_UNIMPL_INSTRUCTION 9
++#define ECR_PRIVILEGE_VIOLATION 10
++#define ECR_FPE 11
++#define ECR_COPROC_ABSENT 12
++#define ECR_ADDR_ALIGN_R 13
++#define ECR_ADDR_ALIGN_W 14
++#define ECR_PROTECTION_R 15
++#define ECR_PROTECTION_W 16
++#define ECR_DTLB_MODIFIED 17
++#define ECR_TLB_MISS_X 20
++#define ECR_TLB_MISS_R 24
++#define ECR_TLB_MISS_W 28
++
++/* Bit manipulation macros */
++#define SYSREG_BIT(name) (1 << SYSREG_##name##_OFFSET)
++#define SYSREG_BF(name,value) (((value) & ((1 << SYSREG_##name##_SIZE) - 1)) << SYSREG_##name##_OFFSET)
++#define SYSREG_BFEXT(name,value) (((value) >> SYSREG_##name##_OFFSET) & ((1 << SYSREG_##name##_SIZE) - 1))
++#define SYSREG_BFINS(name,value,old) (((old) & ~(((1 << SYSREG_##name##_SIZE) - 1) << SYSREG_##name##_OFFSET)) | SYSREG_BF(name,value))
++
++#ifdef __CHECKER__
++extern unsigned long __builtin_mfsr(unsigned long reg);
++extern void __builtin_mtsr(unsigned long reg, unsigned long value);
++#endif
++
++/* Register access macros */
++#define sysreg_read(reg) __builtin_mfsr(SYSREG_##reg)
++#define sysreg_write(reg, value) __builtin_mtsr(SYSREG_##reg, value)
++
++#endif /* __ASM_AVR32_SYSREG_H__ */
+diff --git a/include/asm-avr32/system.h b/include/asm-avr32/system.h
+new file mode 100644
+index 0000000..ac59605
+--- /dev/null
++++ b/include/asm-avr32/system.h
+@@ -0,0 +1,155 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_SYSTEM_H
++#define __ASM_AVR32_SYSTEM_H
++
++#include <linux/compiler.h>
++#include <linux/types.h>
++
++#include <asm/ptrace.h>
++#include <asm/sysreg.h>
++
++#define xchg(ptr,x) \
++ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
++
++#define nop() asm volatile("nop")
++
++#define mb() asm volatile("" : : : "memory")
++#define rmb() mb()
++#define wmb() asm volatile("sync 0" : : : "memory")
++#define read_barrier_depends() do { } while(0)
++#define set_mb(var, value) do { var = value; mb(); } while(0)
++
++/*
++ * Help PathFinder and other Nexus-compliant debuggers keep track of
++ * the current PID by emitting an Ownership Trace Message each time we
++ * switch task.
++ */
++#ifdef CONFIG_OWNERSHIP_TRACE
++#include <asm/ocd.h>
++#define finish_arch_switch(prev) \
++ do { \
++ __mtdr(DBGREG_PID, prev->pid); \
++ __mtdr(DBGREG_PID, current->pid); \
++ } while(0)
++#endif
++
++/*
++ * switch_to(prev, next, last) should switch from task `prev' to task
++ * `next'. `prev' will never be the same as `next'.
++ *
++ * We just delegate everything to the __switch_to assembly function,
++ * which is implemented in arch/avr32/kernel/switch_to.S
++ *
++ * mb() tells GCC not to cache `current' across this call.
++ */
++struct cpu_context;
++struct task_struct;
++extern struct task_struct *__switch_to(struct task_struct *,
++ struct cpu_context *,
++ struct cpu_context *);
++#define switch_to(prev, next, last) \
++ do { \
++ last = __switch_to(prev, &prev->thread.cpu_context + 1, \
++ &next->thread.cpu_context); \
++ } while (0)
++
++#ifdef CONFIG_SMP
++# error "The AVR32 port does not support SMP"
++#else
++# define smp_mb() barrier()
++# define smp_rmb() barrier()
++# define smp_wmb() barrier()
++# define smp_read_barrier_depends() do { } while(0)
++#endif
++
++#include <linux/irqflags.h>
++
++extern void __xchg_called_with_bad_pointer(void);
++
++#ifdef __CHECKER__
++extern unsigned long __builtin_xchg(void *ptr, unsigned long x);
++#endif
++
++#define xchg_u32(val, m) __builtin_xchg((void *)m, val)
++
++static inline unsigned long __xchg(unsigned long x,
++ volatile void *ptr,
++ int size)
++{
++ switch(size) {
++ case 4:
++ return xchg_u32(x, ptr);
++ default:
++ __xchg_called_with_bad_pointer();
++ return x;
++ }
++}
++
++static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
++ unsigned long new)
++{
++ __u32 ret;
++
++ asm volatile(
++ "1: ssrf 5\n"
++ " ld.w %[ret], %[m]\n"
++ " cp.w %[ret], %[old]\n"
++ " brne 2f\n"
++ " stcond %[m], %[new]\n"
++ " brne 1b\n"
++ "2:\n"
++ : [ret] "=&r"(ret), [m] "=m"(*m)
++ : "m"(m), [old] "ir"(old), [new] "r"(new)
++ : "memory", "cc");
++ return ret;
++}
++
++extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
++ volatile int * m, unsigned long old, unsigned long new);
++#define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
++
++/* 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);
++
++#define __HAVE_ARCH_CMPXCHG 1
++
++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);
++ case 8:
++ return __cmpxchg_u64(ptr, old, new);
++ }
++
++ __cmpxchg_called_with_bad_pointer();
++ return old;
++}
++
++#define cmpxchg(ptr, old, new) \
++ ((typeof(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), \
++ (unsigned long)(new), \
++ sizeof(*(ptr))))
++
++struct pt_regs;
++extern void __die(const char *, struct pt_regs *, unsigned long,
++ const char *, const char *, unsigned long);
++extern void __die_if_kernel(const char *, struct pt_regs *, unsigned long,
++ const char *, const char *, unsigned long);
++
++#define die(msg, regs, err) \
++ __die(msg, regs, err, __FILE__ ":", __FUNCTION__, __LINE__)
++#define die_if_kernel(msg, regs, err) \
++ __die_if_kernel(msg, regs, err, __FILE__ ":", __FUNCTION__, __LINE__)
++
++#define arch_align_stack(x) (x)
++
++#endif /* __ASM_AVR32_SYSTEM_H */
+diff --git a/include/asm-avr32/termbits.h b/include/asm-avr32/termbits.h
+new file mode 100644
+index 0000000..9dc6eac
+--- /dev/null
++++ b/include/asm-avr32/termbits.h
+@@ -0,0 +1,173 @@
++#ifndef __ASM_AVR32_TERMBITS_H
++#define __ASM_AVR32_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 /* __ASM_AVR32_TERMBITS_H */
+diff --git a/include/asm-avr32/termios.h b/include/asm-avr32/termios.h
+new file mode 100644
+index 0000000..615bc06
+--- /dev/null
++++ b/include/asm-avr32/termios.h
+@@ -0,0 +1,80 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_TERMIOS_H
++#define __ASM_AVR32_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 at cafe.net> */
++#define N_R3964 9 /* Reserved for Simatic R3964 module */
++#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave at 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 /* synchronous PPP */
++#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"
++
++#include <asm-generic/termios.h>
++
++#endif /* __KERNEL__ */
++
++#endif /* __ASM_AVR32_TERMIOS_H */
+diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
+new file mode 100644
+index 0000000..d1f5b35
+--- /dev/null
++++ b/include/asm-avr32/thread_info.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_THREAD_INFO_H
++#define __ASM_AVR32_THREAD_INFO_H
++
++#include <asm/page.h>
++
++#define THREAD_SIZE_ORDER 1
++#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
++
++#ifndef __ASSEMBLY__
++#include <asm/types.h>
++
++struct task_struct;
++struct exec_domain;
++
++struct thread_info {
++ struct task_struct *task; /* main task structure */
++ struct exec_domain *exec_domain; /* execution domain */
++ unsigned long flags; /* low level flags */
++ __u32 cpu;
++ __s32 preempt_count; /* 0 => preemptable, <0 => BUG */
++ struct restart_block restart_block;
++ __u8 supervisor_stack[0];
++};
++
++#define INIT_THREAD_INFO(tsk) \
++{ \
++ .task = &tsk, \
++ .exec_domain = &default_exec_domain, \
++ .flags = 0, \
++ .cpu = 0, \
++ .preempt_count = 1, \
++ .restart_block = { \
++ .fn = do_no_restart_syscall \
++ } \
++}
++
++#define init_thread_info (init_thread_union.thread_info)
++#define init_stack (init_thread_union.stack)
++
++/*
++ * Get the thread information struct from C.
++ * We do the usual trick and use the lower end of the stack for this
++ */
++static inline struct thread_info *current_thread_info(void)
++{
++ unsigned long addr = ~(THREAD_SIZE - 1);
++
++ asm("and %0, sp" : "=r"(addr) : "0"(addr));
++ return (struct thread_info *)addr;
++}
++
++/* thread information allocation */
++#define alloc_thread_info(ti) \
++ ((struct thread_info *) __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER))
++#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)
++
++#endif /* !__ASSEMBLY__ */
++
++#define PREEMPT_ACTIVE 0x40000000
++
++/*
++ * 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_POLLING_NRFLAG 4 /* true if poll_idle() is polling
++ TIF_NEED_RESCHED */
++#define TIF_BREAKPOINT 5 /* true if we should break after return */
++#define TIF_SINGLE_STEP 6 /* single step after next break */
++#define TIF_MEMDIE 7
++#define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal */
++#define TIF_USERSPACE 31 /* true if FS sets userspace */
++
++#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_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
++#define _TIF_BREAKPOINT (1 << TIF_BREAKPOINT)
++#define _TIF_SINGLE_STEP (1 << TIF_SINGLE_STEP)
++#define _TIF_MEMDIE (1 << TIF_MEMDIE)
++#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
++
++/* XXX: These two masks must never span more than 16 bits! */
++/* work to do on interrupt/exception return */
++#define _TIF_WORK_MASK 0x0000013e
++/* work to do on any return to userspace */
++#define _TIF_ALLWORK_MASK 0x0000013f
++/* work to do on return from debug mode */
++#define _TIF_DBGWORK_MASK 0x0000017e
++
++#endif /* __ASM_AVR32_THREAD_INFO_H */
+diff --git a/include/asm-avr32/timex.h b/include/asm-avr32/timex.h
+new file mode 100644
+index 0000000..5e44ecb
+--- /dev/null
++++ b/include/asm-avr32/timex.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_TIMEX_H
++#define __ASM_AVR32_TIMEX_H
++
++/*
++ * This is the frequency of the timer used for Linux's timer interrupt.
++ * The value should be defined as accurate as possible or under certain
++ * circumstances Linux timekeeping might become inaccurate or fail.
++ *
++ * For many system the exact clockrate of the timer isn't known but due to
++ * the way this value is used we can get away with a wrong value as long
++ * as this value is:
++ *
++ * - a multiple of HZ
++ * - a divisor of the actual rate
++ *
++ * 500000 is a good such cheat value.
++ *
++ * The obscure number 1193182 is the same as used by the original i8254
++ * time in legacy PC hardware; the chip is never found in AVR32 systems.
++ */
++#define CLOCK_TICK_RATE 500000 /* Underlying HZ */
++
++typedef unsigned long cycles_t;
++
++static inline cycles_t get_cycles (void)
++{
++ return 0;
++}
++
++extern int read_current_timer(unsigned long *timer_value);
++#define ARCH_HAS_READ_CURRENT_TIMER 1
++
++#endif /* __ASM_AVR32_TIMEX_H */
+diff --git a/include/asm-avr32/tlb.h b/include/asm-avr32/tlb.h
+new file mode 100644
+index 0000000..5c55f9c
+--- /dev/null
++++ b/include/asm-avr32/tlb.h
+@@ -0,0 +1,32 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_TLB_H
++#define __ASM_AVR32_TLB_H
++
++#define tlb_start_vma(tlb, vma) \
++ flush_cache_range(vma, vma->vm_start, vma->vm_end)
++
++#define tlb_end_vma(tlb, vma) \
++ flush_tlb_range(vma, vma->vm_start, vma->vm_end)
++
++#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while(0)
++
++/*
++ * Flush whole TLB for MM
++ */
++#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
++
++#include <asm-generic/tlb.h>
++
++/*
++ * For debugging purposes
++ */
++extern void show_dtlb_entry(unsigned int index);
++extern void dump_dtlb(void);
++
++#endif /* __ASM_AVR32_TLB_H */
+diff --git a/include/asm-avr32/tlbflush.h b/include/asm-avr32/tlbflush.h
+new file mode 100644
+index 0000000..730e268
+--- /dev/null
++++ b/include/asm-avr32/tlbflush.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_TLBFLUSH_H
++#define __ASM_AVR32_TLBFLUSH_H
++
++#include <asm/mmu.h>
++
++/*
++ * TLB flushing:
++ *
++ * - flush_tlb() flushes the current mm struct TLBs
++ * - flush_tlb_all() flushes all processes' TLB entries
++ * - flush_tlb_mm(mm) flushes the specified mm context TLBs
++ * - flush_tlb_page(vma, vmaddr) flushes one page
++ * - flush_tlb_range(vma, start, end) flushes a range of pages
++ * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
++ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
++ */
++extern void flush_tlb(void);
++extern void flush_tlb_all(void);
++extern void flush_tlb_mm(struct mm_struct *mm);
++extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end);
++extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
++extern void __flush_tlb_page(unsigned long asid, unsigned long page);
++
++static inline void flush_tlb_pgtables(struct mm_struct *mm,
++ unsigned long start, unsigned long end)
++{
++ /* Nothing to do */
++}
++
++extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
++
++#endif /* __ASM_AVR32_TLBFLUSH_H */
+diff --git a/include/asm-avr32/topology.h b/include/asm-avr32/topology.h
+new file mode 100644
+index 0000000..5b766cb
+--- /dev/null
++++ b/include/asm-avr32/topology.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_AVR32_TOPOLOGY_H
++#define __ASM_AVR32_TOPOLOGY_H
++
++#include <asm-generic/topology.h>
++
++#endif /* __ASM_AVR32_TOPOLOGY_H */
+diff --git a/include/asm-avr32/traps.h b/include/asm-avr32/traps.h
+new file mode 100644
+index 0000000..6a8fb94
+--- /dev/null
++++ b/include/asm-avr32/traps.h
+@@ -0,0 +1,23 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_TRAPS_H
++#define __ASM_AVR32_TRAPS_H
++
++#include <linux/list.h>
++
++struct undef_hook {
++ struct list_head node;
++ u32 insn_mask;
++ u32 insn_val;
++ int (*fn)(struct pt_regs *regs, u32 insn);
++};
++
++void register_undef_hook(struct undef_hook *hook);
++void unregister_undef_hook(struct undef_hook *hook);
++
++#endif /* __ASM_AVR32_TRAPS_H */
+diff --git a/include/asm-avr32/types.h b/include/asm-avr32/types.h
+new file mode 100644
+index 0000000..3f47db9
+--- /dev/null
++++ b/include/asm-avr32/types.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_TYPES_H
++#define __ASM_AVR32_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
++
++#endif /* __ASSEMBLY__ */
++
++/*
++ * These aren't exported outside the kernel to avoid name space clashes
++ */
++#ifdef __KERNEL__
++
++#define BITS_PER_LONG 32
++
++#ifndef __ASSEMBLY__
++
++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;
++
++/* Dma addresses are 32-bits wide. */
++
++typedef u32 dma_addr_t;
++
++#ifdef CONFIG_LBD
++typedef u64 sector_t;
++#define HAVE_SECTOR_T
++#endif
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __KERNEL__ */
++
++
++#endif /* __ASM_AVR32_TYPES_H */
+diff --git a/include/asm-avr32/uaccess.h b/include/asm-avr32/uaccess.h
+new file mode 100644
+index 0000000..821deb5
+--- /dev/null
++++ b/include/asm-avr32/uaccess.h
+@@ -0,0 +1,335 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_UACCESS_H
++#define __ASM_AVR32_UACCESS_H
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++
++#define VERIFY_READ 0
++#define VERIFY_WRITE 1
++
++typedef struct {
++ unsigned int is_user_space;
++} mm_segment_t;
++
++/*
++ * 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 misnamed.
++ */
++#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
++#define segment_eq(a,b) ((a).is_user_space == (b).is_user_space)
++
++#define USER_ADDR_LIMIT 0x80000000
++
++#define KERNEL_DS MAKE_MM_SEG(0)
++#define USER_DS MAKE_MM_SEG(1)
++
++#define get_ds() (KERNEL_DS)
++
++static inline mm_segment_t get_fs(void)
++{
++ return MAKE_MM_SEG(test_thread_flag(TIF_USERSPACE));
++}
++
++static inline void set_fs(mm_segment_t s)
++{
++ if (s.is_user_space)
++ set_thread_flag(TIF_USERSPACE);
++ else
++ clear_thread_flag(TIF_USERSPACE);
++}
++
++/*
++ * Test whether a block of memory is a valid user space address.
++ * Returns 0 if the range is valid, nonzero otherwise.
++ *
++ * We do the following checks:
++ * 1. Is the access from kernel space?
++ * 2. Does (addr + size) set the carry bit?
++ * 3. Is (addr + size) a negative number (i.e. >= 0x80000000)?
++ *
++ * If yes on the first check, access is granted.
++ * If no on any of the others, access is denied.
++ */
++#define __range_ok(addr, size) \
++ (test_thread_flag(TIF_USERSPACE) \
++ && (((unsigned long)(addr) >= 0x80000000) \
++ || ((unsigned long)(size) > 0x80000000) \
++ || (((unsigned long)(addr) + (unsigned long)(size)) > 0x80000000)))
++
++#define access_ok(type, addr, size) (likely(__range_ok(addr, size) == 0))
++
++static inline int
++verify_area(int type, const void __user *addr, unsigned long size)
++{
++ return access_ok(type, addr, size) ? 0 : -EFAULT;
++}
++
++/* Generic arbitrary sized copy. Return the number of bytes NOT copied */
++extern __kernel_size_t __copy_user(void *to, const void *from,
++ __kernel_size_t n);
++
++extern __kernel_size_t copy_to_user(void __user *to, const void *from,
++ __kernel_size_t n);
++extern __kernel_size_t copy_from_user(void *to, const void __user *from,
++ __kernel_size_t n);
++
++static inline __kernel_size_t __copy_to_user(void __user *to, const void *from,
++ __kernel_size_t n)
++{
++ return __copy_user((void __force *)to, from, n);
++}
++static inline __kernel_size_t __copy_from_user(void *to,
++ const void __user *from,
++ __kernel_size_t n)
++{
++ return __copy_user(to, (const void __force *)from, n);
++}
++
++#define __copy_to_user_inatomic __copy_to_user
++#define __copy_from_user_inatomic __copy_from_user
++
++/*
++ * put_user: - Write a simple value into user space.
++ * @x: Value to copy to user space.
++ * @ptr: Destination address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple value from kernel space to user
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
++ * to the result of dereferencing @ptr.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ */
++#define put_user(x,ptr) \
++ __put_user_check((x),(ptr),sizeof(*(ptr)))
++
++/*
++ * get_user: - Get a simple variable from user space.
++ * @x: Variable to store result.
++ * @ptr: Source address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple variable from user space to kernel
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and the result of
++ * dereferencing @ptr must be assignable to @x without a cast.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ * On error, the variable @x is set to zero.
++ */
++#define get_user(x,ptr) \
++ __get_user_check((x),(ptr),sizeof(*(ptr)))
++
++/*
++ * __put_user: - Write a simple value into user space, with less checking.
++ * @x: Value to copy to user space.
++ * @ptr: Destination address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple value from kernel space to user
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
++ * to the result of dereferencing @ptr.
++ *
++ * Caller must check the pointer with access_ok() before calling this
++ * function.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ */
++#define __put_user(x,ptr) \
++ __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
++
++/*
++ * __get_user: - Get a simple variable from user space, with less checking.
++ * @x: Variable to store result.
++ * @ptr: Source address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple variable from user space to kernel
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and the result of
++ * dereferencing @ptr must be assignable to @x without a cast.
++ *
++ * Caller must check the pointer with access_ok() before calling this
++ * function.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ * On error, the variable @x is set to zero.
++ */
++#define __get_user(x,ptr) \
++ __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
++
++extern int __get_user_bad(void);
++extern int __put_user_bad(void);
++
++#define __get_user_nocheck(x, ptr, size) \
++({ \
++ typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0; \
++ int __gu_err = 0; \
++ \
++ switch (size) { \
++ case 1: __get_user_asm("ub", __gu_val, ptr, __gu_err); break; \
++ case 2: __get_user_asm("uh", __gu_val, ptr, __gu_err); break; \
++ case 4: __get_user_asm("w", __gu_val, ptr, __gu_err); break; \
++ case 8: __get_user_asm("d", __gu_val, ptr, __gu_err); break; \
++ default: __gu_err = __get_user_bad(); break; \
++ } \
++ \
++ x = __gu_val; \
++ __gu_err; \
++})
++
++#define __get_user_check(x, ptr, size) \
++({ \
++ typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0; \
++ const typeof(*(ptr)) __user * __gu_addr = (ptr); \
++ int __gu_err = 0; \
++ \
++ if (access_ok(VERIFY_READ, __gu_addr, size)) { \
++ switch (size) { \
++ case 1: \
++ __get_user_asm("ub", __gu_val, __gu_addr, \
++ __gu_err); \
++ break; \
++ case 2: \
++ __get_user_asm("uh", __gu_val, __gu_addr, \
++ __gu_err); \
++ break; \
++ case 4: \
++ __get_user_asm("w", __gu_val, __gu_addr, \
++ __gu_err); \
++ break; \
++ case 8: \
++ __get_user_asm("d", __gu_val, __gu_addr, \
++ __gu_err); \
++ break; \
++ default: \
++ __gu_err = __get_user_bad(); \
++ break; \
++ } \
++ } else { \
++ __gu_err = -EFAULT; \
++ } \
++ x = __gu_val; \
++ __gu_err; \
++})
++
++#define __get_user_asm(suffix, __gu_val, ptr, __gu_err) \
++ asm volatile( \
++ "1: ld." suffix " %1, %3 \n" \
++ "2: \n" \
++ " .section .fixup, \"ax\" \n" \
++ "3: mov %0, %4 \n" \
++ " rjmp 2b \n" \
++ " .previous \n" \
++ " .section __ex_table, \"a\" \n" \
++ " .long 1b, 3b \n" \
++ " .previous \n" \
++ : "=r"(__gu_err), "=r"(__gu_val) \
++ : "0"(__gu_err), "m"(*(ptr)), "i"(-EFAULT))
++
++#define __put_user_nocheck(x, ptr, size) \
++({ \
++ typeof(*(ptr)) __pu_val; \
++ int __pu_err = 0; \
++ \
++ __pu_val = (x); \
++ switch (size) { \
++ case 1: __put_user_asm("b", ptr, __pu_val, __pu_err); break; \
++ case 2: __put_user_asm("h", ptr, __pu_val, __pu_err); break; \
++ case 4: __put_user_asm("w", ptr, __pu_val, __pu_err); break; \
++ case 8: __put_user_asm("d", ptr, __pu_val, __pu_err); break; \
++ default: __pu_err = __put_user_bad(); break; \
++ } \
++ __pu_err; \
++})
++
++#define __put_user_check(x, ptr, size) \
++({ \
++ typeof(*(ptr)) __pu_val; \
++ typeof(*(ptr)) __user *__pu_addr = (ptr); \
++ int __pu_err = 0; \
++ \
++ __pu_val = (x); \
++ if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \
++ switch (size) { \
++ case 1: \
++ __put_user_asm("b", __pu_addr, __pu_val, \
++ __pu_err); \
++ break; \
++ case 2: \
++ __put_user_asm("h", __pu_addr, __pu_val, \
++ __pu_err); \
++ break; \
++ case 4: \
++ __put_user_asm("w", __pu_addr, __pu_val, \
++ __pu_err); \
++ break; \
++ case 8: \
++ __put_user_asm("d", __pu_addr, __pu_val, \
++ __pu_err); \
++ break; \
++ default: \
++ __pu_err = __put_user_bad(); \
++ break; \
++ } \
++ } else { \
++ __pu_err = -EFAULT; \
++ } \
++ __pu_err; \
++})
++
++#define __put_user_asm(suffix, ptr, __pu_val, __gu_err) \
++ asm volatile( \
++ "1: st." suffix " %1, %3 \n" \
++ "2: \n" \
++ " .section .fixup, \"ax\" \n" \
++ "3: mov %0, %4 \n" \
++ " rjmp 2b \n" \
++ " .previous \n" \
++ " .section __ex_table, \"a\" \n" \
++ " .long 1b, 3b \n" \
++ " .previous \n" \
++ : "=r"(__gu_err), "=m"(*(ptr)) \
++ : "0"(__gu_err), "r"(__pu_val), "i"(-EFAULT))
++
++extern __kernel_size_t clear_user(void __user *addr, __kernel_size_t size);
++extern __kernel_size_t __clear_user(void __user *addr, __kernel_size_t size);
++
++extern long strncpy_from_user(char *dst, const char __user *src, long count);
++extern long __strncpy_from_user(char *dst, const char __user *src, long count);
++
++extern long strnlen_user(const char __user *__s, long __n);
++extern long __strnlen_user(const char __user *__s, long __n);
++
++#define strlen_user(s) strnlen_user(s, ~0UL >> 1)
++
++struct exception_table_entry
++{
++ unsigned long insn, fixup;
++};
++
++#endif /* __ASM_AVR32_UACCESS_H */
+diff --git a/include/asm-avr32/ucontext.h b/include/asm-avr32/ucontext.h
+new file mode 100644
+index 0000000..ac7259c
+--- /dev/null
++++ b/include/asm-avr32/ucontext.h
+@@ -0,0 +1,12 @@
++#ifndef __ASM_AVR32_UCONTEXT_H
++#define __ASM_AVR32_UCONTEXT_H
++
++struct ucontext {
++ unsigned long uc_flags;
++ struct ucontext * uc_link;
++ stack_t uc_stack;
++ struct sigcontext uc_mcontext;
++ sigset_t uc_sigmask;
++};
++
++#endif /* __ASM_AVR32_UCONTEXT_H */
+diff --git a/include/asm-avr32/unaligned.h b/include/asm-avr32/unaligned.h
+new file mode 100644
+index 0000000..3042723
+--- /dev/null
++++ b/include/asm-avr32/unaligned.h
+@@ -0,0 +1,25 @@
++#ifndef __ASM_AVR32_UNALIGNED_H
++#define __ASM_AVR32_UNALIGNED_H
++
++/*
++ * AVR32 can handle some unaligned accesses, depending on the
++ * implementation. The AVR32 AP implementation can handle unaligned
++ * words, but halfwords must be halfword-aligned, and doublewords must
++ * be word-aligned.
++ *
++ * TODO: Make all this CPU-specific and optimize.
++ */
++
++#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 /* __ASM_AVR32_UNALIGNED_H */
+diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h
+new file mode 100644
+index 0000000..56ed1f9
+--- /dev/null
++++ b/include/asm-avr32/unistd.h
+@@ -0,0 +1,314 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ */
++#ifndef __ASM_AVR32_UNISTD_H
++#define __ASM_AVR32_UNISTD_H
++
++/*
++ * This file contains the system call numbers.
++ */
++
++#define __NR_restart_syscall 0
++#define __NR_exit 1
++#define __NR_fork 2
++#define __NR_read 3
++#define __NR_write 4
++#define __NR_open 5
++#define __NR_close 6
++#define __NR_umask 7
++#define __NR_creat 8
++#define __NR_link 9
++#define __NR_unlink 10
++#define __NR_execve 11
++#define __NR_chdir 12
++#define __NR_time 13
++#define __NR_mknod 14
++#define __NR_chmod 15
++#define __NR_chown 16
++#define __NR_lchown 17
++#define __NR_lseek 18
++#define __NR__llseek 19
++#define __NR_getpid 20
++#define __NR_mount 21
++#define __NR_umount2 22
++#define __NR_setuid 23
++#define __NR_getuid 24
++#define __NR_stime 25
++#define __NR_ptrace 26
++#define __NR_alarm 27
++#define __NR_pause 28
++#define __NR_utime 29
++#define __NR_stat 30
++#define __NR_fstat 31
++#define __NR_lstat 32
++#define __NR_access 33
++#define __NR_chroot 34
++#define __NR_sync 35
++#define __NR_fsync 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_clone 44
++#define __NR_brk 45
++#define __NR_setgid 46
++#define __NR_getgid 47
++#define __NR_getcwd 48
++#define __NR_geteuid 49
++#define __NR_getegid 50
++#define __NR_acct 51
++#define __NR_setfsuid 52
++#define __NR_setfsgid 53
++#define __NR_ioctl 54
++#define __NR_fcntl 55
++#define __NR_setpgid 56
++#define __NR_mremap 57
++#define __NR_setresuid 58
++#define __NR_getresuid 59
++#define __NR_setreuid 60
++#define __NR_setregid 61
++#define __NR_ustat 62
++#define __NR_dup2 63
++#define __NR_getppid 64
++#define __NR_getpgrp 65
++#define __NR_setsid 66
++#define __NR_rt_sigaction 67
++#define __NR_rt_sigreturn 68
++#define __NR_rt_sigprocmask 69
++#define __NR_rt_sigpending 70
++#define __NR_rt_sigtimedwait 71
++#define __NR_rt_sigqueueinfo 72
++#define __NR_rt_sigsuspend 73
++#define __NR_sethostname 74
++#define __NR_setrlimit 75
++#define __NR_getrlimit 76 /* SuS compliant getrlimit */
++#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_fchdir 84
++#define __NR_readlink 85
++#define __NR_pread 86
++#define __NR_pwrite 87
++#define __NR_swapon 88
++#define __NR_reboot 89
++#define __NR_mmap2 90
++#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_wait4 98
++#define __NR_statfs 99
++#define __NR_fstatfs 100
++#define __NR_vhangup 101
++#define __NR_sigaltstack 102
++#define __NR_syslog 103
++#define __NR_setitimer 104
++#define __NR_getitimer 105
++#define __NR_swapoff 106
++#define __NR_sysinfo 107
++#define __NR_ipc 108
++#define __NR_sendfile 109
++#define __NR_setdomainname 110
++#define __NR_uname 111
++#define __NR_adjtimex 112
++#define __NR_mprotect 113
++#define __NR_vfork 114
++#define __NR_init_module 115
++#define __NR_delete_module 116
++#define __NR_quotactl 117
++#define __NR_getpgid 118
++#define __NR_bdflush 119
++#define __NR_sysfs 120
++#define __NR_personality 121
++#define __NR_afs_syscall 122 /* Syscall for Andrew File System */
++#define __NR_getdents 123
++#define __NR_flock 124
++#define __NR_msync 125
++#define __NR_readv 126
++#define __NR_writev 127
++#define __NR_getsid 128
++#define __NR_fdatasync 129
++#define __NR__sysctl 130
++#define __NR_mlock 131
++#define __NR_munlock 132
++#define __NR_mlockall 133
++#define __NR_munlockall 134
++#define __NR_sched_setparam 135
++#define __NR_sched_getparam 136
++#define __NR_sched_setscheduler 137
++#define __NR_sched_getscheduler 138
++#define __NR_sched_yield 139
++#define __NR_sched_get_priority_max 140
++#define __NR_sched_get_priority_min 141
++#define __NR_sched_rr_get_interval 142
++#define __NR_nanosleep 143
++#define __NR_poll 144
++#define __NR_nfsservctl 145
++#define __NR_setresgid 146
++#define __NR_getresgid 147
++#define __NR_prctl 148
++#define __NR_socket 149
++#define __NR_bind 150
++#define __NR_connect 151
++#define __NR_listen 152
++#define __NR_accept 153
++#define __NR_getsockname 154
++#define __NR_getpeername 155
++#define __NR_socketpair 156
++#define __NR_send 157
++#define __NR_recv 158
++#define __NR_sendto 159
++#define __NR_recvfrom 160
++#define __NR_shutdown 161
++#define __NR_setsockopt 162
++#define __NR_getsockopt 163
++#define __NR_sendmsg 164
++#define __NR_recvmsg 165
++#define __NR_truncate64 166
++#define __NR_ftruncate64 167
++#define __NR_stat64 168
++#define __NR_lstat64 169
++#define __NR_fstat64 170
++#define __NR_pivot_root 171
++#define __NR_mincore 172
++#define __NR_madvise 173
++#define __NR_getdents64 174
++#define __NR_fcntl64 175
++#define __NR_gettid 176
++#define __NR_readahead 177
++#define __NR_setxattr 178
++#define __NR_lsetxattr 179
++#define __NR_fsetxattr 180
++#define __NR_getxattr 181
++#define __NR_lgetxattr 182
++#define __NR_fgetxattr 183
++#define __NR_listxattr 184
++#define __NR_llistxattr 185
++#define __NR_flistxattr 186
++#define __NR_removexattr 187
++#define __NR_lremovexattr 188
++#define __NR_fremovexattr 189
++#define __NR_tkill 190
++#define __NR_sendfile64 191
++#define __NR_futex 192
++#define __NR_sched_setaffinity 193
++#define __NR_sched_getaffinity 194
++#define __NR_capget 195
++#define __NR_capset 196
++#define __NR_io_setup 197
++#define __NR_io_destroy 198
++#define __NR_io_getevents 199
++#define __NR_io_submit 200
++#define __NR_io_cancel 201
++#define __NR_fadvise64 202
++#define __NR_exit_group 203
++#define __NR_lookup_dcookie 204
++#define __NR_epoll_create 205
++#define __NR_epoll_ctl 206
++#define __NR_epoll_wait 207
++#define __NR_remap_file_pages 208
++#define __NR_set_tid_address 209
++
++#define __NR_timer_create 210
++#define __NR_timer_settime 211
++#define __NR_timer_gettime 212
++#define __NR_timer_getoverrun 213
++#define __NR_timer_delete 214
++#define __NR_clock_settime 215
++#define __NR_clock_gettime 216
++#define __NR_clock_getres 217
++#define __NR_clock_nanosleep 218
++#define __NR_statfs64 219
++#define __NR_fstatfs64 220
++#define __NR_tgkill 221
++ /* 222 reserved for tux */
++#define __NR_utimes 223
++#define __NR_fadvise64_64 224
++
++#define __NR_cacheflush 225
++
++#define __NR_vserver 226
++#define __NR_mq_open 227
++#define __NR_mq_unlink 228
++#define __NR_mq_timedsend 229
++#define __NR_mq_timedreceive 230
++#define __NR_mq_notify 231
++#define __NR_mq_getsetattr 232
++#define __NR_kexec_load 233
++#define __NR_waitid 234
++#define __NR_add_key 235
++#define __NR_request_key 236
++#define __NR_keyctl 237
++#define __NR_ioprio_set 238
++#define __NR_ioprio_get 239
++#define __NR_inotify_init 240
++#define __NR_inotify_add_watch 241
++#define __NR_inotify_rm_watch 242
++#define __NR_openat 243
++#define __NR_mkdirat 244
++#define __NR_mknodat 245
++#define __NR_fchownat 246
++#define __NR_futimesat 247
++#define __NR_fstatat64 248
++#define __NR_unlinkat 249
++#define __NR_renameat 250
++#define __NR_linkat 251
++#define __NR_symlinkat 252
++#define __NR_readlinkat 253
++#define __NR_fchmodat 254
++#define __NR_faccessat 255
++#define __NR_pselect6 256
++#define __NR_ppoll 257
++#define __NR_unshare 258
++#define __NR_set_robust_list 259
++#define __NR_get_robust_list 260
++#define __NR_splice 261
++#define __NR_sync_file_range 262
++#define __NR_tee 263
++#define __NR_vmsplice 264
++#define __NR_epoll_pwait 265
++
++#ifdef __KERNEL__
++#define NR_syscalls 266
++
++
++#define __ARCH_WANT_IPC_PARSE_VERSION
++#define __ARCH_WANT_STAT64
++#define __ARCH_WANT_SYS_ALARM
++#define __ARCH_WANT_SYS_GETHOSTNAME
++#define __ARCH_WANT_SYS_PAUSE
++#define __ARCH_WANT_SYS_TIME
++#define __ARCH_WANT_SYS_UTIME
++#define __ARCH_WANT_SYS_WAITPID
++#define __ARCH_WANT_SYS_FADVISE64
++#define __ARCH_WANT_SYS_GETPGRP
++#define __ARCH_WANT_SYS_LLSEEK
++#define __ARCH_WANT_SYS_GETPGRP
++#define __ARCH_WANT_SYS_RT_SIGACTION
++#define __ARCH_WANT_SYS_RT_SIGSUSPEND
++
++/*
++ * "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");
++
++#endif /* __KERNEL__ */
++
++#endif /* __ASM_AVR32_UNISTD_H */
+diff --git a/include/asm-avr32/user.h b/include/asm-avr32/user.h
+new file mode 100644
+index 0000000..060fb3a
+--- /dev/null
++++ b/include/asm-avr32/user.h
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2004-2006 Atmel 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.
++ *
++ * Note: We may not need these definitions for AVR32, as we don't
++ * support a.out.
++ */
++#ifndef __ASM_AVR32_USER_H
++#define __ASM_AVR32_USER_H
++
++#include <linux/types.h>
++#include <asm/ptrace.h>
++#include <asm/page.h>
++
++/*
++ * Core file format: The core file is written in such a way that gdb
++ * can understand it and provide useful information to the user (under
++ * linux we use the `trad-core' bfd). The file contents are as follows:
++ *
++ * upage: 1 page consisting of a user struct that tells gdb
++ * what is present in the file. Directly after this is a
++ * copy of the task_struct, which is currently not used by gdb,
++ * but it may come in handy at some point. All of the registers
++ * are stored as part of the upage. The upage should always be
++ * only one page long.
++ * data: The data segment follows next. We use current->end_text to
++ * current->brk to pick up all of the user variables, plus any memory
++ * that may have been sbrk'ed. No attempt is made to determine if a
++ * page is demand-zero or if a page is totally unused, we just cover
++ * the entire range. All of the addresses are rounded in such a way
++ * that an integral number of pages is written.
++ * stack: We need the stack information in order to get a meaningful
++ * backtrace. We need to write the data from usp to
++ * current->start_stack, so we round each of these in order to be able
++ * to write an integer number of pages.
++ */
++
++struct user_fpu_struct {
++ /* We have no FPU (yet) */
++};
++
++struct user {
++ struct pt_regs regs; /* entire machine state */
++ size_t u_tsize; /* text size (pages) */
++ size_t u_dsize; /* data size (pages) */
++ size_t u_ssize; /* stack size (pages) */
++ unsigned long start_code; /* text starting address */
++ unsigned long start_data; /* data starting address */
++ unsigned long start_stack; /* stack starting address */
++ long int signal; /* signal causing core dump */
++ struct regs * u_ar0; /* help gdb find registers */
++ unsigned long magic; /* identifies a core file */
++ char u_comm[32]; /* user command name */
++};
++
++#define NBPG PAGE_SIZE
++#define UPAGES 1
++#define HOST_TEXT_START_ADDR (u.start_code)
++#define HOST_DATA_START_ADDR (u.start_data)
++#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
++
++#endif /* __ASM_AVR32_USER_H */
+diff --git a/include/asm-cris/Kbuild b/include/asm-cris/Kbuild
+index c68e168..14498d5 100644
+--- a/include/asm-cris/Kbuild
++++ b/include/asm-cris/Kbuild
+@@ -1 +1,5 @@
+ include include/asm-generic/Kbuild.asm
++
++header-y += arch-v10/ arch-v32/
++
++unifdef-y += rs485.h
+diff --git a/include/asm-cris/arch-v10/Kbuild b/include/asm-cris/arch-v10/Kbuild
+new file mode 100644
+index 0000000..d7f27dc
+--- /dev/null
++++ b/include/asm-cris/arch-v10/Kbuild
+@@ -0,0 +1,2 @@
++header-y += ptrace.h
++header-y += user.h
+diff --git a/include/asm-cris/arch-v32/Kbuild b/include/asm-cris/arch-v32/Kbuild
+new file mode 100644
+index 0000000..d7f27dc
+--- /dev/null
++++ b/include/asm-cris/arch-v32/Kbuild
+@@ -0,0 +1,2 @@
++header-y += ptrace.h
++header-y += user.h
+diff --git a/include/asm-cris/arch-v32/spinlock.h b/include/asm-cris/arch-v32/spinlock.h
+index 52df72a..5f43df0 100644
+--- a/include/asm-cris/arch-v32/spinlock.h
++++ b/include/asm-cris/arch-v32/spinlock.h
+@@ -160,4 +160,8 @@ static __inline__ int is_write_locked(rw
+ return rw->counter < 0;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_ARCH_SPINLOCK_H */
+diff --git a/include/asm-cris/byteorder.h b/include/asm-cris/byteorder.h
+index a1a222a..0cd9db1 100644
+--- a/include/asm-cris/byteorder.h
++++ b/include/asm-cris/byteorder.h
+@@ -3,14 +3,15 @@
+
+ #ifdef __GNUC__
+
++#ifdef __KERNEL__
+ #include <asm/arch/byteorder.h>
+
+ /* defines are necessary because the other files detect the presence
+ * of a defined __arch_swab32, not an inline
+ */
+-
+ #define __arch__swab32(x) ___arch__swab32(x)
+ #define __arch__swab16(x) ___arch__swab16(x)
++#endif /* __KERNEL__ */
+
+ #if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+ # define __BYTEORDER_HAS_U64__
+diff --git a/include/asm-cris/elf.h b/include/asm-cris/elf.h
+index 87a60bd..96a40c1 100644
+--- a/include/asm-cris/elf.h
++++ b/include/asm-cris/elf.h
+@@ -5,7 +5,6 @@
+ * ELF register definitions..
+ */
+
+-#include <asm/arch/elf.h>
+ #include <asm/user.h>
+
+ #define R_CRIS_NONE 0
+@@ -46,6 +45,9 @@ typedef unsigned long elf_fpregset_t;
+ #define ELF_DATA ELFDATA2LSB
+ #define ELF_ARCH EM_CRIS
+
++#ifdef __KERNEL__
++#include <asm/arch/elf.h>
++
+ /* The master for these definitions is {binutils}/include/elf/cris.h: */
+ /* User symbols in this file have a leading underscore. */
+ #define EF_CRIS_UNDERSCORE 0x00000001
+@@ -87,8 +89,8 @@ typedef unsigned long elf_fpregset_t;
+
+ #define ELF_PLATFORM (NULL)
+
+-#ifdef __KERNEL__
+ #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+-#endif
++
++#endif /* __KERNEL__ */
+
+ #endif
+diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h
+index 81832e9..9f13c32 100644
+--- a/include/asm-cris/page.h
++++ b/include/asm-cris/page.h
+@@ -1,6 +1,8 @@
+ #ifndef _CRIS_PAGE_H
+ #define _CRIS_PAGE_H
+
++#ifdef __KERNEL__
++
+ #include <asm/arch/page.h>
+
+ /* PAGE_SHIFT determines the page size */
+@@ -12,8 +14,6 @@
+ #endif
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+
+-#ifdef __KERNEL__
+-
+ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
+ #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+
+@@ -73,10 +73,10 @@ typedef struct { unsigned long pgprot; }
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++#endif /* __KERNEL__ */
++
+ #endif /* _CRIS_PAGE_H */
+
+diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
+index 5d76c1c..c94a710 100644
+--- a/include/asm-cris/pgtable.h
++++ b/include/asm-cris/pgtable.h
+@@ -253,7 +253,7 @@ static inline void pmd_set(pmd_t * pmdp,
+ { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; }
+
+ #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+-#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ /* to find an entry in a page-table-directory. */
+ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+@@ -271,7 +271,7 @@ static inline pgd_t * pgd_offset(struct
+ #define __pte_offset(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
+ #define pte_offset_map(dir, address) \
+ ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
+ #define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
+diff --git a/include/asm-cris/posix_types.h b/include/asm-cris/posix_types.h
+index 6d26fee..7b9ed22 100644
+--- a/include/asm-cris/posix_types.h
++++ b/include/asm-cris/posix_types.h
+@@ -6,8 +6,6 @@
+ #ifndef __ARCH_CRIS_POSIX_TYPES_H
+ #define __ARCH_CRIS_POSIX_TYPES_H
+
+-#include <asm/bitops.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
+@@ -53,9 +51,8 @@ typedef struct {
+ #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+ } __kernel_fsid_t;
+
+-/* should this ifdef be here ? */
+-
+-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
++#ifdef __KERNEL__
++#include <asm/bitops.h>
+
+ #undef __FD_SET
+ #define __FD_SET(fd,fdsetp) set_bit(fd, (void *)(fdsetp))
+@@ -69,6 +66,6 @@ typedef struct {
+ #undef __FD_ZERO
+ #define __FD_ZERO(fdsetp) memset((void *)(fdsetp), 0, __FDSET_LONGS << 2)
+
+-#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
++#endif /* __KERNEL__ */
+
+ #endif /* __ARCH_CRIS_POSIX_TYPES_H */
+diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h
+index c2954e9..7c90fa9 100644
+--- a/include/asm-cris/unistd.h
++++ b/include/asm-cris/unistd.h
+@@ -1,8 +1,6 @@
+ #ifndef _ASM_CRIS_UNISTD_H_
+ #define _ASM_CRIS_UNISTD_H_
+
+-#include <asm/arch/unistd.h>
+-
+ /*
+ * This file contains the system call numbers, and stub macros for libc.
+ */
+@@ -299,6 +297,7 @@
+
+ #define NR_syscalls 289
+
++#include <asm/arch/unistd.h>
+
+ #define __ARCH_WANT_IPC_PARSE_VERSION
+ #define __ARCH_WANT_OLD_READDIR
+@@ -322,68 +321,6 @@
+ #define __ARCH_WANT_SYS_SIGPENDING
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+-#endif
+-
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/linkage.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static inline _syscall0(pid_t,setsid)
+-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static inline _syscall1(int,dup,int,fd)
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+-static inline _syscall1(int,close,int,fd)
+-
+-struct pt_regs;
+-asmlinkage long sys_mmap2(
+- unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
+- long r13, long mof, long srp, struct pt_regs *regs);
+-asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
+- int* parent_tid, int* child_tid, long mof, long srp,
+- struct pt_regs *regs);
+-asmlinkage int sys_fork(long r10, long r11, long r12, long r13,
+- long mof, long srp, struct pt_regs *regs);
+-asmlinkage int sys_vfork(long r10, long r11, long r12, long r13,
+- long mof, long srp, struct pt_regs *regs);
+-asmlinkage int sys_pipe(unsigned long __user *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-/*
+- * Since we define it "external", it collides with the built-in
+- * definition, which has the "noreturn" attribute and will cause
+- * complaints. We don't want to use -fno-builtin, so just use a
+- * different name when in the kernel.
+- */
+-#define _exit kernel_syscall_exit
+-static inline _syscall1(int,_exit,int,exitcode)
+-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+
+ /*
+ * "Conditional" syscalls
+diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h
+index 980ae1b..1f70d47 100644
+--- a/include/asm-frv/bitops.h
++++ b/include/asm-frv/bitops.h
+@@ -157,23 +157,105 @@ static inline int __test_bit(int nr, con
+ __constant_test_bit((nr),(addr)) : \
+ __test_bit((nr),(addr)))
+
+-#include <asm-generic/bitops/ffs.h>
+-#include <asm-generic/bitops/__ffs.h>
+ #include <asm-generic/bitops/find.h>
+
+-/*
+- * fls: find last bit set.
++/**
++ * fls - find last bit set
++ * @x: the word to search
++ *
++ * This is defined the same way as ffs:
++ * - return 32..1 to indicate bit 31..0 most significant bit set
++ * - return 0 to indicate no bits set
+ */
+ #define fls(x) \
+ ({ \
+ int bit; \
+ \
+- asm("scan %1,gr0,%0" : "=r"(bit) : "r"(x)); \
++ asm(" subcc %1,gr0,gr0,icc0 \n" \
++ " ckne icc0,cc4 \n" \
++ " cscan.p %1,gr0,%0 ,cc4,#1 \n" \
++ " csub %0,%0,%0 ,cc4,#0 \n" \
++ " csub %2,%0,%0 ,cc4,#1 \n" \
++ : "=&r"(bit) \
++ : "r"(x), "r"(32) \
++ : "icc0", "cc4" \
++ ); \
+ \
+- bit ? 33 - bit : bit; \
++ bit; \
+ })
+
+-#include <asm-generic/bitops/fls64.h>
++/**
++ * fls64 - find last bit set in a 64-bit value
++ * @n: the value to search
++ *
++ * This is defined the same way as ffs:
++ * - return 64..1 to indicate bit 63..0 most significant bit set
++ * - return 0 to indicate no bits set
++ */
++static inline __attribute__((const))
++int fls64(u64 n)
++{
++ union {
++ u64 ll;
++ struct { u32 h, l; };
++ } _;
++ int bit, x, y;
++
++ _.ll = n;
++
++ asm(" subcc.p %3,gr0,gr0,icc0 \n"
++ " subcc %4,gr0,gr0,icc1 \n"
++ " ckne icc0,cc4 \n"
++ " ckne icc1,cc5 \n"
++ " norcr cc4,cc5,cc6 \n"
++ " csub.p %0,%0,%0 ,cc6,1 \n"
++ " orcr cc5,cc4,cc4 \n"
++ " andcr cc4,cc5,cc4 \n"
++ " cscan.p %3,gr0,%0 ,cc4,0 \n"
++ " setlos #64,%1 \n"
++ " cscan.p %4,gr0,%0 ,cc4,1 \n"
++ " setlos #32,%2 \n"
++ " csub.p %1,%0,%0 ,cc4,0 \n"
++ " csub %2,%0,%0 ,cc4,1 \n"
++ : "=&r"(bit), "=r"(x), "=r"(y)
++ : "0r"(_.h), "r"(_.l)
++ : "icc0", "icc1", "cc4", "cc5", "cc6"
++ );
++ return bit;
++
++}
++
++/**
++ * ffs - find first bit set
++ * @x: the word to search
++ *
++ * - return 32..1 to indicate bit 31..0 most least significant bit set
++ * - return 0 to indicate no bits set
++ */
++static inline __attribute__((const))
++int ffs(int x)
++{
++ /* Note: (x & -x) gives us a mask that is the least significant
++ * (rightmost) 1-bit of the value in x.
++ */
++ return fls(x & -x);
++}
++
++/**
++ * __ffs - find first bit set
++ * @x: the word to search
++ *
++ * - return 31..0 to indicate bit 31..0 most least significant bit set
++ * - if no bits are set in x, the result is undefined
++ */
++static inline __attribute__((const))
++int __ffs(unsigned long x)
++{
++ int bit;
++ asm("scan %1,gr0,%0" : "=r"(bit) : "r"(x & -x));
++ return 31 - bit;
++}
++
+ #include <asm-generic/bitops/sched.h>
+ #include <asm-generic/bitops/hweight.h>
+
+diff --git a/include/asm-frv/cpu-irqs.h b/include/asm-frv/cpu-irqs.h
+index 5cd691e..478f349 100644
+--- a/include/asm-frv/cpu-irqs.h
++++ b/include/asm-frv/cpu-irqs.h
+@@ -14,36 +14,6 @@
+
+ #ifndef __ASSEMBLY__
+
+-#include <asm/irq-routing.h>
+-
+-#define IRQ_BASE_CPU (NR_IRQ_ACTIONS_PER_GROUP * 0)
+-
+-/* IRQ IDs presented to drivers */
+-enum {
+- IRQ_CPU__UNUSED = IRQ_BASE_CPU,
+- IRQ_CPU_UART0,
+- IRQ_CPU_UART1,
+- IRQ_CPU_TIMER0,
+- IRQ_CPU_TIMER1,
+- IRQ_CPU_TIMER2,
+- IRQ_CPU_DMA0,
+- IRQ_CPU_DMA1,
+- IRQ_CPU_DMA2,
+- IRQ_CPU_DMA3,
+- IRQ_CPU_DMA4,
+- IRQ_CPU_DMA5,
+- IRQ_CPU_DMA6,
+- IRQ_CPU_DMA7,
+- IRQ_CPU_EXTERNAL0,
+- IRQ_CPU_EXTERNAL1,
+- IRQ_CPU_EXTERNAL2,
+- IRQ_CPU_EXTERNAL3,
+- IRQ_CPU_EXTERNAL4,
+- IRQ_CPU_EXTERNAL5,
+- IRQ_CPU_EXTERNAL6,
+- IRQ_CPU_EXTERNAL7,
+-};
+-
+ /* IRQ to level mappings */
+ #define IRQ_GDBSTUB_LEVEL 15
+ #define IRQ_UART_LEVEL 13
+@@ -82,6 +52,30 @@ enum {
+ #define IRQ_XIRQ6_LEVEL 7
+ #define IRQ_XIRQ7_LEVEL 8
+
++/* IRQ IDs presented to drivers */
++#define IRQ_CPU__UNUSED IRQ_BASE_CPU
++#define IRQ_CPU_UART0 (IRQ_BASE_CPU + IRQ_UART0_LEVEL)
++#define IRQ_CPU_UART1 (IRQ_BASE_CPU + IRQ_UART1_LEVEL)
++#define IRQ_CPU_TIMER0 (IRQ_BASE_CPU + IRQ_TIMER0_LEVEL)
++#define IRQ_CPU_TIMER1 (IRQ_BASE_CPU + IRQ_TIMER1_LEVEL)
++#define IRQ_CPU_TIMER2 (IRQ_BASE_CPU + IRQ_TIMER2_LEVEL)
++#define IRQ_CPU_DMA0 (IRQ_BASE_CPU + IRQ_DMA0_LEVEL)
++#define IRQ_CPU_DMA1 (IRQ_BASE_CPU + IRQ_DMA1_LEVEL)
++#define IRQ_CPU_DMA2 (IRQ_BASE_CPU + IRQ_DMA2_LEVEL)
++#define IRQ_CPU_DMA3 (IRQ_BASE_CPU + IRQ_DMA3_LEVEL)
++#define IRQ_CPU_DMA4 (IRQ_BASE_CPU + IRQ_DMA4_LEVEL)
++#define IRQ_CPU_DMA5 (IRQ_BASE_CPU + IRQ_DMA5_LEVEL)
++#define IRQ_CPU_DMA6 (IRQ_BASE_CPU + IRQ_DMA6_LEVEL)
++#define IRQ_CPU_DMA7 (IRQ_BASE_CPU + IRQ_DMA7_LEVEL)
++#define IRQ_CPU_EXTERNAL0 (IRQ_BASE_CPU + IRQ_XIRQ0_LEVEL)
++#define IRQ_CPU_EXTERNAL1 (IRQ_BASE_CPU + IRQ_XIRQ1_LEVEL)
++#define IRQ_CPU_EXTERNAL2 (IRQ_BASE_CPU + IRQ_XIRQ2_LEVEL)
++#define IRQ_CPU_EXTERNAL3 (IRQ_BASE_CPU + IRQ_XIRQ3_LEVEL)
++#define IRQ_CPU_EXTERNAL4 (IRQ_BASE_CPU + IRQ_XIRQ4_LEVEL)
++#define IRQ_CPU_EXTERNAL5 (IRQ_BASE_CPU + IRQ_XIRQ5_LEVEL)
++#define IRQ_CPU_EXTERNAL6 (IRQ_BASE_CPU + IRQ_XIRQ6_LEVEL)
++#define IRQ_CPU_EXTERNAL7 (IRQ_BASE_CPU + IRQ_XIRQ7_LEVEL)
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif /* _ASM_CPU_IRQS_H */
+diff --git a/include/asm-frv/dma.h b/include/asm-frv/dma.h
+index 18d6bb8..683c47d 100644
+--- a/include/asm-frv/dma.h
++++ b/include/asm-frv/dma.h
+@@ -24,10 +24,7 @@
+ /*
+ * FRV DMA controller management
+ */
+-struct pt_regs;
+-
+-typedef irqreturn_t (*dma_irq_handler_t)(int dmachan, unsigned long cstr, void *data,
+- struct pt_regs *regs);
++typedef irqreturn_t (*dma_irq_handler_t)(int dmachan, unsigned long cstr, void *data);
+
+ extern void frv_dma_init(void);
+
+diff --git a/include/asm-frv/hardirq.h b/include/asm-frv/hardirq.h
+index 7581b5a..fc47515 100644
+--- a/include/asm-frv/hardirq.h
++++ b/include/asm-frv/hardirq.h
+@@ -26,5 +26,10 @@ typedef struct {
+ #error SMP not available on FR-V
+ #endif /* CONFIG_SMP */
+
++extern atomic_t irq_err_count;
++static inline void ack_bad_irq(int irq)
++{
++ atomic_inc(&irq_err_count);
++}
+
+ #endif
+diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h
+index e2247c2..0f390f4 100644
+--- a/include/asm-frv/highmem.h
++++ b/include/asm-frv/highmem.h
+@@ -82,11 +82,11 @@ extern struct page *kmap_atomic_to_page(
+ dampr = paddr | xAMPRx_L | xAMPRx_M | xAMPRx_S | xAMPRx_SS_16Kb | xAMPRx_V; \
+ \
+ if (type != __KM_CACHE) \
+- asm volatile("movgs %0,dampr"#ampr :: "r"(dampr)); \
++ asm volatile("movgs %0,dampr"#ampr :: "r"(dampr) : "memory"); \
+ else \
+ asm volatile("movgs %0,iampr"#ampr"\n" \
+ "movgs %0,dampr"#ampr"\n" \
+- :: "r"(dampr) \
++ :: "r"(dampr) : "memory" \
+ ); \
+ \
+ asm("movsg damlr"#ampr",%0" : "=r"(damlr)); \
+@@ -104,7 +104,7 @@ extern struct page *kmap_atomic_to_page(
+ asm volatile("movgs %0,tplr \n" \
+ "movgs %1,tppr \n" \
+ "tlbpr %0,gr0,#2,#1" \
+- : : "r"(damlr), "r"(dampr)); \
++ : : "r"(damlr), "r"(dampr) : "memory"); \
+ \
+ /*printk("TLB: SECN sl=%d L=%08lx P=%08lx\n", slot, damlr, dampr);*/ \
+ \
+@@ -115,7 +115,7 @@ static inline void *kmap_atomic(struct p
+ {
+ unsigned long paddr;
+
+- preempt_disable();
++ inc_preempt_count();
+ paddr = page_to_phys(page);
+
+ switch (type) {
+@@ -138,16 +138,16 @@ static inline void *kmap_atomic(struct p
+ }
+ }
+
+-#define __kunmap_atomic_primary(type, ampr) \
+-do { \
+- asm volatile("movgs gr0,dampr"#ampr"\n"); \
+- if (type == __KM_CACHE) \
+- asm volatile("movgs gr0,iampr"#ampr"\n"); \
++#define __kunmap_atomic_primary(type, ampr) \
++do { \
++ asm volatile("movgs gr0,dampr"#ampr"\n" ::: "memory"); \
++ if (type == __KM_CACHE) \
++ asm volatile("movgs gr0,iampr"#ampr"\n" ::: "memory"); \
+ } while(0)
+
+-#define __kunmap_atomic_secondary(slot, vaddr) \
+-do { \
+- asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr)); \
++#define __kunmap_atomic_secondary(slot, vaddr) \
++do { \
++ asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory"); \
+ } while(0)
+
+ static inline void kunmap_atomic(void *kvaddr, enum km_type type)
+@@ -170,7 +170,8 @@ static inline void kunmap_atomic(void *k
+ default:
+ BUG();
+ }
+- preempt_enable();
++ dec_preempt_count();
++ preempt_check_resched();
+ }
+
+ #endif /* !__ASSEMBLY__ */
+diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h
+index 7765f55..20e44fe 100644
+--- a/include/asm-frv/io.h
++++ b/include/asm-frv/io.h
+@@ -385,27 +385,6 @@ static inline void pci_iounmap(struct pc
+ */
+ #define xlate_dev_kmem_ptr(p) p
+
+-/*
+- * Check BIOS signature
+- */
+-static inline int check_signature(volatile void __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+-
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+-
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ #endif /* __KERNEL__ */
+
+ #endif /* _ASM_IO_H */
+diff --git a/include/asm-frv/irq-routing.h b/include/asm-frv/irq-routing.h
+deleted file mode 100644
+index ac3ab90..0000000
+--- a/include/asm-frv/irq-routing.h
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/* irq-routing.h: multiplexed IRQ routing
+- *
+- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+- * Written by David Howells (dhowells at 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.
+- */
+-
+-#ifndef _ASM_IRQ_ROUTING_H
+-#define _ASM_IRQ_ROUTING_H
+-
+-#ifndef __ASSEMBLY__
+-
+-#include <linux/spinlock.h>
+-#include <asm/irq.h>
+-
+-struct irq_source;
+-struct irq_level;
+-
+-/*
+- * IRQ action distribution sets
+- */
+-struct irq_group {
+- int first_irq; /* first IRQ distributed here */
+- void (*control)(struct irq_group *group, int index, int on);
+-
+- struct irqaction *actions[NR_IRQ_ACTIONS_PER_GROUP]; /* IRQ action chains */
+- struct irq_source *sources[NR_IRQ_ACTIONS_PER_GROUP]; /* IRQ sources */
+- int disable_cnt[NR_IRQ_ACTIONS_PER_GROUP]; /* disable counts */
+-};
+-
+-/*
+- * IRQ source manager
+- */
+-struct irq_source {
+- struct irq_source *next;
+- struct irq_level *level;
+- const char *muxname;
+- volatile void __iomem *muxdata;
+- unsigned long irqmask;
+-
+- void (*doirq)(struct irq_source *source);
+-};
+-
+-/*
+- * IRQ level management (per CPU IRQ priority / entry vector)
+- */
+-struct irq_level {
+- int usage;
+- int disable_count;
+- unsigned long flags; /* current IRQF_DISABLED and IRQF_SHARED settings */
+- spinlock_t lock;
+- struct irq_source *sources;
+-};
+-
+-extern struct irq_level frv_irq_levels[16];
+-extern struct irq_group *irq_groups[NR_IRQ_GROUPS];
+-
+-extern void frv_irq_route(struct irq_source *source, int irqlevel);
+-extern void frv_irq_route_external(struct irq_source *source, int irq);
+-extern void frv_irq_set_group(struct irq_group *group);
+-extern void distribute_irqs(struct irq_group *group, unsigned long irqmask);
+-extern void route_cpu_irqs(void);
+-
+-#endif /* !__ASSEMBLY__ */
+-
+-#endif /* _ASM_IRQ_ROUTING_H */
+diff --git a/include/asm-frv/irq.h b/include/asm-frv/irq.h
+index 58b6192..8fefd6b 100644
+--- a/include/asm-frv/irq.h
++++ b/include/asm-frv/irq.h
+@@ -1,6 +1,6 @@
+ /* irq.h: FRV IRQ definitions
+ *
+- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -12,32 +12,22 @@
+ #ifndef _ASM_IRQ_H_
+ #define _ASM_IRQ_H_
+
+-
+-/*
+- * the system has an on-CPU PIC and another PIC on the FPGA and other PICs on other peripherals,
+- * so we do some routing in irq-routing.[ch] to reduce the number of false-positives seen by
+- * drivers
+- */
+-
+ /* this number is used when no interrupt has been assigned */
+ #define NO_IRQ (-1)
+
+-#define NR_IRQ_LOG2_ACTIONS_PER_GROUP 5
+-#define NR_IRQ_ACTIONS_PER_GROUP (1 << NR_IRQ_LOG2_ACTIONS_PER_GROUP)
+-#define NR_IRQ_GROUPS 4
+-#define NR_IRQS (NR_IRQ_ACTIONS_PER_GROUP * NR_IRQ_GROUPS)
++#define NR_IRQS 48
++#define IRQ_BASE_CPU (0 * 16)
++#define IRQ_BASE_FPGA (1 * 16)
++#define IRQ_BASE_MB93493 (2 * 16)
+
+ /* probe returns a 32-bit IRQ mask:-/ */
+-#define MIN_PROBE_IRQ (NR_IRQS - 32)
++#define MIN_PROBE_IRQ (NR_IRQS - 32)
+
++#ifndef __ASSEMBLY__
+ static inline int irq_canonicalize(int irq)
+ {
+ return irq;
+ }
+-
+-extern void disable_irq_nosync(unsigned int irq);
+-extern void disable_irq(unsigned int irq);
+-extern void enable_irq(unsigned int irq);
+-
++#endif
+
+ #endif /* _ASM_IRQ_H_ */
+diff --git a/include/asm-frv/irq_regs.h b/include/asm-frv/irq_regs.h
+new file mode 100644
+index 0000000..d22e832
+--- /dev/null
++++ b/include/asm-frv/irq_regs.h
+@@ -0,0 +1,27 @@
++/* FRV per-CPU frame pointer holder
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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.
++ */
++
++#ifndef _ASM_IRQ_REGS_H
++#define _ASM_IRQ_REGS_H
++
++/*
++ * Per-cpu current frame pointer - the location of the last exception frame on
++ * the stack
++ * - on FRV, GR28 is dedicated to keeping a pointer to the current exception
++ * frame
++ */
++#define ARCH_HAS_OWN_IRQ_REGS
++
++#ifndef __ASSEMBLY__
++#define get_irq_regs() (__frame)
++#endif
++
++#endif /* _ASM_IRQ_REGS_H */
+diff --git a/include/asm-frv/mb93091-fpga-irqs.h b/include/asm-frv/mb93091-fpga-irqs.h
+index 341bfc5..19778c5 100644
+--- a/include/asm-frv/mb93091-fpga-irqs.h
++++ b/include/asm-frv/mb93091-fpga-irqs.h
+@@ -12,11 +12,9 @@
+ #ifndef _ASM_MB93091_FPGA_IRQS_H
+ #define _ASM_MB93091_FPGA_IRQS_H
+
+-#ifndef __ASSEMBLY__
+-
+-#include <asm/irq-routing.h>
++#include <asm/irq.h>
+
+-#define IRQ_BASE_FPGA (NR_IRQ_ACTIONS_PER_GROUP * 1)
++#ifndef __ASSEMBLY__
+
+ /* IRQ IDs presented to drivers */
+ enum {
+diff --git a/include/asm-frv/mb93093-fpga-irqs.h b/include/asm-frv/mb93093-fpga-irqs.h
+index 1e0f11c..590266b 100644
+--- a/include/asm-frv/mb93093-fpga-irqs.h
++++ b/include/asm-frv/mb93093-fpga-irqs.h
+@@ -12,11 +12,9 @@
+ #ifndef _ASM_MB93093_FPGA_IRQS_H
+ #define _ASM_MB93093_FPGA_IRQS_H
+
+-#ifndef __ASSEMBLY__
+-
+-#include <asm/irq-routing.h>
++#include <asm/irq.h>
+
+-#define IRQ_BASE_FPGA (NR_IRQ_ACTIONS_PER_GROUP * 1)
++#ifndef __ASSEMBLY__
+
+ /* IRQ IDs presented to drivers */
+ enum {
+diff --git a/include/asm-frv/mb93493-irqs.h b/include/asm-frv/mb93493-irqs.h
+index 15096e7..82c7aed 100644
+--- a/include/asm-frv/mb93493-irqs.h
++++ b/include/asm-frv/mb93493-irqs.h
+@@ -12,11 +12,9 @@
+ #ifndef _ASM_MB93493_IRQS_H
+ #define _ASM_MB93493_IRQS_H
+
+-#ifndef __ASSEMBLY__
+-
+-#include <asm/irq-routing.h>
++#include <asm/irq.h>
+
+-#define IRQ_BASE_MB93493 (NR_IRQ_ACTIONS_PER_GROUP * 2)
++#ifndef __ASSEMBLY__
+
+ /* IRQ IDs presented to drivers */
+ enum {
+diff --git a/include/asm-frv/mb93493-regs.h b/include/asm-frv/mb93493-regs.h
+index c54aa9d..8a1f6aa 100644
+--- a/include/asm-frv/mb93493-regs.h
++++ b/include/asm-frv/mb93493-regs.h
+@@ -15,6 +15,7 @@
+ #include <asm/mb-regs.h>
+ #include <asm/mb93493-irqs.h>
+
++#define __addr_MB93493(X) ((volatile unsigned long *)(__region_CS3 + (X)))
+ #define __get_MB93493(X) ({ *(volatile unsigned long *)(__region_CS3 + (X)); })
+
+ #define __set_MB93493(X,V) \
+@@ -26,6 +27,7 @@ do { \
+ #define __set_MB93493_STSR(X,V) __set_MB93493(0x3c0 + (X) * 4, (V))
+ #define MB93493_STSR_EN
+
++#define __addr_MB93493_IQSR(X) __addr_MB93493(0x3d0 + (X) * 4)
+ #define __get_MB93493_IQSR(X) __get_MB93493(0x3d0 + (X) * 4)
+ #define __set_MB93493_IQSR(X,V) __set_MB93493(0x3d0 + (X) * 4, (V))
+
+diff --git a/include/asm-frv/namei.h b/include/asm-frv/namei.h
+index 84ddd64..4ea5717 100644
+--- a/include/asm-frv/namei.h
++++ b/include/asm-frv/namei.h
+@@ -1,5 +1,5 @@
+ /*
+- * asm/namei.h
++ * include/asm-frv/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
+index 7af7485..ba1b37d 100644
+--- a/include/asm-frv/pgtable.h
++++ b/include/asm-frv/pgtable.h
+@@ -176,8 +176,6 @@ do { \
+ } while(0)
+ #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+-#define set_pte_atomic(pteptr, pteval) set_pte((pteptr), (pteval))
+-
+ /*
+ * pgd_offset() returns a (pgd_t *)
+ * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
+@@ -217,7 +215,7 @@ static inline pud_t *pud_offset(pgd_t *p
+ }
+
+ #define pgd_page(pgd) (pud_page((pud_t){ pgd }))
+-#define pgd_page_kernel(pgd) (pud_page_kernel((pud_t){ pgd }))
++#define pgd_page_vaddr(pgd) (pud_page_vaddr((pud_t){ pgd }))
+
+ /*
+ * allocating and freeing a pud is trivial: the 1-entry pud is
+@@ -246,7 +244,7 @@ static inline void pud_clear(pud_t *pud)
+ #define set_pud(pudptr, pudval) set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval })
+
+ #define pud_page(pud) (pmd_page((pmd_t){ pud }))
+-#define pud_page_kernel(pud) (pmd_page_kernel((pmd_t){ pud }))
++#define pud_page_vaddr(pud) (pmd_page_vaddr((pmd_t){ pud }))
+
+ /*
+ * (pmds are folded into pgds so this doesn't get actually called,
+@@ -362,7 +360,7 @@ static inline pmd_t *pmd_offset(pud_t *d
+ #define pmd_bad(x) (pmd_val(x) & xAMPRx_SS)
+ #define pmd_clear(xp) do { __set_pmd(xp, 0); } while(0)
+
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ #ifndef CONFIG_DISCONTIGMEM
+@@ -458,7 +456,7 @@ static inline pte_t pte_modify(pte_t pte
+ #define pte_index(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
+
+ #if defined(CONFIG_HIGHPTE)
+ #define pte_offset_map(dir, address) \
+diff --git a/include/asm-frv/ptrace.h b/include/asm-frv/ptrace.h
+index 7ff5251..9a2241b 100644
+--- a/include/asm-frv/ptrace.h
++++ b/include/asm-frv/ptrace.h
+@@ -12,6 +12,7 @@
+ #define _ASM_PTRACE_H
+
+ #include <asm/registers.h>
++#include <asm/irq_regs.h>
+
+ #define in_syscall(regs) (((regs)->tbr & TBR_TT) == TBR_TT_TRAP0)
+
+diff --git a/include/asm-frv/timex.h b/include/asm-frv/timex.h
+index 2aa562f..a89bdde 100644
+--- a/include/asm-frv/timex.h
++++ b/include/asm-frv/timex.h
+@@ -6,11 +6,6 @@
+ #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 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)
+-
+ typedef unsigned long cycles_t;
+
+ static inline cycles_t get_cycles(void)
+diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
+index b80dbd8..725e854 100644
+--- a/include/asm-frv/unistd.h
++++ b/include/asm-frv/unistd.h
+@@ -320,6 +320,7 @@
+ #ifdef __KERNEL__
+
+ #define NR_syscalls 310
++#include <linux/err.h>
+
+ /*
+ * process the return value of a syscall, consigning it to one of two possible fates
+@@ -329,7 +330,7 @@
+ #define __syscall_return(type, res) \
+ do { \
+ unsigned long __sr2 = (res); \
+- if (__builtin_expect(__sr2 >= (unsigned long)(-4095), 0)) { \
++ if (__builtin_expect(__sr2 >= (unsigned long)(-MAX_ERRNO), 0)) { \
+ errno = (-__sr2); \
+ __sr2 = ~0UL; \
+ } \
+@@ -439,31 +440,6 @@ type name (type1 arg1, type2 arg2, type3
+ __syscall_return(type, __sc0); \
+ }
+
+-
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/linkage.h>
+-#include <asm/ptrace.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ #define __ARCH_WANT_IPC_PARSE_VERSION
+ /* #define __ARCH_WANT_OLD_READDIR */
+ #define __ARCH_WANT_OLD_STAT
+diff --git a/include/asm-generic/4level-fixup.h b/include/asm-generic/4level-fixup.h
+index 68c6fea..7b88d39 100644
+--- a/include/asm-generic/4level-fixup.h
++++ b/include/asm-generic/4level-fixup.h
+@@ -21,6 +21,10 @@
+ #define pud_present(pud) 1
+ #define pud_ERROR(pud) do { } while (0)
+ #define pud_clear(pud) pgd_clear(pud)
++#define pud_val(pud) pgd_val(pud)
++#define pud_populate(mm, pud, pmd) pgd_populate(mm, pud, pmd)
++#define pud_page(pud) pgd_page(pud)
++#define pud_page_vaddr(pud) pgd_page_vaddr(pud)
+
+ #undef pud_free_tlb
+ #define pud_free_tlb(tlb, x) do { } while (0)
+diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild
+index 70594b2..3c06be3 100644
+--- a/include/asm-generic/Kbuild
++++ b/include/asm-generic/Kbuild
+@@ -1,3 +1,12 @@
+-header-y += atomic.h errno-base.h errno.h fcntl.h ioctl.h ipc.h mman.h \
+- signal.h statfs.h
+-unifdef-y := resource.h siginfo.h
++header-y += atomic.h
++header-y += errno-base.h
++header-y += errno.h
++header-y += fcntl.h
++header-y += ioctl.h
++header-y += ipc.h
++header-y += mman.h
++header-y += signal.h
++header-y += statfs.h
++
++unifdef-y += resource.h
++unifdef-y += siginfo.h
+diff --git a/include/asm-generic/Kbuild.asm b/include/asm-generic/Kbuild.asm
+index c00de60..a84c3d8 100644
+--- a/include/asm-generic/Kbuild.asm
++++ b/include/asm-generic/Kbuild.asm
+@@ -1,8 +1,34 @@
+-unifdef-y += a.out.h auxvec.h byteorder.h errno.h fcntl.h ioctl.h \
+- ioctls.h ipcbuf.h mman.h msgbuf.h param.h poll.h \
+- posix_types.h ptrace.h resource.h sembuf.h shmbuf.h shmparam.h \
+- sigcontext.h siginfo.h signal.h socket.h sockios.h stat.h \
+- statfs.h termbits.h termios.h types.h unistd.h user.h
++unifdef-y += a.out.h
++unifdef-y += auxvec.h
++unifdef-y += byteorder.h
++unifdef-y += errno.h
++unifdef-y += fcntl.h
++unifdef-y += ioctl.h
++unifdef-y += ioctls.h
++unifdef-y += ipcbuf.h
++unifdef-y += mman.h
++unifdef-y += msgbuf.h
++unifdef-y += param.h
++unifdef-y += poll.h
++unifdef-y += posix_types.h
++unifdef-y += ptrace.h
++unifdef-y += resource.h
++unifdef-y += sembuf.h
++unifdef-y += shmbuf.h
++unifdef-y += sigcontext.h
++unifdef-y += siginfo.h
++unifdef-y += signal.h
++unifdef-y += socket.h
++unifdef-y += sockios.h
++unifdef-y += stat.h
++unifdef-y += statfs.h
++unifdef-y += termbits.h
++unifdef-y += termios.h
++unifdef-y += types.h
++unifdef-y += unistd.h
++unifdef-y += user.h
+
+ # These probably shouldn't be exported
+-unifdef-y += elf.h page.h
++unifdef-y += shmparam.h
++unifdef-y += elf.h
++unifdef-y += page.h
+diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h
+index cb05bf6..5076455 100644
+--- a/include/asm-generic/audit_change_attr.h
++++ b/include/asm-generic/audit_change_attr.h
+@@ -1,16 +1,20 @@
+ __NR_chmod,
+ __NR_fchmod,
++#ifdef __NR_chown
+ __NR_chown,
+ __NR_fchown,
+ __NR_lchown,
++#endif
+ __NR_setxattr,
+ __NR_lsetxattr,
+ __NR_fsetxattr,
+ __NR_removexattr,
+ __NR_lremovexattr,
+ __NR_fremovexattr,
++#ifdef __NR_fchownat
+ __NR_fchownat,
+ __NR_fchmodat,
++#endif
+ #ifdef __NR_chown32
+ __NR_chown32,
+ __NR_fchown32,
+diff --git a/include/asm-generic/audit_dir_write.h b/include/asm-generic/audit_dir_write.h
+index 161a7a5..6621bd8 100644
+--- a/include/asm-generic/audit_dir_write.h
++++ b/include/asm-generic/audit_dir_write.h
+@@ -1,14 +1,18 @@
+ __NR_rename,
+ __NR_mkdir,
+ __NR_rmdir,
++#ifdef __NR_creat
+ __NR_creat,
++#endif
+ __NR_link,
+ __NR_unlink,
+ __NR_symlink,
+ __NR_mknod,
++#ifdef __NR_mkdirat
+ __NR_mkdirat,
+ __NR_mknodat,
+ __NR_unlinkat,
+ __NR_renameat,
+ __NR_linkat,
+ __NR_symlinkat,
++#endif
+diff --git a/include/asm-generic/bitops/sched.h b/include/asm-generic/bitops/sched.h
+index 5ef93a4..815bb01 100644
+--- a/include/asm-generic/bitops/sched.h
++++ b/include/asm-generic/bitops/sched.h
+@@ -15,7 +15,7 @@ static inline int sched_find_first_bit(c
+ #if BITS_PER_LONG == 64
+ if (unlikely(b[0]))
+ return __ffs(b[0]);
+- if (unlikely(b[1]))
++ if (likely(b[1]))
+ return __ffs(b[1]) + 64;
+ return __ffs(b[2]) + 128;
+ #elif BITS_PER_LONG == 32
+diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
+index 8ceab7b..c92ae0f 100644
+--- a/include/asm-generic/bug.h
++++ b/include/asm-generic/bug.h
+@@ -16,12 +16,15 @@
+ #endif
+
+ #ifndef HAVE_ARCH_WARN_ON
+-#define WARN_ON(condition) do { \
+- if (unlikely((condition)!=0)) { \
+- printk("BUG: warning at %s:%d/%s()\n", __FILE__, __LINE__, __FUNCTION__); \
+- dump_stack(); \
+- } \
+-} while (0)
++#define WARN_ON(condition) ({ \
++ typeof(condition) __ret_warn_on = (condition); \
++ if (unlikely(__ret_warn_on)) { \
++ printk("BUG: warning at %s:%d/%s()\n", __FILE__, \
++ __LINE__, __FUNCTION__); \
++ dump_stack(); \
++ } \
++ unlikely(__ret_warn_on); \
++})
+ #endif
+
+ #else /* !CONFIG_BUG */
+@@ -34,21 +37,21 @@
+ #endif
+
+ #ifndef HAVE_ARCH_WARN_ON
+-#define WARN_ON(condition) do { if (condition) ; } while(0)
++#define WARN_ON(condition) ({ \
++ typeof(condition) __ret_warn_on = (condition); \
++ unlikely(__ret_warn_on); \
++})
+ #endif
+ #endif
+
+-#define WARN_ON_ONCE(condition) \
+-({ \
+- static int __warn_once = 1; \
+- int __ret = 0; \
+- \
+- if (unlikely((condition) && __warn_once)) { \
+- __warn_once = 0; \
+- WARN_ON(1); \
+- __ret = 1; \
+- } \
+- __ret; \
++#define WARN_ON_ONCE(condition) ({ \
++ static int __warned; \
++ typeof(condition) __ret_warn_once = (condition); \
++ \
++ if (unlikely(__ret_warn_once)) \
++ if (WARN_ON(!__warned)) \
++ __warned = 1; \
++ unlikely(__ret_warn_once); \
+ })
+
+ #ifdef CONFIG_SMP
+diff --git a/include/asm-generic/irq_regs.h b/include/asm-generic/irq_regs.h
+new file mode 100644
+index 0000000..5ae1d07
+--- /dev/null
++++ b/include/asm-generic/irq_regs.h
+@@ -0,0 +1,37 @@
++/* Fallback per-CPU frame pointer holder
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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.
++ */
++
++#ifndef _ASM_GENERIC_IRQ_REGS_H
++#define _ASM_GENERIC_IRQ_REGS_H
++
++#include <linux/percpu.h>
++
++/*
++ * Per-cpu current frame pointer - the location of the last exception frame on
++ * the stack
++ */
++DECLARE_PER_CPU(struct pt_regs *, __irq_regs);
++
++static inline struct pt_regs *get_irq_regs(void)
++{
++ return __get_cpu_var(__irq_regs);
++}
++
++static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
++{
++ struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs);
++
++ old_regs = *pp_regs;
++ *pp_regs = new_regs;
++ return old_regs;
++}
++
++#endif /* _ASM_GENERIC_IRQ_REGS_H */
+diff --git a/include/asm-generic/libata-portmap.h b/include/asm-generic/libata-portmap.h
+new file mode 100644
+index 0000000..9202fd0
+--- /dev/null
++++ b/include/asm-generic/libata-portmap.h
+@@ -0,0 +1,12 @@
++#ifndef __ASM_GENERIC_LIBATA_PORTMAP_H
++#define __ASM_GENERIC_LIBATA_PORTMAP_H
++
++#define ATA_PRIMARY_CMD 0x1F0
++#define ATA_PRIMARY_CTL 0x3F6
++#define ATA_PRIMARY_IRQ 14
++
++#define ATA_SECONDARY_CMD 0x170
++#define ATA_SECONDARY_CTL 0x376
++#define ATA_SECONDARY_IRQ 15
++
++#endif
+diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h
+index 29c6ac3..0134151 100644
+--- a/include/asm-generic/mutex-dec.h
++++ b/include/asm-generic/mutex-dec.h
+@@ -1,5 +1,5 @@
+ /*
+- * asm-generic/mutex-dec.h
++ * include/asm-generic/mutex-dec.h
+ *
+ * Generic implementation of the mutex fastpath, based on atomic
+ * decrement/increment.
+diff --git a/include/asm-generic/mutex-null.h b/include/asm-generic/mutex-null.h
+index 254a126..e1bbbc7 100644
+--- a/include/asm-generic/mutex-null.h
++++ b/include/asm-generic/mutex-null.h
+@@ -1,5 +1,5 @@
+ /*
+- * asm-generic/mutex-null.h
++ * include/asm-generic/mutex-null.h
+ *
+ * Generic implementation of the mutex fastpath, based on NOP :-)
+ *
+diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h
+index 32a2100..6a7e8c1 100644
+--- a/include/asm-generic/mutex-xchg.h
++++ b/include/asm-generic/mutex-xchg.h
+@@ -1,5 +1,5 @@
+ /*
+- * asm-generic/mutex-xchg.h
++ * include/asm-generic/mutex-xchg.h
+ *
+ * Generic implementation of the mutex fastpath, based on xchg().
+ *
+diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
+index e160e04..1963762 100644
+--- a/include/asm-generic/percpu.h
++++ b/include/asm-generic/percpu.h
+@@ -14,7 +14,9 @@ extern unsigned long __per_cpu_offset[NR
+ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+
+ /* var is in discarded region: offset to particular copy we want */
+-#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
++#define per_cpu(var, cpu) (*({ \
++ extern int simple_identifier_##var(void); \
++ RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
+ #define __get_cpu_var(var) per_cpu(var, smp_processor_id())
+ #define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id())
+
+diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
+index c8d53ba..29ff5d8 100644
+--- a/include/asm-generic/pgtable-nopmd.h
++++ b/include/asm-generic/pgtable-nopmd.h
+@@ -47,7 +47,7 @@ static inline pmd_t * pmd_offset(pud_t *
+ #define __pmd(x) ((pmd_t) { __pud(x) } )
+
+ #define pud_page(pud) (pmd_page((pmd_t){ pud }))
+-#define pud_page_kernel(pud) (pmd_page_kernel((pmd_t){ pud }))
++#define pud_page_vaddr(pud) (pmd_page_vaddr((pmd_t){ pud }))
+
+ /*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
+index 82e29f0..5664645 100644
+--- a/include/asm-generic/pgtable-nopud.h
++++ b/include/asm-generic/pgtable-nopud.h
+@@ -44,7 +44,7 @@ static inline pud_t * pud_offset(pgd_t *
+ #define __pud(x) ((pud_t) { __pgd(x) } )
+
+ #define pgd_page(pgd) (pud_page((pud_t){ pgd }))
+-#define pgd_page_kernel(pgd) (pud_page_kernel((pud_t){ pgd }))
++#define pgd_page_vaddr(pgd) (pud_page_vaddr((pud_t){ pgd }))
+
+ /*
+ * allocating and freeing a pud is trivial: the 1-entry pud is
+diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
+index c2059a3..9d774d0 100644
+--- a/include/asm-generic/pgtable.h
++++ b/include/asm-generic/pgtable.h
+@@ -1,6 +1,8 @@
+ #ifndef _ASM_GENERIC_PGTABLE_H
+ #define _ASM_GENERIC_PGTABLE_H
+
++#ifndef __ASSEMBLY__
++
+ #ifndef __HAVE_ARCH_PTEP_ESTABLISH
+ /*
+ * Establish a new mapping:
+@@ -13,19 +15,11 @@
+ * Note: the old pte is known to not be writable, so we don't need to
+ * worry about dirty bits etc getting lost.
+ */
+-#ifndef __HAVE_ARCH_SET_PTE_ATOMIC
+ #define ptep_establish(__vma, __address, __ptep, __entry) \
+ do { \
+ set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \
+ flush_tlb_page(__vma, __address); \
+ } while (0)
+-#else /* __HAVE_ARCH_SET_PTE_ATOMIC */
+-#define ptep_establish(__vma, __address, __ptep, __entry) \
+-do { \
+- set_pte_atomic(__ptep, __entry); \
+- flush_tlb_page(__vma, __address); \
+-} while (0)
+-#endif /* __HAVE_ARCH_SET_PTE_ATOMIC */
+ #endif
+
+ #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+@@ -110,8 +104,13 @@ do { \
+ })
+ #endif
+
+-#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
+-#define pte_clear_full(__mm, __address, __ptep, __full) \
++/*
++ * Some architectures may be able to avoid expensive synchronization
++ * primitives when modifications are made to PTE's which are already
++ * not present, or in the process of an address space destruction.
++ */
++#ifndef __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
++#define pte_clear_not_present_full(__mm, __address, __ptep, __full) \
+ do { \
+ pte_clear((__mm), (__address), (__ptep)); \
+ } while (0)
+@@ -164,6 +163,26 @@ static inline void ptep_set_wrprotect(st
+ #endif
+
+ /*
++ * A facility to provide lazy MMU batching. This allows PTE updates and
++ * page invalidations to be delayed until a call to leave lazy MMU mode
++ * is issued. Some architectures may benefit from doing this, and it is
++ * beneficial for both shadow and direct mode hypervisors, which may batch
++ * the PTE updates which happen during this window. Note that using this
++ * interface requires that read hazards be removed from the code. A read
++ * hazard could result in the direct mode hypervisor case, since the actual
++ * write to the page tables may not yet have taken place, so reads though
++ * a raw PTE pointer after it has been modified are not guaranteed to be
++ * up to date. This mode can only be entered and left under the protection of
++ * the page table locks for all page tables which may be modified. In the UP
++ * case, this is required so that preemption is disabled, and in the SMP case,
++ * it must synchronize the delayed page table writes properly on other CPUs.
++ */
++#ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE
++#define arch_enter_lazy_mmu_mode() do {} while (0)
++#define arch_leave_lazy_mmu_mode() do {} while (0)
++#endif
++
++/*
+ * When walking page tables, get the address of the next boundary,
+ * or the end address of the range if that comes earlier. Although no
+ * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout.
+@@ -188,7 +207,6 @@ static inline void ptep_set_wrprotect(st
+ })
+ #endif
+
+-#ifndef __ASSEMBLY__
+ /*
+ * When walking page tables, we usually want to skip any p?d_none entries;
+ * and any p?d_bad entries - reporting the error before resetting to none.
+diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
+index 4087037..d3238f1 100644
+--- a/include/asm-generic/rtc.h
++++ b/include/asm-generic/rtc.h
+@@ -1,5 +1,5 @@
+ /*
+- * inclue/asm-generic/rtc.h
++ * include/asm-generic/rtc.h
+ *
+ * Author: Tom Rini <trini at mvista.com>
+ *
+diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
+index 867d900..f490e43 100644
+--- a/include/asm-generic/tlb.h
++++ b/include/asm-generic/tlb.h
+@@ -1,4 +1,4 @@
+-/* asm-generic/tlb.h
++/* include/asm-generic/tlb.h
+ *
+ * Generic TLB shootdown code
+ *
+diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
+index db5a373..9d87316 100644
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -118,15 +118,19 @@
+ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
+ *(__ksymtab_strings) \
+ } \
+- __end_rodata = .; \
+- . = ALIGN(4096); \
+ \
+ /* Built-in module parameters. */ \
+ __param : AT(ADDR(__param) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___param) = .; \
+ *(__param) \
+ VMLINUX_SYMBOL(__stop___param) = .; \
+- }
++ } \
++ \
++ /* Unwind data binary search table */ \
++ EH_FRAME_HDR \
++ \
++ __end_rodata = .; \
++ . = ALIGN(4096);
+
+ #define SECURITY_INIT \
+ .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
+@@ -157,6 +161,18 @@
+ *(.kprobes.text) \
+ VMLINUX_SYMBOL(__kprobes_text_end) = .;
+
++#ifdef CONFIG_STACK_UNWIND
++ /* Unwind data binary search table */
++#define EH_FRAME_HDR \
++ .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \
++ VMLINUX_SYMBOL(__start_unwind_hdr) = .; \
++ *(.eh_frame_hdr) \
++ VMLINUX_SYMBOL(__end_unwind_hdr) = .; \
++ }
++#else
++#define EH_FRAME_HDR
++#endif
++
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to
+ the beginning of the section so we begin them at 0. */
+@@ -194,3 +210,23 @@
+ .stab.index 0 : { *(.stab.index) } \
+ .stab.indexstr 0 : { *(.stab.indexstr) } \
+ .comment 0 : { *(.comment) }
++
++#define NOTES \
++ .notes : { *(.note.*) } :note
++
++#define INITCALLS \
++ *(.initcall1.init) \
++ *(.initcall1s.init) \
++ *(.initcall2.init) \
++ *(.initcall2s.init) \
++ *(.initcall3.init) \
++ *(.initcall3s.init) \
++ *(.initcall4.init) \
++ *(.initcall4s.init) \
++ *(.initcall5.init) \
++ *(.initcall5s.init) \
++ *(.initcall6.init) \
++ *(.initcall6s.init) \
++ *(.initcall7.init) \
++ *(.initcall7s.init)
++
+diff --git a/include/asm-h8300/keyboard.h b/include/asm-h8300/keyboard.h
+index fbad65e..90efbd6 100644
+--- a/include/asm-h8300/keyboard.h
++++ b/include/asm-h8300/keyboard.h
+@@ -18,14 +18,6 @@
+ #define kbd_enable_irq(x...) do {;} while (0)
+ #define kbd_disable_irq(x...) do {;} while (0)
+
+-
+-/* needed if MAGIC_SYSRQ is enabled for serial console */
+-#ifndef SYSRQ_KEY
+-#define SYSRQ_KEY ((unsigned char)(-1))
+-#define kbd_sysrq_xlate ((unsigned char *)NULL)
+-#endif
+-
+-
+ #endif /* _H8300_KEYBOARD_H */
+
+
+diff --git a/include/asm-h8300/page.h b/include/asm-h8300/page.h
+index d673077..3b4f290 100644
+--- a/include/asm-h8300/page.h
++++ b/include/asm-h8300/page.h
+@@ -1,6 +1,7 @@
+ #ifndef _H8300_PAGE_H
+ #define _H8300_PAGE_H
+
++#ifdef __KERNEL__
+
+ /* PAGE_SHIFT determines the page size */
+
+@@ -8,8 +9,6 @@
+ #define PAGE_SIZE (1UL << PAGE_SHIFT)
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+
+-#ifdef __KERNEL__
+-
+ #include <asm/setup.h>
+
+ #ifndef __ASSEMBLY__
+@@ -76,9 +75,9 @@ extern unsigned long memory_end;
+
+ #endif /* __ASSEMBLY__ */
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++#endif /* __KERNEL__ */
++
+ #endif /* _H8300_PAGE_H */
+diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h
+index 226dd59..747788d 100644
+--- a/include/asm-h8300/unistd.h
++++ b/include/asm-h8300/unistd.h
+@@ -295,14 +295,14 @@
+ #ifdef __KERNEL__
+
+ #define NR_syscalls 289
++#include <linux/err.h>
+
+-
+-/* user-visible error numbers are in the range -1 - -122: see
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
+ <asm-m68k/errno.h> */
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ /* avoid using res which is declared to be in register d0; \
+ errno might expand to a function call and clobber it. */ \
+ int __err = -(res); \
+@@ -485,57 +485,6 @@ type name(atype a, btype b, ctype c, dty
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static inline _syscall0(int,pause)
+-static inline _syscall0(int,sync)
+-static inline _syscall0(pid_t,setsid)
+-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static inline _syscall1(int,dup,int,fd)
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+-static inline _syscall1(int,close,int,fd)
+-static inline _syscall1(int,_exit,int,exitcode)
+-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-static inline _syscall1(int,delete_module,const char *,name)
+-
+-static inline pid_t wait(int * wait_stat)
+-{
+- return waitpid(-1,wait_stat,0);
+-}
+-
+-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(char *name, char **argv, char **envp,
+- int dummy, ...);
+-asmlinkage int sys_pipe(unsigned long *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ */
+diff --git a/include/asm-i386/Kbuild b/include/asm-i386/Kbuild
+index 2308190..147e4ac 100644
+--- a/include/asm-i386/Kbuild
++++ b/include/asm-i386/Kbuild
+@@ -1,5 +1,11 @@
+ include include/asm-generic/Kbuild.asm
+
+-header-y += boot.h debugreg.h ldt.h ucontext.h
++header-y += boot.h
++header-y += debugreg.h
++header-y += ldt.h
++header-y += ptrace-abi.h
++header-y += ucontext.h
+
+-unifdef-y += mtrr.h setup.h vm86.h
++unifdef-y += mtrr.h
++unifdef-y += setup.h
++unifdef-y += vm86.h
+diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
+index 20f5239..6016632 100644
+--- a/include/asm-i386/acpi.h
++++ b/include/asm-i386/acpi.h
+@@ -131,21 +131,7 @@ static inline void disable_acpi(void)
+ extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
+
+ #ifdef CONFIG_X86_IO_APIC
+-extern int skip_ioapic_setup;
+ extern int acpi_skip_timer_override;
+-
+-static inline void disable_ioapic_setup(void)
+-{
+- skip_ioapic_setup = 1;
+-}
+-
+-static inline int ioapic_setup_disabled(void)
+-{
+- return skip_ioapic_setup;
+-}
+-
+-#else
+-static inline void disable_ioapic_setup(void) { }
+ #endif
+
+ static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
+diff --git a/include/asm-i386/alternative-asm.i b/include/asm-i386/alternative-asm.i
+new file mode 100644
+index 0000000..f051020
+--- /dev/null
++++ b/include/asm-i386/alternative-asm.i
+@@ -0,0 +1,12 @@
++#ifdef CONFIG_SMP
++ .macro LOCK_PREFIX
++1: lock
++ .section .smp_locks,"a"
++ .align 4
++ .long 1b
++ .previous
++ .endm
++#else
++ .macro LOCK_PREFIX
++ .endm
++#endif
+diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
+index 2c1e371..b952957 100644
+--- a/include/asm-i386/apic.h
++++ b/include/asm-i386/apic.h
+@@ -16,20 +16,8 @@
+ #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
+@@ -42,6 +30,8 @@ static inline void lapic_enable(void)
+ } while (0)
+
+
++extern void generic_apic_probe(void);
++
+ #ifdef CONFIG_X86_LOCAL_APIC
+
+ /*
+@@ -108,7 +98,7 @@ extern void sync_Arb_IDs (void);
+ extern void init_bsp_APIC (void);
+ extern void setup_local_APIC (void);
+ extern void init_apic_mappings (void);
+-extern void smp_local_timer_interrupt (struct pt_regs * regs);
++extern void smp_local_timer_interrupt (void);
+ extern void setup_boot_APIC_clock (void);
+ extern void setup_secondary_APIC_clock (void);
+ extern int APIC_init_uniprocessor (void);
+@@ -117,9 +107,7 @@ extern void enable_APIC_timer(void);
+
+ extern void enable_NMI_through_LVT0 (void * dummy);
+
+-extern int disable_timer_pin_1;
+-
+-void smp_send_timer_broadcast_ipi(struct pt_regs *regs);
++void smp_send_timer_broadcast_ipi(void);
+ void switch_APIC_timer_to_ipi(void *cpumask);
+ void switch_ipi_to_APIC_timer(void *cpumask);
+ #define ARCH_APICTIMER_STOPS_ON_C3 1
+diff --git a/include/asm-i386/arch_hooks.h b/include/asm-i386/arch_hooks.h
+index 238cf42..a8c1fca 100644
+--- a/include/asm-i386/arch_hooks.h
++++ b/include/asm-i386/arch_hooks.h
+@@ -14,7 +14,7 @@
+ extern void init_ISA_irqs(void);
+ extern void apic_intr_init(void);
+ extern void smp_intr_init(void);
+-extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t timer_interrupt(int irq, void *dev_id);
+
+ /* these are the defined hooks */
+ extern void intr_init_hook(void);
+diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
+index 2a9e4ee..592ffee 100644
+--- a/include/asm-i386/bugs.h
++++ b/include/asm-i386/bugs.h
+@@ -189,6 +189,6 @@ static void __init check_bugs(void)
+ check_fpu();
+ check_hlt();
+ check_popad();
+- system_utsname.machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
++ init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+ alternative_instructions();
+ }
+diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h
+index 89b8b82..5874ef1 100644
+--- a/include/asm-i386/desc.h
++++ b/include/asm-i386/desc.h
+@@ -33,50 +33,99 @@ static inline struct desc_struct *get_cp
+ return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address;
+ }
+
++/*
++ * This is the ldt that every process will get unless we need
++ * something other than this.
++ */
++extern struct desc_struct default_ldt[];
++extern struct desc_struct idt_table[];
++extern void set_intr_gate(unsigned int irq, void * addr);
++
++static inline void pack_descriptor(__u32 *a, __u32 *b,
++ unsigned long base, unsigned long limit, unsigned char type, unsigned char flags)
++{
++ *a = ((base & 0xffff) << 16) | (limit & 0xffff);
++ *b = (base & 0xff000000) | ((base & 0xff0000) >> 16) |
++ (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20);
++}
++
++static inline void pack_gate(__u32 *a, __u32 *b,
++ unsigned long base, unsigned short seg, unsigned char type, unsigned char flags)
++{
++ *a = (seg << 16) | (base & 0xffff);
++ *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff);
++}
++
++#define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */
++#define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */
++#define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */
++#define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */
++#define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */
++#define DESCTYPE_DPL3 0x60 /* DPL-3 */
++#define DESCTYPE_S 0x10 /* !system */
++
+ #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
+ #define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8))
+
+ #define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
+ #define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
+-#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr))
+-#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt))
++#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr))
++#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt))
+
+ #define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr))
+ #define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr))
+-#define store_tr(tr) __asm__ ("str %0":"=mr" (tr))
+-#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt))
++#define store_tr(tr) __asm__ ("str %0":"=m" (tr))
++#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt))
+
+-/*
+- * This is the ldt that every process will get unless we need
+- * something other than this.
+- */
+-extern struct desc_struct default_ldt[];
+-extern void set_intr_gate(unsigned int irq, void * addr);
++#if TLS_SIZE != 24
++# error update this code.
++#endif
+
+-#define _set_tssldt_desc(n,addr,limit,type) \
+-__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
+- "movw %w1,2(%2)\n\t" \
+- "rorl $16,%1\n\t" \
+- "movb %b1,4(%2)\n\t" \
+- "movb %4,5(%2)\n\t" \
+- "movb $0,6(%2)\n\t" \
+- "movb %h1,7(%2)\n\t" \
+- "rorl $16,%1" \
+- : "=m"(*(n)) : "q" (addr), "r"(n), "ir"(limit), "i"(type))
+-
+-static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
++static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
+ {
+- _set_tssldt_desc(&get_cpu_gdt_table(cpu)[entry], (int)addr,
+- offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89);
++#define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]
++ C(0); C(1); C(2);
++#undef C
+ }
+
+-#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
++static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b)
++{
++ __u32 *lp = (__u32 *)((char *)dt + entry*8);
++ *lp = entry_a;
++ *(lp+1) = entry_b;
++}
++
++#define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b)
++#define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b)
++#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b)
++
++static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg)
++{
++ __u32 a, b;
++ pack_gate(&a, &b, (unsigned long)addr, seg, type, 0);
++ write_idt_entry(idt_table, gate, a, b);
++}
+
+-static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
++static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr)
+ {
+- _set_tssldt_desc(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82);
++ __u32 a, b;
++ pack_descriptor(&a, &b, (unsigned long)addr,
++ offsetof(struct tss_struct, __cacheline_filler) - 1,
++ DESCTYPE_TSS, 0);
++ write_gdt_entry(get_cpu_gdt_table(cpu), entry, a, b);
+ }
+
++static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int entries)
++{
++ __u32 a, b;
++ pack_descriptor(&a, &b, (unsigned long)addr,
++ entries * sizeof(struct desc_struct) - 1,
++ DESCTYPE_LDT, 0);
++ write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, a, b);
++}
++
++#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
++
+ #define LDT_entry_a(info) \
+ ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
+
+@@ -102,24 +151,6 @@ static inline void set_ldt_desc(unsigned
+ (info)->seg_not_present == 1 && \
+ (info)->useable == 0 )
+
+-static inline void write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b)
+-{
+- __u32 *lp = (__u32 *)((char *)ldt + entry*8);
+- *lp = entry_a;
+- *(lp+1) = entry_b;
+-}
+-
+-#if TLS_SIZE != 24
+-# error update this code.
+-#endif
+-
+-static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
+-{
+-#define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]
+- C(0); C(1); C(2);
+-#undef C
+-}
+-
+ static inline void clear_LDT(void)
+ {
+ int cpu = get_cpu();
+diff --git a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h
+index 9cf20ca..81999a3 100644
+--- a/include/asm-i386/dma-mapping.h
++++ b/include/asm-i386/dma-mapping.h
+@@ -21,8 +21,7 @@ static inline dma_addr_t
+ dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction)
+ {
+- if (direction == DMA_NONE)
+- BUG();
++ BUG_ON(!valid_dma_direction(direction));
+ WARN_ON(size == 0);
+ flush_write_buffers();
+ return virt_to_phys(ptr);
+@@ -32,8 +31,7 @@ static inline void
+ dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction)
+ {
+- if (direction == DMA_NONE)
+- BUG();
++ BUG_ON(!valid_dma_direction(direction));
+ }
+
+ static inline int
+@@ -42,8 +40,7 @@ dma_map_sg(struct device *dev, struct sc
+ {
+ int i;
+
+- if (direction == DMA_NONE)
+- BUG();
++ BUG_ON(!valid_dma_direction(direction));
+ WARN_ON(nents == 0 || sg[0].length == 0);
+
+ for (i = 0; i < nents; i++ ) {
+@@ -60,7 +57,7 @@ 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);
++ BUG_ON(!valid_dma_direction(direction));
+ return page_to_phys(page) + offset;
+ }
+
+@@ -68,7 +65,7 @@ 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);
++ BUG_ON(!valid_dma_direction(direction));
+ }
+
+
+@@ -76,7 +73,7 @@ static inline void
+ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+ enum dma_data_direction direction)
+ {
+- BUG_ON(direction == DMA_NONE);
++ BUG_ON(!valid_dma_direction(direction));
+ }
+
+ static inline void
+diff --git a/include/asm-i386/dwarf2.h b/include/asm-i386/dwarf2.h
+index 2280f62..6d66398 100644
+--- a/include/asm-i386/dwarf2.h
++++ b/include/asm-i386/dwarf2.h
+@@ -1,8 +1,6 @@
+ #ifndef _DWARF2_H
+ #define _DWARF2_H
+
+-#include <linux/config.h>
+-
+ #ifndef __ASSEMBLY__
+ #warning "asm/dwarf2.h should be only included in pure assembly files"
+ #endif
+@@ -28,6 +26,13 @@
+ #define CFI_RESTORE .cfi_restore
+ #define CFI_REMEMBER_STATE .cfi_remember_state
+ #define CFI_RESTORE_STATE .cfi_restore_state
++#define CFI_UNDEFINED .cfi_undefined
++
++#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
++#define CFI_SIGNAL_FRAME .cfi_signal_frame
++#else
++#define CFI_SIGNAL_FRAME
++#endif
+
+ #else
+
+@@ -48,6 +53,8 @@
+ #define CFI_RESTORE ignore
+ #define CFI_REMEMBER_STATE ignore
+ #define CFI_RESTORE_STATE ignore
++#define CFI_UNDEFINED ignore
++#define CFI_SIGNAL_FRAME ignore
+
+ #endif
+
+diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
+index ca82acb..f7514fb 100644
+--- a/include/asm-i386/e820.h
++++ b/include/asm-i386/e820.h
+@@ -18,7 +18,7 @@
+
+ #define E820_RAM 1
+ #define E820_RESERVED 2
+-#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
++#define E820_ACPI 3
+ #define E820_NVS 4
+
+ #define HIGH_MEMORY (1024*1024)
+diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
+index db4344d..3a05436 100644
+--- a/include/asm-i386/elf.h
++++ b/include/asm-i386/elf.h
+@@ -112,7 +112,7 @@ typedef struct user_fxsr_struct elf_fpxr
+ For the moment, we have only optimizations for the Intel generations,
+ but that could change... */
+
+-#define ELF_PLATFORM (system_utsname.machine)
++#define ELF_PLATFORM (utsname()->machine)
+
+ #define SET_PERSONALITY(ex, ibcs2) do { } while (0)
+
+diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
+index a48cc3f..02428cb 100644
+--- a/include/asm-i386/fixmap.h
++++ b/include/asm-i386/fixmap.h
+@@ -19,7 +19,11 @@
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap.
+ */
+-#define __FIXADDR_TOP 0xfffff000
++#ifndef CONFIG_COMPAT_VDSO
++extern unsigned long __FIXADDR_TOP;
++#else
++#define __FIXADDR_TOP 0xfffff000
++#endif
+
+ #ifndef __ASSEMBLY__
+ #include <linux/kernel.h>
+@@ -93,6 +97,7 @@ enum fixed_addresses {
+
+ extern void __set_fixmap (enum fixed_addresses idx,
+ unsigned long phys, pgprot_t flags);
++extern void reserve_top_address(unsigned long reserve);
+
+ #define set_fixmap(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL)
+diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h
+index 359ead6..44ef2f5 100644
+--- a/include/asm-i386/floppy.h
++++ b/include/asm-i386/floppy.h
+@@ -51,7 +51,7 @@ static char *virtual_dma_addr;
+ static int virtual_dma_mode;
+ static int doing_pdma;
+
+-static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t floppy_hardint(int irq, void *dev_id)
+ {
+ register unsigned char st;
+
+@@ -63,7 +63,7 @@ static irqreturn_t floppy_hardint(int ir
+ static int dma_wait=0;
+ #endif
+ if (!doing_pdma)
+- return floppy_interrupt(irq, dev_id, regs);
++ return floppy_interrupt(irq, dev_id);
+
+ #ifdef TRACE_FLPY_INT
+ if(!calls)
+@@ -106,7 +106,7 @@ static irqreturn_t floppy_hardint(int ir
+ dma_wait=0;
+ #endif
+ doing_pdma = 0;
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+ #ifdef TRACE_FLPY_INT
+diff --git a/include/asm-i386/frame.i b/include/asm-i386/frame.i
+new file mode 100644
+index 0000000..0362025
+--- /dev/null
++++ b/include/asm-i386/frame.i
+@@ -0,0 +1,23 @@
++#include <asm/dwarf2.h>
++
++/* The annotation hides the frame from the unwinder and makes it look
++ like a ordinary ebp save/restore. This avoids some special cases for
++ frame pointer later */
++#ifdef CONFIG_FRAME_POINTER
++ .macro FRAME
++ pushl %ebp
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ebp,0
++ movl %esp,%ebp
++ .endm
++ .macro ENDFRAME
++ popl %ebp
++ CFI_ADJUST_CFA_OFFSET -4
++ CFI_RESTORE ebp
++ .endm
++#else
++ .macro FRAME
++ .endm
++ .macro ENDFRAME
++ .endm
++#endif
+diff --git a/include/asm-i386/genapic.h b/include/asm-i386/genapic.h
+index b3783a3..8ffbb0f 100644
+--- a/include/asm-i386/genapic.h
++++ b/include/asm-i386/genapic.h
+@@ -1,6 +1,8 @@
+ #ifndef _ASM_GENAPIC_H
+ #define _ASM_GENAPIC_H 1
+
++#include <asm/mpspec.h>
++
+ /*
+ * Generic APIC driver interface.
+ *
+@@ -63,14 +65,25 @@ struct genapic {
+ unsigned (*get_apic_id)(unsigned long x);
+ unsigned long apic_id_mask;
+ unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask);
+-
++
++#ifdef CONFIG_SMP
+ /* ipi */
+ void (*send_IPI_mask)(cpumask_t mask, int vector);
+ void (*send_IPI_allbutself)(int vector);
+ void (*send_IPI_all)(int vector);
++#endif
+ };
+
+-#define APICFUNC(x) .x = x
++#define APICFUNC(x) .x = x,
++
++/* More functions could be probably marked IPIFUNC and save some space
++ in UP GENERICARCH kernels, but I don't have the nerve right now
++ to untangle this mess. -AK */
++#ifdef CONFIG_SMP
++#define IPIFUNC(x) APICFUNC(x)
++#else
++#define IPIFUNC(x)
++#endif
+
+ #define APIC_INIT(aname, aprobe) { \
+ .name = aname, \
+@@ -80,33 +93,33 @@ struct genapic {
+ .no_balance_irq = NO_BALANCE_IRQ, \
+ .ESR_DISABLE = esr_disable, \
+ .apic_destination_logical = APIC_DEST_LOGICAL, \
+- APICFUNC(apic_id_registered), \
+- APICFUNC(target_cpus), \
+- APICFUNC(check_apicid_used), \
+- APICFUNC(check_apicid_present), \
+- APICFUNC(init_apic_ldr), \
+- APICFUNC(ioapic_phys_id_map), \
+- APICFUNC(clustered_apic_check), \
+- APICFUNC(multi_timer_check), \
+- APICFUNC(apicid_to_node), \
+- APICFUNC(cpu_to_logical_apicid), \
+- APICFUNC(cpu_present_to_apicid), \
+- APICFUNC(apicid_to_cpu_present), \
+- APICFUNC(mpc_apic_id), \
+- APICFUNC(setup_portio_remap), \
+- APICFUNC(check_phys_apicid_present), \
+- APICFUNC(mpc_oem_bus_info), \
+- APICFUNC(mpc_oem_pci_bus), \
+- APICFUNC(mps_oem_check), \
+- APICFUNC(get_apic_id), \
++ APICFUNC(apic_id_registered) \
++ APICFUNC(target_cpus) \
++ APICFUNC(check_apicid_used) \
++ APICFUNC(check_apicid_present) \
++ APICFUNC(init_apic_ldr) \
++ APICFUNC(ioapic_phys_id_map) \
++ APICFUNC(clustered_apic_check) \
++ APICFUNC(multi_timer_check) \
++ APICFUNC(apicid_to_node) \
++ APICFUNC(cpu_to_logical_apicid) \
++ APICFUNC(cpu_present_to_apicid) \
++ APICFUNC(apicid_to_cpu_present) \
++ APICFUNC(mpc_apic_id) \
++ APICFUNC(setup_portio_remap) \
++ APICFUNC(check_phys_apicid_present) \
++ APICFUNC(mpc_oem_bus_info) \
++ APICFUNC(mpc_oem_pci_bus) \
++ APICFUNC(mps_oem_check) \
++ APICFUNC(get_apic_id) \
+ .apic_id_mask = APIC_ID_MASK, \
+- APICFUNC(cpu_mask_to_apicid), \
+- APICFUNC(acpi_madt_oem_check), \
+- APICFUNC(send_IPI_mask), \
+- APICFUNC(send_IPI_allbutself), \
+- APICFUNC(send_IPI_all), \
+- APICFUNC(enable_apic_mode), \
+- APICFUNC(phys_pkg_id), \
++ APICFUNC(cpu_mask_to_apicid) \
++ APICFUNC(acpi_madt_oem_check) \
++ IPIFUNC(send_IPI_mask) \
++ IPIFUNC(send_IPI_allbutself) \
++ IPIFUNC(send_IPI_all) \
++ APICFUNC(enable_apic_mode) \
++ APICFUNC(phys_pkg_id) \
+ }
+
+ extern struct genapic *genapic;
+diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
+index af5d435..e47be9a 100644
+--- a/include/asm-i386/hpet.h
++++ b/include/asm-i386/hpet.h
+@@ -108,7 +108,7 @@ extern int hpet_set_alarm_time(unsigned
+ extern int hpet_set_periodic_freq(unsigned long freq);
+ extern int hpet_rtc_dropped_irq(void);
+ extern int hpet_rtc_timer_init(void);
+-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+ #endif /* CONFIG_HPET_EMULATE_RTC */
+ #endif /* CONFIG_HPET_TIMER */
+ #endif /* _I386_HPET_H */
+diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
+index 87e5a35..0bedbdf 100644
+--- a/include/asm-i386/hw_irq.h
++++ b/include/asm-i386/hw_irq.h
+@@ -17,8 +17,6 @@
+ #include <asm/irq.h>
+ #include <asm/sections.h>
+
+-struct hw_interrupt_type;
+-
+ #define NMI_VECTOR 0x02
+
+ /*
+@@ -28,10 +26,6 @@ struct hw_interrupt_type;
+ * Interrupt entry/exit code at both C and assembly level
+ */
+
+-extern u8 irq_vector[NR_IRQ_VECTORS];
+-#define IO_APIC_VECTOR(irq) (irq_vector[irq])
+-#define AUTO_ASSIGN -1
+-
+ extern void (*interrupt[NR_IRQS])(void);
+
+ #ifdef CONFIG_SMP
+@@ -44,7 +38,7 @@ fastcall void call_function_interrupt(vo
+ fastcall void apic_timer_interrupt(void);
+ fastcall void error_interrupt(void);
+ fastcall void spurious_interrupt(void);
+-fastcall void thermal_interrupt(struct pt_regs *);
++fastcall void thermal_interrupt(void);
+ #define platform_legacy_irq(irq) ((irq) < 16)
+ #endif
+
+diff --git a/include/asm-i386/hypertransport.h b/include/asm-i386/hypertransport.h
+new file mode 100644
+index 0000000..c16c6ff
+--- /dev/null
++++ b/include/asm-i386/hypertransport.h
+@@ -0,0 +1,42 @@
++#ifndef ASM_HYPERTRANSPORT_H
++#define ASM_HYPERTRANSPORT_H
++
++/*
++ * Constants for x86 Hypertransport Interrupts.
++ */
++
++#define HT_IRQ_LOW_BASE 0xf8000000
++
++#define HT_IRQ_LOW_VECTOR_SHIFT 16
++#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
++#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
++
++#define HT_IRQ_LOW_DEST_ID_SHIFT 8
++#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
++#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
++
++#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
++#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
++
++#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
++#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
++
++
++#define HT_IRQ_LOW_MT_FIXED 0x0000000
++#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
++#define HT_IRQ_LOW_MT_SMI 0x0000008
++#define HT_IRQ_LOW_MT_NMI 0x000000c
++#define HT_IRQ_LOW_MT_INIT 0x0000010
++#define HT_IRQ_LOW_MT_STARTUP 0x0000014
++#define HT_IRQ_LOW_MT_EXTINT 0x0000018
++#define HT_IRQ_LOW_MT_LINT1 0x000008c
++#define HT_IRQ_LOW_MT_LINT0 0x0000098
++
++#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
++
++
++#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
++#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
++#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
++
++#endif /* ASM_HYPERTRANSPORT_H */
+diff --git a/include/asm-i386/intel_arch_perfmon.h b/include/asm-i386/intel_arch_perfmon.h
+index 134ea9c..b52cd60 100644
+--- a/include/asm-i386/intel_arch_perfmon.h
++++ b/include/asm-i386/intel_arch_perfmon.h
+@@ -14,6 +14,18 @@
+
+ #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL (0x3c)
+ #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
+-#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
++#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX (0)
++#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
++ (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
++
++union cpuid10_eax {
++ struct {
++ unsigned int version_id:8;
++ unsigned int num_counters:8;
++ unsigned int bit_width:8;
++ unsigned int mask_length:8;
++ } split;
++ unsigned int full;
++};
+
+ #endif /* X86_INTEL_ARCH_PERFMON_H */
+diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
+index b3724fe..68df0dc 100644
+--- a/include/asm-i386/io.h
++++ b/include/asm-i386/io.h
+@@ -224,33 +224,6 @@ static inline void memcpy_toio(volatile
+
+ #define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d))
+
+-/**
+- * check_signature - find BIOS signatures
+- * @io_addr: mmio address to check
+- * @signature: signature block
+- * @length: length of signature
+- *
+- * Perform a signature comparison with the mmio address io_addr. This
+- * address should have been obtained by ioremap.
+- * Returns 1 on a match.
+- */
+-
+-static inline int check_signature(volatile void __iomem * io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ /*
+ * Cache management
+ *
+diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h
+index 5092e81..059a9ff 100644
+--- a/include/asm-i386/io_apic.h
++++ b/include/asm-i386/io_apic.h
+@@ -12,50 +12,6 @@
+
+ #ifdef CONFIG_X86_IO_APIC
+
+-#ifdef CONFIG_PCI_MSI
+-static inline int use_pci_vector(void) {return 1;}
+-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+-static inline void end_edge_ioapic_vector (unsigned int vector) { }
+-#define startup_level_ioapic startup_level_ioapic_vector
+-#define shutdown_level_ioapic mask_IO_APIC_vector
+-#define enable_level_ioapic unmask_IO_APIC_vector
+-#define disable_level_ioapic mask_IO_APIC_vector
+-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
+-#define end_level_ioapic end_level_ioapic_vector
+-#define set_ioapic_affinity set_ioapic_affinity_vector
+-
+-#define startup_edge_ioapic startup_edge_ioapic_vector
+-#define shutdown_edge_ioapic disable_edge_ioapic_vector
+-#define enable_edge_ioapic unmask_IO_APIC_vector
+-#define disable_edge_ioapic disable_edge_ioapic_vector
+-#define ack_edge_ioapic ack_edge_ioapic_vector
+-#define end_edge_ioapic end_edge_ioapic_vector
+-#else
+-static inline int use_pci_vector(void) {return 0;}
+-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
+-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
+-static inline void end_edge_ioapic_irq (unsigned int irq) { }
+-#define startup_level_ioapic startup_level_ioapic_irq
+-#define shutdown_level_ioapic mask_IO_APIC_irq
+-#define enable_level_ioapic unmask_IO_APIC_irq
+-#define disable_level_ioapic mask_IO_APIC_irq
+-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
+-#define end_level_ioapic end_level_ioapic_irq
+-#define set_ioapic_affinity set_ioapic_affinity_irq
+-
+-#define startup_edge_ioapic startup_edge_ioapic_irq
+-#define shutdown_edge_ioapic disable_edge_ioapic_irq
+-#define enable_edge_ioapic unmask_IO_APIC_irq
+-#define disable_edge_ioapic disable_edge_ioapic_irq
+-#define ack_edge_ioapic ack_edge_ioapic_irq
+-#define end_edge_ioapic end_edge_ioapic_irq
+-#endif
+-
+-#define IO_APIC_BASE(idx) \
+- ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
+- + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
+-
+ /*
+ * The structure of the IO-APIC:
+ */
+@@ -159,35 +115,22 @@ extern struct mpc_config_intsrc mp_irqs[
+ /* non-0 if default (table-less) MP configuration */
+ extern int mpc_default_type;
+
+-static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+-{
+- *IO_APIC_BASE(apic) = reg;
+- return *(IO_APIC_BASE(apic)+4);
+-}
++/* Older SiS APIC requires we rewrite the index register */
++extern int sis_apic_bug;
++
++/* 1 if "noapic" boot option passed */
++extern int skip_ioapic_setup;
+
+-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
++static inline void disable_ioapic_setup(void)
+ {
+- *IO_APIC_BASE(apic) = reg;
+- *(IO_APIC_BASE(apic)+4) = value;
++ skip_ioapic_setup = 1;
+ }
+
+-/*
+- * Re-write a value: to be used for read-modify-write
+- * cycles where the read already set up the index register.
+- *
+- * Older SiS APIC requires we rewrite the index regiser
+- */
+-extern int sis_apic_bug;
+-static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
++static inline int ioapic_setup_disabled(void)
+ {
+- if (sis_apic_bug)
+- *IO_APIC_BASE(apic) = reg;
+- *(IO_APIC_BASE(apic)+4) = value;
++ return skip_ioapic_setup;
+ }
+
+-/* 1 if "noapic" boot option passed */
+-extern int skip_ioapic_setup;
+-
+ /*
+ * If we use the IO-APIC for IRQ routing, disable automatic
+ * assignment of PCI IRQ's.
+@@ -206,8 +149,7 @@ extern int (*ioapic_renumber_irq)(int io
+
+ #else /* !CONFIG_X86_IO_APIC */
+ #define io_apic_assign_pci_irqs 0
++static inline void disable_ioapic_setup(void) { }
+ #endif
+
+-extern int assign_irq_vector(int irq);
+-
+ #endif
+diff --git a/include/asm-i386/irq_regs.h b/include/asm-i386/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-i386/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-i386/kexec.h b/include/asm-i386/kexec.h
+index 53f0e06..4dfc9f5 100644
+--- a/include/asm-i386/kexec.h
++++ b/include/asm-i386/kexec.h
+@@ -1,6 +1,26 @@
+ #ifndef _I386_KEXEC_H
+ #define _I386_KEXEC_H
+
++#define PA_CONTROL_PAGE 0
++#define VA_CONTROL_PAGE 1
++#define PA_PGD 2
++#define VA_PGD 3
++#define PA_PTE_0 4
++#define VA_PTE_0 5
++#define PA_PTE_1 6
++#define VA_PTE_1 7
++#ifdef CONFIG_X86_PAE
++#define PA_PMD_0 8
++#define VA_PMD_0 9
++#define PA_PMD_1 10
++#define VA_PMD_1 11
++#define PAGES_NR 12
++#else
++#define PAGES_NR 8
++#endif
++
++#ifndef __ASSEMBLY__
++
+ #include <asm/fixmap.h>
+ #include <asm/ptrace.h>
+ #include <asm/string.h>
+@@ -72,5 +92,12 @@ static inline void crash_setup_regs(stru
+ newregs->eip = (unsigned long)current_text_addr();
+ }
+ }
++asmlinkage NORET_TYPE void
++relocate_kernel(unsigned long indirection_page,
++ unsigned long control_page,
++ unsigned long start_address,
++ unsigned int has_pae) ATTRIB_NORET;
++
++#endif /* __ASSEMBLY__ */
+
+ #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 6312c3e..7d606e3 100644
+--- a/include/asm-i386/mach-default/do_timer.h
++++ b/include/asm-i386/mach-default/do_timer.h
+@@ -14,11 +14,11 @@
+ * timer interrupt as a means of triggering reschedules etc.
+ **/
+
+-static inline void do_timer_interrupt_hook(struct pt_regs *regs)
++static inline void do_timer_interrupt_hook(void)
+ {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode_vm(regs));
++ update_process_times(user_mode_vm(get_irq_regs()));
+ #endif
+ /*
+ * In the SMP case we use the local APIC timer interrupt to do the
+@@ -26,10 +26,10 @@ static inline void do_timer_interrupt_ho
+ * system, in that case we have to call the local interrupt handler.
+ */
+ #ifndef CONFIG_X86_LOCAL_APIC
+- profile_tick(CPU_PROFILING, regs);
++ profile_tick(CPU_PROFILING);
+ #else
+ if (!using_apic_timer)
+- smp_local_timer_interrupt(regs);
++ smp_local_timer_interrupt();
+ #endif
+ }
+
+diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
+index b330026..7f161e7 100644
+--- a/include/asm-i386/mach-default/irq_vectors_limits.h
++++ b/include/asm-i386/mach-default/irq_vectors_limits.h
+@@ -1,10 +1,6 @@
+ #ifndef _ASM_IRQ_VECTORS_LIMITS_H
+ #define _ASM_IRQ_VECTORS_LIMITS_H
+
+-#ifdef CONFIG_PCI_MSI
+-#define NR_IRQS FIRST_SYSTEM_VECTOR
+-#define NR_IRQ_VECTORS NR_IRQS
+-#else
+ #ifdef CONFIG_X86_IO_APIC
+ #define NR_IRQS 224
+ # if (224 >= 32 * NR_CPUS)
+@@ -16,6 +12,5 @@
+ #define NR_IRQS 16
+ #define NR_IRQ_VECTORS NR_IRQS
+ #endif
+-#endif
+
+ #endif /* _ASM_IRQ_VECTORS_LIMITS_H */
+diff --git a/include/asm-i386/mach-es7000/mach_apic.h b/include/asm-i386/mach-es7000/mach_apic.h
+index b5f3f0d..2633368 100644
+--- a/include/asm-i386/mach-es7000/mach_apic.h
++++ b/include/asm-i386/mach-es7000/mach_apic.h
+@@ -123,9 +123,13 @@ extern u8 cpu_2_logical_apicid[];
+ /* Mapping from cpu number to logical apicid */
+ static inline int cpu_to_logical_apicid(int cpu)
+ {
++#ifdef CONFIG_SMP
+ if (cpu >= NR_CPUS)
+ return BAD_APICID;
+ return (int)cpu_2_logical_apicid[cpu];
++#else
++ return logical_smp_processor_id();
++#endif
+ }
+
+ static inline int mpc_apic_id(struct mpc_config_processor *m, struct mpc_config_translation *unused)
+diff --git a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h
+index 9fd0732..ef0671e 100644
+--- a/include/asm-i386/mach-summit/mach_apic.h
++++ b/include/asm-i386/mach-summit/mach_apic.h
+@@ -46,10 +46,12 @@ extern u8 cpu_2_logical_apicid[];
+ static inline void init_apic_ldr(void)
+ {
+ unsigned long val, id;
+- int i, count;
+- u8 lid;
++ int count = 0;
+ u8 my_id = (u8)hard_smp_processor_id();
+ u8 my_cluster = (u8)apicid_cluster(my_id);
++#ifdef CONFIG_SMP
++ u8 lid;
++ int i;
+
+ /* Create logical APIC IDs by counting CPUs already in cluster. */
+ for (count = 0, i = NR_CPUS; --i >= 0; ) {
+@@ -57,6 +59,7 @@ static inline void init_apic_ldr(void)
+ if (lid != BAD_APICID && apicid_cluster(lid) == my_cluster)
+ ++count;
+ }
++#endif
+ /* We only have a 4 wide bitmap in cluster mode. If a deranged
+ * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
+ BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
+@@ -85,15 +88,19 @@ static inline void clustered_apic_check(
+
+ static inline int apicid_to_node(int logical_apicid)
+ {
+- return logical_apicid >> 5; /* 2 clusterids per CEC */
++ return apicid_2_node[hard_smp_processor_id()];
+ }
+
+ /* Mapping from cpu number to logical apicid */
+ static inline int cpu_to_logical_apicid(int cpu)
+ {
++#ifdef CONFIG_SMP
+ if (cpu >= NR_CPUS)
+ return BAD_APICID;
+ return (int)cpu_2_logical_apicid[cpu];
++#else
++ return logical_smp_processor_id();
++#endif
+ }
+
+ static inline int cpu_present_to_apicid(int mps_cpu)
+diff --git a/include/asm-i386/mach-visws/do_timer.h b/include/asm-i386/mach-visws/do_timer.h
+deleted file mode 100644
+index 95568e6..0000000
+--- a/include/asm-i386/mach-visws/do_timer.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/* defines for inline arch setup functions */
+-
+-#include <asm/fixmap.h>
+-#include <asm/i8259.h>
+-#include "cobalt.h"
+-
+-static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+-{
+- /* Clear the interrupt */
+- co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);
+-
+- do_timer(regs);
+-#ifndef CONFIG_SMP
+- update_process_times(user_mode_vm(regs));
+-#endif
+-/*
+- * In the SMP case we use the local APIC timer interrupt to do the
+- * profiling, except when we simulate SMP mode on a uniprocessor
+- * system, in that case we have to call the local interrupt handler.
+- */
+-#ifndef CONFIG_X86_LOCAL_APIC
+- profile_tick(CPU_PROFILING, regs);
+-#else
+- if (!using_apic_timer)
+- smp_local_timer_interrupt(regs);
+-#endif
+-}
+-
+-static inline int do_timer_overflow(int count)
+-{
+- int i;
+-
+- spin_lock(&i8259A_lock);
+- /*
+- * This is tricky when I/O APICs are used;
+- * see do_timer_interrupt().
+- */
+- i = inb(0x20);
+- spin_unlock(&i8259A_lock);
+-
+- /* assumption about timer being IRQ0 */
+- if (i & 0x01) {
+- /*
+- * We cannot detect lost timer interrupts ...
+- * well, that's why we call them lost, don't we? :)
+- * [hmm, on the Pentium and Alpha we can ... sort of]
+- */
+- count -= LATCH;
+- } else {
+- printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+- }
+- return count;
+-}
+diff --git a/include/asm-i386/mach-visws/mach_apic.h b/include/asm-i386/mach-visws/mach_apic.h
+index de438c7..18afe6b 100644
+--- a/include/asm-i386/mach-visws/mach_apic.h
++++ b/include/asm-i386/mach-visws/mach_apic.h
+@@ -51,6 +51,11 @@ static inline void clustered_apic_check(
+ {
+ }
+
++static inline int apicid_to_node(int logical_apicid)
++{
++ return 0;
++}
++
+ /* Mapping from cpu number to logical apicid */
+ static inline int cpu_to_logical_apicid(int cpu)
+ {
+diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h
+index eaf5180..04e69c1 100644
+--- a/include/asm-i386/mach-voyager/do_timer.h
++++ b/include/asm-i386/mach-voyager/do_timer.h
+@@ -1,14 +1,14 @@
+ /* defines for inline arch setup functions */
+ #include <asm/voyager.h>
+
+-static inline void do_timer_interrupt_hook(struct pt_regs *regs)
++static inline void do_timer_interrupt_hook(void)
+ {
+- do_timer(regs);
++ do_timer(1);
+ #ifndef CONFIG_SMP
+- update_process_times(user_mode_vm(regs));
++ update_process_times(user_mode_vm(irq_regs));
+ #endif
+
+- voyager_timer_interrupt(regs);
++ voyager_timer_interrupt();
+ }
+
+ static inline int do_timer_overflow(int count)
+diff --git a/include/asm-i386/mca_dma.h b/include/asm-i386/mca_dma.h
+index 4b3b526..fbb1f3b 100644
+--- a/include/asm-i386/mca_dma.h
++++ b/include/asm-i386/mca_dma.h
+@@ -181,7 +181,7 @@ static __inline__ void mca_set_dma_io(un
+ * @mode: mode to set
+ *
+ * The DMA controller supports several modes. The mode values you can
+- * set are :
++ * set are-
+ *
+ * %MCA_DMA_MODE_READ when reading from the DMA device.
+ *
+@@ -190,7 +190,6 @@ static __inline__ void mca_set_dma_io(un
+ * %MCA_DMA_MODE_IO to do DMA to or from an I/O port.
+ *
+ * %MCA_DMA_MODE_16 to do 16bit transfers.
+- *
+ */
+
+ static __inline__ void mca_set_dma_mode(unsigned int dmanr, unsigned int mode)
+diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
+index 22cb07c..61b0733 100644
+--- a/include/asm-i386/mmzone.h
++++ b/include/asm-i386/mmzone.h
+@@ -38,10 +38,16 @@ static inline void get_memcfg_numa(void)
+ }
+
+ extern int early_pfn_to_nid(unsigned long pfn);
++extern void numa_kva_reserve(void);
+
+ #else /* !CONFIG_NUMA */
++
+ #define get_memcfg_numa get_memcfg_numa_flat
+ #define get_zholes_size(n) (0)
++
++static inline void numa_kva_reserve(void)
++{
++}
+ #endif /* CONFIG_NUMA */
+
+ #ifdef CONFIG_DISCONTIGMEM
+diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
+deleted file mode 100644
+index b11c4b7..0000000
+--- a/include/asm-i386/msi.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * Copyright (C) 2003-2004 Intel
+- * Copyright (C) Tom Long Nguyen (tom.l.nguyen at intel.com)
+- */
+-
+-#ifndef ASM_MSI_H
+-#define ASM_MSI_H
+-
+-#include <asm/desc.h>
+-#include <mach_apic.h>
+-
+-#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
+-#define MSI_TARGET_CPU_SHIFT 12
+-
+-extern struct msi_ops msi_apic_ops;
+-
+-static inline int msi_arch_init(void)
+-{
+- msi_register(&msi_apic_ops);
+- return 0;
+-}
+-
+-#endif /* ASM_MSI_H */
+diff --git a/include/asm-i386/msidef.h b/include/asm-i386/msidef.h
+new file mode 100644
+index 0000000..5b8acdd
+--- /dev/null
++++ b/include/asm-i386/msidef.h
+@@ -0,0 +1,47 @@
++#ifndef ASM_MSIDEF_H
++#define ASM_MSIDEF_H
++
++/*
++ * Constants for Intel APIC based MSI messages.
++ */
++
++/*
++ * Shifts for MSI data
++ */
++
++#define MSI_DATA_VECTOR_SHIFT 0
++#define MSI_DATA_VECTOR_MASK 0x000000ff
++#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
++
++#define MSI_DATA_DELIVERY_MODE_SHIFT 8
++#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
++#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
++
++#define MSI_DATA_LEVEL_SHIFT 14
++#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
++#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
++
++#define MSI_DATA_TRIGGER_SHIFT 15
++#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
++#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
++
++/*
++ * Shift/mask fields for msi address
++ */
++
++#define MSI_ADDR_BASE_HI 0
++#define MSI_ADDR_BASE_LO 0xfee00000
++
++#define MSI_ADDR_DEST_MODE_SHIFT 2
++#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
++#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
++
++#define MSI_ADDR_REDIRECTION_SHIFT 3
++#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
++#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
++
++#define MSI_ADDR_DEST_ID_SHIFT 12
++#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
++#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
++
++#endif /* ASM_MSIDEF_H */
+diff --git a/include/asm-i386/mutex.h b/include/asm-i386/mutex.h
+index 05a5385..7a17d9e 100644
+--- a/include/asm-i386/mutex.h
++++ b/include/asm-i386/mutex.h
+@@ -30,14 +30,10 @@ do { \
+ \
+ __asm__ __volatile__( \
+ LOCK_PREFIX " decl (%%eax) \n" \
+- " js 2f \n" \
++ " jns 1f \n" \
++ " call "#fail_fn" \n" \
+ "1: \n" \
+ \
+- LOCK_SECTION_START("") \
+- "2: call "#fail_fn" \n" \
+- " jmp 1b \n" \
+- LOCK_SECTION_END \
+- \
+ :"=a" (dummy) \
+ : "a" (count) \
+ : "memory", "ecx", "edx"); \
+@@ -86,14 +82,10 @@ do { \
+ \
+ __asm__ __volatile__( \
+ LOCK_PREFIX " incl (%%eax) \n" \
+- " jle 2f \n" \
++ " jg 1f \n" \
++ " call "#fail_fn" \n" \
+ "1: \n" \
+ \
+- LOCK_SECTION_START("") \
+- "2: call "#fail_fn" \n" \
+- " jmp 1b \n" \
+- LOCK_SECTION_END \
+- \
+ :"=a" (dummy) \
+ : "a" (count) \
+ : "memory", "ecx", "edx"); \
+diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
+index 67d9947..269d315 100644
+--- a/include/asm-i386/nmi.h
++++ b/include/asm-i386/nmi.h
+@@ -6,32 +6,29 @@
+
+ #include <linux/pm.h>
+
+-struct pt_regs;
+-
+-typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
+-
+-/**
+- * set_nmi_callback
+- *
+- * Set a handler for an NMI. Only one handler may be
+- * set. Return 1 if the NMI was handled.
+- */
+-void set_nmi_callback(nmi_callback_t callback);
+-
+ /**
+- * unset_nmi_callback
++ * do_nmi_callback
+ *
+- * Remove the handler previously set.
++ * Check to see if a callback exists and execute it. Return 1
++ * if the handler exists and was handled successfully.
+ */
+-void unset_nmi_callback(void);
+-
+-extern void setup_apic_nmi_watchdog (void);
+-extern int reserve_lapic_nmi(void);
+-extern void release_lapic_nmi(void);
++int do_nmi_callback(struct pt_regs *regs, int cpu);
++
++extern int nmi_watchdog_enabled;
++extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
++extern int avail_to_resrv_perfctr_nmi(unsigned int);
++extern int reserve_perfctr_nmi(unsigned int);
++extern void release_perfctr_nmi(unsigned int);
++extern int reserve_evntsel_nmi(unsigned int);
++extern void release_evntsel_nmi(unsigned int);
++
++extern void setup_apic_nmi_watchdog (void *);
++extern void stop_apic_nmi_watchdog (void *);
+ extern void disable_timer_nmi_watchdog(void);
+ extern void enable_timer_nmi_watchdog(void);
+-extern void nmi_watchdog_tick (struct pt_regs * regs);
++extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
+
++extern atomic_t nmi_active;
+ extern unsigned int nmi_watchdog;
+ #define NMI_DEFAULT -1
+ #define NMI_NONE 0
+@@ -39,4 +36,10 @@ extern unsigned int nmi_watchdog;
+ #define NMI_LOCAL_APIC 2
+ #define NMI_INVALID 3
+
++struct ctl_table;
++struct file;
++extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
++ void __user *, size_t *, loff_t *);
++extern int unknown_nmi_panic;
++
+ #endif /* ASM_NMI_H */
+diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
+index 2756d4b..8d8d3b9 100644
+--- a/include/asm-i386/pgtable-2level.h
++++ b/include/asm-i386/pgtable-2level.h
+@@ -16,13 +16,15 @@
+ #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+ #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+ #define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
++#define set_pte_present(mm,addr,ptep,pteval) set_pte_at(mm,addr,ptep,pteval)
+ #define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+
+ #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
+ #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
+
++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+ #define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte_low, 0))
+-#define pte_same(a, b) ((a).pte_low == (b).pte_low)
++
+ #define pte_page(x) pfn_to_page(pte_pfn(x))
+ #define pte_none(x) (!(x).pte_low)
+ #define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
+diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
+index dccb1b3..c2d701e 100644
+--- a/include/asm-i386/pgtable-3level.h
++++ b/include/asm-i386/pgtable-3level.h
+@@ -58,7 +58,21 @@ static inline void set_pte(pte_t *ptep,
+ }
+ #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+-#define __HAVE_ARCH_SET_PTE_ATOMIC
++/*
++ * Since this is only called on user PTEs, and the page fault handler
++ * must handle the already racy situation of simultaneous page faults,
++ * we are justified in merely clearing the PTE present bit, followed
++ * by a set. The ordering here is important.
++ */
++static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
++{
++ ptep->pte_low = 0;
++ smp_wmb();
++ ptep->pte_high = pte.pte_high;
++ smp_wmb();
++ ptep->pte_low = pte.pte_low;
++}
++
+ #define set_pte_atomic(pteptr,pteval) \
+ set_64bit((unsigned long long *)(pteptr),pte_val(pteval))
+ #define set_pmd(pmdptr,pmdval) \
+@@ -77,7 +91,7 @@ static inline void pud_clear (pud_t * pu
+ #define pud_page(pud) \
+ ((struct page *) __va(pud_val(pud) & PAGE_MASK))
+
+-#define pud_page_kernel(pud) \
++#define pud_page_vaddr(pud) \
+ ((unsigned long) __va(pud_val(pud) & PAGE_MASK))
+
+
+@@ -105,6 +119,7 @@ static inline void pmd_clear(pmd_t *pmd)
+ *(tmp + 1) = 0;
+ }
+
++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+ {
+ pte_t res;
+@@ -117,6 +132,7 @@ static inline pte_t ptep_get_and_clear(s
+ return res;
+ }
+
++#define __HAVE_ARCH_PTE_SAME
+ static inline int pte_same(pte_t a, pte_t b)
+ {
+ return a.pte_low == b.pte_low && a.pte_high == b.pte_high;
+diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
+index 09697fe..7d398f4 100644
+--- a/include/asm-i386/pgtable.h
++++ b/include/asm-i386/pgtable.h
+@@ -246,20 +246,85 @@ static inline pte_t pte_mkhuge(pte_t pte
+ # include <asm/pgtable-2level.h>
+ #endif
+
+-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+-{
+- if (!pte_dirty(*ptep))
+- return 0;
+- return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
+-}
++/*
++ * Rules for using pte_update - it must be called after any PTE update which
++ * has not been done using the set_pte / clear_pte interfaces. It is used by
++ * shadow mode hypervisors to resynchronize the shadow page tables. Kernel PTE
++ * updates should either be sets, clears, or set_pte_atomic for P->P
++ * transitions, which means this hook should only be called for user PTEs.
++ * This hook implies a P->P protection or access change has taken place, which
++ * requires a subsequent TLB flush. The notification can optionally be delayed
++ * until the TLB flush event by using the pte_update_defer form of the
++ * interface, but care must be taken to assure that the flush happens while
++ * still holding the same page table lock so that the shadow and primary pages
++ * do not become out of sync on SMP.
++ */
++#define pte_update(mm, addr, ptep) do { } while (0)
++#define pte_update_defer(mm, addr, ptep) do { } while (0)
+
+-static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+-{
+- if (!pte_young(*ptep))
+- return 0;
+- return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
+-}
+
++/*
++ * We only update the dirty/accessed state if we set
++ * the dirty bit by hand in the kernel, since the hardware
++ * will do the accessed bit for us, and we don't want to
++ * race with other CPU's that might be updating the dirty
++ * bit at the same time.
++ */
++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
++#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \
++do { \
++ if (dirty) { \
++ (ptep)->pte_low = (entry).pte_low; \
++ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \
++ flush_tlb_page(vma, address); \
++ } \
++} while (0)
++
++/*
++ * We don't actually have these, but we want to advertise them so that
++ * we can encompass the flush here.
++ */
++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
++
++/*
++ * Rules for using ptep_establish: the pte MUST be a user pte, and
++ * must be a present->present transition.
++ */
++#define __HAVE_ARCH_PTEP_ESTABLISH
++#define ptep_establish(vma, address, ptep, pteval) \
++do { \
++ set_pte_present((vma)->vm_mm, address, ptep, pteval); \
++ flush_tlb_page(vma, address); \
++} while (0)
++
++#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
++#define ptep_clear_flush_dirty(vma, address, ptep) \
++({ \
++ int __dirty; \
++ __dirty = pte_dirty(*(ptep)); \
++ if (__dirty) { \
++ clear_bit(_PAGE_BIT_DIRTY, &(ptep)->pte_low); \
++ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \
++ flush_tlb_page(vma, address); \
++ } \
++ __dirty; \
++})
++
++#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
++#define ptep_clear_flush_young(vma, address, ptep) \
++({ \
++ int __young; \
++ __young = pte_young(*(ptep)); \
++ if (__young) { \
++ clear_bit(_PAGE_BIT_ACCESSED, &(ptep)->pte_low); \
++ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \
++ flush_tlb_page(vma, address); \
++ } \
++ __young; \
++})
++
++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
+ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
+ {
+ pte_t pte;
+@@ -272,9 +337,11 @@ static inline pte_t ptep_get_and_clear_f
+ return pte;
+ }
+
++#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+ {
+ clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
++ pte_update(mm, addr, ptep);
+ }
+
+ /*
+@@ -364,11 +431,11 @@ static inline pte_t pte_modify(pte_t pte
+ #define pte_index(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
+
+ #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ /*
+@@ -391,8 +458,6 @@ extern pte_t *lookup_address(unsigned lo
+ static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;}
+ #endif
+
+-extern void noexec_setup(const char *str);
+-
+ #if defined(CONFIG_HIGHPTE)
+ #define pte_offset_map(dir, address) \
+ ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
+@@ -408,26 +473,18 @@ extern void noexec_setup(const char *str
+ #define pte_unmap_nested(pte) do { } while (0)
+ #endif
+
++/* Clear a kernel PTE and flush it from the TLB */
++#define kpte_clear_flush(ptep, vaddr) \
++do { \
++ pte_clear(&init_mm, vaddr, ptep); \
++ __flush_tlb_one(vaddr); \
++} while (0)
++
+ /*
+ * The i386 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+- *
+- * Also, we only update the dirty/accessed state if we set
+- * the dirty bit by hand in the kernel, since the hardware
+- * will do the accessed bit for us, and we don't want to
+- * race with other CPU's that might be updating the dirty
+- * bit at the same time.
+ */
+ #define update_mmu_cache(vma,address,pte) do { } while (0)
+-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+-#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+- do { \
+- if (__dirty) { \
+- (__ptep)->pte_low = (__entry).pte_low; \
+- flush_tlb_page(__vma, __address); \
+- } \
+- } while (0)
+-
+ #endif /* !__ASSEMBLY__ */
+
+ #ifdef CONFIG_FLATMEM
+@@ -441,12 +498,6 @@ extern void noexec_setup(const char *str
+ #define GET_IOSPACE(pfn) 0
+ #define GET_PFN(pfn) (pfn)
+
+-#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_GET_AND_CLEAR_FULL
+-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+-#define __HAVE_ARCH_PTE_SAME
+ #include <asm-generic/pgtable.h>
+
+ #endif /* _I386_PGTABLE_H */
+diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
+index b32346d..e0ddca9 100644
+--- a/include/asm-i386/processor.h
++++ b/include/asm-i386/processor.h
+@@ -143,6 +143,18 @@ static inline void detect_ht(struct cpui
+ #define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+ #define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
++static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
++ unsigned int *ecx, unsigned int *edx)
++{
++ /* ecx is often an input as well as an output. */
++ __asm__("cpuid"
++ : "=a" (*eax),
++ "=b" (*ebx),
++ "=c" (*ecx),
++ "=d" (*edx)
++ : "0" (*eax), "2" (*ecx));
++}
++
+ /*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+@@ -150,24 +162,18 @@ static inline void detect_ht(struct cpui
+ */
+ static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
+ {
+- __asm__("cpuid"
+- : "=a" (*eax),
+- "=b" (*ebx),
+- "=c" (*ecx),
+- "=d" (*edx)
+- : "0" (op), "c"(0));
++ *eax = op;
++ *ecx = 0;
++ __cpuid(eax, ebx, ecx, edx);
+ }
+
+ /* Some CPUID calls want 'count' to be placed in ecx */
+ static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
+- int *edx)
++ int *edx)
+ {
+- __asm__("cpuid"
+- : "=a" (*eax),
+- "=b" (*ebx),
+- "=c" (*ecx),
+- "=d" (*edx)
+- : "0" (op), "c" (count));
++ *eax = op;
++ *ecx = count;
++ __cpuid(eax, ebx, ecx, edx);
+ }
+
+ /*
+@@ -175,42 +181,30 @@ static inline void cpuid_count(int op, i
+ */
+ static inline unsigned int cpuid_eax(unsigned int op)
+ {
+- unsigned int eax;
++ unsigned int eax, ebx, ecx, edx;
+
+- __asm__("cpuid"
+- : "=a" (eax)
+- : "0" (op)
+- : "bx", "cx", "dx");
++ cpuid(op, &eax, &ebx, &ecx, &edx);
+ return eax;
+ }
+ static inline unsigned int cpuid_ebx(unsigned int op)
+ {
+- unsigned int eax, ebx;
++ unsigned int eax, ebx, ecx, edx;
+
+- __asm__("cpuid"
+- : "=a" (eax), "=b" (ebx)
+- : "0" (op)
+- : "cx", "dx" );
++ cpuid(op, &eax, &ebx, &ecx, &edx);
+ return ebx;
+ }
+ static inline unsigned int cpuid_ecx(unsigned int op)
+ {
+- unsigned int eax, ecx;
++ unsigned int eax, ebx, ecx, edx;
+
+- __asm__("cpuid"
+- : "=a" (eax), "=c" (ecx)
+- : "0" (op)
+- : "bx", "dx" );
++ cpuid(op, &eax, &ebx, &ecx, &edx);
+ return ecx;
+ }
+ static inline unsigned int cpuid_edx(unsigned int op)
+ {
+- unsigned int eax, edx;
++ unsigned int eax, ebx, ecx, edx;
+
+- __asm__("cpuid"
+- : "=a" (eax), "=d" (edx)
+- : "0" (op)
+- : "bx", "cx");
++ cpuid(op, &eax, &ebx, &ecx, &edx);
+ return edx;
+ }
+
+@@ -312,6 +306,8 @@ static inline void __mwait(unsigned long
+ : :"a" (eax), "c" (ecx));
+ }
+
++extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
++
+ /* from system description table in BIOS. Mostly for MCA use, but
+ others may find it useful. */
+ extern unsigned int machine_id;
+diff --git a/include/asm-i386/ptrace-abi.h b/include/asm-i386/ptrace-abi.h
+new file mode 100644
+index 0000000..a449018
+--- /dev/null
++++ b/include/asm-i386/ptrace-abi.h
+@@ -0,0 +1,39 @@
++#ifndef I386_PTRACE_ABI_H
++#define I386_PTRACE_ABI_H
++
++#define EBX 0
++#define ECX 1
++#define EDX 2
++#define ESI 3
++#define EDI 4
++#define EBP 5
++#define EAX 6
++#define DS 7
++#define ES 8
++#define FS 9
++#define GS 10
++#define ORIG_EAX 11
++#define EIP 12
++#define CS 13
++#define EFL 14
++#define UESP 15
++#define SS 16
++#define FRAME_SIZE 17
++
++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
++#define PTRACE_GETREGS 12
++#define PTRACE_SETREGS 13
++#define PTRACE_GETFPREGS 14
++#define PTRACE_SETFPREGS 15
++#define PTRACE_GETFPXREGS 18
++#define PTRACE_SETFPXREGS 19
++
++#define PTRACE_OLDSETOPTIONS 21
++
++#define PTRACE_GET_THREAD_AREA 25
++#define PTRACE_SET_THREAD_AREA 26
++
++#define PTRACE_SYSEMU 31
++#define PTRACE_SYSEMU_SINGLESTEP 32
++
++#endif
+diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h
+index f324c53..d505f50 100644
+--- a/include/asm-i386/ptrace.h
++++ b/include/asm-i386/ptrace.h
+@@ -1,24 +1,7 @@
+ #ifndef _I386_PTRACE_H
+ #define _I386_PTRACE_H
+
+-#define EBX 0
+-#define ECX 1
+-#define EDX 2
+-#define ESI 3
+-#define EDI 4
+-#define EBP 5
+-#define EAX 6
+-#define DS 7
+-#define ES 8
+-#define FS 9
+-#define GS 10
+-#define ORIG_EAX 11
+-#define EIP 12
+-#define CS 13
+-#define EFL 14
+-#define UESP 15
+-#define SS 16
+-#define FRAME_SIZE 17
++#include <asm/ptrace-abi.h>
+
+ /* this struct defines the way the registers are stored on the
+ stack during a system call. */
+@@ -41,25 +24,10 @@ struct pt_regs {
+ int xss;
+ };
+
+-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+-#define PTRACE_GETREGS 12
+-#define PTRACE_SETREGS 13
+-#define PTRACE_GETFPREGS 14
+-#define PTRACE_SETFPREGS 15
+-#define PTRACE_GETFPXREGS 18
+-#define PTRACE_SETFPXREGS 19
+-
+-#define PTRACE_OLDSETOPTIONS 21
+-
+-#define PTRACE_GET_THREAD_AREA 25
+-#define PTRACE_SET_THREAD_AREA 26
+-
+-#define PTRACE_SYSEMU 31
+-#define PTRACE_SYSEMU_SINGLESTEP 32
+-
+ #ifdef __KERNEL__
+
+ #include <asm/vm86.h>
++#include <asm/segment.h>
+
+ struct task_struct;
+ extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
+@@ -73,18 +41,17 @@ extern void send_sigtrap(struct task_str
+ */
+ static inline int user_mode(struct pt_regs *regs)
+ {
+- return (regs->xcs & 3) != 0;
++ return (regs->xcs & SEGMENT_RPL_MASK) == USER_RPL;
+ }
+ static inline int user_mode_vm(struct pt_regs *regs)
+ {
+- return ((regs->xcs & 3) | (regs->eflags & VM_MASK)) != 0;
++ return ((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= USER_RPL;
+ }
++
+ #define instruction_pointer(regs) ((regs)->eip)
+-#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
++#define regs_return_value(regs) ((regs)->eax)
++
+ extern unsigned long profile_pc(struct pt_regs *regs);
+-#else
+-#define profile_pc(regs) instruction_pointer(regs)
+-#endif
+ #endif /* __KERNEL__ */
+
+ #endif
+diff --git a/include/asm-i386/rwlock.h b/include/asm-i386/rwlock.h
+index 87c069c..c3e5db3 100644
+--- a/include/asm-i386/rwlock.h
++++ b/include/asm-i386/rwlock.h
+@@ -20,52 +20,6 @@
+ #define RW_LOCK_BIAS 0x01000000
+ #define RW_LOCK_BIAS_STR "0x01000000"
+
+-#define __build_read_lock_ptr(rw, helper) \
+- asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t" \
+- "jns 1f\n" \
+- "call " helper "\n\t" \
+- "1:\n" \
+- ::"a" (rw) : "memory")
+-
+-#define __build_read_lock_const(rw, helper) \
+- asm volatile(LOCK_PREFIX " subl $1,%0\n\t" \
+- "jns 1f\n" \
+- "pushl %%eax\n\t" \
+- "leal %0,%%eax\n\t" \
+- "call " helper "\n\t" \
+- "popl %%eax\n\t" \
+- "1:\n" \
+- :"+m" (*(volatile int *)rw) : : "memory")
+-
+-#define __build_read_lock(rw, helper) do { \
+- if (__builtin_constant_p(rw)) \
+- __build_read_lock_const(rw, helper); \
+- else \
+- __build_read_lock_ptr(rw, helper); \
+- } while (0)
+-
+-#define __build_write_lock_ptr(rw, helper) \
+- asm volatile(LOCK_PREFIX " subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+- "jz 1f\n" \
+- "call " helper "\n\t" \
+- "1:\n" \
+- ::"a" (rw) : "memory")
+-
+-#define __build_write_lock_const(rw, helper) \
+- asm volatile(LOCK_PREFIX " subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+- "jz 1f\n" \
+- "pushl %%eax\n\t" \
+- "leal %0,%%eax\n\t" \
+- "call " helper "\n\t" \
+- "popl %%eax\n\t" \
+- "1:\n" \
+- :"+m" (*(volatile int *)rw) : : "memory")
+-
+-#define __build_write_lock(rw, helper) do { \
+- if (__builtin_constant_p(rw)) \
+- __build_write_lock_const(rw, helper); \
+- else \
+- __build_write_lock_ptr(rw, helper); \
+- } while (0)
++/* Code is in asm-i386/spinlock.h */
+
+ #endif
+diff --git a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h
+index 43113f5..bc598d6 100644
+--- a/include/asm-i386/rwsem.h
++++ b/include/asm-i386/rwsem.h
+@@ -99,17 +99,9 @@ static inline void __down_read(struct rw
+ __asm__ __volatile__(
+ "# beginning down_read\n\t"
+ LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */
+- " js 2f\n\t" /* jump if we weren't granted the lock */
++ " jns 1f\n"
++ " call call_rwsem_down_read_failed\n"
+ "1:\n\t"
+- LOCK_SECTION_START("")
+- "2:\n\t"
+- " pushl %%ecx\n\t"
+- " pushl %%edx\n\t"
+- " call rwsem_down_read_failed\n\t"
+- " popl %%edx\n\t"
+- " popl %%ecx\n\t"
+- " jmp 1b\n"
+- LOCK_SECTION_END
+ "# ending down_read\n\t"
+ : "+m" (sem->count)
+ : "a" (sem)
+@@ -151,15 +143,9 @@ static inline void __down_write_nested(s
+ "# beginning down_write\n\t"
+ LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */
+ " testl %%edx,%%edx\n\t" /* was the count 0 before? */
+- " jnz 2f\n\t" /* jump if we weren't granted the lock */
+- "1:\n\t"
+- LOCK_SECTION_START("")
+- "2:\n\t"
+- " pushl %%ecx\n\t"
+- " call rwsem_down_write_failed\n\t"
+- " popl %%ecx\n\t"
+- " jmp 1b\n"
+- LOCK_SECTION_END
++ " jz 1f\n"
++ " call call_rwsem_down_write_failed\n"
++ "1:\n"
+ "# ending down_write"
+ : "+m" (sem->count), "=d" (tmp)
+ : "a" (sem), "1" (tmp)
+@@ -193,17 +179,9 @@ static inline void __up_read(struct rw_s
+ __asm__ __volatile__(
+ "# beginning __up_read\n\t"
+ LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old value */
+- " js 2f\n\t" /* jump if the lock is being waited upon */
+- "1:\n\t"
+- LOCK_SECTION_START("")
+- "2:\n\t"
+- " decw %%dx\n\t" /* do nothing if still outstanding active readers */
+- " jnz 1b\n\t"
+- " pushl %%ecx\n\t"
+- " call rwsem_wake\n\t"
+- " popl %%ecx\n\t"
+- " jmp 1b\n"
+- LOCK_SECTION_END
++ " jns 1f\n\t"
++ " call call_rwsem_wake\n"
++ "1:\n"
+ "# ending __up_read\n"
+ : "+m" (sem->count), "=d" (tmp)
+ : "a" (sem), "1" (tmp)
+@@ -219,17 +197,9 @@ static inline void __up_write(struct rw_
+ "# beginning __up_write\n\t"
+ " movl %2,%%edx\n\t"
+ LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
+- " jnz 2f\n\t" /* jump if the lock is being waited upon */
++ " jz 1f\n"
++ " call call_rwsem_wake\n"
+ "1:\n\t"
+- LOCK_SECTION_START("")
+- "2:\n\t"
+- " decw %%dx\n\t" /* did the active count reduce to 0? */
+- " jnz 1b\n\t" /* jump back if not */
+- " pushl %%ecx\n\t"
+- " call rwsem_wake\n\t"
+- " popl %%ecx\n\t"
+- " jmp 1b\n"
+- LOCK_SECTION_END
+ "# ending __up_write\n"
+ : "+m" (sem->count)
+ : "a" (sem), "i" (-RWSEM_ACTIVE_WRITE_BIAS)
+@@ -244,17 +214,9 @@ static inline void __downgrade_write(str
+ __asm__ __volatile__(
+ "# beginning __downgrade_write\n\t"
+ LOCK_PREFIX " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
+- " js 2f\n\t" /* jump if the lock is being waited upon */
++ " jns 1f\n\t"
++ " call call_rwsem_downgrade_wake\n"
+ "1:\n\t"
+- LOCK_SECTION_START("")
+- "2:\n\t"
+- " pushl %%ecx\n\t"
+- " pushl %%edx\n\t"
+- " call rwsem_downgrade_wake\n\t"
+- " popl %%edx\n\t"
+- " popl %%ecx\n\t"
+- " jmp 1b\n"
+- LOCK_SECTION_END
+ "# ending __downgrade_write\n"
+ : "+m" (sem->count)
+ : "a" (sem), "i" (-RWSEM_WAITING_BIAS)
+diff --git a/include/asm-i386/segment.h b/include/asm-i386/segment.h
+index faf9953..b7ab596 100644
+--- a/include/asm-i386/segment.h
++++ b/include/asm-i386/segment.h
+@@ -83,6 +83,11 @@
+
+ #define GDT_SIZE (GDT_ENTRIES * 8)
+
++/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */
++#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8)
++/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */
++#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8)
++
+ /* Simple and small GDT entries for booting only */
+
+ #define GDT_ENTRY_BOOT_CS 2
+@@ -112,4 +117,16 @@
+ */
+ #define IDT_ENTRIES 256
+
++/* Bottom two bits of selector give the ring privilege level */
++#define SEGMENT_RPL_MASK 0x3
++/* Bit 2 is table indicator (LDT/GDT) */
++#define SEGMENT_TI_MASK 0x4
++
++/* User mode is privilege level 3 */
++#define USER_RPL 0x3
++/* LDT segment has TI set, GDT has it cleared */
++#define SEGMENT_LDT 0x4
++#define SEGMENT_GDT 0x0
++
++#define get_kernel_rpl() 0
+ #endif
+diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h
+index d51e800..4e34a46 100644
+--- a/include/asm-i386/semaphore.h
++++ b/include/asm-i386/semaphore.h
+@@ -100,13 +100,10 @@ static inline void down(struct semaphore
+ __asm__ __volatile__(
+ "# atomic down operation\n\t"
+ LOCK_PREFIX "decl %0\n\t" /* --sem->count */
+- "js 2f\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tlea %0,%%eax\n\t"
+- "call __down_failed\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
++ "jns 2f\n"
++ "\tlea %0,%%eax\n\t"
++ "call __down_failed\n"
++ "2:"
+ :"+m" (sem->count)
+ :
+ :"memory","ax");
+@@ -123,16 +120,13 @@ static inline int down_interruptible(str
+ might_sleep();
+ __asm__ __volatile__(
+ "# atomic interruptible down operation\n\t"
++ "xorl %0,%0\n\t"
+ LOCK_PREFIX "decl %1\n\t" /* --sem->count */
+- "js 2f\n\t"
+- "xorl %0,%0\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tlea %1,%%eax\n\t"
+- "call __down_failed_interruptible\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
+- :"=a" (result), "+m" (sem->count)
++ "jns 2f\n\t"
++ "lea %1,%%eax\n\t"
++ "call __down_failed_interruptible\n"
++ "2:"
++ :"=&a" (result), "+m" (sem->count)
+ :
+ :"memory");
+ return result;
+@@ -148,16 +142,13 @@ static inline int down_trylock(struct se
+
+ __asm__ __volatile__(
+ "# atomic interruptible down operation\n\t"
++ "xorl %0,%0\n\t"
+ LOCK_PREFIX "decl %1\n\t" /* --sem->count */
+- "js 2f\n\t"
+- "xorl %0,%0\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tlea %1,%%eax\n\t"
++ "jns 2f\n\t"
++ "lea %1,%%eax\n\t"
+ "call __down_failed_trylock\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
+- :"=a" (result), "+m" (sem->count)
++ "2:\n"
++ :"=&a" (result), "+m" (sem->count)
+ :
+ :"memory");
+ return result;
+@@ -166,22 +157,16 @@ static inline int down_trylock(struct se
+ /*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+- * The default case (no contention) will result in NO
+- * jumps for both down() and up().
+ */
+ static inline void up(struct semaphore * sem)
+ {
+ __asm__ __volatile__(
+ "# atomic up operation\n\t"
+ LOCK_PREFIX "incl %0\n\t" /* ++sem->count */
+- "jle 2f\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tlea %0,%%eax\n\t"
+- "call __up_wakeup\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
+- ".subsection 0\n"
++ "jg 1f\n\t"
++ "lea %0,%%eax\n\t"
++ "call __up_wakeup\n"
++ "1:"
+ :"+m" (sem->count)
+ :
+ :"memory","ax");
+diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
+index 142d10e..bd59c15 100644
+--- a/include/asm-i386/smp.h
++++ b/include/asm-i386/smp.h
+@@ -80,24 +80,35 @@ static inline int hard_smp_processor_id(
+ return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+ }
+ #endif
+-
+-static __inline int logical_smp_processor_id(void)
+-{
+- /* we don't want to mark this access volatile - bad code generation */
+- return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
+-}
+-
+ #endif
+
++extern int safe_smp_processor_id(void);
+ extern int __cpu_disable(void);
+ extern void __cpu_die(unsigned int cpu);
++extern unsigned int num_processors;
++
+ #endif /* !__ASSEMBLY__ */
+
+ #else /* CONFIG_SMP */
+
++#define safe_smp_processor_id() 0
+ #define cpu_physical_id(cpu) boot_cpu_physical_apicid
+
+ #define NO_PROC_ID 0xFF /* No processor magic marker */
+
+ #endif
++
++#ifndef __ASSEMBLY__
++
++extern u8 apicid_2_node[];
++
++#ifdef CONFIG_X86_LOCAL_APIC
++static __inline int logical_smp_processor_id(void)
++{
++ /* we don't want to mark this access volatile - bad code generation */
++ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
++}
++#endif
++#endif
++
+ #endif
+diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h
+index d102036..c18b71f 100644
+--- a/include/asm-i386/spinlock.h
++++ b/include/asm-i386/spinlock.h
+@@ -4,8 +4,12 @@
+ #include <asm/atomic.h>
+ #include <asm/rwlock.h>
+ #include <asm/page.h>
++#include <asm/processor.h>
+ #include <linux/compiler.h>
+
++#define CLI_STRING "cli"
++#define STI_STRING "sti"
++
+ /*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ *
+@@ -17,67 +21,64 @@
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+-#define __raw_spin_is_locked(x) \
+- (*(volatile signed char *)(&(x)->slock) <= 0)
+-
+-#define __raw_spin_lock_string \
+- "\n1:\t" \
+- LOCK_PREFIX " ; decb %0\n\t" \
+- "jns 3f\n" \
+- "2:\t" \
+- "rep;nop\n\t" \
+- "cmpb $0,%0\n\t" \
+- "jle 2b\n\t" \
+- "jmp 1b\n" \
+- "3:\n\t"
+-
+-/*
+- * NOTE: there's an irqs-on section here, which normally would have to be
+- * irq-traced, but on CONFIG_TRACE_IRQFLAGS we never use
+- * __raw_spin_lock_string_flags().
+- */
+-#define __raw_spin_lock_string_flags \
+- "\n1:\t" \
+- LOCK_PREFIX " ; decb %0\n\t" \
+- "jns 5f\n" \
+- "2:\t" \
+- "testl $0x200, %1\n\t" \
+- "jz 4f\n\t" \
+- "sti\n" \
+- "3:\t" \
+- "rep;nop\n\t" \
+- "cmpb $0, %0\n\t" \
+- "jle 3b\n\t" \
+- "cli\n\t" \
+- "jmp 1b\n" \
+- "4:\t" \
+- "rep;nop\n\t" \
+- "cmpb $0, %0\n\t" \
+- "jg 1b\n\t" \
+- "jmp 4b\n" \
+- "5:\n\t"
++static inline int __raw_spin_is_locked(raw_spinlock_t *x)
++{
++ return *(volatile signed char *)(&(x)->slock) <= 0;
++}
+
+ static inline void __raw_spin_lock(raw_spinlock_t *lock)
+ {
+- asm(__raw_spin_lock_string : "+m" (lock->slock) : : "memory");
++ asm volatile("\n1:\t"
++ LOCK_PREFIX " ; decb %0\n\t"
++ "jns 3f\n"
++ "2:\t"
++ "rep;nop\n\t"
++ "cmpb $0,%0\n\t"
++ "jle 2b\n\t"
++ "jmp 1b\n"
++ "3:\n\t"
++ : "+m" (lock->slock) : : "memory");
+ }
+
+ /*
+ * It is easier for the lock validator if interrupts are not re-enabled
+ * in the middle of a lock-acquire. This is a performance feature anyway
+ * so we turn it off:
++ *
++ * NOTE: there's an irqs-on section here, which normally would have to be
++ * irq-traced, but on CONFIG_TRACE_IRQFLAGS we never use this variant.
+ */
+ #ifndef CONFIG_PROVE_LOCKING
+ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
+ {
+- asm(__raw_spin_lock_string_flags : "+m" (lock->slock) : "r" (flags) : "memory");
++ asm volatile(
++ "\n1:\t"
++ LOCK_PREFIX " ; decb %0\n\t"
++ "jns 5f\n"
++ "2:\t"
++ "testl $0x200, %1\n\t"
++ "jz 4f\n\t"
++ STI_STRING "\n"
++ "3:\t"
++ "rep;nop\n\t"
++ "cmpb $0, %0\n\t"
++ "jle 3b\n\t"
++ CLI_STRING "\n\t"
++ "jmp 1b\n"
++ "4:\t"
++ "rep;nop\n\t"
++ "cmpb $0, %0\n\t"
++ "jg 1b\n\t"
++ "jmp 4b\n"
++ "5:\n\t"
++ : "+m" (lock->slock) : "r" (flags) : "memory");
+ }
+ #endif
+
+ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+ {
+ char oldval;
+- __asm__ __volatile__(
++ asm volatile(
+ "xchgb %b0,%1"
+ :"=q" (oldval), "+m" (lock->slock)
+ :"0" (0) : "memory");
+@@ -93,38 +94,29 @@ static inline int __raw_spin_trylock(raw
+
+ #if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE)
+
+-#define __raw_spin_unlock_string \
+- "movb $1,%0" \
+- :"+m" (lock->slock) : : "memory"
+-
+-
+ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+ {
+- __asm__ __volatile__(
+- __raw_spin_unlock_string
+- );
++ asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory");
+ }
+
+ #else
+
+-#define __raw_spin_unlock_string \
+- "xchgb %b0, %1" \
+- :"=q" (oldval), "+m" (lock->slock) \
+- :"0" (oldval) : "memory"
+-
+ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+ {
+ char oldval = 1;
+
+- __asm__ __volatile__(
+- __raw_spin_unlock_string
+- );
++ asm volatile("xchgb %b0, %1"
++ : "=q" (oldval), "+m" (lock->slock)
++ : "0" (oldval) : "memory");
+ }
+
+ #endif
+
+-#define __raw_spin_unlock_wait(lock) \
+- do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
++static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
++{
++ while (__raw_spin_is_locked(lock))
++ cpu_relax();
++}
+
+ /*
+ * Read-write spinlocks, allowing multiple readers
+@@ -151,22 +143,36 @@ static inline void __raw_spin_unlock(raw
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+-#define __raw_read_can_lock(x) ((int)(x)->lock > 0)
++static inline int __raw_read_can_lock(raw_rwlock_t *x)
++{
++ return (int)(x)->lock > 0;
++}
+
+ /**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+-#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
++static inline int __raw_write_can_lock(raw_rwlock_t *x)
++{
++ return (x)->lock == RW_LOCK_BIAS;
++}
+
+ static inline void __raw_read_lock(raw_rwlock_t *rw)
+ {
+- __build_read_lock(rw, "__read_lock_failed");
++ asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t"
++ "jns 1f\n"
++ "call __read_lock_failed\n\t"
++ "1:\n"
++ ::"a" (rw) : "memory");
+ }
+
+ static inline void __raw_write_lock(raw_rwlock_t *rw)
+ {
+- __build_write_lock(rw, "__write_lock_failed");
++ asm volatile(LOCK_PREFIX " subl $" RW_LOCK_BIAS_STR ",(%0)\n\t"
++ "jz 1f\n"
++ "call __write_lock_failed\n\t"
++ "1:\n"
++ ::"a" (rw) : "memory");
+ }
+
+ static inline int __raw_read_trylock(raw_rwlock_t *lock)
+@@ -199,4 +205,8 @@ static inline void __raw_write_unlock(ra
+ : "+m" (rw->lock) : : "memory");
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-i386/stacktrace.h b/include/asm-i386/stacktrace.h
+new file mode 100644
+index 0000000..7d1f6a5
+--- /dev/null
++++ b/include/asm-i386/stacktrace.h
+@@ -0,0 +1 @@
++#include <asm-x86_64/stacktrace.h>
+diff --git a/include/asm-i386/sync_bitops.h b/include/asm-i386/sync_bitops.h
+new file mode 100644
+index 0000000..c94d51c
+--- /dev/null
++++ b/include/asm-i386/sync_bitops.h
+@@ -0,0 +1,156 @@
++#ifndef _I386_SYNC_BITOPS_H
++#define _I386_SYNC_BITOPS_H
++
++/*
++ * Copyright 1992, Linus Torvalds.
++ */
++
++/*
++ * These have to be done with inline assembly: that way the bit-setting
++ * is guaranteed to be atomic. All bit operations return 0 if the bit
++ * was cleared before the operation and != 0 if it was not.
++ *
++ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
++ */
++
++#define ADDR (*(volatile long *) addr)
++
++/**
++ * sync_set_bit - Atomically set a bit in memory
++ * @nr: the bit to set
++ * @addr: the address to start counting from
++ *
++ * This function is atomic and may not be reordered. See __set_bit()
++ * if you do not require the atomic guarantees.
++ *
++ * Note: there are no guarantees that this function will not be reordered
++ * on non x86 architectures, so if you are writting portable code,
++ * make sure not to rely on its reordering guarantees.
++ *
++ * Note that @nr may be almost arbitrarily large; this function is not
++ * restricted to acting on a single-word quantity.
++ */
++static inline void sync_set_bit(int nr, volatile unsigned long * addr)
++{
++ __asm__ __volatile__("lock; btsl %1,%0"
++ :"+m" (ADDR)
++ :"Ir" (nr)
++ : "memory");
++}
++
++/**
++ * sync_clear_bit - Clears a bit in memory
++ * @nr: Bit to clear
++ * @addr: Address to start counting from
++ *
++ * sync_clear_bit() is atomic and may not be reordered. However, it does
++ * not contain a memory barrier, so if it is used for locking purposes,
++ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
++ * in order to ensure changes are visible on other processors.
++ */
++static inline void sync_clear_bit(int nr, volatile unsigned long * addr)
++{
++ __asm__ __volatile__("lock; btrl %1,%0"
++ :"+m" (ADDR)
++ :"Ir" (nr)
++ : "memory");
++}
++
++/**
++ * sync_change_bit - Toggle a bit in memory
++ * @nr: Bit to change
++ * @addr: Address to start counting from
++ *
++ * change_bit() is atomic and may not be reordered. It may be
++ * reordered on other architectures than x86.
++ * Note that @nr may be almost arbitrarily large; this function is not
++ * restricted to acting on a single-word quantity.
++ */
++static inline void sync_change_bit(int nr, volatile unsigned long * addr)
++{
++ __asm__ __volatile__("lock; btcl %1,%0"
++ :"+m" (ADDR)
++ :"Ir" (nr)
++ : "memory");
++}
++
++/**
++ * sync_test_and_set_bit - Set a bit and return its old value
++ * @nr: Bit to set
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It may be reordered on other architectures than x86.
++ * It also implies a memory barrier.
++ */
++static inline int sync_test_and_set_bit(int nr, volatile unsigned long * addr)
++{
++ int oldbit;
++
++ __asm__ __volatile__("lock; btsl %2,%1\n\tsbbl %0,%0"
++ :"=r" (oldbit),"+m" (ADDR)
++ :"Ir" (nr) : "memory");
++ return oldbit;
++}
++
++/**
++ * sync_test_and_clear_bit - Clear a bit and return its old value
++ * @nr: Bit to clear
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It can be reorderdered on other architectures other than x86.
++ * It also implies a memory barrier.
++ */
++static inline int sync_test_and_clear_bit(int nr, volatile unsigned long * addr)
++{
++ int oldbit;
++
++ __asm__ __volatile__("lock; btrl %2,%1\n\tsbbl %0,%0"
++ :"=r" (oldbit),"+m" (ADDR)
++ :"Ir" (nr) : "memory");
++ return oldbit;
++}
++
++/**
++ * sync_test_and_change_bit - Change a bit and return its old value
++ * @nr: Bit to change
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It also implies a memory barrier.
++ */
++static inline int sync_test_and_change_bit(int nr, volatile unsigned long* addr)
++{
++ int oldbit;
++
++ __asm__ __volatile__("lock; btcl %2,%1\n\tsbbl %0,%0"
++ :"=r" (oldbit),"+m" (ADDR)
++ :"Ir" (nr) : "memory");
++ return oldbit;
++}
++
++static __always_inline int sync_const_test_bit(int nr, const volatile unsigned long *addr)
++{
++ return ((1UL << (nr & 31)) &
++ (((const volatile unsigned int *)addr)[nr >> 5])) != 0;
++}
++
++static inline int sync_var_test_bit(int nr, const volatile unsigned long * addr)
++{
++ int oldbit;
++
++ __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
++ :"=r" (oldbit)
++ :"m" (ADDR),"Ir" (nr));
++ return oldbit;
++}
++
++#define sync_test_bit(nr,addr) \
++ (__builtin_constant_p(nr) ? \
++ sync_constant_test_bit((nr),(addr)) : \
++ sync_var_test_bit((nr),(addr)))
++
++#undef ADDR
++
++#endif /* _I386_SYNC_BITOPS_H */
+diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
+index 098bcee..a6dabbc 100644
+--- a/include/asm-i386/system.h
++++ b/include/asm-i386/system.h
+@@ -267,6 +267,9 @@ static inline unsigned long __xchg(unsig
+ #define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
++#define sync_cmpxchg(ptr,o,n)\
++ ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
++ (unsigned long)(n),sizeof(*(ptr))))
+ #endif
+
+ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+@@ -296,6 +299,39 @@ static inline unsigned long __cmpxchg(vo
+ return old;
+ }
+
++/*
++ * Always use locked operations when touching memory shared with a
++ * hypervisor, since the system may be SMP even if the guest kernel
++ * isn't.
++ */
++static inline unsigned long __sync_cmpxchg(volatile void *ptr,
++ unsigned long old,
++ unsigned long new, int size)
++{
++ unsigned long prev;
++ switch (size) {
++ case 1:
++ __asm__ __volatile__("lock; cmpxchgb %b1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 2:
++ __asm__ __volatile__("lock; cmpxchgw %w1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 4:
++ __asm__ __volatile__("lock; cmpxchgl %1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ }
++ return old;
++}
++
+ #ifndef CONFIG_X86_CMPXCHG
+ /*
+ * Building a kernel capable running on 80386. It may be necessary to
+diff --git a/include/asm-i386/therm_throt.h b/include/asm-i386/therm_throt.h
+new file mode 100644
+index 0000000..399bf60
+--- /dev/null
++++ b/include/asm-i386/therm_throt.h
+@@ -0,0 +1,9 @@
++#ifndef __ASM_I386_THERM_THROT_H__
++#define __ASM_I386_THERM_THROT_H__ 1
++
++#include <asm/atomic.h>
++
++extern atomic_t therm_throt_en;
++int therm_throt_process(int curr);
++
++#endif /* __ASM_I386_THERM_THROT_H__ */
+diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
+index d57ca5c..360648b 100644
+--- a/include/asm-i386/tlbflush.h
++++ b/include/asm-i386/tlbflush.h
+@@ -36,8 +36,6 @@
+ : "memory"); \
+ } while (0)
+
+-extern unsigned long pgkern_mask;
+-
+ # define __flush_tlb_all() \
+ do { \
+ if (cpu_has_pge) \
+@@ -49,7 +47,7 @@ extern unsigned long pgkern_mask;
+ #define cpu_has_invlpg (boot_cpu_data.x86 > 3)
+
+ #define __flush_tlb_single(addr) \
+- __asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
++ __asm__ __volatile__("invlpg (%0)" ::"r" (addr) : "memory")
+
+ #ifdef CONFIG_X86_INVLPG
+ # define __flush_tlb_one(addr) __flush_tlb_single(addr)
+diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
+index 6adbd9b..978d095 100644
+--- a/include/asm-i386/topology.h
++++ b/include/asm-i386/topology.h
+@@ -74,6 +74,7 @@ static inline int node_to_first_cpu(int
+ #define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 32, \
+diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
+index 97b828c..c139331 100644
+--- a/include/asm-i386/tsc.h
++++ b/include/asm-i386/tsc.h
+@@ -6,7 +6,6 @@
+ #ifndef _ASM_i386_TSC_H
+ #define _ASM_i386_TSC_H
+
+-#include <linux/config.h>
+ #include <asm/processor.h>
+
+ /*
+diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
+index 54d905e..eef5133 100644
+--- a/include/asm-i386/uaccess.h
++++ b/include/asm-i386/uaccess.h
+@@ -404,20 +404,6 @@ unsigned long __must_check __copy_from_u
+ * anything, so this is accurate.
+ */
+
+-/**
+- * __copy_to_user: - Copy a block of data into user space, with less checking.
+- * @to: Destination address, in user space.
+- * @from: Source address, in kernel space.
+- * @n: Number of bytes to copy.
+- *
+- * Context: User context only. This function may sleep.
+- *
+- * Copy data from kernel space to user space. Caller must check
+- * the specified block with access_ok() before calling this function.
+- *
+- * Returns number of bytes that could not be copied.
+- * On success, this will be zero.
+- */
+ static __always_inline unsigned long __must_check
+ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
+ {
+@@ -439,35 +425,27 @@ __copy_to_user_inatomic(void __user *to,
+ return __copy_to_user_ll(to, from, n);
+ }
+
+-static __always_inline unsigned long __must_check
+-__copy_to_user(void __user *to, const void *from, unsigned long n)
+-{
+- might_sleep();
+- return __copy_to_user_inatomic(to, from, n);
+-}
+-
+ /**
+- * __copy_from_user: - Copy a block of data from user space, with less checking.
+- * @to: Destination address, in kernel space.
+- * @from: Source address, in user space.
++ * __copy_to_user: - Copy a block of data into user space, with less checking.
++ * @to: Destination address, in user space.
++ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+- * Copy data from user space to kernel space. Caller must check
++ * Copy data from kernel space to user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+- *
+- * If some data could not be copied, this function will pad the copied
+- * data to the requested size using zero bytes.
+- *
+- * An alternate version - __copy_from_user_inatomic() - may be called from
+- * atomic context and will fail rather than sleep. In this case the
+- * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h
+- * for explanation of why this is needed.
+ */
++static __always_inline unsigned long __must_check
++__copy_to_user(void __user *to, const void *from, unsigned long n)
++{
++ might_sleep();
++ return __copy_to_user_inatomic(to, from, n);
++}
++
+ static __always_inline unsigned long
+ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
+ {
+@@ -493,6 +471,29 @@ __copy_from_user_inatomic(void *to, cons
+ }
+ return __copy_from_user_ll_nozero(to, from, n);
+ }
++
++/**
++ * __copy_from_user: - Copy a block of data from user space, with less checking.
++ * @to: Destination address, in kernel space.
++ * @from: Source address, in user space.
++ * @n: Number of bytes to copy.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * Copy data from user space to kernel space. Caller must check
++ * the specified block with access_ok() before calling this function.
++ *
++ * Returns number of bytes that could not be copied.
++ * On success, this will be zero.
++ *
++ * If some data could not be copied, this function will pad the copied
++ * data to the requested size using zero bytes.
++ *
++ * An alternate version - __copy_from_user_inatomic() - may be called from
++ * atomic context and will fail rather than sleep. In this case the
++ * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h
++ * for explanation of why this is needed.
++ */
+ static __always_inline unsigned long
+ __copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
+diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
+index fc1c8dd..beeeaf6 100644
+--- a/include/asm-i386/unistd.h
++++ b/include/asm-i386/unistd.h
+@@ -323,18 +323,21 @@
+ #define __NR_tee 315
+ #define __NR_vmsplice 316
+ #define __NR_move_pages 317
++#define __NR_getcpu 318
++#define __NR_epoll_pwait 319
+
+ #ifdef __KERNEL__
+
+-#define NR_syscalls 318
++#define NR_syscalls 320
++#include <linux/err.h>
+
+ /*
+- * user-visible error numbers are in the range -1 - -128: see
++ * user-visible error numbers are in the range -1 - -MAX_ERRNO: see
+ * <asm-i386/errno.h>
+ */
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ errno = -(res); \
+ res = -1; \
+ } \
+@@ -449,45 +452,6 @@ __syscall_return(type,__res); \
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+ #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/linkage.h>
+-#include <asm/ptrace.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount);
+-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(struct pt_regs regs);
+-asmlinkage int sys_clone(struct pt_regs regs);
+-asmlinkage int sys_fork(struct pt_regs regs);
+-asmlinkage int sys_vfork(struct pt_regs regs);
+-asmlinkage int sys_pipe(unsigned long __user *fildes);
+-asmlinkage long sys_iopl(unsigned long unused);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h
+index 4c1a0b9..5031d69 100644
+--- a/include/asm-i386/unwind.h
++++ b/include/asm-i386/unwind.h
+@@ -18,6 +18,7 @@ struct unwind_frame_info
+ {
+ struct pt_regs regs;
+ struct task_struct *task;
++ unsigned call_frame:1;
+ };
+
+ #define UNW_PC(frame) (frame)->regs.eip
+@@ -28,6 +29,8 @@ struct unwind_frame_info
+ #define FRAME_LINK_OFFSET 0
+ #define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.esp0)
+ #define STACK_TOP(tsk) ((tsk)->thread.esp0)
++#else
++#define UNW_FP(frame) ((void)(frame), 0)
+ #endif
+ #define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
+
+@@ -42,6 +45,10 @@ struct unwind_frame_info
+ PTREGS_INFO(edi), \
+ PTREGS_INFO(eip)
+
++#define UNW_DEFAULT_RA(raItem, dataAlign) \
++ ((raItem).where == Memory && \
++ !((raItem).value * (dataAlign) + 4))
++
+ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
+ /*const*/ struct pt_regs *regs)
+ {
+@@ -88,6 +95,7 @@ static inline int arch_unw_user_mode(con
+
+ #define UNW_PC(frame) ((void)(frame), 0)
+ #define UNW_SP(frame) ((void)(frame), 0)
++#define UNW_FP(frame) ((void)(frame), 0)
+
+ static inline int arch_unw_user_mode(const void *info)
+ {
+diff --git a/include/asm-i386/vic.h b/include/asm-i386/vic.h
+index 4abfcfb..53100f3 100644
+--- a/include/asm-i386/vic.h
++++ b/include/asm-i386/vic.h
+@@ -58,4 +58,4 @@ static const int VIC_CPI_Registers[] =
+
+ #define VIC_BOOT_INTERRUPT_MASK 0xfe
+
+-extern void smp_vic_timer_interrupt(struct pt_regs *regs);
++extern void smp_vic_timer_interrupt(void);
+diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h
+index aaf432d..5b27838 100644
+--- a/include/asm-i386/voyager.h
++++ b/include/asm-i386/voyager.h
+@@ -118,33 +118,33 @@ typedef struct voyager_module {
+ } voyager_module_t;
+
+ typedef struct voyager_eeprom_hdr {
+- __u8 module_id[4] __attribute__((packed));
+- __u8 version_id __attribute__((packed));
+- __u8 config_id __attribute__((packed));
+- __u16 boundry_id __attribute__((packed)); /* boundary scan id */
+- __u16 ee_size __attribute__((packed)); /* size of EEPROM */
+- __u8 assembly[11] __attribute__((packed)); /* assembly # */
+- __u8 assembly_rev __attribute__((packed)); /* assembly rev */
+- __u8 tracer[4] __attribute__((packed)); /* tracer number */
+- __u16 assembly_cksum __attribute__((packed)); /* asm checksum */
+- __u16 power_consump __attribute__((packed)); /* pwr requirements */
+- __u16 num_asics __attribute__((packed)); /* number of asics */
+- __u16 bist_time __attribute__((packed)); /* min. bist time */
+- __u16 err_log_offset __attribute__((packed)); /* error log offset */
+- __u16 scan_path_offset __attribute__((packed));/* scan path offset */
+- __u16 cct_offset __attribute__((packed));
+- __u16 log_length __attribute__((packed)); /* length of err log */
+- __u16 xsum_end __attribute__((packed)); /* offset to end of
++ __u8 module_id[4];
++ __u8 version_id;
++ __u8 config_id;
++ __u16 boundry_id; /* boundary scan id */
++ __u16 ee_size; /* size of EEPROM */
++ __u8 assembly[11]; /* assembly # */
++ __u8 assembly_rev; /* assembly rev */
++ __u8 tracer[4]; /* tracer number */
++ __u16 assembly_cksum; /* asm checksum */
++ __u16 power_consump; /* pwr requirements */
++ __u16 num_asics; /* number of asics */
++ __u16 bist_time; /* min. bist time */
++ __u16 err_log_offset; /* error log offset */
++ __u16 scan_path_offset;/* scan path offset */
++ __u16 cct_offset;
++ __u16 log_length; /* length of err log */
++ __u16 xsum_end; /* offset to end of
+ checksum */
+- __u8 reserved[4] __attribute__((packed));
+- __u8 sflag __attribute__((packed)); /* starting sentinal */
+- __u8 part_number[13] __attribute__((packed)); /* prom part number */
+- __u8 version[10] __attribute__((packed)); /* version number */
+- __u8 signature[8] __attribute__((packed));
+- __u16 eeprom_chksum __attribute__((packed));
+- __u32 data_stamp_offset __attribute__((packed));
+- __u8 eflag __attribute__((packed)); /* ending sentinal */
+-} voyager_eprom_hdr_t;
++ __u8 reserved[4];
++ __u8 sflag; /* starting sentinal */
++ __u8 part_number[13]; /* prom part number */
++ __u8 version[10]; /* version number */
++ __u8 signature[8];
++ __u16 eeprom_chksum;
++ __u32 data_stamp_offset;
++ __u8 eflag ; /* ending sentinal */
++} __attribute__((packed)) voyager_eprom_hdr_t;
+
+
+
+@@ -155,30 +155,30 @@ typedef struct voyager_eeprom_hdr {
+ * in the module EPROMs. We really only care about the IDs and
+ * offsets */
+ typedef struct voyager_sp_table {
+- __u8 asic_id __attribute__((packed));
+- __u8 bypass_flag __attribute__((packed));
+- __u16 asic_data_offset __attribute__((packed));
+- __u16 config_data_offset __attribute__((packed));
+-} voyager_sp_table_t;
++ __u8 asic_id;
++ __u8 bypass_flag;
++ __u16 asic_data_offset;
++ __u16 config_data_offset;
++} __attribute__((packed)) voyager_sp_table_t;
+
+ typedef struct voyager_jtag_table {
+- __u8 icode[4] __attribute__((packed));
+- __u8 runbist[4] __attribute__((packed));
+- __u8 intest[4] __attribute__((packed));
+- __u8 samp_preld[4] __attribute__((packed));
+- __u8 ireg_len __attribute__((packed));
+-} voyager_jtt_t;
++ __u8 icode[4];
++ __u8 runbist[4];
++ __u8 intest[4];
++ __u8 samp_preld[4];
++ __u8 ireg_len;
++} __attribute__((packed)) voyager_jtt_t;
+
+ typedef struct voyager_asic_data_table {
+- __u8 jtag_id[4] __attribute__((packed));
+- __u16 length_bsr __attribute__((packed));
+- __u16 length_bist_reg __attribute__((packed));
+- __u32 bist_clk __attribute__((packed));
+- __u16 subaddr_bits __attribute__((packed));
+- __u16 seed_bits __attribute__((packed));
+- __u16 sig_bits __attribute__((packed));
+- __u16 jtag_offset __attribute__((packed));
+-} voyager_at_t;
++ __u8 jtag_id[4];
++ __u16 length_bsr;
++ __u16 length_bist_reg;
++ __u32 bist_clk;
++ __u16 subaddr_bits;
++ __u16 seed_bits;
++ __u16 sig_bits;
++ __u16 jtag_offset;
++} __attribute__((packed)) voyager_at_t;
+
+ /* Voyager Interrupt Controller (VIC) registers */
+
+@@ -328,52 +328,52 @@ struct voyager_bios_info {
+ #define NUMBER_OF_POS_REGS 8
+
+ typedef struct {
+- __u8 MC_Slot __attribute__((packed));
+- __u8 POS_Values[NUMBER_OF_POS_REGS] __attribute__((packed));
+-} MC_SlotInformation_t;
++ __u8 MC_Slot;
++ __u8 POS_Values[NUMBER_OF_POS_REGS];
++} __attribute__((packed)) MC_SlotInformation_t;
+
+ struct QuadDescription {
+- __u8 Type __attribute__((packed)); /* for type 0 (DYADIC or MONADIC) all fields
++ __u8 Type; /* for type 0 (DYADIC or MONADIC) all fields
+ * will be zero except for slot */
+- __u8 StructureVersion __attribute__((packed));
+- __u32 CPI_BaseAddress __attribute__((packed));
+- __u32 LARC_BankSize __attribute__((packed));
+- __u32 LocalMemoryStateBits __attribute__((packed));
+- __u8 Slot __attribute__((packed)); /* Processor slots 1 - 4 */
+-};
++ __u8 StructureVersion;
++ __u32 CPI_BaseAddress;
++ __u32 LARC_BankSize;
++ __u32 LocalMemoryStateBits;
++ __u8 Slot; /* Processor slots 1 - 4 */
++} __attribute__((packed));
+
+ struct ProcBoardInfo {
+- __u8 Type __attribute__((packed));
+- __u8 StructureVersion __attribute__((packed));
+- __u8 NumberOfBoards __attribute__((packed));
+- struct QuadDescription QuadData[MAX_PROCESSOR_BOARDS] __attribute__((packed));
+-};
++ __u8 Type;
++ __u8 StructureVersion;
++ __u8 NumberOfBoards;
++ struct QuadDescription QuadData[MAX_PROCESSOR_BOARDS];
++} __attribute__((packed));
+
+ struct CacheDescription {
+- __u8 Level __attribute__((packed));
+- __u32 TotalSize __attribute__((packed));
+- __u16 LineSize __attribute__((packed));
+- __u8 Associativity __attribute__((packed));
+- __u8 CacheType __attribute__((packed));
+- __u8 WriteType __attribute__((packed));
+- __u8 Number_CPUs_SharedBy __attribute__((packed));
+- __u8 Shared_CPUs_Hardware_IDs[MAX_SHARED_CPUS] __attribute__((packed));
++ __u8 Level;
++ __u32 TotalSize;
++ __u16 LineSize;
++ __u8 Associativity;
++ __u8 CacheType;
++ __u8 WriteType;
++ __u8 Number_CPUs_SharedBy;
++ __u8 Shared_CPUs_Hardware_IDs[MAX_SHARED_CPUS];
+
+-};
++} __attribute__((packed));
+
+ struct CPU_Description {
+- __u8 CPU_HardwareId __attribute__((packed));
+- char *FRU_String __attribute__((packed));
+- __u8 NumberOfCacheLevels __attribute__((packed));
+- struct CacheDescription CacheLevelData[MAX_CACHE_LEVELS] __attribute__((packed));
+-};
++ __u8 CPU_HardwareId;
++ char *FRU_String;
++ __u8 NumberOfCacheLevels;
++ struct CacheDescription CacheLevelData[MAX_CACHE_LEVELS];
++} __attribute__((packed));
+
+ struct CPU_Info {
+- __u8 Type __attribute__((packed));
+- __u8 StructureVersion __attribute__((packed));
+- __u8 NumberOf_CPUs __attribute__((packed));
+- struct CPU_Description CPU_Data[MAX_CPUS] __attribute__((packed));
+-};
++ __u8 Type;
++ __u8 StructureVersion;
++ __u8 NumberOf_CPUs;
++ struct CPU_Description CPU_Data[MAX_CPUS];
++} __attribute__((packed));
+
+
+ /*
+@@ -505,8 +505,8 @@ extern int voyager_memory_detect(int reg
+ extern void voyager_smp_intr_init(void);
+ extern __u8 voyager_extended_cmos_read(__u16 cmos_address);
+ extern void voyager_smp_dump(void);
+-extern void voyager_timer_interrupt(struct pt_regs *regs);
+-extern void smp_local_timer_interrupt(struct pt_regs * regs);
++extern void voyager_timer_interrupt(void);
++extern void smp_local_timer_interrupt(void);
+ extern void voyager_power_off(void);
+ extern void smp_voyager_power_off(void *dummy);
+ extern void voyager_restart(void);
+diff --git a/include/asm-ia64/Kbuild b/include/asm-ia64/Kbuild
+index f1cb00f..15818a1 100644
+--- a/include/asm-ia64/Kbuild
++++ b/include/asm-ia64/Kbuild
+@@ -1,7 +1,17 @@
+ include include/asm-generic/Kbuild.asm
+
+-header-y += break.h fpu.h fpswa.h gcc_intrin.h ia64regs.h \
+- intel_intrin.h intrinsics.h perfmon_default_smpl.h \
+- ptrace_offsets.h rse.h setup.h ucontext.h
++header-y += break.h
++header-y += fpu.h
++header-y += fpswa.h
++header-y += gcc_intrin.h
++header-y += ia64regs.h
++header-y += intel_intrin.h
++header-y += intrinsics.h
++header-y += perfmon_default_smpl.h
++header-y += ptrace_offsets.h
++header-y += rse.h
++header-y += setup.h
++header-y += ucontext.h
+
+-unifdef-y += perfmon.h ustack.h
++unifdef-y += perfmon.h
++unifdef-y += ustack.h
+diff --git a/include/asm-ia64/esi.h b/include/asm-ia64/esi.h
+new file mode 100644
+index 0000000..84aac0e
+--- /dev/null
++++ b/include/asm-ia64/esi.h
+@@ -0,0 +1,30 @@
++/*
++ * ESI service calls.
++ *
++ * Copyright (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P.
++ * Alex Williamson <alex.williamson at hp.com>
++ */
++#ifndef esi_h
++#define esi_h
++
++#include <linux/efi.h>
++
++#define ESI_QUERY 0x00000001
++#define ESI_OPEN_HANDLE 0x02000000
++#define ESI_CLOSE_HANDLE 0x02000001
++
++enum esi_proc_type {
++ ESI_PROC_SERIALIZED, /* calls need to be serialized */
++ ESI_PROC_MP_SAFE, /* MP-safe, but not reentrant */
++ ESI_PROC_REENTRANT /* MP-safe and reentrant */
++};
++
++extern int ia64_esi_init (void);
++extern struct ia64_sal_retval esi_call_phys (void *, u64 *);
++extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *,
++ enum esi_proc_type,
++ u64, u64, u64, u64, u64, u64, u64, u64);
++extern int ia64_esi_call_phys(efi_guid_t, struct ia64_sal_retval *, u64, u64,
++ u64, u64, u64, u64, u64, u64);
++
++#endif /* esi_h */
+diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h
+index 6a332a9..07d77f3 100644
+--- a/include/asm-ia64/futex.h
++++ b/include/asm-ia64/futex.h
+@@ -1,6 +1,124 @@
+ #ifndef _ASM_FUTEX_H
+ #define _ASM_FUTEX_H
+
+-#include <asm-generic/futex.h>
++#include <linux/futex.h>
++#include <asm/errno.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
+
+-#endif
++#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
++do { \
++ register unsigned long r8 __asm ("r8") = 0; \
++ __asm__ __volatile__( \
++ " mf;; \n" \
++ "[1:] " insn ";; \n" \
++ " .xdata4 \"__ex_table\", 1b-., 2f-. \n" \
++ "[2:]" \
++ : "+r" (r8), "=r" (oldval) \
++ : "r" (uaddr), "r" (oparg) \
++ : "memory"); \
++ ret = r8; \
++} while (0)
++
++#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
++do { \
++ register unsigned long r8 __asm ("r8") = 0; \
++ int val, newval; \
++ do { \
++ __asm__ __volatile__( \
++ " mf;; \n" \
++ "[1:] ld4 %3=[%4];; \n" \
++ " mov %2=%3 \n" \
++ insn ";; \n" \
++ " mov ar.ccv=%2;; \n" \
++ "[2:] cmpxchg4.acq %1=[%4],%3,ar.ccv;; \n" \
++ " .xdata4 \"__ex_table\", 1b-., 3f-.\n" \
++ " .xdata4 \"__ex_table\", 2b-., 3f-.\n" \
++ "[3:]" \
++ : "+r" (r8), "=r" (val), "=&r" (oldval), \
++ "=&r" (newval) \
++ : "r" (uaddr), "r" (oparg) \
++ : "memory"); \
++ if (unlikely (r8)) \
++ break; \
++ } while (unlikely (val != oldval)); \
++ ret = r8; \
++} while (0)
++
++static inline int
++futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
++{
++ int op = (encoded_op >> 28) & 7;
++ int cmp = (encoded_op >> 24) & 15;
++ int oparg = (encoded_op << 8) >> 20;
++ int cmparg = (encoded_op << 20) >> 20;
++ int oldval = 0, ret;
++ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
++ oparg = 1 << oparg;
++
++ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
++ return -EFAULT;
++
++ inc_preempt_count();
++
++ switch (op) {
++ case FUTEX_OP_SET:
++ __futex_atomic_op1("xchg4 %1=[%2],%3", ret, oldval, uaddr,
++ oparg);
++ break;
++ case FUTEX_OP_ADD:
++ __futex_atomic_op2("add %3=%3,%5", ret, oldval, uaddr, oparg);
++ break;
++ case FUTEX_OP_OR:
++ __futex_atomic_op2("or %3=%3,%5", ret, oldval, uaddr, oparg);
++ break;
++ case FUTEX_OP_ANDN:
++ __futex_atomic_op2("and %3=%3,%5", ret, oldval, uaddr,
++ ~oparg);
++ break;
++ case FUTEX_OP_XOR:
++ __futex_atomic_op2("xor %3=%3,%5", ret, oldval, uaddr, oparg);
++ break;
++ default:
++ ret = -ENOSYS;
++ }
++
++ dec_preempt_count();
++
++ if (!ret) {
++ switch (cmp) {
++ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
++ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
++ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
++ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
++ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
++ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
++ default: ret = -ENOSYS;
++ }
++ }
++ return ret;
++}
++
++static inline int
++futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
++{
++ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
++ return -EFAULT;
++
++ {
++ register unsigned long r8 __asm ("r8");
++ __asm__ __volatile__(
++ " mf;; \n"
++ " mov ar.ccv=%3;; \n"
++ "[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
++ " .xdata4 \"__ex_table\", 1b-., 2f-. \n"
++ "[2:]"
++ : "=r" (r8)
++ : "r" (uaddr), "r" (newval),
++ "rO" ((long) (unsigned) oldval)
++ : "memory");
++ return r8;
++ }
++}
++
++#endif /* _ASM_FUTEX_H */
+diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
+index 43bfff6..855c30a 100644
+--- a/include/asm-ia64/io.h
++++ b/include/asm-ia64/io.h
+@@ -417,6 +417,8 @@ __writeq (unsigned long val, volatile vo
+ # define outl_p outl
+ #endif
+
++# ifdef __KERNEL__
++
+ extern void __iomem * ioremap(unsigned long offset, unsigned long size);
+ extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
+
+@@ -430,8 +432,6 @@ iounmap (volatile void __iomem *addr)
+ #define dmi_iounmap(x,l) iounmap(x)
+ #define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
+
+-# ifdef __KERNEL__
+-
+ /*
+ * String version of IO memory access ops:
+ */
+diff --git a/include/asm-ia64/irq_regs.h b/include/asm-ia64/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-ia64/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
+index 9389049..1b45b71 100644
+--- a/include/asm-ia64/kprobes.h
++++ b/include/asm-ia64/kprobes.h
+@@ -29,7 +29,8 @@
+ #include <linux/percpu.h>
+ #include <asm/break.h>
+
+-#define MAX_INSN_SIZE 16
++#define __ARCH_WANT_KPROBES_INSN_SLOT
++#define MAX_INSN_SIZE 1
+ #define BREAK_INST (long)(__IA64_BREAK_KPROBE << 6)
+
+ typedef union cmp_inst {
+@@ -94,7 +95,7 @@ struct kprobe_ctlblk {
+ #define IP_RELATIVE_PREDICT_OPCODE (7)
+ #define LONG_BRANCH_OPCODE (0xC)
+ #define LONG_CALL_OPCODE (0xD)
+-#define arch_remove_kprobe(p) do {} while (0)
++#define flush_insn_slot(p) do { } while (0)
+
+ typedef struct kprobe_opcode {
+ bundle_t bundle;
+@@ -108,7 +109,7 @@ struct fnptr {
+ /* Architecture specific copy of original instruction*/
+ struct arch_specific_insn {
+ /* copy of the instruction to be emulated */
+- kprobe_opcode_t insn;
++ kprobe_opcode_t *insn;
+ #define INST_FLAG_FIX_RELATIVE_IP_ADDR 1
+ #define INST_FLAG_FIX_BRANCH_REG 2
+ #define INST_FLAG_BREAK_INST 4
+@@ -125,6 +126,6 @@ static inline void jprobe_return(void)
+ }
+ extern void invalidate_stacked_regs(void);
+ extern void flush_register_stack(void);
+-extern void flush_insn_slot(struct kprobe *p);
++extern void arch_remove_kprobe(struct kprobe *p);
+
+ #endif /* _ASM_KPROBES_H */
+diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
+index 15b545a..7ffbddf 100644
+--- a/include/asm-ia64/machvec.h
++++ b/include/asm-ia64/machvec.h
+@@ -20,12 +20,13 @@ struct page;
+ struct mm_struct;
+ struct pci_bus;
+ struct task_struct;
++struct pci_dev;
+
+ typedef void ia64_mv_setup_t (char **);
+ typedef void ia64_mv_cpu_init_t (void);
+ typedef void ia64_mv_irq_init_t (void);
+ typedef void ia64_mv_send_ipi_t (int, int, int, int);
+-typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *);
++typedef void ia64_mv_timer_interrupt_t (int, void *);
+ typedef void ia64_mv_global_tlb_purge_t (struct mm_struct *, unsigned long, unsigned long, unsigned long);
+ typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *);
+ typedef unsigned int ia64_mv_local_vector_to_irq (u8);
+@@ -75,7 +76,9 @@ typedef unsigned char ia64_mv_readb_rela
+ typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
+ typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
+ typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+-typedef int ia64_mv_msi_init_t (void);
++
++typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
++typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
+
+ static inline void
+ machvec_noop (void)
+@@ -93,7 +96,7 @@ machvec_noop_task (struct task_struct *t
+ }
+
+ extern void machvec_setup (char **);
+-extern void machvec_timer_interrupt (int, void *, struct pt_regs *);
++extern void machvec_timer_interrupt (int, void *);
+ extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int);
+ extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int);
+ extern void machvec_tlb_migrate_finish (struct mm_struct *);
+@@ -154,7 +157,8 @@ extern void machvec_tlb_migrate_finish (
+ # define platform_readl_relaxed ia64_mv.readl_relaxed
+ # define platform_readq_relaxed ia64_mv.readq_relaxed
+ # define platform_migrate ia64_mv.migrate
+-# define platform_msi_init ia64_mv.msi_init
++# define platform_setup_msi_irq ia64_mv.setup_msi_irq
++# define platform_teardown_msi_irq ia64_mv.teardown_msi_irq
+ # endif
+
+ /* __attribute__((__aligned__(16))) is required to make size of the
+@@ -204,7 +208,8 @@ struct ia64_machine_vector {
+ ia64_mv_readl_relaxed_t *readl_relaxed;
+ ia64_mv_readq_relaxed_t *readq_relaxed;
+ ia64_mv_migrate_t *migrate;
+- ia64_mv_msi_init_t *msi_init;
++ ia64_mv_setup_msi_irq_t *setup_msi_irq;
++ ia64_mv_teardown_msi_irq_t *teardown_msi_irq;
+ } __attribute__((__aligned__(16))); /* align attrib? see above comment */
+
+ #define MACHVEC_INIT(name) \
+@@ -250,7 +255,8 @@ struct ia64_machine_vector {
+ platform_readl_relaxed, \
+ platform_readq_relaxed, \
+ platform_migrate, \
+- platform_msi_init, \
++ platform_setup_msi_irq, \
++ platform_teardown_msi_irq, \
+ }
+
+ extern struct ia64_machine_vector ia64_mv;
+@@ -404,8 +410,11 @@ extern int ia64_pci_legacy_write(struct
+ #ifndef platform_migrate
+ # define platform_migrate machvec_noop_task
+ #endif
+-#ifndef platform_msi_init
+-# define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
++#ifndef platform_setup_msi_irq
++# define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL)
++#endif
++#ifndef platform_teardown_msi_irq
++# define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL)
+ #endif
+
+ #endif /* _ASM_IA64_MACHVEC_H */
+diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
+index cf724dc..c54b165 100644
+--- a/include/asm-ia64/machvec_sn2.h
++++ b/include/asm-ia64/machvec_sn2.h
+@@ -67,7 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn
+ extern ia64_mv_dma_mapping_error sn_dma_mapping_error;
+ extern ia64_mv_dma_supported sn_dma_supported;
+ extern ia64_mv_migrate_t sn_migrate;
+-extern ia64_mv_msi_init_t sn_msi_init;
++extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq;
++extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq;
+
+
+ /*
+@@ -120,9 +121,11 @@ extern ia64_mv_msi_init_t sn_msi_init;
+ #define platform_dma_supported sn_dma_supported
+ #define platform_migrate sn_migrate
+ #ifdef CONFIG_PCI_MSI
+-#define platform_msi_init sn_msi_init
++#define platform_setup_msi_irq sn_setup_msi_irq
++#define platform_teardown_msi_irq sn_teardown_msi_irq
+ #else
+-#define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
++#define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL)
++#define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL)
+ #endif
+
+ #include <asm/sn/io.h>
+diff --git a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h
+index 27c9203..76203f9 100644
+--- a/include/asm-ia64/mca_asm.h
++++ b/include/asm-ia64/mca_asm.h
+@@ -197,9 +197,9 @@
+ movl temp2 = start_addr; \
+ ;; \
+ mov cr.iip = temp2; \
++ movl gp = __gp \
+ ;; \
+ DATA_PA_TO_VA(sp, temp1); \
+- DATA_PA_TO_VA(gp, temp2); \
+ srlz.i; \
+ ;; \
+ nop 1; \
+diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
+index 6a33a07..c3b1f86 100644
+--- a/include/asm-ia64/meminit.h
++++ b/include/asm-ia64/meminit.h
+@@ -55,6 +55,7 @@ extern void efi_memmap_init(unsigned lon
+ extern unsigned long vmalloc_end;
+ extern struct page *vmem_map;
+ extern int find_largest_hole (u64 start, u64 end, void *arg);
++ extern int register_active_ranges (u64 start, u64 end, void *arg);
+ extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
+ extern int vmemmap_find_next_valid_pfn(int, int);
+ #else
+diff --git a/include/asm-ia64/module.h b/include/asm-ia64/module.h
+index 85c82bd..d2da61e 100644
+--- a/include/asm-ia64/module.h
++++ b/include/asm-ia64/module.h
+@@ -28,7 +28,8 @@ struct mod_arch_specific {
+ #define Elf_Ehdr Elf64_Ehdr
+
+ #define MODULE_PROC_FAMILY "ia64"
+-#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
++#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \
++ "gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
+
+ #define ARCH_SHF_SMALL SHF_IA_64_SHORT
+
+diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h
+deleted file mode 100644
+index bb92b0d..0000000
+--- a/include/asm-ia64/msi.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * Copyright (C) 2003-2004 Intel
+- * Copyright (C) Tom Long Nguyen (tom.l.nguyen at intel.com)
+- */
+-
+-#ifndef ASM_MSI_H
+-#define ASM_MSI_H
+-
+-#define NR_VECTORS NR_IRQS
+-#define FIRST_DEVICE_VECTOR IA64_FIRST_DEVICE_VECTOR
+-#define LAST_DEVICE_VECTOR IA64_LAST_DEVICE_VECTOR
+-static inline void set_intr_gate (int nr, void *func) {}
+-#define IO_APIC_VECTOR(irq) (irq)
+-#define ack_APIC_irq ia64_eoi
+-#define MSI_TARGET_CPU_SHIFT 4
+-
+-extern struct msi_ops msi_apic_ops;
+-
+-static inline int msi_arch_init(void)
+-{
+- if (platform_msi_init)
+- return platform_msi_init();
+-
+- /* default ops for most ia64 platforms */
+- msi_register(&msi_apic_ops);
+- return 0;
+-}
+-
+-#endif /* ASM_MSI_H */
+diff --git a/include/asm-ia64/numa.h b/include/asm-ia64/numa.h
+index e5a8260..7d5e2cc 100644
+--- a/include/asm-ia64/numa.h
++++ b/include/asm-ia64/numa.h
+@@ -64,7 +64,13 @@ extern int paddr_to_nid(unsigned long pa
+
+ #define local_nodeid (cpu_to_node_map[smp_processor_id()])
+
++extern void map_cpu_to_node(int cpu, int nid);
++extern void unmap_cpu_from_node(int cpu, int nid);
++
++
+ #else /* !CONFIG_NUMA */
++#define map_cpu_to_node(cpu, nid) do{}while(0)
++#define unmap_cpu_from_node(cpu, nid) do{}while(0)
+
+ #define paddr_to_nid(addr) 0
+
+diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
+index 20a8d61..4283ddc 100644
+--- a/include/asm-ia64/pal.h
++++ b/include/asm-ia64/pal.h
+@@ -78,6 +78,7 @@
+ #define PAL_VM_TR_READ 261 /* read contents of translation register */
+ #define PAL_GET_PSTATE 262 /* get the current P-state */
+ #define PAL_SET_PSTATE 263 /* set the P-state */
++#define PAL_BRAND_INFO 274 /* Processor branding information */
+
+ #ifndef __ASSEMBLY__
+
+@@ -763,7 +764,7 @@ struct ia64_pal_retval {
+ * (generally 0) MUST be passed. Reserved parameters are not optional
+ * parameters.
+ */
+-extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64, u64);
++extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64);
+ extern struct ia64_pal_retval ia64_pal_call_stacked (u64, u64, u64, u64);
+ extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64);
+ extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64);
+@@ -773,14 +774,7 @@ extern void ia64_load_scratch_fpregs (st
+ #define PAL_CALL(iprv,a0,a1,a2,a3) do { \
+ struct ia64_fpreg fr[6]; \
+ ia64_save_scratch_fpregs(fr); \
+- iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \
+- ia64_load_scratch_fpregs(fr); \
+-} while (0)
+-
+-#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do { \
+- struct ia64_fpreg fr[6]; \
+- ia64_save_scratch_fpregs(fr); \
+- iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \
++ iprv = ia64_pal_call_static(a0, a1, a2, a3); \
+ ia64_load_scratch_fpregs(fr); \
+ } while (0)
+
+@@ -963,7 +957,8 @@ static inline s64
+ ia64_pal_cache_read (pal_cache_line_id_u_t line_id, u64 physical_addr)
+ {
+ struct ia64_pal_retval iprv;
+- PAL_CALL(iprv, PAL_CACHE_READ, line_id.pclid_data, physical_addr, 0);
++ PAL_CALL_PHYS_STK(iprv, PAL_CACHE_READ, line_id.pclid_data,
++ physical_addr, 0);
+ return iprv.status;
+ }
+
+@@ -985,7 +980,8 @@ static inline s64
+ ia64_pal_cache_write (pal_cache_line_id_u_t line_id, u64 physical_addr, u64 data)
+ {
+ struct ia64_pal_retval iprv;
+- PAL_CALL(iprv, PAL_CACHE_WRITE, line_id.pclid_data, physical_addr, data);
++ PAL_CALL_PHYS_STK(iprv, PAL_CACHE_WRITE, line_id.pclid_data,
++ physical_addr, data);
+ return iprv.status;
+ }
+
+@@ -1133,6 +1129,15 @@ ia64_pal_set_pstate (u64 pstate_index)
+ return iprv.status;
+ }
+
++/* Processor branding information*/
++static inline s64
++ia64_pal_get_brand_info (char *brand_info)
++{
++ struct ia64_pal_retval iprv;
++ PAL_CALL_STK(iprv, PAL_BRAND_INFO, 0, (u64)brand_info, 0);
++ return iprv.status;
++}
++
+ /* Cause the processor to enter LIGHT HALT state, where prefetching and execution are
+ * suspended, but cache and TLB coherency is maintained.
+ */
+diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
+index 228981c..5531827 100644
+--- a/include/asm-ia64/pgtable.h
++++ b/include/asm-ia64/pgtable.h
+@@ -275,21 +275,23 @@ ia64_phys_addr_valid (unsigned long addr
+ #define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd)))
+ #define pmd_present(pmd) (pmd_val(pmd) != 0UL)
+ #define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL)
+-#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK))
++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK))
+ #define pmd_page(pmd) virt_to_page((pmd_val(pmd) + PAGE_OFFSET))
+
+ #define pud_none(pud) (!pud_val(pud))
+ #define pud_bad(pud) (!ia64_phys_addr_valid(pud_val(pud)))
+ #define pud_present(pud) (pud_val(pud) != 0UL)
+ #define pud_clear(pudp) (pud_val(*(pudp)) = 0UL)
+-#define pud_page(pud) ((unsigned long) __va(pud_val(pud) & _PFN_MASK))
++#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & _PFN_MASK))
++#define pud_page(pud) virt_to_page((pud_val(pud) + PAGE_OFFSET))
+
+ #ifdef CONFIG_PGTABLE_4
+ #define pgd_none(pgd) (!pgd_val(pgd))
+ #define pgd_bad(pgd) (!ia64_phys_addr_valid(pgd_val(pgd)))
+ #define pgd_present(pgd) (pgd_val(pgd) != 0UL)
+ #define pgd_clear(pgdp) (pgd_val(*(pgdp)) = 0UL)
+-#define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & _PFN_MASK))
++#define pgd_page_vaddr(pgd) ((unsigned long) __va(pgd_val(pgd) & _PFN_MASK))
++#define pgd_page(pgd) virt_to_page((pgd_val(pgd) + PAGE_OFFSET))
+ #endif
+
+ /*
+@@ -360,19 +362,19 @@ pgd_offset (struct mm_struct *mm, unsign
+ #ifdef CONFIG_PGTABLE_4
+ /* Find an entry in the second-level page table.. */
+ #define pud_offset(dir,addr) \
+- ((pud_t *) pgd_page(*(dir)) + (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))
++ ((pud_t *) pgd_page_vaddr(*(dir)) + (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))
+ #endif
+
+ /* Find an entry in the third-level page table.. */
+ #define pmd_offset(dir,addr) \
+- ((pmd_t *) pud_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
++ ((pmd_t *) pud_page_vaddr(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+
+ /*
+ * Find an entry in the third-level page table. This looks more complicated than it
+ * should be because some platforms place page tables in high memory.
+ */
+ #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+-#define pte_offset_kernel(dir,addr) ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr))
++#define pte_offset_kernel(dir,addr) ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
+ #define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr)
+ #define pte_offset_map_nested(dir,addr) pte_offset_map(dir, addr)
+ #define pte_unmap(pte) do { } while (0)
+diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
+index 265f482..5830d36 100644
+--- a/include/asm-ia64/processor.h
++++ b/include/asm-ia64/processor.h
+@@ -20,12 +20,6 @@
+ #include <asm/ustack.h>
+
+ #define IA64_NUM_DBG_REGS 8
+-/*
+- * Limits for PMC and PMD are set to less than maximum architected values
+- * but should be sufficient for a while
+- */
+-#define IA64_NUM_PMC_REGS 64
+-#define IA64_NUM_PMD_REGS 64
+
+ #define DEFAULT_MAP_BASE __IA64_UL_CONST(0x2000000000000000)
+ #define DEFAULT_TASK_SIZE __IA64_UL_CONST(0xa000000000000000)
+@@ -163,6 +157,7 @@ struct cpuinfo_ia64 {
+ __u8 family;
+ __u8 archrev;
+ char vendor[16];
++ char *model_name;
+
+ #ifdef CONFIG_NUMA
+ struct ia64_node_data *node_data;
+@@ -262,13 +257,9 @@ struct thread_struct {
+ # define INIT_THREAD_IA32
+ #endif /* CONFIG_IA32_SUPPORT */
+ #ifdef CONFIG_PERFMON
+- __u64 pmcs[IA64_NUM_PMC_REGS];
+- __u64 pmds[IA64_NUM_PMD_REGS];
+ void *pfm_context; /* pointer to detailed PMU context */
+ unsigned long pfm_needs_checking; /* when >0, pending perfmon work on kernel exit */
+-# define INIT_THREAD_PM .pmcs = {0UL, }, \
+- .pmds = {0UL, }, \
+- .pfm_context = NULL, \
++# define INIT_THREAD_PM .pfm_context = NULL, \
+ .pfm_needs_checking = 0UL,
+ #else
+ # define INIT_THREAD_PM
+diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
+index 1414316..f4ef87a 100644
+--- a/include/asm-ia64/ptrace.h
++++ b/include/asm-ia64/ptrace.h
+@@ -241,6 +241,9 @@ struct switch_stack {
+ * the canonical representation by adding to instruction pointer.
+ */
+ # define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri)
++
++#define regs_return_value(regs) ((regs)->r8)
++
+ /* Conserve space in histogram by encoding slot bits in address
+ * bits 2 and 3 rather than bits 0 and 1.
+ */
+diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h
+index 0b210ab..d000689 100644
+--- a/include/asm-ia64/sal.h
++++ b/include/asm-ia64/sal.h
+@@ -659,6 +659,7 @@ ia64_sal_freq_base (unsigned long which,
+ }
+
+ extern s64 ia64_sal_cache_flush (u64 cache_type);
++extern void __init check_sal_cache_flush (void);
+
+ /* Initialize all the processor and platform level instruction and data caches */
+ static inline s64
+diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
+index 719ff30..60fd4ae 100644
+--- a/include/asm-ia64/smp.h
++++ b/include/asm-ia64/smp.h
+@@ -122,12 +122,11 @@ extern void __init smp_build_cpu_map(voi
+ extern void __init init_smp_config (void);
+ extern void smp_do_timer (struct pt_regs *regs);
+
+-extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info,
+- int retry, int wait);
+ extern void smp_send_reschedule (int cpu);
+ extern void lock_ipi_calllock(void);
+ extern void unlock_ipi_calllock(void);
+ extern void identify_siblings (struct cpuinfo_ia64 *);
++extern int is_multithreading_enabled(void);
+
+ #else
+
+diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
+index e3b0c3f..da3eade 100644
+--- a/include/asm-ia64/sn/pcibr_provider.h
++++ b/include/asm-ia64/sn/pcibr_provider.h
+@@ -135,7 +135,7 @@ extern void pcireg_intr_addr
+ extern void pcireg_force_intr_set(struct pcibus_info *, int);
+ extern u64 pcireg_wrb_flush_get(struct pcibus_info *, int);
+ extern void pcireg_int_ate_set(struct pcibus_info *, int, u64);
+-extern u64 * pcireg_int_ate_addr(struct pcibus_info *, int);
++extern u64 __iomem * pcireg_int_ate_addr(struct pcibus_info *, int);
+ extern void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info);
+ extern void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info);
+ extern int pcibr_ate_alloc(struct pcibus_info *, int);
+diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h
+index 65cdd73..9a820ac 100644
+--- a/include/asm-ia64/sn/tioca_provider.h
++++ b/include/asm-ia64/sn/tioca_provider.h
+@@ -162,11 +162,11 @@ static inline void
+ tioca_tlbflush(struct tioca_kernel *tioca_kernel)
+ {
+ volatile u64 tmp;
+- volatile struct tioca *ca_base;
++ volatile struct tioca __iomem *ca_base;
+ struct tioca_common *tioca_common;
+
+ tioca_common = tioca_kernel->ca_common;
+- ca_base = (struct tioca *)tioca_common->ca_common.bs_base;
++ ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base;
+
+ /*
+ * Explicit flushes not needed if GART is in cached mode
+diff --git a/include/asm-ia64/sn/tioce_provider.h b/include/asm-ia64/sn/tioce_provider.h
+index 6d62b13..32c32f3 100644
+--- a/include/asm-ia64/sn/tioce_provider.h
++++ b/include/asm-ia64/sn/tioce_provider.h
+@@ -53,7 +53,7 @@ struct tioce_dmamap {
+ u64 ct_start; /* coretalk start address */
+ u64 pci_start; /* bus start address */
+
+- u64 *ate_hw; /* hw ptr of first ate in map */
++ u64 __iomem *ate_hw;/* hw ptr of first ate in map */
+ u64 *ate_shadow; /* shadow ptr of firat ate */
+ u16 ate_count; /* # ate's in the map */
+ };
+diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h
+index 35e1386..1d45e15 100644
+--- a/include/asm-ia64/sn/xpc.h
++++ b/include/asm-ia64/sn/xpc.h
+@@ -669,7 +669,7 @@ extern struct device *xpc_part;
+ extern struct device *xpc_chan;
+ extern int xpc_disengage_request_timelimit;
+ extern int xpc_disengage_request_timedout;
+-extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *);
++extern irqreturn_t xpc_notify_IRQ_handler(int, void *);
+ extern void xpc_dropped_IPI_check(struct xpc_partition *);
+ extern void xpc_activate_partition(struct xpc_partition *);
+ extern void xpc_activate_kthreads(struct xpc_channel *, int);
+diff --git a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h
+index 9e83210..ff857e3 100644
+--- a/include/asm-ia64/spinlock.h
++++ b/include/asm-ia64/spinlock.h
+@@ -213,4 +213,8 @@ static inline int __raw_read_trylock(raw
+ return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* _ASM_IA64_SPINLOCK_H */
+diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
+index 937c212..a6e3856 100644
+--- a/include/asm-ia64/topology.h
++++ b/include/asm-ia64/topology.h
+@@ -59,6 +59,7 @@ void build_cpu_to_node_map(void);
+ #define SD_CPU_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 1, \
+ .max_interval = 4, \
+@@ -84,6 +85,7 @@ void build_cpu_to_node_map(void);
+ #define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 8*(min(num_online_cpus(), 32)), \
+diff --git a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
+index 9adb512..449c8c0 100644
+--- a/include/asm-ia64/uaccess.h
++++ b/include/asm-ia64/uaccess.h
+@@ -389,7 +389,7 @@ xlate_dev_kmem_ptr (char * p)
+ struct page *page;
+ char * ptr;
+
+- page = virt_to_page((unsigned long)p >> PAGE_SHIFT);
++ page = virt_to_page((unsigned long)p);
+ if (PageUncached(page))
+ ptr = (char *)__pa(p) + __IA64_UNCACHED_OFFSET;
+ else
+diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
+index f581662..53c5c0e 100644
+--- a/include/asm-ia64/unistd.h
++++ b/include/asm-ia64/unistd.h
+@@ -286,7 +286,8 @@
+ /* 1294, 1295 reserved for pselect/ppoll */
+ #define __NR_unshare 1296
+ #define __NR_splice 1297
+-/* 1298, 1299 reserved for set_robust_list/get_robust_list */
++#define __NR_set_robust_list 1298
++#define __NR_get_robust_list 1299
+ #define __NR_sync_file_range 1300
+ #define __NR_tee 1301
+ #define __NR_vmsplice 1302
+@@ -318,78 +319,6 @@
+
+ extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr);
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/string.h>
+-#include <linux/signal.h>
+-#include <asm/ptrace.h>
+-#include <linux/stringify.h>
+-#include <linux/syscalls.h>
+-
+-static inline long
+-open (const char * name, int mode, int flags)
+-{
+- return sys_open(name, mode, flags);
+-}
+-
+-static inline long
+-dup (int fd)
+-{
+- return sys_dup(fd);
+-}
+-
+-static inline long
+-close (int fd)
+-{
+- return sys_close(fd);
+-}
+-
+-static inline off_t
+-lseek (int fd, off_t off, int whence)
+-{
+- return sys_lseek(fd, off, whence);
+-}
+-
+-static inline void
+-_exit (int value)
+-{
+- sys_exit(value);
+-}
+-
+-#define exit(x) _exit(x)
+-
+-static inline long
+-write (int fd, const char * buf, size_t nr)
+-{
+- return sys_write(fd, buf, nr);
+-}
+-
+-static inline long
+-read (int fd, char * buf, size_t nr)
+-{
+- return sys_read(fd, buf, nr);
+-}
+-
+-
+-static inline long
+-setsid (void)
+-{
+- return sys_setsid();
+-}
+-
+-static inline pid_t
+-waitpid (int pid, int * wait_stat, int flags)
+-{
+- return sys_wait4(pid, wait_stat, flags, NULL);
+-}
+-
+-
+-extern int execve (const char *filename, char *const av[], char *const ep[]);
+-extern pid_t clone (unsigned long flags, void *sp);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ asmlinkage unsigned long sys_mmap(
+ unsigned long addr, unsigned long len,
+ int prot, int flags,
+diff --git a/include/asm-m32r/io.h b/include/asm-m32r/io.h
+index 70ad1c9..d06933b 100644
+--- a/include/asm-m32r/io.h
++++ b/include/asm-m32r/io.h
+@@ -166,38 +166,6 @@ static inline void _writel(unsigned long
+
+ #define flush_write_buffers() do { } while (0) /* M32R_FIXME */
+
+-/**
+- * check_signature - find BIOS signatures
+- * @io_addr: mmio address to check
+- * @signature: signature block
+- * @length: length of signature
+- *
+- * Perform a signature comparison with the ISA mmio address io_addr.
+- * Returns 1 on a match.
+- *
+- * This function is deprecated. New drivers should use ioremap and
+- * check_signature.
+- */
+-
+-static inline int check_signature(void __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+-#if 0
+-printk("check_signature\n");
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+-#endif
+- return retval;
+-}
+-
+ static inline void
+ memset_io(volatile void __iomem *addr, unsigned char val, int count)
+ {
+diff --git a/include/asm-m32r/irq_regs.h b/include/asm-m32r/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-m32r/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-m32r/m32104ut/m32104ut_pld.h b/include/asm-m32r/m32104ut/m32104ut_pld.h
+index 6ba4ddf..cbdbc58 100644
+--- a/include/asm-m32r/m32104ut/m32104ut_pld.h
++++ b/include/asm-m32r/m32104ut/m32104ut_pld.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/m32104ut/m32104ut_pld.h
++ * include/asm-m32r/m32104ut/m32104ut_pld.h
+ *
+ * Definitions for Programable Logic Device(PLD) on M32104UT board.
+ * Based on m32700ut_pld.h
+diff --git a/include/asm-m32r/m32700ut/m32700ut_lan.h b/include/asm-m32r/m32700ut/m32700ut_lan.h
+index c050b19..f1e47ae 100644
+--- a/include/asm-m32r/m32700ut/m32700ut_lan.h
++++ b/include/asm-m32r/m32700ut/m32700ut_lan.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/m32700ut_lan.h
++ * include/asm-m32r/m32700ut/m32700ut_lan.h
+ *
+ * M32700UT-LAN board
+ *
+diff --git a/include/asm-m32r/m32700ut/m32700ut_lcd.h b/include/asm-m32r/m32700ut/m32700ut_lcd.h
+index 4da4e82..e41c4aa 100644
+--- a/include/asm-m32r/m32700ut/m32700ut_lcd.h
++++ b/include/asm-m32r/m32700ut/m32700ut_lcd.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/m32700ut_lcd.h
++ * include/asm-m32r/m32700ut/m32700ut_lcd.h
+ *
+ * M32700UT-LCD board
+ *
+diff --git a/include/asm-m32r/m32700ut/m32700ut_pld.h b/include/asm-m32r/m32700ut/m32700ut_pld.h
+index f35f915..a48c22c 100644
+--- a/include/asm-m32r/m32700ut/m32700ut_pld.h
++++ b/include/asm-m32r/m32700ut/m32700ut_pld.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/m32700ut/m32700ut_pld.h
++ * include/asm-m32r/m32700ut/m32700ut_pld.h
+ *
+ * Definitions for Programable Logic Device(PLD) on M32700UT board.
+ *
+diff --git a/include/asm-m32r/mappi2/mappi2_pld.h b/include/asm-m32r/mappi2/mappi2_pld.h
+index 01dcdd1..56a2b12 100644
+--- a/include/asm-m32r/mappi2/mappi2_pld.h
++++ b/include/asm-m32r/mappi2/mappi2_pld.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/mappi2/mappi2_pld.h
++ * include/asm-m32r/mappi2/mappi2_pld.h
+ *
+ * Definitions for Extended IO Logic on MAPPI2 board.
+ * based on m32700ut_pld.h by
+diff --git a/include/asm-m32r/mappi3/mappi3_pld.h b/include/asm-m32r/mappi3/mappi3_pld.h
+index 031369a..92f10de 100644
+--- a/include/asm-m32r/mappi3/mappi3_pld.h
++++ b/include/asm-m32r/mappi3/mappi3_pld.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/mappi3/mappi3_pld.h
++ * include/asm-m32r/mappi3/mappi3_pld.h
+ *
+ * Definitions for Extended IO Logic on MAPPI3 board.
+ * based on m32700ut_pld.h
+diff --git a/include/asm-m32r/opsput/opsput_lan.h b/include/asm-m32r/opsput/opsput_lan.h
+index 6194829..f53e101 100644
+--- a/include/asm-m32r/opsput/opsput_lan.h
++++ b/include/asm-m32r/opsput/opsput_lan.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/opsput_lan.h
++ * include/asm-m32r/opsput/opsput_lan.h
+ *
+ * OPSPUT-LAN board
+ *
+diff --git a/include/asm-m32r/opsput/opsput_lcd.h b/include/asm-m32r/opsput/opsput_lcd.h
+index 44cfd7f..99f296e 100644
+--- a/include/asm-m32r/opsput/opsput_lcd.h
++++ b/include/asm-m32r/opsput/opsput_lcd.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/opsput_lcd.h
++ * include/asm-m32r/opsput/opsput_lcd.h
+ *
+ * OPSPUT-LCD board
+ *
+diff --git a/include/asm-m32r/opsput/opsput_pld.h b/include/asm-m32r/opsput/opsput_pld.h
+index 46296fe..a8d6452 100644
+--- a/include/asm-m32r/opsput/opsput_pld.h
++++ b/include/asm-m32r/opsput/opsput_pld.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm/opsput/opsput_pld.h
++ * include/asm-m32r/opsput/opsput_pld.h
+ *
+ * Definitions for Programable Logic Device(PLD) on OPSPUT board.
+ *
+diff --git a/include/asm-m32r/page.h b/include/asm-m32r/page.h
+index 9688be0..404a4c2 100644
+--- a/include/asm-m32r/page.h
++++ b/include/asm-m32r/page.h
+@@ -87,10 +87,9 @@ typedef struct { unsigned long pgprot; }
+
+ #define devmem_is_allowed(x) 1
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++#endif /* __KERNEL__ */
+ #endif /* _ASM_M32R_PAGE_H */
+
+diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h
+index be0f167..8415276 100644
+--- a/include/asm-m32r/pgtable-2level.h
++++ b/include/asm-m32r/pgtable-2level.h
+@@ -44,7 +44,7 @@ static inline int pgd_present(pgd_t pgd)
+ */
+ #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+ #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+-#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
++
+ /*
+ * (pmds are folded into pgds so this doesnt get actually called,
+ * but the define is needed for a generic inline function.)
+@@ -52,9 +52,13 @@ static inline int pgd_present(pgd_t pgd)
+ #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+ #define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
+-#define pgd_page(pgd) \
++#define pgd_page_vaddr(pgd) \
+ ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
++#ifndef CONFIG_DISCONTIGMEM
++#define pgd_page(pgd) (mem_map + ((pgd_val(pgd) >> PAGE_SHIFT) - PFN_BASE))
++#endif /* !CONFIG_DISCONTIGMEM */
++
+ static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address)
+ {
+ return (pmd_t *) dir;
+diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
+index 1983b7f..1c15ba7 100644
+--- a/include/asm-m32r/pgtable.h
++++ b/include/asm-m32r/pgtable.h
+@@ -336,7 +336,7 @@ static inline void pmd_set(pmd_t * pmdp,
+ pmd_val(*pmdp) = (((unsigned long) ptep) & PAGE_MASK);
+ }
+
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ #ifndef CONFIG_DISCONTIGMEM
+@@ -358,7 +358,7 @@ static inline void pmd_set(pmd_t * pmdp,
+ #define pte_index(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *)pmd_page_kernel(*(dir)) + pte_index(address))
++ ((pte_t *)pmd_page_vaddr(*(dir)) + pte_index(address))
+ #define pte_offset_map(dir, address) \
+ ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
+ #define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
+diff --git a/include/asm-m32r/ptrace.h b/include/asm-m32r/ptrace.h
+index a07fa90..2d2a6c9 100644
+--- a/include/asm-m32r/ptrace.h
++++ b/include/asm-m32r/ptrace.h
+@@ -12,8 +12,6 @@
+ * Copyright (C) 2001-2002, 2004 Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+-#include <asm/m32r.h> /* M32R_PSW_BSM, M32R_PSW_BPM */
+-
+ /* 0 - 13 are integer registers (general purpose registers). */
+ #define PT_R4 0
+ #define PT_R5 1
+@@ -140,6 +138,8 @@ struct pt_regs {
+
+ #ifdef __KERNEL__
+
++#include <asm/m32r.h> /* M32R_PSW_BSM, M32R_PSW_BPM */
++
+ #define __ARCH_SYS_PTRACE 1
+
+ #if defined(CONFIG_ISA_M32R2) || defined(CONFIG_CHIP_VDEC2)
+diff --git a/include/asm-m32r/signal.h b/include/asm-m32r/signal.h
+index e750045..65423be 100644
+--- a/include/asm-m32r/signal.h
++++ b/include/asm-m32r/signal.h
+@@ -6,7 +6,6 @@
+ /* orig : i386 2.4.18 */
+
+ #include <linux/types.h>
+-#include <linux/linkage.h>
+ #include <linux/time.h>
+ #include <linux/compiler.h>
+
+diff --git a/include/asm-m32r/spinlock.h b/include/asm-m32r/spinlock.h
+index f94c1a6..f5cfba8 100644
+--- a/include/asm-m32r/spinlock.h
++++ b/include/asm-m32r/spinlock.h
+@@ -298,7 +298,14 @@ static inline void __raw_write_unlock(ra
+ );
+ }
+
+-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
++static inline int __raw_read_trylock(raw_rwlock_t *lock)
++{
++ atomic_t *count = (atomic_t*)lock;
++ if (atomic_dec_return(count) >= 0)
++ return 1;
++ atomic_inc(count);
++ return 0;
++}
+
+ static inline int __raw_write_trylock(raw_rwlock_t *lock)
+ {
+@@ -309,4 +316,8 @@ static inline int __raw_write_trylock(ra
+ return 0;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* _ASM_M32R_SPINLOCK_H */
+diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
+index 9e618af..4ce0619 100644
+--- a/include/asm-m32r/system.h
++++ b/include/asm-m32r/system.h
+@@ -328,15 +328,15 @@ __cmpxchg(volatile void *ptr, unsigned l
+ #define smp_rmb() rmb()
+ #define smp_wmb() wmb()
+ #define smp_read_barrier_depends() read_barrier_depends()
++#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
+ #else
+ #define smp_mb() barrier()
+ #define smp_rmb() barrier()
+ #define smp_wmb() barrier()
+ #define smp_read_barrier_depends() do { } while (0)
++#define set_mb(var, value) do { var = value; barrier(); } while (0)
+ #endif
+
+-#define set_mb(var, value) do { xchg(&var, value); } while (0)
+-
+ #define arch_align_stack(x) (x)
+
+ #endif /* _ASM_M32R_SYSTEM_H */
+diff --git a/include/asm-m32r/timex.h b/include/asm-m32r/timex.h
+index e89bfd1..019441c 100644
+--- a/include/asm-m32r/timex.h
++++ b/include/asm-m32r/timex.h
+@@ -12,9 +12,6 @@
+
+ #define CLOCK_TICK_RATE (CONFIG_BUS_CLOCK / CONFIG_TIMER_DIVIDE)
+ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 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 __KERNEL__
+ /*
+diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h
+index cc31790..95aa342 100644
+--- a/include/asm-m32r/unistd.h
++++ b/include/asm-m32r/unistd.h
+@@ -3,8 +3,6 @@
+
+ /* $Id$ */
+
+-#include <asm/syscall.h> /* SYSCALL_* */
+-
+ /*
+ * This file contains the system call numbers.
+ */
+@@ -298,14 +296,17 @@
+ #ifdef __KERNEL__
+
+ #define NR_syscalls 285
++#include <linux/err.h>
+
+-/* user-visible error numbers are in the range -1 - -124: see
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
+ * <asm-m32r/errno.h>
+ */
+
++#include <asm/syscall.h> /* SYSCALL_* */
++
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-(124 + 1))) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ /* Avoid using "res" which is declared to be in register r0; \
+ errno might expand to a function call and clobber it. */ \
+ int __err = -(res); \
+@@ -423,43 +424,6 @@ __syscall_return(type,__res); \
+ #define __ARCH_WANT_SYS_OLDUMOUNT
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/linkage.h>
+-#include <asm/ptrace.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-
+-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(struct pt_regs regs);
+-asmlinkage int sys_clone(struct pt_regs regs);
+-asmlinkage int sys_fork(struct pt_regs regs);
+-asmlinkage int sys_vfork(struct pt_regs regs);
+-asmlinkage int sys_pipe(unsigned long __user *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-m32r/user.h b/include/asm-m32r/user.h
+index 2ffd0c6..1ad4ded 100644
+--- a/include/asm-m32r/user.h
++++ b/include/asm-m32r/user.h
+@@ -8,7 +8,6 @@
+ */
+
+ #include <linux/types.h>
+-#include <asm/processor.h>
+ #include <asm/ptrace.h>
+ #include <asm/page.h>
+
+diff --git a/include/asm-m68k/atari_stdma.h b/include/asm-m68k/atari_stdma.h
+index b4eadf8..8e389b7 100644
+--- a/include/asm-m68k/atari_stdma.h
++++ b/include/asm-m68k/atari_stdma.h
+@@ -8,8 +8,7 @@
+
+ /***************************** Prototypes *****************************/
+
+-void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *),
+- void *data);
++void stdma_lock(irq_handler_t handler, void *data);
+ void stdma_release( void );
+ int stdma_others_waiting( void );
+ int stdma_islocked( void );
+diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h
+index cebbb03..d90d841 100644
+--- a/include/asm-m68k/dma-mapping.h
++++ b/include/asm-m68k/dma-mapping.h
+@@ -5,6 +5,7 @@
+
+ struct scatterlist;
+
++#ifndef CONFIG_MMU_SUN3
+ static inline int dma_supported(struct device *dev, u64 mask)
+ {
+ return 1;
+@@ -26,7 +27,7 @@ static inline int dma_is_consistent(dma_
+ }
+
+ extern void *dma_alloc_coherent(struct device *, size_t,
+- dma_addr_t *, int);
++ dma_addr_t *, gfp_t);
+ extern void dma_free_coherent(struct device *, size_t,
+ void *, dma_addr_t);
+
+@@ -88,4 +89,8 @@ static inline int dma_mapping_error(dma_
+ return 0;
+ }
+
++#else
++#include <asm-generic/dma-mapping-broken.h>
++#endif
++
+ #endif /* _M68K_DMA_MAPPING_H */
+diff --git a/include/asm-m68k/floppy.h b/include/asm-m68k/floppy.h
+index 57f4fdd..45dc908 100644
+--- a/include/asm-m68k/floppy.h
++++ b/include/asm-m68k/floppy.h
+@@ -17,8 +17,7 @@
+
+ #include <linux/vmalloc.h>
+
+-asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id,
+- struct pt_regs *regs);
++asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id);
+
+ /* constants... */
+
+@@ -184,8 +183,7 @@ static void fd_disable_dma(void)
+
+ /* this is the only truly Q40 specific function */
+
+-asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id,
+- struct pt_regs *regs)
++asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id)
+ {
+ register unsigned char st;
+
+@@ -198,7 +196,7 @@ asmlinkage irqreturn_t floppy_hardint(in
+ static int dma_wait=0;
+ #endif
+ if(!doing_pdma) {
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+
+@@ -246,7 +244,7 @@ asmlinkage irqreturn_t floppy_hardint(in
+ dma_wait=0;
+ #endif
+ doing_pdma = 0;
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+ #ifdef TRACE_FLPY_INT
+diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h
+index 365f76f..f9ffb2c 100644
+--- a/include/asm-m68k/ide.h
++++ b/include/asm-m68k/ide.h
+@@ -123,7 +123,7 @@ static __inline__ void ide_release_lock
+ }
+
+ static __inline__ void
+-ide_get_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *), void *data)
++ide_get_lock(irq_handler_t handler, void *data)
+ {
+ if (MACH_IS_ATARI) {
+ if (falconide_intr_lock == 0) {
+diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
+index 3257f98..4901cb1 100644
+--- a/include/asm-m68k/irq.h
++++ b/include/asm-m68k/irq.h
+@@ -83,7 +83,7 @@ struct pt_regs;
+ * interrupt source (if it supports chaining).
+ */
+ typedef struct irq_node {
+- int (*handler)(int, void *, struct pt_regs *);
++ int (*handler)(int, void *);
+ void *dev_id;
+ struct irq_node *next;
+ unsigned long flags;
+@@ -93,12 +93,12 @@ typedef struct irq_node {
+ /*
+ * This structure has only 4 elements for speed reasons
+ */
+-typedef struct irq_handler {
+- int (*handler)(int, void *, struct pt_regs *);
++struct irq_handler {
++ int (*handler)(int, void *);
+ unsigned long flags;
+ void *dev_id;
+ const char *devname;
+-} irq_handler_t;
++};
+
+ struct irq_controller {
+ const char *name;
+@@ -122,6 +122,7 @@ extern void m68k_setup_user_interrupt(un
+ void (*handler)(unsigned int, struct pt_regs *));
+ extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
+
+-asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *);
++asmlinkage void m68k_handle_int(unsigned int);
++asmlinkage void __m68k_handle_int(unsigned int, struct pt_regs *);
+
+ #endif /* _M68K_IRQ_H_ */
+diff --git a/include/asm-m68k/irq_regs.h b/include/asm-m68k/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-m68k/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-m68k/mac_iop.h b/include/asm-m68k/mac_iop.h
+index b0d2e34..a2c7e6f 100644
+--- a/include/asm-m68k/mac_iop.h
++++ b/include/asm-m68k/mac_iop.h
+@@ -143,17 +143,17 @@ struct iop_msg {
+ int status; /* status of this message */
+ __u8 message[IOP_MSG_LEN]; /* the message being sent/received */
+ __u8 reply[IOP_MSG_LEN]; /* the reply to the message */
+- void (*handler)(struct iop_msg *, struct pt_regs *);
++ void (*handler)(struct iop_msg *);
+ /* function to call when reply recvd */
+ };
+
+ extern int iop_scc_present,iop_ism_present;
+
+ extern int iop_listen(uint, uint,
+- void (*handler)(struct iop_msg *, struct pt_regs *),
++ void (*handler)(struct iop_msg *),
+ const char *);
+ extern int iop_send_message(uint, uint, void *, uint, __u8 *,
+- void (*)(struct iop_msg *, struct pt_regs *));
++ void (*)(struct iop_msg *));
+ extern void iop_complete_message(struct iop_msg *);
+ extern void iop_upload_code(uint, __u8 *, uint, __u16);
+ extern void iop_download_code(uint, __u8 *, uint, __u16);
+diff --git a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h
+index df898f2..26d2b91 100644
+--- a/include/asm-m68k/machdep.h
++++ b/include/asm-m68k/machdep.h
+@@ -10,7 +10,7 @@ struct rtc_time;
+ struct rtc_pll_info;
+ struct buffer_head;
+
+-extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *));
++extern void (*mach_sched_init) (irq_handler_t handler);
+ /* machine dependent irq functions */
+ extern void (*mach_init_IRQ) (void);
+ extern void (*mach_get_model) (char *model);
+diff --git a/include/asm-m68k/motorola_pgtable.h b/include/asm-m68k/motorola_pgtable.h
+index 1ccc733..61e4406 100644
+--- a/include/asm-m68k/motorola_pgtable.h
++++ b/include/asm-m68k/motorola_pgtable.h
+@@ -150,6 +150,7 @@ static inline void pgd_set(pgd_t *pgdp,
+ #define pgd_bad(pgd) ((pgd_val(pgd) & _DESCTYPE_MASK) != _PAGE_TABLE)
+ #define pgd_present(pgd) (pgd_val(pgd) & _PAGE_TABLE)
+ #define pgd_clear(pgdp) ({ pgd_val(*pgdp) = 0; })
++#define pgd_page(pgd) (mem_map + ((unsigned long)(__va(pgd_val(pgd)) - PAGE_OFFSET) >> PAGE_SHIFT))
+
+ #define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+diff --git a/include/asm-m68k/rtc.h b/include/asm-m68k/rtc.h
+index 71406fc..5d3e038 100644
+--- a/include/asm-m68k/rtc.h
++++ b/include/asm-m68k/rtc.h
+@@ -1,4 +1,4 @@
+-/* asm-m68k/rtc.h
++/* include/asm-m68k/rtc.h
+ *
+ * Copyright Richard Zidlicky
+ * implementation details for genrtc/q40rtc driver
+diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h
+index de1ba6e..3db8a81 100644
+--- a/include/asm-m68k/signal.h
++++ b/include/asm-m68k/signal.h
+@@ -198,6 +198,7 @@ static inline int sigfindinword(unsigned
+ return word ^ 31;
+ }
+
++struct pt_regs;
+ extern void ptrace_signal_deliver(struct pt_regs *regs, void *cookie);
+
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-m68k/string.h b/include/asm-m68k/string.h
+index 6c59215..2eb7df1 100644
+--- a/include/asm-m68k/string.h
++++ b/include/asm-m68k/string.h
+@@ -1,138 +1,114 @@
+ #ifndef _M68K_STRING_H_
+ #define _M68K_STRING_H_
+
+-#include <asm/setup.h>
+-#include <asm/page.h>
++#include <linux/types.h>
++#include <linux/compiler.h>
+
+-#define __HAVE_ARCH_STRCPY
+-static inline char * strcpy(char * dest,const char *src)
++static inline size_t __kernel_strlen(const char *s)
+ {
+- char *xdest = dest;
+-
+- __asm__ __volatile__
+- ("1:\tmoveb %1 at +,%0 at +\n\t"
+- "jne 1b"
+- : "=a" (dest), "=a" (src)
+- : "0" (dest), "1" (src) : "memory");
+- return xdest;
+-}
++ const char *sc;
+
+-#define __HAVE_ARCH_STRNCPY
+-static inline char * strncpy(char *dest, const char *src, size_t n)
+-{
+- char *xdest = dest;
+-
+- if (n == 0)
+- return xdest;
+-
+- __asm__ __volatile__
+- ("1:\tmoveb %1 at +,%0 at +\n\t"
+- "jeq 2f\n\t"
+- "subql #1,%2\n\t"
+- "jne 1b\n\t"
+- "2:"
+- : "=a" (dest), "=a" (src), "=d" (n)
+- : "0" (dest), "1" (src), "2" (n)
+- : "memory");
+- return xdest;
++ for (sc = s; *sc++; )
++ ;
++ return sc - s - 1;
+ }
+
+-#define __HAVE_ARCH_STRCAT
+-static inline char * strcat(char * dest, const char * src)
++static inline char *__kernel_strcpy(char *dest, const char *src)
+ {
+- char *tmp = dest;
+-
+- while (*dest)
+- dest++;
+- while ((*dest++ = *src++))
+- ;
+-
+- return tmp;
++ char *xdest = dest;
++
++ asm volatile ("\n"
++ "1: move.b (%1)+,(%0)+\n"
++ " jne 1b"
++ : "+a" (dest), "+a" (src)
++ : : "memory");
++ return xdest;
+ }
+
+-#define __HAVE_ARCH_STRNCAT
+-static inline char * strncat(char *dest, const char *src, size_t count)
+-{
+- char *tmp = dest;
+-
+- if (count) {
+- while (*dest)
+- dest++;
+- while ((*dest++ = *src++)) {
+- if (--count == 0) {
+- *dest++='\0';
+- break;
+- }
+- }
+- }
++#ifndef __IN_STRING_C
+
+- return tmp;
+-}
++#define __HAVE_ARCH_STRLEN
++#define strlen(s) (__builtin_constant_p(s) ? \
++ __builtin_strlen(s) : \
++ __kernel_strlen(s))
+
+-#define __HAVE_ARCH_STRCHR
+-static inline char * strchr(const char * s, int c)
++#define __HAVE_ARCH_STRNLEN
++static inline size_t strnlen(const char *s, size_t count)
+ {
+- const char ch = c;
+-
+- for(; *s != ch; ++s)
+- if (*s == '\0')
+- return( NULL );
+- return( (char *) s);
++ const char *sc = s;
++
++ asm volatile ("\n"
++ "1: subq.l #1,%1\n"
++ " jcs 2f\n"
++ " tst.b (%0)+\n"
++ " jne 1b\n"
++ " subq.l #1,%0\n"
++ "2:"
++ : "+a" (sc), "+d" (count));
++ return sc - s;
+ }
+
+-/* strstr !! */
++#define __HAVE_ARCH_STRCPY
++#if __GNUC__ >= 4
++#define strcpy(d, s) (__builtin_constant_p(s) && \
++ __builtin_strlen(s) <= 32 ? \
++ __builtin_strcpy(d, s) : \
++ __kernel_strcpy(d, s))
++#else
++#define strcpy(d, s) __kernel_strcpy(d, s)
++#endif
+
+-#define __HAVE_ARCH_STRLEN
+-static inline size_t strlen(const char * s)
++#define __HAVE_ARCH_STRNCPY
++static inline char *strncpy(char *dest, const char *src, size_t n)
+ {
+- const char *sc;
+- for (sc = s; *sc != '\0'; ++sc) ;
+- return(sc - s);
++ char *xdest = dest;
++
++ asm volatile ("\n"
++ " jra 2f\n"
++ "1: move.b (%1),(%0)+\n"
++ " jeq 2f\n"
++ " addq.l #1,%1\n"
++ "2: subq.l #1,%2\n"
++ " jcc 1b\n"
++ : "+a" (dest), "+a" (src), "+d" (n)
++ : : "memory");
++ return xdest;
+ }
+
+-/* strnlen !! */
++#define __HAVE_ARCH_STRCAT
++#define strcat(d, s) ({ \
++ char *__d = (d); \
++ strcpy(__d + strlen(__d), (s)); \
++})
+
+-#define __HAVE_ARCH_STRCMP
+-static inline int strcmp(const char * cs,const char * ct)
++#define __HAVE_ARCH_STRCHR
++static inline char *strchr(const char *s, int c)
+ {
+- char __res;
+-
+- __asm__
+- ("1:\tmoveb %0 at +,%2\n\t" /* get *cs */
+- "cmpb %1 at +,%2\n\t" /* compare a byte */
+- "jne 2f\n\t" /* not equal, break out */
+- "tstb %2\n\t" /* at end of cs? */
+- "jne 1b\n\t" /* no, keep going */
+- "jra 3f\n\t" /* strings are equal */
+- "2:\tsubb %1 at -,%2\n\t" /* *cs - *ct */
+- "3:"
+- : "=a" (cs), "=a" (ct), "=d" (__res)
+- : "0" (cs), "1" (ct));
+- return __res;
++ char sc, ch = c;
++
++ for (; (sc = *s++) != ch; ) {
++ if (!sc)
++ return NULL;
++ }
++ return (char *)s - 1;
+ }
+
+-#define __HAVE_ARCH_STRNCMP
+-static inline int strncmp(const char * cs,const char * ct,size_t count)
++#define __HAVE_ARCH_STRCMP
++static inline int strcmp(const char *cs, const char *ct)
+ {
+- char __res;
+-
+- if (!count)
+- return 0;
+- __asm__
+- ("1:\tmovb %0 at +,%3\n\t" /* get *cs */
+- "cmpb %1 at +,%3\n\t" /* compare a byte */
+- "jne 3f\n\t" /* not equal, break out */
+- "tstb %3\n\t" /* at end of cs? */
+- "jeq 4f\n\t" /* yes, all done */
+- "subql #1,%2\n\t" /* no, adjust count */
+- "jne 1b\n\t" /* more to do, keep going */
+- "2:\tmoveq #0,%3\n\t" /* strings are equal */
+- "jra 4f\n\t"
+- "3:\tsubb %1 at -,%3\n\t" /* *cs - *ct */
+- "4:"
+- : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res)
+- : "0" (cs), "1" (ct), "2" (count));
+- return __res;
++ char res;
++
++ asm ("\n"
++ "1: move.b (%0)+,%2\n" /* get *cs */
++ " cmp.b (%1)+,%2\n" /* compare a byte */
++ " jne 2f\n" /* not equal, break out */
++ " tst.b %2\n" /* at end of cs? */
++ " jne 1b\n" /* no, keep going */
++ " jra 3f\n" /* strings are equal */
++ "2: sub.b -(%1),%2\n" /* *cs - *ct */
++ "3:"
++ : "+a" (cs), "+a" (ct), "=d" (res));
++ return res;
+ }
+
+ #define __HAVE_ARCH_MEMSET
+@@ -150,4 +126,6 @@ extern void *memmove(void *, const void
+ extern int memcmp(const void *, const void *, __kernel_size_t);
+ #define memcmp(d, s, n) __builtin_memcmp(d, s, n)
+
++#endif
++
+ #endif /* _M68K_STRING_H_ */
+diff --git a/include/asm-m68k/sun3mmu.h b/include/asm-m68k/sun3mmu.h
+index 6c8c17d..d8f17a0 100644
+--- a/include/asm-m68k/sun3mmu.h
++++ b/include/asm-m68k/sun3mmu.h
+@@ -4,6 +4,7 @@
+ #ifndef __SUN3_MMU_H__
+ #define __SUN3_MMU_H__
+
++#include <linux/types.h>
+ #include <asm/movs.h>
+ #include <asm/sun3-head.h>
+
+@@ -160,7 +161,7 @@ static inline void sun3_put_context(unsi
+ return;
+ }
+
+-extern void *sun3_ioremap(unsigned long phys, unsigned long size,
++extern void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
+ unsigned long type);
+
+ extern int sun3_map_test(unsigned long addr, char *val);
+diff --git a/include/asm-m68k/sun3xflop.h b/include/asm-m68k/sun3xflop.h
+index ca8cc41..32c45f8 100644
+--- a/include/asm-m68k/sun3xflop.h
++++ b/include/asm-m68k/sun3xflop.h
+@@ -111,8 +111,7 @@ static void sun3x_82072_fd_outb(unsigned
+ }
+
+
+-asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id,
+- struct pt_regs * regs)
++asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id)
+ {
+ register unsigned char st;
+
+@@ -125,7 +124,7 @@ asmlinkage irqreturn_t sun3xflop_hardint
+ static int dma_wait=0;
+ #endif
+ if(!doing_pdma) {
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+
+@@ -189,7 +188,7 @@ asmlinkage irqreturn_t sun3xflop_hardint
+ dma_wait=0;
+ #endif
+
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+
+diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
+index 131a0cb..243dd13 100644
+--- a/include/asm-m68k/system.h
++++ b/include/asm-m68k/system.h
+@@ -78,13 +78,13 @@ static inline int irqs_disabled(void)
+ #define mb() barrier()
+ #define rmb() barrier()
+ #define wmb() barrier()
+-#define read_barrier_depends() do { } while(0)
+-#define set_mb(var, value) do { xchg(&var, value); } while (0)
++#define read_barrier_depends() ((void)0)
++#define set_mb(var, value) ({ (var) = (value); wmb(); })
+
+ #define smp_mb() barrier()
+ #define smp_rmb() barrier()
+ #define smp_wmb() barrier()
+-#define smp_read_barrier_depends() do { } while(0)
++#define smp_read_barrier_depends() ((void)0)
+
+
+ #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
+index 88b1f47..e4c9f08 100644
+--- a/include/asm-m68k/uaccess.h
++++ b/include/asm-m68k/uaccess.h
+@@ -76,7 +76,7 @@ asm volatile ("\n" \
+ break; \
+ case 8: \
+ { \
+- const void *__pu_ptr = (ptr); \
++ const void __user *__pu_ptr = (ptr); \
+ asm volatile ("\n" \
+ "1: moves.l %2,(%1)+\n" \
+ "2: moves.l %R2,(%1)\n" \
+@@ -125,7 +125,7 @@ asm volatile ("\n" \
+ " .previous" \
+ : "+d" (res), "=&" #reg (__gu_val) \
+ : "m" (*(ptr)), "i" (err)); \
+- (x) = (typeof(*(ptr)))(long)__gu_val; \
++ (x) = (typeof(*(ptr)))(unsigned long)__gu_val; \
+ })
+
+ #define __get_user(x, ptr) \
+@@ -221,16 +221,16 @@ __constant_copy_from_user(void *to, cons
+
+ switch (n) {
+ case 1:
+- __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1);
++ __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1);
+ break;
+ case 2:
+- __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2);
++ __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2);
+ break;
+ case 3:
+ __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
+ break;
+ case 4:
+- __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4);
++ __get_user_asm(res, *(u32 *)to, (u32 __user *)from, u32, l, r, 4);
+ break;
+ case 5:
+ __constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
+@@ -302,16 +302,16 @@ __constant_copy_to_user(void __user *to,
+
+ switch (n) {
+ case 1:
+- __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1);
++ __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
+ break;
+ case 2:
+- __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2);
++ __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2);
+ break;
+ case 3:
+ __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
+ break;
+ case 4:
+- __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4);
++ __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
+ break;
+ case 5:
+ __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
+diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
+index 7c0b629..ad43480 100644
+--- a/include/asm-m68k/unistd.h
++++ b/include/asm-m68k/unistd.h
+@@ -284,17 +284,47 @@
+ #define __NR_add_key 279
+ #define __NR_request_key 280
+ #define __NR_keyctl 281
++#define __NR_ioprio_set 282
++#define __NR_ioprio_get 283
++#define __NR_inotify_init 284
++#define __NR_inotify_add_watch 285
++#define __NR_inotify_rm_watch 286
++#define __NR_migrate_pages 287
++#define __NR_openat 288
++#define __NR_mkdirat 289
++#define __NR_mknodat 290
++#define __NR_fchownat 291
++#define __NR_futimesat 292
++#define __NR_fstatat64 293
++#define __NR_unlinkat 294
++#define __NR_renameat 295
++#define __NR_linkat 296
++#define __NR_symlinkat 297
++#define __NR_readlinkat 298
++#define __NR_fchmodat 299
++#define __NR_faccessat 300
++#define __NR_pselect6 301
++#define __NR_ppoll 302
++#define __NR_unshare 303
++#define __NR_set_robust_list 304
++#define __NR_get_robust_list 305
++#define __NR_splice 306
++#define __NR_sync_file_range 307
++#define __NR_tee 308
++#define __NR_vmsplice 309
++#define __NR_move_pages 310
+
+ #ifdef __KERNEL__
+
+-#define NR_syscalls 282
++#define NR_syscalls 311
++#include <linux/err.h>
+
+-/* user-visible error numbers are in the range -1 - -124: see
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
+ <asm-m68k/errno.h> */
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ /* avoid using res which is declared to be in register d0; \
+ errno might expand to a function call and clobber it. */ \
+ int __err = -(res); \
+@@ -408,12 +438,6 @@ __syscall_return(type,__res); \
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-m68k/user.h b/include/asm-m68k/user.h
+index e8d5a64..d7c0b10 100644
+--- a/include/asm-m68k/user.h
++++ b/include/asm-m68k/user.h
+@@ -81,7 +81,7 @@ struct user{
+ unsigned long magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+ };
+-#define NBPG PAGE_SIZE
++#define NBPG 4096
+ #define UPAGES 1
+ #define HOST_TEXT_START_ADDR (u.start_code)
+ #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+diff --git a/include/asm-m68knommu/page.h b/include/asm-m68knommu/page.h
+index a22bf5a..2a1b8bd 100644
+--- a/include/asm-m68knommu/page.h
++++ b/include/asm-m68knommu/page.h
+@@ -1,6 +1,7 @@
+ #ifndef _M68KNOMMU_PAGE_H
+ #define _M68KNOMMU_PAGE_H
+
++#ifdef __KERNEL__
+
+ /* PAGE_SHIFT determines the page size */
+
+@@ -8,8 +9,6 @@
+ #define PAGE_SIZE (1UL << PAGE_SHIFT)
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+
+-#ifdef __KERNEL__
+-
+ #include <asm/setup.h>
+
+ #ifndef __ASSEMBLY__
+@@ -76,8 +75,8 @@ extern unsigned long memory_end;
+
+ #endif /* __ASSEMBLY__ */
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/page.h>
+
++#endif /* __KERNEL__ */
++
+ #endif /* _M68KNOMMU_PAGE_H */
+diff --git a/include/asm-m68knommu/processor.h b/include/asm-m68knommu/processor.h
+index 9d3a1bf..91cba18 100644
+--- a/include/asm-m68knommu/processor.h
++++ b/include/asm-m68knommu/processor.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-m68k/processor.h
++ * include/asm-m68knommu/processor.h
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h
+index 1b2abdf..ebaf031 100644
+--- a/include/asm-m68knommu/unistd.h
++++ b/include/asm-m68knommu/unistd.h
+@@ -281,21 +281,51 @@
+ #define __NR_mq_notify 275
+ #define __NR_mq_getsetattr 276
+ #define __NR_waitid 277
+-#define __NR_sys_setaltroot 278
++#define __NR_vserver 278
+ #define __NR_add_key 279
+ #define __NR_request_key 280
+ #define __NR_keyctl 281
+-
++#define __NR_ioprio_set 282
++#define __NR_ioprio_get 283
++#define __NR_inotify_init 284
++#define __NR_inotify_add_watch 285
++#define __NR_inotify_rm_watch 286
++#define __NR_migrate_pages 287
++#define __NR_openat 288
++#define __NR_mkdirat 289
++#define __NR_mknodat 290
++#define __NR_fchownat 291
++#define __NR_futimesat 292
++#define __NR_fstatat64 293
++#define __NR_unlinkat 294
++#define __NR_renameat 295
++#define __NR_linkat 296
++#define __NR_symlinkat 297
++#define __NR_readlinkat 298
++#define __NR_fchmodat 299
++#define __NR_faccessat 300
++#define __NR_pselect6 301
++#define __NR_ppoll 302
++#define __NR_unshare 303
++#define __NR_set_robust_list 304
++#define __NR_get_robust_list 305
++#define __NR_splice 306
++#define __NR_sync_file_range 307
++#define __NR_tee 308
++#define __NR_vmsplice 309
++#define __NR_move_pages 310
++
+ #ifdef __KERNEL__
+
+-#define NR_syscalls 282
++#define NR_syscalls 311
++#include <linux/err.h>
+
+-/* user-visible error numbers are in the range -1 - -122: see
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
+ <asm-m68k/errno.h> */
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ /* avoid using res which is declared to be in register d0; \
+ errno might expand to a function call and clobber it. */ \
+ int __err = -(res); \
+@@ -462,61 +492,6 @@ type name(atype a, btype b, ctype c, dty
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/interrupt.h>
+-#include <linux/types.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static inline _syscall0(int,pause)
+-static inline _syscall0(int,sync)
+-static inline _syscall0(pid_t,setsid)
+-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static inline _syscall1(int,dup,int,fd)
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+-static inline _syscall1(int,close,int,fd)
+-static inline _syscall1(int,_exit,int,exitcode)
+-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-static inline _syscall1(int,delete_module,const char *,name)
+-
+-static inline pid_t wait(int * wait_stat)
+-{
+- return waitpid(-1,wait_stat,0);
+-}
+-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(char *name, char **argv, char **envp);
+-asmlinkage int sys_pipe(unsigned long *fildes);
+-struct pt_regs;
+-int sys_request_irq(unsigned int,
+- irqreturn_t (*)(int, void *, struct pt_regs *),
+- unsigned long, const char *, void *);
+-void sys_free_irq(unsigned int, void *);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-mips/Kbuild b/include/asm-mips/Kbuild
+index c68e168..7897f05 100644
+--- a/include/asm-mips/Kbuild
++++ b/include/asm-mips/Kbuild
+@@ -1 +1,3 @@
+ include include/asm-generic/Kbuild.asm
++
++header-y += cachectl.h sgidefs.h sysmips.h
+diff --git a/include/asm-mips/asm.h b/include/asm-mips/asm.h
+index e3038a4..838eb31 100644
+--- a/include/asm-mips/asm.h
++++ b/include/asm-mips/asm.h
+@@ -344,6 +344,7 @@ symbol = value
+ #define PTR_L lw
+ #define PTR_S sw
+ #define PTR_LA la
++#define PTR_LI li
+ #define PTR_SLL sll
+ #define PTR_SLLV sllv
+ #define PTR_SRL srl
+@@ -368,6 +369,7 @@ symbol = value
+ #define PTR_L ld
+ #define PTR_S sd
+ #define PTR_LA dla
++#define PTR_LI dli
+ #define PTR_SLL dsll
+ #define PTR_SLLV dsllv
+ #define PTR_SRL dsrl
+diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
+index 3b745e7..1e5ccda 100644
+--- a/include/asm-mips/bootinfo.h
++++ b/include/asm-mips/bootinfo.h
+@@ -112,8 +112,7 @@
+ * Valid machtype for group GALILEO
+ */
+ #define MACH_GROUP_GALILEO 11 /* Galileo Eval Boards */
+-#define MACH_EV96100 0 /* EV96100 */
+-#define MACH_EV64120A 1 /* EV64120A */
++#define MACH_EV64120A 0 /* EV64120A */
+
+ /*
+ * Valid machtype for group MOMENCO
+@@ -126,12 +125,6 @@
+ #define MACH_MOMENCO_OCELOT_3 4
+
+ /*
+- * Valid machtype for group ITE
+- */
+-#define MACH_GROUP_ITE 13 /* ITE Semi Eval Boards */
+-#define MACH_QED_4N_S01B 0 /* ITE8172 based eval board */
+-
+-/*
+ * Valid machtype for group PHILIPS
+ */
+ #define MACH_GROUP_PHILIPS 14
+@@ -140,12 +133,6 @@
+ #define MACH_PHILIPS_JBS 2 /* JBS */
+
+ /*
+- * Valid machtype for group Globespan
+- */
+-#define MACH_GROUP_GLOBESPAN 15 /* Globespan */
+-#define MACH_IVR 0 /* IVR eval board */
+-
+-/*
+ * Valid machtype for group SIBYTE
+ */
+ #define MACH_GROUP_SIBYTE 16 /* Sibyte / Broadcom */
+diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
+index 47bc8f6..e3c9925 100644
+--- a/include/asm-mips/cacheflush.h
++++ b/include/asm-mips/cacheflush.h
+@@ -21,7 +21,6 @@
+ * - flush_cache_range(vma, start, end) flushes a range of pages
+ * - flush_icache_range(start, end) flush a range of instructions
+ * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
+- * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache
+ *
+ * MIPS specific flush operations:
+ *
+@@ -39,7 +38,7 @@ extern void __flush_dcache_page(struct p
+
+ static inline void flush_dcache_page(struct page *page)
+ {
+- if (cpu_has_dc_aliases)
++ if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
+ __flush_dcache_page(page);
+
+ }
+@@ -47,30 +46,22 @@ static inline void flush_dcache_page(str
+ #define flush_dcache_mmap_lock(mapping) do { } while (0)
+ #define flush_dcache_mmap_unlock(mapping) do { } while (0)
+
+-extern void (*flush_icache_page)(struct vm_area_struct *vma,
+- struct page *page);
++static inline void flush_icache_page(struct vm_area_struct *vma,
++ struct page *page)
++{
++}
++
+ extern void (*flush_icache_range)(unsigned long start, unsigned long end);
+ #define flush_cache_vmap(start, end) flush_cache_all()
+ #define flush_cache_vunmap(start, end) flush_cache_all()
+
+-static inline void copy_to_user_page(struct vm_area_struct *vma,
++extern void copy_to_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr, void *dst, const void *src,
+- unsigned long len)
+-{
+- if (cpu_has_dc_aliases)
+- flush_cache_page(vma, vaddr, page_to_pfn(page));
+- memcpy(dst, src, len);
+- flush_icache_page(vma, page);
+-}
++ unsigned long len);
+
+-static inline void copy_from_user_page(struct vm_area_struct *vma,
++extern void copy_from_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr, void *dst, const void *src,
+- unsigned long len)
+-{
+- if (cpu_has_dc_aliases)
+- flush_cache_page(vma, vaddr, page_to_pfn(page));
+- memcpy(dst, src, len);
+-}
++ unsigned long len);
+
+ extern void (*flush_cache_sigtramp)(unsigned long addr);
+ extern void (*flush_icache_all)(void);
+diff --git a/include/asm-mips/dec/ecc.h b/include/asm-mips/dec/ecc.h
+index 19495a4..707ffdb 100644
+--- a/include/asm-mips/dec/ecc.h
++++ b/include/asm-mips/dec/ecc.h
+@@ -49,8 +49,7 @@ struct pt_regs;
+
+ extern void dec_ecc_be_init(void);
+ extern int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup);
+-extern irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++extern irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id);
+ #endif
+
+ #endif /* __ASM_MIPS_DEC_ECC_H */
+diff --git a/include/asm-mips/dec/kn01.h b/include/asm-mips/dec/kn01.h
+index eb522aa..28fa717 100644
+--- a/include/asm-mips/dec/kn01.h
++++ b/include/asm-mips/dec/kn01.h
+@@ -84,8 +84,7 @@ extern spinlock_t kn01_lock;
+
+ extern void dec_kn01_be_init(void);
+ extern int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup);
+-extern irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++extern irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id);
+ #endif
+
+ #endif /* __ASM_MIPS_DEC_KN01_H */
+diff --git a/include/asm-mips/dec/kn02xa.h b/include/asm-mips/dec/kn02xa.h
+index a25f3d7..b56b457 100644
+--- a/include/asm-mips/dec/kn02xa.h
++++ b/include/asm-mips/dec/kn02xa.h
+@@ -78,8 +78,7 @@ struct pt_regs;
+
+ extern void dec_kn02xa_be_init(void);
+ extern int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup);
+-extern irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++extern irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id);
+ #endif
+
+ #endif /* __ASM_MIPS_DEC_KN02XA_H */
+diff --git a/include/asm-mips/div64.h b/include/asm-mips/div64.h
+index 5f7dcf5..d107832 100644
+--- a/include/asm-mips/div64.h
++++ b/include/asm-mips/div64.h
+@@ -83,27 +83,6 @@
+ #if (_MIPS_SZLONG == 64)
+
+ /*
+- * Don't use this one in new code
+- */
+-#define do_div64_32(res, high, low, base) ({ \
+- unsigned int __quot, __mod; \
+- unsigned long __div; \
+- unsigned int __low, __high, __base; \
+- \
+- __high = (high); \
+- __low = (low); \
+- __div = __high; \
+- __div = __div << 32 | __low; \
+- __base = (base); \
+- \
+- __mod = __div % __base; \
+- __div = __div / __base; \
+- \
+- __quot = __div; \
+- (res) = __quot; \
+- __mod; })
+-
+-/*
+ * Hey, we're already 64-bit, no
+ * need to play games..
+ */
+diff --git a/include/asm-mips/fcntl.h b/include/asm-mips/fcntl.h
+index 787220e..00a50ec 100644
+--- a/include/asm-mips/fcntl.h
++++ b/include/asm-mips/fcntl.h
+@@ -25,8 +25,6 @@
+
+ #define F_SETOWN 24 /* for sockets. */
+ #define F_GETOWN 23 /* for sockets. */
+-#define F_SETSIG 10 /* for sockets. */
+-#define F_GETSIG 11 /* for sockets. */
+
+ #ifndef __mips64
+ #define F_GETLK64 33 /* using 'struct flock64' */
+diff --git a/include/asm-mips/fixmap.h b/include/asm-mips/fixmap.h
+index 6959bdb..02c8a13 100644
+--- a/include/asm-mips/fixmap.h
++++ b/include/asm-mips/fixmap.h
+@@ -45,8 +45,16 @@
+ * fix-mapped?
+ */
+ enum fixed_addresses {
++#define FIX_N_COLOURS 8
++ FIX_CMAP_BEGIN,
++#ifdef CONFIG_MIPS_MT_SMTC
++ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS),
++#else
++ FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
++#endif
+ #ifdef CONFIG_HIGHMEM
+- FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
++ /* reserved pte's for temporary kernel mappings */
++ FIX_KMAP_BEGIN = FIX_CMAP_END + 1,
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ #endif
+ __end_of_fixed_addresses
+@@ -70,9 +78,9 @@ extern void __set_fixmap (enum fixed_add
+ * at the top of mem..
+ */
+ #if defined(CONFIG_CPU_TX39XX) || defined(CONFIG_CPU_TX49XX)
+-#define FIXADDR_TOP (0xff000000UL - 0x2000)
++#define FIXADDR_TOP ((unsigned long)(long)(int)(0xff000000 - 0x20000))
+ #else
+-#define FIXADDR_TOP (0xffffe000UL)
++#define FIXADDR_TOP ((unsigned long)(long)(int)0xfffe0000)
+ #endif
+ #define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+ #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
+diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
+index 58c561a..efef843 100644
+--- a/include/asm-mips/fpu.h
++++ b/include/asm-mips/fpu.h
+@@ -134,9 +134,11 @@ static inline void restore_fp(struct tas
+
+ static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
+ {
+- if (cpu_has_fpu) {
+- if ((tsk == current) && __is_fpu_owner())
++ if (tsk == current) {
++ preempt_disable();
++ if (is_fpu_owner())
+ _save_fp(current);
++ preempt_enable();
+ }
+
+ return tsk->thread.fpu.fpr;
+diff --git a/include/asm-mips/galileo-boards/ev96100.h b/include/asm-mips/galileo-boards/ev96100.h
+deleted file mode 100644
+index 070dfd8..0000000
+--- a/include/asm-mips/galileo-boards/ev96100.h
++++ /dev/null
+@@ -1,55 +0,0 @@
+-/*
+- *
+- */
+-#ifndef _MIPS_EV96100_H
+-#define _MIPS_EV96100_H
+-
+-#include <asm/addrspace.h>
+-
+-/*
+- * GT64120 config space base address
+- */
+-#define GT64120_BASE (KSEG1ADDR(0x14000000))
+-#define MIPS_GT_BASE GT64120_BASE
+-
+-/*
+- * PCI Bus allocation
+- */
+-#define GT_PCI_MEM_BASE 0x12000000UL
+-#define GT_PCI_MEM_SIZE 0x02000000UL
+-#define GT_PCI_IO_BASE 0x10000000UL
+-#define GT_PCI_IO_SIZE 0x02000000UL
+-#define GT_ISA_IO_BASE PCI_IO_BASE
+-
+-/*
+- * Duart I/O ports.
+- */
+-#define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20)
+-#define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00)
+-
+-
+-/*
+- * EV96100 interrupt controller register base.
+- */
+-#define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000))
+-
+-/*
+- * EV96100 UART register base.
+- */
+-#define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR
+-#define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR
+-#define EV96100_BASE_BAUD ( 3686400 / 16 )
+-
+-
+-/*
+- * Because of an error/peculiarity in the Galileo chip, we need to swap the
+- * bytes when running bigendian.
+- */
+-#define __GT_READ(ofs) \
+- (*(volatile u32 *)(GT64120_BASE+(ofs)))
+-#define __GT_WRITE(ofs, data) \
+- do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0)
+-#define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs))
+-#define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data))
+-
+-#endif /* !(_MIPS_EV96100_H) */
+diff --git a/include/asm-mips/galileo-boards/ev96100int.h b/include/asm-mips/galileo-boards/ev96100int.h
+deleted file mode 100644
+index c58b16d..0000000
+--- a/include/asm-mips/galileo-boards/ev96100int.h
++++ /dev/null
+@@ -1,12 +0,0 @@
+-/*
+- *
+- */
+-#ifndef _MIPS_EV96100INT_H
+-#define _MIPS_EV96100INT_H
+-
+-#define EV96100INT_UART_0 6 /* IP 6 */
+-#define EV96100INT_TIMER 7 /* IP 7 */
+-
+-extern void ev96100int_init(void);
+-
+-#endif /* !(_MIPS_EV96100_H) */
+diff --git a/include/asm-mips/galileo-boards/gt96100.h b/include/asm-mips/galileo-boards/gt96100.h
+deleted file mode 100644
+index aabd1b6..0000000
+--- a/include/asm-mips/galileo-boards/gt96100.h
++++ /dev/null
+@@ -1,427 +0,0 @@
+-/*
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at mvista.com
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+- * for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+- *
+- * Register offsets of the MIPS GT96100 Advanced Communication Controller.
+- */
+-#ifndef _GT96100_H
+-#define _GT96100_H
+-
+-/*
+- * Galileo GT96100 internal register base.
+- */
+-#define MIPS_GT96100_BASE (KSEG1ADDR(0x14000000))
+-
+-#define GT96100_WRITE(ofs, data) \
+- *(volatile u32 *)(MIPS_GT96100_BASE+ofs) = cpu_to_le32(data)
+-#define GT96100_READ(ofs) \
+- le32_to_cpu(*(volatile u32 *)(MIPS_GT96100_BASE+ofs))
+-
+-#define GT96100_ETH_IO_SIZE 0x4000
+-
+-/************************************************************************
+- * Register offset addresses follow
+- ************************************************************************/
+-
+-/* CPU Interface Control Registers */
+-#define GT96100_CPU_INTERF_CONFIG 0x000000
+-
+-/* Ethernet Ports */
+-#define GT96100_ETH_PHY_ADDR_REG 0x080800
+-#define GT96100_ETH_SMI_REG 0x080810
+-/*
+- These are offsets to port 0 registers. Add GT96100_ETH_IO_SIZE to
+- get offsets to port 1 registers.
+-*/
+-#define GT96100_ETH_PORT_CONFIG 0x084800
+-#define GT96100_ETH_PORT_CONFIG_EXT 0x084808
+-#define GT96100_ETH_PORT_COMM 0x084810
+-#define GT96100_ETH_PORT_STATUS 0x084818
+-#define GT96100_ETH_SER_PARAM 0x084820
+-#define GT96100_ETH_HASH_TBL_PTR 0x084828
+-#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_L 0x084830
+-#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_H 0x084838
+-#define GT96100_ETH_SDMA_CONFIG 0x084840
+-#define GT96100_ETH_SDMA_COMM 0x084848
+-#define GT96100_ETH_INT_CAUSE 0x084850
+-#define GT96100_ETH_INT_MASK 0x084858
+-#define GT96100_ETH_1ST_RX_DESC_PTR0 0x084880
+-#define GT96100_ETH_1ST_RX_DESC_PTR1 0x084884
+-#define GT96100_ETH_1ST_RX_DESC_PTR2 0x084888
+-#define GT96100_ETH_1ST_RX_DESC_PTR3 0x08488C
+-#define GT96100_ETH_CURR_RX_DESC_PTR0 0x0848A0
+-#define GT96100_ETH_CURR_RX_DESC_PTR1 0x0848A4
+-#define GT96100_ETH_CURR_RX_DESC_PTR2 0x0848A8
+-#define GT96100_ETH_CURR_RX_DESC_PTR3 0x0848AC
+-#define GT96100_ETH_CURR_TX_DESC_PTR0 0x0848E0
+-#define GT96100_ETH_CURR_TX_DESC_PTR1 0x0848E4
+-#define GT96100_ETH_MIB_COUNT_BASE 0x085800
+-
+-/* SDMAs */
+-#define GT96100_SDMA_GROUP_CONFIG 0x101AF0
+-/* SDMA Group 0 */
+-#define GT96100_SDMA_G0_CHAN0_CONFIG 0x000900
+-#define GT96100_SDMA_G0_CHAN0_COMM 0x000908
+-#define GT96100_SDMA_G0_CHAN0_RX_DESC_BASE 0x008900
+-#define GT96100_SDMA_G0_CHAN0_CURR_RX_DESC_PTR 0x008910
+-#define GT96100_SDMA_G0_CHAN0_TX_DESC_BASE 0x00C900
+-#define GT96100_SDMA_G0_CHAN0_CURR_TX_DESC_PTR 0x00C910
+-#define GT96100_SDMA_G0_CHAN0_1ST_TX_DESC_PTR 0x00C914
+-#define GT96100_SDMA_G0_CHAN1_CONFIG 0x010900
+-#define GT96100_SDMA_G0_CHAN1_COMM 0x010908
+-#define GT96100_SDMA_G0_CHAN1_RX_DESC_BASE 0x018900
+-#define GT96100_SDMA_G0_CHAN1_CURR_RX_DESC_PTR 0x018910
+-#define GT96100_SDMA_G0_CHAN1_TX_DESC_BASE 0x01C900
+-#define GT96100_SDMA_G0_CHAN1_CURR_TX_DESC_PTR 0x01C910
+-#define GT96100_SDMA_G0_CHAN1_1ST_TX_DESC_PTR 0x01C914
+-#define GT96100_SDMA_G0_CHAN2_CONFIG 0x020900
+-#define GT96100_SDMA_G0_CHAN2_COMM 0x020908
+-#define GT96100_SDMA_G0_CHAN2_RX_DESC_BASE 0x028900
+-#define GT96100_SDMA_G0_CHAN2_CURR_RX_DESC_PTR 0x028910
+-#define GT96100_SDMA_G0_CHAN2_TX_DESC_BASE 0x02C900
+-#define GT96100_SDMA_G0_CHAN2_CURR_TX_DESC_PTR 0x02C910
+-#define GT96100_SDMA_G0_CHAN2_1ST_TX_DESC_PTR 0x02C914
+-#define GT96100_SDMA_G0_CHAN3_CONFIG 0x030900
+-#define GT96100_SDMA_G0_CHAN3_COMM 0x030908
+-#define GT96100_SDMA_G0_CHAN3_RX_DESC_BASE 0x038900
+-#define GT96100_SDMA_G0_CHAN3_CURR_RX_DESC_PTR 0x038910
+-#define GT96100_SDMA_G0_CHAN3_TX_DESC_BASE 0x03C900
+-#define GT96100_SDMA_G0_CHAN3_CURR_TX_DESC_PTR 0x03C910
+-#define GT96100_SDMA_G0_CHAN3_1ST_TX_DESC_PTR 0x03C914
+-#define GT96100_SDMA_G0_CHAN4_CONFIG 0x040900
+-#define GT96100_SDMA_G0_CHAN4_COMM 0x040908
+-#define GT96100_SDMA_G0_CHAN4_RX_DESC_BASE 0x048900
+-#define GT96100_SDMA_G0_CHAN4_CURR_RX_DESC_PTR 0x048910
+-#define GT96100_SDMA_G0_CHAN4_TX_DESC_BASE 0x04C900
+-#define GT96100_SDMA_G0_CHAN4_CURR_TX_DESC_PTR 0x04C910
+-#define GT96100_SDMA_G0_CHAN4_1ST_TX_DESC_PTR 0x04C914
+-#define GT96100_SDMA_G0_CHAN5_CONFIG 0x050900
+-#define GT96100_SDMA_G0_CHAN5_COMM 0x050908
+-#define GT96100_SDMA_G0_CHAN5_RX_DESC_BASE 0x058900
+-#define GT96100_SDMA_G0_CHAN5_CURR_RX_DESC_PTR 0x058910
+-#define GT96100_SDMA_G0_CHAN5_TX_DESC_BASE 0x05C900
+-#define GT96100_SDMA_G0_CHAN5_CURR_TX_DESC_PTR 0x05C910
+-#define GT96100_SDMA_G0_CHAN5_1ST_TX_DESC_PTR 0x05C914
+-#define GT96100_SDMA_G0_CHAN6_CONFIG 0x060900
+-#define GT96100_SDMA_G0_CHAN6_COMM 0x060908
+-#define GT96100_SDMA_G0_CHAN6_RX_DESC_BASE 0x068900
+-#define GT96100_SDMA_G0_CHAN6_CURR_RX_DESC_PTR 0x068910
+-#define GT96100_SDMA_G0_CHAN6_TX_DESC_BASE 0x06C900
+-#define GT96100_SDMA_G0_CHAN6_CURR_TX_DESC_PTR 0x06C910
+-#define GT96100_SDMA_G0_CHAN6_1ST_TX_DESC_PTR 0x06C914
+-#define GT96100_SDMA_G0_CHAN7_CONFIG 0x070900
+-#define GT96100_SDMA_G0_CHAN7_COMM 0x070908
+-#define GT96100_SDMA_G0_CHAN7_RX_DESC_BASE 0x078900
+-#define GT96100_SDMA_G0_CHAN7_CURR_RX_DESC_PTR 0x078910
+-#define GT96100_SDMA_G0_CHAN7_TX_DESC_BASE 0x07C900
+-#define GT96100_SDMA_G0_CHAN7_CURR_TX_DESC_PTR 0x07C910
+-#define GT96100_SDMA_G0_CHAN7_1ST_TX_DESC_PTR 0x07C914
+-/* SDMA Group 1 */
+-#define GT96100_SDMA_G1_CHAN0_CONFIG 0x100900
+-#define GT96100_SDMA_G1_CHAN0_COMM 0x100908
+-#define GT96100_SDMA_G1_CHAN0_RX_DESC_BASE 0x108900
+-#define GT96100_SDMA_G1_CHAN0_CURR_RX_DESC_PTR 0x108910
+-#define GT96100_SDMA_G1_CHAN0_TX_DESC_BASE 0x10C900
+-#define GT96100_SDMA_G1_CHAN0_CURR_TX_DESC_PTR 0x10C910
+-#define GT96100_SDMA_G1_CHAN0_1ST_TX_DESC_PTR 0x10C914
+-#define GT96100_SDMA_G1_CHAN1_CONFIG 0x110900
+-#define GT96100_SDMA_G1_CHAN1_COMM 0x110908
+-#define GT96100_SDMA_G1_CHAN1_RX_DESC_BASE 0x118900
+-#define GT96100_SDMA_G1_CHAN1_CURR_RX_DESC_PTR 0x118910
+-#define GT96100_SDMA_G1_CHAN1_TX_DESC_BASE 0x11C900
+-#define GT96100_SDMA_G1_CHAN1_CURR_TX_DESC_PTR 0x11C910
+-#define GT96100_SDMA_G1_CHAN1_1ST_TX_DESC_PTR 0x11C914
+-#define GT96100_SDMA_G1_CHAN2_CONFIG 0x120900
+-#define GT96100_SDMA_G1_CHAN2_COMM 0x120908
+-#define GT96100_SDMA_G1_CHAN2_RX_DESC_BASE 0x128900
+-#define GT96100_SDMA_G1_CHAN2_CURR_RX_DESC_PTR 0x128910
+-#define GT96100_SDMA_G1_CHAN2_TX_DESC_BASE 0x12C900
+-#define GT96100_SDMA_G1_CHAN2_CURR_TX_DESC_PTR 0x12C910
+-#define GT96100_SDMA_G1_CHAN2_1ST_TX_DESC_PTR 0x12C914
+-#define GT96100_SDMA_G1_CHAN3_CONFIG 0x130900
+-#define GT96100_SDMA_G1_CHAN3_COMM 0x130908
+-#define GT96100_SDMA_G1_CHAN3_RX_DESC_BASE 0x138900
+-#define GT96100_SDMA_G1_CHAN3_CURR_RX_DESC_PTR 0x138910
+-#define GT96100_SDMA_G1_CHAN3_TX_DESC_BASE 0x13C900
+-#define GT96100_SDMA_G1_CHAN3_CURR_TX_DESC_PTR 0x13C910
+-#define GT96100_SDMA_G1_CHAN3_1ST_TX_DESC_PTR 0x13C914
+-#define GT96100_SDMA_G1_CHAN4_CONFIG 0x140900
+-#define GT96100_SDMA_G1_CHAN4_COMM 0x140908
+-#define GT96100_SDMA_G1_CHAN4_RX_DESC_BASE 0x148900
+-#define GT96100_SDMA_G1_CHAN4_CURR_RX_DESC_PTR 0x148910
+-#define GT96100_SDMA_G1_CHAN4_TX_DESC_BASE 0x14C900
+-#define GT96100_SDMA_G1_CHAN4_CURR_TX_DESC_PTR 0x14C910
+-#define GT96100_SDMA_G1_CHAN4_1ST_TX_DESC_PTR 0x14C914
+-#define GT96100_SDMA_G1_CHAN5_CONFIG 0x150900
+-#define GT96100_SDMA_G1_CHAN5_COMM 0x150908
+-#define GT96100_SDMA_G1_CHAN5_RX_DESC_BASE 0x158900
+-#define GT96100_SDMA_G1_CHAN5_CURR_RX_DESC_PTR 0x158910
+-#define GT96100_SDMA_G1_CHAN5_TX_DESC_BASE 0x15C900
+-#define GT96100_SDMA_G1_CHAN5_CURR_TX_DESC_PTR 0x15C910
+-#define GT96100_SDMA_G1_CHAN5_1ST_TX_DESC_PTR 0x15C914
+-#define GT96100_SDMA_G1_CHAN6_CONFIG 0x160900
+-#define GT96100_SDMA_G1_CHAN6_COMM 0x160908
+-#define GT96100_SDMA_G1_CHAN6_RX_DESC_BASE 0x168900
+-#define GT96100_SDMA_G1_CHAN6_CURR_RX_DESC_PTR 0x168910
+-#define GT96100_SDMA_G1_CHAN6_TX_DESC_BASE 0x16C900
+-#define GT96100_SDMA_G1_CHAN6_CURR_TX_DESC_PTR 0x16C910
+-#define GT96100_SDMA_G1_CHAN6_1ST_TX_DESC_PTR 0x16C914
+-#define GT96100_SDMA_G1_CHAN7_CONFIG 0x170900
+-#define GT96100_SDMA_G1_CHAN7_COMM 0x170908
+-#define GT96100_SDMA_G1_CHAN7_RX_DESC_BASE 0x178900
+-#define GT96100_SDMA_G1_CHAN7_CURR_RX_DESC_PTR 0x178910
+-#define GT96100_SDMA_G1_CHAN7_TX_DESC_BASE 0x17C900
+-#define GT96100_SDMA_G1_CHAN7_CURR_TX_DESC_PTR 0x17C910
+-#define GT96100_SDMA_G1_CHAN7_1ST_TX_DESC_PTR 0x17C914
+-/* MPSCs */
+-#define GT96100_MPSC0_MAIN_CONFIG_LOW 0x000A00
+-#define GT96100_MPSC0_MAIN_CONFIG_HIGH 0x000A04
+-#define GT96100_MPSC0_PROTOCOL_CONFIG 0x000A08
+-#define GT96100_MPSC_CHAN0_REG1 0x000A0C
+-#define GT96100_MPSC_CHAN0_REG2 0x000A10
+-#define GT96100_MPSC_CHAN0_REG3 0x000A14
+-#define GT96100_MPSC_CHAN0_REG4 0x000A18
+-#define GT96100_MPSC_CHAN0_REG5 0x000A1C
+-#define GT96100_MPSC_CHAN0_REG6 0x000A20
+-#define GT96100_MPSC_CHAN0_REG7 0x000A24
+-#define GT96100_MPSC_CHAN0_REG8 0x000A28
+-#define GT96100_MPSC_CHAN0_REG9 0x000A2C
+-#define GT96100_MPSC_CHAN0_REG10 0x000A30
+-#define GT96100_MPSC_CHAN0_REG11 0x000A34
+-#define GT96100_MPSC1_MAIN_CONFIG_LOW 0x008A00
+-#define GT96100_MPSC1_MAIN_CONFIG_HIGH 0x008A04
+-#define GT96100_MPSC1_PROTOCOL_CONFIG 0x008A08
+-#define GT96100_MPSC_CHAN1_REG1 0x008A0C
+-#define GT96100_MPSC_CHAN1_REG2 0x008A10
+-#define GT96100_MPSC_CHAN1_REG3 0x008A14
+-#define GT96100_MPSC_CHAN1_REG4 0x008A18
+-#define GT96100_MPSC_CHAN1_REG5 0x008A1C
+-#define GT96100_MPSC_CHAN1_REG6 0x008A20
+-#define GT96100_MPSC_CHAN1_REG7 0x008A24
+-#define GT96100_MPSC_CHAN1_REG8 0x008A28
+-#define GT96100_MPSC_CHAN1_REG9 0x008A2C
+-#define GT96100_MPSC_CHAN1_REG10 0x008A30
+-#define GT96100_MPSC_CHAN1_REG11 0x008A34
+-#define GT96100_MPSC2_MAIN_CONFIG_LOW 0x010A00
+-#define GT96100_MPSC2_MAIN_CONFIG_HIGH 0x010A04
+-#define GT96100_MPSC2_PROTOCOL_CONFIG 0x010A08
+-#define GT96100_MPSC_CHAN2_REG1 0x010A0C
+-#define GT96100_MPSC_CHAN2_REG2 0x010A10
+-#define GT96100_MPSC_CHAN2_REG3 0x010A14
+-#define GT96100_MPSC_CHAN2_REG4 0x010A18
+-#define GT96100_MPSC_CHAN2_REG5 0x010A1C
+-#define GT96100_MPSC_CHAN2_REG6 0x010A20
+-#define GT96100_MPSC_CHAN2_REG7 0x010A24
+-#define GT96100_MPSC_CHAN2_REG8 0x010A28
+-#define GT96100_MPSC_CHAN2_REG9 0x010A2C
+-#define GT96100_MPSC_CHAN2_REG10 0x010A30
+-#define GT96100_MPSC_CHAN2_REG11 0x010A34
+-#define GT96100_MPSC3_MAIN_CONFIG_LOW 0x018A00
+-#define GT96100_MPSC3_MAIN_CONFIG_HIGH 0x018A04
+-#define GT96100_MPSC3_PROTOCOL_CONFIG 0x018A08
+-#define GT96100_MPSC_CHAN3_REG1 0x018A0C
+-#define GT96100_MPSC_CHAN3_REG2 0x018A10
+-#define GT96100_MPSC_CHAN3_REG3 0x018A14
+-#define GT96100_MPSC_CHAN3_REG4 0x018A18
+-#define GT96100_MPSC_CHAN3_REG5 0x018A1C
+-#define GT96100_MPSC_CHAN3_REG6 0x018A20
+-#define GT96100_MPSC_CHAN3_REG7 0x018A24
+-#define GT96100_MPSC_CHAN3_REG8 0x018A28
+-#define GT96100_MPSC_CHAN3_REG9 0x018A2C
+-#define GT96100_MPSC_CHAN3_REG10 0x018A30
+-#define GT96100_MPSC_CHAN3_REG11 0x018A34
+-#define GT96100_MPSC4_MAIN_CONFIG_LOW 0x020A00
+-#define GT96100_MPSC4_MAIN_CONFIG_HIGH 0x020A04
+-#define GT96100_MPSC4_PROTOCOL_CONFIG 0x020A08
+-#define GT96100_MPSC_CHAN4_REG1 0x020A0C
+-#define GT96100_MPSC_CHAN4_REG2 0x020A10
+-#define GT96100_MPSC_CHAN4_REG3 0x020A14
+-#define GT96100_MPSC_CHAN4_REG4 0x020A18
+-#define GT96100_MPSC_CHAN4_REG5 0x020A1C
+-#define GT96100_MPSC_CHAN4_REG6 0x020A20
+-#define GT96100_MPSC_CHAN4_REG7 0x020A24
+-#define GT96100_MPSC_CHAN4_REG8 0x020A28
+-#define GT96100_MPSC_CHAN4_REG9 0x020A2C
+-#define GT96100_MPSC_CHAN4_REG10 0x020A30
+-#define GT96100_MPSC_CHAN4_REG11 0x020A34
+-#define GT96100_MPSC5_MAIN_CONFIG_LOW 0x028A00
+-#define GT96100_MPSC5_MAIN_CONFIG_HIGH 0x028A04
+-#define GT96100_MPSC5_PROTOCOL_CONFIG 0x028A08
+-#define GT96100_MPSC_CHAN5_REG1 0x028A0C
+-#define GT96100_MPSC_CHAN5_REG2 0x028A10
+-#define GT96100_MPSC_CHAN5_REG3 0x028A14
+-#define GT96100_MPSC_CHAN5_REG4 0x028A18
+-#define GT96100_MPSC_CHAN5_REG5 0x028A1C
+-#define GT96100_MPSC_CHAN5_REG6 0x028A20
+-#define GT96100_MPSC_CHAN5_REG7 0x028A24
+-#define GT96100_MPSC_CHAN5_REG8 0x028A28
+-#define GT96100_MPSC_CHAN5_REG9 0x028A2C
+-#define GT96100_MPSC_CHAN5_REG10 0x028A30
+-#define GT96100_MPSC_CHAN5_REG11 0x028A34
+-#define GT96100_MPSC6_MAIN_CONFIG_LOW 0x030A00
+-#define GT96100_MPSC6_MAIN_CONFIG_HIGH 0x030A04
+-#define GT96100_MPSC6_PROTOCOL_CONFIG 0x030A08
+-#define GT96100_MPSC_CHAN6_REG1 0x030A0C
+-#define GT96100_MPSC_CHAN6_REG2 0x030A10
+-#define GT96100_MPSC_CHAN6_REG3 0x030A14
+-#define GT96100_MPSC_CHAN6_REG4 0x030A18
+-#define GT96100_MPSC_CHAN6_REG5 0x030A1C
+-#define GT96100_MPSC_CHAN6_REG6 0x030A20
+-#define GT96100_MPSC_CHAN6_REG7 0x030A24
+-#define GT96100_MPSC_CHAN6_REG8 0x030A28
+-#define GT96100_MPSC_CHAN6_REG9 0x030A2C
+-#define GT96100_MPSC_CHAN6_REG10 0x030A30
+-#define GT96100_MPSC_CHAN6_REG11 0x030A34
+-#define GT96100_MPSC7_MAIN_CONFIG_LOW 0x038A00
+-#define GT96100_MPSC7_MAIN_CONFIG_HIGH 0x038A04
+-#define GT96100_MPSC7_PROTOCOL_CONFIG 0x038A08
+-#define GT96100_MPSC_CHAN7_REG1 0x038A0C
+-#define GT96100_MPSC_CHAN7_REG2 0x038A10
+-#define GT96100_MPSC_CHAN7_REG3 0x038A14
+-#define GT96100_MPSC_CHAN7_REG4 0x038A18
+-#define GT96100_MPSC_CHAN7_REG5 0x038A1C
+-#define GT96100_MPSC_CHAN7_REG6 0x038A20
+-#define GT96100_MPSC_CHAN7_REG7 0x038A24
+-#define GT96100_MPSC_CHAN7_REG8 0x038A28
+-#define GT96100_MPSC_CHAN7_REG9 0x038A2C
+-#define GT96100_MPSC_CHAN7_REG10 0x038A30
+-#define GT96100_MPSC_CHAN7_REG11 0x038A34
+-/* FlexTDMs */
+-/* TDPR0 - Transmit Dual Port RAM. block size 0xff */
+-#define GT96100_FXTDM0_TDPR0_BLK0_BASE 0x000B00
+-#define GT96100_FXTDM0_TDPR0_BLK1_BASE 0x001B00
+-#define GT96100_FXTDM0_TDPR0_BLK2_BASE 0x002B00
+-#define GT96100_FXTDM0_TDPR0_BLK3_BASE 0x003B00
+-/* RDPR0 - Receive Dual Port RAM. block size 0xff */
+-#define GT96100_FXTDM0_RDPR0_BLK0_BASE 0x004B00
+-#define GT96100_FXTDM0_RDPR0_BLK1_BASE 0x005B00
+-#define GT96100_FXTDM0_RDPR0_BLK2_BASE 0x006B00
+-#define GT96100_FXTDM0_RDPR0_BLK3_BASE 0x007B00
+-#define GT96100_FXTDM0_TX_READ_PTR 0x008B00
+-#define GT96100_FXTDM0_RX_READ_PTR 0x008B04
+-#define GT96100_FXTDM0_CONFIG 0x008B08
+-#define GT96100_FXTDM0_AUX_CHANA_TX 0x008B0C
+-#define GT96100_FXTDM0_AUX_CHANA_RX 0x008B10
+-#define GT96100_FXTDM0_AUX_CHANB_TX 0x008B14
+-#define GT96100_FXTDM0_AUX_CHANB_RX 0x008B18
+-#define GT96100_FXTDM1_TDPR1_BLK0_BASE 0x010B00
+-#define GT96100_FXTDM1_TDPR1_BLK1_BASE 0x011B00
+-#define GT96100_FXTDM1_TDPR1_BLK2_BASE 0x012B00
+-#define GT96100_FXTDM1_TDPR1_BLK3_BASE 0x013B00
+-#define GT96100_FXTDM1_RDPR1_BLK0_BASE 0x014B00
+-#define GT96100_FXTDM1_RDPR1_BLK1_BASE 0x015B00
+-#define GT96100_FXTDM1_RDPR1_BLK2_BASE 0x016B00
+-#define GT96100_FXTDM1_RDPR1_BLK3_BASE 0x017B00
+-#define GT96100_FXTDM1_TX_READ_PTR 0x018B00
+-#define GT96100_FXTDM1_RX_READ_PTR 0x018B04
+-#define GT96100_FXTDM1_CONFIG 0x018B08
+-#define GT96100_FXTDM1_AUX_CHANA_TX 0x018B0C
+-#define GT96100_FXTDM1_AUX_CHANA_RX 0x018B10
+-#define GT96100_FLTDM1_AUX_CHANB_TX 0x018B14
+-#define GT96100_FLTDM1_AUX_CHANB_RX 0x018B18
+-#define GT96100_FLTDM2_TDPR2_BLK0_BASE 0x020B00
+-#define GT96100_FLTDM2_TDPR2_BLK1_BASE 0x021B00
+-#define GT96100_FLTDM2_TDPR2_BLK2_BASE 0x022B00
+-#define GT96100_FLTDM2_TDPR2_BLK3_BASE 0x023B00
+-#define GT96100_FLTDM2_RDPR2_BLK0_BASE 0x024B00
+-#define GT96100_FLTDM2_RDPR2_BLK1_BASE 0x025B00
+-#define GT96100_FLTDM2_RDPR2_BLK2_BASE 0x026B00
+-#define GT96100_FLTDM2_RDPR2_BLK3_BASE 0x027B00
+-#define GT96100_FLTDM2_TX_READ_PTR 0x028B00
+-#define GT96100_FLTDM2_RX_READ_PTR 0x028B04
+-#define GT96100_FLTDM2_CONFIG 0x028B08
+-#define GT96100_FLTDM2_AUX_CHANA_TX 0x028B0C
+-#define GT96100_FLTDM2_AUX_CHANA_RX 0x028B10
+-#define GT96100_FLTDM2_AUX_CHANB_TX 0x028B14
+-#define GT96100_FLTDM2_AUX_CHANB_RX 0x028B18
+-#define GT96100_FLTDM3_TDPR3_BLK0_BASE 0x030B00
+-#define GT96100_FLTDM3_TDPR3_BLK1_BASE 0x031B00
+-#define GT96100_FLTDM3_TDPR3_BLK2_BASE 0x032B00
+-#define GT96100_FLTDM3_TDPR3_BLK3_BASE 0x033B00
+-#define GT96100_FXTDM3_RDPR3_BLK0_BASE 0x034B00
+-#define GT96100_FXTDM3_RDPR3_BLK1_BASE 0x035B00
+-#define GT96100_FXTDM3_RDPR3_BLK2_BASE 0x036B00
+-#define GT96100_FXTDM3_RDPR3_BLK3_BASE 0x037B00
+-#define GT96100_FXTDM3_TX_READ_PTR 0x038B00
+-#define GT96100_FXTDM3_RX_READ_PTR 0x038B04
+-#define GT96100_FXTDM3_CONFIG 0x038B08
+-#define GT96100_FXTDM3_AUX_CHANA_TX 0x038B0C
+-#define GT96100_FXTDM3_AUX_CHANA_RX 0x038B10
+-#define GT96100_FXTDM3_AUX_CHANB_TX 0x038B14
+-#define GT96100_FXTDM3_AUX_CHANB_RX 0x038B18
+-/* Baud Rate Generators */
+-#define GT96100_BRG0_CONFIG 0x102A00
+-#define GT96100_BRG0_BAUD_TUNE 0x102A04
+-#define GT96100_BRG1_CONFIG 0x102A08
+-#define GT96100_BRG1_BAUD_TUNE 0x102A0C
+-#define GT96100_BRG2_CONFIG 0x102A10
+-#define GT96100_BRG2_BAUD_TUNE 0x102A14
+-#define GT96100_BRG3_CONFIG 0x102A18
+-#define GT96100_BRG3_BAUD_TUNE 0x102A1C
+-#define GT96100_BRG4_CONFIG 0x102A20
+-#define GT96100_BRG4_BAUD_TUNE 0x102A24
+-#define GT96100_BRG5_CONFIG 0x102A28
+-#define GT96100_BRG5_BAUD_TUNE 0x102A2C
+-#define GT96100_BRG6_CONFIG 0x102A30
+-#define GT96100_BRG6_BAUD_TUNE 0x102A34
+-#define GT96100_BRG7_CONFIG 0x102A38
+-#define GT96100_BRG7_BAUD_TUNE 0x102A3C
+-/* Routing Registers */
+-#define GT96100_ROUTE_MAIN 0x101A00
+-#define GT96100_ROUTE_RX_CLOCK 0x101A10
+-#define GT96100_ROUTE_TX_CLOCK 0x101A20
+-/* General Purpose Ports */
+-#define GT96100_GPP_CONFIG0 0x100A00
+-#define GT96100_GPP_CONFIG1 0x100A04
+-#define GT96100_GPP_CONFIG2 0x100A08
+-#define GT96100_GPP_CONFIG3 0x100A0C
+-#define GT96100_GPP_IO0 0x100A20
+-#define GT96100_GPP_IO1 0x100A24
+-#define GT96100_GPP_IO2 0x100A28
+-#define GT96100_GPP_IO3 0x100A2C
+-#define GT96100_GPP_DATA0 0x100A40
+-#define GT96100_GPP_DATA1 0x100A44
+-#define GT96100_GPP_DATA2 0x100A48
+-#define GT96100_GPP_DATA3 0x100A4C
+-#define GT96100_GPP_LEVEL0 0x100A60
+-#define GT96100_GPP_LEVEL1 0x100A64
+-#define GT96100_GPP_LEVEL2 0x100A68
+-#define GT96100_GPP_LEVEL3 0x100A6C
+-/* Watchdog */
+-#define GT96100_WD_CONFIG 0x101A80
+-#define GT96100_WD_VALUE 0x101A84
+-/* Communication Unit Arbiter */
+-#define GT96100_COMM_UNIT_ARBTR_CONFIG 0x101AC0
+-/* PCI Arbiters */
+-#define GT96100_PCI0_ARBTR_CONFIG 0x101AE0
+-#define GT96100_PCI1_ARBTR_CONFIG 0x101AE4
+-/* CIU Arbiter */
+-#define GT96100_CIU_ARBITER_CONFIG 0x101AC0
+-/* Interrupt Controller */
+-#define GT96100_MAIN_CAUSE 0x000C18
+-#define GT96100_INT0_MAIN_MASK 0x000C1C
+-#define GT96100_INT1_MAIN_MASK 0x000C24
+-#define GT96100_HIGH_CAUSE 0x000C98
+-#define GT96100_INT0_HIGH_MASK 0x000C9C
+-#define GT96100_INT1_HIGH_MASK 0x000CA4
+-#define GT96100_INT0_SELECT 0x000C70
+-#define GT96100_INT1_SELECT 0x000C74
+-#define GT96100_SERIAL_CAUSE 0x103A00
+-#define GT96100_SERINT0_MASK 0x103A80
+-#define GT96100_SERINT1_MASK 0x103A88
+-
+-#endif /* _GT96100_H */
+diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h
+index 25f5e8a..0fe0294 100644
+--- a/include/asm-mips/hazards.h
++++ b/include/asm-mips/hazards.h
+@@ -12,102 +12,95 @@
+
+
+ #ifdef __ASSEMBLY__
+-
+- .macro _ssnop
+- sll $0, $0, 1
+- .endm
+-
+- .macro _ehb
+- sll $0, $0, 3
+- .endm
+-
+-/*
+- * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
+- * use of the JTLB for instructions should not occur for 4 cpu cycles and use
+- * for data translations should not occur for 3 cpu cycles.
+- */
+-#ifdef CONFIG_CPU_RM9000
+-
+- .macro mtc0_tlbw_hazard
+- .set push
+- .set mips32
+- _ssnop; _ssnop; _ssnop; _ssnop
+- .set pop
+- .endm
+-
+- .macro tlbw_eret_hazard
+- .set push
+- .set mips32
+- _ssnop; _ssnop; _ssnop; _ssnop
+- .set pop
+- .endm
+-
++#define ASMMACRO(name, code...) .macro name; code; .endm
+ #else
+
+-/*
+- * The taken branch will result in a two cycle penalty for the two killed
+- * instructions on R4000 / R4400. Other processors only have a single cycle
+- * hazard so this is nice trick to have an optimal code for a range of
+- * processors.
+- */
+- .macro mtc0_tlbw_hazard
+- b . + 8
+- .endm
++#define ASMMACRO(name, code...) \
++__asm__(".macro " #name "; " #code "; .endm"); \
++ \
++static inline void name(void) \
++{ \
++ __asm__ __volatile__ (#name); \
++}
+
+- .macro tlbw_eret_hazard
+- .endm
+ #endif
+
++ASMMACRO(_ssnop,
++ sll $0, $0, 1
++ )
++
++ASMMACRO(_ehb,
++ sll $0, $0, 3
++ )
++
+ /*
+- * mtc0->mfc0 hazard
+- * The 24K has a 2 cycle mtc0/mfc0 execution hazard.
+- * It is a MIPS32R2 processor so ehb will clear the hazard.
++ * TLB hazards
+ */
++#if defined(CONFIG_CPU_MIPSR2)
+
+-#ifdef CONFIG_CPU_MIPSR2
+ /*
+- * Use a macro for ehb unless explicit support for MIPSR2 is enabled
++ * MIPSR2 defines ehb for hazard avoidance
+ */
+
+-#define irq_enable_hazard \
++ASMMACRO(mtc0_tlbw_hazard,
++ _ehb
++ )
++ASMMACRO(tlbw_use_hazard,
++ _ehb
++ )
++ASMMACRO(tlb_probe_hazard,
++ _ehb
++ )
++ASMMACRO(irq_enable_hazard,
++ )
++ASMMACRO(irq_disable_hazard,
+ _ehb
+-
+-#define irq_disable_hazard \
+- _ehb
+-
+-#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
+-
++ )
++ASMMACRO(back_to_back_c0_hazard,
++ _ehb
++ )
+ /*
+- * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
++ * gcc has a tradition of misscompiling the previous construct using the
++ * address of a label as argument to inline assembler. Gas otoh has the
++ * annoying difference between la and dla which are only usable for 32-bit
++ * rsp. 64-bit code, so can't be used without conditional compilation.
++ * The alterantive is switching the assembler to 64-bit code which happens
++ * to work right even for 32-bit code ...
+ */
++#define instruction_hazard() \
++do { \
++ unsigned long tmp; \
++ \
++ __asm__ __volatile__( \
++ " .set mips64r2 \n" \
++ " dla %0, 1f \n" \
++ " jr.hb %0 \n" \
++ " .set mips0 \n" \
++ "1: \n" \
++ : "=r" (tmp)); \
++} while (0)
+
+-#define irq_enable_hazard
+-
+-#define irq_disable_hazard
+-
+-#else
++#elif defined(CONFIG_CPU_R10000)
+
+ /*
+- * Classic MIPS needs 1 - 3 nops or ssnops
++ * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
+ */
+-#define irq_enable_hazard
+-#define irq_disable_hazard \
+- _ssnop; _ssnop; _ssnop
+
+-#endif
+-
+-#else /* __ASSEMBLY__ */
+-
+-__asm__(
+- " .macro _ssnop \n"
+- " sll $0, $0, 1 \n"
+- " .endm \n"
+- " \n"
+- " .macro _ehb \n"
+- " sll $0, $0, 3 \n"
+- " .endm \n");
++ASMMACRO(mtc0_tlbw_hazard,
++ )
++ASMMACRO(tlbw_use_hazard,
++ )
++ASMMACRO(tlb_probe_hazard,
++ )
++ASMMACRO(irq_enable_hazard,
++ )
++ASMMACRO(irq_disable_hazard,
++ )
++ASMMACRO(back_to_back_c0_hazard,
++ )
++#define instruction_hazard() do { } while (0)
+
+-#ifdef CONFIG_CPU_RM9000
++#elif defined(CONFIG_CPU_RM9000)
+
+ /*
+ * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
+@@ -115,176 +108,73 @@ __asm__(
+ * for data translations should not occur for 3 cpu cycles.
+ */
+
+-#define mtc0_tlbw_hazard() \
+- __asm__ __volatile__( \
+- " .set mips32 \n" \
+- " _ssnop \n" \
+- " _ssnop \n" \
+- " _ssnop \n" \
+- " _ssnop \n" \
+- " .set mips0 \n")
+-
+-#define tlbw_use_hazard() \
+- __asm__ __volatile__( \
+- " .set mips32 \n" \
+- " _ssnop \n" \
+- " _ssnop \n" \
+- " _ssnop \n" \
+- " _ssnop \n" \
+- " .set mips0 \n")
+-
+-#else
+-
+-/*
+- * Overkill warning ...
+- */
+-#define mtc0_tlbw_hazard() \
+- __asm__ __volatile__( \
+- " .set noreorder \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " .set reorder \n")
+-
+-#define tlbw_use_hazard() \
+- __asm__ __volatile__( \
+- " .set noreorder \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " nop \n" \
+- " .set reorder \n")
+-
+-#endif
+-
+-/*
+- * Interrupt enable/disable hazards
+- * Some processors have hazards when modifying
+- * the status register to change the interrupt state
+- */
+-
+-#ifdef CONFIG_CPU_MIPSR2
+-
+-__asm__(" .macro irq_enable_hazard \n"
+- " _ehb \n"
+- " .endm \n"
+- " \n"
+- " .macro irq_disable_hazard \n"
+- " _ehb \n"
+- " .endm \n");
++ASMMACRO(mtc0_tlbw_hazard,
++ _ssnop; _ssnop; _ssnop; _ssnop
++ )
++ASMMACRO(tlbw_use_hazard,
++ _ssnop; _ssnop; _ssnop; _ssnop
++ )
++ASMMACRO(tlb_probe_hazard,
++ _ssnop; _ssnop; _ssnop; _ssnop
++ )
++ASMMACRO(irq_enable_hazard,
++ )
++ASMMACRO(irq_disable_hazard,
++ )
++ASMMACRO(back_to_back_c0_hazard,
++ )
++#define instruction_hazard() do { } while (0)
+
+-#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
++#elif defined(CONFIG_CPU_SB1)
+
+ /*
+- * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
++ * Mostly like R4000 for historic reasons
+ */
+-
+-__asm__(
+- " .macro irq_enable_hazard \n"
+- " .endm \n"
+- " \n"
+- " .macro irq_disable_hazard \n"
+- " .endm \n");
++ASMMACRO(mtc0_tlbw_hazard,
++ )
++ASMMACRO(tlbw_use_hazard,
++ )
++ASMMACRO(tlb_probe_hazard,
++ )
++ASMMACRO(irq_enable_hazard,
++ )
++ASMMACRO(irq_disable_hazard,
++ _ssnop; _ssnop; _ssnop
++ )
++ASMMACRO(back_to_back_c0_hazard,
++ )
++#define instruction_hazard() do { } while (0)
+
+ #else
+
+ /*
+- * Default for classic MIPS processors. Assume worst case hazards but don't
+- * care about the irq_enable_hazard - sooner or later the hardware will
+- * enable it and we don't care when exactly.
+- */
+-
+-__asm__(
+- " # \n"
+- " # There is a hazard but we do not care \n"
+- " # \n"
+- " .macro\tirq_enable_hazard \n"
+- " .endm \n"
+- " \n"
+- " .macro\tirq_disable_hazard \n"
+- " _ssnop \n"
+- " _ssnop \n"
+- " _ssnop \n"
+- " .endm \n");
+-
+-#endif
+-
+-#define irq_enable_hazard() \
+- __asm__ __volatile__("irq_enable_hazard")
+-#define irq_disable_hazard() \
+- __asm__ __volatile__("irq_disable_hazard")
+-
+-
+-/*
+- * Back-to-back hazards -
++ * Finally the catchall case for all other processors including R4000, R4400,
++ * R4600, R4700, R5000, RM7000, NEC VR41xx etc.
+ *
+- * What is needed to separate a move to cp0 from a subsequent read from the
+- * same cp0 register?
+- */
+-#ifdef CONFIG_CPU_MIPSR2
+-
+-__asm__(" .macro back_to_back_c0_hazard \n"
+- " _ehb \n"
+- " .endm \n");
+-
+-#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000) || \
+- defined(CONFIG_CPU_SB1)
+-
+-__asm__(" .macro back_to_back_c0_hazard \n"
+- " .endm \n");
+-
+-#else
+-
+-__asm__(" .macro back_to_back_c0_hazard \n"
+- " .set noreorder \n"
+- " _ssnop \n"
+- " _ssnop \n"
+- " _ssnop \n"
+- " .set reorder \n"
+- " .endm");
+-
+-#endif
+-
+-#define back_to_back_c0_hazard() \
+- __asm__ __volatile__("back_to_back_c0_hazard")
+-
+-
+-/*
+- * Instruction execution hazard
+- */
+-#ifdef CONFIG_CPU_MIPSR2
+-/*
+- * gcc has a tradition of misscompiling the previous construct using the
+- * address of a label as argument to inline assembler. Gas otoh has the
+- * annoying difference between la and dla which are only usable for 32-bit
+- * rsp. 64-bit code, so can't be used without conditional compilation.
+- * The alterantive is switching the assembler to 64-bit code which happens
+- * to work right even for 32-bit code ...
++ * The taken branch will result in a two cycle penalty for the two killed
++ * instructions on R4000 / R4400. Other processors only have a single cycle
++ * hazard so this is nice trick to have an optimal code for a range of
++ * processors.
+ */
+-#define instruction_hazard() \
+-do { \
+- unsigned long tmp; \
+- \
+- __asm__ __volatile__( \
+- " .set mips64r2 \n" \
+- " dla %0, 1f \n" \
+- " jr.hb %0 \n" \
+- " .set mips0 \n" \
+- "1: \n" \
+- : "=r" (tmp)); \
+-} while (0)
+-
+-#else
++ASMMACRO(mtc0_tlbw_hazard,
++ nop
++ )
++ASMMACRO(tlbw_use_hazard,
++ nop; nop; nop
++ )
++ASMMACRO(tlb_probe_hazard,
++ nop; nop; nop
++ )
++ASMMACRO(irq_enable_hazard,
++ )
++ASMMACRO(irq_disable_hazard,
++ nop; nop; nop
++ )
++ASMMACRO(back_to_back_c0_hazard,
++ _ssnop; _ssnop; _ssnop;
++ )
+ #define instruction_hazard() do { } while (0)
+-#endif
+-
+-extern void mips_ihb(void);
+
+-#endif /* __ASSEMBLY__ */
++#endif
+
+ #endif /* _ASM_HAZARDS_H */
+diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
+index df624e1..bc5f3c5 100644
+--- a/include/asm-mips/io.h
++++ b/include/asm-mips/io.h
+@@ -172,7 +172,7 @@ extern unsigned long isa_slot_offset;
+ #define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
+
+ extern void __iomem * __ioremap(phys_t offset, phys_t size, unsigned long flags);
+-extern void __iounmap(volatile void __iomem *addr);
++extern void __iounmap(const volatile void __iomem *addr);
+
+ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
+ unsigned long flags)
+@@ -279,7 +279,7 @@ static inline void __iomem * __ioremap_m
+ #define ioremap_uncached_accelerated(offset, size) \
+ __ioremap_mode((offset), (size), _CACHE_UNCACHED_ACCELERATED)
+
+-static inline void iounmap(volatile void __iomem *addr)
++static inline void iounmap(const volatile void __iomem *addr)
+ {
+ #define __IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1)
+
+@@ -562,32 +562,6 @@ extern void pci_iounmap(struct pci_dev *
+ #define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len))
+
+ /*
+- * check_signature - find BIOS signatures
+- * @io_addr: mmio address to check
+- * @signature: signature block
+- * @length: length of signature
+- *
+- * Perform a signature comparison with the mmio address io_addr. This
+- * address should have been obtained by ioremap.
+- * Returns 1 on a match.
+- */
+-static inline int check_signature(char __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+-/*
+ * The caches on some architectures aren't dma-coherent and have need to
+ * handle this in software. There are three types of operations that
+ * can be applied to dma buffers.
+diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h
+index 896550b..35a05ca 100644
+--- a/include/asm-mips/irq.h
++++ b/include/asm-mips/irq.h
+@@ -24,9 +24,7 @@ static inline int irq_canonicalize(int i
+ #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */
+ #endif
+
+-struct pt_regs;
+-
+-extern asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs);
++extern asmlinkage unsigned int do_IRQ(unsigned int irq);
+
+ #ifdef CONFIG_MIPS_MT_SMTC
+ /*
+@@ -55,18 +53,18 @@ do { \
+ * Ideally there should be away to get this into kernel/irq/handle.c to
+ * avoid the overhead of a call for just a tiny function ...
+ */
+-#define do_IRQ(irq, regs) \
++#define do_IRQ(irq) \
+ do { \
+ irq_enter(); \
+ __DO_IRQ_SMTC_HOOK(); \
+- __do_IRQ((irq), (regs)); \
++ __do_IRQ((irq)); \
+ irq_exit(); \
+ } while (0)
+
+ #endif
+
+ extern void arch_init_irq(void);
+-extern void spurious_interrupt(struct pt_regs *regs);
++extern void spurious_interrupt(void);
+
+ #ifdef CONFIG_MIPS_MT_SMTC
+ struct irqaction;
+@@ -76,8 +74,8 @@ extern int setup_irq_smtc(unsigned int i
+ unsigned long hwmask);
+ #endif /* CONFIG_MIPS_MT_SMTC */
+
+-#ifdef CONFIG_SMP
+-#define ARCH_HAS_IRQ_PER_CPU
+-#endif
++extern int allocate_irqno(void);
++extern void alloc_legacy_irqno(void);
++extern void free_irqno(unsigned int irq);
+
+ #endif /* _ASM_IRQ_H */
+diff --git a/include/asm-mips/irq_regs.h b/include/asm-mips/irq_regs.h
+new file mode 100644
+index 0000000..33bd2a0
+--- /dev/null
++++ b/include/asm-mips/irq_regs.h
+@@ -0,0 +1,21 @@
++/*
++ * 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) 2006 Ralf Baechle (ralf at linux-mips.org)
++ */
++#ifndef __ASM_IRQ_REGS_H
++#define __ASM_IRQ_REGS_H
++
++#define ARCH_HAS_OWN_IRQ_REGS
++
++#include <linux/thread_info.h>
++
++static inline struct pt_regs *get_irq_regs(void)
++{
++ return current_thread_info()->regs;
++}
++
++#endif /* __ASM_IRQ_REGS_H */
+diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h
+index 43ca09a..46bf5de 100644
+--- a/include/asm-mips/irqflags.h
++++ b/include/asm-mips/irqflags.h
+@@ -213,12 +213,37 @@ static inline int raw_irqs_disabled_flag
+ * Do the CPU's IRQ-state tracing from assembly code.
+ */
+ #ifdef CONFIG_TRACE_IRQFLAGS
++/* Reload some registers clobbered by trace_hardirqs_on */
++#ifdef CONFIG_64BIT
++# define TRACE_IRQS_RELOAD_REGS \
++ LONG_L $11, PT_R11(sp); \
++ LONG_L $10, PT_R10(sp); \
++ LONG_L $9, PT_R9(sp); \
++ LONG_L $8, PT_R8(sp); \
++ LONG_L $7, PT_R7(sp); \
++ LONG_L $6, PT_R6(sp); \
++ LONG_L $5, PT_R5(sp); \
++ LONG_L $4, PT_R4(sp); \
++ LONG_L $2, PT_R2(sp)
++#else
++# define TRACE_IRQS_RELOAD_REGS \
++ LONG_L $7, PT_R7(sp); \
++ LONG_L $6, PT_R6(sp); \
++ LONG_L $5, PT_R5(sp); \
++ LONG_L $4, PT_R4(sp); \
++ LONG_L $2, PT_R2(sp)
++#endif
+ # define TRACE_IRQS_ON \
++ CLI; /* make sure trace_hardirqs_on() is called in kernel level */ \
+ jal trace_hardirqs_on
++# define TRACE_IRQS_ON_RELOAD \
++ TRACE_IRQS_ON; \
++ TRACE_IRQS_RELOAD_REGS
+ # define TRACE_IRQS_OFF \
+ jal trace_hardirqs_off
+ #else
+ # define TRACE_IRQS_ON
++# define TRACE_IRQS_ON_RELOAD
+ # define TRACE_IRQS_OFF
+ #endif
+
+diff --git a/include/asm-mips/it8172/it8172.h b/include/asm-mips/it8172/it8172.h
+deleted file mode 100644
+index 8f23af0..0000000
+--- a/include/asm-mips/it8172/it8172.h
++++ /dev/null
+@@ -1,348 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * IT8172 system controller defines.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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.
+- */
+-
+-#ifndef __IT8172__H__
+-#define __IT8172__H__
+-
+-#include <asm/addrspace.h>
+-
+-#define IT8172_BASE 0x18000000
+-#define IT8172_PCI_IO_BASE 0x14000000
+-#define IT8172_PCI_MEM_BASE 0x10000000
+-
+-// System registers offsets from IT8172_BASE
+-#define IT_CMFPCR 0x0
+-#define IT_DSRR 0x2
+-#define IT_PCDCR 0x4
+-#define IT_SPLLCR 0x6
+-#define IT_CIDR 0x10
+-#define IT_CRNR 0x12
+-#define IT_CPUTR 0x14
+-#define IT_CTCR 0x16
+-#define IT_SDPR 0xF0
+-
+-// Power management register offset from IT8172_PCI_IO_BASE
+-// Power Management Device Standby Register
+-#define IT_PM_DSR 0x15800
+-
+-#define IT_PM_DSR_TMR0SB 0x0001
+-#define IT_PM_DSR_TMR1SB 0x0002
+-#define IT_PM_DSR_CIR0SB 0x0004
+-#define IT_PM_DSR_CIR1SB 0x0008
+-#define IT_PM_DSR_SCR0SB 0x0010
+-#define IT_PM_DSR_SCR1SB 0x0020
+-#define IT_PM_DSR_PPSB 0x0040
+-#define IT_PM_DSR_I2CSB 0x0080
+-#define IT_PM_DSR_UARTSB 0x0100
+-#define IT_PM_DSR_IDESB 0x0200
+-#define IT_PM_DSR_ACSB 0x0400
+-#define IT_PM_DSR_M68KSB 0x0800
+-
+-// Power Management PCI Device Software Reset Register
+-#define IT_PM_PCISR 0x15802
+-
+-#define IT_PM_PCISR_IDESR 0x0001
+-#define IT_PM_PCISR_CDMASR 0x0002
+-#define IT_PM_PCISR_USBSR 0x0004
+-#define IT_PM_PCISR_DMASR 0x0008
+-#define IT_PM_PCISR_ACSR 0x0010
+-#define IT_PM_PCISR_MEMSR 0x0020
+-#define IT_PM_PCISR_68KSR 0x0040
+-
+-
+-// PCI Configuration address and data register offsets
+-// from IT8172_BASE
+-#define IT_CONFADDR 0x4000
+-#define IT_BUSNUM_SHF 16
+-#define IT_DEVNUM_SHF 11
+-#define IT_FUNCNUM_SHF 8
+-#define IT_REGNUM_SHF 2
+-
+-#define IT_CONFDATA 0x4004
+-
+-// PCI configuration header common register offsets
+-#define IT_VID 0x00
+-#define IT_DID 0x02
+-#define IT_PCICMD 0x04
+-#define IT_PCISTS 0x06
+-#define IT_RID 0x08
+-#define IT_CLASSC 0x09
+-#define IT_HEADT 0x0E
+-#define IT_SERIRQC 0x49
+-
+-// PCI to Internal/LPC Bus Bridge configuration header register offset
+-#define IT_P2I_BCR 0x4C
+-#define IT_P2I_D0IOSC 0x50
+-#define IT_P2I_D1IOSC 0x54
+-#define IT_P2I_D2IOSC 0x58
+-#define IT_P2I_D3IOSC 0x5C
+-#define IT_P2I_D4IOSC 0x60
+-#define IT_P2I_D5IOSC 0x64
+-#define IT_P2I_D6IOSC 0x68
+-#define IT_P2I_D7IOSC 0x6C
+-#define IT_P2I_D8IOSC 0x70
+-#define IT_P2I_D9IOSC 0x74
+-#define IT_P2I_D10IOSC 0x78
+-#define IT_P2I_D11IOSC 0x7C
+-
+-// Memory controller register offsets from IT8172_BASE
+-#define IT_MC_SDRMR 0x1000
+-#define IT_MC_SDRTR 0x1004
+-#define IT_MC_MCR 0x1008
+-#define IT_MC_SDTYPE 0x100C
+-#define IT_MC_WPBA 0x1010
+-#define IT_MC_WPTA 0x1014
+-#define IT_MC_HATR 0x1018
+-#define IT_MC_PCICR 0x101C
+-
+-// Flash/ROM control register offsets from IT8172_BASE
+-#define IT_FC_BRCR 0x2000
+-#define IT_FC_FCR 0x2004
+-#define IT_FC_DCR 0x2008
+-
+-// M68K interface bridge configuration header register offset
+-#define IT_M68K_MBCSR 0x54
+-#define IT_M68K_TMR 0x58
+-#define IT_M68K_BCR 0x5C
+-#define IT_M68K_BSR 0x5D
+-#define IT_M68K_DTR 0x5F
+-
+-// Register offset from IT8172_PCI_IO_BASE
+-// These registers are accessible through 8172 PCI IO window.
+-
+-// INTC
+-#define IT_INTC_BASE 0x10000
+-#define IT_INTC_LBDNIRR 0x10000
+-#define IT_INTC_LBDNIMR 0x10002
+-#define IT_INTC_LBDNITR 0x10004
+-#define IT_INTC_LBDNIAR 0x10006
+-#define IT_INTC_LPCNIRR 0x10010
+-#define IT_INTC_LPCNIMR 0x10012
+-#define IT_INTC_LPCNITR 0x10014
+-#define IT_INTC_LPCNIAR 0x10016
+-#define IT_INTC_PDNIRR 0x10020
+-#define IT_INTC_PDNIMR 0x10022
+-#define IT_INTC_PDNITR 0x10024
+-#define IT_INTC_PDNIAR 0x10026
+-#define IT_INTC_UMNIRR 0x10030
+-#define IT_INTC_UMNITR 0x10034
+-#define IT_INTC_UMNIAR 0x10036
+-#define IT_INTC_TYPER 0x107FE
+-
+-// IT8172 PCI device number
+-#define IT_C2P_DEVICE 0
+-#define IT_AUDIO_DEVICE 1
+-#define IT_DMAC_DEVICE 1
+-#define IT_CDMAC_DEVICE 1
+-#define IT_USB_DEVICE 1
+-#define IT_P2I_DEVICE 1
+-#define IT_IDE_DEVICE 1
+-#define IT_M68K_DEVICE 1
+-
+-// IT8172 PCI function number
+-#define IT_C2P_FUNCION 0
+-#define IT_AUDIO_FUNCTION 0
+-#define IT_DMAC_FUNCTION 1
+-#define IT_CDMAC_FUNCTION 2
+-#define IT_USB_FUNCTION 3
+-#define IT_P2I_FUNCTION 4
+-#define IT_IDE_FUNCTION 5
+-#define IT_M68K_FUNCTION 6
+-
+-// IT8172 GPIO
+-#define IT_GPADR 0x13800
+-#define IT_GPBDR 0x13808
+-#define IT_GPCDR 0x13810
+-#define IT_GPACR 0x13802
+-#define IT_GPBCR 0x1380A
+-#define IT_GPCCR 0x13812
+-#define IT_GPAICR 0x13804
+-#define IT_GPBICR 0x1380C
+-#define IT_GPCICR 0x13814
+-#define IT_GPAISR 0x13806
+-#define IT_GPBISR 0x1380E
+-#define IT_GPCISR 0x13816
+-#define IT_GCR 0x13818
+-
+-// IT8172 RTC
+-#define IT_RTC_BASE 0x14800
+-#define IT_RTC_CENTURY 0x14808
+-
+-#define IT_RTC_RIR0 0x00
+-#define IT_RTC_RTR0 0x01
+-#define IT_RTC_RIR1 0x02
+-#define IT_RTC_RTR1 0x03
+-#define IT_RTC_RIR2 0x04
+-#define IT_RTC_RTR2 0x05
+-#define IT_RTC_RCTR 0x08
+-#define IT_RTC_RA 0x0A
+-#define IT_RTC_RB 0x0B
+-#define IT_RTC_RC 0x0C
+-#define IT_RTC_RD 0x0D
+-
+-#define RTC_SEC_INDEX 0x00
+-#define RTC_MIN_INDEX 0x02
+-#define RTC_HOUR_INDEX 0x04
+-#define RTC_DAY_INDEX 0x06
+-#define RTC_DATE_INDEX 0x07
+-#define RTC_MONTH_INDEX 0x08
+-#define RTC_YEAR_INDEX 0x09
+-
+-// IT8172 internal device registers
+-#define IT_TIMER_BASE 0x10800
+-#define IT_CIR0_BASE 0x11000
+-#define IT_UART_BASE 0x11800
+-#define IT_SCR0_BASE 0x12000
+-#define IT_SCR1_BASE 0x12800
+-#define IT_PP_BASE 0x13000
+-#define IT_I2C_BASE 0x14000
+-#define IT_CIR1_BASE 0x15000
+-
+-// IT8172 Smart Card Reader offsets from IT_SCR*_BASE
+-#define IT_SCR_SFR 0x08
+-#define IT_SCR_SCDR 0x09
+-
+-// IT8172 IT_SCR_SFR bit definition & mask
+-#define IT_SCR_SFR_GATE_UART 0x40
+-#define IT_SCR_SFR_GATE_UART_BIT 6
+-#define IT_SCR_SFR_GATE_UART_OFF 0
+-#define IT_SCR_SFR_GATE_UART_ON 1
+-#define IT_SCR_SFR_FET_CHARGE 0x30
+-#define IT_SCR_SFR_FET_CHARGE_BIT 4
+-#define IT_SCR_SFR_FET_CHARGE_3_3_US 3
+-#define IT_SCR_SFR_FET_CHARGE_13_US 2
+-#define IT_SCR_SFR_FET_CHARGE_53_US 1
+-#define IT_SCR_SFR_FET_CHARGE_213_US 0
+-#define IT_SCR_SFR_CARD_FREQ 0x0C
+-#define IT_SCR_SFR_CARD_FREQ_BIT 2
+-#define IT_SCR_SFR_CARD_FREQ_STOP 3
+-#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ 0
+-#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ 2
+-#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ 1
+-#define IT_SCR_SFR_FET_ACTIVE 0x02
+-#define IT_SCR_SFR_FET_ACTIVE_BIT 1
+-#define IT_SCR_SFR_FET_ACTIVE_INVERT 0
+-#define IT_SCR_SFR_FET_ACTIVE_NONINVERT 1
+-#define IT_SCR_SFR_ENABLE 0x01
+-#define IT_SCR_SFR_ENABLE_BIT 0
+-#define IT_SCR_SFR_ENABLE_OFF 0
+-#define IT_SCR_SFR_ENABLE_ON 1
+-
+-// IT8172 IT_SCR_SCDR bit definition & mask
+-#define IT_SCR_SCDR_RESET_MODE 0x80
+-#define IT_SCR_SCDR_RESET_MODE_BIT 7
+-#define IT_SCR_SCDR_RESET_MODE_ASYNC 0
+-#define IT_SCR_SCDR_RESET_MODE_SYNC 1
+-#define IT_SCR_SCDR_DIVISOR 0x7F
+-#define IT_SCR_SCDR_DIVISOR_BIT 0
+-#define IT_SCR_SCDR_DIVISOR_STOP_VAL_1 0x00
+-#define IT_SCR_SCDR_DIVISOR_STOP_VAL_2 0x01
+-#define IT_SCR_SCDR_DIVISOR_STOP_VAL_3 0x7F
+-
+-// IT8172 DMA
+-#define IT_DMAC_BASE 0x16000
+-#define IT_DMAC_BCAR0 0x00
+-#define IT_DMAC_BCAR1 0x04
+-#define IT_DMAC_BCAR2 0x08
+-#define IT_DMAC_BCAR3 0x0C
+-#define IT_DMAC_BCCR0 0x02
+-#define IT_DMAC_BCCR1 0x06
+-#define IT_DMAC_BCCR2 0x0a
+-#define IT_DMAC_BCCR3 0x0e
+-#define IT_DMAC_CR 0x10
+-#define IT_DMAC_SR 0x12
+-#define IT_DMAC_ESR 0x13
+-#define IT_DMAC_RQR 0x14
+-#define IT_DMAC_MR 0x16
+-#define IT_DMAC_EMR 0x17
+-#define IT_DMAC_MKR 0x18
+-#define IT_DMAC_PAR0 0x20
+-#define IT_DMAC_PAR1 0x22
+-#define IT_DMAC_PAR2 0x24
+-#define IT_DMAC_PAR3 0x26
+-
+-// IT8172 IDE
+-#define IT_IDE_BASE 0x17800
+-#define IT_IDE_STATUS 0x1F7
+-
+-// IT8172 Audio Controller
+-#define IT_AC_BASE 0x17000
+-#define IT_AC_PCMOV 0x00
+-#define IT_AC_FMOV 0x02
+-#define IT_AC_I2SV 0x04
+-#define IT_AC_DRSS 0x06
+-#define IT_AC_PCC 0x08
+-#define IT_AC_PCDL 0x0A
+-#define IT_AC_PCB1STA 0x0C
+-#define IT_AC_PCB2STA 0x10
+-#define IT_AC_CAPCC 0x14
+-#define IT_AC_CAPCDL 0x16
+-#define IT_AC_CAPB1STA 0x18
+-#define IT_AC_CAPB2STA 0x1C
+-#define IT_AC_CODECC 0x22
+-#define IT_AC_I2SMC 0x24
+-#define IT_AC_VS 0x26
+-#define IT_AC_SRCS 0x28
+-#define IT_AC_CIRCP 0x2A
+-#define IT_AC_CIRDP 0x2C
+-#define IT_AC_TM 0x4A
+-#define IT_AC_PFDP 0x4C
+-#define IT_AC_GC 0x54
+-#define IT_AC_IMC 0x56
+-#define IT_AC_ISC 0x5B
+-#define IT_AC_OPL3SR 0x68
+-#define IT_AC_OPL3DWDR 0x69
+-#define IT_AC_OPL3AB1W 0x6A
+-#define IT_AC_OPL3DW 0x6B
+-#define IT_AC_BPDC 0x70
+-
+-
+-// IT8172 Timer
+-#define IT_TIMER_BASE 0x10800
+-#define TIMER_TCVR0 0x00
+-#define TIMER_TRVR0 0x02
+-#define TIMER_TCR0 0x04
+-#define TIMER_TIRR 0x06
+-#define TIMER_TCVR1 0x08
+-#define TIMER_TRVR1 0x0A
+-#define TIMER_TCR1 0x0C
+-#define TIMER_TIDR 0x0E
+-
+-
+-#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data
+-#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs))
+-
+-#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
+-#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
+-
+-#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
+-#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
+-
+-#endif
+diff --git a/include/asm-mips/it8172/it8172_cir.h b/include/asm-mips/it8172/it8172_cir.h
+deleted file mode 100644
+index 6a1dbd2..0000000
+--- a/include/asm-mips/it8172/it8172_cir.h
++++ /dev/null
+@@ -1,140 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * IT8172 Consumer IR port defines.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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.
+- */
+-
+-#define NUM_CIR_PORTS 2
+-
+-/* Master Control Register */
+-#define CIR_RESET 0x1
+-#define CIR_FIFO_CLEAR 0x2
+-#define CIR_SET_FIFO_TL(x) (((x)&0x3)<<2)
+-#define CIR_ILE 0x10
+-#define CIR_ILSEL 0x20
+-
+-/* Interrupt Enable Register */
+-#define CIR_TLDLIE 0x1
+-#define CIR_RDAIE 0x2
+-#define CIR_RFOIE 0x4
+-#define CIR_IEC 0x80
+-
+-/* Interrupt Identification Register */
+-#define CIR_TLDLI 0x1
+-#define CIR_RDAI 0x2
+-#define CIR_RFOI 0x4
+-#define CIR_NIP 0x80
+-
+-/* Carrier Frequency Register */
+-#define CIR_SET_CF(x) ((x)&0x1f)
+- #define CFQ_38_480 0xB /* 38 KHz low, 480 KHz high */
+-#define CIR_HCFS 0x20
+- #define CIR_SET_HS(x) (((x)&0x1)<<5)
+-
+-
+-/* Receiver Control Register */
+-#define CIR_SET_RXDCR(x) ((x)&0x7)
+-#define CIR_RXACT 0x8
+-#define CIR_RXEND 0x10
+-#define CIR_RDWOS 0x20
+- #define CIR_SET_RDWOS(x) (((x)&0x1)<<5)
+-#define CIR_RXEN 0x80
+-
+-/* Transmitter Control Register */
+-#define CIR_SET_TXMPW(x) ((x)&0x7)
+-#define CIR_SET_TXMPM(x) (((x)&0x3)<<3)
+-#define CIR_TXENDF 0x20
+-#define CIR_TXRLE 0x40
+-
+-/* Receiver FIFO Status Register */
+-#define CIR_RXFBC_MASK 0x3f
+-#define CIR_RXFTO 0x80
+-
+-/* Wakeup Code Length Register */
+-#define CIR_SET_WCL ((x)&0x3f)
+-#define CIR_WCL_MASK(x) ((x)&0x3f)
+-
+-/* Wakeup Power Control/Status Register */
+-#define CIR_BTMON 0x2
+-#define CIR_CIRON 0x4
+-#define CIR_RCRST 0x10
+-#define CIR_WCRST 0x20
+-
+-struct cir_port {
+- int port;
+- unsigned short baud_rate;
+- unsigned char fifo_tl;
+- unsigned char cfq;
+- unsigned char hcfs;
+- unsigned char rdwos;
+- unsigned char rxdcr;
+-};
+-
+-struct it8172_cir_regs {
+- unsigned char dr; /* data */
+- char pad;
+- unsigned char mstcr; /* master control */
+- char pad1;
+- unsigned char ier; /* interrupt enable */
+- char pad2;
+- unsigned char iir; /* interrupt identification */
+- char pad3;
+- unsigned char cfr; /* carrier frequency */
+- char pad4;
+- unsigned char rcr; /* receiver control */
+- char pad5;
+- unsigned char tcr; /* transmitter control */
+- char pad6;
+- char pad7;
+- char pad8;
+- unsigned char bdlr; /* baud rate divisor low byte */
+- char pad9;
+- unsigned char bdhr; /* baud rate divisor high byte */
+- char pad10;
+- unsigned char tfsr; /* tx fifo byte count */
+- char pad11;
+- unsigned char rfsr; /* rx fifo status */
+- char pad12;
+- unsigned char wcl; /* wakeup code length */
+- char pad13;
+- unsigned char wcr; /* wakeup code read/write */
+- char pad14;
+- unsigned char wps; /* wakeup power control/status */
+-};
+-
+-int cir_port_init(struct cir_port *cir);
+-extern void clear_fifo(struct cir_port *cir);
+-extern void enable_receiver(struct cir_port *cir);
+-extern void disable_receiver(struct cir_port *cir);
+-extern void enable_rx_demodulation(struct cir_port *cir);
+-extern void disable_rx_demodulation(struct cir_port *cir);
+-extern void set_rx_active(struct cir_port *cir);
+-extern void int_enable(struct cir_port *cir);
+-extern void rx_int_enable(struct cir_port *cir);
+-extern char get_int_status(struct cir_port *cir);
+-extern int cir_get_rx_count(struct cir_port *cir);
+-extern char cir_read_data(struct cir_port *cir);
+diff --git a/include/asm-mips/it8172/it8172_dbg.h b/include/asm-mips/it8172/it8172_dbg.h
+deleted file mode 100644
+index f404ec7..0000000
+--- a/include/asm-mips/it8172/it8172_dbg.h
++++ /dev/null
+@@ -1,38 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Function prototypes for low level uart routines to
+- * directly access a 16550 uart.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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/types.h>
+-
+-extern void putch(const unsigned char c);
+-extern void puts(unsigned char *cp);
+-extern void fputs(unsigned char *cp);
+-extern void put64(uint64_t ul);
+-extern void put32(unsigned u);
+diff --git a/include/asm-mips/it8172/it8172_int.h b/include/asm-mips/it8172/it8172_int.h
+deleted file mode 100644
+index 837e83a..0000000
+--- a/include/asm-mips/it8172/it8172_int.h
++++ /dev/null
+@@ -1,144 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * ITE 8172 Interrupt Numbering
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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.
+- */
+-
+-#ifndef _MIPS_ITEINT_H
+-#define _MIPS_ITEINT_H
+-
+-/*
+- * Here's the "strategy":
+- * We number the LPC serial irqs from 0 to 15,
+- * the local bus irqs from 16 to 31,
+- * the pci dev register interrupts from 32 to 47,
+- * and the non-maskable ints from 48 to 53.
+- */
+-
+-#define IT8172_LPC_IRQ_BASE 0 /* first LPC int number */
+-#define IT8172_SERIRQ_0 (IT8172_LPC_IRQ_BASE + 0)
+-#define IT8172_SERIRQ_1 (IT8172_LPC_IRQ_BASE + 1)
+-#define IT8172_SERIRQ_2 (IT8172_LPC_IRQ_BASE + 2)
+-#define IT8172_SERIRQ_3 (IT8172_LPC_IRQ_BASE + 3)
+-#define IT8172_SERIRQ_4 (IT8172_LPC_IRQ_BASE + 4)
+-#define IT8172_SERIRQ_5 (IT8172_LPC_IRQ_BASE + 5)
+-#define IT8172_SERIRQ_6 (IT8172_LPC_IRQ_BASE + 6)
+-#define IT8172_SERIRQ_7 (IT8172_LPC_IRQ_BASE + 7)
+-#define IT8172_SERIRQ_8 (IT8172_LPC_IRQ_BASE + 8)
+-#define IT8172_SERIRQ_9 (IT8172_LPC_IRQ_BASE + 9)
+-#define IT8172_SERIRQ_10 (IT8172_LPC_IRQ_BASE + 10)
+-#define IT8172_SERIRQ_11 (IT8172_LPC_IRQ_BASE + 11)
+-#define IT8172_SERIRQ_12 (IT8172_LPC_IRQ_BASE + 12)
+-#define IT8172_SERIRQ_13 (IT8172_LPC_IRQ_BASE + 13)
+-#define IT8172_SERIRQ_14 (IT8172_LPC_IRQ_BASE + 14)
+-#define IT8172_SERIRQ_15 (IT8172_LPC_IRQ_BASE + 15)
+-
+-#define IT8172_LB_IRQ_BASE 16 /* first local bus int number */
+-#define IT8172_PPR_IRQ (IT8172_LB_IRQ_BASE + 0) /* parallel port */
+-#define IT8172_TIMER0_IRQ (IT8172_LB_IRQ_BASE + 1)
+-#define IT8172_TIMER1_IRQ (IT8172_LB_IRQ_BASE + 2)
+-#define IT8172_I2C_IRQ (IT8172_LB_IRQ_BASE + 3)
+-#define IT8172_GPIO_IRQ (IT8172_LB_IRQ_BASE + 4)
+-#define IT8172_CIR0_IRQ (IT8172_LB_IRQ_BASE + 5)
+-#define IT8172_CIR1_IRQ (IT8172_LB_IRQ_BASE + 6)
+-#define IT8172_UART_IRQ (IT8172_LB_IRQ_BASE + 7)
+-#define IT8172_SCR0_IRQ (IT8172_LB_IRQ_BASE + 8)
+-#define IT8172_SCR1_IRQ (IT8172_LB_IRQ_BASE + 9)
+-#define IT8172_RTC_IRQ (IT8172_LB_IRQ_BASE + 10)
+-#define IT8172_IOCHK_IRQ (IT8172_LB_IRQ_BASE + 11)
+-/* 12 - 15 reserved */
+-
+-/*
+- * Note here that the pci dev registers includes bits for more than
+- * just the pci devices.
+- */
+-#define IT8172_PCI_DEV_IRQ_BASE 32 /* first pci dev irq */
+-#define IT8172_AC97_IRQ (IT8172_PCI_DEV_IRQ_BASE + 0)
+-#define IT8172_MC68K_IRQ (IT8172_PCI_DEV_IRQ_BASE + 1)
+-#define IT8172_IDE_IRQ (IT8172_PCI_DEV_IRQ_BASE + 2)
+-#define IT8172_USB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 3)
+-#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4)
+-#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5)
+-#define IT8172_PCI_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 6)
+-#define IT8172_PCI_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 7)
+-#define IT8172_PCI_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 8)
+-#define IT8172_PCI_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 9)
+-#define IT8172_S_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 10)
+-#define IT8172_S_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 11)
+-#define IT8172_S_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 12)
+-#define IT8172_S_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 13)
+-#define IT8172_CDMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 14)
+-#define IT8172_DMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 15)
+-
+-#define IT8172_NMI_IRQ_BASE 48
+-#define IT8172_SER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 0)
+-#define IT8172_PCI_NMI_IRQ (IT8172_NMI_IRQ_BASE + 1)
+-#define IT8172_RTC_NMI_IRQ (IT8172_NMI_IRQ_BASE + 2)
+-#define IT8172_CPUIF_NMI_IRQ (IT8172_NMI_IRQ_BASE + 3)
+-#define IT8172_PMER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 4)
+-#define IT8172_POWER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 5)
+-
+-#define IT8172_LAST_IRQ (IT8172_POWER_NMI_IRQ)
+-/* Finally, let's move over here the mips cpu timer interrupt.
+- */
+-#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1)
+-
+-/*
+- * IT8172 Interrupt Controller Registers
+- */
+-struct it8172_intc_regs {
+- volatile unsigned short lb_req; /* offset 0 */
+- volatile unsigned short lb_mask;
+- volatile unsigned short lb_trigger;
+- volatile unsigned short lb_level;
+- unsigned char pad0[8];
+-
+- volatile unsigned short lpc_req; /* offset 0x10 */
+- volatile unsigned short lpc_mask;
+- volatile unsigned short lpc_trigger;
+- volatile unsigned short lpc_level;
+- unsigned char pad1[8];
+-
+- volatile unsigned short pci_req; /* offset 0x20 */
+- volatile unsigned short pci_mask;
+- volatile unsigned short pci_trigger;
+- volatile unsigned short pci_level;
+- unsigned char pad2[8];
+-
+- volatile unsigned short nmi_req; /* offset 0x30 */
+- volatile unsigned short nmi_mask;
+- volatile unsigned short nmi_trigger;
+- volatile unsigned short nmi_level;
+- unsigned char pad3[6];
+-
+- volatile unsigned short nmi_redir; /* offset 0x3E */
+- unsigned char pad4[0xBE];
+-
+- volatile unsigned short intstatus; /* offset 0xFE */
+-};
+-
+-#endif /* _MIPS_ITEINT_H */
+diff --git a/include/asm-mips/it8172/it8172_pci.h b/include/asm-mips/it8172/it8172_pci.h
+deleted file mode 100644
+index 42c61f5..0000000
+--- a/include/asm-mips/it8172/it8172_pci.h
++++ /dev/null
+@@ -1,108 +0,0 @@
+-/*
+- *
+- * BRIEF MODULE DESCRIPTION
+- * IT8172 system controller specific pci defines.
+- *
+- * Copyright 2000 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * ppopov at mvista.com or source at 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.
+- *
+- * 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.
+- */
+-
+-#ifndef _8172PCI_H_
+-#define _8172PCI_H_
+-
+-// PCI configuration space Type0
+-#define PCI_IDREG 0x00
+-#define PCI_CMDSTSREG 0x04
+-#define PCI_CLASSREG 0x08
+-#define PCI_BHLCREG 0x0C
+-#define PCI_BASE1REG 0x10
+-#define PCI_BASE2REG 0x14
+-#define PCI_BASE3REG 0x18
+-#define PCI_BASE4REG 0x1C
+-#define PCI_BASE5REG 0x20
+-#define PCI_BASE6REG 0x24
+-#define PCI_ROMBASEREG 0x30
+-#define PCI_INTRREG 0x3C
+-
+-// PCI configuration space Type1
+-#define PCI_BUSNOREG 0x18
+-
+-#define IT_PCI_VENDORID(x) ((x) & 0xFFFF)
+-#define IT_PCI_DEVICEID(x) (((x)>>16) & 0xFFFF)
+-
+-// Command register
+-#define PCI_CMD_IOEN 0x00000001
+-#define PCI_CMD_MEMEN 0x00000002
+-#define PCI_CMD_BUSMASTER 0x00000004
+-#define PCI_CMD_SPCYCLE 0x00000008
+-#define PCI_CMD_WRINV 0x00000010
+-#define PCI_CMD_VGASNOOP 0x00000020
+-#define PCI_CMD_PERR 0x00000040
+-#define PCI_CMD_WAITCTRL 0x00000080
+-#define PCI_CMD_SERR 0x00000100
+-#define PCI_CMD_FAST_BACKTOBACK 0x00000200
+-
+-// Status register
+-#define PCI_STS_66MHZ 0x00200000
+-#define PCI_STS_SUPPORT_UDF 0x00400000
+-#define PCI_STS_FAST_BACKTOBACK 0x00800000
+-#define PCI_STS_DATA_PERR 0x01000000
+-#define PCI_STS_DEVSEL0 0x02000000
+-#define PCI_STS_DEVSEL1 0x04000000
+-#define PCI_STS_SIG_TGTABORT 0x08000000
+-#define PCI_STS_RCV_TGTABORT 0x10000000
+-#define PCI_STS_RCV_MSTABORT 0x20000000
+-#define PCI_STS_SYSERR 0x40000000
+-#define PCI_STS_DETCT_PERR 0x80000000
+-
+-#define IT_PCI_CLASS(x) (((x)>>24) & 0xFF)
+-#define IT_PCI_SUBCLASS(x) (((x)>>16) & 0xFF)
+-#define IT_PCI_INTERFACE(x) (((x)>>8) & 0xFF)
+-#define IT_PCI_REVISION(x) ((x) & 0xFF)
+-
+-// PCI class code
+-#define PCI_CLASS_BRIDGE 0x06
+-
+-// bridge subclass
+-#define PCI_SUBCLASS_BRIDGE_HOST 0x00
+-#define PCI_SUBCLASS_BRIDGE_PCI 0x04
+-
+-// BHLCREG
+-#define IT_PCI_BIST(x) (((x)>>24) & 0xFF)
+-#define IT_PCI_HEADERTYPE(x) (((x)>>16) & 0xFF)
+-#define IT_PCI_LATENCYTIMER(x) (((x)>>8) & 0xFF)
+-#define IT_PCI_CACHELINESIZE(x) ((x) & 0xFF)
+-
+-#define PCI_MULTIFUNC 0x80
+-
+-// INTRREG
+-#define IT_PCI_MAXLAT(x) (((x)>>24) & 0xFF)
+-#define IT_PCI_MINGNT(x) (((x)>>16) & 0xFF)
+-#define IT_PCI_INTRPIN(x) (((x)>>8) & 0xFF)
+-#define IT_PCI_INTRLINE(x) ((x) & 0xFF)
+-
+-#define PCI_VENDOR_NEC 0x1033
+-#define PCI_VENDOR_DEC 0x1101
+-
+-#endif // _8172PCI_H_
+diff --git a/include/asm-mips/it8712.h b/include/asm-mips/it8712.h
+deleted file mode 100644
+index ca2dee0..0000000
+--- a/include/asm-mips/it8712.h
++++ /dev/null
+@@ -1,28 +0,0 @@
+-
+-#ifndef __IT8712_H__
+-#define __IT8712_H__
+-
+-#define LPC_BASE_ADDR 0x14000000
+-
+-// MB PnP configuration register
+-#define LPC_KEY_ADDR 0x1400002E
+-#define LPC_DATA_ADDR 0x1400002F
+-
+-// Device LDN
+-#define LDN_SERIAL1 0x01
+-#define LDN_SERIAL2 0x02
+-#define LDN_PARALLEL 0x03
+-#define LDN_KEYBOARD 0x05
+-#define LDN_MOUSE 0x06
+-
+-#define IT8712_UART1_PORT 0x3F8
+-#define IT8712_UART2_PORT 0x2F8
+-
+-#ifndef ASM_ONLY
+-
+-void LPCSetConfig(char LdnNumber, char Index, char data);
+-char LPCGetConfig(char LdnNumber, char Index);
+-
+-#endif
+-
+-#endif
+diff --git a/include/asm-mips/jmr3927/irq.h b/include/asm-mips/jmr3927/irq.h
+index fe551f3..e3e7ed3 100644
+--- a/include/asm-mips/jmr3927/irq.h
++++ b/include/asm-mips/jmr3927/irq.h
+@@ -45,10 +45,6 @@ extern int
+ toshibaboards_setup_irq(int irq, struct irqaction * new);
+
+
+-#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
+-extern void tx_branch_likely_bug_fixup(struct pt_regs *regs);
+-#endif
+-
+ extern int (*toshibaboards_gen_iack)(void);
+
+ #endif /* !__ASSEMBLY__ */
+diff --git a/include/asm-mips/mach-atlas/mc146818rtc.h b/include/asm-mips/mach-atlas/mc146818rtc.h
+index 397522e..a73a569 100644
+--- a/include/asm-mips/mach-atlas/mc146818rtc.h
++++ b/include/asm-mips/mach-atlas/mc146818rtc.h
+@@ -28,10 +28,12 @@
+ #include <asm/mips-boards/atlas.h>
+ #include <asm/mips-boards/atlasint.h>
+
++#define ARCH_RTC_LOCATION
++
+ #define RTC_PORT(x) (ATLAS_RTC_ADR_REG + (x) * 8)
+ #define RTC_IO_EXTENT 0x100
+ #define RTC_IOMAPPED 0
+-#define RTC_IRQ ATLASINT_RTC
++#define RTC_IRQ ATLAS_INT_RTC
+
+ static inline unsigned char CMOS_READ(unsigned long addr)
+ {
+diff --git a/include/asm-mips/mach-au1x00/au1000_dma.h b/include/asm-mips/mach-au1x00/au1000_dma.h
+index 810f2fa..9f29520 100644
+--- a/include/asm-mips/mach-au1x00/au1000_dma.h
++++ b/include/asm-mips/mach-au1x00/au1000_dma.h
+@@ -123,8 +123,7 @@ struct dma_chan {
+ extern struct dma_chan au1000_dma_table[];
+ extern int request_au1000_dma(int dev_id,
+ const char *dev_str,
+- irqreturn_t (*irqhandler)(int, void *,
+- struct pt_regs *),
++ irq_handler_t irqhandler,
+ unsigned long irqflags,
+ void *irq_dev_id);
+ extern void free_au1000_dma(unsigned int dmanr);
+diff --git a/include/asm-mips/mach-au1x00/au1000_usbdev.h b/include/asm-mips/mach-au1x00/au1000_usbdev.h
+deleted file mode 100644
+index 05bc74b..0000000
+--- a/include/asm-mips/mach-au1x00/au1000_usbdev.h
++++ /dev/null
+@@ -1,73 +0,0 @@
+-/*
+- * BRIEF MODULE DESCRIPTION
+- * Au1000 USB Device-Side Driver
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at 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.
+- *
+- * 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.
+- */
+-
+-#define USBDEV_REV 0x0110 // BCD
+-#define USBDEV_EP0_MAX_PACKET_SIZE 64
+-
+-typedef enum {
+- ATTACHED = 0,
+- POWERED,
+- DEFAULT,
+- ADDRESS,
+- CONFIGURED
+-} usbdev_state_t;
+-
+-typedef enum {
+- CB_NEW_STATE = 0,
+- CB_PKT_COMPLETE
+-} usbdev_cb_type_t;
+-
+-
+-typedef struct usbdev_pkt {
+- int ep_addr; // ep addr this packet routed to
+- int size; // size of payload in bytes
+- unsigned status; // packet status
+- struct usbdev_pkt* next; // function layer can't touch this
+- u8 payload[0]; // the payload
+-} usbdev_pkt_t;
+-
+-#define PKT_STATUS_ACK (1<<0)
+-#define PKT_STATUS_NAK (1<<1)
+-#define PKT_STATUS_SU (1<<2)
+-
+-extern int usbdev_init(struct usb_device_descriptor* dev_desc,
+- struct usb_config_descriptor* config_desc,
+- struct usb_interface_descriptor* if_desc,
+- struct usb_endpoint_descriptor* ep_desc,
+- struct usb_string_descriptor* str_desc[],
+- void (*cb)(usbdev_cb_type_t, unsigned long, void *),
+- void* cb_data);
+-
+-extern void usbdev_exit(void);
+-
+-extern int usbdev_alloc_packet (int ep_addr, int data_size,
+- usbdev_pkt_t** pkt);
+-extern int usbdev_send_packet (int ep_addr, usbdev_pkt_t* pkt);
+-extern int usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt);
+-extern int usbdev_get_byte_count(int ep_addr);
+diff --git a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h b/include/asm-mips/mach-au1x00/au1xxx_dbdma.h
+index d5b38a2..eeb0c31 100644
+--- a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h
++++ b/include/asm-mips/mach-au1x00/au1xxx_dbdma.h
+@@ -316,7 +316,7 @@ typedef struct dbdma_chan_config {
+ au1x_ddma_desc_t *chan_desc_base;
+ au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr;
+ void *chan_callparam;
+- void (*chan_callback)(int, void *, struct pt_regs *);
++ void (*chan_callback)(int, void *);
+ } chan_tab_t;
+
+ #define DEV_FLAGS_INUSE (1 << 0)
+@@ -334,8 +334,8 @@ typedef struct dbdma_chan_config {
+ * meaningful name. The 'callback' is called during dma completion
+ * interrupt.
+ */
+-u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
+- void (*callback)(int, void *, struct pt_regs *), void *callparam);
++extern u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
++ void (*callback)(int, void *), void *callparam);
+
+ #define DBDMA_MEM_CHAN DSCR_CMD0_ALWAYS
+
+diff --git a/include/asm-mips/mach-ev64120/mach-gt64120.h b/include/asm-mips/mach-ev64120/mach-gt64120.h
+index 13b1443..7e272ce 100644
+--- a/include/asm-mips/mach-ev64120/mach-gt64120.h
++++ b/include/asm-mips/mach-ev64120/mach-gt64120.h
+@@ -42,6 +42,7 @@ extern unsigned long gt64120_base;
+ #define EV64120_UART0_REGS_BASE (KSEG1ADDR(EV64120_COM1_BASE_ADDR))
+ #define EV64120_UART1_REGS_BASE (KSEG1ADDR(EV64120_COM2_BASE_ADDR))
+ #define EV64120_BASE_BAUD ( 3686400 / 16 )
++#define EV64120_UART_IRQ 6
+
+ /*
+ * PCI interrupts will come in on either the INTA or INTD interrups lines,
+diff --git a/include/asm-mips/mach-ev96100/mach-gt64120.h b/include/asm-mips/mach-ev96100/mach-gt64120.h
+deleted file mode 100644
+index 0ef1e6c..0000000
+--- a/include/asm-mips/mach-ev96100/mach-gt64120.h
++++ /dev/null
+@@ -1,46 +0,0 @@
+-/*
+- * This is a direct copy of the ev96100.h file, with a global
+- * search and replace. The numbers are the same.
+- *
+- * The reason I'm duplicating this is so that the 64120/96100
+- * defines won't be confusing in the source code.
+- */
+-#ifndef _ASM_GT64120_EV96100_GT64120_DEP_H
+-#define _ASM_GT64120_EV96100_GT64120_DEP_H
+-
+-/*
+- * GT96100 config space base address
+- */
+-#define GT64120_BASE (KSEG1ADDR(0x14000000))
+-
+-/*
+- * PCI Bus allocation
+- *
+- * (Guessing ...)
+- */
+-#define GT_PCI_MEM_BASE 0x12000000UL
+-#define GT_PCI_MEM_SIZE 0x02000000UL
+-#define GT_PCI_IO_BASE 0x10000000UL
+-#define GT_PCI_IO_SIZE 0x02000000UL
+-#define GT_ISA_IO_BASE PCI_IO_BASE
+-
+-/*
+- * Duart I/O ports.
+- */
+-#define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20)
+-#define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00)
+-
+-
+-/*
+- * EV96100 interrupt controller register base.
+- */
+-#define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000))
+-
+-/*
+- * EV96100 UART register base.
+- */
+-#define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR
+-#define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR
+-#define EV96100_BASE_BAUD ( 3686400 / 16 )
+-
+-#endif /* _ASM_GT64120_EV96100_GT64120_DEP_H */
+diff --git a/include/asm-mips/mach-excite/excite.h b/include/asm-mips/mach-excite/excite.h
+index 130bd4b..4c29ba4 100644
+--- a/include/asm-mips/mach-excite/excite.h
++++ b/include/asm-mips/mach-excite/excite.h
+@@ -7,7 +7,7 @@
+
+ #define EXCITE_CPU_EXT_CLOCK 100000000
+
+-#if !defined(__ASSEMBLER__)
++#if !defined(__ASSEMBLY__)
+ void __init excite_kgdb_init(void);
+ void excite_procfs_init(void);
+ extern unsigned long memsize;
+diff --git a/include/asm-mips/mach-excite/excite_fpga.h b/include/asm-mips/mach-excite/excite_fpga.h
+new file mode 100644
+index 0000000..38fcda7
+--- /dev/null
++++ b/include/asm-mips/mach-excite/excite_fpga.h
+@@ -0,0 +1,80 @@
++#ifndef EXCITE_FPGA_H_INCLUDED
++#define EXCITE_FPGA_H_INCLUDED
++
++
++/**
++ * Adress alignment of the individual FPGA bytes.
++ * The address arrangement of the individual bytes of the FPGA is two
++ * byte aligned at the embedded MK2 platform.
++ */
++#ifdef EXCITE_CCI_FPGA_MK2
++typedef unsigned char excite_cci_fpga_align_t __attribute__ ((aligned(2)));
++#else
++typedef unsigned char excite_cci_fpga_align_t;
++#endif
++
++
++/**
++ * Size of Dual Ported RAM.
++ */
++#define EXCITE_DPR_SIZE 263
++
++
++/**
++ * Size of Reserved Status Fields in Dual Ported RAM.
++ */
++#define EXCITE_DPR_STATUS_SIZE 7
++
++
++
++/**
++ * FPGA.
++ * Hardware register layout of the FPGA interface. The FPGA must accessed
++ * byte wise solely.
++ * @see EXCITE_CCI_DPR_MK2
++ */
++typedef struct excite_fpga {
++
++ /**
++ * Dual Ported RAM.
++ */
++ excite_cci_fpga_align_t dpr[EXCITE_DPR_SIZE];
++
++ /**
++ * Status.
++ */
++ excite_cci_fpga_align_t status[EXCITE_DPR_STATUS_SIZE];
++
++#ifdef EXCITE_CCI_FPGA_MK2
++ /**
++ * RM9000 Interrupt.
++ * Write access initiates interrupt at the RM9000 (MIPS) processor of the eXcite.
++ */
++ excite_cci_fpga_align_t rm9k_int;
++#else
++ /**
++ * MK2 Interrupt.
++ * Write access initiates interrupt at the ARM processor of the MK2.
++ */
++ excite_cci_fpga_align_t mk2_int;
++
++ excite_cci_fpga_align_t gap[0x1000-0x10f];
++
++ /**
++ * IRQ Source/Acknowledge.
++ */
++ excite_cci_fpga_align_t rm9k_irq_src;
++
++ /**
++ * IRQ Mask.
++ * Set bits enable the related interrupt.
++ */
++ excite_cci_fpga_align_t rm9k_irq_mask;
++#endif
++
++
++} excite_fpga;
++
++
++
++#endif /* ndef EXCITE_FPGA_H_INCLUDED */
+diff --git a/include/asm-mips/mach-ip27/topology.h b/include/asm-mips/mach-ip27/topology.h
+index 59d26b5..a13b715 100644
+--- a/include/asm-mips/mach-ip27/topology.h
++++ b/include/asm-mips/mach-ip27/topology.h
+@@ -22,6 +22,7 @@ extern unsigned char __node_distances[MA
+ #define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 32, \
+diff --git a/include/asm-mips/mach-pnx8550/uart.h b/include/asm-mips/mach-pnx8550/uart.h
+index e32b9a2..814a7a1 100644
+--- a/include/asm-mips/mach-pnx8550/uart.h
++++ b/include/asm-mips/mach-pnx8550/uart.h
+@@ -13,4 +13,18 @@
+ #define PNX8550_UART_INT(x) (PNX8550_INT_GIC_MIN+19+x)
+ #define IRQ_TO_UART(x) (x-PNX8550_INT_GIC_MIN-19)
+
++/* early macros needed for prom/kgdb */
++
++#define ip3106_lcr(base,port) *(volatile u32 *)(base+(port*0x1000) + 0x000)
++#define ip3106_mcr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x004)
++#define ip3106_baud(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x008)
++#define ip3106_cfg(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x00C)
++#define ip3106_fifo(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x028)
++#define ip3106_istat(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE0)
++#define ip3106_ien(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE4)
++#define ip3106_iclr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE8)
++#define ip3106_iset(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFEC)
++#define ip3106_pd(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFF4)
++#define ip3106_mid(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFFC)
++
+ #endif
+diff --git a/include/asm-mips/mach-qemu/cpu-feature-overrides.h b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
+index f4e370e..529445d 100644
+--- a/include/asm-mips/mach-qemu/cpu-feature-overrides.h
++++ b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
+@@ -20,7 +20,7 @@
+
+ #define cpu_has_llsc 1
+ #define cpu_has_vtag_icache 0
+-#define cpu_has_dc_aliases (PAGE_SIZE < 0x4000)
++#define cpu_has_dc_aliases 0
+ #define cpu_has_ic_fills_f_dc 0
+
+ #define cpu_has_dsp 0
+diff --git a/include/asm-mips/marvell.h b/include/asm-mips/marvell.h
+index 6bb2125..df94955 100644
+--- a/include/asm-mips/marvell.h
++++ b/include/asm-mips/marvell.h
+@@ -53,6 +53,6 @@ struct mv_pci_controller {
+ unsigned long config_vreg;
+ };
+
+-extern void ll_mv64340_irq(struct pt_regs *regs);
++extern void ll_mv64340_irq(void);
+
+ #endif /* __ASM_MIPS_MARVELL_H */
+diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h
+index fd7ebc5..b15e4ea 100644
+--- a/include/asm-mips/mips-boards/atlasint.h
++++ b/include/asm-mips/mips-boards/atlasint.h
+@@ -1,6 +1,7 @@
+ /*
+- * Carsten Langgaard, carstenl at mips.com
+- * Copyright (C) 1999 MIPS Technologies, Inc. All rights reserved.
++ * Copyright (C) 1999, 2006 MIPS Technologies, Inc. All rights reserved.
++ * Authors: Carsten Langgaard <carstenl at mips.com>
++ * Maciej W. Rozycki <macro at mips.com>
+ *
+ * ########################################################################
+ *
+@@ -25,41 +26,88 @@
+ #ifndef _MIPS_ATLASINT_H
+ #define _MIPS_ATLASINT_H
+
+-#define ATLASINT_BASE 1
+-#define ATLASINT_UART (ATLASINT_BASE+0)
+-#define ATLASINT_TIM0 (ATLASINT_BASE+1)
+-#define ATLASINT_RES2 (ATLASINT_BASE+2)
+-#define ATLASINT_RES3 (ATLASINT_BASE+3)
+-#define ATLASINT_RTC (ATLASINT_BASE+4)
+-#define ATLASINT_COREHI (ATLASINT_BASE+5)
+-#define ATLASINT_CORELO (ATLASINT_BASE+6)
+-#define ATLASINT_RES7 (ATLASINT_BASE+7)
+-#define ATLASINT_PCIA (ATLASINT_BASE+8)
+-#define ATLASINT_PCIB (ATLASINT_BASE+9)
+-#define ATLASINT_PCIC (ATLASINT_BASE+10)
+-#define ATLASINT_PCID (ATLASINT_BASE+11)
+-#define ATLASINT_ENUM (ATLASINT_BASE+12)
+-#define ATLASINT_DEG (ATLASINT_BASE+13)
+-#define ATLASINT_ATXFAIL (ATLASINT_BASE+14)
+-#define ATLASINT_INTA (ATLASINT_BASE+15)
+-#define ATLASINT_INTB (ATLASINT_BASE+16)
+-#define ATLASINT_ETH ATLASINT_INTB
+-#define ATLASINT_INTC (ATLASINT_BASE+17)
+-#define ATLASINT_SCSI ATLASINT_INTC
+-#define ATLASINT_INTD (ATLASINT_BASE+18)
+-#define ATLASINT_SERR (ATLASINT_BASE+19)
+-#define ATLASINT_RES20 (ATLASINT_BASE+20)
+-#define ATLASINT_RES21 (ATLASINT_BASE+21)
+-#define ATLASINT_RES22 (ATLASINT_BASE+22)
+-#define ATLASINT_RES23 (ATLASINT_BASE+23)
+-#define ATLASINT_RES24 (ATLASINT_BASE+24)
+-#define ATLASINT_RES25 (ATLASINT_BASE+25)
+-#define ATLASINT_RES26 (ATLASINT_BASE+26)
+-#define ATLASINT_RES27 (ATLASINT_BASE+27)
+-#define ATLASINT_RES28 (ATLASINT_BASE+28)
+-#define ATLASINT_RES29 (ATLASINT_BASE+29)
+-#define ATLASINT_RES30 (ATLASINT_BASE+30)
+-#define ATLASINT_RES31 (ATLASINT_BASE+31)
+-#define ATLASINT_END (ATLASINT_BASE+31)
++/*
++ * Interrupts 0..7 are used for Atlas CPU interrupts (nonEIC mode)
++ */
++#define MIPSCPU_INT_BASE 0
++
++/* CPU interrupt offsets */
++#define MIPSCPU_INT_SW0 0
++#define MIPSCPU_INT_SW1 1
++#define MIPSCPU_INT_MB0 2
++#define MIPSCPU_INT_ATLAS MIPSCPU_INT_MB0
++#define MIPSCPU_INT_MB1 3
++#define MIPSCPU_INT_MB2 4
++#define MIPSCPU_INT_MB3 5
++#define MIPSCPU_INT_MB4 6
++#define MIPSCPU_INT_CPUCTR 7
++
++/*
++ * Interrupts 8..39 are used for Atlas interrupt controller interrupts
++ */
++#define ATLAS_INT_BASE 8
++#define ATLAS_INT_UART (ATLAS_INT_BASE + 0)
++#define ATLAS_INT_TIM0 (ATLAS_INT_BASE + 1)
++#define ATLAS_INT_RES2 (ATLAS_INT_BASE + 2)
++#define ATLAS_INT_RES3 (ATLAS_INT_BASE + 3)
++#define ATLAS_INT_RTC (ATLAS_INT_BASE + 4)
++#define ATLAS_INT_COREHI (ATLAS_INT_BASE + 5)
++#define ATLAS_INT_CORELO (ATLAS_INT_BASE + 6)
++#define ATLAS_INT_RES7 (ATLAS_INT_BASE + 7)
++#define ATLAS_INT_PCIA (ATLAS_INT_BASE + 8)
++#define ATLAS_INT_PCIB (ATLAS_INT_BASE + 9)
++#define ATLAS_INT_PCIC (ATLAS_INT_BASE + 10)
++#define ATLAS_INT_PCID (ATLAS_INT_BASE + 11)
++#define ATLAS_INT_ENUM (ATLAS_INT_BASE + 12)
++#define ATLAS_INT_DEG (ATLAS_INT_BASE + 13)
++#define ATLAS_INT_ATXFAIL (ATLAS_INT_BASE + 14)
++#define ATLAS_INT_INTA (ATLAS_INT_BASE + 15)
++#define ATLAS_INT_INTB (ATLAS_INT_BASE + 16)
++#define ATLAS_INT_ETH ATLAS_INT_INTB
++#define ATLAS_INT_INTC (ATLAS_INT_BASE + 17)
++#define ATLAS_INT_SCSI ATLAS_INT_INTC
++#define ATLAS_INT_INTD (ATLAS_INT_BASE + 18)
++#define ATLAS_INT_SERR (ATLAS_INT_BASE + 19)
++#define ATLAS_INT_RES20 (ATLAS_INT_BASE + 20)
++#define ATLAS_INT_RES21 (ATLAS_INT_BASE + 21)
++#define ATLAS_INT_RES22 (ATLAS_INT_BASE + 22)
++#define ATLAS_INT_RES23 (ATLAS_INT_BASE + 23)
++#define ATLAS_INT_RES24 (ATLAS_INT_BASE + 24)
++#define ATLAS_INT_RES25 (ATLAS_INT_BASE + 25)
++#define ATLAS_INT_RES26 (ATLAS_INT_BASE + 26)
++#define ATLAS_INT_RES27 (ATLAS_INT_BASE + 27)
++#define ATLAS_INT_RES28 (ATLAS_INT_BASE + 28)
++#define ATLAS_INT_RES29 (ATLAS_INT_BASE + 29)
++#define ATLAS_INT_RES30 (ATLAS_INT_BASE + 30)
++#define ATLAS_INT_RES31 (ATLAS_INT_BASE + 31)
++#define ATLAS_INT_END (ATLAS_INT_BASE + 31)
++
++/*
++ * Interrupts 64..127 are used for Soc-it Classic interrupts
++ */
++#define MSC01C_INT_BASE 64
++
++/* SOC-it Classic interrupt offsets */
++#define MSC01C_INT_TMR 0
++#define MSC01C_INT_PCI 1
++
++/*
++ * Interrupts 64..127 are used for Soc-it EIC interrupts
++ */
++#define MSC01E_INT_BASE 64
++
++/* SOC-it EIC interrupt offsets */
++#define MSC01E_INT_SW0 1
++#define MSC01E_INT_SW1 2
++#define MSC01E_INT_MB0 3
++#define MSC01E_INT_ATLAS MSC01E_INT_MB0
++#define MSC01E_INT_MB1 4
++#define MSC01E_INT_MB2 5
++#define MSC01E_INT_MB3 6
++#define MSC01E_INT_MB4 7
++#define MSC01E_INT_TMR 8
++#define MSC01E_INT_PCI 9
++#define MSC01E_INT_PERFCTR 10
++#define MSC01E_INT_CPUCTR 11
+
+ #endif /* !(_MIPS_ATLASINT_H) */
+diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h
+index f637ce7..3e9468f 100644
+--- a/include/asm-mips/mipsmtregs.h
++++ b/include/asm-mips/mipsmtregs.h
+@@ -352,6 +352,8 @@ do { \
+ #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val)
+ #define read_vpe_c0_vpeconf0() mftc0(1, 2)
+ #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val)
++#define read_vpe_c0_count() mftc0(9, 0)
++#define write_vpe_c0_count(val) mttc0(9, 0, val)
+ #define read_vpe_c0_status() mftc0(12, 0)
+ #define write_vpe_c0_status(val) mttc0(12, 0, val)
+ #define read_vpe_c0_cause() mftc0(13, 0)
+diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
+index 18b69de..fe065d6 100644
+--- a/include/asm-mips/mmu_context.h
++++ b/include/asm-mips/mmu_context.h
+@@ -262,10 +262,10 @@ drop_mmu_context(struct mm_struct *mm, u
+ /* See comments for similar code above */
+ prevvpe = dvpe();
+ oldasid = (read_c0_entryhi() & ASID_MASK);
+- if(smtc_live_asid[mytlb][oldasid]) {
+- smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
+- if(smtc_live_asid[mytlb][oldasid] == 0)
+- smtc_flush_tlb_asid(oldasid);
++ if (smtc_live_asid[mytlb][oldasid]) {
++ smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
++ if(smtc_live_asid[mytlb][oldasid] == 0)
++ smtc_flush_tlb_asid(oldasid);
+ }
+ /* See comments for similar code above */
+ write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
+diff --git a/include/asm-mips/msc01_ic.h b/include/asm-mips/msc01_ic.h
+index 64f1720..aa7ad9a 100644
+--- a/include/asm-mips/msc01_ic.h
++++ b/include/asm-mips/msc01_ic.h
+@@ -145,7 +145,7 @@ typedef struct msc_irqmap {
+ #define MSC01_IRQ_EDGE 1
+
+ extern void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq);
+-extern void ll_msc_irq(struct pt_regs *regs);
++extern void ll_msc_irq(void);
+
+ #endif /* __ASM_MIPS_BOARDS_MSC01_IC_H */
+
+diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
+index 219d359..85b258e 100644
+--- a/include/asm-mips/page.h
++++ b/include/asm-mips/page.h
+@@ -34,6 +34,8 @@
+
+ #ifndef __ASSEMBLY__
+
++#include <asm/cpu-features.h>
++
+ extern void clear_page(void * page);
+ extern void copy_page(void * to, void * from);
+
+@@ -53,7 +55,7 @@ static inline void clear_user_page(void
+ extern void (*flush_data_cache_page)(unsigned long addr);
+
+ clear_page(addr);
+- if (pages_do_alias((unsigned long) addr, vaddr))
++ if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK))
+ flush_data_cache_page((unsigned long)addr);
+ }
+
+@@ -63,7 +65,8 @@ static inline void copy_user_page(void *
+ extern void (*flush_data_cache_page)(unsigned long addr);
+
+ copy_page(vto, vfrom);
+- if (pages_do_alias((unsigned long)vto, vaddr))
++ if (!cpu_has_ic_fills_f_dc ||
++ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+ flush_data_cache_page((unsigned long)vto);
+ }
+
+@@ -74,15 +77,17 @@ static inline void copy_user_page(void *
+ #ifdef CONFIG_CPU_MIPS32
+ typedef struct { unsigned long pte_low, pte_high; } pte_t;
+ #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
++ #define __pte(x) ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; })
+ #else
+ typedef struct { unsigned long long pte; } pte_t;
+ #define pte_val(x) ((x).pte)
++ #define __pte(x) ((pte_t) { (x) } )
+ #endif
+ #else
+ typedef struct { unsigned long pte; } pte_t;
+ #define pte_val(x) ((x).pte)
+-#endif
+ #define __pte(x) ((pte_t) { (x) } )
++#endif
+
+ /*
+ * For 3-level pagetables we defines these ourselves, for 2-level the
+diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h
+index 582c1fe..af121c6 100644
+--- a/include/asm-mips/pgalloc.h
++++ b/include/asm-mips/pgalloc.h
+@@ -48,7 +48,7 @@ static inline pgd_t *pgd_alloc(struct mm
+
+ ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER);
+ if (ret) {
+- init = pgd_offset(&init_mm, 0);
++ init = pgd_offset(&init_mm, 0UL);
+ pgd_init((unsigned long)ret);
+ memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h
+index 4b26d85..d20f2e9 100644
+--- a/include/asm-mips/pgtable-32.h
++++ b/include/asm-mips/pgtable-32.h
+@@ -156,9 +156,9 @@ pfn_pte(unsigned long pfn, pgprot_t prot
+ #define __pte_offset(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset(dir, address) \
+- ((pte_t *) (pmd_page_kernel(*dir)) + __pte_offset(address))
++ ((pte_t *) (pmd_page_vaddr(*dir)) + __pte_offset(address))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
+
+ #define pte_offset_map(dir, address) \
+ ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
+diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h
+index e3db932..7e73203 100644
+--- a/include/asm-mips/pgtable-64.h
++++ b/include/asm-mips/pgtable-64.h
+@@ -93,8 +93,12 @@
+ #define PTRS_PER_PMD ((PAGE_SIZE << PMD_ORDER) / sizeof(pmd_t))
+ #define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
+
++#if PGDIR_SIZE >= TASK_SIZE
++#define USER_PTRS_PER_PGD (1)
++#else
+ #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
+-#define FIRST_USER_ADDRESS 0
++#endif
++#define FIRST_USER_ADDRESS 0UL
+
+ #define VMALLOC_START MAP_BASE
+ #define VMALLOC_END \
+@@ -170,7 +174,7 @@ static inline void pud_clear(pud_t *pudp
+ #define __pmd_offset(address) pmd_index(address)
+
+ /* to find an entry in a kernel page-table-directory */
+-#define pgd_offset_k(address) pgd_offset(&init_mm, 0)
++#define pgd_offset_k(address) pgd_offset(&init_mm, 0UL)
+
+ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+ #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+@@ -178,24 +182,26 @@ static inline void pud_clear(pud_t *pudp
+ /* to find an entry in a page-table-directory */
+ #define pgd_offset(mm,addr) ((mm)->pgd + pgd_index(addr))
+
+-static inline unsigned long pud_page(pud_t pud)
++static inline unsigned long pud_page_vaddr(pud_t pud)
+ {
+ return pud_val(pud);
+ }
++#define pud_phys(pud) (pud_val(pud) - PAGE_OFFSET)
++#define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT))
+
+ /* Find an entry in the second-level page table.. */
+ static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address)
+ {
+- return (pmd_t *) pud_page(*pud) + pmd_index(address);
++ return (pmd_t *) pud_page_vaddr(*pud) + pmd_index(address);
+ }
+
+ /* Find an entry in the third-level page table.. */
+ #define __pte_offset(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset(dir, address) \
+- ((pte_t *) (pmd_page_kernel(*dir)) + __pte_offset(address))
++ ((pte_t *) (pmd_page_vaddr(*dir)) + __pte_offset(address))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
+ #define pte_offset_map(dir, address) \
+ ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
+ #define pte_offset_map_nested(dir, address) \
+diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
+index a36ca1b..1ca4d1e 100644
+--- a/include/asm-mips/pgtable.h
++++ b/include/asm-mips/pgtable.h
+@@ -87,7 +87,7 @@ extern void paging_init(void);
+ */
+ #define pmd_phys(pmd) (pmd_val(pmd) - PAGE_OFFSET)
+ #define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
+-#define pmd_page_kernel(pmd) pmd_val(pmd)
++#define pmd_page_vaddr(pmd) pmd_val(pmd)
+
+ #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+
+diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
+index 4113316..5f3a907 100644
+--- a/include/asm-mips/ptrace.h
++++ b/include/asm-mips/ptrace.h
+@@ -10,8 +10,6 @@
+ #define _ASM_PTRACE_H
+
+
+-#include <asm/isadep.h>
+-
+ /* 0 - 31 are integer registers, 32 - 63 are fp registers. */
+ #define FPR_BASE 32
+ #define PC 64
+@@ -46,9 +44,8 @@ struct pt_regs {
+ unsigned long cp0_epc;
+ #ifdef CONFIG_MIPS_MT_SMTC
+ unsigned long cp0_tcstatus;
+- unsigned long smtc_pad;
+ #endif /* CONFIG_MIPS_MT_SMTC */
+-};
++} __attribute__ ((aligned (8)));
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+ #define PTRACE_GETREGS 12
+@@ -73,6 +70,7 @@ struct pt_regs {
+ #ifdef __KERNEL__
+
+ #include <linux/linkage.h>
++#include <asm/isadep.h>
+
+ /*
+ * Does the process account for user or for system time?
+diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h
+index 584bd9c..d7a6513 100644
+--- a/include/asm-mips/serial.h
++++ b/include/asm-mips/serial.h
+@@ -52,54 +52,21 @@
+ #endif
+
+ /*
+- * Both Galileo boards have the same UART mappings.
++ * Galileo EV64120 evaluation board
+ */
+-#if defined (CONFIG_MIPS_EV96100) || defined (CONFIG_MIPS_EV64120)
+-#include <asm/galileo-boards/ev96100.h>
+-#include <asm/galileo-boards/ev96100int.h>
+-#define EV96100_SERIAL_PORT_DEFNS \
+- { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \
++#ifdef CONFIG_MIPS_EV64120
++#include <mach-gt64120.h>
++#define EV64120_SERIAL_PORT_DEFNS \
++ { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \
+ .flags = STD_COM_FLAGS, \
+- .iomem_base = EV96100_UART0_REGS_BASE, .iomem_reg_shift = 2, \
++ .iomem_base = EV64120_UART0_REGS_BASE, .iomem_reg_shift = 2, \
+ .io_type = SERIAL_IO_MEM }, \
+- { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \
++ { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \
+ .flags = STD_COM_FLAGS, \
+- .iomem_base = EV96100_UART1_REGS_BASE, .iomem_reg_shift = 2, \
++ .iomem_base = EV64120_UART1_REGS_BASE, .iomem_reg_shift = 2, \
+ .io_type = SERIAL_IO_MEM },
+ #else
+-#define EV96100_SERIAL_PORT_DEFNS
+-#endif
+-
+-#ifdef CONFIG_MIPS_ITE8172
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_int.h>
+-#include <asm/it8712.h>
+-#define ITE_SERIAL_PORT_DEFNS \
+- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \
+- .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
+- { .baud_base = (24000000/(16*13)), .port = (IT8172_PCI_IO_BASE + IT8712_UART1_PORT), \
+- .irq = IT8172_SERIRQ_4, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
+- /* Smart Card Reader 0 */ \
+- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR0_BASE), \
+- .irq = IT8172_SCR0_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
+- /* Smart Card Reader 1 */ \
+- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \
+- .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 },
+-#else
+-#define ITE_SERIAL_PORT_DEFNS
+-#endif
+-
+-#ifdef CONFIG_MIPS_IVR
+-#include <asm/it8172/it8172.h>
+-#include <asm/it8172/it8172_int.h>
+-#define IVR_SERIAL_PORT_DEFNS \
+- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \
+- .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
+- /* Smart Card Reader 1 */ \
+- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \
+- .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 },
+-#else
+-#define IVR_SERIAL_PORT_DEFNS
++#define EV64120_SERIAL_PORT_DEFNS
+ #endif
+
+ #ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT
+@@ -239,10 +206,8 @@
+
+ #define SERIAL_PORT_DFNS \
+ DDB5477_SERIAL_PORT_DEFNS \
+- EV96100_SERIAL_PORT_DEFNS \
++ EV64120_SERIAL_PORT_DEFNS \
+ IP32_SERIAL_PORT_DEFNS \
+- ITE_SERIAL_PORT_DEFNS \
+- IVR_SERIAL_PORT_DEFNS \
+ JAZZ_SERIAL_PORT_DEFNS \
+ STD_SERIAL_PORT_DEFNS \
+ MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \
+diff --git a/include/asm-mips/sibyte/sb1250.h b/include/asm-mips/sibyte/sb1250.h
+index b09e16c..2ba6988 100644
+--- a/include/asm-mips/sibyte/sb1250.h
++++ b/include/asm-mips/sibyte/sb1250.h
+@@ -51,8 +51,8 @@ extern void sb1250_mask_irq(int cpu, int
+ extern void sb1250_unmask_irq(int cpu, int irq);
+ extern void sb1250_smp_finish(void);
+
++extern void bcm1480_hpt_setup(void);
+ extern void bcm1480_time_init(void);
+-extern unsigned long bcm1480_gettimeoffset(void);
+ extern void bcm1480_mask_irq(int cpu, int irq);
+ extern void bcm1480_unmask_irq(int cpu, int irq);
+ extern void bcm1480_smp_finish(void);
+diff --git a/include/asm-mips/sibyte/sb1250_defs.h b/include/asm-mips/sibyte/sb1250_defs.h
+index 335dbaf..a885491 100644
+--- a/include/asm-mips/sibyte/sb1250_defs.h
++++ b/include/asm-mips/sibyte/sb1250_defs.h
+@@ -212,7 +212,7 @@
+ * Note: you'll need to define uint32_t and uint64_t in your headers.
+ */
+
+-#if !defined(__ASSEMBLER__)
++#if !defined(__ASSEMBLY__)
+ #define _SB_MAKE64(x) ((uint64_t)(x))
+ #define _SB_MAKE32(x) ((uint32_t)(x))
+ #else
+@@ -251,9 +251,9 @@
+ */
+
+
+-#if defined(__mips64) && !defined(__ASSEMBLER__)
++#if defined(__mips64) && !defined(__ASSEMBLY__)
+ #define SBWRITECSR(csr,val) *((volatile uint64_t *) PHYS_TO_K1(csr)) = (val)
+ #define SBREADCSR(csr) (*((volatile uint64_t *) PHYS_TO_K1(csr)))
+-#endif /* __ASSEMBLER__ */
++#endif /* __ASSEMBLY__ */
+
+ #endif
+diff --git a/include/asm-mips/sibyte/sb1250_scd.h b/include/asm-mips/sibyte/sb1250_scd.h
+index f4178bd..7ed0bb6 100644
+--- a/include/asm-mips/sibyte/sb1250_scd.h
++++ b/include/asm-mips/sibyte/sb1250_scd.h
+@@ -149,7 +149,7 @@
+ * (For the assembler version, sysrev and dest may be the same register.
+ * Also, it clobbers AT.)
+ */
+-#ifdef __ASSEMBLER__
++#ifdef __ASSEMBLY__
+ #define SYS_SOC_TYPE(dest, sysrev) \
+ .set push ; \
+ .set reorder ; \
+diff --git a/include/asm-mips/signal.h b/include/asm-mips/signal.h
+index 87a1dff..8b391a2 100644
+--- a/include/asm-mips/signal.h
++++ b/include/asm-mips/signal.h
+@@ -108,17 +108,8 @@ typedef unsigned long old_sigset_t; /*
+ #define SIG_BLOCK 1 /* for blocking signals */
+ #define SIG_UNBLOCK 2 /* for unblocking signals */
+ #define SIG_SETMASK 3 /* for setting the signal mask */
+-#define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility:
+- set only the low 32 bit of the sigset. */
+
+-/* Type of a signal handler. */
+-typedef void __signalfn_t(int);
+-typedef __signalfn_t __user *__sighandler_t;
+-
+-/* Fake signal functions */
+-#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 */
++#include <asm-generic/signal.h>
+
+ struct sigaction {
+ unsigned int sa_flags;
+diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
+index 669b8e3..c8d5587 100644
+--- a/include/asm-mips/spinlock.h
++++ b/include/asm-mips/spinlock.h
+@@ -239,7 +239,51 @@ static inline void __raw_write_unlock(ra
+ : "memory");
+ }
+
+-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
++static inline int __raw_read_trylock(raw_rwlock_t *rw)
++{
++ unsigned int tmp;
++ int ret;
++
++ if (R10000_LLSC_WAR) {
++ __asm__ __volatile__(
++ " .set noreorder # __raw_read_trylock \n"
++ " li %2, 0 \n"
++ "1: ll %1, %3 \n"
++ " bnez %1, 2f \n"
++ " addu %1, 1 \n"
++ " sc %1, %0 \n"
++ " beqzl %1, 1b \n"
++ " .set reorder \n"
++#ifdef CONFIG_SMP
++ " sync \n"
++#endif
++ " li %2, 1 \n"
++ "2: \n"
++ : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
++ : "m" (rw->lock)
++ : "memory");
++ } else {
++ __asm__ __volatile__(
++ " .set noreorder # __raw_read_trylock \n"
++ " li %2, 0 \n"
++ "1: ll %1, %3 \n"
++ " bnez %1, 2f \n"
++ " addu %1, 1 \n"
++ " sc %1, %0 \n"
++ " beqz %1, 1b \n"
++ " .set reorder \n"
++#ifdef CONFIG_SMP
++ " sync \n"
++#endif
++ " li %2, 1 \n"
++ "2: \n"
++ : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
++ : "m" (rw->lock)
++ : "memory");
++ }
++
++ return ret;
++}
+
+ static inline int __raw_write_trylock(raw_rwlock_t *rw)
+ {
+@@ -283,4 +327,9 @@ static inline int __raw_write_trylock(ra
+ return ret;
+ }
+
++
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* _ASM_SPINLOCK_H */
+diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
+index 158a4cd..1fae5dc 100644
+--- a/include/asm-mips/stackframe.h
++++ b/include/asm-mips/stackframe.h
+@@ -59,69 +59,43 @@
+ .endm
+
+ #ifdef CONFIG_SMP
+- .macro get_saved_sp /* SMP variation */
+-#ifdef CONFIG_32BIT
+ #ifdef CONFIG_MIPS_MT_SMTC
+- .set mips32
+- mfc0 k0, CP0_TCBIND;
+- .set mips0
+- lui k1, %hi(kernelsp)
+- srl k0, k0, 19
+- /* No need to shift down and up to clear bits 0-1 */
++#define PTEBASE_SHIFT 19 /* TCBIND */
+ #else
+- mfc0 k0, CP0_CONTEXT
+- lui k1, %hi(kernelsp)
+- srl k0, k0, 23
+-#endif
+- addu k1, k0
+- LONG_L k1, %lo(kernelsp)(k1)
++#define PTEBASE_SHIFT 23 /* CONTEXT */
+ #endif
+-#ifdef CONFIG_64BIT
++ .macro get_saved_sp /* SMP variation */
+ #ifdef CONFIG_MIPS_MT_SMTC
+- .set mips64
+- mfc0 k0, CP0_TCBIND;
+- .set mips0
+- lui k0, %highest(kernelsp)
+- dsrl k1, 19
+- /* No need to shift down and up to clear bits 0-2 */
++ mfc0 k0, CP0_TCBIND
+ #else
+- MFC0 k1, CP0_CONTEXT
+- lui k0, %highest(kernelsp)
+- dsrl k1, 23
+- daddiu k0, %higher(kernelsp)
+- dsll k0, k0, 16
+- daddiu k0, %hi(kernelsp)
+- dsll k0, k0, 16
+-#endif /* CONFIG_MIPS_MT_SMTC */
+- daddu k1, k1, k0
++ MFC0 k0, CP0_CONTEXT
++#endif
++#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4)
++ lui k1, %highest(kernelsp)
++ daddiu k1, %higher(kernelsp)
++ dsll k1, 16
++ daddiu k1, %hi(kernelsp)
++ dsll k1, 16
++#else
++ lui k1, %hi(kernelsp)
++#endif
++ LONG_SRL k0, PTEBASE_SHIFT
++ LONG_ADDU k1, k0
+ LONG_L k1, %lo(kernelsp)(k1)
+-#endif /* CONFIG_64BIT */
+ .endm
+
+ .macro set_saved_sp stackp temp temp2
+-#ifdef CONFIG_32BIT
+-#ifdef CONFIG_MIPS_MT_SMTC
+- mfc0 \temp, CP0_TCBIND
+- srl \temp, 19
+-#else
+- mfc0 \temp, CP0_CONTEXT
+- srl \temp, 23
+-#endif
+-#endif
+-#ifdef CONFIG_64BIT
+ #ifdef CONFIG_MIPS_MT_SMTC
+ mfc0 \temp, CP0_TCBIND
+- dsrl \temp, 19
+ #else
+ MFC0 \temp, CP0_CONTEXT
+- dsrl \temp, 23
+-#endif
+ #endif
++ LONG_SRL \temp, PTEBASE_SHIFT
+ LONG_S \stackp, kernelsp(\temp)
+ .endm
+ #else
+ .macro get_saved_sp /* Uniprocessor variation */
+-#ifdef CONFIG_64BIT
++#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4)
+ lui k1, %highest(kernelsp)
+ daddiu k1, %higher(kernelsp)
+ dsll k1, k1, 16
+diff --git a/include/asm-mips/stacktrace.h b/include/asm-mips/stacktrace.h
+new file mode 100644
+index 0000000..07f8733
+--- /dev/null
++++ b/include/asm-mips/stacktrace.h
+@@ -0,0 +1,44 @@
++#ifndef _ASM_STACKTRACE_H
++#define _ASM_STACKTRACE_H
++
++#include <asm/ptrace.h>
++
++#ifdef CONFIG_KALLSYMS
++extern int raw_show_trace;
++extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
++ unsigned long pc, unsigned long *ra);
++#else
++#define raw_show_trace 1
++#define unwind_stack(task, sp, pc, ra) 0
++#endif
++
++static __always_inline void prepare_frametrace(struct pt_regs *regs)
++{
++#ifndef CONFIG_KALLSYMS
++ /*
++ * Remove any garbage that may be in regs (specially func
++ * addresses) to avoid show_raw_backtrace() to report them
++ */
++ memset(regs, 0, sizeof(*regs));
++#endif
++ __asm__ __volatile__(
++ ".set push\n\t"
++ ".set noat\n\t"
++#ifdef CONFIG_64BIT
++ "1: dla $1, 1b\n\t"
++ "sd $1, %0\n\t"
++ "sd $29, %1\n\t"
++ "sd $31, %2\n\t"
++#else
++ "1: la $1, 1b\n\t"
++ "sw $1, %0\n\t"
++ "sw $29, %1\n\t"
++ "sw $31, %2\n\t"
++#endif
++ ".set pop\n\t"
++ : "=m" (regs->cp0_epc),
++ "=m" (regs->regs[29]), "=m" (regs->regs[31])
++ : : "memory");
++}
++
++#endif /* _ASM_STACKTRACE_H */
+diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
+index dcb4701..3056fee 100644
+--- a/include/asm-mips/system.h
++++ b/include/asm-mips/system.h
+@@ -392,7 +392,7 @@ static inline unsigned long __cmpxchg_u6
+ {
+ __u64 retval;
+
+- if (cpu_has_llsc) {
++ if (cpu_has_llsc && R10000_LLSC_WAR) {
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noat \n"
+diff --git a/include/asm-mips/termbits.h b/include/asm-mips/termbits.h
+index fa6d04d..b62ec7c 100644
+--- a/include/asm-mips/termbits.h
++++ b/include/asm-mips/termbits.h
+@@ -3,7 +3,7 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 1995, 1996, 1999, 2001 Ralf Baechle
++ * Copyright (C) 1995, 96, 99, 2001, 06 Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+@@ -13,14 +13,8 @@
+ #include <linux/posix_types.h>
+
+ typedef unsigned char cc_t;
+-#if (_MIPS_SZLONG == 32)
+-typedef unsigned long speed_t;
+-typedef unsigned long tcflag_t;
+-#endif
+-#if (_MIPS_SZLONG == 64)
+-typedef __u32 speed_t;
+-typedef __u32 tcflag_t;
+-#endif
++typedef unsigned int speed_t;
++typedef unsigned int tcflag_t;
+
+ /*
+ * The ABI says nothing about NCC but seems to use NCCS as
+diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
+index ae8ada5..e475c45 100644
+--- a/include/asm-mips/thread_info.h
++++ b/include/asm-mips/thread_info.h
+@@ -34,6 +34,7 @@ struct thread_info {
+ 0-0xFFFFFFFF for kernel-thread
+ */
+ struct restart_block restart_block;
++ struct pt_regs *regs;
+ };
+
+ /*
+diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
+index 2d54373..625acd3 100644
+--- a/include/asm-mips/time.h
++++ b/include/asm-mips/time.h
+@@ -48,7 +48,8 @@ extern void (*mips_timer_ack)(void);
+ * If mips_hpt_read is NULL, an R4k-compatible timer setup is attempted.
+ */
+ extern unsigned int (*mips_hpt_read)(void);
+-extern void (*mips_hpt_init)(unsigned int);
++extern void (*mips_hpt_init)(void);
++extern unsigned int mips_hpt_mask;
+
+ /*
+ * to_tm() converts system time back to (year, mon, day, hour, min, sec).
+@@ -58,27 +59,20 @@ extern void (*mips_hpt_init)(unsigned in
+ extern void to_tm(unsigned long tim, struct rtc_time *tm);
+
+ /*
+- * do_gettimeoffset(). By default, this func pointer points to
+- * do_null_gettimeoffset(), which leads to the same resolution as HZ.
+- * Higher resolution versions are available, which give ~1us resolution.
+- */
+-extern unsigned long (*do_gettimeoffset)(void);
+-
+-/*
+ * high-level timer interrupt routines.
+ */
+-extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t timer_interrupt(int irq, void *dev_id);
+
+ /*
+ * the corresponding low-level timer interrupt routine.
+ */
+-extern asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs);
++extern asmlinkage void ll_timer_interrupt(int irq);
+
+ /*
+ * profiling and process accouting is done separately in local_timer_interrupt
+ */
+-extern void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-extern asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs);
++extern void local_timer_interrupt(int irq, void *dev_id);
++extern asmlinkage void ll_local_timer_interrupt(int irq);
+
+ /*
+ * board specific routines required by time_init().
+diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h
+index 98aa737..b80de8e 100644
+--- a/include/asm-mips/timex.h
++++ b/include/asm-mips/timex.h
+@@ -8,6 +8,8 @@
+ #ifndef _ASM_TIMEX_H
+ #define _ASM_TIMEX_H
+
++#ifdef __KERNEL__
++
+ #include <asm/mipsregs.h>
+
+ /*
+@@ -51,4 +53,6 @@ static inline cycles_t get_cycles (void)
+ return read_c0_count();
+ }
+
++#endif /* __KERNEL__ */
++
+ #endif /* _ASM_TIMEX_H */
+diff --git a/include/asm-mips/tx4938/tx4938_mips.h b/include/asm-mips/tx4938/tx4938_mips.h
+index cf89b20..5f8498f 100644
+--- a/include/asm-mips/tx4938/tx4938_mips.h
++++ b/include/asm-mips/tx4938/tx4938_mips.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-mips/tx4938/tx4938_bitmask.h
++ * linux/include/asm-mips/tx4938/tx4938_mips.h
+ * Generic bitmask definitions
+ *
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
+index 610ccb8..ec56aa5 100644
+--- a/include/asm-mips/unistd.h
++++ b/include/asm-mips/unistd.h
+@@ -313,7 +313,7 @@
+ #define __NR_mknodat (__NR_Linux + 290)
+ #define __NR_fchownat (__NR_Linux + 291)
+ #define __NR_futimesat (__NR_Linux + 292)
+-#define __NR_fstatat (__NR_Linux + 293)
++#define __NR_fstatat64 (__NR_Linux + 293)
+ #define __NR_unlinkat (__NR_Linux + 294)
+ #define __NR_renameat (__NR_Linux + 295)
+ #define __NR_linkat (__NR_Linux + 296)
+@@ -329,16 +329,21 @@
+ #define __NR_tee (__NR_Linux + 306)
+ #define __NR_vmsplice (__NR_Linux + 307)
+ #define __NR_move_pages (__NR_Linux + 308)
++#define __NR_set_robust_list (__NR_Linux + 309)
++#define __NR_get_robust_list (__NR_Linux + 310)
++#define __NR_kexec_load (__NR_Linux + 311)
++#define __NR_getcpu (__NR_Linux + 312)
++#define __NR_epoll_pwait (__NR_Linux + 313)
+
+ /*
+ * Offset of the last Linux o32 flavoured syscall
+ */
+-#define __NR_Linux_syscalls 308
++#define __NR_Linux_syscalls 313
+
+ #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
+
+ #define __NR_O32_Linux 4000
+-#define __NR_O32_Linux_syscalls 308
++#define __NR_O32_Linux_syscalls 313
+
+ #if _MIPS_SIM == _MIPS_SIM_ABI64
+
+@@ -598,7 +603,7 @@
+ #define __NR_mknodat (__NR_Linux + 249)
+ #define __NR_fchownat (__NR_Linux + 250)
+ #define __NR_futimesat (__NR_Linux + 251)
+-#define __NR_fstatat (__NR_Linux + 252)
++#define __NR_newfstatat (__NR_Linux + 252)
+ #define __NR_unlinkat (__NR_Linux + 253)
+ #define __NR_renameat (__NR_Linux + 254)
+ #define __NR_linkat (__NR_Linux + 255)
+@@ -614,16 +619,21 @@
+ #define __NR_tee (__NR_Linux + 265)
+ #define __NR_vmsplice (__NR_Linux + 266)
+ #define __NR_move_pages (__NR_Linux + 267)
++#define __NR_set_robust_list (__NR_Linux + 268)
++#define __NR_get_robust_list (__NR_Linux + 269)
++#define __NR_kexec_load (__NR_Linux + 270)
++#define __NR_getcpu (__NR_Linux + 271)
++#define __NR_epoll_pwait (__NR_Linux + 272)
+
+ /*
+ * Offset of the last Linux 64-bit flavoured syscall
+ */
+-#define __NR_Linux_syscalls 267
++#define __NR_Linux_syscalls 272
+
+ #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
+
+ #define __NR_64_Linux 5000
+-#define __NR_64_Linux_syscalls 267
++#define __NR_64_Linux_syscalls 272
+
+ #if _MIPS_SIM == _MIPS_SIM_NABI32
+
+@@ -887,7 +897,7 @@
+ #define __NR_mknodat (__NR_Linux + 253)
+ #define __NR_fchownat (__NR_Linux + 254)
+ #define __NR_futimesat (__NR_Linux + 255)
+-#define __NR_fstatat (__NR_Linux + 256)
++#define __NR_newfstatat (__NR_Linux + 256)
+ #define __NR_unlinkat (__NR_Linux + 257)
+ #define __NR_renameat (__NR_Linux + 258)
+ #define __NR_linkat (__NR_Linux + 259)
+@@ -903,16 +913,21 @@
+ #define __NR_tee (__NR_Linux + 269)
+ #define __NR_vmsplice (__NR_Linux + 270)
+ #define __NR_move_pages (__NR_Linux + 271)
++#define __NR_set_robust_list (__NR_Linux + 272)
++#define __NR_get_robust_list (__NR_Linux + 273)
++#define __NR_kexec_load (__NR_Linux + 274)
++#define __NR_getcpu (__NR_Linux + 275)
++#define __NR_epoll_pwait (__NR_Linux + 276)
+
+ /*
+ * Offset of the last N32 flavoured syscall
+ */
+-#define __NR_Linux_syscalls 271
++#define __NR_Linux_syscalls 276
+
+ #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
+
+ #define __NR_N32_Linux 6000
+-#define __NR_N32_Linux_syscalls 271
++#define __NR_N32_Linux_syscalls 276
+
+ #ifdef __KERNEL__
+
+@@ -1180,6 +1195,7 @@ type name (atype a,btype b,ctype c,dtype
+ #endif /* (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64) */
+
+
++#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
+ #define __ARCH_WANT_IPC_PARSE_VERSION
+ #define __ARCH_WANT_OLD_READDIR
+ #define __ARCH_WANT_SYS_ALARM
+@@ -1206,45 +1222,6 @@ type name (atype a,btype b,ctype c,dtype
+ # define __ARCH_WANT_COMPAT_SYS_TIME
+ # endif
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/linkage.h>
+-#include <asm/ptrace.h>
+-#include <asm/sim.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-
+-asmlinkage unsigned long sys_mmap(
+- unsigned long addr, size_t len,
+- int prot, int flags,
+- int fd, off_t offset);
+-asmlinkage long sys_mmap2(
+- unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs);
+-asmlinkage int sys_pipe(nabi_no_regargs struct pt_regs regs);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+ #endif /* !__ASSEMBLY__ */
+
+ /*
+diff --git a/include/asm-mips/user.h b/include/asm-mips/user.h
+index 89bf8b4..61f2a09 100644
+--- a/include/asm-mips/user.h
++++ b/include/asm-mips/user.h
+@@ -8,6 +8,8 @@
+ #ifndef _ASM_USER_H
+ #define _ASM_USER_H
+
++#ifdef __KERNEL__
++
+ #include <asm/page.h>
+ #include <asm/reg.h>
+
+@@ -55,4 +57,6 @@ struct user {
+ #define HOST_DATA_START_ADDR (u.start_data)
+ #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
++#endif /* __KERNEL__ */
++
+ #endif /* _ASM_USER_H */
+diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h
+index dd3eb3d..88b492f 100644
+--- a/include/asm-mips/vr41xx/vr41xx.h
++++ b/include/asm-mips/vr41xx/vr41xx.h
+@@ -75,7 +75,7 @@ extern void vr41xx_mask_clock(vr41xx_clo
+ * Interrupt Control Unit
+ */
+ extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign);
+-extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *));
++extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int));
+
+ #define PIUINT_COMMAND 0x0040
+ #define PIUINT_DATA 0x0020
+diff --git a/include/asm-parisc/agp.h b/include/asm-parisc/agp.h
+new file mode 100644
+index 0000000..9f61d4e
+--- /dev/null
++++ b/include/asm-parisc/agp.h
+@@ -0,0 +1,25 @@
++#ifndef _ASM_PARISC_AGP_H
++#define _ASM_PARISC_AGP_H
++
++/*
++ * PARISC specific AGP definitions.
++ * Copyright (c) 2006 Kyle McMartin <kyle at parisc-linux.org>
++ *
++ */
++
++#define map_page_into_agp(page) /* nothing */
++#define unmap_page_from_agp(page) /* nothing */
++#define flush_agp_mappings() /* nothing */
++#define flush_agp_cache() mb()
++
++/* Convert a physical address to an address suitable for the GART. */
++#define phys_to_gart(x) (x)
++#define gart_to_phys(x) (x)
++
++/* GATT allocation. Returns/accepts GATT kernel virtual address. */
++#define alloc_gatt_pages(order) \
++ ((char *)__get_free_pages(GFP_KERNEL, (order)))
++#define free_gatt_pages(table, order) \
++ free_pages((unsigned long)(table), (order))
++
++#endif /* _ASM_PARISC_AGP_H */
+diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
+index 1a7bfe6..5a1e0e8 100644
+--- a/include/asm-parisc/assembly.h
++++ b/include/asm-parisc/assembly.h
+@@ -29,7 +29,8 @@
+ #define LDREGX ldd,s
+ #define LDREGM ldd,mb
+ #define STREGM std,ma
+-#define SHRREG shrd
++#define SHRREG shrd
++#define SHLREG shld
+ #define RP_OFFSET 16
+ #define FRAME_SIZE 128
+ #define CALLEE_REG_FRAME_SIZE 144
+@@ -39,7 +40,8 @@
+ #define LDREGX ldwx,s
+ #define LDREGM ldwm
+ #define STREGM stwm
+-#define SHRREG shr
++#define SHRREG shr
++#define SHLREG shlw
+ #define RP_OFFSET 20
+ #define FRAME_SIZE 64
+ #define CALLEE_REG_FRAME_SIZE 128
+diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
+index 0b459cd..2bc41f2 100644
+--- a/include/asm-parisc/cacheflush.h
++++ b/include/asm-parisc/cacheflush.h
+@@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsig
+ }
+ #define ARCH_HAS_FLUSH_ANON_PAGE
+
+-static inline void
+-flush_kernel_dcache_page(struct page *page)
++#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
++void flush_kernel_dcache_page_addr(void *addr);
++static inline void flush_kernel_dcache_page(struct page *page)
+ {
+- flush_kernel_dcache_page_asm(page_address(page));
++ flush_kernel_dcache_page_addr(page_address(page));
+ }
+-#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+
+ #ifdef CONFIG_DEBUG_RODATA
+ void mark_rodata_ro(void);
+ #endif
+
++#ifdef CONFIG_PA8X00
++/* Only pa8800, pa8900 needs this */
++#define ARCH_HAS_KMAP
++
++void kunmap_parisc(void *addr);
++
++static inline void *kmap(struct page *page)
++{
++ might_sleep();
++ return page_address(page);
++}
++
++#define kunmap(page) kunmap_parisc(page_address(page))
++
++#define kmap_atomic(page, idx) page_address(page)
++
++#define kunmap_atomic(addr, idx) kunmap_parisc(addr)
++
++#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn))
++#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
++#endif
++
+ #endif /* _PARISC_CACHEFLUSH_H */
+
+diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
+index 71b4eee..fe85790 100644
+--- a/include/asm-parisc/compat.h
++++ b/include/asm-parisc/compat.h
+@@ -5,7 +5,7 @@
+ */
+ #include <linux/types.h>
+ #include <linux/sched.h>
+-#include <linux/personality.h>
++#include <linux/thread_info.h>
+
+ #define COMPAT_USER_HZ 100
+
+@@ -152,7 +152,7 @@ static __inline__ void __user *compat_al
+
+ static inline int __is_compat_task(struct task_struct *t)
+ {
+- return personality(t->personality) == PER_LINUX32;
++ return test_ti_thread_flag(t->thread_info, TIF_32BIT);
+ }
+
+ static inline int is_compat_task(void)
+diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h
+index 9979c3c..da2cf37 100644
+--- a/include/asm-parisc/dma.h
++++ b/include/asm-parisc/dma.h
+@@ -72,18 +72,13 @@
+ #define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
+ #define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG)
+
+-extern spinlock_t dma_spin_lock;
+-
+ static __inline__ unsigned long claim_dma_lock(void)
+ {
+- unsigned long flags;
+- spin_lock_irqsave(&dma_spin_lock, flags);
+- return flags;
++ return 0;
+ }
+
+ static __inline__ void release_dma_lock(unsigned long flags)
+ {
+- spin_unlock_irqrestore(&dma_spin_lock, flags);
+ }
+
+
+diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
+index 6a332a9..d84bbb2 100644
+--- a/include/asm-parisc/futex.h
++++ b/include/asm-parisc/futex.h
+@@ -1,6 +1,71 @@
+-#ifndef _ASM_FUTEX_H
+-#define _ASM_FUTEX_H
++#ifndef _ASM_PARISC_FUTEX_H
++#define _ASM_PARISC_FUTEX_H
+
+-#include <asm-generic/futex.h>
++#ifdef __KERNEL__
+
++#include <linux/futex.h>
++#include <asm/errno.h>
++#include <asm/uaccess.h>
++
++static inline int
++futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
++{
++ int op = (encoded_op >> 28) & 7;
++ int cmp = (encoded_op >> 24) & 15;
++ int oparg = (encoded_op << 8) >> 20;
++ int cmparg = (encoded_op << 20) >> 20;
++ int oldval = 0, ret;
++ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
++ oparg = 1 << oparg;
++
++ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
++ return -EFAULT;
++
++ inc_preempt_count();
++
++ switch (op) {
++ case FUTEX_OP_SET:
++ case FUTEX_OP_ADD:
++ case FUTEX_OP_OR:
++ case FUTEX_OP_ANDN:
++ case FUTEX_OP_XOR:
++ default:
++ ret = -ENOSYS;
++ }
++
++ dec_preempt_count();
++
++ if (!ret) {
++ switch (cmp) {
++ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
++ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
++ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
++ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
++ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
++ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
++ default: ret = -ENOSYS;
++ }
++ }
++ return ret;
++}
++
++/* Non-atomic version */
++static inline int
++futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
++{
++ int err = 0;
++ int uval;
++
++ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
++ return -EFAULT;
++
++ err = get_user(uval, uaddr);
++ if (err) return -EFAULT;
++ if (uval == oldval)
++ err = put_user(newval, uaddr);
++ if (err) return -EFAULT;
++ return uval;
++}
++
++#endif
+ #endif
+diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
+index b9eb245..c1963ce 100644
+--- a/include/asm-parisc/io.h
++++ b/include/asm-parisc/io.h
+@@ -134,7 +134,7 @@ extern inline void __iomem * ioremap(uns
+ }
+ #define ioremap_nocache(off, sz) ioremap((off), (sz))
+
+-extern void iounmap(void __iomem *addr);
++extern void iounmap(const volatile void __iomem *addr);
+
+ static inline unsigned char __raw_readb(const volatile void __iomem *addr)
+ {
+diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h
+deleted file mode 100644
+index 613390e..0000000
+--- a/include/asm-parisc/iosapic.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*
+-** This file is private to iosapic driver.
+-** If stuff needs to be used by another driver, move it to a common file.
+-**
+-** WARNING: fields most data structures here are ordered to make sure
+-** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
+-*/
+-
+-
+-/*
+-** I/O SAPIC init function
+-** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
+-** Call setup as part of per instance initialization.
+-** (ie *not* init_module() function unless only one is present.)
+-** fixup_irq is to initialize PCI IRQ line support and
+-** virtualize pcidev->irq value. To be called by pci_fixup_bus().
+-*/
+-extern void *iosapic_register(unsigned long hpa);
+-extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
+-
+-
+-#ifdef __IA64__
+-/*
+-** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter.
+-** and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field.
+-**
+-** IA64: PIB is handled by "Local SAPIC" (integrated in the processor).
+-*/
+-struct local_sapic_info {
+- struct local_sapic_info *lsi_next; /* point to next CPU info */
+- int *lsi_cpu_id; /* point to logical CPU id */
+- unsigned long *lsi_id_eid; /* point to IA-64 CPU id */
+- int *lsi_status; /* point to CPU status */
+- void *lsi_private; /* point to special info */
+-};
+-
+-/*
+-** "root" data structure which ties everything together.
+-** Should always be able to start with sapic_root and locate
+-** the desired information.
+-*/
+-struct sapic_info {
+- struct sapic_info *si_next; /* info is per cell */
+- int si_cellid; /* cell id */
+- unsigned int si_status; /* status */
+- char *si_pib_base; /* intr blk base address */
+- local_sapic_info_t *si_local_info;
+- io_sapic_info_t *si_io_info;
+- extint_info_t *si_extint_info;/* External Intr info */
+-};
+-
+-#endif /* IA64 */
+-
+diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
+index 5cae260..399c819 100644
+--- a/include/asm-parisc/irq.h
++++ b/include/asm-parisc/irq.h
+@@ -31,7 +31,7 @@ static __inline__ int irq_canonicalize(i
+ return (irq == 2) ? 9 : irq;
+ }
+
+-struct hw_interrupt_type;
++struct irq_chip;
+
+ /*
+ * Some useful "we don't have to do anything here" handlers. Should
+@@ -39,6 +39,8 @@ struct hw_interrupt_type;
+ */
+ void no_ack_irq(unsigned int irq);
+ void no_end_irq(unsigned int irq);
++void cpu_ack_irq(unsigned int irq);
++void cpu_end_irq(unsigned int irq);
+
+ extern int txn_alloc_irq(unsigned int nbits);
+ extern int txn_claim_irq(int);
+@@ -46,7 +48,7 @@ extern unsigned int txn_alloc_data(unsig
+ extern unsigned long txn_alloc_addr(unsigned int);
+ extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
+
+-extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
++extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
+ extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest);
+
+ /* soft power switch support (power.c) */
+diff --git a/include/asm-parisc/irq_regs.h b/include/asm-parisc/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-parisc/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-parisc/mckinley.h b/include/asm-parisc/mckinley.h
+new file mode 100644
+index 0000000..d1ea6f1
+--- /dev/null
++++ b/include/asm-parisc/mckinley.h
+@@ -0,0 +1,9 @@
++#ifndef ASM_PARISC_MCKINLEY_H
++#define ASM_PARISC_MCKINLEY_H
++#ifdef __KERNEL__
++
++/* declared in arch/parisc/kernel/setup.c */
++extern struct proc_dir_entry * proc_mckinley_root;
++
++#endif /*__KERNEL__*/
++#endif /*ASM_PARISC_MCKINLEY_H*/
+diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
+index 57d6d82..3567208 100644
+--- a/include/asm-parisc/page.h
++++ b/include/asm-parisc/page.h
+@@ -26,24 +26,10 @@
+
+ struct page;
+
+-extern void purge_kernel_dcache_page(unsigned long);
+-extern void copy_user_page_asm(void *to, void *from);
+-extern void clear_user_page_asm(void *page, unsigned long vaddr);
+-
+-static inline void
+-copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
+-{
+- copy_user_page_asm(vto, vfrom);
+- flush_kernel_dcache_page_asm(vto);
+- /* XXX: ppc flushes icache too, should we? */
+-}
+-
+-static inline void
+-clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+-{
+- purge_kernel_dcache_page((unsigned long)page);
+- clear_user_page_asm(page, vaddr);
+-}
++void copy_user_page_asm(void *to, void *from);
++void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
++ struct page *pg);
++void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+
+ /*
+ * These are used to make use of C type-checking..
+diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h
+index 07cb9b9..32e03d8 100644
+--- a/include/asm-parisc/param.h
++++ b/include/asm-parisc/param.h
+@@ -2,13 +2,9 @@
+ #define _ASMPARISC_PARAM_H
+
+ #ifdef __KERNEL__
+-# ifdef CONFIG_PA20
+-# define HZ 1000 /* Faster machines */
+-# else
+-# define HZ 100 /* Internal kernel timer frequency */
+-# endif
+-# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
+-# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
++#define HZ CONFIG_HZ
++#define USER_HZ 100 /* some user API use "ticks" */
++#define CLOCKS_PER_SEC (USER_HZ) /* like times() */
+ #endif
+
+ #ifndef HZ
+diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h
+index 1d247e3..e12624d 100644
+--- a/include/asm-parisc/parisc-device.h
++++ b/include/asm-parisc/parisc-device.h
+@@ -1,3 +1,6 @@
++#ifndef _ASM_PARISC_PARISC_DEVICE_H_
++#define _ASM_PARISC_PARISC_DEVICE_H_
++
+ #include <linux/device.h>
+
+ struct parisc_device {
+@@ -57,3 +60,5 @@ parisc_get_drvdata(struct parisc_device
+ }
+
+ extern struct bus_type parisc_bus_type;
++
++#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
+diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
+index 8b631f4..7b8ad11 100644
+--- a/include/asm-parisc/pci.h
++++ b/include/asm-parisc/pci.h
+@@ -293,4 +293,9 @@ static inline void pcibios_penalize_isa_
+ /* We don't need to penalize isa irq's */
+ }
+
++static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
++{
++ return channel ? 15 : 14;
++}
++
+ #endif /* __ASM_PARISC_PCI_H */
+diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h
+index c9b2e35..423c2b8 100644
+--- a/include/asm-parisc/pdc.h
++++ b/include/asm-parisc/pdc.h
+@@ -774,8 +774,6 @@ int pdc_sti_call(unsigned long func, uns
+ unsigned long inptr, unsigned long outputr,
+ unsigned long glob_cfg);
+
+-extern void pdc_init(void);
+-
+ static inline char * os_id_to_string(u16 os_id) {
+ switch(os_id) {
+ case OS_ID_NONE: return "No OS";
+diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
+index 5066c54..c0b61e0 100644
+--- a/include/asm-parisc/pgtable.h
++++ b/include/asm-parisc/pgtable.h
+@@ -303,7 +303,8 @@ static inline void pmd_clear(pmd_t *pmd)
+
+
+ #if PT_NLEVELS == 3
+-#define pgd_page(pgd) ((unsigned long) __va(pgd_address(pgd)))
++#define pgd_page_vaddr(pgd) ((unsigned long) __va(pgd_address(pgd)))
++#define pgd_page(pgd) virt_to_page((void *)pgd_page_vaddr(pgd))
+
+ /* For 64 bit we have three level tables */
+
+@@ -382,7 +383,7 @@ extern inline pte_t pte_modify(pte_t pte
+
+ #define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
+
+-#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_address(pmd)))
++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_address(pmd)))
+
+ #define __pmd_page(pmd) ((unsigned long) __va(pmd_address(pmd)))
+ #define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd))
+@@ -400,7 +401,7 @@ extern inline pte_t pte_modify(pte_t pte
+
+ #if PT_NLEVELS == 3
+ #define pmd_offset(dir,address) \
+-((pmd_t *) pgd_page(*(dir)) + (((address)>>PMD_SHIFT) & (PTRS_PER_PMD-1)))
++((pmd_t *) pgd_page_vaddr(*(dir)) + (((address)>>PMD_SHIFT) & (PTRS_PER_PMD-1)))
+ #else
+ #define pmd_offset(dir,addr) ((pmd_t *) dir)
+ #endif
+@@ -408,7 +409,7 @@ extern inline pte_t pte_modify(pte_t pte
+ /* Find an entry in the third-level page table.. */
+ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
+ #define pte_offset_kernel(pmd, address) \
+- ((pte_t *) pmd_page_kernel(*(pmd)) + pte_index(address))
++ ((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address))
+ #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
+ #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
+ #define pte_unmap(pte) do { } while (0)
+diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h
+new file mode 100644
+index 0000000..5d02172
+--- /dev/null
++++ b/include/asm-parisc/prefetch.h
+@@ -0,0 +1,39 @@
++/*
++ * include/asm-parisc/prefetch.h
++ *
++ * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
++ * In addition, many implementations do hardware prefetching of both
++ * instructions and data.
++ *
++ * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
++ * to gr0 but not in a way that Linux can use. If the load would cause an
++ * interruption (eg due to prefetching 0), it is suppressed on PA2.0
++ * processors, but not on 7300LC.
++ *
++ */
++
++#ifndef __ASM_PARISC_PREFETCH_H
++#define __ASM_PARISC_PREFETCH_H
++
++#ifndef __ASSEMBLY__
++#ifdef CONFIG_PREFETCH
++
++#define ARCH_HAS_PREFETCH
++extern inline void prefetch(const void *addr)
++{
++ __asm__("ldw 0(%0), %%r0" : : "r" (addr));
++}
++
++/* LDD is a PA2.0 addition. */
++#ifdef CONFIG_PA20
++#define ARCH_HAS_PREFETCHW
++extern inline void prefetchw(const void *addr)
++{
++ __asm__("ldd 0(%0), %%r0" : : "r" (addr));
++}
++#endif /* CONFIG_PA20 */
++
++#endif /* CONFIG_PREFETCH */
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_PARISC_PROCESSOR_H */
+diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
+index b73626f..fd7866d 100644
+--- a/include/asm-parisc/processor.h
++++ b/include/asm-parisc/processor.h
+@@ -9,6 +9,8 @@
+ #define __ASM_PARISC_PROCESSOR_H
+
+ #ifndef __ASSEMBLY__
++#include <asm/prefetch.h> /* lockdep.h needs <linux/prefetch.h> */
++
+ #include <linux/threads.h>
+ #include <linux/spinlock_types.h>
+
+@@ -276,7 +278,7 @@ on downward growing arches, it looks lik
+ */
+
+ #ifdef __LP64__
+-#define USER_WIDE_MODE (personality(current->personality) == PER_LINUX)
++#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT))
+ #else
+ #define USER_WIDE_MODE 0
+ #endif
+@@ -328,33 +330,20 @@ extern unsigned long get_wchan(struct ta
+ #define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
+ #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
+
++#define cpu_relax() barrier()
+
+-/*
+- * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
+- * In addition, many implementations do hardware prefetching of both
+- * instructions and data.
+- *
+- * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
+- * to gr0 but not in a way that Linux can use. If the load would cause an
+- * interruption (eg due to prefetching 0), it is suppressed on PA2.0
+- * processors, but not on 7300LC.
+- */
+-#ifdef CONFIG_PREFETCH
+-#define ARCH_HAS_PREFETCH
+-#define ARCH_HAS_PREFETCHW
+-
+-extern inline void prefetch(const void *addr)
+-{
+- __asm__("ldw 0(%0), %%r0" : : "r" (addr));
+-}
+-
+-extern inline void prefetchw(const void *addr)
++/* Used as a macro to identify the combined VIPT/PIPT cached
++ * CPUs which require a guarantee of coherency (no inequivalent
++ * aliases with different data, whether clean or not) to operate */
++static inline int parisc_requires_coherency(void)
+ {
+- __asm__("ldd 0(%0), %%r0" : : "r" (addr));
+-}
++#ifdef CONFIG_PA8X00
++ /* FIXME: also pa8900 - when we see one */
++ return boot_cpu_data.cpu_type == mako;
++#else
++ return 0;
+ #endif
+-
+-#define cpu_relax() barrier()
++}
+
+ #endif /* __ASSEMBLY__ */
+
+diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h
+new file mode 100644
+index 0000000..5542dd0
+--- /dev/null
++++ b/include/asm-parisc/ropes.h
+@@ -0,0 +1,322 @@
++#ifndef _ASM_PARISC_ROPES_H_
++#define _ASM_PARISC_ROPES_H_
++
++#include <asm-parisc/parisc-device.h>
++
++#ifdef CONFIG_64BIT
++/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
++#define ZX1_SUPPORT
++#endif
++
++#ifdef CONFIG_PROC_FS
++/* depends on proc fs support. But costs CPU performance */
++#undef SBA_COLLECT_STATS
++#endif
++
++/*
++** The number of pdir entries to "free" before issueing
++** a read to PCOM register to flush out PCOM writes.
++** Interacts with allocation granularity (ie 4 or 8 entries
++** allocated and free'd/purged at a time might make this
++** less interesting).
++*/
++#define DELAYED_RESOURCE_CNT 16
++
++#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
++#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
++
++struct ioc {
++ void __iomem *ioc_hpa; /* I/O MMU base address */
++ char *res_map; /* resource map, bit == pdir entry */
++ u64 *pdir_base; /* physical base address */
++ unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
++ unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
++#ifdef ZX1_SUPPORT
++ unsigned long iovp_mask; /* help convert IOVA to IOVP */
++#endif
++ unsigned long *res_hint; /* next avail IOVP - circular search */
++ spinlock_t res_lock;
++ unsigned int res_bitshift; /* from the LEFT! */
++ unsigned int res_size; /* size of resource map in bytes */
++#ifdef SBA_HINT_SUPPORT
++/* FIXME : DMA HINTs not used */
++ unsigned long hint_mask_pdir; /* bits used for DMA hints */
++ unsigned int hint_shift_pdir;
++#endif
++#if DELAYED_RESOURCE_CNT > 0
++ int saved_cnt;
++ struct sba_dma_pair {
++ dma_addr_t iova;
++ size_t size;
++ } saved[DELAYED_RESOURCE_CNT];
++#endif
++
++#ifdef SBA_COLLECT_STATS
++#define SBA_SEARCH_SAMPLE 0x100
++ unsigned long avg_search[SBA_SEARCH_SAMPLE];
++ unsigned long avg_idx; /* current index into avg_search */
++ unsigned long used_pages;
++ unsigned long msingle_calls;
++ unsigned long msingle_pages;
++ unsigned long msg_calls;
++ unsigned long msg_pages;
++ unsigned long usingle_calls;
++ unsigned long usingle_pages;
++ unsigned long usg_calls;
++ unsigned long usg_pages;
++#endif
++ /* STUFF We don't need in performance path */
++ unsigned int pdir_size; /* in bytes, determined by IOV Space size */
++};
++
++struct sba_device {
++ struct sba_device *next; /* list of SBA's in system */
++ struct parisc_device *dev; /* dev found in bus walk */
++ const char *name;
++ void __iomem *sba_hpa; /* base address */
++ spinlock_t sba_lock;
++ unsigned int flags; /* state/functionality enabled */
++ unsigned int hw_rev; /* HW revision of chip */
++
++ struct resource chip_resv; /* MMIO reserved for chip */
++ struct resource iommu_resv; /* MMIO reserved for iommu */
++
++ unsigned int num_ioc; /* number of on-board IOC's */
++ struct ioc ioc[MAX_IOC];
++};
++
++#define ASTRO_RUNWAY_PORT 0x582
++#define IKE_MERCED_PORT 0x803
++#define REO_MERCED_PORT 0x804
++#define REOG_MERCED_PORT 0x805
++#define PLUTO_MCKINLEY_PORT 0x880
++
++static inline int IS_ASTRO(struct parisc_device *d) {
++ return d->id.hversion == ASTRO_RUNWAY_PORT;
++}
++
++static inline int IS_IKE(struct parisc_device *d) {
++ return d->id.hversion == IKE_MERCED_PORT;
++}
++
++static inline int IS_PLUTO(struct parisc_device *d) {
++ return d->id.hversion == PLUTO_MCKINLEY_PORT;
++}
++
++#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */
++#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */
++#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2)
++
++#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL
++
++#define SBA_AGPGART_COOKIE 0x0000badbadc0ffeeULL
++
++#define SBA_FUNC_ID 0x0000 /* function id */
++#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
++
++#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
++
++#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
++#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
++/* Ike's IOC's occupy functions 2 and 3 */
++#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
++
++#define IOC_CTRL 0x8 /* IOC_CTRL offset */
++#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
++#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
++#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
++#define IOC_CTRL_RM (1 << 8) /* Real Mode */
++#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
++#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
++#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
++
++/*
++** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
++** Firmware programs this stuff. Don't touch it.
++*/
++#define LMMIO_DIRECT0_BASE 0x300
++#define LMMIO_DIRECT0_MASK 0x308
++#define LMMIO_DIRECT0_ROUTE 0x310
++
++#define LMMIO_DIST_BASE 0x360
++#define LMMIO_DIST_MASK 0x368
++#define LMMIO_DIST_ROUTE 0x370
++
++#define IOS_DIST_BASE 0x390
++#define IOS_DIST_MASK 0x398
++#define IOS_DIST_ROUTE 0x3A0
++
++#define IOS_DIRECT_BASE 0x3C0
++#define IOS_DIRECT_MASK 0x3C8
++#define IOS_DIRECT_ROUTE 0x3D0
++
++/*
++** Offsets into I/O TLB (Function 2 and 3 on Ike)
++*/
++#define ROPE0_CTL 0x200 /* "regbus pci0" */
++#define ROPE1_CTL 0x208
++#define ROPE2_CTL 0x210
++#define ROPE3_CTL 0x218
++#define ROPE4_CTL 0x220
++#define ROPE5_CTL 0x228
++#define ROPE6_CTL 0x230
++#define ROPE7_CTL 0x238
++
++#define IOC_ROPE0_CFG 0x500 /* pluto only */
++#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
++
++#define HF_ENABLE 0x40
++
++#define IOC_IBASE 0x300 /* IO TLB */
++#define IOC_IMASK 0x308
++#define IOC_PCOM 0x310
++#define IOC_TCNFG 0x318
++#define IOC_PDIR_BASE 0x320
++
++/*
++** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
++** It's safer (avoid memory corruption) to keep DMA page mappings
++** equivalently sized to VM PAGE_SIZE.
++**
++** We really can't avoid generating a new mapping for each
++** page since the Virtual Coherence Index has to be generated
++** and updated for each page.
++**
++** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
++*/
++#define IOVP_SIZE PAGE_SIZE
++#define IOVP_SHIFT PAGE_SHIFT
++#define IOVP_MASK PAGE_MASK
++
++#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
++#define SBA_PERF_MASK1 0x718
++#define SBA_PERF_MASK2 0x730
++
++/*
++** Offsets into PCI Performance Counters (functions 12 and 13)
++** Controlled by PERF registers in function 2 & 3 respectively.
++*/
++#define SBA_PERF_CNT1 0x200
++#define SBA_PERF_CNT2 0x208
++#define SBA_PERF_CNT3 0x210
++
++/*
++** lba_device: Per instance Elroy data structure
++*/
++struct lba_device {
++ struct pci_hba_data hba;
++
++ spinlock_t lba_lock;
++ void *iosapic_obj;
++
++#ifdef CONFIG_64BIT
++ void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */
++#endif
++
++ int flags; /* state/functionality enabled */
++ int hw_rev; /* HW revision of chip */
++};
++
++#define ELROY_HVERS 0x782
++#define MERCURY_HVERS 0x783
++#define QUICKSILVER_HVERS 0x784
++
++static inline int IS_ELROY(struct parisc_device *d) {
++ return (d->id.hversion == ELROY_HVERS);
++}
++
++static inline int IS_MERCURY(struct parisc_device *d) {
++ return (d->id.hversion == MERCURY_HVERS);
++}
++
++static inline int IS_QUICKSILVER(struct parisc_device *d) {
++ return (d->id.hversion == QUICKSILVER_HVERS);
++}
++
++static inline int agp_mode_mercury(void __iomem *hpa) {
++ u64 bus_mode;
++
++ bus_mode = readl(hpa + 0x0620);
++ if (bus_mode & 1)
++ return 1;
++
++ return 0;
++}
++
++/*
++** I/O SAPIC init function
++** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
++** Call setup as part of per instance initialization.
++** (ie *not* init_module() function unless only one is present.)
++** fixup_irq is to initialize PCI IRQ line support and
++** virtualize pcidev->irq value. To be called by pci_fixup_bus().
++*/
++extern void *iosapic_register(unsigned long hpa);
++extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
++
++#define LBA_FUNC_ID 0x0000 /* function id */
++#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
++#define LBA_CAPABLE 0x0030 /* capabilities register */
++
++#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
++#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
++
++#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
++#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
++#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
++
++#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
++#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
++#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
++#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
++
++#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
++
++#define LBA_STAT_CTL 0x0108 /* Status & Control */
++#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
++#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
++#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
++#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
++
++#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
++#define LBA_LMMIO_MASK 0x0208
++
++#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
++#define LBA_GMMIO_MASK 0x0218
++
++#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
++#define LBA_WLMMIO_MASK 0x0228
++
++#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
++#define LBA_WGMMIO_MASK 0x0238
++
++#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
++#define LBA_IOS_MASK 0x0248
++
++#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
++#define LBA_ELMMIO_MASK 0x0258
++
++#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
++#define LBA_EIOS_MASK 0x0268
++
++#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
++#define LBA_DMA_CTL 0x0278 /* firmware sets this */
++
++#define LBA_IBASE 0x0300 /* SBA DMA support */
++#define LBA_IMASK 0x0308
++
++/* FIXME: ignore DMA Hint stuff until we can measure performance */
++#define LBA_HINT_CFG 0x0310
++#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
++
++#define LBA_BUS_MODE 0x0620
++
++/* ERROR regs are needed for config cycle kluges */
++#define LBA_ERROR_CONFIG 0x0680
++#define LBA_SMART_MODE 0x20
++#define LBA_ERROR_STATUS 0x0688
++#define LBA_ROPE_CTL 0x06A0
++
++#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
++
++#endif /*_ASM_PARISC_ROPES_H_*/
+diff --git a/include/asm-parisc/rtc.h b/include/asm-parisc/rtc.h
+index f3d3d6b..f4ebff1 100644
+--- a/include/asm-parisc/rtc.h
++++ b/include/asm-parisc/rtc.h
+@@ -1,5 +1,5 @@
+ /*
+- * inclue/asm-parisc/rtc.h
++ * include/asm-parisc/rtc.h
+ *
+ * Copyright 2002 Randolph CHung <tausq at debian.org>
+ *
+diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
+index 82fd820..d7e3cc6 100644
+--- a/include/asm-parisc/serial.h
++++ b/include/asm-parisc/serial.h
+@@ -3,20 +3,8 @@
+ */
+
+ /*
+- * This assumes you have a 7.272727 MHz clock for your UART.
+- * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
+- * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO
++ * This is used for 16550-compatible UARTs
+ */
++#define BASE_BAUD ( 1843200 / 16 )
+
+-#define LASI_BASE_BAUD ( 7272727 / 16 )
+-#define BASE_BAUD LASI_BASE_BAUD
+-
+-/*
+- * We don't use the ISA probing code, so these entries are just to reserve
+- * space. Some example (maximal) configurations:
+- * - 712 w/ additional Lasi & RJ16 ports: 4
+- * - J5k w/ PCI serial cards: 2 + 4 * card ~= 34
+- * A500 w/ PCI serial cards: 5 + 4 * card ~= 17
+- */
+-
+ #define SERIAL_PORT_DFNS
+diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
+index a93960e..f3d2090 100644
+--- a/include/asm-parisc/spinlock.h
++++ b/include/asm-parisc/spinlock.h
+@@ -56,50 +56,79 @@ static inline int __raw_spin_trylock(raw
+ }
+
+ /*
+- * Read-write spinlocks, allowing multiple readers
+- * but only one writer.
++ * Read-write spinlocks, allowing multiple readers but only one writer.
++ * Linux rwlocks are unfair to writers; they can be starved for an indefinite
++ * time by readers. With care, they can also be taken in interrupt context.
++ *
++ * In the PA-RISC implementation, we have a spinlock and a counter.
++ * Readers use the lock to serialise their access to the counter (which
++ * records how many readers currently hold the lock).
++ * Writers hold the spinlock, preventing any readers or other writers from
++ * grabbing the rwlock.
+ */
+
+-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+-
+-/* read_lock, read_unlock are pretty straightforward. Of course it somehow
+- * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
+-
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to grab the same read lock */
+ static __inline__ void __raw_read_lock(raw_rwlock_t *rw)
+ {
+- __raw_spin_lock(&rw->lock);
+-
++ unsigned long flags;
++ local_irq_save(flags);
++ __raw_spin_lock_flags(&rw->lock, flags);
+ rw->counter++;
+-
+ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
+ }
+
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to grab the same read lock */
+ static __inline__ void __raw_read_unlock(raw_rwlock_t *rw)
+ {
+- __raw_spin_lock(&rw->lock);
+-
++ unsigned long flags;
++ local_irq_save(flags);
++ __raw_spin_lock_flags(&rw->lock, flags);
+ rw->counter--;
+-
+ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
+ }
+
+-/* write_lock is less trivial. We optimistically grab the lock and check
+- * if we surprised any readers. If so we release the lock and wait till
+- * they're all gone before trying again
+- *
+- * Also note that we don't use the _irqsave / _irqrestore suffixes here.
+- * If we're called with interrupts enabled and we've got readers (or other
+- * writers) in interrupt handlers someone fucked up and we'd dead-lock
+- * sooner or later anyway. prumpf */
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to grab the same read lock */
++static __inline__ int __raw_read_trylock(raw_rwlock_t *rw)
++{
++ unsigned long flags;
++ retry:
++ local_irq_save(flags);
++ if (__raw_spin_trylock(&rw->lock)) {
++ rw->counter++;
++ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
++ return 1;
++ }
++
++ local_irq_restore(flags);
++ /* If write-locked, we fail to acquire the lock */
++ if (rw->counter < 0)
++ return 0;
++
++ /* Wait until we have a realistic chance at the lock */
++ while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0)
++ cpu_relax();
++
++ goto retry;
++}
+
+-static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to read_trylock() this lock */
++static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
+ {
++ unsigned long flags;
+ retry:
+- __raw_spin_lock(&rw->lock);
++ local_irq_save(flags);
++ __raw_spin_lock_flags(&rw->lock, flags);
+
+- if(rw->counter != 0) {
+- /* this basically never happens */
++ if (rw->counter != 0) {
+ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
+
+ while (rw->counter != 0)
+ cpu_relax();
+@@ -107,31 +136,37 @@ retry:
+ goto retry;
+ }
+
+- /* got it. now leave without unlocking */
+- rw->counter = -1; /* remember we are locked */
++ rw->counter = -1; /* mark as write-locked */
++ mb();
++ local_irq_restore(flags);
+ }
+
+-/* write_unlock is absolutely trivial - we don't have to wait for anything */
+-
+-static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
++static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
+ {
+ rw->counter = 0;
+ __raw_spin_unlock(&rw->lock);
+ }
+
+-static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to read_trylock() this lock */
++static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
+ {
+- __raw_spin_lock(&rw->lock);
+- if (rw->counter != 0) {
+- /* this basically never happens */
+- __raw_spin_unlock(&rw->lock);
+-
+- return 0;
++ unsigned long flags;
++ int result = 0;
++
++ local_irq_save(flags);
++ if (__raw_spin_trylock(&rw->lock)) {
++ if (rw->counter == 0) {
++ rw->counter = -1;
++ result = 1;
++ } else {
++ /* Read-locked. Oh well. */
++ __raw_spin_unlock(&rw->lock);
++ }
+ }
++ local_irq_restore(flags);
+
+- /* got it. now leave without unlocking */
+- rw->counter = -1; /* remember we are locked */
+- return 1;
++ return result;
+ }
+
+ /*
+@@ -152,4 +187,8 @@ static __inline__ int __raw_write_can_lo
+ return !rw->counter;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
+index 27bcfad..53b0f5d 100644
+--- a/include/asm-parisc/unistd.h
++++ b/include/asm-parisc/unistd.h
+@@ -952,92 +952,6 @@ type name(type1 arg1, type2 arg2, type3
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-/* mmap & mmap2 take 6 arguments */
+-#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
+-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
+-{ \
+- return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6); \
+-}
+-
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <asm/current.h>
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/syscalls.h>
+-
+-static inline pid_t setsid(void)
+-{
+- return sys_setsid();
+-}
+-
+-static inline int write(int fd, const char *buf, off_t count)
+-{
+- return sys_write(fd, buf, count);
+-}
+-
+-static inline int read(int fd, char *buf, off_t count)
+-{
+- return sys_read(fd, buf, count);
+-}
+-
+-static inline off_t lseek(int fd, off_t offset, int count)
+-{
+- return sys_lseek(fd, offset, count);
+-}
+-
+-static inline int dup(int fd)
+-{
+- return sys_dup(fd);
+-}
+-
+-static inline int execve(char *filename, char * argv [],
+- char * envp[])
+-{
+- extern int __execve(char *, char **, char **, struct task_struct *);
+- return __execve(filename, argv, envp, current);
+-}
+-
+-static inline int open(const char *file, int flag, int mode)
+-{
+- return sys_open(file, flag, mode);
+-}
+-
+-static inline int close(int fd)
+-{
+- return sys_close(fd);
+-}
+-
+-static inline void _exit(int exitcode)
+-{
+- sys_exit(exitcode);
+-}
+-
+-static inline pid_t waitpid(pid_t pid, int *wait_stat, int options)
+-{
+- return sys_wait4(pid, wait_stat, options, NULL);
+-}
+-
+-asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long offset);
+-asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-struct pt_regs;
+-asmlinkage int sys_execve(struct pt_regs *regs);
+-int sys_clone(unsigned long clone_flags, unsigned long usp,
+- struct pt_regs *regs);
+-int sys_vfork(struct pt_regs *regs);
+-int sys_pipe(int *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ #endif /* __ASSEMBLY__ */
+
+ #undef STR
+diff --git a/include/asm-powerpc/Kbuild b/include/asm-powerpc/Kbuild
+index ac61d7e..9827849 100644
+--- a/include/asm-powerpc/Kbuild
++++ b/include/asm-powerpc/Kbuild
+@@ -1,10 +1,41 @@
+ include include/asm-generic/Kbuild.asm
+
+-unifdef-y += a.out.h asm-compat.h bootx.h byteorder.h cputable.h elf.h \
+- nvram.h param.h posix_types.h ptrace.h seccomp.h signal.h \
+- termios.h types.h unistd.h
++header-y += auxvec.h
++header-y += ioctls.h
++header-y += mman.h
++header-y += sembuf.h
++header-y += siginfo.h
++header-y += stat.h
++header-y += errno.h
++header-y += ipcbuf.h
++header-y += msgbuf.h
++header-y += shmbuf.h
++header-y += socket.h
++header-y += termbits.h
++header-y += fcntl.h
++header-y += ipc.h
++header-y += poll.h
++header-y += shmparam.h
++header-y += sockios.h
++header-y += ucontext.h
++header-y += ioctl.h
++header-y += linkage.h
++header-y += resource.h
++header-y += sigcontext.h
++header-y += statfs.h
+
+-header-y += auxvec.h ioctls.h mman.h sembuf.h siginfo.h stat.h errno.h \
+- ipcbuf.h msgbuf.h shmbuf.h socket.h termbits.h fcntl.h ipc.h \
+- poll.h shmparam.h sockios.h ucontext.h ioctl.h linkage.h \
+- resource.h sigcontext.h statfs.h
++unifdef-y += a.out.h
++unifdef-y += asm-compat.h
++unifdef-y += bootx.h
++unifdef-y += byteorder.h
++unifdef-y += cputable.h
++unifdef-y += elf.h
++unifdef-y += nvram.h
++unifdef-y += param.h
++unifdef-y += posix_types.h
++unifdef-y += ptrace.h
++unifdef-y += seccomp.h
++unifdef-y += signal.h
++unifdef-y += termios.h
++unifdef-y += types.h
++unifdef-y += unistd.h
+diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
+index 8e64be0..c89bd58 100644
+--- a/include/asm-powerpc/asm-compat.h
++++ b/include/asm-powerpc/asm-compat.h
+@@ -14,6 +14,58 @@
+ # define ASM_CONST(x) __ASM_CONST(x)
+ #endif
+
++
++/*
++ * Feature section common macros
++ *
++ * Note that the entries now contain offsets between the table entry
++ * and the code rather than absolute code pointers in order to be
++ * useable with the vdso shared library. There is also an assumption
++ * that values will be negative, that is, the fixup table has to be
++ * located after the code it fixes up.
++ */
++#ifdef CONFIG_PPC64
++#ifdef __powerpc64__
++/* 64 bits kernel, 64 bits code */
++#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
++99: \
++ .section sect,"a"; \
++ .align 3; \
++98: \
++ .llong msk; \
++ .llong val; \
++ .llong label##b-98b; \
++ .llong 99b-98b; \
++ .previous
++#else /* __powerpc64__ */
++/* 64 bits kernel, 32 bits code (ie. vdso32) */
++#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
++99: \
++ .section sect,"a"; \
++ .align 3; \
++98: \
++ .llong msk; \
++ .llong val; \
++ .long 0xffffffff; \
++ .long label##b-98b; \
++ .long 0xffffffff; \
++ .long 99b-98b; \
++ .previous
++#endif /* !__powerpc64__ */
++#else /* CONFIG_PPC64 */
++/* 32 bits kernel, 32 bits code */
++#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
++99: \
++ .section sect,"a"; \
++ .align 2; \
++98: \
++ .long msk; \
++ .long val; \
++ .long label##b-98b; \
++ .long 99b-98b; \
++ .previous
++#endif /* !CONFIG_PPC64 */
++
+ #ifdef __powerpc64__
+
+ /* operations for longs and pointers */
+diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
+index f44b529..978b2c7 100644
+--- a/include/asm-powerpc/bug.h
++++ b/include/asm-powerpc/bug.h
+@@ -70,9 +70,10 @@ struct bug_entry *find_bug(unsigned long
+ "i" (__FILE__), "i" (__FUNCTION__)); \
+ } while (0)
+
+-#define WARN_ON(x) do { \
+- if (__builtin_constant_p(x)) { \
+- if (x) \
++#define WARN_ON(x) ({ \
++ typeof(x) __ret_warn_on = (x); \
++ if (__builtin_constant_p(__ret_warn_on)) { \
++ if (__ret_warn_on) \
+ __WARN(); \
+ } else { \
+ __asm__ __volatile__( \
+@@ -80,11 +81,12 @@ struct bug_entry *find_bug(unsigned long
+ ".section __bug_table,\"a\"\n" \
+ "\t"PPC_LONG" 1b,%1,%2,%3\n" \
+ ".previous" \
+- : : "r" ((long)(x)), \
++ : : "r" (__ret_warn_on), \
+ "i" (__LINE__ + BUG_WARNING_TRAP), \
+ "i" (__FILE__), "i" (__FUNCTION__)); \
+ } \
+-} while (0)
++ unlikely(__ret_warn_on); \
++})
+
+ #define HAVE_ARCH_BUG
+ #define HAVE_ARCH_BUG_ON
+diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
+index 1ba3c99..a9a4014 100644
+--- a/include/asm-powerpc/cputable.h
++++ b/include/asm-powerpc/cputable.h
+@@ -23,6 +23,7 @@
+ #define PPC_FEATURE_SMT 0x00004000
+ #define PPC_FEATURE_ICACHE_SNOOP 0x00002000
+ #define PPC_FEATURE_ARCH_2_05 0x00001000
++#define PPC_FEATURE_PA6T 0x00000800
+
+ #define PPC_FEATURE_TRUE_LE 0x00000002
+ #define PPC_FEATURE_PPC_LE 0x00000001
+@@ -36,6 +37,7 @@
+ struct cpu_spec;
+
+ typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
++typedef void (*cpu_restore_t)(void);
+
+ enum powerpc_oprofile_type {
+ PPC_OPROFILE_INVALID = 0,
+@@ -65,6 +67,8 @@ struct cpu_spec {
+ * BHT, SPD, etc... from head.S before branching to identify_machine
+ */
+ cpu_setup_t cpu_setup;
++ /* Used to restore cpu setup on secondary processors and at resume */
++ cpu_restore_t cpu_restore;
+
+ /* Used by oprofile userspace to select the right counters */
+ char *oprofile_cpu_type;
+@@ -85,8 +89,11 @@ struct cpu_spec {
+
+ extern struct cpu_spec *cur_cpu_spec;
+
+-extern void identify_cpu(unsigned long offset, unsigned long cpu);
+-extern void do_cpu_ftr_fixups(unsigned long offset);
++extern unsigned int __start___ftr_fixup, __stop___ftr_fixup;
++
++extern struct cpu_spec *identify_cpu(unsigned long offset);
++extern void do_feature_fixups(unsigned long value, void *fixup_start,
++ void *fixup_end);
+
+ #endif /* __ASSEMBLY__ */
+
+@@ -140,12 +147,13 @@ extern void do_cpu_ftr_fixups(unsigned l
+ #define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
+ #define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
+ #define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
++#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
+
+ #ifndef __ASSEMBLY__
+
+ #define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \
+ CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \
+- CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL)
++ CPU_FTR_NODSISRALIGN)
+
+ /* iSeries doesn't support large pages */
+ #ifdef CONFIG_PPC_ISERIES
+@@ -310,24 +318,29 @@ extern void do_cpu_ftr_fixups(unsigned l
+ CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \
+ CPU_FTR_MMCRA | CPU_FTR_CTRL)
+ #define CPU_FTRS_POWER4 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+- CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA)
++ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
++ CPU_FTR_MMCRA)
+ #define CPU_FTRS_PPC970 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+- CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
++ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+ CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA)
+ #define CPU_FTRS_POWER5 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+- CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
++ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+ CPU_FTR_MMCRA | CPU_FTR_SMT | \
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
+ CPU_FTR_PURR)
+ #define CPU_FTRS_POWER6 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+- CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
++ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+ CPU_FTR_MMCRA | CPU_FTR_SMT | \
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
+ CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_REAL_LE)
+ #define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+- CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
++ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
+- CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE)
++ CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
++#define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
++ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
++ CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
++ CPU_FTR_PURR | CPU_FTR_REAL_LE)
+ #define CPU_FTRS_COMPATIBLE (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
+ #endif
+@@ -336,7 +349,7 @@ extern void do_cpu_ftr_fixups(unsigned l
+ #define CPU_FTRS_POSSIBLE \
+ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
+ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
+- CPU_FTRS_CELL | CPU_FTR_CI_LARGE_PAGE)
++ CPU_FTRS_CELL | CPU_FTRS_PA6T)
+ #else
+ enum {
+ CPU_FTRS_POSSIBLE =
+@@ -375,7 +388,7 @@ enum {
+ #define CPU_FTRS_ALWAYS \
+ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \
+ CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_POWER6 & \
+- CPU_FTRS_CELL & CPU_FTRS_POSSIBLE)
++ CPU_FTRS_CELL & CPU_FTRS_PA6T & CPU_FTRS_POSSIBLE)
+ #else
+ enum {
+ CPU_FTRS_ALWAYS =
+@@ -422,29 +435,12 @@ static inline int cpu_has_feature(unsign
+
+ #ifdef __ASSEMBLY__
+
+-#define BEGIN_FTR_SECTION 98:
+-
+-#ifndef __powerpc64__
++#define BEGIN_FTR_SECTION_NESTED(label) label:
++#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(97)
++#define END_FTR_SECTION_NESTED(msk, val, label) \
++ MAKE_FTR_SECTION_ENTRY(msk, val, label, __ftr_fixup)
+ #define END_FTR_SECTION(msk, val) \
+-99: \
+- .section __ftr_fixup,"a"; \
+- .align 2; \
+- .long msk; \
+- .long val; \
+- .long 98b; \
+- .long 99b; \
+- .previous
+-#else /* __powerpc64__ */
+-#define END_FTR_SECTION(msk, val) \
+-99: \
+- .section __ftr_fixup,"a"; \
+- .align 3; \
+- .llong msk; \
+- .llong val; \
+- .llong 98b; \
+- .llong 99b; \
+- .previous
+-#endif /* __powerpc64__ */
++ END_FTR_SECTION_NESTED(msk, val, 97)
+
+ #define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk))
+ #define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0)
+diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
+index 1938d6a..b8708ae 100644
+--- a/include/asm-powerpc/current.h
++++ b/include/asm-powerpc/current.h
+@@ -14,7 +14,17 @@ struct task_struct;
+ #ifdef __powerpc64__
+ #include <asm/paca.h>
+
+-#define current (get_paca()->__current)
++static inline struct task_struct *get_current(void)
++{
++ struct task_struct *task;
++
++ __asm__ __volatile__("ld %0,%1(13)"
++ : "=r" (task)
++ : "i" (offsetof(struct paca_struct, __current)));
++
++ return task;
++}
++#define current get_current()
+
+ #else
+
+diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
+index 77069df..fdf9aff 100644
+--- a/include/asm-powerpc/firmware.h
++++ b/include/asm-powerpc/firmware.h
+@@ -14,34 +14,36 @@
+
+ #ifdef __KERNEL__
+
+-#ifndef __ASSEMBLY__
++#include <asm/asm-compat.h>
+
+ /* firmware feature bitmask values */
+ #define FIRMWARE_MAX_FEATURES 63
+
+-#define FW_FEATURE_PFT (1UL<<0)
+-#define FW_FEATURE_TCE (1UL<<1)
+-#define FW_FEATURE_SPRG0 (1UL<<2)
+-#define FW_FEATURE_DABR (1UL<<3)
+-#define FW_FEATURE_COPY (1UL<<4)
+-#define FW_FEATURE_ASR (1UL<<5)
+-#define FW_FEATURE_DEBUG (1UL<<6)
+-#define FW_FEATURE_TERM (1UL<<7)
+-#define FW_FEATURE_PERF (1UL<<8)
+-#define FW_FEATURE_DUMP (1UL<<9)
+-#define FW_FEATURE_INTERRUPT (1UL<<10)
+-#define FW_FEATURE_MIGRATE (1UL<<11)
+-#define FW_FEATURE_PERFMON (1UL<<12)
+-#define FW_FEATURE_CRQ (1UL<<13)
+-#define FW_FEATURE_VIO (1UL<<14)
+-#define FW_FEATURE_RDMA (1UL<<15)
+-#define FW_FEATURE_LLAN (1UL<<16)
+-#define FW_FEATURE_BULK (1UL<<17)
+-#define FW_FEATURE_XDABR (1UL<<18)
+-#define FW_FEATURE_MULTITCE (1UL<<19)
+-#define FW_FEATURE_SPLPAR (1UL<<20)
+-#define FW_FEATURE_ISERIES (1UL<<21)
+-#define FW_FEATURE_LPAR (1UL<<22)
++#define FW_FEATURE_PFT ASM_CONST(0x0000000000000001)
++#define FW_FEATURE_TCE ASM_CONST(0x0000000000000002)
++#define FW_FEATURE_SPRG0 ASM_CONST(0x0000000000000004)
++#define FW_FEATURE_DABR ASM_CONST(0x0000000000000008)
++#define FW_FEATURE_COPY ASM_CONST(0x0000000000000010)
++#define FW_FEATURE_ASR ASM_CONST(0x0000000000000020)
++#define FW_FEATURE_DEBUG ASM_CONST(0x0000000000000040)
++#define FW_FEATURE_TERM ASM_CONST(0x0000000000000080)
++#define FW_FEATURE_PERF ASM_CONST(0x0000000000000100)
++#define FW_FEATURE_DUMP ASM_CONST(0x0000000000000200)
++#define FW_FEATURE_INTERRUPT ASM_CONST(0x0000000000000400)
++#define FW_FEATURE_MIGRATE ASM_CONST(0x0000000000000800)
++#define FW_FEATURE_PERFMON ASM_CONST(0x0000000000001000)
++#define FW_FEATURE_CRQ ASM_CONST(0x0000000000002000)
++#define FW_FEATURE_VIO ASM_CONST(0x0000000000004000)
++#define FW_FEATURE_RDMA ASM_CONST(0x0000000000008000)
++#define FW_FEATURE_LLAN ASM_CONST(0x0000000000010000)
++#define FW_FEATURE_BULK ASM_CONST(0x0000000000020000)
++#define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000)
++#define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000)
++#define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000)
++#define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000)
++#define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000)
++
++#ifndef __ASSEMBLY__
+
+ enum {
+ #ifdef CONFIG_PPC64
+@@ -94,6 +96,20 @@ extern void machine_check_fwnmi(void);
+ /* This is true if we are using the firmware NMI handler (typically LPAR) */
+ extern int fwnmi_active;
+
++extern unsigned int __start___fw_ftr_fixup, __stop___fw_ftr_fixup;
++
++#else /* __ASSEMBLY__ */
++
++#define BEGIN_FW_FTR_SECTION_NESTED(label) label:
++#define BEGIN_FW_FTR_SECTION BEGIN_FW_FTR_SECTION_NESTED(97)
++#define END_FW_FTR_SECTION_NESTED(msk, val, label) \
++ MAKE_FTR_SECTION_ENTRY(msk, val, label, __fw_ftr_fixup)
++#define END_FW_FTR_SECTION(msk, val) \
++ END_FW_FTR_SECTION_NESTED(msk, val, 97)
++
++#define END_FW_FTR_SECTION_IFSET(msk) END_FW_FTR_SECTION((msk), (msk))
++#define END_FW_FTR_SECTION_IFCLR(msk) END_FW_FTR_SECTION((msk), 0)
++
+ #endif /* __ASSEMBLY__ */
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_POWERPC_FIRMWARE_H */
+diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h
+new file mode 100644
+index 0000000..3d0e819
+--- /dev/null
++++ b/include/asm-powerpc/fs_pd.h
+@@ -0,0 +1,45 @@
++/*
++ * Platform information definitions.
++ *
++ * 2006 (c) MontaVista Software, Inc.
++ * Vitaly Bordug <vbordug at ru.mvista.com>
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#ifndef FS_PD_H
++#define FS_PD_H
++#include <asm/cpm2.h>
++#include <sysdev/fsl_soc.h>
++#include <asm/time.h>
++
++static inline int uart_baudrate(void)
++{
++ return get_baudrate();
++}
++
++static inline int uart_clock(void)
++{
++ return ppc_proc_freq;
++}
++
++#define cpm2_map(member) \
++({ \
++ u32 offset = offsetof(cpm2_map_t, member); \
++ void *addr = ioremap (CPM_MAP_ADDR + offset, \
++ sizeof( ((cpm2_map_t*)0)->member)); \
++ addr; \
++})
++
++#define cpm2_map_size(member, size) \
++({ \
++ u32 offset = offsetof(cpm2_map_t, member); \
++ void *addr = ioremap (CPM_MAP_ADDR + offset, size); \
++ addr; \
++})
++
++#define cpm2_unmap(addr) iounmap(addr)
++
++#endif
+diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
+index 0d3c4e8..257d1ce 100644
+--- a/include/asm-powerpc/hvcall.h
++++ b/include/asm-powerpc/hvcall.h
+@@ -164,9 +164,15 @@
+ #define H_VIO_SIGNAL 0x104
+ #define H_SEND_CRQ 0x108
+ #define H_COPY_RDMA 0x110
++#define H_REGISTER_LOGICAL_LAN 0x114
++#define H_FREE_LOGICAL_LAN 0x118
++#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
++#define H_SEND_LOGICAL_LAN 0x120
++#define H_MULTICAST_CTRL 0x130
+ #define H_SET_XDABR 0x134
+ #define H_STUFF_TCE 0x138
+ #define H_PUT_TCE_INDIRECT 0x13C
++#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+ #define H_VTERM_PARTNER_INFO 0x150
+ #define H_REGISTER_VTERM 0x154
+ #define H_FREE_VTERM 0x158
+@@ -196,102 +202,59 @@
+ #define H_GET_HCA_INFO 0x1B8
+ #define H_GET_PERF_COUNT 0x1BC
+ #define H_MANAGE_TRACE 0x1C0
++#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+ #define H_QUERY_INT_STATE 0x1E4
+ #define H_POLL_PENDING 0x1D8
+ #define H_JOIN 0x298
+ #define H_VASI_STATE 0x2A4
+ #define H_ENABLE_CRQ 0x2B0
++#define MAX_HCALL_OPCODE H_ENABLE_CRQ
+
+ #ifndef __ASSEMBLY__
+
+-/* plpar_hcall() -- Generic call interface using above opcodes
++/**
++ * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
++ * @opcode: The hypervisor call to make.
+ *
+- * The actual call interface is a hypervisor call instruction with
+- * the opcode in R3 and input args in R4-R7.
+- * Status is returned in R3 with variable output values in R4-R11.
+- * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
+- * and return only two out args which MUST ALWAYS BE PROVIDED.
+- */
+-long plpar_hcall(unsigned long opcode,
+- unsigned long arg1,
+- unsigned long arg2,
+- unsigned long arg3,
+- unsigned long arg4,
+- unsigned long *out1,
+- unsigned long *out2,
+- unsigned long *out3);
+-
+-/* Same as plpar_hcall but for those opcodes that return no values
+- * other than status. Slightly more efficient.
++ * This call supports up to 7 arguments and only returns the status of
++ * the hcall. Use this version where possible, its slightly faster than
++ * the other plpar_hcalls.
+ */
+ long plpar_hcall_norets(unsigned long opcode, ...);
+
+-/*
+- * Special hcall interface for ibmveth support.
+- * Takes 8 input parms. Returns a rc and stores the
+- * R4 return value in *out1.
+- */
+-long plpar_hcall_8arg_2ret(unsigned long opcode,
+- unsigned long arg1,
+- unsigned long arg2,
+- unsigned long arg3,
+- unsigned long arg4,
+- unsigned long arg5,
+- unsigned long arg6,
+- unsigned long arg7,
+- unsigned long arg8,
+- unsigned long *out1);
+-
+-/* plpar_hcall_4out()
++/**
++ * plpar_hcall: - Make a pseries hypervisor call
++ * @opcode: The hypervisor call to make.
++ * @retbuf: Buffer to store up to 4 return arguments in.
+ *
+- * same as plpar_hcall except with 4 output arguments.
++ * This call supports up to 6 arguments and 4 return arguments. Use
++ * PLPAR_HCALL_BUFSIZE to size the return argument buffer.
+ *
++ * Used for all but the craziest of phyp interfaces (see plpar_hcall9)
+ */
+-long plpar_hcall_4out(unsigned long opcode,
+- unsigned long arg1,
+- unsigned long arg2,
+- unsigned long arg3,
+- unsigned long arg4,
+- unsigned long *out1,
+- unsigned long *out2,
+- unsigned long *out3,
+- unsigned long *out4);
++#define PLPAR_HCALL_BUFSIZE 4
++long plpar_hcall(unsigned long opcode, unsigned long *retbuf, ...);
+
+-long plpar_hcall_7arg_7ret(unsigned long opcode,
+- unsigned long arg1,
+- unsigned long arg2,
+- unsigned long arg3,
+- unsigned long arg4,
+- unsigned long arg5,
+- unsigned long arg6,
+- unsigned long arg7,
+- unsigned long *out1,
+- unsigned long *out2,
+- unsigned long *out3,
+- unsigned long *out4,
+- unsigned long *out5,
+- unsigned long *out6,
+- unsigned long *out7);
++/**
++ * plpar_hcall9: - Make a pseries hypervisor call with up to 9 return arguments
++ * @opcode: The hypervisor call to make.
++ * @retbuf: Buffer to store up to 9 return arguments in.
++ *
++ * This call supports up to 9 arguments and 9 return arguments. Use
++ * PLPAR_HCALL9_BUFSIZE to size the return argument buffer.
++ */
++#define PLPAR_HCALL9_BUFSIZE 9
++long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...);
+
+-long plpar_hcall_9arg_9ret(unsigned long opcode,
+- unsigned long arg1,
+- unsigned long arg2,
+- unsigned long arg3,
+- unsigned long arg4,
+- unsigned long arg5,
+- unsigned long arg6,
+- unsigned long arg7,
+- unsigned long arg8,
+- unsigned long arg9,
+- unsigned long *out1,
+- unsigned long *out2,
+- unsigned long *out3,
+- unsigned long *out4,
+- unsigned long *out5,
+- unsigned long *out6,
+- unsigned long *out7,
+- unsigned long *out8,
+- unsigned long *out9);
++/* For hcall instrumentation. One structure per-hcall, per-CPU */
++struct hcall_stats {
++ unsigned long num_calls; /* number of calls (on this CPU) */
++ unsigned long tb_total; /* total wall time (mftb) of calls. */
++ unsigned long purr_total; /* total cpu time (PURR) of calls. */
++};
++void update_hcall_stats(unsigned long opcode, unsigned long tb_delta,
++ unsigned long purr_delta);
++#define HCALL_STAT_ARRAY_SIZE ((MAX_HCALL_OPCODE >> 2) + 1)
+
+ #endif /* __ASSEMBLY__ */
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h
+index c80e113..db1362f 100644
+--- a/include/asm-powerpc/i8259.h
++++ b/include/asm-powerpc/i8259.h
+@@ -6,10 +6,11 @@
+
+ #ifdef CONFIG_PPC_MERGE
+ extern void i8259_init(struct device_node *node, unsigned long intack_addr);
+-extern unsigned int i8259_irq(struct pt_regs *regs);
++extern unsigned int i8259_irq(void);
++extern struct irq_host *i8259_get_host(void);
+ #else
+ extern void i8259_init(unsigned long intack_addr, int offset);
+-extern int i8259_irq(struct pt_regs *regs);
++extern int i8259_irq(void);
+ #endif
+
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
+index 7a42723..3493429 100644
+--- a/include/asm-powerpc/ibmebus.h
++++ b/include/asm-powerpc/ibmebus.h
+@@ -48,7 +48,7 @@ extern struct dma_mapping_ops ibmebus_dm
+ extern struct bus_type ibmebus_bus_type;
+
+ struct ibmebus_dev {
+- char *name;
++ const char *name;
+ struct of_device ofdev;
+ };
+
+@@ -65,7 +65,7 @@ void ibmebus_unregister_driver(struct ib
+
+ int ibmebus_request_irq(struct ibmebus_dev *dev,
+ u32 ist,
+- irqreturn_t (*handler)(int, void*, struct pt_regs *),
++ irq_handler_t handler,
+ unsigned long irq_flags, const char * devname,
+ void *dev_id);
+ void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id);
+diff --git a/include/asm-powerpc/ide.h b/include/asm-powerpc/ide.h
+index b09b42a..c8390f9 100644
+--- a/include/asm-powerpc/ide.h
++++ b/include/asm-powerpc/ide.h
+@@ -12,6 +12,7 @@
+ #include <linux/sched.h>
+ #include <asm/mpc8xx.h>
+ #endif
++#include <asm/io.h>
+
+ #ifndef MAX_HWIFS
+ #ifdef __powerpc64__
+@@ -21,15 +22,14 @@
+ #endif
+ #endif
+
++#define __ide_mm_insw(p, a, c) _insw_ns((volatile u16 __iomem *)(p), (a), (c))
++#define __ide_mm_insl(p, a, c) _insl_ns((volatile u32 __iomem *)(p), (a), (c))
++#define __ide_mm_outsw(p, a, c) _outsw_ns((volatile u16 __iomem *)(p), (a), (c))
++#define __ide_mm_outsl(p, a, c) _outsl_ns((volatile u32 __iomem *)(p), (a), (c))
++
+ #ifndef __powerpc64__
+ #include <linux/hdreg.h>
+ #include <linux/ioport.h>
+-#include <asm/io.h>
+-
+-extern void __ide_mm_insw(void __iomem *port, void *addr, u32 count);
+-extern void __ide_mm_outsw(void __iomem *port, void *addr, u32 count);
+-extern void __ide_mm_insl(void __iomem *port, void *addr, u32 count);
+-extern void __ide_mm_outsl(void __iomem *port, void *addr, u32 count);
+
+ struct ide_machdep_calls {
+ int (*default_irq)(unsigned long base);
+diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h
+new file mode 100644
+index 0000000..ce12f85
+--- /dev/null
++++ b/include/asm-powerpc/immap_qe.h
+@@ -0,0 +1,477 @@
++/*
++ * include/asm-powerpc/immap_qe.h
++ *
++ * QUICC Engine (QE) Internal Memory Map.
++ * The Internal Memory Map for devices with QE on them. This
++ * is the superset of all QE devices (8360, etc.).
++
++ * Copyright (C) 2006. Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.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.
++ */
++#ifndef _ASM_POWERPC_IMMAP_QE_H
++#define _ASM_POWERPC_IMMAP_QE_H
++#ifdef __KERNEL__
++
++#include <linux/kernel.h>
++
++#define QE_IMMAP_SIZE (1024 * 1024) /* 1MB from 1MB+IMMR */
++
++/* QE I-RAM */
++struct qe_iram {
++ __be32 iadd; /* I-RAM Address Register */
++ __be32 idata; /* I-RAM Data Register */
++ u8 res0[0x78];
++} __attribute__ ((packed));
++
++/* QE Interrupt Controller */
++struct qe_ic_regs {
++ __be32 qicr;
++ __be32 qivec;
++ __be32 qripnr;
++ __be32 qipnr;
++ __be32 qipxcc;
++ __be32 qipycc;
++ __be32 qipwcc;
++ __be32 qipzcc;
++ __be32 qimr;
++ __be32 qrimr;
++ __be32 qicnr;
++ u8 res0[0x4];
++ __be32 qiprta;
++ __be32 qiprtb;
++ u8 res1[0x4];
++ __be32 qricr;
++ u8 res2[0x20];
++ __be32 qhivec;
++ u8 res3[0x1C];
++} __attribute__ ((packed));
++
++/* Communications Processor */
++struct cp_qe {
++ __be32 cecr; /* QE command register */
++ __be32 ceccr; /* QE controller configuration register */
++ __be32 cecdr; /* QE command data register */
++ u8 res0[0xA];
++ __be16 ceter; /* QE timer event register */
++ u8 res1[0x2];
++ __be16 cetmr; /* QE timers mask register */
++ __be32 cetscr; /* QE time-stamp timer control register */
++ __be32 cetsr1; /* QE time-stamp register 1 */
++ __be32 cetsr2; /* QE time-stamp register 2 */
++ u8 res2[0x8];
++ __be32 cevter; /* QE virtual tasks event register */
++ __be32 cevtmr; /* QE virtual tasks mask register */
++ __be16 cercr; /* QE RAM control register */
++ u8 res3[0x2];
++ u8 res4[0x24];
++ __be16 ceexe1; /* QE external request 1 event register */
++ u8 res5[0x2];
++ __be16 ceexm1; /* QE external request 1 mask register */
++ u8 res6[0x2];
++ __be16 ceexe2; /* QE external request 2 event register */
++ u8 res7[0x2];
++ __be16 ceexm2; /* QE external request 2 mask register */
++ u8 res8[0x2];
++ __be16 ceexe3; /* QE external request 3 event register */
++ u8 res9[0x2];
++ __be16 ceexm3; /* QE external request 3 mask register */
++ u8 res10[0x2];
++ __be16 ceexe4; /* QE external request 4 event register */
++ u8 res11[0x2];
++ __be16 ceexm4; /* QE external request 4 mask register */
++ u8 res12[0x2];
++ u8 res13[0x280];
++} __attribute__ ((packed));
++
++/* QE Multiplexer */
++struct qe_mux {
++ __be32 cmxgcr; /* CMX general clock route register */
++ __be32 cmxsi1cr_l; /* CMX SI1 clock route low register */
++ __be32 cmxsi1cr_h; /* CMX SI1 clock route high register */
++ __be32 cmxsi1syr; /* CMX SI1 SYNC route register */
++ __be32 cmxucr1; /* CMX UCC1, UCC3 clock route register */
++ __be32 cmxucr2; /* CMX UCC5, UCC7 clock route register */
++ __be32 cmxucr3; /* CMX UCC2, UCC4 clock route register */
++ __be32 cmxucr4; /* CMX UCC6, UCC8 clock route register */
++ __be32 cmxupcr; /* CMX UPC clock route register */
++ u8 res0[0x1C];
++} __attribute__ ((packed));
++
++/* QE Timers */
++struct qe_timers {
++ u8 gtcfr1; /* Timer 1 and Timer 2 global config register*/
++ u8 res0[0x3];
++ u8 gtcfr2; /* Timer 3 and timer 4 global config register*/
++ u8 res1[0xB];
++ __be16 gtmdr1; /* Timer 1 mode register */
++ __be16 gtmdr2; /* Timer 2 mode register */
++ __be16 gtrfr1; /* Timer 1 reference register */
++ __be16 gtrfr2; /* Timer 2 reference register */
++ __be16 gtcpr1; /* Timer 1 capture register */
++ __be16 gtcpr2; /* Timer 2 capture register */
++ __be16 gtcnr1; /* Timer 1 counter */
++ __be16 gtcnr2; /* Timer 2 counter */
++ __be16 gtmdr3; /* Timer 3 mode register */
++ __be16 gtmdr4; /* Timer 4 mode register */
++ __be16 gtrfr3; /* Timer 3 reference register */
++ __be16 gtrfr4; /* Timer 4 reference register */
++ __be16 gtcpr3; /* Timer 3 capture register */
++ __be16 gtcpr4; /* Timer 4 capture register */
++ __be16 gtcnr3; /* Timer 3 counter */
++ __be16 gtcnr4; /* Timer 4 counter */
++ __be16 gtevr1; /* Timer 1 event register */
++ __be16 gtevr2; /* Timer 2 event register */
++ __be16 gtevr3; /* Timer 3 event register */
++ __be16 gtevr4; /* Timer 4 event register */
++ __be16 gtps; /* Timer 1 prescale register */
++ u8 res2[0x46];
++} __attribute__ ((packed));
++
++/* BRG */
++struct qe_brg {
++ __be32 brgc1; /* BRG1 configuration register */
++ __be32 brgc2; /* BRG2 configuration register */
++ __be32 brgc3; /* BRG3 configuration register */
++ __be32 brgc4; /* BRG4 configuration register */
++ __be32 brgc5; /* BRG5 configuration register */
++ __be32 brgc6; /* BRG6 configuration register */
++ __be32 brgc7; /* BRG7 configuration register */
++ __be32 brgc8; /* BRG8 configuration register */
++ __be32 brgc9; /* BRG9 configuration register */
++ __be32 brgc10; /* BRG10 configuration register */
++ __be32 brgc11; /* BRG11 configuration register */
++ __be32 brgc12; /* BRG12 configuration register */
++ __be32 brgc13; /* BRG13 configuration register */
++ __be32 brgc14; /* BRG14 configuration register */
++ __be32 brgc15; /* BRG15 configuration register */
++ __be32 brgc16; /* BRG16 configuration register */
++ u8 res0[0x40];
++} __attribute__ ((packed));
++
++/* SPI */
++struct spi {
++ u8 res0[0x20];
++ __be32 spmode; /* SPI mode register */
++ u8 res1[0x2];
++ u8 spie; /* SPI event register */
++ u8 res2[0x1];
++ u8 res3[0x2];
++ u8 spim; /* SPI mask register */
++ u8 res4[0x1];
++ u8 res5[0x1];
++ u8 spcom; /* SPI command register */
++ u8 res6[0x2];
++ __be32 spitd; /* SPI transmit data register (cpu mode) */
++ __be32 spird; /* SPI receive data register (cpu mode) */
++ u8 res7[0x8];
++} __attribute__ ((packed));
++
++/* SI */
++struct si1 {
++ __be16 siamr1; /* SI1 TDMA mode register */
++ __be16 sibmr1; /* SI1 TDMB mode register */
++ __be16 sicmr1; /* SI1 TDMC mode register */
++ __be16 sidmr1; /* SI1 TDMD mode register */
++ u8 siglmr1_h; /* SI1 global mode register high */
++ u8 res0[0x1];
++ u8 sicmdr1_h; /* SI1 command register high */
++ u8 res2[0x1];
++ u8 sistr1_h; /* SI1 status register high */
++ u8 res3[0x1];
++ __be16 sirsr1_h; /* SI1 RAM shadow address register high */
++ u8 sitarc1; /* SI1 RAM counter Tx TDMA */
++ u8 sitbrc1; /* SI1 RAM counter Tx TDMB */
++ u8 sitcrc1; /* SI1 RAM counter Tx TDMC */
++ u8 sitdrc1; /* SI1 RAM counter Tx TDMD */
++ u8 sirarc1; /* SI1 RAM counter Rx TDMA */
++ u8 sirbrc1; /* SI1 RAM counter Rx TDMB */
++ u8 sircrc1; /* SI1 RAM counter Rx TDMC */
++ u8 sirdrc1; /* SI1 RAM counter Rx TDMD */
++ u8 res4[0x8];
++ __be16 siemr1; /* SI1 TDME mode register 16 bits */
++ __be16 sifmr1; /* SI1 TDMF mode register 16 bits */
++ __be16 sigmr1; /* SI1 TDMG mode register 16 bits */
++ __be16 sihmr1; /* SI1 TDMH mode register 16 bits */
++ u8 siglmg1_l; /* SI1 global mode register low 8 bits */
++ u8 res5[0x1];
++ u8 sicmdr1_l; /* SI1 command register low 8 bits */
++ u8 res6[0x1];
++ u8 sistr1_l; /* SI1 status register low 8 bits */
++ u8 res7[0x1];
++ __be16 sirsr1_l; /* SI1 RAM shadow address register low 16 bits*/
++ u8 siterc1; /* SI1 RAM counter Tx TDME 8 bits */
++ u8 sitfrc1; /* SI1 RAM counter Tx TDMF 8 bits */
++ u8 sitgrc1; /* SI1 RAM counter Tx TDMG 8 bits */
++ u8 sithrc1; /* SI1 RAM counter Tx TDMH 8 bits */
++ u8 sirerc1; /* SI1 RAM counter Rx TDME 8 bits */
++ u8 sirfrc1; /* SI1 RAM counter Rx TDMF 8 bits */
++ u8 sirgrc1; /* SI1 RAM counter Rx TDMG 8 bits */
++ u8 sirhrc1; /* SI1 RAM counter Rx TDMH 8 bits */
++ u8 res8[0x8];
++ __be32 siml1; /* SI1 multiframe limit register */
++ u8 siedm1; /* SI1 extended diagnostic mode register */
++ u8 res9[0xBB];
++} __attribute__ ((packed));
++
++/* SI Routing Tables */
++struct sir {
++ u8 tx[0x400];
++ u8 rx[0x400];
++ u8 res0[0x800];
++} __attribute__ ((packed));
++
++/* USB Controller */
++struct usb_ctlr {
++ u8 usb_usmod;
++ u8 usb_usadr;
++ u8 usb_uscom;
++ u8 res1[1];
++ __be16 usb_usep1;
++ __be16 usb_usep2;
++ __be16 usb_usep3;
++ __be16 usb_usep4;
++ u8 res2[4];
++ __be16 usb_usber;
++ u8 res3[2];
++ __be16 usb_usbmr;
++ u8 res4[1];
++ u8 usb_usbs;
++ __be16 usb_ussft;
++ u8 res5[2];
++ __be16 usb_usfrn;
++ u8 res6[0x22];
++} __attribute__ ((packed));
++
++/* MCC */
++struct mcc {
++ __be32 mcce; /* MCC event register */
++ __be32 mccm; /* MCC mask register */
++ __be32 mccf; /* MCC configuration register */
++ __be32 merl; /* MCC emergency request level register */
++ u8 res0[0xF0];
++} __attribute__ ((packed));
++
++/* QE UCC Slow */
++struct ucc_slow {
++ __be32 gumr_l; /* UCCx general mode register (low) */
++ __be32 gumr_h; /* UCCx general mode register (high) */
++ __be16 upsmr; /* UCCx protocol-specific mode register */
++ u8 res0[0x2];
++ __be16 utodr; /* UCCx transmit on demand register */
++ __be16 udsr; /* UCCx data synchronization register */
++ __be16 ucce; /* UCCx event register */
++ u8 res1[0x2];
++ __be16 uccm; /* UCCx mask register */
++ u8 res2[0x1];
++ u8 uccs; /* UCCx status register */
++ u8 res3[0x24];
++ __be16 utpt;
++ u8 guemr; /* UCC general extended mode register */
++ u8 res4[0x200 - 0x091];
++} __attribute__ ((packed));
++
++/* QE UCC Fast */
++struct ucc_fast {
++ __be32 gumr; /* UCCx general mode register */
++ __be32 upsmr; /* UCCx protocol-specific mode register */
++ __be16 utodr; /* UCCx transmit on demand register */
++ u8 res0[0x2];
++ __be16 udsr; /* UCCx data synchronization register */
++ u8 res1[0x2];
++ __be32 ucce; /* UCCx event register */
++ __be32 uccm; /* UCCx mask register */
++ u8 uccs; /* UCCx status register */
++ u8 res2[0x7];
++ __be32 urfb; /* UCC receive FIFO base */
++ __be16 urfs; /* UCC receive FIFO size */
++ u8 res3[0x2];
++ __be16 urfet; /* UCC receive FIFO emergency threshold */
++ __be16 urfset; /* UCC receive FIFO special emergency
++ threshold */
++ __be32 utfb; /* UCC transmit FIFO base */
++ __be16 utfs; /* UCC transmit FIFO size */
++ u8 res4[0x2];
++ __be16 utfet; /* UCC transmit FIFO emergency threshold */
++ u8 res5[0x2];
++ __be16 utftt; /* UCC transmit FIFO transmit threshold */
++ u8 res6[0x2];
++ __be16 utpt; /* UCC transmit polling timer */
++ u8 res7[0x2];
++ __be32 urtry; /* UCC retry counter register */
++ u8 res8[0x4C];
++ u8 guemr; /* UCC general extended mode register */
++ u8 res9[0x100 - 0x091];
++} __attribute__ ((packed));
++
++/* QE UCC */
++struct ucc_common {
++ u8 res1[0x90];
++ u8 guemr;
++ u8 res2[0x200 - 0x091];
++} __attribute__ ((packed));
++
++struct ucc {
++ union {
++ struct ucc_slow slow;
++ struct ucc_fast fast;
++ struct ucc_common common;
++ };
++} __attribute__ ((packed));
++
++/* MultiPHY UTOPIA POS Controllers (UPC) */
++struct upc {
++ __be32 upgcr; /* UTOPIA/POS general configuration register */
++ __be32 uplpa; /* UTOPIA/POS last PHY address */
++ __be32 uphec; /* ATM HEC register */
++ __be32 upuc; /* UTOPIA/POS UCC configuration */
++ __be32 updc1; /* UTOPIA/POS device 1 configuration */
++ __be32 updc2; /* UTOPIA/POS device 2 configuration */
++ __be32 updc3; /* UTOPIA/POS device 3 configuration */
++ __be32 updc4; /* UTOPIA/POS device 4 configuration */
++ __be32 upstpa; /* UTOPIA/POS STPA threshold */
++ u8 res0[0xC];
++ __be32 updrs1_h; /* UTOPIA/POS device 1 rate select */
++ __be32 updrs1_l; /* UTOPIA/POS device 1 rate select */
++ __be32 updrs2_h; /* UTOPIA/POS device 2 rate select */
++ __be32 updrs2_l; /* UTOPIA/POS device 2 rate select */
++ __be32 updrs3_h; /* UTOPIA/POS device 3 rate select */
++ __be32 updrs3_l; /* UTOPIA/POS device 3 rate select */
++ __be32 updrs4_h; /* UTOPIA/POS device 4 rate select */
++ __be32 updrs4_l; /* UTOPIA/POS device 4 rate select */
++ __be32 updrp1; /* UTOPIA/POS device 1 receive priority low */
++ __be32 updrp2; /* UTOPIA/POS device 2 receive priority low */
++ __be32 updrp3; /* UTOPIA/POS device 3 receive priority low */
++ __be32 updrp4; /* UTOPIA/POS device 4 receive priority low */
++ __be32 upde1; /* UTOPIA/POS device 1 event */
++ __be32 upde2; /* UTOPIA/POS device 2 event */
++ __be32 upde3; /* UTOPIA/POS device 3 event */
++ __be32 upde4; /* UTOPIA/POS device 4 event */
++ __be16 uprp1;
++ __be16 uprp2;
++ __be16 uprp3;
++ __be16 uprp4;
++ u8 res1[0x8];
++ __be16 uptirr1_0; /* Device 1 transmit internal rate 0 */
++ __be16 uptirr1_1; /* Device 1 transmit internal rate 1 */
++ __be16 uptirr1_2; /* Device 1 transmit internal rate 2 */
++ __be16 uptirr1_3; /* Device 1 transmit internal rate 3 */
++ __be16 uptirr2_0; /* Device 2 transmit internal rate 0 */
++ __be16 uptirr2_1; /* Device 2 transmit internal rate 1 */
++ __be16 uptirr2_2; /* Device 2 transmit internal rate 2 */
++ __be16 uptirr2_3; /* Device 2 transmit internal rate 3 */
++ __be16 uptirr3_0; /* Device 3 transmit internal rate 0 */
++ __be16 uptirr3_1; /* Device 3 transmit internal rate 1 */
++ __be16 uptirr3_2; /* Device 3 transmit internal rate 2 */
++ __be16 uptirr3_3; /* Device 3 transmit internal rate 3 */
++ __be16 uptirr4_0; /* Device 4 transmit internal rate 0 */
++ __be16 uptirr4_1; /* Device 4 transmit internal rate 1 */
++ __be16 uptirr4_2; /* Device 4 transmit internal rate 2 */
++ __be16 uptirr4_3; /* Device 4 transmit internal rate 3 */
++ __be32 uper1; /* Device 1 port enable register */
++ __be32 uper2; /* Device 2 port enable register */
++ __be32 uper3; /* Device 3 port enable register */
++ __be32 uper4; /* Device 4 port enable register */
++ u8 res2[0x150];
++} __attribute__ ((packed));
++
++/* SDMA */
++struct sdma {
++ __be32 sdsr; /* Serial DMA status register */
++ __be32 sdmr; /* Serial DMA mode register */
++ __be32 sdtr1; /* SDMA system bus threshold register */
++ __be32 sdtr2; /* SDMA secondary bus threshold register */
++ __be32 sdhy1; /* SDMA system bus hysteresis register */
++ __be32 sdhy2; /* SDMA secondary bus hysteresis register */
++ __be32 sdta1; /* SDMA system bus address register */
++ __be32 sdta2; /* SDMA secondary bus address register */
++ __be32 sdtm1; /* SDMA system bus MSNUM register */
++ __be32 sdtm2; /* SDMA secondary bus MSNUM register */
++ u8 res0[0x10];
++ __be32 sdaqr; /* SDMA address bus qualify register */
++ __be32 sdaqmr; /* SDMA address bus qualify mask register */
++ u8 res1[0x4];
++ __be32 sdebcr; /* SDMA CAM entries base register */
++ u8 res2[0x38];
++} __attribute__ ((packed));
++
++/* Debug Space */
++struct dbg {
++ __be32 bpdcr; /* Breakpoint debug command register */
++ __be32 bpdsr; /* Breakpoint debug status register */
++ __be32 bpdmr; /* Breakpoint debug mask register */
++ __be32 bprmrr0; /* Breakpoint request mode risc register 0 */
++ __be32 bprmrr1; /* Breakpoint request mode risc register 1 */
++ u8 res0[0x8];
++ __be32 bprmtr0; /* Breakpoint request mode trb register 0 */
++ __be32 bprmtr1; /* Breakpoint request mode trb register 1 */
++ u8 res1[0x8];
++ __be32 bprmir; /* Breakpoint request mode immediate register */
++ __be32 bprmsr; /* Breakpoint request mode serial register */
++ __be32 bpemr; /* Breakpoint exit mode register */
++ u8 res2[0x48];
++} __attribute__ ((packed));
++
++/* RISC Special Registers (Trap and Breakpoint) */
++struct rsp {
++ u8 fixme[0x100];
++} __attribute__ ((packed));
++
++struct qe_immap {
++ struct qe_iram iram; /* I-RAM */
++ struct qe_ic_regs ic; /* Interrupt Controller */
++ struct cp_qe cp; /* Communications Processor */
++ struct qe_mux qmx; /* QE Multiplexer */
++ struct qe_timers qet; /* QE Timers */
++ struct spi spi[0x2]; /* spi */
++ struct mcc mcc; /* mcc */
++ struct qe_brg brg; /* brg */
++ struct usb_ctlr usb; /* USB */
++ struct si1 si1; /* SI */
++ u8 res11[0x800];
++ struct sir sir; /* SI Routing Tables */
++ struct ucc ucc1; /* ucc1 */
++ struct ucc ucc3; /* ucc3 */
++ struct ucc ucc5; /* ucc5 */
++ struct ucc ucc7; /* ucc7 */
++ u8 res12[0x600];
++ struct upc upc1; /* MultiPHY UTOPIA POS Ctrlr 1*/
++ struct ucc ucc2; /* ucc2 */
++ struct ucc ucc4; /* ucc4 */
++ struct ucc ucc6; /* ucc6 */
++ struct ucc ucc8; /* ucc8 */
++ u8 res13[0x600];
++ struct upc upc2; /* MultiPHY UTOPIA POS Ctrlr 2*/
++ struct sdma sdma; /* SDMA */
++ struct dbg dbg; /* Debug Space */
++ struct rsp rsp[0x2]; /* RISC Special Registers
++ (Trap and Breakpoint) */
++ u8 res14[0x300];
++ u8 res15[0x3A00];
++ u8 res16[0x8000]; /* 0x108000 - 0x110000 */
++ u8 muram[0xC000]; /* 0x110000 - 0x11C000
++ Multi-user RAM */
++ u8 res17[0x24000]; /* 0x11C000 - 0x140000 */
++ u8 res18[0xC0000]; /* 0x140000 - 0x200000 */
++} __attribute__ ((packed));
++
++extern struct qe_immap *qe_immr;
++extern phys_addr_t get_qe_base(void);
++
++static inline unsigned long immrbar_virt_to_phys(volatile void * address)
++{
++ if ( ((u32)address >= (u32)qe_immr) &&
++ ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) )
++ return (unsigned long)(address - (u32)qe_immr +
++ (u32)get_qe_base());
++ return (unsigned long)virt_to_phys(address);
++}
++
++#endif /* __KERNEL__ */
++#endif /* _ASM_POWERPC_IMMAP_QE_H */
+diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
+index 212428d..c2c5f14 100644
+--- a/include/asm-powerpc/io.h
++++ b/include/asm-powerpc/io.h
+@@ -11,6 +11,7 @@
+
+ /* Check of existence of legacy devices */
+ extern int check_legacy_ioport(unsigned long base_port);
++#define PNPBIOS_BASE 0xf000 /* only relevant for PReP */
+
+ #ifndef CONFIG_PPC64
+ #include <asm-ppc/io.h>
+@@ -20,20 +21,11 @@ extern int check_legacy_ioport(unsigned
+ #include <asm/page.h>
+ #include <asm/byteorder.h>
+ #include <asm/paca.h>
+-#ifdef CONFIG_PPC_ISERIES
+-#include <asm/iseries/iseries_io.h>
+-#endif
+ #include <asm/synch.h>
+ #include <asm/delay.h>
+
+ #include <asm-generic/iomap.h>
+
+-#define __ide_mm_insw(p, a, c) _insw_ns((volatile u16 __iomem *)(p), (a), (c))
+-#define __ide_mm_insl(p, a, c) _insl_ns((volatile u32 __iomem *)(p), (a), (c))
+-#define __ide_mm_outsw(p, a, c) _outsw_ns((volatile u16 __iomem *)(p), (a), (c))
+-#define __ide_mm_outsl(p, a, c) _outsl_ns((volatile u32 __iomem *)(p), (a), (c))
+-
+-
+ #define SIO_CONFIG_RA 0x398
+ #define SIO_CONFIG_RD 0x399
+
+@@ -43,42 +35,53 @@ extern unsigned long isa_io_base;
+ extern unsigned long pci_io_base;
+
+ #ifdef CONFIG_PPC_ISERIES
+-/* __raw_* accessors aren't supported on iSeries */
+-#define __raw_readb(addr) { BUG(); 0; }
+-#define __raw_readw(addr) { BUG(); 0; }
+-#define __raw_readl(addr) { BUG(); 0; }
+-#define __raw_readq(addr) { BUG(); 0; }
+-#define __raw_writeb(v, addr) { BUG(); 0; }
+-#define __raw_writew(v, addr) { BUG(); 0; }
+-#define __raw_writel(v, addr) { BUG(); 0; }
+-#define __raw_writeq(v, addr) { BUG(); 0; }
+-#define readb(addr) iSeries_Read_Byte(addr)
+-#define readw(addr) iSeries_Read_Word(addr)
+-#define readl(addr) iSeries_Read_Long(addr)
+-#define writeb(data, addr) iSeries_Write_Byte((data),(addr))
+-#define writew(data, addr) iSeries_Write_Word((data),(addr))
+-#define writel(data, addr) iSeries_Write_Long((data),(addr))
+-#define memset_io(a,b,c) iSeries_memset_io((a),(b),(c))
+-#define memcpy_fromio(a,b,c) iSeries_memcpy_fromio((a), (b), (c))
+-#define memcpy_toio(a,b,c) iSeries_memcpy_toio((a), (b), (c))
+-
+-#define inb(addr) readb(((void __iomem *)(long)(addr)))
+-#define inw(addr) readw(((void __iomem *)(long)(addr)))
+-#define inl(addr) readl(((void __iomem *)(long)(addr)))
+-#define outb(data,addr) writeb(data,((void __iomem *)(long)(addr)))
+-#define outw(data,addr) writew(data,((void __iomem *)(long)(addr)))
+-#define outl(data,addr) writel(data,((void __iomem *)(long)(addr)))
+-/*
+- * The *_ns versions below don't do byte-swapping.
+- * Neither do the standard versions now, these are just here
+- * for older code.
+- */
+-#define insb(port, buf, ns) _insb((u8 __iomem *)((port)+pci_io_base), (buf), (ns))
+-#define insw(port, buf, ns) _insw_ns((u8 __iomem *)((port)+pci_io_base), (buf), (ns))
+-#define insl(port, buf, nl) _insl_ns((u8 __iomem *)((port)+pci_io_base), (buf), (nl))
+-#define insw_ns(port, buf, ns) _insw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
+-#define insl_ns(port, buf, nl) _insl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
+-#else
++
++extern int in_8(const volatile unsigned char __iomem *addr);
++extern void out_8(volatile unsigned char __iomem *addr, int val);
++extern int in_le16(const volatile unsigned short __iomem *addr);
++extern int in_be16(const volatile unsigned short __iomem *addr);
++extern void out_le16(volatile unsigned short __iomem *addr, int val);
++extern void out_be16(volatile unsigned short __iomem *addr, int val);
++extern unsigned in_le32(const volatile unsigned __iomem *addr);
++extern unsigned in_be32(const volatile unsigned __iomem *addr);
++extern void out_le32(volatile unsigned __iomem *addr, int val);
++extern void out_be32(volatile unsigned __iomem *addr, int val);
++extern unsigned long in_le64(const volatile unsigned long __iomem *addr);
++extern unsigned long in_be64(const volatile unsigned long __iomem *addr);
++extern void out_le64(volatile unsigned long __iomem *addr, unsigned long val);
++extern void out_be64(volatile unsigned long __iomem *addr, unsigned long val);
++
++extern unsigned char __raw_readb(const volatile void __iomem *addr);
++extern unsigned short __raw_readw(const volatile void __iomem *addr);
++extern unsigned int __raw_readl(const volatile void __iomem *addr);
++extern unsigned long __raw_readq(const volatile void __iomem *addr);
++extern void __raw_writeb(unsigned char v, volatile void __iomem *addr);
++extern void __raw_writew(unsigned short v, volatile void __iomem *addr);
++extern void __raw_writel(unsigned int v, volatile void __iomem *addr);
++extern void __raw_writeq(unsigned long v, volatile void __iomem *addr);
++
++extern void memset_io(volatile void __iomem *addr, int c, unsigned long n);
++extern void memcpy_fromio(void *dest, const volatile void __iomem *src,
++ unsigned long n);
++extern void memcpy_toio(volatile void __iomem *dest, const void *src,
++ unsigned long n);
++
++#else /* CONFIG_PPC_ISERIES */
++
++#define in_8(addr) __in_8((addr))
++#define out_8(addr, val) __out_8((addr), (val))
++#define in_le16(addr) __in_le16((addr))
++#define in_be16(addr) __in_be16((addr))
++#define out_le16(addr, val) __out_le16((addr), (val))
++#define out_be16(addr, val) __out_be16((addr), (val))
++#define in_le32(addr) __in_le32((addr))
++#define in_be32(addr) __in_be32((addr))
++#define out_le32(addr, val) __out_le32((addr), (val))
++#define out_be32(addr, val) __out_be32((addr), (val))
++#define in_le64(addr) __in_le64((addr))
++#define in_be64(addr) __in_be64((addr))
++#define out_le64(addr, val) __out_le64((addr), (val))
++#define out_be64(addr, val) __out_be64((addr), (val))
+
+ static inline unsigned char __raw_readb(const volatile void __iomem *addr)
+ {
+@@ -112,23 +115,11 @@ static inline void __raw_writeq(unsigned
+ {
+ *(volatile unsigned long __force *)addr = v;
+ }
+-#define readb(addr) eeh_readb(addr)
+-#define readw(addr) eeh_readw(addr)
+-#define readl(addr) eeh_readl(addr)
+-#define readq(addr) eeh_readq(addr)
+-#define writeb(data, addr) eeh_writeb((data), (addr))
+-#define writew(data, addr) eeh_writew((data), (addr))
+-#define writel(data, addr) eeh_writel((data), (addr))
+-#define writeq(data, addr) eeh_writeq((data), (addr))
+ #define memset_io(a,b,c) eeh_memset_io((a),(b),(c))
+ #define memcpy_fromio(a,b,c) eeh_memcpy_fromio((a),(b),(c))
+ #define memcpy_toio(a,b,c) eeh_memcpy_toio((a),(b),(c))
+-#define inb(port) eeh_inb((unsigned long)port)
+-#define outb(val, port) eeh_outb(val, (unsigned long)port)
+-#define inw(port) eeh_inw((unsigned long)port)
+-#define outw(val, port) eeh_outw(val, (unsigned long)port)
+-#define inl(port) eeh_inl((unsigned long)port)
+-#define outl(val, port) eeh_outl(val, (unsigned long)port)
++
++#endif /* CONFIG_PPC_ISERIES */
+
+ /*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+@@ -138,35 +129,45 @@ static inline void __raw_writeq(unsigned
+ #define insb(port, buf, ns) eeh_insb((port), (buf), (ns))
+ #define insw(port, buf, ns) eeh_insw_ns((port), (buf), (ns))
+ #define insl(port, buf, nl) eeh_insl_ns((port), (buf), (nl))
+-#define insw_ns(port, buf, ns) eeh_insw_ns((port), (buf), (ns))
+-#define insl_ns(port, buf, nl) eeh_insl_ns((port), (buf), (nl))
+-
+-#endif
+
+ #define outsb(port, buf, ns) _outsb((u8 __iomem *)((port)+pci_io_base), (buf), (ns))
+ #define outsw(port, buf, ns) _outsw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
+ #define outsl(port, buf, nl) _outsl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
+
++#define readb(addr) eeh_readb(addr)
++#define readw(addr) eeh_readw(addr)
++#define readl(addr) eeh_readl(addr)
++#define readq(addr) eeh_readq(addr)
++#define writeb(data, addr) eeh_writeb((data), (addr))
++#define writew(data, addr) eeh_writew((data), (addr))
++#define writel(data, addr) eeh_writel((data), (addr))
++#define writeq(data, addr) eeh_writeq((data), (addr))
++#define inb(port) eeh_inb((unsigned long)port)
++#define outb(val, port) eeh_outb(val, (unsigned long)port)
++#define inw(port) eeh_inw((unsigned long)port)
++#define outw(val, port) eeh_outw(val, (unsigned long)port)
++#define inl(port) eeh_inl((unsigned long)port)
++#define outl(val, port) eeh_outl(val, (unsigned long)port)
++
+ #define readb_relaxed(addr) readb(addr)
+ #define readw_relaxed(addr) readw(addr)
+ #define readl_relaxed(addr) readl(addr)
+ #define readq_relaxed(addr) readq(addr)
+
+-extern void _insb(volatile u8 __iomem *port, void *buf, int ns);
+-extern void _outsb(volatile u8 __iomem *port, const void *buf, int ns);
+-extern void _insw(volatile u16 __iomem *port, void *buf, int ns);
+-extern void _outsw(volatile u16 __iomem *port, const void *buf, int ns);
+-extern void _insl(volatile u32 __iomem *port, void *buf, int nl);
+-extern void _outsl(volatile u32 __iomem *port, const void *buf, int nl);
+-extern void _insw_ns(volatile u16 __iomem *port, void *buf, int ns);
+-extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, int ns);
+-extern void _insl_ns(volatile u32 __iomem *port, void *buf, int nl);
+-extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl);
++extern void _insb(volatile u8 __iomem *port, void *buf, long count);
++extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
++extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
++extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
++extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
++extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
+
+ static inline void mmiowb(void)
+ {
+- __asm__ __volatile__ ("sync" : : : "memory");
+- get_paca()->io_sync = 0;
++ unsigned long tmp;
++
++ __asm__ __volatile__("sync; li %0,0; stb %0,%1(13)"
++ : "=&r" (tmp) : "i" (offsetof(struct paca_struct, io_sync))
++ : "memory");
+ }
+
+ /*
+@@ -180,14 +181,6 @@ static inline void mmiowb(void)
+ #define inl_p(port) inl(port)
+ #define outl_p(val, port) (udelay(1), outl((val), (port)))
+
+-/*
+- * The *_ns versions below don't do byte-swapping.
+- * Neither do the standard versions now, these are just here
+- * for older code.
+- */
+-#define outsw_ns(port, buf, ns) _outsw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
+-#define outsl_ns(port, buf, nl) _outsl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
+-
+
+ #define IO_SPACE_LIMIT ~(0UL)
+
+@@ -279,7 +272,7 @@ static inline void iosync(void)
+ * and should not be used directly by device drivers. Use inb/readb
+ * instead.
+ */
+-static inline int in_8(const volatile unsigned char __iomem *addr)
++static inline int __in_8(const volatile unsigned char __iomem *addr)
+ {
+ int ret;
+
+@@ -288,14 +281,14 @@ static inline int in_8(const volatile un
+ return ret;
+ }
+
+-static inline void out_8(volatile unsigned char __iomem *addr, int val)
++static inline void __out_8(volatile unsigned char __iomem *addr, int val)
+ {
+ __asm__ __volatile__("sync; stb%U0%X0 %1,%0"
+ : "=m" (*addr) : "r" (val));
+ get_paca()->io_sync = 1;
+ }
+
+-static inline int in_le16(const volatile unsigned short __iomem *addr)
++static inline int __in_le16(const volatile unsigned short __iomem *addr)
+ {
+ int ret;
+
+@@ -304,7 +297,7 @@ static inline int in_le16(const volatile
+ return ret;
+ }
+
+-static inline int in_be16(const volatile unsigned short __iomem *addr)
++static inline int __in_be16(const volatile unsigned short __iomem *addr)
+ {
+ int ret;
+
+@@ -313,21 +306,21 @@ static inline int in_be16(const volatile
+ return ret;
+ }
+
+-static inline void out_le16(volatile unsigned short __iomem *addr, int val)
++static inline void __out_le16(volatile unsigned short __iomem *addr, int val)
+ {
+ __asm__ __volatile__("sync; sthbrx %1,0,%2"
+ : "=m" (*addr) : "r" (val), "r" (addr));
+ get_paca()->io_sync = 1;
+ }
+
+-static inline void out_be16(volatile unsigned short __iomem *addr, int val)
++static inline void __out_be16(volatile unsigned short __iomem *addr, int val)
+ {
+ __asm__ __volatile__("sync; sth%U0%X0 %1,%0"
+ : "=m" (*addr) : "r" (val));
+ get_paca()->io_sync = 1;
+ }
+
+-static inline unsigned in_le32(const volatile unsigned __iomem *addr)
++static inline unsigned __in_le32(const volatile unsigned __iomem *addr)
+ {
+ unsigned ret;
+
+@@ -336,7 +329,7 @@ static inline unsigned in_le32(const vol
+ return ret;
+ }
+
+-static inline unsigned in_be32(const volatile unsigned __iomem *addr)
++static inline unsigned __in_be32(const volatile unsigned __iomem *addr)
+ {
+ unsigned ret;
+
+@@ -345,21 +338,21 @@ static inline unsigned in_be32(const vol
+ return ret;
+ }
+
+-static inline void out_le32(volatile unsigned __iomem *addr, int val)
++static inline void __out_le32(volatile unsigned __iomem *addr, int val)
+ {
+ __asm__ __volatile__("sync; stwbrx %1,0,%2" : "=m" (*addr)
+ : "r" (val), "r" (addr));
+ get_paca()->io_sync = 1;
+ }
+
+-static inline void out_be32(volatile unsigned __iomem *addr, int val)
++static inline void __out_be32(volatile unsigned __iomem *addr, int val)
+ {
+ __asm__ __volatile__("sync; stw%U0%X0 %1,%0"
+ : "=m" (*addr) : "r" (val));
+ get_paca()->io_sync = 1;
+ }
+
+-static inline unsigned long in_le64(const volatile unsigned long __iomem *addr)
++static inline unsigned long __in_le64(const volatile unsigned long __iomem *addr)
+ {
+ unsigned long tmp, ret;
+
+@@ -379,7 +372,7 @@ static inline unsigned long in_le64(cons
+ return ret;
+ }
+
+-static inline unsigned long in_be64(const volatile unsigned long __iomem *addr)
++static inline unsigned long __in_be64(const volatile unsigned long __iomem *addr)
+ {
+ unsigned long ret;
+
+@@ -388,7 +381,7 @@ static inline unsigned long in_be64(cons
+ return ret;
+ }
+
+-static inline void out_le64(volatile unsigned long __iomem *addr, unsigned long val)
++static inline void __out_le64(volatile unsigned long __iomem *addr, unsigned long val)
+ {
+ unsigned long tmp;
+
+@@ -406,43 +399,13 @@ static inline void out_le64(volatile uns
+ get_paca()->io_sync = 1;
+ }
+
+-static inline void out_be64(volatile unsigned long __iomem *addr, unsigned long val)
++static inline void __out_be64(volatile unsigned long __iomem *addr, unsigned long val)
+ {
+ __asm__ __volatile__("sync; std%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
+ get_paca()->io_sync = 1;
+ }
+
+-#ifndef CONFIG_PPC_ISERIES
+ #include <asm/eeh.h>
+-#endif
+-
+-/**
+- * check_signature - find BIOS signatures
+- * @io_addr: mmio address to check
+- * @signature: signature block
+- * @length: length of signature
+- *
+- * Perform a signature comparison with the mmio address io_addr. This
+- * address should have been obtained by ioremap.
+- * Returns 1 on a match.
+- */
+-static inline int check_signature(const volatile void __iomem * io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+-#ifndef CONFIG_PPC_ISERIES
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+-#endif
+- return retval;
+-}
+
+ /* Nothing to do */
+
+diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
+index a5e9864..39fad68 100644
+--- a/include/asm-powerpc/iommu.h
++++ b/include/asm-powerpc/iommu.h
+@@ -22,17 +22,35 @@
+ #define _ASM_IOMMU_H
+ #ifdef __KERNEL__
+
+-#include <asm/types.h>
++#include <linux/compiler.h>
+ #include <linux/spinlock.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
++#include <asm/types.h>
++#include <asm/bitops.h>
++
++#define IOMMU_PAGE_SHIFT 12
++#define IOMMU_PAGE_SIZE (ASM_CONST(1) << IOMMU_PAGE_SHIFT)
++#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1))
++#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
++
++#ifndef __ASSEMBLY__
++
++/* Pure 2^n version of get_order */
++static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
++{
++ return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
++}
++
++#endif /* __ASSEMBLY__ */
++
+
+ /*
+ * IOMAP_MAX_ORDER defines the largest contiguous block
+ * of dma space we can get. IOMAP_MAX_ORDER = 13
+ * allows up to 2**12 pages (4096 * 4096) = 16 MB
+ */
+-#define IOMAP_MAX_ORDER 13
++#define IOMAP_MAX_ORDER 13
+
+ struct iommu_table {
+ unsigned long it_busno; /* Bus number this table belongs to */
+diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h
+index 53079ec..9fbb034 100644
+--- a/include/asm-powerpc/ipic.h
++++ b/include/asm-powerpc/ipic.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/ipic.h
++ * include/asm-powerpc/ipic.h
+ *
+ * IPIC external definitions and structure.
+ *
+@@ -79,12 +79,12 @@ extern void ipic_clear_mcp_status(u32 ma
+
+ #ifdef CONFIG_PPC_MERGE
+ extern void ipic_init(struct device_node *node, unsigned int flags);
+-extern unsigned int ipic_get_irq(struct pt_regs *regs);
++extern unsigned int ipic_get_irq(void);
+ #else
+ extern void ipic_init(phys_addr_t phys_addr, unsigned int flags,
+ unsigned int irq_offset,
+ unsigned char *senses, unsigned int senses_count);
+-extern int ipic_get_irq(struct pt_regs *regs);
++extern int ipic_get_irq(void);
+ #endif
+
+ #endif /* __ASM_IPIC_H__ */
+diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
+index d903a62..f960f53 100644
+--- a/include/asm-powerpc/irq.h
++++ b/include/asm-powerpc/irq.h
+@@ -9,7 +9,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/threads.h>
+ #include <linux/list.h>
+ #include <linux/radix-tree.h>
+@@ -137,7 +136,7 @@ struct irq_map_entry {
+ extern struct irq_map_entry irq_map[NR_IRQS];
+
+
+-/***
++/**
+ * irq_alloc_host - Allocate a new irq_host data structure
+ * @node: device-tree node of the interrupt controller
+ * @revmap_type: type of reverse mapping to use
+@@ -159,14 +158,14 @@ extern struct irq_host *irq_alloc_host(u
+ irq_hw_number_t inval_irq);
+
+
+-/***
++/**
+ * irq_find_host - Locates a host for a given device node
+ * @node: device-tree node of the interrupt controller
+ */
+ extern struct irq_host *irq_find_host(struct device_node *node);
+
+
+-/***
++/**
+ * irq_set_default_host - Set a "default" host
+ * @host: default host pointer
+ *
+@@ -178,7 +177,7 @@ extern struct irq_host *irq_find_host(st
+ extern void irq_set_default_host(struct irq_host *host);
+
+
+-/***
++/**
+ * irq_set_virq_count - Set the maximum number of virt irqs
+ * @count: number of linux virtual irqs, capped with NR_IRQS
+ *
+@@ -188,7 +187,7 @@ extern void irq_set_default_host(struct
+ extern void irq_set_virq_count(unsigned int count);
+
+
+-/***
++/**
+ * irq_create_mapping - Map a hardware interrupt into linux virq space
+ * @host: host owning this hardware interrupt or NULL for default host
+ * @hwirq: hardware irq number in that host space
+@@ -202,13 +201,13 @@ extern unsigned int irq_create_mapping(s
+ irq_hw_number_t hwirq);
+
+
+-/***
++/**
+ * irq_dispose_mapping - Unmap an interrupt
+ * @virq: linux virq number of the interrupt to unmap
+ */
+ extern void irq_dispose_mapping(unsigned int virq);
+
+-/***
++/**
+ * irq_find_mapping - Find a linux virq from an hw irq number.
+ * @host: host owning this hardware interrupt
+ * @hwirq: hardware irq number in that host space
+@@ -221,7 +220,7 @@ extern unsigned int irq_find_mapping(str
+ irq_hw_number_t hwirq);
+
+
+-/***
++/**
+ * irq_radix_revmap - Find a linux virq from a hw irq number.
+ * @host: host owning this hardware interrupt
+ * @hwirq: hardware irq number in that host space
+@@ -232,7 +231,7 @@ extern unsigned int irq_find_mapping(str
+ extern unsigned int irq_radix_revmap(struct irq_host *host,
+ irq_hw_number_t hwirq);
+
+-/***
++/**
+ * irq_linear_revmap - Find a linux virq from a hw irq number.
+ * @host: host owning this hardware interrupt
+ * @hwirq: hardware irq number in that host space
+@@ -247,7 +246,7 @@ extern unsigned int irq_linear_revmap(st
+
+
+
+-/***
++/**
+ * irq_alloc_virt - Allocate virtual irq numbers
+ * @host: host owning these new virtual irqs
+ * @count: number of consecutive numbers to allocate
+@@ -261,7 +260,7 @@ extern unsigned int irq_alloc_virt(struc
+ unsigned int count,
+ unsigned int hint);
+
+-/***
++/**
+ * irq_free_virt - Free virtual irq numbers
+ * @virq: virtual irq number of the first interrupt to free
+ * @count: number of interrupts to free
+@@ -300,7 +299,7 @@ extern unsigned int irq_of_parse_and_map
+
+ /* -- End OF helpers -- */
+
+-/***
++/**
+ * irq_early_init - Init irq remapping subsystem
+ */
+ extern void irq_early_init(void);
+@@ -826,7 +825,7 @@ extern struct thread_info *softirq_ctx[N
+
+ extern void irq_ctx_init(void);
+ extern void call_do_softirq(struct thread_info *tp);
+-extern int call_handle_irq(int irq, void *p1, void *p2,
++extern int call_handle_irq(int irq, void *p1,
+ struct thread_info *tp, void *func);
+ #else
+ #define irq_ctx_init()
+diff --git a/include/asm-powerpc/irq_regs.h b/include/asm-powerpc/irq_regs.h
+new file mode 100644
+index 0000000..ba94b51
+--- /dev/null
++++ b/include/asm-powerpc/irq_regs.h
+@@ -0,0 +1,2 @@
++#include <asm-generic/irq_regs.h>
++
+diff --git a/include/asm-powerpc/iseries/hv_call_xm.h b/include/asm-powerpc/iseries/hv_call_xm.h
+index ca9202c..392ac3f 100644
+--- a/include/asm-powerpc/iseries/hv_call_xm.h
++++ b/include/asm-powerpc/iseries/hv_call_xm.h
+@@ -16,23 +16,6 @@
+ #define HvCallXmSetTce HvCallXm + 11
+ #define HvCallXmSetTces HvCallXm + 13
+
+-/*
+- * Structure passed to HvCallXm_getTceTableParms
+- */
+-struct iommu_table_cb {
+- unsigned long itc_busno; /* Bus number for this tce table */
+- unsigned long itc_start; /* Will be NULL for secondary */
+- unsigned long itc_totalsize; /* Size (in pages) of whole table */
+- unsigned long itc_offset; /* Index into real tce table of the
+- start of our section */
+- unsigned long itc_size; /* Size (in pages) of our section */
+- unsigned long itc_index; /* Index of this tce table */
+- unsigned short itc_maxtables; /* Max num of tables for partition */
+- unsigned char itc_virtbus; /* Flag to indicate virtual bus */
+- unsigned char itc_slotno; /* IOA Tce Slot Index */
+- unsigned char itc_rsvd[4];
+-};
+-
+ static inline void HvCallXm_getTceTableParms(u64 cb)
+ {
+ HvCall1(HvCallXmGetTceTableParms, cb);
+diff --git a/include/asm-powerpc/iseries/hv_lp_config.h b/include/asm-powerpc/iseries/hv_lp_config.h
+index df8b207..a006fd1 100644
+--- a/include/asm-powerpc/iseries/hv_lp_config.h
++++ b/include/asm-powerpc/iseries/hv_lp_config.h
+@@ -25,7 +25,6 @@
+
+ #include <asm/iseries/hv_call_sc.h>
+ #include <asm/iseries/hv_types.h>
+-#include <asm/iseries/it_lp_naca.h>
+
+ enum {
+ HvCallCfg_Cur = 0,
+@@ -44,16 +43,8 @@ enum {
+ #define HvCallCfgGetHostingLpIndex HvCallCfg + 32
+
+ extern HvLpIndex HvLpConfig_getLpIndex_outline(void);
+-
+-static inline HvLpIndex HvLpConfig_getLpIndex(void)
+-{
+- return itLpNaca.xLpIndex;
+-}
+-
+-static inline HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
+-{
+- return itLpNaca.xPrimaryLpIndex;
+-}
++extern HvLpIndex HvLpConfig_getLpIndex(void);
++extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void);
+
+ static inline u64 HvLpConfig_getMsChunks(void)
+ {
+diff --git a/include/asm-powerpc/iseries/hv_lp_event.h b/include/asm-powerpc/iseries/hv_lp_event.h
+index 4065a4d..6ce2ce1 100644
+--- a/include/asm-powerpc/iseries/hv_lp_event.h
++++ b/include/asm-powerpc/iseries/hv_lp_event.h
+@@ -50,7 +50,7 @@ struct HvLpEvent {
+ u64 xCorrelationToken; /* Unique value for source/type x10-x17 */
+ };
+
+-typedef void (*LpEventHandler)(struct HvLpEvent *, struct pt_regs *);
++typedef void (*LpEventHandler)(struct HvLpEvent *);
+
+ /* Register a handler for an event type - returns 0 on success */
+ extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType,
+diff --git a/include/asm-powerpc/iseries/iseries_io.h b/include/asm-powerpc/iseries/iseries_io.h
+deleted file mode 100644
+index f29009b..0000000
+--- a/include/asm-powerpc/iseries/iseries_io.h
++++ /dev/null
+@@ -1,60 +0,0 @@
+-#ifndef _ASM_POWERPC_ISERIES_ISERIES_IO_H
+-#define _ASM_POWERPC_ISERIES_ISERIES_IO_H
+-
+-
+-#ifdef CONFIG_PPC_ISERIES
+-#include <linux/types.h>
+-/*
+- * Created by Allan Trautman on Thu Dec 28 2000.
+- *
+- * Remaps the io.h for the iSeries Io
+- * Copyright (C) 2000 Allan H Trautman, IBM Corporation
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the:
+- * Free Software Foundation, Inc.,
+- * 59 Temple Place, Suite 330,
+- * Boston, MA 02111-1307 USA
+- *
+- * Change Activity:
+- * Created December 28, 2000
+- * End Change Activity
+- */
+-
+-#ifdef CONFIG_PCI
+-extern u8 iSeries_Read_Byte(const volatile void __iomem * IoAddress);
+-extern u16 iSeries_Read_Word(const volatile void __iomem * IoAddress);
+-extern u32 iSeries_Read_Long(const volatile void __iomem * IoAddress);
+-extern void iSeries_Write_Byte(u8 IoData, volatile void __iomem * IoAddress);
+-extern void iSeries_Write_Word(u16 IoData, volatile void __iomem * IoAddress);
+-extern void iSeries_Write_Long(u32 IoData, volatile void __iomem * IoAddress);
+-
+-extern void iSeries_memset_io(volatile void __iomem *dest, char x, size_t n);
+-extern void iSeries_memcpy_toio(volatile void __iomem *dest, void *source,
+- size_t n);
+-extern void iSeries_memcpy_fromio(void *dest,
+- const volatile void __iomem *source, size_t n);
+-#else
+-static inline u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
+-{
+- return 0xff;
+-}
+-
+-static inline void iSeries_Write_Byte(u8 IoData,
+- volatile void __iomem *IoAddress)
+-{
+-}
+-#endif /* CONFIG_PCI */
+-
+-#endif /* CONFIG_PPC_ISERIES */
+-#endif /* _ASM_POWERPC_ISERIES_ISERIES_IO_H */
+diff --git a/include/asm-powerpc/iseries/it_exp_vpd_panel.h b/include/asm-powerpc/iseries/it_exp_vpd_panel.h
+deleted file mode 100644
+index 304a609..0000000
+--- a/include/asm-powerpc/iseries/it_exp_vpd_panel.h
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/*
+- * Copyright (C) 2002 Dave Boutcher IBM Corporation
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- */
+-#ifndef _ASM_POWERPC_ISERIES_IT_EXT_VPD_PANEL_H
+-#define _ASM_POWERPC_ISERIES_IT_EXT_VPD_PANEL_H
+-
+-/*
+- * This struct maps the panel information
+- *
+- * Warning:
+- * This data must match the architecture for the panel information
+- */
+-
+-#include <asm/types.h>
+-
+-struct ItExtVpdPanel {
+- /* Definition of the Extended Vpd On Panel Data Area */
+- char systemSerial[8];
+- char mfgID[4];
+- char reserved1[24];
+- char machineType[4];
+- char systemID[6];
+- char somUniqueCnt[4];
+- char serialNumberCount;
+- char reserved2[7];
+- u16 bbu3;
+- u16 bbu2;
+- u16 bbu1;
+- char xLocationLabel[8];
+- u8 xRsvd1[6];
+- u16 xFrameId;
+- u8 xRsvd2[48];
+-};
+-
+-extern struct ItExtVpdPanel xItExtVpdPanel;
+-
+-#endif /* _ASM_POWERPC_ISERIES_IT_EXT_VPD_PANEL_H */
+diff --git a/include/asm-powerpc/iseries/it_lp_naca.h b/include/asm-powerpc/iseries/it_lp_naca.h
+deleted file mode 100644
+index 4fdcf05..0000000
+--- a/include/asm-powerpc/iseries/it_lp_naca.h
++++ /dev/null
+@@ -1,80 +0,0 @@
+-/*
+- * 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
+- * (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 _ASM_POWERPC_ISERIES_IT_LP_NACA_H
+-#define _ASM_POWERPC_ISERIES_IT_LP_NACA_H
+-
+-#include <linux/types.h>
+-
+-/*
+- * This control block contains the data that is shared between the
+- * hypervisor (PLIC) and the OS.
+- */
+-
+-struct ItLpNaca {
+-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
+- u32 xDesc; // Eye catcher x00-x03
+- u16 xSize; // Size of this class x04-x05
+- u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07
+- u8 xMaxIntHdlrEntries; // Number of entries in array x08-x08
+- u8 xPrimaryLpIndex; // LP Index of Primary x09-x09
+- u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A
+- u8 xLpIndex; // LP Index x0B-x0B
+- u16 xMaxLpQueues; // Number of allocated queues x0C-x0D
+- u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F
+- u8 xPirEnvironMode; // Piranha or hardware x10-x10
+- u8 xPirConsoleMode; // Piranha console indicator x11-x11
+- u8 xPirDasdMode; // Piranha dasd indicator x12-x12
+- u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x17
+- u8 flags; // flags, see below x18-x1F
+- u8 xSpVpdFormat; // VPD areas are in CSP format ...
+- u8 xIntProcRatio; // Ratio of int procs to procs ...
+- u8 xRsvd1_2[5]; // Reserved ...
+- u16 xRsvd1_3; // Reserved x20-x21
+- u16 xPlicVrmIndex; // VRM index of PLIC x22-x23
+- u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x25
+- u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27
+- u64 xLoadAreaAddr; // ER address of load area x28-x2F
+- u32 xLoadAreaChunks; // Chunks for the load area x30-x33
+- u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37
+- // doing an ASR switch on PASE
+- // system call.
+- u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f
+- u8 xRsvd1_4[64]; // x40-x7F
+-
+-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
+- u8 xRsvd2_0[128]; // Reserved x00-x7F
+-
+-// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
+-// NB: Padding required to keep xInterrruptHdlr at x300 which is required
+-// for v4r4 PLIC.
+- u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F
+- u8 xRsvd3_0[384]; // Reserved 180-2FF
+-
+-// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
+-// handlers
+- u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF
+-};
+-
+-extern struct ItLpNaca itLpNaca;
+-
+-#define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */
+-#define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */
+-#define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */
+-#define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */
+-
+-#endif /* _ASM_POWERPC_ISERIES_IT_LP_NACA_H */
+diff --git a/include/asm-powerpc/iseries/it_lp_queue.h b/include/asm-powerpc/iseries/it_lp_queue.h
+index 284c5a7..4282788 100644
+--- a/include/asm-powerpc/iseries/it_lp_queue.h
++++ b/include/asm-powerpc/iseries/it_lp_queue.h
+@@ -27,8 +27,6 @@
+ #include <asm/types.h>
+ #include <asm/ptrace.h>
+
+-struct HvLpEvent;
+-
+ #define IT_LP_MAX_QUEUES 8
+
+ #define IT_LP_NOT_USED 0 /* Queue will not be used by PLIC */
+@@ -74,7 +72,7 @@ struct hvlpevent_queue {
+ extern struct hvlpevent_queue hvlpevent_queue;
+
+ extern int hvlpevent_is_pending(void);
+-extern void process_hvlpevents(struct pt_regs *);
++extern void process_hvlpevents(void);
+ extern void setup_hvlpevent_queue(void);
+
+ #endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */
+diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h
+index 72a97d3..7a95d29 100644
+--- a/include/asm-powerpc/iseries/vio.h
++++ b/include/asm-powerpc/iseries/vio.h
+@@ -122,6 +122,34 @@ enum viorc {
+ viorc_openRejected = 0x0301
+ };
+
++/*
++ * The structure of the events that flow between us and OS/400 for chario
++ * events. You can't mess with this unless the OS/400 side changes too.
++ */
++struct viocharlpevent {
++ struct HvLpEvent event;
++ u32 reserved;
++ u16 version;
++ u16 subtype_result_code;
++ u8 virtual_device;
++ u8 len;
++ u8 data[VIOCHAR_MAX_DATA];
++};
++
++#define VIOCHAR_WINDOW 10
++
++enum viocharsubtype {
++ viocharopen = 0x0001,
++ viocharclose = 0x0002,
++ viochardata = 0x0003,
++ viocharack = 0x0004,
++ viocharconfig = 0x0005
++};
++
++enum viochar_rc {
++ viochar_rc_ebusy = 1
++};
++
+ struct device;
+
+ extern struct device *iSeries_vio_dev;
+diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
+index 34e1f89..2dafa37 100644
+--- a/include/asm-powerpc/kprobes.h
++++ b/include/asm-powerpc/kprobes.h
+@@ -44,6 +44,28 @@ typedef unsigned int kprobe_opcode_t;
+ #define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000)
+ #define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000)
+
++/*
++ * 64bit powerpc uses function descriptors.
++ * Handle cases where:
++ * - User passes a <.symbol> or <module:.symbol>
++ * - User passes a <symbol> or <module:symbol>
++ * - User passes a non-existant symbol, kallsyms_lookup_name
++ * returns 0. Don't deref the NULL pointer in that case
++ */
++#define kprobe_lookup_name(name, addr) \
++{ \
++ addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \
++ if (addr) { \
++ char *colon; \
++ if ((colon = strchr(name, ':')) != NULL) { \
++ colon++; \
++ if (*colon != '\0' && *colon != '.') \
++ addr = *(kprobe_opcode_t **)addr; \
++ } else if (name[0] != '.') \
++ addr = *(kprobe_opcode_t **)addr; \
++ } \
++}
++
+ #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
+
+ #define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
+diff --git a/include/asm-powerpc/lppaca.h b/include/asm-powerpc/lppaca.h
+index 4dc514a..821ea0c 100644
+--- a/include/asm-powerpc/lppaca.h
++++ b/include/asm-powerpc/lppaca.h
+@@ -27,7 +27,9 @@
+ //
+ //
+ //----------------------------------------------------------------------------
++#include <linux/cache.h>
+ #include <asm/types.h>
++#include <asm/mmu.h>
+
+ /* The Hypervisor barfs if the lppaca crosses a page boundary. A 1k
+ * alignment is sufficient to prevent this */
+@@ -114,7 +116,7 @@ struct lppaca {
+
+
+ //=============================================================================
+-// CACHE_LINE_3 0x0100 - 0x007F: This line is shared with other processors
++// CACHE_LINE_3 0x0100 - 0x017F: This line is shared with other processors
+ //=============================================================================
+ // This is the yield_count. An "odd" value (low bit on) means that
+ // the processor is yielded (either because of an OS yield or a PLIC
+@@ -126,12 +128,29 @@ struct lppaca {
+ u8 reserved6[124]; // Reserved x04-x7F
+
+ //=============================================================================
+-// CACHE_LINE_4-5 0x0100 - 0x01FF Contains PMC interrupt data
++// CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
+ //=============================================================================
+ u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF
+ } __attribute__((__aligned__(0x400)));
+
+ extern struct lppaca lppaca[];
+
++/*
++ * SLB shadow buffer structure as defined in the PAPR. The save_area
++ * contains adjacent ESID and VSID pairs for each shadowed SLB. The
++ * ESID is stored in the lower 64bits, then the VSID.
++ */
++struct slb_shadow {
++ u32 persistent; // Number of persistent SLBs x00-x03
++ u32 buffer_length; // Total shadow buffer length x04-x07
++ u64 reserved; // Alignment x08-x0f
++ struct {
++ u64 esid;
++ u64 vsid;
++ } save_area[SLB_NUM_BOLTED]; // x10-x40
++} ____cacheline_aligned;
++
++extern struct slb_shadow slb_shadow[];
++
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_POWERPC_LPPACA_H */
+diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
+index c17c137..dac90dc 100644
+--- a/include/asm-powerpc/machdep.h
++++ b/include/asm-powerpc/machdep.h
+@@ -97,7 +97,7 @@ struct machdep_calls {
+ void (*show_percpuinfo)(struct seq_file *m, int i);
+
+ void (*init_IRQ)(void);
+- unsigned int (*get_irq)(struct pt_regs *);
++ unsigned int (*get_irq)(void);
+ #ifdef CONFIG_KEXEC
+ void (*kexec_cpu_down)(int crash_shutdown, int secondary);
+ #endif
+diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/mpc85xx.h
+new file mode 100644
+index 0000000..ccdb8a2
+--- /dev/null
++++ b/include/asm-powerpc/mpc85xx.h
+@@ -0,0 +1,53 @@
++/*
++ * include/asm-powerpc/mpc85xx.h
++ *
++ * MPC85xx definitions
++ *
++ * Maintainer: Kumar Gala <galak at kernel.crashing.org>
++ *
++ * 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_MPC85xx_H__
++#define __ASM_MPC85xx_H__
++
++#include <asm/mmu.h>
++
++#ifdef CONFIG_85xx
++
++#if defined(CONFIG_MPC8540_ADS) || defined(CONFIG_MPC8560_ADS)
++#include <platforms/85xx/mpc85xx_ads.h>
++#endif
++#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
++#include <platforms/85xx/mpc8555_cds.h>
++#endif
++#ifdef CONFIG_MPC85xx_CDS
++#include <platforms/85xx/mpc85xx_cds.h>
++#endif
++
++#define _IO_BASE isa_io_base
++#define _ISA_MEM_BASE isa_mem_base
++#ifdef CONFIG_PCI
++#define PCI_DRAM_OFFSET pci_dram_offset
++#else
++#define PCI_DRAM_OFFSET 0
++#endif
++
++/* Let modules/drivers get at CCSRBAR */
++extern phys_addr_t get_ccsrbar(void);
++
++#ifdef MODULE
++#define CCSRBAR get_ccsrbar()
++#else
++#define CCSRBAR BOARD_CCSRBAR
++#endif
++
++#endif /* CONFIG_85xx */
++#endif /* __ASM_MPC85xx_H__ */
++#endif /* __KERNEL__ */
+diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
+index a9f9604..ef0a545 100644
+--- a/include/asm-powerpc/mpic.h
++++ b/include/asm-powerpc/mpic.h
+@@ -409,9 +409,9 @@ extern void mpic_send_ipi(unsigned int i
+ void smp_mpic_message_pass(int target, int msg);
+
+ /* Fetch interrupt from a given mpic */
+-extern unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs);
++extern unsigned int mpic_get_one_irq(struct mpic *mpic);
+ /* This one gets to the primary mpic */
+-extern unsigned int mpic_get_irq(struct pt_regs *regs);
++extern unsigned int mpic_get_irq(void);
+
+ /* Set the EPIC clock ratio */
+ void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio);
+diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
+index 5b33994..07a10e5 100644
+--- a/include/asm-powerpc/oprofile_impl.h
++++ b/include/asm-powerpc/oprofile_impl.h
+@@ -42,7 +42,7 @@ struct op_powerpc_model {
+ void (*reg_setup) (struct op_counter_config *,
+ struct op_system_config *,
+ int num_counters);
+- void (*cpu_setup) (void *);
++ void (*cpu_setup) (struct op_counter_config *);
+ void (*start) (struct op_counter_config *);
+ void (*stop) (void);
+ void (*handle_interrupt) (struct pt_regs *,
+@@ -121,7 +121,90 @@ static inline void ctr_write(unsigned in
+ break;
+ }
+ }
+-#endif /* !CONFIG_FSL_BOOKE */
++#else /* CONFIG_FSL_BOOKE */
++static inline u32 get_pmlca(int ctr)
++{
++ u32 pmlca;
++
++ switch (ctr) {
++ case 0:
++ pmlca = mfpmr(PMRN_PMLCA0);
++ break;
++ case 1:
++ pmlca = mfpmr(PMRN_PMLCA1);
++ break;
++ case 2:
++ pmlca = mfpmr(PMRN_PMLCA2);
++ break;
++ case 3:
++ pmlca = mfpmr(PMRN_PMLCA3);
++ break;
++ default:
++ panic("Bad ctr number\n");
++ }
++
++ return pmlca;
++}
++
++static inline void set_pmlca(int ctr, u32 pmlca)
++{
++ switch (ctr) {
++ case 0:
++ mtpmr(PMRN_PMLCA0, pmlca);
++ break;
++ case 1:
++ mtpmr(PMRN_PMLCA1, pmlca);
++ break;
++ case 2:
++ mtpmr(PMRN_PMLCA2, pmlca);
++ break;
++ case 3:
++ mtpmr(PMRN_PMLCA3, pmlca);
++ break;
++ default:
++ panic("Bad ctr number\n");
++ }
++}
++
++static inline unsigned int ctr_read(unsigned int i)
++{
++ switch(i) {
++ case 0:
++ return mfpmr(PMRN_PMC0);
++ case 1:
++ return mfpmr(PMRN_PMC1);
++ case 2:
++ return mfpmr(PMRN_PMC2);
++ case 3:
++ return mfpmr(PMRN_PMC3);
++ default:
++ return 0;
++ }
++}
++
++static inline void ctr_write(unsigned int i, unsigned int val)
++{
++ switch(i) {
++ case 0:
++ mtpmr(PMRN_PMC0, val);
++ break;
++ case 1:
++ mtpmr(PMRN_PMC1, val);
++ break;
++ case 2:
++ mtpmr(PMRN_PMC2, val);
++ break;
++ case 3:
++ mtpmr(PMRN_PMC3, val);
++ break;
++ default:
++ break;
++ }
++}
++
++
++#endif /* CONFIG_FSL_BOOKE */
++
+
+ extern void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
+index 3d5d590..0a4e5c9 100644
+--- a/include/asm-powerpc/paca.h
++++ b/include/asm-powerpc/paca.h
+@@ -23,6 +23,7 @@
+ register struct paca_struct *local_paca asm("r13");
+ #define get_paca() local_paca
+ #define get_lppaca() (get_paca()->lppaca_ptr)
++#define get_slb_shadow() (get_paca()->slb_shadow_ptr)
+
+ struct task_struct;
+
+@@ -99,6 +100,8 @@ struct paca_struct {
+ u64 user_time; /* accumulated usermode TB ticks */
+ u64 system_time; /* accumulated system TB ticks */
+ u64 startpurr; /* PURR/TB value snapshot */
++
++ struct slb_shadow *slb_shadow_ptr;
+ };
+
+ extern struct paca_struct paca[];
+diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
+index fb597b3..b4d38b0 100644
+--- a/include/asm-powerpc/page.h
++++ b/include/asm-powerpc/page.h
+@@ -55,12 +55,6 @@
+ #define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START)
+ #define KERNELBASE (PAGE_OFFSET + PHYSICAL_START)
+
+-#ifdef CONFIG_DISCONTIGMEM
+-#define page_to_pfn(page) discontigmem_page_to_pfn(page)
+-#define pfn_to_page(pfn) discontigmem_pfn_to_page(pfn)
+-#define pfn_valid(pfn) discontigmem_pfn_valid(pfn)
+-#endif
+-
+ #ifdef CONFIG_FLATMEM
+ #define pfn_valid(pfn) ((pfn) < max_mapnr)
+ #endif
+diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
+index 4f55573..86ee46b 100644
+--- a/include/asm-powerpc/pci-bridge.h
++++ b/include/asm-powerpc/pci-bridge.h
+@@ -6,7 +6,6 @@
+ #include <asm-ppc/pci-bridge.h>
+ #else
+
+-#include <linux/config.h>
+ #include <linux/pci.h>
+ #include <linux/list.h>
+
+diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h
+index e703615..345d9b0 100644
+--- a/include/asm-powerpc/pgtable-4k.h
++++ b/include/asm-powerpc/pgtable-4k.h
+@@ -88,10 +88,11 @@
+ #define pgd_bad(pgd) (pgd_val(pgd) == 0)
+ #define pgd_present(pgd) (pgd_val(pgd) != 0)
+ #define pgd_clear(pgdp) (pgd_val(*(pgdp)) = 0)
+-#define pgd_page(pgd) (pgd_val(pgd) & ~PGD_MASKED_BITS)
++#define pgd_page_vaddr(pgd) (pgd_val(pgd) & ~PGD_MASKED_BITS)
++#define pgd_page(pgd) virt_to_page(pgd_page_vaddr(pgd))
+
+ #define pud_offset(pgdp, addr) \
+- (((pud_t *) pgd_page(*(pgdp))) + \
++ (((pud_t *) pgd_page_vaddr(*(pgdp))) + \
+ (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))
+
+ #define pud_ERROR(e) \
+diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
+index 8dbf5ad..10f5274 100644
+--- a/include/asm-powerpc/pgtable.h
++++ b/include/asm-powerpc/pgtable.h
+@@ -196,8 +196,8 @@ static inline pte_t pfn_pte(unsigned lon
+ || (pmd_val(pmd) & PMD_BAD_BITS))
+ #define pmd_present(pmd) (pmd_val(pmd) != 0)
+ #define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
+-#define pmd_page_kernel(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
+-#define pmd_page(pmd) virt_to_page(pmd_page_kernel(pmd))
++#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
++#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd))
+
+ #define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
+ #define pud_none(pud) (!pud_val(pud))
+@@ -205,7 +205,8 @@ static inline pte_t pfn_pte(unsigned lon
+ || (pud_val(pud) & PUD_BAD_BITS))
+ #define pud_present(pud) (pud_val(pud) != 0)
+ #define pud_clear(pudp) (pud_val(*(pudp)) = 0)
+-#define pud_page(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
++#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
++#define pud_page(pud) virt_to_page(pud_page_vaddr(pud))
+
+ #define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
+
+@@ -219,10 +220,10 @@ static inline pte_t pfn_pte(unsigned lon
+ #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+
+ #define pmd_offset(pudp,addr) \
+- (((pmd_t *) pud_page(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
++ (((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+
+ #define pte_offset_kernel(dir,addr) \
+- (((pte_t *) pmd_page_kernel(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
++ (((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+
+ #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
+ #define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
+diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
+index 07d6a42..8588be6 100644
+--- a/include/asm-powerpc/pmc.h
++++ b/include/asm-powerpc/pmc.h
+@@ -32,18 +32,5 @@ void release_pmc_hardware(void);
+ void power4_enable_pmcs(void);
+ #endif
+
+-#ifdef CONFIG_FSL_BOOKE
+-void init_pmc_stop(int ctr);
+-void set_pmc_event(int ctr, int event);
+-void set_pmc_user_kernel(int ctr, int user, int kernel);
+-void set_pmc_marked(int ctr, int mark0, int mark1);
+-void pmc_start_ctr(int ctr, int enable);
+-void pmc_start_ctrs(int enable);
+-void pmc_stop_ctrs(void);
+-void dump_pmcs(void);
+-
+-extern struct op_powerpc_model op_model_fsl_booke;
+-#endif
+-
+ #endif /* __KERNEL__ */
+ #endif /* _POWERPC_PMC_H */
+diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
+index cf79bc7..1115756 100644
+--- a/include/asm-powerpc/ppc-pci.h
++++ b/include/asm-powerpc/ppc-pci.h
+@@ -69,6 +69,17 @@ struct pci_dev *pci_get_device_by_addr(u
+ void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
+
+ /**
++ * rtas_pci_enableo - enable IO transfers for this slot
++ * @pdn: pci device node
++ * @function: either EEH_THAW_MMIO or EEH_THAW_DMA
++ *
++ * Enable I/O transfers to this slot
++ */
++#define EEH_THAW_MMIO 2
++#define EEH_THAW_DMA 3
++int rtas_pci_enable(struct pci_dn *pdn, int function);
++
++/**
+ * rtas_set_slot_reset -- unfreeze a frozen slot
+ *
+ * Clear the EEH-frozen condition on a slot. This routine
+diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h
+index a940cfe..fa083d8 100644
+--- a/include/asm-powerpc/ppc_asm.h
++++ b/include/asm-powerpc/ppc_asm.h
+@@ -30,9 +30,9 @@ BEGIN_FTR_SECTION; \
+ mfspr ra,SPRN_PURR; /* get processor util. reg */ \
+ END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
+ BEGIN_FTR_SECTION; \
+- mftb ra; /* or get TB if no PURR */ \
++ MFTB(ra); /* or get TB if no PURR */ \
+ END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
+- ld rb,PACA_STARTPURR(r13); \
++ ld rb,PACA_STARTPURR(r13); \
+ std ra,PACA_STARTPURR(r13); \
+ subf rb,rb,ra; /* subtract start value */ \
+ ld ra,PACA_USER_TIME(r13); \
+@@ -45,9 +45,9 @@ BEGIN_FTR_SECTION; \
+ mfspr ra,SPRN_PURR; /* get processor util. reg */ \
+ END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
+ BEGIN_FTR_SECTION; \
+- mftb ra; /* or get TB if no PURR */ \
++ MFTB(ra); /* or get TB if no PURR */ \
+ END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
+- ld rb,PACA_STARTPURR(r13); \
++ ld rb,PACA_STARTPURR(r13); \
+ std ra,PACA_STARTPURR(r13); \
+ subf rb,rb,ra; /* subtract start value */ \
+ ld ra,PACA_SYSTEM_TIME(r13); \
+@@ -274,6 +274,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
+ #define ISYNC_601
+ #endif
+
++#ifdef CONFIG_PPC_CELL
++#define MFTB(dest) \
++90: mftb dest; \
++BEGIN_FTR_SECTION_NESTED(96); \
++ cmpwi dest,0; \
++ beq- 90b; \
++END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
++#else
++#define MFTB(dest) mftb dest
++#endif
+
+ #ifndef CONFIG_SMP
+ #define TLBSYNC
+diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
+index 22e54a2..6cb6fb1 100644
+--- a/include/asm-powerpc/processor.h
++++ b/include/asm-powerpc/processor.h
+@@ -32,6 +32,7 @@
+ #define _CHRP_Motorola 0x04 /* motorola chrp, the cobra */
+ #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */
+ #define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */
++#define _CHRP_briq 0x07 /* TotalImpact's briQ */
+
+ #if defined(__KERNEL__) && defined(CONFIG_PPC32)
+
+diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
+index d0fa1b9..ec11d44 100644
+--- a/include/asm-powerpc/prom.h
++++ b/include/asm-powerpc/prom.h
+@@ -72,8 +72,8 @@ struct property {
+ };
+
+ struct device_node {
+- char *name;
+- char *type;
++ const char *name;
++ const char *type;
+ phandle node;
+ phandle linux_phandle;
+ char *full_name;
+@@ -134,7 +134,7 @@ extern struct device_node *of_find_all_n
+ extern struct device_node *of_get_parent(const struct device_node *node);
+ extern struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev);
+-extern struct property *of_find_property(struct device_node *np,
++extern struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp);
+ extern struct device_node *of_node_get(struct device_node *node);
+@@ -158,10 +158,12 @@ extern void of_detach_node(const struct
+ extern void finish_device_tree(void);
+ extern void unflatten_device_tree(void);
+ extern void early_init_devtree(void *);
+-extern int device_is_compatible(struct device_node *device, const char *);
++extern int device_is_compatible(const struct device_node *device,
++ const char *);
+ extern int machine_is_compatible(const char *compat);
+-extern void *get_property(struct device_node *node, const char *name,
+- int *lenp);
++extern const void *get_property(const struct device_node *node,
++ const char *name,
++ int *lenp);
+ extern void print_properties(struct device_node *node);
+ extern int prom_n_addr_cells(struct device_node* np);
+ extern int prom_n_size_cells(struct device_node* np);
+@@ -197,8 +199,8 @@ extern int release_OF_resource(struct de
+ */
+
+
+-/* Helper to read a big number */
+-static inline u64 of_read_number(u32 *cell, int size)
++/* Helper to read a big number; size is in cells (not bytes) */
++static inline u64 of_read_number(const u32 *cell, int size)
+ {
+ u64 r = 0;
+ while (size--)
+@@ -206,18 +208,28 @@ static inline u64 of_read_number(u32 *ce
+ return r;
+ }
+
++/* Like of_read_number, but we want an unsigned long result */
++#ifdef CONFIG_PPC32
++static inline unsigned long of_read_ulong(const u32 *cell, int size)
++{
++ return cell[size-1];
++}
++#else
++#define of_read_ulong(cell, size) of_read_number(cell, size)
++#endif
++
+ /* Translate an OF address block into a CPU physical address
+ */
+ #define OF_BAD_ADDR ((u64)-1)
+-extern u64 of_translate_address(struct device_node *np, u32 *addr);
++extern u64 of_translate_address(struct device_node *np, const u32 *addr);
+
+ /* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+-extern u32 *of_get_address(struct device_node *dev, int index,
++extern const u32 *of_get_address(struct device_node *dev, int index,
+ u64 *size, unsigned int *flags);
+-extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
++extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+ u64 *size, unsigned int *flags);
+
+ /* Get an address as a resource. Note that if your address is
+@@ -234,7 +246,7 @@ extern int of_pci_address_to_resource(st
+ /* Parse the ibm,dma-window property of an OF node into the busno, phys and
+ * size parameters.
+ */
+-void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
++void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
+ unsigned long *busno, unsigned long *phys, unsigned long *size);
+
+ extern void kdump_move_device_tree(void);
+@@ -259,7 +271,7 @@ struct of_irq {
+ u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
+ };
+
+-/***
++/**
+ * of_irq_map_init - Initialize the irq remapper
+ * @flags: flags defining workarounds to enable
+ *
+@@ -272,7 +284,7 @@ struct of_irq {
+
+ extern void of_irq_map_init(unsigned int flags);
+
+-/***
++/**
+ * of_irq_map_raw - Low level interrupt tree parsing
+ * @parent: the device interrupt parent
+ * @intspec: interrupt specifier ("interrupts" property of the device)
+@@ -289,12 +301,12 @@ extern void of_irq_map_init(unsigned int
+ *
+ */
+
+-extern int of_irq_map_raw(struct device_node *parent, u32 *intspec,
+- u32 ointsize, u32 *addr,
++extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
++ u32 ointsize, const u32 *addr,
+ struct of_irq *out_irq);
+
+
+-/***
++/**
+ * of_irq_map_one - Resolve an interrupt for a device
+ * @device: the device whose interrupt is to be resolved
+ * @index: index of the interrupt to resolve
+@@ -307,7 +319,7 @@ extern int of_irq_map_raw(struct device_
+ extern int of_irq_map_one(struct device_node *device, int index,
+ struct of_irq *out_irq);
+
+-/***
++/**
+ * of_irq_map_pci - Resolve the interrupt for a PCI device
+ * @pdev: the device whose interrupt is to be resolved
+ * @out_irq: structure of_irq filled by this function
+diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
+index dc4cb9c..4ad77a1 100644
+--- a/include/asm-powerpc/ptrace.h
++++ b/include/asm-powerpc/ptrace.h
+@@ -73,6 +73,8 @@ struct pt_regs {
+ #ifndef __ASSEMBLY__
+
+ #define instruction_pointer(regs) ((regs)->nip)
++#define regs_return_value(regs) ((regs)->gpr[3])
++
+ #ifdef CONFIG_SMP
+ extern unsigned long profile_pc(struct pt_regs *regs);
+ #else
+@@ -215,12 +217,10 @@ do { \
+ #define PTRACE_GETVRREGS 18
+ #define PTRACE_SETVRREGS 19
+
+-#ifndef __powerpc64__
+ /* Get/set all the upper 32-bits of the SPE registers, accumulator, and
+ * spefscr, in one go */
+ #define PTRACE_GETEVRREGS 20
+ #define PTRACE_SETEVRREGS 21
+-#endif /* __powerpc64__ */
+
+ /*
+ * Get or set a debug register. The first 16 are DABR registers and the
+@@ -235,7 +235,6 @@ do { \
+ #define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */
+ #define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */
+
+-#ifdef __powerpc64__
+ /* Calls to trace a 64bit program from a 32bit program */
+ #define PPC_PTRACE_PEEKTEXT_3264 0x95
+ #define PPC_PTRACE_PEEKDATA_3264 0x94
+@@ -243,6 +242,5 @@ do { \
+ #define PPC_PTRACE_POKEDATA_3264 0x92
+ #define PPC_PTRACE_PEEKUSR_3264 0x91
+ #define PPC_PTRACE_POKEUSR_3264 0x90
+-#endif /* __powerpc64__ */
+
+ #endif /* _ASM_POWERPC_PTRACE_H */
+diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
+new file mode 100644
+index 0000000..a62168e
+--- /dev/null
++++ b/include/asm-powerpc/qe.h
+@@ -0,0 +1,457 @@
++/*
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
++ *
++ * Description:
++ * QUICC Engine (QE) external definitions and structure.
++ *
++ * 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.
++ */
++#ifndef _ASM_POWERPC_QE_H
++#define _ASM_POWERPC_QE_H
++#ifdef __KERNEL__
++
++#include <asm/immap_qe.h>
++
++#define QE_NUM_OF_SNUM 28
++#define QE_NUM_OF_BRGS 16
++#define QE_NUM_OF_PORTS 1024
++
++/* Memory partitions
++*/
++#define MEM_PART_SYSTEM 0
++#define MEM_PART_SECONDARY 1
++#define MEM_PART_MURAM 2
++
++/* Export QE common operations */
++extern void qe_reset(void);
++extern int par_io_init(struct device_node *np);
++extern int par_io_of_config(struct device_node *np);
++
++/* QE internal API */
++int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input);
++void qe_setbrg(u32 brg, u32 rate);
++int qe_get_snum(void);
++void qe_put_snum(u8 snum);
++u32 qe_muram_alloc(u32 size, u32 align);
++int qe_muram_free(u32 offset);
++u32 qe_muram_alloc_fixed(u32 offset, u32 size);
++void qe_muram_dump(void);
++void *qe_muram_addr(u32 offset);
++
++/* Buffer descriptors */
++struct qe_bd {
++ u16 status;
++ u16 length;
++ u32 buf;
++} __attribute__ ((packed));
++
++#define BD_STATUS_MASK 0xffff0000
++#define BD_LENGTH_MASK 0x0000ffff
++
++/* Alignment */
++#define QE_INTR_TABLE_ALIGN 16 /* ??? */
++#define QE_ALIGNMENT_OF_BD 8
++#define QE_ALIGNMENT_OF_PRAM 64
++
++/* RISC allocation */
++enum qe_risc_allocation {
++ QE_RISC_ALLOCATION_RISC1 = 1, /* RISC 1 */
++ QE_RISC_ALLOCATION_RISC2 = 2, /* RISC 2 */
++ QE_RISC_ALLOCATION_RISC1_AND_RISC2 = 3 /* Dynamically choose
++ RISC 1 or RISC 2 */
++};
++
++/* QE extended filtering Table Lookup Key Size */
++enum qe_fltr_tbl_lookup_key_size {
++ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES
++ = 0x3f, /* LookupKey parsed by the Generate LookupKey
++ CMD is truncated to 8 bytes */
++ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES
++ = 0x5f, /* LookupKey parsed by the Generate LookupKey
++ CMD is truncated to 16 bytes */
++};
++
++/* QE FLTR extended filtering Largest External Table Lookup Key Size */
++enum qe_fltr_largest_external_tbl_lookup_key_size {
++ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE
++ = 0x0,/* not used */
++ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES
++ = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES, /* 8 bytes */
++ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES
++ = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES, /* 16 bytes */
++};
++
++/* structure representing QE parameter RAM */
++struct qe_timer_tables {
++ u16 tm_base; /* QE timer table base adr */
++ u16 tm_ptr; /* QE timer table pointer */
++ u16 r_tmr; /* QE timer mode register */
++ u16 r_tmv; /* QE timer valid register */
++ u32 tm_cmd; /* QE timer cmd register */
++ u32 tm_cnt; /* QE timer internal cnt */
++} __attribute__ ((packed));
++
++#define QE_FLTR_TAD_SIZE 8
++
++/* QE extended filtering Termination Action Descriptor (TAD) */
++struct qe_fltr_tad {
++ u8 serialized[QE_FLTR_TAD_SIZE];
++} __attribute__ ((packed));
++
++/* Communication Direction */
++enum comm_dir {
++ COMM_DIR_NONE = 0,
++ COMM_DIR_RX = 1,
++ COMM_DIR_TX = 2,
++ COMM_DIR_RX_AND_TX = 3
++};
++
++/* Clocks and BRGs */
++enum qe_clock {
++ QE_CLK_NONE = 0,
++ QE_BRG1, /* Baud Rate Generator 1 */
++ QE_BRG2, /* Baud Rate Generator 2 */
++ QE_BRG3, /* Baud Rate Generator 3 */
++ QE_BRG4, /* Baud Rate Generator 4 */
++ QE_BRG5, /* Baud Rate Generator 5 */
++ QE_BRG6, /* Baud Rate Generator 6 */
++ QE_BRG7, /* Baud Rate Generator 7 */
++ QE_BRG8, /* Baud Rate Generator 8 */
++ QE_BRG9, /* Baud Rate Generator 9 */
++ QE_BRG10, /* Baud Rate Generator 10 */
++ QE_BRG11, /* Baud Rate Generator 11 */
++ QE_BRG12, /* Baud Rate Generator 12 */
++ QE_BRG13, /* Baud Rate Generator 13 */
++ QE_BRG14, /* Baud Rate Generator 14 */
++ QE_BRG15, /* Baud Rate Generator 15 */
++ QE_BRG16, /* Baud Rate Generator 16 */
++ QE_CLK1, /* Clock 1 */
++ QE_CLK2, /* Clock 2 */
++ QE_CLK3, /* Clock 3 */
++ QE_CLK4, /* Clock 4 */
++ QE_CLK5, /* Clock 5 */
++ QE_CLK6, /* Clock 6 */
++ QE_CLK7, /* Clock 7 */
++ QE_CLK8, /* Clock 8 */
++ QE_CLK9, /* Clock 9 */
++ QE_CLK10, /* Clock 10 */
++ QE_CLK11, /* Clock 11 */
++ QE_CLK12, /* Clock 12 */
++ QE_CLK13, /* Clock 13 */
++ QE_CLK14, /* Clock 14 */
++ QE_CLK15, /* Clock 15 */
++ QE_CLK16, /* Clock 16 */
++ QE_CLK17, /* Clock 17 */
++ QE_CLK18, /* Clock 18 */
++ QE_CLK19, /* Clock 19 */
++ QE_CLK20, /* Clock 20 */
++ QE_CLK21, /* Clock 21 */
++ QE_CLK22, /* Clock 22 */
++ QE_CLK23, /* Clock 23 */
++ QE_CLK24, /* Clock 24 */
++ QE_CLK_DUMMY,
++};
++
++/* QE CMXUCR Registers.
++ * There are two UCCs represented in each of the four CMXUCR registers.
++ * These values are for the UCC in the LSBs
++ */
++#define QE_CMXUCR_MII_ENET_MNG 0x00007000
++#define QE_CMXUCR_MII_ENET_MNG_SHIFT 12
++#define QE_CMXUCR_GRANT 0x00008000
++#define QE_CMXUCR_TSA 0x00004000
++#define QE_CMXUCR_BKPT 0x00000100
++#define QE_CMXUCR_TX_CLK_SRC_MASK 0x0000000F
++
++/* QE CMXGCR Registers.
++*/
++#define QE_CMXGCR_MII_ENET_MNG 0x00007000
++#define QE_CMXGCR_MII_ENET_MNG_SHIFT 12
++#define QE_CMXGCR_USBCS 0x0000000f
++
++/* QE CECR Commands.
++*/
++#define QE_CR_FLG 0x00010000
++#define QE_RESET 0x80000000
++#define QE_INIT_TX_RX 0x00000000
++#define QE_INIT_RX 0x00000001
++#define QE_INIT_TX 0x00000002
++#define QE_ENTER_HUNT_MODE 0x00000003
++#define QE_STOP_TX 0x00000004
++#define QE_GRACEFUL_STOP_TX 0x00000005
++#define QE_RESTART_TX 0x00000006
++#define QE_CLOSE_RX_BD 0x00000007
++#define QE_SWITCH_COMMAND 0x00000007
++#define QE_SET_GROUP_ADDRESS 0x00000008
++#define QE_START_IDMA 0x00000009
++#define QE_MCC_STOP_RX 0x00000009
++#define QE_ATM_TRANSMIT 0x0000000a
++#define QE_HPAC_CLEAR_ALL 0x0000000b
++#define QE_GRACEFUL_STOP_RX 0x0000001a
++#define QE_RESTART_RX 0x0000001b
++#define QE_HPAC_SET_PRIORITY 0x0000010b
++#define QE_HPAC_STOP_TX 0x0000020b
++#define QE_HPAC_STOP_RX 0x0000030b
++#define QE_HPAC_GRACEFUL_STOP_TX 0x0000040b
++#define QE_HPAC_GRACEFUL_STOP_RX 0x0000050b
++#define QE_HPAC_START_TX 0x0000060b
++#define QE_HPAC_START_RX 0x0000070b
++#define QE_USB_STOP_TX 0x0000000a
++#define QE_USB_RESTART_TX 0x0000000b
++#define QE_QMC_STOP_TX 0x0000000c
++#define QE_QMC_STOP_RX 0x0000000d
++#define QE_SS7_SU_FIL_RESET 0x0000000e
++/* jonathbr added from here down for 83xx */
++#define QE_RESET_BCS 0x0000000a
++#define QE_MCC_INIT_TX_RX_16 0x00000003
++#define QE_MCC_STOP_TX 0x00000004
++#define QE_MCC_INIT_TX_1 0x00000005
++#define QE_MCC_INIT_RX_1 0x00000006
++#define QE_MCC_RESET 0x00000007
++#define QE_SET_TIMER 0x00000008
++#define QE_RANDOM_NUMBER 0x0000000c
++#define QE_ATM_MULTI_THREAD_INIT 0x00000011
++#define QE_ASSIGN_PAGE 0x00000012
++#define QE_ADD_REMOVE_HASH_ENTRY 0x00000013
++#define QE_START_FLOW_CONTROL 0x00000014
++#define QE_STOP_FLOW_CONTROL 0x00000015
++#define QE_ASSIGN_PAGE_TO_DEVICE 0x00000016
++
++#define QE_ASSIGN_RISC 0x00000010
++#define QE_CR_MCN_NORMAL_SHIFT 6
++#define QE_CR_MCN_USB_SHIFT 4
++#define QE_CR_MCN_RISC_ASSIGN_SHIFT 8
++#define QE_CR_SNUM_SHIFT 17
++
++/* QE CECR Sub Block - sub block of QE command.
++*/
++#define QE_CR_SUBBLOCK_INVALID 0x00000000
++#define QE_CR_SUBBLOCK_USB 0x03200000
++#define QE_CR_SUBBLOCK_UCCFAST1 0x02000000
++#define QE_CR_SUBBLOCK_UCCFAST2 0x02200000
++#define QE_CR_SUBBLOCK_UCCFAST3 0x02400000
++#define QE_CR_SUBBLOCK_UCCFAST4 0x02600000
++#define QE_CR_SUBBLOCK_UCCFAST5 0x02800000
++#define QE_CR_SUBBLOCK_UCCFAST6 0x02a00000
++#define QE_CR_SUBBLOCK_UCCFAST7 0x02c00000
++#define QE_CR_SUBBLOCK_UCCFAST8 0x02e00000
++#define QE_CR_SUBBLOCK_UCCSLOW1 0x00000000
++#define QE_CR_SUBBLOCK_UCCSLOW2 0x00200000
++#define QE_CR_SUBBLOCK_UCCSLOW3 0x00400000
++#define QE_CR_SUBBLOCK_UCCSLOW4 0x00600000
++#define QE_CR_SUBBLOCK_UCCSLOW5 0x00800000
++#define QE_CR_SUBBLOCK_UCCSLOW6 0x00a00000
++#define QE_CR_SUBBLOCK_UCCSLOW7 0x00c00000
++#define QE_CR_SUBBLOCK_UCCSLOW8 0x00e00000
++#define QE_CR_SUBBLOCK_MCC1 0x03800000
++#define QE_CR_SUBBLOCK_MCC2 0x03a00000
++#define QE_CR_SUBBLOCK_MCC3 0x03000000
++#define QE_CR_SUBBLOCK_IDMA1 0x02800000
++#define QE_CR_SUBBLOCK_IDMA2 0x02a00000
++#define QE_CR_SUBBLOCK_IDMA3 0x02c00000
++#define QE_CR_SUBBLOCK_IDMA4 0x02e00000
++#define QE_CR_SUBBLOCK_HPAC 0x01e00000
++#define QE_CR_SUBBLOCK_SPI1 0x01400000
++#define QE_CR_SUBBLOCK_SPI2 0x01600000
++#define QE_CR_SUBBLOCK_RAND 0x01c00000
++#define QE_CR_SUBBLOCK_TIMER 0x01e00000
++#define QE_CR_SUBBLOCK_GENERAL 0x03c00000
++
++/* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command */
++#define QE_CR_PROTOCOL_UNSPECIFIED 0x00 /* For all other protocols */
++#define QE_CR_PROTOCOL_HDLC_TRANSPARENT 0x00
++#define QE_CR_PROTOCOL_ATM_POS 0x0A
++#define QE_CR_PROTOCOL_ETHERNET 0x0C
++#define QE_CR_PROTOCOL_L2_SWITCH 0x0D
++
++/* BMR byte order */
++#define QE_BMR_BYTE_ORDER_BO_PPC 0x08 /* powerpc little endian */
++#define QE_BMR_BYTE_ORDER_BO_MOT 0x10 /* motorola big endian */
++#define QE_BMR_BYTE_ORDER_BO_MAX 0x18
++
++/* BRG configuration register */
++#define QE_BRGC_ENABLE 0x00010000
++#define QE_BRGC_DIVISOR_SHIFT 1
++#define QE_BRGC_DIVISOR_MAX 0xFFF
++#define QE_BRGC_DIV16 1
++
++/* QE Timers registers */
++#define QE_GTCFR1_PCAS 0x80
++#define QE_GTCFR1_STP2 0x20
++#define QE_GTCFR1_RST2 0x10
++#define QE_GTCFR1_GM2 0x08
++#define QE_GTCFR1_GM1 0x04
++#define QE_GTCFR1_STP1 0x02
++#define QE_GTCFR1_RST1 0x01
++
++/* SDMA registers */
++#define QE_SDSR_BER1 0x02000000
++#define QE_SDSR_BER2 0x01000000
++
++#define QE_SDMR_GLB_1_MSK 0x80000000
++#define QE_SDMR_ADR_SEL 0x20000000
++#define QE_SDMR_BER1_MSK 0x02000000
++#define QE_SDMR_BER2_MSK 0x01000000
++#define QE_SDMR_EB1_MSK 0x00800000
++#define QE_SDMR_ER1_MSK 0x00080000
++#define QE_SDMR_ER2_MSK 0x00040000
++#define QE_SDMR_CEN_MASK 0x0000E000
++#define QE_SDMR_SBER_1 0x00000200
++#define QE_SDMR_SBER_2 0x00000200
++#define QE_SDMR_EB1_PR_MASK 0x000000C0
++#define QE_SDMR_ER1_PR 0x00000008
++
++#define QE_SDMR_CEN_SHIFT 13
++#define QE_SDMR_EB1_PR_SHIFT 6
++
++#define QE_SDTM_MSNUM_SHIFT 24
++
++#define QE_SDEBCR_BA_MASK 0x01FFFFFF
++
++/* UPC */
++#define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */
++#define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */
++#define UPGCR_RMS 0x20000000 /* Receive master/slave mode */
++#define UPGCR_ADDR 0x10000000 /* Master MPHY Addr multiplexing */
++#define UPGCR_DIAG 0x01000000 /* Diagnostic mode */
++
++/* UCC */
++#define UCC_GUEMR_MODE_MASK_RX 0x02
++#define UCC_GUEMR_MODE_MASK_TX 0x01
++#define UCC_GUEMR_MODE_FAST_RX 0x02
++#define UCC_GUEMR_MODE_FAST_TX 0x01
++#define UCC_GUEMR_MODE_SLOW_RX 0x00
++#define UCC_GUEMR_MODE_SLOW_TX 0x00
++#define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 in the guemr is reserved but
++ must be set 1 */
++
++/* structure representing UCC SLOW parameter RAM */
++struct ucc_slow_pram {
++ u16 rbase; /* RX BD base address */
++ u16 tbase; /* TX BD base address */
++ u8 rfcr; /* Rx function code */
++ u8 tfcr; /* Tx function code */
++ u16 mrblr; /* Rx buffer length */
++ u32 rstate; /* Rx internal state */
++ u32 rptr; /* Rx internal data pointer */
++ u16 rbptr; /* rb BD Pointer */
++ u16 rcount; /* Rx internal byte count */
++ u32 rtemp; /* Rx temp */
++ u32 tstate; /* Tx internal state */
++ u32 tptr; /* Tx internal data pointer */
++ u16 tbptr; /* Tx BD pointer */
++ u16 tcount; /* Tx byte count */
++ u32 ttemp; /* Tx temp */
++ u32 rcrc; /* temp receive CRC */
++ u32 tcrc; /* temp transmit CRC */
++} __attribute__ ((packed));
++
++/* General UCC SLOW Mode Register (GUMRH & GUMRL) */
++#define UCC_SLOW_GUMR_H_CRC16 0x00004000
++#define UCC_SLOW_GUMR_H_CRC16CCITT 0x00000000
++#define UCC_SLOW_GUMR_H_CRC32CCITT 0x00008000
++#define UCC_SLOW_GUMR_H_REVD 0x00002000
++#define UCC_SLOW_GUMR_H_TRX 0x00001000
++#define UCC_SLOW_GUMR_H_TTX 0x00000800
++#define UCC_SLOW_GUMR_H_CDP 0x00000400
++#define UCC_SLOW_GUMR_H_CTSP 0x00000200
++#define UCC_SLOW_GUMR_H_CDS 0x00000100
++#define UCC_SLOW_GUMR_H_CTSS 0x00000080
++#define UCC_SLOW_GUMR_H_TFL 0x00000040
++#define UCC_SLOW_GUMR_H_RFW 0x00000020
++#define UCC_SLOW_GUMR_H_TXSY 0x00000010
++#define UCC_SLOW_GUMR_H_4SYNC 0x00000004
++#define UCC_SLOW_GUMR_H_8SYNC 0x00000008
++#define UCC_SLOW_GUMR_H_16SYNC 0x0000000c
++#define UCC_SLOW_GUMR_H_RTSM 0x00000002
++#define UCC_SLOW_GUMR_H_RSYN 0x00000001
++
++#define UCC_SLOW_GUMR_L_TCI 0x10000000
++#define UCC_SLOW_GUMR_L_RINV 0x02000000
++#define UCC_SLOW_GUMR_L_TINV 0x01000000
++#define UCC_SLOW_GUMR_L_TEND 0x00020000
++#define UCC_SLOW_GUMR_L_ENR 0x00000020
++#define UCC_SLOW_GUMR_L_ENT 0x00000010
++
++/* General UCC FAST Mode Register */
++#define UCC_FAST_GUMR_TCI 0x20000000
++#define UCC_FAST_GUMR_TRX 0x10000000
++#define UCC_FAST_GUMR_TTX 0x08000000
++#define UCC_FAST_GUMR_CDP 0x04000000
++#define UCC_FAST_GUMR_CTSP 0x02000000
++#define UCC_FAST_GUMR_CDS 0x01000000
++#define UCC_FAST_GUMR_CTSS 0x00800000
++#define UCC_FAST_GUMR_TXSY 0x00020000
++#define UCC_FAST_GUMR_RSYN 0x00010000
++#define UCC_FAST_GUMR_RTSM 0x00002000
++#define UCC_FAST_GUMR_REVD 0x00000400
++#define UCC_FAST_GUMR_ENR 0x00000020
++#define UCC_FAST_GUMR_ENT 0x00000010
++
++/* Slow UCC Event Register (UCCE) */
++#define UCC_SLOW_UCCE_GLR 0x1000
++#define UCC_SLOW_UCCE_GLT 0x0800
++#define UCC_SLOW_UCCE_DCC 0x0400
++#define UCC_SLOW_UCCE_FLG 0x0200
++#define UCC_SLOW_UCCE_AB 0x0200
++#define UCC_SLOW_UCCE_IDLE 0x0100
++#define UCC_SLOW_UCCE_GRA 0x0080
++#define UCC_SLOW_UCCE_TXE 0x0010
++#define UCC_SLOW_UCCE_RXF 0x0008
++#define UCC_SLOW_UCCE_CCR 0x0008
++#define UCC_SLOW_UCCE_RCH 0x0008
++#define UCC_SLOW_UCCE_BSY 0x0004
++#define UCC_SLOW_UCCE_TXB 0x0002
++#define UCC_SLOW_UCCE_TX 0x0002
++#define UCC_SLOW_UCCE_RX 0x0001
++#define UCC_SLOW_UCCE_GOV 0x0001
++#define UCC_SLOW_UCCE_GUN 0x0002
++#define UCC_SLOW_UCCE_GINT 0x0004
++#define UCC_SLOW_UCCE_IQOV 0x0008
++
++#define UCC_SLOW_UCCE_HDLC_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
++ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF | \
++ UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
++#define UCC_SLOW_UCCE_ENET_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
++ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF)
++#define UCC_SLOW_UCCE_TRANS_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
++ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \
++ UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
++#define UCC_SLOW_UCCE_UART_SET (UCC_SLOW_UCCE_BSY | UCC_SLOW_UCCE_GRA | \
++ UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \
++ UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
++#define UCC_SLOW_UCCE_QMC_SET (UCC_SLOW_UCCE_IQOV | UCC_SLOW_UCCE_GINT | \
++ UCC_SLOW_UCCE_GUN | UCC_SLOW_UCCE_GOV)
++
++#define UCC_SLOW_UCCE_OTHER (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
++ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | \
++ UCC_SLOW_UCCE_GLR)
++
++#define UCC_SLOW_INTR_TX UCC_SLOW_UCCE_TXB
++#define UCC_SLOW_INTR_RX (UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX)
++#define UCC_SLOW_INTR (UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX)
++
++/* UCC Transmit On Demand Register (UTODR) */
++#define UCC_SLOW_TOD 0x8000
++#define UCC_FAST_TOD 0x8000
++
++/* Function code masks */
++#define FC_GBL 0x20
++#define FC_DTB_LCL 0x02
++#define UCC_FAST_FUNCTION_CODE_GBL 0x20
++#define UCC_FAST_FUNCTION_CODE_DTB_LCL 0x02
++#define UCC_FAST_FUNCTION_CODE_BDB_LCL 0x01
++
++static inline long IS_MURAM_ERR(const u32 offset)
++{
++ return offset > (u32) - 1000L;
++}
++
++#endif /* __KERNEL__ */
++#endif /* _ASM_POWERPC_QE_H */
+diff --git a/include/asm-powerpc/qe_ic.h b/include/asm-powerpc/qe_ic.h
+new file mode 100644
+index 0000000..e386fb7
+--- /dev/null
++++ b/include/asm-powerpc/qe_ic.h
+@@ -0,0 +1,64 @@
++/*
++ * include/asm-powerpc/qe_ic.h
++ *
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
++ *
++ * Description:
++ * QE IC external definitions and structure.
++ *
++ * 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.
++ */
++#ifndef _ASM_POWERPC_QE_IC_H
++#define _ASM_POWERPC_QE_IC_H
++
++#include <linux/irq.h>
++
++#define NUM_OF_QE_IC_GROUPS 6
++
++/* Flags when we init the QE IC */
++#define QE_IC_SPREADMODE_GRP_W 0x00000001
++#define QE_IC_SPREADMODE_GRP_X 0x00000002
++#define QE_IC_SPREADMODE_GRP_Y 0x00000004
++#define QE_IC_SPREADMODE_GRP_Z 0x00000008
++#define QE_IC_SPREADMODE_GRP_RISCA 0x00000010
++#define QE_IC_SPREADMODE_GRP_RISCB 0x00000020
++
++#define QE_IC_LOW_SIGNAL 0x00000100
++#define QE_IC_HIGH_SIGNAL 0x00000200
++
++#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH 0x00001000
++#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH 0x00002000
++#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH 0x00004000
++#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH 0x00008000
++#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH 0x00010000
++#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH 0x00020000
++#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH 0x00040000
++#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH 0x00080000
++#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000
++#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000
++#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000
++#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000
++#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT (12)
++
++/* QE interrupt sources groups */
++enum qe_ic_grp_id {
++ QE_IC_GRP_W = 0, /* QE interrupt controller group W */
++ QE_IC_GRP_X, /* QE interrupt controller group X */
++ QE_IC_GRP_Y, /* QE interrupt controller group Y */
++ QE_IC_GRP_Z, /* QE interrupt controller group Z */
++ QE_IC_GRP_RISCA, /* QE interrupt controller RISC group A */
++ QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */
++};
++
++void qe_ic_init(struct device_node *node, unsigned int flags);
++void qe_ic_set_highest_priority(unsigned int virq, int high);
++int qe_ic_set_priority(unsigned int virq, unsigned int priority);
++int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
++
++#endif /* _ASM_POWERPC_QE_IC_H */
+diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
+index cf73475..6faae7b 100644
+--- a/include/asm-powerpc/reg.h
++++ b/include/asm-powerpc/reg.h
+@@ -503,7 +503,7 @@
+
+ /*
+ * An mtfsf instruction with the L bit set. On CPUs that support this a
+- * full 64bits of FPSCR is restored and on other CPUs it is ignored.
++ * full 64bits of FPSCR is restored and on other CPUs the L bit is ignored.
+ *
+ * Until binutils gets the new form of mtfsf, hardwire the instruction.
+ */
+@@ -591,7 +591,9 @@
+ #define PV_630 0x0040
+ #define PV_630p 0x0041
+ #define PV_970MP 0x0044
++#define PV_970GX 0x0045
+ #define PV_BE 0x0070
++#define PV_PA6T 0x0090
+
+ /*
+ * Number of entries in the SLB. If this ever changes we should handle
+@@ -617,10 +619,35 @@
+ : "=r" (rval)); rval;})
+ #define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
+
++#ifdef __powerpc64__
++#ifdef CONFIG_PPC_CELL
++#define mftb() ({unsigned long rval; \
++ asm volatile( \
++ "90: mftb %0;\n" \
++ "97: cmpwi %0,0;\n" \
++ " beq- 90b;\n" \
++ "99:\n" \
++ ".section __ftr_fixup,\"a\"\n" \
++ ".align 3\n" \
++ "98:\n" \
++ " .llong %1\n" \
++ " .llong %1\n" \
++ " .llong 97b-98b\n" \
++ " .llong 99b-98b\n" \
++ ".previous" \
++ : "=r" (rval) : "i" (CPU_FTR_CELL_TB_BUG)); rval;})
++#else
+ #define mftb() ({unsigned long rval; \
+ asm volatile("mftb %0" : "=r" (rval)); rval;})
++#endif /* !CONFIG_PPC_CELL */
++
++#else /* __powerpc64__ */
++
+ #define mftbl() ({unsigned long rval; \
+ asm volatile("mftbl %0" : "=r" (rval)); rval;})
++#define mftbu() ({unsigned long rval; \
++ asm volatile("mftbu %0" : "=r" (rval)); rval;})
++#endif /* !__powerpc64__ */
+
+ #define mttbl(v) asm volatile("mttbl %0":: "r"(v))
+ #define mttbu(v) asm volatile("mttbu %0":: "r"(v))
+diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
+index 82a27e9..d34f9e1 100644
+--- a/include/asm-powerpc/rtas.h
++++ b/include/asm-powerpc/rtas.h
+@@ -230,5 +230,21 @@ extern unsigned long rtas_rmo_buf;
+
+ #define GLOBAL_INTERRUPT_QUEUE 9005
+
++/**
++ * rtas_config_addr - Format a busno, devfn and reg for RTAS.
++ * @busno: The bus number.
++ * @devfn: The device and function number as encoded by PCI_DEVFN().
++ * @reg: The register number.
++ *
++ * This function encodes the given busno, devfn and register number as
++ * required for RTAS calls that take a "config_addr" parameter.
++ * See PAPR requirement 7.3.4-1 for more info.
++ */
++static inline u32 rtas_config_addr(int busno, int devfn, int reg)
++{
++ return ((reg & 0xf00) << 20) | ((busno & 0xff) << 16) |
++ (devfn << 8) | (reg & 0xff);
++}
++
+ #endif /* __KERNEL__ */
+ #endif /* _POWERPC_RTAS_H */
+diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
+index 068f119..20ea7c7 100644
+--- a/include/asm-powerpc/smp.h
++++ b/include/asm-powerpc/smp.h
+@@ -34,8 +34,7 @@ extern void cpu_die(void);
+ #ifdef CONFIG_SMP
+
+ extern void smp_send_debugger_break(int cpu);
+-struct pt_regs;
+-extern void smp_message_recv(int, struct pt_regs *);
++extern void smp_message_recv(int);
+
+ #ifdef CONFIG_HOTPLUG_CPU
+ extern void fixup_irqs(cpumask_t map);
+diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h
+index 51e65fc..e49f644 100644
+--- a/include/asm-powerpc/smu.h
++++ b/include/asm-powerpc/smu.h
+@@ -517,7 +517,7 @@ struct smu_sdbp_cpupiddata {
+ * This returns the pointer to an SMU "sdb" partition data or NULL
+ * if not found. The data format is described below
+ */
+-extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
++extern const struct smu_sdbp_header *smu_get_sdb_partition(int id,
+ unsigned int *size);
+
+ /* Get "sdb" partition data from an SMU satellite */
+diff --git a/include/asm-powerpc/spinlock.h b/include/asm-powerpc/spinlock.h
+index c31e438..cc4cfce 100644
+--- a/include/asm-powerpc/spinlock.h
++++ b/include/asm-powerpc/spinlock.h
+@@ -285,5 +285,9 @@ static __inline__ void __raw_write_unloc
+ rw->lock = 0;
+ }
+
++#define _raw_spin_relax(lock) __spin_yield(lock)
++#define _raw_read_relax(lock) __rw_yield(lock)
++#define _raw_write_relax(lock) __rw_yield(lock)
++
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
+index c02d105..e73ea00 100644
+--- a/include/asm-powerpc/spu.h
++++ b/include/asm-powerpc/spu.h
+@@ -106,7 +106,7 @@ struct spu_context;
+ struct spu_runqueue;
+
+ struct spu {
+- char *name;
++ const char *name;
+ unsigned long local_store_phys;
+ u8 *local_store;
+ unsigned long problem_phys;
+@@ -138,6 +138,7 @@ struct spu {
+ void (* ibox_callback)(struct spu *spu);
+ void (* stop_callback)(struct spu *spu);
+ void (* mfc_callback)(struct spu *spu);
++ void (* dma_callback)(struct spu *spu, int type);
+
+ char irq_c0[8];
+ char irq_c1[8];
+@@ -147,6 +148,7 @@ struct spu {
+ };
+
+ struct spu *spu_alloc(void);
++struct spu *spu_alloc_node(int node);
+ void spu_free(struct spu *spu);
+ int spu_irq_class_0_bottom(struct spu *spu);
+ int spu_irq_class_1_bottom(struct spu *spu);
+@@ -168,6 +170,22 @@ extern struct spufs_calls {
+ struct module *owner;
+ } spufs_calls;
+
++/* return status from spu_run, same as in libspe */
++#define SPE_EVENT_DMA_ALIGNMENT 0x0008 /*A DMA alignment error */
++#define SPE_EVENT_SPE_ERROR 0x0010 /*An illegal instruction error*/
++#define SPE_EVENT_SPE_DATA_SEGMENT 0x0020 /*A DMA segmentation error */
++#define SPE_EVENT_SPE_DATA_STORAGE 0x0040 /*A DMA storage error */
++#define SPE_EVENT_INVALID_DMA 0x0800 /* Invalid MFC DMA */
++
++/*
++ * Flags for sys_spu_create.
++ */
++#define SPU_CREATE_EVENTS_ENABLED 0x0001
++#define SPU_CREATE_GANG 0x0002
++
++#define SPU_CREATE_FLAG_ALL 0x0003 /* mask of all valid flags */
++
++
+ #ifdef CONFIG_SPU_FS_MODULE
+ int register_spu_syscalls(struct spufs_calls *calls);
+ void unregister_spu_syscalls(struct spufs_calls *calls);
+@@ -183,6 +201,24 @@ static inline void unregister_spu_syscal
+
+
+ /*
++ * Notifier blocks:
++ *
++ * oprofile can get notified when a context switch is performed
++ * on an spe. The notifer function that gets called is passed
++ * a pointer to the SPU structure as well as the object-id that
++ * identifies the binary running on that SPU now.
++ *
++ * For a context save, the object-id that is passed is zero,
++ * identifying that the kernel will run from that moment on.
++ *
++ * For a context restore, the object-id is the value written
++ * to object-id spufs file from user space and the notifer
++ * function can assume that spu->ctx is valid.
++ */
++int spu_switch_event_register(struct notifier_block * n);
++int spu_switch_event_unregister(struct notifier_block * n);
++
++/*
+ * This defines the Local Store, Problem Area and Privlege Area of an SPU.
+ */
+
+diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
+index eac85ce..c6a0318 100644
+--- a/include/asm-powerpc/systbl.h
++++ b/include/asm-powerpc/systbl.h
+@@ -261,7 +261,7 @@ SYSX(sys_ni_syscall, ppc_fadvise64_64, p
+ PPC_SYS_SPU(rtas)
+ OLDSYS(debug_setcontext)
+ SYSCALL(ni_syscall)
+-SYSCALL(ni_syscall)
++COMPAT_SYS(migrate_pages)
+ COMPAT_SYS(mbind)
+ COMPAT_SYS(get_mempolicy)
+ COMPAT_SYS(set_mempolicy)
+diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
+index 4c9f522..f7b1227 100644
+--- a/include/asm-powerpc/system.h
++++ b/include/asm-powerpc/system.h
+@@ -25,8 +25,8 @@
+ *
+ * We have to use the sync instructions for mb(), since lwsync doesn't
+ * order loads with respect to previous stores. Lwsync is fine for
+- * rmb(), though. Note that lwsync is interpreted as sync by
+- * 32-bit and older 64-bit CPUs.
++ * rmb(), though. Note that rmb() actually uses a sync on 32-bit
++ * architectures.
+ *
+ * For wmb(), we use sync since wmb is used in drivers to order
+ * stores to system memory with respect to writes to the device.
+@@ -34,7 +34,7 @@
+ * SMP since it is only used to order updates to system memory.
+ */
+ #define mb() __asm__ __volatile__ ("sync" : : : "memory")
+-#define rmb() __asm__ __volatile__ ("lwsync" : : : "memory")
++#define rmb() __asm__ __volatile__ (__stringify(LWSYNC) : : : "memory")
+ #define wmb() __asm__ __volatile__ ("sync" : : : "memory")
+ #define read_barrier_depends() do { } while(0)
+
+@@ -91,10 +91,6 @@ DEBUGGER_BOILERPLATE(debugger_iabr_match
+ DEBUGGER_BOILERPLATE(debugger_dabr_match)
+ DEBUGGER_BOILERPLATE(debugger_fault_handler)
+
+-#ifdef CONFIG_XMON
+-extern void xmon_init(int enable);
+-#endif
+-
+ #else
+ static inline int debugger(struct pt_regs *regs) { return 0; }
+ static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
+@@ -177,11 +173,6 @@ extern u32 booke_wdt_enabled;
+ extern u32 booke_wdt_period;
+ #endif /* CONFIG_BOOKE_WDT */
+
+-/* EBCDIC -> ASCII conversion for [0-9A-Z] on iSeries */
+-extern unsigned char e2a(unsigned char);
+-extern unsigned char* strne2a(unsigned char *dest,
+- const unsigned char *src, size_t n);
+-
+ struct device_node;
+ extern void note_scsi_host(struct device_node *, void *);
+
+diff --git a/include/asm-powerpc/tce.h b/include/asm-powerpc/tce.h
+index c9483ad..f663634 100644
+--- a/include/asm-powerpc/tce.h
++++ b/include/asm-powerpc/tce.h
+@@ -22,6 +22,8 @@
+ #define _ASM_POWERPC_TCE_H
+ #ifdef __KERNEL__
+
++#include <asm/iommu.h>
++
+ /*
+ * Tces come in two formats, one for the virtual bus and a different
+ * format for PCI
+@@ -33,7 +35,6 @@
+
+ #define TCE_SHIFT 12
+ #define TCE_PAGE_SIZE (1 << TCE_SHIFT)
+-#define TCE_PAGE_FACTOR (PAGE_SHIFT - TCE_SHIFT)
+
+ #define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */
+
+diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
+index 5785ac4..a782850 100644
+--- a/include/asm-powerpc/time.h
++++ b/include/asm-powerpc/time.h
+@@ -39,6 +39,10 @@ extern void generic_calibrate_decr(void)
+ extern void wakeup_decrementer(void);
+ extern void snapshot_timebase(void);
+
++#ifdef CONFIG_RTC_CLASS
++extern int __init rtc_class_hookup(void);
++#endif
++
+ /* Some sane defaults: 125 MHz timebase, 1GHz processor */
+ extern unsigned long ppc_proc_freq;
+ #define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8)
+@@ -78,30 +82,35 @@ struct div_result {
+ #define __USE_RTC() 0
+ #endif
+
+-/* On ppc64 this gets us the whole timebase; on ppc32 just the lower half */
++#ifdef CONFIG_PPC64
++
++/* For compatibility, get_tbl() is defined as get_tb() on ppc64 */
++#define get_tbl get_tb
++
++#else
++
+ static inline unsigned long get_tbl(void)
+ {
+- unsigned long tbl;
+-
+ #if defined(CONFIG_403GCX)
++ unsigned long tbl;
+ asm volatile("mfspr %0, 0x3dd" : "=r" (tbl));
++ return tbl;
+ #else
+- asm volatile("mftb %0" : "=r" (tbl));
++ return mftbl();
+ #endif
+- return tbl;
+ }
+
+ static inline unsigned int get_tbu(void)
+ {
++#ifdef CONFIG_403GCX
+ unsigned int tbu;
+-
+-#if defined(CONFIG_403GCX)
+ asm volatile("mfspr %0, 0x3dc" : "=r" (tbu));
++ return tbu;
+ #else
+- asm volatile("mftbu %0" : "=r" (tbu));
++ return mftbu();
+ #endif
+- return tbu;
+ }
++#endif /* !CONFIG_PPC64 */
+
+ static inline unsigned int get_rtcl(void)
+ {
+@@ -127,7 +136,7 @@ static inline u64 get_tb(void)
+ {
+ return mftb();
+ }
+-#else
++#else /* CONFIG_PPC64 */
+ static inline u64 get_tb(void)
+ {
+ unsigned int tbhi, tblo, tbhi2;
+@@ -140,7 +149,7 @@ static inline u64 get_tb(void)
+
+ return ((u64)tbhi << 32) | tblo;
+ }
+-#endif
++#endif /* !CONFIG_PPC64 */
+
+ static inline void set_tb(unsigned int upper, unsigned int lower)
+ {
+@@ -234,4 +243,4 @@ extern void snapshot_timebases(void);
+ #endif
+
+ #endif /* __KERNEL__ */
+-#endif /* __PPC64_TIME_H */
++#endif /* __POWERPC_TIME_H */
+diff --git a/include/asm-powerpc/timex.h b/include/asm-powerpc/timex.h
+index 3b9a8e7..92dedde 100644
+--- a/include/asm-powerpc/timex.h
++++ b/include/asm-powerpc/timex.h
+@@ -8,6 +8,7 @@
+ */
+
+ #include <asm/cputable.h>
++#include <asm/reg.h>
+
+ #define CLOCK_TICK_RATE 1024000 /* Underlying HZ */
+
+@@ -15,13 +16,11 @@ typedef unsigned long cycles_t;
+
+ static inline cycles_t get_cycles(void)
+ {
+- cycles_t ret;
+-
+ #ifdef __powerpc64__
+-
+- __asm__ __volatile__("mftb %0" : "=r" (ret) : );
+-
++ return mftb();
+ #else
++ cycles_t ret;
++
+ /*
+ * For the "cycle" counter we use the timebase lower half.
+ * Currently only used on SMP.
+@@ -30,18 +29,19 @@ static inline cycles_t get_cycles(void)
+ ret = 0;
+
+ __asm__ __volatile__(
+- "98: mftb %0\n"
++ "97: mftb %0\n"
+ "99:\n"
+ ".section __ftr_fixup,\"a\"\n"
++ ".align 2\n"
++ "98:\n"
+ " .long %1\n"
+ " .long 0\n"
+- " .long 98b\n"
+- " .long 99b\n"
++ " .long 97b-98b\n"
++ " .long 99b-98b\n"
+ ".previous"
+ : "=r" (ret) : "i" (CPU_FTR_601));
+-#endif
+-
+ return ret;
++#endif
+ }
+
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
+index bbc3844..8f7ee16 100644
+--- a/include/asm-powerpc/topology.h
++++ b/include/asm-powerpc/topology.h
+@@ -43,6 +43,7 @@ extern int pcibus_to_node(struct pci_bus
+ #define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 32, \
+diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h
+new file mode 100644
+index 0000000..afe3076
+--- /dev/null
++++ b/include/asm-powerpc/ucc.h
+@@ -0,0 +1,84 @@
++/*
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
++ *
++ * Description:
++ * Internal header file for UCC unit routines.
++ *
++ * 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.
++ */
++#ifndef __UCC_H__
++#define __UCC_H__
++
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++
++#define STATISTICS
++
++#define UCC_MAX_NUM 8
++
++/* Slow or fast type for UCCs.
++*/
++enum ucc_speed_type {
++ UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW
++};
++
++/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR).
++*/
++enum ucc_pram_initial_offset {
++ UCC_PRAM_OFFSET_UCC1 = 0x8400,
++ UCC_PRAM_OFFSET_UCC2 = 0x8500,
++ UCC_PRAM_OFFSET_UCC3 = 0x8600,
++ UCC_PRAM_OFFSET_UCC4 = 0x9000,
++ UCC_PRAM_OFFSET_UCC5 = 0x8000,
++ UCC_PRAM_OFFSET_UCC6 = 0x8100,
++ UCC_PRAM_OFFSET_UCC7 = 0x8200,
++ UCC_PRAM_OFFSET_UCC8 = 0x8300
++};
++
++/* ucc_set_type
++ * Sets UCC to slow or fast mode.
++ *
++ * ucc_num - (In) number of UCC (0-7).
++ * regs - (In) pointer to registers base for the UCC.
++ * speed - (In) slow or fast mode for UCC.
++ */
++int ucc_set_type(int ucc_num, struct ucc_common *regs,
++ enum ucc_speed_type speed);
++
++/* ucc_init_guemr
++ * Init the Guemr register.
++ *
++ * regs - (In) pointer to registers base for the UCC.
++ */
++int ucc_init_guemr(struct ucc_common *regs);
++
++int ucc_set_qe_mux_mii_mng(int ucc_num);
++
++int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode);
++
++int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask);
++
++/* QE MUX clock routing for UCC
++*/
++static inline int ucc_set_qe_mux_grant(int ucc_num, int set)
++{
++ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_GRANT);
++}
++
++static inline int ucc_set_qe_mux_tsa(int ucc_num, int set)
++{
++ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA);
++}
++
++static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set)
++{
++ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT);
++}
++
++#endif /* __UCC_H__ */
+diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
+new file mode 100644
+index 0000000..39d1c90
+--- /dev/null
++++ b/include/asm-powerpc/ucc_fast.h
+@@ -0,0 +1,243 @@
++/*
++ * include/asm-powerpc/ucc_fast.h
++ *
++ * Internal header file for UCC FAST unit routines.
++ *
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.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.
++ */
++#ifndef __UCC_FAST_H__
++#define __UCC_FAST_H__
++
++#include <linux/kernel.h>
++
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++
++#include "ucc.h"
++
++/* Receive BD's status */
++#define R_E 0x80000000 /* buffer empty */
++#define R_W 0x20000000 /* wrap bit */
++#define R_I 0x10000000 /* interrupt on reception */
++#define R_L 0x08000000 /* last */
++#define R_F 0x04000000 /* first */
++
++/* transmit BD's status */
++#define T_R 0x80000000 /* ready bit */
++#define T_W 0x20000000 /* wrap bit */
++#define T_I 0x10000000 /* interrupt on completion */
++#define T_L 0x08000000 /* last */
++
++/* Rx Data buffer must be 4 bytes aligned in most cases */
++#define UCC_FAST_RX_ALIGN 4
++#define UCC_FAST_MRBLR_ALIGNMENT 4
++#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8
++
++/* Sizes */
++#define UCC_FAST_URFS_MIN_VAL 0x88
++#define UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR 8
++
++/* ucc_fast_channel_protocol_mode - UCC FAST mode */
++enum ucc_fast_channel_protocol_mode {
++ UCC_FAST_PROTOCOL_MODE_HDLC = 0x00000000,
++ UCC_FAST_PROTOCOL_MODE_RESERVED01 = 0x00000001,
++ UCC_FAST_PROTOCOL_MODE_RESERVED_QMC = 0x00000002,
++ UCC_FAST_PROTOCOL_MODE_RESERVED02 = 0x00000003,
++ UCC_FAST_PROTOCOL_MODE_RESERVED_UART = 0x00000004,
++ UCC_FAST_PROTOCOL_MODE_RESERVED03 = 0x00000005,
++ UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_1 = 0x00000006,
++ UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_2 = 0x00000007,
++ UCC_FAST_PROTOCOL_MODE_RESERVED_BISYNC = 0x00000008,
++ UCC_FAST_PROTOCOL_MODE_RESERVED04 = 0x00000009,
++ UCC_FAST_PROTOCOL_MODE_ATM = 0x0000000A,
++ UCC_FAST_PROTOCOL_MODE_RESERVED05 = 0x0000000B,
++ UCC_FAST_PROTOCOL_MODE_ETHERNET = 0x0000000C,
++ UCC_FAST_PROTOCOL_MODE_RESERVED06 = 0x0000000D,
++ UCC_FAST_PROTOCOL_MODE_POS = 0x0000000E,
++ UCC_FAST_PROTOCOL_MODE_RESERVED07 = 0x0000000F
++};
++
++/* ucc_fast_transparent_txrx - UCC Fast Transparent TX & RX */
++enum ucc_fast_transparent_txrx {
++ UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL = 0x00000000,
++ UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_TRANSPARENT = 0x18000000
++};
++
++/* UCC fast diagnostic mode */
++enum ucc_fast_diag_mode {
++ UCC_FAST_DIAGNOSTIC_NORMAL = 0x0,
++ UCC_FAST_DIAGNOSTIC_LOCAL_LOOP_BACK = 0x40000000,
++ UCC_FAST_DIAGNOSTIC_AUTO_ECHO = 0x80000000,
++ UCC_FAST_DIAGNOSTIC_LOOP_BACK_AND_ECHO = 0xC0000000
++};
++
++/* UCC fast Sync length (transparent mode only) */
++enum ucc_fast_sync_len {
++ UCC_FAST_SYNC_LEN_NOT_USED = 0x0,
++ UCC_FAST_SYNC_LEN_AUTOMATIC = 0x00004000,
++ UCC_FAST_SYNC_LEN_8_BIT = 0x00008000,
++ UCC_FAST_SYNC_LEN_16_BIT = 0x0000C000
++};
++
++/* UCC fast RTS mode */
++enum ucc_fast_ready_to_send {
++ UCC_FAST_SEND_IDLES_BETWEEN_FRAMES = 0x00000000,
++ UCC_FAST_SEND_FLAGS_BETWEEN_FRAMES = 0x00002000
++};
++
++/* UCC fast receiver decoding mode */
++enum ucc_fast_rx_decoding_method {
++ UCC_FAST_RX_ENCODING_NRZ = 0x00000000,
++ UCC_FAST_RX_ENCODING_NRZI = 0x00000800,
++ UCC_FAST_RX_ENCODING_RESERVED0 = 0x00001000,
++ UCC_FAST_RX_ENCODING_RESERVED1 = 0x00001800
++};
++
++/* UCC fast transmitter encoding mode */
++enum ucc_fast_tx_encoding_method {
++ UCC_FAST_TX_ENCODING_NRZ = 0x00000000,
++ UCC_FAST_TX_ENCODING_NRZI = 0x00000100,
++ UCC_FAST_TX_ENCODING_RESERVED0 = 0x00000200,
++ UCC_FAST_TX_ENCODING_RESERVED1 = 0x00000300
++};
++
++/* UCC fast CRC length */
++enum ucc_fast_transparent_tcrc {
++ UCC_FAST_16_BIT_CRC = 0x00000000,
++ UCC_FAST_CRC_RESERVED0 = 0x00000040,
++ UCC_FAST_32_BIT_CRC = 0x00000080,
++ UCC_FAST_CRC_RESERVED1 = 0x000000C0
++};
++
++/* Fast UCC initialization structure */
++struct ucc_fast_info {
++ int ucc_num;
++ enum qe_clock rx_clock;
++ enum qe_clock tx_clock;
++ u32 regs;
++ int irq;
++ u32 uccm_mask;
++ int bd_mem_part;
++ int brkpt_support;
++ int grant_support;
++ int tsa;
++ int cdp;
++ int cds;
++ int ctsp;
++ int ctss;
++ int tci;
++ int txsy;
++ int rtsm;
++ int revd;
++ int rsyn;
++ u16 max_rx_buf_length;
++ u16 urfs;
++ u16 urfet;
++ u16 urfset;
++ u16 utfs;
++ u16 utfet;
++ u16 utftt;
++ u16 ufpt;
++ enum ucc_fast_channel_protocol_mode mode;
++ enum ucc_fast_transparent_txrx ttx_trx;
++ enum ucc_fast_tx_encoding_method tenc;
++ enum ucc_fast_rx_decoding_method renc;
++ enum ucc_fast_transparent_tcrc tcrc;
++ enum ucc_fast_sync_len synl;
++};
++
++struct ucc_fast_private {
++ struct ucc_fast_info *uf_info;
++ struct ucc_fast *uf_regs; /* a pointer to memory map of UCC regs. */
++ u32 *p_ucce; /* a pointer to the event register in memory. */
++ u32 *p_uccm; /* a pointer to the mask register in memory. */
++ int enabled_tx; /* Whether channel is enabled for Tx (ENT) */
++ int enabled_rx; /* Whether channel is enabled for Rx (ENR) */
++ int stopped_tx; /* Whether channel has been stopped for Tx
++ (STOP_TX, etc.) */
++ int stopped_rx; /* Whether channel has been stopped for Rx */
++ u32 ucc_fast_tx_virtual_fifo_base_offset;/* pointer to base of Tx
++ virtual fifo */
++ u32 ucc_fast_rx_virtual_fifo_base_offset;/* pointer to base of Rx
++ virtual fifo */
++#ifdef STATISTICS
++ u32 tx_frames; /* Transmitted frames counter. */
++ u32 rx_frames; /* Received frames counter (only frames
++ passed to application). */
++ u32 tx_discarded; /* Discarded tx frames counter (frames that
++ were discarded by the driver due to errors).
++ */
++ u32 rx_discarded; /* Discarded rx frames counter (frames that
++ were discarded by the driver due to errors).
++ */
++#endif /* STATISTICS */
++ u16 mrblr; /* maximum receive buffer length */
++};
++
++/* ucc_fast_init
++ * Initializes Fast UCC according to user provided parameters.
++ *
++ * uf_info - (In) pointer to the fast UCC info structure.
++ * uccf_ret - (Out) pointer to the fast UCC structure.
++ */
++int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret);
++
++/* ucc_fast_free
++ * Frees all resources for fast UCC.
++ *
++ * uccf - (In) pointer to the fast UCC structure.
++ */
++void ucc_fast_free(struct ucc_fast_private * uccf);
++
++/* ucc_fast_enable
++ * Enables a fast UCC port.
++ * This routine enables Tx and/or Rx through the General UCC Mode Register.
++ *
++ * uccf - (In) pointer to the fast UCC structure.
++ * mode - (In) TX, RX, or both.
++ */
++void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode);
++
++/* ucc_fast_disable
++ * Disables a fast UCC port.
++ * This routine disables Tx and/or Rx through the General UCC Mode Register.
++ *
++ * uccf - (In) pointer to the fast UCC structure.
++ * mode - (In) TX, RX, or both.
++ */
++void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode);
++
++/* ucc_fast_irq
++ * Handles interrupts on fast UCC.
++ * Called from the general interrupt routine to handle interrupts on fast UCC.
++ *
++ * uccf - (In) pointer to the fast UCC structure.
++ */
++void ucc_fast_irq(struct ucc_fast_private * uccf);
++
++/* ucc_fast_transmit_on_demand
++ * Immediately forces a poll of the transmitter for data to be sent.
++ * Typically, the hardware performs a periodic poll for data that the
++ * transmit routine has set up to be transmitted. In cases where
++ * this polling cycle is not soon enough, this optional routine can
++ * be invoked to force a poll right away, instead. Proper use for
++ * each transmission for which this functionality is desired is to
++ * call the transmit routine and then this routine right after.
++ *
++ * uccf - (In) pointer to the fast UCC structure.
++ */
++void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf);
++
++u32 ucc_fast_get_qe_cr_subblock(int uccf_num);
++
++void ucc_fast_dump_regs(struct ucc_fast_private * uccf);
++
++#endif /* __UCC_FAST_H__ */
+diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h
+new file mode 100644
+index 0000000..ca93bc9
+--- /dev/null
++++ b/include/asm-powerpc/ucc_slow.h
+@@ -0,0 +1,289 @@
++/*
++ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Authors: Shlomi Gridish <gridish at freescale.com>
++ * Li Yang <leoli at freescale.com>
++ *
++ * Description:
++ * Internal header file for UCC SLOW unit routines.
++ *
++ * 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.
++ */
++#ifndef __UCC_SLOW_H__
++#define __UCC_SLOW_H__
++
++#include <linux/kernel.h>
++
++#include <asm/immap_qe.h>
++#include <asm/qe.h>
++
++#include "ucc.h"
++
++/* transmit BD's status */
++#define T_R 0x80000000 /* ready bit */
++#define T_PAD 0x40000000 /* add pads to short frames */
++#define T_W 0x20000000 /* wrap bit */
++#define T_I 0x10000000 /* interrupt on completion */
++#define T_L 0x08000000 /* last */
++
++#define T_A 0x04000000 /* Address - the data transmitted as address
++ chars */
++#define T_TC 0x04000000 /* transmit CRC */
++#define T_CM 0x02000000 /* continuous mode */
++#define T_DEF 0x02000000 /* collision on previous attempt to transmit */
++#define T_P 0x01000000 /* Preamble - send Preamble sequence before
++ data */
++#define T_HB 0x01000000 /* heartbeat */
++#define T_NS 0x00800000 /* No Stop */
++#define T_LC 0x00800000 /* late collision */
++#define T_RL 0x00400000 /* retransmission limit */
++#define T_UN 0x00020000 /* underrun */
++#define T_CT 0x00010000 /* CTS lost */
++#define T_CSL 0x00010000 /* carrier sense lost */
++#define T_RC 0x003c0000 /* retry count */
++
++/* Receive BD's status */
++#define R_E 0x80000000 /* buffer empty */
++#define R_W 0x20000000 /* wrap bit */
++#define R_I 0x10000000 /* interrupt on reception */
++#define R_L 0x08000000 /* last */
++#define R_C 0x08000000 /* the last byte in this buffer is a cntl
++ char */
++#define R_F 0x04000000 /* first */
++#define R_A 0x04000000 /* the first byte in this buffer is address
++ byte */
++#define R_CM 0x02000000 /* continuous mode */
++#define R_ID 0x01000000 /* buffer close on reception of idles */
++#define R_M 0x01000000 /* Frame received because of promiscuous
++ mode */
++#define R_AM 0x00800000 /* Address match */
++#define R_DE 0x00800000 /* Address match */
++#define R_LG 0x00200000 /* Break received */
++#define R_BR 0x00200000 /* Frame length violation */
++#define R_NO 0x00100000 /* Rx Non Octet Aligned Packet */
++#define R_FR 0x00100000 /* Framing Error (no stop bit) character
++ received */
++#define R_PR 0x00080000 /* Parity Error character received */
++#define R_AB 0x00080000 /* Frame Aborted */
++#define R_SH 0x00080000 /* frame is too short */
++#define R_CR 0x00040000 /* CRC Error */
++#define R_OV 0x00020000 /* Overrun */
++#define R_CD 0x00010000 /* CD lost */
++#define R_CL 0x00010000 /* this frame is closed because of a
++ collision */
++
++/* Rx Data buffer must be 4 bytes aligned in most cases.*/
++#define UCC_SLOW_RX_ALIGN 4
++#define UCC_SLOW_MRBLR_ALIGNMENT 4
++#define UCC_SLOW_PRAM_SIZE 0x100
++#define ALIGNMENT_OF_UCC_SLOW_PRAM 64
++
++/* UCC Slow Channel Protocol Mode */
++enum ucc_slow_channel_protocol_mode {
++ UCC_SLOW_CHANNEL_PROTOCOL_MODE_QMC = 0x00000002,
++ UCC_SLOW_CHANNEL_PROTOCOL_MODE_UART = 0x00000004,
++ UCC_SLOW_CHANNEL_PROTOCOL_MODE_BISYNC = 0x00000008,
++};
++
++/* UCC Slow Transparent Transmit CRC (TCRC) */
++enum ucc_slow_transparent_tcrc {
++ /* 16-bit CCITT CRC (HDLC). (X16 + X12 + X5 + 1) */
++ UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC16 = 0x00000000,
++ /* CRC16 (BISYNC). (X16 + X15 + X2 + 1) */
++ UCC_SLOW_TRANSPARENT_TCRC_CRC16 = 0x00004000,
++ /* 32-bit CCITT CRC (Ethernet and HDLC) */
++ UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC32 = 0x00008000,
++};
++
++/* UCC Slow oversampling rate for transmitter (TDCR) */
++enum ucc_slow_tx_oversampling_rate {
++ /* 1x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_1 = 0x00000000,
++ /* 8x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_8 = 0x00010000,
++ /* 16x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_16 = 0x00020000,
++ /* 32x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_32 = 0x00030000,
++};
++
++/* UCC Slow Oversampling rate for receiver (RDCR)
++*/
++enum ucc_slow_rx_oversampling_rate {
++ /* 1x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_1 = 0x00000000,
++ /* 8x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_8 = 0x00004000,
++ /* 16x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_16 = 0x00008000,
++ /* 32x clock mode */
++ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_32 = 0x0000c000,
++};
++
++/* UCC Slow Transmitter encoding method (TENC)
++*/
++enum ucc_slow_tx_encoding_method {
++ UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZ = 0x00000000,
++ UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZI = 0x00000100
++};
++
++/* UCC Slow Receiver decoding method (RENC)
++*/
++enum ucc_slow_rx_decoding_method {
++ UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZ = 0x00000000,
++ UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZI = 0x00000800
++};
++
++/* UCC Slow Diagnostic mode (DIAG)
++*/
++enum ucc_slow_diag_mode {
++ UCC_SLOW_DIAG_MODE_NORMAL = 0x00000000,
++ UCC_SLOW_DIAG_MODE_LOOPBACK = 0x00000040,
++ UCC_SLOW_DIAG_MODE_ECHO = 0x00000080,
++ UCC_SLOW_DIAG_MODE_LOOPBACK_ECHO = 0x000000c0
++};
++
++struct ucc_slow_info {
++ int ucc_num;
++ enum qe_clock rx_clock;
++ enum qe_clock tx_clock;
++ struct ucc_slow *us_regs;
++ int irq;
++ u16 uccm_mask;
++ int data_mem_part;
++ int init_tx;
++ int init_rx;
++ u32 tx_bd_ring_len;
++ u32 rx_bd_ring_len;
++ int rx_interrupts;
++ int brkpt_support;
++ int grant_support;
++ int tsa;
++ int cdp;
++ int cds;
++ int ctsp;
++ int ctss;
++ int rinv;
++ int tinv;
++ int rtsm;
++ int rfw;
++ int tci;
++ int tend;
++ int tfl;
++ int txsy;
++ u16 max_rx_buf_length;
++ enum ucc_slow_transparent_tcrc tcrc;
++ enum ucc_slow_channel_protocol_mode mode;
++ enum ucc_slow_diag_mode diag;
++ enum ucc_slow_tx_oversampling_rate tdcr;
++ enum ucc_slow_rx_oversampling_rate rdcr;
++ enum ucc_slow_tx_encoding_method tenc;
++ enum ucc_slow_rx_decoding_method renc;
++};
++
++struct ucc_slow_private {
++ struct ucc_slow_info *us_info;
++ struct ucc_slow *us_regs; /* a pointer to memory map of UCC regs */
++ struct ucc_slow_pram *us_pram; /* a pointer to the parameter RAM */
++ u32 us_pram_offset;
++ int enabled_tx; /* Whether channel is enabled for Tx (ENT) */
++ int enabled_rx; /* Whether channel is enabled for Rx (ENR) */
++ int stopped_tx; /* Whether channel has been stopped for Tx
++ (STOP_TX, etc.) */
++ int stopped_rx; /* Whether channel has been stopped for Rx */
++ struct list_head confQ; /* frames passed to chip waiting for tx */
++ u32 first_tx_bd_mask; /* mask is used in Tx routine to save status
++ and length for first BD in a frame */
++ u32 tx_base_offset; /* first BD in Tx BD table offset (In MURAM) */
++ u32 rx_base_offset; /* first BD in Rx BD table offset (In MURAM) */
++ u8 *confBd; /* next BD for confirm after Tx */
++ u8 *tx_bd; /* next BD for new Tx request */
++ u8 *rx_bd; /* next BD to collect after Rx */
++ void *p_rx_frame; /* accumulating receive frame */
++ u16 *p_ucce; /* a pointer to the event register in memory.
++ */
++ u16 *p_uccm; /* a pointer to the mask register in memory */
++ u16 saved_uccm; /* a saved mask for the RX Interrupt bits */
++#ifdef STATISTICS
++ u32 tx_frames; /* Transmitted frames counters */
++ u32 rx_frames; /* Received frames counters (only frames
++ passed to application) */
++ u32 rx_discarded; /* Discarded frames counters (frames that
++ were discarded by the driver due to
++ errors) */
++#endif /* STATISTICS */
++};
++
++/* ucc_slow_init
++ * Initializes Slow UCC according to provided parameters.
++ *
++ * us_info - (In) pointer to the slow UCC info structure.
++ * uccs_ret - (Out) pointer to the slow UCC structure.
++ */
++int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret);
++
++/* ucc_slow_free
++ * Frees all resources for slow UCC.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ */
++void ucc_slow_free(struct ucc_slow_private * uccs);
++
++/* ucc_slow_enable
++ * Enables a fast UCC port.
++ * This routine enables Tx and/or Rx through the General UCC Mode Register.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ * mode - (In) TX, RX, or both.
++ */
++void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode);
++
++/* ucc_slow_disable
++ * Disables a fast UCC port.
++ * This routine disables Tx and/or Rx through the General UCC Mode Register.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ * mode - (In) TX, RX, or both.
++ */
++void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode);
++
++/* ucc_slow_poll_transmitter_now
++ * Immediately forces a poll of the transmitter for data to be sent.
++ * Typically, the hardware performs a periodic poll for data that the
++ * transmit routine has set up to be transmitted. In cases where
++ * this polling cycle is not soon enough, this optional routine can
++ * be invoked to force a poll right away, instead. Proper use for
++ * each transmission for which this functionality is desired is to
++ * call the transmit routine and then this routine right after.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ */
++void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs);
++
++/* ucc_slow_graceful_stop_tx
++ * Smoothly stops transmission on a specified slow UCC.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ */
++void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs);
++
++/* ucc_slow_stop_tx
++ * Stops transmission on a specified slow UCC.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ */
++void ucc_slow_stop_tx(struct ucc_slow_private * uccs);
++
++/* ucc_slow_restart_x
++ * Restarts transmitting on a specified slow UCC.
++ *
++ * uccs - (In) pointer to the slow UCC structure.
++ */
++void ucc_slow_restart_x(struct ucc_slow_private * uccs);
++
++u32 ucc_slow_get_qe_cr_subblock(int uccs_num);
++
++#endif /* __UCC_SLOW_H__ */
+diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
+index eb66eae..b5fe932 100644
+--- a/include/asm-powerpc/unistd.h
++++ b/include/asm-powerpc/unistd.h
+@@ -276,7 +276,7 @@
+ #define __NR_rtas 255
+ #define __NR_sys_debug_setcontext 256
+ /* Number 257 is reserved for vserver */
+-/* 258 currently unused */
++#define __NR_migrate_pages 258
+ #define __NR_mbind 259
+ #define __NR_get_mempolicy 260
+ #define __NR_set_mempolicy 261
+@@ -479,13 +479,6 @@ type name(type1 arg1, type2 arg2, type3
+ #endif
+
+ /*
+- * System call prototypes.
+- */
+-#ifdef __KERNEL_SYSCALLS__
+-extern int execve(const char *file, char **argv, char **envp);
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+-/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
+index dc9bd10..4b51d42 100644
+--- a/include/asm-powerpc/vio.h
++++ b/include/asm-powerpc/vio.h
+@@ -46,8 +46,8 @@ struct iommu_table;
+ */
+ struct vio_dev {
+ struct iommu_table *iommu_table; /* vio_map_* uses this */
+- char *name;
+- char *type;
++ const char *name;
++ const char *type;
+ uint32_t unit_address;
+ unsigned int irq;
+ struct device dev;
+diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h
+index 43f7129..f1d337e 100644
+--- a/include/asm-powerpc/xmon.h
++++ b/include/asm-powerpc/xmon.h
+@@ -1,12 +1,22 @@
+-#ifndef __PPC_XMON_H
+-#define __PPC_XMON_H
+-#ifdef __KERNEL__
++#ifndef __ASM_POWERPC_XMON_H
++#define __ASM_POWERPC_XMON_H
+
+-struct pt_regs;
++/*
++ * Copyrignt (C) 2006 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.
++ */
+
+-extern int xmon(struct pt_regs *excp);
+-extern void xmon_printf(const char *fmt, ...);
+-extern void xmon_init(int);
++#ifdef __KERNEL__
+
++#ifdef CONFIG_XMON
++extern void xmon_setup(void);
++#else
++static inline void xmon_setup(void) { };
+ #endif
+-#endif
++
++#endif /* __KERNEL __ */
++#endif /* __ASM_POWERPC_XMON_H */
+diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
+index 3247bea..7b06b4e 100644
+--- a/include/asm-ppc/commproc.h
++++ b/include/asm-ppc/commproc.h
+@@ -690,8 +690,7 @@ typedef struct risc_timer_pram {
+ #define CICR_IEN ((uint)0x00000080) /* Int. enable */
+ #define CICR_SPS ((uint)0x00000001) /* SCC Spread */
+
+-extern void cpm_install_handler(int vec,
+- void (*handler)(void *, struct pt_regs *regs), void *dev_id);
++extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
+ extern void cpm_free_handler(int vec);
+
+ #endif /* __CPM_8XX__ */
+diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
+index f6a7ff0..220cc2d 100644
+--- a/include/asm-ppc/cpm2.h
++++ b/include/asm-ppc/cpm2.h
+@@ -42,6 +42,8 @@
+ #define CPM_CR_IDMA4_SBLOCK (0x17)
+ #define CPM_CR_MCC1_SBLOCK (0x1c)
+
++#define CPM_CR_FCC_SBLOCK(x) (x + 0x10)
++
+ #define CPM_CR_SCC1_PAGE (0x00)
+ #define CPM_CR_SCC2_PAGE (0x01)
+ #define CPM_CR_SCC3_PAGE (0x02)
+@@ -62,6 +64,8 @@
+ #define CPM_CR_MCC1_PAGE (0x07)
+ #define CPM_CR_MCC2_PAGE (0x08)
+
++#define CPM_CR_FCC_PAGE(x) (x + 0x04)
++
+ /* Some opcodes (there are more...later)
+ */
+ #define CPM_CR_INIT_TRX ((ushort)0x0000)
+@@ -173,6 +177,10 @@ typedef struct cpm_buf_desc {
+ #define PROFF_I2C_BASE ((uint)0x8afc)
+ #define PROFF_IDMA4_BASE ((uint)0x8afe)
+
++#define PROFF_SCC_SIZE ((uint)0x100)
++#define PROFF_FCC_SIZE ((uint)0x100)
++#define PROFF_SMC_SIZE ((uint)64)
++
+ /* The SMCs are relocated to any of the first eight DPRAM pages.
+ * We will fix these at the first locations of DPRAM, until we
+ * get some microcode patches :-).
+@@ -1186,7 +1194,60 @@ typedef struct im_idma {
+ #define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
+ #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
+ #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
+-#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
++#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
++
++/* Clocks and GRG's */
++
++enum cpm_clk_dir {
++ CPM_CLK_RX,
++ CPM_CLK_TX,
++ CPM_CLK_RTX
++};
++
++enum cpm_clk_target {
++ CPM_CLK_SCC1,
++ CPM_CLK_SCC2,
++ CPM_CLK_SCC3,
++ CPM_CLK_SCC4,
++ CPM_CLK_FCC1,
++ CPM_CLK_FCC2,
++ CPM_CLK_FCC3
++};
++
++enum cpm_clk {
++ CPM_CLK_NONE = 0,
++ CPM_BRG1, /* Baud Rate Generator 1 */
++ CPM_BRG2, /* Baud Rate Generator 2 */
++ CPM_BRG3, /* Baud Rate Generator 3 */
++ CPM_BRG4, /* Baud Rate Generator 4 */
++ CPM_BRG5, /* Baud Rate Generator 5 */
++ CPM_BRG6, /* Baud Rate Generator 6 */
++ CPM_BRG7, /* Baud Rate Generator 7 */
++ CPM_BRG8, /* Baud Rate Generator 8 */
++ CPM_CLK1, /* Clock 1 */
++ CPM_CLK2, /* Clock 2 */
++ CPM_CLK3, /* Clock 3 */
++ CPM_CLK4, /* Clock 4 */
++ CPM_CLK5, /* Clock 5 */
++ CPM_CLK6, /* Clock 6 */
++ CPM_CLK7, /* Clock 7 */
++ CPM_CLK8, /* Clock 8 */
++ CPM_CLK9, /* Clock 9 */
++ CPM_CLK10, /* Clock 10 */
++ CPM_CLK11, /* Clock 11 */
++ CPM_CLK12, /* Clock 12 */
++ CPM_CLK13, /* Clock 13 */
++ CPM_CLK14, /* Clock 14 */
++ CPM_CLK15, /* Clock 15 */
++ CPM_CLK16, /* Clock 16 */
++ CPM_CLK17, /* Clock 17 */
++ CPM_CLK18, /* Clock 18 */
++ CPM_CLK19, /* Clock 19 */
++ CPM_CLK20, /* Clock 20 */
++ CPM_CLK_DUMMY
++};
++
++extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode);
+
+ #endif /* __CPM2__ */
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
+index d3963ca..ae316e6 100644
+--- a/include/asm-ppc/floppy.h
++++ b/include/asm-ppc/floppy.h
+@@ -38,14 +38,14 @@ static int virtual_dma_mode;
+ static int doing_vdma;
+ static struct fd_dma_ops *fd_ops;
+
+-static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t floppy_hardint(int irq, void *dev_id)
+ {
+ unsigned char st;
+ int lcount;
+ char *lptr;
+
+ if (!doing_vdma)
+- return floppy_interrupt(irq, dev_id, regs);
++ return floppy_interrupt(irq, dev_id);
+
+
+ st = 1;
+@@ -69,7 +69,7 @@ static irqreturn_t floppy_hardint(int ir
+ virtual_dma_residue += virtual_dma_count;
+ virtual_dma_count=0;
+ doing_vdma = 0;
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+ return IRQ_HANDLED;
+diff --git a/include/asm-ppc/fs_pd.h b/include/asm-ppc/fs_pd.h
+new file mode 100644
+index 0000000..8691327
+--- /dev/null
++++ b/include/asm-ppc/fs_pd.h
+@@ -0,0 +1,36 @@
++/*
++ * Platform information definitions.
++ *
++ * 2006 (c) MontaVista Software, Inc.
++ * Vitaly Bordug <vbordug at ru.mvista.com>
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#ifndef FS_PD_H
++#define FS_PD_H
++
++static inline int uart_baudrate(void)
++{
++ int baud;
++ bd_t *bd = (bd_t *) __res;
++
++ if (bd->bi_baudrate)
++ baud = bd->bi_baudrate;
++ else
++ baud = -1;
++ return baud;
++}
++
++static inline int uart_clock(void)
++{
++ return (((bd_t *) __res)->bi_intfreq);
++}
++
++#define cpm2_map(member) (&cpm2_immr->member)
++#define cpm2_map_size(member, size) (&cpm2_immr->member)
++#define cpm2_unmap(addr) do {} while(0)
++
++#endif
+diff --git a/include/asm-ppc/gt64260.h b/include/asm-ppc/gt64260.h
+index cd0ef64..9e63b3c 100644
+--- a/include/asm-ppc/gt64260.h
++++ b/include/asm-ppc/gt64260.h
+@@ -315,7 +315,7 @@ int gt64260_get_base(u32 *base);
+ int gt64260_pci_exclude_device(u8 bus, u8 devfn);
+
+ void gt64260_init_irq(void);
+-int gt64260_get_irq(struct pt_regs *regs);
++int gt64260_get_irq(void);
+
+ void gt64260_mpsc_progress(char *s, unsigned short hex);
+
+diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
+index cf62b69..499c146 100644
+--- a/include/asm-ppc/ibm4xx.h
++++ b/include/asm-ppc/ibm4xx.h
+@@ -86,7 +86,7 @@ void ppc4xx_init(unsigned long r3, unsig
+ #define PCI_DRAM_OFFSET 0
+ #endif
+
+-#elif CONFIG_44x
++#elif defined(CONFIG_44x)
+
+ #if defined(CONFIG_BAMBOO)
+ #include <platforms/4xx/bamboo.h>
+diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
+index 680555b..a4c411b 100644
+--- a/include/asm-ppc/io.h
++++ b/include/asm-ppc/io.h
+@@ -327,26 +327,12 @@ __do_out_asm(outl, "stwbrx")
+ #define inl_p(port) inl((port))
+ #define outl_p(val, port) outl((val), (port))
+
+-extern void _insb(volatile u8 __iomem *port, void *buf, int ns);
+-extern void _outsb(volatile u8 __iomem *port, const void *buf, int ns);
+-extern void _insw(volatile u16 __iomem *port, void *buf, int ns);
+-extern void _outsw(volatile u16 __iomem *port, const void *buf, int ns);
+-extern void _insl(volatile u32 __iomem *port, void *buf, int nl);
+-extern void _outsl(volatile u32 __iomem *port, const void *buf, int nl);
+-extern void _insw_ns(volatile u16 __iomem *port, void *buf, int ns);
+-extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, int ns);
+-extern void _insl_ns(volatile u32 __iomem *port, void *buf, int nl);
+-extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl);
+-
+-/*
+- * The *_ns versions below don't do byte-swapping.
+- * Neither do the standard versions now, these are just here
+- * for older code.
+- */
+-#define insw_ns(port, buf, ns) _insw_ns((port)+___IO_BASE, (buf), (ns))
+-#define outsw_ns(port, buf, ns) _outsw_ns((port)+___IO_BASE, (buf), (ns))
+-#define insl_ns(port, buf, nl) _insl_ns((port)+___IO_BASE, (buf), (nl))
+-#define outsl_ns(port, buf, nl) _outsl_ns((port)+___IO_BASE, (buf), (nl))
++extern void _insb(volatile u8 __iomem *port, void *buf, long count);
++extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
++extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
++extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
++extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
++extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
+
+
+ #define IO_SPACE_LIMIT ~0
+@@ -453,22 +439,6 @@ extern inline void * phys_to_virt(unsign
+ #define iobarrier_r() eieio()
+ #define iobarrier_w() eieio()
+
+-static inline int check_signature(volatile void __iomem * io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ /*
+ * Here comes the ppc implementation of the IOMAP
+ * interfaces.
+diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
+index da77467..293a444 100644
+--- a/include/asm-ppc/machdep.h
++++ b/include/asm-ppc/machdep.h
+@@ -43,7 +43,7 @@ struct machdep_calls {
+ /* Optional, may be NULL. */
+ unsigned int (*irq_canonicalize)(unsigned int irq);
+ void (*init_IRQ)(void);
+- int (*get_irq)(struct pt_regs *);
++ int (*get_irq)(void);
+
+ /* A general init function, called by ppc_init in init/main.c.
+ May be NULL. DEPRECATED ! */
+diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
+index 7e98428..64c8874 100644
+--- a/include/asm-ppc/mpc52xx.h
++++ b/include/asm-ppc/mpc52xx.h
+@@ -415,7 +415,7 @@ struct mpc52xx_cdm {
+ #ifndef __ASSEMBLY__
+
+ extern void mpc52xx_init_irq(void);
+-extern int mpc52xx_get_irq(struct pt_regs *regs);
++extern int mpc52xx_get_irq(void);
+
+ extern unsigned long mpc52xx_find_end_of_memory(void);
+ extern void mpc52xx_set_bat(void);
+diff --git a/include/asm-ppc/mpc8260_pci9.h b/include/asm-ppc/mpc8260_pci9.h
+index 26b3f6e..9f71768 100644
+--- a/include/asm-ppc/mpc8260_pci9.h
++++ b/include/asm-ppc/mpc8260_pci9.h
+@@ -30,8 +30,6 @@
+ #undef inb
+ #undef inw
+ #undef inl
+-#undef insw_ns
+-#undef insl_ns
+ #undef memcpy_fromio
+
+ extern int readb(volatile unsigned char *addr);
+@@ -43,8 +41,6 @@ extern void insl(unsigned port, void *bu
+ extern int inb(unsigned port);
+ extern int inw(unsigned port);
+ extern unsigned inl(unsigned port);
+-extern void insw_ns(unsigned port, void *buf, int ns);
+-extern void insl_ns(unsigned port, void *buf, int nl);
+ extern void *memcpy_fromio(void *dest, unsigned long src, size_t count);
+
+ #endif /* !__CONFIG_8260_PCI9_DEFS */
+diff --git a/include/asm-ppc/mv64x60.h b/include/asm-ppc/mv64x60.h
+index 663edbe..db3776f 100644
+--- a/include/asm-ppc/mv64x60.h
++++ b/include/asm-ppc/mv64x60.h
+@@ -336,9 +336,9 @@ int mv64x60_pci_exclude_device(u8 bus, u
+
+
+ void gt64260_init_irq(void);
+-int gt64260_get_irq(struct pt_regs *regs);
++int gt64260_get_irq(void);
+ void mv64360_init_irq(void);
+-int mv64360_get_irq(struct pt_regs *regs);
++int mv64360_get_irq(void);
+
+ u32 mv64x60_mask(u32 val, u32 num_bits);
+ u32 mv64x60_shift_left(u32 val, u32 num_bits);
+diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h
+index f8f7f16..5b0704a 100644
+--- a/include/asm-ppc/mv64x60_defs.h
++++ b/include/asm-ppc/mv64x60_defs.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/gt64260_defs.h
++ * include/asm-ppc/mv64x60_defs.h
+ *
+ * Register definitions for the Marvell/Galileo GT64260, MV64360, etc.
+ * host bridges.
+diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
+index a4fe962..778d572 100644
+--- a/include/asm-ppc/open_pic.h
++++ b/include/asm-ppc/open_pic.h
+@@ -48,12 +48,12 @@ extern void openpic_init(int linux_irq_o
+ 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 *));
++ int (*cascade_fn)(void));
+ extern u_int openpic_irq(void);
+ extern void openpic_eoi(void);
+ extern void openpic_request_IPIs(void);
+ extern void do_openpic_setup_cpu(void);
+-extern int openpic_get_irq(struct pt_regs *regs);
++extern int openpic_get_irq(void);
+ extern void openpic_reset_processor_phys(u_int cpumask);
+ extern void openpic_setup_ISU(int isu_num, unsigned long addr);
+ extern void openpic_cause_IPI(u_int ipi, cpumask_t cpumask);
+@@ -93,6 +93,6 @@ extern void openpic2_init(int linux_irq_
+ extern void openpic2_init_nmi_irq(u_int irq);
+ extern u_int openpic2_irq(void);
+ extern void openpic2_eoi(void);
+-extern int openpic2_get_irq(struct pt_regs *regs);
++extern int openpic2_get_irq(void);
+ extern void openpic2_setup_ISU(int isu_num, unsigned long addr);
+ #endif /* _PPC_KERNEL_OPEN_PIC_H */
+diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
+index 51fa7c6..b1fdbf4 100644
+--- a/include/asm-ppc/pgtable.h
++++ b/include/asm-ppc/pgtable.h
+@@ -526,7 +526,7 @@ static inline int pgd_bad(pgd_t pgd) {
+ static inline int pgd_present(pgd_t pgd) { return 1; }
+ #define pgd_clear(xp) do { } while (0)
+
+-#define pgd_page(pgd) \
++#define pgd_page_vaddr(pgd) \
+ ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+ /*
+@@ -720,12 +720,12 @@ extern pgprot_t phys_mem_access_prot(str
+ * of the pte page. -- paulus
+ */
+ #ifndef CONFIG_BOOKE
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+ #define pmd_page(pmd) \
+ (mem_map + (pmd_val(pmd) >> PAGE_SHIFT))
+ #else
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) (pmd_val(pmd) & PAGE_MASK))
+ #define pmd_page(pmd) \
+ (mem_map + (__pa(pmd_val(pmd)) >> PAGE_SHIFT))
+@@ -748,7 +748,7 @@ static inline pmd_t * pmd_offset(pgd_t *
+ #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))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
+ #define pte_offset_map(dir, addr) \
+ ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
+ #define pte_offset_map_nested(dir, addr) \
+diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
+index 4944c0f..602fbad 100644
+--- a/include/asm-ppc/reg_booke.h
++++ b/include/asm-ppc/reg_booke.h
+@@ -300,14 +300,14 @@ do { \
+ #define DBSR_IC 0x80000000 /* Instruction Completion */
+ #define DBSR_BT 0x40000000 /* Branch taken */
+ #define DBSR_TIE 0x10000000 /* Trap Instruction debug Event */
+-#define DBSR_IAC1 0x00800000 /* Instruction Address Compare 1 Event */
+-#define DBSR_IAC2 0x00400000 /* Instruction Address Compare 2 Event */
+-#define DBSR_IAC3 0x00200000 /* Instruction Address Compare 3 Event */
+-#define DBSR_IAC4 0x00100000 /* Instruction Address Compare 4 Event */
+-#define DBSR_DAC1R 0x00080000 /* Data Address Compare 1 Read Event */
+-#define DBSR_DAC1W 0x00040000 /* Data Address Compare 1 Write Event */
+-#define DBSR_DAC2R 0x00020000 /* Data Address Compare 2 Read Event */
+-#define DBSR_DAC2W 0x00010000 /* Data Address Compare 2 Write Event */
++#define DBSR_IAC1 0x04000000 /* Instruction Address Compare 1 Event */
++#define DBSR_IAC2 0x02000000 /* Instruction Address Compare 2 Event */
++#define DBSR_IAC3 0x00080000 /* Instruction Address Compare 3 Event */
++#define DBSR_IAC4 0x00040000 /* Instruction Address Compare 4 Event */
++#define DBSR_DAC1R 0x01000000 /* Data Address Compare 1 Read Event */
++#define DBSR_DAC1W 0x00800000 /* Data Address Compare 1 Write Event */
++#define DBSR_DAC2R 0x00400000 /* Data Address Compare 2 Read Event */
++#define DBSR_DAC2W 0x00200000 /* Data Address Compare 2 Write Event */
+ #endif
+
+ /* Bit definitions related to the ESR. */
+diff --git a/include/asm-ppc/rheap.h b/include/asm-ppc/rheap.h
+index e6ca1f6..39a10d8 100644
+--- a/include/asm-ppc/rheap.h
++++ b/include/asm-ppc/rheap.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-ppc/rheap.c
++ * include/asm-ppc/rheap.h
+ *
+ * Header file for the implementation of a remote heap.
+ *
+@@ -62,6 +62,10 @@ extern int rh_attach_region(rh_info_t *
+ /* Detach a free region */
+ extern void *rh_detach_region(rh_info_t * info, void *start, int size);
+
++/* Allocate the given size from the remote heap (with alignment) */
++extern void *rh_alloc_align(rh_info_t * info, int size, int alignment,
++ const char *owner);
++
+ /* Allocate the given size from the remote heap */
+ extern void *rh_alloc(rh_info_t * info, int size, const char *owner);
+
+diff --git a/include/asm-ppc/rtc.h b/include/asm-ppc/rtc.h
+index 05fbf91..6025b46 100644
+--- a/include/asm-ppc/rtc.h
++++ b/include/asm-ppc/rtc.h
+@@ -1,5 +1,5 @@
+ /*
+- * inclue/asm-ppc/rtc.h
++ * include/asm-ppc/rtc.h
+ *
+ * Author: Tom Rini <trini at mvista.com>
+ *
+diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h
+index 0b7fa89..e75791e 100644
+--- a/include/asm-ppc/smp.h
++++ b/include/asm-ppc/smp.h
+@@ -39,7 +39,7 @@ extern struct smp_ops_t *smp_ops;
+ extern void smp_send_tlb_invalidate(int);
+ extern void smp_send_xmon_break(int cpu);
+ struct pt_regs;
+-extern void smp_message_recv(int, struct pt_regs *);
++extern void smp_message_recv(int);
+
+ extern int __cpu_disable(void);
+ extern void __cpu_die(unsigned int cpu);
+diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
+index 5c64b75..fccaf55 100644
+--- a/include/asm-ppc/spinlock.h
++++ b/include/asm-ppc/spinlock.h
+@@ -161,4 +161,8 @@ static __inline__ void __raw_write_unloc
+ rw->lock = 0;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-s390/Kbuild b/include/asm-s390/Kbuild
+index ed8955f..e92b429 100644
+--- a/include/asm-s390/Kbuild
++++ b/include/asm-s390/Kbuild
+@@ -1,4 +1,12 @@
+ include include/asm-generic/Kbuild.asm
+
+-unifdef-y += cmb.h debug.h
+-header-y += dasd.h qeth.h tape390.h ucontext.h vtoc.h z90crypt.h
++header-y += dasd.h
++header-y += monwriter.h
++header-y += qeth.h
++header-y += tape390.h
++header-y += ucontext.h
++header-y += vtoc.h
++header-y += zcrypt.h
++
++unifdef-y += cmb.h
++unifdef-y += debug.h
+diff --git a/include/asm-s390/appldata.h b/include/asm-s390/appldata.h
+new file mode 100644
+index 0000000..79283da
+--- /dev/null
++++ b/include/asm-s390/appldata.h
+@@ -0,0 +1,90 @@
++/*
++ * include/asm-s390/appldata.h
++ *
++ * Copyright (C) IBM Corp. 2006
++ *
++ * Author(s): Melissa Howland <melissah at us.ibm.com>
++ */
++
++#ifndef _ASM_S390_APPLDATA_H
++#define _ASM_S390_APPLDATA_H
++
++#include <asm/io.h>
++
++#ifndef CONFIG_64BIT
++
++#define APPLDATA_START_INTERVAL_REC 0x00 /* Function codes for */
++#define APPLDATA_STOP_REC 0x01 /* DIAG 0xDC */
++#define APPLDATA_GEN_EVENT_REC 0x02
++#define APPLDATA_START_CONFIG_REC 0x03
++
++/*
++ * Parameter list for DIAGNOSE X'DC'
++ */
++struct appldata_parameter_list {
++ u16 diag; /* The DIAGNOSE code X'00DC' */
++ u8 function; /* The function code for the DIAGNOSE */
++ u8 parlist_length; /* Length of the parameter list */
++ u32 product_id_addr; /* Address of the 16-byte product ID */
++ u16 reserved;
++ u16 buffer_length; /* Length of the application data buffer */
++ u32 buffer_addr; /* Address of the application data buffer */
++} __attribute__ ((packed));
++
++#else /* CONFIG_64BIT */
++
++#define APPLDATA_START_INTERVAL_REC 0x80
++#define APPLDATA_STOP_REC 0x81
++#define APPLDATA_GEN_EVENT_REC 0x82
++#define APPLDATA_START_CONFIG_REC 0x83
++
++/*
++ * Parameter list for DIAGNOSE X'DC'
++ */
++struct appldata_parameter_list {
++ u16 diag;
++ u8 function;
++ u8 parlist_length;
++ u32 unused01;
++ u16 reserved;
++ u16 buffer_length;
++ u32 unused02;
++ u64 product_id_addr;
++ u64 buffer_addr;
++} __attribute__ ((packed));
++
++#endif /* CONFIG_64BIT */
++
++struct appldata_product_id {
++ char prod_nr[7]; /* product number */
++ u16 prod_fn; /* product function */
++ u8 record_nr; /* record number */
++ u16 version_nr; /* version */
++ u16 release_nr; /* release */
++ u16 mod_lvl; /* modification level */
++} __attribute__ ((packed));
++
++static inline int appldata_asm(struct appldata_product_id *id,
++ unsigned short fn, void *buffer,
++ unsigned short length)
++{
++ struct appldata_parameter_list parm_list;
++ int ry;
++
++ if (!MACHINE_IS_VM)
++ return -ENOSYS;
++ parm_list.diag = 0xdc;
++ parm_list.function = fn;
++ parm_list.parlist_length = sizeof(parm_list);
++ parm_list.buffer_length = length;
++ parm_list.product_id_addr = (unsigned long) id;
++ parm_list.buffer_addr = virt_to_phys(buffer);
++ asm volatile(
++ " diag %1,%0,0xdc"
++ : "=d" (ry)
++ : "d" (&parm_list), "m" (parm_list), "m" (*id)
++ : "cc");
++ return ry;
++}
++
++#endif /* _ASM_S390_APPLDATA_H */
+diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
+index 399bf02..af20c74 100644
+--- a/include/asm-s390/atomic.h
++++ b/include/asm-s390/atomic.h
+@@ -30,20 +30,43 @@ typedef struct {
+
+ #ifdef __KERNEL__
+
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++
+ #define __CS_LOOP(ptr, op_val, op_string) ({ \
+ typeof(ptr->counter) old_val, new_val; \
+- __asm__ __volatile__(" l %0,0(%3)\n" \
+- "0: lr %1,%0\n" \
+- op_string " %1,%4\n" \
+- " cs %0,%1,0(%3)\n" \
+- " jl 0b" \
+- : "=&d" (old_val), "=&d" (new_val), \
+- "=m" (((atomic_t *)(ptr))->counter) \
+- : "a" (ptr), "d" (op_val), \
+- "m" (((atomic_t *)(ptr))->counter) \
+- : "cc", "memory" ); \
++ asm volatile( \
++ " l %0,%2\n" \
++ "0: lr %1,%0\n" \
++ op_string " %1,%3\n" \
++ " cs %0,%1,%2\n" \
++ " jl 0b" \
++ : "=&d" (old_val), "=&d" (new_val), \
++ "=Q" (((atomic_t *)(ptr))->counter) \
++ : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \
++ : "cc", "memory"); \
+ new_val; \
+ })
++
++#else /* __GNUC__ */
++
++#define __CS_LOOP(ptr, op_val, op_string) ({ \
++ typeof(ptr->counter) old_val, new_val; \
++ asm volatile( \
++ " l %0,0(%3)\n" \
++ "0: lr %1,%0\n" \
++ op_string " %1,%4\n" \
++ " cs %0,%1,0(%3)\n" \
++ " jl 0b" \
++ : "=&d" (old_val), "=&d" (new_val), \
++ "=m" (((atomic_t *)(ptr))->counter) \
++ : "a" (ptr), "d" (op_val), \
++ "m" (((atomic_t *)(ptr))->counter) \
++ : "cc", "memory"); \
++ new_val; \
++})
++
++#endif /* __GNUC__ */
++
+ #define atomic_read(v) ((v)->counter)
+ #define atomic_set(v,i) (((v)->counter) = (i))
+
+@@ -81,10 +104,19 @@ static __inline__ void atomic_set_mask(u
+
+ static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new)
+ {
+- __asm__ __volatile__(" cs %0,%3,0(%2)\n"
+- : "+d" (old), "=m" (v->counter)
+- : "a" (v), "d" (new), "m" (v->counter)
+- : "cc", "memory" );
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++ asm volatile(
++ " cs %0,%2,%1"
++ : "+d" (old), "=Q" (v->counter)
++ : "d" (new), "Q" (v->counter)
++ : "cc", "memory");
++#else /* __GNUC__ */
++ asm volatile(
++ " cs %0,%3,0(%2)"
++ : "+d" (old), "=m" (v->counter)
++ : "a" (v), "d" (new), "m" (v->counter)
++ : "cc", "memory");
++#endif /* __GNUC__ */
+ return old;
+ }
+
+@@ -113,20 +145,43 @@ typedef struct {
+ } __attribute__ ((aligned (8))) atomic64_t;
+ #define ATOMIC64_INIT(i) { (i) }
+
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++
+ #define __CSG_LOOP(ptr, op_val, op_string) ({ \
+ typeof(ptr->counter) old_val, new_val; \
+- __asm__ __volatile__(" lg %0,0(%3)\n" \
+- "0: lgr %1,%0\n" \
+- op_string " %1,%4\n" \
+- " csg %0,%1,0(%3)\n" \
+- " jl 0b" \
+- : "=&d" (old_val), "=&d" (new_val), \
+- "=m" (((atomic_t *)(ptr))->counter) \
+- : "a" (ptr), "d" (op_val), \
+- "m" (((atomic_t *)(ptr))->counter) \
+- : "cc", "memory" ); \
++ asm volatile( \
++ " lg %0,%2\n" \
++ "0: lgr %1,%0\n" \
++ op_string " %1,%3\n" \
++ " csg %0,%1,%2\n" \
++ " jl 0b" \
++ : "=&d" (old_val), "=&d" (new_val), \
++ "=Q" (((atomic_t *)(ptr))->counter) \
++ : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \
++ : "cc", "memory" ); \
+ new_val; \
+ })
++
++#else /* __GNUC__ */
++
++#define __CSG_LOOP(ptr, op_val, op_string) ({ \
++ typeof(ptr->counter) old_val, new_val; \
++ asm volatile( \
++ " lg %0,0(%3)\n" \
++ "0: lgr %1,%0\n" \
++ op_string " %1,%4\n" \
++ " csg %0,%1,0(%3)\n" \
++ " jl 0b" \
++ : "=&d" (old_val), "=&d" (new_val), \
++ "=m" (((atomic_t *)(ptr))->counter) \
++ : "a" (ptr), "d" (op_val), \
++ "m" (((atomic_t *)(ptr))->counter) \
++ : "cc", "memory" ); \
++ new_val; \
++})
++
++#endif /* __GNUC__ */
++
+ #define atomic64_read(v) ((v)->counter)
+ #define atomic64_set(v,i) (((v)->counter) = (i))
+
+@@ -163,10 +218,19 @@ static __inline__ void atomic64_set_mask
+ static __inline__ long long atomic64_cmpxchg(atomic64_t *v,
+ long long old, long long new)
+ {
+- __asm__ __volatile__(" csg %0,%3,0(%2)\n"
+- : "+d" (old), "=m" (v->counter)
+- : "a" (v), "d" (new), "m" (v->counter)
+- : "cc", "memory" );
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++ asm volatile(
++ " csg %0,%2,%1"
++ : "+d" (old), "=Q" (v->counter)
++ : "d" (new), "Q" (v->counter)
++ : "cc", "memory");
++#else /* __GNUC__ */
++ asm volatile(
++ " csg %0,%3,0(%2)"
++ : "+d" (old), "=m" (v->counter)
++ : "a" (v), "d" (new), "m" (v->counter)
++ : "cc", "memory");
++#endif /* __GNUC__ */
+ return old;
+ }
+
+diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
+index 0ddcdba..f79c9b7 100644
+--- a/include/asm-s390/bitops.h
++++ b/include/asm-s390/bitops.h
+@@ -67,16 +67,35 @@ extern const char _sb_findmap[];
+ #define __BITOPS_AND "nr"
+ #define __BITOPS_XOR "xr"
+
+-#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
+- __asm__ __volatile__(" l %0,0(%4)\n" \
+- "0: lr %1,%0\n" \
+- __op_string " %1,%3\n" \
+- " cs %0,%1,0(%4)\n" \
+- " jl 0b" \
+- : "=&d" (__old), "=&d" (__new), \
+- "=m" (*(unsigned long *) __addr) \
+- : "d" (__val), "a" (__addr), \
+- "m" (*(unsigned long *) __addr) : "cc" );
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++
++#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
++ asm volatile( \
++ " l %0,%2\n" \
++ "0: lr %1,%0\n" \
++ __op_string " %1,%3\n" \
++ " cs %0,%1,%2\n" \
++ " jl 0b" \
++ : "=&d" (__old), "=&d" (__new), \
++ "=Q" (*(unsigned long *) __addr) \
++ : "d" (__val), "Q" (*(unsigned long *) __addr) \
++ : "cc");
++
++#else /* __GNUC__ */
++
++#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
++ asm volatile( \
++ " l %0,0(%4)\n" \
++ "0: lr %1,%0\n" \
++ __op_string " %1,%3\n" \
++ " cs %0,%1,0(%4)\n" \
++ " jl 0b" \
++ : "=&d" (__old), "=&d" (__new), \
++ "=m" (*(unsigned long *) __addr) \
++ : "d" (__val), "a" (__addr), \
++ "m" (*(unsigned long *) __addr) : "cc");
++
++#endif /* __GNUC__ */
+
+ #else /* __s390x__ */
+
+@@ -86,21 +105,41 @@ extern const char _sb_findmap[];
+ #define __BITOPS_AND "ngr"
+ #define __BITOPS_XOR "xgr"
+
+-#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
+- __asm__ __volatile__(" lg %0,0(%4)\n" \
+- "0: lgr %1,%0\n" \
+- __op_string " %1,%3\n" \
+- " csg %0,%1,0(%4)\n" \
+- " jl 0b" \
+- : "=&d" (__old), "=&d" (__new), \
+- "=m" (*(unsigned long *) __addr) \
+- : "d" (__val), "a" (__addr), \
+- "m" (*(unsigned long *) __addr) : "cc" );
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++
++#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
++ asm volatile( \
++ " lg %0,%2\n" \
++ "0: lgr %1,%0\n" \
++ __op_string " %1,%3\n" \
++ " csg %0,%1,%2\n" \
++ " jl 0b" \
++ : "=&d" (__old), "=&d" (__new), \
++ "=Q" (*(unsigned long *) __addr) \
++ : "d" (__val), "Q" (*(unsigned long *) __addr) \
++ : "cc");
++
++#else /* __GNUC__ */
++
++#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
++ asm volatile( \
++ " lg %0,0(%4)\n" \
++ "0: lgr %1,%0\n" \
++ __op_string " %1,%3\n" \
++ " csg %0,%1,0(%4)\n" \
++ " jl 0b" \
++ : "=&d" (__old), "=&d" (__new), \
++ "=m" (*(unsigned long *) __addr) \
++ : "d" (__val), "a" (__addr), \
++ "m" (*(unsigned long *) __addr) : "cc");
++
++
++#endif /* __GNUC__ */
+
+ #endif /* __s390x__ */
+
+ #define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE)
+-#define __BITOPS_BARRIER() __asm__ __volatile__ ( "" : : : "memory" )
++#define __BITOPS_BARRIER() asm volatile("" : : : "memory")
+
+ #ifdef CONFIG_SMP
+ /*
+@@ -217,10 +256,10 @@ static inline void __set_bit(unsigned lo
+ unsigned long addr;
+
+ addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+- asm volatile("oc 0(1,%1),0(%2)"
+- : "=m" (*(char *) addr)
+- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
+- "m" (*(char *) addr) : "cc" );
++ asm volatile(
++ " oc 0(1,%1),0(%2)"
++ : "=m" (*(char *) addr) : "a" (addr),
++ "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" );
+ }
+
+ static inline void
+@@ -229,40 +268,7 @@ __constant_set_bit(const unsigned long n
+ unsigned long addr;
+
+ addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+- switch (nr&7) {
+- case 0:
+- asm volatile ("oi 0(%1),0x01" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 1:
+- asm volatile ("oi 0(%1),0x02" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 2:
+- asm volatile ("oi 0(%1),0x04" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 3:
+- asm volatile ("oi 0(%1),0x08" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 4:
+- asm volatile ("oi 0(%1),0x10" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 5:
+- asm volatile ("oi 0(%1),0x20" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 6:
+- asm volatile ("oi 0(%1),0x40" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 7:
+- asm volatile ("oi 0(%1),0x80" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- }
++ *(unsigned char *) addr |= 1 << (nr & 7);
+ }
+
+ #define set_bit_simple(nr,addr) \
+@@ -279,10 +285,10 @@ __clear_bit(unsigned long nr, volatile u
+ unsigned long addr;
+
+ addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+- asm volatile("nc 0(1,%1),0(%2)"
+- : "=m" (*(char *) addr)
+- : "a" (addr), "a" (_ni_bitmap + (nr & 7)),
+- "m" (*(char *) addr) : "cc" );
++ asm volatile(
++ " nc 0(1,%1),0(%2)"
++ : "=m" (*(char *) addr) : "a" (addr),
++ "a" (_ni_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc");
+ }
+
+ static inline void
+@@ -291,40 +297,7 @@ __constant_clear_bit(const unsigned long
+ unsigned long addr;
+
+ addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+- switch (nr&7) {
+- case 0:
+- asm volatile ("ni 0(%1),0xFE" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 1:
+- asm volatile ("ni 0(%1),0xFD": "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 2:
+- asm volatile ("ni 0(%1),0xFB" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 3:
+- asm volatile ("ni 0(%1),0xF7" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 4:
+- asm volatile ("ni 0(%1),0xEF" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 5:
+- asm volatile ("ni 0(%1),0xDF" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 6:
+- asm volatile ("ni 0(%1),0xBF" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 7:
+- asm volatile ("ni 0(%1),0x7F" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- }
++ *(unsigned char *) addr &= ~(1 << (nr & 7));
+ }
+
+ #define clear_bit_simple(nr,addr) \
+@@ -340,10 +313,10 @@ static inline void __change_bit(unsigned
+ unsigned long addr;
+
+ addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+- asm volatile("xc 0(1,%1),0(%2)"
+- : "=m" (*(char *) addr)
+- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
+- "m" (*(char *) addr) : "cc" );
++ asm volatile(
++ " xc 0(1,%1),0(%2)"
++ : "=m" (*(char *) addr) : "a" (addr),
++ "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" );
+ }
+
+ static inline void
+@@ -352,40 +325,7 @@ __constant_change_bit(const unsigned lon
+ unsigned long addr;
+
+ addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+- switch (nr&7) {
+- case 0:
+- asm volatile ("xi 0(%1),0x01" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 1:
+- asm volatile ("xi 0(%1),0x02" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 2:
+- asm volatile ("xi 0(%1),0x04" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 3:
+- asm volatile ("xi 0(%1),0x08" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 4:
+- asm volatile ("xi 0(%1),0x10" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 5:
+- asm volatile ("xi 0(%1),0x20" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 6:
+- asm volatile ("xi 0(%1),0x40" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- case 7:
+- asm volatile ("xi 0(%1),0x80" : "=m" (*(char *) addr)
+- : "a" (addr), "m" (*(char *) addr) : "cc" );
+- break;
+- }
++ *(unsigned char *) addr ^= 1 << (nr & 7);
+ }
+
+ #define change_bit_simple(nr,addr) \
+@@ -404,10 +344,11 @@ test_and_set_bit_simple(unsigned long nr
+
+ addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ ch = *(unsigned char *) addr;
+- asm volatile("oc 0(1,%1),0(%2)"
+- : "=m" (*(char *) addr)
+- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
+- "m" (*(char *) addr) : "cc", "memory" );
++ asm volatile(
++ " oc 0(1,%1),0(%2)"
++ : "=m" (*(char *) addr)
++ : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
++ "m" (*(char *) addr) : "cc", "memory");
+ return (ch >> (nr & 7)) & 1;
+ }
+ #define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y)
+@@ -423,10 +364,11 @@ test_and_clear_bit_simple(unsigned long
+
+ addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ ch = *(unsigned char *) addr;
+- asm volatile("nc 0(1,%1),0(%2)"
+- : "=m" (*(char *) addr)
+- : "a" (addr), "a" (_ni_bitmap + (nr & 7)),
+- "m" (*(char *) addr) : "cc", "memory" );
++ asm volatile(
++ " nc 0(1,%1),0(%2)"
++ : "=m" (*(char *) addr)
++ : "a" (addr), "a" (_ni_bitmap + (nr & 7)),
++ "m" (*(char *) addr) : "cc", "memory");
+ return (ch >> (nr & 7)) & 1;
+ }
+ #define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y)
+@@ -442,10 +384,11 @@ test_and_change_bit_simple(unsigned long
+
+ addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ ch = *(unsigned char *) addr;
+- asm volatile("xc 0(1,%1),0(%2)"
+- : "=m" (*(char *) addr)
+- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
+- "m" (*(char *) addr) : "cc", "memory" );
++ asm volatile(
++ " xc 0(1,%1),0(%2)"
++ : "=m" (*(char *) addr)
++ : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
++ "m" (*(char *) addr) : "cc", "memory");
+ return (ch >> (nr & 7)) & 1;
+ }
+ #define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y)
+@@ -557,35 +500,36 @@ find_first_zero_bit(const unsigned long
+
+ if (!size)
+ return 0;
+- __asm__(" lhi %1,-1\n"
+- " lr %2,%3\n"
+- " slr %0,%0\n"
+- " ahi %2,31\n"
+- " srl %2,5\n"
+- "0: c %1,0(%0,%4)\n"
+- " jne 1f\n"
+- " la %0,4(%0)\n"
+- " brct %2,0b\n"
+- " lr %0,%3\n"
+- " j 4f\n"
+- "1: l %2,0(%0,%4)\n"
+- " sll %0,3\n"
+- " lhi %1,0xff\n"
+- " tml %2,0xffff\n"
+- " jno 2f\n"
+- " ahi %0,16\n"
+- " srl %2,16\n"
+- "2: tml %2,0x00ff\n"
+- " jno 3f\n"
+- " ahi %0,8\n"
+- " srl %2,8\n"
+- "3: nr %2,%1\n"
+- " ic %2,0(%2,%5)\n"
+- " alr %0,%2\n"
+- "4:"
+- : "=&a" (res), "=&d" (cmp), "=&a" (count)
+- : "a" (size), "a" (addr), "a" (&_zb_findmap),
+- "m" (*(addrtype *) addr) : "cc" );
++ asm volatile(
++ " lhi %1,-1\n"
++ " lr %2,%3\n"
++ " slr %0,%0\n"
++ " ahi %2,31\n"
++ " srl %2,5\n"
++ "0: c %1,0(%0,%4)\n"
++ " jne 1f\n"
++ " la %0,4(%0)\n"
++ " brct %2,0b\n"
++ " lr %0,%3\n"
++ " j 4f\n"
++ "1: l %2,0(%0,%4)\n"
++ " sll %0,3\n"
++ " lhi %1,0xff\n"
++ " tml %2,0xffff\n"
++ " jno 2f\n"
++ " ahi %0,16\n"
++ " srl %2,16\n"
++ "2: tml %2,0x00ff\n"
++ " jno 3f\n"
++ " ahi %0,8\n"
++ " srl %2,8\n"
++ "3: nr %2,%1\n"
++ " ic %2,0(%2,%5)\n"
++ " alr %0,%2\n"
++ "4:"
++ : "=&a" (res), "=&d" (cmp), "=&a" (count)
++ : "a" (size), "a" (addr), "a" (&_zb_findmap),
++ "m" (*(addrtype *) addr) : "cc");
+ return (res < size) ? res : size;
+ }
+
+@@ -598,35 +542,36 @@ find_first_bit(const unsigned long * add
+
+ if (!size)
+ return 0;
+- __asm__(" slr %1,%1\n"
+- " lr %2,%3\n"
+- " slr %0,%0\n"
+- " ahi %2,31\n"
+- " srl %2,5\n"
+- "0: c %1,0(%0,%4)\n"
+- " jne 1f\n"
+- " la %0,4(%0)\n"
+- " brct %2,0b\n"
+- " lr %0,%3\n"
+- " j 4f\n"
+- "1: l %2,0(%0,%4)\n"
+- " sll %0,3\n"
+- " lhi %1,0xff\n"
+- " tml %2,0xffff\n"
+- " jnz 2f\n"
+- " ahi %0,16\n"
+- " srl %2,16\n"
+- "2: tml %2,0x00ff\n"
+- " jnz 3f\n"
+- " ahi %0,8\n"
+- " srl %2,8\n"
+- "3: nr %2,%1\n"
+- " ic %2,0(%2,%5)\n"
+- " alr %0,%2\n"
+- "4:"
+- : "=&a" (res), "=&d" (cmp), "=&a" (count)
+- : "a" (size), "a" (addr), "a" (&_sb_findmap),
+- "m" (*(addrtype *) addr) : "cc" );
++ asm volatile(
++ " slr %1,%1\n"
++ " lr %2,%3\n"
++ " slr %0,%0\n"
++ " ahi %2,31\n"
++ " srl %2,5\n"
++ "0: c %1,0(%0,%4)\n"
++ " jne 1f\n"
++ " la %0,4(%0)\n"
++ " brct %2,0b\n"
++ " lr %0,%3\n"
++ " j 4f\n"
++ "1: l %2,0(%0,%4)\n"
++ " sll %0,3\n"
++ " lhi %1,0xff\n"
++ " tml %2,0xffff\n"
++ " jnz 2f\n"
++ " ahi %0,16\n"
++ " srl %2,16\n"
++ "2: tml %2,0x00ff\n"
++ " jnz 3f\n"
++ " ahi %0,8\n"
++ " srl %2,8\n"
++ "3: nr %2,%1\n"
++ " ic %2,0(%2,%5)\n"
++ " alr %0,%2\n"
++ "4:"
++ : "=&a" (res), "=&d" (cmp), "=&a" (count)
++ : "a" (size), "a" (addr), "a" (&_sb_findmap),
++ "m" (*(addrtype *) addr) : "cc");
+ return (res < size) ? res : size;
+ }
+
+@@ -640,39 +585,40 @@ find_first_zero_bit(const unsigned long
+
+ if (!size)
+ return 0;
+- __asm__(" lghi %1,-1\n"
+- " lgr %2,%3\n"
+- " slgr %0,%0\n"
+- " aghi %2,63\n"
+- " srlg %2,%2,6\n"
+- "0: cg %1,0(%0,%4)\n"
+- " jne 1f\n"
+- " la %0,8(%0)\n"
+- " brct %2,0b\n"
+- " lgr %0,%3\n"
+- " j 5f\n"
+- "1: lg %2,0(%0,%4)\n"
+- " sllg %0,%0,3\n"
+- " clr %2,%1\n"
+- " jne 2f\n"
+- " aghi %0,32\n"
+- " srlg %2,%2,32\n"
+- "2: lghi %1,0xff\n"
+- " tmll %2,0xffff\n"
+- " jno 3f\n"
+- " aghi %0,16\n"
+- " srl %2,16\n"
+- "3: tmll %2,0x00ff\n"
+- " jno 4f\n"
+- " aghi %0,8\n"
+- " srl %2,8\n"
+- "4: ngr %2,%1\n"
+- " ic %2,0(%2,%5)\n"
+- " algr %0,%2\n"
+- "5:"
+- : "=&a" (res), "=&d" (cmp), "=&a" (count)
++ asm volatile(
++ " lghi %1,-1\n"
++ " lgr %2,%3\n"
++ " slgr %0,%0\n"
++ " aghi %2,63\n"
++ " srlg %2,%2,6\n"
++ "0: cg %1,0(%0,%4)\n"
++ " jne 1f\n"
++ " la %0,8(%0)\n"
++ " brct %2,0b\n"
++ " lgr %0,%3\n"
++ " j 5f\n"
++ "1: lg %2,0(%0,%4)\n"
++ " sllg %0,%0,3\n"
++ " clr %2,%1\n"
++ " jne 2f\n"
++ " aghi %0,32\n"
++ " srlg %2,%2,32\n"
++ "2: lghi %1,0xff\n"
++ " tmll %2,0xffff\n"
++ " jno 3f\n"
++ " aghi %0,16\n"
++ " srl %2,16\n"
++ "3: tmll %2,0x00ff\n"
++ " jno 4f\n"
++ " aghi %0,8\n"
++ " srl %2,8\n"
++ "4: ngr %2,%1\n"
++ " ic %2,0(%2,%5)\n"
++ " algr %0,%2\n"
++ "5:"
++ : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ : "a" (size), "a" (addr), "a" (&_zb_findmap),
+- "m" (*(addrtype *) addr) : "cc" );
++ "m" (*(addrtype *) addr) : "cc");
+ return (res < size) ? res : size;
+ }
+
+@@ -684,39 +630,40 @@ find_first_bit(const unsigned long * add
+
+ if (!size)
+ return 0;
+- __asm__(" slgr %1,%1\n"
+- " lgr %2,%3\n"
+- " slgr %0,%0\n"
+- " aghi %2,63\n"
+- " srlg %2,%2,6\n"
+- "0: cg %1,0(%0,%4)\n"
+- " jne 1f\n"
+- " aghi %0,8\n"
+- " brct %2,0b\n"
+- " lgr %0,%3\n"
+- " j 5f\n"
+- "1: lg %2,0(%0,%4)\n"
+- " sllg %0,%0,3\n"
+- " clr %2,%1\n"
+- " jne 2f\n"
+- " aghi %0,32\n"
+- " srlg %2,%2,32\n"
+- "2: lghi %1,0xff\n"
+- " tmll %2,0xffff\n"
+- " jnz 3f\n"
+- " aghi %0,16\n"
+- " srl %2,16\n"
+- "3: tmll %2,0x00ff\n"
+- " jnz 4f\n"
+- " aghi %0,8\n"
+- " srl %2,8\n"
+- "4: ngr %2,%1\n"
+- " ic %2,0(%2,%5)\n"
+- " algr %0,%2\n"
+- "5:"
+- : "=&a" (res), "=&d" (cmp), "=&a" (count)
++ asm volatile(
++ " slgr %1,%1\n"
++ " lgr %2,%3\n"
++ " slgr %0,%0\n"
++ " aghi %2,63\n"
++ " srlg %2,%2,6\n"
++ "0: cg %1,0(%0,%4)\n"
++ " jne 1f\n"
++ " aghi %0,8\n"
++ " brct %2,0b\n"
++ " lgr %0,%3\n"
++ " j 5f\n"
++ "1: lg %2,0(%0,%4)\n"
++ " sllg %0,%0,3\n"
++ " clr %2,%1\n"
++ " jne 2f\n"
++ " aghi %0,32\n"
++ " srlg %2,%2,32\n"
++ "2: lghi %1,0xff\n"
++ " tmll %2,0xffff\n"
++ " jnz 3f\n"
++ " aghi %0,16\n"
++ " srl %2,16\n"
++ "3: tmll %2,0x00ff\n"
++ " jnz 4f\n"
++ " aghi %0,8\n"
++ " srl %2,8\n"
++ "4: ngr %2,%1\n"
++ " ic %2,0(%2,%5)\n"
++ " algr %0,%2\n"
++ "5:"
++ : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ : "a" (size), "a" (addr), "a" (&_sb_findmap),
+- "m" (*(addrtype *) addr) : "cc" );
++ "m" (*(addrtype *) addr) : "cc");
+ return (res < size) ? res : size;
+ }
+
+@@ -832,36 +779,37 @@ ext2_find_first_zero_bit(void *vaddr, un
+
+ if (!size)
+ return 0;
+- __asm__(" lhi %1,-1\n"
+- " lr %2,%3\n"
+- " ahi %2,31\n"
+- " srl %2,5\n"
+- " slr %0,%0\n"
+- "0: cl %1,0(%0,%4)\n"
+- " jne 1f\n"
+- " ahi %0,4\n"
+- " brct %2,0b\n"
+- " lr %0,%3\n"
+- " j 4f\n"
+- "1: l %2,0(%0,%4)\n"
+- " sll %0,3\n"
+- " ahi %0,24\n"
+- " lhi %1,0xff\n"
+- " tmh %2,0xffff\n"
+- " jo 2f\n"
+- " ahi %0,-16\n"
+- " srl %2,16\n"
+- "2: tml %2,0xff00\n"
+- " jo 3f\n"
+- " ahi %0,-8\n"
+- " srl %2,8\n"
+- "3: nr %2,%1\n"
+- " ic %2,0(%2,%5)\n"
+- " alr %0,%2\n"
+- "4:"
+- : "=&a" (res), "=&d" (cmp), "=&a" (count)
+- : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
+- "m" (*(addrtype *) vaddr) : "cc" );
++ asm volatile(
++ " lhi %1,-1\n"
++ " lr %2,%3\n"
++ " ahi %2,31\n"
++ " srl %2,5\n"
++ " slr %0,%0\n"
++ "0: cl %1,0(%0,%4)\n"
++ " jne 1f\n"
++ " ahi %0,4\n"
++ " brct %2,0b\n"
++ " lr %0,%3\n"
++ " j 4f\n"
++ "1: l %2,0(%0,%4)\n"
++ " sll %0,3\n"
++ " ahi %0,24\n"
++ " lhi %1,0xff\n"
++ " tmh %2,0xffff\n"
++ " jo 2f\n"
++ " ahi %0,-16\n"
++ " srl %2,16\n"
++ "2: tml %2,0xff00\n"
++ " jo 3f\n"
++ " ahi %0,-8\n"
++ " srl %2,8\n"
++ "3: nr %2,%1\n"
++ " ic %2,0(%2,%5)\n"
++ " alr %0,%2\n"
++ "4:"
++ : "=&a" (res), "=&d" (cmp), "=&a" (count)
++ : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
++ "m" (*(addrtype *) vaddr) : "cc");
+ return (res < size) ? res : size;
+ }
+
+@@ -875,39 +823,40 @@ ext2_find_first_zero_bit(void *vaddr, un
+
+ if (!size)
+ return 0;
+- __asm__(" lghi %1,-1\n"
+- " lgr %2,%3\n"
+- " aghi %2,63\n"
+- " srlg %2,%2,6\n"
+- " slgr %0,%0\n"
+- "0: clg %1,0(%0,%4)\n"
+- " jne 1f\n"
+- " aghi %0,8\n"
+- " brct %2,0b\n"
+- " lgr %0,%3\n"
+- " j 5f\n"
+- "1: cl %1,0(%0,%4)\n"
+- " jne 2f\n"
+- " aghi %0,4\n"
+- "2: l %2,0(%0,%4)\n"
+- " sllg %0,%0,3\n"
+- " aghi %0,24\n"
+- " lghi %1,0xff\n"
+- " tmlh %2,0xffff\n"
+- " jo 3f\n"
+- " aghi %0,-16\n"
+- " srl %2,16\n"
+- "3: tmll %2,0xff00\n"
+- " jo 4f\n"
+- " aghi %0,-8\n"
+- " srl %2,8\n"
+- "4: ngr %2,%1\n"
+- " ic %2,0(%2,%5)\n"
+- " algr %0,%2\n"
+- "5:"
+- : "=&a" (res), "=&d" (cmp), "=&a" (count)
++ asm volatile(
++ " lghi %1,-1\n"
++ " lgr %2,%3\n"
++ " aghi %2,63\n"
++ " srlg %2,%2,6\n"
++ " slgr %0,%0\n"
++ "0: clg %1,0(%0,%4)\n"
++ " jne 1f\n"
++ " aghi %0,8\n"
++ " brct %2,0b\n"
++ " lgr %0,%3\n"
++ " j 5f\n"
++ "1: cl %1,0(%0,%4)\n"
++ " jne 2f\n"
++ " aghi %0,4\n"
++ "2: l %2,0(%0,%4)\n"
++ " sllg %0,%0,3\n"
++ " aghi %0,24\n"
++ " lghi %1,0xff\n"
++ " tmlh %2,0xffff\n"
++ " jo 3f\n"
++ " aghi %0,-16\n"
++ " srl %2,16\n"
++ "3: tmll %2,0xff00\n"
++ " jo 4f\n"
++ " aghi %0,-8\n"
++ " srl %2,8\n"
++ "4: ngr %2,%1\n"
++ " ic %2,0(%2,%5)\n"
++ " algr %0,%2\n"
++ "5:"
++ : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
+- "m" (*(addrtype *) vaddr) : "cc" );
++ "m" (*(addrtype *) vaddr) : "cc");
+ return (res < size) ? res : size;
+ }
+
+@@ -927,13 +876,16 @@ ext2_find_next_zero_bit(void *vaddr, uns
+ p = addr + offset / __BITOPS_WORDSIZE;
+ if (bit) {
+ #ifndef __s390x__
+- asm(" ic %0,0(%1)\n"
+- " icm %0,2,1(%1)\n"
+- " icm %0,4,2(%1)\n"
+- " icm %0,8,3(%1)"
+- : "=&a" (word) : "a" (p), "m" (*p) : "cc" );
++ asm volatile(
++ " ic %0,0(%1)\n"
++ " icm %0,2,1(%1)\n"
++ " icm %0,4,2(%1)\n"
++ " icm %0,8,3(%1)"
++ : "=&a" (word) : "a" (p), "m" (*p) : "cc");
+ #else
+- asm(" lrvg %0,%1" : "=a" (word) : "m" (*p) );
++ asm volatile(
++ " lrvg %0,%1"
++ : "=a" (word) : "m" (*p) );
+ #endif
+ /*
+ * s390 version of ffz returns __BITOPS_WORDSIZE
+diff --git a/include/asm-s390/byteorder.h b/include/asm-s390/byteorder.h
+index 2cc35a0..1fe2492 100644
+--- a/include/asm-s390/byteorder.h
++++ b/include/asm-s390/byteorder.h
+@@ -14,60 +14,54 @@
+ #ifdef __GNUC__
+
+ #ifdef __s390x__
+-static __inline__ __u64 ___arch__swab64p(const __u64 *x)
++static inline __u64 ___arch__swab64p(const __u64 *x)
+ {
+ __u64 result;
+
+- __asm__ __volatile__ (
+- " lrvg %0,%1"
+- : "=d" (result) : "m" (*x) );
++ asm volatile("lrvg %0,%1" : "=d" (result) : "m" (*x));
+ return result;
+ }
+
+-static __inline__ __u64 ___arch__swab64(__u64 x)
++static inline __u64 ___arch__swab64(__u64 x)
+ {
+ __u64 result;
+
+- __asm__ __volatile__ (
+- " lrvgr %0,%1"
+- : "=d" (result) : "d" (x) );
++ asm volatile("lrvgr %0,%1" : "=d" (result) : "d" (x));
+ return result;
+ }
+
+-static __inline__ void ___arch__swab64s(__u64 *x)
++static inline void ___arch__swab64s(__u64 *x)
+ {
+ *x = ___arch__swab64p(x);
+ }
+ #endif /* __s390x__ */
+
+-static __inline__ __u32 ___arch__swab32p(const __u32 *x)
++static inline __u32 ___arch__swab32p(const __u32 *x)
+ {
+ __u32 result;
+
+- __asm__ __volatile__ (
++ asm volatile(
+ #ifndef __s390x__
+- " icm %0,8,3(%1)\n"
+- " icm %0,4,2(%1)\n"
+- " icm %0,2,1(%1)\n"
+- " ic %0,0(%1)"
+- : "=&d" (result) : "a" (x), "m" (*x) : "cc" );
++ " icm %0,8,3(%1)\n"
++ " icm %0,4,2(%1)\n"
++ " icm %0,2,1(%1)\n"
++ " ic %0,0(%1)"
++ : "=&d" (result) : "a" (x), "m" (*x) : "cc");
+ #else /* __s390x__ */
+- " lrv %0,%1"
+- : "=d" (result) : "m" (*x) );
++ " lrv %0,%1"
++ : "=d" (result) : "m" (*x));
+ #endif /* __s390x__ */
+ return result;
+ }
+
+-static __inline__ __u32 ___arch__swab32(__u32 x)
++static inline __u32 ___arch__swab32(__u32 x)
+ {
+ #ifndef __s390x__
+ return ___arch__swab32p(&x);
+ #else /* __s390x__ */
+ __u32 result;
+
+- __asm__ __volatile__ (
+- " lrvr %0,%1"
+- : "=d" (result) : "d" (x) );
++ asm volatile("lrvr %0,%1" : "=d" (result) : "d" (x));
+ return result;
+ #endif /* __s390x__ */
+ }
+@@ -81,14 +75,14 @@ static __inline__ __u16 ___arch__swab16p
+ {
+ __u16 result;
+
+- __asm__ __volatile__ (
++ asm volatile(
+ #ifndef __s390x__
+- " icm %0,2,1(%1)\n"
+- " ic %0,0(%1)\n"
+- : "=&d" (result) : "a" (x), "m" (*x) : "cc" );
++ " icm %0,2,1(%1)\n"
++ " ic %0,0(%1)\n"
++ : "=&d" (result) : "a" (x), "m" (*x) : "cc");
+ #else /* __s390x__ */
+- " lrvh %0,%1"
+- : "=d" (result) : "m" (*x) );
++ " lrvh %0,%1"
++ : "=d" (result) : "m" (*x));
+ #endif /* __s390x__ */
+ return result;
+ }
+diff --git a/include/asm-s390/checksum.h b/include/asm-s390/checksum.h
+index 471f2af..37c362d 100644
+--- a/include/asm-s390/checksum.h
++++ b/include/asm-s390/checksum.h
+@@ -30,57 +30,13 @@
+ static inline unsigned int
+ csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ {
+- /*
+- * Experiments with ethernet and slip connections show that buf
+- * is aligned on either a 2-byte or 4-byte boundary.
+- */
+-#ifndef __s390x__
+- register_pair rp;
+-
+- rp.subreg.even = (unsigned long) buff;
+- rp.subreg.odd = (unsigned long) len;
+- __asm__ __volatile__ (
+- "0: cksm %0,%1\n" /* do checksum on longs */
+- " jo 0b\n"
+- : "+&d" (sum), "+&a" (rp) : : "cc", "memory" );
+-#else /* __s390x__ */
+- __asm__ __volatile__ (
+- " lgr 2,%1\n" /* address in gpr 2 */
+- " lgfr 3,%2\n" /* length in gpr 3 */
+- "0: cksm %0,2\n" /* do checksum on longs */
+- " jo 0b\n"
+- : "+&d" (sum)
+- : "d" (buff), "d" (len)
+- : "cc", "memory", "2", "3" );
+-#endif /* __s390x__ */
+- return sum;
+-}
+-
+-/*
+- * csum_partial as an inline function
+- */
+-static inline unsigned int
+-csum_partial_inline(const unsigned char * buff, int len, unsigned int sum)
+-{
+-#ifndef __s390x__
+- register_pair rp;
++ register unsigned long reg2 asm("2") = (unsigned long) buff;
++ register unsigned long reg3 asm("3") = (unsigned long) len;
+
+- rp.subreg.even = (unsigned long) buff;
+- rp.subreg.odd = (unsigned long) len;
+- __asm__ __volatile__ (
+- "0: cksm %0,%1\n" /* do checksum on longs */
+- " jo 0b\n"
+- : "+&d" (sum), "+&a" (rp) : : "cc", "memory" );
+-#else /* __s390x__ */
+- __asm__ __volatile__ (
+- " lgr 2,%1\n" /* address in gpr 2 */
+- " lgfr 3,%2\n" /* length in gpr 3 */
+- "0: cksm %0,2\n" /* do checksum on longs */
+- " jo 0b\n"
+- : "+&d" (sum)
+- : "d" (buff), "d" (len)
+- : "cc", "memory", "2", "3" );
+-#endif /* __s390x__ */
++ asm volatile(
++ "0: cksm %0,%1\n" /* do checksum on longs */
++ " jo 0b\n"
++ : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory");
+ return sum;
+ }
+
+@@ -114,7 +70,7 @@ static inline unsigned int
+ csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
+ {
+ memcpy(dst,src,len);
+- return csum_partial_inline(dst, len, sum);
++ return csum_partial(dst, len, sum);
+ }
+
+ /*
+@@ -126,22 +82,22 @@ csum_fold(unsigned int sum)
+ #ifndef __s390x__
+ register_pair rp;
+
+- __asm__ __volatile__ (
+- " slr %N1,%N1\n" /* %0 = H L */
+- " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */
+- " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */
+- " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */
+- " alr %0,%1\n" /* %0 = H+L+C L+H */
+- " srl %0,16\n" /* %0 = H+L+C */
+- : "+&d" (sum), "=d" (rp) : : "cc" );
++ asm volatile(
++ " slr %N1,%N1\n" /* %0 = H L */
++ " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */
++ " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */
++ " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */
++ " alr %0,%1\n" /* %0 = H+L+C L+H */
++ " srl %0,16\n" /* %0 = H+L+C */
++ : "+&d" (sum), "=d" (rp) : : "cc");
+ #else /* __s390x__ */
+- __asm__ __volatile__ (
+- " sr 3,3\n" /* %0 = H*65536 + L */
+- " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */
+- " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */
+- " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */
+- " alr %0,2\n" /* %0 = H+L+C L+H */
+- " srl %0,16\n" /* %0 = H+L+C */
++ asm volatile(
++ " sr 3,3\n" /* %0 = H*65536 + L */
++ " lr 2,%0\n" /* %0 = H L, 2/3 = H L / 0 0 */
++ " srdl 2,16\n" /* %0 = H L, 2/3 = 0 H / L 0 */
++ " alr 2,3\n" /* %0 = H L, 2/3 = L H / L 0 */
++ " alr %0,2\n" /* %0 = H+L+C L+H */
++ " srl %0,16\n" /* %0 = H+L+C */
+ : "+&d" (sum) : : "cc", "2", "3");
+ #endif /* __s390x__ */
+ return ((unsigned short) ~sum);
+@@ -155,29 +111,7 @@ csum_fold(unsigned int sum)
+ static inline unsigned short
+ ip_fast_csum(unsigned char *iph, unsigned int ihl)
+ {
+- unsigned long sum;
+-#ifndef __s390x__
+- register_pair rp;
+-
+- rp.subreg.even = (unsigned long) iph;
+- rp.subreg.odd = (unsigned long) ihl*4;
+- __asm__ __volatile__ (
+- " sr %0,%0\n" /* set sum to zero */
+- "0: cksm %0,%1\n" /* do checksum on longs */
+- " jo 0b\n"
+- : "=&d" (sum), "+&a" (rp) : : "cc", "memory" );
+-#else /* __s390x__ */
+- __asm__ __volatile__ (
+- " slgr %0,%0\n" /* set sum to zero */
+- " lgr 2,%1\n" /* address in gpr 2 */
+- " lgfr 3,%2\n" /* length in gpr 3 */
+- "0: cksm %0,2\n" /* do checksum on ints */
+- " jo 0b\n"
+- : "=&d" (sum)
+- : "d" (iph), "d" (ihl*4)
+- : "cc", "memory", "2", "3" );
+-#endif /* __s390x__ */
+- return csum_fold(sum);
++ return csum_fold(csum_partial(iph, ihl*4, 0));
+ }
+
+ /*
+@@ -190,47 +124,47 @@ csum_tcpudp_nofold(unsigned long saddr,
+ unsigned int sum)
+ {
+ #ifndef __s390x__
+- __asm__ __volatile__ (
+- " alr %0,%1\n" /* sum += saddr */
+- " brc 12,0f\n"
+- " ahi %0,1\n" /* add carry */
++ asm volatile(
++ " alr %0,%1\n" /* sum += saddr */
++ " brc 12,0f\n"
++ " ahi %0,1\n" /* add carry */
+ "0:"
+- : "+&d" (sum) : "d" (saddr) : "cc" );
+- __asm__ __volatile__ (
+- " alr %0,%1\n" /* sum += daddr */
+- " brc 12,1f\n"
+- " ahi %0,1\n" /* add carry */
++ : "+&d" (sum) : "d" (saddr) : "cc");
++ asm volatile(
++ " alr %0,%1\n" /* sum += daddr */
++ " brc 12,1f\n"
++ " ahi %0,1\n" /* add carry */
+ "1:"
+- : "+&d" (sum) : "d" (daddr) : "cc" );
+- __asm__ __volatile__ (
+- " alr %0,%1\n" /* sum += (len<<16) + (proto<<8) */
+- " brc 12,2f\n"
+- " ahi %0,1\n" /* add carry */
++ : "+&d" (sum) : "d" (daddr) : "cc");
++ asm volatile(
++ " alr %0,%1\n" /* sum += (len<<16) + (proto<<8) */
++ " brc 12,2f\n"
++ " ahi %0,1\n" /* add carry */
+ "2:"
+ : "+&d" (sum)
+ : "d" (((unsigned int) len<<16) + (unsigned int) proto)
+- : "cc" );
++ : "cc");
+ #else /* __s390x__ */
+- __asm__ __volatile__ (
+- " lgfr %0,%0\n"
+- " algr %0,%1\n" /* sum += saddr */
+- " brc 12,0f\n"
+- " aghi %0,1\n" /* add carry */
+- "0: algr %0,%2\n" /* sum += daddr */
+- " brc 12,1f\n"
+- " aghi %0,1\n" /* add carry */
+- "1: algfr %0,%3\n" /* sum += (len<<16) + proto */
+- " brc 12,2f\n"
+- " aghi %0,1\n" /* add carry */
+- "2: srlg 0,%0,32\n"
+- " alr %0,0\n" /* fold to 32 bits */
+- " brc 12,3f\n"
+- " ahi %0,1\n" /* add carry */
+- "3: llgfr %0,%0"
++ asm volatile(
++ " lgfr %0,%0\n"
++ " algr %0,%1\n" /* sum += saddr */
++ " brc 12,0f\n"
++ " aghi %0,1\n" /* add carry */
++ "0: algr %0,%2\n" /* sum += daddr */
++ " brc 12,1f\n"
++ " aghi %0,1\n" /* add carry */
++ "1: algfr %0,%3\n" /* sum += (len<<16) + proto */
++ " brc 12,2f\n"
++ " aghi %0,1\n" /* add carry */
++ "2: srlg 0,%0,32\n"
++ " alr %0,0\n" /* fold to 32 bits */
++ " brc 12,3f\n"
++ " ahi %0,1\n" /* add carry */
++ "3: llgfr %0,%0"
+ : "+&d" (sum)
+ : "d" (saddr), "d" (daddr),
+ "d" (((unsigned int) len<<16) + (unsigned int) proto)
+- : "cc", "0" );
++ : "cc", "0");
+ #endif /* __s390x__ */
+ return sum;
+ }
+diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
+index 28fdd6e..81287d8 100644
+--- a/include/asm-s390/cio.h
++++ b/include/asm-s390/cio.h
+@@ -270,6 +270,17 @@ struct diag210 {
+ __u32 vrdccrft : 8; /* real device feature (output) */
+ } __attribute__ ((packed,aligned(4)));
+
++struct ccw_dev_id {
++ u8 ssid;
++ u16 devno;
++};
++
++static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
++ struct ccw_dev_id *dev_id2)
++{
++ return !memcmp(dev_id1, dev_id2, sizeof(struct ccw_dev_id));
++}
++
+ extern int diag210(struct diag210 *addr);
+
+ extern void wait_cons_dev(void);
+@@ -280,6 +291,8 @@ extern void cio_reset_channel_paths(void
+
+ extern void css_schedule_reprobe(void);
+
++extern void reipl_ccw_dev(struct ccw_dev_id *id);
++
+ #endif
+
+ #endif
+diff --git a/include/asm-s390/div64.h b/include/asm-s390/div64.h
+index af098dc..6cd978c 100644
+--- a/include/asm-s390/div64.h
++++ b/include/asm-s390/div64.h
+@@ -1,49 +1 @@
+-#ifndef __S390_DIV64
+-#define __S390_DIV64
+-
+-#ifndef __s390x__
+-
+-/* for do_div "base" needs to be smaller than 2^31-1 */
+-#define do_div(n, base) ({ \
+- unsigned long long __n = (n); \
+- unsigned long __r; \
+- \
+- asm (" slr 0,0\n" \
+- " l 1,%1\n" \
+- " srdl 0,1\n" \
+- " dr 0,%2\n" \
+- " alr 1,1\n" \
+- " alr 0,0\n" \
+- " lhi 2,1\n" \
+- " n 2,%1\n" \
+- " alr 0,2\n" \
+- " clr 0,%2\n" \
+- " jl 0f\n" \
+- " slr 0,%2\n" \
+- " ahi 1,1\n" \
+- "0: st 1,%1\n" \
+- " l 1,4+%1\n" \
+- " srdl 0,1\n" \
+- " dr 0,%2\n" \
+- " alr 1,1\n" \
+- " alr 0,0\n" \
+- " lhi 2,1\n" \
+- " n 2,4+%1\n" \
+- " alr 0,2\n" \
+- " clr 0,%2\n" \
+- " jl 1f\n" \
+- " slr 0,%2\n" \
+- " ahi 1,1\n" \
+- "1: st 1,4+%1\n" \
+- " lr %0,0" \
+- : "=d" (__r), "=m" (__n) \
+- : "d" (base), "m" (__n) : "0", "1", "2", "cc" ); \
+- (n) = (__n); \
+- __r; \
+-})
+-
+-#else /* __s390x__ */
+ #include <asm-generic/div64.h>
+-#endif /* __s390x__ */
+-
+-#endif
+diff --git a/include/asm-s390/dma.h b/include/asm-s390/dma.h
+index 02720c4..7425c6a 100644
+--- a/include/asm-s390/dma.h
++++ b/include/asm-s390/dma.h
+@@ -11,6 +11,6 @@
+
+ #define MAX_DMA_ADDRESS 0x80000000
+
+-#define free_dma(x)
++#define free_dma(x) do { } while (0)
+
+ #endif /* _ASM_DMA_H */
+diff --git a/include/asm-s390/ebcdic.h b/include/asm-s390/ebcdic.h
+index 15fd2ed..7f6f641 100644
+--- a/include/asm-s390/ebcdic.h
++++ b/include/asm-s390/ebcdic.h
+@@ -26,16 +26,16 @@ codepage_convert(const __u8 *codepage, v
+ {
+ if (nr-- <= 0)
+ return;
+- __asm__ __volatile__(
+- " bras 1,1f\n"
+- " tr 0(1,%0),0(%2)\n"
+- "0: tr 0(256,%0),0(%2)\n"
+- " la %0,256(%0)\n"
+- "1: ahi %1,-256\n"
+- " jnm 0b\n"
+- " ex %1,0(1)"
+- : "+&a" (addr), "+&a" (nr)
+- : "a" (codepage) : "cc", "memory", "1" );
++ asm volatile(
++ " bras 1,1f\n"
++ " tr 0(1,%0),0(%2)\n"
++ "0: tr 0(256,%0),0(%2)\n"
++ " la %0,256(%0)\n"
++ "1: ahi %1,-256\n"
++ " jnm 0b\n"
++ " ex %1,0(1)"
++ : "+&a" (addr), "+&a" (nr)
++ : "a" (codepage) : "cc", "memory", "1");
+ }
+
+ #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr)
+diff --git a/include/asm-s390/futex.h b/include/asm-s390/futex.h
+index ffedf14..5e261e1 100644
+--- a/include/asm-s390/futex.h
++++ b/include/asm-s390/futex.h
+@@ -7,75 +7,21 @@
+ #include <asm/errno.h>
+ #include <asm/uaccess.h>
+
+-#ifndef __s390x__
+-#define __futex_atomic_fixup \
+- ".section __ex_table,\"a\"\n" \
+- " .align 4\n" \
+- " .long 0b,4b,2b,4b,3b,4b\n" \
+- ".previous"
+-#else /* __s390x__ */
+-#define __futex_atomic_fixup \
+- ".section __ex_table,\"a\"\n" \
+- " .align 8\n" \
+- " .quad 0b,4b,2b,4b,3b,4b\n" \
+- ".previous"
+-#endif /* __s390x__ */
+-
+-#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
+- asm volatile(" sacf 256\n" \
+- "0: l %1,0(%6)\n" \
+- "1: " insn \
+- "2: cs %1,%2,0(%6)\n" \
+- "3: jl 1b\n" \
+- " lhi %0,0\n" \
+- "4: sacf 0\n" \
+- __futex_atomic_fixup \
+- : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
+- "=m" (*uaddr) \
+- : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
+- "m" (*uaddr) : "cc" );
+-
+ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+ {
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+- int oldval = 0, newval, ret;
++ int oldval, ret;
++
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+- inc_preempt_count();
+-
+- switch (op) {
+- case FUTEX_OP_SET:
+- __futex_atomic_op("lr %2,%5\n",
+- ret, oldval, newval, uaddr, oparg);
+- break;
+- case FUTEX_OP_ADD:
+- __futex_atomic_op("lr %2,%1\nar %2,%5\n",
+- ret, oldval, newval, uaddr, oparg);
+- break;
+- case FUTEX_OP_OR:
+- __futex_atomic_op("lr %2,%1\nor %2,%5\n",
+- ret, oldval, newval, uaddr, oparg);
+- break;
+- case FUTEX_OP_ANDN:
+- __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+- ret, oldval, newval, uaddr, oparg);
+- break;
+- case FUTEX_OP_XOR:
+- __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+- ret, oldval, newval, uaddr, oparg);
+- break;
+- default:
+- ret = -ENOSYS;
+- }
+-
+- dec_preempt_count();
++ ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval);
+
+ if (!ret) {
+ switch (cmp) {
+@@ -91,32 +37,13 @@ static inline int futex_atomic_op_inuser
+ return ret;
+ }
+
+-static inline int
+-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
++static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
++ int oldval, int newval)
+ {
+- int ret;
+-
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+- asm volatile(" sacf 256\n"
+- " cs %1,%4,0(%5)\n"
+- "0: lr %0,%1\n"
+- "1: sacf 0\n"
+-#ifndef __s390x__
+- ".section __ex_table,\"a\"\n"
+- " .align 4\n"
+- " .long 0b,1b\n"
+- ".previous"
+-#else /* __s390x__ */
+- ".section __ex_table,\"a\"\n"
+- " .align 8\n"
+- " .quad 0b,1b\n"
+- ".previous"
+-#endif /* __s390x__ */
+- : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+- : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+- : "cc", "memory" );
+- return oldval;
++
++ return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
+ }
+
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
+index e84b7ef..c2f6a87 100644
+--- a/include/asm-s390/hardirq.h
++++ b/include/asm-s390/hardirq.h
+@@ -32,6 +32,6 @@ typedef struct {
+
+ #define HARDIRQ_BITS 8
+
+-extern void account_ticks(struct pt_regs *);
++extern void account_ticks(void);
+
+ #endif /* __ASM_HARDIRQ_H */
+diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
+index d4614b3..efb7de9 100644
+--- a/include/asm-s390/io.h
++++ b/include/asm-s390/io.h
+@@ -27,18 +27,16 @@
+ static inline unsigned long virt_to_phys(volatile void * address)
+ {
+ unsigned long real_address;
+- __asm__ (
++ asm volatile(
+ #ifndef __s390x__
+- " lra %0,0(%1)\n"
+- " jz 0f\n"
+- " sr %0,%0\n"
++ " lra %0,0(%1)\n"
+ #else /* __s390x__ */
+- " lrag %0,0(%1)\n"
+- " jz 0f\n"
+- " slgr %0,%0\n"
++ " lrag %0,0(%1)\n"
+ #endif /* __s390x__ */
++ " jz 0f\n"
++ " la %0,0\n"
+ "0:"
+- : "=a" (real_address) : "a" (address) : "cc" );
++ : "=a" (real_address) : "a" (address) : "cc");
+ return real_address;
+ }
+
+@@ -47,11 +45,6 @@ static inline void * phys_to_virt(unsign
+ return __io_virt(address);
+ }
+
+-/*
+- * Change "struct page" to physical address.
+- */
+-#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
+-
+ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+ static inline void * ioremap (unsigned long offset, unsigned long size)
+@@ -116,7 +109,7 @@ extern void iounmap(void *addr);
+ #define outb(x,addr) ((void) writeb(x,addr))
+ #define outb_p(x,addr) outb(x,addr)
+
+-#define mmiowb()
++#define mmiowb() do { } while (0)
+
+ /*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h
+index bd1a721..7da991a 100644
+--- a/include/asm-s390/irq.h
++++ b/include/asm-s390/irq.h
+@@ -19,8 +19,5 @@ enum interruption_class {
+ NR_IRQS,
+ };
+
+-#define touch_nmi_watchdog() do { } while(0)
+-
+ #endif /* __KERNEL__ */
+ #endif
+-
+diff --git a/include/asm-s390/irq_regs.h b/include/asm-s390/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-s390/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-s390/irqflags.h b/include/asm-s390/irqflags.h
+index 3b566a5..3f26131 100644
+--- a/include/asm-s390/irqflags.h
++++ b/include/asm-s390/irqflags.h
+@@ -10,43 +10,93 @@
+
+ #ifdef __KERNEL__
+
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++
++/* store then or system mask. */
++#define __raw_local_irq_stosm(__or) \
++({ \
++ unsigned long __mask; \
++ asm volatile( \
++ " stosm %0,%1" \
++ : "=Q" (__mask) : "i" (__or) : "memory"); \
++ __mask; \
++})
++
++/* store then and system mask. */
++#define __raw_local_irq_stnsm(__and) \
++({ \
++ unsigned long __mask; \
++ asm volatile( \
++ " stnsm %0,%1" \
++ : "=Q" (__mask) : "i" (__and) : "memory"); \
++ __mask; \
++})
++
++/* set system mask. */
++#define __raw_local_irq_ssm(__mask) \
++({ \
++ asm volatile("ssm %0" : : "Q" (__mask) : "memory"); \
++})
++
++#else /* __GNUC__ */
++
++/* store then or system mask. */
++#define __raw_local_irq_stosm(__or) \
++({ \
++ unsigned long __mask; \
++ asm volatile( \
++ " stosm 0(%1),%2" \
++ : "=m" (__mask) \
++ : "a" (&__mask), "i" (__or) : "memory"); \
++ __mask; \
++})
++
++/* store then and system mask. */
++#define __raw_local_irq_stnsm(__and) \
++({ \
++ unsigned long __mask; \
++ asm volatile( \
++ " stnsm 0(%1),%2" \
++ : "=m" (__mask) \
++ : "a" (&__mask), "i" (__and) : "memory"); \
++ __mask; \
++})
++
++/* set system mask. */
++#define __raw_local_irq_ssm(__mask) \
++({ \
++ asm volatile( \
++ " ssm 0(%0)" \
++ : : "a" (&__mask), "m" (__mask) : "memory"); \
++})
++
++#endif /* __GNUC__ */
++
+ /* interrupt control.. */
+-#define raw_local_irq_enable() ({ \
+- unsigned long __dummy; \
+- __asm__ __volatile__ ( \
+- "stosm 0(%1),0x03" \
+- : "=m" (__dummy) : "a" (&__dummy) : "memory" ); \
+- })
+-
+-#define raw_local_irq_disable() ({ \
+- unsigned long __flags; \
+- __asm__ __volatile__ ( \
+- "stnsm 0(%1),0xfc" : "=m" (__flags) : "a" (&__flags) ); \
+- __flags; \
+- })
+-
+-#define raw_local_save_flags(x) \
+-do { \
+- typecheck(unsigned long, x); \
+- __asm__ __volatile__("stosm 0(%1),0" : "=m" (x) : "a" (&x), "m" (x) ); \
+-} while (0)
++static inline unsigned long raw_local_irq_enable(void)
++{
++ return __raw_local_irq_stosm(0x03);
++}
+
+-#define raw_local_irq_restore(x) \
+-do { \
+- typecheck(unsigned long, x); \
+- __asm__ __volatile__("ssm 0(%0)" : : "a" (&x), "m" (x) : "memory"); \
++static inline unsigned long raw_local_irq_disable(void)
++{
++ return __raw_local_irq_stnsm(0xfc);
++}
++
++#define raw_local_save_flags(x) \
++do { \
++ typecheck(unsigned long, x); \
++ (x) = __raw_local_irq_stosm(0x00); \
+ } while (0)
+
+-#define raw_irqs_disabled() \
+-({ \
+- unsigned long flags; \
+- raw_local_save_flags(flags); \
+- !((flags >> __FLAG_SHIFT) & 3); \
+-})
++static inline void raw_local_irq_restore(unsigned long flags)
++{
++ __raw_local_irq_ssm(flags);
++}
+
+ static inline int raw_irqs_disabled_flags(unsigned long flags)
+ {
+- return !((flags >> __FLAG_SHIFT) & 3);
++ return !(flags & (3UL << (BITS_PER_LONG - 8)));
+ }
+
+ /* For spinlocks etc */
+diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h
+new file mode 100644
+index 0000000..40cc680
+--- /dev/null
++++ b/include/asm-s390/kdebug.h
+@@ -0,0 +1,59 @@
++#ifndef _S390_KDEBUG_H
++#define _S390_KDEBUG_H
++
++/*
++ * Feb 2006 Ported to s390 <grundym at us.ibm.com>
++ */
++#include <linux/notifier.h>
++
++struct pt_regs;
++
++struct die_args {
++ struct pt_regs *regs;
++ const char *str;
++ long err;
++ int trapnr;
++ int signr;
++};
++
++/* Note - you should never unregister because that can race with NMIs.
++ * If you really want to do it first unregister - then synchronize_sched
++ * - then free.
++ */
++extern int register_die_notifier(struct notifier_block *);
++extern int unregister_die_notifier(struct notifier_block *);
++extern int register_page_fault_notifier(struct notifier_block *);
++extern int unregister_page_fault_notifier(struct notifier_block *);
++extern struct atomic_notifier_head s390die_chain;
++
++
++enum die_val {
++ DIE_OOPS = 1,
++ DIE_BPT,
++ DIE_SSTEP,
++ DIE_PANIC,
++ DIE_NMI,
++ DIE_DIE,
++ DIE_NMIWATCHDOG,
++ DIE_KERNELDEBUG,
++ DIE_TRAP,
++ DIE_GPF,
++ DIE_CALL,
++ DIE_NMI_IPI,
++ DIE_PAGE_FAULT,
++};
++
++static inline int notify_die(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ struct die_args args = {
++ .regs = regs,
++ .str = str,
++ .err = err,
++ .trapnr = trap,
++ .signr = sig
++ };
++ return atomic_notifier_call_chain(&s390die_chain, val, &args);
++}
++
++#endif
+diff --git a/include/asm-s390/kprobes.h b/include/asm-s390/kprobes.h
+new file mode 100644
+index 0000000..b847ff0
+--- /dev/null
++++ b/include/asm-s390/kprobes.h
+@@ -0,0 +1,114 @@
++#ifndef _ASM_S390_KPROBES_H
++#define _ASM_S390_KPROBES_H
++/*
++ * Kernel Probes (KProbes)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) IBM Corporation, 2002, 2006
++ *
++ * 2002-Oct Created by Vamsi Krishna S <vamsi_krishna at in.ibm.com> Kernel
++ * Probes initial implementation ( includes suggestions from
++ * Rusty Russell).
++ * 2004-Nov Modified for PPC64 by Ananth N Mavinakayanahalli
++ * <ananth at in.ibm.com>
++ * 2005-Dec Used as a template for s390 by Mike Grundy
++ * <grundym at us.ibm.com>
++ */
++#include <linux/types.h>
++#include <linux/ptrace.h>
++#include <linux/percpu.h>
++
++#define __ARCH_WANT_KPROBES_INSN_SLOT
++struct pt_regs;
++struct kprobe;
++
++typedef u16 kprobe_opcode_t;
++#define BREAKPOINT_INSTRUCTION 0x0002
++
++/* Maximum instruction size is 3 (16bit) halfwords: */
++#define MAX_INSN_SIZE 0x0003
++#define MAX_STACK_SIZE 64
++#define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
++ (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) \
++ ? (MAX_STACK_SIZE) \
++ : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
++
++#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)(pentry)
++
++#define ARCH_SUPPORTS_KRETPROBES
++#define ARCH_INACTIVE_KPROBE_COUNT 0
++
++#define KPROBE_SWAP_INST 0x10
++
++#define FIXUP_PSW_NORMAL 0x08
++#define FIXUP_BRANCH_NOT_TAKEN 0x04
++#define FIXUP_RETURN_REGISTER 0x02
++#define FIXUP_NOT_REQUIRED 0x01
++
++/* Architecture specific copy of original instruction */
++struct arch_specific_insn {
++ /* copy of original instruction */
++ kprobe_opcode_t *insn;
++ int fixup;
++ int ilen;
++ int reg;
++};
++
++struct ins_replace_args {
++ kprobe_opcode_t *ptr;
++ kprobe_opcode_t old;
++ kprobe_opcode_t new;
++};
++struct prev_kprobe {
++ struct kprobe *kp;
++ unsigned long status;
++ unsigned long saved_psw;
++ unsigned long kprobe_saved_imask;
++ unsigned long kprobe_saved_ctl[3];
++};
++
++/* per-cpu kprobe control block */
++struct kprobe_ctlblk {
++ unsigned long kprobe_status;
++ unsigned long kprobe_saved_imask;
++ unsigned long kprobe_saved_ctl[3];
++ struct pt_regs jprobe_saved_regs;
++ unsigned long jprobe_saved_r14;
++ unsigned long jprobe_saved_r15;
++ struct prev_kprobe prev_kprobe;
++ kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
++};
++
++void arch_remove_kprobe(struct kprobe *p);
++void kretprobe_trampoline(void);
++int is_prohibited_opcode(kprobe_opcode_t *instruction);
++void get_instruction_type(struct arch_specific_insn *ainsn);
++
++#define flush_insn_slot(p) do { } while (0)
++
++#endif /* _ASM_S390_KPROBES_H */
++
++#ifdef CONFIG_KPROBES
++
++extern int kprobe_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data);
++#else /* !CONFIG_KPROBES */
++static inline int kprobe_exceptions_notify(struct notifier_block *self,
++ unsigned long val, void *data)
++{
++ return 0;
++}
++#endif
+diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
+index 596c8b1..06583ed 100644
+--- a/include/asm-s390/lowcore.h
++++ b/include/asm-s390/lowcore.h
+@@ -35,6 +35,7 @@
+ #define __LC_IO_NEW_PSW 0x01f0
+ #endif /* !__s390x__ */
+
++#define __LC_IPL_PARMBLOCK_PTR 0x014
+ #define __LC_EXT_PARAMS 0x080
+ #define __LC_CPU_ADDRESS 0x084
+ #define __LC_EXT_INT_CODE 0x086
+@@ -47,6 +48,7 @@
+ #define __LC_PER_ATMID 0x096
+ #define __LC_PER_ADDRESS 0x098
+ #define __LC_PER_ACCESS_ID 0x0A1
++#define __LC_AR_MODE_ID 0x0A3
+
+ #define __LC_SUBCHANNEL_ID 0x0B8
+ #define __LC_SUBCHANNEL_NR 0x0BA
+@@ -106,18 +108,28 @@
+ #define __LC_INT_CLOCK 0xDE8
+ #endif /* __s390x__ */
+
+-#define __LC_PANIC_MAGIC 0xE00
+
++#define __LC_PANIC_MAGIC 0xE00
+ #ifndef __s390x__
+ #define __LC_PFAULT_INTPARM 0x080
+ #define __LC_CPU_TIMER_SAVE_AREA 0x0D8
++#define __LC_CLOCK_COMP_SAVE_AREA 0x0E0
++#define __LC_PSW_SAVE_AREA 0x100
++#define __LC_PREFIX_SAVE_AREA 0x108
+ #define __LC_AREGS_SAVE_AREA 0x120
++#define __LC_FPREGS_SAVE_AREA 0x160
+ #define __LC_GPREGS_SAVE_AREA 0x180
+ #define __LC_CREGS_SAVE_AREA 0x1C0
+ #else /* __s390x__ */
+ #define __LC_PFAULT_INTPARM 0x11B8
++#define __LC_FPREGS_SAVE_AREA 0x1200
+ #define __LC_GPREGS_SAVE_AREA 0x1280
++#define __LC_PSW_SAVE_AREA 0x1300
++#define __LC_PREFIX_SAVE_AREA 0x1318
++#define __LC_FP_CREG_SAVE_AREA 0x131C
++#define __LC_TODREG_SAVE_AREA 0x1324
+ #define __LC_CPU_TIMER_SAVE_AREA 0x1328
++#define __LC_CLOCK_COMP_SAVE_AREA 0x1331
+ #define __LC_AREGS_SAVE_AREA 0x1340
+ #define __LC_CREGS_SAVE_AREA 0x1380
+ #endif /* __s390x__ */
+@@ -347,7 +359,7 @@ extern struct _lowcore *lowcore_ptr[];
+
+ static inline void set_prefix(__u32 address)
+ {
+- __asm__ __volatile__ ("spx %0" : : "m" (address) : "memory" );
++ asm volatile("spx %0" : : "m" (address) : "memory");
+ }
+
+ #define __PANIC_MAGIC 0xDEADC0DE
+diff --git a/include/asm-s390/monwriter.h b/include/asm-s390/monwriter.h
+new file mode 100644
+index 0000000..f0cbf96
+--- /dev/null
++++ b/include/asm-s390/monwriter.h
+@@ -0,0 +1,33 @@
++/*
++ * include/asm-s390/monwriter.h
++ *
++ * Copyright (C) IBM Corp. 2006
++ * Character device driver for writing z/VM APPLDATA monitor records
++ * Version 1.0
++ * Author(s): Melissa Howland <melissah at us.ibm.com>
++ *
++ */
++
++#ifndef _ASM_390_MONWRITER_H
++#define _ASM_390_MONWRITER_H
++
++/* mon_function values */
++#define MONWRITE_START_INTERVAL 0x00 /* start interval recording */
++#define MONWRITE_STOP_INTERVAL 0x01 /* stop interval or config recording */
++#define MONWRITE_GEN_EVENT 0x02 /* generate event record */
++#define MONWRITE_START_CONFIG 0x03 /* start configuration recording */
++
++/* the header the app uses in its write() data */
++struct monwrite_hdr {
++ unsigned char mon_function;
++ unsigned short applid;
++ unsigned char record_num;
++ unsigned short version;
++ unsigned short release;
++ unsigned short mod_level;
++ unsigned short datalen;
++ unsigned char hdrlen;
++
++} __attribute__((packed));
++
++#endif /* _ASM_390_MONWRITER_H */
+diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
+index b2628dc..363ea76 100644
+--- a/include/asm-s390/page.h
++++ b/include/asm-s390/page.h
+@@ -22,89 +22,45 @@
+ #include <asm/setup.h>
+ #ifndef __ASSEMBLY__
+
+-#ifndef __s390x__
+-
+-static inline void clear_page(void *page)
+-{
+- register_pair rp;
+-
+- rp.subreg.even = (unsigned long) page;
+- rp.subreg.odd = (unsigned long) 4096;
+- asm volatile (" slr 1,1\n"
+- " mvcl %0,0"
+- : "+&a" (rp) : : "memory", "cc", "1" );
+-}
+-
+-static inline void copy_page(void *to, void *from)
+-{
+- if (MACHINE_HAS_MVPG)
+- asm volatile (" sr 0,0\n"
+- " mvpg %0,%1"
+- : : "a" ((void *)(to)), "a" ((void *)(from))
+- : "memory", "cc", "0" );
+- else
+- asm volatile (" mvc 0(256,%0),0(%1)\n"
+- " mvc 256(256,%0),256(%1)\n"
+- " mvc 512(256,%0),512(%1)\n"
+- " mvc 768(256,%0),768(%1)\n"
+- " mvc 1024(256,%0),1024(%1)\n"
+- " mvc 1280(256,%0),1280(%1)\n"
+- " mvc 1536(256,%0),1536(%1)\n"
+- " mvc 1792(256,%0),1792(%1)\n"
+- " mvc 2048(256,%0),2048(%1)\n"
+- " mvc 2304(256,%0),2304(%1)\n"
+- " mvc 2560(256,%0),2560(%1)\n"
+- " mvc 2816(256,%0),2816(%1)\n"
+- " mvc 3072(256,%0),3072(%1)\n"
+- " mvc 3328(256,%0),3328(%1)\n"
+- " mvc 3584(256,%0),3584(%1)\n"
+- " mvc 3840(256,%0),3840(%1)\n"
+- : : "a"((void *)(to)),"a"((void *)(from))
+- : "memory" );
+-}
+-
+-#else /* __s390x__ */
+-
+ static inline void clear_page(void *page)
+ {
+- asm volatile (" lgr 2,%0\n"
+- " lghi 3,4096\n"
+- " slgr 1,1\n"
+- " mvcl 2,0"
+- : : "a" ((void *) (page))
+- : "memory", "cc", "1", "2", "3" );
++ register unsigned long reg1 asm ("1") = 0;
++ register void *reg2 asm ("2") = page;
++ register unsigned long reg3 asm ("3") = 4096;
++ asm volatile(
++ " mvcl 2,0"
++ : "+d" (reg2), "+d" (reg3) : "d" (reg1) : "memory", "cc");
+ }
+
+ static inline void copy_page(void *to, void *from)
+ {
+- if (MACHINE_HAS_MVPG)
+- asm volatile (" sgr 0,0\n"
+- " mvpg %0,%1"
+- : : "a" ((void *)(to)), "a" ((void *)(from))
+- : "memory", "cc", "0" );
+- else
+- asm volatile (" mvc 0(256,%0),0(%1)\n"
+- " mvc 256(256,%0),256(%1)\n"
+- " mvc 512(256,%0),512(%1)\n"
+- " mvc 768(256,%0),768(%1)\n"
+- " mvc 1024(256,%0),1024(%1)\n"
+- " mvc 1280(256,%0),1280(%1)\n"
+- " mvc 1536(256,%0),1536(%1)\n"
+- " mvc 1792(256,%0),1792(%1)\n"
+- " mvc 2048(256,%0),2048(%1)\n"
+- " mvc 2304(256,%0),2304(%1)\n"
+- " mvc 2560(256,%0),2560(%1)\n"
+- " mvc 2816(256,%0),2816(%1)\n"
+- " mvc 3072(256,%0),3072(%1)\n"
+- " mvc 3328(256,%0),3328(%1)\n"
+- " mvc 3584(256,%0),3584(%1)\n"
+- " mvc 3840(256,%0),3840(%1)\n"
+- : : "a"((void *)(to)),"a"((void *)(from))
+- : "memory" );
++ if (MACHINE_HAS_MVPG) {
++ register unsigned long reg0 asm ("0") = 0;
++ asm volatile(
++ " mvpg %0,%1"
++ : : "a" (to), "a" (from), "d" (reg0)
++ : "memory", "cc");
++ } else
++ asm volatile(
++ " mvc 0(256,%0),0(%1)\n"
++ " mvc 256(256,%0),256(%1)\n"
++ " mvc 512(256,%0),512(%1)\n"
++ " mvc 768(256,%0),768(%1)\n"
++ " mvc 1024(256,%0),1024(%1)\n"
++ " mvc 1280(256,%0),1280(%1)\n"
++ " mvc 1536(256,%0),1536(%1)\n"
++ " mvc 1792(256,%0),1792(%1)\n"
++ " mvc 2048(256,%0),2048(%1)\n"
++ " mvc 2304(256,%0),2304(%1)\n"
++ " mvc 2560(256,%0),2560(%1)\n"
++ " mvc 2816(256,%0),2816(%1)\n"
++ " mvc 3072(256,%0),3072(%1)\n"
++ " mvc 3328(256,%0),3328(%1)\n"
++ " mvc 3584(256,%0),3584(%1)\n"
++ " mvc 3840(256,%0),3840(%1)\n"
++ : : "a" (to), "a" (from) : "memory");
+ }
+
+-#endif /* __s390x__ */
+-
+ #define clear_user_page(page, vaddr, pg) clear_page(page)
+ #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
+
+@@ -159,7 +115,7 @@ extern unsigned int default_storage_key;
+ static inline void
+ page_set_storage_key(unsigned long addr, unsigned int skey)
+ {
+- asm volatile ( "sske %0,%1" : : "d" (skey), "a" (addr) );
++ asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
+ }
+
+ static inline unsigned int
+@@ -167,8 +123,7 @@ page_get_storage_key(unsigned long addr)
+ {
+ unsigned int skey;
+
+- asm volatile ( "iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0) );
+-
++ asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0));
+ return skey;
+ }
+
+@@ -182,6 +137,7 @@ page_get_storage_key(unsigned long addr)
+ #define __pa(x) (unsigned long)(x)
+ #define __va(x) (void *)(unsigned long)(x)
+ #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
++#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+
+ #define pfn_valid(pfn) ((pfn) < max_mapnr)
+ #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
+index 28b3517..9ea7f10 100644
+--- a/include/asm-s390/percpu.h
++++ b/include/asm-s390/percpu.h
+@@ -15,18 +15,20 @@
+ */
+ #if defined(__s390x__) && defined(MODULE)
+
+-#define __reloc_hide(var,offset) \
+- (*({ unsigned long *__ptr; \
+- asm ( "larl %0,per_cpu__"#var"@GOTENT" \
+- : "=a" (__ptr) : "X" (per_cpu__##var) ); \
+- (typeof(&per_cpu__##var))((*__ptr) + (offset)); }))
++#define __reloc_hide(var,offset) (*({ \
++ extern int simple_identifier_##var(void); \
++ unsigned long *__ptr; \
++ asm ( "larl %0,per_cpu__"#var"@GOTENT" \
++ : "=a" (__ptr) : "X" (per_cpu__##var) ); \
++ (typeof(&per_cpu__##var))((*__ptr) + (offset)); }))
+
+ #else
+
+-#define __reloc_hide(var, offset) \
+- (*({ unsigned long __ptr; \
+- asm ( "" : "=a" (__ptr) : "0" (&per_cpu__##var) ); \
+- (typeof(&per_cpu__##var)) (__ptr + (offset)); }))
++#define __reloc_hide(var, offset) (*({ \
++ extern int simple_identifier_##var(void); \
++ unsigned long __ptr; \
++ asm ( "" : "=a" (__ptr) : "0" (&per_cpu__##var) ); \
++ (typeof(&per_cpu__##var)) (__ptr + (offset)); }))
+
+ #endif
+
+diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
+index a78e853..28619de 100644
+--- a/include/asm-s390/pgalloc.h
++++ b/include/asm-s390/pgalloc.h
+@@ -22,6 +22,16 @@
+ extern void diag10(unsigned long addr);
+
+ /*
++ * Page allocation orders.
++ */
++#ifndef __s390x__
++# define PGD_ALLOC_ORDER 1
++#else /* __s390x__ */
++# define PMD_ALLOC_ORDER 2
++# define PGD_ALLOC_ORDER 2
++#endif /* __s390x__ */
++
++/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+@@ -29,30 +39,23 @@ extern void diag10(unsigned long addr);
+
+ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+ {
+- pgd_t *pgd;
++ pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER);
+ int i;
+
++ if (!pgd)
++ return NULL;
++ for (i = 0; i < PTRS_PER_PGD; i++)
+ #ifndef __s390x__
+- pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,1);
+- if (pgd != NULL)
+- for (i = 0; i < USER_PTRS_PER_PGD; i++)
+- pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
+-#else /* __s390x__ */
+- pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2);
+- if (pgd != NULL)
+- for (i = 0; i < PTRS_PER_PGD; i++)
+- pgd_clear(pgd + i);
+-#endif /* __s390x__ */
++ pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
++#else
++ pgd_clear(pgd + i);
++#endif
+ return pgd;
+ }
+
+ static inline void pgd_free(pgd_t *pgd)
+ {
+-#ifndef __s390x__
+- free_pages((unsigned long) pgd, 1);
+-#else /* __s390x__ */
+- free_pages((unsigned long) pgd, 2);
+-#endif /* __s390x__ */
++ free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
+ }
+
+ #ifndef __s390x__
+@@ -68,20 +71,19 @@ static inline void pgd_free(pgd_t *pgd)
+ #else /* __s390x__ */
+ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+ {
+- pmd_t *pmd;
+- int i;
++ pmd_t *pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER);
++ int i;
+
+- pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
+- if (pmd != NULL) {
+- for (i=0; i < PTRS_PER_PMD; i++)
+- pmd_clear(pmd+i);
+- }
++ if (!pmd)
++ return NULL;
++ for (i=0; i < PTRS_PER_PMD; i++)
++ pmd_clear(pmd + i);
+ return pmd;
+ }
+
+ static inline void pmd_free (pmd_t *pmd)
+ {
+- free_pages((unsigned long) pmd, 2);
++ free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
+ }
+
+ #define __pmd_free_tlb(tlb,pmd) \
+@@ -114,7 +116,7 @@ pmd_populate_kernel(struct mm_struct *mm
+ static inline void
+ pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
+ {
+- pmd_populate_kernel(mm, pmd, (pte_t *)((page-mem_map) << PAGE_SHIFT));
++ pmd_populate_kernel(mm, pmd, (pte_t *)page_to_phys(page));
+ }
+
+ /*
+@@ -123,15 +125,14 @@ pmd_populate(struct mm_struct *mm, pmd_t
+ static inline pte_t *
+ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
+ {
+- pte_t *pte;
+- int i;
+-
+- pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
+- if (pte != NULL) {
+- for (i=0; i < PTRS_PER_PTE; i++) {
+- pte_clear(mm, vmaddr, pte+i);
+- vmaddr += PAGE_SIZE;
+- }
++ pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL|__GFP_REPEAT);
++ int i;
++
++ if (!pte)
++ return NULL;
++ for (i=0; i < PTRS_PER_PTE; i++) {
++ pte_clear(mm, vmaddr, pte + i);
++ vmaddr += PAGE_SIZE;
+ }
+ return pte;
+ }
+diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
+index 2431238..36bb6da 100644
+--- a/include/asm-s390/pgtable.h
++++ b/include/asm-s390/pgtable.h
+@@ -31,9 +31,9 @@
+ * the S390 page table tree.
+ */
+ #ifndef __ASSEMBLY__
++#include <linux/mm_types.h>
+ #include <asm/bug.h>
+ #include <asm/processor.h>
+-#include <linux/threads.h>
+
+ struct vm_area_struct; /* forward declaration (include/linux/mm.h) */
+ struct mm_struct;
+@@ -89,19 +89,6 @@ extern char empty_zero_page[PAGE_SIZE];
+ # define PTRS_PER_PGD 2048
+ #endif /* __s390x__ */
+
+-/*
+- * pgd entries used up by user/kernel:
+- */
+-#ifndef __s390x__
+-# define USER_PTRS_PER_PGD 512
+-# define USER_PGD_PTRS 512
+-# define KERNEL_PGD_PTRS 512
+-#else /* __s390x__ */
+-# define USER_PTRS_PER_PGD 2048
+-# define USER_PGD_PTRS 2048
+-# define KERNEL_PGD_PTRS 2048
+-#endif /* __s390x__ */
+-
+ #define FIRST_USER_ADDRESS 0
+
+ #define pte_ERROR(e) \
+@@ -213,15 +200,44 @@ extern char empty_zero_page[PAGE_SIZE];
+ */
+
+ /* Hardware bits in the page table entry */
+-#define _PAGE_RO 0x200 /* HW read-only */
+-#define _PAGE_INVALID 0x400 /* HW invalid */
++#define _PAGE_RO 0x200 /* HW read-only bit */
++#define _PAGE_INVALID 0x400 /* HW invalid bit */
++#define _PAGE_SWT 0x001 /* SW pte type bit t */
++#define _PAGE_SWX 0x002 /* SW pte type bit x */
++
++/* Six different types of pages. */
++#define _PAGE_TYPE_EMPTY 0x400
++#define _PAGE_TYPE_NONE 0x401
++#define _PAGE_TYPE_SWAP 0x403
++#define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */
++#define _PAGE_TYPE_RO 0x200
++#define _PAGE_TYPE_RW 0x000
+
+-/* Mask and four different kinds of invalid pages. */
+-#define _PAGE_INVALID_MASK 0x601
+-#define _PAGE_INVALID_EMPTY 0x400
+-#define _PAGE_INVALID_NONE 0x401
+-#define _PAGE_INVALID_SWAP 0x600
+-#define _PAGE_INVALID_FILE 0x601
++/*
++ * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
++ * pte_none and pte_file to find out the pte type WITHOUT holding the page
++ * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to
++ * invalidate a given pte. ipte sets the hw invalid bit and clears all tlbs
++ * for the page. The page table entry is set to _PAGE_TYPE_EMPTY afterwards.
++ * This change is done while holding the lock, but the intermediate step
++ * of a previously valid pte with the hw invalid bit set can be observed by
++ * handle_pte_fault. That makes it necessary that all valid pte types with
++ * the hw invalid bit set must be distinguishable from the four pte types
++ * empty, none, swap and file.
++ *
++ * irxt ipte irxt
++ * _PAGE_TYPE_EMPTY 1000 -> 1000
++ * _PAGE_TYPE_NONE 1001 -> 1001
++ * _PAGE_TYPE_SWAP 1011 -> 1011
++ * _PAGE_TYPE_FILE 11?1 -> 11?1
++ * _PAGE_TYPE_RO 0100 -> 1100
++ * _PAGE_TYPE_RW 0000 -> 1000
++ *
++ * pte_none is true for bits combinations 1000, 1100
++ * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
++ * pte_file is true for bits combinations 1101, 1111
++ * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid.
++ */
+
+ #ifndef __s390x__
+
+@@ -280,15 +296,14 @@ extern char empty_zero_page[PAGE_SIZE];
+ #endif /* __s390x__ */
+
+ /*
+- * No mapping available
++ * Page protection definitions.
+ */
+-#define PAGE_NONE_SHARED __pgprot(_PAGE_INVALID_NONE)
+-#define PAGE_NONE_PRIVATE __pgprot(_PAGE_INVALID_NONE)
+-#define PAGE_RO_SHARED __pgprot(_PAGE_RO)
+-#define PAGE_RO_PRIVATE __pgprot(_PAGE_RO)
+-#define PAGE_COPY __pgprot(_PAGE_RO)
+-#define PAGE_SHARED __pgprot(0)
+-#define PAGE_KERNEL __pgprot(0)
++#define PAGE_NONE __pgprot(_PAGE_TYPE_NONE)
++#define PAGE_RO __pgprot(_PAGE_TYPE_RO)
++#define PAGE_RW __pgprot(_PAGE_TYPE_RW)
++
++#define PAGE_KERNEL PAGE_RW
++#define PAGE_COPY PAGE_RO
+
+ /*
+ * The S390 can't do page protection for execute, and considers that the
+@@ -296,23 +311,23 @@ extern char empty_zero_page[PAGE_SIZE];
+ * the closest we can get..
+ */
+ /*xwr*/
+-#define __P000 PAGE_NONE_PRIVATE
+-#define __P001 PAGE_RO_PRIVATE
+-#define __P010 PAGE_COPY
+-#define __P011 PAGE_COPY
+-#define __P100 PAGE_RO_PRIVATE
+-#define __P101 PAGE_RO_PRIVATE
+-#define __P110 PAGE_COPY
+-#define __P111 PAGE_COPY
+-
+-#define __S000 PAGE_NONE_SHARED
+-#define __S001 PAGE_RO_SHARED
+-#define __S010 PAGE_SHARED
+-#define __S011 PAGE_SHARED
+-#define __S100 PAGE_RO_SHARED
+-#define __S101 PAGE_RO_SHARED
+-#define __S110 PAGE_SHARED
+-#define __S111 PAGE_SHARED
++#define __P000 PAGE_NONE
++#define __P001 PAGE_RO
++#define __P010 PAGE_RO
++#define __P011 PAGE_RO
++#define __P100 PAGE_RO
++#define __P101 PAGE_RO
++#define __P110 PAGE_RO
++#define __P111 PAGE_RO
++
++#define __S000 PAGE_NONE
++#define __S001 PAGE_RO
++#define __S010 PAGE_RW
++#define __S011 PAGE_RW
++#define __S100 PAGE_RO
++#define __S101 PAGE_RO
++#define __S110 PAGE_RW
++#define __S111 PAGE_RW
+
+ /*
+ * Certain architectures need to do special things when PTEs
+@@ -377,18 +392,21 @@ static inline int pmd_bad(pmd_t pmd)
+
+ static inline int pte_none(pte_t pte)
+ {
+- return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_EMPTY;
++ return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
+ }
+
+ static inline int pte_present(pte_t pte)
+ {
+- return !(pte_val(pte) & _PAGE_INVALID) ||
+- (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_NONE;
++ unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT | _PAGE_SWX;
++ return (pte_val(pte) & mask) == _PAGE_TYPE_NONE ||
++ (!(pte_val(pte) & _PAGE_INVALID) &&
++ !(pte_val(pte) & _PAGE_SWT));
+ }
+
+ static inline int pte_file(pte_t pte)
+ {
+- return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_FILE;
++ unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT;
++ return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
+ }
+
+ #define pte_same(a,b) (pte_val(a) == pte_val(b))
+@@ -461,7 +479,7 @@ static inline void pmd_clear(pmd_t * pmd
+
+ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+ {
+- pte_val(*ptep) = _PAGE_INVALID_EMPTY;
++ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+ }
+
+ /*
+@@ -477,7 +495,7 @@ static inline pte_t pte_modify(pte_t pte
+
+ static inline pte_t pte_wrprotect(pte_t pte)
+ {
+- /* Do not clobber _PAGE_INVALID_NONE pages! */
++ /* Do not clobber _PAGE_TYPE_NONE pages! */
+ if (!(pte_val(pte) & _PAGE_INVALID))
+ pte_val(pte) |= _PAGE_RO;
+ return pte;
+@@ -556,26 +574,31 @@ static inline pte_t ptep_get_and_clear(s
+ return pte;
+ }
+
+-static inline pte_t
+-ptep_clear_flush(struct vm_area_struct *vma,
+- unsigned long address, pte_t *ptep)
++static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
+ {
+- pte_t pte = *ptep;
++ if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+ #ifndef __s390x__
+- if (!(pte_val(pte) & _PAGE_INVALID)) {
+ /* S390 has 1mb segments, we are emulating 4MB segments */
+ pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00);
+- __asm__ __volatile__ ("ipte %2,%3"
+- : "=m" (*ptep) : "m" (*ptep),
+- "a" (pto), "a" (address) );
++#else
++ /* ipte in zarch mode can do the math */
++ pte_t *pto = ptep;
++#endif
++ asm volatile(
++ " ipte %2,%3"
++ : "=m" (*ptep) : "m" (*ptep),
++ "a" (pto), "a" (address));
+ }
+-#else /* __s390x__ */
+- if (!(pte_val(pte) & _PAGE_INVALID))
+- __asm__ __volatile__ ("ipte %2,%3"
+- : "=m" (*ptep) : "m" (*ptep),
+- "a" (ptep), "a" (address) );
+-#endif /* __s390x__ */
+- pte_val(*ptep) = _PAGE_INVALID_EMPTY;
++ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
++}
++
++static inline pte_t
++ptep_clear_flush(struct vm_area_struct *vma,
++ unsigned long address, pte_t *ptep)
++{
++ pte_t pte = *ptep;
++
++ __ptep_ipte(address, ptep);
+ return pte;
+ }
+
+@@ -604,30 +627,31 @@ ptep_establish(struct vm_area_struct *vm
+ * should therefore only be called if it is not mapped in any
+ * address space.
+ */
+-#define page_test_and_clear_dirty(_page) \
+-({ \
+- struct page *__page = (_page); \
+- unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \
+- int __skey = page_get_storage_key(__physpage); \
+- if (__skey & _PAGE_CHANGED) \
+- page_set_storage_key(__physpage, __skey & ~_PAGE_CHANGED);\
+- (__skey & _PAGE_CHANGED); \
+-})
++static inline int page_test_and_clear_dirty(struct page *page)
++{
++ unsigned long physpage = page_to_phys(page);
++ int skey = page_get_storage_key(physpage);
++
++ if (skey & _PAGE_CHANGED)
++ page_set_storage_key(physpage, skey & ~_PAGE_CHANGED);
++ return skey & _PAGE_CHANGED;
++}
+
+ /*
+ * Test and clear referenced bit in storage key.
+ */
+-#define page_test_and_clear_young(page) \
+-({ \
+- struct page *__page = (page); \
+- unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \
+- int __ccode; \
+- asm volatile ("rrbe 0,%1\n\t" \
+- "ipm %0\n\t" \
+- "srl %0,28\n\t" \
+- : "=d" (__ccode) : "a" (__physpage) : "cc" ); \
+- (__ccode & 2); \
+-})
++static inline int page_test_and_clear_young(struct page *page)
++{
++ unsigned long physpage = page_to_phys(page);
++ int ccode;
++
++ asm volatile(
++ " rrbe 0,%1\n"
++ " ipm %0\n"
++ " srl %0,28\n"
++ : "=d" (ccode) : "a" (physpage) : "cc" );
++ return ccode & 2;
++}
+
+ /*
+ * Conversion functions: convert a page and protection to a page entry,
+@@ -640,43 +664,41 @@ static inline pte_t mk_pte_phys(unsigned
+ return __pte;
+ }
+
+-#define mk_pte(pg, pgprot) \
+-({ \
+- struct page *__page = (pg); \
+- pgprot_t __pgprot = (pgprot); \
+- unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \
+- pte_t __pte = mk_pte_phys(__physpage, __pgprot); \
+- __pte; \
+-})
++static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
++{
++ unsigned long physpage = page_to_phys(page);
++
++ return mk_pte_phys(physpage, pgprot);
++}
++
++static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
++{
++ unsigned long physpage = __pa((pfn) << PAGE_SHIFT);
+
+-#define pfn_pte(pfn, pgprot) \
+-({ \
+- pgprot_t __pgprot = (pgprot); \
+- unsigned long __physpage = __pa((pfn) << PAGE_SHIFT); \
+- pte_t __pte = mk_pte_phys(__physpage, __pgprot); \
+- __pte; \
+-})
++ return mk_pte_phys(physpage, pgprot);
++}
+
+ #ifdef __s390x__
+
+-#define pfn_pmd(pfn, pgprot) \
+-({ \
+- pgprot_t __pgprot = (pgprot); \
+- unsigned long __physpage = __pa((pfn) << PAGE_SHIFT); \
+- pmd_t __pmd = __pmd(__physpage + pgprot_val(__pgprot)); \
+- __pmd; \
+-})
++static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot)
++{
++ unsigned long physpage = __pa((pfn) << PAGE_SHIFT);
++
++ return __pmd(physpage + pgprot_val(pgprot));
++}
+
+ #endif /* __s390x__ */
+
+ #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
+ #define pte_page(x) pfn_to_page(pte_pfn(x))
+
+-#define pmd_page_kernel(pmd) (pmd_val(pmd) & PAGE_MASK)
++#define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK)
++
++#define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
+
+-#define pmd_page(pmd) (mem_map+(pmd_val(pmd) >> PAGE_SHIFT))
++#define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK)
+
+-#define pgd_page_kernel(pgd) (pgd_val(pgd) & PAGE_MASK)
++#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)
+
+ /* to find an entry in a page-table-directory */
+ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+@@ -698,14 +720,14 @@ static inline pmd_t * pmd_offset(pgd_t *
+ /* Find an entry in the second-level page table.. */
+ #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+ #define pmd_offset(dir,addr) \
+- ((pmd_t *) pgd_page_kernel(*(dir)) + pmd_index(addr))
++ ((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(addr))
+
+ #endif /* __s390x__ */
+
+ /* Find an entry in the third-level page table.. */
+ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
+ #define pte_offset_kernel(pmd, address) \
+- ((pte_t *) pmd_page_kernel(*(pmd)) + pte_index(address))
++ ((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address))
+ #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
+ #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
+ #define pte_unmap(pte) do { } while (0)
+@@ -755,7 +777,7 @@ static inline pte_t mk_swap_pte(unsigned
+ {
+ pte_t pte;
+ offset &= __SWP_OFFSET_MASK;
+- pte_val(pte) = _PAGE_INVALID_SWAP | ((type & 0x1f) << 2) |
++ pte_val(pte) = _PAGE_TYPE_SWAP | ((type & 0x1f) << 2) |
+ ((offset & 1UL) << 7) | ((offset & ~1UL) << 11);
+ return pte;
+ }
+@@ -778,7 +800,7 @@ static inline pte_t mk_swap_pte(unsigned
+
+ #define pgoff_to_pte(__off) \
+ ((pte_t) { ((((__off) & 0x7f) << 1) + (((__off) >> 7) << 12)) \
+- | _PAGE_INVALID_FILE })
++ | _PAGE_TYPE_FILE })
+
+ #endif /* !__ASSEMBLY__ */
+
+diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
+index 5b71d37..cbbedc6 100644
+--- a/include/asm-s390/processor.h
++++ b/include/asm-s390/processor.h
+@@ -13,7 +13,6 @@
+ #ifndef __ASM_S390_PROCESSOR_H
+ #define __ASM_S390_PROCESSOR_H
+
+-#include <asm/page.h>
+ #include <asm/ptrace.h>
+
+ #ifdef __KERNEL__
+@@ -21,7 +20,7 @@
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+-#define current_text_addr() ({ void *pc; __asm__("basr %0,0":"=a"(pc)); pc; })
++#define current_text_addr() ({ void *pc; asm("basr %0,0" : "=a" (pc)); pc; })
+
+ /*
+ * CPU type and hardware bug flags. Kept separately for each CPU.
+@@ -202,7 +201,7 @@ unsigned long get_wchan(struct task_stru
+ static inline void cpu_relax(void)
+ {
+ if (MACHINE_HAS_DIAG44)
+- asm volatile ("diag 0,0,68" : : : "memory");
++ asm volatile("diag 0,0,68" : : : "memory");
+ else
+ barrier();
+ }
+@@ -213,9 +212,9 @@ static inline void cpu_relax(void)
+ static inline void __load_psw(psw_t psw)
+ {
+ #ifndef __s390x__
+- asm volatile ("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
++ asm volatile("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc");
+ #else
+- asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
++ asm volatile("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc");
+ #endif
+ }
+
+@@ -232,20 +231,20 @@ static inline void __load_psw_mask (unsi
+ psw.mask = mask;
+
+ #ifndef __s390x__
+- asm volatile (
+- " basr %0,0\n"
+- "0: ahi %0,1f-0b\n"
+- " st %0,4(%1)\n"
+- " lpsw 0(%1)\n"
++ asm volatile(
++ " basr %0,0\n"
++ "0: ahi %0,1f-0b\n"
++ " st %0,4(%1)\n"
++ " lpsw 0(%1)\n"
+ "1:"
+- : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc" );
++ : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc");
+ #else /* __s390x__ */
+- asm volatile (
+- " larl %0,1f\n"
+- " stg %0,8(%1)\n"
+- " lpswe 0(%1)\n"
++ asm volatile(
++ " larl %0,1f\n"
++ " stg %0,8(%1)\n"
++ " lpswe 0(%1)\n"
+ "1:"
+- : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc" );
++ : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc");
+ #endif /* __s390x__ */
+ }
+
+@@ -274,56 +273,57 @@ static inline void disabled_wait(unsigne
+ * the processor is dead afterwards
+ */
+ #ifndef __s390x__
+- asm volatile (" stctl 0,0,0(%2)\n"
+- " ni 0(%2),0xef\n" /* switch off protection */
+- " lctl 0,0,0(%2)\n"
+- " stpt 0xd8\n" /* store timer */
+- " stckc 0xe0\n" /* store clock comparator */
+- " stpx 0x108\n" /* store prefix register */
+- " stam 0,15,0x120\n" /* store access registers */
+- " std 0,0x160\n" /* store f0 */
+- " std 2,0x168\n" /* store f2 */
+- " std 4,0x170\n" /* store f4 */
+- " std 6,0x178\n" /* store f6 */
+- " stm 0,15,0x180\n" /* store general registers */
+- " stctl 0,15,0x1c0\n" /* store control registers */
+- " oi 0x1c0,0x10\n" /* fake protection bit */
+- " lpsw 0(%1)"
+- : "=m" (ctl_buf)
+- : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
++ asm volatile(
++ " stctl 0,0,0(%2)\n"
++ " ni 0(%2),0xef\n" /* switch off protection */
++ " lctl 0,0,0(%2)\n"
++ " stpt 0xd8\n" /* store timer */
++ " stckc 0xe0\n" /* store clock comparator */
++ " stpx 0x108\n" /* store prefix register */
++ " stam 0,15,0x120\n" /* store access registers */
++ " std 0,0x160\n" /* store f0 */
++ " std 2,0x168\n" /* store f2 */
++ " std 4,0x170\n" /* store f4 */
++ " std 6,0x178\n" /* store f6 */
++ " stm 0,15,0x180\n" /* store general registers */
++ " stctl 0,15,0x1c0\n" /* store control registers */
++ " oi 0x1c0,0x10\n" /* fake protection bit */
++ " lpsw 0(%1)"
++ : "=m" (ctl_buf)
++ : "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 */
+- " lctlg 0,0,0(%2)\n"
+- " lghi 1,0x1000\n"
+- " stpt 0x328(1)\n" /* store timer */
+- " stckc 0x330(1)\n" /* store clock comparator */
+- " stpx 0x318(1)\n" /* store prefix register */
+- " stam 0,15,0x340(1)\n" /* store access registers */
+- " stfpc 0x31c(1)\n" /* store fpu control */
+- " std 0,0x200(1)\n" /* store f0 */
+- " std 1,0x208(1)\n" /* store f1 */
+- " std 2,0x210(1)\n" /* store f2 */
+- " std 3,0x218(1)\n" /* store f3 */
+- " std 4,0x220(1)\n" /* store f4 */
+- " std 5,0x228(1)\n" /* store f5 */
+- " std 6,0x230(1)\n" /* store f6 */
+- " std 7,0x238(1)\n" /* store f7 */
+- " std 8,0x240(1)\n" /* store f8 */
+- " std 9,0x248(1)\n" /* store f9 */
+- " std 10,0x250(1)\n" /* store f10 */
+- " std 11,0x258(1)\n" /* store f11 */
+- " std 12,0x260(1)\n" /* store f12 */
+- " std 13,0x268(1)\n" /* store f13 */
+- " std 14,0x270(1)\n" /* store f14 */
+- " std 15,0x278(1)\n" /* store f15 */
+- " stmg 0,15,0x280(1)\n" /* store general registers */
+- " stctg 0,15,0x380(1)\n" /* store control registers */
+- " oi 0x384(1),0x10\n" /* fake protection bit */
+- " lpswe 0(%1)"
+- : "=m" (ctl_buf)
+- : "a" (&dw_psw), "a" (&ctl_buf),
+- "m" (dw_psw) : "cc", "0", "1");
++ asm volatile(
++ " stctg 0,0,0(%2)\n"
++ " ni 4(%2),0xef\n" /* switch off protection */
++ " lctlg 0,0,0(%2)\n"
++ " lghi 1,0x1000\n"
++ " stpt 0x328(1)\n" /* store timer */
++ " stckc 0x330(1)\n" /* store clock comparator */
++ " stpx 0x318(1)\n" /* store prefix register */
++ " stam 0,15,0x340(1)\n"/* store access registers */
++ " stfpc 0x31c(1)\n" /* store fpu control */
++ " std 0,0x200(1)\n" /* store f0 */
++ " std 1,0x208(1)\n" /* store f1 */
++ " std 2,0x210(1)\n" /* store f2 */
++ " std 3,0x218(1)\n" /* store f3 */
++ " std 4,0x220(1)\n" /* store f4 */
++ " std 5,0x228(1)\n" /* store f5 */
++ " std 6,0x230(1)\n" /* store f6 */
++ " std 7,0x238(1)\n" /* store f7 */
++ " std 8,0x240(1)\n" /* store f8 */
++ " std 9,0x248(1)\n" /* store f9 */
++ " std 10,0x250(1)\n" /* store f10 */
++ " std 11,0x258(1)\n" /* store f11 */
++ " std 12,0x260(1)\n" /* store f12 */
++ " std 13,0x268(1)\n" /* store f13 */
++ " std 14,0x270(1)\n" /* store f14 */
++ " std 15,0x278(1)\n" /* store f15 */
++ " stmg 0,15,0x280(1)\n"/* store general registers */
++ " stctg 0,15,0x380(1)\n"/* store control registers */
++ " oi 0x384(1),0x10\n"/* fake protection bit */
++ " lpswe 0(%1)"
++ : "=m" (ctl_buf)
++ : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0");
+ #endif /* __s390x__ */
+ }
+
+@@ -337,6 +337,25 @@ struct notifier_block;
+ int register_idle_notifier(struct notifier_block *nb);
+ int unregister_idle_notifier(struct notifier_block *nb);
+
++#define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL
++
++#endif
++
++/*
++ * Helper macro for exception table entries
++ */
++#ifndef __s390x__
++#define EX_TABLE(_fault,_target) \
++ ".section __ex_table,\"a\"\n" \
++ " .align 4\n" \
++ " .long " #_fault "," #_target "\n" \
++ ".previous\n"
++#else
++#define EX_TABLE(_fault,_target) \
++ ".section __ex_table,\"a\"\n" \
++ " .align 8\n" \
++ " .quad " #_fault "," #_target "\n" \
++ ".previous\n"
+ #endif
+
+ #endif /* __ASM_S390_PROCESSOR_H */
+diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
+index 4d75d77..7b768c5 100644
+--- a/include/asm-s390/ptrace.h
++++ b/include/asm-s390/ptrace.h
+@@ -472,6 +472,7 @@ struct user_regs_struct
+
+ #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
+ #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
++#define regs_return_value(regs)((regs)->gprs[2])
+ #define profile_pc(regs) instruction_pointer(regs)
+ extern void show_regs(struct pt_regs * regs);
+ #endif
+@@ -479,7 +480,7 @@ extern void show_regs(struct pt_regs * r
+ static inline void
+ psw_set_key(unsigned int key)
+ {
+- asm volatile ( "spka 0(%0)" : : "d" (key) );
++ asm volatile("spka 0(%0)" : : "d" (key));
+ }
+
+ #endif /* __ASSEMBLY__ */
+diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
+index a2f37a9..7189c79 100644
+--- a/include/asm-s390/qdio.h
++++ b/include/asm-s390/qdio.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm/qdio.h
++ * linux/include/asm-s390/qdio.h
+ *
+ * Linux for S/390 QDIO base support, Hipersocket base support
+ * version 2
+diff --git a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h
+index 13ec169..90f4ecc 100644
+--- a/include/asm-s390/rwsem.h
++++ b/include/asm-s390/rwsem.h
+@@ -122,23 +122,23 @@ static inline void __down_read(struct rw
+ {
+ signed long old, new;
+
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " ahi %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " ahi %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " aghi %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " aghi %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count),
+- "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory" );
++ "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
+ if (old < 0)
+ rwsem_down_read_failed(sem);
+ }
+@@ -150,27 +150,27 @@ static inline int __down_read_trylock(st
+ {
+ signed long old, new;
+
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: ltr %1,%0\n"
+- " jm 1f\n"
+- " ahi %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b\n"
++ " l %0,0(%3)\n"
++ "0: ltr %1,%0\n"
++ " jm 1f\n"
++ " ahi %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b\n"
+ "1:"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: ltgr %1,%0\n"
+- " jm 1f\n"
+- " aghi %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b\n"
++ " lg %0,0(%3)\n"
++ "0: ltgr %1,%0\n"
++ " jm 1f\n"
++ " aghi %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b\n"
+ "1:"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count),
+- "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory" );
++ "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
+ return old >= 0 ? 1 : 0;
+ }
+
+@@ -182,23 +182,23 @@ static inline void __down_write_nested(s
+ signed long old, new, tmp;
+
+ tmp = RWSEM_ACTIVE_WRITE_BIAS;
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " a %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " a %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " ag %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " ag %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count), "m" (tmp)
+- : "cc", "memory" );
++ : "cc", "memory");
+ if (old != 0)
+ rwsem_down_write_failed(sem);
+ }
+@@ -215,24 +215,24 @@ static inline int __down_write_trylock(s
+ {
+ signed long old;
+
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%2)\n"
+- "0: ltr %0,%0\n"
+- " jnz 1f\n"
+- " cs %0,%4,0(%2)\n"
+- " jl 0b\n"
++ " l %0,0(%2)\n"
++ "0: ltr %0,%0\n"
++ " jnz 1f\n"
++ " cs %0,%4,0(%2)\n"
++ " jl 0b\n"
+ #else /* __s390x__ */
+- " lg %0,0(%2)\n"
+- "0: ltgr %0,%0\n"
+- " jnz 1f\n"
+- " csg %0,%4,0(%2)\n"
+- " jl 0b\n"
++ " lg %0,0(%2)\n"
++ "0: ltgr %0,%0\n"
++ " jnz 1f\n"
++ " csg %0,%4,0(%2)\n"
++ " jl 0b\n"
+ #endif /* __s390x__ */
+ "1:"
+- : "=&d" (old), "=m" (sem->count)
++ : "=&d" (old), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count),
+- "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory" );
++ "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory");
+ return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+ }
+
+@@ -243,24 +243,24 @@ static inline void __up_read(struct rw_s
+ {
+ signed long old, new;
+
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " ahi %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " ahi %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " aghi %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " aghi %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count),
+ "i" (-RWSEM_ACTIVE_READ_BIAS)
+- : "cc", "memory" );
++ : "cc", "memory");
+ if (new < 0)
+ if ((new & RWSEM_ACTIVE_MASK) == 0)
+ rwsem_wake(sem);
+@@ -274,23 +274,23 @@ static inline void __up_write(struct rw_
+ signed long old, new, tmp;
+
+ tmp = -RWSEM_ACTIVE_WRITE_BIAS;
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " a %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " a %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " ag %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " ag %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count), "m" (tmp)
+- : "cc", "memory" );
++ : "cc", "memory");
+ if (new < 0)
+ if ((new & RWSEM_ACTIVE_MASK) == 0)
+ rwsem_wake(sem);
+@@ -304,23 +304,23 @@ static inline void __downgrade_write(str
+ signed long old, new, tmp;
+
+ tmp = -RWSEM_WAITING_BIAS;
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " a %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " a %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " ag %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " ag %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count), "m" (tmp)
+- : "cc", "memory" );
++ : "cc", "memory");
+ if (new > 1)
+ rwsem_downgrade_wake(sem);
+ }
+@@ -332,23 +332,23 @@ static inline void rwsem_atomic_add(long
+ {
+ signed long old, new;
+
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " ar %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " ar %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " agr %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " agr %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count), "d" (delta)
+- : "cc", "memory" );
++ : "cc", "memory");
+ }
+
+ /*
+@@ -358,23 +358,23 @@ static inline long rwsem_atomic_update(l
+ {
+ signed long old, new;
+
+- __asm__ __volatile__(
++ asm volatile(
+ #ifndef __s390x__
+- " l %0,0(%3)\n"
+- "0: lr %1,%0\n"
+- " ar %1,%5\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b"
++ " l %0,0(%3)\n"
++ "0: lr %1,%0\n"
++ " ar %1,%5\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b"
+ #else /* __s390x__ */
+- " lg %0,0(%3)\n"
+- "0: lgr %1,%0\n"
+- " agr %1,%5\n"
+- " csg %0,%1,0(%3)\n"
+- " jl 0b"
++ " lg %0,0(%3)\n"
++ "0: lgr %1,%0\n"
++ " agr %1,%5\n"
++ " csg %0,%1,0(%3)\n"
++ " jl 0b"
+ #endif /* __s390x__ */
+- : "=&d" (old), "=&d" (new), "=m" (sem->count)
++ : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "a" (&sem->count), "m" (sem->count), "d" (delta)
+- : "cc", "memory" );
++ : "cc", "memory");
+ return new;
+ }
+
+diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h
+index e9a2862..df9b101 100644
+--- a/include/asm-s390/s390_ext.h
++++ b/include/asm-s390/s390_ext.h
+@@ -10,7 +10,7 @@
+ * Martin Schwidefsky (schwidefsky at de.ibm.com)
+ */
+
+-typedef void (*ext_int_handler_t)(struct pt_regs *regs, __u16 code);
++typedef void (*ext_int_handler_t)(__u16 code);
+
+ /*
+ * Warning: if you change ext_int_info_t you have to change the
+diff --git a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h
+index 32cdc69..dbce058 100644
+--- a/include/asm-s390/semaphore.h
++++ b/include/asm-s390/semaphore.h
+@@ -85,17 +85,17 @@ static inline int down_trylock(struct se
+ * sem->count.counter = --new_val;
+ * In the ppc code this is called atomic_dec_if_positive.
+ */
+- __asm__ __volatile__ (
+- " l %0,0(%3)\n"
+- "0: ltr %1,%0\n"
+- " jle 1f\n"
+- " ahi %1,-1\n"
+- " cs %0,%1,0(%3)\n"
+- " jl 0b\n"
++ asm volatile(
++ " l %0,0(%3)\n"
++ "0: ltr %1,%0\n"
++ " jle 1f\n"
++ " ahi %1,-1\n"
++ " cs %0,%1,0(%3)\n"
++ " jl 0b\n"
+ "1:"
+ : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count.counter)
+ : "a" (&sem->count.counter), "m" (sem->count.counter)
+- : "cc", "memory" );
++ : "cc", "memory");
+ return old_val <= 0;
+ }
+
+diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
+index 19e3197..5d72eda 100644
+--- a/include/asm-s390/setup.h
++++ b/include/asm-s390/setup.h
+@@ -14,8 +14,6 @@
+
+ #define PARMAREA 0x10400
+ #define COMMAND_LINE_SIZE 896
+-#define RAMDISK_ORIGIN 0x800000
+-#define RAMDISK_SIZE 0x800000
+ #define MEMORY_CHUNKS 16 /* max 0x7fff */
+ #define IPL_PARMBLOCK_ORIGIN 0x2000
+
+@@ -41,15 +39,18 @@ extern unsigned long machine_flags;
+ #define MACHINE_IS_P390 (machine_flags & 4)
+ #define MACHINE_HAS_MVPG (machine_flags & 16)
+ #define MACHINE_HAS_IDTE (machine_flags & 128)
++#define MACHINE_HAS_DIAG9C (machine_flags & 256)
+
+ #ifndef __s390x__
+ #define MACHINE_HAS_IEEE (machine_flags & 2)
+ #define MACHINE_HAS_CSP (machine_flags & 8)
+ #define MACHINE_HAS_DIAG44 (1)
++#define MACHINE_HAS_MVCOS (0)
+ #else /* __s390x__ */
+ #define MACHINE_HAS_IEEE (1)
+ #define MACHINE_HAS_CSP (1)
+ #define MACHINE_HAS_DIAG44 (machine_flags & 32)
++#define MACHINE_HAS_MVCOS (machine_flags & 512)
+ #endif /* __s390x__ */
+
+
+@@ -70,52 +71,76 @@ extern unsigned int console_irq;
+ #define SET_CONSOLE_3215 do { console_mode = 2; } while (0)
+ #define SET_CONSOLE_3270 do { console_mode = 3; } while (0)
+
+-struct ipl_list_header {
+- u32 length;
+- u8 reserved[3];
++
++struct ipl_list_hdr {
++ u32 len;
++ u8 reserved1[3];
+ u8 version;
++ u32 blk0_len;
++ u8 pbt;
++ u8 flags;
++ u16 reserved2;
+ } __attribute__((packed));
+
+ struct ipl_block_fcp {
+- u32 length;
+- u8 pbt;
+- u8 reserved1[322-1];
++ u8 reserved1[313-1];
++ u8 opt;
++ u8 reserved2[3];
++ u16 reserved3;
+ u16 devno;
+- u8 reserved2[4];
++ u8 reserved4[4];
+ u64 wwpn;
+ u64 lun;
+ u32 bootprog;
+- u8 reserved3[12];
++ u8 reserved5[12];
+ u64 br_lba;
+ u32 scp_data_len;
+- u8 reserved4[260];
++ u8 reserved6[260];
+ u8 scp_data[];
+ } __attribute__((packed));
+
++struct ipl_block_ccw {
++ u8 load_param[8];
++ u8 reserved1[84];
++ u8 reserved2[2];
++ u16 devno;
++ u8 vm_flags;
++ u8 reserved3[3];
++ u32 vm_parm_len;
++} __attribute__((packed));
++
+ struct ipl_parameter_block {
++ struct ipl_list_hdr hdr;
+ union {
+- u32 length;
+- struct ipl_list_header header;
+- } hdr;
+- struct ipl_block_fcp fcp;
++ struct ipl_block_fcp fcp;
++ struct ipl_block_ccw ccw;
++ } ipl_info;
+ } __attribute__((packed));
+
+-#define IPL_MAX_SUPPORTED_VERSION (0)
++#define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
++ sizeof(struct ipl_block_fcp))
+
+-#define IPL_TYPE_FCP (0)
++#define IPL_PARM_BLK_CCW_LEN (sizeof(struct ipl_list_hdr) + \
++ sizeof(struct ipl_block_ccw))
++
++#define IPL_MAX_SUPPORTED_VERSION (0)
+
+ /*
+ * IPL validity flags and parameters as detected in head.S
+ */
+-extern u32 ipl_parameter_flags;
++extern u32 ipl_flags;
+ extern u16 ipl_devno;
+
+-#define IPL_DEVNO_VALID (ipl_parameter_flags & 1)
+-#define IPL_PARMBLOCK_VALID (ipl_parameter_flags & 2)
++void do_reipl(void);
++
++enum {
++ IPL_DEVNO_VALID = 1,
++ IPL_PARMBLOCK_VALID = 2,
++};
+
+ #define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \
+ IPL_PARMBLOCK_ORIGIN)
+-#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.length)
++#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len)
+
+ #else /* __ASSEMBLY__ */
+
+diff --git a/include/asm-s390/sfp-machine.h b/include/asm-s390/sfp-machine.h
+index de69dfa..8ca8c77 100644
+--- a/include/asm-s390/sfp-machine.h
++++ b/include/asm-s390/sfp-machine.h
+@@ -76,21 +76,23 @@
+ unsigned int __r2 = (x2) + (y2); \
+ unsigned int __r1 = (x1); \
+ unsigned int __r0 = (x0); \
+- __asm__ (" alr %2,%3\n" \
+- " brc 12,0f\n" \
+- " lhi 0,1\n" \
+- " alr %1,0\n" \
+- " brc 12,0f\n" \
+- " alr %0,0\n" \
+- "0:" \
+- : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
+- : "d" (y0), "i" (1) : "cc", "0" ); \
+- __asm__ (" alr %1,%2\n" \
+- " brc 12,0f\n" \
+- " ahi %0,1\n" \
+- "0:" \
+- : "+&d" (__r2), "+&d" (__r1) \
+- : "d" (y1) : "cc" ); \
++ asm volatile( \
++ " alr %2,%3\n" \
++ " brc 12,0f\n" \
++ " lhi 0,1\n" \
++ " alr %1,0\n" \
++ " brc 12,0f\n" \
++ " alr %0,0\n" \
++ "0:" \
++ : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
++ : "d" (y0), "i" (1) : "cc", "0" ); \
++ asm volatile( \
++ " alr %1,%2\n" \
++ " brc 12,0f\n" \
++ " ahi %0,1\n" \
++ "0:" \
++ : "+&d" (__r2), "+&d" (__r1) \
++ : "d" (y1) : "cc"); \
+ (r2) = __r2; \
+ (r1) = __r1; \
+ (r0) = __r0; \
+@@ -100,21 +102,23 @@
+ unsigned int __r2 = (x2) - (y2); \
+ unsigned int __r1 = (x1); \
+ unsigned int __r0 = (x0); \
+- __asm__ (" slr %2,%3\n" \
+- " brc 3,0f\n" \
+- " lhi 0,1\n" \
+- " slr %1,0\n" \
+- " brc 3,0f\n" \
+- " slr %0,0\n" \
+- "0:" \
+- : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
+- : "d" (y0) : "cc", "0" ); \
+- __asm__ (" slr %1,%2\n" \
+- " brc 3,0f\n" \
+- " ahi %0,-1\n" \
+- "0:" \
+- : "+&d" (__r2), "+&d" (__r1) \
+- : "d" (y1) : "cc" ); \
++ asm volatile( \
++ " slr %2,%3\n" \
++ " brc 3,0f\n" \
++ " lhi 0,1\n" \
++ " slr %1,0\n" \
++ " brc 3,0f\n" \
++ " slr %0,0\n" \
++ "0:" \
++ : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
++ : "d" (y0) : "cc", "0"); \
++ asm volatile( \
++ " slr %1,%2\n" \
++ " brc 3,0f\n" \
++ " ahi %0,-1\n" \
++ "0:" \
++ : "+&d" (__r2), "+&d" (__r1) \
++ : "d" (y1) : "cc"); \
+ (r2) = __r2; \
+ (r1) = __r1; \
+ (r0) = __r0; \
+diff --git a/include/asm-s390/sigp.h b/include/asm-s390/sigp.h
+index fc56458..e16d56f 100644
+--- a/include/asm-s390/sigp.h
++++ b/include/asm-s390/sigp.h
+@@ -70,16 +70,16 @@ typedef enum
+ static inline sigp_ccode
+ signal_processor(__u16 cpu_addr, sigp_order_code order_code)
+ {
++ register unsigned long reg1 asm ("1") = 0;
+ sigp_ccode ccode;
+
+- __asm__ __volatile__(
+- " sr 1,1\n" /* parameter=0 in gpr 1 */
+- " sigp 1,%1,0(%2)\n"
+- " ipm %0\n"
+- " srl %0,28\n"
+- : "=d" (ccode)
+- : "d" (__cpu_logical_map[cpu_addr]), "a" (order_code)
+- : "cc" , "memory", "1" );
++ asm volatile(
++ " sigp %1,%2,0(%3)\n"
++ " ipm %0\n"
++ " srl %0,28\n"
++ : "=d" (ccode)
++ : "d" (reg1), "d" (__cpu_logical_map[cpu_addr]),
++ "a" (order_code) : "cc" , "memory");
+ return ccode;
+ }
+
+@@ -87,20 +87,18 @@ signal_processor(__u16 cpu_addr, sigp_or
+ * Signal processor with parameter
+ */
+ static inline sigp_ccode
+-signal_processor_p(__u32 parameter, __u16 cpu_addr,
+- sigp_order_code order_code)
++signal_processor_p(__u32 parameter, __u16 cpu_addr, sigp_order_code order_code)
+ {
++ register unsigned int reg1 asm ("1") = parameter;
+ sigp_ccode ccode;
+-
+- __asm__ __volatile__(
+- " lr 1,%1\n" /* parameter in gpr 1 */
+- " sigp 1,%2,0(%3)\n"
+- " ipm %0\n"
+- " srl %0,28\n"
++
++ asm volatile(
++ " sigp %1,%2,0(%3)\n"
++ " ipm %0\n"
++ " srl %0,28\n"
+ : "=d" (ccode)
+- : "d" (parameter), "d" (__cpu_logical_map[cpu_addr]),
+- "a" (order_code)
+- : "cc" , "memory", "1" );
++ : "d" (reg1), "d" (__cpu_logical_map[cpu_addr]),
++ "a" (order_code) : "cc" , "memory");
+ return ccode;
+ }
+
+@@ -108,24 +106,21 @@ signal_processor_p(__u32 parameter, __u1
+ * Signal processor with parameter and return status
+ */
+ static inline sigp_ccode
+-signal_processor_ps(__u32 *statusptr, __u32 parameter,
+- __u16 cpu_addr, sigp_order_code order_code)
++signal_processor_ps(__u32 *statusptr, __u32 parameter, __u16 cpu_addr,
++ sigp_order_code order_code)
+ {
++ register unsigned int reg1 asm ("1") = parameter;
+ sigp_ccode ccode;
+-
+- __asm__ __volatile__(
+- " sr 2,2\n" /* clear status */
+- " lr 3,%2\n" /* parameter in gpr 3 */
+- " sigp 2,%3,0(%4)\n"
+- " st 2,%1\n"
+- " ipm %0\n"
+- " srl %0,28\n"
+- : "=d" (ccode), "=m" (*statusptr)
+- : "d" (parameter), "d" (__cpu_logical_map[cpu_addr]),
+- "a" (order_code)
+- : "cc" , "memory", "2" , "3"
+- );
+- return ccode;
++
++ asm volatile(
++ " sigp %1,%2,0(%3)\n"
++ " ipm %0\n"
++ " srl %0,28\n"
++ : "=d" (ccode), "+d" (reg1)
++ : "d" (__cpu_logical_map[cpu_addr]), "a" (order_code)
++ : "cc" , "memory");
++ *statusptr = reg1;
++ return ccode;
+ }
+
+ #endif /* __SIGP__ */
+diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
+index 6576460..c3cf030 100644
+--- a/include/asm-s390/smp.h
++++ b/include/asm-s390/smp.h
+@@ -56,7 +56,7 @@ static inline __u16 hard_smp_processor_i
+ {
+ __u16 cpu_address;
+
+- __asm__ ("stap %0\n" : "=m" (cpu_address));
++ asm volatile("stap %0" : "=m" (cpu_address));
+ return cpu_address;
+ }
+
+@@ -104,7 +104,7 @@ smp_call_function_on(void (*func) (void
+ #define smp_cpu_not_running(cpu) 1
+ #define smp_get_cpu(cpu) ({ 0; })
+ #define smp_put_cpu(cpu) ({ 0; })
+-#define smp_setup_cpu_possible_map()
++#define smp_setup_cpu_possible_map() do { } while (0)
+ #endif
+
+ #endif
+diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
+index 273dbec..3fd4382 100644
+--- a/include/asm-s390/spinlock.h
++++ b/include/asm-s390/spinlock.h
+@@ -11,17 +11,38 @@
+ #ifndef __ASM_SPINLOCK_H
+ #define __ASM_SPINLOCK_H
+
++#include <linux/smp.h>
++
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++
+ static inline int
+ _raw_compare_and_swap(volatile unsigned int *lock,
+ unsigned int old, unsigned int new)
+ {
+- asm volatile ("cs %0,%3,0(%4)"
+- : "=d" (old), "=m" (*lock)
+- : "0" (old), "d" (new), "a" (lock), "m" (*lock)
+- : "cc", "memory" );
++ asm volatile(
++ " cs %0,%3,%1"
++ : "=d" (old), "=Q" (*lock)
++ : "0" (old), "d" (new), "Q" (*lock)
++ : "cc", "memory" );
+ return old;
+ }
+
++#else /* __GNUC__ */
++
++static inline int
++_raw_compare_and_swap(volatile unsigned int *lock,
++ unsigned int old, unsigned int new)
++{
++ asm volatile(
++ " cs %0,%3,0(%4)"
++ : "=d" (old), "=m" (*lock)
++ : "0" (old), "d" (new), "a" (lock), "m" (*lock)
++ : "cc", "memory" );
++ return old;
++}
++
++#endif /* __GNUC__ */
++
+ /*
+ * Simple spin lock operations. There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+@@ -31,34 +52,46 @@ _raw_compare_and_swap(volatile unsigned
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+-#define __raw_spin_is_locked(x) ((x)->lock != 0)
++#define __raw_spin_is_locked(x) ((x)->owner_cpu != 0)
+ #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+ #define __raw_spin_unlock_wait(lock) \
+- do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
++ do { while (__raw_spin_is_locked(lock)) \
++ _raw_spin_relax(lock); } while (0)
+
+-extern void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc);
+-extern int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc);
++extern void _raw_spin_lock_wait(raw_spinlock_t *, unsigned int pc);
++extern int _raw_spin_trylock_retry(raw_spinlock_t *, unsigned int pc);
++extern void _raw_spin_relax(raw_spinlock_t *lock);
+
+ static inline void __raw_spin_lock(raw_spinlock_t *lp)
+ {
+ unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
+-
+- if (unlikely(_raw_compare_and_swap(&lp->lock, 0, pc) != 0))
+- _raw_spin_lock_wait(lp, pc);
++ int old;
++
++ old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
++ if (likely(old == 0)) {
++ lp->owner_pc = pc;
++ return;
++ }
++ _raw_spin_lock_wait(lp, pc);
+ }
+
+ static inline int __raw_spin_trylock(raw_spinlock_t *lp)
+ {
+ unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
++ int old;
+
+- if (likely(_raw_compare_and_swap(&lp->lock, 0, pc) == 0))
++ old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
++ if (likely(old == 0)) {
++ lp->owner_pc = pc;
+ return 1;
++ }
+ return _raw_spin_trylock_retry(lp, pc);
+ }
+
+ static inline void __raw_spin_unlock(raw_spinlock_t *lp)
+ {
+- _raw_compare_and_swap(&lp->lock, lp->lock, 0);
++ lp->owner_pc = 0;
++ _raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
+ }
+
+ /*
+@@ -135,4 +168,7 @@ static inline int __raw_write_trylock(ra
+ return _raw_write_trylock_retry(rw);
+ }
+
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-s390/spinlock_types.h b/include/asm-s390/spinlock_types.h
+index f79a221..b7ac13f 100644
+--- a/include/asm-s390/spinlock_types.h
++++ b/include/asm-s390/spinlock_types.h
+@@ -6,16 +6,16 @@
+ #endif
+
+ typedef struct {
+- volatile unsigned int lock;
++ volatile unsigned int owner_cpu;
++ volatile unsigned int owner_pc;
+ } __attribute__ ((aligned (4))) raw_spinlock_t;
+
+ #define __RAW_SPIN_LOCK_UNLOCKED { 0 }
+
+ typedef struct {
+ volatile unsigned int lock;
+- volatile unsigned int owner_pc;
+ } raw_rwlock_t;
+
+-#define __RAW_RW_LOCK_UNLOCKED { 0, 0 }
++#define __RAW_RW_LOCK_UNLOCKED { 0 }
+
+ #endif
+diff --git a/include/asm-s390/string.h b/include/asm-s390/string.h
+index 23a4c39..d074673 100644
+--- a/include/asm-s390/string.h
++++ b/include/asm-s390/string.h
+@@ -60,12 +60,13 @@ static inline void *memchr(const void *
+ register int r0 asm("0") = (char) c;
+ const void *ret = s + n;
+
+- asm volatile ("0: srst %0,%1\n"
+- " jo 0b\n"
+- " jl 1f\n"
+- " la %0,0\n"
+- "1:"
+- : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
++ asm volatile(
++ "0: srst %0,%1\n"
++ " jo 0b\n"
++ " jl 1f\n"
++ " la %0,0\n"
++ "1:"
++ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc");
+ return (void *) ret;
+ }
+
+@@ -74,9 +75,10 @@ static inline void *memscan(void *s, int
+ register int r0 asm("0") = (char) c;
+ const void *ret = s + n;
+
+- asm volatile ("0: srst %0,%1\n"
+- " jo 0b\n"
+- : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
++ asm volatile(
++ "0: srst %0,%1\n"
++ " jo 0b\n"
++ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc");
+ return (void *) ret;
+ }
+
+@@ -86,12 +88,13 @@ static inline char *strcat(char *dst, co
+ unsigned long dummy;
+ char *ret = dst;
+
+- asm volatile ("0: srst %0,%1\n"
+- " jo 0b\n"
+- "1: mvst %0,%2\n"
+- " jo 1b"
+- : "=&a" (dummy), "+a" (dst), "+a" (src)
+- : "d" (r0), "0" (0) : "cc", "memory" );
++ asm volatile(
++ "0: srst %0,%1\n"
++ " jo 0b\n"
++ "1: mvst %0,%2\n"
++ " jo 1b"
++ : "=&a" (dummy), "+a" (dst), "+a" (src)
++ : "d" (r0), "0" (0) : "cc", "memory" );
+ return ret;
+ }
+
+@@ -100,10 +103,11 @@ static inline char *strcpy(char *dst, co
+ register int r0 asm("0") = 0;
+ char *ret = dst;
+
+- asm volatile ("0: mvst %0,%1\n"
+- " jo 0b"
+- : "+&a" (dst), "+&a" (src) : "d" (r0)
+- : "cc", "memory" );
++ asm volatile(
++ "0: mvst %0,%1\n"
++ " jo 0b"
++ : "+&a" (dst), "+&a" (src) : "d" (r0)
++ : "cc", "memory");
+ return ret;
+ }
+
+@@ -112,9 +116,10 @@ static inline size_t strlen(const char *
+ register unsigned long r0 asm("0") = 0;
+ const char *tmp = s;
+
+- asm volatile ("0: srst %0,%1\n"
+- " jo 0b"
+- : "+d" (r0), "+a" (tmp) : : "cc" );
++ asm volatile(
++ "0: srst %0,%1\n"
++ " jo 0b"
++ : "+d" (r0), "+a" (tmp) : : "cc");
+ return r0 - (unsigned long) s;
+ }
+
+@@ -124,9 +129,10 @@ static inline size_t strnlen(const char
+ const char *tmp = s;
+ const char *end = s + n;
+
+- asm volatile ("0: srst %0,%1\n"
+- " jo 0b"
+- : "+a" (end), "+a" (tmp) : "d" (r0) : "cc" );
++ asm volatile(
++ "0: srst %0,%1\n"
++ " jo 0b"
++ : "+a" (end), "+a" (tmp) : "d" (r0) : "cc");
+ return end - s;
+ }
+
+diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
+index 1604004..ccbafe4 100644
+--- a/include/asm-s390/system.h
++++ b/include/asm-s390/system.h
+@@ -23,74 +23,68 @@ struct task_struct;
+
+ extern struct task_struct *__switch_to(void *, void *);
+
+-#ifdef __s390x__
+-#define __FLAG_SHIFT 56
+-#else /* ! __s390x__ */
+-#define __FLAG_SHIFT 24
+-#endif /* ! __s390x__ */
+-
+ static inline void save_fp_regs(s390_fp_regs *fpregs)
+ {
+- asm volatile (
+- " std 0,8(%1)\n"
+- " std 2,24(%1)\n"
+- " std 4,40(%1)\n"
+- " std 6,56(%1)"
+- : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory" );
++ asm volatile(
++ " std 0,8(%1)\n"
++ " std 2,24(%1)\n"
++ " std 4,40(%1)\n"
++ " std 6,56(%1)"
++ : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory");
+ if (!MACHINE_HAS_IEEE)
+ return;
+ asm volatile(
+- " stfpc 0(%1)\n"
+- " std 1,16(%1)\n"
+- " std 3,32(%1)\n"
+- " std 5,48(%1)\n"
+- " std 7,64(%1)\n"
+- " std 8,72(%1)\n"
+- " std 9,80(%1)\n"
+- " std 10,88(%1)\n"
+- " std 11,96(%1)\n"
+- " std 12,104(%1)\n"
+- " std 13,112(%1)\n"
+- " std 14,120(%1)\n"
+- " std 15,128(%1)\n"
+- : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory" );
++ " stfpc 0(%1)\n"
++ " std 1,16(%1)\n"
++ " std 3,32(%1)\n"
++ " std 5,48(%1)\n"
++ " std 7,64(%1)\n"
++ " std 8,72(%1)\n"
++ " std 9,80(%1)\n"
++ " std 10,88(%1)\n"
++ " std 11,96(%1)\n"
++ " std 12,104(%1)\n"
++ " std 13,112(%1)\n"
++ " std 14,120(%1)\n"
++ " std 15,128(%1)\n"
++ : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory");
+ }
+
+ static inline void restore_fp_regs(s390_fp_regs *fpregs)
+ {
+- asm volatile (
+- " ld 0,8(%0)\n"
+- " ld 2,24(%0)\n"
+- " ld 4,40(%0)\n"
+- " ld 6,56(%0)"
+- : : "a" (fpregs), "m" (*fpregs) );
++ asm volatile(
++ " ld 0,8(%0)\n"
++ " ld 2,24(%0)\n"
++ " ld 4,40(%0)\n"
++ " ld 6,56(%0)"
++ : : "a" (fpregs), "m" (*fpregs));
+ if (!MACHINE_HAS_IEEE)
+ return;
+ asm volatile(
+- " lfpc 0(%0)\n"
+- " ld 1,16(%0)\n"
+- " ld 3,32(%0)\n"
+- " ld 5,48(%0)\n"
+- " ld 7,64(%0)\n"
+- " ld 8,72(%0)\n"
+- " ld 9,80(%0)\n"
+- " ld 10,88(%0)\n"
+- " ld 11,96(%0)\n"
+- " ld 12,104(%0)\n"
+- " ld 13,112(%0)\n"
+- " ld 14,120(%0)\n"
+- " ld 15,128(%0)\n"
+- : : "a" (fpregs), "m" (*fpregs) );
++ " lfpc 0(%0)\n"
++ " ld 1,16(%0)\n"
++ " ld 3,32(%0)\n"
++ " ld 5,48(%0)\n"
++ " ld 7,64(%0)\n"
++ " ld 8,72(%0)\n"
++ " ld 9,80(%0)\n"
++ " ld 10,88(%0)\n"
++ " ld 11,96(%0)\n"
++ " ld 12,104(%0)\n"
++ " ld 13,112(%0)\n"
++ " ld 14,120(%0)\n"
++ " ld 15,128(%0)\n"
++ : : "a" (fpregs), "m" (*fpregs));
+ }
+
+ static inline void save_access_regs(unsigned int *acrs)
+ {
+- asm volatile ("stam 0,15,0(%0)" : : "a" (acrs) : "memory" );
++ asm volatile("stam 0,15,0(%0)" : : "a" (acrs) : "memory");
+ }
+
+ static inline void restore_access_regs(unsigned int *acrs)
+ {
+- asm volatile ("lam 0,15,0(%0)" : : "a" (acrs) );
++ asm volatile("lam 0,15,0(%0)" : : "a" (acrs));
+ }
+
+ #define switch_to(prev,next,last) do { \
+@@ -126,7 +120,7 @@ extern void account_system_vtime(struct
+ account_vtime(prev); \
+ } while (0)
+
+-#define nop() __asm__ __volatile__ ("nop")
++#define nop() asm volatile("nop")
+
+ #define xchg(ptr,x) \
+ ({ \
+@@ -147,15 +141,15 @@ static inline unsigned long __xchg(unsig
+ shift = (3 ^ (addr & 3)) << 3;
+ addr ^= addr & 3;
+ asm volatile(
+- " l %0,0(%4)\n"
+- "0: lr 0,%0\n"
+- " nr 0,%3\n"
+- " or 0,%2\n"
+- " cs %0,0,0(%4)\n"
+- " jl 0b\n"
++ " l %0,0(%4)\n"
++ "0: lr 0,%0\n"
++ " nr 0,%3\n"
++ " or 0,%2\n"
++ " cs %0,0,0(%4)\n"
++ " jl 0b\n"
+ : "=&d" (old), "=m" (*(int *) addr)
+ : "d" (x << shift), "d" (~(255 << shift)), "a" (addr),
+- "m" (*(int *) addr) : "memory", "cc", "0" );
++ "m" (*(int *) addr) : "memory", "cc", "0");
+ x = old >> shift;
+ break;
+ case 2:
+@@ -163,36 +157,36 @@ static inline unsigned long __xchg(unsig
+ shift = (2 ^ (addr & 2)) << 3;
+ addr ^= addr & 2;
+ asm volatile(
+- " l %0,0(%4)\n"
+- "0: lr 0,%0\n"
+- " nr 0,%3\n"
+- " or 0,%2\n"
+- " cs %0,0,0(%4)\n"
+- " jl 0b\n"
++ " l %0,0(%4)\n"
++ "0: lr 0,%0\n"
++ " nr 0,%3\n"
++ " or 0,%2\n"
++ " cs %0,0,0(%4)\n"
++ " jl 0b\n"
+ : "=&d" (old), "=m" (*(int *) addr)
+ : "d" (x << shift), "d" (~(65535 << shift)), "a" (addr),
+- "m" (*(int *) addr) : "memory", "cc", "0" );
++ "m" (*(int *) addr) : "memory", "cc", "0");
+ x = old >> shift;
+ break;
+ case 4:
+- asm volatile (
+- " l %0,0(%3)\n"
+- "0: cs %0,%2,0(%3)\n"
+- " jl 0b\n"
++ asm volatile(
++ " l %0,0(%3)\n"
++ "0: cs %0,%2,0(%3)\n"
++ " jl 0b\n"
+ : "=&d" (old), "=m" (*(int *) ptr)
+ : "d" (x), "a" (ptr), "m" (*(int *) ptr)
+- : "memory", "cc" );
++ : "memory", "cc");
+ x = old;
+ break;
+ #ifdef __s390x__
+ case 8:
+- asm volatile (
+- " lg %0,0(%3)\n"
+- "0: csg %0,%2,0(%3)\n"
+- " jl 0b\n"
++ asm volatile(
++ " lg %0,0(%3)\n"
++ "0: csg %0,%2,0(%3)\n"
++ " jl 0b\n"
+ : "=&d" (old), "=m" (*(long *) ptr)
+ : "d" (x), "a" (ptr), "m" (*(long *) ptr)
+- : "memory", "cc" );
++ : "memory", "cc");
+ x = old;
+ break;
+ #endif /* __s390x__ */
+@@ -224,55 +218,55 @@ __cmpxchg(volatile void *ptr, unsigned l
+ shift = (3 ^ (addr & 3)) << 3;
+ addr ^= addr & 3;
+ asm volatile(
+- " l %0,0(%4)\n"
+- "0: nr %0,%5\n"
+- " lr %1,%0\n"
+- " or %0,%2\n"
+- " or %1,%3\n"
+- " cs %0,%1,0(%4)\n"
+- " jnl 1f\n"
+- " xr %1,%0\n"
+- " nr %1,%5\n"
+- " jnz 0b\n"
++ " l %0,0(%4)\n"
++ "0: nr %0,%5\n"
++ " lr %1,%0\n"
++ " or %0,%2\n"
++ " or %1,%3\n"
++ " cs %0,%1,0(%4)\n"
++ " jnl 1f\n"
++ " xr %1,%0\n"
++ " nr %1,%5\n"
++ " jnz 0b\n"
+ "1:"
+ : "=&d" (prev), "=&d" (tmp)
+ : "d" (old << shift), "d" (new << shift), "a" (ptr),
+ "d" (~(255 << shift))
+- : "memory", "cc" );
++ : "memory", "cc");
+ return prev >> shift;
+ case 2:
+ addr = (unsigned long) ptr;
+ shift = (2 ^ (addr & 2)) << 3;
+ addr ^= addr & 2;
+ asm volatile(
+- " l %0,0(%4)\n"
+- "0: nr %0,%5\n"
+- " lr %1,%0\n"
+- " or %0,%2\n"
+- " or %1,%3\n"
+- " cs %0,%1,0(%4)\n"
+- " jnl 1f\n"
+- " xr %1,%0\n"
+- " nr %1,%5\n"
+- " jnz 0b\n"
++ " l %0,0(%4)\n"
++ "0: nr %0,%5\n"
++ " lr %1,%0\n"
++ " or %0,%2\n"
++ " or %1,%3\n"
++ " cs %0,%1,0(%4)\n"
++ " jnl 1f\n"
++ " xr %1,%0\n"
++ " nr %1,%5\n"
++ " jnz 0b\n"
+ "1:"
+ : "=&d" (prev), "=&d" (tmp)
+ : "d" (old << shift), "d" (new << shift), "a" (ptr),
+ "d" (~(65535 << shift))
+- : "memory", "cc" );
++ : "memory", "cc");
+ return prev >> shift;
+ case 4:
+- asm volatile (
+- " cs %0,%2,0(%3)\n"
++ asm volatile(
++ " cs %0,%2,0(%3)\n"
+ : "=&d" (prev) : "0" (old), "d" (new), "a" (ptr)
+- : "memory", "cc" );
++ : "memory", "cc");
+ return prev;
+ #ifdef __s390x__
+ case 8:
+- asm volatile (
+- " csg %0,%2,0(%3)\n"
++ asm volatile(
++ " csg %0,%2,0(%3)\n"
+ : "=&d" (prev) : "0" (old), "d" (new), "a" (ptr)
+- : "memory", "cc" );
++ : "memory", "cc");
+ return prev;
+ #endif /* __s390x__ */
+ }
+@@ -289,8 +283,8 @@ __cmpxchg(volatile void *ptr, unsigned l
+ * all memory ops have completed wrt other CPU's ( see 7-15 POP DJB ).
+ */
+
+-#define eieio() __asm__ __volatile__ ( "bcr 15,0" : : : "memory" )
+-# define SYNC_OTHER_CORES(x) eieio()
++#define eieio() asm volatile("bcr 15,0" : : : "memory")
++#define SYNC_OTHER_CORES(x) eieio()
+ #define mb() eieio()
+ #define rmb() eieio()
+ #define wmb() eieio()
+@@ -307,117 +301,56 @@ __cmpxchg(volatile void *ptr, unsigned l
+
+ #ifdef __s390x__
+
+-#define __ctl_load(array, low, high) ({ \
+- typedef struct { char _[sizeof(array)]; } addrtype; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" \
+- " lctlg 0,0,0(%0)\n" \
+- "0: ex %1,0(1)" \
+- : : "a" (&array), "a" (((low)<<4)+(high)), \
+- "m" (*(addrtype *)(array)) : "1" ); \
++#define __ctl_load(array, low, high) ({ \
++ typedef struct { char _[sizeof(array)]; } addrtype; \
++ asm volatile( \
++ " lctlg %1,%2,0(%0)\n" \
++ : : "a" (&array), "i" (low), "i" (high), \
++ "m" (*(addrtype *)(array))); \
+ })
+
+-#define __ctl_store(array, low, high) ({ \
+- typedef struct { char _[sizeof(array)]; } addrtype; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" \
+- " stctg 0,0,0(%1)\n" \
+- "0: ex %2,0(1)" \
+- : "=m" (*(addrtype *)(array)) \
+- : "a" (&array), "a" (((low)<<4)+(high)) : "1" ); \
++#define __ctl_store(array, low, high) ({ \
++ typedef struct { char _[sizeof(array)]; } addrtype; \
++ asm volatile( \
++ " stctg %2,%3,0(%1)\n" \
++ : "=m" (*(addrtype *)(array)) \
++ : "a" (&array), "i" (low), "i" (high)); \
+ })
+
+-#define __ctl_set_bit(cr, bit) ({ \
+- __u8 __dummy[24]; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" /* skip indirect insns */ \
+- " stctg 0,0,0(%1)\n" \
+- " lctlg 0,0,0(%1)\n" \
+- "0: ex %2,0(1)\n" /* execute stctl */ \
+- " lg 0,0(%1)\n" \
+- " ogr 0,%3\n" /* set the bit */ \
+- " stg 0,0(%1)\n" \
+- "1: ex %2,6(1)" /* execute lctl */ \
+- : "=m" (__dummy) \
+- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
+- "a" (cr*17), "a" (1L<<(bit)) \
+- : "cc", "0", "1" ); \
+- })
+-
+-#define __ctl_clear_bit(cr, bit) ({ \
+- __u8 __dummy[16]; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" /* skip indirect insns */ \
+- " stctg 0,0,0(%1)\n" \
+- " lctlg 0,0,0(%1)\n" \
+- "0: ex %2,0(1)\n" /* execute stctl */ \
+- " lg 0,0(%1)\n" \
+- " ngr 0,%3\n" /* set the bit */ \
+- " stg 0,0(%1)\n" \
+- "1: ex %2,6(1)" /* execute lctl */ \
+- : "=m" (__dummy) \
+- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
+- "a" (cr*17), "a" (~(1L<<(bit))) \
+- : "cc", "0", "1" ); \
+- })
+-
+ #else /* __s390x__ */
+
+-#define __ctl_load(array, low, high) ({ \
+- typedef struct { char _[sizeof(array)]; } addrtype; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" \
+- " lctl 0,0,0(%0)\n" \
+- "0: ex %1,0(1)" \
+- : : "a" (&array), "a" (((low)<<4)+(high)), \
+- "m" (*(addrtype *)(array)) : "1" ); \
+- })
++#define __ctl_load(array, low, high) ({ \
++ typedef struct { char _[sizeof(array)]; } addrtype; \
++ asm volatile( \
++ " lctl %1,%2,0(%0)\n" \
++ : : "a" (&array), "i" (low), "i" (high), \
++ "m" (*(addrtype *)(array))); \
++})
+
+-#define __ctl_store(array, low, high) ({ \
+- typedef struct { char _[sizeof(array)]; } addrtype; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" \
+- " stctl 0,0,0(%1)\n" \
+- "0: ex %2,0(1)" \
+- : "=m" (*(addrtype *)(array)) \
+- : "a" (&array), "a" (((low)<<4)+(high)): "1" ); \
++#define __ctl_store(array, low, high) ({ \
++ typedef struct { char _[sizeof(array)]; } addrtype; \
++ asm volatile( \
++ " stctl %2,%3,0(%1)\n" \
++ : "=m" (*(addrtype *)(array)) \
++ : "a" (&array), "i" (low), "i" (high)); \
+ })
+
+-#define __ctl_set_bit(cr, bit) ({ \
+- __u8 __dummy[16]; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" /* skip indirect insns */ \
+- " stctl 0,0,0(%1)\n" \
+- " lctl 0,0,0(%1)\n" \
+- "0: ex %2,0(1)\n" /* execute stctl */ \
+- " l 0,0(%1)\n" \
+- " or 0,%3\n" /* set the bit */ \
+- " st 0,0(%1)\n" \
+- "1: ex %2,4(1)" /* execute lctl */ \
+- : "=m" (__dummy) \
+- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
+- "a" (cr*17), "a" (1<<(bit)) \
+- : "cc", "0", "1" ); \
+- })
+-
+-#define __ctl_clear_bit(cr, bit) ({ \
+- __u8 __dummy[16]; \
+- __asm__ __volatile__ ( \
+- " bras 1,0f\n" /* skip indirect insns */ \
+- " stctl 0,0,0(%1)\n" \
+- " lctl 0,0,0(%1)\n" \
+- "0: ex %2,0(1)\n" /* execute stctl */ \
+- " l 0,0(%1)\n" \
+- " nr 0,%3\n" /* set the bit */ \
+- " st 0,0(%1)\n" \
+- "1: ex %2,4(1)" /* execute lctl */ \
+- : "=m" (__dummy) \
+- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
+- "a" (cr*17), "a" (~(1<<(bit))) \
+- : "cc", "0", "1" ); \
+- })
+ #endif /* __s390x__ */
+
++#define __ctl_set_bit(cr, bit) ({ \
++ unsigned long __dummy; \
++ __ctl_store(__dummy, cr, cr); \
++ __dummy |= 1UL << (bit); \
++ __ctl_load(__dummy, cr, cr); \
++})
++
++#define __ctl_clear_bit(cr, bit) ({ \
++ unsigned long __dummy; \
++ __ctl_store(__dummy, cr, cr); \
++ __dummy &= ~(1UL << (bit)); \
++ __ctl_load(__dummy, cr, cr); \
++})
++
+ #include <linux/irqflags.h>
+
+ /*
+@@ -427,8 +360,7 @@ __cmpxchg(volatile void *ptr, unsigned l
+ static inline void
+ __set_psw_mask(unsigned long mask)
+ {
+- local_save_flags(mask);
+- __load_psw_mask(mask);
++ __load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
+ }
+
+ #define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS)
+diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h
+index fcd6c25..30e5cbe 100644
+--- a/include/asm-s390/timer.h
++++ b/include/asm-s390/timer.h
+@@ -26,7 +26,7 @@ struct vtimer_list {
+ spinlock_t lock;
+ unsigned long magic;
+
+- void (*function)(unsigned long, struct pt_regs*);
++ void (*function)(unsigned long);
+ unsigned long data;
+ };
+
+diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h
+index 5d0332a..4df4a41 100644
+--- a/include/asm-s390/timex.h
++++ b/include/asm-s390/timex.h
+@@ -15,20 +15,21 @@
+
+ typedef unsigned long long cycles_t;
+
+-static inline cycles_t get_cycles(void)
+-{
+- cycles_t cycles;
+-
+- __asm__ __volatile__ ("stck 0(%1)" : "=m" (cycles) : "a" (&cycles) : "cc");
+- return cycles >> 2;
+-}
+-
+ static inline unsigned long long get_clock (void)
+ {
+ unsigned long long clk;
+
+- __asm__ __volatile__ ("stck 0(%1)" : "=m" (clk) : "a" (&clk) : "cc");
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
++ asm volatile("stck %0" : "=Q" (clk) : : "cc");
++#else /* __GNUC__ */
++ asm volatile("stck 0(%1)" : "=m" (clk) : "a" (&clk) : "cc");
++#endif /* __GNUC__ */
+ return clk;
+ }
+
++static inline cycles_t get_cycles(void)
++{
++ return (cycles_t) get_clock() >> 2;
++}
++
+ #endif
+diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
+index 73cd85b..fa4dc91 100644
+--- a/include/asm-s390/tlbflush.h
++++ b/include/asm-s390/tlbflush.h
+@@ -25,7 +25,7 @@
+ */
+
+ #define local_flush_tlb() \
+-do { __asm__ __volatile__("ptlb": : :"memory"); } while (0)
++do { asm volatile("ptlb": : :"memory"); } while (0)
+
+ #ifndef CONFIG_SMP
+
+@@ -68,24 +68,24 @@ extern void smp_ptlb_all(void);
+
+ static inline void global_flush_tlb(void)
+ {
++ register unsigned long reg2 asm("2");
++ register unsigned long reg3 asm("3");
++ register unsigned long reg4 asm("4");
++ long dummy;
++
+ #ifndef __s390x__
+ if (!MACHINE_HAS_CSP) {
+ smp_ptlb_all();
+ return;
+ }
+ #endif /* __s390x__ */
+- {
+- register unsigned long addr asm("4");
+- long dummy;
+-
+- dummy = 0;
+- addr = ((unsigned long) &dummy) + 1;
+- __asm__ __volatile__ (
+- " slr 2,2\n"
+- " slr 3,3\n"
+- " csp 2,%0"
+- : : "a" (addr), "m" (dummy) : "cc", "2", "3" );
+- }
++
++ dummy = 0;
++ reg2 = reg3 = 0;
++ reg4 = ((unsigned long) &dummy) + 1;
++ asm volatile(
++ " csp %0,%2"
++ : : "d" (reg2), "d" (reg3), "d" (reg4), "m" (dummy) : "cc" );
+ }
+
+ /*
+@@ -102,9 +102,9 @@ static inline void __flush_tlb_mm(struct
+ if (unlikely(cpus_empty(mm->cpu_vm_mask)))
+ return;
+ if (MACHINE_HAS_IDTE) {
+- asm volatile (".insn rrf,0xb98e0000,0,%0,%1,0"
+- : : "a" (2048),
+- "a" (__pa(mm->pgd)&PAGE_MASK) : "cc" );
++ asm volatile(
++ " .insn rrf,0xb98e0000,0,%0,%1,0"
++ : : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc");
+ return;
+ }
+ preempt_disable();
+diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
+index 0b7c0ca..72ae4ef 100644
+--- a/include/asm-s390/uaccess.h
++++ b/include/asm-s390/uaccess.h
+@@ -38,25 +38,14 @@
+ #define get_ds() (KERNEL_DS)
+ #define get_fs() (current->thread.mm_segment)
+
+-#ifdef __s390x__
+ #define set_fs(x) \
+ ({ \
+ unsigned long __pto; \
+ current->thread.mm_segment = (x); \
+ __pto = current->thread.mm_segment.ar4 ? \
+ S390_lowcore.user_asce : S390_lowcore.kernel_asce; \
+- asm volatile ("lctlg 7,7,%0" : : "m" (__pto) ); \
++ __ctl_load(__pto, 7, 7); \
+ })
+-#else
+-#define set_fs(x) \
+-({ \
+- unsigned long __pto; \
+- current->thread.mm_segment = (x); \
+- __pto = current->thread.mm_segment.ar4 ? \
+- S390_lowcore.user_asce : S390_lowcore.kernel_asce; \
+- asm volatile ("lctl 7,7,%0" : : "m" (__pto) ); \
+-})
+-#endif
+
+ #define segment_eq(a,b) ((a).ar4 == (b).ar4)
+
+@@ -85,76 +74,51 @@ struct exception_table_entry
+ unsigned long insn, fixup;
+ };
+
+-#ifndef __s390x__
+-#define __uaccess_fixup \
+- ".section .fixup,\"ax\"\n" \
+- "2: lhi %0,%4\n" \
+- " bras 1,3f\n" \
+- " .long 1b\n" \
+- "3: l 1,0(1)\n" \
+- " br 1\n" \
+- ".previous\n" \
+- ".section __ex_table,\"a\"\n" \
+- " .align 4\n" \
+- " .long 0b,2b\n" \
+- ".previous"
+-#define __uaccess_clobber "cc", "1"
+-#else /* __s390x__ */
+-#define __uaccess_fixup \
+- ".section .fixup,\"ax\"\n" \
+- "2: lghi %0,%4\n" \
+- " jg 1b\n" \
+- ".previous\n" \
+- ".section __ex_table,\"a\"\n" \
+- " .align 8\n" \
+- " .quad 0b,2b\n" \
+- ".previous"
+-#define __uaccess_clobber "cc"
+-#endif /* __s390x__ */
++struct uaccess_ops {
++ size_t (*copy_from_user)(size_t, const void __user *, void *);
++ size_t (*copy_from_user_small)(size_t, const void __user *, void *);
++ size_t (*copy_to_user)(size_t, void __user *, const void *);
++ size_t (*copy_to_user_small)(size_t, void __user *, const void *);
++ size_t (*copy_in_user)(size_t, void __user *, const void __user *);
++ size_t (*clear_user)(size_t, void __user *);
++ size_t (*strnlen_user)(size_t, const char __user *);
++ size_t (*strncpy_from_user)(size_t, const char __user *, char *);
++ int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
++ int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
++};
++
++extern struct uaccess_ops uaccess;
++extern struct uaccess_ops uaccess_std;
++extern struct uaccess_ops uaccess_mvcos;
++
++static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
++{
++ size = uaccess.copy_to_user_small(size, ptr, x);
++ return size ? -EFAULT : size;
++}
++
++static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
++{
++ size = uaccess.copy_from_user_small(size, ptr, x);
++ return size ? -EFAULT : size;
++}
+
+ /*
+ * These are the main single-value transfer routines. They automatically
+ * use the right size if we just have the right pointer type.
+ */
+-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+-#define __put_user_asm(x, ptr, err) \
+-({ \
+- err = 0; \
+- asm volatile( \
+- "0: mvcs 0(%1,%2),%3,%0\n" \
+- "1:\n" \
+- __uaccess_fixup \
+- : "+&d" (err) \
+- : "d" (sizeof(*(ptr))), "a" (ptr), "Q" (x), \
+- "K" (-EFAULT) \
+- : __uaccess_clobber ); \
+-})
+-#else
+-#define __put_user_asm(x, ptr, err) \
+-({ \
+- err = 0; \
+- asm volatile( \
+- "0: mvcs 0(%1,%2),0(%3),%0\n" \
+- "1:\n" \
+- __uaccess_fixup \
+- : "+&d" (err) \
+- : "d" (sizeof(*(ptr))), "a" (ptr), "a" (&(x)), \
+- "K" (-EFAULT), "m" (x) \
+- : __uaccess_clobber ); \
+-})
+-#endif
+-
+ #define __put_user(x, ptr) \
+ ({ \
+ __typeof__(*(ptr)) __x = (x); \
+- int __pu_err; \
++ int __pu_err = -EFAULT; \
+ __chk_user_ptr(ptr); \
+ switch (sizeof (*(ptr))) { \
+ case 1: \
+ case 2: \
+ case 4: \
+ case 8: \
+- __put_user_asm(__x, ptr, __pu_err); \
++ __pu_err = __put_user_fn(sizeof (*(ptr)), \
++ ptr, &__x); \
+ break; \
+ default: \
+ __put_user_bad(); \
+@@ -172,60 +136,36 @@ struct exception_table_entry
+
+ extern int __put_user_bad(void) __attribute__((noreturn));
+
+-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+-#define __get_user_asm(x, ptr, err) \
+-({ \
+- err = 0; \
+- asm volatile ( \
+- "0: mvcp %O1(%2,%R1),0(%3),%0\n" \
+- "1:\n" \
+- __uaccess_fixup \
+- : "+&d" (err), "=Q" (x) \
+- : "d" (sizeof(*(ptr))), "a" (ptr), \
+- "K" (-EFAULT) \
+- : __uaccess_clobber ); \
+-})
+-#else
+-#define __get_user_asm(x, ptr, err) \
+-({ \
+- err = 0; \
+- asm volatile ( \
+- "0: mvcp 0(%2,%5),0(%3),%0\n" \
+- "1:\n" \
+- __uaccess_fixup \
+- : "+&d" (err), "=m" (x) \
+- : "d" (sizeof(*(ptr))), "a" (ptr), \
+- "K" (-EFAULT), "a" (&(x)) \
+- : __uaccess_clobber ); \
+-})
+-#endif
+-
+ #define __get_user(x, ptr) \
+ ({ \
+- int __gu_err; \
+- __chk_user_ptr(ptr); \
++ int __gu_err = -EFAULT; \
++ __chk_user_ptr(ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: { \
+ unsigned char __x; \
+- __get_user_asm(__x, ptr, __gu_err); \
++ __gu_err = __get_user_fn(sizeof (*(ptr)), \
++ ptr, &__x); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__x; \
+ break; \
+ }; \
+ case 2: { \
+ unsigned short __x; \
+- __get_user_asm(__x, ptr, __gu_err); \
++ __gu_err = __get_user_fn(sizeof (*(ptr)), \
++ ptr, &__x); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__x; \
+ break; \
+ }; \
+ case 4: { \
+ unsigned int __x; \
+- __get_user_asm(__x, ptr, __gu_err); \
++ __gu_err = __get_user_fn(sizeof (*(ptr)), \
++ ptr, &__x); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__x; \
+ break; \
+ }; \
+ case 8: { \
+ unsigned long long __x; \
+- __get_user_asm(__x, ptr, __gu_err); \
++ __gu_err = __get_user_fn(sizeof (*(ptr)), \
++ ptr, &__x); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__x; \
+ break; \
+ }; \
+@@ -247,8 +187,6 @@ extern int __get_user_bad(void) __attrib
+ #define __put_user_unaligned __put_user
+ #define __get_user_unaligned __get_user
+
+-extern long __copy_to_user_asm(const void *from, long n, void __user *to);
+-
+ /**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to: Destination address, in user space.
+@@ -266,7 +204,10 @@ extern long __copy_to_user_asm(const voi
+ static inline unsigned long
+ __copy_to_user(void __user *to, const void *from, unsigned long n)
+ {
+- return __copy_to_user_asm(from, n, to);
++ if (__builtin_constant_p(n) && (n <= 256))
++ return uaccess.copy_to_user_small(n, to, from);
++ else
++ return uaccess.copy_to_user(n, to, from);
+ }
+
+ #define __copy_to_user_inatomic __copy_to_user
+@@ -294,8 +235,6 @@ copy_to_user(void __user *to, const void
+ return n;
+ }
+
+-extern long __copy_from_user_asm(void *to, long n, const void __user *from);
+-
+ /**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to: Destination address, in kernel space.
+@@ -316,7 +255,10 @@ extern long __copy_from_user_asm(void *t
+ static inline unsigned long
+ __copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
+- return __copy_from_user_asm(to, n, from);
++ if (__builtin_constant_p(n) && (n <= 256))
++ return uaccess.copy_from_user_small(n, from, to);
++ else
++ return uaccess.copy_from_user(n, from, to);
+ }
+
+ /**
+@@ -346,13 +288,10 @@ copy_from_user(void *to, const void __us
+ return n;
+ }
+
+-extern unsigned long __copy_in_user_asm(const void __user *from, long n,
+- void __user *to);
+-
+ static inline unsigned long
+ __copy_in_user(void __user *to, const void __user *from, unsigned long n)
+ {
+- return __copy_in_user_asm(from, n, to);
++ return uaccess.copy_in_user(n, to, from);
+ }
+
+ static inline unsigned long
+@@ -360,34 +299,28 @@ copy_in_user(void __user *to, const void
+ {
+ might_sleep();
+ if (__access_ok(from,n) && __access_ok(to,n))
+- n = __copy_in_user_asm(from, n, to);
++ n = __copy_in_user(to, from, n);
+ return n;
+ }
+
+ /*
+ * Copy a null terminated string from userspace.
+ */
+-extern long __strncpy_from_user_asm(long count, char *dst,
+- const char __user *src);
+-
+ static inline long
+ strncpy_from_user(char *dst, const char __user *src, long count)
+ {
+ long res = -EFAULT;
+ might_sleep();
+ if (access_ok(VERIFY_READ, src, 1))
+- res = __strncpy_from_user_asm(count, dst, src);
++ res = uaccess.strncpy_from_user(count, src, dst);
+ return res;
+ }
+
+-
+-extern long __strnlen_user_asm(long count, const char __user *src);
+-
+ static inline unsigned long
+ strnlen_user(const char __user * src, unsigned long n)
+ {
+ might_sleep();
+- return __strnlen_user_asm(n, src);
++ return uaccess.strnlen_user(n, src);
+ }
+
+ /**
+@@ -410,12 +343,10 @@ strnlen_user(const char __user * src, un
+ * Zero Userspace
+ */
+
+-extern long __clear_user_asm(void __user *to, long n);
+-
+ static inline unsigned long
+ __clear_user(void __user *to, unsigned long n)
+ {
+- return __clear_user_asm(to, n);
++ return uaccess.clear_user(n, to);
+ }
+
+ static inline unsigned long
+@@ -423,7 +354,7 @@ clear_user(void __user *to, unsigned lon
+ {
+ might_sleep();
+ if (access_ok(VERIFY_WRITE, to, n))
+- n = __clear_user_asm(to, n);
++ n = uaccess.clear_user(n, to);
+ return n;
+ }
+
+diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
+index aa7a243..71d3c21 100644
+--- a/include/asm-s390/unistd.h
++++ b/include/asm-s390/unistd.h
+@@ -25,17 +25,12 @@
+ #define __NR_unlink 10
+ #define __NR_execve 11
+ #define __NR_chdir 12
+-#define __NR_time 13
+ #define __NR_mknod 14
+ #define __NR_chmod 15
+-#define __NR_lchown 16
+ #define __NR_lseek 19
+ #define __NR_getpid 20
+ #define __NR_mount 21
+ #define __NR_umount 22
+-#define __NR_setuid 23
+-#define __NR_getuid 24
+-#define __NR_stime 25
+ #define __NR_ptrace 26
+ #define __NR_alarm 27
+ #define __NR_pause 29
+@@ -51,11 +46,7 @@
+ #define __NR_pipe 42
+ #define __NR_times 43
+ #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_umount2 52
+ #define __NR_ioctl 54
+@@ -69,18 +60,13 @@
+ #define __NR_getpgrp 65
+ #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
+ #define __NR_getrusage 77
+ #define __NR_gettimeofday 78
+ #define __NR_settimeofday 79
+-#define __NR_getgroups 80
+-#define __NR_setgroups 81
+ #define __NR_symlink 83
+ #define __NR_readlink 85
+ #define __NR_uselib 86
+@@ -92,12 +78,10 @@
+ #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_statfs 99
+ #define __NR_fstatfs 100
+-#define __NR_ioperm 101
+ #define __NR_socketcall 102
+ #define __NR_syslog 103
+ #define __NR_setitimer 104
+@@ -131,11 +115,7 @@
+ #define __NR_sysfs 135
+ #define __NR_personality 136
+ #define __NR_afs_syscall 137 /* Syscall for Andrew File System */
+-#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
+@@ -157,13 +137,9 @@
+ #define __NR_sched_rr_get_interval 161
+ #define __NR_nanosleep 162
+ #define __NR_mremap 163
+-#define __NR_setresuid 164
+-#define __NR_getresuid 165
+ #define __NR_query_module 167
+ #define __NR_poll 168
+ #define __NR_nfsservctl 169
+-#define __NR_setresgid 170
+-#define __NR_getresgid 171
+ #define __NR_prctl 172
+ #define __NR_rt_sigreturn 173
+ #define __NR_rt_sigaction 174
+@@ -174,7 +150,6 @@
+ #define __NR_rt_sigsuspend 179
+ #define __NR_pread64 180
+ #define __NR_pwrite64 181
+-#define __NR_chown 182
+ #define __NR_getcwd 183
+ #define __NR_capget 184
+ #define __NR_capset 185
+@@ -183,39 +158,11 @@
+ #define __NR_getpmsg 188
+ #define __NR_putpmsg 189
+ #define __NR_vfork 190
+-#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
+-#define __NR_mmap2 192
+-#define __NR_truncate64 193
+-#define __NR_ftruncate64 194
+-#define __NR_stat64 195
+-#define __NR_lstat64 196
+-#define __NR_fstat64 197
+-#define __NR_lchown32 198
+-#define __NR_getuid32 199
+-#define __NR_getgid32 200
+-#define __NR_geteuid32 201
+-#define __NR_getegid32 202
+-#define __NR_setreuid32 203
+-#define __NR_setregid32 204
+-#define __NR_getgroups32 205
+-#define __NR_setgroups32 206
+-#define __NR_fchown32 207
+-#define __NR_setresuid32 208
+-#define __NR_getresuid32 209
+-#define __NR_setresgid32 210
+-#define __NR_getresgid32 211
+-#define __NR_chown32 212
+-#define __NR_setuid32 213
+-#define __NR_setgid32 214
+-#define __NR_setfsuid32 215
+-#define __NR_setfsgid32 216
+ #define __NR_pivot_root 217
+ #define __NR_mincore 218
+ #define __NR_madvise 219
+ #define __NR_getdents64 220
+-#define __NR_fcntl64 221
+ #define __NR_readahead 222
+-#define __NR_sendfile64 223
+ #define __NR_setxattr 224
+ #define __NR_lsetxattr 225
+ #define __NR_fsetxattr 226
+@@ -256,7 +203,6 @@
+ #define __NR_clock_getres (__NR_timer_create+7)
+ #define __NR_clock_nanosleep (__NR_timer_create+8)
+ /* Number 263 is reserved for vserver */
+-#define __NR_fadvise64_64 264
+ #define __NR_statfs64 265
+ #define __NR_fstatfs64 266
+ #define __NR_remap_file_pages 267
+@@ -285,7 +231,6 @@
+ #define __NR_mknodat 290
+ #define __NR_fchownat 291
+ #define __NR_futimesat 292
+-#define __NR_fstatat64 293
+ #define __NR_unlinkat 294
+ #define __NR_renameat 295
+ #define __NR_linkat 296
+@@ -302,70 +247,76 @@
+ #define __NR_sync_file_range 307
+ #define __NR_tee 308
+ #define __NR_vmsplice 309
++/* Number 310 is reserved for new sys_move_pages */
++#define __NR_getcpu 311
++#define __NR_epoll_pwait 312
+
+-#define NR_syscalls 310
++#define NR_syscalls 313
+
+ /*
+ * There are some system calls that are not present on 64 bit, some
+ * have a different name although they do the same (e.g. __NR_chown32
+ * is __NR_chown on 64 bit).
+ */
+-#ifdef __s390x__
+-#undef __NR_time
+-#undef __NR_lchown
+-#undef __NR_setuid
+-#undef __NR_getuid
+-#undef __NR_stime
+-#undef __NR_setgid
+-#undef __NR_getgid
+-#undef __NR_geteuid
+-#undef __NR_getegid
+-#undef __NR_setreuid
+-#undef __NR_setregid
+-#undef __NR_getrlimit
+-#undef __NR_getgroups
+-#undef __NR_setgroups
+-#undef __NR_fchown
+-#undef __NR_ioperm
+-#undef __NR_setfsuid
+-#undef __NR_setfsgid
+-#undef __NR__llseek
+-#undef __NR__newselect
+-#undef __NR_setresuid
+-#undef __NR_getresuid
+-#undef __NR_setresgid
+-#undef __NR_getresgid
+-#undef __NR_chown
+-#undef __NR_ugetrlimit
+-#undef __NR_mmap2
+-#undef __NR_truncate64
+-#undef __NR_ftruncate64
+-#undef __NR_stat64
+-#undef __NR_lstat64
+-#undef __NR_fstat64
+-#undef __NR_lchown32
+-#undef __NR_getuid32
+-#undef __NR_getgid32
+-#undef __NR_geteuid32
+-#undef __NR_getegid32
+-#undef __NR_setreuid32
+-#undef __NR_setregid32
+-#undef __NR_getgroups32
+-#undef __NR_setgroups32
+-#undef __NR_fchown32
+-#undef __NR_setresuid32
+-#undef __NR_getresuid32
+-#undef __NR_setresgid32
+-#undef __NR_getresgid32
+-#undef __NR_chown32
+-#undef __NR_setuid32
+-#undef __NR_setgid32
+-#undef __NR_setfsuid32
+-#undef __NR_setfsgid32
+-#undef __NR_fcntl64
+-#undef __NR_sendfile64
+-#undef __NR_fadvise64_64
+-#undef __NR_fstatat64
++#ifndef __s390x__
++
++#define __NR_time 13
++#define __NR_lchown 16
++#define __NR_setuid 23
++#define __NR_getuid 24
++#define __NR_stime 25
++#define __NR_setgid 46
++#define __NR_getgid 47
++#define __NR_geteuid 49
++#define __NR_getegid 50
++#define __NR_setreuid 70
++#define __NR_setregid 71
++#define __NR_getrlimit 76
++#define __NR_getgroups 80
++#define __NR_setgroups 81
++#define __NR_fchown 95
++#define __NR_ioperm 101
++#define __NR_setfsuid 138
++#define __NR_setfsgid 139
++#define __NR__llseek 140
++#define __NR__newselect 142
++#define __NR_setresuid 164
++#define __NR_getresuid 165
++#define __NR_setresgid 170
++#define __NR_getresgid 171
++#define __NR_chown 182
++#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
++#define __NR_mmap2 192
++#define __NR_truncate64 193
++#define __NR_ftruncate64 194
++#define __NR_stat64 195
++#define __NR_lstat64 196
++#define __NR_fstat64 197
++#define __NR_lchown32 198
++#define __NR_getuid32 199
++#define __NR_getgid32 200
++#define __NR_geteuid32 201
++#define __NR_getegid32 202
++#define __NR_setreuid32 203
++#define __NR_setregid32 204
++#define __NR_getgroups32 205
++#define __NR_setgroups32 206
++#define __NR_fchown32 207
++#define __NR_setresuid32 208
++#define __NR_getresuid32 209
++#define __NR_setresgid32 210
++#define __NR_getresgid32 211
++#define __NR_chown32 212
++#define __NR_setuid32 213
++#define __NR_setgid32 214
++#define __NR_setfsuid32 215
++#define __NR_setfsgid32 216
++#define __NR_fcntl64 221
++#define __NR_sendfile64 223
++#define __NR_fadvise64_64 264
++#define __NR_fstatat64 293
++
++#else
+
+ #define __NR_select 142
+ #define __NR_getrlimit 191 /* SuS compliant getrlimit */
+@@ -394,9 +345,11 @@
+
+ #ifdef __KERNEL__
+
++#include <linux/err.h>
++
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-4095)) {\
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ errno = -(res); \
+ res = -1; \
+ } \
+@@ -405,145 +358,145 @@ do { \
+
+ #define _svc_clobber "1", "cc", "memory"
+
+-#define _syscall0(type,name) \
+-type name(void) { \
+- register long __svcres asm("2"); \
+- long __res; \
+- __asm__ __volatile__ ( \
+- " .if %1 < 256\n" \
+- " svc %b1\n" \
+- " .else\n" \
+- " la %%r1,%1\n" \
+- " svc 0\n" \
+- " .endif" \
+- : "=d" (__svcres) \
+- : "i" (__NR_##name) \
+- : _svc_clobber ); \
+- __res = __svcres; \
+- __syscall_return(type,__res); \
++#define _syscall0(type,name) \
++type name(void) { \
++ register long __svcres asm("2"); \
++ long __res; \
++ asm volatile( \
++ " .if %1 < 256\n" \
++ " svc %b1\n" \
++ " .else\n" \
++ " la %%r1,%1\n" \
++ " svc 0\n" \
++ " .endif" \
++ : "=d" (__svcres) \
++ : "i" (__NR_##name) \
++ : _svc_clobber); \
++ __res = __svcres; \
++ __syscall_return(type,__res); \
+ }
+
+-#define _syscall1(type,name,type1,arg1) \
+-type name(type1 arg1) { \
+- register type1 __arg1 asm("2") = arg1; \
+- register long __svcres asm("2"); \
+- long __res; \
+- __asm__ __volatile__ ( \
+- " .if %1 < 256\n" \
+- " svc %b1\n" \
+- " .else\n" \
+- " la %%r1,%1\n" \
+- " svc 0\n" \
+- " .endif" \
+- : "=d" (__svcres) \
+- : "i" (__NR_##name), \
+- "0" (__arg1) \
+- : _svc_clobber ); \
+- __res = __svcres; \
+- __syscall_return(type,__res); \
++#define _syscall1(type,name,type1,arg1) \
++type name(type1 arg1) { \
++ register type1 __arg1 asm("2") = arg1; \
++ register long __svcres asm("2"); \
++ long __res; \
++ asm volatile( \
++ " .if %1 < 256\n" \
++ " svc %b1\n" \
++ " .else\n" \
++ " la %%r1,%1\n" \
++ " svc 0\n" \
++ " .endif" \
++ : "=d" (__svcres) \
++ : "i" (__NR_##name), \
++ "0" (__arg1) \
++ : _svc_clobber); \
++ __res = __svcres; \
++ __syscall_return(type,__res); \
+ }
+
+-#define _syscall2(type,name,type1,arg1,type2,arg2) \
+-type name(type1 arg1, type2 arg2) { \
+- register type1 __arg1 asm("2") = arg1; \
+- register type2 __arg2 asm("3") = arg2; \
+- register long __svcres asm("2"); \
+- long __res; \
+- __asm__ __volatile__ ( \
+- " .if %1 < 256\n" \
+- " svc %b1\n" \
+- " .else\n" \
+- " la %%r1,%1\n" \
+- " svc 0\n" \
+- " .endif" \
+- : "=d" (__svcres) \
+- : "i" (__NR_##name), \
+- "0" (__arg1), \
+- "d" (__arg2) \
+- : _svc_clobber ); \
+- __res = __svcres; \
+- __syscall_return(type,__res); \
++#define _syscall2(type,name,type1,arg1,type2,arg2) \
++type name(type1 arg1, type2 arg2) { \
++ register type1 __arg1 asm("2") = arg1; \
++ register type2 __arg2 asm("3") = arg2; \
++ register long __svcres asm("2"); \
++ long __res; \
++ asm volatile( \
++ " .if %1 < 256\n" \
++ " svc %b1\n" \
++ " .else\n" \
++ " la %%r1,%1\n" \
++ " svc 0\n" \
++ " .endif" \
++ : "=d" (__svcres) \
++ : "i" (__NR_##name), \
++ "0" (__arg1), \
++ "d" (__arg2) \
++ : _svc_clobber ); \
++ __res = __svcres; \
++ __syscall_return(type,__res); \
+ }
+
+-#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)\
+-type name(type1 arg1, type2 arg2, type3 arg3) { \
+- register type1 __arg1 asm("2") = arg1; \
+- register type2 __arg2 asm("3") = arg2; \
+- register type3 __arg3 asm("4") = arg3; \
+- register long __svcres asm("2"); \
+- long __res; \
+- __asm__ __volatile__ ( \
+- " .if %1 < 256\n" \
+- " svc %b1\n" \
+- " .else\n" \
+- " la %%r1,%1\n" \
+- " svc 0\n" \
+- " .endif" \
+- : "=d" (__svcres) \
+- : "i" (__NR_##name), \
+- "0" (__arg1), \
+- "d" (__arg2), \
+- "d" (__arg3) \
+- : _svc_clobber ); \
+- __res = __svcres; \
+- __syscall_return(type,__res); \
++#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
++type name(type1 arg1, type2 arg2, type3 arg3) { \
++ register type1 __arg1 asm("2") = arg1; \
++ register type2 __arg2 asm("3") = arg2; \
++ register type3 __arg3 asm("4") = arg3; \
++ register long __svcres asm("2"); \
++ long __res; \
++ asm volatile( \
++ " .if %1 < 256\n" \
++ " svc %b1\n" \
++ " .else\n" \
++ " la %%r1,%1\n" \
++ " svc 0\n" \
++ " .endif" \
++ : "=d" (__svcres) \
++ : "i" (__NR_##name), \
++ "0" (__arg1), \
++ "d" (__arg2), \
++ "d" (__arg3) \
++ : _svc_clobber); \
++ __res = __svcres; \
++ __syscall_return(type,__res); \
+ }
+
+-#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,\
+- type4,name4) \
+-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+- register type1 __arg1 asm("2") = arg1; \
+- register type2 __arg2 asm("3") = arg2; \
+- register type3 __arg3 asm("4") = arg3; \
+- register type4 __arg4 asm("5") = arg4; \
+- register long __svcres asm("2"); \
+- long __res; \
+- __asm__ __volatile__ ( \
+- " .if %1 < 256\n" \
+- " svc %b1\n" \
+- " .else\n" \
+- " la %%r1,%1\n" \
+- " svc 0\n" \
+- " .endif" \
+- : "=d" (__svcres) \
+- : "i" (__NR_##name), \
+- "0" (__arg1), \
+- "d" (__arg2), \
+- "d" (__arg3), \
+- "d" (__arg4) \
+- : _svc_clobber ); \
+- __res = __svcres; \
+- __syscall_return(type,__res); \
++#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3, \
++ type4,name4) \
++type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
++ register type1 __arg1 asm("2") = arg1; \
++ register type2 __arg2 asm("3") = arg2; \
++ register type3 __arg3 asm("4") = arg3; \
++ register type4 __arg4 asm("5") = arg4; \
++ register long __svcres asm("2"); \
++ long __res; \
++ asm volatile( \
++ " .if %1 < 256\n" \
++ " svc %b1\n" \
++ " .else\n" \
++ " la %%r1,%1\n" \
++ " svc 0\n" \
++ " .endif" \
++ : "=d" (__svcres) \
++ : "i" (__NR_##name), \
++ "0" (__arg1), \
++ "d" (__arg2), \
++ "d" (__arg3), \
++ "d" (__arg4) \
++ : _svc_clobber); \
++ __res = __svcres; \
++ __syscall_return(type,__res); \
+ }
+
+-#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,\
+- type4,name4,type5,name5) \
+-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+- type5 arg5) { \
+- register type1 __arg1 asm("2") = arg1; \
+- register type2 __arg2 asm("3") = arg2; \
+- register type3 __arg3 asm("4") = arg3; \
+- register type4 __arg4 asm("5") = arg4; \
+- register type5 __arg5 asm("6") = arg5; \
+- register long __svcres asm("2"); \
+- long __res; \
+- __asm__ __volatile__ ( \
+- " .if %1 < 256\n" \
+- " svc %b1\n" \
+- " .else\n" \
+- " la %%r1,%1\n" \
+- " svc 0\n" \
+- " .endif" \
+- : "=d" (__svcres) \
+- : "i" (__NR_##name), \
+- "0" (__arg1), \
+- "d" (__arg2), \
+- "d" (__arg3), \
+- "d" (__arg4), \
+- "d" (__arg5) \
+- : _svc_clobber ); \
+- __res = __svcres; \
+- __syscall_return(type,__res); \
++#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \
++ type4,name4,type5,name5) \
++type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
++ type5 arg5) { \
++ register type1 __arg1 asm("2") = arg1; \
++ register type2 __arg2 asm("3") = arg2; \
++ register type3 __arg3 asm("4") = arg3; \
++ register type4 __arg4 asm("5") = arg4; \
++ register type5 __arg5 asm("6") = arg5; \
++ register long __svcres asm("2"); \
++ long __res; \
++ asm volatile( \
++ " .if %1 < 256\n" \
++ " svc %b1\n" \
++ " .else\n" \
++ " la %%r1,%1\n" \
++ " svc 0\n" \
++ " .endif" \
++ : "=d" (__svcres) \
++ : "i" (__NR_##name), \
++ "0" (__arg1), \
++ "d" (__arg2), \
++ "d" (__arg3), \
++ "d" (__arg4), \
++ "d" (__arg5) \
++ : _svc_clobber); \
++ __res = __svcres; \
++ __syscall_return(type,__res); \
+ }
+
+ #define __ARCH_WANT_IPC_PARSE_VERSION
+@@ -573,57 +526,6 @@ type name(type1 arg1, type2 arg2, type3
+ # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
+ # endif
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <asm/ptrace.h>
+-#include <asm/stat.h>
+-#include <linux/syscalls.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static inline _syscall0(pid_t,setsid)
+-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static inline _syscall1(int,dup,int,fd)
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+-static inline _syscall1(int,close,int,fd)
+-static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf)
+-
+-static inline pid_t waitpid(int pid, int *wait_stat, int flags)
+-{
+- return sys_wait4(pid, wait_stat, flags, NULL);
+-}
+-struct mmap_arg_struct;
+-asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg);
+-
+-asmlinkage long sys_execve(struct pt_regs regs);
+-asmlinkage long sys_clone(struct pt_regs regs);
+-asmlinkage long sys_fork(struct pt_regs regs);
+-asmlinkage long sys_vfork(struct pt_regs regs);
+-asmlinkage long sys_pipe(unsigned long __user *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-s390/z90crypt.h b/include/asm-s390/z90crypt.h
+deleted file mode 100644
+index 31a2439..0000000
+--- a/include/asm-s390/z90crypt.h
++++ /dev/null
+@@ -1,212 +0,0 @@
+-/*
+- * include/asm-s390/z90crypt.h
+- *
+- * z90crypt 1.3.3 (user-visible header)
+- *
+- * Copyright (C) 2001, 2005 IBM Corporation
+- * Author(s): Robert Burroughs
+- * Eric Rossman (edrossma at us.ibm.com)
+- *
+- * Hotplug & misc device support: Jochen Roehrig (roehrig at de.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, 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 __ASM_S390_Z90CRYPT_H
+-#define __ASM_S390_Z90CRYPT_H
+-#include <linux/ioctl.h>
+-
+-#define z90crypt_VERSION 1
+-#define z90crypt_RELEASE 3 // 2 = PCIXCC, 3 = rewrite for coding standards
+-#define z90crypt_VARIANT 3 // 3 = CEX2A support
+-
+-/**
+- * struct ica_rsa_modexpo
+- *
+- * Requirements:
+- * - outputdatalength is at least as large as inputdatalength.
+- * - All key parts are right justified in their fields, padded on
+- * the left with zeroes.
+- * - length(b_key) = inputdatalength
+- * - length(n_modulus) = inputdatalength
+- */
+-struct ica_rsa_modexpo {
+- char __user * inputdata;
+- unsigned int inputdatalength;
+- char __user * outputdata;
+- unsigned int outputdatalength;
+- char __user * b_key;
+- char __user * n_modulus;
+-};
+-
+-/**
+- * struct ica_rsa_modexpo_crt
+- *
+- * Requirements:
+- * - inputdatalength is even.
+- * - outputdatalength is at least as large as inputdatalength.
+- * - All key parts are right justified in their fields, padded on
+- * the left with zeroes.
+- * - length(bp_key) = inputdatalength/2 + 8
+- * - length(bq_key) = inputdatalength/2
+- * - length(np_key) = inputdatalength/2 + 8
+- * - length(nq_key) = inputdatalength/2
+- * - length(u_mult_inv) = inputdatalength/2 + 8
+- */
+-struct ica_rsa_modexpo_crt {
+- char __user * inputdata;
+- unsigned int inputdatalength;
+- char __user * outputdata;
+- unsigned int outputdatalength;
+- char __user * bp_key;
+- char __user * bq_key;
+- char __user * np_prime;
+- char __user * nq_prime;
+- char __user * u_mult_inv;
+-};
+-
+-#define Z90_IOCTL_MAGIC 'z' // NOTE: Need to allocate from linux folks
+-
+-/**
+- * Interface notes:
+- *
+- * The ioctl()s which are implemented (along with relevant details)
+- * are:
+- *
+- * ICARSAMODEXPO
+- * Perform an RSA operation using a Modulus-Exponent pair
+- * This takes an ica_rsa_modexpo struct as its arg.
+- *
+- * NOTE: please refer to the comments preceding this structure
+- * for the implementation details for the contents of the
+- * block
+- *
+- * ICARSACRT
+- * Perform an RSA operation using a Chinese-Remainder Theorem key
+- * This takes an ica_rsa_modexpo_crt struct as its arg.
+- *
+- * NOTE: please refer to the comments preceding this structure
+- * for the implementation details for the contents of the
+- * block
+- *
+- * Z90STAT_TOTALCOUNT
+- * Return an integer count of all device types together.
+- *
+- * Z90STAT_PCICACOUNT
+- * Return an integer count of all PCICAs.
+- *
+- * Z90STAT_PCICCCOUNT
+- * Return an integer count of all PCICCs.
+- *
+- * Z90STAT_PCIXCCMCL2COUNT
+- * Return an integer count of all MCL2 PCIXCCs.
+- *
+- * Z90STAT_PCIXCCMCL3COUNT
+- * Return an integer count of all MCL3 PCIXCCs.
+- *
+- * Z90STAT_CEX2CCOUNT
+- * Return an integer count of all CEX2Cs.
+- *
+- * Z90STAT_CEX2ACOUNT
+- * Return an integer count of all CEX2As.
+- *
+- * Z90STAT_REQUESTQ_COUNT
+- * Return an integer count of the number of entries waiting to be
+- * sent to a device.
+- *
+- * Z90STAT_PENDINGQ_COUNT
+- * Return an integer count of the number of entries sent to a
+- * device awaiting the reply.
+- *
+- * Z90STAT_TOTALOPEN_COUNT
+- * Return an integer count of the number of open file handles.
+- *
+- * Z90STAT_DOMAIN_INDEX
+- * Return the integer value of the Cryptographic Domain.
+- *
+- * Z90STAT_STATUS_MASK
+- * Return an 64 element array of unsigned chars for the status of
+- * all devices.
+- * 0x01: PCICA
+- * 0x02: PCICC
+- * 0x03: PCIXCC_MCL2
+- * 0x04: PCIXCC_MCL3
+- * 0x05: CEX2C
+- * 0x06: CEX2A
+- * 0x0d: device is disabled via the proc filesystem
+- *
+- * Z90STAT_QDEPTH_MASK
+- * Return an 64 element array of unsigned chars for the queue
+- * depth of all devices.
+- *
+- * Z90STAT_PERDEV_REQCNT
+- * Return an 64 element array of unsigned integers for the number
+- * of successfully completed requests per device since the device
+- * was detected and made available.
+- *
+- * ICAZ90STATUS (deprecated)
+- * Return some device driver status in a ica_z90_status struct
+- * This takes an ica_z90_status struct as its arg.
+- *
+- * NOTE: this ioctl() is deprecated, and has been replaced with
+- * single ioctl()s for each type of status being requested
+- *
+- * Z90STAT_PCIXCCCOUNT (deprecated)
+- * Return an integer count of all PCIXCCs (MCL2 + MCL3).
+- * This is DEPRECATED now that MCL3 PCIXCCs are treated differently from
+- * MCL2 PCIXCCs.
+- *
+- * Z90QUIESCE (not recommended)
+- * Quiesce the driver. This is intended to stop all new
+- * requests from being processed. Its use is NOT recommended,
+- * except in circumstances where there is no other way to stop
+- * callers from accessing the driver. Its original use was to
+- * allow the driver to be "drained" of work in preparation for
+- * a system shutdown.
+- *
+- * NOTE: once issued, this ban on new work cannot be undone
+- * except by unloading and reloading the driver.
+- */
+-
+-/**
+- * Supported ioctl calls
+- */
+-#define ICARSAMODEXPO _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x05, 0)
+-#define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x06, 0)
+-
+-/* DEPRECATED status calls (bound for removal at some point) */
+-#define ICAZ90STATUS _IOR(Z90_IOCTL_MAGIC, 0x10, struct ica_z90_status)
+-#define Z90STAT_PCIXCCCOUNT _IOR(Z90_IOCTL_MAGIC, 0x43, int)
+-
+-/* unrelated to ICA callers */
+-#define Z90QUIESCE _IO(Z90_IOCTL_MAGIC, 0x11)
+-
+-/* New status calls */
+-#define Z90STAT_TOTALCOUNT _IOR(Z90_IOCTL_MAGIC, 0x40, int)
+-#define Z90STAT_PCICACOUNT _IOR(Z90_IOCTL_MAGIC, 0x41, int)
+-#define Z90STAT_PCICCCOUNT _IOR(Z90_IOCTL_MAGIC, 0x42, int)
+-#define Z90STAT_PCIXCCMCL2COUNT _IOR(Z90_IOCTL_MAGIC, 0x4b, int)
+-#define Z90STAT_PCIXCCMCL3COUNT _IOR(Z90_IOCTL_MAGIC, 0x4c, int)
+-#define Z90STAT_CEX2CCOUNT _IOR(Z90_IOCTL_MAGIC, 0x4d, int)
+-#define Z90STAT_CEX2ACOUNT _IOR(Z90_IOCTL_MAGIC, 0x4e, int)
+-#define Z90STAT_REQUESTQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x44, int)
+-#define Z90STAT_PENDINGQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x45, int)
+-#define Z90STAT_TOTALOPEN_COUNT _IOR(Z90_IOCTL_MAGIC, 0x46, int)
+-#define Z90STAT_DOMAIN_INDEX _IOR(Z90_IOCTL_MAGIC, 0x47, int)
+-#define Z90STAT_STATUS_MASK _IOR(Z90_IOCTL_MAGIC, 0x48, char[64])
+-#define Z90STAT_QDEPTH_MASK _IOR(Z90_IOCTL_MAGIC, 0x49, char[64])
+-#define Z90STAT_PERDEV_REQCNT _IOR(Z90_IOCTL_MAGIC, 0x4a, int[64])
+-
+-#endif /* __ASM_S390_Z90CRYPT_H */
+diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h
+new file mode 100644
+index 0000000..7244c68
+--- /dev/null
++++ b/include/asm-s390/zcrypt.h
+@@ -0,0 +1,285 @@
++/*
++ * include/asm-s390/zcrypt.h
++ *
++ * zcrypt 2.1.0 (user-visible header)
++ *
++ * Copyright (C) 2001, 2006 IBM Corporation
++ * Author(s): Robert Burroughs
++ * Eric Rossman (edrossma at us.ibm.com)
++ *
++ * Hotplug & misc device support: Jochen Roehrig (roehrig at de.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, 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 __ASM_S390_ZCRYPT_H
++#define __ASM_S390_ZCRYPT_H
++
++#define ZCRYPT_VERSION 2
++#define ZCRYPT_RELEASE 1
++#define ZCRYPT_VARIANT 0
++
++#include <linux/ioctl.h>
++#include <linux/compiler.h>
++
++/**
++ * struct ica_rsa_modexpo
++ *
++ * Requirements:
++ * - outputdatalength is at least as large as inputdatalength.
++ * - All key parts are right justified in their fields, padded on
++ * the left with zeroes.
++ * - length(b_key) = inputdatalength
++ * - length(n_modulus) = inputdatalength
++ */
++struct ica_rsa_modexpo {
++ char __user * inputdata;
++ unsigned int inputdatalength;
++ char __user * outputdata;
++ unsigned int outputdatalength;
++ char __user * b_key;
++ char __user * n_modulus;
++};
++
++/**
++ * struct ica_rsa_modexpo_crt
++ *
++ * Requirements:
++ * - inputdatalength is even.
++ * - outputdatalength is at least as large as inputdatalength.
++ * - All key parts are right justified in their fields, padded on
++ * the left with zeroes.
++ * - length(bp_key) = inputdatalength/2 + 8
++ * - length(bq_key) = inputdatalength/2
++ * - length(np_key) = inputdatalength/2 + 8
++ * - length(nq_key) = inputdatalength/2
++ * - length(u_mult_inv) = inputdatalength/2 + 8
++ */
++struct ica_rsa_modexpo_crt {
++ char __user * inputdata;
++ unsigned int inputdatalength;
++ char __user * outputdata;
++ unsigned int outputdatalength;
++ char __user * bp_key;
++ char __user * bq_key;
++ char __user * np_prime;
++ char __user * nq_prime;
++ char __user * u_mult_inv;
++};
++
++/**
++ * CPRBX
++ * Note that all shorts and ints are big-endian.
++ * All pointer fields are 16 bytes long, and mean nothing.
++ *
++ * A request CPRB is followed by a request_parameter_block.
++ *
++ * The request (or reply) parameter block is organized thus:
++ * function code
++ * VUD block
++ * key block
++ */
++struct ica_CPRBX {
++ unsigned short cprb_len; /* CPRB length 220 */
++ unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
++ unsigned char pad_000[3]; /* Alignment pad bytes */
++ unsigned char func_id[2]; /* function id 0x5432 */
++ unsigned char cprb_flags[4]; /* Flags */
++ unsigned int req_parml; /* request parameter buffer len */
++ unsigned int req_datal; /* request data buffer */
++ unsigned int rpl_msgbl; /* reply message block length */
++ unsigned int rpld_parml; /* replied parameter block len */
++ unsigned int rpl_datal; /* reply data block len */
++ unsigned int rpld_datal; /* replied data block len */
++ unsigned int req_extbl; /* request extension block len */
++ unsigned char pad_001[4]; /* reserved */
++ unsigned int rpld_extbl; /* replied extension block len */
++ unsigned char padx000[16 - sizeof (char *)];
++ unsigned char * req_parmb; /* request parm block 'address' */
++ unsigned char padx001[16 - sizeof (char *)];
++ unsigned char * req_datab; /* request data block 'address' */
++ unsigned char padx002[16 - sizeof (char *)];
++ unsigned char * rpl_parmb; /* reply parm block 'address' */
++ unsigned char padx003[16 - sizeof (char *)];
++ unsigned char * rpl_datab; /* reply data block 'address' */
++ unsigned char padx004[16 - sizeof (char *)];
++ unsigned char * req_extb; /* request extension block 'addr'*/
++ unsigned char padx005[16 - sizeof (char *)];
++ unsigned char * rpl_extb; /* reply extension block 'addres'*/
++ unsigned short ccp_rtcode; /* server return code */
++ unsigned short ccp_rscode; /* server reason code */
++ unsigned int mac_data_len; /* Mac Data Length */
++ unsigned char logon_id[8]; /* Logon Identifier */
++ unsigned char mac_value[8]; /* Mac Value */
++ unsigned char mac_content_flgs;/* Mac content flag byte */
++ unsigned char pad_002; /* Alignment */
++ unsigned short domain; /* Domain */
++ unsigned char usage_domain[4];/* Usage domain */
++ unsigned char cntrl_domain[4];/* Control domain */
++ unsigned char S390enf_mask[4];/* S/390 enforcement mask */
++ unsigned char pad_004[36]; /* reserved */
++};
++
++/**
++ * xcRB
++ */
++struct ica_xcRB {
++ unsigned short agent_ID;
++ unsigned int user_defined;
++ unsigned short request_ID;
++ unsigned int request_control_blk_length;
++ unsigned char padding1[16 - sizeof (char *)];
++ char __user * request_control_blk_addr;
++ unsigned int request_data_length;
++ char padding2[16 - sizeof (char *)];
++ char __user * request_data_address;
++ unsigned int reply_control_blk_length;
++ char padding3[16 - sizeof (char *)];
++ char __user * reply_control_blk_addr;
++ unsigned int reply_data_length;
++ char padding4[16 - sizeof (char *)];
++ char __user * reply_data_addr;
++ unsigned short priority_window;
++ unsigned int status;
++} __attribute__((packed));
++#define AUTOSELECT ((unsigned int)0xFFFFFFFF)
++
++#define ZCRYPT_IOCTL_MAGIC 'z'
++
++/**
++ * Interface notes:
++ *
++ * The ioctl()s which are implemented (along with relevant details)
++ * are:
++ *
++ * ICARSAMODEXPO
++ * Perform an RSA operation using a Modulus-Exponent pair
++ * This takes an ica_rsa_modexpo struct as its arg.
++ *
++ * NOTE: please refer to the comments preceding this structure
++ * for the implementation details for the contents of the
++ * block
++ *
++ * ICARSACRT
++ * Perform an RSA operation using a Chinese-Remainder Theorem key
++ * This takes an ica_rsa_modexpo_crt struct as its arg.
++ *
++ * NOTE: please refer to the comments preceding this structure
++ * for the implementation details for the contents of the
++ * block
++ *
++ * Z90STAT_TOTALCOUNT
++ * Return an integer count of all device types together.
++ *
++ * Z90STAT_PCICACOUNT
++ * Return an integer count of all PCICAs.
++ *
++ * Z90STAT_PCICCCOUNT
++ * Return an integer count of all PCICCs.
++ *
++ * Z90STAT_PCIXCCMCL2COUNT
++ * Return an integer count of all MCL2 PCIXCCs.
++ *
++ * Z90STAT_PCIXCCMCL3COUNT
++ * Return an integer count of all MCL3 PCIXCCs.
++ *
++ * Z90STAT_CEX2CCOUNT
++ * Return an integer count of all CEX2Cs.
++ *
++ * Z90STAT_CEX2ACOUNT
++ * Return an integer count of all CEX2As.
++ *
++ * Z90STAT_REQUESTQ_COUNT
++ * Return an integer count of the number of entries waiting to be
++ * sent to a device.
++ *
++ * Z90STAT_PENDINGQ_COUNT
++ * Return an integer count of the number of entries sent to a
++ * device awaiting the reply.
++ *
++ * Z90STAT_TOTALOPEN_COUNT
++ * Return an integer count of the number of open file handles.
++ *
++ * Z90STAT_DOMAIN_INDEX
++ * Return the integer value of the Cryptographic Domain.
++ *
++ * Z90STAT_STATUS_MASK
++ * Return an 64 element array of unsigned chars for the status of
++ * all devices.
++ * 0x01: PCICA
++ * 0x02: PCICC
++ * 0x03: PCIXCC_MCL2
++ * 0x04: PCIXCC_MCL3
++ * 0x05: CEX2C
++ * 0x06: CEX2A
++ * 0x0d: device is disabled via the proc filesystem
++ *
++ * Z90STAT_QDEPTH_MASK
++ * Return an 64 element array of unsigned chars for the queue
++ * depth of all devices.
++ *
++ * Z90STAT_PERDEV_REQCNT
++ * Return an 64 element array of unsigned integers for the number
++ * of successfully completed requests per device since the device
++ * was detected and made available.
++ *
++ * ICAZ90STATUS (deprecated)
++ * Return some device driver status in a ica_z90_status struct
++ * This takes an ica_z90_status struct as its arg.
++ *
++ * NOTE: this ioctl() is deprecated, and has been replaced with
++ * single ioctl()s for each type of status being requested
++ *
++ * Z90STAT_PCIXCCCOUNT (deprecated)
++ * Return an integer count of all PCIXCCs (MCL2 + MCL3).
++ * This is DEPRECATED now that MCL3 PCIXCCs are treated differently from
++ * MCL2 PCIXCCs.
++ *
++ * Z90QUIESCE (not recommended)
++ * Quiesce the driver. This is intended to stop all new
++ * requests from being processed. Its use is NOT recommended,
++ * except in circumstances where there is no other way to stop
++ * callers from accessing the driver. Its original use was to
++ * allow the driver to be "drained" of work in preparation for
++ * a system shutdown.
++ *
++ * NOTE: once issued, this ban on new work cannot be undone
++ * except by unloading and reloading the driver.
++ */
++
++/**
++ * Supported ioctl calls
++ */
++#define ICARSAMODEXPO _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x05, 0)
++#define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0)
++#define ZSECSENDCPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0)
++
++/* New status calls */
++#define Z90STAT_TOTALCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int)
++#define Z90STAT_PCICACOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x41, int)
++#define Z90STAT_PCICCCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x42, int)
++#define Z90STAT_PCIXCCMCL2COUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x4b, int)
++#define Z90STAT_PCIXCCMCL3COUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x4c, int)
++#define Z90STAT_CEX2CCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x4d, int)
++#define Z90STAT_CEX2ACOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x4e, int)
++#define Z90STAT_REQUESTQ_COUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x44, int)
++#define Z90STAT_PENDINGQ_COUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x45, int)
++#define Z90STAT_TOTALOPEN_COUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x46, int)
++#define Z90STAT_DOMAIN_INDEX _IOR(ZCRYPT_IOCTL_MAGIC, 0x47, int)
++#define Z90STAT_STATUS_MASK _IOR(ZCRYPT_IOCTL_MAGIC, 0x48, char[64])
++#define Z90STAT_QDEPTH_MASK _IOR(ZCRYPT_IOCTL_MAGIC, 0x49, char[64])
++#define Z90STAT_PERDEV_REQCNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x4a, int[64])
++
++#endif /* __ASM_S390_ZCRYPT_H */
+diff --git a/include/asm-sh/.gitignore b/include/asm-sh/.gitignore
+new file mode 100644
+index 0000000..9218ef8
+--- /dev/null
++++ b/include/asm-sh/.gitignore
+@@ -0,0 +1,3 @@
++cpu
++mach
++machtypes.h
+diff --git a/include/asm-sh/addrspace.h b/include/asm-sh/addrspace.h
+index 720afc1..b860218 100644
+--- a/include/asm-sh/addrspace.h
++++ b/include/asm-sh/addrspace.h
+@@ -14,11 +14,19 @@
+ #include <asm/cpu/addrspace.h>
+
+ /* Memory segments (32bit Privileged mode addresses) */
++#ifndef CONFIG_CPU_SH2A
+ #define P0SEG 0x00000000
+ #define P1SEG 0x80000000
+ #define P2SEG 0xa0000000
+ #define P3SEG 0xc0000000
+ #define P4SEG 0xe0000000
++#else
++#define P0SEG 0x00000000
++#define P1SEG 0x00000000
++#define P2SEG 0x20000000
++#define P3SEG 0x00000000
++#define P4SEG 0x80000000
++#endif
+
+ /* Returns the privileged segment base of a given address */
+ #define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
+diff --git a/include/asm-sh/adx/io.h b/include/asm-sh/adx/io.h
+deleted file mode 100644
+index ab1225f..0000000
+--- a/include/asm-sh/adx/io.h
++++ /dev/null
+@@ -1,86 +0,0 @@
+-/*
+- * include/asm-sh/io_adx.h
+- *
+- * Copyright (C) 2001 A&D Co., Ltd.
+- *
+- * This file may be copied or modified under the terms of the GNU
+- * General Public License. See linux/COPYING for more information.
+- *
+- * IO functions for an A&D ADX Board
+- */
+-
+-#ifndef _ASM_SH_IO_ADX_H
+-#define _ASM_SH_IO_ADX_H
+-
+-#include <asm/io_generic.h>
+-
+-extern unsigned char adx_inb(unsigned long port);
+-extern unsigned short adx_inw(unsigned long port);
+-extern unsigned int adx_inl(unsigned long port);
+-
+-extern void adx_outb(unsigned char value, unsigned long port);
+-extern void adx_outw(unsigned short value, unsigned long port);
+-extern void adx_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char adx_inb_p(unsigned long port);
+-extern void adx_outb_p(unsigned char value, unsigned long port);
+-
+-extern void adx_insb(unsigned long port, void *addr, unsigned long count);
+-extern void adx_insw(unsigned long port, void *addr, unsigned long count);
+-extern void adx_insl(unsigned long port, void *addr, unsigned long count);
+-extern void adx_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void adx_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void adx_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned char adx_readb(unsigned long addr);
+-extern unsigned short adx_readw(unsigned long addr);
+-extern unsigned int adx_readl(unsigned long addr);
+-extern void adx_writeb(unsigned char b, unsigned long addr);
+-extern void adx_writew(unsigned short b, unsigned long addr);
+-extern void adx_writel(unsigned int b, unsigned long addr);
+-
+-extern void * adx_ioremap(unsigned long offset, unsigned long size);
+-extern void adx_iounmap(void *addr);
+-
+-extern unsigned long adx_isa_port2addr(unsigned long offset);
+-
+-extern void setup_adx(void);
+-extern void init_adx_IRQ(void);
+-
+-#ifdef __WANT_IO_DEF
+-
+-#define __inb adx_inb
+-#define __inw adx_inw
+-#define __inl adx_inl
+-#define __outb adx_outb
+-#define __outw adx_outw
+-#define __outl adx_outl
+-
+-#define __inb_p adx_inb_p
+-#define __inw_p adx_inw
+-#define __inl_p adx_inl
+-#define __outb_p adx_outb_p
+-#define __outw_p adx_outw
+-#define __outl_p adx_outl
+-
+-#define __insb adx_insb
+-#define __insw adx_insw
+-#define __insl adx_insl
+-#define __outsb adx_outsb
+-#define __outsw adx_outsw
+-#define __outsl adx_outsl
+-
+-#define __readb adx_readb
+-#define __readw adx_readw
+-#define __readl adx_readl
+-#define __writeb adx_writeb
+-#define __writew adx_writew
+-#define __writel adx_writel
+-
+-#define __isa_port2addr adx_isa_port2addr
+-#define __ioremap adx_ioremap
+-#define __iounmap adx_iounmap
+-
+-#endif
+-
+-#endif /* _ASM_SH_IO_AANDD_H */
+diff --git a/include/asm-sh/apm.h b/include/asm-sh/apm.h
+new file mode 100644
+index 0000000..8b091e9
+--- /dev/null
++++ b/include/asm-sh/apm.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2006 (c) Andriy Skulysh <askulysh at gmail.com>
++ *
++ * 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 __ASM_SH_APM_H
++#define __ASM_SH_APM_H
++
++#define APM_AC_OFFLINE 0
++#define APM_AC_ONLINE 1
++#define APM_AC_BACKUP 2
++#define APM_AC_UNKNOWN 0xff
++
++#define APM_BATTERY_STATUS_HIGH 0
++#define APM_BATTERY_STATUS_LOW 1
++#define APM_BATTERY_STATUS_CRITICAL 2
++#define APM_BATTERY_STATUS_CHARGING 3
++#define APM_BATTERY_STATUS_NOT_PRESENT 4
++#define APM_BATTERY_STATUS_UNKNOWN 0xff
++
++#define APM_BATTERY_LIFE_UNKNOWN 0xFFFF
++#define APM_BATTERY_LIFE_MINUTES 0x8000
++#define APM_BATTERY_LIFE_VALUE_MASK 0x7FFF
++
++#define APM_BATTERY_FLAG_HIGH (1 << 0)
++#define APM_BATTERY_FLAG_LOW (1 << 1)
++#define APM_BATTERY_FLAG_CRITICAL (1 << 2)
++#define APM_BATTERY_FLAG_CHARGING (1 << 3)
++#define APM_BATTERY_FLAG_NOT_PRESENT (1 << 7)
++#define APM_BATTERY_FLAG_UNKNOWN 0xff
++
++#define APM_UNITS_MINS 0
++#define APM_UNITS_SECS 1
++#define APM_UNITS_UNKNOWN -1
++
++
++extern int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
++extern int apm_suspended;
++
++void apm_queue_event(apm_event_t event);
++
++#endif
+diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h
+index fb627de..8bdc1ba 100644
+--- a/include/asm-sh/atomic.h
++++ b/include/asm-sh/atomic.h
+@@ -14,6 +14,7 @@ typedef struct { volatile int counter; }
+ #define atomic_read(v) ((v)->counter)
+ #define atomic_set(v,i) ((v)->counter = (i))
+
++#include <linux/compiler.h>
+ #include <asm/system.h>
+
+ /*
+@@ -21,49 +22,110 @@ typedef struct { volatile int counter; }
+ * forward to code at the end of this object's .text section, then
+ * branch back to restart the operation.
+ */
+-
+-static __inline__ void atomic_add(int i, atomic_t * v)
++static inline void atomic_add(int i, atomic_t *v)
+ {
++#ifdef CONFIG_CPU_SH4A
++ unsigned long tmp;
++
++ __asm__ __volatile__ (
++"1: movli.l @%3, %0 ! atomic_add \n"
++" add %2, %0 \n"
++" movco.l %0, @%3 \n"
++" bf 1b \n"
++ : "=&z" (tmp), "=r" (&v->counter)
++ : "r" (i), "r" (&v->counter)
++ : "t");
++#else
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v += i;
+ local_irq_restore(flags);
++#endif
+ }
+
+-static __inline__ void atomic_sub(int i, atomic_t *v)
++static inline void atomic_sub(int i, atomic_t *v)
+ {
++#ifdef CONFIG_CPU_SH4A
++ unsigned long tmp;
++
++ __asm__ __volatile__ (
++"1: movli.l @%3, %0 ! atomic_sub \n"
++" sub %2, %0 \n"
++" movco.l %0, @%3 \n"
++" bf 1b \n"
++ : "=&z" (tmp), "=r" (&v->counter)
++ : "r" (i), "r" (&v->counter)
++ : "t");
++#else
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v -= i;
+ local_irq_restore(flags);
++#endif
+ }
+
+-static __inline__ int atomic_add_return(int i, atomic_t * v)
++/*
++ * SH-4A note:
++ *
++ * We basically get atomic_xxx_return() for free compared with
++ * atomic_xxx(). movli.l/movco.l require r0 due to the instruction
++ * encoding, so the retval is automatically set without having to
++ * do any special work.
++ */
++static inline int atomic_add_return(int i, atomic_t *v)
+ {
+- unsigned long temp, flags;
++ unsigned long temp;
++
++#ifdef CONFIG_CPU_SH4A
++ __asm__ __volatile__ (
++"1: movli.l @%3, %0 ! atomic_add_return \n"
++" add %2, %0 \n"
++" movco.l %0, @%3 \n"
++" bf 1b \n"
++" synco \n"
++ : "=&z" (temp), "=r" (&v->counter)
++ : "r" (i), "r" (&v->counter)
++ : "t");
++#else
++ unsigned long flags;
+
+ local_irq_save(flags);
+ temp = *(long *)v;
+ temp += i;
+ *(long *)v = temp;
+ local_irq_restore(flags);
++#endif
+
+ return temp;
+ }
+
+ #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
+
+-static __inline__ int atomic_sub_return(int i, atomic_t * v)
++static inline int atomic_sub_return(int i, atomic_t *v)
+ {
+- unsigned long temp, flags;
++ unsigned long temp;
++
++#ifdef CONFIG_CPU_SH4A
++ __asm__ __volatile__ (
++"1: movli.l @%3, %0 ! atomic_sub_return \n"
++" sub %2, %0 \n"
++" movco.l %0, @%3 \n"
++" bf 1b \n"
++" synco \n"
++ : "=&z" (temp), "=r" (&v->counter)
++ : "r" (i), "r" (&v->counter)
++ : "t");
++#else
++ unsigned long flags;
+
+ local_irq_save(flags);
+ temp = *(long *)v;
+ temp -= i;
+ *(long *)v = temp;
+ local_irq_restore(flags);
++#endif
+
+ return temp;
+ }
+@@ -118,22 +180,48 @@ static inline int atomic_add_unless(atom
+ }
+ #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+-static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
++static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
+ {
++#ifdef CONFIG_CPU_SH4A
++ unsigned long tmp;
++
++ __asm__ __volatile__ (
++"1: movli.l @%3, %0 ! atomic_clear_mask \n"
++" and %2, %0 \n"
++" movco.l %0, @%3 \n"
++" bf 1b \n"
++ : "=&z" (tmp), "=r" (&v->counter)
++ : "r" (~mask), "r" (&v->counter)
++ : "t");
++#else
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v &= ~mask;
+ local_irq_restore(flags);
++#endif
+ }
+
+-static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
++static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
+ {
++#ifdef CONFIG_CPU_SH4A
++ unsigned long tmp;
++
++ __asm__ __volatile__ (
++"1: movli.l @%3, %0 ! atomic_set_mask \n"
++" or %2, %0 \n"
++" movco.l %0, @%3 \n"
++" bf 1b \n"
++ : "=&z" (tmp), "=r" (&v->counter)
++ : "r" (mask), "r" (&v->counter)
++ : "t");
++#else
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v |= mask;
+ local_irq_restore(flags);
++#endif
+ }
+
+ /* Atomic operations are already serializing on SH */
+diff --git a/include/asm-sh/auxvec.h b/include/asm-sh/auxvec.h
+index fc21e4d..1b6916e 100644
+--- a/include/asm-sh/auxvec.h
++++ b/include/asm-sh/auxvec.h
+@@ -1,4 +1,18 @@
+ #ifndef __ASM_SH_AUXVEC_H
+ #define __ASM_SH_AUXVEC_H
+
++/*
++ * Architecture-neutral AT_ values in 0-17, leave some room
++ * for more of them.
++ */
++
++#ifdef CONFIG_VSYSCALL
++/*
++ * Only define this in the vsyscall case, the entry point to
++ * the vsyscall page gets placed here. The kernel will attempt
++ * to build a gate VMA we don't care about otherwise..
++ */
++#define AT_SYSINFO_EHDR 33
++#endif
++
+ #endif /* __ASM_SH_AUXVEC_H */
+diff --git a/include/asm-sh/bigsur/io.h b/include/asm-sh/bigsur/io.h
+index 939735e..1470ac8 100644
+--- a/include/asm-sh/bigsur/io.h
++++ b/include/asm-sh/bigsur/io.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-sh/io_bigsur.h
++ * include/asm-sh/bigsur/io.h
+ *
+ * By Dustin McIntire (dustin at sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+diff --git a/include/asm-sh/bigsur/serial.h b/include/asm-sh/bigsur/serial.h
+index 7233af4..a08fa82 100644
+--- a/include/asm-sh/bigsur/serial.h
++++ b/include/asm-sh/bigsur/serial.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-sh/serial-bigsur.h
++ * include/asm-sh/bigsur/serial.h
+ *
+ * Configuration details for Big Sur 16550 based serial ports
+ * i.e. HD64465, PCMCIA, etc.
+diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
+index e34f825..1c16792 100644
+--- a/include/asm-sh/bitops.h
++++ b/include/asm-sh/bitops.h
+@@ -6,7 +6,7 @@
+ /* For __swab32 */
+ #include <asm/byteorder.h>
+
+-static __inline__ void set_bit(int nr, volatile void * addr)
++static inline void set_bit(int nr, volatile void * addr)
+ {
+ int mask;
+ volatile unsigned int *a = addr;
+@@ -24,7 +24,7 @@ static __inline__ void set_bit(int nr, v
+ */
+ #define smp_mb__before_clear_bit() barrier()
+ #define smp_mb__after_clear_bit() barrier()
+-static __inline__ void clear_bit(int nr, volatile void * addr)
++static inline void clear_bit(int nr, volatile void * addr)
+ {
+ int mask;
+ volatile unsigned int *a = addr;
+@@ -37,7 +37,7 @@ static __inline__ void clear_bit(int nr,
+ local_irq_restore(flags);
+ }
+
+-static __inline__ void change_bit(int nr, volatile void * addr)
++static inline void change_bit(int nr, volatile void * addr)
+ {
+ int mask;
+ volatile unsigned int *a = addr;
+@@ -50,7 +50,7 @@ static __inline__ void change_bit(int nr
+ local_irq_restore(flags);
+ }
+
+-static __inline__ int test_and_set_bit(int nr, volatile void * addr)
++static inline int test_and_set_bit(int nr, volatile void * addr)
+ {
+ int mask, retval;
+ volatile unsigned int *a = addr;
+@@ -66,7 +66,7 @@ static __inline__ int test_and_set_bit(i
+ return retval;
+ }
+
+-static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
++static inline int test_and_clear_bit(int nr, volatile void * addr)
+ {
+ int mask, retval;
+ volatile unsigned int *a = addr;
+@@ -82,7 +82,7 @@ static __inline__ int test_and_clear_bit
+ return retval;
+ }
+
+-static __inline__ int test_and_change_bit(int nr, volatile void * addr)
++static inline int test_and_change_bit(int nr, volatile void * addr)
+ {
+ int mask, retval;
+ volatile unsigned int *a = addr;
+@@ -100,7 +100,7 @@ static __inline__ int test_and_change_bi
+
+ #include <asm-generic/bitops/non-atomic.h>
+
+-static __inline__ unsigned long ffz(unsigned long word)
++static inline unsigned long ffz(unsigned long word)
+ {
+ unsigned long result;
+
+@@ -120,7 +120,7 @@ static __inline__ unsigned long ffz(unsi
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+-static __inline__ unsigned long __ffs(unsigned long word)
++static inline unsigned long __ffs(unsigned long word)
+ {
+ unsigned long result;
+
+diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h
+index a6de3d0..beeea40 100644
+--- a/include/asm-sh/bugs.h
++++ b/include/asm-sh/bugs.h
+@@ -18,7 +18,7 @@ static void __init check_bugs(void)
+ {
+ extern char *get_cpu_subtype(void);
+ extern unsigned long loops_per_jiffy;
+- char *p= &system_utsname.machine[2]; /* "sh" */
++ char *p= &init_utsname()->machine[2]; /* "sh" */
+
+ cpu_data->loops_per_jiffy = loops_per_jiffy;
+
+@@ -32,6 +32,10 @@ static void __init check_bugs(void)
+ case CPU_SH7750 ... CPU_SH4_501:
+ *p++ = '4';
+ break;
++ case CPU_SH7770 ... CPU_SH7781:
++ *p++ = '4';
++ *p++ = 'a';
++ break;
+ default:
+ *p++ = '?';
+ *p++ = '!';
+diff --git a/include/asm-sh/cache.h b/include/asm-sh/cache.h
+index 656fdfe..e3a180c 100644
+--- a/include/asm-sh/cache.h
++++ b/include/asm-sh/cache.h
+@@ -10,7 +10,6 @@
+ #ifdef __KERNEL__
+
+ #include <asm/cpu/cache.h>
+-#include <asm/cpu/cacheflush.h>
+
+ #define SH_CACHE_VALID 1
+ #define SH_CACHE_UPDATED 2
+@@ -23,24 +22,31 @@
+ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+ struct cache_info {
+- unsigned int ways;
+- unsigned int sets;
+- unsigned int linesz;
++ unsigned int ways; /* Number of cache ways */
++ unsigned int sets; /* Number of cache sets */
++ unsigned int linesz; /* Cache line size (bytes) */
+
+- unsigned int way_incr;
++ unsigned int way_size; /* sets * line size */
+
++ /*
++ * way_incr is the address offset for accessing the next way
++ * in memory mapped cache array ops.
++ */
++ unsigned int way_incr;
+ unsigned int entry_shift;
+ unsigned int entry_mask;
+
++ /*
++ * Compute a mask which selects the address bits which overlap between
++ * 1. those used to select the cache set during indexing
++ * 2. those in the physical page number.
++ */
++ unsigned int alias_mask;
++
++ unsigned int n_aliases; /* Number of aliases */
++
+ unsigned long flags;
+ };
+
+-/* Flush (write-back only) a region (smaller than a page) */
+-extern void __flush_wback_region(void *start, int size);
+-/* Flush (write-back & invalidate) a region (smaller than a page) */
+-extern void __flush_purge_region(void *start, int size);
+-/* Flush (invalidate only) a region (smaller than a page) */
+-extern void __flush_invalidate_region(void *start, int size);
+-
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_SH_CACHE_H */
+diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h
+index 9dfb33e..07f62ec 100644
+--- a/include/asm-sh/cacheflush.h
++++ b/include/asm-sh/cacheflush.h
+@@ -2,6 +2,7 @@
+ #define __ASM_SH_CACHEFLUSH_H
+ #ifdef __KERNEL__
+
++#include <linux/mm.h>
+ #include <asm/cpu/cacheflush.h>
+
+ /* Flush (write-back only) a region (smaller than a page) */
+@@ -27,5 +28,7 @@ extern void __flush_invalidate_region(vo
+ memcpy(dst, src, len); \
+ } while (0)
+
++#define HAVE_ARCH_UNMAPPED_AREA
++
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_SH_CACHEFLUSH_H */
+diff --git a/include/asm-sh/cat68701/io.h b/include/asm-sh/cat68701/io.h
+deleted file mode 100644
+index 753b846..0000000
+--- a/include/asm-sh/cat68701/io.h
++++ /dev/null
+@@ -1,22 +0,0 @@
+-/*
+- * include/asm-sh/io_cat68701.h
+- *
+- * Copyright 2000 Stuart Menefy (stuart.menefy at st.com)
+- * 2001 Yutarou Ebihar (ebihara at si-linux.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an AONE Corp. CAT-68701 SH7708 Borad
+- */
+-
+-#ifndef _ASM_SH_IO_CAT68701_H
+-#define _ASM_SH_IO_CAT68701_H
+-
+-extern unsigned long cat68701_isa_port2addr(unsigned long offset);
+-extern int cat68701_irq_demux(int irq);
+-
+-extern void init_cat68701_IRQ(void);
+-extern void heartbeat_cat68701(void);
+-
+-#endif /* _ASM_SH_IO_CAT68701_H */
+diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h
+index fa03b30..08168af 100644
+--- a/include/asm-sh/checksum.h
++++ b/include/asm-sh/checksum.h
+@@ -159,6 +159,7 @@ static __inline__ unsigned short ip_comp
+ }
+
+ #define _HAVE_ARCH_IPV6_CSUM
++#ifdef CONFIG_IPV6
+ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u32 len,
+@@ -194,6 +195,7 @@ static __inline__ unsigned short int csu
+
+ return csum_fold(sum);
+ }
++#endif
+
+ /*
+ * Copy and checksum to user
+diff --git a/include/asm-sh/cpu-features.h b/include/asm-sh/cpu-features.h
+new file mode 100644
+index 0000000..4bccd7c
+--- /dev/null
++++ b/include/asm-sh/cpu-features.h
+@@ -0,0 +1,24 @@
++#ifndef __ASM_SH_CPU_FEATURES_H
++#define __ASM_SH_CPU_FEATURES_H
++
++/*
++ * Processor flags
++ *
++ * Note: When adding a new flag, keep cpu_flags[] in
++ * arch/sh/kernel/setup.c in sync so symbolic name
++ * mapping of the processor flags has a chance of being
++ * reasonably accurate.
++ *
++ * These flags are also available through the ELF
++ * auxiliary vector as AT_HWCAP.
++ */
++#define CPU_HAS_FPU 0x0001 /* Hardware FPU support */
++#define CPU_HAS_P2_FLUSH_BUG 0x0002 /* Need to flush the cache in P2 area */
++#define CPU_HAS_MMU_PAGE_ASSOC 0x0004 /* SH3: TLB way selection bit support */
++#define CPU_HAS_DSP 0x0008 /* SH-DSP: DSP support */
++#define CPU_HAS_PERF_COUNTER 0x0010 /* Hardware performance counters */
++#define CPU_HAS_PTEA 0x0020 /* PTEA register */
++#define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */
++#define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */
++
++#endif /* __ASM_SH_CPU_FEATURES_H */
+diff --git a/include/asm-sh/cpu-sh2/shmparam.h b/include/asm-sh/cpu-sh2/shmparam.h
+deleted file mode 100644
+index 817c182..0000000
+--- a/include/asm-sh/cpu-sh2/shmparam.h
++++ /dev/null
+@@ -1,16 +0,0 @@
+-/*
+- * include/asm-sh/cpu-sh2/shmparam.h
+- *
+- * Copyright (C) 2003 Paul Mundt
+- *
+- * 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 __ASM_CPU_SH2_SHMPARAM_H
+-#define __ASM_CPU_SH2_SHMPARAM_H
+-
+-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
+-
+-#endif /* __ASM_CPU_SH2_SHMPARAM_H */
+-
+diff --git a/include/asm-sh/cpu-sh3/cache.h b/include/asm-sh/cpu-sh3/cache.h
+index 406aa8d..ffe08d2 100644
+--- a/include/asm-sh/cpu-sh3/cache.h
++++ b/include/asm-sh/cpu-sh3/cache.h
+@@ -26,12 +26,10 @@
+ #define CCR_CACHE_ENABLE CCR_CACHE_CE
+ #define CCR_CACHE_INVALIDATE CCR_CACHE_CF
+
+-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
++#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+ #define CCR3 0xa40000b4
+ #define CCR_CACHE_16KB 0x00010000
+ #define CCR_CACHE_32KB 0x00020000
+ #endif
+
+-
+ #endif /* __ASM_CPU_SH3_CACHE_H */
+-
+diff --git a/include/asm-sh/cpu-sh3/cacheflush.h b/include/asm-sh/cpu-sh3/cacheflush.h
+index f51aed0..03fde97 100644
+--- a/include/asm-sh/cpu-sh3/cacheflush.h
++++ b/include/asm-sh/cpu-sh3/cacheflush.h
+@@ -10,7 +10,7 @@
+ #ifndef __ASM_CPU_SH3_CACHEFLUSH_H
+ #define __ASM_CPU_SH3_CACHEFLUSH_H
+
+-/*
++/*
+ * Cache flushing:
+ *
+ * - flush_cache_all() flushes entire cache
+@@ -35,53 +35,33 @@
+ /* 32KB cache, 4kb PAGE sizes need to check bit 12 */
+ #define CACHE_ALIAS 0x00001000
+
+-struct page;
+-struct mm_struct;
+-struct vm_area_struct;
+-
+-extern void flush_cache_all(void);
+-extern void flush_cache_mm(struct mm_struct *mm);
+-extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+- unsigned long end);
+-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+-extern void flush_dcache_page(struct page *pg);
+-extern void flush_icache_range(unsigned long start, unsigned long end);
+-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+-
+-#define flush_dcache_mmap_lock(mapping) do { } while (0)
+-#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+-
+-/* SH3 has unified cache so no special action needed here */
+-#define flush_cache_sigtramp(vaddr) do { } while (0)
+-#define flush_page_to_ram(page) do { } while (0)
+-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
+-
+-#define p3_cache_init() do { } while (0)
+-
+ #define PG_mapped PG_arch_1
+
+-/* We provide our own get_unmapped_area to avoid cache alias issue */
+-#define HAVE_ARCH_UNMAPPED_AREA
+-
++void flush_cache_all(void);
++void flush_cache_mm(struct mm_struct *mm);
++void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end);
++void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
++void flush_dcache_page(struct page *pg);
++void flush_icache_range(unsigned long start, unsigned long end);
++void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+ #else
+-
+ #define flush_cache_all() do { } while (0)
+ #define flush_cache_mm(mm) do { } while (0)
+ #define flush_cache_range(vma, start, end) do { } while (0)
+ #define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
+ #define flush_dcache_page(page) do { } while (0)
+-#define flush_dcache_mmap_lock(mapping) do { } while (0)
+-#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+ #define flush_icache_range(start, end) do { } while (0)
+ #define flush_icache_page(vma,pg) do { } while (0)
+-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
+-#define flush_cache_sigtramp(vaddr) do { } while (0)
++#endif
+
+-#define p3_cache_init() do { } while (0)
++#define flush_dcache_mmap_lock(mapping) do { } while (0)
++#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+
+-#define HAVE_ARCH_UNMAPPED_AREA
++/* SH3 has unified cache so no special action needed here */
++#define flush_cache_sigtramp(vaddr) do { } while (0)
++#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
+
+-#endif
++#define p3_cache_init() do { } while (0)
+
+ #endif /* __ASM_CPU_SH3_CACHEFLUSH_H */
+-
+diff --git a/include/asm-sh/cpu-sh3/freq.h b/include/asm-sh/cpu-sh3/freq.h
+index b61b6e3..273f322 100644
+--- a/include/asm-sh/cpu-sh3/freq.h
++++ b/include/asm-sh/cpu-sh3/freq.h
+@@ -18,5 +18,9 @@
+ #define MIN_DIVISOR_NR 0
+ #define MAX_DIVISOR_NR 4
+
++#define FRQCR_CKOEN 0x0100
++#define FRQCR_PLLEN 0x0080
++#define FRQCR_PSTBY 0x0040
++
+ #endif /* __ASM_CPU_SH3_FREQ_H */
+
+diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h
+index a844ea0..bccb7dd 100644
+--- a/include/asm-sh/cpu-sh3/mmu_context.h
++++ b/include/asm-sh/cpu-sh3/mmu_context.h
+@@ -27,8 +27,12 @@
+ #define TRA 0xffffffd0
+ #define EXPEVT 0xffffffd4
+
+-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+- defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
++#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7300) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7710)
+ #define INTEVT 0xa4000000 /* INTEVTE2(0xa4000000) */
+ #else
+ #define INTEVT 0xffffffd8
+diff --git a/include/asm-sh/cpu-sh3/rtc.h b/include/asm-sh/cpu-sh3/rtc.h
+deleted file mode 100644
+index 2d92667..0000000
+--- a/include/asm-sh/cpu-sh3/rtc.h
++++ /dev/null
+@@ -1,25 +0,0 @@
+-#ifndef __ASM_CPU_SH3_RTC_H
+-#define __ASM_CPU_SH3_RTC_H
+-
+-/* SH-3 RTC */
+-#define R64CNT 0xfffffec0
+-#define RSECCNT 0xfffffec2
+-#define RMINCNT 0xfffffec4
+-#define RHRCNT 0xfffffec6
+-#define RWKCNT 0xfffffec8
+-#define RDAYCNT 0xfffffeca
+-#define RMONCNT 0xfffffecc
+-#define RYRCNT 0xfffffece
+-#define RSECAR 0xfffffed0
+-#define RMINAR 0xfffffed2
+-#define RHRAR 0xfffffed4
+-#define RWKAR 0xfffffed6
+-#define RDAYAR 0xfffffed8
+-#define RMONAR 0xfffffeda
+-#define RCR1 0xfffffedc
+-#define RCR2 0xfffffede
+-
+-#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
+-
+-#endif /* __ASM_CPU_SH3_RTC_H */
+-
+diff --git a/include/asm-sh/cpu-sh3/shmparam.h b/include/asm-sh/cpu-sh3/shmparam.h
+deleted file mode 100644
+index da5b5ee..0000000
+--- a/include/asm-sh/cpu-sh3/shmparam.h
++++ /dev/null
+@@ -1,16 +0,0 @@
+-/*
+- * include/asm-sh/cpu-sh3/shmparam.h
+- *
+- * Copyright (C) 1999 Niibe Yutaka
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License. See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#ifndef __ASM_CPU_SH3_SHMPARAM_H
+-#define __ASM_CPU_SH3_SHMPARAM_H
+-
+-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
+-
+-#endif /* __ASM_CPU_SH3_SHMPARAM_H */
+-
+diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h
+index 3d8e95e..b2394cf 100644
+--- a/include/asm-sh/cpu-sh3/timer.h
++++ b/include/asm-sh/cpu-sh3/timer.h
+@@ -20,9 +20,14 @@
+ * SH7710
+ * SH7720
+ * SH7300
++ * SH7710
+ * ---------------------------------------------------------------------------
+ */
+
++#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
++#define TMU_TOCR 0xfffffe90 /* Byte access */
++#endif
++
+ #if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+ #define TMU_TSTR 0xa412fe92 /* Byte access */
+
+@@ -39,9 +44,6 @@
+ #define TMU2_TCR 0xa412feb4 /* Word access */
+
+ #else
+-#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+-#define TMU_TOCR 0xfffffe90 /* Byte access */
+-#endif
+ #define TMU_TSTR 0xfffffe92 /* Byte access */
+
+ #define TMU0_TCOR 0xfffffe94 /* Long access */
+diff --git a/include/asm-sh/cpu-sh3/ubc.h b/include/asm-sh/cpu-sh3/ubc.h
+index 0f809de..9d308cb 100644
+--- a/include/asm-sh/cpu-sh3/ubc.h
++++ b/include/asm-sh/cpu-sh3/ubc.h
+@@ -11,6 +11,19 @@
+ #ifndef __ASM_CPU_SH3_UBC_H
+ #define __ASM_CPU_SH3_UBC_H
+
++#if defined(CONFIG_CPU_SUBTYPE_SH7710)
++#define UBC_BARA 0xa4ffffb0
++#define UBC_BAMRA 0xa4ffffb4
++#define UBC_BBRA 0xa4ffffb8
++#define UBC_BASRA 0xffffffe4
++#define UBC_BARB 0xa4ffffa0
++#define UBC_BAMRB 0xa4ffffa4
++#define UBC_BBRB 0xa4ffffa8
++#define UBC_BASRB 0xffffffe8
++#define UBC_BDRB 0xa4ffff90
++#define UBC_BDMRB 0xa4ffff94
++#define UBC_BRCR 0xa4ffff98
++#else
+ #define UBC_BARA 0xffffffb0
+ #define UBC_BAMRA 0xffffffb4
+ #define UBC_BBRA 0xffffffb8
+@@ -22,6 +35,6 @@
+ #define UBC_BDRB 0xffffff90
+ #define UBC_BDMRB 0xffffff94
+ #define UBC_BRCR 0xffffff98
++#endif
+
+ #endif /* __ASM_CPU_SH3_UBC_H */
+-
+diff --git a/include/asm-sh/cpu-sh4/addrspace.h b/include/asm-sh/cpu-sh4/addrspace.h
+index 727634d..bb2e1b0 100644
+--- a/include/asm-sh/cpu-sh4/addrspace.h
++++ b/include/asm-sh/cpu-sh4/addrspace.h
+@@ -22,5 +22,8 @@
+ #define P4SEG_TLB_DATA 0xf7000000
+ #define P4SEG_REG_BASE 0xff000000
+
++#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
++#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
++
+ #endif /* __ASM_CPU_SH4_ADDRSPACE_H */
+
+diff --git a/include/asm-sh/cpu-sh4/cache.h b/include/asm-sh/cpu-sh4/cache.h
+index 1fe2035..6e9c7e6 100644
+--- a/include/asm-sh/cpu-sh4/cache.h
++++ b/include/asm-sh/cpu-sh4/cache.h
+@@ -22,7 +22,9 @@
+ #define CCR_CACHE_ICE 0x0100 /* Instruction Cache Enable */
+ #define CCR_CACHE_ICI 0x0800 /* IC Invalidate */
+ #define CCR_CACHE_IIX 0x8000 /* IC Index Enable */
++#ifndef CONFIG_CPU_SUBTYPE_SH7780
+ #define CCR_CACHE_EMODE 0x80000000 /* EMODE Enable */
++#endif
+
+ /* Default CCR setup: 8k+16k-byte cache,P1-wb,enable */
+ #define CCR_CACHE_ENABLE (CCR_CACHE_OCE|CCR_CACHE_ICE)
+diff --git a/include/asm-sh/cpu-sh4/cacheflush.h b/include/asm-sh/cpu-sh4/cacheflush.h
+index f323567..515fd57 100644
+--- a/include/asm-sh/cpu-sh4/cacheflush.h
++++ b/include/asm-sh/cpu-sh4/cacheflush.h
+@@ -16,40 +16,29 @@
+ * caching; in which case they're only semi-broken),
+ * so we need them.
+ */
+-
+-/* Page is 4K, OC size is 16K, there are four lines. */
+-#define CACHE_ALIAS 0x00003000
+-
+-struct page;
+-struct mm_struct;
+-struct vm_area_struct;
+-
+-extern void flush_cache_all(void);
+-extern void flush_cache_mm(struct mm_struct *mm);
+-extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+- unsigned long end);
+-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+-extern void flush_dcache_page(struct page *pg);
++void flush_cache_all(void);
++void flush_cache_mm(struct mm_struct *mm);
++void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end);
++void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
++ unsigned long pfn);
++void flush_dcache_page(struct page *pg);
+
+ #define flush_dcache_mmap_lock(mapping) do { } while (0)
+ #define flush_dcache_mmap_unlock(mapping) do { } while (0)
+
+-extern void flush_icache_range(unsigned long start, unsigned long end);
+-extern void flush_cache_sigtramp(unsigned long addr);
+-extern void flush_icache_user_range(struct vm_area_struct *vma,
+- struct page *page, unsigned long addr,
+- int len);
++void flush_icache_range(unsigned long start, unsigned long end);
++void flush_cache_sigtramp(unsigned long addr);
++void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
++ unsigned long addr, int len);
+
+ #define flush_icache_page(vma,pg) do { } while (0)
+
+ /* Initialization of P3 area for copy_user_page */
+-extern void p3_cache_init(void);
++void p3_cache_init(void);
+
+ #define PG_mapped PG_arch_1
+
+-/* We provide our own get_unmapped_area to avoid cache alias issue */
+-#define HAVE_ARCH_UNMAPPED_AREA
+-
+ #ifdef CONFIG_MMU
+ extern int remap_area_pages(unsigned long addr, unsigned long phys_addr,
+ unsigned long size, unsigned long flags);
+@@ -61,4 +50,3 @@ static inline int remap_area_pages(unsig
+ }
+ #endif /* CONFIG_MMU */
+ #endif /* __ASM_CPU_SH4_CACHEFLUSH_H */
+-
+diff --git a/include/asm-sh/cpu-sh4/dma-sh7780.h b/include/asm-sh/cpu-sh4/dma-sh7780.h
+new file mode 100644
+index 0000000..6c90d28
+--- /dev/null
++++ b/include/asm-sh/cpu-sh4/dma-sh7780.h
+@@ -0,0 +1,39 @@
++#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
++#define __ASM_SH_CPU_SH4_DMA_SH7780_H
++
++#define REQ_HE 0x000000C0
++#define REQ_H 0x00000080
++#define REQ_LE 0x00000040
++#define TM_BURST 0x0000020
++#define TS_8 0x00000000
++#define TS_16 0x00000008
++#define TS_32 0x00000010
++#define TS_16BLK 0x00000018
++#define TS_32BLK 0x00100000
++
++/*
++ * The SuperH DMAC supports a number of transmit sizes, we list them here,
++ * with their respective values as they appear in the CHCR registers.
++ *
++ * Defaults to a 64-bit transfer size.
++ */
++enum {
++ XMIT_SZ_8BIT,
++ XMIT_SZ_16BIT,
++ XMIT_SZ_32BIT,
++ XMIT_SZ_128BIT,
++ XMIT_SZ_256BIT,
++};
++
++/*
++ * The DMA count is defined as the number of bytes to transfer.
++ */
++static unsigned int __attribute__ ((used)) ts_shift[] = {
++ [XMIT_SZ_8BIT] = 0,
++ [XMIT_SZ_16BIT] = 1,
++ [XMIT_SZ_32BIT] = 2,
++ [XMIT_SZ_128BIT] = 4,
++ [XMIT_SZ_256BIT] = 5,
++};
++
++#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
+diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
+index 0dfe61f..3e4b3e6 100644
+--- a/include/asm-sh/cpu-sh4/dma.h
++++ b/include/asm-sh/cpu-sh4/dma.h
+@@ -1,11 +1,17 @@
+ #ifndef __ASM_CPU_SH4_DMA_H
+ #define __ASM_CPU_SH4_DMA_H
+
++#define DMAOR_INIT ( 0x8000 | DMAOR_DME )
++
+ #ifdef CONFIG_CPU_SH4A
+ #define SH_DMAC_BASE 0xfc808020
++
++#define CHCR_TS_MASK 0x18
++#define CHCR_TS_SHIFT 3
++
++#include <asm/cpu/dma-sh7780.h>
+ #else
+ #define SH_DMAC_BASE 0xffa00000
+-#endif
+
+ /* Definitions for the SuperH DMAC */
+ #define TM_BURST 0x0000080
+@@ -19,8 +25,6 @@
+
+ #define DMAOR_COD 0x00000008
+
+-#define DMAOR_INIT ( 0x8000 | DMAOR_DME )
+-
+ /*
+ * The SuperH DMAC supports a number of transmit sizes, we list them here,
+ * with their respective values as they appear in the CHCR registers.
+@@ -45,5 +49,6 @@ static unsigned int ts_shift[] __attribu
+ [XMIT_SZ_32BIT] = 2,
+ [XMIT_SZ_256BIT] = 5,
+ };
++#endif
+
+ #endif /* __ASM_CPU_SH4_DMA_H */
+diff --git a/include/asm-sh/cpu-sh4/rtc.h b/include/asm-sh/cpu-sh4/rtc.h
+deleted file mode 100644
+index e091e32..0000000
+--- a/include/asm-sh/cpu-sh4/rtc.h
++++ /dev/null
+@@ -1,25 +0,0 @@
+-#ifndef __ASM_CPU_SH4_RTC_H
+-#define __ASM_CPU_SH4_RTC_H
+-
+-/* SH-4 RTC */
+-#define R64CNT 0xffc80000
+-#define RSECCNT 0xffc80004
+-#define RMINCNT 0xffc80008
+-#define RHRCNT 0xffc8000c
+-#define RWKCNT 0xffc80010
+-#define RDAYCNT 0xffc80014
+-#define RMONCNT 0xffc80018
+-#define RYRCNT 0xffc8001c /* 16bit */
+-#define RSECAR 0xffc80020
+-#define RMINAR 0xffc80024
+-#define RHRAR 0xffc80028
+-#define RWKAR 0xffc8002c
+-#define RDAYAR 0xffc80030
+-#define RMONAR 0xffc80034
+-#define RCR1 0xffc80038
+-#define RCR2 0xffc8003c
+-
+-#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
+-
+-#endif /* __ASM_CPU_SH4_RTC_H */
+-
+diff --git a/include/asm-sh/cpu-sh4/shmparam.h b/include/asm-sh/cpu-sh4/shmparam.h
+deleted file mode 100644
+index a5a0aa9..0000000
+--- a/include/asm-sh/cpu-sh4/shmparam.h
++++ /dev/null
+@@ -1,19 +0,0 @@
+-/*
+- * include/asm-sh/cpu-sh4/shmparam.h
+- *
+- * Copyright (C) 1999 Niibe Yutaka
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License. See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#ifndef __ASM_CPU_SH4_SHMPARAM_H
+-#define __ASM_CPU_SH4_SHMPARAM_H
+-
+-/*
+- * SH-4 has D-cache alias issue
+- */
+-#define SHMLBA (PAGE_SIZE*4) /* attach addr a multiple of this */
+-
+-#endif /* __ASM_CPU_SH4_SHMPARAM_H */
+-
+diff --git a/include/asm-sh/cpu-sh4/sq.h b/include/asm-sh/cpu-sh4/sq.h
+index 366b091..586d649 100644
+--- a/include/asm-sh/cpu-sh4/sq.h
++++ b/include/asm-sh/cpu-sh4/sq.h
+@@ -17,7 +17,7 @@
+ * Store queues range from e0000000-e3fffffc, allowing approx. 64MB to be
+ * mapped to any physical address space. Since data is written (and aligned)
+ * to 32-byte boundaries, we need to be sure that all allocations are aligned.
+- */
++ */
+ #define SQ_SIZE 32
+ #define SQ_ALIGN_MASK (~(SQ_SIZE - 1))
+ #define SQ_ALIGN(addr) (((addr)+SQ_SIZE-1) & SQ_ALIGN_MASK)
+@@ -26,23 +26,10 @@
+ #define SQ_QACR1 (P4SEG_REG_BASE + 0x3c)
+ #define SQ_ADDRMAX (P4SEG_STORE_QUE + 0x04000000)
+
+-struct sq_mapping {
+- const char *name;
+-
+- unsigned long sq_addr;
+- unsigned long addr;
+- unsigned int size;
+-
+- struct list_head list;
+-};
+-
+ /* arch/sh/kernel/cpu/sh4/sq.c */
+-extern struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name);
+-extern void sq_unmap(struct sq_mapping *map);
+-
+-extern void sq_clear(unsigned long addr, unsigned int len);
+-extern void sq_flush(void *addr);
+-extern void sq_flush_range(unsigned long start, unsigned int len);
++unsigned long sq_remap(unsigned long phys, unsigned int size,
++ const char *name, unsigned long flags);
++void sq_unmap(unsigned long vaddr);
++void sq_flush_range(unsigned long start, unsigned int len);
+
+ #endif /* __ASM_CPU_SH4_SQ_H */
+-
+diff --git a/include/asm-sh/cpu-sh4/ubc.h b/include/asm-sh/cpu-sh4/ubc.h
+index 3d09431..c86e170 100644
+--- a/include/asm-sh/cpu-sh4/ubc.h
++++ b/include/asm-sh/cpu-sh4/ubc.h
+@@ -3,6 +3,7 @@
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2003 Paul Mundt
++ * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
+ *
+ * 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
+@@ -11,6 +12,41 @@
+ #ifndef __ASM_CPU_SH4_UBC_H
+ #define __ASM_CPU_SH4_UBC_H
+
++#if defined(CONFIG_CPU_SH4A)
++#define UBC_CBR0 0xff200000
++#define UBC_CRR0 0xff200004
++#define UBC_CAR0 0xff200008
++#define UBC_CAMR0 0xff20000c
++#define UBC_CBR1 0xff200020
++#define UBC_CRR1 0xff200024
++#define UBC_CAR1 0xff200028
++#define UBC_CAMR1 0xff20002c
++#define UBC_CDR1 0xff200030
++#define UBC_CDMR1 0xff200034
++#define UBC_CETR1 0xff200038
++#define UBC_CCMFR 0xff200600
++#define UBC_CBCR 0xff200620
++
++/* CBR */
++#define UBC_CBR_AIE (0x01<<30)
++#define UBC_CBR_ID_INST (0x01<<4)
++#define UBC_CBR_RW_READ (0x01<<1)
++#define UBC_CBR_CE (0x01)
++
++#define UBC_CBR_AIV_MASK (0x00FF0000)
++#define UBC_CBR_AIV_SHIFT (16)
++#define UBC_CBR_AIV_SET(asid) (((asid)<<UBC_CBR_AIV_SHIFT) & UBC_CBR_AIV_MASK)
++
++#define UBC_CBR_INIT 0x20000000
++
++/* CRR */
++#define UBC_CRR_RES (0x01<<13)
++#define UBC_CRR_PCB (0x01<<1)
++#define UBC_CRR_BIE (0x01)
++
++#define UBC_CRR_INIT 0x00002000
++
++#else /* CONFIG_CPU_SH4 */
+ #define UBC_BARA 0xff200000
+ #define UBC_BAMRA 0xff200004
+ #define UBC_BBRA 0xff200008
+@@ -22,6 +58,7 @@
+ #define UBC_BDRB 0xff200018
+ #define UBC_BDMRB 0xff20001c
+ #define UBC_BRCR 0xff200020
++#endif /* CONFIG_CPU_SH4 */
+
+ #endif /* __ASM_CPU_SH4_UBC_H */
+
+diff --git a/include/asm-sh/cqreek/cqreek.h b/include/asm-sh/cqreek/cqreek.h
+deleted file mode 100644
+index 09aecc0..0000000
+--- a/include/asm-sh/cqreek/cqreek.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-#ifndef __ASM_SH_CQREEK_CQREEK_H
+-#define __ASM_SH_CQREEK_CQREEK_H
+-
+-#define BRIDGE_FEATURE 0x0002
+-
+-#define BRIDGE_IDE_CTRL 0x0018
+-#define BRIDGE_IDE_INTR_LVL 0x001A
+-#define BRIDGE_IDE_INTR_MASK 0x001C
+-#define BRIDGE_IDE_INTR_STAT 0x001E
+-
+-#define BRIDGE_ISA_CTRL 0x0028
+-#define BRIDGE_ISA_INTR_LVL 0x002A
+-#define BRIDGE_ISA_INTR_MASK 0x002C
+-#define BRIDGE_ISA_INTR_STAT 0x002E
+-
+-/* arch/sh/boards/cqreek/setup.c */
+-extern void setup_cqreek(void);
+-
+-/* arch/sh/boards/cqreek/irq.c */
+-extern int cqreek_has_ide, cqreek_has_isa;
+-extern void init_cqreek_IRQ(void);
+-
+-/* arch/sh/boards/cqreek/io.c */
+-extern unsigned long cqreek_port2addr(unsigned long port);
+-
+-#endif /* __ASM_SH_CQREEK_CQREEK_H */
+-
+diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
+index 124968f..56cd4b9 100644
+--- a/include/asm-sh/dma-mapping.h
++++ b/include/asm-sh/dma-mapping.h
+@@ -141,25 +141,35 @@ static inline void dma_sync_sg(struct de
+ }
+ }
+
+-static void dma_sync_single_for_cpu(struct device *dev,
+- dma_addr_t dma_handle, size_t size,
+- enum dma_data_direction dir)
+- __attribute__ ((alias("dma_sync_single")));
++static inline void dma_sync_single_for_cpu(struct device *dev,
++ dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction dir)
++{
++ dma_sync_single(dev, dma_handle, size, dir);
++}
++
++static inline void dma_sync_single_for_device(struct device *dev,
++ dma_addr_t dma_handle,
++ size_t size,
++ enum dma_data_direction dir)
++{
++ dma_sync_single(dev, dma_handle, size, dir);
++}
+
+-static void dma_sync_single_for_device(struct device *dev,
+- dma_addr_t dma_handle, size_t size,
++static inline void dma_sync_sg_for_cpu(struct device *dev,
++ struct scatterlist *sg, int nelems,
+ enum dma_data_direction dir)
+- __attribute__ ((alias("dma_sync_single")));
++{
++ dma_sync_sg(dev, sg, nelems, dir);
++}
+
+-static void dma_sync_sg_for_cpu(struct device *dev,
+- struct scatterlist *sg, int nelems,
+- enum dma_data_direction dir)
+- __attribute__ ((alias("dma_sync_sg")));
++static inline void dma_sync_sg_for_device(struct device *dev,
++ struct scatterlist *sg, int nelems,
++ enum dma_data_direction dir)
++{
++ dma_sync_sg(dev, sg, nelems, dir);
++}
+
+-static void dma_sync_sg_for_device(struct device *dev,
+- struct scatterlist *sg, int nelems,
+- enum dma_data_direction dir)
+- __attribute__ ((alias("dma_sync_sg")));
+
+ static inline int dma_get_cache_alignment(void)
+ {
+@@ -174,6 +184,4 @@ static inline int dma_mapping_error(dma_
+ {
+ return dma_addr == 0;
+ }
+-
+ #endif /* __ASM_SH_DMA_MAPPING_H */
+-
+diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h
+index e62a6d0..d9daa02 100644
+--- a/include/asm-sh/dma.h
++++ b/include/asm-sh/dma.h
+@@ -89,6 +89,7 @@ struct dma_channel {
+ wait_queue_head_t wait_queue;
+
+ struct sys_device dev;
++ char *name;
+ };
+
+ struct dma_info {
+diff --git a/include/asm-sh/dmida/io.h b/include/asm-sh/dmida/io.h
+deleted file mode 100644
+index 21bd416..0000000
+--- a/include/asm-sh/dmida/io.h
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#ifndef __ASM_SH_DMIDA_IO_H
+-#define __ASM_SH_DMIDA_IO_H
+-
+-/*
+- * Nothing special here.. just use the generic cchip io routines.
+- */
+-#include <asm/hd64465/io.h>
+-
+-#endif /* __ASM_SH_DMIDA_IO_H */
+-
+diff --git a/include/asm-sh/dreamcast/sysasic.h b/include/asm-sh/dreamcast/sysasic.h
+index c885853..7874e3d 100644
+--- a/include/asm-sh/dreamcast/sysasic.h
++++ b/include/asm-sh/dreamcast/sysasic.h
+@@ -1,4 +1,4 @@
+-/* include/asm-sh/dc_sysasic.h
++/* include/asm-sh/dreamcast/sysasic.h
+ *
+ * Definitions for the Dreamcast System ASIC and related peripherals.
+ *
+diff --git a/include/asm-sh/ec3104/keyboard.h b/include/asm-sh/ec3104/keyboard.h
+index 0dee7b0..c1253a6 100644
+--- a/include/asm-sh/ec3104/keyboard.h
++++ b/include/asm-sh/ec3104/keyboard.h
+@@ -6,8 +6,6 @@ extern char ec3104_kbd_unexpected_up(uns
+ extern void ec3104_kbd_leds(unsigned char);
+ extern void ec3104_kbd_init_hw(void);
+
+-#define SYSRQ_KEY 0x54
+-
+ #define kbd_sysrq_xlate ec3104_kbd_sysrq_xlate
+ #define kbd_setkeycode ec3104_kbd_setkeycode
+ #define kbd_getkeycode ec3104_kbd_getkeycode
+diff --git a/include/asm-sh/edosk7705.h b/include/asm-sh/edosk7705.h
+new file mode 100644
+index 0000000..a1089a6
+--- /dev/null
++++ b/include/asm-sh/edosk7705.h
+@@ -0,0 +1,30 @@
++/*
++ * include/asm-sh/edosk7705/io.h
++ *
++ * Modified version of io_se.h for the EDOSK7705 specific functions.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ * IO functions for an Hitachi EDOSK7705 development board
++ */
++
++#ifndef __ASM_SH_EDOSK7705_IO_H
++#define __ASM_SH_EDOSK7705_IO_H
++
++#include <asm/io_generic.h>
++
++extern unsigned char sh_edosk7705_inb(unsigned long port);
++extern unsigned int sh_edosk7705_inl(unsigned long port);
++
++extern void sh_edosk7705_outb(unsigned char value, unsigned long port);
++extern void sh_edosk7705_outl(unsigned int value, unsigned long port);
++
++extern void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count);
++extern void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count);
++extern void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count);
++extern void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count);
++
++extern unsigned long sh_edosk7705_isa_port2addr(unsigned long offset);
++
++#endif /* __ASM_SH_EDOSK7705_IO_H */
+diff --git a/include/asm-sh/edosk7705/io.h b/include/asm-sh/edosk7705/io.h
+deleted file mode 100644
+index a1089a6..0000000
+--- a/include/asm-sh/edosk7705/io.h
++++ /dev/null
+@@ -1,30 +0,0 @@
+-/*
+- * include/asm-sh/edosk7705/io.h
+- *
+- * Modified version of io_se.h for the EDOSK7705 specific functions.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an Hitachi EDOSK7705 development board
+- */
+-
+-#ifndef __ASM_SH_EDOSK7705_IO_H
+-#define __ASM_SH_EDOSK7705_IO_H
+-
+-#include <asm/io_generic.h>
+-
+-extern unsigned char sh_edosk7705_inb(unsigned long port);
+-extern unsigned int sh_edosk7705_inl(unsigned long port);
+-
+-extern void sh_edosk7705_outb(unsigned char value, unsigned long port);
+-extern void sh_edosk7705_outl(unsigned int value, unsigned long port);
+-
+-extern void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count);
+-extern void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count);
+-extern void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned long sh_edosk7705_isa_port2addr(unsigned long offset);
+-
+-#endif /* __ASM_SH_EDOSK7705_IO_H */
+diff --git a/include/asm-sh/elf.h b/include/asm-sh/elf.h
+index 1b63dfe..fc050fd 100644
+--- a/include/asm-sh/elf.h
++++ b/include/asm-sh/elf.h
+@@ -1,6 +1,10 @@
+ #ifndef __ASM_SH_ELF_H
+ #define __ASM_SH_ELF_H
+
++#include <asm/auxvec.h>
++#include <asm/ptrace.h>
++#include <asm/user.h>
++
+ /* SH relocation types */
+ #define R_SH_NONE 0
+ #define R_SH_DIR32 1
+@@ -46,9 +50,6 @@
+ * ELF register definitions..
+ */
+
+-#include <asm/ptrace.h>
+-#include <asm/user.h>
+-
+ typedef unsigned long elf_greg_t;
+
+ #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+@@ -91,7 +92,7 @@ typedef struct user_fpu_struct elf_fpreg
+ 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)
++#define ELF_HWCAP (boot_cpu_data.flags)
+
+ /* This yields a string that ld.so will use to load implementation
+ specific libraries for optimization. This is more specific in
+@@ -119,4 +120,24 @@ extern int dump_task_fpu (struct task_st
+ #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+ #endif
+
++#ifdef CONFIG_VSYSCALL
++/* vDSO has arch_setup_additional_pages */
++#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
++struct linux_binprm;
++extern int arch_setup_additional_pages(struct linux_binprm *bprm,
++ int executable_stack);
++
++extern unsigned int vdso_enabled;
++extern void __kernel_vsyscall;
++
++#define VDSO_BASE ((unsigned long)current->mm->context.vdso)
++#define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x))
++
++#define ARCH_DLINFO \
++do { \
++ if (vdso_enabled) \
++ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \
++} while (0)
++#endif /* CONFIG_VSYSCALL */
++
+ #endif /* __ASM_SH_ELF_H */
+diff --git a/include/asm-sh/fixmap.h b/include/asm-sh/fixmap.h
+index 412bcca..458e9fa 100644
+--- a/include/asm-sh/fixmap.h
++++ b/include/asm-sh/fixmap.h
+@@ -25,7 +25,7 @@
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+- * from the end of virtual memory (0xfffff000) backwards.
++ * from the end of P3 backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+diff --git a/include/asm-sh/flat.h b/include/asm-sh/flat.h
+index f29072e..0d5cc04 100644
+--- a/include/asm-sh/flat.h
++++ b/include/asm-sh/flat.h
+@@ -13,7 +13,7 @@
+ #define __ASM_SH_FLAT_H
+
+ #define flat_stack_align(sp) /* nothing needed */
+-#define flat_argvp_envp_on_stack() 1
++#define flat_argvp_envp_on_stack() 0
+ #define flat_old_ram_flag(flags) (flags)
+ #define flat_reloc_valid(reloc, size) ((reloc) <= (size))
+ #define flat_get_addr_from_rp(rp, relval, flags) get_unaligned(rp)
+diff --git a/include/asm-sh/harp/harp.h b/include/asm-sh/harp/harp.h
+deleted file mode 100644
+index b2fbcfa..0000000
+--- a/include/asm-sh/harp/harp.h
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * Defintions applicable to the STMicroelectronics ST40STB1 HARP and
+- * compatible boards.
+- */
+-
+-#if defined(CONFIG_SH_STB1_HARP)
+-
+-#define EPLD_BASE 0xa0800000
+-
+-#define EPLD_LED (EPLD_BASE+0x000c0000)
+-#define EPLD_INTSTAT0 (EPLD_BASE+0x00200000)
+-#define EPLD_INTSTAT1 (EPLD_BASE+0x00240000)
+-#define EPLD_INTMASK0 (EPLD_BASE+0x00280000)
+-#define EPLD_INTMASK1 (EPLD_BASE+0x002c0000)
+-#define EPLD_PAGEADDR (EPLD_BASE+0x00300000)
+-#define EPLD_REVID1 (EPLD_BASE+0x00380000)
+-#define EPLD_REVID2 (EPLD_BASE+0x003c0000)
+-
+-#define EPLD_LED_ON 1
+-#define EPLD_LED_OFF 0
+-
+-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+-
+-#define EPLD_BASE 0xa7000000
+-
+-#define EPLD_REVID (EPLD_BASE+0x00000000)
+-#define EPLD_LED (EPLD_BASE+0x00040000)
+-#define EPLD_INTMASK0 (EPLD_BASE+0x001c0000)
+-#define EPLD_INTMASK1 (EPLD_BASE+0x00200000)
+-#define EPLD_INTSTAT0 (EPLD_BASE+0x00240000)
+-#define EPLD_INTSTAT1 (EPLD_BASE+0x00280000)
+-
+-#define EPLD_LED_ON 0
+-#define EPLD_LED_OFF 1
+-
+-#else
+-#error Unknown board
+-#endif
+diff --git a/include/asm-sh/harp/io.h b/include/asm-sh/harp/io.h
+deleted file mode 100644
+index 68f39e0..0000000
+--- a/include/asm-sh/harp/io.h
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#ifndef __ASM_SH_HARP_IO_H
+-#define __ASM_SH_HARP_IO_H
+-
+-/*
+- * Nothing special here.. just use the generic cchip io routines.
+- */
+-#include <asm/hd64465/io.h>
+-
+-#endif /* __ASM_SH_HARP_IO_H */
+-
+diff --git a/include/asm-sh/hd64461.h b/include/asm-sh/hd64461.h
+new file mode 100644
+index 0000000..27e5c34
+--- /dev/null
++++ b/include/asm-sh/hd64461.h
+@@ -0,0 +1,208 @@
++#ifndef __ASM_SH_HD64461
++#define __ASM_SH_HD64461
++/*
++ * $Id: hd64461.h,v 1.5 2004/03/16 00:07:51 lethal Exp $
++ * Copyright (C) 2000 YAEGASHI Takeshi
++ * Hitachi HD64461 companion chip support
++ */
++
++/* Constants for PCMCIA mappings */
++#define HD64461_PCC_WINDOW 0x01000000
++
++#define HD64461_PCC0_BASE 0xb8000000 /* area 6 */
++#define HD64461_PCC0_ATTR (HD64461_PCC0_BASE)
++#define HD64461_PCC0_COMM (HD64461_PCC0_BASE+HD64461_PCC_WINDOW)
++#define HD64461_PCC0_IO (HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW)
++
++#define HD64461_PCC1_BASE 0xb4000000 /* area 5 */
++#define HD64461_PCC1_ATTR (HD64461_PCC1_BASE)
++#define HD64461_PCC1_COMM (HD64461_PCC1_BASE+HD64461_PCC_WINDOW)
++
++#define HD64461_STBCR 0x10000
++#define HD64461_STBCR_CKIO_STBY 0x2000
++#define HD64461_STBCR_SAFECKE_IST 0x1000
++#define HD64461_STBCR_SLCKE_IST 0x0800
++#define HD64461_STBCR_SAFECKE_OST 0x0400
++#define HD64461_STBCR_SLCKE_OST 0x0200
++#define HD64461_STBCR_SMIAST 0x0100
++#define HD64461_STBCR_SLCDST 0x0080
++#define HD64461_STBCR_SPC0ST 0x0040
++#define HD64461_STBCR_SPC1ST 0x0020
++#define HD64461_STBCR_SAFEST 0x0010
++#define HD64461_STBCR_STM0ST 0x0008
++#define HD64461_STBCR_STM1ST 0x0004
++#define HD64461_STBCR_SIRST 0x0002
++#define HD64461_STBCR_SURTST 0x0001
++
++#define HD64461_SYSCR 0x10002
++#define HD64461_SCPUCR 0x10004
++
++#define HD64461_LCDCBAR 0x11000
++#define HD64461_LCDCLOR 0x11002
++#define HD64461_LCDCCR 0x11004
++#define HD64461_LCDCCR_STBACK 0x0400
++#define HD64461_LCDCCR_STREQ 0x0100
++#define HD64461_LCDCCR_MOFF 0x0080
++#define HD64461_LCDCCR_REFSEL 0x0040
++#define HD64461_LCDCCR_EPON 0x0020
++#define HD64461_LCDCCR_SPON 0x0010
++
++#define HD64461_LDR1 0x11010
++#define HD64461_LDR1_DON 0x01
++#define HD64461_LDR1_DINV 0x80
++
++#define HD64461_LDR2 0x11012
++#define HD64461_LDHNCR 0x11014
++#define HD64461_LDHNSR 0x11016
++#define HD64461_LDVNTR 0x11018
++#define HD64461_LDVNDR 0x1101a
++#define HD64461_LDVSPR 0x1101c
++#define HD64461_LDR3 0x1101e
++
++#define HD64461_CPTWAR 0x11030
++#define HD64461_CPTWDR 0x11032
++#define HD64461_CPTRAR 0x11034
++#define HD64461_CPTRDR 0x11036
++
++#define HD64461_GRDOR 0x11040
++#define HD64461_GRSCR 0x11042
++#define HD64461_GRCFGR 0x11044
++#define HD64461_GRCFGR_ACCSTATUS 0x10
++#define HD64461_GRCFGR_ACCRESET 0x08
++#define HD64461_GRCFGR_ACCSTART_BITBLT 0x06
++#define HD64461_GRCFGR_ACCSTART_LINE 0x04
++#define HD64461_GRCFGR_COLORDEPTH16 0x01
++
++#define HD64461_LNSARH 0x11046
++#define HD64461_LNSARL 0x11048
++#define HD64461_LNAXLR 0x1104a
++#define HD64461_LNDGR 0x1104c
++#define HD64461_LNAXR 0x1104e
++#define HD64461_LNERTR 0x11050
++#define HD64461_LNMDR 0x11052
++#define HD64461_BBTSSARH 0x11054
++#define HD64461_BBTSSARL 0x11056
++#define HD64461_BBTDSARH 0x11058
++#define HD64461_BBTDSARL 0x1105a
++#define HD64461_BBTDWR 0x1105c
++#define HD64461_BBTDHR 0x1105e
++#define HD64461_BBTPARH 0x11060
++#define HD64461_BBTPARL 0x11062
++#define HD64461_BBTMARH 0x11064
++#define HD64461_BBTMARL 0x11066
++#define HD64461_BBTROPR 0x11068
++#define HD64461_BBTMDR 0x1106a
++
++/* PC Card Controller Registers */
++#define HD64461_PCC0ISR 0x12000 /* socket 0 interface status */
++#define HD64461_PCC0GCR 0x12002 /* socket 0 general control */
++#define HD64461_PCC0CSCR 0x12004 /* socket 0 card status change */
++#define HD64461_PCC0CSCIER 0x12006 /* socket 0 card status change interrupt enable */
++#define HD64461_PCC0SCR 0x12008 /* socket 0 software control */
++#define HD64461_PCC1ISR 0x12010 /* socket 1 interface status */
++#define HD64461_PCC1GCR 0x12012 /* socket 1 general control */
++#define HD64461_PCC1CSCR 0x12014 /* socket 1 card status change */
++#define HD64461_PCC1CSCIER 0x12016 /* socket 1 card status change interrupt enable */
++#define HD64461_PCC1SCR 0x12018 /* socket 1 software control */
++
++/* PCC Interface Status Register */
++#define HD64461_PCCISR_READY 0x80 /* card ready */
++#define HD64461_PCCISR_MWP 0x40 /* card write-protected */
++#define HD64461_PCCISR_VS2 0x20 /* voltage select pin 2 */
++#define HD64461_PCCISR_VS1 0x10 /* voltage select pin 1 */
++#define HD64461_PCCISR_CD2 0x08 /* card detect 2 */
++#define HD64461_PCCISR_CD1 0x04 /* card detect 1 */
++#define HD64461_PCCISR_BVD2 0x02 /* battery 1 */
++#define HD64461_PCCISR_BVD1 0x01 /* battery 1 */
++
++#define HD64461_PCCISR_PCD_MASK 0x0c /* card detect */
++#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */
++#define HD64461_PCCISR_BVD_BATGOOD 0x03 /* battery good */
++#define HD64461_PCCISR_BVD_BATWARN 0x01 /* battery low warning */
++#define HD64461_PCCISR_BVD_BATDEAD1 0x02 /* battery dead */
++#define HD64461_PCCISR_BVD_BATDEAD2 0x00 /* battery dead */
++
++/* PCC General Control Register */
++#define HD64461_PCCGCR_DRVE 0x80 /* output drive */
++#define HD64461_PCCGCR_PCCR 0x40 /* PC card reset */
++#define HD64461_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */
++#define HD64461_PCCGCR_VCC0 0x10 /* voltage control pin VCC0SEL0 */
++#define HD64461_PCCGCR_PMMOD 0x08 /* memory mode */
++#define HD64461_PCCGCR_PA25 0x04 /* pin A25 */
++#define HD64461_PCCGCR_PA24 0x02 /* pin A24 */
++#define HD64461_PCCGCR_REG 0x01 /* pin PCC0REG# */
++
++/* PCC Card Status Change Register */
++#define HD64461_PCCCSCR_SCDI 0x80 /* sw card detect intr */
++#define HD64461_PCCCSCR_SRV1 0x40 /* reserved */
++#define HD64461_PCCCSCR_IREQ 0x20 /* IREQ intr req */
++#define HD64461_PCCCSCR_SC 0x10 /* STSCHG (status change) pin */
++#define HD64461_PCCCSCR_CDC 0x08 /* CD (card detect) change */
++#define HD64461_PCCCSCR_RC 0x04 /* READY change */
++#define HD64461_PCCCSCR_BW 0x02 /* battery warning change */
++#define HD64461_PCCCSCR_BD 0x01 /* battery dead change */
++
++/* PCC Card Status Change Interrupt Enable Register */
++#define HD64461_PCCCSCIER_CRE 0x80 /* change reset enable */
++#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */
++#define HD64461_PCCCSCIER_IREQE_DISABLED 0x00 /* IREQ disabled */
++#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */
++#define HD64461_PCCCSCIER_IREQE_FALLING 0x40 /* IREQ falling-edge-trig */
++#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */
++
++#define HD64461_PCCCSCIER_SCE 0x10 /* status change enable */
++#define HD64461_PCCCSCIER_CDE 0x08 /* card detect change enable */
++#define HD64461_PCCCSCIER_RE 0x04 /* ready change enable */
++#define HD64461_PCCCSCIER_BWE 0x02 /* battery warn change enable */
++#define HD64461_PCCCSCIER_BDE 0x01 /* battery dead change enable*/
++
++/* PCC Software Control Register */
++#define HD64461_PCCSCR_VCC1 0x02 /* voltage control pin 1 */
++#define HD64461_PCCSCR_SWP 0x01 /* write protect */
++
++#define HD64461_P0OCR 0x1202a
++#define HD64461_P1OCR 0x1202c
++#define HD64461_PGCR 0x1202e
++
++#define HD64461_GPACR 0x14000
++#define HD64461_GPBCR 0x14002
++#define HD64461_GPCCR 0x14004
++#define HD64461_GPDCR 0x14006
++#define HD64461_GPADR 0x14010
++#define HD64461_GPBDR 0x14012
++#define HD64461_GPCDR 0x14014
++#define HD64461_GPDDR 0x14016
++#define HD64461_GPAICR 0x14020
++#define HD64461_GPBICR 0x14022
++#define HD64461_GPCICR 0x14024
++#define HD64461_GPDICR 0x14026
++#define HD64461_GPAISR 0x14040
++#define HD64461_GPBISR 0x14042
++#define HD64461_GPCISR 0x14044
++#define HD64461_GPDISR 0x14046
++
++#define HD64461_NIRR 0x15000
++#define HD64461_NIMR 0x15002
++
++#define HD64461_IRQBASE OFFCHIP_IRQ_BASE
++#define HD64461_IRQ_NUM 16
++
++#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
++#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6)
++#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9)
++#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10)
++#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11)
++#define HD64461_IRQ_AFE (HD64461_IRQBASE+12)
++#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13)
++#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14)
++
++#define __IO_PREFIX hd64461
++#include <asm/io_generic.h>
++
++/* arch/sh/cchips/hd6446x/hd64461/setup.c */
++int hd64461_irq_demux(int irq);
++void hd64461_register_irq_demux(int irq,
++ int (*demux) (int irq, void *dev), void *dev);
++void hd64461_unregister_irq_demux(int irq);
++
++#endif
+diff --git a/include/asm-sh/hd64461/hd64461.h b/include/asm-sh/hd64461/hd64461.h
+deleted file mode 100644
+index 87f13d2..0000000
+--- a/include/asm-sh/hd64461/hd64461.h
++++ /dev/null
+@@ -1,202 +0,0 @@
+-#ifndef __ASM_SH_HD64461
+-#define __ASM_SH_HD64461
+-/*
+- * $Id: hd64461.h,v 1.5 2004/03/16 00:07:51 lethal Exp $
+- * Copyright (C) 2000 YAEGASHI Takeshi
+- * Hitachi HD64461 companion chip support
+- */
+-
+-/* Constants for PCMCIA mappings */
+-#define HD64461_PCC_WINDOW 0x01000000
+-
+-#define HD64461_PCC0_BASE 0xb8000000 /* area 6 */
+-#define HD64461_PCC0_ATTR (HD64461_PCC0_BASE)
+-#define HD64461_PCC0_COMM (HD64461_PCC0_BASE+HD64461_PCC_WINDOW)
+-#define HD64461_PCC0_IO (HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW)
+-
+-#define HD64461_PCC1_BASE 0xb4000000 /* area 5 */
+-#define HD64461_PCC1_ATTR (HD64461_PCC1_BASE)
+-#define HD64461_PCC1_COMM (HD64461_PCC1_BASE+HD64461_PCC_WINDOW)
+-
+-#define HD64461_STBCR 0x10000
+-#define HD64461_STBCR_CKIO_STBY 0x2000
+-#define HD64461_STBCR_SAFECKE_IST 0x1000
+-#define HD64461_STBCR_SLCKE_IST 0x0800
+-#define HD64461_STBCR_SAFECKE_OST 0x0400
+-#define HD64461_STBCR_SLCKE_OST 0x0200
+-#define HD64461_STBCR_SMIAST 0x0100
+-#define HD64461_STBCR_SLCDST 0x0080
+-#define HD64461_STBCR_SPC0ST 0x0040
+-#define HD64461_STBCR_SPC1ST 0x0020
+-#define HD64461_STBCR_SAFEST 0x0010
+-#define HD64461_STBCR_STM0ST 0x0008
+-#define HD64461_STBCR_STM1ST 0x0004
+-#define HD64461_STBCR_SIRST 0x0002
+-#define HD64461_STBCR_SURTST 0x0001
+-
+-#define HD64461_SYSCR 0x10002
+-#define HD64461_SCPUCR 0x10004
+-
+-#define HD64461_LCDCBAR 0x11000
+-#define HD64461_LCDCLOR 0x11002
+-#define HD64461_LCDCCR 0x11004
+-#define HD64461_LCDCCR_MOFF 0x80
+-
+-#define HD64461_LDR1 0x11010
+-#define HD64461_LDR1_DON 0x01
+-#define HD64461_LDR1_DINV 0x80
+-
+-#define HD64461_LDR2 0x11012
+-#define HD64461_LDHNCR 0x11014
+-#define HD64461_LDHNSR 0x11016
+-#define HD64461_LDVNTR 0x11018
+-#define HD64461_LDVNDR 0x1101a
+-#define HD64461_LDVSPR 0x1101c
+-#define HD64461_LDR3 0x1101e
+-
+-#define HD64461_CPTWAR 0x11030
+-#define HD64461_CPTWDR 0x11032
+-#define HD64461_CPTRAR 0x11034
+-#define HD64461_CPTRDR 0x11036
+-
+-#define HD64461_GRDOR 0x11040
+-#define HD64461_GRSCR 0x11042
+-#define HD64461_GRCFGR 0x11044
+-#define HD64461_GRCFGR_ACCSTATUS 0x10
+-#define HD64461_GRCFGR_ACCRESET 0x08
+-#define HD64461_GRCFGR_ACCSTART_BITBLT 0x06
+-#define HD64461_GRCFGR_ACCSTART_LINE 0x04
+-#define HD64461_GRCFGR_COLORDEPTH16 0x01
+-
+-#define HD64461_LNSARH 0x11046
+-#define HD64461_LNSARL 0x11048
+-#define HD64461_LNAXLR 0x1104a
+-#define HD64461_LNDGR 0x1104c
+-#define HD64461_LNAXR 0x1104e
+-#define HD64461_LNERTR 0x11050
+-#define HD64461_LNMDR 0x11052
+-#define HD64461_BBTSSARH 0x11054
+-#define HD64461_BBTSSARL 0x11056
+-#define HD64461_BBTDSARH 0x11058
+-#define HD64461_BBTDSARL 0x1105a
+-#define HD64461_BBTDWR 0x1105c
+-#define HD64461_BBTDHR 0x1105e
+-#define HD64461_BBTPARH 0x11060
+-#define HD64461_BBTPARL 0x11062
+-#define HD64461_BBTMARH 0x11064
+-#define HD64461_BBTMARL 0x11066
+-#define HD64461_BBTROPR 0x11068
+-#define HD64461_BBTMDR 0x1106a
+-
+-/* PC Card Controller Registers */
+-#define HD64461_PCC0ISR 0x12000 /* socket 0 interface status */
+-#define HD64461_PCC0GCR 0x12002 /* socket 0 general control */
+-#define HD64461_PCC0CSCR 0x12004 /* socket 0 card status change */
+-#define HD64461_PCC0CSCIER 0x12006 /* socket 0 card status change interrupt enable */
+-#define HD64461_PCC0SCR 0x12008 /* socket 0 software control */
+-#define HD64461_PCC1ISR 0x12010 /* socket 1 interface status */
+-#define HD64461_PCC1GCR 0x12012 /* socket 1 general control */
+-#define HD64461_PCC1CSCR 0x12014 /* socket 1 card status change */
+-#define HD64461_PCC1CSCIER 0x12016 /* socket 1 card status change interrupt enable */
+-#define HD64461_PCC1SCR 0x12018 /* socket 1 software control */
+-
+-/* PCC Interface Status Register */
+-#define HD64461_PCCISR_READY 0x80 /* card ready */
+-#define HD64461_PCCISR_MWP 0x40 /* card write-protected */
+-#define HD64461_PCCISR_VS2 0x20 /* voltage select pin 2 */
+-#define HD64461_PCCISR_VS1 0x10 /* voltage select pin 1 */
+-#define HD64461_PCCISR_CD2 0x08 /* card detect 2 */
+-#define HD64461_PCCISR_CD1 0x04 /* card detect 1 */
+-#define HD64461_PCCISR_BVD2 0x02 /* battery 1 */
+-#define HD64461_PCCISR_BVD1 0x01 /* battery 1 */
+-
+-#define HD64461_PCCISR_PCD_MASK 0x0c /* card detect */
+-#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */
+-#define HD64461_PCCISR_BVD_BATGOOD 0x03 /* battery good */
+-#define HD64461_PCCISR_BVD_BATWARN 0x01 /* battery low warning */
+-#define HD64461_PCCISR_BVD_BATDEAD1 0x02 /* battery dead */
+-#define HD64461_PCCISR_BVD_BATDEAD2 0x00 /* battery dead */
+-
+-/* PCC General Control Register */
+-#define HD64461_PCCGCR_DRVE 0x80 /* output drive */
+-#define HD64461_PCCGCR_PCCR 0x40 /* PC card reset */
+-#define HD64461_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */
+-#define HD64461_PCCGCR_VCC0 0x10 /* voltage control pin VCC0SEL0 */
+-#define HD64461_PCCGCR_PMMOD 0x08 /* memory mode */
+-#define HD64461_PCCGCR_PA25 0x04 /* pin A25 */
+-#define HD64461_PCCGCR_PA24 0x02 /* pin A24 */
+-#define HD64461_PCCGCR_REG 0x01 /* pin PCC0REG# */
+-
+-/* PCC Card Status Change Register */
+-#define HD64461_PCCCSCR_SCDI 0x80 /* sw card detect intr */
+-#define HD64461_PCCCSCR_SRV1 0x40 /* reserved */
+-#define HD64461_PCCCSCR_IREQ 0x20 /* IREQ intr req */
+-#define HD64461_PCCCSCR_SC 0x10 /* STSCHG (status change) pin */
+-#define HD64461_PCCCSCR_CDC 0x08 /* CD (card detect) change */
+-#define HD64461_PCCCSCR_RC 0x04 /* READY change */
+-#define HD64461_PCCCSCR_BW 0x02 /* battery warning change */
+-#define HD64461_PCCCSCR_BD 0x01 /* battery dead change */
+-
+-/* PCC Card Status Change Interrupt Enable Register */
+-#define HD64461_PCCCSCIER_CRE 0x80 /* change reset enable */
+-#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */
+-#define HD64461_PCCCSCIER_IREQE_DISABLED 0x00 /* IREQ disabled */
+-#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */
+-#define HD64461_PCCCSCIER_IREQE_FALLING 0x40 /* IREQ falling-edge-trig */
+-#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */
+-
+-#define HD64461_PCCCSCIER_SCE 0x10 /* status change enable */
+-#define HD64461_PCCCSCIER_CDE 0x08 /* card detect change enable */
+-#define HD64461_PCCCSCIER_RE 0x04 /* ready change enable */
+-#define HD64461_PCCCSCIER_BWE 0x02 /* battery warn change enable */
+-#define HD64461_PCCCSCIER_BDE 0x01 /* battery dead change enable*/
+-
+-/* PCC Software Control Register */
+-#define HD64461_PCCSCR_VCC1 0x02 /* voltage control pin 1 */
+-#define HD64461_PCCSCR_SWP 0x01 /* write protect */
+-
+-
+-#define HD64461_P0OCR 0x1202a
+-#define HD64461_P1OCR 0x1202c
+-#define HD64461_PGCR 0x1202e
+-
+-#define HD64461_GPACR 0x14000
+-#define HD64461_GPBCR 0x14002
+-#define HD64461_GPCCR 0x14004
+-#define HD64461_GPDCR 0x14006
+-#define HD64461_GPADR 0x14010
+-#define HD64461_GPBDR 0x14012
+-#define HD64461_GPCDR 0x14014
+-#define HD64461_GPDDR 0x14016
+-#define HD64461_GPAICR 0x14020
+-#define HD64461_GPBICR 0x14022
+-#define HD64461_GPCICR 0x14024
+-#define HD64461_GPDICR 0x14026
+-#define HD64461_GPAISR 0x14040
+-#define HD64461_GPBISR 0x14042
+-#define HD64461_GPCISR 0x14044
+-#define HD64461_GPDISR 0x14046
+-
+-#define HD64461_NIRR 0x15000
+-#define HD64461_NIMR 0x15002
+-
+-#ifndef CONFIG_HD64461_IOBASE
+-#define CONFIG_HD64461_IOBASE 0xb0000000
+-#endif
+-#ifndef CONFIG_HD64461_IRQ
+-#define CONFIG_HD64461_IRQ 36
+-#endif
+-
+-#define HD64461_IRQBASE OFFCHIP_IRQ_BASE
+-#define HD64461_IRQ_NUM 16
+-
+-#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
+-#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6)
+-#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9)
+-#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10)
+-#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11)
+-#define HD64461_IRQ_AFE (HD64461_IRQBASE+12)
+-#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13)
+-#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14)
+-
+-#endif
+diff --git a/include/asm-sh/hd64461/io.h b/include/asm-sh/hd64461/io.h
+deleted file mode 100644
+index 67f2489..0000000
+--- a/include/asm-sh/hd64461/io.h
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- * include/asm-sh/io_hd64461.h
+- *
+- * Copyright 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an HD64461
+- */
+-
+-#ifndef _ASM_SH_IO_HD64461_H
+-#define _ASM_SH_IO_HD64461_H
+-
+-extern unsigned char hd64461_inb(unsigned long port);
+-extern unsigned short hd64461_inw(unsigned long port);
+-extern unsigned int hd64461_inl(unsigned long port);
+-
+-extern void hd64461_outb(unsigned char value, unsigned long port);
+-extern void hd64461_outw(unsigned short value, unsigned long port);
+-extern void hd64461_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char hd64461_inb_p(unsigned long port);
+-extern void hd64461_outb_p(unsigned char value, unsigned long port);
+-
+-extern void hd64461_insb(unsigned long port, void *addr, unsigned long count);
+-extern void hd64461_insw(unsigned long port, void *addr, unsigned long count);
+-extern void hd64461_insl(unsigned long port, void *addr, unsigned long count);
+-
+-extern void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count);
+-extern void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count);
+-extern void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count);
+-
+-extern unsigned short hd64461_readw(unsigned long addr);
+-extern void hd64461_writew(unsigned short b, unsigned long addr);
+-
+-
+-extern int hd64461_irq_demux(int irq);
+-extern void hd64461_register_irq_demux(int irq,
+- int (*demux)(int irq, void *dev), void *dev);
+-extern void hd64461_unregister_irq_demux(int irq);
+-
+-#endif /* _ASM_SH_IO_HD64461_H */
+diff --git a/include/asm-sh/hd64465/io.h b/include/asm-sh/hd64465/io.h
+index 1100bcf..139f147 100644
+--- a/include/asm-sh/hd64465/io.h
++++ b/include/asm-sh/hd64465/io.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-sh/io_hd64465.h
++ * include/asm-sh/hd64465/io.h
+ *
+ * By Greg Banks <gbanks at pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+diff --git a/include/asm-sh/hp6xx.h b/include/asm-sh/hp6xx.h
+new file mode 100644
+index 0000000..f35134c
+--- /dev/null
++++ b/include/asm-sh/hp6xx.h
+@@ -0,0 +1,80 @@
++#ifndef __ASM_SH_HP6XX_H
++#define __ASM_SH_HP6XX_H
++
++/*
++ * Copyright (C) 2003, 2004, 2005 Andriy Skulysh
++ *
++ * 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.
++ *
++ */
++
++#define HP680_BTN_IRQ IRQ0_IRQ
++#define HP680_TS_IRQ IRQ3_IRQ
++#define HP680_HD64461_IRQ IRQ4_IRQ
++
++#define DAC_LCD_BRIGHTNESS 0
++#define DAC_SPEAKER_VOLUME 1
++
++#define PGDR_OPENED 0x01
++#define PGDR_MAIN_BATTERY_OUT 0x04
++#define PGDR_PLAY_BUTTON 0x08
++#define PGDR_REWIND_BUTTON 0x10
++#define PGDR_RECORD_BUTTON 0x20
++
++#define PHDR_TS_PEN_DOWN 0x08
++
++#define PJDR_LED_BLINK 0x02
++
++#define PKDR_LED_GREEN 0x10
++
++#define SCPDR_TS_SCAN_ENABLE 0x20
++#define SCPDR_TS_SCAN_Y 0x02
++#define SCPDR_TS_SCAN_X 0x01
++
++#define SCPCR_TS_ENABLE 0x405
++#define SCPCR_TS_MASK 0xc0f
++
++#define ADC_CHANNEL_TS_Y 1
++#define ADC_CHANNEL_TS_X 2
++#define ADC_CHANNEL_BATTERY 3
++#define ADC_CHANNEL_BACKUP 4
++#define ADC_CHANNEL_CHARGE 5
++
++#define HD64461_GPADR_SPEAKER 0x01
++#define HD64461_GPADR_PCMCIA0 (0x02|0x08)
++
++#define HD64461_GPBDR_LCDOFF 0x01
++#define HD64461_GPBDR_LCD_CONTRAST_MASK 0x78
++#define HD64461_GPBDR_LED_RED 0x80
++
++#include <asm/hd64461.h>
++#include <asm/io.h>
++
++#define PJDR 0xa4000130
++#define PKDR 0xa4000132
++
++static inline void hp6xx_led_red(int on)
++{
++ u16 v16;
++ v16 = ctrl_inw(CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
++ if (on)
++ ctrl_outw(v16 & (~HD64461_GPBDR_LED_RED), CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
++ else
++ ctrl_outw(v16 | HD64461_GPBDR_LED_RED, CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
++}
++
++static inline void hp6xx_led_green(int on)
++{
++ u8 v8;
++
++ v8 = ctrl_inb(PKDR);
++ if (on)
++ ctrl_outb(v8 & (~PKDR_LED_GREEN), PKDR);
++ else
++ ctrl_outb(v8 | PKDR_LED_GREEN, PKDR);
++}
++
++
++#endif /* __ASM_SH_HP6XX_H */
+diff --git a/include/asm-sh/hp6xx/hp6xx.h b/include/asm-sh/hp6xx/hp6xx.h
+deleted file mode 100644
+index a26247f..0000000
+--- a/include/asm-sh/hp6xx/hp6xx.h
++++ /dev/null
+@@ -1,31 +0,0 @@
+-#ifndef __ASM_SH_HP6XX_H
+-#define __ASM_SH_HP6XX_H
+-
+-/*
+- * Copyright (C) 2003 Andriy Skulysh
+- */
+-
+-#define HP680_TS_IRQ IRQ3_IRQ
+-
+-#define DAC_LCD_BRIGHTNESS 0
+-#define DAC_SPEAKER_VOLUME 1
+-
+-#define PHDR_TS_PEN_DOWN 0x08
+-
+-#define SCPDR_TS_SCAN_ENABLE 0x20
+-#define SCPDR_TS_SCAN_Y 0x02
+-#define SCPDR_TS_SCAN_X 0x01
+-
+-#define SCPCR_TS_ENABLE 0x405
+-#define SCPCR_TS_MASK 0xc0f
+-
+-#define ADC_CHANNEL_TS_Y 1
+-#define ADC_CHANNEL_TS_X 2
+-
+-#define HD64461_GPADR_SPEAKER 0x01
+-#define HD64461_GPADR_PCMCIA0 (0x02|0x08)
+-#define HD64461_GPBDR_LCDOFF 0x01
+-#define HD64461_GPBDR_LED_RED 0x80
+-
+-
+-#endif /* __ASM_SH_HP6XX_H */
+diff --git a/include/asm-sh/hp6xx/ide.h b/include/asm-sh/hp6xx/ide.h
+deleted file mode 100644
+index 570395a..0000000
+--- a/include/asm-sh/hp6xx/ide.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef __ASM_SH_HP6XX_IDE_H
+-#define __ASM_SH_HP6XX_IDE_H
+-
+-#define IRQ_CFCARD 93
+-#define IRQ_PCMCIA 94
+-
+-#endif /* __ASM_SH_HP6XX_IDE_H */
+-
+diff --git a/include/asm-sh/hp6xx/io.h b/include/asm-sh/hp6xx/io.h
+deleted file mode 100644
+index 7317980..0000000
+--- a/include/asm-sh/hp6xx/io.h
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#ifndef __ASM_SH_HP6XX_IO_H
+-#define __ASM_SH_HP6XX_IO_H
+-
+-/*
+- * Nothing special here.. just use the generic cchip io routines.
+- */
+-#include <asm/hd64461/io.h>
+-
+-#endif /* __ASM_SH_HP6XX_IO_H */
+-
+diff --git a/include/asm-sh/hs7751rvoip.h b/include/asm-sh/hs7751rvoip.h
+new file mode 100644
+index 0000000..c4cff9d
+--- /dev/null
++++ b/include/asm-sh/hs7751rvoip.h
+@@ -0,0 +1,54 @@
++#ifndef __ASM_SH_RENESAS_HS7751RVOIP_H
++#define __ASM_SH_RENESAS_HS7751RVOIP_H
++
++/*
++ * linux/include/asm-sh/hs7751rvoip/hs7751rvoip.h
++ *
++ * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
++ *
++ * Renesas Technology Sales HS7751RVoIP support
++ */
++
++/* Box specific addresses. */
++
++#define PA_BCR 0xa4000000 /* FPGA */
++#define PA_SLICCNTR1 0xa4000006 /* SLIC PIO Control 1 */
++#define PA_SLICCNTR2 0xa4000008 /* SLIC PIO Control 2 */
++#define PA_DMACNTR 0xa400000a /* USB DMA Control */
++#define PA_INPORTR 0xa400000c /* Input Port Register */
++#define PA_OUTPORTR 0xa400000e /* Output Port Reguster */
++#define PA_VERREG 0xa4000014 /* FPGA Version Register */
++
++#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
++
++#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
++#define IRLCNTR2 (PA_BCR + 2) /* Interrupt Control Register2 */
++#define IRLCNTR3 (PA_BCR + 4) /* Interrupt Control Register3 */
++#define IRLCNTR4 (PA_BCR + 16) /* Interrupt Control Register4 */
++#define IRLCNTR5 (PA_BCR + 18) /* Interrupt Control Register5 */
++
++#define IRQ_PCIETH 6 /* PCI Ethernet IRQ */
++#define IRQ_PCIHUB 7 /* PCI Ethernet Hub IRQ */
++#define IRQ_USBCOM 8 /* USB Comunication IRQ */
++#define IRQ_USBCON 9 /* USB Connect IRQ */
++#define IRQ_USBDMA 10 /* USB DMA IRQ */
++#define IRQ_CFCARD 11 /* CF Card IRQ */
++#define IRQ_PCMCIA 12 /* PCMCIA IRQ */
++#define IRQ_PCISLOT 13 /* PCI Slot #1 IRQ */
++#define IRQ_ONHOOK1 0 /* ON HOOK1 IRQ */
++#define IRQ_OFFHOOK1 1 /* OFF HOOK1 IRQ */
++#define IRQ_ONHOOK2 2 /* ON HOOK2 IRQ */
++#define IRQ_OFFHOOK2 3 /* OFF HOOK2 IRQ */
++#define IRQ_RINGING 4 /* Ringing IRQ */
++#define IRQ_CODEC 5 /* CODEC IRQ */
++
++#define __IO_PREFIX hs7751rvoip
++#include <asm/io_generic.h>
++
++/* arch/sh/boards/renesas/hs7751rvoip/irq.c */
++void init_hs7751rvoip_IRQ(void);
++
++/* arch/sh/boards/renesas/hs7751rvoip/io.c */
++void *hs7751rvoip_ioremap(unsigned long, unsigned long);
++
++#endif /* __ASM_SH_RENESAS_HS7751RVOIP */
+diff --git a/include/asm-sh/hs7751rvoip/hs7751rvoip.h b/include/asm-sh/hs7751rvoip/hs7751rvoip.h
+deleted file mode 100644
+index 5f995f9..0000000
+--- a/include/asm-sh/hs7751rvoip/hs7751rvoip.h
++++ /dev/null
+@@ -1,47 +0,0 @@
+-#ifndef __ASM_SH_RENESAS_HS7751RVOIP_H
+-#define __ASM_SH_RENESAS_HS7751RVOIP_H
+-
+-/*
+- * linux/include/asm-sh/hs7751rvoip/hs7751rvoip.h
+- *
+- * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
+- *
+- * Renesas Technology Sales HS7751RVoIP support
+- */
+-
+-/* Box specific addresses. */
+-
+-#define PA_BCR 0xa4000000 /* FPGA */
+-#define PA_SLICCNTR1 0xa4000006 /* SLIC PIO Control 1 */
+-#define PA_SLICCNTR2 0xa4000008 /* SLIC PIO Control 2 */
+-#define PA_DMACNTR 0xa400000a /* USB DMA Control */
+-#define PA_INPORTR 0xa400000c /* Input Port Register */
+-#define PA_OUTPORTR 0xa400000e /* Output Port Reguster */
+-#define PA_VERREG 0xa4000014 /* FPGA Version Register */
+-
+-#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
+-#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
+-#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
+-
+-#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
+-#define IRLCNTR2 (PA_BCR + 2) /* Interrupt Control Register2 */
+-#define IRLCNTR3 (PA_BCR + 4) /* Interrupt Control Register3 */
+-#define IRLCNTR4 (PA_BCR + 16) /* Interrupt Control Register4 */
+-#define IRLCNTR5 (PA_BCR + 18) /* Interrupt Control Register5 */
+-
+-#define IRQ_PCIETH 6 /* PCI Ethernet IRQ */
+-#define IRQ_PCIHUB 7 /* PCI Ethernet Hub IRQ */
+-#define IRQ_USBCOM 8 /* USB Comunication IRQ */
+-#define IRQ_USBCON 9 /* USB Connect IRQ */
+-#define IRQ_USBDMA 10 /* USB DMA IRQ */
+-#define IRQ_CFCARD 11 /* CF Card IRQ */
+-#define IRQ_PCMCIA 12 /* PCMCIA IRQ */
+-#define IRQ_PCISLOT 13 /* PCI Slot #1 IRQ */
+-#define IRQ_ONHOOK1 0 /* ON HOOK1 IRQ */
+-#define IRQ_OFFHOOK1 1 /* OFF HOOK1 IRQ */
+-#define IRQ_ONHOOK2 2 /* ON HOOK2 IRQ */
+-#define IRQ_OFFHOOK2 3 /* OFF HOOK2 IRQ */
+-#define IRQ_RINGING 4 /* Ringing IRQ */
+-#define IRQ_CODEC 5 /* CODEC IRQ */
+-
+-#endif /* __ASM_SH_RENESAS_HS7751RVOIP */
+diff --git a/include/asm-sh/hs7751rvoip/ide.h b/include/asm-sh/hs7751rvoip/ide.h
+deleted file mode 100644
+index 65ad1d0..0000000
+--- a/include/asm-sh/hs7751rvoip/ide.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef __ASM_SH_HS7751RVOIP_IDE_H
+-#define __ASM_SH_HS7751RVOIP_IDE_H
+-
+-/* Nothing to see here.. */
+-#include <asm/hs7751rvoip/hs7751rvoip.h>
+-
+-#endif /* __ASM_SH_HS7751RVOIP_IDE_H */
+-
+diff --git a/include/asm-sh/hs7751rvoip/io.h b/include/asm-sh/hs7751rvoip/io.h
+deleted file mode 100644
+index 513c851..0000000
+--- a/include/asm-sh/hs7751rvoip/io.h
++++ /dev/null
+@@ -1,39 +0,0 @@
+-/*
+- * include/asm-sh/hs7751rvoip/hs7751rvoip.h
+- *
+- * Modified version of io_se.h for the hs7751rvoip-specific functions.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an Renesas Technology sales HS7751RVOIP
+- */
+-
+-#ifndef _ASM_SH_IO_HS7751RVOIP_H
+-#define _ASM_SH_IO_HS7751RVOIP_H
+-
+-#include <asm/io_generic.h>
+-
+-extern unsigned char hs7751rvoip_inb(unsigned long port);
+-extern unsigned short hs7751rvoip_inw(unsigned long port);
+-extern unsigned int hs7751rvoip_inl(unsigned long port);
+-
+-extern void hs7751rvoip_outb(unsigned char value, unsigned long port);
+-extern void hs7751rvoip_outw(unsigned short value, unsigned long port);
+-extern void hs7751rvoip_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char hs7751rvoip_inb_p(unsigned long port);
+-extern void hs7751rvoip_outb_p(unsigned char value, unsigned long port);
+-
+-extern void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count);
+-extern void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count);
+-extern void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count);
+-extern void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern void *hs7751rvoip_ioremap(unsigned long offset, unsigned long size);
+-
+-extern unsigned long hs7751rvoip_isa_port2addr(unsigned long offset);
+-
+-#endif /* _ASM_SH_IO_HS7751RVOIP_H */
+diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
+index fed2661..80ee1cd 100644
+--- a/include/asm-sh/hw_irq.h
++++ b/include/asm-sh/hw_irq.h
+@@ -1,4 +1,8 @@
+ #ifndef __ASM_SH_HW_IRQ_H
+ #define __ASM_SH_HW_IRQ_H
+
++#include <asm/atomic.h>
++
++extern atomic_t irq_err_count;
++
+ #endif /* __ASM_SH_HW_IRQ_H */
+diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h
+index 894e64b..a0e55b0 100644
+--- a/include/asm-sh/io.h
++++ b/include/asm-sh/io.h
+@@ -107,6 +107,9 @@
+ #define __raw_writew(v, a) __writew(v, (void __iomem *)(a))
+ #define __raw_writel(v, a) __writel(v, (void __iomem *)(a))
+
++void __raw_writesl(unsigned long addr, const void *data, int longlen);
++void __raw_readsl(unsigned long addr, void *data, int longlen);
++
+ /*
+ * The platform header files may define some of these macros to use
+ * the inlined versions where appropriate. These macros may also be
+@@ -132,6 +135,9 @@
+ # define writel(v,a) ({ __raw_writel((v),(a)); mb(); })
+ #endif
+
++#define writesl __raw_writesl
++#define readsl __raw_readsl
++
+ #define readb_relaxed(a) readb(a)
+ #define readw_relaxed(a) readw(a)
+ #define readl_relaxed(a) readl(a)
+@@ -209,8 +215,14 @@ static inline void ctrl_outl(unsigned in
+ *(volatile unsigned long*)addr = b;
+ }
+
++static inline void ctrl_delay(void)
++{
++ ctrl_inw(P2SEG);
++}
++
+ #define IO_SPACE_LIMIT 0xffffffff
+
++#ifdef CONFIG_MMU
+ /*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/SuperH mapping
+@@ -224,6 +236,10 @@ static inline void *phys_to_virt(unsigne
+ {
+ return (void *)P1SEGADDR(address);
+ }
++#else
++#define phys_to_virt(address) ((void *)(address))
++#define virt_to_phys(address) ((unsigned long)(address))
++#endif
+
+ #define virt_to_bus virt_to_phys
+ #define bus_to_virt phys_to_virt
+@@ -288,22 +304,6 @@ __ioremap_mode(unsigned long offset, uns
+ #define iounmap(addr) \
+ __iounmap((addr))
+
+-static inline int check_signature(char __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ /*
+ * The caches on some architectures aren't dma-coherent and have need to
+ * handle this in software. There are three types of operations that
+diff --git a/include/asm-sh/irq-sh73180.h b/include/asm-sh/irq-sh73180.h
+index d705252..b28af9a 100644
+--- a/include/asm-sh/irq-sh73180.h
++++ b/include/asm-sh/irq-sh73180.h
+@@ -311,6 +311,4 @@
+ #define IRQ6_PRIORITY 1
+ #define IRQ7_PRIORITY 1
+
+-int shmse_irq_demux(int irq);
+-
+ #endif /* __ASM_SH_IRQ_SH73180_H */
+diff --git a/include/asm-sh/irq-sh7343.h b/include/asm-sh/irq-sh7343.h
+new file mode 100644
+index 0000000..5d15419
+--- /dev/null
++++ b/include/asm-sh/irq-sh7343.h
+@@ -0,0 +1,317 @@
++#ifndef __ASM_SH_IRQ_SH7343_H
++#define __ASM_SH_IRQ_SH7343_H
++
++/*
++ * linux/include/asm-sh/irq-sh7343.h
++ *
++ * Copyright (C) 2006 Kenati Technologies Inc.
++ * Andre Mccurdy <andre at kenati.com>
++ * Ranjit Deshpande <ranjit at kenati.com>
++ */
++
++#undef INTC_IPRA
++#undef INTC_IPRB
++#undef INTC_IPRC
++#undef INTC_IPRD
++
++#undef DMTE0_IRQ
++#undef DMTE1_IRQ
++#undef DMTE2_IRQ
++#undef DMTE3_IRQ
++#undef DMTE4_IRQ
++#undef DMTE5_IRQ
++#undef DMTE6_IRQ
++#undef DMTE7_IRQ
++#undef DMAE_IRQ
++#undef DMA_IPR_ADDR
++#undef DMA_IPR_POS
++#undef DMA_PRIORITY
++
++#undef INTC_IMCR0
++#undef INTC_IMCR1
++#undef INTC_IMCR2
++#undef INTC_IMCR3
++#undef INTC_IMCR4
++#undef INTC_IMCR5
++#undef INTC_IMCR6
++#undef INTC_IMCR7
++#undef INTC_IMCR8
++#undef INTC_IMCR9
++#undef INTC_IMCR10
++
++
++#define INTC_IPRA 0xA4080000UL
++#define INTC_IPRB 0xA4080004UL
++#define INTC_IPRC 0xA4080008UL
++#define INTC_IPRD 0xA408000CUL
++#define INTC_IPRE 0xA4080010UL
++#define INTC_IPRF 0xA4080014UL
++#define INTC_IPRG 0xA4080018UL
++#define INTC_IPRH 0xA408001CUL
++#define INTC_IPRI 0xA4080020UL
++#define INTC_IPRJ 0xA4080024UL
++#define INTC_IPRK 0xA4080028UL
++#define INTC_IPRL 0xA408002CUL
++
++#define INTC_IMR0 0xA4080080UL
++#define INTC_IMR1 0xA4080084UL
++#define INTC_IMR2 0xA4080088UL
++#define INTC_IMR3 0xA408008CUL
++#define INTC_IMR4 0xA4080090UL
++#define INTC_IMR5 0xA4080094UL
++#define INTC_IMR6 0xA4080098UL
++#define INTC_IMR7 0xA408009CUL
++#define INTC_IMR8 0xA40800A0UL
++#define INTC_IMR9 0xA40800A4UL
++#define INTC_IMR10 0xA40800A8UL
++#define INTC_IMR11 0xA40800ACUL
++
++#define INTC_IMCR0 0xA40800C0UL
++#define INTC_IMCR1 0xA40800C4UL
++#define INTC_IMCR2 0xA40800C8UL
++#define INTC_IMCR3 0xA40800CCUL
++#define INTC_IMCR4 0xA40800D0UL
++#define INTC_IMCR5 0xA40800D4UL
++#define INTC_IMCR6 0xA40800D8UL
++#define INTC_IMCR7 0xA40800DCUL
++#define INTC_IMCR8 0xA40800E0UL
++#define INTC_IMCR9 0xA40800E4UL
++#define INTC_IMCR10 0xA40800E8UL
++#define INTC_IMCR11 0xA40800ECUL
++
++#define INTC_ICR0 0xA4140000UL
++#define INTC_ICR1 0xA414001CUL
++
++#define INTMSK0 0xa4140044
++#define INTMSKCLR0 0xa4140064
++#define INTC_INTPRI0 0xa4140010
++
++/*
++ NOTE:
++
++ *_IRQ = (INTEVT2 - 0x200)/0x20
++*/
++
++/* TMU0 */
++#define TMU0_IRQ 16
++#define TMU0_IPR_ADDR INTC_IPRA
++#define TMU0_IPR_POS 3
++#define TMU0_PRIORITY 2
++
++#define TIMER_IRQ 16
++#define TIMER_IPR_ADDR INTC_IPRA
++#define TIMER_IPR_POS 3
++#define TIMER_PRIORITY 2
++
++/* TMU1 */
++#define TMU1_IRQ 17
++#define TMU1_IPR_ADDR INTC_IPRA
++#define TMU1_IPR_POS 2
++#define TMU1_PRIORITY 2
++
++/* TMU2 */
++#define TMU2_IRQ 18
++#define TMU2_IPR_ADDR INTC_IPRA
++#define TMU2_IPR_POS 1
++#define TMU2_PRIORITY 2
++
++/* LCDC */
++#define LCDC_IRQ 28
++#define LCDC_IPR_ADDR INTC_IPRB
++#define LCDC_IPR_POS 2
++#define LCDC_PRIORITY 2
++
++/* VIO (Video I/O) */
++#define CEU_IRQ 52
++#define BEU_IRQ 53
++#define VEU_IRQ 54
++#define VOU_IRQ 55
++#define VIO_IPR_ADDR INTC_IPRE
++#define VIO_IPR_POS 2
++#define VIO_PRIORITY 2
++
++/* MFI (Multi Functional Interface) */
++#define MFI_IRQ 56
++#define MFI_IPR_ADDR INTC_IPRE
++#define MFI_IPR_POS 1
++#define MFI_PRIORITY 2
++
++/* VPU (Video Processing Unit) */
++#define VPU_IRQ 60
++#define VPU_IPR_ADDR INTC_IPRE
++#define VPU_IPR_POS 0
++#define VPU_PRIORITY 2
++
++/* 3DG */
++#define TDG_IRQ 63
++#define TDG_IPR_ADDR INTC_IPRJ
++#define TDG_IPR_POS 2
++#define TDG_PRIORITY 2
++
++/* DMAC(1) */
++#define DMTE0_IRQ 48
++#define DMTE1_IRQ 49
++#define DMTE2_IRQ 50
++#define DMTE3_IRQ 51
++#define DMA1_IPR_ADDR INTC_IPRE
++#define DMA1_IPR_POS 3
++#define DMA1_PRIORITY 7
++
++/* DMAC(2) */
++#define DMTE4_IRQ 76
++#define DMTE5_IRQ 77
++#define DMA2_IPR_ADDR INTC_IPRF
++#define DMA2_IPR_POS 2
++#define DMA2_PRIORITY 7
++
++/* SCIF0 */
++#define SCIF_ERI_IRQ 80
++#define SCIF_RXI_IRQ 81
++#define SCIF_BRI_IRQ 82
++#define SCIF_TXI_IRQ 83
++#define SCIF_IPR_ADDR INTC_IPRG
++#define SCIF_IPR_POS 3
++#define SCIF_PRIORITY 3
++
++/* SIOF0 */
++#define SIOF0_IRQ 84
++#define SIOF0_IPR_ADDR INTC_IPRH
++#define SIOF0_IPR_POS 3
++#define SIOF0_PRIORITY 3
++
++/* FLCTL (Flash Memory Controller) */
++#define FLSTE_IRQ 92
++#define FLTEND_IRQ 93
++#define FLTRQ0_IRQ 94
++#define FLTRQ1_IRQ 95
++#define FLCTL_IPR_ADDR INTC_IPRH
++#define FLCTL_IPR_POS 1
++#define FLCTL_PRIORITY 3
++
++/* IIC(0) (IIC Bus Interface) */
++#define IIC0_ALI_IRQ 96
++#define IIC0_TACKI_IRQ 97
++#define IIC0_WAITI_IRQ 98
++#define IIC0_DTEI_IRQ 99
++#define IIC0_IPR_ADDR INTC_IPRH
++#define IIC0_IPR_POS 0
++#define IIC0_PRIORITY 3
++
++/* IIC(1) (IIC Bus Interface) */
++#define IIC1_ALI_IRQ 44
++#define IIC1_TACKI_IRQ 45
++#define IIC1_WAITI_IRQ 46
++#define IIC1_DTEI_IRQ 47
++#define IIC1_IPR_ADDR INTC_IPRI
++#define IIC1_IPR_POS 0
++#define IIC1_PRIORITY 3
++
++/* SIO0 */
++#define SIO0_IRQ 88
++#define SIO0_IPR_ADDR INTC_IPRI
++#define SIO0_IPR_POS 3
++#define SIO0_PRIORITY 3
++
++/* SDHI */
++#define SDHI_SDHII0_IRQ 100
++#define SDHI_SDHII1_IRQ 101
++#define SDHI_SDHII2_IRQ 102
++#define SDHI_SDHII3_IRQ 103
++#define SDHI_IPR_ADDR INTC_IPRK
++#define SDHI_IPR_POS 0
++#define SDHI_PRIORITY 3
++
++/* SIU (Sound Interface Unit) */
++#define SIU_IRQ 108
++#define SIU_IPR_ADDR INTC_IPRJ
++#define SIU_IPR_POS 1
++#define SIU_PRIORITY 3
++
++#define PORT_PACR 0xA4050100UL
++#define PORT_PBCR 0xA4050102UL
++#define PORT_PCCR 0xA4050104UL
++#define PORT_PDCR 0xA4050106UL
++#define PORT_PECR 0xA4050108UL
++#define PORT_PFCR 0xA405010AUL
++#define PORT_PGCR 0xA405010CUL
++#define PORT_PHCR 0xA405010EUL
++#define PORT_PJCR 0xA4050110UL
++#define PORT_PKCR 0xA4050112UL
++#define PORT_PLCR 0xA4050114UL
++#define PORT_SCPCR 0xA4050116UL
++#define PORT_PMCR 0xA4050118UL
++#define PORT_PNCR 0xA405011AUL
++#define PORT_PQCR 0xA405011CUL
++#define PORT_PRCR 0xA405011EUL
++#define PORT_PTCR 0xA405014CUL
++#define PORT_PUCR 0xA405014EUL
++#define PORT_PVCR 0xA4050150UL
++
++#define PORT_PSELA 0xA4050140UL
++#define PORT_PSELB 0xA4050142UL
++#define PORT_PSELC 0xA4050144UL
++#define PORT_PSELE 0xA4050158UL
++
++#define PORT_HIZCRA 0xA4050146UL
++#define PORT_HIZCRB 0xA4050148UL
++#define PORT_DRVCR 0xA405014AUL
++
++#define PORT_PADR 0xA4050120UL
++#define PORT_PBDR 0xA4050122UL
++#define PORT_PCDR 0xA4050124UL
++#define PORT_PDDR 0xA4050126UL
++#define PORT_PEDR 0xA4050128UL
++#define PORT_PFDR 0xA405012AUL
++#define PORT_PGDR 0xA405012CUL
++#define PORT_PHDR 0xA405012EUL
++#define PORT_PJDR 0xA4050130UL
++#define PORT_PKDR 0xA4050132UL
++#define PORT_PLDR 0xA4050134UL
++#define PORT_SCPDR 0xA4050136UL
++#define PORT_PMDR 0xA4050138UL
++#define PORT_PNDR 0xA405013AUL
++#define PORT_PQDR 0xA405013CUL
++#define PORT_PRDR 0xA405013EUL
++#define PORT_PTDR 0xA405016CUL
++#define PORT_PUDR 0xA405016EUL
++#define PORT_PVDR 0xA4050170UL
++
++#define IRQ0_IRQ 32
++#define IRQ1_IRQ 33
++#define IRQ2_IRQ 34
++#define IRQ3_IRQ 35
++#define IRQ4_IRQ 36
++#define IRQ5_IRQ 37
++#define IRQ6_IRQ 38
++#define IRQ7_IRQ 39
++
++#define INTPRI00 0xA4140010UL
++
++#define IRQ0_IPR_ADDR INTPRI00
++#define IRQ1_IPR_ADDR INTPRI00
++#define IRQ2_IPR_ADDR INTPRI00
++#define IRQ3_IPR_ADDR INTPRI00
++#define IRQ4_IPR_ADDR INTPRI00
++#define IRQ5_IPR_ADDR INTPRI00
++#define IRQ6_IPR_ADDR INTPRI00
++#define IRQ7_IPR_ADDR INTPRI00
++
++#define IRQ0_IPR_POS 7
++#define IRQ1_IPR_POS 6
++#define IRQ2_IPR_POS 5
++#define IRQ3_IPR_POS 4
++#define IRQ4_IPR_POS 3
++#define IRQ5_IPR_POS 2
++#define IRQ6_IPR_POS 1
++#define IRQ7_IPR_POS 0
++
++#define IRQ0_PRIORITY 1
++#define IRQ1_PRIORITY 1
++#define IRQ2_PRIORITY 1
++#define IRQ3_PRIORITY 1
++#define IRQ4_PRIORITY 1
++#define IRQ5_PRIORITY 1
++#define IRQ6_PRIORITY 1
++#define IRQ7_PRIORITY 1
++
++#endif /* __ASM_SH_IRQ_SH7343_H */
+diff --git a/include/asm-sh/irq-sh7780.h b/include/asm-sh/irq-sh7780.h
+index 7f90315..19912ae 100644
+--- a/include/asm-sh/irq-sh7780.h
++++ b/include/asm-sh/irq-sh7780.h
+@@ -6,16 +6,6 @@
+ *
+ * Copyright (C) 2004 Takashi SHUDO <shudo at hitachi-ul.co.jp>
+ */
+-
+-#ifdef CONFIG_IDE
+-# ifndef IRQ_CFCARD
+-# define IRQ_CFCARD 14
+-# endif
+-# ifndef IRQ_PCMCIA
+-# define IRQ_PCMCIA 15
+-# endif
+-#endif
+-
+ #define INTC_BASE 0xffd00000
+ #define INTC_ICR0 (INTC_BASE+0x0)
+ #define INTC_ICR1 (INTC_BASE+0x1c)
+@@ -145,11 +135,6 @@
+ #define TMU_CH5_IPR_POS 1
+ #define TMU_CH5_PRIORITY 2
+
+-#define RTC_IRQ 22
+-#define RTC_IPR_ADDR INTC_INT2PRI1
+-#define RTC_IPR_POS 0
+-#define RTC_PRIORITY TIMER_PRIORITY
+-
+ /* SCIF0 */
+ #define SCIF0_ERI_IRQ 40
+ #define SCIF0_RXI_IRQ 41
+diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
+index 611e67c..6cd3e9e 100644
+--- a/include/asm-sh/irq.h
++++ b/include/asm-sh/irq.h
+@@ -14,16 +14,6 @@
+ #include <asm/machvec.h>
+ #include <asm/ptrace.h> /* for pt_regs */
+
+-#if defined(CONFIG_SH_HP6XX) || \
+- defined(CONFIG_SH_RTS7751R2D) || \
+- defined(CONFIG_SH_HS7751RVOIP) || \
+- defined(CONFIG_SH_HS7751RVOIP) || \
+- defined(CONFIG_SH_SH03) || \
+- defined(CONFIG_SH_R7780RP) || \
+- defined(CONFIG_SH_LANDISK)
+-#include <asm/mach/ide.h>
+-#endif
+-
+ #ifndef CONFIG_CPU_SUBTYPE_SH7780
+
+ #define INTC_DMAC0_MSK 0
+@@ -38,15 +28,6 @@
+ #define INTC_IPRD 0xffd00010UL
+ #endif
+
+-#ifdef CONFIG_IDE
+-# ifndef IRQ_CFCARD
+-# define IRQ_CFCARD 14
+-# endif
+-# ifndef IRQ_PCMCIA
+-# define IRQ_PCMCIA 15
+-# endif
+-#endif
+-
+ #define TIMER_IRQ 16
+ #define TIMER_IPR_ADDR INTC_IPRA
+ #define TIMER_IPR_POS 3
+@@ -192,7 +173,7 @@
+
+ #if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \
+ defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) || \
+- defined (CONFIG_CPU_SUBTYPE_SH7751)
++ defined (CONFIG_CPU_SUBTYPE_SH7751) || defined (CONFIG_CPU_SUBTYPE_SH7706)
+ #define SCI_ERI_IRQ 23
+ #define SCI_RXI_IRQ 24
+ #define SCI_TXI_IRQ 25
+@@ -207,6 +188,7 @@
+ #define SCIF0_IPR_POS 3
+ #define SCIF0_PRIORITY 3
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
+ #define SCIF_ERI_IRQ 56
+@@ -261,9 +243,12 @@
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+ # define ONCHIP_NR_IRQS 32
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7709) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705)
+ # define ONCHIP_NR_IRQS 64 // Actually 61
+ # define PINT_NR_IRQS 16
++#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
++# define ONCHIP_NR_IRQS 104
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+ # define ONCHIP_NR_IRQS 48 // Actually 44
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7751)
+@@ -275,7 +260,8 @@
+ #elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+ # define ONCHIP_NR_IRQS 144
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+- defined(CONFIG_CPU_SUBTYPE_SH73180)
++ defined(CONFIG_CPU_SUBTYPE_SH73180) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7343)
+ # define ONCHIP_NR_IRQS 109
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ # define ONCHIP_NR_IRQS 111
+@@ -311,6 +297,8 @@
+ # define OFFCHIP_NR_IRQS 4
+ #elif defined(CONFIG_SH_R7780RP)
+ # define OFFCHIP_NR_IRQS 16
++#elif defined(CONFIG_SH_7343_SOLUTION_ENGINE)
++# define OFFCHIP_NR_IRQS 12
+ #elif defined(CONFIG_SH_UNKNOWN)
+ # define OFFCHIP_NR_IRQS 16 /* Must also be last */
+ #else
+@@ -335,10 +323,21 @@ extern void make_maskreg_irq(unsigned in
+ extern unsigned short *irq_mask_register;
+
+ /*
++ * PINT IRQs
++ */
++void init_IRQ_pint(void);
++
++struct ipr_data {
++ unsigned int irq;
++ unsigned int addr; /* Address of Interrupt Priority Register */
++ int shift; /* Shifts of the 16-bit data */
++ int priority; /* The priority */
++};
++
++/*
+ * Function for "on chip support modules".
+ */
+-extern void make_ipr_irq(unsigned int irq, unsigned int addr,
+- int pos, int priority);
++extern void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs);
+ extern void make_imask_irq(unsigned int irq);
+
+ #if defined(CONFIG_CPU_SUBTYPE_SH7300)
+@@ -471,8 +470,10 @@ extern int ipr_irq_demux(int irq);
+
+ #define INTC_ICR 0xfffffee0UL
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+- defined(CONFIG_CPU_SUBTYPE_SH7709)
++ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
++ defined(CONFIG_CPU_SUBTYPE_SH7710)
+ #define INTC_IRR0 0xa4000004UL
+ #define INTC_IRR1 0xa4000006UL
+ #define INTC_IRR2 0xa4000008UL
+@@ -491,8 +492,105 @@ extern int ipr_irq_demux(int irq);
+ #define INTC_IPRF 0xa4080000UL
+ #define INTC_IPRG 0xa4080002UL
+ #define INTC_IPRH 0xa4080004UL
+-#endif
++#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
++/* Interrupt Controller Registers */
++#undef INTC_IPRA
++#undef INTC_IPRB
++#define INTC_IPRA 0xA414FEE2UL
++#define INTC_IPRB 0xA414FEE4UL
++#define INTC_IPRF 0xA4080000UL
++#define INTC_IPRG 0xA4080002UL
++#define INTC_IPRH 0xA4080004UL
++#define INTC_IPRI 0xA4080006UL
++
++#undef INTC_ICR0
++#undef INTC_ICR1
++#define INTC_ICR0 0xA414FEE0UL
++#define INTC_ICR1 0xA4140010UL
+
++#define INTC_IRR0 0xa4000004UL
++#define INTC_IRR1 0xa4000006UL
++#define INTC_IRR2 0xa4000008UL
++#define INTC_IRR3 0xa400000AUL
++#define INTC_IRR4 0xa400000CUL
++#define INTC_IRR5 0xa4080020UL
++#define INTC_IRR7 0xa4080024UL
++#define INTC_IRR8 0xa4080026UL
++
++/* Interrupt numbers */
++#define TIMER2_IRQ 18
++#define TIMER2_IPR_ADDR INTC_IPRA
++#define TIMER2_IPR_POS 1
++#define TIMER2_PRIORITY 2
++
++/* WDT */
++#define WDT_IRQ 27
++#define WDT_IPR_ADDR INTC_IPRB
++#define WDT_IPR_POS 3
++#define WDT_PRIORITY 2
++
++#define SCIF0_ERI_IRQ 52
++#define SCIF0_RXI_IRQ 53
++#define SCIF0_BRI_IRQ 54
++#define SCIF0_TXI_IRQ 55
++#define SCIF0_IPR_ADDR INTC_IPRE
++#define SCIF0_IPR_POS 2
++#define SCIF0_PRIORITY 3
++
++#define DMTE4_IRQ 76
++#define DMTE5_IRQ 77
++#define DMA2_IPR_ADDR INTC_IPRF
++#define DMA2_IPR_POS 2
++#define DMA2_PRIORITY 7
++
++#define IPSEC_IRQ 79
++#define IPSEC_IPR_ADDR INTC_IPRF
++#define IPSEC_IPR_POS 3
++#define IPSEC_PRIORITY 3
++
++/* EDMAC */
++#define EDMAC0_IRQ 80
++#define EDMAC0_IPR_ADDR INTC_IPRG
++#define EDMAC0_IPR_POS 3
++#define EDMAC0_PRIORITY 3
++
++#define EDMAC1_IRQ 81
++#define EDMAC1_IPR_ADDR INTC_IPRG
++#define EDMAC1_IPR_POS 2
++#define EDMAC1_PRIORITY 3
++
++#define EDMAC2_IRQ 82
++#define EDMAC2_IPR_ADDR INTC_IPRG
++#define EDMAC2_IPR_POS 1
++#define EDMAC2_PRIORITY 3
++
++/* SIOF */
++#define SIOF0_ERI_IRQ 96
++#define SIOF0_TXI_IRQ 97
++#define SIOF0_RXI_IRQ 98
++#define SIOF0_CCI_IRQ 99
++#define SIOF0_IPR_ADDR INTC_IPRH
++#define SIOF0_IPR_POS 0
++#define SIOF0_PRIORITY 7
++
++#define SIOF1_ERI_IRQ 100
++#define SIOF1_TXI_IRQ 101
++#define SIOF1_RXI_IRQ 102
++#define SIOF1_CCI_IRQ 103
++#define SIOF1_IPR_ADDR INTC_IPRI
++#define SIOF1_IPR_POS 1
++#define SIOF1_PRIORITY 7
++#endif /* CONFIG_CPU_SUBTYPE_SH7710 */
++
++#if defined(CONFIG_CPU_SUBTYPE_SH7710)
++#define PORT_PACR 0xa4050100UL
++#define PORT_PBCR 0xa4050102UL
++#define PORT_PCCR 0xa4050104UL
++#define PORT_PETCR 0xa4050106UL
++#define PORT_PADR 0xa4050120UL
++#define PORT_PBDR 0xa4050122UL
++#define PORT_PCDR 0xa4050124UL
++#else
+ #define PORT_PACR 0xa4000100UL
+ #define PORT_PBCR 0xa4000102UL
+ #define PORT_PCCR 0xa4000104UL
+@@ -501,6 +599,7 @@ extern int ipr_irq_demux(int irq);
+ #define PORT_PBDR 0xa4000122UL
+ #define PORT_PCDR 0xa4000124UL
+ #define PORT_PFDR 0xa400012aUL
++#endif
+
+ #define IRQ0_IRQ 32
+ #define IRQ1_IRQ 33
+@@ -577,7 +676,7 @@ extern int ipr_irq_demux(int irq);
+ #define NR_INTC2_IRQS 64
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ #define INTC2_BASE 0xffd40000
+-#define INTC2_FIRST_IRQ 22
++#define INTC2_FIRST_IRQ 21
+ #define INTC2_INTMSK_OFFSET (0x38)
+ #define INTC2_INTMSKCLR_OFFSET (0x3c)
+ #define NR_INTC2_IRQS 60
+@@ -585,15 +684,19 @@ extern int ipr_irq_demux(int irq);
+
+ #define INTC2_INTPRI_OFFSET 0x00
+
+-void make_intc2_irq(unsigned int irq,
+- unsigned int ipr_offset, unsigned int ipr_shift,
+- unsigned int msk_offset, unsigned int msk_shift,
+- unsigned int priority);
+-void init_IRQ_intc2(void);
+-void intc2_add_clear_irq(int irq, int (*fn)(int));
++struct intc2_data {
++ unsigned short irq;
++ unsigned char ipr_offset, ipr_shift;
++ unsigned char msk_offset, msk_shift;
++ unsigned char priority;
++};
+
++void make_intc2_irq(struct intc2_data *, unsigned int nr_irqs);
++void init_IRQ_intc2(void);
+ #endif
+
++extern int shmse_irq_demux(int irq);
++
+ static inline int generic_irq_demux(int irq)
+ {
+ return irq;
+@@ -605,8 +708,21 @@ static inline int generic_irq_demux(int
+ #define irq_canonicalize(irq) (irq)
+ #define irq_demux(irq) __irq_demux(sh_mv.mv_irq_demux(irq))
+
++#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
++
+ #if defined(CONFIG_CPU_SUBTYPE_SH73180)
+ #include <asm/irq-sh73180.h>
+ #endif
+
++#if defined(CONFIG_CPU_SUBTYPE_SH7343)
++#include <asm/irq-sh7343.h>
++#endif
++
+ #endif /* __ASM_SH_IRQ_H */
+diff --git a/include/asm-sh/irq_regs.h b/include/asm-sh/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-sh/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-sh/kexec.h b/include/asm-sh/kexec.h
+index 9dfe59f..9d235af 100644
+--- a/include/asm-sh/kexec.h
++++ b/include/asm-sh/kexec.h
+@@ -23,11 +23,10 @@
+ /* The native architecture */
+ #define KEXEC_ARCH KEXEC_ARCH_SH
+
+-#ifndef __ASSEMBLY__
++#define MAX_NOTE_BYTES 1024
+
+-extern void machine_shutdown(void);
+-extern void *crash_notes;
+-
+-#endif /* __ASSEMBLY__ */
++/* Provide a dummy definition to avoid build failures. */
++static inline void crash_setup_regs(struct pt_regs *newregs,
++ struct pt_regs *oldregs) { }
+
+ #endif /* _SH_KEXEC_H */
+diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h
+index 1653ffb..7b26f53 100644
+--- a/include/asm-sh/kgdb.h
++++ b/include/asm-sh/kgdb.h
+@@ -128,4 +128,19 @@ extern int setjmp(jmp_buf __jmpb);
+ #define KGDB_ASSERT(condition, message)
+ #endif
+
++/* Taken from sh-stub.c of GDB 4.18 */
++static const char hexchars[] = "0123456789abcdef";
++
++/* Get high hex bits */
++static inline char highhex(const int x)
++{
++ return hexchars[(x >> 4) & 0xf];
++}
++
++/* Get low hex bits */
++static inline char lowhex(const int x)
++{
++ return hexchars[x & 0xf];
++}
++
+ #endif
+diff --git a/include/asm-sh/landisk/gio.h b/include/asm-sh/landisk/gio.h
+new file mode 100644
+index 0000000..3fce4c4
+--- /dev/null
++++ b/include/asm-sh/landisk/gio.h
+@@ -0,0 +1,45 @@
++#ifndef __ASM_SH_LANDISK_GIO_H
++#define __ASM_SH_LANDISK_GIO_H
++
++#include <linux/ioctl.h>
++
++/* version */
++#define VERSION_STR "1.00"
++
++/* Driver name */
++#define GIO_DRIVER_NAME "/dev/giodrv"
++
++/* Use 'k' as magic number */
++#define GIODRV_IOC_MAGIC 'k'
++
++#define GIODRV_IOCRESET _IO(GIODRV_IOC_MAGIC, 0)
++/*
++ * S means "Set" through a ptr,
++ * T means "Tell" directly
++ * G means "Get" (to a pointed var)
++ * Q means "Query", response is on the return value
++ * X means "eXchange": G and S atomically
++ * H means "sHift": T and Q atomically
++ */
++#define GIODRV_IOCSGIODATA1 _IOW(GIODRV_IOC_MAGIC, 1, unsigned char *)
++#define GIODRV_IOCGGIODATA1 _IOR(GIODRV_IOC_MAGIC, 2, unsigned char *)
++#define GIODRV_IOCSGIODATA2 _IOW(GIODRV_IOC_MAGIC, 3, unsigned short *)
++#define GIODRV_IOCGGIODATA2 _IOR(GIODRV_IOC_MAGIC, 4, unsigned short *)
++#define GIODRV_IOCSGIODATA4 _IOW(GIODRV_IOC_MAGIC, 5, unsigned long *)
++#define GIODRV_IOCGGIODATA4 _IOR(GIODRV_IOC_MAGIC, 6, unsigned long *)
++#define GIODRV_IOCSGIOSETADDR _IOW(GIODRV_IOC_MAGIC, 7, unsigned long *)
++#define GIODRV_IOCHARDRESET _IO(GIODRV_IOC_MAGIC, 8) /* debugging tool */
++
++#define GIODRV_IOCSGIO_LED _IOW(GIODRV_IOC_MAGIC, 9, unsigned long *)
++#define GIODRV_IOCGGIO_LED _IOR(GIODRV_IOC_MAGIC, 10, unsigned long *)
++#define GIODRV_IOCSGIO_BUZZER _IOW(GIODRV_IOC_MAGIC, 11, unsigned long *)
++#define GIODRV_IOCGGIO_LANDISK _IOR(GIODRV_IOC_MAGIC, 14, unsigned long *)
++#define GIODRV_IOCGGIO_BTN _IOR(GIODRV_IOC_MAGIC, 22, unsigned long *)
++#define GIODRV_IOCSGIO_BTNPID _IOW(GIODRV_IOC_MAGIC, 23, unsigned long *)
++#define GIODRV_IOCGGIO_BTNPID _IOR(GIODRV_IOC_MAGIC, 24, unsigned long *)
++
++#define GIODRV_IOC_MAXNR 8
++#define GIO_READ 0x00000000
++#define GIO_WRITE 0x00000001
++
++#endif /* __ASM_SH_LANDISK_GIO_H */
+diff --git a/include/asm-sh/landisk/iodata_landisk.h b/include/asm-sh/landisk/iodata_landisk.h
+new file mode 100644
+index 0000000..c74d3c7
+--- /dev/null
++++ b/include/asm-sh/landisk/iodata_landisk.h
+@@ -0,0 +1,79 @@
++#ifndef __ASM_SH_IODATA_LANDISK_H
++#define __ASM_SH_IODATA_LANDISK_H
++
++/*
++ * linux/include/asm-sh/landisk/iodata_landisk.h
++ *
++ * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
++ *
++ * IO-DATA LANDISK support
++ */
++
++/* Box specific addresses. */
++
++#define PA_USB 0xa4000000 /* USB Controller M66590 */
++
++#define PA_ATARST 0xb0000000 /* ATA/FATA Access Control Register */
++#define PA_LED 0xb0000001 /* LED Control Register */
++#define PA_STATUS 0xb0000002 /* Switch Status Register */
++#define PA_SHUTDOWN 0xb0000003 /* Shutdown Control Register */
++#define PA_PCIPME 0xb0000004 /* PCI PME Status Register */
++#define PA_IMASK 0xb0000005 /* Interrupt Mask Register */
++/* 2003.10.31 I-O DATA NSD NWG add. for shutdown port clear */
++#define PA_PWRINT_CLR 0xb0000006 /* Shutdown Interrupt clear Register */
++
++#define PA_LCD_CLRDSP 0x00 /* LCD Clear Display Offset */
++#define PA_LCD_RTNHOME 0x00 /* LCD Return Home Offset */
++#define PA_LCD_ENTMODE 0x00 /* LCD Entry Mode Offset */
++#define PA_LCD_DSPCTL 0x00 /* LCD Display ON/OFF Control Offset */
++#define PA_LCD_FUNC 0x00 /* LCD Function Set Offset */
++#define PA_LCD_CGRAM 0x00 /* LCD Set CGRAM Address Offset */
++#define PA_LCD_DDRAM 0x00 /* LCD Set DDRAM Address Offset */
++#define PA_LCD_RDFLAG 0x01 /* LCD Read Busy Flag Offset */
++#define PA_LCD_WTDATA 0x02 /* LCD Write Datat to RAM Offset */
++#define PA_LCD_RDDATA 0x03 /* LCD Read Data from RAM Offset */
++#define PA_PIDE_OFFSET 0x40 /* CF IDE Offset */
++#define PA_SIDE_OFFSET 0x40 /* HDD IDE Offset */
++
++#define IRQ_PCIINTA 5 /* PCI INTA IRQ */
++#define IRQ_PCIINTB 6 /* PCI INTB IRQ */
++#define IRQ_PCIINDC 7 /* PCI INTC IRQ */
++#define IRQ_PCIINTD 8 /* PCI INTD IRQ */
++#define IRQ_ATA 9 /* ATA IRQ */
++#define IRQ_FATA 10 /* FATA IRQ */
++#define IRQ_POWER 11 /* Power Switch IRQ */
++#define IRQ_BUTTON 12 /* USL-5P Button IRQ */
++#define IRQ_FAULT 13 /* USL-5P Fault IRQ */
++
++#define SHUTDOWN_BTN_MAJOR 99 /* Shutdown button device major no. */
++
++#define SHUTDOWN_LOOP_CNT 5 /* Shutdown button Detection loop */
++#define SHUTDOWN_DELAY 200 /* Shutdown button delay value(ms) */
++
++
++/* added by kogiidena */
++/*
++ * landisk_ledparam
++ *
++ * led ------10 -6543210 -6543210 -6543210
++ * |000000..|0.......|0.......|U.......|
++ * | HARD |fastblik| blink | on |
++ *
++ * led0: power U:update flag
++ * led1: error
++ * led2: usb1
++ * led3: usb2
++ * led4: usb3
++ * led5: usb4
++ * led6: usb5
++ *
++ */
++extern int landisk_ledparam; /* from setup.c */
++extern int landisk_buzzerparam; /* from setup.c */
++extern int landisk_arch; /* from setup.c */
++
++#define __IO_PREFIX landisk
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_IODATA_LANDISK_H */
++
+diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h
+index 550501f..70389b7 100644
+--- a/include/asm-sh/machvec.h
++++ b/include/asm-sh/machvec.h
+@@ -8,17 +8,18 @@
+ */
+
+ #ifndef _ASM_SH_MACHVEC_H
+-#define _ASM_SH_MACHVEC_H 1
++#define _ASM_SH_MACHVEC_H
+
+ #include <linux/types.h>
+ #include <linux/time.h>
+-
+ #include <asm/machtypes.h>
+ #include <asm/machvec_init.h>
+
+ struct device;
+
+ struct sh_machine_vector {
++ void (*mv_setup)(char **cmdline_p);
++ const char *mv_name;
+ int mv_nr_irqs;
+
+ u8 (*mv_inb)(unsigned long);
+@@ -65,4 +66,6 @@ struct sh_machine_vector {
+
+ extern struct sh_machine_vector sh_mv;
+
++#define get_system_type() sh_mv.mv_name
++
+ #endif /* _ASM_SH_MACHVEC_H */
+diff --git a/include/asm-sh/mc146818rtc.h b/include/asm-sh/mc146818rtc.h
+index 1707cfb..0aee96a 100644
+--- a/include/asm-sh/mc146818rtc.h
++++ b/include/asm-sh/mc146818rtc.h
+@@ -4,173 +4,4 @@
+ #ifndef _ASM_MC146818RTC_H
+ #define _ASM_MC146818RTC_H
+
+-#ifdef CONFIG_SH_MPC1211
+-#undef _ASM_MC146818RTC_H
+-#undef RTC_IRQ
+-#include <asm/mpc1211/mc146818rtc.h>
+-#else
+-
+-#include <asm/rtc.h>
+-
+-#define RTC_ALWAYS_BCD 1
+-
+-/* FIXME:RTC Interrupt feature is not implemented yet. */
+-#undef RTC_IRQ
+-#define RTC_IRQ 0
+-
+-#if defined(CONFIG_CPU_SH3)
+-#define RTC_PORT(n) (R64CNT+(n)*2)
+-#define CMOS_READ(addr) __CMOS_READ(addr,b)
+-#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,b)
+-
+-#elif defined(CONFIG_SH_SECUREEDGE5410)
+-#include <asm/snapgear/io.h>
+-
+-#define RTC_PORT(n) SECUREEDGE_IOPORT_ADDR
+-#define CMOS_READ(addr) secureedge5410_cmos_read(addr)
+-#define CMOS_WRITE(val,addr) secureedge5410_cmos_write(val,addr)
+-extern unsigned char secureedge5410_cmos_read(int addr);
+-extern void secureedge5410_cmos_write(unsigned char val, int addr);
+-
+-#elif defined(CONFIG_CPU_SH4)
+-#define RTC_PORT(n) (R64CNT+(n)*4)
+-#define CMOS_READ(addr) __CMOS_READ(addr,w)
+-#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,w)
+-#endif
+-
+-#define __CMOS_READ(addr, s) ({ \
+- unsigned char val=0, rcr1, rcr2, r64cnt, retry; \
+- switch(addr) { \
+- case RTC_SECONDS: \
+- val = ctrl_inb(RSECCNT); \
+- break; \
+- case RTC_SECONDS_ALARM: \
+- val = ctrl_inb(RSECAR); \
+- break; \
+- case RTC_MINUTES: \
+- val = ctrl_inb(RMINCNT); \
+- break; \
+- case RTC_MINUTES_ALARM: \
+- val = ctrl_inb(RMINAR); \
+- break; \
+- case RTC_HOURS: \
+- val = ctrl_inb(RHRCNT); \
+- break; \
+- case RTC_HOURS_ALARM: \
+- val = ctrl_inb(RHRAR); \
+- break; \
+- case RTC_DAY_OF_WEEK: \
+- val = ctrl_inb(RWKCNT); \
+- break; \
+- case RTC_DAY_OF_MONTH: \
+- val = ctrl_inb(RDAYCNT); \
+- break; \
+- case RTC_MONTH: \
+- val = ctrl_inb(RMONCNT); \
+- break; \
+- case RTC_YEAR: \
+- val = ctrl_in##s(RYRCNT); \
+- break; \
+- case RTC_REG_A: /* RTC_FREQ_SELECT */ \
+- rcr2 = ctrl_inb(RCR2); \
+- val = (rcr2 & RCR2_PESMASK) >> 4; \
+- rcr1 = ctrl_inb(RCR1); \
+- rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\
+- retry = 0; \
+- do { \
+- ctrl_outb(rcr1, RCR1); /* clear CF */ \
+- r64cnt = ctrl_inb(R64CNT); \
+- } while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\
+- r64cnt ^= RTC_BIT_INVERTED; \
+- if(r64cnt == 0x7f || r64cnt == 0) \
+- val |= RTC_UIP; \
+- break; \
+- case RTC_REG_B: /* RTC_CONTROL */ \
+- rcr1 = ctrl_inb(RCR1); \
+- rcr2 = ctrl_inb(RCR2); \
+- if(rcr1 & RCR1_CIE) val |= RTC_UIE; \
+- if(rcr1 & RCR1_AIE) val |= RTC_AIE; \
+- if(rcr2 & RCR2_PESMASK) val |= RTC_PIE; \
+- if(!(rcr2 & RCR2_START))val |= RTC_SET; \
+- val |= RTC_24H; \
+- break; \
+- case RTC_REG_C: /* RTC_INTR_FLAGS */ \
+- rcr1 = ctrl_inb(RCR1); \
+- rcr1 &= ~(RCR1_CF | RCR1_AF); \
+- ctrl_outb(rcr1, RCR1); \
+- rcr2 = ctrl_inb(RCR2); \
+- rcr2 &= ~RCR2_PEF; \
+- ctrl_outb(rcr2, RCR2); \
+- break; \
+- case RTC_REG_D: /* RTC_VALID */ \
+- /* Always valid ... */ \
+- val = RTC_VRT; \
+- break; \
+- default: \
+- break; \
+- } \
+- val; \
+-})
+-
+-#define __CMOS_WRITE(val, addr, s) ({ \
+- unsigned char rcr1,rcr2; \
+- switch(addr) { \
+- case RTC_SECONDS: \
+- ctrl_outb(val, RSECCNT); \
+- break; \
+- case RTC_SECONDS_ALARM: \
+- ctrl_outb(val, RSECAR); \
+- break; \
+- case RTC_MINUTES: \
+- ctrl_outb(val, RMINCNT); \
+- break; \
+- case RTC_MINUTES_ALARM: \
+- ctrl_outb(val, RMINAR); \
+- break; \
+- case RTC_HOURS: \
+- ctrl_outb(val, RHRCNT); \
+- break; \
+- case RTC_HOURS_ALARM: \
+- ctrl_outb(val, RHRAR); \
+- break; \
+- case RTC_DAY_OF_WEEK: \
+- ctrl_outb(val, RWKCNT); \
+- break; \
+- case RTC_DAY_OF_MONTH: \
+- ctrl_outb(val, RDAYCNT); \
+- break; \
+- case RTC_MONTH: \
+- ctrl_outb(val, RMONCNT); \
+- break; \
+- case RTC_YEAR: \
+- ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\
+- break; \
+- case RTC_REG_A: /* RTC_FREQ_SELECT */ \
+- rcr2 = ctrl_inb(RCR2); \
+- if((val & RTC_DIV_CTL) == RTC_DIV_RESET2) \
+- rcr2 |= RCR2_RESET; \
+- ctrl_outb(rcr2, RCR2); \
+- break; \
+- case RTC_REG_B: /* RTC_CONTROL */ \
+- rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF; \
+- if(val & RTC_AIE) rcr1 |= RCR1_AIE; \
+- else rcr1 &= ~RCR1_AIE; \
+- if(val & RTC_UIE) rcr1 |= RCR1_CIE; \
+- else rcr1 &= ~RCR1_CIE; \
+- ctrl_outb(rcr1, RCR1); \
+- rcr2 = ctrl_inb(RCR2); \
+- if(val & RTC_SET) rcr2 &= ~RCR2_START; \
+- else rcr2 |= RCR2_START; \
+- ctrl_outb(rcr2, RCR2); \
+- break; \
+- case RTC_REG_C: /* RTC_INTR_FLAGS */ \
+- break; \
+- case RTC_REG_D: /* RTC_VALID */ \
+- break; \
+- default: \
+- break; \
+- } \
+-})
+-
+-#endif /* CONFIG_SH_MPC1211 */
+ #endif /* _ASM_MC146818RTC_H */
+diff --git a/include/asm-sh/mmu.h b/include/asm-sh/mmu.h
+index 72f07be..cf47df7 100644
+--- a/include/asm-sh/mmu.h
++++ b/include/asm-sh/mmu.h
+@@ -3,27 +3,76 @@
+
+ #if !defined(CONFIG_MMU)
+
+-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;
++ struct vm_list_struct *vmlist;
+ unsigned long end_brk;
+ } mm_context_t;
+
+ #else
+
+ /* Default "unsigned long" context */
+-typedef unsigned long mm_context_t;
++typedef unsigned long mm_context_id_t;
++
++typedef struct {
++ mm_context_id_t id;
++ void *vdso;
++} mm_context_t;
+
+ #endif /* CONFIG_MMU */
+-#endif /* __MMH_H */
++
++/*
++ * Privileged Space Mapping Buffer (PMB) definitions
++ */
++#define PMB_PASCR 0xff000070
++#define PMB_IRMCR 0xff000078
++
++#define PMB_ADDR 0xf6100000
++#define PMB_DATA 0xf7100000
++#define PMB_ENTRY_MAX 16
++#define PMB_E_MASK 0x0000000f
++#define PMB_E_SHIFT 8
++
++#define PMB_SZ_16M 0x00000000
++#define PMB_SZ_64M 0x00000010
++#define PMB_SZ_128M 0x00000080
++#define PMB_SZ_512M 0x00000090
++#define PMB_SZ_MASK PMB_SZ_512M
++#define PMB_C 0x00000008
++#define PMB_WT 0x00000001
++#define PMB_UB 0x00000200
++#define PMB_V 0x00000100
++
++#define PMB_NO_ENTRY (-1)
++
++struct pmb_entry;
++
++struct pmb_entry {
++ unsigned long vpn;
++ unsigned long ppn;
++ unsigned long flags;
++
++ /*
++ * 0 .. NR_PMB_ENTRIES for specific entry selection, or
++ * PMB_NO_ENTRY to search for a free one
++ */
++ int entry;
++
++ struct pmb_entry *next;
++ /* Adjacent entry link for contiguous multi-entry mappings */
++ struct pmb_entry *link;
++};
++
++/* arch/sh/mm/pmb.c */
++int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
++ unsigned long flags, int *entry);
++int set_pmb_entry(struct pmb_entry *pmbe);
++void clear_pmb_entry(struct pmb_entry *pmbe);
++struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
++ unsigned long flags);
++void pmb_free(struct pmb_entry *pmbe);
++long pmb_remap(unsigned long virt, unsigned long phys,
++ unsigned long size, unsigned long flags);
++void pmb_unmap(unsigned long addr);
++
++#endif /* __MMU_H */
+
+diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
+index 6760d06..c7088ef 100644
+--- a/include/asm-sh/mmu_context.h
++++ b/include/asm-sh/mmu_context.h
+@@ -49,7 +49,7 @@ get_mmu_context(struct mm_struct *mm)
+ unsigned long mc = mmu_context_cache;
+
+ /* Check if we have old version of context. */
+- if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
++ if (((mm->context.id ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
+ /* It's up to date, do nothing */
+ return;
+
+@@ -68,7 +68,7 @@ get_mmu_context(struct mm_struct *mm)
+ if (!mc)
+ mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
+ }
+- mm->context = mc;
++ mm->context.id = mc;
+ }
+
+ /*
+@@ -78,7 +78,7 @@ get_mmu_context(struct mm_struct *mm)
+ static __inline__ int init_new_context(struct task_struct *tsk,
+ struct mm_struct *mm)
+ {
+- mm->context = NO_CONTEXT;
++ mm->context.id = NO_CONTEXT;
+
+ return 0;
+ }
+@@ -123,7 +123,7 @@ static __inline__ unsigned long get_asid
+ static __inline__ void activate_context(struct mm_struct *mm)
+ {
+ get_mmu_context(mm);
+- set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
++ set_asid(mm->context.id & MMU_CONTEXT_ASID_MASK);
+ }
+
+ /* MMU_TTB can be used for optimizing the fault handling.
+@@ -174,9 +174,7 @@ static inline void enable_mmu(void)
+ {
+ /* Enable MMU */
+ ctrl_outl(MMU_CONTROL_INIT, MMUCR);
+-
+- /* The manual suggests doing some nops after turning on the MMU */
+- __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop\n\t");
++ ctrl_barrier();
+
+ if (mmu_context_cache == NO_CONTEXT)
+ mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
+@@ -191,7 +189,8 @@ static inline void disable_mmu(void)
+ cr = ctrl_inl(MMUCR);
+ cr &= ~MMU_CONTROL_INIT;
+ ctrl_outl(cr, MMUCR);
+- __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop\n\t");
++
++ ctrl_barrier();
+ }
+ #else
+ /*
+diff --git a/include/asm-sh/mpc1211/io.h b/include/asm-sh/mpc1211/io.h
+index eba8a0b..6298370 100644
+--- a/include/asm-sh/mpc1211/io.h
++++ b/include/asm-sh/mpc1211/io.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-sh/io_mpc1211.h
++ * include/asm-sh/mpc1211/io.h
+ *
+ * Copyright 2001 Saito.K & Jeanne
+ *
+diff --git a/include/asm-sh/mpc1211/keyboard.h b/include/asm-sh/mpc1211/keyboard.h
+index 71ef4cf..9020fee 100644
+--- a/include/asm-sh/mpc1211/keyboard.h
++++ b/include/asm-sh/mpc1211/keyboard.h
+@@ -24,7 +24,6 @@ extern void pckbd_leds(unsigned char led
+ extern void pckbd_init_hw(void);
+ extern int pckbd_pm_resume(struct pm_dev *, pm_request_t, void *);
+ extern pm_callback pm_kbd_request_override;
+-extern unsigned char pckbd_sysrq_xlate[128];
+
+ #define kbd_setkeycode pckbd_setkeycode
+ #define kbd_getkeycode pckbd_getkeycode
+@@ -32,9 +31,6 @@ extern unsigned char pckbd_sysrq_xlate[1
+ #define kbd_unexpected_up pckbd_unexpected_up
+ #define kbd_leds pckbd_leds
+ #define kbd_init_hw pckbd_init_hw
+-#define kbd_sysrq_xlate pckbd_sysrq_xlate
+-
+-#define SYSRQ_KEY 0x54
+
+ /* resource allocation */
+ #define kbd_request_region()
+diff --git a/include/asm-sh/overdrive/fpga.h b/include/asm-sh/overdrive/fpga.h
+deleted file mode 100644
+index 1cd8799..0000000
+--- a/include/asm-sh/overdrive/fpga.h
++++ /dev/null
+@@ -1,15 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- */
+-
+-#ifndef __FPGA_OD_H__
+-#define __FPGA_OD_H__
+-
+-/* This routine will program up the fpga which interfaces to the galileo */
+-int init_overdrive_fpga(void);
+-
+-#endif
+diff --git a/include/asm-sh/overdrive/gt64111.h b/include/asm-sh/overdrive/gt64111.h
+deleted file mode 100644
+index 01d58bc..0000000
+--- a/include/asm-sh/overdrive/gt64111.h
++++ /dev/null
+@@ -1,109 +0,0 @@
+-#ifndef _GT64111_H_
+-#define _GT64111_H_
+-
+-#define MASTER_INTERFACE 0x0
+-#define RAS10_LO_DEC_ADR 0x8
+-#define RAS10_HI_DEC_ADR 0x10
+-#define RAS32_LO_DEC_ADR 0x18
+-#define RAS32_HI_DEC_ADR 0x20
+-#define CS20_LO_DEC_ADR 0x28
+-#define CS20_HI_DEC_ADR 0x30
+-#define CS3_LO_DEC_ADR 0x38
+-#define CS3_HI_DEC_ADR 0x40
+-#define PCI_IO_LO_DEC_ADR 0x48
+-#define PCI_IO_HI_DEC_ADR 0x50
+-#define PCI_MEM0_LO_DEC_ADR 0x58
+-#define PCI_MEM0_HI_DEC_ADR 0x60
+-#define INTERNAL_SPACE_DEC 0x68
+-#define BUS_ERR_ADR_LO_CPU 0x70
+-#define READONLY0 0x78
+-#define PCI_MEM1_LO_DEC_ADR 0x80
+-#define PCI_MEM1_HI_DEC_ADR 0x88
+-#define RAS0_LO_DEC_ADR 0x400
+-#define RAS0_HI_DEC_ADR 0x404
+-#define RAS1_LO_DEC_ADR 0x408
+-#define RAS1_HI_DEC_ADR 0x40c
+-#define RAS2_LO_DEC_ADR 0x410
+-#define RAS2_HI_DEC_ADR 0x414
+-#define RAS3_LO_DEC_ADR 0x418
+-#define RAS3_HI_DEC_ADR 0x41c
+-#define DEV_CS0_LO_DEC_ADR 0x420
+-#define DEV_CS0_HI_DEC_ADR 0x424
+-#define DEV_CS1_LO_DEC_ADR 0x428
+-#define DEV_CS1_HI_DEC_ADR 0x42c
+-#define DEV_CS2_LO_DEC_ADR 0x430
+-#define DEV_CS2_HI_DEC_ADR 0x434
+-#define DEV_CS3_LO_DEC_ADR 0x438
+-#define DEV_CS3_HI_DEC_ADR 0x43c
+-#define DEV_BOOTCS_LO_DEC_ADR 0x440
+-#define DEV_BOOTCS_HI_DEC_ADR 0x444
+-#define DEV_ADR_DEC_ERR 0x470
+-#define DRAM_CFG 0x448
+-#define DRAM_BANK0_PARMS 0x44c
+-#define DRAM_BANK1_PARMS 0x450
+-#define DRAM_BANK2_PARMS 0x454
+-#define DRAM_BANK3_PARMS 0x458
+-#define DEV_BANK0_PARMS 0x45c
+-#define DEV_BANK1_PARMS 0x460
+-#define DEV_BANK2_PARMS 0x464
+-#define DEV_BANK3_PARMS 0x468
+-#define DEV_BOOT_BANK_PARMS 0x46c
+-#define CH0_DMA_BYTECOUNT 0x800
+-#define CH1_DMA_BYTECOUNT 0x804
+-#define CH2_DMA_BYTECOUNT 0x808
+-#define CH3_DMA_BYTECOUNT 0x80c
+-#define CH0_DMA_SRC_ADR 0x810
+-#define CH1_DMA_SRC_ADR 0x814
+-#define CH2_DMA_SRC_ADR 0x818
+-#define CH3_DMA_SRC_ADR 0x81c
+-#define CH0_DMA_DST_ADR 0x820
+-#define CH1_DMA_DST_ADR 0x824
+-#define CH2_DMA_DST_ADR 0x828
+-#define CH3_DMA_DST_ADR 0x82c
+-#define CH0_NEXT_REC_PTR 0x830
+-#define CH1_NEXT_REC_PTR 0x834
+-#define CH2_NEXT_REC_PTR 0x838
+-#define CH3_NEXT_REC_PTR 0x83c
+-#define CH0_CTRL 0x840
+-#define CH1_CTRL 0x844
+-#define CH2_CTRL 0x848
+-#define CH3_CTRL 0x84c
+-#define DMA_ARBITER 0x860
+-#define TIMER0 0x850
+-#define TIMER1 0x854
+-#define TIMER2 0x858
+-#define TIMER3 0x85c
+-#define TIMER_CTRL 0x864
+-#define PCI_CMD 0xc00
+-#define PCI_TIMEOUT 0xc04
+-#define PCI_RAS10_BANK_SIZE 0xc08
+-#define PCI_RAS32_BANK_SIZE 0xc0c
+-#define PCI_CS20_BANK_SIZE 0xc10
+-#define PCI_CS3_BANK_SIZE 0xc14
+-#define PCI_SERRMASK 0xc28
+-#define PCI_INTACK 0xc34
+-#define PCI_BAR_EN 0xc3c
+-#define PCI_CFG_ADR 0xcf8
+-#define PCI_CFG_DATA 0xcfc
+-#define PCI_INTCAUSE 0xc18
+-#define PCI_MAST_MASK 0xc1c
+-#define PCI_PCIMASK 0xc24
+-#define BAR_ENABLE_ADR 0xc3c
+-
+-/* These are config registers, accessible via PCI space */
+-#define PCI_CONFIG_RAS10_BASE_ADR 0x010
+-#define PCI_CONFIG_RAS32_BASE_ADR 0x014
+-#define PCI_CONFIG_CS20_BASE_ADR 0x018
+-#define PCI_CONFIG_CS3_BASE_ADR 0x01c
+-#define PCI_CONFIG_INT_REG_MM_ADR 0x020
+-#define PCI_CONFIG_INT_REG_IO_ADR 0x024
+-#define PCI_CONFIG_BOARD_VENDOR 0x02c
+-#define PCI_CONFIG_ROM_ADR 0x030
+-#define PCI_CONFIG_INT_PIN_LINE 0x03c
+-
+-
+-
+-
+-
+-#endif
+-
+diff --git a/include/asm-sh/overdrive/io.h b/include/asm-sh/overdrive/io.h
+deleted file mode 100644
+index 0dba700..0000000
+--- a/include/asm-sh/overdrive/io.h
++++ /dev/null
+@@ -1,39 +0,0 @@
+-/*
+- * include/asm-sh/io_od.h
+- *
+- * Copyright 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an STMicroelectronics Overdrive
+- */
+-
+-#ifndef _ASM_SH_IO_OD_H
+-#define _ASM_SH_IO_OD_H
+-
+-extern unsigned char od_inb(unsigned long port);
+-extern unsigned short od_inw(unsigned long port);
+-extern unsigned int od_inl(unsigned long port);
+-
+-extern void od_outb(unsigned char value, unsigned long port);
+-extern void od_outw(unsigned short value, unsigned long port);
+-extern void od_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char od_inb_p(unsigned long port);
+-extern unsigned short od_inw_p(unsigned long port);
+-extern unsigned int od_inl_p(unsigned long port);
+-extern void od_outb_p(unsigned char value, unsigned long port);
+-extern void od_outw_p(unsigned short value, unsigned long port);
+-extern void od_outl_p(unsigned int value, unsigned long port);
+-
+-extern void od_insb(unsigned long port, void *addr, unsigned long count);
+-extern void od_insw(unsigned long port, void *addr, unsigned long count);
+-extern void od_insl(unsigned long port, void *addr, unsigned long count);
+-extern void od_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void od_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void od_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned long od_isa_port2addr(unsigned long offset);
+-
+-#endif /* _ASM_SH_IO_OD_H */
+diff --git a/include/asm-sh/overdrive/overdrive.h b/include/asm-sh/overdrive/overdrive.h
+deleted file mode 100644
+index fc746c2..0000000
+--- a/include/asm-sh/overdrive/overdrive.h
++++ /dev/null
+@@ -1,88 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- */
+-
+-
+-#ifndef __OVERDRIVE_H__
+-#define __OVERDRIVE_H__
+-
+-#define OVERDRIVE_INT_CT 0xa3a00000
+-#define OVERDRIVE_INT_DT 0xa3b00000
+-
+-#define OVERDRIVE_CTRL 0xa3000000
+-
+-/* Shoving all these bits into the same register is not a good idea.
+- * As soon as I get a spare moment, I'll change the FPGA and put each
+- * bit in a separate register
+- */
+-
+-#define VALID_CTRL_BITS 0x1f
+-
+-#define ENABLE_RS232_MASK 0x1e
+-#define DISABLE_RS232_BIT 0x01
+-
+-#define ENABLE_NMI_MASK 0x1d
+-#define DISABLE_NMI_BIT 0x02
+-
+-#define RESET_PCI_MASK 0x1b
+-#define ENABLE_PCI_BIT 0x04
+-
+-#define ENABLE_LED_MASK 0x17
+-#define DISABLE_LED_BIT 0x08
+-
+-#define RESET_FPGA_MASK 0x0f
+-#define ENABLE_FPGA_BIT 0x10
+-
+-
+-#define FPGA_DCLK_ADDRESS 0xA3C00000
+-
+-#define FPGA_DATA 0x01 /* W */
+-#define FPGA_CONFDONE 0x02 /* R */
+-#define FPGA_NOT_STATUS 0x04 /* R */
+-#define FPGA_INITDONE 0x08 /* R */
+-
+-#define FPGA_TIMEOUT 100000
+-
+-
+-/* Interrupts for the overdrive. Note that these numbers have
+- * nothing to do with the actual IRQ numbers they appear on,
+- * this is all programmable. This is simply the position in the
+- * INT_CT register.
+- */
+-
+-#define OVERDRIVE_PCI_INTA 0
+-#define OVERDRIVE_PCI_INTB 1
+-#define OVERDRIVE_PCI_INTC 2
+-#define OVERDRIVE_PCI_INTD 3
+-#define OVERDRIVE_GALILEO_INT 4
+-#define OVERDRIVE_GALILEO_LOCAL_INT 5
+-#define OVERDRIVE_AUDIO_INT 6
+-#define OVERDRIVE_KEYBOARD_INT 7
+-
+-/* Which Linux IRQ should we assign to each interrupt source? */
+-#define OVERDRIVE_PCI_IRQ1 2
+-#ifdef CONFIG_HACKED_NE2K
+-#define OVERDRIVE_PCI_IRQ2 7
+-#else
+-#define OVERDRIVE_PCI_IRQ2 2
+-#undef OVERDRIVE_PCI_INTB
+-#define OVERDRIVE_PCI_INTB OVERDRIVE_PCI_INTA
+-
+-#endif
+-
+-/* Put the ESS solo audio chip on IRQ 4 */
+-#define OVERDRIVE_ESS_IRQ 4
+-
+-/* Where the memory behind the PCI bus appears */
+-#define PCI_DRAM_BASE 0xb7000000
+-#define PCI_DRAM_SIZE (16*1024*1024)
+-#define PCI_DRAM_FINISH (PCI_DRAM_BASE+PCI_DRAM_SIZE-1)
+-
+-/* Where the IO region appears in the memory */
+-#define PCI_GTIO_BASE 0xb8000000
+-
+-#endif
+diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
+index 5a057b0..ca8b26d 100644
+--- a/include/asm-sh/page.h
++++ b/include/asm-sh/page.h
+@@ -16,7 +16,13 @@
+
+ /* PAGE_SHIFT determines the page size */
+ #define PAGE_SHIFT 12
++
++#ifdef __ASSEMBLY__
++#define PAGE_SIZE (1 << PAGE_SHIFT)
++#else
+ #define PAGE_SIZE (1UL << PAGE_SHIFT)
++#endif
++
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+ #define PTE_MASK PAGE_MASK
+
+@@ -30,7 +36,6 @@
+ #define HPAGE_SIZE (1UL << HPAGE_SHIFT)
+ #define HPAGE_MASK (~(HPAGE_SIZE-1))
+ #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT)
+-#define ARCH_HAS_SETCLEAR_HUGE_PTE
+ #endif
+
+ #ifdef __KERNEL__
+@@ -39,10 +44,18 @@
+ extern void (*clear_page)(void *to);
+ extern void (*copy_page)(void *to, void *from);
+
++extern unsigned long shm_align_mask;
++
++#ifdef CONFIG_MMU
+ extern void clear_page_slow(void *to);
+ extern void copy_page_slow(void *to, void *from);
++#else
++extern void clear_page_nommu(void *to);
++extern void copy_page_nommu(void *to, void *from);
++#endif
+
+-#if defined(CONFIG_SH7705_CACHE_32KB) && defined(CONFIG_MMU)
++#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
++ defined(CONFIG_SH7705_CACHE_32KB))
+ struct page;
+ extern void clear_user_page(void *to, unsigned long address, struct page *pg);
+ extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
+@@ -51,29 +64,20 @@ extern void __copy_user_page(void *to, v
+ #elif defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH3) || !defined(CONFIG_MMU)
+ #define clear_user_page(page, vaddr, pg) clear_page(page)
+ #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
+-#elif defined(CONFIG_CPU_SH4)
+-struct page;
+-extern void clear_user_page(void *to, unsigned long address, struct page *pg);
+-extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
+-extern void __clear_user_page(void *to, void *orig_to);
+-extern void __copy_user_page(void *to, void *from, void *orig_to);
+ #endif
+
+ /*
+ * These are used to make use of C type-checking..
+ */
+ typedef struct { unsigned long pte; } pte_t;
+-typedef struct { unsigned long pmd; } pmd_t;
+ typedef struct { unsigned long pgd; } pgd_t;
+ 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) } )
+
+@@ -93,7 +97,7 @@ typedef struct { unsigned long pgprot; }
+ #define __MEMORY_START CONFIG_MEMORY_START
+ #define __MEMORY_SIZE CONFIG_MEMORY_SIZE
+
+-#define PAGE_OFFSET (0x80000000UL)
++#define PAGE_OFFSET CONFIG_PAGE_OFFSET
+ #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
+ #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
+
+@@ -112,9 +116,13 @@ typedef struct { unsigned long pgprot; }
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++/* vDSO support */
++#ifdef CONFIG_VSYSCALL
++#define __HAVE_ARCH_GATE_AREA
++#endif
++
++#endif /* __KERNEL__ */
+ #endif /* __ASM_SH_PAGE_H */
+diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
+index 0a523c8..6ccc948 100644
+--- a/include/asm-sh/pci.h
++++ b/include/asm-sh/pci.h
+@@ -32,6 +32,34 @@ extern struct pci_channel board_pci_chan
+ #define PCIBIOS_MIN_IO board_pci_channels->io_resource->start
+ #define PCIBIOS_MIN_MEM board_pci_channels->mem_resource->start
+
++/*
++ * I/O routine helpers
++ */
++#ifdef CONFIG_CPU_SUBTYPE_SH7780
++#define PCI_IO_AREA 0xFE400000
++#define PCI_IO_SIZE 0x00400000
++#else
++#define PCI_IO_AREA 0xFE240000
++#define PCI_IO_SIZE 0X00040000
++#endif
++
++#define PCI_MEM_SIZE 0x01000000
++
++#define SH4_PCIIOBR_MASK 0xFFFC0000
++#define pci_ioaddr(addr) (PCI_IO_AREA + (addr & ~SH4_PCIIOBR_MASK))
++
++#if defined(CONFIG_PCI)
++#define is_pci_ioaddr(port) \
++ (((port) >= PCIBIOS_MIN_IO) && \
++ ((port) < (PCIBIOS_MIN_IO + PCI_IO_SIZE)))
++#define is_pci_memaddr(port) \
++ (((port) >= PCIBIOS_MIN_MEM) && \
++ ((port) < (PCIBIOS_MIN_MEM + PCI_MEM_SIZE)))
++#else
++#define is_pci_ioaddr(port) (0)
++#define is_pci_memaddr(port) (0)
++#endif
++
+ struct pci_dev;
+
+ extern void pcibios_set_master(struct pci_dev *dev);
+@@ -87,15 +115,6 @@ static inline void pcibios_penalize_isa_
+ */
+ #define pci_dac_dma_supported(pci_dev, mask) (0)
+
+-/* 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) (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,
+@@ -107,11 +126,12 @@ static inline void pci_dma_burst_advice(
+ #endif
+
+ /* Board-specific fixup routines. */
+-extern void pcibios_fixup(void);
+-extern void pcibios_fixup_irqs(void);
++void pcibios_fixup(void);
++int pcibios_init_platform(void);
++int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
+
+ #ifdef CONFIG_PCI_AUTO
+-extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
++int pciauto_assign_resources(int busno, struct pci_channel *hose);
+ #endif
+
+ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
+index f4f233f..e841465 100644
+--- a/include/asm-sh/pgalloc.h
++++ b/include/asm-sh/pgalloc.h
+@@ -1,15 +1,6 @@
+ #ifndef __ASM_SH_PGALLOC_H
+ #define __ASM_SH_PGALLOC_H
+
+-#include <linux/threads.h>
+-#include <linux/slab.h>
+-#include <linux/mm.h>
+-
+-#define pgd_quicklist ((unsigned long *)0)
+-#define pmd_quicklist ((unsigned long *)0)
+-#define pte_quicklist ((unsigned long *)0)
+-#define pgtable_cache_size 0L
+-
+ #define pmd_populate_kernel(mm, pmd, pte) \
+ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
+
+@@ -24,38 +15,24 @@ static inline void pmd_populate(struct m
+ */
+ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+ {
+- unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
+- pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
+-
+- if (pgd)
+- memset(pgd, 0, pgd_size);
+-
+- return pgd;
++ return (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+ }
+
+ static inline void pgd_free(pgd_t *pgd)
+ {
+- kfree(pgd);
++ free_page((unsigned long)pgd);
+ }
+
+ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+ unsigned long address)
+ {
+- pte_t *pte;
+-
+- pte = (pte_t *) __get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+-
+- return pte;
++ return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+ }
+
+ static inline struct page *pte_alloc_one(struct mm_struct *mm,
+ unsigned long address)
+ {
+- struct page *pte;
+-
+- pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
+-
+- return pte;
++ return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+ }
+
+ static inline void pte_free_kernel(pte_t *pte)
+@@ -75,14 +52,8 @@ static inline void pte_free(struct page
+ * inside the pgd, so has no extra memory associated with it.
+ */
+
+-#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
+ #define pmd_free(x) do { } while (0)
+ #define __pmd_free_tlb(tlb,x) do { } while (0)
+-#define pgd_populate(mm, pmd, pte) BUG()
+ #define check_pgt_cache() do { } while (0)
+
+-#ifdef CONFIG_CPU_SH4
+-#define PG_mapped PG_arch_1
+-#endif
+-
+ #endif /* __ASM_SH_PGALLOC_H */
+diff --git a/include/asm-sh/pgtable-2level.h b/include/asm-sh/pgtable-2level.h
+index b0528aa..b525db6 100644
+--- a/include/asm-sh/pgtable-2level.h
++++ b/include/asm-sh/pgtable-2level.h
+@@ -50,9 +50,12 @@ static inline void pgd_clear (pgd_t * pg
+ #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+ #define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
+-#define pgd_page(pgd) \
++#define pgd_page_vaddr(pgd) \
+ ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
++#define pgd_page(pgd) \
++ (phys_to_page(pgd_val(pgd)))
++
+ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+ {
+ return (pmd_t *) dir;
+diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
+index dcd23a0..2c8682a 100644
+--- a/include/asm-sh/pgtable.h
++++ b/include/asm-sh/pgtable.h
+@@ -1,42 +1,42 @@
+-#ifndef __ASM_SH_PGTABLE_H
+-#define __ASM_SH_PGTABLE_H
+-
+-#include <asm-generic/4level-fixup.h>
+-
+ /*
++ * This file contains the functions and defines necessary to modify and
++ * use the SuperH page table tree.
++ *
+ * Copyright (C) 1999 Niibe Yutaka
+- * Copyright (C) 2002, 2003, 2004 Paul Mundt
++ * Copyright (C) 2002 - 2005 Paul Mundt
++ *
++ * 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 __ASM_SH_PGTABLE_H
++#define __ASM_SH_PGTABLE_H
+
+-#include <asm/pgtable-2level.h>
++#include <asm-generic/pgtable-nopmd.h>
++#include <asm/page.h>
++
++#define PTRS_PER_PGD 1024
+
+-/*
+- * This file contains the functions and defines necessary to modify and use
+- * the SuperH page table tree.
+- */
+ #ifndef __ASSEMBLY__
+-#include <asm/processor.h>
+ #include <asm/addrspace.h>
+ #include <asm/fixmap.h>
+-#include <linux/threads.h>
+
+ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+ extern void paging_init(void);
+
+ /*
+- * Basically we have the same two-level (which is the logical three level
+- * Linux page table layout folded) page tables as the i386.
+- */
+-
+-/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+-extern unsigned long empty_zero_page[1024];
++extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+ #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+ #endif /* !__ASSEMBLY__ */
+
++/* traditional two-level paging structure */
++#define PGDIR_SHIFT 22
++#define PTRS_PER_PMD 1
++#define PTRS_PER_PTE 1024
+ #define PMD_SIZE (1UL << PMD_SHIFT)
+ #define PMD_MASK (~(PMD_SIZE-1))
+ #define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+@@ -47,7 +47,6 @@ extern unsigned long empty_zero_page[102
+
+ #define PTE_PHYS_MASK 0x1ffff000
+
+-#ifndef __ASSEMBLY__
+ /*
+ * First 1MB map is used by fixed purpose.
+ * Currently only 4-enty (16kB) is used (see arch/sh/mm/cache.c)
+@@ -55,20 +54,41 @@ extern unsigned long empty_zero_page[102
+ #define VMALLOC_START (P3SEG+0x00100000)
+ #define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
+
+-#define _PAGE_WT 0x001 /* WT-bit on SH-4, 0 on SH-3 */
+-#define _PAGE_HW_SHARED 0x002 /* SH-bit : page is shared among processes */
+-#define _PAGE_DIRTY 0x004 /* D-bit : page changed */
+-#define _PAGE_CACHABLE 0x008 /* C-bit : cachable */
+-#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */
+-#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */
+-#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */
+-#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */
+-#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */
+-#define _PAGE_PROTNONE 0x200 /* software: if not present */
+-#define _PAGE_ACCESSED 0x400 /* software: page referenced */
+-#define _PAGE_U0_SHARED 0x800 /* software: page is shared in user space */
+-
+-#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */
++/*
++ * Linux PTEL encoding.
++ *
++ * Hardware and software bit definitions for the PTEL value:
++ *
++ * - Bits 0 and 7 are reserved on SH-3 (_PAGE_WT and _PAGE_SZ1 on SH-4).
++ *
++ * - Bit 1 is the SH-bit, but is unused on SH-3 due to an MMU bug (the
++ * hardware PTEL value can't have the SH-bit set when MMUCR.IX is set,
++ * which is the default in cpu-sh3/mmu_context.h:MMU_CONTROL_INIT).
++ *
++ * In order to keep this relatively clean, do not use these for defining
++ * SH-3 specific flags until all of the other unused bits have been
++ * exhausted.
++ *
++ * - Bit 9 is reserved by everyone and used by _PAGE_PROTNONE.
++ *
++ * - Bits 10 and 11 are low bits of the PPN that are reserved on >= 4K pages.
++ * Bit 10 is used for _PAGE_ACCESSED, bit 11 remains unused.
++ *
++ * - Bits 31, 30, and 29 remain unused by everyone and can be used for future
++ * software flags, although care must be taken to update _PAGE_CLEAR_FLAGS.
++ */
++#define _PAGE_WT 0x001 /* WT-bit on SH-4, 0 on SH-3 */
++#define _PAGE_HW_SHARED 0x002 /* SH-bit : shared among processes */
++#define _PAGE_DIRTY 0x004 /* D-bit : page changed */
++#define _PAGE_CACHABLE 0x008 /* C-bit : cachable */
++#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */
++#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */
++#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */
++#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */
++#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */
++#define _PAGE_PROTNONE 0x200 /* software: if not present */
++#define _PAGE_ACCESSED 0x400 /* software: page referenced */
++#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */
+
+ /* software: moves to PTEA.TC (Timing Control) */
+ #define _PAGE_PCC_AREA5 0x00000000 /* use BSC registers for area5 */
+@@ -83,23 +103,17 @@ extern unsigned long empty_zero_page[102
+ #define _PAGE_PCC_ATR8 0x60000000 /* Attribute Memory space, 8 bit bus */
+ #define _PAGE_PCC_ATR16 0x60000001 /* Attribute Memory space, 6 bit bus */
+
+-
+-/* Mask which drop software flags
+- * We also drop WT bit since it is used for _PAGE_FILE
+- * bit in this implementation.
+- */
+-#define _PAGE_CLEAR_FLAGS (_PAGE_WT | _PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_U0_SHARED)
+-
+-#if defined(CONFIG_CPU_SH3)
+-/*
+- * MMU on SH-3 has bug on SH-bit: We can't use it if MMUCR.IX=1.
+- * Work around: Just drop SH-bit.
+- */
+-#define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS | _PAGE_HW_SHARED))
++/* Mask which drops unused bits from the PTEL value */
++#ifdef CONFIG_CPU_SH3
++#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED| \
++ _PAGE_FILE | _PAGE_SZ1 | \
++ _PAGE_HW_SHARED)
+ #else
+-#define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS))
++#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
+ #endif
+
++#define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS))
++
+ /* Hardware flags: SZ0=1 (4k-byte) */
+ #define _PAGE_FLAGS_HARD _PAGE_SZ0
+
+@@ -109,15 +123,15 @@ extern unsigned long empty_zero_page[102
+ #define _PAGE_SZHUGE (_PAGE_SZ0 | _PAGE_SZ1)
+ #endif
+
+-#define _PAGE_SHARED _PAGE_U0_SHARED
+-
+ #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+ #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+-#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_SHARED)
++#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY)
++
++#ifndef __ASSEMBLY__
+
+ #ifdef CONFIG_MMU
+ #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_SHARED | _PAGE_FLAGS_HARD)
++#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+ #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+ #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+ #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD)
+@@ -137,12 +151,13 @@ extern unsigned long empty_zero_page[102
+ #define PAGE_KERNEL_PCC __pgprot(0)
+ #endif
+
++#endif /* __ASSEMBLY__ */
++
+ /*
+ * As i386 and MIPS, SuperH can't do page protection for execute, and
+ * considers that the same as a read. Also, write permissions imply
+- * read permissions. This is the closest we can get..
++ * read permissions. This is the closest we can get..
+ */
+-
+ #define __P000 PAGE_NONE
+ #define __P001 PAGE_READONLY
+ #define __P010 PAGE_COPY
+@@ -161,6 +176,26 @@ extern unsigned long empty_zero_page[102
+ #define __S110 PAGE_SHARED
+ #define __S111 PAGE_SHARED
+
++#ifndef __ASSEMBLY__
++
++/*
++ * Certain architectures need to do special things when PTEs
++ * within a page table are directly modified. Thus, the following
++ * hook is made available.
++ */
++#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
++#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
++
++/*
++ * (pmds are folded into pgds so this doesn't get actually called,
++ * but the define is needed for a generic inline function.)
++ */
++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
++
++#define pte_pfn(x) ((unsigned long)(((x).pte >> PAGE_SHIFT)))
++#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++
+ #define pte_none(x) (!pte_val(x))
+ #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+ #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
+@@ -171,7 +206,7 @@ extern unsigned long empty_zero_page[102
+ #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+
+ #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+-#define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK)
++#define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK)
+
+ /*
+ * The following only work if pte_present() is true.
+@@ -225,7 +260,7 @@ static inline pgprot_t pgprot_noncached(
+ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+ { set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; }
+
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ #define pmd_page(pmd) \
+@@ -242,12 +277,17 @@ static inline pte_t pte_modify(pte_t pte
+ #define pte_index(address) \
+ ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
+ #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
+ #define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
+ #define pte_unmap(pte) do { } while (0)
+ #define pte_unmap_nested(pte) do { } while (0)
+
++#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 %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++
+ struct vm_area_struct;
+ extern void update_mmu_cache(struct vm_area_struct * vma,
+ unsigned long address, pte_t pte);
+@@ -272,8 +312,6 @@ extern void update_mmu_cache(struct vm_a
+
+ typedef pte_t *pte_addr_t;
+
+-#endif /* !__ASSEMBLY__ */
+-
+ #define kern_addr_valid(addr) (1)
+
+ #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+@@ -301,5 +339,5 @@ extern pte_t ptep_get_and_clear(struct m
+
+ #include <asm-generic/pgtable.h>
+
++#endif /* !__ASSEMBLY__ */
+ #endif /* __ASM_SH_PAGE_H */
+-
+diff --git a/include/asm-sh/pm.h b/include/asm-sh/pm.h
+new file mode 100644
+index 0000000..56fdbd6
+--- /dev/null
++++ b/include/asm-sh/pm.h
+@@ -0,0 +1,17 @@
++/*
++ * 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 2006 (c) Andriy Skulysh <askulysh at gmail.com>
++ *
++ */
++#ifndef __ASM_SH_PM_H
++#define __ASM_SH_PM_H
++
++extern u8 wakeup_start;
++extern u8 wakeup_end;
++
++void pm_enter(void);
++
++#endif
+diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
+index eeb0f48..45bb74e 100644
+--- a/include/asm-sh/processor.h
++++ b/include/asm-sh/processor.h
+@@ -14,6 +14,7 @@
+ #include <asm/types.h>
+ #include <asm/cache.h>
+ #include <asm/ptrace.h>
++#include <asm/cpu-features.h>
+
+ /*
+ * Default implementation of macro that returns current
+@@ -38,27 +39,30 @@ enum cpu_type {
+ CPU_SH7604,
+
+ /* SH-3 types */
+- CPU_SH7705, CPU_SH7707, CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
+- CPU_SH7709, CPU_SH7709A, CPU_SH7729, CPU_SH7300,
++ CPU_SH7705, CPU_SH7706, CPU_SH7707,
++ CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
++ CPU_SH7709, CPU_SH7709A, CPU_SH7710,
++ CPU_SH7729, CPU_SH7300,
+
+ /* SH-4 types */
+ CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R,
+ CPU_SH7760, CPU_ST40RA, CPU_ST40GX1, CPU_SH4_202, CPU_SH4_501,
+- CPU_SH73180, CPU_SH7770, CPU_SH7780, CPU_SH7781,
++ CPU_SH73180, CPU_SH7343, CPU_SH7770, CPU_SH7780, CPU_SH7781,
+
+ /* Unknown subtype */
+ CPU_SH_NONE
+ };
+
+ struct sh_cpuinfo {
+- enum cpu_type type;
++ unsigned int type;
+ unsigned long loops_per_jiffy;
+
+- struct cache_info icache;
+- struct cache_info dcache;
++ struct cache_info icache; /* Primary I-cache */
++ struct cache_info dcache; /* Primary D-cache */
++ struct cache_info scache; /* Secondary cache */
+
+ unsigned long flags;
+-};
++} __attribute__ ((aligned(SMP_CACHE_BYTES)));
+
+ extern struct sh_cpuinfo boot_cpu_data;
+
+@@ -125,17 +129,6 @@ union sh_fpu_union {
+ struct sh_fpu_soft_struct soft;
+ };
+
+-/*
+- * Processor flags
+- */
+-
+-#define CPU_HAS_FPU 0x0001 /* Hardware FPU support */
+-#define CPU_HAS_P2_FLUSH_BUG 0x0002 /* Need to flush the cache in P2 area */
+-#define CPU_HAS_MMU_PAGE_ASSOC 0x0004 /* SH3: TLB way selection bit support */
+-#define CPU_HAS_DSP 0x0008 /* SH-DSP: DSP support */
+-#define CPU_HAS_PERF_COUNTER 0x0010 /* Hardware performance counters */
+-#define CPU_HAS_PTEA 0x0020 /* PTEA register */
+-
+ struct thread_struct {
+ unsigned long sp;
+ unsigned long pc;
+@@ -149,6 +142,10 @@ struct thread_struct {
+ union sh_fpu_union fpu;
+ };
+
++typedef struct {
++ unsigned long seg;
++} mm_segment_t;
++
+ /* Count of active tasks with UBC settings */
+ extern int ubc_usercnt;
+
+@@ -258,6 +255,8 @@ extern void save_fpu(struct task_struct
+ */
+ #define thread_saved_pc(tsk) (tsk->thread.pc)
+
++void show_trace(struct task_struct *tsk, unsigned long *sp,
++ struct pt_regs *regs);
+ extern unsigned long get_wchan(struct task_struct *p);
+
+ #define KSTK_EIP(tsk) ((tsk)->thread.pc)
+@@ -266,5 +265,24 @@ extern unsigned long get_wchan(struct ta
+ #define cpu_sleep() __asm__ __volatile__ ("sleep" : : : "memory")
+ #define cpu_relax() barrier()
+
++#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
++ defined(CONFIG_CPU_SH4)
++#define PREFETCH_STRIDE L1_CACHE_BYTES
++#define ARCH_HAS_PREFETCH
++#define ARCH_HAS_PREFETCHW
++static inline void prefetch(void *x)
++{
++ __asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory");
++}
++
++#define prefetchw(x) prefetch(x)
++#endif
++
++#ifdef CONFIG_VSYSCALL
++extern int vsyscall_init(void);
++#else
++#define vsyscall_init() do { } while (0)
++#endif
++
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_SH_PROCESSOR_H */
+diff --git a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h
+index 792fc35..ed358a3 100644
+--- a/include/asm-sh/ptrace.h
++++ b/include/asm-sh/ptrace.h
+@@ -1,8 +1,6 @@
+ #ifndef __ASM_SH_PTRACE_H
+ #define __ASM_SH_PTRACE_H
+
+-#include <asm/ubc.h>
+-
+ /*
+ * Copyright (C) 1999, 2000 Niibe Yutaka
+ *
+diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h
+new file mode 100644
+index 0000000..c18f648
+--- /dev/null
++++ b/include/asm-sh/r7780rp.h
+@@ -0,0 +1,171 @@
++#ifndef __ASM_SH_RENESAS_R7780RP_H
++#define __ASM_SH_RENESAS_R7780RP_H
++
++/*
++ * linux/include/asm-sh/r7780rp.h
++ *
++ * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
++ *
++ * Renesas Solutions Highlander R7780RP support
++ */
++
++/* Box specific addresses. */
++#if defined(CONFIG_SH_R7780MP)
++#define PA_BCR 0xa4000000 /* FPGA */
++#define PA_IRLMSK (PA_BCR+0x0000) /* Interrupt Mask control */
++#define PA_IRLMON (PA_BCR+0x0002) /* Interrupt Status control */
++#define PA_IRLPRI1 (PA_BCR+0x0004) /* Interrupt Priorty 1 */
++#define PA_IRLPRI2 (PA_BCR+0x0006) /* Interrupt Priorty 2 */
++#define PA_IRLPRI3 (PA_BCR+0x0008) /* Interrupt Priorty 3 */
++#define PA_IRLPRI4 (PA_BCR+0x000a) /* Interrupt Priorty 4 */
++#define PA_RSTCTL (PA_BCR+0x000c) /* Reset Control */
++#define PA_PCIBD (PA_BCR+0x000e) /* PCI Board detect control */
++#define PA_PCICD (PA_BCR+0x0010) /* PCI Conector detect control */
++#define PA_EXTGIO (PA_BCR+0x0016) /* Extension GPIO Control */
++#define PA_IVDRMON (PA_BCR+0x0018) /* iVDR Moniter control */
++#define PA_IVDRCTL (PA_BCR+0x001a) /* iVDR control */
++#define PA_OBLED (PA_BCR+0x001c) /* On Board LED control */
++#define PA_OBSW (PA_BCR+0x001e) /* On Board Switch control */
++#define PA_AUDIOSEL (PA_BCR+0x0020) /* Sound Interface Select control */
++#define PA_EXTPLR (PA_BCR+0x001e) /* Extention Pin Polarity control */
++#define PA_TPCTL (PA_BCR+0x0100) /* Touch Panel Access control */
++#define PA_TPDCKCTL (PA_BCR+0x0102) /* Touch Panel Access data control */
++#define PA_TPCTLCLR (PA_BCR+0x0104) /* Touch Panel Access control */
++#define PA_TPXPOS (PA_BCR+0x0106) /* Touch Panel X position control */
++#define PA_TPYPOS (PA_BCR+0x0108) /* Touch Panel Y position control */
++#define PA_DBSW (PA_BCR+0x0200) /* Debug Board Switch control */
++#define PA_CFCTL (PA_BCR+0x0300) /* CF Timing control */
++#define PA_CFPOW (PA_BCR+0x0302) /* CF Power control */
++#define PA_CFCDINTCLR (PA_BCR+0x0304) /* CF Insert Interrupt clear */
++#define PA_SCSMR0 (PA_BCR+0x0400) /* SCIF0 Serial mode control */
++#define PA_SCBRR0 (PA_BCR+0x0404) /* SCIF0 Bit rate control */
++#define PA_SCSCR0 (PA_BCR+0x0408) /* SCIF0 Serial control */
++#define PA_SCFTDR0 (PA_BCR+0x040c) /* SCIF0 Send FIFO control */
++#define PA_SCFSR0 (PA_BCR+0x0410) /* SCIF0 Serial status control */
++#define PA_SCFRDR0 (PA_BCR+0x0414) /* SCIF0 Receive FIFO control */
++#define PA_SCFCR0 (PA_BCR+0x0418) /* SCIF0 FIFO control */
++#define PA_SCTFDR0 (PA_BCR+0x041c) /* SCIF0 Send FIFO data control */
++#define PA_SCRFDR0 (PA_BCR+0x0420) /* SCIF0 Receive FIFO data control */
++#define PA_SCSPTR0 (PA_BCR+0x0424) /* SCIF0 Serial Port control */
++#define PA_SCLSR0 (PA_BCR+0x0428) /* SCIF0 Line Status control */
++#define PA_SCRER0 (PA_BCR+0x042c) /* SCIF0 Serial Error control */
++#define PA_SCSMR1 (PA_BCR+0x0500) /* SCIF1 Serial mode control */
++#define PA_SCBRR1 (PA_BCR+0x0504) /* SCIF1 Bit rate control */
++#define PA_SCSCR1 (PA_BCR+0x0508) /* SCIF1 Serial control */
++#define PA_SCFTDR1 (PA_BCR+0x050c) /* SCIF1 Send FIFO control */
++#define PA_SCFSR1 (PA_BCR+0x0510) /* SCIF1 Serial status control */
++#define PA_SCFRDR1 (PA_BCR+0x0514) /* SCIF1 Receive FIFO control */
++#define PA_SCFCR1 (PA_BCR+0x0518) /* SCIF1 FIFO control */
++#define PA_SCTFDR1 (PA_BCR+0x051c) /* SCIF1 Send FIFO data control */
++#define PA_SCRFDR1 (PA_BCR+0x0520) /* SCIF1 Receive FIFO data control */
++#define PA_SCSPTR1 (PA_BCR+0x0524) /* SCIF1 Serial Port control */
++#define PA_SCLSR1 (PA_BCR+0x0528) /* SCIF1 Line Status control */
++#define PA_SCRER1 (PA_BCR+0x052c) /* SCIF1 Serial Error control */
++#define PA_ICCR (PA_BCR+0x0600) /* Serial control */
++#define PA_SAR (PA_BCR+0x0602) /* Serial Slave control */
++#define PA_MDR (PA_BCR+0x0604) /* Serial Mode control */
++#define PA_ADR1 (PA_BCR+0x0606) /* Serial Address1 control */
++#define PA_DAR1 (PA_BCR+0x0646) /* Serial Data1 control */
++#define PA_VERREG (PA_BCR+0x0700) /* FPGA Version Register */
++#define PA_POFF (PA_BCR+0x0800) /* System Power Off control */
++#define PA_PMR (PA_BCR+0x0900) /* */
++
++#define PA_AX88796L 0xa4100400 /* AX88796L Area */
++#define PA_SC1602BSLB 0xa6000000 /* SC1602BSLB Area */
++#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
++#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
++
++#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
++
++#define IRQ_PCISLOT1 65 /* PCI Slot #1 IRQ */
++#define IRQ_PCISLOT2 66 /* PCI Slot #2 IRQ */
++#define IRQ_PCISLOT3 67 /* PCI Slot #3 IRQ */
++#define IRQ_PCISLOT4 68 /* PCI Slot #4 IRQ */
++// #define IRQ_CFINST 0 /* CF Card Insert IRQ */
++#define IRQ_TP 2 /* Touch Panel IRQ */
++#define IRQ_SCI1 3 /* SCI1 IRQ */
++#define IRQ_SCI0 4 /* SCI0 IRQ */
++#define IRQ_2SERIAL 5 /* Serial IRQ */
++#define IRQ_RTC 6 /* RTC A / B IRQ */
++#define IRQ_EXTENTION6 7 /* EXT6n IRQ */
++#define IRQ_EXTENTION5 8 /* EXT5n IRQ */
++#define IRQ_EXTENTION4 9 /* EXT4n IRQ */
++#define IRQ_EXTENTION2 10 /* EXT2n IRQ */
++#define IRQ_EXTENTION1 11 /* EXT1n IRQ */
++#define IRQ_ONETH 13 /* On board Ethernet IRQ */
++#define IRQ_PSW 14 /* Push Switch IRQ */
++
++#else /* R7780RP */
++
++#define PA_BCR 0xa5000000 /* FPGA */
++#define PA_IRLMSK (PA_BCR+0x0000) /* Interrupt Mask control */
++#define PA_IRLMON (PA_BCR+0x0002) /* Interrupt Status control */
++#define PA_SDPOW (PA_BCR+0x0004) /* SD Power control */
++#define PA_RSTCTL (PA_BCR+0x0006) /* Device Reset control */
++#define PA_PCIBD (PA_BCR+0x0008) /* PCI Board detect control */
++#define PA_PCICD (PA_BCR+0x000a) /* PCI Conector detect control */
++#define PA_ZIGIO1 (PA_BCR+0x000c) /* Zigbee IO control 1 */
++#define PA_ZIGIO2 (PA_BCR+0x000e) /* Zigbee IO control 2 */
++#define PA_ZIGIO3 (PA_BCR+0x0010) /* Zigbee IO control 3 */
++#define PA_ZIGIO4 (PA_BCR+0x0012) /* Zigbee IO control 4 */
++#define PA_IVDRMON (PA_BCR+0x0014) /* iVDR Moniter control */
++#define PA_IVDRCTL (PA_BCR+0x0016) /* iVDR control */
++#define PA_OBLED (PA_BCR+0x0018) /* On Board LED control */
++#define PA_OBSW (PA_BCR+0x001a) /* On Board Switch control */
++#define PA_AUDIOSEL (PA_BCR+0x001c) /* Sound Interface Select control */
++#define PA_EXTPLR (PA_BCR+0x001e) /* Extention Pin Polarity control */
++#define PA_TPCTL (PA_BCR+0x0100) /* Touch Panel Access control */
++#define PA_TPDCKCTL (PA_BCR+0x0102) /* Touch Panel Access data control */
++#define PA_TPCTLCLR (PA_BCR+0x0104) /* Touch Panel Access control */
++#define PA_TPXPOS (PA_BCR+0x0106) /* Touch Panel X position control */
++#define PA_TPYPOS (PA_BCR+0x0108) /* Touch Panel Y position control */
++#define PA_DBDET (PA_BCR+0x0200) /* Debug Board detect control */
++#define PA_DBDISPCTL (PA_BCR+0x0202) /* Debug Board Dot timing control */
++#define PA_DBSW (PA_BCR+0x0204) /* Debug Board Switch control */
++#define PA_CFCTL (PA_BCR+0x0300) /* CF Timing control */
++#define PA_CFPOW (PA_BCR+0x0302) /* CF Power control */
++#define PA_CFCDINTCLR (PA_BCR+0x0304) /* CF Insert Interrupt clear */
++#define PA_SCSMR (PA_BCR+0x0400) /* SCIF Serial mode control */
++#define PA_SCBRR (PA_BCR+0x0402) /* SCIF Bit rate control */
++#define PA_SCSCR (PA_BCR+0x0404) /* SCIF Serial control */
++#define PA_SCFDTR (PA_BCR+0x0406) /* SCIF Send FIFO control */
++#define PA_SCFSR (PA_BCR+0x0408) /* SCIF Serial status control */
++#define PA_SCFRDR (PA_BCR+0x040a) /* SCIF Receive FIFO control */
++#define PA_SCFCR (PA_BCR+0x040c) /* SCIF FIFO control */
++#define PA_SCFDR (PA_BCR+0x040e) /* SCIF FIFO data control */
++#define PA_SCLSR (PA_BCR+0x0412) /* SCIF Line Status control */
++#define PA_ICCR (PA_BCR+0x0500) /* Serial control */
++#define PA_SAR (PA_BCR+0x0502) /* Serial Slave control */
++#define PA_MDR (PA_BCR+0x0504) /* Serial Mode control */
++#define PA_ADR1 (PA_BCR+0x0506) /* Serial Address1 control */
++#define PA_DAR1 (PA_BCR+0x0546) /* Serial Data1 control */
++#define PA_VERREG (PA_BCR+0x0600) /* FPGA Version Register */
++
++#define PA_AX88796L 0xa5800400 /* AX88796L Area */
++#define PA_SC1602BSLB 0xa6000000 /* SC1602BSLB Area */
++#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
++#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
++
++#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
++
++#define IRQ_PCISLOT1 0 /* PCI Slot #1 IRQ */
++#define IRQ_PCISLOT2 1 /* PCI Slot #2 IRQ */
++#define IRQ_PCISLOT3 2 /* PCI Slot #3 IRQ */
++#define IRQ_PCISLOT4 3 /* PCI Slot #4 IRQ */
++#define IRQ_CFINST 5 /* CF Card Insert IRQ */
++#define IRQ_M66596 6 /* M66596 IRQ */
++#define IRQ_SDCARD 7 /* SD Card IRQ */
++#define IRQ_TUCHPANEL 8 /* Touch Panel IRQ */
++#define IRQ_SCI 9 /* SCI IRQ */
++#define IRQ_2SERIAL 10 /* Serial IRQ */
++#define IRQ_EXTENTION 11 /* EXTn IRQ */
++#define IRQ_ONETH 12 /* On board Ethernet IRQ */
++#define IRQ_PSW 13 /* Push Switch IRQ */
++#define IRQ_ZIGBEE 14 /* Ziggbee IO IRQ */
++
++#endif /* CONFIG_SH_R7780MP */
++
++#define __IO_PREFIX r7780rp
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_RENESAS_R7780RP */
+diff --git a/include/asm-sh/rtc.h b/include/asm-sh/rtc.h
+index cea9cdf..91aacc9 100644
+--- a/include/asm-sh/rtc.h
++++ b/include/asm-sh/rtc.h
+@@ -1,29 +1,8 @@
+ #ifndef _ASM_RTC_H
+ #define _ASM_RTC_H
+-#ifdef __KERNEL__
+
+-#include <asm/machvec.h>
+-#include <asm/cpu/rtc.h>
+-
+-extern void sh_rtc_gettimeofday(struct timespec *ts);
+-extern int sh_rtc_settimeofday(const time_t secs);
+ extern void (*board_time_init)(void);
+-extern void (*rtc_get_time)(struct timespec *);
+-extern int (*rtc_set_time)(const time_t);
+-
+-/* RCR1 Bits */
+-#define RCR1_CF 0x80 /* Carry Flag */
+-#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
+-#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
+-#define RCR1_AF 0x01 /* Alarm Flag */
+-
+-/* RCR2 Bits */
+-#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
+-#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
+-#define RCR2_RTCEN 0x08 /* ENable RTC */
+-#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
+-#define RCR2_RESET 0x02 /* Reset bit */
+-#define RCR2_START 0x01 /* Start bit */
++extern void (*rtc_sh_get_time)(struct timespec *);
++extern int (*rtc_sh_set_time)(const time_t);
+
+-#endif /* __KERNEL__ */
+ #endif /* _ASM_RTC_H */
+diff --git a/include/asm-sh/rts7751r2d.h b/include/asm-sh/rts7751r2d.h
+new file mode 100644
+index 0000000..796b8fc
+--- /dev/null
++++ b/include/asm-sh/rts7751r2d.h
+@@ -0,0 +1,74 @@
++#ifndef __ASM_SH_RENESAS_RTS7751R2D_H
++#define __ASM_SH_RENESAS_RTS7751R2D_H
++
++/*
++ * linux/include/asm-sh/renesas_rts7751r2d.h
++ *
++ * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
++ *
++ * Renesas Technology Sales RTS7751R2D support
++ */
++
++/* Box specific addresses. */
++
++#define PA_BCR 0xa4000000 /* FPGA */
++#define PA_IRLMON 0xa4000002 /* Interrupt Status control */
++#define PA_CFCTL 0xa4000004 /* CF Timing control */
++#define PA_CFPOW 0xa4000006 /* CF Power control */
++#define PA_DISPCTL 0xa4000008 /* Display Timing control */
++#define PA_SDMPOW 0xa400000a /* SD Power control */
++#define PA_RTCCE 0xa400000c /* RTC(9701) Enable control */
++#define PA_PCICD 0xa400000e /* PCI Extention detect control */
++#define PA_VOYAGERRTS 0xa4000020 /* VOYAGER Reset control */
++#if defined(CONFIG_RTS7751R2D_REV11)
++#define PA_AXRST 0xa4000022 /* AX_LAN Reset control */
++#define PA_CFRST 0xa4000024 /* CF Reset control */
++#define PA_ADMRTS 0xa4000026 /* SD Reset control */
++#define PA_EXTRST 0xa4000028 /* Extention Reset control */
++#define PA_CFCDINTCLR 0xa400002a /* CF Insert Interrupt clear */
++#else
++#define PA_CFRST 0xa4000022 /* CF Reset control */
++#define PA_ADMRTS 0xa4000024 /* SD Reset control */
++#define PA_EXTRST 0xa4000026 /* Extention Reset control */
++#define PA_CFCDINTCLR 0xa4000028 /* CF Insert Interrupt clear */
++#define PA_KEYCTLCLR 0xa400002a /* Key Interrupt clear */
++#endif
++#define PA_POWOFF 0xa4000030 /* Board Power OFF control */
++#define PA_VERREG 0xa4000032 /* FPGA Version Register */
++#define PA_INPORT 0xa4000034 /* KEY Input Port control */
++#define PA_OUTPORT 0xa4000036 /* LED control */
++#define PA_DMPORT 0xa4000038 /* DM270 Output Port control */
++
++#define PA_AX88796L 0xaa000400 /* AX88796L Area */
++#define PA_VOYAGER 0xab000000 /* VOYAGER GX Area */
++#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
++#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
++
++#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
++
++#if defined(CONFIG_RTS7751R2D_REV11)
++#define IRQ_PCIETH 0 /* PCI Ethernet IRQ */
++#define IRQ_CFCARD 1 /* CF Card IRQ */
++#define IRQ_CFINST 2 /* CF Card Insert IRQ */
++#define IRQ_PCMCIA 3 /* PCMCIA IRQ */
++#define IRQ_VOYAGER 4 /* VOYAGER IRQ */
++#define IRQ_ONETH 5 /* On board Ethernet IRQ */
++#else
++#define IRQ_KEYIN 0 /* Key Input IRQ */
++#define IRQ_PCIETH 1 /* PCI Ethernet IRQ */
++#define IRQ_CFCARD 2 /* CF Card IRQ */
++#define IRQ_CFINST 3 /* CF Card Insert IRQ */
++#define IRQ_PCMCIA 4 /* PCMCIA IRQ */
++#define IRQ_VOYAGER 5 /* VOYAGER IRQ */
++#endif
++#define IRQ_RTCALM 6 /* RTC Alarm IRQ */
++#define IRQ_RTCTIME 7 /* RTC Timer IRQ */
++#define IRQ_SDCARD 8 /* SD Card IRQ */
++#define IRQ_PCISLOT1 9 /* PCI Slot #1 IRQ */
++#define IRQ_PCISLOT2 10 /* PCI Slot #2 IRQ */
++#define IRQ_EXTENTION 11 /* EXTn IRQ */
++
++#define __IO_PREFIX rts7751r2d
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_RENESAS_RTS7751R2D */
+diff --git a/include/asm-sh/rts7751r2d/ide.h b/include/asm-sh/rts7751r2d/ide.h
+deleted file mode 100644
+index 416f96b..0000000
+--- a/include/asm-sh/rts7751r2d/ide.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef __ASM_SH_RTS7751R2D_IDE_H
+-#define __ASM_SH_RTS7751R2D_IDE_H
+-
+-/* Nothing to see here.. */
+-#include <asm/rts7751r2d/rts7751r2d.h>
+-
+-#endif /* __ASM_SH_RTS7751R2D_IDE_H */
+-
+diff --git a/include/asm-sh/rts7751r2d/io.h b/include/asm-sh/rts7751r2d/io.h
+deleted file mode 100644
+index 2410940..0000000
+--- a/include/asm-sh/rts7751r2d/io.h
++++ /dev/null
+@@ -1,37 +0,0 @@
+-/*
+- * include/asm-sh/io_rts7751r2d.h
+- *
+- * Modified version of io_se.h for the rts7751r2d-specific functions.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an Renesas Technology sales RTS7751R2D
+- */
+-
+-#ifndef _ASM_SH_IO_RTS7751R2D_H
+-#define _ASM_SH_IO_RTS7751R2D_H
+-
+-extern unsigned char rts7751r2d_inb(unsigned long port);
+-extern unsigned short rts7751r2d_inw(unsigned long port);
+-extern unsigned int rts7751r2d_inl(unsigned long port);
+-
+-extern void rts7751r2d_outb(unsigned char value, unsigned long port);
+-extern void rts7751r2d_outw(unsigned short value, unsigned long port);
+-extern void rts7751r2d_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char rts7751r2d_inb_p(unsigned long port);
+-extern void rts7751r2d_outb_p(unsigned char value, unsigned long port);
+-
+-extern void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count);
+-extern void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count);
+-extern void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count);
+-extern void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern void *rts7751r2d_ioremap(unsigned long offset, unsigned long size);
+-
+-extern unsigned long rts7751r2d_isa_port2addr(unsigned long offset);
+-
+-#endif /* _ASM_SH_IO_RTS7751R2D_H */
+diff --git a/include/asm-sh/rts7751r2d/rts7751r2d.h b/include/asm-sh/rts7751r2d/rts7751r2d.h
+deleted file mode 100644
+index 4e09ba5..0000000
+--- a/include/asm-sh/rts7751r2d/rts7751r2d.h
++++ /dev/null
+@@ -1,73 +0,0 @@
+-#ifndef __ASM_SH_RENESAS_RTS7751R2D_H
+-#define __ASM_SH_RENESAS_RTS7751R2D_H
+-
+-/*
+- * linux/include/asm-sh/renesas_rts7751r2d.h
+- *
+- * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
+- *
+- * Renesas Technology Sales RTS7751R2D support
+- */
+-
+-/* Box specific addresses. */
+-
+-#define PA_BCR 0xa4000000 /* FPGA */
+-#define PA_IRLMON 0xa4000002 /* Interrupt Status control */
+-#define PA_CFCTL 0xa4000004 /* CF Timing control */
+-#define PA_CFPOW 0xa4000006 /* CF Power control */
+-#define PA_DISPCTL 0xa4000008 /* Display Timing control */
+-#define PA_SDMPOW 0xa400000a /* SD Power control */
+-#define PA_RTCCE 0xa400000c /* RTC(9701) Enable control */
+-#define PA_PCICD 0xa400000e /* PCI Extention detect control */
+-#define PA_VOYAGERRTS 0xa4000020 /* VOYAGER Reset control */
+-#if defined(CONFIG_RTS7751R2D_REV11)
+-#define PA_AXRST 0xa4000022 /* AX_LAN Reset control */
+-#define PA_CFRST 0xa4000024 /* CF Reset control */
+-#define PA_ADMRTS 0xa4000026 /* SD Reset control */
+-#define PA_EXTRST 0xa4000028 /* Extention Reset control */
+-#define PA_CFCDINTCLR 0xa400002a /* CF Insert Interrupt clear */
+-#else
+-#define PA_CFRST 0xa4000022 /* CF Reset control */
+-#define PA_ADMRTS 0xa4000024 /* SD Reset control */
+-#define PA_EXTRST 0xa4000026 /* Extention Reset control */
+-#define PA_CFCDINTCLR 0xa4000028 /* CF Insert Interrupt clear */
+-#define PA_KEYCTLCLR 0xa400002a /* Key Interrupt clear */
+-#endif
+-#define PA_POWOFF 0xa4000030 /* Board Power OFF control */
+-#define PA_VERREG 0xa4000032 /* FPGA Version Register */
+-#define PA_INPORT 0xa4000034 /* KEY Input Port control */
+-#define PA_OUTPORT 0xa4000036 /* LED control */
+-#define PA_DMPORT 0xa4000038 /* DM270 Output Port control */
+-
+-#define PA_AX88796L 0xaa000400 /* AX88796L Area */
+-#define PA_VOYAGER 0xab000000 /* VOYAGER GX Area */
+-#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
+-#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
+-#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
+-#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
+-
+-#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
+-
+-#if defined(CONFIG_RTS7751R2D_REV11)
+-#define IRQ_PCIETH 0 /* PCI Ethernet IRQ */
+-#define IRQ_CFCARD 1 /* CF Card IRQ */
+-#define IRQ_CFINST 2 /* CF Card Insert IRQ */
+-#define IRQ_PCMCIA 3 /* PCMCIA IRQ */
+-#define IRQ_VOYAGER 4 /* VOYAGER IRQ */
+-#define IRQ_ONETH 5 /* On board Ethernet IRQ */
+-#else
+-#define IRQ_KEYIN 0 /* Key Input IRQ */
+-#define IRQ_PCIETH 1 /* PCI Ethernet IRQ */
+-#define IRQ_CFCARD 2 /* CF Card IRQ */
+-#define IRQ_CFINST 3 /* CF Card Insert IRQ */
+-#define IRQ_PCMCIA 4 /* PCMCIA IRQ */
+-#define IRQ_VOYAGER 5 /* VOYAGER IRQ */
+-#endif
+-#define IRQ_RTCALM 6 /* RTC Alarm IRQ */
+-#define IRQ_RTCTIME 7 /* RTC Timer IRQ */
+-#define IRQ_SDCARD 8 /* SD Card IRQ */
+-#define IRQ_PCISLOT1 9 /* PCI Slot #1 IRQ */
+-#define IRQ_PCISLOT2 10 /* PCI Slot #2 IRQ */
+-#define IRQ_EXTENTION 11 /* EXTn IRQ */
+-
+-#endif /* __ASM_SH_RENESAS_RTS7751R2D */
+diff --git a/include/asm-sh/rts7751r2d/voyagergx_reg.h b/include/asm-sh/rts7751r2d/voyagergx_reg.h
+deleted file mode 100644
+index f031b5d..0000000
+--- a/include/asm-sh/rts7751r2d/voyagergx_reg.h
++++ /dev/null
+@@ -1,313 +0,0 @@
+-/* -------------------------------------------------------------------- */
+-/* voyagergx_reg.h */
+-/* -------------------------------------------------------------------- */
+-/* 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.
+-
+- Copyright 2003 (c) Lineo uSolutions,Inc.
+-*/
+-/* -------------------------------------------------------------------- */
+-
+-#ifndef _VOYAGER_GX_REG_H
+-#define _VOYAGER_GX_REG_H
+-
+-#define VOYAGER_BASE 0xb3e00000
+-#define VOYAGER_USBH_BASE (0x40000 + VOYAGER_BASE)
+-#define VOYAGER_UART_BASE (0x30000 + VOYAGER_BASE)
+-#define VOYAGER_AC97_BASE (0xa0000 + VOYAGER_BASE)
+-
+-#define VOYAGER_IRQ_NUM 32
+-#define VOYAGER_IRQ_BASE 50
+-#define VOYAGER_USBH_IRQ VOYAGER_IRQ_BASE + 6
+-#define VOYAGER_8051_IRQ VOYAGER_IRQ_BASE + 10
+-#define VOYAGER_UART0_IRQ VOYAGER_IRQ_BASE + 12
+-#define VOYAGER_UART1_IRQ VOYAGER_IRQ_BASE + 13
+-#define VOYAGER_AC97_IRQ VOYAGER_IRQ_BASE + 17
+-
+-/* ----- MISC controle register ------------------------------ */
+-#define MISC_CTRL (0x000004 + VOYAGER_BASE)
+-#define MISC_CTRL_USBCLK_48 (3 << 28)
+-#define MISC_CTRL_USBCLK_96 (2 << 28)
+-#define MISC_CTRL_USBCLK_CRYSTAL (1 << 28)
+-
+-/* ----- GPIO[31:0] register --------------------------------- */
+-#define GPIO_MUX_LOW (0x000008 + VOYAGER_BASE)
+-#define GPIO_MUX_LOW_AC97 0x1F000000
+-#define GPIO_MUX_LOW_8051 0x0000ffff
+-#define GPIO_MUX_LOW_PWM (1 << 29)
+-
+-/* ----- GPIO[63:32] register --------------------------------- */
+-#define GPIO_MUX_HIGH (0x00000C + VOYAGER_BASE)
+-
+-/* ----- DRAM controle register ------------------------------- */
+-#define DRAM_CTRL (0x000010 + VOYAGER_BASE)
+-#define DRAM_CTRL_EMBEDDED (1 << 31)
+-#define DRAM_CTRL_CPU_BURST_1 (0 << 28)
+-#define DRAM_CTRL_CPU_BURST_2 (1 << 28)
+-#define DRAM_CTRL_CPU_BURST_4 (2 << 28)
+-#define DRAM_CTRL_CPU_BURST_8 (3 << 28)
+-#define DRAM_CTRL_CPU_CAS_LATENCY (1 << 27)
+-#define DRAM_CTRL_CPU_SIZE_2 (0 << 24)
+-#define DRAM_CTRL_CPU_SIZE_4 (1 << 24)
+-#define DRAM_CTRL_CPU_SIZE_64 (4 << 24)
+-#define DRAM_CTRL_CPU_SIZE_32 (5 << 24)
+-#define DRAM_CTRL_CPU_SIZE_16 (6 << 24)
+-#define DRAM_CTRL_CPU_SIZE_8 (7 << 24)
+-#define DRAM_CTRL_CPU_COLUMN_SIZE_1024 (0 << 22)
+-#define DRAM_CTRL_CPU_COLUMN_SIZE_512 (2 << 22)
+-#define DRAM_CTRL_CPU_COLUMN_SIZE_256 (3 << 22)
+-#define DRAM_CTRL_CPU_ACTIVE_PRECHARGE (1 << 21)
+-#define DRAM_CTRL_CPU_RESET (1 << 20)
+-#define DRAM_CTRL_CPU_BANKS (1 << 19)
+-#define DRAM_CTRL_CPU_WRITE_PRECHARGE (1 << 18)
+-#define DRAM_CTRL_BLOCK_WRITE (1 << 17)
+-#define DRAM_CTRL_REFRESH_COMMAND (1 << 16)
+-#define DRAM_CTRL_SIZE_4 (0 << 13)
+-#define DRAM_CTRL_SIZE_8 (1 << 13)
+-#define DRAM_CTRL_SIZE_16 (2 << 13)
+-#define DRAM_CTRL_SIZE_32 (3 << 13)
+-#define DRAM_CTRL_SIZE_64 (4 << 13)
+-#define DRAM_CTRL_SIZE_2 (5 << 13)
+-#define DRAM_CTRL_COLUMN_SIZE_256 (0 << 11)
+-#define DRAM_CTRL_COLUMN_SIZE_512 (2 << 11)
+-#define DRAM_CTRL_COLUMN_SIZE_1024 (3 << 11)
+-#define DRAM_CTRL_BLOCK_WRITE_TIME (1 << 10)
+-#define DRAM_CTRL_BLOCK_WRITE_PRECHARGE (1 << 9)
+-#define DRAM_CTRL_ACTIVE_PRECHARGE (1 << 8)
+-#define DRAM_CTRL_RESET (1 << 7)
+-#define DRAM_CTRL_REMAIN_ACTIVE (1 << 6)
+-#define DRAM_CTRL_BANKS (1 << 1)
+-#define DRAM_CTRL_WRITE_PRECHARGE (1 << 0)
+-
+-/* ----- Arvitration control register -------------------------- */
+-#define ARBITRATION_CTRL (0x000014 + VOYAGER_BASE)
+-#define ARBITRATION_CTRL_CPUMEM (1 << 29)
+-#define ARBITRATION_CTRL_INTMEM (1 << 28)
+-#define ARBITRATION_CTRL_USB_OFF (0 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_1 (1 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_2 (2 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_3 (3 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_4 (4 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_5 (5 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_6 (6 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_7 (7 << 24)
+-#define ARBITRATION_CTRL_PANEL_OFF (0 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_1 (1 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_2 (2 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_3 (3 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_4 (4 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_5 (5 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_6 (6 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_7 (7 << 20)
+-#define ARBITRATION_CTRL_ZVPORT_OFF (0 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_1 (1 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_2 (2 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_3 (3 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_4 (4 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_5 (5 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_6 (6 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_7 (7 << 16)
+-#define ARBITRATION_CTRL_CMD_INTPR_OFF (0 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_1 (1 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_2 (2 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_3 (3 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_4 (4 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_5 (5 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_6 (6 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_7 (7 << 12)
+-#define ARBITRATION_CTRL_DMA_OFF (0 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_1 (1 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_2 (2 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_3 (3 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_4 (4 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_5 (5 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_6 (6 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_7 (7 << 8)
+-#define ARBITRATION_CTRL_VIDEO_OFF (0 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_1 (1 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_2 (2 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_3 (3 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_4 (4 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_5 (5 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_6 (6 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_7 (7 << 4)
+-#define ARBITRATION_CTRL_CRT_OFF (0 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_1 (1 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_2 (2 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_3 (3 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_4 (4 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_5 (5 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_6 (6 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_7 (7 << 0)
+-
+-/* ----- Command list status register -------------------------- */
+-#define CMD_INTPR_STATUS (0x000024 + VOYAGER_BASE)
+-
+-/* ----- Interrupt status register ----------------------------- */
+-#define INT_STATUS (0x00002c + VOYAGER_BASE)
+-#define INT_STATUS_UH (1 << 6)
+-#define INT_STATUS_MC (1 << 10)
+-#define INT_STATUS_U0 (1 << 12)
+-#define INT_STATUS_U1 (1 << 13)
+-#define INT_STATUS_AC (1 << 17)
+-
+-/* ----- Interrupt mask register ------------------------------ */
+-#define VOYAGER_INT_MASK (0x000030 + VOYAGER_BASE)
+-#define VOYAGER_INT_MASK_AC (1 << 17)
+-
+-/* ----- Current Gate register ---------------------------------*/
+-#define CURRENT_GATE (0x000038 + VOYAGER_BASE)
+-
+-/* ----- Power mode 0 gate register --------------------------- */
+-#define POWER_MODE0_GATE (0x000040 + VOYAGER_BASE)
+-#define POWER_MODE0_GATE_G (1 << 6)
+-#define POWER_MODE0_GATE_U0 (1 << 7)
+-#define POWER_MODE0_GATE_U1 (1 << 8)
+-#define POWER_MODE0_GATE_UH (1 << 11)
+-#define POWER_MODE0_GATE_AC (1 << 18)
+-
+-/* ----- Power mode 1 gate register --------------------------- */
+-#define POWER_MODE1_GATE (0x000048 + VOYAGER_BASE)
+-#define POWER_MODE1_GATE_G (1 << 6)
+-#define POWER_MODE1_GATE_U0 (1 << 7)
+-#define POWER_MODE1_GATE_U1 (1 << 8)
+-#define POWER_MODE1_GATE_UH (1 << 11)
+-#define POWER_MODE1_GATE_AC (1 << 18)
+-
+-/* ----- Power mode 0 clock register -------------------------- */
+-#define POWER_MODE0_CLOCK (0x000044 + VOYAGER_BASE)
+-
+-/* ----- Power mode 1 clock register -------------------------- */
+-#define POWER_MODE1_CLOCK (0x00004C + VOYAGER_BASE)
+-
+-/* ----- Power mode controll register ------------------------- */
+-#define POWER_MODE_CTRL (0x000054 + VOYAGER_BASE)
+-
+-/* ----- Miscellaneous Timing register ------------------------ */
+-#define SYSTEM_DRAM_CTRL (0x000068 + VOYAGER_BASE)
+-
+-/* ----- PWM register ------------------------------------------*/
+-#define PWM_0 (0x010020 + VOYAGER_BASE)
+-#define PWM_0_HC(x) (((x)&0x0fff)<<20)
+-#define PWM_0_LC(x) (((x)&0x0fff)<<8 )
+-#define PWM_0_CLK_DEV(x) (((x)&0x000f)<<4 )
+-#define PWM_0_EN (1<<0)
+-
+-/* ----- I2C register ----------------------------------------- */
+-#define I2C_BYTECOUNT (0x010040 + VOYAGER_BASE)
+-#define I2C_CONTROL (0x010041 + VOYAGER_BASE)
+-#define I2C_STATUS (0x010042 + VOYAGER_BASE)
+-#define I2C_RESET (0x010042 + VOYAGER_BASE)
+-#define I2C_SADDRESS (0x010043 + VOYAGER_BASE)
+-#define I2C_DATA (0x010044 + VOYAGER_BASE)
+-
+-/* ----- Controle register bits ----------------------------------------- */
+-#define I2C_CONTROL_E (1 << 0)
+-#define I2C_CONTROL_MODE (1 << 1)
+-#define I2C_CONTROL_STATUS (1 << 2)
+-#define I2C_CONTROL_INT (1 << 4)
+-#define I2C_CONTROL_INTACK (1 << 5)
+-#define I2C_CONTROL_REPEAT (1 << 6)
+-
+-/* ----- Status register bits ----------------------------------------- */
+-#define I2C_STATUS_BUSY (1 << 0)
+-#define I2C_STATUS_ACK (1 << 1)
+-#define I2C_STATUS_ERROR (1 << 2)
+-#define I2C_STATUS_COMPLETE (1 << 3)
+-
+-/* ----- Reset register ---------------------------------------------- */
+-#define I2C_RESET_ERROR (1 << 2)
+-
+-/* ----- transmission frequencies ------------------------------------- */
+-#define I2C_SADDRESS_SELECT (1 << 0)
+-
+-/* ----- Display Controll register ----------------------------------------- */
+-#define PANEL_DISPLAY_CTRL (0x080000 + VOYAGER_BASE)
+-#define PANEL_DISPLAY_CTRL_BIAS (1<<26)
+-#define PANEL_PAN_CTRL (0x080004 + VOYAGER_BASE)
+-#define PANEL_COLOR_KEY (0x080008 + VOYAGER_BASE)
+-#define PANEL_FB_ADDRESS (0x08000C + VOYAGER_BASE)
+-#define PANEL_FB_WIDTH (0x080010 + VOYAGER_BASE)
+-#define PANEL_WINDOW_WIDTH (0x080014 + VOYAGER_BASE)
+-#define PANEL_WINDOW_HEIGHT (0x080018 + VOYAGER_BASE)
+-#define PANEL_PLANE_TL (0x08001C + VOYAGER_BASE)
+-#define PANEL_PLANE_BR (0x080020 + VOYAGER_BASE)
+-#define PANEL_HORIZONTAL_TOTAL (0x080024 + VOYAGER_BASE)
+-#define PANEL_HORIZONTAL_SYNC (0x080028 + VOYAGER_BASE)
+-#define PANEL_VERTICAL_TOTAL (0x08002C + VOYAGER_BASE)
+-#define PANEL_VERTICAL_SYNC (0x080030 + VOYAGER_BASE)
+-#define PANEL_CURRENT_LINE (0x080034 + VOYAGER_BASE)
+-#define VIDEO_DISPLAY_CTRL (0x080040 + VOYAGER_BASE)
+-#define VIDEO_FB_0_ADDRESS (0x080044 + VOYAGER_BASE)
+-#define VIDEO_FB_WIDTH (0x080048 + VOYAGER_BASE)
+-#define VIDEO_FB_0_LAST_ADDRESS (0x08004C + VOYAGER_BASE)
+-#define VIDEO_PLANE_TL (0x080050 + VOYAGER_BASE)
+-#define VIDEO_PLANE_BR (0x080054 + VOYAGER_BASE)
+-#define VIDEO_SCALE (0x080058 + VOYAGER_BASE)
+-#define VIDEO_INITIAL_SCALE (0x08005C + VOYAGER_BASE)
+-#define VIDEO_YUV_CONSTANTS (0x080060 + VOYAGER_BASE)
+-#define VIDEO_FB_1_ADDRESS (0x080064 + VOYAGER_BASE)
+-#define VIDEO_FB_1_LAST_ADDRESS (0x080068 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_DISPLAY_CTRL (0x080080 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_FB_ADDRESS (0x080084 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_FB_WIDTH (0x080088 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_FB_LAST_ADDRESS (0x08008C + VOYAGER_BASE)
+-#define VIDEO_ALPHA_PLANE_TL (0x080090 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_PLANE_BR (0x080094 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_SCALE (0x080098 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_INITIAL_SCALE (0x08009C + VOYAGER_BASE)
+-#define VIDEO_ALPHA_CHROMA_KEY (0x0800A0 + VOYAGER_BASE)
+-#define PANEL_HWC_ADDRESS (0x0800F0 + VOYAGER_BASE)
+-#define PANEL_HWC_LOCATION (0x0800F4 + VOYAGER_BASE)
+-#define PANEL_HWC_COLOR_12 (0x0800F8 + VOYAGER_BASE)
+-#define PANEL_HWC_COLOR_3 (0x0800FC + VOYAGER_BASE)
+-#define ALPHA_DISPLAY_CTRL (0x080100 + VOYAGER_BASE)
+-#define ALPHA_FB_ADDRESS (0x080104 + VOYAGER_BASE)
+-#define ALPHA_FB_WIDTH (0x080108 + VOYAGER_BASE)
+-#define ALPHA_PLANE_TL (0x08010C + VOYAGER_BASE)
+-#define ALPHA_PLANE_BR (0x080110 + VOYAGER_BASE)
+-#define ALPHA_CHROMA_KEY (0x080114 + VOYAGER_BASE)
+-#define CRT_DISPLAY_CTRL (0x080200 + VOYAGER_BASE)
+-#define CRT_FB_ADDRESS (0x080204 + VOYAGER_BASE)
+-#define CRT_FB_WIDTH (0x080208 + VOYAGER_BASE)
+-#define CRT_HORIZONTAL_TOTAL (0x08020C + VOYAGER_BASE)
+-#define CRT_HORIZONTAL_SYNC (0x080210 + VOYAGER_BASE)
+-#define CRT_VERTICAL_TOTAL (0x080214 + VOYAGER_BASE)
+-#define CRT_VERTICAL_SYNC (0x080218 + VOYAGER_BASE)
+-#define CRT_SIGNATURE_ANALYZER (0x08021C + VOYAGER_BASE)
+-#define CRT_CURRENT_LINE (0x080220 + VOYAGER_BASE)
+-#define CRT_MONITOR_DETECT (0x080224 + VOYAGER_BASE)
+-#define CRT_HWC_ADDRESS (0x080230 + VOYAGER_BASE)
+-#define CRT_HWC_LOCATION (0x080234 + VOYAGER_BASE)
+-#define CRT_HWC_COLOR_12 (0x080238 + VOYAGER_BASE)
+-#define CRT_HWC_COLOR_3 (0x08023C + VOYAGER_BASE)
+-#define CRT_PALETTE_RAM (0x080400 + VOYAGER_BASE)
+-#define PANEL_PALETTE_RAM (0x080800 + VOYAGER_BASE)
+-#define VIDEO_PALETTE_RAM (0x080C00 + VOYAGER_BASE)
+-
+-/* ----- 8051 Controle register ----------------------------------------- */
+-#define VOYAGER_8051_BASE (0x000c0000 + VOYAGER_BASE)
+-#define VOYAGER_8051_RESET (0x000b0000 + VOYAGER_BASE)
+-#define VOYAGER_8051_SELECT (0x000b0004 + VOYAGER_BASE)
+-#define VOYAGER_8051_CPU_INT (0x000b000c + VOYAGER_BASE)
+-
+-/* ----- AC97 Controle register ----------------------------------------- */
+-#define AC97_TX_SLOT0 (0x00000000 + VOYAGER_AC97_BASE)
+-#define AC97_CONTROL_STATUS (0x00000080 + VOYAGER_AC97_BASE)
+-#define AC97C_READ (1 << 19)
+-#define AC97C_WD_BIT (1 << 2)
+-#define AC97C_INDEX_MASK 0x7f
+-/* -------------------------------------------------------------------- */
+-
+-#endif /* _VOYAGER_GX_REG_H */
+diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h
+index 7b91df1..d19e7cd 100644
+--- a/include/asm-sh/scatterlist.h
++++ b/include/asm-sh/scatterlist.h
+@@ -10,4 +10,13 @@ struct scatterlist {
+
+ #define ISA_DMA_THRESHOLD (0x1fffffff)
+
++/* 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)
++
+ #endif /* !(__ASM_SH_SCATTERLIST_H) */
+diff --git a/include/asm-sh/sci.h b/include/asm-sh/sci.h
+new file mode 100644
+index 0000000..52e7366
+--- /dev/null
++++ b/include/asm-sh/sci.h
+@@ -0,0 +1,34 @@
++#ifndef __ASM_SH_SCI_H
++#define __ASM_SH_SCI_H
++
++#include <linux/serial_core.h>
++
++/*
++ * Generic header for SuperH SCI(F)
++ *
++ * Do not place SH-specific parts in here, sh64 and h8300 depend on this too.
++ */
++
++/* Offsets into the sci_port->irqs array */
++enum {
++ SCIx_ERI_IRQ,
++ SCIx_RXI_IRQ,
++ SCIx_TXI_IRQ,
++ SCIx_BRI_IRQ,
++ SCIx_NR_IRQS,
++};
++
++/*
++ * Platform device specific platform_data struct
++ */
++struct plat_sci_port {
++ void __iomem *membase; /* io cookie */
++ unsigned long mapbase; /* resource base */
++ unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */
++ unsigned int type; /* SCI / SCIF / IRDA */
++ upf_t flags; /* UPF_* flags */
++};
++
++int early_sci_setup(struct uart_port *port);
++
++#endif /* __ASM_SH_SCI_H */
+diff --git a/include/asm-sh/se.h b/include/asm-sh/se.h
+new file mode 100644
+index 0000000..a183215
+--- /dev/null
++++ b/include/asm-sh/se.h
+@@ -0,0 +1,80 @@
++#ifndef __ASM_SH_HITACHI_SE_H
++#define __ASM_SH_HITACHI_SE_H
++
++/*
++ * linux/include/asm-sh/hitachi_se.h
++ *
++ * Copyright (C) 2000 Kazumoto Kojima
++ *
++ * Hitachi SolutionEngine support
++ */
++
++/* Box specific addresses. */
++
++#define PA_ROM 0x00000000 /* EPROM */
++#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
++#define PA_FROM 0x01000000 /* EPROM */
++#define PA_FROM_SIZE 0x00400000 /* EPROM size 4M byte */
++#define PA_EXT1 0x04000000
++#define PA_EXT1_SIZE 0x04000000
++#define PA_EXT2 0x08000000
++#define PA_EXT2_SIZE 0x04000000
++#define PA_SDRAM 0x0c000000
++#define PA_SDRAM_SIZE 0x04000000
++
++#define PA_EXT4 0x12000000
++#define PA_EXT4_SIZE 0x02000000
++#define PA_EXT5 0x14000000
++#define PA_EXT5_SIZE 0x04000000
++#define PA_PCIC 0x18000000 /* MR-SHPC-01 PCMCIA */
++
++#define PA_83902 0xb0000000 /* DP83902A */
++#define PA_83902_IF 0xb0040000 /* DP83902A remote io port */
++#define PA_83902_RST 0xb0080000 /* DP83902A reset port */
++
++#define PA_SUPERIO 0xb0400000 /* SMC37C935A super io chip */
++#define PA_DIPSW0 0xb0800000 /* Dip switch 5,6 */
++#define PA_DIPSW1 0xb0800002 /* Dip switch 7,8 */
++#define PA_LED 0xb0c00000 /* LED */
++#if defined(CONFIG_CPU_SUBTYPE_SH7705)
++#define PA_BCR 0xb0e00000
++#else
++#define PA_BCR 0xb1400000 /* FPGA */
++#endif
++
++#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controller */
++#define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */
++#define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */
++#define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */
++#define MRSHPC_OPTION (PA_MRSHPC + 6)
++#define MRSHPC_CSR (PA_MRSHPC + 8)
++#define MRSHPC_ISR (PA_MRSHPC + 10)
++#define MRSHPC_ICR (PA_MRSHPC + 12)
++#define MRSHPC_CPWCR (PA_MRSHPC + 14)
++#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
++#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
++#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
++#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
++#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
++#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
++#define MRSHPC_CDCR (PA_MRSHPC + 28)
++#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
++
++#define BCR_ILCRA (PA_BCR + 0)
++#define BCR_ILCRB (PA_BCR + 2)
++#define BCR_ILCRC (PA_BCR + 4)
++#define BCR_ILCRD (PA_BCR + 6)
++#define BCR_ILCRE (PA_BCR + 8)
++#define BCR_ILCRF (PA_BCR + 10)
++#define BCR_ILCRG (PA_BCR + 12)
++
++#if defined(CONFIG_CPU_SUBTYPE_SH7705)
++#define IRQ_STNIC 12
++#else
++#define IRQ_STNIC 10
++#endif
++
++#define __IO_PREFIX se
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_HITACHI_SE_H */
+diff --git a/include/asm-sh/se/io.h b/include/asm-sh/se/io.h
+deleted file mode 100644
+index 9eeb86c..0000000
+--- a/include/asm-sh/se/io.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * include/asm-sh/io_se.h
+- *
+- * Copyright 2000 Stuart Menefy (stuart.menefy at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an Hitachi SolutionEngine
+- */
+-
+-#ifndef _ASM_SH_IO_SE_H
+-#define _ASM_SH_IO_SE_H
+-
+-extern unsigned char se_inb(unsigned long port);
+-extern unsigned short se_inw(unsigned long port);
+-extern unsigned int se_inl(unsigned long port);
+-
+-extern void se_outb(unsigned char value, unsigned long port);
+-extern void se_outw(unsigned short value, unsigned long port);
+-extern void se_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char se_inb_p(unsigned long port);
+-extern void se_outb_p(unsigned char value, unsigned long port);
+-
+-extern void se_insb(unsigned long port, void *addr, unsigned long count);
+-extern void se_insw(unsigned long port, void *addr, unsigned long count);
+-extern void se_insl(unsigned long port, void *addr, unsigned long count);
+-extern void se_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void se_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void se_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned long se_isa_port2addr(unsigned long offset);
+-
+-#endif /* _ASM_SH_IO_SE_H */
+diff --git a/include/asm-sh/se/se.h b/include/asm-sh/se/se.h
+deleted file mode 100644
+index 791c5da..0000000
+--- a/include/asm-sh/se/se.h
++++ /dev/null
+@@ -1,77 +0,0 @@
+-#ifndef __ASM_SH_HITACHI_SE_H
+-#define __ASM_SH_HITACHI_SE_H
+-
+-/*
+- * linux/include/asm-sh/hitachi_se.h
+- *
+- * Copyright (C) 2000 Kazumoto Kojima
+- *
+- * Hitachi SolutionEngine support
+- */
+-
+-/* Box specific addresses. */
+-
+-#define PA_ROM 0x00000000 /* EPROM */
+-#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
+-#define PA_FROM 0x01000000 /* EPROM */
+-#define PA_FROM_SIZE 0x00400000 /* EPROM size 4M byte */
+-#define PA_EXT1 0x04000000
+-#define PA_EXT1_SIZE 0x04000000
+-#define PA_EXT2 0x08000000
+-#define PA_EXT2_SIZE 0x04000000
+-#define PA_SDRAM 0x0c000000
+-#define PA_SDRAM_SIZE 0x04000000
+-
+-#define PA_EXT4 0x12000000
+-#define PA_EXT4_SIZE 0x02000000
+-#define PA_EXT5 0x14000000
+-#define PA_EXT5_SIZE 0x04000000
+-#define PA_PCIC 0x18000000 /* MR-SHPC-01 PCMCIA */
+-
+-#define PA_83902 0xb0000000 /* DP83902A */
+-#define PA_83902_IF 0xb0040000 /* DP83902A remote io port */
+-#define PA_83902_RST 0xb0080000 /* DP83902A reset port */
+-
+-#define PA_SUPERIO 0xb0400000 /* SMC37C935A super io chip */
+-#define PA_DIPSW0 0xb0800000 /* Dip switch 5,6 */
+-#define PA_DIPSW1 0xb0800002 /* Dip switch 7,8 */
+-#define PA_LED 0xb0c00000 /* LED */
+-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+-#define PA_BCR 0xb0e00000
+-#else
+-#define PA_BCR 0xb1400000 /* FPGA */
+-#endif
+-
+-#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controller */
+-#define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */
+-#define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */
+-#define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */
+-#define MRSHPC_OPTION (PA_MRSHPC + 6)
+-#define MRSHPC_CSR (PA_MRSHPC + 8)
+-#define MRSHPC_ISR (PA_MRSHPC + 10)
+-#define MRSHPC_ICR (PA_MRSHPC + 12)
+-#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+-#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+-#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+-#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+-#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+-#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+-#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+-#define MRSHPC_CDCR (PA_MRSHPC + 28)
+-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+-
+-#define BCR_ILCRA (PA_BCR + 0)
+-#define BCR_ILCRB (PA_BCR + 2)
+-#define BCR_ILCRC (PA_BCR + 4)
+-#define BCR_ILCRD (PA_BCR + 6)
+-#define BCR_ILCRE (PA_BCR + 8)
+-#define BCR_ILCRF (PA_BCR + 10)
+-#define BCR_ILCRG (PA_BCR + 12)
+-
+-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+-#define IRQ_STNIC 12
+-#else
+-#define IRQ_STNIC 10
+-#endif
+-
+-#endif /* __ASM_SH_HITACHI_SE_H */
+diff --git a/include/asm-sh/se/smc37c93x.h b/include/asm-sh/se/smc37c93x.h
+deleted file mode 100644
+index 585da2a..0000000
+--- a/include/asm-sh/se/smc37c93x.h
++++ /dev/null
+@@ -1,190 +0,0 @@
+-#ifndef __ASM_SH_SMC37C93X_H
+-#define __ASM_SH_SMC37C93X_H
+-
+-/*
+- * linux/include/asm-sh/smc37c93x.h
+- *
+- * Copyright (C) 2000 Kazumoto Kojima
+- *
+- * SMSC 37C93x Super IO Chip support
+- */
+-
+-/* Default base I/O address */
+-#define FDC_PRIMARY_BASE 0x3f0
+-#define IDE1_PRIMARY_BASE 0x1f0
+-#define IDE1_SECONDARY_BASE 0x170
+-#define PARPORT_PRIMARY_BASE 0x378
+-#define COM1_PRIMARY_BASE 0x2f8
+-#define COM2_PRIMARY_BASE 0x3f8
+-#define RTC_PRIMARY_BASE 0x070
+-#define KBC_PRIMARY_BASE 0x060
+-#define AUXIO_PRIMARY_BASE 0x000 /* XXX */
+-
+-/* Logical device number */
+-#define LDN_FDC 0
+-#define LDN_IDE1 1
+-#define LDN_IDE2 2
+-#define LDN_PARPORT 3
+-#define LDN_COM1 4
+-#define LDN_COM2 5
+-#define LDN_RTC 6
+-#define LDN_KBC 7
+-#define LDN_AUXIO 8
+-
+-/* Configuration port and key */
+-#define CONFIG_PORT 0x3f0
+-#define INDEX_PORT CONFIG_PORT
+-#define DATA_PORT 0x3f1
+-#define CONFIG_ENTER 0x55
+-#define CONFIG_EXIT 0xaa
+-
+-/* Configuration index */
+-#define CURRENT_LDN_INDEX 0x07
+-#define POWER_CONTROL_INDEX 0x22
+-#define ACTIVATE_INDEX 0x30
+-#define IO_BASE_HI_INDEX 0x60
+-#define IO_BASE_LO_INDEX 0x61
+-#define IRQ_SELECT_INDEX 0x70
+-#define DMA_SELECT_INDEX 0x74
+-
+-#define GPIO46_INDEX 0xc6
+-#define GPIO47_INDEX 0xc7
+-
+-/* UART stuff. Only for debugging. */
+-/* UART Register */
+-
+-#define UART_RBR 0x0 /* Receiver Buffer Register (Read Only) */
+-#define UART_THR 0x0 /* Transmitter Holding Register (Write Only) */
+-#define UART_IER 0x2 /* Interrupt Enable Register */
+-#define UART_IIR 0x4 /* Interrupt Ident Register (Read Only) */
+-#define UART_FCR 0x4 /* FIFO Control Register (Write Only) */
+-#define UART_LCR 0x6 /* Line Control Register */
+-#define UART_MCR 0x8 /* MODEM Control Register */
+-#define UART_LSR 0xa /* Line Status Register */
+-#define UART_MSR 0xc /* MODEM Status Register */
+-#define UART_SCR 0xe /* Scratch Register */
+-#define UART_DLL 0x0 /* Divisor Latch (LS) */
+-#define UART_DLM 0x2 /* Divisor Latch (MS) */
+-
+-#ifndef __ASSEMBLY__
+-typedef struct uart_reg {
+- volatile __u16 rbr;
+- volatile __u16 ier;
+- volatile __u16 iir;
+- volatile __u16 lcr;
+- volatile __u16 mcr;
+- volatile __u16 lsr;
+- volatile __u16 msr;
+- volatile __u16 scr;
+-} uart_reg;
+-#endif /* ! __ASSEMBLY__ */
+-
+-/* Alias for Write Only Register */
+-
+-#define thr rbr
+-#define tcr iir
+-
+-/* Alias for Divisor Latch Register */
+-
+-#define dll rbr
+-#define dlm ier
+-#define fcr iir
+-
+-/* Interrupt Enable Register */
+-
+-#define IER_ERDAI 0x0100 /* Enable Received Data Available Interrupt */
+-#define IER_ETHREI 0x0200 /* Enable Transmitter Holding Register Empty Interrupt */
+-#define IER_ELSI 0x0400 /* Enable Receiver Line Status Interrupt */
+-#define IER_EMSI 0x0800 /* Enable MODEM Status Interrupt */
+-
+-/* Interrupt Ident Register */
+-
+-#define IIR_IP 0x0100 /* "0" if Interrupt Pending */
+-#define IIR_IIB0 0x0200 /* Interrupt ID Bit 0 */
+-#define IIR_IIB1 0x0400 /* Interrupt ID Bit 1 */
+-#define IIR_IIB2 0x0800 /* Interrupt ID Bit 2 */
+-#define IIR_FIFO 0xc000 /* FIFOs enabled */
+-
+-/* FIFO Control Register */
+-
+-#define FCR_FEN 0x0100 /* FIFO enable */
+-#define FCR_RFRES 0x0200 /* Receiver FIFO reset */
+-#define FCR_TFRES 0x0400 /* Transmitter FIFO reset */
+-#define FCR_DMA 0x0800 /* DMA mode select */
+-#define FCR_RTL 0x4000 /* Receiver triger (LSB) */
+-#define FCR_RTM 0x8000 /* Receiver triger (MSB) */
+-
+-/* Line Control Register */
+-
+-#define LCR_WLS0 0x0100 /* Word Length Select Bit 0 */
+-#define LCR_WLS1 0x0200 /* Word Length Select Bit 1 */
+-#define LCR_STB 0x0400 /* Number of Stop Bits */
+-#define LCR_PEN 0x0800 /* Parity Enable */
+-#define LCR_EPS 0x1000 /* Even Parity Select */
+-#define LCR_SP 0x2000 /* Stick Parity */
+-#define LCR_SB 0x4000 /* Set Break */
+-#define LCR_DLAB 0x8000 /* Divisor Latch Access Bit */
+-
+-/* MODEM Control Register */
+-
+-#define MCR_DTR 0x0100 /* Data Terminal Ready */
+-#define MCR_RTS 0x0200 /* Request to Send */
+-#define MCR_OUT1 0x0400 /* Out 1 */
+-#define MCR_IRQEN 0x0800 /* IRQ Enable */
+-#define MCR_LOOP 0x1000 /* Loop */
+-
+-/* Line Status Register */
+-
+-#define LSR_DR 0x0100 /* Data Ready */
+-#define LSR_OE 0x0200 /* Overrun Error */
+-#define LSR_PE 0x0400 /* Parity Error */
+-#define LSR_FE 0x0800 /* Framing Error */
+-#define LSR_BI 0x1000 /* Break Interrupt */
+-#define LSR_THRE 0x2000 /* Transmitter Holding Register Empty */
+-#define LSR_TEMT 0x4000 /* Transmitter Empty */
+-#define LSR_FIFOE 0x8000 /* Receiver FIFO error */
+-
+-/* MODEM Status Register */
+-
+-#define MSR_DCTS 0x0100 /* Delta Clear to Send */
+-#define MSR_DDSR 0x0200 /* Delta Data Set Ready */
+-#define MSR_TERI 0x0400 /* Trailing Edge Ring Indicator */
+-#define MSR_DDCD 0x0800 /* Delta Data Carrier Detect */
+-#define MSR_CTS 0x1000 /* Clear to Send */
+-#define MSR_DSR 0x2000 /* Data Set Ready */
+-#define MSR_RI 0x4000 /* Ring Indicator */
+-#define MSR_DCD 0x8000 /* Data Carrier Detect */
+-
+-/* Baud Rate Divisor */
+-
+-#define UART_CLK (1843200) /* 1.8432 MHz */
+-#define UART_BAUD(x) (UART_CLK / (16 * (x)))
+-
+-/* RTC register definition */
+-#define RTC_SECONDS 0
+-#define RTC_SECONDS_ALARM 1
+-#define RTC_MINUTES 2
+-#define RTC_MINUTES_ALARM 3
+-#define RTC_HOURS 4
+-#define RTC_HOURS_ALARM 5
+-#define RTC_DAY_OF_WEEK 6
+-#define RTC_DAY_OF_MONTH 7
+-#define RTC_MONTH 8
+-#define RTC_YEAR 9
+-#define RTC_FREQ_SELECT 10
+-# define RTC_UIP 0x80
+-# define RTC_DIV_CTL 0x70
+-/* This RTC can work under 32.768KHz clock only. */
+-# define RTC_OSC_ENABLE 0x20
+-# define RTC_OSC_DISABLE 0x00
+-#define RTC_CONTROL 11
+-# define RTC_SET 0x80
+-# define RTC_PIE 0x40
+-# define RTC_AIE 0x20
+-# define RTC_UIE 0x10
+-# define RTC_SQWE 0x08
+-# define RTC_DM_BINARY 0x04
+-# define RTC_24H 0x02
+-# define RTC_DST_EN 0x01
+-
+-#endif /* __ASM_SH_SMC37C93X_H */
+diff --git a/include/asm-sh/se7300.h b/include/asm-sh/se7300.h
+new file mode 100644
+index 0000000..4e24edc
+--- /dev/null
++++ b/include/asm-sh/se7300.h
+@@ -0,0 +1,64 @@
++#ifndef __ASM_SH_HITACHI_SE7300_H
++#define __ASM_SH_HITACHI_SE7300_H
++
++/*
++ * linux/include/asm-sh/se/se7300.h
++ *
++ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
++ *
++ * SH-Mobile SolutionEngine 7300 support
++ */
++
++/* Box specific addresses. */
++
++/* Area 0 */
++#define PA_ROM 0x00000000 /* EPROM */
++#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte(Actually 2MB) */
++#define PA_FROM 0x00400000 /* Flash ROM */
++#define PA_FROM_SIZE 0x00400000 /* Flash size 4M byte */
++#define PA_SRAM 0x00800000 /* SRAM */
++#define PA_FROM_SIZE 0x00400000 /* SRAM size 4M byte */
++/* Area 1 */
++#define PA_EXT1 0x04000000
++#define PA_EXT1_SIZE 0x04000000
++/* Area 2 */
++#define PA_EXT2 0x08000000
++#define PA_EXT2_SIZE 0x04000000
++/* Area 3 */
++#define PA_SDRAM 0x0c000000
++#define PA_SDRAM_SIZE 0x04000000
++/* Area 4 */
++#define PA_PCIC 0x10000000 /* MR-SHPC-01 PCMCIA */
++#define PA_MRSHPC 0xb03fffe0 /* MR-SHPC-01 PCMCIA controller */
++#define PA_MRSHPC_MW1 0xb0400000 /* MR-SHPC-01 memory window base */
++#define PA_MRSHPC_MW2 0xb0500000 /* MR-SHPC-01 attribute window base */
++#define PA_MRSHPC_IO 0xb0600000 /* MR-SHPC-01 I/O window base */
++#define MRSHPC_OPTION (PA_MRSHPC + 6)
++#define MRSHPC_CSR (PA_MRSHPC + 8)
++#define MRSHPC_ISR (PA_MRSHPC + 10)
++#define MRSHPC_ICR (PA_MRSHPC + 12)
++#define MRSHPC_CPWCR (PA_MRSHPC + 14)
++#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
++#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
++#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
++#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
++#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
++#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
++#define MRSHPC_CDCR (PA_MRSHPC + 28)
++#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
++#define PA_LED 0xb0800000 /* LED */
++#define PA_DIPSW 0xb0900000 /* Dip switch 31 */
++#define PA_EPLD_MODESET 0xb0a00000 /* FPGA Mode set register */
++#define PA_EPLD_ST1 0xb0a80000 /* FPGA Interrupt status register1 */
++#define PA_EPLD_ST2 0xb0ac0000 /* FPGA Interrupt status register2 */
++/* Area 5 */
++#define PA_EXT5 0x14000000
++#define PA_EXT5_SIZE 0x04000000
++/* Area 6 */
++#define PA_LCD1 0xb8000000
++#define PA_LCD2 0xb8800000
++
++#define __IO_PREFIX sh7300se
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_HITACHI_SE7300_H */
+diff --git a/include/asm-sh/se7300/io.h b/include/asm-sh/se7300/io.h
+deleted file mode 100644
+index c6af855..0000000
+--- a/include/asm-sh/se7300/io.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * include/asm-sh/se7300/io.h
+- *
+- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
+- * IO functions for SH-Mobile(SH7300) SolutionEngine
+- */
+-
+-#ifndef _ASM_SH_IO_7300SE_H
+-#define _ASM_SH_IO_7300SE_H
+-
+-extern unsigned char sh7300se_inb(unsigned long port);
+-extern unsigned short sh7300se_inw(unsigned long port);
+-extern unsigned int sh7300se_inl(unsigned long port);
+-
+-extern void sh7300se_outb(unsigned char value, unsigned long port);
+-extern void sh7300se_outw(unsigned short value, unsigned long port);
+-extern void sh7300se_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char sh7300se_inb_p(unsigned long port);
+-extern void sh7300se_outb_p(unsigned char value, unsigned long port);
+-
+-extern void sh7300se_insb(unsigned long port, void *addr, unsigned long count);
+-extern void sh7300se_insw(unsigned long port, void *addr, unsigned long count);
+-extern void sh7300se_insl(unsigned long port, void *addr, unsigned long count);
+-extern void sh7300se_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void sh7300se_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void sh7300se_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-#endif /* _ASM_SH_IO_7300SE_H */
+diff --git a/include/asm-sh/se7300/se7300.h b/include/asm-sh/se7300/se7300.h
+deleted file mode 100644
+index 3ec1ded..0000000
+--- a/include/asm-sh/se7300/se7300.h
++++ /dev/null
+@@ -1,61 +0,0 @@
+-#ifndef __ASM_SH_HITACHI_SE7300_H
+-#define __ASM_SH_HITACHI_SE7300_H
+-
+-/*
+- * linux/include/asm-sh/se/se7300.h
+- *
+- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
+- *
+- * SH-Mobile SolutionEngine 7300 support
+- */
+-
+-/* Box specific addresses. */
+-
+-/* Area 0 */
+-#define PA_ROM 0x00000000 /* EPROM */
+-#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte(Actually 2MB) */
+-#define PA_FROM 0x00400000 /* Flash ROM */
+-#define PA_FROM_SIZE 0x00400000 /* Flash size 4M byte */
+-#define PA_SRAM 0x00800000 /* SRAM */
+-#define PA_FROM_SIZE 0x00400000 /* SRAM size 4M byte */
+-/* Area 1 */
+-#define PA_EXT1 0x04000000
+-#define PA_EXT1_SIZE 0x04000000
+-/* Area 2 */
+-#define PA_EXT2 0x08000000
+-#define PA_EXT2_SIZE 0x04000000
+-/* Area 3 */
+-#define PA_SDRAM 0x0c000000
+-#define PA_SDRAM_SIZE 0x04000000
+-/* Area 4 */
+-#define PA_PCIC 0x10000000 /* MR-SHPC-01 PCMCIA */
+-#define PA_MRSHPC 0xb03fffe0 /* MR-SHPC-01 PCMCIA controller */
+-#define PA_MRSHPC_MW1 0xb0400000 /* MR-SHPC-01 memory window base */
+-#define PA_MRSHPC_MW2 0xb0500000 /* MR-SHPC-01 attribute window base */
+-#define PA_MRSHPC_IO 0xb0600000 /* MR-SHPC-01 I/O window base */
+-#define MRSHPC_OPTION (PA_MRSHPC + 6)
+-#define MRSHPC_CSR (PA_MRSHPC + 8)
+-#define MRSHPC_ISR (PA_MRSHPC + 10)
+-#define MRSHPC_ICR (PA_MRSHPC + 12)
+-#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+-#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+-#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+-#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+-#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+-#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+-#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+-#define MRSHPC_CDCR (PA_MRSHPC + 28)
+-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+-#define PA_LED 0xb0800000 /* LED */
+-#define PA_DIPSW 0xb0900000 /* Dip switch 31 */
+-#define PA_EPLD_MODESET 0xb0a00000 /* FPGA Mode set register */
+-#define PA_EPLD_ST1 0xb0a80000 /* FPGA Interrupt status register1 */
+-#define PA_EPLD_ST2 0xb0ac0000 /* FPGA Interrupt status register2 */
+-/* Area 5 */
+-#define PA_EXT5 0x14000000
+-#define PA_EXT5_SIZE 0x04000000
+-/* Area 6 */
+-#define PA_LCD1 0xb8000000
+-#define PA_LCD2 0xb8800000
+-
+-#endif /* __ASM_SH_HITACHI_SE7300_H */
+diff --git a/include/asm-sh/se73180.h b/include/asm-sh/se73180.h
+new file mode 100644
+index 0000000..3a4acb3
+--- /dev/null
++++ b/include/asm-sh/se73180.h
+@@ -0,0 +1,65 @@
++#ifndef __ASM_SH_HITACHI_SE73180_H
++#define __ASM_SH_HITACHI_SE73180_H
++
++/*
++ * include/asm-sh/se/se73180.h
++ *
++ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
++ *
++ * SH-Mobile SolutionEngine 73180 support
++ */
++
++/* Box specific addresses. */
++
++/* Area 0 */
++#define PA_ROM 0x00000000 /* EPROM */
++#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte(Actually 2MB) */
++#define PA_FROM 0x00400000 /* Flash ROM */
++#define PA_FROM_SIZE 0x00400000 /* Flash size 4M byte */
++#define PA_SRAM 0x00800000 /* SRAM */
++#define PA_FROM_SIZE 0x00400000 /* SRAM size 4M byte */
++/* Area 1 */
++#define PA_EXT1 0x04000000
++#define PA_EXT1_SIZE 0x04000000
++/* Area 2 */
++#define PA_EXT2 0x08000000
++#define PA_EXT2_SIZE 0x04000000
++/* Area 3 */
++#define PA_SDRAM 0x0c000000
++#define PA_SDRAM_SIZE 0x04000000
++/* Area 4 */
++#define PA_PCIC 0x10000000 /* MR-SHPC-01 PCMCIA */
++#define PA_MRSHPC 0xb03fffe0 /* MR-SHPC-01 PCMCIA controller */
++#define PA_MRSHPC_MW1 0xb0400000 /* MR-SHPC-01 memory window base */
++#define PA_MRSHPC_MW2 0xb0500000 /* MR-SHPC-01 attribute window base */
++#define PA_MRSHPC_IO 0xb0600000 /* MR-SHPC-01 I/O window base */
++#define MRSHPC_OPTION (PA_MRSHPC + 6)
++#define MRSHPC_CSR (PA_MRSHPC + 8)
++#define MRSHPC_ISR (PA_MRSHPC + 10)
++#define MRSHPC_ICR (PA_MRSHPC + 12)
++#define MRSHPC_CPWCR (PA_MRSHPC + 14)
++#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
++#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
++#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
++#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
++#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
++#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
++#define MRSHPC_CDCR (PA_MRSHPC + 28)
++#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
++#define PA_LED 0xb0C00000 /* LED */
++#define LED_SHIFT 0
++#define PA_DIPSW 0xb0900000 /* Dip switch 31 */
++#define PA_EPLD_MODESET 0xb0a00000 /* FPGA Mode set register */
++#define PA_EPLD_ST1 0xb0a80000 /* FPGA Interrupt status register1 */
++#define PA_EPLD_ST2 0xb0ac0000 /* FPGA Interrupt status register2 */
++/* Area 5 */
++#define PA_EXT5 0x14000000
++#define PA_EXT5_SIZE 0x04000000
++/* Area 6 */
++#define PA_LCD1 0xb8000000
++#define PA_LCD2 0xb8800000
++
++#define __IO_PREFIX sh73180se
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_HITACHI_SE73180_H */
+diff --git a/include/asm-sh/se73180/io.h b/include/asm-sh/se73180/io.h
+deleted file mode 100644
+index c9cb1b9..0000000
+--- a/include/asm-sh/se73180/io.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/*
+- * include/asm-sh/se73180/io.h
+- *
+- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
+- * Based on include/asm-sh/se7300/io.h
+- *
+- * IO functions for SH-Mobile3(SH73180) SolutionEngine
+- *
+- */
+-
+-#ifndef _ASM_SH_IO_73180SE_H
+-#define _ASM_SH_IO_73180SE_H
+-
+-extern unsigned char sh73180se_inb(unsigned long port);
+-extern unsigned short sh73180se_inw(unsigned long port);
+-extern unsigned int sh73180se_inl(unsigned long port);
+-
+-extern void sh73180se_outb(unsigned char value, unsigned long port);
+-extern void sh73180se_outw(unsigned short value, unsigned long port);
+-extern void sh73180se_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char sh73180se_inb_p(unsigned long port);
+-extern void sh73180se_outb_p(unsigned char value, unsigned long port);
+-
+-extern void sh73180se_insb(unsigned long port, void *addr, unsigned long count);
+-extern void sh73180se_insw(unsigned long port, void *addr, unsigned long count);
+-extern void sh73180se_insl(unsigned long port, void *addr, unsigned long count);
+-extern void sh73180se_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void sh73180se_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void sh73180se_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-#endif /* _ASM_SH_IO_73180SE_H */
+diff --git a/include/asm-sh/se73180/se73180.h b/include/asm-sh/se73180/se73180.h
+deleted file mode 100644
+index f5b93e3..0000000
+--- a/include/asm-sh/se73180/se73180.h
++++ /dev/null
+@@ -1,62 +0,0 @@
+-#ifndef __ASM_SH_HITACHI_SE73180_H
+-#define __ASM_SH_HITACHI_SE73180_H
+-
+-/*
+- * include/asm-sh/se/se73180.h
+- *
+- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
+- *
+- * SH-Mobile SolutionEngine 73180 support
+- */
+-
+-/* Box specific addresses. */
+-
+-/* Area 0 */
+-#define PA_ROM 0x00000000 /* EPROM */
+-#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte(Actually 2MB) */
+-#define PA_FROM 0x00400000 /* Flash ROM */
+-#define PA_FROM_SIZE 0x00400000 /* Flash size 4M byte */
+-#define PA_SRAM 0x00800000 /* SRAM */
+-#define PA_FROM_SIZE 0x00400000 /* SRAM size 4M byte */
+-/* Area 1 */
+-#define PA_EXT1 0x04000000
+-#define PA_EXT1_SIZE 0x04000000
+-/* Area 2 */
+-#define PA_EXT2 0x08000000
+-#define PA_EXT2_SIZE 0x04000000
+-/* Area 3 */
+-#define PA_SDRAM 0x0c000000
+-#define PA_SDRAM_SIZE 0x04000000
+-/* Area 4 */
+-#define PA_PCIC 0x10000000 /* MR-SHPC-01 PCMCIA */
+-#define PA_MRSHPC 0xb03fffe0 /* MR-SHPC-01 PCMCIA controller */
+-#define PA_MRSHPC_MW1 0xb0400000 /* MR-SHPC-01 memory window base */
+-#define PA_MRSHPC_MW2 0xb0500000 /* MR-SHPC-01 attribute window base */
+-#define PA_MRSHPC_IO 0xb0600000 /* MR-SHPC-01 I/O window base */
+-#define MRSHPC_OPTION (PA_MRSHPC + 6)
+-#define MRSHPC_CSR (PA_MRSHPC + 8)
+-#define MRSHPC_ISR (PA_MRSHPC + 10)
+-#define MRSHPC_ICR (PA_MRSHPC + 12)
+-#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+-#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+-#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+-#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+-#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+-#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+-#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+-#define MRSHPC_CDCR (PA_MRSHPC + 28)
+-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+-#define PA_LED 0xb0C00000 /* LED */
+-#define LED_SHIFT 0
+-#define PA_DIPSW 0xb0900000 /* Dip switch 31 */
+-#define PA_EPLD_MODESET 0xb0a00000 /* FPGA Mode set register */
+-#define PA_EPLD_ST1 0xb0a80000 /* FPGA Interrupt status register1 */
+-#define PA_EPLD_ST2 0xb0ac0000 /* FPGA Interrupt status register2 */
+-/* Area 5 */
+-#define PA_EXT5 0x14000000
+-#define PA_EXT5_SIZE 0x04000000
+-/* Area 6 */
+-#define PA_LCD1 0xb8000000
+-#define PA_LCD2 0xb8800000
+-
+-#endif /* __ASM_SH_HITACHI_SE73180_H */
+diff --git a/include/asm-sh/se7343.h b/include/asm-sh/se7343.h
+new file mode 100644
+index 0000000..e7914a5
+--- /dev/null
++++ b/include/asm-sh/se7343.h
+@@ -0,0 +1,82 @@
++#ifndef __ASM_SH_HITACHI_SE7343_H
++#define __ASM_SH_HITACHI_SE7343_H
++
++/*
++ * include/asm-sh/se/se7343.h
++ *
++ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi at hitachi-ul.co.jp>
++ *
++ * SH-Mobile SolutionEngine 7343 support
++ */
++
++/* Box specific addresses. */
++
++/* Area 0 */
++#define PA_ROM 0x00000000 /* EPROM */
++#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte(Actually 2MB) */
++#define PA_FROM 0x00400000 /* Flash ROM */
++#define PA_FROM_SIZE 0x00400000 /* Flash size 4M byte */
++#define PA_SRAM 0x00800000 /* SRAM */
++#define PA_FROM_SIZE 0x00400000 /* SRAM size 4M byte */
++/* Area 1 */
++#define PA_EXT1 0x04000000
++#define PA_EXT1_SIZE 0x04000000
++/* Area 2 */
++#define PA_EXT2 0x08000000
++#define PA_EXT2_SIZE 0x04000000
++/* Area 3 */
++#define PA_SDRAM 0x0c000000
++#define PA_SDRAM_SIZE 0x04000000
++/* Area 4 */
++#define PA_PCIC 0x10000000 /* MR-SHPC-01 PCMCIA */
++#define PA_MRSHPC 0xb03fffe0 /* MR-SHPC-01 PCMCIA controller */
++#define PA_MRSHPC_MW1 0xb0400000 /* MR-SHPC-01 memory window base */
++#define PA_MRSHPC_MW2 0xb0500000 /* MR-SHPC-01 attribute window base */
++#define PA_MRSHPC_IO 0xb0600000 /* MR-SHPC-01 I/O window base */
++#define MRSHPC_OPTION (PA_MRSHPC + 6)
++#define MRSHPC_CSR (PA_MRSHPC + 8)
++#define MRSHPC_ISR (PA_MRSHPC + 10)
++#define MRSHPC_ICR (PA_MRSHPC + 12)
++#define MRSHPC_CPWCR (PA_MRSHPC + 14)
++#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
++#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
++#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
++#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
++#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
++#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
++#define MRSHPC_CDCR (PA_MRSHPC + 28)
++#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
++#define PA_LED 0xb0C00000 /* LED */
++#define LED_SHIFT 0
++#define PA_DIPSW 0xb0900000 /* Dip switch 31 */
++#define PA_CPLD_MODESET 0xb1400004 /* CPLD Mode set register */
++#define PA_CPLD_ST 0xb1400008 /* CPLD Interrupt status register */
++#define PA_CPLD_IMSK 0xb140000a /* CPLD Interrupt mask register */
++/* Area 5 */
++#define PA_EXT5 0x14000000
++#define PA_EXT5_SIZE 0x04000000
++/* Area 6 */
++#define PA_LCD1 0xb8000000
++#define PA_LCD2 0xb8800000
++
++#define __IO_PREFIX sh7343se
++#include <asm/io_generic.h>
++
++/* External Multiplexed interrupts */
++#define PC_IRQ0 OFFCHIP_IRQ_BASE
++#define PC_IRQ1 (PC_IRQ0 + 1)
++#define PC_IRQ2 (PC_IRQ1 + 1)
++#define PC_IRQ3 (PC_IRQ2 + 1)
++
++#define EXT_IRQ0 (PC_IRQ3 + 1)
++#define EXT_IRQ1 (EXT_IRQ0 + 1)
++#define EXT_IRQ2 (EXT_IRQ1 + 1)
++#define EXT_IRQ3 (EXT_IRQ2 + 1)
++
++#define USB_IRQ0 (EXT_IRQ3 + 1)
++#define USB_IRQ1 (USB_IRQ0 + 1)
++
++#define UART_IRQ0 (USB_IRQ1 + 1)
++#define UART_IRQ1 (UART_IRQ0 + 1)
++
++#endif /* __ASM_SH_HITACHI_SE7343_H */
+diff --git a/include/asm-sh/se7751.h b/include/asm-sh/se7751.h
+new file mode 100644
+index 0000000..88cd379
+--- /dev/null
++++ b/include/asm-sh/se7751.h
+@@ -0,0 +1,71 @@
++#ifndef __ASM_SH_HITACHI_7751SE_H
++#define __ASM_SH_HITACHI_7751SE_H
++
++/*
++ * linux/include/asm-sh/hitachi_7751se.h
++ *
++ * Copyright (C) 2000 Kazumoto Kojima
++ *
++ * Hitachi SolutionEngine support
++
++ * Modified for 7751 Solution Engine by
++ * Ian da Silva and Jeremy Siegel, 2001.
++ */
++
++/* Box specific addresses. */
++
++#define PA_ROM 0x00000000 /* EPROM */
++#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
++#define PA_FROM 0x01000000 /* EPROM */
++#define PA_FROM_SIZE 0x00400000 /* EPROM size 4M byte */
++#define PA_EXT1 0x04000000
++#define PA_EXT1_SIZE 0x04000000
++#define PA_EXT2 0x08000000
++#define PA_EXT2_SIZE 0x04000000
++#define PA_SDRAM 0x0c000000
++#define PA_SDRAM_SIZE 0x04000000
++
++#define PA_EXT4 0x12000000
++#define PA_EXT4_SIZE 0x02000000
++#define PA_EXT5 0x14000000
++#define PA_EXT5_SIZE 0x04000000
++#define PA_PCIC 0x18000000 /* MR-SHPC-01 PCMCIA */
++
++#define PA_DIPSW0 0xb9000000 /* Dip switch 5,6 */
++#define PA_DIPSW1 0xb9000002 /* Dip switch 7,8 */
++#define PA_LED 0xba000000 /* LED */
++#define PA_BCR 0xbb000000 /* FPGA on the MS7751SE01 */
++
++#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controler */
++#define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */
++#define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */
++#define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */
++#define MRSHPC_MODE (PA_MRSHPC + 4)
++#define MRSHPC_OPTION (PA_MRSHPC + 6)
++#define MRSHPC_CSR (PA_MRSHPC + 8)
++#define MRSHPC_ISR (PA_MRSHPC + 10)
++#define MRSHPC_ICR (PA_MRSHPC + 12)
++#define MRSHPC_CPWCR (PA_MRSHPC + 14)
++#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
++#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
++#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
++#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
++#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
++#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
++#define MRSHPC_CDCR (PA_MRSHPC + 28)
++#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
++
++#define BCR_ILCRA (PA_BCR + 0)
++#define BCR_ILCRB (PA_BCR + 2)
++#define BCR_ILCRC (PA_BCR + 4)
++#define BCR_ILCRD (PA_BCR + 6)
++#define BCR_ILCRE (PA_BCR + 8)
++#define BCR_ILCRF (PA_BCR + 10)
++#define BCR_ILCRG (PA_BCR + 12)
++
++#define IRQ_79C973 13
++
++#define __IO_PREFIX sh7751se
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_HITACHI_7751SE_H */
+diff --git a/include/asm-sh/se7751/io.h b/include/asm-sh/se7751/io.h
+deleted file mode 100644
+index 78d8f57..0000000
+--- a/include/asm-sh/se7751/io.h
++++ /dev/null
+@@ -1,42 +0,0 @@
+-/*
+- * include/asm-sh/io_7751se.h
+- *
+- * Modified version of io_se.h for the 7751se-specific functions.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for an Hitachi SolutionEngine
+- */
+-
+-#ifndef _ASM_SH_IO_7751SE_H
+-#define _ASM_SH_IO_7751SE_H
+-
+-extern unsigned char sh7751se_inb(unsigned long port);
+-extern unsigned short sh7751se_inw(unsigned long port);
+-extern unsigned int sh7751se_inl(unsigned long port);
+-
+-extern void sh7751se_outb(unsigned char value, unsigned long port);
+-extern void sh7751se_outw(unsigned short value, unsigned long port);
+-extern void sh7751se_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char sh7751se_inb_p(unsigned long port);
+-extern void sh7751se_outb_p(unsigned char value, unsigned long port);
+-
+-extern void sh7751se_insb(unsigned long port, void *addr, unsigned long count);
+-extern void sh7751se_insw(unsigned long port, void *addr, unsigned long count);
+-extern void sh7751se_insl(unsigned long port, void *addr, unsigned long count);
+-extern void sh7751se_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void sh7751se_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned char sh7751se_readb(unsigned long addr);
+-extern unsigned short sh7751se_readw(unsigned long addr);
+-extern unsigned int sh7751se_readl(unsigned long addr);
+-extern void sh7751se_writeb(unsigned char b, unsigned long addr);
+-extern void sh7751se_writew(unsigned short b, unsigned long addr);
+-extern void sh7751se_writel(unsigned int b, unsigned long addr);
+-
+-extern unsigned long sh7751se_isa_port2addr(unsigned long offset);
+-
+-#endif /* _ASM_SH_IO_7751SE_H */
+diff --git a/include/asm-sh/se7751/se7751.h b/include/asm-sh/se7751/se7751.h
+deleted file mode 100644
+index 738e22b..0000000
+--- a/include/asm-sh/se7751/se7751.h
++++ /dev/null
+@@ -1,68 +0,0 @@
+-#ifndef __ASM_SH_HITACHI_7751SE_H
+-#define __ASM_SH_HITACHI_7751SE_H
+-
+-/*
+- * linux/include/asm-sh/hitachi_7751se.h
+- *
+- * Copyright (C) 2000 Kazumoto Kojima
+- *
+- * Hitachi SolutionEngine support
+-
+- * Modified for 7751 Solution Engine by
+- * Ian da Silva and Jeremy Siegel, 2001.
+- */
+-
+-/* Box specific addresses. */
+-
+-#define PA_ROM 0x00000000 /* EPROM */
+-#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
+-#define PA_FROM 0x01000000 /* EPROM */
+-#define PA_FROM_SIZE 0x00400000 /* EPROM size 4M byte */
+-#define PA_EXT1 0x04000000
+-#define PA_EXT1_SIZE 0x04000000
+-#define PA_EXT2 0x08000000
+-#define PA_EXT2_SIZE 0x04000000
+-#define PA_SDRAM 0x0c000000
+-#define PA_SDRAM_SIZE 0x04000000
+-
+-#define PA_EXT4 0x12000000
+-#define PA_EXT4_SIZE 0x02000000
+-#define PA_EXT5 0x14000000
+-#define PA_EXT5_SIZE 0x04000000
+-#define PA_PCIC 0x18000000 /* MR-SHPC-01 PCMCIA */
+-
+-#define PA_DIPSW0 0xb9000000 /* Dip switch 5,6 */
+-#define PA_DIPSW1 0xb9000002 /* Dip switch 7,8 */
+-#define PA_LED 0xba000000 /* LED */
+-#define PA_BCR 0xbb000000 /* FPGA on the MS7751SE01 */
+-
+-#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controler */
+-#define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */
+-#define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */
+-#define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */
+-#define MRSHPC_MODE (PA_MRSHPC + 4)
+-#define MRSHPC_OPTION (PA_MRSHPC + 6)
+-#define MRSHPC_CSR (PA_MRSHPC + 8)
+-#define MRSHPC_ISR (PA_MRSHPC + 10)
+-#define MRSHPC_ICR (PA_MRSHPC + 12)
+-#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+-#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+-#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+-#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+-#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+-#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+-#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+-#define MRSHPC_CDCR (PA_MRSHPC + 28)
+-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+-
+-#define BCR_ILCRA (PA_BCR + 0)
+-#define BCR_ILCRB (PA_BCR + 2)
+-#define BCR_ILCRC (PA_BCR + 4)
+-#define BCR_ILCRD (PA_BCR + 6)
+-#define BCR_ILCRE (PA_BCR + 8)
+-#define BCR_ILCRF (PA_BCR + 10)
+-#define BCR_ILCRG (PA_BCR + 12)
+-
+-#define IRQ_79C973 13
+-
+-#endif /* __ASM_SH_HITACHI_7751SE_H */
+diff --git a/include/asm-sh/setup.h b/include/asm-sh/setup.h
+index d19de7c..34ca8a7 100644
+--- a/include/asm-sh/setup.h
++++ b/include/asm-sh/setup.h
+@@ -4,5 +4,7 @@
+
+ #define COMMAND_LINE_SIZE 256
+
++int setup_early_printk(char *);
++
+ #endif /* _SH_SETUP_H */
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-sh/sfp-machine.h b/include/asm-sh/sfp-machine.h
+new file mode 100644
+index 0000000..d3c5484
+--- /dev/null
++++ b/include/asm-sh/sfp-machine.h
+@@ -0,0 +1,84 @@
++/* Machine-dependent software floating-point definitions.
++ SuperH kernel version.
++ Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Richard Henderson (rth at cygnus.com),
++ Jakub Jelinek (jj at ultra.linux.cz),
++ David S. Miller (davem at redhat.com) and
++ Peter Maydell (pmaydell at chiark.greenend.org.uk).
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The GNU C Library 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
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the GNU C Library; see the file COPYING.LIB. If
++ not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++#ifndef _SFP_MACHINE_H
++#define _SFP_MACHINE_H
++
++#define _FP_W_TYPE_SIZE 32
++#define _FP_W_TYPE unsigned long
++#define _FP_WS_TYPE signed long
++#define _FP_I_TYPE long
++
++#define _FP_MUL_MEAT_S(R,X,Y) \
++ _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
++#define _FP_MUL_MEAT_D(R,X,Y) \
++ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
++#define _FP_MUL_MEAT_Q(R,X,Y) \
++ _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
++
++#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
++#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
++#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
++
++#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
++#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
++#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
++#define _FP_NANSIGN_S 0
++#define _FP_NANSIGN_D 0
++#define _FP_NANSIGN_Q 0
++
++#define _FP_KEEPNANFRACP 1
++
++/*
++ * If one NaN is signaling and the other is not,
++ * we choose that one, otherwise we choose X.
++ */
++#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
++ do { \
++ if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \
++ && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \
++ { \
++ R##_s = Y##_s; \
++ _FP_FRAC_COPY_##wc(R,Y); \
++ } \
++ else \
++ { \
++ R##_s = X##_s; \
++ _FP_FRAC_COPY_##wc(R,X); \
++ } \
++ R##_c = FP_CLS_NAN; \
++ } while (0)
++
++//#define FP_ROUNDMODE FPSCR_RM
++#define FP_DENORM_ZERO 1/*FPSCR_DN*/
++
++/* Exception flags. */
++#define FP_EX_INVALID (1<<4)
++#define FP_EX_DIVZERO (1<<3)
++#define FP_EX_OVERFLOW (1<<2)
++#define FP_EX_UNDERFLOW (1<<1)
++#define FP_EX_INEXACT (1<<0)
++
++#endif
++
+diff --git a/include/asm-sh/sh03/ide.h b/include/asm-sh/sh03/ide.h
+deleted file mode 100644
+index 73ee92e..0000000
+--- a/include/asm-sh/sh03/ide.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef __ASM_SH_SH03_IDE_H
+-#define __ASM_SH_SH03_IDE_H
+-
+-#define IRQ_CFCARD 8
+-#define IRQ_PCMCIA 8
+-
+-#endif /* __ASM_SH_SH03_IDE_H */
+diff --git a/include/asm-sh/sh03/io.h b/include/asm-sh/sh03/io.h
+index 25792e9..df3b187 100644
+--- a/include/asm-sh/sh03/io.h
++++ b/include/asm-sh/sh03/io.h
+@@ -33,14 +33,6 @@
+ #define IRL3_IPR_POS 0
+ #define IRL3_PRIORITY 4
+
+-
+-extern unsigned long sh03_isa_port2addr(unsigned long offset);
+-
+-extern void setup_sh03(void);
+-extern void init_sh03_IRQ(void);
+-extern void heartbeat_sh03(void);
+-
+-extern void sh03_rtc_gettimeofday(struct timeval *tv);
+-extern int sh03_rtc_settimeofday(const struct timeval *tv);
++void heartbeat_sh03(void);
+
+ #endif /* _ASM_SH_IO_SH03_H */
+diff --git a/include/asm-sh/sh2000/sh2000.h b/include/asm-sh/sh2000/sh2000.h
+deleted file mode 100644
+index 8d54732..0000000
+--- a/include/asm-sh/sh2000/sh2000.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef __ASM_SH_SH2000_SH2000_H
+-#define __ASM_SH_SH2000_SH2000_H
+-
+-/* arch/sh/boards/sh2000/setup.c */
+-extern int setup_sh2000(void);
+-
+-#endif /* __ASM_SH_SH2000_SH2000_H */
+-
+diff --git a/include/asm-sh/shmin.h b/include/asm-sh/shmin.h
+new file mode 100644
+index 0000000..36ba138
+--- /dev/null
++++ b/include/asm-sh/shmin.h
+@@ -0,0 +1,9 @@
++#ifndef __ASM_SH_SHMIN_H
++#define __ASM_SH_SHMIN_H
++
++#define SHMIN_IO_BASE 0xb0000000UL
++
++#define SHMIN_NE_IRQ IRQ2_IRQ
++#define SHMIN_NE_BASE 0x300
++
++#endif
+diff --git a/include/asm-sh/shmparam.h b/include/asm-sh/shmparam.h
+index 0a95604..ba1758d 100644
+--- a/include/asm-sh/shmparam.h
++++ b/include/asm-sh/shmparam.h
+@@ -1,8 +1,22 @@
++/*
++ * include/asm-sh/shmparam.h
++ *
++ * Copyright (C) 1999 Niibe Yutaka
++ * Copyright (C) 2006 Paul Mundt
++ *
++ * 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 __ASM_SH_SHMPARAM_H
+ #define __ASM_SH_SHMPARAM_H
+-#ifdef __KERNEL__
+
+-#include <asm/cpu/shmparam.h>
++/*
++ * SH-4 and SH-3 7705 have an aliasing dcache. Bump this up to a sensible value
++ * for everyone, and work out the specifics from the probed cache descriptor.
++ */
++#define SHMLBA 0x4000 /* attach addr a multiple of this */
++
++#define __ARCH_FORCE_SHMLBA
+
+-#endif /* __KERNEL__ */
+ #endif /* __ASM_SH_SHMPARAM_H */
+diff --git a/include/asm-sh/smc37c93x.h b/include/asm-sh/smc37c93x.h
+new file mode 100644
+index 0000000..585da2a
+--- /dev/null
++++ b/include/asm-sh/smc37c93x.h
+@@ -0,0 +1,190 @@
++#ifndef __ASM_SH_SMC37C93X_H
++#define __ASM_SH_SMC37C93X_H
++
++/*
++ * linux/include/asm-sh/smc37c93x.h
++ *
++ * Copyright (C) 2000 Kazumoto Kojima
++ *
++ * SMSC 37C93x Super IO Chip support
++ */
++
++/* Default base I/O address */
++#define FDC_PRIMARY_BASE 0x3f0
++#define IDE1_PRIMARY_BASE 0x1f0
++#define IDE1_SECONDARY_BASE 0x170
++#define PARPORT_PRIMARY_BASE 0x378
++#define COM1_PRIMARY_BASE 0x2f8
++#define COM2_PRIMARY_BASE 0x3f8
++#define RTC_PRIMARY_BASE 0x070
++#define KBC_PRIMARY_BASE 0x060
++#define AUXIO_PRIMARY_BASE 0x000 /* XXX */
++
++/* Logical device number */
++#define LDN_FDC 0
++#define LDN_IDE1 1
++#define LDN_IDE2 2
++#define LDN_PARPORT 3
++#define LDN_COM1 4
++#define LDN_COM2 5
++#define LDN_RTC 6
++#define LDN_KBC 7
++#define LDN_AUXIO 8
++
++/* Configuration port and key */
++#define CONFIG_PORT 0x3f0
++#define INDEX_PORT CONFIG_PORT
++#define DATA_PORT 0x3f1
++#define CONFIG_ENTER 0x55
++#define CONFIG_EXIT 0xaa
++
++/* Configuration index */
++#define CURRENT_LDN_INDEX 0x07
++#define POWER_CONTROL_INDEX 0x22
++#define ACTIVATE_INDEX 0x30
++#define IO_BASE_HI_INDEX 0x60
++#define IO_BASE_LO_INDEX 0x61
++#define IRQ_SELECT_INDEX 0x70
++#define DMA_SELECT_INDEX 0x74
++
++#define GPIO46_INDEX 0xc6
++#define GPIO47_INDEX 0xc7
++
++/* UART stuff. Only for debugging. */
++/* UART Register */
++
++#define UART_RBR 0x0 /* Receiver Buffer Register (Read Only) */
++#define UART_THR 0x0 /* Transmitter Holding Register (Write Only) */
++#define UART_IER 0x2 /* Interrupt Enable Register */
++#define UART_IIR 0x4 /* Interrupt Ident Register (Read Only) */
++#define UART_FCR 0x4 /* FIFO Control Register (Write Only) */
++#define UART_LCR 0x6 /* Line Control Register */
++#define UART_MCR 0x8 /* MODEM Control Register */
++#define UART_LSR 0xa /* Line Status Register */
++#define UART_MSR 0xc /* MODEM Status Register */
++#define UART_SCR 0xe /* Scratch Register */
++#define UART_DLL 0x0 /* Divisor Latch (LS) */
++#define UART_DLM 0x2 /* Divisor Latch (MS) */
++
++#ifndef __ASSEMBLY__
++typedef struct uart_reg {
++ volatile __u16 rbr;
++ volatile __u16 ier;
++ volatile __u16 iir;
++ volatile __u16 lcr;
++ volatile __u16 mcr;
++ volatile __u16 lsr;
++ volatile __u16 msr;
++ volatile __u16 scr;
++} uart_reg;
++#endif /* ! __ASSEMBLY__ */
++
++/* Alias for Write Only Register */
++
++#define thr rbr
++#define tcr iir
++
++/* Alias for Divisor Latch Register */
++
++#define dll rbr
++#define dlm ier
++#define fcr iir
++
++/* Interrupt Enable Register */
++
++#define IER_ERDAI 0x0100 /* Enable Received Data Available Interrupt */
++#define IER_ETHREI 0x0200 /* Enable Transmitter Holding Register Empty Interrupt */
++#define IER_ELSI 0x0400 /* Enable Receiver Line Status Interrupt */
++#define IER_EMSI 0x0800 /* Enable MODEM Status Interrupt */
++
++/* Interrupt Ident Register */
++
++#define IIR_IP 0x0100 /* "0" if Interrupt Pending */
++#define IIR_IIB0 0x0200 /* Interrupt ID Bit 0 */
++#define IIR_IIB1 0x0400 /* Interrupt ID Bit 1 */
++#define IIR_IIB2 0x0800 /* Interrupt ID Bit 2 */
++#define IIR_FIFO 0xc000 /* FIFOs enabled */
++
++/* FIFO Control Register */
++
++#define FCR_FEN 0x0100 /* FIFO enable */
++#define FCR_RFRES 0x0200 /* Receiver FIFO reset */
++#define FCR_TFRES 0x0400 /* Transmitter FIFO reset */
++#define FCR_DMA 0x0800 /* DMA mode select */
++#define FCR_RTL 0x4000 /* Receiver triger (LSB) */
++#define FCR_RTM 0x8000 /* Receiver triger (MSB) */
++
++/* Line Control Register */
++
++#define LCR_WLS0 0x0100 /* Word Length Select Bit 0 */
++#define LCR_WLS1 0x0200 /* Word Length Select Bit 1 */
++#define LCR_STB 0x0400 /* Number of Stop Bits */
++#define LCR_PEN 0x0800 /* Parity Enable */
++#define LCR_EPS 0x1000 /* Even Parity Select */
++#define LCR_SP 0x2000 /* Stick Parity */
++#define LCR_SB 0x4000 /* Set Break */
++#define LCR_DLAB 0x8000 /* Divisor Latch Access Bit */
++
++/* MODEM Control Register */
++
++#define MCR_DTR 0x0100 /* Data Terminal Ready */
++#define MCR_RTS 0x0200 /* Request to Send */
++#define MCR_OUT1 0x0400 /* Out 1 */
++#define MCR_IRQEN 0x0800 /* IRQ Enable */
++#define MCR_LOOP 0x1000 /* Loop */
++
++/* Line Status Register */
++
++#define LSR_DR 0x0100 /* Data Ready */
++#define LSR_OE 0x0200 /* Overrun Error */
++#define LSR_PE 0x0400 /* Parity Error */
++#define LSR_FE 0x0800 /* Framing Error */
++#define LSR_BI 0x1000 /* Break Interrupt */
++#define LSR_THRE 0x2000 /* Transmitter Holding Register Empty */
++#define LSR_TEMT 0x4000 /* Transmitter Empty */
++#define LSR_FIFOE 0x8000 /* Receiver FIFO error */
++
++/* MODEM Status Register */
++
++#define MSR_DCTS 0x0100 /* Delta Clear to Send */
++#define MSR_DDSR 0x0200 /* Delta Data Set Ready */
++#define MSR_TERI 0x0400 /* Trailing Edge Ring Indicator */
++#define MSR_DDCD 0x0800 /* Delta Data Carrier Detect */
++#define MSR_CTS 0x1000 /* Clear to Send */
++#define MSR_DSR 0x2000 /* Data Set Ready */
++#define MSR_RI 0x4000 /* Ring Indicator */
++#define MSR_DCD 0x8000 /* Data Carrier Detect */
++
++/* Baud Rate Divisor */
++
++#define UART_CLK (1843200) /* 1.8432 MHz */
++#define UART_BAUD(x) (UART_CLK / (16 * (x)))
++
++/* RTC register definition */
++#define RTC_SECONDS 0
++#define RTC_SECONDS_ALARM 1
++#define RTC_MINUTES 2
++#define RTC_MINUTES_ALARM 3
++#define RTC_HOURS 4
++#define RTC_HOURS_ALARM 5
++#define RTC_DAY_OF_WEEK 6
++#define RTC_DAY_OF_MONTH 7
++#define RTC_MONTH 8
++#define RTC_YEAR 9
++#define RTC_FREQ_SELECT 10
++# define RTC_UIP 0x80
++# define RTC_DIV_CTL 0x70
++/* This RTC can work under 32.768KHz clock only. */
++# define RTC_OSC_ENABLE 0x20
++# define RTC_OSC_DISABLE 0x00
++#define RTC_CONTROL 11
++# define RTC_SET 0x80
++# define RTC_PIE 0x40
++# define RTC_AIE 0x20
++# define RTC_UIE 0x10
++# define RTC_SQWE 0x08
++# define RTC_DM_BINARY 0x04
++# define RTC_24H 0x02
++# define RTC_DST_EN 0x01
++
++#endif /* __ASM_SH_SMC37C93X_H */
+diff --git a/include/asm-sh/smp.h b/include/asm-sh/smp.h
+index f57c4fe..71ecddf 100644
+--- a/include/asm-sh/smp.h
++++ b/include/asm-sh/smp.h
+@@ -19,11 +19,6 @@
+ #include <asm/atomic.h>
+ #include <asm/current.h>
+
+-extern cpumask_t cpu_online_map;
+-extern cpumask_t cpu_possible_map;
+-
+-#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
+-
+ #define raw_smp_processor_id() (current_thread_info()->cpu)
+
+ /* I've no idea what the real meaning of this is */
+diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h
+new file mode 100644
+index 0000000..6b5e4dd
+--- /dev/null
++++ b/include/asm-sh/snapgear.h
+@@ -0,0 +1,79 @@
++/*
++ * include/asm-sh/snapgear/io.h
++ *
++ * Modified version of io_se.h for the snapgear-specific functions.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ * IO functions for a SnapGear
++ */
++
++#ifndef _ASM_SH_IO_SNAPGEAR_H
++#define _ASM_SH_IO_SNAPGEAR_H
++
++#if defined(CONFIG_CPU_SH4)
++/*
++ * The external interrupt lines, these take up ints 0 - 15 inclusive
++ * depending on the priority for the interrupt. In fact the priority
++ * is the interrupt :-)
++ */
++
++#define IRL0_IRQ 2
++#define IRL0_IPR_ADDR INTC_IPRD
++#define IRL0_IPR_POS 3
++#define IRL0_PRIORITY 13
++
++#define IRL1_IRQ 5
++#define IRL1_IPR_ADDR INTC_IPRD
++#define IRL1_IPR_POS 2
++#define IRL1_PRIORITY 10
++
++#define IRL2_IRQ 8
++#define IRL2_IPR_ADDR INTC_IPRD
++#define IRL2_IPR_POS 1
++#define IRL2_PRIORITY 7
++
++#define IRL3_IRQ 11
++#define IRL3_IPR_ADDR INTC_IPRD
++#define IRL3_IPR_POS 0
++#define IRL3_PRIORITY 4
++#endif
++
++#define __IO_PREFIX snapgear
++#include <asm/io_generic.h>
++
++#ifdef CONFIG_SH_SECUREEDGE5410
++/*
++ * We need to remember what was written to the ioport as some bits
++ * are shared with other functions and you cannot read back what was
++ * written :-|
++ *
++ * Bit Read Write
++ * -----------------------------------------------
++ * D0 DCD on ttySC1 power
++ * D1 Reset Switch heatbeat
++ * D2 ttySC0 CTS (7100) LAN
++ * D3 - WAN
++ * D4 ttySC0 DCD (7100) CONSOLE
++ * D5 - ONLINE
++ * D6 - VPN
++ * D7 - DTR on ttySC1
++ * D8 - ttySC0 RTS (7100)
++ * D9 - ttySC0 DTR (7100)
++ * D10 - RTC SCLK
++ * D11 RTC DATA RTC DATA
++ * D12 - RTS RESET
++ */
++
++#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
++extern unsigned short secureedge5410_ioport;
++
++#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
++ (secureedge5410_ioport = \
++ ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
++#define SECUREEDGE_READ_IOPORT() \
++ ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
++#endif
++
++#endif /* _ASM_SH_IO_SNAPGEAR_H */
+diff --git a/include/asm-sh/snapgear/io.h b/include/asm-sh/snapgear/io.h
+deleted file mode 100644
+index bfa97ac..0000000
+--- a/include/asm-sh/snapgear/io.h
++++ /dev/null
+@@ -1,92 +0,0 @@
+-/*
+- * include/asm-sh/snapgear/io.h
+- *
+- * Modified version of io_se.h for the snapgear-specific functions.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License. See linux/COPYING for more information.
+- *
+- * IO functions for a SnapGear
+- */
+-
+-#ifndef _ASM_SH_IO_SNAPGEAR_H
+-#define _ASM_SH_IO_SNAPGEAR_H
+-
+-#if defined(CONFIG_CPU_SH4)
+-/*
+- * The external interrupt lines, these take up ints 0 - 15 inclusive
+- * depending on the priority for the interrupt. In fact the priority
+- * is the interrupt :-)
+- */
+-
+-#define IRL0_IRQ 2
+-#define IRL0_IPR_ADDR INTC_IPRD
+-#define IRL0_IPR_POS 3
+-#define IRL0_PRIORITY 13
+-
+-#define IRL1_IRQ 5
+-#define IRL1_IPR_ADDR INTC_IPRD
+-#define IRL1_IPR_POS 2
+-#define IRL1_PRIORITY 10
+-
+-#define IRL2_IRQ 8
+-#define IRL2_IPR_ADDR INTC_IPRD
+-#define IRL2_IPR_POS 1
+-#define IRL2_PRIORITY 7
+-
+-#define IRL3_IRQ 11
+-#define IRL3_IPR_ADDR INTC_IPRD
+-#define IRL3_IPR_POS 0
+-#define IRL3_PRIORITY 4
+-#endif
+-
+-extern unsigned char snapgear_inb(unsigned long port);
+-extern unsigned short snapgear_inw(unsigned long port);
+-extern unsigned int snapgear_inl(unsigned long port);
+-
+-extern void snapgear_outb(unsigned char value, unsigned long port);
+-extern void snapgear_outw(unsigned short value, unsigned long port);
+-extern void snapgear_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char snapgear_inb_p(unsigned long port);
+-extern void snapgear_outb_p(unsigned char value, unsigned long port);
+-
+-extern void snapgear_insl(unsigned long port, void *addr, unsigned long count);
+-extern void snapgear_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned long snapgear_isa_port2addr(unsigned long offset);
+-
+-#ifdef CONFIG_SH_SECUREEDGE5410
+-/*
+- * We need to remember what was written to the ioport as some bits
+- * are shared with other functions and you cannot read back what was
+- * written :-|
+- *
+- * Bit Read Write
+- * -----------------------------------------------
+- * D0 DCD on ttySC1 power
+- * D1 Reset Switch heatbeat
+- * D2 ttySC0 CTS (7100) LAN
+- * D3 - WAN
+- * D4 ttySC0 DCD (7100) CONSOLE
+- * D5 - ONLINE
+- * D6 - VPN
+- * D7 - DTR on ttySC1
+- * D8 - ttySC0 RTS (7100)
+- * D9 - ttySC0 DTR (7100)
+- * D10 - RTC SCLK
+- * D11 RTC DATA RTC DATA
+- * D12 - RTS RESET
+- */
+-
+- #define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
+- extern unsigned short secureedge5410_ioport;
+-
+- #define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
+- (secureedge5410_ioport = \
+- ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
+- #define SECUREEDGE_READ_IOPORT() \
+- ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
+-#endif
+-
+-#endif /* _ASM_SH_IO_SNAPGEAR_H */
+diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h
+index 846322d..2586eef 100644
+--- a/include/asm-sh/spinlock.h
++++ b/include/asm-sh/spinlock.h
+@@ -88,7 +88,14 @@ static inline void __raw_write_unlock(ra
+ __raw_spin_unlock(&rw->lock);
+ }
+
+-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
++static inline int __raw_read_trylock(raw_rwlock_t *lock)
++{
++ atomic_t *count = (atomic_t*)lock;
++ if (atomic_dec_return(count) >= 0)
++ return 1;
++ atomic_inc(count);
++ return 0;
++}
+
+ static inline int __raw_write_trylock(raw_rwlock_t *rw)
+ {
+@@ -100,4 +107,8 @@ static inline int __raw_write_trylock(ra
+ return 0;
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SH_SPINLOCK_H */
+diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h
+index 3e0cff0..95bc7db 100644
+--- a/include/asm-sh/string.h
++++ b/include/asm-sh/string.h
+@@ -1,13 +1,15 @@
+ #ifndef __ASM_SH_STRING_H
+ #define __ASM_SH_STRING_H
+
++#ifdef __KERNEL__
++
+ /*
+ * Copyright (C) 1999 Niibe Yutaka
+ * But consider these trivial functions to be public domain.
+ */
+
+ #define __HAVE_ARCH_STRCPY
+-static __inline__ char *strcpy(char *__dest, const char *__src)
++static inline char *strcpy(char *__dest, const char *__src)
+ {
+ register char *__xdest = __dest;
+ unsigned long __dummy;
+@@ -26,7 +28,7 @@ static __inline__ char *strcpy(char *__d
+ }
+
+ #define __HAVE_ARCH_STRNCPY
+-static __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
++static inline char *strncpy(char *__dest, const char *__src, size_t __n)
+ {
+ register char *__xdest = __dest;
+ unsigned long __dummy;
+@@ -52,7 +54,7 @@ static __inline__ char *strncpy(char *__
+ }
+
+ #define __HAVE_ARCH_STRCMP
+-static __inline__ int strcmp(const char *__cs, const char *__ct)
++static inline int strcmp(const char *__cs, const char *__ct)
+ {
+ register int __res;
+ unsigned long __dummy;
+@@ -78,7 +80,7 @@ static __inline__ int strcmp(const char
+ }
+
+ #define __HAVE_ARCH_STRNCMP
+-static __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
++static inline int strncmp(const char *__cs, const char *__ct, size_t __n)
+ {
+ register int __res;
+ unsigned long __dummy;
+@@ -124,4 +126,9 @@ extern void *memchr(const void *__s, int
+ #define __HAVE_ARCH_STRLEN
+ extern size_t strlen(const char *);
+
++/* arch/sh/lib/strcasecmp.c */
++extern int strcasecmp(const char *, const char *);
++
++#endif /* __KERNEL__ */
++
+ #endif /* __ASM_SH_STRING_H */
+diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
+index ad35ad4..3340126 100644
+--- a/include/asm-sh/system.h
++++ b/include/asm-sh/system.h
+@@ -6,6 +6,7 @@
+ * Copyright (C) 2002 Paul Mundt
+ */
+
++#include <asm/types.h>
+
+ /*
+ * switch_to() should switch tasks to task nr n, first
+@@ -66,13 +67,20 @@ static inline void sched_cacheflush(void
+ {
+ }
+
+-#define nop() __asm__ __volatile__ ("nop")
+-
+-
+-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
++#ifdef CONFIG_CPU_SH4A
++#define __icbi() \
++{ \
++ unsigned long __addr; \
++ __addr = 0xa8000000; \
++ __asm__ __volatile__( \
++ "icbi %0\n\t" \
++ : /* no output */ \
++ : "m" (__m(__addr))); \
++}
++#endif
+
+-static __inline__ unsigned long tas(volatile int *m)
+-{ /* #define tas(ptr) (xchg((ptr),1)) */
++static inline unsigned long tas(volatile int *m)
++{
+ unsigned long retval;
+
+ __asm__ __volatile__ ("tas.b @%1\n\t"
+@@ -81,12 +89,33 @@ static __inline__ unsigned long tas(vola
+ return retval;
+ }
+
+-extern void __xchg_called_with_bad_pointer(void);
+-
+-#define mb() __asm__ __volatile__ ("": : :"memory")
+-#define rmb() mb()
+-#define wmb() __asm__ __volatile__ ("": : :"memory")
++/*
++ * A brief note on ctrl_barrier(), the control register write barrier.
++ *
++ * Legacy SH cores typically require a sequence of 8 nops after
++ * modification of a control register in order for the changes to take
++ * effect. On newer cores (like the sh4a and sh5) this is accomplished
++ * with icbi.
++ *
++ * Also note that on sh4a in the icbi case we can forego a synco for the
++ * write barrier, as it's not necessary for control registers.
++ *
++ * Historically we have only done this type of barrier for the MMUCR, but
++ * it's also necessary for the CCR, so we make it generic here instead.
++ */
++#ifdef CONFIG_CPU_SH4A
++#define mb() __asm__ __volatile__ ("synco": : :"memory")
++#define rmb() mb()
++#define wmb() __asm__ __volatile__ ("synco": : :"memory")
++#define ctrl_barrier() __icbi()
+ #define read_barrier_depends() do { } while(0)
++#else
++#define mb() __asm__ __volatile__ ("": : :"memory")
++#define rmb() mb()
++#define wmb() __asm__ __volatile__ ("": : :"memory")
++#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
++#define read_barrier_depends() do { } while(0)
++#endif
+
+ #ifdef CONFIG_SMP
+ #define smp_mb() mb()
+@@ -103,7 +132,8 @@ extern void __xchg_called_with_bad_point
+ #define set_mb(var, value) do { xchg(&var, value); } while (0)
+
+ /* Interrupt Control */
+-static __inline__ void local_irq_enable(void)
++#ifdef CONFIG_CPU_HAS_SR_RB
++static inline void local_irq_enable(void)
+ {
+ unsigned long __dummy0, __dummy1;
+
+@@ -116,8 +146,22 @@ static __inline__ void local_irq_enable(
+ : "1" (~0x000000f0)
+ : "memory");
+ }
++#else
++static inline void local_irq_enable(void)
++{
++ unsigned long __dummy0, __dummy1;
++
++ __asm__ __volatile__ (
++ "stc sr, %0\n\t"
++ "and %1, %0\n\t"
++ "ldc %0, sr\n\t"
++ : "=&r" (__dummy0), "=r" (__dummy1)
++ : "1" (~0x000000f0)
++ : "memory");
++}
++#endif
+
+-static __inline__ void local_irq_disable(void)
++static inline void local_irq_disable(void)
+ {
+ unsigned long __dummy;
+ __asm__ __volatile__("stc sr, %0\n\t"
+@@ -128,6 +172,31 @@ static __inline__ void local_irq_disable
+ : "memory");
+ }
+
++static inline void set_bl_bit(void)
++{
++ unsigned long __dummy0, __dummy1;
++
++ __asm__ __volatile__ ("stc sr, %0\n\t"
++ "or %2, %0\n\t"
++ "and %3, %0\n\t"
++ "ldc %0, sr"
++ : "=&r" (__dummy0), "=r" (__dummy1)
++ : "r" (0x10000000), "r" (0xffffff0f)
++ : "memory");
++}
++
++static inline void clear_bl_bit(void)
++{
++ unsigned long __dummy0, __dummy1;
++
++ __asm__ __volatile__ ("stc sr, %0\n\t"
++ "and %2, %0\n\t"
++ "ldc %0, sr"
++ : "=&r" (__dummy0), "=r" (__dummy1)
++ : "1" (~0x10000000)
++ : "memory");
++}
++
+ #define local_save_flags(x) \
+ __asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" )
+
+@@ -138,7 +207,7 @@ static __inline__ void local_irq_disable
+ (flags != 0); \
+ })
+
+-static __inline__ unsigned long local_irq_save(void)
++static inline unsigned long local_irq_save(void)
+ {
+ unsigned long flags, __dummy;
+
+@@ -154,35 +223,9 @@ static __inline__ unsigned long local_ir
+ return flags;
+ }
+
+-#ifdef DEBUG_CLI_STI
+-static __inline__ void local_irq_restore(unsigned long x)
+-{
+- if ((x & 0x000000f0) != 0x000000f0)
+- local_irq_enable();
+- else {
+- unsigned long flags;
+- local_save_flags(flags);
+-
+- if (flags == 0) {
+- extern void dump_stack(void);
+- printk(KERN_ERR "BUG!\n");
+- dump_stack();
+- local_irq_disable();
+- }
+- }
+-}
+-#else
+-#define local_irq_restore(x) do { \
+- if ((x & 0x000000f0) != 0x000000f0) \
+- local_irq_enable(); \
+-} while (0)
+-#endif
+-
+-#define really_restore_flags(x) do { \
++#define local_irq_restore(x) do { \
+ if ((x & 0x000000f0) != 0x000000f0) \
+- local_irq_enable(); \
+- else \
+- local_irq_disable(); \
++ local_irq_enable(); \
+ } while (0)
+
+ /*
+@@ -210,8 +253,8 @@ do { \
+ #define back_to_P1() \
+ do { \
+ unsigned long __dummy; \
++ ctrl_barrier(); \
+ __asm__ __volatile__( \
+- "nop;nop;nop;nop;nop;nop;nop\n\t" \
+ "mov.l 1f, %0\n\t" \
+ "jmp @%0\n\t" \
+ " nop\n\t" \
+@@ -224,7 +267,7 @@ do { \
+ /* For spinlocks etc */
+ #define local_irq_save(x) x = local_irq_save()
+
+-static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
++static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
+ {
+ unsigned long flags, retval;
+
+@@ -235,7 +278,7 @@ static __inline__ unsigned long xchg_u32
+ return retval;
+ }
+
+-static __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val)
++static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
+ {
+ unsigned long flags, retval;
+
+@@ -246,18 +289,75 @@ static __inline__ unsigned long xchg_u8(
+ return retval;
+ }
+
+-static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
++extern void __xchg_called_with_bad_pointer(void);
++
++#define __xchg(ptr, x, size) \
++({ \
++ unsigned long __xchg__res; \
++ volatile void *__xchg_ptr = (ptr); \
++ switch (size) { \
++ case 4: \
++ __xchg__res = xchg_u32(__xchg_ptr, x); \
++ break; \
++ case 1: \
++ __xchg__res = xchg_u8(__xchg_ptr, x); \
++ break; \
++ default: \
++ __xchg_called_with_bad_pointer(); \
++ __xchg__res = x; \
++ break; \
++ } \
++ \
++ __xchg__res; \
++})
++
++#define xchg(ptr,x) \
++ ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
++
++static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
++ unsigned long new)
++{
++ __u32 retval;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ retval = *m;
++ if (retval == old)
++ *m = new;
++ local_irq_restore(flags); /* implies memory barrier */
++ return retval;
++}
++
++/* 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);
++
++#define __HAVE_ARCH_CMPXCHG 1
++
++static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
++ unsigned long new, int size)
+ {
+ switch (size) {
+ case 4:
+- return xchg_u32(ptr, x);
+- break;
+- case 1:
+- return xchg_u8(ptr, x);
+- break;
++ return __cmpxchg_u32(ptr, old, new);
+ }
+- __xchg_called_with_bad_pointer();
+- return x;
++ __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))); \
++ })
++
++extern void *set_exception_table_vec(unsigned int vec, void *handler);
++
++static inline void *set_exception_table_evt(unsigned int evt, void *handler)
++{
++ return set_exception_table_vec(evt >> 5, handler);
+ }
+
+ /* XXX
+diff --git a/include/asm-sh/systemh/7751systemh.h b/include/asm-sh/systemh/7751systemh.h
+deleted file mode 100644
+index 4170531..0000000
+--- a/include/asm-sh/systemh/7751systemh.h
++++ /dev/null
+@@ -1,68 +0,0 @@
+-#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
+-#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
+-
+-/*
+- * linux/include/asm-sh/systemh/7751systemh.h
+- *
+- * Copyright (C) 2000 Kazumoto Kojima
+- *
+- * Hitachi SystemH support
+-
+- * Modified for 7751 SystemH by
+- * Jonathan Short, 2002.
+- */
+-
+-/* Box specific addresses. */
+-
+-#define PA_ROM 0x00000000 /* EPROM */
+-#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
+-#define PA_FROM 0x01000000 /* EPROM */
+-#define PA_FROM_SIZE 0x00400000 /* EPROM size 4M byte */
+-#define PA_EXT1 0x04000000
+-#define PA_EXT1_SIZE 0x04000000
+-#define PA_EXT2 0x08000000
+-#define PA_EXT2_SIZE 0x04000000
+-#define PA_SDRAM 0x0c000000
+-#define PA_SDRAM_SIZE 0x04000000
+-
+-#define PA_EXT4 0x12000000
+-#define PA_EXT4_SIZE 0x02000000
+-#define PA_EXT5 0x14000000
+-#define PA_EXT5_SIZE 0x04000000
+-#define PA_PCIC 0x18000000 /* MR-SHPC-01 PCMCIA */
+-
+-#define PA_DIPSW0 0xb9000000 /* Dip switch 5,6 */
+-#define PA_DIPSW1 0xb9000002 /* Dip switch 7,8 */
+-#define PA_LED 0xba000000 /* LED */
+-#define PA_BCR 0xbb000000 /* FPGA on the MS7751SE01 */
+-
+-#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controler */
+-#define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */
+-#define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */
+-#define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */
+-#define MRSHPC_MODE (PA_MRSHPC + 4)
+-#define MRSHPC_OPTION (PA_MRSHPC + 6)
+-#define MRSHPC_CSR (PA_MRSHPC + 8)
+-#define MRSHPC_ISR (PA_MRSHPC + 10)
+-#define MRSHPC_ICR (PA_MRSHPC + 12)
+-#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+-#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+-#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+-#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+-#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+-#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+-#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+-#define MRSHPC_CDCR (PA_MRSHPC + 28)
+-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+-
+-#define BCR_ILCRA (PA_BCR + 0)
+-#define BCR_ILCRB (PA_BCR + 2)
+-#define BCR_ILCRC (PA_BCR + 4)
+-#define BCR_ILCRD (PA_BCR + 6)
+-#define BCR_ILCRE (PA_BCR + 8)
+-#define BCR_ILCRF (PA_BCR + 10)
+-#define BCR_ILCRG (PA_BCR + 12)
+-
+-#define IRQ_79C973 13
+-
+-#endif /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
+diff --git a/include/asm-sh/systemh/io.h b/include/asm-sh/systemh/io.h
+deleted file mode 100644
+index 327849b..0000000
+--- a/include/asm-sh/systemh/io.h
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- * include/asm-sh/systemh/io.h
+- *
+- * Stupid I/O definitions for SystemH, cloned from SE7751.
+- *
+- * Copyright (C) 2003 Paul Mundt
+- *
+- * 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 __ASM_SH_SYSTEMH_IO_H
+-#define __ASM_SH_SYSTEMH_IO_H
+-
+-extern unsigned char sh7751systemh_inb(unsigned long port);
+-extern unsigned short sh7751systemh_inw(unsigned long port);
+-extern unsigned int sh7751systemh_inl(unsigned long port);
+-
+-extern void sh7751systemh_outb(unsigned char value, unsigned long port);
+-extern void sh7751systemh_outw(unsigned short value, unsigned long port);
+-extern void sh7751systemh_outl(unsigned int value, unsigned long port);
+-
+-extern unsigned char sh7751systemh_inb_p(unsigned long port);
+-extern void sh7751systemh_outb_p(unsigned char value, unsigned long port);
+-
+-extern void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count);
+-extern void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count);
+-extern void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count);
+-extern void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count);
+-extern void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count);
+-extern void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count);
+-
+-extern unsigned char sh7751systemh_readb(unsigned long addr);
+-extern unsigned short sh7751systemh_readw(unsigned long addr);
+-extern unsigned int sh7751systemh_readl(unsigned long addr);
+-extern void sh7751systemh_writeb(unsigned char b, unsigned long addr);
+-extern void sh7751systemh_writew(unsigned short b, unsigned long addr);
+-extern void sh7751systemh_writel(unsigned int b, unsigned long addr);
+-
+-extern unsigned long sh7751systemh_isa_port2addr(unsigned long offset);
+-
+-#endif /* __ASM_SH_SYSTEMH_IO_H */
+-
+diff --git a/include/asm-sh/systemh7751.h b/include/asm-sh/systemh7751.h
+new file mode 100644
+index 0000000..b143bb2
+--- /dev/null
++++ b/include/asm-sh/systemh7751.h
+@@ -0,0 +1,71 @@
++#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
++#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
++
++/*
++ * linux/include/asm-sh/systemh/7751systemh.h
++ *
++ * Copyright (C) 2000 Kazumoto Kojima
++ *
++ * Hitachi SystemH support
++
++ * Modified for 7751 SystemH by
++ * Jonathan Short, 2002.
++ */
++
++/* Box specific addresses. */
++
++#define PA_ROM 0x00000000 /* EPROM */
++#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
++#define PA_FROM 0x01000000 /* EPROM */
++#define PA_FROM_SIZE 0x00400000 /* EPROM size 4M byte */
++#define PA_EXT1 0x04000000
++#define PA_EXT1_SIZE 0x04000000
++#define PA_EXT2 0x08000000
++#define PA_EXT2_SIZE 0x04000000
++#define PA_SDRAM 0x0c000000
++#define PA_SDRAM_SIZE 0x04000000
++
++#define PA_EXT4 0x12000000
++#define PA_EXT4_SIZE 0x02000000
++#define PA_EXT5 0x14000000
++#define PA_EXT5_SIZE 0x04000000
++#define PA_PCIC 0x18000000 /* MR-SHPC-01 PCMCIA */
++
++#define PA_DIPSW0 0xb9000000 /* Dip switch 5,6 */
++#define PA_DIPSW1 0xb9000002 /* Dip switch 7,8 */
++#define PA_LED 0xba000000 /* LED */
++#define PA_BCR 0xbb000000 /* FPGA on the MS7751SE01 */
++
++#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controler */
++#define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */
++#define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */
++#define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */
++#define MRSHPC_MODE (PA_MRSHPC + 4)
++#define MRSHPC_OPTION (PA_MRSHPC + 6)
++#define MRSHPC_CSR (PA_MRSHPC + 8)
++#define MRSHPC_ISR (PA_MRSHPC + 10)
++#define MRSHPC_ICR (PA_MRSHPC + 12)
++#define MRSHPC_CPWCR (PA_MRSHPC + 14)
++#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
++#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
++#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
++#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
++#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
++#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
++#define MRSHPC_CDCR (PA_MRSHPC + 28)
++#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
++
++#define BCR_ILCRA (PA_BCR + 0)
++#define BCR_ILCRB (PA_BCR + 2)
++#define BCR_ILCRC (PA_BCR + 4)
++#define BCR_ILCRD (PA_BCR + 6)
++#define BCR_ILCRE (PA_BCR + 8)
++#define BCR_ILCRF (PA_BCR + 10)
++#define BCR_ILCRG (PA_BCR + 12)
++
++#define IRQ_79C973 13
++
++#define __IO_PREFIX sh7751systemh
++#include <asm/io_generic.h>
++
++#endif /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
+diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
+index 7345350..3ebc3f9 100644
+--- a/include/asm-sh/thread_info.h
++++ b/include/asm-sh/thread_info.h
+@@ -9,8 +9,8 @@
+ * Copyright (C) 2002 David Howells (dhowells at redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ */
+-
+ #ifdef __KERNEL__
++#include <asm/page.h>
+
+ #ifndef __ASSEMBLY__
+ #include <asm/processor.h>
+@@ -21,7 +21,10 @@ struct thread_info {
+ unsigned long flags; /* low level flags */
+ __u32 cpu;
+ int preempt_count; /* 0 => preemptable, <0 => BUG */
++ mm_segment_t addr_limit; /* thread address space */
+ struct restart_block restart_block;
++ unsigned long previous_sp; /* sp of previous stack in case
++ of nested IRQ stacks */
+ __u8 supervisor_stack[0];
+ };
+
+@@ -29,6 +32,13 @@ struct thread_info {
+
+ #define PREEMPT_ACTIVE 0x10000000
+
++#ifdef CONFIG_4KSTACKS
++#define THREAD_SIZE (PAGE_SIZE)
++#else
++#define THREAD_SIZE (PAGE_SIZE * 2)
++#endif
++#define STACK_WARN (THREAD_SIZE / 8)
++
+ /*
+ * macros/functions for gaining access to the thread information structure
+ */
+@@ -40,6 +50,7 @@ struct thread_info {
+ .flags = 0, \
+ .cpu = 0, \
+ .preempt_count = 1, \
++ .addr_limit = KERNEL_DS, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
+@@ -48,24 +59,42 @@ struct thread_info {
+ #define init_thread_info (init_thread_union.thread_info)
+ #define init_stack (init_thread_union.stack)
+
++/* how to get the current stack pointer from C */
++register unsigned long current_stack_pointer asm("r15") __attribute_used__;
++
+ /* how to get the thread information struct from C */
+ static inline struct thread_info *current_thread_info(void)
+ {
+ struct thread_info *ti;
++#ifdef CONFIG_CPU_HAS_SR_RB
+ __asm__("stc r7_bank, %0" : "=r" (ti));
++#else
++ unsigned long __dummy;
++
++ __asm__ __volatile__ (
++ "mov r15, %0\n\t"
++ "and %1, %0\n\t"
++ : "=&r" (ti), "=r" (__dummy)
++ : "1" (~(THREAD_SIZE - 1))
++ : "memory");
++#endif
++
+ return ti;
+ }
+
+ /* thread information allocation */
+-#define THREAD_SIZE (2*PAGE_SIZE)
+-#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+-#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
++#ifdef CONFIG_DEBUG_STACK_USAGE
++#define alloc_thread_info(ti) kzalloc(THREAD_SIZE, GFP_KERNEL)
++#else
++#define alloc_thread_info(ti) kmalloc(THREAD_SIZE, GFP_KERNEL)
++#endif
++#define free_thread_info(ti) kfree(ti)
+
+ #else /* !__ASSEMBLY__ */
+
+ /* how to get the thread information struct from ASM */
+ #define GET_THREAD_INFO(reg) \
+- stc r7_bank, reg
++ stc r7_bank, reg
+
+ #endif
+
+@@ -79,18 +108,18 @@ static inline struct thread_info *curren
+ #define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
+ #define TIF_SIGPENDING 2 /* signal pending */
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
++#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
+ #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 */
+ #define TIF_MEMDIE 18
+-#define TIF_USERSPACE 31 /* true if FS sets userspace */
+
+ #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_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
+ #define _TIF_USEDFPU (1<<TIF_USEDFPU)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+-#define _TIF_USERSPACE (1<<TIF_USERSPACE)
+
+ #define _TIF_WORK_MASK 0x000000FE /* work to do on interrupt/exception return */
+ #define _TIF_ALLWORK_MASK 0x000000FF /* work to do on any return to u-space */
+diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h
+index dd6579c..5df842b 100644
+--- a/include/asm-sh/timer.h
++++ b/include/asm-sh/timer.h
+@@ -6,8 +6,11 @@
+
+ struct sys_timer_ops {
+ int (*init)(void);
++ int (*start)(void);
++ int (*stop)(void);
++#ifndef CONFIG_GENERIC_TIME
+ unsigned long (*get_offset)(void);
+- unsigned long (*get_frequency)(void);
++#endif
+ };
+
+ struct sys_timer {
+@@ -22,21 +25,17 @@ struct sys_timer {
+ extern struct sys_timer tmu_timer;
+ extern struct sys_timer *sys_timer;
+
++#ifndef CONFIG_GENERIC_TIME
+ static inline unsigned long get_timer_offset(void)
+ {
+ return sys_timer->ops->get_offset();
+ }
+-
+-static inline unsigned long get_timer_frequency(void)
+-{
+- return sys_timer->ops->get_frequency();
+-}
++#endif
+
+ /* arch/sh/kernel/timers/timer.c */
+ struct sys_timer *get_sys_timer(void);
+
+ /* arch/sh/kernel/time.c */
+-void handle_timer_tick(struct pt_regs *);
++void handle_timer_tick(void);
+
+ #endif /* __ASM_SH_TIMER_H */
+-
+diff --git a/include/asm-sh/titan.h b/include/asm-sh/titan.h
+new file mode 100644
+index 0000000..270a4f4
+--- /dev/null
++++ b/include/asm-sh/titan.h
+@@ -0,0 +1,43 @@
++/*
++ * Platform defintions for Titan
++ */
++
++#ifndef _ASM_SH_TITAN_TITAN_H
++#define _ASM_SH_TITAN_TITAN_H
++
++#define __IO_PREFIX titan
++#include <asm/io_generic.h>
++
++/* IRQ assignments */
++#define TITAN_IRQ_WAN 2 /* eth0 (WAN) */
++#define TITAN_IRQ_LAN 5 /* eth1 (LAN) */
++#define TITAN_IRQ_MPCIA 8 /* mPCI A */
++#define TITAN_IRQ_MPCIB 11 /* mPCI B */
++#define TITAN_IRQ_USB 11 /* USB */
++
++/*
++ * The external interrupt lines, these take up ints 0 - 15 inclusive
++ * depending on the priority for the interrupt. In fact the priority
++ * is the interrupt :-)
++ */
++#define IRL0_IRQ 0
++#define IRL0_IPR_ADDR INTC_IPRD
++#define IRL0_IPR_POS 3
++#define IRL0_PRIORITY 8
++
++#define IRL1_IRQ 1
++#define IRL1_IPR_ADDR INTC_IPRD
++#define IRL1_IPR_POS 2
++#define IRL1_PRIORITY 8
++
++#define IRL2_IRQ 2
++#define IRL2_IPR_ADDR INTC_IPRD
++#define IRL2_IPR_POS 1
++#define IRL2_PRIORITY 8
++
++#define IRL3_IRQ 3
++#define IRL3_IPR_ADDR INTC_IPRD
++#define IRL3_IPR_POS 0
++#define IRL3_PRIORITY 8
++
++#endif
+diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
+index 2cb0186..5c49ed6 100644
+--- a/include/asm-sh/uaccess.h
++++ b/include/asm-sh/uaccess.h
+@@ -16,21 +16,9 @@
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+
+-/*
+- * NOTE: Macro/functions in this file depends on threads_info.h implementation.
+- * Assumes:
+- * TI_FLAGS == 8
+- * TIF_USERSPACE == 31
+- * USER_ADDR_LIMIT == 0x80000000
+- */
+-
+ #define VERIFY_READ 0
+ #define VERIFY_WRITE 1
+
+-typedef struct {
+- unsigned int is_user_space;
+-} mm_segment_t;
+-
+ /*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+@@ -40,16 +28,18 @@ typedef struct {
+ */
+
+ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+-#define segment_eq(a,b) ((a).is_user_space == (b).is_user_space)
+
+-#define USER_ADDR_LIMIT 0x80000000
++#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL)
++#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
+
+-#define KERNEL_DS MAKE_MM_SEG(0)
+-#define USER_DS MAKE_MM_SEG(1)
++#define segment_eq(a,b) ((a).seg == (b).seg)
+
+ #define get_ds() (KERNEL_DS)
+
+ #if !defined(CONFIG_MMU)
++/* NOMMU is always true */
++#define __addr_ok(addr) (1)
++
+ static inline mm_segment_t get_fs(void)
+ {
+ return USER_DS;
+@@ -76,31 +66,11 @@ static inline int __access_ok(unsigned l
+ return ((addr >= memory_start) && ((addr + size) < memory_end));
+ }
+ #else /* CONFIG_MMU */
+-static inline mm_segment_t get_fs(void)
+-{
+- return MAKE_MM_SEG(test_thread_flag(TIF_USERSPACE));
+-}
++#define __addr_ok(addr) \
++ ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
+
+-static inline void set_fs(mm_segment_t s)
+-{
+- unsigned long ti, flag;
+- __asm__ __volatile__(
+- "stc r7_bank, %0\n\t"
+- "mov.l @(8,%0), %1\n\t"
+- "shal %1\n\t"
+- "cmp/pl %2\n\t"
+- "rotcr %1\n\t"
+- "mov.l %1, @(8,%0)"
+- : "=&r" (ti), "=&r" (flag)
+- : "r" (s.is_user_space)
+- : "t");
+-/****
+- if (s.is_user_space)
+- set_thread_flag(TIF_USERSPACE);
+- else
+- clear_thread_flag(TIF_USERSPACE);
+-****/
+-}
++#define get_fs() (current_thread_info()->addr_limit)
++#define set_fs(x) (current_thread_info()->addr_limit = (x))
+
+ /*
+ * __access_ok: Check if address with size is OK or not.
+@@ -108,7 +78,7 @@ static inline void set_fs(mm_segment_t s
+ * We do three checks:
+ * (1) is it user space?
+ * (2) addr + size --> carry?
+- * (3) addr + size >= 0x80000000 (USER_ADDR_LIMIT)
++ * (3) addr + size >= 0x80000000 (PAGE_OFFSET)
+ *
+ * (1) (2) (3) | RESULT
+ * 0 0 0 | ok
+@@ -201,6 +171,7 @@ do { \
+ __gu_err; \
+ })
+
++#ifdef CONFIG_MMU
+ #define __get_user_check(x,ptr,size) \
+ ({ \
+ long __gu_err, __gu_val; \
+@@ -290,6 +261,18 @@ __asm__("stc r7_bank, %1\n\t" \
+ : "r" (addr) \
+ : "t"); \
+ })
++#else /* CONFIG_MMU */
++#define __get_user_check(x,ptr,size) \
++({ \
++ long __gu_err, __gu_val; \
++ if (__access_ok((unsigned long)(ptr), (size))) { \
++ __get_user_size(__gu_val, (ptr), (size), __gu_err); \
++ (x) = (__typeof__(*(ptr)))__gu_val; \
++ } else \
++ __gu_err = -EFAULT; \
++ __gu_err; \
++})
++#endif
+
+ #define __get_user_asm(x, addr, err, insn) \
+ ({ \
+@@ -541,7 +524,7 @@ static __inline__ long __strnlen_user(co
+ "3:\n\t"
+ "mov.l 4f, %1\n\t"
+ "jmp @%1\n\t"
+- " mov %5, %0\n"
++ " mov #0, %0\n"
+ ".balign 4\n"
+ "4: .long 2b\n"
+ ".previous\n"
+@@ -550,26 +533,20 @@ static __inline__ long __strnlen_user(co
+ " .long 1b,3b\n"
+ ".previous"
+ : "=z" (res), "=&r" (__dummy)
+- : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)
++ : "0" (0), "r" (__s), "r" (__n)
+ : "t");
+ return res;
+ }
+
+ static __inline__ long strnlen_user(const char __user *s, long n)
+ {
+- if (!access_ok(VERIFY_READ, s, n))
++ if (!__addr_ok(s))
+ return 0;
+ else
+ return __strnlen_user(s, n);
+ }
+
+-static __inline__ long strlen_user(const char __user *s)
+-{
+- if (!access_ok(VERIFY_READ, s, 0))
+- return 0;
+- else
+- return __strnlen_user(s, ~0UL >> 1);
+-}
++#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
+ /*
+ * The exception table consists of pairs of addresses: the first is the
+diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
+index 76b5430..1c2abde 100644
+--- a/include/asm-sh/unistd.h
++++ b/include/asm-sh/unistd.h
+@@ -292,25 +292,54 @@
+ #define __NR_mq_getsetattr (__NR_mq_open+5)
+ #define __NR_kexec_load 283
+ #define __NR_waitid 284
+-#define __NR_add_key 285
+-#define __NR_request_key 286
+-#define __NR_keyctl 287
+-#define __NR_ioprio_set 288
+-#define __NR_ioprio_get 289
+-#define __NR_inotify_init 290
+-#define __NR_inotify_add_watch 291
+-#define __NR_inotify_rm_watch 292
++/* #define __NR_sys_setaltroot 285 */
++#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_migrate_pages 294
++#define __NR_openat 295
++#define __NR_mkdirat 296
++#define __NR_mknodat 297
++#define __NR_fchownat 298
++#define __NR_futimesat 299
++#define __NR_newfstatat 300
++#define __NR_unlinkat 301
++#define __NR_renameat 302
++#define __NR_linkat 303
++#define __NR_symlinkat 304
++#define __NR_readlinkat 305
++#define __NR_fchmodat 306
++#define __NR_faccessat 307
++#define __NR_pselect6 308
++#define __NR_ppoll 309
++#define __NR_unshare 310
++#define __NR_set_robust_list 311
++#define __NR_get_robust_list 312
++#define __NR_splice 313
++#define __NR_sync_file_range 314
++#define __NR_tee 315
++#define __NR_vmsplice 316
++#define __NR_move_pages 317
++#define __NR_getcpu 318
++#define __NR_epoll_pwait 319
+
+-
+-#define NR_syscalls 293
++#define NR_syscalls 320
+
+ #ifdef __KERNEL__
+
+-/* user-visible error numbers are in the range -1 - -124: see <asm-sh/errno.h> */
++#include <linux/err.h>
++
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO:
++ * see <asm-sh/errno.h> */
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-124)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ /* Avoid using "res" which is declared to be in register r0; \
+ errno might expand to a function call and clobber it. */ \
+ int __err = -(res); \
+@@ -444,76 +473,7 @@ __syscall_return(type,__sc0); \
+ #define __ARCH_WANT_SYS_SIGPENDING
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+-
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <linux/linkage.h>
+-#include <asm/ptrace.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static __inline__ _syscall0(int,pause)
+-static __inline__ _syscall0(int,sync)
+-static __inline__ _syscall0(pid_t,setsid)
+-static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static __inline__ _syscall1(int,dup,int,fd)
+-static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode)
+-static __inline__ _syscall1(int,close,int,fd)
+-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-static __inline__ _syscall1(int,delete_module,const char *,name)
+-
+-static __inline__ pid_t wait(int * wait_stat)
+-{
+- return waitpid(-1,wait_stat,0);
+-}
+-
+-asmlinkage long sys_mmap2(
+- unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-asmlinkage int sys_execve(char *ufilename, char **uargv,
+- char **uenvp, unsigned long r7,
+- struct pt_regs regs);
+-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+- unsigned long parent_tidptr,
+- unsigned long child_tidptr,
+- struct pt_regs regs);
+-asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
+- unsigned long r6, unsigned long r7,
+- struct pt_regs regs);
+-asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
+- unsigned long r6, unsigned long r7,
+- struct pt_regs regs);
+-asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
+- unsigned long r6, unsigned long r7,
+- struct pt_regs regs);
+-asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char *buf,
+- size_t count, long dummy, loff_t pos);
+-asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char *buf,
+- size_t count, long dummy, loff_t pos);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
++#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
+ /*
+ * "Conditional" syscalls
+diff --git a/include/asm-sh/voyagergx.h b/include/asm-sh/voyagergx.h
+new file mode 100644
+index 0000000..99b0807
+--- /dev/null
++++ b/include/asm-sh/voyagergx.h
+@@ -0,0 +1,313 @@
++/* -------------------------------------------------------------------- */
++/* voyagergx.h */
++/* -------------------------------------------------------------------- */
++/* 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.
++
++ Copyright 2003 (c) Lineo uSolutions,Inc.
++*/
++/* -------------------------------------------------------------------- */
++
++#ifndef _VOYAGER_GX_REG_H
++#define _VOYAGER_GX_REG_H
++
++#define VOYAGER_BASE 0xb3e00000
++#define VOYAGER_USBH_BASE (0x40000 + VOYAGER_BASE)
++#define VOYAGER_UART_BASE (0x30000 + VOYAGER_BASE)
++#define VOYAGER_AC97_BASE (0xa0000 + VOYAGER_BASE)
++
++#define VOYAGER_IRQ_NUM 32
++#define VOYAGER_IRQ_BASE 50
++#define VOYAGER_USBH_IRQ VOYAGER_IRQ_BASE + 6
++#define VOYAGER_8051_IRQ VOYAGER_IRQ_BASE + 10
++#define VOYAGER_UART0_IRQ VOYAGER_IRQ_BASE + 12
++#define VOYAGER_UART1_IRQ VOYAGER_IRQ_BASE + 13
++#define VOYAGER_AC97_IRQ VOYAGER_IRQ_BASE + 17
++
++/* ----- MISC controle register ------------------------------ */
++#define MISC_CTRL (0x000004 + VOYAGER_BASE)
++#define MISC_CTRL_USBCLK_48 (3 << 28)
++#define MISC_CTRL_USBCLK_96 (2 << 28)
++#define MISC_CTRL_USBCLK_CRYSTAL (1 << 28)
++
++/* ----- GPIO[31:0] register --------------------------------- */
++#define GPIO_MUX_LOW (0x000008 + VOYAGER_BASE)
++#define GPIO_MUX_LOW_AC97 0x1F000000
++#define GPIO_MUX_LOW_8051 0x0000ffff
++#define GPIO_MUX_LOW_PWM (1 << 29)
++
++/* ----- GPIO[63:32] register --------------------------------- */
++#define GPIO_MUX_HIGH (0x00000C + VOYAGER_BASE)
++
++/* ----- DRAM controle register ------------------------------- */
++#define DRAM_CTRL (0x000010 + VOYAGER_BASE)
++#define DRAM_CTRL_EMBEDDED (1 << 31)
++#define DRAM_CTRL_CPU_BURST_1 (0 << 28)
++#define DRAM_CTRL_CPU_BURST_2 (1 << 28)
++#define DRAM_CTRL_CPU_BURST_4 (2 << 28)
++#define DRAM_CTRL_CPU_BURST_8 (3 << 28)
++#define DRAM_CTRL_CPU_CAS_LATENCY (1 << 27)
++#define DRAM_CTRL_CPU_SIZE_2 (0 << 24)
++#define DRAM_CTRL_CPU_SIZE_4 (1 << 24)
++#define DRAM_CTRL_CPU_SIZE_64 (4 << 24)
++#define DRAM_CTRL_CPU_SIZE_32 (5 << 24)
++#define DRAM_CTRL_CPU_SIZE_16 (6 << 24)
++#define DRAM_CTRL_CPU_SIZE_8 (7 << 24)
++#define DRAM_CTRL_CPU_COLUMN_SIZE_1024 (0 << 22)
++#define DRAM_CTRL_CPU_COLUMN_SIZE_512 (2 << 22)
++#define DRAM_CTRL_CPU_COLUMN_SIZE_256 (3 << 22)
++#define DRAM_CTRL_CPU_ACTIVE_PRECHARGE (1 << 21)
++#define DRAM_CTRL_CPU_RESET (1 << 20)
++#define DRAM_CTRL_CPU_BANKS (1 << 19)
++#define DRAM_CTRL_CPU_WRITE_PRECHARGE (1 << 18)
++#define DRAM_CTRL_BLOCK_WRITE (1 << 17)
++#define DRAM_CTRL_REFRESH_COMMAND (1 << 16)
++#define DRAM_CTRL_SIZE_4 (0 << 13)
++#define DRAM_CTRL_SIZE_8 (1 << 13)
++#define DRAM_CTRL_SIZE_16 (2 << 13)
++#define DRAM_CTRL_SIZE_32 (3 << 13)
++#define DRAM_CTRL_SIZE_64 (4 << 13)
++#define DRAM_CTRL_SIZE_2 (5 << 13)
++#define DRAM_CTRL_COLUMN_SIZE_256 (0 << 11)
++#define DRAM_CTRL_COLUMN_SIZE_512 (2 << 11)
++#define DRAM_CTRL_COLUMN_SIZE_1024 (3 << 11)
++#define DRAM_CTRL_BLOCK_WRITE_TIME (1 << 10)
++#define DRAM_CTRL_BLOCK_WRITE_PRECHARGE (1 << 9)
++#define DRAM_CTRL_ACTIVE_PRECHARGE (1 << 8)
++#define DRAM_CTRL_RESET (1 << 7)
++#define DRAM_CTRL_REMAIN_ACTIVE (1 << 6)
++#define DRAM_CTRL_BANKS (1 << 1)
++#define DRAM_CTRL_WRITE_PRECHARGE (1 << 0)
++
++/* ----- Arvitration control register -------------------------- */
++#define ARBITRATION_CTRL (0x000014 + VOYAGER_BASE)
++#define ARBITRATION_CTRL_CPUMEM (1 << 29)
++#define ARBITRATION_CTRL_INTMEM (1 << 28)
++#define ARBITRATION_CTRL_USB_OFF (0 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_1 (1 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_2 (2 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_3 (3 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_4 (4 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_5 (5 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_6 (6 << 24)
++#define ARBITRATION_CTRL_USB_PRIORITY_7 (7 << 24)
++#define ARBITRATION_CTRL_PANEL_OFF (0 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_1 (1 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_2 (2 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_3 (3 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_4 (4 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_5 (5 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_6 (6 << 20)
++#define ARBITRATION_CTRL_PANEL_PRIORITY_7 (7 << 20)
++#define ARBITRATION_CTRL_ZVPORT_OFF (0 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_1 (1 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_2 (2 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_3 (3 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_4 (4 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_5 (5 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_6 (6 << 16)
++#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_7 (7 << 16)
++#define ARBITRATION_CTRL_CMD_INTPR_OFF (0 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_1 (1 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_2 (2 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_3 (3 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_4 (4 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_5 (5 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_6 (6 << 12)
++#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_7 (7 << 12)
++#define ARBITRATION_CTRL_DMA_OFF (0 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_1 (1 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_2 (2 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_3 (3 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_4 (4 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_5 (5 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_6 (6 << 8)
++#define ARBITRATION_CTRL_DMA_PRIORITY_7 (7 << 8)
++#define ARBITRATION_CTRL_VIDEO_OFF (0 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_1 (1 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_2 (2 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_3 (3 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_4 (4 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_5 (5 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_6 (6 << 4)
++#define ARBITRATION_CTRL_VIDEO_PRIORITY_7 (7 << 4)
++#define ARBITRATION_CTRL_CRT_OFF (0 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_1 (1 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_2 (2 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_3 (3 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_4 (4 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_5 (5 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_6 (6 << 0)
++#define ARBITRATION_CTRL_CRT_PRIORITY_7 (7 << 0)
++
++/* ----- Command list status register -------------------------- */
++#define CMD_INTPR_STATUS (0x000024 + VOYAGER_BASE)
++
++/* ----- Interrupt status register ----------------------------- */
++#define INT_STATUS (0x00002c + VOYAGER_BASE)
++#define INT_STATUS_UH (1 << 6)
++#define INT_STATUS_MC (1 << 10)
++#define INT_STATUS_U0 (1 << 12)
++#define INT_STATUS_U1 (1 << 13)
++#define INT_STATUS_AC (1 << 17)
++
++/* ----- Interrupt mask register ------------------------------ */
++#define VOYAGER_INT_MASK (0x000030 + VOYAGER_BASE)
++#define VOYAGER_INT_MASK_AC (1 << 17)
++
++/* ----- Current Gate register ---------------------------------*/
++#define CURRENT_GATE (0x000038 + VOYAGER_BASE)
++
++/* ----- Power mode 0 gate register --------------------------- */
++#define POWER_MODE0_GATE (0x000040 + VOYAGER_BASE)
++#define POWER_MODE0_GATE_G (1 << 6)
++#define POWER_MODE0_GATE_U0 (1 << 7)
++#define POWER_MODE0_GATE_U1 (1 << 8)
++#define POWER_MODE0_GATE_UH (1 << 11)
++#define POWER_MODE0_GATE_AC (1 << 18)
++
++/* ----- Power mode 1 gate register --------------------------- */
++#define POWER_MODE1_GATE (0x000048 + VOYAGER_BASE)
++#define POWER_MODE1_GATE_G (1 << 6)
++#define POWER_MODE1_GATE_U0 (1 << 7)
++#define POWER_MODE1_GATE_U1 (1 << 8)
++#define POWER_MODE1_GATE_UH (1 << 11)
++#define POWER_MODE1_GATE_AC (1 << 18)
++
++/* ----- Power mode 0 clock register -------------------------- */
++#define POWER_MODE0_CLOCK (0x000044 + VOYAGER_BASE)
++
++/* ----- Power mode 1 clock register -------------------------- */
++#define POWER_MODE1_CLOCK (0x00004C + VOYAGER_BASE)
++
++/* ----- Power mode controll register ------------------------- */
++#define POWER_MODE_CTRL (0x000054 + VOYAGER_BASE)
++
++/* ----- Miscellaneous Timing register ------------------------ */
++#define SYSTEM_DRAM_CTRL (0x000068 + VOYAGER_BASE)
++
++/* ----- PWM register ------------------------------------------*/
++#define PWM_0 (0x010020 + VOYAGER_BASE)
++#define PWM_0_HC(x) (((x)&0x0fff)<<20)
++#define PWM_0_LC(x) (((x)&0x0fff)<<8 )
++#define PWM_0_CLK_DEV(x) (((x)&0x000f)<<4 )
++#define PWM_0_EN (1<<0)
++
++/* ----- I2C register ----------------------------------------- */
++#define I2C_BYTECOUNT (0x010040 + VOYAGER_BASE)
++#define I2C_CONTROL (0x010041 + VOYAGER_BASE)
++#define I2C_STATUS (0x010042 + VOYAGER_BASE)
++#define I2C_RESET (0x010042 + VOYAGER_BASE)
++#define I2C_SADDRESS (0x010043 + VOYAGER_BASE)
++#define I2C_DATA (0x010044 + VOYAGER_BASE)
++
++/* ----- Controle register bits ----------------------------------------- */
++#define I2C_CONTROL_E (1 << 0)
++#define I2C_CONTROL_MODE (1 << 1)
++#define I2C_CONTROL_STATUS (1 << 2)
++#define I2C_CONTROL_INT (1 << 4)
++#define I2C_CONTROL_INTACK (1 << 5)
++#define I2C_CONTROL_REPEAT (1 << 6)
++
++/* ----- Status register bits ----------------------------------------- */
++#define I2C_STATUS_BUSY (1 << 0)
++#define I2C_STATUS_ACK (1 << 1)
++#define I2C_STATUS_ERROR (1 << 2)
++#define I2C_STATUS_COMPLETE (1 << 3)
++
++/* ----- Reset register ---------------------------------------------- */
++#define I2C_RESET_ERROR (1 << 2)
++
++/* ----- transmission frequencies ------------------------------------- */
++#define I2C_SADDRESS_SELECT (1 << 0)
++
++/* ----- Display Controll register ----------------------------------------- */
++#define PANEL_DISPLAY_CTRL (0x080000 + VOYAGER_BASE)
++#define PANEL_DISPLAY_CTRL_BIAS (1<<26)
++#define PANEL_PAN_CTRL (0x080004 + VOYAGER_BASE)
++#define PANEL_COLOR_KEY (0x080008 + VOYAGER_BASE)
++#define PANEL_FB_ADDRESS (0x08000C + VOYAGER_BASE)
++#define PANEL_FB_WIDTH (0x080010 + VOYAGER_BASE)
++#define PANEL_WINDOW_WIDTH (0x080014 + VOYAGER_BASE)
++#define PANEL_WINDOW_HEIGHT (0x080018 + VOYAGER_BASE)
++#define PANEL_PLANE_TL (0x08001C + VOYAGER_BASE)
++#define PANEL_PLANE_BR (0x080020 + VOYAGER_BASE)
++#define PANEL_HORIZONTAL_TOTAL (0x080024 + VOYAGER_BASE)
++#define PANEL_HORIZONTAL_SYNC (0x080028 + VOYAGER_BASE)
++#define PANEL_VERTICAL_TOTAL (0x08002C + VOYAGER_BASE)
++#define PANEL_VERTICAL_SYNC (0x080030 + VOYAGER_BASE)
++#define PANEL_CURRENT_LINE (0x080034 + VOYAGER_BASE)
++#define VIDEO_DISPLAY_CTRL (0x080040 + VOYAGER_BASE)
++#define VIDEO_FB_0_ADDRESS (0x080044 + VOYAGER_BASE)
++#define VIDEO_FB_WIDTH (0x080048 + VOYAGER_BASE)
++#define VIDEO_FB_0_LAST_ADDRESS (0x08004C + VOYAGER_BASE)
++#define VIDEO_PLANE_TL (0x080050 + VOYAGER_BASE)
++#define VIDEO_PLANE_BR (0x080054 + VOYAGER_BASE)
++#define VIDEO_SCALE (0x080058 + VOYAGER_BASE)
++#define VIDEO_INITIAL_SCALE (0x08005C + VOYAGER_BASE)
++#define VIDEO_YUV_CONSTANTS (0x080060 + VOYAGER_BASE)
++#define VIDEO_FB_1_ADDRESS (0x080064 + VOYAGER_BASE)
++#define VIDEO_FB_1_LAST_ADDRESS (0x080068 + VOYAGER_BASE)
++#define VIDEO_ALPHA_DISPLAY_CTRL (0x080080 + VOYAGER_BASE)
++#define VIDEO_ALPHA_FB_ADDRESS (0x080084 + VOYAGER_BASE)
++#define VIDEO_ALPHA_FB_WIDTH (0x080088 + VOYAGER_BASE)
++#define VIDEO_ALPHA_FB_LAST_ADDRESS (0x08008C + VOYAGER_BASE)
++#define VIDEO_ALPHA_PLANE_TL (0x080090 + VOYAGER_BASE)
++#define VIDEO_ALPHA_PLANE_BR (0x080094 + VOYAGER_BASE)
++#define VIDEO_ALPHA_SCALE (0x080098 + VOYAGER_BASE)
++#define VIDEO_ALPHA_INITIAL_SCALE (0x08009C + VOYAGER_BASE)
++#define VIDEO_ALPHA_CHROMA_KEY (0x0800A0 + VOYAGER_BASE)
++#define PANEL_HWC_ADDRESS (0x0800F0 + VOYAGER_BASE)
++#define PANEL_HWC_LOCATION (0x0800F4 + VOYAGER_BASE)
++#define PANEL_HWC_COLOR_12 (0x0800F8 + VOYAGER_BASE)
++#define PANEL_HWC_COLOR_3 (0x0800FC + VOYAGER_BASE)
++#define ALPHA_DISPLAY_CTRL (0x080100 + VOYAGER_BASE)
++#define ALPHA_FB_ADDRESS (0x080104 + VOYAGER_BASE)
++#define ALPHA_FB_WIDTH (0x080108 + VOYAGER_BASE)
++#define ALPHA_PLANE_TL (0x08010C + VOYAGER_BASE)
++#define ALPHA_PLANE_BR (0x080110 + VOYAGER_BASE)
++#define ALPHA_CHROMA_KEY (0x080114 + VOYAGER_BASE)
++#define CRT_DISPLAY_CTRL (0x080200 + VOYAGER_BASE)
++#define CRT_FB_ADDRESS (0x080204 + VOYAGER_BASE)
++#define CRT_FB_WIDTH (0x080208 + VOYAGER_BASE)
++#define CRT_HORIZONTAL_TOTAL (0x08020C + VOYAGER_BASE)
++#define CRT_HORIZONTAL_SYNC (0x080210 + VOYAGER_BASE)
++#define CRT_VERTICAL_TOTAL (0x080214 + VOYAGER_BASE)
++#define CRT_VERTICAL_SYNC (0x080218 + VOYAGER_BASE)
++#define CRT_SIGNATURE_ANALYZER (0x08021C + VOYAGER_BASE)
++#define CRT_CURRENT_LINE (0x080220 + VOYAGER_BASE)
++#define CRT_MONITOR_DETECT (0x080224 + VOYAGER_BASE)
++#define CRT_HWC_ADDRESS (0x080230 + VOYAGER_BASE)
++#define CRT_HWC_LOCATION (0x080234 + VOYAGER_BASE)
++#define CRT_HWC_COLOR_12 (0x080238 + VOYAGER_BASE)
++#define CRT_HWC_COLOR_3 (0x08023C + VOYAGER_BASE)
++#define CRT_PALETTE_RAM (0x080400 + VOYAGER_BASE)
++#define PANEL_PALETTE_RAM (0x080800 + VOYAGER_BASE)
++#define VIDEO_PALETTE_RAM (0x080C00 + VOYAGER_BASE)
++
++/* ----- 8051 Controle register ----------------------------------------- */
++#define VOYAGER_8051_BASE (0x000c0000 + VOYAGER_BASE)
++#define VOYAGER_8051_RESET (0x000b0000 + VOYAGER_BASE)
++#define VOYAGER_8051_SELECT (0x000b0004 + VOYAGER_BASE)
++#define VOYAGER_8051_CPU_INT (0x000b000c + VOYAGER_BASE)
++
++/* ----- AC97 Controle register ----------------------------------------- */
++#define AC97_TX_SLOT0 (0x00000000 + VOYAGER_AC97_BASE)
++#define AC97_CONTROL_STATUS (0x00000080 + VOYAGER_AC97_BASE)
++#define AC97C_READ (1 << 19)
++#define AC97C_WD_BIT (1 << 2)
++#define AC97C_INDEX_MASK 0x7f
++/* -------------------------------------------------------------------- */
++
++#endif /* _VOYAGER_GX_REG_H */
+diff --git a/include/asm-sh/watchdog.h b/include/asm-sh/watchdog.h
+index 09ca419..d19ea62 100644
+--- a/include/asm-sh/watchdog.h
++++ b/include/asm-sh/watchdog.h
+@@ -62,7 +62,6 @@
+
+ /**
+ * sh_wdt_read_cnt - Read from Counter
+- *
+ * Reads back the WTCNT value.
+ */
+ static inline __u8 sh_wdt_read_cnt(void)
+@@ -72,7 +71,6 @@ static inline __u8 sh_wdt_read_cnt(void)
+
+ /**
+ * sh_wdt_write_cnt - Write to Counter
+- *
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+@@ -95,7 +93,6 @@ static inline __u8 sh_wdt_read_csr(void)
+
+ /**
+ * sh_wdt_write_csr - Write to Control/Status Register
+- *
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the control/status
+diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h
+index 252fedb..14d8e7b 100644
+--- a/include/asm-sh64/io.h
++++ b/include/asm-sh64/io.h
+@@ -178,22 +178,6 @@ extern void iounmap(void *addr);
+ unsigned long onchip_remap(unsigned long addr, unsigned long size, const char* name);
+ extern void onchip_unmap(unsigned long vaddr);
+
+-static __inline__ int check_signature(volatile void __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ /*
+ * The caches on some architectures aren't dma-coherent and have need to
+ * handle this in software. There are three types of operations that
+diff --git a/include/asm-sh64/keyboard.h b/include/asm-sh64/keyboard.h
+index 1fab96d..0b01c3b 100644
+--- a/include/asm-sh64/keyboard.h
++++ b/include/asm-sh64/keyboard.h
+@@ -30,7 +30,6 @@ extern int pckbd_translate(unsigned char
+ extern char pckbd_unexpected_up(unsigned char keycode);
+ extern void pckbd_leds(unsigned char leds);
+ extern void pckbd_init_hw(void);
+-extern unsigned char pckbd_sysrq_xlate[128];
+
+ #define kbd_setkeycode pckbd_setkeycode
+ #define kbd_getkeycode pckbd_getkeycode
+@@ -38,9 +37,6 @@ extern unsigned char pckbd_sysrq_xlate[1
+ #define kbd_unexpected_up pckbd_unexpected_up
+ #define kbd_leds pckbd_leds
+ #define kbd_init_hw pckbd_init_hw
+-#define kbd_sysrq_xlate pckbd_sysrq_xlate
+-
+-#define SYSRQ_KEY 0x54
+
+ /* resource allocation */
+ #define kbd_request_region()
+diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h
+index 34fb347..472089a 100644
+--- a/include/asm-sh64/page.h
++++ b/include/asm-sh64/page.h
+@@ -112,9 +112,8 @@ typedef struct { unsigned long pgprot; }
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++#endif /* __KERNEL__ */
+ #endif /* __ASM_SH64_PAGE_H */
+diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
+index 54c7821..6b97c4c 100644
+--- a/include/asm-sh64/pgtable.h
++++ b/include/asm-sh64/pgtable.h
+@@ -190,7 +190,9 @@ static inline int pgd_bad(pgd_t pgd) {
+ #endif
+
+
+-#define pgd_page(pgd_entry) ((unsigned long) (pgd_val(pgd_entry) & PAGE_MASK))
++#define pgd_page_vaddr(pgd_entry) ((unsigned long) (pgd_val(pgd_entry) & PAGE_MASK))
++#define pgd_page(pgd) (virt_to_page(pgd_val(pgd)))
++
+
+ /*
+ * PMD defines. Middle level.
+@@ -219,7 +221,7 @@ static inline pmd_t * pmd_offset(pgd_t *
+ #define pmd_none(pmd_entry) (pmd_val((pmd_entry)) == _PMD_EMPTY)
+ #define pmd_bad(pmd_entry) ((pmd_val(pmd_entry) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+
+-#define pmd_page_kernel(pmd_entry) \
++#define pmd_page_vaddr(pmd_entry) \
+ ((unsigned long) __va(pmd_val(pmd_entry) & PAGE_MASK))
+
+ #define pmd_page(pmd) \
+diff --git a/include/asm-sh64/serial.h b/include/asm-sh64/serial.h
+index 29c9be1..e8d7b3f 100644
+--- a/include/asm-sh64/serial.h
++++ b/include/asm-sh64/serial.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-sh/serial.h
++ * include/asm-sh64/serial.h
+ *
+ * Configuration details for 8250, 16450, 16550, etc. serial ports
+ */
+diff --git a/include/asm-sh64/shmparam.h b/include/asm-sh64/shmparam.h
+index d3a99a4..1bb820c 100644
+--- a/include/asm-sh64/shmparam.h
++++ b/include/asm-sh64/shmparam.h
+@@ -2,19 +2,11 @@
+ #define __ASM_SH64_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.
+- *
+- * include/asm-sh64/shmparam.h
+- *
+- * Copyright (C) 2000, 2001 Paolo Alberelli
+- *
++ * Set this to a sensible safe default, we'll work out the specifics for the
++ * align mask from the cache descriptor at run-time.
+ */
++#define SHMLBA 0x4000
+
+-#include <asm/cache.h>
+-
+-/* attach addr a multiple of this */
+-#define SHMLBA (cpu_data->dcache.sets * L1_CACHE_BYTES)
++#define __ARCH_FORCE_SHMLBA
+
+ #endif /* __ASM_SH64_SHMPARAM_H */
+diff --git a/include/asm-sh64/signal.h b/include/asm-sh64/signal.h
+index a5a2820..244e134 100644
+--- a/include/asm-sh64/signal.h
++++ b/include/asm-sh64/signal.h
+@@ -13,7 +13,6 @@
+ */
+
+ #include <linux/types.h>
+-#include <asm/processor.h>
+
+ /* Avoid too many header ordering problems. */
+ struct siginfo;
+diff --git a/include/asm-sh64/timex.h b/include/asm-sh64/timex.h
+index af0b792..163e2b6 100644
+--- a/include/asm-sh64/timex.h
++++ b/include/asm-sh64/timex.h
+@@ -17,9 +17,6 @@
+
+ #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 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)
+
+ typedef unsigned long cycles_t;
+
+diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h
+index 9a1590f..ee7828b 100644
+--- a/include/asm-sh64/unistd.h
++++ b/include/asm-sh64/unistd.h
+@@ -347,8 +347,10 @@
+ #ifdef __KERNEL__
+
+ #define NR_syscalls 321
++#include <linux/err.h>
+
+-/* user-visible error numbers are in the range -1 - -125: see <asm-sh64/errno.h> */
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO:
++ * see <asm-sh64/errno.h> */
+
+ #define __syscall_return(type, res) \
+ do { \
+@@ -358,7 +360,7 @@ do { \
+ ** life easier in the system call epilogue (see entry.S) \
+ */ \
+ register unsigned long __sr2 __asm__ ("r2") = res; \
+- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ errno = -(res); \
+ __sr2 = -1; \
+ } \
+@@ -511,47 +513,6 @@ __syscall_return(type,__sc0);
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-/* Copy from sh */
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-#include <asm/ptrace.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static inline _syscall0(int,pause)
+-static inline _syscall1(int,setup,int,magic)
+-static inline _syscall0(int,sync)
+-static inline _syscall0(pid_t,setsid)
+-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static inline _syscall1(int,dup,int,fd)
+-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+-static inline _syscall1(int,close,int,fd)
+-static inline _syscall1(int,_exit,int,exitcode)
+-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-static inline _syscall1(int,delete_module,const char *,name)
+-
+-static inline pid_t wait(int * wait_stat)
+-{
+- return waitpid(-1,wait_stat,0);
+-}
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-sh64/user.h b/include/asm-sh64/user.h
+index 8f32f39..eb3b33e 100644
+--- a/include/asm-sh64/user.h
++++ b/include/asm-sh64/user.h
+@@ -13,7 +13,6 @@
+ */
+
+ #include <linux/types.h>
+-#include <asm/processor.h>
+ #include <asm/ptrace.h>
+ #include <asm/page.h>
+
+diff --git a/include/asm-sparc/Kbuild b/include/asm-sparc/Kbuild
+index e2a57fd..c6a55cf 100644
+--- a/include/asm-sparc/Kbuild
++++ b/include/asm-sparc/Kbuild
+@@ -1,6 +1,15 @@
+ include include/asm-generic/Kbuild.asm
+
+-unifdef-y += fbio.h perfctr.h psr.h
+-header-y += apc.h asi.h auxio.h bpp.h head.h ipc.h jsflash.h \
+- openpromio.h pbm.h pconf.h pgtsun4.h reg.h traps.h \
+- turbosparc.h vfc_ioctls.h winmacro.h
++header-y += apc.h
++header-y += asi.h
++header-y += bpp.h
++header-y += jsflash.h
++header-y += openpromio.h
++header-y += pconf.h
++header-y += reg.h
++header-y += traps.h
++header-y += vfc_ioctls.h
++
++unifdef-y += fbio.h
++unifdef-y += perfctr.h
++unifdef-y += psr.h
+diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h
+index 83a3dd1..aaf6ef4 100644
+--- a/include/asm-sparc/elf.h
++++ b/include/asm-sparc/elf.h
+@@ -8,11 +8,6 @@
+
+ #include <asm/ptrace.h>
+
+-#ifdef __KERNEL__
+-#include <asm/mbus.h>
+-#include <asm/uaccess.h>
+-#endif
+-
+ /*
+ * Sparc section types
+ */
+@@ -77,6 +72,23 @@ typedef unsigned long elf_greg_t;
+ #define ELF_NGREG 38
+ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
++typedef struct {
++ union {
++ unsigned long pr_regs[32];
++ double pr_dregs[16];
++ } pr_fr;
++ unsigned long __unused;
++ unsigned long pr_fsr;
++ unsigned char pr_qcnt;
++ unsigned char pr_q_entrysize;
++ unsigned char pr_en;
++ unsigned int pr_q[64];
++} elf_fpregset_t;
++
++#ifdef __KERNEL__
++#include <asm/mbus.h>
++#include <asm/uaccess.h>
++
+ /* Format is:
+ * G0 --> G7
+ * O0 --> O7
+@@ -99,20 +111,7 @@ do { unsigned long *dest = &(__elf_regs[
+ dest[34] = src->npc; \
+ dest[35] = src->y; \
+ dest[36] = dest[37] = 0; /* XXX */ \
+-} while(0); /* Janitors: Don't touch this colon. */
+-
+-typedef struct {
+- union {
+- unsigned long pr_regs[32];
+- double pr_dregs[16];
+- } pr_fr;
+- unsigned long __unused;
+- unsigned long pr_fsr;
+- unsigned char pr_qcnt;
+- unsigned char pr_q_entrysize;
+- unsigned char pr_en;
+- unsigned int pr_q[64];
+-} elf_fpregset_t;
++} while(0); /* Janitors: Don't touch this semicolon. */
+
+ #define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \
+ ({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; })
+@@ -165,8 +164,8 @@ typedef struct {
+
+ #define ELF_PLATFORM (NULL)
+
+-#ifdef __KERNEL__
+ #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+-#endif
++
++#endif /* __KERNEL__ */
+
+ #endif /* !(__ASMSPARC_ELF_H) */
+diff --git a/include/asm-sparc/floppy.h b/include/asm-sparc/floppy.h
+index c53b332..9073c84 100644
+--- a/include/asm-sparc/floppy.h
++++ b/include/asm-sparc/floppy.h
+@@ -262,7 +262,7 @@ static __inline__ void sun_fd_enable_dma
+ }
+
+ /* Our low-level entry point in arch/sparc/kernel/entry.S */
+-irqreturn_t floppy_hardint(int irq, void *unused, struct pt_regs *regs);
++irqreturn_t floppy_hardint(int irq, void *unused);
+
+ static int sun_fd_request_irq(void)
+ {
+diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
+index 3141ddf..ff520ea 100644
+--- a/include/asm-sparc/irq.h
++++ b/include/asm-sparc/irq.h
+@@ -76,8 +76,8 @@ static inline void load_profile_irq(int
+ BTFIXUP_CALL(load_profile_irq)(cpu, limit);
+ }
+
+-extern void (*sparc_init_timers)(irqreturn_t (*lvl10_irq)(int, void *, struct pt_regs *));
+-extern void claim_ticker14(irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
++extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
++extern void claim_ticker14(irq_handler_t irq_handler,
+ int irq,
+ unsigned int timeout);
+
+@@ -91,7 +91,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
+ #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
+ #endif
+
+-extern int request_fast_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, __const__ char *devname);
++extern int request_fast_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, __const__ char *devname);
+
+ /* On the sun4m, just like the timers, we have both per-cpu and master
+ * interrupt registers.
+diff --git a/include/asm-sparc/irq_regs.h b/include/asm-sparc/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-sparc/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h
+index 5bab8a7..ff57648 100644
+--- a/include/asm-sparc/page.h
++++ b/include/asm-sparc/page.h
+@@ -8,6 +8,8 @@
+ #ifndef _SPARC_PAGE_H
+ #define _SPARC_PAGE_H
+
++#ifdef __KERNEL__
++
+ #ifdef CONFIG_SUN4
+ #define PAGE_SHIFT 13
+ #else
+@@ -21,8 +23,6 @@
+ #endif
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+
+-#ifdef __KERNEL__
+-
+ #include <asm/btfixup.h>
+
+ #ifndef __ASSEMBLY__
+@@ -160,9 +160,9 @@ extern unsigned long pfn_base;
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+-#endif /* __KERNEL__ */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++#endif /* __KERNEL__ */
++
+ #endif /* _SPARC_PAGE_H */
+diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
+index 226c647..4f0a5ba 100644
+--- a/include/asm-sparc/pgtable.h
++++ b/include/asm-sparc/pgtable.h
+@@ -143,10 +143,10 @@ extern unsigned long empty_zero_page;
+ /*
+ */
+ BTFIXUPDEF_CALL_CONST(struct page *, pmd_page, pmd_t)
+-BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page, pgd_t)
++BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page_vaddr, pgd_t)
+
+ #define pmd_page(pmd) BTFIXUP_CALL(pmd_page)(pmd)
+-#define pgd_page(pgd) BTFIXUP_CALL(pgd_page)(pgd)
++#define pgd_page_vaddr(pgd) BTFIXUP_CALL(pgd_page_vaddr)(pgd)
+
+ BTFIXUPDEF_SETHI(none_mask)
+ BTFIXUPDEF_CALL_CONST(int, pte_present, pte_t)
+diff --git a/include/asm-sparc/reg.h b/include/asm-sparc/reg.h
+index ed60ebe..ea0a7e5 100644
+--- a/include/asm-sparc/reg.h
++++ b/include/asm-sparc/reg.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/asm-sparc/reg.h
++ * linux/include/asm-sparc/reg.h
+ * Layout of the registers as expected by gdb on the Sparc
+ * we should replace the user.h definitions with those in
+ * this file, we don't even use the other
+diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h
+index 1c75474..de2249b 100644
+--- a/include/asm-sparc/spinlock.h
++++ b/include/asm-sparc/spinlock.h
+@@ -129,6 +129,7 @@ static inline void __raw_write_lock(raw_
+ : /* no outputs */
+ : "r" (lp)
+ : "g2", "g4", "memory", "cc");
++ *(volatile __u32 *)&lp->lock = ~0U;
+ }
+
+ static inline int __raw_write_trylock(raw_rwlock_t *rw)
+@@ -144,15 +145,44 @@ static inline int __raw_write_trylock(ra
+ val = rw->lock & ~0xff;
+ if (val)
+ ((volatile u8*)&rw->lock)[3] = 0;
++ else
++ *(volatile u32*)&rw->lock = ~0U;
+ }
+
+ return (val == 0);
+ }
+
++static inline int __read_trylock(raw_rwlock_t *rw)
++{
++ register raw_rwlock_t *lp asm("g1");
++ register int res asm("o0");
++ lp = rw;
++ __asm__ __volatile__(
++ "mov %%o7, %%g4\n\t"
++ "call ___rw_read_try\n\t"
++ " ldstub [%%g1 + 3], %%g2\n"
++ : "=r" (res)
++ : "r" (lp)
++ : "g2", "g4", "memory", "cc");
++ return res;
++}
++
++#define __raw_read_trylock(lock) \
++({ unsigned long flags; \
++ int res; \
++ local_irq_save(flags); \
++ res = __read_trylock(lock); \
++ local_irq_restore(flags); \
++ res; \
++})
++
+ #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0)
+
+ #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
++
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
+
+ #define __raw_read_can_lock(rw) (!((rw)->lock & 0xff))
+ #define __raw_write_can_lock(rw) (!(rw)->lock)
+diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
+index 2553762..f7827fa 100644
+--- a/include/asm-sparc/unistd.h
++++ b/include/asm-sparc/unistd.h
+@@ -318,12 +318,15 @@
+ #define __NR_unshare 299
+ #define __NR_set_robust_list 300
+ #define __NR_get_robust_list 301
++#define __NR_migrate_pages 302
++
++#define NR_SYSCALLS 303
+
+ #ifdef __KERNEL__
+-/* WARNING: You MAY NOT add syscall numbers larger than 301, since
++/* WARNING: You MAY NOT add syscall numbers larger than 302, since
+ * all of the syscall tables in the Sparc kernel are
+- * sized to have 301 entries (starting at zero). Therefore
+- * find a free slot in the 0-301 range.
++ * sized to have 302 entries (starting at zero). Therefore
++ * find a free slot in the 0-302 range.
+ */
+
+ #define _syscall0(type,name) \
+@@ -478,53 +481,6 @@ return -1; \
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static __inline__ _syscall0(pid_t,setsid)
+-static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
+-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static __inline__ _syscall1(int,dup,int,fd)
+-static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp)
+-static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode)
+-static __inline__ _syscall1(int,close,int,fd)
+-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-
+-#include <linux/linkage.h>
+-
+-asmlinkage unsigned long sys_mmap(
+- unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long off);
+-asmlinkage unsigned long sys_mmap2(
+- unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- void __user *restorer,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/asm-sparc64/Kbuild b/include/asm-sparc64/Kbuild
+index 9284c3c..a7f4440 100644
+--- a/include/asm-sparc64/Kbuild
++++ b/include/asm-sparc64/Kbuild
+@@ -4,7 +4,23 @@ ALTARCH := sparc
+ ARCHDEF := defined __sparc__ && defined __arch64__
+ ALTARCHDEF := defined __sparc__ && !defined __arch64__
+
+-unifdef-y += fbio.h perfctr.h
+-header-y += apb.h asi.h bbc.h bpp.h display7seg.h envctrl.h floppy.h \
+- ipc.h kdebug.h mostek.h openprom.h openpromio.h parport.h \
+- pconf.h psrcompat.h pstate.h reg.h uctx.h utrap.h watchdog.h
++header-y += apb.h
++header-y += asi.h
++header-y += bbc.h
++header-y += bpp.h
++header-y += const.h
++header-y += display7seg.h
++header-y += envctrl.h
++header-y += ipc.h
++header-y += openprom.h
++header-y += openpromio.h
++header-y += pconf.h
++header-y += psrcompat.h
++header-y += pstate.h
++header-y += reg.h
++header-y += uctx.h
++header-y += utrap.h
++header-y += watchdog.h
++
++unifdef-y += fbio.h
++unifdef-y += perfctr.h
+diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h
+index c73935d..36511ca 100644
+--- a/include/asm-sparc64/compat.h
++++ b/include/asm-sparc64/compat.h
+@@ -164,7 +164,7 @@ static inline compat_uptr_t ptr_to_compa
+ return (u32)(unsigned long)uptr;
+ }
+
+-static __inline__ void __user *compat_alloc_user_space(long len)
++static inline void __user *compat_alloc_user_space(long len)
+ {
+ struct pt_regs *regs = current_thread_info()->kregs;
+ unsigned long usp = regs->u_regs[UREG_I6];
+@@ -174,7 +174,10 @@ static __inline__ void __user *compat_al
+ else
+ usp &= 0xffffffffUL;
+
+- return (void __user *) (usp - len);
++ usp -= len;
++ usp &= ~0x7UL;
++
++ return (void __user *) usp;
+ }
+
+ struct compat_ipc64_perm {
+diff --git a/include/asm-sparc64/compat_signal.h b/include/asm-sparc64/compat_signal.h
+new file mode 100644
+index 0000000..b759eab
+--- /dev/null
++++ b/include/asm-sparc64/compat_signal.h
+@@ -0,0 +1,29 @@
++#ifndef _COMPAT_SIGNAL_H
++#define _COMPAT_SIGNAL_H
++
++#include <linux/compat.h>
++#include <asm/signal.h>
++
++#ifdef CONFIG_COMPAT
++struct __new_sigaction32 {
++ unsigned sa_handler;
++ unsigned int sa_flags;
++ unsigned sa_restorer; /* not used by Linux/SPARC yet */
++ compat_sigset_t sa_mask;
++};
++
++struct __old_sigaction32 {
++ unsigned sa_handler;
++ compat_old_sigset_t sa_mask;
++ unsigned int sa_flags;
++ unsigned sa_restorer; /* not used by Linux/SPARC yet */
++};
++
++typedef struct sigaltstack32 {
++ u32 ss_sp;
++ int ss_flags;
++ compat_size_t ss_size;
++} stack_t32;
++#endif
++
++#endif /* !(_COMPAT_SIGNAL_H) */
+diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
+index abf1500..dbe033e 100644
+--- a/include/asm-sparc64/floppy.h
++++ b/include/asm-sparc64/floppy.h
+@@ -208,7 +208,7 @@ static void sun_fd_enable_dma(void)
+ pdma_areasize = pdma_size;
+ }
+
+-irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
++irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie)
+ {
+ if (likely(doing_pdma)) {
+ void __iomem *stat = (void __iomem *) fdc_status;
+@@ -255,7 +255,7 @@ irqreturn_t sparc_floppy_irq(int irq, vo
+ }
+
+ main_interrupt:
+- return floppy_interrupt(irq, dev_cookie, regs);
++ return floppy_interrupt(irq, dev_cookie);
+ }
+
+ static int sun_fd_request_irq(void)
+@@ -311,7 +311,7 @@ struct sun_pci_dma_op {
+ static struct sun_pci_dma_op sun_pci_dma_current = { -1U, 0, 0, NULL};
+ static struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL};
+
+-extern irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t floppy_interrupt(int irq, void *dev_id);
+
+ static unsigned char sun_pci_fd_inb(unsigned long port)
+ {
+@@ -446,7 +446,7 @@ static int sun_pci_fd_eject(int drive)
+
+ void sun_pci_fd_dma_callback(struct ebus_dma_info *p, int event, void *cookie)
+ {
+- floppy_interrupt(0, NULL, NULL);
++ floppy_interrupt(0, NULL);
+ }
+
+ /*
+diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h
+index dee4020..7392fc4 100644
+--- a/include/asm-sparc64/futex.h
++++ b/include/asm-sparc64/futex.h
+@@ -87,24 +87,22 @@ static inline int
+ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+ {
+ __asm__ __volatile__(
+- "\n1: lduwa [%2] %%asi, %0\n"
+- "2: casa [%2] %%asi, %0, %1\n"
+- "3:\n"
++ "\n1: casa [%3] %%asi, %2, %0\n"
++ "2:\n"
+ " .section .fixup,#alloc,#execinstr\n"
+ " .align 4\n"
+- "4: ba 3b\n"
+- " mov %3, %0\n"
++ "3: ba 2b\n"
++ " mov %4, %0\n"
+ " .previous\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+- " .word 1b, 4b\n"
+- " .word 2b, 4b\n"
++ " .word 1b, 3b\n"
+ " .previous\n"
+- : "=&r" (oldval)
+- : "r" (newval), "r" (uaddr), "i" (-EFAULT)
++ : "=r" (newval)
++ : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
+ : "memory");
+
+- return oldval;
++ return newval;
+ }
+
+ #endif /* !(_SPARC64_FUTEX_H) */
+diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
+index 0056770..30b912d 100644
+--- a/include/asm-sparc64/io.h
++++ b/include/asm-sparc64/io.h
+@@ -440,21 +440,6 @@ _memcpy_toio(volatile void __iomem *dst,
+
+ #define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz)
+
+-static inline int check_signature(void __iomem *io_addr,
+- const unsigned char *signature,
+- int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature++)
+- goto out;
+- io_addr++;
+- } while (--length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ #define mmiowb()
+
+ #ifdef __KERNEL__
+diff --git a/include/asm-sparc64/irq_regs.h b/include/asm-sparc64/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-sparc64/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
+index fdf0ceb..ff736ea 100644
+--- a/include/asm-sparc64/page.h
++++ b/include/asm-sparc64/page.h
+@@ -3,6 +3,8 @@
+ #ifndef _SPARC64_PAGE_H
+ #define _SPARC64_PAGE_H
+
++#ifdef __KERNEL__
++
+ #include <asm/const.h>
+
+ #if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
+@@ -27,8 +29,6 @@
+ #define DCACHE_ALIASING_POSSIBLE
+ #endif
+
+-#ifdef __KERNEL__
+-
+ #if defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
+ #define HPAGE_SHIFT 22
+ #elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+@@ -141,8 +141,7 @@ typedef unsigned long pgprot_t;
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+-#endif /* !(__KERNEL__) */
+-
+ #include <asm-generic/page.h>
+
+-#endif /* !(_SPARC64_PAGE_H) */
++#endif /* __KERNEL__ */
++#endif /* _SPARC64_PAGE_H */
+diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
+index ebfe395..b12be7a 100644
+--- a/include/asm-sparc64/pgtable.h
++++ b/include/asm-sparc64/pgtable.h
+@@ -630,8 +630,9 @@ static inline unsigned long pte_present(
+ #define __pmd_page(pmd) \
+ ((unsigned long) __va((((unsigned long)pmd_val(pmd))<<11UL)))
+ #define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd))
+-#define pud_page(pud) \
++#define pud_page_vaddr(pud) \
+ ((unsigned long) __va((((unsigned long)pud_val(pud))<<11UL)))
++#define pud_page(pud) virt_to_page((void *)pud_page_vaddr(pud))
+ #define pmd_none(pmd) (!pmd_val(pmd))
+ #define pmd_bad(pmd) (0)
+ #define pmd_present(pmd) (pmd_val(pmd) != 0U)
+@@ -653,7 +654,7 @@ static inline unsigned long pte_present(
+
+ /* Find an entry in the second-level page table.. */
+ #define pmd_offset(pudp, address) \
+- ((pmd_t *) pud_page(*(pudp)) + \
++ ((pmd_t *) pud_page_vaddr(*(pudp)) + \
+ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)))
+
+ /* Find an entry in the third-level page table.. */
+diff --git a/include/asm-sparc64/shmparam.h b/include/asm-sparc64/shmparam.h
+index 8c66fde..911d042 100644
+--- a/include/asm-sparc64/shmparam.h
++++ b/include/asm-sparc64/shmparam.h
+@@ -1,6 +1,7 @@
+ /* $Id: shmparam.h,v 1.5 2001/09/24 21:17:57 kanoj Exp $ */
+ #ifndef _ASMSPARC64_SHMPARAM_H
+ #define _ASMSPARC64_SHMPARAM_H
++#ifdef __KERNEL__
+
+ #include <asm/spitfire.h>
+
+@@ -8,4 +9,5 @@
+ /* attach addr a multiple of this */
+ #define SHMLBA ((PAGE_SIZE > L1DCACHE_SIZE) ? PAGE_SIZE : L1DCACHE_SIZE)
+
++#endif /* __KERNEL__ */
+ #endif /* _ASMSPARC64_SHMPARAM_H */
+diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h
+index 9968871..fa6f467 100644
+--- a/include/asm-sparc64/signal.h
++++ b/include/asm-sparc64/signal.h
+@@ -8,7 +8,6 @@
+ #ifndef __ASSEMBLY__
+ #include <linux/personality.h>
+ #include <linux/types.h>
+-#include <linux/compat.h>
+ #endif
+ #endif
+
+@@ -167,23 +166,6 @@ struct __new_sigaction {
+ __new_sigset_t sa_mask;
+ };
+
+-#ifdef __KERNEL__
+-
+-#ifdef CONFIG_COMPAT
+-struct __new_sigaction32 {
+- unsigned sa_handler;
+- unsigned int sa_flags;
+- unsigned sa_restorer; /* not used by Linux/SPARC yet */
+- compat_sigset_t sa_mask;
+-};
+-#endif
+-
+-struct k_sigaction {
+- struct __new_sigaction sa;
+- void __user *ka_restorer;
+-};
+-#endif
+-
+ struct __old_sigaction {
+ __sighandler_t sa_handler;
+ __old_sigset_t sa_mask;
+@@ -191,19 +173,6 @@ struct __old_sigaction {
+ void (*sa_restorer)(void); /* not used by Linux/SPARC yet */
+ };
+
+-#ifdef __KERNEL__
+-
+-#ifdef CONFIG_COMPAT
+-struct __old_sigaction32 {
+- unsigned sa_handler;
+- compat_old_sigset_t sa_mask;
+- unsigned int sa_flags;
+- unsigned sa_restorer; /* not used by Linux/SPARC yet */
+-};
+-#endif
+-
+-#endif
+-
+ typedef struct sigaltstack {
+ void __user *ss_sp;
+ int ss_flags;
+@@ -212,13 +181,10 @@ typedef struct sigaltstack {
+
+ #ifdef __KERNEL__
+
+-#ifdef CONFIG_COMPAT
+-typedef struct sigaltstack32 {
+- u32 ss_sp;
+- int ss_flags;
+- compat_size_t ss_size;
+-} stack_t32;
+-#endif
++struct k_sigaction {
++ struct __new_sigaction sa;
++ void __user *ka_restorer;
++};
+
+ struct signal_deliver_cookie {
+ int restart_syscall;
+diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
+index bd5ffc7..0006fe9 100644
+--- a/include/asm-sparc64/spinlock.h
++++ b/include/asm-sparc64/spinlock.h
+@@ -241,6 +241,10 @@ static int inline __write_trylock(raw_rw
+ #define __raw_read_can_lock(rw) (!((rw)->lock & 0x80000000UL))
+ #define __raw_write_can_lock(rw) (!(rw)->lock)
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* !(__ASSEMBLY__) */
+
+ #endif /* !(__SPARC64_SPINLOCK_H) */
+diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
+index badc73f..63669da 100644
+--- a/include/asm-sparc64/unistd.h
++++ b/include/asm-sparc64/unistd.h
+@@ -320,12 +320,16 @@
+ #define __NR_unshare 299
+ #define __NR_set_robust_list 300
+ #define __NR_get_robust_list 301
++#define __NR_migrate_pages 302
++
++#define NR_SYSCALLS 303
+
+ #ifdef __KERNEL__
+-/* WARNING: You MAY NOT add syscall numbers larger than 301, since
++
++/* WARNING: You MAY NOT add syscall numbers larger than 302, since
+ * all of the syscall tables in the Sparc kernel are
+- * sized to have 301 entries (starting at zero). Therefore
+- * find a free slot in the 0-301 range.
++ * sized to have 302 entries (starting at zero). Therefore
++ * find a free slot in the 0-302 range.
+ */
+
+ #define _syscall0(type,name) \
+@@ -445,48 +449,6 @@ if (__res>=0) \
+ errno = -__res; \
+ return -1; \
+ }
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-static __inline__ _syscall0(pid_t,setsid)
+-static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
+-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-static __inline__ _syscall1(int,dup,int,fd)
+-static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp)
+-static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode)
+-static __inline__ _syscall1(int,close,int,fd)
+-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-
+-#include <linux/linkage.h>
+-
+-asmlinkage unsigned long sys_mmap(
+- unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long off);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- void __user *restorer,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+
+ /* sysconf options, for SunOS compatibility */
+ #define _SC_ARG_MAX 1
+diff --git a/include/asm-um/Kbuild b/include/asm-um/Kbuild
+deleted file mode 100644
+index c68e168..0000000
+--- a/include/asm-um/Kbuild
++++ /dev/null
+@@ -1 +0,0 @@
+-include include/asm-generic/Kbuild.asm
+diff --git a/include/asm-um/alternative-asm.i b/include/asm-um/alternative-asm.i
+new file mode 100644
+index 0000000..cae9fac
+--- /dev/null
++++ b/include/asm-um/alternative-asm.i
+@@ -0,0 +1,6 @@
++#ifndef __UM_ALTERNATIVE_ASM_I
++#define __UM_ALTERNATIVE_ASM_I
++
++#include "asm/arch/alternative-asm.i"
++
++#endif
+diff --git a/include/asm-um/archparam-ppc.h b/include/asm-um/archparam-ppc.h
+index 172cd6f..4269d8a 100644
+--- a/include/asm-um/archparam-ppc.h
++++ b/include/asm-um/archparam-ppc.h
+@@ -1,15 +1,6 @@
+ #ifndef __UM_ARCHPARAM_PPC_H
+ #define __UM_ARCHPARAM_PPC_H
+
+-/********* Bits for asm-um/hw_irq.h **********/
+-
+-struct hw_interrupt_type;
+-
+-/********* Bits for asm-um/hardirq.h **********/
+-
+-#define irq_enter(cpu, irq) hardirq_enter(cpu)
+-#define irq_exit(cpu, irq) hardirq_exit(cpu)
+-
+ /********* Bits for asm-um/string.h **********/
+
+ #define __HAVE_ARCH_STRRCHR
+diff --git a/include/asm-um/common.lds.S b/include/asm-um/common.lds.S
+index 1010153..f045451 100644
+--- a/include/asm-um/common.lds.S
++++ b/include/asm-um/common.lds.S
+@@ -42,13 +42,7 @@
+
+ __initcall_start = .;
+ .initcall.init : {
+- *(.initcall1.init)
+- *(.initcall2.init)
+- *(.initcall3.init)
+- *(.initcall4.init)
+- *(.initcall5.init)
+- *(.initcall6.init)
+- *(.initcall7.init)
++ INITCALLS
+ }
+ __initcall_end = .;
+
+diff --git a/include/asm-um/frame.i b/include/asm-um/frame.i
+new file mode 100644
+index 0000000..09d5dca
+--- /dev/null
++++ b/include/asm-um/frame.i
+@@ -0,0 +1,6 @@
++#ifndef __UM_FRAME_I
++#define __UM_FRAME_I
++
++#include "asm/arch/frame.i"
++
++#endif
+diff --git a/include/asm-um/irq_regs.h b/include/asm-um/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-um/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-um/pgtable-2level.h b/include/asm-um/pgtable-2level.h
+index ffe017f..6050e0e 100644
+--- a/include/asm-um/pgtable-2level.h
++++ b/include/asm-um/pgtable-2level.h
+@@ -41,7 +41,7 @@ static inline void pgd_mkuptodate(pgd_t
+ #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
+ #define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
+
+-#define pmd_page_kernel(pmd) \
++#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ /*
+diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h
+index 786c257..ca0c2a9 100644
+--- a/include/asm-um/pgtable-3level.h
++++ b/include/asm-um/pgtable-3level.h
+@@ -74,11 +74,12 @@ extern inline void pud_clear (pud_t *pud
+ set_pud(pud, __pud(0));
+ }
+
+-#define pud_page(pud) \
++#define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK)
++#define pud_page_vaddr(pud) \
+ ((struct page *) __va(pud_val(pud) & PAGE_MASK))
+
+ /* Find an entry in the second-level page table.. */
+-#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
++#define pmd_offset(pud, address) ((pmd_t *) pud_page_vaddr(*(pud)) + \
+ pmd_index(address))
+
+ static inline unsigned long pte_pfn(pte_t pte)
+diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
+index ac64eb9..188f726 100644
+--- a/include/asm-um/pgtable.h
++++ b/include/asm-um/pgtable.h
+@@ -274,12 +274,6 @@ static inline pte_t pte_mkread(pte_t pte
+ return(pte_mknewprot(pte));
+ }
+
+-static inline pte_t pte_mkexec(pte_t pte)
+-{
+- pte_set_bits(pte, _PAGE_USER);
+- return(pte_mknewprot(pte));
+-}
+-
+ static inline pte_t pte_mkdirty(pte_t pte)
+ {
+ pte_set_bits(pte, _PAGE_DIRTY);
+@@ -349,7 +343,7 @@ static inline pte_t pte_modify(pte_t pte
+ return pte;
+ }
+
+-#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+ /*
+ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
+@@ -389,7 +383,7 @@ static inline pte_t pte_modify(pte_t pte
+ */
+ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+- ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
+ #define pte_offset_map(dir, address) \
+ ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
+ #define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
+diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
+index 824c288..d99bbdd 100644
+--- a/include/asm-um/processor-generic.h
++++ b/include/asm-um/processor-generic.h
+@@ -13,6 +13,7 @@ struct task_struct;
+ #include "asm/ptrace.h"
+ #include "choose-mode.h"
+ #include "registers.h"
++#include "sysdep/archsetjmp.h"
+
+ struct mm_struct;
+
+@@ -43,8 +44,7 @@ struct thread_struct {
+ #endif
+ #ifdef CONFIG_MODE_SKAS
+ struct {
+- void *switch_buf;
+- void *fork_buf;
++ jmp_buf switch_buf;
+ int mm_count;
+ } skas;
+ #endif
+@@ -138,9 +138,7 @@ extern struct cpuinfo_um cpu_data[];
+
+ #ifdef CONFIG_MODE_SKAS
+ #define KSTK_REG(tsk, reg) \
+- ({ union uml_pt_regs regs; \
+- get_thread_regs(®s, tsk->thread.mode.skas.switch_buf); \
+- UPT_REG(®s, reg); })
++ get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf)
+ #else
+ #define KSTK_REG(tsk, reg) (0xbadbabe)
+ #endif
+diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
+index a36f537..99c87c5 100644
+--- a/include/asm-um/ptrace-generic.h
++++ b/include/asm-um/ptrace-generic.h
+@@ -8,19 +8,7 @@
+
+ #ifndef __ASSEMBLY__
+
+-
+-#define pt_regs pt_regs_subarch
+-#define show_regs show_regs_subarch
+-#define send_sigtrap send_sigtrap_subarch
+-
+-#include "asm/arch/ptrace.h"
+-
+-#undef pt_regs
+-#undef show_regs
+-#undef send_sigtrap
+-#undef user_mode
+-#undef instruction_pointer
+-
++#include "asm/arch/ptrace-abi.h"
+ #include "sysdep/ptrace.h"
+
+ struct pt_regs {
+diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h
+index c894e68..03b4af4 100644
+--- a/include/asm-um/ptrace-x86_64.h
++++ b/include/asm-um/ptrace-x86_64.h
+@@ -11,21 +11,20 @@
+ #include "asm/errno.h"
+ #include "asm/host_ldt.h"
+
+-#define signal_fault signal_fault_x86_64
+ #define __FRAME_OFFSETS /* Needed to get the R* macros */
+ #include "asm/ptrace-generic.h"
+-#undef signal_fault
+
+ #define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
+
+-void signal_fault(struct pt_regs_subarch *regs, void *frame, char *where);
+-
++/* Also defined in sysdep/ptrace.h, so may already be defined. */
++#ifndef FS_BASE
+ #define FS_BASE (21 * sizeof(unsigned long))
+ #define GS_BASE (22 * sizeof(unsigned long))
+ #define DS (23 * sizeof(unsigned long))
+ #define ES (24 * sizeof(unsigned long))
+ #define FS (25 * sizeof(unsigned long))
+ #define GS (26 * sizeof(unsigned long))
++#endif
+
+ #define PT_REGS_RBX(r) UPT_RBX(&(r)->regs)
+ #define PT_REGS_RCX(r) UPT_RCX(&(r)->regs)
+diff --git a/include/asm-um/unistd.h b/include/asm-um/unistd.h
+index afccfca..732c83f 100644
+--- a/include/asm-um/unistd.h
++++ b/include/asm-um/unistd.h
+@@ -37,34 +37,6 @@ extern int um_execve(const char *file, c
+ #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+ #endif
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-
+-static inline int execve(const char *filename, char *const argv[],
+- char *const envp[])
+-{
+- mm_segment_t fs;
+- int ret;
+-
+- fs = get_fs();
+- set_fs(KERNEL_DS);
+- ret = um_execve(filename, argv, envp);
+- set_fs(fs);
+-
+- if (ret >= 0)
+- return ret;
+-
+- errno = -(long)ret;
+- return -1;
+-}
+-
+-int sys_execve(char *file, char **argv, char **env);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+-#undef __KERNEL_SYSCALLS__
+ #include "asm/arch/unistd.h"
+
+ #endif /* _UM_UNISTD_H_*/
+diff --git a/include/asm-v850/page.h b/include/asm-v850/page.h
+index ad03c46..d693ffb 100644
+--- a/include/asm-v850/page.h
++++ b/include/asm-v850/page.h
+@@ -14,6 +14,8 @@
+ #ifndef __V850_PAGE_H__
+ #define __V850_PAGE_H__
+
++#ifdef __KERNEL__
++
+ #include <asm/machdep.h>
+
+
+@@ -32,7 +34,6 @@
+ #endif
+
+
+-#ifdef __KERNEL__
+ #ifndef __ASSEMBLY__
+
+ #define STRICT_MM_TYPECHECKS
+@@ -122,9 +123,9 @@ typedef unsigned long pgprot_t;
+ #define __va(x) ((void *)__phys_to_virt ((unsigned long)(x)))
+
+
+-#endif /* KERNEL */
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/page.h>
+
++#endif /* KERNEL */
++
+ #endif /* __V850_PAGE_H__ */
+diff --git a/include/asm-v850/param.h b/include/asm-v850/param.h
+index 8d796e4..3c65bd5 100644
+--- a/include/asm-v850/param.h
++++ b/include/asm-v850/param.h
+@@ -14,8 +14,6 @@
+ #ifndef __V850_PARAM_H__
+ #define __V850_PARAM_H__
+
+-#include <asm/machdep.h> /* For HZ */
+-
+ #define EXEC_PAGESIZE 4096
+
+ #ifndef NOGROUP
+@@ -25,6 +23,8 @@
+ #define MAXHOSTNAMELEN 64 /* max length of hostname */
+
+ #ifdef __KERNEL__
++#include <asm/machdep.h> /* For HZ */
++
+ # define USER_HZ 100
+ # define CLOCKS_PER_SEC USER_HZ
+ #endif
+diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h
+index bcb44bf..737401e 100644
+--- a/include/asm-v850/unistd.h
++++ b/include/asm-v850/unistd.h
+@@ -238,12 +238,13 @@
+ #ifdef __KERNEL__
+
+ #include <asm/clinkage.h>
++#include <linux/err.h>
+
+ #define __syscall_return(type, res) \
+ do { \
+- /* user-visible error numbers are in the range -1 - -124: \
++ /* user-visible error numbers are in the range -1 - -MAX_ERRNO: \
+ see <asm-v850/errno.h> */ \
+- if (__builtin_expect ((unsigned long)(res) >= (unsigned long)(-125), 0)) { \
++ if (__builtin_expect ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO), 0)) { \
+ errno = -(res); \
+ res = -1; \
+ } \
+@@ -386,57 +387,6 @@ type name (atype a, btype b, ctype c, dt
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+-#ifdef __KERNEL_SYSCALLS__
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-extern inline _syscall0(pid_t,setsid)
+-extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+-extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+-extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+-extern inline _syscall1(int,dup,int,fd)
+-extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+-extern inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+-extern inline _syscall1(int,close,int,fd)
+-extern inline _syscall1(int,_exit,int,exitcode)
+-extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+-
+-extern inline pid_t wait(int * wait_stat)
+-{
+- return waitpid (-1, wait_stat, 0);
+-}
+-
+-unsigned long sys_mmap(unsigned long addr, size_t len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, off_t offset);
+-unsigned long sys_mmap2(unsigned long addr, size_t len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long pgoff);
+-struct pt_regs;
+-int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs);
+-int sys_pipe (int *fildes);
+-struct sigaction;
+-asmlinkage long sys_rt_sigaction(int sig,
+- const struct sigaction __user *act,
+- struct sigaction __user *oact,
+- size_t sigsetsize);
+-
+-#endif /* __KERNEL_SYSCALLS__ */
+-
+ /*
+ * "Conditional" syscalls
+ */
+diff --git a/include/asm-x86_64/Kbuild b/include/asm-x86_64/Kbuild
+index dc4d101..1ee9b07 100644
+--- a/include/asm-x86_64/Kbuild
++++ b/include/asm-x86_64/Kbuild
+@@ -4,8 +4,19 @@ ALTARCH := i386
+ ARCHDEF := defined __x86_64__
+ ALTARCHDEF := defined __i386__
+
+-header-y += boot.h bootsetup.h cpufeature.h debugreg.h ldt.h \
+- msr.h prctl.h setup.h sigcontext32.h ucontext.h \
+- vsyscall32.h
++header-y += boot.h
++header-y += bootsetup.h
++header-y += cpufeature.h
++header-y += debugreg.h
++header-y += ldt.h
++header-y += msr.h
++header-y += prctl.h
++header-y += ptrace-abi.h
++header-y += setup.h
++header-y += sigcontext32.h
++header-y += ucontext.h
++header-y += vsyscall32.h
+
+-unifdef-y += mce.h mtrr.h vsyscall.h
++unifdef-y += mce.h
++unifdef-y += mtrr.h
++unifdef-y += vsyscall.h
+diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
+index 2c95a31..ed59aa4 100644
+--- a/include/asm-x86_64/acpi.h
++++ b/include/asm-x86_64/acpi.h
+@@ -155,8 +155,6 @@ extern void acpi_reserve_bootmem(void);
+
+ #endif /*CONFIG_ACPI_SLEEP*/
+
+-#define boot_cpu_physical_apicid boot_cpu_id
+-
+ extern int acpi_disabled;
+ extern int acpi_pci_disabled;
+
+diff --git a/include/asm-x86_64/alternative-asm.i b/include/asm-x86_64/alternative-asm.i
+new file mode 100644
+index 0000000..0b3f1a2
+--- /dev/null
++++ b/include/asm-x86_64/alternative-asm.i
+@@ -0,0 +1,12 @@
++#ifdef CONFIG_SMP
++ .macro LOCK_PREFIX
++1: lock
++ .section .smp_locks,"a"
++ .align 8
++ .quad 1b
++ .previous
++ .endm
++#else
++ .macro LOCK_PREFIX
++ .endm
++#endif
+diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
+index 9c96a0a..e81d0f2 100644
+--- a/include/asm-x86_64/apic.h
++++ b/include/asm-x86_64/apic.h
+@@ -17,6 +17,8 @@
+
+ extern int apic_verbosity;
+ extern int apic_runs_main_timer;
++extern int ioapic_force;
++extern int apic_mapped;
+
+ /*
+ * Define the default level of output to be very little
+@@ -29,8 +31,6 @@ extern int apic_runs_main_timer;
+ printk(s, ##a); \
+ } while (0)
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+-
+ struct pt_regs;
+
+ /*
+@@ -77,7 +77,7 @@ extern void sync_Arb_IDs (void);
+ extern void init_bsp_APIC (void);
+ extern void setup_local_APIC (void);
+ extern void init_apic_mappings (void);
+-extern void smp_local_timer_interrupt (struct pt_regs * regs);
++extern void smp_local_timer_interrupt (void);
+ extern void setup_boot_APIC_clock (void);
+ extern void setup_secondary_APIC_clock (void);
+ extern int APIC_init_uniprocessor (void);
+@@ -95,17 +95,12 @@ extern void setup_APIC_extened_lvt(unsig
+ #define K8_APIC_EXT_INT_MSG_EXT 0x7
+ #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0
+
+-extern int disable_timer_pin_1;
+-
+-
+ void smp_send_timer_broadcast_ipi(void);
+ void switch_APIC_timer_to_ipi(void *cpumask);
+ void switch_ipi_to_APIC_timer(void *cpumask);
+
+ #define ARCH_APICTIMER_STOPS_ON_C3 1
+
+-#endif /* CONFIG_X86_LOCAL_APIC */
+-
+ extern unsigned boot_cpu_id;
+
+ #endif /* __ASM_APIC_H */
+diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
+index f7ba57b..5b535ea 100644
+--- a/include/asm-x86_64/bitops.h
++++ b/include/asm-x86_64/bitops.h
+@@ -399,6 +399,8 @@ static __inline__ int fls(int x)
+ return r+1;
+ }
+
++#define ARCH_HAS_FAST_MULTIPLIER 1
++
+ #include <asm-generic/bitops/hweight.h>
+
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-x86_64/cache.h b/include/asm-x86_64/cache.h
+index ed8a9d2..052df75 100644
+--- a/include/asm-x86_64/cache.h
++++ b/include/asm-x86_64/cache.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-x8664/cache.h
++ * include/asm-x86_64/cache.h
+ */
+ #ifndef __ARCH_X8664_CACHE_H
+ #define __ARCH_X8664_CACHE_H
+diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86_64/calgary.h
+index 4e39195..6b93f5a 100644
+--- a/include/asm-x86_64/calgary.h
++++ b/include/asm-x86_64/calgary.h
+@@ -24,7 +24,6 @@
+ #ifndef _ASM_X86_64_CALGARY_H
+ #define _ASM_X86_64_CALGARY_H
+
+-#include <linux/config.h>
+ #include <linux/spinlock.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+@@ -34,12 +33,12 @@ struct iommu_table {
+ unsigned long it_base; /* mapped address of tce table */
+ unsigned long it_hint; /* Hint for next alloc */
+ unsigned long *it_map; /* A simple allocation bitmap for now */
++ void __iomem *bbar; /* Bridge BAR */
++ u64 tar_val; /* Table Address Register */
++ struct timer_list watchdog_timer;
+ spinlock_t it_lock; /* Protects it_map */
+ unsigned int it_size; /* Size of iommu table in entries */
+ unsigned char it_busno; /* Bus number this table belongs to */
+- void __iomem *bbar;
+- u64 tar_val;
+- struct timer_list watchdog_timer;
+ };
+
+ #define TCE_TABLE_SIZE_UNSPECIFIED ~0
+diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
+index b6da83d..10174b1 100644
+--- a/include/asm-x86_64/dma-mapping.h
++++ b/include/asm-x86_64/dma-mapping.h
+@@ -55,13 +55,6 @@ extern dma_addr_t bad_dma_address;
+ extern struct dma_mapping_ops* dma_ops;
+ extern int iommu_merge;
+
+-static inline int valid_dma_direction(int dma_direction)
+-{
+- return ((dma_direction == DMA_BIDIRECTIONAL) ||
+- (dma_direction == DMA_TO_DEVICE) ||
+- (dma_direction == DMA_FROM_DEVICE));
+-}
+-
+ static inline int dma_mapping_error(dma_addr_t dma_addr)
+ {
+ if (dma_ops->mapping_error)
+diff --git a/include/asm-x86_64/dwarf2.h b/include/asm-x86_64/dwarf2.h
+index 0744db7..eedc085 100644
+--- a/include/asm-x86_64/dwarf2.h
++++ b/include/asm-x86_64/dwarf2.h
+@@ -13,7 +13,7 @@
+ away for older version.
+ */
+
+-#ifdef CONFIG_UNWIND_INFO
++#ifdef CONFIG_AS_CFI
+
+ #define CFI_STARTPROC .cfi_startproc
+ #define CFI_ENDPROC .cfi_endproc
+@@ -28,6 +28,11 @@
+ #define CFI_REMEMBER_STATE .cfi_remember_state
+ #define CFI_RESTORE_STATE .cfi_restore_state
+ #define CFI_UNDEFINED .cfi_undefined
++#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
++#define CFI_SIGNAL_FRAME .cfi_signal_frame
++#else
++#define CFI_SIGNAL_FRAME
++#endif
+
+ #else
+
+@@ -45,6 +50,7 @@
+ #define CFI_REMEMBER_STATE #
+ #define CFI_RESTORE_STATE #
+ #define CFI_UNDEFINED #
++#define CFI_SIGNAL_FRAME #
+
+ #endif
+
+diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
+index 670a338..fa20867 100644
+--- a/include/asm-x86_64/e820.h
++++ b/include/asm-x86_64/e820.h
+@@ -19,13 +19,9 @@
+
+ #define E820_RAM 1
+ #define E820_RESERVED 2
+-#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
++#define E820_ACPI 3
+ #define E820_NVS 4
+
+-#define HIGH_MEMORY (1024*1024)
+-
+-#define LOWMEMSIZE() (0x9f000)
+-
+ #ifndef __ASSEMBLY__
+ struct e820entry {
+ u64 addr; /* start of memory segment */
+@@ -46,17 +42,16 @@ extern void setup_memory_region(void);
+ extern void contig_e820_setup(void);
+ extern unsigned long e820_end_of_ram(void);
+ extern void e820_reserve_resources(void);
++extern void e820_mark_nosave_regions(void);
+ extern void e820_print_map(char *who);
+ extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
+ extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);
+
+-extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
+ extern void e820_setup_gap(void);
+-extern unsigned long e820_hole_size(unsigned long start_pfn,
+- unsigned long end_pfn);
++extern void e820_register_active_regions(int nid,
++ unsigned long start_pfn, unsigned long end_pfn);
+
+-extern void __init parse_memopt(char *p, char **end);
+-extern void __init parse_memmapopt(char *p, char **end);
++extern void finish_e820_parsing(void);
+
+ extern struct e820map e820;
+
+diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
+index 0b4ffbd..1b620db 100644
+--- a/include/asm-x86_64/fixmap.h
++++ b/include/asm-x86_64/fixmap.h
+@@ -37,13 +37,9 @@ enum fixed_addresses {
+ VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
+ VSYSCALL_HPET,
+ FIX_HPET_BASE,
+-#ifdef CONFIG_X86_LOCAL_APIC
+ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
+-#endif
+-#ifdef CONFIG_X86_IO_APIC
+ FIX_IO_APIC_BASE_0,
+ FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
+-#endif
+ __end_of_fixed_addresses
+ };
+
+diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h
+index 32ff5d1..6ea13c3 100644
+--- a/include/asm-x86_64/floppy.h
++++ b/include/asm-x86_64/floppy.h
+@@ -51,7 +51,7 @@ static char *virtual_dma_addr;
+ static int virtual_dma_mode;
+ static int doing_pdma;
+
+-static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t floppy_hardint(int irq, void *dev_id)
+ {
+ register unsigned char st;
+
+@@ -63,7 +63,7 @@ static irqreturn_t floppy_hardint(int ir
+ static int dma_wait=0;
+ #endif
+ if (!doing_pdma)
+- return floppy_interrupt(irq, dev_id, regs);
++ return floppy_interrupt(irq, dev_id);
+
+ #ifdef TRACE_FLPY_INT
+ if(!calls)
+@@ -106,7 +106,7 @@ static irqreturn_t floppy_hardint(int ir
+ dma_wait=0;
+ #endif
+ doing_pdma = 0;
+- floppy_interrupt(irq, dev_id, regs);
++ floppy_interrupt(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+ #ifdef TRACE_FLPY_INT
+diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86_64/genapic.h
+index 50b38e7..a0e9a4b 100644
+--- a/include/asm-x86_64/genapic.h
++++ b/include/asm-x86_64/genapic.h
+@@ -16,9 +16,9 @@ struct genapic {
+ char *name;
+ u32 int_delivery_mode;
+ u32 int_dest_mode;
+- u32 int_delivery_dest; /* for quick IPIs */
+ int (*apic_id_registered)(void);
+ cpumask_t (*target_cpus)(void);
++ cpumask_t (*vector_allocation_domain)(int cpu);
+ void (*init_apic_ldr)(void);
+ /* ipi */
+ void (*send_IPI_mask)(cpumask_t mask, int vector);
+diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
+index 64a65ce..95d5e09 100644
+--- a/include/asm-x86_64/hardirq.h
++++ b/include/asm-x86_64/hardirq.h
+@@ -6,6 +6,9 @@
+ #include <asm/pda.h>
+ #include <asm/apic.h>
+
++/* We can have at most NR_VECTORS irqs routed to a cpu at a time */
++#define MAX_HARDIRQS_PER_CPU NR_VECTORS
++
+ #define __ARCH_IRQ_STAT 1
+
+ #define local_softirq_pending() read_pda(__softirq_pending)
+diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
+index 48a4a53..179cce7 100644
+--- a/include/asm-x86_64/hw_irq.h
++++ b/include/asm-x86_64/hw_irq.h
+@@ -19,8 +19,7 @@
+ #include <asm/irq.h>
+ #include <linux/profile.h>
+ #include <linux/smp.h>
+-
+-struct hw_interrupt_type;
++#include <linux/percpu.h>
+ #endif
+
+ #define NMI_VECTOR 0x02
+@@ -75,9 +74,10 @@ struct hw_interrupt_type;
+
+
+ #ifndef __ASSEMBLY__
+-extern u8 irq_vector[NR_IRQ_VECTORS];
+-#define IO_APIC_VECTOR(irq) (irq_vector[irq])
+-#define AUTO_ASSIGN -1
++typedef int vector_irq_t[NR_VECTORS];
++DECLARE_PER_CPU(vector_irq_t, vector_irq);
++extern void __setup_vector_irq(int cpu);
++extern spinlock_t vector_lock;
+
+ /*
+ * Various low-level irq details needed by irq.c, process.c,
+diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h
+new file mode 100644
+index 0000000..c16c6ff
+--- /dev/null
++++ b/include/asm-x86_64/hypertransport.h
+@@ -0,0 +1,42 @@
++#ifndef ASM_HYPERTRANSPORT_H
++#define ASM_HYPERTRANSPORT_H
++
++/*
++ * Constants for x86 Hypertransport Interrupts.
++ */
++
++#define HT_IRQ_LOW_BASE 0xf8000000
++
++#define HT_IRQ_LOW_VECTOR_SHIFT 16
++#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
++#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
++
++#define HT_IRQ_LOW_DEST_ID_SHIFT 8
++#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
++#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
++
++#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
++#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
++
++#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
++#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
++
++
++#define HT_IRQ_LOW_MT_FIXED 0x0000000
++#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
++#define HT_IRQ_LOW_MT_SMI 0x0000008
++#define HT_IRQ_LOW_MT_NMI 0x000000c
++#define HT_IRQ_LOW_MT_INIT 0x0000010
++#define HT_IRQ_LOW_MT_STARTUP 0x0000014
++#define HT_IRQ_LOW_MT_EXTINT 0x0000018
++#define HT_IRQ_LOW_MT_LINT1 0x000008c
++#define HT_IRQ_LOW_MT_LINT0 0x0000098
++
++#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
++
++
++#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
++#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
++#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
++
++#endif /* ASM_HYPERTRANSPORT_H */
+diff --git a/include/asm-x86_64/i387.h b/include/asm-x86_64/i387.h
+index cba8a3b..0217b74 100644
+--- a/include/asm-x86_64/i387.h
++++ b/include/asm-x86_64/i387.h
+@@ -24,6 +24,7 @@ extern unsigned int mxcsr_feature_mask;
+ extern void mxcsr_feature_mask_init(void);
+ extern void init_fpu(struct task_struct *child);
+ extern int save_i387(struct _fpstate __user *buf);
++extern asmlinkage void math_state_restore(void);
+
+ /*
+ * FPU lazy state save handling...
+@@ -31,7 +32,9 @@ extern int save_i387(struct _fpstate __u
+
+ #define unlazy_fpu(tsk) do { \
+ if (task_thread_info(tsk)->status & TS_USEDFPU) \
+- save_init_fpu(tsk); \
++ save_init_fpu(tsk); \
++ else \
++ tsk->fpu_counter = 0; \
+ } while (0)
+
+ /* Ignore delayed exceptions from user space */
+@@ -134,8 +137,8 @@ static inline int save_i387_checking(str
+ #else
+ : [fx] "cdaSDb" (fx), "0" (0));
+ #endif
+- if (unlikely(err))
+- __clear_user(fx, sizeof(struct i387_fxsave_struct));
++ if (unlikely(err) && __clear_user(fx, sizeof(struct i387_fxsave_struct)))
++ err = -EFAULT;
+ /* No need to clear here because the caller clears USED_MATH */
+ return err;
+ }
+diff --git a/include/asm-x86_64/intel_arch_perfmon.h b/include/asm-x86_64/intel_arch_perfmon.h
+index 59c3964..8633331 100644
+--- a/include/asm-x86_64/intel_arch_perfmon.h
++++ b/include/asm-x86_64/intel_arch_perfmon.h
+@@ -14,6 +14,18 @@
+
+ #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL (0x3c)
+ #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
+-#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
++#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX (0)
++#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
++ (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
++
++union cpuid10_eax {
++ struct {
++ unsigned int version_id:8;
++ unsigned int num_counters:8;
++ unsigned int bit_width:8;
++ unsigned int mask_length:8;
++ } split;
++ unsigned int full;
++};
+
+ #endif /* X86_64_INTEL_ARCH_PERFMON_H */
+diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
+index 70e91fe..6ee9fad 100644
+--- a/include/asm-x86_64/io.h
++++ b/include/asm-x86_64/io.h
+@@ -254,33 +254,6 @@ void memset_io(volatile void __iomem *a,
+
+ #define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
+
+-/**
+- * check_signature - find BIOS signatures
+- * @io_addr: mmio address to check
+- * @signature: signature block
+- * @length: length of signature
+- *
+- * Perform a signature comparison with the mmio address io_addr. This
+- * address should have been obtained by ioremap.
+- * Returns 1 on a match.
+- */
+-
+-static inline int check_signature(void __iomem *io_addr,
+- const unsigned char *signature, int length)
+-{
+- int retval = 0;
+- do {
+- if (readb(io_addr) != *signature)
+- goto out;
+- io_addr++;
+- signature++;
+- length--;
+- } while (length);
+- retval = 1;
+-out:
+- return retval;
+-}
+-
+ /* Nothing to do */
+
+ #define dma_cache_inv(_start,_size) do { } while (0)
+diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
+index fb7a090..171ec2d 100644
+--- a/include/asm-x86_64/io_apic.h
++++ b/include/asm-x86_64/io_apic.h
+@@ -10,48 +10,6 @@
+ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
+ */
+
+-#ifdef CONFIG_X86_IO_APIC
+-
+-#ifdef CONFIG_PCI_MSI
+-static inline int use_pci_vector(void) {return 1;}
+-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+-static inline void end_edge_ioapic_vector (unsigned int vector) { }
+-#define startup_level_ioapic startup_level_ioapic_vector
+-#define shutdown_level_ioapic mask_IO_APIC_vector
+-#define enable_level_ioapic unmask_IO_APIC_vector
+-#define disable_level_ioapic mask_IO_APIC_vector
+-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
+-#define end_level_ioapic end_level_ioapic_vector
+-#define set_ioapic_affinity set_ioapic_affinity_vector
+-
+-#define startup_edge_ioapic startup_edge_ioapic_vector
+-#define shutdown_edge_ioapic disable_edge_ioapic_vector
+-#define enable_edge_ioapic unmask_IO_APIC_vector
+-#define disable_edge_ioapic disable_edge_ioapic_vector
+-#define ack_edge_ioapic ack_edge_ioapic_vector
+-#define end_edge_ioapic end_edge_ioapic_vector
+-#else
+-static inline int use_pci_vector(void) {return 0;}
+-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
+-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
+-static inline void end_edge_ioapic_irq (unsigned int irq) { }
+-#define startup_level_ioapic startup_level_ioapic_irq
+-#define shutdown_level_ioapic mask_IO_APIC_irq
+-#define enable_level_ioapic unmask_IO_APIC_irq
+-#define disable_level_ioapic mask_IO_APIC_irq
+-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
+-#define end_level_ioapic end_level_ioapic_irq
+-#define set_ioapic_affinity set_ioapic_affinity_irq
+-
+-#define startup_edge_ioapic startup_edge_ioapic_irq
+-#define shutdown_edge_ioapic disable_edge_ioapic_irq
+-#define enable_edge_ioapic unmask_IO_APIC_irq
+-#define disable_edge_ioapic disable_edge_ioapic_irq
+-#define ack_edge_ioapic ack_edge_ioapic_irq
+-#define end_edge_ioapic end_edge_ioapic_irq
+-#endif
+-
+ #define APIC_MISMATCH_DEBUG
+
+ #define IO_APIC_BASE(idx) \
+@@ -204,17 +162,10 @@ extern int skip_ioapic_setup;
+ extern int io_apic_get_version (int ioapic);
+ extern int io_apic_get_redir_entries (int ioapic);
+ extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
+-extern int timer_uses_ioapic_pin_0;
+ #endif
+
+ extern int sis_apic_bug; /* dummy */
+
+-#else /* !CONFIG_X86_IO_APIC */
+-#define io_apic_assign_pci_irqs 0
+-#endif
+-
+-extern int assign_irq_vector(int irq);
+-
+ void enable_NMI_through_LVT0 (void * dummy);
+
+ extern spinlock_t i8259A_lock;
+diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h
+index 9db5a1b..5006c6e 100644
+--- a/include/asm-x86_64/irq.h
++++ b/include/asm-x86_64/irq.h
+@@ -31,22 +31,15 @@
+
+ #define FIRST_SYSTEM_VECTOR 0xef /* duplicated in hw_irq.h */
+
+-#ifdef CONFIG_PCI_MSI
+-#define NR_IRQS FIRST_SYSTEM_VECTOR
++#define NR_IRQS (NR_VECTORS + (32 *NR_CPUS))
+ #define NR_IRQ_VECTORS NR_IRQS
+-#else
+-#define NR_IRQS 224
+-#define NR_IRQ_VECTORS (32 * NR_CPUS)
+-#endif
+
+ static __inline__ int irq_canonicalize(int irq)
+ {
+ return ((irq == 2) ? 9 : irq);
+ }
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+ #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
+-#endif
+
+ #ifdef CONFIG_HOTPLUG_CPU
+ #include <linux/cpumask.h>
+diff --git a/include/asm-x86_64/irq_regs.h b/include/asm-x86_64/irq_regs.h
+new file mode 100644
+index 0000000..3dd9c0b
+--- /dev/null
++++ b/include/asm-x86_64/irq_regs.h
+@@ -0,0 +1 @@
++#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h
+index c564bae..5fab957 100644
+--- a/include/asm-x86_64/kexec.h
++++ b/include/asm-x86_64/kexec.h
+@@ -1,6 +1,27 @@
+ #ifndef _X86_64_KEXEC_H
+ #define _X86_64_KEXEC_H
+
++#define PA_CONTROL_PAGE 0
++#define VA_CONTROL_PAGE 1
++#define PA_PGD 2
++#define VA_PGD 3
++#define PA_PUD_0 4
++#define VA_PUD_0 5
++#define PA_PMD_0 6
++#define VA_PMD_0 7
++#define PA_PTE_0 8
++#define VA_PTE_0 9
++#define PA_PUD_1 10
++#define VA_PUD_1 11
++#define PA_PMD_1 12
++#define VA_PMD_1 13
++#define PA_PTE_1 14
++#define VA_PTE_1 15
++#define PA_TABLE_PAGE 16
++#define PAGES_NR 17
++
++#ifndef __ASSEMBLY__
++
+ #include <linux/string.h>
+
+ #include <asm/page.h>
+@@ -64,4 +85,12 @@ static inline void crash_setup_regs(stru
+ newregs->rip = (unsigned long)current_text_addr();
+ }
+ }
++
++NORET_TYPE void
++relocate_kernel(unsigned long indirection_page,
++ unsigned long page_list,
++ unsigned long start_address) ATTRIB_NORET;
++
++#endif /* __ASSEMBLY__ */
++
+ #endif /* _X86_64_KEXEC_H */
+diff --git a/include/asm-x86_64/linkage.h b/include/asm-x86_64/linkage.h
+index 291c2d0..b5f39d0 100644
+--- a/include/asm-x86_64/linkage.h
++++ b/include/asm-x86_64/linkage.h
+@@ -1,6 +1,6 @@
+ #ifndef __ASM_LINKAGE_H
+ #define __ASM_LINKAGE_H
+
+-/* Nothing to see here... */
++#define __ALIGN .p2align 4,,15
+
+ #endif
+diff --git a/include/asm-x86_64/mach_apic.h b/include/asm-x86_64/mach_apic.h
+index 0acea44..7b7115a 100644
+--- a/include/asm-x86_64/mach_apic.h
++++ b/include/asm-x86_64/mach_apic.h
+@@ -16,8 +16,8 @@
+
+ #define INT_DELIVERY_MODE (genapic->int_delivery_mode)
+ #define INT_DEST_MODE (genapic->int_dest_mode)
+-#define INT_DELIVERY_DEST (genapic->int_delivery_dest)
+ #define TARGET_CPUS (genapic->target_cpus())
++#define vector_allocation_domain (genapic->vector_allocation_domain)
+ #define apic_id_registered (genapic->apic_id_registered)
+ #define init_apic_ldr (genapic->init_apic_ldr)
+ #define send_IPI_mask (genapic->send_IPI_mask)
+diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h
+index d13687d..5a11146 100644
+--- a/include/asm-x86_64/mce.h
++++ b/include/asm-x86_64/mce.h
+@@ -99,6 +99,8 @@ static inline void mce_amd_feature_init(
+ }
+ #endif
+
++void mce_log_therm_throt_event(unsigned int cpu, __u64 status);
++
+ extern atomic_t mce_entry;
+
+ #endif
+diff --git a/include/asm-x86_64/mmx.h b/include/asm-x86_64/mmx.h
+deleted file mode 100644
+index 46b71da..0000000
+--- a/include/asm-x86_64/mmx.h
++++ /dev/null
+@@ -1,14 +0,0 @@
+-#ifndef _ASM_MMX_H
+-#define _ASM_MMX_H
+-
+-/*
+- * MMX 3Dnow! helper operations
+- */
+-
+-#include <linux/types.h>
+-
+-extern void *_mmx_memcpy(void *to, const void *from, size_t size);
+-extern void mmx_clear_page(void *page);
+-extern void mmx_copy_page(void *to, void *from);
+-
+-#endif
+diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
+index 14fc3dd..017fddb 100644
+--- a/include/asm-x86_64/mpspec.h
++++ b/include/asm-x86_64/mpspec.h
+@@ -159,13 +159,7 @@ struct mpc_config_lintsrc
+ #define MAX_MP_BUSSES 256
+ /* Each PCI slot may be a combo card with its own bus. 4 IRQ pins per slot. */
+ #define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4)
+-enum mp_bustype {
+- MP_BUS_ISA = 1,
+- MP_BUS_EISA,
+- MP_BUS_PCI,
+- MP_BUS_MCA
+-};
+-extern unsigned char mp_bus_id_to_type [MAX_MP_BUSSES];
++extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
+ extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
+
+ extern unsigned int boot_cpu_physical_apicid;
+@@ -178,18 +172,15 @@ extern int mp_irq_entries;
+ extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+ extern int mpc_default_type;
+ extern unsigned long mp_lapic_addr;
+-extern int pic_mode;
+
+ #ifdef CONFIG_ACPI
+ extern void mp_register_lapic (u8 id, u8 enabled);
+ extern void mp_register_lapic_address (u64 address);
+
+-#ifdef CONFIG_X86_IO_APIC
+ extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
+ extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
+ extern void mp_config_acpi_legacy_irqs (void);
+ extern int mp_register_gsi (u32 gsi, int triggering, int polarity);
+-#endif /*CONFIG_X86_IO_APIC*/
+ #endif
+
+ extern int using_apic_timer;
+diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
+deleted file mode 100644
+index 3ad2346..0000000
+--- a/include/asm-x86_64/msi.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-/*
+- * Copyright (C) 2003-2004 Intel
+- * Copyright (C) Tom Long Nguyen (tom.l.nguyen at intel.com)
+- */
+-
+-#ifndef ASM_MSI_H
+-#define ASM_MSI_H
+-
+-#include <asm/desc.h>
+-#include <asm/mach_apic.h>
+-#include <asm/smp.h>
+-
+-#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
+-#define MSI_TARGET_CPU_SHIFT 12
+-
+-extern struct msi_ops msi_apic_ops;
+-
+-static inline int msi_arch_init(void)
+-{
+- msi_register(&msi_apic_ops);
+- return 0;
+-}
+-
+-#endif /* ASM_MSI_H */
+diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h
+new file mode 100644
+index 0000000..5b8acdd
+--- /dev/null
++++ b/include/asm-x86_64/msidef.h
+@@ -0,0 +1,47 @@
++#ifndef ASM_MSIDEF_H
++#define ASM_MSIDEF_H
++
++/*
++ * Constants for Intel APIC based MSI messages.
++ */
++
++/*
++ * Shifts for MSI data
++ */
++
++#define MSI_DATA_VECTOR_SHIFT 0
++#define MSI_DATA_VECTOR_MASK 0x000000ff
++#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
++
++#define MSI_DATA_DELIVERY_MODE_SHIFT 8
++#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
++#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
++
++#define MSI_DATA_LEVEL_SHIFT 14
++#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
++#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
++
++#define MSI_DATA_TRIGGER_SHIFT 15
++#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
++#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
++
++/*
++ * Shift/mask fields for msi address
++ */
++
++#define MSI_ADDR_BASE_HI 0
++#define MSI_ADDR_BASE_LO 0xfee00000
++
++#define MSI_ADDR_DEST_MODE_SHIFT 2
++#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
++#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
++
++#define MSI_ADDR_REDIRECTION_SHIFT 3
++#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
++#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
++
++#define MSI_ADDR_DEST_ID_SHIFT 12
++#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
++#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
++
++#endif /* ASM_MSIDEF_H */
+diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
+index 10f8b51..37e1941 100644
+--- a/include/asm-x86_64/msr.h
++++ b/include/asm-x86_64/msr.h
+@@ -66,14 +66,25 @@
+ #define rdtscl(low) \
+ __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
++#define rdtscp(low,high,aux) \
++ asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (low), "=d" (high), "=c" (aux))
++
+ #define rdtscll(val) do { \
+ unsigned int __a,__d; \
+ asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
+ (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
+ } while(0)
+
++#define rdtscpll(val, aux) do { \
++ unsigned long __a, __d; \
++ asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (__a), "=d" (__d), "=c" (aux)); \
++ (val) = (__d << 32) | __a; \
++} while (0)
++
+ #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
+
++#define write_rdtscp_aux(val) wrmsr(0xc0000103, val, 0)
++
+ #define rdpmc(counter,low,high) \
+ __asm__ __volatile__("rdpmc" \
+ : "=a" (low), "=d" (high) \
+diff --git a/include/asm-x86_64/mutex.h b/include/asm-x86_64/mutex.h
+index 06fab6d..16396b1 100644
+--- a/include/asm-x86_64/mutex.h
++++ b/include/asm-x86_64/mutex.h
+@@ -25,13 +25,9 @@ do { \
+ \
+ __asm__ __volatile__( \
+ LOCK_PREFIX " decl (%%rdi) \n" \
+- " js 2f \n" \
+- "1: \n" \
+- \
+- LOCK_SECTION_START("") \
+- "2: call "#fail_fn" \n" \
+- " jmp 1b \n" \
+- LOCK_SECTION_END \
++ " jns 1f \n" \
++ " call "#fail_fn" \n" \
++ "1:" \
+ \
+ :"=D" (dummy) \
+ : "D" (v) \
+@@ -75,13 +71,9 @@ do { \
+ \
+ __asm__ __volatile__( \
+ LOCK_PREFIX " incl (%%rdi) \n" \
+- " jle 2f \n" \
+- "1: \n" \
+- \
+- LOCK_SECTION_START("") \
+- "2: call "#fail_fn" \n" \
+- " jmp 1b \n" \
+- LOCK_SECTION_END \
++ " jg 1f \n" \
++ " call "#fail_fn" \n" \
++ "1: " \
+ \
+ :"=D" (dummy) \
+ : "D" (v) \
+diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
+index efb45c8..f367d40 100644
+--- a/include/asm-x86_64/nmi.h
++++ b/include/asm-x86_64/nmi.h
+@@ -7,24 +7,13 @@
+ #include <linux/pm.h>
+ #include <asm/io.h>
+
+-struct pt_regs;
+-
+-typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
+-
+-/**
+- * set_nmi_callback
+- *
+- * Set a handler for an NMI. Only one handler may be
+- * set. Return 1 if the NMI was handled.
+- */
+-void set_nmi_callback(nmi_callback_t callback);
+-
+ /**
+- * unset_nmi_callback
++ * do_nmi_callback
+ *
+- * Remove the handler previously set.
++ * Check to see if a callback exists and execute it. Return 1
++ * if the handler exists and was handled successfully.
+ */
+-void unset_nmi_callback(void);
++int do_nmi_callback(struct pt_regs *regs, int cpu);
+
+ #ifdef CONFIG_PM
+
+@@ -48,25 +37,32 @@ static inline void unset_nmi_pm_callback
+ #endif /* CONFIG_PM */
+
+ extern void default_do_nmi(struct pt_regs *);
+-extern void die_nmi(char *str, struct pt_regs *regs);
++extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
+
+ #define get_nmi_reason() inb(0x61)
+
+ extern int panic_on_timeout;
+ extern int unknown_nmi_panic;
++extern int nmi_watchdog_enabled;
+
+ extern int check_nmi_watchdog(void);
+-
+-extern void setup_apic_nmi_watchdog (void);
+-extern int reserve_lapic_nmi(void);
+-extern void release_lapic_nmi(void);
++extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
++extern int avail_to_resrv_perfctr_nmi(unsigned int);
++extern int reserve_perfctr_nmi(unsigned int);
++extern void release_perfctr_nmi(unsigned int);
++extern int reserve_evntsel_nmi(unsigned int);
++extern void release_evntsel_nmi(unsigned int);
++
++extern void setup_apic_nmi_watchdog (void *);
++extern void stop_apic_nmi_watchdog (void *);
+ extern void disable_timer_nmi_watchdog(void);
+ extern void enable_timer_nmi_watchdog(void);
+-extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
++extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
+
+ extern void nmi_watchdog_default(void);
+ extern int setup_nmi_watchdog(char *);
+
++extern atomic_t nmi_active;
+ extern unsigned int nmi_watchdog;
+ #define NMI_DEFAULT -1
+ #define NMI_NONE 0
+@@ -74,4 +70,11 @@ extern unsigned int nmi_watchdog;
+ #define NMI_LOCAL_APIC 2
+ #define NMI_INVALID 3
+
++struct ctl_table;
++struct file;
++extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
++ void __user *, size_t *, loff_t *);
++
++extern int unknown_nmi_panic;
++
+ #endif /* ASM_NMI_H */
+diff --git a/include/asm-x86_64/pci-direct.h b/include/asm-x86_64/pci-direct.h
+index 036b6ca..eba9cb4 100644
+--- a/include/asm-x86_64/pci-direct.h
++++ b/include/asm-x86_64/pci-direct.h
+@@ -2,47 +2,15 @@
+ #define ASM_PCI_DIRECT_H 1
+
+ #include <linux/types.h>
+-#include <asm/io.h>
+
+ /* Direct PCI access. This is used for PCI accesses in early boot before
+ the PCI subsystem works. */
+
+-#define PDprintk(x...)
++extern u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset);
++extern u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset);
++extern u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset);
++extern void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, u32 val);
+
+-static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
+-{
+- u32 v;
+- outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+- v = inl(0xcfc);
+- if (v != 0xffffffff)
+- PDprintk("%x reading 4 from %x: %x\n", slot, offset, v);
+- return v;
+-}
+-
+-static inline u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
+-{
+- u8 v;
+- outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+- v = inb(0xcfc + (offset&3));
+- PDprintk("%x reading 1 from %x: %x\n", slot, offset, v);
+- return v;
+-}
+-
+-static inline u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
+-{
+- u16 v;
+- outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+- v = inw(0xcfc + (offset&2));
+- PDprintk("%x reading 2 from %x: %x\n", slot, offset, v);
+- return v;
+-}
+-
+-static inline void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
+- u32 val)
+-{
+- PDprintk("%x writing to %x: %x\n", slot, offset, val);
+- outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+- outl(val, 0xcfc);
+-}
++extern int early_pci_allowed(void);
+
+ #endif
+diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h
+index b47c3df..14996d9 100644
+--- a/include/asm-x86_64/pda.h
++++ b/include/asm-x86_64/pda.h
+@@ -9,20 +9,24 @@
+
+ /* Per processor datastructure. %gs points to it while the kernel runs */
+ struct x8664_pda {
+- struct task_struct *pcurrent; /* Current process */
+- unsigned long data_offset; /* Per cpu data offset from linker address */
+- unsigned long kernelstack; /* top of kernel stack for current */
+- unsigned long oldrsp; /* user rsp for system call */
+-#if DEBUG_STKSZ > EXCEPTION_STKSZ
+- unsigned long debugstack; /* #DB/#BP stack. */
++ struct task_struct *pcurrent; /* 0 Current process */
++ unsigned long data_offset; /* 8 Per cpu data offset from linker
++ address */
++ unsigned long kernelstack; /* 16 top of kernel stack for current */
++ unsigned long oldrsp; /* 24 user rsp for system call */
++ int irqcount; /* 32 Irq nesting counter. Starts with -1 */
++ int cpunumber; /* 36 Logical CPU number */
++#ifdef CONFIG_CC_STACKPROTECTOR
++ unsigned long stack_canary; /* 40 stack canary value */
++ /* gcc-ABI: this canary MUST be at
++ offset 40!!! */
+ #endif
+- int irqcount; /* Irq nesting counter. Starts with -1 */
+- int cpunumber; /* Logical CPU number */
+- char *irqstackptr; /* top of irqstack */
++ char *irqstackptr;
+ int nodenumber; /* number of current node */
+ unsigned int __softirq_pending;
+ unsigned int __nmi_count; /* number of NMI on this CPUs */
+- int mmu_state;
++ short mmu_state;
++ short isidle;
+ struct mm_struct *active_mm;
+ unsigned apic_timer_irqs;
+ } ____cacheline_aligned_in_smp;
+@@ -36,44 +40,69 @@ extern struct x8664_pda boot_cpu_pda[];
+ * There is no fast way to get the base address of the PDA, all the accesses
+ * have to mention %fs/%gs. So it needs to be done this Torvaldian way.
+ */
+-#define sizeof_field(type,field) (sizeof(((type *)0)->field))
+-#define typeof_field(type,field) typeof(((type *)0)->field)
++extern void __bad_pda_field(void) __attribute__((noreturn));
+
+-extern void __bad_pda_field(void);
++/*
++ * proxy_pda doesn't actually exist, but tell gcc it is accessed for
++ * all PDA accesses so it gets read/write dependencies right.
++ */
++extern struct x8664_pda _proxy_pda;
+
+ #define pda_offset(field) offsetof(struct x8664_pda, field)
+
+-#define pda_to_op(op,field,val) do { \
+- typedef typeof_field(struct x8664_pda, field) T__; \
+- switch (sizeof_field(struct x8664_pda, field)) { \
+-case 2: \
+-asm volatile(op "w %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
+-case 4: \
+-asm volatile(op "l %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
+-case 8: \
+-asm volatile(op "q %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
+- default: __bad_pda_field(); \
+- } \
++#define pda_to_op(op,field,val) do { \
++ typedef typeof(_proxy_pda.field) T__; \
++ if (0) { T__ tmp__; tmp__ = (val); } /* type checking */ \
++ switch (sizeof(_proxy_pda.field)) { \
++ case 2: \
++ asm(op "w %1,%%gs:%c2" : \
++ "+m" (_proxy_pda.field) : \
++ "ri" ((T__)val), \
++ "i"(pda_offset(field))); \
++ break; \
++ case 4: \
++ asm(op "l %1,%%gs:%c2" : \
++ "+m" (_proxy_pda.field) : \
++ "ri" ((T__)val), \
++ "i" (pda_offset(field))); \
++ break; \
++ case 8: \
++ asm(op "q %1,%%gs:%c2": \
++ "+m" (_proxy_pda.field) : \
++ "ri" ((T__)val), \
++ "i"(pda_offset(field))); \
++ break; \
++ default: \
++ __bad_pda_field(); \
++ } \
+ } while (0)
+
+-/*
+- * AK: PDA read accesses should be neither volatile nor have an memory clobber.
+- * Unfortunately removing them causes all hell to break lose currently.
+- */
+-#define pda_from_op(op,field) ({ \
+- typeof_field(struct x8664_pda, field) ret__; \
+- switch (sizeof_field(struct x8664_pda, field)) { \
+-case 2: \
+-asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
+-case 4: \
+-asm volatile(op "l %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
+-case 8: \
+-asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
+- default: __bad_pda_field(); \
+- } \
++#define pda_from_op(op,field) ({ \
++ typeof(_proxy_pda.field) ret__; \
++ switch (sizeof(_proxy_pda.field)) { \
++ case 2: \
++ asm(op "w %%gs:%c1,%0" : \
++ "=r" (ret__) : \
++ "i" (pda_offset(field)), \
++ "m" (_proxy_pda.field)); \
++ break; \
++ case 4: \
++ asm(op "l %%gs:%c1,%0": \
++ "=r" (ret__): \
++ "i" (pda_offset(field)), \
++ "m" (_proxy_pda.field)); \
++ break; \
++ case 8: \
++ asm(op "q %%gs:%c1,%0": \
++ "=r" (ret__) : \
++ "i" (pda_offset(field)), \
++ "m" (_proxy_pda.field)); \
++ break; \
++ default: \
++ __bad_pda_field(); \
++ } \
+ ret__; })
+
+-
+ #define read_pda(field) pda_from_op("mov",field)
+ #define write_pda(field,val) pda_to_op("mov",field,val)
+ #define add_pda(field,val) pda_to_op("add",field,val)
+diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
+index 08dd9f9..5ed0ef3 100644
+--- a/include/asm-x86_64/percpu.h
++++ b/include/asm-x86_64/percpu.h
+@@ -11,6 +11,16 @@
+
+ #include <asm/pda.h>
+
++#ifdef CONFIG_MODULES
++# define PERCPU_MODULE_RESERVE 8192
++#else
++# define PERCPU_MODULE_RESERVE 0
++#endif
++
++#define PERCPU_ENOUGH_ROOM \
++ (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
++ PERCPU_MODULE_RESERVE)
++
+ #define __per_cpu_offset(cpu) (cpu_pda(cpu)->data_offset)
+ #define __my_cpu_offset() read_pda(data_offset)
+
+@@ -21,9 +31,15 @@
+ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+
+ /* var is in discarded region: offset to particular copy we want */
+-#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
+-#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+-#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
++#define per_cpu(var, cpu) (*({ \
++ extern int simple_identifier_##var(void); \
++ RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)); }))
++#define __get_cpu_var(var) (*({ \
++ extern int simple_identifier_##var(void); \
++ RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); }))
++#define __raw_get_cpu_var(var) (*({ \
++ extern int simple_identifier_##var(void); \
++ RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); }))
+
+ /* A macro to avoid #include hell... */
+ #define percpu_modcopy(pcpudst, src, size) \
+diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
+index a31ab4e..0555c1c 100644
+--- a/include/asm-x86_64/pgtable.h
++++ b/include/asm-x86_64/pgtable.h
+@@ -21,12 +21,9 @@ extern unsigned long __supported_pte_mas
+
+ #define swapper_pg_dir init_level4_pgt
+
+-extern int nonx_setup(char *str);
+ extern void paging_init(void);
+ extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
+
+-extern unsigned long pgkern_mask;
+-
+ /*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+@@ -101,9 +98,6 @@ static inline void pgd_clear (pgd_t * pg
+ set_pgd(pgd, __pgd(0));
+ }
+
+-#define pud_page(pud) \
+-((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
+-
+ #define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte, 0))
+
+ struct mm_struct;
+@@ -268,7 +262,7 @@ static inline pte_t pfn_pte(unsigned lon
+ #define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
+ static inline int pte_user(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
+ static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
+-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
++static inline int pte_exec(pte_t pte) { return !(pte_val(pte) & _PAGE_NX); }
+ 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_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+@@ -281,11 +275,12 @@ static inline pte_t pte_mkclean(pte_t pt
+ static inline pte_t pte_mkold(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
+ static inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; }
+ static inline pte_t pte_mkread(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+-static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
++static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_NX)); return pte; }
+ static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
+ static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
+ static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
+ static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_PSE)); return pte; }
++static inline pte_t pte_clrhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_PSE)); return pte; }
+
+ struct vm_area_struct;
+
+@@ -326,7 +321,8 @@ static inline int pmd_large(pmd_t pte) {
+ /*
+ * Level 4 access.
+ */
+-#define pgd_page(pgd) ((unsigned long) __va((unsigned long)pgd_val(pgd) & PTE_MASK))
++#define pgd_page_vaddr(pgd) ((unsigned long) __va((unsigned long)pgd_val(pgd) & PTE_MASK))
++#define pgd_page(pgd) (pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT))
+ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+ #define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
+ #define pgd_offset_k(address) (init_level4_pgt + pgd_index(address))
+@@ -335,16 +331,18 @@ static inline int pmd_large(pmd_t pte) {
+
+ /* PUD - Level3 access */
+ /* to find an entry in a page-table-directory. */
++#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
++#define pud_page(pud) (pfn_to_page(pud_val(pud) >> PAGE_SHIFT))
+ #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
+-#define pud_offset(pgd, address) ((pud_t *) pgd_page(*(pgd)) + pud_index(address))
++#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address))
+ #define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
+
+ /* PMD - Level 2 access */
+-#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
+ #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+
+ #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+-#define pmd_offset(dir, address) ((pmd_t *) pud_page(*(dir)) + \
++#define pmd_offset(dir, address) ((pmd_t *) pud_page_vaddr(*(dir)) + \
+ pmd_index(address))
+ #define pmd_none(x) (!pmd_val(x))
+ #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
+@@ -368,6 +366,7 @@ static inline pte_t mk_pte_phys(unsigned
+ {
+ pte_t pte;
+ pte_val(pte) = physpage | pgprot_val(pgprot);
++ pte_val(pte) &= __supported_pte_mask;
+ return pte;
+ }
+
+@@ -382,7 +381,7 @@ static inline pte_t pte_modify(pte_t pte
+
+ #define pte_index(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+-#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \
++#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + \
+ pte_index(address))
+
+ /* x86-64 always has all page tables mapped. */
+diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
+index de9c314..cef17e0 100644
+--- a/include/asm-x86_64/processor.h
++++ b/include/asm-x86_64/processor.h
+@@ -475,6 +475,8 @@ static inline void __mwait(unsigned long
+ : :"a" (eax), "c" (ecx));
+ }
+
++extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
++
+ #define stack_current() \
+ ({ \
+ struct thread_info *ti; \
+diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
+index 038fe1f..e72cfcd 100644
+--- a/include/asm-x86_64/proto.h
++++ b/include/asm-x86_64/proto.h
+@@ -24,8 +24,6 @@ extern void mtrr_bp_init(void);
+ #define mtrr_bp_init() do {} while (0)
+ #endif
+ extern void init_memory_mapping(unsigned long start, unsigned long end);
+-extern void size_zones(unsigned long *z, unsigned long *h,
+- unsigned long start_pfn, unsigned long end_pfn);
+
+ extern void system_call(void);
+ extern int kernel_syscall(void);
+@@ -51,10 +49,8 @@ extern unsigned long long monotonic_base
+ extern int sysctl_vsyscall;
+ extern int nohpet;
+ extern unsigned long vxtime_hz;
++extern void time_init_gtod(void);
+
+-extern int numa_setup(char *opt);
+-
+-extern int setup_early_printk(char *);
+ extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2)));
+
+ extern void early_identify_cpu(struct cpuinfo_x86 *c);
+@@ -70,7 +66,7 @@ extern void free_bootmem_generic(unsigne
+ extern void load_gs_index(unsigned gs);
+
+ extern void stop_timer_interrupt(void);
+-extern void main_timer_handler(struct pt_regs *regs);
++extern void main_timer_handler(void);
+
+ extern unsigned long end_pfn_map;
+
+@@ -91,7 +87,7 @@ extern void syscall32_cpu_init(void);
+
+ extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
+
+-extern void check_ioapic(void);
++extern void early_quirks(void);
+ extern void check_efer(void);
+
+ extern int unhandled_signal(struct task_struct *tsk, int sig);
+@@ -103,13 +99,7 @@ extern void select_idle_routine(const st
+ extern unsigned long table_start, table_end;
+
+ extern int exception_trace;
+-extern int using_apic_timer;
+-extern int disable_apic;
+ extern unsigned cpu_khz;
+-extern int ioapic_force;
+-extern int skip_ioapic_setup;
+-extern int acpi_ht;
+-extern int acpi_disabled;
+
+ extern void no_iommu_init(void);
+ extern int force_iommu, no_iommu;
+@@ -131,9 +121,12 @@ extern int fix_aperture;
+
+ extern int reboot_force;
+ extern int notsc_setup(char *);
+-extern int setup_additional_cpus(char *);
+
+-extern void smp_local_timer_interrupt(struct pt_regs * regs);
++extern int timer_over_8254;
++
++extern int gsi_irq_sharing(int gsi);
++
++extern void smp_local_timer_interrupt(void);
+
+ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
+
+diff --git a/include/asm-x86_64/ptrace-abi.h b/include/asm-x86_64/ptrace-abi.h
+new file mode 100644
+index 0000000..19184b0
+--- /dev/null
++++ b/include/asm-x86_64/ptrace-abi.h
+@@ -0,0 +1,51 @@
++#ifndef _X86_64_PTRACE_ABI_H
++#define _X86_64_PTRACE_ABI_H
++
++#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS)
++#define R15 0
++#define R14 8
++#define R13 16
++#define R12 24
++#define RBP 32
++#define RBX 40
++/* arguments: interrupts/non tracing syscalls only save upto here*/
++#define R11 48
++#define R10 56
++#define R9 64
++#define R8 72
++#define RAX 80
++#define RCX 88
++#define RDX 96
++#define RSI 104
++#define RDI 112
++#define ORIG_RAX 120 /* = ERROR */
++/* end of arguments */
++/* cpu exception frame or undefined in case of fast syscall. */
++#define RIP 128
++#define CS 136
++#define EFLAGS 144
++#define RSP 152
++#define SS 160
++#define ARGOFFSET R11
++#endif /* __ASSEMBLY__ */
++
++/* top of stack page */
++#define FRAME_SIZE 168
++
++#define PTRACE_OLDSETOPTIONS 21
++
++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
++#define PTRACE_GETREGS 12
++#define PTRACE_SETREGS 13
++#define PTRACE_GETFPREGS 14
++#define PTRACE_SETFPREGS 15
++#define PTRACE_GETFPXREGS 18
++#define PTRACE_SETFPXREGS 19
++
++/* only useful for access 32bit programs */
++#define PTRACE_GET_THREAD_AREA 25
++#define PTRACE_SET_THREAD_AREA 26
++
++#define PTRACE_ARCH_PRCTL 30 /* arch_prctl for child */
++
++#endif
+diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
+index ca6f15f..5ea84db 100644
+--- a/include/asm-x86_64/ptrace.h
++++ b/include/asm-x86_64/ptrace.h
+@@ -1,40 +1,9 @@
+ #ifndef _X86_64_PTRACE_H
+ #define _X86_64_PTRACE_H
+
+-#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS)
+-#define R15 0
+-#define R14 8
+-#define R13 16
+-#define R12 24
+-#define RBP 32
+-#define RBX 40
+-/* arguments: interrupts/non tracing syscalls only save upto here*/
+-#define R11 48
+-#define R10 56
+-#define R9 64
+-#define R8 72
+-#define RAX 80
+-#define RCX 88
+-#define RDX 96
+-#define RSI 104
+-#define RDI 112
+-#define ORIG_RAX 120 /* = ERROR */
+-/* end of arguments */
+-/* cpu exception frame or undefined in case of fast syscall. */
+-#define RIP 128
+-#define CS 136
+-#define EFLAGS 144
+-#define RSP 152
+-#define SS 160
+-#define ARGOFFSET R11
+-#endif /* __ASSEMBLY__ */
++#include <asm/ptrace-abi.h>
+
+-/* top of stack page */
+-#define FRAME_SIZE 168
+-
+-#define PTRACE_OLDSETOPTIONS 21
+-
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLY__
+
+ struct pt_regs {
+ unsigned long r15;
+@@ -45,7 +14,7 @@ struct pt_regs {
+ unsigned long rbx;
+ /* arguments: non interrupts/non tracing syscalls only save upto here*/
+ unsigned long r11;
+- unsigned long r10;
++ unsigned long r10;
+ unsigned long r9;
+ unsigned long r8;
+ unsigned long rax;
+@@ -54,36 +23,24 @@ struct pt_regs {
+ unsigned long rsi;
+ unsigned long rdi;
+ unsigned long orig_rax;
+-/* end of arguments */
++/* end of arguments */
+ /* cpu exception frame or undefined */
+ unsigned long rip;
+ unsigned long cs;
+- unsigned long eflags;
+- unsigned long rsp;
++ unsigned long eflags;
++ unsigned long rsp;
+ unsigned long ss;
+-/* top of stack page */
++/* top of stack page */
+ };
+
+ #endif
+
+-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+-#define PTRACE_GETREGS 12
+-#define PTRACE_SETREGS 13
+-#define PTRACE_GETFPREGS 14
+-#define PTRACE_SETFPREGS 15
+-#define PTRACE_GETFPXREGS 18
+-#define PTRACE_SETFPXREGS 19
+-
+-/* only useful for access 32bit programs */
+-#define PTRACE_GET_THREAD_AREA 25
+-#define PTRACE_SET_THREAD_AREA 26
+-
+-#define PTRACE_ARCH_PRCTL 30 /* arch_prctl for child */
+-
+ #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+ #define user_mode(regs) (!!((regs)->cs & 3))
+ #define user_mode_vm(regs) user_mode(regs)
+ #define instruction_pointer(regs) ((regs)->rip)
++#define regs_return_value(regs) ((regs)->rax)
++
+ extern unsigned long profile_pc(struct pt_regs *regs);
+ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+
+diff --git a/include/asm-x86_64/rwlock.h b/include/asm-x86_64/rwlock.h
+index dea0e94..72aeebe 100644
+--- a/include/asm-x86_64/rwlock.h
++++ b/include/asm-x86_64/rwlock.h
+@@ -18,69 +18,9 @@
+ #ifndef _ASM_X86_64_RWLOCK_H
+ #define _ASM_X86_64_RWLOCK_H
+
+-#include <linux/stringify.h>
+-
+ #define RW_LOCK_BIAS 0x01000000
+-#define RW_LOCK_BIAS_STR "0x01000000"
+-
+-#define __build_read_lock_ptr(rw, helper) \
+- asm volatile(LOCK_PREFIX "subl $1,(%0)\n\t" \
+- "js 2f\n" \
+- "1:\n" \
+- LOCK_SECTION_START("") \
+- "2:\tcall " helper "\n\t" \
+- "jmp 1b\n" \
+- LOCK_SECTION_END \
+- ::"a" (rw) : "memory")
+-
+-#define __build_read_lock_const(rw, helper) \
+- asm volatile(LOCK_PREFIX "subl $1,%0\n\t" \
+- "js 2f\n" \
+- "1:\n" \
+- LOCK_SECTION_START("") \
+- "2:\tpushq %%rax\n\t" \
+- "leaq %0,%%rax\n\t" \
+- "call " helper "\n\t" \
+- "popq %%rax\n\t" \
+- "jmp 1b\n" \
+- LOCK_SECTION_END \
+- :"=m" (*((volatile int *)rw))::"memory")
+-
+-#define __build_read_lock(rw, helper) do { \
+- if (__builtin_constant_p(rw)) \
+- __build_read_lock_const(rw, helper); \
+- else \
+- __build_read_lock_ptr(rw, helper); \
+- } while (0)
+-
+-#define __build_write_lock_ptr(rw, helper) \
+- asm volatile(LOCK_PREFIX "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+- "jnz 2f\n" \
+- "1:\n" \
+- LOCK_SECTION_START("") \
+- "2:\tcall " helper "\n\t" \
+- "jmp 1b\n" \
+- LOCK_SECTION_END \
+- ::"a" (rw) : "memory")
+-
+-#define __build_write_lock_const(rw, helper) \
+- asm volatile(LOCK_PREFIX "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+- "jnz 2f\n" \
+- "1:\n" \
+- LOCK_SECTION_START("") \
+- "2:\tpushq %%rax\n\t" \
+- "leaq %0,%%rax\n\t" \
+- "call " helper "\n\t" \
+- "popq %%rax\n\t" \
+- "jmp 1b\n" \
+- LOCK_SECTION_END \
+- :"=m" (*((volatile long *)rw))::"memory")
++#define RW_LOCK_BIAS_STR "0x01000000"
+
+-#define __build_write_lock(rw, helper) do { \
+- if (__builtin_constant_p(rw)) \
+- __build_write_lock_const(rw, helper); \
+- else \
+- __build_write_lock_ptr(rw, helper); \
+- } while (0)
++/* Actual code is in asm/spinlock.h or in arch/x86_64/lib/rwlock.S */
+
+ #endif
+diff --git a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
+index d4bed33..334ddcd 100644
+--- a/include/asm-x86_64/segment.h
++++ b/include/asm-x86_64/segment.h
+@@ -20,15 +20,16 @@
+ #define __USER_CS 0x33 /* 6*8+3 */
+ #define __USER32_DS __USER_DS
+
+-#define GDT_ENTRY_TLS 1
+ #define GDT_ENTRY_TSS 8 /* needs two entries */
+ #define GDT_ENTRY_LDT 10 /* needs two entries */
+ #define GDT_ENTRY_TLS_MIN 12
+ #define GDT_ENTRY_TLS_MAX 14
+-/* 15 free */
+
+ #define GDT_ENTRY_TLS_ENTRIES 3
+
++#define GDT_ENTRY_PER_CPU 15 /* Abused to load per CPU data from limit */
++#define __PER_CPU_SEG (GDT_ENTRY_PER_CPU * 8 + 3)
++
+ /* TLS indexes for 64bit - hardcoded in arch_prctl */
+ #define FS_TLS 0
+ #define GS_TLS 1
+diff --git a/include/asm-x86_64/semaphore.h b/include/asm-x86_64/semaphore.h
+index 064df08..1194888 100644
+--- a/include/asm-x86_64/semaphore.h
++++ b/include/asm-x86_64/semaphore.h
+@@ -107,12 +107,9 @@ static inline void down(struct semaphore
+ __asm__ __volatile__(
+ "# atomic down operation\n\t"
+ LOCK_PREFIX "decl %0\n\t" /* --sem->count */
+- "js 2f\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tcall __down_failed\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
++ "jns 1f\n\t"
++ "call __down_failed\n"
++ "1:"
+ :"=m" (sem->count)
+ :"D" (sem)
+ :"memory");
+@@ -130,15 +127,12 @@ static inline int down_interruptible(str
+
+ __asm__ __volatile__(
+ "# atomic interruptible down operation\n\t"
++ "xorl %0,%0\n\t"
+ LOCK_PREFIX "decl %1\n\t" /* --sem->count */
+- "js 2f\n\t"
+- "xorl %0,%0\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tcall __down_failed_interruptible\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
+- :"=a" (result), "=m" (sem->count)
++ "jns 2f\n\t"
++ "call __down_failed_interruptible\n"
++ "2:\n"
++ :"=&a" (result), "=m" (sem->count)
+ :"D" (sem)
+ :"memory");
+ return result;
+@@ -154,15 +148,12 @@ static inline int down_trylock(struct se
+
+ __asm__ __volatile__(
+ "# atomic interruptible down operation\n\t"
++ "xorl %0,%0\n\t"
+ LOCK_PREFIX "decl %1\n\t" /* --sem->count */
+- "js 2f\n\t"
+- "xorl %0,%0\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tcall __down_failed_trylock\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
+- :"=a" (result), "=m" (sem->count)
++ "jns 2f\n\t"
++ "call __down_failed_trylock\n\t"
++ "2:\n"
++ :"=&a" (result), "=m" (sem->count)
+ :"D" (sem)
+ :"memory","cc");
+ return result;
+@@ -179,12 +170,9 @@ static inline void up(struct semaphore *
+ __asm__ __volatile__(
+ "# atomic up operation\n\t"
+ LOCK_PREFIX "incl %0\n\t" /* ++sem->count */
+- "jle 2f\n"
+- "1:\n"
+- LOCK_SECTION_START("")
+- "2:\tcall __up_wakeup\n\t"
+- "jmp 1b\n"
+- LOCK_SECTION_END
++ "jg 1f\n\t"
++ "call __up_wakeup\n"
++ "1:"
+ :"=m" (sem->count)
+ :"D" (sem)
+ :"memory");
+diff --git a/include/asm-x86_64/signal.h b/include/asm-x86_64/signal.h
+index 3ede2a6..4581f97 100644
+--- a/include/asm-x86_64/signal.h
++++ b/include/asm-x86_64/signal.h
+@@ -24,10 +24,6 @@ typedef struct {
+ } sigset_t;
+
+
+-struct pt_regs;
+-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+-
+-
+ #else
+ /* Here we must cater to libcs that poke about in kernel headers. */
+
+diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
+index 6805e1f..d6b7c05 100644
+--- a/include/asm-x86_64/smp.h
++++ b/include/asm-x86_64/smp.h
+@@ -4,27 +4,18 @@
+ /*
+ * We need the APIC definitions automatically as part of 'smp.h'
+ */
+-#ifndef __ASSEMBLY__
+ #include <linux/threads.h>
+ #include <linux/cpumask.h>
+ #include <linux/bitops.h>
+ extern int disable_apic;
+-#endif
+
+-#ifdef CONFIG_X86_LOCAL_APIC
+-#ifndef __ASSEMBLY__
+ #include <asm/fixmap.h>
+ #include <asm/mpspec.h>
+-#ifdef CONFIG_X86_IO_APIC
+ #include <asm/io_apic.h>
+-#endif
+ #include <asm/apic.h>
+ #include <asm/thread_info.h>
+-#endif
+-#endif
+
+ #ifdef CONFIG_SMP
+-#ifndef ASSEMBLY
+
+ #include <asm/pda.h>
+
+@@ -42,14 +33,11 @@ extern cpumask_t cpu_initialized;
+
+ 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_send_reschedule(int cpu);
+ void smp_stop_cpu(void);
+-extern int smp_call_function_single(int cpuid, void (*func) (void *info),
+- void *info, int retry, int wait);
+
+ extern cpumask_t cpu_sibling_map[NR_CPUS];
+ extern cpumask_t cpu_core_map[NR_CPUS];
+@@ -76,20 +64,16 @@ static inline int hard_smp_processor_id(
+ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
+ }
+
+-extern int safe_smp_processor_id(void);
+ extern int __cpu_disable(void);
+ extern void __cpu_die(unsigned int cpu);
+ extern void prefill_possible_map(void);
+ extern unsigned num_processors;
+ extern unsigned disabled_cpus;
+
+-#endif /* !ASSEMBLY */
+-
+ #define NO_PROC_ID 0xFF /* No processor magic marker */
+
+ #endif
+
+-#ifndef ASSEMBLY
+ /*
+ * Some lowlevel functions might want to know about
+ * the real APIC ID <-> CPU # mapping.
+@@ -111,11 +95,8 @@ static inline int cpu_present_to_apicid(
+ return BAD_APICID;
+ }
+
+-#endif /* !ASSEMBLY */
+-
+ #ifndef CONFIG_SMP
+ #define stack_smp_processor_id() 0
+-#define safe_smp_processor_id() 0
+ #define cpu_logical_map(x) (x)
+ #else
+ #include <asm/thread_info.h>
+@@ -127,19 +108,23 @@ static inline int cpu_present_to_apicid(
+ })
+ #endif
+
+-#ifndef __ASSEMBLY__
+ static __inline int logical_smp_processor_id(void)
+ {
+ /* we don't want to mark this access volatile - bad code generation */
+ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
+ }
+-#endif
+
+ #ifdef CONFIG_SMP
+ #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu]
+ #else
+ #define cpu_physical_id(cpu) boot_cpu_id
+-#endif
+-
++static inline int smp_call_function_single(int cpuid, void (*func) (void *info),
++ void *info, int retry, int wait)
++{
++ /* Disable interrupts here? */
++ func(info);
++ return 0;
++}
++#endif /* !CONFIG_SMP */
+ #endif
+
+diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h
+index 248a79f..05ef097 100644
+--- a/include/asm-x86_64/spinlock.h
++++ b/include/asm-x86_64/spinlock.h
+@@ -4,6 +4,7 @@
+ #include <asm/atomic.h>
+ #include <asm/rwlock.h>
+ #include <asm/page.h>
++#include <asm/processor.h>
+
+ /*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+@@ -16,31 +17,23 @@
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+-#define __raw_spin_is_locked(x) \
+- (*(volatile signed int *)(&(x)->slock) <= 0)
+-
+-#define __raw_spin_lock_string \
+- "\n1:\t" \
+- LOCK_PREFIX " ; decl %0\n\t" \
+- "js 2f\n" \
+- LOCK_SECTION_START("") \
+- "2:\t" \
+- "rep;nop\n\t" \
+- "cmpl $0,%0\n\t" \
+- "jle 2b\n\t" \
+- "jmp 1b\n" \
+- LOCK_SECTION_END
+-
+-#define __raw_spin_lock_string_up \
+- "\n\tdecl %0"
+-
+-#define __raw_spin_unlock_string \
+- "movl $1,%0" \
+- :"=m" (lock->slock) : : "memory"
++static inline int __raw_spin_is_locked(raw_spinlock_t *lock)
++{
++ return *(volatile signed int *)(&(lock)->slock) <= 0;
++}
+
+ static inline void __raw_spin_lock(raw_spinlock_t *lock)
+ {
+- asm volatile(__raw_spin_lock_string : "=m" (lock->slock) : : "memory");
++ asm volatile(
++ "\n1:\t"
++ LOCK_PREFIX " ; decl %0\n\t"
++ "jns 2f\n"
++ "3:\n"
++ "rep;nop\n\t"
++ "cmpl $0,%0\n\t"
++ "jle 3b\n\t"
++ "jmp 1b\n"
++ "2:\t" : "=m" (lock->slock) : : "memory");
+ }
+
+ #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+@@ -49,7 +42,7 @@ static inline int __raw_spin_trylock(raw
+ {
+ int oldval;
+
+- __asm__ __volatile__(
++ asm volatile(
+ "xchgl %0,%1"
+ :"=q" (oldval), "=m" (lock->slock)
+ :"0" (0) : "memory");
+@@ -59,13 +52,14 @@ static inline int __raw_spin_trylock(raw
+
+ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+ {
+- __asm__ __volatile__(
+- __raw_spin_unlock_string
+- );
++ asm volatile("movl $1,%0" :"=m" (lock->slock) :: "memory");
+ }
+
+-#define __raw_spin_unlock_wait(lock) \
+- do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
++static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
++{
++ while (__raw_spin_is_locked(lock))
++ cpu_relax();
++}
+
+ /*
+ * Read-write spinlocks, allowing multiple readers
+@@ -79,26 +73,34 @@ static inline void __raw_spin_unlock(raw
+ *
+ * On x86, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+- *
+- * The inline assembly is non-obvious. Think about it.
+- *
+- * Changed to use the same technique as rw semaphores. See
+- * semaphore.h for details. -ben
+- *
+- * the helpers are in arch/i386/kernel/semaphore.c
+ */
+
+-#define __raw_read_can_lock(x) ((int)(x)->lock > 0)
+-#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
++static inline int __raw_read_can_lock(raw_rwlock_t *lock)
++{
++ return (int)(lock)->lock > 0;
++}
++
++static inline int __raw_write_can_lock(raw_rwlock_t *lock)
++{
++ return (lock)->lock == RW_LOCK_BIAS;
++}
+
+ static inline void __raw_read_lock(raw_rwlock_t *rw)
+ {
+- __build_read_lock(rw, "__read_lock_failed");
++ asm volatile(LOCK_PREFIX "subl $1,(%0)\n\t"
++ "jns 1f\n"
++ "call __read_lock_failed\n"
++ "1:\n"
++ ::"D" (rw), "i" (RW_LOCK_BIAS) : "memory");
+ }
+
+ static inline void __raw_write_lock(raw_rwlock_t *rw)
+ {
+- __build_write_lock(rw, "__write_lock_failed");
++ asm volatile(LOCK_PREFIX "subl %1,(%0)\n\t"
++ "jz 1f\n"
++ "\tcall __write_lock_failed\n\t"
++ "1:\n"
++ ::"D" (rw), "i" (RW_LOCK_BIAS) : "memory");
+ }
+
+ static inline int __raw_read_trylock(raw_rwlock_t *lock)
+@@ -131,4 +133,8 @@ static inline void __raw_write_unlock(ra
+ : "=m" (rw->lock) : : "memory");
+ }
+
++#define _raw_spin_relax(lock) cpu_relax()
++#define _raw_read_relax(lock) cpu_relax()
++#define _raw_write_relax(lock) cpu_relax()
++
+ #endif /* __ASM_SPINLOCK_H */
+diff --git a/include/asm-x86_64/stacktrace.h b/include/asm-x86_64/stacktrace.h
+new file mode 100644
+index 0000000..5eb9799
+--- /dev/null
++++ b/include/asm-x86_64/stacktrace.h
+@@ -0,0 +1,18 @@
++#ifndef _ASM_STACKTRACE_H
++#define _ASM_STACKTRACE_H 1
++
++/* Generic stack tracer with callbacks */
++
++struct stacktrace_ops {
++ void (*warning)(void *data, char *msg);
++ /* msg must contain %s for the symbol */
++ void (*warning_symbol)(void *data, char *msg, unsigned long symbol);
++ void (*address)(void *data, unsigned long address);
++ /* On negative return stop dumping */
++ int (*stack)(void *data, char *name);
++};
++
++void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack,
++ struct stacktrace_ops *ops, void *data);
++
++#endif
+diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
+index 6bf170b..bd376bc 100644
+--- a/include/asm-x86_64/system.h
++++ b/include/asm-x86_64/system.h
+@@ -14,12 +14,13 @@
+ #define __RESTORE(reg,offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t"
+
+ /* frame pointer must be last for get_wchan */
+-#define SAVE_CONTEXT "pushq %%rbp ; movq %%rsi,%%rbp\n\t"
+-#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\n\t"
++#define SAVE_CONTEXT "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
++#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
+
+ #define __EXTRA_CLOBBER \
+ ,"rcx","rbx","rdx","r8","r9","r10","r11","r12","r13","r14","r15"
+
++/* Save restore flags to clear handle leaking NT */
+ #define switch_to(prev,next,last) \
+ asm volatile(SAVE_CONTEXT \
+ "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
+diff --git a/include/asm-x86_64/tce.h b/include/asm-x86_64/tce.h
+index 53e9a68..dbb047f 100644
+--- a/include/asm-x86_64/tce.h
++++ b/include/asm-x86_64/tce.h
+@@ -24,7 +24,6 @@
+ #ifndef _ASM_X86_64_TCE_H
+ #define _ASM_X86_64_TCE_H
+
+-extern void* tce_table_kva[];
+ extern unsigned int specified_table_size;
+ struct iommu_table;
+
+diff --git a/include/asm-x86_64/therm_throt.h b/include/asm-x86_64/therm_throt.h
+new file mode 100644
+index 0000000..5aac059
+--- /dev/null
++++ b/include/asm-x86_64/therm_throt.h
+@@ -0,0 +1 @@
++#include <asm-i386/therm_throt.h>
+diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
+index 2029b00..787a081 100644
+--- a/include/asm-x86_64/thread_info.h
++++ b/include/asm-x86_64/thread_info.h
+@@ -114,11 +114,14 @@ static inline struct thread_info *stack_
+ #define TIF_IRET 5 /* force IRET */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_SECCOMP 8 /* secure computing */
++#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */
+ /* 16 free */
+ #define TIF_IA32 17 /* 32bit process */
+ #define TIF_FORK 18 /* ret_from_fork */
+ #define TIF_ABI_PENDING 19
+ #define TIF_MEMDIE 20
++#define TIF_DEBUG 21 /* uses debug registers */
++#define TIF_IO_BITMAP 22 /* uses I/O bitmap */
+
+ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
+ #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
+@@ -128,9 +131,12 @@ static inline struct thread_info *stack_
+ #define _TIF_IRET (1<<TIF_IRET)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP (1<<TIF_SECCOMP)
++#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
+ #define _TIF_IA32 (1<<TIF_IA32)
+ #define _TIF_FORK (1<<TIF_FORK)
+ #define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
++#define _TIF_DEBUG (1<<TIF_DEBUG)
++#define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+@@ -138,6 +144,9 @@ static inline struct thread_info *stack_
+ /* work to do on any return to user space */
+ #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
+
++/* flags to check in __switch_to() */
++#define _TIF_WORK_CTXSW (_TIF_DEBUG|_TIF_IO_BITMAP)
++
+ #define PREEMPT_ACTIVE 0x10000000
+
+ /*
+diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
+index d16d5b6..983bd29 100644
+--- a/include/asm-x86_64/tlbflush.h
++++ b/include/asm-x86_64/tlbflush.h
+@@ -4,44 +4,44 @@
+ #include <linux/mm.h>
+ #include <asm/processor.h>
+
+-#define __flush_tlb() \
+- do { \
+- unsigned long tmpreg; \
+- \
+- __asm__ __volatile__( \
+- "movq %%cr3, %0; # flush TLB \n" \
+- "movq %0, %%cr3; \n" \
+- : "=r" (tmpreg) \
+- :: "memory"); \
+- } while (0)
++static inline unsigned long get_cr3(void)
++{
++ unsigned long cr3;
++ asm volatile("mov %%cr3,%0" : "=r" (cr3));
++ return cr3;
++}
+
+-/*
+- * Global pages have to be flushed a bit differently. Not a real
+- * performance problem because this does not happen often.
+- */
+-#define __flush_tlb_global() \
+- do { \
+- unsigned long tmpreg, cr4, cr4_orig; \
+- \
+- __asm__ __volatile__( \
+- "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" (cr4), "=&r" (cr4_orig) \
+- : "i" (~X86_CR4_PGE) \
+- : "memory"); \
+- } while (0)
+-
+-extern unsigned long pgkern_mask;
+-
+-#define __flush_tlb_all() __flush_tlb_global()
++static inline void set_cr3(unsigned long cr3)
++{
++ asm volatile("mov %0,%%cr3" :: "r" (cr3) : "memory");
++}
++
++static inline void __flush_tlb(void)
++{
++ set_cr3(get_cr3());
++}
++
++static inline unsigned long get_cr4(void)
++{
++ unsigned long cr4;
++ asm volatile("mov %%cr4,%0" : "=r" (cr4));
++ return cr4;
++}
++
++static inline void set_cr4(unsigned long cr4)
++{
++ asm volatile("mov %0,%%cr4" :: "r" (cr4) : "memory");
++}
++
++static inline void __flush_tlb_all(void)
++{
++ unsigned long cr4 = get_cr4();
++ set_cr4(cr4 & ~X86_CR4_PGE); /* clear PGE */
++ set_cr4(cr4); /* write old PGE again and flush TLBs */
++}
+
+ #define __flush_tlb_one(addr) \
+- __asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
++ __asm__ __volatile__("invlpg (%0)" :: "r" (addr) : "memory")
+
+
+ /*
+diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
+index 6e7a2e9..5c8f492 100644
+--- a/include/asm-x86_64/topology.h
++++ b/include/asm-x86_64/topology.h
+@@ -31,6 +31,7 @@ extern int __node_distance(int, int);
+ #define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 32, \
+diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
+index 1e1fa00..19f9917 100644
+--- a/include/asm-x86_64/uaccess.h
++++ b/include/asm-x86_64/uaccess.h
+@@ -84,7 +84,7 @@ struct exception_table_entry
+ */
+
+ #define __get_user_x(size,ret,x,ptr) \
+- __asm__ __volatile__("call __get_user_" #size \
++ asm volatile("call __get_user_" #size \
+ :"=a" (ret),"=d" (x) \
+ :"c" (ptr) \
+ :"r8")
+@@ -101,7 +101,7 @@ struct exception_table_entry
+ case 8: __get_user_x(8,__ret_gu,__val_gu,ptr); break; \
+ default: __get_user_bad(); break; \
+ } \
+- (x) = (__typeof__(*(ptr)))__val_gu; \
++ (x) = (typeof(*(ptr)))__val_gu; \
+ __ret_gu; \
+ })
+
+@@ -112,7 +112,7 @@ extern void __put_user_8(void);
+ extern void __put_user_bad(void);
+
+ #define __put_user_x(size,ret,x,ptr) \
+- __asm__ __volatile__("call __put_user_" #size \
++ asm volatile("call __put_user_" #size \
+ :"=a" (ret) \
+ :"c" (ptr),"d" (x) \
+ :"r8")
+@@ -139,7 +139,7 @@ extern void __put_user_bad(void);
+ #define __put_user_check(x,ptr,size) \
+ ({ \
+ int __pu_err; \
+- __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
++ typeof(*(ptr)) __user *__pu_addr = (ptr); \
+ switch (size) { \
+ case 1: __put_user_x(1,__pu_err,x,__pu_addr); break; \
+ case 2: __put_user_x(2,__pu_err,x,__pu_addr); break; \
+@@ -173,7 +173,7 @@ struct __large_struct { unsigned long bu
+ * aliasing issues.
+ */
+ #define __put_user_asm(x, addr, err, itype, rtype, ltype, errno) \
+- __asm__ __volatile__( \
++ asm volatile( \
+ "1: mov"itype" %"rtype"1,%2\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+@@ -193,7 +193,7 @@ struct __large_struct { unsigned long bu
+ int __gu_err; \
+ unsigned long __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),__gu_err); \
+- (x) = (__typeof__(*(ptr)))__gu_val; \
++ (x) = (typeof(*(ptr)))__gu_val; \
+ __gu_err; \
+ })
+
+@@ -217,7 +217,7 @@ do { \
+ } while (0)
+
+ #define __get_user_asm(x, addr, err, itype, rtype, ltype, errno) \
+- __asm__ __volatile__( \
++ asm volatile( \
+ "1: mov"itype" %2,%"rtype"1\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+@@ -237,15 +237,20 @@ do { \
+ */
+
+ /* Handles exceptions in both to and from, but doesn't do access_ok */
+-extern unsigned long copy_user_generic(void *to, const void *from, unsigned len);
+-
+-extern unsigned long copy_to_user(void __user *to, const void *from, unsigned len);
+-extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len);
+-extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len);
+-
+-static __always_inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
++__must_check unsigned long
++copy_user_generic(void *to, const void *from, unsigned len);
++
++__must_check unsigned long
++copy_to_user(void __user *to, const void *from, unsigned len);
++__must_check unsigned long
++copy_from_user(void *to, const void __user *from, unsigned len);
++__must_check unsigned long
++copy_in_user(void __user *to, const void __user *from, unsigned len);
++
++static __always_inline __must_check
++int __copy_from_user(void *dst, const void __user *src, unsigned size)
+ {
+- int ret = 0;
++ int ret = 0;
+ if (!__builtin_constant_p(size))
+ return copy_user_generic(dst,(__force void *)src,size);
+ switch (size) {
+@@ -272,9 +277,10 @@ static __always_inline int __copy_from_u
+ }
+ }
+
+-static __always_inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
++static __always_inline __must_check
++int __copy_to_user(void __user *dst, const void *src, unsigned size)
+ {
+- int ret = 0;
++ int ret = 0;
+ if (!__builtin_constant_p(size))
+ return copy_user_generic((__force void *)dst,src,size);
+ switch (size) {
+@@ -303,10 +309,10 @@ static __always_inline int __copy_to_use
+ }
+ }
+
+-
+-static __always_inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
++static __always_inline __must_check
++int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
+ {
+- int ret = 0;
++ int ret = 0;
+ if (!__builtin_constant_p(size))
+ return copy_user_generic((__force void *)dst,(__force void *)src,size);
+ switch (size) {
+@@ -344,15 +350,22 @@ static __always_inline int __copy_in_use
+ }
+ }
+
+-long strncpy_from_user(char *dst, const char __user *src, long count);
+-long __strncpy_from_user(char *dst, const char __user *src, long count);
+-long strnlen_user(const char __user *str, long n);
+-long __strnlen_user(const char __user *str, long n);
+-long strlen_user(const char __user *str);
+-unsigned long clear_user(void __user *mem, unsigned long len);
+-unsigned long __clear_user(void __user *mem, unsigned long len);
++__must_check long
++strncpy_from_user(char *dst, const char __user *src, long count);
++__must_check long
++__strncpy_from_user(char *dst, const char __user *src, long count);
++__must_check long strnlen_user(const char __user *str, long n);
++__must_check long __strnlen_user(const char __user *str, long n);
++__must_check long strlen_user(const char __user *str);
++__must_check unsigned long clear_user(void __user *mem, unsigned long len);
++__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
+
+-#define __copy_to_user_inatomic __copy_to_user
+-#define __copy_from_user_inatomic __copy_from_user
++__must_check long __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size);
++
++static __must_check __always_inline int
++__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
++{
++ return copy_user_generic((__force void *)dst, src, size);
++}
+
+ #endif /* __X86_64_UACCESS_H */
+diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
+index 80fd48e..777288e 100644
+--- a/include/asm-x86_64/unistd.h
++++ b/include/asm-x86_64/unistd.h
+@@ -600,9 +600,9 @@ __SYSCALL(__NR_fchmodat, sys_fchmodat)
+ #define __NR_faccessat 269
+ __SYSCALL(__NR_faccessat, sys_faccessat)
+ #define __NR_pselect6 270
+-__SYSCALL(__NR_pselect6, sys_ni_syscall) /* for now */
++__SYSCALL(__NR_pselect6, sys_pselect6)
+ #define __NR_ppoll 271
+-__SYSCALL(__NR_ppoll, sys_ni_syscall) /* for now */
++__SYSCALL(__NR_ppoll, sys_ppoll)
+ #define __NR_unshare 272
+ __SYSCALL(__NR_unshare, sys_unshare)
+ #define __NR_set_robust_list 273
+@@ -620,19 +620,21 @@ __SYSCALL(__NR_vmsplice, sys_vmsplice)
+ #define __NR_move_pages 279
+ __SYSCALL(__NR_move_pages, sys_move_pages)
+
+-#ifdef __KERNEL__
+-
+ #define __NR_syscall_max __NR_move_pages
+
++#ifdef __KERNEL__
++#include <linux/err.h>
++#endif
++
+ #ifndef __NO_STUBS
+
+-/* user-visible error numbers are in the range -1 - -4095 */
++/* user-visible error numbers are in the range -1 - -MAX_ERRNO */
+
+ #define __syscall_clobber "r11","rcx","memory"
+
+ #define __syscall_return(type, res) \
+ do { \
+- if ((unsigned long)(res) >= (unsigned long)(-127)) { \
++ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
+ errno = -(res); \
+ res = -1; \
+ } \
+@@ -658,11 +660,10 @@ do { \
+ #define __ARCH_WANT_SYS_SIGPENDING
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
++#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+ #define __ARCH_WANT_SYS_TIME
+ #define __ARCH_WANT_COMPAT_SYS_TIME
+
+-#ifndef __KERNEL_SYSCALLS__
+-
+ #define __syscall "syscall"
+
+ #define _syscall0(type,name) \
+@@ -744,83 +745,7 @@ __asm__ volatile ("movq %5,%%r10 ; movq
+ __syscall_return(type,__res); \
+ }
+
+-#else /* __KERNEL_SYSCALLS__ */
+-
+-#include <linux/syscalls.h>
+-#include <asm/ptrace.h>
+-
+-/*
+- * we need this inline - forking from kernel space will result
+- * in NO COPY ON WRITE (!!!), until an execve is executed. This
+- * is no problem, but for the stack. This is handled by not letting
+- * main() use the stack at all after fork(). Thus, no function
+- * calls - which means inline code for fork too, as otherwise we
+- * would use the stack upon exit from 'fork()'.
+- *
+- * Actually only pause and fork are needed inline, so that there
+- * won't be any messing with the stack from main(), but we define
+- * some others too.
+- */
+-#define __NR__exit __NR_exit
+-
+-static inline pid_t setsid(void)
+-{
+- return sys_setsid();
+-}
+-
+-static inline ssize_t write(unsigned int fd, char * buf, size_t count)
+-{
+- return sys_write(fd, buf, count);
+-}
+-
+-static inline ssize_t read(unsigned int fd, char * buf, size_t count)
+-{
+- return sys_read(fd, buf, count);
+-}
+-
+-static inline off_t lseek(unsigned int fd, off_t offset, unsigned int origin)
+-{
+- return sys_lseek(fd, offset, origin);
+-}
+-
+-static inline long dup(unsigned int fd)
+-{
+- return sys_dup(fd);
+-}
+-
+-/* implemented in asm in arch/x86_64/kernel/entry.S */
+-extern int execve(const char *, char * const *, char * const *);
+-
+-static inline long open(const char * filename, int flags, int mode)
+-{
+- return sys_open(filename, flags, mode);
+-}
+-
+-static inline long close(unsigned int fd)
+-{
+- return sys_close(fd);
+-}
+-
+-static inline pid_t waitpid(int pid, int * wait_stat, int flags)
+-{
+- return sys_wait4(pid, wait_stat, flags, NULL);
+-}
+-
+-extern long sys_mmap(unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags,
+- unsigned long fd, unsigned long off);
+-
+-extern int sys_modify_ldt(int func, void *ptr, unsigned long bytecount);
+-
+-asmlinkage long sys_execve(char *name, char **argv, char **envp,
+- struct pt_regs regs);
+-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
+- void *parent_tid, void *child_tid,
+- struct pt_regs regs);
+-asmlinkage long sys_fork(struct pt_regs regs);
+-asmlinkage long sys_vfork(struct pt_regs regs);
+-asmlinkage long sys_pipe(int *fildes);
+-
++#ifdef __KERNEL__
+ #ifndef __ASSEMBLY__
+
+ #include <linux/linkage.h>
+@@ -837,8 +762,8 @@ asmlinkage long sys_rt_sigaction(int sig
+ size_t sigsetsize);
+
+ #endif /* __ASSEMBLY__ */
+-
+-#endif /* __KERNEL_SYSCALLS__ */
++#endif /* __KERNEL__ */
++#endif /* __NO_STUBS */
+
+ /*
+ * "Conditional" syscalls
+@@ -848,8 +773,4 @@ asmlinkage long sys_rt_sigaction(int sig
+ */
+ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+
+-#endif /* __NO_STUBS */
+-
+-#endif /* __KERNEL__ */
+-
+ #endif /* _ASM_X86_64_UNISTD_H_ */
+diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86_64/unwind.h
+index 1f6e9bf..2e7ff10 100644
+--- a/include/asm-x86_64/unwind.h
++++ b/include/asm-x86_64/unwind.h
+@@ -18,6 +18,7 @@ struct unwind_frame_info
+ {
+ struct pt_regs regs;
+ struct task_struct *task;
++ unsigned call_frame:1;
+ };
+
+ #define UNW_PC(frame) (frame)->regs.rip
+@@ -57,6 +58,10 @@ struct unwind_frame_info
+ PTREGS_INFO(r15), \
+ PTREGS_INFO(rip)
+
++#define UNW_DEFAULT_RA(raItem, dataAlign) \
++ ((raItem).where == Memory && \
++ !((raItem).value * (dataAlign) + 8))
++
+ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
+ /*const*/ struct pt_regs *regs)
+ {
+@@ -94,8 +99,8 @@ static inline int arch_unw_user_mode(con
+
+ #else
+
+-#define UNW_PC(frame) ((void)(frame), 0)
+-#define UNW_SP(frame) ((void)(frame), 0)
++#define UNW_PC(frame) ((void)(frame), 0UL)
++#define UNW_SP(frame) ((void)(frame), 0UL)
+
+ static inline int arch_unw_user_mode(const void *info)
+ {
+diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
+index 146b244..fd452fc 100644
+--- a/include/asm-x86_64/vsyscall.h
++++ b/include/asm-x86_64/vsyscall.h
+@@ -4,6 +4,7 @@
+ enum vsyscall_num {
+ __NR_vgettimeofday,
+ __NR_vtime,
++ __NR_vgetcpu,
+ };
+
+ #define VSYSCALL_START (-10UL << 20)
+@@ -15,7 +16,7 @@ enum vsyscall_num {
+ #include <linux/seqlock.h>
+
+ #define __section_vxtime __attribute__ ((unused, __section__ (".vxtime"), aligned(16)))
+-#define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
++#define __section_vgetcpu_mode __attribute__ ((unused, __section__ (".vgetcpu_mode"), aligned(16)))
+ #define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
+ #define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
+ #define __section_sysctl_vsyscall __attribute__ ((unused, __section__ (".sysctl_vsyscall"), aligned(16)))
+@@ -26,6 +27,9 @@ enum vsyscall_num {
+ #define VXTIME_HPET 2
+ #define VXTIME_PMTMR 3
+
++#define VGETCPU_RDTSCP 1
++#define VGETCPU_LSL 2
++
+ struct vxtime_data {
+ long hpet_address; /* HPET base address */
+ int last;
+@@ -40,21 +44,23 @@ struct vxtime_data {
+
+ /* vsyscall space (readonly) */
+ extern struct vxtime_data __vxtime;
++extern int __vgetcpu_mode;
+ extern struct timespec __xtime;
+ extern volatile unsigned long __jiffies;
+-extern unsigned long __wall_jiffies;
+ extern struct timezone __sys_tz;
+ extern seqlock_t __xtime_lock;
+
+ /* kernel space (writeable) */
+ extern struct vxtime_data vxtime;
+-extern unsigned long wall_jiffies;
++extern int vgetcpu_mode;
+ extern struct timezone sys_tz;
+ extern int sysctl_vsyscall;
+ extern seqlock_t xtime_lock;
+
+ extern int sysctl_vsyscall;
+
++extern void vsyscall_set_cpu(int cpu);
++
+ #define ARCH_HAVE_XTIME_LOCK 1
+
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
+index 3be701d..ffc4dcf 100644
+--- a/include/asm-xtensa/a.out.h
++++ b/include/asm-xtensa/a.out.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-xtensa/addrspace.h
++ * include/asm-xtensa/a.out.h
+ *
+ * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
+ * seems to depend on it.
+diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h
+index 5aae3f1..1e79c0e 100644
+--- a/include/asm-xtensa/cache.h
++++ b/include/asm-xtensa/cache.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-xtensa/cacheflush.h
++ * include/asm-xtensa/cache.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
+diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h
+index a91b96d..5093034 100644
+--- a/include/asm-xtensa/coprocessor.h
++++ b/include/asm-xtensa/coprocessor.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-xtensa/cpextra.h
++ * include/asm-xtensa/coprocessor.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
+diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h
+index c425f10..c39c91d 100644
+--- a/include/asm-xtensa/dma-mapping.h
++++ b/include/asm-xtensa/dma-mapping.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-xtensa/dma_mapping.h
++ * 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
+diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h
+index 3b89a77..39e6f23 100644
+--- a/include/asm-xtensa/ioctls.h
++++ b/include/asm-xtensa/ioctls.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-xtensa/ioctl.h
++ * include/asm-xtensa/ioctls.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
+diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
+index 7b15afb..b431893 100644
+--- a/include/asm-xtensa/pgtable.h
++++ b/include/asm-xtensa/pgtable.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/asm-xtensa/page.h
++ * linux/include/asm-xtensa/pgtable.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
+@@ -218,7 +218,7 @@ extern pgd_t swapper_pg_dir[PAGE_SIZE/si
+ /*
+ * 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_vaddr(pmd) ((unsigned long)(pmd_val(pmd) & PAGE_MASK))
+ #define pmd_page(pmd) virt_to_page(pmd_val(pmd))
+
+ /*
+@@ -349,7 +349,7 @@ ptep_set_wrprotect(struct mm_struct *mm,
+ /* 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))
++ ((pte_t*) pmd_page_vaddr(*(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))
+
+diff --git a/include/asm-xtensa/siginfo.h b/include/asm-xtensa/siginfo.h
+index 44f0ae7..6916248 100644
+--- a/include/asm-xtensa/siginfo.h
++++ b/include/asm-xtensa/siginfo.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/asm-xtensa/processor.h
++ * include/asm-xtensa/siginfo.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
+diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h
+index d14a375..c7b705e 100644
+--- a/include/asm-xtensa/timex.h
++++ b/include/asm-xtensa/timex.h
+@@ -31,9 +31,6 @@
+
+ #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;
+diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
+index 5e1b99d..411f810 100644
+--- a/include/asm-xtensa/unistd.h
++++ b/include/asm-xtensa/unistd.h
+@@ -402,11 +402,6 @@ __asm__ __volatile__ ( \
+ __syscall_return(type,__res); \
+ }
+
+-
+-#ifdef __KERNEL_SYSCALLS__
+-static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp)
+-#endif
+-
+ /*
+ * "Conditional" syscalls
+ *
+diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
+new file mode 100644
+index 0000000..5748aec
+--- /dev/null
++++ b/include/crypto/algapi.h
+@@ -0,0 +1,156 @@
++/*
++ * Cryptographic API for algorithms (i.e., low-level API).
++ *
++ * Copyright (c) 2006 Herbert Xu <herbert at 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
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++#ifndef _CRYPTO_ALGAPI_H
++#define _CRYPTO_ALGAPI_H
++
++#include <linux/crypto.h>
++
++struct module;
++struct seq_file;
++
++struct crypto_type {
++ unsigned int (*ctxsize)(struct crypto_alg *alg);
++ int (*init)(struct crypto_tfm *tfm);
++ void (*exit)(struct crypto_tfm *tfm);
++ void (*show)(struct seq_file *m, struct crypto_alg *alg);
++};
++
++struct crypto_instance {
++ struct crypto_alg alg;
++
++ struct crypto_template *tmpl;
++ struct hlist_node list;
++
++ void *__ctx[] CRYPTO_MINALIGN_ATTR;
++};
++
++struct crypto_template {
++ struct list_head list;
++ struct hlist_head instances;
++ struct module *module;
++
++ struct crypto_instance *(*alloc)(void *param, unsigned int len);
++ void (*free)(struct crypto_instance *inst);
++
++ char name[CRYPTO_MAX_ALG_NAME];
++};
++
++struct crypto_spawn {
++ struct list_head list;
++ struct crypto_alg *alg;
++ struct crypto_instance *inst;
++};
++
++struct scatter_walk {
++ struct scatterlist *sg;
++ unsigned int offset;
++};
++
++struct blkcipher_walk {
++ union {
++ struct {
++ struct page *page;
++ unsigned long offset;
++ } phys;
++
++ struct {
++ u8 *page;
++ u8 *addr;
++ } virt;
++ } src, dst;
++
++ struct scatter_walk in;
++ unsigned int nbytes;
++
++ struct scatter_walk out;
++ unsigned int total;
++
++ void *page;
++ u8 *buffer;
++ u8 *iv;
++
++ int flags;
++};
++
++extern const struct crypto_type crypto_blkcipher_type;
++extern const struct crypto_type crypto_hash_type;
++
++void crypto_mod_put(struct crypto_alg *alg);
++
++int crypto_register_template(struct crypto_template *tmpl);
++void crypto_unregister_template(struct crypto_template *tmpl);
++struct crypto_template *crypto_lookup_template(const char *name);
++
++int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
++ struct crypto_instance *inst);
++void crypto_drop_spawn(struct crypto_spawn *spawn);
++struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn);
++
++struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
++ u32 type, u32 mask);
++struct crypto_instance *crypto_alloc_instance(const char *name,
++ struct crypto_alg *alg);
++
++int blkcipher_walk_done(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk, int err);
++int blkcipher_walk_virt(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk);
++int blkcipher_walk_phys(struct blkcipher_desc *desc,
++ struct blkcipher_walk *walk);
++
++static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm)
++{
++ unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
++ unsigned long align = crypto_tfm_alg_alignmask(tfm);
++
++ if (align <= crypto_tfm_ctx_alignment())
++ align = 1;
++ return (void *)ALIGN(addr, align);
++}
++
++static inline void *crypto_instance_ctx(struct crypto_instance *inst)
++{
++ return inst->__ctx;
++}
++
++static inline void *crypto_blkcipher_ctx(struct crypto_blkcipher *tfm)
++{
++ return crypto_tfm_ctx(&tfm->base);
++}
++
++static inline void *crypto_blkcipher_ctx_aligned(struct crypto_blkcipher *tfm)
++{
++ return crypto_tfm_ctx_aligned(&tfm->base);
++}
++
++static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm)
++{
++ return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher;
++}
++
++static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
++{
++ return crypto_tfm_ctx_aligned(&tfm->base);
++}
++
++static inline void blkcipher_walk_init(struct blkcipher_walk *walk,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ walk->in.sg = src;
++ walk->out.sg = dst;
++ walk->total = nbytes;
++}
++
++#endif /* _CRYPTO_ALGAPI_H */
++
+diff --git a/include/crypto/twofish.h b/include/crypto/twofish.h
+new file mode 100644
+index 0000000..c408522
+--- /dev/null
++++ b/include/crypto/twofish.h
+@@ -0,0 +1,22 @@
++#ifndef _CRYPTO_TWOFISH_H
++#define _CRYPTO_TWOFISH_H
++
++#include <linux/types.h>
++
++#define TF_MIN_KEY_SIZE 16
++#define TF_MAX_KEY_SIZE 32
++#define TF_BLOCK_SIZE 16
++
++struct crypto_tfm;
++
++/* Structure for an expanded Twofish key. s contains the key-dependent
++ * S-boxes composed with the MDS matrix; w contains the eight "whitening"
++ * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
++ * that k[i] corresponds to what the Twofish paper calls K[i+8]. */
++struct twofish_ctx {
++ u32 s[4][256], w[8], k[32];
++};
++
++int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len);
++
++#endif
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 2b8a7d6..a1155a2 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -1,63 +1,347 @@
+-header-y := byteorder/ dvb/ hdlc/ isdn/ nfsd/ raid/ sunrpc/ tc_act/ \
+- netfilter/ netfilter_arp/ netfilter_bridge/ netfilter_ipv4/ \
+- netfilter_ipv6/
++header-y += byteorder/
++header-y += dvb/
++header-y += hdlc/
++header-y += isdn/
++header-y += nfsd/
++header-y += raid/
++header-y += sunrpc/
++header-y += tc_act/
++header-y += netfilter/
++header-y += netfilter_arp/
++header-y += netfilter_bridge/
++header-y += netfilter_ipv4/
++header-y += netfilter_ipv6/
+
+-header-y += affs_fs.h affs_hardblocks.h aio_abi.h a.out.h arcfb.h \
+- atmapi.h atmbr2684.h atmclip.h atm_eni.h atm_he.h \
+- atm_idt77105.h atmioc.h atmlec.h atmmpc.h atm_nicstar.h \
+- atmppp.h atmsap.h atmsvc.h atm_zatm.h auto_fs4.h auxvec.h \
+- awe_voice.h ax25.h b1lli.h baycom.h bfs_fs.h blkpg.h \
+- bpqether.h cdk.h chio.h coda_psdev.h coff.h comstats.h \
+- consolemap.h cycx_cfm.h dm-ioctl.h dn.h dqblk_v1.h \
+- dqblk_v2.h dqblk_xfs.h efs_fs_sb.h elf-fdpic.h elf.h elf-em.h \
+- fadvise.h fd.h fdreg.h ftape-header-segment.h ftape-vendors.h \
+- fuse.h futex.h genetlink.h gen_stats.h gigaset_dev.h hdsmart.h \
+- hpfs_fs.h hysdn_if.h i2c-dev.h i8k.h icmp.h \
+- if_arcnet.h if_arp.h if_bonding.h if_cablemodem.h if_fc.h \
+- if_fddi.h if.h if_hippi.h if_infiniband.h if_packet.h \
+- if_plip.h if_ppp.h if_slip.h if_strip.h if_tunnel.h in6.h \
+- in_route.h ioctl.h ip.h ipmi_msgdefs.h ip_mp_alg.h ipsec.h \
+- ipx.h irda.h isdn_divertif.h iso_fs.h ite_gpio.h ixjuser.h \
+- jffs2.h keyctl.h limits.h major.h matroxfb.h meye.h minix_fs.h \
+- mmtimer.h mqueue.h mtio.h ncp_no.h netfilter_arp.h netrom.h \
+- nfs2.h nfs4_mount.h nfs_mount.h openprom_fs.h param.h \
+- pci_ids.h pci_regs.h personality.h pfkeyv2.h pg.h pkt_cls.h \
+- pkt_sched.h posix_types.h ppdev.h prctl.h ps2esdi.h qic117.h \
+- qnxtypes.h quotaio_v1.h quotaio_v2.h radeonfb.h raw.h \
+- resource.h rose.h sctp.h smbno.h snmp.h sockios.h som.h \
+- sound.h stddef.h synclink.h telephony.h termios.h ticable.h \
+- times.h tiocl.h tipc.h toshiba.h ultrasound.h un.h utime.h \
+- utsname.h video_decoder.h video_encoder.h videotext.h vt.h \
+- wavefront.h wireless.h xattr.h x25.h zorro_ids.h
++header-y += affs_hardblocks.h
++header-y += aio_abi.h
++header-y += a.out.h
++header-y += arcfb.h
++header-y += atmapi.h
++header-y += atmbr2684.h
++header-y += atmclip.h
++header-y += atm_eni.h
++header-y += atm_he.h
++header-y += atm_idt77105.h
++header-y += atmioc.h
++header-y += atmlec.h
++header-y += atmmpc.h
++header-y += atm_nicstar.h
++header-y += atmppp.h
++header-y += atmsap.h
++header-y += atmsvc.h
++header-y += atm_zatm.h
++header-y += auto_fs4.h
++header-y += auxvec.h
++header-y += awe_voice.h
++header-y += ax25.h
++header-y += b1lli.h
++header-y += baycom.h
++header-y += bfs_fs.h
++header-y += blkpg.h
++header-y += bpqether.h
++header-y += cdk.h
++header-y += chio.h
++header-y += coda_psdev.h
++header-y += coff.h
++header-y += comstats.h
++header-y += consolemap.h
++header-y += cycx_cfm.h
++header-y += dlm_device.h
++header-y += dm-ioctl.h
++header-y += dn.h
++header-y += dqblk_v1.h
++header-y += dqblk_v2.h
++header-y += dqblk_xfs.h
++header-y += efs_fs_sb.h
++header-y += elf-fdpic.h
++header-y += elf.h
++header-y += elf-em.h
++header-y += fadvise.h
++header-y += fd.h
++header-y += fdreg.h
++header-y += fib_rules.h
++header-y += ftape-header-segment.h
++header-y += ftape-vendors.h
++header-y += fuse.h
++header-y += futex.h
++header-y += genetlink.h
++header-y += gen_stats.h
++header-y += gigaset_dev.h
++header-y += hdsmart.h
++header-y += hysdn_if.h
++header-y += i2c-dev.h
++header-y += i8k.h
++header-y += icmp.h
++header-y += if_addr.h
++header-y += if_arcnet.h
++header-y += if_arp.h
++header-y += if_bonding.h
++header-y += if_cablemodem.h
++header-y += if_fc.h
++header-y += if_fddi.h
++header-y += if.h
++header-y += if_hippi.h
++header-y += if_infiniband.h
++header-y += if_link.h
++header-y += if_packet.h
++header-y += if_plip.h
++header-y += if_ppp.h
++header-y += if_slip.h
++header-y += if_strip.h
++header-y += if_tunnel.h
++header-y += in6.h
++header-y += in_route.h
++header-y += ioctl.h
++header-y += ip.h
++header-y += ipmi_msgdefs.h
++header-y += ip_mp_alg.h
++header-y += ipsec.h
++header-y += ipx.h
++header-y += irda.h
++header-y += isdn_divertif.h
++header-y += iso_fs.h
++header-y += ixjuser.h
++header-y += jffs2.h
++header-y += keyctl.h
++header-y += limits.h
++header-y += lock_dlm_plock.h
++header-y += magic.h
++header-y += major.h
++header-y += matroxfb.h
++header-y += meye.h
++header-y += minix_fs.h
++header-y += mmtimer.h
++header-y += mqueue.h
++header-y += mtio.h
++header-y += ncp_no.h
++header-y += neighbour.h
++header-y += netfilter_arp.h
++header-y += netrom.h
++header-y += nfs2.h
++header-y += nfs4_mount.h
++header-y += nfs_mount.h
++header-y += oom.h
++header-y += param.h
++header-y += pci_ids.h
++header-y += pci_regs.h
++header-y += personality.h
++header-y += pfkeyv2.h
++header-y += pg.h
++header-y += pkt_cls.h
++header-y += pkt_sched.h
++header-y += posix_types.h
++header-y += ppdev.h
++header-y += prctl.h
++header-y += ps2esdi.h
++header-y += qic117.h
++header-y += qnxtypes.h
++header-y += quotaio_v1.h
++header-y += quotaio_v2.h
++header-y += radeonfb.h
++header-y += raw.h
++header-y += resource.h
++header-y += rose.h
++header-y += sctp.h
++header-y += smbno.h
++header-y += snmp.h
++header-y += sockios.h
++header-y += som.h
++header-y += sound.h
++header-y += synclink.h
++header-y += telephony.h
++header-y += termios.h
++header-y += ticable.h
++header-y += times.h
++header-y += tiocl.h
++header-y += tipc.h
++header-y += toshiba.h
++header-y += ultrasound.h
++header-y += un.h
++header-y += utime.h
++header-y += video_decoder.h
++header-y += video_encoder.h
++header-y += videotext.h
++header-y += vt.h
++header-y += wireless.h
++header-y += xattr.h
++header-y += x25.h
++header-y += zorro_ids.h
+
+-unifdef-y += acct.h adb.h adfs_fs.h agpgart.h apm_bios.h atalk.h \
+- atmarp.h atmdev.h atm.h atm_tcp.h audit.h auto_fs.h binfmts.h \
+- capability.h capi.h cciss_ioctl.h cdrom.h cm4000_cs.h \
+- cn_proc.h coda.h connector.h cramfs_fs.h cuda.h cyclades.h \
+- dccp.h dirent.h divert.h elfcore.h errno.h errqueue.h \
+- ethtool.h eventpoll.h ext2_fs.h ext3_fs.h fb.h fcntl.h \
+- filter.h flat.h fs.h ftape.h gameport.h generic_serial.h \
+- genhd.h hayesesp.h hdlcdrv.h hdlc.h hdreg.h hiddev.h hpet.h \
+- i2c.h i2o-dev.h icmpv6.h if_bridge.h if_ec.h \
+- if_eql.h if_ether.h if_frad.h if_ltalk.h if_pppox.h \
+- if_shaper.h if_tr.h if_tun.h if_vlan.h if_wanpipe.h igmp.h \
+- inet_diag.h in.h inotify.h input.h ipc.h ipmi.h ipv6.h \
+- ipv6_route.h isdn.h isdnif.h isdn_ppp.h isicom.h jbd.h \
+- joystick.h kdev_t.h kd.h kernelcapi.h kernel.h keyboard.h \
+- llc.h loop.h lp.h mempolicy.h mii.h mman.h mroute.h msdos_fs.h \
+- msg.h nbd.h ncp_fs.h ncp.h ncp_mount.h netdevice.h \
+- netfilter_bridge.h netfilter_decnet.h netfilter.h \
+- netfilter_ipv4.h netfilter_ipv6.h netfilter_logging.h net.h \
+- netlink.h nfs3.h nfs4.h nfsacl.h nfs_fs.h nfs.h nfs_idmap.h \
+- n_r3964.h nubus.h nvram.h parport.h patchkey.h pci.h pktcdvd.h \
+- pmu.h poll.h ppp_defs.h ppp-comp.h ptrace.h qnx4_fs.h quota.h \
+- random.h reboot.h reiserfs_fs.h reiserfs_xattr.h romfs_fs.h \
+- route.h rtc.h rtnetlink.h scc.h sched.h sdla.h \
+- selinux_netlink.h sem.h serial_core.h serial.h serio.h shm.h \
+- signal.h smb_fs.h smb.h smb_mount.h socket.h sonet.h sonypi.h \
+- soundcard.h stat.h sysctl.h tcp.h time.h timex.h tty.h types.h \
+- udf_fs_i.h udp.h uinput.h uio.h unistd.h usb_ch9.h \
+- usbdevice_fs.h user.h videodev2.h videodev.h wait.h \
+- wanrouter.h watchdog.h xfrm.h zftape.h
++unifdef-y += acct.h
++unifdef-y += adb.h
++unifdef-y += adfs_fs.h
++unifdef-y += agpgart.h
++unifdef-y += apm_bios.h
++unifdef-y += atalk.h
++unifdef-y += atmarp.h
++unifdef-y += atmdev.h
++unifdef-y += atm.h
++unifdef-y += atm_tcp.h
++unifdef-y += audit.h
++unifdef-y += auto_fs.h
++unifdef-y += binfmts.h
++unifdef-y += capability.h
++unifdef-y += capi.h
++unifdef-y += cciss_ioctl.h
++unifdef-y += cdrom.h
++unifdef-y += cm4000_cs.h
++unifdef-y += cn_proc.h
++unifdef-y += coda.h
++unifdef-y += connector.h
++unifdef-y += cramfs_fs.h
++unifdef-y += cuda.h
++unifdef-y += cyclades.h
++unifdef-y += dccp.h
++unifdef-y += dirent.h
++unifdef-y += divert.h
++unifdef-y += dlm.h
++unifdef-y += elfcore.h
++unifdef-y += errno.h
++unifdef-y += errqueue.h
++unifdef-y += ethtool.h
++unifdef-y += eventpoll.h
++unifdef-y += ext2_fs.h
++unifdef-y += ext3_fs.h
++unifdef-y += fb.h
++unifdef-y += fcntl.h
++unifdef-y += filter.h
++unifdef-y += flat.h
++unifdef-y += fs.h
++unifdef-y += ftape.h
++unifdef-y += gameport.h
++unifdef-y += generic_serial.h
++unifdef-y += genhd.h
++unifdef-y += gfs2_ondisk.h
++unifdef-y += hayesesp.h
++unifdef-y += hdlcdrv.h
++unifdef-y += hdlc.h
++unifdef-y += hdreg.h
++unifdef-y += hiddev.h
++unifdef-y += hpet.h
++unifdef-y += i2c.h
++unifdef-y += i2o-dev.h
++unifdef-y += icmpv6.h
++unifdef-y += if_bridge.h
++unifdef-y += if_ec.h
++unifdef-y += if_eql.h
++unifdef-y += if_ether.h
++unifdef-y += if_frad.h
++unifdef-y += if_ltalk.h
++unifdef-y += if_pppox.h
++unifdef-y += if_shaper.h
++unifdef-y += if_tr.h
++unifdef-y += if_tun.h
++unifdef-y += if_vlan.h
++unifdef-y += if_wanpipe.h
++unifdef-y += igmp.h
++unifdef-y += inet_diag.h
++unifdef-y += in.h
++unifdef-y += inotify.h
++unifdef-y += input.h
++unifdef-y += ipc.h
++unifdef-y += ipmi.h
++unifdef-y += ipv6.h
++unifdef-y += ipv6_route.h
++unifdef-y += isdn.h
++unifdef-y += isdnif.h
++unifdef-y += isdn_ppp.h
++unifdef-y += isicom.h
++unifdef-y += jbd.h
++unifdef-y += joystick.h
++unifdef-y += kdev_t.h
++unifdef-y += kd.h
++unifdef-y += kernelcapi.h
++unifdef-y += kernel.h
++unifdef-y += keyboard.h
++unifdef-y += llc.h
++unifdef-y += loop.h
++unifdef-y += lp.h
++unifdef-y += mempolicy.h
++unifdef-y += mii.h
++unifdef-y += mman.h
++unifdef-y += mroute.h
++unifdef-y += msdos_fs.h
++unifdef-y += msg.h
++unifdef-y += nbd.h
++unifdef-y += ncp_fs.h
++unifdef-y += ncp.h
++unifdef-y += ncp_mount.h
++unifdef-y += netdevice.h
++unifdef-y += netfilter_bridge.h
++unifdef-y += netfilter_decnet.h
++unifdef-y += netfilter.h
++unifdef-y += netfilter_ipv4.h
++unifdef-y += netfilter_ipv6.h
++unifdef-y += net.h
++unifdef-y += netlink.h
++unifdef-y += nfs3.h
++unifdef-y += nfs4.h
++unifdef-y += nfsacl.h
++unifdef-y += nfs_fs.h
++unifdef-y += nfs.h
++unifdef-y += nfs_idmap.h
++unifdef-y += n_r3964.h
++unifdef-y += nubus.h
++unifdef-y += nvram.h
++unifdef-y += parport.h
++unifdef-y += patchkey.h
++unifdef-y += pci.h
++unifdef-y += pktcdvd.h
++unifdef-y += pmu.h
++unifdef-y += poll.h
++unifdef-y += ppp_defs.h
++unifdef-y += ppp-comp.h
++unifdef-y += ptrace.h
++unifdef-y += qnx4_fs.h
++unifdef-y += quota.h
++unifdef-y += random.h
++unifdef-y += reboot.h
++unifdef-y += reiserfs_fs.h
++unifdef-y += reiserfs_xattr.h
++unifdef-y += romfs_fs.h
++unifdef-y += route.h
++unifdef-y += rtc.h
++unifdef-y += rtnetlink.h
++unifdef-y += scc.h
++unifdef-y += sched.h
++unifdef-y += sdla.h
++unifdef-y += selinux_netlink.h
++unifdef-y += sem.h
++unifdef-y += serial_core.h
++unifdef-y += serial.h
++unifdef-y += serio.h
++unifdef-y += shm.h
++unifdef-y += signal.h
++unifdef-y += smb_fs.h
++unifdef-y += smb.h
++unifdef-y += smb_mount.h
++unifdef-y += socket.h
++unifdef-y += sonet.h
++unifdef-y += sonypi.h
++unifdef-y += soundcard.h
++unifdef-y += stat.h
++unifdef-y += stddef.h
++unifdef-y += sysctl.h
++unifdef-y += tcp.h
++unifdef-y += time.h
++unifdef-y += timex.h
++unifdef-y += tty.h
++unifdef-y += types.h
++unifdef-y += udf_fs_i.h
++unifdef-y += udp.h
++unifdef-y += uinput.h
++unifdef-y += uio.h
++unifdef-y += unistd.h
++unifdef-y += usb_ch9.h
++unifdef-y += usbdevice_fs.h
++unifdef-y += user.h
++unifdef-y += utsname.h
++unifdef-y += videodev2.h
++unifdef-y += videodev.h
++unifdef-y += wait.h
++unifdef-y += wanrouter.h
++unifdef-y += watchdog.h
++unifdef-y += xfrm.h
++unifdef-y += zftape.h
+
+-objhdr-y := version.h
++objhdr-y += version.h
+diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
+index 2ed2fd8..22eb936 100644
+--- a/include/linux/ac97_codec.h
++++ b/include/linux/ac97_codec.h
+@@ -331,8 +331,6 @@ extern int ac97_read_proc (char *page_ou
+ extern int ac97_probe_codec(struct ac97_codec *);
+ extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
+ extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
+-extern int ac97_save_state(struct ac97_codec *codec);
+-extern int ac97_restore_state(struct ac97_codec *codec);
+
+ extern struct ac97_codec *ac97_alloc_codec(void);
+ extern void ac97_release_codec(struct ac97_codec *codec);
+@@ -346,9 +344,6 @@ struct ac97_driver {
+ void (*remove) (struct ac97_codec *codec, struct ac97_driver *driver);
+ };
+
+-extern int ac97_register_driver(struct ac97_driver *driver);
+-extern void ac97_unregister_driver(struct ac97_driver *driver);
+-
+ /* quirk types */
+ enum {
+ AC97_TUNE_DEFAULT = -1, /* use default from quirk list (not valid in list) */
+diff --git a/include/linux/acct.h b/include/linux/acct.h
+index e86bae7..0496d1f 100644
+--- a/include/linux/acct.h
++++ b/include/linux/acct.h
+@@ -124,16 +124,12 @@ extern void acct_auto_close(struct super
+ extern void acct_init_pacct(struct pacct_struct *pacct);
+ extern void acct_collect(long exitcode, int group_dead);
+ extern void acct_process(void);
+-extern void acct_update_integrals(struct task_struct *tsk);
+-extern void acct_clear_integrals(struct task_struct *tsk);
+ #else
+ #define acct_auto_close_mnt(x) do { } while (0)
+ #define acct_auto_close(x) do { } while (0)
+ #define acct_init_pacct(x) do { } while (0)
+ #define acct_collect(x,y) do { } while (0)
+ #define acct_process() do { } while (0)
+-#define acct_update_integrals(x) do { } while (0)
+-#define acct_clear_integrals(task) do { } while (0)
+ #endif
+
+ /*
+diff --git a/include/linux/acpi.h b/include/linux/acpi.h
+index 88b5dfd..2b0c955 100644
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct a
+
+ extern int ec_read(u8 addr, u8 *val);
+ extern int ec_write(u8 addr, u8 val);
++extern int ec_transaction(u8 command,
++ const u8 *wdata, unsigned wdata_len,
++ u8 *rdata, unsigned rdata_len);
+
+ #endif /*CONFIG_ACPI_EC*/
+
+diff --git a/include/linux/adb.h b/include/linux/adb.h
+index b7305b1..64d8878 100644
+--- a/include/linux/adb.h
++++ b/include/linux/adb.h
+@@ -90,10 +90,10 @@ extern struct blocking_notifier_head adb
+ int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
+ int flags, int nbytes, ...);
+ int adb_register(int default_id,int handler_id,struct adb_ids *ids,
+- void (*handler)(unsigned char *, int, struct pt_regs *, int));
++ void (*handler)(unsigned char *, int, int));
+ int adb_unregister(int index);
+ void adb_poll(void);
+-void adb_input(unsigned char *, int, struct pt_regs *, int);
++void adb_input(unsigned char *, int, int);
+ int adb_reset_bus(void);
+
+ int adb_try_handler_change(int address, int new_id);
+diff --git a/include/linux/adfs_fs.h b/include/linux/adfs_fs.h
+index 4a5d50c..ef788c2 100644
+--- a/include/linux/adfs_fs.h
++++ b/include/linux/adfs_fs.h
+@@ -2,6 +2,7 @@
+ #define _ADFS_FS_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
+
+ /*
+ * Disc Record at disc address 0xc00
+@@ -38,7 +39,6 @@ struct adfs_discrecord {
+ #define ADFS_DR_OFFSET (0x1c0)
+ #define ADFS_DR_SIZE 60
+ #define ADFS_DR_SIZE_BITS (ADFS_DR_SIZE << 3)
+-#define ADFS_SUPER_MAGIC 0xadf5
+
+ #ifdef __KERNEL__
+ #include <linux/adfs_fs_i.h>
+diff --git a/include/linux/aer.h b/include/linux/aer.h
+new file mode 100644
+index 0000000..402e178
+--- /dev/null
++++ b/include/linux/aer.h
+@@ -0,0 +1,24 @@
++/*
++ * Copyright (C) 2006 Intel Corp.
++ * Tom Long Nguyen (tom.l.nguyen at intel.com)
++ * Zhang Yanmin (yanmin.zhang at intel.com)
++ */
++
++#ifndef _AER_H_
++#define _AER_H_
++
++#if defined(CONFIG_PCIEAER)
++/* pci-e port driver needs this function to enable aer */
++extern int pci_enable_pcie_error_reporting(struct pci_dev *dev);
++extern int pci_find_aer_capability(struct pci_dev *dev);
++extern int pci_disable_pcie_error_reporting(struct pci_dev *dev);
++extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
++#else
++#define pci_enable_pcie_error_reporting(dev) do { } while (0)
++#define pci_find_aer_capability(dev) do { } while (0)
++#define pci_disable_pcie_error_reporting(dev) do { } while (0)
++#define pci_cleanup_aer_uncorrect_error_status(dev) do { } while (0)
++#endif
++
++#endif //_AER_H_
++
+diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h
+deleted file mode 100644
+index c57b5ee..0000000
+--- a/include/linux/affs_fs.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef _AFFS_FS_H
+-#define _AFFS_FS_H
+-/*
+- * The affs filesystem constants/structures
+- */
+-#define AFFS_SUPER_MAGIC 0xadff
+-#endif
+diff --git a/include/linux/aio.h b/include/linux/aio.h
+index 00c8efa..0d71c00 100644
+--- a/include/linux/aio.h
++++ b/include/linux/aio.h
+@@ -4,8 +4,10 @@
+ #include <linux/list.h>
+ #include <linux/workqueue.h>
+ #include <linux/aio_abi.h>
++#include <linux/uio.h>
+
+ #include <asm/atomic.h>
++#include <linux/uio.h>
+
+ #define AIO_MAXSEGS 4
+ #define AIO_KIOGRP_NR_ATOMIC 8
+@@ -110,8 +112,10 @@ struct kiocb {
+ char __user *ki_buf; /* remaining iocb->aio_buf */
+ size_t ki_left; /* remaining bytes */
+ long ki_retried; /* just for testing */
+- long ki_kicked; /* just for testing */
+- long ki_queued; /* just for testing */
++ struct iovec ki_inline_vec; /* inline vector */
++ struct iovec *ki_iovec;
++ unsigned long ki_nr_segs;
++ unsigned long ki_cur_seg;
+
+ struct list_head ki_list; /* the aio core uses this
+ * for cancellation */
+@@ -213,11 +217,11 @@ int FASTCALL(io_submit_one(struct kioctx
+ struct iocb *iocb));
+
+ #define get_ioctx(kioctx) do { \
+- BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
++ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
+ atomic_inc(&(kioctx)->users); \
+ } while (0)
+ #define put_ioctx(kioctx) do { \
+- BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
++ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
+ if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \
+ __put_ioctx(kioctx); \
+ } while (0)
+diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
+index 30fdcc8..e3ca0a4 100644
+--- a/include/linux/aio_abi.h
++++ b/include/linux/aio_abi.h
+@@ -1,4 +1,4 @@
+-/* linux/aio_abi.h
++/* include/linux/aio_abi.h
+ *
+ * Copyright 2000,2001,2002 Red Hat.
+ *
+@@ -41,6 +41,8 @@ enum {
+ * IOCB_CMD_POLL = 5,
+ */
+ IOCB_CMD_NOOP = 6,
++ IOCB_CMD_PREADV = 7,
++ IOCB_CMD_PWRITEV = 8,
+ };
+
+ /* read() from /dev/aio returns these structures. */
+diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h
+index 231ba09..2f85049 100644
+--- a/include/linux/arcdevice.h
++++ b/include/linux/arcdevice.h
+@@ -334,7 +334,7 @@ void arcnet_dump_skb(struct net_device *
+ #endif
+
+ void arcnet_unregister_proto(struct ArcProto *proto);
+-irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t arcnet_interrupt(int irq, void *dev_id);
+ struct net_device *alloc_arcdev(char *name);
+
+ #endif /* __KERNEL__ */
+diff --git a/include/linux/ata.h b/include/linux/ata.h
+index 3671af8..d894419 100644
+--- a/include/linux/ata.h
++++ b/include/linux/ata.h
+@@ -40,6 +40,8 @@ enum {
+ ATA_MAX_DEVICES = 2, /* per bus/port */
+ ATA_MAX_PRD = 256, /* we could make these 256/256 */
+ ATA_SECT_SIZE = 512,
++ ATA_MAX_SECTORS = 256,
++ ATA_MAX_SECTORS_LBA48 = 65535,/* TODO: 65536? */
+
+ ATA_ID_WORDS = 256,
+ ATA_ID_SERNO_OFS = 10,
+@@ -168,12 +170,16 @@ enum {
+ XFER_UDMA_2 = 0x42,
+ XFER_UDMA_1 = 0x41,
+ XFER_UDMA_0 = 0x40,
++ XFER_MW_DMA_4 = 0x24, /* CFA only */
++ XFER_MW_DMA_3 = 0x23, /* CFA only */
+ XFER_MW_DMA_2 = 0x22,
+ XFER_MW_DMA_1 = 0x21,
+ XFER_MW_DMA_0 = 0x20,
+ XFER_SW_DMA_2 = 0x12,
+ XFER_SW_DMA_1 = 0x11,
+ XFER_SW_DMA_0 = 0x10,
++ XFER_PIO_6 = 0x0E, /* CFA only */
++ XFER_PIO_5 = 0x0D, /* CFA only */
+ XFER_PIO_4 = 0x0C,
+ XFER_PIO_3 = 0x0B,
+ XFER_PIO_2 = 0x0A,
+@@ -272,7 +278,6 @@ struct ata_taskfile {
+ };
+
+ #define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0)
+-#define ata_id_is_cfa(id) ((id)[0] == 0x848A)
+ #define ata_id_is_sata(id) ((id)[93] == 0)
+ #define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
+ #define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
+@@ -304,6 +309,9 @@ static inline unsigned int ata_id_major_
+ {
+ unsigned int mver;
+
++ if (id[ATA_ID_MAJOR_VER] == 0xFFFF)
++ return 0;
++
+ for (mver = 14; mver >= 1; mver--)
+ if (id[ATA_ID_MAJOR_VER] & (1 << mver))
+ break;
+@@ -312,8 +320,8 @@ static inline unsigned int ata_id_major_
+
+ static inline int ata_id_current_chs_valid(const u16 *id)
+ {
+- /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
+- has not been issued to the device then the values of
++ /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
++ has not been issued to the device then the values of
+ id[54] to id[56] are vendor specific. */
+ return (id[53] & 0x01) && /* Current translation valid */
+ id[54] && /* cylinders in current translation */
+@@ -322,6 +330,18 @@ static inline int ata_id_current_chs_val
+ id[56]; /* sectors in current translation */
+ }
+
++static inline int ata_id_is_cfa(const u16 *id)
++{
++ u16 v = id[0];
++ if (v == 0x848A) /* Standard CF */
++ return 1;
++ /* Could be CF hiding as standard ATA */
++ if (ata_id_major_version(id) >= 3 && id[82] != 0xFFFF &&
++ (id[82] & ( 1 << 2)))
++ return 1;
++ return 0;
++}
++
+ static inline int atapi_cdb_len(const u16 *dev_id)
+ {
+ u16 tmp = dev_id[0] & 0x3;
+diff --git a/include/linux/atalk.h b/include/linux/atalk.h
+index 6ba3aa8..75b8bac 100644
+--- a/include/linux/atalk.h
++++ b/include/linux/atalk.h
+@@ -88,15 +88,7 @@ static inline struct atalk_sock *at_sk(s
+ #include <asm/byteorder.h>
+
+ struct ddpehdr {
+-#ifdef __LITTLE_ENDIAN_BITFIELD
+- __u16 deh_len:10,
+- deh_hops:4,
+- deh_pad:2;
+-#else
+- __u16 deh_pad:2,
+- deh_hops:4,
+- deh_len:10;
+-#endif
++ __be16 deh_len_hops; /* lower 10 bits are length, next 4 - hops */
+ __be16 deh_sum;
+ __be16 deh_dnet;
+ __be16 deh_snet;
+@@ -112,36 +104,6 @@ static __inline__ struct ddpehdr *ddp_hd
+ return (struct ddpehdr *)skb->h.raw;
+ }
+
+-/*
+- * Don't drop the struct into the struct above. You'll get some
+- * surprise padding.
+- */
+-struct ddpebits {
+-#ifdef __LITTLE_ENDIAN_BITFIELD
+- __u16 deh_len:10,
+- deh_hops:4,
+- deh_pad:2;
+-#else
+- __u16 deh_pad:2,
+- deh_hops:4,
+- deh_len:10;
+-#endif
+-};
+-
+-/* Short form header */
+-struct ddpshdr {
+-#ifdef __LITTLE_ENDIAN_BITFIELD
+- __u16 dsh_len:10,
+- dsh_pad:6;
+-#else
+- __u16 dsh_pad:6,
+- dsh_len:10;
+-#endif
+- __u8 dsh_dport;
+- __u8 dsh_sport;
+- /* And netatalk apps expect to stick the type in themselves */
+-};
+-
+ /* AppleTalk AARP headers */
+ struct elapaarp {
+ __be16 hw_type;
+diff --git a/include/linux/atmlec.h b/include/linux/atmlec.h
+index f267f24..6f5a1ba 100644
+--- a/include/linux/atmlec.h
++++ b/include/linux/atmlec.h
+@@ -1,9 +1,7 @@
+ /*
+- *
+- * ATM Lan Emulation Daemon vs. driver interface
+- *
+- * mkiiskila at yahoo.com
++ * ATM Lan Emulation Daemon driver interface
+ *
++ * Marko Kiiskila <mkiiskila at yahoo.com>
+ */
+
+ #ifndef _ATMLEC_H_
+@@ -13,76 +11,87 @@
+ #include <linux/atmioc.h>
+ #include <linux/atm.h>
+ #include <linux/if_ether.h>
++
+ /* ATM lec daemon control socket */
+-#define ATMLEC_CTRL _IO('a',ATMIOC_LANE)
+-#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1)
+-#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2)
++#define ATMLEC_CTRL _IO('a', ATMIOC_LANE)
++#define ATMLEC_DATA _IO('a', ATMIOC_LANE+1)
++#define ATMLEC_MCAST _IO('a', ATMIOC_LANE+2)
+
+ /* Maximum number of LEC interfaces (tweakable) */
+ #define MAX_LEC_ITF 48
+
+-/* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
++/*
++ * From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
+ * E.g. if MAX_LEC_ITF = 48 and NUM_TR_DEVS = 8, then lec0-lec39 are for
+ * Ethernet ELANs and lec40-lec47 are for Token Ring ELANS.
+ */
+ #define NUM_TR_DEVS 8
+
+-typedef enum {
+- l_set_mac_addr, l_del_mac_addr,
+- l_svc_setup,
+- l_addr_delete, l_topology_change,
+- l_flush_complete, l_arp_update,
+- l_narp_req, /* LANE2 mandates the use of this */
+- l_config, l_flush_tran_id,
+- l_set_lecid, l_arp_xmt,
+- l_rdesc_arp_xmt,
+- l_associate_req,
+- l_should_bridge /* should we bridge this MAC? */
++typedef enum {
++ l_set_mac_addr,
++ l_del_mac_addr,
++ l_svc_setup,
++ l_addr_delete,
++ l_topology_change,
++ l_flush_complete,
++ l_arp_update,
++ l_narp_req, /* LANE2 mandates the use of this */
++ l_config,
++ l_flush_tran_id,
++ l_set_lecid,
++ l_arp_xmt,
++ l_rdesc_arp_xmt,
++ l_associate_req,
++ l_should_bridge /* should we bridge this MAC? */
+ } atmlec_msg_type;
+
+ #define ATMLEC_MSG_TYPE_MAX l_should_bridge
+
+ struct atmlec_config_msg {
+- unsigned int maximum_unknown_frame_count;
+- unsigned int max_unknown_frame_time;
+- unsigned short max_retry_count;
+- unsigned int aging_time;
+- unsigned int forward_delay_time;
+- unsigned int arp_response_time;
+- unsigned int flush_timeout;
+- unsigned int path_switching_delay;
+- unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */
+- int mtu;
+- int is_proxy;
++ unsigned int maximum_unknown_frame_count;
++ unsigned int max_unknown_frame_time;
++ unsigned short max_retry_count;
++ unsigned int aging_time;
++ unsigned int forward_delay_time;
++ unsigned int arp_response_time;
++ unsigned int flush_timeout;
++ unsigned int path_switching_delay;
++ unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */
++ int mtu;
++ int is_proxy;
+ };
+-
++
+ struct atmlec_msg {
+- atmlec_msg_type type;
+- int sizeoftlvs; /* LANE2: if != 0, tlvs follow */
+- union {
+- struct {
+- unsigned char mac_addr[ETH_ALEN];
+- unsigned char atm_addr[ATM_ESA_LEN];
+- unsigned int flag;/* Topology_change flag,
+- remoteflag, permanent flag,
+- lecid, transaction id */
+- unsigned int targetless_le_arp; /* LANE2 */
+- unsigned int no_source_le_narp; /* LANE2 */
+- } normal;
+- struct atmlec_config_msg config;
+- struct {
+- uint16_t lec_id; /* requestor lec_id */
+- uint32_t tran_id; /* transaction id */
+- unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */
+- unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */
+- } proxy;
+- /* For mapping LE_ARP requests to responses. Filled by */
+- } content; /* zeppelin, returned by kernel. Used only when proxying */
++ atmlec_msg_type type;
++ int sizeoftlvs; /* LANE2: if != 0, tlvs follow */
++ union {
++ struct {
++ unsigned char mac_addr[ETH_ALEN];
++ unsigned char atm_addr[ATM_ESA_LEN];
++ unsigned int flag; /*
++ * Topology_change flag,
++ * remoteflag, permanent flag,
++ * lecid, transaction id
++ */
++ unsigned int targetless_le_arp; /* LANE2 */
++ unsigned int no_source_le_narp; /* LANE2 */
++ } normal;
++ struct atmlec_config_msg config;
++ struct {
++ uint16_t lec_id; /* requestor lec_id */
++ uint32_t tran_id; /* transaction id */
++ unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */
++ unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */
++ } proxy; /*
++ * For mapping LE_ARP requests to responses. Filled by
++ * zeppelin, returned by kernel. Used only when proxying
++ */
++ } content;
+ } __ATM_API_ALIGN;
+
+ struct atmlec_ioc {
+- int dev_num;
+- unsigned char atm_addr[ATM_ESA_LEN];
+- unsigned char receive; /* 1= receive vcc, 0 = send vcc */
++ int dev_num;
++ unsigned char atm_addr[ATM_ESA_LEN];
++ unsigned char receive; /* 1= receive vcc, 0 = send vcc */
+ };
+ #endif /* _ATMLEC_H_ */
+diff --git a/include/linux/audit.h b/include/linux/audit.h
+index 40a6c26..b2ca666 100644
+--- a/include/linux/audit.h
++++ b/include/linux/audit.h
+@@ -75,7 +75,7 @@
+ #define AUDIT_DAEMON_CONFIG 1203 /* Daemon config change */
+
+ #define AUDIT_SYSCALL 1300 /* Syscall event */
+-#define AUDIT_FS_WATCH 1301 /* Filesystem watch event */
++/* #define AUDIT_FS_WATCH 1301 * Deprecated */
+ #define AUDIT_PATH 1302 /* Filename path information */
+ #define AUDIT_IPC 1303 /* IPC record */
+ #define AUDIT_SOCKETCALL 1304 /* sys_socketcall arguments */
+@@ -88,6 +88,7 @@
+ #define AUDIT_MQ_SENDRECV 1313 /* POSIX MQ send/receive record type */
+ #define AUDIT_MQ_NOTIFY 1314 /* POSIX MQ notify record type */
+ #define AUDIT_MQ_GETSETATTR 1315 /* POSIX MQ get/set attribute record type */
++#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */
+
+ #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
+ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
+@@ -95,6 +96,11 @@
+ #define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */
+ #define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */
+ #define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */
++#define AUDIT_MAC_UNLBL_ALLOW 1406 /* NetLabel: allow unlabeled traffic */
++#define AUDIT_MAC_CIPSOV4_ADD 1407 /* NetLabel: add CIPSOv4 DOI entry */
++#define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */
++#define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */
++#define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */
+
+ #define AUDIT_FIRST_KERN_ANOM_MSG 1700
+ #define AUDIT_LAST_KERN_ANOM_MSG 1799
+diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h
+index 4bf9f33..bf33f17 100644
+--- a/include/linux/awe_voice.h
++++ b/include/linux/awe_voice.h
+@@ -1,5 +1,5 @@
+ /*
+- * sound/awe_voice.h
++ * include/linux/awe_voice.h
+ *
+ * Voice information definitions for the low level driver for the
+ * AWE32/SB32/AWE64 wave table synth.
+diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
+index f7a1390..7011d62 100644
+--- a/include/linux/backing-dev.h
++++ b/include/linux/backing-dev.h
+@@ -10,6 +10,8 @@
+
+ #include <asm/atomic.h>
+
++struct page;
++
+ /*
+ * Bits in backing_dev_info.state
+ */
+@@ -88,6 +90,11 @@ static inline int bdi_rw_congested(struc
+ (1 << BDI_write_congested));
+ }
+
++void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
++void set_bdi_congested(struct backing_dev_info *bdi, int rw);
++long congestion_wait(int rw, long timeout);
++void congestion_end(int rw);
++
+ #define bdi_cap_writeback_dirty(bdi) \
+ (!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
+
+diff --git a/include/linux/bio.h b/include/linux/bio.h
+index 76bdaea..092dbd0 100644
+--- a/include/linux/bio.h
++++ b/include/linux/bio.h
+@@ -70,7 +70,8 @@ typedef void (bio_destructor_t) (struct
+ * stacking drivers)
+ */
+ struct bio {
+- sector_t bi_sector;
++ sector_t bi_sector; /* device address in 512 byte
++ sectors */
+ struct bio *bi_next; /* request queue link */
+ struct block_device *bi_bdev;
+ unsigned long bi_flags; /* status, command, etc */
+@@ -148,6 +149,7 @@ struct bio {
+ #define BIO_RW_BARRIER 2
+ #define BIO_RW_FAILFAST 3
+ #define BIO_RW_SYNC 4
++#define BIO_RW_META 5
+
+ /*
+ * upper 16 bits of bi_rw define the io priority of this bio
+@@ -178,6 +180,7 @@ struct bio {
+ #define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC))
+ #define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
+ #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD))
++#define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META))
+
+ /*
+ * will die
+diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
+index dcc5de7..64b4641 100644
+--- a/include/linux/bitmap.h
++++ b/include/linux/bitmap.h
+@@ -46,7 +46,8 @@
+ * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
+ * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
+ * bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf
+- * bitmap_parse(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf
++ * bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf
++ * bitmap_parse_user(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf
+ * bitmap_scnlistprintf(buf, len, src, nbits) Print bitmap src as list to buf
+ * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from list
+ * bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region
+@@ -106,7 +107,9 @@ extern int __bitmap_weight(const unsigne
+
+ extern int bitmap_scnprintf(char *buf, unsigned int len,
+ const unsigned long *src, int nbits);
+-extern int bitmap_parse(const char __user *ubuf, unsigned int ulen,
++extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
++ unsigned long *dst, int nbits);
++extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
+ unsigned long *dst, int nbits);
+ extern int bitmap_scnlistprintf(char *buf, unsigned int len,
+ const unsigned long *src, int nbits);
+@@ -270,6 +273,12 @@ static inline void bitmap_shift_left(uns
+ __bitmap_shift_left(dst, src, n, nbits);
+ }
+
++static inline int bitmap_parse(const char *buf, unsigned int buflen,
++ unsigned long *maskp, int nmaskbits)
++{
++ return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
++}
++
+ #endif /* __ASSEMBLY__ */
+
+ #endif /* __LINUX_BITMAP_H */
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index aafe827..7bfcde2 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -1,6 +1,7 @@
+ #ifndef _LINUX_BLKDEV_H
+ #define _LINUX_BLKDEV_H
+
++#include <linux/sched.h>
+ #include <linux/major.h>
+ #include <linux/genhd.h>
+ #include <linux/list.h>
+@@ -16,6 +17,22 @@
+
+ #include <asm/scatterlist.h>
+
++#ifdef CONFIG_LBD
++# include <asm/div64.h>
++# define sector_div(a, b) do_div(a, b)
++#else
++# define sector_div(n, b)( \
++{ \
++ int _res; \
++ _res = (n) % (b); \
++ (n) /= (b); \
++ _res; \
++} \
++)
++#endif
++
++#ifdef CONFIG_BLOCK
++
+ struct scsi_ioctl_command;
+
+ struct request_queue;
+@@ -90,7 +107,7 @@ struct io_context {
+ atomic_t refcount;
+ struct task_struct *task;
+
+- int (*set_ioprio)(struct io_context *, unsigned int);
++ unsigned int ioprio_changed;
+
+ /*
+ * For request batching
+@@ -104,8 +121,7 @@ struct io_context {
+
+ void put_io_context(struct io_context *ioc);
+ void exit_io_context(void);
+-struct io_context *current_io_context(gfp_t gfp_flags);
+-struct io_context *get_io_context(gfp_t gfp_flags);
++struct io_context *get_io_context(gfp_t gfp_flags, int node);
+ void copy_io_context(struct io_context **pdst, struct io_context **psrc);
+ void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
+
+@@ -120,6 +136,91 @@ struct request_list {
+ wait_queue_head_t wait[2];
+ };
+
++/*
++ * request command types
++ */
++enum rq_cmd_type_bits {
++ REQ_TYPE_FS = 1, /* fs request */
++ REQ_TYPE_BLOCK_PC, /* scsi command */
++ REQ_TYPE_SENSE, /* sense request */
++ REQ_TYPE_PM_SUSPEND, /* suspend request */
++ REQ_TYPE_PM_RESUME, /* resume request */
++ REQ_TYPE_PM_SHUTDOWN, /* shutdown request */
++ REQ_TYPE_FLUSH, /* flush request */
++ REQ_TYPE_SPECIAL, /* driver defined type */
++ REQ_TYPE_LINUX_BLOCK, /* generic block layer message */
++ /*
++ * for ATA/ATAPI devices. this really doesn't belong here, ide should
++ * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver
++ * private REQ_LB opcodes to differentiate what type of request this is
++ */
++ REQ_TYPE_ATA_CMD,
++ REQ_TYPE_ATA_TASK,
++ REQ_TYPE_ATA_TASKFILE,
++ REQ_TYPE_ATA_PC,
++};
++
++/*
++ * For request of type REQ_TYPE_LINUX_BLOCK, rq->cmd[0] is the opcode being
++ * sent down (similar to how REQ_TYPE_BLOCK_PC means that ->cmd[] holds a
++ * SCSI cdb.
++ *
++ * 0x00 -> 0x3f are driver private, to be used for whatever purpose they need,
++ * typically to differentiate REQ_TYPE_SPECIAL requests.
++ *
++ */
++enum {
++ /*
++ * just examples for now
++ */
++ REQ_LB_OP_EJECT = 0x40, /* eject request */
++ REQ_LB_OP_FLUSH = 0x41, /* flush device */
++};
++
++/*
++ * request type modified bits. first three bits match BIO_RW* bits, important
++ */
++enum rq_flag_bits {
++ __REQ_RW, /* not set, read. set, write */
++ __REQ_FAILFAST, /* no low level driver retries */
++ __REQ_SORTED, /* elevator knows about this request */
++ __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */
++ __REQ_HARDBARRIER, /* may not be passed by drive either */
++ __REQ_FUA, /* forced unit access */
++ __REQ_NOMERGE, /* don't touch this for merging */
++ __REQ_STARTED, /* drive already may have started this one */
++ __REQ_DONTPREP, /* don't call prep for this one */
++ __REQ_QUEUED, /* uses queueing */
++ __REQ_ELVPRIV, /* elevator private data attached */
++ __REQ_FAILED, /* set if the request failed */
++ __REQ_QUIET, /* don't worry about errors */
++ __REQ_PREEMPT, /* set for "ide_preempt" requests */
++ __REQ_ORDERED_COLOR, /* is before or after barrier */
++ __REQ_RW_SYNC, /* request is sync (O_DIRECT) */
++ __REQ_ALLOCED, /* request came from our alloc pool */
++ __REQ_RW_META, /* metadata io request */
++ __REQ_NR_BITS, /* stops here */
++};
++
++#define REQ_RW (1 << __REQ_RW)
++#define REQ_FAILFAST (1 << __REQ_FAILFAST)
++#define REQ_SORTED (1 << __REQ_SORTED)
++#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER)
++#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER)
++#define REQ_FUA (1 << __REQ_FUA)
++#define REQ_NOMERGE (1 << __REQ_NOMERGE)
++#define REQ_STARTED (1 << __REQ_STARTED)
++#define REQ_DONTPREP (1 << __REQ_DONTPREP)
++#define REQ_QUEUED (1 << __REQ_QUEUED)
++#define REQ_ELVPRIV (1 << __REQ_ELVPRIV)
++#define REQ_FAILED (1 << __REQ_FAILED)
++#define REQ_QUIET (1 << __REQ_QUIET)
++#define REQ_PREEMPT (1 << __REQ_PREEMPT)
++#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR)
++#define REQ_RW_SYNC (1 << __REQ_RW_SYNC)
++#define REQ_ALLOCED (1 << __REQ_ALLOCED)
++#define REQ_RW_META (1 << __REQ_RW_META)
++
+ #define BLK_MAX_CDB 16
+
+ /*
+@@ -129,30 +230,46 @@ struct request {
+ struct list_head queuelist;
+ struct list_head donelist;
+
+- unsigned long flags; /* see REQ_ bits below */
++ request_queue_t *q;
++
++ unsigned int cmd_flags;
++ enum rq_cmd_type_bits cmd_type;
+
+ /* Maintain bio traversal state for part by part I/O submission.
+ * hard_* are block layer internals, no driver should touch them!
+ */
+
+ sector_t sector; /* next sector to submit */
++ sector_t hard_sector; /* next sector to complete */
+ unsigned long nr_sectors; /* no. of sectors left to submit */
++ unsigned long hard_nr_sectors; /* no. of sectors left to complete */
+ /* no. of sectors left to submit in the current segment */
+ unsigned int current_nr_sectors;
+
+- sector_t hard_sector; /* next sector to complete */
+- unsigned long hard_nr_sectors; /* no. of sectors left to complete */
+ /* no. of sectors left to complete in the current segment */
+ unsigned int hard_cur_sectors;
+
+ struct bio *bio;
+ struct bio *biotail;
+
++ struct hlist_node hash; /* merge hash */
++ /*
++ * The rb_node is only used inside the io scheduler, requests
++ * are pruned when moved to the dispatch queue. So let the
++ * completion_data share space with the rb_node.
++ */
++ union {
++ struct rb_node rb_node; /* sort/lookup */
++ void *completion_data;
++ };
++
++ /*
++ * two pointers are available for the IO schedulers, if they need
++ * more they have to dynamically allocate it.
++ */
+ void *elevator_private;
+- void *completion_data;
++ void *elevator_private2;
+
+- int rq_status; /* should split this into a few status bits */
+- int errors;
+ struct gendisk *rq_disk;
+ unsigned long start_time;
+
+@@ -170,15 +287,13 @@ struct request {
+
+ unsigned short ioprio;
+
++ void *special;
++ char *buffer;
++
+ int tag;
++ int errors;
+
+ int ref_count;
+- request_queue_t *q;
+- struct request_list *rl;
+-
+- struct completion *waiting;
+- void *special;
+- char *buffer;
+
+ /*
+ * when request is used as a packet command carrier
+@@ -195,80 +310,14 @@ struct request {
+ int retries;
+
+ /*
+- * completion callback. end_io_data should be folded in with waiting
++ * completion callback.
+ */
+ rq_end_io_fn *end_io;
+ void *end_io_data;
+ };
+
+ /*
+- * first three bits match BIO_RW* bits, important
+- */
+-enum rq_flag_bits {
+- __REQ_RW, /* not set, read. set, write */
+- __REQ_FAILFAST, /* no low level driver retries */
+- __REQ_SORTED, /* elevator knows about this request */
+- __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */
+- __REQ_HARDBARRIER, /* may not be passed by drive either */
+- __REQ_FUA, /* forced unit access */
+- __REQ_CMD, /* is a regular fs rw request */
+- __REQ_NOMERGE, /* don't touch this for merging */
+- __REQ_STARTED, /* drive already may have started this one */
+- __REQ_DONTPREP, /* don't call prep for this one */
+- __REQ_QUEUED, /* uses queueing */
+- __REQ_ELVPRIV, /* elevator private data attached */
+- /*
+- * for ATA/ATAPI devices
+- */
+- __REQ_PC, /* packet command (special) */
+- __REQ_BLOCK_PC, /* queued down pc from block layer */
+- __REQ_SENSE, /* sense retrival */
+-
+- __REQ_FAILED, /* set if the request failed */
+- __REQ_QUIET, /* don't worry about errors */
+- __REQ_SPECIAL, /* driver suplied command */
+- __REQ_DRIVE_CMD,
+- __REQ_DRIVE_TASK,
+- __REQ_DRIVE_TASKFILE,
+- __REQ_PREEMPT, /* set for "ide_preempt" requests */
+- __REQ_PM_SUSPEND, /* suspend request */
+- __REQ_PM_RESUME, /* resume request */
+- __REQ_PM_SHUTDOWN, /* shutdown request */
+- __REQ_ORDERED_COLOR, /* is before or after barrier */
+- __REQ_RW_SYNC, /* request is sync (O_DIRECT) */
+- __REQ_NR_BITS, /* stops here */
+-};
+-
+-#define REQ_RW (1 << __REQ_RW)
+-#define REQ_FAILFAST (1 << __REQ_FAILFAST)
+-#define REQ_SORTED (1 << __REQ_SORTED)
+-#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER)
+-#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER)
+-#define REQ_FUA (1 << __REQ_FUA)
+-#define REQ_CMD (1 << __REQ_CMD)
+-#define REQ_NOMERGE (1 << __REQ_NOMERGE)
+-#define REQ_STARTED (1 << __REQ_STARTED)
+-#define REQ_DONTPREP (1 << __REQ_DONTPREP)
+-#define REQ_QUEUED (1 << __REQ_QUEUED)
+-#define REQ_ELVPRIV (1 << __REQ_ELVPRIV)
+-#define REQ_PC (1 << __REQ_PC)
+-#define REQ_BLOCK_PC (1 << __REQ_BLOCK_PC)
+-#define REQ_SENSE (1 << __REQ_SENSE)
+-#define REQ_FAILED (1 << __REQ_FAILED)
+-#define REQ_QUIET (1 << __REQ_QUIET)
+-#define REQ_SPECIAL (1 << __REQ_SPECIAL)
+-#define REQ_DRIVE_CMD (1 << __REQ_DRIVE_CMD)
+-#define REQ_DRIVE_TASK (1 << __REQ_DRIVE_TASK)
+-#define REQ_DRIVE_TASKFILE (1 << __REQ_DRIVE_TASKFILE)
+-#define REQ_PREEMPT (1 << __REQ_PREEMPT)
+-#define REQ_PM_SUSPEND (1 << __REQ_PM_SUSPEND)
+-#define REQ_PM_RESUME (1 << __REQ_PM_RESUME)
+-#define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN)
+-#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR)
+-#define REQ_RW_SYNC (1 << __REQ_RW_SYNC)
+-
+-/*
+- * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
++ * State information carried for REQ_TYPE_PM_SUSPEND and REQ_TYPE_PM_RESUME
+ * requests. Some step values could eventually be made generic.
+ */
+ struct request_pm_state
+@@ -417,9 +466,9 @@ struct request_queue
+ unsigned int sg_timeout;
+ unsigned int sg_reserved_size;
+ int node;
+-
++#ifdef CONFIG_BLK_DEV_IO_TRACE
+ struct blk_trace *blk_trace;
+-
++#endif
+ /*
+ * reserved for flush operations
+ */
+@@ -432,9 +481,6 @@ struct request_queue
+ struct mutex sysfs_lock;
+ };
+
+-#define RQ_INACTIVE (-1)
+-#define RQ_ACTIVE 1
+-
+ #define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */
+ #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */
+ #define QUEUE_FLAG_STOPPED 2 /* queue is stopped */
+@@ -490,25 +536,34 @@ enum {
+ #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
+ #define blk_queue_flushing(q) ((q)->ordseq)
+
+-#define blk_fs_request(rq) ((rq)->flags & REQ_CMD)
+-#define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC)
+-#define blk_noretry_request(rq) ((rq)->flags & REQ_FAILFAST)
+-#define blk_rq_started(rq) ((rq)->flags & REQ_STARTED)
++#define blk_fs_request(rq) ((rq)->cmd_type == REQ_TYPE_FS)
++#define blk_pc_request(rq) ((rq)->cmd_type == REQ_TYPE_BLOCK_PC)
++#define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL)
++#define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE)
++
++#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST)
++#define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED)
+
+ #define blk_account_rq(rq) (blk_rq_started(rq) && blk_fs_request(rq))
+
+-#define blk_pm_suspend_request(rq) ((rq)->flags & REQ_PM_SUSPEND)
+-#define blk_pm_resume_request(rq) ((rq)->flags & REQ_PM_RESUME)
++#define blk_pm_suspend_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_SUSPEND)
++#define blk_pm_resume_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_RESUME)
+ #define blk_pm_request(rq) \
+- ((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME))
++ (blk_pm_suspend_request(rq) || blk_pm_resume_request(rq))
+
+-#define blk_sorted_rq(rq) ((rq)->flags & REQ_SORTED)
+-#define blk_barrier_rq(rq) ((rq)->flags & REQ_HARDBARRIER)
+-#define blk_fua_rq(rq) ((rq)->flags & REQ_FUA)
++#define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED)
++#define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER)
++#define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA)
+
+ #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist)
+
+-#define rq_data_dir(rq) ((rq)->flags & 1)
++#define rq_data_dir(rq) ((rq)->cmd_flags & 1)
++
++/*
++ * We regard a request as sync, if it's a READ or a SYNC write.
++ */
++#define rq_is_sync(rq) (rq_data_dir((rq)) == READ || (rq)->cmd_flags & REQ_RW_SYNC)
++#define rq_is_meta(rq) ((rq)->cmd_flags & REQ_RW_META)
+
+ static inline int blk_queue_full(struct request_queue *q, int rw)
+ {
+@@ -541,13 +596,7 @@ static inline void blk_clear_queue_full(
+ #define RQ_NOMERGE_FLAGS \
+ (REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER)
+ #define rq_mergeable(rq) \
+- (!((rq)->flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq)))
+-
+-/*
+- * noop, requests are automagically marked as active/inactive by I/O
+- * scheduler -- see elv_next_request
+- */
+-#define blk_queue_headactive(q, head_active)
++ (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq)))
+
+ /*
+ * q->prep_rq_fn return values
+@@ -586,11 +635,6 @@ static inline void blk_queue_bounce(requ
+ if ((rq->bio)) \
+ for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next)
+
+-struct sec_size {
+- unsigned block_size;
+- unsigned block_size_bits;
+-};
+-
+ extern int blk_register_queue(struct gendisk *disk);
+ extern void blk_unregister_queue(struct gendisk *disk);
+ extern void register_disk(struct gendisk *dev);
+@@ -607,11 +651,32 @@ extern void blk_recount_segments(request
+ extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
+ extern int sg_scsi_ioctl(struct file *, struct request_queue *,
+ struct gendisk *, struct scsi_ioctl_command __user *);
++
++/*
++ * A queue has just exitted congestion. Note this in the global counter of
++ * congested queues, and wake up anyone who was waiting for requests to be
++ * put back.
++ */
++static inline void blk_clear_queue_congested(request_queue_t *q, int rw)
++{
++ clear_bdi_congested(&q->backing_dev_info, rw);
++}
++
++/*
++ * A queue has just entered congestion. Flag that in the queue's VM-visible
++ * state flags and increment the global gounter of congested queues.
++ */
++static inline void blk_set_queue_congested(request_queue_t *q, int rw)
++{
++ set_bdi_congested(&q->backing_dev_info, rw);
++}
++
+ extern void blk_start_queue(request_queue_t *q);
+ extern void blk_stop_queue(request_queue_t *q);
+ extern void blk_sync_queue(struct request_queue *q);
+ extern void __blk_stop_queue(request_queue_t *q);
+ extern void blk_run_queue(request_queue_t *);
++extern void blk_start_queueing(request_queue_t *);
+ extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
+ extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int);
+ extern int blk_rq_unmap_user(struct bio *, unsigned int);
+@@ -655,16 +720,6 @@ extern void end_that_request_last(struct
+ extern void end_request(struct request *req, int uptodate);
+ extern void blk_complete_request(struct request *);
+
+-static inline int rq_all_done(struct request *rq, unsigned int nr_bytes)
+-{
+- if (blk_fs_request(rq))
+- return (nr_bytes >= (rq->hard_nr_sectors << 9));
+- else if (blk_pc_request(rq))
+- return nr_bytes >= rq->data_len;
+-
+- return 0;
+-}
+-
+ /*
+ * end_that_request_first/chunk() takes an uptodate argument. we account
+ * any value <= as an io error. 0 means -EIO for compatability reasons,
+@@ -679,21 +734,6 @@ static inline void blkdev_dequeue_reques
+ }
+
+ /*
+- * This should be in elevator.h, but that requires pulling in rq and q
+- */
+-static inline void elv_dispatch_add_tail(struct request_queue *q,
+- struct request *rq)
+-{
+- if (q->last_merge == rq)
+- q->last_merge = NULL;
+- q->nr_sorted--;
+-
+- q->end_sector = rq_end_sector(rq);
+- q->boundary_rq = rq;
+- list_add_tail(&rq->queuelist, &q->queue_head);
+-}
+-
+-/*
+ * Access functions for manipulating queue properties
+ */
+ extern request_queue_t *blk_init_queue_node(request_fn_proc *rfn,
+@@ -737,7 +777,7 @@ extern void blk_put_queue(request_queue_
+ */
+ #define blk_queue_tag_depth(q) ((q)->queue_tags->busy)
+ #define blk_queue_tag_queue(q) ((q)->queue_tags->busy < (q)->queue_tags->max_depth)
+-#define blk_rq_tagged(rq) ((rq)->flags & REQ_QUEUED)
++#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED)
+ extern int blk_queue_start_tag(request_queue_t *, struct request *);
+ extern struct request *blk_queue_find_tag(request_queue_t *, int);
+ extern void blk_queue_end_tag(request_queue_t *, struct request *);
+@@ -745,7 +785,16 @@ extern int blk_queue_init_tags(request_q
+ extern void blk_queue_free_tags(request_queue_t *);
+ extern int blk_queue_resize_tags(request_queue_t *, int);
+ extern void blk_queue_invalidate_tags(request_queue_t *);
+-extern long blk_congestion_wait(int rw, long timeout);
++extern struct blk_queue_tag *blk_init_tags(int);
++extern void blk_free_tags(struct blk_queue_tag *);
++
++static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
++ int tag)
++{
++ if (unlikely(bqt == NULL || tag >= bqt->real_max_depth))
++ return NULL;
++ return bqt->tag_index[tag];
++}
+
+ extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
+ extern int blkdev_issue_flush(struct block_device *, sector_t *);
+@@ -784,14 +833,6 @@ static inline int queue_dma_alignment(re
+ return retval;
+ }
+
+-static inline int bdev_dma_aligment(struct block_device *bdev)
+-{
+- return queue_dma_alignment(bdev_get_queue(bdev));
+-}
+-
+-#define blk_finished_io(nsects) do { } while (0)
+-#define blk_started_io(nsects) do { } while (0)
+-
+ /* assumes size > 256 */
+ static inline unsigned int blksize_bits(unsigned int size)
+ {
+@@ -821,24 +862,32 @@ struct work_struct;
+ int kblockd_schedule_work(struct work_struct *work);
+ void kblockd_flush(void);
+
+-#ifdef CONFIG_LBD
+-# include <asm/div64.h>
+-# define sector_div(a, b) do_div(a, b)
+-#else
+-# define sector_div(n, b)( \
+-{ \
+- int _res; \
+- _res = (n) % (b); \
+- (n) /= (b); \
+- _res; \
+-} \
+-)
+-#endif
+-
+ #define MODULE_ALIAS_BLOCKDEV(major,minor) \
+ MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
+ #define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \
+ MODULE_ALIAS("block-major-" __stringify(major) "-*")
+
+
++#else /* CONFIG_BLOCK */
++/*
++ * stubs for when the block layer is configured out
++ */
++#define buffer_heads_over_limit 0
++
++static inline long blk_congestion_wait(int rw, long timeout)
++{
++ return io_schedule_timeout(timeout);
++}
++
++static inline long nr_blockdev_pages(void)
++{
++ return 0;
++}
++
++static inline void exit_io_context(void)
++{
++}
++
++#endif /* CONFIG_BLOCK */
++
+ #endif
+diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
+index 7520cc1..b99a714 100644
+--- a/include/linux/blktrace_api.h
++++ b/include/linux/blktrace_api.h
+@@ -20,6 +20,7 @@ enum blktrace_cat {
+ BLK_TC_PC = 1 << 9, /* pc requests */
+ BLK_TC_NOTIFY = 1 << 10, /* special message */
+ BLK_TC_AHEAD = 1 << 11, /* readahead */
++ BLK_TC_META = 1 << 12, /* metadata */
+
+ BLK_TC_END = 1 << 15, /* only 16-bits, reminder */
+ };
+@@ -148,7 +149,7 @@ static inline void blk_add_trace_rq(stru
+ u32 what)
+ {
+ struct blk_trace *bt = q->blk_trace;
+- int rw = rq->flags & 0x03;
++ int rw = rq->cmd_flags & 0x03;
+
+ if (likely(!bt))
+ return;
+diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
+index 1021f50..31e9abb 100644
+--- a/include/linux/bootmem.h
++++ b/include/linux/bootmem.h
+@@ -4,11 +4,8 @@
+ #ifndef _LINUX_BOOTMEM_H
+ #define _LINUX_BOOTMEM_H
+
+-#include <asm/pgtable.h>
+-#include <asm/dma.h>
+-#include <linux/cache.h>
+-#include <linux/init.h>
+ #include <linux/mmzone.h>
++#include <asm/dma.h>
+
+ /*
+ * simple boot-time physical memory area allocator.
+@@ -41,45 +38,64 @@ typedef struct bootmem_data {
+ struct list_head list;
+ } bootmem_data_t;
+
+-extern unsigned long __init bootmem_bootmap_pages (unsigned long);
+-extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend);
+-extern void __init free_bootmem (unsigned long addr, unsigned long size);
+-extern void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal);
+-extern void * __init __alloc_bootmem_nopanic (unsigned long size, unsigned long align, unsigned long goal);
+-extern void * __init __alloc_bootmem_low(unsigned long size,
+- unsigned long align,
+- unsigned long goal);
+-extern void * __init __alloc_bootmem_low_node(pg_data_t *pgdat,
+- unsigned long size,
+- unsigned long align,
+- unsigned long goal);
+-extern void * __init __alloc_bootmem_core(struct bootmem_data *bdata,
+- unsigned long size, unsigned long align, unsigned long goal,
+- unsigned long limit);
++extern unsigned long bootmem_bootmap_pages(unsigned long);
++extern unsigned long init_bootmem(unsigned long addr, unsigned long memend);
++extern void free_bootmem(unsigned long addr, unsigned long size);
++extern void *__alloc_bootmem(unsigned long size,
++ unsigned long align,
++ unsigned long goal);
++extern void *__alloc_bootmem_nopanic(unsigned long size,
++ unsigned long align,
++ unsigned long goal);
++extern void *__alloc_bootmem_low(unsigned long size,
++ unsigned long align,
++ unsigned long goal);
++extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
++ unsigned long size,
++ unsigned long align,
++ unsigned long goal);
++extern void *__alloc_bootmem_core(struct bootmem_data *bdata,
++ unsigned long size,
++ unsigned long align,
++ unsigned long goal,
++ unsigned long limit);
++
+ #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
+-extern void __init reserve_bootmem (unsigned long addr, unsigned long size);
++extern void reserve_bootmem(unsigned long addr, unsigned long size);
+ #define alloc_bootmem(x) \
+- __alloc_bootmem((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
++ __alloc_bootmem(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+ #define alloc_bootmem_low(x) \
+- __alloc_bootmem_low((x), SMP_CACHE_BYTES, 0)
++ __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0)
+ #define alloc_bootmem_pages(x) \
+- __alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
++ __alloc_bootmem(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+ #define alloc_bootmem_low_pages(x) \
+- __alloc_bootmem_low((x), PAGE_SIZE, 0)
++ __alloc_bootmem_low(x, PAGE_SIZE, 0)
+ #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
+-extern unsigned long __init free_all_bootmem (void);
+-extern void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal);
+-extern unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn);
+-extern void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size);
+-extern void __init free_bootmem_node (pg_data_t *pgdat, unsigned long addr, unsigned long size);
+-extern unsigned long __init free_all_bootmem_node (pg_data_t *pgdat);
++
++extern unsigned long free_all_bootmem(void);
++extern unsigned long free_all_bootmem_node(pg_data_t *pgdat);
++extern void *__alloc_bootmem_node(pg_data_t *pgdat,
++ unsigned long size,
++ unsigned long align,
++ unsigned long goal);
++extern unsigned long init_bootmem_node(pg_data_t *pgdat,
++ unsigned long freepfn,
++ unsigned long startpfn,
++ unsigned long endpfn);
++extern void reserve_bootmem_node(pg_data_t *pgdat,
++ unsigned long physaddr,
++ unsigned long size);
++extern void free_bootmem_node(pg_data_t *pgdat,
++ unsigned long addr,
++ unsigned long size);
++
+ #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
+ #define alloc_bootmem_node(pgdat, x) \
+- __alloc_bootmem_node((pgdat), (x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
++ __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+ #define alloc_bootmem_pages_node(pgdat, x) \
+- __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
++ __alloc_bootmem_node(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+ #define alloc_bootmem_low_pages_node(pgdat, x) \
+- __alloc_bootmem_low_node((pgdat), (x), PAGE_SIZE, 0)
++ __alloc_bootmem_low_node(pgdat, x, PAGE_SIZE, 0)
+ #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
+
+ #ifdef CONFIG_HAVE_ARCH_ALLOC_REMAP
+@@ -89,19 +105,19 @@ static inline void *alloc_remap(int nid,
+ {
+ return NULL;
+ }
+-#endif
++#endif /* CONFIG_HAVE_ARCH_ALLOC_REMAP */
+
+ extern unsigned long __meminitdata nr_kernel_pages;
+ extern unsigned long nr_all_pages;
+
+-extern void *__init alloc_large_system_hash(const char *tablename,
+- unsigned long bucketsize,
+- unsigned long numentries,
+- int scale,
+- int flags,
+- unsigned int *_hash_shift,
+- unsigned int *_hash_mask,
+- unsigned long limit);
++extern void *alloc_large_system_hash(const char *tablename,
++ unsigned long bucketsize,
++ unsigned long numentries,
++ int scale,
++ int flags,
++ unsigned int *_hash_shift,
++ unsigned int *_hash_mask,
++ unsigned long limit);
+
+ #define HASH_HIGHMEM 0x00000001 /* Consider highmem? */
+ #define HASH_EARLY 0x00000002 /* Allocating during early boot? */
+@@ -114,7 +130,7 @@ extern void *__init alloc_large_system_h
+ #else
+ #define HASHDIST_DEFAULT 0
+ #endif
+-extern int __initdata hashdist; /* Distribute hashes across NUMA nodes? */
++extern int hashdist; /* Distribute hashes across NUMA nodes? */
+
+
+ #endif /* _LINUX_BOOTMEM_H */
+diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
+index 737e407..5d9fb0e 100644
+--- a/include/linux/buffer_head.h
++++ b/include/linux/buffer_head.h
+@@ -14,6 +14,8 @@
+ #include <linux/wait.h>
+ #include <asm/atomic.h>
+
++#ifdef CONFIG_BLOCK
++
+ enum bh_state_bits {
+ BH_Uptodate, /* Contains valid data */
+ BH_Dirty, /* Is dirty */
+@@ -67,6 +69,8 @@ struct buffer_head {
+ bh_end_io_t *b_end_io; /* I/O completion */
+ void *b_private; /* reserved for b_end_io */
+ struct list_head b_assoc_buffers; /* associated with another mapping */
++ struct address_space *b_assoc_map; /* mapping this buffer is
++ associated with */
+ atomic_t b_count; /* users using this buffer_head */
+ };
+
+@@ -190,9 +194,7 @@ extern int buffer_heads_over_limit;
+ * Generic address_space_operations implementations for buffer_head-backed
+ * address_spaces.
+ */
+-int try_to_release_page(struct page * page, gfp_t gfp_mask);
+ void block_invalidatepage(struct page *page, unsigned long offset);
+-void do_invalidatepage(struct page *page, unsigned long offset);
+ int block_write_full_page(struct page *page, get_block_t *get_block,
+ struct writeback_control *wbc);
+ int block_read_full_page(struct page*, get_block_t*);
+@@ -302,4 +304,19 @@ static inline void lock_buffer(struct bu
+ __lock_buffer(bh);
+ }
+
++extern int __set_page_dirty_buffers(struct page *page);
++
++#else /* CONFIG_BLOCK */
++
++static inline void buffer_init(void) {}
++static inline int try_to_free_buffers(struct page *page) { return 1; }
++static inline int sync_blockdev(struct block_device *bdev) { return 0; }
++static inline int inode_has_buffers(struct inode *inode) { return 0; }
++static inline void invalidate_inode_buffers(struct inode *inode) {}
++static inline int remove_inode_buffers(struct inode *inode) { return 1; }
++static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; }
++static inline void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers) {}
++
++
++#endif /* CONFIG_BLOCK */
+ #endif /* _LINUX_BUFFER_HEAD_H */
+diff --git a/include/linux/byteorder/Kbuild b/include/linux/byteorder/Kbuild
+index 84a57d4..56499ab 100644
+--- a/include/linux/byteorder/Kbuild
++++ b/include/linux/byteorder/Kbuild
+@@ -1,2 +1,7 @@
+-unifdef-y += generic.h swabb.h swab.h
+-header-y += big_endian.h little_endian.h pdp_endian.h
++header-y += big_endian.h
++header-y += little_endian.h
++header-y += pdp_endian.h
++
++unifdef-y += generic.h
++unifdef-y += swabb.h
++unifdef-y += swab.h
+diff --git a/include/linux/carta_random32.h b/include/linux/carta_random32.h
+new file mode 100644
+index 0000000..f6f3bd9
+--- /dev/null
++++ b/include/linux/carta_random32.h
+@@ -0,0 +1,29 @@
++/*
++ * Fast, simple, yet decent quality random number generator based on
++ * a paper by David G. Carta ("Two Fast Implementations of the
++ * `Minimal Standard' Random Number Generator," Communications of the
++ * ACM, January, 1990).
++ *
++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian at hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * 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 _LINUX_CARTA_RANDOM32_H_
++#define _LINUX_CARTA_RANDOM32_H_
++
++u64 carta_random32(u64 seed);
++
++#endif /* _LINUX_CARTA_RANDOM32_H_ */
+diff --git a/include/linux/cdev.h b/include/linux/cdev.h
+index 2216638..ee5f53f 100644
+--- a/include/linux/cdev.h
++++ b/include/linux/cdev.h
+@@ -23,5 +23,7 @@ void cdev_del(struct cdev *);
+
+ void cd_forget(struct inode *);
+
++extern struct backing_dev_info directly_mappable_cdev_bdi;
++
+ #endif
+ #endif
+diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
+index 3c9b0bc..bbbe7b4 100644
+--- a/include/linux/cdrom.h
++++ b/include/linux/cdrom.h
+@@ -749,7 +749,7 @@ struct request_sense {
+ #define MRW_MODE_PC 0x03
+
+ struct mrw_feature_desc {
+- __u16 feature_code;
++ __be16 feature_code;
+ #if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved1 : 2;
+ __u8 feature_version : 4;
+@@ -776,7 +776,7 @@ struct mrw_feature_desc {
+
+ /* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */
+ struct rwrt_feature_desc {
+- __u16 feature_code;
++ __be16 feature_code;
+ #if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved1 : 2;
+ __u8 feature_version : 4;
+@@ -803,7 +803,7 @@ struct rwrt_feature_desc {
+ };
+
+ typedef struct {
+- __u16 disc_information_length;
++ __be16 disc_information_length;
+ #if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved1 : 3;
+ __u8 erasable : 1;
+@@ -849,7 +849,7 @@ typedef struct {
+ } disc_information;
+
+ typedef struct {
+- __u16 track_information_length;
++ __be16 track_information_length;
+ __u8 track_lsb;
+ __u8 session_lsb;
+ __u8 reserved1;
+@@ -880,12 +880,12 @@ typedef struct {
+ __u8 lra_v : 1;
+ __u8 reserved3 : 6;
+ #endif
+- __u32 track_start;
+- __u32 next_writable;
+- __u32 free_blocks;
+- __u32 fixed_packet_size;
+- __u32 track_size;
+- __u32 last_rec_address;
++ __be32 track_start;
++ __be32 next_writable;
++ __be32 free_blocks;
++ __be32 fixed_packet_size;
++ __be32 track_size;
++ __be32 last_rec_address;
+ } track_information;
+
+ struct feature_header {
+@@ -896,12 +896,12 @@ struct feature_header {
+ };
+
+ struct mode_page_header {
+- __u16 mode_data_length;
++ __be16 mode_data_length;
+ __u8 medium_type;
+ __u8 reserved1;
+ __u8 reserved2;
+ __u8 reserved3;
+- __u16 desc_length;
++ __be16 desc_length;
+ };
+
+ #ifdef __KERNEL__
+@@ -1106,7 +1106,7 @@ typedef struct {
+ #endif
+ __u8 session_format;
+ __u8 reserved6;
+- __u32 packet_size;
++ __be32 packet_size;
+ __u16 audio_pause;
+ __u8 mcn[16];
+ __u8 isrc[16];
+@@ -1151,7 +1151,7 @@ typedef struct {
+ } rpc_state_t;
+
+ struct event_header {
+- __u16 data_len;
++ __be16 data_len;
+ #if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 nea : 1;
+ __u8 reserved1 : 4;
+diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
+index 98f6c52..b541bb3 100644
+--- a/include/linux/coda_psdev.h
++++ b/include/linux/coda_psdev.h
+@@ -1,11 +1,11 @@
+ #ifndef __CODA_PSDEV_H
+ #define __CODA_PSDEV_H
+
++#include <linux/magic.h>
++
+ #define CODA_PSDEV_MAJOR 67
+ #define MAX_CODADEVS 5 /* how many do we allow */
+
+-#define CODA_SUPER_MAGIC 0x73757245
+-
+ struct kstatfs;
+
+ struct coda_sb_info
+diff --git a/include/linux/compat.h b/include/linux/compat.h
+index 9760753..80b17f4 100644
+--- a/include/linux/compat.h
++++ b/include/linux/compat.h
+@@ -13,6 +13,7 @@
+
+ #include <asm/compat.h>
+ #include <asm/siginfo.h>
++#include <asm/signal.h>
+
+ #define compat_jiffies_to_clock_t(x) \
+ (((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
+@@ -162,7 +163,7 @@ asmlinkage long
+ compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
+ compat_size_t len);
+ asmlinkage long
+-compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
++compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
+ compat_size_t __user *len_ptr);
+
+ long compat_sys_semctl(int first, int second, int third, void __user *uptr);
+@@ -195,7 +196,7 @@ asmlinkage long compat_sys_select(int n,
+ #define BITS_TO_COMPAT_LONGS(bits) \
+ (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
+
+-long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask,
++long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
+ unsigned long bitmap_size);
+ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
+ unsigned long bitmap_size);
+@@ -227,6 +228,11 @@ static inline int compat_timespec_compar
+ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
+
+ extern int compat_printk(const char *fmt, ...);
++extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
++
++asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
++ compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes,
++ const compat_ulong_t __user *new_nodes);
+
+ #endif /* CONFIG_COMPAT */
+ #endif /* _LINUX_COMPAT_H */
+diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
+index bea0255..c26c3ad 100644
+--- a/include/linux/compat_ioctl.h
++++ b/include/linux/compat_ioctl.h
+@@ -61,17 +61,23 @@ COMPATIBLE_IOCTL(FIGETBSZ)
+ * Some need translations, these do not.
+ */
+ COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
+-COMPATIBLE_IOCTL(HDIO_SET_DMA)
+-COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
+-COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
+-COMPATIBLE_IOCTL(HDIO_SET_32BIT)
+-COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
+-COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+ COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
+-COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
+-COMPATIBLE_IOCTL(HDIO_SET_NICE)
+-COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
++COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
++ULONG_IOCTL(HDIO_SET_MULTCOUNT)
++ULONG_IOCTL(HDIO_SET_UNMASKINTR)
++ULONG_IOCTL(HDIO_SET_KEEPSETTINGS)
++ULONG_IOCTL(HDIO_SET_32BIT)
++ULONG_IOCTL(HDIO_SET_NOWERR)
++ULONG_IOCTL(HDIO_SET_DMA)
++ULONG_IOCTL(HDIO_SET_PIO_MODE)
++ULONG_IOCTL(HDIO_SET_NICE)
++ULONG_IOCTL(HDIO_SET_WCACHE)
++ULONG_IOCTL(HDIO_SET_ACOUSTIC)
++ULONG_IOCTL(HDIO_SET_BUSSTATE)
++ULONG_IOCTL(HDIO_SET_ADDRESS)
+ COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
++/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
++COMPATIBLE_IOCTL(0x330)
+ /* 0x02 -- Floppy ioctls */
+ COMPATIBLE_IOCTL(FDMSGON)
+ COMPATIBLE_IOCTL(FDMSGOFF)
+@@ -90,6 +96,7 @@ COMPATIBLE_IOCTL(FDTWADDLE)
+ COMPATIBLE_IOCTL(FDFMTTRK)
+ COMPATIBLE_IOCTL(FDRAWCMD)
+ /* 0x12 */
++#ifdef CONFIG_BLOCK
+ COMPATIBLE_IOCTL(BLKRASET)
+ COMPATIBLE_IOCTL(BLKROSET)
+ COMPATIBLE_IOCTL(BLKROGET)
+@@ -103,6 +110,7 @@ COMPATIBLE_IOCTL(BLKTRACESETUP)
+ COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
+ ULONG_IOCTL(BLKRASET)
+ ULONG_IOCTL(BLKFRASET)
++#endif
+ /* RAID */
+ COMPATIBLE_IOCTL(RAID_VERSION)
+ COMPATIBLE_IOCTL(GET_ARRAY_INFO)
+@@ -120,10 +128,11 @@ COMPATIBLE_IOCTL(PROTECT_ARRAY)
+ ULONG_IOCTL(HOT_ADD_DISK)
+ ULONG_IOCTL(SET_DISK_FAULTY)
+ COMPATIBLE_IOCTL(RUN_ARRAY)
+-ULONG_IOCTL(START_ARRAY)
+ COMPATIBLE_IOCTL(STOP_ARRAY)
+ COMPATIBLE_IOCTL(STOP_ARRAY_RO)
+ COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
++COMPATIBLE_IOCTL(GET_BITMAP_FILE)
++ULONG_IOCTL(SET_BITMAP_FILE)
+ /* DM */
+ COMPATIBLE_IOCTL(DM_VERSION_32)
+ COMPATIBLE_IOCTL(DM_REMOVE_ALL_32)
+@@ -395,12 +404,6 @@ COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+ COMPATIBLE_IOCTL(DVD_AUTH)
+ /* pktcdvd */
+ COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
+-/* Big L */
+-ULONG_IOCTL(LOOP_SET_FD)
+-ULONG_IOCTL(LOOP_CHANGE_FD)
+-COMPATIBLE_IOCTL(LOOP_CLR_FD)
+-COMPATIBLE_IOCTL(LOOP_GET_STATUS64)
+-COMPATIBLE_IOCTL(LOOP_SET_STATUS64)
+ /* Big A */
+ /* sparc only */
+ /* Big Q for sound/OSS */
+@@ -573,18 +576,6 @@ COMPATIBLE_IOCTL(RAW_SETBIND)
+ COMPATIBLE_IOCTL(RAW_GETBIND)
+ /* SMB ioctls which do not need any translations */
+ COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+-/* NCP ioctls which do not need any translations */
+-COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
+-COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
+-COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED)
+-COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED)
+-COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK)
+-COMPATIBLE_IOCTL(NCP_IOC_GETROOT)
+-COMPATIBLE_IOCTL(NCP_IOC_SETROOT)
+-COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS)
+-COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS)
+-COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL)
+-COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL)
+ /* Little a */
+ COMPATIBLE_IOCTL(ATMSIGD_CTRL)
+ COMPATIBLE_IOCTL(ATMARPD_CTRL)
+diff --git a/include/linux/compiler.h b/include/linux/compiler.h
+index 9b4f110..538423d 100644
+--- a/include/linux/compiler.h
++++ b/include/linux/compiler.h
+@@ -10,11 +10,11 @@
+ # define __force __attribute__((force))
+ # define __nocast __attribute__((nocast))
+ # define __iomem __attribute__((noderef, address_space(2)))
+-# define __acquires(x) __attribute__((context(0,1)))
+-# define __releases(x) __attribute__((context(1,0)))
+-# define __acquire(x) __context__(1)
+-# define __release(x) __context__(-1)
+-# define __cond_lock(x) ((x) ? ({ __context__(1); 1; }) : 0)
++# define __acquires(x) __attribute__((context(x,0,1)))
++# define __releases(x) __attribute__((context(x,1,0)))
++# define __acquire(x) __context__(x,1)
++# define __release(x) __context__(x,-1)
++# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
+ extern void __chk_user_ptr(void __user *);
+ extern void __chk_io_ptr(void __iomem *);
+ #else
+@@ -31,7 +31,7 @@ extern void __chk_io_ptr(void __iomem *)
+ # define __releases(x)
+ # define __acquire(x) (void)0
+ # define __release(x) (void)0
+-# define __cond_lock(x) (x)
++# define __cond_lock(x,c) (c)
+ #endif
+
+ #ifdef __KERNEL__
+@@ -99,6 +99,11 @@ extern void __chk_io_ptr(void __iomem *)
+ #define __must_check
+ #endif
+
++#ifndef CONFIG_ENABLE_MUST_CHECK
++#undef __must_check
++#define __must_check
++#endif
++
+ /*
+ * Allow us to avoid 'defined but not used' warnings on functions and data,
+ * as well as force them to be emitted to the assembly file.
+diff --git a/include/linux/config.h b/include/linux/config.h
+deleted file mode 100644
+index a91f5e5..0000000
+--- a/include/linux/config.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef _LINUX_CONFIG_H
+-#define _LINUX_CONFIG_H
+-/* This file is no longer in use and kept only for backward compatibility.
+- * autoconf.h is now included via -imacros on the commandline
+- */
+-#include <linux/autoconf.h>
+-
+-#endif
+diff --git a/include/linux/console.h b/include/linux/console.h
+index 3bdf215..7d04202 100644
+--- a/include/linux/console.h
++++ b/include/linux/console.h
+@@ -120,9 +120,17 @@ extern void console_stop(struct console
+ extern void console_start(struct console *);
+ extern int is_console_locked(void);
+
++#ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
+ /* Suspend and resume console messages over PM events */
+ extern void suspend_console(void);
+ extern void resume_console(void);
++#else
++static inline void suspend_console(void) {}
++static inline void resume_console(void) {}
++#endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
++
++int mda_console_init(void);
++void prom_con_init(void);
+
+ /* Some debug stub to catch some of the obvious races in the VT code */
+ #if 1
+diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
+index 25423f7..ed6c0fe 100644
+--- a/include/linux/console_struct.h
++++ b/include/linux/console_struct.h
+@@ -54,7 +54,7 @@ struct vc_data {
+ struct tty_struct *vc_tty; /* TTY we are attached to */
+ /* data for manual vt switching */
+ struct vt_mode vt_mode;
+- int vt_pid;
++ struct pid *vt_pid;
+ int vt_newvt;
+ wait_queue_head_t paste_wait;
+ /* mode flags */
+diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h
+index 65842ef..82c9a1f 100644
+--- a/include/linux/consolemap.h
++++ b/include/linux/consolemap.h
+@@ -13,3 +13,4 @@ struct vc_data;
+ extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
+ extern unsigned short *set_translate(int m, struct vc_data *vc);
+ extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
++void console_map_init(void);
+diff --git a/include/linux/cpu.h b/include/linux/cpu.h
+index 8fb344a..3fef7d6 100644
+--- a/include/linux/cpu.h
++++ b/include/linux/cpu.h
+@@ -89,4 +89,12 @@ int cpu_down(unsigned int cpu);
+ static inline int cpu_is_offline(int cpu) { return 0; }
+ #endif
+
++#ifdef CONFIG_SUSPEND_SMP
++extern int disable_nonboot_cpus(void);
++extern void enable_nonboot_cpus(void);
++#else
++static inline int disable_nonboot_cpus(void) { return 0; }
++static inline void enable_nonboot_cpus(void) {}
++#endif
++
+ #endif /* _LINUX_CPU_H_ */
+diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
+index b268a3c..d0e8c8b 100644
+--- a/include/linux/cpumask.h
++++ b/include/linux/cpumask.h
+@@ -8,8 +8,8 @@
+ * See detailed comments in the file linux/bitmap.h describing the
+ * data type on which these cpumasks are based.
+ *
+- * For details of cpumask_scnprintf() and cpumask_parse(),
+- * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
++ * For details of cpumask_scnprintf() and cpumask_parse_user(),
++ * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
+ * For details of cpulist_scnprintf() and cpulist_parse(), see
+ * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
+ * For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
+@@ -49,7 +49,7 @@
+ * unsigned long *cpus_addr(mask) Array of unsigned long's in mask
+ *
+ * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
+- * int cpumask_parse(ubuf, ulen, mask) Parse ascii string as cpumask
++ * int cpumask_parse_user(ubuf, ulen, mask) Parse ascii string as cpumask
+ * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
+ * int cpulist_parse(buf, map) Parse ascii string as cpulist
+ * int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
+@@ -273,12 +273,12 @@ static inline int __cpumask_scnprintf(ch
+ return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+ }
+
+-#define cpumask_parse(ubuf, ulen, dst) \
+- __cpumask_parse((ubuf), (ulen), &(dst), NR_CPUS)
+-static inline int __cpumask_parse(const char __user *buf, int len,
++#define cpumask_parse_user(ubuf, ulen, dst) \
++ __cpumask_parse_user((ubuf), (ulen), &(dst), NR_CPUS)
++static inline int __cpumask_parse_user(const char __user *buf, int len,
+ cpumask_t *dstp, int nbits)
+ {
+- return bitmap_parse(buf, len, dstp->bits, nbits);
++ return bitmap_parse_user(buf, len, dstp->bits, nbits);
+ }
+
+ #define cpulist_scnprintf(buf, len, src) \
+diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
+index 9354722..4d8adf6 100644
+--- a/include/linux/cpuset.h
++++ b/include/linux/cpuset.h
+@@ -63,6 +63,8 @@ static inline int cpuset_do_slab_mem_spr
+ return current->flags & PF_SPREAD_SLAB;
+ }
+
++extern void cpuset_track_online_nodes(void);
++
+ #else /* !CONFIG_CPUSETS */
+
+ static inline int cpuset_init_early(void) { return 0; }
+@@ -126,6 +128,8 @@ static inline int cpuset_do_slab_mem_spr
+ return 0;
+ }
+
++static inline void cpuset_track_online_nodes(void) {}
++
+ #endif /* !CONFIG_CPUSETS */
+
+ #endif /* _LINUX_CPUSET_H */
+diff --git a/include/linux/cramfs_fs.h b/include/linux/cramfs_fs.h
+index a41f384..1dba681 100644
+--- a/include/linux/cramfs_fs.h
++++ b/include/linux/cramfs_fs.h
+@@ -87,6 +87,6 @@ struct cramfs_super {
+ /* Uncompression interfaces to the underlying zlib */
+ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
+ int cramfs_uncompress_init(void);
+-int cramfs_uncompress_exit(void);
++void cramfs_uncompress_exit(void);
+
+ #endif
+diff --git a/include/linux/crypto.h b/include/linux/crypto.h
+index 7f94624..8f2ffa4 100644
+--- a/include/linux/crypto.h
++++ b/include/linux/crypto.h
+@@ -17,20 +17,36 @@
+ #ifndef _LINUX_CRYPTO_H
+ #define _LINUX_CRYPTO_H
+
++#include <asm/atomic.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+-#include <linux/types.h>
+ #include <linux/list.h>
++#include <linux/slab.h>
+ #include <linux/string.h>
+-#include <asm/page.h>
++#include <linux/uaccess.h>
+
+ /*
+ * Algorithm masks and types.
+ */
+-#define CRYPTO_ALG_TYPE_MASK 0x000000ff
++#define CRYPTO_ALG_TYPE_MASK 0x0000000f
+ #define CRYPTO_ALG_TYPE_CIPHER 0x00000001
+ #define CRYPTO_ALG_TYPE_DIGEST 0x00000002
+-#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004
++#define CRYPTO_ALG_TYPE_HASH 0x00000003
++#define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004
++#define CRYPTO_ALG_TYPE_COMPRESS 0x00000005
++
++#define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
++
++#define CRYPTO_ALG_LARVAL 0x00000010
++#define CRYPTO_ALG_DEAD 0x00000020
++#define CRYPTO_ALG_DYING 0x00000040
++#define CRYPTO_ALG_ASYNC 0x00000080
++
++/*
++ * Set this bit if and only if the algorithm requires another algorithm of
++ * the same type to handle corner cases.
++ */
++#define CRYPTO_ALG_NEED_FALLBACK 0x00000100
+
+ /*
+ * Transform masks and values (for crt_flags).
+@@ -61,8 +77,37 @@
+ #define CRYPTO_DIR_ENCRYPT 1
+ #define CRYPTO_DIR_DECRYPT 0
+
++/*
++ * The macro CRYPTO_MINALIGN_ATTR (along with the void * type in the actual
++ * declaration) is used to ensure that the crypto_tfm context structure is
++ * aligned correctly for the given architecture so that there are no alignment
++ * faults for C data types. In particular, this is required on platforms such
++ * as arm where pointers are 32-bit aligned but there are data types such as
++ * u64 which require 64-bit alignment.
++ */
++#if defined(ARCH_KMALLOC_MINALIGN)
++#define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN
++#elif defined(ARCH_SLAB_MINALIGN)
++#define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN
++#endif
++
++#ifdef CRYPTO_MINALIGN
++#define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN)))
++#else
++#define CRYPTO_MINALIGN_ATTR
++#endif
++
+ struct scatterlist;
++struct crypto_blkcipher;
++struct crypto_hash;
+ struct crypto_tfm;
++struct crypto_type;
++
++struct blkcipher_desc {
++ struct crypto_blkcipher *tfm;
++ void *info;
++ u32 flags;
++};
+
+ struct cipher_desc {
+ struct crypto_tfm *tfm;
+@@ -72,30 +117,50 @@ struct cipher_desc {
+ void *info;
+ };
+
++struct hash_desc {
++ struct crypto_hash *tfm;
++ u32 flags;
++};
++
+ /*
+ * Algorithms: modular crypto algorithm implementations, managed
+ * via crypto_register_alg() and crypto_unregister_alg().
+ */
++struct blkcipher_alg {
++ int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
++ unsigned int keylen);
++ int (*encrypt)(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes);
++ int (*decrypt)(struct blkcipher_desc *desc,
++ struct scatterlist *dst, struct scatterlist *src,
++ unsigned int nbytes);
++
++ unsigned int min_keysize;
++ unsigned int max_keysize;
++ unsigned int ivsize;
++};
++
+ struct cipher_alg {
+ unsigned int cia_min_keysize;
+ unsigned int cia_max_keysize;
+ int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags);
++ unsigned int keylen);
+ void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+ void (*cia_decrypt)(struct crypto_tfm *tfm, 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 nbytes) __deprecated;
+ unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+- unsigned int nbytes);
++ unsigned int nbytes) __deprecated;
+ unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+- unsigned int nbytes);
++ unsigned int nbytes) __deprecated;
+ unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+- unsigned int nbytes);
++ unsigned int nbytes) __deprecated;
+ };
+
+ struct digest_alg {
+@@ -105,7 +170,20 @@ struct digest_alg {
+ unsigned int len);
+ void (*dia_final)(struct crypto_tfm *tfm, u8 *out);
+ int (*dia_setkey)(struct crypto_tfm *tfm, const u8 *key,
+- unsigned int keylen, u32 *flags);
++ unsigned int keylen);
++};
++
++struct hash_alg {
++ int (*init)(struct hash_desc *desc);
++ int (*update)(struct hash_desc *desc, struct scatterlist *sg,
++ unsigned int nbytes);
++ int (*final)(struct hash_desc *desc, u8 *out);
++ int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
++ unsigned int nbytes, u8 *out);
++ int (*setkey)(struct crypto_hash *tfm, const u8 *key,
++ unsigned int keylen);
++
++ unsigned int digestsize;
+ };
+
+ struct compress_alg {
+@@ -115,30 +193,40 @@ struct compress_alg {
+ unsigned int slen, u8 *dst, unsigned int *dlen);
+ };
+
++#define cra_blkcipher cra_u.blkcipher
+ #define cra_cipher cra_u.cipher
+ #define cra_digest cra_u.digest
++#define cra_hash cra_u.hash
+ #define cra_compress cra_u.compress
+
+ struct crypto_alg {
+ struct list_head cra_list;
++ struct list_head cra_users;
++
+ u32 cra_flags;
+ unsigned int cra_blocksize;
+ unsigned int cra_ctxsize;
+ unsigned int cra_alignmask;
+
+ int cra_priority;
++ atomic_t cra_refcnt;
+
+ char cra_name[CRYPTO_MAX_ALG_NAME];
+ char cra_driver_name[CRYPTO_MAX_ALG_NAME];
+
++ const struct crypto_type *cra_type;
++
+ union {
++ struct blkcipher_alg blkcipher;
+ struct cipher_alg cipher;
+ struct digest_alg digest;
++ struct hash_alg hash;
+ struct compress_alg compress;
+ } cra_u;
+
+ int (*cra_init)(struct crypto_tfm *tfm);
+ void (*cra_exit)(struct crypto_tfm *tfm);
++ void (*cra_destroy)(struct crypto_alg *alg);
+
+ struct module *cra_module;
+ };
+@@ -153,20 +241,39 @@ int crypto_unregister_alg(struct crypto_
+ * Algorithm query interface.
+ */
+ #ifdef CONFIG_CRYPTO
+-int crypto_alg_available(const char *name, u32 flags);
++int crypto_alg_available(const char *name, u32 flags)
++ __deprecated_for_modules;
++int crypto_has_alg(const char *name, u32 type, u32 mask);
+ #else
++static int crypto_alg_available(const char *name, u32 flags);
++ __deprecated_for_modules;
+ static inline int crypto_alg_available(const char *name, u32 flags)
+ {
+ return 0;
+ }
++
++static inline int crypto_has_alg(const char *name, u32 type, u32 mask)
++{
++ return 0;
++}
+ #endif
+
+ /*
+ * Transforms: user-instantiated objects which encapsulate algorithms
+- * and core processing logic. Managed via crypto_alloc_tfm() and
+- * crypto_free_tfm(), as well as the various helpers below.
++ * and core processing logic. Managed via crypto_alloc_*() and
++ * crypto_free_*(), as well as the various helpers below.
+ */
+
++struct blkcipher_tfm {
++ void *iv;
++ int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
++ unsigned int keylen);
++ int (*encrypt)(struct blkcipher_desc *desc, struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes);
++ int (*decrypt)(struct blkcipher_desc *desc, struct scatterlist *dst,
++ struct scatterlist *src, unsigned int nbytes);
++};
++
+ struct cipher_tfm {
+ void *cit_iv;
+ unsigned int cit_ivsize;
+@@ -190,20 +297,20 @@ struct cipher_tfm {
+ struct scatterlist *src,
+ unsigned int nbytes, u8 *iv);
+ void (*cit_xor_block)(u8 *dst, const u8 *src);
++ void (*cit_encrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
++ void (*cit_decrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+ };
+
+-struct digest_tfm {
+- void (*dit_init)(struct crypto_tfm *tfm);
+- void (*dit_update)(struct crypto_tfm *tfm,
+- struct scatterlist *sg, unsigned int nsg);
+- void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
+- void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
+- unsigned int nsg, u8 *out);
+- int (*dit_setkey)(struct crypto_tfm *tfm,
+- const u8 *key, unsigned int keylen);
+-#ifdef CONFIG_CRYPTO_HMAC
+- void *dit_hmac_block;
+-#endif
++struct hash_tfm {
++ int (*init)(struct hash_desc *desc);
++ int (*update)(struct hash_desc *desc,
++ struct scatterlist *sg, unsigned int nsg);
++ int (*final)(struct hash_desc *desc, u8 *out);
++ int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
++ unsigned int nsg, u8 *out);
++ int (*setkey)(struct crypto_hash *tfm, const u8 *key,
++ unsigned int keylen);
++ unsigned int digestsize;
+ };
+
+ struct compress_tfm {
+@@ -215,8 +322,9 @@ struct compress_tfm {
+ u8 *dst, unsigned int *dlen);
+ };
+
++#define crt_blkcipher crt_u.blkcipher
+ #define crt_cipher crt_u.cipher
+-#define crt_digest crt_u.digest
++#define crt_hash crt_u.hash
+ #define crt_compress crt_u.compress
+
+ struct crypto_tfm {
+@@ -224,30 +332,43 @@ struct crypto_tfm {
+ u32 crt_flags;
+
+ union {
++ struct blkcipher_tfm blkcipher;
+ struct cipher_tfm cipher;
+- struct digest_tfm digest;
++ struct hash_tfm hash;
+ struct compress_tfm compress;
+ } crt_u;
+
+ struct crypto_alg *__crt_alg;
+
+- char __crt_ctx[] __attribute__ ((__aligned__));
++ void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
++};
++
++#define crypto_cipher crypto_tfm
++#define crypto_comp crypto_tfm
++
++struct crypto_blkcipher {
++ struct crypto_tfm base;
++};
++
++struct crypto_hash {
++ struct crypto_tfm base;
++};
++
++enum {
++ CRYPTOA_UNSPEC,
++ CRYPTOA_ALG,
++};
++
++struct crypto_attr_alg {
++ char name[CRYPTO_MAX_ALG_NAME];
+ };
+
+ /*
+ * Transform user interface.
+ */
+
+-/*
+- * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm.
+- * If that fails and the kernel supports dynamically loadable modules, it
+- * will then attempt to load a module of the same name or alias. A refcount
+- * is grabbed on the algorithm which is then associated with the new transform.
+- *
+- * crypto_free_tfm() frees up the transform and any associated resources,
+- * then drops the refcount on the associated algorithm.
+- */
+ struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
++struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask);
+ void crypto_free_tfm(struct crypto_tfm *tfm);
+
+ /*
+@@ -258,6 +379,16 @@ static inline const char *crypto_tfm_alg
+ return tfm->__crt_alg->cra_name;
+ }
+
++static inline const char *crypto_tfm_alg_driver_name(struct crypto_tfm *tfm)
++{
++ return tfm->__crt_alg->cra_driver_name;
++}
++
++static inline int crypto_tfm_alg_priority(struct crypto_tfm *tfm)
++{
++ return tfm->__crt_alg->cra_priority;
++}
++
+ static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm)
+ {
+ return module_name(tfm->__crt_alg->cra_module);
+@@ -268,18 +399,23 @@ static inline u32 crypto_tfm_alg_type(st
+ return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK;
+ }
+
++static unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
++ __deprecated;
+ static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
+ {
+ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+ return tfm->__crt_alg->cra_cipher.cia_min_keysize;
+ }
+
++static unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
++ __deprecated;
+ static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
+ {
+ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+ return tfm->__crt_alg->cra_cipher.cia_max_keysize;
+ }
+
++static unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) __deprecated;
+ static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm)
+ {
+ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+@@ -302,6 +438,21 @@ static inline unsigned int crypto_tfm_al
+ return tfm->__crt_alg->cra_alignmask;
+ }
+
++static inline u32 crypto_tfm_get_flags(struct crypto_tfm *tfm)
++{
++ return tfm->crt_flags;
++}
++
++static inline void crypto_tfm_set_flags(struct crypto_tfm *tfm, u32 flags)
++{
++ tfm->crt_flags |= flags;
++}
++
++static inline void crypto_tfm_clear_flags(struct crypto_tfm *tfm, u32 flags)
++{
++ tfm->crt_flags &= ~flags;
++}
++
+ static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
+ {
+ return tfm->__crt_ctx;
+@@ -316,50 +467,374 @@ static inline unsigned int crypto_tfm_ct
+ /*
+ * API wrappers.
+ */
+-static inline void crypto_digest_init(struct crypto_tfm *tfm)
++static inline struct crypto_blkcipher *__crypto_blkcipher_cast(
++ struct crypto_tfm *tfm)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+- tfm->crt_digest.dit_init(tfm);
++ return (struct crypto_blkcipher *)tfm;
+ }
+
+-static inline void crypto_digest_update(struct crypto_tfm *tfm,
+- struct scatterlist *sg,
+- unsigned int nsg)
++static inline struct crypto_blkcipher *crypto_blkcipher_cast(
++ struct crypto_tfm *tfm)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+- tfm->crt_digest.dit_update(tfm, sg, nsg);
++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_BLKCIPHER);
++ return __crypto_blkcipher_cast(tfm);
+ }
+
+-static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
++static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
++ const char *alg_name, u32 type, u32 mask)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+- tfm->crt_digest.dit_final(tfm, out);
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_BLKCIPHER;
++ mask |= CRYPTO_ALG_TYPE_MASK;
++
++ return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
+ }
+
+-static inline void crypto_digest_digest(struct crypto_tfm *tfm,
+- struct scatterlist *sg,
+- unsigned int nsg, u8 *out)
++static inline struct crypto_tfm *crypto_blkcipher_tfm(
++ struct crypto_blkcipher *tfm)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+- tfm->crt_digest.dit_digest(tfm, sg, nsg, out);
++ return &tfm->base;
+ }
+
+-static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
++static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm)
++{
++ crypto_free_tfm(crypto_blkcipher_tfm(tfm));
++}
++
++static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_BLKCIPHER;
++ mask |= CRYPTO_ALG_TYPE_MASK;
++
++ return crypto_has_alg(alg_name, type, mask);
++}
++
++static inline const char *crypto_blkcipher_name(struct crypto_blkcipher *tfm)
++{
++ return crypto_tfm_alg_name(crypto_blkcipher_tfm(tfm));
++}
++
++static inline struct blkcipher_tfm *crypto_blkcipher_crt(
++ struct crypto_blkcipher *tfm)
++{
++ return &crypto_blkcipher_tfm(tfm)->crt_blkcipher;
++}
++
++static inline struct blkcipher_alg *crypto_blkcipher_alg(
++ struct crypto_blkcipher *tfm)
++{
++ return &crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher;
++}
++
++static inline unsigned int crypto_blkcipher_ivsize(struct crypto_blkcipher *tfm)
++{
++ return crypto_blkcipher_alg(tfm)->ivsize;
++}
++
++static inline unsigned int crypto_blkcipher_blocksize(
++ struct crypto_blkcipher *tfm)
++{
++ return crypto_tfm_alg_blocksize(crypto_blkcipher_tfm(tfm));
++}
++
++static inline unsigned int crypto_blkcipher_alignmask(
++ struct crypto_blkcipher *tfm)
++{
++ return crypto_tfm_alg_alignmask(crypto_blkcipher_tfm(tfm));
++}
++
++static inline u32 crypto_blkcipher_get_flags(struct crypto_blkcipher *tfm)
++{
++ return crypto_tfm_get_flags(crypto_blkcipher_tfm(tfm));
++}
++
++static inline void crypto_blkcipher_set_flags(struct crypto_blkcipher *tfm,
++ u32 flags)
++{
++ crypto_tfm_set_flags(crypto_blkcipher_tfm(tfm), flags);
++}
++
++static inline void crypto_blkcipher_clear_flags(struct crypto_blkcipher *tfm,
++ u32 flags)
++{
++ crypto_tfm_clear_flags(crypto_blkcipher_tfm(tfm), flags);
++}
++
++static inline int crypto_blkcipher_setkey(struct crypto_blkcipher *tfm,
++ const u8 *key, unsigned int keylen)
++{
++ return crypto_blkcipher_crt(tfm)->setkey(crypto_blkcipher_tfm(tfm),
++ key, keylen);
++}
++
++static inline int crypto_blkcipher_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ desc->info = crypto_blkcipher_crt(desc->tfm)->iv;
++ return crypto_blkcipher_crt(desc->tfm)->encrypt(desc, dst, src, nbytes);
++}
++
++static inline int crypto_blkcipher_encrypt_iv(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ return crypto_blkcipher_crt(desc->tfm)->encrypt(desc, dst, src, nbytes);
++}
++
++static inline int crypto_blkcipher_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ desc->info = crypto_blkcipher_crt(desc->tfm)->iv;
++ return crypto_blkcipher_crt(desc->tfm)->decrypt(desc, dst, src, nbytes);
++}
++
++static inline int crypto_blkcipher_decrypt_iv(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ return crypto_blkcipher_crt(desc->tfm)->decrypt(desc, dst, src, nbytes);
++}
++
++static inline void crypto_blkcipher_set_iv(struct crypto_blkcipher *tfm,
++ const u8 *src, unsigned int len)
++{
++ memcpy(crypto_blkcipher_crt(tfm)->iv, src, len);
++}
++
++static inline void crypto_blkcipher_get_iv(struct crypto_blkcipher *tfm,
++ u8 *dst, unsigned int len)
++{
++ memcpy(dst, crypto_blkcipher_crt(tfm)->iv, len);
++}
++
++static inline struct crypto_cipher *__crypto_cipher_cast(struct crypto_tfm *tfm)
++{
++ return (struct crypto_cipher *)tfm;
++}
++
++static inline struct crypto_cipher *crypto_cipher_cast(struct crypto_tfm *tfm)
++{
++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
++ return __crypto_cipher_cast(tfm);
++}
++
++static inline struct crypto_cipher *crypto_alloc_cipher(const char *alg_name,
++ u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_CIPHER;
++ mask |= CRYPTO_ALG_TYPE_MASK;
++
++ return __crypto_cipher_cast(crypto_alloc_base(alg_name, type, mask));
++}
++
++static inline struct crypto_tfm *crypto_cipher_tfm(struct crypto_cipher *tfm)
++{
++ return tfm;
++}
++
++static inline void crypto_free_cipher(struct crypto_cipher *tfm)
++{
++ crypto_free_tfm(crypto_cipher_tfm(tfm));
++}
++
++static inline int crypto_has_cipher(const char *alg_name, u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_CIPHER;
++ mask |= CRYPTO_ALG_TYPE_MASK;
++
++ return crypto_has_alg(alg_name, type, mask);
++}
++
++static inline struct cipher_tfm *crypto_cipher_crt(struct crypto_cipher *tfm)
++{
++ return &crypto_cipher_tfm(tfm)->crt_cipher;
++}
++
++static inline unsigned int crypto_cipher_blocksize(struct crypto_cipher *tfm)
++{
++ return crypto_tfm_alg_blocksize(crypto_cipher_tfm(tfm));
++}
++
++static inline unsigned int crypto_cipher_alignmask(struct crypto_cipher *tfm)
++{
++ return crypto_tfm_alg_alignmask(crypto_cipher_tfm(tfm));
++}
++
++static inline u32 crypto_cipher_get_flags(struct crypto_cipher *tfm)
++{
++ return crypto_tfm_get_flags(crypto_cipher_tfm(tfm));
++}
++
++static inline void crypto_cipher_set_flags(struct crypto_cipher *tfm,
++ u32 flags)
++{
++ crypto_tfm_set_flags(crypto_cipher_tfm(tfm), flags);
++}
++
++static inline void crypto_cipher_clear_flags(struct crypto_cipher *tfm,
++ u32 flags)
++{
++ crypto_tfm_clear_flags(crypto_cipher_tfm(tfm), flags);
++}
++
++static inline int crypto_cipher_setkey(struct crypto_cipher *tfm,
+ const u8 *key, unsigned int keylen)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+- if (tfm->crt_digest.dit_setkey == NULL)
+- return -ENOSYS;
+- return tfm->crt_digest.dit_setkey(tfm, key, keylen);
++ return crypto_cipher_crt(tfm)->cit_setkey(crypto_cipher_tfm(tfm),
++ key, keylen);
++}
++
++static inline void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
++ u8 *dst, const u8 *src)
++{
++ crypto_cipher_crt(tfm)->cit_encrypt_one(crypto_cipher_tfm(tfm),
++ dst, src);
++}
++
++static inline void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
++ u8 *dst, const u8 *src)
++{
++ crypto_cipher_crt(tfm)->cit_decrypt_one(crypto_cipher_tfm(tfm),
++ dst, src);
++}
++
++void crypto_digest_init(struct crypto_tfm *tfm) __deprecated_for_modules;
++void crypto_digest_update(struct crypto_tfm *tfm,
++ struct scatterlist *sg, unsigned int nsg)
++ __deprecated_for_modules;
++void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
++ __deprecated_for_modules;
++void crypto_digest_digest(struct crypto_tfm *tfm,
++ struct scatterlist *sg, unsigned int nsg, u8 *out)
++ __deprecated_for_modules;
++
++static inline struct crypto_hash *__crypto_hash_cast(struct crypto_tfm *tfm)
++{
++ return (struct crypto_hash *)tfm;
++}
++
++static inline struct crypto_hash *crypto_hash_cast(struct crypto_tfm *tfm)
++{
++ BUG_ON((crypto_tfm_alg_type(tfm) ^ CRYPTO_ALG_TYPE_HASH) &
++ CRYPTO_ALG_TYPE_HASH_MASK);
++ return __crypto_hash_cast(tfm);
+ }
+
+-static inline int crypto_cipher_setkey(struct crypto_tfm *tfm,
++static int crypto_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
++ unsigned int keylen) __deprecated;
++static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
+ const u8 *key, unsigned int keylen)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+- return tfm->crt_cipher.cit_setkey(tfm, key, keylen);
++ return tfm->crt_hash.setkey(crypto_hash_cast(tfm), key, keylen);
++}
++
++static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name,
++ u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_HASH;
++ mask |= CRYPTO_ALG_TYPE_HASH_MASK;
++
++ return __crypto_hash_cast(crypto_alloc_base(alg_name, type, mask));
++}
++
++static inline struct crypto_tfm *crypto_hash_tfm(struct crypto_hash *tfm)
++{
++ return &tfm->base;
++}
++
++static inline void crypto_free_hash(struct crypto_hash *tfm)
++{
++ crypto_free_tfm(crypto_hash_tfm(tfm));
++}
++
++static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_HASH;
++ mask |= CRYPTO_ALG_TYPE_HASH_MASK;
++
++ return crypto_has_alg(alg_name, type, mask);
++}
++
++static inline struct hash_tfm *crypto_hash_crt(struct crypto_hash *tfm)
++{
++ return &crypto_hash_tfm(tfm)->crt_hash;
++}
++
++static inline unsigned int crypto_hash_blocksize(struct crypto_hash *tfm)
++{
++ return crypto_tfm_alg_blocksize(crypto_hash_tfm(tfm));
++}
++
++static inline unsigned int crypto_hash_alignmask(struct crypto_hash *tfm)
++{
++ return crypto_tfm_alg_alignmask(crypto_hash_tfm(tfm));
++}
++
++static inline unsigned int crypto_hash_digestsize(struct crypto_hash *tfm)
++{
++ return crypto_hash_crt(tfm)->digestsize;
++}
++
++static inline u32 crypto_hash_get_flags(struct crypto_hash *tfm)
++{
++ return crypto_tfm_get_flags(crypto_hash_tfm(tfm));
++}
++
++static inline void crypto_hash_set_flags(struct crypto_hash *tfm, u32 flags)
++{
++ crypto_tfm_set_flags(crypto_hash_tfm(tfm), flags);
+ }
+
++static inline void crypto_hash_clear_flags(struct crypto_hash *tfm, u32 flags)
++{
++ crypto_tfm_clear_flags(crypto_hash_tfm(tfm), flags);
++}
++
++static inline int crypto_hash_init(struct hash_desc *desc)
++{
++ return crypto_hash_crt(desc->tfm)->init(desc);
++}
++
++static inline int crypto_hash_update(struct hash_desc *desc,
++ struct scatterlist *sg,
++ unsigned int nbytes)
++{
++ return crypto_hash_crt(desc->tfm)->update(desc, sg, nbytes);
++}
++
++static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
++{
++ return crypto_hash_crt(desc->tfm)->final(desc, out);
++}
++
++static inline int crypto_hash_digest(struct hash_desc *desc,
++ struct scatterlist *sg,
++ unsigned int nbytes, u8 *out)
++{
++ return crypto_hash_crt(desc->tfm)->digest(desc, sg, nbytes, out);
++}
++
++static inline int crypto_hash_setkey(struct crypto_hash *hash,
++ const u8 *key, unsigned int keylen)
++{
++ return crypto_hash_crt(hash)->setkey(hash, key, keylen);
++}
++
++static int crypto_cipher_encrypt(struct crypto_tfm *tfm,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes) __deprecated;
+ static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+@@ -369,16 +844,23 @@ static inline int crypto_cipher_encrypt(
+ return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes);
+ }
+
++static int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes, u8 *iv) __deprecated;
+ static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes, u8 *iv)
+ {
+ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+- BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
+ return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv);
+ }
+
++static int crypto_cipher_decrypt(struct crypto_tfm *tfm,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes) __deprecated;
+ static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+@@ -388,16 +870,21 @@ static inline int crypto_cipher_decrypt(
+ return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes);
+ }
+
++static int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes, u8 *iv) __deprecated;
+ static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes, u8 *iv)
+ {
+ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+- BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
+ return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv);
+ }
+
++static void crypto_cipher_set_iv(struct crypto_tfm *tfm,
++ const u8 *src, unsigned int len) __deprecated;
+ static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm,
+ const u8 *src, unsigned int len)
+ {
+@@ -405,6 +892,8 @@ static inline void crypto_cipher_set_iv(
+ memcpy(tfm->crt_cipher.cit_iv, src, len);
+ }
+
++static void crypto_cipher_get_iv(struct crypto_tfm *tfm,
++ u8 *dst, unsigned int len) __deprecated;
+ static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm,
+ u8 *dst, unsigned int len)
+ {
+@@ -412,34 +901,70 @@ static inline void crypto_cipher_get_iv(
+ memcpy(dst, tfm->crt_cipher.cit_iv, len);
+ }
+
+-static inline int crypto_comp_compress(struct crypto_tfm *tfm,
++static inline struct crypto_comp *__crypto_comp_cast(struct crypto_tfm *tfm)
++{
++ return (struct crypto_comp *)tfm;
++}
++
++static inline struct crypto_comp *crypto_comp_cast(struct crypto_tfm *tfm)
++{
++ BUG_ON((crypto_tfm_alg_type(tfm) ^ CRYPTO_ALG_TYPE_COMPRESS) &
++ CRYPTO_ALG_TYPE_MASK);
++ return __crypto_comp_cast(tfm);
++}
++
++static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name,
++ u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_COMPRESS;
++ mask |= CRYPTO_ALG_TYPE_MASK;
++
++ return __crypto_comp_cast(crypto_alloc_base(alg_name, type, mask));
++}
++
++static inline struct crypto_tfm *crypto_comp_tfm(struct crypto_comp *tfm)
++{
++ return tfm;
++}
++
++static inline void crypto_free_comp(struct crypto_comp *tfm)
++{
++ crypto_free_tfm(crypto_comp_tfm(tfm));
++}
++
++static inline int crypto_has_comp(const char *alg_name, u32 type, u32 mask)
++{
++ type &= ~CRYPTO_ALG_TYPE_MASK;
++ type |= CRYPTO_ALG_TYPE_COMPRESS;
++ mask |= CRYPTO_ALG_TYPE_MASK;
++
++ return crypto_has_alg(alg_name, type, mask);
++}
++
++static inline const char *crypto_comp_name(struct crypto_comp *tfm)
++{
++ return crypto_tfm_alg_name(crypto_comp_tfm(tfm));
++}
++
++static inline struct compress_tfm *crypto_comp_crt(struct crypto_comp *tfm)
++{
++ return &crypto_comp_tfm(tfm)->crt_compress;
++}
++
++static inline int crypto_comp_compress(struct crypto_comp *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS);
+- return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen);
++ return crypto_comp_crt(tfm)->cot_compress(tfm, src, slen, dst, dlen);
+ }
+
+-static inline int crypto_comp_decompress(struct crypto_tfm *tfm,
++static inline int crypto_comp_decompress(struct crypto_comp *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen)
+ {
+- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS);
+- return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen);
++ return crypto_comp_crt(tfm)->cot_decompress(tfm, src, slen, dst, dlen);
+ }
+
+-/*
+- * HMAC support.
+- */
+-#ifdef CONFIG_CRYPTO_HMAC
+-void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen);
+-void crypto_hmac_update(struct crypto_tfm *tfm,
+- struct scatterlist *sg, unsigned int nsg);
+-void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
+- unsigned int *keylen, u8 *out);
+-void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
+- struct scatterlist *sg, unsigned int nsg, u8 *out);
+-#endif /* CONFIG_CRYPTO_HMAC */
+-
+ #endif /* _LINUX_CRYPTO_H */
+
+diff --git a/include/linux/dcache.h b/include/linux/dcache.h
+index 471781f..63f64a9 100644
+--- a/include/linux/dcache.h
++++ b/include/linux/dcache.h
+@@ -221,6 +221,7 @@ static inline int dname_external(struct
+ */
+ extern void d_instantiate(struct dentry *, struct inode *);
+ extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
++extern struct dentry * d_materialise_unique(struct dentry *, struct inode *);
+ extern void d_delete(struct dentry *);
+
+ /* allocate/de-allocate */
+@@ -229,6 +230,7 @@ extern struct dentry * d_alloc_anon(stru
+ extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
+ extern void shrink_dcache_sb(struct super_block *);
+ extern void shrink_dcache_parent(struct dentry *);
++extern void shrink_dcache_for_umount(struct super_block *);
+ extern int d_invalidate(struct dentry *);
+
+ /* only used at mount-time */
+diff --git a/include/linux/dccp.h b/include/linux/dccp.h
+index 676333b..53553c9 100644
+--- a/include/linux/dccp.h
++++ b/include/linux/dccp.h
+@@ -169,6 +169,12 @@ enum {
+ DCCPO_MAX_CCID_SPECIFIC = 255,
+ };
+
++/* DCCP CCIDS */
++enum {
++ DCCPC_CCID2 = 2,
++ DCCPC_CCID3 = 3,
++};
++
+ /* DCCP features */
+ enum {
+ DCCPF_RESERVED = 0,
+@@ -185,7 +191,7 @@ enum {
+ /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
+ struct dccp_so_feat {
+ __u8 dccpsf_feat;
+- __u8 *dccpsf_val;
++ __u8 __user *dccpsf_val;
+ __u8 dccpsf_len;
+ };
+
+@@ -320,7 +326,7 @@ static inline unsigned int dccp_hdr_len(
+ /* initial values for each feature */
+ #define DCCPF_INITIAL_SEQUENCE_WINDOW 100
+ #define DCCPF_INITIAL_ACK_RATIO 2
+-#define DCCPF_INITIAL_CCID 2
++#define DCCPF_INITIAL_CCID DCCPC_CCID2
+ #define DCCPF_INITIAL_SEND_ACK_VECTOR 1
+ /* FIXME: for now we're default to 1 but it should really be 0 */
+ #define DCCPF_INITIAL_SEND_NDP_COUNT 1
+@@ -404,6 +410,7 @@ struct dccp_service_list {
+ };
+
+ #define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
++#define DCCP_SERVICE_CODE_IS_ABSENT 0
+
+ static inline int dccp_list_has_service(const struct dccp_service_list *sl,
+ const __be32 service)
+@@ -438,6 +445,7 @@ struct dccp_ackvec;
+ * @dccps_role - Role of this sock, one of %dccp_role
+ * @dccps_ndp_count - number of Non Data Packets since last data packet
+ * @dccps_hc_rx_ackvec - rx half connection ack vector
++ * @dccps_xmit_timer - timer for when CCID is not ready to send
+ */
+ struct dccp_sock {
+ /* inet_connection_sock has to be the first member of dccp_sock */
+@@ -470,6 +478,7 @@ struct dccp_sock {
+ enum dccp_role dccps_role:2;
+ __u8 dccps_hc_rx_insert_options:1;
+ __u8 dccps_hc_tx_insert_options:1;
++ struct timer_list dccps_xmit_timer;
+ };
+
+ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
+@@ -482,11 +491,6 @@ static inline struct dccp_minisock *dccp
+ return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
+ }
+
+-static inline int dccp_service_not_initialized(const struct sock *sk)
+-{
+- return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE;
+-}
+-
+ static inline const char *dccp_role(const struct sock *sk)
+ {
+ switch (dccp_sk(sk)->dccps_role) {
+diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
+index 88dafa2..952bee7 100644
+--- a/include/linux/debug_locks.h
++++ b/include/linux/debug_locks.h
+@@ -43,6 +43,8 @@ extern int debug_locks_off(void);
+ # define locking_selftest() do { } while (0)
+ #endif
+
++struct task_struct;
++
+ #ifdef CONFIG_LOCKDEP
+ extern void debug_show_all_locks(void);
+ extern void debug_show_held_locks(struct task_struct *task);
+diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
+index e3d1c33..03ef41c 100644
+--- a/include/linux/device-mapper.h
++++ b/include/linux/device-mapper.h
+@@ -55,8 +55,10 @@ typedef int (*dm_endio_fn) (struct dm_ta
+ struct bio *bio, int error,
+ union map_info *map_context);
+
++typedef void (*dm_flush_fn) (struct dm_target *ti);
+ typedef void (*dm_presuspend_fn) (struct dm_target *ti);
+ typedef void (*dm_postsuspend_fn) (struct dm_target *ti);
++typedef int (*dm_preresume_fn) (struct dm_target *ti);
+ typedef void (*dm_resume_fn) (struct dm_target *ti);
+
+ typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
+@@ -64,9 +66,18 @@ typedef int (*dm_status_fn) (struct dm_t
+
+ typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
+
++typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode,
++ struct file *filp, unsigned int cmd,
++ unsigned long arg);
++
+ void dm_error(const char *message);
+
+ /*
++ * Combine device limits.
++ */
++void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev);
++
++/*
+ * Constructors should call these functions to ensure destination devices
+ * are opened/closed correctly.
+ * FIXME: too many arguments.
+@@ -86,11 +97,14 @@ struct target_type {
+ dm_dtr_fn dtr;
+ dm_map_fn map;
+ dm_endio_fn end_io;
++ dm_flush_fn flush;
+ dm_presuspend_fn presuspend;
+ dm_postsuspend_fn postsuspend;
++ dm_preresume_fn preresume;
+ dm_resume_fn resume;
+ dm_status_fn status;
+ dm_message_fn message;
++ dm_ioctl_fn ioctl;
+ };
+
+ struct io_restrictions {
+diff --git a/include/linux/device.h b/include/linux/device.h
+index 1e5f30d..9d4f6a9 100644
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -15,6 +15,7 @@
+ #include <linux/kobject.h>
+ #include <linux/klist.h>
+ #include <linux/list.h>
++#include <linux/compiler.h>
+ #include <linux/types.h>
+ #include <linux/module.h>
+ #include <linux/pm.h>
+@@ -51,14 +52,17 @@ struct bus_type {
+ int (*probe)(struct device * dev);
+ int (*remove)(struct device * dev);
+ void (*shutdown)(struct device * dev);
+- int (*suspend)(struct device * dev, pm_message_t state);
+- int (*resume)(struct device * dev);
++
++ int (*suspend)(struct device * dev, pm_message_t state);
++ int (*suspend_late)(struct device * dev, pm_message_t state);
++ int (*resume_early)(struct device * dev);
++ int (*resume)(struct device * dev);
+ };
+
+-extern int bus_register(struct bus_type * bus);
++extern int __must_check bus_register(struct bus_type * bus);
+ extern void bus_unregister(struct bus_type * bus);
+
+-extern void bus_rescan_devices(struct bus_type * bus);
++extern int __must_check bus_rescan_devices(struct bus_type * bus);
+
+ /* iterator helpers for buses */
+
+@@ -67,9 +71,9 @@ int bus_for_each_dev(struct bus_type * b
+ 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 *));
+-
++int __must_check bus_for_each_drv(struct bus_type *bus,
++ struct device_driver *start, void *data,
++ int (*fn)(struct device_driver *, void *));
+
+ /* driverfs interface for exporting bus attributes */
+
+@@ -82,7 +86,8 @@ struct bus_attribute {
+ #define BUS_ATTR(_name,_mode,_show,_store) \
+ struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+-extern int bus_create_file(struct bus_type *, struct bus_attribute *);
++extern int __must_check bus_create_file(struct bus_type *,
++ struct bus_attribute *);
+ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
+
+ struct device_driver {
+@@ -101,16 +106,18 @@ struct device_driver {
+ void (*shutdown) (struct device * dev);
+ int (*suspend) (struct device * dev, pm_message_t state);
+ int (*resume) (struct device * dev);
++
++ unsigned int multithread_probe:1;
+ };
+
+
+-extern int driver_register(struct device_driver * drv);
++extern int __must_check driver_register(struct device_driver * drv);
+ extern void driver_unregister(struct device_driver * drv);
+
+ extern struct device_driver * get_driver(struct device_driver * drv);
+ extern void put_driver(struct device_driver * drv);
+ extern struct device_driver *driver_find(const char *name, struct bus_type *bus);
+-
++extern int driver_probe_done(void);
+
+ /* driverfs interface for exporting driver attributes */
+
+@@ -123,16 +130,17 @@ struct driver_attribute {
+ #define DRIVER_ATTR(_name,_mode,_show,_store) \
+ struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+-extern int driver_create_file(struct device_driver *, struct driver_attribute *);
++extern int __must_check driver_create_file(struct device_driver *,
++ struct driver_attribute *);
+ 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 *));
++extern int __must_check 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 *));
+
+-
+ /*
+ * device classes
+ */
+@@ -146,17 +154,26 @@ struct class {
+ struct list_head interfaces;
+ struct semaphore sem; /* locks both the children and interfaces lists */
+
++ struct kobject *virtual_dir;
++
+ struct class_attribute * class_attrs;
+ struct class_device_attribute * class_dev_attrs;
++ struct device_attribute * dev_attrs;
+
+ int (*uevent)(struct class_device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size);
++ int (*dev_uevent)(struct device *dev, char **envp, int num_envp,
++ char *buffer, int buffer_size);
+
+ void (*release)(struct class_device *dev);
+ void (*class_release)(struct class *class);
++ void (*dev_release)(struct device *dev);
++
++ int (*suspend)(struct device *, pm_message_t state);
++ int (*resume)(struct device *);
+ };
+
+-extern int class_register(struct class *);
++extern int __must_check class_register(struct class *);
+ extern void class_unregister(struct class *);
+
+
+@@ -169,7 +186,8 @@ struct class_attribute {
+ #define CLASS_ATTR(_name,_mode,_show,_store) \
+ struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+-extern int class_create_file(struct class *, const struct class_attribute *);
++extern int __must_check class_create_file(struct class *,
++ const struct class_attribute *);
+ extern void class_remove_file(struct class *, const struct class_attribute *);
+
+ struct class_device_attribute {
+@@ -182,7 +200,7 @@ struct class_device_attribute {
+ struct class_device_attribute class_device_attr_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+-extern int class_device_create_file(struct class_device *,
++extern int __must_check class_device_create_file(struct class_device *,
+ const struct class_device_attribute *);
+
+ /**
+@@ -242,10 +260,10 @@ class_set_devdata (struct class_device *
+ }
+
+
+-extern int class_device_register(struct class_device *);
++extern int __must_check class_device_register(struct class_device *);
+ extern void class_device_unregister(struct class_device *);
+ extern void class_device_initialize(struct class_device *);
+-extern int class_device_add(struct class_device *);
++extern int __must_check class_device_add(struct class_device *);
+ extern void class_device_del(struct class_device *);
+
+ extern int class_device_rename(struct class_device *, char *);
+@@ -255,7 +273,7 @@ extern void class_device_put(struct clas
+
+ extern void class_device_remove_file(struct class_device *,
+ const struct class_device_attribute *);
+-extern int class_device_create_bin_file(struct class_device *,
++extern int __must_check class_device_create_bin_file(struct class_device *,
+ struct bin_attribute *);
+ extern void class_device_remove_bin_file(struct class_device *,
+ struct bin_attribute *);
+@@ -266,22 +284,23 @@ struct class_interface {
+
+ int (*add) (struct class_device *, struct class_interface *);
+ void (*remove) (struct class_device *, struct class_interface *);
++ int (*add_dev) (struct device *, struct class_interface *);
++ void (*remove_dev) (struct device *, struct class_interface *);
+ };
+
+-extern int class_interface_register(struct class_interface *);
++extern int __must_check class_interface_register(struct class_interface *);
+ extern void class_interface_unregister(struct class_interface *);
+
+-extern struct class *class_create(struct module *owner, char *name);
++extern struct class *class_create(struct module *owner, const char *name);
+ extern void class_destroy(struct class *cls);
+ extern struct class_device *class_device_create(struct class *cls,
+ struct class_device *parent,
+ dev_t devt,
+ struct device *device,
+- char *fmt, ...)
++ const char *fmt, ...)
+ __attribute__((format(printf,5,6)));
+ extern void class_device_destroy(struct class *cls, dev_t devt);
+
+-
+ /* interface for exporting device attributes */
+ struct device_attribute {
+ struct attribute attr;
+@@ -294,8 +313,13 @@ struct device_attribute {
+ #define DEVICE_ATTR(_name,_mode,_show,_store) \
+ struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+-extern int device_create_file(struct device *device, struct device_attribute * entry);
++extern int __must_check device_create_file(struct device *device,
++ struct device_attribute * entry);
+ extern void device_remove_file(struct device * dev, struct device_attribute * attr);
++extern int __must_check device_create_bin_file(struct device *dev,
++ struct bin_attribute *attr);
++extern void device_remove_bin_file(struct device *dev,
++ struct bin_attribute *attr);
+ struct device {
+ struct klist klist_children;
+ struct klist_node knode_parent; /* node in sibling list */
+@@ -305,6 +329,7 @@ struct device {
+
+ struct kobject kobj;
+ char bus_id[BUS_ID_SIZE]; /* position on parent bus */
++ unsigned is_registered:1;
+ struct device_attribute uevent_attr;
+ struct device_attribute *devt_attr;
+
+@@ -338,6 +363,7 @@ struct device {
+ struct list_head node;
+ struct class *class; /* optional*/
+ dev_t devt; /* dev_t, creates the sysfs "dev" */
++ struct attribute_group **groups; /* optional groups */
+
+ void (*release)(struct device * dev);
+ };
+@@ -356,38 +382,41 @@ dev_set_drvdata (struct device *dev, voi
+
+ static inline int device_is_registered(struct device *dev)
+ {
+- return klist_node_attached(&dev->knode_bus);
++ return dev->is_registered;
+ }
+
+ /*
+ * High level routines for use by the bus drivers
+ */
+-extern int device_register(struct device * dev);
++extern int __must_check device_register(struct device * dev);
+ extern void device_unregister(struct device * dev);
+ extern void device_initialize(struct device * dev);
+-extern int device_add(struct device * dev);
++extern int __must_check device_add(struct device * dev);
+ extern void device_del(struct device * dev);
+ extern int device_for_each_child(struct device *, void *,
+ int (*fn)(struct device *, void *));
++extern int device_rename(struct device *dev, char *new_name);
+
+ /*
+ * Manual binding of a device to driver. See drivers/base/bus.c
+ * for information on use.
+ */
+-extern void device_bind_driver(struct device * dev);
++extern int __must_check device_bind_driver(struct device *dev);
+ extern void device_release_driver(struct device * dev);
+-extern int device_attach(struct device * dev);
+-extern void driver_attach(struct device_driver * drv);
+-extern void device_reprobe(struct device *dev);
++extern int __must_check device_attach(struct device * dev);
++extern int __must_check driver_attach(struct device_driver *drv);
++extern int __must_check device_reprobe(struct device *dev);
+
+ /*
+ * Easy functions for dynamically creating devices on the fly
+ */
+ extern struct device *device_create(struct class *cls, struct device *parent,
+- dev_t devt, char *fmt, ...)
++ dev_t devt, const char *fmt, ...)
+ __attribute__((format(printf,4,5)));
+ extern void device_destroy(struct class *cls, dev_t devt);
+
++extern int virtual_device_parent(struct device *dev);
++
+ /*
+ * Platform "fixup" functions - allow the platform to have their say
+ * about devices and actions that the general device layer doesn't
+@@ -412,7 +441,7 @@ extern void device_shutdown(void);
+
+
+ /* drivers/base/firmware.c */
+-extern int firmware_register(struct subsystem *);
++extern int __must_check firmware_register(struct subsystem *);
+ extern void firmware_unregister(struct subsystem *);
+
+ /* debugging and troubleshooting/diagnostic helpers. */
+diff --git a/include/linux/dlm.h b/include/linux/dlm.h
+new file mode 100644
+index 0000000..1b1dcb9
+--- /dev/null
++++ b/include/linux/dlm.h
+@@ -0,0 +1,302 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++#ifndef __DLM_DOT_H__
++#define __DLM_DOT_H__
++
++/*
++ * Interface to Distributed Lock Manager (DLM)
++ * routines and structures to use DLM lockspaces
++ */
++
++/*
++ * Lock Modes
++ */
++
++#define DLM_LOCK_IV -1 /* invalid */
++#define DLM_LOCK_NL 0 /* null */
++#define DLM_LOCK_CR 1 /* concurrent read */
++#define DLM_LOCK_CW 2 /* concurrent write */
++#define DLM_LOCK_PR 3 /* protected read */
++#define DLM_LOCK_PW 4 /* protected write */
++#define DLM_LOCK_EX 5 /* exclusive */
++
++/*
++ * Maximum size in bytes of a dlm_lock name
++ */
++
++#define DLM_RESNAME_MAXLEN 64
++
++/*
++ * Flags to dlm_lock
++ *
++ * DLM_LKF_NOQUEUE
++ *
++ * Do not queue the lock request on the wait queue if it cannot be granted
++ * immediately. If the lock cannot be granted because of this flag, DLM will
++ * either return -EAGAIN from the dlm_lock call or will return 0 from
++ * dlm_lock and -EAGAIN in the lock status block when the AST is executed.
++ *
++ * DLM_LKF_CANCEL
++ *
++ * Used to cancel a pending lock request or conversion. A converting lock is
++ * returned to its previously granted mode.
++ *
++ * DLM_LKF_CONVERT
++ *
++ * Indicates a lock conversion request. For conversions the name and namelen
++ * are ignored and the lock ID in the LKSB is used to identify the lock.
++ *
++ * DLM_LKF_VALBLK
++ *
++ * Requests DLM to return the current contents of the lock value block in the
++ * lock status block. When this flag is set in a lock conversion from PW or EX
++ * modes, DLM assigns the value specified in the lock status block to the lock
++ * value block of the lock resource. The LVB is a DLM_LVB_LEN size array
++ * containing application-specific information.
++ *
++ * DLM_LKF_QUECVT
++ *
++ * Force a conversion request to be queued, even if it is compatible with
++ * the granted modes of other locks on the same resource.
++ *
++ * DLM_LKF_IVVALBLK
++ *
++ * Invalidate the lock value block.
++ *
++ * DLM_LKF_CONVDEADLK
++ *
++ * Allows the dlm to resolve conversion deadlocks internally by demoting the
++ * granted mode of a converting lock to NL. The DLM_SBF_DEMOTED flag is
++ * returned for a conversion that's been effected by this.
++ *
++ * DLM_LKF_PERSISTENT
++ *
++ * Only relevant to locks originating in userspace. A persistent lock will not
++ * be removed if the process holding the lock exits.
++ *
++ * DLM_LKF_NODLKWT
++ * DLM_LKF_NODLCKBLK
++ *
++ * net yet implemented
++ *
++ * DLM_LKF_EXPEDITE
++ *
++ * Used only with new requests for NL mode locks. Tells the lock manager
++ * to grant the lock, ignoring other locks in convert and wait queues.
++ *
++ * DLM_LKF_NOQUEUEBAST
++ *
++ * Send blocking AST's before returning -EAGAIN to the caller. It is only
++ * used along with the NOQUEUE flag. Blocking AST's are not sent for failed
++ * NOQUEUE requests otherwise.
++ *
++ * DLM_LKF_HEADQUE
++ *
++ * Add a lock to the head of the convert or wait queue rather than the tail.
++ *
++ * DLM_LKF_NOORDER
++ *
++ * Disregard the standard grant order rules and grant a lock as soon as it
++ * is compatible with other granted locks.
++ *
++ * DLM_LKF_ORPHAN
++ *
++ * not yet implemented
++ *
++ * DLM_LKF_ALTPR
++ *
++ * If the requested mode cannot be granted immediately, try to grant the lock
++ * in PR mode instead. If this alternate mode is granted instead of the
++ * requested mode, DLM_SBF_ALTMODE is returned in the lksb.
++ *
++ * DLM_LKF_ALTCW
++ *
++ * The same as ALTPR, but the alternate mode is CW.
++ *
++ * DLM_LKF_FORCEUNLOCK
++ *
++ * Unlock the lock even if it is converting or waiting or has sublocks.
++ * Only really for use by the userland device.c code.
++ *
++ */
++
++#define DLM_LKF_NOQUEUE 0x00000001
++#define DLM_LKF_CANCEL 0x00000002
++#define DLM_LKF_CONVERT 0x00000004
++#define DLM_LKF_VALBLK 0x00000008
++#define DLM_LKF_QUECVT 0x00000010
++#define DLM_LKF_IVVALBLK 0x00000020
++#define DLM_LKF_CONVDEADLK 0x00000040
++#define DLM_LKF_PERSISTENT 0x00000080
++#define DLM_LKF_NODLCKWT 0x00000100
++#define DLM_LKF_NODLCKBLK 0x00000200
++#define DLM_LKF_EXPEDITE 0x00000400
++#define DLM_LKF_NOQUEUEBAST 0x00000800
++#define DLM_LKF_HEADQUE 0x00001000
++#define DLM_LKF_NOORDER 0x00002000
++#define DLM_LKF_ORPHAN 0x00004000
++#define DLM_LKF_ALTPR 0x00008000
++#define DLM_LKF_ALTCW 0x00010000
++#define DLM_LKF_FORCEUNLOCK 0x00020000
++
++/*
++ * Some return codes that are not in errno.h
++ */
++
++#define DLM_ECANCEL 0x10001
++#define DLM_EUNLOCK 0x10002
++
++typedef void dlm_lockspace_t;
++
++/*
++ * Lock status block
++ *
++ * Use this structure to specify the contents of the lock value block. For a
++ * conversion request, this structure is used to specify the lock ID of the
++ * lock. DLM writes the status of the lock request and the lock ID assigned
++ * to the request in the lock status block.
++ *
++ * sb_lkid: the returned lock ID. It is set on new (non-conversion) requests.
++ * It is available when dlm_lock returns.
++ *
++ * sb_lvbptr: saves or returns the contents of the lock's LVB according to rules
++ * shown for the DLM_LKF_VALBLK flag.
++ *
++ * sb_flags: DLM_SBF_DEMOTED is returned if in the process of promoting a lock,
++ * it was first demoted to NL to avoid conversion deadlock.
++ * DLM_SBF_VALNOTVALID is returned if the resource's LVB is marked invalid.
++ *
++ * sb_status: the returned status of the lock request set prior to AST
++ * execution. Possible return values:
++ *
++ * 0 if lock request was successful
++ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
++ * -ENOMEM if there is no memory to process request
++ * -EINVAL if there are invalid parameters
++ * -DLM_EUNLOCK if unlock request was successful
++ * -DLM_ECANCEL if a cancel completed successfully
++ */
++
++#define DLM_SBF_DEMOTED 0x01
++#define DLM_SBF_VALNOTVALID 0x02
++#define DLM_SBF_ALTMODE 0x04
++
++struct dlm_lksb {
++ int sb_status;
++ uint32_t sb_lkid;
++ char sb_flags;
++ char * sb_lvbptr;
++};
++
++
++#ifdef __KERNEL__
++
++#define DLM_LSFL_NODIR 0x00000001
++
++/*
++ * dlm_new_lockspace
++ *
++ * Starts a lockspace with the given name. If the named lockspace exists in
++ * the cluster, the calling node joins it.
++ */
++
++int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace,
++ uint32_t flags, int lvblen);
++
++/*
++ * dlm_release_lockspace
++ *
++ * Stop a lockspace.
++ */
++
++int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force);
++
++/*
++ * dlm_lock
++ *
++ * Make an asyncronous request to acquire or convert a lock on a named
++ * resource.
++ *
++ * lockspace: context for the request
++ * mode: the requested mode of the lock (DLM_LOCK_)
++ * lksb: lock status block for input and async return values
++ * flags: input flags (DLM_LKF_)
++ * name: name of the resource to lock, can be binary
++ * namelen: the length in bytes of the resource name (MAX_RESNAME_LEN)
++ * parent: the lock ID of a parent lock or 0 if none
++ * lockast: function DLM executes when it completes processing the request
++ * astarg: argument passed to lockast and bast functions
++ * bast: function DLM executes when this lock later blocks another request
++ *
++ * Returns:
++ * 0 if request is successfully queued for processing
++ * -EINVAL if any input parameters are invalid
++ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
++ * -ENOMEM if there is no memory to process request
++ * -ENOTCONN if there is a communication error
++ *
++ * If the call to dlm_lock returns an error then the operation has failed and
++ * the AST routine will not be called. If dlm_lock returns 0 it is still
++ * possible that the lock operation will fail. The AST routine will be called
++ * when the locking is complete and the status is returned in the lksb.
++ *
++ * If the AST routines or parameter are passed to a conversion operation then
++ * they will overwrite those values that were passed to a previous dlm_lock
++ * call.
++ *
++ * AST routines should not block (at least not for long), but may make
++ * any locking calls they please.
++ */
++
++int dlm_lock(dlm_lockspace_t *lockspace,
++ int mode,
++ struct dlm_lksb *lksb,
++ uint32_t flags,
++ void *name,
++ unsigned int namelen,
++ uint32_t parent_lkid,
++ void (*lockast) (void *astarg),
++ void *astarg,
++ void (*bast) (void *astarg, int mode));
++
++/*
++ * dlm_unlock
++ *
++ * Asynchronously release a lock on a resource. The AST routine is called
++ * when the resource is successfully unlocked.
++ *
++ * lockspace: context for the request
++ * lkid: the lock ID as returned in the lksb
++ * flags: input flags (DLM_LKF_)
++ * lksb: if NULL the lksb parameter passed to last lock request is used
++ * astarg: the arg used with the completion ast for the unlock
++ *
++ * Returns:
++ * 0 if request is successfully queued for processing
++ * -EINVAL if any input parameters are invalid
++ * -ENOTEMPTY if the lock still has sublocks
++ * -EBUSY if the lock is waiting for a remote lock operation
++ * -ENOTCONN if there is a communication error
++ */
++
++int dlm_unlock(dlm_lockspace_t *lockspace,
++ uint32_t lkid,
++ uint32_t flags,
++ struct dlm_lksb *lksb,
++ void *astarg);
++
++#endif /* __KERNEL__ */
++
++#endif /* __DLM_DOT_H__ */
++
+diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h
+new file mode 100644
+index 0000000..2a2dd18
+--- /dev/null
++++ b/include/linux/dlm_device.h
+@@ -0,0 +1,86 @@
++/******************************************************************************
++*******************************************************************************
++**
++** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
++**
++** This copyrighted material is made available to anyone wishing to use,
++** modify, copy, or redistribute it subject to the terms and conditions
++** of the GNU General Public License v.2.
++**
++*******************************************************************************
++******************************************************************************/
++
++/* This is the device interface for dlm, most users will use a library
++ * interface.
++ */
++
++#define DLM_USER_LVB_LEN 32
++
++/* Version of the device interface */
++#define DLM_DEVICE_VERSION_MAJOR 5
++#define DLM_DEVICE_VERSION_MINOR 0
++#define DLM_DEVICE_VERSION_PATCH 0
++
++/* struct passed to the lock write */
++struct dlm_lock_params {
++ __u8 mode;
++ __u8 namelen;
++ __u16 flags;
++ __u32 lkid;
++ __u32 parent;
++ void __user *castparam;
++ void __user *castaddr;
++ void __user *bastparam;
++ void __user *bastaddr;
++ struct dlm_lksb __user *lksb;
++ char lvb[DLM_USER_LVB_LEN];
++ char name[0];
++};
++
++struct dlm_lspace_params {
++ __u32 flags;
++ __u32 minor;
++ char name[0];
++};
++
++struct dlm_write_request {
++ __u32 version[3];
++ __u8 cmd;
++ __u8 is64bit;
++ __u8 unused[2];
++
++ union {
++ struct dlm_lock_params lock;
++ struct dlm_lspace_params lspace;
++ } i;
++};
++
++/* struct read from the "device" fd,
++ consists mainly of userspace pointers for the library to use */
++struct dlm_lock_result {
++ __u32 length;
++ void __user * user_astaddr;
++ void __user * user_astparam;
++ struct dlm_lksb __user * user_lksb;
++ struct dlm_lksb lksb;
++ __u8 bast_mode;
++ __u8 unused[3];
++ /* Offsets may be zero if no data is present */
++ __u32 lvb_offset;
++};
++
++/* Commands passed to the device */
++#define DLM_USER_LOCK 1
++#define DLM_USER_UNLOCK 2
++#define DLM_USER_QUERY 3
++#define DLM_USER_CREATE_LOCKSPACE 4
++#define DLM_USER_REMOVE_LOCKSPACE 5
++
++/* Arbitrary length restriction */
++#define MAX_LS_NAME_LEN 64
++
++/* Lockspace flags */
++#define DLM_USER_LSFLG_AUTOFREE 1
++#define DLM_USER_LSFLG_FORCEFREE 2
++
+diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
+index 9623bb6..8853fc4 100644
+--- a/include/linux/dm-ioctl.h
++++ b/include/linux/dm-ioctl.h
+@@ -285,9 +285,9 @@ typedef char ioctl_struct[308];
+ #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
+
+ #define DM_VERSION_MAJOR 4
+-#define DM_VERSION_MINOR 7
++#define DM_VERSION_MINOR 10
+ #define DM_VERSION_PATCHLEVEL 0
+-#define DM_VERSION_EXTRA "-ioctl (2006-06-24)"
++#define DM_VERSION_EXTRA "-ioctl (2006-09-14)"
+
+ /* Status bits */
+ #define DM_READONLY_FLAG (1 << 0) /* In/Out */
+diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
+index 635690c..ff203c4 100644
+--- a/include/linux/dma-mapping.h
++++ b/include/linux/dma-mapping.h
+@@ -24,6 +24,13 @@ enum dma_data_direction {
+ #define DMA_28BIT_MASK 0x000000000fffffffULL
+ #define DMA_24BIT_MASK 0x0000000000ffffffULL
+
++static inline int valid_dma_direction(int dma_direction)
++{
++ return ((dma_direction == DMA_BIDIRECTIONAL) ||
++ (dma_direction == DMA_TO_DEVICE) ||
++ (dma_direction == DMA_FROM_DEVICE));
++}
++
+ #include <asm/dma-mapping.h>
+
+ /* Backwards compat, remove in 2.7.x */
+diff --git a/include/linux/dmi.h b/include/linux/dmi.h
+index b2cd207..904bf3d 100644
+--- a/include/linux/dmi.h
++++ b/include/linux/dmi.h
+@@ -27,7 +27,8 @@ enum dmi_device_type {
+ DMI_DEV_TYPE_ETHERNET,
+ DMI_DEV_TYPE_TOKENRING,
+ DMI_DEV_TYPE_SOUND,
+- DMI_DEV_TYPE_IPMI = -1
++ DMI_DEV_TYPE_IPMI = -1,
++ DMI_DEV_TYPE_OEM_STRING = -2
+ };
+
+ struct dmi_header {
+@@ -68,6 +69,7 @@ extern struct dmi_device * dmi_find_devi
+ struct dmi_device *from);
+ extern void dmi_scan_machine(void);
+ extern int dmi_get_year(int field);
++extern int dmi_name_in_vendors(char *str);
+
+ #else
+
+@@ -76,6 +78,7 @@ static inline char * dmi_get_system_info
+ static inline struct dmi_device * dmi_find_device(int type, const char *name,
+ struct dmi_device *from) { return NULL; }
+ static inline int dmi_get_year(int year) { return 0; }
++static inline int dmi_name_in_vendors(char *s) { return 0; }
+
+ #endif
+
+diff --git a/include/linux/dvb/Kbuild b/include/linux/dvb/Kbuild
+index 63973af..d97b3a5 100644
+--- a/include/linux/dvb/Kbuild
++++ b/include/linux/dvb/Kbuild
+@@ -1,2 +1,9 @@
+-header-y += ca.h frontend.h net.h osd.h version.h
+-unifdef-y := audio.h dmx.h video.h
++header-y += ca.h
++header-y += frontend.h
++header-y += net.h
++header-y += osd.h
++header-y += version.h
++
++unifdef-y += audio.h
++unifdef-y += dmx.h
++unifdef-y += video.h
+diff --git a/include/linux/edd.h b/include/linux/edd.h
+index 162512b..b2b3e68 100644
+--- a/include/linux/edd.h
++++ b/include/linux/edd.h
+@@ -52,6 +52,7 @@
+ #define EDD_CL_EQUALS 0x3d646465 /* "edd=" */
+ #define EDD_CL_OFF 0x666f /* "of" for off */
+ #define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */
++#define EDD_CL_ON 0x6e6f /* "on" for on */
+
+ #ifndef __ASSEMBLY__
+
+diff --git a/include/linux/efs_fs_sb.h b/include/linux/efs_fs_sb.h
+index c76088b..ff1945e 100644
+--- a/include/linux/efs_fs_sb.h
++++ b/include/linux/efs_fs_sb.h
+@@ -9,8 +9,7 @@
+ #ifndef __EFS_FS_SB_H__
+ #define __EFS_FS_SB_H__
+
+-/* statfs() magic number for EFS */
+-#define EFS_SUPER_MAGIC 0x414A53
++#include <linux/magic.h>
+
+ /* EFS superblock magic numbers */
+ #define EFS_MAGIC 0x072959
+diff --git a/include/linux/eisa.h b/include/linux/eisa.h
+index 4079242..1ff7c13 100644
+--- a/include/linux/eisa.h
++++ b/include/linux/eisa.h
+@@ -3,8 +3,8 @@
+
+ #include <linux/ioport.h>
+ #include <linux/device.h>
++#include <linux/mod_devicetable.h>
+
+-#define EISA_SIG_LEN 8
+ #define EISA_MAX_SLOTS 8
+
+ #define EISA_MAX_RESOURCES 4
+@@ -27,12 +27,6 @@
+ #define EISA_CONFIG_ENABLED 1
+ #define EISA_CONFIG_FORCED 2
+
+-/* The EISA signature, in ASCII form, null terminated */
+-struct eisa_device_id {
+- char sig[EISA_SIG_LEN];
+- unsigned long driver_data;
+-};
+-
+ /* There is not much we can say about an EISA device, apart from
+ * signature, slot number, and base address. dma_mask is set by
+ * default to parent device mask..*/
+diff --git a/include/linux/elevator.h b/include/linux/elevator.h
+index 1713ace..2fa9f11 100644
+--- a/include/linux/elevator.h
++++ b/include/linux/elevator.h
+@@ -1,12 +1,16 @@
+ #ifndef _LINUX_ELEVATOR_H
+ #define _LINUX_ELEVATOR_H
+
++#include <linux/percpu.h>
++
++#ifdef CONFIG_BLOCK
++
+ typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
+ struct bio *);
+
+ typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
+
+-typedef void (elevator_merged_fn) (request_queue_t *, struct request *);
++typedef void (elevator_merged_fn) (request_queue_t *, struct request *, int);
+
+ typedef int (elevator_dispatch_fn) (request_queue_t *, int);
+
+@@ -14,9 +18,9 @@ typedef void (elevator_add_req_fn) (requ
+ typedef int (elevator_queue_empty_fn) (request_queue_t *);
+ 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, struct bio *);
++typedef int (elevator_may_queue_fn) (request_queue_t *, int);
+
+-typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, gfp_t);
++typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, gfp_t);
+ typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
+ typedef void (elevator_activate_req_fn) (request_queue_t *, struct request *);
+ typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
+@@ -66,7 +70,6 @@ struct elevator_type
+ {
+ struct list_head list;
+ struct elevator_ops ops;
+- struct elevator_type *elevator_type;
+ struct elv_fs_entry *elevator_attrs;
+ char elevator_name[ELV_NAME_MAX];
+ struct module *elevator_owner;
+@@ -82,19 +85,21 @@ struct elevator_queue
+ struct kobject kobj;
+ struct elevator_type *elevator_type;
+ struct mutex sysfs_lock;
++ struct hlist_head *hash;
+ };
+
+ /*
+ * block elevator interface
+ */
+ extern void elv_dispatch_sort(request_queue_t *, struct request *);
++extern void elv_dispatch_add_tail(request_queue_t *, struct request *);
+ extern void elv_add_request(request_queue_t *, struct request *, int, int);
+ extern void __elv_add_request(request_queue_t *, struct request *, int, int);
+ extern void elv_insert(request_queue_t *, struct request *, int);
+ extern int elv_merge(request_queue_t *, struct request **, struct bio *);
+ extern void elv_merge_requests(request_queue_t *, struct request *,
+ struct request *);
+-extern void elv_merged_request(request_queue_t *, struct request *);
++extern void elv_merged_request(request_queue_t *, struct request *, int);
+ extern void elv_dequeue_request(request_queue_t *, struct request *);
+ extern void elv_requeue_request(request_queue_t *, struct request *);
+ extern int elv_queue_empty(request_queue_t *);
+@@ -103,9 +108,9 @@ extern struct request *elv_former_reques
+ 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, struct bio *);
++extern int elv_may_queue(request_queue_t *, int);
+ extern void elv_completed_request(request_queue_t *, struct request *);
+-extern int elv_set_request(request_queue_t *, struct request *, struct bio *, gfp_t);
++extern int elv_set_request(request_queue_t *, struct request *, gfp_t);
+ extern void elv_put_request(request_queue_t *, struct request *);
+
+ /*
+@@ -125,6 +130,19 @@ extern void elevator_exit(elevator_t *);
+ extern int elv_rq_merge_ok(struct request *, struct bio *);
+
+ /*
++ * Helper functions.
++ */
++extern struct request *elv_rb_former_request(request_queue_t *, struct request *);
++extern struct request *elv_rb_latter_request(request_queue_t *, struct request *);
++
++/*
++ * rb support functions.
++ */
++extern struct request *elv_rb_add(struct rb_root *, struct request *);
++extern void elv_rb_del(struct rb_root *, struct request *);
++extern struct request *elv_rb_find(struct rb_root *, sector_t);
++
++/*
+ * Return values from elevator merger
+ */
+ #define ELEVATOR_NO_MERGE 0
+@@ -149,5 +167,42 @@ enum {
+ };
+
+ #define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors)
++#define rb_entry_rq(node) rb_entry((node), struct request, rb_node)
+
++/*
++ * Hack to reuse the donelist list_head as the fifo time holder while
++ * the request is in the io scheduler. Saves an unsigned long in rq.
++ */
++#define rq_fifo_time(rq) ((unsigned long) (rq)->donelist.next)
++#define rq_set_fifo_time(rq,exp) ((rq)->donelist.next = (void *) (exp))
++#define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
++#define rq_fifo_clear(rq) do { \
++ list_del_init(&(rq)->queuelist); \
++ INIT_LIST_HEAD(&(rq)->donelist); \
++ } while (0)
++
++/*
++ * io context count accounting
++ */
++#define elv_ioc_count_mod(name, __val) \
++ do { \
++ preempt_disable(); \
++ __get_cpu_var(name) += (__val); \
++ preempt_enable(); \
++ } while (0)
++
++#define elv_ioc_count_inc(name) elv_ioc_count_mod(name, 1)
++#define elv_ioc_count_dec(name) elv_ioc_count_mod(name, -1)
++
++#define elv_ioc_count_read(name) \
++({ \
++ unsigned long __val = 0; \
++ int __cpu; \
++ smp_wmb(); \
++ for_each_possible_cpu(__cpu) \
++ __val += per_cpu(name, __cpu); \
++ __val; \
++})
++
++#endif /* CONFIG_BLOCK */
+ #endif
+diff --git a/include/linux/elf-em.h b/include/linux/elf-em.h
+index 6a5796c..666e0a5 100644
+--- a/include/linux/elf-em.h
++++ b/include/linux/elf-em.h
+@@ -31,6 +31,7 @@
+ #define EM_M32R 88 /* Renesas M32R */
+ #define EM_H8_300 46 /* Renesas H8/300,300H,H8S */
+ #define EM_FRV 0x5441 /* Fujitsu FR-V */
++#define EM_AVR32 0x18ad /* Atmel AVR32 */
+
+ /*
+ * This is an interim value that we will use until the committee comes
+diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h
+new file mode 100644
+index 0000000..67396db
+--- /dev/null
++++ b/include/linux/elfnote.h
+@@ -0,0 +1,90 @@
++#ifndef _LINUX_ELFNOTE_H
++#define _LINUX_ELFNOTE_H
++/*
++ * Helper macros to generate ELF Note structures, which are put into a
++ * PT_NOTE segment of the final vmlinux image. These are useful for
++ * including name-value pairs of metadata into the kernel binary (or
++ * modules?) for use by external programs.
++ *
++ * Each note has three parts: a name, a type and a desc. The name is
++ * intended to distinguish the note's originator, so it would be a
++ * company, project, subsystem, etc; it must be in a suitable form for
++ * use in a section name. The type is an integer which is used to tag
++ * the data, and is considered to be within the "name" namespace (so
++ * "FooCo"'s type 42 is distinct from "BarProj"'s type 42). The
++ * "desc" field is the actual data. There are no constraints on the
++ * desc field's contents, though typically they're fairly small.
++ *
++ * All notes from a given NAME are put into a section named
++ * .note.NAME. When the kernel image is finally linked, all the notes
++ * are packed into a single .notes section, which is mapped into the
++ * PT_NOTE segment. Because notes for a given name are grouped into
++ * the same section, they'll all be adjacent the output file.
++ *
++ * This file defines macros for both C and assembler use. Their
++ * syntax is slightly different, but they're semantically similar.
++ *
++ * See the ELF specification for more detail about ELF notes.
++ */
++
++#ifdef __ASSEMBLER__
++/*
++ * Generate a structure with the same shape as Elf{32,64}_Nhdr (which
++ * turn out to be the same size and shape), followed by the name and
++ * desc data with appropriate padding. The 'desctype' argument is the
++ * assembler pseudo op defining the type of the data e.g. .asciz while
++ * 'descdata' is the data itself e.g. "hello, world".
++ *
++ * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
++ * ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
++ */
++#define ELFNOTE(name, type, desctype, descdata) \
++.pushsection .note.name ; \
++ .align 4 ; \
++ .long 2f - 1f /* namesz */ ; \
++ .long 4f - 3f /* descsz */ ; \
++ .long type ; \
++1:.asciz "name" ; \
++2:.align 4 ; \
++3:desctype descdata ; \
++4:.align 4 ; \
++.popsection ;
++#else /* !__ASSEMBLER__ */
++#include <linux/elf.h>
++/*
++ * Use an anonymous structure which matches the shape of
++ * Elf{32,64}_Nhdr, but includes the name and desc data. The size and
++ * type of name and desc depend on the macro arguments. "name" must
++ * be a literal string, and "desc" must be passed by value. You may
++ * only define one note per line, since __LINE__ is used to generate
++ * unique symbols.
++ */
++#define _ELFNOTE_PASTE(a,b) a##b
++#define _ELFNOTE(size, name, unique, type, desc) \
++ static const struct { \
++ struct elf##size##_note _nhdr; \
++ unsigned char _name[sizeof(name)] \
++ __attribute__((aligned(sizeof(Elf##size##_Word)))); \
++ typeof(desc) _desc \
++ __attribute__((aligned(sizeof(Elf##size##_Word)))); \
++ } _ELFNOTE_PASTE(_note_, unique) \
++ __attribute_used__ \
++ __attribute__((section(".note." name), \
++ aligned(sizeof(Elf##size##_Word)), \
++ unused)) = { \
++ { \
++ sizeof(name), \
++ sizeof(desc), \
++ type, \
++ }, \
++ name, \
++ desc \
++ }
++#define ELFNOTE(size, name, type, desc) \
++ _ELFNOTE(size, name, __LINE__, type, desc)
++
++#define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc)
++#define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc)
++#endif /* __ASSEMBLER__ */
++
++#endif /* _LINUX_ELFNOTE_H */
+diff --git a/include/linux/err.h b/include/linux/err.h
+index cd3b367..1ab1d44 100644
+--- a/include/linux/err.h
++++ b/include/linux/err.h
+@@ -15,6 +15,8 @@
+ */
+ #define MAX_ERRNO 4095
+
++#ifndef __ASSEMBLY__
++
+ #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
+
+ static inline void *ERR_PTR(long error)
+@@ -32,4 +34,6 @@ static inline long IS_ERR(const void *pt
+ return IS_ERR_VALUE((unsigned long)ptr);
+ }
+
++#endif
++
+ #endif /* _LINUX_ERR_H */
+diff --git a/include/linux/errqueue.h b/include/linux/errqueue.h
+index 408118a..92f8d4f 100644
+--- a/include/linux/errqueue.h
++++ b/include/linux/errqueue.h
+@@ -38,7 +38,7 @@ struct sock_exterr_skb
+ } header;
+ struct sock_extended_err ee;
+ u16 addr_offset;
+- u16 port;
++ __be16 port;
+ };
+
+ #endif
+diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
+index facf34e..153d755 100644
+--- a/include/linux/ext2_fs.h
++++ b/include/linux/ext2_fs.h
+@@ -17,6 +17,7 @@
+ #define _LINUX_EXT2_FS_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
+
+ /*
+ * The second extended filesystem constants/structures
+@@ -63,11 +64,6 @@
+ /* First non-reserved inode for old ext2 filesystems */
+ #define EXT2_GOOD_OLD_FIRST_INO 11
+
+-/*
+- * The second extended file system magic number
+- */
+-#define EXT2_SUPER_MAGIC 0xEF53
+-
+ #ifdef __KERNEL__
+ #include <linux/ext2_fs_sb.h>
+ static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
+@@ -169,41 +165,49 @@ struct ext2_group_desc
+ #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+ /*
+- * Inode flags
++ * Inode flags (GETFLAGS/SETFLAGS)
+ */
+-#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
+-#define EXT2_UNRM_FL 0x00000002 /* Undelete */
+-#define EXT2_COMPR_FL 0x00000004 /* Compress file */
+-#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
+-#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
+-#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
+-#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+-#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
++#define EXT2_SECRM_FL FS_SECRM_FL /* Secure deletion */
++#define EXT2_UNRM_FL FS_UNRM_FL /* Undelete */
++#define EXT2_COMPR_FL FS_COMPR_FL /* Compress file */
++#define EXT2_SYNC_FL FS_SYNC_FL /* Synchronous updates */
++#define EXT2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */
++#define EXT2_APPEND_FL FS_APPEND_FL /* writes to file may only append */
++#define EXT2_NODUMP_FL FS_NODUMP_FL /* do not dump file */
++#define EXT2_NOATIME_FL FS_NOATIME_FL /* do not update atime */
+ /* Reserved for compression usage... */
+-#define EXT2_DIRTY_FL 0x00000100
+-#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+-#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
+-#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
++#define EXT2_DIRTY_FL FS_DIRTY_FL
++#define EXT2_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */
++#define EXT2_NOCOMP_FL FS_NOCOMP_FL /* Don't compress */
++#define EXT2_ECOMPR_FL FS_ECOMPR_FL /* Compression error */
+ /* End compression flags --- maybe not all used */
+-#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+-#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
+-#define EXT2_IMAGIC_FL 0x00002000 /* AFS directory */
+-#define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */
+-#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+-#define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
+-#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+-#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+-
+-#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
+-#define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
++#define EXT2_BTREE_FL FS_BTREE_FL /* btree format dir */
++#define EXT2_INDEX_FL FS_INDEX_FL /* hash-indexed directory */
++#define EXT2_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */
++#define EXT2_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* Reserved for ext3 */
++#define EXT2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */
++#define EXT2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */
++#define EXT2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/
++#define EXT2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */
++
++#define EXT2_FL_USER_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */
++#define EXT2_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */
+
+ /*
+ * ioctl commands
+ */
+-#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
+-#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
+-#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
+-#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
++#define EXT2_IOC_GETFLAGS FS_IOC_GETFLAGS
++#define EXT2_IOC_SETFLAGS FS_IOC_SETFLAGS
++#define EXT2_IOC_GETVERSION FS_IOC_GETVERSION
++#define EXT2_IOC_SETVERSION FS_IOC_SETVERSION
++
++/*
++ * ioctl commands in 32 bit emulation
++ */
++#define EXT2_IOC32_GETFLAGS FS_IOC32_GETFLAGS
++#define EXT2_IOC32_SETFLAGS FS_IOC32_SETFLAGS
++#define EXT2_IOC32_GETVERSION FS_IOC32_GETVERSION
++#define EXT2_IOC32_SETVERSION FS_IOC32_SETVERSION
+
+ /*
+ * Structure of an inode on the disk
+diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
+index 9f9cce7..11cca1b 100644
+--- a/include/linux/ext3_fs.h
++++ b/include/linux/ext3_fs.h
+@@ -17,6 +17,7 @@
+ #define _LINUX_EXT3_FS_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
+
+ /*
+ * The second extended filesystem constants/structures
+@@ -67,11 +68,6 @@
+ #define EXT3_GOOD_OLD_FIRST_INO 11
+
+ /*
+- * The second extended file system magic number
+- */
+-#define EXT3_SUPER_MAGIC 0xEF53
+-
+-/*
+ * Maximal count of links to a file
+ */
+ #define EXT3_LINK_MAX 32000
+@@ -220,14 +216,14 @@ struct ext3_new_group_data {
+ /*
+ * ioctl commands
+ */
+-#define EXT3_IOC_GETFLAGS _IOR('f', 1, long)
+-#define EXT3_IOC_SETFLAGS _IOW('f', 2, long)
++#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS
++#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS
+ #define EXT3_IOC_GETVERSION _IOR('f', 3, long)
+ #define EXT3_IOC_SETVERSION _IOW('f', 4, long)
+ #define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
+ #define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input)
+-#define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long)
+-#define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long)
++#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION
++#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION
+ #ifdef CONFIG_JBD_DEBUG
+ #define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
+ #endif
+@@ -235,6 +231,23 @@ struct ext3_new_group_data {
+ #define EXT3_IOC_SETRSVSZ _IOW('f', 6, long)
+
+ /*
++ * ioctl commands in 32 bit emulation
++ */
++#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS
++#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS
++#define EXT3_IOC32_GETVERSION _IOR('f', 3, int)
++#define EXT3_IOC32_SETVERSION _IOW('f', 4, int)
++#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int)
++#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int)
++#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
++#ifdef CONFIG_JBD_DEBUG
++#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
++#endif
++#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
++#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
++
++
++/*
+ * Mount options
+ */
+ struct ext3_mount_options {
+@@ -464,7 +477,7 @@ struct ext3_super_block {
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+- __u16 s_reserved_gdt_blocks; /* Per group desc for online growth */
++ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+@@ -477,7 +490,7 @@ struct ext3_super_block {
+ __u8 s_reserved_char_pad;
+ __u16 s_reserved_word_pad;
+ __le32 s_default_mount_opts;
+- __le32 s_first_meta_bg; /* First metablock block group */
++ __le32 s_first_meta_bg; /* First metablock block group */
+ __u32 s_reserved[190]; /* Padding to the end of the block */
+ };
+
+@@ -816,6 +829,7 @@ extern void ext3_set_aops(struct inode *
+ /* ioctl.c */
+ extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
++extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long);
+
+ /* namei.c */
+ extern int ext3_orphan_add(handle_t *, struct inode *);
+diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
+index 2f18b95..4395e52 100644
+--- a/include/linux/ext3_fs_i.h
++++ b/include/linux/ext3_fs_i.h
+@@ -35,7 +35,7 @@ struct ext3_reserve_window {
+ };
+
+ struct ext3_reserve_window_node {
+- struct rb_node rsv_node;
++ struct rb_node rsv_node;
+ __u32 rsv_goal_size;
+ __u32 rsv_alloc_hit;
+ struct ext3_reserve_window rsv_window;
+diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
+index c8307c0..ce0e610 100644
+--- a/include/linux/ext3_jbd.h
++++ b/include/linux/ext3_jbd.h
+@@ -23,7 +23,7 @@
+
+ /* Define the number of blocks we need to account to a transaction to
+ * modify one block of data.
+- *
++ *
+ * We may have to touch one inode, one bitmap buffer, up to three
+ * indirection blocks, the group and superblock summaries, and the data
+ * block to complete the transaction. */
+@@ -88,16 +88,16 @@
+ #endif
+
+ int
+-ext3_mark_iloc_dirty(handle_t *handle,
++ext3_mark_iloc_dirty(handle_t *handle,
+ struct inode *inode,
+ struct ext3_iloc *iloc);
+
+-/*
++/*
+ * On success, We end up with an outstanding reference count against
+- * iloc->bh. This _must_ be cleaned up later.
++ * iloc->bh. This _must_ be cleaned up later.
+ */
+
+-int ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
++int ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
+ struct ext3_iloc *iloc);
+
+ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode);
+diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
+new file mode 100644
+index 0000000..498503e
+--- /dev/null
++++ b/include/linux/ext4_fs.h
+@@ -0,0 +1,994 @@
++/*
++ * linux/include/linux/ext4_fs.h
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/include/linux/minix_fs.h
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ */
++
++#ifndef _LINUX_EXT4_FS_H
++#define _LINUX_EXT4_FS_H
++
++#include <linux/types.h>
++#include <linux/blkdev.h>
++#include <linux/magic.h>
++
++/*
++ * The second extended filesystem constants/structures
++ */
++
++/*
++ * Define EXT4FS_DEBUG to produce debug messages
++ */
++#undef EXT4FS_DEBUG
++
++/*
++ * Define EXT4_RESERVATION to reserve data blocks for expanding files
++ */
++#define EXT4_DEFAULT_RESERVE_BLOCKS 8
++/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
++#define EXT4_MAX_RESERVE_BLOCKS 1027
++#define EXT4_RESERVE_WINDOW_NOT_ALLOCATED 0
++/*
++ * Always enable hashed directories
++ */
++#define CONFIG_EXT4_INDEX
++
++/*
++ * Debug code
++ */
++#ifdef EXT4FS_DEBUG
++#define ext4_debug(f, a...) \
++ do { \
++ printk (KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \
++ __FILE__, __LINE__, __FUNCTION__); \
++ printk (KERN_DEBUG f, ## a); \
++ } while (0)
++#else
++#define ext4_debug(f, a...) do {} while (0)
++#endif
++
++/*
++ * Special inodes numbers
++ */
++#define EXT4_BAD_INO 1 /* Bad blocks inode */
++#define EXT4_ROOT_INO 2 /* Root inode */
++#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */
++#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
++#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
++#define EXT4_JOURNAL_INO 8 /* Journal inode */
++
++/* First non-reserved inode for old ext4 filesystems */
++#define EXT4_GOOD_OLD_FIRST_INO 11
++
++/*
++ * Maximal count of links to a file
++ */
++#define EXT4_LINK_MAX 32000
++
++/*
++ * Macro-instructions used to manage several block sizes
++ */
++#define EXT4_MIN_BLOCK_SIZE 1024
++#define EXT4_MAX_BLOCK_SIZE 4096
++#define EXT4_MIN_BLOCK_LOG_SIZE 10
++#ifdef __KERNEL__
++# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize)
++#else
++# define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
++#endif
++#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (__u32))
++#ifdef __KERNEL__
++# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
++#else
++# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
++#endif
++#ifdef __KERNEL__
++#define EXT4_ADDR_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_addr_per_block_bits)
++#define EXT4_INODE_SIZE(s) (EXT4_SB(s)->s_inode_size)
++#define EXT4_FIRST_INO(s) (EXT4_SB(s)->s_first_ino)
++#else
++#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
++ EXT4_GOOD_OLD_INODE_SIZE : \
++ (s)->s_inode_size)
++#define EXT4_FIRST_INO(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
++ EXT4_GOOD_OLD_FIRST_INO : \
++ (s)->s_first_ino)
++#endif
++
++/*
++ * Macro-instructions used to manage fragments
++ */
++#define EXT4_MIN_FRAG_SIZE 1024
++#define EXT4_MAX_FRAG_SIZE 4096
++#define EXT4_MIN_FRAG_LOG_SIZE 10
++#ifdef __KERNEL__
++# define EXT4_FRAG_SIZE(s) (EXT4_SB(s)->s_frag_size)
++# define EXT4_FRAGS_PER_BLOCK(s) (EXT4_SB(s)->s_frags_per_block)
++#else
++# define EXT4_FRAG_SIZE(s) (EXT4_MIN_FRAG_SIZE << (s)->s_log_frag_size)
++# define EXT4_FRAGS_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_FRAG_SIZE(s))
++#endif
++
++/*
++ * Structure of a blocks group descriptor
++ */
++struct ext4_group_desc
++{
++ __le32 bg_block_bitmap; /* Blocks bitmap block */
++ __le32 bg_inode_bitmap; /* Inodes bitmap block */
++ __le32 bg_inode_table; /* Inodes table block */
++ __le16 bg_free_blocks_count; /* Free blocks count */
++ __le16 bg_free_inodes_count; /* Free inodes count */
++ __le16 bg_used_dirs_count; /* Directories count */
++ __u16 bg_flags;
++ __u32 bg_reserved[3];
++ __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
++ __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
++ __le32 bg_inode_table_hi; /* Inodes table block MSB */
++};
++
++#ifdef __KERNEL__
++#include <linux/ext4_fs_i.h>
++#include <linux/ext4_fs_sb.h>
++#endif
++/*
++ * Macro-instructions used to manage group descriptors
++ */
++#define EXT4_MIN_DESC_SIZE 32
++#define EXT4_MIN_DESC_SIZE_64BIT 64
++#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE
++#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size)
++#ifdef __KERNEL__
++# define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group)
++# define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block)
++# define EXT4_INODES_PER_GROUP(s) (EXT4_SB(s)->s_inodes_per_group)
++# define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits)
++#else
++# define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
++# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s))
++# define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
++#endif
++
++/*
++ * Constants relative to the data blocks
++ */
++#define EXT4_NDIR_BLOCKS 12
++#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
++#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
++#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
++#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
++
++/*
++ * Inode flags
++ */
++#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */
++#define EXT4_UNRM_FL 0x00000002 /* Undelete */
++#define EXT4_COMPR_FL 0x00000004 /* Compress file */
++#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */
++#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */
++#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */
++#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */
++#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */
++/* Reserved for compression usage... */
++#define EXT4_DIRTY_FL 0x00000100
++#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
++#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */
++#define EXT4_ECOMPR_FL 0x00000800 /* Compression error */
++/* End compression flags --- maybe not all used */
++#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */
++#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */
++#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
++#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */
++#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
++#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
++#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
++#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
++
++#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
++#define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
++
++/*
++ * Inode dynamic state flags
++ */
++#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */
++#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */
++#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */
++
++/* Used to pass group descriptor data when online resize is done */
++struct ext4_new_group_input {
++ __u32 group; /* Group number for this data */
++ __u64 block_bitmap; /* Absolute block number of block bitmap */
++ __u64 inode_bitmap; /* Absolute block number of inode bitmap */
++ __u64 inode_table; /* Absolute block number of inode table start */
++ __u32 blocks_count; /* Total number of blocks in this group */
++ __u16 reserved_blocks; /* Number of reserved blocks in this group */
++ __u16 unused;
++};
++
++/* The struct ext4_new_group_input in kernel space, with free_blocks_count */
++struct ext4_new_group_data {
++ __u32 group;
++ __u64 block_bitmap;
++ __u64 inode_bitmap;
++ __u64 inode_table;
++ __u32 blocks_count;
++ __u16 reserved_blocks;
++ __u16 unused;
++ __u32 free_blocks_count;
++};
++
++
++/*
++ * ioctl commands
++ */
++#define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS
++#define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS
++#define EXT4_IOC_GETVERSION _IOR('f', 3, long)
++#define EXT4_IOC_SETVERSION _IOW('f', 4, long)
++#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
++#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)
++#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
++#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
++#ifdef CONFIG_JBD_DEBUG
++#define EXT4_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
++#endif
++#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
++#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)
++
++/*
++ * ioctl commands in 32 bit emulation
++ */
++#define EXT4_IOC32_GETFLAGS FS_IOC32_GETFLAGS
++#define EXT4_IOC32_SETFLAGS FS_IOC32_SETFLAGS
++#define EXT4_IOC32_GETVERSION _IOR('f', 3, int)
++#define EXT4_IOC32_SETVERSION _IOW('f', 4, int)
++#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int)
++#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
++#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
++#ifdef CONFIG_JBD_DEBUG
++#define EXT4_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
++#endif
++#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
++#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
++
++
++/*
++ * Mount options
++ */
++struct ext4_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 ext4_inode {
++ __le16 i_mode; /* File mode */
++ __le16 i_uid; /* Low 16 bits of Owner Uid */
++ __le32 i_size; /* Size in bytes */
++ __le32 i_atime; /* Access time */
++ __le32 i_ctime; /* Creation time */
++ __le32 i_mtime; /* Modification time */
++ __le32 i_dtime; /* Deletion Time */
++ __le16 i_gid; /* Low 16 bits of Group Id */
++ __le16 i_links_count; /* Links count */
++ __le32 i_blocks; /* Blocks count */
++ __le32 i_flags; /* File flags */
++ union {
++ struct {
++ __u32 l_i_reserved1;
++ } linux1;
++ struct {
++ __u32 h_i_translator;
++ } hurd1;
++ struct {
++ __u32 m_i_reserved1;
++ } masix1;
++ } osd1; /* OS dependent 1 */
++ __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
++ __le32 i_generation; /* File version (for NFS) */
++ __le32 i_file_acl; /* File ACL */
++ __le32 i_dir_acl; /* Directory ACL */
++ __le32 i_faddr; /* Fragment address */
++ union {
++ struct {
++ __u8 l_i_frag; /* Fragment number */
++ __u8 l_i_fsize; /* Fragment size */
++ __le16 l_i_file_acl_high;
++ __le16 l_i_uid_high; /* these 2 fields */
++ __le16 l_i_gid_high; /* were reserved2[0] */
++ __u32 l_i_reserved2;
++ } linux2;
++ struct {
++ __u8 h_i_frag; /* Fragment number */
++ __u8 h_i_fsize; /* Fragment size */
++ __u16 h_i_mode_high;
++ __u16 h_i_uid_high;
++ __u16 h_i_gid_high;
++ __u32 h_i_author;
++ } hurd2;
++ struct {
++ __u8 m_i_frag; /* Fragment number */
++ __u8 m_i_fsize; /* Fragment size */
++ __le16 m_i_file_acl_high;
++ __u32 m_i_reserved2[2];
++ } masix2;
++ } osd2; /* OS dependent 2 */
++ __le16 i_extra_isize;
++ __le16 i_pad1;
++};
++
++#define i_size_high i_dir_acl
++
++#if defined(__KERNEL__) || defined(__linux__)
++#define i_reserved1 osd1.linux1.l_i_reserved1
++#define i_frag osd2.linux2.l_i_frag
++#define i_fsize osd2.linux2.l_i_fsize
++#define i_file_acl_high osd2.linux2.l_i_file_acl_high
++#define i_uid_low i_uid
++#define i_gid_low i_gid
++#define i_uid_high osd2.linux2.l_i_uid_high
++#define i_gid_high osd2.linux2.l_i_gid_high
++#define i_reserved2 osd2.linux2.l_i_reserved2
++
++#elif defined(__GNU__)
++
++#define i_translator osd1.hurd1.h_i_translator
++#define i_frag osd2.hurd2.h_i_frag;
++#define i_fsize osd2.hurd2.h_i_fsize;
++#define i_uid_high osd2.hurd2.h_i_uid_high
++#define i_gid_high osd2.hurd2.h_i_gid_high
++#define i_author osd2.hurd2.h_i_author
++
++#elif defined(__masix__)
++
++#define i_reserved1 osd1.masix1.m_i_reserved1
++#define i_frag osd2.masix2.m_i_frag
++#define i_fsize osd2.masix2.m_i_fsize
++#define i_file_acl_high osd2.masix2.m_i_file_acl_high
++#define i_reserved2 osd2.masix2.m_i_reserved2
++
++#endif /* defined(__KERNEL__) || defined(__linux__) */
++
++/*
++ * File system states
++ */
++#define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */
++#define EXT4_ERROR_FS 0x0002 /* Errors detected */
++#define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */
++
++/*
++ * Mount flags
++ */
++#define EXT4_MOUNT_CHECK 0x00001 /* Do mount-time checks */
++#define EXT4_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */
++#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
++#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
++#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
++#define EXT4_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */
++#define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */
++#define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */
++#define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/
++#define EXT4_MOUNT_ABORT 0x00200 /* Fatal error detected */
++#define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */
++#define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */
++#define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */
++#define EXT4_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */
++#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
++#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
++#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
++#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
++#define EXT4_MOUNT_RESERVATION 0x10000 /* Preallocation */
++#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
++#define EXT4_MOUNT_NOBH 0x40000 /* No bufferheads */
++#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
++#define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
++#define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
++#define EXT4_MOUNT_EXTENTS 0x400000 /* Extents support */
++
++/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
++#ifndef _LINUX_EXT2_FS_H
++#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
++#define set_opt(o, opt) o |= EXT4_MOUNT_##opt
++#define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \
++ EXT4_MOUNT_##opt)
++#else
++#define EXT2_MOUNT_NOLOAD EXT4_MOUNT_NOLOAD
++#define EXT2_MOUNT_ABORT EXT4_MOUNT_ABORT
++#define EXT2_MOUNT_DATA_FLAGS EXT4_MOUNT_DATA_FLAGS
++#endif
++
++#define ext4_set_bit ext2_set_bit
++#define ext4_set_bit_atomic ext2_set_bit_atomic
++#define ext4_clear_bit ext2_clear_bit
++#define ext4_clear_bit_atomic ext2_clear_bit_atomic
++#define ext4_test_bit ext2_test_bit
++#define ext4_find_first_zero_bit ext2_find_first_zero_bit
++#define ext4_find_next_zero_bit ext2_find_next_zero_bit
++
++/*
++ * Maximal mount counts between two filesystem checks
++ */
++#define EXT4_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
++#define EXT4_DFL_CHECKINTERVAL 0 /* Don't use interval check */
++
++/*
++ * Behaviour when detecting errors
++ */
++#define EXT4_ERRORS_CONTINUE 1 /* Continue execution */
++#define EXT4_ERRORS_RO 2 /* Remount fs read-only */
++#define EXT4_ERRORS_PANIC 3 /* Panic */
++#define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE
++
++/*
++ * Structure of the super block
++ */
++struct ext4_super_block {
++/*00*/ __le32 s_inodes_count; /* Inodes count */
++ __le32 s_blocks_count; /* Blocks count */
++ __le32 s_r_blocks_count; /* Reserved blocks count */
++ __le32 s_free_blocks_count; /* Free blocks count */
++/*10*/ __le32 s_free_inodes_count; /* Free inodes count */
++ __le32 s_first_data_block; /* First Data Block */
++ __le32 s_log_block_size; /* Block size */
++ __le32 s_log_frag_size; /* Fragment size */
++/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */
++ __le32 s_frags_per_group; /* # Fragments per group */
++ __le32 s_inodes_per_group; /* # Inodes per group */
++ __le32 s_mtime; /* Mount time */
++/*30*/ __le32 s_wtime; /* Write time */
++ __le16 s_mnt_count; /* Mount count */
++ __le16 s_max_mnt_count; /* Maximal mount count */
++ __le16 s_magic; /* Magic signature */
++ __le16 s_state; /* File system state */
++ __le16 s_errors; /* Behaviour when detecting errors */
++ __le16 s_minor_rev_level; /* minor revision level */
++/*40*/ __le32 s_lastcheck; /* time of last check */
++ __le32 s_checkinterval; /* max. time between checks */
++ __le32 s_creator_os; /* OS */
++ __le32 s_rev_level; /* Revision level */
++/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */
++ __le16 s_def_resgid; /* Default gid for reserved blocks */
++ /*
++ * These fields are for EXT4_DYNAMIC_REV superblocks only.
++ *
++ * Note: the difference between the compatible feature set and
++ * the incompatible feature set is that if there is a bit set
++ * in the incompatible feature set that the kernel doesn't
++ * know about, it should refuse to mount the filesystem.
++ *
++ * e2fsck's requirements are more strict; if it doesn't know
++ * about a feature in either the compatible or incompatible
++ * feature set, it must abort and not try to meddle with
++ * things it doesn't understand...
++ */
++ __le32 s_first_ino; /* First non-reserved inode */
++ __le16 s_inode_size; /* size of inode structure */
++ __le16 s_block_group_nr; /* block group # of this superblock */
++ __le32 s_feature_compat; /* compatible feature set */
++/*60*/ __le32 s_feature_incompat; /* incompatible feature set */
++ __le32 s_feature_ro_compat; /* readonly-compatible feature set */
++/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
++/*78*/ char s_volume_name[16]; /* volume name */
++/*88*/ char s_last_mounted[64]; /* directory where last mounted */
++/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
++ /*
++ * Performance hints. Directory preallocation should only
++ * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
++ */
++ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
++ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
++ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
++ /*
++ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
++ */
++/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
++/*E0*/ __le32 s_journal_inum; /* inode number of journal file */
++ __le32 s_journal_dev; /* device number of journal file */
++ __le32 s_last_orphan; /* start of list of inodes to delete */
++ __le32 s_hash_seed[4]; /* HTREE hash seed */
++ __u8 s_def_hash_version; /* Default hash version to use */
++ __u8 s_reserved_char_pad;
++ __le16 s_desc_size; /* size of group descriptor */
++/*100*/ __le32 s_default_mount_opts;
++ __le32 s_first_meta_bg; /* First metablock block group */
++ __le32 s_mkfs_time; /* When the filesystem was created */
++ __le32 s_jnl_blocks[17]; /* Backup of the journal inode */
++ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
++/*150*/ __le32 s_blocks_count_hi; /* Blocks count */
++ __le32 s_r_blocks_count_hi; /* Reserved blocks count */
++ __le32 s_free_blocks_count_hi; /* Free blocks count */
++ __u32 s_reserved[169]; /* Padding to the end of the block */
++};
++
++#ifdef __KERNEL__
++static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb)
++{
++ return sb->s_fs_info;
++}
++static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
++{
++ return container_of(inode, struct ext4_inode_info, vfs_inode);
++}
++
++static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
++{
++ return ino == EXT4_ROOT_INO ||
++ ino == EXT4_JOURNAL_INO ||
++ ino == EXT4_RESIZE_INO ||
++ (ino >= EXT4_FIRST_INO(sb) &&
++ ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
++}
++#else
++/* Assume that user mode programs are passing in an ext4fs superblock, not
++ * a kernel struct super_block. This will allow us to call the feature-test
++ * macros from user land. */
++#define EXT4_SB(sb) (sb)
++#endif
++
++#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
++
++/*
++ * Codes for operating systems
++ */
++#define EXT4_OS_LINUX 0
++#define EXT4_OS_HURD 1
++#define EXT4_OS_MASIX 2
++#define EXT4_OS_FREEBSD 3
++#define EXT4_OS_LITES 4
++
++/*
++ * Revision levels
++ */
++#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */
++#define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
++
++#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV
++#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV
++
++#define EXT4_GOOD_OLD_INODE_SIZE 128
++
++/*
++ * Feature set definitions
++ */
++
++#define EXT4_HAS_COMPAT_FEATURE(sb,mask) \
++ ( EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
++#define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask) \
++ ( EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
++#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \
++ ( EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
++#define EXT4_SET_COMPAT_FEATURE(sb,mask) \
++ EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
++#define EXT4_SET_RO_COMPAT_FEATURE(sb,mask) \
++ EXT4_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
++#define EXT4_SET_INCOMPAT_FEATURE(sb,mask) \
++ EXT4_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
++#define EXT4_CLEAR_COMPAT_FEATURE(sb,mask) \
++ EXT4_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
++#define EXT4_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
++ EXT4_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
++#define EXT4_CLEAR_INCOMPAT_FEATURE(sb,mask) \
++ EXT4_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
++
++#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
++#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
++#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
++#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
++#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
++#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
++
++#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
++#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
++#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
++
++#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
++#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
++#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
++#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
++#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
++#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
++#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
++
++#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
++#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
++ EXT4_FEATURE_INCOMPAT_RECOVER| \
++ EXT4_FEATURE_INCOMPAT_META_BG| \
++ EXT4_FEATURE_INCOMPAT_EXTENTS| \
++ EXT4_FEATURE_INCOMPAT_64BIT)
++#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
++ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
++ EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
++
++/*
++ * Default values for user and/or group using reserved blocks
++ */
++#define EXT4_DEF_RESUID 0
++#define EXT4_DEF_RESGID 0
++
++/*
++ * Default mount options
++ */
++#define EXT4_DEFM_DEBUG 0x0001
++#define EXT4_DEFM_BSDGROUPS 0x0002
++#define EXT4_DEFM_XATTR_USER 0x0004
++#define EXT4_DEFM_ACL 0x0008
++#define EXT4_DEFM_UID16 0x0010
++#define EXT4_DEFM_JMODE 0x0060
++#define EXT4_DEFM_JMODE_DATA 0x0020
++#define EXT4_DEFM_JMODE_ORDERED 0x0040
++#define EXT4_DEFM_JMODE_WBACK 0x0060
++
++/*
++ * Structure of a directory entry
++ */
++#define EXT4_NAME_LEN 255
++
++struct ext4_dir_entry {
++ __le32 inode; /* Inode number */
++ __le16 rec_len; /* Directory entry length */
++ __le16 name_len; /* Name length */
++ char name[EXT4_NAME_LEN]; /* File name */
++};
++
++/*
++ * The new version of the directory entry. Since EXT4 structures are
++ * stored in intel byte order, and the name_len field could never be
++ * bigger than 255 chars, it's safe to reclaim the extra byte for the
++ * file_type field.
++ */
++struct ext4_dir_entry_2 {
++ __le32 inode; /* Inode number */
++ __le16 rec_len; /* Directory entry length */
++ __u8 name_len; /* Name length */
++ __u8 file_type;
++ char name[EXT4_NAME_LEN]; /* File name */
++};
++
++/*
++ * Ext4 directory file types. Only the low 3 bits are used. The
++ * other bits are reserved for now.
++ */
++#define EXT4_FT_UNKNOWN 0
++#define EXT4_FT_REG_FILE 1
++#define EXT4_FT_DIR 2
++#define EXT4_FT_CHRDEV 3
++#define EXT4_FT_BLKDEV 4
++#define EXT4_FT_FIFO 5
++#define EXT4_FT_SOCK 6
++#define EXT4_FT_SYMLINK 7
++
++#define EXT4_FT_MAX 8
++
++/*
++ * EXT4_DIR_PAD defines the directory entries boundaries
++ *
++ * NOTE: It must be a multiple of 4
++ */
++#define EXT4_DIR_PAD 4
++#define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1)
++#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \
++ ~EXT4_DIR_ROUND)
++/*
++ * Hash Tree Directory indexing
++ * (c) Daniel Phillips, 2001
++ */
++
++#ifdef CONFIG_EXT4_INDEX
++ #define is_dx(dir) (EXT4_HAS_COMPAT_FEATURE(dir->i_sb, \
++ EXT4_FEATURE_COMPAT_DIR_INDEX) && \
++ (EXT4_I(dir)->i_flags & EXT4_INDEX_FL))
++#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX)
++#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
++#else
++ #define is_dx(dir) 0
++#define EXT4_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT4_LINK_MAX)
++#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
++#endif
++
++/* Legal values for the dx_root hash_version field: */
++
++#define DX_HASH_LEGACY 0
++#define DX_HASH_HALF_MD4 1
++#define DX_HASH_TEA 2
++
++#ifdef __KERNEL__
++
++/* hash info structure used by the directory hash */
++struct dx_hash_info
++{
++ u32 hash;
++ u32 minor_hash;
++ int hash_version;
++ u32 *seed;
++};
++
++#define EXT4_HTREE_EOF 0x7fffffff
++
++/*
++ * Control parameters used by ext4_htree_next_block
++ */
++#define HASH_NB_ALWAYS 1
++
++
++/*
++ * Describe an inode's exact location on disk and in memory
++ */
++struct ext4_iloc
++{
++ struct buffer_head *bh;
++ unsigned long offset;
++ unsigned long block_group;
++};
++
++static inline struct ext4_inode *ext4_raw_inode(struct ext4_iloc *iloc)
++{
++ return (struct ext4_inode *) (iloc->bh->b_data + iloc->offset);
++}
++
++/*
++ * This structure is stuffed into the struct file's private_data field
++ * for directories. It is where we put information so that we can do
++ * readdir operations in hash tree order.
++ */
++struct dir_private_info {
++ struct rb_root root;
++ struct rb_node *curr_node;
++ struct fname *extra_fname;
++ loff_t last_pos;
++ __u32 curr_hash;
++ __u32 curr_minor_hash;
++ __u32 next_hash;
++};
++
++/* calculate the first block number of the group */
++static inline ext4_fsblk_t
++ext4_group_first_block_no(struct super_block *sb, unsigned long group_no)
++{
++ return group_no * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
++}
++
++/*
++ * Special error return code only used by dx_probe() and its callers.
++ */
++#define ERR_BAD_DX_DIR -75000
++
++void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
++ unsigned long *blockgrpp, ext4_grpblk_t *offsetp);
++
++/*
++ * Function prototypes
++ */
++
++/*
++ * Ok, these declarations are also in <linux/kernel.h> but none of the
++ * ext4 source programs needs to include it so they are duplicated here.
++ */
++# define NORET_TYPE /**/
++# define ATTRIB_NORET __attribute__((noreturn))
++# define NORET_AND noreturn,
++
++/* balloc.c */
++extern unsigned int ext4_block_group(struct super_block *sb,
++ ext4_fsblk_t blocknr);
++extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
++ ext4_fsblk_t blocknr);
++extern int ext4_bg_has_super(struct super_block *sb, int group);
++extern unsigned long ext4_bg_num_gdb(struct super_block *sb, int group);
++extern ext4_fsblk_t ext4_new_block (handle_t *handle, struct inode *inode,
++ ext4_fsblk_t goal, int *errp);
++extern ext4_fsblk_t ext4_new_blocks (handle_t *handle, struct inode *inode,
++ ext4_fsblk_t goal, unsigned long *count, int *errp);
++extern void ext4_free_blocks (handle_t *handle, struct inode *inode,
++ ext4_fsblk_t block, unsigned long count);
++extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb,
++ ext4_fsblk_t block, unsigned long count,
++ unsigned long *pdquot_freed_blocks);
++extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *);
++extern void ext4_check_blocks_bitmap (struct super_block *);
++extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
++ unsigned int block_group,
++ struct buffer_head ** bh);
++extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
++extern void ext4_init_block_alloc_info(struct inode *);
++extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv);
++
++/* dir.c */
++extern int ext4_check_dir_entry(const char *, struct inode *,
++ struct ext4_dir_entry_2 *,
++ struct buffer_head *, unsigned long);
++extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
++ __u32 minor_hash,
++ struct ext4_dir_entry_2 *dirent);
++extern void ext4_htree_free_dir_info(struct dir_private_info *p);
++
++/* fsync.c */
++extern int ext4_sync_file (struct file *, struct dentry *, int);
++
++/* hash.c */
++extern int ext4fs_dirhash(const char *name, int len, struct
++ dx_hash_info *hinfo);
++
++/* ialloc.c */
++extern struct inode * ext4_new_inode (handle_t *, struct inode *, int);
++extern void ext4_free_inode (handle_t *, struct inode *);
++extern struct inode * ext4_orphan_get (struct super_block *, unsigned long);
++extern unsigned long ext4_count_free_inodes (struct super_block *);
++extern unsigned long ext4_count_dirs (struct super_block *);
++extern void ext4_check_inodes_bitmap (struct super_block *);
++extern unsigned long ext4_count_free (struct buffer_head *, unsigned);
++
++
++/* inode.c */
++int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
++ struct buffer_head *bh, ext4_fsblk_t blocknr);
++struct buffer_head * ext4_getblk (handle_t *, struct inode *, long, int, int *);
++struct buffer_head * ext4_bread (handle_t *, struct inode *, int, int, int *);
++int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
++ sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
++ int create, int extend_disksize);
++
++extern void ext4_read_inode (struct inode *);
++extern int ext4_write_inode (struct inode *, int);
++extern int ext4_setattr (struct dentry *, struct iattr *);
++extern void ext4_delete_inode (struct inode *);
++extern int ext4_sync_inode (handle_t *, struct inode *);
++extern void ext4_discard_reservation (struct inode *);
++extern void ext4_dirty_inode(struct inode *);
++extern int ext4_change_inode_journal_flag(struct inode *, int);
++extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
++extern void ext4_truncate (struct inode *);
++extern void ext4_set_inode_flags(struct inode *);
++extern void ext4_set_aops(struct inode *inode);
++extern int ext4_writepage_trans_blocks(struct inode *);
++extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
++ struct address_space *mapping, loff_t from);
++
++/* ioctl.c */
++extern int ext4_ioctl (struct inode *, struct file *, unsigned int,
++ unsigned long);
++extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
++
++/* namei.c */
++extern int ext4_orphan_add(handle_t *, struct inode *);
++extern int ext4_orphan_del(handle_t *, struct inode *);
++extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
++ __u32 start_minor_hash, __u32 *next_hash);
++
++/* resize.c */
++extern int ext4_group_add(struct super_block *sb,
++ struct ext4_new_group_data *input);
++extern int ext4_group_extend(struct super_block *sb,
++ struct ext4_super_block *es,
++ ext4_fsblk_t n_blocks_count);
++
++/* super.c */
++extern void ext4_error (struct super_block *, const char *, const char *, ...)
++ __attribute__ ((format (printf, 3, 4)));
++extern void __ext4_std_error (struct super_block *, const char *, int);
++extern void ext4_abort (struct super_block *, const char *, const char *, ...)
++ __attribute__ ((format (printf, 3, 4)));
++extern void ext4_warning (struct super_block *, const char *, const char *, ...)
++ __attribute__ ((format (printf, 3, 4)));
++extern void ext4_update_dynamic_rev (struct super_block *sb);
++extern ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
++ struct ext4_group_desc *bg);
++extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
++ struct ext4_group_desc *bg);
++extern ext4_fsblk_t ext4_inode_table(struct super_block *sb,
++ struct ext4_group_desc *bg);
++extern void ext4_block_bitmap_set(struct super_block *sb,
++ struct ext4_group_desc *bg, ext4_fsblk_t blk);
++extern void ext4_inode_bitmap_set(struct super_block *sb,
++ struct ext4_group_desc *bg, ext4_fsblk_t blk);
++extern void ext4_inode_table_set(struct super_block *sb,
++ struct ext4_group_desc *bg, ext4_fsblk_t blk);
++
++static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
++{
++ return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
++ le32_to_cpu(es->s_blocks_count);
++}
++
++static inline ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
++{
++ return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
++ le32_to_cpu(es->s_r_blocks_count);
++}
++
++static inline ext4_fsblk_t ext4_free_blocks_count(struct ext4_super_block *es)
++{
++ return ((ext4_fsblk_t)le32_to_cpu(es->s_free_blocks_count_hi) << 32) |
++ le32_to_cpu(es->s_free_blocks_count);
++}
++
++static inline void ext4_blocks_count_set(struct ext4_super_block *es,
++ ext4_fsblk_t blk)
++{
++ es->s_blocks_count = cpu_to_le32((u32)blk);
++ es->s_blocks_count_hi = cpu_to_le32(blk >> 32);
++}
++
++static inline void ext4_free_blocks_count_set(struct ext4_super_block *es,
++ ext4_fsblk_t blk)
++{
++ es->s_free_blocks_count = cpu_to_le32((u32)blk);
++ es->s_free_blocks_count_hi = cpu_to_le32(blk >> 32);
++}
++
++static inline void ext4_r_blocks_count_set(struct ext4_super_block *es,
++ ext4_fsblk_t blk)
++{
++ es->s_r_blocks_count = cpu_to_le32((u32)blk);
++ es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32);
++}
++
++
++
++#define ext4_std_error(sb, errno) \
++do { \
++ if ((errno)) \
++ __ext4_std_error((sb), __FUNCTION__, (errno)); \
++} while (0)
++
++/*
++ * Inodes and files operations
++ */
++
++/* dir.c */
++extern const struct file_operations ext4_dir_operations;
++
++/* file.c */
++extern struct inode_operations ext4_file_inode_operations;
++extern const struct file_operations ext4_file_operations;
++
++/* namei.c */
++extern struct inode_operations ext4_dir_inode_operations;
++extern struct inode_operations ext4_special_inode_operations;
++
++/* symlink.c */
++extern struct inode_operations ext4_symlink_inode_operations;
++extern struct inode_operations ext4_fast_symlink_inode_operations;
++
++/* extents.c */
++extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
++extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
++extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t iblock,
++ unsigned long max_blocks, struct buffer_head *bh_result,
++ int create, int extend_disksize);
++extern void ext4_ext_truncate(struct inode *, struct page *);
++extern void ext4_ext_init(struct super_block *);
++extern void ext4_ext_release(struct super_block *);
++static inline int
++ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
++ unsigned long max_blocks, struct buffer_head *bh,
++ int create, int extend_disksize)
++{
++ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
++ return ext4_ext_get_blocks(handle, inode, block, max_blocks,
++ bh, create, extend_disksize);
++ return ext4_get_blocks_handle(handle, inode, block, max_blocks, bh,
++ create, extend_disksize);
++}
++
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_EXT4_FS_H */
+diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h
+new file mode 100644
+index 0000000..a41cc24
+--- /dev/null
++++ b/include/linux/ext4_fs_extents.h
+@@ -0,0 +1,198 @@
++/*
++ * Copyright (c) 2003-2006, Cluster File Systems, Inc, info at clusterfs.com
++ * Written by Alex Tomas <alex at clusterfs.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.
++ *
++ * 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 Licens
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
++ */
++
++#ifndef _LINUX_EXT4_EXTENTS
++#define _LINUX_EXT4_EXTENTS
++
++#include <linux/ext4_fs.h>
++
++/*
++ * With AGRESSIVE_TEST defined, the capacity of index/leaf blocks
++ * becomes very small, so index split, in-depth growing and
++ * other hard changes happen much more often.
++ * This is for debug purposes only.
++ */
++#define AGRESSIVE_TEST_
++
++/*
++ * With EXTENTS_STATS defined, the number of blocks and extents
++ * are collected in the truncate path. They'll be shown at
++ * umount time.
++ */
++#define EXTENTS_STATS__
++
++/*
++ * If CHECK_BINSEARCH is defined, then the results of the binary search
++ * will also be checked by linear search.
++ */
++#define CHECK_BINSEARCH__
++
++/*
++ * If EXT_DEBUG is defined you can use the 'extdebug' mount option
++ * to get lots of info about what's going on.
++ */
++#define EXT_DEBUG__
++#ifdef EXT_DEBUG
++#define ext_debug(a...) printk(a)
++#else
++#define ext_debug(a...)
++#endif
++
++/*
++ * If EXT_STATS is defined then stats numbers are collected.
++ * These number will be displayed at umount time.
++ */
++#define EXT_STATS_
++
++
++/*
++ * ext4_inode has i_block array (60 bytes total).
++ * The first 12 bytes store ext4_extent_header;
++ * the remainder stores an array of ext4_extent.
++ */
++
++/*
++ * This is the extent on-disk structure.
++ * It's used at the bottom of the tree.
++ */
++struct ext4_extent {
++ __le32 ee_block; /* first logical block extent covers */
++ __le16 ee_len; /* number of blocks covered by extent */
++ __le16 ee_start_hi; /* high 16 bits of physical block */
++ __le32 ee_start; /* low 32 bits of physical block */
++};
++
++/*
++ * This is index on-disk structure.
++ * It's used at all the levels except the bottom.
++ */
++struct ext4_extent_idx {
++ __le32 ei_block; /* index covers logical blocks from 'block' */
++ __le32 ei_leaf; /* pointer to the physical block of the next *
++ * level. leaf or next index could be there */
++ __le16 ei_leaf_hi; /* high 16 bits of physical block */
++ __u16 ei_unused;
++};
++
++/*
++ * Each block (leaves and indexes), even inode-stored has header.
++ */
++struct ext4_extent_header {
++ __le16 eh_magic; /* probably will support different formats */
++ __le16 eh_entries; /* number of valid entries */
++ __le16 eh_max; /* capacity of store in entries */
++ __le16 eh_depth; /* has tree real underlying blocks? */
++ __le32 eh_generation; /* generation of the tree */
++};
++
++#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a)
++
++/*
++ * Array of ext4_ext_path contains path to some extent.
++ * Creation/lookup routines use it for traversal/splitting/etc.
++ * Truncate uses it to simulate recursive walking.
++ */
++struct ext4_ext_path {
++ ext4_fsblk_t p_block;
++ __u16 p_depth;
++ struct ext4_extent *p_ext;
++ struct ext4_extent_idx *p_idx;
++ struct ext4_extent_header *p_hdr;
++ struct buffer_head *p_bh;
++};
++
++/*
++ * structure for external API
++ */
++
++#define EXT4_EXT_CACHE_NO 0
++#define EXT4_EXT_CACHE_GAP 1
++#define EXT4_EXT_CACHE_EXTENT 2
++
++/*
++ * to be called by ext4_ext_walk_space()
++ * negative retcode - error
++ * positive retcode - signal for ext4_ext_walk_space(), see below
++ * callback must return valid extent (passed or newly created)
++ */
++typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
++ struct ext4_ext_cache *,
++ void *);
++
++#define EXT_CONTINUE 0
++#define EXT_BREAK 1
++#define EXT_REPEAT 2
++
++
++#define EXT_MAX_BLOCK 0xffffffff
++
++#define EXT_MAX_LEN ((1UL << 15) - 1)
++
++
++#define EXT_FIRST_EXTENT(__hdr__) \
++ ((struct ext4_extent *) (((char *) (__hdr__)) + \
++ sizeof(struct ext4_extent_header)))
++#define EXT_FIRST_INDEX(__hdr__) \
++ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \
++ sizeof(struct ext4_extent_header)))
++#define EXT_HAS_FREE_INDEX(__path__) \
++ (le16_to_cpu((__path__)->p_hdr->eh_entries) \
++ < le16_to_cpu((__path__)->p_hdr->eh_max))
++#define EXT_LAST_EXTENT(__hdr__) \
++ (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
++#define EXT_LAST_INDEX(__hdr__) \
++ (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
++#define EXT_MAX_EXTENT(__hdr__) \
++ (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
++#define EXT_MAX_INDEX(__hdr__) \
++ (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
++
++static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
++{
++ return (struct ext4_extent_header *) EXT4_I(inode)->i_data;
++}
++
++static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh)
++{
++ return (struct ext4_extent_header *) bh->b_data;
++}
++
++static inline unsigned short ext_depth(struct inode *inode)
++{
++ return le16_to_cpu(ext_inode_hdr(inode)->eh_depth);
++}
++
++static inline void ext4_ext_tree_changed(struct inode *inode)
++{
++ EXT4_I(inode)->i_ext_generation++;
++}
++
++static inline void
++ext4_ext_invalidate_cache(struct inode *inode)
++{
++ EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
++}
++
++extern int ext4_extent_tree_init(handle_t *, struct inode *);
++extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
++extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
++extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
++extern struct ext4_ext_path * ext4_ext_find_extent(struct inode *, int, struct ext4_ext_path *);
++
++#endif /* _LINUX_EXT4_EXTENTS */
++
+diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h
+new file mode 100644
+index 0000000..bb42379
+--- /dev/null
++++ b/include/linux/ext4_fs_i.h
+@@ -0,0 +1,158 @@
++/*
++ * linux/include/linux/ext4_fs_i.h
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/include/linux/minix_fs_i.h
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ */
++
++#ifndef _LINUX_EXT4_FS_I
++#define _LINUX_EXT4_FS_I
++
++#include <linux/rwsem.h>
++#include <linux/rbtree.h>
++#include <linux/seqlock.h>
++#include <linux/mutex.h>
++
++/* data type for block offset of block group */
++typedef int ext4_grpblk_t;
++
++/* data type for filesystem-wide blocks number */
++typedef unsigned long long ext4_fsblk_t;
++
++struct ext4_reserve_window {
++ ext4_fsblk_t _rsv_start; /* First byte reserved */
++ ext4_fsblk_t _rsv_end; /* Last byte reserved or 0 */
++};
++
++struct ext4_reserve_window_node {
++ struct rb_node rsv_node;
++ __u32 rsv_goal_size;
++ __u32 rsv_alloc_hit;
++ struct ext4_reserve_window rsv_window;
++};
++
++struct ext4_block_alloc_info {
++ /* information about reservation window */
++ struct ext4_reserve_window_node rsv_window_node;
++ /*
++ * was i_next_alloc_block in ext4_inode_info
++ * is the logical (file-relative) number of the
++ * most-recently-allocated block in this file.
++ * We use this for detecting linearly ascending allocation requests.
++ */
++ __u32 last_alloc_logical_block;
++ /*
++ * Was i_next_alloc_goal in ext4_inode_info
++ * is the *physical* companion to i_next_alloc_block.
++ * it the the physical block number of the block which was most-recentl
++ * allocated to this file. This give us the goal (target) for the next
++ * allocation when we detect linearly ascending requests.
++ */
++ ext4_fsblk_t last_alloc_physical_block;
++};
++
++#define rsv_start rsv_window._rsv_start
++#define rsv_end rsv_window._rsv_end
++
++/*
++ * storage for cached extent
++ */
++struct ext4_ext_cache {
++ ext4_fsblk_t ec_start;
++ __u32 ec_block;
++ __u32 ec_len; /* must be 32bit to return holes */
++ __u32 ec_type;
++};
++
++/*
++ * third extended file system inode data in memory
++ */
++struct ext4_inode_info {
++ __le32 i_data[15]; /* unconverted */
++ __u32 i_flags;
++#ifdef EXT4_FRAGMENTS
++ __u32 i_faddr;
++ __u8 i_frag_no;
++ __u8 i_frag_size;
++#endif
++ ext4_fsblk_t i_file_acl;
++ __u32 i_dir_acl;
++ __u32 i_dtime;
++
++ /*
++ * i_block_group is the number of the block group which contains
++ * this file's inode. Constant across the lifetime of the inode,
++ * it is ued for making block allocation decisions - we try to
++ * place a file's data blocks near its inode block, and new inodes
++ * near to their parent directory's inode.
++ */
++ __u32 i_block_group;
++ __u32 i_state; /* Dynamic state flags for ext4 */
++
++ /* block reservation info */
++ struct ext4_block_alloc_info *i_block_alloc_info;
++
++ __u32 i_dir_start_lookup;
++#ifdef CONFIG_EXT4DEV_FS_XATTR
++ /*
++ * Extended attributes can be read independently of the main file
++ * data. Taking i_mutex even when reading would cause contention
++ * between readers of EAs and writers of regular file data, so
++ * instead we synchronize on xattr_sem when reading or changing
++ * EAs.
++ */
++ struct rw_semaphore xattr_sem;
++#endif
++#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
++ struct posix_acl *i_acl;
++ struct posix_acl *i_default_acl;
++#endif
++
++ struct list_head i_orphan; /* unlinked but open inodes */
++
++ /*
++ * i_disksize keeps track of what the inode size is ON DISK, not
++ * in memory. During truncate, i_size is set to the new size by
++ * the VFS prior to calling ext4_truncate(), but the filesystem won't
++ * set i_disksize to 0 until the truncate is actually under way.
++ *
++ * The intent is that i_disksize always represents the blocks which
++ * are used by this file. This allows recovery to restart truncate
++ * on orphans if we crash during truncate. We actually write i_disksize
++ * into the on-disk inode when writing inodes out, instead of i_size.
++ *
++ * The only time when i_disksize and i_size may be different is when
++ * a truncate is in progress. The only things which change i_disksize
++ * are ext4_get_block (growth) and ext4_truncate (shrinkth).
++ */
++ loff_t i_disksize;
++
++ /* on-disk additional length */
++ __u16 i_extra_isize;
++
++ /*
++ * truncate_mutex is for serialising ext4_truncate() against
++ * ext4_getblock(). In the 2.4 ext2 design, great chunks of inode's
++ * data tree are chopped off during truncate. We can't do that in
++ * ext4 because whenever we perform intermediate commits during
++ * truncate, the inode and all the metadata blocks *must* be in a
++ * consistent state which allows truncation of the orphans to restart
++ * during recovery. Hence we must fix the get_block-vs-truncate race
++ * by other means, so we have truncate_mutex.
++ */
++ struct mutex truncate_mutex;
++ struct inode vfs_inode;
++
++ unsigned long i_ext_generation;
++ struct ext4_ext_cache i_cached_extent;
++};
++
++#endif /* _LINUX_EXT4_FS_I */
+diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h
+new file mode 100644
+index 0000000..691a713
+--- /dev/null
++++ b/include/linux/ext4_fs_sb.h
+@@ -0,0 +1,94 @@
++/*
++ * linux/include/linux/ext4_fs_sb.h
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/include/linux/minix_fs_sb.h
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ */
++
++#ifndef _LINUX_EXT4_FS_SB
++#define _LINUX_EXT4_FS_SB
++
++#ifdef __KERNEL__
++#include <linux/timer.h>
++#include <linux/wait.h>
++#include <linux/blockgroup_lock.h>
++#include <linux/percpu_counter.h>
++#endif
++#include <linux/rbtree.h>
++
++/*
++ * third extended-fs super-block data in memory
++ */
++struct ext4_sb_info {
++ unsigned long s_frag_size; /* Size of a fragment in bytes */
++ unsigned long s_desc_size; /* Size of a group descriptor in bytes */
++ unsigned long s_frags_per_block;/* Number of fragments per block */
++ unsigned long s_inodes_per_block;/* Number of inodes per block */
++ unsigned long s_frags_per_group;/* Number of fragments in a group */
++ unsigned long s_blocks_per_group;/* Number of blocks in a group */
++ unsigned long s_inodes_per_group;/* Number of inodes in a group */
++ unsigned long s_itb_per_group; /* Number of inode table blocks per group */
++ unsigned long s_gdb_count; /* Number of group descriptor blocks */
++ unsigned long s_desc_per_block; /* Number of group descriptors per block */
++ unsigned long s_groups_count; /* Number of groups in the fs */
++ struct buffer_head * s_sbh; /* Buffer containing the super block */
++ struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
++ struct buffer_head ** s_group_desc;
++ unsigned long s_mount_opt;
++ uid_t s_resuid;
++ gid_t s_resgid;
++ unsigned short s_mount_state;
++ unsigned short s_pad;
++ int s_addr_per_block_bits;
++ int s_desc_per_block_bits;
++ int s_inode_size;
++ int s_first_ino;
++ spinlock_t s_next_gen_lock;
++ u32 s_next_generation;
++ u32 s_hash_seed[4];
++ int s_def_hash_version;
++ struct percpu_counter s_freeblocks_counter;
++ struct percpu_counter s_freeinodes_counter;
++ struct percpu_counter s_dirs_counter;
++ struct blockgroup_lock s_blockgroup_lock;
++
++ /* root of the per fs reservation window tree */
++ spinlock_t s_rsv_window_lock;
++ struct rb_root s_rsv_window_root;
++ struct ext4_reserve_window_node s_rsv_window_head;
++
++ /* Journaling */
++ struct inode * s_journal_inode;
++ struct journal_s * s_journal;
++ struct list_head s_orphan;
++ unsigned long s_commit_interval;
++ struct block_device *journal_bdev;
++#ifdef CONFIG_JBD_DEBUG
++ struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */
++ wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */
++#endif
++#ifdef CONFIG_QUOTA
++ char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */
++ int s_jquota_fmt; /* Format of quota to use */
++#endif
++
++#ifdef EXTENTS_STATS
++ /* ext4 extents stats */
++ unsigned long s_ext_min;
++ unsigned long s_ext_max;
++ unsigned long s_depth_max;
++ spinlock_t s_ext_stats_lock;
++ unsigned long s_ext_blocks;
++ unsigned long s_ext_extents;
++#endif
++};
++
++#endif /* _LINUX_EXT4_FS_SB */
+diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h
+new file mode 100644
+index 0000000..72dd631
+--- /dev/null
++++ b/include/linux/ext4_jbd2.h
+@@ -0,0 +1,273 @@
++/*
++ * linux/include/linux/ext4_jbd2.h
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>, 1999
++ *
++ * Copyright 1998--1999 Red Hat corp --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Ext4-specific journaling extensions.
++ */
++
++#ifndef _LINUX_EXT4_JBD_H
++#define _LINUX_EXT4_JBD_H
++
++#include <linux/fs.h>
++#include <linux/jbd2.h>
++#include <linux/ext4_fs.h>
++
++#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal)
++
++/* Define the number of blocks we need to account to a transaction to
++ * modify one block of data.
++ *
++ * We may have to touch one inode, one bitmap buffer, up to three
++ * indirection blocks, the group and superblock summaries, and the data
++ * block to complete the transaction.
++ *
++ * For extents-enabled fs we may have to allocate and modify up to
++ * 5 levels of tree + root which are stored in the inode. */
++
++#define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \
++ (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS) \
++ || test_opt(sb, EXTENTS) ? 27U : 8U)
++
++/* Extended attribute operations touch at most two data buffers,
++ * two bitmap buffers, and two group summaries, in addition to the inode
++ * and the superblock, which are already accounted for. */
++
++#define EXT4_XATTR_TRANS_BLOCKS 6U
++
++/* Define the minimum size for a transaction which modifies data. This
++ * needs to take into account the fact that we may end up modifying two
++ * quota files too (one for the group, one for the user quota). The
++ * superblock only gets updated once, of course, so don't bother
++ * counting that again for the quota updates. */
++
++#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \
++ EXT4_XATTR_TRANS_BLOCKS - 2 + \
++ 2*EXT4_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 EXT4_DELETE_TRANS_BLOCKS(sb) (2 * EXT4_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
++ * write(2) and truncate(2) we can write more than this, but we always
++ * start off at the maximum transaction size and grow the transaction
++ * optimistically as we go. */
++
++#define EXT4_MAX_TRANS_DATA 64U
++
++/* We break up a large truncate or write transaction once the handle's
++ * buffer credits gets this low, we need either to extend the
++ * transaction or to start a new one. Reserve enough space here for
++ * inode, bitmap, superblock, group and indirection updates for at least
++ * one block, plus two quota updates. Quota allocations are not
++ * needed. */
++
++#define EXT4_RESERVE_TRANS_BLOCKS 12U
++
++#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8
++
++#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 EXT4_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 EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
++ (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0)
++#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
++ (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0)
++#else
++#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0
++#define EXT4_QUOTA_INIT_BLOCKS(sb) 0
++#define EXT4_QUOTA_DEL_BLOCKS(sb) 0
++#endif
++
++int
++ext4_mark_iloc_dirty(handle_t *handle,
++ struct inode *inode,
++ struct ext4_iloc *iloc);
++
++/*
++ * On success, We end up with an outstanding reference count against
++ * iloc->bh. This _must_ be cleaned up later.
++ */
++
++int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
++ struct ext4_iloc *iloc);
++
++int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
++
++/*
++ * Wrapper functions with which ext4 calls into JBD. The intent here is
++ * to allow these to be turned into appropriate stubs so ext4 can control
++ * ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't
++ * been done yet.
++ */
++
++void ext4_journal_abort_handle(const char *caller, const char *err_fn,
++ struct buffer_head *bh, handle_t *handle, int err);
++
++static inline int
++__ext4_journal_get_undo_access(const char *where, handle_t *handle,
++ struct buffer_head *bh)
++{
++ int err = jbd2_journal_get_undo_access(handle, bh);
++ if (err)
++ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
++ return err;
++}
++
++static inline int
++__ext4_journal_get_write_access(const char *where, handle_t *handle,
++ struct buffer_head *bh)
++{
++ int err = jbd2_journal_get_write_access(handle, bh);
++ if (err)
++ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
++ return err;
++}
++
++static inline void
++ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
++{
++ jbd2_journal_release_buffer(handle, bh);
++}
++
++static inline int
++__ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh)
++{
++ int err = jbd2_journal_forget(handle, bh);
++ if (err)
++ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
++ return err;
++}
++
++static inline int
++__ext4_journal_revoke(const char *where, handle_t *handle,
++ ext4_fsblk_t blocknr, struct buffer_head *bh)
++{
++ int err = jbd2_journal_revoke(handle, blocknr, bh);
++ if (err)
++ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
++ return err;
++}
++
++static inline int
++__ext4_journal_get_create_access(const char *where,
++ handle_t *handle, struct buffer_head *bh)
++{
++ int err = jbd2_journal_get_create_access(handle, bh);
++ if (err)
++ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
++ return err;
++}
++
++static inline int
++__ext4_journal_dirty_metadata(const char *where,
++ handle_t *handle, struct buffer_head *bh)
++{
++ int err = jbd2_journal_dirty_metadata(handle, bh);
++ if (err)
++ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
++ return err;
++}
++
++
++#define ext4_journal_get_undo_access(handle, bh) \
++ __ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh))
++#define ext4_journal_get_write_access(handle, bh) \
++ __ext4_journal_get_write_access(__FUNCTION__, (handle), (bh))
++#define ext4_journal_revoke(handle, blocknr, bh) \
++ __ext4_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
++#define ext4_journal_get_create_access(handle, bh) \
++ __ext4_journal_get_create_access(__FUNCTION__, (handle), (bh))
++#define ext4_journal_dirty_metadata(handle, bh) \
++ __ext4_journal_dirty_metadata(__FUNCTION__, (handle), (bh))
++#define ext4_journal_forget(handle, bh) \
++ __ext4_journal_forget(__FUNCTION__, (handle), (bh))
++
++int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
++
++handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
++int __ext4_journal_stop(const char *where, handle_t *handle);
++
++static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
++{
++ return ext4_journal_start_sb(inode->i_sb, nblocks);
++}
++
++#define ext4_journal_stop(handle) \
++ __ext4_journal_stop(__FUNCTION__, (handle))
++
++static inline handle_t *ext4_journal_current_handle(void)
++{
++ return journal_current_handle();
++}
++
++static inline int ext4_journal_extend(handle_t *handle, int nblocks)
++{
++ return jbd2_journal_extend(handle, nblocks);
++}
++
++static inline int ext4_journal_restart(handle_t *handle, int nblocks)
++{
++ return jbd2_journal_restart(handle, nblocks);
++}
++
++static inline int ext4_journal_blocks_per_page(struct inode *inode)
++{
++ return jbd2_journal_blocks_per_page(inode);
++}
++
++static inline int ext4_journal_force_commit(journal_t *journal)
++{
++ return jbd2_journal_force_commit(journal);
++}
++
++/* super.c */
++int ext4_force_commit(struct super_block *sb);
++
++static inline int ext4_should_journal_data(struct inode *inode)
++{
++ if (!S_ISREG(inode->i_mode))
++ return 1;
++ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
++ return 1;
++ if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
++ return 1;
++ return 0;
++}
++
++static inline int ext4_should_order_data(struct inode *inode)
++{
++ if (!S_ISREG(inode->i_mode))
++ return 0;
++ if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
++ return 0;
++ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
++ return 1;
++ return 0;
++}
++
++static inline int ext4_should_writeback_data(struct inode *inode)
++{
++ if (!S_ISREG(inode->i_mode))
++ return 0;
++ if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
++ return 0;
++ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
++ return 1;
++ return 0;
++}
++
++#endif /* _LINUX_EXT4_JBD_H */
+diff --git a/include/linux/fb.h b/include/linux/fb.h
+index 2f335e9..3e69241 100644
+--- a/include/linux/fb.h
++++ b/include/linux/fb.h
+@@ -2,6 +2,7 @@
+ #define _LINUX_FB_H
+
+ #include <asm/types.h>
++#include <linux/i2c.h>
+
+ /* Definitions of frame buffers */
+
+@@ -775,6 +776,7 @@ struct fb_info {
+ struct fb_ops *fbops;
+ struct device *device;
+ struct class_device *class_device; /* sysfs per device attrs */
++ int class_flag; /* private sysfs flags */
+ #ifdef CONFIG_FB_TILEBLITTING
+ struct fb_tile_ops *tileops; /* Tile Blitting */
+ #endif
+@@ -940,6 +942,7 @@ extern void fb_edid_to_monspecs(unsigned
+ struct fb_monspecs *specs);
+ extern void fb_destroy_modedb(struct fb_videomode *modedb);
+ extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb);
++extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter);
+
+ /* drivers/video/modedb.c */
+ #define VESA_MODEDB_SIZE 34
+diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
+new file mode 100644
+index 0000000..4418c8d
+--- /dev/null
++++ b/include/linux/fib_rules.h
+@@ -0,0 +1,65 @@
++#ifndef __LINUX_FIB_RULES_H
++#define __LINUX_FIB_RULES_H
++
++#include <linux/types.h>
++#include <linux/rtnetlink.h>
++
++/* rule is permanent, and cannot be deleted */
++#define FIB_RULE_PERMANENT 1
++
++struct fib_rule_hdr
++{
++ __u8 family;
++ __u8 dst_len;
++ __u8 src_len;
++ __u8 tos;
++
++ __u8 table;
++ __u8 res1; /* reserved */
++ __u8 res2; /* reserved */
++ __u8 action;
++
++ __u32 flags;
++};
++
++enum
++{
++ FRA_UNSPEC,
++ FRA_DST, /* destination address */
++ FRA_SRC, /* source address */
++ FRA_IFNAME, /* interface name */
++ FRA_UNUSED1,
++ FRA_UNUSED2,
++ FRA_PRIORITY, /* priority/preference */
++ FRA_UNUSED3,
++ FRA_UNUSED4,
++ FRA_UNUSED5,
++ FRA_FWMARK, /* netfilter mark */
++ FRA_FLOW, /* flow/class id */
++ FRA_UNUSED6,
++ FRA_UNUSED7,
++ FRA_UNUSED8,
++ FRA_TABLE, /* Extended table id */
++ FRA_FWMASK, /* mask for netfilter mark */
++ __FRA_MAX
++};
++
++#define FRA_MAX (__FRA_MAX - 1)
++
++enum
++{
++ FR_ACT_UNSPEC,
++ FR_ACT_TO_TBL, /* Pass to fixed table */
++ FR_ACT_RES1,
++ FR_ACT_RES2,
++ FR_ACT_RES3,
++ FR_ACT_RES4,
++ FR_ACT_BLACKHOLE, /* Drop without notification */
++ FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
++ FR_ACT_PROHIBIT, /* Drop with EACCES */
++ __FR_ACT_MAX,
++};
++
++#define FR_ACT_MAX (__FR_ACT_MAX - 1)
++
++#endif
+diff --git a/include/linux/file.h b/include/linux/file.h
+index 9f7c251..74183e6 100644
+--- a/include/linux/file.h
++++ b/include/linux/file.h
+@@ -112,5 +112,6 @@ struct task_struct;
+
+ struct files_struct *get_files_struct(struct task_struct *);
+ void FASTCALL(put_files_struct(struct files_struct *fs));
++void reset_files_struct(struct task_struct *, struct files_struct *);
+
+ #endif /* __LINUX_FILE_H */
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index c6cb8f0..91b2e3b 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -25,10 +25,10 @@
+
+ struct sock_filter /* Filter block */
+ {
+- __u16 code; /* Actual filter code */
+- __u8 jt; /* Jump true */
+- __u8 jf; /* Jump false */
+- __u32 k; /* Generic multiuse field */
++ __u16 code; /* Actual filter code */
++ __u8 jt; /* Jump true */
++ __u8 jf; /* Jump false */
++ __u32 k; /* Generic multiuse field */
+ };
+
+ struct sock_fprog /* Required for SO_ATTACH_FILTER. */
+@@ -41,8 +41,9 @@ struct sock_fprog /* Required for SO_ATT
+ struct sk_filter
+ {
+ atomic_t refcnt;
+- unsigned int len; /* Number of filter blocks */
+- struct sock_filter insns[0];
++ unsigned int len; /* Number of filter blocks */
++ struct rcu_head rcu;
++ struct sock_filter insns[0];
+ };
+
+ static inline unsigned int sk_filter_len(struct sk_filter *fp)
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 555bc19..2fe6e3f 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -79,8 +79,8 @@ extern int dir_notify_enable;
+ #define WRITE 1
+ #define READA 2 /* read-ahead - don't block if no resources */
+ #define SWRITE 3 /* for ll_rw_block() - wait for buffer lock */
+-#define SPECIAL 4 /* For non-blockdevice requests in request queue */
+ #define READ_SYNC (READ | (1 << BIO_RW_SYNC))
++#define READ_META (READ | (1 << BIO_RW_META))
+ #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC))
+ #define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER))
+
+@@ -92,9 +92,10 @@ extern int dir_notify_enable;
+ #define FS_REQUIRES_DEV 1
+ #define FS_BINARY_MOUNTDATA 2
+ #define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */
+-#define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
+- * as nfs_rename() will be cleaned up
+- */
++#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move()
++ * during rename() internally.
++ */
++
+ /*
+ * These are the fs-independent mount-flags: up to 32 flags are supported
+ */
+@@ -216,6 +217,47 @@ extern int dir_notify_enable;
+ #define FIBMAP _IO(0x00,1) /* bmap access */
+ #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
+
++#define FS_IOC_GETFLAGS _IOR('f', 1, long)
++#define FS_IOC_SETFLAGS _IOW('f', 2, long)
++#define FS_IOC_GETVERSION _IOR('v', 1, long)
++#define FS_IOC_SETVERSION _IOW('v', 2, long)
++#define FS_IOC32_GETFLAGS _IOR('f', 1, int)
++#define FS_IOC32_SETFLAGS _IOW('f', 2, int)
++#define FS_IOC32_GETVERSION _IOR('v', 1, int)
++#define FS_IOC32_SETVERSION _IOW('v', 2, int)
++
++/*
++ * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
++ */
++#define FS_SECRM_FL 0x00000001 /* Secure deletion */
++#define FS_UNRM_FL 0x00000002 /* Undelete */
++#define FS_COMPR_FL 0x00000004 /* Compress file */
++#define FS_SYNC_FL 0x00000008 /* Synchronous updates */
++#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */
++#define FS_APPEND_FL 0x00000020 /* writes to file may only append */
++#define FS_NODUMP_FL 0x00000040 /* do not dump file */
++#define FS_NOATIME_FL 0x00000080 /* do not update atime */
++/* Reserved for compression usage... */
++#define FS_DIRTY_FL 0x00000100
++#define FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
++#define FS_NOCOMP_FL 0x00000400 /* Don't compress */
++#define FS_ECOMPR_FL 0x00000800 /* Compression error */
++/* End compression flags --- maybe not all used */
++#define FS_BTREE_FL 0x00001000 /* btree format dir */
++#define FS_INDEX_FL 0x00001000 /* hash-indexed directory */
++#define FS_IMAGIC_FL 0x00002000 /* AFS directory */
++#define FS_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */
++#define FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */
++#define FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
++#define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
++#define FS_EXTENT_FL 0x00080000 /* Extents */
++#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */
++#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
++
++#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
++#define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
++
++
+ #define SYNC_FILE_RANGE_WAIT_BEFORE 1
+ #define SYNC_FILE_RANGE_WRITE 2
+ #define SYNC_FILE_RANGE_WAIT_AFTER 4
+@@ -511,7 +553,6 @@ struct inode {
+ struct timespec i_mtime;
+ struct timespec i_ctime;
+ unsigned int i_blkbits;
+- unsigned long i_blksize;
+ unsigned long i_version;
+ blkcnt_t i_blocks;
+ unsigned short i_bytes;
+@@ -527,11 +568,12 @@ struct inode {
+ #ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+ #endif
+- /* These three should probably be a union */
+ struct list_head i_devices;
+- struct pipe_inode_info *i_pipe;
+- struct block_device *i_bdev;
+- struct cdev *i_cdev;
++ union {
++ struct pipe_inode_info *i_pipe;
++ struct block_device *i_bdev;
++ struct cdev *i_cdev;
++ };
+ int i_cindex;
+
+ __u32 i_generation;
+@@ -552,10 +594,10 @@ struct inode {
+ unsigned int i_flags;
+
+ atomic_t i_writecount;
++#ifdef CONFIG_SECURITY
+ void *i_security;
+- union {
+- void *generic_ip;
+- } u;
++#endif
++ void *i_private; /* fs or device private pointer */
+ #ifdef __NEED_I_SIZE_ORDERED
+ seqcount_t i_size_seqcount;
+ #endif
+@@ -581,6 +623,9 @@ enum inode_i_mutex_lock_class
+ I_MUTEX_QUOTA
+ };
+
++extern void inode_double_lock(struct inode *inode1, struct inode *inode2);
++extern void inode_double_unlock(struct inode *inode1, struct inode *inode2);
++
+ /*
+ * NOTE: in a 32bit arch with a preemptable kernel and
+ * an UP compile the i_size_read/write must be atomic
+@@ -614,7 +659,11 @@ static inline loff_t i_size_read(struct
+ #endif
+ }
+
+-
++/*
++ * NOTE: unlike i_size_read(), i_size_write() does need locking around it
++ * (normally i_mutex), otherwise on 32bit/SMP an update of i_size_seqcount
++ * can be lost, resulting in subsequent i_size_read() calls spinning forever.
++ */
+ static inline void i_size_write(struct inode *inode, loff_t i_size)
+ {
+ #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+@@ -644,9 +693,9 @@ extern struct block_device *I_BDEV(struc
+
+ struct fown_struct {
+ rwlock_t lock; /* protects pid, uid, euid fields */
+- int pid; /* pid or -pgrp where SIGIO should be sent */
++ struct pid *pid; /* pid or -pgrp where SIGIO should be sent */
++ enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
+ uid_t uid, euid; /* uid/euid of process setting the owner */
+- void *security;
+ int signum; /* posix.1b rt signal to be delivered on IO */
+ };
+
+@@ -689,8 +738,9 @@ struct file {
+ struct file_ra_state f_ra;
+
+ unsigned long f_version;
++#ifdef CONFIG_SECURITY
+ void *f_security;
+-
++#endif
+ /* needed for tty driver, and maybe others */
+ void *private_data;
+
+@@ -840,8 +890,10 @@ extern void kill_fasync(struct fasync_st
+ /* only for net: no internal synchronization */
+ extern void __kill_fasync(struct fasync_struct *, int, int);
+
++extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
+ extern int f_setown(struct file *filp, unsigned long arg, int force);
+ extern void f_delown(struct file *filp);
++extern pid_t f_getown(struct file *filp);
+ extern int send_sigurg(struct fown_struct *fown);
+
+ /*
+@@ -878,7 +930,9 @@ struct super_block {
+ int s_syncing;
+ int s_need_sync_fs;
+ atomic_t s_active;
++#ifdef CONFIG_SECURITY
+ void *s_security;
++#endif
+ struct xattr_handler **s_xattr;
+
+ struct list_head s_inodes; /* all inodes */
+@@ -1004,7 +1058,7 @@ int generic_osync_inode(struct inode *,
+ * This allows the kernel to read directories into kernel space or
+ * to have different dirent layouts depending on the binary type.
+ */
+-typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
++typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
+
+ struct block_device_operations {
+ int (*open) (struct inode *, struct file *);
+@@ -1055,9 +1109,9 @@ struct file_operations {
+ struct module *owner;
+ loff_t (*llseek) (struct file *, loff_t, int);
+ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+- ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
+ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+- ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
++ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
++ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ int (*readdir) (struct file *, void *, filldir_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+@@ -1071,8 +1125,6 @@ struct file_operations {
+ int (*aio_fsync) (struct kiocb *, int datasync);
+ int (*fasync) (int, struct file *, int);
+ int (*lock) (struct file *, int, struct file_lock *);
+- ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
+- ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
+ ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
+ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
+ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+@@ -1110,6 +1162,11 @@ struct inode_operations {
+
+ struct seq_file;
+
++ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
++ unsigned long nr_segs, unsigned long fast_segs,
++ struct iovec *fast_pointer,
++ struct iovec **ret_pointer);
++
+ extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
+ extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
+ extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
+@@ -1144,9 +1201,10 @@ struct super_operations {
+
+ int (*show_options)(struct seq_file *, struct vfsmount *);
+ int (*show_stats)(struct seq_file *, struct vfsmount *);
+-
++#ifdef CONFIG_QUOTA
+ ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
+ ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
++#endif
+ };
+
+ /* Inode state bits. Protected by inode_lock. */
+@@ -1173,15 +1231,30 @@ static inline void mark_inode_dirty_sync
+ __mark_inode_dirty(inode, I_DIRTY_SYNC);
+ }
+
+-static inline void inode_inc_link_count(struct inode *inode)
++static inline void inc_nlink(struct inode *inode)
+ {
+ inode->i_nlink++;
++}
++
++static inline void inode_inc_link_count(struct inode *inode)
++{
++ inc_nlink(inode);
+ mark_inode_dirty(inode);
+ }
+
+-static inline void inode_dec_link_count(struct inode *inode)
++static inline void drop_nlink(struct inode *inode)
+ {
+ inode->i_nlink--;
++}
++
++static inline void clear_nlink(struct inode *inode)
++{
++ inode->i_nlink = 0;
++}
++
++static inline void inode_dec_link_count(struct inode *inode)
++{
++ drop_nlink(inode);
+ mark_inode_dirty(inode);
+ }
+
+@@ -1439,6 +1512,7 @@ extern void __init vfs_caches_init(unsig
+ extern void putname(const char *name);
+ #endif
+
++#ifdef CONFIG_BLOCK
+ extern int register_blkdev(unsigned int, const char *);
+ extern int unregister_blkdev(unsigned int, const char *);
+ extern struct block_device *bdget(dev_t);
+@@ -1447,13 +1521,20 @@ extern void bd_forget(struct inode *inod
+ extern void bdput(struct block_device *);
+ extern struct block_device *open_by_devnum(dev_t, unsigned);
+ extern struct block_device *open_partition_by_devnum(dev_t, unsigned);
+-extern const struct file_operations def_blk_fops;
+ extern const struct address_space_operations def_blk_aops;
++#else
++static inline void bd_forget(struct inode *inode) {}
++#endif
++extern const struct file_operations def_blk_fops;
+ extern const struct file_operations def_chr_fops;
+ extern const struct file_operations bad_sock_fops;
+ extern const struct file_operations def_fifo_fops;
++#ifdef CONFIG_BLOCK
+ extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
+ extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
++extern int blkdev_driver_ioctl(struct inode *inode, struct file *file,
++ struct gendisk *disk, unsigned cmd,
++ unsigned long arg);
+ extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
+ extern int blkdev_get(struct block_device *, mode_t, unsigned);
+ extern int blkdev_put(struct block_device *);
+@@ -1467,6 +1548,7 @@ extern void bd_release_from_disk(struct
+ #define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder)
+ #define bd_release_from_disk(bdev, disk) bd_release(bdev)
+ #endif
++#endif
+
+ /* fs/char_dev.c */
+ #define CHRDEV_MAJOR_HASH_SIZE 255
+@@ -1480,14 +1562,19 @@ extern int chrdev_open(struct inode *, s
+ extern void chrdev_show(struct seq_file *,off_t);
+
+ /* fs/block_dev.c */
+-#define BLKDEV_MAJOR_HASH_SIZE 255
+ #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */
++
++#ifdef CONFIG_BLOCK
++#define BLKDEV_MAJOR_HASH_SIZE 255
+ extern const char *__bdevname(dev_t, char *buffer);
+ extern const char *bdevname(struct block_device *bdev, char *buffer);
+ extern struct block_device *lookup_bdev(const char *);
+ extern struct block_device *open_bdev_excl(const char *, int, void *);
+ extern void close_bdev_excl(struct block_device *);
+ extern void blkdev_show(struct seq_file *,off_t);
++#else
++#define BLKDEV_MAJOR_HASH_SIZE 0
++#endif
+
+ extern void init_special_inode(struct inode *, umode_t, dev_t);
+
+@@ -1501,6 +1588,7 @@ extern const struct file_operations rdwr
+
+ extern int fs_may_remount_ro(struct super_block *);
+
++#ifdef CONFIG_BLOCK
+ /*
+ * return READ, READA, or WRITE
+ */
+@@ -1512,9 +1600,10 @@ extern int fs_may_remount_ro(struct supe
+ #define bio_data_dir(bio) ((bio)->bi_rw & 1)
+
+ extern int check_disk_change(struct block_device *);
+-extern int invalidate_inodes(struct super_block *);
+ extern int __invalidate_device(struct block_device *);
+ extern int invalidate_partition(struct gendisk *, int);
++#endif
++extern int invalidate_inodes(struct super_block *);
+ unsigned long invalidate_mapping_pages(struct address_space *mapping,
+ pgoff_t start, pgoff_t end);
+ unsigned long invalidate_inode_pages(struct address_space *mapping);
+@@ -1542,11 +1631,14 @@ extern int __filemap_fdatawrite_range(st
+ extern long do_fsync(struct file *file, int datasync);
+ extern void sync_supers(void);
+ extern void sync_filesystems(int wait);
++extern void __fsync_super(struct super_block *sb);
+ extern void emergency_sync(void);
+ extern void emergency_remount(void);
+ extern int do_remount_sb(struct super_block *sb, int flags,
+ void *data, int force);
++#ifdef CONFIG_BLOCK
+ extern sector_t bmap(struct inode *, sector_t);
++#endif
+ extern int notify_change(struct dentry *, struct iattr *);
+ extern int permission(struct inode *, int, struct nameidata *);
+ extern int generic_permission(struct inode *, int,
+@@ -1564,6 +1656,9 @@ static inline void allow_write_access(st
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
+ }
+ extern int do_pipe(int *);
++extern struct file *create_read_pipe(struct file *f);
++extern struct file *create_write_pipe(void);
++extern void free_write_pipe(struct file *);
+
+ extern int open_namei(int dfd, const char *, int, int, struct nameidata *);
+ extern int may_open(struct nameidata *, int, int);
+@@ -1617,6 +1712,8 @@ extern void __iget(struct inode * inode)
+ extern void clear_inode(struct inode *);
+ extern void destroy_inode(struct inode *);
+ extern struct inode *new_inode(struct super_block *);
++extern int __remove_suid(struct dentry *, int);
++extern int should_remove_suid(struct dentry *);
+ extern int remove_suid(struct dentry *);
+ extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
+
+@@ -1629,9 +1726,11 @@ static inline void insert_inode_hash(str
+ extern struct file * get_empty_filp(void);
+ extern void file_move(struct file *f, struct list_head *list);
+ extern void file_kill(struct file *f);
++#ifdef CONFIG_BLOCK
+ struct bio;
+ extern void submit_bio(int, struct bio *);
+ extern int bdev_read_only(struct block_device *);
++#endif
+ extern int set_blocksize(struct block_device *, int);
+ extern int sb_set_blocksize(struct super_block *, int);
+ extern int sb_min_blocksize(struct super_block *, int);
+@@ -1640,22 +1739,17 @@ extern int generic_file_mmap(struct file
+ extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
+ extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
+ extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
+-extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *);
+ int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
+-extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *);
+-extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t);
+-extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *);
+-extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t);
++extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
++extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *,
+- unsigned long, loff_t *);
++ unsigned long, loff_t);
+ extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *,
+ unsigned long *, loff_t, loff_t *, size_t, size_t);
+ extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t, loff_t *, size_t, ssize_t);
+ extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
+ extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
+-ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos);
+ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
+ extern void do_generic_mapping_read(struct address_space *mapping,
+ struct file_ra_state *, struct file *,
+@@ -1666,6 +1760,8 @@ extern ssize_t generic_file_splice_read(
+ struct pipe_inode_info *, size_t, unsigned int);
+ extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
+ struct file *, loff_t *, size_t, unsigned int);
++extern ssize_t generic_file_splice_write_nolock(struct pipe_inode_info *,
++ struct file *, loff_t *, size_t, unsigned int);
+ extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
+ struct file *out, loff_t *, size_t len, unsigned int flags);
+ extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
+@@ -1673,10 +1769,6 @@ extern long do_splice_direct(struct file
+
+ extern void
+ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
+-extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos);
+-ssize_t generic_file_writev(struct file *filp, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos);
+ extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
+ extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
+ extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
+@@ -1712,6 +1804,7 @@ static inline void do_generic_file_read(
+ actor);
+ }
+
++#ifdef CONFIG_BLOCK
+ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+ struct block_device *bdev, const struct iovec *iov, loff_t offset,
+ unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+@@ -1749,6 +1842,7 @@ static inline ssize_t blockdev_direct_IO
+ return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+ nr_segs, get_block, end_io, DIO_OWN_LOCKING);
+ }
++#endif
+
+ extern const struct file_operations generic_ro_fops;
+
+diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
+index 74ed35a..543cd3c 100644
+--- a/include/linux/fs_enet_pd.h
++++ b/include/linux/fs_enet_pd.h
+@@ -55,6 +55,30 @@ static inline int fs_get_scc_index(enum
+ return -1;
+ }
+
++static inline int fs_fec_index2id(int index)
++{
++ int id = fsid_fec1 + index - 1;
++ if (id >= fsid_fec1 && id <= fsid_fec2)
++ return id;
++ return FS_MAX_INDEX;
++ }
++
++static inline int fs_fcc_index2id(int index)
++{
++ int id = fsid_fcc1 + index - 1;
++ if (id >= fsid_fcc1 && id <= fsid_fcc3)
++ return id;
++ return FS_MAX_INDEX;
++}
++
++static inline int fs_scc_index2id(int index)
++{
++ int id = fsid_scc1 + index - 1;
++ if (id >= fsid_scc1 && id <= fsid_scc4)
++ return id;
++ return FS_MAX_INDEX;
++}
++
+ enum fs_mii_method {
+ fsmii_fixed,
+ fsmii_fec,
+@@ -87,18 +111,21 @@ struct fs_mii_bb_platform_info {
+ };
+
+ struct fs_platform_info {
+-
+- void(*init_ioports)(void);
++
++ void(*init_ioports)(struct fs_platform_info *);
+ /* device specific information */
+ int fs_no; /* controller index */
++ char fs_type[4]; /* controller type */
+
+ u32 cp_page; /* CPM page */
+ u32 cp_block; /* CPM sblock */
+-
++
+ u32 clk_trx; /* some stuff for pins & mux configuration*/
++ u32 clk_rx;
++ u32 clk_tx;
+ u32 clk_route;
+ u32 clk_mask;
+-
++
+ u32 mem_offset;
+ u32 dpram_offset;
+ u32 fcc_regs_c;
+@@ -124,4 +151,16 @@ struct fs_mii_fec_platform_info {
+ u32 irq[32];
+ u32 mii_speed;
+ };
++
++static inline int fs_get_id(struct fs_platform_info *fpi)
++{
++ if(strstr(fpi->fs_type, "SCC"))
++ return fs_scc_index2id(fpi->fs_no);
++ if(strstr(fpi->fs_type, "FCC"))
++ return fs_fcc_index2id(fpi->fs_no);
++ if(strstr(fpi->fs_type, "FEC"))
++ return fs_fec_index2id(fpi->fs_no);
++ return fpi->fs_no;
++}
++
+ #endif
+diff --git a/include/linux/fs_uart_pd.h b/include/linux/fs_uart_pd.h
+index f597512..809bb9f 100644
+--- a/include/linux/fs_uart_pd.h
++++ b/include/linux/fs_uart_pd.h
+@@ -46,15 +46,27 @@ static inline int fs_uart_id_fsid2smc(in
+ }
+
+ struct fs_uart_platform_info {
+- void(*init_ioports)(void);
++ void(*init_ioports)(struct fs_uart_platform_info *);
+ /* device specific information */
+ int fs_no; /* controller index */
++ char fs_type[4]; /* controller type */
+ u32 uart_clk;
+ u8 tx_num_fifo;
+ u8 tx_buf_size;
+ u8 rx_num_fifo;
+ u8 rx_buf_size;
+ u8 brg;
++ u8 clk_rx;
++ u8 clk_tx;
+ };
+
++static inline int fs_uart_get_id(struct fs_uart_platform_info *fpi)
++{
++ if(strstr(fpi->fs_type, "SMC"))
++ return fs_uart_id_smc2fsid(fpi->fs_no);
++ if(strstr(fpi->fs_type, "SCC"))
++ return fs_uart_id_scc2fsid(fpi->fs_no);
++ return fpi->fs_no;
++}
++
+ #endif
+diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
+index 16fbe59..3da29e2 100644
+--- a/include/linux/fsl_devices.h
++++ b/include/linux/fsl_devices.h
+@@ -46,18 +46,17 @@
+
+ struct gianfar_platform_data {
+ /* device specific information */
+- u32 device_flags;
+-
++ u32 device_flags;
+ /* board specific information */
+- u32 board_flags;
+- u32 bus_id;
+- u32 phy_id;
+- u8 mac_addr[6];
++ u32 board_flags;
++ u32 bus_id;
++ u32 phy_id;
++ u8 mac_addr[6];
+ };
+
+ struct gianfar_mdio_data {
+ /* board specific information */
+- int irq[32];
++ int irq[32];
+ };
+
+ /* Flags related to gianfar device features */
+@@ -76,14 +75,13 @@ struct gianfar_mdio_data {
+
+ struct fsl_i2c_platform_data {
+ /* device specific information */
+- u32 device_flags;
++ u32 device_flags;
+ };
+
+ /* Flags related to I2C device features */
+ #define FSL_I2C_DEV_SEPARATE_DFSRR 0x00000001
+ #define FSL_I2C_DEV_CLOCK_5200 0x00000002
+
+-
+ enum fsl_usb2_operating_modes {
+ FSL_USB2_MPH_HOST,
+ FSL_USB2_DR_HOST,
+@@ -101,9 +99,9 @@ enum fsl_usb2_phy_modes {
+
+ struct fsl_usb2_platform_data {
+ /* board specific information */
+- enum fsl_usb2_operating_modes operating_mode;
+- enum fsl_usb2_phy_modes phy_mode;
+- unsigned int port_enables;
++ enum fsl_usb2_operating_modes operating_mode;
++ enum fsl_usb2_phy_modes phy_mode;
++ unsigned int port_enables;
+ };
+
+ /* Flags in fsl_usb2_mph_platform_data */
+@@ -121,5 +119,44 @@ struct fsl_spi_platform_data {
+ u32 sysclk;
+ };
+
+-#endif /* _FSL_DEVICE_H_ */
+-#endif /* __KERNEL__ */
++/* Ethernet interface (phy management and speed)
++*/
++enum enet_interface {
++ ENET_10_MII, /* 10 Base T, MII interface */
++ ENET_10_RMII, /* 10 Base T, RMII interface */
++ ENET_10_RGMII, /* 10 Base T, RGMII interface */
++ ENET_100_MII, /* 100 Base T, MII interface */
++ ENET_100_RMII, /* 100 Base T, RMII interface */
++ ENET_100_RGMII, /* 100 Base T, RGMII interface */
++ ENET_1000_GMII, /* 1000 Base T, GMII interface */
++ ENET_1000_RGMII, /* 1000 Base T, RGMII interface */
++ ENET_1000_TBI, /* 1000 Base T, TBI interface */
++ ENET_1000_RTBI /* 1000 Base T, RTBI interface */
++};
++
++struct ucc_geth_platform_data {
++ /* device specific information */
++ u32 device_flags;
++ u32 phy_reg_addr;
++
++ /* board specific information */
++ u32 board_flags;
++ u8 rx_clock;
++ u8 tx_clock;
++ u32 phy_id;
++ enum enet_interface phy_interface;
++ u32 phy_interrupt;
++ u8 mac_addr[6];
++};
++
++/* Flags related to UCC Gigabit Ethernet device features */
++#define FSL_UGETH_DEV_HAS_GIGABIT 0x00000001
++#define FSL_UGETH_DEV_HAS_COALESCE 0x00000002
++#define FSL_UGETH_DEV_HAS_RMON 0x00000004
++
++/* Flags in ucc_geth_platform_data */
++#define FSL_UGETH_BRD_HAS_PHY_INTR 0x00000001
++ /* if not set use a timer */
++
++#endif /* _FSL_DEVICE_H_ */
++#endif /* __KERNEL__ */
+diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
+index 690c428..9869ef3 100644
+--- a/include/linux/genalloc.h
++++ b/include/linux/genalloc.h
+@@ -31,5 +31,6 @@ struct gen_pool_chunk {
+
+ extern struct gen_pool *gen_pool_create(int, int);
+ extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int);
++extern void gen_pool_destroy(struct gen_pool *);
+ extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
+ extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
+diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h
+new file mode 100644
+index 0000000..80764f4
+--- /dev/null
++++ b/include/linux/generic_acl.h
+@@ -0,0 +1,36 @@
++/*
++ * fs/generic_acl.c
++ *
++ * (C) 2005 Andreas Gruenbacher <agruen at suse.de>
++ *
++ * This file is released under the GPL.
++ */
++
++#ifndef GENERIC_ACL_H
++#define GENERIC_ACL_H
++
++#include <linux/posix_acl.h>
++#include <linux/posix_acl_xattr.h>
++
++/**
++ * struct generic_acl_operations - filesystem operations
++ *
++ * Filesystems must make these operations available to the generic
++ * operations.
++ */
++struct generic_acl_operations {
++ struct posix_acl *(*getacl)(struct inode *, int);
++ void (*setacl)(struct inode *, int, struct posix_acl *);
++};
++
++size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int,
++ char *, size_t);
++int generic_acl_get(struct inode *, struct generic_acl_operations *, int,
++ void *, size_t);
++int generic_acl_set(struct inode *, struct generic_acl_operations *, int,
++ const void *, size_t);
++int generic_acl_init(struct inode *, struct inode *,
++ struct generic_acl_operations *);
++int generic_acl_chmod(struct inode *, struct generic_acl_operations *);
++
++#endif
+diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
+index 84f12a4..9049dc6 100644
+--- a/include/linux/genetlink.h
++++ b/include/linux/genetlink.h
+@@ -16,6 +16,8 @@ struct genlmsghdr {
+
+ #define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
+
++#define GENL_ADMIN_PERM 0x01
++
+ /*
+ * List of reserved static generic netlink identifiers:
+ */
+@@ -43,9 +45,25 @@ enum {
+ CTRL_ATTR_UNSPEC,
+ CTRL_ATTR_FAMILY_ID,
+ CTRL_ATTR_FAMILY_NAME,
++ CTRL_ATTR_VERSION,
++ CTRL_ATTR_HDRSIZE,
++ CTRL_ATTR_MAXATTR,
++ CTRL_ATTR_OPS,
+ __CTRL_ATTR_MAX,
+ };
+
+ #define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
++enum {
++ CTRL_ATTR_OP_UNSPEC,
++ CTRL_ATTR_OP_ID,
++ CTRL_ATTR_OP_FLAGS,
++ CTRL_ATTR_OP_POLICY,
++ CTRL_ATTR_OP_DOIT,
++ CTRL_ATTR_OP_DUMPIT,
++ __CTRL_ATTR_OP_MAX,
++};
++
++#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
++
+ #endif /* __LINUX_GENERIC_NETLINK_H */
+diff --git a/include/linux/genhd.h b/include/linux/genhd.h
+index e4af57e..41f276f 100644
+--- a/include/linux/genhd.h
++++ b/include/linux/genhd.h
+@@ -11,6 +11,8 @@
+
+ #include <linux/types.h>
+
++#ifdef CONFIG_BLOCK
++
+ enum {
+ /* These three have identical behaviour; use the second one if DOS FDISK gets
+ confused about extended/logical partitions starting past cylinder 1023. */
+@@ -420,3 +422,5 @@ static inline struct block_device *bdget
+ #endif
+
+ #endif
++
++#endif
+diff --git a/include/linux/getcpu.h b/include/linux/getcpu.h
+new file mode 100644
+index 0000000..c7372d7
+--- /dev/null
++++ b/include/linux/getcpu.h
+@@ -0,0 +1,18 @@
++#ifndef _LINUX_GETCPU_H
++#define _LINUX_GETCPU_H 1
++
++/* Cache for getcpu() to speed it up. Results might be a short time
++ out of date, but will be faster.
++
++ User programs should not refer to the contents of this structure.
++ I repeat they should not refer to it. If they do they will break
++ in future kernels.
++
++ It is only a private cache for vgetcpu(). It will change in future kernels.
++ The user program must store this information per thread (__thread)
++ If you want 100% accurate information pass NULL instead. */
++struct getcpu_cache {
++ unsigned long blob[128 / sizeof(long)];
++};
++
++#endif
+diff --git a/include/linux/gfp.h b/include/linux/gfp.h
+index cc9e608..bf2b6bc 100644
+--- a/include/linux/gfp.h
++++ b/include/linux/gfp.h
+@@ -9,17 +9,16 @@ struct vm_area_struct;
+
+ /*
+ * GFP bitmasks..
++ *
++ * Zone modifiers (see linux/mmzone.h - low three bits)
++ *
++ * Do not put any conditional on these. If necessary modify the definitions
++ * without the underscores and use the consistently. The definitions here may
++ * be used in bit comparisons.
+ */
+-/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low three bits) */
+ #define __GFP_DMA ((__force gfp_t)0x01u)
+ #define __GFP_HIGHMEM ((__force gfp_t)0x02u)
+-#ifdef CONFIG_DMA_IS_DMA32
+-#define __GFP_DMA32 ((__force gfp_t)0x01) /* ZONE_DMA is ZONE_DMA32 */
+-#elif BITS_PER_LONG < 64
+-#define __GFP_DMA32 ((__force gfp_t)0x00) /* ZONE_NORMAL is ZONE_DMA32 */
+-#else
+-#define __GFP_DMA32 ((__force gfp_t)0x04) /* Has own ZONE_DMA32 */
+-#endif
++#define __GFP_DMA32 ((__force gfp_t)0x04u)
+
+ /*
+ * Action modifiers - doesn't change the zoning
+@@ -46,6 +45,7 @@ struct vm_area_struct;
+ #define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */
+ #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
+ #define __GFP_HARDWALL ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
++#define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */
+
+ #define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */
+ #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
+@@ -54,7 +54,7 @@ struct vm_area_struct;
+ #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
+ __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
+ __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
+- __GFP_NOMEMALLOC|__GFP_HARDWALL)
++ __GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)
+
+ /* This equals 0, but use constants in case they ever change */
+ #define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH)
+@@ -67,6 +67,13 @@ struct vm_area_struct;
+ #define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \
+ __GFP_HIGHMEM)
+
++#ifdef CONFIG_NUMA
++#define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
++#else
++#define GFP_THISNODE 0
++#endif
++
++
+ /* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
+ platforms, used as appropriate on others */
+
+@@ -76,11 +83,19 @@ struct vm_area_struct;
+ #define GFP_DMA32 __GFP_DMA32
+
+
+-static inline int gfp_zone(gfp_t gfp)
++static inline enum zone_type gfp_zone(gfp_t flags)
+ {
+- int zone = GFP_ZONEMASK & (__force int) gfp;
+- BUG_ON(zone >= GFP_ZONETYPES);
+- return zone;
++ if (flags & __GFP_DMA)
++ return ZONE_DMA;
++#ifdef CONFIG_ZONE_DMA32
++ if (flags & __GFP_DMA32)
++ return ZONE_DMA32;
++#endif
++#ifdef CONFIG_HIGHMEM
++ if (flags & __GFP_HIGHMEM)
++ return ZONE_HIGHMEM;
++#endif
++ return ZONE_NORMAL;
+ }
+
+ /*
+diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
+new file mode 100644
+index 0000000..a7ae7c1
+--- /dev/null
++++ b/include/linux/gfs2_ondisk.h
+@@ -0,0 +1,443 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License v.2.
++ */
++
++#ifndef __GFS2_ONDISK_DOT_H__
++#define __GFS2_ONDISK_DOT_H__
++
++#define GFS2_MAGIC 0x01161970
++#define GFS2_BASIC_BLOCK 512
++#define GFS2_BASIC_BLOCK_SHIFT 9
++
++/* Lock numbers of the LM_TYPE_NONDISK type */
++
++#define GFS2_MOUNT_LOCK 0
++#define GFS2_LIVE_LOCK 1
++#define GFS2_TRANS_LOCK 2
++#define GFS2_RENAME_LOCK 3
++
++/* Format numbers for various metadata types */
++
++#define GFS2_FORMAT_NONE 0
++#define GFS2_FORMAT_SB 100
++#define GFS2_FORMAT_RG 200
++#define GFS2_FORMAT_RB 300
++#define GFS2_FORMAT_DI 400
++#define GFS2_FORMAT_IN 500
++#define GFS2_FORMAT_LF 600
++#define GFS2_FORMAT_JD 700
++#define GFS2_FORMAT_LH 800
++#define GFS2_FORMAT_LD 900
++#define GFS2_FORMAT_LB 1000
++#define GFS2_FORMAT_EA 1600
++#define GFS2_FORMAT_ED 1700
++#define GFS2_FORMAT_QC 1400
++/* These are format numbers for entities contained in files */
++#define GFS2_FORMAT_RI 1100
++#define GFS2_FORMAT_DE 1200
++#define GFS2_FORMAT_QU 1500
++/* These are part of the superblock */
++#define GFS2_FORMAT_FS 1801
++#define GFS2_FORMAT_MULTI 1900
++
++/*
++ * An on-disk inode number
++ */
++
++struct gfs2_inum {
++ __be64 no_formal_ino;
++ __be64 no_addr;
++};
++
++static inline int gfs2_inum_equal(const struct gfs2_inum *ino1,
++ const struct gfs2_inum *ino2)
++{
++ return ino1->no_formal_ino == ino2->no_formal_ino &&
++ ino1->no_addr == ino2->no_addr;
++}
++
++/*
++ * Generic metadata head structure
++ * Every inplace buffer logged in the journal must start with this.
++ */
++
++#define GFS2_METATYPE_NONE 0
++#define GFS2_METATYPE_SB 1
++#define GFS2_METATYPE_RG 2
++#define GFS2_METATYPE_RB 3
++#define GFS2_METATYPE_DI 4
++#define GFS2_METATYPE_IN 5
++#define GFS2_METATYPE_LF 6
++#define GFS2_METATYPE_JD 7
++#define GFS2_METATYPE_LH 8
++#define GFS2_METATYPE_LD 9
++#define GFS2_METATYPE_LB 12
++#define GFS2_METATYPE_EA 10
++#define GFS2_METATYPE_ED 11
++#define GFS2_METATYPE_QC 14
++
++struct gfs2_meta_header {
++ __be32 mh_magic;
++ __be32 mh_type;
++ __be64 __pad0; /* Was generation number in gfs1 */
++ __be32 mh_format;
++ __be32 __pad1; /* Was incarnation number in gfs1 */
++};
++
++/*
++ * super-block structure
++ *
++ * It's probably good if SIZEOF_SB <= GFS2_BASIC_BLOCK (512 bytes)
++ *
++ * Order is important, need to be able to read old superblocks to do on-disk
++ * version upgrades.
++ */
++
++/* Address of superblock in GFS2 basic blocks */
++#define GFS2_SB_ADDR 128
++
++/* The lock number for the superblock (must be zero) */
++#define GFS2_SB_LOCK 0
++
++/* Requirement: GFS2_LOCKNAME_LEN % 8 == 0
++ Includes: the fencing zero at the end */
++#define GFS2_LOCKNAME_LEN 64
++
++struct gfs2_sb {
++ struct gfs2_meta_header sb_header;
++
++ __be32 sb_fs_format;
++ __be32 sb_multihost_format;
++ __u32 __pad0; /* Was superblock flags in gfs1 */
++
++ __be32 sb_bsize;
++ __be32 sb_bsize_shift;
++ __u32 __pad1; /* Was journal segment size in gfs1 */
++
++ struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
++ struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
++ struct gfs2_inum sb_root_dir;
++
++ char sb_lockproto[GFS2_LOCKNAME_LEN];
++ char sb_locktable[GFS2_LOCKNAME_LEN];
++ /* In gfs1, quota and license dinodes followed */
++};
++
++/*
++ * resource index structure
++ */
++
++struct gfs2_rindex {
++ __be64 ri_addr; /* grp block disk address */
++ __be32 ri_length; /* length of rgrp header in fs blocks */
++ __u32 __pad;
++
++ __be64 ri_data0; /* first data location */
++ __be32 ri_data; /* num of data blocks in rgrp */
++
++ __be32 ri_bitbytes; /* number of bytes in data bitmaps */
++
++ __u8 ri_reserved[64];
++};
++
++/*
++ * resource group header structure
++ */
++
++/* Number of blocks per byte in rgrp */
++#define GFS2_NBBY 4
++#define GFS2_BIT_SIZE 2
++#define GFS2_BIT_MASK 0x00000003
++
++#define GFS2_BLKST_FREE 0
++#define GFS2_BLKST_USED 1
++#define GFS2_BLKST_UNLINKED 2
++#define GFS2_BLKST_DINODE 3
++
++#define GFS2_RGF_JOURNAL 0x00000001
++#define GFS2_RGF_METAONLY 0x00000002
++#define GFS2_RGF_DATAONLY 0x00000004
++#define GFS2_RGF_NOALLOC 0x00000008
++
++struct gfs2_rgrp {
++ struct gfs2_meta_header rg_header;
++
++ __be32 rg_flags;
++ __be32 rg_free;
++ __be32 rg_dinodes;
++ __be32 __pad;
++ __be64 rg_igeneration;
++
++ __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */
++};
++
++/*
++ * quota structure
++ */
++
++struct gfs2_quota {
++ __be64 qu_limit;
++ __be64 qu_warn;
++ __be64 qu_value;
++ __u8 qu_reserved[64];
++};
++
++/*
++ * dinode structure
++ */
++
++#define GFS2_MAX_META_HEIGHT 10
++#define GFS2_DIR_MAX_DEPTH 17
++
++#define DT2IF(dt) (((dt) << 12) & S_IFMT)
++#define IF2DT(sif) (((sif) & S_IFMT) >> 12)
++
++enum {
++ gfs2fl_Jdata = 0,
++ gfs2fl_ExHash = 1,
++ gfs2fl_Unused = 2,
++ gfs2fl_EaIndirect = 3,
++ gfs2fl_Directio = 4,
++ gfs2fl_Immutable = 5,
++ gfs2fl_AppendOnly = 6,
++ gfs2fl_NoAtime = 7,
++ gfs2fl_Sync = 8,
++ gfs2fl_System = 9,
++ gfs2fl_TruncInProg = 29,
++ gfs2fl_InheritDirectio = 30,
++ gfs2fl_InheritJdata = 31,
++};
++
++/* Dinode flags */
++#define GFS2_DIF_JDATA 0x00000001
++#define GFS2_DIF_EXHASH 0x00000002
++#define GFS2_DIF_UNUSED 0x00000004 /* only in gfs1 */
++#define GFS2_DIF_EA_INDIRECT 0x00000008
++#define GFS2_DIF_DIRECTIO 0x00000010
++#define GFS2_DIF_IMMUTABLE 0x00000020
++#define GFS2_DIF_APPENDONLY 0x00000040
++#define GFS2_DIF_NOATIME 0x00000080
++#define GFS2_DIF_SYNC 0x00000100
++#define GFS2_DIF_SYSTEM 0x00000200 /* New in gfs2 */
++#define GFS2_DIF_TRUNC_IN_PROG 0x20000000 /* New in gfs2 */
++#define GFS2_DIF_INHERIT_DIRECTIO 0x40000000
++#define GFS2_DIF_INHERIT_JDATA 0x80000000
++
++struct gfs2_dinode {
++ struct gfs2_meta_header di_header;
++
++ struct gfs2_inum di_num;
++
++ __be32 di_mode; /* mode of file */
++ __be32 di_uid; /* owner's user id */
++ __be32 di_gid; /* owner's group id */
++ __be32 di_nlink; /* number of links to this file */
++ __be64 di_size; /* number of bytes in file */
++ __be64 di_blocks; /* number of blocks in file */
++ __be64 di_atime; /* time last accessed */
++ __be64 di_mtime; /* time last modified */
++ __be64 di_ctime; /* time last changed */
++ __be32 di_major; /* device major number */
++ __be32 di_minor; /* device minor number */
++
++ /* This section varies from gfs1. Padding added to align with
++ * remainder of dinode
++ */
++ __be64 di_goal_meta; /* rgrp to alloc from next */
++ __be64 di_goal_data; /* data block goal */
++ __be64 di_generation; /* generation number for NFS */
++
++ __be32 di_flags; /* GFS2_DIF_... */
++ __be32 di_payload_format; /* GFS2_FORMAT_... */
++ __u16 __pad1; /* Was ditype in gfs1 */
++ __be16 di_height; /* height of metadata */
++ __u32 __pad2; /* Unused incarnation number from gfs1 */
++
++ /* These only apply to directories */
++ __u16 __pad3; /* Padding */
++ __be16 di_depth; /* Number of bits in the table */
++ __be32 di_entries; /* The number of entries in the directory */
++
++ struct gfs2_inum __pad4; /* Unused even in current gfs1 */
++
++ __be64 di_eattr; /* extended attribute block number */
++
++ __u8 di_reserved[56];
++};
++
++/*
++ * directory structure - many of these per directory file
++ */
++
++#define GFS2_FNAMESIZE 255
++#define GFS2_DIRENT_SIZE(name_len) ((sizeof(struct gfs2_dirent) + (name_len) + 7) & ~7)
++
++struct gfs2_dirent {
++ struct gfs2_inum de_inum;
++ __be32 de_hash;
++ __be16 de_rec_len;
++ __be16 de_name_len;
++ __be16 de_type;
++ __u8 __pad[14];
++};
++
++/*
++ * Header of leaf directory nodes
++ */
++
++struct gfs2_leaf {
++ struct gfs2_meta_header lf_header;
++
++ __be16 lf_depth; /* Depth of leaf */
++ __be16 lf_entries; /* Number of dirents in leaf */
++ __be32 lf_dirent_format; /* Format of the dirents */
++ __be64 lf_next; /* Next leaf, if overflow */
++
++ __u8 lf_reserved[64];
++};
++
++/*
++ * Extended attribute header format
++ */
++
++#define GFS2_EA_MAX_NAME_LEN 255
++#define GFS2_EA_MAX_DATA_LEN 65536
++
++#define GFS2_EATYPE_UNUSED 0
++#define GFS2_EATYPE_USR 1
++#define GFS2_EATYPE_SYS 2
++#define GFS2_EATYPE_SECURITY 3
++
++#define GFS2_EATYPE_LAST 3
++#define GFS2_EATYPE_VALID(x) ((x) <= GFS2_EATYPE_LAST)
++
++#define GFS2_EAFLAG_LAST 0x01 /* last ea in block */
++
++struct gfs2_ea_header {
++ __be32 ea_rec_len;
++ __be32 ea_data_len;
++ __u8 ea_name_len; /* no NULL pointer after the string */
++ __u8 ea_type; /* GFS2_EATYPE_... */
++ __u8 ea_flags; /* GFS2_EAFLAG_... */
++ __u8 ea_num_ptrs;
++ __u32 __pad;
++};
++
++/*
++ * Log header structure
++ */
++
++#define GFS2_LOG_HEAD_UNMOUNT 0x00000001 /* log is clean */
++
++struct gfs2_log_header {
++ struct gfs2_meta_header lh_header;
++
++ __be64 lh_sequence; /* Sequence number of this transaction */
++ __be32 lh_flags; /* GFS2_LOG_HEAD_... */
++ __be32 lh_tail; /* Block number of log tail */
++ __be32 lh_blkno;
++ __be32 lh_hash;
++};
++
++/*
++ * Log type descriptor
++ */
++
++#define GFS2_LOG_DESC_METADATA 300
++/* ld_data1 is the number of metadata blocks in the descriptor.
++ ld_data2 is unused. */
++
++#define GFS2_LOG_DESC_REVOKE 301
++/* ld_data1 is the number of revoke blocks in the descriptor.
++ ld_data2 is unused. */
++
++#define GFS2_LOG_DESC_JDATA 302
++/* ld_data1 is the number of data blocks in the descriptor.
++ ld_data2 is unused. */
++
++struct gfs2_log_descriptor {
++ struct gfs2_meta_header ld_header;
++
++ __be32 ld_type; /* GFS2_LOG_DESC_... */
++ __be32 ld_length; /* Number of buffers in this chunk */
++ __be32 ld_data1; /* descriptor-specific field */
++ __be32 ld_data2; /* descriptor-specific field */
++
++ __u8 ld_reserved[32];
++};
++
++/*
++ * Inum Range
++ * Describe a range of formal inode numbers allocated to
++ * one machine to assign to inodes.
++ */
++
++#define GFS2_INUM_QUANTUM 1048576
++
++struct gfs2_inum_range {
++ __be64 ir_start;
++ __be64 ir_length;
++};
++
++/*
++ * Statfs change
++ * Describes an change to the pool of free and allocated
++ * blocks.
++ */
++
++struct gfs2_statfs_change {
++ __be64 sc_total;
++ __be64 sc_free;
++ __be64 sc_dinodes;
++};
++
++/*
++ * Quota change
++ * Describes an allocation change for a particular
++ * user or group.
++ */
++
++#define GFS2_QCF_USER 0x00000001
++
++struct gfs2_quota_change {
++ __be64 qc_change;
++ __be32 qc_flags; /* GFS2_QCF_... */
++ __be32 qc_id;
++};
++
++#ifdef __KERNEL__
++/* Translation functions */
++
++extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf);
++extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf);
++extern void gfs2_sb_in(struct gfs2_sb *sb, const void *buf);
++extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf);
++extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf);
++extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf);
++extern void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf);
++extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf);
++extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf);
++extern void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf);
++extern void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf);
++extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf);
++extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf);
++extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf);
++extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf);
++extern void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf);
++extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf);
++extern void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf);
++extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf);
++
++/* Printing functions */
++
++extern void gfs2_rindex_print(const struct gfs2_rindex *ri);
++extern void gfs2_dinode_print(const struct gfs2_dinode *di);
++
++#endif /* __KERNEL__ */
++
++#endif /* __GFS2_ONDISK_DOT_H__ */
+diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
+index 50d8b57..612472a 100644
+--- a/include/linux/hardirq.h
++++ b/include/linux/hardirq.h
+@@ -28,11 +28,16 @@
+
+ #ifndef HARDIRQ_BITS
+ #define HARDIRQ_BITS 12
++
++#ifndef MAX_HARDIRQS_PER_CPU
++#define MAX_HARDIRQS_PER_CPU NR_IRQS
++#endif
++
+ /*
+ * The hardirq mask has to be large enough to have space for potentially
+ * all IRQ sources in the system nesting on a single CPU.
+ */
+-#if (1 << HARDIRQ_BITS) < NR_IRQS
++#if (1 << HARDIRQ_BITS) < MAX_HARDIRQS_PER_CPU
+ # error HARDIRQ_BITS is too low!
+ #endif
+ #endif
+diff --git a/include/linux/harrier_defs.h b/include/linux/harrier_defs.h
+index 685b252..efef11d 100644
+--- a/include/linux/harrier_defs.h
++++ b/include/linux/harrier_defs.h
+@@ -1,5 +1,5 @@
+ /*
+- * asm-ppc/harrier_defs.h
++ * include/linux/harrier_defs.h
+ *
+ * Definitions for Motorola MCG Harrier North Bridge & Memory controller
+ *
+diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
+index d5ebbb2..d4b3339 100644
+--- a/include/linux/hdlc.h
++++ b/include/linux/hdlc.h
+@@ -11,95 +11,46 @@
+ #ifndef __HDLC_H
+ #define __HDLC_H
+
+-#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
+-
+-#define CLOCK_DEFAULT 0 /* Default setting */
+-#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
+-#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
+-#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
+-#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
+-
+-
+-#define ENCODING_DEFAULT 0 /* Default setting */
+-#define ENCODING_NRZ 1
+-#define ENCODING_NRZI 2
+-#define ENCODING_FM_MARK 3
+-#define ENCODING_FM_SPACE 4
+-#define ENCODING_MANCHESTER 5
+-
+-
+-#define PARITY_DEFAULT 0 /* Default setting */
+-#define PARITY_NONE 1 /* No parity */
+-#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
+-#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
+-#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
+-#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
+-#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
+-#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
+-
+-#define LMI_DEFAULT 0 /* Default setting */
+-#define LMI_NONE 1 /* No LMI, all PVCs are static */
+-#define LMI_ANSI 2 /* ANSI Annex D */
+-#define LMI_CCITT 3 /* ITU-T Annex A */
+-#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
+
+ #define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
++#if 0
+ #define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */
++#else
++#define HDLC_MAX_MRU 1600 /* as required for FR network */
++#endif
+
+
+ #ifdef __KERNEL__
+
+ #include <linux/skbuff.h>
+ #include <linux/netdevice.h>
+-#include <net/syncppp.h>
+ #include <linux/hdlc/ioctl.h>
+
+
+-typedef struct { /* Used in Cisco and PPP mode */
+- u8 address;
+- u8 control;
+- u16 protocol;
+-}__attribute__ ((packed)) hdlc_header;
+-
+-
+-
+-typedef struct {
+- u32 type; /* code */
+- u32 par1;
+- u32 par2;
+- u16 rel; /* reliability */
+- u32 time;
+-}__attribute__ ((packed)) cisco_packet;
+-#define CISCO_PACKET_LEN 18
+-#define CISCO_BIG_PACKET_LEN 20
+-
+-
+-
+-typedef struct pvc_device_struct {
+- struct net_device *master;
+- struct net_device *main;
+- struct net_device *ether; /* bridged Ethernet interface */
+- struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
+- int dlci;
+- int open_count;
+-
+- struct {
+- unsigned int new: 1;
+- unsigned int active: 1;
+- unsigned int exist: 1;
+- unsigned int deleted: 1;
+- unsigned int fecn: 1;
+- unsigned int becn: 1;
+- unsigned int bandwidth; /* Cisco LMI reporting only */
+- }state;
+-}pvc_device;
+-
+-
+-
+-typedef struct hdlc_device_struct {
+- /* To be initialized by hardware driver */
++/* Used by all network devices here, pointed to by netdev_priv(dev) */
++struct hdlc_device_desc {
++ int (*netif_rx)(struct sk_buff *skb);
+ struct net_device_stats stats;
+-
++};
++
++/* This structure is a private property of HDLC protocols.
++ Hardware drivers have no interest here */
++
++struct hdlc_proto {
++ int (*open)(struct net_device *dev);
++ void (*close)(struct net_device *dev);
++ void (*start)(struct net_device *dev); /* if open & DCD */
++ void (*stop)(struct net_device *dev); /* if open & !DCD */
++ void (*detach)(struct net_device *dev);
++ int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
++ unsigned short (*type_trans)(struct sk_buff *skb,
++ struct net_device *dev);
++ struct module *module;
++ struct hdlc_proto *next; /* next protocol in the list */
++};
++
++
++typedef struct hdlc_device {
+ /* used by HDLC layer to take control over HDLC device from hw driver*/
+ int (*attach)(struct net_device *dev,
+ unsigned short encoding, unsigned short parity);
+@@ -107,82 +58,18 @@ typedef struct hdlc_device_struct {
+ /* hardware driver must handle this instead of dev->hard_start_xmit */
+ int (*xmit)(struct sk_buff *skb, struct net_device *dev);
+
+-
+ /* Things below are for HDLC layer internal use only */
+- struct {
+- int (*open)(struct net_device *dev);
+- void (*close)(struct net_device *dev);
+-
+- /* if open & DCD */
+- void (*start)(struct net_device *dev);
+- /* if open & !DCD */
+- void (*stop)(struct net_device *dev);
+-
+- void (*detach)(struct hdlc_device_struct *hdlc);
+- int (*netif_rx)(struct sk_buff *skb);
+- unsigned short (*type_trans)(struct sk_buff *skb,
+- struct net_device *dev);
+- int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */
+- }proto;
+-
++ const struct hdlc_proto *proto;
+ int carrier;
+ int open;
+ spinlock_t state_lock;
+-
+- union {
+- struct {
+- fr_proto settings;
+- pvc_device *first_pvc;
+- int dce_pvc_count;
+-
+- struct timer_list timer;
+- unsigned long last_poll;
+- int reliable;
+- int dce_changed;
+- int request;
+- int fullrep_sent;
+- u32 last_errors; /* last errors bit list */
+- u8 n391cnt;
+- u8 txseq; /* TX sequence number */
+- u8 rxseq; /* RX sequence number */
+- }fr;
+-
+- struct {
+- cisco_proto settings;
+-
+- struct timer_list timer;
+- unsigned long last_poll;
+- int up;
+- int request_sent;
+- u32 txseq; /* TX sequence number */
+- u32 rxseq; /* RX sequence number */
+- }cisco;
+-
+- struct {
+- raw_hdlc_proto settings;
+- }raw_hdlc;
+-
+- struct {
+- struct ppp_device pppdev;
+- struct ppp_device *syncppp_ptr;
+- int (*old_change_mtu)(struct net_device *dev,
+- int new_mtu);
+- }ppp;
+- }state;
++ void *state;
+ void *priv;
+ }hdlc_device;
+
+
+
+-int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr);
+-int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
+-int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
+-int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
+-int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr);
+-int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr);
+-
+-
+-/* Exported from hdlc.o */
++/* Exported from hdlc module */
+
+ /* Called by hardware driver when a user requests HDLC service */
+ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+@@ -191,17 +78,21 @@ int hdlc_ioctl(struct net_device *dev, s
+ #define register_hdlc_device(dev) register_netdev(dev)
+ void unregister_hdlc_device(struct net_device *dev);
+
++
++void register_hdlc_protocol(struct hdlc_proto *proto);
++void unregister_hdlc_protocol(struct hdlc_proto *proto);
++
+ struct net_device *alloc_hdlcdev(void *priv);
+
+-static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
++
++static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
+ {
+ return netdev_priv(dev);
+ }
+
+-
+-static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
++static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+ {
+- return (pvc_device*)dev->priv;
++ return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
+ }
+
+
+@@ -225,18 +116,14 @@ int hdlc_open(struct net_device *dev);
+ /* Must be called by hardware driver when HDLC device is being closed */
+ void hdlc_close(struct net_device *dev);
+
++int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
++ int (*rx)(struct sk_buff *skb), size_t size);
+ /* May be used by hardware driver to gain control over HDLC device */
+-static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
+-{
+- if (hdlc->proto.detach)
+- hdlc->proto.detach(hdlc);
+- hdlc->proto.detach = NULL;
+-}
+-
++void detach_hdlc_protocol(struct net_device *dev);
+
+ static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
+ {
+- return &dev_to_hdlc(dev)->stats;
++ return &dev_to_desc(dev)->stats;
+ }
+
+
+@@ -248,8 +135,8 @@ static __inline__ __be16 hdlc_type_trans
+ skb->mac.raw = skb->data;
+ skb->dev = dev;
+
+- if (hdlc->proto.type_trans)
+- return hdlc->proto.type_trans(skb, dev);
++ if (hdlc->proto->type_trans)
++ return hdlc->proto->type_trans(skb, dev);
+ else
+ return htons(ETH_P_HDLC);
+ }
+diff --git a/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h
+index 78430ba..5839723 100644
+--- a/include/linux/hdlc/ioctl.h
++++ b/include/linux/hdlc/ioctl.h
+@@ -1,6 +1,39 @@
+ #ifndef __HDLC_IOCTL_H__
+ #define __HDLC_IOCTL_H__
+
++
++#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
++
++#define CLOCK_DEFAULT 0 /* Default setting */
++#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
++#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
++#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
++#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
++
++
++#define ENCODING_DEFAULT 0 /* Default setting */
++#define ENCODING_NRZ 1
++#define ENCODING_NRZI 2
++#define ENCODING_FM_MARK 3
++#define ENCODING_FM_SPACE 4
++#define ENCODING_MANCHESTER 5
++
++
++#define PARITY_DEFAULT 0 /* Default setting */
++#define PARITY_NONE 1 /* No parity */
++#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
++#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
++#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
++#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
++#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
++#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
++
++#define LMI_DEFAULT 0 /* Default setting */
++#define LMI_NONE 1 /* No LMI, all PVCs are static */
++#define LMI_ANSI 2 /* ANSI Annex D */
++#define LMI_CCITT 3 /* ITU-T Annex A */
++#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
++
+ typedef struct {
+ unsigned int clock_rate; /* bits per second */
+ unsigned int clock_type; /* internal, external, TX-internal etc. */
+diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
+index 945ba1a..acbdae6 100644
+--- a/include/linux/hiddev.h
++++ b/include/linux/hiddev.h
+@@ -222,7 +222,7 @@ struct hid_report;
+ int hiddev_connect(struct hid_device *);
+ void hiddev_disconnect(struct hid_device *);
+ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+- struct hid_usage *usage, __s32 value, struct pt_regs *regs);
++ struct hid_usage *usage, __s32 value);
+ void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
+ int __init hiddev_init(void);
+ void hiddev_exit(void);
+@@ -230,7 +230,7 @@ void hiddev_exit(void);
+ static inline int hiddev_connect(struct hid_device *hid) { return -1; }
+ static inline void hiddev_disconnect(struct hid_device *hid) { }
+ static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+- struct hid_usage *usage, __s32 value, struct pt_regs *regs) { }
++ struct hid_usage *usage, __s32 value) { }
+ static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { }
+ static inline int hiddev_init(void) { return 0; }
+ static inline void hiddev_exit(void) { }
+diff --git a/include/linux/highmem.h b/include/linux/highmem.h
+index 85ce7ef..fd7d12d 100644
+--- a/include/linux/highmem.h
++++ b/include/linux/highmem.h
+@@ -24,11 +24,15 @@ static inline void flush_kernel_dcache_p
+
+ /* declarations for linux/mm/highmem.c */
+ unsigned int nr_free_highpages(void);
++extern unsigned long totalhigh_pages;
+
+ #else /* CONFIG_HIGHMEM */
+
+ static inline unsigned int nr_free_highpages(void) { return 0; }
+
++#define totalhigh_pages 0
++
++#ifndef ARCH_HAS_KMAP
+ static inline void *kmap(struct page *page)
+ {
+ might_sleep();
+@@ -41,6 +45,7 @@ static inline void *kmap(struct page *pa
+ #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
+
+ #endif /* CONFIG_HIGHMEM */
+
+diff --git a/include/linux/hpfs_fs.h b/include/linux/hpfs_fs.h
+deleted file mode 100644
+index a5028dd..0000000
+--- a/include/linux/hpfs_fs.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef _LINUX_HPFS_FS_H
+-#define _LINUX_HPFS_FS_H
+-
+-/* HPFS magic number (word 0 of block 16) */
+-
+-#define HPFS_SUPER_MAGIC 0xf995e849
+-
+-#endif
+diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
+index 4fc379d..fca9302 100644
+--- a/include/linux/hrtimer.h
++++ b/include/linux/hrtimer.h
+@@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct tim
+ struct timespec __user *rmtp,
+ const enum hrtimer_mode mode,
+ const clockid_t clockid);
++extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
+
+ extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
+ struct task_struct *tsk);
+diff --git a/include/linux/htirq.h b/include/linux/htirq.h
+new file mode 100644
+index 0000000..1f15ce2
+--- /dev/null
++++ b/include/linux/htirq.h
+@@ -0,0 +1,15 @@
++#ifndef LINUX_HTIRQ_H
++#define LINUX_HTIRQ_H
++
++/* Helper functions.. */
++void write_ht_irq_low(unsigned int irq, u32 data);
++void write_ht_irq_high(unsigned int irq, u32 data);
++u32 read_ht_irq_low(unsigned int irq);
++u32 read_ht_irq_high(unsigned int irq);
++void mask_ht_irq(unsigned int irq);
++void unmask_ht_irq(unsigned int irq);
++
++/* The arch hook for getting things started */
++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
++
++#endif /* LINUX_HTIRQ_H */
+diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
+index c25a38d..5081d27 100644
+--- a/include/linux/hugetlb.h
++++ b/include/linux/hugetlb.h
+@@ -17,6 +17,7 @@ int hugetlb_sysctl_handler(struct ctl_ta
+ int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *);
+ int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int);
+ void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
++void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
+ int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
+ int hugetlb_report_meminfo(char *);
+ int hugetlb_report_node_meminfo(int, char *);
+diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
+index c0e7fab..c8f8df2 100644
+--- a/include/linux/i2c-algo-bit.h
++++ b/include/linux/i2c-algo-bit.h
+@@ -40,7 +40,6 @@ struct i2c_algo_bit_data {
+ /* local settings */
+ int udelay; /* half-clock-cycle time in microsecs */
+ /* i.e. clock is (500 / udelay) KHz */
+- int mdelay; /* in millisecs, unused */
+ int timeout; /* in jiffies */
+ };
+
+diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
+index 18b0adf..9908f3f 100644
+--- a/include/linux/i2c-algo-pcf.h
++++ b/include/linux/i2c-algo-pcf.h
+@@ -35,7 +35,6 @@ struct i2c_algo_pcf_data {
+
+ /* local settings */
+ int udelay;
+- int mdelay;
+ int timeout;
+ };
+
+diff --git a/include/linux/i2c-algo-sibyte.h b/include/linux/i2c-algo-sibyte.h
+deleted file mode 100644
+index 03914de..0000000
+--- a/include/linux/i2c-algo-sibyte.h
++++ /dev/null
+@@ -1,33 +0,0 @@
+-/*
+- * Copyright (C) 2001,2002,2003 Broadcom Corporation
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version 2
+- * of the License, or (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#ifndef I2C_ALGO_SIBYTE_H
+-#define I2C_ALGO_SIBYTE_H 1
+-
+-#include <linux/i2c.h>
+-
+-struct i2c_algo_sibyte_data {
+- void *data; /* private data */
+- int bus; /* which bus */
+- void *reg_base; /* CSR base */
+-};
+-
+-int i2c_sibyte_add_bus(struct i2c_adapter *, int speed);
+-int i2c_sibyte_del_bus(struct i2c_adapter *);
+-
+-#endif /* I2C_ALGO_SIBYTE_H */
+diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
+index 9418519..0a8f750 100644
+--- a/include/linux/i2c-id.h
++++ b/include/linux/i2c-id.h
+@@ -193,6 +193,7 @@
+ #define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */
+ #define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */
+ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
++#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */
+
+ /* --- PCF 8584 based algorithms */
+ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index eb0628a..9b5d047 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -64,14 +64,6 @@ extern int i2c_master_recv(struct i2c_cl
+ */
+ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
+
+-/*
+- * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor.
+- * This is not tested/implemented yet and will change in the future.
+- */
+-extern int i2c_slave_send(struct i2c_client *,char*,int);
+-extern int i2c_slave_recv(struct i2c_client *,char*,int);
+-
+-
+
+ /* This is the very generalized SMBus access routine. You probably do not
+ want to use this, though; one of the functions below may be much easier,
+@@ -201,10 +193,6 @@ struct i2c_algorithm {
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data);
+
+- /* --- these optional/future use for some adapter types.*/
+- int (*slave_send)(struct i2c_adapter *,char*,int);
+- int (*slave_recv)(struct i2c_adapter *,char*,int);
+-
+ /* --- ioctl like call to set div. parameters. */
+ int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
+
+@@ -220,7 +208,7 @@ struct i2c_adapter {
+ struct module *owner;
+ unsigned int id;
+ unsigned int class;
+- struct i2c_algorithm *algo;/* the algorithm to access the bus */
++ const struct i2c_algorithm *algo; /* the algorithm to access the bus */
+ void *algo_data;
+
+ /* --- administration stuff. */
+diff --git a/include/linux/icmp.h b/include/linux/icmp.h
+index f0b571f..878cfe4 100644
+--- a/include/linux/icmp.h
++++ b/include/linux/icmp.h
+@@ -68,16 +68,16 @@
+ struct icmphdr {
+ __u8 type;
+ __u8 code;
+- __u16 checksum;
++ __be16 checksum;
+ union {
+ struct {
+- __u16 id;
+- __u16 sequence;
++ __be16 id;
++ __be16 sequence;
+ } echo;
+- __u32 gateway;
++ __be32 gateway;
+ struct {
+- __u16 __unused;
+- __u16 mtu;
++ __be16 __unused;
++ __be16 mtu;
+ } frag;
+ } un;
+ };
+diff --git a/include/linux/ide.h b/include/linux/ide.h
+index 9962045..9c20502 100644
+--- a/include/linux/ide.h
++++ b/include/linux/ide.h
+@@ -251,7 +251,8 @@ static inline void ide_std_init_ports(hw
+
+ #include <asm/ide.h>
+
+-#ifndef MAX_HWIFS
++#if !defined(MAX_HWIFS) || defined(CONFIG_EMBEDDED)
++#undef MAX_HWIFS
+ #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS
+ #endif
+
+@@ -773,12 +774,13 @@ typedef struct hwif_s {
+ unsigned long dma_status; /* dma status register */
+ unsigned long dma_vendor3; /* dma vendor 3 register */
+ unsigned long dma_prdtable; /* actual prd table address */
+- unsigned long dma_base2; /* extended base addr for dma ports */
+
+- unsigned dma_extra; /* extra addr for dma ports */
+ unsigned long config_data; /* for use by chipset-specific code */
+ unsigned long select_data; /* for use by chipset-specific code */
+
++ unsigned long extra_base; /* extra addr for dma ports */
++ unsigned extra_ports; /* number of extra dma ports */
++
+ unsigned noprobe : 1; /* don't probe for this interface */
+ unsigned present : 1; /* this interface exists */
+ unsigned hold : 1; /* this interface is always present */
+@@ -823,6 +825,9 @@ typedef struct hwgroup_s {
+ unsigned int sleeping : 1;
+ /* BOOL: polling active & poll_timeout field valid */
+ unsigned int polling : 1;
++ /* BOOL: in a polling reset situation. Must not trigger another reset yet */
++ unsigned int resetting : 1;
++
+ /* current drive */
+ ide_drive_t *drive;
+ /* ptr to current hwif in linked-list */
+@@ -1180,7 +1185,7 @@ extern void ide_stall_queue(ide_drive_t
+
+ extern int ide_spin_wait_hwgroup(ide_drive_t *);
+ extern void ide_timer_expiry(unsigned long);
+-extern irqreturn_t ide_intr(int irq, void *dev_id, struct pt_regs *regs);
++extern irqreturn_t ide_intr(int irq, void *dev_id);
+ extern void do_ide_request(request_queue_t *);
+
+ void ide_init_disk(struct gendisk *, ide_drive_t *);
+@@ -1190,7 +1195,6 @@ extern int ideprobe_init(void);
+ extern void ide_scan_pcibus(int scan_direction) __init;
+ extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner);
+ #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE)
+-extern void ide_pci_unregister_driver(struct pci_driver *driver);
+ void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *);
+ extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d);
+
+diff --git a/include/linux/if.h b/include/linux/if.h
+index 374e20a..32bf419 100644
+--- a/include/linux/if.h
++++ b/include/linux/if.h
+@@ -59,6 +59,8 @@
+ #define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
+ #define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
+ #define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
++#define IFF_BONDING 0x20 /* bonding master or slave */
++#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
+
+ #define IF_GET_IFACE 0x0001 /* for querying only */
+ #define IF_GET_PROTO 0x0002
+@@ -212,5 +214,4 @@ struct ifconf
+ #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
+ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */
+
+-
+ #endif /* _LINUX_IF_H */
+diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
+new file mode 100644
+index 0000000..dbe8f61
+--- /dev/null
++++ b/include/linux/if_addr.h
+@@ -0,0 +1,55 @@
++#ifndef __LINUX_IF_ADDR_H
++#define __LINUX_IF_ADDR_H
++
++#include <linux/netlink.h>
++
++struct ifaddrmsg
++{
++ __u8 ifa_family;
++ __u8 ifa_prefixlen; /* The prefix length */
++ __u8 ifa_flags; /* Flags */
++ __u8 ifa_scope; /* Address scope */
++ __u32 ifa_index; /* Link index */
++};
++
++/*
++ * Important comment:
++ * IFA_ADDRESS is prefix address, rather than local interface address.
++ * It makes no difference for normally configured broadcast interfaces,
++ * but for point-to-point IFA_ADDRESS is DESTINATION address,
++ * local address is supplied in IFA_LOCAL attribute.
++ */
++enum
++{
++ IFA_UNSPEC,
++ IFA_ADDRESS,
++ IFA_LOCAL,
++ IFA_LABEL,
++ IFA_BROADCAST,
++ IFA_ANYCAST,
++ IFA_CACHEINFO,
++ IFA_MULTICAST,
++ __IFA_MAX,
++};
++
++#define IFA_MAX (__IFA_MAX - 1)
++
++/* ifa_flags */
++#define IFA_F_SECONDARY 0x01
++#define IFA_F_TEMPORARY IFA_F_SECONDARY
++
++#define IFA_F_NODAD 0x02
++#define IFA_F_HOMEADDRESS 0x10
++#define IFA_F_DEPRECATED 0x20
++#define IFA_F_TENTATIVE 0x40
++#define IFA_F_PERMANENT 0x80
++
++struct ifa_cacheinfo
++{
++ __u32 ifa_prefered;
++ __u32 ifa_valid;
++ __u32 cstamp; /* created timestamp, hundredths of seconds */
++ __u32 tstamp; /* updated timestamp, hundredths of seconds */
++};
++
++#endif
+diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
+index a8b1a20..7f57142 100644
+--- a/include/linux/if_arp.h
++++ b/include/linux/if_arp.h
+@@ -130,11 +130,11 @@ struct arpreq_old {
+
+ struct arphdr
+ {
+- unsigned short ar_hrd; /* format of hardware address */
+- unsigned short ar_pro; /* format of protocol address */
++ __be16 ar_hrd; /* format of hardware address */
++ __be16 ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+- unsigned short ar_op; /* ARP opcode (command) */
++ __be16 ar_op; /* ARP opcode (command) */
+
+ #if 0
+ /*
+diff --git a/include/linux/if_link.h b/include/linux/if_link.h
+new file mode 100644
+index 0000000..e963a07
+--- /dev/null
++++ b/include/linux/if_link.h
+@@ -0,0 +1,136 @@
++#ifndef _LINUX_IF_LINK_H
++#define _LINUX_IF_LINK_H
++
++#include <linux/netlink.h>
++
++/* The struct should be in sync with struct net_device_stats */
++struct rtnl_link_stats
++{
++ __u32 rx_packets; /* total packets received */
++ __u32 tx_packets; /* total packets transmitted */
++ __u32 rx_bytes; /* total bytes received */
++ __u32 tx_bytes; /* total bytes transmitted */
++ __u32 rx_errors; /* bad packets received */
++ __u32 tx_errors; /* packet transmit problems */
++ __u32 rx_dropped; /* no space in linux buffers */
++ __u32 tx_dropped; /* no space available in linux */
++ __u32 multicast; /* multicast packets received */
++ __u32 collisions;
++
++ /* detailed rx_errors: */
++ __u32 rx_length_errors;
++ __u32 rx_over_errors; /* receiver ring buff overflow */
++ __u32 rx_crc_errors; /* recved pkt with crc error */
++ __u32 rx_frame_errors; /* recv'd frame alignment error */
++ __u32 rx_fifo_errors; /* recv'r fifo overrun */
++ __u32 rx_missed_errors; /* receiver missed packet */
++
++ /* detailed tx_errors */
++ __u32 tx_aborted_errors;
++ __u32 tx_carrier_errors;
++ __u32 tx_fifo_errors;
++ __u32 tx_heartbeat_errors;
++ __u32 tx_window_errors;
++
++ /* for cslip etc */
++ __u32 rx_compressed;
++ __u32 tx_compressed;
++};
++
++/* The struct should be in sync with struct ifmap */
++struct rtnl_link_ifmap
++{
++ __u64 mem_start;
++ __u64 mem_end;
++ __u64 base_addr;
++ __u16 irq;
++ __u8 dma;
++ __u8 port;
++};
++
++enum
++{
++ IFLA_UNSPEC,
++ IFLA_ADDRESS,
++ IFLA_BROADCAST,
++ IFLA_IFNAME,
++ IFLA_MTU,
++ IFLA_LINK,
++ IFLA_QDISC,
++ IFLA_STATS,
++ IFLA_COST,
++#define IFLA_COST IFLA_COST
++ IFLA_PRIORITY,
++#define IFLA_PRIORITY IFLA_PRIORITY
++ IFLA_MASTER,
++#define IFLA_MASTER IFLA_MASTER
++ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
++#define IFLA_WIRELESS IFLA_WIRELESS
++ IFLA_PROTINFO, /* Protocol specific information for a link */
++#define IFLA_PROTINFO IFLA_PROTINFO
++ IFLA_TXQLEN,
++#define IFLA_TXQLEN IFLA_TXQLEN
++ IFLA_MAP,
++#define IFLA_MAP IFLA_MAP
++ IFLA_WEIGHT,
++#define IFLA_WEIGHT IFLA_WEIGHT
++ IFLA_OPERSTATE,
++ IFLA_LINKMODE,
++ __IFLA_MAX
++};
++
++
++#define IFLA_MAX (__IFLA_MAX - 1)
++
++/* ifi_flags.
++
++ IFF_* flags.
++
++ The only change is:
++ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
++ more not changeable by user. They describe link media
++ characteristics and set by device driver.
++
++ Comments:
++ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
++ - If neither of these three flags are set;
++ the interface is NBMA.
++
++ - IFF_MULTICAST does not mean anything special:
++ multicasts can be used on all not-NBMA links.
++ IFF_MULTICAST means that this media uses special encapsulation
++ for multicast frames. Apparently, all IFF_POINTOPOINT and
++ IFF_BROADCAST devices are able to use multicasts too.
++ */
++
++/* IFLA_LINK.
++ For usual devices it is equal ifi_index.
++ If it is a "virtual interface" (f.e. tunnel), ifi_link
++ can point to real physical interface (f.e. for bandwidth calculations),
++ or maybe 0, what means, that real media is unknown (usual
++ for IPIP tunnels, when route to endpoint is allowed to change)
++ */
++
++/* Subtype attributes for IFLA_PROTINFO */
++enum
++{
++ IFLA_INET6_UNSPEC,
++ IFLA_INET6_FLAGS, /* link flags */
++ IFLA_INET6_CONF, /* sysctl parameters */
++ IFLA_INET6_STATS, /* statistics */
++ IFLA_INET6_MCAST, /* MC things. What of them? */
++ IFLA_INET6_CACHEINFO, /* time values and max reasm size */
++ __IFLA_INET6_MAX
++};
++
++#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
++
++struct ifla_cacheinfo
++{
++ __u32 max_reasm_len;
++ __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
++ __u32 reachable_time;
++ __u32 retrans_time;
++};
++
++#endif /* _LINUX_IF_LINK_H */
+diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
+index ab27408..35cb385 100644
+--- a/include/linux/if_vlan.h
++++ b/include/linux/if_vlan.h
+@@ -44,7 +44,7 @@ struct vlan_ethhdr {
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ __be16 h_vlan_proto; /* Should always be 0x8100 */
+ __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */
+- unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */
++ __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */
+ };
+
+ #include <linux/skbuff.h>
+diff --git a/include/linux/igmp.h b/include/linux/igmp.h
+index 899c3d4..03f43e2 100644
+--- a/include/linux/igmp.h
++++ b/include/linux/igmp.h
+@@ -30,8 +30,8 @@ struct igmphdr
+ {
+ __u8 type;
+ __u8 code; /* For newer IGMP */
+- __u16 csum;
+- __u32 group;
++ __be16 csum;
++ __be32 group;
+ };
+
+ /* V3 group record types [grec_type] */
+@@ -45,25 +45,25 @@ struct igmphdr
+ struct igmpv3_grec {
+ __u8 grec_type;
+ __u8 grec_auxwords;
+- __u16 grec_nsrcs;
+- __u32 grec_mca;
+- __u32 grec_src[0];
++ __be16 grec_nsrcs;
++ __be32 grec_mca;
++ __be32 grec_src[0];
+ };
+
+ struct igmpv3_report {
+ __u8 type;
+ __u8 resv1;
+- __u16 csum;
+- __u16 resv2;
+- __u16 ngrec;
++ __be16 csum;
++ __be16 resv2;
++ __be16 ngrec;
+ struct igmpv3_grec grec[0];
+ };
+
+ struct igmpv3_query {
+ __u8 type;
+ __u8 code;
+- __u16 csum;
+- __u32 group;
++ __be16 csum;
++ __be32 group;
+ #if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 qrv:3,
+ suppress:1,
+@@ -76,8 +76,8 @@ struct igmpv3_query {
+ #error "Please fix <asm/byteorder.h>"
+ #endif
+ __u8 qqic;
+- __u16 nsrcs;
+- __u32 srcs[0];
++ __be16 nsrcs;
++ __be32 srcs[0];
+ };
+
+ #define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */
+@@ -136,11 +136,11 @@ struct ip_sf_socklist
+ {
+ unsigned int sl_max;
+ unsigned int sl_count;
+- __u32 sl_addr[0];
++ __be32 sl_addr[0];
+ };
+
+ #define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \
+- (count) * sizeof(__u32))
++ (count) * sizeof(__be32))
+
+ #define IP_SFBLOCK 10 /* allocate this many at once */
+
+@@ -159,7 +159,7 @@ struct ip_mc_socklist
+ struct ip_sf_list
+ {
+ struct ip_sf_list *sf_next;
+- __u32 sf_inaddr;
++ __be32 sf_inaddr;
+ unsigned long sf_count[2]; /* include/exclude counts */
+ unsigned char sf_gsresp; /* include in g & s response? */
+ unsigned char sf_oldin; /* change state */
+@@ -197,7 +197,7 @@ struct ip_mc_list
+ #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
+ #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
+
+-extern int ip_check_mc(struct in_device *dev, u32 mc_addr, u32 src_addr, u16 proto);
++extern int ip_check_mc(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u16 proto);
+ extern int igmp_rcv(struct sk_buff *);
+ extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
+ extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
+@@ -209,13 +209,13 @@ extern int ip_mc_msfget(struct sock *sk,
+ struct ip_msfilter __user *optval, int __user *optlen);
+ extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
+ struct group_filter __user *optval, int __user *optlen);
+-extern int ip_mc_sf_allow(struct sock *sk, u32 local, u32 rmt, int dif);
++extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
+ extern void ip_mr_init(void);
+ extern void ip_mc_init_dev(struct in_device *);
+ extern void ip_mc_destroy_dev(struct in_device *);
+ extern void ip_mc_up(struct in_device *);
+ extern void ip_mc_down(struct in_device *);
+-extern void ip_mc_dec_group(struct in_device *in_dev, u32 addr);
+-extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr);
++extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
++extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
+ #endif
+ #endif
+diff --git a/include/linux/in.h b/include/linux/in.h
+index 94f557f..2619859 100644
+--- a/include/linux/in.h
++++ b/include/linux/in.h
+@@ -40,6 +40,7 @@ enum {
+
+ IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
+ IPPROTO_AH = 51, /* Authentication Header protocol */
++ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
+ IPPROTO_PIM = 103, /* Protocol Independent Multicast */
+
+ IPPROTO_COMP = 108, /* Compression Header protocol */
+@@ -52,7 +53,7 @@ enum {
+
+ /* Internet address. */
+ struct in_addr {
+- __u32 s_addr;
++ __be32 s_addr;
+ };
+
+ #define IP_TOS 1
+@@ -123,17 +124,17 @@ struct ip_mreqn
+ };
+
+ struct ip_mreq_source {
+- __u32 imr_multiaddr;
+- __u32 imr_interface;
+- __u32 imr_sourceaddr;
++ __be32 imr_multiaddr;
++ __be32 imr_interface;
++ __be32 imr_sourceaddr;
+ };
+
+ struct ip_msfilter {
+- __u32 imsf_multiaddr;
+- __u32 imsf_interface;
++ __be32 imsf_multiaddr;
++ __be32 imsf_interface;
+ __u32 imsf_fmode;
+ __u32 imsf_numsrc;
+- __u32 imsf_slist[1];
++ __be32 imsf_slist[1];
+ };
+
+ #define IP_MSFILTER_SIZE(numsrc) \
+@@ -177,7 +178,7 @@ struct in_pktinfo
+ #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
+ struct sockaddr_in {
+ sa_family_t sin_family; /* Address family */
+- unsigned short int sin_port; /* Port number */
++ __be16 sin_port; /* Port number */
+ struct in_addr sin_addr; /* Internet address */
+
+ /* Pad to size of `struct sockaddr'. */
+diff --git a/include/linux/in6.h b/include/linux/in6.h
+index 304aaed..9be6a47 100644
+--- a/include/linux/in6.h
++++ b/include/linux/in6.h
+@@ -32,8 +32,8 @@ struct in6_addr
+ union
+ {
+ __u8 u6_addr8[16];
+- __u16 u6_addr16[8];
+- __u32 u6_addr32[4];
++ __be16 u6_addr16[8];
++ __be32 u6_addr32[4];
+ } in6_u;
+ #define s6_addr in6_u.u6_addr8
+ #define s6_addr16 in6_u.u6_addr16
+@@ -53,7 +53,7 @@ extern const struct in6_addr in6addr_loo
+
+ struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+- __u16 sin6_port; /* Transport layer port # */
++ __be16 sin6_port; /* Transport layer port # */
+ __u32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+@@ -134,6 +134,7 @@ struct in6_flowlabel_req
+ #define IPPROTO_ICMPV6 58 /* ICMPv6 */
+ #define IPPROTO_NONE 59 /* IPv6 no next header */
+ #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
++#define IPPROTO_MH 135 /* IPv6 mobility header */
+
+ /*
+ * IPv6 TLV options.
+@@ -142,6 +143,7 @@ struct in6_flowlabel_req
+ #define IPV6_TLV_PADN 1
+ #define IPV6_TLV_ROUTERALERT 5
+ #define IPV6_TLV_JUMBO 194
++#define IPV6_TLV_HAO 201 /* home address option */
+
+ /*
+ * IPV6 socket options
+diff --git a/include/linux/inet.h b/include/linux/inet.h
+index 6c5587a..b7c6da7 100644
+--- a/include/linux/inet.h
++++ b/include/linux/inet.h
+@@ -46,5 +46,7 @@
+ #include <linux/types.h>
+
+ extern __be32 in_aton(const char *str);
++extern int in4_pton(const char *src, int srclen, u8 *dst, char delim, const char **end);
++extern int in6_pton(const char *src, int srclen, u8 *dst, char delim, const char **end);
+ #endif
+ #endif /* _LINUX_INET_H */
+diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
+index a4606e5..6e8bc54 100644
+--- a/include/linux/inet_diag.h
++++ b/include/linux/inet_diag.h
+@@ -9,10 +9,10 @@
+
+ /* Socket identity */
+ struct inet_diag_sockid {
+- __u16 idiag_sport;
+- __u16 idiag_dport;
+- __u32 idiag_src[4];
+- __u32 idiag_dst[4];
++ __be16 idiag_sport;
++ __be16 idiag_dport;
++ __be32 idiag_src[4];
++ __be32 idiag_dst[4];
+ __u32 idiag_if;
+ __u32 idiag_cookie[2];
+ #define INET_DIAG_NOCOOKIE (~0U)
+@@ -67,7 +67,7 @@ struct inet_diag_hostcond {
+ __u8 family;
+ __u8 prefix_len;
+ int port;
+- __u32 addr[0];
++ __be32 addr[0];
+ };
+
+ /* Base info structure. It contains socket identity (addrs/ports/cookie)
+diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
+index 92297ff..5a0ab04 100644
+--- a/include/linux/inetdevice.h
++++ b/include/linux/inetdevice.h
+@@ -90,11 +90,11 @@ struct in_ifaddr
+ struct in_ifaddr *ifa_next;
+ struct in_device *ifa_dev;
+ struct rcu_head rcu_head;
+- u32 ifa_local;
+- u32 ifa_address;
+- u32 ifa_mask;
+- u32 ifa_broadcast;
+- u32 ifa_anycast;
++ __be32 ifa_local;
++ __be32 ifa_address;
++ __be32 ifa_mask;
++ __be32 ifa_broadcast;
++ __be32 ifa_anycast;
+ unsigned char ifa_scope;
+ unsigned char ifa_flags;
+ unsigned char ifa_prefixlen;
+@@ -104,18 +104,18 @@ struct in_ifaddr
+ extern int register_inetaddr_notifier(struct notifier_block *nb);
+ extern int unregister_inetaddr_notifier(struct notifier_block *nb);
+
+-extern struct net_device *ip_dev_find(u32 addr);
+-extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b);
++extern struct net_device *ip_dev_find(__be32 addr);
++extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
+ extern int devinet_ioctl(unsigned int cmd, void __user *);
+ extern void devinet_init(void);
+ extern struct in_device *inetdev_init(struct net_device *dev);
+ extern struct in_device *inetdev_by_index(int);
+-extern u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope);
+-extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope);
+-extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
++extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
++extern __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope);
++extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask);
+ extern void inet_forward_change(void);
+
+-static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
++static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa)
+ {
+ return !((addr^ifa->ifa_address)&ifa->ifa_mask);
+ }
+@@ -183,7 +183,7 @@ static inline void in_dev_put(struct in_
+
+ #endif /* __KERNEL__ */
+
+-static __inline__ __u32 inet_make_mask(int logmask)
++static __inline__ __be32 inet_make_mask(int logmask)
+ {
+ if (logmask)
+ return htonl(~((1<<(32-logmask))-1));
+diff --git a/include/linux/init.h b/include/linux/init.h
+index 6667785..ff40ea1 100644
+--- a/include/linux/init.h
++++ b/include/linux/init.h
+@@ -68,6 +68,7 @@ extern initcall_t __security_initcall_st
+
+ /* Defined in init/main.c */
+ extern char saved_command_line[];
++extern unsigned int reset_devices;
+
+ /* used by init/main.c */
+ extern void setup_arch(char **);
+@@ -83,19 +84,29 @@ extern void setup_arch(char **);
+ * by link order.
+ * For backwards compatibility, initcall() puts the call in
+ * the device init subsection.
++ *
++ * The `id' arg to __define_initcall() is needed so that multiple initcalls
++ * can point at the same handler without causing duplicate-symbol build errors.
+ */
+
+-#define __define_initcall(level,fn) \
+- static initcall_t __initcall_##fn __attribute_used__ \
++#define __define_initcall(level,fn,id) \
++ static initcall_t __initcall_##fn##id __attribute_used__ \
+ __attribute__((__section__(".initcall" level ".init"))) = fn
+
+-#define core_initcall(fn) __define_initcall("1",fn)
+-#define postcore_initcall(fn) __define_initcall("2",fn)
+-#define arch_initcall(fn) __define_initcall("3",fn)
+-#define subsys_initcall(fn) __define_initcall("4",fn)
+-#define fs_initcall(fn) __define_initcall("5",fn)
+-#define device_initcall(fn) __define_initcall("6",fn)
+-#define late_initcall(fn) __define_initcall("7",fn)
++#define core_initcall(fn) __define_initcall("1",fn,1)
++#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
++#define postcore_initcall(fn) __define_initcall("2",fn,2)
++#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
++#define arch_initcall(fn) __define_initcall("3",fn,3)
++#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
++#define subsys_initcall(fn) __define_initcall("4",fn,4)
++#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
++#define fs_initcall(fn) __define_initcall("5",fn,5)
++#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
++#define device_initcall(fn) __define_initcall("6",fn,6)
++#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
++#define late_initcall(fn) __define_initcall("7",fn,7)
++#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
+
+ #define __initcall(fn) device_initcall(fn)
+
+diff --git a/include/linux/init_task.h b/include/linux/init_task.h
+index 60aac2c..33c5daa 100644
+--- a/include/linux/init_task.h
++++ b/include/linux/init_task.h
+@@ -4,7 +4,9 @@
+ #include <linux/file.h>
+ #include <linux/rcupdate.h>
+ #include <linux/irqflags.h>
++#include <linux/utsname.h>
+ #include <linux/lockdep.h>
++#include <linux/ipc.h>
+
+ #define INIT_FDTABLE \
+ { \
+@@ -68,6 +70,15 @@
+ .session = 1, \
+ }
+
++extern struct nsproxy init_nsproxy;
++#define INIT_NSPROXY(nsproxy) { \
++ .count = ATOMIC_INIT(1), \
++ .nslock = SPIN_LOCK_UNLOCKED, \
++ .uts_ns = &init_uts_ns, \
++ .namespace = NULL, \
++ INIT_IPC_NS(ipc_ns) \
++}
++
+ #define INIT_SIGHAND(sighand) { \
+ .count = ATOMIC_INIT(1), \
+ .action = { { { .sa_handler = NULL, } }, }, \
+@@ -117,6 +128,7 @@ extern struct group_info init_groups;
+ .files = &init_files, \
+ .signal = &init_signals, \
+ .sighand = &init_sighand, \
++ .nsproxy = &init_nsproxy, \
+ .pending = { \
+ .list = LIST_HEAD_INIT(tsk.pending.list), \
+ .signal = {{0}}}, \
+diff --git a/include/linux/input.h b/include/linux/input.h
+index b3253ab..c38507b 100644
+--- a/include/linux/input.h
++++ b/include/linux/input.h
+@@ -349,6 +349,9 @@ struct input_absinfo {
+
+ #define KEY_BATTERY 236
+
++#define KEY_BLUETOOTH 237
++#define KEY_WLAN 238
++
+ #define KEY_UNKNOWN 240
+
+ #define BTN_MISC 0x100
+@@ -645,6 +648,7 @@ struct input_absinfo {
+ #define BUS_USB 0x03
+ #define BUS_HIL 0x04
+ #define BUS_BLUETOOTH 0x05
++#define BUS_VIRTUAL 0x06
+
+ #define BUS_ISA 0x10
+ #define BUS_I8042 0x11
+@@ -667,98 +671,167 @@ struct input_absinfo {
+
+ /*
+ * Structures used in ioctls to upload effects to a device
+- * The first structures are not passed directly by using ioctls.
+- * They are sub-structures of the actually sent structure (called ff_effect)
++ * They are pieces of a bigger structure (called ff_effect)
++ */
++
++/*
++ * All duration values are expressed in ms. Values above 32767 ms (0x7fff)
++ * should not be used and have unspecified results.
+ */
+
++/**
++ * struct ff_replay - defines scheduling of the effect
++ * @length: duration of the effect
++ * @delay: delay before effect should start playing
++ */
+ struct ff_replay {
+- __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
+- __u16 delay; /* Time to wait before to start playing an effect */
++ __u16 length;
++ __u16 delay;
+ };
+
++/**
++ * struct ff_trigger - defines what triggers the effect
++ * @button: number of the button triggering the effect
++ * @interval: controls how soon the effect can be re-triggered
++ */
+ struct ff_trigger {
+- __u16 button; /* Number of button triggering an effect */
+- __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
++ __u16 button;
++ __u16 interval;
+ };
+
++/**
++ * struct ff_envelope - generic effect envelope
++ * @attack_length: duration of the attack (ms)
++ * @attack_level: level at the beginning of the attack
++ * @fade_length: duration of fade (ms)
++ * @fade_level: level at the end of fade
++ *
++ * The @attack_level and @fade_level are absolute values; when applying
++ * envelope force-feedback core will convert to positive/negative
++ * value based on polarity of the default level of the effect.
++ * Valid range for the attack and fade levels is 0x0000 - 0x7fff
++ */
+ struct ff_envelope {
+- __u16 attack_length; /* Duration of attack (ms) */
+- __u16 attack_level; /* Level at beginning of attack */
+- __u16 fade_length; /* Duration of fade (ms) */
+- __u16 fade_level; /* Level at end of fade */
++ __u16 attack_length;
++ __u16 attack_level;
++ __u16 fade_length;
++ __u16 fade_level;
+ };
+
+-/* FF_CONSTANT */
++/**
++ * struct ff_constant_effect - defines parameters of a constant effect
++ * @level: strength of the effect; may be negative
++ * @envelope: envelope data
++ */
+ struct ff_constant_effect {
+- __s16 level; /* Strength of effect. Negative values are OK */
++ __s16 level;
+ struct ff_envelope envelope;
+ };
+
+-/* FF_RAMP */
++/**
++ * struct ff_ramp_effect - defines parameters of a ramp effect
++ * @start_level: beginning strength of the effect; may be negative
++ * @end_level: final strength of the effect; may be negative
++ * @envelope: envelope data
++ */
+ struct ff_ramp_effect {
+ __s16 start_level;
+ __s16 end_level;
+ struct ff_envelope envelope;
+ };
+
+-/* FF_SPRING of FF_FRICTION */
++/**
++ * struct ff_condition_effect - defines a spring or friction effect
++ * @right_saturation: maximum level when joystick moved all way to the right
++ * @left_saturation: same for the left side
++ * @right_coeff: controls how fast the force grows when the joystick moves
++ * to the right
++ * @left_coeff: same for the left side
++ * @deadband: size of the dead zone, where no force is produced
++ * @center: position of the dead zone
++ */
+ struct ff_condition_effect {
+- __u16 right_saturation; /* Max level when joystick is on the right */
+- __u16 left_saturation; /* Max level when joystick in on the left */
+-
+- __s16 right_coeff; /* Indicates how fast the force grows when the
+- joystick moves to the right */
+- __s16 left_coeff; /* Same for left side */
++ __u16 right_saturation;
++ __u16 left_saturation;
+
+- __u16 deadband; /* Size of area where no force is produced */
+- __s16 center; /* Position of dead zone */
++ __s16 right_coeff;
++ __s16 left_coeff;
+
++ __u16 deadband;
++ __s16 center;
+ };
+
+-/* FF_PERIODIC */
++/**
++ * struct ff_periodic_effect - defines parameters of a periodic effect
++ * @waveform: kind of the effect (wave)
++ * @period: period of the wave (ms)
++ * @magnitude: peak value
++ * @offset: mean value of the wave (roughly)
++ * @phase: 'horizontal' shift
++ * @envelope: envelope data
++ * @custom_len: number of samples (FF_CUSTOM only)
++ * @custom_data: buffer of samples (FF_CUSTOM only)
++ *
++ * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
++ * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
++ * for the time being as no driver supports it yet.
++ *
++ * Note: the data pointed by custom_data is copied by the driver.
++ * You can therefore dispose of the memory after the upload/update.
++ */
+ struct ff_periodic_effect {
+- __u16 waveform; /* Kind of wave (sine, square...) */
+- __u16 period; /* in ms */
+- __s16 magnitude; /* Peak value */
+- __s16 offset; /* Mean value of wave (roughly) */
+- __u16 phase; /* 'Horizontal' shift */
++ __u16 waveform;
++ __u16 period;
++ __s16 magnitude;
++ __s16 offset;
++ __u16 phase;
+
+ struct ff_envelope envelope;
+
+-/* Only used if waveform == FF_CUSTOM */
+- __u32 custom_len; /* Number of samples */
+- __s16 *custom_data; /* Buffer of samples */
+-/* Note: the data pointed by custom_data is copied by the driver. You can
+- * therefore dispose of the memory after the upload/update */
++ __u32 custom_len;
++ __s16 *custom_data;
+ };
+
+-/* FF_RUMBLE */
+-/* Some rumble pads have two motors of different weight.
+- strong_magnitude represents the magnitude of the vibration generated
+- by the heavy motor.
+-*/
++/**
++ * struct ff_rumble_effect - defines parameters of a periodic effect
++ * @strong_magnitude: magnitude of the heavy motor
++ * @weak_magnitude: magnitude of the light one
++ *
++ * Some rumble pads have two motors of different weight. Strong_magnitude
++ * represents the magnitude of the vibration generated by the heavy one.
++ */
+ struct ff_rumble_effect {
+- __u16 strong_magnitude; /* Magnitude of the heavy motor */
+- __u16 weak_magnitude; /* Magnitude of the light one */
++ __u16 strong_magnitude;
++ __u16 weak_magnitude;
+ };
+
+-/*
+- * Structure sent through ioctl from the application to the driver
++/**
++ * struct ff_effect - defines force feedback effect
++ * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
++ * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
++ * @id: an unique id assigned to an effect
++ * @direction: direction of the effect
++ * @trigger: trigger conditions (struct ff_trigger)
++ * @replay: scheduling of the effect (struct ff_replay)
++ * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
++ * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
++ * defining effect parameters
++ *
++ * This structure is sent through ioctl from the application to the driver.
++ * To create a new effect aplication should set its @id to -1; the kernel
++ * will return assigned @id which can later be used to update or delete
++ * this effect.
++ *
++ * Direction of the effect is encoded as follows:
++ * 0 deg -> 0x0000 (down)
++ * 90 deg -> 0x4000 (left)
++ * 180 deg -> 0x8000 (up)
++ * 270 deg -> 0xC000 (right)
+ */
+ struct ff_effect {
+ __u16 type;
+-/* Following field denotes the unique id assigned to an effect.
+- * If user sets if to -1, a new effect is created, and its id is returned in the same field
+- * Else, the user sets it to the effect id it wants to update.
+- */
+ __s16 id;
+-
+- __u16 direction; /* Direction. 0 deg -> 0x0000 (down)
+- 90 deg -> 0x4000 (left)
+- 180 deg -> 0x8000 (up)
+- 270 deg -> 0xC000 (right)
+- */
+-
++ __u16 direction;
+ struct ff_trigger trigger;
+ struct ff_replay replay;
+
+@@ -784,6 +857,9 @@ struct ff_effect {
+ #define FF_INERTIA 0x56
+ #define FF_RAMP 0x57
+
++#define FF_EFFECT_MIN FF_RUMBLE
++#define FF_EFFECT_MAX FF_RAMP
++
+ /*
+ * Force feedback periodic effect types
+ */
+@@ -795,6 +871,9 @@ struct ff_effect {
+ #define FF_SAW_DOWN 0x5c
+ #define FF_CUSTOM 0x5d
+
++#define FF_WAVEFORM_MIN FF_SQUARE
++#define FF_WAVEFORM_MAX FF_CUSTOM
++
+ /*
+ * Set ff device properties
+ */
+@@ -864,16 +943,16 @@ struct input_dev {
+ unsigned long sndbit[NBITS(SND_MAX)];
+ unsigned long ffbit[NBITS(FF_MAX)];
+ unsigned long swbit[NBITS(SW_MAX)];
+- int ff_effects_max;
+
+ unsigned int keycodemax;
+ unsigned int keycodesize;
+ void *keycode;
+
++ struct ff_device *ff;
++
+ unsigned int repeat_key;
+ struct timer_list timer;
+
+- struct pt_regs *regs;
+ int state;
+
+ int sync;
+@@ -895,8 +974,6 @@ struct input_dev {
+ void (*close)(struct input_dev *dev);
+ int (*flush)(struct input_dev *dev, struct file *file);
+ int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+- int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
+- int (*erase_effect)(struct input_dev *dev, int effect_id);
+
+ struct input_handle *grab;
+
+@@ -904,9 +981,6 @@ struct input_dev {
+ unsigned int users;
+
+ struct class_device cdev;
+- struct device *dev; /* will be removed soon */
+-
+- int dynalloc; /* temporarily */
+
+ struct list_head h_list;
+ struct list_head node;
+@@ -985,16 +1059,16 @@ struct input_handler {
+ void *private;
+
+ void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+- struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
++ struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
+ void (*disconnect)(struct input_handle *handle);
+ void (*start)(struct input_handle *handle);
+
+ const struct file_operations *fops;
+ int minor;
+- char *name;
++ const char *name;
+
+- struct input_device_id *id_table;
+- struct input_device_id *blacklist;
++ const struct input_device_id *id_table;
++ const struct input_device_id *blacklist;
+
+ struct list_head h_list;
+ struct list_head node;
+@@ -1005,7 +1079,7 @@ struct input_handle {
+ void *private;
+
+ int open;
+- char *name;
++ const char *name;
+
+ struct input_dev *dev;
+ struct input_handler *handler;
+@@ -1019,12 +1093,6 @@ struct input_handle {
+ #define to_handle(n) container_of(n,struct input_handle,d_node)
+ #define to_handle_h(n) container_of(n,struct input_handle,h_node)
+
+-static inline void init_input_dev(struct input_dev *dev)
+-{
+- INIT_LIST_HEAD(&dev->h_list);
+- INIT_LIST_HEAD(&dev->node);
+-}
+-
+ struct input_dev *input_allocate_device(void);
+ void input_free_device(struct input_dev *dev);
+
+@@ -1041,7 +1109,7 @@ static inline void input_put_device(stru
+ int input_register_device(struct input_dev *);
+ void input_unregister_device(struct input_dev *);
+
+-void input_register_handler(struct input_handler *);
++int input_register_handler(struct input_handler *);
+ void input_unregister_handler(struct input_handler *);
+
+ int input_grab_device(struct input_handle *);
+@@ -1070,11 +1138,6 @@ static inline void input_report_abs(stru
+ input_event(dev, EV_ABS, code, value);
+ }
+
+-static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value)
+-{
+- input_event(dev, EV_FF, code, value);
+-}
+-
+ static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
+ {
+ input_event(dev, EV_FF_STATUS, code, value);
+@@ -1085,15 +1148,9 @@ static inline void input_report_switch(s
+ input_event(dev, EV_SW, code, !!value);
+ }
+
+-static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
+-{
+- dev->regs = regs;
+-}
+-
+ static inline void input_sync(struct input_dev *dev)
+ {
+ input_event(dev, EV_SYN, SYN_REPORT, 0);
+- dev->regs = NULL;
+ }
+
+ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
+@@ -1108,5 +1165,61 @@ static inline void input_set_abs_params(
+
+ extern struct class input_class;
+
++/**
++ * struct ff_device - force-feedback part of an input device
++ * @upload: Called to upload an new effect into device
++ * @erase: Called to erase an effect from device
++ * @playback: Called to request device to start playing specified effect
++ * @set_gain: Called to set specified gain
++ * @set_autocenter: Called to auto-center device
++ * @destroy: called by input core when parent input device is being
++ * destroyed
++ * @private: driver-specific data, will be freed automatically
++ * @ffbit: bitmap of force feedback capabilities truly supported by
++ * device (not emulated like ones in input_dev->ffbit)
++ * @mutex: mutex for serializing access to the device
++ * @max_effects: maximum number of effects supported by device
++ * @effects: pointer to an array of effects currently loaded into device
++ * @effect_owners: array of effect owners; when file handle owning
++ * an effect gets closed the effcet is automatically erased
++ *
++ * Every force-feedback device must implement upload() and playback()
++ * methods; erase() is optional. set_gain() and set_autocenter() need
++ * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
++ * bits.
++ */
++struct ff_device {
++ int (*upload)(struct input_dev *dev, struct ff_effect *effect,
++ struct ff_effect *old);
++ int (*erase)(struct input_dev *dev, int effect_id);
++
++ int (*playback)(struct input_dev *dev, int effect_id, int value);
++ void (*set_gain)(struct input_dev *dev, u16 gain);
++ void (*set_autocenter)(struct input_dev *dev, u16 magnitude);
++
++ void (*destroy)(struct ff_device *);
++
++ void *private;
++
++ unsigned long ffbit[NBITS(FF_MAX)];
++
++ struct mutex mutex;
++
++ int max_effects;
++ struct ff_effect *effects;
++ struct file *effect_owners[];
++};
++
++int input_ff_create(struct input_dev *dev, int max_effects);
++void input_ff_destroy(struct input_dev *dev);
++
++int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
++
++int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file);
++int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
++
++int input_ff_create_memless(struct input_dev *dev, void *data,
++ int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
++
+ #endif
+ #endif
+diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
+index d5afee9..5b83e7b 100644
+--- a/include/linux/interrupt.h
++++ b/include/linux/interrupt.h
+@@ -64,8 +64,10 @@
+ #define SA_TRIGGER_RISING IRQF_TRIGGER_RISING
+ #define SA_TRIGGER_MASK IRQF_TRIGGER_MASK
+
++typedef irqreturn_t (*irq_handler_t)(int, void *);
++
+ struct irqaction {
+- irqreturn_t (*handler)(int, void *, struct pt_regs *);
++ irq_handler_t handler;
+ unsigned long flags;
+ cpumask_t mask;
+ const char *name;
+@@ -75,9 +77,8 @@ struct irqaction {
+ struct proc_dir_entry *dir;
+ };
+
+-extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
+-extern int request_irq(unsigned int,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++extern irqreturn_t no_action(int cpl, void *dev_id);
++extern int request_irq(unsigned int, irq_handler_t handler,
+ unsigned long, const char *, void *);
+ extern void free_irq(unsigned int, void *);
+
+@@ -123,6 +124,14 @@ static inline void disable_irq_nosync_lo
+ #endif
+ }
+
++static inline void disable_irq_nosync_lockdep_irqsave(unsigned int irq, unsigned long *flags)
++{
++ disable_irq_nosync(irq);
++#ifdef CONFIG_LOCKDEP
++ local_irq_save(*flags);
++#endif
++}
++
+ static inline void disable_irq_lockdep(unsigned int irq)
+ {
+ disable_irq(irq);
+@@ -139,6 +148,14 @@ static inline void enable_irq_lockdep(un
+ enable_irq(irq);
+ }
+
++static inline void enable_irq_lockdep_irqrestore(unsigned int irq, unsigned long *flags)
++{
++#ifdef CONFIG_LOCKDEP
++ local_irq_restore(*flags);
++#endif
++ enable_irq(irq);
++}
++
+ /* IRQ wakeup (PM) control: */
+ extern int set_irq_wake(unsigned int irq, unsigned int on);
+
+diff --git a/include/linux/io.h b/include/linux/io.h
+index 420e2fd..81877ea 100644
+--- a/include/linux/io.h
++++ b/include/linux/io.h
+@@ -18,9 +18,41 @@
+ #ifndef _LINUX_IO_H
+ #define _LINUX_IO_H
+
++#include <linux/types.h>
+ #include <asm/io.h>
++#include <asm/page.h>
+
+ void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
+ void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
+
++int ioremap_page_range(unsigned long addr, unsigned long end,
++ unsigned long phys_addr, pgprot_t prot);
++
++/**
++ * check_signature - find BIOS signatures
++ * @io_addr: mmio address to check
++ * @signature: signature block
++ * @length: length of signature
++ *
++ * Perform a signature comparison with the mmio address io_addr. This
++ * address should have been obtained by ioremap.
++ * Returns 1 on a match.
++ */
++
++static inline int check_signature(const volatile void __iomem *io_addr,
++ const unsigned char *signature, int length)
++{
++ int retval = 0;
++ do {
++ if (readb(io_addr) != *signature)
++ goto out;
++ io_addr++;
++ signature++;
++ length--;
++ } while (length);
++ retval = 1;
++out:
++ return retval;
++}
++
+ #endif /* _LINUX_IO_H */
+diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
+index da7c09e..38b286e 100644
+--- a/include/linux/ioc3.h
++++ b/include/linux/ioc3.h
+@@ -63,7 +63,7 @@ struct ioc3_submodule {
+ /* IRQ stuff */
+ unsigned int irq_mask; /* IOC3 IRQ mask, leave clear for Ethernet */
+ int reset_mask; /* non-zero if you want the ioc3.c module to reset interrupts */
+- int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int, struct pt_regs *);
++ int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+ /* private submodule data */
+ void *data; /* assigned by submodule */
+ };
+diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h
+index de73a32..51e2b9f 100644
+--- a/include/linux/ioc4.h
++++ b/include/linux/ioc4.h
+@@ -157,7 +157,7 @@ struct ioc4_driver_data {
+ unsigned long idd_bar0;
+ struct pci_dev *idd_pdev;
+ const struct pci_device_id *idd_pci_id;
+- struct __iomem ioc4_misc_regs *idd_misc_regs;
++ struct ioc4_misc_regs __iomem *idd_misc_regs;
+ unsigned long count_period;
+ void *idd_serial_data;
+ unsigned int idd_variant;
+diff --git a/include/linux/ip.h b/include/linux/ip.h
+index 4b55cf1..ecee9bb 100644
+--- a/include/linux/ip.h
++++ b/include/linux/ip.h
+@@ -57,6 +57,7 @@
+ #define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY)
+ #define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY)
+ #define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT)
++#define IPOPT_CIPSO (6 |IPOPT_CONTROL|IPOPT_COPY)
+ #define IPOPT_RR (7 |IPOPT_CONTROL)
+ #define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY)
+ #define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY)
+@@ -79,6 +80,8 @@
+ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
+ #define IPOPT_TS_PRESPEC 3 /* specified modules only */
+
++#define IPV4_BEET_PHMAXLEN 8
++
+ struct iphdr {
+ #if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 ihl:4,
+@@ -95,7 +98,7 @@ struct iphdr {
+ __be16 frag_off;
+ __u8 ttl;
+ __u8 protocol;
+- __u16 check;
++ __be16 check;
+ __be32 saddr;
+ __be32 daddr;
+ /*The options start here. */
+@@ -104,22 +107,29 @@ struct iphdr {
+ struct ip_auth_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen; /* This one is measured in 32 bit units! */
+- __u16 reserved;
+- __u32 spi;
+- __u32 seq_no; /* Sequence number */
++ __be16 reserved;
++ __be32 spi;
++ __be32 seq_no; /* Sequence number */
+ __u8 auth_data[0]; /* Variable len but >=4. Mind the 64 bit alignment! */
+ };
+
+ struct ip_esp_hdr {
+- __u32 spi;
+- __u32 seq_no; /* Sequence number */
++ __be32 spi;
++ __be32 seq_no; /* Sequence number */
+ __u8 enc_data[0]; /* Variable len but >=8. Mind the 64 bit alignment! */
+ };
+
+ struct ip_comp_hdr {
+ __u8 nexthdr;
+ __u8 flags;
+- __u16 cpi;
++ __be16 cpi;
++};
++
++struct ip_beet_phdr {
++ __u8 nexthdr;
++ __u8 hdrlen;
++ __u8 padlen;
++ __u8 reserved;
+ };
+
+ #endif /* _LINUX_IP_H */
+diff --git a/include/linux/ipc.h b/include/linux/ipc.h
+index b291189..636094c 100644
+--- a/include/linux/ipc.h
++++ b/include/linux/ipc.h
+@@ -51,6 +51,8 @@ struct ipc_perm
+
+ #ifdef __KERNEL__
+
++#include <linux/kref.h>
++
+ #define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
+
+ /* used by in-kernel data structures */
+@@ -68,6 +70,59 @@ struct kern_ipc_perm
+ void *security;
+ };
+
++struct ipc_ids;
++struct ipc_namespace {
++ struct kref kref;
++ struct ipc_ids *ids[3];
++
++ int sem_ctls[4];
++ int used_sems;
++
++ int msg_ctlmax;
++ int msg_ctlmnb;
++ int msg_ctlmni;
++
++ size_t shm_ctlmax;
++ size_t shm_ctlall;
++ int shm_ctlmni;
++ int shm_tot;
++};
++
++extern struct ipc_namespace init_ipc_ns;
++
++#ifdef CONFIG_SYSVIPC
++#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
++#else
++#define INIT_IPC_NS(ns)
++#endif
++
++#ifdef CONFIG_IPC_NS
++extern void free_ipc_ns(struct kref *kref);
++extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
++extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
++#else
++static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk)
++{
++ return 0;
++}
++#endif
++
++static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
++{
++#ifdef CONFIG_IPC_NS
++ if (ns)
++ kref_get(&ns->kref);
++#endif
++ return ns;
++}
++
++static inline void put_ipc_ns(struct ipc_namespace *ns)
++{
++#ifdef CONFIG_IPC_NS
++ kref_put(&ns->kref, free_ipc_ns);
++#endif
++}
++
+ #endif /* __KERNEL__ */
+
+ #endif /* _LINUX_IPC_H */
+diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
+index d09fbea..796ca00 100644
+--- a/include/linux/ipmi.h
++++ b/include/linux/ipmi.h
+@@ -148,6 +148,13 @@ struct ipmi_lan_addr
+ #define IPMI_BMC_CHANNEL 0xf
+ #define IPMI_NUM_CHANNELS 0x10
+
++/*
++ * Used to signify an "all channel" bitmask. This is more than the
++ * actual number of channels because this is used in userland and
++ * will cover us if the number of channels is extended.
++ */
++#define IPMI_CHAN_ALL (~0)
++
+
+ /*
+ * A raw IPMI message without any addressing. This covers both
+@@ -350,18 +357,21 @@ int ipmi_request_supply_msgs(ipmi_user_t
+
+ /*
+ * When commands come in to the SMS, the user can register to receive
+- * them. Only one user can be listening on a specific netfn/cmd pair
++ * them. Only one user can be listening on a specific netfn/cmd/chan tuple
+ * at a time, you will get an EBUSY error if the command is already
+ * registered. If a command is received that does not have a user
+ * registered, the driver will automatically return the proper
+- * error.
++ * error. Channels are specified as a bitfield, use IPMI_CHAN_ALL to
++ * mean all channels.
+ */
+ int ipmi_register_for_cmd(ipmi_user_t user,
+ unsigned char netfn,
+- unsigned char cmd);
++ unsigned char cmd,
++ unsigned int chans);
+ int ipmi_unregister_for_cmd(ipmi_user_t user,
+ unsigned char netfn,
+- unsigned char cmd);
++ unsigned char cmd,
++ unsigned int chans);
+
+ /*
+ * Allow run-to-completion mode to be set for the interface of
+@@ -571,6 +581,36 @@ struct ipmi_cmdspec
+ #define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, \
+ struct ipmi_cmdspec)
+
++/*
++ * Register to get commands from other entities on specific channels.
++ * This way, you can only listen on specific channels, or have messages
++ * from some channels go to one place and other channels to someplace
++ * else. The chans field is a bitmask, (1 << channel) for each channel.
++ * It may be IPMI_CHAN_ALL for all channels.
++ */
++struct ipmi_cmdspec_chans
++{
++ unsigned int netfn;
++ unsigned int cmd;
++ unsigned int chans;
++};
++
++/*
++ * Register to receive a specific command on specific channels. error values:
++ * - EFAULT - an address supplied was invalid.
++ * - EBUSY - One of the netfn/cmd/chans supplied was already in use.
++ * - ENOMEM - could not allocate memory for the entry.
++ */
++#define IPMICTL_REGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 28, \
++ struct ipmi_cmdspec_chans)
++/*
++ * Unregister some netfn/cmd/chans. error values:
++ * - EFAULT - an address supplied was invalid.
++ * - ENOENT - None of the netfn/cmd/chans were found registered for this user.
++ */
++#define IPMICTL_UNREGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 29, \
++ struct ipmi_cmdspec_chans)
++
+ /*
+ * Set whether this interface receives events. Note that the first
+ * user registered for events will get all pending events for the
+diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h
+index d3c5276..d17a630 100644
+--- a/include/linux/ipsec.h
++++ b/include/linux/ipsec.h
+@@ -12,7 +12,8 @@
+ enum {
+ IPSEC_MODE_ANY = 0, /* We do not support this for SA */
+ IPSEC_MODE_TRANSPORT = 1,
+- IPSEC_MODE_TUNNEL = 2
++ IPSEC_MODE_TUNNEL = 2,
++ IPSEC_MODE_BEET = 3
+ };
+
+ enum {
+diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
+index 297853c..4f435c5 100644
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -29,6 +29,7 @@ struct in6_ifreq {
+
+ #define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
+ #define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
++#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */
+
+ /*
+ * routing header
+@@ -73,25 +74,47 @@ struct rt0_hdr {
+ #define rt0_type rt_hdr.type
+ };
+
++/*
++ * routing header type 2
++ */
++
++struct rt2_hdr {
++ struct ipv6_rt_hdr rt_hdr;
++ __u32 reserved;
++ struct in6_addr addr;
++
++#define rt2_type rt_hdr.type
++};
++
++/*
++ * home address option in destination options header
++ */
++
++struct ipv6_destopt_hao {
++ __u8 type;
++ __u8 length;
++ struct in6_addr addr;
++} __attribute__ ((__packed__));
++
+ struct ipv6_auth_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen; /* This one is measured in 32 bit units! */
+- __u16 reserved;
+- __u32 spi;
+- __u32 seq_no; /* Sequence number */
++ __be16 reserved;
++ __be32 spi;
++ __be32 seq_no; /* Sequence number */
+ __u8 auth_data[0]; /* Length variable but >=4. Mind the 64 bit alignment! */
+ };
+
+ struct ipv6_esp_hdr {
+- __u32 spi;
+- __u32 seq_no; /* Sequence number */
++ __be32 spi;
++ __be32 seq_no; /* Sequence number */
+ __u8 enc_data[0]; /* Length variable but >=8. Mind the 64 bit alignment! */
+ };
+
+ struct ipv6_comp_hdr {
+ __u8 nexthdr;
+ __u8 flags;
+- __u16 cpi;
++ __be16 cpi;
+ };
+
+ /*
+@@ -113,7 +136,7 @@ struct ipv6hdr {
+ #endif
+ __u8 flow_lbl[3];
+
+- __u16 payload_len;
++ __be16 payload_len;
+ __u8 nexthdr;
+ __u8 hop_limit;
+
+@@ -153,6 +176,7 @@ struct ipv6_devconf {
+ __s32 accept_ra_rt_info_max_plen;
+ #endif
+ #endif
++ __s32 proxy_ndp;
+ void *sysctl;
+ };
+
+@@ -180,6 +204,7 @@ enum {
+ DEVCONF_ACCEPT_RA_RTR_PREF,
+ DEVCONF_RTR_PROBE_INTERVAL,
+ DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
++ DEVCONF_PROXY_NDP,
+ DEVCONF_MAX
+ };
+
+@@ -206,6 +231,9 @@ struct inet6_skb_parm {
+ __u16 lastopt;
+ __u32 nhoff;
+ __u16 flags;
++#ifdef CONFIG_IPV6_MIP6
++ __u16 dsthao;
++#endif
+
+ #define IP6SKB_XFRM_TRANSFORMED 1
+ };
+@@ -242,6 +270,9 @@ struct ipv6_pinfo {
+ struct in6_addr rcv_saddr;
+ struct in6_addr daddr;
+ struct in6_addr *daddr_cache;
++#ifdef CONFIG_IPV6_SUBTREES
++ struct in6_addr *saddr_cache;
++#endif
+
+ __u32 flow_label;
+ __u32 frag_size;
+@@ -430,7 +461,7 @@ static inline struct raw6_sock *raw6_sk(
+
+ #define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\
+ (((__sk)->sk_hash == (__hash)) && \
+- ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
++ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ ((__sk)->sk_family == AF_INET6) && \
+ ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \
+ ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
+diff --git a/include/linux/ipx.h b/include/linux/ipx.h
+index 4f29c60..eb19b4e 100644
+--- a/include/linux/ipx.h
++++ b/include/linux/ipx.h
+@@ -7,8 +7,8 @@
+
+ struct sockaddr_ipx {
+ sa_family_t sipx_family;
+- __u16 sipx_port;
+- __u32 sipx_network;
++ __be16 sipx_port;
++ __be32 sipx_network;
+ unsigned char sipx_node[IPX_NODE_LEN];
+ __u8 sipx_type;
+ unsigned char sipx_zero; /* 16 byte fill */
+@@ -23,13 +23,13 @@ struct sockaddr_ipx {
+ #define IPX_CRTITF 1
+
+ struct ipx_route_definition {
+- __u32 ipx_network;
+- __u32 ipx_router_network;
++ __be32 ipx_network;
++ __be32 ipx_router_network;
+ unsigned char ipx_router_node[IPX_NODE_LEN];
+ };
+
+ struct ipx_interface_definition {
+- __u32 ipx_network;
++ __be32 ipx_network;
+ unsigned char ipx_device[16];
+ unsigned char ipx_dlink_type;
+ #define IPX_FRAME_NONE 0
+@@ -55,8 +55,8 @@ struct ipx_config_data {
+ */
+
+ struct ipx_route_def {
+- __u32 ipx_network;
+- __u32 ipx_router_network;
++ __be32 ipx_network;
++ __be32 ipx_router_network;
+ #define IPX_ROUTE_NO_ROUTER 0
+ unsigned char ipx_router_node[IPX_NODE_LEN];
+ unsigned char ipx_device[16];
+diff --git a/include/linux/irq.h b/include/linux/irq.h
+index fbf6d90..52fc405 100644
+--- a/include/linux/irq.h
++++ b/include/linux/irq.h
+@@ -21,6 +21,12 @@
+
+ #include <asm/irq.h>
+ #include <asm/ptrace.h>
++#include <asm/irq_regs.h>
++
++struct irq_desc;
++typedef void fastcall (*irq_flow_handler_t)(unsigned int irq,
++ struct irq_desc *desc);
++
+
+ /*
+ * IRQ line status.
+@@ -59,6 +65,7 @@
+ #define IRQ_NOAUTOEN 0x08000000 /* IRQ will not be enabled on request irq */
+ #define IRQ_DELAYED_DISABLE 0x10000000 /* IRQ disable (masking) happens delayed. */
+ #define IRQ_WAKEUP 0x20000000 /* IRQ triggers system wakeup */
++#define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */
+
+ struct proc_dir_entry;
+
+@@ -132,16 +139,14 @@ struct irq_chip {
+ * @affinity: IRQ affinity on SMP
+ * @cpu: cpu index useful for balancing
+ * @pending_mask: pending rebalanced interrupts
+- * @move_irq: need to re-target IRQ destination
+ * @dir: /proc/irq/ procfs entry
+ * @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
++ * @name: flow handler name for /proc/interrupts output
+ *
+ * Pad this out to 32 bytes for cache and indexing reasons.
+ */
+ struct irq_desc {
+- void fastcall (*handle_irq)(unsigned int irq,
+- struct irq_desc *desc,
+- struct pt_regs *regs);
++ irq_flow_handler_t handle_irq;
+ struct irq_chip *chip;
+ void *handler_data;
+ void *chip_data;
+@@ -159,11 +164,11 @@ struct irq_desc {
+ #endif
+ #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+ cpumask_t pending_mask;
+- unsigned int move_irq; /* need to re-target IRQ dest */
+ #endif
+ #ifdef CONFIG_PROC_FS
+- struct proc_dir_entry *dir;
++ struct proc_dir_entry *dir;
+ #endif
++ const char *name;
+ } ____cacheline_aligned;
+
+ extern struct irq_desc irq_desc[NR_IRQS];
+@@ -206,36 +211,7 @@ static inline void set_native_irq_info(i
+
+ void set_pending_irq(unsigned int irq, cpumask_t mask);
+ void move_native_irq(int irq);
+-
+-#ifdef CONFIG_PCI_MSI
+-/*
+- * Wonder why these are dummies?
+- * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq()
+- * counter part after translating the vector to irq info. We need to perform
+- * this operation on the real irq, when we dont use vector, i.e when
+- * pci_use_vector() is false.
+- */
+-static inline void move_irq(int irq)
+-{
+-}
+-
+-static inline void set_irq_info(int irq, cpumask_t mask)
+-{
+-}
+-
+-#else /* CONFIG_PCI_MSI */
+-
+-static inline void move_irq(int irq)
+-{
+- move_native_irq(irq);
+-}
+-
+-static inline void set_irq_info(int irq, cpumask_t mask)
+-{
+- set_native_irq_info(irq, mask);
+-}
+-
+-#endif /* CONFIG_PCI_MSI */
++void move_masked_irq(int irq);
+
+ #else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */
+
+@@ -247,21 +223,20 @@ static inline void move_native_irq(int i
+ {
+ }
+
+-static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
++static inline void move_masked_irq(int irq)
+ {
+ }
+
+-static inline void set_irq_info(int irq, cpumask_t mask)
++static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+ {
+- set_native_irq_info(irq, mask);
+ }
+
+ #endif /* CONFIG_GENERIC_PENDING_IRQ */
+
+ #else /* CONFIG_SMP */
+
+-#define move_irq(x)
+ #define move_native_irq(x)
++#define move_masked_irq(x)
+
+ #endif /* CONFIG_SMP */
+
+@@ -285,42 +260,26 @@ static inline int select_smp_affinity(un
+ extern int no_irq_affinity;
+
+ /* Handle irq action chains: */
+-extern int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+- struct irqaction *action);
++extern int handle_IRQ_event(unsigned int irq, struct irqaction *action);
+
+ /*
+ * Built-in IRQ handlers for various IRQ types,
+ * callable via desc->chip->handle_irq()
+ */
+-extern void fastcall
+-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+-extern void fastcall
+-handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs);
+-extern void fastcall
+-handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+-extern void fastcall
+-handle_simple_irq(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs);
+-extern void fastcall
+-handle_percpu_irq(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs);
+-extern void fastcall
+-handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+-
+-/*
+- * Get a descriptive string for the highlevel handler, for
+- * /proc/interrupts output:
+- */
+-extern const char *
+-handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
+- struct pt_regs *));
++extern void fastcall handle_level_irq(unsigned int irq, struct irq_desc *desc);
++extern void fastcall handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc);
++extern void fastcall handle_edge_irq(unsigned int irq, struct irq_desc *desc);
++extern void fastcall handle_simple_irq(unsigned int irq, struct irq_desc *desc);
++extern void fastcall handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
++extern void fastcall handle_bad_irq(unsigned int irq, struct irq_desc *desc);
+
+ /*
+ * Monolithic do_IRQ implementation.
+ * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly)
+ */
+-extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
++#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
++extern fastcall unsigned int __do_IRQ(unsigned int irq);
++#endif
+
+ /*
+ * Architectures call this to let the generic IRQ layer
+@@ -328,19 +287,23 @@ extern fastcall unsigned int __do_IRQ(un
+ * irqchip-style controller then we call the ->handle_irq() handler,
+ * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
+ */
+-static inline void generic_handle_irq(unsigned int irq, struct pt_regs *regs)
++static inline void generic_handle_irq(unsigned int irq)
+ {
+ struct irq_desc *desc = irq_desc + irq;
+
++#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
++ desc->handle_irq(irq, desc);
++#else
+ if (likely(desc->handle_irq))
+- desc->handle_irq(irq, desc, regs);
++ desc->handle_irq(irq, desc);
+ else
+- __do_IRQ(irq, regs);
++ __do_IRQ(irq);
++#endif
+ }
+
+ /* Handling of unhandled and spurious interrupts: */
+ extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
+- int action_ret, struct pt_regs *regs);
++ int action_ret);
+
+ /* Resending of interrupts :*/
+ void check_irq_resend(struct irq_desc *desc, unsigned int irq);
+@@ -360,24 +323,22 @@ extern struct irq_chip dummy_irq_chip;
+
+ extern void
+ set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+- void fastcall (*handle)(unsigned int,
+- struct irq_desc *,
+- struct pt_regs *));
++ irq_flow_handler_t handle);
+ extern void
+-__set_irq_handler(unsigned int irq,
+- void fastcall (*handle)(unsigned int, struct irq_desc *,
+- struct pt_regs *),
+- int is_chained);
++set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
++ irq_flow_handler_t handle, const char *name);
++
++extern void
++__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
++ const char *name);
+
+ /*
+ * Set a highlevel flow handler for a given IRQ:
+ */
+ static inline void
+-set_irq_handler(unsigned int irq,
+- void fastcall (*handle)(unsigned int, struct irq_desc *,
+- struct pt_regs *))
++set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
+ {
+- __set_irq_handler(irq, handle, 0);
++ __set_irq_handler(irq, handle, 0, NULL);
+ }
+
+ /*
+@@ -387,14 +348,27 @@ set_irq_handler(unsigned int irq,
+ */
+ static inline void
+ set_irq_chained_handler(unsigned int irq,
+- void fastcall (*handle)(unsigned int, struct irq_desc *,
+- struct pt_regs *))
++ irq_flow_handler_t handle)
+ {
+- __set_irq_handler(irq, handle, 1);
++ __set_irq_handler(irq, handle, 1, NULL);
+ }
+
+-/* Set/get chip/data for an IRQ: */
++/* Handle dynamic irq creation and destruction */
++extern int create_irq(void);
++extern void destroy_irq(unsigned int irq);
+
++/* Test to see if a driver has successfully requested an irq */
++static inline int irq_has_action(unsigned int irq)
++{
++ struct irq_desc *desc = irq_desc + irq;
++ return desc->action != NULL;
++}
++
++/* Dynamic irq helper functions */
++extern void dynamic_irq_init(unsigned int irq);
++extern void dynamic_irq_cleanup(unsigned int irq);
++
++/* Set/get chip/data for an IRQ: */
+ extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
+ extern int set_irq_data(unsigned int irq, void *data);
+ extern int set_irq_chip_data(unsigned int irq, void *data);
+diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
+index 4796787..4688ac4 100644
+--- a/include/linux/iso_fs.h
++++ b/include/linux/iso_fs.h
+@@ -2,6 +2,8 @@
+ #define _ISOFS_FS_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
++
+ /*
+ * The isofs filesystem constants/structures
+ */
+@@ -160,6 +162,4 @@ struct iso_directory_record {
+ #define ISOFS_BUFFER_SIZE(INODE) ((INODE)->i_sb->s_blocksize)
+ #define ISOFS_BUFFER_BITS(INODE) ((INODE)->i_sb->s_blocksize_bits)
+
+-#define ISOFS_SUPER_MAGIC 0x9660
+-
+-#endif
++#endif /* _ISOFS_FS_H */
+diff --git a/include/linux/istallion.h b/include/linux/istallion.h
+index 1f99662..b55e2a0 100644
+--- a/include/linux/istallion.h
++++ b/include/linux/istallion.h
+@@ -100,7 +100,7 @@ typedef struct stlibrd {
+ unsigned int iobase;
+ int iosize;
+ unsigned long memaddr;
+- void *membase;
++ void __iomem *membase;
+ int memsize;
+ int pagesize;
+ int hostoffset;
+@@ -113,7 +113,7 @@ typedef struct stlibrd {
+ void (*enable)(struct stlibrd *brdp);
+ void (*reenable)(struct stlibrd *brdp);
+ void (*disable)(struct stlibrd *brdp);
+- char *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
++ void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
+ void (*intr)(struct stlibrd *brdp);
+ void (*reset)(struct stlibrd *brdp);
+ stliport_t *ports[STL_MAXPORTS];
+diff --git a/include/linux/ite_gpio.h b/include/linux/ite_gpio.h
+deleted file mode 100644
+index b123a14..0000000
+--- a/include/linux/ite_gpio.h
++++ /dev/null
+@@ -1,66 +0,0 @@
+-/*
+- * FILE NAME ite_gpio.h
+- *
+- * BRIEF MODULE DESCRIPTION
+- * Generic gpio.
+- *
+- * Author: MontaVista Software, Inc. <source at mvista.com>
+- * Hai-Pao Fan <haipao at mvista.com>
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the
+- * Free Software Foundation; either version 2 of the License, or (at your
+- * option) any later version.
+- *
+- * 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.
+- */
+-
+-#ifndef __ITE_GPIO_H
+-#define __ITE_GPIO_H
+-
+-#include <linux/ioctl.h>
+-
+-struct ite_gpio_ioctl_data {
+- __u32 device;
+- __u32 mask;
+- __u32 data;
+-};
+-
+-#define ITE_GPIO_IOCTL_BASE 'Z'
+-
+-#define ITE_GPIO_IN _IOWR(ITE_GPIO_IOCTL_BASE, 0, struct ite_gpio_ioctl_data)
+-#define ITE_GPIO_OUT _IOW (ITE_GPIO_IOCTL_BASE, 1, struct ite_gpio_ioctl_data)
+-#define ITE_GPIO_INT_CTRL _IOW (ITE_GPIO_IOCTL_BASE, 2, struct ite_gpio_ioctl_data)
+-#define ITE_GPIO_IN_STATUS _IOW (ITE_GPIO_IOCTL_BASE, 3, struct ite_gpio_ioctl_data)
+-#define ITE_GPIO_OUT_STATUS _IOW (ITE_GPIO_IOCTL_BASE, 4, struct ite_gpio_ioctl_data)
+-#define ITE_GPIO_GEN_CTRL _IOW (ITE_GPIO_IOCTL_BASE, 5, struct ite_gpio_ioctl_data)
+-#define ITE_GPIO_INT_WAIT _IOW (ITE_GPIO_IOCTL_BASE, 6, struct ite_gpio_ioctl_data)
+-
+-#define ITE_GPIO_PORTA 0x01
+-#define ITE_GPIO_PORTB 0x02
+-#define ITE_GPIO_PORTC 0x04
+-
+-extern int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data);
+-extern int ite_gpio_out(__u32 device, __u32 mask, __u32 data);
+-extern int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data);
+-extern int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data);
+-extern int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data);
+-extern int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data);
+-extern int ite_gpio_int_wait(__u32 device, __u32 mask, __u32 data);
+-
+-#endif
+diff --git a/include/linux/jbd.h b/include/linux/jbd.h
+index a04c154..fe89444 100644
+--- a/include/linux/jbd.h
++++ b/include/linux/jbd.h
+@@ -1,6 +1,6 @@
+ /*
+ * linux/include/linux/jbd.h
+- *
++ *
+ * Written by Stephen C. Tweedie <sct at redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+@@ -64,7 +64,7 @@ extern int journal_enable_debug;
+ if ((n) <= journal_enable_debug) { \
+ printk (KERN_DEBUG "(%s, %d): %s: ", \
+ __FILE__, __LINE__, __FUNCTION__); \
+- printk (f, ## a); \
++ printk (f, ## a); \
+ } \
+ } while (0)
+ #else
+@@ -97,8 +97,8 @@ extern void jbd_slab_free(void *ptr, siz
+ * number of outstanding buffers possible at any time. When the
+ * operation completes, any buffer credits not used are credited back to
+ * the transaction, so that at all times we know how many buffers the
+- * outstanding updates on a transaction might possibly touch.
+- *
++ * outstanding updates on a transaction might possibly touch.
++ *
+ * This is an opaque datatype.
+ **/
+ typedef struct handle_s handle_t; /* Atomic operation type */
+@@ -108,7 +108,7 @@ typedef struct handle_s handle_t; /* At
+ * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem.
+ *
+ * journal_t is linked to from the fs superblock structure.
+- *
++ *
+ * We use the journal_t to keep track of all outstanding transaction
+ * activity on the filesystem, and to manage the state of the log
+ * writing process.
+@@ -128,7 +128,7 @@ typedef struct journal_s journal_t; /* J
+ * On-disk structures
+ */
+
+-/*
++/*
+ * Descriptor block types:
+ */
+
+@@ -149,8 +149,8 @@ typedef struct journal_header_s
+ } journal_header_t;
+
+
+-/*
+- * The block tag: used to describe a single buffer in the journal
++/*
++ * The block tag: used to describe a single buffer in the journal
+ */
+ typedef struct journal_block_tag_s
+ {
+@@ -158,9 +158,9 @@ typedef struct journal_block_tag_s
+ __be32 t_flags; /* See below */
+ } journal_block_tag_t;
+
+-/*
++/*
+ * The revoke descriptor: used on disk to describe a series of blocks to
+- * be revoked from the log
++ * be revoked from the log
+ */
+ typedef struct journal_revoke_header_s
+ {
+@@ -201,9 +201,9 @@ typedef struct journal_superblock_s
+
+ /* 0x0024 */
+ /* Remaining fields are only valid in a version-2 superblock */
+- __be32 s_feature_compat; /* compatible feature set */
+- __be32 s_feature_incompat; /* incompatible feature set */
+- __be32 s_feature_ro_compat; /* readonly-compatible feature set */
++ __be32 s_feature_compat; /* compatible feature set */
++ __be32 s_feature_incompat; /* incompatible feature set */
++ __be32 s_feature_ro_compat; /* readonly-compatible feature set */
+ /* 0x0030 */
+ __u8 s_uuid[16]; /* 128-bit uuid for journal */
+
+@@ -374,10 +374,10 @@ struct jbd_revoke_table_s;
+ **/
+
+ /* Docbook can't yet cope with the bit fields, but will leave the documentation
+- * in so it can be fixed later.
++ * in so it can be fixed later.
+ */
+
+-struct handle_s
++struct handle_s
+ {
+ /* Which compound transaction is this update a part of? */
+ transaction_t *h_transaction;
+@@ -435,7 +435,7 @@ struct handle_s
+ *
+ */
+
+-struct transaction_s
++struct transaction_s
+ {
+ /* Pointer to the journal for this transaction. [no locking] */
+ journal_t *t_journal;
+@@ -455,7 +455,7 @@ struct transaction_s
+ T_RUNDOWN,
+ T_FLUSH,
+ T_COMMIT,
+- T_FINISHED
++ T_FINISHED
+ } t_state;
+
+ /*
+@@ -569,7 +569,7 @@ struct transaction_s
+ * journal_t.
+ * @j_flags: General journaling state flags
+ * @j_errno: Is there an outstanding uncleared error on the journal (from a
+- * prior abort)?
++ * prior abort)?
+ * @j_sb_buffer: First part of superblock buffer
+ * @j_superblock: Second part of superblock buffer
+ * @j_format_version: Version of the superblock format
+@@ -583,7 +583,7 @@ struct transaction_s
+ * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction
+ * to start committing, or for a barrier lock to be released
+ * @j_wait_logspace: Wait queue for waiting for checkpointing to complete
+- * @j_wait_done_commit: Wait queue for waiting for commit to complete
++ * @j_wait_done_commit: Wait queue for waiting for commit to complete
+ * @j_wait_checkpoint: Wait queue to trigger checkpointing
+ * @j_wait_commit: Wait queue to trigger commit
+ * @j_wait_updates: Wait queue to wait for updates to complete
+@@ -592,7 +592,7 @@ struct transaction_s
+ * @j_tail: Journal tail - identifies the oldest still-used block in the
+ * journal.
+ * @j_free: Journal free - how many free blocks are there in the journal?
+- * @j_first: The block number of the first usable block
++ * @j_first: The block number of the first usable block
+ * @j_last: The block number one beyond the last usable block
+ * @j_dev: Device where we store the journal
+ * @j_blocksize: blocksize for the location where we store the journal.
+@@ -604,12 +604,12 @@ struct transaction_s
+ * @j_list_lock: Protects the buffer lists and internal buffer state.
+ * @j_inode: Optional inode where we store the journal. If present, all journal
+ * block numbers are mapped into this inode via bmap().
+- * @j_tail_sequence: Sequence number of the oldest transaction in the log
++ * @j_tail_sequence: Sequence number of the oldest transaction in the log
+ * @j_transaction_sequence: Sequence number of the next transaction to grant
+ * @j_commit_sequence: Sequence number of the most recently committed
+ * transaction
+ * @j_commit_request: Sequence number of the most recent transaction wanting
+- * commit
++ * commit
+ * @j_uuid: Uuid of client object.
+ * @j_task: Pointer to the current commit thread for this journal
+ * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a
+@@ -699,7 +699,7 @@ struct journal_s
+ wait_queue_head_t j_wait_updates;
+
+ /* Semaphore for locking against concurrent checkpoints */
+- struct mutex j_checkpoint_mutex;
++ struct mutex j_checkpoint_mutex;
+
+ /*
+ * Journal head: identifies the first unused block in the journal.
+@@ -732,7 +732,7 @@ struct journal_s
+ */
+ struct block_device *j_dev;
+ int j_blocksize;
+- unsigned int j_blk_offset;
++ unsigned long j_blk_offset;
+
+ /*
+ * Device which holds the client fs. For internal journal this will be
+@@ -823,8 +823,8 @@ struct journal_s
+ void *j_private;
+ };
+
+-/*
+- * Journal flag definitions
++/*
++ * Journal flag definitions
+ */
+ #define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */
+ #define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */
+@@ -833,7 +833,7 @@ struct journal_s
+ #define JFS_LOADED 0x010 /* The journal superblock has been loaded */
+ #define JFS_BARRIER 0x020 /* Use IDE barriers */
+
+-/*
++/*
+ * Function declarations for the journaling transaction and buffer
+ * management
+ */
+@@ -862,11 +862,11 @@ int __journal_remove_checkpoint(struct j
+ void __journal_insert_checkpoint(struct journal_head *, transaction_t *);
+
+ /* Buffer IO */
+-extern int
++extern int
+ journal_write_metadata_buffer(transaction_t *transaction,
+ struct journal_head *jh_in,
+ struct journal_head **jh_out,
+- int blocknr);
++ unsigned long blocknr);
+
+ /* Transaction locking */
+ extern void __wait_on_journal (journal_t *);
+@@ -890,7 +890,7 @@ static inline handle_t *journal_current_
+ /* The journaling code user interface:
+ *
+ * Create and destroy handles
+- * Register buffer modifications against the current transaction.
++ * Register buffer modifications against the current transaction.
+ */
+
+ extern handle_t *journal_start(journal_t *, int nblocks);
+@@ -917,11 +917,11 @@ extern journal_t * journal_init_dev(stru
+ int start, int len, int bsize);
+ extern journal_t * journal_init_inode (struct inode *);
+ extern int journal_update_format (journal_t *);
+-extern int journal_check_used_features
++extern int journal_check_used_features
+ (journal_t *, unsigned long, unsigned long, unsigned long);
+-extern int journal_check_available_features
++extern int journal_check_available_features
+ (journal_t *, unsigned long, unsigned long, unsigned long);
+-extern int journal_set_features
++extern int journal_set_features
+ (journal_t *, unsigned long, unsigned long, unsigned long);
+ extern int journal_create (journal_t *);
+ extern int journal_load (journal_t *journal);
+@@ -977,7 +977,6 @@ extern void journal_write_revoke_reco
+ extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
+ extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
+ extern void journal_clear_revoke(journal_t *);
+-extern void journal_brelse_array(struct buffer_head *b[], int n);
+ extern void journal_switch_revoke_table(journal_t *journal);
+
+ /*
+@@ -1015,7 +1014,7 @@ do { \
+ * bit, when set, indicates that we have had a fatal error somewhere,
+ * either inside the journaling layer or indicated to us by the client
+ * (eg. ext3), and that we and should not commit any further
+- * transactions.
++ * transactions.
+ */
+
+ static inline int is_journal_aborted(journal_t *journal)
+@@ -1082,7 +1081,7 @@ static inline int jbd_space_needed(journ
+ #define BJ_Reserved 7 /* Buffer is reserved for access by journal */
+ #define BJ_Locked 8 /* Locked for I/O during commit */
+ #define BJ_Types 9
+-
++
+ extern int jbd_blocks_per_page(struct inode *inode);
+
+ #ifdef __KERNEL__
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+new file mode 100644
+index 0000000..ddb1287
+--- /dev/null
++++ b/include/linux/jbd2.h
+@@ -0,0 +1,1107 @@
++/*
++ * linux/include/linux/jbd2.h
++ *
++ * Written by Stephen C. Tweedie <sct at redhat.com>
++ *
++ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Definitions for transaction data structures for the buffer cache
++ * filesystem journaling support.
++ */
++
++#ifndef _LINUX_JBD_H
++#define _LINUX_JBD_H
++
++/* Allow this file to be included directly into e2fsprogs */
++#ifndef __KERNEL__
++#include "jfs_compat.h"
++#define JBD2_DEBUG
++#define jfs_debug jbd_debug
++#else
++
++#include <linux/types.h>
++#include <linux/buffer_head.h>
++#include <linux/journal-head.h>
++#include <linux/stddef.h>
++#include <linux/bit_spinlock.h>
++#include <linux/mutex.h>
++#include <linux/timer.h>
++
++#include <asm/semaphore.h>
++#endif
++
++#define journal_oom_retry 1
++
++/*
++ * Define JBD_PARANIOD_IOFAIL to cause a kernel BUG() if ext3 finds
++ * certain classes of error which can occur due to failed IOs. Under
++ * normal use we want ext3 to continue after such errors, because
++ * hardware _can_ fail, but for debugging purposes when running tests on
++ * known-good hardware we may want to trap these errors.
++ */
++#undef JBD_PARANOID_IOFAIL
++
++/*
++ * The default maximum commit age, in seconds.
++ */
++#define JBD_DEFAULT_MAX_COMMIT_AGE 5
++
++#ifdef CONFIG_JBD_DEBUG
++/*
++ * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
++ * consistency checks. By default we don't do this unless
++ * CONFIG_JBD_DEBUG is on.
++ */
++#define JBD_EXPENSIVE_CHECKING
++extern int jbd2_journal_enable_debug;
++
++#define jbd_debug(n, f, a...) \
++ do { \
++ if ((n) <= jbd2_journal_enable_debug) { \
++ printk (KERN_DEBUG "(%s, %d): %s: ", \
++ __FILE__, __LINE__, __FUNCTION__); \
++ printk (f, ## a); \
++ } \
++ } while (0)
++#else
++#define jbd_debug(f, a...) /**/
++#endif
++
++extern void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry);
++extern void * jbd2_slab_alloc(size_t size, gfp_t flags);
++extern void jbd2_slab_free(void *ptr, size_t size);
++
++#define jbd_kmalloc(size, flags) \
++ __jbd2_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
++#define jbd_rep_kmalloc(size, flags) \
++ __jbd2_kmalloc(__FUNCTION__, (size), (flags), 1)
++
++#define JBD2_MIN_JOURNAL_BLOCKS 1024
++
++#ifdef __KERNEL__
++
++/**
++ * typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
++ *
++ * All filesystem modifications made by the process go
++ * through this handle. Recursive operations (such as quota operations)
++ * are gathered into a single update.
++ *
++ * The buffer credits field is used to account for journaled buffers
++ * being modified by the running process. To ensure that there is
++ * enough log space for all outstanding operations, we need to limit the
++ * number of outstanding buffers possible at any time. When the
++ * operation completes, any buffer credits not used are credited back to
++ * the transaction, so that at all times we know how many buffers the
++ * outstanding updates on a transaction might possibly touch.
++ *
++ * This is an opaque datatype.
++ **/
++typedef struct handle_s handle_t; /* Atomic operation type */
++
++
++/**
++ * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem.
++ *
++ * journal_t is linked to from the fs superblock structure.
++ *
++ * We use the journal_t to keep track of all outstanding transaction
++ * activity on the filesystem, and to manage the state of the log
++ * writing process.
++ *
++ * This is an opaque datatype.
++ **/
++typedef struct journal_s journal_t; /* Journal control structure */
++#endif
++
++/*
++ * Internal structures used by the logging mechanism:
++ */
++
++#define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
++
++/*
++ * On-disk structures
++ */
++
++/*
++ * Descriptor block types:
++ */
++
++#define JBD2_DESCRIPTOR_BLOCK 1
++#define JBD2_COMMIT_BLOCK 2
++#define JBD2_SUPERBLOCK_V1 3
++#define JBD2_SUPERBLOCK_V2 4
++#define JBD2_REVOKE_BLOCK 5
++
++/*
++ * Standard header for all descriptor blocks:
++ */
++typedef struct journal_header_s
++{
++ __be32 h_magic;
++ __be32 h_blocktype;
++ __be32 h_sequence;
++} journal_header_t;
++
++
++/*
++ * The block tag: used to describe a single buffer in the journal.
++ * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this
++ * raw struct shouldn't be used for pointer math or sizeof() - use
++ * journal_tag_bytes(journal) instead to compute this.
++ */
++typedef struct journal_block_tag_s
++{
++ __be32 t_blocknr; /* The on-disk block number */
++ __be32 t_flags; /* See below */
++ __be32 t_blocknr_high; /* most-significant high 32bits. */
++} journal_block_tag_t;
++
++#define JBD_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high))
++#define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t))
++
++/*
++ * The revoke descriptor: used on disk to describe a series of blocks to
++ * be revoked from the log
++ */
++typedef struct jbd2_journal_revoke_header_s
++{
++ journal_header_t r_header;
++ __be32 r_count; /* Count of bytes used in the block */
++} jbd2_journal_revoke_header_t;
++
++
++/* Definitions for the journal tag flags word: */
++#define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */
++#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */
++#define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */
++#define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
++
++
++/*
++ * The journal superblock. All fields are in big-endian byte order.
++ */
++typedef struct journal_superblock_s
++{
++/* 0x0000 */
++ journal_header_t s_header;
++
++/* 0x000C */
++ /* Static information describing the journal */
++ __be32 s_blocksize; /* journal device blocksize */
++ __be32 s_maxlen; /* total blocks in journal file */
++ __be32 s_first; /* first block of log information */
++
++/* 0x0018 */
++ /* Dynamic information describing the current state of the log */
++ __be32 s_sequence; /* first commit ID expected in log */
++ __be32 s_start; /* blocknr of start of log */
++
++/* 0x0020 */
++ /* Error value, as set by jbd2_journal_abort(). */
++ __be32 s_errno;
++
++/* 0x0024 */
++ /* Remaining fields are only valid in a version-2 superblock */
++ __be32 s_feature_compat; /* compatible feature set */
++ __be32 s_feature_incompat; /* incompatible feature set */
++ __be32 s_feature_ro_compat; /* readonly-compatible feature set */
++/* 0x0030 */
++ __u8 s_uuid[16]; /* 128-bit uuid for journal */
++
++/* 0x0040 */
++ __be32 s_nr_users; /* Nr of filesystems sharing log */
++
++ __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
++
++/* 0x0048 */
++ __be32 s_max_transaction; /* Limit of journal blocks per trans.*/
++ __be32 s_max_trans_data; /* Limit of data blocks per trans. */
++
++/* 0x0050 */
++ __u32 s_padding[44];
++
++/* 0x0100 */
++ __u8 s_users[16*48]; /* ids of all fs'es sharing the log */
++/* 0x0400 */
++} journal_superblock_t;
++
++#define JBD2_HAS_COMPAT_FEATURE(j,mask) \
++ ((j)->j_format_version >= 2 && \
++ ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
++#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask) \
++ ((j)->j_format_version >= 2 && \
++ ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
++#define JBD2_HAS_INCOMPAT_FEATURE(j,mask) \
++ ((j)->j_format_version >= 2 && \
++ ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
++
++#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
++#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
++
++/* Features known to this kernel version: */
++#define JBD2_KNOWN_COMPAT_FEATURES 0
++#define JBD2_KNOWN_ROCOMPAT_FEATURES 0
++#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \
++ JBD2_FEATURE_INCOMPAT_64BIT)
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/sched.h>
++
++#define JBD_ASSERTIONS
++#ifdef JBD_ASSERTIONS
++#define J_ASSERT(assert) \
++do { \
++ if (!(assert)) { \
++ printk (KERN_EMERG \
++ "Assertion failure in %s() at %s:%d: \"%s\"\n", \
++ __FUNCTION__, __FILE__, __LINE__, # assert); \
++ BUG(); \
++ } \
++} while (0)
++
++#if defined(CONFIG_BUFFER_DEBUG)
++void buffer_assertion_failure(struct buffer_head *bh);
++#define J_ASSERT_BH(bh, expr) \
++ do { \
++ if (!(expr)) \
++ buffer_assertion_failure(bh); \
++ J_ASSERT(expr); \
++ } while (0)
++#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr)
++#else
++#define J_ASSERT_BH(bh, expr) J_ASSERT(expr)
++#define J_ASSERT_JH(jh, expr) J_ASSERT(expr)
++#endif
++
++#else
++#define J_ASSERT(assert) do { } while (0)
++#endif /* JBD_ASSERTIONS */
++
++#if defined(JBD_PARANOID_IOFAIL)
++#define J_EXPECT(expr, why...) J_ASSERT(expr)
++#define J_EXPECT_BH(bh, expr, why...) J_ASSERT_BH(bh, expr)
++#define J_EXPECT_JH(jh, expr, why...) J_ASSERT_JH(jh, expr)
++#else
++#define __journal_expect(expr, why...) \
++ ({ \
++ int val = (expr); \
++ if (!val) { \
++ printk(KERN_ERR \
++ "EXT3-fs unexpected failure: %s;\n",# expr); \
++ printk(KERN_ERR why "\n"); \
++ } \
++ val; \
++ })
++#define J_EXPECT(expr, why...) __journal_expect(expr, ## why)
++#define J_EXPECT_BH(bh, expr, why...) __journal_expect(expr, ## why)
++#define J_EXPECT_JH(jh, expr, why...) __journal_expect(expr, ## why)
++#endif
++
++enum jbd_state_bits {
++ BH_JBD /* Has an attached ext3 journal_head */
++ = BH_PrivateStart,
++ BH_JWrite, /* Being written to log (@@@ DEBUGGING) */
++ BH_Freed, /* Has been freed (truncated) */
++ BH_Revoked, /* Has been revoked from the log */
++ BH_RevokeValid, /* Revoked flag is valid */
++ BH_JBDDirty, /* Is dirty but journaled */
++ BH_State, /* Pins most journal_head state */
++ BH_JournalHead, /* Pins bh->b_private and jh->b_bh */
++ BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */
++};
++
++BUFFER_FNS(JBD, jbd)
++BUFFER_FNS(JWrite, jwrite)
++BUFFER_FNS(JBDDirty, jbddirty)
++TAS_BUFFER_FNS(JBDDirty, jbddirty)
++BUFFER_FNS(Revoked, revoked)
++TAS_BUFFER_FNS(Revoked, revoked)
++BUFFER_FNS(RevokeValid, revokevalid)
++TAS_BUFFER_FNS(RevokeValid, revokevalid)
++BUFFER_FNS(Freed, freed)
++
++static inline struct buffer_head *jh2bh(struct journal_head *jh)
++{
++ return jh->b_bh;
++}
++
++static inline struct journal_head *bh2jh(struct buffer_head *bh)
++{
++ return bh->b_private;
++}
++
++static inline void jbd_lock_bh_state(struct buffer_head *bh)
++{
++ bit_spin_lock(BH_State, &bh->b_state);
++}
++
++static inline int jbd_trylock_bh_state(struct buffer_head *bh)
++{
++ return bit_spin_trylock(BH_State, &bh->b_state);
++}
++
++static inline int jbd_is_locked_bh_state(struct buffer_head *bh)
++{
++ return bit_spin_is_locked(BH_State, &bh->b_state);
++}
++
++static inline void jbd_unlock_bh_state(struct buffer_head *bh)
++{
++ bit_spin_unlock(BH_State, &bh->b_state);
++}
++
++static inline void jbd_lock_bh_journal_head(struct buffer_head *bh)
++{
++ bit_spin_lock(BH_JournalHead, &bh->b_state);
++}
++
++static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh)
++{
++ bit_spin_unlock(BH_JournalHead, &bh->b_state);
++}
++
++struct jbd2_revoke_table_s;
++
++/**
++ * struct handle_s - The handle_s type is the concrete type associated with
++ * handle_t.
++ * @h_transaction: Which compound transaction is this update a part of?
++ * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
++ * @h_ref: Reference count on this handle
++ * @h_err: Field for caller's use to track errors through large fs operations
++ * @h_sync: flag for sync-on-close
++ * @h_jdata: flag to force data journaling
++ * @h_aborted: flag indicating fatal error on handle
++ **/
++
++/* Docbook can't yet cope with the bit fields, but will leave the documentation
++ * in so it can be fixed later.
++ */
++
++struct handle_s
++{
++ /* Which compound transaction is this update a part of? */
++ transaction_t *h_transaction;
++
++ /* Number of remaining buffers we are allowed to dirty: */
++ int h_buffer_credits;
++
++ /* Reference count on this handle */
++ int h_ref;
++
++ /* Field for caller's use to track errors through large fs */
++ /* operations */
++ int h_err;
++
++ /* Flags [no locking] */
++ unsigned int h_sync: 1; /* sync-on-close */
++ unsigned int h_jdata: 1; /* force data journaling */
++ unsigned int h_aborted: 1; /* fatal error on handle */
++};
++
++
++/* The transaction_t type is the guts of the journaling mechanism. It
++ * tracks a compound transaction through its various states:
++ *
++ * RUNNING: accepting new updates
++ * LOCKED: Updates still running but we don't accept new ones
++ * RUNDOWN: Updates are tidying up but have finished requesting
++ * new buffers to modify (state not used for now)
++ * FLUSH: All updates complete, but we are still writing to disk
++ * COMMIT: All data on disk, writing commit record
++ * FINISHED: We still have to keep the transaction for checkpointing.
++ *
++ * The transaction keeps track of all of the buffers modified by a
++ * running transaction, and all of the buffers committed but not yet
++ * flushed to home for finished transactions.
++ */
++
++/*
++ * Lock ranking:
++ *
++ * j_list_lock
++ * ->jbd_lock_bh_journal_head() (This is "innermost")
++ *
++ * j_state_lock
++ * ->jbd_lock_bh_state()
++ *
++ * jbd_lock_bh_state()
++ * ->j_list_lock
++ *
++ * j_state_lock
++ * ->t_handle_lock
++ *
++ * j_state_lock
++ * ->j_list_lock (journal_unmap_buffer)
++ *
++ */
++
++struct transaction_s
++{
++ /* Pointer to the journal for this transaction. [no locking] */
++ journal_t *t_journal;
++
++ /* Sequence number for this transaction [no locking] */
++ tid_t t_tid;
++
++ /*
++ * Transaction's current state
++ * [no locking - only kjournald2 alters this]
++ * FIXME: needs barriers
++ * KLUDGE: [use j_state_lock]
++ */
++ enum {
++ T_RUNNING,
++ T_LOCKED,
++ T_RUNDOWN,
++ T_FLUSH,
++ T_COMMIT,
++ T_FINISHED
++ } t_state;
++
++ /*
++ * Where in the log does this transaction's commit start? [no locking]
++ */
++ unsigned long t_log_start;
++
++ /* Number of buffers on the t_buffers list [j_list_lock] */
++ int t_nr_buffers;
++
++ /*
++ * Doubly-linked circular list of all buffers reserved but not yet
++ * modified by this transaction [j_list_lock]
++ */
++ struct journal_head *t_reserved_list;
++
++ /*
++ * Doubly-linked circular list of all buffers under writeout during
++ * commit [j_list_lock]
++ */
++ struct journal_head *t_locked_list;
++
++ /*
++ * Doubly-linked circular list of all metadata buffers owned by this
++ * transaction [j_list_lock]
++ */
++ struct journal_head *t_buffers;
++
++ /*
++ * Doubly-linked circular list of all data buffers still to be
++ * flushed before this transaction can be committed [j_list_lock]
++ */
++ struct journal_head *t_sync_datalist;
++
++ /*
++ * Doubly-linked circular list of all forget buffers (superseded
++ * buffers which we can un-checkpoint once this transaction commits)
++ * [j_list_lock]
++ */
++ struct journal_head *t_forget;
++
++ /*
++ * Doubly-linked circular list of all buffers still to be flushed before
++ * this transaction can be checkpointed. [j_list_lock]
++ */
++ struct journal_head *t_checkpoint_list;
++
++ /*
++ * Doubly-linked circular list of all buffers submitted for IO while
++ * checkpointing. [j_list_lock]
++ */
++ struct journal_head *t_checkpoint_io_list;
++
++ /*
++ * Doubly-linked circular list of temporary buffers currently undergoing
++ * IO in the log [j_list_lock]
++ */
++ struct journal_head *t_iobuf_list;
++
++ /*
++ * Doubly-linked circular list of metadata buffers being shadowed by log
++ * IO. The IO buffers on the iobuf list and the shadow buffers on this
++ * list match each other one for one at all times. [j_list_lock]
++ */
++ struct journal_head *t_shadow_list;
++
++ /*
++ * Doubly-linked circular list of control buffers being written to the
++ * log. [j_list_lock]
++ */
++ struct journal_head *t_log_list;
++
++ /*
++ * Protects info related to handles
++ */
++ spinlock_t t_handle_lock;
++
++ /*
++ * Number of outstanding updates running on this transaction
++ * [t_handle_lock]
++ */
++ int t_updates;
++
++ /*
++ * Number of buffers reserved for use by all handles in this transaction
++ * handle but not yet modified. [t_handle_lock]
++ */
++ int t_outstanding_credits;
++
++ /*
++ * Forward and backward links for the circular list of all transactions
++ * awaiting checkpoint. [j_list_lock]
++ */
++ transaction_t *t_cpnext, *t_cpprev;
++
++ /*
++ * When will the transaction expire (become due for commit), in jiffies?
++ * [no locking]
++ */
++ unsigned long t_expires;
++
++ /*
++ * How many handles used this transaction? [t_handle_lock]
++ */
++ int t_handle_count;
++
++};
++
++/**
++ * struct journal_s - The journal_s type is the concrete type associated with
++ * journal_t.
++ * @j_flags: General journaling state flags
++ * @j_errno: Is there an outstanding uncleared error on the journal (from a
++ * prior abort)?
++ * @j_sb_buffer: First part of superblock buffer
++ * @j_superblock: Second part of superblock buffer
++ * @j_format_version: Version of the superblock format
++ * @j_state_lock: Protect the various scalars in the journal
++ * @j_barrier_count: Number of processes waiting to create a barrier lock
++ * @j_barrier: The barrier lock itself
++ * @j_running_transaction: The current running transaction..
++ * @j_committing_transaction: the transaction we are pushing to disk
++ * @j_checkpoint_transactions: a linked circular list of all transactions
++ * waiting for checkpointing
++ * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction
++ * to start committing, or for a barrier lock to be released
++ * @j_wait_logspace: Wait queue for waiting for checkpointing to complete
++ * @j_wait_done_commit: Wait queue for waiting for commit to complete
++ * @j_wait_checkpoint: Wait queue to trigger checkpointing
++ * @j_wait_commit: Wait queue to trigger commit
++ * @j_wait_updates: Wait queue to wait for updates to complete
++ * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints
++ * @j_head: Journal head - identifies the first unused block in the journal
++ * @j_tail: Journal tail - identifies the oldest still-used block in the
++ * journal.
++ * @j_free: Journal free - how many free blocks are there in the journal?
++ * @j_first: The block number of the first usable block
++ * @j_last: The block number one beyond the last usable block
++ * @j_dev: Device where we store the journal
++ * @j_blocksize: blocksize for the location where we store the journal.
++ * @j_blk_offset: starting block offset for into the device where we store the
++ * journal
++ * @j_fs_dev: Device which holds the client fs. For internal journal this will
++ * be equal to j_dev
++ * @j_maxlen: Total maximum capacity of the journal region on disk.
++ * @j_list_lock: Protects the buffer lists and internal buffer state.
++ * @j_inode: Optional inode where we store the journal. If present, all journal
++ * block numbers are mapped into this inode via bmap().
++ * @j_tail_sequence: Sequence number of the oldest transaction in the log
++ * @j_transaction_sequence: Sequence number of the next transaction to grant
++ * @j_commit_sequence: Sequence number of the most recently committed
++ * transaction
++ * @j_commit_request: Sequence number of the most recent transaction wanting
++ * commit
++ * @j_uuid: Uuid of client object.
++ * @j_task: Pointer to the current commit thread for this journal
++ * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a
++ * single compound commit transaction
++ * @j_commit_interval: What is the maximum transaction lifetime before we begin
++ * a commit?
++ * @j_commit_timer: The timer used to wakeup the commit thread
++ * @j_revoke_lock: Protect the revoke table
++ * @j_revoke: The revoke table - maintains the list of revoked blocks in the
++ * current transaction.
++ * @j_revoke_table: alternate revoke tables for j_revoke
++ * @j_wbuf: array of buffer_heads for jbd2_journal_commit_transaction
++ * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the
++ * number that will fit in j_blocksize
++ * @j_last_sync_writer: most recent pid which did a synchronous write
++ * @j_private: An opaque pointer to fs-private information.
++ */
++
++struct journal_s
++{
++ /* General journaling state flags [j_state_lock] */
++ unsigned long j_flags;
++
++ /*
++ * Is there an outstanding uncleared error on the journal (from a prior
++ * abort)? [j_state_lock]
++ */
++ int j_errno;
++
++ /* The superblock buffer */
++ struct buffer_head *j_sb_buffer;
++ journal_superblock_t *j_superblock;
++
++ /* Version of the superblock format */
++ int j_format_version;
++
++ /*
++ * Protect the various scalars in the journal
++ */
++ spinlock_t j_state_lock;
++
++ /*
++ * Number of processes waiting to create a barrier lock [j_state_lock]
++ */
++ int j_barrier_count;
++
++ /* The barrier lock itself */
++ struct mutex j_barrier;
++
++ /*
++ * Transactions: The current running transaction...
++ * [j_state_lock] [caller holding open handle]
++ */
++ transaction_t *j_running_transaction;
++
++ /*
++ * the transaction we are pushing to disk
++ * [j_state_lock] [caller holding open handle]
++ */
++ transaction_t *j_committing_transaction;
++
++ /*
++ * ... and a linked circular list of all transactions waiting for
++ * checkpointing. [j_list_lock]
++ */
++ transaction_t *j_checkpoint_transactions;
++
++ /*
++ * Wait queue for waiting for a locked transaction to start committing,
++ * or for a barrier lock to be released
++ */
++ wait_queue_head_t j_wait_transaction_locked;
++
++ /* Wait queue for waiting for checkpointing to complete */
++ wait_queue_head_t j_wait_logspace;
++
++ /* Wait queue for waiting for commit to complete */
++ wait_queue_head_t j_wait_done_commit;
++
++ /* Wait queue to trigger checkpointing */
++ wait_queue_head_t j_wait_checkpoint;
++
++ /* Wait queue to trigger commit */
++ wait_queue_head_t j_wait_commit;
++
++ /* Wait queue to wait for updates to complete */
++ wait_queue_head_t j_wait_updates;
++
++ /* Semaphore for locking against concurrent checkpoints */
++ struct mutex j_checkpoint_mutex;
++
++ /*
++ * Journal head: identifies the first unused block in the journal.
++ * [j_state_lock]
++ */
++ unsigned long j_head;
++
++ /*
++ * Journal tail: identifies the oldest still-used block in the journal.
++ * [j_state_lock]
++ */
++ unsigned long j_tail;
++
++ /*
++ * Journal free: how many free blocks are there in the journal?
++ * [j_state_lock]
++ */
++ unsigned long j_free;
++
++ /*
++ * Journal start and end: the block numbers of the first usable block
++ * and one beyond the last usable block in the journal. [j_state_lock]
++ */
++ unsigned long j_first;
++ unsigned long j_last;
++
++ /*
++ * Device, blocksize and starting block offset for the location where we
++ * store the journal.
++ */
++ struct block_device *j_dev;
++ int j_blocksize;
++ unsigned long long j_blk_offset;
++
++ /*
++ * Device which holds the client fs. For internal journal this will be
++ * equal to j_dev.
++ */
++ struct block_device *j_fs_dev;
++
++ /* Total maximum capacity of the journal region on disk. */
++ unsigned int j_maxlen;
++
++ /*
++ * Protects the buffer lists and internal buffer state.
++ */
++ spinlock_t j_list_lock;
++
++ /* Optional inode where we store the journal. If present, all */
++ /* journal block numbers are mapped into this inode via */
++ /* bmap(). */
++ struct inode *j_inode;
++
++ /*
++ * Sequence number of the oldest transaction in the log [j_state_lock]
++ */
++ tid_t j_tail_sequence;
++
++ /*
++ * Sequence number of the next transaction to grant [j_state_lock]
++ */
++ tid_t j_transaction_sequence;
++
++ /*
++ * Sequence number of the most recently committed transaction
++ * [j_state_lock].
++ */
++ tid_t j_commit_sequence;
++
++ /*
++ * Sequence number of the most recent transaction wanting commit
++ * [j_state_lock]
++ */
++ tid_t j_commit_request;
++
++ /*
++ * Journal uuid: identifies the object (filesystem, LVM volume etc)
++ * backed by this journal. This will eventually be replaced by an array
++ * of uuids, allowing us to index multiple devices within a single
++ * journal and to perform atomic updates across them.
++ */
++ __u8 j_uuid[16];
++
++ /* Pointer to the current commit thread for this journal */
++ struct task_struct *j_task;
++
++ /*
++ * Maximum number of metadata buffers to allow in a single compound
++ * commit transaction
++ */
++ int j_max_transaction_buffers;
++
++ /*
++ * What is the maximum transaction lifetime before we begin a commit?
++ */
++ unsigned long j_commit_interval;
++
++ /* The timer used to wakeup the commit thread: */
++ struct timer_list j_commit_timer;
++
++ /*
++ * The revoke table: maintains the list of revoked blocks in the
++ * current transaction. [j_revoke_lock]
++ */
++ spinlock_t j_revoke_lock;
++ struct jbd2_revoke_table_s *j_revoke;
++ struct jbd2_revoke_table_s *j_revoke_table[2];
++
++ /*
++ * array of bhs for jbd2_journal_commit_transaction
++ */
++ struct buffer_head **j_wbuf;
++ int j_wbufsize;
++
++ pid_t j_last_sync_writer;
++
++ /*
++ * An opaque pointer to fs-private information. ext3 puts its
++ * superblock pointer here
++ */
++ void *j_private;
++};
++
++/*
++ * Journal flag definitions
++ */
++#define JBD2_UNMOUNT 0x001 /* Journal thread is being destroyed */
++#define JBD2_ABORT 0x002 /* Journaling has been aborted for errors. */
++#define JBD2_ACK_ERR 0x004 /* The errno in the sb has been acked */
++#define JBD2_FLUSHED 0x008 /* The journal superblock has been flushed */
++#define JBD2_LOADED 0x010 /* The journal superblock has been loaded */
++#define JBD2_BARRIER 0x020 /* Use IDE barriers */
++
++/*
++ * Function declarations for the journaling transaction and buffer
++ * management
++ */
++
++/* Filing buffers */
++extern void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
++extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *);
++extern void __jbd2_journal_unfile_buffer(struct journal_head *);
++extern void __jbd2_journal_refile_buffer(struct journal_head *);
++extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *);
++extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
++extern void __journal_free_buffer(struct journal_head *bh);
++extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
++extern void __journal_clean_data_list(transaction_t *transaction);
++
++/* Log buffer allocation */
++extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *);
++int jbd2_journal_next_log_block(journal_t *, unsigned long long *);
++
++/* Commit management */
++extern void jbd2_journal_commit_transaction(journal_t *);
++
++/* Checkpoint list management */
++int __jbd2_journal_clean_checkpoint_list(journal_t *journal);
++int __jbd2_journal_remove_checkpoint(struct journal_head *);
++void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
++
++/* Buffer IO */
++extern int
++jbd2_journal_write_metadata_buffer(transaction_t *transaction,
++ struct journal_head *jh_in,
++ struct journal_head **jh_out,
++ unsigned long long blocknr);
++
++/* Transaction locking */
++extern void __wait_on_journal (journal_t *);
++
++/*
++ * Journal locking.
++ *
++ * We need to lock the journal during transaction state changes so that nobody
++ * ever tries to take a handle on the running transaction while we are in the
++ * middle of moving it to the commit phase. j_state_lock does this.
++ *
++ * Note that the locking is completely interrupt unsafe. We never touch
++ * journal structures from interrupts.
++ */
++
++static inline handle_t *journal_current_handle(void)
++{
++ return current->journal_info;
++}
++
++/* The journaling code user interface:
++ *
++ * Create and destroy handles
++ * Register buffer modifications against the current transaction.
++ */
++
++extern handle_t *jbd2_journal_start(journal_t *, int nblocks);
++extern int jbd2_journal_restart (handle_t *, int nblocks);
++extern int jbd2_journal_extend (handle_t *, int nblocks);
++extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *);
++extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *);
++extern int jbd2_journal_get_undo_access(handle_t *, struct buffer_head *);
++extern int jbd2_journal_dirty_data (handle_t *, struct buffer_head *);
++extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *);
++extern void jbd2_journal_release_buffer (handle_t *, struct buffer_head *);
++extern int jbd2_journal_forget (handle_t *, struct buffer_head *);
++extern void journal_sync_buffer (struct buffer_head *);
++extern void jbd2_journal_invalidatepage(journal_t *,
++ struct page *, unsigned long);
++extern int jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t);
++extern int jbd2_journal_stop(handle_t *);
++extern int jbd2_journal_flush (journal_t *);
++extern void jbd2_journal_lock_updates (journal_t *);
++extern void jbd2_journal_unlock_updates (journal_t *);
++
++extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
++ struct block_device *fs_dev,
++ unsigned long long start, int len, int bsize);
++extern journal_t * jbd2_journal_init_inode (struct inode *);
++extern int jbd2_journal_update_format (journal_t *);
++extern int jbd2_journal_check_used_features
++ (journal_t *, unsigned long, unsigned long, unsigned long);
++extern int jbd2_journal_check_available_features
++ (journal_t *, unsigned long, unsigned long, unsigned long);
++extern int jbd2_journal_set_features
++ (journal_t *, unsigned long, unsigned long, unsigned long);
++extern int jbd2_journal_create (journal_t *);
++extern int jbd2_journal_load (journal_t *journal);
++extern void jbd2_journal_destroy (journal_t *);
++extern int jbd2_journal_recover (journal_t *journal);
++extern int jbd2_journal_wipe (journal_t *, int);
++extern int jbd2_journal_skip_recovery (journal_t *);
++extern void jbd2_journal_update_superblock (journal_t *, int);
++extern void __jbd2_journal_abort_hard (journal_t *);
++extern void jbd2_journal_abort (journal_t *, int);
++extern int jbd2_journal_errno (journal_t *);
++extern void jbd2_journal_ack_err (journal_t *);
++extern int jbd2_journal_clear_err (journal_t *);
++extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *);
++extern int jbd2_journal_force_commit(journal_t *);
++
++/*
++ * journal_head management
++ */
++struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh);
++struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh);
++void jbd2_journal_remove_journal_head(struct buffer_head *bh);
++void jbd2_journal_put_journal_head(struct journal_head *jh);
++
++/*
++ * handle management
++ */
++extern kmem_cache_t *jbd2_handle_cache;
++
++static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags)
++{
++ return kmem_cache_alloc(jbd2_handle_cache, gfp_flags);
++}
++
++static inline void jbd_free_handle(handle_t *handle)
++{
++ kmem_cache_free(jbd2_handle_cache, handle);
++}
++
++/* Primary revoke support */
++#define JOURNAL_REVOKE_DEFAULT_HASH 256
++extern int jbd2_journal_init_revoke(journal_t *, int);
++extern void jbd2_journal_destroy_revoke_caches(void);
++extern int jbd2_journal_init_revoke_caches(void);
++
++extern void jbd2_journal_destroy_revoke(journal_t *);
++extern int jbd2_journal_revoke (handle_t *, unsigned long long, struct buffer_head *);
++extern int jbd2_journal_cancel_revoke(handle_t *, struct journal_head *);
++extern void jbd2_journal_write_revoke_records(journal_t *, transaction_t *);
++
++/* Recovery revoke support */
++extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t);
++extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t);
++extern void jbd2_journal_clear_revoke(journal_t *);
++extern void jbd2_journal_switch_revoke_table(journal_t *journal);
++
++/*
++ * The log thread user interface:
++ *
++ * Request space in the current transaction, and force transaction commit
++ * transitions on demand.
++ */
++
++int __jbd2_log_space_left(journal_t *); /* Called with journal locked */
++int jbd2_log_start_commit(journal_t *journal, tid_t tid);
++int __jbd2_log_start_commit(journal_t *journal, tid_t tid);
++int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
++int jbd2_journal_force_commit_nested(journal_t *journal);
++int jbd2_log_wait_commit(journal_t *journal, tid_t tid);
++int jbd2_log_do_checkpoint(journal_t *journal);
++
++void __jbd2_log_wait_for_space(journal_t *journal);
++extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *);
++extern int jbd2_cleanup_journal_tail(journal_t *);
++
++/* Debugging code only: */
++
++#define jbd_ENOSYS() \
++do { \
++ printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \
++ current->state = TASK_UNINTERRUPTIBLE; \
++ schedule(); \
++} while (1)
++
++/*
++ * is_journal_abort
++ *
++ * Simple test wrapper function to test the JBD2_ABORT state flag. This
++ * bit, when set, indicates that we have had a fatal error somewhere,
++ * either inside the journaling layer or indicated to us by the client
++ * (eg. ext3), and that we and should not commit any further
++ * transactions.
++ */
++
++static inline int is_journal_aborted(journal_t *journal)
++{
++ return journal->j_flags & JBD2_ABORT;
++}
++
++static inline int is_handle_aborted(handle_t *handle)
++{
++ if (handle->h_aborted)
++ return 1;
++ return is_journal_aborted(handle->h_transaction->t_journal);
++}
++
++static inline void jbd2_journal_abort_handle(handle_t *handle)
++{
++ handle->h_aborted = 1;
++}
++
++#endif /* __KERNEL__ */
++
++/* Comparison functions for transaction IDs: perform comparisons using
++ * modulo arithmetic so that they work over sequence number wraps. */
++
++static inline int tid_gt(tid_t x, tid_t y)
++{
++ int difference = (x - y);
++ return (difference > 0);
++}
++
++static inline int tid_geq(tid_t x, tid_t y)
++{
++ int difference = (x - y);
++ return (difference >= 0);
++}
++
++extern int jbd2_journal_blocks_per_page(struct inode *inode);
++extern size_t journal_tag_bytes(journal_t *journal);
++
++/*
++ * Return the minimum number of blocks which must be free in the journal
++ * before a new transaction may be started. Must be called under j_state_lock.
++ */
++static inline int jbd_space_needed(journal_t *journal)
++{
++ int nblocks = journal->j_max_transaction_buffers;
++ if (journal->j_committing_transaction)
++ nblocks += journal->j_committing_transaction->
++ t_outstanding_credits;
++ return nblocks;
++}
++
++/*
++ * Definitions which augment the buffer_head layer
++ */
++
++/* journaling buffer types */
++#define BJ_None 0 /* Not journaled */
++#define BJ_SyncData 1 /* Normal data: flush before commit */
++#define BJ_Metadata 2 /* Normal journaled metadata */
++#define BJ_Forget 3 /* Buffer superseded by this transaction */
++#define BJ_IO 4 /* Buffer is for temporary IO use */
++#define BJ_Shadow 5 /* Buffer contents being shadowed to the log */
++#define BJ_LogCtl 6 /* Buffer contains log descriptors */
++#define BJ_Reserved 7 /* Buffer is reserved for access by journal */
++#define BJ_Locked 8 /* Locked for I/O during commit */
++#define BJ_Types 9
++
++extern int jbd_blocks_per_page(struct inode *inode);
++
++#ifdef __KERNEL__
++
++#define buffer_trace_init(bh) do {} while (0)
++#define print_buffer_fields(bh) do {} while (0)
++#define print_buffer_trace(bh) do {} while (0)
++#define BUFFER_TRACE(bh, info) do {} while (0)
++#define BUFFER_TRACE2(bh, bh2, info) do {} while (0)
++#define JBUFFER_TRACE(jh, info) do {} while (0)
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_JBD_H */
+diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
+index c9c7607..840631f 100644
+--- a/include/linux/jffs2.h
++++ b/include/linux/jffs2.h
+@@ -15,12 +15,12 @@
+ #ifndef __LINUX_JFFS2_H__
+ #define __LINUX_JFFS2_H__
+
++#include <linux/magic.h>
++
+ /* You must include something which defines the C99 uintXX_t types.
+ We don't do it from here because this file is used in too many
+ different environments. */
+
+-#define JFFS2_SUPER_MAGIC 0x72b6
+-
+ /* Values we may expect to find in the 'magic' field */
+ #define JFFS2_OLD_MAGIC_BITMASK 0x1984
+ #define JFFS2_MAGIC_BITMASK 0x1985
+diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
+index 329ebcf..c8d5f20 100644
+--- a/include/linux/jiffies.h
++++ b/include/linux/jiffies.h
+@@ -115,6 +115,21 @@ static inline u64 get_jiffies_64(void)
+ ((long)(a) - (long)(b) >= 0))
+ #define time_before_eq(a,b) time_after_eq(b,a)
+
++/* Same as above, but does so with platform independent 64bit types.
++ * These must be used when utilizing jiffies_64 (i.e. return value of
++ * get_jiffies_64() */
++#define time_after64(a,b) \
++ (typecheck(__u64, a) && \
++ typecheck(__u64, b) && \
++ ((__s64)(b) - (__s64)(a) < 0))
++#define time_before64(a,b) time_after64(b,a)
++
++#define time_after_eq64(a,b) \
++ (typecheck(__u64, a) && \
++ typecheck(__u64, b) && \
++ ((__s64)(a) - (__s64)(b) >= 0))
++#define time_before_eq64(a,b) time_after_eq64(b,a)
++
+ /*
+ * Have the 32 bit jiffies value wrap 5 minutes after boot
+ * so jiffies wrap bugs show up earlier.
+diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
+index 849043c..1cebcbc 100644
+--- a/include/linux/kallsyms.h
++++ b/include/linux/kallsyms.h
+@@ -12,6 +12,10 @@
+ /* Lookup the address for a symbol. Returns 0 if not found. */
+ unsigned long kallsyms_lookup_name(const char *name);
+
++extern int kallsyms_lookup_size_offset(unsigned long addr,
++ unsigned long *symbolsize,
++ unsigned long *offset);
++
+ /* Lookup an address. modname is set to NULL if it's in the kernel. */
+ const char *kallsyms_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+@@ -28,6 +32,13 @@ static inline unsigned long kallsyms_loo
+ return 0;
+ }
+
++static inline int kallsyms_lookup_size_offset(unsigned long addr,
++ unsigned long *symbolsize,
++ unsigned long *offset)
++{
++ return 0;
++}
++
+ static inline const char *kallsyms_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+diff --git a/include/linux/kernel.h b/include/linux/kernel.h
+index 851aa1b..24b6111 100644
+--- a/include/linux/kernel.h
++++ b/include/linux/kernel.h
+@@ -31,8 +31,9 @@ extern const char linux_banner[];
+ #define STACK_MAGIC 0xdeadbeef
+
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+-#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
++#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
+ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
++#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+ #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+
+ #define KERN_EMERG "<0>" /* system is unusable */
+@@ -170,6 +171,8 @@ __attribute_const__ roundup_pow_of_two(u
+
+ extern int printk_ratelimit(void);
+ extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
++extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
++ unsigned int interval_msec);
+
+ static inline void console_silent(void)
+ {
+@@ -186,6 +189,7 @@ extern void bust_spinlocks(int yes);
+ extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */
+ extern int panic_timeout;
+ extern int panic_on_oops;
++extern int panic_on_unrecovered_nmi;
+ extern int tainted;
+ extern const char *print_tainted(void);
+ extern void add_taint(unsigned);
+@@ -214,8 +218,10 @@ extern void dump_stack(void);
+ #define pr_debug(fmt,arg...) \
+ printk(KERN_DEBUG fmt,##arg)
+ #else
+-#define pr_debug(fmt,arg...) \
+- do { } while (0)
++static inline int __attribute__ ((format (printf, 1, 2))) pr_debug(const char * fmt, ...)
++{
++ return 0;
++}
+ #endif
+
+ #define pr_info(fmt,arg...) \
+@@ -348,4 +354,11 @@ struct sysinfo {
+ /* Trap pasters of __FUNCTION__ at compile-time */
+ #define __FUNCTION__ (__func__)
+
++/* This helps us to avoid #ifdef CONFIG_NUMA */
++#ifdef CONFIG_NUMA
++#define NUMA_BUILD 1
++#else
++#define NUMA_BUILD 0
++#endif
++
+ #endif
+diff --git a/include/linux/kmod.h b/include/linux/kmod.h
+index 0db22a1..10f505c 100644
+--- a/include/linux/kmod.h
++++ b/include/linux/kmod.h
+@@ -47,4 +47,8 @@ call_usermodehelper(char *path, char **a
+
+ extern void usermodehelper_init(void);
+
++struct file;
++extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
++ struct file **filp);
++
+ #endif /* __LINUX_KMOD_H__ */
+diff --git a/include/linux/kobject.h b/include/linux/kobject.h
+index 2d22932..bcd9cd1 100644
+--- a/include/linux/kobject.h
++++ b/include/linux/kobject.h
+@@ -20,6 +20,7 @@
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/sysfs.h>
++#include <linux/compiler.h>
+ #include <linux/spinlock.h>
+ #include <linux/rwsem.h>
+ #include <linux/kref.h>
+@@ -71,12 +72,12 @@ static inline const char * kobject_name(
+ extern void kobject_init(struct kobject *);
+ extern void kobject_cleanup(struct kobject *);
+
+-extern int kobject_add(struct kobject *);
++extern int __must_check kobject_add(struct kobject *);
+ extern void kobject_del(struct kobject *);
+
+-extern int kobject_rename(struct kobject *, const char *new_name);
++extern int __must_check kobject_rename(struct kobject *, const char *new_name);
+
+-extern int kobject_register(struct kobject *);
++extern int __must_check kobject_register(struct kobject *);
+ extern void kobject_unregister(struct kobject *);
+
+ extern struct kobject * kobject_get(struct kobject *);
+@@ -128,8 +129,8 @@ struct kset {
+
+
+ extern void kset_init(struct kset * k);
+-extern int kset_add(struct kset * k);
+-extern int kset_register(struct kset * k);
++extern int __must_check kset_add(struct kset * k);
++extern int __must_check kset_register(struct kset * k);
+ extern void kset_unregister(struct kset * k);
+
+ static inline struct kset * to_kset(struct kobject * kobj)
+@@ -239,7 +240,7 @@ extern struct subsystem hypervisor_subsy
+ (obj)->subsys.kset.kobj.kset = &(_subsys).kset
+
+ extern void subsystem_init(struct subsystem *);
+-extern int subsystem_register(struct subsystem *);
++extern int __must_check subsystem_register(struct subsystem *);
+ extern void subsystem_unregister(struct subsystem *);
+
+ static inline struct subsystem * subsys_get(struct subsystem * s)
+@@ -258,7 +259,8 @@ struct subsys_attribute {
+ ssize_t (*store)(struct subsystem *, const char *, size_t);
+ };
+
+-extern int subsys_create_file(struct subsystem * , struct subsys_attribute *);
++extern int __must_check subsys_create_file(struct subsystem * ,
++ struct subsys_attribute *);
+
+ #if defined(CONFIG_HOTPLUG)
+ void kobject_uevent(struct kobject *kobj, enum kobject_action action);
+diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
+index 8bf6702..ac4c055 100644
+--- a/include/linux/kprobes.h
++++ b/include/linux/kprobes.h
+@@ -77,6 +77,12 @@ struct kprobe {
+ /* location of the probe point */
+ kprobe_opcode_t *addr;
+
++ /* Allow user to indicate symbol name of the probe point */
++ char *symbol_name;
++
++ /* Offset into the symbol */
++ unsigned int offset;
++
+ /* Called before addr is executed. */
+ kprobe_pre_handler_t pre_handler;
+
+@@ -196,7 +202,7 @@ void unregister_kretprobe(struct kretpro
+ struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
+ void add_rp_inst(struct kretprobe_instance *ri);
+ void kprobe_flush_task(struct task_struct *tk);
+-void recycle_rp_inst(struct kretprobe_instance *ri);
++void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
+ #else /* CONFIG_KPROBES */
+
+ #define __kprobes /**/
+diff --git a/include/linux/latency.h b/include/linux/latency.h
+new file mode 100644
+index 0000000..c08b52b
+--- /dev/null
++++ b/include/linux/latency.h
+@@ -0,0 +1,25 @@
++/*
++ * latency.h: Explicit system-wide latency-expectation infrastructure
++ *
++ * (C) Copyright 2006 Intel Corporation
++ * Author: Arjan van de Ven <arjan at linux.intel.com>
++ *
++ */
++
++#ifndef _INCLUDE_GUARD_LATENCY_H_
++#define _INCLUDE_GUARD_LATENCY_H_
++
++#include <linux/notifier.h>
++
++void set_acceptable_latency(char *identifier, int usecs);
++void modify_acceptable_latency(char *identifier, int usecs);
++void remove_acceptable_latency(char *identifier);
++void synchronize_acceptable_latency(void);
++int system_latency_constraint(void);
++
++int register_latency_notifier(struct notifier_block * nb);
++int unregister_latency_notifier(struct notifier_block * nb);
++
++#define INFINITE_LATENCY 1000000
++
++#endif
+diff --git a/include/linux/leds.h b/include/linux/leds.h
+index dc23c7c..88afcef 100644
+--- a/include/linux/leds.h
++++ b/include/linux/leds.h
+@@ -12,6 +12,9 @@
+ #ifndef __LINUX_LEDS_H_INCLUDED
+ #define __LINUX_LEDS_H_INCLUDED
+
++#include <linux/list.h>
++#include <linux/spinlock.h>
++
+ struct device;
+ struct class_device;
+ /*
+diff --git a/include/linux/libata.h b/include/linux/libata.h
+index 66c3100..abd2deb 100644
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -37,6 +37,16 @@
+ #include <scsi/scsi_host.h>
+
+ /*
++ * Define if arch has non-standard setup. This is a _PCI_ standard
++ * not a legacy or ISA standard.
++ */
++#ifdef CONFIG_ATA_NONSTANDARD
++#include <asm/libata-portmap.h>
++#else
++#include <asm-generic/libata-portmap.h>
++#endif
++
++/*
+ * compile-time options: to be removed as soon as all the drivers are
+ * converted to the new debugging mechanism
+ */
+@@ -44,7 +54,7 @@
+ #undef ATA_VERBOSE_DEBUG /* yet more debugging output */
+ #undef ATA_IRQ_TRAP /* define to ack screaming irqs */
+ #undef ATA_NDEBUG /* define to disable quick runtime checks */
+-#undef ATA_ENABLE_PATA /* define to enable PATA support in some
++#define ATA_ENABLE_PATA /* define to enable PATA support in some
+ * low-level drivers */
+
+
+@@ -99,6 +109,10 @@ static inline u32 ata_msg_init(int dval,
+ #define ATA_TAG_POISON 0xfafbfcfdU
+
+ /* move to PCI layer? */
++#define PCI_VDEVICE(vendor, device) \
++ PCI_VENDOR_ID_##vendor, (device), \
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0
++
+ static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
+ {
+ return &pdev->dev;
+@@ -112,8 +126,6 @@ enum {
+ /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */
+ ATA_MAX_QUEUE = 32,
+ ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1,
+- ATA_MAX_SECTORS = 200, /* FIXME */
+- ATA_MAX_SECTORS_LBA48 = 65535,
+ ATA_MAX_BUS = 2,
+ ATA_DEF_BUSY_WAIT = 10000,
+ ATA_SHORT_PAUSE = (HZ >> 6) + 1,
+@@ -130,8 +142,9 @@ enum {
+ ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
+ ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
+
+- ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
+- ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
++ ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
++ ATA_DFLAG_NCQ_OFF = (1 << 9), /* device limited to non-NCQ mode */
++ ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */
+ ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
+
+ ATA_DFLAG_DETACH = (1 << 16),
+@@ -197,8 +210,8 @@ enum {
+ ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */
+
+ /* host set flags */
+- ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */
+-
++ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
++
+ /* various lengths of time */
+ ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
+ ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */
+@@ -225,8 +238,8 @@ enum {
+ /* encoding various smaller bitmaps into a single
+ * unsigned int bitmap
+ */
+- ATA_BITS_PIO = 5,
+- ATA_BITS_MWDMA = 3,
++ ATA_BITS_PIO = 7,
++ ATA_BITS_MWDMA = 5,
+ ATA_BITS_UDMA = 8,
+
+ ATA_SHIFT_PIO = 0,
+@@ -289,6 +302,11 @@ enum {
+ * most devices.
+ */
+ ATA_SPINUP_WAIT = 8000,
++
++ /* Horkage types. May be set by libata or controller on drives
++ (some horkage may be drive/controller pair dependant */
++
++ ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */
+ };
+
+ enum hsm_task_states {
+@@ -350,23 +368,32 @@ struct ata_probe_ent {
+ struct scsi_host_template *sht;
+ struct ata_ioports port[ATA_MAX_PORTS];
+ unsigned int n_ports;
+- unsigned int hard_port_no;
++ unsigned int dummy_port_mask;
+ unsigned int pio_mask;
+ unsigned int mwdma_mask;
+ unsigned int udma_mask;
+- unsigned int legacy_mode;
+ unsigned long irq;
++ unsigned long irq2;
+ unsigned int irq_flags;
+- unsigned long host_flags;
+- unsigned long host_set_flags;
++ unsigned long port_flags;
++ unsigned long _host_flags;
+ void __iomem *mmio_base;
+ void *private_data;
++
++ /* port_info for the secondary port. Together with irq2, it's
++ * used to implement non-uniform secondary port. Currently,
++ * the only user is ata_piix combined mode. This workaround
++ * will be removed together with ata_probe_ent when init model
++ * is updated.
++ */
++ const struct ata_port_info *pinfo2;
+ };
+
+-struct ata_host_set {
++struct ata_host {
+ spinlock_t lock;
+ struct device *dev;
+ unsigned long irq;
++ unsigned long irq2;
+ void __iomem *mmio_base;
+ unsigned int n_ports;
+ void *private_data;
+@@ -374,7 +401,6 @@ struct ata_host_set {
+ unsigned long flags;
+ int simplex_claimed; /* Keep seperate in case we
+ ever need to do this locked */
+- struct ata_host_set *next; /* for legacy mode */
+ struct ata_port *ports[0];
+ };
+
+@@ -420,7 +446,7 @@ struct ata_queued_cmd {
+ void *private_data;
+ };
+
+-struct ata_host_stats {
++struct ata_port_stats {
+ unsigned long unhandled_irq;
+ unsigned long idle_irq;
+ unsigned long rw_reqbuf;
+@@ -468,6 +494,7 @@ struct ata_device {
+
+ /* error history */
+ struct ata_ering ering;
++ unsigned int horkage; /* List of broken features */
+ };
+
+ /* Offset into struct ata_device. Fields above it are maintained
+@@ -498,14 +525,13 @@ struct ata_eh_context {
+ };
+
+ struct ata_port {
+- struct Scsi_Host *host; /* our co-allocated scsi host */
++ struct Scsi_Host *scsi_host; /* our co-allocated scsi host */
+ const struct ata_port_operations *ops;
+ spinlock_t *lock;
+ unsigned long flags; /* ATA_FLAG_xxx */
+ unsigned int pflags; /* ATA_PFLAG_xxx */
+ unsigned int id; /* unique id req'd by scsi midlyr */
+ unsigned int port_no; /* unique port #; from zero */
+- unsigned int hard_port_no; /* hardware port #; from zero */
+
+ struct ata_prd *prd; /* our SG list */
+ dma_addr_t prd_dma; /* and its DMA mapping */
+@@ -524,7 +550,7 @@ struct ata_port {
+ unsigned int hw_sata_spd_limit;
+ unsigned int sata_spd_limit; /* SATA PHY speed limit */
+
+- /* record runtime error info, protected by host_set lock */
++ /* record runtime error info, protected by host lock */
+ struct ata_eh_info eh_info;
+ /* EH context owned by EH */
+ struct ata_eh_context eh_context;
+@@ -538,8 +564,8 @@ struct ata_port {
+ unsigned int active_tag;
+ u32 sactive;
+
+- struct ata_host_stats stats;
+- struct ata_host_set *host_set;
++ struct ata_port_stats stats;
++ struct ata_host *host;
+ struct device *dev;
+
+ struct work_struct port_task;
+@@ -602,7 +628,7 @@ struct ata_port_operations {
+ void (*error_handler) (struct ata_port *ap);
+ void (*post_internal_cmd) (struct ata_queued_cmd *qc);
+
+- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
++ irq_handler_t irq_handler;
+ void (*irq_clear) (struct ata_port *);
+
+ u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
+@@ -615,7 +641,7 @@ struct ata_port_operations {
+ int (*port_start) (struct ata_port *ap);
+ void (*port_stop) (struct ata_port *ap);
+
+- void (*host_stop) (struct ata_host_set *host_set);
++ void (*host_stop) (struct ata_host *host);
+
+ void (*bmdma_stop) (struct ata_queued_cmd *qc);
+ u8 (*bmdma_status) (struct ata_port *ap);
+@@ -623,7 +649,7 @@ struct ata_port_operations {
+
+ struct ata_port_info {
+ struct scsi_host_template *sht;
+- unsigned long host_flags;
++ unsigned long flags;
+ unsigned long pio_mask;
+ unsigned long mwdma_mask;
+ unsigned long udma_mask;
+@@ -649,6 +675,8 @@ extern const unsigned long sata_deb_timi
+ extern const unsigned long sata_deb_timing_hotplug[];
+ extern const unsigned long sata_deb_timing_long[];
+
++extern const struct ata_port_operations ata_dummy_port_ops;
++
+ static inline const unsigned long *
+ sata_ehc_deb_timing(struct ata_eh_context *ehc)
+ {
+@@ -658,6 +686,11 @@ sata_ehc_deb_timing(struct ata_eh_contex
+ return sata_deb_timing_normal;
+ }
+
++static inline int ata_port_is_dummy(struct ata_port *ap)
++{
++ return ap->ops == &ata_dummy_port_ops;
++}
++
+ extern void ata_port_probe(struct ata_port *);
+ extern void __sata_phy_reset(struct ata_port *ap);
+ extern void sata_phy_reset(struct ata_port *ap);
+@@ -669,26 +702,36 @@ extern int ata_std_prereset(struct ata_p
+ extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
+ extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
+ extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+-extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
+ extern void ata_port_disable(struct ata_port *);
+ extern void ata_std_ports(struct ata_ioports *ioaddr);
+ #ifdef CONFIG_PCI
+ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+ unsigned int n_ports);
+ extern void ata_pci_remove_one (struct pci_dev *pdev);
+-extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state);
++extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg);
+ extern void ata_pci_device_do_resume(struct pci_dev *pdev);
+-extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
++extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+ extern int ata_pci_device_resume(struct pci_dev *pdev);
+ extern int ata_pci_clear_simplex(struct pci_dev *pdev);
+ #endif /* CONFIG_PCI */
+ extern int ata_device_add(const struct ata_probe_ent *ent);
+ extern void ata_port_detach(struct ata_port *ap);
+-extern void ata_host_set_remove(struct ata_host_set *host_set);
++extern void ata_host_init(struct ata_host *, struct device *,
++ unsigned long, const struct ata_port_operations *);
++extern void ata_host_remove(struct ata_host *host);
+ extern int ata_scsi_detect(struct scsi_host_template *sht);
+ extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
+ extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+ extern int ata_scsi_release(struct Scsi_Host *host);
++extern void ata_sas_port_destroy(struct ata_port *);
++extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
++ struct ata_port_info *, struct Scsi_Host *);
++extern int ata_sas_port_init(struct ata_port *);
++extern int ata_sas_port_start(struct ata_port *ap);
++extern void ata_sas_port_stop(struct ata_port *ap);
++extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
++extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
++ struct ata_port *ap);
+ extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+ extern int sata_scr_valid(struct ata_port *ap);
+ extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
+@@ -697,10 +740,9 @@ extern int sata_scr_write_flush(struct a
+ extern int ata_port_online(struct ata_port *ap);
+ extern int ata_port_offline(struct ata_port *ap);
+ extern int ata_scsi_device_resume(struct scsi_device *);
+-extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
+-extern int ata_host_set_suspend(struct ata_host_set *host_set,
+- pm_message_t mesg);
+-extern void ata_host_set_resume(struct ata_host_set *host_set);
++extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t mesg);
++extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
++extern void ata_host_resume(struct ata_host *host);
+ extern int ata_ratelimit(void);
+ extern unsigned int ata_busy_sleep(struct ata_port *ap,
+ unsigned long timeout_pat,
+@@ -725,8 +767,8 @@ extern u8 ata_altstatus(struct ata_port
+ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf);
+ extern int ata_port_start (struct ata_port *ap);
+ extern void ata_port_stop (struct ata_port *ap);
+-extern void ata_host_stop (struct ata_host_set *host_set);
+-extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
++extern void ata_host_stop (struct ata_host *host);
++extern irqreturn_t ata_interrupt (int irq, void *dev_instance);
+ extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data);
+ extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
+@@ -811,7 +853,7 @@ struct pci_bits {
+ unsigned long val;
+ };
+
+-extern void ata_pci_host_stop (struct ata_host_set *host_set);
++extern void ata_pci_host_stop (struct ata_host *host);
+ extern struct ata_probe_ent *
+ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
+ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
+diff --git a/include/linux/libps2.h b/include/linux/libps2.h
+index 08a450a..f6f301e 100644
+--- a/include/linux/libps2.h
++++ b/include/linux/libps2.h
+@@ -47,5 +47,6 @@ int ps2_schedule_command(struct ps2dev *
+ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
+ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
+ void ps2_cmd_aborted(struct ps2dev *ps2dev);
++int ps2_is_keyboard_id(char id);
+
+ #endif /* _LIBPS2_H */
+diff --git a/include/linux/linkage.h b/include/linux/linkage.h
+index 932021f..6c9873f 100644
+--- a/include/linux/linkage.h
++++ b/include/linux/linkage.h
+@@ -35,9 +35,13 @@
+ #endif
+
+ #define KPROBE_ENTRY(name) \
+- .section .kprobes.text, "ax"; \
++ .pushsection .kprobes.text, "ax"; \
+ ENTRY(name)
+
++#define KPROBE_END(name) \
++ END(name); \
++ .popsection
++
+ #ifndef END
+ #define END(name) \
+ .size name, .-name
+diff --git a/include/linux/list.h b/include/linux/list.h
+index 65a5b5c..a9c9028 100644
+--- a/include/linux/list.h
++++ b/include/linux/list.h
+@@ -39,6 +39,7 @@ static inline void INIT_LIST_HEAD(struct
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
++#ifndef CONFIG_DEBUG_LIST
+ static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+@@ -48,6 +49,11 @@ static inline void __list_add(struct lis
+ new->prev = prev;
+ prev->next = new;
+ }
++#else
++extern void __list_add(struct list_head *new,
++ struct list_head *prev,
++ struct list_head *next);
++#endif
+
+ /**
+ * list_add - add a new entry
+@@ -57,10 +63,15 @@ static inline void __list_add(struct lis
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
++#ifndef CONFIG_DEBUG_LIST
+ static inline void list_add(struct list_head *new, struct list_head *head)
+ {
+ __list_add(new, head, head->next);
+ }
++#else
++extern void list_add(struct list_head *new, struct list_head *head);
++#endif
++
+
+ /**
+ * list_add_tail - add a new entry
+@@ -153,12 +164,16 @@ static inline void __list_del(struct lis
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
++#ifndef CONFIG_DEBUG_LIST
+ static inline void list_del(struct list_head *entry)
+ {
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+ }
++#else
++extern void list_del(struct list_head *entry);
++#endif
+
+ /**
+ * list_del_rcu - deletes entry from list without re-initialization
+diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h
+new file mode 100644
+index 0000000..1418fdc
+--- /dev/null
++++ b/include/linux/lm_interface.h
+@@ -0,0 +1,273 @@
++/*
++ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
++ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License version 2.
++ */
++
++#ifndef __LM_INTERFACE_DOT_H__
++#define __LM_INTERFACE_DOT_H__
++
++
++typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
++
++/*
++ * lm_mount() flags
++ *
++ * LM_MFLAG_SPECTATOR
++ * GFS is asking to join the filesystem's lockspace, but it doesn't want to
++ * modify the filesystem. The lock module shouldn't assign a journal to the FS
++ * mount. It shouldn't send recovery callbacks to the FS mount. If the node
++ * dies or withdraws, all locks can be wiped immediately.
++ */
++
++#define LM_MFLAG_SPECTATOR 0x00000001
++
++/*
++ * lm_lockstruct flags
++ *
++ * LM_LSFLAG_LOCAL
++ * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS
++ * can make single-node optimizations.
++ */
++
++#define LM_LSFLAG_LOCAL 0x00000001
++
++/*
++ * lm_lockname types
++ */
++
++#define LM_TYPE_RESERVED 0x00
++#define LM_TYPE_NONDISK 0x01
++#define LM_TYPE_INODE 0x02
++#define LM_TYPE_RGRP 0x03
++#define LM_TYPE_META 0x04
++#define LM_TYPE_IOPEN 0x05
++#define LM_TYPE_FLOCK 0x06
++#define LM_TYPE_PLOCK 0x07
++#define LM_TYPE_QUOTA 0x08
++#define LM_TYPE_JOURNAL 0x09
++
++/*
++ * lm_lock() states
++ *
++ * SHARED is compatible with SHARED, not with DEFERRED or EX.
++ * DEFERRED is compatible with DEFERRED, not with SHARED or EX.
++ */
++
++#define LM_ST_UNLOCKED 0
++#define LM_ST_EXCLUSIVE 1
++#define LM_ST_DEFERRED 2
++#define LM_ST_SHARED 3
++
++/*
++ * lm_lock() flags
++ *
++ * LM_FLAG_TRY
++ * Don't wait to acquire the lock if it can't be granted immediately.
++ *
++ * LM_FLAG_TRY_1CB
++ * Send one blocking callback if TRY is set and the lock is not granted.
++ *
++ * LM_FLAG_NOEXP
++ * GFS sets this flag on lock requests it makes while doing journal recovery.
++ * These special requests should not be blocked due to the recovery like
++ * ordinary locks would be.
++ *
++ * LM_FLAG_ANY
++ * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
++ * also be granted in SHARED. The preferred state is whichever is compatible
++ * with other granted locks, or the specified state if no other locks exist.
++ *
++ * LM_FLAG_PRIORITY
++ * Override fairness considerations. Suppose a lock is held in a shared state
++ * and there is a pending request for the deferred state. A shared lock
++ * request with the priority flag would be allowed to bypass the deferred
++ * request and directly join the other shared lock. A shared lock request
++ * without the priority flag might be forced to wait until the deferred
++ * requested had acquired and released the lock.
++ */
++
++#define LM_FLAG_TRY 0x00000001
++#define LM_FLAG_TRY_1CB 0x00000002
++#define LM_FLAG_NOEXP 0x00000004
++#define LM_FLAG_ANY 0x00000008
++#define LM_FLAG_PRIORITY 0x00000010
++
++/*
++ * lm_lock() and lm_async_cb return flags
++ *
++ * LM_OUT_ST_MASK
++ * Masks the lower two bits of lock state in the returned value.
++ *
++ * LM_OUT_CACHEABLE
++ * The lock hasn't been released so GFS can continue to cache data for it.
++ *
++ * LM_OUT_CANCELED
++ * The lock request was canceled.
++ *
++ * LM_OUT_ASYNC
++ * The result of the request will be returned in an LM_CB_ASYNC callback.
++ */
++
++#define LM_OUT_ST_MASK 0x00000003
++#define LM_OUT_CACHEABLE 0x00000004
++#define LM_OUT_CANCELED 0x00000008
++#define LM_OUT_ASYNC 0x00000080
++#define LM_OUT_ERROR 0x00000100
++
++/*
++ * lm_callback_t types
++ *
++ * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S
++ * Blocking callback, a remote node is requesting the given lock in
++ * EXCLUSIVE, DEFERRED, or SHARED.
++ *
++ * LM_CB_NEED_RECOVERY
++ * The given journal needs to be recovered.
++ *
++ * LM_CB_DROPLOCKS
++ * Reduce the number of cached locks.
++ *
++ * LM_CB_ASYNC
++ * The given lock has been granted.
++ */
++
++#define LM_CB_NEED_E 257
++#define LM_CB_NEED_D 258
++#define LM_CB_NEED_S 259
++#define LM_CB_NEED_RECOVERY 260
++#define LM_CB_DROPLOCKS 261
++#define LM_CB_ASYNC 262
++
++/*
++ * lm_recovery_done() messages
++ */
++
++#define LM_RD_GAVEUP 308
++#define LM_RD_SUCCESS 309
++
++
++struct lm_lockname {
++ u64 ln_number;
++ unsigned int ln_type;
++};
++
++#define lm_name_equal(name1, name2) \
++ (((name1)->ln_number == (name2)->ln_number) && \
++ ((name1)->ln_type == (name2)->ln_type)) \
++
++struct lm_async_cb {
++ struct lm_lockname lc_name;
++ int lc_ret;
++};
++
++struct lm_lockstruct;
++
++struct lm_lockops {
++ const char *lm_proto_name;
++
++ /*
++ * Mount/Unmount
++ */
++
++ int (*lm_mount) (char *table_name, char *host_data,
++ lm_callback_t cb, void *cb_data,
++ unsigned int min_lvb_size, int flags,
++ struct lm_lockstruct *lockstruct,
++ struct kobject *fskobj);
++
++ void (*lm_others_may_mount) (void *lockspace);
++
++ void (*lm_unmount) (void *lockspace);
++
++ void (*lm_withdraw) (void *lockspace);
++
++ /*
++ * Lock oriented operations
++ */
++
++ int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp);
++
++ void (*lm_put_lock) (void *lock);
++
++ unsigned int (*lm_lock) (void *lock, unsigned int cur_state,
++ unsigned int req_state, unsigned int flags);
++
++ unsigned int (*lm_unlock) (void *lock, unsigned int cur_state);
++
++ void (*lm_cancel) (void *lock);
++
++ int (*lm_hold_lvb) (void *lock, char **lvbp);
++ void (*lm_unhold_lvb) (void *lock, char *lvb);
++
++ /*
++ * Posix Lock oriented operations
++ */
++
++ int (*lm_plock_get) (void *lockspace, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl);
++
++ int (*lm_plock) (void *lockspace, struct lm_lockname *name,
++ struct file *file, int cmd, struct file_lock *fl);
++
++ int (*lm_punlock) (void *lockspace, struct lm_lockname *name,
++ struct file *file, struct file_lock *fl);
++
++ /*
++ * Client oriented operations
++ */
++
++ void (*lm_recovery_done) (void *lockspace, unsigned int jid,
++ unsigned int message);
++
++ struct module *lm_owner;
++};
++
++/*
++ * lm_mount() return values
++ *
++ * ls_jid - the journal ID this node should use
++ * ls_first - this node is the first to mount the file system
++ * ls_lvb_size - size in bytes of lock value blocks
++ * ls_lockspace - lock module's context for this file system
++ * ls_ops - lock module's functions
++ * ls_flags - lock module features
++ */
++
++struct lm_lockstruct {
++ unsigned int ls_jid;
++ unsigned int ls_first;
++ unsigned int ls_lvb_size;
++ void *ls_lockspace;
++ const struct lm_lockops *ls_ops;
++ int ls_flags;
++};
++
++/*
++ * Lock module bottom interface. A lock module makes itself available to GFS
++ * with these functions.
++ */
++
++int gfs2_register_lockproto(const struct lm_lockops *proto);
++void gfs2_unregister_lockproto(const struct lm_lockops *proto);
++
++/*
++ * Lock module top interface. GFS calls these functions when mounting or
++ * unmounting a file system.
++ */
++
++int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
++ lm_callback_t cb, void *cb_data,
++ unsigned int min_lvb_size, int flags,
++ struct lm_lockstruct *lockstruct,
++ struct kobject *fskobj);
++
++void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct);
++
++void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct);
++
++#endif /* __LM_INTERFACE_DOT_H__ */
++
+diff --git a/include/linux/lock_dlm_plock.h b/include/linux/lock_dlm_plock.h
+new file mode 100644
+index 0000000..fc34151
+--- /dev/null
++++ b/include/linux/lock_dlm_plock.h
+@@ -0,0 +1,41 @@
++/*
++ * Copyright (C) 2005 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License v.2.
++ */
++
++#ifndef __LOCK_DLM_PLOCK_DOT_H__
++#define __LOCK_DLM_PLOCK_DOT_H__
++
++#define GDLM_PLOCK_MISC_NAME "lock_dlm_plock"
++
++#define GDLM_PLOCK_VERSION_MAJOR 1
++#define GDLM_PLOCK_VERSION_MINOR 1
++#define GDLM_PLOCK_VERSION_PATCH 0
++
++enum {
++ GDLM_PLOCK_OP_LOCK = 1,
++ GDLM_PLOCK_OP_UNLOCK,
++ GDLM_PLOCK_OP_GET,
++};
++
++struct gdlm_plock_info {
++ __u32 version[3];
++ __u8 optype;
++ __u8 ex;
++ __u8 wait;
++ __u8 pad;
++ __u32 pid;
++ __s32 nodeid;
++ __s32 rv;
++ __u32 fsid;
++ __u64 number;
++ __u64 start;
++ __u64 end;
++ __u64 owner;
++};
++
++#endif
++
+diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
+index b054deb..aa50d89 100644
+--- a/include/linux/lockd/bind.h
++++ b/include/linux/lockd/bind.h
+@@ -10,6 +10,11 @@
+ #define LINUX_LOCKD_BIND_H
+
+ #include <linux/lockd/nlm.h>
++/* need xdr-encoded error codes too, so... */
++#include <linux/lockd/xdr.h>
++#ifdef CONFIG_LOCKD_V4
++#include <linux/lockd/xdr4.h>
++#endif
+
+ /* Dummy declarations */
+ struct svc_rqst;
+@@ -30,7 +35,7 @@ extern struct nlmsvc_binding * nlmsvc_op
+ * Functions exported by the lockd module
+ */
+ extern int nlmclnt_proc(struct inode *, int, struct file_lock *);
+-extern int lockd_up(void);
++extern int lockd_up(int proto);
+ extern void lockd_down(void);
+
+ #endif /* LINUX_LOCKD_BIND_H */
+diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
+index 0d92c46..862d973 100644
+--- a/include/linux/lockd/lockd.h
++++ b/include/linux/lockd/lockd.h
+@@ -37,17 +37,15 @@
+ * Lockd host handle (used both by the client and server personality).
+ */
+ struct nlm_host {
+- struct nlm_host * h_next; /* linked list (hash table) */
++ struct hlist_node h_hash; /* doubly linked list */
+ struct sockaddr_in h_addr; /* peer address */
+ struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
+- char h_name[20]; /* remote hostname */
++ char * h_name; /* remote hostname */
+ u32 h_version; /* interface version */
+ unsigned short h_proto; /* transport proto */
+ unsigned short h_reclaiming : 1,
+ h_server : 1, /* server side, not client side */
+- h_inuse : 1,
+- h_killed : 1,
+- h_monitored : 1;
++ h_inuse : 1;
+ wait_queue_head_t h_gracewait; /* wait while reclaiming */
+ struct rw_semaphore h_rwsem; /* Reboot recovery lock */
+ u32 h_state; /* pseudo-state counter */
+@@ -61,6 +59,16 @@ struct nlm_host {
+ spinlock_t h_lock;
+ struct list_head h_granted; /* Locks in GRANTED state */
+ struct list_head h_reclaim; /* Locks in RECLAIM state */
++ struct nsm_handle * h_nsmhandle; /* NSM status handle */
++};
++
++struct nsm_handle {
++ struct list_head sm_link;
++ atomic_t sm_count;
++ char * sm_name;
++ struct sockaddr_in sm_addr;
++ unsigned int sm_monitored : 1,
++ sm_sticky : 1; /* don't unmonitor */
+ };
+
+ /*
+@@ -80,7 +88,7 @@ struct nlm_wait;
+ /*
+ * Memory chunk for NLM client RPC request.
+ */
+-#define NLMCLNT_OHSIZE (sizeof(system_utsname.nodename)+10)
++#define NLMCLNT_OHSIZE (sizeof(utsname()->nodename)+10)
+ struct nlm_rqst {
+ unsigned int a_flags; /* initial RPC task flags */
+ struct nlm_host * a_host; /* host handle */
+@@ -96,15 +104,14 @@ struct nlm_rqst {
+ * an NFS client.
+ */
+ struct nlm_file {
+- struct nlm_file * f_next; /* linked list */
++ struct hlist_node f_list; /* linked list */
+ struct nfs_fh f_handle; /* NFS file handle */
+ struct file * f_file; /* VFS file pointer */
+ struct nlm_share * f_shares; /* DOS shares */
+- struct nlm_block * f_blocks; /* blocked locks */
++ struct list_head f_blocks; /* blocked locks */
+ unsigned int f_locks; /* guesstimate # of locks */
+ unsigned int f_count; /* reference count */
+- struct semaphore f_sema; /* avoid concurrent access */
+- int f_hash; /* hash of f_handle */
++ struct mutex f_mutex; /* avoid concurrent access */
+ };
+
+ /*
+@@ -114,26 +121,18 @@ struct nlm_file {
+ #define NLM_NEVER (~(unsigned long) 0)
+ struct nlm_block {
+ struct kref b_count; /* Reference count */
+- struct nlm_block * b_next; /* linked list (all blocks) */
+- struct nlm_block * b_fnext; /* linked list (per file) */
++ struct list_head b_list; /* linked list of all blocks */
++ struct list_head b_flist; /* linked list (per file) */
+ struct nlm_rqst * b_call; /* RPC args & callback info */
+ struct svc_serv * b_daemon; /* NLM service */
+ struct nlm_host * b_host; /* host handle for RPC clnt */
+ unsigned long b_when; /* next re-xmit */
+ unsigned int b_id; /* block id */
+- unsigned char b_queued; /* re-queued */
+ unsigned char b_granted; /* VFS granted lock */
+ struct nlm_file * b_file; /* file in question */
+ };
+
+ /*
+- * Valid actions for nlmsvc_traverse_files
+- */
+-#define NLM_ACT_CHECK 0 /* check for locks */
+-#define NLM_ACT_MARK 1 /* mark & sweep */
+-#define NLM_ACT_UNLOCK 2 /* release all locks */
+-
+-/*
+ * Global variables
+ */
+ extern struct rpc_program nlm_program;
+@@ -143,6 +142,7 @@ extern struct svc_procedure nlmsvc_proce
+ #endif
+ extern int nlmsvc_grace_period;
+ extern unsigned long nlmsvc_timeout;
++extern int nsm_use_hostnames;
+
+ /*
+ * Lockd client functions
+@@ -154,42 +154,51 @@ int nlm_async_reply(struct nlm_rqst *
+ struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
+ void nlmclnt_finish_block(struct nlm_wait *block);
+ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
+-u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
+-void nlmclnt_recovery(struct nlm_host *, u32);
++__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
++void nlmclnt_recovery(struct nlm_host *);
+ int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
++void nlmclnt_next_cookie(struct nlm_cookie *);
+
+ /*
+ * Host cache
+ */
+-struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int);
+-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *);
+-struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int);
++struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
++struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
++struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int, const char *, int);
+ struct rpc_clnt * nlm_bind_host(struct nlm_host *);
+ void nlm_rebind_host(struct nlm_host *);
+ struct nlm_host * nlm_get_host(struct nlm_host *);
+ void nlm_release_host(struct nlm_host *);
+ void nlm_shutdown_hosts(void);
+-extern struct nlm_host *nlm_find_client(void);
++extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
++struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int);
++void nsm_release(struct nsm_handle *);
++
+
++/*
++ * This is used in garbage collection and resource reclaim
++ * A return value != 0 means destroy the lock/block/share
++ */
++typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref);
+
+ /*
+ * Server-side lock handling
+ */
+-u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
++__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
+ struct nlm_lock *, int, struct nlm_cookie *);
+-u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
+-u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
++__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
++__be32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
+ struct nlm_lock *);
+-u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
++__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
+ unsigned long nlmsvc_retry_blocked(void);
+ void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
+- int action);
+-void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32);
++ nlm_host_match_fn_t match);
++void nlmsvc_grant_reply(struct nlm_cookie *, u32);
+
+ /*
+ * File handling for the server personality
+ */
+-u32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
++__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
+ struct nfs_fh *);
+ void nlm_release_file(struct nlm_file *);
+ void nlmsvc_mark_resources(void);
+diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h
+index c75a424..630c5bf 100644
+--- a/include/linux/lockd/share.h
++++ b/include/linux/lockd/share.h
+@@ -21,10 +21,11 @@ struct nlm_share {
+ u32 s_mode; /* deny mode */
+ };
+
+-u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
++__be32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
+ struct nlm_args *);
+-u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
++__be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
+ struct nlm_args *);
+-void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int);
++void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
++ nlm_host_match_fn_t);
+
+ #endif /* LINUX_LOCKD_SHARE_H */
+diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
+index 1080bb6..fc61d40 100644
+--- a/include/linux/lockd/sm_inter.h
++++ b/include/linux/lockd/sm_inter.h
+@@ -28,7 +28,8 @@ struct nsm_args {
+ u32 prog; /* RPC callback info */
+ u32 vers;
+ u32 proc;
+- u32 proto; /* protocol (udp/tcp) plus server/client flag */
++
++ char * mon_name;
+ };
+
+ /*
+@@ -41,6 +42,6 @@ struct nsm_res {
+
+ int nsm_monitor(struct nlm_host *);
+ int nsm_unmonitor(struct nlm_host *);
+-extern u32 nsm_local_state;
++extern int nsm_local_state;
+
+ #endif /* LINUX_LOCKD_SM_INTER_H */
+diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
+index bb0a0f1..29e7d9f 100644
+--- a/include/linux/lockd/xdr.h
++++ b/include/linux/lockd/xdr.h
+@@ -13,6 +13,8 @@
+ #include <linux/nfs.h>
+ #include <linux/sunrpc/xdr.h>
+
++struct svc_rqst;
++
+ #define NLM_MAXCOOKIELEN 32
+ #define NLM_MAXSTRLEN 1024
+
+@@ -22,6 +24,8 @@
+ #define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED)
+ #define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
+
++#define nlm_drop_reply __constant_htonl(30000)
++
+ /* Lock info passed via NLM */
+ struct nlm_lock {
+ char * caller;
+@@ -86,19 +90,19 @@ struct nlm_reboot {
+ */
+ #define NLMSVC_XDRSIZE sizeof(struct nlm_args)
+
+-int nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlmsvc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlmsvc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlmsvc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlmsvc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlmsvc_encode_void(struct svc_rqst *, u32 *, void *);
+-int nlmsvc_decode_void(struct svc_rqst *, u32 *, void *);
+-int nlmsvc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlmsvc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlmsvc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlmsvc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
++int nlmsvc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlmsvc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlmsvc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlmsvc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlmsvc_encode_void(struct svc_rqst *, __be32 *, void *);
++int nlmsvc_decode_void(struct svc_rqst *, __be32 *, void *);
++int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlmsvc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
+ /*
+ int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+ int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h
+index cee36e7..dd12b4c 100644
+--- a/include/linux/lockd/xdr4.h
++++ b/include/linux/lockd/xdr4.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/linux/lockd/xdr.h
++ * linux/include/linux/lockd/xdr4.h
+ *
+ * XDR types for the NLM protocol
+ *
+@@ -23,19 +23,19 @@
+
+
+
+-int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlm4svc_encode_void(struct svc_rqst *, u32 *, void *);
+-int nlm4svc_decode_void(struct svc_rqst *, u32 *, void *);
+-int nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
+-int nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
+-int nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
++int nlm4svc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlm4svc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlm4svc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlm4svc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlm4svc_encode_void(struct svc_rqst *, __be32 *, void *);
++int nlm4svc_decode_void(struct svc_rqst *, __be32 *, void *);
++int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
++int nlm4svc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
++int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
+ /*
+ int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+ int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
+index c040a8c..819f08f 100644
+--- a/include/linux/lockdep.h
++++ b/include/linux/lockdep.h
+@@ -8,13 +8,13 @@
+ #ifndef __LINUX_LOCKDEP_H
+ #define __LINUX_LOCKDEP_H
+
++#ifdef CONFIG_LOCKDEP
++
+ #include <linux/linkage.h>
+ #include <linux/list.h>
+ #include <linux/debug_locks.h>
+ #include <linux/stacktrace.h>
+
+-#ifdef CONFIG_LOCKDEP
+-
+ /*
+ * Lock-class usage-state bits:
+ */
+@@ -202,7 +202,7 @@ extern int lockdep_internal(void);
+ */
+
+ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
+- struct lock_class_key *key);
++ struct lock_class_key *key, int subclass);
+
+ /*
+ * Reinitialize a lock key - for cases where there is special locking or
+@@ -211,9 +211,14 @@ extern void lockdep_init_map(struct lock
+ * or they are too narrow (they suffer from a false class-split):
+ */
+ #define lockdep_set_class(lock, key) \
+- lockdep_init_map(&(lock)->dep_map, #key, key)
++ lockdep_init_map(&(lock)->dep_map, #key, key, 0)
+ #define lockdep_set_class_and_name(lock, key, name) \
+- lockdep_init_map(&(lock)->dep_map, name, key)
++ lockdep_init_map(&(lock)->dep_map, name, key, 0)
++#define lockdep_set_class_and_subclass(lock, key, sub) \
++ lockdep_init_map(&(lock)->dep_map, #key, key, sub)
++#define lockdep_set_subclass(lock, sub) \
++ lockdep_init_map(&(lock)->dep_map, #lock, \
++ (lock)->dep_map.key, sub)
+
+ /*
+ * Acquire a lock.
+@@ -257,10 +262,14 @@ static inline int lockdep_internal(void)
+ # define lock_release(l, n, i) do { } while (0)
+ # define lockdep_init() do { } while (0)
+ # define lockdep_info() do { } while (0)
+-# define lockdep_init_map(lock, name, key) do { (void)(key); } while (0)
++# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0)
+ # define lockdep_set_class(lock, key) do { (void)(key); } while (0)
+ # define lockdep_set_class_and_name(lock, key, name) \
+ do { (void)(key); } while (0)
++#define lockdep_set_class_and_subclass(lock, key, sub) \
++ do { (void)(key); } while (0)
++#define lockdep_set_subclass(lock, sub) do { } while (0)
++
+ # define INIT_LOCKDEP
+ # define lockdep_reset() do { debug_locks = 1; } while (0)
+ # define lockdep_free_key_range(start, size) do { } while (0)
+diff --git a/include/linux/loop.h b/include/linux/loop.h
+index e76c761..191a595 100644
+--- a/include/linux/loop.h
++++ b/include/linux/loop.h
+@@ -59,10 +59,9 @@ struct loop_device {
+ struct bio *lo_bio;
+ struct bio *lo_biotail;
+ int lo_state;
+- struct completion lo_done;
+- struct completion lo_bh_done;
+ struct mutex lo_ctl_mutex;
+- int lo_pending;
++ struct task_struct *lo_thread;
++ wait_queue_head_t lo_event;
+
+ request_queue_t *lo_queue;
+ };
+diff --git a/include/linux/magic.h b/include/linux/magic.h
+new file mode 100644
+index 0000000..156c40f
+--- /dev/null
++++ b/include/linux/magic.h
+@@ -0,0 +1,38 @@
++#ifndef __LINUX_MAGIC_H__
++#define __LINUX_MAGIC_H__
++
++#define ADFS_SUPER_MAGIC 0xadf5
++#define AFFS_SUPER_MAGIC 0xadff
++#define AUTOFS_SUPER_MAGIC 0x0187
++#define CODA_SUPER_MAGIC 0x73757245
++#define EFS_SUPER_MAGIC 0x414A53
++#define EXT2_SUPER_MAGIC 0xEF53
++#define EXT3_SUPER_MAGIC 0xEF53
++#define EXT4_SUPER_MAGIC 0xEF53
++#define HPFS_SUPER_MAGIC 0xf995e849
++#define ISOFS_SUPER_MAGIC 0x9660
++#define JFFS2_SUPER_MAGIC 0x72b6
++
++#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
++#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
++#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
++#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
++
++#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
++#define NCP_SUPER_MAGIC 0x564c /* Guess, what 0x564c is :-) */
++#define NFS_SUPER_MAGIC 0x6969
++#define OPENPROM_SUPER_MAGIC 0x9fa1
++#define PROC_SUPER_MAGIC 0x9fa0
++#define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */
++
++#define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */
++ /* used by file system utilities that
++ look at the superblock, etc. */
++#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
++#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
++#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
++
++#define SMB_SUPER_MAGIC 0x517B
++#define USBDEVICE_SUPER_MAGIC 0x9fa2
++
++#endif /* __LINUX_MAGIC_H__ */
+diff --git a/include/linux/memory.h b/include/linux/memory.h
+index 8f04143..654ef55 100644
+--- a/include/linux/memory.h
++++ b/include/linux/memory.h
+@@ -57,7 +57,7 @@ struct memory_block {
+ struct notifier_block;
+ struct mem_section;
+
+-#ifndef CONFIG_MEMORY_HOTPLUG
++#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
+ static inline int memory_dev_init(void)
+ {
+ return 0;
+@@ -78,7 +78,7 @@ extern int remove_memory_block(unsigned
+ #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT)
+
+
+-#endif /* CONFIG_MEMORY_HOTPLUG */
++#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
+
+ #define hotplug_memory_notifier(fn, pri) { \
+ static struct notifier_block fn##_mem_nb = \
+diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
+index 218501c..7b54666 100644
+--- a/include/linux/memory_hotplug.h
++++ b/include/linux/memory_hotplug.h
+@@ -172,5 +172,7 @@ static inline int __remove_pages(struct
+ extern int add_memory(int nid, u64 start, u64 size);
+ extern int arch_add_memory(int nid, u64 start, u64 size);
+ extern int remove_memory(u64 start, u64 size);
++extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
++ int nr_pages);
+
+ #endif /* __LINUX_MEMORY_HOTPLUG_H */
+diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
+index 72440f0..daabb3a 100644
+--- a/include/linux/mempolicy.h
++++ b/include/linux/mempolicy.h
+@@ -150,7 +150,7 @@ extern void mpol_rebind_mm(struct mm_str
+ extern void mpol_fix_fork_child_flag(struct task_struct *p);
+ #define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x))
+
+-#ifdef CONFIG_CPUSET
++#ifdef CONFIG_CPUSETS
+ #define current_cpuset_is_being_rebound() \
+ (cpuset_being_rebound == current->cpuset)
+ #else
+@@ -162,9 +162,9 @@ extern struct zonelist *huge_zonelist(st
+ unsigned long addr);
+ extern unsigned slab_node(struct mempolicy *policy);
+
+-extern int policy_zone;
++extern enum zone_type policy_zone;
+
+-static inline void check_highest_zone(int k)
++static inline void check_highest_zone(enum zone_type k)
+ {
+ if (k > policy_zone)
+ policy_zone = k;
+diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
+index 1ecc3cc..916e8f7 100644
+--- a/include/linux/minix_fs.h
++++ b/include/linux/minix_fs.h
+@@ -1,6 +1,8 @@
+ #ifndef _LINUX_MINIX_FS_H
+ #define _LINUX_MINIX_FS_H
+
++#include <linux/magic.h>
++
+ /*
+ * The minix filesystem constants/structures
+ */
+@@ -19,10 +21,6 @@
+
+ #define MINIX_I_MAP_SLOTS 8
+ #define MINIX_Z_MAP_SLOTS 64
+-#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
+-#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+-#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
+-#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
+ #define MINIX_VALID_FS 0x0001 /* Clean fs. */
+ #define MINIX_ERROR_FS 0x0002 /* fs has errors. */
+
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index f0b135c..d538de9 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -15,6 +15,8 @@
+ #include <linux/fs.h>
+ #include <linux/mutex.h>
+ #include <linux/debug_locks.h>
++#include <linux/backing-dev.h>
++#include <linux/mm_types.h>
+
+ struct mempolicy;
+ struct anon_vma;
+@@ -197,6 +199,7 @@ struct vm_operations_struct {
+ void (*open)(struct vm_area_struct * area);
+ void (*close)(struct vm_area_struct * area);
+ struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);
++ unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address);
+ int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
+
+ /* notification that a previously read-only page is about to become
+@@ -214,61 +217,6 @@ struct vm_operations_struct {
+ struct mmu_gather;
+ struct inode;
+
+-/*
+- * Each physical page in the system has a struct page associated with
+- * it to keep track of whatever it is we are using the page for at the
+- * moment. Note that we have no way to track which tasks are using
+- * a page.
+- */
+-struct page {
+- unsigned long flags; /* Atomic flags, some possibly
+- * updated asynchronously */
+- atomic_t _count; /* Usage count, see below. */
+- atomic_t _mapcount; /* Count of ptes mapped in mms,
+- * to show when page is mapped
+- * & limit reverse map searches.
+- */
+- union {
+- struct {
+- unsigned long private; /* Mapping-private opaque data:
+- * usually used for buffer_heads
+- * if PagePrivate set; used for
+- * swp_entry_t if PageSwapCache;
+- * indicates order in the buddy
+- * system if PG_buddy is set.
+- */
+- struct address_space *mapping; /* If low bit clear, points to
+- * inode address_space, or NULL.
+- * If page mapped as anonymous
+- * memory, low bit is set, and
+- * it points to anon_vma object:
+- * see PAGE_MAPPING_ANON below.
+- */
+- };
+-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+- spinlock_t ptl;
+-#endif
+- };
+- pgoff_t index; /* Our offset within mapping. */
+- struct list_head lru; /* Pageout list, eg. active_list
+- * protected by zone->lru_lock !
+- */
+- /*
+- * On machines where all RAM is mapped into kernel address space,
+- * we can simply calculate the virtual address. On machines with
+- * highmem some memory is mapped into kernel virtual memory
+- * dynamically, so we need a place to store that address.
+- * Note that this field could be 16 bits on x86 ... ;)
+- *
+- * Architectures with slow multiplication can define
+- * WANT_PAGE_VIRTUAL in asm/page.h
+- */
+-#if defined(WANT_PAGE_VIRTUAL)
+- void *virtual; /* Kernel virtual address (NULL if
+- not kmapped, ie. highmem) */
+-#endif /* WANT_PAGE_VIRTUAL */
+-};
+-
+ #define page_private(page) ((page)->private)
+ #define set_page_private(page, v) ((page)->private = (v))
+
+@@ -278,6 +226,12 @@ struct page {
+ */
+ #include <linux/page-flags.h>
+
++#ifdef CONFIG_DEBUG_VM
++#define VM_BUG_ON(cond) BUG_ON(cond)
++#else
++#define VM_BUG_ON(condition) do { } while(0)
++#endif
++
+ /*
+ * Methods to modify the page usage count.
+ *
+@@ -292,12 +246,11 @@ struct page {
+ */
+
+ /*
+- * Drop a ref, return true if the logical refcount fell to zero (the page has
+- * no users)
++ * Drop a ref, return true if the refcount fell to zero (the page has no users)
+ */
+ static inline int put_page_testzero(struct page *page)
+ {
+- BUG_ON(atomic_read(&page->_count) == 0);
++ VM_BUG_ON(atomic_read(&page->_count) == 0);
+ return atomic_dec_and_test(&page->_count);
+ }
+
+@@ -307,11 +260,10 @@ static inline int put_page_testzero(stru
+ */
+ static inline int get_page_unless_zero(struct page *page)
+ {
++ VM_BUG_ON(PageCompound(page));
+ return atomic_inc_not_zero(&page->_count);
+ }
+
+-extern void FASTCALL(__page_cache_release(struct page *));
+-
+ static inline int page_count(struct page *page)
+ {
+ if (unlikely(PageCompound(page)))
+@@ -323,6 +275,7 @@ static inline void get_page(struct page
+ {
+ if (unlikely(PageCompound(page)))
+ page = (struct page *)page_private(page);
++ VM_BUG_ON(atomic_read(&page->_count) == 0);
+ atomic_inc(&page->_count);
+ }
+
+@@ -349,43 +302,55 @@ void split_page(struct page *page, unsig
+ * For the non-reserved pages, page_count(page) denotes a reference count.
+ * page_count() == 0 means the page is free. page->lru is then used for
+ * freelist management in the buddy allocator.
+- * page_count() == 1 means the page is used for exactly one purpose
+- * (e.g. a private data page of one process).
++ * page_count() > 0 means the page has been allocated.
++ *
++ * Pages are allocated by the slab allocator in order to provide memory
++ * to kmalloc and kmem_cache_alloc. In this case, the management of the
++ * page, and the fields in 'struct page' are the responsibility of mm/slab.c
++ * unless a particular usage is carefully commented. (the responsibility of
++ * freeing the kmalloc memory is the caller's, of course).
+ *
+- * A page may be used for kmalloc() or anyone else who does a
+- * __get_free_page(). In this case the page_count() is at least 1, and
+- * all other fields are unused but should be 0 or NULL. The
+- * management of this page is the responsibility of the one who uses
+- * it.
++ * A page may be used by anyone else who does a __get_free_page().
++ * In this case, page_count still tracks the references, and should only
++ * be used through the normal accessor functions. The top bits of page->flags
++ * and page->virtual store page management information, but all other fields
++ * are unused and could be used privately, carefully. The management of this
++ * page is the responsibility of the one who allocated it, and those who have
++ * subsequently been given references to it.
+ *
+- * The other pages (we may call them "process pages") are completely
++ * The other pages (we may call them "pagecache pages") are completely
+ * managed by the Linux memory manager: I/O, buffers, swapping etc.
+ * The following discussion applies only to them.
+ *
+- * A page may belong to an inode's memory mapping. In this case,
+- * page->mapping is the pointer to the inode, and page->index is the
+- * file offset of the page, in units of PAGE_CACHE_SIZE.
++ * A pagecache page contains an opaque `private' member, which belongs to the
++ * page's address_space. Usually, this is the address of a circular list of
++ * the page's disk buffers. PG_private must be set to tell the VM to call
++ * into the filesystem to release these pages.
+ *
+- * A page contains an opaque `private' member, which belongs to the
+- * page's address_space. Usually, this is the address of a circular
+- * list of the page's disk buffers.
++ * A page may belong to an inode's memory mapping. In this case, page->mapping
++ * is the pointer to the inode, and page->index is the file offset of the page,
++ * in units of PAGE_CACHE_SIZE.
+ *
+- * For pages belonging to inodes, the page_count() is the number of
+- * attaches, plus 1 if `private' contains something, plus one for
+- * the page cache itself.
++ * If pagecache pages are not associated with an inode, they are said to be
++ * anonymous pages. These may become associated with the swapcache, and in that
++ * case PG_swapcache is set, and page->private is an offset into the swapcache.
+ *
+- * Instead of keeping dirty/clean pages in per address-space lists, we instead
+- * now tag pages as dirty/under writeback in the radix tree.
++ * In either case (swapcache or inode backed), the pagecache itself holds one
++ * reference to the page. Setting PG_private should also increment the
++ * refcount. The each user mapping also has a reference to the page.
+ *
+- * There is also a per-mapping radix tree mapping index to the page
+- * in memory if present. The tree is rooted at mapping->root.
++ * The pagecache pages are stored in a per-mapping radix tree, which is
++ * rooted at mapping->page_tree, and indexed by offset.
++ * Where 2.4 and early 2.6 kernels kept dirty/clean pages in per-address_space
++ * lists, we instead now tag pages as dirty/writeback in the radix tree.
+ *
+- * All process pages can do I/O:
++ * All pagecache pages may be subject to I/O:
+ * - inode pages may need to be read from disk,
+ * - inode pages which have been modified and are MAP_SHARED may need
+- * to be written to disk,
+- * - private pages which have been modified may need to be swapped out
+- * to swap space and (later) to be read back into memory.
++ * to be written back to the inode on disk,
++ * - anonymous pages (including MAP_PRIVATE file mappings) which have been
++ * modified may need to be swapped out to swap space and (later) to be read
++ * back into memory.
+ */
+
+ /*
+@@ -463,7 +428,7 @@ void split_page(struct page *page, unsig
+ #define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1)
+ #define ZONETABLE_MASK ((1UL << ZONETABLE_SHIFT) - 1)
+
+-static inline unsigned long page_zonenum(struct page *page)
++static inline enum zone_type page_zonenum(struct page *page)
+ {
+ return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK;
+ }
+@@ -480,23 +445,33 @@ static inline struct zone *page_zone(str
+ return zone_table[page_zone_id(page)];
+ }
+
++static inline unsigned long zone_to_nid(struct zone *zone)
++{
++#ifdef CONFIG_NUMA
++ return zone->node;
++#else
++ return 0;
++#endif
++}
++
+ static inline unsigned long page_to_nid(struct page *page)
+ {
+ if (FLAGS_HAS_NODE)
+ return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
+ else
+- return page_zone(page)->zone_pgdat->node_id;
++ return zone_to_nid(page_zone(page));
+ }
+ static inline unsigned long page_to_section(struct page *page)
+ {
+ return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
+ }
+
+-static inline void set_page_zone(struct page *page, unsigned long zone)
++static inline void set_page_zone(struct page *page, enum zone_type zone)
+ {
+ page->flags &= ~(ZONES_MASK << ZONES_PGSHIFT);
+ page->flags |= (zone & ZONES_MASK) << ZONES_PGSHIFT;
+ }
++
+ static inline void set_page_node(struct page *page, unsigned long node)
+ {
+ page->flags &= ~(NODES_MASK << NODES_PGSHIFT);
+@@ -508,7 +483,7 @@ static inline void set_page_section(stru
+ page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
+ }
+
+-static inline void set_page_links(struct page *page, unsigned long zone,
++static inline void set_page_links(struct page *page, enum zone_type zone,
+ unsigned long node, unsigned long pfn)
+ {
+ set_page_zone(page, zone);
+@@ -521,11 +496,6 @@ static inline void set_page_links(struct
+ */
+ #include <linux/vmstat.h>
+
+-#ifndef CONFIG_DISCONTIGMEM
+-/* The array of struct pages - for discontigmem use pgdat->lmem_map */
+-extern struct page *mem_map;
+-#endif
+-
+ static __always_inline void *lowmem_page_address(struct page *page)
+ {
+ return __va(page_to_pfn(page) << PAGE_SHIFT);
+@@ -623,6 +593,13 @@ static inline int page_mapped(struct pag
+ */
+ #define NOPAGE_SIGBUS (NULL)
+ #define NOPAGE_OOM ((struct page *) (-1))
++#define NOPAGE_REFAULT ((struct page *) (-2)) /* Return to userspace, rerun */
++
++/*
++ * Error return values for the *_nopfn functions
++ */
++#define NOPFN_SIGBUS ((unsigned long) -1)
++#define NOPFN_OOM ((unsigned long) -2)
+
+ /*
+ * Different kinds of faults, as returned by handle_mm_fault().
+@@ -767,7 +744,9 @@ int get_user_pages(struct task_struct *t
+ int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+ void print_bad_pte(struct vm_area_struct *, pte_t, unsigned long);
+
+-int __set_page_dirty_buffers(struct page *page);
++extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
++extern void do_invalidatepage(struct page *page, unsigned long offset);
++
+ int __set_page_dirty_nobuffers(struct page *page);
+ int redirty_page_for_writepage(struct writeback_control *wbc,
+ struct page *page);
+@@ -802,6 +781,39 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++/*
++ * Some shared mappigns will want the pages marked read-only
++ * to track write events. If so, we'll downgrade vm_page_prot
++ * to the private version (using protection_map[] without the
++ * VM_SHARED bit).
++ */
++static inline int vma_wants_writenotify(struct vm_area_struct *vma)
++{
++ unsigned int vm_flags = vma->vm_flags;
++
++ /* If it was private or non-writable, the write bit is already clear */
++ if ((vm_flags & (VM_WRITE|VM_SHARED)) != ((VM_WRITE|VM_SHARED)))
++ return 0;
++
++ /* The backer wishes to know when pages are first written to? */
++ if (vma->vm_ops && vma->vm_ops->page_mkwrite)
++ return 1;
++
++ /* The open routine did something to the protections already? */
++ if (pgprot_val(vma->vm_page_prot) !=
++ pgprot_val(protection_map[vm_flags &
++ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]))
++ return 0;
++
++ /* Specialty mapping? */
++ if (vm_flags & (VM_PFNMAP|VM_INSERTPAGE))
++ return 0;
++
++ /* Can the mapping track the dirty pages? */
++ return vma->vm_file && vma->vm_file->f_mapping &&
++ mapping_cap_account_dirty(vma->vm_file->f_mapping);
++}
++
+ extern pte_t *FASTCALL(get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl));
+
+ int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address);
+@@ -879,12 +891,64 @@ extern void free_area_init(unsigned long
+ extern void free_area_init_node(int nid, pg_data_t *pgdat,
+ unsigned long * zones_size, unsigned long zone_start_pfn,
+ unsigned long *zholes_size);
++#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
++/*
++ * With CONFIG_ARCH_POPULATES_NODE_MAP set, an architecture may initialise its
++ * zones, allocate the backing mem_map and account for memory holes in a more
++ * architecture independent manner. This is a substitute for creating the
++ * zone_sizes[] and zholes_size[] arrays and passing them to
++ * free_area_init_node()
++ *
++ * An architecture is expected to register range of page frames backed by
++ * physical memory with add_active_range() before calling
++ * free_area_init_nodes() passing in the PFN each zone ends at. At a basic
++ * usage, an architecture is expected to do something like
++ *
++ * unsigned long max_zone_pfns[MAX_NR_ZONES] = {max_dma, max_normal_pfn,
++ * max_highmem_pfn};
++ * for_each_valid_physical_page_range()
++ * add_active_range(node_id, start_pfn, end_pfn)
++ * free_area_init_nodes(max_zone_pfns);
++ *
++ * If the architecture guarantees that there are no holes in the ranges
++ * registered with add_active_range(), free_bootmem_active_regions()
++ * will call free_bootmem_node() for each registered physical page range.
++ * Similarly sparse_memory_present_with_active_regions() calls
++ * memory_present() for each range when SPARSEMEM is enabled.
++ *
++ * See mm/page_alloc.c for more information on each function exposed by
++ * CONFIG_ARCH_POPULATES_NODE_MAP
++ */
++extern void free_area_init_nodes(unsigned long *max_zone_pfn);
++extern void add_active_range(unsigned int nid, unsigned long start_pfn,
++ unsigned long end_pfn);
++extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
++ unsigned long new_end_pfn);
++extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn,
++ unsigned long end_pfn);
++extern void remove_all_active_ranges(void);
++extern unsigned long absent_pages_in_range(unsigned long start_pfn,
++ unsigned long end_pfn);
++extern void get_pfn_range_for_nid(unsigned int nid,
++ unsigned long *start_pfn, unsigned long *end_pfn);
++extern unsigned long find_min_pfn_with_active_regions(void);
++extern unsigned long find_max_pfn_with_active_regions(void);
++extern void free_bootmem_with_active_regions(int nid,
++ unsigned long max_low_pfn);
++extern void sparse_memory_present_with_active_regions(int nid);
++#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
++extern int early_pfn_to_nid(unsigned long pfn);
++#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
++#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
++extern void set_dma_reserve(unsigned long new_dma_reserve);
+ extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long);
+ extern void setup_per_zone_pages_min(void);
+ extern void mem_init(void);
+ extern void show_mem(void);
+ extern void si_meminfo(struct sysinfo * val);
+ extern void si_meminfo_node(struct sysinfo *val, int nid);
++extern void zonetable_add(struct zone *zone, int nid, enum zone_type zid,
++ unsigned long pfn, unsigned long size);
+
+ #ifdef CONFIG_NUMA
+ extern void setup_per_cpu_pageset(void);
+@@ -1013,6 +1077,7 @@ static inline unsigned long vma_pages(st
+ return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ }
+
++pgprot_t vm_get_page_prot(unsigned long vm_flags);
+ struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr);
+ struct page *vmalloc_to_page(void *addr);
+ unsigned long vmalloc_to_pfn(void *addr);
+@@ -1038,12 +1103,7 @@ static inline void vm_stat_account(struc
+
+ #ifndef CONFIG_DEBUG_PAGEALLOC
+ static inline void
+-kernel_map_pages(struct page *page, int numpages, int enable)
+-{
+- if (!PageHighMem(page) && !enable)
+- debug_check_no_locks_freed(page_address(page),
+- numpages * PAGE_SIZE);
+-}
++kernel_map_pages(struct page *page, int numpages, int enable) {}
+ #endif
+
+ extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
+@@ -1055,9 +1115,6 @@ int in_gate_area_no_task(unsigned long a
+ #define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);})
+ #endif /* __HAVE_ARCH_GATE_AREA */
+
+-/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
+-#define OOM_DISABLE -17
+-
+ int drop_caches_sysctl_handler(struct ctl_table *, int, struct file *,
+ void __user *, size_t *, loff_t *);
+ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
+@@ -1071,7 +1128,7 @@ void drop_slab(void);
+ extern int randomize_va_space;
+ #endif
+
+-const char *arch_vma_name(struct vm_area_struct *vma);
++__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma);
+
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_MM_H */
+diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
+new file mode 100644
+index 0000000..c3852fd
+--- /dev/null
++++ b/include/linux/mm_types.h
+@@ -0,0 +1,67 @@
++#ifndef _LINUX_MM_TYPES_H
++#define _LINUX_MM_TYPES_H
++
++#include <linux/types.h>
++#include <linux/threads.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++
++struct address_space;
++
++/*
++ * Each physical page in the system has a struct page associated with
++ * it to keep track of whatever it is we are using the page for at the
++ * moment. Note that we have no way to track which tasks are using
++ * a page, though if it is a pagecache page, rmap structures can tell us
++ * who is mapping it.
++ */
++struct page {
++ unsigned long flags; /* Atomic flags, some possibly
++ * updated asynchronously */
++ atomic_t _count; /* Usage count, see below. */
++ atomic_t _mapcount; /* Count of ptes mapped in mms,
++ * to show when page is mapped
++ * & limit reverse map searches.
++ */
++ union {
++ struct {
++ unsigned long private; /* Mapping-private opaque data:
++ * usually used for buffer_heads
++ * if PagePrivate set; used for
++ * swp_entry_t if PageSwapCache;
++ * indicates order in the buddy
++ * system if PG_buddy is set.
++ */
++ struct address_space *mapping; /* If low bit clear, points to
++ * inode address_space, or NULL.
++ * If page mapped as anonymous
++ * memory, low bit is set, and
++ * it points to anon_vma object:
++ * see PAGE_MAPPING_ANON below.
++ */
++ };
++#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
++ spinlock_t ptl;
++#endif
++ };
++ pgoff_t index; /* Our offset within mapping. */
++ struct list_head lru; /* Pageout list, eg. active_list
++ * protected by zone->lru_lock !
++ */
++ /*
++ * On machines where all RAM is mapped into kernel address space,
++ * we can simply calculate the virtual address. On machines with
++ * highmem some memory is mapped into kernel virtual memory
++ * dynamically, so we need a place to store that address.
++ * Note that this field could be 16 bits on x86 ... ;)
++ *
++ * Architectures with slow multiplication can define
++ * WANT_PAGE_VIRTUAL in asm/page.h
++ */
++#if defined(WANT_PAGE_VIRTUAL)
++ void *virtual; /* Kernel virtual address (NULL if
++ not kmapped, ie. highmem) */
++#endif /* WANT_PAGE_VIRTUAL */
++};
++
++#endif /* _LINUX_MM_TYPES_H */
+diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
+index ba095ae..587264a 100644
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -85,6 +85,8 @@ struct mmc_host {
+ unsigned long caps; /* Host capabilities */
+
+ #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
++#define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */
++#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */
+
+ /* host specific block data */
+ unsigned int max_seg_size; /* see blk_queue_max_segment_size */
+diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
+index 627e2c0..a3594df 100644
+--- a/include/linux/mmc/mmc.h
++++ b/include/linux/mmc/mmc.h
+@@ -68,7 +68,6 @@ struct mmc_command {
+ struct mmc_data {
+ unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
+ unsigned int timeout_clks; /* data timeout (in clocks) */
+- unsigned int blksz_bits; /* data block size */
+ unsigned int blksz; /* data block size */
+ unsigned int blocks; /* number of blocks */
+ unsigned int error; /* data error */
+diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
+index 81c3f77..08dec8d 100644
+--- a/include/linux/mmc/protocol.h
++++ b/include/linux/mmc/protocol.h
+@@ -83,6 +83,7 @@
+
+ /* Application commands */
+ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
++#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
+ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
+ #define SD_APP_SEND_SCR 51 /* adtc R1 */
+
+diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
+index f45163c..e06683e 100644
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -51,12 +51,14 @@ enum zone_stat_item {
+ NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
+ only modified from process context */
+ NR_FILE_PAGES,
+- NR_SLAB, /* Pages used by slab allocator */
++ NR_SLAB_RECLAIMABLE,
++ NR_SLAB_UNRECLAIMABLE,
+ NR_PAGETABLE, /* used for pagetables */
+ NR_FILE_DIRTY,
+ NR_WRITEBACK,
+ NR_UNSTABLE_NFS, /* NFS unstable pages */
+ NR_BOUNCE,
++ NR_VMSCAN_WRITE,
+ #ifdef CONFIG_NUMA
+ NUMA_HIT, /* allocated in intended node */
+ NUMA_MISS, /* allocated in non intended node */
+@@ -88,53 +90,68 @@ struct per_cpu_pageset {
+ #define zone_pcp(__z, __cpu) (&(__z)->pageset[(__cpu)])
+ #endif
+
+-#define ZONE_DMA 0
+-#define ZONE_DMA32 1
+-#define ZONE_NORMAL 2
+-#define ZONE_HIGHMEM 3
+-
+-#define MAX_NR_ZONES 4 /* Sync this with ZONES_SHIFT */
+-#define ZONES_SHIFT 2 /* ceil(log2(MAX_NR_ZONES)) */
+-
++enum zone_type {
++ /*
++ * ZONE_DMA is used when there are devices that are not able
++ * to do DMA to all of addressable memory (ZONE_NORMAL). Then we
++ * carve out the portion of memory that is needed for these devices.
++ * The range is arch specific.
++ *
++ * Some examples
++ *
++ * Architecture Limit
++ * ---------------------------
++ * parisc, ia64, sparc <4G
++ * s390 <2G
++ * arm26 <48M
++ * arm Various
++ * alpha Unlimited or 0-16MB.
++ *
++ * i386, x86_64 and multiple other arches
++ * <16M.
++ */
++ ZONE_DMA,
++#ifdef CONFIG_ZONE_DMA32
++ /*
++ * x86_64 needs two ZONE_DMAs because it supports devices that are
++ * only able to do DMA to the lower 16M but also 32 bit devices that
++ * can only do DMA areas below 4G.
++ */
++ ZONE_DMA32,
++#endif
++ /*
++ * Normal addressable memory is in ZONE_NORMAL. DMA operations can be
++ * performed on pages in ZONE_NORMAL if the DMA devices support
++ * transfers to all addressable memory.
++ */
++ ZONE_NORMAL,
++#ifdef CONFIG_HIGHMEM
++ /*
++ * A memory area that is only addressable by the kernel through
++ * mapping portions into its own address space. This is for example
++ * used by i386 to allow the kernel to address the memory beyond
++ * 900MB. The kernel will set up special mappings (page
++ * table entries on i386) for each page that the kernel needs to
++ * access.
++ */
++ ZONE_HIGHMEM,
++#endif
++ MAX_NR_ZONES
++};
+
+ /*
+ * When a memory allocation must conform to specific limitations (such
+ * as being suitable for DMA) the caller will pass in hints to the
+ * allocator in the gfp_mask, in the zone modifier bits. These bits
+ * are used to select a priority ordered list of memory zones which
+- * match the requested limits. GFP_ZONEMASK defines which bits within
+- * the gfp_mask should be considered as zone modifiers. Each valid
+- * combination of the zone modifier bits has a corresponding list
+- * of zones (in node_zonelists). Thus for two zone modifiers there
+- * will be a maximum of 4 (2 ** 2) zonelists, for 3 modifiers there will
+- * be 8 (2 ** 3) zonelists. GFP_ZONETYPES defines the number of possible
+- * combinations of zone modifiers in "zone modifier space".
+- *
+- * As an optimisation any zone modifier bits which are only valid when
+- * no other zone modifier bits are set (loners) should be placed in
+- * the highest order bits of this field. This allows us to reduce the
+- * extent of the zonelists thus saving space. For example in the case
+- * of three zone modifier bits, we could require up to eight zonelists.
+- * If the left most zone modifier is a "loner" then the highest valid
+- * zonelist would be four allowing us to allocate only five zonelists.
+- * Use the first form for GFP_ZONETYPES when the left most bit is not
+- * a "loner", otherwise use the second.
+- *
+- * NOTE! Make sure this matches the zones in <linux/gfp.h>
++ * match the requested limits. See gfp_zone() in include/linux/gfp.h
+ */
+-#define GFP_ZONEMASK 0x07
+-/* #define GFP_ZONETYPES (GFP_ZONEMASK + 1) */ /* Non-loner */
+-#define GFP_ZONETYPES ((GFP_ZONEMASK + 1) / 2 + 1) /* Loner */
+
+-/*
+- * On machines where it is needed (eg PCs) we divide physical memory
+- * into multiple physical zones. On a 32bit PC we have 4 zones:
+- *
+- * ZONE_DMA < 16 MB ISA DMA capable memory
+- * ZONE_DMA32 0 MB Empty
+- * ZONE_NORMAL 16-896 MB direct mapped by the kernel
+- * ZONE_HIGHMEM > 896 MB only page cache and user processes
+- */
++#if !defined(CONFIG_ZONE_DMA32) && !defined(CONFIG_HIGHMEM)
++#define ZONES_SHIFT 1
++#else
++#define ZONES_SHIFT 2
++#endif
+
+ struct zone {
+ /* Fields commonly accessed by the page allocator */
+@@ -151,10 +168,12 @@ struct zone {
+ unsigned long lowmem_reserve[MAX_NR_ZONES];
+
+ #ifdef CONFIG_NUMA
++ int node;
+ /*
+ * zone reclaim becomes active if more unmapped pages exist.
+ */
+- unsigned long min_unmapped_ratio;
++ unsigned long min_unmapped_pages;
++ unsigned long min_slab_pages;
+ struct per_cpu_pageset *pageset[NR_CPUS];
+ #else
+ struct per_cpu_pageset pageset[NR_CPUS];
+@@ -199,13 +218,9 @@ struct zone {
+ * under - it drives the swappiness decision: whether to unmap mapped
+ * pages.
+ *
+- * temp_priority is used to remember the scanning priority at which
+- * this zone was successfully refilled to free_pages == pages_high.
+- *
+- * Access to both these fields is quite racy even on uniprocessor. But
++ * Access to both this field is quite racy even on uniprocessor. But
+ * it is expected to average out OK.
+ */
+- int temp_priority;
+ int prev_priority;
+
+
+@@ -266,7 +281,6 @@ struct zone {
+ char *name;
+ } ____cacheline_internodealigned_in_smp;
+
+-
+ /*
+ * The "priority" of VM scanning is how much of the queues we will scan in one
+ * go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the
+@@ -289,6 +303,18 @@ struct zonelist {
+ struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited
+ };
+
++#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
++struct node_active_region {
++ unsigned long start_pfn;
++ unsigned long end_pfn;
++ int nid;
++};
++#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
++
++#ifndef CONFIG_DISCONTIGMEM
++/* The array of struct pages - for discontigmem use pgdat->lmem_map */
++extern struct page *mem_map;
++#endif
+
+ /*
+ * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
+@@ -304,7 +330,7 @@ struct zonelist {
+ struct bootmem_data;
+ typedef struct pglist_data {
+ struct zone node_zones[MAX_NR_ZONES];
+- struct zonelist node_zonelists[GFP_ZONETYPES];
++ struct zonelist node_zonelists[MAX_NR_ZONES];
+ int nr_zones;
+ #ifdef CONFIG_FLAT_NODE_MEM_MAP
+ struct page *node_mem_map;
+@@ -373,12 +399,16 @@ static inline int populated_zone(struct
+ return (!!zone->present_pages);
+ }
+
+-static inline int is_highmem_idx(int idx)
++static inline int is_highmem_idx(enum zone_type idx)
+ {
++#ifdef CONFIG_HIGHMEM
+ return (idx == ZONE_HIGHMEM);
++#else
++ return 0;
++#endif
+ }
+
+-static inline int is_normal_idx(int idx)
++static inline int is_normal_idx(enum zone_type idx)
+ {
+ return (idx == ZONE_NORMAL);
+ }
+@@ -391,7 +421,11 @@ static inline int is_normal_idx(int idx)
+ */
+ static inline int is_highmem(struct zone *zone)
+ {
++#ifdef CONFIG_HIGHMEM
+ return zone == zone->zone_pgdat->node_zones + ZONE_HIGHMEM;
++#else
++ return 0;
++#endif
+ }
+
+ static inline int is_normal(struct zone *zone)
+@@ -401,7 +435,11 @@ static inline int is_normal(struct zone
+
+ static inline int is_dma32(struct zone *zone)
+ {
++#ifdef CONFIG_ZONE_DMA32
+ return zone == zone->zone_pgdat->node_zones + ZONE_DMA32;
++#else
++ return 0;
++#endif
+ }
+
+ static inline int is_dma(struct zone *zone)
+@@ -421,6 +459,8 @@ int percpu_pagelist_fraction_sysctl_hand
+ void __user *, size_t *, loff_t *);
+ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *, int,
+ struct file *, void __user *, size_t *, loff_t *);
++int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *, int,
++ struct file *, void __user *, size_t *, loff_t *);
+
+ #include <linux/topology.h>
+ /* Returns the number of the current Node. */
+@@ -488,7 +528,8 @@ extern struct zone *next_zone(struct zon
+
+ #endif
+
+-#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
++#if !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) && \
++ !defined(CONFIG_ARCH_POPULATES_NODE_MAP)
+ #define early_pfn_to_nid(nid) (0UL)
+ #endif
+
+@@ -629,6 +670,12 @@ void sparse_init(void);
+ #define sparse_index_init(_sec, _nid) do {} while (0)
+ #endif /* CONFIG_SPARSEMEM */
+
++#ifdef CONFIG_NODES_SPAN_OTHER_NODES
++#define early_pfn_in_nid(pfn, nid) (early_pfn_to_nid(pfn) == (nid))
++#else
++#define early_pfn_in_nid(pfn, nid) (1)
++#endif
++
+ #ifndef early_pfn_valid
+ #define early_pfn_valid(pfn) (1)
+ #endif
+diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
+index f697770..e0c393c 100644
+--- a/include/linux/mod_devicetable.h
++++ b/include/linux/mod_devicetable.h
+@@ -148,6 +148,17 @@ struct ccw_device_id {
+ #define CCW_DEVICE_ID_MATCH_DEVICE_TYPE 0x04
+ #define CCW_DEVICE_ID_MATCH_DEVICE_MODEL 0x08
+
++/* s390 AP bus devices */
++struct ap_device_id {
++ __u16 match_flags; /* which fields to match against */
++ __u8 dev_type; /* device type */
++ __u8 pad1;
++ __u32 pad2;
++ kernel_ulong_t driver_info;
++};
++
++#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01
++
+
+ #define PNP_ID_LEN 8
+ #define PNP_MAX_DEVICES 8
+@@ -297,4 +308,16 @@ struct input_device_id {
+ kernel_ulong_t driver_info;
+ };
+
++/* EISA */
++
++#define EISA_SIG_LEN 8
++
++/* The EISA signature, in ASCII form, null terminated */
++struct eisa_device_id {
++ char sig[EISA_SIG_LEN];
++ kernel_ulong_t driver_data;
++};
++
++#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s"
++
+ #endif /* LINUX_MOD_DEVICETABLE_H */
+diff --git a/include/linux/module.h b/include/linux/module.h
+index 0dfb794..d1d00ce 100644
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -156,6 +156,11 @@ extern struct module __this_module;
+ */
+ #define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+
++/* Optional firmware file (or files) needed by the module
++ * format is simply firmware file name. Multiple firmware
++ * files require multiple MODULE_FIRMWARE() specifiers */
++#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
++
+ /* Given an address, look for it in the exception tables */
+ const struct exception_table_entry *search_exception_tables(unsigned long add);
+
+@@ -227,17 +232,17 @@ enum module_state
+ };
+
+ /* Similar stuff for section attributes. */
+-#define MODULE_SECT_NAME_LEN 32
+ struct module_sect_attr
+ {
+ struct module_attribute mattr;
+- char name[MODULE_SECT_NAME_LEN];
++ char *name;
+ unsigned long address;
+ };
+
+ struct module_sect_attrs
+ {
+ struct attribute_group grp;
++ int nsections;
+ struct module_sect_attr attrs[0];
+ };
+
+@@ -312,8 +317,7 @@ struct module
+ /* Am I unsafe to unload? */
+ int unsafe;
+
+- /* Am I GPL-compatible */
+- int license_gplok;
++ unsigned int taints; /* same bits as kernel:tainted */
+
+ #ifdef CONFIG_MODULE_UNLOAD
+ /* Reference counts */
+diff --git a/include/linux/mpage.h b/include/linux/mpage.h
+index 3ca8804..cc5fb75 100644
+--- a/include/linux/mpage.h
++++ b/include/linux/mpage.h
+@@ -9,6 +9,7 @@
+ * (And no, it doesn't do the #ifdef __MPAGE_H thing, and it doesn't do
+ * nested includes. Get it right in the .c file).
+ */
++#ifdef CONFIG_BLOCK
+
+ struct writeback_control;
+ typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
+@@ -21,8 +22,4 @@ int mpage_writepages(struct address_spac
+ int mpage_writepage(struct page *page, get_block_t *get_block,
+ struct writeback_control *wbc);
+
+-static inline int
+-generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
+-{
+- return mpage_writepages(mapping, wbc, NULL);
+-}
++#endif
+diff --git a/include/linux/mroute.h b/include/linux/mroute.h
+index e05d54a..7da2cee 100644
+--- a/include/linux/mroute.h
++++ b/include/linux/mroute.h
+@@ -142,7 +142,7 @@ struct vif_device
+ unsigned long rate_limit; /* Traffic shaping (NI) */
+ unsigned char threshold; /* TTL threshold */
+ unsigned short flags; /* Control flags */
+- __u32 local,remote; /* Addresses(remote for tunnels)*/
++ __be32 local,remote; /* Addresses(remote for tunnels)*/
+ int link; /* Physical interface index */
+ };
+
+@@ -151,8 +151,8 @@ struct vif_device
+ struct mfc_cache
+ {
+ struct mfc_cache *next; /* Next entry on cache line */
+- __u32 mfc_mcastgrp; /* Group the entry belongs to */
+- __u32 mfc_origin; /* Source of packet */
++ __be32 mfc_mcastgrp; /* Group the entry belongs to */
++ __be32 mfc_origin; /* Source of packet */
+ vifi_t mfc_parent; /* Source interface */
+ int mfc_flags; /* Flags on line */
+
+@@ -179,9 +179,9 @@ struct mfc_cache
+ #define MFC_LINES 64
+
+ #ifdef __BIG_ENDIAN
+-#define MFC_HASH(a,b) ((((a)>>24)^((b)>>26))&(MFC_LINES-1))
++#define MFC_HASH(a,b) (((((__force u32)(__be32)a)>>24)^(((__force u32)(__be32)b)>>26))&(MFC_LINES-1))
+ #else
+-#define MFC_HASH(a,b) (((a)^((b)>>2))&(MFC_LINES-1))
++#define MFC_HASH(a,b) ((((__force u32)(__be32)a)^(((__force u32)(__be32)b)>>2))&(MFC_LINES-1))
+ #endif
+
+ #endif
+@@ -213,8 +213,8 @@ struct pimreghdr
+ {
+ __u8 type;
+ __u8 reserved;
+- __u16 csum;
+- __u32 flags;
++ __be16 csum;
++ __be32 flags;
+ };
+
+ extern int pim_rcv_v1(struct sk_buff *);
+diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
+index d9035c7..ce6c858 100644
+--- a/include/linux/msdos_fs.h
++++ b/include/linux/msdos_fs.h
+@@ -1,6 +1,8 @@
+ #ifndef _LINUX_MSDOS_FS_H
+ #define _LINUX_MSDOS_FS_H
+
++#include <linux/magic.h>
++
+ /*
+ * The MS-DOS filesystem constants/structures
+ */
+@@ -18,8 +20,6 @@
+ #define CT_LE_L(v) cpu_to_le32(v)
+
+
+-#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
+-
+ #define MSDOS_ROOT_INO 1 /* == MINIX_ROOT_INO */
+ #define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */
+
+@@ -204,6 +204,7 @@ struct fat_mount_options {
+ unicode_xlate:1, /* create escape sequences for unhandled Unicode */
+ numtail:1, /* Does first alias have a numeric '~1' type tail? */
+ atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */
++ flush:1, /* write things quickly */
+ nocase:1; /* Does this need case conversion? 0=need case conversion*/
+ };
+
+@@ -412,6 +413,8 @@ extern int fat_sync_inode(struct inode *
+ extern int fat_fill_super(struct super_block *sb, void *data, int silent,
+ struct inode_operations *fs_dir_inode_ops, int isvfat);
+
++extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
++ struct inode *i2);
+ /* fat/misc.c */
+ extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
+ extern void fat_clusters_flush(struct super_block *sb);
+diff --git a/include/linux/msi.h b/include/linux/msi.h
+new file mode 100644
+index 0000000..c7ef943
+--- /dev/null
++++ b/include/linux/msi.h
+@@ -0,0 +1,49 @@
++#ifndef LINUX_MSI_H
++#define LINUX_MSI_H
++
++struct msi_msg {
++ u32 address_lo; /* low 32 bits of msi message address */
++ u32 address_hi; /* high 32 bits of msi message address */
++ u32 data; /* 16 bits of msi message data */
++};
++
++/* Heper functions */
++extern void mask_msi_irq(unsigned int irq);
++extern void unmask_msi_irq(unsigned int irq);
++extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
++
++extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
++
++struct msi_desc {
++ struct {
++ __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
++ __u8 maskbit : 1; /* mask-pending bit supported ? */
++ __u8 unused : 1;
++ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
++ __u8 pos; /* Location of the msi capability */
++ __u16 entry_nr; /* specific enabled entry */
++ unsigned default_irq; /* default pre-assigned irq */
++ }msi_attrib;
++
++ struct {
++ __u16 head;
++ __u16 tail;
++ }link;
++
++ void __iomem *mask_base;
++ struct pci_dev *dev;
++
++#ifdef CONFIG_PM
++ /* PM save area for MSIX address/data */
++ struct msi_msg msg_save;
++#endif
++};
++
++/*
++ * The arch hook for setup up msi irqs
++ */
++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
++void arch_teardown_msi_irq(unsigned int irq);
++
++
++#endif /* LINUX_MSI_H */
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 0b4cd2f..8b3ef41 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -27,9 +27,17 @@
+ struct mtd_info;
+ /* Scan and identify a NAND device */
+ extern int nand_scan (struct mtd_info *mtd, int max_chips);
++/* Separate phases of nand_scan(), allowing board driver to intervene
++ * and override command or ECC setup according to flash type */
++extern int nand_scan_ident(struct mtd_info *mtd, int max_chips);
++extern int nand_scan_tail(struct mtd_info *mtd);
++
+ /* Free resources held by the NAND device */
+ extern void nand_release (struct mtd_info *mtd);
+
++/* Internal helper for board drivers which need to override command function */
++extern void nand_wait_ready(struct mtd_info *mtd);
++
+ /* The maximum number of NAND chips in an array */
+ #define NAND_MAX_CHIPS 8
+
+@@ -178,7 +186,9 @@ typedef enum {
+ #define NAND_USE_FLASH_BBT 0x00010000
+ /* This option skips the bbt scan during initialization. */
+ #define NAND_SKIP_BBTSCAN 0x00020000
+-
++/* This option is defined if the board driver allocates its own buffers
++ (e.g. because it needs them DMA-coherent */
++#define NAND_OWN_BUFFERS 0x00040000
+ /* Options set by nand scan */
+ /* Nand scan has allocated controller struct */
+ #define NAND_CONTROLLER_ALLOC 0x80000000
+@@ -228,6 +238,8 @@ struct nand_hw_control {
+ * be provided if an hardware ECC is available
+ * @calculate: function for ecc calculation or readback from ecc hardware
+ * @correct: function for ecc correction, matching to ecc generator (sw/hw)
++ * @read_page_raw: function to read a raw page without ECC
++ * @write_page_raw: function to write a raw page without ECC
+ * @read_page: function to read a page according to the ecc generator requirements
+ * @write_page: function to write a page according to the ecc generator requirements
+ * @read_oob: function to read chip OOB data
+@@ -249,6 +261,12 @@ struct nand_ecc_ctrl {
+ int (*correct)(struct mtd_info *mtd, uint8_t *dat,
+ uint8_t *read_ecc,
+ uint8_t *calc_ecc);
++ int (*read_page_raw)(struct mtd_info *mtd,
++ struct nand_chip *chip,
++ uint8_t *buf);
++ void (*write_page_raw)(struct mtd_info *mtd,
++ struct nand_chip *chip,
++ const uint8_t *buf);
+ int (*read_page)(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint8_t *buf);
+@@ -337,6 +355,7 @@ struct nand_buffers {
+ * @priv: [OPTIONAL] pointer to private chip date
+ * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
+ * (determine if errors are correctable)
++ * @write_page: [REPLACEABLE] High-level page write function
+ */
+
+ struct nand_chip {
+@@ -359,6 +378,8 @@ struct nand_chip {
+ void (*erase_cmd)(struct mtd_info *mtd, int page);
+ int (*scan_bbt)(struct mtd_info *mtd);
+ int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
++ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int page, int cached, int raw);
+
+ int chip_delay;
+ unsigned int options;
+@@ -380,7 +401,7 @@ struct nand_chip {
+ struct nand_ecclayout *ecclayout;
+
+ struct nand_ecc_ctrl ecc;
+- struct nand_buffers buffers;
++ struct nand_buffers *buffers;
+ struct nand_hw_control hwcontrol;
+
+ struct mtd_oob_ops ops;
+diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
+index 1f49721..6f045b5 100644
+--- a/include/linux/mtd/onenand.h
++++ b/include/linux/mtd/onenand.h
+@@ -1,7 +1,7 @@
+ /*
+ * linux/include/linux/mtd/onenand.h
+ *
+- * Copyright (C) 2005 Samsung Electronics
++ * Copyright (C) 2005-2006 Samsung Electronics
+ * Kyungmin Park <kyungmin.park at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+@@ -96,6 +96,7 @@ struct onenand_chip {
+ void __iomem *base;
+ unsigned int chipsize;
+ unsigned int device_id;
++ unsigned int version_id;
+ unsigned int density_mask;
+ unsigned int options;
+
+@@ -149,7 +150,8 @@ struct onenand_chip {
+ /*
+ * Options bits
+ */
+-#define ONENAND_CONT_LOCK (0x0001)
++#define ONENAND_HAS_CONT_LOCK (0x0001)
++#define ONENAND_HAS_UNLOCK_ALL (0x0002)
+ #define ONENAND_PAGEBUF_ALLOC (0x1000)
+
+ /*
+diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
+index 4a72818..9e409fe 100644
+--- a/include/linux/mtd/onenand_regs.h
++++ b/include/linux/mtd/onenand_regs.h
+@@ -3,7 +3,7 @@
+ *
+ * OneNAND Register header file
+ *
+- * Copyright (C) 2005 Samsung Electronics
++ * Copyright (C) 2005-2006 Samsung Electronics
+ *
+ * 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
+@@ -72,6 +72,7 @@
+ #define ONENAND_DEVICE_VCC_MASK (0x3)
+
+ #define ONENAND_DEVICE_DENSITY_512Mb (0x002)
++#define ONENAND_DEVICE_DENSITY_1Gb (0x003)
+
+ /*
+ * Version ID Register F002h (R)
+@@ -110,6 +111,7 @@
+ #define ONENAND_CMD_UNLOCK (0x23)
+ #define ONENAND_CMD_LOCK (0x2A)
+ #define ONENAND_CMD_LOCK_TIGHT (0x2C)
++#define ONENAND_CMD_UNLOCK_ALL (0x27)
+ #define ONENAND_CMD_ERASE (0x94)
+ #define ONENAND_CMD_RESET (0xF0)
+ #define ONENAND_CMD_OTP_ACCESS (0x65)
+diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h
+index 2332eda..9667863 100644
+--- a/include/linux/mtd/plat-ram.h
++++ b/include/linux/mtd/plat-ram.h
+@@ -1,4 +1,4 @@
+-/* linux/include/mtd/plat-ram.h
++/* linux/include/linux/mtd/plat-ram.h
+ *
+ * (c) 2004 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index 45511a5..f5f1960 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -1,6 +1,7 @@
+ #ifndef _LINUX_NAMEI_H
+ #define _LINUX_NAMEI_H
+
++#include <linux/dcache.h>
+ #include <linux/linkage.h>
+
+ struct vfsmount;
+@@ -54,6 +55,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LA
+ #define LOOKUP_OPEN (0x0100)
+ #define LOOKUP_CREATE (0x0200)
+ #define LOOKUP_ACCESS (0x0400)
++#define LOOKUP_CHDIR (0x0800)
+
+ extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *));
+ extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *));
+diff --git a/include/linux/namespace.h b/include/linux/namespace.h
+index 3abc8e3..d137009 100644
+--- a/include/linux/namespace.h
++++ b/include/linux/namespace.h
+@@ -4,6 +4,7 @@
+
+ #include <linux/mount.h>
+ #include <linux/sched.h>
++#include <linux/nsproxy.h>
+
+ struct namespace {
+ atomic_t count;
+@@ -26,11 +27,8 @@ static inline void put_namespace(struct
+
+ static inline void exit_namespace(struct task_struct *p)
+ {
+- struct namespace *namespace = p->namespace;
++ struct namespace *namespace = p->nsproxy->namespace;
+ if (namespace) {
+- task_lock(p);
+- p->namespace = NULL;
+- task_unlock(p);
+ put_namespace(namespace);
+ }
+ }
+diff --git a/include/linux/nbd.h b/include/linux/nbd.h
+index e712e7d..d6b6dc0 100644
+--- a/include/linux/nbd.h
++++ b/include/linux/nbd.h
+@@ -15,6 +15,8 @@
+ #ifndef LINUX_NBD_H
+ #define LINUX_NBD_H
+
++#include <linux/types.h>
++
+ #define NBD_SET_SOCK _IO( 0xab, 0 )
+ #define NBD_SET_BLKSIZE _IO( 0xab, 1 )
+ #define NBD_SET_SIZE _IO( 0xab, 2 )
+diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
+index b208f0c..0ea7f89 100644
+--- a/include/linux/ncp_fs.h
++++ b/include/linux/ncp_fs.h
+@@ -11,6 +11,7 @@
+ #include <linux/fs.h>
+ #include <linux/in.h>
+ #include <linux/types.h>
++#include <linux/magic.h>
+
+ #include <linux/ipx.h>
+ #include <linux/ncp_no.h>
+@@ -185,10 +186,6 @@ struct ncp_entry_info {
+ __u8 file_handle[6];
+ };
+
+-/* Guess, what 0x564c is :-) */
+-#define NCP_SUPER_MAGIC 0x564c
+-
+-
+ static inline struct ncp_server *NCP_SBP(struct super_block *sb)
+ {
+ return sb->s_fs_info;
+@@ -215,6 +212,7 @@ void ncp_date_unix2dos(int unix_date, __
+
+ /* linux/fs/ncpfs/ioctl.c */
+ int ncp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
++long ncp_compat_ioctl(struct file *, unsigned int, unsigned long);
+
+ /* linux/fs/ncpfs/sock.c */
+ int ncp_request2(struct ncp_server *server, int function,
+diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
+new file mode 100644
+index 0000000..bd3bbf6
+--- /dev/null
++++ b/include/linux/neighbour.h
+@@ -0,0 +1,159 @@
++#ifndef __LINUX_NEIGHBOUR_H
++#define __LINUX_NEIGHBOUR_H
++
++#include <linux/netlink.h>
++
++struct ndmsg
++{
++ __u8 ndm_family;
++ __u8 ndm_pad1;
++ __u16 ndm_pad2;
++ __s32 ndm_ifindex;
++ __u16 ndm_state;
++ __u8 ndm_flags;
++ __u8 ndm_type;
++};
++
++enum
++{
++ NDA_UNSPEC,
++ NDA_DST,
++ NDA_LLADDR,
++ NDA_CACHEINFO,
++ NDA_PROBES,
++ __NDA_MAX
++};
++
++#define NDA_MAX (__NDA_MAX - 1)
++
++/*
++ * Neighbor Cache Entry Flags
++ */
++
++#define NTF_PROXY 0x08 /* == ATF_PUBL */
++#define NTF_ROUTER 0x80
++
++/*
++ * Neighbor Cache Entry States.
++ */
++
++#define NUD_INCOMPLETE 0x01
++#define NUD_REACHABLE 0x02
++#define NUD_STALE 0x04
++#define NUD_DELAY 0x08
++#define NUD_PROBE 0x10
++#define NUD_FAILED 0x20
++
++/* Dummy states */
++#define NUD_NOARP 0x40
++#define NUD_PERMANENT 0x80
++#define NUD_NONE 0x00
++
++/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
++ and make no address resolution or NUD.
++ NUD_PERMANENT is also cannot be deleted by garbage collectors.
++ */
++
++struct nda_cacheinfo
++{
++ __u32 ndm_confirmed;
++ __u32 ndm_used;
++ __u32 ndm_updated;
++ __u32 ndm_refcnt;
++};
++
++/*****************************************************************
++ * Neighbour tables specific messages.
++ *
++ * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
++ * NLM_F_DUMP flag set. Every neighbour table configuration is
++ * spread over multiple messages to avoid running into message
++ * size limits on systems with many interfaces. The first message
++ * in the sequence transports all not device specific data such as
++ * statistics, configuration, and the default parameter set.
++ * This message is followed by 0..n messages carrying device
++ * specific parameter sets.
++ * Although the ordering should be sufficient, NDTA_NAME can be
++ * used to identify sequences. The initial message can be identified
++ * by checking for NDTA_CONFIG. The device specific messages do
++ * not contain this TLV but have NDTPA_IFINDEX set to the
++ * corresponding interface index.
++ *
++ * To change neighbour table attributes, send RTM_SETNEIGHTBL
++ * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
++ * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
++ * otherwise. Device specific parameter sets can be changed by
++ * setting NDTPA_IFINDEX to the interface index of the corresponding
++ * device.
++ ****/
++
++struct ndt_stats
++{
++ __u64 ndts_allocs;
++ __u64 ndts_destroys;
++ __u64 ndts_hash_grows;
++ __u64 ndts_res_failed;
++ __u64 ndts_lookups;
++ __u64 ndts_hits;
++ __u64 ndts_rcv_probes_mcast;
++ __u64 ndts_rcv_probes_ucast;
++ __u64 ndts_periodic_gc_runs;
++ __u64 ndts_forced_gc_runs;
++};
++
++enum {
++ NDTPA_UNSPEC,
++ NDTPA_IFINDEX, /* u32, unchangeable */
++ NDTPA_REFCNT, /* u32, read-only */
++ NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */
++ NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */
++ NDTPA_RETRANS_TIME, /* u64, msecs */
++ NDTPA_GC_STALETIME, /* u64, msecs */
++ NDTPA_DELAY_PROBE_TIME, /* u64, msecs */
++ NDTPA_QUEUE_LEN, /* u32 */
++ NDTPA_APP_PROBES, /* u32 */
++ NDTPA_UCAST_PROBES, /* u32 */
++ NDTPA_MCAST_PROBES, /* u32 */
++ NDTPA_ANYCAST_DELAY, /* u64, msecs */
++ NDTPA_PROXY_DELAY, /* u64, msecs */
++ NDTPA_PROXY_QLEN, /* u32 */
++ NDTPA_LOCKTIME, /* u64, msecs */
++ __NDTPA_MAX
++};
++#define NDTPA_MAX (__NDTPA_MAX - 1)
++
++struct ndtmsg
++{
++ __u8 ndtm_family;
++ __u8 ndtm_pad1;
++ __u16 ndtm_pad2;
++};
++
++struct ndt_config
++{
++ __u16 ndtc_key_len;
++ __u16 ndtc_entry_size;
++ __u32 ndtc_entries;
++ __u32 ndtc_last_flush; /* delta to now in msecs */
++ __u32 ndtc_last_rand; /* delta to now in msecs */
++ __u32 ndtc_hash_rnd;
++ __u32 ndtc_hash_mask;
++ __u32 ndtc_hash_chain_gc;
++ __u32 ndtc_proxy_qlen;
++};
++
++enum {
++ NDTA_UNSPEC,
++ NDTA_NAME, /* char *, unchangeable */
++ NDTA_THRESH1, /* u32 */
++ NDTA_THRESH2, /* u32 */
++ NDTA_THRESH3, /* u32 */
++ NDTA_CONFIG, /* struct ndt_config, read-only */
++ NDTA_PARMS, /* nested TLV NDTPA_* */
++ NDTA_STATS, /* struct ndt_stats, read-only */
++ NDTA_GC_INTERVAL, /* u64, msecs */
++ __NDTA_MAX
++};
++#define NDTA_MAX (__NDTA_MAX - 1)
++
++#endif
+diff --git a/include/linux/net.h b/include/linux/net.h
+index b20c53c..15c733b 100644
+--- a/include/linux/net.h
++++ b/include/linux/net.h
+@@ -19,6 +19,7 @@
+ #define _LINUX_NET_H
+
+ #include <linux/wait.h>
++#include <linux/random.h>
+ #include <asm/socket.h>
+
+ struct poll_table_struct;
+@@ -169,11 +170,6 @@ struct proto_ops {
+ struct net_proto_family {
+ int family;
+ int (*create)(struct socket *sock, int protocol);
+- /* These are counters for the number of different methods of
+- each we support */
+- short authentication;
+- short encryption;
+- short encrypt_net;
+ struct module *owner;
+ };
+
+@@ -181,8 +177,8 @@ struct iovec;
+ struct kvec;
+
+ extern int sock_wake_async(struct socket *sk, int how, int band);
+-extern int sock_register(struct net_proto_family *fam);
+-extern int sock_unregister(int family);
++extern int sock_register(const struct net_proto_family *fam);
++extern void sock_unregister(int family);
+ extern int sock_create(int family, int type, int proto,
+ struct socket **res);
+ extern int sock_create_kern(int family, int type, int proto,
+@@ -198,9 +194,9 @@ extern int sock_map_fd(struct sock
+ extern struct socket *sockfd_lookup(int fd, int *err);
+ #define sockfd_put(sock) fput(sock->file)
+ extern int net_ratelimit(void);
+-extern unsigned long net_random(void);
+-extern void net_srandom(unsigned long);
+-extern void net_random_init(void);
++
++#define net_random() random32()
++#define net_srandom(seed) srandom32(seed)
+
+ extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
+ struct kvec *vec, size_t num, size_t len);
+@@ -208,6 +204,25 @@ extern int kernel_recvmsg(struct
+ struct kvec *vec, size_t num,
+ size_t len, int flags);
+
++extern int kernel_bind(struct socket *sock, struct sockaddr *addr,
++ int addrlen);
++extern int kernel_listen(struct socket *sock, int backlog);
++extern int kernel_accept(struct socket *sock, struct socket **newsock,
++ int flags);
++extern int kernel_connect(struct socket *sock, struct sockaddr *addr,
++ int addrlen, int flags);
++extern int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
++ int *addrlen);
++extern int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
++ int *addrlen);
++extern int kernel_getsockopt(struct socket *sock, int level, int optname,
++ char *optval, int *optlen);
++extern int kernel_setsockopt(struct socket *sock, int level, int optname,
++ char *optval, int optlen);
++extern int kernel_sendpage(struct socket *sock, struct page *page, int offset,
++ size_t size, int flags);
++extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
++
+ #ifndef CONFIG_SMP
+ #define SOCKOPS_WRAPPED(name) name
+ #define SOCKOPS_WRAP(name, fam)
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 50a4719..9264139 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -187,7 +187,7 @@ struct hh_cache
+ {
+ struct hh_cache *hh_next; /* Next entry */
+ atomic_t hh_refcnt; /* number of users */
+- unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP
++ __be16 hh_type; /* protocol identifier, f.e ETH_P_IP
+ * NOTE: For VLANs, this will be the
+ * encapuslated type. --BLG
+ */
+@@ -334,7 +334,6 @@ struct net_device
+
+
+ struct net_device_stats* (*get_stats)(struct net_device *dev);
+- struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
+
+ /* List of functions to handle Wireless Extensions (instead of ioctl).
+ * See <net/iw_handler.h> for details. Jean II */
+@@ -342,7 +341,7 @@ struct net_device
+ /* Instance data managed by the core of Wireless Extensions. */
+ struct iw_public_data * wireless_data;
+
+- struct ethtool_ops *ethtool_ops;
++ const struct ethtool_ops *ethtool_ops;
+
+ /*
+ * This marks the end of the "visible" part of the structure. All
+@@ -976,7 +975,7 @@ extern void dev_mcast_init(void);
+ extern int netdev_max_backlog;
+ extern int weight_p;
+ extern int netdev_set_master(struct net_device *dev, struct net_device *master);
+-extern int skb_checksum_help(struct sk_buff *skb, int inward);
++extern int skb_checksum_help(struct sk_buff *skb);
+ extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features);
+ #ifdef CONFIG_BUG
+ extern void netdev_rx_csum_fault(struct net_device *dev);
+@@ -1012,11 +1011,12 @@ static inline int netif_needs_gso(struct
+ {
+ return skb_is_gso(skb) &&
+ (!skb_gso_ok(skb, dev->features) ||
+- unlikely(skb->ip_summed != CHECKSUM_HW));
++ unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
+ }
+
+ /* On bonding slaves other than the currently active slave, suppress
+- * duplicates except for 802.3ad ETH_P_SLOW and alb non-mcast/bcast.
++ * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
++ * ARP on active-backup slaves with arp_validate enabled.
+ */
+ static inline int skb_bond_should_drop(struct sk_buff *skb)
+ {
+@@ -1025,6 +1025,10 @@ static inline int skb_bond_should_drop(s
+
+ if (master &&
+ (dev->priv_flags & IFF_SLAVE_INACTIVE)) {
++ if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
++ skb->protocol == __constant_htons(ETH_P_ARP))
++ return 0;
++
+ if (master->priv_flags & IFF_MASTER_ALB) {
+ if (skb->pkt_type != PACKET_BROADCAST &&
+ skb->pkt_type != PACKET_MULTICAST)
+diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
+index 10168e2..b7e67d1 100644
+--- a/include/linux/netfilter.h
++++ b/include/linux/netfilter.h
+@@ -282,6 +282,12 @@ extern void nf_invalidate_cache(int pf);
+ Returns true or false. */
+ extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
+
++extern u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval,
++ u_int32_t csum);
++extern u_int16_t nf_proto_csum_update(struct sk_buff *skb,
++ u_int32_t oldval, u_int32_t newval,
++ u_int16_t csum, int pseudohdr);
++
+ struct nf_afinfo {
+ unsigned short family;
+ unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook,
+diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
+index 1d3a14e..312bd2f 100644
+--- a/include/linux/netfilter/Kbuild
++++ b/include/linux/netfilter/Kbuild
+@@ -1,11 +1,40 @@
+-header-y := nf_conntrack_sctp.h nf_conntrack_tuple_common.h \
+- nfnetlink_conntrack.h nfnetlink_log.h nfnetlink_queue.h \
+- xt_CLASSIFY.h xt_comment.h xt_connbytes.h xt_connmark.h \
+- xt_CONNMARK.h xt_conntrack.h xt_dccp.h xt_esp.h \
+- xt_helper.h xt_length.h xt_limit.h xt_mac.h xt_mark.h \
+- xt_MARK.h xt_multiport.h xt_NFQUEUE.h xt_pkttype.h \
+- xt_policy.h xt_realm.h xt_sctp.h xt_state.h xt_string.h \
+- xt_tcpmss.h xt_tcpudp.h xt_SECMARK.h xt_CONNSECMARK.h
++header-y += nf_conntrack_sctp.h
++header-y += nf_conntrack_tuple_common.h
++header-y += nfnetlink_conntrack.h
++header-y += nfnetlink_log.h
++header-y += nfnetlink_queue.h
++header-y += xt_CLASSIFY.h
++header-y += xt_comment.h
++header-y += xt_connbytes.h
++header-y += xt_connmark.h
++header-y += xt_CONNMARK.h
++header-y += xt_conntrack.h
++header-y += xt_dccp.h
++header-y += xt_dscp.h
++header-y += xt_DSCP.h
++header-y += xt_esp.h
++header-y += xt_helper.h
++header-y += xt_length.h
++header-y += xt_limit.h
++header-y += xt_mac.h
++header-y += xt_mark.h
++header-y += xt_MARK.h
++header-y += xt_multiport.h
++header-y += xt_NFQUEUE.h
++header-y += xt_pkttype.h
++header-y += xt_policy.h
++header-y += xt_realm.h
++header-y += xt_sctp.h
++header-y += xt_state.h
++header-y += xt_string.h
++header-y += xt_tcpmss.h
++header-y += xt_tcpudp.h
++header-y += xt_SECMARK.h
++header-y += xt_CONNSECMARK.h
+
+-unifdef-y := nf_conntrack_common.h nf_conntrack_ftp.h \
+- nf_conntrack_tcp.h nfnetlink.h x_tables.h xt_physdev.h
++unifdef-y += nf_conntrack_common.h
++unifdef-y += nf_conntrack_ftp.h
++unifdef-y += nf_conntrack_tcp.h
++unifdef-y += nfnetlink.h
++unifdef-y += x_tables.h
++unifdef-y += xt_physdev.h
+diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
+index d2e4bd7..9e0dae0 100644
+--- a/include/linux/netfilter/nf_conntrack_common.h
++++ b/include/linux/netfilter/nf_conntrack_common.h
+@@ -125,6 +125,10 @@ enum ip_conntrack_events
+ /* Counter highest bit has been set */
+ IPCT_COUNTER_FILLING_BIT = 11,
+ IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT),
++
++ /* Mark is set */
++ IPCT_MARK_BIT = 12,
++ IPCT_MARK = (1 << IPCT_MARK_BIT),
+ };
+
+ enum ip_conntrack_expect_events {
+diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h
+index b2feeff..6b01ba2 100644
+--- a/include/linux/netfilter/nf_conntrack_tcp.h
++++ b/include/linux/netfilter/nf_conntrack_tcp.h
+@@ -49,6 +49,7 @@ struct ip_ct_tcp
+ u_int32_t last_seq; /* Last sequence number seen in dir */
+ u_int32_t last_ack; /* Last sequence number seen in opposite dir */
+ u_int32_t last_end; /* Last seq + len */
++ u_int16_t last_win; /* Last window advertisement seen in dir */
+ };
+
+ #endif /* __KERNEL__ */
+diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
+index 9f5b12c..6d8e3e5 100644
+--- a/include/linux/netfilter/nfnetlink.h
++++ b/include/linux/netfilter/nfnetlink.h
+@@ -43,7 +43,7 @@ struct nfattr
+ u_int16_t nfa_len;
+ u_int16_t nfa_type; /* we use 15 bits for the type, and the highest
+ * bit to indicate whether the payload is nested */
+-} __attribute__ ((packed));
++};
+
+ /* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from
+ * rtnetlink.h, it's time to put this in a generic file */
+@@ -79,7 +79,7 @@ struct nfgenmsg {
+ u_int8_t nfgen_family; /* AF_xxx */
+ u_int8_t version; /* nfnetlink version */
+ u_int16_t res_id; /* resource id */
+-} __attribute__ ((packed));
++};
+
+ #define NFNETLINK_V0 0
+
+diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h
+index a7497c7..87b92f8 100644
+--- a/include/linux/netfilter/nfnetlink_log.h
++++ b/include/linux/netfilter/nfnetlink_log.h
+@@ -19,18 +19,18 @@ struct nfulnl_msg_packet_hdr {
+ u_int16_t hw_protocol; /* hw protocol (network order) */
+ u_int8_t hook; /* netfilter hook */
+ u_int8_t _pad;
+-} __attribute__ ((packed));
++};
+
+ struct nfulnl_msg_packet_hw {
+ u_int16_t hw_addrlen;
+ u_int16_t _pad;
+ u_int8_t hw_addr[8];
+-} __attribute__ ((packed));
++};
+
+ struct nfulnl_msg_packet_timestamp {
+ aligned_u64 sec;
+ aligned_u64 usec;
+-} __attribute__ ((packed));
++};
+
+ #define NFULNL_PREFIXLEN 30 /* just like old log target */
+
+diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
+index 9e77437..36af036 100644
+--- a/include/linux/netfilter/nfnetlink_queue.h
++++ b/include/linux/netfilter/nfnetlink_queue.h
+@@ -22,12 +22,12 @@ struct nfqnl_msg_packet_hw {
+ u_int16_t hw_addrlen;
+ u_int16_t _pad;
+ u_int8_t hw_addr[8];
+-} __attribute__ ((packed));
++};
+
+ struct nfqnl_msg_packet_timestamp {
+ aligned_u64 sec;
+ aligned_u64 usec;
+-} __attribute__ ((packed));
++};
+
+ enum nfqnl_attr_type {
+ NFQA_UNSPEC,
+@@ -49,7 +49,7 @@ enum nfqnl_attr_type {
+ struct nfqnl_msg_verdict_hdr {
+ u_int32_t verdict;
+ u_int32_t id;
+-} __attribute__ ((packed));
++};
+
+
+ enum nfqnl_msg_config_cmds {
+@@ -64,7 +64,7 @@ struct nfqnl_msg_config_cmd {
+ u_int8_t command; /* nfqnl_msg_config_cmds */
+ u_int8_t _pad;
+ u_int16_t pf; /* AF_xxx for PF_[UN]BIND */
+-} __attribute__ ((packed));
++};
+
+ enum nfqnl_config_mode {
+ NFQNL_COPY_NONE,
+diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
+index 48cc32d..04319a7 100644
+--- a/include/linux/netfilter/x_tables.h
++++ b/include/linux/netfilter/x_tables.h
+@@ -138,16 +138,6 @@ struct xt_counters_info
+
+ #include <linux/netdevice.h>
+
+-#define ASSERT_READ_LOCK(x)
+-#define ASSERT_WRITE_LOCK(x)
+-#include <linux/netfilter_ipv4/listhelp.h>
+-
+-#ifdef CONFIG_COMPAT
+-#define COMPAT_TO_USER 1
+-#define COMPAT_FROM_USER -1
+-#define COMPAT_CALC_SIZE 0
+-#endif
+-
+ struct xt_match
+ {
+ struct list_head list;
+@@ -174,21 +164,24 @@ struct xt_match
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask);
+
+ /* Called when entry of this type deleted. */
+- void (*destroy)(const struct xt_match *match, void *matchinfo,
+- unsigned int matchinfosize);
++ void (*destroy)(const struct xt_match *match, void *matchinfo);
+
+ /* Called when userspace align differs from kernel space one */
+- int (*compat)(void *match, void **dstptr, int *size, int convert);
++ void (*compat_from_user)(void *dst, void *src);
++ int (*compat_to_user)(void __user *dst, void *src);
+
+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+ struct module *me;
+
++ /* Free to use by each match */
++ unsigned long data;
++
+ char *table;
+ unsigned int matchsize;
++ unsigned int compatsize;
+ unsigned int hooks;
+ unsigned short proto;
+
+@@ -211,8 +204,7 @@ struct xt_target
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userdata);
++ const void *targinfo);
+
+ /* Called when user tries to insert an entry of this type:
+ hook_mask is a bitmask of hooks from which it can be
+@@ -222,21 +214,21 @@ struct xt_target
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask);
+
+ /* Called when entry of this type deleted. */
+- void (*destroy)(const struct xt_target *target, void *targinfo,
+- unsigned int targinfosize);
++ void (*destroy)(const struct xt_target *target, void *targinfo);
+
+ /* Called when userspace align differs from kernel space one */
+- int (*compat)(void *target, void **dstptr, int *size, int convert);
++ void (*compat_from_user)(void *dst, void *src);
++ int (*compat_to_user)(void __user *dst, void *src);
+
+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+ struct module *me;
+
+ char *table;
+ unsigned int targetsize;
++ unsigned int compatsize;
+ unsigned int hooks;
+ unsigned short proto;
+
+@@ -290,8 +282,13 @@ struct xt_table_info
+
+ extern int xt_register_target(struct xt_target *target);
+ extern void xt_unregister_target(struct xt_target *target);
++extern int xt_register_targets(struct xt_target *target, unsigned int n);
++extern void xt_unregister_targets(struct xt_target *target, unsigned int n);
++
+ extern int xt_register_match(struct xt_match *target);
+ extern void xt_unregister_match(struct xt_match *target);
++extern int xt_register_matches(struct xt_match *match, unsigned int n);
++extern void xt_unregister_matches(struct xt_match *match, unsigned int n);
+
+ extern int xt_check_match(const struct xt_match *match, unsigned short family,
+ unsigned int size, const char *table, unsigned int hook,
+@@ -388,9 +385,18 @@ struct compat_xt_counters_info
+
+ extern void xt_compat_lock(int af);
+ extern void xt_compat_unlock(int af);
+-extern int xt_compat_match(void *match, void **dstptr, int *size, int convert);
+-extern int xt_compat_target(void *target, void **dstptr, int *size,
+- int convert);
++
++extern int xt_compat_match_offset(struct xt_match *match);
++extern void xt_compat_match_from_user(struct xt_entry_match *m,
++ void **dstptr, int *size);
++extern int xt_compat_match_to_user(struct xt_entry_match *m,
++ void __user **dstptr, int *size);
++
++extern int xt_compat_target_offset(struct xt_target *target);
++extern void xt_compat_target_from_user(struct xt_entry_target *t,
++ void **dstptr, int *size);
++extern int xt_compat_target_to_user(struct xt_entry_target *t,
++ void __user **dstptr, int *size);
+
+ #endif /* CONFIG_COMPAT */
+ #endif /* __KERNEL__ */
+diff --git a/include/linux/netfilter/xt_DSCP.h b/include/linux/netfilter/xt_DSCP.h
+new file mode 100644
+index 0000000..3c7c963
+--- /dev/null
++++ b/include/linux/netfilter/xt_DSCP.h
+@@ -0,0 +1,20 @@
++/* x_tables module for setting the IPv4/IPv6 DSCP field
++ *
++ * (C) 2002 Harald Welte <laforge at gnumonks.org>
++ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm at paktronix.com>
++ * This software is distributed under GNU GPL v2, 1991
++ *
++ * See RFC2474 for a description of the DSCP field within the IP Header.
++ *
++ * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
++*/
++#ifndef _XT_DSCP_TARGET_H
++#define _XT_DSCP_TARGET_H
++#include <linux/netfilter/xt_dscp.h>
++
++/* target info */
++struct xt_DSCP_info {
++ u_int8_t dscp;
++};
++
++#endif /* _XT_DSCP_TARGET_H */
+diff --git a/include/linux/netfilter/xt_dscp.h b/include/linux/netfilter/xt_dscp.h
+new file mode 100644
+index 0000000..1da61e6
+--- /dev/null
++++ b/include/linux/netfilter/xt_dscp.h
+@@ -0,0 +1,23 @@
++/* x_tables module for matching the IPv4/IPv6 DSCP field
++ *
++ * (C) 2002 Harald Welte <laforge at gnumonks.org>
++ * This software is distributed under GNU GPL v2, 1991
++ *
++ * See RFC2474 for a description of the DSCP field within the IP Header.
++ *
++ * xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
++*/
++#ifndef _XT_DSCP_H
++#define _XT_DSCP_H
++
++#define XT_DSCP_MASK 0xfc /* 11111100 */
++#define XT_DSCP_SHIFT 2
++#define XT_DSCP_MAX 0x3f /* 00111111 */
++
++/* match info */
++struct xt_dscp_info {
++ u_int8_t dscp;
++ u_int8_t invert;
++};
++
++#endif /* _XT_DSCP_H */
+diff --git a/include/linux/netfilter_arp/Kbuild b/include/linux/netfilter_arp/Kbuild
+index 198ec5e..4f13dfc 100644
+--- a/include/linux/netfilter_arp/Kbuild
++++ b/include/linux/netfilter_arp/Kbuild
+@@ -1,2 +1,3 @@
+-header-y := arpt_mangle.h
+-unifdef-y := arp_tables.h
++header-y += arpt_mangle.h
++
++unifdef-y += arp_tables.h
+diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
+index 62cc27d..44e39b6 100644
+--- a/include/linux/netfilter_arp/arp_tables.h
++++ b/include/linux/netfilter_arp/arp_tables.h
+@@ -46,11 +46,11 @@ struct arpt_arp {
+ struct arpt_devaddr_info tgt_devaddr;
+
+ /* ARP operation code. */
+- u_int16_t arpop, arpop_mask;
++ __be16 arpop, arpop_mask;
+
+ /* ARP hardware address and protocol address format. */
+- u_int16_t arhrd, arhrd_mask;
+- u_int16_t arpro, arpro_mask;
++ __be16 arhrd, arhrd_mask;
++ __be16 arpro, arpro_mask;
+
+ /* The protocol address length is only accepted if it is 4
+ * so there is no use in offering a way to do filtering on it.
+@@ -248,8 +248,7 @@ extern unsigned int arpt_do_table(struct
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+- struct arpt_table *table,
+- void *userdata);
++ struct arpt_table *table);
+
+ #define ARPT_ALIGN(s) (((s) + (__alignof__(struct arpt_entry)-1)) & ~(__alignof__(struct arpt_entry)-1))
+ #endif /*__KERNEL__*/
+diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
+index 427c67f..9a4dd11 100644
+--- a/include/linux/netfilter_bridge.h
++++ b/include/linux/netfilter_bridge.h
+@@ -5,9 +5,8 @@
+ */
+
+ #include <linux/netfilter.h>
+-#if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER)
+ #include <linux/if_ether.h>
+-#endif
++#include <linux/if_vlan.h>
+
+ /* Bridge Hooks */
+ /* After promisc drops, checksum checks. */
+@@ -47,40 +46,20 @@ enum nf_br_hook_priorities {
+
+
+ /* Only used in br_forward.c */
+-static inline
+-int nf_bridge_maybe_copy_header(struct sk_buff *skb)
++extern int nf_bridge_copy_header(struct sk_buff *skb);
++static inline int nf_bridge_maybe_copy_header(struct sk_buff *skb)
+ {
+- int err;
+-
+- if (skb->nf_bridge) {
+- if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+- err = skb_cow(skb, 18);
+- if (err)
+- return err;
+- memcpy(skb->data - 18, skb->nf_bridge->data, 18);
+- skb_push(skb, 4);
+- } else {
+- err = skb_cow(skb, 16);
+- if (err)
+- return err;
+- memcpy(skb->data - 16, skb->nf_bridge->data, 16);
+- }
+- }
+- return 0;
++ if (skb->nf_bridge)
++ return nf_bridge_copy_header(skb);
++ return 0;
+ }
+
+ /* This is called by the IP fragmenting code and it ensures there is
+ * enough room for the encapsulating header (if there is one). */
+-static inline
+-int nf_bridge_pad(struct sk_buff *skb)
++static inline int nf_bridge_pad(const struct sk_buff *skb)
+ {
+- if (skb->protocol == __constant_htons(ETH_P_IP))
+- return 0;
+- if (skb->nf_bridge) {
+- if (skb->protocol == __constant_htons(ETH_P_8021Q))
+- return 4;
+- }
+- return 0;
++ return (skb->nf_bridge && skb->protocol == htons(ETH_P_8021Q))
++ ? VLAN_HLEN : 0;
+ }
+
+ struct bridge_skb_cb {
+@@ -90,6 +69,9 @@ struct bridge_skb_cb {
+ };
+
+ extern int brnf_deferred_hooks;
++#else
++#define nf_bridge_maybe_copy_header(skb) (0)
++#define nf_bridge_pad(skb) (0)
+ #endif /* CONFIG_BRIDGE_NETFILTER */
+
+ #endif /* __KERNEL__ */
+diff --git a/include/linux/netfilter_bridge/Kbuild b/include/linux/netfilter_bridge/Kbuild
+index 5b1aba6..76ff4c4 100644
+--- a/include/linux/netfilter_bridge/Kbuild
++++ b/include/linux/netfilter_bridge/Kbuild
+@@ -1,4 +1,17 @@
+-header-y += ebt_among.h ebt_arp.h ebt_arpreply.h ebt_ip.h ebt_limit.h \
+- ebt_log.h ebt_mark_m.h ebt_mark_t.h ebt_nat.h ebt_pkttype.h \
+- ebt_redirect.h ebt_stp.h ebt_ulog.h ebt_vlan.h
+-unifdef-y := ebtables.h ebt_802_3.h
++header-y += ebt_among.h
++header-y += ebt_arp.h
++header-y += ebt_arpreply.h
++header-y += ebt_ip.h
++header-y += ebt_limit.h
++header-y += ebt_log.h
++header-y += ebt_mark_m.h
++header-y += ebt_mark_t.h
++header-y += ebt_nat.h
++header-y += ebt_pkttype.h
++header-y += ebt_redirect.h
++header-y += ebt_stp.h
++header-y += ebt_ulog.h
++header-y += ebt_vlan.h
++
++unifdef-y += ebtables.h
++unifdef-y += ebt_802_3.h
+diff --git a/include/linux/netfilter_bridge/ebt_mark_t.h b/include/linux/netfilter_bridge/ebt_mark_t.h
+index 110fec6..6270f6f 100644
+--- a/include/linux/netfilter_bridge/ebt_mark_t.h
++++ b/include/linux/netfilter_bridge/ebt_mark_t.h
+@@ -1,6 +1,18 @@
+ #ifndef __LINUX_BRIDGE_EBT_MARK_T_H
+ #define __LINUX_BRIDGE_EBT_MARK_T_H
+
++/* The target member is reused for adding new actions, the
++ * value of the real target is -1 to -NUM_STANDARD_TARGETS.
++ * For backward compatibility, the 4 lsb (2 would be enough,
++ * but let's play it safe) are kept to designate this target.
++ * The remaining bits designate the action. By making the set
++ * action 0xfffffff0, the result will look ok for older
++ * versions. [September 2006] */
++#define MARK_SET_VALUE (0xfffffff0)
++#define MARK_OR_VALUE (0xffffffe0)
++#define MARK_AND_VALUE (0xffffffd0)
++#define MARK_XOR_VALUE (0xffffffc0)
++
+ struct ebt_mark_t_info
+ {
+ unsigned long mark;
+diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
+index ce02c98..5b63a23 100644
+--- a/include/linux/netfilter_ipv4.h
++++ b/include/linux/netfilter_ipv4.h
+@@ -77,7 +77,7 @@ enum nf_ip_hook_priorities {
+ #define SO_ORIGINAL_DST 80
+
+ #ifdef __KERNEL__
+-extern int ip_route_me_harder(struct sk_buff **pskb);
++extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type);
+ extern int ip_xfrm_me_harder(struct sk_buff **pskb);
+ extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
+ unsigned int dataoff, u_int8_t protocol);
+diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild
+index 04e4d27..591c1a8 100644
+--- a/include/linux/netfilter_ipv4/Kbuild
++++ b/include/linux/netfilter_ipv4/Kbuild
+@@ -1,21 +1,63 @@
++header-y += ip_conntrack_helper.h
++header-y += ip_conntrack_helper_h323_asn1.h
++header-y += ip_conntrack_helper_h323_types.h
++header-y += ip_conntrack_protocol.h
++header-y += ip_conntrack_sctp.h
++header-y += ip_conntrack_tcp.h
++header-y += ip_conntrack_tftp.h
++header-y += ip_nat_pptp.h
++header-y += ipt_addrtype.h
++header-y += ipt_ah.h
++header-y += ipt_CLASSIFY.h
++header-y += ipt_CLUSTERIP.h
++header-y += ipt_comment.h
++header-y += ipt_connbytes.h
++header-y += ipt_connmark.h
++header-y += ipt_CONNMARK.h
++header-y += ipt_conntrack.h
++header-y += ipt_dccp.h
++header-y += ipt_dscp.h
++header-y += ipt_DSCP.h
++header-y += ipt_ecn.h
++header-y += ipt_ECN.h
++header-y += ipt_esp.h
++header-y += ipt_hashlimit.h
++header-y += ipt_helper.h
++header-y += ipt_iprange.h
++header-y += ipt_length.h
++header-y += ipt_limit.h
++header-y += ipt_LOG.h
++header-y += ipt_mac.h
++header-y += ipt_mark.h
++header-y += ipt_MARK.h
++header-y += ipt_multiport.h
++header-y += ipt_NFQUEUE.h
++header-y += ipt_owner.h
++header-y += ipt_physdev.h
++header-y += ipt_pkttype.h
++header-y += ipt_policy.h
++header-y += ipt_realm.h
++header-y += ipt_recent.h
++header-y += ipt_REJECT.h
++header-y += ipt_SAME.h
++header-y += ipt_sctp.h
++header-y += ipt_state.h
++header-y += ipt_string.h
++header-y += ipt_tcpmss.h
++header-y += ipt_TCPMSS.h
++header-y += ipt_tos.h
++header-y += ipt_TOS.h
++header-y += ipt_ttl.h
++header-y += ipt_TTL.h
++header-y += ipt_ULOG.h
+
+-header-y := ip_conntrack_helper.h ip_conntrack_helper_h323_asn1.h \
+- ip_conntrack_helper_h323_types.h ip_conntrack_protocol.h \
+- ip_conntrack_sctp.h ip_conntrack_tcp.h ip_conntrack_tftp.h \
+- ip_nat_pptp.h ipt_addrtype.h ipt_ah.h \
+- ipt_CLASSIFY.h ipt_CLUSTERIP.h ipt_comment.h \
+- ipt_connbytes.h ipt_connmark.h ipt_CONNMARK.h \
+- ipt_conntrack.h ipt_dccp.h ipt_dscp.h ipt_DSCP.h ipt_ecn.h \
+- ipt_ECN.h ipt_esp.h ipt_hashlimit.h ipt_helper.h \
+- ipt_iprange.h ipt_length.h ipt_limit.h ipt_LOG.h ipt_mac.h \
+- ipt_mark.h ipt_MARK.h ipt_multiport.h ipt_NFQUEUE.h \
+- ipt_owner.h ipt_physdev.h ipt_pkttype.h ipt_policy.h \
+- ipt_realm.h ipt_recent.h ipt_REJECT.h ipt_SAME.h \
+- ipt_sctp.h ipt_state.h ipt_string.h ipt_tcpmss.h \
+- ipt_TCPMSS.h ipt_tos.h ipt_TOS.h ipt_ttl.h ipt_TTL.h \
+- ipt_ULOG.h
+-
+-unifdef-y := ip_conntrack.h ip_conntrack_h323.h ip_conntrack_irc.h \
+- ip_conntrack_pptp.h ip_conntrack_proto_gre.h \
+- ip_conntrack_tuple.h ip_nat.h ip_nat_rule.h ip_queue.h \
+- ip_tables.h
++unifdef-y += ip_conntrack.h
++unifdef-y += ip_conntrack_h323.h
++unifdef-y += ip_conntrack_irc.h
++unifdef-y += ip_conntrack_pptp.h
++unifdef-y += ip_conntrack_proto_gre.h
++unifdef-y += ip_conntrack_tuple.h
++unifdef-y += ip_nat.h
++unifdef-y += ip_nat_rule.h
++unifdef-y += ip_queue.h
++unifdef-y += ip_tables.h
+diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
+index 51dbec1..64e8680 100644
+--- a/include/linux/netfilter_ipv4/ip_conntrack.h
++++ b/include/linux/netfilter_ipv4/ip_conntrack.h
+@@ -157,7 +157,7 @@ struct ip_conntrack_expect
+ unsigned int flags;
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+- u_int32_t saved_ip;
++ __be32 saved_ip;
+ /* This is the original per-proto part, used to map the
+ * expected connection the way the recipient expects. */
+ union ip_conntrack_manip_proto saved_proto;
+diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+index 3cbff73..943cc6a 100644
+--- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h
++++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+@@ -30,7 +30,7 @@ struct ip_ct_h323_master {
+ struct ip_conntrack_expect;
+
+ extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
+- u_int32_t * ip, u_int16_t * port);
++ __be32 * ip, u_int16_t * port);
+ extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this);
+ extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
+@@ -38,11 +38,11 @@ extern void ip_conntrack_q931_expect(str
+ extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+- u_int32_t ip, u_int16_t port);
++ __be32 ip, u_int16_t port);
+ extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr,
+- u_int32_t ip, u_int16_t port);
++ __be32 ip, u_int16_t port);
+ extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h
+index 8d69279..77fe868 100644
+--- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h
++++ b/include/linux/netfilter_ipv4/ip_conntrack_helper.h
+@@ -25,6 +25,8 @@ struct ip_conntrack_helper
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info conntrackinfo);
+
++ void (*destroy)(struct ip_conntrack *ct);
++
+ int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct);
+ };
+
+diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
+index 816144c..2644b1f 100644
+--- a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
++++ b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
+@@ -31,8 +31,8 @@ struct ip_ct_pptp_master {
+ /* everything below is going to be per-expectation in newnat,
+ * since there could be more than one call within one session */
+ enum pptp_ctrlcall_state cstate; /* call state */
+- u_int16_t pac_call_id; /* call id of PAC, host byte order */
+- u_int16_t pns_call_id; /* call id of PNS, host byte order */
++ __be16 pac_call_id; /* call id of PAC, host byte order */
++ __be16 pns_call_id; /* call id of PNS, host byte order */
+
+ /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack
+ * and therefore imposes a fixed limit on the number of maps */
+@@ -42,8 +42,8 @@ struct ip_ct_pptp_master {
+ /* conntrack_expect private member */
+ struct ip_ct_pptp_expect {
+ enum pptp_ctrlcall_state cstate; /* call state */
+- u_int16_t pac_call_id; /* call id of PAC */
+- u_int16_t pns_call_id; /* call id of PNS */
++ __be16 pac_call_id; /* call id of PAC */
++ __be16 pns_call_id; /* call id of PNS */
+ };
+
+
+@@ -107,8 +107,7 @@ struct PptpControlHeader {
+
+ struct PptpStartSessionRequest {
+ __be16 protocolVersion;
+- __u8 reserved1;
+- __u8 reserved2;
++ __u16 reserved1;
+ __be32 framingCapability;
+ __be32 bearerCapability;
+ __be16 maxChannels;
+@@ -143,6 +142,8 @@ struct PptpStartSessionReply {
+
+ struct PptpStopSessionRequest {
+ __u8 reason;
++ __u8 reserved1;
++ __u16 reserved2;
+ };
+
+ /* PptpStopSessionResultCode */
+@@ -152,6 +153,7 @@ struct PptpStopSessionRequest {
+ struct PptpStopSessionReply {
+ __u8 resultCode;
+ __u8 generalErrorCode;
++ __u16 reserved1;
+ };
+
+ struct PptpEchoRequest {
+@@ -188,9 +190,8 @@ struct PptpOutCallRequest {
+ __be32 framingType;
+ __be16 packetWindow;
+ __be16 packetProcDelay;
+- __u16 reserved1;
+ __be16 phoneNumberLength;
+- __u16 reserved2;
++ __u16 reserved1;
+ __u8 phoneNumber[64];
+ __u8 subAddress[64];
+ };
+@@ -285,19 +286,19 @@ struct PptpSetLinkInfo {
+ };
+
+ union pptp_ctrl_union {
+- struct PptpStartSessionRequest sreq;
+- struct PptpStartSessionReply srep;
+- struct PptpStopSessionRequest streq;
+- struct PptpStopSessionReply strep;
+- struct PptpOutCallRequest ocreq;
+- struct PptpOutCallReply ocack;
+- struct PptpInCallRequest icreq;
+- struct PptpInCallReply icack;
+- struct PptpInCallConnected iccon;
+- struct PptpClearCallRequest clrreq;
+- struct PptpCallDisconnectNotify disc;
+- struct PptpWanErrorNotify wanerr;
+- struct PptpSetLinkInfo setlink;
++ struct PptpStartSessionRequest sreq;
++ struct PptpStartSessionReply srep;
++ struct PptpStopSessionRequest streq;
++ struct PptpStopSessionReply strep;
++ struct PptpOutCallRequest ocreq;
++ struct PptpOutCallReply ocack;
++ struct PptpInCallRequest icreq;
++ struct PptpInCallReply icack;
++ struct PptpInCallConnected iccon;
++ struct PptpClearCallRequest clrreq;
++ struct PptpCallDisconnectNotify disc;
++ struct PptpWanErrorNotify wanerr;
++ struct PptpSetLinkInfo setlink;
+ };
+
+ extern int
+@@ -314,7 +315,7 @@ extern int
+ struct PptpControlHeader *ctlh,
+ union pptp_ctrl_union *pptpReq);
+
+-extern int
++extern void
+ (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig,
+ struct ip_conntrack_expect *exp_reply);
+
+diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
+index 8d090ef..1d853aa 100644
+--- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
++++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
+@@ -49,18 +49,18 @@ struct gre_hdr {
+ #else
+ #error "Adjust your <asm/byteorder.h> defines"
+ #endif
+- __u16 protocol;
++ __be16 protocol;
+ };
+
+ /* modified GRE header for PPTP */
+ struct gre_hdr_pptp {
+- __u8 flags; /* bitfield */
+- __u8 version; /* should be GRE_VERSION_PPTP */
+- __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
+- __u16 payload_len; /* size of ppp payload, not inc. gre header */
+- __u16 call_id; /* peer's call_id for this session */
+- __u32 seq; /* sequence number. Present if S==1 */
+- __u32 ack; /* seq number of highest packet recieved by */
++ __u8 flags; /* bitfield */
++ __u8 version; /* should be GRE_VERSION_PPTP */
++ __be16 protocol; /* should be GRE_PROTOCOL_PPTP */
++ __be16 payload_len; /* size of ppp payload, not inc. gre header */
++ __be16 call_id; /* peer's call_id for this session */
++ __be32 seq; /* sequence number. Present if S==1 */
++ __be32 ack; /* seq number of highest packet recieved by */
+ /* sender in this session */
+ };
+
+@@ -92,13 +92,13 @@ void ip_ct_gre_keymap_destroy(struct ip_
+
+
+ /* get pointer to gre key, if present */
+-static inline u_int32_t *gre_key(struct gre_hdr *greh)
++static inline __be32 *gre_key(struct gre_hdr *greh)
+ {
+ if (!greh->key)
+ return NULL;
+ if (greh->csum || greh->routing)
+- return (u_int32_t *) (greh+sizeof(*greh)+4);
+- return (u_int32_t *) (greh+sizeof(*greh));
++ return (__be32 *) (greh+sizeof(*greh)+4);
++ return (__be32 *) (greh+sizeof(*greh));
+ }
+
+ /* get pointer ot gre csum, if present */
+diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+index 2fdabdb..c228bde 100644
+--- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
++++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+@@ -23,13 +23,13 @@ union ip_conntrack_manip_proto
+ __be16 port;
+ } tcp;
+ struct {
+- u_int16_t port;
++ __be16 port;
+ } udp;
+ struct {
+- u_int16_t id;
++ __be16 id;
+ } icmp;
+ struct {
+- u_int16_t port;
++ __be16 port;
+ } sctp;
+ struct {
+ __be16 key; /* key is 32bit, pptp only uses 16 */
+@@ -39,7 +39,7 @@ union ip_conntrack_manip_proto
+ /* The manipulable part of the tuple. */
+ struct ip_conntrack_manip
+ {
+- u_int32_t ip;
++ __be32 ip;
+ union ip_conntrack_manip_proto u;
+ };
+
+@@ -50,22 +50,22 @@ struct ip_conntrack_tuple
+
+ /* These are the parts of the tuple which are fixed. */
+ struct {
+- u_int32_t ip;
++ __be32 ip;
+ union {
+ /* Add other protocols here. */
+ u_int16_t all;
+
+ struct {
+- u_int16_t port;
++ __be16 port;
+ } tcp;
+ struct {
+- u_int16_t port;
++ __be16 port;
+ } udp;
+ struct {
+ u_int8_t type, code;
+ } icmp;
+ struct {
+- u_int16_t port;
++ __be16 port;
+ } sctp;
+ struct {
+ __be16 key; /* key is 32bit,
+diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h
+index e9f5ed1..bdf5536 100644
+--- a/include/linux/netfilter_ipv4/ip_nat.h
++++ b/include/linux/netfilter_ipv4/ip_nat.h
+@@ -33,7 +33,7 @@ struct ip_nat_range
+ unsigned int flags;
+
+ /* Inclusive: network order. */
+- u_int32_t min_ip, max_ip;
++ __be32 min_ip, max_ip;
+
+ /* Inclusive: network order */
+ union ip_conntrack_manip_proto min, max;
+@@ -72,10 +72,6 @@ extern unsigned int ip_nat_setup_info(st
+ extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack *ignored_conntrack);
+
+-/* Calculate relative checksum. */
+-extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
+- u_int32_t newval,
+- u_int16_t oldcheck);
+ #else /* !__KERNEL__: iptables wants this to compile. */
+ #define ip_nat_multi_range ip_nat_multi_range_compat
+ #endif /*__KERNEL__*/
+diff --git a/include/linux/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h
+index 30db23f..60566f9 100644
+--- a/include/linux/netfilter_ipv4/ip_nat_core.h
++++ b/include/linux/netfilter_ipv4/ip_nat_core.h
+@@ -11,8 +11,8 @@ extern unsigned int ip_nat_packet(struct
+ unsigned int hooknum,
+ struct sk_buff **pskb);
+
+-extern int ip_nat_icmp_reply_translation(struct sk_buff **pskb,
+- struct ip_conntrack *ct,
+- enum ip_nat_manip_type manip,
+- enum ip_conntrack_dir dir);
++extern int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb);
+ #endif /* _IP_NAT_CORE_H */
+diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h
+index eaf66c2..36668bf 100644
+--- a/include/linux/netfilter_ipv4/ip_nat_pptp.h
++++ b/include/linux/netfilter_ipv4/ip_nat_pptp.h
+@@ -4,8 +4,8 @@
+
+ /* conntrack private data */
+ struct ip_nat_pptp {
+- u_int16_t pns_call_id; /* NAT'ed PNS call id */
+- u_int16_t pac_call_id; /* NAT'ed PAC call id */
++ __be16 pns_call_id; /* NAT'ed PNS call id */
++ __be16 pac_call_id; /* NAT'ed PAC call id */
+ };
+
+ #endif /* _NAT_PPTP_H */
+diff --git a/include/linux/netfilter_ipv4/ip_queue.h b/include/linux/netfilter_ipv4/ip_queue.h
+index aa08d68..a03507f 100644
+--- a/include/linux/netfilter_ipv4/ip_queue.h
++++ b/include/linux/netfilter_ipv4/ip_queue.h
+@@ -26,7 +26,7 @@ typedef struct ipq_packet_msg {
+ unsigned int hook; /* Netfilter hook we rode in on */
+ char indev_name[IFNAMSIZ]; /* Name of incoming interface */
+ char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */
+- unsigned short hw_protocol; /* Hardware protocol (network order) */
++ __be16 hw_protocol; /* Hardware protocol (network order) */
+ unsigned short hw_type; /* Hardware type */
+ unsigned char hw_addrlen; /* Hardware address length */
+ unsigned char hw_addr[8]; /* Hardware address */
+diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
+index c0dac16..a536bbd 100644
+--- a/include/linux/netfilter_ipv4/ip_tables.h
++++ b/include/linux/netfilter_ipv4/ip_tables.h
+@@ -312,8 +312,7 @@ extern unsigned int ipt_do_table(struct
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+- struct ipt_table *table,
+- void *userdata);
++ struct ipt_table *table);
+
+ #define IPT_ALIGN(s) XT_ALIGN(s)
+
+diff --git a/include/linux/netfilter_ipv4/ipt_DSCP.h b/include/linux/netfilter_ipv4/ipt_DSCP.h
+index b30f510..3491e52 100644
+--- a/include/linux/netfilter_ipv4/ipt_DSCP.h
++++ b/include/linux/netfilter_ipv4/ipt_DSCP.h
+@@ -11,10 +11,8 @@
+ #ifndef _IPT_DSCP_TARGET_H
+ #define _IPT_DSCP_TARGET_H
+ #include <linux/netfilter_ipv4/ipt_dscp.h>
++#include <linux/netfilter/xt_DSCP.h>
+
+-/* target info */
+-struct ipt_DSCP_info {
+- u_int8_t dscp;
+-};
++#define ipt_DSCP_info xt_DSCP_info
+
+ #endif /* _IPT_DSCP_TARGET_H */
+diff --git a/include/linux/netfilter_ipv4/ipt_dscp.h b/include/linux/netfilter_ipv4/ipt_dscp.h
+index 2fa6dfe..4b82ca9 100644
+--- a/include/linux/netfilter_ipv4/ipt_dscp.h
++++ b/include/linux/netfilter_ipv4/ipt_dscp.h
+@@ -10,14 +10,12 @@
+ #ifndef _IPT_DSCP_H
+ #define _IPT_DSCP_H
+
+-#define IPT_DSCP_MASK 0xfc /* 11111100 */
+-#define IPT_DSCP_SHIFT 2
+-#define IPT_DSCP_MAX 0x3f /* 00111111 */
++#include <linux/netfilter/xt_dscp.h>
+
+-/* match info */
+-struct ipt_dscp_info {
+- u_int8_t dscp;
+- u_int8_t invert;
+-};
++#define IPT_DSCP_MASK XT_DSCP_MASK
++#define IPT_DSCP_SHIFT XT_DSCP_SHIFT
++#define IPT_DSCP_MAX XT_DSCP_MAX
++
++#define ipt_dscp_info xt_dscp_info
+
+ #endif /* _IPT_DSCP_H */
+diff --git a/include/linux/netfilter_ipv4/ipt_iprange.h b/include/linux/netfilter_ipv4/ipt_iprange.h
+index 3ecb3bd..34ab0fb 100644
+--- a/include/linux/netfilter_ipv4/ipt_iprange.h
++++ b/include/linux/netfilter_ipv4/ipt_iprange.h
+@@ -8,7 +8,7 @@
+
+ struct ipt_iprange {
+ /* Inclusive: network order. */
+- u_int32_t min_ip, max_ip;
++ __be32 min_ip, max_ip;
+ };
+
+ struct ipt_iprange_info
+diff --git a/include/linux/netfilter_ipv4/listhelp.h b/include/linux/netfilter_ipv4/listhelp.h
+deleted file mode 100644
+index 5d92cf0..0000000
+--- a/include/linux/netfilter_ipv4/listhelp.h
++++ /dev/null
+@@ -1,123 +0,0 @@
+-#ifndef _LISTHELP_H
+-#define _LISTHELP_H
+-#include <linux/list.h>
+-
+-/* Header to do more comprehensive job than linux/list.h; assume list
+- is first entry in structure. */
+-
+-/* Return pointer to first true entry, if any, or NULL. A macro
+- required to allow inlining of cmpfn. */
+-#define LIST_FIND(head, cmpfn, type, args...) \
+-({ \
+- const struct list_head *__i, *__j = NULL; \
+- \
+- ASSERT_READ_LOCK(head); \
+- list_for_each(__i, (head)) \
+- if (cmpfn((const type)__i , ## args)) { \
+- __j = __i; \
+- break; \
+- } \
+- (type)__j; \
+-})
+-
+-#define LIST_FIND_W(head, cmpfn, type, args...) \
+-({ \
+- const struct list_head *__i, *__j = NULL; \
+- \
+- ASSERT_WRITE_LOCK(head); \
+- list_for_each(__i, (head)) \
+- if (cmpfn((type)__i , ## args)) { \
+- __j = __i; \
+- break; \
+- } \
+- (type)__j; \
+-})
+-
+-/* Just like LIST_FIND but we search backwards */
+-#define LIST_FIND_B(head, cmpfn, type, args...) \
+-({ \
+- const struct list_head *__i, *__j = NULL; \
+- \
+- ASSERT_READ_LOCK(head); \
+- list_for_each_prev(__i, (head)) \
+- if (cmpfn((const type)__i , ## args)) { \
+- __j = __i; \
+- break; \
+- } \
+- (type)__j; \
+-})
+-
+-static inline int
+-__list_cmp_same(const void *p1, const void *p2) { return p1 == p2; }
+-
+-/* Is this entry in the list? */
+-static inline int
+-list_inlist(struct list_head *head, const void *entry)
+-{
+- return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL;
+-}
+-
+-/* Delete from list. */
+-#ifdef CONFIG_NETFILTER_DEBUG
+-#define LIST_DELETE(head, oldentry) \
+-do { \
+- ASSERT_WRITE_LOCK(head); \
+- if (!list_inlist(head, oldentry)) \
+- printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \
+- __FILE__, __LINE__, #oldentry, oldentry, #head); \
+- else list_del((struct list_head *)oldentry); \
+-} while(0)
+-#else
+-#define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry)
+-#endif
+-
+-/* Append. */
+-static inline void
+-list_append(struct list_head *head, void *new)
+-{
+- ASSERT_WRITE_LOCK(head);
+- list_add((new), (head)->prev);
+-}
+-
+-/* Prepend. */
+-static inline void
+-list_prepend(struct list_head *head, void *new)
+-{
+- ASSERT_WRITE_LOCK(head);
+- list_add(new, head);
+-}
+-
+-/* Insert according to ordering function; insert before first true. */
+-#define LIST_INSERT(head, new, cmpfn) \
+-do { \
+- struct list_head *__i; \
+- ASSERT_WRITE_LOCK(head); \
+- list_for_each(__i, (head)) \
+- if ((new), (typeof (new))__i) \
+- break; \
+- list_add((struct list_head *)(new), __i->prev); \
+-} while(0)
+-
+-/* If the field after the list_head is a nul-terminated string, you
+- can use these functions. */
+-static inline int __list_cmp_name(const void *i, const char *name)
+-{
+- return strcmp(name, i+sizeof(struct list_head)) == 0;
+-}
+-
+-/* Returns false if same name already in list, otherwise does insert. */
+-static inline int
+-list_named_insert(struct list_head *head, void *new)
+-{
+- if (LIST_FIND(head, __list_cmp_name, void *,
+- new + sizeof(struct list_head)))
+- return 0;
+- list_prepend(head, new);
+- return 1;
+-}
+-
+-/* Find this named element in the list. */
+-#define list_named_find(head, name) \
+-LIST_FIND(head, __list_cmp_name, void *, name)
+-
+-#endif /*_LISTHELP_H*/
+diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
+index 52a7b9e..d97e268 100644
+--- a/include/linux/netfilter_ipv6.h
++++ b/include/linux/netfilter_ipv6.h
+@@ -73,6 +73,7 @@ enum nf_ip6_hook_priorities {
+ };
+
+ #ifdef CONFIG_NETFILTER
++extern int ip6_route_me_harder(struct sk_buff *skb);
+ extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
+ unsigned int dataoff, u_int8_t protocol);
+
+diff --git a/include/linux/netfilter_ipv6/Kbuild b/include/linux/netfilter_ipv6/Kbuild
+index 913ddbf..9dd978d 100644
+--- a/include/linux/netfilter_ipv6/Kbuild
++++ b/include/linux/netfilter_ipv6/Kbuild
+@@ -1,6 +1,21 @@
+-header-y += ip6t_HL.h ip6t_LOG.h ip6t_MARK.h ip6t_REJECT.h ip6t_ah.h \
+- ip6t_esp.h ip6t_frag.h ip6t_hl.h ip6t_ipv6header.h \
+- ip6t_length.h ip6t_limit.h ip6t_mac.h ip6t_mark.h \
+- ip6t_multiport.h ip6t_opts.h ip6t_owner.h ip6t_policy.h \
+- ip6t_physdev.h ip6t_rt.h
+-unifdef-y := ip6_tables.h
++header-y += ip6t_HL.h
++header-y += ip6t_LOG.h
++header-y += ip6t_MARK.h
++header-y += ip6t_REJECT.h
++header-y += ip6t_ah.h
++header-y += ip6t_esp.h
++header-y += ip6t_frag.h
++header-y += ip6t_hl.h
++header-y += ip6t_ipv6header.h
++header-y += ip6t_length.h
++header-y += ip6t_limit.h
++header-y += ip6t_mac.h
++header-y += ip6t_mark.h
++header-y += ip6t_multiport.h
++header-y += ip6t_opts.h
++header-y += ip6t_owner.h
++header-y += ip6t_policy.h
++header-y += ip6t_physdev.h
++header-y += ip6t_rt.h
++
++unifdef-y += ip6_tables.h
+diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
+index d0d5d1e..d7a8e9c 100644
+--- a/include/linux/netfilter_ipv6/ip6_tables.h
++++ b/include/linux/netfilter_ipv6/ip6_tables.h
+@@ -300,8 +300,7 @@ extern unsigned int ip6t_do_table(struct
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+- struct ip6t_table *table,
+- void *userdata);
++ struct ip6t_table *table);
+
+ /* Check for an extension */
+ extern int ip6t_ext_hdr(u8 nexthdr);
+diff --git a/include/linux/netfilter_logging.h b/include/linux/netfilter_logging.h
+deleted file mode 100644
+index 562bb6a..0000000
+--- a/include/linux/netfilter_logging.h
++++ /dev/null
+@@ -1,33 +0,0 @@
+-/* Internal logging interface, which relies on the real
+- LOG target modules */
+-#ifndef __LINUX_NETFILTER_LOGGING_H
+-#define __LINUX_NETFILTER_LOGGING_H
+-
+-#ifdef __KERNEL__
+-#include <asm/atomic.h>
+-
+-struct nf_logging_t {
+- void (*nf_log_packet)(struct sk_buff **pskb,
+- unsigned int hooknum,
+- const struct net_device *in,
+- const struct net_device *out,
+- const char *prefix);
+- void (*nf_log)(char *pfh, size_t len,
+- const char *prefix);
+-};
+-
+-extern void nf_log_register(int pf, const struct nf_logging_t *logging);
+-extern void nf_log_unregister(int pf, const struct nf_logging_t *logging);
+-
+-extern void nf_log_packet(int pf,
+- struct sk_buff **pskb,
+- unsigned int hooknum,
+- const struct net_device *in,
+- const struct net_device *out,
+- const char *fmt, ...);
+-extern void nf_log(int pf,
+- char *pfh, size_t len,
+- const char *fmt, ...);
+-#endif /*__KERNEL__*/
+-
+-#endif /*__LINUX_NETFILTER_LOGGING_H*/
+diff --git a/include/linux/netlink.h b/include/linux/netlink.h
+index 855b446..6641162 100644
+--- a/include/linux/netlink.h
++++ b/include/linux/netlink.h
+@@ -21,6 +21,8 @@
+ #define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+ #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
+ #define NETLINK_GENERIC 16
++/* leave room for NETLINK_DM (DM Events) */
++#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
+
+ #define MAX_LINKS 32
+
+diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
+index 6c2066c..45228c1 100644
+--- a/include/linux/nfs_fs.h
++++ b/include/linux/nfs_fs.h
+@@ -9,6 +9,8 @@
+ #ifndef _LINUX_NFS_FS_H
+ #define _LINUX_NFS_FS_H
+
++#include <linux/magic.h>
++
+ /*
+ * Enable debugging support for nfs client.
+ * Requires RPC_DEBUG.
+@@ -22,11 +24,6 @@
+ #define NFS_MAX_TCP_TIMEOUT (600*HZ)
+
+ /*
+- * superblock magic number for NFS
+- */
+-#define NFS_SUPER_MAGIC 0x6969
+-
+-/*
+ * When flushing a cluster of dirty pages, there can be different
+ * strategies:
+ */
+@@ -42,6 +39,7 @@
+ #include <linux/in.h>
+ #include <linux/mm.h>
+ #include <linux/pagemap.h>
++#include <linux/rbtree.h>
+ #include <linux/rwsem.h>
+ #include <linux/wait.h>
+
+@@ -69,6 +67,8 @@
+ * NFSv3/v4 Access mode cache entry
+ */
+ struct nfs_access_entry {
++ struct rb_node rb_node;
++ struct list_head lru;
+ unsigned long jiffies;
+ struct rpc_cred * cred;
+ int mask;
+@@ -145,7 +145,9 @@ struct nfs_inode {
+ */
+ atomic_t data_updates;
+
+- struct nfs_access_entry cache_access;
++ struct rb_root access_cache;
++ struct list_head access_cache_entry_lru;
++ struct list_head access_cache_inode_lru;
+ #ifdef CONFIG_NFS_V3_ACL
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+@@ -155,7 +157,7 @@ struct nfs_inode {
+ * This is the cookie verifier used for NFSv3 readdir
+ * operations
+ */
+- __u32 cookieverf[2];
++ __be32 cookieverf[2];
+
+ /*
+ * This is the list of dirty unwritten pages.
+@@ -199,6 +201,7 @@ struct nfs_inode {
+ #define NFS_INO_REVALIDATING (0) /* revalidating attrs */
+ #define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */
+ #define NFS_INO_STALE (2) /* possible stale inode */
++#define NFS_INO_ACL_LRU_SET (3) /* Inode is on the LRU list */
+
+ static inline struct nfs_inode *NFS_I(struct inode *inode)
+ {
+@@ -209,8 +212,7 @@ static inline struct nfs_inode *NFS_I(st
+ #define NFS_FH(inode) (&NFS_I(inode)->fh)
+ #define NFS_SERVER(inode) (NFS_SB(inode->i_sb))
+ #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
+-#define NFS_PROTO(inode) (NFS_SERVER(inode)->rpc_ops)
+-#define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode)))
++#define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops)
+ #define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf)
+ #define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies)
+ #define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr)
+@@ -288,6 +290,7 @@ static inline int nfs_verify_change_attr
+ * linux/fs/nfs/inode.c
+ */
+ extern int nfs_sync_mapping(struct address_space *mapping);
++extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
+ extern void nfs_zap_caches(struct inode *);
+ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
+ struct nfs_fattr *);
+@@ -297,6 +300,7 @@ extern int nfs_getattr(struct vfsmount *
+ extern int nfs_permission(struct inode *, int, struct nameidata *);
+ extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
+ extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
++extern void nfs_access_zap_cache(struct inode *inode);
+ extern int nfs_open(struct inode *, struct file *);
+ extern int nfs_release(struct inode *, struct file *);
+ extern int nfs_attribute_timeout(struct inode *inode);
+@@ -312,10 +316,6 @@ extern void nfs_end_data_update(struct i
+ extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
+ extern void put_nfs_open_context(struct nfs_open_context *ctx);
+ extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
+-extern struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+- const struct dentry *dentry,
+- struct nfs_fh *fh,
+- struct nfs_fattr *fattr);
+
+ /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
+ extern u32 root_nfs_parse_addr(char *name); /*__init*/
+@@ -368,10 +368,12 @@ extern int nfs3_removexattr (struct dent
+ */
+ extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
+ unsigned long);
+-extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf,
+- size_t count, loff_t pos);
+-extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos);
++extern ssize_t nfs_file_direct_read(struct kiocb *iocb,
++ const struct iovec *iov, unsigned long nr_segs,
++ loff_t pos);
++extern ssize_t nfs_file_direct_write(struct kiocb *iocb,
++ const struct iovec *iov, unsigned long nr_segs,
++ loff_t pos);
+
+ /*
+ * linux/fs/nfs/dir.c
+@@ -579,6 +581,7 @@ extern void * nfs_root_data(void);
+ #define NFSDBG_FILE 0x0040
+ #define NFSDBG_ROOT 0x0080
+ #define NFSDBG_CALLBACK 0x0100
++#define NFSDBG_CLIENT 0x0200
+ #define NFSDBG_ALL 0xFFFF
+
+ #ifdef __KERNEL__
+diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
+index 6b4a13c..7ccfc7e 100644
+--- a/include/linux/nfs_fs_sb.h
++++ b/include/linux/nfs_fs_sb.h
+@@ -7,13 +7,79 @@
+ struct nfs_iostats;
+
+ /*
++ * The nfs_client identifies our client state to the server.
++ */
++struct nfs_client {
++ atomic_t cl_count;
++ int cl_cons_state; /* current construction state (-ve: init error) */
++#define NFS_CS_READY 0 /* ready to be used */
++#define NFS_CS_INITING 1 /* busy initialising */
++ int cl_nfsversion; /* NFS protocol version */
++ unsigned long cl_res_state; /* NFS resources state */
++#define NFS_CS_RPCIOD 0 /* - rpciod started */
++#define NFS_CS_CALLBACK 1 /* - callback started */
++#define NFS_CS_IDMAP 2 /* - idmap started */
++#define NFS_CS_RENEWD 3 /* - renewd started */
++ struct sockaddr_in cl_addr; /* server identifier */
++ char * cl_hostname; /* hostname of server */
++ struct list_head cl_share_link; /* link in global client list */
++ struct list_head cl_superblocks; /* List of nfs_server structs */
++
++ struct rpc_clnt * cl_rpcclient;
++ const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */
++ unsigned long retrans_timeo; /* retransmit timeout */
++ unsigned int retrans_count; /* number of retransmit tries */
++
++#ifdef CONFIG_NFS_V4
++ u64 cl_clientid; /* constant */
++ nfs4_verifier cl_confirm;
++ unsigned long cl_state;
++
++ u32 cl_lockowner_id;
++
++ /*
++ * The following rwsem ensures exclusive access to the server
++ * while we recover the state following a lease expiration.
++ */
++ struct rw_semaphore cl_sem;
++
++ struct list_head cl_delegations;
++ struct list_head cl_state_owners;
++ struct list_head cl_unused;
++ int cl_nunused;
++ spinlock_t cl_lock;
++
++ unsigned long cl_lease_time;
++ unsigned long cl_last_renewal;
++ struct work_struct cl_renewd;
++
++ struct rpc_wait_queue cl_rpcwaitq;
++
++ /* used for the setclientid verifier */
++ struct timespec cl_boot_time;
++
++ /* idmapper */
++ struct idmap * cl_idmap;
++
++ /* Our own IP address, as a null-terminated string.
++ * This is used to generate the clientid, and the callback address.
++ */
++ char cl_ipaddr[16];
++ unsigned char cl_id_uniquifier;
++#endif
++};
++
++/*
+ * NFS client parameters stored in the superblock.
+ */
+ struct nfs_server {
++ struct nfs_client * nfs_client; /* shared client and NFS4 state */
++ struct list_head client_link; /* List of other nfs_server structs
++ * that share the same client
++ */
++ struct list_head master_link; /* link in master servers list */
+ struct rpc_clnt * client; /* RPC client handle */
+- struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */
+ struct rpc_clnt * client_acl; /* ACL RPC client handle */
+- struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
+ struct nfs_iostats * io_stats; /* I/O statistics */
+ struct backing_dev_info backing_dev_info;
+ int flags; /* various flags */
+@@ -29,24 +95,14 @@ struct nfs_server {
+ unsigned int acregmax;
+ unsigned int acdirmin;
+ unsigned int acdirmax;
+- unsigned long retrans_timeo; /* retransmit timeout */
+- unsigned int retrans_count; /* number of retransmit tries */
+ unsigned int namelen;
+- char * hostname; /* remote hostname */
+- struct nfs_fh fh;
+- struct sockaddr_in addr;
++
+ struct nfs_fsid fsid;
++ __u64 maxfilesize; /* maximum file size */
+ unsigned long mount_time; /* when this fs was mounted */
++ dev_t s_dev; /* superblock dev numbers */
++
+ #ifdef CONFIG_NFS_V4
+- /* Our own IP address, as a null-terminated string.
+- * This is used to generate the clientid, and the callback address.
+- */
+- char ip_addr[16];
+- char * mnt_path;
+- struct nfs4_client * nfs4_state; /* all NFSv4 state starts here */
+- struct list_head nfs4_siblings; /* List of other nfs_server structs
+- * that share the same clientid
+- */
+ u32 attr_bitmask[2];/* V4 bitmask representing the set
+ of attributes supported on this
+ filesystem */
+@@ -54,6 +110,7 @@ struct nfs_server {
+ that are supported on this
+ filesystem */
+ #endif
++ void (*destroy)(struct nfs_server *);
+ };
+
+ /* Server capabilities */
+diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h
+index 102e560..15a9f3b 100644
+--- a/include/linux/nfs_idmap.h
++++ b/include/linux/nfs_idmap.h
+@@ -62,15 +62,15 @@ struct idmap_msg {
+ #ifdef __KERNEL__
+
+ /* Forward declaration to make this header independent of others */
+-struct nfs4_client;
++struct nfs_client;
+
+-void nfs_idmap_new(struct nfs4_client *);
+-void nfs_idmap_delete(struct nfs4_client *);
++int nfs_idmap_new(struct nfs_client *);
++void nfs_idmap_delete(struct nfs_client *);
+
+-int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
+-int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
+-int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
+-int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
++int nfs_map_name_to_uid(struct nfs_client *, const char *, size_t, __u32 *);
++int nfs_map_group_to_gid(struct nfs_client *, const char *, size_t, __u32 *);
++int nfs_map_uid_to_name(struct nfs_client *, __u32, char *);
++int nfs_map_gid_to_group(struct nfs_client *, __u32, char *);
+
+ extern unsigned int nfs_idmap_cache_timeout;
+ #endif /* __KERNEL__ */
+diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
+index 41e5a19..768c1ad 100644
+--- a/include/linux/nfs_xdr.h
++++ b/include/linux/nfs_xdr.h
+@@ -1,7 +1,6 @@
+ #ifndef _LINUX_NFS_XDR_H
+ #define _LINUX_NFS_XDR_H
+
+-#include <linux/sunrpc/xprt.h>
+ #include <linux/nfsacl.h>
+
+ /*
+@@ -267,7 +266,7 @@ struct nfs_writeargs {
+
+ struct nfs_writeverf {
+ enum nfs3_stable_how committed;
+- __u32 verifier[2];
++ __be32 verifier[2];
+ };
+
+ struct nfs_writeres {
+@@ -359,8 +358,8 @@ struct nfs_symlinkargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ unsigned int fromlen;
+- const char * topath;
+- unsigned int tolen;
++ struct page ** pages;
++ unsigned int pathlen;
+ struct iattr * sattr;
+ };
+
+@@ -421,7 +420,7 @@ struct nfs3_createargs {
+ unsigned int len;
+ struct iattr * sattr;
+ enum nfs3_createmode createmode;
+- __u32 verifier[2];
++ __be32 verifier[2];
+ };
+
+ struct nfs3_mkdirargs {
+@@ -435,8 +434,8 @@ struct nfs3_symlinkargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ unsigned int fromlen;
+- const char * topath;
+- unsigned int tolen;
++ struct page ** pages;
++ unsigned int pathlen;
+ struct iattr * sattr;
+ };
+
+@@ -468,7 +467,7 @@ struct nfs3_linkargs {
+ struct nfs3_readdirargs {
+ struct nfs_fh * fh;
+ __u64 cookie;
+- __u32 verf[2];
++ __be32 verf[2];
+ int plus;
+ unsigned int count;
+ struct page ** pages;
+@@ -504,7 +503,7 @@ struct nfs3_linkres {
+
+ struct nfs3_readdirres {
+ struct nfs_fattr * dir_attr;
+- __u32 * verf;
++ __be32 * verf;
+ int plus;
+ };
+
+@@ -534,7 +533,10 @@ struct nfs4_accessres {
+ struct nfs4_create_arg {
+ u32 ftype;
+ union {
+- struct qstr * symlink; /* NF4LNK */
++ struct {
++ struct page ** pages;
++ unsigned int len;
++ } symlink; /* NF4LNK */
+ struct {
+ u32 specdata1;
+ u32 specdata2;
+@@ -770,6 +772,9 @@ struct nfs_rpc_ops {
+
+ int (*getroot) (struct nfs_server *, struct nfs_fh *,
+ struct nfs_fsinfo *);
++ int (*lookupfh)(struct nfs_server *, struct nfs_fh *,
++ struct qstr *, struct nfs_fh *,
++ struct nfs_fattr *);
+ int (*getattr) (struct nfs_server *, struct nfs_fh *,
+ struct nfs_fattr *);
+ int (*setattr) (struct dentry *, struct nfs_fattr *,
+@@ -791,9 +796,8 @@ struct nfs_rpc_ops {
+ int (*rename) (struct inode *, struct qstr *,
+ struct inode *, struct qstr *);
+ int (*link) (struct inode *, struct inode *, struct qstr *);
+- int (*symlink) (struct inode *, struct qstr *, struct qstr *,
+- struct iattr *, struct nfs_fh *,
+- struct nfs_fattr *);
++ int (*symlink) (struct inode *, struct dentry *, struct page *,
++ unsigned int, struct iattr *);
+ int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
+ int (*rmdir) (struct inode *, struct qstr *);
+ int (*readdir) (struct dentry *, struct rpc_cred *,
+@@ -806,7 +810,8 @@ struct nfs_rpc_ops {
+ struct nfs_fsinfo *);
+ int (*pathconf) (struct nfs_server *, struct nfs_fh *,
+ struct nfs_pathconf *);
+- u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
++ int (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
++ __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus);
+ void (*read_setup) (struct nfs_read_data *);
+ int (*read_done) (struct rpc_task *, struct nfs_read_data *);
+ void (*write_setup) (struct nfs_write_data *, int how);
+@@ -829,9 +834,9 @@ struct nfs_rpc_ops {
+ /*
+ * Function vectors etc. for the NFS client
+ */
+-extern struct nfs_rpc_ops nfs_v2_clientops;
+-extern struct nfs_rpc_ops nfs_v3_clientops;
+-extern struct nfs_rpc_ops nfs_v4_clientops;
++extern const struct nfs_rpc_ops nfs_v2_clientops;
++extern const struct nfs_rpc_ops nfs_v3_clientops;
++extern const struct nfs_rpc_ops nfs_v4_clientops;
+ extern struct rpc_version nfs_version2;
+ extern struct rpc_version nfs_version3;
+ extern struct rpc_version nfs_version4;
+diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild
+index c8c5456..d9c5455 100644
+--- a/include/linux/nfsd/Kbuild
++++ b/include/linux/nfsd/Kbuild
+@@ -1,2 +1,7 @@
+-unifdef-y := const.h export.h stats.h syscall.h nfsfh.h debug.h auth.h
+-
++unifdef-y += const.h
++unifdef-y += export.h
++unifdef-y += stats.h
++unifdef-y += syscall.h
++unifdef-y += nfsfh.h
++unifdef-y += debug.h
++unifdef-y += auth.h
+diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
+index c3a3557..007480c 100644
+--- a/include/linux/nfsd/cache.h
++++ b/include/linux/nfsd/cache.h
+@@ -26,14 +26,14 @@ struct svc_cacherep {
+ c_type, /* status, buffer */
+ c_secure : 1; /* req came from port < 1024 */
+ struct sockaddr_in c_addr;
+- u32 c_xid;
++ __be32 c_xid;
+ u32 c_prot;
+ u32 c_proc;
+ u32 c_vers;
+ unsigned long c_timestamp;
+ union {
+ struct kvec u_vec;
+- u32 u_status;
++ __be32 u_status;
+ } c_u;
+ };
+
+@@ -75,7 +75,7 @@ enum {
+ void nfsd_cache_init(void);
+ void nfsd_cache_shutdown(void);
+ int nfsd_cache_lookup(struct svc_rqst *, int);
+-void nfsd_cache_update(struct svc_rqst *, int, u32 *);
++void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
+
+ #endif /* __KERNEL__ */
+ #endif /* NFSCACHE_H */
+diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
+index b75bb1b..f0cc777 100644
+--- a/include/linux/nfsd/const.h
++++ b/include/linux/nfsd/const.h
+@@ -20,17 +20,31 @@
+ #define NFSSVC_MAXVERS 3
+
+ /*
+- * Maximum blocksize supported by daemon currently at 32K
++ * Maximum blocksizes supported by daemon under various circumstances.
+ */
+-#define NFSSVC_MAXBLKSIZE (32*1024)
++#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD
++/* NFSv2 is limited by the protocol specification, see RFC 1094 */
++#define NFSSVC_MAXBLKSIZE_V2 (8*1024)
+
+ #ifdef __KERNEL__
+
++#include <linux/sunrpc/msg_prot.h>
++
+ #ifndef NFS_SUPER_MAGIC
+ # define NFS_SUPER_MAGIC 0x6969
+ #endif
+
+-#define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE)
++/*
++ * Largest number of bytes we need to allocate for an NFS
++ * call or reply. Used to control buffer sizes. We use
++ * the length of v3 WRITE, READDIR and READDIR replies
++ * which are an RPC header, up to 26 XDR units of reply
++ * data, and some page data.
++ *
++ * Note that accuracy here doesn't matter too much as the
++ * size is rounded up to a page size when allocating space.
++ */
++#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
+
+ #ifdef CONFIG_NFSD_V4
+ # define NFSSVC_XDRSIZE NFS4_SVC_XDRSIZE
+diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
+index d2a8abb..045e38c 100644
+--- a/include/linux/nfsd/export.h
++++ b/include/linux/nfsd/export.h
+@@ -45,15 +45,36 @@
+
+ #ifdef __KERNEL__
+
++/*
++ * FS Locations
++ */
++
++#define MAX_FS_LOCATIONS 128
++
++struct nfsd4_fs_location {
++ char *hosts; /* colon separated list of hosts */
++ char *path; /* slash separated list of path components */
++};
++
++struct nfsd4_fs_locations {
++ uint32_t locations_count;
++ struct nfsd4_fs_location *locations;
++/* If we're not actually serving this data ourselves (only providing a
++ * list of replicas that do serve it) then we set "migrated": */
++ int migrated;
++};
++
+ struct svc_export {
+ struct cache_head h;
+ struct auth_domain * ex_client;
+ int ex_flags;
+ struct vfsmount * ex_mnt;
+ struct dentry * ex_dentry;
++ char * ex_path;
+ uid_t ex_anon_uid;
+ gid_t ex_anon_gid;
+ int ex_fsid;
++ struct nfsd4_fs_locations ex_fslocs;
+ };
+
+ /* an "export key" (expkey) maps a filehandlefragement to an
+@@ -96,8 +117,8 @@ struct svc_export * exp_parent(struct au
+ struct cache_req *reqp);
+ int exp_rootfh(struct auth_domain *,
+ char *path, struct knfsd_fh *, int maxsize);
+-int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
+-int nfserrno(int errno);
++__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
++__be32 nfserrno(int errno);
+
+ extern struct cache_detail svc_export_cache;
+
+diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
+index 2dcad29..eb23114 100644
+--- a/include/linux/nfsd/nfsd.h
++++ b/include/linux/nfsd/nfsd.h
+@@ -50,7 +50,7 @@
+ * Callback function for readdir
+ */
+ struct readdir_cd {
+- int err; /* 0, nfserr, or nfserr_eof */
++ __be32 err; /* 0, nfserr, or nfserr_eof */
+ };
+ typedef int (*encode_dent_fn)(struct readdir_cd *, const char *,
+ int, loff_t, ino_t, unsigned int);
+@@ -64,7 +64,7 @@ extern struct svc_serv *nfsd_serv;
+ * Function prototypes.
+ */
+ int nfsd_svc(unsigned short port, int nrservs);
+-int nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp);
++int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
+
+ /* nfsd/vfs.c */
+ int fh_lock_parent(struct svc_fh *, struct dentry *);
+@@ -72,57 +72,57 @@ int nfsd_racache_init(int);
+ void nfsd_racache_shutdown(void);
+ int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
+ struct svc_export **expp);
+-int nfsd_lookup(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
+ const char *, int, struct svc_fh *);
+-int nfsd_setattr(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
+ struct iattr *, int, time_t);
+ #ifdef CONFIG_NFSD_V4
+-int nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
+ struct nfs4_acl *);
+ int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
+ #endif /* CONFIG_NFSD_V4 */
+-int nfsd_create(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
+ char *name, int len, struct iattr *attrs,
+ int type, dev_t rdev, struct svc_fh *res);
+ #ifdef CONFIG_NFSD_V3
+-int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
+-int nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
++__be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
+ char *name, int len, struct iattr *attrs,
+ struct svc_fh *res, int createmode,
+ u32 *verifier, int *truncp);
+-int nfsd_commit(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
+ loff_t, unsigned long);
+ #endif /* CONFIG_NFSD_V3 */
+-int nfsd_open(struct svc_rqst *, struct svc_fh *, int,
++__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int,
+ int, struct file **);
+ void nfsd_close(struct file *);
+-int nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
++__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
+ loff_t, struct kvec *, int, unsigned long *);
+-int nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
++__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
+ loff_t, struct kvec *,int, unsigned long, int *);
+-int nfsd_readlink(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
+ char *, int *);
+-int nfsd_symlink(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
+ char *name, int len, char *path, int plen,
+ struct svc_fh *res, struct iattr *);
+-int nfsd_link(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
+ char *, int, struct svc_fh *);
+-int nfsd_rename(struct svc_rqst *,
++__be32 nfsd_rename(struct svc_rqst *,
+ struct svc_fh *, char *, int,
+ struct svc_fh *, char *, int);
+-int nfsd_remove(struct svc_rqst *,
++__be32 nfsd_remove(struct svc_rqst *,
+ struct svc_fh *, char *, int);
+-int nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
++__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
+ char *name, int len);
+ int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
+ unsigned long size);
+-int nfsd_readdir(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
+ loff_t *, struct readdir_cd *, encode_dent_fn);
+-int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
++__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
+ struct kstatfs *);
+
+ int nfsd_notify_change(struct inode *, struct iattr *);
+-int nfsd_permission(struct svc_export *, struct dentry *, int);
++__be32 nfsd_permission(struct svc_export *, struct dentry *, int);
+ int nfsd_sync_dir(struct dentry *dp);
+
+ #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+@@ -140,6 +140,12 @@ struct posix_acl *nfsd_get_posix_acl(str
+ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
+ #endif
+
++enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
++int nfsd_vers(int vers, enum vers_op change);
++void nfsd_reset_versions(void);
++int nfsd_create_serv(void);
++
++extern int nfsd_max_blksize;
+
+ /*
+ * NFSv4 State
+@@ -210,6 +216,7 @@ void nfsd_lockd_shutdown(void);
+ #define nfserr_clid_inuse __constant_htonl(NFSERR_CLID_INUSE)
+ #define nfserr_stale_clientid __constant_htonl(NFSERR_STALE_CLIENTID)
+ #define nfserr_resource __constant_htonl(NFSERR_RESOURCE)
++#define nfserr_moved __constant_htonl(NFSERR_MOVED)
+ #define nfserr_nofilehandle __constant_htonl(NFSERR_NOFILEHANDLE)
+ #define nfserr_minor_vers_mismatch __constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
+ #define nfserr_share_denied __constant_htonl(NFSERR_SHARE_DENIED)
+@@ -231,6 +238,7 @@ void nfsd_lockd_shutdown(void);
+ #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)
++#define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME)
+
+ /* error codes for internal use */
+ /* if a request fails due to kmalloc failure, it gets dropped.
+@@ -286,7 +294,6 @@ static inline int is_fsid(struct svc_fh
+ /*
+ * The following attributes are currently not supported by the NFSv4 server:
+ * ARCHIVE (deprecated anyway)
+- * FS_LOCATIONS (will be supported eventually)
+ * HIDDEN (unlikely to be supported any time soon)
+ * MIMETYPE (unlikely to be supported any time soon)
+ * QUOTA_* (will be supported in a forthcoming patch)
+@@ -302,7 +309,7 @@ static inline int is_fsid(struct svc_fh
+ | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \
+ | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \
+ | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \
+- | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_HOMOGENEOUS \
++ | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \
+ | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \
+ | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL)
+
+diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
+index f9edcd2..f3b51d6 100644
+--- a/include/linux/nfsd/nfsfh.h
++++ b/include/linux/nfsd/nfsfh.h
+@@ -157,7 +157,7 @@ typedef struct svc_fh {
+ __u64 fh_post_size; /* i_size */
+ unsigned long fh_post_blocks; /* i_blocks */
+ unsigned long fh_post_blksize;/* i_blksize */
+- __u32 fh_post_rdev[2];/* i_rdev */
++ __be32 fh_post_rdev[2];/* i_rdev */
+ struct timespec fh_post_atime; /* i_atime */
+ struct timespec fh_post_mtime; /* i_mtime */
+ struct timespec fh_post_ctime; /* i_ctime */
+@@ -209,9 +209,9 @@ extern char * SVCFH_fmt(struct svc_fh *f
+ /*
+ * Function prototypes
+ */
+-u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
+-int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
+-int fh_update(struct svc_fh *);
++__be32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
++__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
++__be32 fh_update(struct svc_fh *);
+ void fh_put(struct svc_fh *);
+
+ static __inline__ struct svc_fh *
+@@ -269,14 +269,8 @@ fill_post_wcc(struct svc_fh *fhp)
+ fhp->fh_post_uid = inode->i_uid;
+ fhp->fh_post_gid = inode->i_gid;
+ fhp->fh_post_size = inode->i_size;
+- if (inode->i_blksize) {
+- fhp->fh_post_blksize = inode->i_blksize;
+- fhp->fh_post_blocks = inode->i_blocks;
+- } else {
+- fhp->fh_post_blksize = BLOCK_SIZE;
+- /* how much do we care for accuracy with MinixFS? */
+- fhp->fh_post_blocks = (inode->i_size+511) >> 9;
+- }
++ fhp->fh_post_blksize = BLOCK_SIZE;
++ fhp->fh_post_blocks = inode->i_blocks;
+ fhp->fh_post_rdev[0] = htonl((u32)imajor(inode));
+ fhp->fh_post_rdev[1] = htonl((u32)iminor(inode));
+ fhp->fh_post_atime = inode->i_atime;
+@@ -296,8 +290,9 @@ fill_post_wcc(struct svc_fh *fhp)
+ * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
+ * so, any changes here should be reflected there.
+ */
++
+ static inline void
+-fh_lock(struct svc_fh *fhp)
++fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
+ {
+ struct dentry *dentry = fhp->fh_dentry;
+ struct inode *inode;
+@@ -316,11 +311,17 @@ fh_lock(struct svc_fh *fhp)
+ }
+
+ inode = dentry->d_inode;
+- mutex_lock(&inode->i_mutex);
++ mutex_lock_nested(&inode->i_mutex, subclass);
+ fill_pre_wcc(fhp);
+ fhp->fh_locked = 1;
+ }
+
++static inline void
++fh_lock(struct svc_fh *fhp)
++{
++ fh_lock_nested(fhp, I_MUTEX_NORMAL);
++}
++
+ /*
+ * Unlock a file handle/inode
+ */
+diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
+index 8bf23cf..c3673f4 100644
+--- a/include/linux/nfsd/state.h
++++ b/include/linux/nfsd/state.h
+@@ -125,7 +125,7 @@ struct nfs4_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 */
++ __be32 cl_addr; /* client ipaddress */
+ struct svc_cred cl_cred; /* setclientid principal */
+ clientid_t cl_clientid; /* generated by server */
+ nfs4_verifier cl_confirm; /* generated by server */
+@@ -164,7 +164,7 @@ update_stateid(stateid_t *stateid)
+ * is cached.
+ */
+ struct nfs4_replay {
+- u32 rp_status;
++ __be32 rp_status;
+ unsigned int rp_buflen;
+ char *rp_buf;
+ unsigned intrp_allocated;
+@@ -273,19 +273,19 @@ struct nfs4_stateid {
+ ((err) != nfserr_stale_stateid) && \
+ ((err) != nfserr_bad_stateid))
+
+-extern int nfsd4_renew(clientid_t *clid);
+-extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
++extern __be32 nfsd4_renew(clientid_t *clid);
++extern __be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
+ stateid_t *stateid, int flags, struct file **filp);
+ extern void nfs4_lock_state(void);
+ extern void nfs4_unlock_state(void);
+ extern int nfs4_in_grace(void);
+-extern int nfs4_check_open_reclaim(clientid_t *clid);
++extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
+ extern void put_nfs4_client(struct nfs4_client *clp);
+ 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 __be32 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);
+diff --git a/include/linux/nfsd/stats.h b/include/linux/nfsd/stats.h
+index 28a82fd..7678cfb 100644
+--- a/include/linux/nfsd/stats.h
++++ b/include/linux/nfsd/stats.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/nfsd/stats.h
++ * linux/include/linux/nfsd/stats.h
+ *
+ * Statistics for NFS server.
+ *
+diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
+index dae0fae..8bcddcc 100644
+--- a/include/linux/nfsd/syscall.h
++++ b/include/linux/nfsd/syscall.h
+@@ -38,21 +38,6 @@
+ #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
+ #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */
+
+-/*
+- * Macros used to set version
+- */
+-#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v)))
+-#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v)))
+-#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v)))
+-
+-#if defined(CONFIG_NFSD_V4)
+-#define NFSCTL_VERALL (0x1c /* 0b011100 */)
+-#elif defined(CONFIG_NFSD_V3)
+-#define NFSCTL_VERALL (0x0c /* 0b001100 */)
+-#else
+-#define NFSCTL_VERALL (0x04 /* 0b000100 */)
+-#endif
+-
+ /* SVC */
+ struct nfsctl_svc {
+ unsigned short svc_port;
+@@ -134,8 +119,6 @@ extern int exp_delclient(struct nfsctl_
+ extern int exp_export(struct nfsctl_export *nxp);
+ extern int exp_unexport(struct nfsctl_export *nxp);
+
+-extern unsigned int nfsd_versbits;
+-
+ #endif /* __KERNEL__ */
+
+ #endif /* NFSD_SYSCALL_H */
+diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
+index 3f4f714..877192d 100644
+--- a/include/linux/nfsd/xdr.h
++++ b/include/linux/nfsd/xdr.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/inxlude/linux/nfsd/xdr.h
++ * linux/include/linux/nfsd/xdr.h
+ *
+ * XDR types for nfsd. This is mainly a typing exercise.
+ */
+@@ -30,7 +30,6 @@ struct nfsd_readargs {
+ struct svc_fh fh;
+ __u32 offset;
+ __u32 count;
+- struct kvec vec[RPCSVC_MAXPAGES];
+ int vlen;
+ };
+
+@@ -38,7 +37,6 @@ struct nfsd_writeargs {
+ svc_fh fh;
+ __u32 offset;
+ int len;
+- struct kvec vec[RPCSVC_MAXPAGES];
+ int vlen;
+ };
+
+@@ -83,7 +81,7 @@ struct nfsd_readdirargs {
+ struct svc_fh fh;
+ __u32 cookie;
+ __u32 count;
+- u32 * buffer;
++ __be32 * buffer;
+ };
+
+ struct nfsd_attrstat {
+@@ -110,9 +108,9 @@ struct nfsd_readdirres {
+ int count;
+
+ struct readdir_cd common;
+- u32 * buffer;
++ __be32 * buffer;
+ int buflen;
+- u32 * offset;
++ __be32 * offset;
+ };
+
+ struct nfsd_statfsres {
+@@ -137,43 +135,43 @@ union nfsd_xdrstore {
+ #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore)
+
+
+-int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
+-int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
+-int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *);
++int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
++int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *,
+ struct nfsd_sattrargs *);
+-int nfssvc_decode_diropargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *,
+ struct nfsd_diropargs *);
+-int nfssvc_decode_readargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_readargs(struct svc_rqst *, __be32 *,
+ struct nfsd_readargs *);
+-int nfssvc_decode_writeargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *,
+ struct nfsd_writeargs *);
+-int nfssvc_decode_createargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_createargs(struct svc_rqst *, __be32 *,
+ struct nfsd_createargs *);
+-int nfssvc_decode_renameargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *,
+ struct nfsd_renameargs *);
+-int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *,
+ struct nfsd_readlinkargs *);
+-int nfssvc_decode_linkargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *,
+ struct nfsd_linkargs *);
+-int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *,
+ struct nfsd_symlinkargs *);
+-int nfssvc_decode_readdirargs(struct svc_rqst *, u32 *,
++int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *,
+ struct nfsd_readdirargs *);
+-int nfssvc_encode_void(struct svc_rqst *, u32 *, void *);
+-int nfssvc_encode_attrstat(struct svc_rqst *, u32 *, struct nfsd_attrstat *);
+-int nfssvc_encode_diropres(struct svc_rqst *, u32 *, struct nfsd_diropres *);
+-int nfssvc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd_readlinkres *);
+-int nfssvc_encode_readres(struct svc_rqst *, u32 *, struct nfsd_readres *);
+-int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *);
+-int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *);
++int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *);
++int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *);
++int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *);
++int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *);
++int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *);
++int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *);
++int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *);
+
+ int nfssvc_encode_entry(struct readdir_cd *, const char *name,
+ int namlen, loff_t offset, ino_t ino, unsigned int);
+
+-int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
++int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
+
+ /* Helper functions for NFSv2 ACL code */
+-u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp);
+-u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp);
++__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp);
++__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp);
+
+ #endif /* LINUX_NFSD_H */
+diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
+index a432274..7996386 100644
+--- a/include/linux/nfsd/xdr3.h
++++ b/include/linux/nfsd/xdr3.h
+@@ -33,7 +33,6 @@ struct nfsd3_readargs {
+ struct svc_fh fh;
+ __u64 offset;
+ __u32 count;
+- struct kvec vec[RPCSVC_MAXPAGES];
+ int vlen;
+ };
+
+@@ -43,7 +42,6 @@ struct nfsd3_writeargs {
+ __u32 count;
+ int stable;
+ __u32 len;
+- struct kvec vec[RPCSVC_MAXPAGES];
+ int vlen;
+ };
+
+@@ -53,7 +51,7 @@ struct nfsd3_createargs {
+ int len;
+ int createmode;
+ struct iattr attrs;
+- __u32 * verf;
++ __be32 * verf;
+ };
+
+ struct nfsd3_mknodargs {
+@@ -100,8 +98,8 @@ struct nfsd3_readdirargs {
+ __u64 cookie;
+ __u32 dircount;
+ __u32 count;
+- __u32 * verf;
+- u32 * buffer;
++ __be32 * verf;
++ __be32 * buffer;
+ };
+
+ struct nfsd3_commitargs {
+@@ -124,79 +122,79 @@ struct nfsd3_setaclargs {
+ };
+
+ struct nfsd3_attrstat {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ struct kstat stat;
+ };
+
+ /* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */
+ struct nfsd3_diropres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh dirfh;
+ struct svc_fh fh;
+ };
+
+ struct nfsd3_accessres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ __u32 access;
+ };
+
+ struct nfsd3_readlinkres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ __u32 len;
+ };
+
+ struct nfsd3_readres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ unsigned long count;
+ int eof;
+ };
+
+ struct nfsd3_writeres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ unsigned long count;
+ int committed;
+ };
+
+ struct nfsd3_renameres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh ffh;
+ struct svc_fh tfh;
+ };
+
+ struct nfsd3_linkres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh tfh;
+ struct svc_fh fh;
+ };
+
+ struct nfsd3_readdirres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ int count;
+- __u32 verf[2];
++ __be32 verf[2];
+
+ struct readdir_cd common;
+- u32 * buffer;
++ __be32 * buffer;
+ int buflen;
+- u32 * offset;
+- u32 * offset1;
++ __be32 * offset;
++ __be32 * offset1;
+ struct svc_rqst * rqstp;
+
+ };
+
+ struct nfsd3_fsstatres {
+- __u32 status;
++ __be32 status;
+ struct kstatfs stats;
+ __u32 invarsec;
+ };
+
+ struct nfsd3_fsinfores {
+- __u32 status;
++ __be32 status;
+ __u32 f_rtmax;
+ __u32 f_rtpref;
+ __u32 f_rtmult;
+@@ -209,7 +207,7 @@ struct nfsd3_fsinfores {
+ };
+
+ struct nfsd3_pathconfres {
+- __u32 status;
++ __be32 status;
+ __u32 p_link_max;
+ __u32 p_name_max;
+ __u32 p_no_trunc;
+@@ -219,12 +217,12 @@ struct nfsd3_pathconfres {
+ };
+
+ struct nfsd3_commitres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ };
+
+ struct nfsd3_getaclres {
+- __u32 status;
++ __be32 status;
+ struct svc_fh fh;
+ int mask;
+ struct posix_acl *acl_access;
+@@ -268,70 +266,70 @@ union nfsd3_xdrstore {
+
+ #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
+
+-int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
+-int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
++int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_sattrargs *);
+-int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_diropargs *);
+-int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_accessargs *);
+-int nfs3svc_decode_readargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_readargs *);
+-int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_writeargs *);
+-int nfs3svc_decode_createargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_createargs *);
+-int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_createargs *);
+-int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_mknodargs *);
+-int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_renameargs *);
+-int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_readlinkargs *);
+-int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_linkargs *);
+-int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_symlinkargs *);
+-int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_readdirargs *);
+-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_readdirargs *);
+-int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *,
++int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *,
+ struct nfsd3_commitargs *);
+-int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *);
+-int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *,
++int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
++int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *,
+ struct nfsd3_attrstat *);
+-int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *,
++int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *,
+ struct nfsd3_attrstat *);
+-int nfs3svc_encode_diropres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *,
+ struct nfsd3_diropres *);
+-int nfs3svc_encode_accessres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *,
+ struct nfsd3_accessres *);
+-int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *,
+ struct nfsd3_readlinkres *);
+-int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *);
+-int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *);
+-int nfs3svc_encode_createres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *);
++int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *);
++int nfs3svc_encode_createres(struct svc_rqst *, __be32 *,
+ struct nfsd3_diropres *);
+-int nfs3svc_encode_renameres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *,
+ struct nfsd3_renameres *);
+-int nfs3svc_encode_linkres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *,
+ struct nfsd3_linkres *);
+-int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *,
+ struct nfsd3_readdirres *);
+-int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *,
+ struct nfsd3_fsstatres *);
+-int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *,
++int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *,
+ struct nfsd3_fsinfores *);
+-int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *,
+ struct nfsd3_pathconfres *);
+-int nfs3svc_encode_commitres(struct svc_rqst *, u32 *,
++int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *,
+ struct nfsd3_commitres *);
+
+-int nfs3svc_release_fhandle(struct svc_rqst *, u32 *,
++int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *,
+ struct nfsd3_attrstat *);
+-int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
++int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *,
+ struct nfsd3_fhandle_pair *);
+ int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
+ int namlen, loff_t offset, ino_t ino,
+@@ -340,9 +338,9 @@ int nfs3svc_encode_entry_plus(struct rea
+ int namlen, loff_t offset, ino_t ino,
+ unsigned int);
+ /* Helper functions for NFSv3 ACL code */
+-u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p,
++__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
+ struct svc_fh *fhp);
+-u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp);
++__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp);
+
+
+ #endif /* _LINUX_NFSD_XDR3_H */
+diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
+index 77adba7..45ca01b 100644
+--- a/include/linux/nfsd/xdr4.h
++++ b/include/linux/nfsd/xdr4.h
+@@ -241,7 +241,6 @@ struct nfsd4_read {
+ stateid_t rd_stateid; /* request */
+ u64 rd_offset; /* request */
+ u32 rd_length; /* request */
+- struct kvec rd_iov[RPCSVC_MAXPAGES];
+ int rd_vlen;
+ struct file *rd_filp;
+
+@@ -259,9 +258,9 @@ struct nfsd4_readdir {
+ struct svc_fh * rd_fhp; /* response */
+
+ struct readdir_cd common;
+- u32 * buffer;
++ __be32 * buffer;
+ int buflen;
+- u32 * offset;
++ __be32 * offset;
+ };
+
+ struct nfsd4_release_lockowner {
+@@ -326,7 +325,6 @@ struct nfsd4_write {
+ u64 wr_offset; /* request */
+ u32 wr_stable_how; /* request */
+ u32 wr_buflen; /* request */
+- struct kvec wr_vec[RPCSVC_MAXPAGES]; /* request */
+ int wr_vlen;
+
+ u32 wr_bytes_written; /* response */
+@@ -336,7 +334,7 @@ struct nfsd4_write {
+
+ struct nfsd4_op {
+ int opnum;
+- int status;
++ __be32 status;
+ union {
+ struct nfsd4_access access;
+ struct nfsd4_close close;
+@@ -373,12 +371,12 @@ struct nfsd4_op {
+
+ struct nfsd4_compoundargs {
+ /* scratch variables for XDR decode */
+- u32 * p;
+- u32 * end;
++ __be32 * p;
++ __be32 * end;
+ struct page ** pagelist;
+ int pagelen;
+- u32 tmp[8];
+- u32 * tmpp;
++ __be32 tmp[8];
++ __be32 * tmpp;
+ struct tmpbuf {
+ struct tmpbuf *next;
+ void (*release)(const void *);
+@@ -397,15 +395,15 @@ struct nfsd4_compoundargs {
+
+ struct nfsd4_compoundres {
+ /* scratch variables for XDR encode */
+- u32 * p;
+- u32 * end;
++ __be32 * p;
++ __be32 * end;
+ struct xdr_buf * xbuf;
+ struct svc_rqst * rqstp;
+
+ u32 taglen;
+ char * tag;
+ u32 opcnt;
+- u32 * tagp; /* where to encode tag and opcount */
++ __be32 * tagp; /* where to encode tag and opcount */
+ };
+
+ #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
+@@ -421,45 +419,45 @@ set_change_info(struct nfsd4_change_info
+ cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec;
+ }
+
+-int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *);
+-int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *,
++int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
++int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
+ struct nfsd4_compoundargs *);
+-int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *,
++int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
+ struct nfsd4_compoundres *);
+ void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
+ void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
+-int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+- struct dentry *dentry, u32 *buffer, int *countp,
++__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
++ struct dentry *dentry, __be32 *buffer, int *countp,
+ u32 *bmval, struct svc_rqst *);
+-extern int nfsd4_setclientid(struct svc_rqst *rqstp,
++extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
+ struct nfsd4_setclientid *setclid);
+-extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
++extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ struct nfsd4_setclientid_confirm *setclientid_confirm);
+-extern int nfsd4_process_open1(struct nfsd4_open *open);
+-extern int nfsd4_process_open2(struct svc_rqst *rqstp,
++extern __be32 nfsd4_process_open1(struct nfsd4_open *open);
++extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
+ struct svc_fh *current_fh, struct nfsd4_open *open);
+-extern int nfsd4_open_confirm(struct svc_rqst *rqstp,
++extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
+ struct svc_fh *current_fh, struct nfsd4_open_confirm *oc,
+ struct nfs4_stateowner **);
+-extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
++extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct nfsd4_close *close,
+ struct nfs4_stateowner **replay_owner);
+-extern int nfsd4_open_downgrade(struct svc_rqst *rqstp,
++extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp,
+ struct svc_fh *current_fh, struct nfsd4_open_downgrade *od,
+ struct nfs4_stateowner **replay_owner);
+-extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh,
++extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct nfsd4_lock *lock,
+ struct nfs4_stateowner **replay_owner);
+-extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh,
++extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct nfsd4_lockt *lockt);
+-extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
++extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct nfsd4_locku *locku,
+ struct nfs4_stateowner **replay_owner);
+-extern int
++extern __be32
+ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ struct nfsd4_release_lockowner *rlockowner);
+ extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
+-extern int nfsd4_delegreturn(struct svc_rqst *rqstp,
++extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
+ struct svc_fh *current_fh, struct nfsd4_delegreturn *dr);
+ #endif
+
+diff --git a/include/linux/nmi.h b/include/linux/nmi.h
+index c8f4d2f..e16904e 100644
+--- a/include/linux/nmi.h
++++ b/include/linux/nmi.h
+@@ -4,6 +4,7 @@
+ #ifndef LINUX_NMI_H
+ #define LINUX_NMI_H
+
++#include <linux/sched.h>
+ #include <asm/irq.h>
+
+ /**
+@@ -16,7 +17,7 @@
+ #ifdef ARCH_HAS_NMI_WATCHDOG
+ extern void touch_nmi_watchdog(void);
+ #else
+-# define touch_nmi_watchdog() do { } while(0)
++# define touch_nmi_watchdog() touch_softlockup_watchdog()
+ #endif
+
+ #endif
+diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
+index 1a9ef3e..b1063e9 100644
+--- a/include/linux/nodemask.h
++++ b/include/linux/nodemask.h
+@@ -8,8 +8,8 @@
+ * See detailed comments in the file linux/bitmap.h describing the
+ * data type on which these nodemasks are based.
+ *
+- * For details of nodemask_scnprintf() and nodemask_parse(),
+- * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
++ * For details of nodemask_scnprintf() and nodemask_parse_user(),
++ * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
+ * For details of nodelist_scnprintf() and nodelist_parse(), see
+ * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
+ * For details of node_remap(), see bitmap_bitremap in lib/bitmap.c.
+@@ -51,7 +51,7 @@
+ * unsigned long *nodes_addr(mask) Array of unsigned long's in mask
+ *
+ * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
+- * int nodemask_parse(ubuf, ulen, mask) Parse ascii string as nodemask
++ * int nodemask_parse_user(ubuf, ulen, mask) Parse ascii string as nodemask
+ * int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
+ * int nodelist_parse(buf, map) Parse ascii string as nodelist
+ * int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
+@@ -288,12 +288,12 @@ static inline int __nodemask_scnprintf(c
+ return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+ }
+
+-#define nodemask_parse(ubuf, ulen, dst) \
+- __nodemask_parse((ubuf), (ulen), &(dst), MAX_NUMNODES)
+-static inline int __nodemask_parse(const char __user *buf, int len,
++#define nodemask_parse_user(ubuf, ulen, dst) \
++ __nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES)
++static inline int __nodemask_parse_user(const char __user *buf, int len,
+ nodemask_t *dstp, int nbits)
+ {
+- return bitmap_parse(buf, len, dstp->bits, nbits);
++ return bitmap_parse_user(buf, len, dstp->bits, nbits);
+ }
+
+ #define nodelist_scnprintf(buf, len, src) \
+@@ -352,6 +352,7 @@ extern nodemask_t node_possible_map;
+ #define node_possible(node) node_isset((node), node_possible_map)
+ #define first_online_node first_node(node_online_map)
+ #define next_online_node(nid) next_node((nid), node_online_map)
++int highest_possible_node_id(void);
+ #else
+ #define num_online_nodes() 1
+ #define num_possible_nodes() 1
+@@ -359,6 +360,7 @@ extern nodemask_t node_possible_map;
+ #define node_possible(node) ((node) == 0)
+ #define first_online_node 0
+ #define next_online_node(nid) (MAX_NUMNODES)
++#define highest_possible_node_id() 0
+ #endif
+
+ #define any_online_node(mask) \
+diff --git a/include/linux/notifier.h b/include/linux/notifier.h
+index 7ff386a..10a43ed 100644
+--- a/include/linux/notifier.h
++++ b/include/linux/notifier.h
+@@ -12,9 +12,10 @@
+ #include <linux/errno.h>
+ #include <linux/mutex.h>
+ #include <linux/rwsem.h>
++#include <linux/srcu.h>
+
+ /*
+- * Notifier chains are of three types:
++ * Notifier chains are of four types:
+ *
+ * Atomic notifier chains: Chain callbacks run in interrupt/atomic
+ * context. Callouts are not allowed to block.
+@@ -23,13 +24,27 @@
+ * Raw notifier chains: There are no restrictions on callbacks,
+ * registration, or unregistration. All locking and protection
+ * must be provided by the caller.
++ * SRCU notifier chains: A variant of blocking notifier chains, with
++ * the same restrictions.
+ *
+ * atomic_notifier_chain_register() may be called from an atomic context,
+- * but blocking_notifier_chain_register() must be called from a process
+- * context. Ditto for the corresponding _unregister() routines.
++ * but blocking_notifier_chain_register() and srcu_notifier_chain_register()
++ * must be called from a process context. Ditto for the corresponding
++ * _unregister() routines.
+ *
+- * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister()
+- * _must not_ be called from within the call chain.
++ * atomic_notifier_chain_unregister(), blocking_notifier_chain_unregister(),
++ * and srcu_notifier_chain_unregister() _must not_ be called from within
++ * the call chain.
++ *
++ * SRCU notifier chains are an alternative form of blocking notifier chains.
++ * They use SRCU (Sleepable Read-Copy Update) instead of rw-semaphores for
++ * protection of the chain links. This means there is _very_ low overhead
++ * in srcu_notifier_call_chain(): no cache bounces and no memory barriers.
++ * As compensation, srcu_notifier_chain_unregister() is rather expensive.
++ * SRCU notifier chains should be used when the chain will be called very
++ * often but notifier_blocks will seldom be removed. Also, SRCU notifier
++ * chains are slightly more difficult to use because they require special
++ * runtime initialization.
+ */
+
+ struct notifier_block {
+@@ -52,6 +67,12 @@ struct raw_notifier_head {
+ struct notifier_block *head;
+ };
+
++struct srcu_notifier_head {
++ struct mutex mutex;
++ struct srcu_struct srcu;
++ struct notifier_block *head;
++};
++
+ #define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \
+ spin_lock_init(&(name)->lock); \
+ (name)->head = NULL; \
+@@ -64,6 +85,11 @@ struct raw_notifier_head {
+ (name)->head = NULL; \
+ } while (0)
+
++/* srcu_notifier_heads must be initialized and cleaned up dynamically */
++extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
++#define srcu_cleanup_notifier_head(name) \
++ cleanup_srcu_struct(&(name)->srcu);
++
+ #define ATOMIC_NOTIFIER_INIT(name) { \
+ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \
+ .head = NULL }
+@@ -72,6 +98,7 @@ struct raw_notifier_head {
+ .head = NULL }
+ #define RAW_NOTIFIER_INIT(name) { \
+ .head = NULL }
++/* srcu_notifier_heads cannot be initialized statically */
+
+ #define ATOMIC_NOTIFIER_HEAD(name) \
+ struct atomic_notifier_head name = \
+@@ -91,6 +118,8 @@ extern int blocking_notifier_chain_regis
+ struct notifier_block *);
+ extern int raw_notifier_chain_register(struct raw_notifier_head *,
+ struct notifier_block *);
++extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
++ struct notifier_block *);
+
+ extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
+ struct notifier_block *);
+@@ -98,6 +127,8 @@ extern int blocking_notifier_chain_unreg
+ struct notifier_block *);
+ extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
+ struct notifier_block *);
++extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
++ struct notifier_block *);
+
+ extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
+ unsigned long val, void *v);
+@@ -105,6 +136,8 @@ extern int blocking_notifier_call_chain(
+ unsigned long val, void *v);
+ extern int raw_notifier_call_chain(struct raw_notifier_head *,
+ unsigned long val, void *v);
++extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
++ unsigned long val, void *v);
+
+ #define NOTIFY_DONE 0x0000 /* Don't care */
+ #define NOTIFY_OK 0x0001 /* Suits me */
+diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
+new file mode 100644
+index 0000000..f6baecd
+--- /dev/null
++++ b/include/linux/nsproxy.h
+@@ -0,0 +1,52 @@
++#ifndef _LINUX_NSPROXY_H
++#define _LINUX_NSPROXY_H
++
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++
++struct namespace;
++struct uts_namespace;
++struct ipc_namespace;
++
++/*
++ * A structure to contain pointers to all per-process
++ * namespaces - fs (mount), uts, network, sysvipc, etc.
++ *
++ * 'count' is the number of tasks holding a reference.
++ * The count for each namespace, then, will be the number
++ * of nsproxies pointing to it, not the number of tasks.
++ *
++ * The nsproxy is shared by tasks which share all namespaces.
++ * As soon as a single namespace is cloned or unshared, the
++ * nsproxy is copied.
++ */
++struct nsproxy {
++ atomic_t count;
++ spinlock_t nslock;
++ struct uts_namespace *uts_ns;
++ struct ipc_namespace *ipc_ns;
++ struct namespace *namespace;
++};
++extern struct nsproxy init_nsproxy;
++
++struct nsproxy *dup_namespaces(struct nsproxy *orig);
++int copy_namespaces(int flags, struct task_struct *tsk);
++void get_task_namespaces(struct task_struct *tsk);
++void free_nsproxy(struct nsproxy *ns);
++
++static inline void put_nsproxy(struct nsproxy *ns)
++{
++ if (atomic_dec_and_test(&ns->count)) {
++ free_nsproxy(ns);
++ }
++}
++
++static inline void exit_task_namespaces(struct task_struct *p)
++{
++ struct nsproxy *ns = p->nsproxy;
++ if (ns) {
++ put_nsproxy(ns);
++ p->nsproxy = NULL;
++ }
++}
++#endif
+diff --git a/include/linux/oom.h b/include/linux/oom.h
+new file mode 100644
+index 0000000..ad76463
+--- /dev/null
++++ b/include/linux/oom.h
+@@ -0,0 +1,10 @@
++#ifndef __INCLUDE_LINUX_OOM_H
++#define __INCLUDE_LINUX_OOM_H
++
++/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
++#define OOM_DISABLE (-17)
++/* inclusive */
++#define OOM_ADJUST_MIN (-16)
++#define OOM_ADJUST_MAX 15
++
++#endif
+diff --git a/include/linux/openprom_fs.h b/include/linux/openprom_fs.h
+deleted file mode 100644
+index a837aab..0000000
+--- a/include/linux/openprom_fs.h
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#ifndef _LINUX_OPENPROM_FS_H
+-#define _LINUX_OPENPROM_FS_H
+-
+-/*
+- * The openprom filesystem constants/structures
+- */
+-
+-#define OPENPROM_SUPER_MAGIC 0x9fa1
+-
+-#endif /* _LINUX_OPENPROM_FS_H */
+diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
+index 5748642..4830a3b 100644
+--- a/include/linux/page-flags.h
++++ b/include/linux/page-flags.h
+@@ -13,24 +13,25 @@
+ * PG_reserved is set for special pages, which can never be swapped out. Some
+ * of them might not even exist (eg empty_bad_page)...
+ *
+- * The PG_private bitflag is set if page->private contains a valid value.
++ * The PG_private bitflag is set on pagecache pages if they contain filesystem
++ * specific data (which is normally at page->private). It can be used by
++ * private allocations for its own usage.
+ *
+- * During disk I/O, PG_locked is used. This bit is set before I/O and
+- * reset when I/O completes. page_waitqueue(page) is a wait queue of all tasks
+- * waiting for the I/O on this page to complete.
++ * During initiation of disk I/O, PG_locked is set. This bit is set before I/O
++ * and cleared when writeback _starts_ or when read _completes_. PG_writeback
++ * is set before writeback starts and cleared when it finishes.
++ *
++ * PG_locked also pins a page in pagecache, and blocks truncation of the file
++ * while it is held.
++ *
++ * page_waitqueue(page) is a wait queue of all tasks waiting for the page
++ * to become unlocked.
+ *
+ * PG_uptodate tells whether the page's contents is valid. When a read
+ * completes, the page becomes uptodate, unless a disk I/O error happened.
+ *
+- * For choosing which pages to swap out, inode pages carry a PG_referenced bit,
+- * which is set any time the system accesses that page through the (mapping,
+- * index) hash table. This referenced bit, together with the referenced bit
+- * in the page tables, is used to manipulate page->age and move the page across
+- * the active, inactive_dirty and inactive_clean lists.
+- *
+- * Note that the referenced bit, the page->lru list_head and the active,
+- * inactive_dirty and inactive_clean lists are protected by the
+- * zone->lru_lock, and *NOT* by the usual PG_locked bit!
++ * PG_referenced, PG_reclaim are used for page reclaim for anonymous and
++ * file-backed pagecache (see mm/vmscan.c).
+ *
+ * PG_error is set to indicate that an I/O error occurred on this page.
+ *
+@@ -42,6 +43,10 @@
+ * space, they need to be kmapped separately for doing IO on the pages. The
+ * struct page (these bits with information) are always mapped into kernel
+ * address space...
++ *
++ * PG_buddy is set to indicate that the page is free and in the buddy system
++ * (see mm/page_alloc.c).
++ *
+ */
+
+ /*
+@@ -74,7 +79,7 @@
+ #define PG_checked 8 /* kill me in 2.5.<early>. */
+ #define PG_arch_1 9
+ #define PG_reserved 10
+-#define PG_private 11 /* Has something at ->private */
++#define PG_private 11 /* If pagecache, has fs-private data */
+
+ #define PG_writeback 12 /* Page is under writeback */
+ #define PG_nosave 13 /* Used for system suspend/resume */
+@@ -83,7 +88,7 @@
+
+ #define PG_mappedtodisk 16 /* Has blocks allocated on-disk */
+ #define PG_reclaim 17 /* To be reclaimed asap */
+-#define PG_nosave_free 18 /* Free, should not be written */
++#define PG_nosave_free 18 /* Used for system suspend/resume */
+ #define PG_buddy 19 /* Page is free, on buddy lists */
+
+
+@@ -123,12 +128,11 @@
+
+ #define PageUptodate(page) test_bit(PG_uptodate, &(page)->flags)
+ #ifdef CONFIG_S390
+-#define SetPageUptodate(_page) \
+- do { \
+- struct page *__page = (_page); \
+- if (!test_and_set_bit(PG_uptodate, &__page->flags)) \
+- page_test_and_clear_dirty(_page); \
+- } while (0)
++static inline void SetPageUptodate(struct page *page)
++{
++ if (!test_and_set_bit(PG_uptodate, &page->flags))
++ page_test_and_clear_dirty(page);
++}
+ #else
+ #define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags)
+ #endif
+diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
+index 0a2f5d2..c3e255b 100644
+--- a/include/linux/pagemap.h
++++ b/include/linux/pagemap.h
+@@ -52,19 +52,23 @@ static inline void mapping_set_gfp_mask(
+ void release_pages(struct page **pages, int nr, int cold);
+
+ #ifdef CONFIG_NUMA
+-extern struct page *page_cache_alloc(struct address_space *x);
+-extern struct page *page_cache_alloc_cold(struct address_space *x);
++extern struct page *__page_cache_alloc(gfp_t gfp);
+ #else
++static inline struct page *__page_cache_alloc(gfp_t gfp)
++{
++ return alloc_pages(gfp, 0);
++}
++#endif
++
+ static inline struct page *page_cache_alloc(struct address_space *x)
+ {
+- return alloc_pages(mapping_gfp_mask(x), 0);
++ return __page_cache_alloc(mapping_gfp_mask(x));
+ }
+
+ static inline struct page *page_cache_alloc_cold(struct address_space *x)
+ {
+- return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
++ return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD);
+ }
+-#endif
+
+ typedef int filler_t(void *, struct page *);
+
+@@ -130,14 +134,29 @@ static inline pgoff_t linear_page_index(
+ }
+
+ extern void FASTCALL(__lock_page(struct page *page));
++extern void FASTCALL(__lock_page_nosync(struct page *page));
+ extern void FASTCALL(unlock_page(struct page *page));
+
++/*
++ * lock_page may only be called if we have the page's inode pinned.
++ */
+ static inline void lock_page(struct page *page)
+ {
+ might_sleep();
+ if (TestSetPageLocked(page))
+ __lock_page(page);
+ }
++
++/*
++ * lock_page_nosync should only be used if we can't pin the page's inode.
++ * Doesn't play quite so well with block device plugging.
++ */
++static inline void lock_page_nosync(struct page *page)
++{
++ might_sleep();
++ if (TestSetPageLocked(page))
++ __lock_page_nosync(page);
++}
+
+ /*
+ * This is exported only for wait_on_page_locked/wait_on_page_writeback.
+diff --git a/include/linux/parport.h b/include/linux/parport.h
+index 5bf321e..80682aa 100644
+--- a/include/linux/parport.h
++++ b/include/linux/parport.h
+@@ -229,7 +229,7 @@ struct pardevice {
+ int (*preempt)(void *);
+ void (*wakeup)(void *);
+ void *private;
+- void (*irq_func)(int, void *, struct pt_regs *);
++ void (*irq_func)(int, void *);
+ unsigned int flags;
+ struct pardevice *next;
+ struct pardevice *prev;
+@@ -375,7 +375,7 @@ extern void parport_put_port (struct par
+ struct pardevice *parport_register_device(struct parport *port,
+ const char *name,
+ int (*pf)(void *), void (*kf)(void *),
+- void (*irq_func)(int, void *, struct pt_regs *),
++ void (*irq_func)(int, void *),
+ int flags, void *handle);
+
+ /* parport_unregister unlinks a device from the chain. */
+@@ -457,7 +457,7 @@ static __inline__ int parport_yield_bloc
+ #define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */
+
+ /* IEEE1284 functions */
+-extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
++extern void parport_ieee1284_interrupt (int, void *);
+ extern int parport_negotiate (struct parport *, int mode);
+ extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
+ extern ssize_t parport_read (struct parport *, void *buf, size_t len);
+@@ -502,8 +502,7 @@ extern void parport_daisy_fini (struct p
+ extern struct pardevice *parport_open (int devnum, const char *name,
+ int (*pf) (void *),
+ void (*kf) (void *),
+- void (*irqf) (int, void *,
+- struct pt_regs *),
++ void (*irqf) (int, void *),
+ int flags, void *handle);
+ extern void parport_close (struct pardevice *dev);
+ extern ssize_t parport_device_id (int devnum, char *buffer, size_t len);
+@@ -512,13 +511,12 @@ extern void parport_daisy_deselect_all (
+ extern int parport_daisy_select (struct parport *port, int daisy, int mode);
+
+ /* Lowlevel drivers _can_ call this support function to handle irqs. */
+-static __inline__ void parport_generic_irq(int irq, struct parport *port,
+- struct pt_regs *regs)
++static __inline__ void parport_generic_irq(int irq, struct parport *port)
+ {
+- parport_ieee1284_interrupt (irq, port, regs);
++ parport_ieee1284_interrupt (irq, port);
+ read_lock(&port->cad_lock);
+ if (port->cad && port->cad->irq_func)
+- port->cad->irq_func(irq, port->cad->private, regs);
++ port->cad->irq_func(irq, port->cad->private);
+ read_unlock(&port->cad_lock);
+ }
+
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 8565b81..09be0f8 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -49,6 +49,7 @@
+ #include <linux/types.h>
+ #include <linux/ioport.h>
+ #include <linux/list.h>
++#include <linux/compiler.h>
+ #include <linux/errno.h>
+ #include <linux/device.h>
+
+@@ -346,6 +347,8 @@ struct pci_driver {
+ int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
+ void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
+ int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
++ int (*suspend_late) (struct pci_dev *dev, pm_message_t state);
++ int (*resume_early) (struct pci_dev *dev);
+ int (*resume) (struct pci_dev *dev); /* Device woken up */
+ int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable); /* Enable wake event */
+ void (*shutdown) (struct pci_dev *dev);
+@@ -353,6 +356,8 @@ struct pci_driver {
+ struct pci_error_handlers *err_handler;
+ struct device_driver driver;
+ struct pci_dynids dynids;
++
++ int multithread_probe;
+ };
+
+ #define to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
+@@ -401,7 +406,7 @@ extern struct list_head pci_root_buses;
+ extern struct list_head pci_devices; /* list of all devices */
+
+ void pcibios_fixup_bus(struct pci_bus *);
+-int pcibios_enable_device(struct pci_dev *, int mask);
++int __must_check pcibios_enable_device(struct pci_dev *, int mask);
+ char *pcibios_setup (char *str);
+
+ /* Used only when drivers/pci/setup.c is used */
+@@ -428,7 +433,7 @@ int pci_scan_slot(struct pci_bus *bus, i
+ struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
+ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
+ unsigned int pci_scan_child_bus(struct pci_bus *bus);
+-void pci_bus_add_device(struct pci_dev *dev);
++int __must_check pci_bus_add_device(struct pci_dev *dev);
+ void pci_read_bridge_bases(struct pci_bus *child);
+ struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res);
+ int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
+@@ -436,7 +441,9 @@ extern struct pci_dev *pci_dev_get(struc
+ extern void pci_dev_put(struct pci_dev *dev);
+ extern void pci_remove_bus(struct pci_bus *b);
+ extern void pci_remove_bus_device(struct pci_dev *dev);
++extern void pci_stop_bus_device(struct pci_dev *dev);
+ void pci_setup_cardbus(struct pci_bus *bus);
++extern void pci_sort_breadthfirst(void);
+
+ /* Generic PCI functions exported to card drivers */
+
+@@ -446,13 +453,18 @@ struct pci_dev *pci_find_slot (unsigned
+ int pci_find_capability (struct pci_dev *dev, int cap);
+ int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
+ int pci_find_ext_capability (struct pci_dev *dev, int cap);
+-struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
++struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
++
++struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
++ struct pci_dev *from);
++struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device,
++ struct pci_dev *from);
+
+-struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
+ struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
+ unsigned int ss_vendor, unsigned int ss_device,
+ struct pci_dev *from);
+ struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn);
++struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn);
+ struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from);
+ int pci_dev_present(const struct pci_device_id *ids);
+
+@@ -488,19 +500,19 @@ static inline int pci_write_config_dword
+ return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val);
+ }
+
+-int pci_enable_device(struct pci_dev *dev);
+-int pci_enable_device_bars(struct pci_dev *dev, int mask);
++int __must_check pci_enable_device(struct pci_dev *dev);
++int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask);
+ void pci_disable_device(struct pci_dev *dev);
+ void pci_set_master(struct pci_dev *dev);
+ #define HAVE_PCI_SET_MWI
+-int pci_set_mwi(struct pci_dev *dev);
++int __must_check pci_set_mwi(struct pci_dev *dev);
+ void pci_clear_mwi(struct pci_dev *dev);
+ void pci_intx(struct pci_dev *dev, int enable);
+ int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
+ int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
+ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
+-int pci_assign_resource(struct pci_dev *dev, int i);
+-int pci_assign_resource_fixed(struct pci_dev *dev, int i);
++int __must_check pci_assign_resource(struct pci_dev *dev, int i);
++int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
+ void pci_restore_bars(struct pci_dev *dev);
+
+ /* ROM control related routines */
+@@ -526,23 +538,24 @@ void pdev_sort_resources(struct pci_dev
+ void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
+ int (*)(struct pci_dev *, u8, u8));
+ #define HAVE_PCI_REQ_REGIONS 2
+-int pci_request_regions(struct pci_dev *, const char *);
++int __must_check pci_request_regions(struct pci_dev *, const char *);
+ void pci_release_regions(struct pci_dev *);
+-int pci_request_region(struct pci_dev *, int, const char *);
++int __must_check pci_request_region(struct pci_dev *, int, const char *);
+ void pci_release_region(struct pci_dev *, int);
+
+ /* drivers/pci/bus.c */
+-int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+- resource_size_t size, resource_size_t align,
+- resource_size_t min, unsigned int type_mask,
+- void (*alignf)(void *, struct resource *,
+- resource_size_t, resource_size_t),
+- void *alignf_data);
++int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
++ struct resource *res, resource_size_t size,
++ resource_size_t align, resource_size_t min,
++ unsigned int type_mask,
++ void (*alignf)(void *, struct resource *,
++ resource_size_t, resource_size_t),
++ void *alignf_data);
+ void pci_enable_bridges(struct pci_bus *bus);
+
+ /* Proper probing supporting hot-pluggable devices */
+-int __pci_register_driver(struct pci_driver *, struct module *);
+-static inline int pci_register_driver(struct pci_driver *driver)
++int __must_check __pci_register_driver(struct pci_driver *, struct module *);
++static inline int __must_check pci_register_driver(struct pci_driver *driver)
+ {
+ return __pci_register_driver(driver, THIS_MODULE);
+ }
+@@ -588,6 +601,7 @@ struct msix_entry {
+ u16 entry; /* driver uses to specify entry, OS writes */
+ };
+
++
+ #ifndef CONFIG_PCI_MSI
+ static inline void pci_scan_msi_device(struct pci_dev *dev) {}
+ static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
+@@ -606,6 +620,12 @@ extern void pci_disable_msix(struct pci_
+ extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+ #endif
+
++#ifdef CONFIG_HT_IRQ
++/* The functions a driver should call */
++int ht_create_irq(struct pci_dev *dev, int idx);
++void ht_destroy_irq(unsigned int irq);
++#endif /* CONFIG_HT_IRQ */
++
+ extern void pci_block_user_cfg_access(struct pci_dev *dev);
+ extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
+
+@@ -644,7 +664,12 @@ static inline struct pci_dev *pci_find_d
+ static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
+ { return NULL; }
+
+-static inline struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from)
++static inline struct pci_dev *pci_get_device(unsigned int vendor,
++ unsigned int device, struct pci_dev *from)
++{ return NULL; }
++
++static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor,
++ unsigned int device, struct pci_dev *from)
+ { return NULL; }
+
+ static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
+@@ -780,12 +805,13 @@ enum pci_fixup_pass {
+ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
+
+ extern int pci_pci_problems;
+-#define PCIPCI_FAIL 1
++#define PCIPCI_FAIL 1 /* No PCI PCI DMA */
+ #define PCIPCI_TRITON 2
+ #define PCIPCI_NATOMA 4
+ #define PCIPCI_VIAETBF 8
+ #define PCIPCI_VSFX 16
+-#define PCIPCI_ALIMAGIK 32
++#define PCIPCI_ALIMAGIK 32 /* Need low latency setting */
++#define PCIAGP_FAIL 64 /* No PCI to AGP DMA */
+
+ #endif /* __KERNEL__ */
+ #endif /* LINUX_PCI_H */
+diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
+new file mode 100644
+index 0000000..a675a05
+--- /dev/null
++++ b/include/linux/pci_hotplug.h
+@@ -0,0 +1,236 @@
++/*
++ * PCI HotPlug Core Functions
++ *
++ * Copyright (C) 1995,2001 Compaq Computer Corporation
++ * Copyright (C) 2001 Greg Kroah-Hartman (greg at kroah.com)
++ * Copyright (C) 2001 IBM Corp.
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
++ * NON INFRINGEMENT. See the GNU General Public License for more
++ * details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Send feedback to <kristen.c.accardi at intel.com>
++ *
++ */
++#ifndef _PCI_HOTPLUG_H
++#define _PCI_HOTPLUG_H
++
++
++/* These values come from the PCI Hotplug Spec */
++enum pci_bus_speed {
++ PCI_SPEED_33MHz = 0x00,
++ PCI_SPEED_66MHz = 0x01,
++ PCI_SPEED_66MHz_PCIX = 0x02,
++ PCI_SPEED_100MHz_PCIX = 0x03,
++ PCI_SPEED_133MHz_PCIX = 0x04,
++ PCI_SPEED_66MHz_PCIX_ECC = 0x05,
++ PCI_SPEED_100MHz_PCIX_ECC = 0x06,
++ PCI_SPEED_133MHz_PCIX_ECC = 0x07,
++ PCI_SPEED_66MHz_PCIX_266 = 0x09,
++ PCI_SPEED_100MHz_PCIX_266 = 0x0a,
++ PCI_SPEED_133MHz_PCIX_266 = 0x0b,
++ PCI_SPEED_66MHz_PCIX_533 = 0x11,
++ PCI_SPEED_100MHz_PCIX_533 = 0x12,
++ PCI_SPEED_133MHz_PCIX_533 = 0x13,
++ PCI_SPEED_UNKNOWN = 0xff,
++};
++
++/* These values come from the PCI Express Spec */
++enum pcie_link_width {
++ PCIE_LNK_WIDTH_RESRV = 0x00,
++ PCIE_LNK_X1 = 0x01,
++ PCIE_LNK_X2 = 0x02,
++ PCIE_LNK_X4 = 0x04,
++ PCIE_LNK_X8 = 0x08,
++ PCIE_LNK_X12 = 0x0C,
++ PCIE_LNK_X16 = 0x10,
++ PCIE_LNK_X32 = 0x20,
++ PCIE_LNK_WIDTH_UNKNOWN = 0xFF,
++};
++
++enum pcie_link_speed {
++ PCIE_2PT5GB = 0x14,
++ PCIE_LNK_SPEED_UNKNOWN = 0xFF,
++};
++
++struct hotplug_slot;
++struct hotplug_slot_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct hotplug_slot *, char *);
++ ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
++};
++#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr);
++
++/**
++ * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
++ * @owner: The module owner of this structure
++ * @enable_slot: Called when the user wants to enable a specific pci slot
++ * @disable_slot: Called when the user wants to disable a specific pci slot
++ * @set_attention_status: Called to set the specific slot's attention LED to
++ * the specified value
++ * @hardware_test: Called to run a specified hardware test on the specified
++ * slot.
++ * @get_power_status: Called to get the current power status of a slot.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ * @get_attention_status: Called to get the current attention status of a slot.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ * @get_latch_status: Called to get the current latch status of a slot.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ * @get_address: Called to get pci address of a slot.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ * @get_max_bus_speed: Called to get the max bus speed for a slot.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ * @get_cur_bus_speed: Called to get the current bus speed for a slot.
++ * If this field is NULL, the value passed in the struct hotplug_slot_info
++ * will be used when this value is requested by a user.
++ *
++ * The table of function pointers that is passed to the hotplug pci core by a
++ * hotplug pci driver. These functions are called by the hotplug pci core when
++ * the user wants to do something to a specific slot (query it for information,
++ * set an LED, enable / disable power, etc.)
++ */
++struct hotplug_slot_ops {
++ struct module *owner;
++ int (*enable_slot) (struct hotplug_slot *slot);
++ int (*disable_slot) (struct hotplug_slot *slot);
++ int (*set_attention_status) (struct hotplug_slot *slot, u8 value);
++ int (*hardware_test) (struct hotplug_slot *slot, u32 value);
++ int (*get_power_status) (struct hotplug_slot *slot, u8 *value);
++ int (*get_attention_status) (struct hotplug_slot *slot, u8 *value);
++ int (*get_latch_status) (struct hotplug_slot *slot, u8 *value);
++ int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value);
++ int (*get_address) (struct hotplug_slot *slot, u32 *value);
++ int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value);
++ int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value);
++};
++
++/**
++ * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot
++ * @power: if power is enabled or not (1/0)
++ * @attention_status: if the attention light is enabled or not (1/0)
++ * @latch_status: if the latch (if any) is open or closed (1/0)
++ * @adapter_present: if there is a pci board present in the slot or not (1/0)
++ * @address: (domain << 16 | bus << 8 | dev)
++ *
++ * Used to notify the hotplug pci core of the status of a specific slot.
++ */
++struct hotplug_slot_info {
++ u8 power_status;
++ u8 attention_status;
++ u8 latch_status;
++ u8 adapter_status;
++ u32 address;
++ enum pci_bus_speed max_bus_speed;
++ enum pci_bus_speed cur_bus_speed;
++};
++
++/**
++ * struct hotplug_slot - used to register a physical slot with the hotplug pci core
++ * @name: the name of the slot being registered. This string must
++ * be unique amoung slots registered on this system.
++ * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
++ * @info: pointer to the &struct hotplug_slot_info for the initial values for
++ * this slot.
++ * @release: called during pci_hp_deregister to free memory allocated in a
++ * hotplug_slot structure.
++ * @private: used by the hotplug pci controller driver to store whatever it
++ * needs.
++ */
++struct hotplug_slot {
++ char *name;
++ struct hotplug_slot_ops *ops;
++ struct hotplug_slot_info *info;
++ void (*release) (struct hotplug_slot *slot);
++ void *private;
++
++ /* Variables below this are for use only by the hotplug pci core. */
++ struct list_head slot_list;
++ struct kobject kobj;
++};
++#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)
++
++extern int pci_hp_register (struct hotplug_slot *slot);
++extern int pci_hp_deregister (struct hotplug_slot *slot);
++extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
++ struct hotplug_slot_info *info);
++extern struct subsystem pci_hotplug_slots_subsys;
++
++/* PCI Setting Record (Type 0) */
++struct hpp_type0 {
++ u32 revision;
++ u8 cache_line_size;
++ u8 latency_timer;
++ u8 enable_serr;
++ u8 enable_perr;
++};
++
++/* PCI-X Setting Record (Type 1) */
++struct hpp_type1 {
++ u32 revision;
++ u8 max_mem_read;
++ u8 avg_max_split;
++ u16 tot_max_split;
++};
++
++/* PCI Express Setting Record (Type 2) */
++struct hpp_type2 {
++ u32 revision;
++ u32 unc_err_mask_and;
++ u32 unc_err_mask_or;
++ u32 unc_err_sever_and;
++ u32 unc_err_sever_or;
++ u32 cor_err_mask_and;
++ u32 cor_err_mask_or;
++ u32 adv_err_cap_and;
++ u32 adv_err_cap_or;
++ u16 pci_exp_devctl_and;
++ u16 pci_exp_devctl_or;
++ u16 pci_exp_lnkctl_and;
++ u16 pci_exp_lnkctl_or;
++ u32 sec_unc_err_sever_and;
++ u32 sec_unc_err_sever_or;
++ u32 sec_unc_err_mask_and;
++ u32 sec_unc_err_mask_or;
++};
++
++struct hotplug_params {
++ struct hpp_type0 *t0; /* Type0: NULL if not available */
++ struct hpp_type1 *t1; /* Type1: NULL if not available */
++ struct hpp_type2 *t2; /* Type2: NULL if not available */
++ struct hpp_type0 type0_data;
++ struct hpp_type1 type1_data;
++ struct hpp_type2 type2_data;
++};
++
++#ifdef CONFIG_ACPI
++#include <acpi/acpi.h>
++#include <acpi/acpi_bus.h>
++#include <acpi/actypes.h>
++extern acpi_status acpi_run_oshp(acpi_handle handle);
++extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
++ struct hotplug_params *hpp);
++int acpi_root_bridge(acpi_handle handle);
++#endif
++#endif
++
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index 7a24915..fa4e1d7 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -479,6 +479,7 @@
+
+ #define PCI_VENDOR_ID_AMD 0x1022
+ #define PCI_DEVICE_ID_AMD_K8_NB 0x1100
++#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103
+ #define PCI_DEVICE_ID_AMD_LANCE 0x2000
+ #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
+ #define PCI_DEVICE_ID_AMD_SCSI 0x2020
+@@ -506,6 +507,7 @@
+ #define PCI_DEVICE_ID_AMD_8151_0 0x7454
+ #define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
+ #define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
++#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
+ #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
+ #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
+ #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
+@@ -1211,6 +1213,7 @@
+ #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451
+ #define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452
+ #define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453
++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560
+
+ #define PCI_VENDOR_ID_IMS 0x10e0
+ #define PCI_DEVICE_ID_IMS_TT128 0x9128
+@@ -1411,6 +1414,7 @@
+ #define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009
+ #define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017
+ #define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103
++#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
+ #define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
+@@ -1482,9 +1486,6 @@
+ #define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
+ #define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
+ #define PCI_DEVICE_ID_MARVELL_MV64460 0x6480
+-#define PCI_DEVICE_ID_MARVELL_GT96100 0x9652
+-#define PCI_DEVICE_ID_MARVELL_GT96100A 0x9653
+-
+
+ #define PCI_VENDOR_ID_V3 0x11b0
+ #define PCI_DEVICE_ID_V3_V960 0x0001
+@@ -1615,8 +1616,6 @@
+ #define PCI_VENDOR_ID_ROCKWELL 0x127A
+
+ #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
+@@ -1883,6 +1882,8 @@
+ #define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
+ #define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
+
++#define PCI_VENDOR_ID_SIPACKETS 0x14d9
++#define PCI_DEVICE_ID_SP1011 0x0010
+
+ #define PCI_VENDOR_ID_AFAVLAB 0x14db
+ #define PCI_DEVICE_ID_AFAVLAB_P028 0x2180
+@@ -1905,6 +1906,7 @@
+ #define PCI_DEVICE_ID_TIGON3_5705_2 0x1654
+ #define PCI_DEVICE_ID_TIGON3_5720 0x1658
+ #define PCI_DEVICE_ID_TIGON3_5721 0x1659
++#define PCI_DEVICE_ID_TIGON3_5722 0x165a
+ #define PCI_DEVICE_ID_TIGON3_5705M 0x165d
+ #define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e
+ #define PCI_DEVICE_ID_TIGON3_5714 0x1668
+@@ -1914,6 +1916,7 @@
+ #define PCI_DEVICE_ID_TIGON3_5705F 0x166e
+ #define PCI_DEVICE_ID_TIGON3_5754M 0x1672
+ #define PCI_DEVICE_ID_TIGON3_5755M 0x1673
++#define PCI_DEVICE_ID_TIGON3_5756 0x1674
+ #define PCI_DEVICE_ID_TIGON3_5750 0x1676
+ #define PCI_DEVICE_ID_TIGON3_5751 0x1677
+ #define PCI_DEVICE_ID_TIGON3_5715 0x1678
+@@ -1943,6 +1946,8 @@
+ #define PCI_DEVICE_ID_TIGON3_5901 0x170d
+ #define PCI_DEVICE_ID_BCM4401B1 0x170c
+ #define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
++#define PCI_DEVICE_ID_TIGON3_5906 0x1712
++#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
+ #define PCI_DEVICE_ID_BCM4401 0x4401
+ #define PCI_DEVICE_ID_BCM4401B0 0x4402
+
+@@ -1993,6 +1998,7 @@
+ #define PCI_DEVICE_ID_FARSITE_TE1C 0x1612
+
+ #define PCI_VENDOR_ID_SIBYTE 0x166d
++#define PCI_DEVICE_ID_BCM1250_PCI 0x0001
+ #define PCI_DEVICE_ID_BCM1250_HT 0x0002
+
+ #define PCI_VENDOR_ID_NETCELL 0x169c
+@@ -2010,6 +2016,23 @@
+ #define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
+ #define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb
+
++#define PCI_VENDOR_ID_ARECA 0x17d3
++#define PCI_DEVICE_ID_ARECA_1110 0x1110
++#define PCI_DEVICE_ID_ARECA_1120 0x1120
++#define PCI_DEVICE_ID_ARECA_1130 0x1130
++#define PCI_DEVICE_ID_ARECA_1160 0x1160
++#define PCI_DEVICE_ID_ARECA_1170 0x1170
++#define PCI_DEVICE_ID_ARECA_1210 0x1210
++#define PCI_DEVICE_ID_ARECA_1220 0x1220
++#define PCI_DEVICE_ID_ARECA_1230 0x1230
++#define PCI_DEVICE_ID_ARECA_1260 0x1260
++#define PCI_DEVICE_ID_ARECA_1270 0x1270
++#define PCI_DEVICE_ID_ARECA_1280 0x1280
++#define PCI_DEVICE_ID_ARECA_1380 0x1380
++#define PCI_DEVICE_ID_ARECA_1381 0x1381
++#define PCI_DEVICE_ID_ARECA_1680 0x1680
++#define PCI_DEVICE_ID_ARECA_1681 0x1681
++
+ #define PCI_VENDOR_ID_S2IO 0x17d5
+ #define PCI_DEVICE_ID_S2IO_WIN 0x5731
+ #define PCI_DEVICE_ID_S2IO_UNI 0x5831
+@@ -2329,3 +2352,5 @@
+ #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897
+ #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
+
++#define PCI_VENDOR_ID_QUICKNET 0x15E2
++#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
+diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
+index 96930cb..c312a12 100644
+--- a/include/linux/pci_regs.h
++++ b/include/linux/pci_regs.h
+@@ -12,6 +12,11 @@
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
++ *
++ * For hypertransport information, please consult the following manuals
++ * from http://www.hypertransport.org
++ *
++ * The Hypertransport I/O Link Specification
+ */
+
+ #ifndef LINUX_PCI_REGS_H
+@@ -196,7 +201,7 @@
+ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
+ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
+ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
+-#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */
++#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
+ #define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */
+ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
+ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */
+@@ -463,4 +468,20 @@
+ #define PCI_PWR_CAP 12 /* Capability */
+ #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
+
++/* Hypertransport sub capability types */
++#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
++#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
++#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
++#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
++#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
++#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
++#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */
++#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
++#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */
++#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
++#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
++#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */
++#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */
++
++
+ #endif /* LINUX_PCI_REGS_H */
+diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
+index b44e01a..6cd91e3 100644
+--- a/include/linux/pcieport_if.h
++++ b/include/linux/pcieport_if.h
+@@ -62,6 +62,12 @@ struct pcie_port_service_driver {
+ int (*suspend) (struct pcie_device *dev, pm_message_t state);
+ int (*resume) (struct pcie_device *dev);
+
++ /* Service Error Recovery Handler */
++ struct pci_error_handlers *err_handler;
++
++ /* Link Reset Capability - AER service driver specific */
++ pci_ers_result_t (*reset_link) (struct pci_dev *dev);
++
+ const struct pcie_port_service_id *id_table;
+ struct device_driver driver;
+ };
+diff --git a/include/linux/percpu.h b/include/linux/percpu.h
+index cb9039a..600e3d3 100644
+--- a/include/linux/percpu.h
++++ b/include/linux/percpu.h
+@@ -1,9 +1,12 @@
+ #ifndef __LINUX_PERCPU_H
+ #define __LINUX_PERCPU_H
++
+ #include <linux/spinlock.h> /* For preempt_disable() */
+ #include <linux/slab.h> /* For kmalloc() */
+ #include <linux/smp.h>
+ #include <linux/string.h> /* For memset() */
++#include <linux/cpumask.h>
++
+ #include <asm/percpu.h>
+
+ /* Enough to cover all DEFINE_PER_CPUs in kernel, including modules. */
+@@ -11,8 +14,14 @@
+ #define PERCPU_ENOUGH_ROOM 32768
+ #endif
+
+-/* Must be an lvalue. */
+-#define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); }))
++/*
++ * Must be an lvalue. Since @var must be a simple identifier,
++ * we force a syntax error here if it isn't.
++ */
++#define get_cpu_var(var) (*({ \
++ extern int simple_identifier_##var(void); \
++ preempt_disable(); \
++ &__get_cpu_var(var); }))
+ #define put_cpu_var(var) preempt_enable()
+
+ #ifdef CONFIG_SMP
+@@ -21,39 +30,77 @@ struct percpu_data {
+ void *ptrs[NR_CPUS];
+ };
+
++#define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
+ /*
+- * Use this to get to a cpu's version of the per-cpu object allocated using
+- * alloc_percpu. Non-atomic access to the current CPU's version should
++ * Use this to get to a cpu's version of the per-cpu object dynamically
++ * allocated. Non-atomic access to the current CPU's version should
+ * probably be combined with get_cpu()/put_cpu().
+ */
+-#define per_cpu_ptr(ptr, cpu) \
+-({ \
+- struct percpu_data *__p = (struct percpu_data *)~(unsigned long)(ptr); \
+- (__typeof__(ptr))__p->ptrs[(cpu)]; \
++#define percpu_ptr(ptr, cpu) \
++({ \
++ struct percpu_data *__p = __percpu_disguise(ptr); \
++ (__typeof__(ptr))__p->ptrs[(cpu)]; \
+ })
+
+-extern void *__alloc_percpu(size_t size);
+-extern void free_percpu(const void *);
++extern void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu);
++extern void percpu_depopulate(void *__pdata, int cpu);
++extern int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp,
++ cpumask_t *mask);
++extern void __percpu_depopulate_mask(void *__pdata, cpumask_t *mask);
++extern void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask);
++extern void percpu_free(void *__pdata);
+
+ #else /* CONFIG_SMP */
+
+-#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
++#define percpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
++
++static inline void percpu_depopulate(void *__pdata, int cpu)
++{
++}
++
++static inline void __percpu_depopulate_mask(void *__pdata, cpumask_t *mask)
++{
++}
+
+-static inline void *__alloc_percpu(size_t size)
++static inline void *percpu_populate(void *__pdata, size_t size, gfp_t gfp,
++ int cpu)
+ {
+- void *ret = kmalloc(size, GFP_KERNEL);
+- if (ret)
+- memset(ret, 0, size);
+- return ret;
++ return percpu_ptr(__pdata, cpu);
+ }
+-static inline void free_percpu(const void *ptr)
+-{
+- kfree(ptr);
++
++static inline int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp,
++ cpumask_t *mask)
++{
++ return 0;
++}
++
++static __always_inline void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
++{
++ return kzalloc(size, gfp);
++}
++
++static inline void percpu_free(void *__pdata)
++{
++ kfree(__pdata);
+ }
+
+ #endif /* CONFIG_SMP */
+
+-/* Simple wrapper for the common case: zeros memory. */
+-#define alloc_percpu(type) ((type *)(__alloc_percpu(sizeof(type))))
++#define percpu_populate_mask(__pdata, size, gfp, mask) \
++ __percpu_populate_mask((__pdata), (size), (gfp), &(mask))
++#define percpu_depopulate_mask(__pdata, mask) \
++ __percpu_depopulate_mask((__pdata), &(mask))
++#define percpu_alloc_mask(size, gfp, mask) \
++ __percpu_alloc_mask((size), (gfp), &(mask))
++
++#define percpu_alloc(size, gfp) percpu_alloc_mask((size), (gfp), cpu_online_map)
++
++/* (legacy) interface for use without CPU hotplug handling */
++
++#define __alloc_percpu(size) percpu_alloc_mask((size), GFP_KERNEL, \
++ cpu_possible_map)
++#define alloc_percpu(type) (type *)__alloc_percpu(sizeof(type))
++#define free_percpu(ptr) percpu_free((ptr))
++#define per_cpu_ptr(ptr, cpu) percpu_ptr((ptr), (cpu))
+
+ #endif /* __LINUX_PERCPU_H */
+diff --git a/include/linux/personality.h b/include/linux/personality.h
+index 80d780e..bf4cf20 100644
+--- a/include/linux/personality.h
++++ b/include/linux/personality.h
+@@ -1,6 +1,8 @@
+ #ifndef _LINUX_PERSONALITY_H
+ #define _LINUX_PERSONALITY_H
+
++#ifdef __KERNEL__
++
+ /*
+ * Handling of different ABIs (personalities).
+ */
+@@ -12,6 +14,8 @@ extern int register_exec_domain(struct
+ extern int unregister_exec_domain(struct exec_domain *);
+ extern int __set_personality(unsigned long);
+
++#endif /* __KERNEL__ */
++
+ /*
+ * Flags for bug emulation.
+ *
+@@ -71,6 +75,7 @@ enum {
+ PER_MASK = 0x00ff,
+ };
+
++#ifdef __KERNEL__
+
+ /*
+ * Description of an execution domain.
+@@ -111,4 +116,6 @@ struct exec_domain {
+ #define set_personality(pers) \
+ ((current->personality == pers) ? 0 : __set_personality(pers))
+
++#endif /* __KERNEL__ */
++
+ #endif /* _LINUX_PERSONALITY_H */
+diff --git a/include/linux/pid.h b/include/linux/pid.h
+index 29960b0..2c0007d 100644
+--- a/include/linux/pid.h
++++ b/include/linux/pid.h
+@@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_
+ extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid,
+ enum pid_type));
+
++extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
++
+ /*
+ * attach_pid() and detach_pid() must be called with the tasklist_lock
+ * write-held.
+@@ -76,6 +78,8 @@ extern int FASTCALL(attach_pid(struct ta
+ enum pid_type type, int nr));
+
+ extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type));
++extern void FASTCALL(transfer_pid(struct task_struct *old,
++ struct task_struct *new, enum pid_type));
+
+ /*
+ * look up a PID in the hash table. Must be called with the tasklist_lock
+@@ -87,33 +91,42 @@ extern struct pid *FASTCALL(find_pid(int
+ * Lookup a PID in the hash table, and return with it's count elevated.
+ */
+ extern struct pid *find_get_pid(int nr);
++extern struct pid *find_ge_pid(int nr);
+
+ extern struct pid *alloc_pid(void);
+ extern void FASTCALL(free_pid(struct pid *pid));
+
+-#define pid_next(task, type) \
+- ((task)->pids[(type)].node.next)
+-
+-#define pid_next_task(task, type) \
+- hlist_entry(pid_next(task, type), struct task_struct, \
+- pids[(type)].node)
++static inline pid_t pid_nr(struct pid *pid)
++{
++ pid_t nr = 0;
++ if (pid)
++ nr = pid->nr;
++ return nr;
++}
+
+
+-/* We could use hlist_for_each_entry_rcu here but it takes more arguments
+- * than the do_each_task_pid/while_each_task_pid. So we roll our own
+- * to preserve the existing interface.
+- */
+ #define do_each_task_pid(who, type, task) \
+- if ((task = find_task_by_pid_type(type, who))) { \
+- prefetch(pid_next(task, type)); \
+- do {
++ do { \
++ struct hlist_node *pos___; \
++ struct pid *pid___ = find_pid(who); \
++ if (pid___ != NULL) \
++ hlist_for_each_entry_rcu((task), pos___, \
++ &pid___->tasks[type], pids[type].node) {
+
+ #define while_each_task_pid(who, type, task) \
+- } while (pid_next(task, type) && ({ \
+- task = pid_next_task(task, type); \
+- rcu_dereference(task); \
+- prefetch(pid_next(task, type)); \
+- 1; }) ); \
+- }
++ } \
++ } while (0)
++
++
++#define do_each_pid_task(pid, type, task) \
++ do { \
++ struct hlist_node *pos___; \
++ if (pid != NULL) \
++ hlist_for_each_entry_rcu((task), pos___, \
++ &pid->tasks[type], pids[type].node) {
++
++#define while_each_pid_task(pid, type, task) \
++ } \
++ } while (0)
+
+ #endif /* _LINUX_PID_H */
+diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
+index bd2c5a2..c3f01b3 100644
+--- a/include/linux/pkt_cls.h
++++ b/include/linux/pkt_cls.h
+@@ -305,6 +305,7 @@ enum
+ TCA_FW_POLICE,
+ TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */
+ TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
++ TCA_FW_MASK,
+ __TCA_FW_MAX
+ };
+
+diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
+index 782090c..29cd6de 100644
+--- a/include/linux/platform_device.h
++++ b/include/linux/platform_device.h
+@@ -49,6 +49,8 @@ struct platform_driver {
+ int (*remove)(struct platform_device *);
+ void (*shutdown)(struct platform_device *);
+ int (*suspend)(struct platform_device *, pm_message_t state);
++ int (*suspend_late)(struct platform_device *, pm_message_t state);
++ int (*resume_early)(struct platform_device *);
+ int (*resume)(struct platform_device *);
+ struct device_driver driver;
+ };
+diff --git a/include/linux/pm.h b/include/linux/pm.h
+index 658c1b9..070394e 100644
+--- a/include/linux/pm.h
++++ b/include/linux/pm.h
+@@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_metho
+ #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2)
+ #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3)
+ #define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4)
+-#define PM_DISK_MAX ((__force suspend_disk_method_t) 5)
++#define PM_DISK_TEST ((__force suspend_disk_method_t) 5)
++#define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6)
++#define PM_DISK_MAX ((__force suspend_disk_method_t) 7)
+
+ struct pm_ops {
+ suspend_disk_method_t pm_disk_mode;
+@@ -142,29 +144,61 @@ typedef struct pm_message {
+ } 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.
++ * Several driver power state transitions are externally visible, affecting
++ * the state of pending I/O queues and (for drivers that touch hardware)
++ * interrupts, wakeups, DMA, and other hardware state. There may also be
++ * internal transitions to various low power modes, which are transparent
++ * to the rest of the driver stack (such as a driver that's ON gating off
++ * clocks which are not in active use).
+ *
+- * 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.
++ * One transition is triggered by resume(), after a suspend() call; the
++ * message is implicit:
++ *
++ * ON Driver starts working again, responding to hardware events
++ * and software requests. The hardware may have gone through
++ * a power-off reset, or it may have maintained state from the
++ * previous suspend() which the driver will rely on while
++ * resuming. On most platforms, there are no restrictions on
++ * availability of resources like clocks during resume().
++ *
++ * Other transitions are triggered by messages sent using suspend(). All
++ * these transitions quiesce the driver, so that I/O queues are inactive.
++ * That commonly entails turning off IRQs and DMA; there may be rules
++ * about how to quiesce that are specific to the bus or the device's type.
++ * (For example, network drivers mark the link state.) Other details may
++ * differ according to the message:
++ *
++ * SUSPEND Quiesce, enter a low power device state appropriate for
++ * the upcoming system state (such as PCI_D3hot), and enable
++ * wakeup events as appropriate.
++ *
++ * FREEZE Quiesce operations so that a consistent image can be saved;
++ * but do NOT otherwise enter a low power device state, and do
++ * NOT emit system wakeup events.
++ *
++ * PRETHAW Quiesce as if for FREEZE; additionally, prepare for restoring
++ * the system from a snapshot taken after an earlier FREEZE.
++ * Some drivers will need to reset their hardware state instead
++ * of preserving it, to ensure that it's never mistaken for the
++ * state which that earlier snapshot had set up.
++ *
++ * A minimally power-aware driver treats all messages as SUSPEND, fully
++ * reinitializes its device during resume() -- whether or not it was reset
++ * during the suspend/resume cycle -- and can't issue wakeup events.
++ *
++ * More power-aware drivers may also use low power states at runtime as
++ * well as during system sleep states like PM_SUSPEND_STANDBY. They may
++ * be able to use wakeup events to exit from runtime low-power states,
++ * or from system low-power states such as standby or suspend-to-RAM.
+ */
+
+ #define PM_EVENT_ON 0
+ #define PM_EVENT_FREEZE 1
+ #define PM_EVENT_SUSPEND 2
++#define PM_EVENT_PRETHAW 3
+
+ #define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, })
++#define PMSG_PRETHAW ((struct pm_message){ .event = PM_EVENT_PRETHAW, })
+ #define PMSG_SUSPEND ((struct pm_message){ .event = PM_EVENT_SUSPEND, })
+ #define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, })
+
+@@ -190,6 +224,7 @@ extern void device_resume(void);
+ extern suspend_disk_method_t pm_disk_mode;
+
+ extern int device_suspend(pm_message_t state);
++extern int device_prepare_suspend(pm_message_t state);
+
+ #define device_set_wakeup_enable(dev,val) \
+ ((dev)->power.should_wakeup = !!(val))
+diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
+index 95572c4..a7dd38f 100644
+--- a/include/linux/posix-timers.h
++++ b/include/linux/posix-timers.h
+@@ -72,6 +72,7 @@ struct k_clock {
+ int (*timer_create) (struct k_itimer *timer);
+ int (*nsleep) (const clockid_t which_clock, int flags,
+ struct timespec *, struct timespec __user *);
++ long (*nsleep_restart) (struct restart_block *restart_block);
+ int (*timer_set) (struct k_itimer * timr, int flags,
+ struct itimerspec * new_setting,
+ struct itimerspec * old_setting);
+@@ -97,6 +98,7 @@ int posix_cpu_clock_set(const clockid_t
+ int posix_cpu_timer_create(struct k_itimer *timer);
+ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
+ struct timespec *rqtp, struct timespec __user *rmtp);
++long posix_cpu_nsleep_restart(struct restart_block *restart_block);
+ int posix_cpu_timer_set(struct k_itimer *timer, int flags,
+ struct itimerspec *new, struct itimerspec *old);
+ int posix_cpu_timer_del(struct k_itimer *timer);
+@@ -111,4 +113,6 @@ void posix_cpu_timers_exit_group(struct
+ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
+ cputime_t *newval, cputime_t *oldval);
+
++long clock_nanosleep_restart(struct restart_block *restart_block);
++
+ #endif
+diff --git a/include/linux/ppdev.h b/include/linux/ppdev.h
+index f376a75..dc18c5d 100644
+--- a/include/linux/ppdev.h
++++ b/include/linux/ppdev.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/char/ppdev.h
++ * linux/include/linux/ppdev.h
+ *
+ * User-space parallel port device driver (header file).
+ *
+diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
+index 17e7578..87dec8f 100644
+--- a/include/linux/proc_fs.h
++++ b/include/linux/proc_fs.h
+@@ -4,6 +4,7 @@
+ #include <linux/slab.h>
+ #include <linux/fs.h>
+ #include <linux/spinlock.h>
++#include <linux/magic.h>
+ #include <asm/atomic.h>
+
+ /*
+@@ -24,8 +25,6 @@ enum {
+ PROC_ROOT_INO = 1,
+ };
+
+-#define PROC_SUPER_MAGIC 0x9fa0
+-
+ /*
+ * This is not completely implemented yet. The idea is to
+ * create an in-memory tree (like the actual /proc filesystem
+@@ -245,13 +244,15 @@ static inline void kclist_add(struct kco
+ extern void kclist_add(struct kcore_list *, void *, size_t);
+ #endif
+
++union proc_op {
++ int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
++ int (*proc_read)(struct task_struct *task, char *page);
++};
++
+ struct proc_inode {
+ struct pid *pid;
+ int fd;
+- union {
+- int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
+- int (*proc_read)(struct task_struct *task, char *page);
+- } op;
++ union proc_op op;
+ struct proc_dir_entry *pde;
+ struct inode vfs_inode;
+ };
+@@ -269,7 +270,9 @@ static inline struct proc_dir_entry *PDE
+ struct proc_maps_private {
+ struct pid *pid;
+ struct task_struct *task;
++#ifdef CONFIG_MMU
+ struct vm_area_struct *tail_vma;
++#endif
+ };
+
+ #endif /* _LINUX_PROC_FS_H */
+diff --git a/include/linux/profile.h b/include/linux/profile.h
+index e633004..acce53f 100644
+--- a/include/linux/profile.h
++++ b/include/linux/profile.h
+@@ -17,7 +17,7 @@ struct notifier_block;
+
+ /* init basic kernel profiler */
+ void __init profile_init(void);
+-void profile_tick(int, struct pt_regs *);
++void profile_tick(int);
+ void profile_hit(int, void *);
+ #ifdef CONFIG_PROC_FS
+ void create_prof_cpu_mask(struct proc_dir_entry *);
+diff --git a/include/linux/pspace.h b/include/linux/pspace.h
+new file mode 100644
+index 0000000..91d48b8
+--- /dev/null
++++ b/include/linux/pspace.h
+@@ -0,0 +1,23 @@
++#ifndef _LINUX_PSPACE_H
++#define _LINUX_PSPACE_H
++
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/threads.h>
++#include <linux/pid.h>
++
++struct pidmap {
++ atomic_t nr_free;
++ void *page;
++};
++
++#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
++
++struct pspace {
++ struct pidmap pidmap[PIDMAP_ENTRIES];
++ int last_pid;
++};
++
++extern struct pspace init_pspace;
++
++#endif /* _LINUX_PSPACE_H */
+diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
+index 8b2749a..eeb1976 100644
+--- a/include/linux/ptrace.h
++++ b/include/linux/ptrace.h
+@@ -16,8 +16,8 @@
+ #define PTRACE_KILL 8
+ #define PTRACE_SINGLESTEP 9
+
+-#define PTRACE_ATTACH 0x10
+-#define PTRACE_DETACH 0x11
++#define PTRACE_ATTACH 16
++#define PTRACE_DETACH 17
+
+ #define PTRACE_SYSCALL 24
+
+diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
+index 27f49c8..0c7ac44 100644
+--- a/include/linux/qnx4_fs.h
++++ b/include/linux/qnx4_fs.h
+@@ -11,6 +11,7 @@
+ #define _LINUX_QNX4_FS_H
+
+ #include <linux/qnxtypes.h>
++#include <linux/magic.h>
+
+ #define QNX4_ROOT_INO 1
+
+@@ -25,7 +26,6 @@
+
+ #define QNX4_I_MAP_SLOTS 8
+ #define QNX4_Z_MAP_SLOTS 64
+-#define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */
+ #define QNX4_VALID_FS 0x0001 /* Clean fs. */
+ #define QNX4_ERROR_FS 0x0002 /* fs has errors. */
+ #define QNX4_BLOCK_SIZE 0x200 /* blocksize of 512 bytes */
+diff --git a/include/linux/raid/Kbuild b/include/linux/raid/Kbuild
+index 73fa27a..2415a64 100644
+--- a/include/linux/raid/Kbuild
++++ b/include/linux/raid/Kbuild
+@@ -1 +1,2 @@
+-header-y += md_p.h md_u.h
++header-y += md_p.h
++header-y += md_u.h
+diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
+index 63df898..ebd42a3 100644
+--- a/include/linux/raid/bitmap.h
++++ b/include/linux/raid/bitmap.h
+@@ -146,16 +146,16 @@ enum bitmap_state {
+
+ /* the superblock at the front of the bitmap file -- little endian */
+ typedef struct bitmap_super_s {
+- __u32 magic; /* 0 BITMAP_MAGIC */
+- __u32 version; /* 4 the bitmap major for now, could change... */
+- __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */
+- __u64 events; /* 24 event counter for the bitmap (1)*/
+- __u64 events_cleared;/*32 event counter when last bit cleared (2) */
+- __u64 sync_size; /* 40 the size of the md device's sync range(3) */
+- __u32 state; /* 48 bitmap state information */
+- __u32 chunksize; /* 52 the bitmap chunk size in bytes */
+- __u32 daemon_sleep; /* 56 seconds between disk flushes */
+- __u32 write_behind; /* 60 number of outstanding write-behind writes */
++ __le32 magic; /* 0 BITMAP_MAGIC */
++ __le32 version; /* 4 the bitmap major for now, could change... */
++ __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */
++ __le64 events; /* 24 event counter for the bitmap (1)*/
++ __le64 events_cleared;/*32 event counter when last bit cleared (2) */
++ __le64 sync_size; /* 40 the size of the md device's sync range(3) */
++ __le32 state; /* 48 bitmap state information */
++ __le32 chunksize; /* 52 the bitmap chunk size in bytes */
++ __le32 daemon_sleep; /* 56 seconds between disk flushes */
++ __le32 write_behind; /* 60 number of outstanding write-behind writes */
+
+ __u8 pad[256 - 64]; /* set to zero */
+ } bitmap_super_t;
+@@ -265,6 +265,8 @@ int bitmap_update_sb(struct bitmap *bitm
+ int bitmap_setallbits(struct bitmap *bitmap);
+ void bitmap_write_all(struct bitmap *bitmap);
+
++void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e);
++
+ /* these are exported */
+ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset,
+ unsigned long sectors, int behind);
+diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
+index eb3e547..866a1e2 100644
+--- a/include/linux/raid/md.h
++++ b/include/linux/raid/md.h
+@@ -53,6 +53,8 @@
+ #include <linux/raid/md_u.h>
+ #include <linux/raid/md_k.h>
+
++#ifdef CONFIG_MD
++
+ /*
+ * Different major versions are not compatible.
+ * Different minor versions are only downward compatible.
+@@ -93,7 +95,7 @@ extern int sync_page_io(struct block_dev
+ extern void md_do_sync(mddev_t *mddev);
+ extern void md_new_event(mddev_t *mddev);
+
+-extern void md_update_sb(mddev_t * mddev);
+
++#endif /* CONFIG_MD */
+ #endif
+
+diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
+index d288902..8245c28 100644
+--- a/include/linux/raid/md_k.h
++++ b/include/linux/raid/md_k.h
+@@ -18,6 +18,8 @@
+ /* and dm-bio-list.h is not under include/linux because.... ??? */
+ #include "../../../drivers/md/dm-bio-list.h"
+
++#ifdef CONFIG_BLOCK
++
+ #define LEVEL_MULTIPATH (-4)
+ #define LEVEL_LINEAR (-1)
+ #define LEVEL_FAULTY (-5)
+@@ -29,18 +31,15 @@
+ #define LEVEL_NONE (-1000000)
+
+ #define MaxSector (~(sector_t)0)
+-#define MD_THREAD_NAME_MAX 14
+
+ typedef struct mddev_s mddev_t;
+ typedef struct mdk_rdev_s mdk_rdev_t;
+
+-#define MAX_MD_DEVS 256 /* Max number of md dev */
+-
+ /*
+ * options passed in raidrun:
+ */
+
+-/* Currently this must fix in an 'int' */
++/* Currently this must fit in an 'int' */
+ #define MAX_CHUNK_SIZE (1<<30)
+
+ /*
+@@ -114,7 +113,11 @@ struct mddev_s
+ dev_t unit;
+ int md_minor;
+ struct list_head disks;
+- int sb_dirty;
++ unsigned long flags;
++#define MD_CHANGE_DEVS 0 /* Some device status has changed */
++#define MD_CHANGE_CLEAN 1 /* transition to or from 'clean' */
++#define MD_CHANGE_PENDING 2 /* superblock update in progress */
++
+ int ro;
+
+ struct gendisk *gendisk;
+@@ -362,5 +365,6 @@ static inline void safe_put_page(struct
+ if (p) put_page(p);
+ }
+
++#endif /* CONFIG_BLOCK */
+ #endif
+
+diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
+index b6ebc69..3f2cd98 100644
+--- a/include/linux/raid/md_p.h
++++ b/include/linux/raid/md_p.h
+@@ -206,52 +206,52 @@ static inline __u64 md_event(mdp_super_t
+ */
+ struct mdp_superblock_1 {
+ /* constant array information - 128 bytes */
+- __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
+- __u32 major_version; /* 1 */
+- __u32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */
+- __u32 pad0; /* always set to 0 when writing */
++ __le32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
++ __le32 major_version; /* 1 */
++ __le32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */
++ __le32 pad0; /* always set to 0 when writing */
+
+ __u8 set_uuid[16]; /* user-space generated. */
+ char set_name[32]; /* set and interpreted by user-space */
+
+- __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/
+- __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */
+- __u32 layout; /* only for raid5 and raid10 currently */
+- __u64 size; /* used size of component devices, in 512byte sectors */
++ __le64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/
++ __le32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */
++ __le32 layout; /* only for raid5 and raid10 currently */
++ __le64 size; /* used size of component devices, in 512byte sectors */
+
+- __u32 chunksize; /* in 512byte sectors */
+- __u32 raid_disks;
+- __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts
++ __le32 chunksize; /* in 512byte sectors */
++ __le32 raid_disks;
++ __le32 bitmap_offset; /* sectors after start of superblock that bitmap starts
+ * NOTE: signed, so bitmap can be before superblock
+ * only meaningful of feature_map[0] is set.
+ */
+
+ /* These are only valid with feature bit '4' */
+- __u32 new_level; /* new level we are reshaping to */
+- __u64 reshape_position; /* next address in array-space for reshape */
+- __u32 delta_disks; /* change in number of raid_disks */
+- __u32 new_layout; /* new layout */
+- __u32 new_chunk; /* new chunk size (bytes) */
++ __le32 new_level; /* new level we are reshaping to */
++ __le64 reshape_position; /* next address in array-space for reshape */
++ __le32 delta_disks; /* change in number of raid_disks */
++ __le32 new_layout; /* new layout */
++ __le32 new_chunk; /* new chunk size (bytes) */
+ __u8 pad1[128-124]; /* set to 0 when written */
+
+ /* constant this-device information - 64 bytes */
+- __u64 data_offset; /* sector start of data, often 0 */
+- __u64 data_size; /* sectors in this device that can be used for data */
+- __u64 super_offset; /* sector start of this superblock */
+- __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
+- __u32 dev_number; /* permanent identifier of this device - not role in raid */
+- __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */
++ __le64 data_offset; /* sector start of data, often 0 */
++ __le64 data_size; /* sectors in this device that can be used for data */
++ __le64 super_offset; /* sector start of this superblock */
++ __le64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
++ __le32 dev_number; /* permanent identifier of this device - not role in raid */
++ __le32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */
+ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */
+ __u8 devflags; /* per-device flags. Only one defined...*/
+ #define WriteMostly1 1 /* mask for writemostly flag in above */
+ __u8 pad2[64-57]; /* set to 0 when writing */
+
+ /* array state information - 64 bytes */
+- __u64 utime; /* 40 bits second, 24 btes microseconds */
+- __u64 events; /* incremented when superblock updated */
+- __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */
+- __u32 sb_csum; /* checksum upto devs[max_dev] */
+- __u32 max_dev; /* size of devs[] array to consider */
++ __le64 utime; /* 40 bits second, 24 btes microseconds */
++ __le64 events; /* incremented when superblock updated */
++ __le64 resync_offset; /* data before this offset (from data_offset) known to be in sync */
++ __le32 sb_csum; /* checksum upto devs[max_dev] */
++ __le32 max_dev; /* size of devs[] array to consider */
+ __u8 pad3[64-32]; /* set to 0 when writing */
+
+ /* device state information. Indexed by dev_number.
+@@ -260,7 +260,7 @@ struct mdp_superblock_1 {
+ * into the 'roles' value. If a device is spare or faulty, then it doesn't
+ * have a meaningful role.
+ */
+- __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
++ __le16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
+ };
+
+ /* feature_map bits */
+diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h
+index 81da20c..7192035 100644
+--- a/include/linux/raid/md_u.h
++++ b/include/linux/raid/md_u.h
+@@ -41,7 +41,7 @@
+
+ /* usage */
+ #define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t)
+-#define START_ARRAY _IO (MD_MAJOR, 0x31)
++/* 0x31 was START_ARRAY */
+ #define STOP_ARRAY _IO (MD_MAJOR, 0x32)
+ #define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33)
+ #define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34)
+diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
+index 3009c81..0a9ba7c 100644
+--- a/include/linux/raid/raid1.h
++++ b/include/linux/raid/raid1.h
+@@ -30,7 +30,6 @@ struct r1_private_data_s {
+ mddev_t *mddev;
+ mirror_info_t *mirrors;
+ int raid_disks;
+- int working_disks;
+ int last_used;
+ sector_t next_seq_sect;
+ spinlock_t device_lock;
+diff --git a/include/linux/raid/raid10.h b/include/linux/raid/raid10.h
+index c41e56a..e9091cf 100644
+--- a/include/linux/raid/raid10.h
++++ b/include/linux/raid/raid10.h
+@@ -16,7 +16,6 @@ struct r10_private_data_s {
+ mddev_t *mddev;
+ mirror_info_t *mirrors;
+ int raid_disks;
+- int working_disks;
+ spinlock_t device_lock;
+
+ /* geometry */
+diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
+index 20ed4c9..f13299a 100644
+--- a/include/linux/raid/raid5.h
++++ b/include/linux/raid/raid5.h
+@@ -195,8 +195,9 @@ struct stripe_head {
+ * it to the count of prereading stripes.
+ * When write is initiated, or the stripe refcnt == 0 (just in case) we
+ * clear the PREREAD_ACTIVE flag and decrement the count
+- * Whenever the delayed queue is empty and the device is not plugged, we
+- * move any strips from delayed to handle and clear the DELAYED flag and set PREREAD_ACTIVE.
++ * Whenever the 'handle' queue is empty and the device is not plugged, we
++ * move any strips from delayed to handle and clear the DELAYED flag and set
++ * PREREAD_ACTIVE.
+ * In stripe_handle, if we find pre-reading is necessary, we do it if
+ * PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue.
+ * HANDLE gets cleared if stripe_handle leave nothing locked.
+@@ -213,7 +214,7 @@ struct raid5_private_data {
+ struct disk_info *spare;
+ int chunk_size, level, algorithm;
+ int max_degraded;
+- int raid_disks, working_disks, failed_disks;
++ int raid_disks;
+ int max_nr_stripes;
+
+ /* used during an expand */
+diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h
+index d0dd38b..d22ad39 100644
+--- a/include/linux/raid_class.h
++++ b/include/linux/raid_class.h
+@@ -77,5 +77,6 @@ DEFINE_RAID_ATTRIBUTE(enum raid_state, s
+ struct raid_template *raid_class_attach(struct raid_function_template *);
+ void raid_class_release(struct raid_template *);
+
+-void raid_component_add(struct raid_template *, struct device *,
+- struct device *);
++int __must_check raid_component_add(struct raid_template *, struct device *,
++ struct device *);
++
+diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
+index 00b340b..b160fb1 100644
+--- a/include/linux/ramfs.h
++++ b/include/linux/ramfs.h
+@@ -17,5 +17,6 @@ extern int ramfs_nommu_mmap(struct file
+
+ extern const struct file_operations ramfs_file_operations;
+ extern struct vm_operations_struct generic_file_vm_ops;
++extern int __init init_rootfs(void);
+
+ #endif
+diff --git a/include/linux/random.h b/include/linux/random.h
+index 5d6456b..0248b30 100644
+--- a/include/linux/random.h
++++ b/include/linux/random.h
+@@ -69,6 +69,9 @@ extern struct file_operations random_fop
+ unsigned int get_random_int(void);
+ unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
+
++u32 random32(void);
++void srandom32(u32 seed);
++
+ #endif /* __KERNEL___ */
+
+ #endif /* _LINUX_RANDOM_H */
+diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
+index 8d5382e..344bc34 100644
+--- a/include/linux/rbtree.h
++++ b/include/linux/rbtree.h
+@@ -133,7 +133,7 @@ static inline void rb_set_color(struct r
+ #define rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+ #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+-#define RB_EMPTY_NODE(node) (rb_parent(node) != node)
++#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
+ #define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
+ extern void rb_insert_color(struct rb_node *, struct rb_root *);
+diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
+index b4ca73d..c6b7485 100644
+--- a/include/linux/rcupdate.h
++++ b/include/linux/rcupdate.h
+@@ -19,7 +19,7 @@
+ *
+ * Author: Dipankar Sarma <dipankar at in.ibm.com>
+ *
+- * Based on the original work by Paul McKenney <paul.mckenney at us.ibm.com>
++ * Based on the original work by Paul McKenney <paulmck at us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+@@ -66,6 +66,8 @@ struct rcu_ctrlblk {
+ long completed; /* Number of the last completed batch */
+ int next_pending; /* Is the next batch already waiting? */
+
++ int signaled;
++
+ spinlock_t lock ____cacheline_internodealigned_in_smp;
+ cpumask_t cpumask; /* CPUs that need to switch in order */
+ /* for current batch to proceed. */
+@@ -106,9 +108,6 @@ struct rcu_data {
+ long blimit; /* Upper limit on a processed batch */
+ int cpu;
+ struct rcu_head barrier;
+-#ifdef CONFIG_SMP
+- long last_rs_qlen; /* qlen during the last resched */
+-#endif
+ };
+
+ DECLARE_PER_CPU(struct rcu_data, rcu_data);
+diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h
+index 806ec5b..fe00f78 100644
+--- a/include/linux/reiserfs_acl.h
++++ b/include/linux/reiserfs_acl.h
+@@ -56,6 +56,16 @@ extern int reiserfs_xattr_posix_acl_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;
++
++static inline void reiserfs_init_acl_access(struct inode *inode)
++{
++ REISERFS_I(inode)->i_acl_access = NULL;
++}
++
++static inline void reiserfs_init_acl_default(struct inode *inode)
++{
++ REISERFS_I(inode)->i_acl_default = NULL;
++}
+ #else
+
+ #define reiserfs_cache_default_acl(inode) 0
+@@ -87,4 +97,11 @@ reiserfs_inherit_default_acl(const struc
+ return 0;
+ }
+
++static inline void reiserfs_init_acl_access(struct inode *inode)
++{
++}
++
++static inline void reiserfs_init_acl_default(struct inode *inode)
++{
++}
+ #endif
+diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
+index daa2d83..7bc6bfb 100644
+--- a/include/linux/reiserfs_fs.h
++++ b/include/linux/reiserfs_fs.h
+@@ -12,6 +12,8 @@
+ #define _LINUX_REISER_FS_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
++
+ #ifdef __KERNEL__
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+@@ -227,14 +229,6 @@ struct reiserfs_super_block {
+ ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(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. */
+-#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);
+@@ -813,21 +807,19 @@ struct stat_data_v1 {
+ #define set_sd_v1_first_direct_byte(sdp,v) \
+ ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
+
+-#include <linux/ext2_fs.h>
+-
+ /* inode flags stored in sd_attrs (nee sd_reserved) */
+
+ /* we want common flags to have the same values as in ext2,
+ so chattr(1) will work without problems */
+-#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+-#define REISERFS_APPEND_FL EXT2_APPEND_FL
+-#define REISERFS_SYNC_FL EXT2_SYNC_FL
+-#define REISERFS_NOATIME_FL EXT2_NOATIME_FL
+-#define REISERFS_NODUMP_FL EXT2_NODUMP_FL
+-#define REISERFS_SECRM_FL EXT2_SECRM_FL
+-#define REISERFS_UNRM_FL EXT2_UNRM_FL
+-#define REISERFS_COMPR_FL EXT2_COMPR_FL
+-#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL
++#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL
++#define REISERFS_APPEND_FL FS_APPEND_FL
++#define REISERFS_SYNC_FL FS_SYNC_FL
++#define REISERFS_NOATIME_FL FS_NOATIME_FL
++#define REISERFS_NODUMP_FL FS_NODUMP_FL
++#define REISERFS_SECRM_FL FS_SECRM_FL
++#define REISERFS_UNRM_FL FS_UNRM_FL
++#define REISERFS_COMPR_FL FS_COMPR_FL
++#define REISERFS_NOTAIL_FL FS_NOTAIL_FL
+
+ /* persistent flags that file inherits from the parent directory */
+ #define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \
+@@ -2081,6 +2073,10 @@ void reiserfs_init_alloc_options(struct
+ */
+ __le32 reiserfs_choose_packing(struct inode *dir);
+
++int reiserfs_init_bitmap_cache(struct super_block *sb);
++void reiserfs_free_bitmap_cache(struct super_block *sb);
++void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
++struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
+ 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);
+@@ -2169,15 +2165,24 @@ __u32 r5_hash(const signed char *msg, in
+ /* prototypes from ioctl.c */
+ int reiserfs_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
++long reiserfs_compat_ioctl(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),
+ lsattr(1) will work with us. */
+-#define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS
+-#define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS
+-#define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION
+-#define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION
++#define REISERFS_IOC_GETFLAGS FS_IOC_GETFLAGS
++#define REISERFS_IOC_SETFLAGS FS_IOC_SETFLAGS
++#define REISERFS_IOC_GETVERSION FS_IOC_GETVERSION
++#define REISERFS_IOC_SETVERSION FS_IOC_SETVERSION
++
++/* the 32 bit compat definitions with int argument */
++#define REISERFS_IOC32_UNPACK _IOW(0xCD, 1, int)
++#define REISERFS_IOC32_GETFLAGS FS_IOC32_GETFLAGS
++#define REISERFS_IOC32_SETFLAGS FS_IOC32_SETFLAGS
++#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION
++#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION
+
+ /* Locking primitives */
+ /* Right now we are still falling back to (un)lock_kernel, but eventually that
+diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
+index 149be8d..5b3b297 100644
+--- a/include/linux/reiserfs_fs_i.h
++++ b/include/linux/reiserfs_fs_i.h
+@@ -52,10 +52,13 @@ struct reiserfs_inode_info {
+ ** flushed */
+ unsigned long i_trans_id;
+ struct reiserfs_journal_list *i_jl;
+-
++#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+ struct posix_acl *i_acl_access;
+ struct posix_acl *i_acl_default;
++#endif
++#ifdef CONFIG_REISERFS_FS_XATTR
+ struct rw_semaphore xattr_sem;
++#endif
+ struct inode vfs_inode;
+ };
+
+diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
+index 31b4c0b..73e0bec 100644
+--- a/include/linux/reiserfs_fs_sb.h
++++ b/include/linux/reiserfs_fs_sb.h
+@@ -267,7 +267,6 @@ 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;
+@@ -414,6 +413,7 @@ struct reiserfs_sb_info {
+ /* Definitions of reiserfs on-disk properties: */
+ #define REISERFS_3_5 0
+ #define REISERFS_3_6 1
++#define REISERFS_OLD_FORMAT 2
+
+ enum reiserfs_mount_options {
+ /* Mount options */
+diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
+index 5e96103..966c358 100644
+--- a/include/linux/reiserfs_xattr.h
++++ b/include/linux/reiserfs_xattr.h
+@@ -97,6 +97,11 @@ static inline void reiserfs_mark_inode_p
+ inode->i_flags |= S_PRIVATE;
+ }
+
++static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
++{
++ init_rwsem(&REISERFS_I(inode)->xattr_sem);
++}
++
+ #else
+
+ #define is_reiserfs_priv_object(inode) 0
+@@ -129,6 +134,9 @@ static inline int reiserfs_xattr_init(st
+ sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */
+ return 0;
+ };
++static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
++{
++}
+ #endif
+
+ #endif /* __KERNEL__ */
+diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
+index a376bd4..81e9299 100644
+--- a/include/linux/resume-trace.h
++++ b/include/linux/resume-trace.h
+@@ -3,21 +3,25 @@
+
+ #ifdef CONFIG_PM_TRACE
+
++extern int pm_trace_enabled;
++
+ struct device;
+ extern void set_trace_device(struct device *);
+ extern void generate_resume_trace(void *tracedata, unsigned int user);
+
+ #define TRACE_DEVICE(dev) set_trace_device(dev)
+-#define TRACE_RESUME(user) do { \
+- void *tracedata; \
+- asm volatile("movl $1f,%0\n" \
+- ".section .tracedata,\"a\"\n" \
+- "1:\t.word %c1\n" \
+- "\t.long %c2\n" \
+- ".previous" \
+- :"=r" (tracedata) \
+- : "i" (__LINE__), "i" (__FILE__)); \
+- generate_resume_trace(tracedata, user); \
++#define TRACE_RESUME(user) do { \
++ if (pm_trace_enabled) { \
++ void *tracedata; \
++ asm volatile("movl $1f,%0\n" \
++ ".section .tracedata,\"a\"\n" \
++ "1:\t.word %c1\n" \
++ "\t.long %c2\n" \
++ ".previous" \
++ :"=r" (tracedata) \
++ : "i" (__LINE__), "i" (__FILE__)); \
++ generate_resume_trace(tracedata, user); \
++ } \
+ } while (0)
+
+ #else
+diff --git a/include/linux/rmap.h b/include/linux/rmap.h
+index bf97b09..db2c1df 100644
+--- a/include/linux/rmap.h
++++ b/include/linux/rmap.h
+@@ -103,6 +103,14 @@ pte_t *page_check_address(struct page *,
+ */
+ unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
+
++/*
++ * Cleans the PTEs of shared mappings.
++ * (and since clean PTEs should also be readonly, write protects them too)
++ *
++ * returns the number of cleaned PTEs.
++ */
++int page_mkclean(struct page *);
++
+ #else /* !CONFIG_MMU */
+
+ #define anon_vma_init() do {} while (0)
+@@ -112,6 +120,12 @@ unsigned long page_address_in_vma(struct
+ #define page_referenced(page,l) TestClearPageReferenced(page)
+ #define try_to_unmap(page, refs) SWAP_FAIL
+
++static inline int page_mkclean(struct page *page)
++{
++ return 0;
++}
++
++
+ #endif /* CONFIG_MMU */
+
+ /*
+diff --git a/include/linux/rtc.h b/include/linux/rtc.h
+index 5371e4e..09ff4c3 100644
+--- a/include/linux/rtc.h
++++ b/include/linux/rtc.h
+@@ -141,7 +141,7 @@ struct rtc_device
+ int id;
+ char name[RTC_DEVICE_NAME_SIZE];
+
+- struct rtc_class_ops *ops;
++ const struct rtc_class_ops *ops;
+ struct mutex ops_lock;
+
+ struct class_device *rtc_dev;
+@@ -172,7 +172,7 @@ struct rtc_device
+
+ extern struct rtc_device *rtc_device_register(const char *name,
+ struct device *dev,
+- struct rtc_class_ops *ops,
++ const struct rtc_class_ops *ops,
+ struct module *owner);
+ extern void rtc_device_unregister(struct rtc_device *rdev);
+ extern int rtc_interface_register(struct class_interface *intf);
+@@ -208,7 +208,7 @@ int rtc_register(rtc_task_t *task);
+ int rtc_unregister(rtc_task_t *task);
+ int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
+ void rtc_get_rtc_time(struct rtc_time *rtc_tm);
+-irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t rtc_interrupt(int irq, void *dev_id);
+
+ #endif /* __KERNEL__ */
+
+diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
+index facd9ee..3a18add 100644
+--- a/include/linux/rtnetlink.h
++++ b/include/linux/rtnetlink.h
+@@ -2,6 +2,7 @@
+ #define __LINUX_RTNETLINK_H
+
+ #include <linux/netlink.h>
++#include <linux/if_link.h>
+
+ /****
+ * Routing/neighbour discovery messages.
+@@ -238,10 +239,8 @@ enum rt_class_t
+ RT_TABLE_DEFAULT=253,
+ RT_TABLE_MAIN=254,
+ RT_TABLE_LOCAL=255,
+- __RT_TABLE_MAX
++ RT_TABLE_MAX=0xFFFFFFFF
+ };
+-#define RT_TABLE_MAX (__RT_TABLE_MAX - 1)
+-
+
+
+ /* Routing message attributes */
+@@ -263,6 +262,7 @@ enum rtattr_type_t
+ RTA_CACHEINFO,
+ RTA_SESSION,
+ RTA_MP_ALGO,
++ RTA_TABLE,
+ __RTA_MAX
+ };
+
+@@ -383,226 +383,6 @@ struct rta_session
+ } u;
+ };
+
+-
+-/*********************************************************
+- * Interface address.
+- ****/
+-
+-struct ifaddrmsg
+-{
+- unsigned char ifa_family;
+- unsigned char ifa_prefixlen; /* The prefix length */
+- unsigned char ifa_flags; /* Flags */
+- unsigned char ifa_scope; /* See above */
+- int ifa_index; /* Link index */
+-};
+-
+-enum
+-{
+- IFA_UNSPEC,
+- IFA_ADDRESS,
+- IFA_LOCAL,
+- IFA_LABEL,
+- IFA_BROADCAST,
+- IFA_ANYCAST,
+- IFA_CACHEINFO,
+- IFA_MULTICAST,
+- __IFA_MAX
+-};
+-
+-#define IFA_MAX (__IFA_MAX - 1)
+-
+-/* ifa_flags */
+-
+-#define IFA_F_SECONDARY 0x01
+-#define IFA_F_TEMPORARY IFA_F_SECONDARY
+-
+-#define IFA_F_DEPRECATED 0x20
+-#define IFA_F_TENTATIVE 0x40
+-#define IFA_F_PERMANENT 0x80
+-
+-struct ifa_cacheinfo
+-{
+- __u32 ifa_prefered;
+- __u32 ifa_valid;
+- __u32 cstamp; /* created timestamp, hundredths of seconds */
+- __u32 tstamp; /* updated timestamp, hundredths of seconds */
+-};
+-
+-
+-#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+-#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+-
+-/*
+- Important comment:
+- IFA_ADDRESS is prefix address, rather than local interface address.
+- It makes no difference for normally configured broadcast interfaces,
+- but for point-to-point IFA_ADDRESS is DESTINATION address,
+- local address is supplied in IFA_LOCAL attribute.
+- */
+-
+-/**************************************************************
+- * Neighbour discovery.
+- ****/
+-
+-struct ndmsg
+-{
+- unsigned char ndm_family;
+- unsigned char ndm_pad1;
+- unsigned short ndm_pad2;
+- int ndm_ifindex; /* Link index */
+- __u16 ndm_state;
+- __u8 ndm_flags;
+- __u8 ndm_type;
+-};
+-
+-enum
+-{
+- NDA_UNSPEC,
+- NDA_DST,
+- NDA_LLADDR,
+- NDA_CACHEINFO,
+- NDA_PROBES,
+- __NDA_MAX
+-};
+-
+-#define NDA_MAX (__NDA_MAX - 1)
+-
+-#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+-#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
+-
+-/*
+- * Neighbor Cache Entry Flags
+- */
+-
+-#define NTF_PROXY 0x08 /* == ATF_PUBL */
+-#define NTF_ROUTER 0x80
+-
+-/*
+- * Neighbor Cache Entry States.
+- */
+-
+-#define NUD_INCOMPLETE 0x01
+-#define NUD_REACHABLE 0x02
+-#define NUD_STALE 0x04
+-#define NUD_DELAY 0x08
+-#define NUD_PROBE 0x10
+-#define NUD_FAILED 0x20
+-
+-/* Dummy states */
+-#define NUD_NOARP 0x40
+-#define NUD_PERMANENT 0x80
+-#define NUD_NONE 0x00
+-
+-
+-struct nda_cacheinfo
+-{
+- __u32 ndm_confirmed;
+- __u32 ndm_used;
+- __u32 ndm_updated;
+- __u32 ndm_refcnt;
+-};
+-
+-
+-/*****************************************************************
+- * Neighbour tables specific messages.
+- *
+- * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
+- * NLM_F_DUMP flag set. Every neighbour table configuration is
+- * spread over multiple messages to avoid running into message
+- * size limits on systems with many interfaces. The first message
+- * in the sequence transports all not device specific data such as
+- * statistics, configuration, and the default parameter set.
+- * This message is followed by 0..n messages carrying device
+- * specific parameter sets.
+- * Although the ordering should be sufficient, NDTA_NAME can be
+- * used to identify sequences. The initial message can be identified
+- * by checking for NDTA_CONFIG. The device specific messages do
+- * not contain this TLV but have NDTPA_IFINDEX set to the
+- * corresponding interface index.
+- *
+- * To change neighbour table attributes, send RTM_SETNEIGHTBL
+- * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
+- * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
+- * otherwise. Device specific parameter sets can be changed by
+- * setting NDTPA_IFINDEX to the interface index of the corresponding
+- * device.
+- ****/
+-
+-struct ndt_stats
+-{
+- __u64 ndts_allocs;
+- __u64 ndts_destroys;
+- __u64 ndts_hash_grows;
+- __u64 ndts_res_failed;
+- __u64 ndts_lookups;
+- __u64 ndts_hits;
+- __u64 ndts_rcv_probes_mcast;
+- __u64 ndts_rcv_probes_ucast;
+- __u64 ndts_periodic_gc_runs;
+- __u64 ndts_forced_gc_runs;
+-};
+-
+-enum {
+- NDTPA_UNSPEC,
+- NDTPA_IFINDEX, /* u32, unchangeable */
+- NDTPA_REFCNT, /* u32, read-only */
+- NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */
+- NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */
+- NDTPA_RETRANS_TIME, /* u64, msecs */
+- NDTPA_GC_STALETIME, /* u64, msecs */
+- NDTPA_DELAY_PROBE_TIME, /* u64, msecs */
+- NDTPA_QUEUE_LEN, /* u32 */
+- NDTPA_APP_PROBES, /* u32 */
+- NDTPA_UCAST_PROBES, /* u32 */
+- NDTPA_MCAST_PROBES, /* u32 */
+- NDTPA_ANYCAST_DELAY, /* u64, msecs */
+- NDTPA_PROXY_DELAY, /* u64, msecs */
+- NDTPA_PROXY_QLEN, /* u32 */
+- NDTPA_LOCKTIME, /* u64, msecs */
+- __NDTPA_MAX
+-};
+-#define NDTPA_MAX (__NDTPA_MAX - 1)
+-
+-struct ndtmsg
+-{
+- __u8 ndtm_family;
+- __u8 ndtm_pad1;
+- __u16 ndtm_pad2;
+-};
+-
+-struct ndt_config
+-{
+- __u16 ndtc_key_len;
+- __u16 ndtc_entry_size;
+- __u32 ndtc_entries;
+- __u32 ndtc_last_flush; /* delta to now in msecs */
+- __u32 ndtc_last_rand; /* delta to now in msecs */
+- __u32 ndtc_hash_rnd;
+- __u32 ndtc_hash_mask;
+- __u32 ndtc_hash_chain_gc;
+- __u32 ndtc_proxy_qlen;
+-};
+-
+-enum {
+- NDTA_UNSPEC,
+- NDTA_NAME, /* char *, unchangeable */
+- NDTA_THRESH1, /* u32 */
+- NDTA_THRESH2, /* u32 */
+- NDTA_THRESH3, /* u32 */
+- NDTA_CONFIG, /* struct ndt_config, read-only */
+- NDTA_PARMS, /* nested TLV NDTPA_* */
+- NDTA_STATS, /* struct ndt_stats, read-only */
+- NDTA_GC_INTERVAL, /* u64, msecs */
+- __NDTA_MAX
+-};
+-#define NDTA_MAX (__NDTA_MAX - 1)
+-
+-#define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) + \
+- NLMSG_ALIGN(sizeof(struct ndtmsg))))
+-#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
+-
+-
+ /****
+ * General form of address family dependent message.
+ ****/
+@@ -663,138 +443,6 @@ struct prefix_cacheinfo
+ __u32 valid_time;
+ };
+
+-/* The struct should be in sync with struct net_device_stats */
+-struct rtnl_link_stats
+-{
+- __u32 rx_packets; /* total packets received */
+- __u32 tx_packets; /* total packets transmitted */
+- __u32 rx_bytes; /* total bytes received */
+- __u32 tx_bytes; /* total bytes transmitted */
+- __u32 rx_errors; /* bad packets received */
+- __u32 tx_errors; /* packet transmit problems */
+- __u32 rx_dropped; /* no space in linux buffers */
+- __u32 tx_dropped; /* no space available in linux */
+- __u32 multicast; /* multicast packets received */
+- __u32 collisions;
+-
+- /* detailed rx_errors: */
+- __u32 rx_length_errors;
+- __u32 rx_over_errors; /* receiver ring buff overflow */
+- __u32 rx_crc_errors; /* recved pkt with crc error */
+- __u32 rx_frame_errors; /* recv'd frame alignment error */
+- __u32 rx_fifo_errors; /* recv'r fifo overrun */
+- __u32 rx_missed_errors; /* receiver missed packet */
+-
+- /* detailed tx_errors */
+- __u32 tx_aborted_errors;
+- __u32 tx_carrier_errors;
+- __u32 tx_fifo_errors;
+- __u32 tx_heartbeat_errors;
+- __u32 tx_window_errors;
+-
+- /* for cslip etc */
+- __u32 rx_compressed;
+- __u32 tx_compressed;
+-};
+-
+-/* The struct should be in sync with struct ifmap */
+-struct rtnl_link_ifmap
+-{
+- __u64 mem_start;
+- __u64 mem_end;
+- __u64 base_addr;
+- __u16 irq;
+- __u8 dma;
+- __u8 port;
+-};
+-
+-enum
+-{
+- IFLA_UNSPEC,
+- IFLA_ADDRESS,
+- IFLA_BROADCAST,
+- IFLA_IFNAME,
+- IFLA_MTU,
+- IFLA_LINK,
+- IFLA_QDISC,
+- IFLA_STATS,
+- IFLA_COST,
+-#define IFLA_COST IFLA_COST
+- IFLA_PRIORITY,
+-#define IFLA_PRIORITY IFLA_PRIORITY
+- IFLA_MASTER,
+-#define IFLA_MASTER IFLA_MASTER
+- IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+-#define IFLA_WIRELESS IFLA_WIRELESS
+- IFLA_PROTINFO, /* Protocol specific information for a link */
+-#define IFLA_PROTINFO IFLA_PROTINFO
+- IFLA_TXQLEN,
+-#define IFLA_TXQLEN IFLA_TXQLEN
+- IFLA_MAP,
+-#define IFLA_MAP IFLA_MAP
+- IFLA_WEIGHT,
+-#define IFLA_WEIGHT IFLA_WEIGHT
+- IFLA_OPERSTATE,
+- IFLA_LINKMODE,
+- __IFLA_MAX
+-};
+-
+-
+-#define IFLA_MAX (__IFLA_MAX - 1)
+-
+-#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+-#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+-
+-/* ifi_flags.
+-
+- IFF_* flags.
+-
+- The only change is:
+- IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+- more not changeable by user. They describe link media
+- characteristics and set by device driver.
+-
+- Comments:
+- - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+- - If neither of these three flags are set;
+- the interface is NBMA.
+-
+- - IFF_MULTICAST does not mean anything special:
+- multicasts can be used on all not-NBMA links.
+- IFF_MULTICAST means that this media uses special encapsulation
+- for multicast frames. Apparently, all IFF_POINTOPOINT and
+- IFF_BROADCAST devices are able to use multicasts too.
+- */
+-
+-/* IFLA_LINK.
+- For usual devices it is equal ifi_index.
+- If it is a "virtual interface" (f.e. tunnel), ifi_link
+- can point to real physical interface (f.e. for bandwidth calculations),
+- or maybe 0, what means, that real media is unknown (usual
+- for IPIP tunnels, when route to endpoint is allowed to change)
+- */
+-
+-/* Subtype attributes for IFLA_PROTINFO */
+-enum
+-{
+- IFLA_INET6_UNSPEC,
+- IFLA_INET6_FLAGS, /* link flags */
+- IFLA_INET6_CONF, /* sysctl parameters */
+- IFLA_INET6_STATS, /* statistics */
+- IFLA_INET6_MCAST, /* MC things. What of them? */
+- IFLA_INET6_CACHEINFO, /* time values and max reasm size */
+- __IFLA_INET6_MAX
+-};
+-
+-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+-
+-struct ifla_cacheinfo
+-{
+- __u32 max_reasm_len;
+- __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
+- __u32 reachable_time;
+- __u32 retrans_time;
+-};
+
+ /*****************************************************************
+ * Traffic control messages.
+@@ -885,10 +533,13 @@ enum rtnetlink_groups {
+ RTNLGRP_NOP2,
+ RTNLGRP_DECnet_ROUTE,
+ #define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE
+- RTNLGRP_NOP3,
++ RTNLGRP_DECnet_RULE,
++#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE
+ RTNLGRP_NOP4,
+ RTNLGRP_IPV6_PREFIX,
+ #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX
++ RTNLGRP_IPV6_RULE,
++#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE
+ __RTNLGRP_MAX
+ };
+ #define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
+@@ -923,8 +574,6 @@ extern int rtattr_parse(struct rtattr *t
+ #define rtattr_parse_nested(tb, max, rta) \
+ rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta)))
+
+-extern struct sock *rtnl;
+-
+ struct rtnetlink_link
+ {
+ int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);
+@@ -933,6 +582,10 @@ struct rtnetlink_link
+
+ extern struct rtnetlink_link * rtnetlink_links[NPROTO];
+ extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo);
++extern int rtnl_unicast(struct sk_buff *skb, u32 pid);
++extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
++ struct nlmsghdr *nlh, gfp_t flags);
++extern void rtnl_set_sk_err(u32 group, int error);
+ extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
+
+ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data);
+@@ -1065,6 +718,13 @@ extern void __rtnl_unlock(void);
+ } \
+ } while(0)
+
++static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
++{
++ return RTA_GET_U32(rta[RTA_TABLE-1]);
++rtattr_failure:
++ return table;
++}
++
+ #endif /* __KERNEL__ */
+
+
+diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
+index 66ff545..4efbd9c 100644
+--- a/include/linux/scatterlist.h
++++ b/include/linux/scatterlist.h
+@@ -5,7 +5,7 @@
+ #include <linux/mm.h>
+ #include <linux/string.h>
+
+-static inline void sg_set_buf(struct scatterlist *sg, void *buf,
++static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
+ unsigned int buflen)
+ {
+ sg->page = virt_to_page(buf);
+@@ -13,7 +13,7 @@ static inline void sg_set_buf(struct sca
+ sg->length = buflen;
+ }
+
+-static inline void sg_init_one(struct scatterlist *sg, void *buf,
++static inline void sg_init_one(struct scatterlist *sg, const void *buf,
+ unsigned int buflen)
+ {
+ memset(sg, 0, sizeof(*sg));
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index 34ed0d9..eafe4a7 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -24,6 +24,8 @@
+ #define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */
+ #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */
+ #define CLONE_STOPPED 0x02000000 /* Start in stopped state */
++#define CLONE_NEWUTS 0x04000000 /* New utsname group? */
++#define CLONE_NEWIPC 0x08000000 /* New ipcs */
+
+ /*
+ * Scheduling policies
+@@ -118,7 +120,6 @@ extern unsigned long avenrun[]; /* Load
+
+ extern unsigned long total_forks;
+ extern int nr_threads;
+-extern int last_pid;
+ DECLARE_PER_CPU(unsigned long, process_counts);
+ extern int nr_processes(void);
+ extern unsigned long nr_running(void);
+@@ -148,6 +149,7 @@ extern unsigned long weighted_cpuload(co
+ #define EXIT_DEAD 32
+ /* in tsk->state again */
+ #define TASK_NONINTERACTIVE 64
++#define TASK_DEAD 128
+
+ #define __set_task_state(tsk, state_value) \
+ do { (tsk)->state = (state_value); } while (0)
+@@ -238,7 +240,7 @@ extern signed long schedule_timeout_inte
+ extern signed long schedule_timeout_uninterruptible(signed long timeout);
+ asmlinkage void schedule(void);
+
+-struct namespace;
++struct nsproxy;
+
+ /* Maximum number of active map areas.. This is a random (large) number */
+ #define DEFAULT_MAX_MAP_COUNT 65536
+@@ -464,7 +466,6 @@ struct signal_struct {
+ struct pacct_struct pacct; /* per-process accounting information */
+ #endif
+ #ifdef CONFIG_TASKSTATS
+- spinlock_t stats_lock;
+ struct taskstats *stats;
+ #endif
+ };
+@@ -504,8 +505,8 @@ struct signal_struct {
+ #define rt_prio(prio) unlikely((prio) < MAX_RT_PRIO)
+ #define rt_task(p) rt_prio((p)->prio)
+ #define batch_task(p) (unlikely((p)->policy == SCHED_BATCH))
+-#define has_rt_policy(p) \
+- unlikely((p)->policy != SCHED_NORMAL && (p)->policy != SCHED_BATCH)
++#define is_rt_policy(p) ((p) != SCHED_NORMAL && (p) != SCHED_BATCH)
++#define has_rt_policy(p) unlikely(is_rt_policy((p)->policy))
+
+ /*
+ * Some day this will be a full-fledged user tracking system..
+@@ -623,9 +624,17 @@ enum idle_type
+ #define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */
+ #define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */
+ #define SD_POWERSAVINGS_BALANCE 256 /* Balance for power savings */
++#define SD_SHARE_PKG_RESOURCES 512 /* Domain members share cpu pkg resources */
+
+-#define BALANCE_FOR_POWER ((sched_mc_power_savings || sched_smt_power_savings) \
+- ? SD_POWERSAVINGS_BALANCE : 0)
++#define BALANCE_FOR_MC_POWER \
++ (sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0)
++
++#define BALANCE_FOR_PKG_POWER \
++ ((sched_mc_power_savings || sched_smt_power_savings) ? \
++ SD_POWERSAVINGS_BALANCE : 0)
++
++#define test_sd_parent(sd, flag) ((sd->parent && \
++ (sd->parent->flags & flag)) ? 1 : 0)
+
+
+ struct sched_group {
+@@ -642,6 +651,7 @@ struct sched_group {
+ struct sched_domain {
+ /* These fields must be setup */
+ struct sched_domain *parent; /* top domain must be null terminated */
++ struct sched_domain *child; /* bottom domain must be null terminated */
+ struct sched_group *groups; /* the balancing groups of the domain */
+ cpumask_t span; /* span of all CPUs in this domain */
+ unsigned long min_interval; /* Minimum balance interval ms */
+@@ -709,7 +719,6 @@ extern unsigned int max_cache_size;
+
+
+ struct io_context; /* See blkdev.h */
+-void exit_io_context(void);
+ struct cpuset;
+
+ #define NGROUPS_SMALL 32
+@@ -754,6 +763,7 @@ static inline void prefetch_stack(struct
+ struct audit_context; /* See audit.c */
+ struct mempolicy;
+ struct pipe_inode_info;
++struct uts_namespace;
+
+ enum sleep_type {
+ SLEEP_NORMAL,
+@@ -784,8 +794,9 @@ struct task_struct {
+ struct prio_array *array;
+
+ unsigned short ioprio;
++#ifdef CONFIG_BLK_DEV_IO_TRACE
+ unsigned int btrace_seq;
+-
++#endif
+ unsigned long sleep_avg;
+ unsigned long long timestamp, last_ran;
+ unsigned long long sched_time; /* sched_clock time spent running */
+@@ -819,6 +830,11 @@ struct task_struct {
+ unsigned did_exec:1;
+ pid_t pid;
+ pid_t tgid;
++
++#ifdef CONFIG_CC_STACKPROTECTOR
++ /* Canary value for the -fstack-protector gcc feature */
++ unsigned long stack_canary;
++#endif
+ /*
+ * pointers to (original) parent process, youngest child, younger sibling,
+ * older sibling, respectively. (p->father can be replaced with
+@@ -865,6 +881,15 @@ struct task_struct {
+ struct key *thread_keyring; /* keyring private to this thread */
+ unsigned char jit_keyring; /* default keyring to attach requested keys to */
+ #endif
++ /*
++ * fpu_counter contains the number of consecutive context switches
++ * that the FPU is used. If this is over a threshold, the lazy fpu
++ * saving becomes unlazy to save the trap. This is an unsigned char
++ * so that after 256 times the counter wraps and the behavior turns
++ * lazy again; this to deal with bursty apps that only use FPU for
++ * a short time
++ */
++ unsigned char fpu_counter;
+ int oomkilladj; /* OOM kill score adjustment (bit shift). */
+ char comm[TASK_COMM_LEN]; /* executable name excluding path
+ - access with [gs]et_task_comm (which lock
+@@ -872,16 +897,18 @@ struct task_struct {
+ - initialized normally by flush_old_exec */
+ /* file system info */
+ int link_count, total_link_count;
++#ifdef CONFIG_SYSVIPC
+ /* ipc stuff */
+ struct sysv_sem sysvsem;
++#endif
+ /* CPU-specific state of this task */
+ struct thread_struct thread;
+ /* filesystem information */
+ struct fs_struct *fs;
+ /* open file information */
+ struct files_struct *files;
+-/* namespace */
+- struct namespace *namespace;
++/* namespaces */
++ struct nsproxy *nsproxy;
+ /* signal handlers */
+ struct signal_struct *signal;
+ struct sighand_struct *sighand;
+@@ -964,10 +991,10 @@ struct task_struct {
+ wait_queue_t *io_wait;
+ /* i/o counters(bytes read/written, #syscalls */
+ u64 rchar, wchar, syscr, syscw;
+-#if defined(CONFIG_BSD_PROCESS_ACCT)
++#if defined(CONFIG_TASK_XACCT)
+ u64 acct_rss_mem1; /* accumulated rss usage */
+ u64 acct_vm_mem1; /* accumulated virtual memory usage */
+- clock_t acct_stimexpd; /* clock_t-converted stime since last update */
++ cputime_t acct_stimexpd;/* stime since last update */
+ #endif
+ #ifdef CONFIG_NUMA
+ struct mempolicy *mempolicy;
+@@ -1003,6 +1030,26 @@ static inline pid_t process_group(struct
+ return tsk->signal->pgrp;
+ }
+
++static inline struct pid *task_pid(struct task_struct *task)
++{
++ return task->pids[PIDTYPE_PID].pid;
++}
++
++static inline struct pid *task_tgid(struct task_struct *task)
++{
++ return task->group_leader->pids[PIDTYPE_PID].pid;
++}
++
++static inline struct pid *task_pgrp(struct task_struct *task)
++{
++ return task->group_leader->pids[PIDTYPE_PGID].pid;
++}
++
++static inline struct pid *task_session(struct task_struct *task)
++{
++ return task->group_leader->pids[PIDTYPE_SID].pid;
++}
++
+ /**
+ * pid_alive - check that a task structure is not stale
+ * @p: Task structure to be checked.
+@@ -1016,6 +1063,19 @@ static inline int pid_alive(struct task_
+ return p->pids[PIDTYPE_PID].pid != NULL;
+ }
+
++/**
++ * is_init - check if a task structure is init
++ * @tsk: Task structure to be checked.
++ *
++ * Check if a task structure is the first user space task the kernel created.
++ */
++static inline int is_init(struct task_struct *tsk)
++{
++ return tsk->pid == 1;
++}
++
++extern struct pid *cad_pid;
++
+ extern void free_task(struct task_struct *tsk);
+ #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0)
+
+@@ -1034,7 +1094,6 @@ static inline void put_task_struct(struc
+ /* Not implemented yet, only for 486*/
+ #define PF_STARTING 0x00000002 /* being created */
+ #define PF_EXITING 0x00000004 /* getting shut down */
+-#define PF_DEAD 0x00000008 /* Dead */
+ #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
+ #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
+ #define PF_DUMPCORE 0x00000200 /* dumped core */
+@@ -1179,7 +1238,7 @@ extern void switch_uid(struct user_struc
+
+ #include <asm/current.h>
+
+-extern void do_timer(struct pt_regs *);
++extern void do_timer(unsigned long ticks);
+
+ extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state));
+ extern int FASTCALL(wake_up_process(struct task_struct * tsk));
+@@ -1221,10 +1280,15 @@ extern int send_sig_info(int, struct sig
+ extern int send_group_sig_info(int, struct siginfo *, struct task_struct *);
+ extern int force_sigsegv(int, struct task_struct *);
+ extern int force_sig_info(int, struct siginfo *, struct task_struct *);
++extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
++extern int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
++extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
++extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_t, u32);
++extern int kill_pgrp(struct pid *pid, int sig, int priv);
++extern int kill_pid(struct pid *pid, int sig, int priv);
+ extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
+ extern int kill_pg_info(int, struct siginfo *, pid_t);
+ extern int kill_proc_info(int, struct siginfo *, pid_t);
+-extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t, u32);
+ extern void do_notify_parent(struct task_struct *, int);
+ extern void force_sig(int, struct task_struct *);
+ extern void force_sig_specific(int, struct task_struct *);
+@@ -1239,6 +1303,11 @@ extern int send_group_sigqueue(int, stru
+ extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
+ extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
+
++static inline int kill_cad_pid(int sig, int priv)
++{
++ return kill_pid(cad_pid, sig, priv);
++}
++
+ /* These can be the second arg to send_sig_info/send_group_sig_info. */
+ #define SEND_SIG_NOINFO ((struct siginfo *) 0)
+ #define SEND_SIG_PRIV ((struct siginfo *) 1)
+@@ -1332,6 +1401,17 @@ extern void wait_task_inactive(struct ta
+ /* de_thread depends on thread_group_leader not being a pid based check */
+ #define thread_group_leader(p) (p == p->group_leader)
+
++/* Do to the insanities of de_thread it is possible for a process
++ * to have the pid of the thread group leader without actually being
++ * the thread group leader. For iteration through the pids in proc
++ * all we care about is that we have a task with the appropriate
++ * pid, we don't actually care if we have the right task.
++ */
++static inline int has_group_leader_pid(struct task_struct *p)
++{
++ return p->pid == p->tgid;
++}
++
+ static inline struct task_struct *next_thread(const struct task_struct *p)
+ {
+ return list_entry(rcu_dereference(p->thread_group.next),
+diff --git a/include/linux/scx200.h b/include/linux/scx200.h
+index 693c055..de466e1 100644
+--- a/include/linux/scx200.h
++++ b/include/linux/scx200.h
+@@ -32,7 +32,7 @@ extern unsigned scx200_cb_base;
+
+ /* High Resolution Timer */
+ #define SCx200_TIMER_OFFSET 0x08
+-#define SCx200_TIMER_SIZE 0x05
++#define SCx200_TIMER_SIZE 0x06
+
+ /* Clock Generators */
+ #define SCx200_CLOCKGEN_OFFSET 0x10
+diff --git a/include/linux/scx200_gpio.h b/include/linux/scx200_gpio.h
+index 90dd069..1a82d30 100644
+--- a/include/linux/scx200_gpio.h
++++ b/include/linux/scx200_gpio.h
+@@ -4,6 +4,7 @@ u32 scx200_gpio_configure(unsigned index
+
+ extern unsigned scx200_gpio_base;
+ extern long scx200_gpio_shadow[2];
++extern struct nsc_gpio_ops scx200_gpio_ops;
+
+ #define scx200_gpio_present() (scx200_gpio_base!=0)
+
+diff --git a/include/linux/security.h b/include/linux/security.h
+index 6bc2aad..b200b98 100644
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -31,6 +31,8 @@
+ #include <linux/msg.h>
+ #include <linux/sched.h>
+ #include <linux/key.h>
++#include <linux/xfrm.h>
++#include <net/flow.h>
+
+ struct ctl_table;
+
+@@ -88,6 +90,7 @@ extern int cap_netlink_recv(struct sk_bu
+ struct nfsctl_arg;
+ struct sched_param;
+ struct swap_info_struct;
++struct request_sock;
+
+ /* bprm_apply_creds unsafe reasons */
+ #define LSM_UNSAFE_SHARE 1
+@@ -812,9 +815,19 @@ struct swap_info_struct;
+ * which is used to copy security attributes between local stream sockets.
+ * @sk_free_security:
+ * Deallocate security structure.
+- * @sk_getsid:
+- * Retrieve the LSM-specific sid for the sock to enable caching of network
++ * @sk_clone_security:
++ * Clone/copy security structure.
++ * @sk_getsecid:
++ * Retrieve the LSM-specific secid for the sock to enable caching of network
+ * authorizations.
++ * @sock_graft:
++ * Sets the socket's isec sid to the sock's sid.
++ * @inet_conn_request:
++ * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid.
++ * @inet_csk_clone:
++ * Sets the new child socket's sid to the openreq sid.
++ * @req_classify_flow:
++ * Sets the flow's sid to the openreq sid.
+ *
+ * Security hooks for XFRM operations.
+ *
+@@ -823,9 +836,10 @@ struct swap_info_struct;
+ * used by the XFRM system.
+ * @sec_ctx contains the security context information being provided by
+ * the user-level policy update program (e.g., setkey).
+- * Allocate a security structure to the xp->security field.
+- * The security field is initialized to NULL when the xfrm_policy is
+- * allocated.
++ * @sk refers to the sock from which to derive the security context.
++ * Allocate a security structure to the xp->security field; the security
++ * field is initialized to NULL when the xfrm_policy is allocated. Only
++ * one of sec_ctx or sock can be specified.
+ * Return 0 if operation was successful (memory to allocate, legal context)
+ * @xfrm_policy_clone_security:
+ * @old contains an existing xfrm_policy in the SPD.
+@@ -844,9 +858,14 @@ struct swap_info_struct;
+ * Database by the XFRM system.
+ * @sec_ctx contains the security context information being provided by
+ * the user-level SA generation program (e.g., setkey or racoon).
+- * Allocate a security structure to the x->security field. The
+- * security field is initialized to NULL when the xfrm_state is
+- * allocated.
++ * @polsec contains the security context information associated with a xfrm
++ * policy rule from which to take the base context. polsec must be NULL
++ * when sec_ctx is specified.
++ * @secid contains the secid from which to take the mls portion of the context.
++ * Allocate a security structure to the x->security field; the security
++ * field is initialized to NULL when the xfrm_state is allocated. Set the
++ * context to correspond to either sec_ctx or polsec, with the mls portion
++ * taken from secid in the latter case.
+ * Return 0 if operation was successful (memory to allocate, legal context).
+ * @xfrm_state_free_security:
+ * @x contains the xfrm_state.
+@@ -857,13 +876,29 @@ struct swap_info_struct;
+ * @xfrm_policy_lookup:
+ * @xp contains the xfrm_policy for which the access control is being
+ * checked.
+- * @sk_sid contains the sock security label that is used to authorize
++ * @fl_secid contains the flow security label that is used to authorize
+ * access to the policy xp.
+ * @dir contains the direction of the flow (input or output).
+- * Check permission when a sock selects a xfrm_policy for processing
++ * Check permission when a flow selects a xfrm_policy for processing
+ * XFRMs on a packet. The hook is called when selecting either a
+ * per-socket policy or a generic xfrm policy.
+- * Return 0 if permission is granted.
++ * Return 0 if permission is granted, -ESRCH otherwise, or -errno
++ * on other errors.
++ * @xfrm_state_pol_flow_match:
++ * @x contains the state to match.
++ * @xp contains the policy to check for a match.
++ * @fl contains the flow to check for a match.
++ * Return 1 if there is a match.
++ * @xfrm_flow_state_match:
++ * @fl contains the flow key to match.
++ * @xfrm points to the xfrm_state to match.
++ * @xp points to the xfrm_policy to match.
++ * Return 1 if there is a match.
++ * @xfrm_decode_session:
++ * @skb points to skb to decode.
++ * @secid points to the flow key secid to set.
++ * @ckall says if all xfrms used should be checked for same secid.
++ * Return 0 if ckall is zero or all xfrms used have the same secid.
+ *
+ * Security hooks affecting all Key Management operations
+ *
+@@ -1308,8 +1343,8 @@ struct security_operations {
+ int (*unix_may_send) (struct socket * sock, struct socket * other);
+
+ int (*socket_create) (int family, int type, int protocol, int kern);
+- void (*socket_post_create) (struct socket * sock, int family,
+- int type, int protocol, int kern);
++ int (*socket_post_create) (struct socket * sock, int family,
++ int type, int protocol, int kern);
+ int (*socket_bind) (struct socket * sock,
+ struct sockaddr * address, int addrlen);
+ int (*socket_connect) (struct socket * sock,
+@@ -1332,18 +1367,32 @@ struct security_operations {
+ int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
+ int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
+ void (*sk_free_security) (struct sock *sk);
+- unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir);
++ void (*sk_clone_security) (const struct sock *sk, struct sock *newsk);
++ void (*sk_getsecid) (struct sock *sk, u32 *secid);
++ void (*sock_graft)(struct sock* sk, struct socket *parent);
++ int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb,
++ struct request_sock *req);
++ void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req);
++ void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl);
+ #endif /* CONFIG_SECURITY_NETWORK */
+
+ #ifdef CONFIG_SECURITY_NETWORK_XFRM
+- int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx);
++ int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp,
++ struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk);
+ int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new);
+ void (*xfrm_policy_free_security) (struct xfrm_policy *xp);
+ int (*xfrm_policy_delete_security) (struct xfrm_policy *xp);
+- int (*xfrm_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx);
++ int (*xfrm_state_alloc_security) (struct xfrm_state *x,
++ struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *polsec,
++ u32 secid);
+ void (*xfrm_state_free_security) (struct xfrm_state *x);
+ int (*xfrm_state_delete_security) (struct xfrm_state *x);
+- int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 sk_sid, u8 dir);
++ int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir);
++ int (*xfrm_state_pol_flow_match)(struct xfrm_state *x,
++ struct xfrm_policy *xp, struct flowi *fl);
++ int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm,
++ struct xfrm_policy *xp);
++ int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall);
+ #endif /* CONFIG_SECURITY_NETWORK_XFRM */
+
+ /* key management security hooks */
+@@ -1549,6 +1598,7 @@ static inline void security_sb_post_pivo
+
+ static inline int security_inode_alloc (struct inode *inode)
+ {
++ inode->i_security = NULL;
+ return security_ops->inode_alloc_security (inode);
+ }
+
+@@ -2778,13 +2828,13 @@ static inline int security_socket_create
+ return security_ops->socket_create(family, type, protocol, kern);
+ }
+
+-static inline void security_socket_post_create(struct socket * sock,
+- int family,
+- int type,
+- int protocol, int kern)
++static inline int security_socket_post_create(struct socket * sock,
++ int family,
++ int type,
++ int protocol, int kern)
+ {
+- security_ops->socket_post_create(sock, family, type,
+- protocol, kern);
++ return security_ops->socket_post_create(sock, family, type,
++ protocol, kern);
+ }
+
+ static inline int security_socket_bind(struct socket * sock,
+@@ -2885,9 +2935,36 @@ static inline void security_sk_free(stru
+ return security_ops->sk_free_security(sk);
+ }
+
+-static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir)
++static inline void security_sk_clone(const struct sock *sk, struct sock *newsk)
++{
++ return security_ops->sk_clone_security(sk, newsk);
++}
++
++static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
++{
++ security_ops->sk_getsecid(sk, &fl->secid);
++}
++
++static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl)
++{
++ security_ops->req_classify_flow(req, fl);
++}
++
++static inline void security_sock_graft(struct sock* sk, struct socket *parent)
++{
++ security_ops->sock_graft(sk, parent);
++}
++
++static inline int security_inet_conn_request(struct sock *sk,
++ struct sk_buff *skb, struct request_sock *req)
++{
++ return security_ops->inet_conn_request(sk, skb, req);
++}
++
++static inline void security_inet_csk_clone(struct sock *newsk,
++ const struct request_sock *req)
+ {
+- return security_ops->sk_getsid(sk, fl, dir);
++ security_ops->inet_csk_clone(newsk, req);
+ }
+ #else /* CONFIG_SECURITY_NETWORK */
+ static inline int security_unix_stream_connect(struct socket * sock,
+@@ -2909,11 +2986,12 @@ static inline int security_socket_create
+ return 0;
+ }
+
+-static inline void security_socket_post_create(struct socket * sock,
+- int family,
+- int type,
+- int protocol, int kern)
++static inline int security_socket_post_create(struct socket * sock,
++ int family,
++ int type,
++ int protocol, int kern)
+ {
++ return 0;
+ }
+
+ static inline int security_socket_bind(struct socket * sock,
+@@ -3011,16 +3089,38 @@ static inline void security_sk_free(stru
+ {
+ }
+
+-static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir)
++static inline void security_sk_clone(const struct sock *sk, struct sock *newsk)
++{
++}
++
++static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
++{
++}
++
++static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl)
++{
++}
++
++static inline void security_sock_graft(struct sock* sk, struct socket *parent)
++{
++}
++
++static inline int security_inet_conn_request(struct sock *sk,
++ struct sk_buff *skb, struct request_sock *req)
+ {
+ return 0;
+ }
++
++static inline void security_inet_csk_clone(struct sock *newsk,
++ const struct request_sock *req)
++{
++}
+ #endif /* CONFIG_SECURITY_NETWORK */
+
+ #ifdef CONFIG_SECURITY_NETWORK_XFRM
+ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx)
+ {
+- return security_ops->xfrm_policy_alloc_security(xp, sec_ctx);
++ return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL);
+ }
+
+ static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
+@@ -3038,9 +3138,18 @@ static inline int security_xfrm_policy_d
+ return security_ops->xfrm_policy_delete_security(xp);
+ }
+
+-static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx)
++static inline int security_xfrm_state_alloc(struct xfrm_state *x,
++ struct xfrm_user_sec_ctx *sec_ctx)
+ {
+- return security_ops->xfrm_state_alloc_security(x, sec_ctx);
++ return security_ops->xfrm_state_alloc_security(x, sec_ctx, NULL, 0);
++}
++
++static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
++ struct xfrm_sec_ctx *polsec, u32 secid)
++{
++ if (!polsec)
++ return 0;
++ return security_ops->xfrm_state_alloc_security(x, NULL, polsec, secid);
+ }
+
+ static inline int security_xfrm_state_delete(struct xfrm_state *x)
+@@ -3053,9 +3162,33 @@ static inline void security_xfrm_state_f
+ security_ops->xfrm_state_free_security(x);
+ }
+
+-static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
++static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
++{
++ return security_ops->xfrm_policy_lookup(xp, fl_secid, dir);
++}
++
++static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
++ struct xfrm_policy *xp, struct flowi *fl)
++{
++ return security_ops->xfrm_state_pol_flow_match(x, xp, fl);
++}
++
++static inline int security_xfrm_flow_state_match(struct flowi *fl,
++ struct xfrm_state *xfrm, struct xfrm_policy *xp)
+ {
+- return security_ops->xfrm_policy_lookup(xp, sk_sid, dir);
++ return security_ops->xfrm_flow_state_match(fl, xfrm, xp);
++}
++
++static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
++{
++ return security_ops->xfrm_decode_session(skb, secid, 1);
++}
++
++static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl)
++{
++ int rc = security_ops->xfrm_decode_session(skb, &fl->secid, 0);
++
++ BUG_ON(rc);
+ }
+ #else /* CONFIG_SECURITY_NETWORK_XFRM */
+ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx)
+@@ -3077,7 +3210,14 @@ static inline int security_xfrm_policy_d
+ return 0;
+ }
+
+-static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx)
++static inline int security_xfrm_state_alloc(struct xfrm_state *x,
++ struct xfrm_user_sec_ctx *sec_ctx)
++{
++ return 0;
++}
++
++static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
++ struct xfrm_sec_ctx *polsec, u32 secid)
+ {
+ return 0;
+ }
+@@ -3091,10 +3231,32 @@ static inline int security_xfrm_state_de
+ return 0;
+ }
+
+-static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
++static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
+ {
+ return 0;
+ }
++
++static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
++ struct xfrm_policy *xp, struct flowi *fl)
++{
++ return 1;
++}
++
++static inline int security_xfrm_flow_state_match(struct flowi *fl,
++ struct xfrm_state *xfrm, struct xfrm_policy *xp)
++{
++ return 1;
++}
++
++static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
++{
++ return 0;
++}
++
++static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl)
++{
++}
++
+ #endif /* CONFIG_SECURITY_NETWORK_XFRM */
+
+ #ifdef CONFIG_KEYS
+diff --git a/include/linux/selinux.h b/include/linux/selinux.h
+index aad4e39..d1b7ca6 100644
+--- a/include/linux/selinux.h
++++ b/include/linux/selinux.h
+@@ -46,7 +46,7 @@ void selinux_audit_rule_free(struct seli
+
+ /**
+ * selinux_audit_rule_match - determine if a context ID matches a rule.
+- * @ctxid: the context ID to check
++ * @sid: the context ID to check
+ * @field: the field this rule refers to
+ * @op: the operater the rule uses
+ * @rule: pointer to the audit rule to check against
+@@ -55,7 +55,7 @@ void selinux_audit_rule_free(struct seli
+ * Returns 1 if the context id matches the rule, 0 if it does not, and
+ * -errno on failure.
+ */
+-int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
++int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
+ struct selinux_audit_rule *rule,
+ struct audit_context *actx);
+
+@@ -70,18 +70,8 @@ int selinux_audit_rule_match(u32 ctxid,
+ void selinux_audit_set_callback(int (*callback)(void));
+
+ /**
+- * selinux_task_ctxid - determine a context ID for a process.
+- * @tsk: the task object
+- * @ctxid: ID value returned via this
+- *
+- * On return, ctxid will contain an ID for the context. This value
+- * should only be used opaquely.
+- */
+-void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid);
+-
+-/**
+- * selinux_ctxid_to_string - map a security context ID to a string
+- * @ctxid: security context ID to be converted.
++ * selinux_sid_to_string - map a security context ID to a string
++ * @sid: security context ID to be converted.
+ * @ctx: address of context string to be returned
+ * @ctxlen: length of returned context string.
+ *
+@@ -89,7 +79,7 @@ void selinux_task_ctxid(struct task_stru
+ * string will be allocated internally, and the caller must call
+ * kfree() on it after use.
+ */
+-int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen);
++int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen);
+
+ /**
+ * selinux_get_inode_sid - get the inode's security context ID
+@@ -154,7 +144,7 @@ static inline void selinux_audit_rule_fr
+ return;
+ }
+
+-static inline int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
++static inline int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
+ struct selinux_audit_rule *rule,
+ struct audit_context *actx)
+ {
+@@ -166,12 +156,7 @@ static inline void selinux_audit_set_cal
+ return;
+ }
+
+-static inline void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+-{
+- *ctxid = 0;
+-}
+-
+-static inline int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen)
++static inline int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
+ {
+ *ctx = NULL;
+ *ctxlen = 0;
+diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
+index 86501a3..463ab95 100644
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -67,8 +67,8 @@
+ /* Parisc type numbers. */
+ #define PORT_MUX 48
+
+-/* Atmel AT91xxx SoC */
+-#define PORT_AT91 49
++/* Atmel AT91 / AT32 SoC */
++#define PORT_ATMEL 49
+
+ /* Macintosh Zilog type numbers */
+ #define PORT_MAC_ZILOG 50 /* m68k : not yet implemented */
+@@ -319,6 +319,7 @@ struct uart_info {
+ #define UIF_CTS_FLOW ((__force uif_t) (1 << 26))
+ #define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29))
+ #define UIF_INITIALIZED ((__force uif_t) (1 << 31))
++#define UIF_SUSPENDED ((__force uif_t) (1 << 30))
+
+ int blocked_open;
+
+@@ -408,13 +409,12 @@ int uart_resume_port(struct uart_driver
+ * The following are helper functions for the low level drivers.
+ */
+ static inline int
+-uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
+- struct pt_regs *regs)
++uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
+ {
+ #ifdef SUPPORT_SYSRQ
+ if (port->sysrq) {
+ if (ch && time_before(jiffies, port->sysrq)) {
+- handle_sysrq(ch, regs, NULL);
++ handle_sysrq(ch, port->info->tty);
+ port->sysrq = 0;
+ return 1;
+ }
+@@ -424,7 +424,7 @@ uart_handle_sysrq_char(struct uart_port
+ return 0;
+ }
+ #ifndef SUPPORT_SYSRQ
+-#define uart_handle_sysrq_char(port,ch,regs) uart_handle_sysrq_char(port, 0, NULL)
++#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0)
+ #endif
+
+ /*
+diff --git a/include/linux/serio.h b/include/linux/serio.h
+index 6348e83..b99c5ca 100644
+--- a/include/linux/serio.h
++++ b/include/linux/serio.h
+@@ -41,6 +41,7 @@ struct serio {
+ void (*stop)(struct serio *);
+
+ struct serio *parent, *child;
++ unsigned int depth; /* level of nesting in serio hierarchy */
+
+ struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */
+ struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */
+@@ -60,8 +61,7 @@ struct serio_driver {
+ unsigned int manual_bind;
+
+ void (*write_wakeup)(struct serio *);
+- irqreturn_t (*interrupt)(struct serio *, unsigned char,
+- unsigned int, struct pt_regs *);
++ irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int);
+ int (*connect)(struct serio *, struct serio_driver *drv);
+ int (*reconnect)(struct serio *);
+ void (*disconnect)(struct serio *);
+@@ -75,7 +75,7 @@ int serio_open(struct serio *serio, stru
+ void serio_close(struct serio *serio);
+ void serio_rescan(struct serio *serio);
+ void serio_reconnect(struct serio *serio);
+-irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
++irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags);
+
+ void __serio_register_port(struct serio *serio, struct module *owner);
+ static inline void serio_register_port(struct serio *serio)
+@@ -217,5 +217,8 @@ static inline void serio_unpin_driver(st
+ #define SERIO_LKKBD 0x28
+ #define SERIO_ELO 0x29
+ #define SERIO_MICROTOUCH 0x30
++#define SERIO_PENMOUNT 0x31
++#define SERIO_TOUCHRIGHT 0x32
++#define SERIO_TOUCHWIN 0x33
+
+ #endif
+diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
+index c057f0b..f3c5189 100644
+--- a/include/linux/shmem_fs.h
++++ b/include/linux/shmem_fs.h
+@@ -19,6 +19,10 @@ struct shmem_inode_info {
+ swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
+ struct list_head swaplist; /* chain of maybes on swap */
+ struct inode vfs_inode;
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ struct posix_acl *i_acl;
++ struct posix_acl *i_default_acl;
++#endif
+ };
+
+ struct shmem_sb_info {
+@@ -36,4 +40,24 @@ static inline struct shmem_inode_info *S
+ return container_of(inode, struct shmem_inode_info, vfs_inode);
+ }
+
++#ifdef CONFIG_TMPFS_POSIX_ACL
++int shmem_permission(struct inode *, int, struct nameidata *);
++int shmem_acl_init(struct inode *, struct inode *);
++void shmem_acl_destroy_inode(struct inode *);
++
++extern struct xattr_handler shmem_xattr_acl_access_handler;
++extern struct xattr_handler shmem_xattr_acl_default_handler;
++
++extern struct generic_acl_operations shmem_acl_ops;
++
++#else
++static inline int shmem_acl_init(struct inode *inode, struct inode *dir)
++{
++ return 0;
++}
++static inline void shmem_acl_destroy_inode(struct inode *inode)
++{
++}
++#endif /* CONFIG_TMPFS_POSIX_ACL */
++
+ #endif
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 755e9cd..85577a4 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -34,8 +34,9 @@
+ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */
+
+ #define CHECKSUM_NONE 0
+-#define CHECKSUM_HW 1
++#define CHECKSUM_PARTIAL 1
+ #define CHECKSUM_UNNECESSARY 2
++#define CHECKSUM_COMPLETE 3
+
+ #define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \
+ ~(SMP_CACHE_BYTES - 1))
+@@ -56,17 +57,17 @@
+ * Apparently with secret goal to sell you new device, when you
+ * will add new protocol to your host. F.e. IPv6. 8)
+ *
+- * HW: the most generic way. Device supplied checksum of _all_
++ * COMPLETE: the most generic way. Device supplied checksum of _all_
+ * the packet as seen by netif_rx in skb->csum.
+ * NOTE: Even if device supports only some protocols, but
+- * is able to produce some skb->csum, it MUST use HW,
++ * is able to produce some skb->csum, it MUST use COMPLETE,
+ * not UNNECESSARY.
+ *
+ * B. Checksumming on output.
+ *
+ * NONE: skb is checksummed by protocol or csum is not required.
+ *
+- * HW: device is required to csum packet as seen by hard_start_xmit
++ * PARTIAL: device is required to csum packet as seen by hard_start_xmit
+ * from skb->h.raw to the end and to record the checksum
+ * at skb->h.raw+skb->csum.
+ *
+@@ -1261,14 +1262,14 @@ static inline int skb_linearize_cow(stru
+ * @len: length of data pulled
+ *
+ * After doing a pull on a received packet, you need to call this to
+- * update the CHECKSUM_HW checksum, or set ip_summed to CHECKSUM_NONE
+- * so that it can be recomputed from scratch.
++ * update the CHECKSUM_COMPLETE checksum, or set ip_summed to
++ * CHECKSUM_NONE so that it can be recomputed from scratch.
+ */
+
+ static inline void skb_postpull_rcsum(struct sk_buff *skb,
+ const void *start, unsigned int len)
+ {
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0));
+ }
+
+@@ -1287,7 +1288,7 @@ static inline int pskb_trim_rcsum(struct
+ {
+ if (likely(len >= skb->len))
+ return 0;
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_NONE;
+ return __pskb_trim(skb, len);
+ }
+diff --git a/include/linux/slab.h b/include/linux/slab.h
+index 45ad55b..c4947b8 100644
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/mm/slab.h
++ * linux/include/linux/slab.h
+ * Written by Mark Hemment, 1996.
+ * (markhe at nextd.demon.co.uk)
+ */
+@@ -60,14 +60,13 @@ extern void __init kmem_cache_init(void)
+ extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
+ void (*)(void *, kmem_cache_t *, unsigned long),
+ void (*)(void *, kmem_cache_t *, unsigned long));
+-extern int kmem_cache_destroy(kmem_cache_t *);
++extern void kmem_cache_destroy(kmem_cache_t *);
+ extern int kmem_cache_shrink(kmem_cache_t *);
+ extern void *kmem_cache_alloc(kmem_cache_t *, gfp_t);
+ extern void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
+ 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, gfp_t gfpflags);
+
+ /* Size description struct for general caches. */
+ struct cache_sizes {
+@@ -78,13 +77,6 @@ struct cache_sizes {
+ extern struct cache_sizes malloc_sizes[];
+
+ extern void *__kmalloc(size_t, gfp_t);
+-#ifndef CONFIG_DEBUG_SLAB
+-#define ____kmalloc(size, flags) __kmalloc(size, flags)
+-#else
+-extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
+-#define ____kmalloc(size, flags) \
+- __kmalloc_track_caller(size, flags, __builtin_return_address(0))
+-#endif
+
+ /**
+ * kmalloc - allocate memory
+@@ -154,6 +146,23 @@ found:
+ return __kmalloc(size, flags);
+ }
+
++/*
++ * kmalloc_track_caller is a special version of kmalloc that records the
++ * calling function of the routine calling it for slab leak tracking instead
++ * of just the calling function (confusing, eh?).
++ * It's useful when the call to kmalloc comes from a widely-used standard
++ * allocator where we care about the real place the memory allocation
++ * request comes from.
++ */
++#ifndef CONFIG_DEBUG_SLAB
++#define kmalloc_track_caller(size, flags) \
++ __kmalloc(size, flags)
++#else
++extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
++#define kmalloc_track_caller(size, flags) \
++ __kmalloc_track_caller(size, flags, __builtin_return_address(0))
++#endif
++
+ extern void *__kzalloc(size_t, gfp_t);
+
+ /**
+@@ -203,7 +212,30 @@ extern int slab_is_available(void);
+
+ #ifdef CONFIG_NUMA
+ extern void *kmem_cache_alloc_node(kmem_cache_t *, gfp_t flags, int node);
+-extern void *kmalloc_node(size_t size, gfp_t flags, int node);
++extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
++
++static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
++{
++ if (__builtin_constant_p(size)) {
++ int i = 0;
++#define CACHE(x) \
++ if (size <= x) \
++ goto found; \
++ else \
++ i++;
++#include "kmalloc_sizes.h"
++#undef CACHE
++ {
++ extern void __you_cannot_kmalloc_that_much(void);
++ __you_cannot_kmalloc_that_much();
++ }
++found:
++ return kmem_cache_alloc_node((flags & GFP_DMA) ?
++ malloc_sizes[i].cs_dmacachep :
++ malloc_sizes[i].cs_cachep, flags, node);
++ }
++ return __kmalloc_node(size, flags, node);
++}
+ #else
+ static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int node)
+ {
+@@ -223,12 +255,11 @@ extern int FASTCALL(kmem_ptr_validate(km
+ /* SLOB allocator routines */
+
+ void kmem_cache_init(void);
+-struct kmem_cache *kmem_find_general_cachep(size_t, gfp_t gfpflags);
+ struct kmem_cache *kmem_cache_create(const char *c, size_t, size_t,
+ unsigned long,
+ void (*)(void *, struct kmem_cache *, unsigned long),
+ void (*)(void *, struct kmem_cache *, unsigned long));
+-int kmem_cache_destroy(struct kmem_cache *c);
++void kmem_cache_destroy(struct kmem_cache *c);
+ void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags);
+ void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
+ void kmem_cache_free(struct kmem_cache *c, void *b);
+@@ -250,7 +281,7 @@ static inline void *kcalloc(size_t n, si
+ #define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f)
+ #define kmalloc_node(s, f, n) kmalloc(s, f)
+ #define kzalloc(s, f) __kzalloc(s, f)
+-#define ____kmalloc kmalloc
++#define kmalloc_track_caller kmalloc
+
+ #endif /* CONFIG_SLOB */
+
+@@ -263,8 +294,6 @@ extern kmem_cache_t *fs_cachep;
+ extern kmem_cache_t *sighand_cachep;
+ extern kmem_cache_t *bio_cachep;
+
+-extern atomic_t slab_reclaim_pages;
+-
+ #endif /* __KERNEL__ */
+
+ #endif /* _LINUX_SLAB_H */
+diff --git a/include/linux/smb.h b/include/linux/smb.h
+index b016220..f098dff 100644
+--- a/include/linux/smb.h
++++ b/include/linux/smb.h
+@@ -10,6 +10,7 @@
+ #define _LINUX_SMB_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
+
+ enum smb_protocol {
+ SMB_PROTOCOL_NONE,
+@@ -88,7 +89,6 @@ struct smb_fattr {
+ struct timespec f_atime;
+ struct timespec f_mtime;
+ struct timespec f_ctime;
+- unsigned long f_blksize;
+ unsigned long f_blocks;
+ int f_unix;
+ };
+@@ -101,8 +101,6 @@ enum smb_conn_state {
+ CONN_RETRYING /* Currently trying to reconnect */
+ };
+
+-#define SMB_SUPER_MAGIC 0x517B
+-
+ #define SMB_HEADER_LEN 37 /* includes everything up to, but not
+ * including smb_bcc */
+
+diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
+index 367d6c3..13b3af5 100644
+--- a/include/linux/smb_fs.h
++++ b/include/linux/smb_fs.h
+@@ -43,17 +43,17 @@ static inline struct smb_inode_info *SMB
+
+ /* macro names are short for word, double-word, long value (?) */
+ #define WVAL(buf,pos) \
+- (le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos)))))
++ (le16_to_cpu(get_unaligned((__le16 *)((u8 *)(buf) + (pos)))))
+ #define DVAL(buf,pos) \
+- (le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos)))))
++ (le32_to_cpu(get_unaligned((__le32 *)((u8 *)(buf) + (pos)))))
+ #define LVAL(buf,pos) \
+- (le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos)))))
++ (le64_to_cpu(get_unaligned((__le64 *)((u8 *)(buf) + (pos)))))
+ #define WSET(buf,pos,val) \
+- put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos)))
++ put_unaligned(cpu_to_le16((u16)(val)), (__le16 *)((u8 *)(buf) + (pos)))
+ #define DSET(buf,pos,val) \
+- put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos)))
++ put_unaligned(cpu_to_le32((u32)(val)), (__le32 *)((u8 *)(buf) + (pos)))
+ #define LSET(buf,pos,val) \
+- put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos)))
++ put_unaligned(cpu_to_le64((u64)(val)), (__le64 *)((u8 *)(buf) + (pos)))
+
+ /* where to find the base of the SMB packet proper */
+ #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
+diff --git a/include/linux/smp.h b/include/linux/smp.h
+index 837e8bc..5164998 100644
+--- a/include/linux/smp.h
++++ b/include/linux/smp.h
+@@ -53,6 +53,9 @@ extern void smp_cpus_done(unsigned int m
+ */
+ int smp_call_function(void(*func)(void *info), void *info, int retry, int wait);
+
++int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
++ int retry, int wait);
++
+ /*
+ * Call a function on all processors
+ */
+diff --git a/include/linux/snmp.h b/include/linux/snmp.h
+index 4db25d5..854aa6b 100644
+--- a/include/linux/snmp.h
++++ b/include/linux/snmp.h
+@@ -155,42 +155,11 @@ enum
+ UDP_MIB_NOPORTS, /* NoPorts */
+ UDP_MIB_INERRORS, /* InErrors */
+ UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */
++ UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */
++ UDP_MIB_SNDBUFERRORS, /* SndbufErrors */
+ __UDP_MIB_MAX
+ };
+
+-/* sctp mib definitions */
+-/*
+- * draft-ietf-sigtran-sctp-mib-07.txt
+- */
+-enum
+-{
+- SCTP_MIB_NUM = 0,
+- SCTP_MIB_CURRESTAB, /* CurrEstab */
+- SCTP_MIB_ACTIVEESTABS, /* ActiveEstabs */
+- SCTP_MIB_PASSIVEESTABS, /* PassiveEstabs */
+- SCTP_MIB_ABORTEDS, /* Aborteds */
+- SCTP_MIB_SHUTDOWNS, /* Shutdowns */
+- SCTP_MIB_OUTOFBLUES, /* OutOfBlues */
+- SCTP_MIB_CHECKSUMERRORS, /* ChecksumErrors */
+- SCTP_MIB_OUTCTRLCHUNKS, /* OutCtrlChunks */
+- SCTP_MIB_OUTORDERCHUNKS, /* OutOrderChunks */
+- SCTP_MIB_OUTUNORDERCHUNKS, /* OutUnorderChunks */
+- SCTP_MIB_INCTRLCHUNKS, /* InCtrlChunks */
+- SCTP_MIB_INORDERCHUNKS, /* InOrderChunks */
+- SCTP_MIB_INUNORDERCHUNKS, /* InUnorderChunks */
+- SCTP_MIB_FRAGUSRMSGS, /* FragUsrMsgs */
+- SCTP_MIB_REASMUSRMSGS, /* ReasmUsrMsgs */
+- SCTP_MIB_OUTSCTPPACKS, /* OutSCTPPacks */
+- SCTP_MIB_INSCTPPACKS, /* InSCTPPacks */
+- SCTP_MIB_RTOALGORITHM, /* RtoAlgorithm */
+- SCTP_MIB_RTOMIN, /* RtoMin */
+- SCTP_MIB_RTOMAX, /* RtoMax */
+- SCTP_MIB_RTOINITIAL, /* RtoInitial */
+- SCTP_MIB_VALCOOKIELIFE, /* ValCookieLife */
+- SCTP_MIB_MAXINITRETR, /* MaxInitRetr */
+- __SCTP_MIB_MAX
+-};
+-
+ /* linux mib definitions */
+ enum
+ {
+diff --git a/include/linux/sound.h b/include/linux/sound.h
+index f63d834..9e2a94f 100644
+--- a/include/linux/sound.h
++++ b/include/linux/sound.h
+@@ -35,10 +35,8 @@ extern int register_sound_special_device
+ extern int register_sound_mixer(const struct file_operations *fops, int dev);
+ extern int register_sound_midi(const struct file_operations *fops, int dev);
+ extern int register_sound_dsp(const struct file_operations *fops, int dev);
+-extern int register_sound_synth(const struct file_operations *fops, int dev);
+
+ extern void unregister_sound_special(int unit);
+ extern void unregister_sound_mixer(int unit);
+ extern void unregister_sound_midi(int unit);
+ extern void unregister_sound_dsp(int unit);
+-extern void unregister_sound_synth(int unit);
+diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
+index 31473db..b800d2d 100644
+--- a/include/linux/spinlock.h
++++ b/include/linux/spinlock.h
+@@ -167,9 +167,9 @@ do { \
+ * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
+ * methods are defined as nops in the case they are not required.
+ */
+-#define spin_trylock(lock) __cond_lock(_spin_trylock(lock))
+-#define read_trylock(lock) __cond_lock(_read_trylock(lock))
+-#define write_trylock(lock) __cond_lock(_write_trylock(lock))
++#define spin_trylock(lock) __cond_lock(lock, _spin_trylock(lock))
++#define read_trylock(lock) __cond_lock(lock, _read_trylock(lock))
++#define write_trylock(lock) __cond_lock(lock, _write_trylock(lock))
+
+ #define spin_lock(lock) _spin_lock(lock)
+
+@@ -236,19 +236,19 @@ do { \
+ _write_unlock_irqrestore(lock, flags)
+ #define write_unlock_bh(lock) _write_unlock_bh(lock)
+
+-#define spin_trylock_bh(lock) __cond_lock(_spin_trylock_bh(lock))
++#define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock))
+
+ #define spin_trylock_irq(lock) \
+ ({ \
+ local_irq_disable(); \
+- _spin_trylock(lock) ? \
++ spin_trylock(lock) ? \
+ 1 : ({ local_irq_enable(); 0; }); \
+ })
+
+ #define spin_trylock_irqsave(lock, flags) \
+ ({ \
+ local_irq_save(flags); \
+- _spin_trylock(lock) ? \
++ spin_trylock(lock) ? \
+ 1 : ({ local_irq_restore(flags); 0; }); \
+ })
+
+@@ -264,7 +264,7 @@ do { \
+ */
+ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
+ #define atomic_dec_and_lock(atomic, lock) \
+- __cond_lock(_atomic_dec_and_lock(atomic, lock))
++ __cond_lock(lock, _atomic_dec_and_lock(atomic, lock))
+
+ /**
+ * spin_can_lock - would spin_trylock() succeed?
+diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h
+index b2c4f82..8828b81 100644
+--- a/include/linux/spinlock_api_smp.h
++++ b/include/linux/spinlock_api_smp.h
+@@ -19,41 +19,41 @@ int in_lock_functions(unsigned long addr
+
+ #define assert_spin_locked(x) BUG_ON(!spin_is_locked(x))
+
+-void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t);
++void __lockfunc _spin_lock(spinlock_t *lock) __acquires(lock);
+ void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
+- __acquires(spinlock_t);
+-void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t);
+-void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t);
+-void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t);
+-void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(rwlock_t);
+-void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(rwlock_t);
+-void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(spinlock_t);
+-void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(rwlock_t);
+-void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(rwlock_t);
++ __acquires(lock);
++void __lockfunc _read_lock(rwlock_t *lock) __acquires(lock);
++void __lockfunc _write_lock(rwlock_t *lock) __acquires(lock);
++void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(lock);
++void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(lock);
++void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(lock);
++void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(lock);
++void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(lock);
++void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock);
+ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
+- __acquires(spinlock_t);
++ __acquires(lock);
+ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
+- __acquires(rwlock_t);
++ __acquires(lock);
+ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
+- __acquires(rwlock_t);
++ __acquires(lock);
+ int __lockfunc _spin_trylock(spinlock_t *lock);
+ int __lockfunc _read_trylock(rwlock_t *lock);
+ int __lockfunc _write_trylock(rwlock_t *lock);
+ int __lockfunc _spin_trylock_bh(spinlock_t *lock);
+-void __lockfunc _spin_unlock(spinlock_t *lock) __releases(spinlock_t);
+-void __lockfunc _read_unlock(rwlock_t *lock) __releases(rwlock_t);
+-void __lockfunc _write_unlock(rwlock_t *lock) __releases(rwlock_t);
+-void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(spinlock_t);
+-void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(rwlock_t);
+-void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(rwlock_t);
+-void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(spinlock_t);
+-void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(rwlock_t);
+-void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(rwlock_t);
++void __lockfunc _spin_unlock(spinlock_t *lock) __releases(lock);
++void __lockfunc _read_unlock(rwlock_t *lock) __releases(lock);
++void __lockfunc _write_unlock(rwlock_t *lock) __releases(lock);
++void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(lock);
++void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(lock);
++void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(lock);
++void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(lock);
++void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(lock);
++void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(lock);
+ void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+- __releases(spinlock_t);
++ __releases(lock);
+ void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+- __releases(rwlock_t);
++ __releases(lock);
+ void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+- __releases(rwlock_t);
++ __releases(lock);
+
+ #endif /* __LINUX_SPINLOCK_API_SMP_H */
+diff --git a/include/linux/srcu.h b/include/linux/srcu.h
+new file mode 100644
+index 0000000..aca0eee
+--- /dev/null
++++ b/include/linux/srcu.h
+@@ -0,0 +1,53 @@
++/*
++ * Sleepable Read-Copy Update mechanism for mutual exclusion
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) IBM Corporation, 2006
++ *
++ * Author: Paul McKenney <paulmck at us.ibm.com>
++ *
++ * For detailed explanation of Read-Copy Update mechanism see -
++ * Documentation/RCU/ *.txt
++ *
++ */
++
++#ifndef _LINUX_SRCU_H
++#define _LINUX_SRCU_H
++
++struct srcu_struct_array {
++ int c[2];
++};
++
++struct srcu_struct {
++ int completed;
++ struct srcu_struct_array *per_cpu_ref;
++ struct mutex mutex;
++};
++
++#ifndef CONFIG_PREEMPT
++#define srcu_barrier() barrier()
++#else /* #ifndef CONFIG_PREEMPT */
++#define srcu_barrier()
++#endif /* #else #ifndef CONFIG_PREEMPT */
++
++int init_srcu_struct(struct srcu_struct *sp);
++void cleanup_srcu_struct(struct srcu_struct *sp);
++int srcu_read_lock(struct srcu_struct *sp) __acquires(sp);
++void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp);
++void synchronize_srcu(struct srcu_struct *sp);
++long srcu_batches_completed(struct srcu_struct *sp);
++
++#endif
+diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
+index 9cc81e5..50e2b01 100644
+--- a/include/linux/stacktrace.h
++++ b/include/linux/stacktrace.h
+@@ -5,15 +5,16 @@
+ struct stack_trace {
+ unsigned int nr_entries, max_entries;
+ unsigned long *entries;
++ int skip; /* input argument: How many entries to skip */
++ int all_contexts; /* input argument: if true do than one stack */
+ };
+
+ extern void save_stack_trace(struct stack_trace *trace,
+- struct task_struct *task, int all_contexts,
+- unsigned int skip);
++ struct task_struct *task);
+
+ extern void print_stack_trace(struct stack_trace *trace, int spaces);
+ #else
+-# define save_stack_trace(trace, task, all, skip) do { } while (0)
++# define save_stack_trace(trace, task) do { } while (0)
+ # define print_stack_trace(trace) do { } while (0)
+ #endif
+
+diff --git a/include/linux/stat.h b/include/linux/stat.h
+index 8669291..679ef0d 100644
+--- a/include/linux/stat.h
++++ b/include/linux/stat.h
+@@ -57,7 +57,7 @@
+ #include <linux/time.h>
+
+ struct kstat {
+- unsigned long ino;
++ u64 ino;
+ dev_t dev;
+ umode_t mode;
+ unsigned int nlink;
+diff --git a/include/linux/stddef.h b/include/linux/stddef.h
+index b3a2cad..6a40c76 100644
+--- a/include/linux/stddef.h
++++ b/include/linux/stddef.h
+@@ -10,11 +10,19 @@
+ #define NULL ((void *)0)
+ #endif
+
++#ifdef __KERNEL__
++
++enum {
++ false = 0,
++ true = 1
++};
++
+ #undef offsetof
+ #ifdef __compiler_offsetof
+ #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+ #else
+ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+ #endif
++#endif /* __KERNEL__ */
+
+ #endif
+diff --git a/include/linux/string.h b/include/linux/string.h
+index e4c7558..4f69ef9 100644
+--- a/include/linux/string.h
++++ b/include/linux/string.h
+@@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__
+ #endif
+
+ extern char *kstrdup(const char *s, gfp_t gfp);
++extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+
+ #ifdef __cplusplus
+ }
+diff --git a/include/linux/sunrpc/Kbuild b/include/linux/sunrpc/Kbuild
+index 0d1d768..fb438f1 100644
+--- a/include/linux/sunrpc/Kbuild
++++ b/include/linux/sunrpc/Kbuild
+@@ -1 +1 @@
+-unifdef-y := debug.h
++unifdef-y += debug.h
+diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
+index a6de332..534cdc7 100644
+--- a/include/linux/sunrpc/auth.h
++++ b/include/linux/sunrpc/auth.h
+@@ -20,9 +20,6 @@
+ /* size of the nodename buffer */
+ #define UNX_MAXNODENAME 32
+
+-/* Maximum size (in bytes) of an rpc credential or verifier */
+-#define RPC_MAX_AUTH_SIZE (400)
+-
+ /* Work around the lack of a VFS credential */
+ struct auth_cred {
+ uid_t uid;
+@@ -109,13 +106,13 @@ struct rpc_credops {
+ void (*crdestroy)(struct rpc_cred *);
+
+ int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
+- u32 * (*crmarshal)(struct rpc_task *, u32 *);
++ __be32 * (*crmarshal)(struct rpc_task *, __be32 *);
+ int (*crrefresh)(struct rpc_task *);
+- u32 * (*crvalidate)(struct rpc_task *, u32 *);
++ __be32 * (*crvalidate)(struct rpc_task *, __be32 *);
+ int (*crwrap_req)(struct rpc_task *, kxdrproc_t,
+- void *, u32 *, void *);
++ void *, __be32 *, void *);
+ int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t,
+- void *, u32 *, void *);
++ void *, __be32 *, void *);
+ };
+
+ extern struct rpc_authops authunix_ops;
+@@ -134,10 +131,10 @@ struct rpc_cred * rpcauth_bindcred(struc
+ void rpcauth_holdcred(struct rpc_task *);
+ void put_rpccred(struct rpc_cred *);
+ void rpcauth_unbindcred(struct rpc_task *);
+-u32 * rpcauth_marshcred(struct rpc_task *, u32 *);
+-u32 * rpcauth_checkverf(struct rpc_task *, u32 *);
+-int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj);
+-int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj);
++__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *);
++__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *);
++int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj);
++int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, __be32 *data, void *obj);
+ int rpcauth_refreshcred(struct rpc_task *);
+ void rpcauth_invalcred(struct rpc_task *);
+ int rpcauth_uptodatecred(struct rpc_task *);
+diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h
+index 03084dc..97b62e9 100644
+--- a/include/linux/sunrpc/auth_gss.h
++++ b/include/linux/sunrpc/auth_gss.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/linux/auth_gss.h
++ * linux/include/linux/sunrpc/auth_gss.h
+ *
+ * Declarations for RPCSEC_GSS
+ *
+diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
+index b5612c9..3699dff 100644
+--- a/include/linux/sunrpc/cache.h
++++ b/include/linux/sunrpc/cache.h
+@@ -163,6 +163,17 @@ static inline void cache_put(struct cach
+ kref_put(&h->ref, cd->cache_put);
+ }
+
++static inline int cache_valid(struct cache_head *h)
++{
++ /* If an item has been unhashed pending removal when
++ * the refcount drops to 0, the expiry_time will be
++ * set to 0. We don't want to consider such items
++ * valid in this context even though CACHE_VALID is
++ * set.
++ */
++ return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags));
++}
++
+ extern int cache_check(struct cache_detail *detail,
+ struct cache_head *h, struct cache_req *rqstp);
+ extern void cache_flush(void);
+diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
+index 8fe9f35..f6d1d64 100644
+--- a/include/linux/sunrpc/clnt.h
++++ b/include/linux/sunrpc/clnt.h
+@@ -18,18 +18,6 @@
+ #include <linux/sunrpc/timer.h>
+ #include <asm/signal.h>
+
+-/*
+- * This defines an RPC port mapping
+- */
+-struct rpc_portmap {
+- __u32 pm_prog;
+- __u32 pm_vers;
+- __u32 pm_prot;
+- __u16 pm_port;
+- unsigned char pm_binding : 1; /* doing a getport() */
+- struct rpc_wait_queue pm_bindwait; /* waiting on getport() */
+-};
+-
+ struct rpc_inode;
+
+ /*
+@@ -40,7 +28,9 @@ struct rpc_clnt {
+ atomic_t cl_users; /* number of references */
+ struct rpc_xprt * cl_xprt; /* transport */
+ struct rpc_procinfo * cl_procinfo; /* procedure info */
+- u32 cl_maxproc; /* max procedure number */
++ u32 cl_prog, /* RPC program number */
++ cl_vers, /* RPC version number */
++ cl_maxproc; /* max procedure number */
+
+ char * cl_server; /* server machine name */
+ char * cl_protname; /* protocol name */
+@@ -55,7 +45,6 @@ struct rpc_clnt {
+ cl_dead : 1;/* abandoned */
+
+ struct rpc_rtt * cl_rtt; /* RTO estimator data */
+- struct rpc_portmap * cl_pmap; /* port mapping */
+
+ int cl_nodelen; /* nodename length */
+ char cl_nodename[UNX_MAXNODENAME];
+@@ -64,14 +53,8 @@ struct rpc_clnt {
+ struct dentry * cl_dentry; /* inode */
+ struct rpc_clnt * cl_parent; /* Points to parent of clones */
+ struct rpc_rtt cl_rtt_default;
+- struct rpc_portmap cl_pmap_default;
+ char cl_inline_name[32];
+ };
+-#define cl_timeout cl_xprt->timeout
+-#define cl_prog cl_pmap->pm_prog
+-#define cl_vers cl_pmap->pm_vers
+-#define cl_port cl_pmap->pm_port
+-#define cl_prot cl_pmap->pm_prot
+
+ /*
+ * General RPC program info
+@@ -106,24 +89,36 @@ struct rpc_procinfo {
+ char * p_name; /* name of procedure */
+ };
+
+-#define RPC_CONGESTED(clnt) (RPCXPRT_CONGESTED((clnt)->cl_xprt))
+-#define RPC_PEERADDR(clnt) (&(clnt)->cl_xprt->addr)
+-
+ #ifdef __KERNEL__
+
+-struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
+- struct rpc_program *info,
+- u32 version, rpc_authflavor_t authflavor);
+-struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname,
+- struct rpc_program *info,
+- u32 version, rpc_authflavor_t authflavor);
++struct rpc_create_args {
++ int protocol;
++ struct sockaddr *address;
++ size_t addrsize;
++ struct rpc_timeout *timeout;
++ char *servername;
++ struct rpc_program *program;
++ u32 version;
++ rpc_authflavor_t authflavor;
++ unsigned long flags;
++};
++
++/* Values for "flags" field */
++#define RPC_CLNT_CREATE_HARDRTRY (1UL << 0)
++#define RPC_CLNT_CREATE_INTR (1UL << 1)
++#define RPC_CLNT_CREATE_AUTOBIND (1UL << 2)
++#define RPC_CLNT_CREATE_ONESHOT (1UL << 3)
++#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4)
++#define RPC_CLNT_CREATE_NOPING (1UL << 5)
++
++struct rpc_clnt *rpc_create(struct rpc_create_args *args);
+ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
+ struct rpc_program *, int);
+ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
+ int rpc_shutdown_client(struct rpc_clnt *);
+ int rpc_destroy_client(struct rpc_clnt *);
+ void rpc_release_client(struct rpc_clnt *);
+-void rpc_getport(struct rpc_task *, struct rpc_clnt *);
++void rpc_getport(struct rpc_task *);
+ int rpc_register(u32, u32, int, unsigned short, int *);
+
+ void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
+@@ -140,6 +135,8 @@ void rpc_setbufsize(struct rpc_clnt *,
+ size_t rpc_max_payload(struct rpc_clnt *);
+ void rpc_force_rebind(struct rpc_clnt *);
+ int rpc_ping(struct rpc_clnt *clnt, int flags);
++size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
++char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
+
+ /*
+ * Helper function for NFSroot support
+diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
+index 6e112cc..5eca9e4 100644
+--- a/include/linux/sunrpc/gss_api.h
++++ b/include/linux/sunrpc/gss_api.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/linux/gss_api.h
++ * linux/include/linux/sunrpc/gss_api.h
+ *
+ * Somewhat simplified version of the gss api.
+ *
+diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
+index 1279280..e30ba20 100644
+--- a/include/linux/sunrpc/gss_krb5.h
++++ b/include/linux/sunrpc/gss_krb5.h
+@@ -46,8 +46,8 @@ struct krb5_ctx {
+ unsigned char seed[16];
+ int signalg;
+ int sealalg;
+- struct crypto_tfm *enc;
+- struct crypto_tfm *seq;
++ struct crypto_blkcipher *enc;
++ struct crypto_blkcipher *seq;
+ s32 endtime;
+ u32 seq_send;
+ struct xdr_netobj mech_used;
+@@ -136,26 +136,27 @@ gss_unwrap_kerberos(struct gss_ctx *ctx_
+
+
+ u32
+-krb5_encrypt(struct crypto_tfm * key,
++krb5_encrypt(struct crypto_blkcipher *key,
+ void *iv, void *in, void *out, int length);
+
+ u32
+-krb5_decrypt(struct crypto_tfm * key,
++krb5_decrypt(struct crypto_blkcipher *key,
+ void *iv, void *in, void *out, int length);
+
+ int
+-gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *outbuf, int offset,
+- struct page **pages);
++gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *outbuf,
++ int offset, struct page **pages);
+
+ int
+-gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *inbuf, int offset);
++gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *inbuf,
++ int offset);
+
+ s32
+-krb5_make_seq_num(struct crypto_tfm * key,
++krb5_make_seq_num(struct crypto_blkcipher *key,
+ int direction,
+ s32 seqnum, unsigned char *cksum, unsigned char *buf);
+
+ s32
+-krb5_get_seq_num(struct crypto_tfm * key,
++krb5_get_seq_num(struct crypto_blkcipher *key,
+ unsigned char *cksum,
+ unsigned char *buf, int *direction, s32 * seqnum);
+diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h
+index 336e218..2cf3fbb 100644
+--- a/include/linux/sunrpc/gss_spkm3.h
++++ b/include/linux/sunrpc/gss_spkm3.h
+@@ -19,9 +19,9 @@ struct spkm3_ctx {
+ unsigned int req_flags ;
+ struct xdr_netobj share_key;
+ int conf_alg;
+- struct crypto_tfm* derived_conf_key;
++ struct crypto_blkcipher *derived_conf_key;
+ int intg_alg;
+- struct crypto_tfm* derived_integ_key;
++ struct crypto_blkcipher *derived_integ_key;
+ int keyestb_alg; /* alg used to get share_key */
+ int owf_alg; /* one way function */
+ };
+diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
+index f43f237..606cb21 100644
+--- a/include/linux/sunrpc/msg_prot.h
++++ b/include/linux/sunrpc/msg_prot.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/net/sunrpc/msg_prot.h
++ * linux/include/linux/sunrpc/msg_prot.h
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir at monad.swb.de>
+ */
+@@ -11,6 +11,9 @@
+
+ #define RPC_VERSION 2
+
++/* size of an XDR encoding unit in bytes, i.e. 32bit */
++#define XDR_UNIT (4)
++
+ /* spec defines authentication flavor as an unsigned 32 bit integer */
+ typedef u32 rpc_authflavor_t;
+
+@@ -34,6 +37,9 @@ enum rpc_auth_flavors {
+ RPC_AUTH_GSS_SPKMP = 390011,
+ };
+
++/* Maximum size (in bytes) of an rpc credential or verifier */
++#define RPC_MAX_AUTH_SIZE (400)
++
+ enum rpc_msg_type {
+ RPC_CALL = 0,
+ RPC_REPLY = 1
+@@ -50,7 +56,9 @@ enum rpc_accept_stat {
+ RPC_PROG_MISMATCH = 2,
+ RPC_PROC_UNAVAIL = 3,
+ RPC_GARBAGE_ARGS = 4,
+- RPC_SYSTEM_ERR = 5
++ RPC_SYSTEM_ERR = 5,
++ /* internal use only */
++ RPC_DROP_REPLY = 60000,
+ };
+
+ enum rpc_reject_stat {
+@@ -95,11 +103,45 @@ enum rpc_auth_stat {
+ * 2GB.
+ */
+
+-typedef u32 rpc_fraghdr;
++typedef __be32 rpc_fraghdr;
+
+ #define RPC_LAST_STREAM_FRAGMENT (1U << 31)
+ #define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT)
+ #define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1)
+
++/*
++ * RPC call and reply header size as number of 32bit words (verifier
++ * size computed separately, see below)
++ */
++#define RPC_CALLHDRSIZE (6)
++#define RPC_REPHDRSIZE (4)
++
++
++/*
++ * Maximum RPC header size, including authentication,
++ * as number of 32bit words (see RFCs 1831, 1832).
++ *
++ * xid 1 xdr unit = 4 bytes
++ * mtype 1
++ * rpc_version 1
++ * program 1
++ * prog_version 1
++ * procedure 1
++ * cred {
++ * flavor 1
++ * length 1
++ * body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
++ * }
++ * verf {
++ * flavor 1
++ * length 1
++ * body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
++ * }
++ * TOTAL 210 xdr units = 840 bytes
++ */
++#define RPC_MAX_HEADER_WITH_AUTH \
++ (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
++
++
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_SUNRPC_MSGPROT_H_ */
+diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
+index a481472..a2eb9b4 100644
+--- a/include/linux/sunrpc/rpc_pipe_fs.h
++++ b/include/linux/sunrpc/rpc_pipe_fs.h
+@@ -43,7 +43,7 @@ extern int rpc_queue_upcall(struct inode
+
+ extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
+ extern int rpc_rmdir(struct dentry *);
+-extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
++extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, struct rpc_pipe_ops *, int flags);
+ extern int rpc_unlink(struct dentry *);
+ extern struct vfsmount *rpc_get_mount(void);
+ extern void rpc_put_mount(void);
+diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
+index 82a91bb..f399c13 100644
+--- a/include/linux/sunrpc/sched.h
++++ b/include/linux/sunrpc/sched.h
+@@ -127,7 +127,6 @@ struct rpc_call_ops {
+ */
+ #define RPC_TASK_ASYNC 0x0001 /* is an async task */
+ #define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */
+-#define RPC_TASK_CHILD 0x0008 /* is child of other task */
+ #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */
+ #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */
+ #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
+@@ -136,7 +135,6 @@ struct rpc_call_ops {
+ #define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */
+
+ #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
+-#define RPC_IS_CHILD(t) ((t)->tk_flags & RPC_TASK_CHILD)
+ #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
+ #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
+ #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
+@@ -253,7 +251,6 @@ struct rpc_task *rpc_new_task(struct rpc
+ const struct rpc_call_ops *ops, void *data);
+ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
+ const struct rpc_call_ops *ops, void *data);
+-struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent);
+ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
+ int flags, const struct rpc_call_ops *ops,
+ void *data);
+@@ -261,8 +258,6 @@ void rpc_release_task(struct rpc_task *
+ void rpc_exit_task(struct rpc_task *);
+ void rpc_killall_tasks(struct rpc_clnt *);
+ int rpc_execute(struct rpc_task *);
+-void rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
+- rpc_action action);
+ void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
+ void rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
+ void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
+diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
+index 7b27c09..965d6c2 100644
+--- a/include/linux/sunrpc/svc.h
++++ b/include/linux/sunrpc/svc.h
+@@ -13,11 +13,36 @@
+ #include <linux/in.h>
+ #include <linux/sunrpc/types.h>
+ #include <linux/sunrpc/xdr.h>
++#include <linux/sunrpc/auth.h>
+ #include <linux/sunrpc/svcauth.h>
+ #include <linux/wait.h>
+ #include <linux/mm.h>
+
+ /*
++ * This is the RPC server thread function prototype
++ */
++typedef void (*svc_thread_fn)(struct svc_rqst *);
++
++/*
++ *
++ * RPC service thread pool.
++ *
++ * Pool of threads and temporary sockets. Generally there is only
++ * a single one of these per RPC service, but on NUMA machines those
++ * services that can benefit from it (i.e. nfs but not lockd) will
++ * have one pool per NUMA node. This optimisation reduces cross-
++ * node traffic on multi-node NUMA NFS servers.
++ */
++struct svc_pool {
++ unsigned int sp_id; /* pool id; also node id on NUMA */
++ spinlock_t sp_lock; /* protects all fields */
++ struct list_head sp_threads; /* idle server threads */
++ struct list_head sp_sockets; /* pending sockets */
++ unsigned int sp_nrthreads; /* # of threads in pool */
++ struct list_head sp_all_threads; /* all server threads */
++} ____cacheline_aligned_in_smp;
++
++/*
+ * RPC service.
+ *
+ * An RPC service is a ``daemon,'' possibly multithreaded, which
+@@ -28,28 +53,72 @@
+ * We currently do not support more than one RPC program per daemon.
+ */
+ struct svc_serv {
+- struct list_head sv_threads; /* idle server threads */
+- struct list_head sv_sockets; /* pending sockets */
+ struct svc_program * sv_program; /* RPC program */
+ struct svc_stat * sv_stats; /* RPC statistics */
+ spinlock_t sv_lock;
+ unsigned int sv_nrthreads; /* # of server threads */
+- unsigned int sv_bufsz; /* datagram buffer size */
++ unsigned int sv_max_payload; /* datagram payload size */
++ unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
+ unsigned int sv_xdrsize; /* XDR buffer size */
+
+ struct list_head sv_permsocks; /* all permanent sockets */
+ struct list_head sv_tempsocks; /* all temporary sockets */
+ int sv_tmpcnt; /* count of temporary sockets */
++ struct timer_list sv_temptimer; /* timer for aging temporary sockets */
+
+ char * sv_name; /* service name */
++
++ unsigned int sv_nrpools; /* number of thread pools */
++ struct svc_pool * sv_pools; /* array of thread pools */
++
++ void (*sv_shutdown)(struct svc_serv *serv);
++ /* Callback to use when last thread
++ * exits.
++ */
++
++ struct module * sv_module; /* optional module to count when
++ * adding threads */
++ svc_thread_fn sv_function; /* main function for threads */
++ int sv_kill_signal; /* signal to kill threads */
+ };
+
+ /*
++ * We use sv_nrthreads as a reference count. svc_destroy() drops
++ * this refcount, so we need to bump it up around operations that
++ * change the number of threads. Horrible, but there it is.
++ * Should be called with the BKL held.
++ */
++static inline void svc_get(struct svc_serv *serv)
++{
++ serv->sv_nrthreads++;
++}
++
++/*
+ * Maximum payload size supported by a kernel RPC server.
+ * This is use to determine the max number of pages nfsd is
+ * willing to return in a single READ operation.
++ *
++ * These happen to all be powers of 2, which is not strictly
++ * necessary but helps enforce the real limitation, which is
++ * that they should be multiples of PAGE_CACHE_SIZE.
++ *
++ * For UDP transports, a block plus NFS,RPC, and UDP headers
++ * has to fit into the IP datagram limit of 64K. The largest
++ * feasible number for all known page sizes is probably 48K,
++ * but we choose 32K here. This is the same as the historical
++ * Linux limit; someone who cares more about NFS/UDP performance
++ * can test a larger number.
++ *
++ * For TCP transports we have more freedom. A size of 1MB is
++ * chosen to match the client limit. Other OSes are known to
++ * have larger limits, but those numbers are probably beyond
++ * the point of diminishing returns.
+ */
+-#define RPCSVC_MAXPAYLOAD (64*1024u)
++#define RPCSVC_MAXPAYLOAD (1*1024*1024u)
++#define RPCSVC_MAXPAYLOAD_TCP RPCSVC_MAXPAYLOAD
++#define RPCSVC_MAXPAYLOAD_UDP (32*1024u)
++
++extern u32 svc_max_payload(const struct svc_rqst *rqstp);
+
+ /*
+ * RPC Requsts and replies are stored in one or more pages.
+@@ -78,43 +147,61 @@ struct svc_serv {
+ */
+ #define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2)
+
+-static inline u32 svc_getu32(struct kvec *iov)
++static inline u32 svc_getnl(struct kvec *iov)
++{
++ __be32 val, *vp;
++ vp = iov->iov_base;
++ val = *vp++;
++ iov->iov_base = (void*)vp;
++ iov->iov_len -= sizeof(__be32);
++ return ntohl(val);
++}
++
++static inline void svc_putnl(struct kvec *iov, u32 val)
++{
++ __be32 *vp = iov->iov_base + iov->iov_len;
++ *vp = htonl(val);
++ iov->iov_len += sizeof(__be32);
++}
++
++static inline __be32 svc_getu32(struct kvec *iov)
+ {
+- u32 val, *vp;
++ __be32 val, *vp;
+ vp = iov->iov_base;
+ val = *vp++;
+ iov->iov_base = (void*)vp;
+- iov->iov_len -= sizeof(u32);
++ iov->iov_len -= sizeof(__be32);
+ return val;
+ }
+
+ static inline void svc_ungetu32(struct kvec *iov)
+ {
+- u32 *vp = (u32 *)iov->iov_base;
++ __be32 *vp = (__be32 *)iov->iov_base;
+ iov->iov_base = (void *)(vp - 1);
+ iov->iov_len += sizeof(*vp);
+ }
+
+-static inline void svc_putu32(struct kvec *iov, u32 val)
++static inline void svc_putu32(struct kvec *iov, __be32 val)
+ {
+- u32 *vp = iov->iov_base + iov->iov_len;
++ __be32 *vp = iov->iov_base + iov->iov_len;
+ *vp = val;
+- iov->iov_len += sizeof(u32);
++ iov->iov_len += sizeof(__be32);
+ }
+
+
+ /*
+ * The context of a single thread, including the request currently being
+ * processed.
+- * NOTE: First two items must be prev/next.
+ */
+ struct svc_rqst {
+ struct list_head rq_list; /* idle list */
++ struct list_head rq_all; /* all threads list */
+ struct svc_sock * rq_sock; /* socket */
+ struct sockaddr_in rq_addr; /* peer address */
+ int rq_addrlen;
+
+ struct svc_serv * rq_server; /* RPC service definition */
++ struct svc_pool * rq_pool; /* thread pool */
+ struct svc_procedure * rq_procinfo; /* procedure info */
+ struct auth_ops * rq_authop; /* authentication flavour */
+ struct svc_cred rq_cred; /* auth info */
+@@ -123,14 +210,13 @@ struct svc_rqst {
+
+ struct xdr_buf rq_arg;
+ struct xdr_buf rq_res;
+- struct page * rq_argpages[RPCSVC_MAXPAGES];
+- struct page * rq_respages[RPCSVC_MAXPAGES];
+- int rq_restailpage;
+- short rq_argused; /* pages used for argument */
+- short rq_arghi; /* pages available in argument page list */
+- short rq_resused; /* pages used for result */
+-
+- u32 rq_xid; /* transmission id */
++ struct page * rq_pages[RPCSVC_MAXPAGES];
++ struct page * *rq_respages; /* points into rq_pages */
++ int rq_resused; /* number of pages used for result */
++
++ struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
++
++ __be32 rq_xid; /* transmission id */
+ u32 rq_prog; /* program number */
+ u32 rq_vers; /* program version */
+ u32 rq_proc; /* procedure number */
+@@ -139,7 +225,7 @@ struct svc_rqst {
+ rq_secure : 1; /* secure port */
+
+
+- __u32 rq_daddr; /* dest addr of request - reply from here */
++ __be32 rq_daddr; /* dest addr of request - reply from here */
+
+ void * rq_argp; /* decoded arguments */
+ void * rq_resp; /* xdr'd results */
+@@ -163,13 +249,14 @@ struct svc_rqst {
+ * to prevent encrypting page
+ * cache pages */
+ wait_queue_head_t rq_wait; /* synchronization */
++ struct task_struct *rq_task; /* service thread */
+ };
+
+ /*
+ * Check buffer bounds after decoding arguments
+ */
+ static inline int
+-xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
++xdr_argsize_check(struct svc_rqst *rqstp, __be32 *p)
+ {
+ char *cp = (char *)p;
+ struct kvec *vec = &rqstp->rq_arg.head[0];
+@@ -178,7 +265,7 @@ xdr_argsize_check(struct svc_rqst *rqstp
+ }
+
+ static inline int
+-xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
++xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p)
+ {
+ struct kvec *vec = &rqstp->rq_res.head[0];
+ char *cp = (char*)p;
+@@ -188,71 +275,26 @@ xdr_ressize_check(struct svc_rqst *rqstp
+ return vec->iov_len <= PAGE_SIZE;
+ }
+
+-static inline struct page *
+-svc_take_res_page(struct svc_rqst *rqstp)
+-{
+- if (rqstp->rq_arghi <= rqstp->rq_argused)
+- return NULL;
+- rqstp->rq_arghi--;
+- rqstp->rq_respages[rqstp->rq_resused] =
+- rqstp->rq_argpages[rqstp->rq_arghi];
+- return rqstp->rq_respages[rqstp->rq_resused++];
+-}
+-
+-static inline void svc_take_page(struct svc_rqst *rqstp)
+-{
+- if (rqstp->rq_arghi <= rqstp->rq_argused) {
+- WARN_ON(1);
+- return;
+- }
+- rqstp->rq_arghi--;
+- rqstp->rq_respages[rqstp->rq_resused] =
+- rqstp->rq_argpages[rqstp->rq_arghi];
+- rqstp->rq_resused++;
+-}
+-
+-static inline void svc_pushback_allpages(struct svc_rqst *rqstp)
+-{
+- while (rqstp->rq_resused) {
+- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
+- continue;
+- rqstp->rq_argpages[rqstp->rq_arghi++] =
+- rqstp->rq_respages[rqstp->rq_resused];
+- rqstp->rq_respages[rqstp->rq_resused] = NULL;
+- }
+-}
+-
+-static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp)
++static inline void svc_free_res_pages(struct svc_rqst *rqstp)
+ {
+- while (rqstp->rq_resused &&
+- rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) {
+-
+- if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
+- rqstp->rq_argpages[rqstp->rq_arghi++] =
+- rqstp->rq_respages[rqstp->rq_resused];
+- rqstp->rq_respages[rqstp->rq_resused] = NULL;
++ while (rqstp->rq_resused) {
++ struct page **pp = (rqstp->rq_respages +
++ --rqstp->rq_resused);
++ if (*pp) {
++ put_page(*pp);
++ *pp = NULL;
+ }
+ }
+ }
+
+-static inline void svc_free_allpages(struct svc_rqst *rqstp)
+-{
+- while (rqstp->rq_resused) {
+- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
+- continue;
+- put_page(rqstp->rq_respages[rqstp->rq_resused]);
+- rqstp->rq_respages[rqstp->rq_resused] = NULL;
+- }
+-}
+-
+ struct svc_deferred_req {
+ u32 prot; /* protocol (UDP or TCP) */
+ struct sockaddr_in addr;
+ struct svc_sock *svsk; /* where reply must go */
+- u32 daddr; /* where reply must come from */
++ __be32 daddr; /* where reply must come from */
+ struct cache_deferred_req handle;
+ int argslen;
+- u32 args[0];
++ __be32 args[0];
+ };
+
+ /*
+@@ -280,17 +322,20 @@ struct svc_version {
+ struct svc_procedure * vs_proc; /* per-procedure info */
+ u32 vs_xdrsize; /* xdrsize needed for this version */
+
++ unsigned int vs_hidden : 1; /* Don't register with portmapper.
++ * Only used for nfsacl so far. */
++
+ /* Override dispatch function (e.g. when caching replies).
+ * A return value of 0 means drop the request.
+ * vs_dispatch == NULL means use default dispatcher.
+ */
+- int (*vs_dispatch)(struct svc_rqst *, u32 *);
++ int (*vs_dispatch)(struct svc_rqst *, __be32 *);
+ };
+
+ /*
+ * RPC procedure info
+ */
+-typedef int (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
++typedef __be32 (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
+ struct svc_procedure {
+ svc_procfunc pc_func; /* process the request */
+ kxdrproc_t pc_decode; /* XDR decode args */
+@@ -304,20 +349,21 @@ struct svc_procedure {
+ };
+
+ /*
+- * This is the RPC server thread function prototype
+- */
+-typedef void (*svc_thread_fn)(struct svc_rqst *);
+-
+-/*
+ * Function prototypes.
+ */
+-struct svc_serv * svc_create(struct svc_program *, unsigned int);
++struct svc_serv * svc_create(struct svc_program *, unsigned int,
++ void (*shutdown)(struct svc_serv*));
+ int svc_create_thread(svc_thread_fn, struct svc_serv *);
+ void svc_exit_thread(struct svc_rqst *);
++struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
++ void (*shutdown)(struct svc_serv*),
++ svc_thread_fn, int sig, struct module *);
++int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
+ void svc_destroy(struct svc_serv *);
+-int svc_process(struct svc_serv *, struct svc_rqst *);
++int svc_process(struct svc_rqst *);
+ int svc_register(struct svc_serv *, int, unsigned short);
+ void svc_wake_up(struct svc_serv *);
+ void svc_reserve(struct svc_rqst *rqstp, int space);
++struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
+
+ #endif /* SUNRPC_SVC_H */
+diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
+index 2fe2087..de92619 100644
+--- a/include/linux/sunrpc/svcauth.h
++++ b/include/linux/sunrpc/svcauth.h
+@@ -95,7 +95,7 @@ struct auth_ops {
+ char * name;
+ struct module *owner;
+ int flavour;
+- int (*accept)(struct svc_rqst *rq, u32 *authp);
++ int (*accept)(struct svc_rqst *rq, __be32 *authp);
+ int (*release)(struct svc_rqst *rq);
+ void (*domain_release)(struct auth_domain *);
+ int (*set_client)(struct svc_rqst *rq);
+@@ -112,7 +112,7 @@ struct auth_ops {
+ #define SVC_COMPLETE 9
+
+
+-extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp);
++extern int svc_authenticate(struct svc_rqst *rqstp, __be32 *authp);
+ extern int svc_authorise(struct svc_rqst *rqstp);
+ extern int svc_set_client(struct svc_rqst *rqstp);
+ extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
+@@ -126,6 +126,7 @@ extern struct auth_domain *auth_domain_f
+ extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+ extern int auth_unix_forget_old(struct auth_domain *dom);
+ extern void svcauth_unix_purge(void);
++extern void svcauth_unix_info_release(void *);
+
+ static inline unsigned long hash_str(char *name, int bits)
+ {
+diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
+index 3a2206f..5a5db16 100644
+--- a/include/linux/sunrpc/svcauth_gss.h
++++ b/include/linux/sunrpc/svcauth_gss.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/include/linux/svcauth_gss.h
++ * linux/include/linux/sunrpc/svcauth_gss.h
+ *
+ * Bruce Fields <bfields at umich.edu>
+ * Copyright (c) 2002 The Regents of the Unviersity of Michigan
+diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
+index b4acb3d..98b21ad 100644
+--- a/include/linux/sunrpc/svcsock.h
++++ b/include/linux/sunrpc/svcsock.h
+@@ -20,8 +20,9 @@ struct svc_sock {
+ struct socket * sk_sock; /* berkeley socket layer */
+ struct sock * sk_sk; /* INET layer */
+
++ struct svc_pool * sk_pool; /* current pool iff queued */
+ struct svc_serv * sk_server; /* service for this socket */
+- unsigned int sk_inuse; /* use count */
++ atomic_t sk_inuse; /* use count */
+ unsigned long sk_flags;
+ #define SK_BUSY 0 /* enqueued/receiving */
+ #define SK_CONN 1 /* conn pending */
+@@ -31,9 +32,12 @@ struct svc_sock {
+ #define SK_DEAD 6 /* socket closed */
+ #define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */
+ #define SK_DEFERRED 8 /* request on sk_deferred */
++#define SK_OLD 9 /* used for temp socket aging mark+sweep */
++#define SK_DETACHED 10 /* detached from tempsocks list */
+
+- int sk_reserved; /* space on outq that is reserved */
++ atomic_t sk_reserved; /* space on outq that is reserved */
+
++ spinlock_t sk_defer_lock; /* protects sk_deferred */
+ struct list_head sk_deferred; /* deferred requests that need to
+ * be revisted */
+ struct mutex sk_mutex; /* to serialize sending data */
+@@ -50,6 +54,9 @@ struct svc_sock {
+ int sk_reclen; /* length of record */
+ int sk_tcplen; /* current read length */
+ time_t sk_lastrecv; /* time of last received request */
++
++ /* cache of various info for TCP sockets */
++ void *sk_info_authunix;
+ };
+
+ /*
+@@ -57,9 +64,14 @@ struct svc_sock {
+ */
+ int svc_makesock(struct svc_serv *, int, unsigned short);
+ void svc_delete_socket(struct svc_sock *);
+-int svc_recv(struct svc_serv *, struct svc_rqst *, long);
++int svc_recv(struct svc_rqst *, long);
+ int svc_send(struct svc_rqst *);
+ void svc_drop(struct svc_rqst *);
+ void svc_sock_update_bufs(struct svc_serv *serv);
++int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
++int svc_addsock(struct svc_serv *serv,
++ int fd,
++ char *name_return,
++ int *proto);
+
+ #endif /* SUNRPC_SVCSOCK_H */
+diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
+index e6d3d34..ac69e55 100644
+--- a/include/linux/sunrpc/xdr.h
++++ b/include/linux/sunrpc/xdr.h
+@@ -32,7 +32,7 @@ struct xdr_netobj {
+ * side) or svc_rqst pointer (server side).
+ * Encode functions always assume there's enough room in the buffer.
+ */
+-typedef int (*kxdrproc_t)(void *rqstp, u32 *data, void *obj);
++typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
+
+ /*
+ * Basic structure for transmission/reception of a client XDR message.
+@@ -74,6 +74,7 @@ struct xdr_buf {
+ #define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL)
+ #define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS)
+ #define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR)
++#define rpc_drop_reply __constant_htonl(RPC_DROP_REPLY)
+
+ #define rpc_auth_ok __constant_htonl(RPC_AUTH_OK)
+ #define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED)
+@@ -88,19 +89,19 @@ struct xdr_buf {
+ /*
+ * Miscellaneous XDR helper functions
+ */
+-u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len);
+-u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len);
+-u32 * xdr_encode_string(u32 *p, const char *s);
+-u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
+-u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
+-u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *);
++__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
++__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
++__be32 *xdr_encode_string(__be32 *p, const char *s);
++__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen);
++__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
++__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
+
+ void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
+ unsigned int);
+ void xdr_inline_pages(struct xdr_buf *, unsigned int,
+ struct page **, unsigned int, unsigned int);
+
+-static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len)
++static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
+ {
+ return xdr_encode_opaque(p, s, len);
+ }
+@@ -108,16 +109,16 @@ static inline u32 *xdr_encode_array(u32
+ /*
+ * Decode 64bit quantities (NFSv3 support)
+ */
+-static inline u32 *
+-xdr_encode_hyper(u32 *p, __u64 val)
++static inline __be32 *
++xdr_encode_hyper(__be32 *p, __u64 val)
+ {
+ *p++ = htonl(val >> 32);
+ *p++ = htonl(val & 0xFFFFFFFF);
+ return p;
+ }
+
+-static inline u32 *
+-xdr_decode_hyper(u32 *p, __u64 *valp)
++static inline __be32 *
++xdr_decode_hyper(__be32 *p, __u64 *valp)
+ {
+ *valp = ((__u64) ntohl(*p++)) << 32;
+ *valp |= ntohl(*p++);
+@@ -128,7 +129,7 @@ xdr_decode_hyper(u32 *p, __u64 *valp)
+ * Adjust kvec to reflect end of xdr'ed data (RPC client XDR)
+ */
+ static inline int
+-xdr_adjust_iovec(struct kvec *iov, u32 *p)
++xdr_adjust_iovec(struct kvec *iov, __be32 *p)
+ {
+ return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
+ }
+@@ -180,19 +181,19 @@ extern int xdr_encode_array2(struct xdr_
+ * Provide some simple tools for XDR buffer overflow-checking etc.
+ */
+ struct xdr_stream {
+- uint32_t *p; /* start of available buffer */
++ __be32 *p; /* start of available buffer */
+ struct xdr_buf *buf; /* XDR buffer to read/write */
+
+- uint32_t *end; /* end of available buffer space */
++ __be32 *end; /* end of available buffer space */
+ struct kvec *iov; /* pointer to the current kvec */
+ };
+
+-extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
+-extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
++extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
++extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
+ extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
+ unsigned int base, unsigned int len);
+-extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
+-extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
++extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
++extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
+ extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
+ extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
+
+diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
+index 3a0cca2..60394fb 100644
+--- a/include/linux/sunrpc/xprt.h
++++ b/include/linux/sunrpc/xprt.h
+@@ -12,8 +12,10 @@
+ #include <linux/uio.h>
+ #include <linux/socket.h>
+ #include <linux/in.h>
++#include <linux/kref.h>
+ #include <linux/sunrpc/sched.h>
+ #include <linux/sunrpc/xdr.h>
++#include <linux/sunrpc/msg_prot.h>
+
+ extern unsigned int xprt_udp_slot_table_entries;
+ extern unsigned int xprt_tcp_slot_table_entries;
+@@ -23,13 +25,6 @@ extern unsigned int xprt_tcp_slot_table_
+ #define RPC_MAX_SLOT_TABLE (128U)
+
+ /*
+- * RPC call and reply header size as number of 32bit words (verifier
+- * size computed separately)
+- */
+-#define RPC_CALLHDRSIZE 6
+-#define RPC_REPHDRSIZE 4
+-
+-/*
+ * Parameters for choosing a free port
+ */
+ extern unsigned int xprt_min_resvport;
+@@ -51,6 +46,14 @@ struct rpc_timeout {
+ unsigned char to_exponential;
+ };
+
++enum rpc_display_format_t {
++ RPC_DISPLAY_ADDR = 0,
++ RPC_DISPLAY_PORT,
++ RPC_DISPLAY_PROTO,
++ RPC_DISPLAY_ALL,
++ RPC_DISPLAY_MAX,
++};
++
+ struct rpc_task;
+ struct rpc_xprt;
+ struct seq_file;
+@@ -70,7 +73,7 @@ struct rpc_rqst {
+ * This is the private part
+ */
+ struct rpc_task * rq_task; /* RPC task data */
+- __u32 rq_xid; /* request XID */
++ __be32 rq_xid; /* request XID */
+ int rq_cong; /* has incremented xprt->cong */
+ int rq_received; /* receive completed */
+ u32 rq_seqno; /* gss seq no. used on req. */
+@@ -103,8 +106,10 @@ struct rpc_rqst {
+
+ struct rpc_xprt_ops {
+ void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
++ char * (*print_addr)(struct rpc_xprt *xprt, enum rpc_display_format_t format);
+ int (*reserve_xprt)(struct rpc_task *task);
+ void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
++ void (*rpcbind)(struct rpc_task *task);
+ void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
+ void (*connect)(struct rpc_task *task);
+ void * (*buf_alloc)(struct rpc_task *task, size_t size);
+@@ -119,12 +124,14 @@ struct rpc_xprt_ops {
+ };
+
+ struct rpc_xprt {
++ struct kref kref; /* Reference count */
+ struct rpc_xprt_ops * ops; /* transport methods */
+ struct socket * sock; /* BSD socket layer */
+ struct sock * inet; /* INET layer */
+
+ struct rpc_timeout timeout; /* timeout parms */
+- struct sockaddr_in addr; /* server address */
++ struct sockaddr_storage addr; /* server address */
++ size_t addrlen; /* size of server address */
+ int prot; /* IP protocol */
+
+ unsigned long cong; /* current congestion */
+@@ -138,6 +145,7 @@ struct rpc_xprt {
+ unsigned int tsh_size; /* size of transport specific
+ header */
+
++ struct rpc_wait_queue binding; /* requests waiting on rpcbind */
+ struct rpc_wait_queue sending; /* requests waiting to send */
+ struct rpc_wait_queue resend; /* requests waiting to resend */
+ struct rpc_wait_queue pending; /* requests in flight */
+@@ -157,9 +165,9 @@ struct rpc_xprt {
+ /*
+ * State of TCP reply receive stuff
+ */
+- u32 tcp_recm, /* Fragment header */
+- tcp_xid, /* Current XID */
+- tcp_reclen, /* fragment length */
++ __be32 tcp_recm, /* Fragment header */
++ tcp_xid; /* Current XID */
++ u32 tcp_reclen, /* fragment length */
+ tcp_offset; /* fragment offset */
+ unsigned long tcp_copied, /* copied to request */
+ tcp_flags;
+@@ -205,6 +213,8 @@ struct rpc_xprt {
+ void (*old_data_ready)(struct sock *, int);
+ void (*old_state_change)(struct sock *);
+ void (*old_write_space)(struct sock *);
++
++ char * address_strings[RPC_DISPLAY_MAX];
+ };
+
+ #define XPRT_LAST_FRAG (1 << 0)
+@@ -217,12 +227,12 @@ struct rpc_xprt {
+ /*
+ * Transport operations used by ULPs
+ */
+-struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, struct rpc_timeout *to);
+ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr);
+
+ /*
+ * Generic internal transport functions
+ */
++struct rpc_xprt * xprt_create_transport(int proto, struct sockaddr *addr, size_t size, struct rpc_timeout *toparms);
+ void xprt_connect(struct rpc_task *task);
+ void xprt_reserve(struct rpc_task *task);
+ int xprt_reserve_xprt(struct rpc_task *task);
+@@ -234,9 +244,10 @@ int xprt_adjust_timeout(struct rpc_rqs
+ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
+ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
+ void xprt_release(struct rpc_task *task);
+-int xprt_destroy(struct rpc_xprt *xprt);
++struct rpc_xprt * xprt_get(struct rpc_xprt *xprt);
++void xprt_put(struct rpc_xprt *xprt);
+
+-static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p)
++static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
+ {
+ return p + xprt->tsh_size;
+ }
+@@ -251,7 +262,7 @@ void xprt_wait_for_buffer_space(struct
+ void xprt_write_space(struct rpc_xprt *xprt);
+ void xprt_update_rtt(struct rpc_task *task);
+ void xprt_adjust_cwnd(struct rpc_task *task, int result);
+-struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid);
++struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid);
+ void xprt_complete_rqst(struct rpc_task *task, int copied);
+ void xprt_release_rqst_cong(struct rpc_task *task);
+ void xprt_disconnect(struct rpc_xprt *xprt);
+@@ -269,6 +280,8 @@ int xs_setup_tcp(struct rpc_xprt *xprt
+ #define XPRT_CONNECTED (1)
+ #define XPRT_CONNECTING (2)
+ #define XPRT_CLOSE_WAIT (3)
++#define XPRT_BOUND (4)
++#define XPRT_BINDING (5)
+
+ static inline void xprt_set_connected(struct rpc_xprt *xprt)
+ {
+@@ -312,6 +325,33 @@ static inline int xprt_test_and_set_conn
+ return test_and_set_bit(XPRT_CONNECTING, &xprt->state);
+ }
+
++static inline void xprt_set_bound(struct rpc_xprt *xprt)
++{
++ test_and_set_bit(XPRT_BOUND, &xprt->state);
++}
++
++static inline int xprt_bound(struct rpc_xprt *xprt)
++{
++ return test_bit(XPRT_BOUND, &xprt->state);
++}
++
++static inline void xprt_clear_bound(struct rpc_xprt *xprt)
++{
++ clear_bit(XPRT_BOUND, &xprt->state);
++}
++
++static inline void xprt_clear_binding(struct rpc_xprt *xprt)
++{
++ smp_mb__before_clear_bit();
++ clear_bit(XPRT_BINDING, &xprt->state);
++ smp_mb__after_clear_bit();
++}
++
++static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt)
++{
++ return test_and_set_bit(XPRT_BINDING, &xprt->state);
++}
++
+ #endif /* __KERNEL__*/
+
+ #endif /* _LINUX_SUNRPC_XPRT_H */
+diff --git a/include/linux/suspend.h b/include/linux/suspend.h
+index 96e31aa..b1237f1 100644
+--- a/include/linux/suspend.h
++++ b/include/linux/suspend.h
+@@ -10,29 +10,11 @@
+ #include <linux/pm.h>
+
+ /* page backup entry */
+-typedef struct pbe {
++struct pbe {
+ unsigned long address; /* address of the copy */
+ unsigned long orig_address; /* original address of page */
+ struct pbe *next;
+-} suspend_pagedir_t;
+-
+-#define for_each_pbe(pbe, pblist) \
+- for (pbe = pblist ; pbe ; pbe = pbe->next)
+-
+-#define PBES_PER_PAGE (PAGE_SIZE/sizeof(struct pbe))
+-#define PB_PAGE_SKIP (PBES_PER_PAGE-1)
+-
+-#define for_each_pb_page(pbe, pblist) \
+- for (pbe = pblist ; pbe ; pbe = (pbe+PB_PAGE_SKIP)->next)
+-
+-
+-#define SWAP_FILENAME_MAXLENGTH 32
+-
+-
+-extern dev_t swsusp_resume_device;
+-
+-/* mm/vmscan.c */
+-extern int shrink_mem(void);
++};
+
+ /* mm/page_alloc.c */
+ extern void drain_local_pages(void);
+@@ -53,18 +35,10 @@ static inline void pm_restore_console(vo
+ static inline int software_suspend(void)
+ {
+ printk("Warning: fake suspend called\n");
+- return -EPERM;
++ return -ENOSYS;
+ }
+ #endif /* CONFIG_PM */
+
+-#ifdef CONFIG_SUSPEND_SMP
+-extern void disable_nonboot_cpus(void);
+-extern void enable_nonboot_cpus(void);
+-#else
+-static inline void disable_nonboot_cpus(void) {}
+-static inline void enable_nonboot_cpus(void) {}
+-#endif
+-
+ void save_processor_state(void);
+ void restore_processor_state(void);
+ struct saved_context;
+diff --git a/include/linux/swap.h b/include/linux/swap.h
+index 5e59184..e7c36ba 100644
+--- a/include/linux/swap.h
++++ b/include/linux/swap.h
+@@ -10,6 +10,10 @@
+ #include <asm/atomic.h>
+ #include <asm/page.h>
+
++struct notifier_block;
++
++struct bio;
++
+ #define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */
+ #define SWAP_FLAG_PRIO_MASK 0x7fff
+ #define SWAP_FLAG_PRIO_SHIFT 0
+@@ -156,13 +160,14 @@ struct swap_list_t {
+
+ /* linux/mm/oom_kill.c */
+ extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order);
++extern int register_oom_notifier(struct notifier_block *nb);
++extern int unregister_oom_notifier(struct notifier_block *nb);
+
+ /* linux/mm/memory.c */
+ extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
+
+ /* linux/mm/page_alloc.c */
+ extern unsigned long totalram_pages;
+-extern unsigned long totalhigh_pages;
+ extern unsigned long totalreserve_pages;
+ extern long nr_swap_pages;
+ extern unsigned int nr_free_pages(void);
+@@ -190,6 +195,7 @@ extern long vm_total_pages;
+ #ifdef CONFIG_NUMA
+ extern int zone_reclaim_mode;
+ extern int sysctl_min_unmapped_ratio;
++extern int sysctl_min_slab_ratio;
+ extern int zone_reclaim(struct zone *, gfp_t, unsigned int);
+ #else
+ #define zone_reclaim_mode 0
+@@ -212,7 +218,9 @@ extern void swap_unplug_io_fn(struct bac
+ /* linux/mm/page_io.c */
+ extern int swap_readpage(struct file *, struct page *);
+ extern int swap_writepage(struct page *page, struct writeback_control *wbc);
+-extern int rw_swap_page_sync(int, swp_entry_t, struct page *);
++extern int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page,
++ struct bio **bio_chain);
++extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err);
+
+ /* linux/mm/swap_state.c */
+ extern struct address_space swapper_space;
+diff --git a/include/linux/synclink.h b/include/linux/synclink.h
+index 0577f52..c8b0426 100644
+--- a/include/linux/synclink.h
++++ b/include/linux/synclink.h
+@@ -1,7 +1,7 @@
+ /*
+ * SyncLink Multiprotocol Serial Adapter Driver
+ *
+- * $Id: synclink.h,v 3.13 2006/05/23 18:25:06 paulkf Exp $
++ * $Id: synclink.h,v 3.14 2006/07/17 20:15:43 paulkf Exp $
+ *
+ * Copyright (C) 1998-2000 by Microgate Corporation
+ *
+@@ -124,6 +124,8 @@
+
+ #define MGSL_MODE_ASYNC 1
+ #define MGSL_MODE_HDLC 2
++#define MGSL_MODE_MONOSYNC 3
++#define MGSL_MODE_BISYNC 4
+ #define MGSL_MODE_RAW 6
+
+ #define MGSL_BUS_TYPE_ISA 1
+diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
+index 008f04c..1912c6c 100644
+--- a/include/linux/syscalls.h
++++ b/include/linux/syscalls.h
+@@ -53,6 +53,7 @@ struct mq_attr;
+ struct compat_stat;
+ struct compat_timeval;
+ struct robust_list_head;
++struct getcpu_cache;
+
+ #include <linux/types.h>
+ #include <linux/aio_abi.h>
+@@ -430,6 +431,10 @@ asmlinkage long sys_epoll_ctl(int epfd,
+ struct epoll_event __user *event);
+ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
+ int maxevents, int timeout);
++asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
++ int maxevents, int timeout,
++ const sigset_t __user *sigmask,
++ size_t sigsetsize);
+ asmlinkage long sys_gethostname(char __user *name, int len);
+ asmlinkage long sys_sethostname(char __user *name, int len);
+ asmlinkage long sys_setdomainname(char __user *name, int len);
+@@ -592,9 +597,12 @@ asmlinkage long sys_tee(int fdin, int fd
+ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
+ unsigned int flags);
+ asmlinkage long sys_get_robust_list(int pid,
+- struct robust_list_head __user **head_ptr,
++ struct robust_list_head __user * __user *head_ptr,
+ size_t __user *len_ptr);
+ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
+ size_t len);
++asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
++
++int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
+
+ #endif
+diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
+index e4b1a4d..d98562f 100644
+--- a/include/linux/sysctl.h
++++ b/include/linux/sysctl.h
+@@ -6,10 +6,17 @@
+ ****************************************************************
+ ****************************************************************
+ **
++ ** WARNING:
+ ** The values in this file are exported to user space via
+- ** the sysctl() binary interface. However this interface
+- ** is unstable and deprecated and will be removed in the future.
+- ** For a stable interface use /proc/sys.
++ ** the sysctl() binary interface. Do *NOT* change the
++ ** numbering of any existing values here, and do not change
++ ** any numbers within any one set of values. If you have to
++ ** have to redefine an existing interface, use a new number for it.
++ ** The kernel will then return -ENOTDIR to any application using
++ ** the old binary interface.
++ **
++ ** For new interfaces unless you really need a binary number
++ ** please use CTL_UNNUMBERED.
+ **
+ ****************************************************************
+ ****************************************************************
+@@ -48,6 +55,7 @@ struct __sysctl_args {
+ #ifdef __KERNEL__
+ #define CTL_ANY -1 /* Matches any name */
+ #define CTL_NONE 0
++#define CTL_UNNUMBERED CTL_NONE /* sysctl without a binary number */
+ #endif
+
+ enum
+@@ -150,6 +158,8 @@ enum
+ KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
+ KERN_COMPAT_LOG=73, /* int: print compat layer messages */
+ KERN_MAX_LOCK_DEPTH=74,
++ KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
++ KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
+ };
+
+
+@@ -191,6 +201,7 @@ enum
+ VM_MIN_UNMAPPED=32, /* Set min percent of unmapped pages */
+ VM_PANIC_ON_OOM=33, /* panic at out-of-memory */
+ VM_VDSO_ENABLED=34, /* map VDSO into new processes? */
++ VM_MIN_SLAB=35, /* Percent pages ignored by zone reclaim */
+ };
+
+
+@@ -411,6 +422,10 @@ enum
+ NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115,
+ NET_TCP_DMA_COPYBREAK=116,
+ NET_TCP_SLOW_START_AFTER_IDLE=117,
++ NET_CIPSOV4_CACHE_ENABLE=118,
++ NET_CIPSOV4_CACHE_BUCKET_SIZE=119,
++ NET_CIPSOV4_RBM_OPTFMT=120,
++ NET_CIPSOV4_RBM_STRICTVALID=121,
+ };
+
+ enum {
+@@ -552,6 +567,7 @@ enum {
+ NET_IPV6_ACCEPT_RA_RTR_PREF=20,
+ NET_IPV6_RTR_PROBE_INTERVAL=21,
+ NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
++ NET_IPV6_PROXY_NDP=23,
+ __NET_IPV6_MAX
+ };
+
+@@ -953,8 +969,8 @@ extern ctl_handler sysctl_ms_jiffies;
+ /*
+ * Register a set of sysctl names by calling register_sysctl_table
+ * with an initialised array of ctl_table's. An entry with zero
+- * ctl_name terminates the table. table->de will be set up by the
+- * registration and need not be initialised in advance.
++ * ctl_name and NULL procname terminates the table. table->de will be
++ * set up by the registration and need not be initialised in advance.
+ *
+ * sysctl names can be mirrored automatically under /proc/sys. The
+ * procname supplied controls /proc naming.
+@@ -965,7 +981,10 @@ extern ctl_handler sysctl_ms_jiffies;
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories. A
+ * null procname disables /proc mirroring at this node.
+- *
++ *
++ * sysctl entries with a zero ctl_name will not be available through
++ * the binary sysctl interface.
++ *
+ * sysctl(2) can automatically manage read and write requests through
+ * the sysctl table. The data and maxlen fields of the ctl_table
+ * struct enable minimal validation of the values being written to be
+diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
+index 1ea5d3c..6d5c43d 100644
+--- a/include/linux/sysfs.h
++++ b/include/linux/sysfs.h
+@@ -10,6 +10,7 @@
+ #ifndef _SYSFS_H_
+ #define _SYSFS_H_
+
++#include <linux/compiler.h>
+ #include <asm/atomic.h>
+
+ struct kobject;
+@@ -86,40 +87,44 @@ struct sysfs_dirent {
+
+ #ifdef CONFIG_SYSFS
+
+-extern int
++extern int __must_check
+ sysfs_create_dir(struct kobject *);
+
+ extern void
+ sysfs_remove_dir(struct kobject *);
+
+-extern int
++extern int __must_check
+ sysfs_rename_dir(struct kobject *, const char *new_name);
+
+-extern int
++extern int __must_check
+ sysfs_create_file(struct kobject *, const struct attribute *);
+
+-extern int
++extern int __must_check
+ sysfs_update_file(struct kobject *, const struct attribute *);
+
+-extern int
++extern int __must_check
+ sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode);
+
+ extern void
+ sysfs_remove_file(struct kobject *, const struct attribute *);
+
+-extern int
++extern int __must_check
+ sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name);
+
+ extern void
+ sysfs_remove_link(struct kobject *, const char * name);
+
+-int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);
+-int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
++int __must_check sysfs_create_bin_file(struct kobject *kobj,
++ struct bin_attribute *attr);
++void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
+
+-int sysfs_create_group(struct kobject *, const struct attribute_group *);
++int __must_check sysfs_create_group(struct kobject *,
++ const struct attribute_group *);
+ void sysfs_remove_group(struct kobject *, const struct attribute_group *);
+ void sysfs_notify(struct kobject * k, char *dir, char *attr);
+
++extern int __must_check sysfs_init(void);
++
+ #else /* CONFIG_SYSFS */
+
+ static inline int sysfs_create_dir(struct kobject * k)
+@@ -191,6 +196,11 @@ static inline void sysfs_notify(struct k
+ {
+ }
+
++static inline int __must_check sysfs_init(void)
++{
++ return 0;
++}
++
+ #endif /* CONFIG_SYSFS */
+
+ #endif /* _SYSFS_H_ */
+diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
+index 4812ff6..9df8833 100644
+--- a/include/linux/sysrq.h
++++ b/include/linux/sysrq.h
+@@ -11,6 +11,8 @@
+ * based upon discusions in irc://irc.openprojects.net/#kernelnewbies
+ */
+
++#ifndef _LINUX_SYSRQ_H
++#define _LINUX_SYSRQ_H
+
+ struct pt_regs;
+ struct tty_struct;
+@@ -27,7 +29,7 @@ struct tty_struct;
+ #define SYSRQ_ENABLE_RTNICE 0x0100
+
+ struct sysrq_key_op {
+- void (*handler)(int, struct pt_regs *, struct tty_struct *);
++ void (*handler)(int, struct tty_struct *);
+ char *help_msg;
+ char *action_msg;
+ int enable_mask;
+@@ -40,8 +42,8 @@ struct sysrq_key_op {
+ * are available -- else NULL's).
+ */
+
+-void handle_sysrq(int, struct pt_regs *, struct tty_struct *);
+-void __handle_sysrq(int, struct pt_regs *, struct tty_struct *, int check_mask);
++void handle_sysrq(int, struct tty_struct *);
++void __handle_sysrq(int, struct tty_struct *, int check_mask);
+ int register_sysrq_key(int, struct sysrq_key_op *);
+ int unregister_sysrq_key(int, struct sysrq_key_op *);
+ struct sysrq_key_op *__sysrq_get_key_op(int key);
+@@ -57,3 +59,5 @@ static inline int __reterr(void)
+ #define unregister_sysrq_key(ig,nore) __reterr()
+
+ #endif
++
++#endif /* _LINUX_SYSRQ_H */
+diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h
+index f1cb6cd..4524880 100644
+--- a/include/linux/taskstats.h
++++ b/include/linux/taskstats.h
+@@ -2,6 +2,7 @@
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ * (C) Balbir Singh, IBM Corp. 2006
++ * (C) Jay Lan, SGI, 2006
+ *
+ * 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
+@@ -29,16 +30,25 @@
+ * c) add new fields after version comment; maintain 64-bit alignment
+ */
+
+-#define TASKSTATS_VERSION 1
++
++#define TASKSTATS_VERSION 2
++#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
++ * in linux/sched.h */
+
+ struct taskstats {
+
+- /* Version 1 */
++ /* The version number of this struct. This field is always set to
++ * TAKSTATS_VERSION, which is defined in <linux/taskstats.h>.
++ * Each time the struct is changed, the value should be incremented.
++ */
+ __u16 version;
+- __u16 padding[3]; /* Userspace should not interpret the padding
+- * field which can be replaced by useful
+- * fields if struct taskstats is extended.
+- */
++ __u32 ac_exitcode; /* Exit status */
++
++ /* The accounting flags of a task as defined in <linux/acct.h>
++ * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG.
++ */
++ __u8 ac_flag; /* Record flags */
++ __u8 ac_nice; /* task_nice */
+
+ /* Delay accounting fields start
+ *
+@@ -88,6 +98,48 @@ struct taskstats {
+ __u64 cpu_run_virtual_total;
+ /* Delay accounting fields end */
+ /* version 1 ends here */
++
++ /* Basic Accounting Fields start */
++ char ac_comm[TS_COMM_LEN]; /* Command name */
++ __u8 ac_sched; /* Scheduling discipline */
++ __u8 ac_pad[3];
++ __u32 ac_uid; /* User ID */
++ __u32 ac_gid; /* Group ID */
++ __u32 ac_pid; /* Process ID */
++ __u32 ac_ppid; /* Parent process ID */
++ __u32 ac_btime; /* Begin time [sec since 1970] */
++ __u64 ac_etime; /* Elapsed time [usec] */
++ __u64 ac_utime; /* User CPU time [usec] */
++ __u64 ac_stime; /* SYstem CPU time [usec] */
++ __u64 ac_minflt; /* Minor Page Fault Count */
++ __u64 ac_majflt; /* Major Page Fault Count */
++ /* Basic Accounting Fields end */
++
++ /* Extended accounting fields start */
++ /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
++ * The current rss usage is added to this counter every time
++ * a tick is charged to a task's system time. So, at the end we
++ * will have memory usage multiplied by system time. Thus an
++ * average usage per system time unit can be calculated.
++ */
++ __u64 coremem; /* accumulated RSS usage in MB-usec */
++ /* Accumulated virtual memory usage in duration of a task.
++ * Same as acct_rss_mem1 above except that we keep track of VM usage.
++ */
++ __u64 virtmem; /* accumulated VM usage in MB-usec */
++
++ /* High watermark of RSS and virtual memory usage in duration of
++ * a task, in KBytes.
++ */
++ __u64 hiwater_rss; /* High-watermark of RSS usage, in KB */
++ __u64 hiwater_vm; /* High-water VM usage, in KB */
++
++ /* The following four fields are I/O statistics of a task. */
++ __u64 read_char; /* bytes read */
++ __u64 write_char; /* bytes written */
++ __u64 read_syscalls; /* read syscalls */
++ __u64 write_syscalls; /* write syscalls */
++ /* Extended accounting fields end */
+ };
+
+
+diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h
+index 16894b7..6562a20 100644
+--- a/include/linux/taskstats_kern.h
++++ b/include/linux/taskstats_kern.h
+@@ -23,25 +23,26 @@ static inline void taskstats_exit_free(s
+
+ static inline void taskstats_tgid_init(struct signal_struct *sig)
+ {
+- spin_lock_init(&sig->stats_lock);
+ sig->stats = NULL;
+ }
+
+-static inline void taskstats_tgid_alloc(struct signal_struct *sig)
++static inline void taskstats_tgid_alloc(struct task_struct *tsk)
+ {
++ struct signal_struct *sig = tsk->signal;
+ struct taskstats *stats;
+- unsigned long flags;
+
+- stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL);
+- if (!stats)
++ if (sig->stats != NULL)
+ return;
+
+- spin_lock_irqsave(&sig->stats_lock, flags);
++ /* No problem if kmem_cache_zalloc() fails */
++ stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL);
++
++ spin_lock_irq(&tsk->sighand->siglock);
+ if (!sig->stats) {
+ sig->stats = stats;
+ stats = NULL;
+ }
+- spin_unlock_irqrestore(&sig->stats_lock, flags);
++ spin_unlock_irq(&tsk->sighand->siglock);
+
+ if (stats)
+ kmem_cache_free(taskstats_cache, stats);
+@@ -49,23 +50,13 @@ static inline void taskstats_tgid_alloc(
+
+ static inline void taskstats_tgid_free(struct signal_struct *sig)
+ {
+- struct taskstats *stats = NULL;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&sig->stats_lock, flags);
+- if (sig->stats) {
+- stats = sig->stats;
+- sig->stats = NULL;
+- }
+- spin_unlock_irqrestore(&sig->stats_lock, flags);
+- if (stats)
+- kmem_cache_free(taskstats_cache, stats);
++ if (sig->stats)
++ kmem_cache_free(taskstats_cache, sig->stats);
+ }
+
+ extern void taskstats_exit_alloc(struct taskstats **, unsigned int *);
+ extern void taskstats_exit_send(struct task_struct *, struct taskstats *, int, unsigned int);
+ extern void taskstats_init_early(void);
+-extern void taskstats_tgid_alloc(struct signal_struct *);
+ #else
+ static inline void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu)
+ {}
+@@ -77,7 +68,7 @@ static inline void taskstats_exit_send(s
+ {}
+ static inline void taskstats_tgid_init(struct signal_struct *sig)
+ {}
+-static inline void taskstats_tgid_alloc(struct signal_struct *sig)
++static inline void taskstats_tgid_alloc(struct task_struct *tsk)
+ {}
+ static inline void taskstats_tgid_free(struct signal_struct *sig)
+ {}
+diff --git a/include/linux/tc_act/Kbuild b/include/linux/tc_act/Kbuild
+index 5251a50..78dfbac 100644
+--- a/include/linux/tc_act/Kbuild
++++ b/include/linux/tc_act/Kbuild
+@@ -1 +1,4 @@
+-header-y += tc_gact.h tc_ipt.h tc_mirred.h tc_pedit.h
++header-y += tc_gact.h
++header-y += tc_ipt.h
++header-y += tc_mirred.h
++header-y += tc_pedit.h
+diff --git a/include/linux/tc_ematch/Kbuild b/include/linux/tc_ematch/Kbuild
+index 381e930..4a58a1c 100644
+--- a/include/linux/tc_ematch/Kbuild
++++ b/include/linux/tc_ematch/Kbuild
+@@ -1 +1,4 @@
+-headers-y := tc_em_cmp.h tc_em_meta.h tc_em_nbyte.h tc_em_text.h
++header-y += tc_em_cmp.h
++header-y += tc_em_meta.h
++header-y += tc_em_nbyte.h
++header-y += tc_em_text.h
+diff --git a/include/linux/tcp.h b/include/linux/tcp.h
+index 8ebf497..2d36f6d 100644
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -21,10 +21,10 @@
+ #include <asm/byteorder.h>
+
+ struct tcphdr {
+- __u16 source;
+- __u16 dest;
+- __u32 seq;
+- __u32 ack_seq;
++ __be16 source;
++ __be16 dest;
++ __be32 seq;
++ __be32 ack_seq;
+ #if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u16 res1:4,
+ doff:4,
+@@ -50,9 +50,9 @@ struct tcphdr {
+ #else
+ #error "Adjust your <asm/byteorder.h> defines"
+ #endif
+- __u16 window;
+- __u16 check;
+- __u16 urg_ptr;
++ __be16 window;
++ __be16 check;
++ __be16 urg_ptr;
+ };
+
+ /*
+@@ -62,7 +62,7 @@ struct tcphdr {
+ */
+ union tcp_word_hdr {
+ struct tcphdr hdr;
+- __u32 words[5];
++ __be32 words[5];
+ };
+
+ #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3])
+@@ -166,6 +166,11 @@ struct tcp_info
+ #include <net/inet_timewait_sock.h>
+
+ /* This defines a selective acknowledgement block. */
++struct tcp_sack_block_wire {
++ __be32 start_seq;
++ __be32 end_seq;
++};
++
+ struct tcp_sack_block {
+ __u32 start_seq;
+ __u32 end_seq;
+@@ -211,7 +216,7 @@ struct tcp_sock {
+ * Header prediction flags
+ * 0x5?10 << 16 + snd_wnd in net byte order
+ */
+- __u32 pred_flags;
++ __be32 pred_flags;
+
+ /*
+ * RFC793 variables by their proper names. This means you can
+@@ -337,6 +342,8 @@ struct tcp_sock {
+
+ unsigned long last_synq_overflow;
+
++ __u32 tso_deferred;
++
+ /* Receiver side RTT estimation */
+ struct {
+ __u32 rtt;
+diff --git a/include/linux/tifm.h b/include/linux/tifm.h
+new file mode 100644
+index 0000000..dfb8052
+--- /dev/null
++++ b/include/linux/tifm.h
+@@ -0,0 +1,159 @@
++/*
++ * tifm.h - TI FlashMedia driver
++ *
++ * Copyright (C) 2006 Alex Dubov <oakad at yahoo.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.
++ *
++ */
++
++#ifndef _TIFM_H
++#define _TIFM_H
++
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/wait.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/scatterlist.h>
++
++/* Host registers (relative to pci base address): */
++enum {
++ FM_SET_INTERRUPT_ENABLE = 0x008,
++ FM_CLEAR_INTERRUPT_ENABLE = 0x00c,
++ FM_INTERRUPT_STATUS = 0x014 };
++
++/* Socket registers (relative to socket base address): */
++enum {
++ SOCK_CONTROL = 0x004,
++ SOCK_PRESENT_STATE = 0x008,
++ SOCK_DMA_ADDRESS = 0x00c,
++ SOCK_DMA_CONTROL = 0x010,
++ SOCK_DMA_FIFO_INT_ENABLE_SET = 0x014,
++ SOCK_DMA_FIFO_INT_ENABLE_CLEAR = 0x018,
++ SOCK_DMA_FIFO_STATUS = 0x020,
++ SOCK_FIFO_CONTROL = 0x024,
++ SOCK_FIFO_PAGE_SIZE = 0x028,
++ SOCK_MMCSD_COMMAND = 0x104,
++ SOCK_MMCSD_ARG_LOW = 0x108,
++ SOCK_MMCSD_ARG_HIGH = 0x10c,
++ SOCK_MMCSD_CONFIG = 0x110,
++ SOCK_MMCSD_STATUS = 0x114,
++ SOCK_MMCSD_INT_ENABLE = 0x118,
++ SOCK_MMCSD_COMMAND_TO = 0x11c,
++ SOCK_MMCSD_DATA_TO = 0x120,
++ SOCK_MMCSD_DATA = 0x124,
++ SOCK_MMCSD_BLOCK_LEN = 0x128,
++ SOCK_MMCSD_NUM_BLOCKS = 0x12c,
++ SOCK_MMCSD_BUFFER_CONFIG = 0x130,
++ SOCK_MMCSD_SPI_CONFIG = 0x134,
++ SOCK_MMCSD_SDIO_MODE_CONFIG = 0x138,
++ SOCK_MMCSD_RESPONSE = 0x144,
++ SOCK_MMCSD_SDIO_SR = 0x164,
++ SOCK_MMCSD_SYSTEM_CONTROL = 0x168,
++ SOCK_MMCSD_SYSTEM_STATUS = 0x16c,
++ SOCK_MS_COMMAND = 0x184,
++ SOCK_MS_DATA = 0x188,
++ SOCK_MS_STATUS = 0x18c,
++ SOCK_MS_SYSTEM = 0x190,
++ SOCK_FIFO_ACCESS = 0x200 };
++
++
++#define TIFM_IRQ_ENABLE 0x80000000
++#define TIFM_IRQ_SOCKMASK 0x00000001
++#define TIFM_IRQ_CARDMASK 0x00000100
++#define TIFM_IRQ_FIFOMASK 0x00010000
++#define TIFM_IRQ_SETALL 0xffffffff
++#define TIFM_IRQ_SETALLSOCK 0x0000000f
++
++#define TIFM_CTRL_LED 0x00000040
++#define TIFM_CTRL_FAST_CLK 0x00000100
++
++#define TIFM_SOCK_STATE_OCCUPIED 0x00000008
++#define TIFM_SOCK_STATE_POWERED 0x00000080
++
++#define TIFM_FIFO_ENABLE 0x00000001 /* Meaning of this constant is unverified */
++#define TIFM_FIFO_INT_SETALL 0x0000ffff
++#define TIFM_FIFO_INTMASK 0x00000005 /* Meaning of this constant is unverified */
++
++#define TIFM_DMA_RESET 0x00000002 /* Meaning of this constant is unverified */
++#define TIFM_DMA_TX 0x00008000 /* Meaning of this constant is unverified */
++#define TIFM_DMA_EN 0x00000001 /* Meaning of this constant is unverified */
++
++typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id;
++
++struct tifm_driver;
++struct tifm_dev {
++ char __iomem *addr;
++ spinlock_t lock;
++ tifm_media_id media_id;
++ char wq_name[KOBJ_NAME_LEN];
++ struct workqueue_struct *wq;
++
++ unsigned int (*signal_irq)(struct tifm_dev *sock,
++ unsigned int sock_irq_status);
++
++ struct tifm_driver *drv;
++ struct device dev;
++};
++
++struct tifm_driver {
++ tifm_media_id *id_table;
++ int (*probe)(struct tifm_dev *dev);
++ void (*remove)(struct tifm_dev *dev);
++
++ struct device_driver driver;
++};
++
++struct tifm_adapter {
++ char __iomem *addr;
++ unsigned int irq_status;
++ unsigned int insert_mask;
++ unsigned int remove_mask;
++ spinlock_t lock;
++ unsigned int id;
++ unsigned int max_sockets;
++ char wq_name[KOBJ_NAME_LEN];
++ unsigned int inhibit_new_cards;
++ struct workqueue_struct *wq;
++ struct work_struct media_inserter;
++ struct work_struct media_remover;
++ struct tifm_dev **sockets;
++ struct class_device cdev;
++ struct device *dev;
++
++ void (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock);
++};
++
++struct tifm_adapter *tifm_alloc_adapter(void);
++void tifm_free_device(struct device *dev);
++void tifm_free_adapter(struct tifm_adapter *fm);
++int tifm_add_adapter(struct tifm_adapter *fm);
++void tifm_remove_adapter(struct tifm_adapter *fm);
++struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
++int tifm_register_driver(struct tifm_driver *drv);
++void tifm_unregister_driver(struct tifm_driver *drv);
++void tifm_eject(struct tifm_dev *sock);
++int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
++ int direction);
++void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
++ int direction);
++
++
++static inline void *tifm_get_drvdata(struct tifm_dev *dev)
++{
++ return dev_get_drvdata(&dev->dev);
++}
++
++static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
++{
++ dev_set_drvdata(&dev->dev, data);
++}
++
++struct tifm_device_id {
++ tifm_media_id media_id;
++};
++
++#endif
+diff --git a/include/linux/timex.h b/include/linux/timex.h
+index d543d38..db501dc 100644
+--- a/include/linux/timex.h
++++ b/include/linux/timex.h
+@@ -69,34 +69,28 @@
+ * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
+ * respectively.
+ */
+-#define SHIFT_KG 6 /* phase factor (shift) */
+-#define SHIFT_KF 16 /* PLL frequency factor (shift) */
+-#define SHIFT_KH 2 /* FLL frequency factor (shift) */
+-#define MAXTC 6 /* maximum time constant (shift) */
++#define SHIFT_PLL 4 /* PLL frequency factor (shift) */
++#define SHIFT_FLL 2 /* FLL frequency factor (shift) */
++#define MAXTC 10 /* maximum time constant (shift) */
+
+ /*
+- * The SHIFT_SCALE define establishes the decimal point of the time_phase
+- * variable which serves as an extension to the low-order bits of the
+- * system clock variable. The SHIFT_UPDATE define establishes the decimal
+- * point of the time_offset variable which represents the current offset
+- * with respect to standard time. The FINENSEC define represents 1 nsec in
+- * scaled units.
++ * The SHIFT_UPDATE define establishes the decimal point of the
++ * time_offset variable which represents the current offset with
++ * respect to standard time.
+ *
+ * SHIFT_USEC defines the scaling (shift) of the time_freq and
+ * time_tolerance variables, which represent the current frequency
+ * offset and maximum frequency tolerance.
+- *
+- * FINENSEC is 1 ns in SHIFT_UPDATE units of the time_phase variable.
+ */
+-#define SHIFT_SCALE 22 /* phase scale (shift) */
+-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
++#define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */
+ #define SHIFT_USEC 16 /* frequency offset scale (shift) */
+-#define FINENSEC (1L << (SHIFT_SCALE - 10)) /* ~1 ns in phase units */
++#define SHIFT_NSEC 12 /* kernel frequency offset scale */
+
+ #define MAXPHASE 512000L /* max phase error (us) */
+ #define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */
+-#define MINSEC 16L /* min interval between updates (s) */
+-#define MAXSEC 1200L /* max interval between updates (s) */
++#define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */
++#define MINSEC 256 /* min interval between updates (s) */
++#define MAXSEC 2048 /* max interval between updates (s) */
+ #define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
+
+ /*
+@@ -204,33 +198,15 @@ extern int tickadj; /* amount of adjus
+ /*
+ * phase-lock loop variables
+ */
+-extern int time_state; /* clock status */
+ extern int time_status; /* clock synchronization status bits */
+-extern long time_offset; /* time adjustment (us) */
+-extern long time_constant; /* pll time constant */
+-extern long time_tolerance; /* frequency tolerance (ppm) */
+-extern long time_precision; /* clock precision (us) */
+ extern long time_maxerror; /* maximum error */
+ extern long time_esterror; /* estimated error */
+
+ extern long time_freq; /* frequency offset (scaled ppm) */
+-extern long time_reftime; /* time at last adjustment (s) */
+
+ extern long time_adjust; /* The amount of adjtime left */
+-extern long time_next_adjust; /* Value for time_adjust at next tick */
+
+-/**
+- * ntp_clear - Clears the NTP state variables
+- *
+- * Must be called while holding a write on the xtime_lock
+- */
+-static inline void ntp_clear(void)
+-{
+- time_adjust = 0; /* stop active adjtime() */
+- time_status |= STA_UNSYNC;
+- time_maxerror = NTP_PHASE_LIMIT;
+- time_esterror = NTP_PHASE_LIMIT;
+-}
++extern void ntp_clear(void);
+
+ /**
+ * ntp_synced - Returns 1 if the NTP status is not UNSYNC
+@@ -294,11 +270,15 @@ extern void register_time_interpolator(s
+ extern void unregister_time_interpolator(struct time_interpolator *);
+ extern void time_interpolator_reset(void);
+ extern unsigned long time_interpolator_get_offset(void);
++extern void time_interpolator_update(long delta_nsec);
+
+ #else /* !CONFIG_TIME_INTERPOLATION */
+
+-static inline void
+-time_interpolator_reset(void)
++static inline void time_interpolator_reset(void)
++{
++}
++
++static inline void time_interpolator_update(long delta_nsec)
+ {
+ }
+
+@@ -309,8 +289,13 @@ time_interpolator_reset(void)
+ /* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
+ extern u64 current_tick_length(void);
+
++extern void second_overflow(void);
++extern void update_ntp_one_tick(void);
+ extern int do_adjtimex(struct timex *);
+
++/* Don't use! Compatibility define for existing users. */
++#define tickadj (500/HZ ? : 1)
++
+ #endif /* KERNEL */
+
+ #endif /* LINUX_TIMEX_H */
+diff --git a/include/linux/tipc.h b/include/linux/tipc.h
+index 243a15f..bea4694 100644
+--- a/include/linux/tipc.h
++++ b/include/linux/tipc.h
+@@ -129,6 +129,7 @@ static inline unsigned int tipc_node(__u
+
+ #define TIPC_SUB_PORTS 0x01 /* filter for port availability */
+ #define TIPC_SUB_SERVICE 0x02 /* filter for service availability */
++#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
+ #if 0
+ /* The following filter options are not currently implemented */
+ #define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */
+diff --git a/include/linux/topology.h b/include/linux/topology.h
+index ec1eca8..da508d1 100644
+--- a/include/linux/topology.h
++++ b/include/linux/topology.h
+@@ -89,6 +89,7 @@
+ #define SD_SIBLING_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 1, \
+ .max_interval = 2, \
+@@ -114,11 +115,44 @@
+ #endif
+ #endif /* CONFIG_SCHED_SMT */
+
++#ifdef CONFIG_SCHED_MC
++/* Common values for MC siblings. for now mostly derived from SD_CPU_INIT */
++#ifndef SD_MC_INIT
++#define SD_MC_INIT (struct sched_domain) { \
++ .span = CPU_MASK_NONE, \
++ .parent = NULL, \
++ .child = NULL, \
++ .groups = NULL, \
++ .min_interval = 1, \
++ .max_interval = 4, \
++ .busy_factor = 64, \
++ .imbalance_pct = 125, \
++ .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_SHARE_PKG_RESOURCES\
++ | BALANCE_FOR_MC_POWER, \
++ .last_balance = jiffies, \
++ .balance_interval = 1, \
++ .nr_balance_failed = 0, \
++}
++#endif
++#endif /* CONFIG_SCHED_MC */
++
+ /* Common values for CPUs */
+ #ifndef SD_CPU_INIT
+ #define SD_CPU_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 1, \
+ .max_interval = 4, \
+@@ -135,7 +169,7 @@
+ | SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_EXEC \
+ | SD_WAKE_AFFINE \
+- | BALANCE_FOR_POWER, \
++ | BALANCE_FOR_PKG_POWER,\
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+@@ -146,6 +180,7 @@
+ #define SD_ALLNODES_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
++ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 64, \
+ .max_interval = 64*num_online_cpus(), \
+@@ -165,15 +200,6 @@
+ .nr_balance_failed = 0, \
+ }
+
+-#ifdef CONFIG_SCHED_MC
+-#ifndef SD_MC_INIT
+-/* for now its same as SD_CPU_INIT.
+- * TBD: Tune Domain parameters!
+- */
+-#define SD_MC_INIT SD_CPU_INIT
+-#endif
+-#endif
+-
+ #ifdef CONFIG_NUMA
+ #ifndef SD_NODE_INIT
+ #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
+diff --git a/include/linux/trdevice.h b/include/linux/trdevice.h
+index 99e02ef..bfc84a7 100644
+--- a/include/linux/trdevice.h
++++ b/include/linux/trdevice.h
+@@ -28,7 +28,7 @@
+ #include <linux/if_tr.h>
+
+ #ifdef __KERNEL__
+-extern unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev);
++extern __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev);
+ extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh, struct net_device *dev);
+ extern struct net_device *alloc_trdev(int sizeof_priv);
+
+diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h
+new file mode 100644
+index 0000000..7e50ac7
+--- /dev/null
++++ b/include/linux/tsacct_kern.h
+@@ -0,0 +1,34 @@
++/*
++ * tsacct_kern.h - kernel header for system accounting over taskstats interface
++ *
++ * Copyright (C) Jay Lan SGI
++ */
++
++#ifndef _LINUX_TSACCT_KERN_H
++#define _LINUX_TSACCT_KERN_H
++
++#include <linux/taskstats.h>
++
++#ifdef CONFIG_TASKSTATS
++extern void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk);
++#else
++static inline void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
++{}
++#endif /* CONFIG_TASKSTATS */
++
++#ifdef CONFIG_TASK_XACCT
++extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p);
++extern void acct_update_integrals(struct task_struct *tsk);
++extern void acct_clear_integrals(struct task_struct *tsk);
++#else
++static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
++{}
++static inline void acct_update_integrals(struct task_struct *tsk)
++{}
++static inline void acct_clear_integrals(struct task_struct *tsk)
++{}
++#endif /* CONFIG_TASK_XACCT */
++
++#endif
++
++
+diff --git a/include/linux/tty.h b/include/linux/tty.h
+index 04827ca..44091c0 100644
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -174,7 +174,7 @@ struct tty_struct {
+ struct tty_driver *driver;
+ int index;
+ struct tty_ldisc ldisc;
+- struct semaphore termios_sem;
++ struct mutex termios_mutex;
+ struct termios *termios, *termios_locked;
+ char name[64];
+ int pgrp;
+@@ -190,7 +190,6 @@ struct tty_struct {
+ struct tty_struct *link;
+ struct fasync_struct *fasync;
+ struct tty_bufhead buf;
+- int max_flip_cnt;
+ int alt_speed; /* For magic substitution of 38400 bps */
+ wait_queue_head_t write_wait;
+ wait_queue_head_t read_wait;
+@@ -308,6 +307,9 @@ extern void tty_ldisc_put(int);
+ extern void tty_wakeup(struct tty_struct *tty);
+ extern void tty_ldisc_flush(struct tty_struct *tty);
+
++extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg);
++
+ extern struct mutex tty_mutex;
+
+ /* n_tty.c */
+diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
+index 58c961c..5c8473b 100644
+--- a/include/linux/tty_driver.h
++++ b/include/linux/tty_driver.h
+@@ -219,7 +219,8 @@ extern struct list_head tty_drivers;
+
+ struct tty_driver *alloc_tty_driver(int lines);
+ void put_tty_driver(struct tty_driver *driver);
+-void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);
++void tty_set_operations(struct tty_driver *driver,
++ const struct tty_operations *op);
+
+ /* tty driver magic number */
+ #define TTY_DRIVER_MAGIC 0x5402
+diff --git a/include/linux/types.h b/include/linux/types.h
+index 3f23566..750f085 100644
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -33,6 +33,8 @@ typedef __kernel_clockid_t clockid_t;
+ typedef __kernel_mqd_t mqd_t;
+
+ #ifdef __KERNEL__
++typedef _Bool bool;
++
+ typedef __kernel_uid32_t uid_t;
+ typedef __kernel_gid32_t gid_t;
+ typedef __kernel_uid16_t uid16_t;
+@@ -127,8 +129,12 @@ typedef __s64 int64_t;
+ /* this is a special 64bit data type that is 8-byte aligned */
+ #define aligned_u64 unsigned long long __attribute__((aligned(8)))
+
+-/*
++/**
+ * The type used for indexing onto a disc or disc partition.
++ *
++ * Linux always considers sectors to be 512 bytes long independently
++ * of the devices real block size.
++ *
+ * If required, asm/types.h can override it and define
+ * HAVE_SECTOR_T
+ */
+diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
+index 391e7ed..a48d7f1 100644
+--- a/include/linux/uaccess.h
++++ b/include/linux/uaccess.h
+@@ -19,4 +19,26 @@ static inline unsigned long __copy_from_
+
+ #endif /* ARCH_HAS_NOCACHE_UACCESS */
+
++/**
++ * probe_kernel_address(): safely attempt to read from a location
++ * @addr: address to read from - its type is type typeof(retval)*
++ * @retval: read into this variable
++ *
++ * Safely read from address @addr into variable @revtal. If a kernel fault
++ * happens, handle that and return -EFAULT.
++ * We ensure that the __get_user() is executed in atomic context so that
++ * do_page_fault() doesn't attempt to take mmap_sem. This makes
++ * probe_kernel_address() suitable for use within regions where the caller
++ * already holds mmap_sem, or other locks which nest inside mmap_sem.
++ */
++#define probe_kernel_address(addr, retval) \
++ ({ \
++ long ret; \
++ \
++ inc_preempt_count(); \
++ ret = __get_user(retval, addr); \
++ dec_preempt_count(); \
++ ret; \
++ })
++
+ #endif /* __LINUX_UACCESS_H__ */
+diff --git a/include/linux/udp.h b/include/linux/udp.h
+index 90223f0..014b41d 100644
+--- a/include/linux/udp.h
++++ b/include/linux/udp.h
+@@ -20,10 +20,10 @@
+ #include <linux/types.h>
+
+ struct udphdr {
+- __u16 source;
+- __u16 dest;
+- __u16 len;
+- __u16 check;
++ __be16 source;
++ __be16 dest;
++ __be16 len;
++ __be16 check;
+ };
+
+ /* UDP socket options */
+diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
+index fc62887..28967ed 100644
+--- a/include/linux/ufs_fs.h
++++ b/include/linux/ufs_fs.h
+@@ -351,6 +351,14 @@ struct ufs2_csum_total {
+ __fs64 cs_spare[3]; /* future expansion */
+ };
+
++struct ufs_csum_core {
++ __u64 cs_ndir; /* number of directories */
++ __u64 cs_nbfree; /* number of free blocks */
++ __u64 cs_nifree; /* number of free inodes */
++ __u64 cs_nffree; /* number of free frags */
++ __u64 cs_numclusters; /* number of free clusters */
++};
++
+ /*
+ * File system flags
+ */
+@@ -715,7 +723,7 @@ struct ufs_cg_private_info {
+
+ struct ufs_sb_private_info {
+ struct ufs_buffer_head s_ubh; /* buffer containing super block */
+- struct ufs2_csum_total cs_total;
++ struct ufs_csum_core cs_total;
+ __u32 s_sblkno; /* offset of super-blocks in filesys */
+ __u32 s_cblkno; /* offset of cg-block in filesys */
+ __u32 s_iblkno; /* offset of inode-blocks in filesys */
+@@ -900,7 +908,7 @@ struct ufs_super_block_third {
+ __fs64 fs_csaddr; /* blk addr of cyl grp summary area */
+ __fs64 fs_pendingblocks;/* blocks in process of being freed */
+ __fs32 fs_pendinginodes;/*inodes in process of being freed */
+- } fs_u2;
++ } __attribute__ ((packed)) fs_u2;
+ } fs_un1;
+ union {
+ struct {
+diff --git a/include/linux/uinput.h b/include/linux/uinput.h
+index 7168302..1fd61ee 100644
+--- a/include/linux/uinput.h
++++ b/include/linux/uinput.h
+@@ -22,12 +22,18 @@
+ * Author: Aristeu Sergio Rozanski Filho <aris at cathedrallabs.org>
+ *
+ * Changes/Revisions:
++ * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
++ * - update ff support for the changes in kernel interface
++ * - add UINPUT_VERSION
+ * 0.2 16/10/2004 (Micah Dowty <micah at navi.cx>)
+ * - added force feedback support
+ * - added UI_SET_PHYS
+ * 0.1 20/06/2002
+ * - first public version
+ */
++
++#define UINPUT_VERSION 3
++
+ #ifdef __KERNEL__
+ #define UINPUT_MINOR 223
+ #define UINPUT_NAME "uinput"
+@@ -45,7 +51,10 @@ struct uinput_request {
+
+ union {
+ int effect_id;
+- struct ff_effect* effect;
++ struct {
++ struct ff_effect *effect;
++ struct ff_effect *old;
++ } upload;
+ } u;
+ };
+
+@@ -58,6 +67,7 @@ struct uinput_device {
+ unsigned char head;
+ unsigned char tail;
+ struct input_event buff[UINPUT_BUFFER_SIZE];
++ int ff_effects_max;
+
+ struct uinput_request *requests[UINPUT_NUM_REQUESTS];
+ wait_queue_head_t requests_waitq;
+@@ -69,6 +79,7 @@ struct uinput_ff_upload {
+ int request_id;
+ int retval;
+ struct ff_effect effect;
++ struct ff_effect old;
+ };
+
+ struct uinput_ff_erase {
+@@ -98,33 +109,33 @@ struct uinput_ff_erase {
+ #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
+ #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
+
+-/* To write a force-feedback-capable driver, the upload_effect
++/*
++ * To write a force-feedback-capable driver, the upload_effect
+ * and erase_effect callbacks in input_dev must be implemented.
+ * The uinput driver will generate a fake input event when one of
+ * these callbacks are invoked. The userspace code then uses
+ * ioctls to retrieve additional parameters and send the return code.
+ * The callback blocks until this return code is sent.
+ *
+- * The described callback mechanism is only used if EV_FF is set.
+- * Otherwise, default implementations of upload_effect and erase_effect
+- * are used.
++ * The described callback mechanism is only used if ff_effects_max
++ * is set.
+ *
+ * To implement upload_effect():
+- * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD.
++ * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD.
+ * A request ID will be given in 'value'.
+ * 2. Allocate a uinput_ff_upload struct, fill in request_id with
+ * the 'value' from the EV_UINPUT event.
+ * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
+ * uinput_ff_upload struct. It will be filled in with the
+- * ff_effect passed to upload_effect().
+- * 4. Perform the effect upload, and place the modified ff_effect
+- * and a return code back into the uinput_ff_upload struct.
++ * ff_effects passed to upload_effect().
++ * 4. Perform the effect upload, and place a return code back into
++ the uinput_ff_upload struct.
+ * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
+ * uinput_ff_upload_effect struct. This will complete execution
+ * of our upload_effect() handler.
+ *
+ * To implement erase_effect():
+- * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE.
++ * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE.
+ * A request ID will be given in 'value'.
+ * 2. Allocate a uinput_ff_erase struct, fill in request_id with
+ * the 'value' from the EV_UINPUT event.
+@@ -133,13 +144,13 @@ struct uinput_ff_erase {
+ * effect ID passed to erase_effect().
+ * 4. Perform the effect erasure, and place a return code back
+ * into the uinput_ff_erase struct.
+- * and a return code back into the uinput_ff_erase struct.
+ * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the
+ * uinput_ff_erase_effect struct. This will complete execution
+ * of our erase_effect() handler.
+ */
+
+-/* This is the new event type, used only by uinput.
++/*
++ * This is the new event type, used only by uinput.
+ * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
+ * is the unique request ID. This number was picked
+ * arbitrarily, above EV_MAX (since the input system
+diff --git a/include/linux/unistd.h b/include/linux/unistd.h
+index c18c60f..aa8d5b5 100644
+--- a/include/linux/unistd.h
++++ b/include/linux/unistd.h
+@@ -1,12 +1,8 @@
+ #ifndef _LINUX_UNISTD_H_
+ #define _LINUX_UNISTD_H_
+
+-#ifdef __KERNEL__
+-extern int errno;
+-#endif
+-
+ /*
+- * Include machine specific syscallX macros
++ * Include machine specific syscall numbers
+ */
+ #include <asm/unistd.h>
+
+diff --git a/include/linux/unwind.h b/include/linux/unwind.h
+index ce48e2c..749928c 100644
+--- a/include/linux/unwind.h
++++ b/include/linux/unwind.h
+@@ -12,8 +12,6 @@
+ * is not much point in implementing the full Dwarf2 unwind API.
+ */
+
+-#include <linux/config.h>
+-
+ struct module;
+
+ #ifdef CONFIG_STACK_UNWIND
+@@ -28,6 +26,7 @@ struct module;
+ * Initialize unwind support.
+ */
+ extern void unwind_init(void);
++extern void unwind_setup(void);
+
+ #ifdef CONFIG_MODULES
+
+@@ -75,6 +74,7 @@ extern int unwind_to_user(struct unwind_
+ struct unwind_frame_info {};
+
+ static inline void unwind_init(void) {}
++static inline void unwind_setup(void) {}
+
+ #ifdef CONFIG_MODULES
+
+diff --git a/include/linux/usb.h b/include/linux/usb.h
+index d2bd0c8..5482bfb 100644
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -19,6 +19,7 @@
+ #include <linux/fs.h> /* for struct file_operations */
+ #include <linux/completion.h> /* for struct completion */
+ #include <linux/sched.h> /* for current && schedule_timeout */
++#include <linux/mutex.h> /* for struct mutex */
+
+ struct usb_device;
+ struct usb_driver;
+@@ -102,8 +103,13 @@ enum usb_interface_condition {
+ * number from the USB core by calling usb_register_dev().
+ * @condition: binding state of the interface: not bound, binding
+ * (in probe()), bound to a driver, or unbinding (in disconnect())
++ * @is_active: flag set when the interface is bound and not suspended.
++ * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
++ * capability during autosuspend.
+ * @dev: driver model's view of this device
+ * @class_dev: driver model's class view of this device.
++ * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
++ * allowed unless the counter is 0.
+ *
+ * USB device drivers attach to interfaces on a physical device. Each
+ * interface encapsulates a single high level function, such as feeding
+@@ -142,8 +148,12 @@ struct usb_interface {
+ int minor; /* minor number this interface is
+ * bound to */
+ enum usb_interface_condition condition; /* state of binding */
++ unsigned is_active:1; /* the interface is not suspended */
++ unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
++
+ struct device dev; /* interface specific device info */
+ struct class_device *class_dev;
++ int pm_usage_cnt; /* usage counter for autosuspend */
+ };
+ #define to_usb_interface(d) container_of(d, struct usb_interface, dev)
+ #define interface_to_usbdev(intf) \
+@@ -254,8 +264,6 @@ int __usb_get_extra_descriptor(char *buf
+
+ /* ----------------------------------------------------------------------- */
+
+-struct usb_operations;
+-
+ /* USB device number allocation bitmap */
+ struct usb_devmap {
+ unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+@@ -268,6 +276,7 @@ struct usb_bus {
+ struct device *controller; /* host/master side hardware */
+ int busnum; /* Bus number (in order of reg) */
+ char *bus_name; /* stable id (PCI slot_name etc) */
++ u8 uses_dma; /* Does the host controller use DMA? */
+ u8 otg_port; /* 0, or number of OTG/HNP port */
+ unsigned is_b_host:1; /* true during some HNP roleswitches */
+ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
+@@ -276,10 +285,8 @@ struct usb_bus {
+ * round-robin allocation */
+
+ struct usb_devmap devmap; /* device address allocation map */
+- struct usb_operations *op; /* Operations (specific to the HC) */
+ struct usb_device *root_hub; /* Root hub */
+ struct list_head bus_list; /* list of busses */
+- void *hcpriv; /* Host Controller private data */
+
+ int bandwidth_allocated; /* on this bus: how much of the time
+ * reserved for periodic (intr/iso)
+@@ -294,8 +301,6 @@ struct usb_bus {
+ struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
+
+ struct class_device *class_dev; /* class device for this bus */
+- struct kref kref; /* reference counting for this bus */
+- void (*release)(struct usb_bus *bus);
+
+ #if defined(CONFIG_USB_MON)
+ struct mon_bus *mon_bus; /* non-null when associated */
+@@ -350,6 +355,7 @@ struct usb_device {
+
+ unsigned short bus_mA; /* Current available from the bus */
+ u8 portnum; /* Parent port number (origin 1) */
++ u8 level; /* Number of USB hub ancestors */
+
+ int have_langid; /* whether string_langid is valid */
+ int string_langid; /* language ID for strings */
+@@ -373,6 +379,15 @@ struct usb_device {
+
+ int maxchild; /* Number of ports if hub */
+ struct usb_device *children[USB_MAXCHILDREN];
++
++ int pm_usage_cnt; /* usage counter for autosuspend */
++#ifdef CONFIG_PM
++ struct work_struct autosuspend; /* for delayed autosuspends */
++ struct mutex pm_mutex; /* protects PM operations */
++
++ unsigned auto_pm:1; /* autosuspend/resume in progress */
++ unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */
++#endif
+ };
+ #define to_usb_device(d) container_of(d, struct usb_device, dev)
+
+@@ -384,7 +399,7 @@ extern void usb_put_dev(struct usb_devic
+ #define usb_unlock_device(udev) up(&(udev)->dev.sem)
+ #define usb_trylock_device(udev) down_trylock(&(udev)->dev.sem)
+ extern int usb_lock_device_for_reset(struct usb_device *udev,
+- struct usb_interface *iface);
++ const struct usb_interface *iface);
+
+ /* USB port reset for device reinitialization */
+ extern int usb_reset_device(struct usb_device *dev);
+@@ -393,6 +408,17 @@ extern int usb_reset_composite_device(st
+
+ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
+
++/* USB autosuspend and autoresume */
++#ifdef CONFIG_USB_SUSPEND
++extern int usb_autopm_get_interface(struct usb_interface *intf);
++extern void usb_autopm_put_interface(struct usb_interface *intf);
++
++#else
++#define usb_autopm_get_interface(intf) 0
++#define usb_autopm_put_interface(intf) do {} while (0)
++#endif
++
++
+ /*-------------------------------------------------------------------------*/
+
+ /* for drivers using iso endpoints */
+@@ -423,10 +449,10 @@ const struct usb_device_id *usb_match_id
+
+ extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
+ int minor);
+-extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev,
++extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
+ unsigned ifnum);
+ extern struct usb_host_interface *usb_altnum_to_altsetting(
+- struct usb_interface *intf, unsigned int altnum);
++ const struct usb_interface *intf, unsigned int altnum);
+
+
+ /**
+@@ -464,6 +490,20 @@ static inline int usb_make_path (struct
+
+ /*-------------------------------------------------------------------------*/
+
++extern int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd);
++extern int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd);
++
++/*-------------------------------------------------------------------------*/
++
+ #define USB_DEVICE_ID_MATCH_DEVICE \
+ (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+ #define USB_DEVICE_ID_MATCH_DEV_RANGE \
+@@ -540,7 +580,17 @@ struct usb_dynids {
+ };
+
+ /**
+- * struct usb_driver - identifies USB driver to usbcore
++ * struct usbdrv_wrap - wrapper for driver-model structure
++ * @driver: The driver-model core driver structure.
++ * @for_devices: Non-zero for device drivers, 0 for interface drivers.
++ */
++struct usbdrv_wrap {
++ struct device_driver driver;
++ int for_devices;
++};
++
++/**
++ * struct usb_driver - identifies USB interface driver to usbcore
+ * @name: The driver name should be unique among USB drivers,
+ * and should normally be the same as the module name.
+ * @probe: Called to see if the driver is willing to manage a particular
+@@ -567,12 +617,14 @@ struct usb_dynids {
+ * or your driver's probe function will never get called.
+ * @dynids: used internally to hold the list of dynamically added device
+ * ids for this driver.
+- * @driver: the driver model core driver structure.
++ * @drvwrap: Driver-model core structure wrapper.
+ * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
+ * added to this driver by preventing the sysfs file from being created.
++ * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
++ * for interfaces bound to this driver.
+ *
+- * USB drivers must provide a name, probe() and disconnect() methods,
+- * and an id_table. Other driver fields are optional.
++ * USB interface drivers must provide a name, probe() and disconnect()
++ * methods, and an id_table. Other driver fields are optional.
+ *
+ * The id_table is used in hotplugging. It holds a set of descriptors,
+ * and specialized data may be associated with each entry. That table
+@@ -606,10 +658,44 @@ struct usb_driver {
+ const struct usb_device_id *id_table;
+
+ struct usb_dynids dynids;
+- struct device_driver driver;
++ struct usbdrv_wrap drvwrap;
+ unsigned int no_dynamic_id:1;
++ unsigned int supports_autosuspend:1;
+ };
+-#define to_usb_driver(d) container_of(d, struct usb_driver, driver)
++#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
++
++/**
++ * struct usb_device_driver - identifies USB device driver to usbcore
++ * @name: The driver name should be unique among USB drivers,
++ * and should normally be the same as the module name.
++ * @probe: Called to see if the driver is willing to manage a particular
++ * device. If it is, probe returns zero and uses dev_set_drvdata()
++ * to associate driver-specific data with the device. If unwilling
++ * to manage the device, return a negative errno value.
++ * @disconnect: Called when the device is no longer accessible, usually
++ * because it has been (or is being) disconnected or the driver's
++ * module is being unloaded.
++ * @suspend: Called when the device is going to be suspended by the system.
++ * @resume: Called when the device is being resumed by the system.
++ * @drvwrap: Driver-model core structure wrapper.
++ * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
++ * for devices bound to this driver.
++ *
++ * USB drivers must provide all the fields listed above except drvwrap.
++ */
++struct usb_device_driver {
++ const char *name;
++
++ int (*probe) (struct usb_device *udev);
++ void (*disconnect) (struct usb_device *udev);
++
++ int (*suspend) (struct usb_device *udev, pm_message_t message);
++ int (*resume) (struct usb_device *udev);
++ struct usbdrv_wrap drvwrap;
++ unsigned int supports_autosuspend:1;
++};
++#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
++ drvwrap.driver)
+
+ extern struct bus_type usb_bus_type;
+
+@@ -633,13 +719,17 @@ struct usb_class_driver {
+ * use these in module_init()/module_exit()
+ * and don't forget MODULE_DEVICE_TABLE(usb, ...)
+ */
+-int usb_register_driver(struct usb_driver *, struct module *);
++extern int usb_register_driver(struct usb_driver *, struct module *);
+ static inline int usb_register(struct usb_driver *driver)
+ {
+ return usb_register_driver(driver, THIS_MODULE);
+ }
+ extern void usb_deregister(struct usb_driver *);
+
++extern int usb_register_device_driver(struct usb_device_driver *,
++ struct module *);
++extern void usb_deregister_device_driver(struct usb_device_driver *);
++
+ extern int usb_register_dev(struct usb_interface *intf,
+ struct usb_class_driver *class_driver);
+ extern void usb_deregister_dev(struct usb_interface *intf,
+@@ -674,9 +764,8 @@ struct usb_iso_packet_descriptor {
+ };
+
+ struct urb;
+-struct pt_regs;
+
+-typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
++typedef void (*usb_complete_t)(struct urb *);
+
+ /**
+ * struct urb - USB Request Block
+@@ -885,7 +974,7 @@ struct urb
+ * @setup_packet: pointer to the setup_packet buffer
+ * @transfer_buffer: pointer to the transfer buffer
+ * @buffer_length: length of the transfer buffer
+- * @complete: pointer to the usb_complete_t function
++ * @complete_fn: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ *
+ * Initializes a control urb with the proper information needed to submit
+@@ -897,7 +986,7 @@ static inline void usb_fill_control_urb
+ unsigned char *setup_packet,
+ void *transfer_buffer,
+ int buffer_length,
+- usb_complete_t complete,
++ usb_complete_t complete_fn,
+ void *context)
+ {
+ spin_lock_init(&urb->lock);
+@@ -906,7 +995,7 @@ static inline void usb_fill_control_urb
+ urb->setup_packet = setup_packet;
+ urb->transfer_buffer = transfer_buffer;
+ urb->transfer_buffer_length = buffer_length;
+- urb->complete = complete;
++ urb->complete = complete_fn;
+ urb->context = context;
+ }
+
+@@ -917,7 +1006,7 @@ static inline void usb_fill_control_urb
+ * @pipe: the endpoint pipe
+ * @transfer_buffer: pointer to the transfer buffer
+ * @buffer_length: length of the transfer buffer
+- * @complete: pointer to the usb_complete_t function
++ * @complete_fn: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ *
+ * Initializes a bulk urb with the proper information needed to submit it
+@@ -928,7 +1017,7 @@ static inline void usb_fill_bulk_urb (st
+ unsigned int pipe,
+ void *transfer_buffer,
+ int buffer_length,
+- usb_complete_t complete,
++ usb_complete_t complete_fn,
+ void *context)
+ {
+ spin_lock_init(&urb->lock);
+@@ -936,7 +1025,7 @@ static inline void usb_fill_bulk_urb (st
+ urb->pipe = pipe;
+ urb->transfer_buffer = transfer_buffer;
+ urb->transfer_buffer_length = buffer_length;
+- urb->complete = complete;
++ urb->complete = complete_fn;
+ urb->context = context;
+ }
+
+@@ -947,7 +1036,7 @@ static inline void usb_fill_bulk_urb (st
+ * @pipe: the endpoint pipe
+ * @transfer_buffer: pointer to the transfer buffer
+ * @buffer_length: length of the transfer buffer
+- * @complete: pointer to the usb_complete_t function
++ * @complete_fn: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ * @interval: what to set the urb interval to, encoded like
+ * the endpoint descriptor's bInterval value.
+@@ -963,7 +1052,7 @@ static inline void usb_fill_int_urb (str
+ unsigned int pipe,
+ void *transfer_buffer,
+ int buffer_length,
+- usb_complete_t complete,
++ usb_complete_t complete_fn,
+ void *context,
+ int interval)
+ {
+@@ -972,7 +1061,7 @@ static inline void usb_fill_int_urb (str
+ urb->pipe = pipe;
+ urb->transfer_buffer = transfer_buffer;
+ urb->transfer_buffer_length = buffer_length;
+- urb->complete = complete;
++ urb->complete = complete_fn;
+ urb->context = context;
+ if (dev->speed == USB_SPEED_HIGH)
+ urb->interval = 1 << (interval - 1);
+@@ -990,7 +1079,6 @@ extern int usb_submit_urb(struct urb *ur
+ 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,
+ gfp_t mem_flags, dma_addr_t *dma);
+ void usb_buffer_free (struct usb_device *dev, size_t size,
+@@ -1003,14 +1091,14 @@ void usb_buffer_unmap (struct urb *urb);
+ #endif
+
+ struct scatterlist;
+-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
+- struct scatterlist *sg, int nents);
++int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int nents);
+ #if 0
+-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
+- struct scatterlist *sg, int n_hw_ents);
++void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int n_hw_ents);
+ #endif
+-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
+- struct scatterlist *sg, int n_hw_ents);
++void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int n_hw_ents);
+
+ /*-------------------------------------------------------------------*
+ * SYNCHRONOUS CALL SUPPORT *
+@@ -1038,6 +1126,9 @@ extern int usb_clear_halt(struct usb_dev
+ extern int usb_reset_configuration(struct usb_device *dev);
+ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+
++/* this request isn't really synchronous, but it belongs with the others */
++extern int usb_driver_set_configuration(struct usb_device *udev, int config);
++
+ /*
+ * timeouts, in milliseconds, used for sending/receiving control messages
+ * they typically complete within a few frames (msec) after they're issued
+diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
+new file mode 100644
+index 0000000..6bd2359
+--- /dev/null
++++ b/include/linux/usb/audio.h
+@@ -0,0 +1,53 @@
++/*
++ * <linux/usb/audio.h> -- USB Audio definitions.
++ *
++ * Copyright (C) 2006 Thumtronics Pty Ltd.
++ * Developed for Thumtronics by Grey Innovation
++ * Ben Williamson <ben.williamson at greyinnovation.com>
++ *
++ * This software is distributed under the terms of the GNU General Public
++ * License ("GPL") version 2, as published by the Free Software Foundation.
++ *
++ * This file holds USB constants and structures defined
++ * by the USB Device Class Definition for Audio Devices.
++ * Comments below reference relevant sections of that document:
++ *
++ * http://www.usb.org/developers/devclass_docs/audio10.pdf
++ */
++
++#ifndef __LINUX_USB_AUDIO_H
++#define __LINUX_USB_AUDIO_H
++
++#include <linux/types.h>
++
++/* A.2 Audio Interface Subclass Codes */
++#define USB_SUBCLASS_AUDIOCONTROL 0x01
++#define USB_SUBCLASS_AUDIOSTREAMING 0x02
++#define USB_SUBCLASS_MIDISTREAMING 0x03
++
++/* 4.3.2 Class-Specific AC Interface Descriptor */
++struct usb_ac_header_descriptor {
++ __u8 bLength; // 8+n
++ __u8 bDescriptorType; // USB_DT_CS_INTERFACE
++ __u8 bDescriptorSubtype; // USB_MS_HEADER
++ __le16 bcdADC; // 0x0100
++ __le16 wTotalLength; // includes Unit and Terminal desc.
++ __u8 bInCollection; // n
++ __u8 baInterfaceNr[]; // [n]
++} __attribute__ ((packed));
++
++#define USB_DT_AC_HEADER_SIZE(n) (8+(n))
++
++/* As above, but more useful for defining your own descriptors: */
++#define DECLARE_USB_AC_HEADER_DESCRIPTOR(n) \
++struct usb_ac_header_descriptor_##n { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubtype; \
++ __le16 bcdADC; \
++ __le16 wTotalLength; \
++ __u8 bInCollection; \
++ __u8 baInterfaceNr[n]; \
++} __attribute__ ((packed))
++
++#endif
+diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h
+new file mode 100644
+index 0000000..11a97d5
+--- /dev/null
++++ b/include/linux/usb/midi.h
+@@ -0,0 +1,112 @@
++/*
++ * <linux/usb/midi.h> -- USB MIDI definitions.
++ *
++ * Copyright (C) 2006 Thumtronics Pty Ltd.
++ * Developed for Thumtronics by Grey Innovation
++ * Ben Williamson <ben.williamson at greyinnovation.com>
++ *
++ * This software is distributed under the terms of the GNU General Public
++ * License ("GPL") version 2, as published by the Free Software Foundation.
++ *
++ * This file holds USB constants and structures defined
++ * by the USB Device Class Definition for MIDI Devices.
++ * Comments below reference relevant sections of that document:
++ *
++ * http://www.usb.org/developers/devclass_docs/midi10.pdf
++ */
++
++#ifndef __LINUX_USB_MIDI_H
++#define __LINUX_USB_MIDI_H
++
++#include <linux/types.h>
++
++/* A.1 MS Class-Specific Interface Descriptor Subtypes */
++#define USB_MS_HEADER 0x01
++#define USB_MS_MIDI_IN_JACK 0x02
++#define USB_MS_MIDI_OUT_JACK 0x03
++#define USB_MS_ELEMENT 0x04
++
++/* A.2 MS Class-Specific Endpoint Descriptor Subtypes */
++#define USB_MS_GENERAL 0x01
++
++/* A.3 MS MIDI IN and OUT Jack Types */
++#define USB_MS_EMBEDDED 0x01
++#define USB_MS_EXTERNAL 0x02
++
++/* 6.1.2.1 Class-Specific MS Interface Header Descriptor */
++struct usb_ms_header_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubtype;
++ __le16 bcdMSC;
++ __le16 wTotalLength;
++} __attribute__ ((packed));
++
++#define USB_DT_MS_HEADER_SIZE 7
++
++/* 6.1.2.2 MIDI IN Jack Descriptor */
++struct usb_midi_in_jack_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType; // USB_DT_CS_INTERFACE
++ __u8 bDescriptorSubtype; // USB_MS_MIDI_IN_JACK
++ __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL
++ __u8 bJackID;
++ __u8 iJack;
++} __attribute__ ((packed));
++
++#define USB_DT_MIDI_IN_SIZE 6
++
++struct usb_midi_source_pin {
++ __u8 baSourceID;
++ __u8 baSourcePin;
++} __attribute__ ((packed));
++
++/* 6.1.2.3 MIDI OUT Jack Descriptor */
++struct usb_midi_out_jack_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType; // USB_DT_CS_INTERFACE
++ __u8 bDescriptorSubtype; // USB_MS_MIDI_OUT_JACK
++ __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL
++ __u8 bJackID;
++ __u8 bNrInputPins; // p
++ struct usb_midi_source_pin pins[]; // [p]
++ /*__u8 iJack; -- ommitted due to variable-sized pins[] */
++} __attribute__ ((packed));
++
++#define USB_DT_MIDI_OUT_SIZE(p) (7 + 2 * (p))
++
++/* As above, but more useful for defining your own descriptors: */
++#define DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(p) \
++struct usb_midi_out_jack_descriptor_##p { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubtype; \
++ __u8 bJackType; \
++ __u8 bJackID; \
++ __u8 bNrInputPins; \
++ struct usb_midi_source_pin pins[p]; \
++ __u8 iJack; \
++} __attribute__ ((packed))
++
++/* 6.2.2 Class-Specific MS Bulk Data Endpoint Descriptor */
++struct usb_ms_endpoint_descriptor {
++ __u8 bLength; // 4+n
++ __u8 bDescriptorType; // USB_DT_CS_ENDPOINT
++ __u8 bDescriptorSubtype; // USB_MS_GENERAL
++ __u8 bNumEmbMIDIJack; // n
++ __u8 baAssocJackID[]; // [n]
++} __attribute__ ((packed));
++
++#define USB_DT_MS_ENDPOINT_SIZE(n) (4 + (n))
++
++/* As above, but more useful for defining your own descriptors: */
++#define DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(n) \
++struct usb_ms_endpoint_descriptor_##n { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubtype; \
++ __u8 bNumEmbMIDIJack; \
++ __u8 baAssocJackID[n]; \
++} __attribute__ ((packed))
++
++#endif
+diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
+new file mode 100644
+index 0000000..9897f7a
+--- /dev/null
++++ b/include/linux/usb/otg.h
+@@ -0,0 +1,131 @@
++// include/linux/usb/otg.h
++
++/*
++ * These APIs may be used between USB controllers. USB device drivers
++ * (for either host or peripheral roles) don't use these calls; they
++ * continue to use just usb_device and usb_gadget.
++ */
++
++
++/* OTG defines lots of enumeration states before device reset */
++enum usb_otg_state {
++ OTG_STATE_UNDEFINED = 0,
++
++ /* single-role peripheral, and dual-role default-b */
++ OTG_STATE_B_IDLE,
++ OTG_STATE_B_SRP_INIT,
++ OTG_STATE_B_PERIPHERAL,
++
++ /* extra dual-role default-b states */
++ OTG_STATE_B_WAIT_ACON,
++ OTG_STATE_B_HOST,
++
++ /* dual-role default-a */
++ OTG_STATE_A_IDLE,
++ OTG_STATE_A_WAIT_VRISE,
++ OTG_STATE_A_WAIT_BCON,
++ OTG_STATE_A_HOST,
++ OTG_STATE_A_SUSPEND,
++ OTG_STATE_A_PERIPHERAL,
++ OTG_STATE_A_WAIT_VFALL,
++ OTG_STATE_A_VBUS_ERR,
++};
++
++/*
++ * the otg driver needs to interact with both device side and host side
++ * usb controllers. it decides which controller is active at a given
++ * moment, using the transceiver, ID signal, HNP and sometimes static
++ * configuration information (including "board isn't wired for otg").
++ */
++struct otg_transceiver {
++ struct device *dev;
++ const char *label;
++
++ u8 default_a;
++ enum usb_otg_state state;
++
++ struct usb_bus *host;
++ struct usb_gadget *gadget;
++
++ /* to pass extra port status to the root hub */
++ u16 port_status;
++ u16 port_change;
++
++ /* bind/unbind the host controller */
++ int (*set_host)(struct otg_transceiver *otg,
++ struct usb_bus *host);
++
++ /* bind/unbind the peripheral controller */
++ int (*set_peripheral)(struct otg_transceiver *otg,
++ struct usb_gadget *gadget);
++
++ /* effective for B devices, ignored for A-peripheral */
++ int (*set_power)(struct otg_transceiver *otg,
++ unsigned mA);
++
++ /* for non-OTG B devices: set transceiver into suspend mode */
++ int (*set_suspend)(struct otg_transceiver *otg,
++ int suspend);
++
++ /* for B devices only: start session with A-Host */
++ int (*start_srp)(struct otg_transceiver *otg);
++
++ /* start or continue HNP role switch */
++ int (*start_hnp)(struct otg_transceiver *otg);
++
++};
++
++
++/* for board-specific init logic */
++extern int otg_set_transceiver(struct otg_transceiver *);
++
++
++/* for usb host and peripheral controller drivers */
++extern struct otg_transceiver *otg_get_transceiver(void);
++
++static inline int
++otg_start_hnp(struct otg_transceiver *otg)
++{
++ return otg->start_hnp(otg);
++}
++
++
++/* for HCDs */
++static inline int
++otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
++{
++ return otg->set_host(otg, host);
++}
++
++
++/* for usb peripheral controller drivers */
++static inline int
++otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph)
++{
++ return otg->set_peripheral(otg, periph);
++}
++
++static inline int
++otg_set_power(struct otg_transceiver *otg, unsigned mA)
++{
++ return otg->set_power(otg, mA);
++}
++
++static inline int
++otg_set_suspend(struct otg_transceiver *otg, int suspend)
++{
++ if (otg->set_suspend != NULL)
++ return otg->set_suspend(otg, suspend);
++ else
++ return 0;
++}
++
++static inline int
++otg_start_srp(struct otg_transceiver *otg)
++{
++ return otg->start_srp(otg);
++}
++
++
++/* for OTG controller drivers (and maybe other stuff) */
++extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
+diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
+index 91c983e..91b3ea2 100644
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -226,10 +226,10 @@ struct usb_serial_driver {
+ int (*tiocmget) (struct usb_serial_port *port, struct file *file);
+ int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
+
+- void (*read_int_callback)(struct urb *urb, struct pt_regs *regs);
+- void (*write_int_callback)(struct urb *urb, struct pt_regs *regs);
+- void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
+- void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
++ void (*read_int_callback)(struct urb *urb);
++ void (*write_int_callback)(struct urb *urb);
++ void (*read_bulk_callback)(struct urb *urb);
++ void (*write_bulk_callback)(struct urb *urb);
+ };
+ #define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
+
+@@ -262,8 +262,8 @@ extern int usb_serial_generic_write (str
+ extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
+ extern int usb_serial_generic_write_room (struct usb_serial_port *port);
+ extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
+-extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+-extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
++extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
++extern void usb_serial_generic_write_bulk_callback (struct urb *urb);
+ extern void usb_serial_generic_shutdown (struct usb_serial *serial);
+ extern int usb_serial_generic_register (int debug);
+ extern void usb_serial_generic_deregister (void);
+diff --git a/include/linux/usb_otg.h b/include/linux/usb_otg.h
+deleted file mode 100644
+index f827f6e..0000000
+--- a/include/linux/usb_otg.h
++++ /dev/null
+@@ -1,131 +0,0 @@
+-// include/linux/usb_otg.h
+-
+-/*
+- * These APIs may be used between USB controllers. USB device drivers
+- * (for either host or peripheral roles) don't use these calls; they
+- * continue to use just usb_device and usb_gadget.
+- */
+-
+-
+-/* OTG defines lots of enumeration states before device reset */
+-enum usb_otg_state {
+- OTG_STATE_UNDEFINED = 0,
+-
+- /* single-role peripheral, and dual-role default-b */
+- OTG_STATE_B_IDLE,
+- OTG_STATE_B_SRP_INIT,
+- OTG_STATE_B_PERIPHERAL,
+-
+- /* extra dual-role default-b states */
+- OTG_STATE_B_WAIT_ACON,
+- OTG_STATE_B_HOST,
+-
+- /* dual-role default-a */
+- OTG_STATE_A_IDLE,
+- OTG_STATE_A_WAIT_VRISE,
+- OTG_STATE_A_WAIT_BCON,
+- OTG_STATE_A_HOST,
+- OTG_STATE_A_SUSPEND,
+- OTG_STATE_A_PERIPHERAL,
+- OTG_STATE_A_WAIT_VFALL,
+- OTG_STATE_A_VBUS_ERR,
+-};
+-
+-/*
+- * the otg driver needs to interact with both device side and host side
+- * usb controllers. it decides which controller is active at a given
+- * moment, using the transceiver, ID signal, HNP and sometimes static
+- * configuration information (including "board isn't wired for otg").
+- */
+-struct otg_transceiver {
+- struct device *dev;
+- const char *label;
+-
+- u8 default_a;
+- enum usb_otg_state state;
+-
+- struct usb_bus *host;
+- struct usb_gadget *gadget;
+-
+- /* to pass extra port status to the root hub */
+- u16 port_status;
+- u16 port_change;
+-
+- /* bind/unbind the host controller */
+- int (*set_host)(struct otg_transceiver *otg,
+- struct usb_bus *host);
+-
+- /* bind/unbind the peripheral controller */
+- int (*set_peripheral)(struct otg_transceiver *otg,
+- struct usb_gadget *gadget);
+-
+- /* effective for B devices, ignored for A-peripheral */
+- int (*set_power)(struct otg_transceiver *otg,
+- unsigned mA);
+-
+- /* for non-OTG B devices: set transceiver into suspend mode */
+- int (*set_suspend)(struct otg_transceiver *otg,
+- int suspend);
+-
+- /* for B devices only: start session with A-Host */
+- int (*start_srp)(struct otg_transceiver *otg);
+-
+- /* start or continue HNP role switch */
+- int (*start_hnp)(struct otg_transceiver *otg);
+-
+-};
+-
+-
+-/* for board-specific init logic */
+-extern int otg_set_transceiver(struct otg_transceiver *);
+-
+-
+-/* for usb host and peripheral controller drivers */
+-extern struct otg_transceiver *otg_get_transceiver(void);
+-
+-static inline int
+-otg_start_hnp(struct otg_transceiver *otg)
+-{
+- return otg->start_hnp(otg);
+-}
+-
+-
+-/* for HCDs */
+-static inline int
+-otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+-{
+- return otg->set_host(otg, host);
+-}
+-
+-
+-/* for usb peripheral controller drivers */
+-static inline int
+-otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph)
+-{
+- return otg->set_peripheral(otg, periph);
+-}
+-
+-static inline int
+-otg_set_power(struct otg_transceiver *otg, unsigned mA)
+-{
+- return otg->set_power(otg, mA);
+-}
+-
+-static inline int
+-otg_set_suspend(struct otg_transceiver *otg, int suspend)
+-{
+- if (otg->set_suspend != NULL)
+- return otg->set_suspend(otg, suspend);
+- else
+- return 0;
+-}
+-
+-static inline int
+-otg_start_srp(struct otg_transceiver *otg)
+-{
+- return otg->start_srp(otg);
+-}
+-
+-
+-/* for OTG controller drivers (and maybe other stuff) */
+-extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
+diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
+index e7fc5fe..2ae76fe 100644
+--- a/include/linux/usb_usual.h
++++ b/include/linux/usb_usual.h
+@@ -108,6 +108,9 @@ enum { US_DO_ALL_FLAGS };
+ #ifdef CONFIG_USB_STORAGE_ALAUDA
+ #define US_PR_ALAUDA 0xf4 /* Alauda chipsets */
+ #endif
++#ifdef CONFIG_USB_STORAGE_KARMA
++#define US_PR_KARMA 0xf5 /* Rio Karma */
++#endif
+
+ #define US_PR_DEVICE 0xff /* Use device's value */
+
+diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
+index 7b7aadb..617d8a1 100644
+--- a/include/linux/usbdevice_fs.h
++++ b/include/linux/usbdevice_fs.h
+@@ -32,11 +32,10 @@
+ #define _LINUX_USBDEVICE_FS_H
+
+ #include <linux/types.h>
++#include <linux/magic.h>
+
+ /* --------------------------------------------------------------------- */
+
+-#define USBDEVICE_SUPER_MAGIC 0x9fa2
+-
+ /* usbdevfs ioctl codes */
+
+ struct usbdevfs_ctrltransfer {
+diff --git a/include/linux/utime.h b/include/linux/utime.h
+index c6bf27b..640be6a 100644
+--- a/include/linux/utime.h
++++ b/include/linux/utime.h
+@@ -1,6 +1,8 @@
+ #ifndef _LINUX_UTIME_H
+ #define _LINUX_UTIME_H
+
++#include <linux/types.h>
++
+ struct utimbuf {
+ time_t actime;
+ time_t modtime;
+diff --git a/include/linux/utsname.h b/include/linux/utsname.h
+index 13e1da0..a4555fe 100644
+--- a/include/linux/utsname.h
++++ b/include/linux/utsname.h
+@@ -30,7 +30,65 @@ struct new_utsname {
+ char domainname[65];
+ };
+
+-extern struct new_utsname system_utsname;
++#ifdef __KERNEL__
+
+-extern struct rw_semaphore uts_sem;
++#include <linux/sched.h>
++#include <linux/kref.h>
++#include <linux/nsproxy.h>
++#include <asm/atomic.h>
++
++struct uts_namespace {
++ struct kref kref;
++ struct new_utsname name;
++};
++extern struct uts_namespace init_uts_ns;
++
++static inline void get_uts_ns(struct uts_namespace *ns)
++{
++ kref_get(&ns->kref);
++}
++
++#ifdef CONFIG_UTS_NS
++extern int unshare_utsname(unsigned long unshare_flags,
++ struct uts_namespace **new_uts);
++extern int copy_utsname(int flags, struct task_struct *tsk);
++extern void free_uts_ns(struct kref *kref);
++
++static inline void put_uts_ns(struct uts_namespace *ns)
++{
++ kref_put(&ns->kref, free_uts_ns);
++}
++#else
++static inline int unshare_utsname(unsigned long unshare_flags,
++ struct uts_namespace **new_uts)
++{
++ if (unshare_flags & CLONE_NEWUTS)
++ return -EINVAL;
++
++ return 0;
++}
++
++static inline int copy_utsname(int flags, struct task_struct *tsk)
++{
++ return 0;
++}
++static inline void put_uts_ns(struct uts_namespace *ns)
++{
++}
+ #endif
++
++static inline struct new_utsname *utsname(void)
++{
++ return ¤t->nsproxy->uts_ns->name;
++}
++
++static inline struct new_utsname *init_utsname(void)
++{
++ return &init_uts_ns.name;
++}
++
++extern struct rw_semaphore uts_sem;
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_UTSNAME_H */
+diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h
+index 46919f9..4d0909e 100644
+--- a/include/linux/vermagic.h
++++ b/include/linux/vermagic.h
+@@ -24,5 +24,5 @@
+ #define VERMAGIC_STRING \
+ UTS_RELEASE " " \
+ MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
+- MODULE_VERMAGIC_MODULE_UNLOAD MODULE_ARCH_VERMAGIC \
+- "gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
++ MODULE_VERMAGIC_MODULE_UNLOAD MODULE_ARCH_VERMAGIC
++
+diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
+index e3715d7..df5c465 100644
+--- a/include/linux/videodev2.h
++++ b/include/linux/videodev2.h
+@@ -243,7 +243,7 @@ struct v4l2_pix_format
+ #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */
+ #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */
+ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */
+-#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:1:1 16x16 macroblocks */
++#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */
+
+ /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
+ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
+@@ -276,6 +276,82 @@ struct v4l2_fmtdesc
+
+ #define V4L2_FMT_FLAG_COMPRESSED 0x0001
+
++#if 1
++ /* Experimental Frame Size and frame rate enumeration */
++/*
++ * F R A M E S I Z E E N U M E R A T I O N
++ */
++enum v4l2_frmsizetypes
++{
++ V4L2_FRMSIZE_TYPE_DISCRETE = 1,
++ V4L2_FRMSIZE_TYPE_CONTINUOUS = 2,
++ V4L2_FRMSIZE_TYPE_STEPWISE = 3,
++};
++
++struct v4l2_frmsize_discrete
++{
++ __u32 width; /* Frame width [pixel] */
++ __u32 height; /* Frame height [pixel] */
++};
++
++struct v4l2_frmsize_stepwise
++{
++ __u32 min_width; /* Minimum frame width [pixel] */
++ __u32 max_width; /* Maximum frame width [pixel] */
++ __u32 step_width; /* Frame width step size [pixel] */
++ __u32 min_height; /* Minimum frame height [pixel] */
++ __u32 max_height; /* Maximum frame height [pixel] */
++ __u32 step_height; /* Frame height step size [pixel] */
++};
++
++struct v4l2_frmsizeenum
++{
++ __u32 index; /* Frame size number */
++ __u32 pixel_format; /* Pixel format */
++ __u32 type; /* Frame size type the device supports. */
++
++ union { /* Frame size */
++ struct v4l2_frmsize_discrete discrete;
++ struct v4l2_frmsize_stepwise stepwise;
++ };
++
++ __u32 reserved[2]; /* Reserved space for future use */
++};
++
++/*
++ * F R A M E R A T E E N U M E R A T I O N
++ */
++enum v4l2_frmivaltypes
++{
++ V4L2_FRMIVAL_TYPE_DISCRETE = 1,
++ V4L2_FRMIVAL_TYPE_CONTINUOUS = 2,
++ V4L2_FRMIVAL_TYPE_STEPWISE = 3,
++};
++
++struct v4l2_frmival_stepwise
++{
++ struct v4l2_fract min; /* Minimum frame interval [s] */
++ struct v4l2_fract max; /* Maximum frame interval [s] */
++ struct v4l2_fract step; /* Frame interval step size [s] */
++};
++
++struct v4l2_frmivalenum
++{
++ __u32 index; /* Frame format index */
++ __u32 pixel_format; /* Pixel format */
++ __u32 width; /* Frame width */
++ __u32 height; /* Frame height */
++ __u32 type; /* Frame interval type the device supports. */
++
++ union { /* Frame interval */
++ struct v4l2_fract discrete;
++ struct v4l2_frmival_stepwise stepwise;
++ };
++
++ __u32 reserved[2]; /* Reserved space for future use */
++};
++#endif
++
+ /*
+ * T I M E C O D E
+ */
+@@ -1135,7 +1211,8 @@ struct v4l2_sliced_vbi_cap
+ (equals frame lines 313-336 for 625 line video
+ standards, 263-286 for 525 line standards) */
+ __u16 service_lines[2][24];
+- __u32 reserved[4]; /* must be 0 */
++ enum v4l2_buf_type type;
++ __u32 reserved[3]; /* must be 0 */
+ };
+
+ struct v4l2_sliced_vbi_data
+@@ -1242,12 +1319,16 @@ struct v4l2_streamparm
+ #define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority)
+ #define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority)
+ #if 1
+-#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap)
++#define VIDIOC_G_SLICED_VBI_CAP _IOWR ('V', 69, struct v4l2_sliced_vbi_cap)
+ #endif
+ #define VIDIOC_LOG_STATUS _IO ('V', 70)
+ #define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls)
+ #define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls)
+ #define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls)
++#if 1
++#define VIDIOC_ENUM_FRAMESIZES _IOWR ('V', 74, struct v4l2_frmsizeenum)
++#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR ('V', 75, struct v4l2_frmivalenum)
++#endif
+
+ #ifdef __OLD_VIDIOC_
+ /* for compatibility, will go away some day */
+diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
+index 71b6363..dc9a29d 100644
+--- a/include/linux/vmalloc.h
++++ b/include/linux/vmalloc.h
+@@ -44,8 +44,6 @@ extern void *vmalloc_32_user(unsigned lo
+ extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
+ extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask,
+ pgprot_t prot);
+-extern void *__vmalloc_node(unsigned long size, gfp_t gfp_mask,
+- pgprot_t prot, int node);
+ extern void vfree(void *addr);
+
+ extern void *vmap(struct page **pages, unsigned int count,
+@@ -62,9 +60,9 @@ extern struct vm_struct *get_vm_area(uns
+ extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
+ unsigned long start, unsigned long end);
+ extern struct vm_struct *get_vm_area_node(unsigned long size,
+- unsigned long flags, int node);
++ unsigned long flags, int node,
++ gfp_t gfp_mask);
+ extern struct vm_struct *remove_vm_area(void *addr);
+-extern struct vm_struct *__remove_vm_area(void *addr);
+ extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
+ struct page ***pages);
+ extern void unmap_vm_area(struct vm_struct *area);
+diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
+index 2d9b1b6..c89df55 100644
+--- a/include/linux/vmstat.h
++++ b/include/linux/vmstat.h
+@@ -3,7 +3,6 @@
+
+ #include <linux/types.h>
+ #include <linux/percpu.h>
+-#include <linux/config.h>
+ #include <linux/mmzone.h>
+ #include <asm/atomic.h>
+
+@@ -18,7 +17,19 @@
+ * generated will simply be the increment of a global address.
+ */
+
+-#define FOR_ALL_ZONES(x) x##_DMA, x##_DMA32, x##_NORMAL, x##_HIGH
++#ifdef CONFIG_ZONE_DMA32
++#define DMA32_ZONE(xx) xx##_DMA32,
++#else
++#define DMA32_ZONE(xx)
++#endif
++
++#ifdef CONFIG_HIGHMEM
++#define HIGHMEM_ZONE(xx) , xx##_HIGH
++#else
++#define HIGHMEM_ZONE(xx)
++#endif
++
++#define FOR_ALL_ZONES(xx) xx##_DMA, DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx)
+
+ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
+ FOR_ALL_ZONES(PGALLOC),
+@@ -124,12 +135,10 @@ static inline unsigned long node_page_st
+ struct zone *zones = NODE_DATA(node)->node_zones;
+
+ return
+-#ifndef CONFIG_DMA_IS_NORMAL
+-#if !defined(CONFIG_DMA_IS_DMA32) && BITS_PER_LONG >= 64
++#ifdef CONFIG_ZONE_DMA32
+ zone_page_state(&zones[ZONE_DMA32], item) +
+ #endif
+ zone_page_state(&zones[ZONE_NORMAL], item) +
+-#endif
+ #ifdef CONFIG_HIGHMEM
+ zone_page_state(&zones[ZONE_HIGHMEM], item) +
+ #endif
+diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
+index 918a297..37a1a41 100644
+--- a/include/linux/vt_kern.h
++++ b/include/linux/vt_kern.h
+@@ -33,7 +33,8 @@ extern int fg_console, last_console, wan
+ int vc_allocate(unsigned int console);
+ int vc_cons_allocated(unsigned int console);
+ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
+-void vc_disallocate(unsigned int console);
++int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
++void vc_deallocate(unsigned int console);
+ void reset_palette(struct vc_data *vc);
+ void do_blank_screen(int entering_gfx);
+ void do_unblank_screen(int leaving_gfx);
+@@ -83,4 +84,11 @@ void reset_vc(struct vc_data *vc);
+ extern char con_buf[CON_BUF_SIZE];
+ extern struct semaphore con_buf_sem;
+
++struct vt_spawn_console {
++ spinlock_t lock;
++ struct pid *pid;
++ int sig;
++};
++extern struct vt_spawn_console vt_spawn_con;
++
+ #endif /* _VT_KERN_H */
+diff --git a/include/linux/wait.h b/include/linux/wait.h
+index b3b9048..e820d00 100644
+--- a/include/linux/wait.h
++++ b/include/linux/wait.h
+@@ -79,6 +79,15 @@ struct task_struct;
+
+ extern void init_waitqueue_head(wait_queue_head_t *q);
+
++#ifdef CONFIG_LOCKDEP
++# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \
++ ({ init_waitqueue_head(&name); name; })
++# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) \
++ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INIT_ONSTACK(name)
++#else
++# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name)
++#endif
++
+ static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
+ {
+ q->flags = 0;
+diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h
+deleted file mode 100644
+index 51ab3c9..0000000
+--- a/include/linux/wavefront.h
++++ /dev/null
+@@ -1,675 +0,0 @@
+-#ifndef __wavefront_h__
+-#define __wavefront_h__
+-
+-/* WaveFront header file.
+- *
+- * Copyright (C) by Paul Barton-Davis 1998
+- *
+- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- */
+-
+-#if (!defined(__GNUC__) && !defined(__GNUG__))
+-
+- You will not be able to compile this file correctly without gcc, because
+- it is necessary to pack the "wavefront_alias" structure to a size
+- of 22 bytes, corresponding to 16-bit alignment (as would have been
+- the case on the original platform, MS-DOS). If this is not done,
+- then WavePatch-format files cannot be read/written correctly.
+- The method used to do this here ("__attribute__((packed)") is
+- completely compiler dependent.
+-
+- All other wavefront_* types end up aligned to 32 bit values and
+- still have the same (correct) size.
+-
+-#else
+-
+- /* However, note that as of G++ 2.7.3.2, g++ was unable to
+- correctly parse *type* __attribute__ tags. It will do the
+- right thing if we use the "packed" attribute on each struct
+- member, which has the same semantics anyway.
+- */
+-
+-#endif /* __GNUC__ */
+-
+-/***************************** WARNING ********************************
+- PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO
+- BE USED WITH EITHER C *OR* C++.
+- **********************************************************************/
+-
+-#ifndef NUM_MIDIKEYS
+-#define NUM_MIDIKEYS 128
+-#endif /* NUM_MIDIKEYS */
+-
+-#ifndef NUM_MIDICHANNELS
+-#define NUM_MIDICHANNELS 16
+-#endif /* NUM_MIDICHANNELS */
+-
+-/* These are very useful/important. the original wavefront interface
+- was developed on a 16 bit system, where sizeof(int) = 2
+- bytes. Defining things like this makes the code much more portable, and
+- easier to understand without having to toggle back and forth
+- between a 16-bit view of the world and a 32-bit one.
+- */
+-
+-typedef short INT16;
+-typedef unsigned short UINT16;
+-typedef int INT32;
+-typedef unsigned int UINT32;
+-typedef char CHAR8;
+-typedef unsigned char UCHAR8;
+-
+-/* Pseudo-commands not part of the WaveFront command set.
+- These are used for various driver controls and direct
+- hardware control.
+- */
+-
+-#define WFC_DEBUG_DRIVER 0
+-#define WFC_FX_IOCTL 1
+-#define WFC_PATCH_STATUS 2
+-#define WFC_PROGRAM_STATUS 3
+-#define WFC_SAMPLE_STATUS 4
+-#define WFC_DISABLE_INTERRUPTS 5
+-#define WFC_ENABLE_INTERRUPTS 6
+-#define WFC_INTERRUPT_STATUS 7
+-#define WFC_ROMSAMPLES_RDONLY 8
+-#define WFC_IDENTIFY_SLOT_TYPE 9
+-
+-/* Wavefront synth commands
+- */
+-
+-#define WFC_DOWNLOAD_SAMPLE 0x80
+-#define WFC_DOWNLOAD_BLOCK 0x81
+-#define WFC_DOWNLOAD_MULTISAMPLE 0x82
+-#define WFC_DOWNLOAD_SAMPLE_ALIAS 0x83
+-#define WFC_DELETE_SAMPLE 0x84
+-#define WFC_REPORT_FREE_MEMORY 0x85
+-#define WFC_DOWNLOAD_PATCH 0x86
+-#define WFC_DOWNLOAD_PROGRAM 0x87
+-#define WFC_SET_SYNTHVOL 0x89
+-#define WFC_SET_NVOICES 0x8B
+-#define WFC_DOWNLOAD_DRUM 0x90
+-#define WFC_GET_SYNTHVOL 0x92
+-#define WFC_GET_NVOICES 0x94
+-#define WFC_DISABLE_CHANNEL 0x9A
+-#define WFC_ENABLE_CHANNEL 0x9B
+-#define WFC_MISYNTH_OFF 0x9D
+-#define WFC_MISYNTH_ON 0x9E
+-#define WFC_FIRMWARE_VERSION 0x9F
+-#define WFC_GET_NSAMPLES 0xA0
+-#define WFC_DISABLE_DRUM_PROGRAM 0xA2
+-#define WFC_UPLOAD_PATCH 0xA3
+-#define WFC_UPLOAD_PROGRAM 0xA4
+-#define WFC_SET_TUNING 0xA6
+-#define WFC_GET_TUNING 0xA7
+-#define WFC_VMIDI_ON 0xA8
+-#define WFC_VMIDI_OFF 0xA9
+-#define WFC_MIDI_STATUS 0xAA
+-#define WFC_GET_CHANNEL_STATUS 0xAB
+-#define WFC_DOWNLOAD_SAMPLE_HEADER 0xAC
+-#define WFC_UPLOAD_SAMPLE_HEADER 0xAD
+-#define WFC_UPLOAD_MULTISAMPLE 0xAE
+-#define WFC_UPLOAD_SAMPLE_ALIAS 0xAF
+-#define WFC_IDENTIFY_SAMPLE_TYPE 0xB0
+-#define WFC_DOWNLOAD_EDRUM_PROGRAM 0xB1
+-#define WFC_UPLOAD_EDRUM_PROGRAM 0xB2
+-#define WFC_SET_EDRUM_CHANNEL 0xB3
+-#define WFC_INSTOUT_LEVELS 0xB4
+-#define WFC_PEAKOUT_LEVELS 0xB5
+-#define WFC_REPORT_CHANNEL_PROGRAMS 0xB6
+-#define WFC_HARDWARE_VERSION 0xCF
+-#define WFC_UPLOAD_SAMPLE_PARAMS 0xD7
+-#define WFC_DOWNLOAD_OS 0xF1
+-#define WFC_NOOP 0xFF
+-
+-#define WF_MAX_SAMPLE 512
+-#define WF_MAX_PATCH 256
+-#define WF_MAX_PROGRAM 128
+-
+-#define WF_SECTION_MAX 44 /* longest OS section length */
+-
+-/* # of bytes we send to the board when sending it various kinds of
+- substantive data, such as samples, patches and programs.
+-*/
+-
+-#define WF_PROGRAM_BYTES 32
+-#define WF_PATCH_BYTES 132
+-#define WF_SAMPLE_BYTES 27
+-#define WF_SAMPLE_HDR_BYTES 25
+-#define WF_ALIAS_BYTES 25
+-#define WF_DRUM_BYTES 9
+-#define WF_MSAMPLE_BYTES 259 /* (MIDI_KEYS * 2) + 3 */
+-
+-#define WF_ACK 0x80
+-#define WF_DMA_ACK 0x81
+-
+-/* OR-values for MIDI status bits */
+-
+-#define WF_MIDI_VIRTUAL_ENABLED 0x1
+-#define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2
+-#define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4
+-
+-/* slot indexes for struct address_info: makes code a little more mnemonic */
+-
+-#define WF_SYNTH_SLOT 0
+-#define WF_INTERNAL_MIDI_SLOT 1
+-#define WF_EXTERNAL_MIDI_SLOT 2
+-
+-/* Magic MIDI bytes used to switch I/O streams on the ICS2115 MPU401
+- emulation. Note these NEVER show up in output from the device and
+- should NEVER be used in input unless Virtual MIDI mode has been
+- disabled. If they do show up as input, the results are unpredictable.
+-*/
+-
+-#define WF_EXTERNAL_SWITCH 0xFD
+-#define WF_INTERNAL_SWITCH 0xF9
+-
+-/* Debugging flags */
+-
+-#define WF_DEBUG_CMD 0x1
+-#define WF_DEBUG_DATA 0x2
+-#define WF_DEBUG_LOAD_PATCH 0x4
+-#define WF_DEBUG_IO 0x8
+-
+-/* WavePatch file format stuff */
+-
+-#define WF_WAVEPATCH_VERSION 120; /* Current version number (1.2) */
+-#define WF_MAX_COMMENT 64 /* Comment length */
+-#define WF_NUM_LAYERS 4
+-#define WF_NAME_LENGTH 32
+-#define WF_SOURCE_LENGTH 260
+-
+-#define BankFileID "Bank"
+-#define DrumkitFileID "DrumKit"
+-#define ProgramFileID "Program"
+-
+-struct wf_envelope
+-{
+- UCHAR8 attack_time:7;
+- UCHAR8 Unused1:1;
+-
+- UCHAR8 decay1_time:7;
+- UCHAR8 Unused2:1;
+-
+- UCHAR8 decay2_time:7;
+- UCHAR8 Unused3:1;
+-
+- UCHAR8 sustain_time:7;
+- UCHAR8 Unused4:1;
+-
+- UCHAR8 release_time:7;
+- UCHAR8 Unused5:1;
+-
+- UCHAR8 release2_time:7;
+- UCHAR8 Unused6:1;
+-
+- CHAR8 attack_level;
+- CHAR8 decay1_level;
+- CHAR8 decay2_level;
+- CHAR8 sustain_level;
+- CHAR8 release_level;
+-
+- UCHAR8 attack_velocity:7;
+- UCHAR8 Unused7:1;
+-
+- UCHAR8 volume_velocity:7;
+- UCHAR8 Unused8:1;
+-
+- UCHAR8 keyboard_scaling:7;
+- UCHAR8 Unused9:1;
+-};
+-typedef struct wf_envelope wavefront_envelope;
+-
+-struct wf_lfo
+-{
+- UCHAR8 sample_number;
+-
+- UCHAR8 frequency:7;
+- UCHAR8 Unused1:1;
+-
+- UCHAR8 am_src:4;
+- UCHAR8 fm_src:4;
+-
+- CHAR8 fm_amount;
+- CHAR8 am_amount;
+- CHAR8 start_level;
+- CHAR8 end_level;
+-
+- UCHAR8 ramp_delay:7;
+- UCHAR8 wave_restart:1; /* for LFO2 only */
+-
+- UCHAR8 ramp_time:7;
+- UCHAR8 Unused2:1;
+-};
+-typedef struct wf_lfo wavefront_lfo;
+-
+-struct wf_patch
+-{
+- INT16 frequency_bias; /* ** THIS IS IN MOTOROLA FORMAT!! ** */
+-
+- UCHAR8 amplitude_bias:7;
+- UCHAR8 Unused1:1;
+-
+- UCHAR8 portamento:7;
+- UCHAR8 Unused2:1;
+-
+- UCHAR8 sample_number;
+-
+- UCHAR8 pitch_bend:4;
+- UCHAR8 sample_msb:1;
+- UCHAR8 Unused3:3;
+-
+- UCHAR8 mono:1;
+- UCHAR8 retrigger:1;
+- UCHAR8 nohold:1;
+- UCHAR8 restart:1;
+- UCHAR8 filterconfig:2; /* SDK says "not used" */
+- UCHAR8 reuse:1;
+- UCHAR8 reset_lfo:1;
+-
+- UCHAR8 fm_src2:4;
+- UCHAR8 fm_src1:4;
+-
+- CHAR8 fm_amount1;
+- CHAR8 fm_amount2;
+-
+- UCHAR8 am_src:4;
+- UCHAR8 Unused4:4;
+-
+- CHAR8 am_amount;
+-
+- UCHAR8 fc1_mode:4;
+- UCHAR8 fc2_mode:4;
+-
+- CHAR8 fc1_mod_amount;
+- CHAR8 fc1_keyboard_scaling;
+- CHAR8 fc1_bias;
+- CHAR8 fc2_mod_amount;
+- CHAR8 fc2_keyboard_scaling;
+- CHAR8 fc2_bias;
+-
+- UCHAR8 randomizer:7;
+- UCHAR8 Unused5:1;
+-
+- struct wf_envelope envelope1;
+- struct wf_envelope envelope2;
+- struct wf_lfo lfo1;
+- struct wf_lfo lfo2;
+-};
+-typedef struct wf_patch wavefront_patch;
+-
+-struct wf_layer
+-{
+- UCHAR8 patch_number;
+-
+- UCHAR8 mix_level:7;
+- UCHAR8 mute:1;
+-
+- UCHAR8 split_point:7;
+- UCHAR8 play_below:1;
+-
+- UCHAR8 pan_mod_src:2;
+- UCHAR8 pan_or_mod:1;
+- UCHAR8 pan:4;
+- UCHAR8 split_type:1;
+-};
+-typedef struct wf_layer wavefront_layer;
+-
+-struct wf_program
+-{
+- struct wf_layer layer[WF_NUM_LAYERS];
+-};
+-typedef struct wf_program wavefront_program;
+-
+-struct wf_sample_offset
+-{
+- INT32 Fraction:4;
+- INT32 Integer:20;
+- INT32 Unused:8;
+-};
+-typedef struct wf_sample_offset wavefront_sample_offset;
+-
+-/* Sample slot types */
+-
+-#define WF_ST_SAMPLE 0
+-#define WF_ST_MULTISAMPLE 1
+-#define WF_ST_ALIAS 2
+-#define WF_ST_EMPTY 3
+-
+-/* pseudo's */
+-
+-#define WF_ST_DRUM 4
+-#define WF_ST_PROGRAM 5
+-#define WF_ST_PATCH 6
+-#define WF_ST_SAMPLEHDR 7
+-
+-#define WF_ST_MASK 0xf
+-
+-/* Flags for slot status. These occupy the upper bits of the same byte
+- as a sample type.
+-*/
+-
+-#define WF_SLOT_USED 0x80 /* XXX don't rely on this being accurate */
+-#define WF_SLOT_FILLED 0x40
+-#define WF_SLOT_ROM 0x20
+-
+-#define WF_SLOT_MASK 0xf0
+-
+-/* channel constants */
+-
+-#define WF_CH_MONO 0
+-#define WF_CH_LEFT 1
+-#define WF_CH_RIGHT 2
+-
+-/* Sample formats */
+-
+-#define LINEAR_16BIT 0
+-#define WHITE_NOISE 1
+-#define LINEAR_8BIT 2
+-#define MULAW_8BIT 3
+-
+-#define WF_SAMPLE_IS_8BIT(smpl) ((smpl)->SampleResolution&2)
+-
+-
+-/*
+-
+- Because most/all of the sample data we pass in via pointers has
+- never been copied (just mmap-ed into user space straight from the
+- disk), it would be nice to allow handling of multi-channel sample
+- data without forcing user-level extraction of the relevant bytes.
+-
+- So, we need a way of specifying which channel to use (the WaveFront
+- only handles mono samples in a given slot), and the only way to do
+- this without using some struct other than wavefront_sample as the
+- interface is the awful hack of using the unused bits in a
+- wavefront_sample:
+-
+- Val Meaning
+- --- -------
+- 0 no channel selection (use channel 1, sample is MONO)
+- 1 use first channel, and skip one
+- 2 use second channel, and skip one
+- 3 use third channel, and skip two
+- 4 use fourth channel, skip three
+- 5 use fifth channel, skip four
+- 6 use six channel, skip five
+-
+-
+- This can handle up to 4 channels, and anyone downloading >4 channels
+- of sample data just to select one of them needs to find some tools
+- like sox ...
+-
+- NOTE: values 0, 1 and 2 correspond to WF_CH_* above. This is
+- important.
+-
+-*/
+-
+-#define WF_SET_CHANNEL(samp,chn) \
+- (samp)->Unused1 = chn & 0x1; \
+- (samp)->Unused2 = chn & 0x2; \
+- (samp)->Unused3 = chn & 0x4
+-
+-#define WF_GET_CHANNEL(samp) \
+- (((samp)->Unused3 << 2)|((samp)->Unused2<<1)|(samp)->Unused1)
+-
+-typedef struct wf_sample {
+- struct wf_sample_offset sampleStartOffset;
+- struct wf_sample_offset loopStartOffset;
+- struct wf_sample_offset loopEndOffset;
+- struct wf_sample_offset sampleEndOffset;
+- INT16 FrequencyBias;
+- UCHAR8 SampleResolution:2; /* sample_format */
+- UCHAR8 Unused1:1;
+- UCHAR8 Loop:1;
+- UCHAR8 Bidirectional:1;
+- UCHAR8 Unused2:1;
+- UCHAR8 Reverse:1;
+- UCHAR8 Unused3:1;
+-} wavefront_sample;
+-
+-typedef struct wf_multisample {
+- INT16 NumberOfSamples; /* log2 of the number of samples */
+- INT16 SampleNumber[NUM_MIDIKEYS];
+-} wavefront_multisample;
+-
+-typedef struct wf_alias {
+- INT16 OriginalSample;
+-
+- struct wf_sample_offset sampleStartOffset;
+- struct wf_sample_offset loopStartOffset;
+- struct wf_sample_offset sampleEndOffset;
+- struct wf_sample_offset loopEndOffset;
+-
+- INT16 FrequencyBias;
+-
+- UCHAR8 SampleResolution:2;
+- UCHAR8 Unused1:1;
+- UCHAR8 Loop:1;
+- UCHAR8 Bidirectional:1;
+- UCHAR8 Unused2:1;
+- UCHAR8 Reverse:1;
+- UCHAR8 Unused3:1;
+-
+- /* This structure is meant to be padded only to 16 bits on their
+- original. Of course, whoever wrote their documentation didn't
+- realize that sizeof(struct) can be >=
+- sum(sizeof(struct-fields)) and so thought that giving a C level
+- description of the structs used in WavePatch files was
+- sufficient. I suppose it was, as long as you remember the
+- standard 16->32 bit issues.
+- */
+-
+- UCHAR8 sixteen_bit_padding;
+-} __attribute__((packed)) wavefront_alias;
+-
+-typedef struct wf_drum {
+- UCHAR8 PatchNumber;
+- UCHAR8 MixLevel:7;
+- UCHAR8 Unmute:1;
+- UCHAR8 Group:4;
+- UCHAR8 Unused1:4;
+- UCHAR8 PanModSource:2;
+- UCHAR8 PanModulated:1;
+- UCHAR8 PanAmount:4;
+- UCHAR8 Unused2:1;
+-} wavefront_drum;
+-
+-typedef struct wf_drumkit {
+- struct wf_drum drum[NUM_MIDIKEYS];
+-} wavefront_drumkit;
+-
+-typedef struct wf_channel_programs {
+- UCHAR8 Program[NUM_MIDICHANNELS];
+-} wavefront_channel_programs;
+-
+-/* How to get MIDI channel status from the data returned by
+- a WFC_GET_CHANNEL_STATUS command (a struct wf_channel_programs)
+-*/
+-
+-#define WF_CHANNEL_STATUS(ch,wcp) (wcp)[(ch/7)] & (1<<((ch)%7))
+-
+-typedef union wf_any {
+- wavefront_sample s;
+- wavefront_multisample ms;
+- wavefront_alias a;
+- wavefront_program pr;
+- wavefront_patch p;
+- wavefront_drum d;
+-} wavefront_any;
+-
+-/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h
+- might work for other wave-table based patch loading situations.
+- Alas, his fears were correct. The WaveFront doesn't even come with
+- just "patches", but several different kind of structures that
+- control the sound generation process.
+- */
+-
+-typedef struct wf_patch_info {
+-
+- /* the first two fields are used by the OSS "patch loading" interface
+- only, and are unused by the current user-level library.
+- */
+-
+- INT16 key; /* Use WAVEFRONT_PATCH here */
+- UINT16 devno; /* fill in when sending */
+- UCHAR8 subkey; /* WF_ST_{SAMPLE,ALIAS,etc.} */
+-
+-#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999
+-
+- UINT16 number; /* patch/sample/prog number */
+-
+- UINT32 size; /* size of any data included in
+- one of the fields in `hdrptr', or
+- as `dataptr'.
+-
+- NOTE: for actual samples, this is
+- the size of the *SELECTED CHANNEL*
+- even if more data is actually available.
+-
+- So, a stereo sample (2 channels) of
+- 6000 bytes total has `size' = 3000.
+-
+- See the macros and comments for
+- WF_{GET,SET}_CHANNEL above.
+-
+- */
+- wavefront_any __user *hdrptr; /* user-space ptr to hdr bytes */
+- UINT16 __user *dataptr; /* actual sample data */
+-
+- wavefront_any hdr; /* kernel-space copy of hdr bytes */
+-} wavefront_patch_info;
+-
+-/* The maximum number of bytes we will ever move to or from user space
+- in response to a WFC_* command. This obviously doesn't cover
+- actual sample data.
+-*/
+-
+-#define WF_MAX_READ sizeof(wavefront_multisample)
+-#define WF_MAX_WRITE sizeof(wavefront_multisample)
+-
+-/*
+- This allows us to execute any WF command except the download/upload
+- ones, which are handled differently due to copyin/copyout issues as
+- well as data-nybbling to/from the card.
+- */
+-
+-typedef struct wavefront_control {
+- int cmd; /* WFC_* */
+- char status; /* return status to user-space */
+- unsigned char rbuf[WF_MAX_READ]; /* bytes read from card */
+- unsigned char wbuf[WF_MAX_WRITE]; /* bytes written to card */
+-} wavefront_control;
+-
+-#define WFCTL_WFCMD 0x1
+-#define WFCTL_LOAD_SPP 0x2
+-
+-/* Modulator table */
+-
+-#define WF_MOD_LFO1 0
+-#define WF_MOD_LFO2 1
+-#define WF_MOD_ENV1 2
+-#define WF_MOD_ENV2 3
+-#define WF_MOD_KEYBOARD 4
+-#define WF_MOD_LOGKEY 5
+-#define WF_MOD_VELOCITY 6
+-#define WF_MOD_LOGVEL 7
+-#define WF_MOD_RANDOM 8
+-#define WF_MOD_PRESSURE 9
+-#define WF_MOD_MOD_WHEEL 10
+-#define WF_MOD_1 WF_MOD_MOD_WHEEL
+-#define WF_MOD_BREATH 11
+-#define WF_MOD_2 WF_MOD_BREATH
+-#define WF_MOD_FOOT 12
+-#define WF_MOD_4 WF_MOD_FOOT
+-#define WF_MOD_VOLUME 13
+-#define WF_MOD_7 WF_MOD_VOLUME
+-#define WF_MOD_PAN 14
+-#define WF_MOD_10 WF_MOD_PAN
+-#define WF_MOD_EXPR 15
+-#define WF_MOD_11 WF_MOD_EXPR
+-
+-/* FX-related material */
+-
+-typedef struct wf_fx_info {
+- int request; /* see list below */
+- int data[4]; /* we don't need much */
+-} wavefront_fx_info;
+-
+-/* support for each of these will be forthcoming once I or someone
+- else has figured out which of the addresses on page 6 and page 7 of
+- the YSS225 control each parameter. Incidentally, these come from
+- the Windows driver interface, but again, Turtle Beach didn't
+- document the API to use them.
+-*/
+-
+-#define WFFX_SETOUTGAIN 0
+-#define WFFX_SETSTEREOOUTGAIN 1
+-#define WFFX_SETREVERBIN1GAIN 2
+-#define WFFX_SETREVERBIN2GAIN 3
+-#define WFFX_SETREVERBIN3GAIN 4
+-#define WFFX_SETCHORUSINPORT 5
+-#define WFFX_SETREVERBIN1PORT 6
+-#define WFFX_SETREVERBIN2PORT 7
+-#define WFFX_SETREVERBIN3PORT 8
+-#define WFFX_SETEFFECTPORT 9
+-#define WFFX_SETAUXPORT 10
+-#define WFFX_SETREVERBTYPE 11
+-#define WFFX_SETREVERBDELAY 12
+-#define WFFX_SETCHORUSLFO 13
+-#define WFFX_SETCHORUSPMD 14
+-#define WFFX_SETCHORUSAMD 15
+-#define WFFX_SETEFFECT 16
+-#define WFFX_SETBASEALL 17
+-#define WFFX_SETREVERBALL 18
+-#define WFFX_SETCHORUSALL 20
+-#define WFFX_SETREVERBDEF 22
+-#define WFFX_SETCHORUSDEF 23
+-#define WFFX_DELAYSETINGAIN 24
+-#define WFFX_DELAYSETFBGAIN 25
+-#define WFFX_DELAYSETFBLPF 26
+-#define WFFX_DELAYSETGAIN 27
+-#define WFFX_DELAYSETTIME 28
+-#define WFFX_DELAYSETFBTIME 29
+-#define WFFX_DELAYSETALL 30
+-#define WFFX_DELAYSETDEF 32
+-#define WFFX_SDELAYSETINGAIN 33
+-#define WFFX_SDELAYSETFBGAIN 34
+-#define WFFX_SDELAYSETFBLPF 35
+-#define WFFX_SDELAYSETGAIN 36
+-#define WFFX_SDELAYSETTIME 37
+-#define WFFX_SDELAYSETFBTIME 38
+-#define WFFX_SDELAYSETALL 39
+-#define WFFX_SDELAYSETDEF 41
+-#define WFFX_DEQSETINGAIN 42
+-#define WFFX_DEQSETFILTER 43
+-#define WFFX_DEQSETALL 44
+-#define WFFX_DEQSETDEF 46
+-#define WFFX_MUTE 47
+-#define WFFX_FLANGESETBALANCE 48
+-#define WFFX_FLANGESETDELAY 49
+-#define WFFX_FLANGESETDWFFX_TH 50
+-#define WFFX_FLANGESETFBGAIN 51
+-#define WFFX_FLANGESETINGAIN 52
+-#define WFFX_FLANGESETLFO 53
+-#define WFFX_FLANGESETALL 54
+-#define WFFX_FLANGESETDEF 56
+-#define WFFX_PITCHSETSHIFT 57
+-#define WFFX_PITCHSETBALANCE 58
+-#define WFFX_PITCHSETALL 59
+-#define WFFX_PITCHSETDEF 61
+-#define WFFX_SRSSETINGAIN 62
+-#define WFFX_SRSSETSPACE 63
+-#define WFFX_SRSSETCENTER 64
+-#define WFFX_SRSSETGAIN 65
+-#define WFFX_SRSSETMODE 66
+-#define WFFX_SRSSETDEF 68
+-
+-/* Allow direct user-space control over FX memory/coefficient data.
+- In theory this could be used to download the FX microprogram,
+- but it would be a little slower, and involve some weird code.
+- */
+-
+-#define WFFX_MEMSET 69
+-
+-#endif /* __wavefront_h__ */
+diff --git a/include/linux/wireless.h b/include/linux/wireless.h
+index 1358856..a50a013 100644
+--- a/include/linux/wireless.h
++++ b/include/linux/wireless.h
+@@ -1,7 +1,7 @@
+ /*
+ * This file define a set of standard wireless extensions
+ *
+- * Version : 20 17.2.06
++ * Version : 21 14.3.06
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt at hpl.hp.com>
+ * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
+@@ -69,9 +69,14 @@
+
+ /***************************** INCLUDES *****************************/
+
++/* This header is used in user-space, therefore need to be sanitised
++ * for that purpose. Those includes are usually not compatible with glibc.
++ * To know which includes to use in user-space, check iwlib.h. */
++#ifdef __KERNEL__
+ #include <linux/types.h> /* for "caddr_t" et al */
+ #include <linux/socket.h> /* for "struct sockaddr" et al */
+ #include <linux/if.h> /* for IFNAMSIZ and co... */
++#endif /* __KERNEL__ */
+
+ /***************************** VERSION *****************************/
+ /*
+@@ -80,7 +85,7 @@
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+-#define WIRELESS_EXT 20
++#define WIRELESS_EXT 21
+
+ /*
+ * Changes :
+@@ -208,6 +213,14 @@
+ * V19 to V20
+ * ----------
+ * - RtNetlink requests support (SET/GET)
++ *
++ * V20 to V21
++ * ----------
++ * - Remove (struct net_device *)->get_wireless_stats()
++ * - Change length in ESSID and NICK to strlen() instead of strlen()+1
++ * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers
++ * - Power/Retry relative values no longer * 100000
++ * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI
+ */
+
+ /**************************** CONSTANTS ****************************/
+@@ -448,6 +461,7 @@
+ #define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
+ #define IW_QUAL_LEVEL_INVALID 0x20
+ #define IW_QUAL_NOISE_INVALID 0x40
++#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */
+ #define IW_QUAL_ALL_INVALID 0x70
+
+ /* Frequency flags */
+@@ -500,10 +514,12 @@
+ #define IW_RETRY_TYPE 0xF000 /* Type of parameter */
+ #define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/
+ #define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */
+-#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */
++#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */
+ #define IW_RETRY_MIN 0x0001 /* Value is a minimum */
+ #define IW_RETRY_MAX 0x0002 /* Value is a maximum */
+ #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
++#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */
++#define IW_RETRY_LONG 0x0020 /* Value is for long packets */
+
+ /* Scanning request flags */
+ #define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */
+@@ -1017,7 +1033,7 @@ struct iw_range
+ /* Note : this frequency list doesn't need to fit channel numbers,
+ * because each entry contain its channel index */
+
+- __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
++ __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
+ };
+
+ /*
+diff --git a/include/linux/writeback.h b/include/linux/writeback.h
+index 9e38b56..fc35e6b 100644
+--- a/include/linux/writeback.h
++++ b/include/linux/writeback.h
+@@ -1,5 +1,5 @@
+ /*
+- * include/linux/writeback.h.
++ * include/linux/writeback.h
+ */
+ #ifndef WRITEBACK_H
+ #define WRITEBACK_H
+@@ -110,11 +110,15 @@ balance_dirty_pages_ratelimited(struct a
+ }
+
+ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
++extern int generic_writepages(struct address_space *mapping,
++ struct writeback_control *wbc);
+ int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
+ int sync_page_range(struct inode *inode, struct address_space *mapping,
+ loff_t pos, loff_t count);
+ int sync_page_range_nolock(struct inode *inode, struct address_space *mapping,
+ loff_t pos, loff_t count);
++void set_page_dirty_balance(struct page *page);
++void writeback_set_ratelimit(void);
+
+ /* pdflush.c */
+ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
+diff --git a/include/linux/xattr.h b/include/linux/xattr.h
+index cda8a96..0e7f1e2 100644
+--- a/include/linux/xattr.h
++++ b/include/linux/xattr.h
+@@ -41,6 +41,7 @@ struct xattr_handler {
+ };
+
+ ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
++ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
+ int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
+ int vfs_removexattr(struct dentry *, char *);
+
+diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
+index 46a15c7..8ae7f74 100644
+--- a/include/linux/xfrm.h
++++ b/include/linux/xfrm.h
+@@ -12,8 +12,8 @@
+ */
+ typedef union
+ {
+- __u32 a4;
+- __u32 a6[4];
++ __be32 a4;
++ __be32 a6[4];
+ } xfrm_address_t;
+
+ /* Ident of a specific xfrm_state. It is used on input to lookup
+@@ -23,7 +23,7 @@ typedef union
+ struct xfrm_id
+ {
+ xfrm_address_t daddr;
+- __u32 spi;
++ __be32 spi;
+ __u8 proto;
+ };
+
+@@ -49,10 +49,10 @@ struct xfrm_selector
+ {
+ xfrm_address_t daddr;
+ xfrm_address_t saddr;
+- __u16 dport;
+- __u16 dport_mask;
+- __u16 sport;
+- __u16 sport_mask;
++ __be16 dport;
++ __be16 dport_mask;
++ __be16 sport;
++ __be16 sport_mask;
+ __u16 family;
+ __u8 prefixlen_d;
+ __u8 prefixlen_s;
+@@ -104,6 +104,13 @@ struct xfrm_stats {
+
+ enum
+ {
++ XFRM_POLICY_TYPE_MAIN = 0,
++ XFRM_POLICY_TYPE_SUB = 1,
++ XFRM_POLICY_TYPE_MAX = 2
++};
++
++enum
++{
+ XFRM_POLICY_IN = 0,
+ XFRM_POLICY_OUT = 1,
+ XFRM_POLICY_FWD = 2,
+@@ -120,7 +127,10 @@ enum
+
+ #define XFRM_MODE_TRANSPORT 0
+ #define XFRM_MODE_TUNNEL 1
+-#define XFRM_MODE_MAX 2
++#define XFRM_MODE_ROUTEOPTIMIZATION 2
++#define XFRM_MODE_IN_TRIGGER 3
++#define XFRM_MODE_BEET 4
++#define XFRM_MODE_MAX 5
+
+ /* Netlink configuration messages. */
+ enum {
+@@ -164,6 +174,10 @@ enum {
+ #define XFRM_MSG_NEWAE XFRM_MSG_NEWAE
+ XFRM_MSG_GETAE,
+ #define XFRM_MSG_GETAE XFRM_MSG_GETAE
++
++ XFRM_MSG_REPORT,
++#define XFRM_MSG_REPORT XFRM_MSG_REPORT
++
+ __XFRM_MSG_MAX
+ };
+ #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
+@@ -217,6 +231,12 @@ enum xfrm_ae_ftype_t {
+ #define XFRM_AE_MAX (__XFRM_AE_MAX - 1)
+ };
+
++struct xfrm_userpolicy_type {
++ __u8 type;
++ __u16 reserved1;
++ __u8 reserved2;
++};
++
+ /* Netlink message attributes. */
+ enum xfrm_attr_type_t {
+ XFRMA_UNSPEC,
+@@ -232,6 +252,10 @@ enum xfrm_attr_type_t {
+ XFRMA_REPLAY_VAL,
+ XFRMA_REPLAY_THRESH,
+ XFRMA_ETIMER_THRESH,
++ XFRMA_SRCADDR, /* xfrm_address_t */
++ XFRMA_COADDR, /* xfrm_address_t */
++ XFRMA_LASTUSED,
++ XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
+ __XFRMA_MAX
+
+ #define XFRMA_MAX (__XFRMA_MAX - 1)
+@@ -247,17 +271,18 @@ struct xfrm_usersa_info {
+ __u32 seq;
+ __u32 reqid;
+ __u16 family;
+- __u8 mode; /* 0=transport,1=tunnel */
++ __u8 mode; /* XFRM_MODE_xxx */
+ __u8 replay_window;
+ __u8 flags;
+ #define XFRM_STATE_NOECN 1
+ #define XFRM_STATE_DECAP_DSCP 2
+ #define XFRM_STATE_NOPMTUDISC 4
++#define XFRM_STATE_WILDRECV 8
+ };
+
+ struct xfrm_usersa_id {
+ xfrm_address_t daddr;
+- __u32 spi;
++ __be32 spi;
+ __u16 family;
+ __u8 proto;
+ };
+@@ -319,12 +344,18 @@ struct xfrm_usersa_flush {
+ __u8 proto;
+ };
+
++struct xfrm_user_report {
++ __u8 proto;
++ struct xfrm_selector sel;
++};
++
+ #ifndef __KERNEL__
+ /* backwards compatibility for userspace */
+ #define XFRMGRP_ACQUIRE 1
+ #define XFRMGRP_EXPIRE 2
+ #define XFRMGRP_SA 4
+ #define XFRMGRP_POLICY 8
++#define XFRMGRP_REPORT 0x10
+ #endif
+
+ enum xfrm_nlgroups {
+@@ -340,6 +371,8 @@ enum xfrm_nlgroups {
+ #define XFRMNLGRP_POLICY XFRMNLGRP_POLICY
+ XFRMNLGRP_AEVENTS,
+ #define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS
++ XFRMNLGRP_REPORT,
++#define XFRMNLGRP_REPORT XFRMNLGRP_REPORT
+ __XFRMNLGRP_MAX
+ };
+ #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1)
+diff --git a/include/media/audiochip.h b/include/media/audiochip.h
+index 1fd4a22..db8823d 100644
+--- a/include/media/audiochip.h
++++ b/include/media/audiochip.h
+@@ -18,7 +18,9 @@ enum audiochip {
+ AUDIO_CHIP_TDA9874,
+ AUDIO_CHIP_PIC16C54,
+ /* Provided by msp3400.c */
+- AUDIO_CHIP_MSP34XX
++ AUDIO_CHIP_MSP34XX,
++ /* Provided by wm8775.c */
++ AUDIO_CHIP_WM8775
+ };
+
+ #endif /* AUDIOCHIP_H */
+diff --git a/include/media/ir-common.h b/include/media/ir-common.h
+index 7bab09b..8f58406 100644
+--- a/include/media/ir-common.h
++++ b/include/media/ir-common.h
+@@ -90,6 +90,8 @@ extern IR_KEYTAB_TYPE ir_codes_winfast[I
+ extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
++extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
++extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
+
+ #endif
+
+diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
+index 3c43b95..37dad07 100644
+--- a/include/media/tuner-types.h
++++ b/include/media/tuner-types.h
+@@ -72,6 +72,9 @@ struct tuner_params {
+ unsigned int port2_invert_for_secam_lc:1;
+ /* Some cards require PORT1 to be 1 for mono Radio FM and 0 for stereo. */
+ unsigned int port1_set_for_fm_mono:1;
++ /* Select 18% (or according to datasheet 0%) L standard PLL gating,
++ vs the driver default of 36%. */
++ unsigned int default_pll_gating_18:1;
+ /* Default tda9887 TOP value in dB for the low band. Default is 0.
+ Range: -16:+15 */
+ signed int default_top_low:5;
+diff --git a/include/media/tuner.h b/include/media/tuner.h
+index 2f7b00b..3116e75 100644
+--- a/include/media/tuner.h
++++ b/include/media/tuner.h
+@@ -144,6 +144,7 @@ extern int tuner_debug;
+ #define TDA9887_DEEMPHASIS_50 (2<<16)
+ #define TDA9887_DEEMPHASIS_75 (3<<16)
+ #define TDA9887_AUTOMUTE (1<<18)
++#define TDA9887_GATING_18 (1<<19)
+
+ #ifdef __KERNEL__
+
+diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
+index 5564db1..aecc946 100644
+--- a/include/media/v4l2-common.h
++++ b/include/media/v4l2-common.h
+@@ -121,10 +121,17 @@ enum v4l2_chip_ident {
+ /* general idents: reserved range 0-49 */
+ V4L2_IDENT_UNKNOWN = 0,
+
+- /* module saa7115: reserved range 100-149 */
++ /* module saa7110: just ident= 100 */
++ V4L2_IDENT_SAA7110 = 100,
++
++ /* module saa7111: just ident= 101 */
++ V4L2_IDENT_SAA7111 = 101,
++
++ /* module saa7115: reserved range 102-149 */
+ V4L2_IDENT_SAA7113 = 103,
+ V4L2_IDENT_SAA7114 = 104,
+ V4L2_IDENT_SAA7115 = 105,
++ V4L2_IDENT_SAA7118 = 108,
+
+ /* module saa7127: reserved range 150-199 */
+ V4L2_IDENT_SAA7127 = 157,
+@@ -166,11 +173,12 @@ enum v4l2_chip_ident {
+ #define VIDIOC_INT_S_STANDBY _IOW('d', 94, u32)
+
+ /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
+-#define VIDIOC_INT_S_REGISTER _IOR ('d', 100, struct v4l2_register)
++#define VIDIOC_INT_S_REGISTER _IOW ('d', 100, struct v4l2_register)
+ #define VIDIOC_INT_G_REGISTER _IOWR('d', 101, struct v4l2_register)
+
+-/* Reset the I2C chip */
+-#define VIDIOC_INT_RESET _IO ('d', 102)
++/* Generic reset command. The argument selects which subsystems to reset.
++ Passing 0 will always reset the whole chip. */
++#define VIDIOC_INT_RESET _IOW ('d', 102, u32)
+
+ /* Set the frequency (in Hz) of the audio clock output.
+ Used to slave an audio processor to the video decoder, ensuring that audio
+diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
+index 810462f..6a11d77 100644
+--- a/include/media/v4l2-dev.h
++++ b/include/media/v4l2-dev.h
+@@ -9,7 +9,8 @@
+ #ifndef _V4L2_DEV_H
+ #define _V4L2_DEV_H
+
+-#define OBSOLETE_OWNER 1 /* to be removed soon */
++#define OBSOLETE_OWNER 1 /* to be removed soon */
++#define OBSOLETE_DEVDATA 1 /* to be removed soon */
+
+ #include <linux/poll.h>
+ #include <linux/fs.h>
+@@ -338,10 +339,8 @@ extern int video_usercopy(struct inode *
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+ #include <linux/mm.h>
+
+-extern struct video_device* video_devdata(struct file*);
+-
+ #define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+-static inline int
++static inline int __must_check
+ video_device_create_file(struct video_device *vfd,
+ struct class_device_attribute *attr)
+ {
+@@ -370,9 +369,14 @@ static inline void video_set_drvdata(str
+ {
+ dev->priv = data;
+ }
++
+ #endif
+
++#ifdef OBSOLETE_DEVDATA /* to be removed soon */
++/* Obsolete stuff - Still needed for radio devices and obsolete drivers */
++extern struct video_device* video_devdata(struct file*);
+ extern int video_exclusive_open(struct inode *inode, struct file *file);
+ extern int video_exclusive_release(struct inode *inode, struct file *file);
++#endif
+
+ #endif /* _V4L2_DEV_H */
+diff --git a/include/mtd/Kbuild b/include/mtd/Kbuild
+index e1da2a5..e0fe92b 100644
+--- a/include/mtd/Kbuild
++++ b/include/mtd/Kbuild
+@@ -1,2 +1,5 @@
+-unifdef-y := mtd-abi.h
+-header-y := inftl-user.h jffs2-user.h mtd-user.h nftl-user.h
++header-y += inftl-user.h
++header-y += jffs2-user.h
++header-y += mtd-abi.h
++header-y += mtd-user.h
++header-y += nftl-user.h
+diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
+index 1da3f7f..f913c30 100644
+--- a/include/mtd/mtd-abi.h
++++ b/include/mtd/mtd-abi.h
+@@ -7,12 +7,6 @@
+ #ifndef __MTD_ABI_H__
+ #define __MTD_ABI_H__
+
+-#ifndef __KERNEL__
+-/* Urgh. The whole point of splitting this out into
+- separate files was to avoid #ifdef __KERNEL__ */
+-#define __user
+-#endif
+-
+ struct erase_info_user {
+ uint32_t start;
+ uint32_t length;
+@@ -34,6 +28,7 @@ struct mtd_oob_buf {
+ #define MTD_WRITEABLE 0x400 /* Device is writeable */
+ #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
+ #define MTD_NO_ERASE 0x1000 /* No erase necessary */
++#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */
+
+ // Some common devices / combinations of capabilities
+ #define MTD_CAP_ROM 0
+diff --git a/include/net/act_api.h b/include/net/act_api.h
+index 11e9eaf..8b06c2f 100644
+--- a/include/net/act_api.h
++++ b/include/net/act_api.h
+@@ -8,70 +8,110 @@
+ #include <net/sch_generic.h>
+ #include <net/pkt_sched.h>
+
+-#define tca_gen(name) \
+-struct tcf_##name *next; \
+- u32 index; \
+- int refcnt; \
+- int bindcnt; \
+- u32 capab; \
+- int action; \
+- struct tcf_t tm; \
+- struct gnet_stats_basic bstats; \
+- struct gnet_stats_queue qstats; \
+- struct gnet_stats_rate_est rate_est; \
+- spinlock_t *stats_lock; \
+- spinlock_t lock
+-
+-struct tcf_police
+-{
+- tca_gen(police);
+- int result;
+- u32 ewma_rate;
+- u32 burst;
+- u32 mtu;
+- u32 toks;
+- u32 ptoks;
+- psched_time_t t_c;
+- struct qdisc_rate_table *R_tab;
+- struct qdisc_rate_table *P_tab;
++struct tcf_common {
++ struct tcf_common *tcfc_next;
++ u32 tcfc_index;
++ int tcfc_refcnt;
++ int tcfc_bindcnt;
++ u32 tcfc_capab;
++ int tcfc_action;
++ struct tcf_t tcfc_tm;
++ struct gnet_stats_basic tcfc_bstats;
++ struct gnet_stats_queue tcfc_qstats;
++ struct gnet_stats_rate_est tcfc_rate_est;
++ spinlock_t *tcfc_stats_lock;
++ spinlock_t tcfc_lock;
++};
++#define tcf_next common.tcfc_next
++#define tcf_index common.tcfc_index
++#define tcf_refcnt common.tcfc_refcnt
++#define tcf_bindcnt common.tcfc_bindcnt
++#define tcf_capab common.tcfc_capab
++#define tcf_action common.tcfc_action
++#define tcf_tm common.tcfc_tm
++#define tcf_bstats common.tcfc_bstats
++#define tcf_qstats common.tcfc_qstats
++#define tcf_rate_est common.tcfc_rate_est
++#define tcf_stats_lock common.tcfc_stats_lock
++#define tcf_lock common.tcfc_lock
++
++struct tcf_police {
++ struct tcf_common common;
++ int tcfp_result;
++ u32 tcfp_ewma_rate;
++ u32 tcfp_burst;
++ u32 tcfp_mtu;
++ u32 tcfp_toks;
++ u32 tcfp_ptoks;
++ psched_time_t tcfp_t_c;
++ struct qdisc_rate_table *tcfp_R_tab;
++ struct qdisc_rate_table *tcfp_P_tab;
+ };
++#define to_police(pc) \
++ container_of(pc, struct tcf_police, common)
++
++struct tcf_hashinfo {
++ struct tcf_common **htab;
++ unsigned int hmask;
++ rwlock_t *lock;
++};
++
++static inline unsigned int tcf_hash(u32 index, unsigned int hmask)
++{
++ return index & hmask;
++}
+
+ #ifdef CONFIG_NET_CLS_ACT
+
+ #define ACT_P_CREATED 1
+ #define ACT_P_DELETED 1
+
+-struct tcf_act_hdr
+-{
+- tca_gen(act_hdr);
++struct tcf_act_hdr {
++ struct tcf_common common;
+ };
+
+-struct tc_action
+-{
+- void *priv;
+- struct tc_action_ops *ops;
+- __u32 type; /* for backward compat(TCA_OLD_COMPAT) */
+- __u32 order;
+- struct tc_action *next;
++struct tc_action {
++ void *priv;
++ struct tc_action_ops *ops;
++ __u32 type; /* for backward compat(TCA_OLD_COMPAT) */
++ __u32 order;
++ struct tc_action *next;
+ };
+
+ #define TCA_CAP_NONE 0
+-struct tc_action_ops
+-{
++struct tc_action_ops {
+ struct tc_action_ops *next;
++ struct tcf_hashinfo *hinfo;
+ char kind[IFNAMSIZ];
+ __u32 type; /* TBD to match kind */
+ __u32 capab; /* capabilities includes 4 bit version */
+ struct module *owner;
+ int (*act)(struct sk_buff *, struct tc_action *, struct tcf_result *);
+ int (*get_stats)(struct sk_buff *, struct tc_action *);
+- int (*dump)(struct sk_buff *, struct tc_action *,int , int);
++ int (*dump)(struct sk_buff *, struct tc_action *, int, int);
+ int (*cleanup)(struct tc_action *, int bind);
+- int (*lookup)(struct tc_action *, u32 );
+- int (*init)(struct rtattr *,struct rtattr *,struct tc_action *, int , int );
+- int (*walk)(struct sk_buff *, struct netlink_callback *, int , struct tc_action *);
++ int (*lookup)(struct tc_action *, u32);
++ int (*init)(struct rtattr *, struct rtattr *, struct tc_action *, int , int);
++ int (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *);
+ };
+
++extern struct tcf_common *tcf_hash_lookup(u32 index,
++ struct tcf_hashinfo *hinfo);
++extern void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo);
++extern int tcf_hash_release(struct tcf_common *p, int bind,
++ struct tcf_hashinfo *hinfo);
++extern int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
++ int type, struct tc_action *a);
++extern u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo);
++extern int tcf_hash_search(struct tc_action *a, u32 index);
++extern struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a,
++ int bind, struct tcf_hashinfo *hinfo);
++extern struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est,
++ struct tc_action *a, int size,
++ int bind, u32 *idx_gen,
++ struct tcf_hashinfo *hinfo);
++extern void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo);
++
+ extern int tcf_register_action(struct tc_action_ops *a);
+ extern int tcf_unregister_action(struct tc_action_ops *a);
+ extern void tcf_action_destroy(struct tc_action *a, int bind);
+@@ -96,17 +136,17 @@ tcf_police_release(struct tcf_police *p,
+ int ret = 0;
+ #ifdef CONFIG_NET_CLS_ACT
+ if (p) {
+- if (bind) {
+- p->bindcnt--;
+- }
+- p->refcnt--;
+- if (p->refcnt <= 0 && !p->bindcnt) {
++ if (bind)
++ p->tcf_bindcnt--;
++
++ p->tcf_refcnt--;
++ if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
+ tcf_police_destroy(p);
+ ret = 1;
+ }
+ }
+ #else
+- if (p && --p->refcnt == 0)
++ if (p && --p->tcf_refcnt == 0)
+ tcf_police_destroy(p);
+
+ #endif /* CONFIG_NET_CLS_ACT */
+diff --git a/include/net/act_generic.h b/include/net/act_generic.h
+deleted file mode 100644
+index c9daa7e..0000000
+--- a/include/net/act_generic.h
++++ /dev/null
+@@ -1,142 +0,0 @@
+-/*
+- * include/net/act_generic.h
+- *
+-*/
+-#ifndef _NET_ACT_GENERIC_H
+-#define _NET_ACT_GENERIC_H
+-static inline int tcf_defact_release(struct tcf_defact *p, int bind)
+-{
+- int ret = 0;
+- if (p) {
+- if (bind) {
+- p->bindcnt--;
+- }
+- p->refcnt--;
+- if (p->bindcnt <= 0 && p->refcnt <= 0) {
+- kfree(p->defdata);
+- tcf_hash_destroy(p);
+- ret = 1;
+- }
+- }
+- return ret;
+-}
+-
+-static inline int
+-alloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata)
+-{
+- p->defdata = kmalloc(datalen, GFP_KERNEL);
+- if (p->defdata == NULL)
+- return -ENOMEM;
+- p->datalen = datalen;
+- memcpy(p->defdata, defdata, datalen);
+- return 0;
+-}
+-
+-static inline int
+-realloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata)
+-{
+- /* safer to be just brute force for now */
+- kfree(p->defdata);
+- return alloc_defdata(p, datalen, defdata);
+-}
+-
+-static inline int
+-tcf_defact_init(struct rtattr *rta, struct rtattr *est,
+- struct tc_action *a, int ovr, int bind)
+-{
+- struct rtattr *tb[TCA_DEF_MAX];
+- struct tc_defact *parm;
+- struct tcf_defact *p;
+- void *defdata;
+- u32 datalen = 0;
+- int ret = 0;
+-
+- if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0)
+- return -EINVAL;
+-
+- if (tb[TCA_DEF_PARMS - 1] == NULL ||
+- RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm))
+- return -EINVAL;
+-
+- parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]);
+- defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]);
+- if (defdata == NULL)
+- return -EINVAL;
+-
+- datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]);
+- if (datalen <= 0)
+- return -EINVAL;
+-
+- p = tcf_hash_check(parm->index, a, ovr, bind);
+- if (p == NULL) {
+- p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
+- if (p == NULL)
+- return -ENOMEM;
+-
+- ret = alloc_defdata(p, datalen, defdata);
+- if (ret < 0) {
+- kfree(p);
+- return ret;
+- }
+- ret = ACT_P_CREATED;
+- } else {
+- if (!ovr) {
+- tcf_defact_release(p, bind);
+- return -EEXIST;
+- }
+- realloc_defdata(p, datalen, defdata);
+- }
+-
+- spin_lock_bh(&p->lock);
+- p->action = parm->action;
+- spin_unlock_bh(&p->lock);
+- if (ret == ACT_P_CREATED)
+- tcf_hash_insert(p);
+- return ret;
+-}
+-
+-static inline int tcf_defact_cleanup(struct tc_action *a, int bind)
+-{
+- struct tcf_defact *p = PRIV(a, defact);
+-
+- if (p != NULL)
+- return tcf_defact_release(p, bind);
+- return 0;
+-}
+-
+-static inline int
+-tcf_defact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+-{
+- unsigned char *b = skb->tail;
+- struct tc_defact opt;
+- struct tcf_defact *p = PRIV(a, defact);
+- struct tcf_t t;
+-
+- opt.index = p->index;
+- opt.refcnt = p->refcnt - ref;
+- opt.bindcnt = p->bindcnt - bind;
+- opt.action = p->action;
+- RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt);
+- RTA_PUT(skb, TCA_DEF_DATA, p->datalen, p->defdata);
+- t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+- t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+- t.expires = jiffies_to_clock_t(p->tm.expires);
+- RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t);
+- return skb->len;
+-
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
+-}
+-
+-#define tca_use_default_ops \
+- .dump = tcf_defact_dump, \
+- .cleanup = tcf_defact_cleanup, \
+- .init = tcf_defact_init, \
+- .walk = tcf_generic_walker, \
+-
+-#define tca_use_default_defines(name) \
+- static u32 idx_gen; \
+- static struct tcf_defact *tcf_##name_ht[MY_TAB_SIZE]; \
+- static DEFINE_RWLOCK(##name_lock);
+-#endif /* _NET_ACT_GENERIC_H */
+diff --git a/include/net/addrconf.h b/include/net/addrconf.h
+index 3d71251..44f1b67 100644
+--- a/include/net/addrconf.h
++++ b/include/net/addrconf.h
+@@ -61,6 +61,9 @@ extern int addrconf_set_dstaddr(void _
+ extern int ipv6_chk_addr(struct in6_addr *addr,
+ struct net_device *dev,
+ int strict);
++#ifdef CONFIG_IPV6_MIP6
++extern int ipv6_chk_home_addr(struct in6_addr *addr);
++#endif
+ extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr,
+ struct net_device *dev,
+ int strict);
+@@ -126,20 +129,18 @@ extern int unregister_inet6addr_notifier
+ static inline struct inet6_dev *
+ __in6_dev_get(struct net_device *dev)
+ {
+- return (struct inet6_dev *)dev->ip6_ptr;
++ return rcu_dereference(dev->ip6_ptr);
+ }
+
+-extern rwlock_t addrconf_lock;
+-
+ static inline struct inet6_dev *
+ in6_dev_get(struct net_device *dev)
+ {
+ struct inet6_dev *idev = NULL;
+- read_lock(&addrconf_lock);
+- idev = dev->ip6_ptr;
++ rcu_read_lock();
++ idev = __in6_dev_get(dev);
+ if (idev)
+ atomic_inc(&idev->refcnt);
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ return idev;
+ }
+
+diff --git a/include/net/ah.h b/include/net/ah.h
+index ceff00a..8f257c1 100644
+--- a/include/net/ah.h
++++ b/include/net/ah.h
+@@ -1,6 +1,7 @@
+ #ifndef _NET_AH_H
+ #define _NET_AH_H
+
++#include <linux/crypto.h>
+ #include <net/xfrm.h>
+
+ /* This is the maximum truncated ICV length that we know of. */
+@@ -14,22 +15,29 @@ struct ah_data
+ int icv_full_len;
+ int icv_trunc_len;
+
+- void (*icv)(struct ah_data*,
+- struct sk_buff *skb, u8 *icv);
+-
+- struct crypto_tfm *tfm;
++ struct crypto_hash *tfm;
+ };
+
+-static inline void
+-ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data)
++static inline int ah_mac_digest(struct ah_data *ahp, struct sk_buff *skb,
++ u8 *auth_data)
+ {
+- struct crypto_tfm *tfm = ahp->tfm;
++ struct hash_desc desc;
++ int err;
++
++ desc.tfm = ahp->tfm;
++ desc.flags = 0;
+
+ memset(auth_data, 0, ahp->icv_trunc_len);
+- crypto_hmac_init(tfm, ahp->key, &ahp->key_len);
+- skb_icv_walk(skb, tfm, 0, skb->len, crypto_hmac_update);
+- crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_icv);
+- memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len);
++ err = crypto_hash_init(&desc);
++ if (unlikely(err))
++ goto out;
++ err = skb_icv_walk(skb, &desc, 0, skb->len, crypto_hash_update);
++ if (unlikely(err))
++ goto out;
++ err = crypto_hash_final(&desc, ahp->work_icv);
++
++out:
++ return err;
+ }
+
+ #endif
+diff --git a/include/net/arp.h b/include/net/arp.h
+index 643bded..6a3d9a7 100644
+--- a/include/net/arp.h
++++ b/include/net/arp.h
+@@ -12,15 +12,15 @@ extern struct neigh_table arp_tbl;
+ extern void arp_init(void);
+ extern int arp_find(unsigned char *haddr, struct sk_buff *skb);
+ extern int arp_ioctl(unsigned int cmd, void __user *arg);
+-extern void arp_send(int type, int ptype, u32 dest_ip,
+- struct net_device *dev, u32 src_ip,
++extern void arp_send(int type, int ptype, __be32 dest_ip,
++ struct net_device *dev, __be32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
+ extern int arp_bind_neighbour(struct dst_entry *dst);
+ extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir);
+ extern void arp_ifdown(struct net_device *dev);
+
+-extern struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
+- struct net_device *dev, u32 src_ip,
++extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
++ struct net_device *dev, __be32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw,
+ unsigned char *target_hw);
+ extern void arp_xmit(struct sk_buff *skb);
+diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
+index b2bdb1a..10a3eec 100644
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -44,12 +44,13 @@
+ #define HCI_NOTIFY_VOICE_SETTING 3
+
+ /* HCI device types */
+-#define HCI_VHCI 0
++#define HCI_VIRTUAL 0
+ #define HCI_USB 1
+ #define HCI_PCCARD 2
+ #define HCI_UART 3
+ #define HCI_RS232 4
+ #define HCI_PCI 5
++#define HCI_SDIO 6
+
+ /* HCI device quirks */
+ enum {
+@@ -296,6 +297,7 @@ struct hci_cp_host_buffer_size {
+
+ /* Link Control */
+ #define OGF_LINK_CTL 0x01
++
+ #define OCF_CREATE_CONN 0x0005
+ struct hci_cp_create_conn {
+ bdaddr_t bdaddr;
+@@ -306,6 +308,11 @@ struct hci_cp_create_conn {
+ __u8 role_switch;
+ } __attribute__ ((packed));
+
++#define OCF_CREATE_CONN_CANCEL 0x0008
++struct hci_cp_create_conn_cancel {
++ bdaddr_t bdaddr;
++} __attribute__ ((packed));
++
+ #define OCF_ACCEPT_CONN_REQ 0x0009
+ struct hci_cp_accept_conn_req {
+ bdaddr_t bdaddr;
+@@ -339,6 +346,8 @@ struct hci_cp_inquiry {
+
+ #define OCF_INQUIRY_CANCEL 0x0002
+
++#define OCF_EXIT_PERIODIC_INQ 0x0004
++
+ #define OCF_LINK_KEY_REPLY 0x000B
+ struct hci_cp_link_key_reply {
+ bdaddr_t bdaddr;
+diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
+index d84855f..c0fc396 100644
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -72,6 +72,9 @@ struct hci_dev {
+ __u8 type;
+ bdaddr_t bdaddr;
+ __u8 features[8];
++ __u8 hci_ver;
++ __u16 hci_rev;
++ __u16 manufacturer;
+ __u16 voice_setting;
+
+ __u16 pkt_type;
+@@ -150,6 +153,7 @@ struct hci_conn {
+ __u8 mode;
+ __u8 type;
+ __u8 out;
++ __u8 attempt;
+ __u8 dev_class[3];
+ __u8 features[8];
+ __u16 interval;
+@@ -165,6 +169,10 @@ struct hci_conn {
+ struct timer_list disc_timer;
+ struct timer_list idle_timer;
+
++ struct work_struct work;
++
++ struct device dev;
++
+ struct hci_dev *hdev;
+ void *l2cap_data;
+ void *sco_data;
+@@ -282,6 +290,22 @@ static inline struct hci_conn *hci_conn_
+ return NULL;
+ }
+
++static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
++ __u8 type, __u16 state)
++{
++ struct hci_conn_hash *h = &hdev->conn_hash;
++ struct list_head *p;
++ struct hci_conn *c;
++
++ list_for_each(p, &h->list) {
++ c = list_entry(p, struct hci_conn, list);
++ if (c->type == type && c->state == state)
++ return c;
++ }
++ return NULL;
++}
++
++void hci_acl_connect(struct hci_conn *conn);
+ void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
+ void hci_add_sco(struct hci_conn *conn, __u16 handle);
+
+@@ -309,10 +333,13 @@ static inline void hci_conn_put(struct h
+ if (atomic_dec_and_test(&conn->refcnt)) {
+ unsigned long timeo;
+ if (conn->type == ACL_LINK) {
+- timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
+- if (!conn->out)
+- timeo *= 2;
+ del_timer(&conn->idle_timer);
++ if (conn->state == BT_CONNECTED) {
++ timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
++ if (!conn->out)
++ timeo *= 2;
++ } else
++ timeo = msecs_to_jiffies(10);
+ } else
+ timeo = msecs_to_jiffies(10);
+ mod_timer(&conn->disc_timer, jiffies + timeo);
+@@ -412,6 +439,8 @@ static inline int hci_recv_frame(struct
+
+ int hci_register_sysfs(struct hci_dev *hdev);
+ void hci_unregister_sysfs(struct hci_dev *hdev);
++void hci_conn_add_sysfs(struct hci_conn *conn);
++void hci_conn_del_sysfs(struct hci_conn *conn);
+
+ #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
+
+diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
+new file mode 100644
+index 0000000..718b4d9
+--- /dev/null
++++ b/include/net/cipso_ipv4.h
+@@ -0,0 +1,254 @@
++/*
++ * CIPSO - Commercial IP Security Option
++ *
++ * This is an implementation of the CIPSO 2.2 protocol as specified in
++ * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
++ * FIPS-188, copies of both documents can be found in the Documentation
++ * directory. While CIPSO never became a full IETF RFC standard many vendors
++ * have chosen to adopt the protocol and over the years it has become a
++ * de-facto standard for labeled networking.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _CIPSO_IPV4_H
++#define _CIPSO_IPV4_H
++
++#include <linux/types.h>
++#include <linux/rcupdate.h>
++#include <linux/list.h>
++#include <linux/net.h>
++#include <linux/skbuff.h>
++#include <net/netlabel.h>
++
++/* known doi values */
++#define CIPSO_V4_DOI_UNKNOWN 0x00000000
++
++/* tag types */
++#define CIPSO_V4_TAG_INVALID 0
++#define CIPSO_V4_TAG_RBITMAP 1
++#define CIPSO_V4_TAG_ENUM 2
++#define CIPSO_V4_TAG_RANGE 5
++#define CIPSO_V4_TAG_PBITMAP 6
++#define CIPSO_V4_TAG_FREEFORM 7
++
++/* doi mapping types */
++#define CIPSO_V4_MAP_UNKNOWN 0
++#define CIPSO_V4_MAP_STD 1
++#define CIPSO_V4_MAP_PASS 2
++
++/* limits */
++#define CIPSO_V4_MAX_REM_LVLS 256
++#define CIPSO_V4_INV_LVL 0x80000000
++#define CIPSO_V4_MAX_LOC_LVLS (CIPSO_V4_INV_LVL - 1)
++#define CIPSO_V4_MAX_REM_CATS 65536
++#define CIPSO_V4_INV_CAT 0x80000000
++#define CIPSO_V4_MAX_LOC_CATS (CIPSO_V4_INV_CAT - 1)
++
++/*
++ * CIPSO DOI definitions
++ */
++
++/* DOI definition struct */
++#define CIPSO_V4_TAG_MAXCNT 5
++struct cipso_v4_doi {
++ u32 doi;
++ u32 type;
++ union {
++ struct cipso_v4_std_map_tbl *std;
++ } map;
++ u8 tags[CIPSO_V4_TAG_MAXCNT];
++
++ u32 valid;
++ struct list_head list;
++ struct rcu_head rcu;
++ struct list_head dom_list;
++};
++
++/* Standard CIPSO mapping table */
++/* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the
++ * bit is set then consider that value as unspecified, meaning the
++ * mapping for that particular level/category is invalid */
++struct cipso_v4_std_map_tbl {
++ struct {
++ u32 *cipso;
++ u32 *local;
++ u32 cipso_size;
++ u32 local_size;
++ } lvl;
++ struct {
++ u32 *cipso;
++ u32 *local;
++ u32 cipso_size;
++ u32 local_size;
++ } cat;
++};
++
++/*
++ * Sysctl Variables
++ */
++
++#ifdef CONFIG_NETLABEL
++extern int cipso_v4_cache_enabled;
++extern int cipso_v4_cache_bucketsize;
++extern int cipso_v4_rbm_optfmt;
++extern int cipso_v4_rbm_strictvalid;
++#endif
++
++/*
++ * Helper Functions
++ */
++
++#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0)
++#define CIPSO_V4_OPTPTR(x) ((x)->nh.raw + IPCB(x)->opt.cipso)
++
++/*
++ * DOI List Functions
++ */
++
++#ifdef CONFIG_NETLABEL
++int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
++int cipso_v4_doi_remove(u32 doi,
++ struct netlbl_audit *audit_info,
++ void (*callback) (struct rcu_head * head));
++struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
++int cipso_v4_doi_walk(u32 *skip_cnt,
++ int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
++ void *cb_arg);
++int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
++int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
++ const char *domain);
++#else
++static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
++{
++ return -ENOSYS;
++}
++
++static inline int cipso_v4_doi_remove(u32 doi,
++ struct netlbl_audit *audit_info,
++ void (*callback) (struct rcu_head * head))
++{
++ return 0;
++}
++
++static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
++{
++ return NULL;
++}
++
++static inline int cipso_v4_doi_walk(u32 *skip_cnt,
++ int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
++ void *cb_arg)
++{
++ return 0;
++}
++
++static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def,
++ const char *domain)
++{
++ return -ENOSYS;
++}
++
++static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
++ const char *domain)
++{
++ return 0;
++}
++#endif /* CONFIG_NETLABEL */
++
++/*
++ * Label Mapping Cache Functions
++ */
++
++#ifdef CONFIG_NETLABEL
++void cipso_v4_cache_invalidate(void);
++int cipso_v4_cache_add(const struct sk_buff *skb,
++ const struct netlbl_lsm_secattr *secattr);
++#else
++static inline void cipso_v4_cache_invalidate(void)
++{
++ return;
++}
++
++static inline int cipso_v4_cache_add(const struct sk_buff *skb,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ return 0;
++}
++#endif /* CONFIG_NETLABEL */
++
++/*
++ * Protocol Handling Functions
++ */
++
++#ifdef CONFIG_NETLABEL
++void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
++int cipso_v4_socket_setattr(const struct socket *sock,
++ const struct cipso_v4_doi *doi_def,
++ const struct netlbl_lsm_secattr *secattr);
++int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
++int cipso_v4_socket_getattr(const struct socket *sock,
++ struct netlbl_lsm_secattr *secattr);
++int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr);
++int cipso_v4_validate(unsigned char **option);
++#else
++static inline void cipso_v4_error(struct sk_buff *skb,
++ int error,
++ u32 gateway)
++{
++ return;
++}
++
++static inline int cipso_v4_socket_setattr(const struct socket *sock,
++ const struct cipso_v4_doi *doi_def,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int cipso_v4_sock_getattr(struct sock *sk,
++ struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int cipso_v4_socket_getattr(const struct socket *sock,
++ struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int cipso_v4_validate(unsigned char **option)
++{
++ return -ENOSYS;
++}
++#endif /* CONFIG_NETLABEL */
++
++#endif /* _CIPSO_IPV4_H */
+diff --git a/include/net/dn.h b/include/net/dn.h
+index 465b783..ac4ce90 100644
+--- a/include/net/dn.h
++++ b/include/net/dn.h
+@@ -199,11 +199,6 @@ static inline void dn_sk_ports_copy(stru
+ {
+ fl->uli_u.dnports.sport = scp->addrloc;
+ fl->uli_u.dnports.dport = scp->addrrem;
+- fl->uli_u.dnports.objnum = scp->addr.sdn_objnum;
+- if (fl->uli_u.dnports.objnum == 0) {
+- fl->uli_u.dnports.objnamel = (__u8)dn_ntohs(scp->addr.sdn_objnamel);
+- memcpy(fl->uli_u.dnports.objname, scp->addr.sdn_objname, 16);
+- }
+ }
+
+ extern unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu);
+diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h
+index a15dcf0..f01626c 100644
+--- a/include/net/dn_fib.h
++++ b/include/net/dn_fib.h
+@@ -22,7 +22,7 @@ struct dn_kern_rta
+ };
+
+ struct dn_fib_res {
+- struct dn_fib_rule *r;
++ struct fib_rule *r;
+ struct dn_fib_info *fi;
+ unsigned char prefixlen;
+ unsigned char nh_sel;
+@@ -94,7 +94,8 @@ struct dn_fib_node {
+
+
+ struct dn_fib_table {
+- int n;
++ struct hlist_node hlist;
++ u32 n;
+
+ int (*insert)(struct dn_fib_table *t, struct rtmsg *r,
+ struct dn_kern_rta *rta, struct nlmsghdr *n,
+@@ -130,14 +131,11 @@ extern __le16 dn_fib_get_attr16(struct r
+ extern void dn_fib_flush(void);
+ extern void dn_fib_select_multipath(const struct flowi *fl,
+ struct dn_fib_res *res);
+-extern int dn_fib_sync_down(__le16 local, struct net_device *dev,
+- int force);
+-extern int dn_fib_sync_up(struct net_device *dev);
+
+ /*
+ * dn_tables.c
+ */
+-extern struct dn_fib_table *dn_fib_get_table(int n, int creat);
++extern struct dn_fib_table *dn_fib_get_table(u32 n, int creat);
+ extern struct dn_fib_table *dn_fib_empty_table(void);
+ extern void dn_fib_table_init(void);
+ extern void dn_fib_table_cleanup(void);
+@@ -147,10 +145,8 @@ extern void dn_fib_table_cleanup(void);
+ */
+ extern void dn_fib_rules_init(void);
+ extern void dn_fib_rules_cleanup(void);
+-extern void dn_fib_rule_put(struct dn_fib_rule *);
+-extern __le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags);
+ extern unsigned dnet_addr_type(__le16 addr);
+-extern int dn_fib_lookup(const struct flowi *fl, struct dn_fib_res *res);
++extern int dn_fib_lookup(struct flowi *fl, struct dn_fib_res *res);
+
+ /*
+ * rtnetlink interface
+@@ -176,11 +172,9 @@ static inline void dn_fib_res_put(struct
+ if (res->fi)
+ dn_fib_info_put(res->fi);
+ if (res->r)
+- dn_fib_rule_put(res->r);
++ fib_rule_put(res->r);
+ }
+
+-extern struct dn_fib_table *dn_fib_tables[];
+-
+ #else /* Endnode */
+
+ #define dn_fib_init() do { } while(0)
+diff --git a/include/net/dst.h b/include/net/dst.h
+index 36d54fc..e156e38 100644
+--- a/include/net/dst.h
++++ b/include/net/dst.h
+@@ -54,6 +54,7 @@ struct dst_entry
+ unsigned long expires;
+
+ unsigned short header_len; /* more space at head required */
++ unsigned short nfheader_len; /* more non-fragment space at head required */
+ unsigned short trailer_len; /* space to reserve at tail */
+
+ u32 metrics[RTAX_MAX];
+@@ -83,7 +84,7 @@ struct dst_entry
+ struct dst_ops
+ {
+ unsigned short family;
+- unsigned short protocol;
++ __be16 protocol;
+ unsigned gc_thresh;
+
+ int (*gc)(void);
+diff --git a/include/net/esp.h b/include/net/esp.h
+index 90cd94f..713d039 100644
+--- a/include/net/esp.h
++++ b/include/net/esp.h
+@@ -1,6 +1,7 @@
+ #ifndef _NET_ESP_H
+ #define _NET_ESP_H
+
++#include <linux/crypto.h>
+ #include <net/xfrm.h>
+ #include <asm/scatterlist.h>
+
+@@ -14,14 +15,15 @@ struct esp_data
+ struct {
+ u8 *key; /* Key */
+ int key_len; /* Key length */
+- u8 *ivec; /* ivec buffer */
++ int padlen; /* 0..255 */
+ /* ivlen is offset from enc_data, where encrypted data start.
+ * It is logically different of crypto_tfm_alg_ivsize(tfm).
+ * We assume that it is either zero (no ivec), or
+ * >= crypto_tfm_alg_ivsize(tfm). */
+ int ivlen;
+- int padlen; /* 0..255 */
+- struct crypto_tfm *tfm; /* crypto handle */
++ int ivinitted;
++ u8 *ivec; /* ivec buffer */
++ struct crypto_blkcipher *tfm; /* crypto handle */
+ } conf;
+
+ /* Integrity. It is active when icv_full_len != 0 */
+@@ -34,7 +36,7 @@ struct esp_data
+ void (*icv)(struct esp_data*,
+ struct sk_buff *skb,
+ int offset, int len, u8 *icv);
+- struct crypto_tfm *tfm;
++ struct crypto_hash *tfm;
+ } auth;
+ };
+
+@@ -42,18 +44,22 @@ extern int skb_to_sgvec(struct sk_buff *
+ extern int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
+ extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len);
+
+-static inline void
+-esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset,
+- int len, u8 *auth_data)
++static inline int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb,
++ int offset, int len)
+ {
+- struct crypto_tfm *tfm = esp->auth.tfm;
+- char *icv = esp->auth.work_icv;
+-
+- memset(auth_data, 0, esp->auth.icv_trunc_len);
+- crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len);
+- skb_icv_walk(skb, tfm, offset, len, crypto_hmac_update);
+- crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, icv);
+- memcpy(auth_data, icv, esp->auth.icv_trunc_len);
++ struct hash_desc desc;
++ int err;
++
++ desc.tfm = esp->auth.tfm;
++ desc.flags = 0;
++
++ err = crypto_hash_init(&desc);
++ if (unlikely(err))
++ return err;
++ err = skb_icv_walk(skb, &desc, offset, len, crypto_hash_update);
++ if (unlikely(err))
++ return err;
++ return crypto_hash_final(&desc, esp->auth.work_icv);
+ }
+
+ #endif
+diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
+new file mode 100644
+index 0000000..8e2f473
+--- /dev/null
++++ b/include/net/fib_rules.h
+@@ -0,0 +1,97 @@
++#ifndef __NET_FIB_RULES_H
++#define __NET_FIB_RULES_H
++
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/fib_rules.h>
++#include <net/flow.h>
++#include <net/netlink.h>
++
++struct fib_rule
++{
++ struct list_head list;
++ atomic_t refcnt;
++ int ifindex;
++ char ifname[IFNAMSIZ];
++ u32 pref;
++ u32 flags;
++ u32 table;
++ u8 action;
++ struct rcu_head rcu;
++};
++
++struct fib_lookup_arg
++{
++ void *lookup_ptr;
++ void *result;
++ struct fib_rule *rule;
++};
++
++struct fib_rules_ops
++{
++ int family;
++ struct list_head list;
++ int rule_size;
++
++ int (*action)(struct fib_rule *,
++ struct flowi *, int,
++ struct fib_lookup_arg *);
++ int (*match)(struct fib_rule *,
++ struct flowi *, int);
++ int (*configure)(struct fib_rule *,
++ struct sk_buff *,
++ struct nlmsghdr *,
++ struct fib_rule_hdr *,
++ struct nlattr **);
++ int (*compare)(struct fib_rule *,
++ struct fib_rule_hdr *,
++ struct nlattr **);
++ int (*fill)(struct fib_rule *, struct sk_buff *,
++ struct nlmsghdr *,
++ struct fib_rule_hdr *);
++ u32 (*default_pref)(void);
++
++ int nlgroup;
++ struct nla_policy *policy;
++ struct list_head *rules_list;
++ struct module *owner;
++};
++
++static inline void fib_rule_get(struct fib_rule *rule)
++{
++ atomic_inc(&rule->refcnt);
++}
++
++static inline void fib_rule_put_rcu(struct rcu_head *head)
++{
++ struct fib_rule *rule = container_of(head, struct fib_rule, rcu);
++ kfree(rule);
++}
++
++static inline void fib_rule_put(struct fib_rule *rule)
++{
++ if (atomic_dec_and_test(&rule->refcnt))
++ call_rcu(&rule->rcu, fib_rule_put_rcu);
++}
++
++static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
++{
++ if (nla[FRA_TABLE])
++ return nla_get_u32(nla[FRA_TABLE]);
++ return frh->table;
++}
++
++extern int fib_rules_register(struct fib_rules_ops *);
++extern int fib_rules_unregister(struct fib_rules_ops *);
++
++extern int fib_rules_lookup(struct fib_rules_ops *,
++ struct flowi *, int flags,
++ struct fib_lookup_arg *);
++
++extern int fib_nl_newrule(struct sk_buff *,
++ struct nlmsghdr *, void *);
++extern int fib_nl_delrule(struct sk_buff *,
++ struct nlmsghdr *, void *);
++extern int fib_rules_dump(struct sk_buff *,
++ struct netlink_callback *, int);
++#endif
+diff --git a/include/net/flow.h b/include/net/flow.h
+index 04d89f7..5cda27c 100644
+--- a/include/net/flow.h
++++ b/include/net/flow.h
+@@ -16,8 +16,8 @@ struct flowi {
+
+ union {
+ struct {
+- __u32 daddr;
+- __u32 saddr;
++ __be32 daddr;
++ __be32 saddr;
+ __u32 fwmark;
+ __u8 tos;
+ __u8 scope;
+@@ -26,6 +26,7 @@ struct flowi {
+ struct {
+ struct in6_addr daddr;
+ struct in6_addr saddr;
++ __u32 fwmark;
+ __u32 flowlabel;
+ } ip6_u;
+
+@@ -42,6 +43,7 @@ struct flowi {
+ #define fld_scope nl_u.dn_u.scope
+ #define fl6_dst nl_u.ip6_u.daddr
+ #define fl6_src nl_u.ip6_u.saddr
++#define fl6_fwmark nl_u.ip6_u.fwmark
+ #define fl6_flowlabel nl_u.ip6_u.flowlabel
+ #define fl4_dst nl_u.ip4_u.daddr
+ #define fl4_src nl_u.ip4_u.saddr
+@@ -54,8 +56,8 @@ struct flowi {
+ #define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
+ union {
+ struct {
+- __u16 sport;
+- __u16 dport;
++ __be16 sport;
++ __be16 dport;
+ } ports;
+
+ struct {
+@@ -66,18 +68,25 @@ struct flowi {
+ struct {
+ __le16 sport;
+ __le16 dport;
+- __u8 objnum;
+- __u8 objnamel; /* Not 16 bits since max val is 16 */
+- __u8 objname[16]; /* Not zero terminated */
+ } dnports;
+
+- __u32 spi;
++ __be32 spi;
++
++#ifdef CONFIG_IPV6_MIP6
++ struct {
++ __u8 type;
++ } mht;
++#endif
+ } uli_u;
+ #define fl_ip_sport uli_u.ports.sport
+ #define fl_ip_dport uli_u.ports.dport
+ #define fl_icmp_type uli_u.icmpt.type
+ #define fl_icmp_code uli_u.icmpt.code
+ #define fl_ipsec_spi uli_u.spi
++#ifdef CONFIG_IPV6_MIP6
++#define fl_mh_type uli_u.mht.type
++#endif
++ __u32 secid; /* used by xfrm; see secid.txt */
+ } __attribute__((__aligned__(BITS_PER_LONG/8)));
+
+ #define FLOW_DIR_IN 0
+@@ -85,10 +94,10 @@ struct flowi {
+ #define FLOW_DIR_FWD 2
+
+ struct sock;
+-typedef void (*flow_resolve_t)(struct flowi *key, u32 sk_sid, u16 family, u8 dir,
++typedef int (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir,
+ void **objp, atomic_t **obj_refp);
+
+-extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir,
++extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
+ flow_resolve_t resolver);
+ extern void flow_cache_flush(void);
+ extern atomic_t flow_cache_genid;
+diff --git a/include/net/genetlink.h b/include/net/genetlink.h
+index 8c22872..b619314 100644
+--- a/include/net/genetlink.h
++++ b/include/net/genetlink.h
+@@ -27,8 +27,6 @@ struct genl_family
+ struct list_head family_list; /* private */
+ };
+
+-#define GENL_ADMIN_PERM 0x01
+-
+ /**
+ * struct genl_info - receiving information
+ * @snd_seq: sending sequence number
+@@ -133,11 +131,12 @@ static inline int genlmsg_cancel(struct
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
++ * @flags: allocation flags
+ */
+ static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
+- unsigned int group)
++ unsigned int group, gfp_t flags)
+ {
+- return nlmsg_multicast(genl_sock, skb, pid, group);
++ return nlmsg_multicast(genl_sock, skb, pid, group, flags);
+ }
+
+ /**
+@@ -170,4 +169,22 @@ static inline int genlmsg_len(const stru
+ return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
+ }
+
++/**
++ * genlmsg_msg_size - length of genetlink message not including padding
++ * @payload: length of message payload
++ */
++static inline int genlmsg_msg_size(int payload)
++{
++ return GENL_HDRLEN + payload;
++}
++
++/**
++ * genlmsg_total_size - length of genetlink message including padding
++ * @payload: length of message payload
++ */
++static inline int genlmsg_total_size(int payload)
++{
++ return NLMSG_ALIGN(genlmsg_msg_size(payload));
++}
++
+ #endif /* __NET_GENERIC_NETLINK_H */
+diff --git a/include/net/icmp.h b/include/net/icmp.h
+index 05f8ff7..dc09474 100644
+--- a/include/net/icmp.h
++++ b/include/net/icmp.h
+@@ -38,7 +38,7 @@ struct dst_entry;
+ struct net_proto_family;
+ struct sk_buff;
+
+-extern void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info);
++extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
+ extern int icmp_rcv(struct sk_buff *skb);
+ extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+ extern void icmp_init(struct net_proto_family *ops);
+diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
+index ecc4286..b174ebb 100644
+--- a/include/net/ieee80211.h
++++ b/include/net/ieee80211.h
+@@ -240,6 +240,11 @@ struct ieee80211_snap_hdr {
+ #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
+ #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
+
++/* 802.11g ERP information element */
++#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
++#define WLAN_ERP_USE_PROTECTION (1<<1)
++#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
++
+ /* Status codes */
+ enum ieee80211_statuscode {
+ WLAN_STATUS_SUCCESS = 0,
+@@ -747,6 +752,8 @@ struct ieee80211_txb {
+ #define NETWORK_HAS_IBSS_DFS (1<<8)
+ #define NETWORK_HAS_TPC_REPORT (1<<9)
+
++#define NETWORK_HAS_ERP_VALUE (1<<10)
++
+ #define QOS_QUEUE_NUM 4
+ #define QOS_OUI_LEN 3
+ #define QOS_OUI_TYPE 2
+@@ -1252,6 +1259,8 @@ extern int ieee80211_tx_frame(struct iee
+ int total_len, int encrypt_mpdu);
+
+ /* ieee80211_rx.c */
++extern void ieee80211_rx_any(struct ieee80211_device *ieee,
++ struct sk_buff *skb, struct ieee80211_rx_stats *stats);
+ extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats);
+ /* make sure to set stats->len */
+diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
+index 00ad810..617b672 100644
+--- a/include/net/ieee80211softmac.h
++++ b/include/net/ieee80211softmac.h
+@@ -63,13 +63,11 @@ struct ieee80211softmac_wpa {
+
+ /*
+ * Information about association
+- *
+- * Do we need a lock for this?
+- * We only ever use this structure inlined
+- * into our global struct. I've used its lock,
+- * but maybe we need a local one here?
+ */
+ struct ieee80211softmac_assoc_info {
++
++ struct mutex mutex;
++
+ /*
+ * This is the requested ESSID. It is written
+ * only by the WX handlers.
+@@ -86,9 +84,6 @@ struct ieee80211softmac_assoc_info {
+
+ /* BSSID we're trying to associate to */
+ char bssid[ETH_ALEN];
+-
+- /* Rates supported by the network */
+- struct ieee80211softmac_ratesinfo supported_rates;
+
+ /* some flags.
+ * static_essid is valid if the essid is constant,
+@@ -102,11 +97,13 @@ struct ieee80211softmac_assoc_info {
+ *
+ * bssfixed is used for SIOCSIWAP.
+ */
+- u8 static_essid:1,
+- associating:1,
+- assoc_wait:1,
+- bssvalid:1,
+- bssfixed:1;
++ u8 static_essid;
++ u8 short_preamble_available;
++ u8 associating;
++ u8 associated;
++ u8 assoc_wait;
++ u8 bssvalid;
++ u8 bssfixed;
+
+ /* Scan retries remaining */
+ int scan_retry;
+@@ -115,6 +112,19 @@ struct ieee80211softmac_assoc_info {
+ struct work_struct timeout;
+ };
+
++struct ieee80211softmac_bss_info {
++ /* Rates supported by the network */
++ struct ieee80211softmac_ratesinfo supported_rates;
++
++ /* This indicates whether frames can currently be transmitted with
++ * short preamble (only use this variable during TX at CCK rates) */
++ u8 short_preamble:1;
++
++ /* This indicates whether protection (e.g. self-CTS) should be used
++ * when transmitting with OFDM modulation */
++ u8 use_protection:1;
++};
++
+ enum {
+ IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1,
+ IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2,
+@@ -157,6 +167,10 @@ struct ieee80211softmac_txrates {
+ #define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */
+ #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */
+
++#define IEEE80211SOFTMAC_BSSINFOCHG_RATES (1 << 0) /* supported_rates */
++#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE (1 << 1) /* short_preamble */
++#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION (1 << 2) /* use_protection */
++
+ struct ieee80211softmac_device {
+ /* 802.11 structure for data stuff */
+ struct ieee80211_device *ieee;
+@@ -200,22 +214,27 @@ struct ieee80211softmac_device {
+ * The driver just needs to read them.
+ */
+ struct ieee80211softmac_txrates txrates;
+- /* If the driver needs to do stuff on TX rate changes, assign this callback. */
++
++ /* If the driver needs to do stuff on TX rate changes, assign this
++ * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */
+ void (*txrates_change)(struct net_device *dev,
+- u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */
+- const struct ieee80211softmac_txrates *rates_before_change);
++ u32 changes);
++
++ /* If the driver needs to do stuff when BSS properties change, assign
++ * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */
++ void (*bssinfo_change)(struct net_device *dev,
++ u32 changes);
+
+ /* private stuff follows */
+ /* this lock protects this structure */
+ spinlock_t lock;
+-
+- /* couple of flags */
+- u8 scanning:1, /* protects scanning from being done multiple times at once */
+- associated:1,
+- running:1;
+-
++
++ u8 running; /* SoftMAC started? */
++ u8 scanning;
++
+ struct ieee80211softmac_scaninfo *scaninfo;
+ struct ieee80211softmac_assoc_info associnfo;
++ struct ieee80211softmac_bss_info bssinfo;
+
+ struct list_head auth_queue;
+ struct list_head events;
+@@ -228,7 +247,7 @@ struct ieee80211softmac_device {
+
+ /* we need to keep a list of network structs we copied */
+ struct list_head network_list;
+-
++
+ /* This must be the last item so that it points to the data
+ * allocated beyond this structure by alloc_ieee80211 */
+ u8 priv[0];
+@@ -257,6 +276,14 @@ extern void ieee80211softmac_fragment_lo
+ * Note that the rates need to be sorted. */
+ extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
+
++/* Finds the highest rate which is:
++ * 1. Present in ri (optionally a basic rate)
++ * 2. Supported by the device
++ * 3. Less than or equal to the user-defined rate
++ */
++extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
++ struct ieee80211softmac_ratesinfo *ri, int basic_only);
++
+ /* Helper function which advises you the rate at which a frame should be
+ * transmitted at. */
+ static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
+@@ -265,7 +292,7 @@ static inline u8 ieee80211softmac_sugges
+ {
+ struct ieee80211softmac_txrates *txrates = &mac->txrates;
+
+- if (!mac->associated)
++ if (!mac->associnfo.associated)
+ return txrates->mgt_mcast_rate;
+
+ /* We are associated, sending unicast frame */
+@@ -279,6 +306,24 @@ static inline u8 ieee80211softmac_sugges
+ return txrates->mcast_rate;
+ }
+
++/* Helper function which advises you when it is safe to transmit with short
++ * preamble.
++ * You should only call this function when transmitting at CCK rates. */
++static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac,
++ int is_multicast,
++ int is_mgt)
++{
++ return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble;
++}
++
++/* Helper function which advises you whether protection (e.g. self-CTS) is
++ * needed. 1 = protection needed, 0 = no protection needed
++ * Only use this function when transmitting with OFDM modulation. */
++static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac)
++{
++ return mac->bssinfo.use_protection;
++}
++
+ /* Start the SoftMAC. Call this after you initialized the device
+ * and it is ready to run.
+ */
+diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
+index e459e1a..34489c1 100644
+--- a/include/net/if_inet6.h
++++ b/include/net/if_inet6.h
+@@ -189,6 +189,7 @@ struct inet6_dev
+ struct ipv6_devconf cnf;
+ struct ipv6_devstat stats;
+ unsigned long tstamp; /* ipv6InterfaceTable update timestamp */
++ struct rcu_head rcu;
+ };
+
+ extern struct ipv6_devconf ipv6_devconf;
+diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
+index 9bf73fe..0bcf9f2 100644
+--- a/include/net/inet_connection_sock.h
++++ b/include/net/inet_connection_sock.h
+@@ -147,7 +147,8 @@ extern struct sock *inet_csk_clone(struc
+ enum inet_csk_ack_state_t {
+ ICSK_ACK_SCHED = 1,
+ ICSK_ACK_TIMER = 2,
+- ICSK_ACK_PUSHED = 4
++ ICSK_ACK_PUSHED = 4,
++ ICSK_ACK_PUSHED2 = 8
+ };
+
+ extern void inet_csk_init_xmit_timers(struct sock *sk,
+@@ -237,9 +238,9 @@ extern struct sock *inet_csk_accept(stru
+
+ extern struct request_sock *inet_csk_search_req(const struct sock *sk,
+ struct request_sock ***prevp,
+- const __u16 rport,
+- const __u32 raddr,
+- const __u32 laddr);
++ const __be16 rport,
++ const __be32 raddr,
++ const __be32 laddr);
+ extern int inet_csk_bind_conflict(const struct sock *sk,
+ const struct inet_bind_bucket *tb);
+ extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
+diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
+index d599c6b..7849844 100644
+--- a/include/net/inet_ecn.h
++++ b/include/net/inet_ecn.h
+@@ -48,7 +48,7 @@ static inline __u8 INET_ECN_encapsulate(
+
+ #define IP6_ECN_flow_xmit(sk, label) do { \
+ if (INET_ECN_is_capable(inet_sk(sk)->tos)) \
+- (label) |= __constant_htons(INET_ECN_ECT_0 << 4); \
++ (label) |= htonl(INET_ECN_ECT_0 << 20); \
+ } while (0)
+
+ static inline int IP_ECN_set_ce(struct iphdr *iph)
+diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
+index 98e0bb3..a9eb2ea 100644
+--- a/include/net/inet_hashtables.h
++++ b/include/net/inet_hashtables.h
+@@ -271,66 +271,57 @@ static inline int inet_iif(const struct
+ return ((struct rtable *)skb->dst)->rt_iif;
+ }
+
+-extern struct sock *__inet_lookup_listener(const struct hlist_head *head,
+- const u32 daddr,
++extern struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
++ const __be32 daddr,
+ const unsigned short hnum,
+ const int dif);
+
+-/* Optimize the common listener case. */
+-static inline struct sock *
+- inet_lookup_listener(struct inet_hashinfo *hashinfo,
+- const u32 daddr,
+- const unsigned short hnum, const int dif)
++static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
++ __be32 daddr, __be16 dport, int dif)
+ {
+- struct sock *sk = NULL;
+- const struct hlist_head *head;
+-
+- read_lock(&hashinfo->lhash_lock);
+- head = &hashinfo->listening_hash[inet_lhashfn(hnum)];
+- if (!hlist_empty(head)) {
+- const struct inet_sock *inet = inet_sk((sk = __sk_head(head)));
+-
+- if (inet->num == hnum && !sk->sk_node.next &&
+- (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
+- (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
+- !sk->sk_bound_dev_if)
+- goto sherry_cache;
+- sk = __inet_lookup_listener(head, daddr, hnum, dif);
+- }
+- if (sk) {
+-sherry_cache:
+- sock_hold(sk);
+- }
+- read_unlock(&hashinfo->lhash_lock);
+- return sk;
++ return __inet_lookup_listener(hashinfo, daddr, ntohs(dport), dif);
+ }
+
+ /* Socket demux engine toys. */
++/* What happens here is ugly; there's a pair of adjacent fields in
++ struct inet_sock; __be16 dport followed by __u16 num. We want to
++ search by pair, so we combine the keys into a single 32bit value
++ and compare with 32bit value read from &...->dport. Let's at least
++ make sure that it's not mixed with anything else...
++ On 64bit targets we combine comparisons with pair of adjacent __be32
++ fields in the same way.
++*/
++typedef __u32 __bitwise __portpair;
+ #ifdef __BIG_ENDIAN
+ #define INET_COMBINED_PORTS(__sport, __dport) \
+- (((__u32)(__sport) << 16) | (__u32)(__dport))
++ ((__force __portpair)(((__force __u32)(__be16)(__sport) << 16) | (__u32)(__dport)))
+ #else /* __LITTLE_ENDIAN */
+ #define INET_COMBINED_PORTS(__sport, __dport) \
+- (((__u32)(__dport) << 16) | (__u32)(__sport))
++ ((__force __portpair)(((__u32)(__dport) << 16) | (__force __u32)(__be16)(__sport)))
+ #endif
+
+ #if (BITS_PER_LONG == 64)
++typedef __u64 __bitwise __addrpair;
+ #ifdef __BIG_ENDIAN
+ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
+- const __u64 __name = (((__u64)(__saddr)) << 32) | ((__u64)(__daddr));
++ const __addrpair __name = (__force __addrpair) ( \
++ (((__force __u64)(__be32)(__saddr)) << 32) | \
++ ((__force __u64)(__be32)(__daddr)));
+ #else /* __LITTLE_ENDIAN */
+ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
+- const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr));
++ const __addrpair __name = (__force __addrpair) ( \
++ (((__force __u64)(__be32)(__daddr)) << 32) | \
++ ((__force __u64)(__be32)(__saddr)));
+ #endif /* __BIG_ENDIAN */
+ #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
+ (((__sk)->sk_hash == (__hash)) && \
+- ((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
+- ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
++ ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
++ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+ #define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
+ (((__sk)->sk_hash == (__hash)) && \
+- ((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
+- ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
++ ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
++ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
+ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+ #else /* 32-bit arch */
+ #define INET_ADDR_COOKIE(__name, __saddr, __daddr)
+@@ -338,13 +329,13 @@ sherry_cache:
+ (((__sk)->sk_hash == (__hash)) && \
+ (inet_sk(__sk)->daddr == (__saddr)) && \
+ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \
+- ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
++ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+ #define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \
+ (((__sk)->sk_hash == (__hash)) && \
+ (inet_twsk(__sk)->tw_daddr == (__saddr)) && \
+ (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \
+- ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
++ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
+ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+ #endif /* 64-bit arch */
+
+@@ -356,12 +347,12 @@ sherry_cache:
+ */
+ static inline struct sock *
+ __inet_lookup_established(struct inet_hashinfo *hashinfo,
+- const u32 saddr, const u16 sport,
+- const u32 daddr, const u16 hnum,
++ const __be32 saddr, const __be16 sport,
++ const __be32 daddr, const u16 hnum,
+ const int dif)
+ {
+ INET_ADDR_COOKIE(acookie, saddr, daddr)
+- const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
++ const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
+ struct sock *sk;
+ const struct hlist_node *node;
+ /* Optimize here for direct hit, only listening connections can
+@@ -391,25 +382,36 @@ hit:
+ goto out;
+ }
+
++static inline struct sock *
++ inet_lookup_established(struct inet_hashinfo *hashinfo,
++ const __be32 saddr, const __be16 sport,
++ const __be32 daddr, const __be16 dport,
++ const int dif)
++{
++ return __inet_lookup_established(hashinfo, saddr, sport, daddr,
++ ntohs(dport), dif);
++}
++
+ static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
+- const u32 saddr, const u16 sport,
+- const u32 daddr, const u16 hnum,
++ const __be32 saddr, const __be16 sport,
++ const __be32 daddr, const __be16 dport,
+ const int dif)
+ {
++ u16 hnum = ntohs(dport);
+ struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
+ hnum, dif);
+- return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif);
++ return sk ? : __inet_lookup_listener(hashinfo, daddr, hnum, dif);
+ }
+
+ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
+- const u32 saddr, const u16 sport,
+- const u32 daddr, const u16 dport,
++ const __be32 saddr, const __be16 sport,
++ const __be32 daddr, const __be16 dport,
+ const int dif)
+ {
+ struct sock *sk;
+
+ local_bh_disable();
+- sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
++ sk = __inet_lookup(hashinfo, saddr, sport, daddr, dport, dif);
+ local_bh_enable();
+
+ return sk;
+diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
+index 1f4a9a6..ce6da97 100644
+--- a/include/net/inet_sock.h
++++ b/include/net/inet_sock.h
+@@ -27,7 +27,6 @@
+ /** struct ip_options - IP Options
+ *
+ * @faddr - Saved first hop address
+- * @is_setbyuser - Set by setsockopt?
+ * @is_data - Options in __data, rather than skb
+ * @is_strictroute - Strict source route
+ * @srr_is_hit - Packet destination addr was our one
+@@ -37,13 +36,12 @@
+ * @ts_needaddr - Need to record addr of outgoing dev
+ */
+ struct ip_options {
+- __u32 faddr;
++ __be32 faddr;
+ unsigned char optlen;
+ unsigned char srr;
+ unsigned char rr;
+ unsigned char ts;
+- unsigned char is_setbyuser:1,
+- is_data:1,
++ unsigned char is_data:1,
+ is_strictroute:1,
+ srr_is_hit:1,
+ is_changed:1,
+@@ -51,7 +49,7 @@ struct ip_options {
+ ts_needtime:1,
+ ts_needaddr:1;
+ unsigned char router_alert;
+- unsigned char __pad1;
++ unsigned char cipso;
+ unsigned char __pad2;
+ unsigned char __data[0];
+ };
+@@ -64,9 +62,9 @@ struct inet_request_sock {
+ u16 inet6_rsk_offset;
+ /* 2 bytes hole, try to pack */
+ #endif
+- u32 loc_addr;
+- u32 rmt_addr;
+- u16 rmt_port;
++ __be32 loc_addr;
++ __be32 rmt_addr;
++ __be16 rmt_port;
+ u16 snd_wscale : 4,
+ rcv_wscale : 4,
+ tstamp_ok : 1,
+@@ -112,15 +110,15 @@ struct inet_sock {
+ struct ipv6_pinfo *pinet6;
+ #endif
+ /* Socket demultiplex comparisons on incoming packets. */
+- __u32 daddr;
+- __u32 rcv_saddr;
+- __u16 dport;
++ __be32 daddr;
++ __be32 rcv_saddr;
++ __be16 dport;
+ __u16 num;
+- __u32 saddr;
++ __be32 saddr;
+ __s16 uc_ttl;
+ __u16 cmsg_flags;
+ struct ip_options *opt;
+- __u16 sport;
++ __be16 sport;
+ __u16 id;
+ __u8 tos;
+ __u8 mc_ttl;
+@@ -131,7 +129,7 @@ struct inet_sock {
+ hdrincl:1,
+ mc_loop:1;
+ int mc_index;
+- __u32 mc_addr;
++ __be32 mc_addr;
+ struct ip_mc_socklist *mc_list;
+ struct {
+ unsigned int flags;
+@@ -139,7 +137,7 @@ struct inet_sock {
+ struct ip_options *opt;
+ struct rtable *rt;
+ int length; /* Total length of all frames */
+- u32 addr;
++ __be32 addr;
+ struct flowi fl;
+ } cork;
+ };
+@@ -169,10 +167,10 @@ static inline void inet_sk_copy_descenda
+
+ extern int inet_sk_rebuild_header(struct sock *sk);
+
+-static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
+- const __u32 faddr, const __u16 fport)
++static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
++ const __be32 faddr, const __be16 fport)
+ {
+- unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
++ unsigned int h = ((__force __u32)laddr ^ lport) ^ ((__force __u32)faddr ^ (__force __u32)fport);
+ h ^= h >> 16;
+ h ^= h >> 8;
+ return h;
+@@ -181,10 +179,10 @@ static inline unsigned int inet_ehashfn(
+ static inline int inet_sk_ehashfn(const struct sock *sk)
+ {
+ const struct inet_sock *inet = inet_sk(sk);
+- const __u32 laddr = inet->rcv_saddr;
++ const __be32 laddr = inet->rcv_saddr;
+ const __u16 lport = inet->num;
+- const __u32 faddr = inet->daddr;
+- const __u16 fport = inet->dport;
++ const __be32 faddr = inet->daddr;
++ const __be16 fport = inet->dport;
+
+ return inet_ehashfn(laddr, lport, faddr, fport);
+ }
+diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
+index 600cb54..5f48748 100644
+--- a/include/net/inet_timewait_sock.h
++++ b/include/net/inet_timewait_sock.h
+@@ -120,10 +120,10 @@ struct inet_timewait_sock {
+ unsigned char tw_rcv_wscale;
+ /* Socket demultiplex comparisons on incoming packets. */
+ /* these five are in inet_sock */
+- __u16 tw_sport;
+- __u32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
+- __u32 tw_rcv_saddr;
+- __u16 tw_dport;
++ __be16 tw_sport;
++ __be32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
++ __be32 tw_rcv_saddr;
++ __be16 tw_dport;
+ __u16 tw_num;
+ /* And these are ours. */
+ __u8 tw_ipv6only:1;
+@@ -186,7 +186,7 @@ static inline struct inet_timewait_sock
+ return (struct inet_timewait_sock *)sk;
+ }
+
+-static inline u32 inet_rcv_saddr(const struct sock *sk)
++static inline __be32 inet_rcv_saddr(const struct sock *sk)
+ {
+ return likely(sk->sk_state != TCP_TIME_WAIT) ?
+ inet_sk(sk)->rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
+@@ -196,6 +196,7 @@ static inline void inet_twsk_put(struct
+ {
+ if (atomic_dec_and_test(&tw->tw_refcnt)) {
+ struct module *owner = tw->tw_prot->owner;
++ twsk_destructor((struct sock *)tw);
+ #ifdef SOCK_REFCNT_DEBUG
+ printk(KERN_DEBUG "%s timewait_sock %p released\n",
+ tw->tw_prot->name, tw);
+diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
+index 0965515..aa10a81 100644
+--- a/include/net/inetpeer.h
++++ b/include/net/inetpeer.h
+@@ -17,14 +17,15 @@
+
+ struct inet_peer
+ {
++ /* group together avl_left,avl_right,v4daddr to speedup lookups */
+ struct inet_peer *avl_left, *avl_right;
++ __be32 v4daddr; /* peer's address */
++ __u16 avl_height;
++ __u16 ip_id_count; /* IP ID for the next packet */
+ struct inet_peer *unused_next, **unused_prevp;
+- unsigned long dtime; /* the time of last use of not
++ __u32 dtime; /* the time of last use of not
+ * referenced entries */
+ atomic_t refcnt;
+- __u32 v4daddr; /* peer's address */
+- __u16 avl_height;
+- __u16 ip_id_count; /* IP ID for the next packet */
+ atomic_t rid; /* Frag reception counter */
+ __u32 tcp_ts;
+ unsigned long tcp_ts_stamp;
+@@ -33,23 +34,10 @@ struct inet_peer
+ void inet_initpeers(void) __init;
+
+ /* can be called with or without local BH being disabled */
+-struct inet_peer *inet_getpeer(__u32 daddr, int create);
++struct inet_peer *inet_getpeer(__be32 daddr, int create);
+
+-extern spinlock_t inet_peer_unused_lock;
+-extern struct inet_peer **inet_peer_unused_tailp;
+ /* can be called from BH context or outside */
+-static inline void inet_putpeer(struct inet_peer *p)
+-{
+- spin_lock_bh(&inet_peer_unused_lock);
+- if (atomic_dec_and_test(&p->refcnt)) {
+- p->unused_prevp = inet_peer_unused_tailp;
+- p->unused_next = NULL;
+- *inet_peer_unused_tailp = p;
+- inet_peer_unused_tailp = &p->unused_next;
+- p->dtime = jiffies;
+- }
+- spin_unlock_bh(&inet_peer_unused_lock);
+-}
++extern void inet_putpeer(struct inet_peer *p);
+
+ extern spinlock_t inet_peer_idlock;
+ /* can be called with or without local BH being disabled */
+diff --git a/include/net/ip.h b/include/net/ip.h
+index 98f9084..b6d95e5 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -45,7 +45,7 @@ struct inet_skb_parm
+
+ struct ipcm_cookie
+ {
+- u32 addr;
++ __be32 addr;
+ int oif;
+ struct ip_options *opt;
+ };
+@@ -86,7 +86,7 @@ extern int igmp_mc_proc_init(void);
+ */
+
+ extern int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+- u32 saddr, u32 daddr,
++ __be32 saddr, __be32 daddr,
+ struct ip_options *opt);
+ extern int ip_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev);
+@@ -335,7 +335,7 @@ extern int ip_net_unreachable(struct sk_
+ * Functions provided by ip_options.c
+ */
+
+-extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, u32 daddr, struct rtable *rt, int is_frag);
++extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag);
+ extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
+ extern void ip_options_fragment(struct sk_buff *skb);
+ extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb);
+@@ -363,8 +363,8 @@ extern int ip_ra_control(struct sock *sk
+
+ extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len);
+ extern void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+- u16 port, u32 info, u8 *payload);
+-extern void ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
++ __be16 port, u32 info, u8 *payload);
++extern void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
+ u32 info);
+
+ /* sysctl helpers - any sysctl which holds a value that ends up being
+diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
+index a66e9de..e4438de 100644
+--- a/include/net/ip6_fib.h
++++ b/include/net/ip6_fib.h
+@@ -16,14 +16,35 @@
+ #ifdef __KERNEL__
+
+ #include <linux/ipv6_route.h>
+-
+-#include <net/dst.h>
+-#include <net/flow.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/spinlock.h>
++#include <net/dst.h>
++#include <net/flow.h>
++#include <net/netlink.h>
+
+ struct rt6_info;
+
++struct fib6_config
++{
++ u32 fc_table;
++ u32 fc_metric;
++ int fc_dst_len;
++ int fc_src_len;
++ int fc_ifindex;
++ u32 fc_flags;
++ u32 fc_protocol;
++
++ struct in6_addr fc_dst;
++ struct in6_addr fc_src;
++ struct in6_addr fc_gateway;
++
++ unsigned long fc_expires;
++ struct nlattr *fc_mx;
++ int fc_mx_len;
++
++ struct nl_info fc_nlinfo;
++};
++
+ struct fib6_node
+ {
+ struct fib6_node *parent;
+@@ -39,6 +60,11 @@ struct fib6_node
+ __u32 fn_sernum;
+ };
+
++#ifndef CONFIG_IPV6_SUBTREES
++#define FIB6_SUBTREE(fn) NULL
++#else
++#define FIB6_SUBTREE(fn) ((fn)->subtree)
++#endif
+
+ /*
+ * routing information
+@@ -51,6 +77,8 @@ struct rt6key
+ int plen;
+ };
+
++struct fib6_table;
++
+ struct rt6_info
+ {
+ union {
+@@ -71,6 +99,7 @@ struct rt6_info
+ u32 rt6i_flags;
+ u32 rt6i_metric;
+ atomic_t rt6i_ref;
++ struct fib6_table *rt6i_table;
+
+ struct rt6key rt6i_dst;
+ struct rt6key rt6i_src;
+@@ -89,28 +118,6 @@ struct fib6_walker_t
+ void *args;
+ };
+
+-extern struct fib6_walker_t fib6_walker_list;
+-extern rwlock_t fib6_walker_lock;
+-
+-static inline void fib6_walker_link(struct fib6_walker_t *w)
+-{
+- write_lock_bh(&fib6_walker_lock);
+- w->next = fib6_walker_list.next;
+- w->prev = &fib6_walker_list;
+- w->next->prev = w;
+- w->prev->next = w;
+- write_unlock_bh(&fib6_walker_lock);
+-}
+-
+-static inline void fib6_walker_unlink(struct fib6_walker_t *w)
+-{
+- write_lock_bh(&fib6_walker_lock);
+- w->next->prev = w->prev;
+- w->prev->next = w->next;
+- w->prev = w->next = w;
+- write_unlock_bh(&fib6_walker_lock);
+-}
+-
+ struct rt6_statistics {
+ __u32 fib_nodes;
+ __u32 fib_route_nodes;
+@@ -143,12 +150,41 @@ struct rt6_statistics {
+
+ typedef void (*f_pnode)(struct fib6_node *fn, void *);
+
+-extern struct fib6_node ip6_routing_table;
++struct fib6_table {
++ struct hlist_node tb6_hlist;
++ u32 tb6_id;
++ rwlock_t tb6_lock;
++ struct fib6_node tb6_root;
++};
++
++#define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC
++#define RT6_TABLE_MAIN RT_TABLE_MAIN
++#define RT6_TABLE_DFLT RT6_TABLE_MAIN
++#define RT6_TABLE_INFO RT6_TABLE_MAIN
++#define RT6_TABLE_PREFIX RT6_TABLE_MAIN
++
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++#define FIB6_TABLE_MIN 1
++#define FIB6_TABLE_MAX RT_TABLE_MAX
++#define RT6_TABLE_LOCAL RT_TABLE_LOCAL
++#else
++#define FIB6_TABLE_MIN RT_TABLE_MAIN
++#define FIB6_TABLE_MAX FIB6_TABLE_MIN
++#define RT6_TABLE_LOCAL RT6_TABLE_MAIN
++#endif
++
++typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
++ struct flowi *, int);
+
+ /*
+ * exported functions
+ */
+
++extern struct fib6_table * fib6_get_table(u32 id);
++extern struct fib6_table * fib6_new_table(u32 id);
++extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags,
++ pol_lookup_t lookup);
++
+ extern struct fib6_node *fib6_lookup(struct fib6_node *root,
+ struct in6_addr *daddr,
+ struct in6_addr *saddr);
+@@ -157,32 +193,29 @@ struct fib6_node *fib6_locate(struct fi
+ struct in6_addr *daddr, int dst_len,
+ struct in6_addr *saddr, int src_len);
+
+-extern void fib6_clean_tree(struct fib6_node *root,
+- int (*func)(struct rt6_info *, void *arg),
+- int prune, void *arg);
+-
+-extern int fib6_walk(struct fib6_walker_t *w);
+-extern int fib6_walk_continue(struct fib6_walker_t *w);
++extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
++ int prune, void *arg);
+
+ extern int fib6_add(struct fib6_node *root,
+ struct rt6_info *rt,
+- struct nlmsghdr *nlh,
+- void *rtattr,
+- struct netlink_skb_parms *req);
++ struct nl_info *info);
+
+ extern int fib6_del(struct rt6_info *rt,
+- struct nlmsghdr *nlh,
+- void *rtattr,
+- struct netlink_skb_parms *req);
++ struct nl_info *info);
+
+ extern void inet6_rt_notify(int event, struct rt6_info *rt,
+- struct nlmsghdr *nlh,
+- struct netlink_skb_parms *req);
++ struct nl_info *info);
+
+ extern void fib6_run_gc(unsigned long dummy);
+
+ extern void fib6_gc_cleanup(void);
+
+ extern void fib6_init(void);
++
++extern void fib6_rules_init(void);
++extern void fib6_rules_cleanup(void);
++extern int fib6_rules_dump(struct sk_buff *,
++ struct netlink_callback *);
++
+ #endif
+ #endif
+diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
+index 96b0e66..c14b70e 100644
+--- a/include/net/ip6_route.h
++++ b/include/net/ip6_route.h
+@@ -32,15 +32,17 @@ struct route_info {
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
+
+-struct pol_chain {
+- int type;
+- int priority;
+- struct fib6_node *rules;
+- struct pol_chain *next;
+-};
++#define RT6_LOOKUP_F_IFACE 0x1
++#define RT6_LOOKUP_F_REACHABLE 0x2
++#define RT6_LOOKUP_F_HAS_SADDR 0x4
+
+ extern struct rt6_info ip6_null_entry;
+
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++extern struct rt6_info ip6_prohibit_entry;
++extern struct rt6_info ip6_blk_hole_entry;
++#endif
++
+ extern int ip6_rt_gc_interval;
+
+ extern void ip6_route_input(struct sk_buff *skb);
+@@ -48,25 +50,14 @@ extern void ip6_route_input(struct sk_
+ extern struct dst_entry * ip6_route_output(struct sock *sk,
+ struct flowi *fl);
+
+-extern int ip6_route_me_harder(struct sk_buff *skb);
+-
+ extern void ip6_route_init(void);
+ extern void ip6_route_cleanup(void);
+
+ extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg);
+
+-extern int ip6_route_add(struct in6_rtmsg *rtmsg,
+- struct nlmsghdr *,
+- void *rtattr,
+- struct netlink_skb_parms *req);
+-extern int ip6_ins_rt(struct rt6_info *,
+- struct nlmsghdr *,
+- void *rtattr,
+- struct netlink_skb_parms *req);
+-extern int ip6_del_rt(struct rt6_info *,
+- struct nlmsghdr *,
+- void *rtattr,
+- struct netlink_skb_parms *req);
++extern int ip6_route_add(struct fib6_config *cfg);
++extern int ip6_ins_rt(struct rt6_info *);
++extern int ip6_del_rt(struct rt6_info *);
+
+ extern int ip6_rt_addr_add(struct in6_addr *addr,
+ struct net_device *dev,
+@@ -114,6 +105,7 @@ extern int rt6_route_rcv(struct net_de
+ struct in6_addr *gwaddr);
+
+ extern void rt6_redirect(struct in6_addr *dest,
++ struct in6_addr *src,
+ struct in6_addr *saddr,
+ struct neighbour *neigh,
+ u8 *lladdr,
+@@ -131,6 +123,13 @@ extern int inet6_rtm_newroute(struct sk_
+ extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+ extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+
++struct rt6_rtnl_dump_arg
++{
++ struct sk_buff *skb;
++ struct netlink_callback *cb;
++};
++
++extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
+ extern void rt6_ifdown(struct net_device *dev);
+ extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
+
+@@ -140,21 +139,24 @@ extern rwlock_t rt6_lock;
+ * Store a destination cache entry in a socket
+ */
+ static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst,
+- struct in6_addr *daddr)
++ struct in6_addr *daddr, struct in6_addr *saddr)
+ {
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct rt6_info *rt = (struct rt6_info *) dst;
+
+ sk_setup_caps(sk, dst);
+ np->daddr_cache = daddr;
++#ifdef CONFIG_IPV6_SUBTREES
++ np->saddr_cache = saddr;
++#endif
+ np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+ }
+
+ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
+- struct in6_addr *daddr)
++ struct in6_addr *daddr, struct in6_addr *saddr)
+ {
+ write_lock(&sk->sk_dst_lock);
+- __ip6_dst_store(sk, dst, daddr);
++ __ip6_dst_store(sk, dst, daddr, saddr);
+ write_unlock(&sk->sk_dst_lock);
+ }
+
+diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
+index a095d1d..949b932 100644
+--- a/include/net/ip_fib.h
++++ b/include/net/ip_fib.h
+@@ -18,26 +18,31 @@
+
+ #include <net/flow.h>
+ #include <linux/seq_file.h>
+-
+-/* WARNING: The ordering of these elements must match ordering
+- * of RTA_* rtnetlink attribute numbers.
+- */
+-struct kern_rta {
+- void *rta_dst;
+- void *rta_src;
+- int *rta_iif;
+- int *rta_oif;
+- void *rta_gw;
+- u32 *rta_priority;
+- void *rta_prefsrc;
+- struct rtattr *rta_mx;
+- struct rtattr *rta_mp;
+- unsigned char *rta_protoinfo;
+- u32 *rta_flow;
+- struct rta_cacheinfo *rta_ci;
+- struct rta_session *rta_sess;
+- u32 *rta_mp_alg;
+-};
++#include <net/fib_rules.h>
++
++struct fib_config {
++ u8 fc_dst_len;
++ u8 fc_tos;
++ u8 fc_protocol;
++ u8 fc_scope;
++ u8 fc_type;
++ /* 3 bytes unused */
++ u32 fc_table;
++ __be32 fc_dst;
++ __be32 fc_gw;
++ int fc_oif;
++ u32 fc_flags;
++ u32 fc_priority;
++ __be32 fc_prefsrc;
++ struct nlattr *fc_mx;
++ struct rtnexthop *fc_mp;
++ int fc_mx_len;
++ int fc_mp_len;
++ u32 fc_flow;
++ u32 fc_mp_alg;
++ u32 fc_nlflags;
++ struct nl_info fc_nlinfo;
++ };
+
+ struct fib_info;
+
+@@ -55,7 +60,7 @@ struct fib_nh {
+ __u32 nh_tclassid;
+ #endif
+ int nh_oif;
+- u32 nh_gw;
++ __be32 nh_gw;
+ };
+
+ /*
+@@ -70,7 +75,7 @@ struct fib_info {
+ int fib_dead;
+ unsigned fib_flags;
+ int fib_protocol;
+- u32 fib_prefsrc;
++ __be32 fib_prefsrc;
+ u32 fib_priority;
+ u32 fib_metrics[RTAX_MAX];
+ #define fib_mtu fib_metrics[RTAX_MTU-1]
+@@ -99,8 +104,8 @@ struct fib_result {
+ unsigned char type;
+ unsigned char scope;
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+- __u32 network;
+- __u32 netmask;
++ __be32 network;
++ __be32 netmask;
+ #endif
+ struct fib_info *fi;
+ #ifdef CONFIG_IP_MULTIPLE_TABLES
+@@ -109,7 +114,7 @@ struct fib_result {
+ };
+
+ struct fib_result_nl {
+- u32 fl_addr; /* To be looked up*/
++ __be32 fl_addr; /* To be looked up*/
+ u32 fl_fwmark;
+ unsigned char fl_tos;
+ unsigned char fl_scope;
+@@ -149,15 +154,12 @@ struct fib_result_nl {
+ #endif /* CONFIG_IP_ROUTE_MULTIPATH_WRANDOM */
+
+ struct fib_table {
+- unsigned char tb_id;
++ struct hlist_node tb_hlist;
++ u32 tb_id;
+ unsigned tb_stamp;
+ int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
+- int (*tb_insert)(struct fib_table *table, struct rtmsg *r,
+- struct kern_rta *rta, struct nlmsghdr *n,
+- struct netlink_skb_parms *req);
+- int (*tb_delete)(struct fib_table *table, struct rtmsg *r,
+- struct kern_rta *rta, struct nlmsghdr *n,
+- struct netlink_skb_parms *req);
++ int (*tb_insert)(struct fib_table *, struct fib_config *);
++ int (*tb_delete)(struct fib_table *, struct fib_config *);
+ int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
+ struct netlink_callback *cb);
+ int (*tb_flush)(struct fib_table *table);
+@@ -172,14 +174,14 @@ struct fib_table {
+ extern struct fib_table *ip_fib_local_table;
+ extern struct fib_table *ip_fib_main_table;
+
+-static inline struct fib_table *fib_get_table(int id)
++static inline struct fib_table *fib_get_table(u32 id)
+ {
+ if (id != RT_TABLE_LOCAL)
+ return ip_fib_main_table;
+ return ip_fib_local_table;
+ }
+
+-static inline struct fib_table *fib_new_table(int id)
++static inline struct fib_table *fib_new_table(u32 id)
+ {
+ return fib_get_table(id);
+ }
+@@ -199,67 +201,48 @@ static inline void fib_select_default(co
+ }
+
+ #else /* CONFIG_IP_MULTIPLE_TABLES */
+-#define ip_fib_local_table (fib_tables[RT_TABLE_LOCAL])
+-#define ip_fib_main_table (fib_tables[RT_TABLE_MAIN])
+-
+-extern struct fib_table * fib_tables[RT_TABLE_MAX+1];
+-extern int fib_lookup(const struct flowi *flp, struct fib_result *res);
+-extern struct fib_table *__fib_new_table(int id);
+-extern void fib_rule_put(struct fib_rule *r);
++#define ip_fib_local_table fib_get_table(RT_TABLE_LOCAL)
++#define ip_fib_main_table fib_get_table(RT_TABLE_MAIN)
+
+-static inline struct fib_table *fib_get_table(int id)
+-{
+- if (id == 0)
+- id = RT_TABLE_MAIN;
+-
+- return fib_tables[id];
+-}
+-
+-static inline struct fib_table *fib_new_table(int id)
+-{
+- if (id == 0)
+- id = RT_TABLE_MAIN;
+-
+- return fib_tables[id] ? : __fib_new_table(id);
+-}
++extern int fib_lookup(struct flowi *flp, struct fib_result *res);
+
++extern struct fib_table *fib_new_table(u32 id);
++extern struct fib_table *fib_get_table(u32 id);
+ extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
+
+ #endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+ /* Exported by fib_frontend.c */
++extern struct nla_policy rtm_ipv4_policy[];
+ extern void ip_fib_init(void);
+ extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+ extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+ extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+ extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
+-extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
+- struct net_device *dev, u32 *spec_dst, u32 *itag);
++extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
++ struct net_device *dev, __be32 *spec_dst, u32 *itag);
+ extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
+
+ struct rtentry;
+
+ /* Exported by fib_semantics.c */
+-extern int ip_fib_check_default(u32 gw, struct net_device *dev);
+-extern int fib_sync_down(u32 local, struct net_device *dev, int force);
++extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
++extern int fib_sync_down(__be32 local, struct net_device *dev, int force);
+ extern int fib_sync_up(struct net_device *dev);
+-extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
+- struct kern_rta *rta, struct rtentry *r);
+-extern u32 __fib_res_prefsrc(struct fib_result *res);
++extern __be32 __fib_res_prefsrc(struct fib_result *res);
+
+ /* Exported by fib_hash.c */
+-extern struct fib_table *fib_hash_init(int id);
++extern struct fib_table *fib_hash_init(u32 id);
+
+ #ifdef CONFIG_IP_MULTIPLE_TABLES
+-/* Exported by fib_rules.c */
++extern int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb);
++
++extern void __init fib4_rules_init(void);
+
+-extern int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+-extern int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+-extern int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
+ #ifdef CONFIG_NET_CLS_ROUTE
+ extern u32 fib_rules_tclass(struct fib_result *res);
+ #endif
+-extern void fib_rules_init(void);
++
+ #endif
+
+ static inline void fib_combine_itag(u32 *itag, struct fib_result *res)
+diff --git a/include/net/ip_mp_alg.h b/include/net/ip_mp_alg.h
+index ac747b6..beffdd6 100644
+--- a/include/net/ip_mp_alg.h
++++ b/include/net/ip_mp_alg.h
+@@ -17,7 +17,7 @@ struct ip_mp_alg_ops {
+ void (*mp_alg_select_route)(const struct flowi *flp,
+ struct rtable *rth, struct rtable **rp);
+ void (*mp_alg_flush)(void);
+- void (*mp_alg_set_nhinfo)(__u32 network, __u32 netmask,
++ void (*mp_alg_set_nhinfo)(__be32 network, __be32 netmask,
+ unsigned char prefixlen,
+ const struct fib_nh *nh);
+ void (*mp_alg_remove)(struct rtable *rth);
+@@ -59,7 +59,7 @@ static inline void multipath_flush(void)
+ }
+
+ static inline void multipath_set_nhinfo(struct rtable *rth,
+- __u32 network, __u32 netmask,
++ __be32 network, __be32 netmask,
+ unsigned char prefixlen,
+ const struct fib_nh *nh)
+ {
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 3b57b15..49c717e 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -100,22 +100,22 @@
+ struct ip_vs_service_user {
+ /* virtual service addresses */
+ u_int16_t protocol;
+- u_int32_t addr; /* virtual ip address */
+- u_int16_t port;
++ __be32 addr; /* virtual ip address */
++ __be16 port;
+ u_int32_t fwmark; /* firwall mark of service */
+
+ /* virtual service options */
+ char sched_name[IP_VS_SCHEDNAME_MAXLEN];
+ unsigned flags; /* virtual service flags */
+ unsigned timeout; /* persistent timeout in sec */
+- u_int32_t netmask; /* persistent netmask */
++ __be32 netmask; /* persistent netmask */
+ };
+
+
+ struct ip_vs_dest_user {
+ /* destination server address */
+- u_int32_t addr;
+- u_int16_t port;
++ __be32 addr;
++ __be16 port;
+
+ /* real server options */
+ unsigned conn_flags; /* connection flags */
+@@ -163,15 +163,15 @@ struct ip_vs_getinfo {
+ struct ip_vs_service_entry {
+ /* which service: user fills in these */
+ u_int16_t protocol;
+- u_int32_t addr; /* virtual address */
+- u_int16_t port;
++ __be32 addr; /* virtual address */
++ __be16 port;
+ u_int32_t fwmark; /* firwall mark of service */
+
+ /* service options */
+ char sched_name[IP_VS_SCHEDNAME_MAXLEN];
+ unsigned flags; /* virtual service flags */
+ unsigned timeout; /* persistent timeout */
+- u_int32_t netmask; /* persistent netmask */
++ __be32 netmask; /* persistent netmask */
+
+ /* number of real servers */
+ unsigned int num_dests;
+@@ -182,8 +182,8 @@ struct ip_vs_service_entry {
+
+
+ struct ip_vs_dest_entry {
+- u_int32_t addr; /* destination address */
+- u_int16_t port;
++ __be32 addr; /* destination address */
++ __be16 port;
+ unsigned conn_flags; /* connection flags */
+ int weight; /* destination weight */
+
+@@ -203,8 +203,8 @@ struct ip_vs_dest_entry {
+ struct ip_vs_get_dests {
+ /* which service: user fills in these */
+ u_int16_t protocol;
+- u_int32_t addr; /* virtual address */
+- u_int16_t port;
++ __be32 addr; /* virtual address */
++ __be16 port;
+ u_int32_t fwmark; /* firwall mark of service */
+
+ /* number of real servers */
+@@ -502,12 +502,12 @@ struct ip_vs_conn {
+ struct list_head c_list; /* hashed list heads */
+
+ /* Protocol, addresses and port numbers */
+- __u32 caddr; /* client address */
+- __u32 vaddr; /* virtual address */
+- __u32 daddr; /* destination address */
+- __u16 cport;
+- __u16 vport;
+- __u16 dport;
++ __be32 caddr; /* client address */
++ __be32 vaddr; /* virtual address */
++ __be32 daddr; /* destination address */
++ __be16 cport;
++ __be16 vport;
++ __be16 dport;
+ __u16 protocol; /* Which protocol (TCP/UDP) */
+
+ /* counter and timer */
+@@ -554,12 +554,12 @@ struct ip_vs_service {
+ atomic_t usecnt; /* use counter */
+
+ __u16 protocol; /* which protocol (TCP/UDP) */
+- __u32 addr; /* IP address for virtual service */
+- __u16 port; /* port number for the service */
++ __be32 addr; /* IP address for virtual service */
++ __be16 port; /* port number for the service */
+ __u32 fwmark; /* firewall mark of the service */
+ unsigned flags; /* service status flags */
+ unsigned timeout; /* persistent timeout in ticks */
+- __u32 netmask; /* grouping granularity */
++ __be32 netmask; /* grouping granularity */
+
+ struct list_head destinations; /* real server d-linked list */
+ __u32 num_dests; /* number of servers */
+@@ -581,8 +581,8 @@ struct ip_vs_dest {
+ struct list_head n_list; /* for the dests in the service */
+ struct list_head d_list; /* for table with all the dests */
+
+- __u32 addr; /* IP address of the server */
+- __u16 port; /* port number of the server */
++ __be32 addr; /* IP address of the server */
++ __be16 port; /* port number of the server */
+ volatile unsigned flags; /* dest status flags */
+ atomic_t conn_flags; /* flags to copy to conn */
+ atomic_t weight; /* server weight */
+@@ -605,8 +605,8 @@ struct ip_vs_dest {
+ /* for virtual service */
+ struct ip_vs_service *svc; /* service it belongs to */
+ __u16 protocol; /* which protocol (TCP/UDP) */
+- __u32 vaddr; /* virtual IP address */
+- __u16 vport; /* virtual port number */
++ __be32 vaddr; /* virtual IP address */
++ __be16 vport; /* virtual port number */
+ __u32 vfwmark; /* firewall mark of service */
+ };
+
+@@ -648,7 +648,7 @@ struct ip_vs_app
+ /* members for application incarnations */
+ struct list_head p_list; /* member in proto app list */
+ struct ip_vs_app *app; /* its real application */
+- __u16 port; /* port number in net order */
++ __be16 port; /* port number in net order */
+ atomic_t usecnt; /* usage counter */
+
+ /* output hook: return false if can't linearize. diff set for TCP. */
+@@ -740,11 +740,11 @@ enum {
+ };
+
+ extern struct ip_vs_conn *ip_vs_conn_in_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+ extern struct ip_vs_conn *ip_vs_ct_in_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+ extern struct ip_vs_conn *ip_vs_conn_out_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+
+ /* put back the conn without restarting its timer */
+ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
+@@ -752,11 +752,11 @@ static inline void __ip_vs_conn_put(stru
+ atomic_dec(&cp->refcnt);
+ }
+ extern void ip_vs_conn_put(struct ip_vs_conn *cp);
+-extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport);
++extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
+
+ extern struct ip_vs_conn *
+-ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
+- __u32 daddr, __u16 dport, unsigned flags,
++ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
++ __be32 daddr, __be16 dport, unsigned flags,
+ struct ip_vs_dest *dest);
+ extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
+
+@@ -887,7 +887,7 @@ extern int sysctl_ip_vs_nat_icmp_send;
+ extern struct ip_vs_stats ip_vs_stats;
+
+ extern struct ip_vs_service *
+-ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport);
++ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport);
+
+ static inline void ip_vs_service_put(struct ip_vs_service *svc)
+ {
+@@ -895,7 +895,7 @@ static inline void ip_vs_service_put(str
+ }
+
+ extern struct ip_vs_dest *
+-ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport);
++ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
+ extern int ip_vs_use_count_inc(void);
+ extern void ip_vs_use_count_dec(void);
+ extern int ip_vs_control_init(void);
+diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h
+index e651a57..87c1af3 100644
+--- a/include/net/ipcomp.h
++++ b/include/net/ipcomp.h
+@@ -1,11 +1,14 @@
+ #ifndef _NET_IPCOMP_H
+ #define _NET_IPCOMP_H
+
++#include <linux/crypto.h>
++#include <linux/types.h>
++
+ #define IPCOMP_SCRATCH_SIZE 65400
+
+ struct ipcomp_data {
+ u16 threshold;
+- struct crypto_tfm **tfms;
++ struct crypto_comp **tfms;
+ };
+
+ #endif
+diff --git a/include/net/ipv6.h b/include/net/ipv6.h
+index ece7e8a..8223c44 100644
+--- a/include/net/ipv6.h
++++ b/include/net/ipv6.h
+@@ -40,6 +40,7 @@
+ #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
+ #define NEXTHDR_NONE 59 /* No next header */
+ #define NEXTHDR_DEST 60 /* Destination options header. */
++#define NEXTHDR_MOBILITY 135 /* Mobility header. */
+
+ #define NEXTHDR_MAX 255
+
+@@ -229,7 +230,7 @@ extern int ip6_ra_control(struct sock
+ void (*destructor)(struct sock *));
+
+
+-extern int ipv6_parse_hopopts(struct sk_buff *skb);
++extern int ipv6_parse_hopopts(struct sk_buff **skbp);
+
+ extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
+ extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
+@@ -317,8 +318,8 @@ static inline void ipv6_addr_prefix(stru
+
+ #ifndef __HAVE_ARCH_ADDR_SET
+ static inline void ipv6_addr_set(struct in6_addr *addr,
+- __u32 w1, __u32 w2,
+- __u32 w3, __u32 w4)
++ __be32 w1, __be32 w2,
++ __be32 w3, __be32 w4)
+ {
+ addr->s6_addr32[0] = w1;
+ addr->s6_addr32[1] = w2;
+@@ -336,7 +337,7 @@ static inline int ipv6_addr_equal(const
+ a1->s6_addr32[3] == a2->s6_addr32[3]);
+ }
+
+-static inline int __ipv6_prefix_equal(const u32 *a1, const u32 *a2,
++static inline int __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2,
+ unsigned int prefixlen)
+ {
+ unsigned pdw, pbi;
+@@ -506,6 +507,8 @@ extern int ipv6_skip_exthdr(const stru
+
+ extern int ipv6_ext_hdr(u8 nexthdr);
+
++extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);
++
+ extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk,
+ struct ipv6_rt_hdr *hdr);
+
+diff --git a/include/net/ipx.h b/include/net/ipx.h
+index 5c0cf33..c6b2ee6 100644
+--- a/include/net/ipx.h
++++ b/include/net/ipx.h
+@@ -15,9 +15,9 @@
+ #include <linux/list.h>
+
+ struct ipx_address {
+- __u32 net;
++ __be32 net;
+ __u8 node[IPX_NODE_LEN];
+- __u16 sock;
++ __be16 sock;
+ };
+
+ #define ipx_broadcast_node "\377\377\377\377\377\377"
+@@ -26,9 +26,9 @@ struct ipx_address {
+ #define IPX_MAX_PPROP_HOPS 8
+
+ struct ipxhdr {
+- __u16 ipx_checksum __attribute__ ((packed));
+-#define IPX_NO_CHECKSUM 0xFFFF
+- __u16 ipx_pktsize __attribute__ ((packed));
++ __be16 ipx_checksum __attribute__ ((packed));
++#define IPX_NO_CHECKSUM __constant_htons(0xFFFF)
++ __be16 ipx_pktsize __attribute__ ((packed));
+ __u8 ipx_tctrl;
+ __u8 ipx_type;
+ #define IPX_TYPE_UNKNOWN 0x00
+@@ -48,14 +48,14 @@ static __inline__ struct ipxhdr *ipx_hdr
+
+ struct ipx_interface {
+ /* IPX address */
+- __u32 if_netnum;
++ __be32 if_netnum;
+ unsigned char if_node[IPX_NODE_LEN];
+ atomic_t refcnt;
+
+ /* physical device info */
+ struct net_device *if_dev;
+ struct datalink_proto *if_dlink;
+- unsigned short if_dlink_type;
++ __be16 if_dlink_type;
+
+ /* socket support */
+ unsigned short if_sknum;
+@@ -71,7 +71,7 @@ struct ipx_interface {
+ };
+
+ struct ipx_route {
+- __u32 ir_net;
++ __be32 ir_net;
+ struct ipx_interface *ir_intrfc;
+ unsigned char ir_routed;
+ unsigned char ir_router_node[IPX_NODE_LEN];
+@@ -82,10 +82,10 @@ struct ipx_route {
+ #ifdef __KERNEL__
+ struct ipx_cb {
+ u8 ipx_tctrl;
+- u32 ipx_dest_net;
+- u32 ipx_source_net;
++ __be32 ipx_dest_net;
++ __be32 ipx_source_net;
+ struct {
+- u32 netnum;
++ __be32 netnum;
+ int index;
+ } last_hop;
+ };
+@@ -97,7 +97,7 @@ struct ipx_sock {
+ struct sock sk;
+ struct ipx_address dest_addr;
+ struct ipx_interface *intrfc;
+- unsigned short port;
++ __be16 port;
+ #ifdef CONFIG_IPX_INTERN
+ unsigned char node[IPX_NODE_LEN];
+ #endif
+@@ -132,7 +132,7 @@ extern struct ipx_interface *ipx_primary
+ extern int ipx_proc_init(void);
+ extern void ipx_proc_exit(void);
+
+-extern const char *ipx_frame_name(unsigned short);
++extern const char *ipx_frame_name(__be16);
+ extern const char *ipx_device_name(struct ipx_interface *intrfc);
+
+ static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
+diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
+index 1c73bdb..9592c37 100644
+--- a/include/net/irda/irlan_common.h
++++ b/include/net/irda/irlan_common.h
+@@ -98,7 +98,15 @@
+ #define IRLAN_SHORT 1
+ #define IRLAN_ARRAY 2
+
+-#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_MAX_HEADER)
++/* IrLAN sits on top if IrTTP */
++#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER)
++/* 1 byte for the command code and 1 byte for the parameter count */
++#define IRLAN_CMD_HEADER 2
++
++#define IRLAN_STRING_PARAMETER_LEN(name, value) (1 + strlen((name)) + 2 \
++ + strlen ((value)))
++#define IRLAN_BYTE_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 1)
++#define IRLAN_SHORT_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 2)
+
+ /*
+ * IrLAN client
+diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h
+index 3452ae2..9dd54a5 100644
+--- a/include/net/irda/irlap_frame.h
++++ b/include/net/irda/irlap_frame.h
+@@ -74,6 +74,19 @@ struct discovery_t;
+
+ #define PF_BIT 0x10 /* Poll/final bit */
+
++/* Some IrLAP field lengths */
++/*
++ * Only baud rate triplet is 4 bytes (PV can be 2 bytes).
++ * All others params (7) are 3 bytes, so that's 7*3 + 1*4 bytes.
++ */
++#define IRLAP_NEGOCIATION_PARAMS_LEN 25
++#define IRLAP_DISCOVERY_INFO_LEN 32
++
++struct disc_frame {
++ __u8 caddr; /* Connection address */
++ __u8 control;
++} IRDA_PACK;
++
+ struct xid_frame {
+ __u8 caddr; /* Connection address */
+ __u8 control;
+@@ -95,11 +108,25 @@ struct test_frame {
+ struct ua_frame {
+ __u8 caddr;
+ __u8 control;
+-
+ __u32 saddr; /* Source device address */
+ __u32 daddr; /* Dest device address */
+ } IRDA_PACK;
+-
++
++struct dm_frame {
++ __u8 caddr; /* Connection address */
++ __u8 control;
++} IRDA_PACK;
++
++struct rd_frame {
++ __u8 caddr; /* Connection address */
++ __u8 control;
++} IRDA_PACK;
++
++struct rr_frame {
++ __u8 caddr; /* Connection address */
++ __u8 control;
++} IRDA_PACK;
++
+ struct i_frame {
+ __u8 caddr;
+ __u8 control;
+diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
+index 11ecfa5..e212b9b 100644
+--- a/include/net/irda/irlmp.h
++++ b/include/net/irda/irlmp.h
+@@ -48,7 +48,7 @@
+ #define DEV_ADDR_ANY 0xffffffff
+
+ #define LMP_HEADER 2 /* Dest LSAP + Source LSAP */
+-#define LMP_CONTROL_HEADER 4
++#define LMP_CONTROL_HEADER 4 /* LMP_HEADER + opcode + parameter */
+ #define LMP_PID_HEADER 1 /* Used by Ultra */
+ #define LMP_MAX_HEADER (LMP_CONTROL_HEADER+LAP_MAX_HEADER)
+
+diff --git a/include/net/mip6.h b/include/net/mip6.h
+new file mode 100644
+index 0000000..68263c6
+--- /dev/null
++++ b/include/net/mip6.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C)2003-2006 Helsinki University of Technology
++ * Copyright (C)2003-2006 USAGI/WIDE Project
++ *
++ * 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
++ */
++/*
++ * Authors:
++ * Noriaki TAKAMIYA @USAGI
++ * Masahide NAKAMURA @USAGI
++ * YOSHIFUJI Hideaki @USAGI
++ */
++#ifndef _NET_MIP6_H
++#define _NET_MIP6_H
++
++#include <linux/skbuff.h>
++#include <net/sock.h>
++
++#define MIP6_OPT_PAD_1 0
++#define MIP6_OPT_PAD_N 1
++
++/*
++ * Mobility Header
++ */
++struct ip6_mh {
++ __u8 ip6mh_proto;
++ __u8 ip6mh_hdrlen;
++ __u8 ip6mh_type;
++ __u8 ip6mh_reserved;
++ __u16 ip6mh_cksum;
++ /* Followed by type specific messages */
++ __u8 data[0];
++} __attribute__ ((__packed__));
++
++#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */
++#define IP6_MH_TYPE_HOTI 1 /* HOTI Message */
++#define IP6_MH_TYPE_COTI 2 /* COTI Message */
++#define IP6_MH_TYPE_HOT 3 /* HOT Message */
++#define IP6_MH_TYPE_COT 4 /* COT Message */
++#define IP6_MH_TYPE_BU 5 /* Binding Update */
++#define IP6_MH_TYPE_BACK 6 /* Binding ACK */
++#define IP6_MH_TYPE_BERROR 7 /* Binding Error */
++#define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR
++
++extern int mip6_init(void);
++extern void mip6_fini(void);
++extern int mip6_mh_filter(struct sock *sk, struct sk_buff *skb);
++
++#endif
+diff --git a/include/net/neighbour.h b/include/net/neighbour.h
+index 4901ee4..c8aacbd 100644
+--- a/include/net/neighbour.h
++++ b/include/net/neighbour.h
+@@ -1,6 +1,8 @@
+ #ifndef _NET_NEIGHBOUR_H
+ #define _NET_NEIGHBOUR_H
+
++#include <linux/neighbour.h>
++
+ /*
+ * Generic neighbour manipulation
+ *
+@@ -14,40 +16,6 @@
+ * - Add neighbour cache statistics like rtstat
+ */
+
+-/* The following flags & states are exported to user space,
+- so that they should be moved to include/linux/ directory.
+- */
+-
+-/*
+- * Neighbor Cache Entry Flags
+- */
+-
+-#define NTF_PROXY 0x08 /* == ATF_PUBL */
+-#define NTF_ROUTER 0x80
+-
+-/*
+- * Neighbor Cache Entry States.
+- */
+-
+-#define NUD_INCOMPLETE 0x01
+-#define NUD_REACHABLE 0x02
+-#define NUD_STALE 0x04
+-#define NUD_DELAY 0x08
+-#define NUD_PROBE 0x10
+-#define NUD_FAILED 0x20
+-
+-/* Dummy states */
+-#define NUD_NOARP 0x40
+-#define NUD_PERMANENT 0x80
+-#define NUD_NONE 0x00
+-
+-/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+- and make no address resolution or NUD.
+- NUD_PERMANENT is also cannot be deleted by garbage collectors.
+- */
+-
+-#ifdef __KERNEL__
+-
+ #include <asm/atomic.h>
+ #include <linux/netdevice.h>
+ #include <linux/skbuff.h>
+@@ -133,7 +101,7 @@ struct neighbour
+ __u8 dead;
+ atomic_t probes;
+ rwlock_t lock;
+- unsigned char ha[(MAX_ADDR_LEN+sizeof(unsigned long)-1)&~(sizeof(unsigned long)-1)];
++ unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
+ struct hh_cache *hh;
+ atomic_t refcnt;
+ int (*output)(struct sk_buff *skb);
+@@ -158,6 +126,7 @@ struct pneigh_entry
+ {
+ struct pneigh_entry *next;
+ struct net_device *dev;
++ u8 flags;
+ u8 key[0];
+ };
+
+@@ -374,6 +343,3 @@ struct neighbour_cb {
+ #define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb)
+
+ #endif
+-#endif
+-
+-
+diff --git a/include/net/netdma.h b/include/net/netdma.h
+index 7f53cd1..f28c6e0 100644
+--- a/include/net/netdma.h
++++ b/include/net/netdma.h
+@@ -20,7 +20,6 @@
+ */
+ #ifndef NETDMA_H
+ #define NETDMA_H
+-#include <linux/config.h>
+ #ifdef CONFIG_NET_DMA
+ #include <linux/dmaengine.h>
+ #include <linux/skbuff.h>
+diff --git a/include/net/netlabel.h b/include/net/netlabel.h
+new file mode 100644
+index 0000000..12c214b
+--- /dev/null
++++ b/include/net/netlabel.h
+@@ -0,0 +1,293 @@
++/*
++ * NetLabel System
++ *
++ * The NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _NETLABEL_H
++#define _NETLABEL_H
++
++#include <linux/types.h>
++#include <linux/net.h>
++#include <linux/skbuff.h>
++#include <net/netlink.h>
++#include <asm/atomic.h>
++
++/*
++ * NetLabel - A management interface for maintaining network packet label
++ * mapping tables for explicit packet labling protocols.
++ *
++ * Network protocols such as CIPSO and RIPSO require a label translation layer
++ * to convert the label on the packet into something meaningful on the host
++ * machine. In the current Linux implementation these mapping tables live
++ * inside the kernel; NetLabel provides a mechanism for user space applications
++ * to manage these mapping tables.
++ *
++ * NetLabel makes use of the Generic NETLINK mechanism as a transport layer to
++ * send messages between kernel and user space. The general format of a
++ * NetLabel message is shown below:
++ *
++ * +-----------------+-------------------+--------- --- -- -
++ * | struct nlmsghdr | struct genlmsghdr | payload
++ * +-----------------+-------------------+--------- --- -- -
++ *
++ * The 'nlmsghdr' and 'genlmsghdr' structs should be dealt with like normal.
++ * The payload is dependent on the subsystem specified in the
++ * 'nlmsghdr->nlmsg_type' and should be defined below, supporting functions
++ * should be defined in the corresponding net/netlabel/netlabel_<subsys>.h|c
++ * file. All of the fields in the NetLabel payload are NETLINK attributes, see
++ * the include/net/netlink.h file for more information on NETLINK attributes.
++ *
++ */
++
++/*
++ * NetLabel NETLINK protocol
++ */
++
++#define NETLBL_PROTO_VERSION 1
++
++/* NetLabel NETLINK types/families */
++#define NETLBL_NLTYPE_NONE 0
++#define NETLBL_NLTYPE_MGMT 1
++#define NETLBL_NLTYPE_MGMT_NAME "NLBL_MGMT"
++#define NETLBL_NLTYPE_RIPSO 2
++#define NETLBL_NLTYPE_RIPSO_NAME "NLBL_RIPSO"
++#define NETLBL_NLTYPE_CIPSOV4 3
++#define NETLBL_NLTYPE_CIPSOV4_NAME "NLBL_CIPSOv4"
++#define NETLBL_NLTYPE_CIPSOV6 4
++#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6"
++#define NETLBL_NLTYPE_UNLABELED 5
++#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
++
++/*
++ * NetLabel - Kernel API for accessing the network packet label mappings.
++ *
++ * The following functions are provided for use by other kernel modules,
++ * specifically kernel LSM modules, to provide a consistent, transparent API
++ * for dealing with explicit packet labeling protocols such as CIPSO and
++ * RIPSO. The functions defined here are implemented in the
++ * net/netlabel/netlabel_kapi.c file.
++ *
++ */
++
++/* NetLabel audit information */
++struct netlbl_audit {
++ u32 secid;
++ uid_t loginuid;
++};
++
++/* Domain mapping definition struct */
++struct netlbl_dom_map;
++
++/* Domain mapping operations */
++int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
++
++/* LSM security attributes */
++struct netlbl_lsm_cache {
++ atomic_t refcount;
++ void (*free) (const void *data);
++ void *data;
++};
++struct netlbl_lsm_secattr {
++ char *domain;
++
++ u32 mls_lvl;
++ u32 mls_lvl_vld;
++ unsigned char *mls_cat;
++ size_t mls_cat_len;
++
++ struct netlbl_lsm_cache *cache;
++};
++
++/*
++ * LSM security attribute operations
++ */
++
++
++/**
++ * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache
++ * @flags: the memory allocation flags
++ *
++ * Description:
++ * Allocate and initialize a netlbl_lsm_cache structure. Returns a pointer
++ * on success, NULL on failure.
++ *
++ */
++static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags)
++{
++ struct netlbl_lsm_cache *cache;
++
++ cache = kzalloc(sizeof(*cache), flags);
++ if (cache)
++ atomic_set(&cache->refcount, 1);
++ return cache;
++}
++
++/**
++ * netlbl_secattr_cache_free - Frees a netlbl_lsm_cache struct
++ * @cache: the struct to free
++ *
++ * Description:
++ * Frees @secattr including all of the internal buffers.
++ *
++ */
++static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
++{
++ if (!atomic_dec_and_test(&cache->refcount))
++ return;
++
++ if (cache->free)
++ cache->free(cache->data);
++ kfree(cache);
++}
++
++/**
++ * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
++ * @secattr: the struct to initialize
++ *
++ * Description:
++ * Initialize an already allocated netlbl_lsm_secattr struct. Returns zero on
++ * success, negative values on error.
++ *
++ */
++static inline int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
++{
++ memset(secattr, 0, sizeof(*secattr));
++ return 0;
++}
++
++/**
++ * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct
++ * @secattr: the struct to clear
++ *
++ * Description:
++ * Destroys the @secattr struct, including freeing all of the internal buffers.
++ * The struct must be reset with a call to netlbl_secattr_init() before reuse.
++ *
++ */
++static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
++{
++ if (secattr->cache)
++ netlbl_secattr_cache_free(secattr->cache);
++ kfree(secattr->domain);
++ kfree(secattr->mls_cat);
++}
++
++/**
++ * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct
++ * @flags: the memory allocation flags
++ *
++ * Description:
++ * Allocate and initialize a netlbl_lsm_secattr struct. Returns a valid
++ * pointer on success, or NULL on failure.
++ *
++ */
++static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(int flags)
++{
++ return kzalloc(sizeof(struct netlbl_lsm_secattr), flags);
++}
++
++/**
++ * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct
++ * @secattr: the struct to free
++ *
++ * Description:
++ * Frees @secattr including all of the internal buffers.
++ *
++ */
++static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
++{
++ netlbl_secattr_destroy(secattr);
++ kfree(secattr);
++}
++
++/*
++ * LSM protocol operations
++ */
++
++#ifdef CONFIG_NETLABEL
++int netlbl_socket_setattr(const struct socket *sock,
++ const struct netlbl_lsm_secattr *secattr);
++int netlbl_sock_getattr(struct sock *sk,
++ struct netlbl_lsm_secattr *secattr);
++int netlbl_socket_getattr(const struct socket *sock,
++ struct netlbl_lsm_secattr *secattr);
++int netlbl_skbuff_getattr(const struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr);
++void netlbl_skbuff_err(struct sk_buff *skb, int error);
++#else
++static inline int netlbl_socket_setattr(const struct socket *sock,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int netlbl_sock_getattr(struct sock *sk,
++ struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int netlbl_socket_getattr(const struct socket *sock,
++ struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr)
++{
++ return -ENOSYS;
++}
++
++static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
++{
++ return;
++}
++#endif /* CONFIG_NETLABEL */
++
++/*
++ * LSM label mapping cache operations
++ */
++
++#ifdef CONFIG_NETLABEL
++void netlbl_cache_invalidate(void);
++int netlbl_cache_add(const struct sk_buff *skb,
++ const struct netlbl_lsm_secattr *secattr);
++#else
++static inline void netlbl_cache_invalidate(void)
++{
++ return;
++}
++
++static inline int netlbl_cache_add(const struct sk_buff *skb,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ return 0;
++}
++#endif /* CONFIG_NETLABEL */
++
++#endif /* _NETLABEL_H */
+diff --git a/include/net/netlink.h b/include/net/netlink.h
+index 640c26a..ce5cba1 100644
+--- a/include/net/netlink.h
++++ b/include/net/netlink.h
+@@ -35,12 +35,15 @@
+ * nlmsg_put() add a netlink message to an skb
+ * nlmsg_put_answer() callback based nlmsg_put()
+ * nlmsg_end() finanlize netlink message
++ * nlmsg_get_pos() return current position in message
++ * nlmsg_trim() trim part of message
+ * nlmsg_cancel() cancel message construction
+ * nlmsg_free() free a netlink message
+ *
+ * Message Sending:
+ * nlmsg_multicast() multicast message to several groups
+ * nlmsg_unicast() unicast a message to a single socket
++ * nlmsg_notify() send notification message
+ *
+ * Message Length Calculations:
+ * nlmsg_msg_size(payload) length of message w/o padding
+@@ -62,6 +65,9 @@
+ * nlmsg_validate() validate netlink message incl. attrs
+ * nlmsg_for_each_attr() loop over all attributes
+ *
++ * Misc:
++ * nlmsg_report() report back to application?
++ *
+ * ------------------------------------------------------------------------
+ * Attributes Interface
+ * ------------------------------------------------------------------------
+@@ -80,8 +86,10 @@
+ * struct nlattr netlink attribtue header
+ *
+ * Attribute Construction:
+- * nla_reserve(skb, type, len) reserve skb tailroom for an attribute
++ * nla_reserve(skb, type, len) reserve room for an attribute
++ * nla_reserve_nohdr(skb, len) reserve room for an attribute w/o hdr
+ * nla_put(skb, type, len, data) add attribute to skb
++ * nla_put_nohdr(skb, len, data) add attribute w/o hdr
+ *
+ * Attribute Construction for Basic Types:
+ * nla_put_u8(skb, type, value) add u8 attribute to skb
+@@ -138,10 +146,13 @@
+ * nla_ok(nla, remaining) does nla fit into remaining bytes?
+ * nla_next(nla, remaining) get next netlink attribute
+ * nla_validate() validate a stream of attributes
++ * nla_validate_nested() validate a stream of nested attributes
+ * nla_find() find attribute in stream of attributes
++ * nla_find_nested() find attribute in nested attributes
+ * nla_parse() parse and validate stream of attrs
+ * nla_parse_nested() parse nested attribuets
+ * nla_for_each_attr() loop over all attributes
++ * nla_for_each_nested() loop over the nested attributes
+ *=========================================================================
+ */
+
+@@ -158,6 +169,7 @@ enum {
+ NLA_FLAG,
+ NLA_MSECS,
+ NLA_NESTED,
++ NLA_NUL_STRING,
+ __NLA_TYPE_MAX,
+ };
+
+@@ -166,21 +178,37 @@ enum {
+ /**
+ * struct nla_policy - attribute validation policy
+ * @type: Type of attribute or NLA_UNSPEC
+- * @minlen: Minimal length of payload required to be available
++ * @len: Type specific length of payload
+ *
+ * Policies are defined as arrays of this struct, the array must be
+ * accessible by attribute type up to the highest identifier to be expected.
+ *
++ * Meaning of `len' field:
++ * NLA_STRING Maximum length of string
++ * NLA_NUL_STRING Maximum length of string (excluding NUL)
++ * NLA_FLAG Unused
++ * All other Exact length of attribute payload
++ *
+ * Example:
+ * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = {
+ * [ATTR_FOO] = { .type = NLA_U16 },
+- * [ATTR_BAR] = { .type = NLA_STRING },
+- * [ATTR_BAZ] = { .minlen = sizeof(struct mystruct) },
++ * [ATTR_BAR] = { .type = NLA_STRING, len = BARSIZ },
++ * [ATTR_BAZ] = { .len = sizeof(struct mystruct) },
+ * };
+ */
+ struct nla_policy {
+ u16 type;
+- u16 minlen;
++ u16 len;
++};
++
++/**
++ * struct nl_info - netlink source information
++ * @nlh: Netlink message header of original request
++ * @pid: Netlink PID of requesting application
++ */
++struct nl_info {
++ struct nlmsghdr *nlh;
++ u32 pid;
+ };
+
+ extern void netlink_run_queue(struct sock *sk, unsigned int *qlen,
+@@ -188,6 +216,9 @@ extern void netlink_run_queue(struct so
+ struct nlmsghdr *, int *));
+ extern void netlink_queue_skip(struct nlmsghdr *nlh,
+ struct sk_buff *skb);
++extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb,
++ u32 pid, unsigned int group, int report,
++ gfp_t flags);
+
+ extern int nla_validate(struct nlattr *head, int len, int maxtype,
+ struct nla_policy *policy);
+@@ -203,12 +234,18 @@ extern int nla_memcmp(const struct nlat
+ extern int nla_strcmp(const struct nlattr *nla, const char *str);
+ extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype,
+ int attrlen);
++extern void * __nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
+ extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype,
+ int attrlen);
++extern void * nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
+ extern void __nla_put(struct sk_buff *skb, int attrtype,
+ int attrlen, const void *data);
++extern void __nla_put_nohdr(struct sk_buff *skb, int attrlen,
++ const void *data);
+ extern int nla_put(struct sk_buff *skb, int attrtype,
+ int attrlen, const void *data);
++extern int nla_put_nohdr(struct sk_buff *skb, int attrlen,
++ const void *data);
+
+ /**************************************************************************
+ * Netlink Messages
+@@ -364,6 +401,17 @@ static inline int nlmsg_validate(struct
+ }
+
+ /**
++ * nlmsg_report - need to report back to application?
++ * @nlh: netlink message header
++ *
++ * Returns 1 if a report back to the application is requested.
++ */
++static inline int nlmsg_report(struct nlmsghdr *nlh)
++{
++ return !!(nlh->nlmsg_flags & NLM_F_ECHO);
++}
++
++/**
+ * nlmsg_for_each_attr - iterate over a stream of attributes
+ * @pos: loop counter, set to current attribute
+ * @nlh: netlink message header
+@@ -453,12 +501,13 @@ static inline struct nlmsghdr *nlmsg_put
+ /**
+ * nlmsg_new - Allocate a new netlink message
+ * @size: maximum size of message
++ * @flags: the type of memory to allocate.
+ *
+ * Use NLMSG_GOODSIZE if size isn't know and you need a good default size.
+ */
+-static inline struct sk_buff *nlmsg_new(int size)
++static inline struct sk_buff *nlmsg_new(int size, gfp_t flags)
+ {
+- return alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
++ return alloc_skb(size, flags);
+ }
+
+ /**
+@@ -480,6 +529,32 @@ static inline int nlmsg_end(struct sk_bu
+ }
+
+ /**
++ * nlmsg_get_pos - return current position in netlink message
++ * @skb: socket buffer the message is stored in
++ *
++ * Returns a pointer to the current tail of the message.
++ */
++static inline void *nlmsg_get_pos(struct sk_buff *skb)
++{
++ return skb->tail;
++}
++
++/**
++ * nlmsg_trim - Trim message to a mark
++ * @skb: socket buffer the message is stored in
++ * @mark: mark to trim to
++ *
++ * Trims the message to the provided mark. Returns -1.
++ */
++static inline int nlmsg_trim(struct sk_buff *skb, void *mark)
++{
++ if (mark)
++ skb_trim(skb, (unsigned char *) mark - skb->data);
++
++ return -1;
++}
++
++/**
+ * nlmsg_cancel - Cancel construction of a netlink message
+ * @skb: socket buffer the message is stored in
+ * @nlh: netlink message header
+@@ -489,9 +564,7 @@ static inline int nlmsg_end(struct sk_bu
+ */
+ static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh)
+ {
+- skb_trim(skb, (unsigned char *) nlh - skb->data);
+-
+- return -1;
++ return nlmsg_trim(skb, nlh);
+ }
+
+ /**
+@@ -509,15 +582,16 @@ static inline void nlmsg_free(struct sk_
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
++ * @flags: allocation flags
+ */
+ static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
+- u32 pid, unsigned int group)
++ u32 pid, unsigned int group, gfp_t flags)
+ {
+ int err;
+
+ NETLINK_CB(skb).dst_group = group;
+
+- err = netlink_broadcast(sk, skb, pid, group, GFP_KERNEL);
++ err = netlink_broadcast(sk, skb, pid, group, flags);
+ if (err > 0)
+ err = 0;
+
+@@ -631,6 +705,18 @@ static inline struct nlattr *nla_next(co
+ }
+
+ /**
++ * nla_find_nested - find attribute in a set of nested attributes
++ * @nla: attribute containing the nested attributes
++ * @attrtype: type of attribute to look for
++ *
++ * Returns the first attribute which matches the specified type.
++ */
++static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype)
++{
++ return nla_find(nla_data(nla), nla_len(nla), attrtype);
++}
++
++/**
+ * nla_parse_nested - parse nested attributes
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+@@ -745,13 +831,16 @@ static inline int nla_put_msecs(struct s
+ #define NLA_PUT_U32(skb, attrtype, value) \
+ NLA_PUT_TYPE(skb, u32, attrtype, value)
+
++#define NLA_PUT_BE32(skb, attrtype, value) \
++ NLA_PUT_TYPE(skb, __be32, attrtype, value)
++
+ #define NLA_PUT_U64(skb, attrtype, value) \
+ NLA_PUT_TYPE(skb, u64, attrtype, value)
+
+ #define NLA_PUT_STRING(skb, attrtype, value) \
+ NLA_PUT(skb, attrtype, strlen(value) + 1, value)
+
+-#define NLA_PUT_FLAG(skb, attrtype, value) \
++#define NLA_PUT_FLAG(skb, attrtype) \
+ NLA_PUT(skb, attrtype, 0, NULL)
+
+ #define NLA_PUT_MSECS(skb, attrtype, jiffies) \
+@@ -767,6 +856,15 @@ static inline u32 nla_get_u32(struct nla
+ }
+
+ /**
++ * nla_get_be32 - return payload of __be32 attribute
++ * @nla: __be32 netlink attribute
++ */
++static inline __be32 nla_get_be32(struct nlattr *nla)
++{
++ return *(__be32 *) nla_data(nla);
++}
++
++/**
+ * nla_get_u16 - return payload of u16 attribute
+ * @nla: u16 netlink attribute
+ */
+@@ -862,10 +960,25 @@ static inline int nla_nest_end(struct sk
+ */
+ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
+ {
+- if (start)
+- skb_trim(skb, (unsigned char *) start - skb->data);
++ return nlmsg_trim(skb, start);
++}
+
+- return -1;
++/**
++ * nla_validate_nested - Validate a stream of nested attributes
++ * @start: container attribute
++ * @maxtype: maximum attribute type to be expected
++ * @policy: validation policy
++ *
++ * Validates all attributes in the nested attribute stream against the
++ * specified policy. Attributes with a type exceeding maxtype will be
++ * ignored. See documenation of struct nla_policy for more details.
++ *
++ * Returns 0 on success or a negative error code.
++ */
++static inline int nla_validate_nested(struct nlattr *start, int maxtype,
++ struct nla_policy *policy)
++{
++ return nla_validate(nla_data(start), nla_len(start), maxtype, policy);
+ }
+
+ /**
+@@ -880,4 +993,13 @@ static inline int nla_nest_cancel(struct
+ nla_ok(pos, rem); \
+ pos = nla_next(pos, &(rem)))
+
++/**
++ * nla_for_each_nested - iterate over nested attributes
++ * @pos: loop counter, set to current attribute
++ * @nla: attribute containing the nested attributes
++ * @rem: initialized to len, holds bytes currently remaining in stream
++ */
++#define nla_for_each_nested(pos, nla, rem) \
++ nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)
++
+ #endif
+diff --git a/include/net/nexthop.h b/include/net/nexthop.h
+new file mode 100644
+index 0000000..3334dbf
+--- /dev/null
++++ b/include/net/nexthop.h
+@@ -0,0 +1,33 @@
++#ifndef __NET_NEXTHOP_H
++#define __NET_NEXTHOP_H
++
++#include <linux/rtnetlink.h>
++#include <net/netlink.h>
++
++static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining)
++{
++ return remaining >= sizeof(*rtnh) &&
++ rtnh->rtnh_len >= sizeof(*rtnh) &&
++ rtnh->rtnh_len <= remaining;
++}
++
++static inline struct rtnexthop *rtnh_next(const struct rtnexthop *rtnh,
++ int *remaining)
++{
++ int totlen = NLA_ALIGN(rtnh->rtnh_len);
++
++ *remaining -= totlen;
++ return (struct rtnexthop *) ((char *) rtnh + totlen);
++}
++
++static inline struct nlattr *rtnh_attrs(const struct rtnexthop *rtnh)
++{
++ return (struct nlattr *) ((char *) rtnh + NLA_ALIGN(sizeof(*rtnh)));
++}
++
++static inline int rtnh_attrlen(const struct rtnexthop *rtnh)
++{
++ return rtnh->rtnh_len - NLA_ALIGN(sizeof(*rtnh));
++}
++
++#endif
+diff --git a/include/net/pkt_act.h b/include/net/pkt_act.h
+deleted file mode 100644
+index cf5e4d2..0000000
+--- a/include/net/pkt_act.h
++++ /dev/null
+@@ -1,273 +0,0 @@
+-#ifndef __NET_PKT_ACT_H
+-#define __NET_PKT_ACT_H
+-
+-#include <asm/uaccess.h>
+-#include <asm/system.h>
+-#include <linux/bitops.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/string.h>
+-#include <linux/mm.h>
+-#include <linux/socket.h>
+-#include <linux/sockios.h>
+-#include <linux/in.h>
+-#include <linux/errno.h>
+-#include <linux/interrupt.h>
+-#include <linux/skbuff.h>
+-#include <linux/rtnetlink.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/proc_fs.h>
+-#include <net/sock.h>
+-#include <net/pkt_sched.h>
+-
+-#define tca_st(val) (struct tcf_##val *)
+-#define PRIV(a,name) ( tca_st(name) (a)->priv)
+-
+-#if 0 /* control */
+-#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
+-#else
+-#define DPRINTK(format,args...)
+-#endif
+-
+-#if 0 /* data */
+-#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
+-#else
+-#define D2PRINTK(format,args...)
+-#endif
+-
+-static __inline__ unsigned
+-tcf_hash(u32 index)
+-{
+- return index & MY_TAB_MASK;
+-}
+-
+-/* probably move this from being inline
+- * and put into act_generic
+-*/
+-static inline void
+-tcf_hash_destroy(struct tcf_st *p)
+-{
+- unsigned h = tcf_hash(p->index);
+- struct tcf_st **p1p;
+-
+- for (p1p = &tcf_ht[h]; *p1p; p1p = &(*p1p)->next) {
+- if (*p1p == p) {
+- write_lock_bh(&tcf_t_lock);
+- *p1p = p->next;
+- write_unlock_bh(&tcf_t_lock);
+-#ifdef CONFIG_NET_ESTIMATOR
+- gen_kill_estimator(&p->bstats, &p->rate_est);
+-#endif
+- kfree(p);
+- return;
+- }
+- }
+- BUG_TRAP(0);
+-}
+-
+-static inline int
+-tcf_hash_release(struct tcf_st *p, int bind )
+-{
+- int ret = 0;
+- if (p) {
+- if (bind) {
+- p->bindcnt--;
+- }
+- p->refcnt--;
+- if(p->bindcnt <=0 && p->refcnt <= 0) {
+- tcf_hash_destroy(p);
+- ret = 1;
+- }
+- }
+- return ret;
+-}
+-
+-static __inline__ int
+-tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
+- struct tc_action *a)
+-{
+- struct tcf_st *p;
+- int err =0, index = -1,i= 0, s_i = 0, n_i = 0;
+- struct rtattr *r ;
+-
+- read_lock(&tcf_t_lock);
+-
+- s_i = cb->args[0];
+-
+- for (i = 0; i < MY_TAB_SIZE; i++) {
+- p = tcf_ht[tcf_hash(i)];
+-
+- for (; p; p = p->next) {
+- index++;
+- if (index < s_i)
+- continue;
+- a->priv = p;
+- a->order = n_i;
+- r = (struct rtattr*) skb->tail;
+- RTA_PUT(skb, a->order, 0, NULL);
+- err = tcf_action_dump_1(skb, a, 0, 0);
+- if (0 > err) {
+- index--;
+- skb_trim(skb, (u8*)r - skb->data);
+- goto done;
+- }
+- r->rta_len = skb->tail - (u8*)r;
+- n_i++;
+- if (n_i >= TCA_ACT_MAX_PRIO) {
+- goto done;
+- }
+- }
+- }
+-done:
+- read_unlock(&tcf_t_lock);
+- if (n_i)
+- cb->args[0] += n_i;
+- return n_i;
+-
+-rtattr_failure:
+- skb_trim(skb, (u8*)r - skb->data);
+- goto done;
+-}
+-
+-static __inline__ int
+-tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
+-{
+- struct tcf_st *p, *s_p;
+- struct rtattr *r ;
+- int i= 0, n_i = 0;
+-
+- r = (struct rtattr*) skb->tail;
+- RTA_PUT(skb, a->order, 0, NULL);
+- RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind);
+- for (i = 0; i < MY_TAB_SIZE; i++) {
+- p = tcf_ht[tcf_hash(i)];
+-
+- while (p != NULL) {
+- s_p = p->next;
+- if (ACT_P_DELETED == tcf_hash_release(p, 0)) {
+- module_put(a->ops->owner);
+- }
+- n_i++;
+- p = s_p;
+- }
+- }
+- RTA_PUT(skb, TCA_FCNT, 4, &n_i);
+- r->rta_len = skb->tail - (u8*)r;
+-
+- return n_i;
+-rtattr_failure:
+- skb_trim(skb, (u8*)r - skb->data);
+- return -EINVAL;
+-}
+-
+-static __inline__ int
+-tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, int type,
+- struct tc_action *a)
+-{
+- if (type == RTM_DELACTION) {
+- return tcf_del_walker(skb,a);
+- } else if (type == RTM_GETACTION) {
+- return tcf_dump_walker(skb,cb,a);
+- } else {
+- printk("tcf_generic_walker: unknown action %d\n",type);
+- return -EINVAL;
+- }
+-}
+-
+-static __inline__ struct tcf_st *
+-tcf_hash_lookup(u32 index)
+-{
+- struct tcf_st *p;
+-
+- read_lock(&tcf_t_lock);
+- for (p = tcf_ht[tcf_hash(index)]; p; p = p->next) {
+- if (p->index == index)
+- break;
+- }
+- read_unlock(&tcf_t_lock);
+- return p;
+-}
+-
+-static __inline__ u32
+-tcf_hash_new_index(void)
+-{
+- do {
+- if (++idx_gen == 0)
+- idx_gen = 1;
+- } while (tcf_hash_lookup(idx_gen));
+-
+- return idx_gen;
+-}
+-
+-
+-static inline int
+-tcf_hash_search(struct tc_action *a, u32 index)
+-{
+- struct tcf_st *p = tcf_hash_lookup(index);
+-
+- if (p != NULL) {
+- a->priv = p;
+- return 1;
+- }
+- return 0;
+-}
+-
+-#ifdef CONFIG_NET_ACT_INIT
+-static inline struct tcf_st *
+-tcf_hash_check(u32 index, struct tc_action *a, int ovr, int bind)
+-{
+- struct tcf_st *p = NULL;
+- if (index && (p = tcf_hash_lookup(index)) != NULL) {
+- if (bind) {
+- p->bindcnt++;
+- p->refcnt++;
+- }
+- a->priv = p;
+- }
+- return p;
+-}
+-
+-static inline struct tcf_st *
+-tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind)
+-{
+- struct tcf_st *p = NULL;
+-
+- p = kmalloc(size, GFP_KERNEL);
+- if (p == NULL)
+- return p;
+-
+- memset(p, 0, size);
+- p->refcnt = 1;
+-
+- if (bind) {
+- p->bindcnt = 1;
+- }
+-
+- spin_lock_init(&p->lock);
+- p->stats_lock = &p->lock;
+- p->index = index ? : tcf_hash_new_index();
+- p->tm.install = jiffies;
+- p->tm.lastuse = jiffies;
+-#ifdef CONFIG_NET_ESTIMATOR
+- if (est)
+- gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
+-#endif
+- a->priv = (void *) p;
+- return p;
+-}
+-
+-static inline void tcf_hash_insert(struct tcf_st *p)
+-{
+- unsigned h = tcf_hash(p->index);
+-
+- write_lock_bh(&tcf_t_lock);
+- p->next = tcf_ht[h];
+- tcf_ht[h] = p;
+- write_unlock_bh(&tcf_t_lock);
+-}
+-
+-#endif
+-
+-#endif
+diff --git a/include/net/request_sock.h b/include/net/request_sock.h
+index c5d7f92..8e165ca 100644
+--- a/include/net/request_sock.h
++++ b/include/net/request_sock.h
+@@ -53,6 +53,7 @@ struct request_sock {
+ unsigned long expires;
+ struct request_sock_ops *rsk_ops;
+ struct sock *sk;
++ u32 secid;
+ };
+
+ static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops)
+diff --git a/include/net/route.h b/include/net/route.h
+index c4a0686..486e37a 100644
+--- a/include/net/route.h
++++ b/include/net/route.h
+@@ -32,6 +32,7 @@
+ #include <linux/route.h>
+ #include <linux/ip.h>
+ #include <linux/cache.h>
++#include <linux/security.h>
+
+ #ifndef __KERNEL__
+ #warning This file is not supposed to be used outside of kernel.
+@@ -61,18 +62,18 @@ struct rtable
+ __u16 rt_type;
+ __u16 rt_multipath_alg;
+
+- __u32 rt_dst; /* Path destination */
+- __u32 rt_src; /* Path source */
++ __be32 rt_dst; /* Path destination */
++ __be32 rt_src; /* Path source */
+ int rt_iif;
+
+ /* Info on neighbour */
+- __u32 rt_gateway;
++ __be32 rt_gateway;
+
+ /* Cache lookup keys */
+ struct flowi fl;
+
+ /* Miscellaneous cached information */
+- __u32 rt_spec_dst; /* RFC1122 specific destination */
++ __be32 rt_spec_dst; /* RFC1122 specific destination */
+ struct inet_peer *peer; /* long-living peer info */
+ };
+
+@@ -108,18 +109,18 @@ extern struct ip_rt_acct *ip_rt_acct;
+
+ struct in_device;
+ extern int ip_rt_init(void);
+-extern void ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
+- u32 src, struct net_device *dev);
++extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,
++ __be32 src, struct net_device *dev);
+ extern void ip_rt_advice(struct rtable **rp, int advice);
+ extern void rt_cache_flush(int how);
+ extern int __ip_route_output_key(struct rtable **, const struct flowi *flp);
+ extern int ip_route_output_key(struct rtable **, struct flowi *flp);
+ extern int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
+-extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
++extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
+ extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
+ extern void ip_rt_send_redirect(struct sk_buff *skb);
+
+-extern unsigned inet_addr_type(u32 addr);
++extern unsigned inet_addr_type(__be32 addr);
+ extern void ip_rt_multicast_event(struct in_device *);
+ extern int ip_rt_ioctl(unsigned int cmd, void __user *arg);
+ extern void ip_rt_get_source(u8 *src, struct rtable *rt);
+@@ -143,9 +144,9 @@ static inline char rt_tos2priority(u8 to
+ return ip_tos2prio[IPTOS_TOS(tos)>>1];
+ }
+
+-static inline int ip_route_connect(struct rtable **rp, u32 dst,
+- u32 src, u32 tos, int oif, u8 protocol,
+- u16 sport, u16 dport, struct sock *sk)
++static inline int ip_route_connect(struct rtable **rp, __be32 dst,
++ __be32 src, u32 tos, int oif, u8 protocol,
++ __be16 sport, __be16 dport, struct sock *sk)
+ {
+ struct flowi fl = { .oif = oif,
+ .nl_u = { .ip4_u = { .daddr = dst,
+@@ -166,11 +167,12 @@ static inline int ip_route_connect(struc
+ ip_rt_put(*rp);
+ *rp = NULL;
+ }
++ security_sk_classify_flow(sk, &fl);
+ return ip_route_output_flow(rp, &fl, sk, 0);
+ }
+
+ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
+- u16 sport, u16 dport, struct sock *sk)
++ __be16 sport, __be16 dport, struct sock *sk)
+ {
+ if (sport != (*rp)->fl.fl_ip_sport ||
+ dport != (*rp)->fl.fl_ip_dport) {
+@@ -182,6 +184,7 @@ static inline int ip_route_newports(stru
+ fl.proto = protocol;
+ ip_rt_put(*rp);
+ *rp = NULL;
++ security_sk_classify_flow(sk, &fl);
+ return ip_route_output_flow(rp, &fl, sk, 0);
+ }
+ return 0;
+diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
+index c51541e..6c632e2 100644
+--- a/include/net/sctp/constants.h
++++ b/include/net/sctp/constants.h
+@@ -264,10 +264,10 @@ enum { SCTP_MAX_DUP_TSNS = 16 };
+ enum { SCTP_MAX_GABS = 16 };
+
+ /* Heartbeat interval - 30 secs */
+-#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30 * HZ)
++#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30*1000)
+
+ /* Delayed sack timer - 200ms */
+-#define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000)
++#define SCTP_DEFAULT_TIMEOUT_SACK (200)
+
+ /* RTO.Initial - 3 seconds
+ * RTO.Min - 1 second
+@@ -275,9 +275,9 @@ enum { SCTP_MAX_GABS = 16 };
+ * RTO.Alpha - 1/8
+ * RTO.Beta - 1/4
+ */
+-#define SCTP_RTO_INITIAL (3 * HZ)
+-#define SCTP_RTO_MIN (1 * HZ)
+-#define SCTP_RTO_MAX (60 * HZ)
++#define SCTP_RTO_INITIAL (3 * 1000)
++#define SCTP_RTO_MIN (1 * 1000)
++#define SCTP_RTO_MAX (60 * 1000)
+
+ #define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */
+ #define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */
+@@ -290,8 +290,7 @@ enum { SCTP_MAX_GABS = 16 };
+ #define SCTP_DEF_MAX_INIT 6
+ #define SCTP_DEF_MAX_SEND 10
+
+-#define SCTP_DEFAULT_COOKIE_LIFE_SEC 60 /* seconds */
+-#define SCTP_DEFAULT_COOKIE_LIFE_USEC 0 /* microseconds */
++#define SCTP_DEFAULT_COOKIE_LIFE (60 * 1000) /* 60 seconds */
+
+ #define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */
+ #define SCTP_DEFAULT_MAXWINDOW 65535 /* default rwnd size */
+@@ -312,9 +311,9 @@ enum { SCTP_MAX_GABS = 16 };
+ */
+
+ #if defined (CONFIG_SCTP_HMAC_MD5)
+-#define SCTP_COOKIE_HMAC_ALG "md5"
++#define SCTP_COOKIE_HMAC_ALG "hmac(md5)"
+ #elif defined (CONFIG_SCTP_HMAC_SHA1)
+-#define SCTP_COOKIE_HMAC_ALG "sha1"
++#define SCTP_COOKIE_HMAC_ALG "hmac(sha1)"
+ #else
+ #define SCTP_COOKIE_HMAC_ALG NULL
+ #endif
+diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
+index 92eae0e..764e3af 100644
+--- a/include/net/sctp/sctp.h
++++ b/include/net/sctp/sctp.h
+@@ -128,6 +128,8 @@ extern int sctp_copy_local_addr_list(str
+ 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);
++int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
++ void *ptr);
+
+ /*
+ * sctp/socket.c
+@@ -137,6 +139,7 @@ int sctp_inet_listen(struct socket *sock
+ void sctp_write_space(struct sock *sk);
+ unsigned int sctp_poll(struct file *file, struct socket *sock,
+ poll_table *wait);
++void sctp_sock_rfree(struct sk_buff *skb);
+
+ /*
+ * sctp/primitive.c
+@@ -178,6 +181,17 @@ void sctp_backlog_migrate(struct sctp_as
+ struct sock *oldsk, struct sock *newsk);
+
+ /*
++ * sctp/proc.c
++ */
++int sctp_snmp_proc_init(void);
++void sctp_snmp_proc_exit(void);
++int sctp_eps_proc_init(void);
++void sctp_eps_proc_exit(void);
++int sctp_assocs_proc_init(void);
++void sctp_assocs_proc_exit(void);
++
++
++/*
+ * Section: Macros, externs, and inlines
+ */
+
+@@ -216,6 +230,50 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_
+
+ #endif /* !TEST_FRAME */
+
++/* sctp mib definitions */
++enum
++{
++ SCTP_MIB_NUM = 0,
++ SCTP_MIB_CURRESTAB, /* CurrEstab */
++ SCTP_MIB_ACTIVEESTABS, /* ActiveEstabs */
++ SCTP_MIB_PASSIVEESTABS, /* PassiveEstabs */
++ SCTP_MIB_ABORTEDS, /* Aborteds */
++ SCTP_MIB_SHUTDOWNS, /* Shutdowns */
++ SCTP_MIB_OUTOFBLUES, /* OutOfBlues */
++ SCTP_MIB_CHECKSUMERRORS, /* ChecksumErrors */
++ SCTP_MIB_OUTCTRLCHUNKS, /* OutCtrlChunks */
++ SCTP_MIB_OUTORDERCHUNKS, /* OutOrderChunks */
++ SCTP_MIB_OUTUNORDERCHUNKS, /* OutUnorderChunks */
++ SCTP_MIB_INCTRLCHUNKS, /* InCtrlChunks */
++ SCTP_MIB_INORDERCHUNKS, /* InOrderChunks */
++ SCTP_MIB_INUNORDERCHUNKS, /* InUnorderChunks */
++ SCTP_MIB_FRAGUSRMSGS, /* FragUsrMsgs */
++ SCTP_MIB_REASMUSRMSGS, /* ReasmUsrMsgs */
++ SCTP_MIB_OUTSCTPPACKS, /* OutSCTPPacks */
++ SCTP_MIB_INSCTPPACKS, /* InSCTPPacks */
++ SCTP_MIB_T1_INIT_EXPIREDS,
++ SCTP_MIB_T1_COOKIE_EXPIREDS,
++ SCTP_MIB_T2_SHUTDOWN_EXPIREDS,
++ SCTP_MIB_T3_RTX_EXPIREDS,
++ SCTP_MIB_T4_RTO_EXPIREDS,
++ SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS,
++ SCTP_MIB_DELAY_SACK_EXPIREDS,
++ SCTP_MIB_AUTOCLOSE_EXPIREDS,
++ SCTP_MIB_T3_RETRANSMITS,
++ SCTP_MIB_PMTUD_RETRANSMITS,
++ SCTP_MIB_FAST_RETRANSMITS,
++ SCTP_MIB_IN_PKT_SOFTIRQ,
++ SCTP_MIB_IN_PKT_BACKLOG,
++ SCTP_MIB_IN_PKT_DISCARDS,
++ SCTP_MIB_IN_DATA_CHUNK_DISCARDS,
++ __SCTP_MIB_MAX
++};
++
++#define SCTP_MIB_MAX __SCTP_MIB_MAX
++struct sctp_mib {
++ unsigned long mibs[SCTP_MIB_MAX];
++} __SNMP_MIB_ALIGN__;
++
+
+ /* Print debugging messages. */
+ #if SCTP_DEBUG
+@@ -330,17 +388,6 @@ static inline void sctp_v6_exit(void) {
+
+ #endif /* #if defined(CONFIG_IPV6) */
+
+-/* Some wrappers, in case crypto not available. */
+-#if defined (CONFIG_CRYPTO_HMAC)
+-#define sctp_crypto_alloc_tfm crypto_alloc_tfm
+-#define sctp_crypto_free_tfm crypto_free_tfm
+-#define sctp_crypto_hmac crypto_hmac
+-#else
+-#define sctp_crypto_alloc_tfm(x...) NULL
+-#define sctp_crypto_free_tfm(x...)
+-#define sctp_crypto_hmac(x...)
+-#endif
+-
+
+ /* Map an association to an assoc_id. */
+ static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
+@@ -398,6 +445,19 @@ static inline struct list_head *sctp_lis
+ return result;
+ }
+
++/* SCTP version of skb_set_owner_r. We need this one because
++ * of the way we have to do receive buffer accounting on bundled
++ * chunks.
++ */
++static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
++{
++ struct sctp_ulpevent *event = sctp_skb2event(skb);
++
++ skb->sk = sk;
++ skb->destructor = sctp_sock_rfree;
++ atomic_add(event->rmem_len, &sk->sk_rmem_alloc);
++}
++
+ /* Tests if the list has one and only one entry. */
+ static inline int sctp_list_single_entry(struct list_head *head)
+ {
+diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
+index e5aa7ff..c6d93bb 100644
+--- a/include/net/sctp/structs.h
++++ b/include/net/sctp/structs.h
+@@ -87,6 +87,7 @@ struct sctp_bind_addr;
+ struct sctp_ulpq;
+ struct sctp_ep_common;
+ struct sctp_ssnmap;
++struct crypto_hash;
+
+
+ #include <net/sctp/tsnmap.h>
+@@ -127,9 +128,9 @@ extern struct sctp_globals {
+ * RTO.Alpha - 1/8 (3 when converted to right shifts.)
+ * RTO.Beta - 1/4 (2 when converted to right shifts.)
+ */
+- unsigned long rto_initial;
+- unsigned long rto_min;
+- unsigned long rto_max;
++ unsigned int rto_initial;
++ unsigned int rto_min;
++ unsigned int rto_max;
+
+ /* Note: rto_alpha and rto_beta are really defined as inverse
+ * powers of two to facilitate integer operations.
+@@ -144,13 +145,13 @@ extern struct sctp_globals {
+ int cookie_preserve_enable;
+
+ /* Valid.Cookie.Life - 60 seconds */
+- unsigned long valid_cookie_life;
++ unsigned int valid_cookie_life;
+
+ /* Delayed SACK timeout 200ms default*/
+- unsigned long sack_timeout;
++ unsigned int sack_timeout;
+
+ /* HB.interval - 30 seconds */
+- unsigned long hb_interval;
++ unsigned int hb_interval;
+
+ /* Association.Max.Retrans - 10 attempts
+ * Path.Max.Retrans - 5 attempts (per destination address)
+@@ -264,7 +265,7 @@ struct sctp_sock {
+ struct sctp_pf *pf;
+
+ /* Access to HMAC transform. */
+- struct crypto_tfm *hmac;
++ struct crypto_hash *hmac;
+
+ /* What is our base endpointer? */
+ struct sctp_endpoint *ep;
+diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
+index 6c40cfc..1a4ddc1 100644
+--- a/include/net/sctp/ulpevent.h
++++ b/include/net/sctp/ulpevent.h
+@@ -63,6 +63,7 @@ struct sctp_ulpevent {
+ __u32 cumtsn;
+ int msg_flags;
+ int iif;
++ unsigned int rmem_len;
+ };
+
+ /* Retrieve the skb this event sits inside of. */
+diff --git a/include/net/snmp.h b/include/net/snmp.h
+index a36bed8..464970e 100644
+--- a/include/net/snmp.h
++++ b/include/net/snmp.h
+@@ -100,12 +100,6 @@ struct udp_mib {
+ unsigned long mibs[UDP_MIB_MAX];
+ } __SNMP_MIB_ALIGN__;
+
+-/* SCTP */
+-#define SCTP_MIB_MAX __SCTP_MIB_MAX
+-struct sctp_mib {
+- unsigned long mibs[SCTP_MIB_MAX];
+-} __SNMP_MIB_ALIGN__;
+-
+ /* Linux */
+ #define LINUX_MIB_MAX __LINUX_MIB_MAX
+ struct linux_mib {
+diff --git a/include/net/sock.h b/include/net/sock.h
+index 324b3ea..ac286a3 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -665,7 +665,6 @@ struct sock_iocb {
+ struct sock *sk;
+ struct scm_cookie *scm;
+ struct msghdr *msg, async_msg;
+- struct iovec async_iov;
+ struct kiocb *kiocb;
+ };
+
+@@ -862,41 +861,40 @@ extern void sock_init_data(struct socket
+ *
+ */
+
+-static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
++static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
+ {
+ int err;
++ struct sk_filter *filter;
+
+ err = security_sock_rcv_skb(sk, skb);
+ if (err)
+ return err;
+
+- if (sk->sk_filter) {
+- struct sk_filter *filter;
+-
+- if (needlock)
+- bh_lock_sock(sk);
+-
+- filter = sk->sk_filter;
+- if (filter) {
+- unsigned int pkt_len = sk_run_filter(skb, filter->insns,
+- filter->len);
+- err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
+- }
+-
+- if (needlock)
+- bh_unlock_sock(sk);
++ rcu_read_lock_bh();
++ filter = sk->sk_filter;
++ if (filter) {
++ unsigned int pkt_len = sk_run_filter(skb, filter->insns,
++ filter->len);
++ err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
+ }
++ rcu_read_unlock_bh();
++
+ return err;
+ }
+
+ /**
+ * sk_filter_release: Release a socket filter
+- * @sk: socket
+- * @fp: filter to remove
++ * @rcu: rcu_head that contains the sk_filter info to remove
+ *
+ * Remove a filter from a socket and release its resources.
+ */
+
++static inline void sk_filter_rcu_free(struct rcu_head *rcu)
++{
++ struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
++ kfree(fp);
++}
++
+ static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp)
+ {
+ unsigned int size = sk_filter_len(fp);
+@@ -904,7 +902,7 @@ static inline void sk_filter_release(str
+ atomic_sub(size, &sk->sk_omem_alloc);
+
+ if (atomic_dec_and_test(&fp->refcnt))
+- kfree(fp);
++ call_rcu_bh(&fp->rcu, sk_filter_rcu_free);
+ }
+
+ static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
+@@ -969,9 +967,23 @@ static inline void sock_graft(struct soc
+ sk->sk_sleep = &parent->wait;
+ parent->sk = sk;
+ sk->sk_socket = parent;
++ security_sock_graft(sk, parent);
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+
++static inline void sock_copy(struct sock *nsk, const struct sock *osk)
++{
++#ifdef CONFIG_SECURITY_NETWORK
++ void *sptr = nsk->sk_security;
++#endif
++
++ memcpy(nsk, osk, osk->sk_prot->obj_size);
++#ifdef CONFIG_SECURITY_NETWORK
++ nsk->sk_security = sptr;
++ security_sk_clone(osk, nsk);
++#endif
++}
++
+ extern int sock_i_uid(struct sock *sk);
+ extern unsigned long sock_i_ino(struct sock *sk);
+
+diff --git a/include/net/tc_act/tc_defact.h b/include/net/tc_act/tc_defact.h
+index 463aa67..65f024b 100644
+--- a/include/net/tc_act/tc_defact.h
++++ b/include/net/tc_act/tc_defact.h
+@@ -3,11 +3,12 @@
+
+ #include <net/act_api.h>
+
+-struct tcf_defact
+-{
+- tca_gen(defact);
+- u32 datalen;
+- void *defdata;
++struct tcf_defact {
++ struct tcf_common common;
++ u32 tcfd_datalen;
++ void *tcfd_defdata;
+ };
++#define to_defact(pc) \
++ container_of(pc, struct tcf_defact, common)
+
+-#endif
++#endif /* __NET_TC_DEF_H */
+diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h
+index 59f0d96..9e3f676 100644
+--- a/include/net/tc_act/tc_gact.h
++++ b/include/net/tc_act/tc_gact.h
+@@ -3,15 +3,15 @@
+
+ #include <net/act_api.h>
+
+-struct tcf_gact
+-{
+- tca_gen(gact);
++struct tcf_gact {
++ struct tcf_common common;
+ #ifdef CONFIG_GACT_PROB
+- u16 ptype;
+- u16 pval;
+- int paction;
++ u16 tcfg_ptype;
++ u16 tcfg_pval;
++ int tcfg_paction;
+ #endif
+-
+ };
+-
+-#endif
++#define to_gact(pc) \
++ container_of(pc, struct tcf_gact, common)
++
++#endif /* __NET_TC_GACT_H */
+diff --git a/include/net/tc_act/tc_ipt.h b/include/net/tc_act/tc_ipt.h
+index cb37ad0..f7d25df 100644
+--- a/include/net/tc_act/tc_ipt.h
++++ b/include/net/tc_act/tc_ipt.h
+@@ -5,12 +5,13 @@
+
+ struct xt_entry_target;
+
+-struct tcf_ipt
+-{
+- tca_gen(ipt);
+- u32 hook;
+- char *tname;
+- struct xt_entry_target *t;
++struct tcf_ipt {
++ struct tcf_common common;
++ u32 tcfi_hook;
++ char *tcfi_tname;
++ struct xt_entry_target *tcfi_t;
+ };
++#define to_ipt(pc) \
++ container_of(pc, struct tcf_ipt, common)
+
+-#endif
++#endif /* __NET_TC_IPT_H */
+diff --git a/include/net/tc_act/tc_mirred.h b/include/net/tc_act/tc_mirred.h
+index b5c32f6..ceac661 100644
+--- a/include/net/tc_act/tc_mirred.h
++++ b/include/net/tc_act/tc_mirred.h
+@@ -3,13 +3,14 @@
+
+ #include <net/act_api.h>
+
+-struct tcf_mirred
+-{
+- tca_gen(mirred);
+- int eaction;
+- int ifindex;
+- int ok_push;
+- struct net_device *dev;
++struct tcf_mirred {
++ struct tcf_common common;
++ int tcfm_eaction;
++ int tcfm_ifindex;
++ int tcfm_ok_push;
++ struct net_device *tcfm_dev;
+ };
++#define to_mirred(pc) \
++ container_of(pc, struct tcf_mirred, common)
+
+-#endif
++#endif /* __NET_TC_MIR_H */
+diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h
+index eb21689..e6f6e15 100644
+--- a/include/net/tc_act/tc_pedit.h
++++ b/include/net/tc_act/tc_pedit.h
+@@ -3,12 +3,13 @@
+
+ #include <net/act_api.h>
+
+-struct tcf_pedit
+-{
+- tca_gen(pedit);
+- unsigned char nkeys;
+- unsigned char flags;
+- struct tc_pedit_key *keys;
++struct tcf_pedit {
++ struct tcf_common common;
++ unsigned char tcfp_nkeys;
++ unsigned char tcfp_flags;
++ struct tc_pedit_key *tcfp_keys;
+ };
++#define to_pedit(pc) \
++ container_of(pc, struct tcf_pedit, common)
+
+-#endif
++#endif /* __NET_TC_PED_H */
+diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h
+index 2544281..be293d7 100644
+--- a/include/net/timewait_sock.h
++++ b/include/net/timewait_sock.h
+@@ -19,6 +19,7 @@ struct timewait_sock_ops {
+ unsigned int twsk_obj_size;
+ int (*twsk_unique)(struct sock *sk,
+ struct sock *sktw, void *twp);
++ void (*twsk_destructor)(struct sock *sk);
+ };
+
+ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
+@@ -28,4 +29,10 @@ static inline int twsk_unique(struct soc
+ return 0;
+ }
+
++static inline void twsk_destructor(struct sock *sk)
++{
++ if (sk->sk_prot->twsk_prot->twsk_destructor != NULL)
++ sk->sk_prot->twsk_prot->twsk_destructor(sk);
++}
++
+ #endif /* _TIMEWAIT_SOCK_H */
+diff --git a/include/net/udp.h b/include/net/udp.h
+index 766fba1..db0c05f 100644
+--- a/include/net/udp.h
++++ b/include/net/udp.h
+@@ -30,25 +30,9 @@
+
+ #define UDP_HTABLE_SIZE 128
+
+-/* udp.c: This needs to be shared by v4 and v6 because the lookup
+- * and hashing code needs to work with different AF's yet
+- * the port space is shared.
+- */
+ extern struct hlist_head udp_hash[UDP_HTABLE_SIZE];
+ extern rwlock_t udp_hash_lock;
+
+-extern int udp_port_rover;
+-
+-static inline int udp_lport_inuse(u16 num)
+-{
+- struct sock *sk;
+- struct hlist_node *node;
+-
+- sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)])
+- if (inet_sk(sk)->num == num)
+- return 1;
+- return 0;
+-}
+
+ /* Note: this must match 'valbool' in sock_setsockopt */
+ #define UDP_CSUM_NOXMIT 1
+@@ -63,6 +47,8 @@ extern struct proto udp_prot;
+
+ struct sk_buff;
+
++extern int udp_get_port(struct sock *sk, unsigned short snum,
++ int (*saddr_cmp)(const struct sock *, const struct sock *));
+ extern void udp_err(struct sk_buff *, u32);
+
+ extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
+diff --git a/include/net/xfrm.h b/include/net/xfrm.h
+index 9c5ee9f..737fdb2 100644
+--- a/include/net/xfrm.h
++++ b/include/net/xfrm.h
+@@ -8,8 +8,8 @@
+ #include <linux/list.h>
+ #include <linux/skbuff.h>
+ #include <linux/socket.h>
+-#include <linux/crypto.h>
+ #include <linux/pfkeyv2.h>
++#include <linux/ipsec.h>
+ #include <linux/in6.h>
+ #include <linux/mutex.h>
+
+@@ -94,8 +94,9 @@ extern struct mutex xfrm_cfg_mutex;
+ struct xfrm_state
+ {
+ /* Note: bydst is re-used during gc */
+- struct list_head bydst;
+- struct list_head byspi;
++ struct hlist_node bydst;
++ struct hlist_node bysrc;
++ struct hlist_node byspi;
+
+ atomic_t refcnt;
+ spinlock_t lock;
+@@ -103,6 +104,8 @@ struct xfrm_state
+ struct xfrm_id id;
+ struct xfrm_selector sel;
+
++ u32 genid;
++
+ /* Key manger bits */
+ struct {
+ u8 state;
+@@ -133,6 +136,9 @@ struct xfrm_state
+ /* Data for encapsulator */
+ struct xfrm_encap_tmpl *encap;
+
++ /* Data for care-of address */
++ xfrm_address_t *coaddr;
++
+ /* IPComp needs an IPIP tunnel for handling uncompressed packets */
+ struct xfrm_state *tunnel;
+
+@@ -163,6 +169,9 @@ struct xfrm_state
+ struct xfrm_lifetime_cur curlft;
+ struct timer_list timer;
+
++ /* Last used time */
++ u64 lastused;
++
+ /* Reference to data common to all the instances of this
+ * transformer. */
+ struct xfrm_type *type;
+@@ -196,6 +205,7 @@ struct km_event
+ u32 proto;
+ u32 byid;
+ u32 aevent;
++ u32 type;
+ } data;
+
+ u32 seq;
+@@ -212,6 +222,7 @@ struct xfrm_policy_afinfo {
+ struct dst_ops *dst_ops;
+ void (*garbage_collect)(void);
+ int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
++ int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
+ struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
+ int (*bundle_create)(struct xfrm_policy *policy,
+ struct xfrm_state **xfrm,
+@@ -235,16 +246,12 @@ extern int __xfrm_state_delete(struct xf
+
+ struct xfrm_state_afinfo {
+ unsigned short family;
+- struct list_head *state_bydst;
+- struct list_head *state_byspi;
+ int (*init_flags)(struct xfrm_state *x);
+ void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl,
+ struct xfrm_tmpl *tmpl,
+ xfrm_address_t *daddr, xfrm_address_t *saddr);
+- struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto);
+- struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto,
+- xfrm_address_t *daddr, xfrm_address_t *saddr,
+- int create);
++ int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);
++ int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n);
+ };
+
+ extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
+@@ -257,11 +264,17 @@ struct xfrm_type
+ char *description;
+ struct module *owner;
+ __u8 proto;
++ __u8 flags;
++#define XFRM_TYPE_NON_FRAGMENT 1
+
+ int (*init_state)(struct xfrm_state *x);
+ void (*destructor)(struct xfrm_state *);
+ int (*input)(struct xfrm_state *, struct sk_buff *skb);
+ int (*output)(struct xfrm_state *, struct sk_buff *pskb);
++ int (*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *);
++ int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **);
++ xfrm_address_t *(*local_addr)(struct xfrm_state *, xfrm_address_t *);
++ xfrm_address_t *(*remote_addr)(struct xfrm_state *, xfrm_address_t *);
+ /* Estimate maximal size of result of transformation of a dgram */
+ u32 (*get_max_size)(struct xfrm_state *, int size);
+ };
+@@ -273,7 +286,7 @@ extern void xfrm_put_type(struct xfrm_ty
+
+ struct xfrm_mode {
+ int (*input)(struct xfrm_state *x, struct sk_buff *skb);
+- int (*output)(struct sk_buff *skb);
++ int (*output)(struct xfrm_state *x,struct sk_buff *skb);
+
+ struct module *owner;
+ unsigned int encap;
+@@ -299,7 +312,7 @@ struct xfrm_tmpl
+
+ __u32 reqid;
+
+-/* Mode: transport/tunnel */
++/* Mode: transport, tunnel etc. */
+ __u8 mode;
+
+ /* Sharing mode: unique, this session only, this user only etc. */
+@@ -314,18 +327,20 @@ struct xfrm_tmpl
+ __u32 calgos;
+ };
+
+-#define XFRM_MAX_DEPTH 4
++#define XFRM_MAX_DEPTH 6
+
+ struct xfrm_policy
+ {
+ struct xfrm_policy *next;
+- struct list_head list;
++ struct hlist_node bydst;
++ struct hlist_node byidx;
+
+ /* This lock only affects elements except for entry. */
+ rwlock_t lock;
+ atomic_t refcnt;
+ struct timer_list timer;
+
++ u8 type;
+ u32 priority;
+ u32 index;
+ struct xfrm_selector selector;
+@@ -363,16 +378,16 @@ struct xfrm_mgr
+ char *id;
+ int (*notify)(struct xfrm_state *x, struct km_event *c);
+ int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
+- struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
++ struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir);
+ int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
++ int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
+ };
+
+ extern int xfrm_register_km(struct xfrm_mgr *km);
+ extern int xfrm_unregister_km(struct xfrm_mgr *km);
+
+-
+-extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2];
++extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
+
+ static inline void xfrm_pol_hold(struct xfrm_policy *policy)
+ {
+@@ -388,67 +403,19 @@ static inline void xfrm_pol_put(struct x
+ __xfrm_policy_destroy(policy);
+ }
+
+-#define XFRM_DST_HSIZE 1024
+-
+-static __inline__
+-unsigned __xfrm4_dst_hash(xfrm_address_t *addr)
+-{
+- unsigned h;
+- h = ntohl(addr->a4);
+- h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
+- return h;
+-}
+-
+-static __inline__
+-unsigned __xfrm6_dst_hash(xfrm_address_t *addr)
+-{
+- unsigned h;
+- h = ntohl(addr->a6[2]^addr->a6[3]);
+- h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
+- return h;
+-}
+-
+-static __inline__
+-unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family)
+-{
+- switch (family) {
+- case AF_INET:
+- return __xfrm4_dst_hash(addr);
+- case AF_INET6:
+- return __xfrm6_dst_hash(addr);
+- }
+- return 0;
+-}
+-
+-static __inline__
+-unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
++#ifdef CONFIG_XFRM_SUB_POLICY
++static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
+ {
+- unsigned h;
+- h = ntohl(addr->a4^spi^proto);
+- h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
+- return h;
++ int i;
++ for (i = npols - 1; i >= 0; --i)
++ xfrm_pol_put(pols[i]);
+ }
+-
+-static __inline__
+-unsigned __xfrm6_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
+-{
+- unsigned h;
+- h = ntohl(addr->a6[2]^addr->a6[3]^spi^proto);
+- h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
+- return h;
+-}
+-
+-static __inline__
+-unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family)
++#else
++static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
+ {
+- switch (family) {
+- case AF_INET:
+- return __xfrm4_spi_hash(addr, spi, proto);
+- case AF_INET6:
+- return __xfrm6_spi_hash(addr, spi, proto);
+- }
+- return 0; /*XXX*/
++ xfrm_pol_put(pols[0]);
+ }
++#endif
+
+ extern void __xfrm_state_destroy(struct xfrm_state *);
+
+@@ -470,8 +437,8 @@ static inline void xfrm_state_hold(struc
+
+ static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
+ {
+- __u32 *a1 = token1;
+- __u32 *a2 = token2;
++ __be32 *a1 = token1;
++ __be32 *a2 = token2;
+ int pdw;
+ int pbi;
+
+@@ -483,7 +450,7 @@ static __inline__ int addr_match(void *t
+ return 0;
+
+ if (pbi) {
+- __u32 mask;
++ __be32 mask;
+
+ mask = htonl((0xffffffff) << (32 - pbi));
+
+@@ -495,9 +462,9 @@ static __inline__ int addr_match(void *t
+ }
+
+ static __inline__
+-u16 xfrm_flowi_sport(struct flowi *fl)
++__be16 xfrm_flowi_sport(struct flowi *fl)
+ {
+- u16 port;
++ __be16 port;
+ switch(fl->proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+@@ -508,6 +475,11 @@ u16 xfrm_flowi_sport(struct flowi *fl)
+ case IPPROTO_ICMPV6:
+ port = htons(fl->fl_icmp_type);
+ break;
++#ifdef CONFIG_IPV6_MIP6
++ case IPPROTO_MH:
++ port = htons(fl->fl_mh_type);
++ break;
++#endif
+ default:
+ port = 0; /*XXX*/
+ }
+@@ -515,9 +487,9 @@ u16 xfrm_flowi_sport(struct flowi *fl)
+ }
+
+ static __inline__
+-u16 xfrm_flowi_dport(struct flowi *fl)
++__be16 xfrm_flowi_dport(struct flowi *fl)
+ {
+- u16 port;
++ __be16 port;
+ switch(fl->proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+@@ -608,6 +580,7 @@ struct xfrm_dst
+ struct rt6_info rt6;
+ } u;
+ struct dst_entry *route;
++ u32 genid;
+ u32 route_mtu_cached;
+ u32 child_mtu_cached;
+ u32 route_cookie;
+@@ -659,6 +632,18 @@ secpath_reset(struct sk_buff *skb)
+ }
+
+ static inline int
++xfrm_addr_any(xfrm_address_t *addr, unsigned short family)
++{
++ switch (family) {
++ case AF_INET:
++ return addr->a4 == 0;
++ case AF_INET6:
++ return ipv6_addr_any((struct in6_addr *)&addr->a6);
++ }
++ return 0;
++}
++
++static inline int
+ __xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x)
+ {
+ return (tmpl->saddr.a4 &&
+@@ -692,8 +677,8 @@ static inline int xfrm_policy_check(stru
+ {
+ if (sk && sk->sk_policy[XFRM_POLICY_IN])
+ return __xfrm_policy_check(sk, dir, skb, family);
+-
+- return (!xfrm_policy_list[dir] && !skb->sp) ||
++
++ return (!xfrm_policy_count[dir] && !skb->sp) ||
+ (skb->dst->flags & DST_NOPOLICY) ||
+ __xfrm_policy_check(sk, dir, skb, family);
+ }
+@@ -713,7 +698,7 @@ extern int __xfrm_route_forward(struct s
+
+ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
+ {
+- return !xfrm_policy_list[XFRM_POLICY_OUT] ||
++ return !xfrm_policy_count[XFRM_POLICY_OUT] ||
+ (skb->dst->flags & DST_NOXFRM) ||
+ __xfrm_route_forward(skb, family);
+ }
+@@ -831,11 +816,36 @@ xfrm_state_addr_check(struct xfrm_state
+ return 0;
+ }
+
++static __inline__ int
++xfrm_state_addr_flow_check(struct xfrm_state *x, struct flowi *fl,
++ unsigned short family)
++{
++ switch (family) {
++ case AF_INET:
++ return __xfrm4_state_addr_check(x,
++ (xfrm_address_t *)&fl->fl4_dst,
++ (xfrm_address_t *)&fl->fl4_src);
++ case AF_INET6:
++ return __xfrm6_state_addr_check(x,
++ (xfrm_address_t *)&fl->fl6_dst,
++ (xfrm_address_t *)&fl->fl6_src);
++ }
++ return 0;
++}
++
+ static inline int xfrm_state_kern(struct xfrm_state *x)
+ {
+ return atomic_read(&x->tunnel_users);
+ }
+
++static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
++{
++ return (!userproto || proto == userproto ||
++ (userproto == IPSEC_PROTO_ANY && (proto == IPPROTO_AH ||
++ proto == IPPROTO_ESP ||
++ proto == IPPROTO_COMP)));
++}
++
+ /*
+ * xfrm algorithm information
+ */
+@@ -855,6 +865,7 @@ struct xfrm_algo_comp_info {
+
+ struct xfrm_algo_desc {
+ char *name;
++ char *compat;
+ u8 available:1;
+ union {
+ struct xfrm_algo_auth_info auth;
+@@ -901,12 +912,31 @@ extern int xfrm_state_check_expire(struc
+ extern void xfrm_state_insert(struct xfrm_state *x);
+ extern int xfrm_state_add(struct xfrm_state *x);
+ extern int xfrm_state_update(struct xfrm_state *x);
+-extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
++extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family);
++extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family);
++#ifdef CONFIG_XFRM_SUB_POLICY
++extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
++ int n, unsigned short family);
++extern int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src,
++ int n, unsigned short family);
++#else
++static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
++ int n, unsigned short family)
++{
++ return -ENOSYS;
++}
++
++static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src,
++ int n, unsigned short family)
++{
++ return -ENOSYS;
++}
++#endif
+ extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
+ extern int xfrm_state_delete(struct xfrm_state *x);
+ extern void xfrm_state_flush(u8 proto);
+-extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
+-extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
++extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq);
++extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq);
+ extern void xfrm_replay_notify(struct xfrm_state *x, int event);
+ extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
+ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
+@@ -915,14 +945,18 @@ extern int xfrm4_rcv(struct sk_buff *skb
+ extern int xfrm4_output(struct sk_buff *skb);
+ extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
+ extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
+-extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi);
++extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi);
+ extern int xfrm6_rcv(struct sk_buff **pskb);
++extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
++ xfrm_address_t *saddr, u8 proto);
+ extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
+ extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
+ extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
+ extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
+ extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
+ extern int xfrm6_output(struct sk_buff *skb);
++extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
++ u8 **prevhdr);
+
+ #ifdef CONFIG_XFRM
+ extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
+@@ -947,30 +981,31 @@ static inline int xfrm_dst_lookup(struct
+ #endif
+
+ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
+-extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *);
++extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
+ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
+-struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel,
++struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
++ struct xfrm_selector *sel,
+ struct xfrm_sec_ctx *ctx, int delete);
+-struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete);
+-void xfrm_policy_flush(void);
++struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete);
++void xfrm_policy_flush(u8 type);
+ u32 xfrm_get_acqseq(void);
+-void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
++void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi);
+ struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
+ xfrm_address_t *daddr, xfrm_address_t *saddr,
+ int create, unsigned short family);
+-extern void xfrm_policy_flush(void);
++extern void xfrm_policy_flush(u8 type);
+ extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
+-extern int xfrm_flush_bundles(void);
+-extern void xfrm_flush_all_bundles(void);
+-extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family);
++extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
++ struct flowi *fl, int family, int strict);
+ extern void xfrm_init_pmtu(struct dst_entry *dst);
+
+ extern wait_queue_head_t km_waitq;
+ extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
+ extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
++extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
+
+ extern void xfrm_input_init(void);
+-extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
++extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq);
+
+ extern void xfrm_probe_algs(void);
+ extern int xfrm_count_auth_supported(void);
+@@ -984,11 +1019,13 @@ extern struct xfrm_algo_desc *xfrm_aalg_
+ extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
+ extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
+
+-struct crypto_tfm;
+-typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, unsigned int);
++struct hash_desc;
++struct scatterlist;
++typedef int (icv_update_fn_t)(struct hash_desc *, struct scatterlist *,
++ unsigned int);
+
+-extern void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
+- int offset, int len, icv_update_fn_t icv_update);
++extern int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *tfm,
++ int offset, int len, icv_update_fn_t icv_update);
+
+ static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b,
+ int family)
+diff --git a/include/rdma/Kbuild b/include/rdma/Kbuild
+index eb710ba..e7c0432 100644
+--- a/include/rdma/Kbuild
++++ b/include/rdma/Kbuild
+@@ -1 +1 @@
+-header-y := ib_user_mad.h
++header-y += ib_user_mad.h
+diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
+index 0ff6739..c094e50 100644
+--- a/include/rdma/ib_addr.h
++++ b/include/rdma/ib_addr.h
+@@ -36,11 +36,27 @@
+ #include <linux/socket.h>
+ #include <rdma/ib_verbs.h>
+
++struct rdma_addr_client {
++ atomic_t refcount;
++ struct completion comp;
++};
++
++/**
++ * rdma_addr_register_client - Register an address client.
++ */
++void rdma_addr_register_client(struct rdma_addr_client *client);
++
++/**
++ * rdma_addr_unregister_client - Deregister an address client.
++ * @client: Client object to deregister.
++ */
++void rdma_addr_unregister_client(struct rdma_addr_client *client);
++
+ struct rdma_dev_addr {
+ unsigned char src_dev_addr[MAX_ADDR_LEN];
+ unsigned char dst_dev_addr[MAX_ADDR_LEN];
+ unsigned char broadcast[MAX_ADDR_LEN];
+- enum ib_node_type dev_type;
++ enum rdma_node_type dev_type;
+ };
+
+ /**
+@@ -52,6 +68,7 @@ int rdma_translate_ip(struct sockaddr *a
+ /**
+ * rdma_resolve_ip - Resolve source and destination IP addresses to
+ * RDMA hardware addresses.
++ * @client: Address client associated with request.
+ * @src_addr: An optional source address to use in the resolution. If a
+ * source address is not provided, a usable address will be returned via
+ * the callback.
+@@ -64,7 +81,8 @@ int rdma_translate_ip(struct sockaddr *a
+ * or been canceled. A status of 0 indicates success.
+ * @context: User-specified context associated with the call.
+ */
+-int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
++int rdma_resolve_ip(struct rdma_addr_client *client,
++ struct sockaddr *src_addr, struct sockaddr *dst_addr,
+ struct rdma_dev_addr *addr, int timeout_ms,
+ void (*callback)(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context),
+@@ -72,6 +90,9 @@ int rdma_resolve_ip(struct sockaddr *src
+
+ void rdma_addr_cancel(struct rdma_dev_addr *addr);
+
++int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
++ const unsigned char *dst_dev_addr);
++
+ static inline int ip_addr_size(struct sockaddr *addr)
+ {
+ return addr->sa_family == AF_INET6 ?
+@@ -113,4 +134,16 @@ static inline void ib_addr_set_dgid(stru
+ memcpy(dev_addr->dst_dev_addr + 4, gid, sizeof *gid);
+ }
+
++static inline void iw_addr_get_sgid(struct rdma_dev_addr *dev_addr,
++ union ib_gid *gid)
++{
++ memcpy(gid, dev_addr->src_dev_addr, sizeof *gid);
++}
++
++static inline void iw_addr_get_dgid(struct rdma_dev_addr *dev_addr,
++ union ib_gid *gid)
++{
++ memcpy(gid, dev_addr->dst_dev_addr, sizeof *gid);
++}
++
+ #endif /* IB_ADDR_H */
+diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h
+index c99e442..97715b0 100644
+--- a/include/rdma/ib_sa.h
++++ b/include/rdma/ib_sa.h
+@@ -1,6 +1,7 @@
+ /*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
++ * Copyright (c) 2006 Intel Corporation. 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
+@@ -36,8 +37,11 @@
+ #ifndef IB_SA_H
+ #define IB_SA_H
+
++#include <linux/completion.h>
+ #include <linux/compiler.h>
+
++#include <asm/atomic.h>
++
+ #include <rdma/ib_verbs.h>
+ #include <rdma/ib_mad.h>
+
+@@ -79,8 +83,8 @@ enum {
+ };
+
+ enum ib_sa_selector {
+- IB_SA_GTE = 0,
+- IB_SA_LTE = 1,
++ IB_SA_GT = 0,
++ IB_SA_LT = 1,
+ IB_SA_EQ = 2,
+ /*
+ * The meaning of "best" depends on the attribute: for
+@@ -250,11 +254,28 @@ struct ib_sa_service_rec {
+ u64 data64[2];
+ };
+
++struct ib_sa_client {
++ atomic_t users;
++ struct completion comp;
++};
++
++/**
++ * ib_sa_register_client - Register an SA client.
++ */
++void ib_sa_register_client(struct ib_sa_client *client);
++
++/**
++ * ib_sa_unregister_client - Deregister an SA client.
++ * @client: Client object to deregister.
++ */
++void ib_sa_unregister_client(struct ib_sa_client *client);
++
+ struct ib_sa_query;
+
+ void ib_sa_cancel_query(int id, struct ib_sa_query *query);
+
+-int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
++int ib_sa_path_rec_get(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ struct ib_sa_path_rec *rec,
+ ib_sa_comp_mask comp_mask,
+ int timeout_ms, gfp_t gfp_mask,
+@@ -264,7 +285,8 @@ int ib_sa_path_rec_get(struct ib_device
+ void *context,
+ struct ib_sa_query **query);
+
+-int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
++int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ u8 method,
+ struct ib_sa_mcmember_rec *rec,
+ ib_sa_comp_mask comp_mask,
+@@ -275,7 +297,8 @@ int ib_sa_mcmember_rec_query(struct ib_d
+ void *context,
+ struct ib_sa_query **query);
+
+-int ib_sa_service_rec_query(struct ib_device *device, u8 port_num,
++int ib_sa_service_rec_query(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ u8 method,
+ struct ib_sa_service_rec *rec,
+ ib_sa_comp_mask comp_mask,
+@@ -288,6 +311,7 @@ int ib_sa_service_rec_query(struct ib_de
+
+ /**
+ * ib_sa_mcmember_rec_set - Start an MCMember set query
++ * @client:SA client
+ * @device:device to send query on
+ * @port_num: port number to send query on
+ * @rec:MCMember Record to send in query
+@@ -311,7 +335,8 @@ int ib_sa_service_rec_query(struct ib_de
+ * cancel the query.
+ */
+ static inline int
+-ib_sa_mcmember_rec_set(struct ib_device *device, u8 port_num,
++ib_sa_mcmember_rec_set(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ struct ib_sa_mcmember_rec *rec,
+ ib_sa_comp_mask comp_mask,
+ int timeout_ms, gfp_t gfp_mask,
+@@ -321,7 +346,7 @@ ib_sa_mcmember_rec_set(struct ib_device
+ void *context,
+ struct ib_sa_query **query)
+ {
+- return ib_sa_mcmember_rec_query(device, port_num,
++ return ib_sa_mcmember_rec_query(client, device, port_num,
+ IB_MGMT_METHOD_SET,
+ rec, comp_mask,
+ timeout_ms, gfp_mask, callback,
+@@ -330,6 +355,7 @@ ib_sa_mcmember_rec_set(struct ib_device
+
+ /**
+ * ib_sa_mcmember_rec_delete - Start an MCMember delete query
++ * @client:SA client
+ * @device:device to send query on
+ * @port_num: port number to send query on
+ * @rec:MCMember Record to send in query
+@@ -353,7 +379,8 @@ ib_sa_mcmember_rec_set(struct ib_device
+ * cancel the query.
+ */
+ static inline int
+-ib_sa_mcmember_rec_delete(struct ib_device *device, u8 port_num,
++ib_sa_mcmember_rec_delete(struct ib_sa_client *client,
++ struct ib_device *device, u8 port_num,
+ struct ib_sa_mcmember_rec *rec,
+ ib_sa_comp_mask comp_mask,
+ int timeout_ms, gfp_t gfp_mask,
+@@ -363,7 +390,7 @@ ib_sa_mcmember_rec_delete(struct ib_devi
+ void *context,
+ struct ib_sa_query **query)
+ {
+- return ib_sa_mcmember_rec_query(device, port_num,
++ return ib_sa_mcmember_rec_query(client, device, port_num,
+ IB_SA_METHOD_DELETE,
+ rec, comp_mask,
+ timeout_ms, gfp_mask, callback,
+diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h
+index 7b53720..64a721f 100644
+--- a/include/rdma/ib_user_verbs.h
++++ b/include/rdma/ib_user_verbs.h
+@@ -275,6 +275,8 @@ struct ib_uverbs_resize_cq {
+
+ struct ib_uverbs_resize_cq_resp {
+ __u32 cqe;
++ __u32 reserved;
++ __u64 driver_data[0];
+ };
+
+ struct ib_uverbs_poll_cq {
+@@ -456,7 +458,7 @@ struct ib_uverbs_query_qp_resp {
+ __u8 cur_qp_state;
+ __u8 path_mtu;
+ __u8 path_mig_state;
+- __u8 en_sqd_async_notify;
++ __u8 sq_draining;
+ __u8 max_rd_atomic;
+ __u8 max_dest_rd_atomic;
+ __u8 min_rnr_timer;
+diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
+index ee1f3a3..8eacc35 100644
+--- a/include/rdma/ib_verbs.h
++++ b/include/rdma/ib_verbs.h
+@@ -56,12 +56,22 @@ union ib_gid {
+ } global;
+ };
+
+-enum ib_node_type {
+- IB_NODE_CA = 1,
+- IB_NODE_SWITCH,
+- IB_NODE_ROUTER
++enum rdma_node_type {
++ /* IB values map to NodeInfo:NodeType. */
++ RDMA_NODE_IB_CA = 1,
++ RDMA_NODE_IB_SWITCH,
++ RDMA_NODE_IB_ROUTER,
++ RDMA_NODE_RNIC
+ };
+
++enum rdma_transport_type {
++ RDMA_TRANSPORT_IB,
++ RDMA_TRANSPORT_IWARP
++};
++
++enum rdma_transport_type
++rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__;
++
+ enum ib_device_cap_flags {
+ IB_DEVICE_RESIZE_MAX_WR = 1,
+ IB_DEVICE_BAD_PKEY_CNTR = (1<<1),
+@@ -78,6 +88,9 @@ enum ib_device_cap_flags {
+ IB_DEVICE_RC_RNR_NAK_GEN = (1<<12),
+ IB_DEVICE_SRQ_RESIZE = (1<<13),
+ IB_DEVICE_N_NOTIFY_CQ = (1<<14),
++ IB_DEVICE_ZERO_STAG = (1<<15),
++ IB_DEVICE_SEND_W_INV = (1<<16),
++ IB_DEVICE_MEM_WINDOW = (1<<17)
+ };
+
+ enum ib_atomic_cap {
+@@ -835,6 +848,8 @@ struct ib_cache {
+ u8 *lmc_cache;
+ };
+
++struct iw_cm_verbs;
++
+ struct ib_device {
+ struct device *dma_device;
+
+@@ -851,6 +866,8 @@ struct ib_device {
+
+ u32 flags;
+
++ struct iw_cm_verbs *iwcm;
++
+ int (*query_device)(struct ib_device *device,
+ struct ib_device_attr *device_attr);
+ int (*query_port)(struct ib_device *device,
+@@ -888,7 +905,8 @@ struct ib_device {
+ struct ib_udata *udata);
+ int (*modify_srq)(struct ib_srq *srq,
+ struct ib_srq_attr *srq_attr,
+- enum ib_srq_attr_mask srq_attr_mask);
++ enum ib_srq_attr_mask srq_attr_mask,
++ struct ib_udata *udata);
+ int (*query_srq)(struct ib_srq *srq,
+ struct ib_srq_attr *srq_attr);
+ int (*destroy_srq)(struct ib_srq *srq);
+@@ -900,7 +918,8 @@ struct ib_device {
+ struct ib_udata *udata);
+ int (*modify_qp)(struct ib_qp *qp,
+ struct ib_qp_attr *qp_attr,
+- int qp_attr_mask);
++ int qp_attr_mask,
++ struct ib_udata *udata);
+ int (*query_qp)(struct ib_qp *qp,
+ struct ib_qp_attr *qp_attr,
+ int qp_attr_mask,
+diff --git a/include/rdma/iw_cm.h b/include/rdma/iw_cm.h
+new file mode 100644
+index 0000000..aeefa9b
+--- /dev/null
++++ b/include/rdma/iw_cm.h
+@@ -0,0 +1,258 @@
++/*
++ * Copyright (c) 2005 Network Appliance, Inc. All rights reserved.
++ * Copyright (c) 2005 Open Grid Computing, 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
++ * 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 IW_CM_H
++#define IW_CM_H
++
++#include <linux/in.h>
++#include <rdma/ib_cm.h>
++
++struct iw_cm_id;
++
++enum iw_cm_event_type {
++ IW_CM_EVENT_CONNECT_REQUEST = 1, /* connect request received */
++ IW_CM_EVENT_CONNECT_REPLY, /* reply from active connect request */
++ IW_CM_EVENT_ESTABLISHED, /* passive side accept successful */
++ IW_CM_EVENT_DISCONNECT, /* orderly shutdown */
++ IW_CM_EVENT_CLOSE /* close complete */
++};
++
++enum iw_cm_event_status {
++ IW_CM_EVENT_STATUS_OK = 0, /* request successful */
++ IW_CM_EVENT_STATUS_ACCEPTED = 0, /* connect request accepted */
++ IW_CM_EVENT_STATUS_REJECTED, /* connect request rejected */
++ IW_CM_EVENT_STATUS_TIMEOUT, /* the operation timed out */
++ IW_CM_EVENT_STATUS_RESET, /* reset from remote peer */
++ IW_CM_EVENT_STATUS_EINVAL, /* asynchronous failure for bad parm */
++};
++
++struct iw_cm_event {
++ enum iw_cm_event_type event;
++ enum iw_cm_event_status status;
++ struct sockaddr_in local_addr;
++ struct sockaddr_in remote_addr;
++ void *private_data;
++ u8 private_data_len;
++ void* provider_data;
++};
++
++/**
++ * iw_cm_handler - Function to be called by the IW CM when delivering events
++ * to the client.
++ *
++ * @cm_id: The IW CM identifier associated with the event.
++ * @event: Pointer to the event structure.
++ */
++typedef int (*iw_cm_handler)(struct iw_cm_id *cm_id,
++ struct iw_cm_event *event);
++
++/**
++ * iw_event_handler - Function called by the provider when delivering provider
++ * events to the IW CM. Returns either 0 indicating the event was processed
++ * or -errno if the event could not be processed.
++ *
++ * @cm_id: The IW CM identifier associated with the event.
++ * @event: Pointer to the event structure.
++ */
++typedef int (*iw_event_handler)(struct iw_cm_id *cm_id,
++ struct iw_cm_event *event);
++
++struct iw_cm_id {
++ iw_cm_handler cm_handler; /* client callback function */
++ void *context; /* client cb context */
++ struct ib_device *device;
++ struct sockaddr_in local_addr;
++ struct sockaddr_in remote_addr;
++ void *provider_data; /* provider private data */
++ iw_event_handler event_handler; /* cb for provider
++ events */
++ /* Used by provider to add and remove refs on IW cm_id */
++ void (*add_ref)(struct iw_cm_id *);
++ void (*rem_ref)(struct iw_cm_id *);
++};
++
++struct iw_cm_conn_param {
++ const void *private_data;
++ u16 private_data_len;
++ u32 ord;
++ u32 ird;
++ u32 qpn;
++};
++
++struct iw_cm_verbs {
++ void (*add_ref)(struct ib_qp *qp);
++
++ void (*rem_ref)(struct ib_qp *qp);
++
++ struct ib_qp * (*get_qp)(struct ib_device *device,
++ int qpn);
++
++ int (*connect)(struct iw_cm_id *cm_id,
++ struct iw_cm_conn_param *conn_param);
++
++ int (*accept)(struct iw_cm_id *cm_id,
++ struct iw_cm_conn_param *conn_param);
++
++ int (*reject)(struct iw_cm_id *cm_id,
++ const void *pdata, u8 pdata_len);
++
++ int (*create_listen)(struct iw_cm_id *cm_id,
++ int backlog);
++
++ int (*destroy_listen)(struct iw_cm_id *cm_id);
++};
++
++/**
++ * iw_create_cm_id - Create an IW CM identifier.
++ *
++ * @device: The IB device on which to create the IW CM identier.
++ * @event_handler: User callback invoked to report events associated with the
++ * returned IW CM identifier.
++ * @context: User specified context associated with the id.
++ */
++struct iw_cm_id *iw_create_cm_id(struct ib_device *device,
++ iw_cm_handler cm_handler, void *context);
++
++/**
++ * iw_destroy_cm_id - Destroy an IW CM identifier.
++ *
++ * @cm_id: The previously created IW CM identifier to destroy.
++ *
++ * The client can assume that no events will be delivered for the CM ID after
++ * this function returns.
++ */
++void iw_destroy_cm_id(struct iw_cm_id *cm_id);
++
++/**
++ * iw_cm_bind_qp - Unbind the specified IW CM identifier and QP
++ *
++ * @cm_id: The IW CM idenfier to unbind from the QP.
++ * @qp: The QP
++ *
++ * This is called by the provider when destroying the QP to ensure
++ * that any references held by the IWCM are released. It may also
++ * be called by the IWCM when destroying a CM_ID to that any
++ * references held by the provider are released.
++ */
++void iw_cm_unbind_qp(struct iw_cm_id *cm_id, struct ib_qp *qp);
++
++/**
++ * iw_cm_get_qp - Return the ib_qp associated with a QPN
++ *
++ * @ib_device: The IB device
++ * @qpn: The queue pair number
++ */
++struct ib_qp *iw_cm_get_qp(struct ib_device *device, int qpn);
++
++/**
++ * iw_cm_listen - Listen for incoming connection requests on the
++ * specified IW CM id.
++ *
++ * @cm_id: The IW CM identifier.
++ * @backlog: The maximum number of outstanding un-accepted inbound listen
++ * requests to queue.
++ *
++ * The source address and port number are specified in the IW CM identifier
++ * structure.
++ */
++int iw_cm_listen(struct iw_cm_id *cm_id, int backlog);
++
++/**
++ * iw_cm_accept - Called to accept an incoming connect request.
++ *
++ * @cm_id: The IW CM identifier associated with the connection request.
++ * @iw_param: Pointer to a structure containing connection establishment
++ * parameters.
++ *
++ * The specified cm_id will have been provided in the event data for a
++ * CONNECT_REQUEST event. Subsequent events related to this connection will be
++ * delivered to the specified IW CM identifier prior and may occur prior to
++ * the return of this function. If this function returns a non-zero value, the
++ * client can assume that no events will be delivered to the specified IW CM
++ * identifier.
++ */
++int iw_cm_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param);
++
++/**
++ * iw_cm_reject - Reject an incoming connection request.
++ *
++ * @cm_id: Connection identifier associated with the request.
++ * @private_daa: Pointer to data to deliver to the remote peer as part of the
++ * reject message.
++ * @private_data_len: The number of bytes in the private_data parameter.
++ *
++ * The client can assume that no events will be delivered to the specified IW
++ * CM identifier following the return of this function. The private_data
++ * buffer is available for reuse when this function returns.
++ */
++int iw_cm_reject(struct iw_cm_id *cm_id, const void *private_data,
++ u8 private_data_len);
++
++/**
++ * iw_cm_connect - Called to request a connection to a remote peer.
++ *
++ * @cm_id: The IW CM identifier for the connection.
++ * @iw_param: Pointer to a structure containing connection establishment
++ * parameters.
++ *
++ * Events may be delivered to the specified IW CM identifier prior to the
++ * return of this function. If this function returns a non-zero value, the
++ * client can assume that no events will be delivered to the specified IW CM
++ * identifier.
++ */
++int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param);
++
++/**
++ * iw_cm_disconnect - Close the specified connection.
++ *
++ * @cm_id: The IW CM identifier to close.
++ * @abrupt: If 0, the connection will be closed gracefully, otherwise, the
++ * connection will be reset.
++ *
++ * The IW CM identifier is still active until the IW_CM_EVENT_CLOSE event is
++ * delivered.
++ */
++int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt);
++
++/**
++ * iw_cm_init_qp_attr - Called to initialize the attributes of the QP
++ * associated with a IW CM identifier.
++ *
++ * @cm_id: The IW CM identifier associated with the QP
++ * @qp_attr: Pointer to the QP attributes structure.
++ * @qp_attr_mask: Pointer to a bit vector specifying which QP attributes are
++ * valid.
++ */
++int iw_cm_init_qp_attr(struct iw_cm_id *cm_id, struct ib_qp_attr *qp_attr,
++ int *qp_attr_mask);
++
++#endif /* IW_CM_H */
+diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h
+index 402c63d..deb5a0a 100644
+--- a/include/rdma/rdma_cm.h
++++ b/include/rdma/rdma_cm.h
+@@ -117,6 +117,14 @@ struct rdma_cm_id {
+ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+ void *context, enum rdma_port_space ps);
+
++/**
++ * rdma_destroy_id - Destroys an RDMA identifier.
++ *
++ * @id: RDMA identifier.
++ *
++ * Note: calling this function has the effect of canceling in-flight
++ * asynchronous operations associated with the id.
++ */
+ void rdma_destroy_id(struct rdma_cm_id *id);
+
+ /**
+@@ -237,6 +245,10 @@ int rdma_listen(struct rdma_cm_id *id, i
+ * Typically, this routine is only called by the listener to accept a connection
+ * request. It must also be called on the active side of a connection if the
+ * user is performing their own QP transitions.
++ *
++ * In the case of error, a reject message is sent to the remote side and the
++ * state of the qp associated with the id is modified to error, such that any
++ * previously posted receive buffers would be flushed.
+ */
+ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
+
+diff --git a/include/scsi/Kbuild b/include/scsi/Kbuild
+index 14a033d..744f850 100644
+--- a/include/scsi/Kbuild
++++ b/include/scsi/Kbuild
+@@ -1,2 +1,4 @@
+ header-y += scsi.h
+-unifdef-y := scsi_ioctl.h sg.h
++
++unifdef-y += scsi_ioctl.h
++unifdef-y += sg.h
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 41904f6..61eebec 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -102,6 +102,8 @@ struct iscsi_cmd_task {
+ uint32_t unsol_datasn;
+ int imm_count; /* imm-data (bytes) */
+ int unsol_count; /* unsolicited (bytes)*/
++ /* offset in unsolicited stream (bytes); */
++ int unsol_offset;
+ int data_count; /* remaining Data-Out */
+ struct scsi_cmnd *sc; /* associated SCSI cmd*/
+ int total_length;
+@@ -110,6 +112,7 @@ struct iscsi_cmd_task {
+
+ /* state set/tested under session->lock */
+ int state;
++ atomic_t refcount;
+ struct list_head running; /* running cmd list */
+ void *dd_data; /* driver/transport data */
+ };
+@@ -133,7 +136,6 @@ struct iscsi_conn {
+
+ /* control data */
+ int id; /* CID */
+- struct list_head item; /* maintains list of conns */
+ int c_stage; /* connection state */
+ /*
+ * Preallocated buffer for pdus that have data but do not
+@@ -232,10 +234,8 @@ struct iscsi_session {
+ * - mgmtpool, *
+ * - r2tpool */
+ int state; /* session state */
+- struct list_head item;
+ int age; /* counts session re-opens */
+
+- struct list_head connections; /* list of connections */
+ int cmds_max; /* size of cmds array */
+ struct iscsi_cmd_task **cmds; /* Original Cmds arr */
+ struct iscsi_queue cmdpool; /* PDU's pool */
+@@ -290,8 +290,7 @@ extern int iscsi_conn_get_param(struct i
+ extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
+ struct iscsi_nopin *);
+ extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
+- struct iscsi_data *hdr,
+- int transport_data_cnt);
++ struct iscsi_data *hdr);
+ extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
+ char *, uint32_t);
+ extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
+diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
+new file mode 100644
+index 0000000..9582e84
+--- /dev/null
++++ b/include/scsi/libsas.h
+@@ -0,0 +1,627 @@
++/*
++ * SAS host prototypes and structures header file
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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 _LIBSAS_H_
++#define _LIBSAS_H_
++
++
++#include <linux/timer.h>
++#include <linux/pci.h>
++#include <scsi/sas.h>
++#include <linux/list.h>
++#include <asm/semaphore.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_transport_sas.h>
++
++struct block_device;
++
++enum sas_class {
++ SAS,
++ EXPANDER
++};
++
++enum sas_phy_role {
++ PHY_ROLE_NONE = 0,
++ PHY_ROLE_TARGET = 0x40,
++ PHY_ROLE_INITIATOR = 0x80,
++};
++
++enum sas_phy_type {
++ PHY_TYPE_PHYSICAL,
++ PHY_TYPE_VIRTUAL
++};
++
++/* The events are mnemonically described in sas_dump.c
++ * so when updating/adding events here, please also
++ * update the other file too.
++ */
++enum ha_event {
++ HAE_RESET = 0U,
++ HA_NUM_EVENTS = 1,
++};
++
++enum port_event {
++ PORTE_BYTES_DMAED = 0U,
++ PORTE_BROADCAST_RCVD = 1,
++ PORTE_LINK_RESET_ERR = 2,
++ PORTE_TIMER_EVENT = 3,
++ PORTE_HARD_RESET = 4,
++ PORT_NUM_EVENTS = 5,
++};
++
++enum phy_event {
++ PHYE_LOSS_OF_SIGNAL = 0U,
++ PHYE_OOB_DONE = 1,
++ PHYE_OOB_ERROR = 2,
++ PHYE_SPINUP_HOLD = 3, /* hot plug SATA, no COMWAKE sent */
++ PHY_NUM_EVENTS = 4,
++};
++
++enum discover_event {
++ DISCE_DISCOVER_DOMAIN = 0U,
++ DISCE_REVALIDATE_DOMAIN = 1,
++ DISCE_PORT_GONE = 2,
++ DISC_NUM_EVENTS = 3,
++};
++
++/* ---------- Expander Devices ---------- */
++
++#define ETASK 0xFA
++
++#define to_dom_device(_obj) container_of(_obj, struct domain_device, dev_obj)
++#define to_dev_attr(_attr) container_of(_attr, struct domain_dev_attribute,\
++ attr)
++
++enum routing_attribute {
++ DIRECT_ROUTING,
++ SUBTRACTIVE_ROUTING,
++ TABLE_ROUTING,
++};
++
++enum ex_phy_state {
++ PHY_EMPTY,
++ PHY_VACANT,
++ PHY_NOT_PRESENT,
++ PHY_DEVICE_DISCOVERED
++};
++
++struct ex_phy {
++ int phy_id;
++
++ enum ex_phy_state phy_state;
++
++ enum sas_dev_type attached_dev_type;
++ enum sas_linkrate linkrate;
++
++ u8 attached_sata_host:1;
++ u8 attached_sata_dev:1;
++ u8 attached_sata_ps:1;
++
++ enum sas_proto attached_tproto;
++ enum sas_proto attached_iproto;
++
++ u8 attached_sas_addr[SAS_ADDR_SIZE];
++ u8 attached_phy_id;
++
++ u8 phy_change_count;
++ enum routing_attribute routing_attr;
++ u8 virtual:1;
++
++ int last_da_index;
++
++ struct sas_phy *phy;
++ struct sas_port *port;
++};
++
++struct expander_device {
++ struct list_head children;
++
++ u16 ex_change_count;
++ u16 max_route_indexes;
++ u8 num_phys;
++ u8 configuring:1;
++ u8 conf_route_table:1;
++ u8 enclosure_logical_id[8];
++
++ struct ex_phy *ex_phy;
++ struct sas_port *parent_port;
++};
++
++/* ---------- SATA device ---------- */
++enum ata_command_set {
++ ATA_COMMAND_SET = 0,
++ ATAPI_COMMAND_SET = 1,
++};
++
++struct sata_device {
++ enum ata_command_set command_set;
++ struct smp_resp rps_resp; /* report_phy_sata_resp */
++ __le16 *identify_device;
++ __le16 *identify_packet_device;
++
++ u8 port_no; /* port number, if this is a PM (Port) */
++ struct list_head children; /* PM Ports if this is a PM */
++};
++
++/* ---------- Domain device ---------- */
++struct domain_device {
++ enum sas_dev_type dev_type;
++
++ enum sas_linkrate linkrate;
++ enum sas_linkrate min_linkrate;
++ enum sas_linkrate max_linkrate;
++
++ int pathways;
++
++ struct domain_device *parent;
++ struct list_head siblings; /* devices on the same level */
++ struct asd_sas_port *port; /* shortcut to root of the tree */
++
++ struct list_head dev_list_node;
++
++ enum sas_proto iproto;
++ enum sas_proto tproto;
++
++ struct sas_rphy *rphy;
++
++ u8 sas_addr[SAS_ADDR_SIZE];
++ u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
++
++ u8 frame_rcvd[32];
++
++ union {
++ struct expander_device ex_dev;
++ struct sata_device sata_dev; /* STP & directly attached */
++ };
++
++ void *lldd_dev;
++};
++
++struct sas_discovery {
++ spinlock_t disc_event_lock;
++ struct work_struct disc_work[DISC_NUM_EVENTS];
++ unsigned long pending;
++ u8 fanout_sas_addr[8];
++ u8 eeds_a[8];
++ u8 eeds_b[8];
++ int max_level;
++};
++
++
++/* The port struct is Class:RW, driver:RO */
++struct asd_sas_port {
++/* private: */
++ struct completion port_gone_completion;
++
++ struct sas_discovery disc;
++ struct domain_device *port_dev;
++ spinlock_t dev_list_lock;
++ struct list_head dev_list;
++ enum sas_linkrate linkrate;
++
++ struct sas_phy *phy;
++ struct work_struct work;
++
++/* public: */
++ int id;
++
++ enum sas_class class;
++ u8 sas_addr[SAS_ADDR_SIZE];
++ u8 attached_sas_addr[SAS_ADDR_SIZE];
++ enum sas_proto iproto;
++ enum sas_proto tproto;
++
++ enum sas_oob_mode oob_mode;
++
++ spinlock_t phy_list_lock;
++ struct list_head phy_list;
++ int num_phys;
++ u32 phy_mask;
++
++ struct sas_ha_struct *ha;
++
++ struct sas_port *port;
++
++ void *lldd_port; /* not touched by the sas class code */
++};
++
++/* The phy pretty much is controlled by the LLDD.
++ * The class only reads those fields.
++ */
++struct asd_sas_phy {
++/* private: */
++ /* protected by ha->event_lock */
++ struct work_struct port_events[PORT_NUM_EVENTS];
++ struct work_struct phy_events[PHY_NUM_EVENTS];
++
++ unsigned long port_events_pending;
++ unsigned long phy_events_pending;
++
++ int error;
++
++ struct sas_phy *phy;
++
++/* public: */
++ /* The following are class:RO, driver:R/W */
++ int enabled; /* must be set */
++
++ int id; /* must be set */
++ enum sas_class class;
++ enum sas_proto iproto;
++ enum sas_proto tproto;
++
++ enum sas_phy_type type;
++ enum sas_phy_role role;
++ enum sas_oob_mode oob_mode;
++ enum sas_linkrate linkrate;
++
++ u8 *sas_addr; /* must be set */
++ u8 attached_sas_addr[SAS_ADDR_SIZE]; /* class:RO, driver: R/W */
++
++ spinlock_t frame_rcvd_lock;
++ u8 *frame_rcvd; /* must be set */
++ int frame_rcvd_size;
++
++ spinlock_t sas_prim_lock;
++ u32 sas_prim;
++
++ struct list_head port_phy_el; /* driver:RO */
++ struct asd_sas_port *port; /* Class:RW, driver: RO */
++
++ struct sas_ha_struct *ha; /* may be set; the class sets it anyway */
++
++ void *lldd_phy; /* not touched by the sas_class_code */
++};
++
++struct scsi_core {
++ struct Scsi_Host *shost;
++
++ spinlock_t task_queue_lock;
++ struct list_head task_queue;
++ int task_queue_size;
++
++ struct semaphore queue_thread_sema;
++ int queue_thread_kill;
++};
++
++struct sas_ha_struct {
++/* private: */
++ spinlock_t event_lock;
++ struct work_struct ha_events[HA_NUM_EVENTS];
++ unsigned long pending;
++
++ struct scsi_core core;
++
++/* public: */
++ char *sas_ha_name;
++ struct pci_dev *pcidev; /* should be set */
++ struct module *lldd_module; /* should be set */
++
++ u8 *sas_addr; /* must be set */
++ u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
++
++ spinlock_t phy_port_lock;
++ struct asd_sas_phy **sas_phy; /* array of valid pointers, must be set */
++ struct asd_sas_port **sas_port; /* array of valid pointers, must be set */
++ int num_phys; /* must be set, gt 0, static */
++
++ /* The class calls this to send a task for execution. */
++ int lldd_max_execute_num;
++ int lldd_queue_size;
++
++ /* LLDD calls these to notify the class of an event. */
++ void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
++ void (*notify_port_event)(struct asd_sas_phy *, enum port_event);
++ void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event);
++
++ void *lldd_ha; /* not touched by sas class code */
++};
++
++#define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)
++
++static inline struct domain_device *
++starget_to_domain_dev(struct scsi_target *starget) {
++ return starget->hostdata;
++}
++
++static inline struct domain_device *
++sdev_to_domain_dev(struct scsi_device *sdev) {
++ return starget_to_domain_dev(sdev->sdev_target);
++}
++
++static inline struct domain_device *
++cmd_to_domain_dev(struct scsi_cmnd *cmd)
++{
++ return sdev_to_domain_dev(cmd->device);
++}
++
++void sas_hash_addr(u8 *hashed, const u8 *sas_addr);
++
++/* Before calling a notify event, LLDD should use this function
++ * when the link is severed (possibly from its tasklet).
++ * The idea is that the Class only reads those, while the LLDD,
++ * can R/W these (thus avoiding a race).
++ */
++static inline void sas_phy_disconnected(struct asd_sas_phy *phy)
++{
++ phy->oob_mode = OOB_NOT_CONNECTED;
++ phy->linkrate = SAS_LINK_RATE_UNKNOWN;
++}
++
++/* ---------- Tasks ---------- */
++/*
++ service_response | SAS_TASK_COMPLETE | SAS_TASK_UNDELIVERED |
++ exec_status | | |
++ ---------------------+---------------------+-----------------------+
++ SAM_... | X | |
++ DEV_NO_RESPONSE | X | X |
++ INTERRUPTED | X | |
++ QUEUE_FULL | | X |
++ DEVICE_UNKNOWN | | X |
++ SG_ERR | | X |
++ ---------------------+---------------------+-----------------------+
++ */
++
++enum service_response {
++ SAS_TASK_COMPLETE,
++ SAS_TASK_UNDELIVERED = -1,
++};
++
++enum exec_status {
++ SAM_GOOD = 0,
++ SAM_CHECK_COND = 2,
++ SAM_COND_MET = 4,
++ SAM_BUSY = 8,
++ SAM_INTERMEDIATE = 0x10,
++ SAM_IM_COND_MET = 0x12,
++ SAM_RESV_CONFLICT= 0x14,
++ SAM_TASK_SET_FULL= 0x28,
++ SAM_ACA_ACTIVE = 0x30,
++ SAM_TASK_ABORTED = 0x40,
++
++ SAS_DEV_NO_RESPONSE = 0x80,
++ SAS_DATA_UNDERRUN,
++ SAS_DATA_OVERRUN,
++ SAS_INTERRUPTED,
++ SAS_QUEUE_FULL,
++ SAS_DEVICE_UNKNOWN,
++ SAS_SG_ERR,
++ SAS_OPEN_REJECT,
++ SAS_OPEN_TO,
++ SAS_PROTO_RESPONSE,
++ SAS_PHY_DOWN,
++ SAS_NAK_R_ERR,
++ SAS_PENDING,
++ SAS_ABORTED_TASK,
++};
++
++/* When a task finishes with a response, the LLDD examines the
++ * response:
++ * - For an ATA task task_status_struct::stat is set to
++ * SAS_PROTO_RESPONSE, and the task_status_struct::buf is set to the
++ * contents of struct ata_task_resp.
++ * - For SSP tasks, if no data is present or status/TMF response
++ * is valid, task_status_struct::stat is set. If data is present
++ * (SENSE data), the LLDD copies up to SAS_STATUS_BUF_SIZE, sets
++ * task_status_struct::buf_valid_size, and task_status_struct::stat is
++ * set to SAM_CHECK_COND.
++ *
++ * "buf" has format SCSI Sense for SSP task, or struct ata_task_resp
++ * for ATA task.
++ *
++ * "frame_len" is the total frame length, which could be more or less
++ * than actually copied.
++ *
++ * Tasks ending with response, always set the residual field.
++ */
++struct ata_task_resp {
++ u16 frame_len;
++ u8 ending_fis[24]; /* dev to host or data-in */
++ u32 sstatus;
++ u32 serror;
++ u32 scontrol;
++ u32 sactive;
++};
++
++#define SAS_STATUS_BUF_SIZE 96
++
++struct task_status_struct {
++ enum service_response resp;
++ enum exec_status stat;
++ int buf_valid_size;
++
++ u8 buf[SAS_STATUS_BUF_SIZE];
++
++ u32 residual;
++ enum sas_open_rej_reason open_rej_reason;
++};
++
++/* ATA and ATAPI task queuable to a SAS LLDD.
++ */
++struct sas_ata_task {
++ struct host_to_dev_fis fis;
++ u8 atapi_packet[16]; /* 0 if not ATAPI task */
++
++ u8 retry_count; /* hardware retry, should be > 0 */
++
++ u8 dma_xfer:1; /* PIO:0 or DMA:1 */
++ u8 use_ncq:1;
++ u8 set_affil_pol:1;
++ u8 stp_affil_pol:1;
++
++ u8 device_control_reg_update:1;
++};
++
++struct sas_smp_task {
++ struct scatterlist smp_req;
++ struct scatterlist smp_resp;
++};
++
++enum task_attribute {
++ TASK_ATTR_SIMPLE = 0,
++ TASK_ATTR_HOQ = 1,
++ TASK_ATTR_ORDERED= 2,
++ TASK_ATTR_ACA = 4,
++};
++
++struct sas_ssp_task {
++ u8 retry_count; /* hardware retry, should be > 0 */
++
++ u8 LUN[8];
++ u8 enable_first_burst:1;
++ enum task_attribute task_attr;
++ u8 task_prio;
++ u8 cdb[16];
++};
++
++struct sas_task {
++ struct domain_device *dev;
++ struct list_head list;
++
++ spinlock_t task_state_lock;
++ unsigned task_state_flags;
++
++ enum sas_proto task_proto;
++
++ /* Used by the discovery code. */
++ struct timer_list timer;
++ struct completion completion;
++
++ union {
++ struct sas_ata_task ata_task;
++ struct sas_smp_task smp_task;
++ struct sas_ssp_task ssp_task;
++ };
++
++ struct scatterlist *scatter;
++ int num_scatter;
++ u32 total_xfer_len;
++ u8 data_dir:2; /* Use PCI_DMA_... */
++
++ struct task_status_struct task_status;
++ void (*task_done)(struct sas_task *);
++
++ void *lldd_task; /* for use by LLDDs */
++ void *uldd_task;
++};
++
++
++
++#define SAS_TASK_STATE_PENDING 1
++#define SAS_TASK_STATE_DONE 2
++#define SAS_TASK_STATE_ABORTED 4
++
++static inline struct sas_task *sas_alloc_task(gfp_t flags)
++{
++ extern kmem_cache_t *sas_task_cache;
++ struct sas_task *task = kmem_cache_alloc(sas_task_cache, flags);
++
++ if (task) {
++ memset(task, 0, sizeof(*task));
++ INIT_LIST_HEAD(&task->list);
++ spin_lock_init(&task->task_state_lock);
++ task->task_state_flags = SAS_TASK_STATE_PENDING;
++ init_timer(&task->timer);
++ init_completion(&task->completion);
++ }
++
++ return task;
++}
++
++static inline void sas_free_task(struct sas_task *task)
++{
++ if (task) {
++ extern kmem_cache_t *sas_task_cache;
++ BUG_ON(!list_empty(&task->list));
++ kmem_cache_free(sas_task_cache, task);
++ }
++}
++
++struct sas_domain_function_template {
++ /* The class calls these to notify the LLDD of an event. */
++ void (*lldd_port_formed)(struct asd_sas_phy *);
++ void (*lldd_port_deformed)(struct asd_sas_phy *);
++
++ /* The class calls these when a device is found or gone. */
++ int (*lldd_dev_found)(struct domain_device *);
++ void (*lldd_dev_gone)(struct domain_device *);
++
++ int (*lldd_execute_task)(struct sas_task *, int num,
++ gfp_t gfp_flags);
++
++ /* Task Management Functions. Must be called from process context. */
++ int (*lldd_abort_task)(struct sas_task *);
++ int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
++ int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
++ int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
++ int (*lldd_I_T_nexus_reset)(struct domain_device *);
++ int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
++ int (*lldd_query_task)(struct sas_task *);
++
++ /* Port and Adapter management */
++ int (*lldd_clear_nexus_port)(struct asd_sas_port *);
++ int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
++
++ /* Phy management */
++ int (*lldd_control_phy)(struct asd_sas_phy *, enum phy_func, void *);
++};
++
++extern int sas_register_ha(struct sas_ha_struct *);
++extern int sas_unregister_ha(struct sas_ha_struct *);
++
++extern int sas_queuecommand(struct scsi_cmnd *,
++ void (*scsi_done)(struct scsi_cmnd *));
++extern int sas_target_alloc(struct scsi_target *);
++extern int sas_slave_alloc(struct scsi_device *);
++extern int sas_slave_configure(struct scsi_device *);
++extern void sas_slave_destroy(struct scsi_device *);
++extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
++extern int sas_change_queue_type(struct scsi_device *, int qt);
++extern int sas_bios_param(struct scsi_device *,
++ struct block_device *,
++ sector_t capacity, int *hsc);
++extern struct scsi_transport_template *
++sas_domain_attach_transport(struct sas_domain_function_template *);
++extern void sas_domain_release_transport(struct scsi_transport_template *);
++
++int sas_discover_root_expander(struct domain_device *);
++
++void sas_init_ex_attr(void);
++
++int sas_ex_revalidate_domain(struct domain_device *);
++
++void sas_unregister_domain_devices(struct asd_sas_port *port);
++void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *);
++int sas_discover_event(struct asd_sas_port *, enum discover_event ev);
++
++int sas_discover_sata(struct domain_device *);
++int sas_discover_end_dev(struct domain_device *);
++
++void sas_unregister_dev(struct domain_device *);
++
++void sas_init_dev(struct domain_device *);
++
++#endif /* _SASLIB_H_ */
+diff --git a/include/scsi/sas.h b/include/scsi/sas.h
+new file mode 100644
+index 0000000..2f4b6af
+--- /dev/null
++++ b/include/scsi/sas.h
+@@ -0,0 +1,631 @@
++/*
++ * SAS structures and definitions header file
++ *
++ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
++ * Copyright (C) 2005 Luben Tuikov <luben_tuikov at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * 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 _SAS_H_
++#define _SAS_H_
++
++#include <linux/types.h>
++#include <asm/byteorder.h>
++
++#define SAS_ADDR_SIZE 8
++#define HASHED_SAS_ADDR_SIZE 3
++#define SAS_ADDR(_sa) ((unsigned long long) be64_to_cpu(*(__be64 *)(_sa)))
++
++#define SMP_REQUEST 0x40
++#define SMP_RESPONSE 0x41
++
++#define SSP_DATA 0x01
++#define SSP_XFER_RDY 0x05
++#define SSP_COMMAND 0x06
++#define SSP_RESPONSE 0x07
++#define SSP_TASK 0x16
++
++#define SMP_REPORT_GENERAL 0x00
++#define SMP_REPORT_MANUF_INFO 0x01
++#define SMP_READ_GPIO_REG 0x02
++#define SMP_DISCOVER 0x10
++#define SMP_REPORT_PHY_ERR_LOG 0x11
++#define SMP_REPORT_PHY_SATA 0x12
++#define SMP_REPORT_ROUTE_INFO 0x13
++#define SMP_WRITE_GPIO_REG 0x82
++#define SMP_CONF_ROUTE_INFO 0x90
++#define SMP_PHY_CONTROL 0x91
++#define SMP_PHY_TEST_FUNCTION 0x92
++
++#define SMP_RESP_FUNC_ACC 0x00
++#define SMP_RESP_FUNC_UNK 0x01
++#define SMP_RESP_FUNC_FAILED 0x02
++#define SMP_RESP_INV_FRM_LEN 0x03
++#define SMP_RESP_NO_PHY 0x10
++#define SMP_RESP_NO_INDEX 0x11
++#define SMP_RESP_PHY_NO_SATA 0x12
++#define SMP_RESP_PHY_UNK_OP 0x13
++#define SMP_RESP_PHY_UNK_TESTF 0x14
++#define SMP_RESP_PHY_TEST_INPROG 0x15
++#define SMP_RESP_PHY_VACANT 0x16
++
++/* SAM TMFs */
++#define TMF_ABORT_TASK 0x01
++#define TMF_ABORT_TASK_SET 0x02
++#define TMF_CLEAR_TASK_SET 0x04
++#define TMF_LU_RESET 0x08
++#define TMF_CLEAR_ACA 0x40
++#define TMF_QUERY_TASK 0x80
++
++/* SAS TMF responses */
++#define TMF_RESP_FUNC_COMPLETE 0x00
++#define TMF_RESP_INVALID_FRAME 0x02
++#define TMF_RESP_FUNC_ESUPP 0x04
++#define TMF_RESP_FUNC_FAILED 0x05
++#define TMF_RESP_FUNC_SUCC 0x08
++#define TMF_RESP_NO_LUN 0x09
++#define TMF_RESP_OVERLAPPED_TAG 0x0A
++
++enum sas_oob_mode {
++ OOB_NOT_CONNECTED,
++ SATA_OOB_MODE,
++ SAS_OOB_MODE
++};
++
++/* See sas_discover.c if you plan on changing these.
++ */
++enum sas_dev_type {
++ NO_DEVICE = 0, /* protocol */
++ SAS_END_DEV = 1, /* protocol */
++ EDGE_DEV = 2, /* protocol */
++ FANOUT_DEV = 3, /* protocol */
++ SAS_HA = 4,
++ SATA_DEV = 5,
++ SATA_PM = 7,
++ SATA_PM_PORT= 8,
++};
++
++/* Partly from IDENTIFY address frame. */
++enum sas_proto {
++ SATA_PROTO = 1,
++ SAS_PROTO_SMP = 2, /* protocol */
++ SAS_PROTO_STP = 4, /* protocol */
++ SAS_PROTO_SSP = 8, /* protocol */
++ SAS_PROTO_ALL = 0xE,
++};
++
++/* From the spec; local phys only */
++enum phy_func {
++ PHY_FUNC_NOP,
++ PHY_FUNC_LINK_RESET, /* Enables the phy */
++ PHY_FUNC_HARD_RESET,
++ PHY_FUNC_DISABLE,
++ PHY_FUNC_CLEAR_ERROR_LOG = 5,
++ PHY_FUNC_CLEAR_AFFIL,
++ PHY_FUNC_TX_SATA_PS_SIGNAL,
++ PHY_FUNC_RELEASE_SPINUP_HOLD = 0x10, /* LOCAL PORT ONLY! */
++ PHY_FUNC_SET_LINK_RATE,
++};
++
++/* SAS LLDD would need to report only _very_few_ of those, like BROADCAST.
++ * Most of those are here for completeness.
++ */
++enum sas_prim {
++ SAS_PRIM_AIP_NORMAL = 1,
++ SAS_PRIM_AIP_R0 = 2,
++ SAS_PRIM_AIP_R1 = 3,
++ SAS_PRIM_AIP_R2 = 4,
++ SAS_PRIM_AIP_WC = 5,
++ SAS_PRIM_AIP_WD = 6,
++ SAS_PRIM_AIP_WP = 7,
++ SAS_PRIM_AIP_RWP = 8,
++
++ SAS_PRIM_BC_CH = 9,
++ SAS_PRIM_BC_RCH0 = 10,
++ SAS_PRIM_BC_RCH1 = 11,
++ SAS_PRIM_BC_R0 = 12,
++ SAS_PRIM_BC_R1 = 13,
++ SAS_PRIM_BC_R2 = 14,
++ SAS_PRIM_BC_R3 = 15,
++ SAS_PRIM_BC_R4 = 16,
++
++ SAS_PRIM_NOTIFY_ENSP= 17,
++ SAS_PRIM_NOTIFY_R0 = 18,
++ SAS_PRIM_NOTIFY_R1 = 19,
++ SAS_PRIM_NOTIFY_R2 = 20,
++
++ SAS_PRIM_CLOSE_CLAF = 21,
++ SAS_PRIM_CLOSE_NORM = 22,
++ SAS_PRIM_CLOSE_R0 = 23,
++ SAS_PRIM_CLOSE_R1 = 24,
++
++ SAS_PRIM_OPEN_RTRY = 25,
++ SAS_PRIM_OPEN_RJCT = 26,
++ SAS_PRIM_OPEN_ACPT = 27,
++
++ SAS_PRIM_DONE = 28,
++ SAS_PRIM_BREAK = 29,
++
++ SATA_PRIM_DMAT = 33,
++ SATA_PRIM_PMNAK = 34,
++ SATA_PRIM_PMACK = 35,
++ SATA_PRIM_PMREQ_S = 36,
++ SATA_PRIM_PMREQ_P = 37,
++ SATA_SATA_R_ERR = 38,
++};
++
++enum sas_open_rej_reason {
++ /* Abandon open */
++ SAS_OREJ_UNKNOWN = 0,
++ SAS_OREJ_BAD_DEST = 1,
++ SAS_OREJ_CONN_RATE = 2,
++ SAS_OREJ_EPROTO = 3,
++ SAS_OREJ_RESV_AB0 = 4,
++ SAS_OREJ_RESV_AB1 = 5,
++ SAS_OREJ_RESV_AB2 = 6,
++ SAS_OREJ_RESV_AB3 = 7,
++ SAS_OREJ_WRONG_DEST= 8,
++ SAS_OREJ_STP_NORES = 9,
++
++ /* Retry open */
++ SAS_OREJ_NO_DEST = 10,
++ SAS_OREJ_PATH_BLOCKED = 11,
++ SAS_OREJ_RSVD_CONT0 = 12,
++ SAS_OREJ_RSVD_CONT1 = 13,
++ SAS_OREJ_RSVD_INIT0 = 14,
++ SAS_OREJ_RSVD_INIT1 = 15,
++ SAS_OREJ_RSVD_STOP0 = 16,
++ SAS_OREJ_RSVD_STOP1 = 17,
++ SAS_OREJ_RSVD_RETRY = 18,
++};
++
++struct dev_to_host_fis {
++ u8 fis_type; /* 0x34 */
++ u8 flags;
++ u8 status;
++ u8 error;
++
++ u8 lbal;
++ union { u8 lbam; u8 byte_count_low; };
++ union { u8 lbah; u8 byte_count_high; };
++ u8 device;
++
++ u8 lbal_exp;
++ u8 lbam_exp;
++ u8 lbah_exp;
++ u8 _r_a;
++
++ union { u8 sector_count; u8 interrupt_reason; };
++ u8 sector_count_exp;
++ u8 _r_b;
++ u8 _r_c;
++
++ u32 _r_d;
++} __attribute__ ((packed));
++
++struct host_to_dev_fis {
++ u8 fis_type; /* 0x27 */
++ u8 flags;
++ u8 command;
++ u8 features;
++
++ u8 lbal;
++ union { u8 lbam; u8 byte_count_low; };
++ union { u8 lbah; u8 byte_count_high; };
++ u8 device;
++
++ u8 lbal_exp;
++ u8 lbam_exp;
++ u8 lbah_exp;
++ u8 features_exp;
++
++ union { u8 sector_count; u8 interrupt_reason; };
++ u8 sector_count_exp;
++ u8 _r_a;
++ u8 control;
++
++ u32 _r_b;
++} __attribute__ ((packed));
++
++/* Prefer to have code clarity over header file clarity.
++ */
++#ifdef __LITTLE_ENDIAN_BITFIELD
++struct sas_identify_frame {
++ /* Byte 0 */
++ u8 frame_type:4;
++ u8 dev_type:3;
++ u8 _un0:1;
++
++ /* Byte 1 */
++ u8 _un1;
++
++ /* Byte 2 */
++ union {
++ struct {
++ u8 _un20:1;
++ u8 smp_iport:1;
++ u8 stp_iport:1;
++ u8 ssp_iport:1;
++ u8 _un247:4;
++ };
++ u8 initiator_bits;
++ };
++
++ /* Byte 3 */
++ union {
++ struct {
++ u8 _un30:1;
++ u8 smp_tport:1;
++ u8 stp_tport:1;
++ u8 ssp_tport:1;
++ u8 _un347:4;
++ };
++ u8 target_bits;
++ };
++
++ /* Byte 4 - 11 */
++ u8 _un4_11[8];
++
++ /* Byte 12 - 19 */
++ u8 sas_addr[SAS_ADDR_SIZE];
++
++ /* Byte 20 */
++ u8 phy_id;
++
++ u8 _un21_27[7];
++
++ __be32 crc;
++} __attribute__ ((packed));
++
++struct ssp_frame_hdr {
++ u8 frame_type;
++ u8 hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
++ u8 _r_a;
++ u8 hashed_src_addr[HASHED_SAS_ADDR_SIZE];
++ __be16 _r_b;
++
++ u8 changing_data_ptr:1;
++ u8 retransmit:1;
++ u8 retry_data_frames:1;
++ u8 _r_c:5;
++
++ u8 num_fill_bytes:2;
++ u8 _r_d:6;
++
++ u32 _r_e;
++ __be16 tag;
++ __be16 tptt;
++ __be32 data_offs;
++} __attribute__ ((packed));
++
++struct ssp_response_iu {
++ u8 _r_a[10];
++
++ u8 datapres:2;
++ u8 _r_b:6;
++
++ u8 status;
++
++ u32 _r_c;
++
++ __be32 sense_data_len;
++ __be32 response_data_len;
++
++ u8 resp_data[0];
++ u8 sense_data[0];
++} __attribute__ ((packed));
++
++/* ---------- SMP ---------- */
++
++struct report_general_resp {
++ __be16 change_count;
++ __be16 route_indexes;
++ u8 _r_a;
++ u8 num_phys;
++
++ u8 conf_route_table:1;
++ u8 configuring:1;
++ u8 _r_b:6;
++
++ u8 _r_c;
++
++ u8 enclosure_logical_id[8];
++
++ u8 _r_d[12];
++} __attribute__ ((packed));
++
++struct discover_resp {
++ u8 _r_a[5];
++
++ u8 phy_id;
++ __be16 _r_b;
++
++ u8 _r_c:4;
++ u8 attached_dev_type:3;
++ u8 _r_d:1;
++
++ u8 linkrate:4;
++ u8 _r_e:4;
++
++ u8 attached_sata_host:1;
++ u8 iproto:3;
++ u8 _r_f:4;
++
++ u8 attached_sata_dev:1;
++ u8 tproto:3;
++ u8 _r_g:3;
++ u8 attached_sata_ps:1;
++
++ u8 sas_addr[8];
++ u8 attached_sas_addr[8];
++ u8 attached_phy_id;
++
++ u8 _r_h[7];
++
++ u8 hmin_linkrate:4;
++ u8 pmin_linkrate:4;
++ u8 hmax_linkrate:4;
++ u8 pmax_linkrate:4;
++
++ u8 change_count;
++
++ u8 pptv:4;
++ u8 _r_i:3;
++ u8 virtual:1;
++
++ u8 routing_attr:4;
++ u8 _r_j:4;
++
++ u8 conn_type;
++ u8 conn_el_index;
++ u8 conn_phy_link;
++
++ u8 _r_k[8];
++} __attribute__ ((packed));
++
++struct report_phy_sata_resp {
++ u8 _r_a[5];
++
++ u8 phy_id;
++ u8 _r_b;
++
++ u8 affil_valid:1;
++ u8 affil_supp:1;
++ u8 _r_c:6;
++
++ u32 _r_d;
++
++ u8 stp_sas_addr[8];
++
++ struct dev_to_host_fis fis;
++
++ u32 _r_e;
++
++ u8 affil_stp_ini_addr[8];
++
++ __be32 crc;
++} __attribute__ ((packed));
++
++struct smp_resp {
++ u8 frame_type;
++ u8 function;
++ u8 result;
++ u8 reserved;
++ union {
++ struct report_general_resp rg;
++ struct discover_resp disc;
++ struct report_phy_sata_resp rps;
++ };
++} __attribute__ ((packed));
++
++#elif defined(__BIG_ENDIAN_BITFIELD)
++struct sas_identify_frame {
++ /* Byte 0 */
++ u8 _un0:1;
++ u8 dev_type:3;
++ u8 frame_type:4;
++
++ /* Byte 1 */
++ u8 _un1;
++
++ /* Byte 2 */
++ union {
++ struct {
++ u8 _un247:4;
++ u8 ssp_iport:1;
++ u8 stp_iport:1;
++ u8 smp_iport:1;
++ u8 _un20:1;
++ };
++ u8 initiator_bits;
++ };
++
++ /* Byte 3 */
++ union {
++ struct {
++ u8 _un347:4;
++ u8 ssp_tport:1;
++ u8 stp_tport:1;
++ u8 smp_tport:1;
++ u8 _un30:1;
++ };
++ u8 target_bits;
++ };
++
++ /* Byte 4 - 11 */
++ u8 _un4_11[8];
++
++ /* Byte 12 - 19 */
++ u8 sas_addr[SAS_ADDR_SIZE];
++
++ /* Byte 20 */
++ u8 phy_id;
++
++ u8 _un21_27[7];
++
++ __be32 crc;
++} __attribute__ ((packed));
++
++struct ssp_frame_hdr {
++ u8 frame_type;
++ u8 hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
++ u8 _r_a;
++ u8 hashed_src_addr[HASHED_SAS_ADDR_SIZE];
++ __be16 _r_b;
++
++ u8 _r_c:5;
++ u8 retry_data_frames:1;
++ u8 retransmit:1;
++ u8 changing_data_ptr:1;
++
++ u8 _r_d:6;
++ u8 num_fill_bytes:2;
++
++ u32 _r_e;
++ __be16 tag;
++ __be16 tptt;
++ __be32 data_offs;
++} __attribute__ ((packed));
++
++struct ssp_response_iu {
++ u8 _r_a[10];
++
++ u8 _r_b:6;
++ u8 datapres:2;
++
++ u8 status;
++
++ u32 _r_c;
++
++ __be32 sense_data_len;
++ __be32 response_data_len;
++
++ u8 resp_data[0];
++ u8 sense_data[0];
++} __attribute__ ((packed));
++
++/* ---------- SMP ---------- */
++
++struct report_general_resp {
++ __be16 change_count;
++ __be16 route_indexes;
++ u8 _r_a;
++ u8 num_phys;
++
++ u8 _r_b:6;
++ u8 configuring:1;
++ u8 conf_route_table:1;
++
++ u8 _r_c;
++
++ u8 enclosure_logical_id[8];
++
++ u8 _r_d[12];
++} __attribute__ ((packed));
++
++struct discover_resp {
++ u8 _r_a[5];
++
++ u8 phy_id;
++ __be16 _r_b;
++
++ u8 _r_d:1;
++ u8 attached_dev_type:3;
++ u8 _r_c:4;
++
++ u8 _r_e:4;
++ u8 linkrate:4;
++
++ u8 _r_f:4;
++ u8 iproto:3;
++ u8 attached_sata_host:1;
++
++ u8 attached_sata_ps:1;
++ u8 _r_g:3;
++ u8 tproto:3;
++ u8 attached_sata_dev:1;
++
++ u8 sas_addr[8];
++ u8 attached_sas_addr[8];
++ u8 attached_phy_id;
++
++ u8 _r_h[7];
++
++ u8 pmin_linkrate:4;
++ u8 hmin_linkrate:4;
++ u8 pmax_linkrate:4;
++ u8 hmax_linkrate:4;
++
++ u8 change_count;
++
++ u8 virtual:1;
++ u8 _r_i:3;
++ u8 pptv:4;
++
++ u8 _r_j:4;
++ u8 routing_attr:4;
++
++ u8 conn_type;
++ u8 conn_el_index;
++ u8 conn_phy_link;
++
++ u8 _r_k[8];
++} __attribute__ ((packed));
++
++struct report_phy_sata_resp {
++ u8 _r_a[5];
++
++ u8 phy_id;
++ u8 _r_b;
++
++ u8 _r_c:6;
++ u8 affil_supp:1;
++ u8 affil_valid:1;
++
++ u32 _r_d;
++
++ u8 stp_sas_addr[8];
++
++ struct dev_to_host_fis fis;
++
++ u32 _r_e;
++
++ u8 affil_stp_ini_addr[8];
++
++ __be32 crc;
++} __attribute__ ((packed));
++
++struct smp_resp {
++ u8 frame_type;
++ u8 function;
++ u8 result;
++ u8 reserved;
++ union {
++ struct report_general_resp rg;
++ struct discover_resp disc;
++ struct report_phy_sata_resp rps;
++ };
++} __attribute__ ((packed));
++
++#else
++#error "Bitfield order not defined!"
++#endif
++
++#endif /* _SAS_H_ */
+diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
+index c60b8ff..5c0e979 100644
+--- a/include/scsi/scsi.h
++++ b/include/scsi/scsi.h
+@@ -25,13 +25,6 @@ extern const unsigned char scsi_command_
+ #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
+
+ /*
+- * SCSI device types
+- */
+-
+-#define MAX_SCSI_DEVICE_CODE 15
+-extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+-
+-/*
+ * Special value for scanning to specify scanning or rescanning of all
+ * possible channels, (target) ids, or luns on a given shost.
+ */
+@@ -104,6 +97,7 @@ extern const char *const scsi_device_typ
+ #define PERSISTENT_RESERVE_IN 0x5e
+ #define PERSISTENT_RESERVE_OUT 0x5f
+ #define REPORT_LUNS 0xa0
++#define MAINTENANCE_IN 0xa3
+ #define MOVE_MEDIUM 0xa5
+ #define EXCHANGE_MEDIUM 0xa6
+ #define READ_12 0xa8
+@@ -121,6 +115,8 @@ extern const char *const scsi_device_typ
+ #define SERVICE_ACTION_IN 0x9e
+ /* values for service action in */
+ #define SAI_READ_CAPACITY_16 0x10
++/* values for maintenance in */
++#define MI_REPORT_TARGET_PGS 0x0a
+
+ /* Values for T10/04-262r7 */
+ #define ATA_16 0x85 /* 16-byte pass-thru */
+@@ -225,6 +221,9 @@ static inline int scsi_status_is_good(in
+ #define TYPE_RBC 0x0e
+ #define TYPE_NO_LUN 0x7f
+
++/* Returns a human-readable name for the device */
++extern const char * scsi_device_type(unsigned type);
++
+ /*
+ * standard mode-select header prepended to all mode-select commands
+ */
+@@ -433,4 +432,10 @@ struct scsi_lun {
+ /* Used to obtain the PCI location of a device */
+ #define SCSI_IOCTL_GET_PCI 0x5387
+
++/* Pull a u32 out of a SCSI message (using BE SCSI conventions) */
++static inline __u32 scsi_to_u32(__u8 *ptr)
++{
++ return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3];
++}
++
+ #endif /* _SCSI_SCSI_H */
+diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
+index 58e6444..be117f8 100644
+--- a/include/scsi/scsi_cmnd.h
++++ b/include/scsi/scsi_cmnd.h
+@@ -118,20 +118,6 @@ struct scsi_cmnd {
+ unsigned long pid; /* Process ID, starts at 0. Unique per host. */
+ };
+
+-/*
+- * These are the values that scsi_cmd->state can take.
+- */
+-#define SCSI_STATE_TIMEOUT 0x1000
+-#define SCSI_STATE_FINISHED 0x1001
+-#define SCSI_STATE_FAILED 0x1002
+-#define SCSI_STATE_QUEUED 0x1003
+-#define SCSI_STATE_UNUSED 0x1006
+-#define SCSI_STATE_DISCONNECTING 0x1008
+-#define SCSI_STATE_INITIALIZING 0x1009
+-#define SCSI_STATE_BHQUEUE 0x100a
+-#define SCSI_STATE_MLQUEUE 0x100b
+-
+-
+ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
+ extern void scsi_put_command(struct scsi_cmnd *);
+ extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
+diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
+index 895d212..b401c82 100644
+--- a/include/scsi/scsi_device.h
++++ b/include/scsi/scsi_device.h
+@@ -298,9 +298,9 @@ extern int scsi_execute_async(struct scs
+ void (*done)(void *, char *, int, int),
+ gfp_t gfp);
+
+-static inline void scsi_device_reprobe(struct scsi_device *sdev)
++static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
+ {
+- device_reprobe(&sdev->sdev_gendev);
++ return device_reprobe(&sdev->sdev_gendev);
+ }
+
+ static inline unsigned int sdev_channel(struct scsi_device *sdev)
+diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
+index b3dd90f..39c6f8c 100644
+--- a/include/scsi/scsi_host.h
++++ b/include/scsi/scsi_host.h
+@@ -16,6 +16,7 @@ struct scsi_target;
+ struct Scsi_Host;
+ struct scsi_host_cmd_pool;
+ struct scsi_transport_template;
++struct blk_queue_tags;
+
+
+ /*
+@@ -466,6 +467,12 @@ struct Scsi_Host {
+ struct scsi_transport_template *transportt;
+
+ /*
++ * area to keep a shared tag map (if needed, will be
++ * NULL if not)
++ */
++ struct blk_queue_tag *bqt;
++
++ /*
+ * The following two fields are protected with host_lock;
+ * however, eh routines can safely access during eh processing
+ * without acquiring the lock.
+diff --git a/include/scsi/scsi_netlink.h b/include/scsi/scsi_netlink.h
+new file mode 100644
+index 0000000..8c1470c
+--- /dev/null
++++ b/include/scsi/scsi_netlink.h
+@@ -0,0 +1,87 @@
++/*
++ * SCSI Transport Netlink Interface
++ * Used for the posting of outbound SCSI transport events
++ *
++ * Copyright (C) 2006 James Smart, Emulex Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#ifndef SCSI_NETLINK_H
++#define SCSI_NETLINK_H
++
++/*
++ * This file intended to be included by both kernel and user space
++ */
++
++/* Single Netlink Message type to send all SCSI Transport messages */
++#define SCSI_TRANSPORT_MSG NLMSG_MIN_TYPE + 1
++
++/* SCSI Transport Broadcast Groups */
++ /* leaving groups 0 and 1 unassigned */
++#define SCSI_NL_GRP_FC_EVENTS (1<<2) /* Group 2 */
++#define SCSI_NL_GRP_CNT 3
++
++
++/* SCSI_TRANSPORT_MSG event message header */
++struct scsi_nl_hdr {
++ uint8_t version;
++ uint8_t transport;
++ uint16_t magic;
++ uint16_t msgtype;
++ uint16_t msglen;
++} __attribute__((aligned(sizeof(uint64_t))));
++
++/* scsi_nl_hdr->version value */
++#define SCSI_NL_VERSION 1
++
++/* scsi_nl_hdr->magic value */
++#define SCSI_NL_MAGIC 0xA1B2
++
++/* scsi_nl_hdr->transport value */
++#define SCSI_NL_TRANSPORT 0
++#define SCSI_NL_TRANSPORT_FC 1
++#define SCSI_NL_MAX_TRANSPORTS 2
++
++/* scsi_nl_hdr->msgtype values are defined in each transport */
++
++
++/*
++ * Vendor ID:
++ * If transports post vendor-unique events, they must pass a well-known
++ * 32-bit vendor identifier. This identifier consists of 8 bits indicating
++ * the "type" of identifier contained, and 24 bits of id data.
++ *
++ * Identifiers for each type:
++ * PCI : ID data is the 16 bit PCI Registered Vendor ID
++ */
++#define SCSI_NL_VID_TYPE_SHIFT 56
++#define SCSI_NL_VID_TYPE_MASK ((u64)0xFF << SCSI_NL_VID_TYPE_SHIFT)
++#define SCSI_NL_VID_TYPE_PCI ((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT)
++#define SCSI_NL_VID_ID_MASK (~ SCSI_NL_VID_TYPE_MASK)
++
++
++#define INIT_SCSI_NL_HDR(hdr, t, mtype, mlen) \
++ { \
++ (hdr)->version = SCSI_NL_VERSION; \
++ (hdr)->transport = t; \
++ (hdr)->magic = SCSI_NL_MAGIC; \
++ (hdr)->msgtype = mtype; \
++ (hdr)->msglen = mlen; \
++ }
++
++
++#endif /* SCSI_NETLINK_H */
++
+diff --git a/include/scsi/scsi_netlink_fc.h b/include/scsi/scsi_netlink_fc.h
+new file mode 100644
+index 0000000..cbf76e4
+--- /dev/null
++++ b/include/scsi/scsi_netlink_fc.h
+@@ -0,0 +1,71 @@
++/*
++ * FC Transport Netlink Interface
++ *
++ * Copyright (C) 2006 James Smart, Emulex Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#ifndef SCSI_NETLINK_FC_H
++#define SCSI_NETLINK_FC_H
++
++#include <scsi/scsi_netlink.h>
++
++/*
++ * This file intended to be included by both kernel and user space
++ */
++
++/*
++ * FC Transport Message Types
++ */
++ /* kernel -> user */
++#define FC_NL_ASYNC_EVENT 0x0100
++ /* user -> kernel */
++/* none */
++
++
++/*
++ * Message Structures :
++ */
++
++/* macro to round up message lengths to 8byte boundary */
++#define FC_NL_MSGALIGN(len) (((len) + 7) & ~7)
++
++
++/*
++ * FC Transport Broadcast Event Message :
++ * FC_NL_ASYNC_EVENT
++ *
++ * Note: if Vendor Unique message, &event_data will be start of
++ * vendor unique payload, and the length of the payload is
++ * per event_datalen
++ *
++ * Note: When specifying vendor_id, be sure to read the Vendor Type and ID
++ * formatting requirements specified in scsi_netlink.h
++ */
++struct fc_nl_event {
++ struct scsi_nl_hdr snlh; /* must be 1st element ! */
++ uint64_t seconds;
++ uint64_t vendor_id;
++ uint16_t host_no;
++ uint16_t event_datalen;
++ uint32_t event_num;
++ uint32_t event_code;
++ uint32_t event_data;
++} __attribute__((aligned(sizeof(uint64_t))));
++
++
++#endif /* SCSI_NETLINK_FC_H */
++
+diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
+index e47e36a..cf4c219 100644
+--- a/include/scsi/scsi_tcq.h
++++ b/include/scsi/scsi_tcq.h
+@@ -4,7 +4,7 @@
+ #include <linux/blkdev.h>
+ #include <scsi/scsi_cmnd.h>
+ #include <scsi/scsi_device.h>
+-
++#include <scsi/scsi_host.h>
+
+ #define MSG_SIMPLE_TAG 0x20
+ #define MSG_HEAD_TAG 0x21
+@@ -13,6 +13,7 @@
+ #define SCSI_NO_TAG (-1) /* identify no tag in use */
+
+
++#ifdef CONFIG_BLOCK
+
+ /**
+ * scsi_get_tag_type - get the type of tag the device supports
+@@ -66,7 +67,8 @@ static inline void scsi_activate_tcq(str
+ return;
+
+ if (!blk_queue_tagged(sdev->request_queue))
+- blk_queue_init_tags(sdev->request_queue, depth, NULL);
++ blk_queue_init_tags(sdev->request_queue, depth,
++ sdev->host->bqt);
+
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ }
+@@ -98,7 +100,7 @@ static inline int scsi_populate_tag_msg(
+ struct scsi_device *sdev = cmd->device;
+
+ if (blk_rq_tagged(req)) {
+- if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER)
++ if (sdev->ordered_tags && req->cmd_flags & REQ_HARDBARRIER)
+ *msg++ = MSG_ORDERED_TAG;
+ else
+ *msg++ = MSG_SIMPLE_TAG;
+@@ -131,4 +133,36 @@ static inline struct scsi_cmnd *scsi_fin
+ return sdev->current_cmnd;
+ }
+
++/**
++ * scsi_init_shared_tag_map - create a shared tag map
++ * @shost: the host to share the tag map among all devices
++ * @depth: the total depth of the map
++ */
++static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
++{
++ shost->bqt = blk_init_tags(depth);
++ return shost->bqt ? 0 : -ENOMEM;
++}
++
++/**
++ * scsi_host_find_tag - find the tagged command by host
++ * @shost: pointer to scsi_host
++ * @tag: tag of the scsi_cmnd
++ *
++ * Notes:
++ * Only works with tags allocated by the generic blk layer.
++ **/
++static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
++ int tag)
++{
++ struct request *req;
++
++ if (tag != SCSI_NO_TAG) {
++ req = blk_map_queue_find_tag(shost->bqt, tag);
++ return req ? (struct scsi_cmnd *)req->special : NULL;
++ }
++ return NULL;
++}
++
++#endif /* CONFIG_BLOCK */
+ #endif /* _SCSI_SCSI_TCQ_H */
+diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
+index 6d28b03..fd35232 100644
+--- a/include/scsi/scsi_transport_fc.h
++++ b/include/scsi/scsi_transport_fc.h
+@@ -29,6 +29,7 @@
+
+ #include <linux/sched.h>
+ #include <scsi/scsi.h>
++#include <scsi/scsi_netlink.h>
+
+ struct scsi_transport_template;
+
+@@ -194,6 +195,7 @@ struct fc_rport { /* aka fc_starget_attr
+ u32 roles;
+ enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */
+ u32 scsi_target_id;
++ u32 fast_io_fail_tmo;
+
+ /* exported data */
+ void *dd_data; /* Used for driver-specific storage */
+@@ -206,6 +208,7 @@ struct fc_rport { /* aka fc_starget_attr
+ struct device dev;
+ struct work_struct dev_loss_work;
+ struct work_struct scan_work;
++ struct work_struct fail_io_work;
+ struct work_struct stgt_delete_work;
+ struct work_struct rport_delete_work;
+ } __attribute__((aligned(sizeof(unsigned long))));
+@@ -284,6 +287,30 @@ struct fc_host_statistics {
+
+
+ /*
++ * FC Event Codes - Polled and Async, following FC HBAAPI v2.0 guidelines
++ */
++
++/*
++ * fc_host_event_code: If you alter this, you also need to alter
++ * scsi_transport_fc.c (for the ascii descriptions).
++ */
++enum fc_host_event_code {
++ FCH_EVT_LIP = 0x1,
++ FCH_EVT_LINKUP = 0x2,
++ FCH_EVT_LINKDOWN = 0x3,
++ FCH_EVT_LIPRESET = 0x4,
++ FCH_EVT_RSCN = 0x5,
++ FCH_EVT_ADAPTER_CHANGE = 0x103,
++ FCH_EVT_PORT_UNKNOWN = 0x200,
++ FCH_EVT_PORT_OFFLINE = 0x201,
++ FCH_EVT_PORT_ONLINE = 0x202,
++ FCH_EVT_PORT_FABRIC = 0x204,
++ FCH_EVT_LINK_UNKNOWN = 0x500,
++ FCH_EVT_VENDOR_UNIQUE = 0xffff,
++};
++
++
++/*
+ * FC Local Port (Host) Attributes
+ *
+ * Attributes are based on HBAAPI V2.0 definitions.
+@@ -312,7 +339,6 @@ struct fc_host_attrs {
+ u64 permanent_port_name;
+ u32 supported_classes;
+ u8 supported_fc4s[FC_FC4_LIST_SIZE];
+- char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
+ u32 supported_speeds;
+ u32 maxframe_size;
+ char serial_number[FC_SERIAL_NUMBER_SIZE];
+@@ -324,6 +350,8 @@ struct fc_host_attrs {
+ u8 active_fc4s[FC_FC4_LIST_SIZE];
+ u32 speed;
+ u64 fabric_name;
++ char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
++ char system_hostname[FC_SYMBOLIC_NAME_SIZE];
+
+ /* Private (Transport-managed) Attributes */
+ enum fc_tgtid_binding_type tgtid_bind_type;
+@@ -354,8 +382,6 @@ struct fc_host_attrs {
+ (((struct fc_host_attrs *)(x)->shost_data)->supported_classes)
+ #define fc_host_supported_fc4s(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->supported_fc4s)
+-#define fc_host_symbolic_name(x) \
+- (((struct fc_host_attrs *)(x)->shost_data)->symbolic_name)
+ #define fc_host_supported_speeds(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
+ #define fc_host_maxframe_size(x) \
+@@ -374,6 +400,10 @@ struct fc_host_attrs {
+ (((struct fc_host_attrs *)(x)->shost_data)->speed)
+ #define fc_host_fabric_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->fabric_name)
++#define fc_host_symbolic_name(x) \
++ (((struct fc_host_attrs *)(x)->shost_data)->symbolic_name)
++#define fc_host_system_hostname(x) \
++ (((struct fc_host_attrs *)(x)->shost_data)->system_hostname)
+ #define fc_host_tgtid_bind_type(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->tgtid_bind_type)
+ #define fc_host_rports(x) \
+@@ -409,12 +439,17 @@ struct fc_function_template {
+ void (*get_host_active_fc4s)(struct Scsi_Host *);
+ void (*get_host_speed)(struct Scsi_Host *);
+ void (*get_host_fabric_name)(struct Scsi_Host *);
++ void (*get_host_symbolic_name)(struct Scsi_Host *);
++ void (*set_host_system_hostname)(struct Scsi_Host *);
+
+ struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *);
+ void (*reset_fc_host_stats)(struct Scsi_Host *);
+
+ int (*issue_fc_host_lip)(struct Scsi_Host *);
+
++ void (*dev_loss_tmo_callbk)(struct fc_rport *);
++ void (*terminate_rport_io)(struct fc_rport *);
++
+ /* allocation lengths for host-specific data */
+ u32 dd_fcrport_size;
+
+@@ -445,7 +480,6 @@ struct fc_function_template {
+ unsigned long show_host_permanent_port_name:1;
+ unsigned long show_host_supported_classes:1;
+ unsigned long show_host_supported_fc4s:1;
+- unsigned long show_host_symbolic_name:1;
+ unsigned long show_host_supported_speeds:1;
+ unsigned long show_host_maxframe_size:1;
+ unsigned long show_host_serial_number:1;
+@@ -456,6 +490,8 @@ struct fc_function_template {
+ unsigned long show_host_active_fc4s:1;
+ unsigned long show_host_speed:1;
+ unsigned long show_host_fabric_name:1;
++ unsigned long show_host_symbolic_name:1;
++ unsigned long show_host_system_hostname:1;
+ };
+
+
+@@ -491,6 +527,25 @@ fc_remote_port_chkready(struct fc_rport
+ return result;
+ }
+
++static inline u64 wwn_to_u64(u8 *wwn)
++{
++ return (u64)wwn[0] << 56 | (u64)wwn[1] << 48 |
++ (u64)wwn[2] << 40 | (u64)wwn[3] << 32 |
++ (u64)wwn[4] << 24 | (u64)wwn[5] << 16 |
++ (u64)wwn[6] << 8 | (u64)wwn[7];
++}
++
++static inline void u64_to_wwn(u64 inm, u8 *wwn)
++{
++ wwn[0] = (inm >> 56) & 0xff;
++ wwn[1] = (inm >> 48) & 0xff;
++ wwn[2] = (inm >> 40) & 0xff;
++ wwn[3] = (inm >> 32) & 0xff;
++ wwn[4] = (inm >> 24) & 0xff;
++ wwn[5] = (inm >> 16) & 0xff;
++ wwn[6] = (inm >> 8) & 0xff;
++ wwn[7] = inm & 0xff;
++}
+
+ struct scsi_transport_template *fc_attach_transport(
+ struct fc_function_template *);
+@@ -501,13 +556,14 @@ struct fc_rport *fc_remote_port_add(stru
+ void fc_remote_port_delete(struct fc_rport *rport);
+ void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles);
+ int scsi_is_fc_rport(const struct device *);
+-
+-static inline u64 wwn_to_u64(u8 *wwn)
+-{
+- return (u64)wwn[0] << 56 | (u64)wwn[1] << 48 |
+- (u64)wwn[2] << 40 | (u64)wwn[3] << 32 |
+- (u64)wwn[4] << 24 | (u64)wwn[5] << 16 |
+- (u64)wwn[6] << 8 | (u64)wwn[7];
+-}
++u32 fc_get_event_number(void);
++void fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
++ enum fc_host_event_code event_code, u32 event_data);
++void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
++ u32 data_len, char * data_buf, u64 vendor_id);
++ /* Note: when specifying vendor_id to fc_host_post_vendor_event()
++ * be sure to read the Vendor Type and ID formatting requirements
++ * specified in scsi_netlink.h
++ */
+
+ #endif /* SCSI_TRANSPORT_FC_H */
+diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
+index 39e8332..4b95c89 100644
+--- a/include/scsi/scsi_transport_iscsi.h
++++ b/include/scsi/scsi_transport_iscsi.h
+@@ -29,7 +29,6 @@
+ struct scsi_transport_template;
+ struct iscsi_transport;
+ struct Scsi_Host;
+-struct mempool_zone;
+ struct iscsi_cls_conn;
+ struct iscsi_conn;
+ struct iscsi_cmd_task;
+@@ -157,9 +156,6 @@ struct iscsi_cls_conn {
+
+ int active; /* must be accessed with the connlock */
+ struct device dev; /* sysfs transport/container device */
+- struct mempool_zone *z_error;
+- struct mempool_zone *z_pdu;
+- struct list_head freequeue;
+ };
+
+ #define iscsi_dev_to_conn(_dev) \
+diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
+index 6cc2314..5302437 100644
+--- a/include/scsi/scsi_transport_sas.h
++++ b/include/scsi/scsi_transport_sas.h
+@@ -24,15 +24,23 @@ enum sas_protocol {
+ };
+
+ enum sas_linkrate {
+- SAS_LINK_RATE_UNKNOWN,
+- SAS_PHY_DISABLED,
+- SAS_LINK_RATE_FAILED,
+- SAS_SATA_SPINUP_HOLD,
+- SAS_SATA_PORT_SELECTOR,
+- SAS_LINK_RATE_1_5_GBPS,
+- SAS_LINK_RATE_3_0_GBPS,
+- SAS_LINK_RATE_6_0_GBPS,
+- SAS_LINK_VIRTUAL,
++ /* These Values are defined in the SAS standard */
++ SAS_LINK_RATE_UNKNOWN = 0,
++ SAS_PHY_DISABLED = 1,
++ SAS_PHY_RESET_PROBLEM = 2,
++ SAS_SATA_SPINUP_HOLD = 3,
++ SAS_SATA_PORT_SELECTOR = 4,
++ SAS_PHY_RESET_IN_PROGRESS = 5,
++ SAS_LINK_RATE_1_5_GBPS = 8,
++ SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
++ SAS_LINK_RATE_3_0_GBPS = 9,
++ SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
++ SAS_LINK_RATE_6_0_GBPS = 10,
++ /* These are virtual to the transport class and may never
++ * be signalled normally since the standard defined field
++ * is only 4 bits */
++ SAS_LINK_RATE_FAILED = 0x10,
++ SAS_PHY_VIRTUAL = 0x11,
+ };
+
+ struct sas_identify {
+@@ -57,9 +65,6 @@ struct sas_phy {
+ enum sas_linkrate maximum_linkrate_hw;
+ enum sas_linkrate maximum_linkrate;
+
+- /* internal state */
+- unsigned int local_attached : 1;
+-
+ /* link error statistics */
+ u32 invalid_dword_count;
+ u32 running_disparity_error_count;
+@@ -145,12 +150,18 @@ struct sas_port {
+ #define transport_class_to_sas_port(cdev) \
+ dev_to_sas_port((cdev)->dev)
+
++struct sas_phy_linkrates {
++ enum sas_linkrate maximum_linkrate;
++ enum sas_linkrate minimum_linkrate;
++};
++
+ /* The functions by which the transport class and the driver communicate */
+ struct sas_function_template {
+ int (*get_linkerrors)(struct sas_phy *);
+ int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
+ int (*get_bay_identifier)(struct sas_rphy *);
+ int (*phy_reset)(struct sas_phy *, int);
++ int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
+ };
+
+
+@@ -196,4 +207,6 @@ scsi_is_sas_expander_device(struct devic
+ rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE;
+ }
+
++#define scsi_is_sas_phy_local(phy) scsi_is_host_device((phy)->dev.parent)
++
+ #endif /* SCSI_TRANSPORT_SAS_H */
+diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
+index 302680c..da180f7 100644
+--- a/include/scsi/scsi_transport_spi.h
++++ b/include/scsi/scsi_transport_spi.h
+@@ -53,7 +53,8 @@ struct spi_transport_attrs {
+ unsigned int support_ius; /* support Information Units */
+ unsigned int support_qas; /* supports quick arbitration and selection */
+ /* Private Fields */
+- unsigned int dv_pending:1; /* Internal flag */
++ unsigned int dv_pending:1; /* Internal flag: DV Requested */
++ unsigned int dv_in_progress:1; /* Internal: DV started */
+ struct mutex dv_mutex; /* semaphore to serialise dv */
+ };
+
+diff --git a/include/scsi/sg.h b/include/scsi/sg.h
+index 0a487fe..519c49a 100644
+--- a/include/scsi/sg.h
++++ b/include/scsi/sg.h
+@@ -11,26 +11,10 @@
+ Original driver (sg.h):
+ * Copyright (C) 1992 Lawrence Foard
+ Version 2 and 3 extensions to driver:
+-* Copyright (C) 1998 - 2003 Douglas Gilbert
+-
+- Version: 3.5.29 (20030529)
+- This version is for 2.5 series kernels.
+-
+- Changes since 3.5.28 (20030308)
+- - fix bug introduced in version 3.1.24 (last segment of sgat list)
+- Changes since 3.5.27 (20020812)
+- - remove procfs entries: hosts, host_hdr + host_strs (now in sysfs)
+- - add sysfs sg driver params: def_reserved_size, allow_dio, version
+- - new boot option: "sg_allow_dio" and module parameter: "allow_dio"
+- - multiple internal changes due to scsi subsystem rework
+- Changes since 3.5.26 (20020708)
+- - re-add direct IO using Kai Makisara's work
+- - re-tab to 8, start using C99-isms
+- - simplify memory management
+- Changes since 3.5.25 (20020504)
+- - driverfs additions
+- - copy_to/from_user() fixes [William Stinson]
+- - disable kiobufs support
++* Copyright (C) 1998 - 2006 Douglas Gilbert
++
++ Version: 3.5.34 (20060920)
++ This version is for 2.6 series kernels.
+
+ For a full changelog see http://www.torque.net/sg
+
+@@ -40,7 +24,7 @@ Map of SG verions to the Linux kernels i
+ 2.1.40 2.2.20
+ 3.0.x optional version 3 sg driver for 2.2 series
+ 3.1.17++ 2.4.0++
+- 3.5.23++ 2.5.0++
++ 3.5.30++ 2.6.0++
+
+ Major new features in SG 3.x driver (cf SG 2.x drivers)
+ - SG_IO ioctl() combines function if write() and read()
+@@ -51,14 +35,15 @@ Major new features in SG 3.x driver (cf
+ data into kernel buffers and then use the CPU to copy the data into the
+ user space (vice versa for writes). That is called "indirect" IO due to
+ the double handling of data. There are two methods offered to remove the
+- redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and
+- 2) using the mmap() system call to map the reserve buffer (this driver has
+- one reserve buffer per fd) into the user space. Both have their advantages.
++ redundant copy: 1) direct IO and 2) using the mmap() system call to map
++ the reserve buffer (this driver has one reserve buffer per fd) into the
++ user space. Both have their advantages.
+ In terms of absolute speed mmap() is faster. If speed is not a concern,
+ indirect IO should be fine. Read the documentation for more information.
+
+- ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
+- needed. That pseudo file's content is defaulted to 0. **
++ ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or
++ 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed.
++ That attribute is 0 by default. **
+
+ Historical note: this SCSI pass-through driver has been known as "sg" for
+ a decade. In broader kernel discussions "sg" is used to refer to scatter
+@@ -72,20 +57,17 @@ Major new features in SG 3.x driver (cf
+ http://www.torque.net/sg/p/sg_v3_ho.html
+ This is a rendering from DocBook source [change the extension to "sgml"
+ or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
++ The SG_IO ioctl is now found in other parts kernel (e.g. the block layer).
++ For more information see http://www.torque.net/sg/sg_io.html
+
+ The older, version 2 documents discuss the original sg interface in detail:
+ http://www.torque.net/sg/p/scsi-generic.txt
+ http://www.torque.net/sg/p/scsi-generic_long.txt
+- A version of this document (potentially out of date) may also be found in
+- the kernel source tree, probably at:
+- Documentation/scsi/scsi-generic.txt .
++ Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt
+
+ Utility and test programs are available at the sg web site. They are
+- bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
+- lk 2.4 series).
+-
+- There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
+- http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
++ packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils
++ (for the lk 2.2 series).
+ */
+
+
+@@ -238,13 +220,12 @@ typedef struct sg_req_info { /* used by
+ #define SG_GET_ACCESS_COUNT 0x2289
+
+
+-#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
++#define SG_SCATTER_SZ (8 * 4096)
+ /* Largest size (in bytes) a single scatter-gather list element can have.
+- The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on
+- i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
+- by adapter then this value is the largest data block that can be
+- read/written by a single scsi command. The user can find the value of
+- PAGE_SIZE by calling getpagesize() defined in unistd.h . */
++ The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
++ This value should be a power of 2 (and may be rounded up internally).
++ If scatter-gather is not supported by adapter then this value is the
++ largest data block that can be read/written by a single scsi command. */
+
+ #define SG_DEFAULT_RETRIES 0
+
+diff --git a/include/sound/Kbuild b/include/sound/Kbuild
+index 3a5a3df..fd054a3 100644
+--- a/include/sound/Kbuild
++++ b/include/sound/Kbuild
+@@ -1,2 +1,10 @@
+-header-y := asound_fm.h hdsp.h hdspm.h sfnt_info.h sscape_ioctl.h
+-unifdef-y := asequencer.h asound.h emu10k1.h sb16_csp.h
++header-y += asound_fm.h
++header-y += hdsp.h
++header-y += hdspm.h
++header-y += sfnt_info.h
++header-y += sscape_ioctl.h
++
++unifdef-y += asequencer.h
++unifdef-y += asound.h
++unifdef-y += emu10k1.h
++unifdef-y += sb16_csp.h
+diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
+index 758f8bf..4c43521 100644
+--- a/include/sound/ac97_codec.h
++++ b/include/sound/ac97_codec.h
+@@ -27,6 +27,7 @@
+
+ #include <linux/bitops.h>
+ #include <linux/device.h>
++#include <linux/workqueue.h>
+ #include "pcm.h"
+ #include "control.h"
+ #include "info.h"
+@@ -140,6 +141,20 @@
+ #define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */
+ #define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */
+
++/* powerdown bits */
++#define AC97_PD_ADC_STATUS 0x0001 /* ADC status (RO) */
++#define AC97_PD_DAC_STATUS 0x0002 /* DAC status (RO) */
++#define AC97_PD_MIXER_STATUS 0x0004 /* Analog mixer status (RO) */
++#define AC97_PD_VREF_STATUS 0x0008 /* Vref status (RO) */
++#define AC97_PD_PR0 0x0100 /* Power down PCM ADCs and input MUX */
++#define AC97_PD_PR1 0x0200 /* Power down PCM front DAC */
++#define AC97_PD_PR2 0x0400 /* Power down Mixer (Vref still on) */
++#define AC97_PD_PR3 0x0800 /* Power down Mixer (Vref off) */
++#define AC97_PD_PR4 0x1000 /* Power down AC-Link */
++#define AC97_PD_PR5 0x2000 /* Disable internal clock usage */
++#define AC97_PD_PR6 0x4000 /* Headphone amplifier */
++#define AC97_PD_EAPD 0x8000 /* External Amplifer Power Down (EAPD) */
++
+ /* extended audio ID bit defines */
+ #define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
+ #define AC97_EI_DRA 0x0002 /* Double rate supported */
+@@ -359,6 +374,7 @@
+ #define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */
+ #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
+ #define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
++#define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */
+
+ /* ac97->flags */
+ #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
+@@ -491,6 +507,12 @@ struct snd_ac97 {
+ /* jack-sharing info */
+ unsigned char indep_surround;
+ unsigned char channel_mode;
++
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ unsigned int power_up; /* power states */
++ struct workqueue_struct *power_workq;
++ struct work_struct power_work;
++#endif
+ struct device dev;
+ };
+
+@@ -532,6 +554,15 @@ unsigned short snd_ac97_read(struct snd_
+ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
+ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
+ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value);
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup);
++#else
++static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg,
++ int powerup)
++{
++ return 0;
++}
++#endif
+ #ifdef CONFIG_PM
+ void snd_ac97_suspend(struct snd_ac97 *ac97);
+ void snd_ac97_resume(struct snd_ac97 *ac97);
+@@ -583,6 +614,7 @@ struct ac97_pcm {
+ copy_flag: 1, /* lowlevel driver must fill all entries */
+ spdif: 1; /* spdif pcm */
+ unsigned short aslots; /* active slots */
++ unsigned short cur_dbl; /* current double-rate state */
+ unsigned int rates; /* available rates */
+ struct {
+ unsigned short slots; /* driver input: requested AC97 slot numbers */
+diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
+index 57af1fe..c8de6f8 100644
+--- a/include/sound/ad1848.h
++++ b/include/sound/ad1848.h
+@@ -179,14 +179,13 @@ enum { AD1848_MIX_SINGLE, AD1848_MIX_DOU
+ #define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \
+ ((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22))
+
+-int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value);
+-
+ /* for ease of use */
+ struct ad1848_mix_elem {
+ const char *name;
+ int index;
+ int type;
+ unsigned long private_value;
++ unsigned int *tlv;
+ };
+
+ #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
+@@ -195,15 +194,26 @@ struct ad1848_mix_elem {
+ .type = AD1848_MIX_SINGLE, \
+ .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) }
+
++#define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
++{ .name = xname, \
++ .index = xindex, \
++ .type = AD1848_MIX_SINGLE, \
++ .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert), \
++ .tlv = xtlv }
++
+ #define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+ { .name = xname, \
+ .index = xindex, \
+ .type = AD1848_MIX_DOUBLE, \
+ .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) }
+
+-static inline int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c)
+-{
+- return snd_ad1848_add_ctl(chip, c->name, c->index, c->type, c->private_value);
+-}
++#define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
++{ .name = xname, \
++ .index = xindex, \
++ .type = AD1848_MIX_DOUBLE, \
++ .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert), \
++ .tlv = xtlv }
++
++int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c);
+
+ #endif /* __SOUND_AD1848_H */
+diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
+index 3d98884..d0deca6 100644
+--- a/include/sound/ak4xxx-adda.h
++++ b/include/sound/ak4xxx-adda.h
+@@ -39,26 +39,39 @@ struct snd_ak4xxx_ops {
+
+ #define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */
+
++/* DAC label and channels */
++struct snd_akm4xxx_dac_channel {
++ char *name; /* mixer volume name */
++ unsigned int num_channels;
++};
++
++/* ADC labels and channels */
++struct snd_akm4xxx_adc_channel {
++ char *name; /* capture gain volume label */
++ char *switch_name; /* capture switch */
++ unsigned int num_channels;
++};
++
+ struct snd_akm4xxx {
+ struct snd_card *card;
+ unsigned int num_adcs; /* AK4524 or AK4528 ADCs */
+ unsigned int num_dacs; /* AK4524 or AK4528 DACs */
+ unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
+- unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image
+- * for IPGA (AK4528)
+- */
++ unsigned char volumes[AK4XXX_IMAGE_SIZE]; /* saved volume values */
+ unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */
+ void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */
+ /* template should fill the following fields */
+ unsigned int idx_offset; /* control index offset */
+ enum {
+ SND_AK4524, SND_AK4528, SND_AK4529,
+- SND_AK4355, SND_AK4358, SND_AK4381
++ SND_AK4355, SND_AK4358, SND_AK4381,
++ SND_AK5365
+ } type;
+- unsigned int *num_stereo; /* array of combined counts
+- * for the mixer
+- */
+- char **channel_names; /* array of mixer channel names */
++
++ /* (array) information of combined codecs */
++ struct snd_akm4xxx_dac_channel *dac_info;
++ struct snd_akm4xxx_adc_channel *adc_info;
++
+ struct snd_ak4xxx_ops ops;
+ };
+
+@@ -72,9 +85,9 @@ int snd_akm4xxx_build_controls(struct sn
+ (ak)->images[(chip) * 16 + (reg)]
+ #define snd_akm4xxx_set(ak,chip,reg,val) \
+ ((ak)->images[(chip) * 16 + (reg)] = (val))
+-#define snd_akm4xxx_get_ipga(ak,chip,reg) \
+- (ak)->ipga_gain[chip][(reg)-4]
+-#define snd_akm4xxx_set_ipga(ak,chip,reg,val) \
+- ((ak)->ipga_gain[chip][(reg)-4] = (val))
++#define snd_akm4xxx_get_vol(ak,chip,reg) \
++ (ak)->volumes[(chip) * 16 + (reg)]
++#define snd_akm4xxx_set_vol(ak,chip,reg,val) \
++ ((ak)->volumes[(chip) * 16 + (reg)] = (val))
+
+ #endif /* __SOUND_AK4XXX_ADDA_H */
+diff --git a/include/sound/asound.h b/include/sound/asound.h
+index 41885f4..c1621c6 100644
+--- a/include/sound/asound.h
++++ b/include/sound/asound.h
+@@ -688,7 +688,7 @@ struct snd_timer_tread {
+ * *
+ ****************************************************************************/
+
+-#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3)
++#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
+
+ struct snd_ctl_card_info {
+ int card; /* card number */
+@@ -727,10 +727,15 @@ typedef int __bitwise snd_ctl_elem_iface
+ #define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
+ #define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
+ #define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
+-#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<2) /* when was control changed */
++#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */
++#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */
++#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */
++#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
++#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */
+ #define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */
+ #define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */
+ #define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */
++#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* kernel use a TLV callback */
+ #define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */
+ #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */
+ #define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */
+@@ -818,6 +823,12 @@ struct snd_ctl_elem_value {
+ unsigned char reserved[128-sizeof(struct timespec)];
+ };
+
++struct snd_ctl_tlv {
++ unsigned int numid; /* control element numeric identification */
++ unsigned int length; /* in bytes aligned to 4 */
++ unsigned int tlv[0]; /* first TLV */
++};
++
+ enum {
+ SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
+ SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
+@@ -831,6 +842,9 @@ enum {
+ SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
+ SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
+ SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
++ SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
++ SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
++ SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct snd_ctl_tlv),
+ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
+ SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
+ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
+@@ -855,6 +869,7 @@ enum sndrv_ctl_event_type {
+ #define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */
+ #define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */
+ #define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */
++#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) /* element TLV tree was changed */
+ #define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */
+
+ struct snd_ctl_event {
+diff --git a/include/sound/control.h b/include/sound/control.h
+index 2489b1e..1de148b 100644
+--- a/include/sound/control.h
++++ b/include/sound/control.h
+@@ -30,6 +30,11 @@ struct snd_kcontrol;
+ typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
+ typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
+ typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
++typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
++ int op_flag, /* 0=read,1=write,-1=command */
++ unsigned int size,
++ unsigned int __user *tlv);
++
+
+ struct snd_kcontrol_new {
+ snd_ctl_elem_iface_t iface; /* interface identifier */
+@@ -42,6 +47,10 @@ struct snd_kcontrol_new {
+ snd_kcontrol_info_t *info;
+ snd_kcontrol_get_t *get;
+ snd_kcontrol_put_t *put;
++ union {
++ snd_kcontrol_tlv_rw_t *c;
++ unsigned int *p;
++ } tlv;
+ unsigned long private_value;
+ };
+
+@@ -58,6 +67,10 @@ struct snd_kcontrol {
+ snd_kcontrol_info_t *info;
+ snd_kcontrol_get_t *get;
+ snd_kcontrol_put_t *put;
++ union {
++ snd_kcontrol_tlv_rw_t *c;
++ unsigned int *p;
++ } tlv;
+ unsigned long private_value;
+ void *private_data;
+ void (*private_free)(struct snd_kcontrol *kcontrol);
+diff --git a/include/sound/core.h b/include/sound/core.h
+index bab3ff4..fa1ca01 100644
+--- a/include/sound/core.h
++++ b/include/sound/core.h
+@@ -25,8 +25,8 @@
+ #include <linux/sched.h> /* wake_up() */
+ #include <linux/mutex.h> /* struct mutex */
+ #include <linux/rwsem.h> /* struct rw_semaphore */
+-#include <linux/workqueue.h> /* struct workqueue_struct */
+ #include <linux/pm.h> /* pm_message_t */
++#include <linux/device.h>
+
+ /* forward declarations */
+ #ifdef CONFIG_PCI
+@@ -71,7 +71,6 @@ struct snd_device_ops {
+ int (*dev_free)(struct snd_device *dev);
+ int (*dev_register)(struct snd_device *dev);
+ int (*dev_disconnect)(struct snd_device *dev);
+- int (*dev_unregister)(struct snd_device *dev);
+ };
+
+ struct snd_device {
+@@ -90,10 +89,10 @@ struct snd_device {
+ struct snd_monitor_file {
+ struct file *file;
+ struct snd_monitor_file *next;
++ const struct file_operations *disconnected_f_op;
++ struct list_head shutdown_list;
+ };
+
+-struct snd_shutdown_f_ops; /* define it later in init.c */
+-
+ /* main structure for soundcard */
+
+ struct snd_card {
+@@ -131,8 +130,8 @@ struct snd_card {
+ state */
+ spinlock_t files_lock; /* lock the files for this card */
+ int shutdown; /* this card is going down */
++ int free_on_last_close; /* free in context of file_release */
+ wait_queue_head_t shutdown_sleep;
+- struct work_struct free_workq; /* for free in workqueue */
+ struct device *dev;
+
+ #ifdef CONFIG_PM
+@@ -188,6 +187,7 @@ struct snd_minor {
+ int device; /* device number */
+ const struct file_operations *f_ops; /* file operations */
+ void *private_data; /* private data for f_ops->open */
++ struct class_device *class_dev; /* class device for sysfs */
+ };
+
+ /* sound.c */
+@@ -202,6 +202,8 @@ int snd_register_device(int type, struct
+ const char *name);
+ int snd_unregister_device(int type, struct snd_card *card, int dev);
+ void *snd_lookup_minor_data(unsigned int minor, int type);
++int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
++ const struct class_device_attribute *attr);
+
+ #ifdef CONFIG_SND_OSSEMUL
+ int snd_register_oss_device(int type, struct snd_card *card, int dev,
+@@ -244,7 +246,7 @@ struct snd_card *snd_card_new(int idx, c
+ struct module *module, int extra_size);
+ int snd_card_disconnect(struct snd_card *card);
+ int snd_card_free(struct snd_card *card);
+-int snd_card_free_in_thread(struct snd_card *card);
++int snd_card_free_when_closed(struct snd_card *card);
+ int snd_card_register(struct snd_card *card);
+ int snd_card_info_init(void);
+ int snd_card_info_done(void);
+diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h
+index 60b5b92..ab51ce1 100644
+--- a/include/sound/cs4231.h
++++ b/include/sound/cs4231.h
+@@ -273,7 +273,7 @@ unsigned char snd_cs4236_ext_in(struct s
+ void snd_cs4231_mce_up(struct snd_cs4231 *chip);
+ void snd_cs4231_mce_down(struct snd_cs4231 *chip);
+
+-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id);
+
+ const char *snd_cs4231_chip_id(struct snd_cs4231 *chip);
+
+diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
+index 884bbf5..3d3c151 100644
+--- a/include/sound/emu10k1.h
++++ b/include/sound/emu10k1.h
+@@ -1194,7 +1194,7 @@ int snd_emu10k1_mixer(struct snd_emu10k1
+ int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device);
+ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep);
+
+-irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id);
+
+ void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int voice);
+ int snd_emu10k1_init_efx(struct snd_emu10k1 *emu);
+@@ -1524,6 +1524,10 @@ struct snd_emu10k1_fx8010_control_gpr {
+ unsigned int value[32]; /* initial values */
+ unsigned int min; /* minimum range */
+ unsigned int max; /* maximum range */
++ union {
++ snd_kcontrol_tlv_rw_t *c;
++ unsigned int *p;
++ } tlv;
+ unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
+ };
+
+diff --git a/include/sound/gus.h b/include/sound/gus.h
+index 68a664a..c49ea57 100644
+--- a/include/sound/gus.h
++++ b/include/sound/gus.h
+@@ -638,7 +638,7 @@ int snd_gus_initialize(struct snd_gus_ca
+
+ /* gus_irq.c */
+
+-irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t snd_gus_interrupt(int irq, void *dev_id);
+ #ifdef CONFIG_SND_DEBUG
+ void snd_gus_irq_profile_init(struct snd_gus_card *gus);
+ #endif
+diff --git a/include/sound/info.h b/include/sound/info.h
+index 74f6996..97ffc4f 100644
+--- a/include/sound/info.h
++++ b/include/sound/info.h
+@@ -71,7 +71,6 @@ struct snd_info_entry {
+ mode_t mode;
+ long size;
+ unsigned short content;
+- unsigned short disconnected: 1;
+ union {
+ struct snd_info_entry_text text;
+ struct snd_info_entry_ops *ops;
+@@ -83,6 +82,8 @@ struct snd_info_entry {
+ void (*private_free)(struct snd_info_entry *entry);
+ struct proc_dir_entry *p;
+ struct mutex access;
++ struct list_head children;
++ struct list_head list;
+ };
+
+ #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
+@@ -122,8 +123,8 @@ int snd_info_restore_text(struct snd_inf
+ int snd_info_card_create(struct snd_card * card);
+ int snd_info_card_register(struct snd_card * card);
+ int snd_info_card_free(struct snd_card * card);
++void snd_info_card_disconnect(struct snd_card * card);
+ int snd_info_register(struct snd_info_entry * entry);
+-int snd_info_unregister(struct snd_info_entry * entry);
+
+ /* for card drivers */
+ int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp);
+@@ -156,8 +157,8 @@ static inline void snd_info_free_entry(s
+ static inline int snd_info_card_create(struct snd_card * card) { return 0; }
+ static inline int snd_info_card_register(struct snd_card * card) { return 0; }
+ static inline int snd_info_card_free(struct snd_card * card) { return 0; }
++static inline void snd_info_card_disconnect(struct snd_card * card) { }
+ static inline int snd_info_register(struct snd_info_entry * entry) { return 0; }
+-static inline int snd_info_unregister(struct snd_info_entry * entry) { return 0; }
+
+ static inline int snd_card_proc_new(struct snd_card *card, const char *name,
+ struct snd_info_entry **entryp) { return -EINVAL; }
+diff --git a/include/sound/initval.h b/include/sound/initval.h
+index 2ae76ef..e85b907 100644
+--- a/include/sound/initval.h
++++ b/include/sound/initval.h
+@@ -53,7 +53,7 @@
+ #ifdef SNDRV_LEGACY_FIND_FREE_IRQ
+ #include <linux/interrupt.h>
+
+-static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id)
+ {
+ return IRQ_HANDLED;
+ }
+diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h
+index ac50432..8c88267 100644
+--- a/include/sound/mpu401.h
++++ b/include/sound/mpu401.h
+@@ -106,10 +106,8 @@ struct snd_mpu401 {
+
+ */
+
+-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
+-irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
+- struct pt_regs *regs);
++irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id);
++irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id);
+
+ int snd_mpu401_uart_new(struct snd_card *card,
+ int device,
+diff --git a/include/sound/pcm.h b/include/sound/pcm.h
+index f84d849..afaf3e8 100644
+--- a/include/sound/pcm.h
++++ b/include/sound/pcm.h
+@@ -190,7 +190,7 @@ struct snd_pcm_ops {
+
+ struct snd_pcm_file {
+ struct snd_pcm_substream *substream;
+- struct snd_pcm_file *next;
++ int no_compat_mmap;
+ };
+
+ struct snd_pcm_hw_rule;
+@@ -347,6 +347,7 @@ struct snd_pcm_substream {
+ int number;
+ char name[32]; /* substream name */
+ int stream; /* stream (direction) */
++ char latency_id[20]; /* latency identifier */
+ size_t buffer_bytes_max; /* limit ring buffer size */
+ struct snd_dma_buffer dma_buffer;
+ unsigned int dma_buf_id;
+@@ -384,7 +385,6 @@ struct snd_pcm_substream {
+ struct snd_info_entry *proc_prealloc_entry;
+ #endif
+ /* misc flags */
+- unsigned int no_mmap_ctrl: 1;
+ unsigned int hw_opened: 1;
+ };
+
+@@ -402,7 +402,6 @@ struct snd_pcm_str {
+ /* -- OSS things -- */
+ struct snd_pcm_oss_stream oss;
+ #endif
+- struct snd_pcm_file *files;
+ #ifdef CONFIG_SND_VERBOSE_PROCFS
+ struct snd_info_entry *proc_root;
+ struct snd_info_entry *proc_info_entry;
+diff --git a/include/sound/sb.h b/include/sound/sb.h
+index 431d066..2dd5c8e 100644
+--- a/include/sound/sb.h
++++ b/include/sound/sb.h
+@@ -100,7 +100,7 @@ struct snd_sb {
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_substream *midi_substream_input;
+ struct snd_rawmidi_substream *midi_substream_output;
+- irqreturn_t (*rmidi_callback)(int irq, void *dev_id, struct pt_regs *regs);
++ irq_handler_t rmidi_callback;
+
+ spinlock_t reg_lock;
+ spinlock_t open_lock;
+@@ -286,7 +286,7 @@ int snd_sbdsp_reset(struct snd_sb *chip)
+ int snd_sbdsp_create(struct snd_card *card,
+ unsigned long port,
+ int irq,
+- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
++ irq_handler_t irq_handler,
+ int dma8, int dma16,
+ unsigned short hardware,
+ struct snd_sb **r_chip);
+@@ -316,7 +316,7 @@ int snd_sb16dsp_pcm(struct snd_sb *chip,
+ const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction);
+ int snd_sb16dsp_configure(struct snd_sb *chip);
+ /* sb16.c */
+-irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id);
+
+ /* exported mixer stuffs */
+ enum {
+diff --git a/include/sound/timer.h b/include/sound/timer.h
+index 5ece2bf..d42c083 100644
+--- a/include/sound/timer.h
++++ b/include/sound/timer.h
+@@ -129,7 +129,6 @@ void snd_timer_notify(struct snd_timer *
+ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
+ int snd_timer_global_free(struct snd_timer *timer);
+ int snd_timer_global_register(struct snd_timer *timer);
+-int snd_timer_global_unregister(struct snd_timer *timer);
+
+ int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id);
+ int snd_timer_close(struct snd_timer_instance *timeri);
+diff --git a/include/sound/tlv.h b/include/sound/tlv.h
+new file mode 100644
+index 0000000..d93a96b
+--- /dev/null
++++ b/include/sound/tlv.h
+@@ -0,0 +1,60 @@
++#ifndef __SOUND_TLV_H
++#define __SOUND_TLV_H
++
++/*
++ * Advanced Linux Sound Architecture - ALSA - Driver
++ * Copyright (c) 2006 by Jaroslav Kysela <perex at suse.cz>
++ *
++ *
++ * 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
++ *
++ */
++
++/*
++ * TLV structure is right behind the struct snd_ctl_tlv:
++ * unsigned int type - see SNDRV_CTL_TLVT_*
++ * unsigned int length
++ * .... data aligned to sizeof(unsigned int), use
++ * block_length = (length + (sizeof(unsigned int) - 1)) &
++ * ~(sizeof(unsigned int) - 1)) ....
++ */
++
++#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
++#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
++#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
++#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
++
++#define TLV_DB_SCALE_ITEM(min, step, mute) \
++ SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
++ (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
++#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
++ unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
++
++/* linear volume between min_dB and max_dB (.01dB unit) */
++#define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \
++ SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
++ (min_dB), (max_dB)
++#define DECLARE_TLV_DB_LINEAR(name, min_dB, max_dB) \
++ unsigned int name[] = { TLV_DB_LINEAR_ITEM(min_dB, max_dB) }
++
++/* dB range container */
++/* Each item is: <min> <max> <TLV> */
++/* The below assumes that each item TLV is 4 words like DB_SCALE or LINEAR */
++#define TLV_DB_RANGE_HEAD(num) \
++ SNDRV_CTL_TLVT_DB_RANGE, 6 * (num) * sizeof(unsigned int)
++
++#define TLV_DB_GAIN_MUTE -9999999
++
++#endif /* __SOUND_TLV_H */
+diff --git a/include/sound/version.h b/include/sound/version.h
+index 2ee849d..52fd687 100644
+--- a/include/sound/version.h
++++ b/include/sound/version.h
+@@ -1,3 +1,3 @@
+-/* include/version.h. Generated by configure. */
+-#define CONFIG_SND_VERSION "1.0.12rc1"
+-#define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)"
++/* include/version.h. Generated by alsa/ksync script. */
++#define CONFIG_SND_VERSION "1.0.13"
++#define CONFIG_SND_DATE " (Sun Oct 22 08:56:16 2006 UTC)"
+diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
+index 9821a61..2173946 100644
+--- a/include/sound/vx_core.h
++++ b/include/sound/vx_core.h
+@@ -128,6 +128,7 @@ struct snd_vx_hardware {
+ unsigned int num_ins;
+ unsigned int num_outs;
+ unsigned int output_level_max;
++ unsigned int *output_level_db_scale;
+ };
+
+ /* hwdep id string */
+@@ -227,7 +228,7 @@ void snd_vx_free_firmware(struct vx_core
+ /*
+ * interrupt handler; exported for pcmcia
+ */
+-irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs);
++irqreturn_t snd_vx_irq_handler(int irq, void *dev);
+
+ /*
+ * lowlevel functions
+diff --git a/include/video/Kbuild b/include/video/Kbuild
+index 76a6073..a14f9c0 100644
+--- a/include/video/Kbuild
++++ b/include/video/Kbuild
+@@ -1 +1 @@
+-unifdef-y := sisfb.h
++unifdef-y += sisfb.h
+diff --git a/include/video/s1d13xxxfb.h b/include/video/s1d13xxxfb.h
+index f06cc88..c99d261 100644
+--- a/include/video/s1d13xxxfb.h
++++ b/include/video/s1d13xxxfb.h
+@@ -1,4 +1,4 @@
+-/* drivers/video/s1d3xxxfb.h
++/* include/video/s1d13xxxfb.h
+ *
+ * (c) 2004 Simtec Electronics
+ * (c) 2005 Thibaut VARENE <varenet at parisc-linux.org>
+diff --git a/include/video/sstfb.h b/include/video/sstfb.h
+index 3570f9c..5dbf5e7 100644
+--- a/include/video/sstfb.h
++++ b/include/video/sstfb.h
+@@ -68,10 +68,6 @@
+ # define print_var(X,Y...)
+ #endif
+
+-#define eprintk(X...) printk(KERN_ERR "sstfb: " X)
+-#define iprintk(X...) printk(KERN_INFO "sstfb: " X)
+-#define wprintk(X...) printk(KERN_WARNING "sstfb: " X)
+-
+ #define BIT(x) (1ul<<(x))
+ #define POW2(x) (1ul<<(x))
+
+diff --git a/init/Kconfig b/init/Kconfig
+index 9a7656f..c8b2624 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1,5 +1,6 @@
+ config DEFCONFIG_LIST
+ string
++ depends on !UML
+ option defconfig_list
+ default "/lib/modules/$UNAME_RELEASE/.config"
+ default "/etc/kernel-config"
+@@ -92,7 +93,7 @@ config LOCALVERSION_AUTO
+
+ config SWAP
+ bool "Support for paging of anonymous memory (swap)"
+- depends on MMU
++ depends on MMU && BLOCK
+ default y
+ help
+ This option allows you to choose whether you want to have support
+@@ -115,6 +116,15 @@ config SYSVIPC
+ section 6.4 of the Linux Programmer's Guide, available from
+ <http://www.tldp.org/guides.html>.
+
++config IPC_NS
++ bool "IPC Namespaces"
++ depends on SYSVIPC
++ default n
++ help
++ Support ipc namespaces. This allows containers, i.e. virtual
++ environments, to use ipc namespaces to provide different ipc
++ objects for different servers. If unsure, say N.
++
+ config POSIX_MQUEUE
+ bool "POSIX Message Queues"
+ depends on NET && EXPERIMENTAL
+@@ -182,6 +192,14 @@ config TASK_DELAY_ACCT
+
+ Say N if unsure.
+
++config UTS_NS
++ bool "UTS Namespaces"
++ default n
++ help
++ Support uts namespaces. This allows containers, i.e.
++ vservers, to use uts namespaces to provide different
++ uts info for different servers. If unsure, say N.
++
+ config AUDIT
+ bool "Auditing support"
+ depends on NET
+@@ -202,7 +220,7 @@ config AUDITSYSCALL
+ ensure that INOTIFY is configured.
+
+ config IKCONFIG
+- bool "Kernel .config support"
++ tristate "Kernel .config support"
+ ---help---
+ This option enables the complete Linux kernel ".config" file
+ contents to be saved in the kernel. It provides documentation
+@@ -257,6 +275,18 @@ config CC_OPTIMIZE_FOR_SIZE
+
+ If unsure, say N.
+
++config TASK_XACCT
++ bool "Enable extended accounting over taskstats (EXPERIMENTAL)"
++ depends on TASKSTATS
++ help
++ Collect extended task accounting data and send the data
++ to userland for processing over the taskstats interface.
++
++ Say N if unsure.
++
++config SYSCTL
++ bool
++
+ menuconfig EMBEDDED
+ bool "Configure standard kernel features (for small systems)"
+ help
+@@ -272,22 +302,22 @@ config UID16
+ help
+ This enables the legacy 16-bit UID syscall wrappers.
+
+-config SYSCTL
+- bool "Sysctl support" if EMBEDDED
+- default y
++config SYSCTL_SYSCALL
++ bool "Sysctl syscall support" if EMBEDDED
++ default n
++ select SYSCTL
+ ---help---
+- The sysctl interface provides a means of dynamically changing
+- certain kernel parameters and variables on the fly without requiring
+- a recompile of the kernel or reboot of the system. The primary
+- interface consists of a system call, but if you say Y to "/proc
+- file system support", a tree of modifiable sysctl entries will be
+- generated beneath the /proc/sys directory. They are explained in the
+- files in <file:Documentation/sysctl/>. Note that enabling this
+- option will enlarge the kernel by at least 8 KB.
+-
+- As it is generally a good thing, you should say Y here unless
+- building a kernel for install/rescue disks or your system is very
+- limited in memory.
++ Enable the deprecated sysctl system call. sys_sysctl uses
++ binary paths that have been found to be a major pain to maintain
++ and use. The interface in /proc/sys is now the primary and what
++ everyone uses.
++
++ Nothing has been using the binary sysctl interface for some
++ time now so nothing should break if you disable sysctl syscall
++ support, and your kernel will get marginally smaller.
++
++ Unless you have an application that uses the sys_sysctl interface
++ you should probably say N here.
+
+ config KALLSYMS
+ bool "Load all symbols for debugging/kksymoops" if EMBEDDED
+diff --git a/init/do_mounts.c b/init/do_mounts.c
+index 94aeec7..dc1ec08 100644
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -8,6 +8,7 @@
+ #include <linux/security.h>
+ #include <linux/delay.h>
+ #include <linux/mount.h>
++#include <linux/device.h>
+
+ #include <linux/nfs_fs.h>
+ #include <linux/nfs_fs_sb.h>
+@@ -284,7 +285,11 @@ void __init mount_block_root(char *name,
+ {
+ char *fs_names = __getname();
+ char *p;
++#ifdef CONFIG_BLOCK
+ char b[BDEVNAME_SIZE];
++#else
++ const char *b = name;
++#endif
+
+ get_fs_names(fs_names);
+ retry:
+@@ -303,7 +308,9 @@ retry:
+ * Allow the user to distinguish between failed sys_open
+ * and bad superblock on root device.
+ */
++#ifdef CONFIG_BLOCK
+ __bdevname(ROOT_DEV, b);
++#endif
+ printk("VFS: Cannot open root device \"%s\" or %s\n",
+ root_device_name, b);
+ printk("Please append a correct \"root=\" boot option\n");
+@@ -315,7 +322,10 @@ retry:
+ for (p = fs_names; *p; p += strlen(p)+1)
+ printk(" %s", p);
+ printk("\n");
+- panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b));
++#ifdef CONFIG_BLOCK
++ __bdevname(ROOT_DEV, b);
++#endif
++ panic("VFS: Unable to mount root fs on %s", b);
+ out:
+ putname(fs_names);
+ }
+@@ -386,8 +396,10 @@ void __init mount_root(void)
+ change_floppy("root floppy");
+ }
+ #endif
++#ifdef CONFIG_BLOCK
+ create_dev("/dev/root", ROOT_DEV);
+ mount_block_root("/dev/root", root_mountflags);
++#endif
+ }
+
+ /*
+@@ -403,6 +415,10 @@ void __init prepare_namespace(void)
+ ssleep(root_delay);
+ }
+
++ /* wait for the known devices to complete their probing */
++ while (driver_probe_done() != 0)
++ msleep(100);
++
+ md_run_setup();
+
+ if (saved_root_name[0]) {
+diff --git a/init/do_mounts.h b/init/do_mounts.h
+index e7f2e7f..735705d 100644
+--- a/init/do_mounts.h
++++ b/init/do_mounts.h
+@@ -1,4 +1,3 @@
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/syscalls.h>
+diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
+index a06f037..919a80c 100644
+--- a/init/do_mounts_initrd.c
++++ b/init/do_mounts_initrd.c
+@@ -1,4 +1,3 @@
+-#define __KERNEL_SYSCALLS__
+ #include <linux/unistd.h>
+ #include <linux/kernel.h>
+ #include <linux/fs.h>
+@@ -35,7 +34,7 @@ static int __init do_linuxrc(void * shel
+ (void) sys_open("/dev/console",O_RDWR,0);
+ (void) sys_dup(0);
+ (void) sys_dup(0);
+- return execve(shell, argv, envp_init);
++ return kernel_execve(shell, argv, envp_init);
+ }
+
+ static void __init handle_initrd(void)
+diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
+index 2429e1b..753dc54 100644
+--- a/init/do_mounts_md.c
++++ b/init/do_mounts_md.c
+@@ -20,7 +20,7 @@ static struct {
+ int level;
+ int chunk;
+ char *device_names;
+-} md_setup_args[MAX_MD_DEVS] __initdata;
++} md_setup_args[256] __initdata;
+
+ static int md_setup_ents __initdata;
+
+@@ -61,10 +61,6 @@ static int __init md_setup(char *str)
+ return 0;
+ }
+ str1 = str;
+- if (minor >= MAX_MD_DEVS) {
+- printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
+- return 0;
+- }
+ for (ent=0 ; ent< md_setup_ents ; ent++)
+ if (md_setup_args[ent].minor == minor &&
+ md_setup_args[ent].partitioned == partitioned) {
+@@ -72,7 +68,7 @@ static int __init md_setup(char *str)
+ "Replacing previous definition.\n", partitioned?"d":"", minor);
+ break;
+ }
+- if (ent >= MAX_MD_DEVS) {
++ if (ent >= ARRAY_SIZE(md_setup_args)) {
+ printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor);
+ return 0;
+ }
+diff --git a/init/main.c b/init/main.c
+index 8651a72..36f608a 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -9,8 +9,6 @@
+ * Simplified starting of init: Michael A. Griffith <grif at acm.org>
+ */
+
+-#define __KERNEL_SYSCALLS__
+-
+ #include <linux/types.h>
+ #include <linux/module.h>
+ #include <linux/proc_fs.h>
+@@ -128,6 +126,18 @@ static char *ramdisk_execute_command;
+ static unsigned int max_cpus = NR_CPUS;
+
+ /*
++ * If set, this is an indication to the drivers that reset the underlying
++ * device before going ahead with the initialization otherwise driver might
++ * rely on the BIOS and skip the reset operation.
++ *
++ * This is useful if kernel is booting in an unreliable environment.
++ * For ex. kdump situaiton where previous kernel has crashed, BIOS has been
++ * skipped and devices will be in unknown state.
++ */
++unsigned int reset_devices;
++EXPORT_SYMBOL(reset_devices);
++
++/*
+ * Setup routine for controlling SMP activation
+ *
+ * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+@@ -153,6 +163,14 @@ static int __init maxcpus(char *str)
+
+ __setup("maxcpus=", maxcpus);
+
++static int __init set_reset_devices(char *str)
++{
++ reset_devices = 1;
++ return 1;
++}
++
++__setup("reset_devices", set_reset_devices);
++
+ static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
+ char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
+ static const char *panic_later, *panic_param;
+@@ -162,16 +180,19 @@ extern struct obs_kernel_param __setup_s
+ static int __init obsolete_checksetup(char *line)
+ {
+ struct obs_kernel_param *p;
++ int had_early_param = 0;
+
+ p = __setup_start;
+ do {
+ int n = strlen(p->str);
+ if (!strncmp(line, p->str, n)) {
+ if (p->early) {
+- /* Already done in parse_early_param? (Needs
+- * exact match on param part) */
++ /* Already done in parse_early_param?
++ * (Needs exact match on param part).
++ * Keep iterating, as we can have early
++ * params and __setups of same names 8( */
+ if (line[n] == '\0' || line[n] == '=')
+- return 1;
++ had_early_param = 1;
+ } else if (!p->setup_func) {
+ printk(KERN_WARNING "Parameter %s is obsolete,"
+ " ignored\n", p->str);
+@@ -181,7 +202,8 @@ static int __init obsolete_checksetup(ch
+ }
+ p++;
+ } while (p < __setup_end);
+- return 0;
++
++ return had_early_param;
+ }
+
+ /*
+@@ -464,6 +486,7 @@ asmlinkage void __init start_kernel(void
+ * Need to run as early as possible, to initialize the
+ * lockdep hash:
+ */
++ unwind_init();
+ lockdep_init();
+
+ local_irq_disable();
+@@ -480,6 +503,7 @@ asmlinkage void __init start_kernel(void
+ printk(KERN_NOTICE);
+ printk(linux_banner);
+ setup_arch(&command_line);
++ unwind_setup();
+ setup_per_cpu_areas();
+ smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
+
+@@ -502,7 +526,6 @@ asmlinkage void __init start_kernel(void
+ __stop___param - __start___param,
+ &unknown_bootoption);
+ sort_main_extable();
+- unwind_init();
+ trap_init();
+ rcu_init();
+ init_IRQ();
+@@ -679,7 +702,7 @@ static void do_pre_smp_initcalls(void)
+ static void run_init_process(char *init_filename)
+ {
+ argv_init[0] = init_filename;
+- execve(init_filename, argv_init, envp_init);
++ kernel_execve(init_filename, argv_init, envp_init);
+ }
+
+ static int init(void * unused)
+@@ -699,6 +722,8 @@ static int init(void * unused)
+ */
+ child_reaper = current;
+
++ cad_pid = task_pid(current);
++
+ smp_prepare_cpus(max_cpus);
+
+ do_pre_smp_initcalls();
+diff --git a/init/version.c b/init/version.c
+index e290802..8f28344 100644
+--- a/init/version.c
++++ b/init/version.c
+@@ -12,22 +12,27 @@
+ #include <linux/utsname.h>
+ #include <linux/utsrelease.h>
+ #include <linux/version.h>
++#include <linux/sched.h>
+
+ #define version(a) Version_ ## a
+ #define version_string(a) version(a)
+
+ int version_string(LINUX_VERSION_CODE);
+
+-struct new_utsname system_utsname = {
+- .sysname = UTS_SYSNAME,
+- .nodename = UTS_NODENAME,
+- .release = UTS_RELEASE,
+- .version = UTS_VERSION,
+- .machine = UTS_MACHINE,
+- .domainname = UTS_DOMAINNAME,
++struct uts_namespace init_uts_ns = {
++ .kref = {
++ .refcount = ATOMIC_INIT(2),
++ },
++ .name = {
++ .sysname = UTS_SYSNAME,
++ .nodename = UTS_NODENAME,
++ .release = UTS_RELEASE,
++ .version = UTS_VERSION,
++ .machine = UTS_MACHINE,
++ .domainname = UTS_DOMAINNAME,
++ },
+ };
+-
+-EXPORT_SYMBOL(system_utsname);
++EXPORT_SYMBOL_GPL(init_uts_ns);
+
+ const char linux_banner[] =
+ "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
+diff --git a/ipc/mqueue.c b/ipc/mqueue.c
+index 02e6f67..7c27400 100644
+--- a/ipc/mqueue.c
++++ b/ipc/mqueue.c
+@@ -2,7 +2,7 @@
+ * POSIX message queues filesystem for Linux.
+ *
+ * Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi at mat.uni.torun.pl)
+- * Michal Wronski (Michal.Wronski at motorola.com)
++ * Michal Wronski (michal.wronski at gmail.com)
+ *
+ * Spinlocks: Mohamed Abbas (abbas.mohamed at intel.com)
+ * Lockless receive & send, fd based notify:
+@@ -73,7 +73,7 @@ struct mqueue_inode_info {
+ struct mq_attr attr;
+
+ struct sigevent notify;
+- pid_t notify_owner;
++ struct pid* notify_owner;
+ struct user_struct *user; /* user who created, for accounting */
+ struct sock *notify_sock;
+ struct sk_buff *notify_cookie;
+@@ -115,7 +115,6 @@ static struct inode *mqueue_get_inode(st
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_ctime = inode->i_atime =
+ CURRENT_TIME;
+@@ -135,7 +134,7 @@ static struct inode *mqueue_get_inode(st
+ INIT_LIST_HEAD(&info->e_wait_q[0].list);
+ INIT_LIST_HEAD(&info->e_wait_q[1].list);
+ info->messages = NULL;
+- info->notify_owner = 0;
++ info->notify_owner = NULL;
+ info->qsize = 0;
+ info->user = NULL; /* set when all is ok */
+ memset(&info->attr, 0, sizeof(info->attr));
+@@ -169,7 +168,7 @@ static struct inode *mqueue_get_inode(st
+ /* all is ok */
+ info->user = get_uid(u);
+ } else if (S_ISDIR(mode)) {
+- inode->i_nlink++;
++ inc_nlink(inode);
+ /* Some things misbehave if size == 0 on a directory */
+ inode->i_size = 2 * DIRENT_SIZE;
+ inode->i_op = &mqueue_dir_inode_operations;
+@@ -308,7 +307,7 @@ static int mqueue_unlink(struct inode *d
+
+ dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+ dir->i_size -= DIRENT_SIZE;
+- inode->i_nlink--;
++ drop_nlink(inode);
+ dput(dentry);
+ return 0;
+ }
+@@ -339,7 +338,7 @@ static ssize_t mqueue_read_file(struct f
+ (info->notify_owner &&
+ info->notify.sigev_notify == SIGEV_SIGNAL) ?
+ info->notify.sigev_signo : 0,
+- info->notify_owner);
++ pid_nr(info->notify_owner));
+ spin_unlock(&info->lock);
+ buffer[sizeof(buffer)-1] = '\0';
+ slen = strlen(buffer)+1;
+@@ -364,7 +363,7 @@ static int mqueue_flush_file(struct file
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+
+ spin_lock(&info->lock);
+- if (current->tgid == info->notify_owner)
++ if (task_tgid(current) == info->notify_owner)
+ remove_notification(info);
+
+ spin_unlock(&info->lock);
+@@ -519,8 +518,8 @@ static void __do_notify(struct mqueue_in
+ sig_i.si_pid = current->tgid;
+ sig_i.si_uid = current->uid;
+
+- kill_proc_info(info->notify.sigev_signo,
+- &sig_i, info->notify_owner);
++ kill_pid_info(info->notify.sigev_signo,
++ &sig_i, info->notify_owner);
+ break;
+ case SIGEV_THREAD:
+ set_cookie(info->notify_cookie, NOTIFY_WOKENUP);
+@@ -529,7 +528,8 @@ static void __do_notify(struct mqueue_in
+ break;
+ }
+ /* after notification unregisters process */
+- info->notify_owner = 0;
++ put_pid(info->notify_owner);
++ info->notify_owner = NULL;
+ }
+ wake_up(&info->wait_q);
+ }
+@@ -567,12 +567,13 @@ static long prepare_timeout(const struct
+
+ static void remove_notification(struct mqueue_inode_info *info)
+ {
+- if (info->notify_owner != 0 &&
++ if (info->notify_owner != NULL &&
+ info->notify.sigev_notify == SIGEV_THREAD) {
+ set_cookie(info->notify_cookie, NOTIFY_REMOVED);
+ netlink_sendskb(info->notify_sock, info->notify_cookie, 0);
+ }
+- info->notify_owner = 0;
++ put_pid(info->notify_owner);
++ info->notify_owner = NULL;
+ }
+
+ static int mq_attr_ok(struct mq_attr *attr)
+@@ -1063,11 +1064,11 @@ retry:
+ ret = 0;
+ spin_lock(&info->lock);
+ if (u_notification == NULL) {
+- if (info->notify_owner == current->tgid) {
++ if (info->notify_owner == task_tgid(current)) {
+ remove_notification(info);
+ inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ }
+- } else if (info->notify_owner != 0) {
++ } else if (info->notify_owner != NULL) {
+ ret = -EBUSY;
+ } else {
+ switch (notification.sigev_notify) {
+@@ -1087,7 +1088,8 @@ retry:
+ info->notify.sigev_notify = SIGEV_SIGNAL;
+ break;
+ }
+- info->notify_owner = current->tgid;
++
++ info->notify_owner = get_pid(task_tgid(current));
+ inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ }
+ spin_unlock(&info->lock);
+@@ -1275,10 +1277,7 @@ out_filesystem:
+ out_sysctl:
+ if (mq_sysctl_table)
+ unregister_sysctl_table(mq_sysctl_table);
+- if (kmem_cache_destroy(mqueue_inode_cachep)) {
+- printk(KERN_INFO
+- "mqueue_inode_cache: not all structures were freed\n");
+- }
++ kmem_cache_destroy(mqueue_inode_cachep);
+ return error;
+ }
+
+diff --git a/ipc/msg.c b/ipc/msg.c
+index 2b4fccf..1266b1d 100644
+--- a/ipc/msg.c
++++ b/ipc/msg.c
+@@ -16,6 +16,10 @@
+ *
+ * support for audit of ipc object properties and permission changes
+ * Dustin Kirkland <dustin.kirkland at us.ibm.com>
++ *
++ * namespaces support
++ * OpenVZ, SWsoft Inc.
++ * Pavel Emelianov <xemul at openvz.org>
+ */
+
+ #include <linux/capability.h>
+@@ -31,16 +35,12 @@
+ #include <linux/audit.h>
+ #include <linux/seq_file.h>
+ #include <linux/mutex.h>
++#include <linux/nsproxy.h>
+
+ #include <asm/current.h>
+ #include <asm/uaccess.h>
+ #include "util.h"
+
+-/* sysctl: */
+-int msg_ctlmax = MSGMAX;
+-int msg_ctlmnb = MSGMNB;
+-int msg_ctlmni = MSGMNI;
+-
+ /*
+ * one msg_receiver structure for each sleeping receiver:
+ */
+@@ -52,7 +52,7 @@ struct msg_receiver {
+ long r_msgtype;
+ long r_maxsize;
+
+- volatile struct msg_msg *r_msg;
++ struct msg_msg *volatile r_msg;
+ };
+
+ /* one msg_sender for each sleeping sender */
+@@ -69,30 +69,76 @@ struct msg_sender {
+ static atomic_t msg_bytes = ATOMIC_INIT(0);
+ static atomic_t msg_hdrs = ATOMIC_INIT(0);
+
+-static struct ipc_ids msg_ids;
++static struct ipc_ids init_msg_ids;
+
+-#define msg_lock(id) ((struct msg_queue *)ipc_lock(&msg_ids, id))
+-#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
+-#define msg_rmid(id) ((struct msg_queue *)ipc_rmid(&msg_ids, id))
+-#define msg_checkid(msq, msgid) ipc_checkid(&msg_ids, &msq->q_perm, msgid)
+-#define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq)
++#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS]))
+
+-static void freeque(struct msg_queue *msq, int id);
+-static int newque(key_t key, int msgflg);
++#define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id))
++#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
++#define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id))
++#define msg_checkid(ns, msq, msgid) \
++ ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid)
++#define msg_buildid(ns, id, seq) \
++ ipc_buildid(&msg_ids(ns), id, seq)
++
++static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id);
++static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
+ #ifdef CONFIG_PROC_FS
+ static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
+ #endif
+
++static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
++{
++ ns->ids[IPC_MSG_IDS] = ids;
++ ns->msg_ctlmax = MSGMAX;
++ ns->msg_ctlmnb = MSGMNB;
++ ns->msg_ctlmni = MSGMNI;
++ ipc_init_ids(ids, ns->msg_ctlmni);
++}
++
++#ifdef CONFIG_IPC_NS
++int msg_init_ns(struct ipc_namespace *ns)
++{
++ struct ipc_ids *ids;
++
++ ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
++ if (ids == NULL)
++ return -ENOMEM;
++
++ __msg_init_ns(ns, ids);
++ return 0;
++}
++
++void msg_exit_ns(struct ipc_namespace *ns)
++{
++ int i;
++ struct msg_queue *msq;
++
++ mutex_lock(&msg_ids(ns).mutex);
++ for (i = 0; i <= msg_ids(ns).max_id; i++) {
++ msq = msg_lock(ns, i);
++ if (msq == NULL)
++ continue;
++
++ freeque(ns, msq, i);
++ }
++ mutex_unlock(&msg_ids(ns).mutex);
++
++ ipc_fini_ids(ns->ids[IPC_MSG_IDS]);
++ kfree(ns->ids[IPC_MSG_IDS]);
++ ns->ids[IPC_MSG_IDS] = NULL;
++}
++#endif
++
+ void __init msg_init(void)
+ {
+- ipc_init_ids(&msg_ids, msg_ctlmni);
++ __msg_init_ns(&init_ipc_ns, &init_msg_ids);
+ ipc_init_proc_interface("sysvipc/msg",
+ " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
+- &msg_ids,
+- sysvipc_msg_proc_show);
++ IPC_MSG_IDS, sysvipc_msg_proc_show);
+ }
+
+-static int newque(key_t key, int msgflg)
++static int newque (struct ipc_namespace *ns, key_t key, int msgflg)
+ {
+ struct msg_queue *msq;
+ int id, retval;
+@@ -111,18 +157,18 @@ static int newque(key_t key, int msgflg)
+ return retval;
+ }
+
+- id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
++ id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
+ if (id == -1) {
+ security_msg_queue_free(msq);
+ ipc_rcu_putref(msq);
+ return -ENOSPC;
+ }
+
+- msq->q_id = msg_buildid(id, msq->q_perm.seq);
++ msq->q_id = msg_buildid(ns, id, msq->q_perm.seq);
+ msq->q_stime = msq->q_rtime = 0;
+ msq->q_ctime = get_seconds();
+ msq->q_cbytes = msq->q_qnum = 0;
+- msq->q_qbytes = msg_ctlmnb;
++ msq->q_qbytes = ns->msg_ctlmnb;
+ msq->q_lspid = msq->q_lrpid = 0;
+ INIT_LIST_HEAD(&msq->q_messages);
+ INIT_LIST_HEAD(&msq->q_receivers);
+@@ -186,13 +232,13 @@ static void expunge_all(struct msg_queue
+ * msg_ids.mutex and the spinlock for this message queue is hold
+ * before freeque() is called. msg_ids.mutex remains locked on exit.
+ */
+-static void freeque(struct msg_queue *msq, int id)
++static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id)
+ {
+ struct list_head *tmp;
+
+ expunge_all(msq, -EIDRM);
+ ss_wakeup(&msq->q_senders, 1);
+- msq = msg_rmid(id);
++ msq = msg_rmid(ns, id);
+ msg_unlock(msq);
+
+ tmp = msq->q_messages.next;
+@@ -212,24 +258,27 @@ asmlinkage long sys_msgget(key_t key, in
+ {
+ struct msg_queue *msq;
+ int id, ret = -EPERM;
++ struct ipc_namespace *ns;
++
++ ns = current->nsproxy->ipc_ns;
+
+- mutex_lock(&msg_ids.mutex);
++ mutex_lock(&msg_ids(ns).mutex);
+ if (key == IPC_PRIVATE)
+- ret = newque(key, msgflg);
+- else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
++ ret = newque(ns, key, msgflg);
++ else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */
+ if (!(msgflg & IPC_CREAT))
+ ret = -ENOENT;
+ else
+- ret = newque(key, msgflg);
++ ret = newque(ns, key, msgflg);
+ } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
+ ret = -EEXIST;
+ } else {
+- msq = msg_lock(id);
++ msq = msg_lock(ns, id);
+ BUG_ON(msq == NULL);
+ if (ipcperms(&msq->q_perm, msgflg))
+ ret = -EACCES;
+ else {
+- int qid = msg_buildid(id, msq->q_perm.seq);
++ int qid = msg_buildid(ns, id, msq->q_perm.seq);
+
+ ret = security_msg_queue_associate(msq, msgflg);
+ if (!ret)
+@@ -237,7 +286,7 @@ asmlinkage long sys_msgget(key_t key, in
+ }
+ msg_unlock(msq);
+ }
+- mutex_unlock(&msg_ids.mutex);
++ mutex_unlock(&msg_ids(ns).mutex);
+
+ return ret;
+ }
+@@ -341,11 +390,13 @@ asmlinkage long sys_msgctl(int msqid, in
+ struct msq_setbuf setbuf;
+ struct msg_queue *msq;
+ int err, version;
++ struct ipc_namespace *ns;
+
+ if (msqid < 0 || cmd < 0)
+ return -EINVAL;
+
+ version = ipc_parse_version(&cmd);
++ ns = current->nsproxy->ipc_ns;
+
+ switch (cmd) {
+ case IPC_INFO:
+@@ -366,14 +417,14 @@ asmlinkage long sys_msgctl(int msqid, in
+ return err;
+
+ memset(&msginfo, 0, sizeof(msginfo));
+- msginfo.msgmni = msg_ctlmni;
+- msginfo.msgmax = msg_ctlmax;
+- msginfo.msgmnb = msg_ctlmnb;
++ msginfo.msgmni = ns->msg_ctlmni;
++ msginfo.msgmax = ns->msg_ctlmax;
++ msginfo.msgmnb = ns->msg_ctlmnb;
+ msginfo.msgssz = MSGSSZ;
+ msginfo.msgseg = MSGSEG;
+- mutex_lock(&msg_ids.mutex);
++ mutex_lock(&msg_ids(ns).mutex);
+ if (cmd == MSG_INFO) {
+- msginfo.msgpool = msg_ids.in_use;
++ msginfo.msgpool = msg_ids(ns).in_use;
+ msginfo.msgmap = atomic_read(&msg_hdrs);
+ msginfo.msgtql = atomic_read(&msg_bytes);
+ } else {
+@@ -381,8 +432,8 @@ asmlinkage long sys_msgctl(int msqid, in
+ msginfo.msgpool = MSGPOOL;
+ msginfo.msgtql = MSGTQL;
+ }
+- max_id = msg_ids.max_id;
+- mutex_unlock(&msg_ids.mutex);
++ max_id = msg_ids(ns).max_id;
++ mutex_unlock(&msg_ids(ns).mutex);
+ if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
+ return -EFAULT;
+ return (max_id < 0) ? 0 : max_id;
+@@ -395,20 +446,20 @@ asmlinkage long sys_msgctl(int msqid, in
+
+ if (!buf)
+ return -EFAULT;
+- if (cmd == MSG_STAT && msqid >= msg_ids.entries->size)
++ if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
+ return -EINVAL;
+
+ memset(&tbuf, 0, sizeof(tbuf));
+
+- msq = msg_lock(msqid);
++ msq = msg_lock(ns, msqid);
+ if (msq == NULL)
+ return -EINVAL;
+
+ if (cmd == MSG_STAT) {
+- success_return = msg_buildid(msqid, msq->q_perm.seq);
++ success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
+ } else {
+ err = -EIDRM;
+- if (msg_checkid(msq, msqid))
++ if (msg_checkid(ns, msq, msqid))
+ goto out_unlock;
+ success_return = 0;
+ }
+@@ -446,14 +497,14 @@ asmlinkage long sys_msgctl(int msqid, in
+ return -EINVAL;
+ }
+
+- mutex_lock(&msg_ids.mutex);
+- msq = msg_lock(msqid);
++ mutex_lock(&msg_ids(ns).mutex);
++ msq = msg_lock(ns, msqid);
+ err = -EINVAL;
+ if (msq == NULL)
+ goto out_up;
+
+ err = -EIDRM;
+- if (msg_checkid(msq, msqid))
++ if (msg_checkid(ns, msq, msqid))
+ goto out_unlock_up;
+ ipcp = &msq->q_perm;
+
+@@ -481,7 +532,7 @@ asmlinkage long sys_msgctl(int msqid, in
+ case IPC_SET:
+ {
+ err = -EPERM;
+- if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
++ if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
+ goto out_unlock_up;
+
+ msq->q_qbytes = setbuf.qbytes;
+@@ -503,12 +554,12 @@ asmlinkage long sys_msgctl(int msqid, in
+ break;
+ }
+ case IPC_RMID:
+- freeque(msq, msqid);
++ freeque(ns, msq, msqid);
+ break;
+ }
+ err = 0;
+ out_up:
+- mutex_unlock(&msg_ids.mutex);
++ mutex_unlock(&msg_ids(ns).mutex);
+ return err;
+ out_unlock_up:
+ msg_unlock(msq);
+@@ -582,8 +633,11 @@ sys_msgsnd(int msqid, struct msgbuf __us
+ struct msg_msg *msg;
+ long mtype;
+ int err;
++ struct ipc_namespace *ns;
++
++ ns = current->nsproxy->ipc_ns;
+
+- if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
++ if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
+ return -EINVAL;
+ if (get_user(mtype, &msgp->mtype))
+ return -EFAULT;
+@@ -597,13 +651,13 @@ sys_msgsnd(int msqid, struct msgbuf __us
+ msg->m_type = mtype;
+ msg->m_ts = msgsz;
+
+- msq = msg_lock(msqid);
++ msq = msg_lock(ns, msqid);
+ err = -EINVAL;
+ if (msq == NULL)
+ goto out_free;
+
+ err= -EIDRM;
+- if (msg_checkid(msq, msqid))
++ if (msg_checkid(ns, msq, msqid))
+ goto out_unlock_free;
+
+ for (;;) {
+@@ -694,17 +748,19 @@ asmlinkage long sys_msgrcv(int msqid, st
+ struct msg_queue *msq;
+ struct msg_msg *msg;
+ int mode;
++ struct ipc_namespace *ns;
+
+ if (msqid < 0 || (long) msgsz < 0)
+ return -EINVAL;
+ mode = convert_mode(&msgtyp, msgflg);
++ ns = current->nsproxy->ipc_ns;
+
+- msq = msg_lock(msqid);
++ msq = msg_lock(ns, msqid);
+ if (msq == NULL)
+ return -EINVAL;
+
+ msg = ERR_PTR(-EIDRM);
+- if (msg_checkid(msq, msqid))
++ if (msg_checkid(ns, msq, msqid))
+ goto out_unlock;
+
+ for (;;) {
+diff --git a/ipc/msgutil.c b/ipc/msgutil.c
+index 66cfb87..0992616 100644
+--- a/ipc/msgutil.c
++++ b/ipc/msgutil.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/ipc/util.c
++ * linux/ipc/msgutil.c
+ * Copyright (C) 1999, 2004 Manfred Spraul
+ *
+ * This file is released under GNU General Public Licence version 2 or
+diff --git a/ipc/sem.c b/ipc/sem.c
+index 6013c75..21b3289 100644
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -64,6 +64,10 @@
+ *
+ * support for audit of ipc object properties and permission changes
+ * Dustin Kirkland <dustin.kirkland at us.ibm.com>
++ *
++ * namespaces support
++ * OpenVZ, SWsoft Inc.
++ * Pavel Emelianov <xemul at openvz.org>
+ */
+
+ #include <linux/slab.h>
+@@ -78,22 +82,25 @@
+ #include <linux/capability.h>
+ #include <linux/seq_file.h>
+ #include <linux/mutex.h>
++#include <linux/nsproxy.h>
+
+ #include <asm/uaccess.h>
+ #include "util.h"
+
++#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS]))
++
++#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id))
++#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
++#define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id))
++#define sem_checkid(ns, sma, semid) \
++ ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid)
++#define sem_buildid(ns, id, seq) \
++ ipc_buildid(&sem_ids(ns), id, seq)
+
+-#define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id))
+-#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
+-#define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id))
+-#define sem_checkid(sma, semid) \
+- ipc_checkid(&sem_ids,&sma->sem_perm,semid)
+-#define sem_buildid(id, seq) \
+- ipc_buildid(&sem_ids, id, seq)
+-static struct ipc_ids sem_ids;
++static struct ipc_ids init_sem_ids;
+
+-static int newary (key_t, int, int);
+-static void freeary (struct sem_array *sma, int id);
++static int newary(struct ipc_namespace *, key_t, int, int);
++static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id);
+ #ifdef CONFIG_PROC_FS
+ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
+ #endif
+@@ -110,22 +117,62 @@ static int sysvipc_sem_proc_show(struct
+ *
+ */
+
+-int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI};
+-#define sc_semmsl (sem_ctls[0])
+-#define sc_semmns (sem_ctls[1])
+-#define sc_semopm (sem_ctls[2])
+-#define sc_semmni (sem_ctls[3])
++#define sc_semmsl sem_ctls[0]
++#define sc_semmns sem_ctls[1]
++#define sc_semopm sem_ctls[2]
++#define sc_semmni sem_ctls[3]
+
+-static int used_sems;
++static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
++{
++ ns->ids[IPC_SEM_IDS] = ids;
++ ns->sc_semmsl = SEMMSL;
++ ns->sc_semmns = SEMMNS;
++ ns->sc_semopm = SEMOPM;
++ ns->sc_semmni = SEMMNI;
++ ns->used_sems = 0;
++ ipc_init_ids(ids, ns->sc_semmni);
++}
++
++#ifdef CONFIG_IPC_NS
++int sem_init_ns(struct ipc_namespace *ns)
++{
++ struct ipc_ids *ids;
++
++ ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
++ if (ids == NULL)
++ return -ENOMEM;
++
++ __sem_init_ns(ns, ids);
++ return 0;
++}
++
++void sem_exit_ns(struct ipc_namespace *ns)
++{
++ int i;
++ struct sem_array *sma;
++
++ mutex_lock(&sem_ids(ns).mutex);
++ for (i = 0; i <= sem_ids(ns).max_id; i++) {
++ sma = sem_lock(ns, i);
++ if (sma == NULL)
++ continue;
++
++ freeary(ns, sma, i);
++ }
++ mutex_unlock(&sem_ids(ns).mutex);
++
++ ipc_fini_ids(ns->ids[IPC_SEM_IDS]);
++ kfree(ns->ids[IPC_SEM_IDS]);
++ ns->ids[IPC_SEM_IDS] = NULL;
++}
++#endif
+
+ void __init sem_init (void)
+ {
+- used_sems = 0;
+- ipc_init_ids(&sem_ids,sc_semmni);
++ __sem_init_ns(&init_ipc_ns, &init_sem_ids);
+ ipc_init_proc_interface("sysvipc/sem",
+ " key semid perms nsems uid gid cuid cgid otime ctime\n",
+- &sem_ids,
+- sysvipc_sem_proc_show);
++ IPC_SEM_IDS, sysvipc_sem_proc_show);
+ }
+
+ /*
+@@ -162,7 +209,7 @@ void __init sem_init (void)
+ */
+ #define IN_WAKEUP 1
+
+-static int newary (key_t key, int nsems, int semflg)
++static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
+ {
+ int id;
+ int retval;
+@@ -171,7 +218,7 @@ static int newary (key_t key, int nsems,
+
+ if (!nsems)
+ return -EINVAL;
+- if (used_sems + nsems > sc_semmns)
++ if (ns->used_sems + nsems > ns->sc_semmns)
+ return -ENOSPC;
+
+ size = sizeof (*sma) + nsems * sizeof (struct sem);
+@@ -191,15 +238,15 @@ static int newary (key_t key, int nsems,
+ return retval;
+ }
+
+- id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
++ id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+ if(id == -1) {
+ security_sem_free(sma);
+ ipc_rcu_putref(sma);
+ return -ENOSPC;
+ }
+- used_sems += nsems;
++ ns->used_sems += nsems;
+
+- sma->sem_id = sem_buildid(id, sma->sem_perm.seq);
++ sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq);
+ sma->sem_base = (struct sem *) &sma[1];
+ /* sma->sem_pending = NULL; */
+ sma->sem_pending_last = &sma->sem_pending;
+@@ -215,29 +262,32 @@ asmlinkage long sys_semget (key_t key, i
+ {
+ int id, err = -EINVAL;
+ struct sem_array *sma;
++ struct ipc_namespace *ns;
+
+- if (nsems < 0 || nsems > sc_semmsl)
++ ns = current->nsproxy->ipc_ns;
++
++ if (nsems < 0 || nsems > ns->sc_semmsl)
+ return -EINVAL;
+- mutex_lock(&sem_ids.mutex);
++ mutex_lock(&sem_ids(ns).mutex);
+
+ if (key == IPC_PRIVATE) {
+- err = newary(key, nsems, semflg);
+- } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */
++ err = newary(ns, key, nsems, semflg);
++ } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */
+ if (!(semflg & IPC_CREAT))
+ err = -ENOENT;
+ else
+- err = newary(key, nsems, semflg);
++ err = newary(ns, key, nsems, semflg);
+ } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
+ err = -EEXIST;
+ } else {
+- sma = sem_lock(id);
++ sma = sem_lock(ns, id);
+ BUG_ON(sma==NULL);
+ if (nsems > sma->sem_nsems)
+ err = -EINVAL;
+ else if (ipcperms(&sma->sem_perm, semflg))
+ err = -EACCES;
+ else {
+- int semid = sem_buildid(id, sma->sem_perm.seq);
++ int semid = sem_buildid(ns, id, sma->sem_perm.seq);
+ err = security_sem_associate(sma, semflg);
+ if (!err)
+ err = semid;
+@@ -245,7 +295,7 @@ asmlinkage long sys_semget (key_t key, i
+ sem_unlock(sma);
+ }
+
+- mutex_unlock(&sem_ids.mutex);
++ mutex_unlock(&sem_ids(ns).mutex);
+ return err;
+ }
+
+@@ -444,7 +494,7 @@ static int count_semzcnt (struct sem_arr
+ * the spinlock for this semaphore set hold. sem_ids.mutex remains locked
+ * on exit.
+ */
+-static void freeary (struct sem_array *sma, int id)
++static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id)
+ {
+ struct sem_undo *un;
+ struct sem_queue *q;
+@@ -472,10 +522,10 @@ static void freeary (struct sem_array *s
+ }
+
+ /* Remove the semaphore set from the ID array*/
+- sma = sem_rmid(id);
++ sma = sem_rmid(ns, id);
+ sem_unlock(sma);
+
+- used_sems -= sma->sem_nsems;
++ ns->used_sems -= sma->sem_nsems;
+ size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
+ security_sem_free(sma);
+ ipc_rcu_putref(sma);
+@@ -503,7 +553,8 @@ static unsigned long copy_semid_to_user(
+ }
+ }
+
+-static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
++static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
++ int cmd, int version, union semun arg)
+ {
+ int err = -EINVAL;
+ struct sem_array *sma;
+@@ -520,24 +571,24 @@ static int semctl_nolock(int semid, int
+ return err;
+
+ memset(&seminfo,0,sizeof(seminfo));
+- seminfo.semmni = sc_semmni;
+- seminfo.semmns = sc_semmns;
+- seminfo.semmsl = sc_semmsl;
+- seminfo.semopm = sc_semopm;
++ seminfo.semmni = ns->sc_semmni;
++ seminfo.semmns = ns->sc_semmns;
++ seminfo.semmsl = ns->sc_semmsl;
++ seminfo.semopm = ns->sc_semopm;
+ seminfo.semvmx = SEMVMX;
+ seminfo.semmnu = SEMMNU;
+ seminfo.semmap = SEMMAP;
+ seminfo.semume = SEMUME;
+- mutex_lock(&sem_ids.mutex);
++ mutex_lock(&sem_ids(ns).mutex);
+ if (cmd == SEM_INFO) {
+- seminfo.semusz = sem_ids.in_use;
+- seminfo.semaem = used_sems;
++ seminfo.semusz = sem_ids(ns).in_use;
++ seminfo.semaem = ns->used_sems;
+ } else {
+ seminfo.semusz = SEMUSZ;
+ seminfo.semaem = SEMAEM;
+ }
+- max_id = sem_ids.max_id;
+- mutex_unlock(&sem_ids.mutex);
++ max_id = sem_ids(ns).max_id;
++ mutex_unlock(&sem_ids(ns).mutex);
+ if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
+ return -EFAULT;
+ return (max_id < 0) ? 0: max_id;
+@@ -547,12 +598,12 @@ static int semctl_nolock(int semid, int
+ struct semid64_ds tbuf;
+ int id;
+
+- if(semid >= sem_ids.entries->size)
++ if(semid >= sem_ids(ns).entries->size)
+ return -EINVAL;
+
+ memset(&tbuf,0,sizeof(tbuf));
+
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ if(sma == NULL)
+ return -EINVAL;
+
+@@ -564,7 +615,7 @@ static int semctl_nolock(int semid, int
+ if (err)
+ goto out_unlock;
+
+- id = sem_buildid(semid, sma->sem_perm.seq);
++ id = sem_buildid(ns, semid, sma->sem_perm.seq);
+
+ kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
+ tbuf.sem_otime = sma->sem_otime;
+@@ -584,7 +635,8 @@ out_unlock:
+ return err;
+ }
+
+-static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
++static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
++ int cmd, int version, union semun arg)
+ {
+ struct sem_array *sma;
+ struct sem* curr;
+@@ -593,14 +645,14 @@ static int semctl_main(int semid, int se
+ ushort* sem_io = fast_sem_io;
+ int nsems;
+
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ if(sma==NULL)
+ return -EINVAL;
+
+ nsems = sma->sem_nsems;
+
+ err=-EIDRM;
+- if (sem_checkid(sma,semid))
++ if (sem_checkid(ns,sma,semid))
+ goto out_unlock;
+
+ err = -EACCES;
+@@ -802,7 +854,8 @@ static inline unsigned long copy_semid_f
+ }
+ }
+
+-static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
++static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
++ int cmd, int version, union semun arg)
+ {
+ struct sem_array *sma;
+ int err;
+@@ -813,11 +866,11 @@ static int semctl_down(int semid, int se
+ if(copy_semid_from_user (&setbuf, arg.buf, version))
+ return -EFAULT;
+ }
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ if(sma==NULL)
+ return -EINVAL;
+
+- if (sem_checkid(sma,semid)) {
++ if (sem_checkid(ns,sma,semid)) {
+ err=-EIDRM;
+ goto out_unlock;
+ }
+@@ -844,7 +897,7 @@ static int semctl_down(int semid, int se
+
+ switch(cmd){
+ case IPC_RMID:
+- freeary(sma, semid);
++ freeary(ns, sma, semid);
+ err = 0;
+ break;
+ case IPC_SET:
+@@ -872,17 +925,19 @@ asmlinkage long sys_semctl (int semid, i
+ {
+ int err = -EINVAL;
+ int version;
++ struct ipc_namespace *ns;
+
+ if (semid < 0)
+ return -EINVAL;
+
+ version = ipc_parse_version(&cmd);
++ ns = current->nsproxy->ipc_ns;
+
+ switch(cmd) {
+ case IPC_INFO:
+ case SEM_INFO:
+ case SEM_STAT:
+- err = semctl_nolock(semid,semnum,cmd,version,arg);
++ err = semctl_nolock(ns,semid,semnum,cmd,version,arg);
+ return err;
+ case GETALL:
+ case GETVAL:
+@@ -892,13 +947,13 @@ asmlinkage long sys_semctl (int semid, i
+ case IPC_STAT:
+ case SETVAL:
+ case SETALL:
+- err = semctl_main(semid,semnum,cmd,version,arg);
++ err = semctl_main(ns,semid,semnum,cmd,version,arg);
+ return err;
+ case IPC_RMID:
+ case IPC_SET:
+- mutex_lock(&sem_ids.mutex);
+- err = semctl_down(semid,semnum,cmd,version,arg);
+- mutex_unlock(&sem_ids.mutex);
++ mutex_lock(&sem_ids(ns).mutex);
++ err = semctl_down(ns,semid,semnum,cmd,version,arg);
++ mutex_unlock(&sem_ids(ns).mutex);
+ return err;
+ default:
+ return -EINVAL;
+@@ -949,15 +1004,12 @@ static inline void unlock_semundo(void)
+ static inline int get_undo_list(struct sem_undo_list **undo_listp)
+ {
+ struct sem_undo_list *undo_list;
+- int size;
+
+ undo_list = current->sysvsem.undo_list;
+ if (!undo_list) {
+- size = sizeof(struct sem_undo_list);
+- undo_list = (struct sem_undo_list *) kmalloc(size, GFP_KERNEL);
++ undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL);
+ if (undo_list == NULL)
+ return -ENOMEM;
+- memset(undo_list, 0, size);
+ spin_lock_init(&undo_list->lock);
+ atomic_set(&undo_list->refcnt, 1);
+ current->sysvsem.undo_list = undo_list;
+@@ -986,7 +1038,7 @@ static struct sem_undo *lookup_undo(stru
+ return un;
+ }
+
+-static struct sem_undo *find_undo(int semid)
++static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
+ {
+ struct sem_array *sma;
+ struct sem_undo_list *ulp;
+@@ -1005,12 +1057,12 @@ static struct sem_undo *find_undo(int se
+ goto out;
+
+ /* no undo structure around - allocate one. */
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ un = ERR_PTR(-EINVAL);
+ if(sma==NULL)
+ goto out;
+ un = ERR_PTR(-EIDRM);
+- if (sem_checkid(sma,semid)) {
++ if (sem_checkid(ns,sma,semid)) {
+ sem_unlock(sma);
+ goto out;
+ }
+@@ -1070,10 +1122,13 @@ asmlinkage long sys_semtimedop(int semid
+ int undos = 0, alter = 0, max;
+ struct sem_queue queue;
+ unsigned long jiffies_left = 0;
++ struct ipc_namespace *ns;
++
++ ns = current->nsproxy->ipc_ns;
+
+ if (nsops < 1 || semid < 0)
+ return -EINVAL;
+- if (nsops > sc_semopm)
++ if (nsops > ns->sc_semopm)
+ return -E2BIG;
+ if(nsops > SEMOPM_FAST) {
+ sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
+@@ -1109,7 +1164,7 @@ asmlinkage long sys_semtimedop(int semid
+
+ retry_undos:
+ if (undos) {
+- un = find_undo(semid);
++ un = find_undo(ns, semid);
+ if (IS_ERR(un)) {
+ error = PTR_ERR(un);
+ goto out_free;
+@@ -1117,12 +1172,12 @@ retry_undos:
+ } else
+ un = NULL;
+
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ error=-EINVAL;
+ if(sma==NULL)
+ goto out_free;
+ error = -EIDRM;
+- if (sem_checkid(sma,semid))
++ if (sem_checkid(ns,sma,semid))
+ goto out_unlock_free;
+ /*
+ * semid identifies are not unique - find_undo may have
+@@ -1190,7 +1245,7 @@ retry_undos:
+ goto out_free;
+ }
+
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ if(sma==NULL) {
+ BUG_ON(queue.prev != NULL);
+ error = -EIDRM;
+@@ -1267,6 +1322,7 @@ void exit_sem(struct task_struct *tsk)
+ {
+ struct sem_undo_list *undo_list;
+ struct sem_undo *u, **up;
++ struct ipc_namespace *ns;
+
+ undo_list = tsk->sysvsem.undo_list;
+ if (!undo_list)
+@@ -1275,6 +1331,7 @@ void exit_sem(struct task_struct *tsk)
+ if (!atomic_dec_and_test(&undo_list->refcnt))
+ return;
+
++ ns = tsk->nsproxy->ipc_ns;
+ /* There's no need to hold the semundo list lock, as current
+ * is the last task exiting for this undo list.
+ */
+@@ -1288,14 +1345,14 @@ void exit_sem(struct task_struct *tsk)
+
+ if(semid == -1)
+ continue;
+- sma = sem_lock(semid);
++ sma = sem_lock(ns, semid);
+ if (sma == NULL)
+ continue;
+
+ if (u->semid == -1)
+ goto next_entry;
+
+- BUG_ON(sem_checkid(sma,u->semid));
++ BUG_ON(sem_checkid(ns,sma,u->semid));
+
+ /* remove u from the sma->undo list */
+ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
+diff --git a/ipc/shm.c b/ipc/shm.c
+index 940b0c9..d1198dd 100644
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -15,6 +15,10 @@
+ *
+ * support for audit of ipc object properties and permission changes
+ * Dustin Kirkland <dustin.kirkland at us.ibm.com>
++ *
++ * namespaces support
++ * OpenVZ, SWsoft Inc.
++ * Pavel Emelianov <xemul at openvz.org>
+ */
+
+ #include <linux/slab.h>
+@@ -32,6 +36,7 @@
+ #include <linux/ptrace.h>
+ #include <linux/seq_file.h>
+ #include <linux/mutex.h>
++#include <linux/nsproxy.h>
+
+ #include <asm/uaccess.h>
+
+@@ -40,59 +45,116 @@
+ static struct file_operations shm_file_operations;
+ static struct vm_operations_struct shm_vm_ops;
+
+-static struct ipc_ids shm_ids;
++static struct ipc_ids init_shm_ids;
++
++#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS]))
+
+-#define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id))
+-#define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm)
+-#define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id))
+-#define shm_buildid(id, seq) \
+- ipc_buildid(&shm_ids, id, seq)
++#define shm_lock(ns, id) \
++ ((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id))
++#define shm_unlock(shp) \
++ ipc_unlock(&(shp)->shm_perm)
++#define shm_get(ns, id) \
++ ((struct shmid_kernel*)ipc_get(&shm_ids(ns),id))
++#define shm_buildid(ns, id, seq) \
++ ipc_buildid(&shm_ids(ns), id, seq)
+
+-static int newseg (key_t key, int shmflg, size_t size);
++static int newseg (struct ipc_namespace *ns, key_t key,
++ int shmflg, size_t size);
+ static void shm_open (struct vm_area_struct *shmd);
+ static void shm_close (struct vm_area_struct *shmd);
++static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
+ #ifdef CONFIG_PROC_FS
+ static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
+ #endif
+
+-size_t shm_ctlmax = SHMMAX;
+-size_t shm_ctlall = SHMALL;
+-int shm_ctlmni = SHMMNI;
++static void __ipc_init __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
++{
++ ns->ids[IPC_SHM_IDS] = ids;
++ ns->shm_ctlmax = SHMMAX;
++ ns->shm_ctlall = SHMALL;
++ ns->shm_ctlmni = SHMMNI;
++ ns->shm_tot = 0;
++ ipc_init_ids(ids, 1);
++}
++
++static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
++{
++ if (shp->shm_nattch){
++ shp->shm_perm.mode |= SHM_DEST;
++ /* Do not find it any more */
++ shp->shm_perm.key = IPC_PRIVATE;
++ shm_unlock(shp);
++ } else
++ shm_destroy(ns, shp);
++}
++
++#ifdef CONFIG_IPC_NS
++int shm_init_ns(struct ipc_namespace *ns)
++{
++ struct ipc_ids *ids;
++
++ ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
++ if (ids == NULL)
++ return -ENOMEM;
+
+-static int shm_tot; /* total number of shared memory pages */
++ __shm_init_ns(ns, ids);
++ return 0;
++}
++
++void shm_exit_ns(struct ipc_namespace *ns)
++{
++ int i;
++ struct shmid_kernel *shp;
++
++ mutex_lock(&shm_ids(ns).mutex);
++ for (i = 0; i <= shm_ids(ns).max_id; i++) {
++ shp = shm_lock(ns, i);
++ if (shp == NULL)
++ continue;
++
++ do_shm_rmid(ns, shp);
++ }
++ mutex_unlock(&shm_ids(ns).mutex);
++
++ ipc_fini_ids(ns->ids[IPC_SHM_IDS]);
++ kfree(ns->ids[IPC_SHM_IDS]);
++ ns->ids[IPC_SHM_IDS] = NULL;
++}
++#endif
+
+ void __init shm_init (void)
+ {
+- ipc_init_ids(&shm_ids, 1);
++ __shm_init_ns(&init_ipc_ns, &init_shm_ids);
+ ipc_init_proc_interface("sysvipc/shm",
+ " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n",
+- &shm_ids,
+- sysvipc_shm_proc_show);
++ IPC_SHM_IDS, sysvipc_shm_proc_show);
+ }
+
+-static inline int shm_checkid(struct shmid_kernel *s, int id)
++static inline int shm_checkid(struct ipc_namespace *ns,
++ struct shmid_kernel *s, int id)
+ {
+- if (ipc_checkid(&shm_ids,&s->shm_perm,id))
++ if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id))
+ return -EIDRM;
+ return 0;
+ }
+
+-static inline struct shmid_kernel *shm_rmid(int id)
++static inline struct shmid_kernel *shm_rmid(struct ipc_namespace *ns, int id)
+ {
+- return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
++ return (struct shmid_kernel *)ipc_rmid(&shm_ids(ns), id);
+ }
+
+-static inline int shm_addid(struct shmid_kernel *shp)
++static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
+ {
+- return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
++ return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
+ }
+
+
+
+-static inline void shm_inc (int id) {
++static inline void shm_inc(struct ipc_namespace *ns, int id)
++{
+ struct shmid_kernel *shp;
+
+- shp = shm_lock(id);
++ shp = shm_lock(ns, id);
+ BUG_ON(!shp);
+ shp->shm_atim = get_seconds();
+ shp->shm_lprid = current->tgid;
+@@ -100,10 +162,13 @@ static inline void shm_inc (int id) {
+ shm_unlock(shp);
+ }
+
++#define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data))
++
+ /* This is called by fork, once for every shm attach. */
+-static void shm_open (struct vm_area_struct *shmd)
++static void shm_open(struct vm_area_struct *shmd)
+ {
+- shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
++ shm_inc(shm_file_ns(shmd->vm_file),
++ shmd->vm_file->f_dentry->d_inode->i_ino);
+ }
+
+ /*
+@@ -114,10 +179,10 @@ static void shm_open (struct vm_area_str
+ * It has to be called with shp and shm_ids.mutex locked,
+ * but returns with shp unlocked and freed.
+ */
+-static void shm_destroy (struct shmid_kernel *shp)
++static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
+ {
+- shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
+- shm_rmid (shp->id);
++ ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
++ shm_rmid(ns, shp->id);
+ shm_unlock(shp);
+ if (!is_file_hugepages(shp->shm_file))
+ shmem_lock(shp->shm_file, 0, shp->mlock_user);
+@@ -140,20 +205,23 @@ static void shm_close (struct vm_area_st
+ struct file * file = shmd->vm_file;
+ int id = file->f_dentry->d_inode->i_ino;
+ struct shmid_kernel *shp;
++ struct ipc_namespace *ns;
+
+- mutex_lock(&shm_ids.mutex);
++ ns = shm_file_ns(file);
++
++ mutex_lock(&shm_ids(ns).mutex);
+ /* remove from the list of attaches of the shm segment */
+- shp = shm_lock(id);
++ shp = shm_lock(ns, id);
+ BUG_ON(!shp);
+ shp->shm_lprid = current->tgid;
+ shp->shm_dtim = get_seconds();
+ shp->shm_nattch--;
+ if(shp->shm_nattch == 0 &&
+ shp->shm_perm.mode & SHM_DEST)
+- shm_destroy (shp);
++ shm_destroy(ns, shp);
+ else
+ shm_unlock(shp);
+- mutex_unlock(&shm_ids.mutex);
++ mutex_unlock(&shm_ids(ns).mutex);
+ }
+
+ static int shm_mmap(struct file * file, struct vm_area_struct * vma)
+@@ -165,14 +233,25 @@ static int shm_mmap(struct file * file,
+ vma->vm_ops = &shm_vm_ops;
+ if (!(vma->vm_flags & VM_WRITE))
+ vma->vm_flags &= ~VM_MAYWRITE;
+- shm_inc(file->f_dentry->d_inode->i_ino);
++ shm_inc(shm_file_ns(file), file->f_dentry->d_inode->i_ino);
+ }
+
+ return ret;
+ }
+
++static int shm_release(struct inode *ino, struct file *file)
++{
++ struct ipc_namespace *ns;
++
++ ns = shm_file_ns(file);
++ put_ipc_ns(ns);
++ shm_file_ns(file) = NULL;
++ return 0;
++}
++
+ static struct file_operations shm_file_operations = {
+- .mmap = shm_mmap,
++ .mmap = shm_mmap,
++ .release = shm_release,
+ #ifndef CONFIG_MMU
+ .get_unmapped_area = shmem_get_unmapped_area,
+ #endif
+@@ -188,7 +267,7 @@ static struct vm_operations_struct shm_v
+ #endif
+ };
+
+-static int newseg (key_t key, int shmflg, size_t size)
++static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
+ {
+ int error;
+ struct shmid_kernel *shp;
+@@ -197,10 +276,10 @@ static int newseg (key_t key, int shmflg
+ char name[13];
+ int id;
+
+- if (size < SHMMIN || size > shm_ctlmax)
++ if (size < SHMMIN || size > ns->shm_ctlmax)
+ return -EINVAL;
+
+- if (shm_tot + numpages >= shm_ctlall)
++ if (ns->shm_tot + numpages >= ns->shm_ctlall)
+ return -ENOSPC;
+
+ shp = ipc_rcu_alloc(sizeof(*shp));
+@@ -239,7 +318,7 @@ static int newseg (key_t key, int shmflg
+ goto no_file;
+
+ error = -ENOSPC;
+- id = shm_addid(shp);
++ id = shm_addid(ns, shp);
+ if(id == -1)
+ goto no_id;
+
+@@ -249,15 +328,17 @@ static int newseg (key_t key, int shmflg
+ shp->shm_ctim = get_seconds();
+ shp->shm_segsz = size;
+ shp->shm_nattch = 0;
+- shp->id = shm_buildid(id,shp->shm_perm.seq);
++ shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
+ shp->shm_file = file;
+ file->f_dentry->d_inode->i_ino = shp->id;
+
++ shm_file_ns(file) = get_ipc_ns(ns);
++
+ /* Hugetlb ops would have already been assigned. */
+ if (!(shmflg & SHM_HUGETLB))
+ file->f_op = &shm_file_operations;
+
+- shm_tot += numpages;
++ ns->shm_tot += numpages;
+ shm_unlock(shp);
+ return shp->id;
+
+@@ -273,33 +354,36 @@ asmlinkage long sys_shmget (key_t key, s
+ {
+ struct shmid_kernel *shp;
+ int err, id = 0;
++ struct ipc_namespace *ns;
++
++ ns = current->nsproxy->ipc_ns;
+
+- mutex_lock(&shm_ids.mutex);
++ mutex_lock(&shm_ids(ns).mutex);
+ if (key == IPC_PRIVATE) {
+- err = newseg(key, shmflg, size);
+- } else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
++ err = newseg(ns, key, shmflg, size);
++ } else if ((id = ipc_findkey(&shm_ids(ns), key)) == -1) {
+ if (!(shmflg & IPC_CREAT))
+ err = -ENOENT;
+ else
+- err = newseg(key, shmflg, size);
++ err = newseg(ns, key, shmflg, size);
+ } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
+ err = -EEXIST;
+ } else {
+- shp = shm_lock(id);
++ shp = shm_lock(ns, id);
+ BUG_ON(shp==NULL);
+ if (shp->shm_segsz < size)
+ err = -EINVAL;
+ else if (ipcperms(&shp->shm_perm, shmflg))
+ err = -EACCES;
+ else {
+- int shmid = shm_buildid(id, shp->shm_perm.seq);
++ int shmid = shm_buildid(ns, id, shp->shm_perm.seq);
+ err = security_shm_associate(shp, shmflg);
+ if (!err)
+ err = shmid;
+ }
+ shm_unlock(shp);
+ }
+- mutex_unlock(&shm_ids.mutex);
++ mutex_unlock(&shm_ids(ns).mutex);
+
+ return err;
+ }
+@@ -395,18 +479,19 @@ static inline unsigned long copy_shminfo
+ }
+ }
+
+-static void shm_get_stat(unsigned long *rss, unsigned long *swp)
++static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
++ unsigned long *swp)
+ {
+ int i;
+
+ *rss = 0;
+ *swp = 0;
+
+- for (i = 0; i <= shm_ids.max_id; i++) {
++ for (i = 0; i <= shm_ids(ns).max_id; i++) {
+ struct shmid_kernel *shp;
+ struct inode *inode;
+
+- shp = shm_get(i);
++ shp = shm_get(ns, i);
+ if(!shp)
+ continue;
+
+@@ -430,6 +515,7 @@ asmlinkage long sys_shmctl (int shmid, i
+ struct shm_setbuf setbuf;
+ struct shmid_kernel *shp;
+ int err, version;
++ struct ipc_namespace *ns;
+
+ if (cmd < 0 || shmid < 0) {
+ err = -EINVAL;
+@@ -437,6 +523,7 @@ asmlinkage long sys_shmctl (int shmid, i
+ }
+
+ version = ipc_parse_version(&cmd);
++ ns = current->nsproxy->ipc_ns;
+
+ switch (cmd) { /* replace with proc interface ? */
+ case IPC_INFO:
+@@ -448,15 +535,15 @@ asmlinkage long sys_shmctl (int shmid, i
+ return err;
+
+ memset(&shminfo,0,sizeof(shminfo));
+- shminfo.shmmni = shminfo.shmseg = shm_ctlmni;
+- shminfo.shmmax = shm_ctlmax;
+- shminfo.shmall = shm_ctlall;
++ shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
++ shminfo.shmmax = ns->shm_ctlmax;
++ shminfo.shmall = ns->shm_ctlall;
+
+ shminfo.shmmin = SHMMIN;
+ if(copy_shminfo_to_user (buf, &shminfo, version))
+ return -EFAULT;
+ /* reading a integer is always atomic */
+- err= shm_ids.max_id;
++ err= shm_ids(ns).max_id;
+ if(err<0)
+ err = 0;
+ goto out;
+@@ -470,14 +557,14 @@ asmlinkage long sys_shmctl (int shmid, i
+ return err;
+
+ memset(&shm_info,0,sizeof(shm_info));
+- mutex_lock(&shm_ids.mutex);
+- shm_info.used_ids = shm_ids.in_use;
+- shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
+- shm_info.shm_tot = shm_tot;
++ mutex_lock(&shm_ids(ns).mutex);
++ shm_info.used_ids = shm_ids(ns).in_use;
++ shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
++ shm_info.shm_tot = ns->shm_tot;
+ shm_info.swap_attempts = 0;
+ shm_info.swap_successes = 0;
+- err = shm_ids.max_id;
+- mutex_unlock(&shm_ids.mutex);
++ err = shm_ids(ns).max_id;
++ mutex_unlock(&shm_ids(ns).mutex);
+ if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
+ err = -EFAULT;
+ goto out;
+@@ -492,17 +579,17 @@ asmlinkage long sys_shmctl (int shmid, i
+ struct shmid64_ds tbuf;
+ int result;
+ memset(&tbuf, 0, sizeof(tbuf));
+- shp = shm_lock(shmid);
++ shp = shm_lock(ns, shmid);
+ if(shp==NULL) {
+ err = -EINVAL;
+ goto out;
+ } else if(cmd==SHM_STAT) {
+ err = -EINVAL;
+- if (shmid > shm_ids.max_id)
++ if (shmid > shm_ids(ns).max_id)
+ goto out_unlock;
+- result = shm_buildid(shmid, shp->shm_perm.seq);
++ result = shm_buildid(ns, shmid, shp->shm_perm.seq);
+ } else {
+- err = shm_checkid(shp,shmid);
++ err = shm_checkid(ns, shp,shmid);
+ if(err)
+ goto out_unlock;
+ result = 0;
+@@ -534,12 +621,12 @@ asmlinkage long sys_shmctl (int shmid, i
+ case SHM_LOCK:
+ case SHM_UNLOCK:
+ {
+- shp = shm_lock(shmid);
++ shp = shm_lock(ns, shmid);
+ if(shp==NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+- err = shm_checkid(shp,shmid);
++ err = shm_checkid(ns, shp,shmid);
+ if(err)
+ goto out_unlock;
+
+@@ -590,12 +677,12 @@ asmlinkage long sys_shmctl (int shmid, i
+ * Instead we set a destroyed flag, and then blow
+ * the name away when the usage hits zero.
+ */
+- mutex_lock(&shm_ids.mutex);
+- shp = shm_lock(shmid);
++ mutex_lock(&shm_ids(ns).mutex);
++ shp = shm_lock(ns, shmid);
+ err = -EINVAL;
+ if (shp == NULL)
+ goto out_up;
+- err = shm_checkid(shp, shmid);
++ err = shm_checkid(ns, shp, shmid);
+ if(err)
+ goto out_unlock_up;
+
+@@ -614,14 +701,8 @@ asmlinkage long sys_shmctl (int shmid, i
+ if (err)
+ goto out_unlock_up;
+
+- if (shp->shm_nattch){
+- shp->shm_perm.mode |= SHM_DEST;
+- /* Do not find it any more */
+- shp->shm_perm.key = IPC_PRIVATE;
+- shm_unlock(shp);
+- } else
+- shm_destroy (shp);
+- mutex_unlock(&shm_ids.mutex);
++ do_shm_rmid(ns, shp);
++ mutex_unlock(&shm_ids(ns).mutex);
+ goto out;
+ }
+
+@@ -631,12 +712,12 @@ asmlinkage long sys_shmctl (int shmid, i
+ err = -EFAULT;
+ goto out;
+ }
+- mutex_lock(&shm_ids.mutex);
+- shp = shm_lock(shmid);
++ mutex_lock(&shm_ids(ns).mutex);
++ shp = shm_lock(ns, shmid);
+ err=-EINVAL;
+ if(shp==NULL)
+ goto out_up;
+- err = shm_checkid(shp,shmid);
++ err = shm_checkid(ns, shp,shmid);
+ if(err)
+ goto out_unlock_up;
+ err = audit_ipc_obj(&(shp->shm_perm));
+@@ -673,7 +754,7 @@ asmlinkage long sys_shmctl (int shmid, i
+ out_unlock_up:
+ shm_unlock(shp);
+ out_up:
+- mutex_unlock(&shm_ids.mutex);
++ mutex_unlock(&shm_ids(ns).mutex);
+ goto out;
+ out_unlock:
+ shm_unlock(shp);
+@@ -699,6 +780,7 @@ long do_shmat(int shmid, char __user *sh
+ unsigned long prot;
+ int acc_mode;
+ void *user_addr;
++ struct ipc_namespace *ns;
+
+ if (shmid < 0) {
+ err = -EINVAL;
+@@ -737,12 +819,13 @@ long do_shmat(int shmid, char __user *sh
+ * We cannot rely on the fs check since SYSV IPC does have an
+ * additional creator id...
+ */
+- shp = shm_lock(shmid);
++ ns = current->nsproxy->ipc_ns;
++ shp = shm_lock(ns, shmid);
+ if(shp == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+- err = shm_checkid(shp,shmid);
++ err = shm_checkid(ns, shp,shmid);
+ if (err) {
+ shm_unlock(shp);
+ goto out;
+@@ -783,16 +866,16 @@ long do_shmat(int shmid, char __user *sh
+ invalid:
+ up_write(¤t->mm->mmap_sem);
+
+- mutex_lock(&shm_ids.mutex);
+- shp = shm_lock(shmid);
++ mutex_lock(&shm_ids(ns).mutex);
++ shp = shm_lock(ns, shmid);
+ BUG_ON(!shp);
+ shp->shm_nattch--;
+ if(shp->shm_nattch == 0 &&
+ shp->shm_perm.mode & SHM_DEST)
+- shm_destroy (shp);
++ shm_destroy(ns, shp);
+ else
+ shm_unlock(shp);
+- mutex_unlock(&shm_ids.mutex);
++ mutex_unlock(&shm_ids(ns).mutex);
+
+ *raddr = (unsigned long) user_addr;
+ err = 0;
+diff --git a/ipc/util.c b/ipc/util.c
+index 67b6d17..cd8bb14 100644
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -12,6 +12,9 @@
+ * Mingming Cao <cmm at us.ibm.com>
+ * Mar 2006 - support for audit of ipc object properties
+ * Dustin Kirkland <dustin.kirkland at us.ibm.com>
++ * Jun 2006 - namespaces ssupport
++ * OpenVZ, SWsoft Inc.
++ * Pavel Emelianov <xemul at openvz.org>
+ */
+
+ #include <linux/mm.h>
+@@ -29,6 +32,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/proc_fs.h>
+ #include <linux/audit.h>
++#include <linux/nsproxy.h>
+
+ #include <asm/unistd.h>
+
+@@ -37,10 +41,111 @@
+ struct ipc_proc_iface {
+ const char *path;
+ const char *header;
+- struct ipc_ids *ids;
++ int ids;
+ int (*show)(struct seq_file *, void *);
+ };
+
++struct ipc_namespace init_ipc_ns = {
++ .kref = {
++ .refcount = ATOMIC_INIT(2),
++ },
++};
++
++#ifdef CONFIG_IPC_NS
++static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
++{
++ int err;
++ struct ipc_namespace *ns;
++
++ err = -ENOMEM;
++ ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
++ if (ns == NULL)
++ goto err_mem;
++
++ err = sem_init_ns(ns);
++ if (err)
++ goto err_sem;
++ err = msg_init_ns(ns);
++ if (err)
++ goto err_msg;
++ err = shm_init_ns(ns);
++ if (err)
++ goto err_shm;
++
++ kref_init(&ns->kref);
++ return ns;
++
++err_shm:
++ msg_exit_ns(ns);
++err_msg:
++ sem_exit_ns(ns);
++err_sem:
++ kfree(ns);
++err_mem:
++ return ERR_PTR(err);
++}
++
++int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc)
++{
++ struct ipc_namespace *new;
++
++ if (unshare_flags & CLONE_NEWIPC) {
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ new = clone_ipc_ns(current->nsproxy->ipc_ns);
++ if (IS_ERR(new))
++ return PTR_ERR(new);
++
++ *new_ipc = new;
++ }
++
++ return 0;
++}
++
++int copy_ipcs(unsigned long flags, struct task_struct *tsk)
++{
++ struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns;
++ struct ipc_namespace *new_ns;
++ int err = 0;
++
++ if (!old_ns)
++ return 0;
++
++ get_ipc_ns(old_ns);
++
++ if (!(flags & CLONE_NEWIPC))
++ return 0;
++
++ if (!capable(CAP_SYS_ADMIN)) {
++ err = -EPERM;
++ goto out;
++ }
++
++ new_ns = clone_ipc_ns(old_ns);
++ if (!new_ns) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ tsk->nsproxy->ipc_ns = new_ns;
++out:
++ put_ipc_ns(old_ns);
++ return err;
++}
++
++void free_ipc_ns(struct kref *kref)
++{
++ struct ipc_namespace *ns;
++
++ ns = container_of(kref, struct ipc_namespace, kref);
++ sem_exit_ns(ns);
++ msg_exit_ns(ns);
++ shm_exit_ns(ns);
++ kfree(ns);
++}
++#endif
++
+ /**
+ * ipc_init - initialise IPC subsystem
+ *
+@@ -67,7 +172,7 @@ __initcall(ipc_init);
+ * array itself.
+ */
+
+-void __init ipc_init_ids(struct ipc_ids* ids, int size)
++void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size)
+ {
+ int i;
+
+@@ -110,8 +215,7 @@ static struct file_operations sysvipc_pr
+ * @show: show routine.
+ */
+ void __init ipc_init_proc_interface(const char *path, const char *header,
+- struct ipc_ids *ids,
+- int (*show)(struct seq_file *, void *))
++ int ids, int (*show)(struct seq_file *, void *))
+ {
+ struct proc_dir_entry *pde;
+ struct ipc_proc_iface *iface;
+@@ -197,7 +301,7 @@ static int grow_ary(struct ipc_ids* ids,
+ */
+ rcu_assign_pointer(ids->entries, new);
+
+- ipc_rcu_putref(old);
++ __ipc_fini_ids(ids, old);
+ return newsize;
+ }
+
+@@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct se
+ struct ipc_proc_iface *iface = s->private;
+ struct kern_ipc_perm *ipc = it;
+ loff_t p;
++ struct ipc_ids *ids;
++
++ ids = current->nsproxy->ipc_ns->ids[iface->ids];
+
+ /* If we had an ipc id locked before, unlock it */
+ if (ipc && ipc != SEQ_START_TOKEN)
+@@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct se
+ * p = *pos - 1 (because id 0 starts at position 1)
+ * + 1 (because we increment the position by one)
+ */
+- for (p = *pos; p <= iface->ids->max_id; p++) {
+- if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
++ for (p = *pos; p <= ids->max_id; p++) {
++ if ((ipc = ipc_lock(ids, p)) != NULL) {
+ *pos = p + 1;
+ return ipc;
+ }
+@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct s
+ struct ipc_proc_iface *iface = s->private;
+ struct kern_ipc_perm *ipc;
+ loff_t p;
++ struct ipc_ids *ids;
++
++ ids = current->nsproxy->ipc_ns->ids[iface->ids];
+
+ /*
+ * Take the lock - this will be released by the corresponding
+ * call to stop().
+ */
+- mutex_lock(&iface->ids->mutex);
++ mutex_lock(&ids->mutex);
+
+ /* pos < 0 is invalid */
+ if (*pos < 0)
+@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct s
+ return SEQ_START_TOKEN;
+
+ /* Find the (pos-1)th ipc */
+- for (p = *pos - 1; p <= iface->ids->max_id; p++) {
+- if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
++ for (p = *pos - 1; p <= ids->max_id; p++) {
++ if ((ipc = ipc_lock(ids, p)) != NULL) {
+ *pos = p + 1;
+ return ipc;
+ }
+@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq
+ {
+ struct kern_ipc_perm *ipc = it;
+ struct ipc_proc_iface *iface = s->private;
++ struct ipc_ids *ids;
+
+ /* If we had a locked segment, release it */
+ if (ipc && ipc != SEQ_START_TOKEN)
+ ipc_unlock(ipc);
+
++ ids = current->nsproxy->ipc_ns->ids[iface->ids];
+ /* Release the lock we took in start() */
+- mutex_unlock(&iface->ids->mutex);
++ mutex_unlock(&ids->mutex);
+ }
+
+ static int sysvipc_proc_show(struct seq_file *s, void *it)
+diff --git a/ipc/util.h b/ipc/util.h
+index 0181553..e3aa2c5 100644
+--- a/ipc/util.h
++++ b/ipc/util.h
+@@ -3,6 +3,8 @@
+ * Copyright (C) 1999 Christoph Rohland
+ *
+ * ipc helper functions (c) 1999 Manfred Spraul <manfred at colorfullife.com>
++ * namespaces support. 2006 OpenVZ, SWsoft Inc.
++ * Pavel Emelianov <xemul at openvz.org>
+ */
+
+ #ifndef _IPC_UTIL_H
+@@ -15,6 +17,14 @@ void sem_init (void);
+ void msg_init (void);
+ void shm_init (void);
+
++int sem_init_ns(struct ipc_namespace *ns);
++int msg_init_ns(struct ipc_namespace *ns);
++int shm_init_ns(struct ipc_namespace *ns);
++
++void sem_exit_ns(struct ipc_namespace *ns);
++void msg_exit_ns(struct ipc_namespace *ns);
++void shm_exit_ns(struct ipc_namespace *ns);
++
+ struct ipc_id_ary {
+ int size;
+ struct kern_ipc_perm *p[0];
+@@ -31,15 +41,23 @@ struct ipc_ids {
+ };
+
+ struct seq_file;
+-void __init ipc_init_ids(struct ipc_ids* ids, int size);
++#ifdef CONFIG_IPC_NS
++#define __ipc_init
++#else
++#define __ipc_init __init
++#endif
++void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size);
+ #ifdef CONFIG_PROC_FS
+ void __init ipc_init_proc_interface(const char *path, const char *header,
+- struct ipc_ids *ids,
+- int (*show)(struct seq_file *, void *));
++ int ids, int (*show)(struct seq_file *, void *));
+ #else
+ #define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
+ #endif
+
++#define IPC_SEM_IDS 0
++#define IPC_MSG_IDS 1
++#define IPC_SHM_IDS 2
++
+ /* must be called with ids->mutex acquired.*/
+ int ipc_findkey(struct ipc_ids* ids, key_t key);
+ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
+@@ -65,6 +83,18 @@ void* ipc_rcu_alloc(int size);
+ void ipc_rcu_getref(void *ptr);
+ void ipc_rcu_putref(void *ptr);
+
++static inline void __ipc_fini_ids(struct ipc_ids *ids,
++ struct ipc_id_ary *entries)
++{
++ if (entries != &ids->nullentry)
++ ipc_rcu_putref(entries);
++}
++
++static inline void ipc_fini_ids(struct ipc_ids *ids)
++{
++ __ipc_fini_ids(ids, ids->entries);
++}
++
+ struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id);
+ struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id);
+ void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp);
+diff --git a/kernel/Makefile b/kernel/Makefile
+index d62ec66..5e3f3b7 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o
+ signal.o sys.o kmod.o workqueue.o pid.o \
+ rcupdate.o extable.o params.o posix-timers.o \
+ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
+- hrtimer.o rwsem.o
++ hrtimer.o rwsem.o latency.o nsproxy.o srcu.o
+
+ obj-$(CONFIG_STACKTRACE) += stacktrace.o
+ obj-y += time/
+@@ -48,8 +48,9 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
+ obj-$(CONFIG_SECCOMP) += seccomp.o
+ obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
+ obj-$(CONFIG_RELAY) += relay.o
++obj-$(CONFIG_UTS_NS) += utsname.o
+ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+-obj-$(CONFIG_TASKSTATS) += taskstats.o
++obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
+
+ ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
+ # According to Alan Modra <alan at linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff --git a/kernel/acct.c b/kernel/acct.c
+index 2a7c933..0aad5ca 100644
+--- a/kernel/acct.c
++++ b/kernel/acct.c
+@@ -483,10 +483,14 @@ static void do_acct_process(struct file
+ ac.ac_ppid = current->parent->tgid;
+ #endif
+
+- read_lock(&tasklist_lock); /* pin current->signal */
++ mutex_lock(&tty_mutex);
++ /* FIXME: Whoever is responsible for current->signal locking needs
++ to use the same locking all over the kernel and document it */
++ read_lock(&tasklist_lock);
+ ac.ac_tty = current->signal->tty ?
+ old_encode_dev(tty_devnum(current->signal->tty)) : 0;
+ read_unlock(&tasklist_lock);
++ mutex_unlock(&tty_mutex);
+
+ spin_lock_irq(¤t->sighand->siglock);
+ ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
+@@ -598,33 +602,3 @@ void acct_process(void)
+ do_acct_process(file);
+ fput(file);
+ }
+-
+-
+-/**
+- * acct_update_integrals - update mm integral fields in task_struct
+- * @tsk: task_struct for accounting
+- */
+-void acct_update_integrals(struct task_struct *tsk)
+-{
+- if (likely(tsk->mm)) {
+- long delta =
+- cputime_to_jiffies(tsk->stime) - tsk->acct_stimexpd;
+-
+- if (delta == 0)
+- return;
+- tsk->acct_stimexpd = tsk->stime;
+- tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm);
+- tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
+- }
+-}
+-
+-/**
+- * acct_clear_integrals - clear the mm integral fields in task_struct
+- * @tsk: task_struct whose accounting fields are cleared
+- */
+-void acct_clear_integrals(struct task_struct *tsk)
+-{
+- tsk->acct_stimexpd = 0;
+- tsk->acct_rss_mem1 = 0;
+- tsk->acct_vm_mem1 = 0;
+-}
+diff --git a/kernel/audit.c b/kernel/audit.c
+index 963fd15..98106f6 100644
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -244,7 +244,7 @@ static int audit_set_rate_limit(int limi
+ char *ctx = NULL;
+ u32 len;
+ int rc;
+- if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
++ if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
+ return rc;
+ else
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+@@ -267,7 +267,7 @@ static int audit_set_backlog_limit(int l
+ char *ctx = NULL;
+ u32 len;
+ int rc;
+- if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
++ if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
+ return rc;
+ else
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+@@ -293,7 +293,7 @@ static int audit_set_enabled(int state,
+ char *ctx = NULL;
+ u32 len;
+ int rc;
+- if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
++ if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
+ return rc;
+ else
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+@@ -321,7 +321,7 @@ static int audit_set_failure(int state,
+ char *ctx = NULL;
+ u32 len;
+ int rc;
+- if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
++ if ((rc = selinux_sid_to_string(sid, &ctx, &len)))
+ return rc;
+ else
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+@@ -340,7 +340,7 @@ static int kauditd_thread(void *dummy)
+ {
+ struct sk_buff *skb;
+
+- while (1) {
++ while (!kthread_should_stop()) {
+ skb = skb_dequeue(&audit_skb_queue);
+ wake_up(&audit_backlog_wait);
+ if (skb) {
+@@ -369,6 +369,7 @@ static int kauditd_thread(void *dummy)
+ remove_wait_queue(&kauditd_wait, &wait);
+ }
+ }
++ return 0;
+ }
+
+ int audit_send_list(void *_dest)
+@@ -538,7 +539,7 @@ static int audit_receive_msg(struct sk_b
+ if (status_get->mask & AUDIT_STATUS_PID) {
+ int old = audit_pid;
+ if (sid) {
+- if ((err = selinux_ctxid_to_string(
++ if ((err = selinux_sid_to_string(
+ sid, &ctx, &len)))
+ return err;
+ else
+@@ -576,7 +577,7 @@ static int audit_receive_msg(struct sk_b
+ "user pid=%d uid=%u auid=%u",
+ pid, uid, loginuid);
+ if (sid) {
+- if (selinux_ctxid_to_string(
++ if (selinux_sid_to_string(
+ sid, &ctx, &len)) {
+ audit_log_format(ab,
+ " ssid=%u", sid);
+@@ -614,7 +615,7 @@ static int audit_receive_msg(struct sk_b
+ loginuid, sid);
+ break;
+ case AUDIT_SIGNAL_INFO:
+- err = selinux_ctxid_to_string(audit_sig_sid, &ctx, &len);
++ err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
+ if (err)
+ return err;
+ sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
+diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
+index a44879b..4f40d92 100644
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -411,7 +411,6 @@ static struct audit_entry *audit_rule_to
+ case AUDIT_FSGID:
+ case AUDIT_LOGINUID:
+ case AUDIT_PERS:
+- case AUDIT_ARCH:
+ case AUDIT_MSGTYPE:
+ case AUDIT_PPID:
+ case AUDIT_DEVMAJOR:
+@@ -423,6 +422,14 @@ static struct audit_entry *audit_rule_to
+ case AUDIT_ARG2:
+ case AUDIT_ARG3:
+ break;
++ /* arch is only allowed to be = or != */
++ case AUDIT_ARCH:
++ if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL)
++ && (f->op != AUDIT_NEGATE) && (f->op)) {
++ err = -EINVAL;
++ goto exit_free;
++ }
++ break;
+ case AUDIT_PERM:
+ if (f->val & ~15)
+ goto exit_free;
+@@ -1398,7 +1405,7 @@ static void audit_log_rule_change(uid_t
+ if (sid) {
+ char *ctx = NULL;
+ u32 len;
+- if (selinux_ctxid_to_string(sid, &ctx, &len))
++ if (selinux_sid_to_string(sid, &ctx, &len))
+ audit_log_format(ab, " ssid=%u", sid);
+ else
+ audit_log_format(ab, " subj=%s", ctx);
+diff --git a/kernel/auditsc.c b/kernel/auditsc.c
+index 1bd8827..42f2f11 100644
+--- a/kernel/auditsc.c
++++ b/kernel/auditsc.c
+@@ -278,8 +278,11 @@ static int audit_filter_rules(struct tas
+ result = audit_comparator(tsk->pid, f->op, f->val);
+ break;
+ case AUDIT_PPID:
+- if (ctx)
++ if (ctx) {
++ if (!ctx->ppid)
++ ctx->ppid = sys_getppid();
+ result = audit_comparator(ctx->ppid, f->op, f->val);
++ }
+ break;
+ case AUDIT_UID:
+ result = audit_comparator(tsk->uid, f->op, f->val);
+@@ -385,7 +388,7 @@ static int audit_filter_rules(struct tas
+ logged upon error */
+ if (f->se_rule) {
+ if (need_sid) {
+- selinux_task_ctxid(tsk, &sid);
++ selinux_get_task_sid(tsk, &sid);
+ need_sid = 0;
+ }
+ result = selinux_audit_rule_match(sid, f->type,
+@@ -795,7 +798,8 @@ static void audit_log_exit(struct audit_
+
+ /* tsk == current */
+ context->pid = tsk->pid;
+- context->ppid = sys_getppid(); /* sic. tsk == current in all cases */
++ if (!context->ppid)
++ context->ppid = sys_getppid();
+ context->uid = tsk->uid;
+ context->gid = tsk->gid;
+ context->euid = tsk->euid;
+@@ -817,6 +821,8 @@ static void audit_log_exit(struct audit_
+ audit_log_format(ab, " success=%s exit=%ld",
+ (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
+ context->return_code);
++
++ mutex_lock(&tty_mutex);
+ if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
+ tty = tsk->signal->tty->name;
+ else
+@@ -838,6 +844,9 @@ static void audit_log_exit(struct audit_
+ context->gid,
+ context->euid, context->suid, context->fsuid,
+ context->egid, context->sgid, context->fsgid, tty);
++
++ mutex_unlock(&tty_mutex);
++
+ audit_log_task_info(ab, tsk);
+ if (context->filterkey) {
+ audit_log_format(ab, " key=");
+@@ -898,7 +907,7 @@ static void audit_log_exit(struct audit_
+ if (axi->osid != 0) {
+ char *ctx = NULL;
+ u32 len;
+- if (selinux_ctxid_to_string(
++ if (selinux_sid_to_string(
+ axi->osid, &ctx, &len)) {
+ audit_log_format(ab, " osid=%u",
+ axi->osid);
+@@ -1005,7 +1014,7 @@ static void audit_log_exit(struct audit_
+ if (n->osid != 0) {
+ char *ctx = NULL;
+ u32 len;
+- if (selinux_ctxid_to_string(
++ if (selinux_sid_to_string(
+ n->osid, &ctx, &len)) {
+ audit_log_format(ab, " osid=%u", n->osid);
+ call_panic = 2;
+@@ -1132,6 +1141,7 @@ void audit_syscall_entry(int arch, int m
+ context->ctime = CURRENT_TIME;
+ context->in_syscall = 1;
+ context->auditable = !!(state == AUDIT_RECORD_CONTEXT);
++ context->ppid = 0;
+ }
+
+ /**
+@@ -1347,7 +1357,13 @@ void __audit_inode_child(const char *dna
+ }
+
+ update_context:
+- idx = context->name_count++;
++ idx = context->name_count;
++ if (context->name_count == AUDIT_NAMES) {
++ printk(KERN_DEBUG "name_count maxed and losing %s\n",
++ found_name ?: "(null)");
++ return;
++ }
++ context->name_count++;
+ #if AUDIT_DEBUG
+ context->ino_count++;
+ #endif
+@@ -1365,7 +1381,16 @@ update_context:
+ /* A parent was not found in audit_names, so copy the inode data for the
+ * provided parent. */
+ if (!found_name) {
+- idx = context->name_count++;
++ idx = context->name_count;
++ if (context->name_count == AUDIT_NAMES) {
++ printk(KERN_DEBUG
++ "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
++ MAJOR(parent->i_sb->s_dev),
++ MINOR(parent->i_sb->s_dev),
++ parent->i_ino);
++ return;
++ }
++ context->name_count++;
+ #if AUDIT_DEBUG
+ context->ino_count++;
+ #endif
+diff --git a/kernel/capability.c b/kernel/capability.c
+index c7685ad..edb845a 100644
+--- a/kernel/capability.c
++++ b/kernel/capability.c
+@@ -133,7 +133,7 @@ static inline int cap_set_all(kernel_cap
+ int found = 0;
+
+ do_each_thread(g, target) {
+- if (target == current || target->pid == 1)
++ if (target == current || is_init(target))
+ continue;
+ found = 1;
+ if (security_capset_check(target, effective, inheritable,
+diff --git a/kernel/compat.c b/kernel/compat.c
+index 126dee9..6952dd0 100644
+--- a/kernel/compat.c
++++ b/kernel/compat.c
+@@ -22,6 +22,7 @@
+ #include <linux/security.h>
+ #include <linux/timex.h>
+ #include <linux/migrate.h>
++#include <linux/posix-timers.h>
+
+ #include <asm/uaccess.h>
+
+@@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t w
+ return err;
+ }
+
++static long compat_clock_nanosleep_restart(struct restart_block *restart)
++{
++ long err;
++ mm_segment_t oldfs;
++ struct timespec tu;
++ struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1);
++
++ restart->arg1 = (unsigned long) &tu;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = clock_nanosleep_restart(restart);
++ set_fs(oldfs);
++
++ if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
++ put_compat_timespec(&tu, rmtp))
++ return -EFAULT;
++
++ if (err == -ERESTART_RESTARTBLOCK) {
++ restart->fn = compat_clock_nanosleep_restart;
++ restart->arg1 = (unsigned long) rmtp;
++ }
++ return err;
++}
++
+ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
+ struct compat_timespec __user *rqtp,
+ struct compat_timespec __user *rmtp)
+@@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_
+ long err;
+ mm_segment_t oldfs;
+ struct timespec in, out;
++ struct restart_block *restart;
+
+ if (get_compat_timespec(&in, rqtp))
+ return -EFAULT;
+@@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_
+ (struct timespec __user *) &in,
+ (struct timespec __user *) &out);
+ set_fs(oldfs);
++
+ if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
+ put_compat_timespec(&out, rmtp))
+ return -EFAULT;
++
++ if (err == -ERESTART_RESTARTBLOCK) {
++ restart = ¤t_thread_info()->restart_block;
++ restart->fn = compat_clock_nanosleep_restart;
++ restart->arg1 = (unsigned long) rmtp;
++ }
+ return err;
+ }
+
+@@ -645,7 +678,7 @@ int get_compat_sigevent(struct sigevent
+ ? -EFAULT : 0;
+ }
+
+-long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask,
++long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
+ unsigned long bitmap_size)
+ {
+ int i, j;
+@@ -949,4 +982,37 @@ asmlinkage long compat_sys_move_pages(pi
+ }
+ return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
+ }
++
++asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
++ compat_ulong_t maxnode,
++ const compat_ulong_t __user *old_nodes,
++ const compat_ulong_t __user *new_nodes)
++{
++ unsigned long __user *old = NULL;
++ unsigned long __user *new = NULL;
++ nodemask_t tmp_mask;
++ unsigned long nr_bits;
++ unsigned long size;
++
++ nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES);
++ size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
++ if (old_nodes) {
++ if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits))
++ return -EFAULT;
++ old = compat_alloc_user_space(new_nodes ? size * 2 : size);
++ if (new_nodes)
++ new = old + size / sizeof(unsigned long);
++ if (copy_to_user(old, nodes_addr(tmp_mask), size))
++ return -EFAULT;
++ }
++ if (new_nodes) {
++ if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits))
++ return -EFAULT;
++ if (new == NULL)
++ new = compat_alloc_user_space(size);
++ if (copy_to_user(new, nodes_addr(tmp_mask), size))
++ return -EFAULT;
++ }
++ return sys_migrate_pages(pid, nr_bits + 1, old, new);
++}
+ #endif
+diff --git a/kernel/cpu.c b/kernel/cpu.c
+index f230f9a..272254f 100644
+--- a/kernel/cpu.c
++++ b/kernel/cpu.c
+@@ -19,7 +19,12 @@
+ static DEFINE_MUTEX(cpu_add_remove_lock);
+ static DEFINE_MUTEX(cpu_bitmask_lock);
+
+-static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain);
++static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
++
++/* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
++ * Should always be manipulated under cpu_add_remove_lock
++ */
++static int cpu_hotplug_disabled;
+
+ #ifdef CONFIG_HOTPLUG_CPU
+
+@@ -53,8 +58,8 @@ void unlock_cpu_hotplug(void)
+ recursive_depth--;
+ return;
+ }
+- mutex_unlock(&cpu_bitmask_lock);
+ recursive = NULL;
++ mutex_unlock(&cpu_bitmask_lock);
+ }
+ EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
+
+@@ -63,7 +68,11 @@ EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
+ /* Need to know about CPUs going up/down? */
+ int __cpuinit register_cpu_notifier(struct notifier_block *nb)
+ {
+- return blocking_notifier_chain_register(&cpu_chain, nb);
++ int ret;
++ mutex_lock(&cpu_add_remove_lock);
++ ret = raw_notifier_chain_register(&cpu_chain, nb);
++ mutex_unlock(&cpu_add_remove_lock);
++ return ret;
+ }
+
+ #ifdef CONFIG_HOTPLUG_CPU
+@@ -72,7 +81,9 @@ EXPORT_SYMBOL(register_cpu_notifier);
+
+ void unregister_cpu_notifier(struct notifier_block *nb)
+ {
+- blocking_notifier_chain_unregister(&cpu_chain, nb);
++ mutex_lock(&cpu_add_remove_lock);
++ raw_notifier_chain_unregister(&cpu_chain, nb);
++ mutex_unlock(&cpu_add_remove_lock);
+ }
+ EXPORT_SYMBOL(unregister_cpu_notifier);
+
+@@ -108,30 +119,25 @@ static int take_cpu_down(void *unused)
+ return 0;
+ }
+
+-int cpu_down(unsigned int cpu)
++/* Requires cpu_add_remove_lock to be held */
++static int _cpu_down(unsigned int cpu)
+ {
+ int err;
+ struct task_struct *p;
+ cpumask_t old_allowed, tmp;
+
+- mutex_lock(&cpu_add_remove_lock);
+- if (num_online_cpus() == 1) {
+- err = -EBUSY;
+- goto out;
+- }
++ if (num_online_cpus() == 1)
++ return -EBUSY;
+
+- if (!cpu_online(cpu)) {
+- err = -EINVAL;
+- goto out;
+- }
++ if (!cpu_online(cpu))
++ return -EINVAL;
+
+- err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
++ err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
+ (void *)(long)cpu);
+ if (err == NOTIFY_BAD) {
+ printk("%s: attempt to take down CPU %u failed\n",
+ __FUNCTION__, cpu);
+- err = -EINVAL;
+- goto out;
++ return -EINVAL;
+ }
+
+ /* Ensure that we are not runnable on dying cpu */
+@@ -144,18 +150,18 @@ int cpu_down(unsigned int cpu)
+ p = __stop_machine_run(take_cpu_down, NULL, cpu);
+ mutex_unlock(&cpu_bitmask_lock);
+
+- if (IS_ERR(p)) {
++ if (IS_ERR(p) || cpu_online(cpu)) {
+ /* CPU didn't die: tell everyone. Can't complain. */
+- if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
++ if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
+ (void *)(long)cpu) == NOTIFY_BAD)
+ BUG();
+
+- err = PTR_ERR(p);
+- goto out_allowed;
+- }
+-
+- if (cpu_online(cpu))
++ if (IS_ERR(p)) {
++ err = PTR_ERR(p);
++ goto out_allowed;
++ }
+ goto out_thread;
++ }
+
+ /* Wait for it to sleep (leaving idle task). */
+ while (!idle_cpu(cpu))
+@@ -169,7 +175,7 @@ int cpu_down(unsigned int cpu)
+ put_cpu();
+
+ /* CPU is completely dead: tell everyone. Too late to complain. */
+- if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD,
++ if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD,
+ (void *)(long)cpu) == NOTIFY_BAD)
+ BUG();
+
+@@ -179,24 +185,34 @@ out_thread:
+ err = kthread_stop(p);
+ out_allowed:
+ set_cpus_allowed(current, old_allowed);
+-out:
++ return err;
++}
++
++int cpu_down(unsigned int cpu)
++{
++ int err = 0;
++
++ mutex_lock(&cpu_add_remove_lock);
++ if (cpu_hotplug_disabled)
++ err = -EBUSY;
++ else
++ err = _cpu_down(cpu);
++
+ mutex_unlock(&cpu_add_remove_lock);
+ return err;
+ }
+ #endif /*CONFIG_HOTPLUG_CPU*/
+
+-int __devinit cpu_up(unsigned int cpu)
++/* Requires cpu_add_remove_lock to be held */
++static int __devinit _cpu_up(unsigned int cpu)
+ {
+ int ret;
+ void *hcpu = (void *)(long)cpu;
+
+- mutex_lock(&cpu_add_remove_lock);
+- if (cpu_online(cpu) || !cpu_present(cpu)) {
+- ret = -EINVAL;
+- goto out;
+- }
++ if (cpu_online(cpu) || !cpu_present(cpu))
++ return -EINVAL;
+
+- ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
++ ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
+ if (ret == NOTIFY_BAD) {
+ printk("%s: attempt to bring up CPU %u failed\n",
+ __FUNCTION__, cpu);
+@@ -213,13 +229,101 @@ int __devinit cpu_up(unsigned int cpu)
+ BUG_ON(!cpu_online(cpu));
+
+ /* Now call notifier in preparation. */
+- blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
++ raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
+
+ out_notify:
+ if (ret != 0)
+- blocking_notifier_call_chain(&cpu_chain,
++ raw_notifier_call_chain(&cpu_chain,
+ CPU_UP_CANCELED, hcpu);
++
++ return ret;
++}
++
++int __devinit cpu_up(unsigned int cpu)
++{
++ int err = 0;
++
++ mutex_lock(&cpu_add_remove_lock);
++ if (cpu_hotplug_disabled)
++ err = -EBUSY;
++ else
++ err = _cpu_up(cpu);
++
++ mutex_unlock(&cpu_add_remove_lock);
++ return err;
++}
++
++#ifdef CONFIG_SUSPEND_SMP
++static cpumask_t frozen_cpus;
++
++int disable_nonboot_cpus(void)
++{
++ int cpu, first_cpu, error;
++
++ mutex_lock(&cpu_add_remove_lock);
++ first_cpu = first_cpu(cpu_present_map);
++ if (!cpu_online(first_cpu)) {
++ error = _cpu_up(first_cpu);
++ if (error) {
++ printk(KERN_ERR "Could not bring CPU%d up.\n",
++ first_cpu);
++ goto out;
++ }
++ }
++ error = set_cpus_allowed(current, cpumask_of_cpu(first_cpu));
++ if (error) {
++ printk(KERN_ERR "Could not run on CPU%d\n", first_cpu);
++ goto out;
++ }
++ /* We take down all of the non-boot CPUs in one shot to avoid races
++ * with the userspace trying to use the CPU hotplug at the same time
++ */
++ cpus_clear(frozen_cpus);
++ printk("Disabling non-boot CPUs ...\n");
++ for_each_online_cpu(cpu) {
++ if (cpu == first_cpu)
++ continue;
++ error = _cpu_down(cpu);
++ if (!error) {
++ cpu_set(cpu, frozen_cpus);
++ printk("CPU%d is down\n", cpu);
++ } else {
++ printk(KERN_ERR "Error taking CPU%d down: %d\n",
++ cpu, error);
++ break;
++ }
++ }
++ if (!error) {
++ BUG_ON(num_online_cpus() > 1);
++ /* Make sure the CPUs won't be enabled by someone else */
++ cpu_hotplug_disabled = 1;
++ } else {
++ printk(KERN_ERR "Non-boot CPUs are not disabled");
++ }
+ out:
+ mutex_unlock(&cpu_add_remove_lock);
+- return ret;
++ return error;
++}
++
++void enable_nonboot_cpus(void)
++{
++ int cpu, error;
++
++ /* Allow everyone to use the CPU hotplug again */
++ mutex_lock(&cpu_add_remove_lock);
++ cpu_hotplug_disabled = 0;
++ mutex_unlock(&cpu_add_remove_lock);
++
++ printk("Enabling non-boot CPUs ...\n");
++ for_each_cpu_mask(cpu, frozen_cpus) {
++ error = cpu_up(cpu);
++ if (!error) {
++ printk("CPU%d is up\n", cpu);
++ continue;
++ }
++ printk(KERN_WARNING "Error taking CPU%d up: %d\n",
++ cpu, error);
++ }
++ cpus_clear(frozen_cpus);
+ }
++#endif
+diff --git a/kernel/cpuset.c b/kernel/cpuset.c
+index 4ea6f0d..6313c38 100644
+--- a/kernel/cpuset.c
++++ b/kernel/cpuset.c
+@@ -240,7 +240,7 @@ static struct super_block *cpuset_sb;
+ * A cpuset can only be deleted if both its 'count' of using tasks
+ * is zero, and its list of 'children' cpusets is empty. Since all
+ * tasks in the system use _some_ cpuset, and since there is always at
+- * least one task in the system (init, pid == 1), therefore, top_cpuset
++ * least one task in the system (init), therefore, top_cpuset
+ * always has either children cpusets and/or using tasks. So we don't
+ * need a special hack to ensure that top_cpuset cannot be deleted.
+ *
+@@ -289,7 +289,6 @@ static struct inode *cpuset_new_inode(mo
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mapping->backing_dev_info = &cpuset_backing_dev_info;
+@@ -378,7 +377,7 @@ static int cpuset_fill_super(struct supe
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ /* directories start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ } else {
+ return -ENOMEM;
+ }
+@@ -913,6 +912,10 @@ static int update_nodemask(struct cpuset
+ int fudge;
+ int retval;
+
++ /* top_cpuset.mems_allowed tracks node_online_map; it's read-only */
++ if (cs == &top_cpuset)
++ return -EACCES;
++
+ trialcs = *cs;
+ retval = nodelist_parse(buf, trialcs.mems_allowed);
+ if (retval < 0)
+@@ -1222,7 +1225,12 @@ static int attach_task(struct cpuset *cs
+
+ task_lock(tsk);
+ oldcs = tsk->cpuset;
+- if (!oldcs) {
++ /*
++ * After getting 'oldcs' cpuset ptr, be sure still not exiting.
++ * If 'oldcs' might be the top_cpuset due to the_top_cpuset_hack
++ * then fail this attach_task(), to avoid breaking top_cpuset.count.
++ */
++ if (tsk->flags & PF_EXITING) {
+ task_unlock(tsk);
+ mutex_unlock(&callback_mutex);
+ put_task_struct(tsk);
+@@ -1557,7 +1565,7 @@ static int cpuset_create_file(struct den
+ inode->i_fop = &simple_dir_operations;
+
+ /* start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ } else if (S_ISREG(mode)) {
+ inode->i_size = 0;
+ inode->i_fop = &cpuset_file_operations;
+@@ -1590,7 +1598,7 @@ static int cpuset_create_dir(struct cpus
+ error = cpuset_create_file(dentry, S_IFDIR | mode);
+ if (!error) {
+ dentry->d_fsdata = cs;
+- parent->d_inode->i_nlink++;
++ inc_nlink(parent->d_inode);
+ cs->dentry = dentry;
+ }
+ dput(dentry);
+@@ -2025,7 +2033,7 @@ int __init cpuset_init(void)
+ }
+ root = cpuset_mount->mnt_sb->s_root;
+ root->d_fsdata = &top_cpuset;
+- root->d_inode->i_nlink++;
++ inc_nlink(root->d_inode);
+ top_cpuset.dentry = root;
+ root->d_inode->i_op = &cpuset_dir_inode_operations;
+ number_of_cpusets = 1;
+@@ -2037,33 +2045,104 @@ out:
+ return err;
+ }
+
++#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
+ /*
+- * The top_cpuset tracks what CPUs and Memory Nodes are online,
+- * period. This is necessary in order to make cpusets transparent
+- * (of no affect) on systems that are actively using CPU hotplug
+- * but making no active use of cpusets.
+- *
+- * This handles CPU hotplug (cpuhp) events. If someday Memory
+- * Nodes can be hotplugged (dynamically changing node_online_map)
+- * then we should handle that too, perhaps in a similar way.
++ * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs
++ * or memory nodes, we need to walk over the cpuset hierarchy,
++ * removing that CPU or node from all cpusets. If this removes the
++ * last CPU or node from a cpuset, then the guarantee_online_cpus()
++ * or guarantee_online_mems() code will use that emptied cpusets
++ * parent online CPUs or nodes. Cpusets that were already empty of
++ * CPUs or nodes are left empty.
++ *
++ * This routine is intentionally inefficient in a couple of regards.
++ * It will check all cpusets in a subtree even if the top cpuset of
++ * the subtree has no offline CPUs or nodes. It checks both CPUs and
++ * nodes, even though the caller could have been coded to know that
++ * only one of CPUs or nodes needed to be checked on a given call.
++ * This was done to minimize text size rather than cpu cycles.
++ *
++ * Call with both manage_mutex and callback_mutex held.
++ *
++ * Recursive, on depth of cpuset subtree.
+ */
+
+-#ifdef CONFIG_HOTPLUG_CPU
+-static int cpuset_handle_cpuhp(struct notifier_block *nb,
+- unsigned long phase, void *cpu)
++static void guarantee_online_cpus_mems_in_subtree(const struct cpuset *cur)
++{
++ struct cpuset *c;
++
++ /* Each of our child cpusets mems must be online */
++ list_for_each_entry(c, &cur->children, sibling) {
++ guarantee_online_cpus_mems_in_subtree(c);
++ if (!cpus_empty(c->cpus_allowed))
++ guarantee_online_cpus(c, &c->cpus_allowed);
++ if (!nodes_empty(c->mems_allowed))
++ guarantee_online_mems(c, &c->mems_allowed);
++ }
++}
++
++/*
++ * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
++ * cpu_online_map and node_online_map. Force the top cpuset to track
++ * whats online after any CPU or memory node hotplug or unplug event.
++ *
++ * To ensure that we don't remove a CPU or node from the top cpuset
++ * that is currently in use by a child cpuset (which would violate
++ * the rule that cpusets must be subsets of their parent), we first
++ * call the recursive routine guarantee_online_cpus_mems_in_subtree().
++ *
++ * Since there are two callers of this routine, one for CPU hotplug
++ * events and one for memory node hotplug events, we could have coded
++ * two separate routines here. We code it as a single common routine
++ * in order to minimize text size.
++ */
++
++static void common_cpu_mem_hotplug_unplug(void)
+ {
+ mutex_lock(&manage_mutex);
+ mutex_lock(&callback_mutex);
+
++ guarantee_online_cpus_mems_in_subtree(&top_cpuset);
+ top_cpuset.cpus_allowed = cpu_online_map;
++ top_cpuset.mems_allowed = node_online_map;
+
+ mutex_unlock(&callback_mutex);
+ mutex_unlock(&manage_mutex);
++}
++#endif
++
++#ifdef CONFIG_HOTPLUG_CPU
++/*
++ * The top_cpuset tracks what CPUs and Memory Nodes are online,
++ * period. This is necessary in order to make cpusets transparent
++ * (of no affect) on systems that are actively using CPU hotplug
++ * but making no active use of cpusets.
++ *
++ * This routine ensures that top_cpuset.cpus_allowed tracks
++ * cpu_online_map on each CPU hotplug (cpuhp) event.
++ */
+
++static int cpuset_handle_cpuhp(struct notifier_block *nb,
++ unsigned long phase, void *cpu)
++{
++ common_cpu_mem_hotplug_unplug();
+ return 0;
+ }
+ #endif
+
++#ifdef CONFIG_MEMORY_HOTPLUG
++/*
++ * Keep top_cpuset.mems_allowed tracking node_online_map.
++ * Call this routine anytime after you change node_online_map.
++ * See also the previous routine cpuset_handle_cpuhp().
++ */
++
++void cpuset_track_online_nodes(void)
++{
++ common_cpu_mem_hotplug_unplug();
++}
++#endif
++
+ /**
+ * cpuset_init_smp - initialize cpus_allowed
+ *
+@@ -2245,7 +2324,7 @@ int cpuset_zonelist_valid_mems_allowed(s
+ int i;
+
+ for (i = 0; zl->zones[i]; i++) {
+- int nid = zl->zones[i]->zone_pgdat->node_id;
++ int nid = zone_to_nid(zl->zones[i]);
+
+ if (node_isset(nid, current->mems_allowed))
+ return 1;
+@@ -2316,9 +2395,9 @@ int __cpuset_zone_allowed(struct zone *z
+ const struct cpuset *cs; /* current cpuset ancestors */
+ int allowed; /* is allocation in zone z allowed? */
+
+- if (in_interrupt())
++ if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
+ return 1;
+- node = z->zone_pgdat->node_id;
++ node = zone_to_nid(z);
+ might_sleep_if(!(gfp_mask & __GFP_HARDWALL));
+ if (node_isset(node, current->mems_allowed))
+ return 1;
+diff --git a/kernel/delayacct.c b/kernel/delayacct.c
+index 36752f1..66a0ea4 100644
+--- a/kernel/delayacct.c
++++ b/kernel/delayacct.c
+@@ -66,6 +66,7 @@ static void delayacct_end(struct timespe
+ {
+ struct timespec ts;
+ s64 ns;
++ unsigned long flags;
+
+ do_posix_clock_monotonic_gettime(end);
+ ts = timespec_sub(*end, *start);
+@@ -73,10 +74,10 @@ static void delayacct_end(struct timespe
+ if (ns < 0)
+ return;
+
+- spin_lock(¤t->delays->lock);
++ spin_lock_irqsave(¤t->delays->lock, flags);
+ *total += ns;
+ (*count)++;
+- spin_unlock(¤t->delays->lock);
++ spin_unlock_irqrestore(¤t->delays->lock, flags);
+ }
+
+ void __delayacct_blkio_start(void)
+@@ -104,6 +105,7 @@ int __delayacct_add_tsk(struct taskstats
+ s64 tmp;
+ struct timespec ts;
+ unsigned long t1,t2,t3;
++ unsigned long flags;
+
+ /* Though tsk->delays accessed later, early exit avoids
+ * unnecessary returning of other data
+@@ -136,14 +138,14 @@ int __delayacct_add_tsk(struct taskstats
+
+ /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
+
+- spin_lock(&tsk->delays->lock);
++ spin_lock_irqsave(&tsk->delays->lock, flags);
+ tmp = d->blkio_delay_total + tsk->delays->blkio_delay;
+ d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp;
+ tmp = d->swapin_delay_total + tsk->delays->swapin_delay;
+ d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp;
+ d->blkio_count += tsk->delays->blkio_count;
+ d->swapin_count += tsk->delays->swapin_count;
+- spin_unlock(&tsk->delays->lock);
++ spin_unlock_irqrestore(&tsk->delays->lock, flags);
+
+ done:
+ return 0;
+@@ -152,11 +154,12 @@ done:
+ __u64 __delayacct_blkio_ticks(struct task_struct *tsk)
+ {
+ __u64 ret;
++ unsigned long flags;
+
+- spin_lock(&tsk->delays->lock);
++ spin_lock_irqsave(&tsk->delays->lock, flags);
+ ret = nsec_to_clock_t(tsk->delays->blkio_delay +
+ tsk->delays->swapin_delay);
+- spin_unlock(&tsk->delays->lock);
++ spin_unlock_irqrestore(&tsk->delays->lock, flags);
+ return ret;
+ }
+
+diff --git a/kernel/dma.c b/kernel/dma.c
+index aef0a45..2020644 100644
+--- a/kernel/dma.c
++++ b/kernel/dma.c
+@@ -62,6 +62,11 @@ static struct dma_chan dma_chan_busy[MAX
+ };
+
+
++/**
++ * request_dma - request and reserve a system DMA channel
++ * @dmanr: DMA channel number
++ * @device_id: reserving device ID string, used in /proc/dma
++ */
+ int request_dma(unsigned int dmanr, const char * device_id)
+ {
+ if (dmanr >= MAX_DMA_CHANNELS)
+@@ -76,7 +81,10 @@ int request_dma(unsigned int dmanr, cons
+ return 0;
+ } /* request_dma */
+
+-
++/**
++ * free_dma - free a reserved system DMA channel
++ * @dmanr: DMA channel number
++ */
+ void free_dma(unsigned int dmanr)
+ {
+ if (dmanr >= MAX_DMA_CHANNELS) {
+diff --git a/kernel/exit.c b/kernel/exit.c
+index d891883..06de6c4 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -18,8 +18,10 @@
+ #include <linux/security.h>
+ #include <linux/cpu.h>
+ #include <linux/acct.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/file.h>
+ #include <linux/binfmts.h>
++#include <linux/nsproxy.h>
+ #include <linux/ptrace.h>
+ #include <linux/profile.h>
+ #include <linux/mount.h>
+@@ -38,6 +40,7 @@
+ #include <linux/pipe_fs_i.h>
+ #include <linux/audit.h> /* for audit_free() */
+ #include <linux/resource.h>
++#include <linux/blkdev.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/unistd.h>
+@@ -125,6 +128,7 @@ static void __exit_signal(struct task_st
+ flush_sigqueue(&tsk->pending);
+ if (sig) {
+ flush_sigqueue(&sig->shared_pending);
++ taskstats_tgid_free(sig);
+ __cleanup_signal(sig);
+ }
+ }
+@@ -219,7 +223,7 @@ static int will_become_orphaned_pgrp(int
+ do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
+ if (p == ignored_task
+ || p->exit_state
+- || p->real_parent->pid == 1)
++ || is_init(p->real_parent))
+ continue;
+ if (process_group(p->real_parent) != pgrp
+ && p->real_parent->signal->session == p->signal->session) {
+@@ -249,17 +253,6 @@ static int has_stopped_jobs(int pgrp)
+ do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
+ if (p->state != TASK_STOPPED)
+ continue;
+-
+- /* If p is stopped by a debugger on a signal that won't
+- stop it, then don't count p as stopped. This isn't
+- perfect but it's a good approximation. */
+- if (unlikely (p->ptrace)
+- && p->exit_code != SIGSTOP
+- && p->exit_code != SIGTSTP
+- && p->exit_code != SIGTTOU
+- && p->exit_code != SIGTTIN)
+- continue;
+-
+ retval = 1;
+ break;
+ } while_each_task_pid(pgrp, PIDTYPE_PGID, p);
+@@ -292,9 +285,7 @@ static void reparent_to_init(void)
+ /* Set the exit signal to SIGCHLD so we signal init on exit */
+ current->exit_signal = SIGCHLD;
+
+- if ((current->policy == SCHED_NORMAL ||
+- current->policy == SCHED_BATCH)
+- && (task_nice(current) < 0))
++ if (!has_rt_policy(current) && (task_nice(current) < 0))
+ set_user_nice(current, 0);
+ /* cpus_allowed? */
+ /* rt_priority? */
+@@ -408,9 +399,11 @@ void daemonize(const char *name, ...)
+ fs = init_task.fs;
+ current->fs = fs;
+ atomic_inc(&fs->count);
+- exit_namespace(current);
+- current->namespace = init_task.namespace;
+- get_namespace(current->namespace);
++
++ exit_task_namespaces(current);
++ current->nsproxy = init_task.nsproxy;
++ get_task_namespaces(current);
++
+ exit_files(current);
+ current->files = init_task.files;
+ atomic_inc(¤t->files->count);
+@@ -487,6 +480,18 @@ void fastcall put_files_struct(struct fi
+
+ EXPORT_SYMBOL(put_files_struct);
+
++void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
++{
++ struct files_struct *old;
++
++ old = tsk->files;
++ task_lock(tsk);
++ tsk->files = files;
++ task_unlock(tsk);
++ put_files_struct(old);
++}
++EXPORT_SYMBOL(reset_files_struct);
++
+ static inline void __exit_files(struct task_struct *tsk)
+ {
+ struct files_struct * files = tsk->files;
+@@ -916,7 +921,6 @@ fastcall NORET_TYPE void do_exit(long co
+ exit_sem(tsk);
+ __exit_files(tsk);
+ __exit_fs(tsk);
+- exit_namespace(tsk);
+ exit_thread();
+ cpuset_exit(tsk);
+ exit_keys(tsk);
+@@ -931,6 +935,7 @@ fastcall NORET_TYPE void do_exit(long co
+ tsk->exit_code = code;
+ proc_exit_connector(tsk);
+ exit_notify(tsk);
++ exit_task_namespaces(tsk);
+ #ifdef CONFIG_NUMA
+ mpol_free(tsk->mempolicy);
+ tsk->mempolicy = NULL;
+@@ -954,15 +959,15 @@ fastcall NORET_TYPE void do_exit(long co
+ if (tsk->splice_pipe)
+ __free_pipe_info(tsk->splice_pipe);
+
+- /* PF_DEAD causes final put_task_struct after we schedule. */
+ preempt_disable();
+- BUG_ON(tsk->flags & PF_DEAD);
+- tsk->flags |= PF_DEAD;
++ /* causes final put_task_struct in finish_task_switch(). */
++ tsk->state = TASK_DEAD;
+
+ schedule();
+ BUG();
+ /* Avoid "noreturn function does return". */
+- for (;;) ;
++ for (;;)
++ cpu_relax(); /* For when BUG is null */
+ }
+
+ EXPORT_SYMBOL_GPL(do_exit);
+@@ -971,7 +976,7 @@ NORET_TYPE void complete_and_exit(struct
+ {
+ if (comp)
+ complete(comp);
+-
++
+ do_exit(code);
+ }
+
+diff --git a/kernel/fork.c b/kernel/fork.c
+index f9b014e..3da978e 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -27,6 +27,7 @@
+ #include <linux/binfmts.h>
+ #include <linux/mman.h>
+ #include <linux/fs.h>
++#include <linux/nsproxy.h>
+ #include <linux/capability.h>
+ #include <linux/cpu.h>
+ #include <linux/cpuset.h>
+@@ -42,9 +43,11 @@
+ #include <linux/profile.h>
+ #include <linux/rmap.h>
+ #include <linux/acct.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/cn_proc.h>
+ #include <linux/delayacct.h>
+ #include <linux/taskstats_kern.h>
++#include <linux/random.h>
+
+ #include <asm/pgtable.h>
+ #include <asm/pgalloc.h>
+@@ -175,10 +178,16 @@ static struct task_struct *dup_task_stru
+ tsk->thread_info = ti;
+ setup_thread_stack(tsk, orig);
+
++#ifdef CONFIG_CC_STACKPROTECTOR
++ tsk->stack_canary = get_random_int();
++#endif
++
+ /* One for us, one for whoever does the "release_task()" (usually parent) */
+ atomic_set(&tsk->usage,2);
+ atomic_set(&tsk->fs_excl, 0);
++#ifdef CONFIG_BLK_DEV_IO_TRACE
+ tsk->btrace_seq = 0;
++#endif
+ tsk->splice_pipe = NULL;
+ return tsk;
+ }
+@@ -821,7 +830,7 @@ static inline int copy_signal(unsigned l
+ if (clone_flags & CLONE_THREAD) {
+ atomic_inc(¤t->signal->count);
+ atomic_inc(¤t->signal->live);
+- taskstats_tgid_alloc(current->signal);
++ taskstats_tgid_alloc(current);
+ return 0;
+ }
+ sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
+@@ -888,7 +897,6 @@ static inline int copy_signal(unsigned l
+ void __cleanup_signal(struct signal_struct *sig)
+ {
+ exit_thread_group_keys(sig);
+- taskstats_tgid_free(sig);
+ kmem_cache_free(signal_cachep, sig);
+ }
+
+@@ -975,6 +983,8 @@ static struct task_struct *copy_process(
+ if (!p)
+ goto fork_out;
+
++ rt_mutex_init_task(p);
++
+ #ifdef CONFIG_TRACE_IRQFLAGS
+ DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
+ DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
+@@ -1056,7 +1066,11 @@ static struct task_struct *copy_process(
+ #endif
+ #ifdef CONFIG_TRACE_IRQFLAGS
+ p->irq_events = 0;
++#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
++ p->hardirqs_enabled = 1;
++#else
+ p->hardirqs_enabled = 0;
++#endif
+ p->hardirq_enable_ip = 0;
+ p->hardirq_enable_event = 0;
+ p->hardirq_disable_ip = _THIS_IP_;
+@@ -1075,8 +1089,6 @@ static struct task_struct *copy_process(
+ p->lockdep_recursion = 0;
+ #endif
+
+- rt_mutex_init_task(p);
+-
+ #ifdef CONFIG_DEBUG_MUTEXES
+ p->blocked_on = NULL; /* not blocked yet */
+ #endif
+@@ -1104,11 +1116,11 @@ static struct task_struct *copy_process(
+ goto bad_fork_cleanup_signal;
+ if ((retval = copy_keys(clone_flags, p)))
+ goto bad_fork_cleanup_mm;
+- if ((retval = copy_namespace(clone_flags, p)))
++ if ((retval = copy_namespaces(clone_flags, p)))
+ goto bad_fork_cleanup_keys;
+ retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
+ if (retval)
+- goto bad_fork_cleanup_namespace;
++ goto bad_fork_cleanup_namespaces;
+
+ p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
+ /*
+@@ -1139,7 +1151,6 @@ static struct task_struct *copy_process(
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+-
+ p->parent_exec_id = p->self_exec_id;
+
+ /* ok, now we should be set up.. */
+@@ -1162,6 +1173,9 @@ static struct task_struct *copy_process(
+ /* Need tasklist lock for parent etc handling! */
+ write_lock_irq(&tasklist_lock);
+
++ /* for sys_ioprio_set(IOPRIO_WHO_PGRP) */
++ p->ioprio = current->ioprio;
++
+ /*
+ * The task hasn't been attached yet, so its cpus_allowed mask will
+ * not be changed, nor will its assigned CPU.
+@@ -1198,7 +1212,7 @@ static struct task_struct *copy_process(
+ spin_unlock(¤t->sighand->siglock);
+ write_unlock_irq(&tasklist_lock);
+ retval = -ERESTARTNOINTR;
+- goto bad_fork_cleanup_namespace;
++ goto bad_fork_cleanup_namespaces;
+ }
+
+ if (clone_flags & CLONE_THREAD) {
+@@ -1221,11 +1235,6 @@ static struct task_struct *copy_process(
+ }
+ }
+
+- /*
+- * inherit ioprio
+- */
+- p->ioprio = current->ioprio;
+-
+ if (likely(p->pid)) {
+ add_parent(p);
+ if (unlikely(p->ptrace & PT_PTRACED))
+@@ -1251,8 +1260,8 @@ static struct task_struct *copy_process(
+ proc_fork_connector(p);
+ return p;
+
+-bad_fork_cleanup_namespace:
+- exit_namespace(p);
++bad_fork_cleanup_namespaces:
++ exit_task_namespaces(p);
+ bad_fork_cleanup_keys:
+ exit_keys(p);
+ bad_fork_cleanup_mm:
+@@ -1505,10 +1514,9 @@ static int unshare_fs(unsigned long unsh
+ */
+ static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
+ {
+- struct namespace *ns = current->namespace;
++ struct namespace *ns = current->nsproxy->namespace;
+
+- if ((unshare_flags & CLONE_NEWNS) &&
+- (ns && atomic_read(&ns->count) > 1)) {
++ if ((unshare_flags & CLONE_NEWNS) && ns) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+@@ -1580,6 +1588,16 @@ static int unshare_semundo(unsigned long
+ return 0;
+ }
+
++#ifndef CONFIG_IPC_NS
++static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns)
++{
++ if (flags & CLONE_NEWIPC)
++ return -EINVAL;
++
++ return 0;
++}
++#endif
++
+ /*
+ * unshare allows a process to 'unshare' part of the process
+ * context which was originally shared using clone. copy_*
+@@ -1597,13 +1615,17 @@ asmlinkage long sys_unshare(unsigned lon
+ struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
+ struct files_struct *fd, *new_fd = NULL;
+ struct sem_undo_list *new_ulist = NULL;
++ struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
++ struct uts_namespace *uts, *new_uts = NULL;
++ struct ipc_namespace *ipc, *new_ipc = NULL;
+
+ check_unshare_flags(&unshare_flags);
+
+ /* Return -EINVAL for all unsupported flags */
+ err = -EINVAL;
+ if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
+- CLONE_VM|CLONE_FILES|CLONE_SYSVSEM))
++ CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
++ CLONE_NEWUTS|CLONE_NEWIPC))
+ goto bad_unshare_out;
+
+ if ((err = unshare_thread(unshare_flags)))
+@@ -1620,11 +1642,30 @@ asmlinkage long sys_unshare(unsigned lon
+ goto bad_unshare_cleanup_vm;
+ if ((err = unshare_semundo(unshare_flags, &new_ulist)))
+ goto bad_unshare_cleanup_fd;
++ if ((err = unshare_utsname(unshare_flags, &new_uts)))
++ goto bad_unshare_cleanup_semundo;
++ if ((err = unshare_ipcs(unshare_flags, &new_ipc)))
++ goto bad_unshare_cleanup_uts;
++
++ if (new_ns || new_uts || new_ipc) {
++ old_nsproxy = current->nsproxy;
++ new_nsproxy = dup_namespaces(old_nsproxy);
++ if (!new_nsproxy) {
++ err = -ENOMEM;
++ goto bad_unshare_cleanup_ipc;
++ }
++ }
+
+- if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) {
++ if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
++ new_uts || new_ipc) {
+
+ task_lock(current);
+
++ if (new_nsproxy) {
++ current->nsproxy = new_nsproxy;
++ new_nsproxy = old_nsproxy;
++ }
++
+ if (new_fs) {
+ fs = current->fs;
+ current->fs = new_fs;
+@@ -1632,8 +1673,8 @@ asmlinkage long sys_unshare(unsigned lon
+ }
+
+ if (new_ns) {
+- ns = current->namespace;
+- current->namespace = new_ns;
++ ns = current->nsproxy->namespace;
++ current->nsproxy->namespace = new_ns;
+ new_ns = ns;
+ }
+
+@@ -1658,9 +1699,33 @@ asmlinkage long sys_unshare(unsigned lon
+ new_fd = fd;
+ }
+
++ if (new_uts) {
++ uts = current->nsproxy->uts_ns;
++ current->nsproxy->uts_ns = new_uts;
++ new_uts = uts;
++ }
++
++ if (new_ipc) {
++ ipc = current->nsproxy->ipc_ns;
++ current->nsproxy->ipc_ns = new_ipc;
++ new_ipc = ipc;
++ }
++
+ task_unlock(current);
+ }
+
++ if (new_nsproxy)
++ put_nsproxy(new_nsproxy);
++
++bad_unshare_cleanup_ipc:
++ if (new_ipc)
++ put_ipc_ns(new_ipc);
++
++bad_unshare_cleanup_uts:
++ if (new_uts)
++ put_uts_ns(new_uts);
++
++bad_unshare_cleanup_semundo:
+ bad_unshare_cleanup_fd:
+ if (new_fd)
+ put_files_struct(new_fd);
+diff --git a/kernel/futex.c b/kernel/futex.c
+index 9d260e8..93ef30b 100644
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -389,7 +389,7 @@ static struct task_struct * futex_find_g
+ {
+ struct task_struct *p;
+
+- read_lock(&tasklist_lock);
++ rcu_read_lock();
+ p = find_task_by_pid(pid);
+ if (!p)
+ goto out_unlock;
+@@ -403,7 +403,7 @@ static struct task_struct * futex_find_g
+ }
+ get_task_struct(p);
+ out_unlock:
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+
+ return p;
+ }
+@@ -1507,6 +1507,13 @@ static int futex_fd(u32 __user *uaddr, i
+ struct futex_q *q;
+ struct file *filp;
+ int ret, err;
++ static unsigned long printk_interval;
++
++ if (printk_timed_ratelimit(&printk_interval, 60 * 60 * 1000)) {
++ printk(KERN_WARNING "Process `%s' used FUTEX_FD, which "
++ "will be removed from the kernel in June 2007\n",
++ current->comm);
++ }
+
+ ret = -EINVAL;
+ if (!valid_signal(signal))
+@@ -1527,7 +1534,7 @@ static int futex_fd(u32 __user *uaddr, i
+ filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+
+ if (signal) {
+- err = f_setown(filp, current->pid, 1);
++ err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1);
+ if (err < 0) {
+ goto error;
+ }
+@@ -1612,10 +1619,10 @@ sys_set_robust_list(struct robust_list_h
+ * @len_ptr: pointer to a length field, the kernel fills in the header size
+ */
+ asmlinkage long
+-sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
++sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
+ size_t __user *len_ptr)
+ {
+- struct robust_list_head *head;
++ struct robust_list_head __user *head;
+ unsigned long ret;
+
+ if (!pid)
+@@ -1624,7 +1631,7 @@ sys_get_robust_list(int pid, struct robu
+ struct task_struct *p;
+
+ ret = -ESRCH;
+- read_lock(&tasklist_lock);
++ rcu_read_lock();
+ p = find_task_by_pid(pid);
+ if (!p)
+ goto err_unlock;
+@@ -1633,7 +1640,7 @@ sys_get_robust_list(int pid, struct robu
+ !capable(CAP_SYS_PTRACE))
+ goto err_unlock;
+ head = p->robust_list;
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+ }
+
+ if (put_user(sizeof(*head), len_ptr))
+@@ -1641,7 +1648,7 @@ sys_get_robust_list(int pid, struct robu
+ return put_user(head, head_ptr);
+
+ err_unlock:
+- read_unlock(&tasklist_lock);
++ rcu_read_unlock();
+
+ return ret;
+ }
+@@ -1694,14 +1701,15 @@ retry:
+ * Fetch a robust-list pointer. Bit 0 signals PI futexes:
+ */
+ static inline int fetch_robust_entry(struct robust_list __user **entry,
+- struct robust_list __user **head, int *pi)
++ struct robust_list __user * __user *head,
++ int *pi)
+ {
+ unsigned long uentry;
+
+- if (get_user(uentry, (unsigned long *)head))
++ if (get_user(uentry, (unsigned long __user *)head))
+ return -EFAULT;
+
+- *entry = (void *)(uentry & ~1UL);
++ *entry = (void __user *)(uentry & ~1UL);
+ *pi = uentry & 1;
+
+ return 0;
+@@ -1739,7 +1747,7 @@ void exit_robust_list(struct task_struct
+ return;
+
+ if (pending)
+- handle_futex_death((void *)pending + futex_offset, curr, pip);
++ handle_futex_death((void __user *)pending + futex_offset, curr, pip);
+
+ while (entry != &head->list) {
+ /*
+@@ -1747,7 +1755,7 @@ void exit_robust_list(struct task_struct
+ * don't process it twice:
+ */
+ if (entry != pending)
+- if (handle_futex_death((void *)entry + futex_offset,
++ if (handle_futex_death((void __user *)entry + futex_offset,
+ curr, pi))
+ return;
+ /*
+diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
+index c5cca3f..50f24ee 100644
+--- a/kernel/futex_compat.c
++++ b/kernel/futex_compat.c
+@@ -18,7 +18,7 @@
+ */
+ static inline int
+ fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
+- compat_uptr_t *head, int *pi)
++ compat_uptr_t __user *head, int *pi)
+ {
+ if (get_user(*uentry, head))
+ return -EFAULT;
+@@ -62,7 +62,7 @@ void compat_exit_robust_list(struct task
+ &head->list_op_pending, &pip))
+ return;
+ if (upending)
+- handle_futex_death((void *)pending + futex_offset, curr, pip);
++ handle_futex_death((void __user *)pending + futex_offset, curr, pip);
+
+ while (compat_ptr(uentry) != &head->list) {
+ /*
+@@ -70,7 +70,7 @@ void compat_exit_robust_list(struct task
+ * dont process it twice:
+ */
+ if (entry != pending)
+- if (handle_futex_death((void *)entry + futex_offset,
++ if (handle_futex_death((void __user *)entry + futex_offset,
+ curr, pi))
+ return;
+
+@@ -78,7 +78,7 @@ void compat_exit_robust_list(struct task
+ * Fetch the next entry in the list:
+ */
+ if (fetch_robust_entry(&uentry, &entry,
+- (compat_uptr_t *)&entry->next, &pi))
++ (compat_uptr_t __user *)&entry->next, &pi))
+ return;
+ /*
+ * Avoid excessively long or circular lists:
+@@ -103,10 +103,10 @@ compat_sys_set_robust_list(struct compat
+ }
+
+ asmlinkage long
+-compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
++compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
+ compat_size_t __user *len_ptr)
+ {
+- struct compat_robust_list_head *head;
++ struct compat_robust_list_head __user *head;
+ unsigned long ret;
+
+ if (!pid)
+diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
+index 21c38a7..d0ba190 100644
+--- a/kernel/hrtimer.c
++++ b/kernel/hrtimer.c
+@@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct h
+ return t->task == NULL;
+ }
+
+-static long __sched nanosleep_restart(struct restart_block *restart)
++long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
+ {
+ struct hrtimer_sleeper t;
+ struct timespec __user *rmtp;
+@@ -702,13 +702,13 @@ static long __sched nanosleep_restart(st
+
+ restart->fn = do_no_restart_syscall;
+
+- hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
+- t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
++ hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS);
++ t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2;
+
+ if (do_nanosleep(&t, HRTIMER_ABS))
+ return 0;
+
+- rmtp = (struct timespec __user *) restart->arg2;
++ rmtp = (struct timespec __user *) restart->arg1;
+ if (rmtp) {
+ time = ktime_sub(t.timer.expires, t.timer.base->get_time());
+ if (time.tv64 <= 0)
+@@ -718,7 +718,7 @@ static long __sched nanosleep_restart(st
+ return -EFAULT;
+ }
+
+- restart->fn = nanosleep_restart;
++ restart->fn = hrtimer_nanosleep_restart;
+
+ /* The other values in restart are already filled in */
+ return -ERESTART_RESTARTBLOCK;
+@@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *
+ }
+
+ restart = ¤t_thread_info()->restart_block;
+- restart->fn = nanosleep_restart;
+- restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
+- restart->arg1 = t.timer.expires.tv64 >> 32;
+- restart->arg2 = (unsigned long) rmtp;
+- restart->arg3 = (unsigned long) t.timer.base->index;
++ restart->fn = hrtimer_nanosleep_restart;
++ restart->arg0 = (unsigned long) t.timer.base->index;
++ restart->arg1 = (unsigned long) rmtp;
++ restart->arg2 = t.timer.expires.tv64 & 0xFFFFFFFF;
++ restart->arg3 = t.timer.expires.tv64 >> 32;
+
+ return -ERESTART_RESTARTBLOCK;
+ }
+diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
+index ac1f850..2d0dc3e 100644
+--- a/kernel/irq/chip.c
++++ b/kernel/irq/chip.c
+@@ -18,6 +18,69 @@
+ #include "internals.h"
+
+ /**
++ * dynamic_irq_init - initialize a dynamically allocated irq
++ * @irq: irq number to initialize
++ */
++void dynamic_irq_init(unsigned int irq)
++{
++ struct irq_desc *desc;
++ unsigned long flags;
++
++ if (irq >= NR_IRQS) {
++ printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
++ WARN_ON(1);
++ return;
++ }
++
++ /* Ensure we don't have left over values from a previous use of this irq */
++ desc = irq_desc + irq;
++ spin_lock_irqsave(&desc->lock, flags);
++ desc->status = IRQ_DISABLED;
++ desc->chip = &no_irq_chip;
++ desc->handle_irq = handle_bad_irq;
++ desc->depth = 1;
++ desc->handler_data = NULL;
++ desc->chip_data = NULL;
++ desc->action = NULL;
++ desc->irq_count = 0;
++ desc->irqs_unhandled = 0;
++#ifdef CONFIG_SMP
++ desc->affinity = CPU_MASK_ALL;
++#endif
++ spin_unlock_irqrestore(&desc->lock, flags);
++}
++
++/**
++ * dynamic_irq_cleanup - cleanup a dynamically allocated irq
++ * @irq: irq number to initialize
++ */
++void dynamic_irq_cleanup(unsigned int irq)
++{
++ struct irq_desc *desc;
++ unsigned long flags;
++
++ if (irq >= NR_IRQS) {
++ printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
++ WARN_ON(1);
++ return;
++ }
++
++ desc = irq_desc + irq;
++ spin_lock_irqsave(&desc->lock, flags);
++ if (desc->action) {
++ spin_unlock_irqrestore(&desc->lock, flags);
++ printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n",
++ irq);
++ WARN_ON(1);
++ return;
++ }
++ desc->handle_irq = handle_bad_irq;
++ desc->chip = &no_irq_chip;
++ spin_unlock_irqrestore(&desc->lock, flags);
++}
++
++
++/**
+ * set_irq_chip - set the irq chip for an irq
+ * @irq: irq number
+ * @chip: pointer to irq chip description structure
+@@ -40,10 +103,6 @@ int set_irq_chip(unsigned int irq, struc
+ spin_lock_irqsave(&desc->lock, flags);
+ irq_chip_set_defaults(chip);
+ desc->chip = chip;
+- /*
+- * For compatibility only:
+- */
+- desc->chip = chip;
+ spin_unlock_irqrestore(&desc->lock, flags);
+
+ return 0;
+@@ -146,7 +205,7 @@ static void default_disable(unsigned int
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (!(desc->status & IRQ_DELAYED_DISABLE))
+- irq_desc[irq].chip->mask(irq);
++ desc->chip->mask(irq);
+ }
+
+ /*
+@@ -190,7 +249,6 @@ static inline void mask_ack_irq(struct i
+ * handle_simple_irq - Simple and software-decoded IRQs.
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+- * @regs: pointer to a register structure
+ *
+ * Simple interrupts are either sent from a demultiplexing interrupt
+ * handler or come from hardware, where no interrupt hardware control
+@@ -200,7 +258,7 @@ static inline void mask_ack_irq(struct i
+ * unmask issues if necessary.
+ */
+ void fastcall
+-handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
++handle_simple_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ struct irqaction *action;
+ irqreturn_t action_ret;
+@@ -220,9 +278,9 @@ handle_simple_irq(unsigned int irq, stru
+ desc->status |= IRQ_INPROGRESS;
+ spin_unlock(&desc->lock);
+
+- action_ret = handle_IRQ_event(irq, regs, action);
++ action_ret = handle_IRQ_event(irq, action);
+ if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
++ note_interrupt(irq, desc, action_ret);
+
+ spin_lock(&desc->lock);
+ desc->status &= ~IRQ_INPROGRESS;
+@@ -234,7 +292,6 @@ out_unlock:
+ * handle_level_irq - Level type irq handler
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+- * @regs: pointer to a register structure
+ *
+ * Level type interrupts are active as long as the hardware line has
+ * the active level. This may require to mask the interrupt and unmask
+@@ -242,7 +299,7 @@ out_unlock:
+ * interrupt line is back to inactive.
+ */
+ void fastcall
+-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
++handle_level_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ unsigned int cpu = smp_processor_id();
+ struct irqaction *action;
+@@ -270,9 +327,9 @@ handle_level_irq(unsigned int irq, struc
+ desc->status &= ~IRQ_PENDING;
+ spin_unlock(&desc->lock);
+
+- action_ret = handle_IRQ_event(irq, regs, action);
++ action_ret = handle_IRQ_event(irq, action);
+ if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
++ note_interrupt(irq, desc, action_ret);
+
+ spin_lock(&desc->lock);
+ desc->status &= ~IRQ_INPROGRESS;
+@@ -286,7 +343,6 @@ out_unlock:
+ * handle_fasteoi_irq - irq handler for transparent controllers
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+- * @regs: pointer to a register structure
+ *
+ * Only a single callback will be issued to the chip: an ->eoi()
+ * call when the interrupt has been serviced. This enables support
+@@ -294,8 +350,7 @@ out_unlock:
+ * details in hardware, transparently.
+ */
+ void fastcall
+-handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
+- struct pt_regs *regs)
++handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ unsigned int cpu = smp_processor_id();
+ struct irqaction *action;
+@@ -323,9 +378,9 @@ handle_fasteoi_irq(unsigned int irq, str
+ desc->status &= ~IRQ_PENDING;
+ spin_unlock(&desc->lock);
+
+- action_ret = handle_IRQ_event(irq, regs, action);
++ action_ret = handle_IRQ_event(irq, action);
+ if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
++ note_interrupt(irq, desc, action_ret);
+
+ spin_lock(&desc->lock);
+ desc->status &= ~IRQ_INPROGRESS;
+@@ -339,7 +394,6 @@ out:
+ * handle_edge_irq - edge type IRQ handler
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+- * @regs: pointer to a register structure
+ *
+ * Interrupt occures on the falling and/or rising edge of a hardware
+ * signal. The occurence is latched into the irq controller hardware
+@@ -353,7 +407,7 @@ out:
+ * loop is left.
+ */
+ void fastcall
+-handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
++handle_edge_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ const unsigned int cpu = smp_processor_id();
+
+@@ -404,9 +458,9 @@ handle_edge_irq(unsigned int irq, struct
+
+ desc->status &= ~IRQ_PENDING;
+ spin_unlock(&desc->lock);
+- action_ret = handle_IRQ_event(irq, regs, action);
++ action_ret = handle_IRQ_event(irq, action);
+ if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
++ note_interrupt(irq, desc, action_ret);
+ spin_lock(&desc->lock);
+
+ } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+@@ -421,12 +475,11 @@ out_unlock:
+ * handle_percpu_IRQ - Per CPU local irq handler
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+- * @regs: pointer to a register structure
+ *
+ * Per CPU interrupts on SMP machines without locking requirements
+ */
+ void fastcall
+-handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
++handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ irqreturn_t action_ret;
+
+@@ -435,9 +488,9 @@ handle_percpu_irq(unsigned int irq, stru
+ if (desc->chip->ack)
+ desc->chip->ack(irq);
+
+- action_ret = handle_IRQ_event(irq, regs, desc->action);
++ action_ret = handle_IRQ_event(irq, desc->action);
+ if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
++ note_interrupt(irq, desc, action_ret);
+
+ if (desc->chip->eoi)
+ desc->chip->eoi(irq);
+@@ -446,10 +499,8 @@ handle_percpu_irq(unsigned int irq, stru
+ #endif /* CONFIG_SMP */
+
+ void
+-__set_irq_handler(unsigned int irq,
+- void fastcall (*handle)(unsigned int, irq_desc_t *,
+- struct pt_regs *),
+- int is_chained)
++__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
++ const char *name)
+ {
+ struct irq_desc *desc;
+ unsigned long flags;
+@@ -490,6 +541,7 @@ __set_irq_handler(unsigned int irq,
+ desc->depth = 1;
+ }
+ desc->handle_irq = handle;
++ desc->name = name;
+
+ if (handle != handle_bad_irq && is_chained) {
+ desc->status &= ~IRQ_DISABLED;
+@@ -502,36 +554,16 @@ __set_irq_handler(unsigned int irq,
+
+ void
+ set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+- void fastcall (*handle)(unsigned int,
+- struct irq_desc *,
+- struct pt_regs *))
++ irq_flow_handler_t handle)
+ {
+ set_irq_chip(irq, chip);
+- __set_irq_handler(irq, handle, 0);
++ __set_irq_handler(irq, handle, 0, NULL);
+ }
+
+-/*
+- * Get a descriptive string for the highlevel handler, for
+- * /proc/interrupts output:
+- */
+-const char *
+-handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
+- struct pt_regs *))
++void
++set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
++ irq_flow_handler_t handle, const char *name)
+ {
+- if (handle == handle_level_irq)
+- return "level ";
+- if (handle == handle_fasteoi_irq)
+- return "fasteoi";
+- if (handle == handle_edge_irq)
+- return "edge ";
+- if (handle == handle_simple_irq)
+- return "simple ";
+-#ifdef CONFIG_SMP
+- if (handle == handle_percpu_irq)
+- return "percpu ";
+-#endif
+- if (handle == handle_bad_irq)
+- return "bad ";
+-
+- return NULL;
++ set_irq_chip(irq, chip);
++ __set_irq_handler(irq, handle, 0, name);
+ }
+diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
+index 48a53f6..42aa6f1 100644
+--- a/kernel/irq/handle.c
++++ b/kernel/irq/handle.c
+@@ -27,7 +27,7 @@
+ * Handles spurious and unhandled IRQ's. It also prints a debugmessage.
+ */
+ void fastcall
+-handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
++handle_bad_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ print_irq_desc(irq, desc);
+ kstat_this_cpu.irqs[irq]++;
+@@ -115,7 +115,7 @@ struct irq_chip dummy_irq_chip = {
+ /*
+ * Special, empty irq handler:
+ */
+-irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
++irqreturn_t no_action(int cpl, void *dev_id)
+ {
+ return IRQ_NONE;
+ }
+@@ -123,13 +123,11 @@ irqreturn_t no_action(int cpl, void *dev
+ /**
+ * handle_IRQ_event - irq action chain handler
+ * @irq: the interrupt number
+- * @regs: pointer to a register structure
+ * @action: the interrupt action chain for this irq
+ *
+ * Handles the action chain of an irq event
+ */
+-irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+- struct irqaction *action)
++irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
+ {
+ irqreturn_t ret, retval = IRQ_NONE;
+ unsigned int status = 0;
+@@ -140,7 +138,7 @@ irqreturn_t handle_IRQ_event(unsigned in
+ local_irq_enable_in_hardirq();
+
+ do {
+- ret = action->handler(irq, action->dev_id, regs);
++ ret = action->handler(irq, action->dev_id);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+@@ -154,10 +152,10 @@ irqreturn_t handle_IRQ_event(unsigned in
+ return retval;
+ }
+
++#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
+ /**
+ * __do_IRQ - original all in one highlevel IRQ handler
+ * @irq: the interrupt number
+- * @regs: pointer to a register structure
+ *
+ * __do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+@@ -166,7 +164,7 @@ irqreturn_t handle_IRQ_event(unsigned in
+ * This is the original x86 implementation which is used for every
+ * interrupt type.
+ */
+-fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
++fastcall unsigned int __do_IRQ(unsigned int irq)
+ {
+ struct irq_desc *desc = irq_desc + irq;
+ struct irqaction *action;
+@@ -181,7 +179,7 @@ fastcall unsigned int __do_IRQ(unsigned
+ */
+ if (desc->chip->ack)
+ desc->chip->ack(irq);
+- action_ret = handle_IRQ_event(irq, regs, desc->action);
++ action_ret = handle_IRQ_event(irq, desc->action);
+ desc->chip->end(irq);
+ return 1;
+ }
+@@ -232,11 +230,11 @@ fastcall unsigned int __do_IRQ(unsigned
+
+ spin_unlock(&desc->lock);
+
+- action_ret = handle_IRQ_event(irq, regs, action);
++ action_ret = handle_IRQ_event(irq, action);
+
+ spin_lock(&desc->lock);
+ if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
++ note_interrupt(irq, desc, action_ret);
+ if (likely(!(desc->status & IRQ_PENDING)))
+ break;
+ desc->status &= ~IRQ_PENDING;
+@@ -253,6 +251,7 @@ out:
+
+ return 1;
+ }
++#endif
+
+ #ifdef CONFIG_TRACE_IRQFLAGS
+
+diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
+index 92be519..6879202 100644
+--- a/kernel/irq/manage.c
++++ b/kernel/irq/manage.c
+@@ -427,8 +427,7 @@ EXPORT_SYMBOL(free_irq);
+ * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
+ *
+ */
+-int request_irq(unsigned int irq,
+- irqreturn_t (*handler)(int, void *, struct pt_regs *),
++int request_irq(unsigned int irq, irq_handler_t handler,
+ unsigned long irqflags, const char *devname, void *dev_id)
+ {
+ struct irqaction *action;
+@@ -475,4 +474,3 @@ int request_irq(unsigned int irq,
+ return retval;
+ }
+ EXPORT_SYMBOL(request_irq);
+-
+diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
+index a57ebe9..4baa3bb 100644
+--- a/kernel/irq/migration.c
++++ b/kernel/irq/migration.c
+@@ -7,17 +7,17 @@ void set_pending_irq(unsigned int irq, c
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+- desc->move_irq = 1;
++ desc->status |= IRQ_MOVE_PENDING;
+ irq_desc[irq].pending_mask = mask;
+ spin_unlock_irqrestore(&desc->lock, flags);
+ }
+
+-void move_native_irq(int irq)
++void move_masked_irq(int irq)
+ {
+ struct irq_desc *desc = irq_desc + irq;
+ cpumask_t tmp;
+
+- if (likely(!desc->move_irq))
++ if (likely(!(desc->status & IRQ_MOVE_PENDING)))
+ return;
+
+ /*
+@@ -28,7 +28,7 @@ void move_native_irq(int irq)
+ return;
+ }
+
+- desc->move_irq = 0;
++ desc->status &= ~IRQ_MOVE_PENDING;
+
+ if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
+ return;
+@@ -48,15 +48,29 @@ void move_native_irq(int irq)
+ * when an active trigger is comming in. This could
+ * cause some ioapics to mal-function.
+ * Being paranoid i guess!
++ *
++ * For correct operation this depends on the caller
++ * masking the irqs.
+ */
+ if (likely(!cpus_empty(tmp))) {
+- if (likely(!(desc->status & IRQ_DISABLED)))
+- desc->chip->disable(irq);
+-
+ desc->chip->set_affinity(irq,tmp);
+-
+- if (likely(!(desc->status & IRQ_DISABLED)))
+- desc->chip->enable(irq);
+ }
+ cpus_clear(irq_desc[irq].pending_mask);
+ }
++
++void move_native_irq(int irq)
++{
++ struct irq_desc *desc = irq_desc + irq;
++
++ if (likely(!(desc->status & IRQ_MOVE_PENDING)))
++ return;
++
++ if (likely(!(desc->status & IRQ_DISABLED)))
++ desc->chip->disable(irq);
++
++ move_masked_irq(irq);
++
++ if (likely(!(desc->status & IRQ_DISABLED)))
++ desc->chip->enable(irq);
++}
++
+diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
+index 607c780..9a35266 100644
+--- a/kernel/irq/proc.c
++++ b/kernel/irq/proc.c
+@@ -57,7 +57,7 @@ static int irq_affinity_write_proc(struc
+ if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
+ return -EIO;
+
+- err = cpumask_parse(buffer, count, new_value);
++ err = cpumask_parse_user(buffer, count, new_value);
+ if (err)
+ return err;
+
+diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
+index 35f10f7..5bfeaed 100644
+--- a/kernel/irq/resend.c
++++ b/kernel/irq/resend.c
+@@ -38,7 +38,7 @@ static void resend_irqs(unsigned long ar
+ clear_bit(irq, irqs_resend);
+ desc = irq_desc + irq;
+ local_irq_disable();
+- desc->handle_irq(irq, desc, NULL);
++ desc->handle_irq(irq, desc);
+ local_irq_enable();
+ }
+ }
+diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
+index 417e980..543ea2e 100644
+--- a/kernel/irq/spurious.c
++++ b/kernel/irq/spurious.c
+@@ -16,7 +16,7 @@ static int irqfixup __read_mostly;
+ /*
+ * Recovery handler for misrouted interrupts.
+ */
+-static int misrouted_irq(int irq, struct pt_regs *regs)
++static int misrouted_irq(int irq)
+ {
+ int i;
+ int ok = 0;
+@@ -49,7 +49,7 @@ static int misrouted_irq(int irq, struct
+ while (action) {
+ /* Only shared IRQ handlers are safe to call */
+ if (action->flags & IRQF_SHARED) {
+- if (action->handler(i, action->dev_id, regs) ==
++ if (action->handler(i, action->dev_id) ==
+ IRQ_HANDLED)
+ ok = 1;
+ }
+@@ -70,7 +70,7 @@ static int misrouted_irq(int irq, struct
+ */
+ work = 1;
+ spin_unlock(&desc->lock);
+- handle_IRQ_event(i, regs, action);
++ handle_IRQ_event(i, action);
+ spin_lock(&desc->lock);
+ desc->status &= ~IRQ_PENDING;
+ }
+@@ -136,7 +136,7 @@ report_bad_irq(unsigned int irq, struct
+ }
+
+ void note_interrupt(unsigned int irq, struct irq_desc *desc,
+- irqreturn_t action_ret, struct pt_regs *regs)
++ irqreturn_t action_ret)
+ {
+ if (unlikely(action_ret != IRQ_HANDLED)) {
+ desc->irqs_unhandled++;
+@@ -147,7 +147,7 @@ void note_interrupt(unsigned int irq, st
+ if (unlikely(irqfixup)) {
+ /* Don't punish working computers */
+ if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
+- int ok = misrouted_irq(irq, regs);
++ int ok = misrouted_irq(irq);
+ if (action_ret == IRQ_NONE)
+ desc->irqs_unhandled -= ok;
+ }
+diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
+index ab16a5a..eeac3e3 100644
+--- a/kernel/kallsyms.c
++++ b/kernel/kallsyms.c
+@@ -69,6 +69,15 @@ static inline int is_kernel(unsigned lon
+ return in_gate_area_no_task(addr);
+ }
+
++static int is_ksym_addr(unsigned long addr)
++{
++ if (all_var)
++ return is_kernel(addr);
++
++ return is_kernel_text(addr) || is_kernel_inittext(addr) ||
++ is_kernel_extratext(addr);
++}
++
+ /* expand a compressed symbol data into the resulting uncompressed string,
+ given the offset to where the symbol is in the compressed stream */
+ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
+@@ -154,7 +163,73 @@ unsigned long kallsyms_lookup_name(const
+ }
+ return module_kallsyms_lookup_name(name);
+ }
+-EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
++
++static unsigned long get_symbol_pos(unsigned long addr,
++ unsigned long *symbolsize,
++ unsigned long *offset)
++{
++ unsigned long symbol_start = 0, symbol_end = 0;
++ unsigned long i, low, high, mid;
++
++ /* This kernel should never had been booted. */
++ BUG_ON(!kallsyms_addresses);
++
++ /* do a binary search on the sorted kallsyms_addresses array */
++ low = 0;
++ high = kallsyms_num_syms;
++
++ while (high - low > 1) {
++ mid = (low + high) / 2;
++ if (kallsyms_addresses[mid] <= addr)
++ low = mid;
++ else
++ high = mid;
++ }
++
++ /*
++ * search for the first aliased symbol. Aliased
++ * symbols are symbols with the same address
++ */
++ while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
++ --low;
++
++ symbol_start = kallsyms_addresses[low];
++
++ /* Search for next non-aliased symbol */
++ for (i = low + 1; i < kallsyms_num_syms; i++) {
++ if (kallsyms_addresses[i] > symbol_start) {
++ symbol_end = kallsyms_addresses[i];
++ break;
++ }
++ }
++
++ /* if we found no next symbol, we use the end of the section */
++ if (!symbol_end) {
++ if (is_kernel_inittext(addr))
++ symbol_end = (unsigned long)_einittext;
++ else if (all_var)
++ symbol_end = (unsigned long)_end;
++ else
++ symbol_end = (unsigned long)_etext;
++ }
++
++ *symbolsize = symbol_end - symbol_start;
++ *offset = addr - symbol_start;
++
++ return low;
++}
++
++/*
++ * Lookup an address but don't bother to find any names.
++ */
++int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
++ unsigned long *offset)
++{
++ if (is_ksym_addr(addr))
++ return !!get_symbol_pos(addr, symbolsize, offset);
++
++ return !!module_address_lookup(addr, symbolsize, offset, NULL);
++}
+
+ /*
+ * Lookup an address
+@@ -168,57 +243,18 @@ const char *kallsyms_lookup(unsigned lon
+ unsigned long *offset,
+ char **modname, char *namebuf)
+ {
+- unsigned long i, low, high, mid;
+ const char *msym;
+
+- /* This kernel should never had been booted. */
+- BUG_ON(!kallsyms_addresses);
+-
+ namebuf[KSYM_NAME_LEN] = 0;
+ namebuf[0] = 0;
+
+- if ((all_var && is_kernel(addr)) ||
+- (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
+- is_kernel_extratext(addr)))) {
+- unsigned long symbol_end = 0;
+-
+- /* do a binary search on the sorted kallsyms_addresses array */
+- low = 0;
+- high = kallsyms_num_syms;
+-
+- while (high-low > 1) {
+- mid = (low + high) / 2;
+- if (kallsyms_addresses[mid] <= addr) low = mid;
+- else high = mid;
+- }
+-
+- /* search for the first aliased symbol. Aliased symbols are
+- symbols with the same address */
+- while (low && kallsyms_addresses[low - 1] == kallsyms_addresses[low])
+- --low;
++ if (is_ksym_addr(addr)) {
++ unsigned long pos;
+
++ pos = get_symbol_pos(addr, symbolsize, offset);
+ /* Grab name */
+- kallsyms_expand_symbol(get_symbol_offset(low), namebuf);
+-
+- /* Search for next non-aliased symbol */
+- for (i = low + 1; i < kallsyms_num_syms; i++) {
+- if (kallsyms_addresses[i] > kallsyms_addresses[low]) {
+- symbol_end = kallsyms_addresses[i];
+- break;
+- }
+- }
+-
+- /* if we found no next symbol, we use the end of the section */
+- if (!symbol_end) {
+- if (is_kernel_inittext(addr))
+- symbol_end = (unsigned long)_einittext;
+- else
+- symbol_end = all_var ? (unsigned long)_end : (unsigned long)_etext;
+- }
+-
+- *symbolsize = symbol_end - kallsyms_addresses[low];
++ kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
+ *modname = NULL;
+- *offset = addr - kallsyms_addresses[low];
+ return namebuf;
+ }
+
+diff --git a/kernel/kexec.c b/kernel/kexec.c
+index 50087ec..fcdd5d2 100644
+--- a/kernel/kexec.c
++++ b/kernel/kexec.c
+@@ -40,7 +40,7 @@ struct resource crashk_res = {
+
+ int kexec_should_crash(struct task_struct *p)
+ {
+- if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops)
++ if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops)
+ return 1;
+ return 0;
+ }
+@@ -995,7 +995,8 @@ asmlinkage long sys_kexec_load(unsigned
+ image = xchg(dest_image, image);
+
+ out:
+- xchg(&kexec_lock, 0); /* Release the mutex */
++ locked = xchg(&kexec_lock, 0); /* Release the mutex */
++ BUG_ON(!locked);
+ kimage_free(image);
+
+ return result;
+@@ -1061,7 +1062,8 @@ void crash_kexec(struct pt_regs *regs)
+ machine_crash_shutdown(&fixed_regs);
+ machine_kexec(kexec_crash_image);
+ }
+- xchg(&kexec_lock, 0);
++ locked = xchg(&kexec_lock, 0);
++ BUG_ON(!locked);
+ }
+ }
+
+diff --git a/kernel/kfifo.c b/kernel/kfifo.c
+index 64ab045..5d1d907 100644
+--- a/kernel/kfifo.c
++++ b/kernel/kfifo.c
+@@ -122,6 +122,13 @@ unsigned int __kfifo_put(struct kfifo *f
+
+ len = min(len, fifo->size - fifo->in + fifo->out);
+
++ /*
++ * Ensure that we sample the fifo->out index -before- we
++ * start putting bytes into the kfifo.
++ */
++
++ smp_mb();
++
+ /* first put the data starting from fifo->in to buffer end */
+ l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
+ memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
+@@ -129,6 +136,13 @@ unsigned int __kfifo_put(struct kfifo *f
+ /* then put the rest (if any) at the beginning of the buffer */
+ memcpy(fifo->buffer, buffer + l, len - l);
+
++ /*
++ * Ensure that we add the bytes to the kfifo -before-
++ * we update the fifo->in index.
++ */
++
++ smp_wmb();
++
+ fifo->in += len;
+
+ return len;
+@@ -154,6 +168,13 @@ unsigned int __kfifo_get(struct kfifo *f
+
+ len = min(len, fifo->in - fifo->out);
+
++ /*
++ * Ensure that we sample the fifo->in index -before- we
++ * start removing bytes from the kfifo.
++ */
++
++ smp_rmb();
++
+ /* first get the data from fifo->out until the end of the buffer */
+ l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
+ memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
+@@ -161,6 +182,13 @@ unsigned int __kfifo_get(struct kfifo *f
+ /* then get the rest (if any) from the beginning of the buffer */
+ memcpy(buffer + l, fifo->buffer, len - l);
+
++ /*
++ * Ensure that we remove the bytes from the kfifo -before-
++ * we update the fifo->out index.
++ */
++
++ smp_mb();
++
+ fifo->out += len;
+
+ return len;
+diff --git a/kernel/kmod.c b/kernel/kmod.c
+index 5c470c5..bb4e29d 100644
+--- a/kernel/kmod.c
++++ b/kernel/kmod.c
+@@ -18,8 +18,6 @@
+ call_usermodehelper wait flag, and remove exec_usermodehelper.
+ Rusty Russell <rusty at rustcorp.com.au> Jan 2003
+ */
+-#define __KERNEL_SYSCALLS__
+-
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/syscalls.h>
+@@ -35,6 +33,7 @@
+ #include <linux/mount.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
++#include <linux/resource.h>
+ #include <asm/uaccess.h>
+
+ extern int max_threads;
+@@ -122,6 +121,7 @@ struct subprocess_info {
+ struct key *ring;
+ int wait;
+ int retval;
++ struct file *stdin;
+ };
+
+ /*
+@@ -145,12 +145,30 @@ static int ____call_usermodehelper(void
+
+ key_put(old_session);
+
++ /* Install input pipe when needed */
++ if (sub_info->stdin) {
++ struct files_struct *f = current->files;
++ struct fdtable *fdt;
++ /* no races because files should be private here */
++ sys_close(0);
++ fd_install(0, sub_info->stdin);
++ spin_lock(&f->file_lock);
++ fdt = files_fdtable(f);
++ FD_SET(0, fdt->open_fds);
++ FD_CLR(0, fdt->close_on_exec);
++ spin_unlock(&f->file_lock);
++
++ /* and disallow core files too */
++ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0};
++ }
++
+ /* We can run anywhere, unlike our parent keventd(). */
+ set_cpus_allowed(current, CPU_MASK_ALL);
+
+ retval = -EPERM;
+ if (current->fs->root)
+- retval = execve(sub_info->path, sub_info->argv,sub_info->envp);
++ retval = kernel_execve(sub_info->path,
++ sub_info->argv, sub_info->envp);
+
+ /* Exec failed? */
+ sub_info->retval = retval;
+@@ -176,6 +194,8 @@ static int wait_for_helper(void *data)
+ if (pid < 0) {
+ sub_info->retval = pid;
+ } else {
++ int ret;
++
+ /*
+ * Normally it is bogus to call wait4() from in-kernel because
+ * wait4() wants to write the exit code to a userspace address.
+@@ -185,7 +205,15 @@ static int wait_for_helper(void *data)
+ *
+ * Thus the __user pointer cast is valid here.
+ */
+- sys_wait4(pid, (int __user *) &sub_info->retval, 0, NULL);
++ sys_wait4(pid, (int __user *)&ret, 0, NULL);
++
++ /*
++ * If ret is 0, either ____call_usermodehelper failed and the
++ * real error code is already in sub_info->retval or
++ * sub_info->retval is 0 anyway, so don't mess with it then.
++ */
++ if (ret)
++ sub_info->retval = ret;
+ }
+
+ complete(sub_info->complete);
+@@ -258,6 +286,44 @@ int call_usermodehelper_keys(char *path,
+ }
+ EXPORT_SYMBOL(call_usermodehelper_keys);
+
++int call_usermodehelper_pipe(char *path, char **argv, char **envp,
++ struct file **filp)
++{
++ DECLARE_COMPLETION(done);
++ struct subprocess_info sub_info = {
++ .complete = &done,
++ .path = path,
++ .argv = argv,
++ .envp = envp,
++ .retval = 0,
++ };
++ struct file *f;
++ DECLARE_WORK(work, __call_usermodehelper, &sub_info);
++
++ if (!khelper_wq)
++ return -EBUSY;
++
++ if (path[0] == '\0')
++ return 0;
++
++ f = create_write_pipe();
++ if (!f)
++ return -ENOMEM;
++ *filp = f;
++
++ f = create_read_pipe(f);
++ if (!f) {
++ free_write_pipe(*filp);
++ return -ENOMEM;
++ }
++ sub_info.stdin = f;
++
++ queue_work(khelper_wq, &work);
++ wait_for_completion(&done);
++ return sub_info.retval;
++}
++EXPORT_SYMBOL(call_usermodehelper_pipe);
++
+ void __init usermodehelper_init(void)
+ {
+ khelper_wq = create_singlethread_workqueue("khelper");
+diff --git a/kernel/kprobes.c b/kernel/kprobes.c
+index 3f57dfd..610c837 100644
+--- a/kernel/kprobes.c
++++ b/kernel/kprobes.c
+@@ -37,6 +37,7 @@
+ #include <linux/slab.h>
+ #include <linux/module.h>
+ #include <linux/moduleloader.h>
++#include <linux/kallsyms.h>
+ #include <asm-generic/sections.h>
+ #include <asm/cacheflush.h>
+ #include <asm/errno.h>
+@@ -45,6 +46,16 @@
+ #define KPROBE_HASH_BITS 6
+ #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
+
++
++/*
++ * Some oddball architectures like 64bit powerpc have function descriptors
++ * so this must be overridable.
++ */
++#ifndef kprobe_lookup_name
++#define kprobe_lookup_name(name, addr) \
++ addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name)))
++#endif
++
+ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
+ static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
+ static atomic_t kprobe_count;
+@@ -308,7 +319,8 @@ void __kprobes add_rp_inst(struct kretpr
+ }
+
+ /* Called with kretprobe_lock held */
+-void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
++void __kprobes recycle_rp_inst(struct kretprobe_instance *ri,
++ struct hlist_head *head)
+ {
+ /* remove rp inst off the rprobe_inst_table */
+ hlist_del(&ri->hlist);
+@@ -320,7 +332,7 @@ void __kprobes recycle_rp_inst(struct kr
+ hlist_add_head(&ri->uflist, &ri->rp->free_instances);
+ } else
+ /* Unregistering */
+- kfree(ri);
++ hlist_add_head(&ri->hlist, head);
+ }
+
+ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
+@@ -336,18 +348,24 @@ struct hlist_head __kprobes *kretprobe_i
+ */
+ void __kprobes kprobe_flush_task(struct task_struct *tk)
+ {
+- struct kretprobe_instance *ri;
+- struct hlist_head *head;
++ struct kretprobe_instance *ri;
++ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
+ unsigned long flags = 0;
+
++ INIT_HLIST_HEAD(&empty_rp);
+ spin_lock_irqsave(&kretprobe_lock, flags);
+- head = kretprobe_inst_table_head(tk);
+- hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+- if (ri->task == tk)
+- recycle_rp_inst(ri);
+- }
++ head = kretprobe_inst_table_head(tk);
++ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
++ if (ri->task == tk)
++ recycle_rp_inst(ri, &empty_rp);
++ }
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
++
++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++ hlist_del(&ri->hlist);
++ kfree(ri);
++ }
+ }
+
+ static inline void free_rp_inst(struct kretprobe *rp)
+@@ -447,6 +465,21 @@ static int __kprobes __register_kprobe(s
+ struct kprobe *old_p;
+ struct module *probed_mod;
+
++ /*
++ * If we have a symbol_name argument look it up,
++ * and add it to the address. That way the addr
++ * field can either be global or relative to a symbol.
++ */
++ if (p->symbol_name) {
++ if (p->addr)
++ return -EINVAL;
++ kprobe_lookup_name(p->symbol_name, p->addr);
++ }
++
++ if (!p->addr)
++ return -EINVAL;
++ p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset);
++
+ if ((!kernel_text_address((unsigned long) p->addr)) ||
+ in_kprobes_functions((unsigned long) p->addr))
+ return -EINVAL;
+@@ -488,7 +521,7 @@ static int __kprobes __register_kprobe(s
+ (ARCH_INACTIVE_KPROBE_COUNT + 1))
+ register_page_fault_notifier(&kprobe_page_fault_nb);
+
+- arch_arm_kprobe(p);
++ arch_arm_kprobe(p);
+
+ out:
+ mutex_unlock(&kprobe_mutex);
+diff --git a/kernel/latency.c b/kernel/latency.c
+new file mode 100644
+index 0000000..258f255
+--- /dev/null
++++ b/kernel/latency.c
+@@ -0,0 +1,279 @@
++/*
++ * latency.c: Explicit system-wide latency-expectation infrastructure
++ *
++ * The purpose of this infrastructure is to allow device drivers to set
++ * latency constraint they have and to collect and summarize these
++ * expectations globally. The cummulated result can then be used by
++ * power management and similar users to make decisions that have
++ * tradoffs with a latency component.
++ *
++ * An example user of this are the x86 C-states; each higher C state saves
++ * more power, but has a higher exit latency. For the idle loop power
++ * code to make a good decision which C-state to use, information about
++ * acceptable latencies is required.
++ *
++ * An example announcer of latency is an audio driver that knowns it
++ * will get an interrupt when the hardware has 200 usec of samples
++ * left in the DMA buffer; in that case the driver can set a latency
++ * constraint of, say, 150 usec.
++ *
++ * Multiple drivers can each announce their maximum accepted latency,
++ * to keep these appart, a string based identifier is used.
++ *
++ *
++ * (C) Copyright 2006 Intel Corporation
++ * Author: Arjan van de Ven <arjan at linux.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; version 2
++ * of the License.
++ */
++
++#include <linux/latency.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <asm/atomic.h>
++
++struct latency_info {
++ struct list_head list;
++ int usecs;
++ char *identifier;
++};
++
++/*
++ * locking rule: all modifications to current_max_latency and
++ * latency_list need to be done while holding the latency_lock.
++ * latency_lock needs to be taken _irqsave.
++ */
++static atomic_t current_max_latency;
++static DEFINE_SPINLOCK(latency_lock);
++
++static LIST_HEAD(latency_list);
++static BLOCKING_NOTIFIER_HEAD(latency_notifier);
++
++/*
++ * This function returns the maximum latency allowed, which
++ * happens to be the minimum of all maximum latencies on the
++ * list.
++ */
++static int __find_max_latency(void)
++{
++ int min = INFINITE_LATENCY;
++ struct latency_info *info;
++
++ list_for_each_entry(info, &latency_list, list) {
++ if (info->usecs < min)
++ min = info->usecs;
++ }
++ return min;
++}
++
++/**
++ * set_acceptable_latency - sets the maximum latency acceptable
++ * @identifier: string that identifies this driver
++ * @usecs: maximum acceptable latency for this driver
++ *
++ * This function informs the kernel that this device(driver)
++ * can accept at most usecs latency. This setting is used for
++ * power management and similar tradeoffs.
++ *
++ * This function sleeps and can only be called from process
++ * context.
++ * Calling this function with an existing identifier is valid
++ * and will cause the existing latency setting to be changed.
++ */
++void set_acceptable_latency(char *identifier, int usecs)
++{
++ struct latency_info *info, *iter;
++ unsigned long flags;
++ int found_old = 0;
++
++ info = kzalloc(sizeof(struct latency_info), GFP_KERNEL);
++ if (!info)
++ return;
++ info->usecs = usecs;
++ info->identifier = kstrdup(identifier, GFP_KERNEL);
++ if (!info->identifier)
++ goto free_info;
++
++ spin_lock_irqsave(&latency_lock, flags);
++ list_for_each_entry(iter, &latency_list, list) {
++ if (strcmp(iter->identifier, identifier)==0) {
++ found_old = 1;
++ iter->usecs = usecs;
++ break;
++ }
++ }
++ if (!found_old)
++ list_add(&info->list, &latency_list);
++
++ if (usecs < atomic_read(¤t_max_latency))
++ atomic_set(¤t_max_latency, usecs);
++
++ spin_unlock_irqrestore(&latency_lock, flags);
++
++ blocking_notifier_call_chain(&latency_notifier,
++ atomic_read(¤t_max_latency), NULL);
++
++ /*
++ * if we inserted the new one, we're done; otherwise there was
++ * an existing one so we need to free the redundant data
++ */
++ if (!found_old)
++ return;
++
++ kfree(info->identifier);
++free_info:
++ kfree(info);
++}
++EXPORT_SYMBOL_GPL(set_acceptable_latency);
++
++/**
++ * modify_acceptable_latency - changes the maximum latency acceptable
++ * @identifier: string that identifies this driver
++ * @usecs: maximum acceptable latency for this driver
++ *
++ * This function informs the kernel that this device(driver)
++ * can accept at most usecs latency. This setting is used for
++ * power management and similar tradeoffs.
++ *
++ * This function does not sleep and can be called in any context.
++ * Trying to use a non-existing identifier silently gets ignored.
++ *
++ * Due to the atomic nature of this function, the modified latency
++ * value will only be used for future decisions; past decisions
++ * can still lead to longer latencies in the near future.
++ */
++void modify_acceptable_latency(char *identifier, int usecs)
++{
++ struct latency_info *iter;
++ unsigned long flags;
++
++ spin_lock_irqsave(&latency_lock, flags);
++ list_for_each_entry(iter, &latency_list, list) {
++ if (strcmp(iter->identifier, identifier) == 0) {
++ iter->usecs = usecs;
++ break;
++ }
++ }
++ if (usecs < atomic_read(¤t_max_latency))
++ atomic_set(¤t_max_latency, usecs);
++ spin_unlock_irqrestore(&latency_lock, flags);
++}
++EXPORT_SYMBOL_GPL(modify_acceptable_latency);
++
++/**
++ * remove_acceptable_latency - removes the maximum latency acceptable
++ * @identifier: string that identifies this driver
++ *
++ * This function removes a previously set maximum latency setting
++ * for the driver and frees up any resources associated with the
++ * bookkeeping needed for this.
++ *
++ * This function does not sleep and can be called in any context.
++ * Trying to use a non-existing identifier silently gets ignored.
++ */
++void remove_acceptable_latency(char *identifier)
++{
++ unsigned long flags;
++ int newmax = 0;
++ struct latency_info *iter, *temp;
++
++ spin_lock_irqsave(&latency_lock, flags);
++
++ list_for_each_entry_safe(iter, temp, &latency_list, list) {
++ if (strcmp(iter->identifier, identifier) == 0) {
++ list_del(&iter->list);
++ newmax = iter->usecs;
++ kfree(iter->identifier);
++ kfree(iter);
++ break;
++ }
++ }
++
++ /* If we just deleted the system wide value, we need to
++ * recalculate with a full search
++ */
++ if (newmax == atomic_read(¤t_max_latency)) {
++ newmax = __find_max_latency();
++ atomic_set(¤t_max_latency, newmax);
++ }
++ spin_unlock_irqrestore(&latency_lock, flags);
++}
++EXPORT_SYMBOL_GPL(remove_acceptable_latency);
++
++/**
++ * system_latency_constraint - queries the system wide latency maximum
++ *
++ * This function returns the system wide maximum latency in
++ * microseconds.
++ *
++ * This function does not sleep and can be called in any context.
++ */
++int system_latency_constraint(void)
++{
++ return atomic_read(¤t_max_latency);
++}
++EXPORT_SYMBOL_GPL(system_latency_constraint);
++
++/**
++ * synchronize_acceptable_latency - recalculates all latency decisions
++ *
++ * This function will cause a callback to various kernel pieces that
++ * will make those pieces rethink their latency decisions. This implies
++ * that if there are overlong latencies in hardware state already, those
++ * latencies get taken right now. When this call completes no overlong
++ * latency decisions should be active anymore.
++ *
++ * Typical usecase of this is after a modify_acceptable_latency() call,
++ * which in itself is non-blocking and non-synchronizing.
++ *
++ * This function blocks and should not be called with locks held.
++ */
++
++void synchronize_acceptable_latency(void)
++{
++ blocking_notifier_call_chain(&latency_notifier,
++ atomic_read(¤t_max_latency), NULL);
++}
++EXPORT_SYMBOL_GPL(synchronize_acceptable_latency);
++
++/*
++ * Latency notifier: this notifier gets called when a non-atomic new
++ * latency value gets set. The expectation nof the caller of the
++ * non-atomic set is that when the call returns, future latencies
++ * are within bounds, so the functions on the notifier list are
++ * expected to take the overlong latencies immediately, inside the
++ * callback, and not make a overlong latency decision anymore.
++ *
++ * The callback gets called when the new latency value is made
++ * active so system_latency_constraint() returns the new latency.
++ */
++int register_latency_notifier(struct notifier_block * nb)
++{
++ return blocking_notifier_chain_register(&latency_notifier, nb);
++}
++EXPORT_SYMBOL_GPL(register_latency_notifier);
++
++int unregister_latency_notifier(struct notifier_block * nb)
++{
++ return blocking_notifier_chain_unregister(&latency_notifier, nb);
++}
++EXPORT_SYMBOL_GPL(unregister_latency_notifier);
++
++static __init int latency_init(void)
++{
++ atomic_set(¤t_max_latency, INFINITE_LATENCY);
++ /*
++ * we don't want by default to have longer latencies than 2 ticks,
++ * since that would cause lost ticks
++ */
++ set_acceptable_latency("kernel", 2*1000000/HZ);
++ return 0;
++}
++
++module_init(latency_init);
+diff --git a/kernel/lockdep.c b/kernel/lockdep.c
+index 9bad178..b739be2 100644
+--- a/kernel/lockdep.c
++++ b/kernel/lockdep.c
+@@ -36,6 +36,7 @@
+ #include <linux/stacktrace.h>
+ #include <linux/debug_locks.h>
+ #include <linux/irqflags.h>
++#include <linux/utsname.h>
+
+ #include <asm/sections.h>
+
+@@ -121,8 +122,8 @@ static struct list_head chainhash_table[
+ * unique.
+ */
+ #define iterate_chain_key(key1, key2) \
+- (((key1) << MAX_LOCKDEP_KEYS_BITS/2) ^ \
+- ((key1) >> (64-MAX_LOCKDEP_KEYS_BITS/2)) ^ \
++ (((key1) << MAX_LOCKDEP_KEYS_BITS) ^ \
++ ((key1) >> (64-MAX_LOCKDEP_KEYS_BITS)) ^ \
+ (key2))
+
+ void lockdep_off(void)
+@@ -224,7 +225,14 @@ static int save_trace(struct stack_trace
+ trace->max_entries = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries;
+ trace->entries = stack_trace + nr_stack_trace_entries;
+
+- save_stack_trace(trace, NULL, 0, 3);
++ trace->skip = 3;
++ trace->all_contexts = 0;
++
++ /* Make sure to not recurse in case the the unwinder needs to tak
++e locks. */
++ lockdep_off();
++ save_stack_trace(trace, NULL);
++ lockdep_on();
+
+ trace->max_entries = trace->nr_entries;
+
+@@ -508,6 +516,13 @@ print_circular_bug_entry(struct lock_lis
+ return 0;
+ }
+
++static void print_kernel_version(void)
++{
++ printk("%s %.*s\n", init_utsname()->release,
++ (int)strcspn(init_utsname()->version, " "),
++ init_utsname()->version);
++}
++
+ /*
+ * When a circular dependency is detected, print the
+ * header first:
+@@ -524,6 +539,7 @@ print_circular_bug_header(struct lock_li
+
+ printk("\n=======================================================\n");
+ printk( "[ INFO: possible circular locking dependency detected ]\n");
++ print_kernel_version();
+ printk( "-------------------------------------------------------\n");
+ printk("%s/%d is trying to acquire lock:\n",
+ curr->comm, curr->pid);
+@@ -559,6 +575,8 @@ static noinline int print_circular_bug_t
+ return 0;
+ }
+
++#define RECURSION_LIMIT 40
++
+ static int noinline print_infinite_recursion_bug(void)
+ {
+ __raw_spin_unlock(&hash_lock);
+@@ -579,7 +597,7 @@ check_noncircular(struct lock_class *sou
+ debug_atomic_inc(&nr_cyclic_check_recursions);
+ if (depth > max_recursion_depth)
+ max_recursion_depth = depth;
+- if (depth >= 20)
++ if (depth >= RECURSION_LIMIT)
+ return print_infinite_recursion_bug();
+ /*
+ * Check this lock's dependency list:
+@@ -629,7 +647,7 @@ find_usage_forwards(struct lock_class *s
+
+ if (depth > max_recursion_depth)
+ max_recursion_depth = depth;
+- if (depth >= 20)
++ if (depth >= RECURSION_LIMIT)
+ return print_infinite_recursion_bug();
+
+ debug_atomic_inc(&nr_find_usage_forwards_checks);
+@@ -668,7 +686,7 @@ find_usage_backwards(struct lock_class *
+
+ if (depth > max_recursion_depth)
+ max_recursion_depth = depth;
+- if (depth >= 20)
++ if (depth >= RECURSION_LIMIT)
+ return print_infinite_recursion_bug();
+
+ debug_atomic_inc(&nr_find_usage_backwards_checks);
+@@ -705,6 +723,7 @@ print_bad_irq_dependency(struct task_str
+ printk("\n======================================================\n");
+ printk( "[ INFO: %s-safe -> %s-unsafe lock order detected ]\n",
+ irqclass, irqclass);
++ print_kernel_version();
+ printk( "------------------------------------------------------\n");
+ printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n",
+ curr->comm, curr->pid,
+@@ -786,6 +805,7 @@ print_deadlock_bug(struct task_struct *c
+
+ printk("\n=============================================\n");
+ printk( "[ INFO: possible recursive locking detected ]\n");
++ print_kernel_version();
+ printk( "---------------------------------------------\n");
+ printk("%s/%d is trying to acquire lock:\n",
+ curr->comm, curr->pid);
+@@ -1096,8 +1116,6 @@ static int count_matching_names(struct l
+ return count + 1;
+ }
+
+-extern void __error_too_big_MAX_LOCKDEP_SUBCLASSES(void);
+-
+ /*
+ * Register a lock's class in the hash-table, if the class is not present
+ * yet. Otherwise we look it up. We cache the result in the lock object
+@@ -1135,8 +1153,7 @@ look_up_lock_class(struct lockdep_map *l
+ * (or spin_lock_init()) call - which acts as the key. For static
+ * locks we use the lock object itself as the key.
+ */
+- if (sizeof(struct lock_class_key) > sizeof(struct lock_class))
+- __error_too_big_MAX_LOCKDEP_SUBCLASSES();
++ BUILD_BUG_ON(sizeof(struct lock_class_key) > sizeof(struct lock_class));
+
+ key = lock->key->subkeys + subclass;
+
+@@ -1159,7 +1176,7 @@ look_up_lock_class(struct lockdep_map *l
+ * itself, so actual lookup of the hash should be once per lock object.
+ */
+ static inline struct lock_class *
+-register_lock_class(struct lockdep_map *lock, unsigned int subclass)
++register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
+ {
+ struct lockdep_subclass_key *key;
+ struct list_head *hash_head;
+@@ -1231,7 +1248,7 @@ register_lock_class(struct lockdep_map *
+ out_unlock_set:
+ __raw_spin_unlock(&hash_lock);
+
+- if (!subclass)
++ if (!subclass || force)
+ lock->class_cache = class;
+
+ DEBUG_LOCKS_WARN_ON(class->subclass != subclass);
+@@ -1368,6 +1385,7 @@ print_irq_inversion_bug(struct task_stru
+
+ printk("\n=========================================================\n");
+ printk( "[ INFO: possible irq lock inversion dependency detected ]\n");
++ print_kernel_version();
+ printk( "---------------------------------------------------------\n");
+ printk("%s/%d just changed the state of lock:\n",
+ curr->comm, curr->pid);
+@@ -1462,6 +1480,7 @@ print_usage_bug(struct task_struct *curr
+
+ printk("\n=================================\n");
+ printk( "[ INFO: inconsistent lock state ]\n");
++ print_kernel_version();
+ printk( "---------------------------------\n");
+
+ printk("inconsistent {%s} -> {%s} usage.\n",
+@@ -1917,7 +1936,7 @@ void trace_softirqs_off(unsigned long ip
+ * Initialize a lock instance's lock-class mapping info:
+ */
+ void lockdep_init_map(struct lockdep_map *lock, const char *name,
+- struct lock_class_key *key)
++ struct lock_class_key *key, int subclass)
+ {
+ if (unlikely(!debug_locks))
+ return;
+@@ -1937,6 +1956,8 @@ void lockdep_init_map(struct lockdep_map
+ lock->name = name;
+ lock->key = key;
+ lock->class_cache = NULL;
++ if (subclass)
++ register_lock_class(lock, subclass, 1);
+ }
+
+ EXPORT_SYMBOL_GPL(lockdep_init_map);
+@@ -1975,7 +1996,7 @@ static int __lock_acquire(struct lockdep
+ * Not cached yet or subclass?
+ */
+ if (unlikely(!class)) {
+- class = register_lock_class(lock, subclass);
++ class = register_lock_class(lock, subclass, 0);
+ if (!class)
+ return 0;
+ }
+diff --git a/kernel/module.c b/kernel/module.c
+index 2a19cd4..f016656 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -87,6 +87,12 @@ static inline int strong_try_module_get(
+ return try_module_get(mod);
+ }
+
++static inline void add_taint_module(struct module *mod, unsigned flag)
++{
++ add_taint(flag);
++ mod->taints |= flag;
++}
++
+ /* A thread that wants to hold a reference to a module only while it
+ * is running can call ths to safely exit.
+ * nfsd and lockd use this.
+@@ -847,11 +853,10 @@ static int check_version(Elf_Shdr *sechd
+ return 0;
+ }
+ /* Not in module's version table. OK, but that taints the kernel. */
+- if (!(tainted & TAINT_FORCED_MODULE)) {
++ if (!(tainted & TAINT_FORCED_MODULE))
+ printk("%s: no version for \"%s\" found: kernel tainted.\n",
+ mod->name, symname);
+- add_taint(TAINT_FORCED_MODULE);
+- }
++ add_taint_module(mod, TAINT_FORCED_MODULE);
+ return 1;
+ }
+
+@@ -909,7 +914,8 @@ static unsigned long resolve_symbol(Elf_
+ unsigned long ret;
+ const unsigned long *crc;
+
+- ret = __find_symbol(name, &owner, &crc, mod->license_gplok);
++ ret = __find_symbol(name, &owner, &crc,
++ !(mod->taints & TAINT_PROPRIETARY_MODULE));
+ if (ret) {
+ /* use_module can fail due to OOM, or module unloading */
+ if (!check_version(sechdrs, versindex, name, mod, crc) ||
+@@ -933,6 +939,15 @@ static ssize_t module_sect_show(struct m
+ return sprintf(buf, "0x%lx\n", sattr->address);
+ }
+
++static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
++{
++ int section;
++
++ for (section = 0; section < sect_attrs->nsections; section++)
++ kfree(sect_attrs->attrs[section].name);
++ kfree(sect_attrs);
++}
++
+ static void add_sect_attrs(struct module *mod, unsigned int nsect,
+ char *secstrings, Elf_Shdr *sechdrs)
+ {
+@@ -949,21 +964,26 @@ static void add_sect_attrs(struct module
+ + nloaded * sizeof(sect_attrs->attrs[0]),
+ sizeof(sect_attrs->grp.attrs[0]));
+ size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
+- if (! (sect_attrs = kmalloc(size[0] + size[1], GFP_KERNEL)))
++ sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
++ if (sect_attrs == NULL)
+ return;
+
+ /* Setup section attributes. */
+ sect_attrs->grp.name = "sections";
+ sect_attrs->grp.attrs = (void *)sect_attrs + size[0];
+
++ sect_attrs->nsections = 0;
+ sattr = §_attrs->attrs[0];
+ gattr = §_attrs->grp.attrs[0];
+ for (i = 0; i < nsect; i++) {
+ if (! (sechdrs[i].sh_flags & SHF_ALLOC))
+ continue;
+ sattr->address = sechdrs[i].sh_addr;
+- strlcpy(sattr->name, secstrings + sechdrs[i].sh_name,
+- MODULE_SECT_NAME_LEN);
++ sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
++ GFP_KERNEL);
++ if (sattr->name == NULL)
++ goto out;
++ sect_attrs->nsections++;
+ sattr->mattr.show = module_sect_show;
+ sattr->mattr.store = NULL;
+ sattr->mattr.attr.name = sattr->name;
+@@ -979,7 +999,7 @@ static void add_sect_attrs(struct module
+ mod->sect_attrs = sect_attrs;
+ return;
+ out:
+- kfree(sect_attrs);
++ free_sect_attrs(sect_attrs);
+ }
+
+ static void remove_sect_attrs(struct module *mod)
+@@ -989,13 +1009,13 @@ static void remove_sect_attrs(struct mod
+ &mod->sect_attrs->grp);
+ /* We are positive that no one is using any sect attrs
+ * at this point. Deallocate immediately. */
+- kfree(mod->sect_attrs);
++ free_sect_attrs(mod->sect_attrs);
+ mod->sect_attrs = NULL;
+ }
+ }
+
+-
+ #else
++
+ static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
+ char *sectstrings, Elf_Shdr *sechdrs)
+ {
+@@ -1054,6 +1074,12 @@ static int mod_sysfs_setup(struct module
+ {
+ int err;
+
++ if (!module_subsys.kset.subsys) {
++ printk(KERN_ERR "%s: module_subsys not initialized\n",
++ mod->name);
++ err = -EINVAL;
++ goto out;
++ }
+ memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
+ err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name);
+ if (err)
+@@ -1314,11 +1340,11 @@ static void set_license(struct module *m
+ if (!license)
+ license = "unspecified";
+
+- mod->license_gplok = license_is_gpl_compatible(license);
+- if (!mod->license_gplok && !(tainted & TAINT_PROPRIETARY_MODULE)) {
+- printk(KERN_WARNING "%s: module license '%s' taints kernel.\n",
+- mod->name, license);
+- add_taint(TAINT_PROPRIETARY_MODULE);
++ if (!license_is_gpl_compatible(license)) {
++ if (!(tainted & TAINT_PROPRIETARY_MODULE))
++ printk(KERN_WARNING "%s: module license '%s' taints "
++ "kernel.\n", mod->name, license);
++ add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
+ }
+ }
+
+@@ -1597,7 +1623,7 @@ static struct module *load_module(void _
+ modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
+ /* This is allowed: modprobe --force will invalidate it. */
+ if (!modmagic) {
+- add_taint(TAINT_FORCED_MODULE);
++ add_taint_module(mod, TAINT_FORCED_MODULE);
+ printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
+ mod->name);
+ } else if (!same_magic(modmagic, vermagic)) {
+@@ -1694,7 +1720,7 @@ static struct module *load_module(void _
+ if (strcmp(mod->name, "ndiswrapper") == 0)
+ add_taint(TAINT_PROPRIETARY_MODULE);
+ if (strcmp(mod->name, "driverloader") == 0)
+- add_taint(TAINT_PROPRIETARY_MODULE);
++ add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
+
+ /* Set up MODINFO_ATTR fields */
+ setup_modinfo(mod, sechdrs, infoindex);
+@@ -1739,7 +1765,7 @@ static struct module *load_module(void _
+ (mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
+ printk(KERN_WARNING "%s: No versions for exported symbols."
+ " Tainting kernel.\n", mod->name);
+- add_taint(TAINT_FORCED_MODULE);
++ add_taint_module(mod, TAINT_FORCED_MODULE);
+ }
+ #endif
+
+@@ -2012,7 +2038,8 @@ const char *module_address_lookup(unsign
+ list_for_each_entry(mod, &modules, list) {
+ if (within(addr, mod->module_init, mod->init_size)
+ || within(addr, mod->module_core, mod->core_size)) {
+- *modname = mod->name;
++ if (modname)
++ *modname = mod->name;
+ return get_ksymbol(mod, addr, size, offset);
+ }
+ }
+@@ -2103,9 +2130,33 @@ static void m_stop(struct seq_file *m, v
+ mutex_unlock(&module_mutex);
+ }
+
++static char *taint_flags(unsigned int taints, char *buf)
++{
++ int bx = 0;
++
++ if (taints) {
++ buf[bx++] = '(';
++ if (taints & TAINT_PROPRIETARY_MODULE)
++ buf[bx++] = 'P';
++ if (taints & TAINT_FORCED_MODULE)
++ buf[bx++] = 'F';
++ /*
++ * TAINT_FORCED_RMMOD: could be added.
++ * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
++ * apply to modules.
++ */
++ buf[bx++] = ')';
++ }
++ buf[bx] = '\0';
++
++ return buf;
++}
++
+ static int m_show(struct seq_file *m, void *p)
+ {
+ struct module *mod = list_entry(p, struct module, list);
++ char buf[8];
++
+ seq_printf(m, "%s %lu",
+ mod->name, mod->init_size + mod->core_size);
+ print_unload_info(m, mod);
+@@ -2118,6 +2169,10 @@ static int m_show(struct seq_file *m, vo
+ /* Used by oprofile and other similar tools. */
+ seq_printf(m, " 0x%p", mod->module_core);
+
++ /* Taints info */
++ if (mod->taints)
++ seq_printf(m, " %s", taint_flags(mod->taints, buf));
++
+ seq_printf(m, "\n");
+ return 0;
+ }
+@@ -2210,10 +2265,11 @@ struct module *module_text_address(unsig
+ void print_modules(void)
+ {
+ struct module *mod;
++ char buf[8];
+
+ printk("Modules linked in:");
+ list_for_each_entry(mod, &modules, list)
+- printk(" %s", mod->name);
++ printk(" %s%s", mod->name, taint_flags(mod->taints, buf));
+ printk("\n");
+ }
+
+diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c
+index e3203c6..1865164 100644
+--- a/kernel/mutex-debug.c
++++ b/kernel/mutex-debug.c
+@@ -91,7 +91,7 @@ void debug_mutex_init(struct mutex *lock
+ * Make sure we are not reinitializing a held lock:
+ */
+ debug_check_no_locks_freed((void *)lock, sizeof(*lock));
+- lockdep_init_map(&lock->dep_map, name, key);
++ lockdep_init_map(&lock->dep_map, name, key, 0);
+ #endif
+ lock->owner = NULL;
+ lock->magic = lock;
+diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
+new file mode 100644
+index 0000000..674aceb
+--- /dev/null
++++ b/kernel/nsproxy.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (C) 2006 IBM Corporation
++ *
++ * Author: Serge Hallyn <serue at 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, version 2 of the
++ * License.
++ *
++ * Jun 2006 - namespaces support
++ * OpenVZ, SWsoft Inc.
++ * Pavel Emelianov <xemul at openvz.org>
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/nsproxy.h>
++#include <linux/init_task.h>
++#include <linux/namespace.h>
++#include <linux/utsname.h>
++
++struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
++
++static inline void get_nsproxy(struct nsproxy *ns)
++{
++ atomic_inc(&ns->count);
++}
++
++void get_task_namespaces(struct task_struct *tsk)
++{
++ struct nsproxy *ns = tsk->nsproxy;
++ if (ns) {
++ get_nsproxy(ns);
++ }
++}
++
++/*
++ * creates a copy of "orig" with refcount 1.
++ * This does not grab references to the contained namespaces,
++ * so that needs to be done by dup_namespaces.
++ */
++static inline struct nsproxy *clone_namespaces(struct nsproxy *orig)
++{
++ struct nsproxy *ns;
++
++ ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL);
++ if (ns)
++ atomic_set(&ns->count, 1);
++ return ns;
++}
++
++/*
++ * copies the nsproxy, setting refcount to 1, and grabbing a
++ * reference to all contained namespaces. Called from
++ * sys_unshare()
++ */
++struct nsproxy *dup_namespaces(struct nsproxy *orig)
++{
++ struct nsproxy *ns = clone_namespaces(orig);
++
++ if (ns) {
++ if (ns->namespace)
++ get_namespace(ns->namespace);
++ if (ns->uts_ns)
++ get_uts_ns(ns->uts_ns);
++ if (ns->ipc_ns)
++ get_ipc_ns(ns->ipc_ns);
++ }
++
++ return ns;
++}
++
++/*
++ * called from clone. This now handles copy for nsproxy and all
++ * namespaces therein.
++ */
++int copy_namespaces(int flags, struct task_struct *tsk)
++{
++ struct nsproxy *old_ns = tsk->nsproxy;
++ struct nsproxy *new_ns;
++ int err = 0;
++
++ if (!old_ns)
++ return 0;
++
++ get_nsproxy(old_ns);
++
++ if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
++ return 0;
++
++ new_ns = clone_namespaces(old_ns);
++ if (!new_ns) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ tsk->nsproxy = new_ns;
++
++ err = copy_namespace(flags, tsk);
++ if (err)
++ goto out_ns;
++
++ err = copy_utsname(flags, tsk);
++ if (err)
++ goto out_uts;
++
++ err = copy_ipcs(flags, tsk);
++ if (err)
++ goto out_ipc;
++
++out:
++ put_nsproxy(old_ns);
++ return err;
++
++out_ipc:
++ if (new_ns->uts_ns)
++ put_uts_ns(new_ns->uts_ns);
++out_uts:
++ if (new_ns->namespace)
++ put_namespace(new_ns->namespace);
++out_ns:
++ tsk->nsproxy = old_ns;
++ kfree(new_ns);
++ goto out;
++}
++
++void free_nsproxy(struct nsproxy *ns)
++{
++ if (ns->namespace)
++ put_namespace(ns->namespace);
++ if (ns->uts_ns)
++ put_uts_ns(ns->uts_ns);
++ if (ns->ipc_ns)
++ put_ipc_ns(ns->ipc_ns);
++ kfree(ns);
++}
+diff --git a/kernel/panic.c b/kernel/panic.c
+index 8010b9b..525e365 100644
+--- a/kernel/panic.c
++++ b/kernel/panic.c
+@@ -270,3 +270,15 @@ void oops_exit(void)
+ {
+ do_oops_enter_exit();
+ }
++
++#ifdef CONFIG_CC_STACKPROTECTOR
++/*
++ * Called when gcc's -fstack-protector feature is used, and
++ * gcc detects corruption of the on-stack canary value
++ */
++void __stack_chk_fail(void)
++{
++ panic("stack-protector: Kernel stack is corrupted");
++}
++EXPORT_SYMBOL(__stack_chk_fail);
++#endif
+diff --git a/kernel/params.c b/kernel/params.c
+index 91aea7a..f406655 100644
+--- a/kernel/params.c
++++ b/kernel/params.c
+@@ -547,6 +547,7 @@ static void __init kernel_param_sysfs_se
+ unsigned int name_skip)
+ {
+ struct module_kobject *mk;
++ int ret;
+
+ mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
+ BUG_ON(!mk);
+@@ -554,7 +555,8 @@ static void __init kernel_param_sysfs_se
+ mk->mod = THIS_MODULE;
+ kobj_set_kset_s(mk, module_subsys);
+ kobject_set_name(&mk->kobj, name);
+- kobject_register(&mk->kobj);
++ ret = kobject_register(&mk->kobj);
++ BUG_ON(ret < 0);
+
+ /* no need to keep the kobject if no parameter is exported */
+ if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) {
+@@ -684,13 +686,20 @@ decl_subsys(module, &module_ktype, NULL)
+ */
+ static int __init param_sysfs_init(void)
+ {
+- subsystem_register(&module_subsys);
++ int ret;
++
++ ret = subsystem_register(&module_subsys);
++ if (ret < 0) {
++ printk(KERN_WARNING "%s (%d): subsystem_register error: %d\n",
++ __FILE__, __LINE__, ret);
++ return ret;
++ }
+
+ param_sysfs_builtin();
+
+ return 0;
+ }
+-__initcall(param_sysfs_init);
++subsys_initcall(param_sysfs_init);
+
+ EXPORT_SYMBOL(param_set_byte);
+ EXPORT_SYMBOL(param_get_byte);
+diff --git a/kernel/pid.c b/kernel/pid.c
+index 93e212f..b914392 100644
+--- a/kernel/pid.c
++++ b/kernel/pid.c
+@@ -26,6 +26,7 @@
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
+ #include <linux/hash.h>
++#include <linux/pspace.h>
+
+ #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
+ static struct hlist_head *pid_hash;
+@@ -33,17 +34,20 @@ static int pidhash_shift;
+ static kmem_cache_t *pid_cachep;
+
+ int pid_max = PID_MAX_DEFAULT;
+-int last_pid;
+
+ #define RESERVED_PIDS 300
+
+ int pid_max_min = RESERVED_PIDS + 1;
+ int pid_max_max = PID_MAX_LIMIT;
+
+-#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
+ #define BITS_PER_PAGE (PAGE_SIZE*8)
+ #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
+-#define mk_pid(map, off) (((map) - pidmap_array)*BITS_PER_PAGE + (off))
++
++static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off)
++{
++ return (map - pspace->pidmap)*BITS_PER_PAGE + off;
++}
++
+ #define find_next_offset(map, off) \
+ find_next_zero_bit((map)->page, BITS_PER_PAGE, off)
+
+@@ -53,13 +57,12 @@ int pid_max_max = PID_MAX_LIMIT;
+ * value does not cause lots of bitmaps to be allocated, but
+ * the scheme scales to up to 4 million PIDs, runtime.
+ */
+-typedef struct pidmap {
+- atomic_t nr_free;
+- void *page;
+-} pidmap_t;
+-
+-static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
+- { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } };
++struct pspace init_pspace = {
++ .pidmap = {
++ [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
++ },
++ .last_pid = 0
++};
+
+ /*
+ * Note: disable interrupts while the pidmap_lock is held as an
+@@ -74,40 +77,41 @@ static pidmap_t pidmap_array[PIDMAP_ENTR
+ * irq handlers that take it we can leave the interrupts enabled.
+ * For now it is easier to be safe than to prove it can't happen.
+ */
++
+ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock);
+
+-static fastcall void free_pidmap(int pid)
++static fastcall void free_pidmap(struct pspace *pspace, int pid)
+ {
+- pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE;
++ struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE;
+ int offset = pid & BITS_PER_PAGE_MASK;
+
+ clear_bit(offset, map->page);
+ atomic_inc(&map->nr_free);
+ }
+
+-static int alloc_pidmap(void)
++static int alloc_pidmap(struct pspace *pspace)
+ {
+- int i, offset, max_scan, pid, last = last_pid;
+- pidmap_t *map;
++ int i, offset, max_scan, pid, last = pspace->last_pid;
++ struct pidmap *map;
+
+ pid = last + 1;
+ if (pid >= pid_max)
+ pid = RESERVED_PIDS;
+ offset = pid & BITS_PER_PAGE_MASK;
+- map = &pidmap_array[pid/BITS_PER_PAGE];
++ map = &pspace->pidmap[pid/BITS_PER_PAGE];
+ max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset;
+ for (i = 0; i <= max_scan; ++i) {
+ if (unlikely(!map->page)) {
+- unsigned long page = get_zeroed_page(GFP_KERNEL);
++ void *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ /*
+ * Free the page if someone raced with us
+ * installing it:
+ */
+ spin_lock_irq(&pidmap_lock);
+ if (map->page)
+- free_page(page);
++ kfree(page);
+ else
+- map->page = (void *)page;
++ map->page = page;
+ spin_unlock_irq(&pidmap_lock);
+ if (unlikely(!map->page))
+ break;
+@@ -116,11 +120,11 @@ static int alloc_pidmap(void)
+ do {
+ if (!test_and_set_bit(offset, map->page)) {
+ atomic_dec(&map->nr_free);
+- last_pid = pid;
++ pspace->last_pid = pid;
+ return pid;
+ }
+ offset = find_next_offset(map, offset);
+- pid = mk_pid(map, offset);
++ pid = mk_pid(pspace, map, offset);
+ /*
+ * find_next_offset() found a bit, the pid from it
+ * is in-bounds, and if we fell back to the last
+@@ -131,16 +135,34 @@ static int alloc_pidmap(void)
+ (i != max_scan || pid < last ||
+ !((last+1) & BITS_PER_PAGE_MASK)));
+ }
+- if (map < &pidmap_array[(pid_max-1)/BITS_PER_PAGE]) {
++ if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
+ ++map;
+ offset = 0;
+ } else {
+- map = &pidmap_array[0];
++ map = &pspace->pidmap[0];
+ offset = RESERVED_PIDS;
+ if (unlikely(last == offset))
+ break;
+ }
+- pid = mk_pid(map, offset);
++ pid = mk_pid(pspace, map, offset);
++ }
++ return -1;
++}
++
++static int next_pidmap(struct pspace *pspace, int last)
++{
++ int offset;
++ struct pidmap *map, *end;
++
++ offset = (last + 1) & BITS_PER_PAGE_MASK;
++ map = &pspace->pidmap[(last + 1)/BITS_PER_PAGE];
++ end = &pspace->pidmap[PIDMAP_ENTRIES];
++ for (; map < end; map++, offset = 0) {
++ if (unlikely(!map->page))
++ continue;
++ offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
++ if (offset < BITS_PER_PAGE)
++ return mk_pid(pspace, map, offset);
+ }
+ return -1;
+ }
+@@ -153,6 +175,7 @@ fastcall void put_pid(struct pid *pid)
+ atomic_dec_and_test(&pid->count))
+ kmem_cache_free(pid_cachep, pid);
+ }
++EXPORT_SYMBOL_GPL(put_pid);
+
+ static void delayed_put_pid(struct rcu_head *rhp)
+ {
+@@ -169,7 +192,7 @@ fastcall void free_pid(struct pid *pid)
+ hlist_del_rcu(&pid->pid_chain);
+ spin_unlock_irqrestore(&pidmap_lock, flags);
+
+- free_pidmap(pid->nr);
++ free_pidmap(&init_pspace, pid->nr);
+ call_rcu(&pid->rcu, delayed_put_pid);
+ }
+
+@@ -183,7 +206,7 @@ struct pid *alloc_pid(void)
+ if (!pid)
+ goto out;
+
+- nr = alloc_pidmap();
++ nr = alloc_pidmap(&init_pspace);
+ if (nr < 0)
+ goto out_free;
+
+@@ -217,15 +240,13 @@ struct pid * fastcall find_pid(int nr)
+ }
+ return NULL;
+ }
++EXPORT_SYMBOL_GPL(find_pid);
+
+ int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr)
+ {
+ struct pid_link *link;
+ struct pid *pid;
+
+- WARN_ON(!task->pid); /* to be removed soon */
+- WARN_ON(!nr); /* to be removed soon */
+-
+ link = &task->pids[type];
+ link->pid = pid = find_pid(nr);
+ hlist_add_head_rcu(&link->node, &pid->tasks[type]);
+@@ -252,6 +273,15 @@ void fastcall detach_pid(struct task_str
+ free_pid(pid);
+ }
+
++/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
++void fastcall transfer_pid(struct task_struct *old, struct task_struct *new,
++ enum pid_type type)
++{
++ new->pids[type].pid = old->pids[type].pid;
++ hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node);
++ old->pids[type].pid = NULL;
++}
++
+ struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type)
+ {
+ struct task_struct *result = NULL;
+@@ -274,6 +304,15 @@ struct task_struct *find_task_by_pid_typ
+
+ EXPORT_SYMBOL(find_task_by_pid_type);
+
++struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
++{
++ struct pid *pid;
++ rcu_read_lock();
++ pid = get_pid(task->pids[type].pid);
++ rcu_read_unlock();
++ return pid;
++}
++
+ struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type)
+ {
+ struct task_struct *result;
+@@ -297,6 +336,26 @@ struct pid *find_get_pid(pid_t nr)
+ }
+
+ /*
++ * Used by proc to find the first pid that is greater then or equal to nr.
++ *
++ * If there is a pid at nr this function is exactly the same as find_pid.
++ */
++struct pid *find_ge_pid(int nr)
++{
++ struct pid *pid;
++
++ do {
++ pid = find_pid(nr);
++ if (pid)
++ break;
++ nr = next_pidmap(&init_pspace, nr);
++ } while (nr > 0);
++
++ return pid;
++}
++EXPORT_SYMBOL_GPL(find_get_pid);
++
++/*
+ * The pid hash table is scaled according to the amount of memory in the
+ * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or
+ * more.
+@@ -323,10 +382,10 @@ void __init pidhash_init(void)
+
+ void __init pidmap_init(void)
+ {
+- pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL);
++ init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ /* Reserve PID 0. We never call free_pidmap(0) */
+- set_bit(0, pidmap_array->page);
+- atomic_dec(&pidmap_array->nr_free);
++ set_bit(0, init_pspace.pidmap[0].page);
++ atomic_dec(&init_pspace.pidmap[0].nr_free);
+
+ pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
+ __alignof__(struct pid),
+diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
+index d38d9ec..7c3e1e6 100644
+--- a/kernel/posix-cpu-timers.c
++++ b/kernel/posix-cpu-timers.c
+@@ -88,6 +88,19 @@ static inline union cpu_time_count cpu_t
+ }
+
+ /*
++ * Divide and limit the result to res >= 1
++ *
++ * This is necessary to prevent signal delivery starvation, when the result of
++ * the division would be rounded down to 0.
++ */
++static inline cputime_t cputime_div_non_zero(cputime_t time, unsigned long div)
++{
++ cputime_t res = cputime_div(time, div);
++
++ return max_t(cputime_t, res, 1);
++}
++
++/*
+ * Update expiry time from increment, and increase overrun count,
+ * given the current clock sample.
+ */
+@@ -483,8 +496,8 @@ static void process_timer_rebalance(stru
+ BUG();
+ break;
+ case CPUCLOCK_PROF:
+- left = cputime_div(cputime_sub(expires.cpu, val.cpu),
+- nthreads);
++ left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu),
++ nthreads);
+ do {
+ if (likely(!(t->flags & PF_EXITING))) {
+ ticks = cputime_add(prof_ticks(t), left);
+@@ -498,8 +511,8 @@ static void process_timer_rebalance(stru
+ } while (t != p);
+ break;
+ case CPUCLOCK_VIRT:
+- left = cputime_div(cputime_sub(expires.cpu, val.cpu),
+- nthreads);
++ left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu),
++ nthreads);
+ do {
+ if (likely(!(t->flags & PF_EXITING))) {
+ ticks = cputime_add(virt_ticks(t), left);
+@@ -515,6 +528,7 @@ static void process_timer_rebalance(stru
+ case CPUCLOCK_SCHED:
+ nsleft = expires.sched - val.sched;
+ do_div(nsleft, nthreads);
++ nsleft = max_t(unsigned long long, nsleft, 1);
+ do {
+ if (likely(!(t->flags & PF_EXITING))) {
+ ns = t->sched_time + nsleft;
+@@ -1159,12 +1173,13 @@ static void check_process_timers(struct
+
+ prof_left = cputime_sub(prof_expires, utime);
+ prof_left = cputime_sub(prof_left, stime);
+- prof_left = cputime_div(prof_left, nthreads);
++ prof_left = cputime_div_non_zero(prof_left, nthreads);
+ virt_left = cputime_sub(virt_expires, utime);
+- virt_left = cputime_div(virt_left, nthreads);
++ virt_left = cputime_div_non_zero(virt_left, nthreads);
+ if (sched_expires) {
+ sched_left = sched_expires - sched_time;
+ do_div(sched_left, nthreads);
++ sched_left = max_t(unsigned long long, sched_left, 1);
+ } else {
+ sched_left = 0;
+ }
+@@ -1393,25 +1408,13 @@ void set_process_cpu_timer(struct task_s
+ }
+ }
+
+-static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
+-
+-int posix_cpu_nsleep(const clockid_t which_clock, int flags,
+- struct timespec *rqtp, struct timespec __user *rmtp)
++static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
++ struct timespec *rqtp, struct itimerspec *it)
+ {
+- struct restart_block *restart_block =
+- ¤t_thread_info()->restart_block;
+ struct k_itimer timer;
+ int error;
+
+ /*
+- * Diagnose required errors first.
+- */
+- if (CPUCLOCK_PERTHREAD(which_clock) &&
+- (CPUCLOCK_PID(which_clock) == 0 ||
+- CPUCLOCK_PID(which_clock) == current->pid))
+- return -EINVAL;
+-
+- /*
+ * Set up a temporary timer and then wait for it to go off.
+ */
+ memset(&timer, 0, sizeof timer);
+@@ -1422,11 +1425,12 @@ int posix_cpu_nsleep(const clockid_t whi
+ timer.it_process = current;
+ if (!error) {
+ static struct itimerspec zero_it;
+- struct itimerspec it = { .it_value = *rqtp,
+- .it_interval = {} };
++
++ memset(it, 0, sizeof *it);
++ it->it_value = *rqtp;
+
+ spin_lock_irq(&timer.it_lock);
+- error = posix_cpu_timer_set(&timer, flags, &it, NULL);
++ error = posix_cpu_timer_set(&timer, flags, it, NULL);
+ if (error) {
+ spin_unlock_irq(&timer.it_lock);
+ return error;
+@@ -1454,49 +1458,89 @@ int posix_cpu_nsleep(const clockid_t whi
+ * We were interrupted by a signal.
+ */
+ sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
+- posix_cpu_timer_set(&timer, 0, &zero_it, &it);
++ posix_cpu_timer_set(&timer, 0, &zero_it, it);
+ spin_unlock_irq(&timer.it_lock);
+
+- if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
++ if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) {
+ /*
+ * It actually did fire already.
+ */
+ return 0;
+ }
+
++ error = -ERESTART_RESTARTBLOCK;
++ }
++
++ return error;
++}
++
++int posix_cpu_nsleep(const clockid_t which_clock, int flags,
++ struct timespec *rqtp, struct timespec __user *rmtp)
++{
++ struct restart_block *restart_block =
++ ¤t_thread_info()->restart_block;
++ struct itimerspec it;
++ int error;
++
++ /*
++ * Diagnose required errors first.
++ */
++ if (CPUCLOCK_PERTHREAD(which_clock) &&
++ (CPUCLOCK_PID(which_clock) == 0 ||
++ CPUCLOCK_PID(which_clock) == current->pid))
++ return -EINVAL;
++
++ error = do_cpu_nanosleep(which_clock, flags, rqtp, &it);
++
++ if (error == -ERESTART_RESTARTBLOCK) {
++
++ if (flags & TIMER_ABSTIME)
++ return -ERESTARTNOHAND;
+ /*
+- * Report back to the user the time still remaining.
+- */
+- if (rmtp != NULL && !(flags & TIMER_ABSTIME) &&
+- copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
++ * Report back to the user the time still remaining.
++ */
++ if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+ return -EFAULT;
+
+- restart_block->fn = posix_cpu_clock_nanosleep_restart;
+- /* Caller already set restart_block->arg1 */
++ restart_block->fn = posix_cpu_nsleep_restart;
+ restart_block->arg0 = which_clock;
+ restart_block->arg1 = (unsigned long) rmtp;
+ restart_block->arg2 = rqtp->tv_sec;
+ restart_block->arg3 = rqtp->tv_nsec;
+-
+- error = -ERESTART_RESTARTBLOCK;
+ }
+-
+ return error;
+ }
+
+-static long
+-posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
++long posix_cpu_nsleep_restart(struct restart_block *restart_block)
+ {
+ clockid_t which_clock = restart_block->arg0;
+ struct timespec __user *rmtp;
+ struct timespec t;
++ struct itimerspec it;
++ int error;
+
+ rmtp = (struct timespec __user *) restart_block->arg1;
+ t.tv_sec = restart_block->arg2;
+ t.tv_nsec = restart_block->arg3;
+
+ restart_block->fn = do_no_restart_syscall;
+- return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t, rmtp);
++ error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it);
++
++ if (error == -ERESTART_RESTARTBLOCK) {
++ /*
++ * Report back to the user the time still remaining.
++ */
++ if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
++ return -EFAULT;
++
++ restart_block->fn = posix_cpu_nsleep_restart;
++ restart_block->arg0 = which_clock;
++ restart_block->arg1 = (unsigned long) rmtp;
++ restart_block->arg2 = t.tv_sec;
++ restart_block->arg3 = t.tv_nsec;
++ }
++ return error;
++
+ }
+
+
+@@ -1524,6 +1568,10 @@ static int process_cpu_nsleep(const cloc
+ {
+ return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp);
+ }
++static long process_cpu_nsleep_restart(struct restart_block *restart_block)
++{
++ return -EINVAL;
++}
+ static int thread_cpu_clock_getres(const clockid_t which_clock,
+ struct timespec *tp)
+ {
+@@ -1544,6 +1592,10 @@ static int thread_cpu_nsleep(const clock
+ {
+ return -EINVAL;
+ }
++static long thread_cpu_nsleep_restart(struct restart_block *restart_block)
++{
++ return -EINVAL;
++}
+
+ static __init int init_posix_cpu_timers(void)
+ {
+@@ -1553,6 +1605,7 @@ static __init int init_posix_cpu_timers(
+ .clock_set = do_posix_clock_nosettime,
+ .timer_create = process_cpu_timer_create,
+ .nsleep = process_cpu_nsleep,
++ .nsleep_restart = process_cpu_nsleep_restart,
+ };
+ struct k_clock thread = {
+ .clock_getres = thread_cpu_clock_getres,
+@@ -1560,6 +1613,7 @@ static __init int init_posix_cpu_timers(
+ .clock_set = do_posix_clock_nosettime,
+ .timer_create = thread_cpu_timer_create,
+ .nsleep = thread_cpu_nsleep,
++ .nsleep_restart = thread_cpu_nsleep_restart,
+ };
+
+ register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
+diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
+index ac6dc87..9cbb5d1 100644
+--- a/kernel/posix-timers.c
++++ b/kernel/posix-timers.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/kernel/posix_timers.c
++ * linux/kernel/posix-timers.c
+ *
+ *
+ * 2002-10-15 Posix Clocks & timers
+@@ -973,3 +973,24 @@ sys_clock_nanosleep(const clockid_t whic
+ return CLOCK_DISPATCH(which_clock, nsleep,
+ (which_clock, flags, &t, rmtp));
+ }
++
++/*
++ * nanosleep_restart for monotonic and realtime clocks
++ */
++static int common_nsleep_restart(struct restart_block *restart_block)
++{
++ return hrtimer_nanosleep_restart(restart_block);
++}
++
++/*
++ * This will restart clock_nanosleep. This is required only by
++ * compat_clock_nanosleep_restart for now.
++ */
++long
++clock_nanosleep_restart(struct restart_block *restart_block)
++{
++ clockid_t which_clock = restart_block->arg0;
++
++ return CLOCK_DISPATCH(which_clock, nsleep_restart,
++ (restart_block));
++}
+diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
+index 619ecab..825068c 100644
+--- a/kernel/power/Kconfig
++++ b/kernel/power/Kconfig
+@@ -36,6 +36,17 @@ config PM_DEBUG
+ code. This is helpful when debugging and reporting various PM bugs,
+ like suspend support.
+
++config DISABLE_CONSOLE_SUSPEND
++ bool "Keep console(s) enabled during suspend/resume (DANGEROUS)"
++ depends on PM && PM_DEBUG
++ default n
++ ---help---
++ This option turns off the console suspend mechanism that prevents
++ debug messages from reaching the console during the suspend/resume
++ operations. This may be helpful when debugging device drivers'
++ suspend/resume routines, but may itself lead to problems, for example
++ if netconsole is used.
++
+ config PM_TRACE
+ bool "Suspend/resume event tracing"
+ depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
+@@ -53,6 +64,17 @@ config PM_TRACE
+ CAUTION: this option will cause your machine's real-time clock to be
+ set to an invalid time after a resume.
+
++config PM_SYSFS_DEPRECATED
++ bool "Driver model /sys/devices/.../power/state files (DEPRECATED)"
++ depends on PM && SYSFS
++ default n
++ help
++ The driver model started out with a sysfs file intended to provide
++ a userspace hook for device power management. This feature has never
++ worked very well, except for limited testing purposes, and so it will
++ be removed. It's not clear that a generic mechanism could really
++ handle the wide variability of device power states; any replacements
++ are likely to be bus or driver specific.
+
+ config SOFTWARE_SUSPEND
+ bool "Software Suspend"
+diff --git a/kernel/power/Makefile b/kernel/power/Makefile
+index 8d0af3d..38725f5 100644
+--- a/kernel/power/Makefile
++++ b/kernel/power/Makefile
+@@ -7,6 +7,4 @@ obj-y := main.o process.o console.o
+ obj-$(CONFIG_PM_LEGACY) += pm.o
+ obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o snapshot.o swap.o user.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 e13e740..b1fb786 100644
+--- a/kernel/power/disk.c
++++ b/kernel/power/disk.c
+@@ -18,6 +18,8 @@
+ #include <linux/fs.h>
+ #include <linux/mount.h>
+ #include <linux/pm.h>
++#include <linux/console.h>
++#include <linux/cpu.h>
+
+ #include "power.h"
+
+@@ -69,21 +71,31 @@ static inline void platform_finish(void)
+
+ static int prepare_processes(void)
+ {
+- int error;
++ int error = 0;
+
+ pm_prepare_console();
+- disable_nonboot_cpus();
++
++ error = disable_nonboot_cpus();
++ if (error)
++ goto enable_cpus;
+
+ if (freeze_processes()) {
+ error = -EBUSY;
+ goto thaw;
+ }
+
++ if (pm_disk_mode == PM_DISK_TESTPROC) {
++ printk("swsusp debug: Waiting for 5 seconds.\n");
++ mdelay(5000);
++ goto thaw;
++ }
++
+ /* Free memory before shutting down devices. */
+ if (!(error = swsusp_shrink_memory()))
+ return 0;
+ thaw:
+ thaw_processes();
++enable_cpus:
+ enable_nonboot_cpus();
+ pm_restore_console();
+ return error;
+@@ -98,7 +110,7 @@ static void unprepare_processes(void)
+ }
+
+ /**
+- * pm_suspend_disk - The granpappy of power management.
++ * pm_suspend_disk - The granpappy of hibernation power management.
+ *
+ * If we're going through the firmware, then get it over with quickly.
+ *
+@@ -114,11 +126,21 @@ int pm_suspend_disk(void)
+ if (error)
+ return error;
+
++ if (pm_disk_mode == PM_DISK_TESTPROC)
++ goto Thaw;
++
++ suspend_console();
+ error = device_suspend(PMSG_FREEZE);
+ if (error) {
++ resume_console();
+ printk("Some devices failed to suspend\n");
+- unprepare_processes();
+- return error;
++ goto Thaw;
++ }
++
++ if (pm_disk_mode == PM_DISK_TEST) {
++ printk("swsusp debug: Waiting for 5 seconds.\n");
++ mdelay(5000);
++ goto Done;
+ }
+
+ pr_debug("PM: snapshotting memory.\n");
+@@ -128,21 +150,24 @@ int pm_suspend_disk(void)
+
+ if (in_suspend) {
+ device_resume();
++ resume_console();
+ pr_debug("PM: writing image.\n");
+ error = swsusp_write();
+ if (!error)
+ power_down(pm_disk_mode);
+ else {
+ swsusp_free();
+- unprepare_processes();
+- return error;
++ goto Thaw;
+ }
+- } else
++ } else {
+ pr_debug("PM: Image restored successfully.\n");
++ }
+
+ swsusp_free();
+ Done:
+ device_resume();
++ resume_console();
++ Thaw:
+ unprepare_processes();
+ return error;
+ }
+@@ -207,7 +232,9 @@ static int software_resume(void)
+
+ pr_debug("PM: Preparing devices for restore.\n");
+
+- if ((error = device_suspend(PMSG_FREEZE))) {
++ suspend_console();
++ if ((error = device_suspend(PMSG_PRETHAW))) {
++ resume_console();
+ printk("Some devices failed to suspend\n");
+ swsusp_free();
+ goto Thaw;
+@@ -219,6 +246,7 @@ static int software_resume(void)
+ swsusp_resume();
+ pr_debug("PM: Restore failed, recovering.n");
+ device_resume();
++ resume_console();
+ Thaw:
+ unprepare_processes();
+ Done:
+@@ -236,6 +264,8 @@ static const char * const pm_disk_modes[
+ [PM_DISK_PLATFORM] = "platform",
+ [PM_DISK_SHUTDOWN] = "shutdown",
+ [PM_DISK_REBOOT] = "reboot",
++ [PM_DISK_TEST] = "test",
++ [PM_DISK_TESTPROC] = "testproc",
+ };
+
+ /**
+@@ -290,17 +320,19 @@ static ssize_t disk_store(struct subsyst
+ }
+ }
+ if (mode) {
+- if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT)
++ if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
++ mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
+ pm_disk_mode = mode;
+- else {
++ } else {
+ if (pm_ops && pm_ops->enter &&
+ (mode == pm_ops->pm_disk_mode))
+ pm_disk_mode = mode;
+ else
+ error = -EINVAL;
+ }
+- } else
++ } else {
+ error = -EINVAL;
++ }
+
+ pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+ pm_disk_modes[mode]);
+diff --git a/kernel/power/main.c b/kernel/power/main.c
+index 6d295c7..873228c 100644
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -16,6 +16,8 @@
+ #include <linux/init.h>
+ #include <linux/pm.h>
+ #include <linux/console.h>
++#include <linux/cpu.h>
++#include <linux/resume-trace.h>
+
+ #include "power.h"
+
+@@ -51,7 +53,7 @@ void pm_set_ops(struct pm_ops * ops)
+
+ static int suspend_prepare(suspend_state_t state)
+ {
+- int error = 0;
++ int error;
+ unsigned int free_pages;
+
+ if (!pm_ops || !pm_ops->enter)
+@@ -59,12 +61,9 @@ static int suspend_prepare(suspend_state
+
+ pm_prepare_console();
+
+- disable_nonboot_cpus();
+-
+- if (num_online_cpus() != 1) {
+- error = -EPERM;
++ error = disable_nonboot_cpus();
++ if (error)
+ goto Enable_cpu;
+- }
+
+ if (freeze_processes()) {
+ error = -EAGAIN;
+@@ -283,10 +282,39 @@ static ssize_t state_store(struct subsys
+
+ power_attr(state);
+
++#ifdef CONFIG_PM_TRACE
++int pm_trace_enabled;
++
++static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
++{
++ return sprintf(buf, "%d\n", pm_trace_enabled);
++}
++
++static ssize_t
++pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
++{
++ int val;
++
++ if (sscanf(buf, "%d", &val) == 1) {
++ pm_trace_enabled = !!val;
++ return n;
++ }
++ return -EINVAL;
++}
++
++power_attr(pm_trace);
++
++static struct attribute * g[] = {
++ &state_attr.attr,
++ &pm_trace_attr.attr,
++ NULL,
++};
++#else
+ static struct attribute * g[] = {
+ &state_attr.attr,
+ NULL,
+ };
++#endif /* CONFIG_PM_TRACE */
+
+ static struct attribute_group attr_group = {
+ .attrs = g,
+diff --git a/kernel/power/power.h b/kernel/power/power.h
+index 57a7929..bfe999f 100644
+--- a/kernel/power/power.h
++++ b/kernel/power/power.h
+@@ -38,8 +38,6 @@ extern struct subsystem power_subsys;
+ /* References to section boundaries */
+ extern const void __nosave_begin, __nosave_end;
+
+-extern struct pbe *pagedir_nosave;
+-
+ /* Preferred image size in bytes (default 500 MB) */
+ extern unsigned long image_size;
+ extern int in_suspend;
+@@ -50,21 +48,62 @@ extern asmlinkage int swsusp_arch_resume
+
+ extern unsigned int count_data_pages(void);
+
++/**
++ * Auxiliary structure used for reading the snapshot image data and
++ * metadata from and writing them to the list of page backup entries
++ * (PBEs) which is the main data structure of swsusp.
++ *
++ * Using struct snapshot_handle we can transfer the image, including its
++ * metadata, as a continuous sequence of bytes with the help of
++ * snapshot_read_next() and snapshot_write_next().
++ *
++ * The code that writes the image to a storage or transfers it to
++ * the user land is required to use snapshot_read_next() for this
++ * purpose and it should not make any assumptions regarding the internal
++ * structure of the image. Similarly, the code that reads the image from
++ * a storage or transfers it from the user land is required to use
++ * snapshot_write_next().
++ *
++ * This may allow us to change the internal structure of the image
++ * in the future with considerably less effort.
++ */
++
+ struct snapshot_handle {
+- loff_t offset;
+- unsigned int page;
+- unsigned int page_offset;
+- unsigned int prev;
+- struct pbe *pbe, *last_pbe;
+- void *buffer;
+- unsigned int buf_offset;
++ loff_t offset; /* number of the last byte ready for reading
++ * or writing in the sequence
++ */
++ unsigned int cur; /* number of the block of PAGE_SIZE bytes the
++ * next operation will refer to (ie. current)
++ */
++ unsigned int cur_offset; /* offset with respect to the current
++ * block (for the next operation)
++ */
++ unsigned int prev; /* number of the block of PAGE_SIZE bytes that
++ * was the current one previously
++ */
++ void *buffer; /* address of the block to read from
++ * or write to
++ */
++ unsigned int buf_offset; /* location to read from or write to,
++ * given as a displacement from 'buffer'
++ */
++ int sync_read; /* Set to one to notify the caller of
++ * snapshot_write_next() that it may
++ * need to call wait_on_bio_chain()
++ */
+ };
+
++/* This macro returns the address from/to which the caller of
++ * snapshot_read_next()/snapshot_write_next() is allowed to
++ * read/write data after the function returns
++ */
+ #define data_of(handle) ((handle).buffer + (handle).buf_offset)
+
++extern unsigned int snapshot_additional_pages(struct zone *zone);
+ extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
+ extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
+-int snapshot_image_loaded(struct snapshot_handle *handle);
++extern int snapshot_image_loaded(struct snapshot_handle *handle);
++extern void snapshot_free_unused_memory(struct snapshot_handle *handle);
+
+ #define SNAPSHOT_IOC_MAGIC '3'
+ #define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
+diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c
+index 7a4144b..f1f900a 100644
+--- a/kernel/power/poweroff.c
++++ b/kernel/power/poweroff.c
+@@ -23,8 +23,7 @@ static void do_poweroff(void *dummy)
+
+ static DECLARE_WORK(poweroff_work, do_poweroff, NULL);
+
+-static void handle_poweroff(int key, struct pt_regs *pt_regs,
+- struct tty_struct *tty)
++static void handle_poweroff(int key, struct tty_struct *tty)
+ {
+ schedule_work(&poweroff_work);
+ }
+diff --git a/kernel/power/smp.c b/kernel/power/smp.c
+deleted file mode 100644
+index 5957312..0000000
+--- a/kernel/power/smp.c
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*
+- * drivers/power/smp.c - Functions for stopping other CPUs.
+- *
+- * Copyright 2004 Pavel Machek <pavel at suse.cz>
+- * Copyright (C) 2002-2003 Nigel Cunningham <ncunningham at clear.net.nz>
+- *
+- * This file is released under the GPLv2.
+- */
+-
+-#undef DEBUG
+-
+-#include <linux/smp_lock.h>
+-#include <linux/interrupt.h>
+-#include <linux/suspend.h>
+-#include <linux/module.h>
+-#include <linux/cpu.h>
+-#include <asm/atomic.h>
+-#include <asm/tlbflush.h>
+-
+-/* This is protected by pm_sem semaphore */
+-static cpumask_t frozen_cpus;
+-
+-void disable_nonboot_cpus(void)
+-{
+- int cpu, error;
+-
+- 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);
+- }
+- BUG_ON(raw_smp_processor_id() != 0);
+- if (error)
+- panic("cpus not sleeping");
+-}
+-
+-void enable_nonboot_cpus(void)
+-{
+- int cpu, error;
+-
+- printk("Thawing cpus ...\n");
+- for_each_cpu_mask(cpu, frozen_cpus) {
+- 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/snapshot.c b/kernel/power/snapshot.c
+index 75d4886..99f9b7d 100644
+--- a/kernel/power/snapshot.c
++++ b/kernel/power/snapshot.c
+@@ -34,10 +34,12 @@
+
+ #include "power.h"
+
+-struct pbe *pagedir_nosave;
++/* List of PBEs used for creating and restoring the suspend image */
++struct pbe *restore_pblist;
++
+ static unsigned int nr_copy_pages;
+ static unsigned int nr_meta_pages;
+-static unsigned long *buffer;
++static void *buffer;
+
+ #ifdef CONFIG_HIGHMEM
+ unsigned int count_highmem_pages(void)
+@@ -156,240 +158,637 @@ static inline int save_highmem(void) {re
+ static inline int restore_highmem(void) {return 0;}
+ #endif
+
+-static int pfn_is_nosave(unsigned long pfn)
++/**
++ * @safe_needed - on resume, for storing the PBE list and the image,
++ * we can only use memory pages that do not conflict with the pages
++ * used before suspend.
++ *
++ * The unsafe pages are marked with the PG_nosave_free flag
++ * and we count them using unsafe_pages
++ */
++
++#define PG_ANY 0
++#define PG_SAFE 1
++#define PG_UNSAFE_CLEAR 1
++#define PG_UNSAFE_KEEP 0
++
++static unsigned int allocated_unsafe_pages;
++
++static void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
+ {
+- unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+- unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
+- return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
++ void *res;
++
++ res = (void *)get_zeroed_page(gfp_mask);
++ if (safe_needed)
++ while (res && PageNosaveFree(virt_to_page(res))) {
++ /* The page is unsafe, mark it for swsusp_free() */
++ SetPageNosave(virt_to_page(res));
++ allocated_unsafe_pages++;
++ res = (void *)get_zeroed_page(gfp_mask);
++ }
++ if (res) {
++ SetPageNosave(virt_to_page(res));
++ SetPageNosaveFree(virt_to_page(res));
++ }
++ return res;
++}
++
++unsigned long get_safe_page(gfp_t gfp_mask)
++{
++ return (unsigned long)alloc_image_page(gfp_mask, PG_SAFE);
+ }
+
+ /**
+- * saveable - Determine whether a page should be cloned or not.
+- * @pfn: The page
+- *
+- * We save a page if it's Reserved, and not in the range of pages
+- * statically defined as 'unsaveable', or if it isn't reserved, and
+- * isn't part of a free chunk of pages.
++ * free_image_page - free page represented by @addr, allocated with
++ * alloc_image_page (page flags set by it must be cleared)
+ */
+
+-static int saveable(struct zone *zone, unsigned long *zone_pfn)
++static inline void free_image_page(void *addr, int clear_nosave_free)
+ {
+- unsigned long pfn = *zone_pfn + zone->zone_start_pfn;
+- struct page *page;
++ ClearPageNosave(virt_to_page(addr));
++ if (clear_nosave_free)
++ ClearPageNosaveFree(virt_to_page(addr));
++ free_page((unsigned long)addr);
++}
+
+- if (!pfn_valid(pfn))
+- return 0;
++/* struct linked_page is used to build chains of pages */
+
+- page = pfn_to_page(pfn);
+- BUG_ON(PageReserved(page) && PageNosave(page));
+- if (PageNosave(page))
+- return 0;
+- if (PageReserved(page) && pfn_is_nosave(pfn))
+- return 0;
+- if (PageNosaveFree(page))
+- return 0;
++#define LINKED_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(void *))
+
+- return 1;
+-}
++struct linked_page {
++ struct linked_page *next;
++ char data[LINKED_PAGE_DATA_SIZE];
++} __attribute__((packed));
+
+-unsigned int count_data_pages(void)
++static inline void
++free_list_of_pages(struct linked_page *list, int clear_page_nosave)
+ {
+- struct zone *zone;
+- unsigned long zone_pfn;
+- unsigned int n = 0;
++ while (list) {
++ struct linked_page *lp = list->next;
+
+- for_each_zone (zone) {
+- if (is_highmem(zone))
+- continue;
+- mark_free_pages(zone);
+- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+- n += saveable(zone, &zone_pfn);
++ free_image_page(list, clear_page_nosave);
++ list = lp;
+ }
+- return n;
+ }
+
+-static void copy_data_pages(struct pbe *pblist)
++/**
++ * struct chain_allocator is used for allocating small objects out of
++ * a linked list of pages called 'the chain'.
++ *
++ * The chain grows each time when there is no room for a new object in
++ * the current page. The allocated objects cannot be freed individually.
++ * It is only possible to free them all at once, by freeing the entire
++ * chain.
++ *
++ * NOTE: The chain allocator may be inefficient if the allocated objects
++ * are not much smaller than PAGE_SIZE.
++ */
++
++struct chain_allocator {
++ struct linked_page *chain; /* the chain */
++ unsigned int used_space; /* total size of objects allocated out
++ * of the current page
++ */
++ gfp_t gfp_mask; /* mask for allocating pages */
++ int safe_needed; /* if set, only "safe" pages are allocated */
++};
++
++static void
++chain_init(struct chain_allocator *ca, gfp_t gfp_mask, int safe_needed)
+ {
+- struct zone *zone;
+- unsigned long zone_pfn;
+- struct pbe *pbe, *p;
++ ca->chain = NULL;
++ ca->used_space = LINKED_PAGE_DATA_SIZE;
++ ca->gfp_mask = gfp_mask;
++ ca->safe_needed = safe_needed;
++}
+
+- pbe = pblist;
+- for_each_zone (zone) {
+- if (is_highmem(zone))
+- continue;
+- mark_free_pages(zone);
+- /* This is necessary for swsusp_free() */
+- for_each_pb_page (p, pblist)
+- SetPageNosaveFree(virt_to_page(p));
+- for_each_pbe (p, pblist)
+- SetPageNosaveFree(virt_to_page(p->address));
+- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
+- if (saveable(zone, &zone_pfn)) {
+- struct page *page;
+- long *src, *dst;
+- int n;
+-
+- page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
+- BUG_ON(!pbe);
+- pbe->orig_address = (unsigned long)page_address(page);
+- /* copy_page and memcpy are not usable for copying task structs. */
+- dst = (long *)pbe->address;
+- src = (long *)pbe->orig_address;
+- for (n = PAGE_SIZE / sizeof(long); n; n--)
+- *dst++ = *src++;
+- pbe = pbe->next;
+- }
+- }
++static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
++{
++ void *ret;
++
++ if (LINKED_PAGE_DATA_SIZE - ca->used_space < size) {
++ struct linked_page *lp;
++
++ lp = alloc_image_page(ca->gfp_mask, ca->safe_needed);
++ if (!lp)
++ return NULL;
++
++ lp->next = ca->chain;
++ ca->chain = lp;
++ ca->used_space = 0;
+ }
+- BUG_ON(pbe);
++ ret = ca->chain->data + ca->used_space;
++ ca->used_space += size;
++ return ret;
+ }
+
++static void chain_free(struct chain_allocator *ca, int clear_page_nosave)
++{
++ free_list_of_pages(ca->chain, clear_page_nosave);
++ memset(ca, 0, sizeof(struct chain_allocator));
++}
+
+ /**
+- * free_pagedir - free pages allocated with alloc_pagedir()
++ * Data types related to memory bitmaps.
++ *
++ * Memory bitmap is a structure consiting of many linked lists of
++ * objects. The main list's elements are of type struct zone_bitmap
++ * and each of them corresonds to one zone. For each zone bitmap
++ * object there is a list of objects of type struct bm_block that
++ * represent each blocks of bit chunks in which information is
++ * stored.
++ *
++ * struct memory_bitmap contains a pointer to the main list of zone
++ * bitmap objects, a struct bm_position used for browsing the bitmap,
++ * and a pointer to the list of pages used for allocating all of the
++ * zone bitmap objects and bitmap block objects.
++ *
++ * NOTE: It has to be possible to lay out the bitmap in memory
++ * using only allocations of order 0. Additionally, the bitmap is
++ * designed to work with arbitrary number of zones (this is over the
++ * top for now, but let's avoid making unnecessary assumptions ;-).
++ *
++ * struct zone_bitmap contains a pointer to a list of bitmap block
++ * objects and a pointer to the bitmap block object that has been
++ * most recently used for setting bits. Additionally, it contains the
++ * pfns that correspond to the start and end of the represented zone.
++ *
++ * struct bm_block contains a pointer to the memory page in which
++ * information is stored (in the form of a block of bit chunks
++ * of type unsigned long each). It also contains the pfns that
++ * correspond to the start and end of the represented memory area and
++ * the number of bit chunks in the block.
++ *
++ * NOTE: Memory bitmaps are used for two types of operations only:
++ * "set a bit" and "find the next bit set". Moreover, the searching
++ * is always carried out after all of the "set a bit" operations
++ * on given bitmap.
+ */
+
+-static void free_pagedir(struct pbe *pblist, int clear_nosave_free)
++#define BM_END_OF_MAP (~0UL)
++
++#define BM_CHUNKS_PER_BLOCK (PAGE_SIZE / sizeof(long))
++#define BM_BITS_PER_CHUNK (sizeof(long) << 3)
++#define BM_BITS_PER_BLOCK (PAGE_SIZE << 3)
++
++struct bm_block {
++ struct bm_block *next; /* next element of the list */
++ unsigned long start_pfn; /* pfn represented by the first bit */
++ unsigned long end_pfn; /* pfn represented by the last bit plus 1 */
++ unsigned int size; /* number of bit chunks */
++ unsigned long *data; /* chunks of bits representing pages */
++};
++
++struct zone_bitmap {
++ struct zone_bitmap *next; /* next element of the list */
++ unsigned long start_pfn; /* minimal pfn in this zone */
++ unsigned long end_pfn; /* maximal pfn in this zone plus 1 */
++ struct bm_block *bm_blocks; /* list of bitmap blocks */
++ struct bm_block *cur_block; /* recently used bitmap block */
++};
++
++/* strcut bm_position is used for browsing memory bitmaps */
++
++struct bm_position {
++ struct zone_bitmap *zone_bm;
++ struct bm_block *block;
++ int chunk;
++ int bit;
++};
++
++struct memory_bitmap {
++ struct zone_bitmap *zone_bm_list; /* list of zone bitmaps */
++ struct linked_page *p_list; /* list of pages used to store zone
++ * bitmap objects and bitmap block
++ * objects
++ */
++ struct bm_position cur; /* most recently used bit position */
++};
++
++/* Functions that operate on memory bitmaps */
++
++static inline void memory_bm_reset_chunk(struct memory_bitmap *bm)
+ {
+- struct pbe *pbe;
++ bm->cur.chunk = 0;
++ bm->cur.bit = -1;
++}
+
+- while (pblist) {
+- pbe = (pblist + PB_PAGE_SKIP)->next;
+- ClearPageNosave(virt_to_page(pblist));
+- if (clear_nosave_free)
+- ClearPageNosaveFree(virt_to_page(pblist));
+- free_page((unsigned long)pblist);
+- pblist = pbe;
+- }
++static void memory_bm_position_reset(struct memory_bitmap *bm)
++{
++ struct zone_bitmap *zone_bm;
++
++ zone_bm = bm->zone_bm_list;
++ bm->cur.zone_bm = zone_bm;
++ bm->cur.block = zone_bm->bm_blocks;
++ memory_bm_reset_chunk(bm);
+ }
+
++static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free);
++
+ /**
+- * fill_pb_page - Create a list of PBEs on a given memory page
++ * create_bm_block_list - create a list of block bitmap objects
+ */
+
+-static inline void fill_pb_page(struct pbe *pbpage)
++static inline struct bm_block *
++create_bm_block_list(unsigned int nr_blocks, struct chain_allocator *ca)
+ {
+- struct pbe *p;
++ struct bm_block *bblist = NULL;
++
++ while (nr_blocks-- > 0) {
++ struct bm_block *bb;
+
+- p = pbpage;
+- pbpage += PB_PAGE_SKIP;
+- do
+- p->next = p + 1;
+- while (++p < pbpage);
++ bb = chain_alloc(ca, sizeof(struct bm_block));
++ if (!bb)
++ return NULL;
++
++ bb->next = bblist;
++ bblist = bb;
++ }
++ return bblist;
+ }
+
+ /**
+- * create_pbe_list - Create a list of PBEs on top of a given chain
+- * of memory pages allocated with alloc_pagedir()
++ * create_zone_bm_list - create a list of zone bitmap objects
+ */
+
+-static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
++static inline struct zone_bitmap *
++create_zone_bm_list(unsigned int nr_zones, struct chain_allocator *ca)
+ {
+- struct pbe *pbpage, *p;
+- unsigned int num = PBES_PER_PAGE;
++ struct zone_bitmap *zbmlist = NULL;
+
+- for_each_pb_page (pbpage, pblist) {
+- if (num >= nr_pages)
+- break;
++ while (nr_zones-- > 0) {
++ struct zone_bitmap *zbm;
++
++ zbm = chain_alloc(ca, sizeof(struct zone_bitmap));
++ if (!zbm)
++ return NULL;
++
++ zbm->next = zbmlist;
++ zbmlist = zbm;
++ }
++ return zbmlist;
++}
++
++/**
++ * memory_bm_create - allocate memory for a memory bitmap
++ */
++
++static int
++memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed)
++{
++ struct chain_allocator ca;
++ struct zone *zone;
++ struct zone_bitmap *zone_bm;
++ struct bm_block *bb;
++ unsigned int nr;
++
++ chain_init(&ca, gfp_mask, safe_needed);
+
+- fill_pb_page(pbpage);
+- num += PBES_PER_PAGE;
++ /* Compute the number of zones */
++ nr = 0;
++ for_each_zone (zone)
++ if (populated_zone(zone) && !is_highmem(zone))
++ nr++;
++
++ /* Allocate the list of zones bitmap objects */
++ zone_bm = create_zone_bm_list(nr, &ca);
++ bm->zone_bm_list = zone_bm;
++ if (!zone_bm) {
++ chain_free(&ca, PG_UNSAFE_CLEAR);
++ return -ENOMEM;
+ }
+- if (pbpage) {
+- for (num -= PBES_PER_PAGE - 1, p = pbpage; num < nr_pages; p++, num++)
+- p->next = p + 1;
+- p->next = NULL;
++
++ /* Initialize the zone bitmap objects */
++ for_each_zone (zone) {
++ unsigned long pfn;
++
++ if (!populated_zone(zone) || is_highmem(zone))
++ continue;
++
++ zone_bm->start_pfn = zone->zone_start_pfn;
++ zone_bm->end_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ /* Allocate the list of bitmap block objects */
++ nr = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK);
++ bb = create_bm_block_list(nr, &ca);
++ zone_bm->bm_blocks = bb;
++ zone_bm->cur_block = bb;
++ if (!bb)
++ goto Free;
++
++ nr = zone->spanned_pages;
++ pfn = zone->zone_start_pfn;
++ /* Initialize the bitmap block objects */
++ while (bb) {
++ unsigned long *ptr;
++
++ ptr = alloc_image_page(gfp_mask, safe_needed);
++ bb->data = ptr;
++ if (!ptr)
++ goto Free;
++
++ bb->start_pfn = pfn;
++ if (nr >= BM_BITS_PER_BLOCK) {
++ pfn += BM_BITS_PER_BLOCK;
++ bb->size = BM_CHUNKS_PER_BLOCK;
++ nr -= BM_BITS_PER_BLOCK;
++ } else {
++ /* This is executed only once in the loop */
++ pfn += nr;
++ bb->size = DIV_ROUND_UP(nr, BM_BITS_PER_CHUNK);
++ }
++ bb->end_pfn = pfn;
++ bb = bb->next;
++ }
++ zone_bm = zone_bm->next;
+ }
++ bm->p_list = ca.chain;
++ memory_bm_position_reset(bm);
++ return 0;
++
++Free:
++ bm->p_list = ca.chain;
++ memory_bm_free(bm, PG_UNSAFE_CLEAR);
++ return -ENOMEM;
+ }
+
+-static unsigned int unsafe_pages;
++/**
++ * memory_bm_free - free memory occupied by the memory bitmap @bm
++ */
++
++static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
++{
++ struct zone_bitmap *zone_bm;
++
++ /* Free the list of bit blocks for each zone_bitmap object */
++ zone_bm = bm->zone_bm_list;
++ while (zone_bm) {
++ struct bm_block *bb;
++
++ bb = zone_bm->bm_blocks;
++ while (bb) {
++ if (bb->data)
++ free_image_page(bb->data, clear_nosave_free);
++ bb = bb->next;
++ }
++ zone_bm = zone_bm->next;
++ }
++ free_list_of_pages(bm->p_list, clear_nosave_free);
++ bm->zone_bm_list = NULL;
++}
+
+ /**
+- * @safe_needed - on resume, for storing the PBE list and the image,
+- * we can only use memory pages that do not conflict with the pages
+- * used before suspend.
++ * memory_bm_set_bit - set the bit in the bitmap @bm that corresponds
++ * to given pfn. The cur_zone_bm member of @bm and the cur_block member
++ * of @bm->cur_zone_bm are updated.
+ *
+- * The unsafe pages are marked with the PG_nosave_free flag
+- * and we count them using unsafe_pages
++ * If the bit cannot be set, the function returns -EINVAL .
+ */
+
+-static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
++static int
++memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
+ {
+- void *res;
+-
+- res = (void *)get_zeroed_page(gfp_mask);
+- if (safe_needed)
+- while (res && PageNosaveFree(virt_to_page(res))) {
+- /* The page is unsafe, mark it for swsusp_free() */
+- SetPageNosave(virt_to_page(res));
+- unsafe_pages++;
+- res = (void *)get_zeroed_page(gfp_mask);
++ struct zone_bitmap *zone_bm;
++ struct bm_block *bb;
++
++ /* Check if the pfn is from the current zone */
++ zone_bm = bm->cur.zone_bm;
++ if (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
++ zone_bm = bm->zone_bm_list;
++ /* We don't assume that the zones are sorted by pfns */
++ while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
++ zone_bm = zone_bm->next;
++ if (unlikely(!zone_bm))
++ return -EINVAL;
+ }
+- if (res) {
+- SetPageNosave(virt_to_page(res));
+- SetPageNosaveFree(virt_to_page(res));
++ bm->cur.zone_bm = zone_bm;
+ }
+- return res;
++ /* Check if the pfn corresponds to the current bitmap block */
++ bb = zone_bm->cur_block;
++ if (pfn < bb->start_pfn)
++ bb = zone_bm->bm_blocks;
++
++ while (pfn >= bb->end_pfn) {
++ bb = bb->next;
++ if (unlikely(!bb))
++ return -EINVAL;
++ }
++ zone_bm->cur_block = bb;
++ pfn -= bb->start_pfn;
++ set_bit(pfn % BM_BITS_PER_CHUNK, bb->data + pfn / BM_BITS_PER_CHUNK);
++ return 0;
+ }
+
+-unsigned long get_safe_page(gfp_t gfp_mask)
++/* Two auxiliary functions for memory_bm_next_pfn */
++
++/* Find the first set bit in the given chunk, if there is one */
++
++static inline int next_bit_in_chunk(int bit, unsigned long *chunk_p)
+ {
+- return (unsigned long)alloc_image_page(gfp_mask, 1);
++ bit++;
++ while (bit < BM_BITS_PER_CHUNK) {
++ if (test_bit(bit, chunk_p))
++ return bit;
++
++ bit++;
++ }
++ return -1;
++}
++
++/* Find a chunk containing some bits set in given block of bits */
++
++static inline int next_chunk_in_block(int n, struct bm_block *bb)
++{
++ n++;
++ while (n < bb->size) {
++ if (bb->data[n])
++ return n;
++
++ n++;
++ }
++ return -1;
+ }
+
+ /**
+- * alloc_pagedir - Allocate the page directory.
+- *
+- * First, determine exactly how many pages we need and
+- * allocate them.
++ * memory_bm_next_pfn - find the pfn that corresponds to the next set bit
++ * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is
++ * returned.
+ *
+- * We arrange the pages in a chain: each page is an array of PBES_PER_PAGE
+- * struct pbe elements (pbes) and the last element in the page points
+- * to the next page.
++ * It is required to run memory_bm_position_reset() before the first call to
++ * this function.
++ */
++
++static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm)
++{
++ struct zone_bitmap *zone_bm;
++ struct bm_block *bb;
++ int chunk;
++ int bit;
++
++ do {
++ bb = bm->cur.block;
++ do {
++ chunk = bm->cur.chunk;
++ bit = bm->cur.bit;
++ do {
++ bit = next_bit_in_chunk(bit, bb->data + chunk);
++ if (bit >= 0)
++ goto Return_pfn;
++
++ chunk = next_chunk_in_block(chunk, bb);
++ bit = -1;
++ } while (chunk >= 0);
++ bb = bb->next;
++ bm->cur.block = bb;
++ memory_bm_reset_chunk(bm);
++ } while (bb);
++ zone_bm = bm->cur.zone_bm->next;
++ if (zone_bm) {
++ bm->cur.zone_bm = zone_bm;
++ bm->cur.block = zone_bm->bm_blocks;
++ memory_bm_reset_chunk(bm);
++ }
++ } while (zone_bm);
++ memory_bm_position_reset(bm);
++ return BM_END_OF_MAP;
++
++Return_pfn:
++ bm->cur.chunk = chunk;
++ bm->cur.bit = bit;
++ return bb->start_pfn + chunk * BM_BITS_PER_CHUNK + bit;
++}
++
++/**
++ * snapshot_additional_pages - estimate the number of additional pages
++ * be needed for setting up the suspend image data structures for given
++ * zone (usually the returned value is greater than the exact number)
++ */
++
++unsigned int snapshot_additional_pages(struct zone *zone)
++{
++ unsigned int res;
++
++ res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK);
++ res += DIV_ROUND_UP(res * sizeof(struct bm_block), PAGE_SIZE);
++ return res;
++}
++
++/**
++ * pfn_is_nosave - check if given pfn is in the 'nosave' section
++ */
++
++static inline int pfn_is_nosave(unsigned long pfn)
++{
++ unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
++ unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
++ return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
++}
++
++/**
++ * saveable - Determine whether a page should be cloned or not.
++ * @pfn: The page
+ *
+- * On each page we set up a list of struct_pbe elements.
++ * We save a page if it isn't Nosave, and is not in the range of pages
++ * statically defined as 'unsaveable', and it
++ * isn't a part of a free chunk of pages.
+ */
+
+-static struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask,
+- int safe_needed)
++static struct page *saveable_page(unsigned long pfn)
+ {
+- unsigned int num;
+- struct pbe *pblist, *pbe;
++ struct page *page;
++
++ if (!pfn_valid(pfn))
++ return NULL;
+
+- if (!nr_pages)
++ page = pfn_to_page(pfn);
++
++ if (PageNosave(page))
++ return NULL;
++ if (PageReserved(page) && pfn_is_nosave(pfn))
+ return NULL;
++ if (PageNosaveFree(page))
++ return NULL;
++
++ return page;
++}
++
++unsigned int count_data_pages(void)
++{
++ struct zone *zone;
++ unsigned long pfn, max_zone_pfn;
++ unsigned int n = 0;
+
+- pblist = alloc_image_page(gfp_mask, safe_needed);
+- /* FIXME: rewrite this ugly loop */
+- for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
+- pbe = pbe->next, num += PBES_PER_PAGE) {
+- pbe += PB_PAGE_SKIP;
+- pbe->next = alloc_image_page(gfp_mask, safe_needed);
++ for_each_zone (zone) {
++ if (is_highmem(zone))
++ continue;
++ mark_free_pages(zone);
++ max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
++ n += !!saveable_page(pfn);
+ }
+- if (!pbe) { /* get_zeroed_page() failed */
+- free_pagedir(pblist, 1);
+- pblist = NULL;
+- } else
+- create_pbe_list(pblist, nr_pages);
+- return pblist;
++ return n;
++}
++
++static inline void copy_data_page(long *dst, long *src)
++{
++ int n;
++
++ /* copy_page and memcpy are not usable for copying task structs. */
++ for (n = PAGE_SIZE / sizeof(long); n; n--)
++ *dst++ = *src++;
++}
++
++static void
++copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
++{
++ struct zone *zone;
++ unsigned long pfn;
++
++ for_each_zone (zone) {
++ unsigned long max_zone_pfn;
++
++ if (is_highmem(zone))
++ continue;
++
++ mark_free_pages(zone);
++ max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
++ if (saveable_page(pfn))
++ memory_bm_set_bit(orig_bm, pfn);
++ }
++ memory_bm_position_reset(orig_bm);
++ memory_bm_position_reset(copy_bm);
++ do {
++ pfn = memory_bm_next_pfn(orig_bm);
++ if (likely(pfn != BM_END_OF_MAP)) {
++ struct page *page;
++ void *src;
++
++ page = pfn_to_page(pfn);
++ src = page_address(page);
++ page = pfn_to_page(memory_bm_next_pfn(copy_bm));
++ copy_data_page(page_address(page), src);
++ }
++ } while (pfn != BM_END_OF_MAP);
+ }
+
+ /**
+- * Free pages we allocated for suspend. Suspend pages are alocated
+- * before atomic copy, so we need to free them after resume.
++ * swsusp_free - free pages allocated for the suspend.
++ *
++ * Suspend pages are alocated before the atomic copy is made, so we
++ * need to release them after the resume.
+ */
+
+ void swsusp_free(void)
+ {
+ struct zone *zone;
+- unsigned long zone_pfn;
++ unsigned long pfn, max_zone_pfn;
+
+ for_each_zone(zone) {
+- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+- if (pfn_valid(zone_pfn + zone->zone_start_pfn)) {
+- struct page *page;
+- page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
++ max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
++ if (pfn_valid(pfn)) {
++ struct page *page = pfn_to_page(pfn);
++
+ if (PageNosave(page) && PageNosaveFree(page)) {
+ ClearPageNosave(page);
+ ClearPageNosaveFree(page);
+@@ -399,7 +798,7 @@ void swsusp_free(void)
+ }
+ nr_copy_pages = 0;
+ nr_meta_pages = 0;
+- pagedir_nosave = NULL;
++ restore_pblist = NULL;
+ buffer = NULL;
+ }
+
+@@ -414,46 +813,57 @@ void swsusp_free(void)
+ static int enough_free_mem(unsigned int nr_pages)
+ {
+ struct zone *zone;
+- unsigned int n = 0;
++ unsigned int free = 0, meta = 0;
+
+ for_each_zone (zone)
+- if (!is_highmem(zone))
+- n += zone->free_pages;
+- pr_debug("swsusp: available memory: %u pages\n", n);
+- return n > (nr_pages + PAGES_FOR_IO +
+- (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
+-}
++ if (!is_highmem(zone)) {
++ free += zone->free_pages;
++ meta += snapshot_additional_pages(zone);
++ }
+
+-static int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed)
+-{
+- struct pbe *p;
++ pr_debug("swsusp: pages needed: %u + %u + %u, available pages: %u\n",
++ nr_pages, PAGES_FOR_IO, meta, free);
+
+- for_each_pbe (p, pblist) {
+- p->address = (unsigned long)alloc_image_page(gfp_mask, safe_needed);
+- if (!p->address)
+- return -ENOMEM;
+- }
+- return 0;
++ return free > nr_pages + PAGES_FOR_IO + meta;
+ }
+
+-static struct pbe *swsusp_alloc(unsigned int nr_pages)
++static int
++swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
++ unsigned int nr_pages)
+ {
+- struct pbe *pblist;
++ int error;
+
+- if (!(pblist = alloc_pagedir(nr_pages, GFP_ATOMIC | __GFP_COLD, 0))) {
+- printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
+- return NULL;
+- }
++ error = memory_bm_create(orig_bm, GFP_ATOMIC | __GFP_COLD, PG_ANY);
++ if (error)
++ goto Free;
+
+- if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
+- printk(KERN_ERR "suspend: Allocating image pages failed.\n");
+- swsusp_free();
+- return NULL;
++ error = memory_bm_create(copy_bm, GFP_ATOMIC | __GFP_COLD, PG_ANY);
++ if (error)
++ goto Free;
++
++ while (nr_pages-- > 0) {
++ struct page *page = alloc_page(GFP_ATOMIC | __GFP_COLD);
++ if (!page)
++ goto Free;
++
++ SetPageNosave(page);
++ SetPageNosaveFree(page);
++ memory_bm_set_bit(copy_bm, page_to_pfn(page));
+ }
++ return 0;
+
+- return pblist;
++Free:
++ swsusp_free();
++ return -ENOMEM;
+ }
+
++/* Memory bitmap used for marking saveable pages */
++static struct memory_bitmap orig_bm;
++/* Memory bitmap used for marking allocated pages that will contain the copies
++ * of saveable pages
++ */
++static struct memory_bitmap copy_bm;
++
+ asmlinkage int swsusp_save(void)
+ {
+ unsigned int nr_pages;
+@@ -464,25 +874,19 @@ asmlinkage int swsusp_save(void)
+ nr_pages = count_data_pages();
+ printk("swsusp: Need to copy %u pages\n", nr_pages);
+
+- pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n",
+- nr_pages,
+- (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE,
+- PAGES_FOR_IO, nr_free_pages());
+-
+ if (!enough_free_mem(nr_pages)) {
+ printk(KERN_ERR "swsusp: Not enough free memory\n");
+ return -ENOMEM;
+ }
+
+- pagedir_nosave = swsusp_alloc(nr_pages);
+- if (!pagedir_nosave)
++ if (swsusp_alloc(&orig_bm, ©_bm, nr_pages))
+ return -ENOMEM;
+
+ /* During allocating of suspend pagedir, new cold pages may appear.
+ * Kill them.
+ */
+ drain_local_pages();
+- copy_data_pages(pagedir_nosave);
++ copy_data_pages(©_bm, &orig_bm);
+
+ /*
+ * End of critical section. From now on, we can write to memory,
+@@ -502,7 +906,7 @@ static void init_header(struct swsusp_in
+ memset(info, 0, sizeof(struct swsusp_info));
+ info->version_code = LINUX_VERSION_CODE;
+ info->num_physpages = num_physpages;
+- memcpy(&info->uts, &system_utsname, sizeof(system_utsname));
++ memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));
+ info->cpus = num_online_cpus();
+ info->image_pages = nr_copy_pages;
+ info->pages = nr_copy_pages + nr_meta_pages + 1;
+@@ -511,22 +915,20 @@ static void init_header(struct swsusp_in
+ }
+
+ /**
+- * pack_orig_addresses - the .orig_address fields of the PBEs from the
+- * list starting at @pbe are stored in the array @buf[] (1 page)
++ * pack_pfns - pfns corresponding to the set bits found in the bitmap @bm
++ * are stored in the array @buf[] (1 page at a time)
+ */
+
+-static inline struct pbe *pack_orig_addresses(unsigned long *buf, struct pbe *pbe)
++static inline void
++pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
+ {
+ int j;
+
+- for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
+- buf[j] = pbe->orig_address;
+- pbe = pbe->next;
++ for (j = 0; j < PAGE_SIZE / sizeof(long); j++) {
++ buf[j] = memory_bm_next_pfn(bm);
++ if (unlikely(buf[j] == BM_END_OF_MAP))
++ break;
+ }
+- if (!pbe)
+- for (; j < PAGE_SIZE / sizeof(long); j++)
+- buf[j] = 0;
+- return pbe;
+ }
+
+ /**
+@@ -553,37 +955,39 @@ static inline struct pbe *pack_orig_addr
+
+ int snapshot_read_next(struct snapshot_handle *handle, size_t count)
+ {
+- if (handle->page > nr_meta_pages + nr_copy_pages)
++ if (handle->cur > nr_meta_pages + nr_copy_pages)
+ return 0;
++
+ if (!buffer) {
+ /* This makes the buffer be freed by swsusp_free() */
+- buffer = alloc_image_page(GFP_ATOMIC, 0);
++ buffer = alloc_image_page(GFP_ATOMIC, PG_ANY);
+ if (!buffer)
+ return -ENOMEM;
+ }
+ if (!handle->offset) {
+ init_header((struct swsusp_info *)buffer);
+ handle->buffer = buffer;
+- handle->pbe = pagedir_nosave;
++ memory_bm_position_reset(&orig_bm);
++ memory_bm_position_reset(©_bm);
+ }
+- if (handle->prev < handle->page) {
+- if (handle->page <= nr_meta_pages) {
+- handle->pbe = pack_orig_addresses(buffer, handle->pbe);
+- if (!handle->pbe)
+- handle->pbe = pagedir_nosave;
++ if (handle->prev < handle->cur) {
++ if (handle->cur <= nr_meta_pages) {
++ memset(buffer, 0, PAGE_SIZE);
++ pack_pfns(buffer, &orig_bm);
+ } else {
+- handle->buffer = (void *)handle->pbe->address;
+- handle->pbe = handle->pbe->next;
++ unsigned long pfn = memory_bm_next_pfn(©_bm);
++
++ handle->buffer = page_address(pfn_to_page(pfn));
+ }
+- handle->prev = handle->page;
++ handle->prev = handle->cur;
+ }
+- handle->buf_offset = handle->page_offset;
+- if (handle->page_offset + count >= PAGE_SIZE) {
+- count = PAGE_SIZE - handle->page_offset;
+- handle->page_offset = 0;
+- handle->page++;
++ handle->buf_offset = handle->cur_offset;
++ if (handle->cur_offset + count >= PAGE_SIZE) {
++ count = PAGE_SIZE - handle->cur_offset;
++ handle->cur_offset = 0;
++ handle->cur++;
+ } else {
+- handle->page_offset += count;
++ handle->cur_offset += count;
+ }
+ handle->offset += count;
+ return count;
+@@ -595,47 +999,50 @@ int snapshot_read_next(struct snapshot_h
+ * had been used before suspend
+ */
+
+-static int mark_unsafe_pages(struct pbe *pblist)
++static int mark_unsafe_pages(struct memory_bitmap *bm)
+ {
+ struct zone *zone;
+- unsigned long zone_pfn;
+- struct pbe *p;
+-
+- if (!pblist) /* a sanity check */
+- return -EINVAL;
++ unsigned long pfn, max_zone_pfn;
+
+ /* Clear page flags */
+ for_each_zone (zone) {
+- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+- if (pfn_valid(zone_pfn + zone->zone_start_pfn))
+- ClearPageNosaveFree(pfn_to_page(zone_pfn +
+- zone->zone_start_pfn));
++ max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
++ if (pfn_valid(pfn))
++ ClearPageNosaveFree(pfn_to_page(pfn));
+ }
+
+- /* Mark orig addresses */
+- for_each_pbe (p, pblist) {
+- if (virt_addr_valid(p->orig_address))
+- SetPageNosaveFree(virt_to_page(p->orig_address));
+- else
+- return -EFAULT;
+- }
++ /* Mark pages that correspond to the "original" pfns as "unsafe" */
++ memory_bm_position_reset(bm);
++ do {
++ pfn = memory_bm_next_pfn(bm);
++ if (likely(pfn != BM_END_OF_MAP)) {
++ if (likely(pfn_valid(pfn)))
++ SetPageNosaveFree(pfn_to_page(pfn));
++ else
++ return -EFAULT;
++ }
++ } while (pfn != BM_END_OF_MAP);
+
+- unsafe_pages = 0;
++ allocated_unsafe_pages = 0;
+
+ return 0;
+ }
+
+-static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
++static void
++duplicate_memory_bitmap(struct memory_bitmap *dst, struct memory_bitmap *src)
+ {
+- /* We assume both lists contain the same number of elements */
+- while (src) {
+- dst->orig_address = src->orig_address;
+- dst = dst->next;
+- src = src->next;
++ unsigned long pfn;
++
++ memory_bm_position_reset(src);
++ pfn = memory_bm_next_pfn(src);
++ while (pfn != BM_END_OF_MAP) {
++ memory_bm_set_bit(dst, pfn);
++ pfn = memory_bm_next_pfn(src);
+ }
+ }
+
+-static int check_header(struct swsusp_info *info)
++static inline int check_header(struct swsusp_info *info)
+ {
+ char *reason = NULL;
+
+@@ -643,13 +1050,13 @@ static int check_header(struct swsusp_in
+ reason = "kernel version";
+ if (info->num_physpages != num_physpages)
+ reason = "memory size";
+- if (strcmp(info->uts.sysname,system_utsname.sysname))
++ if (strcmp(info->uts.sysname,init_utsname()->sysname))
+ reason = "system type";
+- if (strcmp(info->uts.release,system_utsname.release))
++ if (strcmp(info->uts.release,init_utsname()->release))
+ reason = "kernel release";
+- if (strcmp(info->uts.version,system_utsname.version))
++ if (strcmp(info->uts.version,init_utsname()->version))
+ reason = "version";
+- if (strcmp(info->uts.machine,system_utsname.machine))
++ if (strcmp(info->uts.machine,init_utsname()->machine))
+ reason = "machine";
+ if (reason) {
+ printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
+@@ -662,19 +1069,14 @@ static int check_header(struct swsusp_in
+ * load header - check the image header and copy data from it
+ */
+
+-static int load_header(struct snapshot_handle *handle,
+- struct swsusp_info *info)
++static int
++load_header(struct swsusp_info *info)
+ {
+ int error;
+- struct pbe *pblist;
+
++ restore_pblist = NULL;
+ error = check_header(info);
+ if (!error) {
+- pblist = alloc_pagedir(info->image_pages, GFP_ATOMIC, 0);
+- if (!pblist)
+- return -ENOMEM;
+- pagedir_nosave = pblist;
+- handle->pbe = pblist;
+ nr_copy_pages = info->image_pages;
+ nr_meta_pages = info->pages - info->image_pages - 1;
+ }
+@@ -682,113 +1084,137 @@ static int load_header(struct snapshot_h
+ }
+
+ /**
+- * unpack_orig_addresses - copy the elements of @buf[] (1 page) to
+- * the PBEs in the list starting at @pbe
++ * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set
++ * the corresponding bit in the memory bitmap @bm
+ */
+
+-static inline struct pbe *unpack_orig_addresses(unsigned long *buf,
+- struct pbe *pbe)
++static inline void
++unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
+ {
+ int j;
+
+- for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
+- pbe->orig_address = buf[j];
+- pbe = pbe->next;
++ for (j = 0; j < PAGE_SIZE / sizeof(long); j++) {
++ if (unlikely(buf[j] == BM_END_OF_MAP))
++ break;
++
++ memory_bm_set_bit(bm, buf[j]);
+ }
+- return pbe;
+ }
+
+ /**
+- * prepare_image - use metadata contained in the PBE list
+- * pointed to by pagedir_nosave to mark the pages that will
+- * be overwritten in the process of restoring the system
+- * memory state from the image ("unsafe" pages) and allocate
+- * memory for the image
++ * prepare_image - use the memory bitmap @bm to mark the pages that will
++ * be overwritten in the process of restoring the system memory state
++ * from the suspend image ("unsafe" pages) and allocate memory for the
++ * image.
+ *
+- * The idea is to allocate the PBE list first and then
+- * allocate as many pages as it's needed for the image data,
+- * but not to assign these pages to the PBEs initially.
+- * Instead, we just mark them as allocated and create a list
+- * of "safe" which will be used later
++ * The idea is to allocate a new memory bitmap first and then allocate
++ * as many pages as needed for the image data, but not to assign these
++ * pages to specific tasks initially. Instead, we just mark them as
++ * allocated and create a list of "safe" pages that will be used later.
+ */
+
+-struct safe_page {
+- struct safe_page *next;
+- char padding[PAGE_SIZE - sizeof(void *)];
+-};
++#define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe))
+
+-static struct safe_page *safe_pages;
++static struct linked_page *safe_pages_list;
+
+-static int prepare_image(struct snapshot_handle *handle)
++static int
++prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
+ {
+- int error = 0;
+- unsigned int nr_pages = nr_copy_pages;
+- struct pbe *p, *pblist = NULL;
++ unsigned int nr_pages;
++ struct linked_page *sp_list, *lp;
++ int error;
+
+- p = pagedir_nosave;
+- error = mark_unsafe_pages(p);
+- if (!error) {
+- pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, 1);
+- if (pblist)
+- copy_page_backup_list(pblist, p);
+- free_pagedir(p, 0);
+- if (!pblist)
++ error = mark_unsafe_pages(bm);
++ if (error)
++ goto Free;
++
++ error = memory_bm_create(new_bm, GFP_ATOMIC, PG_SAFE);
++ if (error)
++ goto Free;
++
++ duplicate_memory_bitmap(new_bm, bm);
++ memory_bm_free(bm, PG_UNSAFE_KEEP);
++ /* Reserve some safe pages for potential later use.
++ *
++ * NOTE: This way we make sure there will be enough safe pages for the
++ * chain_alloc() in get_buffer(). It is a bit wasteful, but
++ * nr_copy_pages cannot be greater than 50% of the memory anyway.
++ */
++ sp_list = NULL;
++ /* nr_copy_pages cannot be lesser than allocated_unsafe_pages */
++ nr_pages = nr_copy_pages - allocated_unsafe_pages;
++ nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE);
++ while (nr_pages > 0) {
++ lp = alloc_image_page(GFP_ATOMIC, PG_SAFE);
++ if (!lp) {
+ error = -ENOMEM;
++ goto Free;
++ }
++ lp->next = sp_list;
++ sp_list = lp;
++ nr_pages--;
+ }
+- safe_pages = NULL;
+- if (!error && nr_pages > unsafe_pages) {
+- nr_pages -= unsafe_pages;
+- while (nr_pages--) {
+- struct safe_page *ptr;
+-
+- ptr = (struct safe_page *)get_zeroed_page(GFP_ATOMIC);
+- if (!ptr) {
+- error = -ENOMEM;
+- break;
+- }
+- if (!PageNosaveFree(virt_to_page(ptr))) {
+- /* The page is "safe", add it to the list */
+- ptr->next = safe_pages;
+- safe_pages = ptr;
+- }
+- /* Mark the page as allocated */
+- SetPageNosave(virt_to_page(ptr));
+- SetPageNosaveFree(virt_to_page(ptr));
++ /* Preallocate memory for the image */
++ safe_pages_list = NULL;
++ nr_pages = nr_copy_pages - allocated_unsafe_pages;
++ while (nr_pages > 0) {
++ lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC);
++ if (!lp) {
++ error = -ENOMEM;
++ goto Free;
++ }
++ if (!PageNosaveFree(virt_to_page(lp))) {
++ /* The page is "safe", add it to the list */
++ lp->next = safe_pages_list;
++ safe_pages_list = lp;
+ }
++ /* Mark the page as allocated */
++ SetPageNosave(virt_to_page(lp));
++ SetPageNosaveFree(virt_to_page(lp));
++ nr_pages--;
+ }
+- if (!error) {
+- pagedir_nosave = pblist;
+- } else {
+- handle->pbe = NULL;
+- swsusp_free();
++ /* Free the reserved safe pages so that chain_alloc() can use them */
++ while (sp_list) {
++ lp = sp_list->next;
++ free_image_page(sp_list, PG_UNSAFE_CLEAR);
++ sp_list = lp;
+ }
++ return 0;
++
++Free:
++ swsusp_free();
+ return error;
+ }
+
+-static void *get_buffer(struct snapshot_handle *handle)
++/**
++ * get_buffer - compute the address that snapshot_write_next() should
++ * set for its caller to write to.
++ */
++
++static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
+ {
+- struct pbe *pbe = handle->pbe, *last = handle->last_pbe;
+- struct page *page = virt_to_page(pbe->orig_address);
++ struct pbe *pbe;
++ struct page *page = pfn_to_page(memory_bm_next_pfn(bm));
+
+- if (PageNosave(page) && PageNosaveFree(page)) {
+- /*
+- * We have allocated the "original" page frame and we can
+- * use it directly to store the read page
++ if (PageNosave(page) && PageNosaveFree(page))
++ /* We have allocated the "original" page frame and we can
++ * use it directly to store the loaded page.
+ */
+- pbe->address = 0;
+- if (last && last->next)
+- last->next = NULL;
+- return (void *)pbe->orig_address;
+- }
+- /*
+- * The "original" page frame has not been allocated and we have to
+- * use a "safe" page frame to store the read page
++ return page_address(page);
++
++ /* The "original" page frame has not been allocated and we have to
++ * use a "safe" page frame to store the loaded page.
+ */
+- pbe->address = (unsigned long)safe_pages;
+- safe_pages = safe_pages->next;
+- if (last)
+- last->next = pbe;
+- handle->last_pbe = pbe;
++ pbe = chain_alloc(ca, sizeof(struct pbe));
++ if (!pbe) {
++ swsusp_free();
++ return NULL;
++ }
++ pbe->orig_address = (unsigned long)page_address(page);
++ pbe->address = (unsigned long)safe_pages_list;
++ safe_pages_list = safe_pages_list->next;
++ pbe->next = restore_pblist;
++ restore_pblist = pbe;
+ return (void *)pbe->address;
+ }
+
+@@ -816,46 +1242,60 @@ static void *get_buffer(struct snapshot_
+
+ int snapshot_write_next(struct snapshot_handle *handle, size_t count)
+ {
++ static struct chain_allocator ca;
+ int error = 0;
+
+- if (handle->prev && handle->page > nr_meta_pages + nr_copy_pages)
++ /* Check if we have already loaded the entire image */
++ if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages)
+ return 0;
++
+ if (!buffer) {
+ /* This makes the buffer be freed by swsusp_free() */
+- buffer = alloc_image_page(GFP_ATOMIC, 0);
++ buffer = alloc_image_page(GFP_ATOMIC, PG_ANY);
+ if (!buffer)
+ return -ENOMEM;
+ }
+ if (!handle->offset)
+ handle->buffer = buffer;
+- if (handle->prev < handle->page) {
+- if (!handle->prev) {
+- error = load_header(handle, (struct swsusp_info *)buffer);
++ handle->sync_read = 1;
++ if (handle->prev < handle->cur) {
++ if (handle->prev == 0) {
++ error = load_header(buffer);
+ if (error)
+ return error;
++
++ error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY);
++ if (error)
++ return error;
++
+ } else if (handle->prev <= nr_meta_pages) {
+- handle->pbe = unpack_orig_addresses(buffer, handle->pbe);
+- if (!handle->pbe) {
+- error = prepare_image(handle);
++ unpack_orig_pfns(buffer, ©_bm);
++ if (handle->prev == nr_meta_pages) {
++ error = prepare_image(&orig_bm, ©_bm);
+ if (error)
+ return error;
+- handle->pbe = pagedir_nosave;
+- handle->last_pbe = NULL;
+- handle->buffer = get_buffer(handle);
++
++ chain_init(&ca, GFP_ATOMIC, PG_SAFE);
++ memory_bm_position_reset(&orig_bm);
++ restore_pblist = NULL;
++ handle->buffer = get_buffer(&orig_bm, &ca);
++ handle->sync_read = 0;
++ if (!handle->buffer)
++ return -ENOMEM;
+ }
+ } else {
+- handle->pbe = handle->pbe->next;
+- handle->buffer = get_buffer(handle);
++ handle->buffer = get_buffer(&orig_bm, &ca);
++ handle->sync_read = 0;
+ }
+- handle->prev = handle->page;
++ handle->prev = handle->cur;
+ }
+- handle->buf_offset = handle->page_offset;
+- if (handle->page_offset + count >= PAGE_SIZE) {
+- count = PAGE_SIZE - handle->page_offset;
+- handle->page_offset = 0;
+- handle->page++;
++ handle->buf_offset = handle->cur_offset;
++ if (handle->cur_offset + count >= PAGE_SIZE) {
++ count = PAGE_SIZE - handle->cur_offset;
++ handle->cur_offset = 0;
++ handle->cur++;
+ } else {
+- handle->page_offset += count;
++ handle->cur_offset += count;
+ }
+ handle->offset += count;
+ return count;
+@@ -863,6 +1303,13 @@ int snapshot_write_next(struct snapshot_
+
+ int snapshot_image_loaded(struct snapshot_handle *handle)
+ {
+- return !(!handle->pbe || handle->pbe->next || !nr_copy_pages ||
+- handle->page <= nr_meta_pages + nr_copy_pages);
++ return !(!nr_copy_pages ||
++ handle->cur <= nr_meta_pages + nr_copy_pages);
++}
++
++void snapshot_free_unused_memory(struct snapshot_handle *handle)
++{
++ /* Free only if we have loaded the image entirely */
++ if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages)
++ memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR);
+ }
+diff --git a/kernel/power/swap.c b/kernel/power/swap.c
+index f1dd146..1a3b0dd 100644
+--- a/kernel/power/swap.c
++++ b/kernel/power/swap.c
+@@ -22,6 +22,7 @@
+ #include <linux/device.h>
+ #include <linux/buffer_head.h>
+ #include <linux/bio.h>
++#include <linux/blkdev.h>
+ #include <linux/swap.h>
+ #include <linux/swapops.h>
+ #include <linux/pm.h>
+@@ -49,18 +50,16 @@ static int mark_swapfiles(swp_entry_t st
+ {
+ int error;
+
+- rw_swap_page_sync(READ,
+- swp_entry(root_swap, 0),
+- virt_to_page((unsigned long)&swsusp_header));
++ rw_swap_page_sync(READ, swp_entry(root_swap, 0),
++ virt_to_page((unsigned long)&swsusp_header), NULL);
+ if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
+ !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
+ memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
+ memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
+ swsusp_header.image = start;
+- error = rw_swap_page_sync(WRITE,
+- swp_entry(root_swap, 0),
+- virt_to_page((unsigned long)
+- &swsusp_header));
++ error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0),
++ virt_to_page((unsigned long)&swsusp_header),
++ NULL);
+ } else {
+ pr_debug("swsusp: Partition is not swap space.\n");
+ error = -ENODEV;
+@@ -88,16 +87,37 @@ static int swsusp_swap_check(void) /* Th
+ * write_page - Write one page to given swap location.
+ * @buf: Address we're writing.
+ * @offset: Offset of the swap page we're writing to.
++ * @bio_chain: Link the next write BIO here
+ */
+
+-static int write_page(void *buf, unsigned long offset)
++static int write_page(void *buf, unsigned long offset, struct bio **bio_chain)
+ {
+ swp_entry_t entry;
+ int error = -ENOSPC;
+
+ if (offset) {
++ struct page *page = virt_to_page(buf);
++
++ if (bio_chain) {
++ /*
++ * Whether or not we successfully allocated a copy page,
++ * we take a ref on the page here. It gets undone in
++ * wait_on_bio_chain().
++ */
++ struct page *page_copy;
++ page_copy = alloc_page(GFP_ATOMIC);
++ if (page_copy == NULL) {
++ WARN_ON_ONCE(1);
++ bio_chain = NULL; /* Go synchronous */
++ get_page(page);
++ } else {
++ memcpy(page_address(page_copy),
++ page_address(page), PAGE_SIZE);
++ page = page_copy;
++ }
++ }
+ entry = swp_entry(root_swap, offset);
+- error = rw_swap_page_sync(WRITE, entry, virt_to_page(buf));
++ error = rw_swap_page_sync(WRITE, entry, page, bio_chain);
+ }
+ return error;
+ }
+@@ -146,6 +166,26 @@ static void release_swap_writer(struct s
+ handle->bitmap = NULL;
+ }
+
++static void show_speed(struct timeval *start, struct timeval *stop,
++ unsigned nr_pages, char *msg)
++{
++ s64 elapsed_centisecs64;
++ int centisecs;
++ int k;
++ int kps;
++
++ elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
++ do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
++ centisecs = elapsed_centisecs64;
++ if (centisecs == 0)
++ centisecs = 1; /* avoid div-by-zero */
++ k = nr_pages * (PAGE_SIZE / 1024);
++ kps = (k * 100) / centisecs;
++ printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k,
++ centisecs / 100, centisecs % 100,
++ kps / 1000, (kps % 1000) / 10);
++}
++
+ static int get_swap_writer(struct swap_map_handle *handle)
+ {
+ handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
+@@ -165,37 +205,70 @@ static int get_swap_writer(struct swap_m
+ return 0;
+ }
+
+-static int swap_write_page(struct swap_map_handle *handle, void *buf)
++static int wait_on_bio_chain(struct bio **bio_chain)
+ {
+- int error;
++ struct bio *bio;
++ struct bio *next_bio;
++ int ret = 0;
++
++ if (bio_chain == NULL)
++ return 0;
++
++ bio = *bio_chain;
++ if (bio == NULL)
++ return 0;
++ while (bio) {
++ struct page *page;
++
++ next_bio = bio->bi_private;
++ page = bio->bi_io_vec[0].bv_page;
++ wait_on_page_locked(page);
++ if (!PageUptodate(page) || PageError(page))
++ ret = -EIO;
++ put_page(page);
++ bio_put(bio);
++ bio = next_bio;
++ }
++ *bio_chain = NULL;
++ return ret;
++}
++
++static int swap_write_page(struct swap_map_handle *handle, void *buf,
++ struct bio **bio_chain)
++{
++ int error = 0;
+ unsigned long offset;
+
+ if (!handle->cur)
+ return -EINVAL;
+ offset = alloc_swap_page(root_swap, handle->bitmap);
+- error = write_page(buf, offset);
++ error = write_page(buf, offset, bio_chain);
+ if (error)
+ return error;
+ handle->cur->entries[handle->k++] = offset;
+ if (handle->k >= MAP_PAGE_ENTRIES) {
++ error = wait_on_bio_chain(bio_chain);
++ if (error)
++ goto out;
+ offset = alloc_swap_page(root_swap, handle->bitmap);
+ if (!offset)
+ return -ENOSPC;
+ handle->cur->next_swap = offset;
+- error = write_page(handle->cur, handle->cur_swap);
++ error = write_page(handle->cur, handle->cur_swap, NULL);
+ if (error)
+- return error;
++ goto out;
+ memset(handle->cur, 0, PAGE_SIZE);
+ handle->cur_swap = offset;
+ handle->k = 0;
+ }
+- return 0;
++out:
++ return error;
+ }
+
+ static int flush_swap_writer(struct swap_map_handle *handle)
+ {
+ if (handle->cur && handle->cur_swap)
+- return write_page(handle->cur, handle->cur_swap);
++ return write_page(handle->cur, handle->cur_swap, NULL);
+ else
+ return -EINVAL;
+ }
+@@ -206,21 +279,29 @@ static int flush_swap_writer(struct swap
+
+ static int save_image(struct swap_map_handle *handle,
+ struct snapshot_handle *snapshot,
+- unsigned int nr_pages)
++ unsigned int nr_to_write)
+ {
+ unsigned int m;
+ int ret;
+ int error = 0;
++ int nr_pages;
++ int err2;
++ struct bio *bio;
++ struct timeval start;
++ struct timeval stop;
+
+- printk("Saving image data pages (%u pages) ... ", nr_pages);
+- m = nr_pages / 100;
++ printk("Saving image data pages (%u pages) ... ", nr_to_write);
++ m = nr_to_write / 100;
+ if (!m)
+ m = 1;
+ nr_pages = 0;
++ bio = NULL;
++ do_gettimeofday(&start);
+ do {
+ ret = snapshot_read_next(snapshot, PAGE_SIZE);
+ if (ret > 0) {
+- error = swap_write_page(handle, data_of(*snapshot));
++ error = swap_write_page(handle, data_of(*snapshot),
++ &bio);
+ if (error)
+ break;
+ if (!(nr_pages % m))
+@@ -228,8 +309,13 @@ static int save_image(struct swap_map_ha
+ nr_pages++;
+ }
+ } while (ret > 0);
++ err2 = wait_on_bio_chain(&bio);
++ do_gettimeofday(&stop);
++ if (!error)
++ error = err2;
+ if (!error)
+ printk("\b\b\b\bdone\n");
++ show_speed(&start, &stop, nr_to_write, "Wrote");
+ return error;
+ }
+
+@@ -245,8 +331,7 @@ static int enough_swap(unsigned int nr_p
+ unsigned int free_swap = count_swap_pages(root_swap, 1);
+
+ pr_debug("swsusp: free swap pages: %u\n", free_swap);
+- return free_swap > (nr_pages + PAGES_FOR_IO +
+- (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
++ return free_swap > nr_pages + PAGES_FOR_IO;
+ }
+
+ /**
+@@ -266,7 +351,8 @@ int swsusp_write(void)
+ int error;
+
+ if ((error = swsusp_swap_check())) {
+- printk(KERN_ERR "swsusp: Cannot find swap device, try swapon -a.\n");
++ printk(KERN_ERR "swsusp: Cannot find swap device, try "
++ "swapon -a.\n");
+ return error;
+ }
+ memset(&snapshot, 0, sizeof(struct snapshot_handle));
+@@ -281,7 +367,7 @@ int swsusp_write(void)
+ error = get_swap_writer(&handle);
+ if (!error) {
+ unsigned long start = handle.cur_swap;
+- error = swap_write_page(&handle, header);
++ error = swap_write_page(&handle, header, NULL);
+ if (!error)
+ error = save_image(&handle, &snapshot,
+ header->pages - 1);
+@@ -298,27 +384,6 @@ int swsusp_write(void)
+ return error;
+ }
+
+-/*
+- * Using bio to read from swap.
+- * This code requires a bit more work than just using buffer heads
+- * but, it is the recommended way for 2.5/2.6.
+- * The following are to signal the beginning and end of I/O. Bios
+- * finish asynchronously, while we want them to happen synchronously.
+- * A simple atomic_t, and a wait loop take care of this problem.
+- */
+-
+-static atomic_t io_done = ATOMIC_INIT(0);
+-
+-static int end_io(struct bio *bio, unsigned int num, int err)
+-{
+- if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+- printk(KERN_ERR "I/O error reading swsusp image.\n");
+- return -EIO;
+- }
+- atomic_set(&io_done, 0);
+- return 0;
+-}
+-
+ static struct block_device *resume_bdev;
+
+ /**
+@@ -326,15 +391,15 @@ static struct block_device *resume_bdev;
+ * @rw: READ or WRITE.
+ * @off physical offset of page.
+ * @page: page we're reading or writing.
++ * @bio_chain: list of pending biod (for async reading)
+ *
+ * Straight from the textbook - allocate and initialize the bio.
+- * If we're writing, make sure the page is marked as dirty.
+- * Then submit it and wait.
++ * If we're reading, make sure the page is marked as dirty.
++ * Then submit it and, if @bio_chain == NULL, wait.
+ */
+-
+-static int submit(int rw, pgoff_t page_off, void *page)
++static int submit(int rw, pgoff_t page_off, struct page *page,
++ struct bio **bio_chain)
+ {
+- int error = 0;
+ struct bio *bio;
+
+ bio = bio_alloc(GFP_ATOMIC, 1);
+@@ -342,33 +407,41 @@ static int submit(int rw, pgoff_t page_o
+ return -ENOMEM;
+ bio->bi_sector = page_off * (PAGE_SIZE >> 9);
+ bio->bi_bdev = resume_bdev;
+- bio->bi_end_io = end_io;
++ bio->bi_end_io = end_swap_bio_read;
+
+- if (bio_add_page(bio, virt_to_page(page), PAGE_SIZE, 0) < PAGE_SIZE) {
+- printk("swsusp: ERROR: adding page to bio at %ld\n",page_off);
+- error = -EFAULT;
+- goto Done;
++ if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
++ printk("swsusp: ERROR: adding page to bio at %ld\n", page_off);
++ bio_put(bio);
++ return -EFAULT;
+ }
+
+- atomic_set(&io_done, 1);
+- submit_bio(rw | (1 << BIO_RW_SYNC), bio);
+- while (atomic_read(&io_done))
+- yield();
+- if (rw == READ)
+- bio_set_pages_dirty(bio);
+- Done:
+- bio_put(bio);
+- return error;
++ lock_page(page);
++ bio_get(bio);
++
++ if (bio_chain == NULL) {
++ submit_bio(rw | (1 << BIO_RW_SYNC), bio);
++ wait_on_page_locked(page);
++ if (rw == READ)
++ bio_set_pages_dirty(bio);
++ bio_put(bio);
++ } else {
++ if (rw == READ)
++ get_page(page); /* These pages are freed later */
++ bio->bi_private = *bio_chain;
++ *bio_chain = bio;
++ submit_bio(rw | (1 << BIO_RW_SYNC), bio);
++ }
++ return 0;
+ }
+
+-static int bio_read_page(pgoff_t page_off, void *page)
++static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+ {
+- return submit(READ, page_off, page);
++ return submit(READ, page_off, virt_to_page(addr), bio_chain);
+ }
+
+-static int bio_write_page(pgoff_t page_off, void *page)
++static int bio_write_page(pgoff_t page_off, void *addr)
+ {
+- return submit(WRITE, page_off, page);
++ return submit(WRITE, page_off, virt_to_page(addr), NULL);
+ }
+
+ /**
+@@ -393,7 +466,7 @@ static int get_swap_reader(struct swap_m
+ handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
+ if (!handle->cur)
+ return -ENOMEM;
+- error = bio_read_page(swp_offset(start), handle->cur);
++ error = bio_read_page(swp_offset(start), handle->cur, NULL);
+ if (error) {
+ release_swap_reader(handle);
+ return error;
+@@ -402,7 +475,8 @@ static int get_swap_reader(struct swap_m
+ return 0;
+ }
+
+-static int swap_read_page(struct swap_map_handle *handle, void *buf)
++static int swap_read_page(struct swap_map_handle *handle, void *buf,
++ struct bio **bio_chain)
+ {
+ unsigned long offset;
+ int error;
+@@ -412,16 +486,17 @@ static int swap_read_page(struct swap_ma
+ offset = handle->cur->entries[handle->k];
+ if (!offset)
+ return -EFAULT;
+- error = bio_read_page(offset, buf);
++ error = bio_read_page(offset, buf, bio_chain);
+ if (error)
+ return error;
+ if (++handle->k >= MAP_PAGE_ENTRIES) {
++ error = wait_on_bio_chain(bio_chain);
+ handle->k = 0;
+ offset = handle->cur->next_swap;
+ if (!offset)
+ release_swap_reader(handle);
+- else
+- error = bio_read_page(offset, handle->cur);
++ else if (!error)
++ error = bio_read_page(offset, handle->cur, NULL);
+ }
+ return error;
+ }
+@@ -434,33 +509,49 @@ static int swap_read_page(struct swap_ma
+
+ static int load_image(struct swap_map_handle *handle,
+ struct snapshot_handle *snapshot,
+- unsigned int nr_pages)
++ unsigned int nr_to_read)
+ {
+ unsigned int m;
+- int ret;
+ int error = 0;
++ struct timeval start;
++ struct timeval stop;
++ struct bio *bio;
++ int err2;
++ unsigned nr_pages;
+
+- printk("Loading image data pages (%u pages) ... ", nr_pages);
+- m = nr_pages / 100;
++ printk("Loading image data pages (%u pages) ... ", nr_to_read);
++ m = nr_to_read / 100;
+ if (!m)
+ m = 1;
+ nr_pages = 0;
+- do {
+- ret = snapshot_write_next(snapshot, PAGE_SIZE);
+- if (ret > 0) {
+- error = swap_read_page(handle, data_of(*snapshot));
+- if (error)
+- break;
+- if (!(nr_pages % m))
+- printk("\b\b\b\b%3d%%", nr_pages / m);
+- nr_pages++;
+- }
+- } while (ret > 0);
++ bio = NULL;
++ do_gettimeofday(&start);
++ for ( ; ; ) {
++ error = snapshot_write_next(snapshot, PAGE_SIZE);
++ if (error <= 0)
++ break;
++ error = swap_read_page(handle, data_of(*snapshot), &bio);
++ if (error)
++ break;
++ if (snapshot->sync_read)
++ error = wait_on_bio_chain(&bio);
++ if (error)
++ break;
++ if (!(nr_pages % m))
++ printk("\b\b\b\b%3d%%", nr_pages / m);
++ nr_pages++;
++ }
++ err2 = wait_on_bio_chain(&bio);
++ do_gettimeofday(&stop);
++ if (!error)
++ error = err2;
+ if (!error) {
+ printk("\b\b\b\bdone\n");
++ snapshot_free_unused_memory(snapshot);
+ if (!snapshot_image_loaded(snapshot))
+ error = -ENODATA;
+ }
++ show_speed(&start, &stop, nr_to_read, "Read");
+ return error;
+ }
+
+@@ -483,7 +574,7 @@ int swsusp_read(void)
+ header = (struct swsusp_info *)data_of(snapshot);
+ error = get_swap_reader(&handle, swsusp_header.image);
+ if (!error)
+- error = swap_read_page(&handle, header);
++ error = swap_read_page(&handle, header, NULL);
+ if (!error)
+ error = load_image(&handle, &snapshot, header->pages - 1);
+ release_swap_reader(&handle);
+@@ -509,7 +600,7 @@ int swsusp_check(void)
+ if (!IS_ERR(resume_bdev)) {
+ set_blocksize(resume_bdev, PAGE_SIZE);
+ memset(&swsusp_header, 0, sizeof(swsusp_header));
+- if ((error = bio_read_page(0, &swsusp_header)))
++ if ((error = bio_read_page(0, &swsusp_header, NULL)))
+ return error;
+ if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
+ memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
+diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
+index 17f669c..0b66659 100644
+--- a/kernel/power/swsusp.c
++++ b/kernel/power/swsusp.c
+@@ -193,14 +193,13 @@ int swsusp_shrink_memory(void)
+ printk("Shrinking memory... ");
+ do {
+ size = 2 * count_highmem_pages();
+- size += size / 50 + count_data_pages();
+- size += (size + PBES_PER_PAGE - 1) / PBES_PER_PAGE +
+- PAGES_FOR_IO;
++ size += size / 50 + count_data_pages() + PAGES_FOR_IO;
+ tmp = size;
+ for_each_zone (zone)
+ if (!is_highmem(zone) && populated_zone(zone)) {
+ tmp -= zone->free_pages;
+ tmp += zone->lowmem_reserve[ZONE_NORMAL];
++ tmp += snapshot_additional_pages(zone);
+ }
+ if (tmp > 0) {
+ tmp = __shrink_memory(tmp);
+@@ -248,6 +247,9 @@ int swsusp_suspend(void)
+ restore_processor_state();
+ Restore_highmem:
+ restore_highmem();
++ /* NOTE: device_power_up() is just a resume() for devices
++ * that suspended with irqs off ... no overall powerup.
++ */
+ device_power_up();
+ Enable_irqs:
+ local_irq_enable();
+@@ -257,8 +259,12 @@ Enable_irqs:
+ int swsusp_resume(void)
+ {
+ int error;
++
+ local_irq_disable();
+- if (device_power_down(PMSG_FREEZE))
++ /* NOTE: device_power_down() is just a suspend() with irqs off;
++ * it has no special "power things down" semantics
++ */
++ if (device_power_down(PMSG_PRETHAW))
+ printk(KERN_ERR "Some devices failed to power down, very bad\n");
+ /* We'll ignore saved state, but this gets preempt count (etc) right */
+ save_processor_state();
+diff --git a/kernel/power/user.c b/kernel/power/user.c
+index 3f1539f..d991d3b 100644
+--- a/kernel/power/user.c
++++ b/kernel/power/user.c
+@@ -19,6 +19,8 @@
+ #include <linux/swapops.h>
+ #include <linux/pm.h>
+ #include <linux/fs.h>
++#include <linux/console.h>
++#include <linux/cpu.h>
+
+ #include <asm/uaccess.h>
+
+@@ -139,11 +141,14 @@ static int snapshot_ioctl(struct inode *
+ if (data->frozen)
+ break;
+ down(&pm_sem);
+- disable_nonboot_cpus();
+- if (freeze_processes()) {
+- thaw_processes();
+- enable_nonboot_cpus();
+- error = -EBUSY;
++ error = disable_nonboot_cpus();
++ if (!error) {
++ error = freeze_processes();
++ if (error) {
++ thaw_processes();
++ enable_nonboot_cpus();
++ error = -EBUSY;
++ }
+ }
+ up(&pm_sem);
+ if (!error)
+@@ -169,12 +174,14 @@ static int snapshot_ioctl(struct inode *
+ /* Free memory before shutting down devices. */
+ error = swsusp_shrink_memory();
+ if (!error) {
++ suspend_console();
+ error = device_suspend(PMSG_FREEZE);
+ if (!error) {
+ in_suspend = 1;
+ error = swsusp_suspend();
+ device_resume();
+ }
++ resume_console();
+ }
+ up(&pm_sem);
+ if (!error)
+@@ -189,13 +196,16 @@ static int snapshot_ioctl(struct inode *
+ error = -EPERM;
+ break;
+ }
++ snapshot_free_unused_memory(&data->handle);
+ down(&pm_sem);
+ pm_prepare_console();
+- error = device_suspend(PMSG_FREEZE);
++ suspend_console();
++ error = device_suspend(PMSG_PRETHAW);
+ if (!error) {
+ error = swsusp_resume();
+ device_resume();
+ }
++ resume_console();
+ pm_restore_console();
+ up(&pm_sem);
+ break;
+@@ -284,6 +294,7 @@ static int snapshot_ioctl(struct inode *
+ }
+
+ /* Put devices to sleep */
++ suspend_console();
+ error = device_suspend(PMSG_SUSPEND);
+ if (error) {
+ printk(KERN_ERR "Failed to suspend some devices.\n");
+@@ -294,7 +305,7 @@ static int snapshot_ioctl(struct inode *
+ /* Wake up devices */
+ device_resume();
+ }
+-
++ resume_console();
+ if (pm_ops->finish)
+ pm_ops->finish(PM_SUSPEND_MEM);
+
+diff --git a/kernel/printk.c b/kernel/printk.c
+index 1149365..6642655 100644
+--- a/kernel/printk.c
++++ b/kernel/printk.c
+@@ -31,6 +31,7 @@
+ #include <linux/security.h>
+ #include <linux/bootmem.h>
+ #include <linux/syscalls.h>
++#include <linux/jiffies.h>
+
+ #include <asm/uaccess.h>
+
+@@ -721,6 +722,7 @@ int __init add_preferred_console(char *n
+ return 0;
+ }
+
++#ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
+ /**
+ * suspend_console - suspend the console subsystem
+ *
+@@ -728,6 +730,7 @@ int __init add_preferred_console(char *n
+ */
+ void suspend_console(void)
+ {
++ printk("Suspending console(s)\n");
+ acquire_console_sem();
+ console_suspended = 1;
+ }
+@@ -737,6 +740,7 @@ void resume_console(void)
+ console_suspended = 0;
+ release_console_sem();
+ }
++#endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
+
+ /**
+ * acquire_console_sem - lock the console system for exclusive use.
+@@ -817,15 +821,8 @@ void release_console_sem(void)
+ console_locked = 0;
+ up(&console_sem);
+ spin_unlock_irqrestore(&logbuf_lock, flags);
+- if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) {
+- /*
+- * If we printk from within the lock dependency code,
+- * from within the scheduler code, then do not lock
+- * up due to self-recursion:
+- */
+- if (!lockdep_internal())
+- wake_up_interruptible(&log_wait);
+- }
++ if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
++ wake_up_interruptible(&log_wait);
+ }
+ EXPORT_SYMBOL(release_console_sem);
+
+@@ -1105,3 +1102,23 @@ int printk_ratelimit(void)
+ printk_ratelimit_burst);
+ }
+ EXPORT_SYMBOL(printk_ratelimit);
++
++/**
++ * printk_timed_ratelimit - caller-controlled printk ratelimiting
++ * @caller_jiffies: pointer to caller's state
++ * @interval_msecs: minimum interval between prints
++ *
++ * printk_timed_ratelimit() returns true if more than @interval_msecs
++ * milliseconds have elapsed since the last time printk_timed_ratelimit()
++ * returned true.
++ */
++bool printk_timed_ratelimit(unsigned long *caller_jiffies,
++ unsigned int interval_msecs)
++{
++ if (*caller_jiffies == 0 || time_after(jiffies, *caller_jiffies)) {
++ *caller_jiffies = jiffies + msecs_to_jiffies(interval_msecs);
++ return true;
++ }
++ return false;
++}
++EXPORT_SYMBOL(printk_timed_ratelimit);
+diff --git a/kernel/profile.c b/kernel/profile.c
+index d5bd75e..f940b46 100644
+--- a/kernel/profile.c
++++ b/kernel/profile.c
+@@ -25,6 +25,7 @@
+ #include <linux/mutex.h>
+ #include <asm/sections.h>
+ #include <asm/semaphore.h>
++#include <asm/irq_regs.h>
+
+ struct profile_hit {
+ u32 pc, hits;
+@@ -309,13 +310,17 @@ static int __devinit profile_cpu_callbac
+ node = cpu_to_node(cpu);
+ per_cpu(cpu_profile_flip, cpu) = 0;
+ if (!per_cpu(cpu_profile_hits, cpu)[1]) {
+- page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
++ page = alloc_pages_node(node,
++ GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
++ 0);
+ if (!page)
+ return NOTIFY_BAD;
+ per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
+ }
+ if (!per_cpu(cpu_profile_hits, cpu)[0]) {
+- page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
++ page = alloc_pages_node(node,
++ GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
++ 0);
+ if (!page)
+ goto out_free;
+ per_cpu(cpu_profile_hits, cpu)[0] = page_address(page);
+@@ -362,8 +367,10 @@ void profile_hit(int type, void *__pc)
+ }
+ #endif /* !CONFIG_SMP */
+
+-void profile_tick(int type, struct pt_regs *regs)
++void profile_tick(int type)
+ {
++ struct pt_regs *regs = get_irq_regs();
++
+ if (type == CPU_PROFILING && timer_hook)
+ timer_hook(regs);
+ if (!user_mode(regs) && cpu_isset(smp_processor_id(), prof_cpu_mask))
+@@ -392,7 +399,7 @@ static int prof_cpu_mask_write_proc (str
+ unsigned long full_count = count, err;
+ cpumask_t new_value;
+
+- err = cpumask_parse(buffer, count, new_value);
++ err = cpumask_parse_user(buffer, count, new_value);
+ if (err)
+ return err;
+
+@@ -491,12 +498,16 @@ static int __init create_hash_tables(voi
+ int node = cpu_to_node(cpu);
+ struct page *page;
+
+- page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
++ page = alloc_pages_node(node,
++ GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
++ 0);
+ if (!page)
+ goto out_cleanup;
+ per_cpu(cpu_profile_hits, cpu)[1]
+ = (struct profile_hit *)page_address(page);
+- page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
++ page = alloc_pages_node(node,
++ GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
++ 0);
+ if (!page)
+ goto out_cleanup;
+ per_cpu(cpu_profile_hits, cpu)[0]
+diff --git a/kernel/ptrace.c b/kernel/ptrace.c
+index 9a111f7..4d50e06 100644
+--- a/kernel/ptrace.c
++++ b/kernel/ptrace.c
+@@ -241,60 +241,6 @@ int ptrace_detach(struct task_struct *ch
+ return 0;
+ }
+
+-/*
+- * Access another process' address space.
+- * Source/target buffer must be kernel space,
+- * Do not walk the page table directly, use get_user_pages
+- */
+-
+-int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+-{
+- struct mm_struct *mm;
+- struct vm_area_struct *vma;
+- struct page *page;
+- void *old_buf = buf;
+-
+- mm = get_task_mm(tsk);
+- if (!mm)
+- return 0;
+-
+- down_read(&mm->mmap_sem);
+- /* ignore errors, just check how much was sucessfully transfered */
+- while (len) {
+- int bytes, ret, offset;
+- void *maddr;
+-
+- ret = get_user_pages(tsk, mm, addr, 1,
+- write, 1, &page, &vma);
+- if (ret <= 0)
+- break;
+-
+- bytes = len;
+- offset = addr & (PAGE_SIZE-1);
+- if (bytes > PAGE_SIZE-offset)
+- bytes = PAGE_SIZE-offset;
+-
+- maddr = kmap(page);
+- if (write) {
+- copy_to_user_page(vma, page, addr,
+- maddr + offset, buf, bytes);
+- set_page_dirty_lock(page);
+- } else {
+- copy_from_user_page(vma, page, addr,
+- buf, maddr + offset, bytes);
+- }
+- kunmap(page);
+- page_cache_release(page);
+- len -= bytes;
+- buf += bytes;
+- addr += bytes;
+- }
+- up_read(&mm->mmap_sem);
+- mmput(mm);
+-
+- return buf - old_buf;
+-}
+-
+ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
+ {
+ int copied = 0;
+@@ -494,6 +440,7 @@ struct task_struct *ptrace_get_task_stru
+ child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
++
+ read_unlock(&tasklist_lock);
+ if (!child)
+ return ERR_PTR(-ESRCH);
+diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
+index 523e464..26bb5ff 100644
+--- a/kernel/rcupdate.c
++++ b/kernel/rcupdate.c
+@@ -71,9 +71,6 @@ static DEFINE_PER_CPU(struct tasklet_str
+ static int blimit = 10;
+ static int qhimark = 10000;
+ static int qlowmark = 100;
+-#ifdef CONFIG_SMP
+-static int rsinterval = 1000;
+-#endif
+
+ static atomic_t rcu_barrier_cpu_count;
+ static DEFINE_MUTEX(rcu_barrier_mutex);
+@@ -86,8 +83,8 @@ static void force_quiescent_state(struct
+ int cpu;
+ cpumask_t cpumask;
+ set_need_resched();
+- if (unlikely(rdp->qlen - rdp->last_rs_qlen > rsinterval)) {
+- rdp->last_rs_qlen = rdp->qlen;
++ if (unlikely(!rcp->signaled)) {
++ rcp->signaled = 1;
+ /*
+ * Don't send IPI to itself. With irqs disabled,
+ * rdp->cpu is the current cpu.
+@@ -301,6 +298,7 @@ static void rcu_start_batch(struct rcu_c
+ smp_mb();
+ cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
+
++ rcp->signaled = 0;
+ }
+ }
+
+@@ -628,9 +626,6 @@ void synchronize_rcu(void)
+ module_param(blimit, int, 0);
+ module_param(qhimark, int, 0);
+ module_param(qlowmark, int, 0);
+-#ifdef CONFIG_SMP
+-module_param(rsinterval, int, 0);
+-#endif
+ EXPORT_SYMBOL_GPL(rcu_batches_completed);
+ EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
+ EXPORT_SYMBOL_GPL(call_rcu);
+diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
+index 4d1c3d2..e2bda18 100644
+--- a/kernel/rcutorture.c
++++ b/kernel/rcutorture.c
+@@ -15,9 +15,10 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+- * Copyright (C) IBM Corporation, 2005
++ * Copyright (C) IBM Corporation, 2005, 2006
+ *
+ * Authors: Paul E. McKenney <paulmck at us.ibm.com>
++ * Josh Triplett <josh at freedesktop.org>
+ *
+ * See also: Documentation/RCU/torture.txt
+ */
+@@ -44,19 +45,25 @@
+ #include <linux/delay.h>
+ #include <linux/byteorder/swabb.h>
+ #include <linux/stat.h>
++#include <linux/srcu.h>
+
+ MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Paul E. McKenney <paulmck at us.ibm.com> and "
++ "Josh Triplett <josh at freedesktop.org>");
+
+-static int nreaders = -1; /* # reader threads, defaults to 4*ncpus */
++static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */
++static int nfakewriters = 4; /* # fake writer threads */
+ static int stat_interval; /* Interval between stats, in seconds. */
+ /* Defaults to "only at end of test". */
+ static int verbose; /* Print more debug info. */
+ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
+ static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
+-static char *torture_type = "rcu"; /* What to torture. */
++static char *torture_type = "rcu"; /* What RCU implementation to torture. */
+
+ module_param(nreaders, int, 0);
+ MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
++module_param(nfakewriters, int, 0);
++MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
+ module_param(stat_interval, int, 0);
+ MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
+ module_param(verbose, bool, 0);
+@@ -66,7 +73,7 @@ MODULE_PARM_DESC(test_no_idle_hz, "Test
+ module_param(shuffle_interval, int, 0);
+ MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
+ module_param(torture_type, charp, 0);
+-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
++MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
+
+ #define TORTURE_FLAG "-torture:"
+ #define PRINTK_STRING(s) \
+@@ -80,6 +87,7 @@ static char printk_buf[4096];
+
+ static int nrealreaders;
+ static struct task_struct *writer_task;
++static struct task_struct **fakewriter_tasks;
+ static struct task_struct **reader_tasks;
+ static struct task_struct *stats_task;
+ static struct task_struct *shuffler_task;
+@@ -104,11 +112,12 @@ static DEFINE_PER_CPU(long [RCU_TORTURE_
+ static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
+ { 0 };
+ static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
+-atomic_t n_rcu_torture_alloc;
+-atomic_t n_rcu_torture_alloc_fail;
+-atomic_t n_rcu_torture_free;
+-atomic_t n_rcu_torture_mberror;
+-atomic_t n_rcu_torture_error;
++static atomic_t n_rcu_torture_alloc;
++static atomic_t n_rcu_torture_alloc_fail;
++static atomic_t n_rcu_torture_free;
++static atomic_t n_rcu_torture_mberror;
++static atomic_t n_rcu_torture_error;
++static struct list_head rcu_torture_removed;
+
+ /*
+ * Allocate an element from the rcu_tortures pool.
+@@ -145,7 +154,7 @@ rcu_torture_free(struct rcu_torture *p)
+
+ struct rcu_random_state {
+ unsigned long rrs_state;
+- unsigned long rrs_count;
++ long rrs_count;
+ };
+
+ #define RCU_RANDOM_MULT 39916801 /* prime */
+@@ -158,7 +167,7 @@ struct rcu_random_state {
+ * Crude but fast random-number generator. Uses a linear congruential
+ * generator, with occasional help from get_random_bytes().
+ */
+-static long
++static unsigned long
+ rcu_random(struct rcu_random_state *rrsp)
+ {
+ long refresh;
+@@ -180,9 +189,11 @@ struct rcu_torture_ops {
+ void (*init)(void);
+ void (*cleanup)(void);
+ int (*readlock)(void);
++ void (*readdelay)(struct rcu_random_state *rrsp);
+ void (*readunlock)(int idx);
+ int (*completed)(void);
+ void (*deferredfree)(struct rcu_torture *p);
++ void (*sync)(void);
+ int (*stats)(char *page);
+ char *name;
+ };
+@@ -192,13 +203,25 @@ static struct rcu_torture_ops *cur_ops =
+ * Definitions for rcu torture testing.
+ */
+
+-static int rcu_torture_read_lock(void)
++static int rcu_torture_read_lock(void) __acquires(RCU)
+ {
+ rcu_read_lock();
+ return 0;
+ }
+
+-static void rcu_torture_read_unlock(int idx)
++static void rcu_read_delay(struct rcu_random_state *rrsp)
++{
++ long delay;
++ const long longdelay = 200;
++
++ /* We want there to be long-running readers, but not all the time. */
++
++ delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay);
++ if (!delay)
++ udelay(longdelay);
++}
++
++static void rcu_torture_read_unlock(int idx) __releases(RCU)
+ {
+ rcu_read_unlock();
+ }
+@@ -239,24 +262,65 @@ static struct rcu_torture_ops rcu_ops =
+ .init = NULL,
+ .cleanup = NULL,
+ .readlock = rcu_torture_read_lock,
++ .readdelay = rcu_read_delay,
+ .readunlock = rcu_torture_read_unlock,
+ .completed = rcu_torture_completed,
+ .deferredfree = rcu_torture_deferred_free,
++ .sync = synchronize_rcu,
+ .stats = NULL,
+ .name = "rcu"
+ };
+
++static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
++{
++ int i;
++ struct rcu_torture *rp;
++ struct rcu_torture *rp1;
++
++ cur_ops->sync();
++ list_add(&p->rtort_free, &rcu_torture_removed);
++ list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
++ i = rp->rtort_pipe_count;
++ if (i > RCU_TORTURE_PIPE_LEN)
++ i = RCU_TORTURE_PIPE_LEN;
++ atomic_inc(&rcu_torture_wcount[i]);
++ if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
++ rp->rtort_mbtest = 0;
++ list_del(&rp->rtort_free);
++ rcu_torture_free(rp);
++ }
++ }
++}
++
++static void rcu_sync_torture_init(void)
++{
++ INIT_LIST_HEAD(&rcu_torture_removed);
++}
++
++static struct rcu_torture_ops rcu_sync_ops = {
++ .init = rcu_sync_torture_init,
++ .cleanup = NULL,
++ .readlock = rcu_torture_read_lock,
++ .readdelay = rcu_read_delay,
++ .readunlock = rcu_torture_read_unlock,
++ .completed = rcu_torture_completed,
++ .deferredfree = rcu_sync_torture_deferred_free,
++ .sync = synchronize_rcu,
++ .stats = NULL,
++ .name = "rcu_sync"
++};
++
+ /*
+ * Definitions for rcu_bh torture testing.
+ */
+
+-static int rcu_bh_torture_read_lock(void)
++static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
+ {
+ rcu_read_lock_bh();
+ return 0;
+ }
+
+-static void rcu_bh_torture_read_unlock(int idx)
++static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
+ {
+ rcu_read_unlock_bh();
+ }
+@@ -271,19 +335,176 @@ static void rcu_bh_torture_deferred_free
+ call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
+ }
+
++struct rcu_bh_torture_synchronize {
++ struct rcu_head head;
++ struct completion completion;
++};
++
++static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
++{
++ struct rcu_bh_torture_synchronize *rcu;
++
++ rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
++ complete(&rcu->completion);
++}
++
++static void rcu_bh_torture_synchronize(void)
++{
++ struct rcu_bh_torture_synchronize rcu;
++
++ init_completion(&rcu.completion);
++ call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
++ wait_for_completion(&rcu.completion);
++}
++
+ static struct rcu_torture_ops rcu_bh_ops = {
+ .init = NULL,
+ .cleanup = NULL,
+ .readlock = rcu_bh_torture_read_lock,
++ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = rcu_bh_torture_read_unlock,
+ .completed = rcu_bh_torture_completed,
+ .deferredfree = rcu_bh_torture_deferred_free,
++ .sync = rcu_bh_torture_synchronize,
+ .stats = NULL,
+ .name = "rcu_bh"
+ };
+
++static struct rcu_torture_ops rcu_bh_sync_ops = {
++ .init = rcu_sync_torture_init,
++ .cleanup = NULL,
++ .readlock = rcu_bh_torture_read_lock,
++ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
++ .readunlock = rcu_bh_torture_read_unlock,
++ .completed = rcu_bh_torture_completed,
++ .deferredfree = rcu_sync_torture_deferred_free,
++ .sync = rcu_bh_torture_synchronize,
++ .stats = NULL,
++ .name = "rcu_bh_sync"
++};
++
++/*
++ * Definitions for srcu torture testing.
++ */
++
++static struct srcu_struct srcu_ctl;
++
++static void srcu_torture_init(void)
++{
++ init_srcu_struct(&srcu_ctl);
++ rcu_sync_torture_init();
++}
++
++static void srcu_torture_cleanup(void)
++{
++ synchronize_srcu(&srcu_ctl);
++ cleanup_srcu_struct(&srcu_ctl);
++}
++
++static int srcu_torture_read_lock(void)
++{
++ return srcu_read_lock(&srcu_ctl);
++}
++
++static void srcu_read_delay(struct rcu_random_state *rrsp)
++{
++ long delay;
++ const long uspertick = 1000000 / HZ;
++ const long longdelay = 10;
++
++ /* We want there to be long-running readers, but not all the time. */
++
++ delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
++ if (!delay)
++ schedule_timeout_interruptible(longdelay);
++}
++
++static void srcu_torture_read_unlock(int idx)
++{
++ srcu_read_unlock(&srcu_ctl, idx);
++}
++
++static int srcu_torture_completed(void)
++{
++ return srcu_batches_completed(&srcu_ctl);
++}
++
++static void srcu_torture_synchronize(void)
++{
++ synchronize_srcu(&srcu_ctl);
++}
++
++static int srcu_torture_stats(char *page)
++{
++ int cnt = 0;
++ int cpu;
++ int idx = srcu_ctl.completed & 0x1;
++
++ cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):",
++ torture_type, TORTURE_FLAG, idx);
++ for_each_possible_cpu(cpu) {
++ cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu,
++ per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
++ per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
++ }
++ cnt += sprintf(&page[cnt], "\n");
++ return cnt;
++}
++
++static struct rcu_torture_ops srcu_ops = {
++ .init = srcu_torture_init,
++ .cleanup = srcu_torture_cleanup,
++ .readlock = srcu_torture_read_lock,
++ .readdelay = srcu_read_delay,
++ .readunlock = srcu_torture_read_unlock,
++ .completed = srcu_torture_completed,
++ .deferredfree = rcu_sync_torture_deferred_free,
++ .sync = srcu_torture_synchronize,
++ .stats = srcu_torture_stats,
++ .name = "srcu"
++};
++
++/*
++ * Definitions for sched torture testing.
++ */
++
++static int sched_torture_read_lock(void)
++{
++ preempt_disable();
++ return 0;
++}
++
++static void sched_torture_read_unlock(int idx)
++{
++ preempt_enable();
++}
++
++static int sched_torture_completed(void)
++{
++ return 0;
++}
++
++static void sched_torture_synchronize(void)
++{
++ synchronize_sched();
++}
++
++static struct rcu_torture_ops sched_ops = {
++ .init = rcu_sync_torture_init,
++ .cleanup = NULL,
++ .readlock = sched_torture_read_lock,
++ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
++ .readunlock = sched_torture_read_unlock,
++ .completed = sched_torture_completed,
++ .deferredfree = rcu_sync_torture_deferred_free,
++ .sync = sched_torture_synchronize,
++ .stats = NULL,
++ .name = "sched"
++};
++
+ static struct rcu_torture_ops *torture_ops[] =
+- { &rcu_ops, &rcu_bh_ops, NULL };
++ { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops,
++ &sched_ops, NULL };
+
+ /*
+ * RCU torture writer kthread. Repeatedly substitutes a new structure
+@@ -330,6 +551,30 @@ rcu_torture_writer(void *arg)
+ }
+
+ /*
++ * RCU torture fake writer kthread. Repeatedly calls sync, with a random
++ * delay between calls.
++ */
++static int
++rcu_torture_fakewriter(void *arg)
++{
++ DEFINE_RCU_RANDOM(rand);
++
++ VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
++ set_user_nice(current, 19);
++
++ do {
++ schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
++ udelay(rcu_random(&rand) & 0x3ff);
++ cur_ops->sync();
++ } while (!kthread_should_stop() && !fullstop);
++
++ VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
++ while (!kthread_should_stop())
++ schedule_timeout_uninterruptible(1);
++ return 0;
++}
++
++/*
+ * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
+ * incrementing the corresponding element of the pipeline array. The
+ * counter in the element should never be greater than 1, otherwise, the
+@@ -359,7 +604,7 @@ rcu_torture_reader(void *arg)
+ }
+ if (p->rtort_mbtest == 0)
+ atomic_inc(&n_rcu_torture_mberror);
+- udelay(rcu_random(&rand) & 0x7f);
++ cur_ops->readdelay(&rand);
+ preempt_disable();
+ pipe_count = p->rtort_pipe_count;
+ if (pipe_count > RCU_TORTURE_PIPE_LEN) {
+@@ -483,7 +728,7 @@ static int rcu_idle_cpu; /* Force all to
+ /* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
+ * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
+ */
+-void rcu_torture_shuffle_tasks(void)
++static void rcu_torture_shuffle_tasks(void)
+ {
+ cpumask_t tmp_mask = CPU_MASK_ALL;
+ int i;
+@@ -507,6 +752,12 @@ void rcu_torture_shuffle_tasks(void)
+ set_cpus_allowed(reader_tasks[i], tmp_mask);
+ }
+
++ if (fakewriter_tasks != NULL) {
++ for (i = 0; i < nfakewriters; i++)
++ if (fakewriter_tasks[i])
++ set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
++ }
++
+ if (writer_task)
+ set_cpus_allowed(writer_task, tmp_mask);
+
+@@ -540,11 +791,12 @@ rcu_torture_shuffle(void *arg)
+ static inline void
+ rcu_torture_print_module_parms(char *tag)
+ {
+- printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
++ printk(KERN_ALERT "%s" TORTURE_FLAG
++ "--- %s: nreaders=%d nfakewriters=%d "
+ "stat_interval=%d verbose=%d test_no_idle_hz=%d "
+ "shuffle_interval = %d\n",
+- torture_type, tag, nrealreaders, stat_interval, verbose,
+- test_no_idle_hz, shuffle_interval);
++ torture_type, tag, nrealreaders, nfakewriters,
++ stat_interval, verbose, test_no_idle_hz, shuffle_interval);
+ }
+
+ static void
+@@ -579,6 +831,19 @@ rcu_torture_cleanup(void)
+ }
+ rcu_torture_current = NULL;
+
++ if (fakewriter_tasks != NULL) {
++ for (i = 0; i < nfakewriters; i++) {
++ if (fakewriter_tasks[i] != NULL) {
++ VERBOSE_PRINTK_STRING(
++ "Stopping rcu_torture_fakewriter task");
++ kthread_stop(fakewriter_tasks[i]);
++ }
++ fakewriter_tasks[i] = NULL;
++ }
++ kfree(fakewriter_tasks);
++ fakewriter_tasks = NULL;
++ }
++
+ if (stats_task != NULL) {
+ VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
+ kthread_stop(stats_task);
+@@ -666,7 +931,25 @@ rcu_torture_init(void)
+ writer_task = NULL;
+ goto unwind;
+ }
+- reader_tasks = kmalloc(nrealreaders * sizeof(reader_tasks[0]),
++ fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
++ GFP_KERNEL);
++ if (fakewriter_tasks == NULL) {
++ VERBOSE_PRINTK_ERRSTRING("out of memory");
++ firsterr = -ENOMEM;
++ goto unwind;
++ }
++ for (i = 0; i < nfakewriters; i++) {
++ VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
++ fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
++ "rcu_torture_fakewriter");
++ if (IS_ERR(fakewriter_tasks[i])) {
++ firsterr = PTR_ERR(fakewriter_tasks[i]);
++ VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
++ fakewriter_tasks[i] = NULL;
++ goto unwind;
++ }
++ }
++ reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
+ GFP_KERNEL);
+ if (reader_tasks == NULL) {
+ VERBOSE_PRINTK_ERRSTRING("out of memory");
+diff --git a/kernel/relay.c b/kernel/relay.c
+index 33345e7..f04bbdb 100644
+--- a/kernel/relay.c
++++ b/kernel/relay.c
+@@ -95,7 +95,7 @@ int relay_mmap_buf(struct rchan_buf *buf
+ * @buf: the buffer struct
+ * @size: total size of the buffer
+ *
+- * Returns a pointer to the resulting buffer, NULL if unsuccessful. The
++ * Returns a pointer to the resulting buffer, %NULL if unsuccessful. The
+ * passed in size will get page aligned, if it isn't already.
+ */
+ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
+@@ -132,10 +132,9 @@ depopulate:
+
+ /**
+ * relay_create_buf - allocate and initialize a channel buffer
+- * @alloc_size: size of the buffer to allocate
+- * @n_subbufs: number of sub-buffers in the channel
++ * @chan: the relay channel
+ *
+- * Returns channel buffer if successful, NULL otherwise
++ * Returns channel buffer if successful, %NULL otherwise.
+ */
+ struct rchan_buf *relay_create_buf(struct rchan *chan)
+ {
+@@ -163,6 +162,7 @@ free_buf:
+
+ /**
+ * relay_destroy_channel - free the channel struct
++ * @kref: target kernel reference that contains the relay channel
+ *
+ * Should only be called from kref_put().
+ */
+@@ -194,6 +194,7 @@ void relay_destroy_buf(struct rchan_buf
+
+ /**
+ * relay_remove_buf - remove a channel buffer
++ * @kref: target kernel reference that contains the relay buffer
+ *
+ * Removes the file from the fileystem, which also frees the
+ * rchan_buf_struct and the channel buffer. Should only be called from
+@@ -374,7 +375,7 @@ void relay_reset(struct rchan *chan)
+ }
+ EXPORT_SYMBOL_GPL(relay_reset);
+
+-/**
++/*
+ * relay_open_buf - create a new relay channel buffer
+ *
+ * Internal - used by relay_open().
+@@ -448,12 +449,12 @@ static inline void setup_callbacks(struc
+ /**
+ * relay_open - create a new relay channel
+ * @base_filename: base name of files to create
+- * @parent: dentry of parent directory, NULL for root directory
++ * @parent: dentry of parent directory, %NULL for root directory
+ * @subbuf_size: size of sub-buffers
+ * @n_subbufs: number of sub-buffers
+ * @cb: client callback functions
+ *
+- * Returns channel pointer if successful, NULL otherwise.
++ * Returns channel pointer if successful, %NULL otherwise.
+ *
+ * Creates a channel buffer for each cpu using the sizes and
+ * attributes specified. The created channel buffer files
+@@ -585,7 +586,7 @@ EXPORT_SYMBOL_GPL(relay_switch_subbuf);
+ * subbufs_consumed should be the number of sub-buffers newly consumed,
+ * not the total consumed.
+ *
+- * NOTE: kernel clients don't need to call this function if the channel
++ * NOTE: Kernel clients don't need to call this function if the channel
+ * mode is 'overwrite'.
+ */
+ void relay_subbufs_consumed(struct rchan *chan,
+@@ -641,7 +642,7 @@ EXPORT_SYMBOL_GPL(relay_close);
+ * relay_flush - close the channel
+ * @chan: the channel
+ *
+- * Flushes all channel buffers i.e. forces buffer switch.
++ * Flushes all channel buffers, i.e. forces buffer switch.
+ */
+ void relay_flush(struct rchan *chan)
+ {
+@@ -669,7 +670,7 @@ EXPORT_SYMBOL_GPL(relay_flush);
+ */
+ static int relay_file_open(struct inode *inode, struct file *filp)
+ {
+- struct rchan_buf *buf = inode->u.generic_ip;
++ struct rchan_buf *buf = inode->i_private;
+ kref_get(&buf->kref);
+ filp->private_data = buf;
+
+@@ -729,7 +730,7 @@ static int relay_file_release(struct ino
+ return 0;
+ }
+
+-/**
++/*
+ * relay_file_read_consume - update the consumed count for the buffer
+ */
+ static void relay_file_read_consume(struct rchan_buf *buf,
+@@ -756,7 +757,7 @@ static void relay_file_read_consume(stru
+ }
+ }
+
+-/**
++/*
+ * relay_file_read_avail - boolean, are there unconsumed bytes available?
+ */
+ static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos)
+@@ -793,6 +794,8 @@ static int relay_file_read_avail(struct
+
+ /**
+ * relay_file_read_subbuf_avail - return bytes available in sub-buffer
++ * @read_pos: file read position
++ * @buf: relay channel buffer
+ */
+ static size_t relay_file_read_subbuf_avail(size_t read_pos,
+ struct rchan_buf *buf)
+@@ -818,6 +821,8 @@ static size_t relay_file_read_subbuf_ava
+
+ /**
+ * relay_file_read_start_pos - find the first available byte to read
++ * @read_pos: file read position
++ * @buf: relay channel buffer
+ *
+ * If the read_pos is in the middle of padding, return the
+ * position of the first actually available byte, otherwise
+@@ -844,6 +849,9 @@ static size_t relay_file_read_start_pos(
+
+ /**
+ * relay_file_read_end_pos - return the new read position
++ * @read_pos: file read position
++ * @buf: relay channel buffer
++ * @count: number of bytes to be read
+ */
+ static size_t relay_file_read_end_pos(struct rchan_buf *buf,
+ size_t read_pos,
+@@ -865,7 +873,7 @@ static size_t relay_file_read_end_pos(st
+ return end_pos;
+ }
+
+-/**
++/*
+ * subbuf_read_actor - read up to one subbuf's worth of data
+ */
+ static int subbuf_read_actor(size_t read_start,
+@@ -879,7 +887,7 @@ static int subbuf_read_actor(size_t read
+
+ from = buf->start + read_start;
+ ret = avail;
+- if (copy_to_user(desc->arg.data, from, avail)) {
++ if (copy_to_user(desc->arg.buf, from, avail)) {
+ desc->error = -EFAULT;
+ ret = 0;
+ }
+@@ -890,7 +898,7 @@ static int subbuf_read_actor(size_t read
+ return ret;
+ }
+
+-/**
++/*
+ * subbuf_send_actor - send up to one subbuf's worth of data
+ */
+ static int subbuf_send_actor(size_t read_start,
+@@ -933,29 +941,22 @@ typedef int (*subbuf_actor_t) (size_t re
+ read_descriptor_t *desc,
+ read_actor_t actor);
+
+-/**
++/*
+ * relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
+ */
+ static inline ssize_t relay_file_read_subbufs(struct file *filp,
+ loff_t *ppos,
+- size_t count,
+ subbuf_actor_t subbuf_actor,
+ read_actor_t actor,
+- void *target)
++ read_descriptor_t *desc)
+ {
+ struct rchan_buf *buf = filp->private_data;
+ size_t read_start, avail;
+- read_descriptor_t desc;
+ int ret;
+
+- if (!count)
++ if (!desc->count)
+ return 0;
+
+- desc.written = 0;
+- desc.count = count;
+- desc.arg.data = target;
+- desc.error = 0;
+-
+ mutex_lock(&filp->f_dentry->d_inode->i_mutex);
+ do {
+ if (!relay_file_read_avail(buf, *ppos))
+@@ -966,19 +967,19 @@ static inline ssize_t relay_file_read_su
+ if (!avail)
+ break;
+
+- avail = min(desc.count, avail);
+- ret = subbuf_actor(read_start, buf, avail, &desc, actor);
+- if (desc.error < 0)
++ avail = min(desc->count, avail);
++ ret = subbuf_actor(read_start, buf, avail, desc, actor);
++ if (desc->error < 0)
+ break;
+
+ if (ret) {
+ relay_file_read_consume(buf, read_start, ret);
+ *ppos = relay_file_read_end_pos(buf, read_start, ret);
+ }
+- } while (desc.count && ret);
++ } while (desc->count && ret);
+ mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
+
+- return desc.written;
++ return desc->written;
+ }
+
+ static ssize_t relay_file_read(struct file *filp,
+@@ -986,8 +987,13 @@ static ssize_t relay_file_read(struct fi
+ size_t count,
+ loff_t *ppos)
+ {
+- return relay_file_read_subbufs(filp, ppos, count, subbuf_read_actor,
+- NULL, buffer);
++ read_descriptor_t desc;
++ desc.written = 0;
++ desc.count = count;
++ desc.arg.buf = buffer;
++ desc.error = 0;
++ return relay_file_read_subbufs(filp, ppos, subbuf_read_actor,
++ NULL, &desc);
+ }
+
+ static ssize_t relay_file_sendfile(struct file *filp,
+@@ -996,8 +1002,13 @@ static ssize_t relay_file_sendfile(struc
+ read_actor_t actor,
+ void *target)
+ {
+- return relay_file_read_subbufs(filp, ppos, count, subbuf_send_actor,
+- actor, target);
++ read_descriptor_t desc;
++ desc.written = 0;
++ desc.count = count;
++ desc.arg.data = target;
++ desc.error = 0;
++ return relay_file_read_subbufs(filp, ppos, subbuf_send_actor,
++ actor, &desc);
+ }
+
+ struct file_operations relay_file_operations = {
+diff --git a/kernel/resource.c b/kernel/resource.c
+index 4628643..6de60c1 100644
+--- a/kernel/resource.c
++++ b/kernel/resource.c
+@@ -193,6 +193,13 @@ static int __release_resource(struct res
+ return -EINVAL;
+ }
+
++/**
++ * request_resource - request and reserve an I/O or memory resource
++ * @root: root resource descriptor
++ * @new: resource descriptor desired by caller
++ *
++ * Returns 0 for success, negative error code on error.
++ */
+ int request_resource(struct resource *root, struct resource *new)
+ {
+ struct resource *conflict;
+@@ -205,6 +212,15 @@ int request_resource(struct resource *ro
+
+ EXPORT_SYMBOL(request_resource);
+
++/**
++ * ____request_resource - reserve a resource, with resource conflict returned
++ * @root: root resource descriptor
++ * @new: resource descriptor desired by caller
++ *
++ * Returns:
++ * On success, NULL is returned.
++ * On error, a pointer to the conflicting resource is returned.
++ */
+ struct resource *____request_resource(struct resource *root, struct resource *new)
+ {
+ struct resource *conflict;
+@@ -217,6 +233,10 @@ struct resource *____request_resource(st
+
+ EXPORT_SYMBOL(____request_resource);
+
++/**
++ * release_resource - release a previously reserved resource
++ * @old: resource pointer
++ */
+ int release_resource(struct resource *old)
+ {
+ int retval;
+@@ -315,8 +335,16 @@ static int find_resource(struct resource
+ return -EBUSY;
+ }
+
+-/*
+- * Allocate empty slot in the resource tree given range and alignment.
++/**
++ * allocate_resource - allocate empty slot in the resource tree given range & alignment
++ * @root: root resource descriptor
++ * @new: resource descriptor desired by caller
++ * @size: requested resource region size
++ * @min: minimum size to allocate
++ * @max: maximum size to allocate
++ * @align: alignment requested, in bytes
++ * @alignf: alignment function, optional, called if not NULL
++ * @alignf_data: arbitrary data to pass to the @alignf function
+ */
+ int allocate_resource(struct resource *root, struct resource *new,
+ resource_size_t size, resource_size_t min,
+@@ -344,12 +372,11 @@ EXPORT_SYMBOL(allocate_resource);
+ *
+ * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+- * This function is equivalent of request_resource when no conflict
++ * This function is equivalent to request_resource when no conflict
+ * happens. If a conflict happens, and the conflicting resources
+ * entirely fit within the range of the new resource, then the new
+- * resource is inserted and the conflicting resources become childs of
+- * the new resource. Otherwise the new resource becomes the child of
+- * the conflicting resource
++ * resource is inserted and the conflicting resources become children of
++ * the new resource.
+ */
+ int insert_resource(struct resource *parent, struct resource *new)
+ {
+@@ -357,20 +384,21 @@ int insert_resource(struct resource *par
+ struct resource *first, *next;
+
+ write_lock(&resource_lock);
+- begin:
+- result = 0;
+- first = __request_resource(parent, new);
+- if (!first)
+- goto out;
+
+- result = -EBUSY;
+- if (first == parent)
+- goto out;
++ for (;; parent = first) {
++ result = 0;
++ first = __request_resource(parent, new);
++ if (!first)
++ goto out;
+
+- /* Resource fully contained by the clashing resource? Recurse into it */
+- if (first->start <= new->start && first->end >= new->end) {
+- parent = first;
+- goto begin;
++ result = -EBUSY;
++ if (first == parent)
++ goto out;
++
++ if ((first->start > new->start) || (first->end < new->end))
++ break;
++ if ((first->start == new->start) && (first->end == new->end))
++ break;
+ }
+
+ for (next = first; ; next = next->sibling) {
+@@ -407,10 +435,15 @@ int insert_resource(struct resource *par
+ return result;
+ }
+
+-/*
++/**
++ * adjust_resource - modify a resource's start and size
++ * @res: resource to modify
++ * @start: new start value
++ * @size: new size
++ *
+ * Given an existing resource, change its start and size to match the
+- * arguments. Returns -EBUSY if it can't fit. Existing children of
+- * the resource are assumed to be immutable.
++ * arguments. Returns 0 on success, -EBUSY if it can't fit.
++ * Existing children of the resource are assumed to be immutable.
+ */
+ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size)
+ {
+@@ -456,11 +489,19 @@ EXPORT_SYMBOL(adjust_resource);
+ * Note how this, unlike the above, knows about
+ * the IO flag meanings (busy etc).
+ *
+- * Request-region creates a new busy region.
++ * request_region creates a new busy region.
+ *
+- * Check-region returns non-zero if the area is already busy
++ * check_region returns non-zero if the area is already busy.
+ *
+- * Release-region releases a matching busy region.
++ * release_region releases a matching busy region.
++ */
++
++/**
++ * __request_region - create a new busy resource region
++ * @parent: parent resource descriptor
++ * @start: resource start address
++ * @n: resource region size
++ * @name: reserving caller's ID string
+ */
+ struct resource * __request_region(struct resource *parent,
+ resource_size_t start, resource_size_t n,
+@@ -497,9 +538,23 @@ struct resource * __request_region(struc
+ }
+ return res;
+ }
+-
+ EXPORT_SYMBOL(__request_region);
+
++/**
++ * __check_region - check if a resource region is busy or free
++ * @parent: parent resource descriptor
++ * @start: resource start address
++ * @n: resource region size
++ *
++ * Returns 0 if the region is free at the moment it is checked,
++ * returns %-EBUSY if the region is busy.
++ *
++ * NOTE:
++ * This function is deprecated because its use is racy.
++ * Even if it returns 0, a subsequent call to request_region()
++ * may fail because another driver etc. just allocated the region.
++ * Do NOT use it. It will be removed from the kernel.
++ */
+ int __check_region(struct resource *parent, resource_size_t start,
+ resource_size_t n)
+ {
+@@ -513,9 +568,16 @@ int __check_region(struct resource *pare
+ kfree(res);
+ return 0;
+ }
+-
+ EXPORT_SYMBOL(__check_region);
+
++/**
++ * __release_region - release a previously reserved resource region
++ * @parent: parent resource descriptor
++ * @start: resource start address
++ * @n: resource region size
++ *
++ * The described resource region must match a currently busy region.
++ */
+ void __release_region(struct resource *parent, resource_size_t start,
+ resource_size_t n)
+ {
+@@ -553,7 +615,6 @@ void __release_region(struct resource *p
+ "<%016llx-%016llx>\n", (unsigned long long)start,
+ (unsigned long long)end);
+ }
+-
+ EXPORT_SYMBOL(__release_region);
+
+ /*
+diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c
+index 0c1faa9..da8d6bf 100644
+--- a/kernel/rtmutex-debug.c
++++ b/kernel/rtmutex-debug.c
+@@ -16,7 +16,6 @@
+ *
+ * See rt.c in preempt-rt for proper credits and further information
+ */
+-#include <linux/config.h>
+ #include <linux/sched.h>
+ #include <linux/delay.h>
+ #include <linux/module.h>
+diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
+index 948bd8f..6dcea9d 100644
+--- a/kernel/rtmutex-tester.c
++++ b/kernel/rtmutex-tester.c
+@@ -6,7 +6,6 @@
+ * Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx at timesys.com>
+ *
+ */
+-#include <linux/config.h>
+ #include <linux/kthread.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
+index 3e13a1e..4ab17da 100644
+--- a/kernel/rtmutex.c
++++ b/kernel/rtmutex.c
+@@ -251,6 +251,7 @@ static int rt_mutex_adjust_prio_chain(st
+
+ /* Grab the next task */
+ task = rt_mutex_owner(lock);
++ get_task_struct(task);
+ spin_lock_irqsave(&task->pi_lock, flags);
+
+ if (waiter == rt_mutex_top_waiter(lock)) {
+@@ -269,7 +270,6 @@ static int rt_mutex_adjust_prio_chain(st
+ __rt_mutex_adjust_prio(task);
+ }
+
+- get_task_struct(task);
+ spin_unlock_irqrestore(&task->pi_lock, flags);
+
+ top_waiter = rt_mutex_top_waiter(lock);
+@@ -409,7 +409,7 @@ static int task_blocks_on_rt_mutex(struc
+ struct task_struct *owner = rt_mutex_owner(lock);
+ struct rt_mutex_waiter *top_waiter = waiter;
+ unsigned long flags;
+- int boost = 0, res;
++ int chain_walk = 0, res;
+
+ spin_lock_irqsave(¤t->pi_lock, flags);
+ __rt_mutex_adjust_prio(current);
+@@ -433,25 +433,23 @@ static int task_blocks_on_rt_mutex(struc
+ plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
+
+ __rt_mutex_adjust_prio(owner);
+- if (owner->pi_blocked_on) {
+- boost = 1;
+- /* gets dropped in rt_mutex_adjust_prio_chain()! */
+- get_task_struct(owner);
+- }
+- spin_unlock_irqrestore(&owner->pi_lock, flags);
+- }
+- else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
+- spin_lock_irqsave(&owner->pi_lock, flags);
+- if (owner->pi_blocked_on) {
+- boost = 1;
+- /* gets dropped in rt_mutex_adjust_prio_chain()! */
+- get_task_struct(owner);
+- }
++ if (owner->pi_blocked_on)
++ chain_walk = 1;
+ spin_unlock_irqrestore(&owner->pi_lock, flags);
+ }
+- if (!boost)
++ else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock))
++ chain_walk = 1;
++
++ if (!chain_walk)
+ return 0;
+
++ /*
++ * The owner can't disappear while holding a lock,
++ * so the owner struct is protected by wait_lock.
++ * Gets dropped in rt_mutex_adjust_prio_chain()!
++ */
++ get_task_struct(owner);
++
+ spin_unlock(&lock->wait_lock);
+
+ res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
+@@ -532,7 +530,7 @@ static void remove_waiter(struct rt_mute
+ int first = (waiter == rt_mutex_top_waiter(lock));
+ struct task_struct *owner = rt_mutex_owner(lock);
+ unsigned long flags;
+- int boost = 0;
++ int chain_walk = 0;
+
+ spin_lock_irqsave(¤t->pi_lock, flags);
+ plist_del(&waiter->list_entry, &lock->wait_list);
+@@ -554,19 +552,20 @@ static void remove_waiter(struct rt_mute
+ }
+ __rt_mutex_adjust_prio(owner);
+
+- if (owner->pi_blocked_on) {
+- boost = 1;
+- /* gets dropped in rt_mutex_adjust_prio_chain()! */
+- get_task_struct(owner);
+- }
++ if (owner->pi_blocked_on)
++ chain_walk = 1;
++
+ spin_unlock_irqrestore(&owner->pi_lock, flags);
+ }
+
+ WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
+
+- if (!boost)
++ if (!chain_walk)
+ return;
+
++ /* gets dropped in rt_mutex_adjust_prio_chain()! */
++ get_task_struct(owner);
++
+ spin_unlock(&lock->wait_lock);
+
+ rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current);
+@@ -592,10 +591,10 @@ void rt_mutex_adjust_pi(struct task_stru
+ return;
+ }
+
+- /* gets dropped in rt_mutex_adjust_prio_chain()! */
+- get_task_struct(task);
+ spin_unlock_irqrestore(&task->pi_lock, flags);
+
++ /* gets dropped in rt_mutex_adjust_prio_chain()! */
++ get_task_struct(task);
+ rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task);
+ }
+
+diff --git a/kernel/sched.c b/kernel/sched.c
+index a234fbe..3399701 100644
+--- a/kernel/sched.c
++++ b/kernel/sched.c
+@@ -49,7 +49,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/syscalls.h>
+ #include <linux/times.h>
+-#include <linux/acct.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/kprobes.h>
+ #include <linux/delayacct.h>
+ #include <asm/tlb.h>
+@@ -160,15 +160,6 @@
+ #define TASK_PREEMPTS_CURR(p, rq) \
+ ((p)->prio < (rq)->curr->prio)
+
+-/*
+- * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
+- * to time slice values: [800ms ... 100ms ... 5ms]
+- *
+- * The higher a thread's priority, the bigger timeslices
+- * it gets during one round of execution. But even the lowest
+- * priority thread gets MIN_TIMESLICE worth of execution time.
+- */
+-
+ #define SCALE_PRIO(x, prio) \
+ max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
+
+@@ -180,6 +171,15 @@ static unsigned int static_prio_timeslic
+ return SCALE_PRIO(DEF_TIMESLICE, static_prio);
+ }
+
++/*
++ * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
++ * to time slice values: [800ms ... 100ms ... 5ms]
++ *
++ * The higher a thread's priority, the bigger timeslices
++ * it gets during one round of execution. But even the lowest
++ * priority thread gets MIN_TIMESLICE worth of execution time.
++ */
++
+ static inline unsigned int task_timeslice(struct task_struct *p)
+ {
+ return static_prio_timeslice(p->static_prio);
+@@ -238,6 +238,7 @@ struct rq {
+ /* For active balancing */
+ int active_balance;
+ int push_cpu;
++ int cpu; /* cpu of this runqueue */
+
+ struct task_struct *migration_thread;
+ struct list_head migration_queue;
+@@ -267,6 +268,15 @@ struct rq {
+
+ static DEFINE_PER_CPU(struct rq, runqueues);
+
++static inline int cpu_of(struct rq *rq)
++{
++#ifdef CONFIG_SMP
++ return rq->cpu;
++#else
++ return 0;
++#endif
++}
++
+ /*
+ * The domain tree (rq->sd) is protected by RCU's quiescent state transition.
+ * See detach_destroy_domains: synchronize_sched for details.
+@@ -1222,7 +1232,7 @@ nextgroup:
+ }
+
+ /*
+- * find_idlest_queue - find the idlest runqueue among the cpus in group.
++ * find_idlest_cpu - find the idlest cpu among the cpus in group.
+ */
+ static int
+ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
+@@ -1276,21 +1286,29 @@ static int sched_balance_self(int cpu, i
+ while (sd) {
+ cpumask_t span;
+ struct sched_group *group;
+- int new_cpu;
+- int weight;
++ int new_cpu, weight;
++
++ if (!(sd->flags & flag)) {
++ sd = sd->child;
++ continue;
++ }
+
+ span = sd->span;
+ group = find_idlest_group(sd, t, cpu);
+- if (!group)
+- goto nextlevel;
++ if (!group) {
++ sd = sd->child;
++ continue;
++ }
+
+ new_cpu = find_idlest_cpu(group, t, cpu);
+- if (new_cpu == -1 || new_cpu == cpu)
+- goto nextlevel;
++ if (new_cpu == -1 || new_cpu == cpu) {
++ /* Now try balancing at a lower domain level of cpu */
++ sd = sd->child;
++ continue;
++ }
+
+- /* Now try balancing at a lower domain level */
++ /* Now try balancing at a lower domain level of new_cpu */
+ cpu = new_cpu;
+-nextlevel:
+ sd = NULL;
+ weight = cpus_weight(span);
+ for_each_domain(cpu, tmp) {
+@@ -1745,27 +1763,27 @@ static inline void finish_task_switch(st
+ __releases(rq->lock)
+ {
+ struct mm_struct *mm = rq->prev_mm;
+- unsigned long prev_task_flags;
++ long prev_state;
+
+ rq->prev_mm = NULL;
+
+ /*
+ * A task struct has one reference for the use as "current".
+- * If a task dies, then it sets EXIT_ZOMBIE in tsk->exit_state and
+- * calls schedule one last time. The schedule call will never return,
+- * and the scheduled task must drop that reference.
+- * The test for EXIT_ZOMBIE must occur while the runqueue locks are
++ * If a task dies, then it sets TASK_DEAD in tsk->state and calls
++ * schedule one last time. The schedule call will never return, and
++ * the scheduled task must drop that reference.
++ * The test for TASK_DEAD must occur while the runqueue locks are
+ * still held, otherwise prev could be scheduled on another cpu, die
+ * there before we look at prev->state, and then the reference would
+ * be dropped twice.
+ * Manfred Spraul <manfred at colorfullife.com>
+ */
+- prev_task_flags = prev->flags;
++ prev_state = prev->state;
+ finish_arch_switch(prev);
+ finish_lock_switch(rq, prev);
+ if (mm)
+ mmdrop(mm);
+- if (unlikely(prev_task_flags & PF_DEAD)) {
++ if (unlikely(prev_state == TASK_DEAD)) {
+ /*
+ * Remove function-return probe instances associated with this
+ * task and put them back on the free list.
+@@ -1804,14 +1822,14 @@ context_switch(struct rq *rq, struct tas
+ struct mm_struct *mm = next->mm;
+ struct mm_struct *oldmm = prev->active_mm;
+
+- if (unlikely(!mm)) {
++ if (!mm) {
+ next->active_mm = oldmm;
+ atomic_inc(&oldmm->mm_count);
+ enter_lazy_tlb(oldmm, next);
+ } else
+ switch_mm(oldmm, mm, next);
+
+- if (unlikely(!prev->mm)) {
++ if (!prev->mm) {
+ prev->active_mm = NULL;
+ WARN_ON(rq->prev_mm);
+ rq->prev_mm = oldmm;
+@@ -2211,7 +2229,8 @@ out:
+ */
+ static struct sched_group *
+ find_busiest_group(struct sched_domain *sd, int this_cpu,
+- unsigned long *imbalance, enum idle_type idle, int *sd_idle)
++ unsigned long *imbalance, enum idle_type idle, int *sd_idle,
++ cpumask_t *cpus)
+ {
+ struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
+ unsigned long max_load, avg_load, total_load, this_load, total_pwr;
+@@ -2248,7 +2267,12 @@ find_busiest_group(struct sched_domain *
+ sum_weighted_load = sum_nr_running = avg_load = 0;
+
+ for_each_cpu_mask(i, group->cpumask) {
+- struct rq *rq = cpu_rq(i);
++ struct rq *rq;
++
++ if (!cpu_isset(i, *cpus))
++ continue;
++
++ rq = cpu_rq(i);
+
+ if (*sd_idle && !idle_cpu(i))
+ *sd_idle = 0;
+@@ -2466,13 +2490,17 @@ ret:
+ */
+ static struct rq *
+ find_busiest_queue(struct sched_group *group, enum idle_type idle,
+- unsigned long imbalance)
++ unsigned long imbalance, cpumask_t *cpus)
+ {
+ struct rq *busiest = NULL, *rq;
+ unsigned long max_load = 0;
+ int i;
+
+ for_each_cpu_mask(i, group->cpumask) {
++
++ if (!cpu_isset(i, *cpus))
++ continue;
++
+ rq = cpu_rq(i);
+
+ if (rq->nr_running == 1 && rq->raw_weighted_load > imbalance)
+@@ -2511,20 +2539,29 @@ static int load_balance(int this_cpu, st
+ struct sched_group *group;
+ unsigned long imbalance;
+ struct rq *busiest;
++ cpumask_t cpus = CPU_MASK_ALL;
+
++ /*
++ * When power savings policy is enabled for the parent domain, idle
++ * sibling can pick up load irrespective of busy siblings. In this case,
++ * let the state of idle sibling percolate up as IDLE, instead of
++ * portraying it as NOT_IDLE.
++ */
+ if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
+- !sched_smt_power_savings)
++ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
+ sd_idle = 1;
+
+ schedstat_inc(sd, lb_cnt[idle]);
+
+- group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle);
++redo:
++ group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
++ &cpus);
+ if (!group) {
+ schedstat_inc(sd, lb_nobusyg[idle]);
+ goto out_balanced;
+ }
+
+- busiest = find_busiest_queue(group, idle, imbalance);
++ busiest = find_busiest_queue(group, idle, imbalance, &cpus);
+ if (!busiest) {
+ schedstat_inc(sd, lb_nobusyq[idle]);
+ goto out_balanced;
+@@ -2549,8 +2586,12 @@ static int load_balance(int this_cpu, st
+ double_rq_unlock(this_rq, busiest);
+
+ /* All tasks on this runqueue were pinned by CPU affinity */
+- if (unlikely(all_pinned))
++ if (unlikely(all_pinned)) {
++ cpu_clear(cpu_of(busiest), cpus);
++ if (!cpus_empty(cpus))
++ goto redo;
+ goto out_balanced;
++ }
+ }
+
+ if (!nr_moved) {
+@@ -2603,7 +2644,7 @@ static int load_balance(int this_cpu, st
+ }
+
+ if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
+- !sched_smt_power_savings)
++ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
+ return -1;
+ return nr_moved;
+
+@@ -2619,7 +2660,7 @@ out_one_pinned:
+ sd->balance_interval *= 2;
+
+ if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
+- !sched_smt_power_savings)
++ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
+ return -1;
+ return 0;
+ }
+@@ -2639,18 +2680,29 @@ load_balance_newidle(int this_cpu, struc
+ unsigned long imbalance;
+ int nr_moved = 0;
+ int sd_idle = 0;
++ cpumask_t cpus = CPU_MASK_ALL;
+
+- if (sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
++ /*
++ * When power savings policy is enabled for the parent domain, idle
++ * sibling can pick up load irrespective of busy siblings. In this case,
++ * let the state of idle sibling percolate up as IDLE, instead of
++ * portraying it as NOT_IDLE.
++ */
++ if (sd->flags & SD_SHARE_CPUPOWER &&
++ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
+ sd_idle = 1;
+
+ schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
+- group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE, &sd_idle);
++redo:
++ group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE,
++ &sd_idle, &cpus);
+ if (!group) {
+ schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
+ goto out_balanced;
+ }
+
+- busiest = find_busiest_queue(group, NEWLY_IDLE, imbalance);
++ busiest = find_busiest_queue(group, NEWLY_IDLE, imbalance,
++ &cpus);
+ if (!busiest) {
+ schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
+ goto out_balanced;
+@@ -2668,11 +2720,18 @@ load_balance_newidle(int this_cpu, struc
+ minus_1_or_zero(busiest->nr_running),
+ imbalance, sd, NEWLY_IDLE, NULL);
+ spin_unlock(&busiest->lock);
++
++ if (!nr_moved) {
++ cpu_clear(cpu_of(busiest), cpus);
++ if (!cpus_empty(cpus))
++ goto redo;
++ }
+ }
+
+ if (!nr_moved) {
+ schedstat_inc(sd, lb_failed[NEWLY_IDLE]);
+- if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER)
++ if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
++ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
+ return -1;
+ } else
+ sd->nr_balance_failed = 0;
+@@ -2682,7 +2741,7 @@ load_balance_newidle(int this_cpu, struc
+ out_balanced:
+ schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
+ if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
+- !sched_smt_power_savings)
++ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
+ return -1;
+ sd->nr_balance_failed = 0;
+
+@@ -3311,9 +3370,6 @@ need_resched_nonpreemptible:
+
+ spin_lock_irq(&rq->lock);
+
+- if (unlikely(prev->flags & PF_DEAD))
+- prev->state = EXIT_DEAD;
+-
+ switch_count = &prev->nivcsw;
+ if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
+ switch_count = &prev->nvcsw;
+@@ -3435,7 +3491,7 @@ asmlinkage void __sched preempt_schedule
+ * If there is a non-zero preempt_count or interrupts are disabled,
+ * we do not want to preempt the current task. Just return..
+ */
+- if (unlikely(ti->preempt_count || irqs_disabled()))
++ if (likely(ti->preempt_count || irqs_disabled()))
+ return;
+
+ need_resched:
+@@ -4043,6 +4099,8 @@ static void __setscheduler(struct task_s
+ * @p: the task in question.
+ * @policy: new policy.
+ * @param: structure containing the new RT priority.
++ *
++ * NOTE: the task may be already dead
+ */
+ int sched_setscheduler(struct task_struct *p, int policy,
+ struct sched_param *param)
+@@ -4070,28 +4128,32 @@ recheck:
+ (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) ||
+ (!p->mm && param->sched_priority > MAX_RT_PRIO-1))
+ return -EINVAL;
+- if ((policy == SCHED_NORMAL || policy == SCHED_BATCH)
+- != (param->sched_priority == 0))
++ if (is_rt_policy(policy) != (param->sched_priority != 0))
+ return -EINVAL;
+
+ /*
+ * Allow unprivileged RT tasks to decrease priority:
+ */
+ if (!capable(CAP_SYS_NICE)) {
+- /*
+- * can't change policy, except between SCHED_NORMAL
+- * and SCHED_BATCH:
+- */
+- if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
+- (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&
+- !p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+- return -EPERM;
+- /* can't increase priority */
+- if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) &&
+- param->sched_priority > p->rt_priority &&
+- param->sched_priority >
+- p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+- return -EPERM;
++ if (is_rt_policy(policy)) {
++ unsigned long rlim_rtprio;
++ unsigned long flags;
++
++ if (!lock_task_sighand(p, &flags))
++ return -ESRCH;
++ rlim_rtprio = p->signal->rlim[RLIMIT_RTPRIO].rlim_cur;
++ unlock_task_sighand(p, &flags);
++
++ /* can't set/change the rt policy */
++ if (policy != p->policy && !rlim_rtprio)
++ return -EPERM;
++
++ /* can't increase priority */
++ if (param->sched_priority > p->rt_priority &&
++ param->sched_priority > rlim_rtprio)
++ return -EPERM;
++ }
++
+ /* can't change other user's priorities */
+ if ((current->euid != p->euid) &&
+ (current->euid != p->uid))
+@@ -4156,14 +4218,13 @@ do_sched_setscheduler(pid_t pid, int pol
+ return -EINVAL;
+ if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
+ return -EFAULT;
+- read_lock_irq(&tasklist_lock);
++
++ rcu_read_lock();
++ retval = -ESRCH;
+ p = find_process_by_pid(pid);
+- if (!p) {
+- read_unlock_irq(&tasklist_lock);
+- return -ESRCH;
+- }
+- retval = sched_setscheduler(p, policy, &lparam);
+- read_unlock_irq(&tasklist_lock);
++ if (p != NULL)
++ retval = sched_setscheduler(p, policy, &lparam);
++ rcu_read_unlock();
+
+ return retval;
+ }
+@@ -4345,7 +4406,10 @@ EXPORT_SYMBOL(cpu_present_map);
+
+ #ifndef CONFIG_SMP
+ cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL;
++EXPORT_SYMBOL(cpu_online_map);
++
+ cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL;
++EXPORT_SYMBOL(cpu_possible_map);
+ #endif
+
+ long sched_getaffinity(pid_t pid, cpumask_t *mask)
+@@ -4775,7 +4839,7 @@ void show_state(void)
+ * NOTE: this function does not set the idle thread's NEED_RESCHED
+ * flag, to make booting more robust.
+ */
+-void __devinit init_idle(struct task_struct *idle, int cpu)
++void __cpuinit init_idle(struct task_struct *idle, int cpu)
+ {
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+@@ -5114,7 +5178,7 @@ static void migrate_dead(unsigned int de
+ BUG_ON(p->exit_state != EXIT_ZOMBIE && p->exit_state != EXIT_DEAD);
+
+ /* Cannot have done final schedule yet: would have vanished. */
+- BUG_ON(p->flags & PF_DEAD);
++ BUG_ON(p->state == TASK_DEAD);
+
+ get_task_struct(p);
+
+@@ -5235,9 +5299,11 @@ static struct notifier_block __cpuinitda
+ int __init migration_init(void)
+ {
+ void *cpu = (void *)(long)smp_processor_id();
++ int err;
+
+ /* Start one for the boot CPU: */
+- migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
++ err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
++ BUG_ON(err == NOTIFY_BAD);
+ migration_call(&migration_notifier, CPU_ONLINE, cpu);
+ register_cpu_notifier(&migration_notifier);
+
+@@ -5348,7 +5414,9 @@ static int sd_degenerate(struct sched_do
+ if (sd->flags & (SD_LOAD_BALANCE |
+ SD_BALANCE_NEWIDLE |
+ SD_BALANCE_FORK |
+- SD_BALANCE_EXEC)) {
++ SD_BALANCE_EXEC |
++ SD_SHARE_CPUPOWER |
++ SD_SHARE_PKG_RESOURCES)) {
+ if (sd->groups != sd->groups->next)
+ return 0;
+ }
+@@ -5382,7 +5450,9 @@ sd_parent_degenerate(struct sched_domain
+ pflags &= ~(SD_LOAD_BALANCE |
+ SD_BALANCE_NEWIDLE |
+ SD_BALANCE_FORK |
+- SD_BALANCE_EXEC);
++ SD_BALANCE_EXEC |
++ SD_SHARE_CPUPOWER |
++ SD_SHARE_PKG_RESOURCES);
+ }
+ if (~cflags & pflags)
+ return 0;
+@@ -5404,12 +5474,18 @@ static void cpu_attach_domain(struct sch
+ struct sched_domain *parent = tmp->parent;
+ if (!parent)
+ break;
+- if (sd_parent_degenerate(tmp, parent))
++ if (sd_parent_degenerate(tmp, parent)) {
+ tmp->parent = parent->parent;
++ if (parent->parent)
++ parent->parent->child = tmp;
++ }
+ }
+
+- if (sd && sd_degenerate(sd))
++ if (sd && sd_degenerate(sd)) {
+ sd = sd->parent;
++ if (sd)
++ sd->child = NULL;
++ }
+
+ sched_domain_debug(sd, cpu);
+
+@@ -5417,7 +5493,7 @@ static void cpu_attach_domain(struct sch
+ }
+
+ /* cpus with isolated domains */
+-static cpumask_t __devinitdata cpu_isolated_map = CPU_MASK_NONE;
++static cpumask_t __cpuinitdata cpu_isolated_map = CPU_MASK_NONE;
+
+ /* Setup the mask of cpus configured for isolated domains */
+ static int __init isolated_cpu_setup(char *str)
+@@ -5445,15 +5521,17 @@ __setup ("isolcpus=", isolated_cpu_setup
+ * covered by the given span, and will set each group's ->cpumask correctly,
+ * and ->cpu_power to 0.
+ */
+-static void init_sched_build_groups(struct sched_group groups[], cpumask_t span,
+- int (*group_fn)(int cpu))
++static void
++init_sched_build_groups(struct sched_group groups[], cpumask_t span,
++ const cpumask_t *cpu_map,
++ int (*group_fn)(int cpu, const cpumask_t *cpu_map))
+ {
+ struct sched_group *first = NULL, *last = NULL;
+ cpumask_t covered = CPU_MASK_NONE;
+ int i;
+
+ for_each_cpu_mask(i, span) {
+- int group = group_fn(i);
++ int group = group_fn(i, cpu_map);
+ struct sched_group *sg = &groups[group];
+ int j;
+
+@@ -5464,7 +5542,7 @@ static void init_sched_build_groups(stru
+ sg->cpu_power = 0;
+
+ for_each_cpu_mask(j, span) {
+- if (group_fn(j) != group)
++ if (group_fn(j, cpu_map) != group)
+ continue;
+
+ cpu_set(j, covered);
+@@ -5931,13 +6009,15 @@ static void calibrate_migration_costs(co
+ #endif
+ );
+ if (system_state == SYSTEM_BOOTING) {
+- printk("migration_cost=");
+- for (distance = 0; distance <= max_distance; distance++) {
+- if (distance)
+- printk(",");
+- printk("%ld", (long)migration_cost[distance] / 1000);
++ if (num_online_cpus() > 1) {
++ printk("migration_cost=");
++ for (distance = 0; distance <= max_distance; distance++) {
++ if (distance)
++ printk(",");
++ printk("%ld", (long)migration_cost[distance] / 1000);
++ }
++ printk("\n");
+ }
+- printk("\n");
+ }
+ j1 = jiffies;
+ if (migration_debug)
+@@ -6040,7 +6120,7 @@ int sched_smt_power_savings = 0, sched_m
+ static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
+ static struct sched_group sched_group_cpus[NR_CPUS];
+
+-static int cpu_to_cpu_group(int cpu)
++static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map)
+ {
+ return cpu;
+ }
+@@ -6051,31 +6131,36 @@ static int cpu_to_cpu_group(int cpu)
+ */
+ #ifdef CONFIG_SCHED_MC
+ static DEFINE_PER_CPU(struct sched_domain, core_domains);
+-static struct sched_group *sched_group_core_bycpu[NR_CPUS];
++static struct sched_group sched_group_core[NR_CPUS];
+ #endif
+
+ #if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
+-static int cpu_to_core_group(int cpu)
++static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
+ {
+- return first_cpu(cpu_sibling_map[cpu]);
++ cpumask_t mask = cpu_sibling_map[cpu];
++ cpus_and(mask, mask, *cpu_map);
++ return first_cpu(mask);
+ }
+ #elif defined(CONFIG_SCHED_MC)
+-static int cpu_to_core_group(int cpu)
++static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
+ {
+ return cpu;
+ }
+ #endif
+
+ static DEFINE_PER_CPU(struct sched_domain, phys_domains);
+-static struct sched_group *sched_group_phys_bycpu[NR_CPUS];
++static struct sched_group sched_group_phys[NR_CPUS];
+
+-static int cpu_to_phys_group(int cpu)
++static int cpu_to_phys_group(int cpu, const cpumask_t *cpu_map)
+ {
+ #ifdef CONFIG_SCHED_MC
+ cpumask_t mask = cpu_coregroup_map(cpu);
++ cpus_and(mask, mask, *cpu_map);
+ return first_cpu(mask);
+ #elif defined(CONFIG_SCHED_SMT)
+- return first_cpu(cpu_sibling_map[cpu]);
++ cpumask_t mask = cpu_sibling_map[cpu];
++ cpus_and(mask, mask, *cpu_map);
++ return first_cpu(mask);
+ #else
+ return cpu;
+ #endif
+@@ -6093,7 +6178,7 @@ static struct sched_group **sched_group_
+ static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
+ static struct sched_group *sched_group_allnodes_bycpu[NR_CPUS];
+
+-static int cpu_to_allnodes_group(int cpu)
++static int cpu_to_allnodes_group(int cpu, const cpumask_t *cpu_map)
+ {
+ return cpu_to_node(cpu);
+ }
+@@ -6125,12 +6210,11 @@ next_sg:
+ }
+ #endif
+
++#ifdef CONFIG_NUMA
+ /* Free memory allocated for various sched_group structures */
+ static void free_sched_groups(const cpumask_t *cpu_map)
+ {
+- int cpu;
+-#ifdef CONFIG_NUMA
+- int i;
++ int cpu, i;
+
+ for_each_cpu_mask(cpu, *cpu_map) {
+ struct sched_group *sched_group_allnodes
+@@ -6167,19 +6251,63 @@ next_sg:
+ kfree(sched_group_nodes);
+ sched_group_nodes_bycpu[cpu] = NULL;
+ }
++}
++#else
++static void free_sched_groups(const cpumask_t *cpu_map)
++{
++}
+ #endif
+- for_each_cpu_mask(cpu, *cpu_map) {
+- if (sched_group_phys_bycpu[cpu]) {
+- kfree(sched_group_phys_bycpu[cpu]);
+- sched_group_phys_bycpu[cpu] = NULL;
+- }
+-#ifdef CONFIG_SCHED_MC
+- if (sched_group_core_bycpu[cpu]) {
+- kfree(sched_group_core_bycpu[cpu]);
+- sched_group_core_bycpu[cpu] = NULL;
+- }
+-#endif
++
++/*
++ * Initialize sched groups cpu_power.
++ *
++ * cpu_power indicates the capacity of sched group, which is used while
++ * distributing the load between different sched groups in a sched domain.
++ * Typically cpu_power for all the groups in a sched domain will be same unless
++ * there are asymmetries in the topology. If there are asymmetries, group
++ * having more cpu_power will pickup more load compared to the group having
++ * less cpu_power.
++ *
++ * cpu_power will be a multiple of SCHED_LOAD_SCALE. This multiple represents
++ * the maximum number of tasks a group can handle in the presence of other idle
++ * or lightly loaded groups in the same sched domain.
++ */
++static void init_sched_groups_power(int cpu, struct sched_domain *sd)
++{
++ struct sched_domain *child;
++ struct sched_group *group;
++
++ WARN_ON(!sd || !sd->groups);
++
++ if (cpu != first_cpu(sd->groups->cpumask))
++ return;
++
++ child = sd->child;
++
++ /*
++ * For perf policy, if the groups in child domain share resources
++ * (for example cores sharing some portions of the cache hierarchy
++ * or SMT), then set this domain groups cpu_power such that each group
++ * can handle only one task, when there are other idle groups in the
++ * same sched domain.
++ */
++ if (!child || (!(sd->flags & SD_POWERSAVINGS_BALANCE) &&
++ (child->flags &
++ (SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES)))) {
++ sd->groups->cpu_power = SCHED_LOAD_SCALE;
++ return;
+ }
++
++ sd->groups->cpu_power = 0;
++
++ /*
++ * add cpu_power of each child group to this groups cpu_power
++ */
++ group = child->groups;
++ do {
++ sd->groups->cpu_power += group->cpu_power;
++ group = group->next;
++ } while (group != child->groups);
+ }
+
+ /*
+@@ -6189,10 +6317,7 @@ next_sg:
+ static int build_sched_domains(const cpumask_t *cpu_map)
+ {
+ int i;
+- struct sched_group *sched_group_phys = NULL;
+-#ifdef CONFIG_SCHED_MC
+- struct sched_group *sched_group_core = NULL;
+-#endif
++ struct sched_domain *sd;
+ #ifdef CONFIG_NUMA
+ struct sched_group **sched_group_nodes = NULL;
+ struct sched_group *sched_group_allnodes = NULL;
+@@ -6224,9 +6349,10 @@ static int build_sched_domains(const cpu
+ > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
+ if (!sched_group_allnodes) {
+ sched_group_allnodes
+- = kmalloc(sizeof(struct sched_group)
+- * MAX_NUMNODES,
+- GFP_KERNEL);
++ = kmalloc_node(sizeof(struct sched_group)
++ * MAX_NUMNODES,
++ GFP_KERNEL,
++ cpu_to_node(i));
+ if (!sched_group_allnodes) {
+ printk(KERN_WARNING
+ "Can not alloc allnodes sched group\n");
+@@ -6238,7 +6364,7 @@ static int build_sched_domains(const cpu
+ sd = &per_cpu(allnodes_domains, i);
+ *sd = SD_ALLNODES_INIT;
+ sd->span = *cpu_map;
+- group = cpu_to_allnodes_group(i);
++ group = cpu_to_allnodes_group(i, cpu_map);
+ sd->groups = &sched_group_allnodes[group];
+ p = sd;
+ } else
+@@ -6248,60 +6374,42 @@ static int build_sched_domains(const cpu
+ *sd = SD_NODE_INIT;
+ sd->span = sched_domain_node_span(cpu_to_node(i));
+ sd->parent = p;
++ if (p)
++ p->child = sd;
+ cpus_and(sd->span, sd->span, *cpu_map);
+ #endif
+
+- if (!sched_group_phys) {
+- sched_group_phys
+- = kmalloc(sizeof(struct sched_group) * NR_CPUS,
+- GFP_KERNEL);
+- if (!sched_group_phys) {
+- printk (KERN_WARNING "Can not alloc phys sched"
+- "group\n");
+- goto error;
+- }
+- sched_group_phys_bycpu[i] = sched_group_phys;
+- }
+-
+ p = sd;
+ sd = &per_cpu(phys_domains, i);
+- group = cpu_to_phys_group(i);
++ group = cpu_to_phys_group(i, cpu_map);
+ *sd = SD_CPU_INIT;
+ sd->span = nodemask;
+ sd->parent = p;
++ if (p)
++ p->child = sd;
+ sd->groups = &sched_group_phys[group];
+
+ #ifdef CONFIG_SCHED_MC
+- if (!sched_group_core) {
+- sched_group_core
+- = kmalloc(sizeof(struct sched_group) * NR_CPUS,
+- GFP_KERNEL);
+- if (!sched_group_core) {
+- printk (KERN_WARNING "Can not alloc core sched"
+- "group\n");
+- goto error;
+- }
+- sched_group_core_bycpu[i] = sched_group_core;
+- }
+-
+ p = sd;
+ sd = &per_cpu(core_domains, i);
+- group = cpu_to_core_group(i);
++ group = cpu_to_core_group(i, cpu_map);
+ *sd = SD_MC_INIT;
+ sd->span = cpu_coregroup_map(i);
+ cpus_and(sd->span, sd->span, *cpu_map);
+ sd->parent = p;
++ p->child = sd;
+ sd->groups = &sched_group_core[group];
+ #endif
+
+ #ifdef CONFIG_SCHED_SMT
+ p = sd;
+ sd = &per_cpu(cpu_domains, i);
+- group = cpu_to_cpu_group(i);
++ group = cpu_to_cpu_group(i, cpu_map);
+ *sd = SD_SIBLING_INIT;
+ sd->span = cpu_sibling_map[i];
+ cpus_and(sd->span, sd->span, *cpu_map);
+ sd->parent = p;
++ p->child = sd;
+ sd->groups = &sched_group_cpus[group];
+ #endif
+ }
+@@ -6315,7 +6423,7 @@ static int build_sched_domains(const cpu
+ continue;
+
+ init_sched_build_groups(sched_group_cpus, this_sibling_map,
+- &cpu_to_cpu_group);
++ cpu_map, &cpu_to_cpu_group);
+ }
+ #endif
+
+@@ -6327,7 +6435,7 @@ static int build_sched_domains(const cpu
+ if (i != first_cpu(this_core_map))
+ continue;
+ init_sched_build_groups(sched_group_core, this_core_map,
+- &cpu_to_core_group);
++ cpu_map, &cpu_to_core_group);
+ }
+ #endif
+
+@@ -6341,14 +6449,14 @@ static int build_sched_domains(const cpu
+ continue;
+
+ init_sched_build_groups(sched_group_phys, nodemask,
+- &cpu_to_phys_group);
++ cpu_map, &cpu_to_phys_group);
+ }
+
+ #ifdef CONFIG_NUMA
+ /* Set up node groups */
+ if (sched_group_allnodes)
+ init_sched_build_groups(sched_group_allnodes, *cpu_map,
+- &cpu_to_allnodes_group);
++ cpu_map, &cpu_to_allnodes_group);
+
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ /* Set up node groups */
+@@ -6420,72 +6528,20 @@ static int build_sched_domains(const cpu
+ /* Calculate CPU power for physical packages and nodes */
+ #ifdef CONFIG_SCHED_SMT
+ for_each_cpu_mask(i, *cpu_map) {
+- struct sched_domain *sd;
+ sd = &per_cpu(cpu_domains, i);
+- sd->groups->cpu_power = SCHED_LOAD_SCALE;
++ init_sched_groups_power(i, sd);
+ }
+ #endif
+ #ifdef CONFIG_SCHED_MC
+ for_each_cpu_mask(i, *cpu_map) {
+- int power;
+- struct sched_domain *sd;
+ sd = &per_cpu(core_domains, i);
+- if (sched_smt_power_savings)
+- power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
+- else
+- power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
+- * SCHED_LOAD_SCALE / 10;
+- sd->groups->cpu_power = power;
++ init_sched_groups_power(i, sd);
+ }
+ #endif
+
+ for_each_cpu_mask(i, *cpu_map) {
+- struct sched_domain *sd;
+-#ifdef CONFIG_SCHED_MC
+- sd = &per_cpu(phys_domains, i);
+- if (i != first_cpu(sd->groups->cpumask))
+- continue;
+-
+- sd->groups->cpu_power = 0;
+- if (sched_mc_power_savings || sched_smt_power_savings) {
+- int j;
+-
+- for_each_cpu_mask(j, sd->groups->cpumask) {
+- struct sched_domain *sd1;
+- sd1 = &per_cpu(core_domains, j);
+- /*
+- * for each core we will add once
+- * to the group in physical domain
+- */
+- if (j != first_cpu(sd1->groups->cpumask))
+- continue;
+-
+- if (sched_smt_power_savings)
+- sd->groups->cpu_power += sd1->groups->cpu_power;
+- else
+- sd->groups->cpu_power += SCHED_LOAD_SCALE;
+- }
+- } else
+- /*
+- * This has to be < 2 * SCHED_LOAD_SCALE
+- * Lets keep it SCHED_LOAD_SCALE, so that
+- * while calculating NUMA group's cpu_power
+- * we can simply do
+- * numa_group->cpu_power += phys_group->cpu_power;
+- *
+- * See "only add power once for each physical pkg"
+- * comment below
+- */
+- sd->groups->cpu_power = SCHED_LOAD_SCALE;
+-#else
+- int power;
+ sd = &per_cpu(phys_domains, i);
+- if (sched_smt_power_savings)
+- power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
+- else
+- power = SCHED_LOAD_SCALE;
+- sd->groups->cpu_power = power;
+-#endif
++ init_sched_groups_power(i, sd);
+ }
+
+ #ifdef CONFIG_NUMA
+@@ -6493,7 +6549,7 @@ static int build_sched_domains(const cpu
+ init_numa_sched_groups_power(sched_group_nodes[i]);
+
+ if (sched_group_allnodes) {
+- int group = cpu_to_allnodes_group(first_cpu(*cpu_map));
++ int group = cpu_to_allnodes_group(first_cpu(*cpu_map), cpu_map);
+ struct sched_group *sg = &sched_group_allnodes[group];
+
+ init_numa_sched_groups_power(sg);
+@@ -6519,9 +6575,11 @@ static int build_sched_domains(const cpu
+
+ return 0;
+
++#ifdef CONFIG_NUMA
+ error:
+ free_sched_groups(cpu_map);
+ return -ENOMEM;
++#endif
+ }
+ /*
+ * Set up scheduler domains and groups. Callers must hold the hotplug lock.
+@@ -6703,11 +6761,20 @@ static int update_sched_domains(struct n
+
+ void __init sched_init_smp(void)
+ {
++ cpumask_t non_isolated_cpus;
++
+ lock_cpu_hotplug();
+ arch_init_sched_domains(&cpu_online_map);
++ cpus_andnot(non_isolated_cpus, cpu_online_map, cpu_isolated_map);
++ if (cpus_empty(non_isolated_cpus))
++ cpu_set(smp_processor_id(), non_isolated_cpus);
+ unlock_cpu_hotplug();
+ /* XXX: Theoretical race here - CPU may be hotplugged now */
+ hotcpu_notifier(update_sched_domains, 0);
++
++ /* Move init over to a non-isolated CPU */
++ if (set_cpus_allowed(current, non_isolated_cpus) < 0)
++ BUG();
+ }
+ #else
+ void __init sched_init_smp(void)
+@@ -6747,6 +6814,7 @@ void __init sched_init(void)
+ rq->cpu_load[j] = 0;
+ rq->active_balance = 0;
+ rq->push_cpu = 0;
++ rq->cpu = i;
+ rq->migration_thread = NULL;
+ INIT_LIST_HEAD(&rq->migration_queue);
+ #endif
+diff --git a/kernel/signal.c b/kernel/signal.c
+index bfdb568..df18c16 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -267,18 +267,25 @@ static struct sigqueue *__sigqueue_alloc
+ int override_rlimit)
+ {
+ struct sigqueue *q = NULL;
++ struct user_struct *user;
+
+- atomic_inc(&t->user->sigpending);
++ /*
++ * In order to avoid problems with "switch_user()", we want to make
++ * sure that the compiler doesn't re-load "t->user"
++ */
++ user = t->user;
++ barrier();
++ atomic_inc(&user->sigpending);
+ if (override_rlimit ||
+- atomic_read(&t->user->sigpending) <=
++ atomic_read(&user->sigpending) <=
+ t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
+ q = kmem_cache_alloc(sigqueue_cachep, flags);
+ if (unlikely(q == NULL)) {
+- atomic_dec(&t->user->sigpending);
++ atomic_dec(&user->sigpending);
+ } else {
+ INIT_LIST_HEAD(&q->list);
+ q->flags = 0;
+- q->user = get_uid(t->user);
++ q->user = get_uid(user);
+ }
+ return(q);
+ }
+@@ -417,9 +424,8 @@ static int collect_signal(int sig, struc
+ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
+ siginfo_t *info)
+ {
+- int sig = 0;
++ int sig = next_signal(pending, mask);
+
+- sig = next_signal(pending, mask);
+ if (sig) {
+ if (current->notifier) {
+ if (sigismember(current->notifier_mask, sig)) {
+@@ -432,9 +438,7 @@ static int __dequeue_signal(struct sigpe
+
+ if (!collect_signal(sig, pending, info))
+ sig = 0;
+-
+ }
+- recalc_sigpending();
+
+ return sig;
+ }
+@@ -451,6 +455,7 @@ int dequeue_signal(struct task_struct *t
+ if (!signr)
+ signr = __dequeue_signal(&tsk->signal->shared_pending,
+ mask, info);
++ recalc_sigpending_tsk(tsk);
+ if (signr && unlikely(sig_kernel_stop(signr))) {
+ /*
+ * Set a marker that we have dequeued a stop signal. Our
+@@ -1057,28 +1062,44 @@ int group_send_sig_info(int sig, struct
+ }
+
+ /*
+- * kill_pg_info() sends a signal to a process group: this is what the tty
++ * kill_pgrp_info() sends a signal to a process group: this is what the tty
+ * control characters do (^C, ^Z etc)
+ */
+
+-int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
++int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
+ {
+ struct task_struct *p = NULL;
+ int retval, success;
+
+- if (pgrp <= 0)
+- return -EINVAL;
+-
+ success = 0;
+ retval = -ESRCH;
+- do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
++ do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
+ int err = group_send_sig_info(sig, info, p);
+ success |= !err;
+ retval = err;
+- } while_each_task_pid(pgrp, PIDTYPE_PGID, p);
++ } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
+ return success ? 0 : retval;
+ }
+
++int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
++{
++ int retval;
++
++ read_lock(&tasklist_lock);
++ retval = __kill_pgrp_info(sig, info, pgrp);
++ read_unlock(&tasklist_lock);
++
++ return retval;
++}
++
++int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
++{
++ if (pgrp <= 0)
++ return -EINVAL;
++
++ return __kill_pgrp_info(sig, info, find_pid(pgrp));
++}
++
+ int
+ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
+ {
+@@ -1091,8 +1112,7 @@ kill_pg_info(int sig, struct siginfo *in
+ return retval;
+ }
+
+-int
+-kill_proc_info(int sig, struct siginfo *info, pid_t pid)
++int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
+ {
+ int error;
+ int acquired_tasklist_lock = 0;
+@@ -1103,7 +1123,7 @@ kill_proc_info(int sig, struct siginfo *
+ read_lock(&tasklist_lock);
+ acquired_tasklist_lock = 1;
+ }
+- p = find_task_by_pid(pid);
++ p = pid_task(pid, PIDTYPE_PID);
+ error = -ESRCH;
+ if (p)
+ error = group_send_sig_info(sig, info, p);
+@@ -1113,8 +1133,18 @@ kill_proc_info(int sig, struct siginfo *
+ return error;
+ }
+
+-/* like kill_proc_info(), but doesn't use uid/euid of "current" */
+-int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid,
++int
++kill_proc_info(int sig, struct siginfo *info, pid_t pid)
++{
++ int error;
++ rcu_read_lock();
++ error = kill_pid_info(sig, info, find_pid(pid));
++ rcu_read_unlock();
++ return error;
++}
++
++/* like kill_pid_info(), but doesn't use uid/euid of "current" */
++int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
+ uid_t uid, uid_t euid, u32 secid)
+ {
+ int ret = -EINVAL;
+@@ -1124,7 +1154,7 @@ int kill_proc_info_as_uid(int sig, struc
+ return ret;
+
+ read_lock(&tasklist_lock);
+- p = find_task_by_pid(pid);
++ p = pid_task(pid, PIDTYPE_PID);
+ if (!p) {
+ ret = -ESRCH;
+ goto out_unlock;
+@@ -1148,7 +1178,7 @@ out_unlock:
+ read_unlock(&tasklist_lock);
+ return ret;
+ }
+-EXPORT_SYMBOL_GPL(kill_proc_info_as_uid);
++EXPORT_SYMBOL_GPL(kill_pid_info_as_uid);
+
+ /*
+ * kill_something_info() interprets pid in interesting ways just like kill(2).
+@@ -1266,6 +1296,18 @@ force_sigsegv(int sig, struct task_struc
+ return 0;
+ }
+
++int kill_pgrp(struct pid *pid, int sig, int priv)
++{
++ return kill_pgrp_info(sig, __si_special(priv), pid);
++}
++EXPORT_SYMBOL(kill_pgrp);
++
++int kill_pid(struct pid *pid, int sig, int priv)
++{
++ return kill_pid_info(sig, __si_special(priv), pid);
++}
++EXPORT_SYMBOL(kill_pid);
++
+ int
+ kill_pg(pid_t pgrp, int sig, int priv)
+ {
+@@ -2577,6 +2619,11 @@ asmlinkage long sys_rt_sigsuspend(sigset
+ }
+ #endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+
++__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
++{
++ return NULL;
++}
++
+ void __init signals_init(void)
+ {
+ sigqueue_cachep =
+diff --git a/kernel/softirq.c b/kernel/softirq.c
+index 3789ca9..bf25015 100644
+--- a/kernel/softirq.c
++++ b/kernel/softirq.c
+@@ -612,7 +612,9 @@ static struct notifier_block __cpuinitda
+ __init int spawn_ksoftirqd(void)
+ {
+ void *cpu = (void *)(long)smp_processor_id();
+- cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
++ int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
++
++ BUG_ON(err == NOTIFY_BAD);
+ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+ register_cpu_notifier(&cpu_nfb);
+ return 0;
+diff --git a/kernel/softlockup.c b/kernel/softlockup.c
+index 03e6a2b..50afeb8 100644
+--- a/kernel/softlockup.c
++++ b/kernel/softlockup.c
+@@ -149,8 +149,9 @@ static struct notifier_block __cpuinitda
+ __init void spawn_softlockup_task(void)
+ {
+ void *cpu = (void *)(long)smp_processor_id();
++ int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+
+- cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
++ BUG_ON(err == NOTIFY_BAD);
+ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+ register_cpu_notifier(&cpu_nfb);
+
+diff --git a/kernel/spinlock.c b/kernel/spinlock.c
+index fb524b0..476c374 100644
+--- a/kernel/spinlock.c
++++ b/kernel/spinlock.c
+@@ -7,6 +7,11 @@
+ *
+ * This file contains the spinlock/rwlock implementations for the
+ * SMP and the DEBUG_SPINLOCK cases. (UP-nondebug inlines them)
++ *
++ * Note that some architectures have special knowledge about the
++ * stack frames of these functions in their profile_pc. If you
++ * change anything significant here that could change the stack
++ * frame contact the architecture maintainers.
+ */
+
+ #include <linux/linkage.h>
+@@ -16,17 +21,6 @@
+ #include <linux/debug_locks.h>
+ #include <linux/module.h>
+
+-/*
+- * Generic declaration of the raw read_trylock() function,
+- * architectures are supposed to optimize this:
+- */
+-int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock)
+-{
+- __raw_read_lock(lock);
+- return 1;
+-}
+-EXPORT_SYMBOL(generic__raw_read_trylock);
+-
+ int __lockfunc _spin_trylock(spinlock_t *lock)
+ {
+ preempt_disable();
+@@ -221,7 +215,7 @@ void __lockfunc _##op##_lock(locktype##_
+ if (!(lock)->break_lock) \
+ (lock)->break_lock = 1; \
+ while (!op##_can_lock(lock) && (lock)->break_lock) \
+- cpu_relax(); \
++ _raw_##op##_relax(&lock->raw_lock); \
+ } \
+ (lock)->break_lock = 0; \
+ } \
+@@ -243,7 +237,7 @@ unsigned long __lockfunc _##op##_lock_ir
+ if (!(lock)->break_lock) \
+ (lock)->break_lock = 1; \
+ while (!op##_can_lock(lock) && (lock)->break_lock) \
+- cpu_relax(); \
++ _raw_##op##_relax(&lock->raw_lock); \
+ } \
+ (lock)->break_lock = 0; \
+ return flags; \
+diff --git a/kernel/srcu.c b/kernel/srcu.c
+new file mode 100644
+index 0000000..3507cab
+--- /dev/null
++++ b/kernel/srcu.c
+@@ -0,0 +1,258 @@
++/*
++ * Sleepable Read-Copy Update mechanism for mutual exclusion.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) IBM Corporation, 2006
++ *
++ * Author: Paul McKenney <paulmck at us.ibm.com>
++ *
++ * For detailed explanation of Read-Copy Update mechanism see -
++ * Documentation/RCU/ *.txt
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/percpu.h>
++#include <linux/preempt.h>
++#include <linux/rcupdate.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp.h>
++#include <linux/srcu.h>
++
++/**
++ * init_srcu_struct - initialize a sleep-RCU structure
++ * @sp: structure to initialize.
++ *
++ * Must invoke this on a given srcu_struct before passing that srcu_struct
++ * to any other function. Each srcu_struct represents a separate domain
++ * of SRCU protection.
++ */
++int init_srcu_struct(struct srcu_struct *sp)
++{
++ sp->completed = 0;
++ mutex_init(&sp->mutex);
++ sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
++ return (sp->per_cpu_ref ? 0 : -ENOMEM);
++}
++
++/*
++ * srcu_readers_active_idx -- returns approximate number of readers
++ * active on the specified rank of per-CPU counters.
++ */
++
++static int srcu_readers_active_idx(struct srcu_struct *sp, int idx)
++{
++ int cpu;
++ int sum;
++
++ sum = 0;
++ for_each_possible_cpu(cpu)
++ sum += per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx];
++ return sum;
++}
++
++/**
++ * srcu_readers_active - returns approximate number of readers.
++ * @sp: which srcu_struct to count active readers (holding srcu_read_lock).
++ *
++ * Note that this is not an atomic primitive, and can therefore suffer
++ * severe errors when invoked on an active srcu_struct. That said, it
++ * can be useful as an error check at cleanup time.
++ */
++int srcu_readers_active(struct srcu_struct *sp)
++{
++ return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
++}
++
++/**
++ * cleanup_srcu_struct - deconstruct a sleep-RCU structure
++ * @sp: structure to clean up.
++ *
++ * Must invoke this after you are finished using a given srcu_struct that
++ * was initialized via init_srcu_struct(), else you leak memory.
++ */
++void cleanup_srcu_struct(struct srcu_struct *sp)
++{
++ int sum;
++
++ sum = srcu_readers_active(sp);
++ WARN_ON(sum); /* Leakage unless caller handles error. */
++ if (sum != 0)
++ return;
++ free_percpu(sp->per_cpu_ref);
++ sp->per_cpu_ref = NULL;
++}
++
++/**
++ * srcu_read_lock - register a new reader for an SRCU-protected structure.
++ * @sp: srcu_struct in which to register the new reader.
++ *
++ * Counts the new reader in the appropriate per-CPU element of the
++ * srcu_struct. Must be called from process context.
++ * Returns an index that must be passed to the matching srcu_read_unlock().
++ */
++int srcu_read_lock(struct srcu_struct *sp)
++{
++ int idx;
++
++ preempt_disable();
++ idx = sp->completed & 0x1;
++ barrier(); /* ensure compiler looks -once- at sp->completed. */
++ per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]++;
++ srcu_barrier(); /* ensure compiler won't misorder critical section. */
++ preempt_enable();
++ return idx;
++}
++
++/**
++ * srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
++ * @sp: srcu_struct in which to unregister the old reader.
++ * @idx: return value from corresponding srcu_read_lock().
++ *
++ * Removes the count for the old reader from the appropriate per-CPU
++ * element of the srcu_struct. Note that this may well be a different
++ * CPU than that which was incremented by the corresponding srcu_read_lock().
++ * Must be called from process context.
++ */
++void srcu_read_unlock(struct srcu_struct *sp, int idx)
++{
++ preempt_disable();
++ srcu_barrier(); /* ensure compiler won't misorder critical section. */
++ per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--;
++ preempt_enable();
++}
++
++/**
++ * synchronize_srcu - wait for prior SRCU read-side critical-section completion
++ * @sp: srcu_struct with which to synchronize.
++ *
++ * Flip the completed counter, and wait for the old count to drain to zero.
++ * As with classic RCU, the updater must use some separate means of
++ * synchronizing concurrent updates. Can block; must be called from
++ * process context.
++ *
++ * Note that it is illegal to call synchornize_srcu() from the corresponding
++ * SRCU read-side critical section; doing so will result in deadlock.
++ * However, it is perfectly legal to call synchronize_srcu() on one
++ * srcu_struct from some other srcu_struct's read-side critical section.
++ */
++void synchronize_srcu(struct srcu_struct *sp)
++{
++ int idx;
++
++ idx = sp->completed;
++ mutex_lock(&sp->mutex);
++
++ /*
++ * Check to see if someone else did the work for us while we were
++ * waiting to acquire the lock. We need -two- advances of
++ * the counter, not just one. If there was but one, we might have
++ * shown up -after- our helper's first synchronize_sched(), thus
++ * having failed to prevent CPU-reordering races with concurrent
++ * srcu_read_unlock()s on other CPUs (see comment below). So we
++ * either (1) wait for two or (2) supply the second ourselves.
++ */
++
++ if ((sp->completed - idx) >= 2) {
++ mutex_unlock(&sp->mutex);
++ return;
++ }
++
++ synchronize_sched(); /* Force memory barrier on all CPUs. */
++
++ /*
++ * The preceding synchronize_sched() ensures that any CPU that
++ * sees the new value of sp->completed will also see any preceding
++ * changes to data structures made by this CPU. This prevents
++ * some other CPU from reordering the accesses in its SRCU
++ * read-side critical section to precede the corresponding
++ * srcu_read_lock() -- ensuring that such references will in
++ * fact be protected.
++ *
++ * So it is now safe to do the flip.
++ */
++
++ idx = sp->completed & 0x1;
++ sp->completed++;
++
++ synchronize_sched(); /* Force memory barrier on all CPUs. */
++
++ /*
++ * At this point, because of the preceding synchronize_sched(),
++ * all srcu_read_lock() calls using the old counters have completed.
++ * Their corresponding critical sections might well be still
++ * executing, but the srcu_read_lock() primitives themselves
++ * will have finished executing.
++ */
++
++ while (srcu_readers_active_idx(sp, idx))
++ schedule_timeout_interruptible(1);
++
++ synchronize_sched(); /* Force memory barrier on all CPUs. */
++
++ /*
++ * The preceding synchronize_sched() forces all srcu_read_unlock()
++ * primitives that were executing concurrently with the preceding
++ * for_each_possible_cpu() loop to have completed by this point.
++ * More importantly, it also forces the corresponding SRCU read-side
++ * critical sections to have also completed, and the corresponding
++ * references to SRCU-protected data items to be dropped.
++ *
++ * Note:
++ *
++ * Despite what you might think at first glance, the
++ * preceding synchronize_sched() -must- be within the
++ * critical section ended by the following mutex_unlock().
++ * Otherwise, a task taking the early exit can race
++ * with a srcu_read_unlock(), which might have executed
++ * just before the preceding srcu_readers_active() check,
++ * and whose CPU might have reordered the srcu_read_unlock()
++ * with the preceding critical section. In this case, there
++ * is nothing preventing the synchronize_sched() task that is
++ * taking the early exit from freeing a data structure that
++ * is still being referenced (out of order) by the task
++ * doing the srcu_read_unlock().
++ *
++ * Alternatively, the comparison with "2" on the early exit
++ * could be changed to "3", but this increases synchronize_srcu()
++ * latency for bulk loads. So the current code is preferred.
++ */
++
++ mutex_unlock(&sp->mutex);
++}
++
++/**
++ * srcu_batches_completed - return batches completed.
++ * @sp: srcu_struct on which to report batch completion.
++ *
++ * Report the number of batches, correlated with, but not necessarily
++ * precisely the same as, the number of grace periods that have elapsed.
++ */
++
++long srcu_batches_completed(struct srcu_struct *sp)
++{
++ return sp->completed;
++}
++
++EXPORT_SYMBOL_GPL(init_srcu_struct);
++EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
++EXPORT_SYMBOL_GPL(srcu_read_lock);
++EXPORT_SYMBOL_GPL(srcu_read_unlock);
++EXPORT_SYMBOL_GPL(synchronize_srcu);
++EXPORT_SYMBOL_GPL(srcu_batches_completed);
++EXPORT_SYMBOL_GPL(srcu_readers_active);
+diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
+index 51cacd1..1245804 100644
+--- a/kernel/stop_machine.c
++++ b/kernel/stop_machine.c
+@@ -1,3 +1,6 @@
++/* Copyright 2005 Rusty Russell rusty at rustcorp.com.au IBM Corporation.
++ * GPL v2 and any later version.
++ */
+ #include <linux/stop_machine.h>
+ #include <linux/kthread.h>
+ #include <linux/sched.h>
+diff --git a/kernel/sys.c b/kernel/sys.c
+index e236f98..98489d8 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -28,6 +28,7 @@
+ #include <linux/tty.h>
+ #include <linux/signal.h>
+ #include <linux/cn_proc.h>
++#include <linux/getcpu.h>
+
+ #include <linux/compat.h>
+ #include <linux/syscalls.h>
+@@ -91,7 +92,8 @@ EXPORT_SYMBOL(fs_overflowgid);
+ */
+
+ int C_A_D = 1;
+-int cad_pid = 1;
++struct pid *cad_pid;
++EXPORT_SYMBOL(cad_pid);
+
+ /*
+ * Notifier list for kernel code which wants to be called
+@@ -151,7 +153,7 @@ static int __kprobes notifier_call_chain
+
+ /*
+ * Atomic notifier chain routines. Registration and unregistration
+- * use a mutex, and call_chain is synchronized by RCU (no locks).
++ * use a spinlock, and call_chain is synchronized by RCU (no locks).
+ */
+
+ /**
+@@ -220,7 +222,7 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_
+ * of the last notifier function called.
+ */
+
+-int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
++int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+ unsigned long val, void *v)
+ {
+ int ret;
+@@ -399,6 +401,129 @@ int raw_notifier_call_chain(struct raw_n
+
+ EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
+
++/*
++ * SRCU notifier chain routines. Registration and unregistration
++ * use a mutex, and call_chain is synchronized by SRCU (no locks).
++ */
++
++/**
++ * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain
++ * @nh: Pointer to head of the SRCU notifier chain
++ * @n: New entry in notifier chain
++ *
++ * Adds a notifier to an SRCU notifier chain.
++ * Must be called in process context.
++ *
++ * Currently always returns zero.
++ */
++
++int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
++ struct notifier_block *n)
++{
++ int ret;
++
++ /*
++ * This code gets used during boot-up, when task switching is
++ * not yet working and interrupts must remain disabled. At
++ * such times we must not call mutex_lock().
++ */
++ if (unlikely(system_state == SYSTEM_BOOTING))
++ return notifier_chain_register(&nh->head, n);
++
++ mutex_lock(&nh->mutex);
++ ret = notifier_chain_register(&nh->head, n);
++ mutex_unlock(&nh->mutex);
++ return ret;
++}
++
++EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
++
++/**
++ * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain
++ * @nh: Pointer to head of the SRCU notifier chain
++ * @n: Entry to remove from notifier chain
++ *
++ * Removes a notifier from an SRCU notifier chain.
++ * Must be called from process context.
++ *
++ * Returns zero on success or %-ENOENT on failure.
++ */
++int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
++ struct notifier_block *n)
++{
++ int ret;
++
++ /*
++ * This code gets used during boot-up, when task switching is
++ * not yet working and interrupts must remain disabled. At
++ * such times we must not call mutex_lock().
++ */
++ if (unlikely(system_state == SYSTEM_BOOTING))
++ return notifier_chain_unregister(&nh->head, n);
++
++ mutex_lock(&nh->mutex);
++ ret = notifier_chain_unregister(&nh->head, n);
++ mutex_unlock(&nh->mutex);
++ synchronize_srcu(&nh->srcu);
++ return ret;
++}
++
++EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
++
++/**
++ * srcu_notifier_call_chain - Call functions in an SRCU notifier chain
++ * @nh: Pointer to head of the SRCU notifier chain
++ * @val: Value passed unmodified to notifier function
++ * @v: Pointer passed unmodified to notifier function
++ *
++ * Calls each function in a notifier chain in turn. The functions
++ * run in a process context, so they are allowed to block.
++ *
++ * If the return value of the notifier can be and'ed
++ * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain
++ * will return immediately, with the return value of
++ * the notifier function which halted execution.
++ * Otherwise the return value is the return value
++ * of the last notifier function called.
++ */
++
++int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
++ unsigned long val, void *v)
++{
++ int ret;
++ int idx;
++
++ idx = srcu_read_lock(&nh->srcu);
++ ret = notifier_call_chain(&nh->head, val, v);
++ srcu_read_unlock(&nh->srcu, idx);
++ return ret;
++}
++
++EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
++
++/**
++ * srcu_init_notifier_head - Initialize an SRCU notifier head
++ * @nh: Pointer to head of the srcu notifier chain
++ *
++ * Unlike other sorts of notifier heads, SRCU notifier heads require
++ * dynamic initialization. Be sure to call this routine before
++ * calling any of the other SRCU notifier routines for this head.
++ *
++ * If an SRCU notifier head is deallocated, it must first be cleaned
++ * up by calling srcu_cleanup_notifier_head(). Otherwise the head's
++ * per-cpu data (used by the SRCU mechanism) will leak.
++ */
++
++void srcu_init_notifier_head(struct srcu_notifier_head *nh)
++{
++ mutex_init(&nh->mutex);
++ if (init_srcu_struct(&nh->srcu) < 0)
++ BUG();
++ nh->head = NULL;
++}
++
++EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
++
+ /**
+ * register_reboot_notifier - Register function to be called at reboot time
+ * @nb: Info about notifier function to be called
+@@ -606,12 +731,10 @@ static void kernel_restart_prepare(char
+ void kernel_restart(char *cmd)
+ {
+ kernel_restart_prepare(cmd);
+- if (!cmd) {
++ if (!cmd)
+ printk(KERN_EMERG "Restarting system.\n");
+- } else {
++ else
+ printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
+- }
+- printk(".\n");
+ machine_restart(cmd);
+ }
+ EXPORT_SYMBOL_GPL(kernel_restart);
+@@ -627,9 +750,8 @@ static void kernel_kexec(void)
+ #ifdef CONFIG_KEXEC
+ struct kimage *image;
+ image = xchg(&kexec_image, NULL);
+- if (!image) {
++ if (!image)
+ return;
+- }
+ kernel_restart_prepare(NULL);
+ printk(KERN_EMERG "Starting new kernel\n");
+ machine_shutdown();
+@@ -775,10 +897,9 @@ void ctrl_alt_del(void)
+ if (C_A_D)
+ schedule_work(&cad_work);
+ else
+- kill_proc(cad_pid, SIGINT, 1);
++ kill_cad_pid(SIGINT, 1);
+ }
+
+-
+ /*
+ * Unprivileged users may change the real gid to the effective gid
+ * or vice versa. (BSD-style)
+@@ -823,12 +944,10 @@ asmlinkage long sys_setregid(gid_t rgid,
+ (current->sgid == egid) ||
+ capable(CAP_SETGID))
+ new_egid = egid;
+- else {
++ else
+ return -EPERM;
+- }
+ }
+- if (new_egid != old_egid)
+- {
++ if (new_egid != old_egid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -857,19 +976,14 @@ asmlinkage long sys_setgid(gid_t gid)
+ if (retval)
+ return retval;
+
+- if (capable(CAP_SETGID))
+- {
+- if(old_egid != gid)
+- {
++ if (capable(CAP_SETGID)) {
++ if (old_egid != gid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+ current->gid = current->egid = current->sgid = current->fsgid = gid;
+- }
+- else if ((gid == current->gid) || (gid == current->sgid))
+- {
+- if(old_egid != gid)
+- {
++ } else if ((gid == current->gid) || (gid == current->sgid)) {
++ if (old_egid != gid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -900,8 +1014,7 @@ static int set_user(uid_t new_ruid, int
+
+ switch_uid(new_user);
+
+- if(dumpclear)
+- {
++ if (dumpclear) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -957,8 +1070,7 @@ asmlinkage long sys_setreuid(uid_t ruid,
+ if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
+ return -EAGAIN;
+
+- if (new_euid != old_euid)
+- {
++ if (new_euid != old_euid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -1008,8 +1120,7 @@ asmlinkage long sys_setuid(uid_t uid)
+ } else if ((uid != current->uid) && (uid != new_suid))
+ return -EPERM;
+
+- if (old_euid != uid)
+- {
++ if (old_euid != uid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -1054,8 +1165,7 @@ asmlinkage long sys_setresuid(uid_t ruid
+ return -EAGAIN;
+ }
+ if (euid != (uid_t) -1) {
+- if (euid != current->euid)
+- {
++ if (euid != current->euid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -1105,8 +1215,7 @@ asmlinkage long sys_setresgid(gid_t rgid
+ return -EPERM;
+ }
+ if (egid != (gid_t) -1) {
+- if (egid != current->egid)
+- {
++ if (egid != current->egid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -1151,10 +1260,8 @@ asmlinkage long sys_setfsuid(uid_t uid)
+
+ if (uid == current->uid || uid == current->euid ||
+ uid == current->suid || uid == current->fsuid ||
+- capable(CAP_SETUID))
+- {
+- if (uid != old_fsuid)
+- {
++ capable(CAP_SETUID)) {
++ if (uid != old_fsuid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -1182,10 +1289,8 @@ asmlinkage long sys_setfsgid(gid_t gid)
+
+ if (gid == current->gid || gid == current->egid ||
+ gid == current->sgid || gid == current->fsgid ||
+- capable(CAP_SETGID))
+- {
+- if (gid != old_fsgid)
+- {
++ capable(CAP_SETGID)) {
++ if (gid != old_fsgid) {
+ current->mm->dumpable = suid_dumpable;
+ smp_wmb();
+ }
+@@ -1321,9 +1426,9 @@ out:
+
+ asmlinkage long sys_getpgid(pid_t pid)
+ {
+- if (!pid) {
++ if (!pid)
+ return process_group(current);
+- } else {
++ else {
+ int retval;
+ struct task_struct *p;
+
+@@ -1353,9 +1458,9 @@ asmlinkage long sys_getpgrp(void)
+
+ asmlinkage long sys_getsid(pid_t pid)
+ {
+- if (!pid) {
++ if (!pid)
+ return current->signal->session;
+- } else {
++ else {
+ int retval;
+ struct task_struct *p;
+
+@@ -1363,7 +1468,7 @@ asmlinkage long sys_getsid(pid_t pid)
+ p = find_task_by_pid(pid);
+
+ retval = -ESRCH;
+- if(p) {
++ if (p) {
+ retval = security_task_getsid(p);
+ if (!retval)
+ retval = p->signal->session;
+@@ -1431,9 +1536,9 @@ struct group_info *groups_alloc(int gids
+ group_info->nblocks = nblocks;
+ atomic_set(&group_info->usage, 1);
+
+- if (gidsetsize <= NGROUPS_SMALL) {
++ if (gidsetsize <= NGROUPS_SMALL)
+ group_info->blocks[0] = group_info->small_block;
+- } else {
++ else {
+ for (i = 0; i < nblocks; i++) {
+ gid_t *b;
+ b = (void *)__get_free_page(GFP_USER);
+@@ -1489,7 +1594,7 @@ static int groups_to_user(gid_t __user *
+ /* fill a group_info from a user-space array - it must be allocated already */
+ static int groups_from_user(struct group_info *group_info,
+ gid_t __user *grouplist)
+- {
++{
+ int i;
+ int count = group_info->ngroups;
+
+@@ -1647,9 +1752,8 @@ asmlinkage long sys_setgroups(int gidset
+ int in_group_p(gid_t grp)
+ {
+ int retval = 1;
+- if (grp != current->fsgid) {
++ if (grp != current->fsgid)
+ retval = groups_search(current->group_info, grp);
+- }
+ return retval;
+ }
+
+@@ -1658,9 +1762,8 @@ EXPORT_SYMBOL(in_group_p);
+ int in_egroup_p(gid_t grp)
+ {
+ int retval = 1;
+- if (grp != current->egid) {
++ if (grp != current->egid)
+ retval = groups_search(current->group_info, grp);
+- }
+ return retval;
+ }
+
+@@ -1675,7 +1778,7 @@ asmlinkage long sys_newuname(struct new_
+ int errno = 0;
+
+ down_read(&uts_sem);
+- if (copy_to_user(name,&system_utsname,sizeof *name))
++ if (copy_to_user(name, utsname(), sizeof *name))
+ errno = -EFAULT;
+ up_read(&uts_sem);
+ return errno;
+@@ -1693,8 +1796,8 @@ asmlinkage long sys_sethostname(char __u
+ down_write(&uts_sem);
+ errno = -EFAULT;
+ if (!copy_from_user(tmp, name, len)) {
+- memcpy(system_utsname.nodename, tmp, len);
+- system_utsname.nodename[len] = 0;
++ memcpy(utsname()->nodename, tmp, len);
++ utsname()->nodename[len] = 0;
+ errno = 0;
+ }
+ up_write(&uts_sem);
+@@ -1710,11 +1813,11 @@ asmlinkage long sys_gethostname(char __u
+ if (len < 0)
+ return -EINVAL;
+ down_read(&uts_sem);
+- i = 1 + strlen(system_utsname.nodename);
++ i = 1 + strlen(utsname()->nodename);
+ if (i > len)
+ i = len;
+ errno = 0;
+- if (copy_to_user(name, system_utsname.nodename, i))
++ if (copy_to_user(name, utsname()->nodename, i))
+ errno = -EFAULT;
+ up_read(&uts_sem);
+ return errno;
+@@ -1739,8 +1842,8 @@ asmlinkage long sys_setdomainname(char _
+ down_write(&uts_sem);
+ errno = -EFAULT;
+ if (!copy_from_user(tmp, name, len)) {
+- memcpy(system_utsname.domainname, tmp, len);
+- system_utsname.domainname[len] = 0;
++ memcpy(utsname()->domainname, tmp, len);
++ utsname()->domainname[len] = 0;
+ errno = 0;
+ }
+ up_write(&uts_sem);
+@@ -1775,9 +1878,9 @@ asmlinkage long sys_old_getrlimit(unsign
+ task_lock(current->group_leader);
+ x = current->signal->rlim[resource];
+ task_unlock(current->group_leader);
+- if(x.rlim_cur > 0x7FFFFFFF)
++ if (x.rlim_cur > 0x7FFFFFFF)
+ x.rlim_cur = 0x7FFFFFFF;
+- if(x.rlim_max > 0x7FFFFFFF)
++ if (x.rlim_max > 0x7FFFFFFF)
+ x.rlim_max = 0x7FFFFFFF;
+ return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
+ }
+@@ -2062,3 +2165,33 @@ asmlinkage long sys_prctl(int option, un
+ }
+ return error;
+ }
++
++asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
++ struct getcpu_cache __user *cache)
++{
++ int err = 0;
++ int cpu = raw_smp_processor_id();
++ if (cpup)
++ err |= put_user(cpu, cpup);
++ if (nodep)
++ err |= put_user(cpu_to_node(cpu), nodep);
++ if (cache) {
++ /*
++ * The cache is not needed for this implementation,
++ * but make sure user programs pass something
++ * valid. vsyscall implementations can instead make
++ * good use of the cache. Only use t0 and t1 because
++ * these are available in both 32bit and 64bit ABI (no
++ * need for a compat_getcpu). 32bit has enough
++ * padding
++ */
++ unsigned long t0, t1;
++ get_user(t0, &cache->blob[0]);
++ get_user(t1, &cache->blob[1]);
++ t0++;
++ t1++;
++ put_user(t0, &cache->blob[0]);
++ put_user(t1, &cache->blob[1]);
++ }
++ return err ? -EFAULT : 0;
++}
+diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
+index 6991bec..d7306d0 100644
+--- a/kernel/sys_ni.c
++++ b/kernel/sys_ni.c
+@@ -49,6 +49,7 @@ cond_syscall(compat_sys_get_robust_list)
+ cond_syscall(sys_epoll_create);
+ cond_syscall(sys_epoll_ctl);
+ cond_syscall(sys_epoll_wait);
++cond_syscall(sys_epoll_pwait);
+ cond_syscall(sys_semget);
+ cond_syscall(sys_semop);
+ cond_syscall(sys_semtimedop);
+@@ -134,3 +135,9 @@ cond_syscall(sys_madvise);
+ cond_syscall(sys_mremap);
+ cond_syscall(sys_remap_file_pages);
+ cond_syscall(compat_sys_move_pages);
++cond_syscall(compat_sys_migrate_pages);
++
++/* block-layer dependent */
++cond_syscall(sys_bdflush);
++cond_syscall(sys_ioprio_set);
++cond_syscall(sys_ioprio_get);
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 362a0cc..09e569f 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -52,6 +52,10 @@
+ extern int proc_nr_files(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+
++#ifdef CONFIG_X86
++#include <asm/nmi.h>
++#endif
++
+ #if defined(CONFIG_SYSCTL)
+
+ /* External variables not in a header file. */
+@@ -64,7 +68,6 @@ extern int sysrq_enabled;
+ extern int core_uses_pid;
+ extern int suid_dumpable;
+ extern char core_pattern[];
+-extern int cad_pid;
+ extern int pid_max;
+ extern int min_free_kbytes;
+ extern int printk_ratelimit_jiffies;
+@@ -74,12 +77,6 @@ extern int sysctl_drop_caches;
+ extern int percpu_pagelist_fraction;
+ extern int compat_log;
+
+-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
+-int unknown_nmi_panic;
+-extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *,
+- void __user *, size_t *, loff_t *);
+-#endif
+-
+ /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
+ static int maxolduid = 65535;
+ static int minolduid;
+@@ -94,13 +91,8 @@ extern char modprobe_path[];
+ extern int sg_big_buff;
+ #endif
+ #ifdef CONFIG_SYSVIPC
+-extern size_t shm_ctlmax;
+-extern size_t shm_ctlall;
+-extern int shm_ctlmni;
+-extern int msg_ctlmax;
+-extern int msg_ctlmnb;
+-extern int msg_ctlmni;
+-extern int sem_ctls[];
++static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos);
+ #endif
+
+ #ifdef __sparc__
+@@ -136,10 +128,18 @@ extern int no_unaligned_warning;
+ extern int max_lock_depth;
+ #endif
+
+-static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
+- ctl_table *, void **);
+-static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
++#ifdef CONFIG_SYSCTL_SYSCALL
++static int parse_table(int __user *, int, void __user *, size_t __user *,
++ void __user *, size_t, ctl_table *, void **);
++#endif
++
++static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos);
++
++#ifdef CONFIG_PROC_SYSCTL
++static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
++#endif
+
+ static ctl_table root_table[];
+ static struct ctl_table_header root_table_header =
+@@ -164,7 +164,7 @@ int sysctl_legacy_va_layout;
+
+ /* /proc declarations: */
+
+-#ifdef CONFIG_PROC_FS
++#ifdef CONFIG_PROC_SYSCTL
+
+ static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *);
+ static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *);
+@@ -228,51 +228,100 @@ static ctl_table root_table[] = {
+ };
+
+ static ctl_table kern_table[] = {
++#ifndef CONFIG_UTS_NS
++ {
++ .ctl_name = KERN_OSTYPE,
++ .procname = "ostype",
++ .data = init_uts_ns.name.sysname,
++ .maxlen = sizeof(init_uts_ns.name.sysname),
++ .mode = 0444,
++ .proc_handler = &proc_do_uts_string,
++ .strategy = &sysctl_string,
++ },
++ {
++ .ctl_name = KERN_OSRELEASE,
++ .procname = "osrelease",
++ .data = init_uts_ns.name.release,
++ .maxlen = sizeof(init_uts_ns.name.release),
++ .mode = 0444,
++ .proc_handler = &proc_do_uts_string,
++ .strategy = &sysctl_string,
++ },
++ {
++ .ctl_name = KERN_VERSION,
++ .procname = "version",
++ .data = init_uts_ns.name.version,
++ .maxlen = sizeof(init_uts_ns.name.version),
++ .mode = 0444,
++ .proc_handler = &proc_do_uts_string,
++ .strategy = &sysctl_string,
++ },
++ {
++ .ctl_name = KERN_NODENAME,
++ .procname = "hostname",
++ .data = init_uts_ns.name.nodename,
++ .maxlen = sizeof(init_uts_ns.name.nodename),
++ .mode = 0644,
++ .proc_handler = &proc_do_uts_string,
++ .strategy = &sysctl_string,
++ },
++ {
++ .ctl_name = KERN_DOMAINNAME,
++ .procname = "domainname",
++ .data = init_uts_ns.name.domainname,
++ .maxlen = sizeof(init_uts_ns.name.domainname),
++ .mode = 0644,
++ .proc_handler = &proc_do_uts_string,
++ .strategy = &sysctl_string,
++ },
++#else /* !CONFIG_UTS_NS */
+ {
+ .ctl_name = KERN_OSTYPE,
+ .procname = "ostype",
+- .data = system_utsname.sysname,
+- .maxlen = sizeof(system_utsname.sysname),
++ .data = NULL,
++ /* could maybe use __NEW_UTS_LEN here? */
++ .maxlen = FIELD_SIZEOF(struct new_utsname, sysname),
+ .mode = 0444,
+- .proc_handler = &proc_doutsstring,
++ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_OSRELEASE,
+ .procname = "osrelease",
+- .data = system_utsname.release,
+- .maxlen = sizeof(system_utsname.release),
++ .data = NULL,
++ .maxlen = FIELD_SIZEOF(struct new_utsname, release),
+ .mode = 0444,
+- .proc_handler = &proc_doutsstring,
++ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_VERSION,
+ .procname = "version",
+- .data = system_utsname.version,
+- .maxlen = sizeof(system_utsname.version),
++ .data = NULL,
++ .maxlen = FIELD_SIZEOF(struct new_utsname, version),
+ .mode = 0444,
+- .proc_handler = &proc_doutsstring,
++ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_NODENAME,
+ .procname = "hostname",
+- .data = system_utsname.nodename,
+- .maxlen = sizeof(system_utsname.nodename),
++ .data = NULL,
++ .maxlen = FIELD_SIZEOF(struct new_utsname, nodename),
+ .mode = 0644,
+- .proc_handler = &proc_doutsstring,
++ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_DOMAINNAME,
+ .procname = "domainname",
+- .data = system_utsname.domainname,
+- .maxlen = sizeof(system_utsname.domainname),
++ .data = NULL,
++ .maxlen = FIELD_SIZEOF(struct new_utsname, domainname),
+ .mode = 0644,
+- .proc_handler = &proc_doutsstring,
++ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
++#endif /* !CONFIG_UTS_NS */
+ {
+ .ctl_name = KERN_PANIC,
+ .procname = "panic",
+@@ -293,7 +342,7 @@ static ctl_table kern_table[] = {
+ .ctl_name = KERN_CORE_PATTERN,
+ .procname = "core_pattern",
+ .data = core_pattern,
+- .maxlen = 64,
++ .maxlen = 128,
+ .mode = 0644,
+ .proc_handler = &proc_dostring,
+ .strategy = &sysctl_string,
+@@ -431,58 +480,58 @@ static ctl_table kern_table[] = {
+ {
+ .ctl_name = KERN_SHMMAX,
+ .procname = "shmmax",
+- .data = &shm_ctlmax,
++ .data = NULL,
+ .maxlen = sizeof (size_t),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_minmax,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ {
+ .ctl_name = KERN_SHMALL,
+ .procname = "shmall",
+- .data = &shm_ctlall,
++ .data = NULL,
+ .maxlen = sizeof (size_t),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_minmax,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ {
+ .ctl_name = KERN_SHMMNI,
+ .procname = "shmmni",
+- .data = &shm_ctlmni,
++ .data = NULL,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ {
+ .ctl_name = KERN_MSGMAX,
+ .procname = "msgmax",
+- .data = &msg_ctlmax,
++ .data = NULL,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ {
+ .ctl_name = KERN_MSGMNI,
+ .procname = "msgmni",
+- .data = &msg_ctlmni,
++ .data = NULL,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ {
+ .ctl_name = KERN_MSGMNB,
+ .procname = "msgmnb",
+- .data = &msg_ctlmnb,
++ .data = NULL,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ {
+ .ctl_name = KERN_SEM,
+ .procname = "sem",
+- .data = &sem_ctls,
++ .data = NULL,
+ .maxlen = 4*sizeof (int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_do_ipc_string,
+ },
+ #endif
+ #ifdef CONFIG_MAGIC_SYSRQ
+@@ -495,14 +544,16 @@ static ctl_table kern_table[] = {
+ .proc_handler = &proc_dointvec,
+ },
+ #endif
++#ifdef CONFIG_PROC_SYSCTL
+ {
+ .ctl_name = KERN_CADPID,
+ .procname = "cad_pid",
+- .data = &cad_pid,
++ .data = NULL,
+ .maxlen = sizeof (int),
+ .mode = 0600,
+- .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_do_cad_pid,
+ },
++#endif
+ {
+ .ctl_name = KERN_MAX_THREADS,
+ .procname = "threads-max",
+@@ -628,11 +679,27 @@ static ctl_table kern_table[] = {
+ .data = &unknown_nmi_panic,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+- .proc_handler = &proc_unknown_nmi_panic,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = KERN_NMI_WATCHDOG,
++ .procname = "nmi_watchdog",
++ .data = &nmi_watchdog_enabled,
++ .maxlen = sizeof (int),
++ .mode = 0644,
++ .proc_handler = &proc_nmi_enabled,
+ },
+ #endif
+ #if defined(CONFIG_X86)
+ {
++ .ctl_name = KERN_PANIC_ON_NMI,
++ .procname = "panic_on_unrecovered_nmi",
++ .data = &panic_on_unrecovered_nmi,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
+ .ctl_name = KERN_BOOTLOADER_TYPE,
+ .procname = "bootloader_type",
+ .data = &bootloader_type,
+@@ -943,6 +1010,17 @@ static ctl_table vm_table[] = {
+ .extra1 = &zero,
+ .extra2 = &one_hundred,
+ },
++ {
++ .ctl_name = VM_MIN_SLAB,
++ .procname = "min_slab_ratio",
++ .data = &sysctl_min_slab_ratio,
++ .maxlen = sizeof(sysctl_min_slab_ratio),
++ .mode = 0644,
++ .proc_handler = &sysctl_min_slab_ratio_sysctl_handler,
++ .strategy = &sysctl_intvec,
++ .extra1 = &zero,
++ .extra2 = &one_hundred,
++ },
+ #endif
+ #ifdef CONFIG_X86_32
+ {
+@@ -1138,12 +1216,13 @@ static void start_unregistering(struct c
+
+ void __init sysctl_init(void)
+ {
+-#ifdef CONFIG_PROC_FS
++#ifdef CONFIG_PROC_SYSCTL
+ register_proc_table(root_table, proc_sys_root, &root_table_header);
+ init_irq_proc();
+ #endif
+ }
+
++#ifdef CONFIG_SYSCTL_SYSCALL
+ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+ {
+@@ -1197,6 +1276,7 @@ asmlinkage long sys_sysctl(struct __sysc
+ unlock_kernel();
+ return error;
+ }
++#endif /* CONFIG_SYSCTL_SYSCALL */
+
+ /*
+ * ctl_perm does NOT grant the superuser all rights automatically, because
+@@ -1223,6 +1303,7 @@ static inline int ctl_perm(ctl_table *ta
+ return test_perm(table->mode, op);
+ }
+
++#ifdef CONFIG_SYSCTL_SYSCALL
+ static int parse_table(int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen,
+@@ -1234,7 +1315,9 @@ repeat:
+ return -ENOTDIR;
+ if (get_user(n, name))
+ return -EFAULT;
+- for ( ; table->ctl_name; table++) {
++ for ( ; table->ctl_name || table->procname; table++) {
++ if (!table->ctl_name)
++ continue;
+ if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
+ int error;
+ if (table->child) {
+@@ -1312,6 +1395,7 @@ int do_sysctl_strategy (ctl_table *table
+ }
+ return 0;
+ }
++#endif /* CONFIG_SYSCTL_SYSCALL */
+
+ /**
+ * register_sysctl_table - register a sysctl hierarchy
+@@ -1399,7 +1483,7 @@ struct ctl_table_header *register_sysctl
+ else
+ list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
+ spin_unlock(&sysctl_lock);
+-#ifdef CONFIG_PROC_FS
++#ifdef CONFIG_PROC_SYSCTL
+ register_proc_table(table, proc_sys_root, tmp);
+ #endif
+ return tmp;
+@@ -1417,18 +1501,31 @@ void unregister_sysctl_table(struct ctl_
+ might_sleep();
+ spin_lock(&sysctl_lock);
+ start_unregistering(header);
+-#ifdef CONFIG_PROC_FS
++#ifdef CONFIG_PROC_SYSCTL
+ unregister_proc_table(header->ctl_table, proc_sys_root);
+ #endif
+ spin_unlock(&sysctl_lock);
+ kfree(header);
+ }
+
++#else /* !CONFIG_SYSCTL */
++struct ctl_table_header * register_sysctl_table(ctl_table * table,
++ int insert_at_head)
++{
++ return NULL;
++}
++
++void unregister_sysctl_table(struct ctl_table_header * table)
++{
++}
++
++#endif /* CONFIG_SYSCTL */
++
+ /*
+ * /proc/sys support
+ */
+
+-#ifdef CONFIG_PROC_FS
++#ifdef CONFIG_PROC_SYSCTL
+
+ /* Scan the sysctl entries in table and add them all into /proc */
+ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
+@@ -1437,7 +1534,7 @@ static void register_proc_table(ctl_tabl
+ int len;
+ mode_t mode;
+
+- for (; table->ctl_name; table++) {
++ for (; table->ctl_name || table->procname; table++) {
+ /* Can't do anything without a proc name. */
+ if (!table->procname)
+ continue;
+@@ -1484,7 +1581,7 @@ static void register_proc_table(ctl_tabl
+ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
+ {
+ struct proc_dir_entry *de;
+- for (; table->ctl_name; table++) {
++ for (; table->ctl_name || table->procname; table++) {
+ if (!(de = table->de))
+ continue;
+ if (de->mode & S_IFDIR) {
+@@ -1579,32 +1676,15 @@ static ssize_t proc_writesys(struct file
+ return do_rw_proc(1, file, (char __user *) buf, count, ppos);
+ }
+
+-/**
+- * proc_dostring - read a string sysctl
+- * @table: the sysctl table
+- * @write: %TRUE if this is a write to the sysctl file
+- * @filp: the file structure
+- * @buffer: the user buffer
+- * @lenp: the size of the user buffer
+- * @ppos: file position
+- *
+- * Reads/writes a string from/to the user buffer. If the kernel
+- * buffer provided is not large enough to hold the string, the
+- * string is truncated. The copied string is %NULL-terminated.
+- * If the string is being read by the user process, it is copied
+- * and a newline '\n' is added. It is truncated if the buffer is
+- * not large enough.
+- *
+- * Returns 0 on success.
+- */
+-int proc_dostring(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
++static int _proc_do_string(void* data, int maxlen, int write,
++ struct file *filp, void __user *buffer,
++ size_t *lenp, loff_t *ppos)
+ {
+ size_t len;
+ char __user *p;
+ char c;
+
+- if (!table->data || !table->maxlen || !*lenp ||
++ if (!data || !maxlen || !*lenp ||
+ (*ppos && !write)) {
+ *lenp = 0;
+ return 0;
+@@ -1620,20 +1700,20 @@ int proc_dostring(ctl_table *table, int
+ break;
+ len++;
+ }
+- if (len >= table->maxlen)
+- len = table->maxlen-1;
+- if(copy_from_user(table->data, buffer, len))
++ if (len >= maxlen)
++ len = maxlen-1;
++ if(copy_from_user(data, buffer, len))
+ return -EFAULT;
+- ((char *) table->data)[len] = 0;
++ ((char *) data)[len] = 0;
+ *ppos += *lenp;
+ } else {
+- len = strlen(table->data);
+- if (len > table->maxlen)
+- len = table->maxlen;
++ len = strlen(data);
++ if (len > maxlen)
++ len = maxlen;
+ if (len > *lenp)
+ len = *lenp;
+ if (len)
+- if(copy_to_user(buffer, table->data, len))
++ if(copy_to_user(buffer, data, len))
+ return -EFAULT;
+ if (len < *lenp) {
+ if(put_user('\n', ((char __user *) buffer) + len))
+@@ -1646,12 +1726,38 @@ int proc_dostring(ctl_table *table, int
+ return 0;
+ }
+
++/**
++ * proc_dostring - read a string sysctl
++ * @table: the sysctl table
++ * @write: %TRUE if this is a write to the sysctl file
++ * @filp: the file structure
++ * @buffer: the user buffer
++ * @lenp: the size of the user buffer
++ * @ppos: file position
++ *
++ * Reads/writes a string from/to the user buffer. If the kernel
++ * buffer provided is not large enough to hold the string, the
++ * string is truncated. The copied string is %NULL-terminated.
++ * If the string is being read by the user process, it is copied
++ * and a newline '\n' is added. It is truncated if the buffer is
++ * not large enough.
++ *
++ * Returns 0 on success.
++ */
++int proc_dostring(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ return _proc_do_string(table->data, table->maxlen, write, filp,
++ buffer, lenp, ppos);
++}
++
+ /*
+ * Special case of dostring for the UTS structure. This has locks
+ * to observe. Should this be in kernel/sys.c ????
+ */
+
+-static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
++#ifndef CONFIG_UTS_NS
++static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+ int r;
+@@ -1667,6 +1773,48 @@ static int proc_doutsstring(ctl_table *t
+ }
+ return r;
+ }
++#else /* !CONFIG_UTS_NS */
++static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ int r;
++ struct uts_namespace* uts_ns = current->nsproxy->uts_ns;
++ char* which;
++
++ switch (table->ctl_name) {
++ case KERN_OSTYPE:
++ which = uts_ns->name.sysname;
++ break;
++ case KERN_NODENAME:
++ which = uts_ns->name.nodename;
++ break;
++ case KERN_OSRELEASE:
++ which = uts_ns->name.release;
++ break;
++ case KERN_VERSION:
++ which = uts_ns->name.version;
++ break;
++ case KERN_DOMAINNAME:
++ which = uts_ns->name.domainname;
++ break;
++ default:
++ r = -EINVAL;
++ goto out;
++ }
++
++ if (!write) {
++ down_read(&uts_sem);
++ r=_proc_do_string(which,table->maxlen,0,filp,buffer,lenp, ppos);
++ up_read(&uts_sem);
++ } else {
++ down_write(&uts_sem);
++ r=_proc_do_string(which,table->maxlen,1,filp,buffer,lenp, ppos);
++ up_write(&uts_sem);
++ }
++ out:
++ return r;
++}
++#endif /* !CONFIG_UTS_NS */
+
+ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
+ int *valp,
+@@ -1687,8 +1835,9 @@ static int do_proc_dointvec_conv(int *ne
+ return 0;
+ }
+
+-static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos,
++static int __do_proc_dointvec(void *tbl_data, ctl_table *table,
++ int write, struct file *filp, void __user *buffer,
++ size_t *lenp, loff_t *ppos,
+ int (*conv)(int *negp, unsigned long *lvalp, int *valp,
+ int write, void *data),
+ void *data)
+@@ -1701,13 +1850,13 @@ static int do_proc_dointvec(ctl_table *t
+ char buf[TMPBUFLEN], *p;
+ char __user *s = buffer;
+
+- if (!table->data || !table->maxlen || !*lenp ||
++ if (!tbl_data || !table->maxlen || !*lenp ||
+ (*ppos && !write)) {
+ *lenp = 0;
+ return 0;
+ }
+
+- i = (int *) table->data;
++ i = (int *) tbl_data;
+ vleft = table->maxlen / sizeof(*i);
+ left = *lenp;
+
+@@ -1796,6 +1945,16 @@ static int do_proc_dointvec(ctl_table *t
+ #undef TMPBUFLEN
+ }
+
++static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos,
++ int (*conv)(int *negp, unsigned long *lvalp, int *valp,
++ int write, void *data),
++ void *data)
++{
++ return __do_proc_dointvec(table->data, table, write, filp,
++ buffer, lenp, ppos, conv, data);
++}
++
+ /**
+ * proc_dointvec - read a vector of integers
+ * @table: the sysctl table
+@@ -1867,7 +2026,7 @@ int proc_dointvec_bset(ctl_table *table,
+ return -EPERM;
+ }
+
+- op = (current->pid == 1) ? OP_SET : OP_AND;
++ op = is_init(current) ? OP_SET : OP_AND;
+ return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
+ do_proc_dointvec_bset_conv,&op);
+ }
+@@ -1929,7 +2088,7 @@ int proc_dointvec_minmax(ctl_table *tabl
+ do_proc_dointvec_minmax_conv, ¶m);
+ }
+
+-static int do_proc_doulongvec_minmax(ctl_table *table, int write,
++static int __do_proc_doulongvec_minmax(void *data, ctl_table *table, int write,
+ struct file *filp,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos,
+@@ -1943,13 +2102,13 @@ static int do_proc_doulongvec_minmax(ctl
+ char buf[TMPBUFLEN], *p;
+ char __user *s = buffer;
+
+- if (!table->data || !table->maxlen || !*lenp ||
++ if (!data || !table->maxlen || !*lenp ||
+ (*ppos && !write)) {
+ *lenp = 0;
+ return 0;
+ }
+
+- i = (unsigned long *) table->data;
++ i = (unsigned long *) data;
+ min = (unsigned long *) table->extra1;
+ max = (unsigned long *) table->extra2;
+ vleft = table->maxlen / sizeof(unsigned long);
+@@ -2034,6 +2193,17 @@ static int do_proc_doulongvec_minmax(ctl
+ #undef TMPBUFLEN
+ }
+
++static int do_proc_doulongvec_minmax(ctl_table *table, int write,
++ struct file *filp,
++ void __user *buffer,
++ size_t *lenp, loff_t *ppos,
++ unsigned long convmul,
++ unsigned long convdiv)
++{
++ return __do_proc_doulongvec_minmax(table->data, table, write,
++ filp, buffer, lenp, ppos, convmul, convdiv);
++}
++
+ /**
+ * proc_doulongvec_minmax - read a vector of long integers with min/max values
+ * @table: the sysctl table
+@@ -2222,6 +2392,71 @@ int proc_dointvec_ms_jiffies(ctl_table *
+ do_proc_dointvec_ms_jiffies_conv, NULL);
+ }
+
++#ifdef CONFIG_SYSVIPC
++static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ void *data;
++ struct ipc_namespace *ns;
++
++ ns = current->nsproxy->ipc_ns;
++
++ switch (table->ctl_name) {
++ case KERN_SHMMAX:
++ data = &ns->shm_ctlmax;
++ goto proc_minmax;
++ case KERN_SHMALL:
++ data = &ns->shm_ctlall;
++ goto proc_minmax;
++ case KERN_SHMMNI:
++ data = &ns->shm_ctlmni;
++ break;
++ case KERN_MSGMAX:
++ data = &ns->msg_ctlmax;
++ break;
++ case KERN_MSGMNI:
++ data = &ns->msg_ctlmni;
++ break;
++ case KERN_MSGMNB:
++ data = &ns->msg_ctlmnb;
++ break;
++ case KERN_SEM:
++ data = &ns->sem_ctls;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return __do_proc_dointvec(data, table, write, filp, buffer,
++ lenp, ppos, NULL, NULL);
++proc_minmax:
++ return __do_proc_doulongvec_minmax(data, table, write, filp, buffer,
++ lenp, ppos, 1l, 1l);
++}
++#endif
++
++static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ struct pid *new_pid;
++ pid_t tmp;
++ int r;
++
++ tmp = pid_nr(cad_pid);
++
++ r = __do_proc_dointvec(&tmp, table, write, filp, buffer,
++ lenp, ppos, NULL, NULL);
++ if (r || !write)
++ return r;
++
++ new_pid = find_get_pid(tmp);
++ if (!new_pid)
++ return -ESRCH;
++
++ put_pid(xchg(&cad_pid, new_pid));
++ return 0;
++}
++
+ #else /* CONFIG_PROC_FS */
+
+ int proc_dostring(ctl_table *table, int write, struct file *filp,
+@@ -2230,11 +2465,19 @@ int proc_dostring(ctl_table *table, int
+ return -ENOSYS;
+ }
+
+-static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
++static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ return -ENOSYS;
++}
++
++#ifdef CONFIG_SYSVIPC
++static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+ return -ENOSYS;
+ }
++#endif
+
+ int proc_dointvec(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+@@ -2290,6 +2533,7 @@ int proc_doulongvec_ms_jiffies_minmax(ct
+ #endif /* CONFIG_PROC_FS */
+
+
++#ifdef CONFIG_SYSCTL_SYSCALL
+ /*
+ * General sysctl support routines
+ */
+@@ -2432,11 +2676,39 @@ int sysctl_ms_jiffies(ctl_table *table,
+ return 1;
+ }
+
+-#else /* CONFIG_SYSCTL */
++#else /* CONFIG_SYSCTL_SYSCALL */
+
+
+ asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
+ {
++ static int msg_count;
++ struct __sysctl_args tmp;
++ int name[CTL_MAXNAME];
++ int i;
++
++ /* Read in the sysctl name for better debug message logging */
++ if (copy_from_user(&tmp, args, sizeof(tmp)))
++ return -EFAULT;
++ if (tmp.nlen <= 0 || tmp.nlen >= CTL_MAXNAME)
++ return -ENOTDIR;
++ for (i = 0; i < tmp.nlen; i++)
++ if (get_user(name[i], tmp.name + i))
++ return -EFAULT;
++
++ /* Ignore accesses to kernel.version */
++ if ((tmp.nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
++ goto out;
++
++ if (msg_count < 5) {
++ msg_count++;
++ printk(KERN_INFO
++ "warning: process `%s' used the removed sysctl "
++ "system call with ", current->comm);
++ for (i = 0; i < tmp.nlen; i++)
++ printk("%d.", name[i]);
++ printk("\n");
++ }
++out:
+ return -ENOSYS;
+ }
+
+@@ -2468,73 +2740,7 @@ int sysctl_ms_jiffies(ctl_table *table,
+ return -ENOSYS;
+ }
+
+-int proc_dostring(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_dointvec(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
+- struct file *filp,
+- void __user *buffer,
+- size_t *lenp, loff_t *ppos)
+-{
+- return -ENOSYS;
+-}
+-
+-struct ctl_table_header * register_sysctl_table(ctl_table * table,
+- int insert_at_head)
+-{
+- return NULL;
+-}
+-
+-void unregister_sysctl_table(struct ctl_table_header * table)
+-{
+-}
+-
+-#endif /* CONFIG_SYSCTL */
++#endif /* CONFIG_SYSCTL_SYSCALL */
+
+ /*
+ * No sense putting this after each symbol definition, twice,
+diff --git a/kernel/taskstats.c b/kernel/taskstats.c
+index e781876..f45c5e7 100644
+--- a/kernel/taskstats.c
++++ b/kernel/taskstats.c
+@@ -18,7 +18,9 @@
+
+ #include <linux/kernel.h>
+ #include <linux/taskstats_kern.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/delayacct.h>
++#include <linux/tsacct_kern.h>
+ #include <linux/cpumask.h>
+ #include <linux/percpu.h>
+ #include <net/genetlink.h>
+@@ -75,7 +77,8 @@ static int prepare_reply(struct genl_inf
+ /*
+ * If new attributes are added, please revisit this allocation
+ */
+- skb = nlmsg_new(size);
++ size = nlmsg_total_size(genlmsg_total_size(size));
++ skb = nlmsg_new(size, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+@@ -172,21 +175,19 @@ static void send_cpu_listeners(struct sk
+ up_write(&listeners->sem);
+ }
+
+-static int fill_pid(pid_t pid, struct task_struct *pidtsk,
++static int fill_pid(pid_t pid, struct task_struct *tsk,
+ struct taskstats *stats)
+ {
+ int rc = 0;
+- struct task_struct *tsk = pidtsk;
+
+- if (!pidtsk) {
+- read_lock(&tasklist_lock);
++ if (!tsk) {
++ rcu_read_lock();
+ tsk = find_task_by_pid(pid);
+- if (!tsk) {
+- read_unlock(&tasklist_lock);
++ if (tsk)
++ get_task_struct(tsk);
++ rcu_read_unlock();
++ if (!tsk)
+ return -ESRCH;
+- }
+- get_task_struct(tsk);
+- read_unlock(&tasklist_lock);
+ } else
+ get_task_struct(tsk);
+
+@@ -198,7 +199,13 @@ static int fill_pid(pid_t pid, struct ta
+ */
+
+ delayacct_add_tsk(stats, tsk);
++
++ /* fill in basic acct fields */
+ stats->version = TASKSTATS_VERSION;
++ bacct_add_tsk(stats, tsk);
++
++ /* fill in extended acct fields */
++ xacct_add_tsk(stats, tsk);
+
+ /* Define err: label here if needed */
+ put_task_struct(tsk);
+@@ -206,39 +213,30 @@ static int fill_pid(pid_t pid, struct ta
+
+ }
+
+-static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk,
++static int fill_tgid(pid_t tgid, struct task_struct *first,
+ struct taskstats *stats)
+ {
+- struct task_struct *tsk, *first;
++ struct task_struct *tsk;
+ unsigned long flags;
++ int rc = -ESRCH;
+
+ /*
+ * Add additional stats from live tasks except zombie thread group
+ * leaders who are already counted with the dead tasks
+ */
+- first = tgidtsk;
+- if (!first) {
+- read_lock(&tasklist_lock);
++ rcu_read_lock();
++ if (!first)
+ first = find_task_by_pid(tgid);
+- if (!first) {
+- read_unlock(&tasklist_lock);
+- return -ESRCH;
+- }
+- get_task_struct(first);
+- read_unlock(&tasklist_lock);
+- } else
+- get_task_struct(first);
+
+- /* Start with stats from dead tasks */
+- spin_lock_irqsave(&first->signal->stats_lock, flags);
++ if (!first || !lock_task_sighand(first, &flags))
++ goto out;
++
+ if (first->signal->stats)
+ memcpy(stats, first->signal->stats, sizeof(*stats));
+- spin_unlock_irqrestore(&first->signal->stats_lock, flags);
+
+ tsk = first;
+- read_lock(&tasklist_lock);
+ do {
+- if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk))
++ if (tsk->exit_state)
+ continue;
+ /*
+ * Accounting subsystem can call its functions here to
+@@ -249,15 +247,18 @@ static int fill_tgid(pid_t tgid, struct
+ delayacct_add_tsk(stats, tsk);
+
+ } while_each_thread(first, tsk);
+- read_unlock(&tasklist_lock);
+- stats->version = TASKSTATS_VERSION;
+
++ unlock_task_sighand(first, &flags);
++ rc = 0;
++out:
++ rcu_read_unlock();
++
++ stats->version = TASKSTATS_VERSION;
+ /*
+ * Accounting subsytems can also add calls here to modify
+ * fields of taskstats.
+ */
+-
+- return 0;
++ return rc;
+ }
+
+
+@@ -265,7 +266,7 @@ static void fill_tgid_exit(struct task_s
+ {
+ unsigned long flags;
+
+- spin_lock_irqsave(&tsk->signal->stats_lock, flags);
++ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ if (!tsk->signal->stats)
+ goto ret;
+
+@@ -277,7 +278,7 @@ static void fill_tgid_exit(struct task_s
+ */
+ delayacct_add_tsk(tsk->signal->stats, tsk);
+ ret:
+- spin_unlock_irqrestore(&tsk->signal->stats_lock, flags);
++ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+ return;
+ }
+
+@@ -411,7 +412,7 @@ static int taskstats_user_cmd(struct sk_
+ return send_reply(rep_skb, info->snd_pid);
+
+ nla_put_failure:
+- return genlmsg_cancel(rep_skb, reply);
++ rc = genlmsg_cancel(rep_skb, reply);
+ err:
+ nlmsg_free(rep_skb);
+ return rc;
+@@ -453,24 +454,26 @@ void taskstats_exit_send(struct task_str
+ size_t size;
+ int is_thread_group;
+ struct nlattr *na;
+- unsigned long flags;
+
+- if (!family_registered || !tidstats)
++ if (!family_registered)
+ return;
+
+- spin_lock_irqsave(&tsk->signal->stats_lock, flags);
+- is_thread_group = tsk->signal->stats ? 1 : 0;
+- spin_unlock_irqrestore(&tsk->signal->stats_lock, flags);
+-
+- rc = 0;
+ /*
+ * Size includes space for nested attributes
+ */
+ size = nla_total_size(sizeof(u32)) +
+ nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+
+- if (is_thread_group)
+- size = 2 * size; /* PID + STATS + TGID + STATS */
++ is_thread_group = (tsk->signal->stats != NULL);
++ if (is_thread_group) {
++ /* PID + STATS + TGID + STATS */
++ size = 2 * size;
++ /* fill the tsk->signal->stats structure */
++ fill_tgid_exit(tsk);
++ }
++
++ if (!tidstats)
++ return;
+
+ rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
+ if (rc < 0)
+@@ -490,11 +493,8 @@ void taskstats_exit_send(struct task_str
+ goto send;
+
+ /*
+- * tsk has/had a thread group so fill the tsk->signal->stats structure
+ * Doesn't matter if tsk is the leader or the last group member leaving
+ */
+-
+- fill_tgid_exit(tsk);
+ if (!group_dead)
+ goto send;
+
+@@ -511,7 +511,6 @@ send:
+
+ nla_put_failure:
+ genlmsg_cancel(rep_skb, reply);
+- goto ret;
+ err_skb:
+ nlmsg_free(rep_skb);
+ ret:
+diff --git a/kernel/time.c b/kernel/time.c
+index 5bd4897..0e017bf 100644
+--- a/kernel/time.c
++++ b/kernel/time.c
+@@ -202,179 +202,6 @@ asmlinkage long sys_settimeofday(struct
+ return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
+ }
+
+-/* we call this to notify the arch when the clock is being
+- * controlled. If no such arch routine, do nothing.
+- */
+-void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+-{
+- return;
+-}
+-
+-/* adjtimex mainly allows reading (and writing, if superuser) of
+- * kernel time-keeping variables. used by xntpd.
+- */
+-int do_adjtimex(struct timex *txc)
+-{
+- long ltemp, mtemp, save_adjust;
+- int result;
+-
+- /* In order to modify anything, you gotta be super-user! */
+- if (txc->modes && !capable(CAP_SYS_TIME))
+- return -EPERM;
+-
+- /* Now we validate the data before disabling interrupts */
+-
+- if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
+- /* singleshot must not be used with any other mode bits */
+- if (txc->modes != ADJ_OFFSET_SINGLESHOT)
+- return -EINVAL;
+-
+- if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
+- /* adjustment Offset limited to +- .512 seconds */
+- if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
+- return -EINVAL;
+-
+- /* if the quartz is off by more than 10% something is VERY wrong ! */
+- if (txc->modes & ADJ_TICK)
+- if (txc->tick < 900000/USER_HZ ||
+- txc->tick > 1100000/USER_HZ)
+- return -EINVAL;
+-
+- write_seqlock_irq(&xtime_lock);
+- result = time_state; /* mostly `TIME_OK' */
+-
+- /* Save for later - semantics of adjtime is to return old value */
+- save_adjust = time_next_adjust ? time_next_adjust : time_adjust;
+-
+-#if 0 /* STA_CLOCKERR is never set yet */
+- time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
+-#endif
+- /* If there are input parameters, then process them */
+- if (txc->modes)
+- {
+- if (txc->modes & ADJ_STATUS) /* only set allowed bits */
+- time_status = (txc->status & ~STA_RONLY) |
+- (time_status & STA_RONLY);
+-
+- if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */
+- if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
+- result = -EINVAL;
+- goto leave;
+- }
+- time_freq = txc->freq;
+- }
+-
+- if (txc->modes & ADJ_MAXERROR) {
+- if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
+- result = -EINVAL;
+- goto leave;
+- }
+- time_maxerror = txc->maxerror;
+- }
+-
+- if (txc->modes & ADJ_ESTERROR) {
+- if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
+- result = -EINVAL;
+- goto leave;
+- }
+- time_esterror = txc->esterror;
+- }
+-
+- if (txc->modes & ADJ_TIMECONST) { /* p. 24 */
+- if (txc->constant < 0) { /* NTP v4 uses values > 6 */
+- result = -EINVAL;
+- goto leave;
+- }
+- time_constant = txc->constant;
+- }
+-
+- if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
+- if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
+- /* adjtime() is independent from ntp_adjtime() */
+- if ((time_next_adjust = txc->offset) == 0)
+- time_adjust = 0;
+- }
+- else if (time_status & STA_PLL) {
+- ltemp = txc->offset;
+-
+- /*
+- * Scale the phase adjustment and
+- * clamp to the operating range.
+- */
+- if (ltemp > MAXPHASE)
+- time_offset = MAXPHASE << SHIFT_UPDATE;
+- else if (ltemp < -MAXPHASE)
+- time_offset = -(MAXPHASE << SHIFT_UPDATE);
+- else
+- time_offset = ltemp << SHIFT_UPDATE;
+-
+- /*
+- * Select whether the frequency is to be controlled
+- * and in which mode (PLL or FLL). Clamp to the operating
+- * range. Ugly multiply/divide should be replaced someday.
+- */
+-
+- if (time_status & STA_FREQHOLD || time_reftime == 0)
+- time_reftime = xtime.tv_sec;
+- mtemp = xtime.tv_sec - time_reftime;
+- time_reftime = xtime.tv_sec;
+- if (time_status & STA_FLL) {
+- if (mtemp >= MINSEC) {
+- ltemp = (time_offset / mtemp) << (SHIFT_USEC -
+- SHIFT_UPDATE);
+- time_freq += shift_right(ltemp, SHIFT_KH);
+- } else /* calibration interval too short (p. 12) */
+- result = TIME_ERROR;
+- } else { /* PLL mode */
+- if (mtemp < MAXSEC) {
+- ltemp *= mtemp;
+- time_freq += shift_right(ltemp,(time_constant +
+- time_constant +
+- SHIFT_KF - SHIFT_USEC));
+- } else /* calibration interval too long (p. 12) */
+- result = TIME_ERROR;
+- }
+- time_freq = min(time_freq, time_tolerance);
+- time_freq = max(time_freq, -time_tolerance);
+- } /* STA_PLL */
+- } /* txc->modes & ADJ_OFFSET */
+- if (txc->modes & ADJ_TICK) {
+- tick_usec = txc->tick;
+- tick_nsec = TICK_USEC_TO_NSEC(tick_usec);
+- }
+- } /* txc->modes */
+-leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
+- result = TIME_ERROR;
+-
+- if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
+- txc->offset = save_adjust;
+- else {
+- txc->offset = shift_right(time_offset, SHIFT_UPDATE);
+- }
+- txc->freq = time_freq;
+- txc->maxerror = time_maxerror;
+- txc->esterror = time_esterror;
+- txc->status = time_status;
+- txc->constant = time_constant;
+- txc->precision = time_precision;
+- txc->tolerance = time_tolerance;
+- txc->tick = tick_usec;
+-
+- /* PPS is not implemented, so these are zero */
+- txc->ppsfreq = 0;
+- txc->jitter = 0;
+- txc->shift = 0;
+- txc->stabil = 0;
+- txc->jitcnt = 0;
+- txc->calcnt = 0;
+- txc->errcnt = 0;
+- txc->stbcnt = 0;
+- write_sequnlock_irq(&xtime_lock);
+- do_gettimeofday(&txc->time);
+- notify_arch_cmos_timer();
+- return(result);
+-}
+-
+ asmlinkage long sys_adjtimex(struct timex __user *txc_p)
+ {
+ struct timex txc; /* Local copy of parameter */
+diff --git a/kernel/time/Makefile b/kernel/time/Makefile
+index e1dfd8e..61a3907 100644
+--- a/kernel/time/Makefile
++++ b/kernel/time/Makefile
+@@ -1 +1 @@
+-obj-y += clocksource.o jiffies.o
++obj-y += ntp.o clocksource.o jiffies.o
+diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
+index 126bb30..a99b2a6 100644
+--- a/kernel/time/jiffies.c
++++ b/kernel/time/jiffies.c
+@@ -57,7 +57,7 @@ static cycle_t jiffies_read(void)
+
+ struct clocksource clocksource_jiffies = {
+ .name = "jiffies",
+- .rating = 0, /* lowest rating*/
++ .rating = 1, /* lowest valid rating*/
+ .read = jiffies_read,
+ .mask = 0xffffffff, /*32bits*/
+ .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+new file mode 100644
+index 0000000..3afeaa3
+--- /dev/null
++++ b/kernel/time/ntp.c
+@@ -0,0 +1,350 @@
++/*
++ * linux/kernel/time/ntp.c
++ *
++ * NTP state machine interfaces and logic.
++ *
++ * This code was mainly moved from kernel/timer.c and kernel/time.c
++ * Please see those files for relevant copyright info and historical
++ * changelogs.
++ */
++
++#include <linux/mm.h>
++#include <linux/time.h>
++#include <linux/timex.h>
++
++#include <asm/div64.h>
++#include <asm/timex.h>
++
++/*
++ * Timekeeping variables
++ */
++unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
++unsigned long tick_nsec; /* ACTHZ period (nsec) */
++static u64 tick_length, tick_length_base;
++
++#define MAX_TICKADJ 500 /* microsecs */
++#define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
++ TICK_LENGTH_SHIFT) / HZ)
++
++/*
++ * phase-lock loop variables
++ */
++/* TIME_ERROR prevents overwriting the CMOS clock */
++static int time_state = TIME_OK; /* clock synchronization status */
++int time_status = STA_UNSYNC; /* clock status bits */
++static long time_offset; /* time adjustment (ns) */
++static long time_constant = 2; /* pll time constant */
++long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
++long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
++long time_freq; /* frequency offset (scaled ppm)*/
++static long time_reftime; /* time at last adjustment (s) */
++long time_adjust;
++
++#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE)
++#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
++ (s64)CLOCK_TICK_RATE)
++
++static void ntp_update_frequency(void)
++{
++ tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT;
++ tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT;
++ tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC);
++
++ do_div(tick_length_base, HZ);
++
++ tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT;
++}
++
++/**
++ * ntp_clear - Clears the NTP state variables
++ *
++ * Must be called while holding a write on the xtime_lock
++ */
++void ntp_clear(void)
++{
++ time_adjust = 0; /* stop active adjtime() */
++ time_status |= STA_UNSYNC;
++ time_maxerror = NTP_PHASE_LIMIT;
++ time_esterror = NTP_PHASE_LIMIT;
++
++ ntp_update_frequency();
++
++ tick_length = tick_length_base;
++ time_offset = 0;
++}
++
++/*
++ * this routine handles the overflow of the microsecond field
++ *
++ * The tricky bits of code to handle the accurate clock support
++ * were provided by Dave Mills (Mills at UDEL.EDU) of NTP fame.
++ * They were originally developed for SUN and DEC kernels.
++ * All the kudos should go to Dave for this stuff.
++ */
++void second_overflow(void)
++{
++ long time_adj;
++
++ /* Bump the maxerror field */
++ time_maxerror += MAXFREQ >> SHIFT_USEC;
++ if (time_maxerror > NTP_PHASE_LIMIT) {
++ time_maxerror = NTP_PHASE_LIMIT;
++ time_status |= STA_UNSYNC;
++ }
++
++ /*
++ * Leap second processing. If in leap-insert state at the end of the
++ * day, the system clock is set back one second; if in leap-delete
++ * state, the system clock is set ahead one second. The microtime()
++ * routine or external clock driver will insure that reported time is
++ * always monotonic. The ugly divides should be replaced.
++ */
++ switch (time_state) {
++ case TIME_OK:
++ if (time_status & STA_INS)
++ time_state = TIME_INS;
++ else if (time_status & STA_DEL)
++ time_state = TIME_DEL;
++ break;
++ case TIME_INS:
++ if (xtime.tv_sec % 86400 == 0) {
++ xtime.tv_sec--;
++ wall_to_monotonic.tv_sec++;
++ /*
++ * The timer interpolator will make time change
++ * gradually instead of an immediate jump by one second
++ */
++ time_interpolator_update(-NSEC_PER_SEC);
++ time_state = TIME_OOP;
++ clock_was_set();
++ printk(KERN_NOTICE "Clock: inserting leap second "
++ "23:59:60 UTC\n");
++ }
++ break;
++ case TIME_DEL:
++ if ((xtime.tv_sec + 1) % 86400 == 0) {
++ xtime.tv_sec++;
++ wall_to_monotonic.tv_sec--;
++ /*
++ * Use of time interpolator for a gradual change of
++ * time
++ */
++ time_interpolator_update(NSEC_PER_SEC);
++ time_state = TIME_WAIT;
++ clock_was_set();
++ printk(KERN_NOTICE "Clock: deleting leap second "
++ "23:59:59 UTC\n");
++ }
++ break;
++ case TIME_OOP:
++ time_state = TIME_WAIT;
++ break;
++ case TIME_WAIT:
++ if (!(time_status & (STA_INS | STA_DEL)))
++ time_state = TIME_OK;
++ }
++
++ /*
++ * Compute the phase adjustment for the next second. The offset is
++ * reduced by a fixed factor times the time constant.
++ */
++ tick_length = tick_length_base;
++ time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
++ time_offset -= time_adj;
++ tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
++
++ if (unlikely(time_adjust)) {
++ if (time_adjust > MAX_TICKADJ) {
++ time_adjust -= MAX_TICKADJ;
++ tick_length += MAX_TICKADJ_SCALED;
++ } else if (time_adjust < -MAX_TICKADJ) {
++ time_adjust += MAX_TICKADJ;
++ tick_length -= MAX_TICKADJ_SCALED;
++ } else {
++ tick_length += (s64)(time_adjust * NSEC_PER_USEC /
++ HZ) << TICK_LENGTH_SHIFT;
++ time_adjust = 0;
++ }
++ }
++}
++
++/*
++ * Return how long ticks are at the moment, that is, how much time
++ * update_wall_time_one_tick will add to xtime next time we call it
++ * (assuming no calls to do_adjtimex in the meantime).
++ * The return value is in fixed-point nanoseconds shifted by the
++ * specified number of bits to the right of the binary point.
++ * This function has no side-effects.
++ */
++u64 current_tick_length(void)
++{
++ return tick_length;
++}
++
++
++void __attribute__ ((weak)) notify_arch_cmos_timer(void)
++{
++ return;
++}
++
++/* adjtimex mainly allows reading (and writing, if superuser) of
++ * kernel time-keeping variables. used by xntpd.
++ */
++int do_adjtimex(struct timex *txc)
++{
++ long ltemp, mtemp, save_adjust;
++ s64 freq_adj, temp64;
++ int result;
++
++ /* In order to modify anything, you gotta be super-user! */
++ if (txc->modes && !capable(CAP_SYS_TIME))
++ return -EPERM;
++
++ /* Now we validate the data before disabling interrupts */
++
++ if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
++ /* singleshot must not be used with any other mode bits */
++ if (txc->modes != ADJ_OFFSET_SINGLESHOT)
++ return -EINVAL;
++
++ if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
++ /* adjustment Offset limited to +- .512 seconds */
++ if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
++ return -EINVAL;
++
++ /* if the quartz is off by more than 10% something is VERY wrong ! */
++ if (txc->modes & ADJ_TICK)
++ if (txc->tick < 900000/USER_HZ ||
++ txc->tick > 1100000/USER_HZ)
++ return -EINVAL;
++
++ write_seqlock_irq(&xtime_lock);
++ result = time_state; /* mostly `TIME_OK' */
++
++ /* Save for later - semantics of adjtime is to return old value */
++ save_adjust = time_adjust;
++
++#if 0 /* STA_CLOCKERR is never set yet */
++ time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
++#endif
++ /* If there are input parameters, then process them */
++ if (txc->modes)
++ {
++ if (txc->modes & ADJ_STATUS) /* only set allowed bits */
++ time_status = (txc->status & ~STA_RONLY) |
++ (time_status & STA_RONLY);
++
++ if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */
++ if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
++ result = -EINVAL;
++ goto leave;
++ }
++ time_freq = ((s64)txc->freq * NSEC_PER_USEC) >> (SHIFT_USEC - SHIFT_NSEC);
++ }
++
++ if (txc->modes & ADJ_MAXERROR) {
++ if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
++ result = -EINVAL;
++ goto leave;
++ }
++ time_maxerror = txc->maxerror;
++ }
++
++ if (txc->modes & ADJ_ESTERROR) {
++ if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
++ result = -EINVAL;
++ goto leave;
++ }
++ time_esterror = txc->esterror;
++ }
++
++ if (txc->modes & ADJ_TIMECONST) { /* p. 24 */
++ if (txc->constant < 0) { /* NTP v4 uses values > 6 */
++ result = -EINVAL;
++ goto leave;
++ }
++ time_constant = min(txc->constant + 4, (long)MAXTC);
++ }
++
++ if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
++ if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
++ /* adjtime() is independent from ntp_adjtime() */
++ time_adjust = txc->offset;
++ }
++ else if (time_status & STA_PLL) {
++ ltemp = txc->offset * NSEC_PER_USEC;
++
++ /*
++ * Scale the phase adjustment and
++ * clamp to the operating range.
++ */
++ time_offset = min(ltemp, MAXPHASE * NSEC_PER_USEC);
++ time_offset = max(time_offset, -MAXPHASE * NSEC_PER_USEC);
++
++ /*
++ * Select whether the frequency is to be controlled
++ * and in which mode (PLL or FLL). Clamp to the operating
++ * range. Ugly multiply/divide should be replaced someday.
++ */
++
++ if (time_status & STA_FREQHOLD || time_reftime == 0)
++ time_reftime = xtime.tv_sec;
++ mtemp = xtime.tv_sec - time_reftime;
++ time_reftime = xtime.tv_sec;
++
++ freq_adj = (s64)time_offset * mtemp;
++ freq_adj = shift_right(freq_adj, time_constant * 2 +
++ (SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
++ if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
++ temp64 = (s64)time_offset << (SHIFT_NSEC - SHIFT_FLL);
++ if (time_offset < 0) {
++ temp64 = -temp64;
++ do_div(temp64, mtemp);
++ freq_adj -= temp64;
++ } else {
++ do_div(temp64, mtemp);
++ freq_adj += temp64;
++ }
++ }
++ freq_adj += time_freq;
++ freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
++ time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
++ time_offset = (time_offset / HZ) << SHIFT_UPDATE;
++ } /* STA_PLL */
++ } /* txc->modes & ADJ_OFFSET */
++ if (txc->modes & ADJ_TICK)
++ tick_usec = txc->tick;
++
++ if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
++ ntp_update_frequency();
++ } /* txc->modes */
++leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
++ result = TIME_ERROR;
++
++ if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
++ txc->offset = save_adjust;
++ else
++ txc->offset = shift_right(time_offset, SHIFT_UPDATE) * HZ / 1000;
++ txc->freq = (time_freq / NSEC_PER_USEC) << (SHIFT_USEC - SHIFT_NSEC);
++ txc->maxerror = time_maxerror;
++ txc->esterror = time_esterror;
++ txc->status = time_status;
++ txc->constant = time_constant;
++ txc->precision = 1;
++ txc->tolerance = MAXFREQ;
++ txc->tick = tick_usec;
++
++ /* PPS is not implemented, so these are zero */
++ txc->ppsfreq = 0;
++ txc->jitter = 0;
++ txc->shift = 0;
++ txc->stabil = 0;
++ txc->jitcnt = 0;
++ txc->calcnt = 0;
++ txc->errcnt = 0;
++ txc->stbcnt = 0;
++ write_sequnlock_irq(&xtime_lock);
++ do_gettimeofday(&txc->time);
++ notify_arch_cmos_timer();
++ return(result);
++}
+diff --git a/kernel/timer.c b/kernel/timer.c
+index 1d7dd62..c1c7fbc 100644
+--- a/kernel/timer.c
++++ b/kernel/timer.c
+@@ -41,12 +41,6 @@
+ #include <asm/timex.h>
+ #include <asm/io.h>
+
+-#ifdef CONFIG_TIME_INTERPOLATION
+-static void time_interpolator_update(long delta_nsec);
+-#else
+-#define time_interpolator_update(x)
+-#endif
+-
+ u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
+
+ EXPORT_SYMBOL(jiffies_64);
+@@ -136,7 +130,7 @@ static void internal_add_timer(tvec_base
+ list_add_tail(&timer->entry, vec);
+ }
+
+-/***
++/**
+ * init_timer - initialize a timer.
+ * @timer: the timer to be initialized
+ *
+@@ -175,6 +169,7 @@ static inline void detach_timer(struct t
+ */
+ static tvec_base_t *lock_timer_base(struct timer_list *timer,
+ unsigned long *flags)
++ __acquires(timer->base->lock)
+ {
+ tvec_base_t *base;
+
+@@ -235,7 +230,7 @@ int __mod_timer(struct timer_list *timer
+
+ EXPORT_SYMBOL(__mod_timer);
+
+-/***
++/**
+ * add_timer_on - start a timer on a particular CPU
+ * @timer: the timer to be added
+ * @cpu: the CPU to start it on
+@@ -255,9 +250,10 @@ void add_timer_on(struct timer_list *tim
+ }
+
+
+-/***
++/**
+ * mod_timer - modify a timer's timeout
+ * @timer: the timer to be modified
++ * @expires: new timeout in jiffies
+ *
+ * mod_timer is a more efficient way to update the expire field of an
+ * active timer (if the timer is inactive it will be activated)
+@@ -291,7 +287,7 @@ int mod_timer(struct timer_list *timer,
+
+ EXPORT_SYMBOL(mod_timer);
+
+-/***
++/**
+ * del_timer - deactive a timer.
+ * @timer: the timer to be deactivated
+ *
+@@ -323,7 +319,10 @@ int del_timer(struct timer_list *timer)
+ EXPORT_SYMBOL(del_timer);
+
+ #ifdef CONFIG_SMP
+-/*
++/**
++ * try_to_del_timer_sync - Try to deactivate a timer
++ * @timer: timer do del
++ *
+ * This function tries to deactivate a timer. Upon successful (ret >= 0)
+ * exit the timer is not queued and the handler is not running on any CPU.
+ *
+@@ -351,7 +350,7 @@ out:
+ return ret;
+ }
+
+-/***
++/**
+ * del_timer_sync - deactivate a timer and wait for the handler to finish.
+ * @timer: the timer to be deactivated
+ *
+@@ -401,15 +400,15 @@ static int cascade(tvec_base_t *base, tv
+ return index;
+ }
+
+-/***
++#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
++
++/**
+ * __run_timers - run all expired timers (if any) on this CPU.
+ * @base: the timer vector to be processed.
+ *
+ * This function cascades all vectors and executes all expired timer
+ * vectors.
+ */
+-#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
+-
+ static inline void __run_timers(tvec_base_t *base)
+ {
+ struct timer_list *timer;
+@@ -563,12 +562,6 @@ found:
+
+ /******************************************************************/
+
+-/*
+- * Timekeeping variables
+- */
+-unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
+-unsigned long tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */
+-
+ /*
+ * The current time
+ * wall_to_monotonic is what we need to add to xtime (or xtime corrected
+@@ -582,209 +575,6 @@ struct timespec wall_to_monotonic __attr
+
+ EXPORT_SYMBOL(xtime);
+
+-/* Don't completely fail for HZ > 500. */
+-int tickadj = 500/HZ ? : 1; /* microsecs */
+-
+-
+-/*
+- * phase-lock loop variables
+- */
+-/* TIME_ERROR prevents overwriting the CMOS clock */
+-int time_state = TIME_OK; /* clock synchronization status */
+-int time_status = STA_UNSYNC; /* clock status bits */
+-long time_offset; /* time adjustment (us) */
+-long time_constant = 2; /* pll time constant */
+-long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
+-long time_precision = 1; /* clock precision (us) */
+-long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
+-long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
+-long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC;
+- /* frequency offset (scaled ppm)*/
+-static long time_adj; /* tick adjust (scaled 1 / HZ) */
+-long time_reftime; /* time at last adjustment (s) */
+-long time_adjust;
+-long time_next_adjust;
+-
+-/*
+- * this routine handles the overflow of the microsecond field
+- *
+- * The tricky bits of code to handle the accurate clock support
+- * were provided by Dave Mills (Mills at UDEL.EDU) of NTP fame.
+- * They were originally developed for SUN and DEC kernels.
+- * All the kudos should go to Dave for this stuff.
+- *
+- */
+-static void second_overflow(void)
+-{
+- long ltemp;
+-
+- /* Bump the maxerror field */
+- time_maxerror += time_tolerance >> SHIFT_USEC;
+- if (time_maxerror > NTP_PHASE_LIMIT) {
+- time_maxerror = NTP_PHASE_LIMIT;
+- time_status |= STA_UNSYNC;
+- }
+-
+- /*
+- * Leap second processing. If in leap-insert state at the end of the
+- * day, the system clock is set back one second; if in leap-delete
+- * state, the system clock is set ahead one second. The microtime()
+- * routine or external clock driver will insure that reported time is
+- * always monotonic. The ugly divides should be replaced.
+- */
+- switch (time_state) {
+- case TIME_OK:
+- if (time_status & STA_INS)
+- time_state = TIME_INS;
+- else if (time_status & STA_DEL)
+- time_state = TIME_DEL;
+- break;
+- case TIME_INS:
+- if (xtime.tv_sec % 86400 == 0) {
+- xtime.tv_sec--;
+- wall_to_monotonic.tv_sec++;
+- /*
+- * The timer interpolator will make time change
+- * gradually instead of an immediate jump by one second
+- */
+- time_interpolator_update(-NSEC_PER_SEC);
+- time_state = TIME_OOP;
+- clock_was_set();
+- printk(KERN_NOTICE "Clock: inserting leap second "
+- "23:59:60 UTC\n");
+- }
+- break;
+- case TIME_DEL:
+- if ((xtime.tv_sec + 1) % 86400 == 0) {
+- xtime.tv_sec++;
+- wall_to_monotonic.tv_sec--;
+- /*
+- * Use of time interpolator for a gradual change of
+- * time
+- */
+- time_interpolator_update(NSEC_PER_SEC);
+- time_state = TIME_WAIT;
+- clock_was_set();
+- printk(KERN_NOTICE "Clock: deleting leap second "
+- "23:59:59 UTC\n");
+- }
+- break;
+- case TIME_OOP:
+- time_state = TIME_WAIT;
+- break;
+- case TIME_WAIT:
+- if (!(time_status & (STA_INS | STA_DEL)))
+- time_state = TIME_OK;
+- }
+-
+- /*
+- * Compute the phase adjustment for the next second. In PLL mode, the
+- * offset is reduced by a fixed factor times the time constant. In FLL
+- * mode the offset is used directly. In either mode, the maximum phase
+- * adjustment for each second is clamped so as to spread the adjustment
+- * over not more than the number of seconds between updates.
+- */
+- ltemp = time_offset;
+- if (!(time_status & STA_FLL))
+- ltemp = shift_right(ltemp, SHIFT_KG + time_constant);
+- ltemp = min(ltemp, (MAXPHASE / MINSEC) << SHIFT_UPDATE);
+- ltemp = max(ltemp, -(MAXPHASE / MINSEC) << SHIFT_UPDATE);
+- time_offset -= ltemp;
+- time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+-
+- /*
+- * Compute the frequency estimate and additional phase adjustment due
+- * to frequency error for the next second.
+- */
+- ltemp = time_freq;
+- time_adj += shift_right(ltemp,(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE));
+-
+-#if HZ == 100
+- /*
+- * Compensate for (HZ==100) != (1 << SHIFT_HZ). Add 25% and 3.125% to
+- * get 128.125; => only 0.125% error (p. 14)
+- */
+- time_adj += shift_right(time_adj, 2) + shift_right(time_adj, 5);
+-#endif
+-#if HZ == 250
+- /*
+- * Compensate for (HZ==250) != (1 << SHIFT_HZ). Add 1.5625% and
+- * 0.78125% to get 255.85938; => only 0.05% error (p. 14)
+- */
+- time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7);
+-#endif
+-#if HZ == 1000
+- /*
+- * Compensate for (HZ==1000) != (1 << SHIFT_HZ). Add 1.5625% and
+- * 0.78125% to get 1023.4375; => only 0.05% error (p. 14)
+- */
+- time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7);
+-#endif
+-}
+-
+-/*
+- * Returns how many microseconds we need to add to xtime this tick
+- * in doing an adjustment requested with adjtime.
+- */
+-static long adjtime_adjustment(void)
+-{
+- long time_adjust_step;
+-
+- time_adjust_step = time_adjust;
+- if (time_adjust_step) {
+- /*
+- * We are doing an adjtime thing. Prepare time_adjust_step to
+- * be within bounds. Note that a positive time_adjust means we
+- * want the clock to run faster.
+- *
+- * Limit the amount of the step to be in the range
+- * -tickadj .. +tickadj
+- */
+- time_adjust_step = min(time_adjust_step, (long)tickadj);
+- time_adjust_step = max(time_adjust_step, (long)-tickadj);
+- }
+- return time_adjust_step;
+-}
+-
+-/* in the NTP reference this is called "hardclock()" */
+-static void update_ntp_one_tick(void)
+-{
+- long time_adjust_step;
+-
+- time_adjust_step = adjtime_adjustment();
+- if (time_adjust_step)
+- /* Reduce by this step the amount of time left */
+- time_adjust -= time_adjust_step;
+-
+- /* Changes by adjtime() do not take effect till next tick. */
+- if (time_next_adjust != 0) {
+- time_adjust = time_next_adjust;
+- time_next_adjust = 0;
+- }
+-}
+-
+-/*
+- * Return how long ticks are at the moment, that is, how much time
+- * update_wall_time_one_tick will add to xtime next time we call it
+- * (assuming no calls to do_adjtimex in the meantime).
+- * The return value is in fixed-point nanoseconds shifted by the
+- * specified number of bits to the right of the binary point.
+- * This function has no side-effects.
+- */
+-u64 current_tick_length(void)
+-{
+- long delta_nsec;
+- u64 ret;
+-
+- /* calculate the finest interval NTP will allow.
+- * ie: nanosecond value shifted by (SHIFT_SCALE - 10)
+- */
+- delta_nsec = tick_nsec + adjtime_adjustment() * 1000;
+- ret = (u64)delta_nsec << TICK_LENGTH_SHIFT;
+- ret += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10));
+-
+- return ret;
+-}
+
+ /* XXX - all of this timekeeping code should be later moved to time.c */
+ #include <linux/clocksource.h>
+@@ -961,21 +751,24 @@ void __init timekeeping_init(void)
+ unsigned long flags;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
++
++ ntp_clear();
++
+ clock = clocksource_get_next();
+ clocksource_calculate_interval(clock, tick_nsec);
+ clock->cycle_last = clocksource_read(clock);
+- ntp_clear();
++
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ }
+
+
+ static int timekeeping_suspended;
+-/*
++/**
+ * timekeeping_resume - Resumes the generic timekeeping subsystem.
+ * @dev: unused
+ *
+ * This is for the generic clocksource timekeeping.
+- * xtime/wall_to_monotonic/jiffies/wall_jiffies/etc are
++ * xtime/wall_to_monotonic/jiffies/etc are
+ * still managed by arch specific suspend/resume code.
+ */
+ static int timekeeping_resume(struct sys_device *dev)
+@@ -1106,7 +899,7 @@ static void clocksource_adjust(struct cl
+ clock->error -= (interval - offset) << (TICK_LENGTH_SHIFT - clock->shift);
+ }
+
+-/*
++/**
+ * update_wall_time - Uses the current clocksource to increment the wall time
+ *
+ * Called from the timer interrupt, must hold a write on xtime_lock.
+@@ -1144,8 +937,6 @@ static void update_wall_time(void)
+ /* interpolator bits */
+ time_interpolator_update(clock->xtime_interval
+ >> clock->shift);
+- /* increment the NTP state machine */
+- update_ntp_one_tick();
+
+ /* accumulate error between NTP and clock interval */
+ clock->error += current_tick_length();
+@@ -1217,19 +1008,14 @@ static inline void calc_load(unsigned lo
+ unsigned long active_tasks; /* fixed-point */
+ static int count = LOAD_FREQ;
+
+- count -= ticks;
+- if (count < 0) {
+- count += LOAD_FREQ;
+- active_tasks = count_active_tasks();
++ active_tasks = count_active_tasks();
++ for (count -= ticks; count < 0; count += LOAD_FREQ) {
+ CALC_LOAD(avenrun[0], EXP_1, active_tasks);
+ CALC_LOAD(avenrun[1], EXP_5, active_tasks);
+ CALC_LOAD(avenrun[2], EXP_15, active_tasks);
+ }
+ }
+
+-/* jiffies at the most recent update of wall time */
+-unsigned long wall_jiffies = INITIAL_JIFFIES;
+-
+ /*
+ * This read-write spinlock protects us from races in SMP while
+ * playing with xtime and avenrun.
+@@ -1265,12 +1051,8 @@ void run_local_timers(void)
+ * Called by the timer interrupt. xtime_lock must already be taken
+ * by the timer IRQ!
+ */
+-static inline void update_times(void)
++static inline void update_times(unsigned long ticks)
+ {
+- unsigned long ticks;
+-
+- ticks = jiffies - wall_jiffies;
+- wall_jiffies += ticks;
+ update_wall_time();
+ calc_load(ticks);
+ }
+@@ -1281,12 +1063,10 @@ static inline void update_times(void)
+ * jiffies is defined in the linker script...
+ */
+
+-void do_timer(struct pt_regs *regs)
++void do_timer(unsigned long ticks)
+ {
+- jiffies_64++;
+- /* prevent loading jiffies before storing new jiffies_64 value. */
+- barrier();
+- update_times();
++ jiffies_64 += ticks;
++ update_times(ticks);
+ }
+
+ #ifdef __ARCH_WANT_SYS_ALARM
+@@ -1470,8 +1250,9 @@ asmlinkage long sys_gettid(void)
+ return current->pid;
+ }
+
+-/*
++/**
+ * sys_sysinfo - fill in sysinfo struct
++ * @info: pointer to buffer to fill
+ */
+ asmlinkage long sys_sysinfo(struct sysinfo __user *info)
+ {
+@@ -1688,8 +1469,10 @@ static struct notifier_block __cpuinitda
+
+ void __init init_timers(void)
+ {
+- timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
++ int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
+ (void *)(long)smp_processor_id());
++
++ BUG_ON(err == NOTIFY_BAD);
+ register_cpu_notifier(&timers_nb);
+ open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
+ }
+@@ -1774,7 +1557,7 @@ unsigned long time_interpolator_get_offs
+ #define INTERPOLATOR_ADJUST 65536
+ #define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST
+
+-static void time_interpolator_update(long delta_nsec)
++void time_interpolator_update(long delta_nsec)
+ {
+ u64 counter;
+ unsigned long offset;
+diff --git a/kernel/tsacct.c b/kernel/tsacct.c
+new file mode 100644
+index 0000000..96f7701
+--- /dev/null
++++ b/kernel/tsacct.c
+@@ -0,0 +1,131 @@
++/*
++ * tsacct.c - System accounting over taskstats interface
++ *
++ * Copyright (C) Jay Lan, <jlan at sgi.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.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/tsacct_kern.h>
++#include <linux/acct.h>
++#include <linux/jiffies.h>
++
++
++#define USEC_PER_TICK (USEC_PER_SEC/HZ)
++/*
++ * fill in basic accounting fields
++ */
++void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
++{
++ struct timespec uptime, ts;
++ s64 ac_etime;
++
++ BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN);
++
++ /* calculate task elapsed time in timespec */
++ do_posix_clock_monotonic_gettime(&uptime);
++ ts = timespec_sub(uptime, tsk->start_time);
++ /* rebase elapsed time to usec */
++ ac_etime = timespec_to_ns(&ts);
++ do_div(ac_etime, NSEC_PER_USEC);
++ stats->ac_etime = ac_etime;
++ stats->ac_btime = xtime.tv_sec - ts.tv_sec;
++ if (thread_group_leader(tsk)) {
++ stats->ac_exitcode = tsk->exit_code;
++ if (tsk->flags & PF_FORKNOEXEC)
++ stats->ac_flag |= AFORK;
++ }
++ if (tsk->flags & PF_SUPERPRIV)
++ stats->ac_flag |= ASU;
++ if (tsk->flags & PF_DUMPCORE)
++ stats->ac_flag |= ACORE;
++ if (tsk->flags & PF_SIGNALED)
++ stats->ac_flag |= AXSIG;
++ stats->ac_nice = task_nice(tsk);
++ stats->ac_sched = tsk->policy;
++ stats->ac_uid = tsk->uid;
++ stats->ac_gid = tsk->gid;
++ stats->ac_pid = tsk->pid;
++ rcu_read_lock();
++ stats->ac_ppid = pid_alive(tsk) ?
++ rcu_dereference(tsk->real_parent)->tgid : 0;
++ rcu_read_unlock();
++ stats->ac_utime = cputime_to_msecs(tsk->utime) * USEC_PER_MSEC;
++ stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC;
++ stats->ac_minflt = tsk->min_flt;
++ stats->ac_majflt = tsk->maj_flt;
++
++ strncpy(stats->ac_comm, tsk->comm, sizeof(stats->ac_comm));
++}
++
++
++#ifdef CONFIG_TASK_XACCT
++
++#define KB 1024
++#define MB (1024*KB)
++/*
++ * fill in extended accounting fields
++ */
++void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
++{
++ struct mm_struct *mm;
++
++ /* convert pages-jiffies to Mbyte-usec */
++ stats->coremem = jiffies_to_usecs(p->acct_rss_mem1) * PAGE_SIZE / MB;
++ stats->virtmem = jiffies_to_usecs(p->acct_vm_mem1) * PAGE_SIZE / MB;
++ mm = get_task_mm(p);
++ if (mm) {
++ /* adjust to KB unit */
++ stats->hiwater_rss = mm->hiwater_rss * PAGE_SIZE / KB;
++ stats->hiwater_vm = mm->hiwater_vm * PAGE_SIZE / KB;
++ mmput(mm);
++ }
++ stats->read_char = p->rchar;
++ stats->write_char = p->wchar;
++ stats->read_syscalls = p->syscr;
++ stats->write_syscalls = p->syscw;
++}
++#undef KB
++#undef MB
++
++/**
++ * acct_update_integrals - update mm integral fields in task_struct
++ * @tsk: task_struct for accounting
++ */
++void acct_update_integrals(struct task_struct *tsk)
++{
++ if (likely(tsk->mm)) {
++ long delta = cputime_to_jiffies(
++ cputime_sub(tsk->stime, tsk->acct_stimexpd));
++
++ if (delta == 0)
++ return;
++ tsk->acct_stimexpd = tsk->stime;
++ tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm);
++ tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
++ }
++}
++
++/**
++ * acct_clear_integrals - clear the mm integral fields in task_struct
++ * @tsk: task_struct whose accounting fields are cleared
++ */
++void acct_clear_integrals(struct task_struct *tsk)
++{
++ tsk->acct_stimexpd = 0;
++ tsk->acct_rss_mem1 = 0;
++ tsk->acct_vm_mem1 = 0;
++}
++#endif
+diff --git a/kernel/unwind.c b/kernel/unwind.c
+index f69c804..f7e50d1 100644
+--- a/kernel/unwind.c
++++ b/kernel/unwind.c
+@@ -11,13 +11,15 @@
+
+ #include <linux/unwind.h>
+ #include <linux/module.h>
+-#include <linux/delay.h>
++#include <linux/bootmem.h>
++#include <linux/sort.h>
+ #include <linux/stop_machine.h>
+ #include <asm/sections.h>
+ #include <asm/uaccess.h>
+ #include <asm/unaligned.h>
+
+ extern char __start_unwind[], __end_unwind[];
++extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];
+
+ #define MAX_STACK_DEPTH 8
+
+@@ -100,9 +102,11 @@ static struct unwind_table {
+ } core, init;
+ const void *address;
+ unsigned long size;
++ const unsigned char *header;
++ unsigned long hdrsz;
+ struct unwind_table *link;
+ const char *name;
+-} root_table, *last_table;
++} root_table;
+
+ struct unwind_item {
+ enum item_location {
+@@ -145,6 +149,10 @@ static struct unwind_table *find_table(u
+ return table;
+ }
+
++static unsigned long read_pointer(const u8 **pLoc,
++ const void *end,
++ signed ptrType);
++
+ static void init_unwind_table(struct unwind_table *table,
+ const char *name,
+ const void *core_start,
+@@ -152,14 +160,30 @@ static void init_unwind_table(struct unw
+ const void *init_start,
+ unsigned long init_size,
+ const void *table_start,
+- unsigned long table_size)
++ unsigned long table_size,
++ const u8 *header_start,
++ unsigned long header_size)
+ {
++ const u8 *ptr = header_start + 4;
++ const u8 *end = header_start + header_size;
++
+ table->core.pc = (unsigned long)core_start;
+ table->core.range = core_size;
+ table->init.pc = (unsigned long)init_start;
+ table->init.range = init_size;
+ table->address = table_start;
+ table->size = table_size;
++ /* See if the linker provided table looks valid. */
++ if (header_size <= 4
++ || header_start[0] != 1
++ || (void *)read_pointer(&ptr, end, header_start[1]) != table_start
++ || header_start[2] == DW_EH_PE_omit
++ || read_pointer(&ptr, end, header_start[2]) <= 0
++ || header_start[3] == DW_EH_PE_omit)
++ header_start = NULL;
++ table->hdrsz = header_size;
++ smp_wmb();
++ table->header = header_start;
+ table->link = NULL;
+ table->name = name;
+ }
+@@ -169,11 +193,149 @@ void __init unwind_init(void)
+ init_unwind_table(&root_table, "kernel",
+ _text, _end - _text,
+ NULL, 0,
+- __start_unwind, __end_unwind - __start_unwind);
++ __start_unwind, __end_unwind - __start_unwind,
++ __start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);
++}
++
++static const u32 bad_cie, not_fde;
++static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
++static signed fde_pointer_type(const u32 *cie);
++
++struct eh_frame_hdr_table_entry {
++ unsigned long start, fde;
++};
++
++static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
++{
++ const struct eh_frame_hdr_table_entry *e1 = p1;
++ const struct eh_frame_hdr_table_entry *e2 = p2;
++
++ return (e1->start > e2->start) - (e1->start < e2->start);
++}
++
++static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
++{
++ struct eh_frame_hdr_table_entry *e1 = p1;
++ struct eh_frame_hdr_table_entry *e2 = p2;
++ unsigned long v;
++
++ v = e1->start;
++ e1->start = e2->start;
++ e2->start = v;
++ v = e1->fde;
++ e1->fde = e2->fde;
++ e2->fde = v;
++}
++
++static void __init setup_unwind_table(struct unwind_table *table,
++ void *(*alloc)(unsigned long))
++{
++ const u8 *ptr;
++ unsigned long tableSize = table->size, hdrSize;
++ unsigned n;
++ const u32 *fde;
++ struct {
++ u8 version;
++ u8 eh_frame_ptr_enc;
++ u8 fde_count_enc;
++ u8 table_enc;
++ unsigned long eh_frame_ptr;
++ unsigned int fde_count;
++ struct eh_frame_hdr_table_entry table[];
++ } __attribute__((__packed__)) *header;
++
++ if (table->header)
++ return;
++
++ if (table->hdrsz)
++ printk(KERN_WARNING ".eh_frame_hdr for '%s' present but unusable\n",
++ table->name);
++
++ if (tableSize & (sizeof(*fde) - 1))
++ return;
++
++ for (fde = table->address, n = 0;
++ tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
++ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
++ const u32 *cie = cie_for_fde(fde, table);
++ signed ptrType;
++
++ if (cie == ¬_fde)
++ continue;
++ if (cie == NULL
++ || cie == &bad_cie
++ || (ptrType = fde_pointer_type(cie)) < 0)
++ return;
++ ptr = (const u8 *)(fde + 2);
++ if (!read_pointer(&ptr,
++ (const u8 *)(fde + 1) + *fde,
++ ptrType))
++ return;
++ ++n;
++ }
++
++ if (tableSize || !n)
++ return;
++
++ hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
++ + 2 * n * sizeof(unsigned long);
++ header = alloc(hdrSize);
++ if (!header)
++ return;
++ header->version = 1;
++ header->eh_frame_ptr_enc = DW_EH_PE_abs|DW_EH_PE_native;
++ header->fde_count_enc = DW_EH_PE_abs|DW_EH_PE_data4;
++ header->table_enc = DW_EH_PE_abs|DW_EH_PE_native;
++ put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
++ BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
++ % __alignof(typeof(header->fde_count)));
++ header->fde_count = n;
++
++ BUILD_BUG_ON(offsetof(typeof(*header), table)
++ % __alignof(typeof(*header->table)));
++ for (fde = table->address, tableSize = table->size, n = 0;
++ tableSize;
++ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
++ const u32 *cie = fde + 1 - fde[1] / sizeof(*fde);
++
++ if (!fde[1])
++ continue; /* this is a CIE */
++ ptr = (const u8 *)(fde + 2);
++ header->table[n].start = read_pointer(&ptr,
++ (const u8 *)(fde + 1) + *fde,
++ fde_pointer_type(cie));
++ header->table[n].fde = (unsigned long)fde;
++ ++n;
++ }
++ WARN_ON(n != header->fde_count);
++
++ sort(header->table,
++ n,
++ sizeof(*header->table),
++ cmp_eh_frame_hdr_table_entries,
++ swap_eh_frame_hdr_table_entries);
++
++ table->hdrsz = hdrSize;
++ smp_wmb();
++ table->header = (const void *)header;
++}
++
++static void *__init balloc(unsigned long sz)
++{
++ return __alloc_bootmem_nopanic(sz,
++ sizeof(unsigned int),
++ __pa(MAX_DMA_ADDRESS));
++}
++
++void __init unwind_setup(void)
++{
++ setup_unwind_table(&root_table, balloc);
+ }
+
+ #ifdef CONFIG_MODULES
+
++static struct unwind_table *last_table;
++
+ /* Must be called with module_mutex held. */
+ void *unwind_add_table(struct module *module,
+ const void *table_start,
+@@ -191,7 +353,8 @@ void *unwind_add_table(struct module *mo
+ init_unwind_table(table, module->name,
+ module->module_core, module->core_size,
+ module->module_init, module->init_size,
+- table_start, table_size);
++ table_start, table_size,
++ NULL, 0);
+
+ if (last_table)
+ last_table->link = table;
+@@ -301,6 +464,26 @@ static sleb128_t get_sleb128(const u8 **
+ return value;
+ }
+
++static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
++{
++ const u32 *cie;
++
++ if (!*fde || (*fde & (sizeof(*fde) - 1)))
++ return &bad_cie;
++ if (!fde[1])
++ return ¬_fde; /* this is a CIE */
++ if ((fde[1] & (sizeof(*fde) - 1))
++ || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address)
++ return NULL; /* this is not a valid FDE */
++ cie = fde + 1 - fde[1] / sizeof(*fde);
++ if (*cie <= sizeof(*cie) + 4
++ || *cie >= fde[1] - sizeof(*fde)
++ || (*cie & (sizeof(*cie) - 1))
++ || cie[1])
++ return NULL; /* this is not a (valid) CIE */
++ return cie;
++}
++
+ static unsigned long read_pointer(const u8 **pLoc,
+ const void *end,
+ signed ptrType)
+@@ -603,53 +786,113 @@ int unwind(struct unwind_frame_info *fra
+ #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
+ const u32 *fde = NULL, *cie = NULL;
+ const u8 *ptr = NULL, *end = NULL;
++ unsigned long pc = UNW_PC(frame) - frame->call_frame;
+ unsigned long startLoc = 0, endLoc = 0, cfa;
+ unsigned i;
+ signed ptrType = -1;
+ uleb128_t retAddrReg = 0;
+- struct unwind_table *table;
++ const struct unwind_table *table;
+ struct unwind_state state;
+
+ if (UNW_PC(frame) == 0)
+ return -EINVAL;
+- if ((table = find_table(UNW_PC(frame))) != NULL
++ if ((table = find_table(pc)) != NULL
+ && !(table->size & (sizeof(*fde) - 1))) {
+- unsigned long tableSize = table->size;
+-
+- for (fde = table->address;
+- tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
+- tableSize -= sizeof(*fde) + *fde,
+- fde += 1 + *fde / sizeof(*fde)) {
+- if (!*fde || (*fde & (sizeof(*fde) - 1)))
+- break;
+- if (!fde[1])
+- continue; /* this is a CIE */
+- if ((fde[1] & (sizeof(*fde) - 1))
+- || fde[1] > (unsigned long)(fde + 1)
+- - (unsigned long)table->address)
+- continue; /* this is not a valid FDE */
+- cie = fde + 1 - fde[1] / sizeof(*fde);
+- if (*cie <= sizeof(*cie) + 4
+- || *cie >= fde[1] - sizeof(*fde)
+- || (*cie & (sizeof(*cie) - 1))
+- || cie[1]
+- || (ptrType = fde_pointer_type(cie)) < 0) {
+- cie = NULL; /* this is not a (valid) CIE */
+- continue;
++ const u8 *hdr = table->header;
++ unsigned long tableSize;
++
++ smp_rmb();
++ if (hdr && hdr[0] == 1) {
++ switch(hdr[3] & DW_EH_PE_FORM) {
++ case DW_EH_PE_native: tableSize = sizeof(unsigned long); break;
++ case DW_EH_PE_data2: tableSize = 2; break;
++ case DW_EH_PE_data4: tableSize = 4; break;
++ case DW_EH_PE_data8: tableSize = 8; break;
++ default: tableSize = 0; break;
++ }
++ ptr = hdr + 4;
++ end = hdr + table->hdrsz;
++ if (tableSize
++ && read_pointer(&ptr, end, hdr[1])
++ == (unsigned long)table->address
++ && (i = read_pointer(&ptr, end, hdr[2])) > 0
++ && i == (end - ptr) / (2 * tableSize)
++ && !((end - ptr) % (2 * tableSize))) {
++ do {
++ const u8 *cur = ptr + (i / 2) * (2 * tableSize);
++
++ startLoc = read_pointer(&cur,
++ cur + tableSize,
++ hdr[3]);
++ if (pc < startLoc)
++ i /= 2;
++ else {
++ ptr = cur - tableSize;
++ i = (i + 1) / 2;
++ }
++ } while (startLoc && i > 1);
++ if (i == 1
++ && (startLoc = read_pointer(&ptr,
++ ptr + tableSize,
++ hdr[3])) != 0
++ && pc >= startLoc)
++ fde = (void *)read_pointer(&ptr,
++ ptr + tableSize,
++ hdr[3]);
+ }
++ }
++
++ if (fde != NULL) {
++ cie = cie_for_fde(fde, table);
+ ptr = (const u8 *)(fde + 2);
+- startLoc = read_pointer(&ptr,
+- (const u8 *)(fde + 1) + *fde,
+- ptrType);
+- endLoc = startLoc
+- + read_pointer(&ptr,
+- (const u8 *)(fde + 1) + *fde,
+- ptrType & DW_EH_PE_indirect
+- ? ptrType
+- : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed));
+- if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc)
+- break;
+- cie = NULL;
++ if(cie != NULL
++ && cie != &bad_cie
++ && cie != ¬_fde
++ && (ptrType = fde_pointer_type(cie)) >= 0
++ && read_pointer(&ptr,
++ (const u8 *)(fde + 1) + *fde,
++ ptrType) == startLoc) {
++ if (!(ptrType & DW_EH_PE_indirect))
++ ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
++ endLoc = startLoc
++ + read_pointer(&ptr,
++ (const u8 *)(fde + 1) + *fde,
++ ptrType);
++ if(pc >= endLoc)
++ fde = NULL;
++ } else
++ fde = NULL;
++ }
++ if (fde == NULL) {
++ for (fde = table->address, tableSize = table->size;
++ cie = NULL, tableSize > sizeof(*fde)
++ && tableSize - sizeof(*fde) >= *fde;
++ tableSize -= sizeof(*fde) + *fde,
++ fde += 1 + *fde / sizeof(*fde)) {
++ cie = cie_for_fde(fde, table);
++ if (cie == &bad_cie) {
++ cie = NULL;
++ break;
++ }
++ if (cie == NULL
++ || cie == ¬_fde
++ || (ptrType = fde_pointer_type(cie)) < 0)
++ continue;
++ ptr = (const u8 *)(fde + 2);
++ startLoc = read_pointer(&ptr,
++ (const u8 *)(fde + 1) + *fde,
++ ptrType);
++ if (!startLoc)
++ continue;
++ if (!(ptrType & DW_EH_PE_indirect))
++ ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
++ endLoc = startLoc
++ + read_pointer(&ptr,
++ (const u8 *)(fde + 1) + *fde,
++ ptrType);
++ if (pc >= startLoc && pc < endLoc)
++ break;
++ }
+ }
+ }
+ if (cie != NULL) {
+@@ -657,16 +900,28 @@ int unwind(struct unwind_frame_info *fra
+ state.cieEnd = ptr; /* keep here temporarily */
+ ptr = (const u8 *)(cie + 2);
+ end = (const u8 *)(cie + 1) + *cie;
++ frame->call_frame = 1;
+ if ((state.version = *ptr) != 1)
+ cie = NULL; /* unsupported version */
+ else if (*++ptr) {
+ /* check if augmentation size is first (and thus present) */
+ if (*ptr == 'z') {
+- /* check for ignorable (or already handled)
+- * nul-terminated augmentation string */
+- while (++ptr < end && *ptr)
+- if (strchr("LPR", *ptr) == NULL)
++ while (++ptr < end && *ptr) {
++ switch(*ptr) {
++ /* check for ignorable (or already handled)
++ * nul-terminated augmentation string */
++ case 'L':
++ case 'P':
++ case 'R':
++ continue;
++ case 'S':
++ frame->call_frame = 0;
++ continue;
++ default:
+ break;
++ }
++ break;
++ }
+ }
+ if (ptr >= end || *ptr)
+ cie = NULL;
+@@ -755,7 +1010,7 @@ int unwind(struct unwind_frame_info *fra
+ state.org = startLoc;
+ memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
+ /* process instructions */
+- if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state)
++ if (!processCFI(ptr, end, pc, ptrType, &state)
+ || state.loc > endLoc
+ || state.regs[retAddrReg].where == Nowhere
+ || state.cfa.reg >= ARRAY_SIZE(reg_info)
+@@ -763,6 +1018,11 @@ int unwind(struct unwind_frame_info *fra
+ || state.cfa.offs % sizeof(unsigned long))
+ return -EIO;
+ /* update frame */
++#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
++ if(frame->call_frame
++ && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
++ frame->call_frame = 0;
++#endif
+ cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
+ startLoc = min((unsigned long)UNW_SP(frame), cfa);
+ endLoc = max((unsigned long)UNW_SP(frame), cfa);
+@@ -866,6 +1126,7 @@ int unwind_init_frame_info(struct unwind
+ /*const*/ struct pt_regs *regs)
+ {
+ info->task = tsk;
++ info->call_frame = 0;
+ arch_unw_init_frame_info(info, regs);
+
+ return 0;
+@@ -879,6 +1140,7 @@ int unwind_init_blocked(struct unwind_fr
+ struct task_struct *tsk)
+ {
+ info->task = tsk;
++ info->call_frame = 0;
+ arch_unw_init_blocked(info);
+
+ return 0;
+@@ -894,6 +1156,7 @@ int unwind_init_running(struct unwind_fr
+ void *arg)
+ {
+ info->task = current;
++ info->call_frame = 0;
+
+ return arch_unwind_init_running(info, callback, arg);
+ }
+diff --git a/kernel/user.c b/kernel/user.c
+index 6408c04..220e586 100644
+--- a/kernel/user.c
++++ b/kernel/user.c
+@@ -187,6 +187,17 @@ void switch_uid(struct user_struct *new_
+ atomic_dec(&old_user->processes);
+ switch_uid_keyring(new_user);
+ current->user = new_user;
++
++ /*
++ * We need to synchronize with __sigqueue_alloc()
++ * doing a get_uid(p->user).. If that saw the old
++ * user value, we need to wait until it has exited
++ * its critical region before we can free the old
++ * structure.
++ */
++ smp_mb();
++ spin_unlock_wait(¤t->sighand->siglock);
++
+ free_uid(old_user);
+ suid_keys(current);
+ }
+diff --git a/kernel/utsname.c b/kernel/utsname.c
+new file mode 100644
+index 0000000..c859164
+--- /dev/null
++++ b/kernel/utsname.c
+@@ -0,0 +1,95 @@
++/*
++ * Copyright (C) 2004 IBM Corporation
++ *
++ * Author: Serge Hallyn <serue at 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, version 2 of the
++ * License.
++ */
++
++#include <linux/module.h>
++#include <linux/uts.h>
++#include <linux/utsname.h>
++#include <linux/version.h>
++
++/*
++ * Clone a new ns copying an original utsname, setting refcount to 1
++ * @old_ns: namespace to clone
++ * Return NULL on error (failure to kmalloc), new ns otherwise
++ */
++static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
++{
++ struct uts_namespace *ns;
++
++ ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL);
++ if (ns) {
++ memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
++ kref_init(&ns->kref);
++ }
++ return ns;
++}
++
++/*
++ * unshare the current process' utsname namespace.
++ * called only in sys_unshare()
++ */
++int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts)
++{
++ if (unshare_flags & CLONE_NEWUTS) {
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ *new_uts = clone_uts_ns(current->nsproxy->uts_ns);
++ if (!*new_uts)
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++/*
++ * Copy task tsk's utsname namespace, or clone it if flags
++ * specifies CLONE_NEWUTS. In latter case, changes to the
++ * utsname of this process won't be seen by parent, and vice
++ * versa.
++ */
++int copy_utsname(int flags, struct task_struct *tsk)
++{
++ struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
++ struct uts_namespace *new_ns;
++ int err = 0;
++
++ if (!old_ns)
++ return 0;
++
++ get_uts_ns(old_ns);
++
++ if (!(flags & CLONE_NEWUTS))
++ return 0;
++
++ if (!capable(CAP_SYS_ADMIN)) {
++ err = -EPERM;
++ goto out;
++ }
++
++ new_ns = clone_uts_ns(old_ns);
++ if (!new_ns) {
++ err = -ENOMEM;
++ goto out;
++ }
++ tsk->nsproxy->uts_ns = new_ns;
++
++out:
++ put_uts_ns(old_ns);
++ return err;
++}
++
++void free_uts_ns(struct kref *kref)
++{
++ struct uts_namespace *ns;
++
++ ns = container_of(kref, struct uts_namespace, kref);
++ kfree(ns);
++}
+diff --git a/kernel/workqueue.c b/kernel/workqueue.c
+index 835fe28..17c2f03 100644
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -28,13 +28,14 @@
+ #include <linux/notifier.h>
+ #include <linux/kthread.h>
+ #include <linux/hardirq.h>
++#include <linux/mempolicy.h>
+
+ /*
+ * The per-CPU workqueue (if single thread, we always use the first
+ * possible cpu).
+ *
+ * The sequence counters are for flush_scheduled_work(). It wants to wait
+- * until until all currently-scheduled works are completed, but it doesn't
++ * until all currently-scheduled works are completed, but it doesn't
+ * want to be livelocked by new, incoming ones. So it waits until
+ * remove_sequence is >= the insert_sequence which pertained when
+ * flush_scheduled_work() was called.
+@@ -98,7 +99,7 @@ static void __queue_work(struct cpu_work
+ * @wq: workqueue to use
+ * @work: work to queue
+ *
+- * Returns non-zero if it was successfully added.
++ * Returns 0 if @work was already on a queue, non-zero otherwise.
+ *
+ * We queue the work to the CPU it was submitted, but there is no
+ * guarantee that it will be processed by that CPU.
+@@ -137,7 +138,7 @@ static void delayed_work_timer_fn(unsign
+ * @work: work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+- * Returns non-zero if it was successfully added.
++ * Returns 0 if @work was already on a queue, non-zero otherwise.
+ */
+ int fastcall queue_delayed_work(struct workqueue_struct *wq,
+ struct work_struct *work, unsigned long delay)
+@@ -168,7 +169,7 @@ EXPORT_SYMBOL_GPL(queue_delayed_work);
+ * @work: work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+- * Returns non-zero if it was successfully added.
++ * Returns 0 if @work was already on a queue, non-zero otherwise.
+ */
+ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct work_struct *work, unsigned long delay)
+@@ -245,6 +246,12 @@ static int worker_thread(void *__cwq)
+ sigprocmask(SIG_BLOCK, &blocked, NULL);
+ flush_signals(current);
+
++ /*
++ * We inherited MPOL_INTERLEAVE from the booting kernel.
++ * Set MPOL_DEFAULT to insure node local allocations.
++ */
++ numa_default_policy();
++
+ /* SIG_IGN makes children autoreap: see do_notify_parent(). */
+ sa.sa.sa_handler = SIG_IGN;
+ sa.sa.sa_flags = 0;
+diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
+index 554ee68..d367910 100644
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -8,6 +8,13 @@ config PRINTK_TIME
+ operations. This is useful for identifying long delays
+ in kernel startup.
+
++config ENABLE_MUST_CHECK
++ bool "Enable __must_check logic"
++ default y
++ help
++ Enable the __must_check logic in the kernel build. Disable this to
++ suppress the "warning: ignoring return value of 'foo', declared with
++ attribute warn_unused_result" messages.
+
+ config MAGIC_SYSRQ
+ bool "Magic SysRq key"
+@@ -64,7 +71,7 @@ config LOG_BUF_SHIFT
+
+ config DETECT_SOFTLOCKUP
+ bool "Detect Soft Lockups"
+- depends on DEBUG_KERNEL
++ depends on DEBUG_KERNEL && !S390
+ default y
+ help
+ Say Y here to enable the kernel to detect "soft lockups",
+@@ -218,7 +225,7 @@ config LOCKDEP
+ bool
+ depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+ select STACKTRACE
+- select FRAME_POINTER
++ select FRAME_POINTER if !X86
+ select KALLSYMS
+ select KALLSYMS_ALL
+
+@@ -277,7 +284,7 @@ config DEBUG_HIGHMEM
+ config DEBUG_BUGVERBOSE
+ bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
+ depends on BUG
+- depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV
++ depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV || SUPERH
+ default !EMBEDDED
+ help
+ Say Y here to make BUG() panics output the file name and line number
+@@ -313,9 +320,18 @@ config DEBUG_VM
+
+ If unsure, say N.
+
++config DEBUG_LIST
++ bool "Debug linked list manipulation"
++ depends on DEBUG_KERNEL
++ help
++ Enable this to turn on extended checks in the linked-list
++ walking routines.
++
++ If unsure, say N.
++
+ config FRAME_POINTER
+ bool "Compile the kernel with frame pointers"
+- depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390)
++ depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH)
+ default y if DEBUG_INFO && UML
+ help
+ If you say Y here the resulting kernel image will be slightly larger
+@@ -325,7 +341,7 @@ config FRAME_POINTER
+
+ config UNWIND_INFO
+ bool "Compile the kernel with frame unwind information"
+- depends on !IA64 && !PARISC
++ depends on !IA64 && !PARISC && !ARM
+ depends on !MODULES || !(MIPS || PPC || SUPERH || V850)
+ help
+ If you say Y here the resulting kernel image will be slightly larger
+@@ -355,6 +371,20 @@ config FORCED_INLINING
+ become the default in the future, until then this option is there to
+ test gcc for this.
+
++config HEADERS_CHECK
++ bool "Run 'make headers_check' when building vmlinux"
++ depends on !UML
++ help
++ This option will extract the user-visible kernel headers whenever
++ building the kernel, and will run basic sanity checks on them to
++ ensure that exported files do not attempt to include files which
++ were not exported, etc.
++
++ If you're making modifications to header files which are
++ relevant for userspace, say 'Y', and check the headers
++ exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
++ your build tree), to make sure they're suitable.
++
+ config RCU_TORTURE_TEST
+ tristate "torture tests for RCU"
+ depends on DEBUG_KERNEL
+@@ -368,3 +398,17 @@ config RCU_TORTURE_TEST
+ at boot time (you probably don't).
+ Say M if you want the RCU torture tests to build as a module.
+ Say N if you are unsure.
++
++config LKDTM
++ tristate "Linux Kernel Dump Test Tool Module"
++ depends on KPROBES
++ default n
++ help
++ This module enables testing of the different dumping mechanisms by
++ inducing system failures at predefined crash points.
++ If you don't need it: say N
++ Choose M here to compile this code as a module. The module will be
++ called lkdtm.
++
++ Documentation on how to use the module can be found in
++ drivers/misc/lkdtm.c
+diff --git a/lib/Makefile b/lib/Makefile
+index ef1d37a..cf98fab 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -2,16 +2,17 @@
+ # Makefile for some libs needed in the kernel.
+ #
+
+-lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
++lib-y := ctype.o string.o vsprintf.o cmdline.o \
+ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
+ idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
+- sha1.o
++ sha1.o irq_regs.o
+
++lib-$(CONFIG_MMU) += ioremap.o
+ lib-$(CONFIG_SMP) += cpumask.o
+
+ lib-y += kobject.o kref.o kobject_uevent.o klist.o
+
+-obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o
++obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o random32.o
+
+ ifeq ($(CONFIG_DEBUG_KOBJECT),y)
+ CFLAGS_kobject.o += -DDEBUG
+@@ -28,6 +29,7 @@ lib-$(CONFIG_GENERIC_HWEIGHT) += hweight
+ obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
+ obj-$(CONFIG_PLIST) += plist.o
+ obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
++obj-$(CONFIG_DEBUG_LIST) += list_debug.o
+
+ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
+ lib-y += dec_and_lock.o
+diff --git a/lib/audit.c b/lib/audit.c
+index 8c21625..3b1289f 100644
+--- a/lib/audit.c
++++ b/lib/audit.c
+@@ -28,8 +28,10 @@ int audit_classify_syscall(int abi, unsi
+ switch(syscall) {
+ case __NR_open:
+ return 2;
++#ifdef __NR_openat
+ case __NR_openat:
+ return 3;
++#endif
+ #ifdef __NR_socketcall
+ case __NR_socketcall:
+ return 4;
+diff --git a/lib/bitmap.c b/lib/bitmap.c
+index d71e38c..037fa9a 100644
+--- a/lib/bitmap.c
++++ b/lib/bitmap.c
+@@ -316,10 +316,11 @@ int bitmap_scnprintf(char *buf, unsigned
+ EXPORT_SYMBOL(bitmap_scnprintf);
+
+ /**
+- * bitmap_parse - convert an ASCII hex string into a bitmap.
+- * @ubuf: pointer to buffer in user space containing string.
+- * @ubuflen: buffer size in bytes. If string is smaller than this
++ * __bitmap_parse - convert an ASCII hex string into a bitmap.
++ * @buf: pointer to buffer containing string.
++ * @buflen: buffer size in bytes. If string is smaller than this
+ * then it must be terminated with a \0.
++ * @is_user: location of buffer, 0 indicates kernel space
+ * @maskp: pointer to bitmap array that will contain result.
+ * @nmaskbits: size of bitmap, in bits.
+ *
+@@ -330,11 +331,13 @@ EXPORT_SYMBOL(bitmap_scnprintf);
+ * characters and for grouping errors such as "1,,5", ",44", "," and "".
+ * Leading and trailing whitespace accepted, but not embedded whitespace.
+ */
+-int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
+- unsigned long *maskp, int nmaskbits)
++int __bitmap_parse(const char *buf, unsigned int buflen,
++ int is_user, unsigned long *maskp,
++ int nmaskbits)
+ {
+ int c, old_c, totaldigits, ndigits, nchunks, nbits;
+ u32 chunk;
++ const char __user *ubuf = buf;
+
+ bitmap_zero(maskp, nmaskbits);
+
+@@ -343,11 +346,15 @@ int bitmap_parse(const char __user *ubuf
+ chunk = ndigits = 0;
+
+ /* Get the next chunk of the bitmap */
+- while (ubuflen) {
++ while (buflen) {
+ old_c = c;
+- if (get_user(c, ubuf++))
+- return -EFAULT;
+- ubuflen--;
++ if (is_user) {
++ if (__get_user(c, ubuf++))
++ return -EFAULT;
++ }
++ else
++ c = *buf++;
++ buflen--;
+ if (isspace(c))
+ continue;
+
+@@ -388,11 +395,36 @@ int bitmap_parse(const char __user *ubuf
+ nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
+ if (nbits > nmaskbits)
+ return -EOVERFLOW;
+- } while (ubuflen && c == ',');
++ } while (buflen && c == ',');
+
+ return 0;
+ }
+-EXPORT_SYMBOL(bitmap_parse);
++EXPORT_SYMBOL(__bitmap_parse);
++
++/**
++ * bitmap_parse_user()
++ *
++ * @ubuf: pointer to user buffer containing string.
++ * @ulen: buffer size in bytes. If string is smaller than this
++ * then it must be terminated with a \0.
++ * @maskp: pointer to bitmap array that will contain result.
++ * @nmaskbits: size of bitmap, in bits.
++ *
++ * Wrapper for __bitmap_parse(), providing it with user buffer.
++ *
++ * We cannot have this as an inline function in bitmap.h because it needs
++ * linux/uaccess.h to get the access_ok() declaration and this causes
++ * cyclic dependencies.
++ */
++int bitmap_parse_user(const char __user *ubuf,
++ unsigned int ulen, unsigned long *maskp,
++ int nmaskbits)
++{
++ if (!access_ok(VERIFY_READ, ubuf, ulen))
++ return -EFAULT;
++ return __bitmap_parse((const char *)ubuf, ulen, 1, maskp, nmaskbits);
++}
++EXPORT_SYMBOL(bitmap_parse_user);
+
+ /*
+ * bscnl_emit(buf, buflen, rbot, rtop, bp)
+diff --git a/lib/errno.c b/lib/errno.c
+deleted file mode 100644
+index 41cb9d7..0000000
+--- a/lib/errno.c
++++ /dev/null
+@@ -1,7 +0,0 @@
+-/*
+- * linux/lib/errno.c
+- *
+- * Copyright (C) 1991, 1992 Linus Torvalds
+- */
+-
+-int errno;
+diff --git a/lib/genalloc.c b/lib/genalloc.c
+index 71338b4..75ae68c 100644
+--- a/lib/genalloc.c
++++ b/lib/genalloc.c
+@@ -14,11 +14,13 @@
+ #include <linux/genalloc.h>
+
+
+-/*
+- * Create a new special memory pool.
+- *
++/**
++ * gen_pool_create - create a new special memory pool
+ * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
+ * @nid: node id of the node the pool structure should be allocated on, or -1
++ *
++ * Create a new special memory pool that can be used to manage special purpose
++ * memory not managed by the regular kmalloc/kfree interface.
+ */
+ struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
+ {
+@@ -34,15 +36,15 @@ struct gen_pool *gen_pool_create(int min
+ }
+ EXPORT_SYMBOL(gen_pool_create);
+
+-
+-/*
+- * Add a new chunk of memory to the specified pool.
+- *
++/**
++ * gen_pool_add - add a new chunk of special memory to the pool
+ * @pool: pool to add new memory chunk to
+ * @addr: starting address of memory chunk to add to pool
+ * @size: size in bytes of the memory chunk to add to pool
+ * @nid: node id of the node the chunk structure and bitmap should be
+ * allocated on, or -1
++ *
++ * Add a new chunk of special memory to the specified pool.
+ */
+ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
+ int nid)
+@@ -69,13 +71,44 @@ int gen_pool_add(struct gen_pool *pool,
+ }
+ EXPORT_SYMBOL(gen_pool_add);
+
+-
+-/*
+- * Allocate the requested number of bytes from the specified pool.
+- * Uses a first-fit algorithm.
++/**
++ * gen_pool_destroy - destroy a special memory pool
++ * @pool: pool to destroy
+ *
++ * Destroy the specified special memory pool. Verifies that there are no
++ * outstanding allocations.
++ */
++void gen_pool_destroy(struct gen_pool *pool)
++{
++ struct list_head *_chunk, *_next_chunk;
++ struct gen_pool_chunk *chunk;
++ int order = pool->min_alloc_order;
++ int bit, end_bit;
++
++
++ write_lock(&pool->lock);
++ list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
++ chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
++ list_del(&chunk->next_chunk);
++
++ end_bit = (chunk->end_addr - chunk->start_addr) >> order;
++ bit = find_next_bit(chunk->bits, end_bit, 0);
++ BUG_ON(bit < end_bit);
++
++ kfree(chunk);
++ }
++ kfree(pool);
++ return;
++}
++EXPORT_SYMBOL(gen_pool_destroy);
++
++/**
++ * gen_pool_alloc - allocate special memory from the pool
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
++ *
++ * Allocate the requested number of bytes from the specified pool.
++ * Uses a first-fit algorithm.
+ */
+ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
+ {
+@@ -127,13 +160,13 @@ unsigned long gen_pool_alloc(struct gen_
+ }
+ EXPORT_SYMBOL(gen_pool_alloc);
+
+-
+-/*
+- * Free the specified memory back to the specified pool.
+- *
++/**
++ * gen_pool_free - free allocated special memory back to the pool
+ * @pool: pool to free to
+ * @addr: starting address of memory to free back to pool
+ * @size: size in bytes of memory to free
++ *
++ * Free previously allocated special memory back to the specified pool.
+ */
+ void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
+ {
+diff --git a/lib/hweight.c b/lib/hweight.c
+index 4382576..360556a 100644
+--- a/lib/hweight.c
++++ b/lib/hweight.c
+@@ -1,5 +1,6 @@
+ #include <linux/module.h>
+ #include <asm/types.h>
++#include <asm/bitops.h>
+
+ /**
+ * hweightN - returns the hamming weight of a N-bit word
+@@ -40,14 +41,19 @@ unsigned long hweight64(__u64 w)
+ #if BITS_PER_LONG == 32
+ return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+ #elif BITS_PER_LONG == 64
++#ifdef ARCH_HAS_FAST_MULTIPLIER
++ w -= (w >> 1) & 0x5555555555555555ul;
++ w = (w & 0x3333333333333333ul) + ((w >> 2) & 0x3333333333333333ul);
++ w = (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0ful;
++ return (w * 0x0101010101010101ul) >> 56;
++#else
+ __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
+ res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
+ res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
+ res = res + (res >> 8);
+ res = res + (res >> 16);
+ return (res + (res >> 32)) & 0x00000000000000FFul;
+-#else
+-#error BITS_PER_LONG not defined
++#endif
+ #endif
+ }
+ EXPORT_SYMBOL(hweight64);
+diff --git a/lib/ioremap.c b/lib/ioremap.c
+new file mode 100644
+index 0000000..99fa277
+--- /dev/null
++++ b/lib/ioremap.c
+@@ -0,0 +1,92 @@
++/*
++ * Re-map IO memory to kernel address space so that we can access it.
++ * This is needed for high PCI addresses that aren't mapped in the
++ * 640k-1MB IO memory area on PC's
++ *
++ * (C) Copyright 1995 1996 Linus Torvalds
++ */
++#include <linux/io.h>
++#include <linux/vmalloc.h>
++#include <linux/mm.h>
++
++#include <asm/cacheflush.h>
++#include <asm/pgtable.h>
++
++static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
++ unsigned long end, unsigned long phys_addr, pgprot_t prot)
++{
++ pte_t *pte;
++ unsigned long pfn;
++
++ pfn = phys_addr >> PAGE_SHIFT;
++ pte = pte_alloc_kernel(pmd, addr);
++ if (!pte)
++ return -ENOMEM;
++ do {
++ BUG_ON(!pte_none(*pte));
++ set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
++ pfn++;
++ } while (pte++, addr += PAGE_SIZE, addr != end);
++ return 0;
++}
++
++static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
++ unsigned long end, unsigned long phys_addr, pgprot_t prot)
++{
++ pmd_t *pmd;
++ unsigned long next;
++
++ phys_addr -= addr;
++ pmd = pmd_alloc(&init_mm, pud, addr);
++ if (!pmd)
++ return -ENOMEM;
++ do {
++ next = pmd_addr_end(addr, end);
++ if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot))
++ return -ENOMEM;
++ } while (pmd++, addr = next, addr != end);
++ return 0;
++}
++
++static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
++ unsigned long end, unsigned long phys_addr, pgprot_t prot)
++{
++ pud_t *pud;
++ unsigned long next;
++
++ phys_addr -= addr;
++ pud = pud_alloc(&init_mm, pgd, addr);
++ if (!pud)
++ return -ENOMEM;
++ do {
++ next = pud_addr_end(addr, end);
++ if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
++ return -ENOMEM;
++ } while (pud++, addr = next, addr != end);
++ return 0;
++}
++
++int ioremap_page_range(unsigned long addr,
++ unsigned long end, unsigned long phys_addr, pgprot_t prot)
++{
++ pgd_t *pgd;
++ unsigned long start;
++ unsigned long next;
++ int err;
++
++ BUG_ON(addr >= end);
++
++ start = addr;
++ phys_addr -= addr;
++ pgd = pgd_offset_k(addr);
++ do {
++ next = pgd_addr_end(addr, end);
++ err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
++ if (err)
++ break;
++ } while (pgd++, addr = next, addr != end);
++
++ flush_cache_vmap(start, end);
++
++ return err;
++}
+diff --git a/lib/irq_regs.c b/lib/irq_regs.c
+new file mode 100644
+index 0000000..753880a
+--- /dev/null
++++ b/lib/irq_regs.c
+@@ -0,0 +1,17 @@
++/* saved per-CPU IRQ register pointer
++ *
++ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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 <asm/irq_regs.h>
++
++#ifndef ARCH_HAS_OWN_IRQ_REGS
++DEFINE_PER_CPU(struct pt_regs *, __irq_regs);
++EXPORT_PER_CPU_SYMBOL(__irq_regs);
++#endif
+diff --git a/lib/klist.c b/lib/klist.c
+index 9c94f0b..120bd17 100644
+--- a/lib/klist.c
++++ b/lib/klist.c
+@@ -123,12 +123,10 @@ EXPORT_SYMBOL_GPL(klist_add_tail);
+ static void klist_release(struct kref * kref)
+ {
+ struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+- void (*put)(struct klist_node *) = n->n_klist->put;
++
+ list_del(&n->n_node);
+ complete(&n->n_removed);
+ n->n_klist = NULL;
+- if (put)
+- put(n);
+ }
+
+ static int klist_dec_and_del(struct klist_node * n)
+@@ -145,10 +143,14 @@ static int klist_dec_and_del(struct klis
+ void klist_del(struct klist_node * n)
+ {
+ struct klist * k = n->n_klist;
++ void (*put)(struct klist_node *) = k->put;
+
+ spin_lock(&k->k_lock);
+- klist_dec_and_del(n);
++ if (!klist_dec_and_del(n))
++ put = NULL;
+ spin_unlock(&k->k_lock);
++ if (put)
++ put(n);
+ }
+
+ EXPORT_SYMBOL_GPL(klist_del);
+@@ -161,10 +163,7 @@ EXPORT_SYMBOL_GPL(klist_del);
+
+ void klist_remove(struct klist_node * n)
+ {
+- struct klist * k = n->n_klist;
+- spin_lock(&k->k_lock);
+- klist_dec_and_del(n);
+- spin_unlock(&k->k_lock);
++ klist_del(n);
+ wait_for_completion(&n->n_removed);
+ }
+
+@@ -260,12 +259,15 @@ static struct klist_node * to_klist_node
+ struct klist_node * klist_next(struct klist_iter * i)
+ {
+ struct list_head * next;
++ struct klist_node * lnode = i->i_cur;
+ struct klist_node * knode = NULL;
++ void (*put)(struct klist_node *) = i->i_klist->put;
+
+ spin_lock(&i->i_klist->k_lock);
+- if (i->i_cur) {
+- next = i->i_cur->n_node.next;
+- klist_dec_and_del(i->i_cur);
++ if (lnode) {
++ next = lnode->n_node.next;
++ if (!klist_dec_and_del(lnode))
++ put = NULL;
+ } else
+ next = i->i_head->next;
+
+@@ -275,6 +277,8 @@ struct klist_node * klist_next(struct kl
+ }
+ i->i_cur = knode;
+ spin_unlock(&i->i_klist->k_lock);
++ if (put && lnode)
++ put(lnode);
+ return knode;
+ }
+
+diff --git a/lib/kobject.c b/lib/kobject.c
+index 8e7c719..7dd5c0e 100644
+--- a/lib/kobject.c
++++ b/lib/kobject.c
+@@ -119,6 +119,7 @@ char *kobject_get_path(struct kobject *k
+
+ return path;
+ }
++EXPORT_SYMBOL_GPL(kobject_get_path);
+
+ /**
+ * kobject_init - initialize object.
+@@ -407,6 +408,7 @@ static struct kobj_type dir_ktype = {
+ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+ {
+ struct kobject *k;
++ int ret;
+
+ if (!parent)
+ return NULL;
+@@ -418,7 +420,13 @@ struct kobject *kobject_add_dir(struct k
+ k->parent = parent;
+ k->ktype = &dir_ktype;
+ kobject_set_name(k, name);
+- kobject_register(k);
++ ret = kobject_register(k);
++ if (ret < 0) {
++ printk(KERN_WARNING "kobject_add_dir: "
++ "kobject_register error: %d\n", ret);
++ kobject_del(k);
++ return NULL;
++ }
+
+ return k;
+ }
+diff --git a/lib/list_debug.c b/lib/list_debug.c
+new file mode 100644
+index 0000000..7ba9d82
+--- /dev/null
++++ b/lib/list_debug.c
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 2006, Red Hat, Inc., Dave Jones
++ * Released under the General Public License (GPL).
++ *
++ * This file contains the linked list implementations for
++ * DEBUG_LIST.
++ */
++
++#include <linux/module.h>
++#include <linux/list.h>
++
++/*
++ * Insert a new entry between two known consecutive entries.
++ *
++ * This is only for internal list manipulation where we know
++ * the prev/next entries already!
++ */
++
++void __list_add(struct list_head *new,
++ struct list_head *prev,
++ struct list_head *next)
++{
++ if (unlikely(next->prev != prev)) {
++ printk(KERN_ERR "list_add corruption. next->prev should be %p, but was %p\n",
++ prev, next->prev);
++ BUG();
++ }
++ if (unlikely(prev->next != next)) {
++ printk(KERN_ERR "list_add corruption. prev->next should be %p, but was %p\n",
++ next, prev->next);
++ BUG();
++ }
++ next->prev = new;
++ new->next = next;
++ new->prev = prev;
++ prev->next = new;
++}
++EXPORT_SYMBOL(__list_add);
++
++/**
++ * list_add - add a new entry
++ * @new: new entry to be added
++ * @head: list head to add it after
++ *
++ * Insert a new entry after the specified head.
++ * This is good for implementing stacks.
++ */
++void list_add(struct list_head *new, struct list_head *head)
++{
++ __list_add(new, head, head->next);
++}
++EXPORT_SYMBOL(list_add);
++
++/**
++ * list_del - deletes entry from list.
++ * @entry: the element to delete from the list.
++ * Note: list_empty on entry does not return true after this, the entry is
++ * in an undefined state.
++ */
++void list_del(struct list_head *entry)
++{
++ if (unlikely(entry->prev->next != entry)) {
++ printk(KERN_ERR "list_del corruption. prev->next should be %p, "
++ "but was %p\n", entry, entry->prev->next);
++ BUG();
++ }
++ if (unlikely(entry->next->prev != entry)) {
++ printk(KERN_ERR "list_del corruption. next->prev should be %p, "
++ "but was %p\n", entry, entry->next->prev);
++ BUG();
++ }
++ __list_del(entry->prev, entry->next);
++ entry->next = LIST_POISON1;
++ entry->prev = LIST_POISON2;
++}
++EXPORT_SYMBOL(list_del);
+diff --git a/lib/radix-tree.c b/lib/radix-tree.c
+index 637d556..aa9bfd0 100644
+--- a/lib/radix-tree.c
++++ b/lib/radix-tree.c
+@@ -160,13 +160,13 @@ static inline int tag_get(struct radix_t
+
+ static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
+ {
+- root->gfp_mask |= (1 << (tag + __GFP_BITS_SHIFT));
++ root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT));
+ }
+
+
+ static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
+ {
+- root->gfp_mask &= ~(1 << (tag + __GFP_BITS_SHIFT));
++ root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT));
+ }
+
+ static inline void root_tag_clear_all(struct radix_tree_root *root)
+@@ -176,7 +176,7 @@ static inline void root_tag_clear_all(st
+
+ static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag)
+ {
+- return root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
++ return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
+ }
+
+ /*
+diff --git a/lib/random32.c b/lib/random32.c
+new file mode 100644
+index 0000000..4a15ce5
+--- /dev/null
++++ b/lib/random32.c
+@@ -0,0 +1,142 @@
++/*
++ This is a maximally equidistributed combined Tausworthe generator
++ based on code from GNU Scientific Library 1.5 (30 Jun 2004)
++
++ x_n = (s1_n ^ s2_n ^ s3_n)
++
++ s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
++ s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
++ s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
++
++ The period of this generator is about 2^88.
++
++ From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
++ Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
++
++ This is available on the net from L'Ecuyer's home page,
++
++ http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
++ ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
++
++ There is an erratum in the paper "Tables of Maximally
++ Equidistributed Combined LFSR Generators", Mathematics of
++ Computation, 68, 225 (1999), 261--269:
++ http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
++
++ ... the k_j most significant bits of z_j must be non-
++ zero, for each j. (Note: this restriction also applies to the
++ computer code given in [4], but was mistakenly not mentioned in
++ that paper.)
++
++ This affects the seeding procedure by imposing the requirement
++ s1 > 1, s2 > 7, s3 > 15.
++
++*/
++
++#include <linux/types.h>
++#include <linux/percpu.h>
++#include <linux/module.h>
++#include <linux/random.h>
++
++struct rnd_state {
++ u32 s1, s2, s3;
++};
++
++static DEFINE_PER_CPU(struct rnd_state, net_rand_state);
++
++static u32 __random32(struct rnd_state *state)
++{
++#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
++
++ state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
++ state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
++ state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
++
++ return (state->s1 ^ state->s2 ^ state->s3);
++}
++
++static void __set_random32(struct rnd_state *state, unsigned long s)
++{
++ if (s == 0)
++ s = 1; /* default seed is 1 */
++
++#define LCG(n) (69069 * n)
++ state->s1 = LCG(s);
++ state->s2 = LCG(state->s1);
++ state->s3 = LCG(state->s2);
++
++ /* "warm it up" */
++ __random32(state);
++ __random32(state);
++ __random32(state);
++ __random32(state);
++ __random32(state);
++ __random32(state);
++}
++
++/**
++ * random32 - pseudo random number generator
++ *
++ * A 32 bit pseudo-random number is generated using a fast
++ * algorithm suitable for simulation. This algorithm is NOT
++ * considered safe for cryptographic use.
++ */
++u32 random32(void)
++{
++ unsigned long r;
++ struct rnd_state *state = &get_cpu_var(net_rand_state);
++ r = __random32(state);
++ put_cpu_var(state);
++ return r;
++}
++EXPORT_SYMBOL(random32);
++
++/**
++ * srandom32 - add entropy to pseudo random number generator
++ * @seed: seed value
++ *
++ * Add some additional seeding to the random32() pool.
++ * Note: this pool is per cpu so it only affects current CPU.
++ */
++void srandom32(u32 entropy)
++{
++ struct rnd_state *state = &get_cpu_var(net_rand_state);
++ __set_random32(state, state->s1 ^ entropy);
++ put_cpu_var(state);
++}
++EXPORT_SYMBOL(srandom32);
++
++/*
++ * Generate some initially weak seeding values to allow
++ * to start the random32() engine.
++ */
++static int __init random32_init(void)
++{
++ int i;
++
++ for_each_possible_cpu(i) {
++ struct rnd_state *state = &per_cpu(net_rand_state,i);
++ __set_random32(state, i + jiffies);
++ }
++ return 0;
++}
++core_initcall(random32_init);
++
++/*
++ * Generate better values after random number generator
++ * is fully initalized.
++ */
++static int __init random32_reseed(void)
++{
++ int i;
++ unsigned long seed;
++
++ for_each_possible_cpu(i) {
++ struct rnd_state *state = &per_cpu(net_rand_state,i);
++
++ get_random_bytes(&seed, sizeof(seed));
++ __set_random32(state, seed);
++ }
++ return 0;
++}
++late_initcall(random32_reseed);
+diff --git a/lib/rbtree.c b/lib/rbtree.c
+index 1e55ba1..48499c2 100644
+--- a/lib/rbtree.c
++++ b/lib/rbtree.c
+@@ -322,6 +322,9 @@ struct rb_node *rb_next(struct rb_node *
+ {
+ struct rb_node *parent;
+
++ if (rb_parent(node) == node)
++ return NULL;
++
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->rb_right) {
+@@ -348,6 +351,9 @@ struct rb_node *rb_prev(struct rb_node *
+ {
+ struct rb_node *parent;
+
++ if (rb_parent(node) == node)
++ return NULL;
++
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->rb_left) {
+diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
+index 2cc11fa..a4b730a 100644
+--- a/lib/reed_solomon/reed_solomon.c
++++ b/lib/reed_solomon/reed_solomon.c
+@@ -1,5 +1,5 @@
+ /*
+- * lib/reed_solomon/rslib.c
++ * lib/reed_solomon/reed_solomon.c
+ *
+ * Overview:
+ * Generic Reed Solomon encoder / decoder library
+diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c
+index db4fed7..c4cfd6c 100644
+--- a/lib/rwsem-spinlock.c
++++ b/lib/rwsem-spinlock.c
+@@ -28,7 +28,7 @@ void __init_rwsem(struct rw_semaphore *s
+ * Make sure we are not reinitializing a held semaphore:
+ */
+ debug_check_no_locks_freed((void *)sem, sizeof(*sem));
+- lockdep_init_map(&sem->dep_map, name, key);
++ lockdep_init_map(&sem->dep_map, name, key, 0);
+ #endif
+ sem->activity = 0;
+ spin_lock_init(&sem->wait_lock);
+diff --git a/lib/rwsem.c b/lib/rwsem.c
+index b322421..cdb4e3d 100644
+--- a/lib/rwsem.c
++++ b/lib/rwsem.c
+@@ -19,7 +19,7 @@ void __init_rwsem(struct rw_semaphore *s
+ * Make sure we are not reinitializing a held semaphore:
+ */
+ debug_check_no_locks_freed((void *)sem, sizeof(*sem));
+- lockdep_init_map(&sem->dep_map, name, key);
++ lockdep_init_map(&sem->dep_map, name, key, 0);
+ #endif
+ sem->count = RWSEM_UNLOCKED_VALUE;
+ spin_lock_init(&sem->wait_lock);
+@@ -146,7 +146,7 @@ __rwsem_do_wake(struct rw_semaphore *sem
+ /*
+ * wait for a lock to be granted
+ */
+-static inline struct rw_semaphore *
++static struct rw_semaphore *
+ rwsem_down_failed_common(struct rw_semaphore *sem,
+ struct rwsem_waiter *waiter, signed long adjustment)
+ {
+diff --git a/lib/sort.c b/lib/sort.c
+index 5f3b51f..488788b 100644
+--- a/lib/sort.c
++++ b/lib/sort.c
+@@ -49,15 +49,15 @@ void sort(void *base, size_t num, size_t
+ void (*swap)(void *, void *, int size))
+ {
+ /* pre-scale counters for performance */
+- int i = (num/2) * size, n = num * size, c, r;
++ int i = (num/2 - 1) * size, n = num * size, c, r;
+
+ if (!swap)
+ swap = (size == 4 ? u32_swap : generic_swap);
+
+ /* heapify */
+ for ( ; i >= 0; i -= size) {
+- for (r = i; r * 2 < n; r = c) {
+- c = r * 2;
++ for (r = i; r * 2 + size < n; r = c) {
++ c = r * 2 + size;
+ if (c < n - size && cmp(base + c, base + c + size) < 0)
+ c += size;
+ if (cmp(base + r, base + c) >= 0)
+@@ -69,8 +69,8 @@ void sort(void *base, size_t num, size_t
+ /* sort */
+ for (i = n - size; i >= 0; i -= size) {
+ swap(base, base + i, size);
+- for (r = 0; r * 2 < i; r = c) {
+- c = r * 2;
++ for (r = 0; r * 2 + size < i; r = c) {
++ c = r * 2 + size;
+ if (c < i - size && cmp(base + c, base + c + size) < 0)
+ c += size;
+ if (cmp(base + r, base + c) >= 0)
+diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
+index 58c577d..b6c4f89 100644
+--- a/lib/spinlock_debug.c
++++ b/lib/spinlock_debug.c
+@@ -20,7 +20,7 @@ void __spin_lock_init(spinlock_t *lock,
+ * Make sure we are not reinitializing a held lock:
+ */
+ debug_check_no_locks_freed((void *)lock, sizeof(*lock));
+- lockdep_init_map(&lock->dep_map, name, key);
++ lockdep_init_map(&lock->dep_map, name, key, 0);
+ #endif
+ lock->raw_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
+ lock->magic = SPINLOCK_MAGIC;
+@@ -38,7 +38,7 @@ void __rwlock_init(rwlock_t *lock, const
+ * Make sure we are not reinitializing a held lock:
+ */
+ debug_check_no_locks_freed((void *)lock, sizeof(*lock));
+- lockdep_init_map(&lock->dep_map, name, key);
++ lockdep_init_map(&lock->dep_map, name, key, 0);
+ #endif
+ lock->raw_lock = (raw_rwlock_t) __RAW_RW_LOCK_UNLOCKED;
+ lock->magic = RWLOCK_MAGIC;
+@@ -99,11 +99,12 @@ static inline void debug_spin_unlock(spi
+
+ static void __spin_lock_debug(spinlock_t *lock)
+ {
+- int print_once = 1;
+ u64 i;
++ u64 loops = loops_per_jiffy * HZ;
++ int print_once = 1;
+
+ for (;;) {
+- for (i = 0; i < loops_per_jiffy * HZ; i++) {
++ for (i = 0; i < loops; i++) {
+ if (__raw_spin_trylock(&lock->raw_lock))
+ return;
+ __delay(1);
+@@ -165,11 +166,12 @@ static void rwlock_bug(rwlock_t *lock, c
+ #if 0 /* __write_lock_debug() can lock up - maybe this can too? */
+ static void __read_lock_debug(rwlock_t *lock)
+ {
+- int print_once = 1;
+ u64 i;
++ u64 loops = loops_per_jiffy * HZ;
++ int print_once = 1;
+
+ for (;;) {
+- for (i = 0; i < loops_per_jiffy * HZ; i++) {
++ for (i = 0; i < loops; i++) {
+ if (__raw_read_trylock(&lock->raw_lock))
+ return;
+ __delay(1);
+@@ -239,11 +241,12 @@ static inline void debug_write_unlock(rw
+ #if 0 /* This can cause lockups */
+ static void __write_lock_debug(rwlock_t *lock)
+ {
+- int print_once = 1;
+ u64 i;
++ u64 loops = loops_per_jiffy * HZ;
++ int print_once = 1;
+
+ for (;;) {
+- for (i = 0; i < loops_per_jiffy * HZ; i++) {
++ for (i = 0; i < loops; i++) {
+ if (__raw_write_trylock(&lock->raw_lock))
+ return;
+ __delay(1);
+diff --git a/lib/string.c b/lib/string.c
+index 6307726..a485d75 100644
+--- a/lib/string.c
++++ b/lib/string.c
+@@ -320,7 +320,7 @@ char *strstrip(char *s)
+ return s;
+
+ end = s + size - 1;
+- while (end != s && isspace(*end))
++ while (end >= s && isspace(*end))
+ end--;
+ *(end + 1) = '\0';
+
+diff --git a/lib/ts_fsm.c b/lib/ts_fsm.c
+index 87847c2..af575b6 100644
+--- a/lib/ts_fsm.c
++++ b/lib/ts_fsm.c
+@@ -12,13 +12,13 @@
+ *
+ * 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
++ * sequentially on an 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
++ * The algorithm differs between strict/non-strict mode specifying
++ * whether the pattern has to start at the first octet. Strict mode
+ * is enabled by default and can be disabled by inserting
+ * TS_FSM_HEAD_IGNORE as the first token in the chain.
+ *
+@@ -44,7 +44,7 @@ struct ts_fsm
+ #define _W 0x200 /* wildcard */
+
+ /* Map to _ctype flags and some magic numbers */
+-static u16 token_map[TS_FSM_TYPE_MAX+1] = {
++static const u16 token_map[TS_FSM_TYPE_MAX+1] = {
+ [TS_FSM_SPECIFIC] = 0,
+ [TS_FSM_WILDCARD] = _W,
+ [TS_FSM_CNTRL] = _C,
+@@ -61,7 +61,7 @@ static u16 token_map[TS_FSM_TYPE_MAX+1]
+ [TS_FSM_ASCII] = _A,
+ };
+
+-static u16 token_lookup_tbl[256] = {
++static const 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 */
+diff --git a/mm/Kconfig b/mm/Kconfig
+index 8f5b456..db7c55d 100644
+--- a/mm/Kconfig
++++ b/mm/Kconfig
+@@ -92,7 +92,7 @@ config HAVE_MEMORY_PRESENT
+
+ #
+ # SPARSEMEM_EXTREME (which is the default) does some bootmem
+-# allocations when memory_present() is called. If this can not
++# allocations when memory_present() is called. If this cannot
+ # be done on your architecture, select this option. However,
+ # statically allocating the mem_section[] array can potentially
+ # consume vast quantities of .bss, so be careful.
+@@ -104,7 +104,7 @@ config SPARSEMEM_STATIC
+ def_bool n
+
+ #
+-# Architectecture platforms which require a two level mem_section in SPARSEMEM
++# Architecture platforms which require a two level mem_section in SPARSEMEM
+ # must select this option. This is usually for architecture platforms with
+ # an extremely sparse physical address space.
+ #
+@@ -115,12 +115,17 @@ config SPARSEMEM_EXTREME
+ # eventually, we can have this option just 'select SPARSEMEM'
+ config MEMORY_HOTPLUG
+ bool "Allow for memory hot-add"
+- depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
++ depends on SPARSEMEM || X86_64_ACPI_NUMA
++ depends on HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
+ depends on (IA64 || X86 || PPC64)
+
+ comment "Memory hotplug is currently incompatible with Software Suspend"
+ depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
+
++config MEMORY_HOTPLUG_SPARSE
++ def_bool y
++ depends on SPARSEMEM && MEMORY_HOTPLUG
++
+ # Heavily threaded applications may benefit from splitting the mm-wide
+ # page_table_lock, so that faults on different parts of the user address
+ # space can be handled with less contention: split it at this NR_CPUS.
+diff --git a/mm/Makefile b/mm/Makefile
+index 9dd824c..f3c077e 100644
+--- a/mm/Makefile
++++ b/mm/Makefile
+@@ -10,17 +10,22 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o
+ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
+ page_alloc.o page-writeback.o pdflush.o \
+ readahead.o swap.o truncate.o vmscan.o \
+- prio_tree.o util.o mmzone.o vmstat.o $(mmu-y)
++ prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
++ $(mmu-y)
+
++ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy)
++obj-y += bounce.o
++endif
+ obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o
+ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
+ obj-$(CONFIG_NUMA) += mempolicy.o
+ obj-$(CONFIG_SPARSEMEM) += sparse.o
+ obj-$(CONFIG_SHMEM) += shmem.o
++obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ obj-$(CONFIG_SLOB) += slob.o
+ obj-$(CONFIG_SLAB) += slab.o
+ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
+ obj-$(CONFIG_MIGRATION) += migrate.o
+-
++obj-$(CONFIG_SMP) += allocpercpu.o
+diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
+new file mode 100644
+index 0000000..eaa9abe
+--- /dev/null
++++ b/mm/allocpercpu.c
+@@ -0,0 +1,129 @@
++/*
++ * linux/mm/allocpercpu.c
++ *
++ * Separated from slab.c August 11, 2006 Christoph Lameter <clameter at sgi.com>
++ */
++#include <linux/mm.h>
++#include <linux/module.h>
++
++/**
++ * percpu_depopulate - depopulate per-cpu data for given cpu
++ * @__pdata: per-cpu data to depopulate
++ * @cpu: depopulate per-cpu data for this cpu
++ *
++ * Depopulating per-cpu data for a cpu going offline would be a typical
++ * use case. You need to register a cpu hotplug handler for that purpose.
++ */
++void percpu_depopulate(void *__pdata, int cpu)
++{
++ struct percpu_data *pdata = __percpu_disguise(__pdata);
++ if (pdata->ptrs[cpu]) {
++ kfree(pdata->ptrs[cpu]);
++ pdata->ptrs[cpu] = NULL;
++ }
++}
++EXPORT_SYMBOL_GPL(percpu_depopulate);
++
++/**
++ * percpu_depopulate_mask - depopulate per-cpu data for some cpu's
++ * @__pdata: per-cpu data to depopulate
++ * @mask: depopulate per-cpu data for cpu's selected through mask bits
++ */
++void __percpu_depopulate_mask(void *__pdata, cpumask_t *mask)
++{
++ int cpu;
++ for_each_cpu_mask(cpu, *mask)
++ percpu_depopulate(__pdata, cpu);
++}
++EXPORT_SYMBOL_GPL(__percpu_depopulate_mask);
++
++/**
++ * percpu_populate - populate per-cpu data for given cpu
++ * @__pdata: per-cpu data to populate further
++ * @size: size of per-cpu object
++ * @gfp: may sleep or not etc.
++ * @cpu: populate per-data for this cpu
++ *
++ * Populating per-cpu data for a cpu coming online would be a typical
++ * use case. You need to register a cpu hotplug handler for that purpose.
++ * Per-cpu object is populated with zeroed buffer.
++ */
++void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu)
++{
++ struct percpu_data *pdata = __percpu_disguise(__pdata);
++ int node = cpu_to_node(cpu);
++
++ BUG_ON(pdata->ptrs[cpu]);
++ if (node_online(node)) {
++ /* FIXME: kzalloc_node(size, gfp, node) */
++ pdata->ptrs[cpu] = kmalloc_node(size, gfp, node);
++ if (pdata->ptrs[cpu])
++ memset(pdata->ptrs[cpu], 0, size);
++ } else
++ pdata->ptrs[cpu] = kzalloc(size, gfp);
++ return pdata->ptrs[cpu];
++}
++EXPORT_SYMBOL_GPL(percpu_populate);
++
++/**
++ * percpu_populate_mask - populate per-cpu data for more cpu's
++ * @__pdata: per-cpu data to populate further
++ * @size: size of per-cpu object
++ * @gfp: may sleep or not etc.
++ * @mask: populate per-cpu data for cpu's selected through mask bits
++ *
++ * Per-cpu objects are populated with zeroed buffers.
++ */
++int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp,
++ cpumask_t *mask)
++{
++ cpumask_t populated = CPU_MASK_NONE;
++ int cpu;
++
++ for_each_cpu_mask(cpu, *mask)
++ if (unlikely(!percpu_populate(__pdata, size, gfp, cpu))) {
++ __percpu_depopulate_mask(__pdata, &populated);
++ return -ENOMEM;
++ } else
++ cpu_set(cpu, populated);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(__percpu_populate_mask);
++
++/**
++ * percpu_alloc_mask - initial setup of per-cpu data
++ * @size: size of per-cpu object
++ * @gfp: may sleep or not etc.
++ * @mask: populate per-data for cpu's selected through mask bits
++ *
++ * Populating per-cpu data for all online cpu's would be a typical use case,
++ * which is simplified by the percpu_alloc() wrapper.
++ * Per-cpu objects are populated with zeroed buffers.
++ */
++void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
++{
++ void *pdata = kzalloc(sizeof(struct percpu_data), gfp);
++ void *__pdata = __percpu_disguise(pdata);
++
++ if (unlikely(!pdata))
++ return NULL;
++ if (likely(!__percpu_populate_mask(__pdata, size, gfp, mask)))
++ return __pdata;
++ kfree(pdata);
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(__percpu_alloc_mask);
++
++/**
++ * percpu_free - final cleanup of per-cpu data
++ * @__pdata: object to clean up
++ *
++ * We simply clean up any per-cpu object left. No need for the client to
++ * track and specify through a bis mask which per-cpu objects are to free.
++ */
++void percpu_free(void *__pdata)
++{
++ __percpu_depopulate_mask(__pdata, &cpu_possible_map);
++ kfree(__percpu_disguise(__pdata));
++}
++EXPORT_SYMBOL_GPL(percpu_free);
+diff --git a/mm/backing-dev.c b/mm/backing-dev.c
+new file mode 100644
+index 0000000..f50a281
+--- /dev/null
++++ b/mm/backing-dev.c
+@@ -0,0 +1,69 @@
++
++#include <linux/wait.h>
++#include <linux/backing-dev.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/module.h>
++
++static wait_queue_head_t congestion_wqh[2] = {
++ __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
++ __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
++ };
++
++
++void clear_bdi_congested(struct backing_dev_info *bdi, int rw)
++{
++ enum bdi_state bit;
++ wait_queue_head_t *wqh = &congestion_wqh[rw];
++
++ bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
++ clear_bit(bit, &bdi->state);
++ smp_mb__after_clear_bit();
++ if (waitqueue_active(wqh))
++ wake_up(wqh);
++}
++EXPORT_SYMBOL(clear_bdi_congested);
++
++void set_bdi_congested(struct backing_dev_info *bdi, int rw)
++{
++ enum bdi_state bit;
++
++ bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
++ set_bit(bit, &bdi->state);
++}
++EXPORT_SYMBOL(set_bdi_congested);
++
++/**
++ * congestion_wait - wait for a backing_dev to become uncongested
++ * @rw: READ or WRITE
++ * @timeout: timeout in jiffies
++ *
++ * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit
++ * write congestion. If no backing_devs are congested then just wait for the
++ * next write to be completed.
++ */
++long congestion_wait(int rw, long timeout)
++{
++ long ret;
++ DEFINE_WAIT(wait);
++ wait_queue_head_t *wqh = &congestion_wqh[rw];
++
++ prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
++ ret = io_schedule_timeout(timeout);
++ finish_wait(wqh, &wait);
++ return ret;
++}
++EXPORT_SYMBOL(congestion_wait);
++
++/**
++ * congestion_end - wake up sleepers on a congested backing_dev_info
++ * @rw: READ or WRITE
++ */
++void congestion_end(int rw)
++{
++ wait_queue_head_t *wqh = &congestion_wqh[rw];
++
++ if (waitqueue_active(wqh))
++ wake_up(wqh);
++}
++EXPORT_SYMBOL(congestion_end);
+diff --git a/mm/bootmem.c b/mm/bootmem.c
+index 50353e0..d53112f 100644
+--- a/mm/bootmem.c
++++ b/mm/bootmem.c
+@@ -8,17 +8,15 @@
+ * free memory collector. It's used to deal with reserved
+ * system memory and memory holes as well.
+ */
+-
+-#include <linux/mm.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/swap.h>
+-#include <linux/interrupt.h>
+ #include <linux/init.h>
++#include <linux/pfn.h>
+ #include <linux/bootmem.h>
+-#include <linux/mmzone.h>
+ #include <linux/module.h>
+-#include <asm/dma.h>
++
++#include <asm/bug.h>
+ #include <asm/io.h>
++#include <asm/processor.h>
++
+ #include "internal.h"
+
+ /*
+@@ -41,7 +39,7 @@ 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)
++unsigned long __init bootmem_bootmap_pages(unsigned long pages)
+ {
+ unsigned long mapsize;
+
+@@ -51,12 +49,14 @@ unsigned long __init bootmem_bootmap_pag
+
+ return mapsize;
+ }
++
+ /*
+ * link bdata in order
+ */
+-static void link_bootmem(bootmem_data_t *bdata)
++static void __init link_bootmem(bootmem_data_t *bdata)
+ {
+ bootmem_data_t *ent;
++
+ if (list_empty(&bdata_list)) {
+ list_add(&bdata->list, &bdata_list);
+ return;
+@@ -69,22 +69,32 @@ static void link_bootmem(bootmem_data_t
+ }
+ }
+ list_add_tail(&bdata->list, &bdata_list);
+- return;
+ }
+
++/*
++ * Given an initialised bdata, it returns the size of the boot bitmap
++ */
++static unsigned long __init get_mapsize(bootmem_data_t *bdata)
++{
++ unsigned long mapsize;
++ unsigned long start = PFN_DOWN(bdata->node_boot_start);
++ unsigned long end = bdata->node_low_pfn;
++
++ mapsize = ((end - start) + 7) / 8;
++ return ALIGN(mapsize, sizeof(long));
++}
+
+ /*
+ * Called once to set up the allocator itself.
+ */
+-static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
++static unsigned long __init init_bootmem_core(pg_data_t *pgdat,
+ unsigned long mapstart, unsigned long start, unsigned long end)
+ {
+ bootmem_data_t *bdata = pgdat->bdata;
+- unsigned long mapsize = ((end - start)+7)/8;
++ unsigned long mapsize;
+
+- mapsize = ALIGN(mapsize, sizeof(long));
+- bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
+- bdata->node_boot_start = (start << PAGE_SHIFT);
++ bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));
++ bdata->node_boot_start = PFN_PHYS(start);
+ bdata->node_low_pfn = end;
+ link_bootmem(bdata);
+
+@@ -92,6 +102,7 @@ static unsigned long __init init_bootmem
+ * Initially all pages are reserved - setup_arch() has to
+ * register free RAM areas explicitly.
+ */
++ mapsize = get_mapsize(bdata);
+ memset(bdata->node_bootmem_map, 0xff, mapsize);
+
+ return mapsize;
+@@ -102,22 +113,22 @@ static unsigned long __init init_bootmem
+ * might be used for boot-time allocations - or it might get added
+ * to the free page pool later on.
+ */
+-static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
++static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
++ unsigned long size)
+ {
++ unsigned long sidx, eidx;
+ unsigned long i;
++
+ /*
+ * round up, partially reserved pages are considered
+ * fully reserved.
+ */
+- unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE;
+- unsigned long eidx = (addr + size - bdata->node_boot_start +
+- PAGE_SIZE-1)/PAGE_SIZE;
+- unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE;
+-
+ BUG_ON(!size);
+- BUG_ON(sidx >= eidx);
+- BUG_ON((addr >> PAGE_SHIFT) >= bdata->node_low_pfn);
+- BUG_ON(end > bdata->node_low_pfn);
++ BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn);
++ BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn);
++
++ sidx = PFN_DOWN(addr - bdata->node_boot_start);
++ eidx = PFN_UP(addr + size - bdata->node_boot_start);
+
+ for (i = sidx; i < eidx; i++)
+ if (test_and_set_bit(i, bdata->node_bootmem_map)) {
+@@ -127,20 +138,18 @@ static void __init reserve_bootmem_core(
+ }
+ }
+
+-static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
++static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
++ unsigned long size)
+ {
++ unsigned long sidx, eidx;
+ unsigned long i;
+- unsigned long start;
++
+ /*
+ * round down end of usable mem, partially free pages are
+ * considered reserved.
+ */
+- unsigned long sidx;
+- unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE;
+- unsigned long end = (addr + size)/PAGE_SIZE;
+-
+ BUG_ON(!size);
+- BUG_ON(end > bdata->node_low_pfn);
++ BUG_ON(PFN_DOWN(addr + size) > bdata->node_low_pfn);
+
+ if (addr < bdata->last_success)
+ bdata->last_success = addr;
+@@ -148,8 +157,8 @@ static void __init free_bootmem_core(boo
+ /*
+ * Round up the beginning of the address.
+ */
+- start = (addr + PAGE_SIZE-1) / PAGE_SIZE;
+- sidx = start - (bdata->node_boot_start/PAGE_SIZE);
++ sidx = PFN_UP(addr) - PFN_DOWN(bdata->node_boot_start);
++ eidx = PFN_DOWN(addr + size - bdata->node_boot_start);
+
+ for (i = sidx; i < eidx; i++) {
+ if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map)))
+@@ -175,10 +184,10 @@ __alloc_bootmem_core(struct bootmem_data
+ unsigned long align, unsigned long goal, unsigned long limit)
+ {
+ unsigned long offset, remaining_size, areasize, preferred;
+- unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn;
++ unsigned long i, start = 0, incr, eidx, end_pfn;
+ void *ret;
+
+- if(!size) {
++ if (!size) {
+ printk("__alloc_bootmem_core(): zero-sized request\n");
+ BUG();
+ }
+@@ -187,23 +196,22 @@ __alloc_bootmem_core(struct bootmem_data
+ if (limit && bdata->node_boot_start >= limit)
+ return NULL;
+
+- limit >>=PAGE_SHIFT;
++ end_pfn = bdata->node_low_pfn;
++ limit = PFN_DOWN(limit);
+ if (limit && end_pfn > limit)
+ end_pfn = limit;
+
+- eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
++ eidx = end_pfn - PFN_DOWN(bdata->node_boot_start);
+ offset = 0;
+- if (align &&
+- (bdata->node_boot_start & (align - 1UL)) != 0)
+- offset = (align - (bdata->node_boot_start & (align - 1UL)));
+- offset >>= PAGE_SHIFT;
++ if (align && (bdata->node_boot_start & (align - 1UL)) != 0)
++ offset = align - (bdata->node_boot_start & (align - 1UL));
++ offset = PFN_DOWN(offset);
+
+ /*
+ * We try to allocate bootmem pages above 'goal'
+ * first, then we try to allocate lower pages.
+ */
+- if (goal && (goal >= bdata->node_boot_start) &&
+- ((goal >> PAGE_SHIFT) < end_pfn)) {
++ if (goal && goal >= bdata->node_boot_start && PFN_DOWN(goal) < end_pfn) {
+ preferred = goal - bdata->node_boot_start;
+
+ if (bdata->last_success >= preferred)
+@@ -212,9 +220,8 @@ __alloc_bootmem_core(struct bootmem_data
+ } else
+ preferred = 0;
+
+- preferred = ALIGN(preferred, align) >> PAGE_SHIFT;
+- preferred += offset;
+- areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
++ preferred = PFN_DOWN(ALIGN(preferred, align)) + offset;
++ areasize = (size + PAGE_SIZE-1) / PAGE_SIZE;
+ incr = align >> PAGE_SHIFT ? : 1;
+
+ restart_scan:
+@@ -229,7 +236,7 @@ restart_scan:
+ for (j = i + 1; j < i + areasize; ++j) {
+ if (j >= eidx)
+ goto fail_block;
+- if (test_bit (j, bdata->node_bootmem_map))
++ if (test_bit(j, bdata->node_bootmem_map))
+ goto fail_block;
+ }
+ start = i;
+@@ -245,7 +252,7 @@ restart_scan:
+ return NULL;
+
+ found:
+- bdata->last_success = start << PAGE_SHIFT;
++ bdata->last_success = PFN_PHYS(start);
+ BUG_ON(start >= eidx);
+
+ /*
+@@ -257,19 +264,21 @@ found:
+ bdata->last_offset && bdata->last_pos+1 == start) {
+ offset = ALIGN(bdata->last_offset, align);
+ BUG_ON(offset > PAGE_SIZE);
+- remaining_size = PAGE_SIZE-offset;
++ remaining_size = PAGE_SIZE - offset;
+ if (size < remaining_size) {
+ areasize = 0;
+ /* last_pos unchanged */
+- bdata->last_offset = offset+size;
+- ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
+- bdata->node_boot_start);
++ bdata->last_offset = offset + size;
++ ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
++ offset +
++ bdata->node_boot_start);
+ } else {
+ remaining_size = size - remaining_size;
+- areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE;
+- ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
+- bdata->node_boot_start);
+- bdata->last_pos = start+areasize-1;
++ areasize = (remaining_size + PAGE_SIZE-1) / PAGE_SIZE;
++ ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
++ offset +
++ bdata->node_boot_start);
++ bdata->last_pos = start + areasize - 1;
+ bdata->last_offset = remaining_size;
+ }
+ bdata->last_offset &= ~PAGE_MASK;
+@@ -282,7 +291,7 @@ found:
+ /*
+ * Reserve the area now:
+ */
+- for (i = start; i < start+areasize; i++)
++ for (i = start; i < start + areasize; i++)
+ if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
+ BUG();
+ memset(ret, 0, size);
+@@ -303,8 +312,8 @@ static unsigned long __init free_all_boo
+
+ count = 0;
+ /* first extant page of the node */
+- pfn = bdata->node_boot_start >> PAGE_SHIFT;
+- idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
++ pfn = PFN_DOWN(bdata->node_boot_start);
++ idx = bdata->node_low_pfn - pfn;
+ map = bdata->node_bootmem_map;
+ /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */
+ if (bdata->node_boot_start == 0 ||
+@@ -333,7 +342,7 @@ static unsigned long __init free_all_boo
+ }
+ }
+ } else {
+- i+=BITS_PER_LONG;
++ i += BITS_PER_LONG;
+ }
+ pfn += BITS_PER_LONG;
+ }
+@@ -345,9 +354,10 @@ static unsigned long __init free_all_boo
+ */
+ page = virt_to_page(bdata->node_bootmem_map);
+ count = 0;
+- for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
+- count++;
++ idx = (get_mapsize(bdata) + PAGE_SIZE-1) >> PAGE_SHIFT;
++ for (i = 0; i < idx; i++, page++) {
+ __free_pages_bootmem(page, 0);
++ count++;
+ }
+ total += count;
+ bdata->node_bootmem_map = NULL;
+@@ -355,64 +365,72 @@ static unsigned long __init free_all_boo
+ return total;
+ }
+
+-unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn)
++unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
++ unsigned long startpfn, unsigned long endpfn)
+ {
+- return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn));
++ return init_bootmem_core(pgdat, freepfn, startpfn, endpfn);
+ }
+
+-void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
++void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
++ unsigned long size)
+ {
+ reserve_bootmem_core(pgdat->bdata, physaddr, size);
+ }
+
+-void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
++void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
++ unsigned long size)
+ {
+ free_bootmem_core(pgdat->bdata, physaddr, size);
+ }
+
+-unsigned long __init free_all_bootmem_node (pg_data_t *pgdat)
++unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
+ {
+- return(free_all_bootmem_core(pgdat));
++ return free_all_bootmem_core(pgdat);
+ }
+
+-unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
++unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
+ {
+ max_low_pfn = pages;
+ min_low_pfn = start;
+- return(init_bootmem_core(NODE_DATA(0), start, 0, pages));
++ return init_bootmem_core(NODE_DATA(0), start, 0, pages);
+ }
+
+ #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
+-void __init reserve_bootmem (unsigned long addr, unsigned long size)
++void __init reserve_bootmem(unsigned long addr, unsigned long size)
+ {
+ reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size);
+ }
+ #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
+
+-void __init free_bootmem (unsigned long addr, unsigned long size)
++void __init free_bootmem(unsigned long addr, unsigned long size)
+ {
+ free_bootmem_core(NODE_DATA(0)->bdata, addr, size);
+ }
+
+-unsigned long __init free_all_bootmem (void)
++unsigned long __init free_all_bootmem(void)
+ {
+- return(free_all_bootmem_core(NODE_DATA(0)));
++ return free_all_bootmem_core(NODE_DATA(0));
+ }
+
+-void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, unsigned long goal)
++void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
++ unsigned long goal)
+ {
+ bootmem_data_t *bdata;
+ void *ptr;
+
+- list_for_each_entry(bdata, &bdata_list, list)
+- if ((ptr = __alloc_bootmem_core(bdata, size, align, goal, 0)))
+- return(ptr);
++ list_for_each_entry(bdata, &bdata_list, list) {
++ ptr = __alloc_bootmem_core(bdata, size, align, goal, 0);
++ if (ptr)
++ return ptr;
++ }
+ return NULL;
+ }
+
+-void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal)
++void * __init __alloc_bootmem(unsigned long size, unsigned long align,
++ unsigned long goal)
+ {
+ void *mem = __alloc_bootmem_nopanic(size,align,goal);
++
+ if (mem)
+ return mem;
+ /*
+@@ -424,29 +442,34 @@ void * __init __alloc_bootmem(unsigned l
+ }
+
+
+-void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, unsigned long align,
+- unsigned long goal)
++void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
++ unsigned long align, unsigned long goal)
+ {
+ void *ptr;
+
+ ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal, 0);
+ if (ptr)
+- return (ptr);
++ return ptr;
+
+ return __alloc_bootmem(size, align, goal);
+ }
+
+-#define LOW32LIMIT 0xffffffff
++#ifndef ARCH_LOW_ADDRESS_LIMIT
++#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
++#endif
+
+-void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal)
++void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
++ unsigned long goal)
+ {
+ bootmem_data_t *bdata;
+ void *ptr;
+
+- list_for_each_entry(bdata, &bdata_list, list)
+- if ((ptr = __alloc_bootmem_core(bdata, size,
+- align, goal, LOW32LIMIT)))
+- return(ptr);
++ list_for_each_entry(bdata, &bdata_list, list) {
++ ptr = __alloc_bootmem_core(bdata, size, align, goal,
++ ARCH_LOW_ADDRESS_LIMIT);
++ if (ptr)
++ return ptr;
++ }
+
+ /*
+ * Whoops, we cannot satisfy the allocation request.
+@@ -459,5 +482,6 @@ void * __init __alloc_bootmem_low(unsign
+ void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
+ unsigned long align, unsigned long goal)
+ {
+- return __alloc_bootmem_core(pgdat->bdata, size, align, goal, LOW32LIMIT);
++ return __alloc_bootmem_core(pgdat->bdata, size, align, goal,
++ ARCH_LOW_ADDRESS_LIMIT);
+ }
+diff --git a/mm/bounce.c b/mm/bounce.c
+new file mode 100644
+index 0000000..e4b62d2
+--- /dev/null
++++ b/mm/bounce.c
+@@ -0,0 +1,302 @@
++/* bounce buffer handling for block devices
++ *
++ * - Split from highmem.c
++ */
++
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/swap.h>
++#include <linux/bio.h>
++#include <linux/pagemap.h>
++#include <linux/mempool.h>
++#include <linux/blkdev.h>
++#include <linux/init.h>
++#include <linux/hash.h>
++#include <linux/highmem.h>
++#include <linux/blktrace_api.h>
++#include <asm/tlbflush.h>
++
++#define POOL_SIZE 64
++#define ISA_POOL_SIZE 16
++
++static mempool_t *page_pool, *isa_page_pool;
++
++#ifdef CONFIG_HIGHMEM
++static __init int init_emergency_pool(void)
++{
++ struct sysinfo i;
++ si_meminfo(&i);
++ si_swapinfo(&i);
++
++ if (!i.totalhigh)
++ return 0;
++
++ page_pool = mempool_create_page_pool(POOL_SIZE, 0);
++ BUG_ON(!page_pool);
++ printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
++
++ return 0;
++}
++
++__initcall(init_emergency_pool);
++
++/*
++ * highmem version, map in to vec
++ */
++static void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom)
++{
++ unsigned long flags;
++ unsigned char *vto;
++
++ local_irq_save(flags);
++ vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ);
++ memcpy(vto + to->bv_offset, vfrom, to->bv_len);
++ kunmap_atomic(vto, KM_BOUNCE_READ);
++ local_irq_restore(flags);
++}
++
++#else /* CONFIG_HIGHMEM */
++
++#define bounce_copy_vec(to, vfrom) \
++ memcpy(page_address((to)->bv_page) + (to)->bv_offset, vfrom, (to)->bv_len)
++
++#endif /* CONFIG_HIGHMEM */
++
++/*
++ * allocate pages in the DMA region for the ISA pool
++ */
++static void *mempool_alloc_pages_isa(gfp_t gfp_mask, void *data)
++{
++ return mempool_alloc_pages(gfp_mask | GFP_DMA, data);
++}
++
++/*
++ * gets called "every" time someone init's a queue with BLK_BOUNCE_ISA
++ * as the max address, so check if the pool has already been created.
++ */
++int init_emergency_isa_pool(void)
++{
++ if (isa_page_pool)
++ return 0;
++
++ isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
++ mempool_free_pages, (void *) 0);
++ BUG_ON(!isa_page_pool);
++
++ printk("isa bounce pool size: %d pages\n", ISA_POOL_SIZE);
++ return 0;
++}
++
++/*
++ * Simple bounce buffer support for highmem pages. Depending on the
++ * queue gfp mask set, *to may or may not be a highmem page. kmap it
++ * always, it will do the Right Thing
++ */
++static void copy_to_high_bio_irq(struct bio *to, struct bio *from)
++{
++ unsigned char *vfrom;
++ struct bio_vec *tovec, *fromvec;
++ int i;
++
++ __bio_for_each_segment(tovec, to, i, 0) {
++ fromvec = from->bi_io_vec + i;
++
++ /*
++ * not bounced
++ */
++ if (tovec->bv_page == fromvec->bv_page)
++ continue;
++
++ /*
++ * fromvec->bv_offset and fromvec->bv_len might have been
++ * modified by the block layer, so use the original copy,
++ * bounce_copy_vec already uses tovec->bv_len
++ */
++ vfrom = page_address(fromvec->bv_page) + tovec->bv_offset;
++
++ flush_dcache_page(tovec->bv_page);
++ bounce_copy_vec(tovec, vfrom);
++ }
++}
++
++static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
++{
++ struct bio *bio_orig = bio->bi_private;
++ struct bio_vec *bvec, *org_vec;
++ int i;
++
++ if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags))
++ set_bit(BIO_EOPNOTSUPP, &bio_orig->bi_flags);
++
++ /*
++ * free up bounce indirect pages used
++ */
++ __bio_for_each_segment(bvec, bio, i, 0) {
++ org_vec = bio_orig->bi_io_vec + i;
++ if (bvec->bv_page == org_vec->bv_page)
++ continue;
++
++ dec_zone_page_state(bvec->bv_page, NR_BOUNCE);
++ mempool_free(bvec->bv_page, pool);
++ }
++
++ bio_endio(bio_orig, bio_orig->bi_size, err);
++ bio_put(bio);
++}
++
++static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
++{
++ if (bio->bi_size)
++ return 1;
++
++ bounce_end_io(bio, page_pool, err);
++ return 0;
++}
++
++static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err)
++{
++ if (bio->bi_size)
++ return 1;
++
++ bounce_end_io(bio, isa_page_pool, err);
++ return 0;
++}
++
++static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err)
++{
++ struct bio *bio_orig = bio->bi_private;
++
++ if (test_bit(BIO_UPTODATE, &bio->bi_flags))
++ copy_to_high_bio_irq(bio_orig, bio);
++
++ bounce_end_io(bio, pool, err);
++}
++
++static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
++{
++ if (bio->bi_size)
++ return 1;
++
++ __bounce_end_io_read(bio, page_pool, err);
++ return 0;
++}
++
++static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err)
++{
++ if (bio->bi_size)
++ return 1;
++
++ __bounce_end_io_read(bio, isa_page_pool, err);
++ return 0;
++}
++
++static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
++ mempool_t *pool)
++{
++ struct page *page;
++ struct bio *bio = NULL;
++ int i, rw = bio_data_dir(*bio_orig);
++ struct bio_vec *to, *from;
++
++ bio_for_each_segment(from, *bio_orig, i) {
++ page = from->bv_page;
++
++ /*
++ * is destination page below bounce pfn?
++ */
++ if (page_to_pfn(page) < q->bounce_pfn)
++ continue;
++
++ /*
++ * irk, bounce it
++ */
++ if (!bio)
++ bio = bio_alloc(GFP_NOIO, (*bio_orig)->bi_vcnt);
++
++ to = bio->bi_io_vec + i;
++
++ to->bv_page = mempool_alloc(pool, q->bounce_gfp);
++ to->bv_len = from->bv_len;
++ to->bv_offset = from->bv_offset;
++ inc_zone_page_state(to->bv_page, NR_BOUNCE);
++
++ if (rw == WRITE) {
++ char *vto, *vfrom;
++
++ flush_dcache_page(from->bv_page);
++ vto = page_address(to->bv_page) + to->bv_offset;
++ vfrom = kmap(from->bv_page) + from->bv_offset;
++ memcpy(vto, vfrom, to->bv_len);
++ kunmap(from->bv_page);
++ }
++ }
++
++ /*
++ * no pages bounced
++ */
++ if (!bio)
++ return;
++
++ /*
++ * at least one page was bounced, fill in possible non-highmem
++ * pages
++ */
++ __bio_for_each_segment(from, *bio_orig, i, 0) {
++ to = bio_iovec_idx(bio, i);
++ if (!to->bv_page) {
++ to->bv_page = from->bv_page;
++ to->bv_len = from->bv_len;
++ to->bv_offset = from->bv_offset;
++ }
++ }
++
++ bio->bi_bdev = (*bio_orig)->bi_bdev;
++ bio->bi_flags |= (1 << BIO_BOUNCED);
++ bio->bi_sector = (*bio_orig)->bi_sector;
++ bio->bi_rw = (*bio_orig)->bi_rw;
++
++ bio->bi_vcnt = (*bio_orig)->bi_vcnt;
++ bio->bi_idx = (*bio_orig)->bi_idx;
++ bio->bi_size = (*bio_orig)->bi_size;
++
++ if (pool == page_pool) {
++ bio->bi_end_io = bounce_end_io_write;
++ if (rw == READ)
++ bio->bi_end_io = bounce_end_io_read;
++ } else {
++ bio->bi_end_io = bounce_end_io_write_isa;
++ if (rw == READ)
++ bio->bi_end_io = bounce_end_io_read_isa;
++ }
++
++ bio->bi_private = *bio_orig;
++ *bio_orig = bio;
++}
++
++void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig)
++{
++ mempool_t *pool;
++
++ /*
++ * for non-isa bounce case, just check if the bounce pfn is equal
++ * to or bigger than the highest pfn in the system -- in that case,
++ * don't waste time iterating over bio segments
++ */
++ if (!(q->bounce_gfp & GFP_DMA)) {
++ if (q->bounce_pfn >= blk_max_pfn)
++ return;
++ pool = page_pool;
++ } else {
++ BUG_ON(!isa_page_pool);
++ pool = isa_page_pool;
++ }
++
++ blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
++
++ /*
++ * slow path
++ */
++ __blk_queue_bounce(q, bio_orig, pool);
++}
++
++EXPORT_SYMBOL(blk_queue_bounce);
+diff --git a/mm/filemap.c b/mm/filemap.c
+index b9a60c4..7b84dc8 100644
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -75,8 +75,8 @@ generic_file_direct_IO(int rw, struct ki
+ * ->mmap_sem
+ * ->lock_page (access_process_vm)
+ *
+- * ->mmap_sem
+- * ->i_mutex (msync)
++ * ->i_mutex (generic_file_buffered_write)
++ * ->mmap_sem (fault_in_pages_readable->do_page_fault)
+ *
+ * ->i_mutex
+ * ->i_alloc_sem (various)
+@@ -467,26 +467,22 @@ int add_to_page_cache_lru(struct page *p
+ }
+
+ #ifdef CONFIG_NUMA
+-struct page *page_cache_alloc(struct address_space *x)
++struct page *__page_cache_alloc(gfp_t gfp)
+ {
+ if (cpuset_do_page_mem_spread()) {
+ int n = cpuset_mem_spread_node();
+- return alloc_pages_node(n, mapping_gfp_mask(x), 0);
++ return alloc_pages_node(n, gfp, 0);
+ }
+- return alloc_pages(mapping_gfp_mask(x), 0);
++ return alloc_pages(gfp, 0);
+ }
+-EXPORT_SYMBOL(page_cache_alloc);
++EXPORT_SYMBOL(__page_cache_alloc);
++#endif
+
+-struct page *page_cache_alloc_cold(struct address_space *x)
++static int __sleep_on_page_lock(void *word)
+ {
+- if (cpuset_do_page_mem_spread()) {
+- int n = cpuset_mem_spread_node();
+- return alloc_pages_node(n, mapping_gfp_mask(x)|__GFP_COLD, 0);
+- }
+- return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
++ io_schedule();
++ return 0;
+ }
+-EXPORT_SYMBOL(page_cache_alloc_cold);
+-#endif
+
+ /*
+ * In order to wait for pages to become available there must be
+@@ -577,13 +573,24 @@ void fastcall __lock_page(struct page *p
+ }
+ EXPORT_SYMBOL(__lock_page);
+
++/*
++ * Variant of lock_page that does not require the caller to hold a reference
++ * on the page's mapping.
++ */
++void fastcall __lock_page_nosync(struct page *page)
++{
++ DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
++ __wait_on_bit_lock(page_waitqueue(page), &wait, __sleep_on_page_lock,
++ TASK_UNINTERRUPTIBLE);
++}
++
+ /**
+ * find_get_page - find and get a page reference
+ * @mapping: the address_space to search
+ * @offset: the page index
+ *
+- * A rather lightweight function, finding and getting a reference to a
+- * hashed page atomically.
++ * Is there a pagecache struct page at the given (mapping, offset) tuple?
++ * If yes, increment its refcount and return it; if no, return NULL.
+ */
+ struct page * find_get_page(struct address_space *mapping, unsigned long offset)
+ {
+@@ -809,7 +816,6 @@ struct page *
+ grab_cache_page_nowait(struct address_space *mapping, unsigned long index)
+ {
+ struct page *page = find_get_page(mapping, index);
+- gfp_t gfp_mask;
+
+ if (page) {
+ if (!TestSetPageLocked(page))
+@@ -817,9 +823,8 @@ grab_cache_page_nowait(struct address_sp
+ page_cache_release(page);
+ return NULL;
+ }
+- gfp_mask = mapping_gfp_mask(mapping) & ~__GFP_FS;
+- page = alloc_pages(gfp_mask, 0);
+- if (page && add_to_page_cache_lru(page, mapping, index, gfp_mask)) {
++ page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~__GFP_FS);
++ if (page && add_to_page_cache_lru(page, mapping, index, GFP_KERNEL)) {
+ page_cache_release(page);
+ page = NULL;
+ }
+@@ -970,7 +975,7 @@ page_not_up_to_date:
+ /* Get exclusive access to the page ... */
+ lock_page(page);
+
+- /* Did it get unhashed before we got the lock? */
++ /* Did it get truncated before we got the lock? */
+ if (!page->mapping) {
+ unlock_page(page);
+ page_cache_release(page);
+@@ -1122,23 +1127,24 @@ success:
+ }
+
+ /**
+- * __generic_file_aio_read - generic filesystem read routine
++ * generic_file_aio_read - generic filesystem read routine
+ * @iocb: kernel I/O control block
+ * @iov: io vector request
+ * @nr_segs: number of segments in the iovec
+- * @ppos: current file position
++ * @pos: current file position
+ *
+ * This is the "read()" routine for all filesystems
+ * that can use the page cache directly.
+ */
+ ssize_t
+-__generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
++generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct file *filp = iocb->ki_filp;
+ ssize_t retval;
+ unsigned long seg;
+ size_t count;
++ loff_t *ppos = &iocb->ki_pos;
+
+ count = 0;
+ for (seg = 0; seg < nr_segs; seg++) {
+@@ -1162,7 +1168,7 @@ __generic_file_aio_read(struct kiocb *io
+
+ /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
+ if (filp->f_flags & O_DIRECT) {
+- loff_t pos = *ppos, size;
++ loff_t size;
+ struct address_space *mapping;
+ struct inode *inode;
+
+@@ -1180,8 +1186,10 @@ __generic_file_aio_read(struct kiocb *io
+ if (retval > 0)
+ *ppos = pos + retval;
+ }
+- file_accessed(filp);
+- goto out;
++ if (likely(retval != 0)) {
++ file_accessed(filp);
++ goto out;
++ }
+ }
+
+ retval = 0;
+@@ -1206,33 +1214,8 @@ __generic_file_aio_read(struct kiocb *io
+ out:
+ return retval;
+ }
+-EXPORT_SYMBOL(__generic_file_aio_read);
+-
+-ssize_t
+-generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
+-{
+- struct iovec local_iov = { .iov_base = buf, .iov_len = count };
+-
+- BUG_ON(iocb->ki_pos != pos);
+- return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos);
+-}
+ EXPORT_SYMBOL(generic_file_aio_read);
+
+-ssize_t
+-generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
+-{
+- struct iovec local_iov = { .iov_base = buf, .iov_len = count };
+- struct kiocb kiocb;
+- ssize_t ret;
+-
+- init_sync_kiocb(&kiocb, filp);
+- ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);
+- if (-EIOCBQUEUED == ret)
+- ret = wait_on_sync_kiocb(&kiocb);
+- return ret;
+-}
+-EXPORT_SYMBOL(generic_file_read);
+-
+ int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
+ {
+ ssize_t written;
+@@ -1454,7 +1437,7 @@ outside_data_content:
+ * accessible..
+ */
+ if (area->vm_mm == current->mm)
+- return NULL;
++ return NOPAGE_SIGBUS;
+ /* Fall through to the non-read-ahead case */
+ no_cached_page:
+ /*
+@@ -1479,7 +1462,7 @@ no_cached_page:
+ */
+ if (error == -ENOMEM)
+ return NOPAGE_OOM;
+- return NULL;
++ return NOPAGE_SIGBUS;
+
+ page_not_uptodate:
+ if (!did_readaround) {
+@@ -1548,7 +1531,7 @@ page_not_uptodate:
+ */
+ shrink_readahead_size_eio(file, ra);
+ page_cache_release(page);
+- return NULL;
++ return NOPAGE_SIGBUS;
+ }
+ EXPORT_SYMBOL(filemap_nopage);
+
+@@ -1610,7 +1593,7 @@ no_cached_page:
+ page_not_uptodate:
+ lock_page(page);
+
+- /* Did it get unhashed while we waited for it? */
++ /* Did it get truncated while we waited for it? */
+ if (!page->mapping) {
+ unlock_page(page);
+ goto err;
+@@ -1889,11 +1872,10 @@ repeat:
+ * if suid or (sgid and xgrp)
+ * remove privs
+ */
+-int remove_suid(struct dentry *dentry)
++int should_remove_suid(struct dentry *dentry)
+ {
+ mode_t mode = dentry->d_inode->i_mode;
+ int kill = 0;
+- int result = 0;
+
+ /* suid always must be killed */
+ if (unlikely(mode & S_ISUID))
+@@ -1906,13 +1888,28 @@ int remove_suid(struct dentry *dentry)
+ if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
+ kill |= ATTR_KILL_SGID;
+
+- if (unlikely(kill && !capable(CAP_FSETID))) {
+- struct iattr newattrs;
++ if (unlikely(kill && !capable(CAP_FSETID)))
++ return kill;
+
+- newattrs.ia_valid = ATTR_FORCE | kill;
+- result = notify_change(dentry, &newattrs);
+- }
+- return result;
++ return 0;
++}
++
++int __remove_suid(struct dentry *dentry, int kill)
++{
++ struct iattr newattrs;
++
++ newattrs.ia_valid = ATTR_FORCE | kill;
++ return notify_change(dentry, &newattrs);
++}
++
++int remove_suid(struct dentry *dentry)
++{
++ int kill = should_remove_suid(dentry);
++
++ if (unlikely(kill))
++ return __remove_suid(dentry, kill);
++
++ return 0;
+ }
+ EXPORT_SYMBOL(remove_suid);
+
+@@ -2003,6 +2000,7 @@ inline int generic_write_checks(struct f
+ if (unlikely(*pos + *count > inode->i_sb->s_maxbytes))
+ *count = inode->i_sb->s_maxbytes - *pos;
+ } else {
++#ifdef CONFIG_BLOCK
+ loff_t isize;
+ if (bdev_read_only(I_BDEV(inode)))
+ return -EPERM;
+@@ -2014,6 +2012,9 @@ inline int generic_write_checks(struct f
+
+ if (*pos + *count > isize)
+ *count = isize - *pos;
++#else
++ return -EPERM;
++#endif
+ }
+ return 0;
+ }
+@@ -2223,7 +2224,7 @@ __generic_file_aio_write_nolock(struct k
+ unsigned long nr_segs, loff_t *ppos)
+ {
+ struct file *file = iocb->ki_filp;
+- const struct address_space * mapping = file->f_mapping;
++ struct address_space * mapping = file->f_mapping;
+ size_t ocount; /* original count */
+ size_t count; /* after file limit checks */
+ struct inode *inode = mapping->host;
+@@ -2276,8 +2277,11 @@ __generic_file_aio_write_nolock(struct k
+
+ /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
+ if (unlikely(file->f_flags & O_DIRECT)) {
+- written = generic_file_direct_write(iocb, iov,
+- &nr_segs, pos, ppos, count, ocount);
++ loff_t endbyte;
++ ssize_t written_buffered;
++
++ written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
++ ppos, count, ocount);
+ if (written < 0 || written == count)
+ goto out;
+ /*
+@@ -2286,30 +2290,66 @@ __generic_file_aio_write_nolock(struct k
+ */
+ pos += written;
+ count -= written;
+- }
++ written_buffered = generic_file_buffered_write(iocb, iov,
++ nr_segs, pos, ppos, count,
++ written);
++ /*
++ * If generic_file_buffered_write() retuned a synchronous error
++ * then we want to return the number of bytes which were
++ * direct-written, or the error code if that was zero. Note
++ * that this differs from normal direct-io semantics, which
++ * will return -EFOO even if some bytes were written.
++ */
++ if (written_buffered < 0) {
++ err = written_buffered;
++ goto out;
++ }
+
+- written = generic_file_buffered_write(iocb, iov, nr_segs,
+- pos, ppos, count, written);
++ /*
++ * We need to ensure that the page cache pages are written to
++ * disk and invalidated to preserve the expected O_DIRECT
++ * semantics.
++ */
++ endbyte = pos + written_buffered - written - 1;
++ err = do_sync_file_range(file, pos, endbyte,
++ SYNC_FILE_RANGE_WAIT_BEFORE|
++ SYNC_FILE_RANGE_WRITE|
++ SYNC_FILE_RANGE_WAIT_AFTER);
++ if (err == 0) {
++ written = written_buffered;
++ invalidate_mapping_pages(mapping,
++ pos >> PAGE_CACHE_SHIFT,
++ endbyte >> PAGE_CACHE_SHIFT);
++ } else {
++ /*
++ * We don't know how much we wrote, so just return
++ * the number of bytes which were direct-written
++ */
++ }
++ } else {
++ written = generic_file_buffered_write(iocb, iov, nr_segs,
++ pos, ppos, count, written);
++ }
+ out:
+ current->backing_dev_info = NULL;
+ return written ? written : err;
+ }
+-EXPORT_SYMBOL(generic_file_aio_write_nolock);
+
+-ssize_t
+-generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
++ssize_t generic_file_aio_write_nolock(struct kiocb *iocb,
++ const struct iovec *iov, unsigned long nr_segs, loff_t pos)
+ {
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ ssize_t ret;
+- loff_t pos = *ppos;
+
+- ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos);
++ BUG_ON(iocb->ki_pos != pos);
++
++ ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
++ &iocb->ki_pos);
+
+ if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+- int err;
++ ssize_t err;
+
+ err = sync_page_range_nolock(inode, mapping, pos, ret);
+ if (err < 0)
+@@ -2317,51 +2357,21 @@ generic_file_aio_write_nolock(struct kio
+ }
+ return ret;
+ }
++EXPORT_SYMBOL(generic_file_aio_write_nolock);
+
+-static ssize_t
+-__generic_file_write_nolock(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct kiocb kiocb;
+- ssize_t ret;
+-
+- init_sync_kiocb(&kiocb, file);
+- ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
+- if (ret == -EIOCBQUEUED)
+- ret = wait_on_sync_kiocb(&kiocb);
+- return ret;
+-}
+-
+-ssize_t
+-generic_file_write_nolock(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct kiocb kiocb;
+- ssize_t ret;
+-
+- init_sync_kiocb(&kiocb, file);
+- ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
+- if (-EIOCBQUEUED == ret)
+- ret = wait_on_sync_kiocb(&kiocb);
+- return ret;
+-}
+-EXPORT_SYMBOL(generic_file_write_nolock);
+-
+-ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t count, loff_t pos)
++ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ ssize_t ret;
+- struct iovec local_iov = { .iov_base = (void __user *)buf,
+- .iov_len = count };
+
+ BUG_ON(iocb->ki_pos != pos);
+
+ mutex_lock(&inode->i_mutex);
+- ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1,
+- &iocb->ki_pos);
++ ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
++ &iocb->ki_pos);
+ mutex_unlock(&inode->i_mutex);
+
+ if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+@@ -2375,66 +2385,6 @@ ssize_t generic_file_aio_write(struct ki
+ }
+ EXPORT_SYMBOL(generic_file_aio_write);
+
+-ssize_t generic_file_write(struct file *file, const char __user *buf,
+- size_t count, loff_t *ppos)
+-{
+- struct address_space *mapping = file->f_mapping;
+- struct inode *inode = mapping->host;
+- ssize_t ret;
+- struct iovec local_iov = { .iov_base = (void __user *)buf,
+- .iov_len = count };
+-
+- mutex_lock(&inode->i_mutex);
+- ret = __generic_file_write_nolock(file, &local_iov, 1, ppos);
+- mutex_unlock(&inode->i_mutex);
+-
+- if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+- ssize_t err;
+-
+- err = sync_page_range(inode, mapping, *ppos - ret, ret);
+- if (err < 0)
+- ret = err;
+- }
+- return ret;
+-}
+-EXPORT_SYMBOL(generic_file_write);
+-
+-ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct kiocb kiocb;
+- ssize_t ret;
+-
+- init_sync_kiocb(&kiocb, filp);
+- ret = __generic_file_aio_read(&kiocb, iov, nr_segs, ppos);
+- if (-EIOCBQUEUED == ret)
+- ret = wait_on_sync_kiocb(&kiocb);
+- return ret;
+-}
+-EXPORT_SYMBOL(generic_file_readv);
+-
+-ssize_t generic_file_writev(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct address_space *mapping = file->f_mapping;
+- struct inode *inode = mapping->host;
+- ssize_t ret;
+-
+- mutex_lock(&inode->i_mutex);
+- ret = __generic_file_write_nolock(file, iov, nr_segs, ppos);
+- mutex_unlock(&inode->i_mutex);
+-
+- if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+- int err;
+-
+- err = sync_page_range(inode, mapping, *ppos - ret, ret);
+- if (err < 0)
+- ret = err;
+- }
+- return ret;
+-}
+-EXPORT_SYMBOL(generic_file_writev);
+-
+ /*
+ * Called under i_mutex for writes to S_ISREG files. Returns -EIO if something
+ * went wrong during pagecache shootdown.
+@@ -2474,3 +2424,33 @@ generic_file_direct_IO(int rw, struct ki
+ }
+ return retval;
+ }
++
++/**
++ * try_to_release_page() - release old fs-specific metadata on a page
++ *
++ * @page: the page which the kernel is trying to free
++ * @gfp_mask: memory allocation flags (and I/O mode)
++ *
++ * The address_space is to try to release any data against the page
++ * (presumably at page->private). If the release was successful, return `1'.
++ * Otherwise return zero.
++ *
++ * The @gfp_mask argument specifies whether I/O may be performed to release
++ * this page (__GFP_IO), and whether the call may block (__GFP_WAIT).
++ *
++ * NOTE: @gfp_mask may go away, and this function may become non-blocking.
++ */
++int try_to_release_page(struct page *page, gfp_t gfp_mask)
++{
++ struct address_space * const mapping = page->mapping;
++
++ BUG_ON(!PageLocked(page));
++ if (PageWriteback(page))
++ return 0;
++
++ if (mapping && mapping->a_ops->releasepage)
++ return mapping->a_ops->releasepage(page, gfp_mask);
++ return try_to_free_buffers(page);
++}
++
++EXPORT_SYMBOL(try_to_release_page);
+diff --git a/mm/filemap.h b/mm/filemap.h
+index 3f2a343..c2bff04 100644
+--- a/mm/filemap.h
++++ b/mm/filemap.h
+@@ -12,7 +12,6 @@
+ #include <linux/mm.h>
+ #include <linux/highmem.h>
+ #include <linux/uio.h>
+-#include <linux/config.h>
+ #include <linux/uaccess.h>
+
+ size_t
+diff --git a/mm/fremap.c b/mm/fremap.c
+index 21b7d0c..7a9d0f5 100644
+--- a/mm/fremap.c
++++ b/mm/fremap.c
+@@ -39,7 +39,7 @@ static int zap_pte(struct mm_struct *mm,
+ } else {
+ if (!pte_file(pte))
+ free_swap_and_cache(pte_to_swp_entry(pte));
+- pte_clear(mm, addr, ptep);
++ pte_clear_not_present_full(mm, addr, ptep, 0);
+ }
+ return !!page;
+ }
+@@ -79,9 +79,9 @@ int install_page(struct mm_struct *mm, s
+ inc_mm_counter(mm, file_rss);
+
+ flush_icache_page(vma, page);
+- set_pte_at(mm, addr, pte, mk_pte(page, prot));
++ pte_val = mk_pte(page, prot);
++ set_pte_at(mm, addr, pte, pte_val);
+ page_add_file_rmap(page);
+- pte_val = *pte;
+ update_mmu_cache(vma, addr, pte_val);
+ lazy_mmu_prot_update(pte_val);
+ err = 0;
+diff --git a/mm/highmem.c b/mm/highmem.c
+index 9b2a540..0206e7e 100644
+--- a/mm/highmem.c
++++ b/mm/highmem.c
+@@ -29,13 +29,6 @@
+ #include <linux/blktrace_api.h>
+ #include <asm/tlbflush.h>
+
+-static mempool_t *page_pool, *isa_page_pool;
+-
+-static void *mempool_alloc_pages_isa(gfp_t gfp_mask, void *data)
+-{
+- return mempool_alloc_pages(gfp_mask | GFP_DMA, data);
+-}
+-
+ /*
+ * Virtual_count is not a pure "count".
+ * 0 means that it is not mapped, and has not been mapped
+@@ -46,6 +39,19 @@ static void *mempool_alloc_pages_isa(gfp
+ */
+ #ifdef CONFIG_HIGHMEM
+
++unsigned long totalhigh_pages __read_mostly;
++
++unsigned int nr_free_highpages (void)
++{
++ pg_data_t *pgdat;
++ unsigned int pages = 0;
++
++ for_each_online_pgdat(pgdat)
++ pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages;
++
++ return pages;
++}
++
+ static int pkmap_count[LAST_PKMAP];
+ static unsigned int last_pkmap_nr;
+ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock);
+@@ -204,282 +210,8 @@ void fastcall kunmap_high(struct page *p
+ }
+
+ EXPORT_SYMBOL(kunmap_high);
+-
+-#define POOL_SIZE 64
+-
+-static __init int init_emergency_pool(void)
+-{
+- struct sysinfo i;
+- si_meminfo(&i);
+- si_swapinfo(&i);
+-
+- if (!i.totalhigh)
+- return 0;
+-
+- page_pool = mempool_create_page_pool(POOL_SIZE, 0);
+- BUG_ON(!page_pool);
+- printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
+-
+- return 0;
+-}
+-
+-__initcall(init_emergency_pool);
+-
+-/*
+- * highmem version, map in to vec
+- */
+-static void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom)
+-{
+- unsigned long flags;
+- unsigned char *vto;
+-
+- local_irq_save(flags);
+- vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ);
+- memcpy(vto + to->bv_offset, vfrom, to->bv_len);
+- kunmap_atomic(vto, KM_BOUNCE_READ);
+- local_irq_restore(flags);
+-}
+-
+-#else /* CONFIG_HIGHMEM */
+-
+-#define bounce_copy_vec(to, vfrom) \
+- memcpy(page_address((to)->bv_page) + (to)->bv_offset, vfrom, (to)->bv_len)
+-
+ #endif
+
+-#define ISA_POOL_SIZE 16
+-
+-/*
+- * gets called "every" time someone init's a queue with BLK_BOUNCE_ISA
+- * as the max address, so check if the pool has already been created.
+- */
+-int init_emergency_isa_pool(void)
+-{
+- if (isa_page_pool)
+- return 0;
+-
+- isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
+- mempool_free_pages, (void *) 0);
+- BUG_ON(!isa_page_pool);
+-
+- printk("isa bounce pool size: %d pages\n", ISA_POOL_SIZE);
+- return 0;
+-}
+-
+-/*
+- * Simple bounce buffer support for highmem pages. Depending on the
+- * queue gfp mask set, *to may or may not be a highmem page. kmap it
+- * always, it will do the Right Thing
+- */
+-static void copy_to_high_bio_irq(struct bio *to, struct bio *from)
+-{
+- unsigned char *vfrom;
+- struct bio_vec *tovec, *fromvec;
+- int i;
+-
+- __bio_for_each_segment(tovec, to, i, 0) {
+- fromvec = from->bi_io_vec + i;
+-
+- /*
+- * not bounced
+- */
+- if (tovec->bv_page == fromvec->bv_page)
+- continue;
+-
+- /*
+- * fromvec->bv_offset and fromvec->bv_len might have been
+- * modified by the block layer, so use the original copy,
+- * bounce_copy_vec already uses tovec->bv_len
+- */
+- vfrom = page_address(fromvec->bv_page) + tovec->bv_offset;
+-
+- flush_dcache_page(tovec->bv_page);
+- bounce_copy_vec(tovec, vfrom);
+- }
+-}
+-
+-static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
+-{
+- struct bio *bio_orig = bio->bi_private;
+- struct bio_vec *bvec, *org_vec;
+- int i;
+-
+- if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags))
+- set_bit(BIO_EOPNOTSUPP, &bio_orig->bi_flags);
+-
+- /*
+- * free up bounce indirect pages used
+- */
+- __bio_for_each_segment(bvec, bio, i, 0) {
+- org_vec = bio_orig->bi_io_vec + i;
+- if (bvec->bv_page == org_vec->bv_page)
+- continue;
+-
+- dec_zone_page_state(bvec->bv_page, NR_BOUNCE);
+- mempool_free(bvec->bv_page, pool);
+- }
+-
+- bio_endio(bio_orig, bio_orig->bi_size, err);
+- bio_put(bio);
+-}
+-
+-static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
+-{
+- if (bio->bi_size)
+- return 1;
+-
+- bounce_end_io(bio, page_pool, err);
+- return 0;
+-}
+-
+-static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err)
+-{
+- if (bio->bi_size)
+- return 1;
+-
+- bounce_end_io(bio, isa_page_pool, err);
+- return 0;
+-}
+-
+-static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err)
+-{
+- struct bio *bio_orig = bio->bi_private;
+-
+- if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+- copy_to_high_bio_irq(bio_orig, bio);
+-
+- bounce_end_io(bio, pool, err);
+-}
+-
+-static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
+-{
+- if (bio->bi_size)
+- return 1;
+-
+- __bounce_end_io_read(bio, page_pool, err);
+- return 0;
+-}
+-
+-static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err)
+-{
+- if (bio->bi_size)
+- return 1;
+-
+- __bounce_end_io_read(bio, isa_page_pool, err);
+- return 0;
+-}
+-
+-static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
+- mempool_t *pool)
+-{
+- struct page *page;
+- struct bio *bio = NULL;
+- int i, rw = bio_data_dir(*bio_orig);
+- struct bio_vec *to, *from;
+-
+- bio_for_each_segment(from, *bio_orig, i) {
+- page = from->bv_page;
+-
+- /*
+- * is destination page below bounce pfn?
+- */
+- if (page_to_pfn(page) < q->bounce_pfn)
+- continue;
+-
+- /*
+- * irk, bounce it
+- */
+- if (!bio)
+- bio = bio_alloc(GFP_NOIO, (*bio_orig)->bi_vcnt);
+-
+- to = bio->bi_io_vec + i;
+-
+- to->bv_page = mempool_alloc(pool, q->bounce_gfp);
+- to->bv_len = from->bv_len;
+- to->bv_offset = from->bv_offset;
+- inc_zone_page_state(to->bv_page, NR_BOUNCE);
+-
+- if (rw == WRITE) {
+- char *vto, *vfrom;
+-
+- flush_dcache_page(from->bv_page);
+- vto = page_address(to->bv_page) + to->bv_offset;
+- vfrom = kmap(from->bv_page) + from->bv_offset;
+- memcpy(vto, vfrom, to->bv_len);
+- kunmap(from->bv_page);
+- }
+- }
+-
+- /*
+- * no pages bounced
+- */
+- if (!bio)
+- return;
+-
+- /*
+- * at least one page was bounced, fill in possible non-highmem
+- * pages
+- */
+- __bio_for_each_segment(from, *bio_orig, i, 0) {
+- to = bio_iovec_idx(bio, i);
+- if (!to->bv_page) {
+- to->bv_page = from->bv_page;
+- to->bv_len = from->bv_len;
+- to->bv_offset = from->bv_offset;
+- }
+- }
+-
+- bio->bi_bdev = (*bio_orig)->bi_bdev;
+- bio->bi_flags |= (1 << BIO_BOUNCED);
+- bio->bi_sector = (*bio_orig)->bi_sector;
+- bio->bi_rw = (*bio_orig)->bi_rw;
+-
+- bio->bi_vcnt = (*bio_orig)->bi_vcnt;
+- bio->bi_idx = (*bio_orig)->bi_idx;
+- bio->bi_size = (*bio_orig)->bi_size;
+-
+- if (pool == page_pool) {
+- bio->bi_end_io = bounce_end_io_write;
+- if (rw == READ)
+- bio->bi_end_io = bounce_end_io_read;
+- } else {
+- bio->bi_end_io = bounce_end_io_write_isa;
+- if (rw == READ)
+- bio->bi_end_io = bounce_end_io_read_isa;
+- }
+-
+- bio->bi_private = *bio_orig;
+- *bio_orig = bio;
+-}
+-
+-void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig)
+-{
+- mempool_t *pool;
+-
+- /*
+- * for non-isa bounce case, just check if the bounce pfn is equal
+- * to or bigger than the highest pfn in the system -- in that case,
+- * don't waste time iterating over bio segments
+- */
+- if (!(q->bounce_gfp & GFP_DMA)) {
+- if (q->bounce_pfn >= blk_max_pfn)
+- return;
+- pool = page_pool;
+- } else {
+- BUG_ON(!isa_page_pool);
+- pool = isa_page_pool;
+- }
+-
+- blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
+-
+- /*
+- * slow path
+- */
+- __blk_queue_bounce(q, bio_orig, pool);
+-}
+-
+-EXPORT_SYMBOL(blk_queue_bounce);
+-
+ #if defined(HASHED_PAGE_VIRTUAL)
+
+ #define PA_HASH_ORDER 7
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index df49997..a088f59 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -72,7 +72,7 @@ static struct page *dequeue_huge_page(st
+ struct zone **z;
+
+ for (z = zonelist->zones; *z; z++) {
+- nid = (*z)->zone_pgdat->node_id;
++ nid = zone_to_nid(*z);
+ if (cpuset_zone_allowed(*z, GFP_HIGHUSER) &&
+ !list_empty(&hugepage_freelists[nid]))
+ break;
+@@ -177,7 +177,7 @@ static void update_and_free_page(struct
+ {
+ int i;
+ nr_huge_pages--;
+- nr_huge_pages_node[page_zone(page)->zone_pgdat->node_id]--;
++ nr_huge_pages_node[page_to_nid(page)]--;
+ for (i = 0; i < (HPAGE_SIZE / PAGE_SIZE); i++) {
+ page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
+ 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
+@@ -191,7 +191,8 @@ static void update_and_free_page(struct
+ #ifdef CONFIG_HIGHMEM
+ static void try_to_free_low(unsigned long count)
+ {
+- int i, nid;
++ int i;
++
+ for (i = 0; i < MAX_NUMNODES; ++i) {
+ struct page *page, *next;
+ list_for_each_entry_safe(page, next, &hugepage_freelists[i], lru) {
+@@ -199,9 +200,8 @@ static void try_to_free_low(unsigned lon
+ continue;
+ list_del(&page->lru);
+ update_and_free_page(page);
+- nid = page_zone(page)->zone_pgdat->node_id;
+ free_huge_pages--;
+- free_huge_pages_node[nid]--;
++ free_huge_pages_node[page_to_nid(page)]--;
+ if (count >= nr_huge_pages)
+ return;
+ }
+@@ -356,14 +356,16 @@ nomem:
+ return -ENOMEM;
+ }
+
+-void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
+- unsigned long end)
++void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end)
+ {
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long address;
+ pte_t *ptep;
+ pte_t pte;
+ struct page *page;
++ struct page *tmp;
++ LIST_HEAD(page_list);
+
+ WARN_ON(!is_vm_hugetlb_page(vma));
+ BUG_ON(start & ~HPAGE_MASK);
+@@ -384,12 +386,34 @@ void unmap_hugepage_range(struct vm_area
+ continue;
+
+ page = pte_page(pte);
+- put_page(page);
++ list_add(&page->lru, &page_list);
+ add_mm_counter(mm, file_rss, (int) -(HPAGE_SIZE / PAGE_SIZE));
+ }
+
+ spin_unlock(&mm->page_table_lock);
+ flush_tlb_range(vma, start, end);
++ list_for_each_entry_safe(page, tmp, &page_list, lru) {
++ list_del(&page->lru);
++ put_page(page);
++ }
++}
++
++void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end)
++{
++ /*
++ * It is undesirable to test vma->vm_file as it should be non-null
++ * for valid hugetlb area. However, vm_file will be NULL in the error
++ * cleanup path of do_mmap_pgoff. When hugetlbfs ->mmap method fails,
++ * do_mmap_pgoff() nullifies vma->vm_file before calling this function
++ * to clean up. Since no pte has actually been setup, it is safe to
++ * do nothing in this case.
++ */
++ if (vma->vm_file) {
++ spin_lock(&vma->vm_file->f_mapping->i_mmap_lock);
++ __unmap_hugepage_range(vma, start, end);
++ spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock);
++ }
+ }
+
+ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
+@@ -454,6 +478,9 @@ int hugetlb_no_page(struct mm_struct *mm
+ retry:
+ page = find_lock_page(mapping, idx);
+ if (!page) {
++ size = i_size_read(mapping->host) >> HPAGE_SHIFT;
++ if (idx >= size)
++ goto out;
+ if (hugetlb_get_quota(mapping))
+ goto out;
+ page = alloc_huge_page(vma, address);
+diff --git a/mm/internal.h b/mm/internal.h
+index d20e3cc..d527b80 100644
+--- a/mm/internal.h
++++ b/mm/internal.h
+@@ -24,8 +24,8 @@ static inline void set_page_count(struct
+ */
+ static inline void set_page_refcounted(struct page *page)
+ {
+- BUG_ON(PageCompound(page) && page_private(page) != (unsigned long)page);
+- BUG_ON(atomic_read(&page->_count));
++ VM_BUG_ON(PageCompound(page) && page_private(page) != (unsigned long)page);
++ VM_BUG_ON(atomic_read(&page->_count));
+ set_page_count(page, 1);
+ }
+
+diff --git a/mm/memory.c b/mm/memory.c
+index 109e986..156861f 100644
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -49,6 +49,7 @@
+ #include <linux/module.h>
+ #include <linux/delayacct.h>
+ #include <linux/init.h>
++#include <linux/writeback.h>
+
+ #include <asm/pgalloc.h>
+ #include <asm/uaccess.h>
+@@ -466,7 +467,7 @@ copy_one_pte(struct mm_struct *dst_mm, s
+ */
+ if (is_cow_mapping(vm_flags)) {
+ ptep_set_wrprotect(src_mm, addr, src_pte);
+- pte = *src_pte;
++ pte = pte_wrprotect(pte);
+ }
+
+ /*
+@@ -505,6 +506,7 @@ again:
+ src_pte = pte_offset_map_nested(src_pmd, addr);
+ src_ptl = pte_lockptr(src_mm, src_pmd);
+ spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
++ arch_enter_lazy_mmu_mode();
+
+ do {
+ /*
+@@ -526,6 +528,7 @@ again:
+ progress += 8;
+ } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
+
++ arch_leave_lazy_mmu_mode();
+ spin_unlock(src_ptl);
+ pte_unmap_nested(src_pte - 1);
+ add_mm_rss(dst_mm, rss[0], rss[1]);
+@@ -627,6 +630,7 @@ static unsigned long zap_pte_range(struc
+ int anon_rss = 0;
+
+ pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
++ arch_enter_lazy_mmu_mode();
+ do {
+ pte_t ptent = *pte;
+ if (pte_none(ptent)) {
+@@ -689,10 +693,11 @@ static unsigned long zap_pte_range(struc
+ continue;
+ if (!pte_file(ptent))
+ free_swap_and_cache(pte_to_swp_entry(ptent));
+- pte_clear_full(mm, addr, pte, tlb->fullmm);
++ pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
+ } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
+
+ add_mm_rss(mm, file_rss, anon_rss);
++ arch_leave_lazy_mmu_mode();
+ pte_unmap_unlock(pte - 1, ptl);
+
+ return addr;
+@@ -1081,6 +1086,7 @@ int get_user_pages(struct task_struct *t
+ default:
+ BUG();
+ }
++ cond_resched();
+ }
+ if (pages) {
+ pages[i] = page;
+@@ -1108,6 +1114,7 @@ static int zeromap_pte_range(struct mm_s
+ pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
+ if (!pte)
+ return -ENOMEM;
++ arch_enter_lazy_mmu_mode();
+ do {
+ struct page *page = ZERO_PAGE(addr);
+ pte_t zero_pte = pte_wrprotect(mk_pte(page, prot));
+@@ -1117,6 +1124,7 @@ static int zeromap_pte_range(struct mm_s
+ BUG_ON(!pte_none(*pte));
+ set_pte_at(mm, addr, pte, zero_pte);
+ } while (pte++, addr += PAGE_SIZE, addr != end);
++ arch_leave_lazy_mmu_mode();
+ pte_unmap_unlock(pte - 1, ptl);
+ return 0;
+ }
+@@ -1226,7 +1234,12 @@ out:
+ return retval;
+ }
+
+-/*
++/**
++ * vm_insert_page - insert single page into user vma
++ * @vma: user vma to map to
++ * @addr: target user address of this page
++ * @page: source kernel page
++ *
+ * This allows drivers to insert individual pages they've allocated
+ * into a user vma.
+ *
+@@ -1269,11 +1282,13 @@ static int remap_pte_range(struct mm_str
+ pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
+ if (!pte)
+ return -ENOMEM;
++ arch_enter_lazy_mmu_mode();
+ do {
+ BUG_ON(!pte_none(*pte));
+ set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
++ arch_leave_lazy_mmu_mode();
+ pte_unmap_unlock(pte - 1, ptl);
+ return 0;
+ }
+@@ -1318,7 +1333,16 @@ static inline int remap_pud_range(struct
+ return 0;
+ }
+
+-/* Note: this is only safe if the mm semaphore is held when called. */
++/**
++ * remap_pfn_range - remap kernel memory to userspace
++ * @vma: user vma to map to
++ * @addr: target user address to start at
++ * @pfn: physical address of kernel memory
++ * @size: size of map area
++ * @prot: page protection flags for this mapping
++ *
++ * Note: this is only safe if the mm semaphore is held when called.
++ */
+ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+ {
+@@ -1428,6 +1452,7 @@ static inline void cow_user_page(struct
+ if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
+ memset(kaddr, 0, PAGE_SIZE);
+ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(dst);
+ return;
+
+ }
+@@ -1458,14 +1483,29 @@ static int do_wp_page(struct mm_struct *
+ {
+ struct page *old_page, *new_page;
+ pte_t entry;
+- int reuse, ret = VM_FAULT_MINOR;
++ int reuse = 0, ret = VM_FAULT_MINOR;
++ struct page *dirty_page = NULL;
+
+ old_page = vm_normal_page(vma, address, orig_pte);
+ if (!old_page)
+ goto gotten;
+
+- if (unlikely((vma->vm_flags & (VM_SHARED|VM_WRITE)) ==
+- (VM_SHARED|VM_WRITE))) {
++ /*
++ * Take out anonymous pages first, anonymous shared vmas are
++ * not dirty accountable.
++ */
++ if (PageAnon(old_page)) {
++ if (!TestSetPageLocked(old_page)) {
++ reuse = can_share_swap_page(old_page);
++ unlock_page(old_page);
++ }
++ } else if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
++ (VM_WRITE|VM_SHARED))) {
++ /*
++ * Only catch write-faults on shared writable pages,
++ * read-only shared pages can get COWed by
++ * get_user_pages(.write=1, .force=1).
++ */
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
+ /*
+ * Notify the address space that the page is about to
+@@ -1494,13 +1534,9 @@ static int do_wp_page(struct mm_struct *
+ if (!pte_same(*page_table, orig_pte))
+ goto unlock;
+ }
+-
++ dirty_page = old_page;
++ get_page(dirty_page);
+ reuse = 1;
+- } else if (PageAnon(old_page) && !TestSetPageLocked(old_page)) {
+- reuse = can_share_swap_page(old_page);
+- unlock_page(old_page);
+- } else {
+- reuse = 0;
+ }
+
+ if (reuse) {
+@@ -1551,7 +1587,14 @@ gotten:
+ entry = mk_pte(new_page, vma->vm_page_prot);
+ entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+ lazy_mmu_prot_update(entry);
+- ptep_establish(vma, address, page_table, entry);
++ /*
++ * Clear the pte entry and flush it first, before updating the
++ * pte with the new entry. This will avoid a race condition
++ * seen in the presence of one thread doing SMC and another
++ * thread doing COW.
++ */
++ ptep_clear_flush(vma, address, page_table);
++ set_pte_at(mm, address, page_table, entry);
+ update_mmu_cache(vma, address, entry);
+ lru_cache_add_active(new_page);
+ page_add_new_anon_rmap(new_page, vma, address);
+@@ -1566,6 +1609,10 @@ gotten:
+ page_cache_release(old_page);
+ unlock:
+ pte_unmap_unlock(page_table, ptl);
++ if (dirty_page) {
++ set_page_dirty_balance(dirty_page);
++ put_page(dirty_page);
++ }
+ return ret;
+ oom:
+ if (old_page)
+@@ -1785,9 +1832,10 @@ void unmap_mapping_range(struct address_
+ }
+ EXPORT_SYMBOL(unmap_mapping_range);
+
+-/*
+- * Handle all mappings that got truncated by a "truncate()"
+- * system call.
++/**
++ * vmtruncate - unmap mappings "freed" by truncate() syscall
++ * @inode: inode of the file used
++ * @offset: file offset to start truncating
+ *
+ * NOTE! We have to be ready to update the memory sharing
+ * between the file and the memory map for a potential last
+@@ -1856,11 +1904,16 @@ int vmtruncate_range(struct inode *inode
+ }
+ EXPORT_UNUSED_SYMBOL(vmtruncate_range); /* June 2006 */
+
+-/*
++/**
++ * swapin_readahead - swap in pages in hope we need them soon
++ * @entry: swap entry of this memory
++ * @addr: address to start
++ * @vma: user vma this addresses belong to
++ *
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time. We also make sure to queue
+- * the 'original' request together with the readahead ones...
++ * the 'original' request together with the readahead ones...
+ *
+ * This has been extended to use the NUMA policies from the mm triggering
+ * the readahead.
+@@ -2098,6 +2151,7 @@ static int do_no_page(struct mm_struct *
+ unsigned int sequence = 0;
+ int ret = VM_FAULT_MINOR;
+ int anon = 0;
++ struct page *dirty_page = NULL;
+
+ pte_unmap(page_table);
+ BUG_ON(vma->vm_flags & VM_PFNMAP);
+@@ -2117,11 +2171,13 @@ retry:
+ * after the next truncate_count read.
+ */
+
+- /* no page was available -- either SIGBUS or OOM */
+- if (new_page == NOPAGE_SIGBUS)
++ /* no page was available -- either SIGBUS, OOM or REFAULT */
++ if (unlikely(new_page == NOPAGE_SIGBUS))
+ return VM_FAULT_SIGBUS;
+- if (new_page == NOPAGE_OOM)
++ else if (unlikely(new_page == NOPAGE_OOM))
+ return VM_FAULT_OOM;
++ else if (unlikely(new_page == NOPAGE_REFAULT))
++ return VM_FAULT_MINOR;
+
+ /*
+ * Should we do an early C-O-W break?
+@@ -2192,6 +2248,10 @@ retry:
+ } else {
+ inc_mm_counter(mm, file_rss);
+ page_add_file_rmap(new_page);
++ if (write_access) {
++ dirty_page = new_page;
++ get_page(dirty_page);
++ }
+ }
+ } else {
+ /* One of our sibling threads was faster, back out. */
+@@ -2204,6 +2264,10 @@ retry:
+ lazy_mmu_prot_update(entry);
+ unlock:
+ pte_unmap_unlock(page_table, ptl);
++ if (dirty_page) {
++ set_page_dirty_balance(dirty_page);
++ put_page(dirty_page);
++ }
+ return ret;
+ oom:
+ page_cache_release(new_page);
+@@ -2211,6 +2275,54 @@ oom:
+ }
+
+ /*
++ * do_no_pfn() tries to create a new page mapping for a page without
++ * a struct_page backing it
++ *
++ * As this is called only for pages that do not currently exist, we
++ * do not need to flush old virtual caches or the TLB.
++ *
++ * We enter with non-exclusive mmap_sem (to exclude vma changes,
++ * but allow concurrent faults), and pte mapped but not yet locked.
++ * We return with mmap_sem still held, but pte unmapped and unlocked.
++ *
++ * It is expected that the ->nopfn handler always returns the same pfn
++ * for a given virtual mapping.
++ *
++ * Mark this `noinline' to prevent it from bloating the main pagefault code.
++ */
++static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
++ unsigned long address, pte_t *page_table, pmd_t *pmd,
++ int write_access)
++{
++ spinlock_t *ptl;
++ pte_t entry;
++ unsigned long pfn;
++ int ret = VM_FAULT_MINOR;
++
++ pte_unmap(page_table);
++ BUG_ON(!(vma->vm_flags & VM_PFNMAP));
++ BUG_ON(is_cow_mapping(vma->vm_flags));
++
++ pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK);
++ if (pfn == NOPFN_OOM)
++ return VM_FAULT_OOM;
++ if (pfn == NOPFN_SIGBUS)
++ return VM_FAULT_SIGBUS;
++
++ page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
++
++ /* Only go through if we didn't race with anybody else... */
++ if (pte_none(*page_table)) {
++ entry = pfn_pte(pfn, vma->vm_page_prot);
++ if (write_access)
++ entry = maybe_mkwrite(pte_mkdirty(entry), vma);
++ set_pte_at(mm, address, page_table, entry);
++ }
++ pte_unmap_unlock(page_table, ptl);
++ return ret;
++}
++
++/*
+ * Fault of a previously existing named mapping. Repopulate the pte
+ * from the encoded file_pte if possible. This enables swappable
+ * nonlinear vmas.
+@@ -2272,11 +2384,17 @@ static inline int handle_pte_fault(struc
+ old_entry = entry = *pte;
+ if (!pte_present(entry)) {
+ if (pte_none(entry)) {
+- if (!vma->vm_ops || !vma->vm_ops->nopage)
+- return do_anonymous_page(mm, vma, address,
+- pte, pmd, write_access);
+- return do_no_page(mm, vma, address,
+- pte, pmd, write_access);
++ if (vma->vm_ops) {
++ if (vma->vm_ops->nopage)
++ return do_no_page(mm, vma, address,
++ pte, pmd,
++ write_access);
++ if (unlikely(vma->vm_ops->nopfn))
++ return do_no_pfn(mm, vma, address, pte,
++ pmd, write_access);
++ }
++ return do_anonymous_page(mm, vma, address,
++ pte, pmd, write_access);
+ }
+ if (pte_file(entry))
+ return do_file_page(mm, vma, address,
+@@ -2505,3 +2623,56 @@ int in_gate_area_no_task(unsigned long a
+ }
+
+ #endif /* __HAVE_ARCH_GATE_AREA */
++
++/*
++ * Access another process' address space.
++ * Source/target buffer must be kernel space,
++ * Do not walk the page table directly, use get_user_pages
++ */
++int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
++{
++ struct mm_struct *mm;
++ struct vm_area_struct *vma;
++ struct page *page;
++ void *old_buf = buf;
++
++ mm = get_task_mm(tsk);
++ if (!mm)
++ return 0;
++
++ down_read(&mm->mmap_sem);
++ /* ignore errors, just check how much was sucessfully transfered */
++ while (len) {
++ int bytes, ret, offset;
++ void *maddr;
++
++ ret = get_user_pages(tsk, mm, addr, 1,
++ write, 1, &page, &vma);
++ if (ret <= 0)
++ break;
++
++ bytes = len;
++ offset = addr & (PAGE_SIZE-1);
++ if (bytes > PAGE_SIZE-offset)
++ bytes = PAGE_SIZE-offset;
++
++ maddr = kmap(page);
++ if (write) {
++ copy_to_user_page(vma, page, addr,
++ maddr + offset, buf, bytes);
++ set_page_dirty_lock(page);
++ } else {
++ copy_from_user_page(vma, page, addr,
++ buf, maddr + offset, bytes);
++ }
++ kunmap(page);
++ page_cache_release(page);
++ len -= bytes;
++ buf += bytes;
++ addr += bytes;
++ }
++ up_read(&mm->mmap_sem);
++ mmput(mm);
++
++ return buf - old_buf;
++}
+diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
+index c373195..fd678a6 100644
+--- a/mm/memory_hotplug.c
++++ b/mm/memory_hotplug.c
+@@ -13,6 +13,7 @@
+ #include <linux/compiler.h>
+ #include <linux/module.h>
+ #include <linux/pagevec.h>
++#include <linux/writeback.h>
+ #include <linux/slab.h>
+ #include <linux/sysctl.h>
+ #include <linux/cpu.h>
+@@ -21,11 +22,41 @@
+ #include <linux/highmem.h>
+ #include <linux/vmalloc.h>
+ #include <linux/ioport.h>
++#include <linux/cpuset.h>
+
+ #include <asm/tlbflush.h>
+
+-extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
+- unsigned long size);
++/* add this memory to iomem resource */
++static struct resource *register_memory_resource(u64 start, u64 size)
++{
++ struct resource *res;
++ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
++ BUG_ON(!res);
++
++ res->name = "System RAM";
++ res->start = start;
++ res->end = start + size - 1;
++ res->flags = IORESOURCE_MEM;
++ if (request_resource(&iomem_resource, res) < 0) {
++ printk("System RAM resource %llx - %llx cannot be added\n",
++ (unsigned long long)res->start, (unsigned long long)res->end);
++ kfree(res);
++ res = NULL;
++ }
++ return res;
++}
++
++static void release_memory_resource(struct resource *res)
++{
++ if (!res)
++ return;
++ release_resource(res);
++ kfree(res);
++ return;
++}
++
++
++#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+ static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
+ {
+ struct pglist_data *pgdat = zone->zone_pgdat;
+@@ -45,8 +76,6 @@ static int __add_zone(struct zone *zone,
+ return 0;
+ }
+
+-extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
+- int nr_pages);
+ static int __add_section(struct zone *zone, unsigned long phys_start_pfn)
+ {
+ int nr_pages = PAGES_PER_SECTION;
+@@ -191,8 +220,10 @@ int online_pages(unsigned long pfn, unsi
+ if (need_zonelists_rebuild)
+ build_all_zonelists();
+ vm_total_pages = nr_free_pagecache_pages();
++ writeback_set_ratelimit();
+ return 0;
+ }
++#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
+
+ static pg_data_t *hotadd_new_pgdat(int nid, u64 start)
+ {
+@@ -222,36 +253,6 @@ static void rollback_node_hotadd(int nid
+ return;
+ }
+
+-/* add this memory to iomem resource */
+-static struct resource *register_memory_resource(u64 start, u64 size)
+-{
+- struct resource *res;
+- res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+- BUG_ON(!res);
+-
+- res->name = "System RAM";
+- res->start = start;
+- res->end = start + size - 1;
+- res->flags = IORESOURCE_MEM;
+- if (request_resource(&iomem_resource, res) < 0) {
+- printk("System RAM resource %llx - %llx cannot be added\n",
+- (unsigned long long)res->start, (unsigned long long)res->end);
+- kfree(res);
+- res = NULL;
+- }
+- return res;
+-}
+-
+-static void release_memory_resource(struct resource *res)
+-{
+- if (!res)
+- return;
+- release_resource(res);
+- kfree(res);
+- return;
+-}
+-
+-
+
+ int add_memory(int nid, u64 start, u64 size)
+ {
+@@ -283,6 +284,8 @@ int add_memory(int nid, u64 start, u64 s
+ /* we online node here. we can't roll back from here. */
+ node_set_online(nid);
+
++ cpuset_track_online_nodes();
++
+ if (new_pgdat) {
+ ret = register_one_node(nid);
+ /*
+diff --git a/mm/mempolicy.c b/mm/mempolicy.c
+index a9963ce..617fb31 100644
+--- a/mm/mempolicy.c
++++ b/mm/mempolicy.c
+@@ -105,7 +105,7 @@ static struct kmem_cache *sn_cache;
+
+ /* Highest zone. An specific allocation for a zone below that is not
+ policied. */
+-int policy_zone = ZONE_DMA;
++enum zone_type policy_zone = ZONE_DMA;
+
+ struct mempolicy default_policy = {
+ .refcnt = ATOMIC_INIT(1), /* never free it */
+@@ -137,7 +137,8 @@ static int mpol_check_policy(int mode, n
+ static struct zonelist *bind_zonelist(nodemask_t *nodes)
+ {
+ struct zonelist *zl;
+- int num, max, nd, k;
++ int num, max, nd;
++ enum zone_type k;
+
+ max = 1 + MAX_NR_ZONES * nodes_weight(*nodes);
+ zl = kmalloc(sizeof(struct zone *) * max, GFP_KERNEL);
+@@ -148,12 +149,16 @@ static struct zonelist *bind_zonelist(no
+ lower zones etc. Avoid empty zones because the memory allocator
+ doesn't like them. If you implement node hot removal you
+ have to fix that. */
+- for (k = policy_zone; k >= 0; k--) {
++ k = policy_zone;
++ while (1) {
+ for_each_node_mask(nd, *nodes) {
+ struct zone *z = &NODE_DATA(nd)->node_zones[k];
+ if (z->present_pages > 0)
+ zl->zones[num++] = z;
+ }
++ if (k == 0)
++ break;
++ k--;
+ }
+ zl->zones[num] = NULL;
+ return zl;
+@@ -482,7 +487,7 @@ static void get_zonemask(struct mempolic
+ switch (p->policy) {
+ case MPOL_BIND:
+ for (i = 0; p->v.zonelist->zones[i]; i++)
+- node_set(p->v.zonelist->zones[i]->zone_pgdat->node_id,
++ node_set(zone_to_nid(p->v.zonelist->zones[i]),
+ *nodes);
+ break;
+ case MPOL_DEFAULT:
+@@ -722,7 +727,7 @@ int do_migrate_pages(struct mm_struct *m
+ return -ENOSYS;
+ }
+
+-static struct page *new_vma_page(struct page *page, unsigned long private)
++static struct page *new_vma_page(struct page *page, unsigned long private, int **x)
+ {
+ return NULL;
+ }
+@@ -1131,7 +1136,9 @@ static unsigned interleave_nodes(struct
+ */
+ unsigned slab_node(struct mempolicy *policy)
+ {
+- switch (policy->policy) {
++ int pol = policy ? policy->policy : MPOL_DEFAULT;
++
++ switch (pol) {
+ case MPOL_INTERLEAVE:
+ return interleave_nodes(policy);
+
+@@ -1140,7 +1147,7 @@ unsigned slab_node(struct mempolicy *pol
+ * Follow bind policy behavior and start allocation at the
+ * first node.
+ */
+- return policy->v.zonelist->zones[0]->zone_pgdat->node_id;
++ return zone_to_nid(policy->v.zonelist->zones[0]);
+
+ case MPOL_PREFERRED:
+ if (policy->v.preferred_node >= 0)
+@@ -1285,7 +1292,7 @@ struct page *alloc_pages_current(gfp_t g
+
+ if ((gfp & __GFP_WAIT) && !in_interrupt())
+ cpuset_update_task_memory_state();
+- if (!pol || in_interrupt())
++ if (!pol || in_interrupt() || (gfp & __GFP_THISNODE))
+ pol = &default_policy;
+ if (pol->policy == MPOL_INTERLEAVE)
+ return alloc_page_interleave(gfp, order, interleave_nodes(pol));
+@@ -1317,12 +1324,11 @@ struct mempolicy *__mpol_copy(struct mem
+ atomic_set(&new->refcnt, 1);
+ if (new->policy == MPOL_BIND) {
+ int sz = ksize(old->v.zonelist);
+- new->v.zonelist = kmalloc(sz, SLAB_KERNEL);
++ new->v.zonelist = kmemdup(old->v.zonelist, sz, SLAB_KERNEL);
+ if (!new->v.zonelist) {
+ kmem_cache_free(policy_cache, new);
+ return ERR_PTR(-ENOMEM);
+ }
+- memcpy(new->v.zonelist, old->v.zonelist, sz);
+ }
+ return new;
+ }
+@@ -1644,7 +1650,7 @@ void mpol_rebind_policy(struct mempolicy
+
+ nodes_clear(nodes);
+ for (z = pol->v.zonelist->zones; *z; z++)
+- node_set((*z)->zone_pgdat->node_id, nodes);
++ node_set(zone_to_nid(*z), nodes);
+ nodes_remap(tmp, nodes, *mpolmask, *newmask);
+ nodes = tmp;
+
+diff --git a/mm/migrate.c b/mm/migrate.c
+index 3f1e0c2..b4979d4 100644
+--- a/mm/migrate.c
++++ b/mm/migrate.c
+@@ -409,6 +409,7 @@ int migrate_page(struct address_space *m
+ }
+ EXPORT_SYMBOL(migrate_page);
+
++#ifdef CONFIG_BLOCK
+ /*
+ * Migration function for pages with buffers. This function can only be used
+ * if the underlying filesystem guarantees that no other references to "page"
+@@ -466,6 +467,7 @@ int buffer_migrate_page(struct address_s
+ return 0;
+ }
+ EXPORT_SYMBOL(buffer_migrate_page);
++#endif
+
+ /*
+ * Writeback a page to clean the dirty state
+@@ -525,7 +527,7 @@ static int fallback_migrate_page(struct
+ * Buffers may be managed in a filesystem specific way.
+ * We must have no buffers or drop them.
+ */
+- if (page_has_buffers(page) &&
++ if (PagePrivate(page) &&
+ !try_to_release_page(page, GFP_KERNEL))
+ return -EAGAIN;
+
+@@ -741,7 +743,7 @@ static struct page *new_page_node(struct
+
+ *result = &pm->status;
+
+- return alloc_pages_node(pm->node, GFP_HIGHUSER, 0);
++ return alloc_pages_node(pm->node, GFP_HIGHUSER | GFP_THISNODE, 0);
+ }
+
+ /*
+@@ -950,7 +952,8 @@ asmlinkage long sys_move_pages(pid_t pid
+ goto out;
+
+ pm[i].node = node;
+- }
++ } else
++ pm[i].node = 0; /* anything to not match MAX_NUMNODES */
+ }
+ /* End marker */
+ pm[nr_pages].node = MAX_NUMNODES;
+diff --git a/mm/mmap.c b/mm/mmap.c
+index e66a0b5..497e502 100644
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -64,6 +64,13 @@ pgprot_t protection_map[16] = {
+ __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
+ };
+
++pgprot_t vm_get_page_prot(unsigned long vm_flags)
++{
++ return protection_map[vm_flags &
++ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
++}
++EXPORT_SYMBOL(vm_get_page_prot);
++
+ int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
+ int sysctl_overcommit_ratio = 50; /* default is 50% */
+ int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
+@@ -109,7 +116,7 @@ int __vm_enough_memory(long pages, int c
+ * which are reclaimable, under pressure. The dentry
+ * cache and most inode caches should fall into this
+ */
+- free += atomic_read(&slab_reclaim_pages);
++ free += global_page_state(NR_SLAB_RECLAIMABLE);
+
+ /*
+ * Leave the last 3% for root
+@@ -893,17 +900,6 @@ unsigned long do_mmap_pgoff(struct file
+ int accountable = 1;
+ unsigned long charged = 0, reqprot = prot;
+
+- if (file) {
+- if (is_file_hugepages(file))
+- accountable = 0;
+-
+- if (!file->f_op || !file->f_op->mmap)
+- return -ENODEV;
+-
+- if ((prot & PROT_EXEC) &&
+- (file->f_vfsmnt->mnt_flags & MNT_NOEXEC))
+- return -EPERM;
+- }
+ /*
+ * Does the application expect PROT_READ to imply PROT_EXEC?
+ *
+@@ -993,6 +989,16 @@ unsigned long do_mmap_pgoff(struct file
+ case MAP_PRIVATE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EACCES;
++ if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
++ if (vm_flags & VM_EXEC)
++ return -EPERM;
++ vm_flags &= ~VM_MAYEXEC;
++ }
++ if (is_file_hugepages(file))
++ accountable = 0;
++
++ if (!file->f_op || !file->f_op->mmap)
++ return -ENODEV;
+ break;
+
+ default:
+@@ -1098,12 +1104,6 @@ munmap_back:
+ goto free_vma;
+ }
+
+- /* Don't make the VMA automatically writable if it's shared, but the
+- * backer wishes to know when pages are first written to */
+- if (vma->vm_ops && vma->vm_ops->page_mkwrite)
+- vma->vm_page_prot =
+- protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC)];
+-
+ /* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform
+ * shmem_zero_setup (perhaps called through /dev/zero's ->mmap)
+ * that memory reservation must be checked; but that reservation
+@@ -1121,6 +1121,10 @@ munmap_back:
+ pgoff = vma->vm_pgoff;
+ vm_flags = vma->vm_flags;
+
++ if (vma_wants_writenotify(vma))
++ vma->vm_page_prot =
++ protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC)];
++
+ if (!file || !vma_merge(mm, prev, addr, vma->vm_end,
+ vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) {
+ file = vma->vm_file;
+diff --git a/mm/mprotect.c b/mm/mprotect.c
+index 638edab..3b8f3c0 100644
+--- a/mm/mprotect.c
++++ b/mm/mprotect.c
+@@ -27,12 +27,14 @@
+ #include <asm/tlbflush.h>
+
+ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
+- unsigned long addr, unsigned long end, pgprot_t newprot)
++ unsigned long addr, unsigned long end, pgprot_t newprot,
++ int dirty_accountable)
+ {
+ pte_t *pte, oldpte;
+ spinlock_t *ptl;
+
+ pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
++ arch_enter_lazy_mmu_mode();
+ do {
+ oldpte = *pte;
+ if (pte_present(oldpte)) {
+@@ -42,7 +44,14 @@ static void change_pte_range(struct mm_s
+ * bits by wiping the pte and then setting the new pte
+ * into place.
+ */
+- ptent = pte_modify(ptep_get_and_clear(mm, addr, pte), newprot);
++ ptent = ptep_get_and_clear(mm, addr, pte);
++ ptent = pte_modify(ptent, newprot);
++ /*
++ * Avoid taking write faults for pages we know to be
++ * dirty.
++ */
++ if (dirty_accountable && pte_dirty(ptent))
++ ptent = pte_mkwrite(ptent);
+ set_pte_at(mm, addr, pte, ptent);
+ lazy_mmu_prot_update(ptent);
+ #ifdef CONFIG_MIGRATION
+@@ -62,11 +71,13 @@ static void change_pte_range(struct mm_s
+ }
+
+ } while (pte++, addr += PAGE_SIZE, addr != end);
++ arch_leave_lazy_mmu_mode();
+ pte_unmap_unlock(pte - 1, ptl);
+ }
+
+ static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud,
+- unsigned long addr, unsigned long end, pgprot_t newprot)
++ unsigned long addr, unsigned long end, pgprot_t newprot,
++ int dirty_accountable)
+ {
+ pmd_t *pmd;
+ unsigned long next;
+@@ -76,12 +87,13 @@ static inline void change_pmd_range(stru
+ next = pmd_addr_end(addr, end);
+ if (pmd_none_or_clear_bad(pmd))
+ continue;
+- change_pte_range(mm, pmd, addr, next, newprot);
++ change_pte_range(mm, pmd, addr, next, newprot, dirty_accountable);
+ } while (pmd++, addr = next, addr != end);
+ }
+
+ static inline void change_pud_range(struct mm_struct *mm, pgd_t *pgd,
+- unsigned long addr, unsigned long end, pgprot_t newprot)
++ unsigned long addr, unsigned long end, pgprot_t newprot,
++ int dirty_accountable)
+ {
+ pud_t *pud;
+ unsigned long next;
+@@ -91,12 +103,13 @@ static inline void change_pud_range(stru
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+- change_pmd_range(mm, pud, addr, next, newprot);
++ change_pmd_range(mm, pud, addr, next, newprot, dirty_accountable);
+ } while (pud++, addr = next, addr != end);
+ }
+
+ static void change_protection(struct vm_area_struct *vma,
+- unsigned long addr, unsigned long end, pgprot_t newprot)
++ unsigned long addr, unsigned long end, pgprot_t newprot,
++ int dirty_accountable)
+ {
+ struct mm_struct *mm = vma->vm_mm;
+ pgd_t *pgd;
+@@ -110,7 +123,7 @@ static void change_protection(struct vm_
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+- change_pud_range(mm, pgd, addr, next, newprot);
++ change_pud_range(mm, pgd, addr, next, newprot, dirty_accountable);
+ } while (pgd++, addr = next, addr != end);
+ flush_tlb_range(vma, start, end);
+ }
+@@ -123,10 +136,9 @@ mprotect_fixup(struct vm_area_struct *vm
+ unsigned long oldflags = vma->vm_flags;
+ long nrpages = (end - start) >> PAGE_SHIFT;
+ unsigned long charged = 0;
+- unsigned int mask;
+- pgprot_t newprot;
+ pgoff_t pgoff;
+ int error;
++ int dirty_accountable = 0;
+
+ if (newflags == oldflags) {
+ *pprev = vma;
+@@ -176,24 +188,23 @@ mprotect_fixup(struct vm_area_struct *vm
+ }
+
+ success:
+- /* Don't make the VMA automatically writable if it's shared, but the
+- * backer wishes to know when pages are first written to */
+- mask = VM_READ|VM_WRITE|VM_EXEC|VM_SHARED;
+- if (vma->vm_ops && vma->vm_ops->page_mkwrite)
+- mask &= ~VM_SHARED;
+-
+- newprot = protection_map[newflags & mask];
+-
+ /*
+ * vm_flags and vm_page_prot are protected by the mmap_sem
+ * held in write mode.
+ */
+ vma->vm_flags = newflags;
+- vma->vm_page_prot = newprot;
++ vma->vm_page_prot = protection_map[newflags &
++ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
++ if (vma_wants_writenotify(vma)) {
++ vma->vm_page_prot = protection_map[newflags &
++ (VM_READ|VM_WRITE|VM_EXEC)];
++ dirty_accountable = 1;
++ }
++
+ if (is_vm_hugetlb_page(vma))
+- hugetlb_change_protection(vma, start, end, newprot);
++ hugetlb_change_protection(vma, start, end, vma->vm_page_prot);
+ else
+- change_protection(vma, start, end, newprot);
++ change_protection(vma, start, end, vma->vm_page_prot, dirty_accountable);
+ vm_stat_account(mm, oldflags, vma->vm_file, -nrpages);
+ vm_stat_account(mm, newflags, vma->vm_file, nrpages);
+ return 0;
+diff --git a/mm/mremap.c b/mm/mremap.c
+index 7c15cf3..9c769fa 100644
+--- a/mm/mremap.c
++++ b/mm/mremap.c
+@@ -98,6 +98,7 @@ static void move_ptes(struct vm_area_str
+ new_ptl = pte_lockptr(mm, new_pmd);
+ if (new_ptl != old_ptl)
+ spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
++ arch_enter_lazy_mmu_mode();
+
+ for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
+ new_pte++, new_addr += PAGE_SIZE) {
+@@ -109,6 +110,7 @@ static void move_ptes(struct vm_area_str
+ set_pte_at(mm, new_addr, new_pte, pte);
+ }
+
++ arch_leave_lazy_mmu_mode();
+ if (new_ptl != old_ptl)
+ spin_unlock(new_ptl);
+ pte_unmap_nested(new_pte - 1);
+diff --git a/mm/msync.c b/mm/msync.c
+index d083544..358d73c 100644
+--- a/mm/msync.c
++++ b/mm/msync.c
+@@ -7,149 +7,33 @@
+ /*
+ * The msync() system call.
+ */
+-#include <linux/slab.h>
+-#include <linux/pagemap.h>
+ #include <linux/fs.h>
+ #include <linux/mm.h>
+ #include <linux/mman.h>
+-#include <linux/hugetlb.h>
+-#include <linux/writeback.h>
+ #include <linux/file.h>
+ #include <linux/syscalls.h>
+
+-#include <asm/pgtable.h>
+-#include <asm/tlbflush.h>
+-
+-static unsigned long msync_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+- unsigned long addr, unsigned long end)
+-{
+- pte_t *pte;
+- spinlock_t *ptl;
+- int progress = 0;
+- unsigned long ret = 0;
+-
+-again:
+- pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+- do {
+- struct page *page;
+-
+- if (progress >= 64) {
+- progress = 0;
+- if (need_resched() || need_lockbreak(ptl))
+- break;
+- }
+- progress++;
+- if (!pte_present(*pte))
+- continue;
+- if (!pte_maybe_dirty(*pte))
+- continue;
+- page = vm_normal_page(vma, addr, *pte);
+- if (!page)
+- continue;
+- if (ptep_clear_flush_dirty(vma, addr, pte) ||
+- page_test_and_clear_dirty(page))
+- ret += set_page_dirty(page);
+- progress += 3;
+- } while (pte++, addr += PAGE_SIZE, addr != end);
+- pte_unmap_unlock(pte - 1, ptl);
+- cond_resched();
+- if (addr != end)
+- goto again;
+- return ret;
+-}
+-
+-static inline unsigned long msync_pmd_range(struct vm_area_struct *vma,
+- pud_t *pud, unsigned long addr, unsigned long end)
+-{
+- pmd_t *pmd;
+- unsigned long next;
+- unsigned long ret = 0;
+-
+- pmd = pmd_offset(pud, addr);
+- do {
+- next = pmd_addr_end(addr, end);
+- if (pmd_none_or_clear_bad(pmd))
+- continue;
+- ret += msync_pte_range(vma, pmd, addr, next);
+- } while (pmd++, addr = next, addr != end);
+- return ret;
+-}
+-
+-static inline unsigned long msync_pud_range(struct vm_area_struct *vma,
+- pgd_t *pgd, unsigned long addr, unsigned long end)
+-{
+- pud_t *pud;
+- unsigned long next;
+- unsigned long ret = 0;
+-
+- pud = pud_offset(pgd, addr);
+- do {
+- next = pud_addr_end(addr, end);
+- if (pud_none_or_clear_bad(pud))
+- continue;
+- ret += msync_pmd_range(vma, pud, addr, next);
+- } while (pud++, addr = next, addr != end);
+- return ret;
+-}
+-
+-static unsigned long msync_page_range(struct vm_area_struct *vma,
+- unsigned long addr, unsigned long end)
+-{
+- pgd_t *pgd;
+- unsigned long next;
+- unsigned long ret = 0;
+-
+- /* For hugepages we can't go walking the page table normally,
+- * but that's ok, hugetlbfs is memory based, so we don't need
+- * to do anything more on an msync().
+- */
+- if (vma->vm_flags & VM_HUGETLB)
+- return 0;
+-
+- BUG_ON(addr >= end);
+- pgd = pgd_offset(vma->vm_mm, addr);
+- flush_cache_range(vma, addr, end);
+- do {
+- next = pgd_addr_end(addr, end);
+- if (pgd_none_or_clear_bad(pgd))
+- continue;
+- ret += msync_pud_range(vma, pgd, addr, next);
+- } while (pgd++, addr = next, addr != end);
+- return ret;
+-}
+-
+ /*
+ * MS_SYNC syncs the entire file - including mappings.
+ *
+- * MS_ASYNC does not start I/O (it used to, up to 2.5.67). Instead, it just
+- * marks the relevant pages dirty. The application may now run fsync() to
++ * MS_ASYNC does not start I/O (it used to, up to 2.5.67).
++ * Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
++ * Now it doesn't do anything, since dirty pages are properly tracked.
++ *
++ * The application may now run fsync() to
+ * write out the dirty pages and wait on the writeout and check the result.
+ * Or the application may run fadvise(FADV_DONTNEED) against the fd to start
+ * async writeout immediately.
+ * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to
+ * applications.
+ */
+-static int msync_interval(struct vm_area_struct *vma, unsigned long addr,
+- unsigned long end, int flags,
+- unsigned long *nr_pages_dirtied)
+-{
+- struct file *file = vma->vm_file;
+-
+- if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED))
+- return -EBUSY;
+-
+- if (file && (vma->vm_flags & VM_SHARED))
+- *nr_pages_dirtied = msync_page_range(vma, addr, end);
+- return 0;
+-}
+-
+ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
+ {
+ unsigned long end;
++ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ int unmapped_error = 0;
+ int error = -EINVAL;
+- int done = 0;
+
+ if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
+ goto out;
+@@ -169,64 +53,50 @@ asmlinkage long sys_msync(unsigned long
+ * If the interval [start,end) covers some unmapped address ranges,
+ * just ignore them, but return -ENOMEM at the end.
+ */
+- down_read(¤t->mm->mmap_sem);
+- vma = find_vma(current->mm, start);
+- if (!vma) {
+- error = -ENOMEM;
+- goto out_unlock;
+- }
+- do {
+- unsigned long nr_pages_dirtied = 0;
++ down_read(&mm->mmap_sem);
++ vma = find_vma(mm, start);
++ for (;;) {
+ struct file *file;
+
++ /* Still start < end. */
++ error = -ENOMEM;
++ if (!vma)
++ goto out_unlock;
+ /* Here start < vma->vm_end. */
+ if (start < vma->vm_start) {
+- unmapped_error = -ENOMEM;
+ start = vma->vm_start;
++ if (start >= end)
++ goto out_unlock;
++ unmapped_error = -ENOMEM;
+ }
+ /* Here vma->vm_start <= start < vma->vm_end. */
+- if (end <= vma->vm_end) {
+- if (start < end) {
+- error = msync_interval(vma, start, end, flags,
+- &nr_pages_dirtied);
+- if (error)
+- goto out_unlock;
+- }
+- error = unmapped_error;
+- done = 1;
+- } else {
+- /* Here vma->vm_start <= start < vma->vm_end < end. */
+- error = msync_interval(vma, start, vma->vm_end, flags,
+- &nr_pages_dirtied);
+- if (error)
+- goto out_unlock;
++ if ((flags & MS_INVALIDATE) &&
++ (vma->vm_flags & VM_LOCKED)) {
++ error = -EBUSY;
++ goto out_unlock;
+ }
+ file = vma->vm_file;
+ start = vma->vm_end;
+- if ((flags & MS_ASYNC) && file && nr_pages_dirtied) {
+- get_file(file);
+- up_read(¤t->mm->mmap_sem);
+- balance_dirty_pages_ratelimited_nr(file->f_mapping,
+- nr_pages_dirtied);
+- fput(file);
+- down_read(¤t->mm->mmap_sem);
+- vma = find_vma(current->mm, start);
+- } else if ((flags & MS_SYNC) && file &&
++ if ((flags & MS_SYNC) && file &&
+ (vma->vm_flags & VM_SHARED)) {
+ get_file(file);
+- up_read(¤t->mm->mmap_sem);
++ up_read(&mm->mmap_sem);
+ error = do_fsync(file, 0);
+ fput(file);
+- down_read(¤t->mm->mmap_sem);
+- if (error)
+- goto out_unlock;
+- vma = find_vma(current->mm, start);
++ if (error || start >= end)
++ goto out;
++ down_read(&mm->mmap_sem);
++ vma = find_vma(mm, start);
+ } else {
++ if (start >= end) {
++ error = 0;
++ goto out_unlock;
++ }
+ vma = vma->vm_next;
+ }
+- } while (vma && !done);
++ }
+ out_unlock:
+- up_read(¤t->mm->mmap_sem);
++ up_read(&mm->mmap_sem);
+ out:
+- return error;
++ return error ? : unmapped_error;
+ }
+diff --git a/mm/nommu.c b/mm/nommu.c
+index c576df7..8bdde95 100644
+--- a/mm/nommu.c
++++ b/mm/nommu.c
+@@ -122,26 +122,50 @@ unsigned int kobjsize(const void *objp)
+ }
+
+ /*
+- * The nommu dodgy version :-)
++ * get a list of pages in an address range belonging to the specified process
++ * and indicate the VMA that covers each page
++ * - this is potentially dodgy as we may end incrementing the page count of a
++ * slab page or a secondary page from a compound page
++ * - don't permit access to VMAs that don't support it, such as I/O mappings
+ */
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long start, int len, int write, int force,
+ struct page **pages, struct vm_area_struct **vmas)
+ {
++ struct vm_area_struct *vma;
++ unsigned long vm_flags;
+ int i;
+- static struct vm_area_struct dummy_vma;
++
++ /* calculate required read or write permissions.
++ * - if 'force' is set, we only require the "MAY" flags.
++ */
++ vm_flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
++ vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
+
+ for (i = 0; i < len; i++) {
++ vma = find_vma(mm, start);
++ if (!vma)
++ goto finish_or_fault;
++
++ /* protect what we can, including chardevs */
++ if (vma->vm_flags & (VM_IO | VM_PFNMAP) ||
++ !(vm_flags & vma->vm_flags))
++ goto finish_or_fault;
++
+ if (pages) {
+ pages[i] = virt_to_page(start);
+ if (pages[i])
+ page_cache_get(pages[i]);
+ }
+ if (vmas)
+- vmas[i] = &dummy_vma;
++ vmas[i] = vma;
+ start += PAGE_SIZE;
+ }
+- return(i);
++
++ return i;
++
++finish_or_fault:
++ return i ? : -EFAULT;
+ }
+
+ EXPORT_SYMBOL(get_user_pages);
+@@ -197,7 +221,7 @@ long vwrite(char *buf, char *addr, unsig
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into continguos kernel virtual space.
+ *
+- * For tight cotrol over page level allocator and protection flags
++ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+ void *vmalloc(unsigned long size)
+@@ -286,6 +310,77 @@ static void show_process_blocks(void)
+ }
+ #endif /* DEBUG */
+
++/*
++ * add a VMA into a process's mm_struct in the appropriate place in the list
++ * - should be called with mm->mmap_sem held writelocked
++ */
++static void add_vma_to_mm(struct mm_struct *mm, struct vm_list_struct *vml)
++{
++ struct vm_list_struct **ppv;
++
++ for (ppv = ¤t->mm->context.vmlist; *ppv; ppv = &(*ppv)->next)
++ if ((*ppv)->vma->vm_start > vml->vma->vm_start)
++ break;
++
++ vml->next = *ppv;
++ *ppv = vml;
++}
++
++/*
++ * look up the first VMA in which addr resides, NULL if none
++ * - should be called with mm->mmap_sem at least held readlocked
++ */
++struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
++{
++ struct vm_list_struct *loop, *vml;
++
++ /* search the vm_start ordered list */
++ vml = NULL;
++ for (loop = mm->context.vmlist; loop; loop = loop->next) {
++ if (loop->vma->vm_start > addr)
++ break;
++ vml = loop;
++ }
++
++ if (vml && vml->vma->vm_end > addr)
++ return vml->vma;
++
++ return NULL;
++}
++EXPORT_SYMBOL(find_vma);
++
++/*
++ * find a VMA
++ * - we don't extend stack VMAs under NOMMU conditions
++ */
++struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
++{
++ return find_vma(mm, addr);
++}
++
++/*
++ * look up the first VMA exactly that exactly matches addr
++ * - should be called with mm->mmap_sem at least held readlocked
++ */
++static inline struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
++ unsigned long addr)
++{
++ struct vm_list_struct *vml;
++
++ /* search the vm_start ordered list */
++ for (vml = mm->context.vmlist; vml; vml = vml->next) {
++ if (vml->vma->vm_start == addr)
++ return vml->vma;
++ if (vml->vma->vm_start > addr)
++ break;
++ }
++
++ return NULL;
++}
++
++/*
++ * find a VMA in the global tree
++ */
+ static inline struct vm_area_struct *find_nommu_vma(unsigned long start)
+ {
+ struct vm_area_struct *vma;
+@@ -305,6 +400,9 @@ static inline struct vm_area_struct *fin
+ return NULL;
+ }
+
++/*
++ * add a VMA in the global tree
++ */
+ static void add_nommu_vma(struct vm_area_struct *vma)
+ {
+ struct vm_area_struct *pvma;
+@@ -351,6 +449,9 @@ static void add_nommu_vma(struct vm_area
+ rb_insert_color(&vma->vm_rb, &nommu_vma_tree);
+ }
+
++/*
++ * delete a VMA from the global list
++ */
+ static void delete_nommu_vma(struct vm_area_struct *vma)
+ {
+ struct address_space *mapping;
+@@ -828,8 +929,7 @@ unsigned long do_mmap_pgoff(struct file
+ realalloc += kobjsize(vml);
+ askedalloc += sizeof(*vml);
+
+- vml->next = current->mm->context.vmlist;
+- current->mm->context.vmlist = vml;
++ add_vma_to_mm(current->mm, vml);
+
+ up_write(&nommu_vma_sem);
+
+@@ -848,7 +948,8 @@ unsigned long do_mmap_pgoff(struct file
+ up_write(&nommu_vma_sem);
+ kfree(vml);
+ if (vma) {
+- fput(vma->vm_file);
++ if (vma->vm_file)
++ fput(vma->vm_file);
+ kfree(vma);
+ }
+ return ret;
+@@ -908,6 +1009,11 @@ static void put_vma(struct vm_area_struc
+ }
+ }
+
++/*
++ * release a mapping
++ * - under NOMMU conditions the parameters must match exactly to the mapping to
++ * be removed
++ */
+ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
+ {
+ struct vm_list_struct *vml, **parent;
+@@ -917,10 +1023,13 @@ int do_munmap(struct mm_struct *mm, unsi
+ printk("do_munmap:\n");
+ #endif
+
+- for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next)
++ for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) {
++ if ((*parent)->vma->vm_start > addr)
++ break;
+ if ((*parent)->vma->vm_start == addr &&
+ ((len == 0) || ((*parent)->vma->vm_end == end)))
+ goto found;
++ }
+
+ printk("munmap of non-mmaped memory by process %d (%s): %p\n",
+ current->pid, current->comm, (void *) addr);
+@@ -946,7 +1055,20 @@ int do_munmap(struct mm_struct *mm, unsi
+ return 0;
+ }
+
+-/* Release all mmaps. */
++asmlinkage long sys_munmap(unsigned long addr, size_t len)
++{
++ int ret;
++ struct mm_struct *mm = current->mm;
++
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, addr, len);
++ up_write(&mm->mmap_sem);
++ return ret;
++}
++
++/*
++ * Release all mappings
++ */
+ void exit_mmap(struct mm_struct * mm)
+ {
+ struct vm_list_struct *tmp;
+@@ -973,37 +1095,26 @@ void exit_mmap(struct mm_struct * mm)
+ }
+ }
+
+-asmlinkage long sys_munmap(unsigned long addr, size_t len)
+-{
+- int ret;
+- struct mm_struct *mm = current->mm;
+-
+- down_write(&mm->mmap_sem);
+- ret = do_munmap(mm, addr, len);
+- up_write(&mm->mmap_sem);
+- return ret;
+-}
+-
+ unsigned long do_brk(unsigned long addr, unsigned long len)
+ {
+ return -ENOMEM;
+ }
+
+ /*
+- * Expand (or shrink) an existing mapping, potentially moving it at the
+- * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
++ * expand (or shrink) an existing mapping, potentially moving it at the same
++ * time (controlled by the MREMAP_MAYMOVE flag and available VM space)
+ *
+- * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
+- * This option implies MREMAP_MAYMOVE.
++ * under NOMMU conditions, we only permit changing a mapping's size, and only
++ * as long as it stays within the hole allocated by the kmalloc() call in
++ * do_mmap_pgoff() and the block is not shareable
+ *
+- * on uClinux, we only permit changing a mapping's size, and only as long as it stays within the
+- * hole allocated by the kmalloc() call in do_mmap_pgoff() and the block is not shareable
++ * MREMAP_FIXED is not supported under NOMMU conditions
+ */
+ unsigned long do_mremap(unsigned long addr,
+ unsigned long old_len, unsigned long new_len,
+ unsigned long flags, unsigned long new_addr)
+ {
+- struct vm_list_struct *vml = NULL;
++ struct vm_area_struct *vma;
+
+ /* insanity checks first */
+ if (new_len == 0)
+@@ -1012,58 +1123,46 @@ unsigned long do_mremap(unsigned long ad
+ if (flags & MREMAP_FIXED && new_addr != addr)
+ return (unsigned long) -EINVAL;
+
+- for (vml = current->mm->context.vmlist; vml; vml = vml->next)
+- if (vml->vma->vm_start == addr)
+- goto found;
+-
+- return (unsigned long) -EINVAL;
++ vma = find_vma_exact(current->mm, addr);
++ if (!vma)
++ return (unsigned long) -EINVAL;
+
+- found:
+- if (vml->vma->vm_end != vml->vma->vm_start + old_len)
++ if (vma->vm_end != vma->vm_start + old_len)
+ return (unsigned long) -EFAULT;
+
+- if (vml->vma->vm_flags & VM_MAYSHARE)
++ if (vma->vm_flags & VM_MAYSHARE)
+ return (unsigned long) -EPERM;
+
+ if (new_len > kobjsize((void *) addr))
+ return (unsigned long) -ENOMEM;
+
+ /* all checks complete - do it */
+- vml->vma->vm_end = vml->vma->vm_start + new_len;
++ vma->vm_end = vma->vm_start + new_len;
+
+ askedalloc -= old_len;
+ askedalloc += new_len;
+
+- return vml->vma->vm_start;
++ return vma->vm_start;
+ }
+
+-/*
+- * Look up the first VMA which satisfies addr < vm_end, NULL if none
+- */
+-struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
++asmlinkage unsigned long sys_mremap(unsigned long addr,
++ unsigned long old_len, unsigned long new_len,
++ unsigned long flags, unsigned long new_addr)
+ {
+- struct vm_list_struct *vml;
+-
+- for (vml = mm->context.vmlist; vml; vml = vml->next)
+- if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end)
+- return vml->vma;
++ unsigned long ret;
+
+- return NULL;
++ down_write(¤t->mm->mmap_sem);
++ ret = do_mremap(addr, old_len, new_len, flags, new_addr);
++ up_write(¤t->mm->mmap_sem);
++ return ret;
+ }
+
+-EXPORT_SYMBOL(find_vma);
+-
+ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
+ unsigned int foll_flags)
+ {
+ return NULL;
+ }
+
+-struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
+-{
+- return NULL;
+-}
+-
+ int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long to, unsigned long size, pgprot_t prot)
+ {
+@@ -1133,7 +1232,7 @@ int __vm_enough_memory(long pages, int c
+ * which are reclaimable, under pressure. The dentry
+ * cache and most inode caches should fall into this
+ */
+- free += atomic_read(&slab_reclaim_pages);
++ free += global_page_state(NR_SLAB_RECLAIMABLE);
+
+ /*
+ * Leave the last 3% for root
+@@ -1206,3 +1305,44 @@ struct page *filemap_nopage(struct vm_ar
+ BUG();
+ return NULL;
+ }
++
++/*
++ * Access another process' address space.
++ * - source/target buffer must be kernel space
++ */
++int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
++{
++ struct vm_area_struct *vma;
++ struct mm_struct *mm;
++
++ if (addr + len < addr)
++ return 0;
++
++ mm = get_task_mm(tsk);
++ if (!mm)
++ return 0;
++
++ down_read(&mm->mmap_sem);
++
++ /* the access must start within one of the target process's mappings */
++ vma = find_vma(mm, addr);
++ if (vma) {
++ /* don't overrun this mapping */
++ if (addr + len >= vma->vm_end)
++ len = vma->vm_end - addr;
++
++ /* only read or write mappings where it is permitted */
++ if (write && vma->vm_flags & VM_MAYWRITE)
++ len -= copy_to_user((void *) addr, buf, len);
++ else if (!write && vma->vm_flags & VM_MAYREAD)
++ len -= copy_from_user(buf, (void *) addr, len);
++ else
++ len = 0;
++ } else {
++ len = 0;
++ }
++
++ up_read(&mm->mmap_sem);
++ mmput(mm);
++ return len;
++}
+diff --git a/mm/oom_kill.c b/mm/oom_kill.c
+index b9af136..2e3ce3a 100644
+--- a/mm/oom_kill.c
++++ b/mm/oom_kill.c
+@@ -15,12 +15,15 @@
+ * kernel subsystems and hints as to where to find out what things do.
+ */
+
++#include <linux/oom.h>
+ #include <linux/mm.h>
+ #include <linux/sched.h>
+ #include <linux/swap.h>
+ #include <linux/timex.h>
+ #include <linux/jiffies.h>
+ #include <linux/cpuset.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
+
+ int sysctl_panic_on_oom;
+ /* #define DEBUG */
+@@ -58,6 +61,12 @@ unsigned long badness(struct task_struct
+ }
+
+ /*
++ * swapoff can easily use up all memory, so kill those first.
++ */
++ if (p->flags & PF_SWAPOFF)
++ return ULONG_MAX;
++
++ /*
+ * The memory size of the process is the basis for the badness.
+ */
+ points = mm->total_vm;
+@@ -127,6 +136,14 @@ unsigned long badness(struct task_struct
+ points /= 4;
+
+ /*
++ * If p's nodes don't overlap ours, it may still help to kill p
++ * because p may have allocated or otherwise mapped memory on
++ * this node before. However it will be less likely.
++ */
++ if (!cpuset_excl_nodes_overlap(p))
++ points /= 8;
++
++ /*
+ * Adjust the score by oomkilladj.
+ */
+ if (p->oomkilladj) {
+@@ -161,8 +178,7 @@ static inline int constrained_alloc(stru
+
+ for (z = zonelist->zones; *z; z++)
+ if (cpuset_zone_allowed(*z, gfp_mask))
+- node_clear((*z)->zone_pgdat->node_id,
+- nodes);
++ node_clear(zone_to_nid(*z), nodes);
+ else
+ return CONSTRAINT_CPUSET;
+
+@@ -189,27 +205,49 @@ static struct task_struct *select_bad_pr
+ do_posix_clock_monotonic_gettime(&uptime);
+ do_each_thread(g, p) {
+ unsigned long points;
+- int releasing;
+
+- /* skip the init task with pid == 1 */
+- if (p->pid == 1)
+- continue;
+- if (p->oomkilladj == OOM_DISABLE)
++ /*
++ * skip kernel threads and tasks which have already released
++ * their mm.
++ */
++ if (!p->mm)
+ continue;
+- /* If p's nodes don't overlap ours, it won't help to kill p. */
+- if (!cpuset_excl_nodes_overlap(p))
++ /* skip the init task */
++ if (is_init(p))
+ continue;
+
+ /*
++ * This task already has access to memory reserves and is
++ * being killed. Don't allow any other task access to the
++ * memory reserve.
++ *
++ * Note: this may have a chance of deadlock if it gets
++ * blocked waiting for another task which itself is waiting
++ * for memory. Is there a better alternative?
++ */
++ if (test_tsk_thread_flag(p, TIF_MEMDIE))
++ return ERR_PTR(-1UL);
++
++ /*
+ * This is in the process of releasing memory so wait for it
+ * to finish before killing some other task by mistake.
++ *
++ * However, if p is the current task, we allow the 'kill' to
++ * go ahead if it is exiting: this will simply set TIF_MEMDIE,
++ * which will allow it to gain access to memory reserves in
++ * the process of exiting and releasing its resources.
++ * Otherwise we could get an easy OOM deadlock.
+ */
+- releasing = test_tsk_thread_flag(p, TIF_MEMDIE) ||
+- p->flags & PF_EXITING;
+- if (releasing && !(p->flags & PF_DEAD))
+- return ERR_PTR(-1UL);
+- if (p->flags & PF_SWAPOFF)
+- return p;
++ if (p->flags & PF_EXITING) {
++ if (p != current)
++ return ERR_PTR(-1UL);
++
++ chosen = p;
++ *ppoints = ULONG_MAX;
++ }
++
++ if (p->oomkilladj == OOM_DISABLE)
++ continue;
+
+ points = badness(p, uptime.tv_sec);
+ if (points > *ppoints || !chosen) {
+@@ -217,32 +255,33 @@ static struct task_struct *select_bad_pr
+ *ppoints = points;
+ }
+ } while_each_thread(g, p);
++
+ return chosen;
+ }
+
+ /**
+- * We must be careful though to never send SIGKILL a process with
+- * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that
+- * we select a process with CAP_SYS_RAW_IO set).
++ * Send SIGKILL to the selected process irrespective of CAP_SYS_RAW_IO
++ * flag though it's unlikely that we select a process with CAP_SYS_RAW_IO
++ * set.
+ */
+ static void __oom_kill_task(struct task_struct *p, const char *message)
+ {
+- if (p->pid == 1) {
++ if (is_init(p)) {
+ WARN_ON(1);
+ printk(KERN_WARNING "tried to kill init!\n");
+ return;
+ }
+
+- task_lock(p);
+- if (!p->mm || p->mm == &init_mm) {
++ if (!p->mm) {
+ WARN_ON(1);
+ printk(KERN_WARNING "tried to kill an mm-less task!\n");
+- task_unlock(p);
+ return;
+ }
+- task_unlock(p);
+- printk(KERN_ERR "%s: Killed process %d (%s).\n",
++
++ if (message) {
++ printk(KERN_ERR "%s: Killed process %d (%s).\n",
+ message, p->pid, p->comm);
++ }
+
+ /*
+ * We give our sacrificial lamb high priority and access to
+@@ -271,7 +310,7 @@ static int oom_kill_task(struct task_str
+ * However, this is of no concern to us.
+ */
+
+- if (mm == NULL || mm == &init_mm)
++ if (mm == NULL)
+ return 1;
+
+ __oom_kill_task(p, message);
+@@ -293,8 +332,17 @@ static int oom_kill_process(struct task_
+ struct task_struct *c;
+ struct list_head *tsk;
+
+- printk(KERN_ERR "Out of Memory: Kill process %d (%s) score %li and "
+- "children.\n", p->pid, p->comm, points);
++ /*
++ * If the task is already exiting, don't alarm the sysadmin or kill
++ * its children or threads, just set TIF_MEMDIE so it can die quickly
++ */
++ if (p->flags & PF_EXITING) {
++ __oom_kill_task(p, NULL);
++ return 0;
++ }
++
++ printk(KERN_ERR "Out of Memory: Kill process %d (%s) score %li"
++ " and children.\n", p->pid, p->comm, points);
+ /* Try to kill a child first */
+ list_for_each(tsk, &p->children) {
+ c = list_entry(tsk, struct task_struct, sibling);
+@@ -306,6 +354,20 @@ static int oom_kill_process(struct task_
+ return oom_kill_task(p, message);
+ }
+
++static BLOCKING_NOTIFIER_HEAD(oom_notify_list);
++
++int register_oom_notifier(struct notifier_block *nb)
++{
++ return blocking_notifier_chain_register(&oom_notify_list, nb);
++}
++EXPORT_SYMBOL_GPL(register_oom_notifier);
++
++int unregister_oom_notifier(struct notifier_block *nb)
++{
++ return blocking_notifier_chain_unregister(&oom_notify_list, nb);
++}
++EXPORT_SYMBOL_GPL(unregister_oom_notifier);
++
+ /**
+ * out_of_memory - kill the "best" process when we run out of memory
+ *
+@@ -318,10 +380,17 @@ void out_of_memory(struct zonelist *zone
+ {
+ struct task_struct *p;
+ unsigned long points = 0;
++ unsigned long freed = 0;
++
++ blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
++ if (freed > 0)
++ /* Got some memory back in the last second. */
++ return;
+
+ if (printk_ratelimit()) {
+- printk("oom-killer: gfp_mask=0x%x, order=%d\n",
+- gfp_mask, order);
++ printk(KERN_WARNING "%s invoked oom-killer: "
++ "gfp_mask=0x%x, order=%d, oomkilladj=%d\n",
++ current->comm, gfp_mask, order, current->oomkilladj);
+ dump_stack();
+ show_mem();
+ }
+diff --git a/mm/page-writeback.c b/mm/page-writeback.c
+index e630188..8d9b19f 100644
+--- a/mm/page-writeback.c
++++ b/mm/page-writeback.c
+@@ -1,5 +1,5 @@
+ /*
+- * mm/page-writeback.c.
++ * mm/page-writeback.c
+ *
+ * Copyright (C) 2002, Linus Torvalds.
+ *
+@@ -23,12 +23,15 @@
+ #include <linux/backing-dev.h>
+ #include <linux/blkdev.h>
+ #include <linux/mpage.h>
++#include <linux/rmap.h>
+ #include <linux/percpu.h>
+ #include <linux/notifier.h>
+ #include <linux/smp.h>
+ #include <linux/sysctl.h>
+ #include <linux/cpu.h>
+ #include <linux/syscalls.h>
++#include <linux/buffer_head.h>
++#include <linux/pagevec.h>
+
+ /*
+ * The maximum number of pages to writeout in a single bdflush/kupdate
+@@ -45,7 +48,6 @@
+ */
+ static long ratelimit_pages = 32;
+
+-static long total_pages; /* The total number of pages in the machine. */
+ static int dirty_exceeded __cacheline_aligned_in_smp; /* Dirty mem may be over limit */
+
+ /*
+@@ -125,7 +127,7 @@ get_dirty_limits(long *pbackground, long
+ int unmapped_ratio;
+ long background;
+ long dirty;
+- unsigned long available_memory = total_pages;
++ unsigned long available_memory = vm_total_pages;
+ struct task_struct *tsk;
+
+ #ifdef CONFIG_HIGHMEM
+@@ -140,7 +142,7 @@ get_dirty_limits(long *pbackground, long
+
+ unmapped_ratio = 100 - ((global_page_state(NR_FILE_MAPPED) +
+ global_page_state(NR_ANON_PAGES)) * 100) /
+- total_pages;
++ vm_total_pages;
+
+ dirty_ratio = vm_dirty_ratio;
+ if (dirty_ratio > unmapped_ratio / 2)
+@@ -220,7 +222,7 @@ static void balance_dirty_pages(struct a
+ if (pages_written >= write_chunk)
+ break; /* We've done our duty */
+ }
+- blk_congestion_wait(WRITE, HZ/10);
++ congestion_wait(WRITE, HZ/10);
+ }
+
+ if (nr_reclaimable + global_page_state(NR_WRITEBACK)
+@@ -243,6 +245,16 @@ static void balance_dirty_pages(struct a
+ pdflush_operation(background_writeout, 0);
+ }
+
++void set_page_dirty_balance(struct page *page)
++{
++ if (set_page_dirty(page)) {
++ struct address_space *mapping = page_mapping(page);
++
++ if (mapping)
++ balance_dirty_pages_ratelimited(mapping);
++ }
++}
++
+ /**
+ * balance_dirty_pages_ratelimited_nr - balance dirty memory state
+ * @mapping: address_space which was dirtied
+@@ -302,7 +314,7 @@ void throttle_vm_writeout(void)
+ if (global_page_state(NR_UNSTABLE_NFS) +
+ global_page_state(NR_WRITEBACK) <= dirty_thresh)
+ break;
+- blk_congestion_wait(WRITE, HZ/10);
++ congestion_wait(WRITE, HZ/10);
+ }
+ }
+
+@@ -339,7 +351,7 @@ static void background_writeout(unsigned
+ min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+ if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
+ /* Wrote less than expected */
+- blk_congestion_wait(WRITE, HZ/10);
++ congestion_wait(WRITE, HZ/10);
+ if (!wbc.encountered_congestion)
+ break;
+ }
+@@ -410,7 +422,7 @@ static void wb_kupdate(unsigned long arg
+ writeback_inodes(&wbc);
+ if (wbc.nr_to_write > 0) {
+ if (wbc.encountered_congestion)
+- blk_congestion_wait(WRITE, HZ/10);
++ congestion_wait(WRITE, HZ/10);
+ else
+ break; /* All the old data is written */
+ }
+@@ -491,9 +503,9 @@ void laptop_sync_completion(void)
+ * will write six megabyte chunks, max.
+ */
+
+-static void set_ratelimit(void)
++void writeback_set_ratelimit(void)
+ {
+- ratelimit_pages = total_pages / (num_online_cpus() * 32);
++ ratelimit_pages = vm_total_pages / (num_online_cpus() * 32);
+ if (ratelimit_pages < 16)
+ ratelimit_pages = 16;
+ if (ratelimit_pages * PAGE_CACHE_SIZE > 4096 * 1024)
+@@ -503,7 +515,7 @@ static void set_ratelimit(void)
+ static int __cpuinit
+ ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
+ {
+- set_ratelimit();
++ writeback_set_ratelimit();
+ return 0;
+ }
+
+@@ -522,9 +534,7 @@ void __init page_writeback_init(void)
+ long buffer_pages = nr_free_buffer_pages();
+ long correction;
+
+- total_pages = nr_free_pagecache_pages();
+-
+- correction = (100 * 4 * buffer_pages) / total_pages;
++ correction = (100 * 4 * buffer_pages) / vm_total_pages;
+
+ if (correction < 100) {
+ dirty_background_ratio *= correction;
+@@ -538,10 +548,143 @@ void __init page_writeback_init(void)
+ vm_dirty_ratio = 1;
+ }
+ mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
+- set_ratelimit();
++ writeback_set_ratelimit();
+ register_cpu_notifier(&ratelimit_nb);
+ }
+
++/**
++ * generic_writepages - walk the list of dirty pages of the given
++ * address space and writepage() all of them.
++ *
++ * @mapping: address space structure to write
++ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
++ *
++ * This is a library function, which implements the writepages()
++ * address_space_operation.
++ *
++ * If a page is already under I/O, generic_writepages() skips it, even
++ * if it's dirty. This is desirable behaviour for memory-cleaning writeback,
++ * but it is INCORRECT for data-integrity system calls such as fsync(). fsync()
++ * and msync() need to guarantee that all the data which was dirty at the time
++ * the call was made get new I/O started against them. If wbc->sync_mode is
++ * WB_SYNC_ALL then we were called for data integrity and we must wait for
++ * existing IO to complete.
++ *
++ * Derived from mpage_writepages() - if you fix this you should check that
++ * also!
++ */
++int generic_writepages(struct address_space *mapping,
++ struct writeback_control *wbc)
++{
++ struct backing_dev_info *bdi = mapping->backing_dev_info;
++ int ret = 0;
++ int done = 0;
++ int (*writepage)(struct page *page, struct writeback_control *wbc);
++ struct pagevec pvec;
++ int nr_pages;
++ pgoff_t index;
++ pgoff_t end; /* Inclusive */
++ int scanned = 0;
++ int range_whole = 0;
++
++ if (wbc->nonblocking && bdi_write_congested(bdi)) {
++ wbc->encountered_congestion = 1;
++ return 0;
++ }
++
++ writepage = mapping->a_ops->writepage;
++
++ /* deal with chardevs and other special file */
++ if (!writepage)
++ return 0;
++
++ pagevec_init(&pvec, 0);
++ if (wbc->range_cyclic) {
++ index = mapping->writeback_index; /* Start from prev offset */
++ end = -1;
++ } else {
++ index = wbc->range_start >> PAGE_CACHE_SHIFT;
++ end = wbc->range_end >> PAGE_CACHE_SHIFT;
++ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
++ range_whole = 1;
++ scanned = 1;
++ }
++retry:
++ while (!done && (index <= end) &&
++ (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
++ PAGECACHE_TAG_DIRTY,
++ min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
++ unsigned i;
++
++ scanned = 1;
++ for (i = 0; i < nr_pages; i++) {
++ struct page *page = pvec.pages[i];
++
++ /*
++ * At this point we hold neither mapping->tree_lock nor
++ * lock on the page itself: the page may be truncated or
++ * invalidated (changing page->mapping to NULL), or even
++ * swizzled back from swapper_space to tmpfs file
++ * mapping
++ */
++ lock_page(page);
++
++ if (unlikely(page->mapping != mapping)) {
++ unlock_page(page);
++ continue;
++ }
++
++ if (!wbc->range_cyclic && page->index > end) {
++ done = 1;
++ unlock_page(page);
++ continue;
++ }
++
++ if (wbc->sync_mode != WB_SYNC_NONE)
++ wait_on_page_writeback(page);
++
++ if (PageWriteback(page) ||
++ !clear_page_dirty_for_io(page)) {
++ unlock_page(page);
++ continue;
++ }
++
++ ret = (*writepage)(page, wbc);
++ if (ret) {
++ if (ret == -ENOSPC)
++ set_bit(AS_ENOSPC, &mapping->flags);
++ else
++ set_bit(AS_EIO, &mapping->flags);
++ }
++
++ if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
++ unlock_page(page);
++ if (ret || (--(wbc->nr_to_write) <= 0))
++ done = 1;
++ if (wbc->nonblocking && bdi_write_congested(bdi)) {
++ wbc->encountered_congestion = 1;
++ done = 1;
++ }
++ }
++ pagevec_release(&pvec);
++ cond_resched();
++ }
++ if (!scanned && !done) {
++ /*
++ * We hit the last page and there is more work to be done: wrap
++ * back to the start of the file
++ */
++ scanned = 1;
++ index = 0;
++ goto retry;
++ }
++ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
++ mapping->writeback_index = index;
++ return ret;
++}
++
++EXPORT_SYMBOL(generic_writepages);
++
+ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
+ {
+ int ret;
+@@ -550,7 +693,7 @@ int do_writepages(struct address_space *
+ return 0;
+ wbc->for_writepages = 1;
+ if (mapping->a_ops->writepages)
+- ret = mapping->a_ops->writepages(mapping, wbc);
++ ret = mapping->a_ops->writepages(mapping, wbc);
+ else
+ ret = generic_writepages(mapping, wbc);
+ wbc->for_writepages = 0;
+@@ -664,9 +807,11 @@ int fastcall set_page_dirty(struct page
+
+ if (likely(mapping)) {
+ int (*spd)(struct page *) = mapping->a_ops->set_page_dirty;
+- if (spd)
+- return (*spd)(page);
+- return __set_page_dirty_buffers(page);
++#ifdef CONFIG_BLOCK
++ if (!spd)
++ spd = __set_page_dirty_buffers;
++#endif
++ return (*spd)(page);
+ }
+ if (!PageDirty(page)) {
+ if (!TestSetPageDirty(page))
+@@ -690,7 +835,7 @@ int set_page_dirty_lock(struct page *pag
+ {
+ int ret;
+
+- lock_page(page);
++ lock_page_nosync(page);
+ ret = set_page_dirty(page);
+ unlock_page(page);
+ return ret;
+@@ -712,9 +857,15 @@ int test_clear_page_dirty(struct page *p
+ radix_tree_tag_clear(&mapping->page_tree,
+ page_index(page),
+ PAGECACHE_TAG_DIRTY);
+- if (mapping_cap_account_dirty(mapping))
+- __dec_zone_page_state(page, NR_FILE_DIRTY);
+ write_unlock_irqrestore(&mapping->tree_lock, flags);
++ /*
++ * We can continue to use `mapping' here because the
++ * page is locked, which pins the address_space
++ */
++ if (mapping_cap_account_dirty(mapping)) {
++ page_mkclean(page);
++ dec_zone_page_state(page, NR_FILE_DIRTY);
++ }
+ return 1;
+ }
+ write_unlock_irqrestore(&mapping->tree_lock, flags);
+@@ -744,8 +895,10 @@ int clear_page_dirty_for_io(struct page
+
+ if (mapping) {
+ if (TestClearPageDirty(page)) {
+- if (mapping_cap_account_dirty(mapping))
++ if (mapping_cap_account_dirty(mapping)) {
++ page_mkclean(page);
+ dec_zone_page_state(page, NR_FILE_DIRTY);
++ }
+ return 1;
+ }
+ return 0;
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index 54a4f53..bf2f6cf 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -37,6 +37,9 @@
+ #include <linux/vmalloc.h>
+ #include <linux/mempolicy.h>
+ #include <linux/stop_machine.h>
++#include <linux/sort.h>
++#include <linux/pfn.h>
++#include <linux/backing-dev.h>
+
+ #include <asm/tlbflush.h>
+ #include <asm/div64.h>
+@@ -51,7 +54,6 @@ EXPORT_SYMBOL(node_online_map);
+ nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL;
+ EXPORT_SYMBOL(node_possible_map);
+ unsigned long totalram_pages __read_mostly;
+-unsigned long totalhigh_pages __read_mostly;
+ unsigned long totalreserve_pages __read_mostly;
+ long nr_swap_pages;
+ int percpu_pagelist_fraction;
+@@ -69,7 +71,15 @@ static void __free_pages_ok(struct page
+ * TBD: should special case ZONE_DMA32 machines here - in those we normally
+ * don't need any ZONE_NORMAL reservation
+ */
+-int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { 256, 256, 32 };
++int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = {
++ 256,
++#ifdef CONFIG_ZONE_DMA32
++ 256,
++#endif
++#ifdef CONFIG_HIGHMEM
++ 32
++#endif
++};
+
+ EXPORT_SYMBOL(totalram_pages);
+
+@@ -80,11 +90,53 @@ EXPORT_SYMBOL(totalram_pages);
+ struct zone *zone_table[1 << ZONETABLE_SHIFT] __read_mostly;
+ EXPORT_SYMBOL(zone_table);
+
+-static char *zone_names[MAX_NR_ZONES] = { "DMA", "DMA32", "Normal", "HighMem" };
++static char *zone_names[MAX_NR_ZONES] = {
++ "DMA",
++#ifdef CONFIG_ZONE_DMA32
++ "DMA32",
++#endif
++ "Normal",
++#ifdef CONFIG_HIGHMEM
++ "HighMem"
++#endif
++};
++
+ int min_free_kbytes = 1024;
+
+ unsigned long __meminitdata nr_kernel_pages;
+ unsigned long __meminitdata nr_all_pages;
++static unsigned long __initdata dma_reserve;
++
++#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
++ /*
++ * MAX_ACTIVE_REGIONS determines the maxmimum number of distinct
++ * ranges of memory (RAM) that may be registered with add_active_range().
++ * Ranges passed to add_active_range() will be merged if possible
++ * so the number of times add_active_range() can be called is
++ * related to the number of nodes and the number of holes
++ */
++ #ifdef CONFIG_MAX_ACTIVE_REGIONS
++ /* Allow an architecture to set MAX_ACTIVE_REGIONS to save memory */
++ #define MAX_ACTIVE_REGIONS CONFIG_MAX_ACTIVE_REGIONS
++ #else
++ #if MAX_NUMNODES >= 32
++ /* If there can be many nodes, allow up to 50 holes per node */
++ #define MAX_ACTIVE_REGIONS (MAX_NUMNODES*50)
++ #else
++ /* By default, allow up to 256 distinct regions */
++ #define MAX_ACTIVE_REGIONS 256
++ #endif
++ #endif
++
++ struct node_active_region __initdata early_node_map[MAX_ACTIVE_REGIONS];
++ int __initdata nr_nodemap_entries;
++ unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
++ unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
++ unsigned long __initdata node_boundary_start_pfn[MAX_NUMNODES];
++ unsigned long __initdata node_boundary_end_pfn[MAX_NUMNODES];
++#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
++#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
+
+ #ifdef CONFIG_DEBUG_VM
+ static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
+@@ -127,7 +179,6 @@ static int bad_range(struct zone *zone,
+
+ return 0;
+ }
+-
+ #else
+ static inline int bad_range(struct zone *zone, struct page *page)
+ {
+@@ -218,12 +269,12 @@ static inline void prep_zero_page(struct
+ {
+ int i;
+
+- BUG_ON((gfp_flags & (__GFP_WAIT | __GFP_HIGHMEM)) == __GFP_HIGHMEM);
++ VM_BUG_ON((gfp_flags & (__GFP_WAIT | __GFP_HIGHMEM)) == __GFP_HIGHMEM);
+ /*
+ * clear_highpage() will use KM_USER0, so it's a bug to use __GFP_ZERO
+ * and __GFP_HIGHMEM from hard or soft interrupt context.
+ */
+- BUG_ON((gfp_flags & __GFP_HIGHMEM) && in_interrupt());
++ VM_BUG_ON((gfp_flags & __GFP_HIGHMEM) && in_interrupt());
+ for (i = 0; i < (1 << order); i++)
+ clear_highpage(page + i);
+ }
+@@ -347,8 +398,8 @@ static inline void __free_one_page(struc
+
+ page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
+
+- BUG_ON(page_idx & (order_size - 1));
+- BUG_ON(bad_range(zone, page));
++ VM_BUG_ON(page_idx & (order_size - 1));
++ VM_BUG_ON(bad_range(zone, page));
+
+ zone->free_pages += order_size;
+ while (order < MAX_ORDER-1) {
+@@ -421,7 +472,7 @@ static void free_pages_bulk(struct zone
+ while (count--) {
+ struct page *page;
+
+- BUG_ON(list_empty(list));
++ VM_BUG_ON(list_empty(list));
+ page = list_entry(list->prev, struct page, lru);
+ /* have to delete it as __free_one_page list manipulates */
+ list_del(&page->lru);
+@@ -432,9 +483,11 @@ static void free_pages_bulk(struct zone
+
+ static void free_one_page(struct zone *zone, struct page *page, int order)
+ {
+- LIST_HEAD(list);
+- list_add(&page->lru, &list);
+- free_pages_bulk(zone, 1, &list, order);
++ spin_lock(&zone->lock);
++ zone->all_unreclaimable = 0;
++ zone->pages_scanned = 0;
++ __free_one_page(page, zone ,order);
++ spin_unlock(&zone->lock);
+ }
+
+ static void __free_pages_ok(struct page *page, unsigned int order)
+@@ -443,17 +496,16 @@ static void __free_pages_ok(struct page
+ int i;
+ int reserved = 0;
+
+- arch_free_page(page, order);
+- if (!PageHighMem(page))
+- debug_check_no_locks_freed(page_address(page),
+- PAGE_SIZE<<order);
+-
+ for (i = 0 ; i < (1 << order) ; ++i)
+ reserved += free_pages_check(page + i);
+ if (reserved)
+ return;
+
++ if (!PageHighMem(page))
++ debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
++ arch_free_page(page, order);
+ kernel_map_pages(page, 1 << order, 0);
++
+ local_irq_save(flags);
+ __count_vm_events(PGFREE, 1 << order);
+ free_one_page(page_zone(page), page, order);
+@@ -512,7 +564,7 @@ static inline void expand(struct zone *z
+ area--;
+ high--;
+ size >>= 1;
+- BUG_ON(bad_range(zone, &page[size]));
++ VM_BUG_ON(bad_range(zone, &page[size]));
+ list_add(&page[size].lru, &area->free_list);
+ area->nr_free++;
+ set_page_order(&page[size], high);
+@@ -615,19 +667,23 @@ static int rmqueue_bulk(struct zone *zon
+ #ifdef CONFIG_NUMA
+ /*
+ * Called from the slab reaper to drain pagesets on a particular node that
+- * belong to the currently executing processor.
++ * belongs to the currently executing processor.
+ * Note that this function must be called with the thread pinned to
+ * a single processor.
+ */
+ void drain_node_pages(int nodeid)
+ {
+- int i, z;
++ int i;
++ enum zone_type z;
+ unsigned long flags;
+
+ for (z = 0; z < MAX_NR_ZONES; z++) {
+ struct zone *zone = NODE_DATA(nodeid)->node_zones + z;
+ struct per_cpu_pageset *pset;
+
++ if (!populated_zone(zone))
++ continue;
++
+ pset = zone_pcp(zone, smp_processor_id());
+ for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+ struct per_cpu_pages *pcp;
+@@ -672,7 +728,8 @@ static void __drain_pages(unsigned int c
+
+ void mark_free_pages(struct zone *zone)
+ {
+- unsigned long zone_pfn, flags;
++ unsigned long pfn, max_zone_pfn;
++ unsigned long flags;
+ int order;
+ struct list_head *curr;
+
+@@ -680,18 +737,25 @@ void mark_free_pages(struct zone *zone)
+ return;
+
+ spin_lock_irqsave(&zone->lock, flags);
+- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+- ClearPageNosaveFree(pfn_to_page(zone_pfn + zone->zone_start_pfn));
++
++ max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
++ if (pfn_valid(pfn)) {
++ struct page *page = pfn_to_page(pfn);
++
++ if (!PageNosave(page))
++ ClearPageNosaveFree(page);
++ }
+
+ for (order = MAX_ORDER - 1; order >= 0; --order)
+ list_for_each(curr, &zone->free_area[order].free_list) {
+- unsigned long start_pfn, i;
++ unsigned long i;
+
+- start_pfn = page_to_pfn(list_entry(curr, struct page, lru));
++ pfn = page_to_pfn(list_entry(curr, struct page, lru));
++ for (i = 0; i < (1UL << order); i++)
++ SetPageNosaveFree(pfn_to_page(pfn + i));
++ }
+
+- for (i=0; i < (1<<order); i++)
+- SetPageNosaveFree(pfn_to_page(start_pfn+i));
+- }
+ spin_unlock_irqrestore(&zone->lock, flags);
+ }
+
+@@ -717,13 +781,14 @@ static void fastcall free_hot_cold_page(
+ struct per_cpu_pages *pcp;
+ unsigned long flags;
+
+- arch_free_page(page, 0);
+-
+ if (PageAnon(page))
+ page->mapping = NULL;
+ if (free_pages_check(page))
+ return;
+
++ if (!PageHighMem(page))
++ debug_check_no_locks_freed(page_address(page), PAGE_SIZE);
++ arch_free_page(page, 0);
+ kernel_map_pages(page, 1, 0);
+
+ pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
+@@ -761,8 +826,8 @@ void split_page(struct page *page, unsig
+ {
+ int i;
+
+- BUG_ON(PageCompound(page));
+- BUG_ON(!page_count(page));
++ VM_BUG_ON(PageCompound(page));
++ VM_BUG_ON(!page_count(page));
+ for (i = 1; i < (1 << order); i++)
+ set_page_refcounted(page + i);
+ }
+@@ -788,7 +853,7 @@ again:
+ pcp = &zone_pcp(zone, cpu)->pcp[cold];
+ local_irq_save(flags);
+ if (!pcp->count) {
+- pcp->count += rmqueue_bulk(zone, 0,
++ pcp->count = rmqueue_bulk(zone, 0,
+ pcp->batch, &pcp->list);
+ if (unlikely(!pcp->count))
+ goto failed;
+@@ -809,7 +874,7 @@ again:
+ local_irq_restore(flags);
+ put_cpu();
+
+- BUG_ON(bad_range(zone, page));
++ VM_BUG_ON(bad_range(zone, page));
+ if (prep_new_page(page, order, gfp_flags))
+ goto again;
+ return page;
+@@ -836,7 +901,8 @@ int zone_watermark_ok(struct zone *z, in
+ int classzone_idx, int alloc_flags)
+ {
+ /* free_pages my go negative - that's OK */
+- long min = mark, free_pages = z->free_pages - (1 << order) + 1;
++ unsigned long min = mark;
++ long free_pages = z->free_pages - (1 << order) + 1;
+ int o;
+
+ if (alloc_flags & ALLOC_HIGH)
+@@ -870,32 +936,37 @@ get_page_from_freelist(gfp_t gfp_mask, u
+ struct zone **z = zonelist->zones;
+ struct page *page = NULL;
+ int classzone_idx = zone_idx(*z);
++ struct zone *zone;
+
+ /*
+ * Go through the zonelist once, looking for a zone with enough free.
+ * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+ */
+ do {
++ zone = *z;
++ if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) &&
++ zone->zone_pgdat != zonelist->zones[0]->zone_pgdat))
++ break;
+ if ((alloc_flags & ALLOC_CPUSET) &&
+- !cpuset_zone_allowed(*z, gfp_mask))
++ !cpuset_zone_allowed(zone, gfp_mask))
+ continue;
+
+ if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
+ unsigned long mark;
+ if (alloc_flags & ALLOC_WMARK_MIN)
+- mark = (*z)->pages_min;
++ mark = zone->pages_min;
+ else if (alloc_flags & ALLOC_WMARK_LOW)
+- mark = (*z)->pages_low;
++ mark = zone->pages_low;
+ else
+- mark = (*z)->pages_high;
+- if (!zone_watermark_ok(*z, order, mark,
++ mark = zone->pages_high;
++ if (!zone_watermark_ok(zone , order, mark,
+ classzone_idx, alloc_flags))
+ if (!zone_reclaim_mode ||
+- !zone_reclaim(*z, gfp_mask, order))
++ !zone_reclaim(zone, gfp_mask, order))
+ continue;
+ }
+
+- page = buffered_rmqueue(zonelist, *z, order, gfp_mask);
++ page = buffered_rmqueue(zonelist, zone, order, gfp_mask);
+ if (page) {
+ break;
+ }
+@@ -980,7 +1051,7 @@ nofail_alloc:
+ if (page)
+ goto got_pg;
+ if (gfp_mask & __GFP_NOFAIL) {
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ goto nofail_alloc;
+ }
+ }
+@@ -1043,7 +1114,7 @@ rebalance:
+ do_retry = 1;
+ }
+ if (do_retry) {
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ goto rebalance;
+ }
+
+@@ -1083,7 +1154,7 @@ fastcall unsigned long get_zeroed_page(g
+ * get_zeroed_page() returns a 32-bit address, which cannot represent
+ * a highmem page
+ */
+- BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
++ VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
+
+ page = alloc_pages(gfp_mask | __GFP_ZERO, 0);
+ if (page)
+@@ -1116,7 +1187,7 @@ EXPORT_SYMBOL(__free_pages);
+ fastcall void free_pages(unsigned long addr, unsigned int order)
+ {
+ if (addr != 0) {
+- BUG_ON(!virt_addr_valid((void *)addr));
++ VM_BUG_ON(!virt_addr_valid((void *)addr));
+ __free_pages(virt_to_page((void *)addr), order);
+ }
+ }
+@@ -1142,7 +1213,8 @@ EXPORT_SYMBOL(nr_free_pages);
+ #ifdef CONFIG_NUMA
+ unsigned int nr_free_pages_pgdat(pg_data_t *pgdat)
+ {
+- unsigned int i, sum = 0;
++ unsigned int sum = 0;
++ enum zone_type i;
+
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ sum += pgdat->node_zones[i].free_pages;
+@@ -1187,27 +1259,11 @@ unsigned int nr_free_pagecache_pages(voi
+ return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER));
+ }
+
+-#ifdef CONFIG_HIGHMEM
+-unsigned int nr_free_highpages (void)
+-{
+- pg_data_t *pgdat;
+- unsigned int pages = 0;
+-
+- for_each_online_pgdat(pgdat)
+- pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages;
+-
+- return pages;
+-}
+-#endif
+-
+-#ifdef CONFIG_NUMA
+-static void show_node(struct zone *zone)
++static inline void show_node(struct zone *zone)
+ {
+- printk("Node %d ", zone->zone_pgdat->node_id);
++ if (NUMA_BUILD)
++ printk("Node %ld ", zone_to_nid(zone));
+ }
+-#else
+-#define show_node(zone) do { } while (0)
+-#endif
+
+ void si_meminfo(struct sysinfo *val)
+ {
+@@ -1215,13 +1271,8 @@ void si_meminfo(struct sysinfo *val)
+ val->sharedram = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = nr_blockdev_pages();
+-#ifdef CONFIG_HIGHMEM
+ val->totalhigh = totalhigh_pages;
+ val->freehigh = nr_free_highpages();
+-#else
+- val->totalhigh = 0;
+- val->freehigh = 0;
+-#endif
+ val->mem_unit = PAGE_SIZE;
+ }
+
+@@ -1234,8 +1285,13 @@ void si_meminfo_node(struct sysinfo *val
+
+ val->totalram = pgdat->node_present_pages;
+ val->freeram = nr_free_pages_pgdat(pgdat);
++#ifdef CONFIG_HIGHMEM
+ val->totalhigh = pgdat->node_zones[ZONE_HIGHMEM].present_pages;
+ val->freehigh = pgdat->node_zones[ZONE_HIGHMEM].free_pages;
++#else
++ val->totalhigh = 0;
++ val->freehigh = 0;
++#endif
+ val->mem_unit = PAGE_SIZE;
+ }
+ #endif
+@@ -1249,43 +1305,35 @@ void si_meminfo_node(struct sysinfo *val
+ */
+ void show_free_areas(void)
+ {
+- int cpu, temperature;
++ int cpu;
+ unsigned long active;
+ unsigned long inactive;
+ unsigned long free;
+ struct zone *zone;
+
+ for_each_zone(zone) {
+- show_node(zone);
+- printk("%s per-cpu:", zone->name);
+-
+- if (!populated_zone(zone)) {
+- printk(" empty\n");
++ if (!populated_zone(zone))
+ continue;
+- } else
+- printk("\n");
++
++ show_node(zone);
++ printk("%s per-cpu:\n", zone->name);
+
+ for_each_online_cpu(cpu) {
+ struct per_cpu_pageset *pageset;
+
+ pageset = zone_pcp(zone, cpu);
+
+- for (temperature = 0; temperature < 2; temperature++)
+- printk("cpu %d %s: high %d, batch %d used:%d\n",
+- cpu,
+- temperature ? "cold" : "hot",
+- pageset->pcp[temperature].high,
+- pageset->pcp[temperature].batch,
+- pageset->pcp[temperature].count);
++ printk("CPU %4d: Hot: hi:%5d, btch:%4d usd:%4d "
++ "Cold: hi:%5d, btch:%4d usd:%4d\n",
++ cpu, pageset->pcp[0].high,
++ pageset->pcp[0].batch, pageset->pcp[0].count,
++ pageset->pcp[1].high, pageset->pcp[1].batch,
++ pageset->pcp[1].count);
+ }
+ }
+
+ get_zone_counts(&active, &inactive, &free);
+
+- printk("Free pages: %11ukB (%ukB HighMem)\n",
+- K(nr_free_pages()),
+- K(nr_free_highpages()));
+-
+ printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu "
+ "unstable:%lu free:%u slab:%lu mapped:%lu pagetables:%lu\n",
+ active,
+@@ -1294,13 +1342,17 @@ void show_free_areas(void)
+ global_page_state(NR_WRITEBACK),
+ global_page_state(NR_UNSTABLE_NFS),
+ nr_free_pages(),
+- global_page_state(NR_SLAB),
++ global_page_state(NR_SLAB_RECLAIMABLE) +
++ global_page_state(NR_SLAB_UNRECLAIMABLE),
+ global_page_state(NR_FILE_MAPPED),
+ global_page_state(NR_PAGETABLE));
+
+ for_each_zone(zone) {
+ int i;
+
++ if (!populated_zone(zone))
++ continue;
++
+ show_node(zone);
+ printk("%s"
+ " free:%lukB"
+@@ -1333,12 +1385,11 @@ void show_free_areas(void)
+ for_each_zone(zone) {
+ unsigned long nr[MAX_ORDER], flags, order, total = 0;
+
++ if (!populated_zone(zone))
++ continue;
++
+ show_node(zone);
+ printk("%s: ", zone->name);
+- if (!populated_zone(zone)) {
+- printk("empty\n");
+- continue;
+- }
+
+ spin_lock_irqsave(&zone->lock, flags);
+ for (order = 0; order < MAX_ORDER; order++) {
+@@ -1360,39 +1411,25 @@ void show_free_areas(void)
+ * Add all populated zones of a node to the zonelist.
+ */
+ static int __meminit build_zonelists_node(pg_data_t *pgdat,
+- struct zonelist *zonelist, int nr_zones, int zone_type)
++ struct zonelist *zonelist, int nr_zones, enum zone_type zone_type)
+ {
+ struct zone *zone;
+
+- BUG_ON(zone_type > ZONE_HIGHMEM);
++ BUG_ON(zone_type >= MAX_NR_ZONES);
++ zone_type++;
+
+ do {
++ zone_type--;
+ zone = pgdat->node_zones + zone_type;
+ if (populated_zone(zone)) {
+-#ifndef CONFIG_HIGHMEM
+- BUG_ON(zone_type > ZONE_NORMAL);
+-#endif
+ zonelist->zones[nr_zones++] = zone;
+ check_highest_zone(zone_type);
+ }
+- zone_type--;
+
+- } while (zone_type >= 0);
++ } while (zone_type);
+ return nr_zones;
+ }
+
+-static inline int highest_zone(int zone_bits)
+-{
+- int res = ZONE_NORMAL;
+- if (zone_bits & (__force int)__GFP_HIGHMEM)
+- res = ZONE_HIGHMEM;
+- if (zone_bits & (__force int)__GFP_DMA32)
+- res = ZONE_DMA32;
+- if (zone_bits & (__force int)__GFP_DMA)
+- res = ZONE_DMA;
+- return res;
+-}
+-
+ #ifdef CONFIG_NUMA
+ #define MAX_NODE_LOAD (num_online_nodes())
+ static int __meminitdata node_load[MAX_NUMNODES];
+@@ -1458,13 +1495,14 @@ static int __meminit find_next_best_node
+
+ static void __meminit build_zonelists(pg_data_t *pgdat)
+ {
+- int i, j, k, node, local_node;
++ int j, node, local_node;
++ enum zone_type i;
+ int prev_node, load;
+ struct zonelist *zonelist;
+ nodemask_t used_mask;
+
+ /* initialize zonelists */
+- for (i = 0; i < GFP_ZONETYPES; i++) {
++ for (i = 0; i < MAX_NR_ZONES; i++) {
+ zonelist = pgdat->node_zonelists + i;
+ zonelist->zones[0] = NULL;
+ }
+@@ -1494,13 +1532,11 @@ static void __meminit build_zonelists(pg
+ node_load[node] += load;
+ prev_node = node;
+ load--;
+- for (i = 0; i < GFP_ZONETYPES; i++) {
++ for (i = 0; i < MAX_NR_ZONES; i++) {
+ zonelist = pgdat->node_zonelists + i;
+ for (j = 0; zonelist->zones[j] != NULL; j++);
+
+- k = highest_zone(i);
+-
+- j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
++ j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
+ zonelist->zones[j] = NULL;
+ }
+ }
+@@ -1510,17 +1546,16 @@ static void __meminit build_zonelists(pg
+
+ static void __meminit build_zonelists(pg_data_t *pgdat)
+ {
+- int i, j, k, node, local_node;
++ int node, local_node;
++ enum zone_type i,j;
+
+ local_node = pgdat->node_id;
+- for (i = 0; i < GFP_ZONETYPES; i++) {
++ for (i = 0; i < MAX_NR_ZONES; i++) {
+ struct zonelist *zonelist;
+
+ zonelist = pgdat->node_zonelists + i;
+
+- j = 0;
+- k = highest_zone(i);
+- j = build_zonelists_node(pgdat, zonelist, j, k);
++ j = build_zonelists_node(pgdat, zonelist, 0, i);
+ /*
+ * Now we build the zonelist so that it contains the zones
+ * of all the other nodes.
+@@ -1532,12 +1567,12 @@ static void __meminit build_zonelists(pg
+ for (node = local_node + 1; node < MAX_NUMNODES; node++) {
+ if (!node_online(node))
+ continue;
+- j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
++ j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
+ }
+ for (node = 0; node < local_node; node++) {
+ if (!node_online(node))
+ continue;
+- j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
++ j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
+ }
+
+ zonelist->zones[j] = NULL;
+@@ -1558,7 +1593,7 @@ static int __meminit __build_all_zonelis
+ void __meminit build_all_zonelists(void)
+ {
+ if (system_state == SYSTEM_BOOTING) {
+- __build_all_zonelists(0);
++ __build_all_zonelists(NULL);
+ cpuset_init_current_mems_allowed();
+ } else {
+ /* we have to stop all cpus to guaranntee there is no user
+@@ -1639,25 +1674,6 @@ static inline unsigned long wait_table_b
+
+ #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+-static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
+- unsigned long *zones_size, unsigned long *zholes_size)
+-{
+- unsigned long realtotalpages, totalpages = 0;
+- int i;
+-
+- for (i = 0; i < MAX_NR_ZONES; i++)
+- totalpages += zones_size[i];
+- pgdat->node_spanned_pages = totalpages;
+-
+- realtotalpages = totalpages;
+- if (zholes_size)
+- for (i = 0; i < MAX_NR_ZONES; i++)
+- realtotalpages -= zholes_size[i];
+- pgdat->node_present_pages = realtotalpages;
+- printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
+-}
+-
+-
+ /*
+ * Initially all pages are reserved - free ones are freed
+ * up by free_all_bootmem() once the early boot process is
+@@ -1673,6 +1689,8 @@ void __meminit memmap_init_zone(unsigned
+ for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+ if (!early_pfn_valid(pfn))
+ continue;
++ if (!early_pfn_in_nid(pfn, nid))
++ continue;
+ page = pfn_to_page(pfn);
+ set_page_links(page, zone, nid, pfn);
+ init_page_count(page);
+@@ -1698,8 +1716,8 @@ void zone_init_free_lists(struct pglist_
+ }
+
+ #define ZONETABLE_INDEX(x, zone_nr) ((x << ZONES_SHIFT) | zone_nr)
+-void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
+- unsigned long size)
++void zonetable_add(struct zone *zone, int nid, enum zone_type zid,
++ unsigned long pfn, unsigned long size)
+ {
+ unsigned long snum = pfn_to_section_nr(pfn);
+ unsigned long end = pfn_to_section_nr(pfn + size);
+@@ -1815,6 +1833,9 @@ static int __cpuinit process_zones(int c
+
+ for_each_zone(zone) {
+
++ if (!populated_zone(zone))
++ continue;
++
+ zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset),
+ GFP_KERNEL, cpu_to_node(cpu));
+ if (!zone_pcp(zone, cpu))
+@@ -1845,8 +1866,10 @@ static inline void free_zone_pagesets(in
+ for_each_zone(zone) {
+ struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
+
++ /* Free per_cpu_pageset if it is slab allocated */
++ if (pset != &boot_pageset[cpu])
++ kfree(pset);
+ zone_pcp(zone, cpu) = NULL;
+- kfree(pset);
+ }
+ }
+
+@@ -1972,6 +1995,349 @@ __meminit int init_currently_empty_zone(
+ return 0;
+ }
+
++#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
++/*
++ * Basic iterator support. Return the first range of PFNs for a node
++ * Note: nid == MAX_NUMNODES returns first region regardless of node
++ */
++static int __init first_active_region_index_in_nid(int nid)
++{
++ int i;
++
++ for (i = 0; i < nr_nodemap_entries; i++)
++ if (nid == MAX_NUMNODES || early_node_map[i].nid == nid)
++ return i;
++
++ return -1;
++}
++
++/*
++ * Basic iterator support. Return the next active range of PFNs for a node
++ * Note: nid == MAX_NUMNODES returns next region regardles of node
++ */
++static int __init next_active_region_index_in_nid(int index, int nid)
++{
++ for (index = index + 1; index < nr_nodemap_entries; index++)
++ if (nid == MAX_NUMNODES || early_node_map[index].nid == nid)
++ return index;
++
++ return -1;
++}
++
++#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
++/*
++ * Required by SPARSEMEM. Given a PFN, return what node the PFN is on.
++ * Architectures may implement their own version but if add_active_range()
++ * was used and there are no special requirements, this is a convenient
++ * alternative
++ */
++int __init early_pfn_to_nid(unsigned long pfn)
++{
++ int i;
++
++ for (i = 0; i < nr_nodemap_entries; i++) {
++ unsigned long start_pfn = early_node_map[i].start_pfn;
++ unsigned long end_pfn = early_node_map[i].end_pfn;
++
++ if (start_pfn <= pfn && pfn < end_pfn)
++ return early_node_map[i].nid;
++ }
++
++ return 0;
++}
++#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
++
++/* Basic iterator support to walk early_node_map[] */
++#define for_each_active_range_index_in_nid(i, nid) \
++ for (i = first_active_region_index_in_nid(nid); i != -1; \
++ i = next_active_region_index_in_nid(i, nid))
++
++/**
++ * free_bootmem_with_active_regions - Call free_bootmem_node for each active range
++ * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed.
++ * @max_low_pfn: The highest PFN that will be passed to free_bootmem_node
++ *
++ * If an architecture guarantees that all ranges registered with
++ * add_active_ranges() contain no holes and may be freed, this
++ * this function may be used instead of calling free_bootmem() manually.
++ */
++void __init free_bootmem_with_active_regions(int nid,
++ unsigned long max_low_pfn)
++{
++ int i;
++
++ for_each_active_range_index_in_nid(i, nid) {
++ unsigned long size_pages = 0;
++ unsigned long end_pfn = early_node_map[i].end_pfn;
++
++ if (early_node_map[i].start_pfn >= max_low_pfn)
++ continue;
++
++ if (end_pfn > max_low_pfn)
++ end_pfn = max_low_pfn;
++
++ size_pages = end_pfn - early_node_map[i].start_pfn;
++ free_bootmem_node(NODE_DATA(early_node_map[i].nid),
++ PFN_PHYS(early_node_map[i].start_pfn),
++ size_pages << PAGE_SHIFT);
++ }
++}
++
++/**
++ * sparse_memory_present_with_active_regions - Call memory_present for each active range
++ * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used.
++ *
++ * If an architecture guarantees that all ranges registered with
++ * add_active_ranges() contain no holes and may be freed, this
++ * function may be used instead of calling memory_present() manually.
++ */
++void __init sparse_memory_present_with_active_regions(int nid)
++{
++ int i;
++
++ for_each_active_range_index_in_nid(i, nid)
++ memory_present(early_node_map[i].nid,
++ early_node_map[i].start_pfn,
++ early_node_map[i].end_pfn);
++}
++
++/**
++ * push_node_boundaries - Push node boundaries to at least the requested boundary
++ * @nid: The nid of the node to push the boundary for
++ * @start_pfn: The start pfn of the node
++ * @end_pfn: The end pfn of the node
++ *
++ * In reserve-based hot-add, mem_map is allocated that is unused until hotadd
++ * time. Specifically, on x86_64, SRAT will report ranges that can potentially
++ * be hotplugged even though no physical memory exists. This function allows
++ * an arch to push out the node boundaries so mem_map is allocated that can
++ * be used later.
++ */
++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
++void __init push_node_boundaries(unsigned int nid,
++ unsigned long start_pfn, unsigned long end_pfn)
++{
++ printk(KERN_DEBUG "Entering push_node_boundaries(%u, %lu, %lu)\n",
++ nid, start_pfn, end_pfn);
++
++ /* Initialise the boundary for this node if necessary */
++ if (node_boundary_end_pfn[nid] == 0)
++ node_boundary_start_pfn[nid] = -1UL;
++
++ /* Update the boundaries */
++ if (node_boundary_start_pfn[nid] > start_pfn)
++ node_boundary_start_pfn[nid] = start_pfn;
++ if (node_boundary_end_pfn[nid] < end_pfn)
++ node_boundary_end_pfn[nid] = end_pfn;
++}
++
++/* If necessary, push the node boundary out for reserve hotadd */
++static void __init account_node_boundary(unsigned int nid,
++ unsigned long *start_pfn, unsigned long *end_pfn)
++{
++ printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n",
++ nid, *start_pfn, *end_pfn);
++
++ /* Return if boundary information has not been provided */
++ if (node_boundary_end_pfn[nid] == 0)
++ return;
++
++ /* Check the boundaries and update if necessary */
++ if (node_boundary_start_pfn[nid] < *start_pfn)
++ *start_pfn = node_boundary_start_pfn[nid];
++ if (node_boundary_end_pfn[nid] > *end_pfn)
++ *end_pfn = node_boundary_end_pfn[nid];
++}
++#else
++void __init push_node_boundaries(unsigned int nid,
++ unsigned long start_pfn, unsigned long end_pfn) {}
++
++static void __init account_node_boundary(unsigned int nid,
++ unsigned long *start_pfn, unsigned long *end_pfn) {}
++#endif
++
++
++/**
++ * get_pfn_range_for_nid - Return the start and end page frames for a node
++ * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
++ * @start_pfn: Passed by reference. On return, it will have the node start_pfn.
++ * @end_pfn: Passed by reference. On return, it will have the node end_pfn.
++ *
++ * It returns the start and end page frame of a node based on information
++ * provided by an arch calling add_active_range(). If called for a node
++ * with no available memory, a warning is printed and the start and end
++ * PFNs will be 0.
++ */
++void __init get_pfn_range_for_nid(unsigned int nid,
++ unsigned long *start_pfn, unsigned long *end_pfn)
++{
++ int i;
++ *start_pfn = -1UL;
++ *end_pfn = 0;
++
++ for_each_active_range_index_in_nid(i, nid) {
++ *start_pfn = min(*start_pfn, early_node_map[i].start_pfn);
++ *end_pfn = max(*end_pfn, early_node_map[i].end_pfn);
++ }
++
++ if (*start_pfn == -1UL) {
++ printk(KERN_WARNING "Node %u active with no memory\n", nid);
++ *start_pfn = 0;
++ }
++
++ /* Push the node boundaries out if requested */
++ account_node_boundary(nid, start_pfn, end_pfn);
++}
++
++/*
++ * Return the number of pages a zone spans in a node, including holes
++ * present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node()
++ */
++unsigned long __init zone_spanned_pages_in_node(int nid,
++ unsigned long zone_type,
++ unsigned long *ignored)
++{
++ unsigned long node_start_pfn, node_end_pfn;
++ unsigned long zone_start_pfn, zone_end_pfn;
++
++ /* Get the start and end of the node and zone */
++ get_pfn_range_for_nid(nid, &node_start_pfn, &node_end_pfn);
++ zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
++ zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
++
++ /* Check that this node has pages within the zone's required range */
++ if (zone_end_pfn < node_start_pfn || zone_start_pfn > node_end_pfn)
++ return 0;
++
++ /* Move the zone boundaries inside the node if necessary */
++ zone_end_pfn = min(zone_end_pfn, node_end_pfn);
++ zone_start_pfn = max(zone_start_pfn, node_start_pfn);
++
++ /* Return the spanned pages */
++ return zone_end_pfn - zone_start_pfn;
++}
++
++/*
++ * Return the number of holes in a range on a node. If nid is MAX_NUMNODES,
++ * then all holes in the requested range will be accounted for.
++ */
++unsigned long __init __absent_pages_in_range(int nid,
++ unsigned long range_start_pfn,
++ unsigned long range_end_pfn)
++{
++ int i = 0;
++ unsigned long prev_end_pfn = 0, hole_pages = 0;
++ unsigned long start_pfn;
++
++ /* Find the end_pfn of the first active range of pfns in the node */
++ i = first_active_region_index_in_nid(nid);
++ if (i == -1)
++ return 0;
++
++ /* Account for ranges before physical memory on this node */
++ if (early_node_map[i].start_pfn > range_start_pfn)
++ hole_pages = early_node_map[i].start_pfn - range_start_pfn;
++
++ prev_end_pfn = early_node_map[i].start_pfn;
++
++ /* Find all holes for the zone within the node */
++ for (; i != -1; i = next_active_region_index_in_nid(i, nid)) {
++
++ /* No need to continue if prev_end_pfn is outside the zone */
++ if (prev_end_pfn >= range_end_pfn)
++ break;
++
++ /* Make sure the end of the zone is not within the hole */
++ start_pfn = min(early_node_map[i].start_pfn, range_end_pfn);
++ prev_end_pfn = max(prev_end_pfn, range_start_pfn);
++
++ /* Update the hole size cound and move on */
++ if (start_pfn > range_start_pfn) {
++ BUG_ON(prev_end_pfn > start_pfn);
++ hole_pages += start_pfn - prev_end_pfn;
++ }
++ prev_end_pfn = early_node_map[i].end_pfn;
++ }
++
++ /* Account for ranges past physical memory on this node */
++ if (range_end_pfn > prev_end_pfn)
++ hole_pages += range_end_pfn -
++ max(range_start_pfn, prev_end_pfn);
++
++ return hole_pages;
++}
++
++/**
++ * absent_pages_in_range - Return number of page frames in holes within a range
++ * @start_pfn: The start PFN to start searching for holes
++ * @end_pfn: The end PFN to stop searching for holes
++ *
++ * It returns the number of pages frames in memory holes within a range.
++ */
++unsigned long __init absent_pages_in_range(unsigned long start_pfn,
++ unsigned long end_pfn)
++{
++ return __absent_pages_in_range(MAX_NUMNODES, start_pfn, end_pfn);
++}
++
++/* Return the number of page frames in holes in a zone on a node */
++unsigned long __init zone_absent_pages_in_node(int nid,
++ unsigned long zone_type,
++ unsigned long *ignored)
++{
++ unsigned long node_start_pfn, node_end_pfn;
++ unsigned long zone_start_pfn, zone_end_pfn;
++
++ get_pfn_range_for_nid(nid, &node_start_pfn, &node_end_pfn);
++ zone_start_pfn = max(arch_zone_lowest_possible_pfn[zone_type],
++ node_start_pfn);
++ zone_end_pfn = min(arch_zone_highest_possible_pfn[zone_type],
++ node_end_pfn);
++
++ return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn);
++}
++
++#else
++static inline unsigned long zone_spanned_pages_in_node(int nid,
++ unsigned long zone_type,
++ unsigned long *zones_size)
++{
++ return zones_size[zone_type];
++}
++
++static inline unsigned long zone_absent_pages_in_node(int nid,
++ unsigned long zone_type,
++ unsigned long *zholes_size)
++{
++ if (!zholes_size)
++ return 0;
++
++ return zholes_size[zone_type];
++}
++
++#endif
++
++static void __init calculate_node_totalpages(struct pglist_data *pgdat,
++ unsigned long *zones_size, unsigned long *zholes_size)
++{
++ unsigned long realtotalpages, totalpages = 0;
++ enum zone_type i;
++
++ for (i = 0; i < MAX_NR_ZONES; i++)
++ totalpages += zone_spanned_pages_in_node(pgdat->node_id, i,
++ zones_size);
++ pgdat->node_spanned_pages = totalpages;
++
++ realtotalpages = totalpages;
++ for (i = 0; i < MAX_NR_ZONES; i++)
++ realtotalpages -=
++ zone_absent_pages_in_node(pgdat->node_id, i,
++ zholes_size);
++ pgdat->node_present_pages = realtotalpages;
++ printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id,
++ realtotalpages);
++}
++
+ /*
+ * Set up the zone data structures:
+ * - mark all pages reserved
+@@ -1981,7 +2347,7 @@ __meminit int init_currently_empty_zone(
+ static void __meminit free_area_init_core(struct pglist_data *pgdat,
+ unsigned long *zones_size, unsigned long *zholes_size)
+ {
+- unsigned long j;
++ enum zone_type j;
+ int nid = pgdat->node_id;
+ unsigned long zone_start_pfn = pgdat->node_start_pfn;
+ int ret;
+@@ -1993,21 +2359,46 @@ static void __meminit free_area_init_cor
+
+ for (j = 0; j < MAX_NR_ZONES; j++) {
+ struct zone *zone = pgdat->node_zones + j;
+- unsigned long size, realsize;
++ unsigned long size, realsize, memmap_pages;
+
+- realsize = size = zones_size[j];
+- if (zholes_size)
+- realsize -= zholes_size[j];
++ size = zone_spanned_pages_in_node(nid, j, zones_size);
++ realsize = size - zone_absent_pages_in_node(nid, j,
++ zholes_size);
+
+- if (j < ZONE_HIGHMEM)
++ /*
++ * Adjust realsize so that it accounts for how much memory
++ * is used by this zone for memmap. This affects the watermark
++ * and per-cpu initialisations
++ */
++ memmap_pages = (size * sizeof(struct page)) >> PAGE_SHIFT;
++ if (realsize >= memmap_pages) {
++ realsize -= memmap_pages;
++ printk(KERN_DEBUG
++ " %s zone: %lu pages used for memmap\n",
++ zone_names[j], memmap_pages);
++ } else
++ printk(KERN_WARNING
++ " %s zone: %lu pages exceeds realsize %lu\n",
++ zone_names[j], memmap_pages, realsize);
++
++ /* Account for reserved DMA pages */
++ if (j == ZONE_DMA && realsize > dma_reserve) {
++ realsize -= dma_reserve;
++ printk(KERN_DEBUG " DMA zone: %lu pages reserved\n",
++ dma_reserve);
++ }
++
++ if (!is_highmem_idx(j))
+ nr_kernel_pages += realsize;
+ nr_all_pages += realsize;
+
+ zone->spanned_pages = size;
+ zone->present_pages = realsize;
+ #ifdef CONFIG_NUMA
+- zone->min_unmapped_ratio = (realsize*sysctl_min_unmapped_ratio)
++ zone->node = nid;
++ zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio)
+ / 100;
++ zone->min_slab_pages = (realsize * sysctl_min_slab_ratio) / 100;
+ #endif
+ zone->name = zone_names[j];
+ spin_lock_init(&zone->lock);
+@@ -2016,7 +2407,7 @@ static void __meminit free_area_init_cor
+ zone->zone_pgdat = pgdat;
+ zone->free_pages = 0;
+
+- zone->temp_priority = zone->prev_priority = DEF_PRIORITY;
++ zone->prev_priority = DEF_PRIORITY;
+
+ zone_pcp_init(zone);
+ INIT_LIST_HEAD(&zone->active_list);
+@@ -2067,8 +2458,13 @@ static void __init alloc_node_mem_map(st
+ /*
+ * With no DISCONTIG, the global mem_map is just set as node 0's
+ */
+- if (pgdat == NODE_DATA(0))
++ if (pgdat == NODE_DATA(0)) {
+ mem_map = NODE_DATA(0)->node_mem_map;
++#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
++ if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
++ mem_map -= pgdat->node_start_pfn;
++#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
++ }
+ #endif
+ #endif /* CONFIG_FLAT_NODE_MEM_MAP */
+ }
+@@ -2079,13 +2475,254 @@ void __meminit free_area_init_node(int n
+ {
+ pgdat->node_id = nid;
+ pgdat->node_start_pfn = node_start_pfn;
+- calculate_zone_totalpages(pgdat, zones_size, zholes_size);
++ calculate_node_totalpages(pgdat, zones_size, zholes_size);
+
+ alloc_node_mem_map(pgdat);
+
+ free_area_init_core(pgdat, zones_size, zholes_size);
+ }
+
++#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
++/**
++ * add_active_range - Register a range of PFNs backed by physical memory
++ * @nid: The node ID the range resides on
++ * @start_pfn: The start PFN of the available physical memory
++ * @end_pfn: The end PFN of the available physical memory
++ *
++ * These ranges are stored in an early_node_map[] and later used by
++ * free_area_init_nodes() to calculate zone sizes and holes. If the
++ * range spans a memory hole, it is up to the architecture to ensure
++ * the memory is not freed by the bootmem allocator. If possible
++ * the range being registered will be merged with existing ranges.
++ */
++void __init add_active_range(unsigned int nid, unsigned long start_pfn,
++ unsigned long end_pfn)
++{
++ int i;
++
++ printk(KERN_DEBUG "Entering add_active_range(%d, %lu, %lu) "
++ "%d entries of %d used\n",
++ nid, start_pfn, end_pfn,
++ nr_nodemap_entries, MAX_ACTIVE_REGIONS);
++
++ /* Merge with existing active regions if possible */
++ for (i = 0; i < nr_nodemap_entries; i++) {
++ if (early_node_map[i].nid != nid)
++ continue;
++
++ /* Skip if an existing region covers this new one */
++ if (start_pfn >= early_node_map[i].start_pfn &&
++ end_pfn <= early_node_map[i].end_pfn)
++ return;
++
++ /* Merge forward if suitable */
++ if (start_pfn <= early_node_map[i].end_pfn &&
++ end_pfn > early_node_map[i].end_pfn) {
++ early_node_map[i].end_pfn = end_pfn;
++ return;
++ }
++
++ /* Merge backward if suitable */
++ if (start_pfn < early_node_map[i].end_pfn &&
++ end_pfn >= early_node_map[i].start_pfn) {
++ early_node_map[i].start_pfn = start_pfn;
++ return;
++ }
++ }
++
++ /* Check that early_node_map is large enough */
++ if (i >= MAX_ACTIVE_REGIONS) {
++ printk(KERN_CRIT "More than %d memory regions, truncating\n",
++ MAX_ACTIVE_REGIONS);
++ return;
++ }
++
++ early_node_map[i].nid = nid;
++ early_node_map[i].start_pfn = start_pfn;
++ early_node_map[i].end_pfn = end_pfn;
++ nr_nodemap_entries = i + 1;
++}
++
++/**
++ * shrink_active_range - Shrink an existing registered range of PFNs
++ * @nid: The node id the range is on that should be shrunk
++ * @old_end_pfn: The old end PFN of the range
++ * @new_end_pfn: The new PFN of the range
++ *
++ * i386 with NUMA use alloc_remap() to store a node_mem_map on a local node.
++ * The map is kept at the end physical page range that has already been
++ * registered with add_active_range(). This function allows an arch to shrink
++ * an existing registered range.
++ */
++void __init shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
++ unsigned long new_end_pfn)
++{
++ int i;
++
++ /* Find the old active region end and shrink */
++ for_each_active_range_index_in_nid(i, nid)
++ if (early_node_map[i].end_pfn == old_end_pfn) {
++ early_node_map[i].end_pfn = new_end_pfn;
++ break;
++ }
++}
++
++/**
++ * remove_all_active_ranges - Remove all currently registered regions
++ *
++ * During discovery, it may be found that a table like SRAT is invalid
++ * and an alternative discovery method must be used. This function removes
++ * all currently registered regions.
++ */
++void __init remove_all_active_ranges(void)
++{
++ memset(early_node_map, 0, sizeof(early_node_map));
++ nr_nodemap_entries = 0;
++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
++ memset(node_boundary_start_pfn, 0, sizeof(node_boundary_start_pfn));
++ memset(node_boundary_end_pfn, 0, sizeof(node_boundary_end_pfn));
++#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
++}
++
++/* Compare two active node_active_regions */
++static int __init cmp_node_active_region(const void *a, const void *b)
++{
++ struct node_active_region *arange = (struct node_active_region *)a;
++ struct node_active_region *brange = (struct node_active_region *)b;
++
++ /* Done this way to avoid overflows */
++ if (arange->start_pfn > brange->start_pfn)
++ return 1;
++ if (arange->start_pfn < brange->start_pfn)
++ return -1;
++
++ return 0;
++}
++
++/* sort the node_map by start_pfn */
++static void __init sort_node_map(void)
++{
++ sort(early_node_map, (size_t)nr_nodemap_entries,
++ sizeof(struct node_active_region),
++ cmp_node_active_region, NULL);
++}
++
++/* Find the lowest pfn for a node. This depends on a sorted early_node_map */
++unsigned long __init find_min_pfn_for_node(unsigned long nid)
++{
++ int i;
++
++ /* Assuming a sorted map, the first range found has the starting pfn */
++ for_each_active_range_index_in_nid(i, nid)
++ return early_node_map[i].start_pfn;
++
++ printk(KERN_WARNING "Could not find start_pfn for node %lu\n", nid);
++ return 0;
++}
++
++/**
++ * find_min_pfn_with_active_regions - Find the minimum PFN registered
++ *
++ * It returns the minimum PFN based on information provided via
++ * add_active_range().
++ */
++unsigned long __init find_min_pfn_with_active_regions(void)
++{
++ return find_min_pfn_for_node(MAX_NUMNODES);
++}
++
++/**
++ * find_max_pfn_with_active_regions - Find the maximum PFN registered
++ *
++ * It returns the maximum PFN based on information provided via
++ * add_active_range().
++ */
++unsigned long __init find_max_pfn_with_active_regions(void)
++{
++ int i;
++ unsigned long max_pfn = 0;
++
++ for (i = 0; i < nr_nodemap_entries; i++)
++ max_pfn = max(max_pfn, early_node_map[i].end_pfn);
++
++ return max_pfn;
++}
++
++/**
++ * free_area_init_nodes - Initialise all pg_data_t and zone data
++ * @max_zone_pfn: an array of max PFNs for each zone
++ *
++ * This will call free_area_init_node() for each active node in the system.
++ * Using the page ranges provided by add_active_range(), the size of each
++ * zone in each node and their holes is calculated. If the maximum PFN
++ * between two adjacent zones match, it is assumed that the zone is empty.
++ * For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed
++ * that arch_max_dma32_pfn has no pages. It is also assumed that a zone
++ * starts where the previous one ended. For example, ZONE_DMA32 starts
++ * at arch_max_dma_pfn.
++ */
++void __init free_area_init_nodes(unsigned long *max_zone_pfn)
++{
++ unsigned long nid;
++ enum zone_type i;
++
++ /* Record where the zone boundaries are */
++ memset(arch_zone_lowest_possible_pfn, 0,
++ sizeof(arch_zone_lowest_possible_pfn));
++ memset(arch_zone_highest_possible_pfn, 0,
++ sizeof(arch_zone_highest_possible_pfn));
++ arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
++ arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
++ for (i = 1; i < MAX_NR_ZONES; i++) {
++ arch_zone_lowest_possible_pfn[i] =
++ arch_zone_highest_possible_pfn[i-1];
++ arch_zone_highest_possible_pfn[i] =
++ max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);
++ }
++
++ /* Regions in the early_node_map can be in any order */
++ sort_node_map();
++
++ /* Print out the zone ranges */
++ printk("Zone PFN ranges:\n");
++ for (i = 0; i < MAX_NR_ZONES; i++)
++ printk(" %-8s %8lu -> %8lu\n",
++ zone_names[i],
++ arch_zone_lowest_possible_pfn[i],
++ arch_zone_highest_possible_pfn[i]);
++
++ /* Print out the early_node_map[] */
++ printk("early_node_map[%d] active PFN ranges\n", nr_nodemap_entries);
++ for (i = 0; i < nr_nodemap_entries; i++)
++ printk(" %3d: %8lu -> %8lu\n", early_node_map[i].nid,
++ early_node_map[i].start_pfn,
++ early_node_map[i].end_pfn);
++
++ /* Initialise every node */
++ for_each_online_node(nid) {
++ pg_data_t *pgdat = NODE_DATA(nid);
++ free_area_init_node(nid, pgdat, NULL,
++ find_min_pfn_for_node(nid), NULL);
++ }
++}
++#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
++
++/**
++ * set_dma_reserve - set the specified number of pages reserved in the first zone
++ * @new_dma_reserve: The number of pages to mark reserved
++ *
++ * The per-cpu batchsize and zone watermarks are determined by present_pages.
++ * In the DMA zone, a significant percentage may be consumed by kernel image
++ * and other unfreeable allocations which can skew the watermarks badly. This
++ * function may optionally be used to account for unfreeable pages in the
++ * first zone (e.g., ZONE_DMA). The effect will be lower watermarks and
++ * smaller per-cpu batchsize.
++ */
++void __init set_dma_reserve(unsigned long new_dma_reserve)
++{
++ dma_reserve = new_dma_reserve;
++}
++
+ #ifndef CONFIG_NEED_MULTIPLE_NODES
+ static bootmem_data_t contig_bootmem_data;
+ struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data };
+@@ -2129,7 +2766,7 @@ static void calculate_totalreserve_pages
+ {
+ struct pglist_data *pgdat;
+ unsigned long reserve_pages = 0;
+- int i, j;
++ enum zone_type i, j;
+
+ for_each_online_pgdat(pgdat) {
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+@@ -2162,7 +2799,7 @@ static void calculate_totalreserve_pages
+ static void setup_per_zone_lowmem_reserve(void)
+ {
+ struct pglist_data *pgdat;
+- int j, idx;
++ enum zone_type j, idx;
+
+ for_each_online_pgdat(pgdat) {
+ for (j = 0; j < MAX_NR_ZONES; j++) {
+@@ -2171,9 +2808,12 @@ static void setup_per_zone_lowmem_reserv
+
+ zone->lowmem_reserve[j] = 0;
+
+- for (idx = j-1; idx >= 0; idx--) {
++ idx = j;
++ while (idx) {
+ struct zone *lower_zone;
+
++ idx--;
++
+ if (sysctl_lowmem_reserve_ratio[idx] < 1)
+ sysctl_lowmem_reserve_ratio[idx] = 1;
+
+@@ -2189,10 +2829,11 @@ static void setup_per_zone_lowmem_reserv
+ calculate_totalreserve_pages();
+ }
+
+-/*
+- * setup_per_zone_pages_min - called when min_free_kbytes changes. Ensures
+- * that the pages_{min,low,high} values for each zone are set correctly
+- * with respect to min_free_kbytes.
++/**
++ * setup_per_zone_pages_min - called when min_free_kbytes changes.
++ *
++ * Ensures that the pages_{min,low,high} values for each zone are set correctly
++ * with respect to min_free_kbytes.
+ */
+ void setup_per_zone_pages_min(void)
+ {
+@@ -2314,10 +2955,26 @@ int sysctl_min_unmapped_ratio_sysctl_han
+ return rc;
+
+ for_each_zone(zone)
+- zone->min_unmapped_ratio = (zone->present_pages *
++ zone->min_unmapped_pages = (zone->present_pages *
+ sysctl_min_unmapped_ratio) / 100;
+ return 0;
+ }
++
++int sysctl_min_slab_ratio_sysctl_handler(ctl_table *table, int write,
++ struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
++{
++ struct zone *zone;
++ int rc;
++
++ rc = proc_dointvec_minmax(table, write, file, buffer, length, ppos);
++ if (rc)
++ return rc;
++
++ for_each_zone(zone)
++ zone->min_slab_pages = (zone->present_pages *
++ sysctl_min_slab_ratio) / 100;
++ return 0;
++}
+ #endif
+
+ /*
+@@ -2363,7 +3020,7 @@ int percpu_pagelist_fraction_sysctl_hand
+ return 0;
+ }
+
+-__initdata int hashdist = HASHDIST_DEFAULT;
++int hashdist = HASHDIST_DEFAULT;
+
+ #ifdef CONFIG_NUMA
+ static int __init set_hashdist(char *str)
+@@ -2465,3 +3122,19 @@ unsigned long page_to_pfn(struct page *p
+ EXPORT_SYMBOL(pfn_to_page);
+ EXPORT_SYMBOL(page_to_pfn);
+ #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
++
++#if MAX_NUMNODES > 1
++/*
++ * Find the highest possible node id.
++ */
++int highest_possible_node_id(void)
++{
++ unsigned int node;
++ unsigned int highest = 0;
++
++ for_each_node_mask(node, node_possible_map)
++ highest = node;
++ return highest;
++}
++EXPORT_SYMBOL(highest_possible_node_id);
++#endif
+diff --git a/mm/page_io.c b/mm/page_io.c
+index 8802994..d4840ec 100644
+--- a/mm/page_io.c
++++ b/mm/page_io.c
+@@ -52,14 +52,29 @@ static int end_swap_bio_write(struct bio
+ if (bio->bi_size)
+ return 1;
+
+- if (!uptodate)
++ if (!uptodate) {
+ SetPageError(page);
++ /*
++ * We failed to write the page out to swap-space.
++ * Re-dirty the page in order to avoid it being reclaimed.
++ * Also print a dire warning that things will go BAD (tm)
++ * very quickly.
++ *
++ * Also clear PG_reclaim to avoid rotate_reclaimable_page()
++ */
++ set_page_dirty(page);
++ printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
++ imajor(bio->bi_bdev->bd_inode),
++ iminor(bio->bi_bdev->bd_inode),
++ (unsigned long long)bio->bi_sector);
++ ClearPageReclaim(page);
++ }
+ end_page_writeback(page);
+ bio_put(bio);
+ return 0;
+ }
+
+-static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err)
++int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err)
+ {
+ const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ struct page *page = bio->bi_io_vec[0].bv_page;
+@@ -70,6 +85,10 @@ static int end_swap_bio_read(struct bio
+ if (!uptodate) {
+ SetPageError(page);
+ ClearPageUptodate(page);
++ printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n",
++ imajor(bio->bi_bdev->bd_inode),
++ iminor(bio->bi_bdev->bd_inode),
++ (unsigned long long)bio->bi_sector);
+ } else {
+ SetPageUptodate(page);
+ }
+@@ -137,10 +156,12 @@ out:
+ * We use end_swap_bio_read() even for writes, because it happens to do what
+ * we want.
+ */
+-int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page)
++int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page,
++ struct bio **bio_chain)
+ {
+ struct bio *bio;
+ int ret = 0;
++ int bio_rw;
+
+ lock_page(page);
+
+@@ -151,11 +172,22 @@ int rw_swap_page_sync(int rw, swp_entry_
+ goto out;
+ }
+
+- submit_bio(rw | (1 << BIO_RW_SYNC), bio);
+- wait_on_page_locked(page);
+-
+- if (!PageUptodate(page) || PageError(page))
+- ret = -EIO;
++ bio_rw = rw;
++ if (!bio_chain)
++ bio_rw |= (1 << BIO_RW_SYNC);
++ if (bio_chain)
++ bio_get(bio);
++ submit_bio(bio_rw, bio);
++ if (bio_chain == NULL) {
++ wait_on_page_locked(page);
++
++ if (!PageUptodate(page) || PageError(page))
++ ret = -EIO;
++ }
++ if (bio_chain) {
++ bio->bi_private = *bio_chain;
++ *bio_chain = bio;
++ }
+ out:
+ return ret;
+ }
+diff --git a/mm/readahead.c b/mm/readahead.c
+index aa7ec42..23cb61a 100644
+--- a/mm/readahead.c
++++ b/mm/readahead.c
+@@ -38,6 +38,7 @@ file_ra_state_init(struct file_ra_state
+ ra->ra_pages = mapping->backing_dev_info->ra_pages;
+ ra->prev_page = -1;
+ }
++EXPORT_SYMBOL_GPL(file_ra_state_init);
+
+ /*
+ * Return max readahead size for this inode in number-of-pages.
+@@ -172,6 +173,8 @@ static int read_pages(struct address_spa
+
+ if (mapping->a_ops->readpages) {
+ ret = mapping->a_ops->readpages(filp, mapping, pages, nr_pages);
++ /* Clean up the remaining pages */
++ put_pages_list(pages);
+ goto out;
+ }
+
+diff --git a/mm/rmap.c b/mm/rmap.c
+index 40158b5..d8a842a 100644
+--- a/mm/rmap.c
++++ b/mm/rmap.c
+@@ -21,27 +21,21 @@
+ * Lock ordering in mm:
+ *
+ * inode->i_mutex (while writing or truncating, not reading or faulting)
+- * inode->i_alloc_sem
+- *
+- * When a page fault occurs in writing from user to file, down_read
+- * of mmap_sem nests within i_mutex; in sys_msync, i_mutex nests within
+- * down_read of mmap_sem; i_mutex and down_write of mmap_sem are never
+- * taken together; in truncation, i_mutex is taken outermost.
+- *
+- * mm->mmap_sem
+- * page->flags PG_locked (lock_page)
+- * mapping->i_mmap_lock
+- * anon_vma->lock
+- * mm->page_table_lock or pte_lock
+- * zone->lru_lock (in mark_page_accessed, isolate_lru_page)
+- * swap_lock (in swap_duplicate, swap_info_get)
+- * mmlist_lock (in mmput, drain_mmlist and others)
+- * mapping->private_lock (in __set_page_dirty_buffers)
+- * inode_lock (in set_page_dirty's __mark_inode_dirty)
+- * sb_lock (within inode_lock in fs/fs-writeback.c)
+- * mapping->tree_lock (widely used, in set_page_dirty,
+- * in arch-dependent flush_dcache_mmap_lock,
+- * within inode_lock in __sync_single_inode)
++ * inode->i_alloc_sem (vmtruncate_range)
++ * mm->mmap_sem
++ * page->flags PG_locked (lock_page)
++ * mapping->i_mmap_lock
++ * anon_vma->lock
++ * mm->page_table_lock or pte_lock
++ * zone->lru_lock (in mark_page_accessed, isolate_lru_page)
++ * swap_lock (in swap_duplicate, swap_info_get)
++ * mmlist_lock (in mmput, drain_mmlist and others)
++ * mapping->private_lock (in __set_page_dirty_buffers)
++ * inode_lock (in set_page_dirty's __mark_inode_dirty)
++ * sb_lock (within inode_lock in fs/fs-writeback.c)
++ * mapping->tree_lock (widely used, in set_page_dirty,
++ * in arch-dependent flush_dcache_mmap_lock,
++ * within inode_lock in __sync_single_inode)
+ */
+
+ #include <linux/mm.h>
+@@ -434,6 +428,71 @@ int page_referenced(struct page *page, i
+ return referenced;
+ }
+
++static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
++{
++ struct mm_struct *mm = vma->vm_mm;
++ unsigned long address;
++ pte_t *pte, entry;
++ spinlock_t *ptl;
++ int ret = 0;
++
++ address = vma_address(page, vma);
++ if (address == -EFAULT)
++ goto out;
++
++ pte = page_check_address(page, mm, address, &ptl);
++ if (!pte)
++ goto out;
++
++ if (!pte_dirty(*pte) && !pte_write(*pte))
++ goto unlock;
++
++ entry = ptep_get_and_clear(mm, address, pte);
++ entry = pte_mkclean(entry);
++ entry = pte_wrprotect(entry);
++ ptep_establish(vma, address, pte, entry);
++ lazy_mmu_prot_update(entry);
++ ret = 1;
++
++unlock:
++ pte_unmap_unlock(pte, ptl);
++out:
++ return ret;
++}
++
++static int page_mkclean_file(struct address_space *mapping, struct page *page)
++{
++ pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
++ struct vm_area_struct *vma;
++ struct prio_tree_iter iter;
++ int ret = 0;
++
++ BUG_ON(PageAnon(page));
++
++ spin_lock(&mapping->i_mmap_lock);
++ vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
++ if (vma->vm_flags & VM_SHARED)
++ ret += page_mkclean_one(page, vma);
++ }
++ spin_unlock(&mapping->i_mmap_lock);
++ return ret;
++}
++
++int page_mkclean(struct page *page)
++{
++ int ret = 0;
++
++ BUG_ON(!PageLocked(page));
++
++ if (page_mapped(page)) {
++ struct address_space *mapping = page_mapping(page);
++ if (mapping)
++ ret = page_mkclean_file(mapping, page);
++ }
++
++ return ret;
++}
++
+ /**
+ * page_set_anon_rmap - setup new anonymous rmap
+ * @page: the page to add the mapping to
+@@ -511,15 +570,14 @@ void page_add_file_rmap(struct page *pag
+ void page_remove_rmap(struct page *page)
+ {
+ if (atomic_add_negative(-1, &page->_mapcount)) {
+-#ifdef CONFIG_DEBUG_VM
+ if (unlikely(page_mapcount(page) < 0)) {
+ printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page));
+ printk (KERN_EMERG " page->flags = %lx\n", page->flags);
+ printk (KERN_EMERG " page->count = %x\n", page_count(page));
+ printk (KERN_EMERG " page->mapping = %p\n", page->mapping);
++ BUG();
+ }
+-#endif
+- BUG_ON(page_mapcount(page) < 0);
++
+ /*
+ * It would be tidy to reset the PageAnon mapping here,
+ * but that might overwrite a racing page_add_anon_rmap
+diff --git a/mm/shmem.c b/mm/shmem.c
+index db21c51..4959535 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -26,6 +26,8 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/fs.h>
++#include <linux/xattr.h>
++#include <linux/generic_acl.h>
+ #include <linux/mm.h>
+ #include <linux/mman.h>
+ #include <linux/file.h>
+@@ -45,6 +47,8 @@
+ #include <linux/namei.h>
+ #include <linux/ctype.h>
+ #include <linux/migrate.h>
++#include <linux/highmem.h>
++#include <linux/backing-dev.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/div64.h>
+@@ -176,6 +180,7 @@ static const struct address_space_operat
+ static struct file_operations shmem_file_operations;
+ static struct inode_operations shmem_inode_operations;
+ static struct inode_operations shmem_dir_inode_operations;
++static struct inode_operations shmem_special_inode_operations;
+ static struct vm_operations_struct shmem_vm_ops;
+
+ static struct backing_dev_info shmem_backing_dev_info __read_mostly = {
+@@ -636,7 +641,7 @@ static int shmem_notify_change(struct de
+ struct page *page = NULL;
+ int error;
+
+- if (attr->ia_valid & ATTR_SIZE) {
++ if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
+ if (attr->ia_size < inode->i_size) {
+ /*
+ * If truncating down to a partial page, then
+@@ -669,6 +674,10 @@ static int shmem_notify_change(struct de
+ error = inode_change_ok(inode, attr);
+ if (!error)
+ error = inode_setattr(inode, attr);
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ if (!error && (attr->ia_valid & ATTR_MODE))
++ error = generic_acl_chmod(inode, &shmem_acl_ops);
++#endif
+ if (page)
+ page_cache_release(page);
+ return error;
+@@ -1123,7 +1132,7 @@ repeat:
+ page_cache_release(swappage);
+ if (error == -ENOMEM) {
+ /* let kswapd refresh zone for GFP_ATOMICs */
+- blk_congestion_wait(WRITE, HZ/50);
++ congestion_wait(WRITE, HZ/50);
+ }
+ goto repeat;
+ }
+@@ -1350,11 +1359,11 @@ shmem_get_inode(struct super_block *sb,
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->a_ops = &shmem_aops;
+ inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
++ inode->i_generation = get_seconds();
+ info = SHMEM_I(inode);
+ memset(info, 0, (char *)inode - (char *)info);
+ spin_lock_init(&info->lock);
+@@ -1362,6 +1371,7 @@ shmem_get_inode(struct super_block *sb,
+
+ switch (mode & S_IFMT) {
+ default:
++ inode->i_op = &shmem_special_inode_operations;
+ init_special_inode(inode, mode, dev);
+ break;
+ case S_IFREG:
+@@ -1371,7 +1381,7 @@ shmem_get_inode(struct super_block *sb,
+ &sbinfo->policy_nodes);
+ break;
+ case S_IFDIR:
+- inode->i_nlink++;
++ inc_nlink(inode);
+ /* Some things misbehave if size == 0 on a directory */
+ inode->i_size = 2 * BOGO_DIRENT_SIZE;
+ inode->i_op = &shmem_dir_inode_operations;
+@@ -1682,7 +1692,11 @@ shmem_mknod(struct inode *dir, struct de
+ iput(inode);
+ return error;
+ }
+- error = 0;
++ }
++ error = shmem_acl_init(inode, dir);
++ if (error) {
++ iput(inode);
++ return error;
+ }
+ if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+@@ -1703,7 +1717,7 @@ static int shmem_mkdir(struct inode *dir
+
+ if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
+ return error;
+- dir->i_nlink++;
++ inc_nlink(dir);
+ return 0;
+ }
+
+@@ -1738,7 +1752,7 @@ static int shmem_link(struct dentry *old
+
+ dir->i_size += BOGO_DIRENT_SIZE;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+- inode->i_nlink++;
++ inc_nlink(inode);
+ atomic_inc(&inode->i_count); /* New dentry reference */
+ dget(dentry); /* Extra pinning count for the created dentry */
+ d_instantiate(dentry, inode);
+@@ -1760,7 +1774,7 @@ static int shmem_unlink(struct inode *di
+
+ dir->i_size -= BOGO_DIRENT_SIZE;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+- inode->i_nlink--;
++ drop_nlink(inode);
+ dput(dentry); /* Undo the count from "create" - this does all the work */
+ return 0;
+ }
+@@ -1770,8 +1784,8 @@ static int shmem_rmdir(struct inode *dir
+ if (!simple_empty(dentry))
+ return -ENOTEMPTY;
+
+- dentry->d_inode->i_nlink--;
+- dir->i_nlink--;
++ drop_nlink(dentry->d_inode);
++ drop_nlink(dir);
+ return shmem_unlink(dir, dentry);
+ }
+
+@@ -1792,10 +1806,10 @@ static int shmem_rename(struct inode *ol
+ if (new_dentry->d_inode) {
+ (void) shmem_unlink(new_dir, new_dentry);
+ if (they_are_dirs)
+- old_dir->i_nlink--;
++ drop_nlink(old_dir);
+ } else if (they_are_dirs) {
+- old_dir->i_nlink--;
+- new_dir->i_nlink++;
++ drop_nlink(old_dir);
++ inc_nlink(new_dir);
+ }
+
+ old_dir->i_size -= BOGO_DIRENT_SIZE;
+@@ -1897,6 +1911,132 @@ static struct inode_operations shmem_sym
+ .put_link = shmem_put_link,
+ };
+
++#ifdef CONFIG_TMPFS_POSIX_ACL
++/**
++ * Superblocks without xattr inode operations will get security.* xattr
++ * support from the VFS "for free". As soon as we have any other xattrs
++ * like ACLs, we also need to implement the security.* handlers at
++ * filesystem level, though.
++ */
++
++static size_t shmem_xattr_security_list(struct inode *inode, char *list,
++ size_t list_len, const char *name,
++ size_t name_len)
++{
++ return security_inode_listsecurity(inode, list, list_len);
++}
++
++static int shmem_xattr_security_get(struct inode *inode, const char *name,
++ void *buffer, size_t size)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ return security_inode_getsecurity(inode, name, buffer, size,
++ -EOPNOTSUPP);
++}
++
++static int shmem_xattr_security_set(struct inode *inode, const char *name,
++ const void *value, size_t size, int flags)
++{
++ if (strcmp(name, "") == 0)
++ return -EINVAL;
++ return security_inode_setsecurity(inode, name, value, size, flags);
++}
++
++struct xattr_handler shmem_xattr_security_handler = {
++ .prefix = XATTR_SECURITY_PREFIX,
++ .list = shmem_xattr_security_list,
++ .get = shmem_xattr_security_get,
++ .set = shmem_xattr_security_set,
++};
++
++static struct xattr_handler *shmem_xattr_handlers[] = {
++ &shmem_xattr_acl_access_handler,
++ &shmem_xattr_acl_default_handler,
++ &shmem_xattr_security_handler,
++ NULL
++};
++#endif
++
++static struct dentry *shmem_get_parent(struct dentry *child)
++{
++ return ERR_PTR(-ESTALE);
++}
++
++static int shmem_match(struct inode *ino, void *vfh)
++{
++ __u32 *fh = vfh;
++ __u64 inum = fh[2];
++ inum = (inum << 32) | fh[1];
++ return ino->i_ino == inum && fh[0] == ino->i_generation;
++}
++
++static struct dentry *shmem_get_dentry(struct super_block *sb, void *vfh)
++{
++ struct dentry *de = NULL;
++ struct inode *inode;
++ __u32 *fh = vfh;
++ __u64 inum = fh[2];
++ inum = (inum << 32) | fh[1];
++
++ inode = ilookup5(sb, (unsigned long)(inum+fh[0]), shmem_match, vfh);
++ if (inode) {
++ de = d_find_alias(inode);
++ iput(inode);
++ }
++
++ return de? de: ERR_PTR(-ESTALE);
++}
++
++static struct dentry *shmem_decode_fh(struct super_block *sb, __u32 *fh,
++ int len, int type,
++ int (*acceptable)(void *context, struct dentry *de),
++ void *context)
++{
++ if (len < 3)
++ return ERR_PTR(-ESTALE);
++
++ return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable,
++ context);
++}
++
++static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
++ int connectable)
++{
++ struct inode *inode = dentry->d_inode;
++
++ if (*len < 3)
++ return 255;
++
++ if (hlist_unhashed(&inode->i_hash)) {
++ /* Unfortunately insert_inode_hash is not idempotent,
++ * so as we hash inodes here rather than at creation
++ * time, we need a lock to ensure we only try
++ * to do it once
++ */
++ static DEFINE_SPINLOCK(lock);
++ spin_lock(&lock);
++ if (hlist_unhashed(&inode->i_hash))
++ __insert_inode_hash(inode,
++ inode->i_ino + inode->i_generation);
++ spin_unlock(&lock);
++ }
++
++ fh[0] = inode->i_generation;
++ fh[1] = inode->i_ino;
++ fh[2] = ((__u64)inode->i_ino) >> 32;
++
++ *len = 3;
++ return 1;
++}
++
++static struct export_operations shmem_export_ops = {
++ .get_parent = shmem_get_parent,
++ .get_dentry = shmem_get_dentry,
++ .encode_fh = shmem_encode_fh,
++ .decode_fh = shmem_decode_fh,
++};
++
+ static int shmem_parse_options(char *options, int *mode, uid_t *uid,
+ gid_t *gid, unsigned long *blocks, unsigned long *inodes,
+ int *policy, nodemask_t *policy_nodes)
+@@ -2069,6 +2209,7 @@ static int shmem_fill_super(struct super
+ &inodes, &policy, &policy_nodes))
+ return -EINVAL;
+ }
++ sb->s_export_op = &shmem_export_ops;
+ #else
+ sb->s_flags |= MS_NOUSER;
+ #endif
+@@ -2094,6 +2235,10 @@ static int shmem_fill_super(struct super
+ sb->s_magic = TMPFS_MAGIC;
+ sb->s_op = &shmem_ops;
+ sb->s_time_gran = 1;
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ sb->s_xattr = shmem_xattr_handlers;
++ sb->s_flags |= MS_POSIXACL;
++#endif
+
+ inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
+ if (!inode)
+@@ -2130,6 +2275,7 @@ static void shmem_destroy_inode(struct i
+ /* only struct inode is valid if it's an inline symlink */
+ mpol_free_shared_policy(&SHMEM_I(inode)->policy);
+ }
++ shmem_acl_destroy_inode(inode);
+ kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
+ }
+
+@@ -2141,6 +2287,10 @@ static void init_once(void *foo, struct
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ inode_init_once(&p->vfs_inode);
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ p->i_acl = NULL;
++ p->i_default_acl = NULL;
++#endif
+ }
+ }
+
+@@ -2156,8 +2306,7 @@ static int init_inodecache(void)
+
+ static void destroy_inodecache(void)
+ {
+- if (kmem_cache_destroy(shmem_inode_cachep))
+- printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n");
++ kmem_cache_destroy(shmem_inode_cachep);
+ }
+
+ static const struct address_space_operations shmem_aops = {
+@@ -2185,6 +2334,14 @@ static struct inode_operations shmem_ino
+ .truncate = shmem_truncate,
+ .setattr = shmem_notify_change,
+ .truncate_range = shmem_truncate_range,
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = generic_listxattr,
++ .removexattr = generic_removexattr,
++ .permission = shmem_permission,
++#endif
++
+ };
+
+ static struct inode_operations shmem_dir_inode_operations = {
+@@ -2199,6 +2356,25 @@ static struct inode_operations shmem_dir
+ .mknod = shmem_mknod,
+ .rename = shmem_rename,
+ #endif
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ .setattr = shmem_notify_change,
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = generic_listxattr,
++ .removexattr = generic_removexattr,
++ .permission = shmem_permission,
++#endif
++};
++
++static struct inode_operations shmem_special_inode_operations = {
++#ifdef CONFIG_TMPFS_POSIX_ACL
++ .setattr = shmem_notify_change,
++ .setxattr = generic_setxattr,
++ .getxattr = generic_getxattr,
++ .listxattr = generic_listxattr,
++ .removexattr = generic_removexattr,
++ .permission = shmem_permission,
++#endif
+ };
+
+ static struct super_operations shmem_ops = {
+diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c
+new file mode 100644
+index 0000000..f5664c5
+--- /dev/null
++++ b/mm/shmem_acl.c
+@@ -0,0 +1,197 @@
++/*
++ * mm/shmem_acl.c
++ *
++ * (C) 2005 Andreas Gruenbacher <agruen at suse.de>
++ *
++ * This file is released under the GPL.
++ */
++
++#include <linux/fs.h>
++#include <linux/shmem_fs.h>
++#include <linux/xattr.h>
++#include <linux/generic_acl.h>
++
++/**
++ * shmem_get_acl - generic_acl_operations->getacl() operation
++ */
++static struct posix_acl *
++shmem_get_acl(struct inode *inode, int type)
++{
++ struct posix_acl *acl = NULL;
++
++ spin_lock(&inode->i_lock);
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ acl = posix_acl_dup(SHMEM_I(inode)->i_acl);
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ acl = posix_acl_dup(SHMEM_I(inode)->i_default_acl);
++ break;
++ }
++ spin_unlock(&inode->i_lock);
++
++ return acl;
++}
++
++/**
++ * shmem_set_acl - generic_acl_operations->setacl() operation
++ */
++static void
++shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl)
++{
++ struct posix_acl *free = NULL;
++
++ spin_lock(&inode->i_lock);
++ switch(type) {
++ case ACL_TYPE_ACCESS:
++ free = SHMEM_I(inode)->i_acl;
++ SHMEM_I(inode)->i_acl = posix_acl_dup(acl);
++ break;
++
++ case ACL_TYPE_DEFAULT:
++ free = SHMEM_I(inode)->i_default_acl;
++ SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl);
++ break;
++ }
++ spin_unlock(&inode->i_lock);
++ posix_acl_release(free);
++}
++
++struct generic_acl_operations shmem_acl_ops = {
++ .getacl = shmem_get_acl,
++ .setacl = shmem_set_acl,
++};
++
++/**
++ * shmem_list_acl_access, shmem_get_acl_access, shmem_set_acl_access,
++ * shmem_xattr_acl_access_handler - plumbing code to implement the
++ * system.posix_acl_access xattr using the generic acl functions.
++ */
++
++static size_t
++shmem_list_acl_access(struct inode *inode, char *list, size_t list_size,
++ const char *name, size_t name_len)
++{
++ return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_ACCESS,
++ list, list_size);
++}
++
++static int
++shmem_get_acl_access(struct inode *inode, const char *name, void *buffer,
++ size_t size)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, buffer,
++ size);
++}
++
++static int
++shmem_set_acl_access(struct inode *inode, const char *name, const void *value,
++ size_t size, int flags)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value,
++ size);
++}
++
++struct xattr_handler shmem_xattr_acl_access_handler = {
++ .prefix = POSIX_ACL_XATTR_ACCESS,
++ .list = shmem_list_acl_access,
++ .get = shmem_get_acl_access,
++ .set = shmem_set_acl_access,
++};
++
++/**
++ * shmem_list_acl_default, shmem_get_acl_default, shmem_set_acl_default,
++ * shmem_xattr_acl_default_handler - plumbing code to implement the
++ * system.posix_acl_default xattr using the generic acl functions.
++ */
++
++static size_t
++shmem_list_acl_default(struct inode *inode, char *list, size_t list_size,
++ const char *name, size_t name_len)
++{
++ return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT,
++ list, list_size);
++}
++
++static int
++shmem_get_acl_default(struct inode *inode, const char *name, void *buffer,
++ size_t size)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer,
++ size);
++}
++
++static int
++shmem_set_acl_default(struct inode *inode, const char *name, const void *value,
++ size_t size, int flags)
++{
++ if (strcmp(name, "") != 0)
++ return -EINVAL;
++ return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, value,
++ size);
++}
++
++struct xattr_handler shmem_xattr_acl_default_handler = {
++ .prefix = POSIX_ACL_XATTR_DEFAULT,
++ .list = shmem_list_acl_default,
++ .get = shmem_get_acl_default,
++ .set = shmem_set_acl_default,
++};
++
++/**
++ * shmem_acl_init - Inizialize the acl(s) of a new inode
++ */
++int
++shmem_acl_init(struct inode *inode, struct inode *dir)
++{
++ return generic_acl_init(inode, dir, &shmem_acl_ops);
++}
++
++/**
++ * shmem_acl_destroy_inode - destroy acls hanging off the in-memory inode
++ *
++ * This is done before destroying the actual inode.
++ */
++
++void
++shmem_acl_destroy_inode(struct inode *inode)
++{
++ if (SHMEM_I(inode)->i_acl)
++ posix_acl_release(SHMEM_I(inode)->i_acl);
++ SHMEM_I(inode)->i_acl = NULL;
++ if (SHMEM_I(inode)->i_default_acl)
++ posix_acl_release(SHMEM_I(inode)->i_default_acl);
++ SHMEM_I(inode)->i_default_acl = NULL;
++}
++
++/**
++ * shmem_check_acl - check_acl() callback for generic_permission()
++ */
++static int
++shmem_check_acl(struct inode *inode, int mask)
++{
++ struct posix_acl *acl = shmem_get_acl(inode, ACL_TYPE_ACCESS);
++
++ if (acl) {
++ int error = posix_acl_permission(inode, acl, mask);
++ posix_acl_release(acl);
++ return error;
++ }
++ return -EAGAIN;
++}
++
++/**
++ * shmem_permission - permission() inode operation
++ */
++int
++shmem_permission(struct inode *inode, int mask, struct nameidata *nd)
++{
++ return generic_permission(inode, mask, shmem_check_acl);
++}
+diff --git a/mm/slab.c b/mm/slab.c
+index 21ba060..3c4a7e3 100644
+--- a/mm/slab.c
++++ b/mm/slab.c
+@@ -86,7 +86,6 @@
+ * All object allocations for a node occur from node specific slab lists.
+ */
+
+-#include <linux/config.h>
+ #include <linux/slab.h>
+ #include <linux/mm.h>
+ #include <linux/poison.h>
+@@ -313,7 +312,7 @@ static int drain_freelist(struct kmem_ca
+ struct kmem_list3 *l3, int tofree);
+ static void free_block(struct kmem_cache *cachep, void **objpp, int len,
+ int node);
+-static void enable_cpucache(struct kmem_cache *cachep);
++static int enable_cpucache(struct kmem_cache *cachep);
+ static void cache_reap(void *unused);
+
+ /*
+@@ -674,6 +673,8 @@ static struct kmem_cache cache_cache = {
+ #endif
+ };
+
++#define BAD_ALIEN_MAGIC 0x01020304ul
++
+ #ifdef CONFIG_LOCKDEP
+
+ /*
+@@ -682,42 +683,58 @@ static struct kmem_cache cache_cache = {
+ * The locking for this is tricky in that it nests within the locks
+ * of all other slabs in a few places; to deal with this special
+ * locking we put on-slab caches into a separate lock-class.
++ *
++ * We set lock class for alien array caches which are up during init.
++ * The lock annotation will be lost if all cpus of a node goes down and
++ * then comes back up during hotplug
+ */
+-static struct lock_class_key on_slab_key;
++static struct lock_class_key on_slab_l3_key;
++static struct lock_class_key on_slab_alc_key;
++
++static inline void init_lock_keys(void)
+
+-static inline void init_lock_keys(struct cache_sizes *s)
+ {
+ int q;
+-
+- for (q = 0; q < MAX_NUMNODES; q++) {
+- if (!s->cs_cachep->nodelists[q] || OFF_SLAB(s->cs_cachep))
+- continue;
+- lockdep_set_class(&s->cs_cachep->nodelists[q]->list_lock,
+- &on_slab_key);
++ struct cache_sizes *s = malloc_sizes;
++
++ while (s->cs_size != ULONG_MAX) {
++ for_each_node(q) {
++ struct array_cache **alc;
++ int r;
++ struct kmem_list3 *l3 = s->cs_cachep->nodelists[q];
++ if (!l3 || OFF_SLAB(s->cs_cachep))
++ continue;
++ lockdep_set_class(&l3->list_lock, &on_slab_l3_key);
++ alc = l3->alien;
++ /*
++ * FIXME: This check for BAD_ALIEN_MAGIC
++ * should go away when common slab code is taught to
++ * work even without alien caches.
++ * Currently, non NUMA code returns BAD_ALIEN_MAGIC
++ * for alloc_alien_cache,
++ */
++ if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
++ continue;
++ for_each_node(r) {
++ if (alc[r])
++ lockdep_set_class(&alc[r]->lock,
++ &on_slab_alc_key);
++ }
++ }
++ s++;
+ }
+ }
+-
+ #else
+-static inline void init_lock_keys(struct cache_sizes *s)
++static inline void init_lock_keys(void)
+ {
+ }
+ #endif
+
+-
+-
+ /* Guard access to the cache-chain. */
+ static DEFINE_MUTEX(cache_chain_mutex);
+ static struct list_head cache_chain;
+
+ /*
+- * vm_enough_memory() looks at this to determine how many slab-allocated pages
+- * are possibly freeable under pressure
+- *
+- * SLAB_RECLAIM_ACCOUNT turns this on per-slab
+- */
+-atomic_t slab_reclaim_pages;
+-
+-/*
+ * chicken and egg problem: delay the per-cpu array allocation
+ * until the general caches are up.
+ */
+@@ -768,11 +785,10 @@ static inline struct kmem_cache *__find_
+ return csizep->cs_cachep;
+ }
+
+-struct kmem_cache *kmem_find_general_cachep(size_t size, gfp_t gfpflags)
++static struct kmem_cache *kmem_find_general_cachep(size_t size, gfp_t gfpflags)
+ {
+ return __find_general_cachep(size, gfpflags);
+ }
+-EXPORT_SYMBOL(kmem_find_general_cachep);
+
+ static size_t slab_mgmt_size(size_t nr_objs, size_t align)
+ {
+@@ -867,7 +883,7 @@ static void init_reap_node(int cpu)
+ if (node == MAX_NUMNODES)
+ node = first_node(node_online_map);
+
+- __get_cpu_var(reap_node) = node;
++ per_cpu(reap_node, cpu) = node;
+ }
+
+ static void next_reap_node(void)
+@@ -955,7 +971,39 @@ static int transfer_objects(struct array
+ return nr;
+ }
+
+-#ifdef CONFIG_NUMA
++#ifndef CONFIG_NUMA
++
++#define drain_alien_cache(cachep, alien) do { } while (0)
++#define reap_alien(cachep, l3) do { } while (0)
++
++static inline struct array_cache **alloc_alien_cache(int node, int limit)
++{
++ return (struct array_cache **)BAD_ALIEN_MAGIC;
++}
++
++static inline void free_alien_cache(struct array_cache **ac_ptr)
++{
++}
++
++static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
++{
++ return 0;
++}
++
++static inline void *alternate_node_alloc(struct kmem_cache *cachep,
++ gfp_t flags)
++{
++ return NULL;
++}
++
++static inline void *__cache_alloc_node(struct kmem_cache *cachep,
++ gfp_t flags, int nodeid)
++{
++ return NULL;
++}
++
++#else /* CONFIG_NUMA */
++
+ static void *__cache_alloc_node(struct kmem_cache *, gfp_t, int);
+ static void *alternate_node_alloc(struct kmem_cache *, gfp_t);
+
+@@ -1058,15 +1106,18 @@ static inline int cache_free_alien(struc
+ int nodeid = slabp->nodeid;
+ struct kmem_list3 *l3;
+ struct array_cache *alien = NULL;
++ int node;
++
++ node = numa_node_id();
+
+ /*
+ * Make sure we are not freeing a object from another node to the array
+ * cache on this cpu.
+ */
+- if (likely(slabp->nodeid == numa_node_id()))
++ if (likely(slabp->nodeid == node))
+ return 0;
+
+- l3 = cachep->nodelists[numa_node_id()];
++ l3 = cachep->nodelists[node];
+ STATS_INC_NODEFREES(cachep);
+ if (l3->alien && l3->alien[nodeid]) {
+ alien = l3->alien[nodeid];
+@@ -1084,26 +1135,6 @@ static inline int cache_free_alien(struc
+ }
+ return 1;
+ }
+-
+-#else
+-
+-#define drain_alien_cache(cachep, alien) do { } while (0)
+-#define reap_alien(cachep, l3) do { } while (0)
+-
+-static inline struct array_cache **alloc_alien_cache(int node, int limit)
+-{
+- return (struct array_cache **) 0x01020304ul;
+-}
+-
+-static inline void free_alien_cache(struct array_cache **ac_ptr)
+-{
+-}
+-
+-static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
+-{
+- return 0;
+-}
+-
+ #endif
+
+ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
+@@ -1297,7 +1328,6 @@ static void init_list(struct kmem_cache
+ {
+ struct kmem_list3 *ptr;
+
+- BUG_ON(cachep->nodelists[nodeid] != list);
+ ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, nodeid);
+ BUG_ON(!ptr);
+
+@@ -1324,6 +1354,7 @@ void __init kmem_cache_init(void)
+ struct cache_names *names;
+ int i;
+ int order;
++ int node;
+
+ for (i = 0; i < NUM_INIT_LISTS; i++) {
+ kmem_list3_init(&initkmem_list3[i]);
+@@ -1358,12 +1389,14 @@ void __init kmem_cache_init(void)
+ * 6) Resize the head arrays of the kmalloc caches to their final sizes.
+ */
+
++ node = numa_node_id();
++
+ /* 1) create the cache_cache */
+ INIT_LIST_HEAD(&cache_chain);
+ list_add(&cache_cache.next, &cache_chain);
+ cache_cache.colour_off = cache_line_size();
+ cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
+- cache_cache.nodelists[numa_node_id()] = &initkmem_list3[CACHE_CACHE];
++ cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];
+
+ cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
+ cache_line_size());
+@@ -1422,7 +1455,6 @@ void __init kmem_cache_init(void)
+ ARCH_KMALLOC_FLAGS|SLAB_PANIC,
+ NULL, NULL);
+ }
+- init_lock_keys(sizes);
+
+ sizes->cs_dmacachep = kmem_cache_create(names->name_dma,
+ sizes->cs_size,
+@@ -1469,19 +1501,18 @@ void __init kmem_cache_init(void)
+ }
+ /* 5) Replace the bootstrap kmem_list3's */
+ {
+- int node;
++ int nid;
++
+ /* Replace the static kmem_list3 structures for the boot cpu */
+- init_list(&cache_cache, &initkmem_list3[CACHE_CACHE],
+- numa_node_id());
++ init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);
+
+- for_each_online_node(node) {
++ for_each_online_node(nid) {
+ init_list(malloc_sizes[INDEX_AC].cs_cachep,
+- &initkmem_list3[SIZE_AC + node], node);
++ &initkmem_list3[SIZE_AC + nid], nid);
+
+ if (INDEX_AC != INDEX_L3) {
+ init_list(malloc_sizes[INDEX_L3].cs_cachep,
+- &initkmem_list3[SIZE_L3 + node],
+- node);
++ &initkmem_list3[SIZE_L3 + nid], nid);
+ }
+ }
+ }
+@@ -1491,10 +1522,15 @@ void __init kmem_cache_init(void)
+ struct kmem_cache *cachep;
+ mutex_lock(&cache_chain_mutex);
+ list_for_each_entry(cachep, &cache_chain, next)
+- enable_cpucache(cachep);
++ if (enable_cpucache(cachep))
++ BUG();
+ mutex_unlock(&cache_chain_mutex);
+ }
+
++ /* Annotate slab for lockdep -- annotate the malloc caches */
++ init_lock_keys();
++
++
+ /* Done! */
+ g_cpucache_up = FULL;
+
+@@ -1543,7 +1579,13 @@ static void *kmem_getpages(struct kmem_c
+ */
+ flags |= __GFP_COMP;
+ #endif
+- flags |= cachep->gfpflags;
++
++ /*
++ * Under NUMA we want memory on the indicated node. We will handle
++ * the needed fallback ourselves since we want to serve from our
++ * per node object lists first for other nodes.
++ */
++ flags |= cachep->gfpflags | GFP_THISNODE;
+
+ page = alloc_pages_node(nodeid, flags, cachep->gfporder);
+ if (!page)
+@@ -1551,8 +1593,11 @@ static void *kmem_getpages(struct kmem_c
+
+ nr_pages = (1 << cachep->gfporder);
+ if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
+- atomic_add(nr_pages, &slab_reclaim_pages);
+- add_zone_page_state(page_zone(page), NR_SLAB, nr_pages);
++ add_zone_page_state(page_zone(page),
++ NR_SLAB_RECLAIMABLE, nr_pages);
++ else
++ add_zone_page_state(page_zone(page),
++ NR_SLAB_UNRECLAIMABLE, nr_pages);
+ for (i = 0; i < nr_pages; i++)
+ __SetPageSlab(page + i);
+ return page_address(page);
+@@ -1567,7 +1612,12 @@ static void kmem_freepages(struct kmem_c
+ struct page *page = virt_to_page(addr);
+ const unsigned long nr_freed = i;
+
+- sub_zone_page_state(page_zone(page), NR_SLAB, nr_freed);
++ if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
++ sub_zone_page_state(page_zone(page),
++ NR_SLAB_RECLAIMABLE, nr_freed);
++ else
++ sub_zone_page_state(page_zone(page),
++ NR_SLAB_UNRECLAIMABLE, nr_freed);
+ while (i--) {
+ BUG_ON(!PageSlab(page));
+ __ClearPageSlab(page);
+@@ -1576,8 +1626,6 @@ static void kmem_freepages(struct kmem_c
+ if (current->reclaim_state)
+ current->reclaim_state->reclaimed_slab += nr_freed;
+ free_pages((unsigned long)addr, cachep->gfporder);
+- if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
+- atomic_sub(1 << cachep->gfporder, &slab_reclaim_pages);
+ }
+
+ static void kmem_rcu_free(struct rcu_head *head)
+@@ -1638,10 +1686,32 @@ static void poison_obj(struct kmem_cache
+ static void dump_line(char *data, int offset, int limit)
+ {
+ int i;
++ unsigned char error = 0;
++ int bad_count = 0;
++
+ printk(KERN_ERR "%03x:", offset);
+- for (i = 0; i < limit; i++)
++ for (i = 0; i < limit; i++) {
++ if (data[offset + i] != POISON_FREE) {
++ error = data[offset + i];
++ bad_count++;
++ }
+ printk(" %02x", (unsigned char)data[offset + i]);
++ }
+ printk("\n");
++
++ if (bad_count == 1) {
++ error ^= POISON_FREE;
++ if (!(error & (error - 1))) {
++ printk(KERN_ERR "Single bit error detected. Probably "
++ "bad RAM.\n");
++#ifdef CONFIG_X86
++ printk(KERN_ERR "Run memtest86+ or a similar memory "
++ "test tool.\n");
++#else
++ printk(KERN_ERR "Run a memory test tool.\n");
++#endif
++ }
++ }
+ }
+ #endif
+
+@@ -1834,6 +1904,27 @@ static void set_up_list3s(struct kmem_ca
+ }
+ }
+
++static void __kmem_cache_destroy(struct kmem_cache *cachep)
++{
++ int i;
++ struct kmem_list3 *l3;
++
++ for_each_online_cpu(i)
++ kfree(cachep->array[i]);
++
++ /* NUMA: free the list3 structures */
++ for_each_online_node(i) {
++ l3 = cachep->nodelists[i];
++ if (l3) {
++ kfree(l3->shared);
++ free_alien_cache(l3->alien);
++ kfree(l3);
++ }
++ }
++ kmem_cache_free(&cache_cache, cachep);
++}
++
++
+ /**
+ * calculate_slab_order - calculate size (page order) of slabs
+ * @cachep: pointer to the cache that is being created
+@@ -1904,12 +1995,11 @@ static size_t calculate_slab_order(struc
+ return left_over;
+ }
+
+-static void setup_cpu_cache(struct kmem_cache *cachep)
++static int setup_cpu_cache(struct kmem_cache *cachep)
+ {
+- if (g_cpucache_up == FULL) {
+- enable_cpucache(cachep);
+- return;
+- }
++ if (g_cpucache_up == FULL)
++ return enable_cpucache(cachep);
++
+ if (g_cpucache_up == NONE) {
+ /*
+ * Note: the first kmem_cache_create must create the cache
+@@ -1956,6 +2046,7 @@ static void setup_cpu_cache(struct kmem_
+ cpu_cache_get(cachep)->touched = 0;
+ cachep->batchcount = 1;
+ cachep->limit = BOOT_CPUCACHE_ENTRIES;
++ return 0;
+ }
+
+ /**
+@@ -2097,6 +2188,15 @@ kmem_cache_create (const char *name, siz
+ } else {
+ ralign = BYTES_PER_WORD;
+ }
++
++ /*
++ * Redzoning and user store require word alignment. Note this will be
++ * overridden by architecture or caller mandated alignment if either
++ * is greater than BYTES_PER_WORD.
++ */
++ if (flags & SLAB_RED_ZONE || flags & SLAB_STORE_USER)
++ ralign = BYTES_PER_WORD;
++
+ /* 2) arch mandated alignment: disables debug if necessary */
+ if (ralign < ARCH_SLAB_MINALIGN) {
+ ralign = ARCH_SLAB_MINALIGN;
+@@ -2110,8 +2210,7 @@ kmem_cache_create (const char *name, siz
+ flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
+ }
+ /*
+- * 4) Store it. Note that the debug code below can reduce
+- * the alignment to BYTES_PER_WORD.
++ * 4) Store it.
+ */
+ align = ralign;
+
+@@ -2123,20 +2222,19 @@ kmem_cache_create (const char *name, siz
+ #if DEBUG
+ cachep->obj_size = size;
+
++ /*
++ * Both debugging options require word-alignment which is calculated
++ * into align above.
++ */
+ if (flags & SLAB_RED_ZONE) {
+- /* redzoning only works with word aligned caches */
+- align = BYTES_PER_WORD;
+-
+ /* add space for red zone words */
+ cachep->obj_offset += BYTES_PER_WORD;
+ size += 2 * BYTES_PER_WORD;
+ }
+ if (flags & SLAB_STORE_USER) {
+- /* user store requires word alignment and
+- * one word storage behind the end of the real
+- * object.
++ /* user store requires one word storage behind the end of
++ * the real object.
+ */
+- align = BYTES_PER_WORD;
+ size += BYTES_PER_WORD;
+ }
+ #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
+@@ -2200,14 +2298,26 @@ kmem_cache_create (const char *name, siz
+ cachep->gfpflags |= GFP_DMA;
+ cachep->buffer_size = size;
+
+- if (flags & CFLGS_OFF_SLAB)
++ if (flags & CFLGS_OFF_SLAB) {
+ cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u);
++ /*
++ * This is a possibility for one of the malloc_sizes caches.
++ * But since we go off slab only for object size greater than
++ * PAGE_SIZE/8, and malloc_sizes gets created in ascending order,
++ * this should not happen at all.
++ * But leave a BUG_ON for some lucky dude.
++ */
++ BUG_ON(!cachep->slabp_cache);
++ }
+ cachep->ctor = ctor;
+ cachep->dtor = dtor;
+ cachep->name = name;
+
+-
+- setup_cpu_cache(cachep);
++ if (setup_cpu_cache(cachep)) {
++ __kmem_cache_destroy(cachep);
++ cachep = NULL;
++ goto oops;
++ }
+
+ /* cache setup completed, link it into the list */
+ list_add(&cachep->next, &cache_chain);
+@@ -2375,7 +2485,6 @@ EXPORT_SYMBOL(kmem_cache_shrink);
+ * @cachep: the cache to destroy
+ *
+ * Remove a struct kmem_cache object from the slab cache.
+- * Returns 0 on success.
+ *
+ * It is expected this function will be called by a module when it is
+ * unloaded. This will remove the cache completely, and avoid a duplicate
+@@ -2387,11 +2496,8 @@ EXPORT_SYMBOL(kmem_cache_shrink);
+ * The caller must guarantee that noone will allocate memory from the cache
+ * during the kmem_cache_destroy().
+ */
+-int kmem_cache_destroy(struct kmem_cache *cachep)
++void kmem_cache_destroy(struct kmem_cache *cachep)
+ {
+- int i;
+- struct kmem_list3 *l3;
+-
+ BUG_ON(!cachep || in_interrupt());
+
+ /* Don't let CPUs to come and go */
+@@ -2411,31 +2517,28 @@ int kmem_cache_destroy(struct kmem_cache
+ list_add(&cachep->next, &cache_chain);
+ mutex_unlock(&cache_chain_mutex);
+ unlock_cpu_hotplug();
+- return 1;
++ return;
+ }
+
+ if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
+ synchronize_rcu();
+
+- for_each_online_cpu(i)
+- kfree(cachep->array[i]);
+-
+- /* NUMA: free the list3 structures */
+- for_each_online_node(i) {
+- l3 = cachep->nodelists[i];
+- if (l3) {
+- kfree(l3->shared);
+- free_alien_cache(l3->alien);
+- kfree(l3);
+- }
+- }
+- kmem_cache_free(&cache_cache, cachep);
++ __kmem_cache_destroy(cachep);
+ unlock_cpu_hotplug();
+- return 0;
+ }
+ EXPORT_SYMBOL(kmem_cache_destroy);
+
+-/* Get the memory for a slab management obj. */
++/*
++ * Get the memory for a slab management obj.
++ * For a slab cache when the slab descriptor is off-slab, slab descriptors
++ * always come from malloc_sizes caches. The slab descriptor cannot
++ * come from the same cache which is getting created because,
++ * when we are searching for an appropriate cache for these
++ * descriptors in kmem_cache_create, we search through the malloc_sizes array.
++ * If we are creating a malloc_sizes cache here it would not be visible to
++ * kmem_find_general_cachep till the initialization is complete.
++ * Hence we cannot have slabp_cache same as the original cache.
++ */
+ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp,
+ int colour_off, gfp_t local_flags,
+ int nodeid)
+@@ -2819,6 +2922,9 @@ static void *cache_alloc_refill(struct k
+ int batchcount;
+ struct kmem_list3 *l3;
+ struct array_cache *ac;
++ int node;
++
++ node = numa_node_id();
+
+ check_irq_off();
+ ac = cpu_cache_get(cachep);
+@@ -2832,7 +2938,7 @@ retry:
+ */
+ batchcount = BATCHREFILL_LIMIT;
+ }
+- l3 = cachep->nodelists[numa_node_id()];
++ l3 = cachep->nodelists[node];
+
+ BUG_ON(ac->avail > 0 || !l3);
+ spin_lock(&l3->list_lock);
+@@ -2862,7 +2968,7 @@ retry:
+ STATS_SET_HIGH(cachep);
+
+ ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
+- numa_node_id());
++ node);
+ }
+ check_slabp(cachep, slabp);
+
+@@ -2881,7 +2987,7 @@ alloc_done:
+
+ if (unlikely(!ac->avail)) {
+ int x;
+- x = cache_grow(cachep, flags, numa_node_id());
++ x = cache_grow(cachep, flags, node);
+
+ /* cache_grow can reenable interrupts, then ac could change. */
+ ac = cpu_cache_get(cachep);
+@@ -2968,14 +3074,6 @@ static inline void *____cache_alloc(stru
+ void *objp;
+ struct array_cache *ac;
+
+-#ifdef CONFIG_NUMA
+- if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) {
+- objp = alternate_node_alloc(cachep, flags);
+- if (objp != NULL)
+- return objp;
+- }
+-#endif
+-
+ check_irq_off();
+ ac = cpu_cache_get(cachep);
+ if (likely(ac->avail)) {
+@@ -2993,12 +3091,24 @@ static __always_inline void *__cache_all
+ gfp_t flags, void *caller)
+ {
+ unsigned long save_flags;
+- void *objp;
++ void *objp = NULL;
+
+ cache_alloc_debugcheck_before(cachep, flags);
+
+ local_irq_save(save_flags);
+- objp = ____cache_alloc(cachep, flags);
++
++ if (unlikely(NUMA_BUILD &&
++ current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY)))
++ objp = alternate_node_alloc(cachep, flags);
++
++ if (!objp)
++ objp = ____cache_alloc(cachep, flags);
++ /*
++ * We may just have run out of memory on the local node.
++ * __cache_alloc_node() knows how to locate memory on other nodes
++ */
++ if (NUMA_BUILD && !objp)
++ objp = __cache_alloc_node(cachep, flags, numa_node_id());
+ local_irq_restore(save_flags);
+ objp = cache_alloc_debugcheck_after(cachep, flags, objp,
+ caller);
+@@ -3017,7 +3127,7 @@ static void *alternate_node_alloc(struct
+ {
+ int nid_alloc, nid_here;
+
+- if (in_interrupt())
++ if (in_interrupt() || (flags & __GFP_THISNODE))
+ return NULL;
+ nid_alloc = nid_here = numa_node_id();
+ if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
+@@ -3030,6 +3140,31 @@ static void *alternate_node_alloc(struct
+ }
+
+ /*
++ * Fallback function if there was no memory available and no objects on a
++ * certain node and we are allowed to fall back. We mimick the behavior of
++ * the page allocator. We fall back according to a zonelist determined by
++ * the policy layer while obeying cpuset constraints.
++ */
++void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
++{
++ struct zonelist *zonelist = &NODE_DATA(slab_node(current->mempolicy))
++ ->node_zonelists[gfp_zone(flags)];
++ struct zone **z;
++ void *obj = NULL;
++
++ for (z = zonelist->zones; *z && !obj; z++) {
++ int nid = zone_to_nid(*z);
++
++ if (zone_idx(*z) <= ZONE_NORMAL &&
++ cpuset_zone_allowed(*z, flags) &&
++ cache->nodelists[nid])
++ obj = __cache_alloc_node(cache,
++ flags | __GFP_THISNODE, nid);
++ }
++ return obj;
++}
++
++/*
+ * A interface to enable slab creation on nodeid
+ */
+ static void *__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
+@@ -3082,11 +3217,15 @@ retry:
+ must_grow:
+ spin_unlock(&l3->list_lock);
+ x = cache_grow(cachep, flags, nodeid);
++ if (x)
++ goto retry;
+
+- if (!x)
+- return NULL;
++ if (!(flags & __GFP_THISNODE))
++ /* Unable to grow the cache. Fall back to other nodes. */
++ return fallback_alloc(cachep, flags);
++
++ return NULL;
+
+- goto retry;
+ done:
+ return obj;
+ }
+@@ -3119,6 +3258,12 @@ static void free_block(struct kmem_cache
+ if (slabp->inuse == 0) {
+ if (l3->free_objects > l3->free_limit) {
+ l3->free_objects -= cachep->num;
++ /* No need to drop any previously held
++ * lock here, even if we have a off-slab slab
++ * descriptor it is guaranteed to come from
++ * a different cache, refer to comments before
++ * alloc_slabmgmt.
++ */
+ slab_destroy(cachep, slabp);
+ } else {
+ list_add(&slabp->list, &l3->slabs_free);
+@@ -3317,7 +3462,7 @@ void *kmem_cache_alloc_node(struct kmem_
+ }
+ EXPORT_SYMBOL(kmem_cache_alloc_node);
+
+-void *kmalloc_node(size_t size, gfp_t flags, int node)
++void *__kmalloc_node(size_t size, gfp_t flags, int node)
+ {
+ struct kmem_cache *cachep;
+
+@@ -3326,7 +3471,7 @@ void *kmalloc_node(size_t size, gfp_t fl
+ return NULL;
+ return kmem_cache_alloc_node(cachep, flags, node);
+ }
+-EXPORT_SYMBOL(kmalloc_node);
++EXPORT_SYMBOL(__kmalloc_node);
+ #endif
+
+ /**
+@@ -3352,71 +3497,25 @@ static __always_inline void *__do_kmallo
+ }
+
+
++#ifdef CONFIG_DEBUG_SLAB
+ void *__kmalloc(size_t size, gfp_t flags)
+ {
+-#ifndef CONFIG_DEBUG_SLAB
+- return __do_kmalloc(size, flags, NULL);
+-#else
+ return __do_kmalloc(size, flags, __builtin_return_address(0));
+-#endif
+ }
+ EXPORT_SYMBOL(__kmalloc);
+
+-#ifdef CONFIG_DEBUG_SLAB
+ void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
+ {
+ return __do_kmalloc(size, flags, caller);
+ }
+ EXPORT_SYMBOL(__kmalloc_track_caller);
+-#endif
+
+-#ifdef CONFIG_SMP
+-/**
+- * __alloc_percpu - allocate one copy of the object for every present
+- * cpu in the system, zeroing them.
+- * Objects should be dereferenced using the per_cpu_ptr macro only.
+- *
+- * @size: how many bytes of memory are required.
+- */
+-void *__alloc_percpu(size_t size)
++#else
++void *__kmalloc(size_t size, gfp_t flags)
+ {
+- int i;
+- struct percpu_data *pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
+-
+- if (!pdata)
+- return NULL;
+-
+- /*
+- * Cannot use for_each_online_cpu since a cpu may come online
+- * and we have no way of figuring out how to fix the array
+- * that we have allocated then....
+- */
+- for_each_possible_cpu(i) {
+- int node = cpu_to_node(i);
+-
+- if (node_online(node))
+- pdata->ptrs[i] = kmalloc_node(size, GFP_KERNEL, node);
+- else
+- pdata->ptrs[i] = kmalloc(size, GFP_KERNEL);
+-
+- if (!pdata->ptrs[i])
+- goto unwind_oom;
+- memset(pdata->ptrs[i], 0, size);
+- }
+-
+- /* Catch derefs w/o wrappers */
+- return (void *)(~(unsigned long)pdata);
+-
+-unwind_oom:
+- while (--i >= 0) {
+- if (!cpu_possible(i))
+- continue;
+- kfree(pdata->ptrs[i]);
+- }
+- kfree(pdata);
+- return NULL;
++ return __do_kmalloc(size, flags, NULL);
+ }
+-EXPORT_SYMBOL(__alloc_percpu);
++EXPORT_SYMBOL(__kmalloc);
+ #endif
+
+ /**
+@@ -3464,29 +3563,6 @@ void kfree(const void *objp)
+ }
+ EXPORT_SYMBOL(kfree);
+
+-#ifdef CONFIG_SMP
+-/**
+- * free_percpu - free previously allocated percpu memory
+- * @objp: pointer returned by alloc_percpu.
+- *
+- * Don't free memory not originally allocated by alloc_percpu()
+- * The complemented objp is to check for that.
+- */
+-void free_percpu(const void *objp)
+-{
+- int i;
+- struct percpu_data *p = (struct percpu_data *)(~(unsigned long)objp);
+-
+- /*
+- * We allocate for all cpus so we cannot use for online cpu here.
+- */
+- for_each_possible_cpu(i)
+- kfree(p->ptrs[i]);
+- kfree(p);
+-}
+-EXPORT_SYMBOL(free_percpu);
+-#endif
+-
+ unsigned int kmem_cache_size(struct kmem_cache *cachep)
+ {
+ return obj_size(cachep);
+@@ -3603,22 +3679,26 @@ static void do_ccupdate_local(void *info
+ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
+ int batchcount, int shared)
+ {
+- struct ccupdate_struct new;
+- int i, err;
++ struct ccupdate_struct *new;
++ int i;
++
++ new = kzalloc(sizeof(*new), GFP_KERNEL);
++ if (!new)
++ return -ENOMEM;
+
+- memset(&new.new, 0, sizeof(new.new));
+ for_each_online_cpu(i) {
+- new.new[i] = alloc_arraycache(cpu_to_node(i), limit,
++ new->new[i] = alloc_arraycache(cpu_to_node(i), limit,
+ batchcount);
+- if (!new.new[i]) {
++ if (!new->new[i]) {
+ for (i--; i >= 0; i--)
+- kfree(new.new[i]);
++ kfree(new->new[i]);
++ kfree(new);
+ return -ENOMEM;
+ }
+ }
+- new.cachep = cachep;
++ new->cachep = cachep;
+
+- on_each_cpu(do_ccupdate_local, (void *)&new, 1, 1);
++ on_each_cpu(do_ccupdate_local, (void *)new, 1, 1);
+
+ check_irq_on();
+ cachep->batchcount = batchcount;
+@@ -3626,7 +3706,7 @@ static int do_tune_cpucache(struct kmem_
+ cachep->shared = shared;
+
+ for_each_online_cpu(i) {
+- struct array_cache *ccold = new.new[i];
++ struct array_cache *ccold = new->new[i];
+ if (!ccold)
+ continue;
+ spin_lock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock);
+@@ -3634,18 +3714,12 @@ static int do_tune_cpucache(struct kmem_
+ spin_unlock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock);
+ kfree(ccold);
+ }
+-
+- err = alloc_kmemlist(cachep);
+- if (err) {
+- printk(KERN_ERR "alloc_kmemlist failed for %s, error %d.\n",
+- cachep->name, -err);
+- BUG();
+- }
+- return 0;
++ kfree(new);
++ return alloc_kmemlist(cachep);
+ }
+
+ /* Called with cache_chain_mutex held always */
+-static void enable_cpucache(struct kmem_cache *cachep)
++static int enable_cpucache(struct kmem_cache *cachep)
+ {
+ int err;
+ int limit, shared;
+@@ -3697,6 +3771,7 @@ static void enable_cpucache(struct kmem_
+ if (err)
+ printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n",
+ cachep->name, -err);
++ return err;
+ }
+
+ /*
+@@ -4157,6 +4232,7 @@ static int leaks_show(struct seq_file *m
+ show_symbol(m, n[2*i+2]);
+ seq_putc(m, '\n');
+ }
++
+ return 0;
+ }
+
+diff --git a/mm/slob.c b/mm/slob.c
+index 7b52b20..5423941 100644
+--- a/mm/slob.c
++++ b/mm/slob.c
+@@ -270,10 +270,9 @@ struct kmem_cache *kmem_cache_create(con
+ }
+ EXPORT_SYMBOL(kmem_cache_create);
+
+-int kmem_cache_destroy(struct kmem_cache *c)
++void kmem_cache_destroy(struct kmem_cache *c)
+ {
+ slob_free(c, sizeof(struct kmem_cache));
+- return 0;
+ }
+ EXPORT_SYMBOL(kmem_cache_destroy);
+
+@@ -339,52 +338,3 @@ void kmem_cache_init(void)
+
+ mod_timer(&slob_timer, jiffies + HZ);
+ }
+-
+-atomic_t slab_reclaim_pages = ATOMIC_INIT(0);
+-EXPORT_SYMBOL(slab_reclaim_pages);
+-
+-#ifdef CONFIG_SMP
+-
+-void *__alloc_percpu(size_t size)
+-{
+- int i;
+- struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL);
+-
+- if (!pdata)
+- return NULL;
+-
+- for_each_possible_cpu(i) {
+- pdata->ptrs[i] = kmalloc(size, GFP_KERNEL);
+- if (!pdata->ptrs[i])
+- goto unwind_oom;
+- memset(pdata->ptrs[i], 0, size);
+- }
+-
+- /* Catch derefs w/o wrappers */
+- return (void *) (~(unsigned long) pdata);
+-
+-unwind_oom:
+- while (--i >= 0) {
+- if (!cpu_possible(i))
+- continue;
+- kfree(pdata->ptrs[i]);
+- }
+- kfree(pdata);
+- return NULL;
+-}
+-EXPORT_SYMBOL(__alloc_percpu);
+-
+-void
+-free_percpu(const void *objp)
+-{
+- int i;
+- struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp);
+-
+- for_each_possible_cpu(i)
+- kfree(p->ptrs[i]);
+-
+- kfree(p);
+-}
+-EXPORT_SYMBOL(free_percpu);
+-
+-#endif
+diff --git a/mm/sparse.c b/mm/sparse.c
+index 86c52ab..b3c82ba 100644
+--- a/mm/sparse.c
++++ b/mm/sparse.c
+@@ -211,7 +211,7 @@ static struct page *__kmalloc_section_me
+ struct page *page, *ret;
+ unsigned long memmap_size = sizeof(struct page) * nr_pages;
+
+- page = alloc_pages(GFP_KERNEL, get_order(memmap_size));
++ page = alloc_pages(GFP_KERNEL|__GFP_NOWARN, get_order(memmap_size));
+ if (page)
+ goto got_map_page;
+
+diff --git a/mm/swap.c b/mm/swap.c
+index 687686a..2e0e871 100644
+--- a/mm/swap.c
++++ b/mm/swap.c
+@@ -34,6 +34,25 @@
+ /* How many pages do we try to swap or page in/out together? */
+ int page_cluster;
+
++/*
++ * This path almost never happens for VM activity - pages are normally
++ * freed via pagevecs. But it gets used by networking.
++ */
++static void fastcall __page_cache_release(struct page *page)
++{
++ if (PageLRU(page)) {
++ unsigned long flags;
++ struct zone *zone = page_zone(page);
++
++ spin_lock_irqsave(&zone->lru_lock, flags);
++ VM_BUG_ON(!PageLRU(page));
++ __ClearPageLRU(page);
++ del_page_from_lru(zone, page);
++ spin_unlock_irqrestore(&zone->lru_lock, flags);
++ }
++ free_hot_page(page);
++}
++
+ static void put_compound_page(struct page *page)
+ {
+ page = (struct page *)page_private(page);
+@@ -223,26 +242,6 @@ int lru_add_drain_all(void)
+ #endif
+
+ /*
+- * This path almost never happens for VM activity - pages are normally
+- * freed via pagevecs. But it gets used by networking.
+- */
+-void fastcall __page_cache_release(struct page *page)
+-{
+- if (PageLRU(page)) {
+- unsigned long flags;
+- struct zone *zone = page_zone(page);
+-
+- spin_lock_irqsave(&zone->lru_lock, flags);
+- BUG_ON(!PageLRU(page));
+- __ClearPageLRU(page);
+- del_page_from_lru(zone, page);
+- spin_unlock_irqrestore(&zone->lru_lock, flags);
+- }
+- free_hot_page(page);
+-}
+-EXPORT_SYMBOL(__page_cache_release);
+-
+-/*
+ * Batched page_cache_release(). Decrement the reference count on all the
+ * passed pages. If it fell to zero then remove the page from the LRU and
+ * free it.
+@@ -284,7 +283,7 @@ void release_pages(struct page **pages,
+ zone = pagezone;
+ spin_lock_irq(&zone->lru_lock);
+ }
+- BUG_ON(!PageLRU(page));
++ VM_BUG_ON(!PageLRU(page));
+ __ClearPageLRU(page);
+ del_page_from_lru(zone, page);
+ }
+@@ -337,7 +336,7 @@ void __pagevec_release_nonlru(struct pag
+ for (i = 0; i < pagevec_count(pvec); i++) {
+ struct page *page = pvec->pages[i];
+
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ if (put_page_testzero(page))
+ pagevec_add(&pages_to_free, page);
+ }
+@@ -364,7 +363,7 @@ void __pagevec_lru_add(struct pagevec *p
+ zone = pagezone;
+ spin_lock_irq(&zone->lru_lock);
+ }
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+ add_page_to_inactive_list(zone, page);
+ }
+@@ -391,9 +390,9 @@ void __pagevec_lru_add_active(struct pag
+ zone = pagezone;
+ spin_lock_irq(&zone->lru_lock);
+ }
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+- BUG_ON(PageActive(page));
++ VM_BUG_ON(PageActive(page));
+ SetPageActive(page);
+ add_page_to_active_list(zone, page);
+ }
+diff --git a/mm/swapfile.c b/mm/swapfile.c
+index f1f5ec7..a15def6 100644
+--- a/mm/swapfile.c
++++ b/mm/swapfile.c
+@@ -1723,13 +1723,14 @@ get_swap_info_struct(unsigned type)
+ */
+ int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
+ {
+- int ret = 0, i = 1 << page_cluster;
++ int our_page_cluster = page_cluster;
++ int ret = 0, i = 1 << our_page_cluster;
+ unsigned long toff;
+ struct swap_info_struct *swapdev = swp_type(entry) + swap_info;
+
+- if (!page_cluster) /* no readahead */
++ if (!our_page_cluster) /* no readahead */
+ return 0;
+- toff = (swp_offset(entry) >> page_cluster) << page_cluster;
++ toff = (swp_offset(entry) >> our_page_cluster) << our_page_cluster;
+ if (!toff) /* first page is swap header */
+ toff++, i--;
+ *offset = toff;
+diff --git a/mm/truncate.c b/mm/truncate.c
+index c6ab55e..e07b1e6 100644
+--- a/mm/truncate.c
++++ b/mm/truncate.c
+@@ -9,6 +9,7 @@
+
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
++#include <linux/swap.h>
+ #include <linux/module.h>
+ #include <linux/pagemap.h>
+ #include <linux/pagevec.h>
+@@ -16,6 +17,32 @@
+ do_invalidatepage */
+
+
++/**
++ * do_invalidatepage - invalidate part of all of a page
++ * @page: the page which is affected
++ * @offset: the index of the truncation point
++ *
++ * do_invalidatepage() is called when all or part of the page has become
++ * invalidated by a truncate operation.
++ *
++ * do_invalidatepage() does not have to release all buffers, but it must
++ * ensure that no dirty buffer is left outside @offset and that no I/O
++ * is underway against any of the blocks which are outside the truncation
++ * point. Because the caller is about to free (and possibly reuse) those
++ * blocks on-disk.
++ */
++void do_invalidatepage(struct page *page, unsigned long offset)
++{
++ void (*invalidatepage)(struct page *, unsigned long);
++ invalidatepage = page->mapping->a_ops->invalidatepage;
++#ifdef CONFIG_BLOCK
++ if (!invalidatepage)
++ invalidatepage = block_invalidatepage;
++#endif
++ if (invalidatepage)
++ (*invalidatepage)(page, offset);
++}
++
+ static inline void truncate_partial_page(struct page *page, unsigned partial)
+ {
+ memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
+@@ -52,36 +79,25 @@ truncate_complete_page(struct address_sp
+ /*
+ * This is for invalidate_inode_pages(). That function can be called at
+ * any time, and is not supposed to throw away dirty pages. But pages can
+- * be marked dirty at any time too. So we re-check the dirtiness inside
+- * ->tree_lock. That provides exclusion against the __set_page_dirty
+- * functions.
++ * be marked dirty at any time too, so use remove_mapping which safely
++ * discards clean, unused pages.
+ *
+ * Returns non-zero if the page was successfully invalidated.
+ */
+ static int
+ invalidate_complete_page(struct address_space *mapping, struct page *page)
+ {
++ int ret;
++
+ if (page->mapping != mapping)
+ return 0;
+
+ if (PagePrivate(page) && !try_to_release_page(page, 0))
+ return 0;
+
+- write_lock_irq(&mapping->tree_lock);
+- if (PageDirty(page))
+- goto failed;
+- if (page_count(page) != 2) /* caller's ref + pagecache ref */
+- goto failed;
++ ret = remove_mapping(mapping, page);
+
+- BUG_ON(PagePrivate(page));
+- __remove_from_page_cache(page);
+- write_unlock_irq(&mapping->tree_lock);
+- ClearPageUptodate(page);
+- page_cache_release(page); /* pagecache ref */
+- return 1;
+-failed:
+- write_unlock_irq(&mapping->tree_lock);
+- return 0;
++ return ret;
+ }
+
+ /**
+@@ -270,9 +286,39 @@ unsigned long invalidate_inode_pages(str
+ {
+ return invalidate_mapping_pages(mapping, 0, ~0UL);
+ }
+-
+ EXPORT_SYMBOL(invalidate_inode_pages);
+
++/*
++ * This is like invalidate_complete_page(), except it ignores the page's
++ * refcount. We do this because invalidate_inode_pages2() needs stronger
++ * invalidation guarantees, and cannot afford to leave pages behind because
++ * shrink_list() has a temp ref on them, or because they're transiently sitting
++ * in the lru_cache_add() pagevecs.
++ */
++static int
++invalidate_complete_page2(struct address_space *mapping, struct page *page)
++{
++ if (page->mapping != mapping)
++ return 0;
++
++ if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
++ return 0;
++
++ write_lock_irq(&mapping->tree_lock);
++ if (PageDirty(page))
++ goto failed;
++
++ BUG_ON(PagePrivate(page));
++ __remove_from_page_cache(page);
++ write_unlock_irq(&mapping->tree_lock);
++ ClearPageUptodate(page);
++ page_cache_release(page); /* pagecache ref */
++ return 1;
++failed:
++ write_unlock_irq(&mapping->tree_lock);
++ return 0;
++}
++
+ /**
+ * invalidate_inode_pages2_range - remove range of pages from an address_space
+ * @mapping: the address_space
+@@ -339,7 +385,7 @@ int invalidate_inode_pages2_range(struct
+ }
+ }
+ was_dirty = test_clear_page_dirty(page);
+- if (!invalidate_complete_page(mapping, page)) {
++ if (!invalidate_complete_page2(mapping, page)) {
+ if (was_dirty)
+ set_page_dirty(page);
+ ret = -EIO;
+@@ -349,6 +395,7 @@ int invalidate_inode_pages2_range(struct
+ pagevec_release(&pvec);
+ cond_resched();
+ }
++ WARN_ON_ONCE(ret);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
+diff --git a/mm/util.c b/mm/util.c
+index 7368479..ace2aea 100644
+--- a/mm/util.c
++++ b/mm/util.c
+@@ -11,7 +11,7 @@
+ */
+ void *__kzalloc(size_t size, gfp_t flags)
+ {
+- void *ret = ____kmalloc(size, flags);
++ void *ret = kmalloc_track_caller(size, flags);
+ if (ret)
+ memset(ret, 0, size);
+ return ret;
+@@ -33,13 +33,31 @@ char *kstrdup(const char *s, gfp_t gfp)
+ return NULL;
+
+ len = strlen(s) + 1;
+- buf = ____kmalloc(len, gfp);
++ buf = kmalloc_track_caller(len, gfp);
+ if (buf)
+ memcpy(buf, s, len);
+ return buf;
+ }
+ EXPORT_SYMBOL(kstrdup);
+
++/**
++ * kmemdup - duplicate region of memory
++ *
++ * @src: memory region to duplicate
++ * @len: memory region length
++ * @gfp: GFP mask to use
++ */
++void *kmemdup(const void *src, size_t len, gfp_t gfp)
++{
++ void *p;
++
++ p = kmalloc_track_caller(len, gfp);
++ if (p)
++ memcpy(p, src, len);
++ return p;
++}
++EXPORT_SYMBOL(kmemdup);
++
+ /*
+ * strndup_user - duplicate an existing string from user space
+ *
+diff --git a/mm/vmalloc.c b/mm/vmalloc.c
+index 266162d..46606c1 100644
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -24,6 +24,9 @@
+ DEFINE_RWLOCK(vmlist_lock);
+ struct vm_struct *vmlist;
+
++static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
++ int node);
++
+ static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
+ {
+ pte_t *pte;
+@@ -157,13 +160,15 @@ int map_vm_area(struct vm_struct *area,
+ return err;
+ }
+
+-struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
+- unsigned long start, unsigned long end, int node)
++static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
++ unsigned long start, unsigned long end,
++ int node, gfp_t gfp_mask)
+ {
+ struct vm_struct **p, *tmp, *area;
+ unsigned long align = 1;
+ unsigned long addr;
+
++ BUG_ON(in_interrupt());
+ if (flags & VM_IOREMAP) {
+ int bit = fls(size);
+
+@@ -177,7 +182,7 @@ struct vm_struct *__get_vm_area_node(uns
+ addr = ALIGN(start, align);
+ size = PAGE_ALIGN(size);
+
+- area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);
++ area = kmalloc_node(sizeof(*area), gfp_mask & GFP_LEVEL_MASK, node);
+ if (unlikely(!area))
+ return NULL;
+
+@@ -233,12 +238,11 @@ out:
+ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
+ unsigned long start, unsigned long end)
+ {
+- return __get_vm_area_node(size, flags, start, end, -1);
++ return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL);
+ }
+
+ /**
+ * get_vm_area - reserve a contingous kernel virtual area
+- *
+ * @size: size of the area
+ * @flags: %VM_IOREMAP for I/O mappings or VM_ALLOC
+ *
+@@ -251,9 +255,11 @@ struct vm_struct *get_vm_area(unsigned l
+ return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
+ }
+
+-struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node)
++struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags,
++ int node, gfp_t gfp_mask)
+ {
+- return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node);
++ return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node,
++ gfp_mask);
+ }
+
+ /* Caller must hold vmlist_lock */
+@@ -270,7 +276,7 @@ static struct vm_struct *__find_vm_area(
+ }
+
+ /* Caller must hold vmlist_lock */
+-struct vm_struct *__remove_vm_area(void *addr)
++static struct vm_struct *__remove_vm_area(void *addr)
+ {
+ struct vm_struct **p, *tmp;
+
+@@ -293,7 +299,6 @@ found:
+
+ /**
+ * remove_vm_area - find and remove a contingous kernel virtual area
+- *
+ * @addr: base address
+ *
+ * Search for the kernel VM area starting at @addr, and remove it.
+@@ -352,7 +357,6 @@ void __vunmap(void *addr, int deallocate
+
+ /**
+ * vfree - release memory allocated by vmalloc()
+- *
+ * @addr: memory base address
+ *
+ * Free the virtually contiguous memory area starting at @addr, as
+@@ -370,7 +374,6 @@ EXPORT_SYMBOL(vfree);
+
+ /**
+ * vunmap - release virtual mapping obtained by vmap()
+- *
+ * @addr: memory base address
+ *
+ * Free the virtually contiguous memory area starting at @addr,
+@@ -387,7 +390,6 @@ EXPORT_SYMBOL(vunmap);
+
+ /**
+ * vmap - map an array of pages into virtually contiguous space
+- *
+ * @pages: array of page pointers
+ * @count: number of pages to map
+ * @flags: vm_area->flags
+@@ -430,8 +432,11 @@ void *__vmalloc_area_node(struct vm_stru
+ if (array_size > PAGE_SIZE) {
+ pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
+ area->flags |= VM_VPAGES;
+- } else
+- pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);
++ } else {
++ pages = kmalloc_node(array_size,
++ (gfp_mask & ~(__GFP_HIGHMEM | __GFP_ZERO)),
++ node);
++ }
+ area->pages = pages;
+ if (!area->pages) {
+ remove_vm_area(area->addr);
+@@ -468,7 +473,6 @@ void *__vmalloc_area(struct vm_struct *a
+
+ /**
+ * __vmalloc_node - allocate virtually contiguous memory
+- *
+ * @size: allocation size
+ * @gfp_mask: flags for the page level allocator
+ * @prot: protection mask for the allocated pages
+@@ -478,8 +482,8 @@ void *__vmalloc_area(struct vm_struct *a
+ * allocator with @gfp_mask flags. Map them into contiguous
+ * kernel virtual space, using a pagetable protection of @prot.
+ */
+-void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
+- int node)
++static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
++ int node)
+ {
+ struct vm_struct *area;
+
+@@ -487,13 +491,12 @@ void *__vmalloc_node(unsigned long size,
+ if (!size || (size >> PAGE_SHIFT) > num_physpages)
+ return NULL;
+
+- area = get_vm_area_node(size, VM_ALLOC, node);
++ area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask);
+ if (!area)
+ return NULL;
+
+ return __vmalloc_area_node(area, gfp_mask, prot, node);
+ }
+-EXPORT_SYMBOL(__vmalloc_node);
+
+ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
+ {
+@@ -503,13 +506,11 @@ EXPORT_SYMBOL(__vmalloc);
+
+ /**
+ * vmalloc - allocate virtually contiguous memory
+- *
+ * @size: allocation size
+- *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ *
+- * For tight cotrol over page level allocator and protection flags
++ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+ void *vmalloc(unsigned long size)
+@@ -519,11 +520,11 @@ void *vmalloc(unsigned long size)
+ EXPORT_SYMBOL(vmalloc);
+
+ /**
+- * vmalloc_user - allocate virtually contiguous memory which has
+- * been zeroed so it can be mapped to userspace without
+- * leaking data.
++ * vmalloc_user - allocate zeroed virtually contiguous memory for userspace
++ * @size: allocation size
+ *
+- * @size: allocation size
++ * The resulting memory area is zeroed so it can be mapped to userspace
++ * without leaking data.
+ */
+ void *vmalloc_user(unsigned long size)
+ {
+@@ -542,14 +543,13 @@ EXPORT_SYMBOL(vmalloc_user);
+
+ /**
+ * vmalloc_node - allocate memory on a specific node
+- *
+ * @size: allocation size
+ * @node: numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ *
+- * For tight cotrol over page level allocator and protection flags
++ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+ void *vmalloc_node(unsigned long size, int node)
+@@ -564,14 +564,13 @@ EXPORT_SYMBOL(vmalloc_node);
+
+ /**
+ * vmalloc_exec - allocate virtually contiguous, executable memory
+- *
+ * @size: allocation size
+ *
+ * Kernel-internal function to allocate enough pages to cover @size
+ * the page level allocator and map them into contiguous and
+ * executable kernel virtual space.
+ *
+- * For tight cotrol over page level allocator and protection flags
++ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+
+@@ -582,7 +581,6 @@ void *vmalloc_exec(unsigned long size)
+
+ /**
+ * vmalloc_32 - allocate virtually contiguous memory (32bit addressable)
+- *
+ * @size: allocation size
+ *
+ * Allocate enough 32bit PA addressable pages to cover @size from the
+@@ -595,11 +593,11 @@ void *vmalloc_32(unsigned long size)
+ EXPORT_SYMBOL(vmalloc_32);
+
+ /**
+- * vmalloc_32_user - allocate virtually contiguous memory (32bit
+- * addressable) which is zeroed so it can be
+- * mapped to userspace without leaking data.
+- *
++ * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory
+ * @size: allocation size
++ *
++ * The resulting memory area is 32bit addressable and zeroed so it can be
++ * mapped to userspace without leaking data.
+ */
+ void *vmalloc_32_user(unsigned long size)
+ {
+@@ -693,7 +691,6 @@ finished:
+
+ /**
+ * remap_vmalloc_range - map vmalloc pages to userspace
+- *
+ * @vma: vma to cover (map full range of vma)
+ * @addr: vmalloc memory
+ * @pgoff: number of pages into addr before first page to map
+diff --git a/mm/vmscan.c b/mm/vmscan.c
+index 5d4c4d0..518540a 100644
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -19,6 +19,7 @@
+ #include <linux/pagemap.h>
+ #include <linux/init.h>
+ #include <linux/highmem.h>
++#include <linux/vmstat.h>
+ #include <linux/file.h>
+ #include <linux/writeback.h>
+ #include <linux/blkdev.h>
+@@ -62,6 +63,8 @@ struct scan_control {
+ int swap_cluster_max;
+
+ int swappiness;
++
++ int all_unreclaimable;
+ };
+
+ /*
+@@ -368,24 +371,49 @@ static pageout_t pageout(struct page *pa
+ /* synchronous write or broken a_ops? */
+ ClearPageReclaim(page);
+ }
+-
++ inc_zone_page_state(page, NR_VMSCAN_WRITE);
+ return PAGE_SUCCESS;
+ }
+
+ return PAGE_CLEAN;
+ }
+
++/*
++ * Attempt to detach a locked page from its ->mapping. If it is dirty or if
++ * someone else has a ref on the page, abort and return 0. If it was
++ * successfully detached, return 1. Assumes the caller has a single ref on
++ * this page.
++ */
+ int remove_mapping(struct address_space *mapping, struct page *page)
+ {
+- if (!mapping)
+- return 0; /* truncate got there first */
++ BUG_ON(!PageLocked(page));
++ BUG_ON(mapping != page_mapping(page));
+
+ write_lock_irq(&mapping->tree_lock);
+-
+ /*
+- * The non-racy check for busy page. It is critical to check
+- * PageDirty _after_ making sure that the page is freeable and
+- * not in use by anybody. (pagecache + us == 2)
++ * The non racy check for a busy page.
++ *
++ * Must be careful with the order of the tests. When someone has
++ * a ref to the page, it may be possible that they dirty it then
++ * drop the reference. So if PageDirty is tested before page_count
++ * here, then the following race may occur:
++ *
++ * get_user_pages(&page);
++ * [user mapping goes away]
++ * write_to(page);
++ * !PageDirty(page) [good]
++ * SetPageDirty(page);
++ * put_page(page);
++ * !page_count(page) [good, discard it]
++ *
++ * [oops, our write_to data is lost]
++ *
++ * Reversing the order of the tests ensures such a situation cannot
++ * escape unnoticed. The smp_rmb is needed to ensure the page->flags
++ * load is not satisfied before that of page->_count.
++ *
++ * Note that if SetPageDirty is always performed via set_page_dirty,
++ * and thus under tree_lock, then this ordering is not required.
+ */
+ if (unlikely(page_count(page) != 2))
+ goto cannot_free;
+@@ -440,7 +468,7 @@ static unsigned long shrink_page_list(st
+ if (TestSetPageLocked(page))
+ goto keep;
+
+- BUG_ON(PageActive(page));
++ VM_BUG_ON(PageActive(page));
+
+ sc->nr_scanned++;
+
+@@ -547,7 +575,7 @@ static unsigned long shrink_page_list(st
+ goto free_it;
+ }
+
+- if (!remove_mapping(mapping, page))
++ if (!mapping || !remove_mapping(mapping, page))
+ goto keep_locked;
+
+ free_it:
+@@ -564,7 +592,7 @@ keep_locked:
+ unlock_page(page);
+ keep:
+ list_add(&page->lru, &ret_pages);
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ }
+ list_splice(&ret_pages, page_list);
+ if (pagevec_count(&freed_pvec))
+@@ -603,7 +631,7 @@ static unsigned long isolate_lru_pages(u
+ page = lru_to_page(src);
+ prefetchw_prev_lru_page(page, src, flags);
+
+- BUG_ON(!PageLRU(page));
++ VM_BUG_ON(!PageLRU(page));
+
+ list_del(&page->lru);
+ target = src;
+@@ -674,7 +702,7 @@ static unsigned long shrink_inactive_lis
+ */
+ while (!list_empty(&page_list)) {
+ page = lru_to_page(&page_list);
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+ list_del(&page->lru);
+ if (PageActive(page))
+@@ -696,6 +724,25 @@ done:
+ }
+
+ /*
++ * We are about to scan this zone at a certain priority level. If that priority
++ * level is smaller (ie: more urgent) than the previous priority, then note
++ * that priority level within the zone. This is done so that when the next
++ * process comes in to scan this zone, it will immediately start out at this
++ * priority level rather than having to build up its own scanning priority.
++ * Here, this priority affects only the reclaim-mapped threshold.
++ */
++static inline void note_zone_scanning_priority(struct zone *zone, int priority)
++{
++ if (priority < zone->prev_priority)
++ zone->prev_priority = priority;
++}
++
++static inline int zone_is_near_oom(struct zone *zone)
++{
++ return zone->pages_scanned >= (zone->nr_active + zone->nr_inactive)*3;
++}
++
++/*
+ * This moves pages from the active list to the inactive list.
+ *
+ * We move them the other way if the page is referenced by one or more
+@@ -713,7 +760,7 @@ done:
+ * But we had to alter page->flags anyway.
+ */
+ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
+- struct scan_control *sc)
++ struct scan_control *sc, int priority)
+ {
+ unsigned long pgmoved;
+ int pgdeactivate = 0;
+@@ -730,11 +777,14 @@ static void shrink_active_list(unsigned
+ long distress;
+ long swap_tendency;
+
++ if (zone_is_near_oom(zone))
++ goto force_reclaim_mapped;
++
+ /*
+ * `distress' is a measure of how much trouble we're having
+ * reclaiming pages. 0 -> no problems. 100 -> great trouble.
+ */
+- distress = 100 >> zone->prev_priority;
++ distress = 100 >> min(zone->prev_priority, priority);
+
+ /*
+ * The point of this algorithm is to decide when to start
+@@ -765,6 +815,7 @@ static void shrink_active_list(unsigned
+ * memory onto the inactive list.
+ */
+ if (swap_tendency >= 100)
++force_reclaim_mapped:
+ reclaim_mapped = 1;
+ }
+
+@@ -797,9 +848,9 @@ static void shrink_active_list(unsigned
+ while (!list_empty(&l_inactive)) {
+ page = lru_to_page(&l_inactive);
+ prefetchw_prev_lru_page(page, &l_inactive, flags);
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+- BUG_ON(!PageActive(page));
++ VM_BUG_ON(!PageActive(page));
+ ClearPageActive(page);
+
+ list_move(&page->lru, &zone->inactive_list);
+@@ -827,9 +878,9 @@ static void shrink_active_list(unsigned
+ while (!list_empty(&l_active)) {
+ page = lru_to_page(&l_active);
+ prefetchw_prev_lru_page(page, &l_active, flags);
+- BUG_ON(PageLRU(page));
++ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+- BUG_ON(!PageActive(page));
++ VM_BUG_ON(!PageActive(page));
+ list_move(&page->lru, &zone->active_list);
+ pgmoved++;
+ if (!pagevec_add(&pvec, page)) {
+@@ -885,7 +936,7 @@ static unsigned long shrink_zone(int pri
+ nr_to_scan = min(nr_active,
+ (unsigned long)sc->swap_cluster_max);
+ nr_active -= nr_to_scan;
+- shrink_active_list(nr_to_scan, zone, sc);
++ shrink_active_list(nr_to_scan, zone, sc, priority);
+ }
+
+ if (nr_inactive) {
+@@ -925,6 +976,7 @@ static unsigned long shrink_zones(int pr
+ unsigned long nr_reclaimed = 0;
+ int i;
+
++ sc->all_unreclaimable = 1;
+ for (i = 0; zones[i] != NULL; i++) {
+ struct zone *zone = zones[i];
+
+@@ -934,13 +986,13 @@ static unsigned long shrink_zones(int pr
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ continue;
+
+- zone->temp_priority = priority;
+- if (zone->prev_priority > priority)
+- zone->prev_priority = priority;
++ note_zone_scanning_priority(zone, priority);
+
+ if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+ continue; /* Let kswapd poll it */
+
++ sc->all_unreclaimable = 0;
++
+ nr_reclaimed += shrink_zone(priority, zone, sc);
+ }
+ return nr_reclaimed;
+@@ -984,7 +1036,6 @@ unsigned long try_to_free_pages(struct z
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ continue;
+
+- zone->temp_priority = DEF_PRIORITY;
+ lru_pages += zone->nr_active + zone->nr_inactive;
+ }
+
+@@ -1019,16 +1070,28 @@ unsigned long try_to_free_pages(struct z
+
+ /* Take a nap, wait for some writeback to complete */
+ if (sc.nr_scanned && priority < DEF_PRIORITY - 2)
+- blk_congestion_wait(WRITE, HZ/10);
++ congestion_wait(WRITE, HZ/10);
+ }
++ /* top priority shrink_caches still had more to do? don't OOM, then */
++ if (!sc.all_unreclaimable)
++ ret = 1;
+ out:
++ /*
++ * Now that we've scanned all the zones at this priority level, note
++ * that level within the zone so that the next thread which performs
++ * scanning of this zone will immediately start out at this priority
++ * level. This affects only the decision whether or not to bring
++ * mapped pages onto the inactive list.
++ */
++ if (priority < 0)
++ priority = 0;
+ for (i = 0; zones[i] != 0; i++) {
+ struct zone *zone = zones[i];
+
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ continue;
+
+- zone->prev_priority = zone->temp_priority;
++ zone->prev_priority = priority;
+ }
+ return ret;
+ }
+@@ -1068,6 +1131,11 @@ static unsigned long balance_pgdat(pg_da
+ .swap_cluster_max = SWAP_CLUSTER_MAX,
+ .swappiness = vm_swappiness,
+ };
++ /*
++ * temp_priority is used to remember the scanning priority at which
++ * this zone was successfully refilled to free_pages == pages_high.
++ */
++ int temp_priority[MAX_NR_ZONES];
+
+ loop_again:
+ total_scanned = 0;
+@@ -1075,11 +1143,8 @@ loop_again:
+ sc.may_writepage = !laptop_mode;
+ count_vm_event(PAGEOUTRUN);
+
+- for (i = 0; i < pgdat->nr_zones; i++) {
+- struct zone *zone = pgdat->node_zones + i;
+-
+- zone->temp_priority = DEF_PRIORITY;
+- }
++ for (i = 0; i < pgdat->nr_zones; i++)
++ temp_priority[i] = DEF_PRIORITY;
+
+ for (priority = DEF_PRIORITY; priority >= 0; priority--) {
+ int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */
+@@ -1140,10 +1205,9 @@ scan:
+ if (!zone_watermark_ok(zone, order, zone->pages_high,
+ end_zone, 0))
+ all_zones_ok = 0;
+- zone->temp_priority = priority;
+- if (zone->prev_priority > priority)
+- zone->prev_priority = priority;
++ temp_priority[i] = priority;
+ sc.nr_scanned = 0;
++ note_zone_scanning_priority(zone, priority);
+ nr_reclaimed += shrink_zone(priority, zone, &sc);
+ reclaim_state->reclaimed_slab = 0;
+ nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
+@@ -1153,7 +1217,7 @@ scan:
+ if (zone->all_unreclaimable)
+ continue;
+ if (nr_slab == 0 && zone->pages_scanned >=
+- (zone->nr_active + zone->nr_inactive) * 4)
++ (zone->nr_active + zone->nr_inactive) * 6)
+ zone->all_unreclaimable = 1;
+ /*
+ * If we've done a decent amount of scanning and
+@@ -1171,7 +1235,7 @@ scan:
+ * another pass across the zones.
+ */
+ if (total_scanned && priority < DEF_PRIORITY - 2)
+- blk_congestion_wait(WRITE, HZ/10);
++ congestion_wait(WRITE, HZ/10);
+
+ /*
+ * We do this so kswapd doesn't build up large priorities for
+@@ -1183,10 +1247,15 @@ scan:
+ break;
+ }
+ out:
++ /*
++ * Note within each zone the priority level at which this zone was
++ * brought into a happy state. So that the next thread which scans this
++ * zone will start out at that priority level.
++ */
+ for (i = 0; i < pgdat->nr_zones; i++) {
+ struct zone *zone = pgdat->node_zones + i;
+
+- zone->prev_priority = zone->temp_priority;
++ zone->prev_priority = temp_priority[i];
+ }
+ if (!all_zones_ok) {
+ cond_resched();
+@@ -1315,7 +1384,7 @@ static unsigned long shrink_all_zones(un
+ if (zone->nr_scan_active >= nr_pages || pass > 3) {
+ zone->nr_scan_active = 0;
+ nr_to_scan = min(nr_pages, zone->nr_active);
+- shrink_active_list(nr_to_scan, zone, sc);
++ shrink_active_list(nr_to_scan, zone, sc, prio);
+ }
+ }
+
+@@ -1361,7 +1430,7 @@ unsigned long shrink_all_memory(unsigned
+ for_each_zone(zone)
+ lru_pages += zone->nr_active + zone->nr_inactive;
+
+- nr_slab = global_page_state(NR_SLAB);
++ nr_slab = global_page_state(NR_SLAB_RECLAIMABLE);
+ /* If slab caches are huge, it's better to hit them first */
+ while (nr_slab >= lru_pages) {
+ reclaim_state.reclaimed_slab = 0;
+@@ -1415,7 +1484,7 @@ unsigned long shrink_all_memory(unsigned
+ goto out;
+
+ if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
+- blk_congestion_wait(WRITE, HZ / 10);
++ congestion_wait(WRITE, HZ / 10);
+ }
+
+ lru_pages = 0;
+@@ -1510,7 +1579,6 @@ int zone_reclaim_mode __read_mostly;
+ #define RECLAIM_ZONE (1<<0) /* Run shrink_cache on the zone */
+ #define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */
+ #define RECLAIM_SWAP (1<<2) /* Swap pages out during reclaim */
+-#define RECLAIM_SLAB (1<<3) /* Do a global slab shrink if the zone is out of memory */
+
+ /*
+ * Priority for ZONE_RECLAIM. This determines the fraction of pages
+@@ -1526,6 +1594,12 @@ int zone_reclaim_mode __read_mostly;
+ int sysctl_min_unmapped_ratio = 1;
+
+ /*
++ * If the number of slab pages in a zone grows beyond this percentage then
++ * slab reclaim needs to occur.
++ */
++int sysctl_min_slab_ratio = 5;
++
++/*
+ * Try to free up some pages from this zone through reclaim.
+ */
+ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
+@@ -1544,6 +1618,7 @@ static int __zone_reclaim(struct zone *z
+ .gfp_mask = gfp_mask,
+ .swappiness = vm_swappiness,
+ };
++ unsigned long slab_reclaimable;
+
+ disable_swap_token();
+ cond_resched();
+@@ -1556,29 +1631,44 @@ static int __zone_reclaim(struct zone *z
+ reclaim_state.reclaimed_slab = 0;
+ p->reclaim_state = &reclaim_state;
+
+- /*
+- * Free memory by calling shrink zone with increasing priorities
+- * until we have enough memory freed.
+- */
+- priority = ZONE_RECLAIM_PRIORITY;
+- do {
+- nr_reclaimed += shrink_zone(priority, zone, &sc);
+- priority--;
+- } while (priority >= 0 && nr_reclaimed < nr_pages);
++ if (zone_page_state(zone, NR_FILE_PAGES) -
++ zone_page_state(zone, NR_FILE_MAPPED) >
++ zone->min_unmapped_pages) {
++ /*
++ * Free memory by calling shrink zone with increasing
++ * priorities until we have enough memory freed.
++ */
++ priority = ZONE_RECLAIM_PRIORITY;
++ do {
++ note_zone_scanning_priority(zone, priority);
++ nr_reclaimed += shrink_zone(priority, zone, &sc);
++ priority--;
++ } while (priority >= 0 && nr_reclaimed < nr_pages);
++ }
+
+- if (nr_reclaimed < nr_pages && (zone_reclaim_mode & RECLAIM_SLAB)) {
++ slab_reclaimable = zone_page_state(zone, NR_SLAB_RECLAIMABLE);
++ if (slab_reclaimable > zone->min_slab_pages) {
+ /*
+ * shrink_slab() does not currently allow us to determine how
+- * many pages were freed in this zone. So we just shake the slab
+- * a bit and then go off node for this particular allocation
+- * despite possibly having freed enough memory to allocate in
+- * this zone. If we freed local memory then the next
+- * allocations will be local again.
++ * many pages were freed in this zone. So we take the current
++ * number of slab pages and shake the slab until it is reduced
++ * by the same nr_pages that we used for reclaiming unmapped
++ * pages.
+ *
+- * shrink_slab will free memory on all zones and may take
+- * a long time.
++ * Note that shrink_slab will free memory on all zones and may
++ * take a long time.
++ */
++ while (shrink_slab(sc.nr_scanned, gfp_mask, order) &&
++ zone_page_state(zone, NR_SLAB_RECLAIMABLE) >
++ slab_reclaimable - nr_pages)
++ ;
++
++ /*
++ * Update nr_reclaimed by the number of slab pages we
++ * reclaimed from this zone.
+ */
+- shrink_slab(sc.nr_scanned, gfp_mask, order);
++ nr_reclaimed += slab_reclaimable -
++ zone_page_state(zone, NR_SLAB_RECLAIMABLE);
+ }
+
+ p->reclaim_state = NULL;
+@@ -1592,7 +1682,8 @@ int zone_reclaim(struct zone *zone, gfp_
+ int node_id;
+
+ /*
+- * Zone reclaim reclaims unmapped file backed pages.
++ * Zone reclaim reclaims unmapped file backed pages and
++ * slab pages if we are over the defined limits.
+ *
+ * A small portion of unmapped file backed pages is needed for
+ * file I/O otherwise pages read by file I/O will be immediately
+@@ -1601,7 +1692,9 @@ int zone_reclaim(struct zone *zone, gfp_
+ * unmapped file backed pages.
+ */
+ if (zone_page_state(zone, NR_FILE_PAGES) -
+- zone_page_state(zone, NR_FILE_MAPPED) <= zone->min_unmapped_ratio)
++ zone_page_state(zone, NR_FILE_MAPPED) <= zone->min_unmapped_pages
++ && zone_page_state(zone, NR_SLAB_RECLAIMABLE)
++ <= zone->min_slab_pages)
+ return 0;
+
+ /*
+@@ -1621,7 +1714,7 @@ int zone_reclaim(struct zone *zone, gfp_
+ * over remote processors and spread off node memory allocations
+ * as wide as possible.
+ */
+- node_id = zone->zone_pgdat->node_id;
++ node_id = zone_to_nid(zone);
+ mask = node_to_cpumask(node_id);
+ if (!cpus_empty(mask) && node_id != numa_node_id())
+ return 0;
+diff --git a/mm/vmstat.c b/mm/vmstat.c
+index c1b5f41..8614e8f 100644
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -9,7 +9,6 @@
+ * Christoph Lameter <christoph at lameter.com>
+ */
+
+-#include <linux/config.h>
+ #include <linux/mm.h>
+ #include <linux/module.h>
+ #include <linux/cpu.h>
+@@ -321,6 +320,9 @@ void refresh_cpu_vm_stats(int cpu)
+ for_each_zone(zone) {
+ struct per_cpu_pageset *pcp;
+
++ if (!populated_zone(zone))
++ continue;
++
+ pcp = zone_pcp(zone, cpu);
+
+ for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+@@ -368,7 +370,7 @@ void zone_statistics(struct zonelist *zo
+ __inc_zone_state(z, NUMA_MISS);
+ __inc_zone_state(zonelist->zones[0], NUMA_FOREIGN);
+ }
+- if (z->zone_pgdat == NODE_DATA(numa_node_id()))
++ if (z->node == numa_node_id())
+ __inc_zone_state(z, NUMA_LOCAL);
+ else
+ __inc_zone_state(z, NUMA_OTHER);
+@@ -435,17 +437,34 @@ struct seq_operations fragmentation_op =
+ .show = frag_show,
+ };
+
++#ifdef CONFIG_ZONE_DMA32
++#define TEXT_FOR_DMA32(xx) xx "_dma32",
++#else
++#define TEXT_FOR_DMA32(xx)
++#endif
++
++#ifdef CONFIG_HIGHMEM
++#define TEXT_FOR_HIGHMEM(xx) xx "_high",
++#else
++#define TEXT_FOR_HIGHMEM(xx)
++#endif
++
++#define TEXTS_FOR_ZONES(xx) xx "_dma", TEXT_FOR_DMA32(xx) xx "_normal", \
++ TEXT_FOR_HIGHMEM(xx)
++
+ static char *vmstat_text[] = {
+ /* Zoned VM counters */
+ "nr_anon_pages",
+ "nr_mapped",
+ "nr_file_pages",
+- "nr_slab",
++ "nr_slab_reclaimable",
++ "nr_slab_unreclaimable",
+ "nr_page_table_pages",
+ "nr_dirty",
+ "nr_writeback",
+ "nr_unstable",
+ "nr_bounce",
++ "nr_vmscan_write",
+
+ #ifdef CONFIG_NUMA
+ "numa_hit",
+@@ -462,10 +481,7 @@ static char *vmstat_text[] = {
+ "pswpin",
+ "pswpout",
+
+- "pgalloc_dma",
+- "pgalloc_dma32",
+- "pgalloc_normal",
+- "pgalloc_high",
++ TEXTS_FOR_ZONES("pgalloc")
+
+ "pgfree",
+ "pgactivate",
+@@ -474,25 +490,10 @@ static char *vmstat_text[] = {
+ "pgfault",
+ "pgmajfault",
+
+- "pgrefill_dma",
+- "pgrefill_dma32",
+- "pgrefill_normal",
+- "pgrefill_high",
+-
+- "pgsteal_dma",
+- "pgsteal_dma32",
+- "pgsteal_normal",
+- "pgsteal_high",
+-
+- "pgscan_kswapd_dma",
+- "pgscan_kswapd_dma32",
+- "pgscan_kswapd_normal",
+- "pgscan_kswapd_high",
+-
+- "pgscan_direct_dma",
+- "pgscan_direct_dma32",
+- "pgscan_direct_normal",
+- "pgscan_direct_high",
++ TEXTS_FOR_ZONES("pgrefill")
++ TEXTS_FOR_ZONES("pgsteal")
++ TEXTS_FOR_ZONES("pgscan_kswapd")
++ TEXTS_FOR_ZONES("pgscan_direct")
+
+ "pginodesteal",
+ "slabs_scanned",
+@@ -586,11 +587,9 @@ static int zoneinfo_show(struct seq_file
+ seq_printf(m,
+ "\n all_unreclaimable: %u"
+ "\n prev_priority: %i"
+- "\n temp_priority: %i"
+ "\n start_pfn: %lu",
+ zone->all_unreclaimable,
+ zone->prev_priority,
+- zone->temp_priority,
+ zone->zone_start_pfn);
+ spin_unlock_irqrestore(&zone->lock, flags);
+ seq_putc(m, '\n');
+diff --git a/net/802/tr.c b/net/802/tr.c
+index d7d8f40..829deb4 100644
+--- a/net/802/tr.c
++++ b/net/802/tr.c
+@@ -164,7 +164,7 @@ static int tr_rebuild_header(struct sk_b
+ */
+
+ if(trllc->ethertype != htons(ETH_P_IP)) {
+- printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype));
++ printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n", ntohs(trllc->ethertype));
+ return 0;
+ }
+
+@@ -186,7 +186,7 @@ static int tr_rebuild_header(struct sk_b
+ * it via SNAP.
+ */
+
+-unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev)
++__be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev)
+ {
+
+ struct trh_hdr *trh=(struct trh_hdr *)skb->data;
+@@ -229,15 +229,15 @@ unsigned short tr_type_trans(struct sk_b
+ */
+
+ if (trllc->dsap == EXTENDED_SAP &&
+- (trllc->ethertype == ntohs(ETH_P_IP) ||
+- trllc->ethertype == ntohs(ETH_P_IPV6) ||
+- trllc->ethertype == ntohs(ETH_P_ARP)))
++ (trllc->ethertype == htons(ETH_P_IP) ||
++ trllc->ethertype == htons(ETH_P_IPV6) ||
++ trllc->ethertype == htons(ETH_P_ARP)))
+ {
+ skb_pull(skb, sizeof(struct trllc));
+ return trllc->ethertype;
+ }
+
+- return ntohs(ETH_P_TR_802_2);
++ return htons(ETH_P_TR_802_2);
+ }
+
+ /*
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index da9cfe9..60a508e 100644
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -62,7 +62,7 @@ int vlan_dev_rebuild_header(struct sk_bu
+ default:
+ printk(VLAN_DBG
+ "%s: unable to resolve type %X addresses.\n",
+- dev->name, (int)veth->h_vlan_encapsulated_proto);
++ dev->name, ntohs(veth->h_vlan_encapsulated_proto));
+
+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN);
+ break;
+diff --git a/net/Kconfig b/net/Kconfig
+index 4959a4e..67e39ad 100644
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -63,6 +63,7 @@ config INET
+ if INET
+ source "net/ipv4/Kconfig"
+ source "net/ipv6/Kconfig"
++source "net/netlabel/Kconfig"
+
+ endif # if INET
+
+@@ -231,7 +232,7 @@ config NET_TCPPROBE
+ TCP congestion avoidance modules. If you don't understand
+ what was just said, you don't need it: say N.
+
+- Documentation on how to use the packet generator can be found
++ Documentation on how to use TCP connection probing can be found
+ at http://linux-net.osdl.org/index.php/TcpProbe
+
+ To compile this code as a module, choose M here: the
+@@ -249,6 +250,9 @@ source "net/ieee80211/Kconfig"
+ config WIRELESS_EXT
+ bool
+
++config FIB_RULES
++ bool
++
+ endif # if NET
+ endmenu # Networking
+
+diff --git a/net/Makefile b/net/Makefile
+index 065796f..ad4d14f 100644
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -46,6 +46,7 @@ obj-$(CONFIG_IP_DCCP) += dccp/
+ obj-$(CONFIG_IP_SCTP) += sctp/
+ obj-$(CONFIG_IEEE80211) += ieee80211/
+ obj-$(CONFIG_TIPC) += tipc/
++obj-$(CONFIG_NETLABEL) += netlabel/
+
+ ifeq ($(CONFIG_NET),y)
+ obj-$(CONFIG_SYSCTL) += sysctl_net.o
+diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
+index 96dc6bb..485e35c 100644
+--- a/net/appletalk/ddp.c
++++ b/net/appletalk/ddp.c
+@@ -1002,7 +1002,7 @@ static unsigned long atalk_sum_skb(const
+ return sum;
+ }
+
+-static unsigned short atalk_checksum(const struct sk_buff *skb, int len)
++static __be16 atalk_checksum(const struct sk_buff *skb, int len)
+ {
+ unsigned long sum;
+
+@@ -1010,7 +1010,7 @@ static unsigned short atalk_checksum(con
+ sum = atalk_sum_skb(skb, 4, len-4, 0);
+
+ /* Use 0xFFFF for 0. 0 itself means none */
+- return sum ? htons((unsigned short)sum) : 0xFFFF;
++ return sum ? htons((unsigned short)sum) : htons(0xFFFF);
+ }
+
+ static struct proto ddp_proto = {
+@@ -1289,7 +1289,7 @@ static int handle_ip_over_ddp(struct sk_
+ #endif
+
+ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
+- struct ddpehdr *ddp, struct ddpebits *ddphv,
++ struct ddpehdr *ddp, __u16 len_hops,
+ int origlen)
+ {
+ struct atalk_route *rt;
+@@ -1317,10 +1317,12 @@ static void atalk_route_packet(struct sk
+
+ /* Route the packet */
+ rt = atrtr_find(&ta);
+- if (!rt || ddphv->deh_hops == DDP_MAXHOPS)
++ /* increment hops count */
++ len_hops += 1 << 10;
++ if (!rt || !(len_hops & (15 << 10)))
+ goto free_it;
++
+ /* FIXME: use skb->cb to be able to use shared skbs */
+- ddphv->deh_hops++;
+
+ /*
+ * Route goes through another gateway, so set the target to the
+@@ -1335,11 +1337,10 @@ static void atalk_route_packet(struct sk
+ /* Fix up skb->len field */
+ skb_trim(skb, min_t(unsigned int, origlen,
+ (rt->dev->hard_header_len +
+- ddp_dl->header_length + ddphv->deh_len)));
++ ddp_dl->header_length + (len_hops & 1023))));
+
+- /* Mend the byte order */
+ /* FIXME: use skb->cb to be able to use shared skbs */
+- *((__u16 *)ddp) = ntohs(*((__u16 *)ddphv));
++ ddp->deh_len_hops = htons(len_hops);
+
+ /*
+ * Send the buffer onwards
+@@ -1394,7 +1395,7 @@ static int atalk_rcv(struct sk_buff *skb
+ struct atalk_iface *atif;
+ struct sockaddr_at tosat;
+ int origlen;
+- struct ddpebits ddphv;
++ __u16 len_hops;
+
+ /* Don't mangle buffer if shared */
+ if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+@@ -1406,16 +1407,11 @@ static int atalk_rcv(struct sk_buff *skb
+
+ ddp = ddp_hdr(skb);
+
+- /*
+- * Fix up the length field [Ok this is horrible but otherwise
+- * I end up with unions of bit fields and messy bit field order
+- * compiler/endian dependencies..]
+- */
+- *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
++ len_hops = ntohs(ddp->deh_len_hops);
+
+ /* Trim buffer in case of stray trailing data */
+ origlen = skb->len;
+- skb_trim(skb, min_t(unsigned int, skb->len, ddphv.deh_len));
++ skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));
+
+ /*
+ * Size check to see if ddp->deh_len was crap
+@@ -1430,7 +1426,7 @@ static int atalk_rcv(struct sk_buff *skb
+ * valid for net byte orders all over the networking code...
+ */
+ if (ddp->deh_sum &&
+- atalk_checksum(skb, ddphv.deh_len) != ddp->deh_sum)
++ atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
+ /* Not a valid AppleTalk frame - dustbin time */
+ goto freeit;
+
+@@ -1444,7 +1440,7 @@ static int atalk_rcv(struct sk_buff *skb
+ /* Not ours, so we route the packet via the correct
+ * AppleTalk iface
+ */
+- atalk_route_packet(skb, dev, ddp, &ddphv, origlen);
++ atalk_route_packet(skb, dev, ddp, len_hops, origlen);
+ goto out;
+ }
+
+@@ -1489,7 +1485,7 @@ static int ltalk_rcv(struct sk_buff *skb
+ /* Find our address */
+ struct atalk_addr *ap = atalk_find_dev_addr(dev);
+
+- if (!ap || skb->len < sizeof(struct ddpshdr))
++ if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
+ goto freeit;
+
+ /* Don't mangle buffer if shared */
+@@ -1519,11 +1515,8 @@ static int ltalk_rcv(struct sk_buff *skb
+ /*
+ * Not sure about this bit...
+ */
+- ddp->deh_len = skb->len;
+- ddp->deh_hops = DDP_MAXHOPS; /* Non routable, so force a drop
+- if we slip up later */
+- /* Mend the byte order */
+- *((__u16 *)ddp) = htons(*((__u16 *)ddp));
++ /* Non routable, so force a drop if we slip up later */
++ ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
+ }
+ skb->h.raw = skb->data;
+
+@@ -1591,7 +1584,6 @@ static int atalk_sendmsg(struct kiocb *i
+
+ if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
+ rt = atrtr_find(&usat->sat_addr);
+- dev = rt->dev;
+ } else {
+ struct atalk_addr at_hint;
+
+@@ -1599,7 +1591,6 @@ static int atalk_sendmsg(struct kiocb *i
+ at_hint.s_net = at->src_net;
+
+ rt = atrtr_find(&at_hint);
+- dev = rt->dev;
+ }
+ if (!rt)
+ return -ENETUNREACH;
+@@ -1622,16 +1613,7 @@ static int atalk_sendmsg(struct kiocb *i
+ SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
+
+ ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
+- ddp->deh_pad = 0;
+- ddp->deh_hops = 0;
+- ddp->deh_len = len + sizeof(*ddp);
+- /*
+- * Fix up the length field [Ok this is horrible but otherwise
+- * I end up with unions of bit fields and messy bit field order
+- * compiler/endian dependencies..
+- */
+- *((__u16 *)ddp) = ntohs(*((__u16 *)ddp));
+-
++ ddp->deh_len_hops = htons(len + sizeof(*ddp));
+ ddp->deh_dnet = usat->sat_addr.s_net;
+ ddp->deh_snet = at->src_net;
+ ddp->deh_dnode = usat->sat_addr.s_node;
+@@ -1712,8 +1694,8 @@ static int atalk_recvmsg(struct kiocb *i
+ struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
+ struct ddpehdr *ddp;
+ int copied = 0;
++ int offset = 0;
+ int err = 0;
+- struct ddpebits ddphv;
+ struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ flags & MSG_DONTWAIT, &err);
+ if (!skb)
+@@ -1721,25 +1703,18 @@ static int atalk_recvmsg(struct kiocb *i
+
+ /* FIXME: use skb->cb to be able to use shared skbs */
+ ddp = ddp_hdr(skb);
+- *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
++ copied = ntohs(ddp->deh_len_hops) & 1023;
+
+- if (sk->sk_type == SOCK_RAW) {
+- copied = ddphv.deh_len;
+- if (copied > size) {
+- copied = size;
+- msg->msg_flags |= MSG_TRUNC;
+- }
++ if (sk->sk_type != SOCK_RAW) {
++ offset = sizeof(*ddp);
++ copied -= offset;
++ }
+
+- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+- } else {
+- copied = ddphv.deh_len - sizeof(*ddp);
+- if (copied > size) {
+- copied = size;
+- msg->msg_flags |= MSG_TRUNC;
+- }
+- err = skb_copy_datagram_iovec(skb, sizeof(*ddp),
+- msg->msg_iov, copied);
++ if (copied > size) {
++ copied = size;
++ msg->msg_flags |= MSG_TRUNC;
+ }
++ err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
+
+ if (!err) {
+ if (sat) {
+diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c
+index 5df4b9a..62f6ed1 100644
+--- a/net/atm/atm_sysfs.c
++++ b/net/atm/atm_sysfs.c
+@@ -1,6 +1,5 @@
+ /* ATM driver model support. */
+
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/kobject.h>
+@@ -142,7 +141,7 @@ static struct class atm_class = {
+ int atm_register_sysfs(struct atm_dev *adev)
+ {
+ struct class_device *cdev = &adev->class_dev;
+- int i, err;
++ int i, j, err;
+
+ cdev->class = &atm_class;
+ class_set_devdata(cdev, adev);
+@@ -152,10 +151,19 @@ int atm_register_sysfs(struct atm_dev *a
+ if (err < 0)
+ return err;
+
+- for (i = 0; atm_attrs[i]; i++)
+- class_device_create_file(cdev, atm_attrs[i]);
++ for (i = 0; atm_attrs[i]; i++) {
++ err = class_device_create_file(cdev, atm_attrs[i]);
++ if (err)
++ goto err_out;
++ }
+
+ return 0;
++
++err_out:
++ for (j = 0; j < i; j++)
++ class_device_remove_file(cdev, atm_attrs[j]);
++ class_device_del(cdev);
++ return err;
+ }
+
+ void atm_unregister_sysfs(struct atm_dev *adev)
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index b4aa489..66c57c1 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -1,7 +1,7 @@
+ /*
+ * lec.c: Lan Emulation driver
+- * Marko Kiiskila mkiiskila at yahoo.com
+ *
++ * Marko Kiiskila <mkiiskila at yahoo.com>
+ */
+
+ #include <linux/kernel.h>
+@@ -38,7 +38,7 @@
+ #include <linux/if_bridge.h>
+ #include "../bridge/br_private.h"
+
+-static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
++static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
+ #endif
+
+ /* Modular too */
+@@ -55,38 +55,41 @@ static unsigned char bridge_ula_lec[] =
+ #define DPRINTK(format,args...)
+ #endif
+
+-#define DUMP_PACKETS 0 /* 0 = None,
+- * 1 = 30 first bytes
+- * 2 = Whole packet
+- */
++#define DUMP_PACKETS 0 /*
++ * 0 = None,
++ * 1 = 30 first bytes
++ * 2 = Whole packet
++ */
+
+-#define LEC_UNRES_QUE_LEN 8 /* number of tx packets to queue for a
+- single destination while waiting for SVC */
++#define LEC_UNRES_QUE_LEN 8 /*
++ * number of tx packets to queue for a
++ * single destination while waiting for SVC
++ */
+
+ static int lec_open(struct net_device *dev);
+ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ static int lec_close(struct net_device *dev);
+ static struct net_device_stats *lec_get_stats(struct net_device *dev);
+ static void lec_init(struct net_device *dev);
+-static struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
+- unsigned char *mac_addr);
++static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
++ unsigned char *mac_addr);
+ static int lec_arp_remove(struct lec_priv *priv,
+- struct lec_arp_table *to_remove);
++ struct lec_arp_table *to_remove);
+ /* LANE2 functions */
+-static void lane2_associate_ind (struct net_device *dev, u8 *mac_address,
+- u8 *tlvs, u32 sizeoftlvs);
++static void lane2_associate_ind(struct net_device *dev, u8 *mac_address,
++ u8 *tlvs, u32 sizeoftlvs);
+ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
+- u8 **tlvs, u32 *sizeoftlvs);
+-static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
+- u8 *tlvs, u32 sizeoftlvs);
++ u8 **tlvs, u32 *sizeoftlvs);
++static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
++ u8 *tlvs, u32 sizeoftlvs);
+
+-static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
++static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
+ unsigned long permanent);
+ static void lec_arp_check_empties(struct lec_priv *priv,
+ struct atm_vcc *vcc, struct sk_buff *skb);
+ static void lec_arp_destroy(struct lec_priv *priv);
+ static void lec_arp_init(struct lec_priv *priv);
+-static struct atm_vcc* lec_arp_resolve(struct lec_priv *priv,
++static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
+ unsigned char *mac_to_find,
+ int is_rdesc,
+ struct lec_arp_table **ret_entry);
+@@ -100,16 +103,30 @@ static void lec_set_flush_tran_id(struct
+ unsigned long tran_id);
+ static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
+ struct atm_vcc *vcc,
+- void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb));
++ void (*old_push) (struct atm_vcc *vcc,
++ struct sk_buff *skb));
+ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
+
++/* must be done under lec_arp_lock */
++static inline void lec_arp_hold(struct lec_arp_table *entry)
++{
++ atomic_inc(&entry->usage);
++}
++
++static inline void lec_arp_put(struct lec_arp_table *entry)
++{
++ if (atomic_dec_and_test(&entry->usage))
++ kfree(entry);
++}
++
++
+ static struct lane2_ops lane2_ops = {
+- lane2_resolve, /* resolve, spec 3.1.3 */
+- lane2_associate_req, /* associate_req, spec 3.1.4 */
+- NULL /* associate indicator, spec 3.1.5 */
++ lane2_resolve, /* resolve, spec 3.1.3 */
++ lane2_associate_req, /* associate_req, spec 3.1.4 */
++ NULL /* associate indicator, spec 3.1.5 */
+ };
+
+-static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
++static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ /* Device structures */
+ static struct net_device *dev_lec[MAX_LEC_ITF];
+@@ -117,36 +134,39 @@ static struct net_device *dev_lec[MAX_LE
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ {
+- struct ethhdr *eth;
+- char *buff;
+- struct lec_priv *priv;
+-
+- /* Check if this is a BPDU. If so, ask zeppelin to send
+- * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
+- * as the Config BPDU has */
+- eth = (struct ethhdr *)skb->data;
+- buff = skb->data + skb->dev->hard_header_len;
+- if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
++ struct ethhdr *eth;
++ char *buff;
++ struct lec_priv *priv;
++
++ /*
++ * Check if this is a BPDU. If so, ask zeppelin to send
++ * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
++ * as the Config BPDU has
++ */
++ eth = (struct ethhdr *)skb->data;
++ buff = skb->data + skb->dev->hard_header_len;
++ if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
+ struct sock *sk;
+- struct sk_buff *skb2;
+- struct atmlec_msg *mesg;
+-
+- skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+- if (skb2 == NULL) return;
+- skb2->len = sizeof(struct atmlec_msg);
+- mesg = (struct atmlec_msg *)skb2->data;
+- mesg->type = l_topology_change;
+- buff += 4;
+- mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
+-
+- priv = (struct lec_priv *)dev->priv;
+- atm_force_charge(priv->lecd, skb2->truesize);
++ struct sk_buff *skb2;
++ struct atmlec_msg *mesg;
++
++ skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
++ if (skb2 == NULL)
++ return;
++ skb2->len = sizeof(struct atmlec_msg);
++ mesg = (struct atmlec_msg *)skb2->data;
++ mesg->type = l_topology_change;
++ buff += 4;
++ mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
++
++ priv = (struct lec_priv *)dev->priv;
++ atm_force_charge(priv->lecd, skb2->truesize);
+ sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk, skb2->len);
+- }
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk, skb2->len);
++ }
+
+- return;
++ return;
+ }
+ #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+
+@@ -162,36 +182,35 @@ static void lec_handle_bridge(struct sk_
+ #ifdef CONFIG_TR
+ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
+ {
+- struct trh_hdr *trh;
+- int riflen, num_rdsc;
+-
+- trh = (struct trh_hdr *)packet;
+- if (trh->daddr[0] & (uint8_t)0x80)
+- return bus_mac; /* multicast */
+-
+- if (trh->saddr[0] & TR_RII) {
+- riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+- if ((ntohs(trh->rcf) >> 13) != 0)
+- return bus_mac; /* ARE or STE */
+- }
+- else
+- return trh->daddr; /* not source routed */
+-
+- if (riflen < 6)
+- return trh->daddr; /* last hop, source routed */
+-
+- /* riflen is 6 or more, packet has more than one route descriptor */
+- num_rdsc = (riflen/2) - 1;
+- memset(rdesc, 0, ETH_ALEN);
+- /* offset 4 comes from LAN destination field in LE control frames */
+- if (trh->rcf & htons((uint16_t)TR_RCF_DIR_BIT))
+- memcpy(&rdesc[4], &trh->rseg[num_rdsc-2], sizeof(uint16_t));
+- else {
+- memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
+- rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
+- }
+-
+- return NULL;
++ struct trh_hdr *trh;
++ int riflen, num_rdsc;
++
++ trh = (struct trh_hdr *)packet;
++ if (trh->daddr[0] & (uint8_t) 0x80)
++ return bus_mac; /* multicast */
++
++ if (trh->saddr[0] & TR_RII) {
++ riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
++ if ((ntohs(trh->rcf) >> 13) != 0)
++ return bus_mac; /* ARE or STE */
++ } else
++ return trh->daddr; /* not source routed */
++
++ if (riflen < 6)
++ return trh->daddr; /* last hop, source routed */
++
++ /* riflen is 6 or more, packet has more than one route descriptor */
++ num_rdsc = (riflen / 2) - 1;
++ memset(rdesc, 0, ETH_ALEN);
++ /* offset 4 comes from LAN destination field in LE control frames */
++ if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
++ memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t));
++ else {
++ memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
++ rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
++ }
++
++ return NULL;
+ }
+ #endif /* CONFIG_TR */
+
+@@ -204,15 +223,14 @@ static unsigned char *get_tr_dst(unsigne
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+-static int
+-lec_open(struct net_device *dev)
++static int lec_open(struct net_device *dev)
+ {
+- struct lec_priv *priv = (struct lec_priv *)dev->priv;
+-
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
++
+ netif_start_queue(dev);
+- memset(&priv->stats,0,sizeof(struct net_device_stats));
+-
+- return 0;
++ memset(&priv->stats, 0, sizeof(struct net_device_stats));
++
++ return 0;
+ }
+
+ static __inline__ void
+@@ -231,160 +249,166 @@ lec_send(struct atm_vcc *vcc, struct sk_
+ priv->stats.tx_bytes += skb->len;
+ }
+
+-static void
+-lec_tx_timeout(struct net_device *dev)
++static void lec_tx_timeout(struct net_device *dev)
+ {
+ printk(KERN_INFO "%s: tx timeout\n", dev->name);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ }
+
+-static int
+-lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
++static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+- struct sk_buff *skb2;
+- struct lec_priv *priv = (struct lec_priv *)dev->priv;
+- struct lecdatahdr_8023 *lec_h;
+- struct atm_vcc *vcc;
++ struct sk_buff *skb2;
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
++ struct lecdatahdr_8023 *lec_h;
++ struct atm_vcc *vcc;
+ struct lec_arp_table *entry;
+- unsigned char *dst;
++ unsigned char *dst;
+ int min_frame_size;
+ #ifdef CONFIG_TR
+- unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
++ unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
+ #endif
+- int is_rdesc;
++ int is_rdesc;
+ #if DUMP_PACKETS > 0
+- char buf[300];
+- int i=0;
++ char buf[300];
++ int i = 0;
+ #endif /* DUMP_PACKETS >0 */
+-
+- DPRINTK("lec_start_xmit called\n");
+- if (!priv->lecd) {
+- printk("%s:No lecd attached\n",dev->name);
+- priv->stats.tx_errors++;
+- netif_stop_queue(dev);
+- return -EUNATCH;
+- }
+-
+- DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
+- (long)skb->head, (long)skb->data, (long)skb->tail,
+- (long)skb->end);
++
++ DPRINTK("lec_start_xmit called\n");
++ if (!priv->lecd) {
++ printk("%s:No lecd attached\n", dev->name);
++ priv->stats.tx_errors++;
++ netif_stop_queue(dev);
++ return -EUNATCH;
++ }
++
++ DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
++ (long)skb->head, (long)skb->data, (long)skb->tail,
++ (long)skb->end);
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+- if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
+- lec_handle_bridge(skb, dev);
++ if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
++ lec_handle_bridge(skb, dev);
+ #endif
+
+- /* Make sure we have room for lec_id */
+- if (skb_headroom(skb) < 2) {
++ /* Make sure we have room for lec_id */
++ if (skb_headroom(skb) < 2) {
+
+- DPRINTK("lec_start_xmit: reallocating skb\n");
+- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+- kfree_skb(skb);
+- if (skb2 == NULL) return 0;
+- skb = skb2;
+- }
+- skb_push(skb, 2);
++ DPRINTK("lec_start_xmit: reallocating skb\n");
++ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
++ kfree_skb(skb);
++ if (skb2 == NULL)
++ return 0;
++ skb = skb2;
++ }
++ skb_push(skb, 2);
+
+- /* Put le header to place, works for TokenRing too */
+- lec_h = (struct lecdatahdr_8023*)skb->data;
+- lec_h->le_header = htons(priv->lecid);
++ /* Put le header to place, works for TokenRing too */
++ lec_h = (struct lecdatahdr_8023 *)skb->data;
++ lec_h->le_header = htons(priv->lecid);
+
+ #ifdef CONFIG_TR
+- /* Ugly. Use this to realign Token Ring packets for
+- * e.g. PCA-200E driver. */
+- if (priv->is_trdev) {
+- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+- kfree_skb(skb);
+- if (skb2 == NULL) return 0;
+- skb = skb2;
+- }
++ /*
++ * Ugly. Use this to realign Token Ring packets for
++ * e.g. PCA-200E driver.
++ */
++ if (priv->is_trdev) {
++ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
++ kfree_skb(skb);
++ if (skb2 == NULL)
++ return 0;
++ skb = skb2;
++ }
+ #endif
+
+ #if DUMP_PACKETS > 0
+- printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
+- skb->len, priv->lecid);
++ printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
++ skb->len, priv->lecid);
+ #if DUMP_PACKETS >= 2
+- for(i=0;i<skb->len && i <99;i++) {
+- sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
+- }
++ for (i = 0; i < skb->len && i < 99; i++) {
++ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
++ }
+ #elif DUMP_PACKETS >= 1
+- for(i=0;i<skb->len && i < 30;i++) {
+- sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
+- }
++ for (i = 0; i < skb->len && i < 30; i++) {
++ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
++ }
+ #endif /* DUMP_PACKETS >= 1 */
+- if (i==skb->len)
+- printk("%s\n",buf);
+- else
+- printk("%s...\n",buf);
++ if (i == skb->len)
++ printk("%s\n", buf);
++ else
++ printk("%s...\n", buf);
+ #endif /* DUMP_PACKETS > 0 */
+
+- /* Minimum ethernet-frame size */
++ /* Minimum ethernet-frame size */
+ #ifdef CONFIG_TR
+- if (priv->is_trdev)
+- min_frame_size = LEC_MINIMUM_8025_SIZE;
++ if (priv->is_trdev)
++ min_frame_size = LEC_MINIMUM_8025_SIZE;
+ else
+ #endif
+- min_frame_size = LEC_MINIMUM_8023_SIZE;
+- if (skb->len < min_frame_size) {
+- if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
+- skb2 = skb_copy_expand(skb, 0,
+- min_frame_size - skb->truesize, GFP_ATOMIC);
+- dev_kfree_skb(skb);
+- if (skb2 == NULL) {
+- priv->stats.tx_dropped++;
+- return 0;
+- }
+- skb = skb2;
+- }
++ min_frame_size = LEC_MINIMUM_8023_SIZE;
++ if (skb->len < min_frame_size) {
++ if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
++ skb2 = skb_copy_expand(skb, 0,
++ min_frame_size - skb->truesize,
++ GFP_ATOMIC);
++ dev_kfree_skb(skb);
++ if (skb2 == NULL) {
++ priv->stats.tx_dropped++;
++ return 0;
++ }
++ skb = skb2;
++ }
+ skb_put(skb, min_frame_size - skb->len);
+- }
+-
+- /* Send to right vcc */
+- is_rdesc = 0;
+- dst = lec_h->h_dest;
++ }
++
++ /* Send to right vcc */
++ is_rdesc = 0;
++ dst = lec_h->h_dest;
+ #ifdef CONFIG_TR
+- if (priv->is_trdev) {
+- dst = get_tr_dst(skb->data+2, rdesc);
+- if (dst == NULL) {
+- dst = rdesc;
+- is_rdesc = 1;
+- }
+- }
++ if (priv->is_trdev) {
++ dst = get_tr_dst(skb->data + 2, rdesc);
++ if (dst == NULL) {
++ dst = rdesc;
++ is_rdesc = 1;
++ }
++ }
+ #endif
+- entry = NULL;
+- vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
+- DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
+- vcc, vcc?vcc->flags:0, entry);
+- if (!vcc || !test_bit(ATM_VF_READY,&vcc->flags)) {
+- if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
+- DPRINTK("%s:lec_start_xmit: queuing packet, ", dev->name);
+- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+- skb_queue_tail(&entry->tx_wait, skb);
+- } else {
+- DPRINTK("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name);
+- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+- priv->stats.tx_dropped++;
+- dev_kfree_skb(skb);
+- }
+- return 0;
+- }
+-
+-#if DUMP_PACKETS > 0
+- printk("%s:sending to vpi:%d vci:%d\n", dev->name,
+- vcc->vpi, vcc->vci);
++ entry = NULL;
++ vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
++ DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
++ vcc, vcc ? vcc->flags : 0, entry);
++ if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
++ if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
++ DPRINTK("%s:lec_start_xmit: queuing packet, ",
++ dev->name);
++ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
++ lec_h->h_dest[0], lec_h->h_dest[1],
++ lec_h->h_dest[2], lec_h->h_dest[3],
++ lec_h->h_dest[4], lec_h->h_dest[5]);
++ skb_queue_tail(&entry->tx_wait, skb);
++ } else {
++ DPRINTK
++ ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
++ dev->name);
++ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
++ lec_h->h_dest[0], lec_h->h_dest[1],
++ lec_h->h_dest[2], lec_h->h_dest[3],
++ lec_h->h_dest[4], lec_h->h_dest[5]);
++ priv->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ }
++ goto out;
++ }
++#if DUMP_PACKETS > 0
++ printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
+ #endif /* DUMP_PACKETS > 0 */
+-
+- while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
+- DPRINTK("lec.c: emptying tx queue, ");
+- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
++
++ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
++ DPRINTK("lec.c: emptying tx queue, ");
++ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
++ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
++ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+ lec_send(vcc, skb2, priv);
+- }
++ }
+
+ lec_send(vcc, skb, priv);
+
+@@ -404,210 +428,219 @@ lec_start_xmit(struct sk_buff *skb, stru
+ netif_wake_queue(dev);
+ }
+
++out:
++ if (entry)
++ lec_arp_put(entry);
+ dev->trans_start = jiffies;
+- return 0;
++ return 0;
+ }
+
+ /* The inverse routine to net_open(). */
+-static int
+-lec_close(struct net_device *dev)
++static int lec_close(struct net_device *dev)
+ {
+- netif_stop_queue(dev);
+- return 0;
++ netif_stop_queue(dev);
++ return 0;
+ }
+
+ /*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+-static struct net_device_stats *
+-lec_get_stats(struct net_device *dev)
++static struct net_device_stats *lec_get_stats(struct net_device *dev)
+ {
+- return &((struct lec_priv *)dev->priv)->stats;
++ return &((struct lec_priv *)dev->priv)->stats;
+ }
+
+-static int
+-lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
++static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ {
+ unsigned long flags;
+- struct net_device *dev = (struct net_device*)vcc->proto_data;
+- struct lec_priv *priv = (struct lec_priv*)dev->priv;
+- struct atmlec_msg *mesg;
+- struct lec_arp_table *entry;
+- int i;
+- char *tmp; /* FIXME */
++ struct net_device *dev = (struct net_device *)vcc->proto_data;
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
++ struct atmlec_msg *mesg;
++ struct lec_arp_table *entry;
++ int i;
++ char *tmp; /* FIXME */
+
+ atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+- mesg = (struct atmlec_msg *)skb->data;
+- tmp = skb->data;
+- tmp += sizeof(struct atmlec_msg);
+- DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
+- switch(mesg->type) {
+- case l_set_mac_addr:
+- for (i=0;i<6;i++) {
+- dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
+- }
+- break;
+- case l_del_mac_addr:
+- for(i=0;i<6;i++) {
+- dev->dev_addr[i] = 0;
+- }
+- break;
+- case l_addr_delete:
+- lec_addr_delete(priv, mesg->content.normal.atm_addr,
+- mesg->content.normal.flag);
+- break;
+- case l_topology_change:
+- priv->topology_change = mesg->content.normal.flag;
+- break;
+- case l_flush_complete:
+- lec_flush_complete(priv, mesg->content.normal.flag);
+- break;
+- case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
++ mesg = (struct atmlec_msg *)skb->data;
++ tmp = skb->data;
++ tmp += sizeof(struct atmlec_msg);
++ DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
++ switch (mesg->type) {
++ case l_set_mac_addr:
++ for (i = 0; i < 6; i++) {
++ dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
++ }
++ break;
++ case l_del_mac_addr:
++ for (i = 0; i < 6; i++) {
++ dev->dev_addr[i] = 0;
++ }
++ break;
++ case l_addr_delete:
++ lec_addr_delete(priv, mesg->content.normal.atm_addr,
++ mesg->content.normal.flag);
++ break;
++ case l_topology_change:
++ priv->topology_change = mesg->content.normal.flag;
++ break;
++ case l_flush_complete:
++ lec_flush_complete(priv, mesg->content.normal.flag);
++ break;
++ case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
+- lec_arp_remove(priv, entry);
++ entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
++ lec_arp_remove(priv, entry);
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+
+- if (mesg->content.normal.no_source_le_narp)
+- break;
+- /* FALL THROUGH */
+- case l_arp_update:
+- lec_arp_update(priv, mesg->content.normal.mac_addr,
+- mesg->content.normal.atm_addr,
+- mesg->content.normal.flag,
+- mesg->content.normal.targetless_le_arp);
+- DPRINTK("lec: in l_arp_update\n");
+- if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
+- DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs);
+- lane2_associate_ind(dev,
+- mesg->content.normal.mac_addr,
+- tmp, mesg->sizeoftlvs);
+- }
+- break;
+- case l_config:
+- priv->maximum_unknown_frame_count =
+- mesg->content.config.maximum_unknown_frame_count;
+- priv->max_unknown_frame_time =
+- (mesg->content.config.max_unknown_frame_time*HZ);
+- priv->max_retry_count =
+- mesg->content.config.max_retry_count;
+- priv->aging_time = (mesg->content.config.aging_time*HZ);
+- priv->forward_delay_time =
+- (mesg->content.config.forward_delay_time*HZ);
+- priv->arp_response_time =
+- (mesg->content.config.arp_response_time*HZ);
+- priv->flush_timeout = (mesg->content.config.flush_timeout*HZ);
+- priv->path_switching_delay =
+- (mesg->content.config.path_switching_delay*HZ);
+- priv->lane_version = mesg->content.config.lane_version; /* LANE2 */
++ if (mesg->content.normal.no_source_le_narp)
++ break;
++ /* FALL THROUGH */
++ case l_arp_update:
++ lec_arp_update(priv, mesg->content.normal.mac_addr,
++ mesg->content.normal.atm_addr,
++ mesg->content.normal.flag,
++ mesg->content.normal.targetless_le_arp);
++ DPRINTK("lec: in l_arp_update\n");
++ if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
++ DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n",
++ mesg->sizeoftlvs);
++ lane2_associate_ind(dev, mesg->content.normal.mac_addr,
++ tmp, mesg->sizeoftlvs);
++ }
++ break;
++ case l_config:
++ priv->maximum_unknown_frame_count =
++ mesg->content.config.maximum_unknown_frame_count;
++ priv->max_unknown_frame_time =
++ (mesg->content.config.max_unknown_frame_time * HZ);
++ priv->max_retry_count = mesg->content.config.max_retry_count;
++ priv->aging_time = (mesg->content.config.aging_time * HZ);
++ priv->forward_delay_time =
++ (mesg->content.config.forward_delay_time * HZ);
++ priv->arp_response_time =
++ (mesg->content.config.arp_response_time * HZ);
++ priv->flush_timeout = (mesg->content.config.flush_timeout * HZ);
++ priv->path_switching_delay =
++ (mesg->content.config.path_switching_delay * HZ);
++ priv->lane_version = mesg->content.config.lane_version; /* LANE2 */
+ priv->lane2_ops = NULL;
+ if (priv->lane_version > 1)
+ priv->lane2_ops = &lane2_ops;
+ if (dev->change_mtu(dev, mesg->content.config.mtu))
+ printk("%s: change_mtu to %d failed\n", dev->name,
+- mesg->content.config.mtu);
++ mesg->content.config.mtu);
+ priv->is_proxy = mesg->content.config.is_proxy;
+- break;
+- case l_flush_tran_id:
+- lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
+- mesg->content.normal.flag);
+- break;
+- case l_set_lecid:
+- priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag);
+- break;
+- case l_should_bridge: {
++ break;
++ case l_flush_tran_id:
++ lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
++ mesg->content.normal.flag);
++ break;
++ case l_set_lecid:
++ priv->lecid =
++ (unsigned short)(0xffff & mesg->content.normal.flag);
++ break;
++ case l_should_bridge:
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+- struct net_bridge_fdb_entry *f;
+-
+- DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+- dev->name,
+- mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1],
+- mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3],
+- mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]);
+-
+- if (br_fdb_get_hook == NULL || dev->br_port == NULL)
+- break;
+-
+- f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr);
+- if (f != NULL &&
+- f->dst->dev != dev &&
+- f->dst->state == BR_STATE_FORWARDING) {
+- /* hit from bridge table, send LE_ARP_RESPONSE */
+- struct sk_buff *skb2;
+- struct sock *sk;
+-
+- DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
+- skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+- if (skb2 == NULL) {
+- br_fdb_put_hook(f);
+- break;
+- }
+- skb2->len = sizeof(struct atmlec_msg);
+- memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk, skb2->len);
+- }
+- if (f != NULL) br_fdb_put_hook(f);
++ {
++ struct net_bridge_fdb_entry *f;
++
++ DPRINTK
++ ("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
++ dev->name, mesg->content.proxy.mac_addr[0],
++ mesg->content.proxy.mac_addr[1],
++ mesg->content.proxy.mac_addr[2],
++ mesg->content.proxy.mac_addr[3],
++ mesg->content.proxy.mac_addr[4],
++ mesg->content.proxy.mac_addr[5]);
++
++ if (br_fdb_get_hook == NULL || dev->br_port == NULL)
++ break;
++
++ f = br_fdb_get_hook(dev->br_port->br,
++ mesg->content.proxy.mac_addr);
++ if (f != NULL && f->dst->dev != dev
++ && f->dst->state == BR_STATE_FORWARDING) {
++ /* hit from bridge table, send LE_ARP_RESPONSE */
++ struct sk_buff *skb2;
++ struct sock *sk;
++
++ DPRINTK
++ ("%s: entry found, responding to zeppelin\n",
++ dev->name);
++ skb2 =
++ alloc_skb(sizeof(struct atmlec_msg),
++ GFP_ATOMIC);
++ if (skb2 == NULL) {
++ br_fdb_put_hook(f);
++ break;
++ }
++ skb2->len = sizeof(struct atmlec_msg);
++ memcpy(skb2->data, mesg,
++ sizeof(struct atmlec_msg));
++ atm_force_charge(priv->lecd, skb2->truesize);
++ sk = sk_atm(priv->lecd);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk, skb2->len);
++ }
++ if (f != NULL)
++ br_fdb_put_hook(f);
++ }
+ #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+- }
+- break;
+- default:
+- printk("%s: Unknown message type %d\n", dev->name, mesg->type);
+- dev_kfree_skb(skb);
+- return -EINVAL;
+- }
+- dev_kfree_skb(skb);
+- return 0;
++ break;
++ default:
++ printk("%s: Unknown message type %d\n", dev->name, mesg->type);
++ dev_kfree_skb(skb);
++ return -EINVAL;
++ }
++ dev_kfree_skb(skb);
++ return 0;
+ }
+
+-static void
+-lec_atm_close(struct atm_vcc *vcc)
++static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+- struct net_device *dev = (struct net_device *)vcc->proto_data;
+- struct lec_priv *priv = (struct lec_priv *)dev->priv;
++ struct sk_buff *skb;
++ struct net_device *dev = (struct net_device *)vcc->proto_data;
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+
+- priv->lecd = NULL;
+- /* Do something needful? */
++ priv->lecd = NULL;
++ /* Do something needful? */
+
+- netif_stop_queue(dev);
+- lec_arp_destroy(priv);
++ netif_stop_queue(dev);
++ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
++ if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+ printk("%s lec_atm_close: closing with messages pending\n",
+- dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
+- atm_return(vcc, skb->truesize);
++ dev->name);
++ while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
++ atm_return(vcc, skb->truesize);
+ dev_kfree_skb(skb);
+- }
+-
++ }
++
+ printk("%s: Shut down!\n", dev->name);
+- module_put(THIS_MODULE);
++ module_put(THIS_MODULE);
+ }
+
+ static struct atmdev_ops lecdev_ops = {
+- .close = lec_atm_close,
+- .send = lec_atm_send
++ .close = lec_atm_close,
++ .send = lec_atm_send
+ };
+
+ static struct atm_dev lecatm_dev = {
+- .ops = &lecdev_ops,
+- .type = "lec",
+- .number = 999, /* dummy device number */
+- .lock = SPIN_LOCK_UNLOCKED
++ .ops = &lecdev_ops,
++ .type = "lec",
++ .number = 999, /* dummy device number */
++ .lock = SPIN_LOCK_UNLOCKED
+ };
+
+ /*
+ * LANE2: new argument struct sk_buff *data contains
+ * the LE_ARP based TLVs introduced in the LANE2 spec
+ */
+-static int
+-send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+- unsigned char *mac_addr, unsigned char *atm_addr,
+- struct sk_buff *data)
++static int
++send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
++ unsigned char *mac_addr, unsigned char *atm_addr,
++ struct sk_buff *data)
+ {
+ struct sock *sk;
+ struct sk_buff *skb;
+@@ -621,187 +654,193 @@ send_to_lecd(struct lec_priv *priv, atml
+ return -1;
+ skb->len = sizeof(struct atmlec_msg);
+ mesg = (struct atmlec_msg *)skb->data;
+- memset(mesg, 0, sizeof(struct atmlec_msg));
++ memset(mesg, 0, sizeof(struct atmlec_msg));
+ mesg->type = type;
+- if (data != NULL)
+- mesg->sizeoftlvs = data->len;
++ if (data != NULL)
++ mesg->sizeoftlvs = data->len;
+ if (mac_addr)
+ memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN);
+- else
+- mesg->content.normal.targetless_le_arp = 1;
++ else
++ mesg->content.normal.targetless_le_arp = 1;
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
++ atm_force_charge(priv->lecd, skb->truesize);
+ sk = sk_atm(priv->lecd);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+- sk->sk_data_ready(sk, skb->len);
++ sk->sk_data_ready(sk, skb->len);
+
+- if (data != NULL) {
+- DPRINTK("lec: about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
+- skb_queue_tail(&sk->sk_receive_queue, data);
+- sk->sk_data_ready(sk, skb->len);
+- }
++ if (data != NULL) {
++ DPRINTK("lec: about to send %d bytes of data\n", data->len);
++ atm_force_charge(priv->lecd, data->truesize);
++ skb_queue_tail(&sk->sk_receive_queue, data);
++ sk->sk_data_ready(sk, skb->len);
++ }
+
+- return 0;
++ return 0;
+ }
+
+ /* shamelessly stolen from drivers/net/net_init.c */
+ static int lec_change_mtu(struct net_device *dev, int new_mtu)
+ {
+- if ((new_mtu < 68) || (new_mtu > 18190))
+- return -EINVAL;
+- dev->mtu = new_mtu;
+- return 0;
++ if ((new_mtu < 68) || (new_mtu > 18190))
++ return -EINVAL;
++ dev->mtu = new_mtu;
++ return 0;
+ }
+
+ static void lec_set_multicast_list(struct net_device *dev)
+ {
+- /* by default, all multicast frames arrive over the bus.
+- * eventually support selective multicast service
+- */
+- return;
++ /*
++ * by default, all multicast frames arrive over the bus.
++ * eventually support selective multicast service
++ */
++ return;
+ }
+
+-static void
+-lec_init(struct net_device *dev)
++static void lec_init(struct net_device *dev)
+ {
+- dev->change_mtu = lec_change_mtu;
+- dev->open = lec_open;
+- dev->stop = lec_close;
+- dev->hard_start_xmit = lec_start_xmit;
++ dev->change_mtu = lec_change_mtu;
++ dev->open = lec_open;
++ dev->stop = lec_close;
++ dev->hard_start_xmit = lec_start_xmit;
+ dev->tx_timeout = lec_tx_timeout;
+
+- dev->get_stats = lec_get_stats;
+- dev->set_multicast_list = lec_set_multicast_list;
+- dev->do_ioctl = NULL;
+- printk("%s: Initialized!\n",dev->name);
+- return;
++ dev->get_stats = lec_get_stats;
++ dev->set_multicast_list = lec_set_multicast_list;
++ dev->do_ioctl = NULL;
++ printk("%s: Initialized!\n", dev->name);
++ return;
+ }
+
+ static unsigned char lec_ctrl_magic[] = {
+- 0xff,
+- 0x00,
+- 0x01,
+- 0x01 };
++ 0xff,
++ 0x00,
++ 0x01,
++ 0x01
++};
+
+ #define LEC_DATA_DIRECT_8023 2
+ #define LEC_DATA_DIRECT_8025 3
+
+ static int lec_is_data_direct(struct atm_vcc *vcc)
+-{
++{
+ return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) ||
+ (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
+-}
++}
+
+-static void
+-lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
++static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+ {
+ unsigned long flags;
+- struct net_device *dev = (struct net_device *)vcc->proto_data;
+- struct lec_priv *priv = (struct lec_priv *)dev->priv;
++ struct net_device *dev = (struct net_device *)vcc->proto_data;
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+
+ #if DUMP_PACKETS >0
+- int i=0;
+- char buf[300];
++ int i = 0;
++ char buf[300];
+
+- printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
+- vcc->vpi, vcc->vci);
++ printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
++ vcc->vpi, vcc->vci);
+ #endif
+- if (!skb) {
+- DPRINTK("%s: null skb\n",dev->name);
+- lec_vcc_close(priv, vcc);
+- return;
+- }
++ if (!skb) {
++ DPRINTK("%s: null skb\n", dev->name);
++ lec_vcc_close(priv, vcc);
++ return;
++ }
+ #if DUMP_PACKETS > 0
+- printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
+- skb->len, priv->lecid);
++ printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
++ skb->len, priv->lecid);
+ #if DUMP_PACKETS >= 2
+- for(i=0;i<skb->len && i <99;i++) {
+- sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
+- }
++ for (i = 0; i < skb->len && i < 99; i++) {
++ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
++ }
+ #elif DUMP_PACKETS >= 1
+- for(i=0;i<skb->len && i < 30;i++) {
+- sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
+- }
++ for (i = 0; i < skb->len && i < 30; i++) {
++ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
++ }
+ #endif /* DUMP_PACKETS >= 1 */
+- if (i==skb->len)
+- printk("%s\n",buf);
+- else
+- printk("%s...\n",buf);
++ if (i == skb->len)
++ printk("%s\n", buf);
++ else
++ printk("%s...\n", buf);
+ #endif /* DUMP_PACKETS > 0 */
+- if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
++ if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */
+ struct sock *sk = sk_atm(vcc);
+
+- DPRINTK("%s: To daemon\n",dev->name);
+- skb_queue_tail(&sk->sk_receive_queue, skb);
+- sk->sk_data_ready(sk, skb->len);
+- } else { /* Data frame, queue to protocol handlers */
++ DPRINTK("%s: To daemon\n", dev->name);
++ skb_queue_tail(&sk->sk_receive_queue, skb);
++ sk->sk_data_ready(sk, skb->len);
++ } else { /* Data frame, queue to protocol handlers */
+ struct lec_arp_table *entry;
+- unsigned char *src, *dst;
+-
+- atm_return(vcc,skb->truesize);
+- if (*(uint16_t *)skb->data == htons(priv->lecid) ||
+- !priv->lecd ||
+- !(dev->flags & IFF_UP)) {
+- /* Probably looping back, or if lecd is missing,
+- lecd has gone down */
+- DPRINTK("Ignoring frame...\n");
+- dev_kfree_skb(skb);
+- return;
+- }
++ unsigned char *src, *dst;
++
++ atm_return(vcc, skb->truesize);
++ if (*(uint16_t *) skb->data == htons(priv->lecid) ||
++ !priv->lecd || !(dev->flags & IFF_UP)) {
++ /*
++ * Probably looping back, or if lecd is missing,
++ * lecd has gone down
++ */
++ DPRINTK("Ignoring frame...\n");
++ dev_kfree_skb(skb);
++ return;
++ }
+ #ifdef CONFIG_TR
+- if (priv->is_trdev)
+- dst = ((struct lecdatahdr_8025 *) skb->data)->h_dest;
+- else
++ if (priv->is_trdev)
++ dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
++ else
+ #endif
+- dst = ((struct lecdatahdr_8023 *) skb->data)->h_dest;
++ dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
+
+- /* If this is a Data Direct VCC, and the VCC does not match
++ /*
++ * If this is a Data Direct VCC, and the VCC does not match
+ * the LE_ARP cache entry, delete the LE_ARP cache entry.
+ */
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+ if (lec_is_data_direct(vcc)) {
+ #ifdef CONFIG_TR
+ if (priv->is_trdev)
+- src = ((struct lecdatahdr_8025 *) skb->data)->h_source;
++ src =
++ ((struct lecdatahdr_8025 *)skb->data)->
++ h_source;
+ else
+ #endif
+- src = ((struct lecdatahdr_8023 *) skb->data)->h_source;
++ src =
++ ((struct lecdatahdr_8023 *)skb->data)->
++ h_source;
+ entry = lec_arp_find(priv, src);
+ if (entry && entry->vcc != vcc) {
+ lec_arp_remove(priv, entry);
+- kfree(entry);
++ lec_arp_put(entry);
+ }
+ }
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+
+- if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */
+- !priv->is_proxy && /* Proxy wants all the packets */
++ if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */
++ !priv->is_proxy && /* Proxy wants all the packets */
+ memcmp(dst, dev->dev_addr, dev->addr_len)) {
+- dev_kfree_skb(skb);
+- return;
+- }
+- if (priv->lec_arp_empty_ones) {
+- lec_arp_check_empties(priv, vcc, skb);
+- }
+- skb->dev = dev;
+- skb_pull(skb, 2); /* skip lec_id */
++ dev_kfree_skb(skb);
++ return;
++ }
++ if (!hlist_empty(&priv->lec_arp_empty_ones)) {
++ lec_arp_check_empties(priv, vcc, skb);
++ }
++ skb->dev = dev;
++ skb_pull(skb, 2); /* skip lec_id */
+ #ifdef CONFIG_TR
+- if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
+- else
++ if (priv->is_trdev)
++ skb->protocol = tr_type_trans(skb, dev);
++ else
+ #endif
+- skb->protocol = eth_type_trans(skb, dev);
+- priv->stats.rx_packets++;
+- priv->stats.rx_bytes += skb->len;
+- memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
+- netif_rx(skb);
+- }
++ skb->protocol = eth_type_trans(skb, dev);
++ priv->stats.rx_packets++;
++ priv->stats.rx_bytes += skb->len;
++ memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
++ netif_rx(skb);
++ }
+ }
+
+-static void
+-lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
++static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+ {
+ struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
+ struct net_device *dev = skb->dev;
+@@ -820,123 +859,121 @@ lec_pop(struct atm_vcc *vcc, struct sk_b
+ }
+ }
+
+-static int
+-lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
++static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
+ {
+ struct lec_vcc_priv *vpriv;
+- int bytes_left;
+- struct atmlec_ioc ioc_data;
+-
+- /* Lecd must be up in this case */
+- bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
+- if (bytes_left != 0) {
+- printk("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
+- bytes_left);
+- }
+- if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
+- !dev_lec[ioc_data.dev_num])
+- return -EINVAL;
++ int bytes_left;
++ struct atmlec_ioc ioc_data;
++
++ /* Lecd must be up in this case */
++ bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
++ if (bytes_left != 0) {
++ printk
++ ("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
++ bytes_left);
++ }
++ if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
++ !dev_lec[ioc_data.dev_num])
++ return -EINVAL;
+ if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
+ return -ENOMEM;
+ vpriv->xoff = 0;
+ vpriv->old_pop = vcc->pop;
+ vcc->user_back = vpriv;
+ vcc->pop = lec_pop;
+- lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
+- &ioc_data, vcc, vcc->push);
+- vcc->proto_data = dev_lec[ioc_data.dev_num];
+- vcc->push = lec_push;
+- return 0;
++ lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
++ &ioc_data, vcc, vcc->push);
++ vcc->proto_data = dev_lec[ioc_data.dev_num];
++ vcc->push = lec_push;
++ return 0;
+ }
+
+-static int
+-lec_mcast_attach(struct atm_vcc *vcc, int arg)
++static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
+ {
+- if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
+- return -EINVAL;
+- vcc->proto_data = dev_lec[arg];
+- return (lec_mcast_make((struct lec_priv*)dev_lec[arg]->priv, vcc));
++ if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
++ return -EINVAL;
++ vcc->proto_data = dev_lec[arg];
++ return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));
+ }
+
+ /* Initialize device. */
+-static int
+-lecd_attach(struct atm_vcc *vcc, int arg)
+-{
+- int i;
+- struct lec_priv *priv;
+-
+- if (arg<0)
+- i = 0;
+- else
+- i = arg;
++static int lecd_attach(struct atm_vcc *vcc, int arg)
++{
++ int i;
++ struct lec_priv *priv;
++
++ if (arg < 0)
++ i = 0;
++ else
++ i = arg;
+ #ifdef CONFIG_TR
+- if (arg >= MAX_LEC_ITF)
+- return -EINVAL;
+-#else /* Reserve the top NUM_TR_DEVS for TR */
+- if (arg >= (MAX_LEC_ITF-NUM_TR_DEVS))
+- return -EINVAL;
++ if (arg >= MAX_LEC_ITF)
++ return -EINVAL;
++#else /* Reserve the top NUM_TR_DEVS for TR */
++ if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
++ return -EINVAL;
+ #endif
+- if (!dev_lec[i]) {
+- int is_trdev, size;
++ if (!dev_lec[i]) {
++ int is_trdev, size;
+
+- is_trdev = 0;
+- if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
+- is_trdev = 1;
++ is_trdev = 0;
++ if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
++ is_trdev = 1;
+
+- size = sizeof(struct lec_priv);
++ size = sizeof(struct lec_priv);
+ #ifdef CONFIG_TR
+- if (is_trdev)
+- dev_lec[i] = alloc_trdev(size);
+- else
++ if (is_trdev)
++ dev_lec[i] = alloc_trdev(size);
++ else
+ #endif
+- dev_lec[i] = alloc_etherdev(size);
+- if (!dev_lec[i])
+- return -ENOMEM;
+- snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
+- if (register_netdev(dev_lec[i])) {
+- free_netdev(dev_lec[i]);
+- return -EINVAL;
+- }
+-
+- priv = dev_lec[i]->priv;
+- priv->is_trdev = is_trdev;
+- lec_init(dev_lec[i]);
+- } else {
+- priv = dev_lec[i]->priv;
+- if (priv->lecd)
+- return -EADDRINUSE;
+- }
+- lec_arp_init(priv);
+- priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
+- vcc->dev = &lecatm_dev;
+- vcc_insert_socket(sk_atm(vcc));
+-
+- vcc->proto_data = dev_lec[i];
+- set_bit(ATM_VF_META,&vcc->flags);
+- set_bit(ATM_VF_READY,&vcc->flags);
+-
+- /* Set default values to these variables */
+- priv->maximum_unknown_frame_count = 1;
+- priv->max_unknown_frame_time = (1*HZ);
+- priv->vcc_timeout_period = (1200*HZ);
+- priv->max_retry_count = 1;
+- priv->aging_time = (300*HZ);
+- priv->forward_delay_time = (15*HZ);
+- priv->topology_change = 0;
+- priv->arp_response_time = (1*HZ);
+- priv->flush_timeout = (4*HZ);
+- priv->path_switching_delay = (6*HZ);
+-
+- if (dev_lec[i]->flags & IFF_UP) {
+- netif_start_queue(dev_lec[i]);
+- }
+- __module_get(THIS_MODULE);
+- return i;
++ dev_lec[i] = alloc_etherdev(size);
++ if (!dev_lec[i])
++ return -ENOMEM;
++ snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
++ if (register_netdev(dev_lec[i])) {
++ free_netdev(dev_lec[i]);
++ return -EINVAL;
++ }
++
++ priv = dev_lec[i]->priv;
++ priv->is_trdev = is_trdev;
++ lec_init(dev_lec[i]);
++ } else {
++ priv = dev_lec[i]->priv;
++ if (priv->lecd)
++ return -EADDRINUSE;
++ }
++ lec_arp_init(priv);
++ priv->itfnum = i; /* LANE2 addition */
++ priv->lecd = vcc;
++ vcc->dev = &lecatm_dev;
++ vcc_insert_socket(sk_atm(vcc));
++
++ vcc->proto_data = dev_lec[i];
++ set_bit(ATM_VF_META, &vcc->flags);
++ set_bit(ATM_VF_READY, &vcc->flags);
++
++ /* Set default values to these variables */
++ priv->maximum_unknown_frame_count = 1;
++ priv->max_unknown_frame_time = (1 * HZ);
++ priv->vcc_timeout_period = (1200 * HZ);
++ priv->max_retry_count = 1;
++ priv->aging_time = (300 * HZ);
++ priv->forward_delay_time = (15 * HZ);
++ priv->topology_change = 0;
++ priv->arp_response_time = (1 * HZ);
++ priv->flush_timeout = (4 * HZ);
++ priv->path_switching_delay = (6 * HZ);
++
++ if (dev_lec[i]->flags & IFF_UP) {
++ netif_start_queue(dev_lec[i]);
++ }
++ __module_get(THIS_MODULE);
++ return i;
+ }
+
+ #ifdef CONFIG_PROC_FS
+-static char* lec_arp_get_status_string(unsigned char status)
++static char *lec_arp_get_status_string(unsigned char status)
+ {
+ static char *lec_arp_status_string[] = {
+ "ESI_UNKNOWN ",
+@@ -966,52 +1003,54 @@ static void lec_info(struct seq_file *se
+ if (entry->vcc)
+ seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
+ else
+- seq_printf(seq, " ");
++ seq_printf(seq, " ");
+ if (entry->recv_vcc) {
+ seq_printf(seq, " %3d %3d", entry->recv_vcc->vpi,
+ entry->recv_vcc->vci);
+- }
+- seq_putc(seq, '\n');
++ }
++ seq_putc(seq, '\n');
+ }
+
+-
+ struct lec_state {
+ unsigned long flags;
+ struct lec_priv *locked;
+- struct lec_arp_table *entry;
++ struct hlist_node *node;
+ struct net_device *dev;
+ int itf;
+ int arp_table;
+ int misc_table;
+ };
+
+-static void *lec_tbl_walk(struct lec_state *state, struct lec_arp_table *tbl,
++static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
+ loff_t *l)
+ {
+- struct lec_arp_table *e = state->entry;
++ struct hlist_node *e = state->node;
++ struct lec_arp_table *tmp;
+
+ if (!e)
+- e = tbl;
++ e = tbl->first;
+ if (e == (void *)1) {
+- e = tbl;
++ e = tbl->first;
+ --*l;
+ }
+- for (; e; e = e->next) {
++
++ hlist_for_each_entry_from(tmp, e, next) {
+ if (--*l < 0)
+ break;
+ }
+- state->entry = e;
++ state->node = e;
++
+ return (*l < 0) ? state : NULL;
+ }
+
+ static void *lec_arp_walk(struct lec_state *state, loff_t *l,
+- struct lec_priv *priv)
++ struct lec_priv *priv)
+ {
+ void *v = NULL;
+ int p;
+
+ for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
+- v = lec_tbl_walk(state, priv->lec_arp_tables[p], l);
++ v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l);
+ if (v)
+ break;
+ }
+@@ -1022,10 +1061,10 @@ static void *lec_arp_walk(struct lec_sta
+ static void *lec_misc_walk(struct lec_state *state, loff_t *l,
+ struct lec_priv *priv)
+ {
+- struct lec_arp_table *lec_misc_tables[] = {
+- priv->lec_arp_empty_ones,
+- priv->lec_no_forward,
+- priv->mcast_fwds
++ struct hlist_head *lec_misc_tables[] = {
++ &priv->lec_arp_empty_ones,
++ &priv->lec_no_forward,
++ &priv->mcast_fwds
+ };
+ void *v = NULL;
+ int q;
+@@ -1046,8 +1085,7 @@ static void *lec_priv_walk(struct lec_st
+ state->locked = priv;
+ spin_lock_irqsave(&priv->lec_arp_lock, state->flags);
+ }
+- if (!lec_arp_walk(state, l, priv) &&
+- !lec_misc_walk(state, l, priv)) {
++ if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
+ spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags);
+ state->locked = NULL;
+ /* Partial state reset for the next time we get called */
+@@ -1081,7 +1119,7 @@ static void *lec_get_idx(struct lec_stat
+ if (v)
+ break;
+ }
+- return v;
++ return v;
+ }
+
+ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
+@@ -1093,9 +1131,9 @@ static void *lec_seq_start(struct seq_fi
+ state->locked = NULL;
+ state->arp_table = 0;
+ state->misc_table = 0;
+- state->entry = (void *)1;
++ state->node = (void *)1;
+
+- return *pos ? lec_get_idx(state, *pos) : (void*)1;
++ return *pos ? lec_get_idx(state, *pos) : (void *)1;
+ }
+
+ static void lec_seq_stop(struct seq_file *seq, void *v)
+@@ -1120,27 +1158,28 @@ static void *lec_seq_next(struct seq_fil
+
+ static int lec_seq_show(struct seq_file *seq, void *v)
+ {
+- static char lec_banner[] = "Itf MAC ATM destination"
+- " Status Flags "
+- "VPI/VCI Recv VPI/VCI\n";
++ static char lec_banner[] = "Itf MAC ATM destination"
++ " Status Flags "
++ "VPI/VCI Recv VPI/VCI\n";
+
+ if (v == (void *)1)
+ seq_puts(seq, lec_banner);
+ else {
+ struct lec_state *state = seq->private;
+- struct net_device *dev = state->dev;
++ struct net_device *dev = state->dev;
++ struct lec_arp_table *entry = hlist_entry(state->node, struct lec_arp_table, next);
+
+ seq_printf(seq, "%s ", dev->name);
+- lec_info(seq, state->entry);
++ lec_info(seq, entry);
+ }
+ return 0;
+ }
+
+ static struct seq_operations lec_seq_ops = {
+- .start = lec_seq_start,
+- .next = lec_seq_next,
+- .stop = lec_seq_stop,
+- .show = lec_seq_show,
++ .start = lec_seq_start,
++ .next = lec_seq_next,
++ .stop = lec_seq_stop,
++ .show = lec_seq_show,
+ };
+
+ static int lec_seq_open(struct inode *inode, struct file *file)
+@@ -1174,11 +1213,11 @@ static int lec_seq_release(struct inode
+ }
+
+ static struct file_operations lec_seq_fops = {
+- .owner = THIS_MODULE,
+- .open = lec_seq_open,
+- .read = seq_read,
+- .llseek = seq_lseek,
+- .release = lec_seq_release,
++ .owner = THIS_MODULE,
++ .open = lec_seq_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = lec_seq_release,
+ };
+ #endif
+
+@@ -1186,38 +1225,38 @@ static int lane_ioctl(struct socket *soc
+ {
+ struct atm_vcc *vcc = ATM_SD(sock);
+ int err = 0;
+-
++
+ switch (cmd) {
+- case ATMLEC_CTRL:
+- case ATMLEC_MCAST:
+- case ATMLEC_DATA:
+- if (!capable(CAP_NET_ADMIN))
+- return -EPERM;
+- break;
+- default:
+- return -ENOIOCTLCMD;
++ case ATMLEC_CTRL:
++ case ATMLEC_MCAST:
++ case ATMLEC_DATA:
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ break;
++ default:
++ return -ENOIOCTLCMD;
+ }
+
+ switch (cmd) {
+- case ATMLEC_CTRL:
+- err = lecd_attach(vcc, (int) arg);
+- if (err >= 0)
+- sock->state = SS_CONNECTED;
+- break;
+- case ATMLEC_MCAST:
+- err = lec_mcast_attach(vcc, (int) arg);
+- break;
+- case ATMLEC_DATA:
+- err = lec_vcc_attach(vcc, (void __user *) arg);
+- break;
++ case ATMLEC_CTRL:
++ err = lecd_attach(vcc, (int)arg);
++ if (err >= 0)
++ sock->state = SS_CONNECTED;
++ break;
++ case ATMLEC_MCAST:
++ err = lec_mcast_attach(vcc, (int)arg);
++ break;
++ case ATMLEC_DATA:
++ err = lec_vcc_attach(vcc, (void __user *)arg);
++ break;
+ }
+
+ return err;
+ }
+
+ static struct atm_ioctl lane_ioctl_ops = {
+- .owner = THIS_MODULE,
+- .ioctl = lane_ioctl,
++ .owner = THIS_MODULE,
++ .ioctl = lane_ioctl,
+ };
+
+ static int __init lane_module_init(void)
+@@ -1231,29 +1270,29 @@ static int __init lane_module_init(void)
+ #endif
+
+ register_atm_ioctl(&lane_ioctl_ops);
+- printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+- return 0;
++ printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
++ return 0;
+ }
+
+ static void __exit lane_module_cleanup(void)
+ {
+- int i;
+- struct lec_priv *priv;
++ int i;
++ struct lec_priv *priv;
+
+ remove_proc_entry("lec", atm_proc_root);
+
+ deregister_atm_ioctl(&lane_ioctl_ops);
+
+- for (i = 0; i < MAX_LEC_ITF; i++) {
+- if (dev_lec[i] != NULL) {
+- priv = (struct lec_priv *)dev_lec[i]->priv;
++ for (i = 0; i < MAX_LEC_ITF; i++) {
++ if (dev_lec[i] != NULL) {
++ priv = (struct lec_priv *)dev_lec[i]->priv;
+ unregister_netdev(dev_lec[i]);
+- free_netdev(dev_lec[i]);
+- dev_lec[i] = NULL;
+- }
+- }
++ free_netdev(dev_lec[i]);
++ dev_lec[i] = NULL;
++ }
++ }
+
+- return;
++ return;
+ }
+
+ module_init(lane_module_init);
+@@ -1267,34 +1306,34 @@ module_exit(lane_module_cleanup);
+ * If dst_mac == NULL, targetless LE_ARP will be sent
+ */
+ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
+- u8 **tlvs, u32 *sizeoftlvs)
++ u8 **tlvs, u32 *sizeoftlvs)
+ {
+ unsigned long flags;
+- struct lec_priv *priv = (struct lec_priv *)dev->priv;
+- struct lec_arp_table *table;
+- struct sk_buff *skb;
+- int retval;
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
++ struct lec_arp_table *table;
++ struct sk_buff *skb;
++ int retval;
+
+- if (force == 0) {
++ if (force == 0) {
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- table = lec_arp_find(priv, dst_mac);
++ table = lec_arp_find(priv, dst_mac);
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+- if(table == NULL)
+- return -1;
+-
+- *tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
+- if (*tlvs == NULL)
+- return -1;
+-
+- memcpy(*tlvs, table->tlvs, table->sizeoftlvs);
+- *sizeoftlvs = table->sizeoftlvs;
+-
+- return 0;
+- }
++ if (table == NULL)
++ return -1;
++
++ *tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
++ if (*tlvs == NULL)
++ return -1;
++
++ memcpy(*tlvs, table->tlvs, table->sizeoftlvs);
++ *sizeoftlvs = table->sizeoftlvs;
++
++ return 0;
++ }
+
+ if (sizeoftlvs == NULL)
+ retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL);
+-
++
+ else {
+ skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC);
+ if (skb == NULL)
+@@ -1303,9 +1342,8 @@ static int lane2_resolve(struct net_devi
+ memcpy(skb->data, *tlvs, *sizeoftlvs);
+ retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
+ }
+- return retval;
+-}
+-
++ return retval;
++}
+
+ /*
+ * LANE2: 3.1.4, LE_ASSOCIATE.request
+@@ -1314,80 +1352,85 @@ static int lane2_resolve(struct net_devi
+ * Returns 1 for success, 0 for failure (out of memory)
+ *
+ */
+-static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
+- u8 *tlvs, u32 sizeoftlvs)
++static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
++ u8 *tlvs, u32 sizeoftlvs)
+ {
+- int retval;
+- struct sk_buff *skb;
+- struct lec_priv *priv = (struct lec_priv*)dev->priv;
+-
+- if (compare_ether_addr(lan_dst, dev->dev_addr))
+- return (0); /* not our mac address */
+-
+- kfree(priv->tlvs); /* NULL if there was no previous association */
+-
+- priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
+- if (priv->tlvs == NULL)
+- return (0);
+- priv->sizeoftlvs = sizeoftlvs;
+- memcpy(priv->tlvs, tlvs, sizeoftlvs);
+-
+- skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
+- if (skb == NULL)
+- return 0;
+- skb->len = sizeoftlvs;
+- memcpy(skb->data, tlvs, sizeoftlvs);
+- retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
+- if (retval != 0)
+- printk("lec.c: lane2_associate_req() failed\n");
+- /* If the previous association has changed we must
+- * somehow notify other LANE entities about the change
+- */
+- return (1);
++ int retval;
++ struct sk_buff *skb;
++ struct lec_priv *priv = (struct lec_priv *)dev->priv;
++
++ if (compare_ether_addr(lan_dst, dev->dev_addr))
++ return (0); /* not our mac address */
++
++ kfree(priv->tlvs); /* NULL if there was no previous association */
++
++ priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
++ if (priv->tlvs == NULL)
++ return (0);
++ priv->sizeoftlvs = sizeoftlvs;
++ memcpy(priv->tlvs, tlvs, sizeoftlvs);
++
++ skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
++ if (skb == NULL)
++ return 0;
++ skb->len = sizeoftlvs;
++ memcpy(skb->data, tlvs, sizeoftlvs);
++ retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
++ if (retval != 0)
++ printk("lec.c: lane2_associate_req() failed\n");
++ /*
++ * If the previous association has changed we must
++ * somehow notify other LANE entities about the change
++ */
++ return (1);
+ }
+
+ /*
+ * LANE2: 3.1.5, LE_ASSOCIATE.indication
+ *
+ */
+-static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
+- u8 *tlvs, u32 sizeoftlvs)
++static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr,
++ u8 *tlvs, u32 sizeoftlvs)
+ {
+ #if 0
+- int i = 0;
++ int i = 0;
+ #endif
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+-#if 0 /* Why have the TLVs in LE_ARP entries since we do not use them? When you
+- uncomment this code, make sure the TLVs get freed when entry is killed */
+- struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
++#if 0 /*
++ * Why have the TLVs in LE_ARP entries
++ * since we do not use them? When you
++ * uncomment this code, make sure the
++ * TLVs get freed when entry is killed
++ */
++ struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
+
+- if (entry == NULL)
+- return; /* should not happen */
++ if (entry == NULL)
++ return; /* should not happen */
+
+- kfree(entry->tlvs);
++ kfree(entry->tlvs);
+
+- entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
+- if (entry->tlvs == NULL)
+- return;
++ entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
++ if (entry->tlvs == NULL)
++ return;
+
+- entry->sizeoftlvs = sizeoftlvs;
+- memcpy(entry->tlvs, tlvs, sizeoftlvs);
++ entry->sizeoftlvs = sizeoftlvs;
++ memcpy(entry->tlvs, tlvs, sizeoftlvs);
+ #endif
+ #if 0
+- printk("lec.c: lane2_associate_ind()\n");
+- printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
+- while (i < sizeoftlvs)
+- printk("%02x ", tlvs[i++]);
+-
+- printk("\n");
++ printk("lec.c: lane2_associate_ind()\n");
++ printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
++ while (i < sizeoftlvs)
++ printk("%02x ", tlvs[i++]);
++
++ printk("\n");
+ #endif
+
+- /* tell MPOA about the TLVs we saw */
+- if (priv->lane2_ops && priv->lane2_ops->associate_indicator) {
+- priv->lane2_ops->associate_indicator(dev, mac_addr,
+- tlvs, sizeoftlvs);
+- }
+- return;
++ /* tell MPOA about the TLVs we saw */
++ if (priv->lane2_ops && priv->lane2_ops->associate_indicator) {
++ priv->lane2_ops->associate_indicator(dev, mac_addr,
++ tlvs, sizeoftlvs);
++ }
++ return;
+ }
+
+ /*
+@@ -1395,7 +1438,6 @@ static void lane2_associate_ind (struct
+ *
+ * lec_arpc.c was added here when making
+ * lane client modular. October 1997
+- *
+ */
+
+ #include <linux/types.h>
+@@ -1406,7 +1448,6 @@ static void lane2_associate_ind (struct
+ #include <linux/inetdevice.h>
+ #include <net/route.h>
+
+-
+ #if 0
+ #define DPRINTK(format,args...)
+ /*
+@@ -1417,7 +1458,7 @@ static void lane2_associate_ind (struct
+
+ #define LEC_ARP_REFRESH_INTERVAL (3*HZ)
+
+-static void lec_arp_check_expire(unsigned long data);
++static void lec_arp_check_expire(void *data);
+ static void lec_arp_expire_arp(unsigned long data);
+
+ /*
+@@ -1429,474 +1470,397 @@ static void lec_arp_expire_arp(unsigned
+ /*
+ * Initialization of arp-cache
+ */
+-static void
+-lec_arp_init(struct lec_priv *priv)
++static void lec_arp_init(struct lec_priv *priv)
+ {
+- unsigned short i;
++ unsigned short i;
+
+- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- priv->lec_arp_tables[i] = NULL;
+- }
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
++ }
++ INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
++ INIT_HLIST_HEAD(&priv->lec_no_forward);
++ INIT_HLIST_HEAD(&priv->mcast_fwds);
+ spin_lock_init(&priv->lec_arp_lock);
+- init_timer(&priv->lec_arp_timer);
+- priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
+- priv->lec_arp_timer.data = (unsigned long)priv;
+- priv->lec_arp_timer.function = lec_arp_check_expire;
+- add_timer(&priv->lec_arp_timer);
++ INIT_WORK(&priv->lec_arp_work, lec_arp_check_expire, priv);
++ schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
+ }
+
+-static void
+-lec_arp_clear_vccs(struct lec_arp_table *entry)
++static void lec_arp_clear_vccs(struct lec_arp_table *entry)
+ {
+- if (entry->vcc) {
++ if (entry->vcc) {
+ struct atm_vcc *vcc = entry->vcc;
+ struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
+- struct net_device *dev = (struct net_device*) vcc->proto_data;
++ struct net_device *dev = (struct net_device *)vcc->proto_data;
+
+- vcc->pop = vpriv->old_pop;
++ vcc->pop = vpriv->old_pop;
+ if (vpriv->xoff)
+ netif_wake_queue(dev);
+ kfree(vpriv);
+ vcc->user_back = NULL;
+- vcc->push = entry->old_push;
++ vcc->push = entry->old_push;
+ vcc_release_async(vcc, -EPIPE);
+- vcc = NULL;
+- }
+- if (entry->recv_vcc) {
+- entry->recv_vcc->push = entry->old_recv_push;
++ entry->vcc = NULL;
++ }
++ if (entry->recv_vcc) {
++ entry->recv_vcc->push = entry->old_recv_push;
+ vcc_release_async(entry->recv_vcc, -EPIPE);
+- entry->recv_vcc = NULL;
+- }
++ entry->recv_vcc = NULL;
++ }
+ }
+
+ /*
+ * Insert entry to lec_arp_table
+ * LANE2: Add to the end of the list to satisfy 8.1.13
+ */
+-static inline void
+-lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
++static inline void
++lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
+ {
+- unsigned short place;
+- struct lec_arp_table *tmp;
+-
+- place = HASH(to_add->mac_addr[ETH_ALEN-1]);
+- tmp = priv->lec_arp_tables[place];
+- to_add->next = NULL;
+- if (tmp == NULL)
+- priv->lec_arp_tables[place] = to_add;
+-
+- else { /* add to the end */
+- while (tmp->next)
+- tmp = tmp->next;
+- tmp->next = to_add;
+- }
+-
+- DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+- 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
+- 0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
+- 0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
++ struct hlist_head *tmp;
++
++ tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];
++ hlist_add_head(&entry->next, tmp);
++
++ DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
++ 0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1],
++ 0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3],
++ 0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]);
+ }
+
+ /*
+ * Remove entry from lec_arp_table
+ */
+-static int
+-lec_arp_remove(struct lec_priv *priv,
+- struct lec_arp_table *to_remove)
++static int
++lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
+ {
+- unsigned short place;
+- struct lec_arp_table *tmp;
+- int remove_vcc=1;
+-
+- if (!to_remove) {
+- return -1;
+- }
+- place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
+- tmp = priv->lec_arp_tables[place];
+- if (tmp == to_remove) {
+- priv->lec_arp_tables[place] = tmp->next;
+- } else {
+- while(tmp && tmp->next != to_remove) {
+- tmp = tmp->next;
+- }
+- if (!tmp) {/* Entry was not found */
+- return -1;
+- }
+- }
+- tmp->next = to_remove->next;
+- del_timer(&to_remove->timer);
+-
+- /* If this is the only MAC connected to this VCC, also tear down
+- the VCC */
+- if (to_remove->status >= ESI_FLUSH_PENDING) {
+- /*
+- * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
+- */
+- for(place = 0; place < LEC_ARP_TABLE_SIZE; place++) {
+- for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
+- if (memcmp(tmp->atm_addr, to_remove->atm_addr,
+- ATM_ESA_LEN)==0) {
+- remove_vcc=0;
+- break;
+- }
+- }
+- }
+- if (remove_vcc)
+- lec_arp_clear_vccs(to_remove);
+- }
+- skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
+-
+- DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+- 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
+- 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
+- 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]);
+- return 0;
++ struct hlist_node *node;
++ struct lec_arp_table *entry;
++ int i, remove_vcc = 1;
++
++ if (!to_remove) {
++ return -1;
++ }
++
++ hlist_del(&to_remove->next);
++ del_timer(&to_remove->timer);
++
++ /* If this is the only MAC connected to this VCC, also tear down the VCC */
++ if (to_remove->status >= ESI_FLUSH_PENDING) {
++ /*
++ * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
++ */
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
++ if (memcmp(to_remove->atm_addr,
++ entry->atm_addr, ATM_ESA_LEN) == 0) {
++ remove_vcc = 0;
++ break;
++ }
++ }
++ }
++ if (remove_vcc)
++ lec_arp_clear_vccs(to_remove);
++ }
++ skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
++
++ DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
++ 0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1],
++ 0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3],
++ 0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]);
++ return 0;
+ }
+
+ #if DEBUG_ARP_TABLE
+-static char*
+-get_status_string(unsigned char st)
++static char *get_status_string(unsigned char st)
+ {
+- switch(st) {
+- case ESI_UNKNOWN:
+- return "ESI_UNKNOWN";
+- case ESI_ARP_PENDING:
+- return "ESI_ARP_PENDING";
+- case ESI_VC_PENDING:
+- return "ESI_VC_PENDING";
+- case ESI_FLUSH_PENDING:
+- return "ESI_FLUSH_PENDING";
+- case ESI_FORWARD_DIRECT:
+- return "ESI_FORWARD_DIRECT";
+- default:
+- return "<UNKNOWN>";
+- }
++ switch (st) {
++ case ESI_UNKNOWN:
++ return "ESI_UNKNOWN";
++ case ESI_ARP_PENDING:
++ return "ESI_ARP_PENDING";
++ case ESI_VC_PENDING:
++ return "ESI_VC_PENDING";
++ case ESI_FLUSH_PENDING:
++ return "ESI_FLUSH_PENDING";
++ case ESI_FORWARD_DIRECT:
++ return "ESI_FORWARD_DIRECT";
++ default:
++ return "<UNKNOWN>";
++ }
+ }
+-#endif
+
+-static void
+-dump_arp_table(struct lec_priv *priv)
++static void dump_arp_table(struct lec_priv *priv)
+ {
+-#if DEBUG_ARP_TABLE
+- int i,j, offset;
+- struct lec_arp_table *rulla;
+- char buf[1024];
+- struct lec_arp_table **lec_arp_tables =
+- (struct lec_arp_table **)priv->lec_arp_tables;
+- struct lec_arp_table *lec_arp_empty_ones =
+- (struct lec_arp_table *)priv->lec_arp_empty_ones;
+- struct lec_arp_table *lec_no_forward =
+- (struct lec_arp_table *)priv->lec_no_forward;
+- struct lec_arp_table *mcast_fwds = priv->mcast_fwds;
+-
+-
+- printk("Dump %p:\n",priv);
+- for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+- rulla = lec_arp_tables[i];
+- offset = 0;
+- offset += sprintf(buf,"%d: %p\n",i, rulla);
+- while (rulla) {
+- offset += sprintf(buf+offset,"Mac:");
+- for(j=0;j<ETH_ALEN;j++) {
+- offset+=sprintf(buf+offset,
+- "%2.2x ",
+- rulla->mac_addr[j]&0xff);
+- }
+- offset +=sprintf(buf+offset,"Atm:");
+- for(j=0;j<ATM_ESA_LEN;j++) {
+- offset+=sprintf(buf+offset,
+- "%2.2x ",
+- rulla->atm_addr[j]&0xff);
+- }
+- offset+=sprintf(buf+offset,
+- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+- rulla->vcc?rulla->vcc->vpi:0,
+- rulla->vcc?rulla->vcc->vci:0,
+- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
+- rulla->recv_vcc?rulla->recv_vcc->vci:0,
+- rulla->last_used,
+- rulla->timestamp, rulla->no_tries);
+- offset+=sprintf(buf+offset,
+- "Flags:%x, Packets_flooded:%x, Status: %s ",
+- rulla->flags, rulla->packets_flooded,
+- get_status_string(rulla->status));
+- offset+=sprintf(buf+offset,"->%p\n",rulla->next);
+- rulla = rulla->next;
+- }
+- printk("%s",buf);
+- }
+- rulla = lec_no_forward;
+- if (rulla)
+- printk("No forward\n");
+- while(rulla) {
+- offset=0;
+- offset += sprintf(buf+offset,"Mac:");
+- for(j=0;j<ETH_ALEN;j++) {
+- offset+=sprintf(buf+offset,"%2.2x ",
+- rulla->mac_addr[j]&0xff);
+- }
+- offset +=sprintf(buf+offset,"Atm:");
+- for(j=0;j<ATM_ESA_LEN;j++) {
+- offset+=sprintf(buf+offset,"%2.2x ",
+- rulla->atm_addr[j]&0xff);
+- }
+- offset+=sprintf(buf+offset,
+- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+- rulla->vcc?rulla->vcc->vpi:0,
+- rulla->vcc?rulla->vcc->vci:0,
+- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
+- rulla->recv_vcc?rulla->recv_vcc->vci:0,
+- rulla->last_used,
+- rulla->timestamp, rulla->no_tries);
+- offset+=sprintf(buf+offset,
+- "Flags:%x, Packets_flooded:%x, Status: %s ",
+- rulla->flags, rulla->packets_flooded,
+- get_status_string(rulla->status));
+- offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
+- rulla = rulla->next;
+- printk("%s",buf);
+- }
+- rulla = lec_arp_empty_ones;
+- if (rulla)
+- printk("Empty ones\n");
+- while(rulla) {
+- offset=0;
+- offset += sprintf(buf+offset,"Mac:");
+- for(j=0;j<ETH_ALEN;j++) {
+- offset+=sprintf(buf+offset,"%2.2x ",
+- rulla->mac_addr[j]&0xff);
+- }
+- offset +=sprintf(buf+offset,"Atm:");
+- for(j=0;j<ATM_ESA_LEN;j++) {
+- offset+=sprintf(buf+offset,"%2.2x ",
+- rulla->atm_addr[j]&0xff);
+- }
+- offset+=sprintf(buf+offset,
+- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+- rulla->vcc?rulla->vcc->vpi:0,
+- rulla->vcc?rulla->vcc->vci:0,
+- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
+- rulla->recv_vcc?rulla->recv_vcc->vci:0,
+- rulla->last_used,
+- rulla->timestamp, rulla->no_tries);
+- offset+=sprintf(buf+offset,
+- "Flags:%x, Packets_flooded:%x, Status: %s ",
+- rulla->flags, rulla->packets_flooded,
+- get_status_string(rulla->status));
+- offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
+- rulla = rulla->next;
+- printk("%s",buf);
+- }
+-
+- rulla = mcast_fwds;
+- if (rulla)
+- printk("Multicast Forward VCCs\n");
+- while(rulla) {
+- offset=0;
+- offset += sprintf(buf+offset,"Mac:");
+- for(j=0;j<ETH_ALEN;j++) {
+- offset+=sprintf(buf+offset,"%2.2x ",
+- rulla->mac_addr[j]&0xff);
+- }
+- offset +=sprintf(buf+offset,"Atm:");
+- for(j=0;j<ATM_ESA_LEN;j++) {
+- offset+=sprintf(buf+offset,"%2.2x ",
+- rulla->atm_addr[j]&0xff);
+- }
+- offset+=sprintf(buf+offset,
+- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+- rulla->vcc?rulla->vcc->vpi:0,
+- rulla->vcc?rulla->vcc->vci:0,
+- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
+- rulla->recv_vcc?rulla->recv_vcc->vci:0,
+- rulla->last_used,
+- rulla->timestamp, rulla->no_tries);
+- offset+=sprintf(buf+offset,
+- "Flags:%x, Packets_flooded:%x, Status: %s ",
+- rulla->flags, rulla->packets_flooded,
+- get_status_string(rulla->status));
+- offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
+- rulla = rulla->next;
+- printk("%s",buf);
+- }
++ struct hlist_node *node;
++ struct lec_arp_table *rulla;
++ char buf[256];
++ int i, j, offset;
++
++ printk("Dump %p:\n", priv);
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry(rulla, node, &priv->lec_arp_tables[i], next) {
++ offset = 0;
++ offset += sprintf(buf, "%d: %p\n", i, rulla);
++ offset += sprintf(buf + offset, "Mac:");
++ for (j = 0; j < ETH_ALEN; j++) {
++ offset += sprintf(buf + offset,
++ "%2.2x ",
++ rulla->mac_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset, "Atm:");
++ for (j = 0; j < ATM_ESA_LEN; j++) {
++ offset += sprintf(buf + offset,
++ "%2.2x ",
++ rulla->atm_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset,
++ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
++ rulla->vcc ? rulla->vcc->vpi : 0,
++ rulla->vcc ? rulla->vcc->vci : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->
++ vpi : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->
++ vci : 0, rulla->last_used,
++ rulla->timestamp, rulla->no_tries);
++ offset +=
++ sprintf(buf + offset,
++ "Flags:%x, Packets_flooded:%x, Status: %s ",
++ rulla->flags, rulla->packets_flooded,
++ get_status_string(rulla->status));
++ printk("%s\n", buf);
++ }
++ }
++
++ if (!hlist_empty(&priv->lec_no_forward))
++ printk("No forward\n");
++ hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) {
++ offset = 0;
++ offset += sprintf(buf + offset, "Mac:");
++ for (j = 0; j < ETH_ALEN; j++) {
++ offset += sprintf(buf + offset, "%2.2x ",
++ rulla->mac_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset, "Atm:");
++ for (j = 0; j < ATM_ESA_LEN; j++) {
++ offset += sprintf(buf + offset, "%2.2x ",
++ rulla->atm_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset,
++ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
++ rulla->vcc ? rulla->vcc->vpi : 0,
++ rulla->vcc ? rulla->vcc->vci : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
++ rulla->last_used,
++ rulla->timestamp, rulla->no_tries);
++ offset += sprintf(buf + offset,
++ "Flags:%x, Packets_flooded:%x, Status: %s ",
++ rulla->flags, rulla->packets_flooded,
++ get_status_string(rulla->status));
++ printk("%s\n", buf);
++ }
++
++ if (!hlist_empty(&priv->lec_arp_empty_ones))
++ printk("Empty ones\n");
++ hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) {
++ offset = 0;
++ offset += sprintf(buf + offset, "Mac:");
++ for (j = 0; j < ETH_ALEN; j++) {
++ offset += sprintf(buf + offset, "%2.2x ",
++ rulla->mac_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset, "Atm:");
++ for (j = 0; j < ATM_ESA_LEN; j++) {
++ offset += sprintf(buf + offset, "%2.2x ",
++ rulla->atm_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset,
++ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
++ rulla->vcc ? rulla->vcc->vpi : 0,
++ rulla->vcc ? rulla->vcc->vci : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
++ rulla->last_used,
++ rulla->timestamp, rulla->no_tries);
++ offset += sprintf(buf + offset,
++ "Flags:%x, Packets_flooded:%x, Status: %s ",
++ rulla->flags, rulla->packets_flooded,
++ get_status_string(rulla->status));
++ printk("%s", buf);
++ }
++
++ if (!hlist_empty(&priv->mcast_fwds))
++ printk("Multicast Forward VCCs\n");
++ hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) {
++ offset = 0;
++ offset += sprintf(buf + offset, "Mac:");
++ for (j = 0; j < ETH_ALEN; j++) {
++ offset += sprintf(buf + offset, "%2.2x ",
++ rulla->mac_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset, "Atm:");
++ for (j = 0; j < ATM_ESA_LEN; j++) {
++ offset += sprintf(buf + offset, "%2.2x ",
++ rulla->atm_addr[j] & 0xff);
++ }
++ offset += sprintf(buf + offset,
++ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
++ rulla->vcc ? rulla->vcc->vpi : 0,
++ rulla->vcc ? rulla->vcc->vci : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
++ rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
++ rulla->last_used,
++ rulla->timestamp, rulla->no_tries);
++ offset += sprintf(buf + offset,
++ "Flags:%x, Packets_flooded:%x, Status: %s ",
++ rulla->flags, rulla->packets_flooded,
++ get_status_string(rulla->status));
++ printk("%s\n", buf);
++ }
+
+-#endif
+ }
++#else
++#define dump_arp_table(priv) do { } while (0)
++#endif
+
+ /*
+ * Destruction of arp-cache
+ */
+-static void
+-lec_arp_destroy(struct lec_priv *priv)
++static void lec_arp_destroy(struct lec_priv *priv)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry, *next;
+- int i;
++ struct hlist_node *node, *next;
++ struct lec_arp_table *entry;
++ int i;
++
++ cancel_rearming_delayed_work(&priv->lec_arp_work);
+
+- del_timer_sync(&priv->lec_arp_timer);
+-
+- /*
+- * Remove all entries
+- */
++ /*
++ * Remove all entries
++ */
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- for(entry = priv->lec_arp_tables[i]; entry != NULL; entry=next) {
+- next = entry->next;
+- lec_arp_remove(priv, entry);
+- kfree(entry);
+- }
+- }
+- entry = priv->lec_arp_empty_ones;
+- while(entry) {
+- next = entry->next;
+- del_timer_sync(&entry->timer);
+- lec_arp_clear_vccs(entry);
+- kfree(entry);
+- entry = next;
+- }
+- priv->lec_arp_empty_ones = NULL;
+- entry = priv->lec_no_forward;
+- while(entry) {
+- next = entry->next;
+- del_timer_sync(&entry->timer);
+- lec_arp_clear_vccs(entry);
+- kfree(entry);
+- entry = next;
+- }
+- priv->lec_no_forward = NULL;
+- entry = priv->mcast_fwds;
+- while(entry) {
+- next = entry->next;
+- /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
+- lec_arp_clear_vccs(entry);
+- kfree(entry);
+- entry = next;
+- }
+- priv->mcast_fwds = NULL;
+- priv->mcast_vcc = NULL;
+- memset(priv->lec_arp_tables, 0,
+- sizeof(struct lec_arp_table *) * LEC_ARP_TABLE_SIZE);
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
++ lec_arp_remove(priv, entry);
++ lec_arp_put(entry);
++ }
++ INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
++ }
++
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
++ del_timer_sync(&entry->timer);
++ lec_arp_clear_vccs(entry);
++ hlist_del(&entry->next);
++ lec_arp_put(entry);
++ }
++ INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
++
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
++ del_timer_sync(&entry->timer);
++ lec_arp_clear_vccs(entry);
++ hlist_del(&entry->next);
++ lec_arp_put(entry);
++ }
++ INIT_HLIST_HEAD(&priv->lec_no_forward);
++
++ hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
++ /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
++ lec_arp_clear_vccs(entry);
++ hlist_del(&entry->next);
++ lec_arp_put(entry);
++ }
++ INIT_HLIST_HEAD(&priv->mcast_fwds);
++ priv->mcast_vcc = NULL;
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ }
+
+-
+ /*
+ * Find entry by mac_address
+ */
+-static struct lec_arp_table*
+-lec_arp_find(struct lec_priv *priv,
+- unsigned char *mac_addr)
++static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
++ unsigned char *mac_addr)
+ {
+- unsigned short place;
+- struct lec_arp_table *to_return;
+-
+- DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+- mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff,
+- mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
+- place = HASH(mac_addr[ETH_ALEN-1]);
+-
+- to_return = priv->lec_arp_tables[place];
+- while(to_return) {
+- if (!compare_ether_addr(mac_addr, to_return->mac_addr)) {
+- return to_return;
+- }
+- to_return = to_return->next;
+- }
+- return NULL;
++ struct hlist_node *node;
++ struct hlist_head *head;
++ struct lec_arp_table *entry;
++
++ DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
++ mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff,
++ mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff);
++
++ head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
++ hlist_for_each_entry(entry, node, head, next) {
++ if (!compare_ether_addr(mac_addr, entry->mac_addr)) {
++ return entry;
++ }
++ }
++ return NULL;
+ }
+
+-static struct lec_arp_table*
+-make_entry(struct lec_priv *priv, unsigned char *mac_addr)
++static struct lec_arp_table *make_entry(struct lec_priv *priv,
++ unsigned char *mac_addr)
+ {
+- struct lec_arp_table *to_return;
+-
+- to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
+- if (!to_return) {
+- printk("LEC: Arp entry kmalloc failed\n");
+- return NULL;
+- }
+- memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
+- init_timer(&to_return->timer);
+- to_return->timer.function = lec_arp_expire_arp;
+- to_return->timer.data = (unsigned long) to_return;
+- to_return->last_used = jiffies;
+- to_return->priv = priv;
+- skb_queue_head_init(&to_return->tx_wait);
+- return to_return;
++ struct lec_arp_table *to_return;
++
++ to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
++ if (!to_return) {
++ printk("LEC: Arp entry kmalloc failed\n");
++ return NULL;
++ }
++ memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
++ INIT_HLIST_NODE(&to_return->next);
++ init_timer(&to_return->timer);
++ to_return->timer.function = lec_arp_expire_arp;
++ to_return->timer.data = (unsigned long)to_return;
++ to_return->last_used = jiffies;
++ to_return->priv = priv;
++ skb_queue_head_init(&to_return->tx_wait);
++ atomic_set(&to_return->usage, 1);
++ return to_return;
+ }
+
+-/*
+- *
+- * Arp sent timer expired
+- *
+- */
+-static void
+-lec_arp_expire_arp(unsigned long data)
++/* Arp sent timer expired */
++static void lec_arp_expire_arp(unsigned long data)
+ {
+- struct lec_arp_table *entry;
+-
+- entry = (struct lec_arp_table *)data;
+-
+- DPRINTK("lec_arp_expire_arp\n");
+- if (entry->status == ESI_ARP_PENDING) {
+- if (entry->no_tries <= entry->priv->max_retry_count) {
+- if (entry->is_rdesc)
+- send_to_lecd(entry->priv, l_rdesc_arp_xmt, entry->mac_addr, NULL, NULL);
+- else
+- send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
+- entry->no_tries++;
+- }
+- mod_timer(&entry->timer, jiffies + (1*HZ));
+- }
++ struct lec_arp_table *entry;
++
++ entry = (struct lec_arp_table *)data;
++
++ DPRINTK("lec_arp_expire_arp\n");
++ if (entry->status == ESI_ARP_PENDING) {
++ if (entry->no_tries <= entry->priv->max_retry_count) {
++ if (entry->is_rdesc)
++ send_to_lecd(entry->priv, l_rdesc_arp_xmt,
++ entry->mac_addr, NULL, NULL);
++ else
++ send_to_lecd(entry->priv, l_arp_xmt,
++ entry->mac_addr, NULL, NULL);
++ entry->no_tries++;
++ }
++ mod_timer(&entry->timer, jiffies + (1 * HZ));
++ }
+ }
+
+-/*
+- *
+- * Unknown/unused vcc expire, remove associated entry
+- *
+- */
+-static void
+-lec_arp_expire_vcc(unsigned long data)
++/* Unknown/unused vcc expire, remove associated entry */
++static void lec_arp_expire_vcc(unsigned long data)
+ {
+ unsigned long flags;
+- struct lec_arp_table *to_remove = (struct lec_arp_table*)data;
+- struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
+- struct lec_arp_table *entry = NULL;
++ struct lec_arp_table *to_remove = (struct lec_arp_table *)data;
++ struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
+
+- del_timer(&to_remove->timer);
++ del_timer(&to_remove->timer);
+
+- DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
+- to_remove, priv,
+- to_remove->vcc?to_remove->recv_vcc->vpi:0,
+- to_remove->vcc?to_remove->recv_vcc->vci:0);
+- DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward);
++ DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
++ to_remove, priv,
++ to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
++ to_remove->vcc ? to_remove->recv_vcc->vci : 0);
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- if (to_remove == priv->lec_arp_empty_ones)
+- priv->lec_arp_empty_ones = to_remove->next;
+- else {
+- entry = priv->lec_arp_empty_ones;
+- while (entry && entry->next != to_remove)
+- entry = entry->next;
+- if (entry)
+- entry->next = to_remove->next;
+- }
+- if (!entry) {
+- if (to_remove == priv->lec_no_forward) {
+- priv->lec_no_forward = to_remove->next;
+- } else {
+- entry = priv->lec_no_forward;
+- while (entry && entry->next != to_remove)
+- entry = entry->next;
+- if (entry)
+- entry->next = to_remove->next;
+- }
+- }
++ hlist_del(&to_remove->next);
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+
+- lec_arp_clear_vccs(to_remove);
+- kfree(to_remove);
++ lec_arp_clear_vccs(to_remove);
++ lec_arp_put(to_remove);
+ }
+
+ /*
+@@ -1915,158 +1879,171 @@ lec_arp_expire_vcc(unsigned long data)
+ * to ESI_FORWARD_DIRECT. This causes the flush period to end
+ * regardless of the progress of the flush protocol.
+ */
+-static void
+-lec_arp_check_expire(unsigned long data)
++static void lec_arp_check_expire(void *data)
+ {
+ unsigned long flags;
+- struct lec_priv *priv = (struct lec_priv *)data;
+- struct lec_arp_table *entry, *next;
+- unsigned long now;
+- unsigned long time_to_check;
+- int i;
+-
+- DPRINTK("lec_arp_check_expire %p\n",priv);
+- DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
+- priv->lec_no_forward);
++ struct lec_priv *priv = data;
++ struct hlist_node *node, *next;
++ struct lec_arp_table *entry;
++ unsigned long now;
++ unsigned long time_to_check;
++ int i;
++
++ DPRINTK("lec_arp_check_expire %p\n", priv);
+ now = jiffies;
++restart:
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
+- if ((entry->flags) & LEC_REMOTE_FLAG &&
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
++ if ((entry->flags) & LEC_REMOTE_FLAG &&
+ priv->topology_change)
+ time_to_check = priv->forward_delay_time;
+ else
+ time_to_check = priv->aging_time;
+
+ DPRINTK("About to expire: %lx - %lx > %lx\n",
+- now,entry->last_used, time_to_check);
+- if( time_after(now, entry->last_used+
+- time_to_check) &&
+- !(entry->flags & LEC_PERMANENT_FLAG) &&
+- !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */
++ now, entry->last_used, time_to_check);
++ if (time_after(now, entry->last_used + time_to_check)
++ && !(entry->flags & LEC_PERMANENT_FLAG)
++ && !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */
+ /* Remove entry */
+ DPRINTK("LEC:Entry timed out\n");
+- next = entry->next;
+ lec_arp_remove(priv, entry);
+- kfree(entry);
+- entry = next;
++ lec_arp_put(entry);
+ } else {
+ /* Something else */
+ if ((entry->status == ESI_VC_PENDING ||
+- entry->status == ESI_ARP_PENDING)
++ entry->status == ESI_ARP_PENDING)
+ && time_after_eq(now,
+- entry->timestamp +
+- priv->max_unknown_frame_time)) {
++ entry->timestamp +
++ priv->
++ max_unknown_frame_time)) {
+ entry->timestamp = jiffies;
+ entry->packets_flooded = 0;
+ if (entry->status == ESI_VC_PENDING)
+- send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL);
++ send_to_lecd(priv, l_svc_setup,
++ entry->mac_addr,
++ entry->atm_addr,
++ NULL);
+ }
+- if (entry->status == ESI_FLUSH_PENDING
+- &&
+- time_after_eq(now, entry->timestamp+
+- priv->path_switching_delay)) {
++ if (entry->status == ESI_FLUSH_PENDING
++ &&
++ time_after_eq(now, entry->timestamp +
++ priv->path_switching_delay)) {
+ struct sk_buff *skb;
++ struct atm_vcc *vcc = entry->vcc;
+
++ lec_arp_hold(entry);
++ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+- lec_send(entry->vcc, skb, entry->priv);
++ lec_send(vcc, skb, entry->priv);
+ entry->last_used = jiffies;
+- entry->status =
+- ESI_FORWARD_DIRECT;
++ entry->status = ESI_FORWARD_DIRECT;
++ lec_arp_put(entry);
++ goto restart;
+ }
+- entry = entry->next;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+
+- mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL);
++ schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
+ }
++
+ /*
+ * Try to find vcc where mac_address is attached.
+ *
+ */
+-static struct atm_vcc*
+-lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
+- int is_rdesc, struct lec_arp_table **ret_entry)
++static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
++ unsigned char *mac_to_find, int is_rdesc,
++ struct lec_arp_table **ret_entry)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry;
++ struct lec_arp_table *entry;
+ struct atm_vcc *found;
+
+- if (mac_to_find[0] & 0x01) {
+- switch (priv->lane_version) {
+- case 1:
+- return priv->mcast_vcc;
+- break;
+- case 2: /* LANE2 wants arp for multicast addresses */
+- if (!compare_ether_addr(mac_to_find, bus_mac))
+- return priv->mcast_vcc;
+- break;
+- default:
+- break;
+- }
+- }
++ if (mac_to_find[0] & 0x01) {
++ switch (priv->lane_version) {
++ case 1:
++ return priv->mcast_vcc;
++ break;
++ case 2: /* LANE2 wants arp for multicast addresses */
++ if (!compare_ether_addr(mac_to_find, bus_mac))
++ return priv->mcast_vcc;
++ break;
++ default:
++ break;
++ }
++ }
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- entry = lec_arp_find(priv, mac_to_find);
+-
+- if (entry) {
+- if (entry->status == ESI_FORWARD_DIRECT) {
+- /* Connection Ok */
+- entry->last_used = jiffies;
+- *ret_entry = entry;
+- found = entry->vcc;
++ entry = lec_arp_find(priv, mac_to_find);
++
++ if (entry) {
++ if (entry->status == ESI_FORWARD_DIRECT) {
++ /* Connection Ok */
++ entry->last_used = jiffies;
++ lec_arp_hold(entry);
++ *ret_entry = entry;
++ found = entry->vcc;
+ goto out;
+- }
+- /* If the LE_ARP cache entry is still pending, reset count to 0
++ }
++ /*
++ * If the LE_ARP cache entry is still pending, reset count to 0
+ * so another LE_ARP request can be made for this frame.
+ */
+ if (entry->status == ESI_ARP_PENDING) {
+ entry->no_tries = 0;
+ }
+- /* Data direct VC not yet set up, check to see if the unknown
+- frame count is greater than the limit. If the limit has
+- not been reached, allow the caller to send packet to
+- BUS. */
+- if (entry->status != ESI_FLUSH_PENDING &&
+- entry->packets_flooded<priv->maximum_unknown_frame_count) {
+- entry->packets_flooded++;
+- DPRINTK("LEC_ARP: Flooding..\n");
+- found = priv->mcast_vcc;
++ /*
++ * Data direct VC not yet set up, check to see if the unknown
++ * frame count is greater than the limit. If the limit has
++ * not been reached, allow the caller to send packet to
++ * BUS.
++ */
++ if (entry->status != ESI_FLUSH_PENDING &&
++ entry->packets_flooded <
++ priv->maximum_unknown_frame_count) {
++ entry->packets_flooded++;
++ DPRINTK("LEC_ARP: Flooding..\n");
++ found = priv->mcast_vcc;
+ goto out;
+- }
+- /* We got here because entry->status == ESI_FLUSH_PENDING
++ }
++ /*
++ * We got here because entry->status == ESI_FLUSH_PENDING
+ * or BUS flood limit was reached for an entry which is
+ * in ESI_ARP_PENDING or ESI_VC_PENDING state.
+ */
+- *ret_entry = entry;
+- DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc);
+- found = NULL;
+- } else {
+- /* No matching entry was found */
+- entry = make_entry(priv, mac_to_find);
+- DPRINTK("LEC_ARP: Making entry\n");
+- if (!entry) {
+- found = priv->mcast_vcc;
++ lec_arp_hold(entry);
++ *ret_entry = entry;
++ DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status,
++ entry->vcc);
++ found = NULL;
++ } else {
++ /* No matching entry was found */
++ entry = make_entry(priv, mac_to_find);
++ DPRINTK("LEC_ARP: Making entry\n");
++ if (!entry) {
++ found = priv->mcast_vcc;
+ goto out;
+- }
+- lec_arp_add(priv, entry);
+- /* We want arp-request(s) to be sent */
+- entry->packets_flooded =1;
+- entry->status = ESI_ARP_PENDING;
+- entry->no_tries = 1;
+- entry->last_used = entry->timestamp = jiffies;
+- entry->is_rdesc = is_rdesc;
+- if (entry->is_rdesc)
+- send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, NULL);
+- else
+- send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
+- entry->timer.expires = jiffies + (1*HZ);
+- entry->timer.function = lec_arp_expire_arp;
+- add_timer(&entry->timer);
+- found = priv->mcast_vcc;
+- }
++ }
++ lec_arp_add(priv, entry);
++ /* We want arp-request(s) to be sent */
++ entry->packets_flooded = 1;
++ entry->status = ESI_ARP_PENDING;
++ entry->no_tries = 1;
++ entry->last_used = entry->timestamp = jiffies;
++ entry->is_rdesc = is_rdesc;
++ if (entry->is_rdesc)
++ send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL,
++ NULL);
++ else
++ send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
++ entry->timer.expires = jiffies + (1 * HZ);
++ entry->timer.function = lec_arp_expire_arp;
++ add_timer(&entry->timer);
++ found = priv->mcast_vcc;
++ }
+
+ out:
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+@@ -2074,30 +2051,30 @@ out:
+ }
+
+ static int
+-lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
+- unsigned long permanent)
++lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
++ unsigned long permanent)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry, *next;
+- int i;
++ struct hlist_node *node, *next;
++ struct lec_arp_table *entry;
++ int i;
+
+- DPRINTK("lec_addr_delete\n");
++ DPRINTK("lec_addr_delete\n");
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- for(entry = priv->lec_arp_tables[i]; entry != NULL; entry = next) {
+- next = entry->next;
+- if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
+- && (permanent ||
+- !(entry->flags & LEC_PERMANENT_FLAG))) {
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
++ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
++ && (permanent ||
++ !(entry->flags & LEC_PERMANENT_FLAG))) {
+ lec_arp_remove(priv, entry);
+- kfree(entry);
+- }
++ lec_arp_put(entry);
++ }
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+- return 0;
+- }
+- }
++ return 0;
++ }
++ }
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+- return -1;
++ return -1;
+ }
+
+ /*
+@@ -2105,109 +2082,98 @@ lec_addr_delete(struct lec_priv *priv, u
+ */
+ static void
+ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
+- unsigned char *atm_addr, unsigned long remoteflag,
+- unsigned int targetless_le_arp)
++ unsigned char *atm_addr, unsigned long remoteflag,
++ unsigned int targetless_le_arp)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry, *tmp;
+- int i;
++ struct hlist_node *node, *next;
++ struct lec_arp_table *entry, *tmp;
++ int i;
+
+- DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " ");
+- DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+- mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],
+- mac_addr[4],mac_addr[5]);
++ DPRINTK("lec:%s", (targetless_le_arp) ? "targetless " : " ");
++ DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
++ mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
++ mac_addr[4], mac_addr[5]);
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- entry = lec_arp_find(priv, mac_addr);
+- if (entry == NULL && targetless_le_arp)
+- goto out; /* LANE2: ignore targetless LE_ARPs for which
+- * we have no entry in the cache. 7.1.30
+- */
+- if (priv->lec_arp_empty_ones) {
+- entry = priv->lec_arp_empty_ones;
+- if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
+- priv->lec_arp_empty_ones = entry->next;
+- } else {
+- while(entry->next && memcmp(entry->next->atm_addr,
+- atm_addr, ATM_ESA_LEN))
+- entry = entry->next;
+- if (entry->next) {
+- tmp = entry;
+- entry = entry->next;
+- tmp->next = entry->next;
+- } else
+- entry = NULL;
+-
+- }
+- if (entry) {
+- del_timer(&entry->timer);
+- tmp = lec_arp_find(priv, mac_addr);
+- if (tmp) {
+- del_timer(&tmp->timer);
+- tmp->status = ESI_FORWARD_DIRECT;
+- memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
+- tmp->vcc = entry->vcc;
+- tmp->old_push = entry->old_push;
+- tmp->last_used = jiffies;
+- del_timer(&entry->timer);
+- kfree(entry);
+- entry=tmp;
+- } else {
+- entry->status = ESI_FORWARD_DIRECT;
+- memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
+- entry->last_used = jiffies;
+- lec_arp_add(priv, entry);
+- }
+- if (remoteflag)
+- entry->flags|=LEC_REMOTE_FLAG;
+- else
+- entry->flags&=~LEC_REMOTE_FLAG;
+- DPRINTK("After update\n");
+- dump_arp_table(priv);
+- goto out;
+- }
+- }
+- entry = lec_arp_find(priv, mac_addr);
+- if (!entry) {
+- entry = make_entry(priv, mac_addr);
+- if (!entry)
++ entry = lec_arp_find(priv, mac_addr);
++ if (entry == NULL && targetless_le_arp)
++ goto out; /*
++ * LANE2: ignore targetless LE_ARPs for which
++ * we have no entry in the cache. 7.1.30
++ */
++ if (!hlist_empty(&priv->lec_arp_empty_ones)) {
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
++ if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
++ hlist_del(&entry->next);
++ del_timer(&entry->timer);
++ tmp = lec_arp_find(priv, mac_addr);
++ if (tmp) {
++ del_timer(&tmp->timer);
++ tmp->status = ESI_FORWARD_DIRECT;
++ memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
++ tmp->vcc = entry->vcc;
++ tmp->old_push = entry->old_push;
++ tmp->last_used = jiffies;
++ del_timer(&entry->timer);
++ lec_arp_put(entry);
++ entry = tmp;
++ } else {
++ entry->status = ESI_FORWARD_DIRECT;
++ memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
++ entry->last_used = jiffies;
++ lec_arp_add(priv, entry);
++ }
++ if (remoteflag)
++ entry->flags |= LEC_REMOTE_FLAG;
++ else
++ entry->flags &= ~LEC_REMOTE_FLAG;
++ DPRINTK("After update\n");
++ dump_arp_table(priv);
++ goto out;
++ }
++ }
++ }
++
++ entry = lec_arp_find(priv, mac_addr);
++ if (!entry) {
++ entry = make_entry(priv, mac_addr);
++ if (!entry)
+ goto out;
+- entry->status = ESI_UNKNOWN;
+- lec_arp_add(priv, entry);
+- /* Temporary, changes before end of function */
+- }
+- memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
+- del_timer(&entry->timer);
+- for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- for(tmp = priv->lec_arp_tables[i]; tmp; tmp=tmp->next) {
+- if (entry != tmp &&
+- !memcmp(tmp->atm_addr, atm_addr,
+- ATM_ESA_LEN)) {
+- /* Vcc to this host exists */
+- if (tmp->status > ESI_VC_PENDING) {
+- /*
+- * ESI_FLUSH_PENDING,
+- * ESI_FORWARD_DIRECT
+- */
+- entry->vcc = tmp->vcc;
+- entry->old_push=tmp->old_push;
+- }
+- entry->status=tmp->status;
+- break;
+- }
+- }
+- }
+- if (remoteflag)
+- entry->flags|=LEC_REMOTE_FLAG;
+- else
+- entry->flags&=~LEC_REMOTE_FLAG;
+- if (entry->status == ESI_ARP_PENDING ||
+- entry->status == ESI_UNKNOWN) {
+- entry->status = ESI_VC_PENDING;
+- send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
+- }
+- DPRINTK("After update2\n");
+- dump_arp_table(priv);
++ entry->status = ESI_UNKNOWN;
++ lec_arp_add(priv, entry);
++ /* Temporary, changes before end of function */
++ }
++ memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
++ del_timer(&entry->timer);
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry(tmp, node, &priv->lec_arp_tables[i], next) {
++ if (entry != tmp &&
++ !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
++ /* Vcc to this host exists */
++ if (tmp->status > ESI_VC_PENDING) {
++ /*
++ * ESI_FLUSH_PENDING,
++ * ESI_FORWARD_DIRECT
++ */
++ entry->vcc = tmp->vcc;
++ entry->old_push = tmp->old_push;
++ }
++ entry->status = tmp->status;
++ break;
++ }
++ }
++ }
++ if (remoteflag)
++ entry->flags |= LEC_REMOTE_FLAG;
++ else
++ entry->flags &= ~LEC_REMOTE_FLAG;
++ if (entry->status == ESI_ARP_PENDING || entry->status == ESI_UNKNOWN) {
++ entry->status = ESI_VC_PENDING;
++ send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
++ }
++ DPRINTK("After update2\n");
++ dump_arp_table(priv);
+ out:
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ }
+@@ -2217,299 +2183,299 @@ out:
+ */
+ static void
+ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
+- struct atm_vcc *vcc,
+- void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb))
++ struct atm_vcc *vcc,
++ void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry;
+- int i, found_entry=0;
++ struct hlist_node *node;
++ struct lec_arp_table *entry;
++ int i, found_entry = 0;
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- if (ioc_data->receive == 2) {
+- /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
++ if (ioc_data->receive == 2) {
++ /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
+
+- DPRINTK("LEC_ARP: Attaching mcast forward\n");
++ DPRINTK("LEC_ARP: Attaching mcast forward\n");
+ #if 0
+- entry = lec_arp_find(priv, bus_mac);
+- if (!entry) {
+- printk("LEC_ARP: Multicast entry not found!\n");
++ entry = lec_arp_find(priv, bus_mac);
++ if (!entry) {
++ printk("LEC_ARP: Multicast entry not found!\n");
+ goto out;
+- }
+- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+- entry->recv_vcc = vcc;
+- entry->old_recv_push = old_push;
++ }
++ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
++ entry->recv_vcc = vcc;
++ entry->old_recv_push = old_push;
+ #endif
+- entry = make_entry(priv, bus_mac);
+- if (entry == NULL)
++ entry = make_entry(priv, bus_mac);
++ if (entry == NULL)
+ goto out;
+- del_timer(&entry->timer);
+- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+- entry->recv_vcc = vcc;
+- entry->old_recv_push = old_push;
+- entry->next = priv->mcast_fwds;
+- priv->mcast_fwds = entry;
+- goto out;
+- } else if (ioc_data->receive == 1) {
+- /* Vcc which we don't want to make default vcc, attach it
+- anyway. */
+- DPRINTK("LEC_ARP:Attaching data direct, not default :%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+- ioc_data->atm_addr[0],ioc_data->atm_addr[1],
+- ioc_data->atm_addr[2],ioc_data->atm_addr[3],
+- ioc_data->atm_addr[4],ioc_data->atm_addr[5],
+- ioc_data->atm_addr[6],ioc_data->atm_addr[7],
+- ioc_data->atm_addr[8],ioc_data->atm_addr[9],
+- ioc_data->atm_addr[10],ioc_data->atm_addr[11],
+- ioc_data->atm_addr[12],ioc_data->atm_addr[13],
+- ioc_data->atm_addr[14],ioc_data->atm_addr[15],
+- ioc_data->atm_addr[16],ioc_data->atm_addr[17],
+- ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
+- entry = make_entry(priv, bus_mac);
+- if (entry == NULL)
++ del_timer(&entry->timer);
++ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
++ entry->recv_vcc = vcc;
++ entry->old_recv_push = old_push;
++ hlist_add_head(&entry->next, &priv->mcast_fwds);
++ goto out;
++ } else if (ioc_data->receive == 1) {
++ /*
++ * Vcc which we don't want to make default vcc,
++ * attach it anyway.
++ */
++ DPRINTK
++ ("LEC_ARP:Attaching data direct, not default: "
++ "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
++ ioc_data->atm_addr[0], ioc_data->atm_addr[1],
++ ioc_data->atm_addr[2], ioc_data->atm_addr[3],
++ ioc_data->atm_addr[4], ioc_data->atm_addr[5],
++ ioc_data->atm_addr[6], ioc_data->atm_addr[7],
++ ioc_data->atm_addr[8], ioc_data->atm_addr[9],
++ ioc_data->atm_addr[10], ioc_data->atm_addr[11],
++ ioc_data->atm_addr[12], ioc_data->atm_addr[13],
++ ioc_data->atm_addr[14], ioc_data->atm_addr[15],
++ ioc_data->atm_addr[16], ioc_data->atm_addr[17],
++ ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
++ entry = make_entry(priv, bus_mac);
++ if (entry == NULL)
+ goto out;
+- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+- memset(entry->mac_addr, 0, ETH_ALEN);
+- entry->recv_vcc = vcc;
+- entry->old_recv_push = old_push;
+- entry->status = ESI_UNKNOWN;
+- entry->timer.expires = jiffies + priv->vcc_timeout_period;
+- entry->timer.function = lec_arp_expire_vcc;
+- add_timer(&entry->timer);
+- entry->next = priv->lec_no_forward;
+- priv->lec_no_forward = entry;
++ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
++ memset(entry->mac_addr, 0, ETH_ALEN);
++ entry->recv_vcc = vcc;
++ entry->old_recv_push = old_push;
++ entry->status = ESI_UNKNOWN;
++ entry->timer.expires = jiffies + priv->vcc_timeout_period;
++ entry->timer.function = lec_arp_expire_vcc;
++ hlist_add_head(&entry->next, &priv->lec_no_forward);
++ add_timer(&entry->timer);
+ dump_arp_table(priv);
+ goto out;
+- }
+- DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+- ioc_data->atm_addr[0],ioc_data->atm_addr[1],
+- ioc_data->atm_addr[2],ioc_data->atm_addr[3],
+- ioc_data->atm_addr[4],ioc_data->atm_addr[5],
+- ioc_data->atm_addr[6],ioc_data->atm_addr[7],
+- ioc_data->atm_addr[8],ioc_data->atm_addr[9],
+- ioc_data->atm_addr[10],ioc_data->atm_addr[11],
+- ioc_data->atm_addr[12],ioc_data->atm_addr[13],
+- ioc_data->atm_addr[14],ioc_data->atm_addr[15],
+- ioc_data->atm_addr[16],ioc_data->atm_addr[17],
+- ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
+- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
+- if (memcmp(ioc_data->atm_addr, entry->atm_addr,
+- ATM_ESA_LEN)==0) {
+- DPRINTK("LEC_ARP: Attaching data direct\n");
+- DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n",
+- entry->vcc?entry->vcc->vci:0,
+- entry->recv_vcc?entry->recv_vcc->vci:0);
+- found_entry=1;
+- del_timer(&entry->timer);
+- entry->vcc = vcc;
+- entry->old_push = old_push;
+- if (entry->status == ESI_VC_PENDING) {
+- if(priv->maximum_unknown_frame_count
+- ==0)
+- entry->status =
+- ESI_FORWARD_DIRECT;
+- else {
+- entry->timestamp = jiffies;
+- entry->status =
+- ESI_FLUSH_PENDING;
++ }
++ DPRINTK
++ ("LEC_ARP:Attaching data direct, default: "
++ "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
++ ioc_data->atm_addr[0], ioc_data->atm_addr[1],
++ ioc_data->atm_addr[2], ioc_data->atm_addr[3],
++ ioc_data->atm_addr[4], ioc_data->atm_addr[5],
++ ioc_data->atm_addr[6], ioc_data->atm_addr[7],
++ ioc_data->atm_addr[8], ioc_data->atm_addr[9],
++ ioc_data->atm_addr[10], ioc_data->atm_addr[11],
++ ioc_data->atm_addr[12], ioc_data->atm_addr[13],
++ ioc_data->atm_addr[14], ioc_data->atm_addr[15],
++ ioc_data->atm_addr[16], ioc_data->atm_addr[17],
++ ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
++ if (memcmp
++ (ioc_data->atm_addr, entry->atm_addr,
++ ATM_ESA_LEN) == 0) {
++ DPRINTK("LEC_ARP: Attaching data direct\n");
++ DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n",
++ entry->vcc ? entry->vcc->vci : 0,
++ entry->recv_vcc ? entry->recv_vcc->
++ vci : 0);
++ found_entry = 1;
++ del_timer(&entry->timer);
++ entry->vcc = vcc;
++ entry->old_push = old_push;
++ if (entry->status == ESI_VC_PENDING) {
++ if (priv->maximum_unknown_frame_count
++ == 0)
++ entry->status =
++ ESI_FORWARD_DIRECT;
++ else {
++ entry->timestamp = jiffies;
++ entry->status =
++ ESI_FLUSH_PENDING;
+ #if 0
+- send_to_lecd(priv,l_flush_xmt,
+- NULL,
+- entry->atm_addr,
+- NULL);
++ send_to_lecd(priv, l_flush_xmt,
++ NULL,
++ entry->atm_addr,
++ NULL);
+ #endif
+- }
+- } else {
+- /* They were forming a connection
+- to us, and we to them. Our
+- ATM address is numerically lower
+- than theirs, so we make connection
+- we formed into default VCC (8.1.11).
+- Connection they made gets torn
+- down. This might confuse some
+- clients. Can be changed if
+- someone reports trouble... */
+- ;
+- }
+- }
+- }
+- }
+- if (found_entry) {
+- DPRINTK("After vcc was added\n");
+- dump_arp_table(priv);
++ }
++ } else {
++ /*
++ * They were forming a connection
++ * to us, and we to them. Our
++ * ATM address is numerically lower
++ * than theirs, so we make connection
++ * we formed into default VCC (8.1.11).
++ * Connection they made gets torn
++ * down. This might confuse some
++ * clients. Can be changed if
++ * someone reports trouble...
++ */
++ ;
++ }
++ }
++ }
++ }
++ if (found_entry) {
++ DPRINTK("After vcc was added\n");
++ dump_arp_table(priv);
+ goto out;
+- }
+- /* Not found, snatch address from first data packet that arrives from
+- this vcc */
+- entry = make_entry(priv, bus_mac);
+- if (!entry)
++ }
++ /*
++ * Not found, snatch address from first data packet that arrives
++ * from this vcc
++ */
++ entry = make_entry(priv, bus_mac);
++ if (!entry)
+ goto out;
+- entry->vcc = vcc;
+- entry->old_push = old_push;
+- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+- memset(entry->mac_addr, 0, ETH_ALEN);
+- entry->status = ESI_UNKNOWN;
+- entry->next = priv->lec_arp_empty_ones;
+- priv->lec_arp_empty_ones = entry;
+- entry->timer.expires = jiffies + priv->vcc_timeout_period;
+- entry->timer.function = lec_arp_expire_vcc;
+- add_timer(&entry->timer);
+- DPRINTK("After vcc was added\n");
++ entry->vcc = vcc;
++ entry->old_push = old_push;
++ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
++ memset(entry->mac_addr, 0, ETH_ALEN);
++ entry->status = ESI_UNKNOWN;
++ hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
++ entry->timer.expires = jiffies + priv->vcc_timeout_period;
++ entry->timer.function = lec_arp_expire_vcc;
++ add_timer(&entry->timer);
++ DPRINTK("After vcc was added\n");
+ dump_arp_table(priv);
+ out:
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ }
+
+-static void
+-lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
++static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry;
+- int i;
+-
+- DPRINTK("LEC:lec_flush_complete %lx\n",tran_id);
++ struct hlist_node *node;
++ struct lec_arp_table *entry;
++ int i;
++
++ DPRINTK("LEC:lec_flush_complete %lx\n", tran_id);
++restart:
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+- for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
+- if (entry->flush_tran_id == tran_id &&
+- entry->status == ESI_FLUSH_PENDING) {
+- struct sk_buff *skb;
+-
+- while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+- lec_send(entry->vcc, skb, entry->priv);
+- entry->status = ESI_FORWARD_DIRECT;
+- DPRINTK("LEC_ARP: Flushed\n");
+- }
+- }
+- }
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
++ if (entry->flush_tran_id == tran_id
++ && entry->status == ESI_FLUSH_PENDING) {
++ struct sk_buff *skb;
++ struct atm_vcc *vcc = entry->vcc;
++
++ lec_arp_hold(entry);
++ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
++ while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
++ lec_send(vcc, skb, entry->priv);
++ entry->last_used = jiffies;
++ entry->status = ESI_FORWARD_DIRECT;
++ lec_arp_put(entry);
++ DPRINTK("LEC_ARP: Flushed\n");
++ goto restart;
++ }
++ }
++ }
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+- dump_arp_table(priv);
++ dump_arp_table(priv);
+ }
+
+ static void
+ lec_set_flush_tran_id(struct lec_priv *priv,
+- unsigned char *atm_addr, unsigned long tran_id)
++ unsigned char *atm_addr, unsigned long tran_id)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry;
+- int i;
++ struct hlist_node *node;
++ struct lec_arp_table *entry;
++ int i;
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
+- for(entry = priv->lec_arp_tables[i]; entry; entry=entry->next)
+- if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
+- entry->flush_tran_id = tran_id;
+- DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry);
+- }
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
++ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
++ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
++ entry->flush_tran_id = tran_id;
++ DPRINTK("Set flush transaction id to %lx for %p\n",
++ tran_id, entry);
++ }
++ }
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ }
+
+-static int
+-lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
++static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
+ {
+ unsigned long flags;
+- unsigned char mac_addr[] = {
+- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+- struct lec_arp_table *to_add;
++ unsigned char mac_addr[] = {
++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++ };
++ struct lec_arp_table *to_add;
+ struct lec_vcc_priv *vpriv;
+ int err = 0;
+-
++
+ if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
+ return -ENOMEM;
+ vpriv->xoff = 0;
+ vpriv->old_pop = vcc->pop;
+ vcc->user_back = vpriv;
+- vcc->pop = lec_pop;
++ vcc->pop = lec_pop;
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- to_add = make_entry(priv, mac_addr);
+- if (!to_add) {
++ to_add = make_entry(priv, mac_addr);
++ if (!to_add) {
+ vcc->pop = vpriv->old_pop;
+ kfree(vpriv);
+- err = -ENOMEM;
++ err = -ENOMEM;
+ goto out;
+- }
+- memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
+- to_add->status = ESI_FORWARD_DIRECT;
+- to_add->flags |= LEC_PERMANENT_FLAG;
+- to_add->vcc = vcc;
+- to_add->old_push = vcc->push;
+- vcc->push = lec_push;
+- priv->mcast_vcc = vcc;
+- lec_arp_add(priv, to_add);
++ }
++ memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
++ to_add->status = ESI_FORWARD_DIRECT;
++ to_add->flags |= LEC_PERMANENT_FLAG;
++ to_add->vcc = vcc;
++ to_add->old_push = vcc->push;
++ vcc->push = lec_push;
++ priv->mcast_vcc = vcc;
++ lec_arp_add(priv, to_add);
+ out:
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+- return err;
++ return err;
+ }
+
+-static void
+-lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
++static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
+ {
+ unsigned long flags;
+- struct lec_arp_table *entry, *next;
+- int i;
++ struct hlist_node *node, *next;
++ struct lec_arp_table *entry;
++ int i;
++
++ DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci);
++ dump_arp_table(priv);
+
+- DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
+- dump_arp_table(priv);
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+- for(entry = priv->lec_arp_tables[i];entry; entry=next) {
+- next = entry->next;
+- if (vcc == entry->vcc) {
+- lec_arp_remove(priv, entry);
+- kfree(entry);
+- if (priv->mcast_vcc == vcc) {
+- priv->mcast_vcc = NULL;
+- }
+- }
+- }
+- }
+-
+- entry = priv->lec_arp_empty_ones;
+- priv->lec_arp_empty_ones = NULL;
+- while (entry != NULL) {
+- next = entry->next;
+- if (entry->vcc == vcc) { /* leave it out from the list */
+- lec_arp_clear_vccs(entry);
+- del_timer(&entry->timer);
+- kfree(entry);
+- }
+- else { /* put it back to the list */
+- entry->next = priv->lec_arp_empty_ones;
+- priv->lec_arp_empty_ones = entry;
+- }
+- entry = next;
+- }
+-
+- entry = priv->lec_no_forward;
+- priv->lec_no_forward = NULL;
+- while (entry != NULL) {
+- next = entry->next;
+- if (entry->recv_vcc == vcc) {
+- lec_arp_clear_vccs(entry);
+- del_timer(&entry->timer);
+- kfree(entry);
+- }
+- else {
+- entry->next = priv->lec_no_forward;
+- priv->lec_no_forward = entry;
+- }
+- entry = next;
+- }
+-
+- entry = priv->mcast_fwds;
+- priv->mcast_fwds = NULL;
+- while (entry != NULL) {
+- next = entry->next;
+- if (entry->recv_vcc == vcc) {
+- lec_arp_clear_vccs(entry);
+- /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
+- kfree(entry);
+- }
+- else {
+- entry->next = priv->mcast_fwds;
+- priv->mcast_fwds = entry;
+- }
+- entry = next;
+- }
++
++ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
++ if (vcc == entry->vcc) {
++ lec_arp_remove(priv, entry);
++ lec_arp_put(entry);
++ if (priv->mcast_vcc == vcc) {
++ priv->mcast_vcc = NULL;
++ }
++ }
++ }
++ }
++
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
++ if (entry->vcc == vcc) {
++ lec_arp_clear_vccs(entry);
++ del_timer(&entry->timer);
++ hlist_del(&entry->next);
++ lec_arp_put(entry);
++ }
++ }
++
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
++ if (entry->recv_vcc == vcc) {
++ lec_arp_clear_vccs(entry);
++ del_timer(&entry->timer);
++ hlist_del(&entry->next);
++ lec_arp_put(entry);
++ }
++ }
++
++ hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
++ if (entry->recv_vcc == vcc) {
++ lec_arp_clear_vccs(entry);
++ /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
++ hlist_del(&entry->next);
++ lec_arp_put(entry);
++ }
++ }
+
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ dump_arp_table(priv);
+@@ -2517,57 +2483,42 @@ lec_vcc_close(struct lec_priv *priv, str
+
+ static void
+ lec_arp_check_empties(struct lec_priv *priv,
+- struct atm_vcc *vcc, struct sk_buff *skb)
++ struct atm_vcc *vcc, struct sk_buff *skb)
+ {
+- unsigned long flags;
+- struct lec_arp_table *entry, *prev;
+- struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
+- unsigned char *src;
++ unsigned long flags;
++ struct hlist_node *node, *next;
++ struct lec_arp_table *entry, *tmp;
++ struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
++ unsigned char *src;
+ #ifdef CONFIG_TR
+- struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
++ struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
+
+- if (priv->is_trdev) src = tr_hdr->h_source;
+- else
++ if (priv->is_trdev)
++ src = tr_hdr->h_source;
++ else
+ #endif
+- src = hdr->h_source;
++ src = hdr->h_source;
+
+ spin_lock_irqsave(&priv->lec_arp_lock, flags);
+- entry = priv->lec_arp_empty_ones;
+- if (vcc == entry->vcc) {
+- del_timer(&entry->timer);
+- memcpy(entry->mac_addr, src, ETH_ALEN);
+- entry->status = ESI_FORWARD_DIRECT;
+- entry->last_used = jiffies;
+- priv->lec_arp_empty_ones = entry->next;
+- /* We might have got an entry */
+- if ((prev = lec_arp_find(priv,src))) {
+- lec_arp_remove(priv, prev);
+- kfree(prev);
+- }
+- lec_arp_add(priv, entry);
+- goto out;
+- }
+- prev = entry;
+- entry = entry->next;
+- while (entry && entry->vcc != vcc) {
+- prev= entry;
+- entry = entry->next;
+- }
+- if (!entry) {
+- DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
+- goto out;
+- }
+- del_timer(&entry->timer);
+- memcpy(entry->mac_addr, src, ETH_ALEN);
+- entry->status = ESI_FORWARD_DIRECT;
+- entry->last_used = jiffies;
+- prev->next = entry->next;
+- if ((prev = lec_arp_find(priv, src))) {
+- lec_arp_remove(priv, prev);
+- kfree(prev);
+- }
+- lec_arp_add(priv, entry);
++ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
++ if (vcc == entry->vcc) {
++ del_timer(&entry->timer);
++ memcpy(entry->mac_addr, src, ETH_ALEN);
++ entry->status = ESI_FORWARD_DIRECT;
++ entry->last_used = jiffies;
++ /* We might have got an entry */
++ if ((tmp = lec_arp_find(priv, src))) {
++ lec_arp_remove(priv, tmp);
++ lec_arp_put(tmp);
++ }
++ hlist_del(&entry->next);
++ lec_arp_add(priv, entry);
++ goto out;
++ }
++ }
++ DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
+ out:
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ }
++
+ MODULE_LICENSE("GPL");
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index c22a8bf..877f509 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -1,9 +1,7 @@
+ /*
+- *
+ * Lan Emulation client header file
+ *
+- * Marko Kiiskila mkiiskila at yahoo.com
+- *
++ * Marko Kiiskila <mkiiskila at yahoo.com>
+ */
+
+ #ifndef _LEC_H_
+@@ -16,18 +14,18 @@
+ #define LEC_HEADER_LEN 16
+
+ struct lecdatahdr_8023 {
+- unsigned short le_header;
+- unsigned char h_dest[ETH_ALEN];
+- unsigned char h_source[ETH_ALEN];
+- unsigned short h_type;
++ unsigned short le_header;
++ unsigned char h_dest[ETH_ALEN];
++ unsigned char h_source[ETH_ALEN];
++ unsigned short h_type;
+ };
+
+ struct lecdatahdr_8025 {
+- unsigned short le_header;
+- unsigned char ac_pad;
+- unsigned char fc;
+- unsigned char h_dest[ETH_ALEN];
+- unsigned char h_source[ETH_ALEN];
++ unsigned short le_header;
++ unsigned char ac_pad;
++ unsigned char fc;
++ unsigned char h_dest[ETH_ALEN];
++ unsigned char h_source[ETH_ALEN];
+ };
+
+ #define LEC_MINIMUM_8023_SIZE 62
+@@ -44,17 +42,18 @@ struct lecdatahdr_8025 {
+ *
+ */
+ struct lane2_ops {
+- int (*resolve)(struct net_device *dev, u8 *dst_mac, int force,
+- u8 **tlvs, u32 *sizeoftlvs);
+- int (*associate_req)(struct net_device *dev, u8 *lan_dst,
+- u8 *tlvs, u32 sizeoftlvs);
+- void (*associate_indicator)(struct net_device *dev, u8 *mac_addr,
+- u8 *tlvs, u32 sizeoftlvs);
++ int (*resolve) (struct net_device *dev, u8 *dst_mac, int force,
++ u8 **tlvs, u32 *sizeoftlvs);
++ int (*associate_req) (struct net_device *dev, u8 *lan_dst,
++ u8 *tlvs, u32 sizeoftlvs);
++ void (*associate_indicator) (struct net_device *dev, u8 *mac_addr,
++ u8 *tlvs, u32 sizeoftlvs);
+ };
+
+ /*
+ * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType
+ * frames.
++ *
+ * 1. Dix Ethernet EtherType frames encoded by placing EtherType
+ * field in h_type field. Data follows immediatelly after header.
+ * 2. LLC Data frames whose total length, including LLC field and data,
+@@ -70,72 +69,88 @@ struct lane2_ops {
+ #define LEC_ARP_TABLE_SIZE 16
+
+ struct lec_priv {
+- struct net_device_stats stats;
+- unsigned short lecid; /* Lecid of this client */
+- struct lec_arp_table *lec_arp_empty_ones;
+- /* Used for storing VCC's that don't have a MAC address attached yet */
+- struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE];
+- /* Actual LE ARP table */
+- struct lec_arp_table *lec_no_forward;
+- /* Used for storing VCC's (and forward packets from) which are to
+- age out by not using them to forward packets.
+- This is because to some LE clients there will be 2 VCCs. Only
+- one of them gets used. */
+- struct lec_arp_table *mcast_fwds;
+- /* With LANEv2 it is possible that BUS (or a special multicast server)
+- establishes multiple Multicast Forward VCCs to us. This list
+- collects all those VCCs. LANEv1 client has only one item in this
+- list. These entries are not aged out. */
+- spinlock_t lec_arp_lock;
+- struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
+- struct timer_list lec_arp_timer;
+- /* C10 */
+- unsigned int maximum_unknown_frame_count;
+-/* Within the period of time defined by this variable, the client will send
+- no more than C10 frames to BUS for a given unicast destination. (C11) */
+- unsigned long max_unknown_frame_time;
+-/* If no traffic has been sent in this vcc for this period of time,
+- vcc will be torn down (C12)*/
+- unsigned long vcc_timeout_period;
+-/* An LE Client MUST not retry an LE_ARP_REQUEST for a
+- given frame's LAN Destination more than maximum retry count times,
+- after the first LEC_ARP_REQUEST (C13)*/
+- unsigned short max_retry_count;
+-/* Max time the client will maintain an entry in its arp cache in
+- absence of a verification of that relationship (C17)*/
+- unsigned long aging_time;
+-/* Max time the client will maintain an entry in cache when
+- topology change flag is true (C18) */
+- unsigned long forward_delay_time;
+-/* Topology change flag (C19)*/
+- int topology_change;
+-/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
+- cycle to take (C20)*/
+- unsigned long arp_response_time;
+-/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
+- LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/
+- unsigned long flush_timeout;
+-/* The time since sending a frame to the bus after which the
+- LE Client may assume that the frame has been either discarded or
+- delivered to the recipient (C22) */
+- unsigned long path_switching_delay;
++ struct net_device_stats stats;
++ unsigned short lecid; /* Lecid of this client */
++ struct hlist_head lec_arp_empty_ones;
++ /* Used for storing VCC's that don't have a MAC address attached yet */
++ struct hlist_head lec_arp_tables[LEC_ARP_TABLE_SIZE];
++ /* Actual LE ARP table */
++ struct hlist_head lec_no_forward;
++ /*
++ * Used for storing VCC's (and forward packets from) which are to
++ * age out by not using them to forward packets.
++ * This is because to some LE clients there will be 2 VCCs. Only
++ * one of them gets used.
++ */
++ struct hlist_head mcast_fwds;
++ /*
++ * With LANEv2 it is possible that BUS (or a special multicast server)
++ * establishes multiple Multicast Forward VCCs to us. This list
++ * collects all those VCCs. LANEv1 client has only one item in this
++ * list. These entries are not aged out.
++ */
++ spinlock_t lec_arp_lock;
++ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
++ struct atm_vcc *lecd;
++ struct work_struct lec_arp_work; /* C10 */
++ unsigned int maximum_unknown_frame_count;
++ /*
++ * Within the period of time defined by this variable, the client will send
++ * no more than C10 frames to BUS for a given unicast destination. (C11)
++ */
++ unsigned long max_unknown_frame_time;
++ /*
++ * If no traffic has been sent in this vcc for this period of time,
++ * vcc will be torn down (C12)
++ */
++ unsigned long vcc_timeout_period;
++ /*
++ * An LE Client MUST not retry an LE_ARP_REQUEST for a
++ * given frame's LAN Destination more than maximum retry count times,
++ * after the first LEC_ARP_REQUEST (C13)
++ */
++ unsigned short max_retry_count;
++ /*
++ * Max time the client will maintain an entry in its arp cache in
++ * absence of a verification of that relationship (C17)
++ */
++ unsigned long aging_time;
++ /*
++ * Max time the client will maintain an entry in cache when
++ * topology change flag is true (C18)
++ */
++ unsigned long forward_delay_time; /* Topology change flag (C19) */
++ int topology_change;
++ /*
++ * Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
++ * cycle to take (C20)
++ */
++ unsigned long arp_response_time;
++ /*
++ * Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
++ * LE_FLUSH_REQUEST has been sent before taking recover action. (C21)
++ */
++ unsigned long flush_timeout;
++ /* The time since sending a frame to the bus after which the
++ * LE Client may assume that the frame has been either discarded or
++ * delivered to the recipient (C22)
++ */
++ unsigned long path_switching_delay;
+
+- u8 *tlvs; /* LANE2: TLVs are new */
+- u32 sizeoftlvs; /* The size of the tlv array in bytes */
+- int lane_version; /* LANE2 */
+- int itfnum; /* e.g. 2 for lec2, 5 for lec5 */
+- struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */
+- int is_proxy; /* bridge between ATM and Ethernet */
+- int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */
++ u8 *tlvs; /* LANE2: TLVs are new */
++ u32 sizeoftlvs; /* The size of the tlv array in bytes */
++ int lane_version; /* LANE2 */
++ int itfnum; /* e.g. 2 for lec2, 5 for lec5 */
++ struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */
++ int is_proxy; /* bridge between ATM and Ethernet */
++ int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */
+ };
+
+ struct lec_vcc_priv {
+- void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
++ void (*old_pop) (struct atm_vcc *vcc, struct sk_buff *skb);
+ int xoff;
+ };
+
+ #define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back))
+
+-#endif /* _LEC_H_ */
+-
++#endif /* _LEC_H_ */
+diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h
+index 3974480..ec67435 100644
+--- a/net/atm/lec_arpc.h
++++ b/net/atm/lec_arpc.h
+@@ -1,92 +1,96 @@
+ /*
+ * Lec arp cache
+- * Marko Kiiskila mkiiskila at yahoo.com
+ *
++ * Marko Kiiskila <mkiiskila at yahoo.com>
+ */
+-#ifndef _LEC_ARP_H
+-#define _LEC_ARP_H
++#ifndef _LEC_ARP_H_
++#define _LEC_ARP_H_
+ #include <linux/atm.h>
+ #include <linux/atmdev.h>
+ #include <linux/if_ether.h>
+ #include <linux/atmlec.h>
+
+ struct lec_arp_table {
+- struct lec_arp_table *next; /* Linked entry list */
+- unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
+- unsigned char mac_addr[ETH_ALEN]; /* Mac address */
+- int is_rdesc; /* Mac address is a route descriptor */
+- struct atm_vcc *vcc; /* Vcc this entry is attached */
+- struct atm_vcc *recv_vcc; /* Vcc we receive data from */
+- void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
+- /* Push that leads to daemon */
+- void (*old_recv_push)(struct atm_vcc *vcc, struct sk_buff *skb);
+- /* Push that leads to daemon */
+- void (*old_close)(struct atm_vcc *vcc);
+- /* We want to see when this
+- * vcc gets closed */
+- unsigned long last_used; /* For expiry */
+- unsigned long timestamp; /* Used for various timestamping
+- * things:
+- * 1. FLUSH started
+- * (status=ESI_FLUSH_PENDING)
+- * 2. Counting to
+- * max_unknown_frame_time
+- * (status=ESI_ARP_PENDING||
+- * status=ESI_VC_PENDING)
+- */
+- unsigned char no_tries; /* No of times arp retry has been
+- tried */
+- unsigned char status; /* Status of this entry */
+- unsigned short flags; /* Flags for this entry */
+- unsigned short packets_flooded; /* Data packets flooded */
+- unsigned long flush_tran_id; /* Transaction id in flush protocol */
+- struct timer_list timer; /* Arping timer */
+- struct lec_priv *priv; /* Pointer back */
++ struct hlist_node next; /* Linked entry list */
++ unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
++ unsigned char mac_addr[ETH_ALEN]; /* Mac address */
++ int is_rdesc; /* Mac address is a route descriptor */
++ struct atm_vcc *vcc; /* Vcc this entry is attached */
++ struct atm_vcc *recv_vcc; /* Vcc we receive data from */
+
+- u8 *tlvs; /* LANE2: Each MAC address can have TLVs */
+- u32 sizeoftlvs; /* associated with it. sizeoftlvs tells the */
+- /* the length of the tlvs array */
+- struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
++ void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb);
++ /* Push that leads to daemon */
++
++ void (*old_recv_push) (struct atm_vcc *vcc, struct sk_buff *skb);
++ /* Push that leads to daemon */
++
++ unsigned long last_used; /* For expiry */
++ unsigned long timestamp; /* Used for various timestamping things:
++ * 1. FLUSH started
++ * (status=ESI_FLUSH_PENDING)
++ * 2. Counting to
++ * max_unknown_frame_time
++ * (status=ESI_ARP_PENDING||
++ * status=ESI_VC_PENDING)
++ */
++ unsigned char no_tries; /* No of times arp retry has been tried */
++ unsigned char status; /* Status of this entry */
++ unsigned short flags; /* Flags for this entry */
++ unsigned short packets_flooded; /* Data packets flooded */
++ unsigned long flush_tran_id; /* Transaction id in flush protocol */
++ struct timer_list timer; /* Arping timer */
++ struct lec_priv *priv; /* Pointer back */
++ u8 *tlvs;
++ u32 sizeoftlvs; /*
++ * LANE2: Each MAC address can have TLVs
++ * associated with it. sizeoftlvs tells the
++ * the length of the tlvs array
++ */
++ struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
++ atomic_t usage; /* usage count */
+ };
+
+-struct tlv { /* LANE2: Template tlv struct for accessing */
+- /* the tlvs in the lec_arp_table->tlvs array*/
+- u32 type;
+- u8 length;
+- u8 value[255];
++/*
++ * LANE2: Template tlv struct for accessing
++ * the tlvs in the lec_arp_table->tlvs array
++ */
++struct tlv {
++ u32 type;
++ u8 length;
++ u8 value[255];
+ };
+
+ /* Status fields */
+-#define ESI_UNKNOWN 0 /*
+- * Next packet sent to this mac address
+- * causes ARP-request to be sent
+- */
+-#define ESI_ARP_PENDING 1 /*
+- * There is no ATM address associated with this
+- * 48-bit address. The LE-ARP protocol is in
+- * progress.
+- */
+-#define ESI_VC_PENDING 2 /*
+- * There is a valid ATM address associated with
+- * this 48-bit address but there is no VC set
+- * up to that ATM address. The signaling
+- * protocol is in process.
+- */
+-#define ESI_FLUSH_PENDING 4 /*
+- * The LEC has been notified of the FLUSH_START
+- * status and it is assumed that the flush
+- * protocol is in process.
+- */
+-#define ESI_FORWARD_DIRECT 5 /*
+- * Either the Path Switching Delay (C22) has
+- * elapsed or the LEC has notified the Mapping
+- * that the flush protocol has completed. In
+- * either case, it is safe to forward packets
+- * to this address via the data direct VC.
+- */
++#define ESI_UNKNOWN 0 /*
++ * Next packet sent to this mac address
++ * causes ARP-request to be sent
++ */
++#define ESI_ARP_PENDING 1 /*
++ * There is no ATM address associated with this
++ * 48-bit address. The LE-ARP protocol is in
++ * progress.
++ */
++#define ESI_VC_PENDING 2 /*
++ * There is a valid ATM address associated with
++ * this 48-bit address but there is no VC set
++ * up to that ATM address. The signaling
++ * protocol is in process.
++ */
++#define ESI_FLUSH_PENDING 4 /*
++ * The LEC has been notified of the FLUSH_START
++ * status and it is assumed that the flush
++ * protocol is in process.
++ */
++#define ESI_FORWARD_DIRECT 5 /*
++ * Either the Path Switching Delay (C22) has
++ * elapsed or the LEC has notified the Mapping
++ * that the flush protocol has completed. In
++ * either case, it is safe to forward packets
++ * to this address via the data direct VC.
++ */
+
+ /* Flag values */
+ #define LEC_REMOTE_FLAG 0x0001
+ #define LEC_PERMANENT_FLAG 0x0002
+
+-#endif
++#endif /* _LEC_ARP_H_ */
+diff --git a/net/atm/mpc.c b/net/atm/mpc.c
+index 0070466..0d2b994 100644
+--- a/net/atm/mpc.c
++++ b/net/atm/mpc.c
+@@ -98,11 +98,6 @@ static struct notifier_block mpoa_notifi
+ 0
+ };
+
+-#ifdef CONFIG_PROC_FS
+-extern int mpc_proc_init(void);
+-extern void mpc_proc_clean(void);
+-#endif
+-
+ struct mpoa_client *mpcs = NULL; /* FIXME */
+ static struct atm_mpoa_qos *qos_head = NULL;
+ static DEFINE_TIMER(mpc_timer, NULL, 0, 0);
+@@ -565,7 +560,6 @@ static int atm_mpoa_vcc_attach(struct at
+ struct atmmpc_ioc ioc_data;
+ in_cache_entry *in_entry;
+ uint32_t ipaddr;
+- unsigned char *ip;
+
+ bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc));
+ if (bytes_left != 0) {
+@@ -588,9 +582,8 @@ static int atm_mpoa_vcc_attach(struct at
+ if (in_entry != NULL) mpc->in_ops->put(in_entry);
+ return -EINVAL;
+ }
+- ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip;
+ printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
+- mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
++ mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
+ in_entry->shortcut = vcc;
+ mpc->in_ops->put(in_entry);
+ } else {
+@@ -621,10 +614,8 @@ static void mpc_vcc_close(struct atm_vcc
+ dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
+ in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
+ if (in_entry) {
+- unsigned char *ip __attribute__ ((unused)) =
+- (unsigned char *)&in_entry->ctrl_info.in_dst_ip;
+ dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
+- mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
++ mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
+ in_entry->shortcut = NULL;
+ mpc->in_ops->put(in_entry);
+ }
+@@ -1159,18 +1150,17 @@ static void ingress_purge_rcvd(struct k_
+ {
+ uint32_t dst_ip = msg->content.in_info.in_dst_ip;
+ uint32_t mask = msg->ip_mask;
+- unsigned char *ip = (unsigned char *)&dst_ip;
+ in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
+
+ if(entry == NULL){
+ printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name);
+- printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
++ printk("ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
+ return;
+ }
+
+ do {
+ dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
+- mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
++ mpc->dev->name, NIPQUAD(dst_ip));
+ write_lock_bh(&mpc->ingress_lock);
+ mpc->in_ops->remove_entry(entry, mpc);
+ write_unlock_bh(&mpc->ingress_lock);
+@@ -1439,12 +1429,8 @@ static __init int atm_mpoa_init(void)
+ {
+ register_atm_ioctl(&atm_ioctl_ops);
+
+-#ifdef CONFIG_PROC_FS
+ if (mpc_proc_init() != 0)
+ printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
+- else
+- printk(KERN_INFO "mpoa: /proc/mpoa initialized\n");
+-#endif
+
+ printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
+
+@@ -1457,9 +1443,7 @@ static void __exit atm_mpoa_cleanup(void
+ struct atm_mpoa_qos *qos, *nextqos;
+ struct lec_priv *priv;
+
+-#ifdef CONFIG_PROC_FS
+ mpc_proc_clean();
+-#endif
+
+ del_timer(&mpc_timer);
+ unregister_netdevice_notifier(&mpoa_notifier);
+diff --git a/net/atm/mpc.h b/net/atm/mpc.h
+index 863ddf6..3c7981a 100644
+--- a/net/atm/mpc.h
++++ b/net/atm/mpc.h
+@@ -50,4 +50,12 @@ int atm_mpoa_delete_qos(struct atm_mpoa_
+ struct seq_file;
+ void atm_mpoa_disp_qos(struct seq_file *m);
+
++#ifdef CONFIG_PROC_FS
++int mpc_proc_init(void);
++void mpc_proc_clean(void);
++#else
++#define mpc_proc_init() (0)
++#define mpc_proc_clean() do { } while(0)
++#endif
++
+ #endif /* _MPC_H_ */
+diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c
+index 781ed1b..fbf13cd 100644
+--- a/net/atm/mpoa_caches.c
++++ b/net/atm/mpoa_caches.c
+@@ -87,7 +87,6 @@ static in_cache_entry *in_cache_get_by_v
+ static in_cache_entry *in_cache_add_entry(uint32_t dst_ip,
+ struct mpoa_client *client)
+ {
+- unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
+ in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL);
+
+ if (entry == NULL) {
+@@ -95,7 +94,7 @@ static in_cache_entry *in_cache_add_entr
+ return NULL;
+ }
+
+- dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
++ dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
+ memset(entry,0,sizeof(in_cache_entry));
+
+ atomic_set(&entry->use, 1);
+@@ -152,10 +151,7 @@ static int cache_hit(in_cache_entry *ent
+
+ if( entry->count > mpc->parameters.mpc_p1 &&
+ entry->entry_state == INGRESS_INVALID){
+- unsigned char *ip __attribute__ ((unused)) =
+- (unsigned char *)&entry->ctrl_info.in_dst_ip;
+-
+- dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
++ dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, NIPQUAD(entry->ctrl_info.in_dst_ip));
+ entry->entry_state = INGRESS_RESOLVING;
+ msg.type = SND_MPOA_RES_RQST;
+ memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
+@@ -187,11 +183,9 @@ static void in_cache_remove_entry(in_cac
+ {
+ struct atm_vcc *vcc;
+ struct k_message msg;
+- unsigned char *ip;
+
+ vcc = entry->shortcut;
+- ip = (unsigned char *)&entry->ctrl_info.in_dst_ip;
+- dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]);
++ dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip));
+
+ if (entry->prev != NULL)
+ entry->prev->next = entry->next;
+diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
+index 788ea7a..67df99e 100644
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -48,41 +48,56 @@
+ #define BT_DBG(D...)
+ #endif
+
+-#define VERSION "2.10"
++#define VERSION "2.11"
+
+ /* Bluetooth sockets */
+ #define BT_MAX_PROTO 8
+ static struct net_proto_family *bt_proto[BT_MAX_PROTO];
++static DEFINE_RWLOCK(bt_proto_lock);
+
+ int bt_sock_register(int proto, struct net_proto_family *ops)
+ {
++ int err = 0;
++
+ if (proto < 0 || proto >= BT_MAX_PROTO)
+ return -EINVAL;
+
++ write_lock(&bt_proto_lock);
++
+ if (bt_proto[proto])
+- return -EEXIST;
++ err = -EEXIST;
++ else
++ bt_proto[proto] = ops;
+
+- bt_proto[proto] = ops;
+- return 0;
++ write_unlock(&bt_proto_lock);
++
++ return err;
+ }
+ EXPORT_SYMBOL(bt_sock_register);
+
+ int bt_sock_unregister(int proto)
+ {
++ int err = 0;
++
+ if (proto < 0 || proto >= BT_MAX_PROTO)
+ return -EINVAL;
+
++ write_lock(&bt_proto_lock);
++
+ if (!bt_proto[proto])
+- return -ENOENT;
++ err = -ENOENT;
++ else
++ bt_proto[proto] = NULL;
+
+- bt_proto[proto] = NULL;
+- return 0;
++ write_unlock(&bt_proto_lock);
++
++ return err;
+ }
+ EXPORT_SYMBOL(bt_sock_unregister);
+
+ static int bt_sock_create(struct socket *sock, int proto)
+ {
+- int err = 0;
++ int err;
+
+ if (proto < 0 || proto >= BT_MAX_PROTO)
+ return -EINVAL;
+@@ -92,11 +107,18 @@ static int bt_sock_create(struct socket
+ request_module("bt-proto-%d", proto);
+ }
+ #endif
++
+ err = -EPROTONOSUPPORT;
++
++ read_lock(&bt_proto_lock);
++
+ if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
+ err = bt_proto[proto]->create(sock, proto);
+ module_put(bt_proto[proto]->owner);
+ }
++
++ read_unlock(&bt_proto_lock);
++
+ return err;
+ }
+
+@@ -276,7 +298,7 @@ int bt_sock_wait_state(struct sock *sk,
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (!timeo) {
+- err = -EAGAIN;
++ err = -EINPROGRESS;
+ break;
+ }
+
+diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
+index e620061..4d3424c 100644
+--- a/net/bluetooth/bnep/core.c
++++ b/net/bluetooth/bnep/core.c
+@@ -51,6 +51,7 @@
+ #include <asm/unaligned.h>
+
+ #include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
+ #include <net/bluetooth/l2cap.h>
+
+ #include "bnep.h"
+@@ -515,6 +516,24 @@ static int bnep_session(void *arg)
+ return 0;
+ }
+
++static struct device *bnep_get_device(struct bnep_session *session)
++{
++ bdaddr_t *src = &bt_sk(session->sock->sk)->src;
++ bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
++ struct hci_dev *hdev;
++ struct hci_conn *conn;
++
++ hdev = hci_get_route(dst, src);
++ if (!hdev)
++ return NULL;
++
++ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
++
++ hci_dev_put(hdev);
++
++ return conn ? &conn->dev : NULL;
++}
++
+ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
+ {
+ struct net_device *dev;
+@@ -534,7 +553,6 @@ int bnep_add_connection(struct bnep_conn
+ if (!dev)
+ return -ENOMEM;
+
+-
+ down_write(&bnep_session_sem);
+
+ ss = __bnep_get_session(dst);
+@@ -551,7 +569,7 @@ int bnep_add_connection(struct bnep_conn
+ memcpy(s->eh.h_source, &dst, ETH_ALEN);
+ memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
+
+- s->dev = dev;
++ s->dev = dev;
+ s->sock = sock;
+ s->role = req->role;
+ s->state = BT_CONNECTED;
+@@ -568,6 +586,8 @@ int bnep_add_connection(struct bnep_conn
+ bnep_set_default_proto_filter(s);
+ #endif
+
++ SET_NETDEV_DEV(dev, bnep_get_device(s));
++
+ err = register_netdev(dev);
+ if (err) {
+ goto failed;
+diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
+index 28c5583..5563db1 100644
+--- a/net/bluetooth/bnep/sock.c
++++ b/net/bluetooth/bnep/sock.c
+@@ -43,6 +43,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/file.h>
+ #include <linux/init.h>
++#include <linux/compat.h>
+ #include <net/sock.h>
+
+ #include <asm/system.h>
+@@ -146,24 +147,56 @@ static int bnep_sock_ioctl(struct socket
+ return 0;
+ }
+
++#ifdef CONFIG_COMPAT
++static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++ if (cmd == BNEPGETCONNLIST) {
++ struct bnep_connlist_req cl;
++ uint32_t uci;
++ int err;
++
++ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
++ get_user(uci, (u32 __user *) (arg + 4)))
++ return -EFAULT;
++
++ cl.ci = compat_ptr(uci);
++
++ if (cl.cnum <= 0)
++ return -EINVAL;
++
++ err = bnep_get_connlist(&cl);
++
++ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
++ err = -EFAULT;
++
++ return err;
++ }
++
++ return bnep_sock_ioctl(sock, cmd, arg);
++}
++#endif
++
+ static const struct proto_ops bnep_sock_ops = {
+- .family = PF_BLUETOOTH,
+- .owner = THIS_MODULE,
+- .release = bnep_sock_release,
+- .ioctl = bnep_sock_ioctl,
+- .bind = sock_no_bind,
+- .getname = sock_no_getname,
+- .sendmsg = sock_no_sendmsg,
+- .recvmsg = sock_no_recvmsg,
+- .poll = sock_no_poll,
+- .listen = sock_no_listen,
+- .shutdown = sock_no_shutdown,
+- .setsockopt = sock_no_setsockopt,
+- .getsockopt = sock_no_getsockopt,
+- .connect = sock_no_connect,
+- .socketpair = sock_no_socketpair,
+- .accept = sock_no_accept,
+- .mmap = sock_no_mmap
++ .family = PF_BLUETOOTH,
++ .owner = THIS_MODULE,
++ .release = bnep_sock_release,
++ .ioctl = bnep_sock_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = bnep_sock_compat_ioctl,
++#endif
++ .bind = sock_no_bind,
++ .getname = sock_no_getname,
++ .sendmsg = sock_no_sendmsg,
++ .recvmsg = sock_no_recvmsg,
++ .poll = sock_no_poll,
++ .listen = sock_no_listen,
++ .shutdown = sock_no_shutdown,
++ .setsockopt = sock_no_setsockopt,
++ .getsockopt = sock_no_getsockopt,
++ .connect = sock_no_connect,
++ .socketpair = sock_no_socketpair,
++ .accept = sock_no_accept,
++ .mmap = sock_no_mmap
+ };
+
+ static struct proto bnep_proto = {
+@@ -181,7 +214,7 @@ static int bnep_sock_create(struct socke
+ if (sock->type != SOCK_RAW)
+ return -ESOCKTNOSUPPORT;
+
+- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &bnep_proto, 1);
++ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1);
+ if (!sk)
+ return -ENOMEM;
+
+diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
+index 10ad7fd..53295d3 100644
+--- a/net/bluetooth/cmtp/sock.c
++++ b/net/bluetooth/cmtp/sock.c
+@@ -34,6 +34,7 @@
+ #include <linux/socket.h>
+ #include <linux/ioctl.h>
+ #include <linux/file.h>
++#include <linux/compat.h>
+ #include <net/sock.h>
+
+ #include <linux/isdn/capilli.h>
+@@ -137,11 +138,43 @@ static int cmtp_sock_ioctl(struct socket
+ return -EINVAL;
+ }
+
++#ifdef CONFIG_COMPAT
++static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++ if (cmd == CMTPGETCONNLIST) {
++ struct cmtp_connlist_req cl;
++ uint32_t uci;
++ int err;
++
++ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
++ get_user(uci, (u32 __user *) (arg + 4)))
++ return -EFAULT;
++
++ cl.ci = compat_ptr(uci);
++
++ if (cl.cnum <= 0)
++ return -EINVAL;
++
++ err = cmtp_get_connlist(&cl);
++
++ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
++ err = -EFAULT;
++
++ return err;
++ }
++
++ return cmtp_sock_ioctl(sock, cmd, arg);
++}
++#endif
++
+ static const struct proto_ops cmtp_sock_ops = {
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .release = cmtp_sock_release,
+ .ioctl = cmtp_sock_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = cmtp_sock_compat_ioctl,
++#endif
+ .bind = sock_no_bind,
+ .getname = sock_no_getname,
+ .sendmsg = sock_no_sendmsg,
+@@ -172,7 +205,7 @@ static int cmtp_sock_create(struct socke
+ if (sock->type != SOCK_RAW)
+ return -ESOCKTNOSUPPORT;
+
+- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1);
++ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1);
+ if (!sk)
+ return -ENOMEM;
+
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index 420ed4d..6cd5711 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -51,7 +51,7 @@
+ #define BT_DBG(D...)
+ #endif
+
+-static void hci_acl_connect(struct hci_conn *conn)
++void hci_acl_connect(struct hci_conn *conn)
+ {
+ struct hci_dev *hdev = conn->hdev;
+ struct inquiry_entry *ie;
+@@ -63,6 +63,8 @@ static void hci_acl_connect(struct hci_c
+ conn->out = 1;
+ conn->link_mode = HCI_LM_MASTER;
+
++ conn->attempt++;
++
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, &conn->dst);
+ cp.pscan_rep_mode = 0x02;
+@@ -80,10 +82,24 @@ static void hci_acl_connect(struct hci_c
+ cp.role_switch = 0x01;
+ else
+ cp.role_switch = 0x00;
+-
++
+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
+ }
+
++static void hci_acl_connect_cancel(struct hci_conn *conn)
++{
++ struct hci_cp_create_conn_cancel cp;
++
++ BT_DBG("%p", conn);
++
++ if (conn->hdev->hci_ver < 2)
++ return;
++
++ bacpy(&cp.bdaddr, &conn->dst);
++ hci_send_cmd(conn->hdev, OGF_LINK_CTL,
++ OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
++}
++
+ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
+ {
+ struct hci_cp_disconnect cp;
+@@ -94,7 +110,8 @@ void hci_acl_disconn(struct hci_conn *co
+
+ cp.handle = __cpu_to_le16(conn->handle);
+ cp.reason = reason;
+- hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, sizeof(cp), &cp);
++ hci_send_cmd(conn->hdev, OGF_LINK_CTL,
++ OCF_DISCONNECT, sizeof(cp), &cp);
+ }
+
+ void hci_add_sco(struct hci_conn *conn, __u16 handle)
+@@ -124,12 +141,20 @@ static void hci_conn_timeout(unsigned lo
+ return;
+
+ hci_dev_lock(hdev);
+- if (conn->state == BT_CONNECTED)
++
++ switch (conn->state) {
++ case BT_CONNECT:
++ hci_acl_connect_cancel(conn);
++ break;
++ case BT_CONNECTED:
+ hci_acl_disconn(conn, 0x13);
+- else
++ break;
++ default:
+ conn->state = BT_CLOSED;
++ break;
++ }
++
+ hci_dev_unlock(hdev);
+- return;
+ }
+
+ static void hci_conn_idle(unsigned long arg)
+@@ -179,6 +204,8 @@ struct hci_conn *hci_conn_add(struct hci
+ if (hdev->notify)
+ hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
+
++ hci_conn_add_sysfs(conn);
++
+ tasklet_enable(&hdev->tx_task);
+
+ return conn;
+@@ -211,6 +238,8 @@ int hci_conn_del(struct hci_conn *conn)
+
+ tasklet_disable(&hdev->tx_task);
+
++ hci_conn_del_sysfs(conn);
++
+ hci_conn_hash_del(hdev, conn);
+ if (hdev->notify)
+ hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
+@@ -221,7 +250,9 @@ int hci_conn_del(struct hci_conn *conn)
+
+ hci_dev_put(hdev);
+
+- kfree(conn);
++ /* will free via device release */
++ put_device(&conn->dev);
++
+ return 0;
+ }
+
+diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
+index 5ed4742..338ae97 100644
+--- a/net/bluetooth/hci_core.c
++++ b/net/bluetooth/hci_core.c
+@@ -206,6 +206,9 @@ static void hci_init_req(struct hci_dev
+ /* Read Local Supported Features */
+ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
+
++ /* Read Local Version */
++ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
++
+ /* Read Buffer Size (ACL mtu, max pkt, etc.) */
+ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 3896dab..65f0948 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -62,6 +62,7 @@ static void hci_cc_link_ctl(struct hci_d
+
+ switch (ocf) {
+ case OCF_INQUIRY_CANCEL:
++ case OCF_EXIT_PERIODIC_INQ:
+ status = *((__u8 *) skb->data);
+
+ if (status) {
+@@ -297,6 +298,7 @@ static void hci_cc_host_ctl(struct hci_d
+ /* Command Complete OGF INFO_PARAM */
+ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+ {
++ struct hci_rp_read_loc_version *lv;
+ struct hci_rp_read_local_features *lf;
+ struct hci_rp_read_buffer_size *bs;
+ struct hci_rp_read_bd_addr *ba;
+@@ -304,6 +306,23 @@ static void hci_cc_info_param(struct hci
+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+
+ switch (ocf) {
++ case OCF_READ_LOCAL_VERSION:
++ lv = (struct hci_rp_read_loc_version *) skb->data;
++
++ if (lv->status) {
++ BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status);
++ break;
++ }
++
++ hdev->hci_ver = lv->hci_ver;
++ hdev->hci_rev = btohs(lv->hci_rev);
++ hdev->manufacturer = btohs(lv->manufacturer);
++
++ BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name,
++ hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
++
++ break;
++
+ case OCF_READ_LOCAL_FEATURES:
+ lf = (struct hci_rp_read_local_features *) skb->data;
+
+@@ -328,7 +347,8 @@ static void hci_cc_info_param(struct hci
+ if (hdev->features[1] & LMP_HV3)
+ hdev->pkt_type |= (HCI_HV3);
+
+- BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
++ BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
++ lf->features[0], lf->features[1], lf->features[2]);
+
+ break;
+
+@@ -394,9 +414,12 @@ static inline void hci_cs_create_conn(st
+
+ if (status) {
+ if (conn && conn->state == BT_CONNECT) {
+- conn->state = BT_CLOSED;
+- hci_proto_connect_cfm(conn, status);
+- hci_conn_del(conn);
++ if (status != 0x0c || conn->attempt > 2) {
++ conn->state = BT_CLOSED;
++ hci_proto_connect_cfm(conn, status);
++ hci_conn_del(conn);
++ } else
++ conn->state = BT_CONNECT2;
+ }
+ } else {
+ if (!conn) {
+@@ -708,7 +731,7 @@ static inline void hci_conn_request_evt(
+ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+ struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
+- struct hci_conn *conn;
++ struct hci_conn *conn, *pend;
+
+ BT_DBG("%s", hdev->name);
+
+@@ -757,6 +780,10 @@ static inline void hci_conn_complete_evt
+
+ hci_send_cmd(hdev, OGF_LINK_CTL,
+ OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
++ } else {
++ /* Update disconnect timer */
++ hci_conn_hold(conn);
++ hci_conn_put(conn);
+ }
+ } else
+ conn->state = BT_CLOSED;
+@@ -777,6 +804,10 @@ static inline void hci_conn_complete_evt
+ if (ev->status)
+ hci_conn_del(conn);
+
++ pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
++ if (pend)
++ hci_acl_connect(pend);
++
+ hci_dev_unlock(hdev);
+ }
+
+diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
+index 1a35d34..f26a9eb 100644
+--- a/net/bluetooth/hci_sock.c
++++ b/net/bluetooth/hci_sock.c
+@@ -618,7 +618,7 @@ static int hci_sock_create(struct socket
+
+ sock->ops = &hci_sock_ops;
+
+- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1);
++ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1);
+ if (!sk)
+ return -ENOMEM;
+
+diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
+index 3987d16..954eb74 100644
+--- a/net/bluetooth/hci_sysfs.c
++++ b/net/bluetooth/hci_sysfs.c
+@@ -13,16 +13,32 @@
+ #define BT_DBG(D...)
+ #endif
+
+-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
++static inline char *typetostr(int type)
+ {
+- struct hci_dev *hdev = dev_get_drvdata(dev);
+- return sprintf(buf, "%s\n", hdev->name);
++ switch (type) {
++ case HCI_VIRTUAL:
++ return "VIRTUAL";
++ case HCI_USB:
++ return "USB";
++ case HCI_PCCARD:
++ return "PCCARD";
++ case HCI_UART:
++ return "UART";
++ case HCI_RS232:
++ return "RS232";
++ case HCI_PCI:
++ return "PCI";
++ case HCI_SDIO:
++ return "SDIO";
++ default:
++ return "UNKNOWN";
++ }
+ }
+
+ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+- return sprintf(buf, "%d\n", hdev->type);
++ return sprintf(buf, "%s\n", typetostr(hdev->type));
+ }
+
+ static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -33,10 +49,22 @@ static ssize_t show_address(struct devic
+ return sprintf(buf, "%s\n", batostr(&bdaddr));
+ }
+
+-static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf)
++static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+- return sprintf(buf, "0x%lx\n", hdev->flags);
++ return sprintf(buf, "%d\n", hdev->manufacturer);
++}
++
++static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct hci_dev *hdev = dev_get_drvdata(dev);
++ return sprintf(buf, "%d\n", hdev->hci_ver);
++}
++
++static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct hci_dev *hdev = dev_get_drvdata(dev);
++ return sprintf(buf, "%d\n", hdev->hci_rev);
+ }
+
+ static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf)
+@@ -141,10 +169,11 @@ static ssize_t store_sniff_min_interval(
+ return count;
+ }
+
+-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+ static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+ static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+-static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
++static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
++static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
++static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
+ static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
+
+ static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
+@@ -155,10 +184,11 @@ static DEVICE_ATTR(sniff_min_interval, S
+ show_sniff_min_interval, store_sniff_min_interval);
+
+ static struct device_attribute *bt_attrs[] = {
+- &dev_attr_name,
+ &dev_attr_type,
+ &dev_attr_address,
+- &dev_attr_flags,
++ &dev_attr_manufacturer,
++ &dev_attr_hci_version,
++ &dev_attr_hci_revision,
+ &dev_attr_inquiry_cache,
+ &dev_attr_idle_timeout,
+ &dev_attr_sniff_max_interval,
+@@ -166,6 +196,32 @@ static struct device_attribute *bt_attrs
+ NULL
+ };
+
++static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct hci_conn *conn = dev_get_drvdata(dev);
++ return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO");
++}
++
++static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct hci_conn *conn = dev_get_drvdata(dev);
++ bdaddr_t bdaddr;
++ baswap(&bdaddr, &conn->dst);
++ return sprintf(buf, "%s\n", batostr(&bdaddr));
++}
++
++#define CONN_ATTR(_name,_mode,_show,_store) \
++struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
++
++static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
++static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
++
++static struct device_attribute *conn_attrs[] = {
++ &conn_attr_type,
++ &conn_attr_address,
++ NULL
++};
++
+ struct class *bt_class = NULL;
+ EXPORT_SYMBOL_GPL(bt_class);
+
+@@ -177,8 +233,61 @@ static struct platform_device *bt_platfo
+
+ static void bt_release(struct device *dev)
+ {
+- struct hci_dev *hdev = dev_get_drvdata(dev);
+- kfree(hdev);
++ void *data = dev_get_drvdata(dev);
++ kfree(data);
++}
++
++static void add_conn(void *data)
++{
++ struct hci_conn *conn = data;
++ int i;
++
++ if (device_register(&conn->dev) < 0) {
++ BT_ERR("Failed to register connection device");
++ return;
++ }
++
++ for (i = 0; conn_attrs[i]; i++)
++ if (device_create_file(&conn->dev, conn_attrs[i]) < 0)
++ BT_ERR("Failed to create connection attribute");
++}
++
++void hci_conn_add_sysfs(struct hci_conn *conn)
++{
++ struct hci_dev *hdev = conn->hdev;
++ bdaddr_t *ba = &conn->dst;
++
++ BT_DBG("conn %p", conn);
++
++ conn->dev.parent = &hdev->dev;
++ conn->dev.release = bt_release;
++
++ snprintf(conn->dev.bus_id, BUS_ID_SIZE,
++ "%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
++ conn->type == ACL_LINK ? "acl" : "sco",
++ ba->b[5], ba->b[4], ba->b[3],
++ ba->b[2], ba->b[1], ba->b[0]);
++
++ dev_set_drvdata(&conn->dev, conn);
++
++ INIT_WORK(&conn->work, add_conn, (void *) conn);
++
++ schedule_work(&conn->work);
++}
++
++static void del_conn(void *data)
++{
++ struct hci_conn *conn = data;
++ device_del(&conn->dev);
++}
++
++void hci_conn_del_sysfs(struct hci_conn *conn)
++{
++ BT_DBG("conn %p", conn);
++
++ INIT_WORK(&conn->work, del_conn, (void *) conn);
++
++ schedule_work(&conn->work);
+ }
+
+ int hci_register_sysfs(struct hci_dev *hdev)
+@@ -190,11 +299,7 @@ int hci_register_sysfs(struct hci_dev *h
+ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+
+ dev->class = bt_class;
+-
+- if (hdev->parent)
+- dev->parent = hdev->parent;
+- else
+- dev->parent = &bt_platform->dev;
++ dev->parent = hdev->parent;
+
+ strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
+
+@@ -207,18 +312,17 @@ int hci_register_sysfs(struct hci_dev *h
+ return err;
+
+ for (i = 0; bt_attrs[i]; i++)
+- device_create_file(dev, bt_attrs[i]);
++ if (device_create_file(dev, bt_attrs[i]) < 0)
++ BT_ERR("Failed to create device attribute");
+
+ return 0;
+ }
+
+ void hci_unregister_sysfs(struct hci_dev *hdev)
+ {
+- struct device *dev = &hdev->dev;
+-
+ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+
+- device_del(dev);
++ device_del(&hdev->dev);
+ }
+
+ int __init bt_sysfs_init(void)
+@@ -245,7 +349,7 @@ int __init bt_sysfs_init(void)
+ return 0;
+ }
+
+-void __exit bt_sysfs_cleanup(void)
++void bt_sysfs_cleanup(void)
+ {
+ class_destroy(bt_class);
+
+diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
+index c6e3a2c..6678201 100644
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -40,6 +40,7 @@
+ #include <linux/input.h>
+
+ #include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
+ #include <net/bluetooth/l2cap.h>
+
+ #include "hidp.h"
+@@ -506,14 +507,12 @@ static int hidp_session(void *arg)
+
+ hidp_del_timer(session);
+
+- if (intr_sk->sk_state != BT_CONNECTED)
+- wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ);
+-
+- fput(session->ctrl_sock->file);
++ fput(session->intr_sock->file);
+
+- wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ);
++ wait_event_timeout(*(ctrl_sk->sk_sleep),
++ (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
+
+- fput(session->intr_sock->file);
++ fput(session->ctrl_sock->file);
+
+ __hidp_unlink_session(session);
+
+@@ -528,6 +527,24 @@ static int hidp_session(void *arg)
+ return 0;
+ }
+
++static struct device *hidp_get_device(struct hidp_session *session)
++{
++ bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
++ bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
++ struct hci_dev *hdev;
++ struct hci_conn *conn;
++
++ hdev = hci_get_route(dst, src);
++ if (!hdev)
++ return NULL;
++
++ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
++
++ hci_dev_put(hdev);
++
++ return conn ? &conn->dev : NULL;
++}
++
+ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
+ {
+ struct input_dev *input = session->input;
+@@ -566,6 +583,8 @@ static inline void hidp_setup_input(stru
+ input->relbit[0] |= BIT(REL_WHEEL);
+ }
+
++ input->cdev.dev = hidp_get_device(session);
++
+ input->event = hidp_input_event;
+
+ input_register_device(input);
+diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
+index 099646e..407fba4 100644
+--- a/net/bluetooth/hidp/sock.c
++++ b/net/bluetooth/hidp/sock.c
+@@ -35,6 +35,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/file.h>
+ #include <linux/init.h>
++#include <linux/compat.h>
+ #include <net/sock.h>
+
+ #include "hidp.h"
+@@ -143,11 +144,88 @@ static int hidp_sock_ioctl(struct socket
+ return -EINVAL;
+ }
+
++#ifdef CONFIG_COMPAT
++struct compat_hidp_connadd_req {
++ int ctrl_sock; // Connected control socket
++ int intr_sock; // Connteted interrupt socket
++ __u16 parser;
++ __u16 rd_size;
++ compat_uptr_t rd_data;
++ __u8 country;
++ __u8 subclass;
++ __u16 vendor;
++ __u16 product;
++ __u16 version;
++ __u32 flags;
++ __u32 idle_to;
++ char name[128];
++};
++
++static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++ if (cmd == HIDPGETCONNLIST) {
++ struct hidp_connlist_req cl;
++ uint32_t uci;
++ int err;
++
++ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
++ get_user(uci, (u32 __user *) (arg + 4)))
++ return -EFAULT;
++
++ cl.ci = compat_ptr(uci);
++
++ if (cl.cnum <= 0)
++ return -EINVAL;
++
++ err = hidp_get_connlist(&cl);
++
++ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
++ err = -EFAULT;
++
++ return err;
++ } else if (cmd == HIDPCONNADD) {
++ struct compat_hidp_connadd_req ca;
++ struct hidp_connadd_req __user *uca;
++
++ uca = compat_alloc_user_space(sizeof(*uca));
++
++ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
++ return -EFAULT;
++
++ if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
++ put_user(ca.intr_sock, &uca->intr_sock) ||
++ put_user(ca.parser, &uca->parser) ||
++ put_user(ca.rd_size, &uca->parser) ||
++ put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
++ put_user(ca.country, &uca->country) ||
++ put_user(ca.subclass, &uca->subclass) ||
++ put_user(ca.vendor, &uca->vendor) ||
++ put_user(ca.product, &uca->product) ||
++ put_user(ca.version, &uca->version) ||
++ put_user(ca.flags, &uca->flags) ||
++ put_user(ca.idle_to, &uca->idle_to) ||
++ copy_to_user(&uca->name[0], &ca.name[0], 128))
++ return -EFAULT;
++
++ arg = (unsigned long) uca;
++
++ /* Fall through. We don't actually write back any _changes_
++ to the structure anyway, so there's no need to copy back
++ into the original compat version */
++ }
++
++ return hidp_sock_ioctl(sock, cmd, arg);
++}
++#endif
++
+ static const struct proto_ops hidp_sock_ops = {
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .release = hidp_sock_release,
+ .ioctl = hidp_sock_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = hidp_sock_compat_ioctl,
++#endif
+ .bind = sock_no_bind,
+ .getname = sock_no_getname,
+ .sendmsg = sock_no_sendmsg,
+@@ -178,7 +256,7 @@ static int hidp_sock_create(struct socke
+ if (sock->type != SOCK_RAW)
+ return -ESOCKTNOSUPPORT;
+
+- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1);
++ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1);
+ if (!sk)
+ return -ENOMEM;
+
+diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
+index d56f60b..2b3dcb8 100644
+--- a/net/bluetooth/l2cap.c
++++ b/net/bluetooth/l2cap.c
+@@ -559,7 +559,7 @@ static int l2cap_sock_create(struct sock
+
+ sock->ops = &l2cap_sock_ops;
+
+- sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL);
++ sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC);
+ if (!sk)
+ return -ENOMEM;
+
+@@ -2216,7 +2216,8 @@ static int __init l2cap_init(void)
+ goto error;
+ }
+
+- class_create_file(bt_class, &class_attr_l2cap);
++ if (class_create_file(bt_class, &class_attr_l2cap) < 0)
++ BT_ERR("Failed to create L2CAP info file");
+
+ BT_INFO("L2CAP ver %s", VERSION);
+ BT_INFO("L2CAP socket layer initialized");
+diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
+index 332dd8f..ddc4e9d 100644
+--- a/net/bluetooth/rfcomm/core.c
++++ b/net/bluetooth/rfcomm/core.c
+@@ -644,7 +644,7 @@ static struct rfcomm_session *rfcomm_ses
+ addr.l2_family = AF_BLUETOOTH;
+ addr.l2_psm = htobs(RFCOMM_PSM);
+ *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
+- if (*err == 0 || *err == -EAGAIN)
++ if (*err == 0 || *err == -EINPROGRESS)
+ return s;
+
+ rfcomm_session_del(s);
+@@ -2058,7 +2058,8 @@ static int __init rfcomm_init(void)
+
+ kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
+
+- class_create_file(bt_class, &class_attr_rfcomm_dlc);
++ if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
++ BT_ERR("Failed to create RFCOMM info file");
+
+ rfcomm_init_sockets();
+
+diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
+index 220fee0..544d65b 100644
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -336,7 +336,8 @@ static int rfcomm_sock_create(struct soc
+
+ sock->ops = &rfcomm_sock_ops;
+
+- if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
++ sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC);
++ if (!sk)
+ return -ENOMEM;
+
+ rfcomm_sock_init(sk, NULL);
+@@ -944,7 +945,8 @@ int __init rfcomm_init_sockets(void)
+ if (err < 0)
+ goto error;
+
+- class_create_file(bt_class, &class_attr_rfcomm);
++ if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
++ BT_ERR("Failed to create RFCOMM info file");
+
+ BT_INFO("RFCOMM socket layer initialized");
+
+diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
+index bd8d671..b8e3a5f 100644
+--- a/net/bluetooth/rfcomm/tty.c
++++ b/net/bluetooth/rfcomm/tty.c
+@@ -38,6 +38,7 @@
+ #include <linux/skbuff.h>
+
+ #include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
+ #include <net/bluetooth/rfcomm.h>
+
+ #ifndef CONFIG_BT_RFCOMM_DEBUG
+@@ -161,6 +162,22 @@ static inline struct rfcomm_dev *rfcomm_
+ return dev;
+ }
+
++static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
++{
++ struct hci_dev *hdev;
++ struct hci_conn *conn;
++
++ hdev = hci_get_route(&dev->dst, &dev->src);
++ if (!hdev)
++ return NULL;
++
++ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
++
++ hci_dev_put(hdev);
++
++ return conn ? &conn->dev : NULL;
++}
++
+ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
+ {
+ struct rfcomm_dev *dev;
+@@ -244,7 +261,7 @@ out:
+ return err;
+ }
+
+- tty_register_device(rfcomm_tty_driver, dev->id, NULL);
++ tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev));
+
+ return dev->id;
+ }
+@@ -748,6 +765,9 @@ static void rfcomm_tty_set_termios(struc
+
+ BT_DBG("tty %p termios %p", tty, old);
+
++ if (!dev)
++ return;
++
+ /* Handle turning off CRTSCTS */
+ if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
+ BT_DBG("Turning off CRTSCTS unsupported");
+@@ -992,7 +1012,7 @@ static int rfcomm_tty_tiocmset(struct tt
+
+ /* ---- TTY structure ---- */
+
+-static struct tty_operations rfcomm_ops = {
++static const struct tty_operations rfcomm_ops = {
+ .open = rfcomm_tty_open,
+ .close = rfcomm_tty_close,
+ .write = rfcomm_tty_write,
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 7714a2e..5d13d4f 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -452,7 +452,8 @@ static int sco_sock_create(struct socket
+
+ sock->ops = &sco_sock_ops;
+
+- if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
++ sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC);
++ if (!sk)
+ return -ENOMEM;
+
+ sco_sock_init(sk, NULL);
+@@ -967,7 +968,8 @@ static int __init sco_init(void)
+ goto error;
+ }
+
+- class_create_file(bt_class, &class_attr_sco);
++ if (class_create_file(bt_class, &class_attr_sco) < 0)
++ BT_ERR("Failed to create SCO info file");
+
+ BT_INFO("SCO (Voice Link) ver %s", VERSION);
+ BT_INFO("SCO socket layer initialized");
+diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
+index 3a73b8c..d9f0486 100644
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -128,7 +128,10 @@ void br_fdb_cleanup(unsigned long _data)
+ mod_timer(&br->gc_timer, jiffies + HZ/10);
+ }
+
+-void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
++
++void br_fdb_delete_by_port(struct net_bridge *br,
++ const struct net_bridge_port *p,
++ int do_all)
+ {
+ int i;
+
+@@ -142,6 +145,8 @@ void br_fdb_delete_by_port(struct net_br
+ if (f->dst != p)
+ continue;
+
++ if (f->is_static && !do_all)
++ continue;
+ /*
+ * if multiple ports all have the same device address
+ * then when one port is deleted, assign
+diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
+index 864fbbc..191b861 100644
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -38,13 +38,10 @@ int br_dev_queue_push_xmit(struct sk_buf
+ if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
+ kfree_skb(skb);
+ else {
+-#ifdef CONFIG_BRIDGE_NETFILTER
+ /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
+ if (nf_bridge_maybe_copy_header(skb))
+ kfree_skb(skb);
+- else
+-#endif
+- {
++ else {
+ skb_push(skb, ETH_HLEN);
+
+ dev_queue_xmit(skb);
+diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
+index b1211d5..f753c40 100644
+--- a/net/bridge/br_if.c
++++ b/net/bridge/br_if.c
+@@ -163,7 +163,7 @@ static void del_nbp(struct net_bridge_po
+ br_stp_disable_port(p);
+ spin_unlock_bh(&br->lock);
+
+- br_fdb_delete_by_port(br, p);
++ br_fdb_delete_by_port(br, p, 1);
+
+ list_del_rcu(&p->list);
+
+@@ -448,7 +448,7 @@ int br_add_if(struct net_bridge *br, str
+
+ return 0;
+ err2:
+- br_fdb_delete_by_port(br, p);
++ br_fdb_delete_by_port(br, p, 1);
+ err1:
+ kobject_del(&p->kobj);
+ err0:
+diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
+index 05b3de8..ac181be 100644
+--- a/net/bridge/br_netfilter.c
++++ b/net/bridge/br_netfilter.c
+@@ -53,10 +53,10 @@
+
+ #ifdef CONFIG_SYSCTL
+ static struct ctl_table_header *brnf_sysctl_header;
+-static int brnf_call_iptables = 1;
+-static int brnf_call_ip6tables = 1;
+-static int brnf_call_arptables = 1;
+-static int brnf_filter_vlan_tagged = 1;
++static int brnf_call_iptables __read_mostly = 1;
++static int brnf_call_ip6tables __read_mostly = 1;
++static int brnf_call_arptables __read_mostly = 1;
++static int brnf_filter_vlan_tagged __read_mostly = 1;
+ #else
+ #define brnf_filter_vlan_tagged 1
+ #endif
+@@ -127,14 +127,37 @@ static inline struct nf_bridge_info *nf_
+
+ static inline void nf_bridge_save_header(struct sk_buff *skb)
+ {
+- int header_size = 16;
++ int header_size = ETH_HLEN;
+
+ if (skb->protocol == htons(ETH_P_8021Q))
+- header_size = 18;
++ header_size += VLAN_HLEN;
+
+ memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
+ }
+
++/*
++ * When forwarding bridge frames, we save a copy of the original
++ * header before processing.
++ */
++int nf_bridge_copy_header(struct sk_buff *skb)
++{
++ int err;
++ int header_size = ETH_HLEN;
++
++ if (skb->protocol == htons(ETH_P_8021Q))
++ header_size += VLAN_HLEN;
++
++ err = skb_cow(skb, header_size);
++ if (err)
++ return err;
++
++ memcpy(skb->data - header_size, skb->nf_bridge->data, header_size);
++
++ if (skb->protocol == htons(ETH_P_8021Q))
++ __skb_push(skb, VLAN_HLEN);
++ return 0;
++}
++
+ /* PF_BRIDGE/PRE_ROUTING *********************************************/
+ /* Undo the changes made for ip6tables PREROUTING and continue the
+ * bridge PRE_ROUTING hook. */
+@@ -695,16 +718,6 @@ static unsigned int br_nf_local_out(unsi
+ else
+ pf = PF_INET6;
+
+-#ifdef CONFIG_NETFILTER_DEBUG
+- /* Sometimes we get packets with NULL ->dst here (for example,
+- * running a dhcp client daemon triggers this). This should now
+- * be fixed, but let's keep the check around. */
+- if (skb->dst == NULL) {
+- printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
+- return NF_ACCEPT;
+- }
+-#endif
+-
+ nf_bridge = skb->nf_bridge;
+ nf_bridge->physoutdev = skb->dev;
+ realindev = nf_bridge->physindev;
+@@ -786,7 +799,7 @@ static unsigned int br_nf_post_routing(u
+ * keep the check just to be sure... */
+ if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
+ printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
+- "bad mac.raw pointer.");
++ "bad mac.raw pointer.\n");
+ goto print_error;
+ }
+ #endif
+@@ -804,7 +817,7 @@ static unsigned int br_nf_post_routing(u
+
+ #ifdef CONFIG_NETFILTER_DEBUG
+ if (skb->dst == NULL) {
+- printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
++ printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n");
+ goto print_error;
+ }
+ #endif
+@@ -841,6 +854,7 @@ print_error:
+ }
+ printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw,
+ skb->data);
++ dump_stack();
+ return NF_ACCEPT;
+ #endif
+ }
+diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
+index 53086fb..8f66119 100644
+--- a/net/bridge/br_netlink.c
++++ b/net/bridge/br_netlink.c
+@@ -12,6 +12,7 @@
+
+ #include <linux/kernel.h>
+ #include <linux/rtnetlink.h>
++#include <net/netlink.h>
+ #include "br_private.h"
+
+ /*
+@@ -76,26 +77,24 @@ rtattr_failure:
+ void br_ifinfo_notify(int event, struct net_bridge_port *port)
+ {
+ struct sk_buff *skb;
+- int err = -ENOMEM;
++ int payload = sizeof(struct ifinfomsg) + 128;
++ int err = -ENOBUFS;
+
+ pr_debug("bridge notify event=%d\n", event);
+- skb = alloc_skb(NLMSG_SPACE(sizeof(struct ifinfomsg) + 128),
+- GFP_ATOMIC);
+- if (!skb)
+- goto err_out;
++ skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC);
++ if (skb == NULL)
++ goto errout;
++
++ err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
++ if (err < 0) {
++ kfree_skb(skb);
++ goto errout;
++ }
+
+- err = br_fill_ifinfo(skb, port, current->pid, 0, event, 0);
++ err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
++errout:
+ if (err < 0)
+- goto err_kfree;
+-
+- NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
+- return;
+-
+-err_kfree:
+- kfree_skb(skb);
+-err_out:
+- netlink_set_err(rtnl, 0, RTNLGRP_LINK, err);
++ rtnl_set_sk_err(RTNLGRP_LINK, err);
+ }
+
+ /*
+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
+index c491fb2..74258d8 100644
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -143,7 +143,7 @@ extern void br_fdb_changeaddr(struct net
+ const unsigned char *newaddr);
+ extern void br_fdb_cleanup(unsigned long arg);
+ extern void br_fdb_delete_by_port(struct net_bridge *br,
+- struct net_bridge_port *p);
++ const struct net_bridge_port *p, int do_all);
+ extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
+ const unsigned char *addr);
+ extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
+diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
+index 14cd025..d294224 100644
+--- a/net/bridge/br_stp_if.c
++++ b/net/bridge/br_stp_if.c
+@@ -113,6 +113,8 @@ void br_stp_disable_port(struct net_brid
+ del_timer(&p->forward_delay_timer);
+ del_timer(&p->hold_timer);
+
++ br_fdb_delete_by_port(br, p, 0);
++
+ br_configuration_update(br);
+
+ br_port_state_selection(br);
+diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
+index 96bcb2f..de9d1a9 100644
+--- a/net/bridge/br_sysfs_br.c
++++ b/net/bridge/br_sysfs_br.c
+@@ -376,7 +376,7 @@ int br_sysfs_addbr(struct net_device *de
+
+ err = sysfs_create_bin_file(brobj, &bridge_forward);
+ if (err) {
+- pr_info("%s: can't create attribue file %s/%s\n",
++ pr_info("%s: can't create attribute file %s/%s\n",
+ __FUNCTION__, dev->name, bridge_forward.attr.name);
+ goto out2;
+ }
+diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
+index d19fc4b..0aa7b99 100644
+--- a/net/bridge/netfilter/ebt_arpreply.c
++++ b/net/bridge/netfilter/ebt_arpreply.c
+@@ -20,7 +20,7 @@ static int ebt_target_reply(struct sk_bu
+ const void *data, unsigned int datalen)
+ {
+ struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
+- u32 _sip, *siptr, _dip, *diptr;
++ __be32 _sip, *siptr, _dip, *diptr;
+ struct arphdr _ah, *ap;
+ unsigned char _sha[ETH_ALEN], *shp;
+ struct sk_buff *skb = *pskb;
+diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
+index 770c0df..b54306a 100644
+--- a/net/bridge/netfilter/ebt_mark.c
++++ b/net/bridge/netfilter/ebt_mark.c
+@@ -22,24 +22,37 @@ static int ebt_target_mark(struct sk_buf
+ const void *data, unsigned int datalen)
+ {
+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
++ int action = info->target & -16;
+
+- if ((*pskb)->nfmark != info->mark)
++ if (action == MARK_SET_VALUE)
+ (*pskb)->nfmark = info->mark;
++ else if (action == MARK_OR_VALUE)
++ (*pskb)->nfmark |= info->mark;
++ else if (action == MARK_AND_VALUE)
++ (*pskb)->nfmark &= info->mark;
++ else
++ (*pskb)->nfmark ^= info->mark;
+
+- return info->target;
++ return info->target | -16;
+ }
+
+ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
++ int tmp;
+
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
+ return -EINVAL;
+- if (BASE_CHAIN && info->target == EBT_RETURN)
++ tmp = info->target | -16;
++ if (BASE_CHAIN && tmp == EBT_RETURN)
+ return -EINVAL;
+ CLEAR_BASE_CHAIN_BIT;
+- if (INVALID_TARGET)
++ if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
++ return -EINVAL;
++ tmp = info->target & -16;
++ if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
++ tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
+ return -EINVAL;
+ return 0;
+ }
+diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
+index 3a13ed6..9f85666 100644
+--- a/net/bridge/netfilter/ebtables.c
++++ b/net/bridge/netfilter/ebtables.c
+@@ -24,6 +24,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/netfilter_bridge/ebtables.h>
+ #include <linux/spinlock.h>
++#include <linux/mutex.h>
+ #include <asm/uaccess.h>
+ #include <linux/smp.h>
+ #include <linux/cpumask.h>
+@@ -31,36 +32,9 @@
+ /* needed for logical [in,out]-dev filtering */
+ #include "../br_private.h"
+
+-/* list_named_find */
+-#define ASSERT_READ_LOCK(x)
+-#define ASSERT_WRITE_LOCK(x)
+-#include <linux/netfilter_ipv4/listhelp.h>
+-#include <linux/mutex.h>
+-
+-#if 0
+-/* use this for remote debugging
+- * Copyright (C) 1998 by Ori Pomerantz
+- * Print the string to the appropriate tty, the one
+- * the current task uses
+- */
+-static void print_string(char *str)
+-{
+- struct tty_struct *my_tty;
+-
+- /* The tty for the current task */
+- my_tty = current->signal->tty;
+- if (my_tty != NULL) {
+- my_tty->driver->write(my_tty, 0, str, strlen(str));
+- my_tty->driver->write(my_tty, 0, "\015\012", 2);
+- }
+-}
+-
+-#define BUGPRINT(args) print_string(args);
+-#else
+ #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
+ "report to author: "format, ## args)
+ /* #define BUGPRINT(format, args...) */
+-#endif
+ #define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
+ ": out of memory: "format, ## args)
+ /* #define MEMPRINT(format, args...) */
+@@ -112,7 +86,7 @@ static inline int ebt_do_match (struct e
+ static inline int ebt_dev_check(char *entry, const struct net_device *device)
+ {
+ int i = 0;
+- char *devname = device->name;
++ const char *devname = device->name;
+
+ if (*entry == '\0')
+ return 0;
+@@ -299,18 +273,22 @@ static inline void *
+ find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
+ struct mutex *mutex)
+ {
+- void *ret;
++ struct {
++ struct list_head list;
++ char name[EBT_FUNCTION_MAXNAMELEN];
++ } *e;
+
+ *error = mutex_lock_interruptible(mutex);
+ if (*error != 0)
+ return NULL;
+
+- ret = list_named_find(head, name);
+- if (!ret) {
+- *error = -ENOENT;
+- mutex_unlock(mutex);
++ list_for_each_entry(e, head, list) {
++ if (strcmp(e->name, name) == 0)
++ return e;
+ }
+- return ret;
++ *error = -ENOENT;
++ mutex_unlock(mutex);
++ return NULL;
+ }
+
+ #ifndef CONFIG_KMOD
+@@ -1064,15 +1042,19 @@ free_newinfo:
+
+ int ebt_register_target(struct ebt_target *target)
+ {
++ struct ebt_target *t;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ebt_mutex);
+ if (ret != 0)
+ return ret;
+- if (!list_named_insert(&ebt_targets, target)) {
+- mutex_unlock(&ebt_mutex);
+- return -EEXIST;
++ list_for_each_entry(t, &ebt_targets, list) {
++ if (strcmp(t->name, target->name) == 0) {
++ mutex_unlock(&ebt_mutex);
++ return -EEXIST;
++ }
+ }
++ list_add(&target->list, &ebt_targets);
+ mutex_unlock(&ebt_mutex);
+
+ return 0;
+@@ -1081,21 +1063,25 @@ int ebt_register_target(struct ebt_targe
+ void ebt_unregister_target(struct ebt_target *target)
+ {
+ mutex_lock(&ebt_mutex);
+- LIST_DELETE(&ebt_targets, target);
++ list_del(&target->list);
+ mutex_unlock(&ebt_mutex);
+ }
+
+ int ebt_register_match(struct ebt_match *match)
+ {
++ struct ebt_match *m;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ebt_mutex);
+ if (ret != 0)
+ return ret;
+- if (!list_named_insert(&ebt_matches, match)) {
+- mutex_unlock(&ebt_mutex);
+- return -EEXIST;
++ list_for_each_entry(m, &ebt_matches, list) {
++ if (strcmp(m->name, match->name) == 0) {
++ mutex_unlock(&ebt_mutex);
++ return -EEXIST;
++ }
+ }
++ list_add(&match->list, &ebt_matches);
+ mutex_unlock(&ebt_mutex);
+
+ return 0;
+@@ -1104,21 +1090,25 @@ int ebt_register_match(struct ebt_match
+ void ebt_unregister_match(struct ebt_match *match)
+ {
+ mutex_lock(&ebt_mutex);
+- LIST_DELETE(&ebt_matches, match);
++ list_del(&match->list);
+ mutex_unlock(&ebt_mutex);
+ }
+
+ int ebt_register_watcher(struct ebt_watcher *watcher)
+ {
++ struct ebt_watcher *w;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ebt_mutex);
+ if (ret != 0)
+ return ret;
+- if (!list_named_insert(&ebt_watchers, watcher)) {
+- mutex_unlock(&ebt_mutex);
+- return -EEXIST;
++ list_for_each_entry(w, &ebt_watchers, list) {
++ if (strcmp(w->name, watcher->name) == 0) {
++ mutex_unlock(&ebt_mutex);
++ return -EEXIST;
++ }
+ }
++ list_add(&watcher->list, &ebt_watchers);
+ mutex_unlock(&ebt_mutex);
+
+ return 0;
+@@ -1127,13 +1117,14 @@ int ebt_register_watcher(struct ebt_watc
+ void ebt_unregister_watcher(struct ebt_watcher *watcher)
+ {
+ mutex_lock(&ebt_mutex);
+- LIST_DELETE(&ebt_watchers, watcher);
++ list_del(&watcher->list);
+ mutex_unlock(&ebt_mutex);
+ }
+
+ int ebt_register_table(struct ebt_table *table)
+ {
+ struct ebt_table_info *newinfo;
++ struct ebt_table *t;
+ int ret, i, countersize;
+
+ if (!table || !table->table ||!table->table->entries ||
+@@ -1179,10 +1170,12 @@ int ebt_register_table(struct ebt_table
+ if (ret != 0)
+ goto free_chainstack;
+
+- if (list_named_find(&ebt_tables, table->name)) {
+- ret = -EEXIST;
+- BUGPRINT("Table name already exists\n");
+- goto free_unlock;
++ list_for_each_entry(t, &ebt_tables, list) {
++ if (strcmp(t->name, table->name) == 0) {
++ ret = -EEXIST;
++ BUGPRINT("Table name already exists\n");
++ goto free_unlock;
++ }
+ }
+
+ /* Hold a reference count if the chains aren't empty */
+@@ -1190,7 +1183,7 @@ int ebt_register_table(struct ebt_table
+ ret = -ENOENT;
+ goto free_unlock;
+ }
+- list_prepend(&ebt_tables, table);
++ list_add(&table->list, &ebt_tables);
+ mutex_unlock(&ebt_mutex);
+ return 0;
+ free_unlock:
+@@ -1216,7 +1209,7 @@ void ebt_unregister_table(struct ebt_tab
+ return;
+ }
+ mutex_lock(&ebt_mutex);
+- LIST_DELETE(&ebt_tables, table);
++ list_del(&table->list);
+ mutex_unlock(&ebt_mutex);
+ vfree(table->private->entries);
+ if (table->private->chainstack) {
+@@ -1486,7 +1479,7 @@ static int __init ebtables_init(void)
+ int ret;
+
+ mutex_lock(&ebt_mutex);
+- list_named_insert(&ebt_targets, &ebt_standard_target);
++ list_add(&ebt_standard_target.list, &ebt_targets);
+ mutex_unlock(&ebt_mutex);
+ if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
+ return ret;
+diff --git a/net/compat.c b/net/compat.c
+index d5d69fa..52d32f1 100644
+--- a/net/compat.c
++++ b/net/compat.c
+@@ -285,8 +285,7 @@ void scm_detach_fds_compat(struct msghdr
+
+ if (i > 0) {
+ int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
+- if (!err)
+- err = put_user(SOL_SOCKET, &cm->cmsg_level);
++ err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ if (!err)
+ err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+ if (!err)
+diff --git a/net/core/Makefile b/net/core/Makefile
+index 2645ba4..1195680 100644
+--- a/net/core/Makefile
++++ b/net/core/Makefile
+@@ -17,3 +17,4 @@ obj-$(CONFIG_NET_PKTGEN) += pktgen.o
+ obj-$(CONFIG_WIRELESS_EXT) += wireless.o
+ obj-$(CONFIG_NETPOLL) += netpoll.o
+ obj-$(CONFIG_NET_DMA) += user_dma.o
++obj-$(CONFIG_FIB_RULES) += fib_rules.o
+diff --git a/net/core/datagram.c b/net/core/datagram.c
+index aecddcc..f558c61 100644
+--- a/net/core/datagram.c
++++ b/net/core/datagram.c
+@@ -417,7 +417,7 @@ unsigned int __skb_checksum_complete(str
+
+ sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+ if (likely(!sum)) {
+- if (unlikely(skb->ip_summed == CHECKSUM_HW))
++ if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
+ netdev_rx_csum_fault(skb->dev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+@@ -462,7 +462,7 @@ int skb_copy_and_csum_datagram_iovec(str
+ goto fault;
+ if ((unsigned short)csum_fold(csum))
+ goto csum_error;
+- if (unlikely(skb->ip_summed == CHECKSUM_HW))
++ if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
+ netdev_rx_csum_fault(skb->dev);
+ iov->iov_len -= chunk;
+ iov->iov_base += chunk;
+diff --git a/net/core/dev.c b/net/core/dev.c
+index d4a1ec3..81c426a 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -640,6 +640,8 @@ int dev_valid_name(const char *name)
+ {
+ if (*name == '\0')
+ return 0;
++ if (strlen(name) >= IFNAMSIZ)
++ return 0;
+ if (!strcmp(name, ".") || !strcmp(name, ".."))
+ return 0;
+
+@@ -1166,12 +1168,12 @@ EXPORT_SYMBOL(netif_device_attach);
+ * Invalidate hardware checksum when packet is to be mangled, and
+ * complete checksum manually on outgoing path.
+ */
+-int skb_checksum_help(struct sk_buff *skb, int inward)
++int skb_checksum_help(struct sk_buff *skb)
+ {
+ unsigned int csum;
+ int ret = 0, offset = skb->h.raw - skb->data;
+
+- if (inward)
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ goto out_set_summed;
+
+ if (unlikely(skb_shinfo(skb)->gso_size)) {
+@@ -1223,7 +1225,7 @@ struct sk_buff *skb_gso_segment(struct s
+ skb->mac_len = skb->nh.raw - skb->data;
+ __skb_pull(skb, skb->mac_len);
+
+- if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
++ if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
+ if (skb_header_cloned(skb) &&
+ (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+ return ERR_PTR(err);
+@@ -1232,7 +1234,7 @@ struct sk_buff *skb_gso_segment(struct s
+ rcu_read_lock();
+ list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
+ if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
+- if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
++ if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
+ err = ptype->gso_send_check(skb);
+ segs = ERR_PTR(err);
+ if (err || skb_gso_ok(skb, features))
+@@ -1444,11 +1446,11 @@ int dev_queue_xmit(struct sk_buff *skb)
+ /* If packet is not checksummed and device does not support
+ * checksumming for this protocol, complete checksumming here.
+ */
+- if (skb->ip_summed == CHECKSUM_HW &&
++ if (skb->ip_summed == CHECKSUM_PARTIAL &&
+ (!(dev->features & NETIF_F_GEN_CSUM) &&
+ (!(dev->features & NETIF_F_IP_CSUM) ||
+ skb->protocol != htons(ETH_P_IP))))
+- if (skb_checksum_help(skb, 0))
++ if (skb_checksum_help(skb))
+ goto out_kfree_skb;
+
+ gso:
+@@ -1478,14 +1480,16 @@ gso:
+ if (q->enqueue) {
+ /* Grab device queue */
+ spin_lock(&dev->queue_lock);
++ q = dev->qdisc;
++ if (q->enqueue) {
++ rc = q->enqueue(skb, q);
++ qdisc_run(dev);
++ spin_unlock(&dev->queue_lock);
+
+- rc = q->enqueue(skb, q);
+-
+- qdisc_run(dev);
+-
++ rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
++ goto out;
++ }
+ spin_unlock(&dev->queue_lock);
+- rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
+- goto out;
+ }
+
+ /* The device has no queue. Common case for software devices:
+@@ -3191,13 +3195,15 @@ struct net_device *alloc_netdev(int size
+ struct net_device *dev;
+ int alloc_size;
+
++ BUG_ON(strlen(name) >= sizeof(dev->name));
++
+ /* ensure 32-byte alignment of both the device and private area */
+ alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
+ alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
+
+ p = kzalloc(alloc_size, GFP_KERNEL);
+ if (!p) {
+- printk(KERN_ERR "alloc_dev: Unable to allocate device.\n");
++ printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
+ return NULL;
+ }
+
+@@ -3496,8 +3502,6 @@ static int __init net_dev_init(void)
+
+ BUG_ON(!dev_boot_phase);
+
+- net_random_init();
+-
+ if (dev_proc_init())
+ goto out;
+
+diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
+index c57d887..b22648d 100644
+--- a/net/core/dev_mcast.c
++++ b/net/core/dev_mcast.c
+@@ -21,8 +21,7 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h>
+-#include <linux/module.h>
++#include <linux/module.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <linux/bitops.h>
+diff --git a/net/core/ethtool.c b/net/core/ethtool.c
+index 2797e28..87dc556 100644
+--- a/net/core/ethtool.c
++++ b/net/core/ethtool.c
+@@ -143,7 +143,7 @@ static int ethtool_set_settings(struct n
+ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
+ {
+ struct ethtool_drvinfo info;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+
+ if (!ops->get_drvinfo)
+ return -EOPNOTSUPP;
+@@ -169,7 +169,7 @@ static int ethtool_get_drvinfo(struct ne
+ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
+ {
+ struct ethtool_regs regs;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+ void *regbuf;
+ int reglen, ret;
+
+@@ -282,7 +282,7 @@ static int ethtool_get_link(struct net_d
+ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
+ {
+ struct ethtool_eeprom eeprom;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+ u8 *data;
+ int ret;
+
+@@ -327,7 +327,7 @@ static int ethtool_get_eeprom(struct net
+ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
+ {
+ struct ethtool_eeprom eeprom;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+ u8 *data;
+ int ret;
+
+@@ -640,7 +640,7 @@ static int ethtool_set_gso(struct net_de
+ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
+ {
+ struct ethtool_test test;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+ u64 *data;
+ int ret;
+
+@@ -673,7 +673,7 @@ static int ethtool_self_test(struct net_
+ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
+ {
+ struct ethtool_gstrings gstrings;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+ u8 *data;
+ int ret;
+
+@@ -733,7 +733,7 @@ static int ethtool_phys_id(struct net_de
+ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
+ {
+ struct ethtool_stats stats;
+- struct ethtool_ops *ops = dev->ethtool_ops;
++ const struct ethtool_ops *ops = dev->ethtool_ops;
+ u64 *data;
+ int ret;
+
+@@ -806,13 +806,6 @@ int dev_ethtool(struct ifreq *ifr)
+ int rc;
+ unsigned long old_features;
+
+- /*
+- * XXX: This can be pushed down into the ethtool_* handlers that
+- * need it. Keep existing behaviour for the moment.
+- */
+- if (!capable(CAP_NET_ADMIN))
+- return -EPERM;
+-
+ if (!dev || !netif_device_present(dev))
+ return -ENODEV;
+
+@@ -822,6 +815,27 @@ int dev_ethtool(struct ifreq *ifr)
+ if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd)))
+ return -EFAULT;
+
++ /* Allow some commands to be done by anyone */
++ switch(ethcmd) {
++ case ETHTOOL_GDRVINFO:
++ case ETHTOOL_GMSGLVL:
++ case ETHTOOL_GCOALESCE:
++ case ETHTOOL_GRINGPARAM:
++ case ETHTOOL_GPAUSEPARAM:
++ case ETHTOOL_GRXCSUM:
++ case ETHTOOL_GTXCSUM:
++ case ETHTOOL_GSG:
++ case ETHTOOL_GSTRINGS:
++ case ETHTOOL_GTSO:
++ case ETHTOOL_GPERMADDR:
++ case ETHTOOL_GUFO:
++ case ETHTOOL_GGSO:
++ break;
++ default:
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ }
++
+ if(dev->ethtool_ops->begin)
+ if ((rc = dev->ethtool_ops->begin(dev)) < 0)
+ return rc;
+@@ -947,6 +961,10 @@ int dev_ethtool(struct ifreq *ifr)
+ return rc;
+
+ ioctl:
++ /* Keep existing behaviour for the moment. */
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
+ if (dev->do_ioctl)
+ return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
+ return -EOPNOTSUPP;
+diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
+new file mode 100644
+index 0000000..6b0e63c
+--- /dev/null
++++ b/net/core/fib_rules.c
+@@ -0,0 +1,420 @@
++/*
++ * net/core/fib_rules.c Generic Routing Rules
++ *
++ * 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.
++ *
++ * Authors: Thomas Graf <tgraf at suug.ch>
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <net/fib_rules.h>
++
++static LIST_HEAD(rules_ops);
++static DEFINE_SPINLOCK(rules_mod_lock);
++
++static void notify_rule_change(int event, struct fib_rule *rule,
++ struct fib_rules_ops *ops, struct nlmsghdr *nlh,
++ u32 pid);
++
++static struct fib_rules_ops *lookup_rules_ops(int family)
++{
++ struct fib_rules_ops *ops;
++
++ rcu_read_lock();
++ list_for_each_entry_rcu(ops, &rules_ops, list) {
++ if (ops->family == family) {
++ if (!try_module_get(ops->owner))
++ ops = NULL;
++ rcu_read_unlock();
++ return ops;
++ }
++ }
++ rcu_read_unlock();
++
++ return NULL;
++}
++
++static void rules_ops_put(struct fib_rules_ops *ops)
++{
++ if (ops)
++ module_put(ops->owner);
++}
++
++int fib_rules_register(struct fib_rules_ops *ops)
++{
++ int err = -EEXIST;
++ struct fib_rules_ops *o;
++
++ if (ops->rule_size < sizeof(struct fib_rule))
++ return -EINVAL;
++
++ if (ops->match == NULL || ops->configure == NULL ||
++ ops->compare == NULL || ops->fill == NULL ||
++ ops->action == NULL)
++ return -EINVAL;
++
++ spin_lock(&rules_mod_lock);
++ list_for_each_entry(o, &rules_ops, list)
++ if (ops->family == o->family)
++ goto errout;
++
++ list_add_tail_rcu(&ops->list, &rules_ops);
++ err = 0;
++errout:
++ spin_unlock(&rules_mod_lock);
++
++ return err;
++}
++
++EXPORT_SYMBOL_GPL(fib_rules_register);
++
++static void cleanup_ops(struct fib_rules_ops *ops)
++{
++ struct fib_rule *rule, *tmp;
++
++ list_for_each_entry_safe(rule, tmp, ops->rules_list, list) {
++ list_del_rcu(&rule->list);
++ fib_rule_put(rule);
++ }
++}
++
++int fib_rules_unregister(struct fib_rules_ops *ops)
++{
++ int err = 0;
++ struct fib_rules_ops *o;
++
++ spin_lock(&rules_mod_lock);
++ list_for_each_entry(o, &rules_ops, list) {
++ if (o == ops) {
++ list_del_rcu(&o->list);
++ cleanup_ops(ops);
++ goto out;
++ }
++ }
++
++ err = -ENOENT;
++out:
++ spin_unlock(&rules_mod_lock);
++
++ synchronize_rcu();
++
++ return err;
++}
++
++EXPORT_SYMBOL_GPL(fib_rules_unregister);
++
++int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
++ int flags, struct fib_lookup_arg *arg)
++{
++ struct fib_rule *rule;
++ int err;
++
++ rcu_read_lock();
++
++ list_for_each_entry_rcu(rule, ops->rules_list, list) {
++ if (rule->ifindex && (rule->ifindex != fl->iif))
++ continue;
++
++ if (!ops->match(rule, fl, flags))
++ continue;
++
++ err = ops->action(rule, fl, flags, arg);
++ if (err != -EAGAIN) {
++ fib_rule_get(rule);
++ arg->rule = rule;
++ goto out;
++ }
++ }
++
++ err = -ENETUNREACH;
++out:
++ rcu_read_unlock();
++
++ return err;
++}
++
++EXPORT_SYMBOL_GPL(fib_rules_lookup);
++
++int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
++{
++ struct fib_rule_hdr *frh = nlmsg_data(nlh);
++ struct fib_rules_ops *ops = NULL;
++ struct fib_rule *rule, *r, *last = NULL;
++ struct nlattr *tb[FRA_MAX+1];
++ int err = -EINVAL;
++
++ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
++ goto errout;
++
++ ops = lookup_rules_ops(frh->family);
++ if (ops == NULL) {
++ err = EAFNOSUPPORT;
++ goto errout;
++ }
++
++ err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy);
++ if (err < 0)
++ goto errout;
++
++ rule = kzalloc(ops->rule_size, GFP_KERNEL);
++ if (rule == NULL) {
++ err = -ENOMEM;
++ goto errout;
++ }
++
++ if (tb[FRA_PRIORITY])
++ rule->pref = nla_get_u32(tb[FRA_PRIORITY]);
++
++ if (tb[FRA_IFNAME]) {
++ struct net_device *dev;
++
++ rule->ifindex = -1;
++ nla_strlcpy(rule->ifname, tb[FRA_IFNAME], IFNAMSIZ);
++ dev = __dev_get_by_name(rule->ifname);
++ if (dev)
++ rule->ifindex = dev->ifindex;
++ }
++
++ rule->action = frh->action;
++ rule->flags = frh->flags;
++ rule->table = frh_get_table(frh, tb);
++
++ if (!rule->pref && ops->default_pref)
++ rule->pref = ops->default_pref();
++
++ err = ops->configure(rule, skb, nlh, frh, tb);
++ if (err < 0)
++ goto errout_free;
++
++ list_for_each_entry(r, ops->rules_list, list) {
++ if (r->pref > rule->pref)
++ break;
++ last = r;
++ }
++
++ fib_rule_get(rule);
++
++ if (last)
++ list_add_rcu(&rule->list, &last->list);
++ else
++ list_add_rcu(&rule->list, ops->rules_list);
++
++ notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
++ rules_ops_put(ops);
++ return 0;
++
++errout_free:
++ kfree(rule);
++errout:
++ rules_ops_put(ops);
++ return err;
++}
++
++int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
++{
++ struct fib_rule_hdr *frh = nlmsg_data(nlh);
++ struct fib_rules_ops *ops = NULL;
++ struct fib_rule *rule;
++ struct nlattr *tb[FRA_MAX+1];
++ int err = -EINVAL;
++
++ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
++ goto errout;
++
++ ops = lookup_rules_ops(frh->family);
++ if (ops == NULL) {
++ err = EAFNOSUPPORT;
++ goto errout;
++ }
++
++ err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy);
++ if (err < 0)
++ goto errout;
++
++ list_for_each_entry(rule, ops->rules_list, list) {
++ if (frh->action && (frh->action != rule->action))
++ continue;
++
++ if (frh->table && (frh_get_table(frh, tb) != rule->table))
++ continue;
++
++ if (tb[FRA_PRIORITY] &&
++ (rule->pref != nla_get_u32(tb[FRA_PRIORITY])))
++ continue;
++
++ if (tb[FRA_IFNAME] &&
++ nla_strcmp(tb[FRA_IFNAME], rule->ifname))
++ continue;
++
++ if (!ops->compare(rule, frh, tb))
++ continue;
++
++ if (rule->flags & FIB_RULE_PERMANENT) {
++ err = -EPERM;
++ goto errout;
++ }
++
++ list_del_rcu(&rule->list);
++ synchronize_rcu();
++ notify_rule_change(RTM_DELRULE, rule, ops, nlh,
++ NETLINK_CB(skb).pid);
++ fib_rule_put(rule);
++ rules_ops_put(ops);
++ return 0;
++ }
++
++ err = -ENOENT;
++errout:
++ rules_ops_put(ops);
++ return err;
++}
++
++static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
++ u32 pid, u32 seq, int type, int flags,
++ struct fib_rules_ops *ops)
++{
++ struct nlmsghdr *nlh;
++ struct fib_rule_hdr *frh;
++
++ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*frh), flags);
++ if (nlh == NULL)
++ return -1;
++
++ frh = nlmsg_data(nlh);
++ frh->table = rule->table;
++ NLA_PUT_U32(skb, FRA_TABLE, rule->table);
++ frh->res1 = 0;
++ frh->res2 = 0;
++ frh->action = rule->action;
++ frh->flags = rule->flags;
++
++ if (rule->ifname[0])
++ NLA_PUT_STRING(skb, FRA_IFNAME, rule->ifname);
++
++ if (rule->pref)
++ NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref);
++
++ if (ops->fill(rule, skb, nlh, frh) < 0)
++ goto nla_put_failure;
++
++ return nlmsg_end(skb, nlh);
++
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
++}
++
++int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family)
++{
++ int idx = 0;
++ struct fib_rule *rule;
++ struct fib_rules_ops *ops;
++
++ ops = lookup_rules_ops(family);
++ if (ops == NULL)
++ return -EAFNOSUPPORT;
++
++ rcu_read_lock();
++ list_for_each_entry(rule, ops->rules_list, list) {
++ if (idx < cb->args[0])
++ goto skip;
++
++ if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).pid,
++ cb->nlh->nlmsg_seq, RTM_NEWRULE,
++ NLM_F_MULTI, ops) < 0)
++ break;
++skip:
++ idx++;
++ }
++ rcu_read_unlock();
++ cb->args[0] = idx;
++ rules_ops_put(ops);
++
++ return skb->len;
++}
++
++EXPORT_SYMBOL_GPL(fib_rules_dump);
++
++static void notify_rule_change(int event, struct fib_rule *rule,
++ struct fib_rules_ops *ops, struct nlmsghdr *nlh,
++ u32 pid)
++{
++ struct sk_buff *skb;
++ int err = -ENOBUFS;
++
++ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (skb == NULL)
++ goto errout;
++
++ err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops);
++ if (err < 0) {
++ kfree_skb(skb);
++ goto errout;
++ }
++
++ err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(ops->nlgroup, err);
++}
++
++static void attach_rules(struct list_head *rules, struct net_device *dev)
++{
++ struct fib_rule *rule;
++
++ list_for_each_entry(rule, rules, list) {
++ if (rule->ifindex == -1 &&
++ strcmp(dev->name, rule->ifname) == 0)
++ rule->ifindex = dev->ifindex;
++ }
++}
++
++static void detach_rules(struct list_head *rules, struct net_device *dev)
++{
++ struct fib_rule *rule;
++
++ list_for_each_entry(rule, rules, list)
++ if (rule->ifindex == dev->ifindex)
++ rule->ifindex = -1;
++}
++
++
++static int fib_rules_event(struct notifier_block *this, unsigned long event,
++ void *ptr)
++{
++ struct net_device *dev = ptr;
++ struct fib_rules_ops *ops;
++
++ ASSERT_RTNL();
++ rcu_read_lock();
++
++ switch (event) {
++ case NETDEV_REGISTER:
++ list_for_each_entry(ops, &rules_ops, list)
++ attach_rules(ops->rules_list, dev);
++ break;
++
++ case NETDEV_UNREGISTER:
++ list_for_each_entry(ops, &rules_ops, list)
++ detach_rules(ops->rules_list, dev);
++ break;
++ }
++
++ rcu_read_unlock();
++
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block fib_rules_notifier = {
++ .notifier_call = fib_rules_event,
++};
++
++static int __init fib_rules_init(void)
++{
++ return register_netdevice_notifier(&fib_rules_notifier);
++}
++
++subsys_initcall(fib_rules_init);
+diff --git a/net/core/filter.c b/net/core/filter.c
+index 5b4486a..6732782 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -422,10 +422,10 @@ int sk_attach_filter(struct sock_fprog *
+ if (!err) {
+ struct sk_filter *old_fp;
+
+- spin_lock_bh(&sk->sk_lock.slock);
+- old_fp = sk->sk_filter;
+- sk->sk_filter = fp;
+- spin_unlock_bh(&sk->sk_lock.slock);
++ rcu_read_lock_bh();
++ old_fp = rcu_dereference(sk->sk_filter);
++ rcu_assign_pointer(sk->sk_filter, fp);
++ rcu_read_unlock_bh();
+ fp = old_fp;
+ }
+
+diff --git a/net/core/flow.c b/net/core/flow.c
+index 2191af5..b16d31a 100644
+--- a/net/core/flow.c
++++ b/net/core/flow.c
+@@ -32,7 +32,6 @@ struct flow_cache_entry {
+ u8 dir;
+ struct flowi key;
+ u32 genid;
+- u32 sk_sid;
+ void *object;
+ atomic_t *object_ref;
+ };
+@@ -86,6 +85,14 @@ static void flow_cache_new_hashrnd(unsig
+ add_timer(&flow_hash_rnd_timer);
+ }
+
++static void flow_entry_kill(int cpu, struct flow_cache_entry *fle)
++{
++ if (fle->object)
++ atomic_dec(fle->object_ref);
++ kmem_cache_free(flow_cachep, fle);
++ flow_count(cpu)--;
++}
++
+ static void __flow_cache_shrink(int cpu, int shrink_to)
+ {
+ struct flow_cache_entry *fle, **flp;
+@@ -101,10 +108,7 @@ static void __flow_cache_shrink(int cpu,
+ }
+ while ((fle = *flp) != NULL) {
+ *flp = fle->next;
+- if (fle->object)
+- atomic_dec(fle->object_ref);
+- kmem_cache_free(flow_cachep, fle);
+- flow_count(cpu)--;
++ flow_entry_kill(cpu, fle);
+ }
+ }
+ }
+@@ -165,7 +169,7 @@ static int flow_key_compare(struct flowi
+ return 0;
+ }
+
+-void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir,
++void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
+ flow_resolve_t resolver)
+ {
+ struct flow_cache_entry *fle, **head;
+@@ -189,7 +193,6 @@ void *flow_cache_lookup(struct flowi *ke
+ for (fle = *head; fle; fle = fle->next) {
+ if (fle->family == family &&
+ fle->dir == dir &&
+- fle->sk_sid == sk_sid &&
+ flow_key_compare(key, &fle->key) == 0) {
+ if (fle->genid == atomic_read(&flow_cache_genid)) {
+ void *ret = fle->object;
+@@ -214,7 +217,6 @@ void *flow_cache_lookup(struct flowi *ke
+ *head = fle;
+ fle->family = family;
+ fle->dir = dir;
+- fle->sk_sid = sk_sid;
+ memcpy(&fle->key, key, sizeof(*key));
+ fle->object = NULL;
+ flow_count(cpu)++;
+@@ -223,24 +225,33 @@ void *flow_cache_lookup(struct flowi *ke
+
+ nocache:
+ {
++ int err;
+ void *obj;
+ atomic_t *obj_ref;
+
+- resolver(key, sk_sid, family, dir, &obj, &obj_ref);
++ err = resolver(key, family, dir, &obj, &obj_ref);
+
+ if (fle) {
+- fle->genid = atomic_read(&flow_cache_genid);
+-
+- if (fle->object)
+- atomic_dec(fle->object_ref);
+-
+- fle->object = obj;
+- fle->object_ref = obj_ref;
+- if (obj)
+- atomic_inc(fle->object_ref);
++ if (err) {
++ /* Force security policy check on next lookup */
++ *head = fle->next;
++ flow_entry_kill(cpu, fle);
++ } else {
++ fle->genid = atomic_read(&flow_cache_genid);
++
++ if (fle->object)
++ atomic_dec(fle->object_ref);
++
++ fle->object = obj;
++ fle->object_ref = obj_ref;
++ if (obj)
++ atomic_inc(fle->object_ref);
++ }
+ }
+ local_bh_enable();
+
++ if (err)
++ obj = ERR_PTR(err);
+ return obj;
+ }
+ }
+@@ -346,12 +357,8 @@ static int __init flow_cache_init(void)
+
+ flow_cachep = kmem_cache_create("flow_cache",
+ sizeof(struct flow_cache_entry),
+- 0, SLAB_HWCACHE_ALIGN,
++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+-
+- if (!flow_cachep)
+- panic("NET: failed to allocate flow cache slab\n");
+-
+ flow_hash_shift = 10;
+ flow_lwm = 2 * flow_hash_size;
+ flow_hwm = 4 * flow_hash_size;
+diff --git a/net/core/neighbour.c b/net/core/neighbour.c
+index fe2113f..b4b4783 100644
+--- a/net/core/neighbour.c
++++ b/net/core/neighbour.c
+@@ -30,6 +30,7 @@
+ #include <net/dst.h>
+ #include <net/sock.h>
+ #include <net/netevent.h>
++#include <net/netlink.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/random.h>
+ #include <linux/string.h>
+@@ -343,12 +344,12 @@ struct neighbour *neigh_lookup(struct ne
+ {
+ struct neighbour *n;
+ int key_len = tbl->key_len;
+- u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
++ u32 hash_val = tbl->hash(pkey, dev);
+
+ NEIGH_CACHE_STAT_INC(tbl, lookups);
+
+ read_lock_bh(&tbl->lock);
+- for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
++ for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
+ if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
+ neigh_hold(n);
+ NEIGH_CACHE_STAT_INC(tbl, hits);
+@@ -363,12 +364,12 @@ struct neighbour *neigh_lookup_nodev(str
+ {
+ struct neighbour *n;
+ int key_len = tbl->key_len;
+- u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask;
++ u32 hash_val = tbl->hash(pkey, NULL);
+
+ NEIGH_CACHE_STAT_INC(tbl, lookups);
+
+ read_lock_bh(&tbl->lock);
+- for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
++ for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
+ if (!memcmp(n->primary_key, pkey, key_len)) {
+ neigh_hold(n);
+ NEIGH_CACHE_STAT_INC(tbl, hits);
+@@ -888,7 +889,7 @@ out_unlock_bh:
+ return rc;
+ }
+
+-static __inline__ void neigh_update_hhs(struct neighbour *neigh)
++static void neigh_update_hhs(struct neighbour *neigh)
+ {
+ struct hh_cache *hh;
+ void (*update)(struct hh_cache*, struct net_device*, unsigned char *) =
+@@ -1078,7 +1079,7 @@ struct neighbour *neigh_event_ns(struct
+ }
+
+ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
+- u16 protocol)
++ __be16 protocol)
+ {
+ struct hh_cache *hh;
+ struct net_device *dev = dst->dev;
+@@ -1338,14 +1339,10 @@ void neigh_table_init_no_netlink(struct
+ neigh_rand_reach_time(tbl->parms.base_reachable_time);
+
+ if (!tbl->kmem_cachep)
+- tbl->kmem_cachep = kmem_cache_create(tbl->id,
+- tbl->entry_size,
+- 0, SLAB_HWCACHE_ALIGN,
+- NULL, NULL);
+-
+- if (!tbl->kmem_cachep)
+- panic("cannot create neighbour cache");
+-
++ tbl->kmem_cachep =
++ kmem_cache_create(tbl->id, tbl->entry_size, 0,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC,
++ NULL, NULL);
+ tbl->stats = alloc_percpu(struct neigh_statistics);
+ if (!tbl->stats)
+ panic("cannot create neighbour cache statistics");
+@@ -1440,48 +1437,62 @@ int neigh_table_clear(struct neigh_table
+
+ int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+- struct ndmsg *ndm = NLMSG_DATA(nlh);
+- struct rtattr **nda = arg;
++ struct ndmsg *ndm;
++ struct nlattr *dst_attr;
+ struct neigh_table *tbl;
+ struct net_device *dev = NULL;
+- int err = -ENODEV;
++ int err = -EINVAL;
+
+- if (ndm->ndm_ifindex &&
+- (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
++ if (nlmsg_len(nlh) < sizeof(*ndm))
+ goto out;
+
++ dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
++ if (dst_attr == NULL)
++ goto out;
++
++ ndm = nlmsg_data(nlh);
++ if (ndm->ndm_ifindex) {
++ dev = dev_get_by_index(ndm->ndm_ifindex);
++ if (dev == NULL) {
++ err = -ENODEV;
++ goto out;
++ }
++ }
++
+ read_lock(&neigh_tbl_lock);
+ for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+- struct rtattr *dst_attr = nda[NDA_DST - 1];
+- struct neighbour *n;
++ struct neighbour *neigh;
+
+ if (tbl->family != ndm->ndm_family)
+ continue;
+ read_unlock(&neigh_tbl_lock);
+
+- err = -EINVAL;
+- if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
++ if (nla_len(dst_attr) < tbl->key_len)
+ goto out_dev_put;
+
+ if (ndm->ndm_flags & NTF_PROXY) {
+- err = pneigh_delete(tbl, RTA_DATA(dst_attr), dev);
++ err = pneigh_delete(tbl, nla_data(dst_attr), dev);
+ goto out_dev_put;
+ }
+
+- if (!dev)
+- goto out;
++ if (dev == NULL)
++ goto out_dev_put;
+
+- n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev);
+- if (n) {
+- err = neigh_update(n, NULL, NUD_FAILED,
+- NEIGH_UPDATE_F_OVERRIDE|
+- NEIGH_UPDATE_F_ADMIN);
+- neigh_release(n);
++ neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
++ if (neigh == NULL) {
++ err = -ENOENT;
++ goto out_dev_put;
+ }
++
++ err = neigh_update(neigh, NULL, NUD_FAILED,
++ NEIGH_UPDATE_F_OVERRIDE |
++ NEIGH_UPDATE_F_ADMIN);
++ neigh_release(neigh);
+ goto out_dev_put;
+ }
+ read_unlock(&neigh_tbl_lock);
+- err = -EADDRNOTAVAIL;
++ err = -EAFNOSUPPORT;
++
+ out_dev_put:
+ if (dev)
+ dev_put(dev);
+@@ -1491,76 +1502,93 @@ out:
+
+ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+- struct ndmsg *ndm = NLMSG_DATA(nlh);
+- struct rtattr **nda = arg;
++ struct ndmsg *ndm;
++ struct nlattr *tb[NDA_MAX+1];
+ struct neigh_table *tbl;
+ struct net_device *dev = NULL;
+- int err = -ENODEV;
++ int err;
+
+- if (ndm->ndm_ifindex &&
+- (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
++ err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
++ if (err < 0)
+ goto out;
+
++ err = -EINVAL;
++ if (tb[NDA_DST] == NULL)
++ goto out;
++
++ ndm = nlmsg_data(nlh);
++ if (ndm->ndm_ifindex) {
++ dev = dev_get_by_index(ndm->ndm_ifindex);
++ if (dev == NULL) {
++ err = -ENODEV;
++ goto out;
++ }
++
++ if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
++ goto out_dev_put;
++ }
++
+ read_lock(&neigh_tbl_lock);
+ for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+- struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1];
+- struct rtattr *dst_attr = nda[NDA_DST - 1];
+- int override = 1;
+- struct neighbour *n;
++ int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
++ struct neighbour *neigh;
++ void *dst, *lladdr;
+
+ if (tbl->family != ndm->ndm_family)
+ continue;
+ read_unlock(&neigh_tbl_lock);
+
+- err = -EINVAL;
+- if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
++ if (nla_len(tb[NDA_DST]) < tbl->key_len)
+ goto out_dev_put;
++ dst = nla_data(tb[NDA_DST]);
++ lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
+
+ if (ndm->ndm_flags & NTF_PROXY) {
++ struct pneigh_entry *pn;
++
+ err = -ENOBUFS;
+- if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1))
++ pn = pneigh_lookup(tbl, dst, dev, 1);
++ if (pn) {
++ pn->flags = ndm->ndm_flags;
+ err = 0;
++ }
+ goto out_dev_put;
+ }
+
+- err = -EINVAL;
+- if (!dev)
+- goto out;
+- if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len)
++ if (dev == NULL)
+ goto out_dev_put;
++
++ neigh = neigh_lookup(tbl, dst, dev);
++ if (neigh == NULL) {
++ if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
++ err = -ENOENT;
++ goto out_dev_put;
++ }
+
+- n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev);
+- if (n) {
+- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+- err = -EEXIST;
+- neigh_release(n);
++ neigh = __neigh_lookup_errno(tbl, dst, dev);
++ if (IS_ERR(neigh)) {
++ err = PTR_ERR(neigh);
+ goto out_dev_put;
+ }
+-
+- override = nlh->nlmsg_flags & NLM_F_REPLACE;
+- } else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
+- err = -ENOENT;
+- goto out_dev_put;
+ } else {
+- n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev);
+- if (IS_ERR(n)) {
+- err = PTR_ERR(n);
++ if (nlh->nlmsg_flags & NLM_F_EXCL) {
++ err = -EEXIST;
++ neigh_release(neigh);
+ goto out_dev_put;
+ }
+- }
+
+- err = neigh_update(n,
+- lladdr_attr ? RTA_DATA(lladdr_attr) : NULL,
+- ndm->ndm_state,
+- (override ? NEIGH_UPDATE_F_OVERRIDE : 0) |
+- NEIGH_UPDATE_F_ADMIN);
++ if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
++ flags &= ~NEIGH_UPDATE_F_OVERRIDE;
++ }
+
+- neigh_release(n);
++ err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
++ neigh_release(neigh);
+ goto out_dev_put;
+ }
+
+ read_unlock(&neigh_tbl_lock);
+- err = -EADDRNOTAVAIL;
++ err = -EAFNOSUPPORT;
++
+ out_dev_put:
+ if (dev)
+ dev_put(dev);
+@@ -1570,56 +1598,59 @@ out:
+
+ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
+ {
+- struct rtattr *nest = NULL;
+-
+- nest = RTA_NEST(skb, NDTA_PARMS);
++ struct nlattr *nest;
++
++ nest = nla_nest_start(skb, NDTA_PARMS);
++ if (nest == NULL)
++ return -ENOBUFS;
+
+ if (parms->dev)
+- RTA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
+-
+- RTA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
+- RTA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
+- RTA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
+- RTA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
+- RTA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
+- RTA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
+- RTA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
+- RTA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
++ NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
++
++ NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
++ NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
++ NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
++ NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
++ NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
++ NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
++ NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
++ NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
+ parms->base_reachable_time);
+- RTA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
+- RTA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
+- RTA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
+- RTA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
+- RTA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
+- RTA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
++ NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
++ NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
++ NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
++ NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
++ NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
++ NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
+
+- return RTA_NEST_END(skb, nest);
++ return nla_nest_end(skb, nest);
+
+-rtattr_failure:
+- return RTA_NEST_CANCEL(skb, nest);
++nla_put_failure:
++ return nla_nest_cancel(skb, nest);
+ }
+
+-static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb,
+- struct netlink_callback *cb)
++static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
++ u32 pid, u32 seq, int type, int flags)
+ {
+ struct nlmsghdr *nlh;
+ struct ndtmsg *ndtmsg;
+
+- nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg),
+- NLM_F_MULTI);
++ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
+
+- ndtmsg = NLMSG_DATA(nlh);
++ ndtmsg = nlmsg_data(nlh);
+
+ 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);
+- RTA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
+- RTA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
+- RTA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
++ NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
++ NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
++ NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
++ NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
++ NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
+
+ {
+ unsigned long now = jiffies;
+@@ -1638,7 +1669,7 @@ static int neightbl_fill_info(struct nei
+ .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
+ };
+
+- RTA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
++ NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
+ }
+
+ {
+@@ -1663,55 +1694,50 @@ static int neightbl_fill_info(struct nei
+ ndst.ndts_forced_gc_runs += st->forced_gc_runs;
+ }
+
+- RTA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
++ NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
+ }
+
+ BUG_ON(tbl->parms.dev);
+ if (neightbl_fill_parms(skb, &tbl->parms) < 0)
+- goto rtattr_failure;
++ goto nla_put_failure;
+
+ read_unlock_bh(&tbl->lock);
+- return NLMSG_END(skb, nlh);
++ return nlmsg_end(skb, nlh);
+
+-rtattr_failure:
++nla_put_failure:
+ read_unlock_bh(&tbl->lock);
+- return NLMSG_CANCEL(skb, nlh);
+-
+-nlmsg_failure:
+- return -1;
++ return nlmsg_cancel(skb, nlh);
+ }
+
+-static int neightbl_fill_param_info(struct neigh_table *tbl,
++static int neightbl_fill_param_info(struct sk_buff *skb,
++ struct neigh_table *tbl,
+ struct neigh_parms *parms,
+- struct sk_buff *skb,
+- struct netlink_callback *cb)
++ u32 pid, u32 seq, int type,
++ unsigned int flags)
+ {
+ struct ndtmsg *ndtmsg;
+ struct nlmsghdr *nlh;
+
+- nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg),
+- NLM_F_MULTI);
++ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
+
+- ndtmsg = NLMSG_DATA(nlh);
++ ndtmsg = nlmsg_data(nlh);
+
+ 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)
+- goto rtattr_failure;
++ if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
++ neightbl_fill_parms(skb, parms) < 0)
++ goto errout;
+
+ read_unlock_bh(&tbl->lock);
+- return NLMSG_END(skb, nlh);
+-
+-rtattr_failure:
++ return nlmsg_end(skb, nlh);
++errout:
+ read_unlock_bh(&tbl->lock);
+- return NLMSG_CANCEL(skb, nlh);
+-
+-nlmsg_failure:
+- return -1;
++ return nlmsg_cancel(skb, nlh);
+ }
+
+ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
+@@ -1727,28 +1753,61 @@ static inline struct neigh_parms *lookup
+ return NULL;
+ }
+
++static struct nla_policy nl_neightbl_policy[NDTA_MAX+1] __read_mostly = {
++ [NDTA_NAME] = { .type = NLA_STRING },
++ [NDTA_THRESH1] = { .type = NLA_U32 },
++ [NDTA_THRESH2] = { .type = NLA_U32 },
++ [NDTA_THRESH3] = { .type = NLA_U32 },
++ [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
++ [NDTA_PARMS] = { .type = NLA_NESTED },
++};
++
++static struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] __read_mostly = {
++ [NDTPA_IFINDEX] = { .type = NLA_U32 },
++ [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
++ [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
++ [NDTPA_APP_PROBES] = { .type = NLA_U32 },
++ [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
++ [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
++ [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
++ [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
++ [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
++ [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
++ [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
++ [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
++ [NDTPA_LOCKTIME] = { .type = NLA_U64 },
++};
++
+ int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+ struct neigh_table *tbl;
+- struct ndtmsg *ndtmsg = NLMSG_DATA(nlh);
+- struct rtattr **tb = arg;
+- int err = -EINVAL;
++ struct ndtmsg *ndtmsg;
++ struct nlattr *tb[NDTA_MAX+1];
++ int err;
++
++ err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
++ nl_neightbl_policy);
++ if (err < 0)
++ goto errout;
+
+- if (!tb[NDTA_NAME - 1] || !RTA_PAYLOAD(tb[NDTA_NAME - 1]))
+- return -EINVAL;
++ if (tb[NDTA_NAME] == NULL) {
++ err = -EINVAL;
++ goto errout;
++ }
+
++ ndtmsg = nlmsg_data(nlh);
+ read_lock(&neigh_tbl_lock);
+ for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+ if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
+ continue;
+
+- if (!rtattr_strcmp(tb[NDTA_NAME - 1], tbl->id))
++ if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
+ break;
+ }
+
+ if (tbl == NULL) {
+ err = -ENOENT;
+- goto errout;
++ goto errout_locked;
+ }
+
+ /*
+@@ -1757,165 +1816,178 @@ int neightbl_set(struct sk_buff *skb, st
+ */
+ write_lock_bh(&tbl->lock);
+
+- if (tb[NDTA_THRESH1 - 1])
+- tbl->gc_thresh1 = RTA_GET_U32(tb[NDTA_THRESH1 - 1]);
+-
+- if (tb[NDTA_THRESH2 - 1])
+- tbl->gc_thresh2 = RTA_GET_U32(tb[NDTA_THRESH2 - 1]);
+-
+- if (tb[NDTA_THRESH3 - 1])
+- tbl->gc_thresh3 = RTA_GET_U32(tb[NDTA_THRESH3 - 1]);
+-
+- if (tb[NDTA_GC_INTERVAL - 1])
+- tbl->gc_interval = RTA_GET_MSECS(tb[NDTA_GC_INTERVAL - 1]);
+-
+- if (tb[NDTA_PARMS - 1]) {
+- struct rtattr *tbp[NDTPA_MAX];
++ if (tb[NDTA_PARMS]) {
++ struct nlattr *tbp[NDTPA_MAX+1];
+ struct neigh_parms *p;
+- u32 ifindex = 0;
++ int i, ifindex = 0;
+
+- if (rtattr_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS - 1]) < 0)
+- goto rtattr_failure;
++ err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
++ nl_ntbl_parm_policy);
++ if (err < 0)
++ goto errout_tbl_lock;
+
+- if (tbp[NDTPA_IFINDEX - 1])
+- ifindex = RTA_GET_U32(tbp[NDTPA_IFINDEX - 1]);
++ if (tbp[NDTPA_IFINDEX])
++ ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
+
+ p = lookup_neigh_params(tbl, ifindex);
+ if (p == NULL) {
+ err = -ENOENT;
+- goto rtattr_failure;
++ goto errout_tbl_lock;
+ }
+-
+- if (tbp[NDTPA_QUEUE_LEN - 1])
+- p->queue_len = RTA_GET_U32(tbp[NDTPA_QUEUE_LEN - 1]);
+-
+- if (tbp[NDTPA_PROXY_QLEN - 1])
+- p->proxy_qlen = RTA_GET_U32(tbp[NDTPA_PROXY_QLEN - 1]);
+-
+- if (tbp[NDTPA_APP_PROBES - 1])
+- p->app_probes = RTA_GET_U32(tbp[NDTPA_APP_PROBES - 1]);
+-
+- if (tbp[NDTPA_UCAST_PROBES - 1])
+- p->ucast_probes =
+- RTA_GET_U32(tbp[NDTPA_UCAST_PROBES - 1]);
+
+- if (tbp[NDTPA_MCAST_PROBES - 1])
+- p->mcast_probes =
+- RTA_GET_U32(tbp[NDTPA_MCAST_PROBES - 1]);
+-
+- if (tbp[NDTPA_BASE_REACHABLE_TIME - 1])
+- p->base_reachable_time =
+- RTA_GET_MSECS(tbp[NDTPA_BASE_REACHABLE_TIME - 1]);
+-
+- if (tbp[NDTPA_GC_STALETIME - 1])
+- p->gc_staletime =
+- RTA_GET_MSECS(tbp[NDTPA_GC_STALETIME - 1]);
++ for (i = 1; i <= NDTPA_MAX; i++) {
++ if (tbp[i] == NULL)
++ continue;
+
+- if (tbp[NDTPA_DELAY_PROBE_TIME - 1])
+- p->delay_probe_time =
+- RTA_GET_MSECS(tbp[NDTPA_DELAY_PROBE_TIME - 1]);
++ switch (i) {
++ case NDTPA_QUEUE_LEN:
++ p->queue_len = nla_get_u32(tbp[i]);
++ break;
++ case NDTPA_PROXY_QLEN:
++ p->proxy_qlen = nla_get_u32(tbp[i]);
++ break;
++ case NDTPA_APP_PROBES:
++ p->app_probes = nla_get_u32(tbp[i]);
++ break;
++ case NDTPA_UCAST_PROBES:
++ p->ucast_probes = nla_get_u32(tbp[i]);
++ break;
++ case NDTPA_MCAST_PROBES:
++ p->mcast_probes = nla_get_u32(tbp[i]);
++ break;
++ case NDTPA_BASE_REACHABLE_TIME:
++ p->base_reachable_time = nla_get_msecs(tbp[i]);
++ break;
++ case NDTPA_GC_STALETIME:
++ p->gc_staletime = nla_get_msecs(tbp[i]);
++ break;
++ case NDTPA_DELAY_PROBE_TIME:
++ p->delay_probe_time = nla_get_msecs(tbp[i]);
++ break;
++ case NDTPA_RETRANS_TIME:
++ p->retrans_time = nla_get_msecs(tbp[i]);
++ break;
++ case NDTPA_ANYCAST_DELAY:
++ p->anycast_delay = nla_get_msecs(tbp[i]);
++ break;
++ case NDTPA_PROXY_DELAY:
++ p->proxy_delay = nla_get_msecs(tbp[i]);
++ break;
++ case NDTPA_LOCKTIME:
++ p->locktime = nla_get_msecs(tbp[i]);
++ break;
++ }
++ }
++ }
+
+- if (tbp[NDTPA_RETRANS_TIME - 1])
+- p->retrans_time =
+- RTA_GET_MSECS(tbp[NDTPA_RETRANS_TIME - 1]);
++ if (tb[NDTA_THRESH1])
++ tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
+
+- if (tbp[NDTPA_ANYCAST_DELAY - 1])
+- p->anycast_delay =
+- RTA_GET_MSECS(tbp[NDTPA_ANYCAST_DELAY - 1]);
++ if (tb[NDTA_THRESH2])
++ tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
+
+- if (tbp[NDTPA_PROXY_DELAY - 1])
+- p->proxy_delay =
+- RTA_GET_MSECS(tbp[NDTPA_PROXY_DELAY - 1]);
++ if (tb[NDTA_THRESH3])
++ tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
+
+- if (tbp[NDTPA_LOCKTIME - 1])
+- p->locktime = RTA_GET_MSECS(tbp[NDTPA_LOCKTIME - 1]);
+- }
++ if (tb[NDTA_GC_INTERVAL])
++ tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
+
+ err = 0;
+
+-rtattr_failure:
++errout_tbl_lock:
+ write_unlock_bh(&tbl->lock);
+-errout:
++errout_locked:
+ read_unlock(&neigh_tbl_lock);
++errout:
+ return err;
+ }
+
+ int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+- int idx, family;
+- int s_idx = cb->args[0];
++ int family, tidx, nidx = 0;
++ int tbl_skip = cb->args[0];
++ int neigh_skip = cb->args[1];
+ struct neigh_table *tbl;
+
+- family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family;
++ family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
+
+ read_lock(&neigh_tbl_lock);
+- for (tbl = neigh_tables, idx = 0; tbl; tbl = tbl->next) {
++ for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
+ struct neigh_parms *p;
+
+- if (idx < s_idx || (family && tbl->family != family))
++ if (tidx < tbl_skip || (family && tbl->family != family))
+ continue;
+
+- if (neightbl_fill_info(tbl, skb, cb) <= 0)
++ if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,
++ cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
++ NLM_F_MULTI) <= 0)
+ break;
+
+- for (++idx, p = tbl->parms.next; p; p = p->next, idx++) {
+- if (idx < s_idx)
++ for (nidx = 0, p = tbl->parms.next; p; p = p->next, nidx++) {
++ if (nidx < neigh_skip)
+ continue;
+
+- if (neightbl_fill_param_info(tbl, p, skb, cb) <= 0)
++ if (neightbl_fill_param_info(skb, tbl, p,
++ NETLINK_CB(cb->skb).pid,
++ cb->nlh->nlmsg_seq,
++ RTM_NEWNEIGHTBL,
++ NLM_F_MULTI) <= 0)
+ goto out;
+ }
+
++ neigh_skip = 0;
+ }
+ out:
+ read_unlock(&neigh_tbl_lock);
+- cb->args[0] = idx;
++ cb->args[0] = tidx;
++ cb->args[1] = nidx;
+
+ return skb->len;
+ }
+
+-static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
+- u32 pid, u32 seq, int event, unsigned int flags)
++static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
++ u32 pid, u32 seq, int type, unsigned int flags)
+ {
+ unsigned long now = jiffies;
+- unsigned char *b = skb->tail;
+ struct nda_cacheinfo ci;
+- int locked = 0;
+- u32 probes;
+- struct nlmsghdr *nlh = NLMSG_NEW(skb, pid, seq, event,
+- sizeof(struct ndmsg), flags);
+- struct ndmsg *ndm = NLMSG_DATA(nlh);
++ struct nlmsghdr *nlh;
++ struct ndmsg *ndm;
+
+- ndm->ndm_family = n->ops->family;
++ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ ndm = nlmsg_data(nlh);
++ ndm->ndm_family = neigh->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;
+- RTA_PUT(skb, NDA_DST, n->tbl->key_len, n->primary_key);
+- read_lock_bh(&n->lock);
+- locked = 1;
+- ndm->ndm_state = n->nud_state;
+- if (n->nud_state & NUD_VALID)
+- RTA_PUT(skb, NDA_LLADDR, n->dev->addr_len, n->ha);
+- ci.ndm_used = now - n->used;
+- ci.ndm_confirmed = now - n->confirmed;
+- ci.ndm_updated = now - n->updated;
+- ci.ndm_refcnt = atomic_read(&n->refcnt) - 1;
+- probes = atomic_read(&n->probes);
+- read_unlock_bh(&n->lock);
+- locked = 0;
+- RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
+- RTA_PUT(skb, NDA_PROBES, sizeof(probes), &probes);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ ndm->ndm_flags = neigh->flags;
++ ndm->ndm_type = neigh->type;
++ ndm->ndm_ifindex = neigh->dev->ifindex;
++
++ NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
++
++ read_lock_bh(&neigh->lock);
++ ndm->ndm_state = neigh->nud_state;
++ if ((neigh->nud_state & NUD_VALID) &&
++ nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) {
++ read_unlock_bh(&neigh->lock);
++ goto nla_put_failure;
++ }
+
+-nlmsg_failure:
+-rtattr_failure:
+- if (locked)
+- read_unlock_bh(&n->lock);
+- skb_trim(skb, b - skb->data);
+- return -1;
++ ci.ndm_used = now - neigh->used;
++ ci.ndm_confirmed = now - neigh->confirmed;
++ ci.ndm_updated = now - neigh->updated;
++ ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
++ read_unlock_bh(&neigh->lock);
++
++ NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
++ NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
++
++ return nlmsg_end(skb, nlh);
++
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
+ }
+
+
+@@ -1926,12 +1998,12 @@ static int neigh_dump_table(struct neigh
+ int rc, h, s_h = cb->args[1];
+ int idx, s_idx = idx = cb->args[2];
+
++ read_lock_bh(&tbl->lock);
+ for (h = 0; h <= tbl->hash_mask; h++) {
+ if (h < s_h)
+ continue;
+ if (h > s_h)
+ s_idx = 0;
+- read_lock_bh(&tbl->lock);
+ for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) {
+ if (idx < s_idx)
+ continue;
+@@ -1944,8 +2016,8 @@ static int neigh_dump_table(struct neigh
+ goto out;
+ }
+ }
+- read_unlock_bh(&tbl->lock);
+ }
++ read_unlock_bh(&tbl->lock);
+ rc = skb->len;
+ out:
+ cb->args[1] = h;
+@@ -1959,7 +2031,7 @@ int neigh_dump_info(struct sk_buff *skb,
+ int t, family, s_t;
+
+ read_lock(&neigh_tbl_lock);
+- family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family;
++ family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
+ s_t = cb->args[0];
+
+ for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
+@@ -2338,41 +2410,35 @@ static struct file_operations neigh_stat
+ #endif /* CONFIG_PROC_FS */
+
+ #ifdef CONFIG_ARPD
+-void neigh_app_ns(struct neighbour *n)
++static void __neigh_notify(struct neighbour *n, int type, int flags)
+ {
+- struct nlmsghdr *nlh;
+- int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256);
+- struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC);
++ struct sk_buff *skb;
++ int err = -ENOBUFS;
+
+- if (!skb)
+- return;
++ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
++ if (skb == NULL)
++ goto errout;
+
+- if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH, 0) < 0) {
++ err = neigh_fill_info(skb, n, 0, 0, type, flags);
++ if (err < 0) {
+ kfree_skb(skb);
+- return;
++ goto errout;
+ }
+- nlh = (struct nlmsghdr *)skb->data;
+- nlh->nlmsg_flags = NLM_F_REQUEST;
+- NETLINK_CB(skb).dst_group = RTNLGRP_NEIGH;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC);
++
++ err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_NEIGH, err);
+ }
+
+-static void neigh_app_notify(struct neighbour *n)
++void neigh_app_ns(struct neighbour *n)
+ {
+- struct nlmsghdr *nlh;
+- int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256);
+- struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC);
+-
+- if (!skb)
+- return;
++ __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
++}
+
+- if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH, 0) < 0) {
+- kfree_skb(skb);
+- return;
+- }
+- nlh = (struct nlmsghdr *)skb->data;
+- NETLINK_CB(skb).dst_group = RTNLGRP_NEIGH;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC);
++static void neigh_app_notify(struct neighbour *n)
++{
++ __neigh_notify(n, RTM_NEWNEIGH, 0);
+ }
+
+ #endif /* CONFIG_ARPD */
+@@ -2386,7 +2452,7 @@ static struct neigh_sysctl_table {
+ ctl_table neigh_neigh_dir[2];
+ ctl_table neigh_proto_dir[2];
+ ctl_table neigh_root_dir[2];
+-} neigh_sysctl_template = {
++} neigh_sysctl_template __read_mostly = {
+ .neigh_vars = {
+ {
+ .ctl_name = NET_NEIGH_MCAST_SOLICIT,
+@@ -2659,7 +2725,6 @@ void neigh_sysctl_unregister(struct neig
+ #endif /* CONFIG_SYSCTL */
+
+ EXPORT_SYMBOL(__neigh_event_send);
+-EXPORT_SYMBOL(neigh_add);
+ EXPORT_SYMBOL(neigh_changeaddr);
+ EXPORT_SYMBOL(neigh_compat_output);
+ EXPORT_SYMBOL(neigh_connected_output);
+@@ -2679,11 +2744,8 @@ EXPORT_SYMBOL(neigh_table_clear);
+ EXPORT_SYMBOL(neigh_table_init);
+ EXPORT_SYMBOL(neigh_table_init_no_netlink);
+ EXPORT_SYMBOL(neigh_update);
+-EXPORT_SYMBOL(neigh_update_hhs);
+ EXPORT_SYMBOL(pneigh_enqueue);
+ EXPORT_SYMBOL(pneigh_lookup);
+-EXPORT_SYMBOL(neightbl_dump_info);
+-EXPORT_SYMBOL(neightbl_set);
+
+ #ifdef CONFIG_ARPD
+ EXPORT_SYMBOL(neigh_app_ns);
+diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
+index 1347276..f47f319 100644
+--- a/net/core/net-sysfs.c
++++ b/net/core/net-sysfs.c
+@@ -344,8 +344,6 @@ static ssize_t wireless_show(struct clas
+ if(dev->wireless_handlers &&
+ dev->wireless_handlers->get_wireless_stats)
+ iw = dev->wireless_handlers->get_wireless_stats(dev);
+- else if (dev->get_wireless_stats)
+- iw = dev->get_wireless_stats(dev);
+ if (iw != NULL)
+ ret = (*format)(iw, buf);
+ }
+@@ -465,8 +463,7 @@ int netdev_register_sysfs(struct net_dev
+ *groups++ = &netstat_group;
+
+ #ifdef WIRELESS_EXT
+- if (net->get_wireless_stats
+- || (net->wireless_handlers && net->wireless_handlers->get_wireless_stats))
++ if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
+ *groups++ = &wireless_group;
+ #endif
+
+diff --git a/net/core/netpoll.c b/net/core/netpoll.c
+index 471da45..9308af0 100644
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -110,7 +110,7 @@ static int checksum_udp(struct sk_buff *
+
+ psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+
+- if (skb->ip_summed == CHECKSUM_HW &&
++ if (skb->ip_summed == CHECKSUM_COMPLETE &&
+ !(u16)csum_fold(csum_add(psum, skb->csum)))
+ return 0;
+
+@@ -335,13 +335,13 @@ void netpoll_send_udp(struct netpoll *np
+ memcpy(skb->data, msg, len);
+ skb->len += len;
+
+- udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
++ skb->h.uh = udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+ udph->source = htons(np->local_port);
+ udph->dest = htons(np->remote_port);
+ udph->len = htons(udp_len);
+ udph->check = 0;
+
+- iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
++ skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+
+ /* iph->version = 4; iph->ihl = 5; */
+ put_unaligned(0x45, (unsigned char *)iph);
+@@ -357,8 +357,8 @@ void netpoll_send_udp(struct netpoll *np
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+ eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+-
+- eth->h_proto = htons(ETH_P_IP);
++ skb->mac.raw = skb->data;
++ skb->protocol = eth->h_proto = htons(ETH_P_IP);
+ memcpy(eth->h_source, np->local_mac, 6);
+ memcpy(eth->h_dest, np->remote_mac, 6);
+
+diff --git a/net/core/pktgen.c b/net/core/pktgen.c
+index 6a7320b..733d86d 100644
+--- a/net/core/pktgen.c
++++ b/net/core/pktgen.c
+@@ -109,6 +109,8 @@
+ *
+ * MPLS support by Steven Whitehouse <steve at chygwyn.com>
+ *
++ * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli at gmail.com>
++ *
+ */
+ #include <linux/sys.h>
+ #include <linux/types.h>
+@@ -137,6 +139,7 @@
+ #include <linux/inetdevice.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/if_arp.h>
++#include <linux/if_vlan.h>
+ #include <linux/in.h>
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
+@@ -157,7 +160,7 @@
+ #include <asm/div64.h> /* do_div */
+ #include <asm/timex.h>
+
+-#define VERSION "pktgen v2.67: Packet Generator for packet performance testing.\n"
++#define VERSION "pktgen v2.68: Packet Generator for packet performance testing.\n"
+
+ /* #define PG_DEBUG(a) a */
+ #define PG_DEBUG(a)
+@@ -178,6 +181,8 @@
+ #define F_TXSIZE_RND (1<<6) /* Transmit size is random */
+ #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */
+ #define F_MPLS_RND (1<<8) /* Random MPLS labels */
++#define F_VID_RND (1<<9) /* Random VLAN ID */
++#define F_SVID_RND (1<<10) /* Random SVLAN ID */
+
+ /* Thread control flag bits */
+ #define T_TERMINATE (1<<0)
+@@ -198,6 +203,9 @@ static struct proc_dir_entry *pg_proc_di
+
+ #define MAX_CFLOWS 65536
+
++#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
++#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
++
+ struct flow_state {
+ __u32 cur_daddr;
+ int count;
+@@ -284,10 +292,23 @@ struct pktgen_dev {
+ __u16 udp_dst_min; /* inclusive, dest UDP port */
+ __u16 udp_dst_max; /* exclusive, dest UDP port */
+
++ /* DSCP + ECN */
++ __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */
++ __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */
++
+ /* MPLS */
+ unsigned nr_labels; /* Depth of stack, 0 = no MPLS */
+ __be32 labels[MAX_MPLS_LABELS];
+
++ /* VLAN/SVLAN (802.1Q/Q-in-Q) */
++ __u8 vlan_p;
++ __u8 vlan_cfi;
++ __u16 vlan_id; /* 0xffff means no vlan tag */
++
++ __u8 svlan_p;
++ __u8 svlan_cfi;
++ __u16 svlan_id; /* 0xffff means no svlan tag */
++
+ __u32 src_mac_count; /* How many MACs to iterate through */
+ __u32 dst_mac_count; /* How many MACs to iterate through */
+
+@@ -644,6 +665,24 @@ static int pktgen_if_show(struct seq_fil
+ i == pkt_dev->nr_labels-1 ? "\n" : ", ");
+ }
+
++ if (pkt_dev->vlan_id != 0xffff) {
++ seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n",
++ pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi);
++ }
++
++ if (pkt_dev->svlan_id != 0xffff) {
++ seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n",
++ pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi);
++ }
++
++ if (pkt_dev->tos) {
++ seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos);
++ }
++
++ if (pkt_dev->traffic_class) {
++ seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class);
++ }
++
+ seq_printf(seq, " Flags: ");
+
+ if (pkt_dev->flags & F_IPV6)
+@@ -673,6 +712,12 @@ static int pktgen_if_show(struct seq_fil
+ if (pkt_dev->flags & F_MACDST_RND)
+ seq_printf(seq, "MACDST_RND ");
+
++ if (pkt_dev->flags & F_VID_RND)
++ seq_printf(seq, "VID_RND ");
++
++ if (pkt_dev->flags & F_SVID_RND)
++ seq_printf(seq, "SVID_RND ");
++
+ seq_puts(seq, "\n");
+
+ sa = pkt_dev->started_at;
+@@ -715,12 +760,12 @@ static int pktgen_if_show(struct seq_fil
+ }
+
+
+-static int hex32_arg(const char __user *user_buffer, __u32 *num)
++static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num)
+ {
+ int i = 0;
+ *num = 0;
+
+- for(; i < 8; i++) {
++ for(; i < maxlen; i++) {
+ char c;
+ *num <<= 4;
+ if (get_user(c, &user_buffer[i]))
+@@ -815,7 +860,7 @@ static ssize_t get_labels(const char __u
+ pkt_dev->nr_labels = 0;
+ do {
+ __u32 tmp;
+- len = hex32_arg(&buffer[i], &tmp);
++ len = hex32_arg(&buffer[i], 8, &tmp);
+ if (len <= 0)
+ return len;
+ pkt_dev->labels[n] = htonl(tmp);
+@@ -1140,11 +1185,27 @@ static ssize_t pktgen_if_write(struct fi
+ else if (strcmp(f, "!MPLS_RND") == 0)
+ pkt_dev->flags &= ~F_MPLS_RND;
+
++ else if (strcmp(f, "VID_RND") == 0)
++ pkt_dev->flags |= F_VID_RND;
++
++ else if (strcmp(f, "!VID_RND") == 0)
++ pkt_dev->flags &= ~F_VID_RND;
++
++ else if (strcmp(f, "SVID_RND") == 0)
++ pkt_dev->flags |= F_SVID_RND;
++
++ else if (strcmp(f, "!SVID_RND") == 0)
++ pkt_dev->flags &= ~F_SVID_RND;
++
++ else if (strcmp(f, "!IPV6") == 0)
++ pkt_dev->flags &= ~F_IPV6;
++
+ else {
+ sprintf(pg_result,
+ "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
+ f,
+- "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
++ "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
++ "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND\n");
+ return count;
+ }
+ sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
+@@ -1445,6 +1506,160 @@ static ssize_t pktgen_if_write(struct fi
+ offset += sprintf(pg_result + offset,
+ "%08x%s", ntohl(pkt_dev->labels[n]),
+ n == pkt_dev->nr_labels-1 ? "" : ",");
++
++ if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
++ pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
++ pkt_dev->svlan_id = 0xffff;
++
++ if (debug)
++ printk("pktgen: VLAN/SVLAN auto turned off\n");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "vlan_id")) {
++ len = num_arg(&user_buffer[i], 4, &value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if (value <= 4095) {
++ pkt_dev->vlan_id = value; /* turn on VLAN */
++
++ if (debug)
++ printk("pktgen: VLAN turned on\n");
++
++ if (debug && pkt_dev->nr_labels)
++ printk("pktgen: MPLS auto turned off\n");
++
++ pkt_dev->nr_labels = 0; /* turn off MPLS */
++ sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
++ } else {
++ pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
++ pkt_dev->svlan_id = 0xffff;
++
++ if (debug)
++ printk("pktgen: VLAN/SVLAN turned off\n");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "vlan_p")) {
++ len = num_arg(&user_buffer[i], 1, &value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
++ pkt_dev->vlan_p = value;
++ sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
++ } else {
++ sprintf(pg_result, "ERROR: vlan_p must be 0-7");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "vlan_cfi")) {
++ len = num_arg(&user_buffer[i], 1, &value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
++ pkt_dev->vlan_cfi = value;
++ sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
++ } else {
++ sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "svlan_id")) {
++ len = num_arg(&user_buffer[i], 4, &value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
++ pkt_dev->svlan_id = value; /* turn on SVLAN */
++
++ if (debug)
++ printk("pktgen: SVLAN turned on\n");
++
++ if (debug && pkt_dev->nr_labels)
++ printk("pktgen: MPLS auto turned off\n");
++
++ pkt_dev->nr_labels = 0; /* turn off MPLS */
++ sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
++ } else {
++ pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
++ pkt_dev->svlan_id = 0xffff;
++
++ if (debug)
++ printk("pktgen: VLAN/SVLAN turned off\n");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "svlan_p")) {
++ len = num_arg(&user_buffer[i], 1, &value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
++ pkt_dev->svlan_p = value;
++ sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
++ } else {
++ sprintf(pg_result, "ERROR: svlan_p must be 0-7");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "svlan_cfi")) {
++ len = num_arg(&user_buffer[i], 1, &value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
++ pkt_dev->svlan_cfi = value;
++ sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
++ } else {
++ sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "tos")) {
++ __u32 tmp_value = 0;
++ len = hex32_arg(&user_buffer[i], 2, &tmp_value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if (len == 2) {
++ pkt_dev->tos = tmp_value;
++ sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
++ } else {
++ sprintf(pg_result, "ERROR: tos must be 00-ff");
++ }
++ return count;
++ }
++
++ if (!strcmp(name, "traffic_class")) {
++ __u32 tmp_value = 0;
++ len = hex32_arg(&user_buffer[i], 2, &tmp_value);
++ if (len < 0) {
++ return len;
++ }
++ i += len;
++ if (len == 2) {
++ pkt_dev->traffic_class = tmp_value;
++ sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
++ } else {
++ sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
++ }
+ return count;
+ }
+
+@@ -1786,7 +2001,7 @@ static void pktgen_setup_inject(struct p
+ * use ipv6_get_lladdr if/when it's get exported
+ */
+
+- read_lock(&addrconf_lock);
++ rcu_read_lock();
+ if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) {
+ struct inet6_ifaddr *ifp;
+
+@@ -1805,7 +2020,7 @@ static void pktgen_setup_inject(struct p
+ }
+ read_unlock_bh(&idev->lock);
+ }
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ if (err)
+ printk("pktgen: ERROR: IPv6 link address not availble.\n");
+ }
+@@ -1949,6 +2164,14 @@ static void mod_cur_headers(struct pktge
+ htonl(0x000fffff));
+ }
+
++ if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
++ pkt_dev->vlan_id = pktgen_random() % 4096;
++ }
++
++ if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
++ pkt_dev->svlan_id = pktgen_random() % 4096;
++ }
++
+ if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
+ if (pkt_dev->flags & F_UDPSRC_RND)
+ pkt_dev->cur_udp_src =
+@@ -2081,6 +2304,12 @@ static void mpls_push(__be32 *mpls, stru
+ *mpls |= MPLS_STACK_BOTTOM;
+ }
+
++static inline __be16 build_tci(unsigned int id, unsigned int cfi,
++ unsigned int prio)
++{
++ return htons(id | (cfi << 12) | (prio << 13));
++}
++
+ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
+ struct pktgen_dev *pkt_dev)
+ {
+@@ -2092,10 +2321,18 @@ static struct sk_buff *fill_packet_ipv4(
+ struct pktgen_hdr *pgh = NULL;
+ __be16 protocol = __constant_htons(ETH_P_IP);
+ __be32 *mpls;
++ __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */
++ __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */
++ __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */
++ __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
++
+
+ if (pkt_dev->nr_labels)
+ protocol = __constant_htons(ETH_P_MPLS_UC);
+
++ if (pkt_dev->vlan_id != 0xffff)
++ protocol = __constant_htons(ETH_P_8021Q);
++
+ /* Update any of the values, used when we're incrementing various
+ * fields.
+ */
+@@ -2103,7 +2340,9 @@ static struct sk_buff *fill_packet_ipv4(
+
+ datalen = (odev->hard_header_len + 16) & ~0xf;
+ skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
+- pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC);
++ pkt_dev->nr_labels*sizeof(u32) +
++ VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
++ GFP_ATOMIC);
+ if (!skb) {
+ sprintf(pkt_dev->result, "No memory");
+ return NULL;
+@@ -2116,6 +2355,24 @@ static struct sk_buff *fill_packet_ipv4(
+ mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
+ if (pkt_dev->nr_labels)
+ mpls_push(mpls, pkt_dev);
++
++ if (pkt_dev->vlan_id != 0xffff) {
++ if(pkt_dev->svlan_id != 0xffff) {
++ svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
++ *svlan_tci = build_tci(pkt_dev->svlan_id,
++ pkt_dev->svlan_cfi,
++ pkt_dev->svlan_p);
++ svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
++ *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
++ }
++ vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
++ *vlan_tci = build_tci(pkt_dev->vlan_id,
++ pkt_dev->vlan_cfi,
++ pkt_dev->vlan_p);
++ vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
++ *vlan_encapsulated_proto = __constant_htons(ETH_P_IP);
++ }
++
+ iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
+ udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+
+@@ -2124,7 +2381,7 @@ static struct sk_buff *fill_packet_ipv4(
+
+ /* Eth + IPh + UDPh + mpls */
+ datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
+- pkt_dev->nr_labels*sizeof(u32);
++ pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+ if (datalen < sizeof(struct pktgen_hdr))
+ datalen = sizeof(struct pktgen_hdr);
+
+@@ -2136,7 +2393,7 @@ static struct sk_buff *fill_packet_ipv4(
+ iph->ihl = 5;
+ iph->version = 4;
+ iph->ttl = 32;
+- iph->tos = 0;
++ iph->tos = pkt_dev->tos;
+ iph->protocol = IPPROTO_UDP; /* UDP */
+ iph->saddr = pkt_dev->cur_saddr;
+ iph->daddr = pkt_dev->cur_daddr;
+@@ -2146,7 +2403,8 @@ static struct sk_buff *fill_packet_ipv4(
+ iph->check = 0;
+ iph->check = ip_fast_csum((void *)iph, iph->ihl);
+ skb->protocol = protocol;
+- skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
++ skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) -
++ VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+ skb->dev = odev;
+ skb->pkt_type = PACKET_HOST;
+ skb->nh.iph = iph;
+@@ -2218,7 +2476,6 @@ static struct sk_buff *fill_packet_ipv4(
+ pgh->tv_sec = htonl(timestamp.tv_sec);
+ pgh->tv_usec = htonl(timestamp.tv_usec);
+ }
+- pkt_dev->seq_num++;
+
+ return skb;
+ }
+@@ -2402,17 +2659,26 @@ static struct sk_buff *fill_packet_ipv6(
+ struct pktgen_hdr *pgh = NULL;
+ __be16 protocol = __constant_htons(ETH_P_IPV6);
+ __be32 *mpls;
++ __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */
++ __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */
++ __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */
++ __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
+
+ if (pkt_dev->nr_labels)
+ protocol = __constant_htons(ETH_P_MPLS_UC);
+
++ if (pkt_dev->vlan_id != 0xffff)
++ protocol = __constant_htons(ETH_P_8021Q);
++
+ /* 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 +
+- pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC);
++ pkt_dev->nr_labels*sizeof(u32) +
++ VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
++ GFP_ATOMIC);
+ if (!skb) {
+ sprintf(pkt_dev->result, "No memory");
+ return NULL;
+@@ -2425,16 +2691,34 @@ static struct sk_buff *fill_packet_ipv6(
+ mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
+ if (pkt_dev->nr_labels)
+ mpls_push(mpls, pkt_dev);
++
++ if (pkt_dev->vlan_id != 0xffff) {
++ if(pkt_dev->svlan_id != 0xffff) {
++ svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
++ *svlan_tci = build_tci(pkt_dev->svlan_id,
++ pkt_dev->svlan_cfi,
++ pkt_dev->svlan_p);
++ svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
++ *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
++ }
++ vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
++ *vlan_tci = build_tci(pkt_dev->vlan_id,
++ pkt_dev->vlan_cfi,
++ pkt_dev->vlan_p);
++ vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
++ *vlan_encapsulated_proto = __constant_htons(ETH_P_IPV6);
++ }
++
+ iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
+ udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+
+ memcpy(eth, pkt_dev->hh, 12);
+- *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6);
++ *(u16 *) & eth[12] = protocol;
+
+ /* Eth + IPh + UDPh + mpls */
+ datalen = pkt_dev->cur_pkt_size - 14 -
+ sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
+- pkt_dev->nr_labels*sizeof(u32);
++ pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+
+ if (datalen < sizeof(struct pktgen_hdr)) {
+ datalen = sizeof(struct pktgen_hdr);
+@@ -2450,6 +2734,11 @@ static struct sk_buff *fill_packet_ipv6(
+
+ *(u32 *) iph = __constant_htonl(0x60000000); /* Version + flow */
+
++ if (pkt_dev->traffic_class) {
++ /* Version + traffic class + flow (0) */
++ *(u32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
++ }
++
+ iph->hop_limit = 32;
+
+ iph->payload_len = htons(sizeof(struct udphdr) + datalen);
+@@ -2458,7 +2747,8 @@ static struct sk_buff *fill_packet_ipv6(
+ ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
+ ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
+
+- skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
++ skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) -
++ VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+ skb->protocol = protocol;
+ skb->dev = odev;
+ skb->pkt_type = PACKET_HOST;
+@@ -2531,7 +2821,7 @@ static struct sk_buff *fill_packet_ipv6(
+ pgh->tv_sec = htonl(timestamp.tv_sec);
+ pgh->tv_usec = htonl(timestamp.tv_usec);
+ }
+- pkt_dev->seq_num++;
++ /* pkt_dev->seq_num++; FF: you really mean this? */
+
+ return skb;
+ }
+@@ -3177,6 +3467,13 @@ static int pktgen_add_device(struct pktg
+ pkt_dev->udp_dst_min = 9;
+ pkt_dev->udp_dst_max = 9;
+
++ pkt_dev->vlan_p = 0;
++ pkt_dev->vlan_cfi = 0;
++ pkt_dev->vlan_id = 0xffff;
++ pkt_dev->svlan_p = 0;
++ pkt_dev->svlan_cfi = 0;
++ pkt_dev->svlan_id = 0xffff;
++
+ strncpy(pkt_dev->ifname, ifname, IFNAMSIZ);
+
+ if (!pktgen_setup_dev(pkt_dev)) {
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 30cc1ba..02f3c79 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -35,6 +35,7 @@
+ #include <linux/init.h>
+ #include <linux/security.h>
+ #include <linux/mutex.h>
++#include <linux/if_addr.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -49,6 +50,7 @@
+ #include <net/udp.h>
+ #include <net/sock.h>
+ #include <net/pkt_sched.h>
++#include <net/fib_rules.h>
+ #include <net/netlink.h>
+ #ifdef CONFIG_NET_WIRELESS_RTNETLINK
+ #include <linux/wireless.h>
+@@ -56,6 +58,7 @@
+ #endif /* CONFIG_NET_WIRELESS_RTNETLINK */
+
+ static DEFINE_MUTEX(rtnl_mutex);
++static struct sock *rtnl;
+
+ void rtnl_lock(void)
+ {
+@@ -93,8 +96,6 @@ int rtattr_parse(struct rtattr *tb[], in
+ return 0;
+ }
+
+-struct sock *rtnl;
+-
+ struct rtnetlink_link * rtnetlink_links[NPROTO];
+
+ static const int rtm_min[RTM_NR_FAMILIES] =
+@@ -102,8 +103,7 @@ static const int rtm_min[RTM_NR_FAMILIES
+ [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)),
+- [RTM_FAM(RTM_NEWNEIGH)] = NLMSG_LENGTH(sizeof(struct ndmsg)),
+- [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct rtmsg)),
++ [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
+ [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
+ [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
+ [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
+@@ -111,7 +111,6 @@ static const int rtm_min[RTM_NR_FAMILIES
+ [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+- [RTM_FAM(RTM_NEWNEIGHTBL)] = NLMSG_LENGTH(sizeof(struct ndtmsg)),
+ };
+
+ static const int rta_max[RTM_NR_FAMILIES] =
+@@ -119,13 +118,11 @@ static const int rta_max[RTM_NR_FAMILIES
+ [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX,
+ [RTM_FAM(RTM_NEWADDR)] = IFA_MAX,
+ [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX,
+- [RTM_FAM(RTM_NEWNEIGH)] = NDA_MAX,
+- [RTM_FAM(RTM_NEWRULE)] = RTA_MAX,
++ [RTM_FAM(RTM_NEWRULE)] = FRA_MAX,
+ [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX,
+ [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX,
+ [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX,
+ [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX,
+- [RTM_FAM(RTM_NEWNEIGHTBL)] = NDTA_MAX,
+ };
+
+ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
+@@ -168,24 +165,52 @@ int rtnetlink_send(struct sk_buff *skb,
+ return err;
+ }
+
++int rtnl_unicast(struct sk_buff *skb, u32 pid)
++{
++ return nlmsg_unicast(rtnl, skb, pid);
++}
++
++int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
++ struct nlmsghdr *nlh, gfp_t flags)
++{
++ int report = 0;
++
++ if (nlh)
++ report = nlmsg_report(nlh);
++
++ return nlmsg_notify(rtnl, skb, pid, group, report, flags);
++}
++
++void rtnl_set_sk_err(u32 group, int error)
++{
++ netlink_set_err(rtnl, 0, group, error);
++}
++
+ int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
+ {
+- struct rtattr *mx = (struct rtattr*)skb->tail;
+- int i;
++ struct nlattr *mx;
++ int i, valid = 0;
++
++ mx = nla_nest_start(skb, RTA_METRICS);
++ if (mx == NULL)
++ return -ENOBUFS;
++
++ for (i = 0; i < RTAX_MAX; i++) {
++ if (metrics[i]) {
++ valid++;
++ NLA_PUT_U32(skb, i+1, metrics[i]);
++ }
++ }
+
+- RTA_PUT(skb, RTA_METRICS, 0, NULL);
+- for (i=0; i<RTAX_MAX; i++) {
+- if (metrics[i])
+- RTA_PUT(skb, i+1, sizeof(u32), metrics+i);
++ if (!valid) {
++ nla_nest_cancel(skb, mx);
++ return 0;
+ }
+- mx->rta_len = skb->tail - (u8*)mx;
+- if (mx->rta_len == RTA_LENGTH(0))
+- skb_trim(skb, (u8*)mx - skb->data);
+- return 0;
+
+-rtattr_failure:
+- skb_trim(skb, (u8*)mx - skb->data);
+- return -1;
++ return nla_nest_end(skb, mx);
++
++nla_put_failure:
++ return nla_nest_cancel(skb, mx);
+ }
+
+
+@@ -216,41 +241,73 @@ static void set_operstate(struct net_dev
+ }
+ }
+
+-static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
+- int type, u32 pid, u32 seq, u32 change,
+- unsigned int flags)
++static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
++ struct net_device_stats *b)
+ {
+- struct ifinfomsg *r;
+- struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
+-
+- 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);
+- r->ifi_change = change;
+-
+- RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
+-
+- if (1) {
+- u32 txqlen = dev->tx_queue_len;
+- RTA_PUT(skb, IFLA_TXQLEN, sizeof(txqlen), &txqlen);
+- }
++ a->rx_packets = b->rx_packets;
++ a->tx_packets = b->tx_packets;
++ a->rx_bytes = b->rx_bytes;
++ a->tx_bytes = b->tx_bytes;
++ a->rx_errors = b->rx_errors;
++ a->tx_errors = b->tx_errors;
++ a->rx_dropped = b->rx_dropped;
++ a->tx_dropped = b->tx_dropped;
++
++ a->multicast = b->multicast;
++ a->collisions = b->collisions;
++
++ a->rx_length_errors = b->rx_length_errors;
++ a->rx_over_errors = b->rx_over_errors;
++ a->rx_crc_errors = b->rx_crc_errors;
++ a->rx_frame_errors = b->rx_frame_errors;
++ a->rx_fifo_errors = b->rx_fifo_errors;
++ a->rx_missed_errors = b->rx_missed_errors;
++
++ a->tx_aborted_errors = b->tx_aborted_errors;
++ a->tx_carrier_errors = b->tx_carrier_errors;
++ a->tx_fifo_errors = b->tx_fifo_errors;
++ a->tx_heartbeat_errors = b->tx_heartbeat_errors;
++ a->tx_window_errors = b->tx_window_errors;
++
++ a->rx_compressed = b->rx_compressed;
++ a->tx_compressed = b->tx_compressed;
++};
+
+- if (1) {
+- u32 weight = dev->weight;
+- RTA_PUT(skb, IFLA_WEIGHT, sizeof(weight), &weight);
+- }
++static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
++ void *iwbuf, int iwbuflen, int type, u32 pid,
++ u32 seq, u32 change, unsigned int flags)
++{
++ struct ifinfomsg *ifm;
++ struct nlmsghdr *nlh;
++
++ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ ifm = nlmsg_data(nlh);
++ ifm->ifi_family = AF_UNSPEC;
++ ifm->__ifi_pad = 0;
++ ifm->ifi_type = dev->type;
++ ifm->ifi_index = dev->ifindex;
++ ifm->ifi_flags = dev_get_flags(dev);
++ ifm->ifi_change = change;
++
++ NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
++ NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len);
++ NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight);
++ NLA_PUT_U8(skb, IFLA_OPERSTATE,
++ netif_running(dev) ? dev->operstate : IF_OPER_DOWN);
++ NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode);
++ NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
++
++ if (dev->ifindex != dev->iflink)
++ NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
++
++ if (dev->master)
++ NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex);
+
+- if (1) {
+- u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN;
+- u8 link_mode = dev->link_mode;
+- RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate);
+- RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode);
+- }
++ if (dev->qdisc_sleeping)
++ NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc_sleeping->ops->id);
+
+ if (1) {
+ struct rtnl_link_ifmap map = {
+@@ -261,58 +318,38 @@ static int rtnetlink_fill_ifinfo(struct
+ .dma = dev->dma,
+ .port = dev->if_port,
+ };
+- RTA_PUT(skb, IFLA_MAP, sizeof(map), &map);
++ NLA_PUT(skb, IFLA_MAP, sizeof(map), &map);
+ }
+
+ if (dev->addr_len) {
+- RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
+- RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
+- }
+-
+- if (1) {
+- u32 mtu = dev->mtu;
+- RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu);
+- }
+-
+- if (dev->ifindex != dev->iflink) {
+- u32 iflink = dev->iflink;
+- RTA_PUT(skb, IFLA_LINK, sizeof(iflink), &iflink);
+- }
+-
+- if (dev->qdisc_sleeping)
+- RTA_PUT(skb, IFLA_QDISC,
+- strlen(dev->qdisc_sleeping->ops->id) + 1,
+- dev->qdisc_sleeping->ops->id);
+-
+- if (dev->master) {
+- u32 master = dev->master->ifindex;
+- RTA_PUT(skb, IFLA_MASTER, sizeof(master), &master);
++ NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
++ NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
+ }
+
+ if (dev->get_stats) {
+- unsigned long *stats = (unsigned long*)dev->get_stats(dev);
++ struct net_device_stats *stats = dev->get_stats(dev);
+ if (stats) {
+- struct rtattr *a;
+- __u32 *s;
+- int i;
+- int n = sizeof(struct rtnl_link_stats)/4;
+-
+- a = __RTA_PUT(skb, IFLA_STATS, n*4);
+- s = RTA_DATA(a);
+- for (i=0; i<n; i++)
+- s[i] = stats[i];
++ struct nlattr *attr;
++
++ attr = nla_reserve(skb, IFLA_STATS,
++ sizeof(struct rtnl_link_stats));
++ if (attr == NULL)
++ goto nla_put_failure;
++
++ copy_rtnl_link_stats(nla_data(attr), stats);
+ }
+ }
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ if (iwbuf)
++ NLA_PUT(skb, IFLA_WIRELESS, iwbuflen, iwbuf);
++
++ return nlmsg_end(skb, nlh);
++
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
+ }
+
+-static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
++static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+ int idx;
+ int s_idx = cb->args[0];
+@@ -322,10 +359,9 @@ static int rtnetlink_dump_ifinfo(struct
+ for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ if (idx < s_idx)
+ continue;
+- if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK,
+- NETLINK_CB(cb->skb).pid,
+- cb->nlh->nlmsg_seq, 0,
+- NLM_F_MULTI) <= 0)
++ if (rtnl_fill_ifinfo(skb, dev, NULL, 0, RTM_NEWLINK,
++ NETLINK_CB(cb->skb).pid,
++ cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
+ break;
+ }
+ read_unlock(&dev_base_lock);
+@@ -334,52 +370,70 @@ static int rtnetlink_dump_ifinfo(struct
+ return skb->len;
+ }
+
+-static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
++static struct nla_policy ifla_policy[IFLA_MAX+1] __read_mostly = {
++ [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
++ [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
++ [IFLA_MTU] = { .type = NLA_U32 },
++ [IFLA_TXQLEN] = { .type = NLA_U32 },
++ [IFLA_WEIGHT] = { .type = NLA_U32 },
++ [IFLA_OPERSTATE] = { .type = NLA_U8 },
++ [IFLA_LINKMODE] = { .type = NLA_U8 },
++};
++
++static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+- struct ifinfomsg *ifm = NLMSG_DATA(nlh);
+- struct rtattr **ida = arg;
++ struct ifinfomsg *ifm;
+ struct net_device *dev;
+- int err, send_addr_notify = 0;
++ int err, send_addr_notify = 0, modified = 0;
++ struct nlattr *tb[IFLA_MAX+1];
++ char ifname[IFNAMSIZ];
++
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
++ if (err < 0)
++ goto errout;
++
++ if (tb[IFLA_IFNAME])
++ nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
++ else
++ ifname[0] = '\0';
+
++ err = -EINVAL;
++ ifm = nlmsg_data(nlh);
+ if (ifm->ifi_index >= 0)
+ dev = dev_get_by_index(ifm->ifi_index);
+- else if (ida[IFLA_IFNAME - 1]) {
+- char ifname[IFNAMSIZ];
+-
+- if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
+- IFNAMSIZ) >= IFNAMSIZ)
+- return -EINVAL;
++ else if (tb[IFLA_IFNAME])
+ dev = dev_get_by_name(ifname);
+- } else
+- return -EINVAL;
++ else
++ goto errout;
+
+- if (!dev)
+- return -ENODEV;
++ if (dev == NULL) {
++ err = -ENODEV;
++ goto errout;
++ }
+
+- err = -EINVAL;
++ if (tb[IFLA_ADDRESS] &&
++ nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
++ goto errout_dev;
+
+- if (ifm->ifi_flags)
+- dev_change_flags(dev, ifm->ifi_flags);
++ if (tb[IFLA_BROADCAST] &&
++ nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
++ goto errout_dev;
+
+- if (ida[IFLA_MAP - 1]) {
++ if (tb[IFLA_MAP]) {
+ struct rtnl_link_ifmap *u_map;
+ struct ifmap k_map;
+
+ if (!dev->set_config) {
+ err = -EOPNOTSUPP;
+- goto out;
++ goto errout_dev;
+ }
+
+ if (!netif_device_present(dev)) {
+ err = -ENODEV;
+- goto out;
++ goto errout_dev;
+ }
+-
+- if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map)))
+- goto out;
+-
+- u_map = RTA_DATA(ida[IFLA_MAP - 1]);
+
++ u_map = nla_data(tb[IFLA_MAP]);
+ k_map.mem_start = (unsigned long) u_map->mem_start;
+ k_map.mem_end = (unsigned long) u_map->mem_end;
+ k_map.base_addr = (unsigned short) u_map->base_addr;
+@@ -388,200 +442,175 @@ static int do_setlink(struct sk_buff *sk
+ k_map.port = (unsigned char) u_map->port;
+
+ err = dev->set_config(dev, &k_map);
++ if (err < 0)
++ goto errout_dev;
+
+- if (err)
+- goto out;
++ modified = 1;
+ }
+
+- if (ida[IFLA_ADDRESS - 1]) {
++ if (tb[IFLA_ADDRESS]) {
+ struct sockaddr *sa;
+ int len;
+
+ if (!dev->set_mac_address) {
+ err = -EOPNOTSUPP;
+- goto out;
++ goto errout_dev;
+ }
++
+ if (!netif_device_present(dev)) {
+ err = -ENODEV;
+- goto out;
++ goto errout_dev;
+ }
+- if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len))
+- goto out;
+
+ len = sizeof(sa_family_t) + dev->addr_len;
+ sa = kmalloc(len, GFP_KERNEL);
+ if (!sa) {
+ err = -ENOMEM;
+- goto out;
++ goto errout_dev;
+ }
+ sa->sa_family = dev->type;
+- memcpy(sa->sa_data, RTA_DATA(ida[IFLA_ADDRESS - 1]),
++ memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
+ dev->addr_len);
+ err = dev->set_mac_address(dev, sa);
+ kfree(sa);
+ if (err)
+- goto out;
++ goto errout_dev;
+ send_addr_notify = 1;
++ modified = 1;
+ }
+
+- if (ida[IFLA_BROADCAST - 1]) {
+- if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len))
+- goto out;
+- memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]),
+- dev->addr_len);
+- send_addr_notify = 1;
++ if (tb[IFLA_MTU]) {
++ err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
++ if (err < 0)
++ goto errout_dev;
++ modified = 1;
+ }
+
+- if (ida[IFLA_MTU - 1]) {
+- if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
+- goto out;
+- err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1])));
+-
+- if (err)
+- goto out;
+-
++ /*
++ * Interface selected by interface index but interface
++ * name provided implies that a name change has been
++ * requested.
++ */
++ if (ifm->ifi_index >= 0 && ifname[0]) {
++ err = dev_change_name(dev, ifname);
++ if (err < 0)
++ goto errout_dev;
++ modified = 1;
+ }
+
+- if (ida[IFLA_TXQLEN - 1]) {
+- if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
+- goto out;
++#ifdef CONFIG_NET_WIRELESS_RTNETLINK
++ if (tb[IFLA_WIRELESS]) {
++ /* Call Wireless Extensions.
++ * Various stuff checked in there... */
++ err = wireless_rtnetlink_set(dev, nla_data(tb[IFLA_WIRELESS]),
++ nla_len(tb[IFLA_WIRELESS]));
++ if (err < 0)
++ goto errout_dev;
++ }
++#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
+
+- dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1]));
++ if (tb[IFLA_BROADCAST]) {
++ nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
++ send_addr_notify = 1;
+ }
+
+- if (ida[IFLA_WEIGHT - 1]) {
+- if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
+- goto out;
+
+- dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
+- }
++ if (ifm->ifi_flags)
++ dev_change_flags(dev, ifm->ifi_flags);
+
+- if (ida[IFLA_OPERSTATE - 1]) {
+- if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+- goto out;
++ if (tb[IFLA_TXQLEN])
++ dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
+
+- set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
+- }
++ if (tb[IFLA_WEIGHT])
++ dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
+
+- if (ida[IFLA_LINKMODE - 1]) {
+- if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+- goto out;
++ if (tb[IFLA_OPERSTATE])
++ set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
+
++ if (tb[IFLA_LINKMODE]) {
+ write_lock_bh(&dev_base_lock);
+- dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
++ dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+ write_unlock_bh(&dev_base_lock);
+ }
+
+- if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
+- char ifname[IFNAMSIZ];
+-
+- if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
+- IFNAMSIZ) >= IFNAMSIZ)
+- goto out;
+- err = dev_change_name(dev, ifname);
+- if (err)
+- goto out;
+- }
+-
+-#ifdef CONFIG_NET_WIRELESS_RTNETLINK
+- if (ida[IFLA_WIRELESS - 1]) {
+-
+- /* Call Wireless Extensions.
+- * Various stuff checked in there... */
+- err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
+- if (err)
+- goto out;
+- }
+-#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
+-
+ err = 0;
+
+-out:
++errout_dev:
++ if (err < 0 && modified && net_ratelimit())
++ printk(KERN_WARNING "A link change request failed with "
++ "some changes comitted already. Interface %s may "
++ "have been left with an inconsistent configuration, "
++ "please check.\n", dev->name);
++
+ if (send_addr_notify)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+
+ dev_put(dev);
++errout:
+ return err;
+ }
+
+-#ifdef CONFIG_NET_WIRELESS_RTNETLINK
+-static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg)
++static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+ {
+- struct ifinfomsg *ifm = NLMSG_DATA(in_nlh);
+- struct rtattr **ida = arg;
+- struct net_device *dev;
+- struct ifinfomsg *r;
+- struct nlmsghdr *nlh;
+- int err = -ENOBUFS;
+- struct sk_buff *skb;
+- unsigned char *b;
+- char *iw_buf = NULL;
++ struct ifinfomsg *ifm;
++ struct nlattr *tb[IFLA_MAX+1];
++ struct net_device *dev = NULL;
++ struct sk_buff *nskb;
++ char *iw_buf = NULL, *iw = NULL;
+ int iw_buf_len = 0;
++ int err, payload;
+
+- if (ifm->ifi_index >= 0)
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
++ if (err < 0)
++ return err;
++
++ ifm = nlmsg_data(nlh);
++ if (ifm->ifi_index >= 0) {
+ dev = dev_get_by_index(ifm->ifi_index);
+- else
++ if (dev == NULL)
++ return -ENODEV;
++ } else
+ return -EINVAL;
+- if (!dev)
+- return -ENODEV;
+
+-#ifdef CONFIG_NET_WIRELESS_RTNETLINK
+- if (ida[IFLA_WIRELESS - 1]) {
+
++#ifdef CONFIG_NET_WIRELESS_RTNETLINK
++ if (tb[IFLA_WIRELESS]) {
+ /* Call Wireless Extensions. We need to know the size before
+ * we can alloc. Various stuff checked in there... */
+- err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len);
+- if (err)
+- goto out;
++ err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]),
++ nla_len(tb[IFLA_WIRELESS]),
++ &iw_buf, &iw_buf_len);
++ if (err < 0)
++ goto errout;
++
++ iw += IW_EV_POINT_OFF;
+ }
+ #endif /* CONFIG_NET_WIRELESS_RTNETLINK */
+
+- /* Create a skb big enough to include all the data.
+- * Some requests are way bigger than 4k... Jean II */
+- skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)),
+- GFP_KERNEL);
+- if (!skb)
+- goto out;
+- b = skb->tail;
+-
+- /* Put in the message the usual good stuff */
+- nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq,
+- RTM_NEWLINK, 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;
+- r->ifi_change = 0;
+-
+- /* Put the wireless payload if it exist */
+- if(iw_buf != NULL)
+- RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len,
+- iw_buf + IW_EV_POINT_OFF);
+-
+- nlh->nlmsg_len = skb->tail - b;
+-
+- /* Needed ? */
+- NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+-
+- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+- if (err > 0)
+- err = 0;
+-out:
+- if(iw_buf != NULL)
+- kfree(iw_buf);
++ payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) +
++ nla_total_size(iw_buf_len));
++ nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
++ if (nskb == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
++
++ err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
++ NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
++ if (err <= 0) {
++ kfree_skb(nskb);
++ goto errout;
++ }
++
++ err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
++errout:
++ kfree(iw_buf);
+ dev_put(dev);
+- return err;
+
+-rtattr_failure:
+-nlmsg_failure:
+- kfree_skb(skb);
+- goto out;
++ return err;
+ }
+-#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
+
+-static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
++static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+ int idx;
+ int s_idx = cb->family;
+@@ -608,20 +637,22 @@ static int rtnetlink_dump_all(struct sk_
+ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
+ {
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct ifinfomsg) +
+- sizeof(struct rtnl_link_ifmap) +
+- sizeof(struct rtnl_link_stats) + 128);
++ int err = -ENOBUFS;
+
+- skb = alloc_skb(size, GFP_KERNEL);
+- if (!skb)
+- return;
++ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (skb == NULL)
++ goto errout;
+
+- if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change, 0) < 0) {
++ err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL);
++
++ err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_LINK, err);
+ }
+
+ /* Protected by RTNL sempahore. */
+@@ -746,18 +777,19 @@ static void rtnetlink_rcv(struct sock *s
+
+ static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
+ {
+- [RTM_GETLINK - RTM_BASE] = {
+-#ifdef CONFIG_NET_WIRELESS_RTNETLINK
+- .doit = do_getlink,
+-#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
+- .dumpit = rtnetlink_dump_ifinfo },
+- [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
+- [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
+- [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
++ [RTM_GETLINK - RTM_BASE] = { .doit = rtnl_getlink,
++ .dumpit = rtnl_dump_ifinfo },
++ [RTM_SETLINK - RTM_BASE] = { .doit = rtnl_setlink },
++ [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnl_dump_all },
++ [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnl_dump_all },
+ [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },
+ [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete },
+ [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info },
+- [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
++#ifdef CONFIG_FIB_RULES
++ [RTM_NEWRULE - RTM_BASE] = { .doit = fib_nl_newrule },
++ [RTM_DELRULE - RTM_BASE] = { .doit = fib_nl_delrule },
++#endif
++ [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnl_dump_all },
+ [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info },
+ [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set },
+ };
+@@ -817,7 +849,9 @@ EXPORT_SYMBOL(rtattr_strlcpy);
+ EXPORT_SYMBOL(rtattr_parse);
+ EXPORT_SYMBOL(rtnetlink_links);
+ EXPORT_SYMBOL(rtnetlink_put_metrics);
+-EXPORT_SYMBOL(rtnl);
+ EXPORT_SYMBOL(rtnl_lock);
+ EXPORT_SYMBOL(rtnl_trylock);
+ EXPORT_SYMBOL(rtnl_unlock);
++EXPORT_SYMBOL(rtnl_unicast);
++EXPORT_SYMBOL(rtnl_notify);
++EXPORT_SYMBOL(rtnl_set_sk_err);
+diff --git a/net/core/scm.c b/net/core/scm.c
+index 649d01e..271cf06 100644
+--- a/net/core/scm.c
++++ b/net/core/scm.c
+@@ -245,8 +245,7 @@ void scm_detach_fds(struct msghdr *msg,
+ if (i > 0)
+ {
+ int cmlen = CMSG_LEN(i*sizeof(int));
+- if (!err)
+- err = put_user(SOL_SOCKET, &cm->cmsg_level);
++ err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ if (!err)
+ err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+ if (!err)
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index c54f366..f735455 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -156,7 +156,8 @@ struct sk_buff *__alloc_skb(unsigned int
+
+ /* Get the DATA. Size must match skb_add_mtu(). */
+ size = SKB_DATA_ALIGN(size);
+- data = ____kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
++ data = kmalloc_track_caller(size + sizeof(struct skb_shared_info),
++ gfp_mask);
+ if (!data)
+ goto nodata;
+
+@@ -1397,7 +1398,7 @@ void skb_copy_and_csum_dev(const struct
+ unsigned int csum;
+ long csstart;
+
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ csstart = skb->h.raw - skb->data;
+ else
+ csstart = skb_headlen(skb);
+@@ -1411,7 +1412,7 @@ void skb_copy_and_csum_dev(const struct
+ csum = skb_copy_and_csum_bits(skb, csstart, to + csstart,
+ skb->len - csstart, 0);
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ long csstuff = csstart + skb->csum;
+
+ *((unsigned short *)(to + csstuff)) = csum_fold(csum);
+@@ -1898,10 +1899,10 @@ int skb_append_datato_frags(struct sock
+ * @len: length of data pulled
+ *
+ * This function performs an skb_pull on the packet and updates
+- * update the CHECKSUM_HW checksum. It should be used on receive
+- * path processing instead of skb_pull unless you know that the
+- * checksum difference is zero (e.g., a valid IP header) or you
+- * are setting ip_summed to CHECKSUM_NONE.
++ * update the CHECKSUM_COMPLETE checksum. It should be used on
++ * receive path processing instead of skb_pull unless you know
++ * that the checksum difference is zero (e.g., a valid IP header)
++ * or you are setting ip_summed to CHECKSUM_NONE.
+ */
+ unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
+ {
+@@ -1945,7 +1946,7 @@ struct sk_buff *skb_segment(struct sk_bu
+ do {
+ struct sk_buff *nskb;
+ skb_frag_t *frag;
+- int hsize, nsize;
++ int hsize;
+ int k;
+ int size;
+
+@@ -1956,11 +1957,10 @@ struct sk_buff *skb_segment(struct sk_bu
+ hsize = skb_headlen(skb) - offset;
+ if (hsize < 0)
+ hsize = 0;
+- nsize = hsize + doffset;
+- if (nsize > len + doffset || !sg)
+- nsize = len + doffset;
++ if (hsize > len || !sg)
++ hsize = len;
+
+- nskb = alloc_skb(nsize + headroom, GFP_ATOMIC);
++ nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC);
+ if (unlikely(!nskb))
+ goto err;
+
+@@ -1994,7 +1994,7 @@ struct sk_buff *skb_segment(struct sk_bu
+ frag = skb_shinfo(nskb)->frags;
+ k = 0;
+
+- nskb->ip_summed = CHECKSUM_HW;
++ nskb->ip_summed = CHECKSUM_PARTIAL;
+ nskb->csum = skb->csum;
+ memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
+
+@@ -2046,19 +2046,14 @@ void __init skb_init(void)
+ skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
+ sizeof(struct sk_buff),
+ 0,
+- SLAB_HWCACHE_ALIGN,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+- if (!skbuff_head_cache)
+- panic("cannot create skbuff cache");
+-
+ skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache",
+ (2*sizeof(struct sk_buff)) +
+ sizeof(atomic_t),
+ 0,
+- SLAB_HWCACHE_ALIGN,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+- if (!skbuff_fclone_cache)
+- panic("cannot create skbuff cache");
+ }
+
+ EXPORT_SYMBOL(___pskb_trim);
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 51fcfbc..ee6cd25 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -187,13 +187,13 @@ static struct lock_class_key af_callback
+ #define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS)
+
+ /* Run time adjustable parameters. */
+-__u32 sysctl_wmem_max = SK_WMEM_MAX;
+-__u32 sysctl_rmem_max = SK_RMEM_MAX;
+-__u32 sysctl_wmem_default = SK_WMEM_MAX;
+-__u32 sysctl_rmem_default = SK_RMEM_MAX;
++__u32 sysctl_wmem_max __read_mostly = SK_WMEM_MAX;
++__u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX;
++__u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX;
++__u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
+
+ /* Maximal space eaten by iovec or ancilliary data plus some space */
+-int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
++int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512);
+
+ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
+ {
+@@ -247,11 +247,7 @@ int sock_queue_rcv_skb(struct sock *sk,
+ goto out;
+ }
+
+- /* It would be deadlock, if sock_queue_rcv_skb is used
+- with socket lock! We assume that users of this
+- function are lock free.
+- */
+- err = sk_filter(sk, skb, 1);
++ err = sk_filter(sk, skb);
+ if (err)
+ goto out;
+
+@@ -278,7 +274,7 @@ int sk_receive_skb(struct sock *sk, stru
+ {
+ int rc = NET_RX_SUCCESS;
+
+- if (sk_filter(sk, skb, 0))
++ if (sk_filter(sk, skb))
+ goto discard_and_relse;
+
+ skb->dev = NULL;
+@@ -606,15 +602,15 @@ set_rcvbuf:
+ break;
+
+ case SO_DETACH_FILTER:
+- spin_lock_bh(&sk->sk_lock.slock);
+- filter = sk->sk_filter;
++ rcu_read_lock_bh();
++ filter = rcu_dereference(sk->sk_filter);
+ if (filter) {
+- sk->sk_filter = NULL;
+- spin_unlock_bh(&sk->sk_lock.slock);
++ rcu_assign_pointer(sk->sk_filter, NULL);
+ sk_filter_release(sk, filter);
++ rcu_read_unlock_bh();
+ break;
+ }
+- spin_unlock_bh(&sk->sk_lock.slock);
++ rcu_read_unlock_bh();
+ ret = -ENONET;
+ break;
+
+@@ -827,7 +823,7 @@ static void inline sock_lock_init(struct
+ af_family_slock_key_strings[sk->sk_family]);
+ lockdep_init_map(&sk->sk_lock.dep_map,
+ af_family_key_strings[sk->sk_family],
+- af_family_keys + sk->sk_family);
++ af_family_keys + sk->sk_family, 0);
+ }
+
+ /**
+@@ -884,10 +880,10 @@ void sk_free(struct sock *sk)
+ if (sk->sk_destruct)
+ sk->sk_destruct(sk);
+
+- filter = sk->sk_filter;
++ filter = rcu_dereference(sk->sk_filter);
+ if (filter) {
+ sk_filter_release(sk, filter);
+- sk->sk_filter = NULL;
++ rcu_assign_pointer(sk->sk_filter, NULL);
+ }
+
+ sock_disable_timestamp(sk);
+@@ -911,7 +907,7 @@ struct sock *sk_clone(const struct sock
+ if (newsk != NULL) {
+ struct sk_filter *filter;
+
+- memcpy(newsk, sk, sk->sk_prot->obj_size);
++ sock_copy(newsk, sk);
+
+ /* SANITY */
+ sk_node_init(&newsk->sk_node);
+@@ -1164,7 +1160,7 @@ static struct sk_buff *sock_alloc_send_p
+ goto failure;
+
+ if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
+- skb = alloc_skb(header_len, sk->sk_allocation);
++ skb = alloc_skb(header_len, gfp_mask);
+ if (skb) {
+ int npages;
+ int i;
+diff --git a/net/core/utils.c b/net/core/utils.c
+index e31c90e..d93fe64 100644
+--- a/net/core/utils.c
++++ b/net/core/utils.c
+@@ -3,7 +3,8 @@
+ *
+ * Authors:
+ * net_random Alan Cox
+- * net_ratelimit Andy Kleen
++ * net_ratelimit Andi Kleen
++ * in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
+ *
+ * Created by Alexey Kuznetsov <kuznet at ms2.inr.ac.ru>
+ *
+@@ -29,119 +30,6 @@
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+
+-/*
+- This is a maximally equidistributed combined Tausworthe generator
+- based on code from GNU Scientific Library 1.5 (30 Jun 2004)
+-
+- x_n = (s1_n ^ s2_n ^ s3_n)
+-
+- s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
+- s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
+- s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
+-
+- The period of this generator is about 2^88.
+-
+- From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
+- Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
+-
+- This is available on the net from L'Ecuyer's home page,
+-
+- http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
+- ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
+-
+- There is an erratum in the paper "Tables of Maximally
+- Equidistributed Combined LFSR Generators", Mathematics of
+- Computation, 68, 225 (1999), 261--269:
+- http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
+-
+- ... the k_j most significant bits of z_j must be non-
+- zero, for each j. (Note: this restriction also applies to the
+- computer code given in [4], but was mistakenly not mentioned in
+- that paper.)
+-
+- This affects the seeding procedure by imposing the requirement
+- s1 > 1, s2 > 7, s3 > 15.
+-
+-*/
+-struct nrnd_state {
+- u32 s1, s2, s3;
+-};
+-
+-static DEFINE_PER_CPU(struct nrnd_state, net_rand_state);
+-
+-static u32 __net_random(struct nrnd_state *state)
+-{
+-#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
+-
+- state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
+- state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
+- state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
+-
+- return (state->s1 ^ state->s2 ^ state->s3);
+-}
+-
+-static void __net_srandom(struct nrnd_state *state, unsigned long s)
+-{
+- if (s == 0)
+- s = 1; /* default seed is 1 */
+-
+-#define LCG(n) (69069 * n)
+- state->s1 = LCG(s);
+- state->s2 = LCG(state->s1);
+- state->s3 = LCG(state->s2);
+-
+- /* "warm it up" */
+- __net_random(state);
+- __net_random(state);
+- __net_random(state);
+- __net_random(state);
+- __net_random(state);
+- __net_random(state);
+-}
+-
+-
+-unsigned long net_random(void)
+-{
+- unsigned long r;
+- struct nrnd_state *state = &get_cpu_var(net_rand_state);
+- r = __net_random(state);
+- put_cpu_var(state);
+- return r;
+-}
+-
+-
+-void net_srandom(unsigned long entropy)
+-{
+- struct nrnd_state *state = &get_cpu_var(net_rand_state);
+- __net_srandom(state, state->s1^entropy);
+- put_cpu_var(state);
+-}
+-
+-void __init net_random_init(void)
+-{
+- int i;
+-
+- for_each_possible_cpu(i) {
+- struct nrnd_state *state = &per_cpu(net_rand_state,i);
+- __net_srandom(state, i+jiffies);
+- }
+-}
+-
+-static int net_random_reseed(void)
+-{
+- int i;
+- unsigned long seed;
+-
+- for_each_possible_cpu(i) {
+- struct nrnd_state *state = &per_cpu(net_rand_state,i);
+-
+- get_random_bytes(&seed, sizeof(seed));
+- __net_srandom(state, seed);
+- }
+- return 0;
+-}
+-late_initcall(net_random_reseed);
+-
+ int net_msg_cost = 5*HZ;
+ int net_msg_burst = 10;
+
+@@ -152,10 +40,7 @@ int net_ratelimit(void)
+ {
+ return __printk_ratelimit(net_msg_cost, net_msg_burst);
+ }
+-
+-EXPORT_SYMBOL(net_random);
+ EXPORT_SYMBOL(net_ratelimit);
+-EXPORT_SYMBOL(net_srandom);
+
+ /*
+ * Convert an ASCII string to binary IP.
+@@ -191,3 +76,215 @@ __be32 in_aton(const char *str)
+ }
+
+ EXPORT_SYMBOL(in_aton);
++
++#define IN6PTON_XDIGIT 0x00010000
++#define IN6PTON_DIGIT 0x00020000
++#define IN6PTON_COLON_MASK 0x00700000
++#define IN6PTON_COLON_1 0x00100000 /* single : requested */
++#define IN6PTON_COLON_2 0x00200000 /* second : requested */
++#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
++#define IN6PTON_DOT 0x00800000 /* . */
++#define IN6PTON_DELIM 0x10000000
++#define IN6PTON_NULL 0x20000000 /* first/tail */
++#define IN6PTON_UNKNOWN 0x40000000
++
++static inline int digit2bin(char c, char delim)
++{
++ if (c == delim || c == '\0')
++ return IN6PTON_DELIM;
++ if (c == '.')
++ return IN6PTON_DOT;
++ if (c >= '0' && c <= '9')
++ return (IN6PTON_DIGIT | (c - '0'));
++ return IN6PTON_UNKNOWN;
++}
++
++static inline int xdigit2bin(char c, char delim)
++{
++ if (c == delim || c == '\0')
++ return IN6PTON_DELIM;
++ if (c == ':')
++ return IN6PTON_COLON_MASK;
++ if (c == '.')
++ return IN6PTON_DOT;
++ if (c >= '0' && c <= '9')
++ return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0'));
++ if (c >= 'a' && c <= 'f')
++ return (IN6PTON_XDIGIT | (c - 'a' + 10));
++ if (c >= 'A' && c <= 'F')
++ return (IN6PTON_XDIGIT | (c - 'A' + 10));
++ return IN6PTON_UNKNOWN;
++}
++
++int in4_pton(const char *src, int srclen,
++ u8 *dst,
++ char delim, const char **end)
++{
++ const char *s;
++ u8 *d;
++ u8 dbuf[4];
++ int ret = 0;
++ int i;
++ int w = 0;
++
++ if (srclen < 0)
++ srclen = strlen(src);
++ s = src;
++ d = dbuf;
++ i = 0;
++ while(1) {
++ int c;
++ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
++ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
++ goto out;
++ }
++ if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
++ if (w == 0)
++ goto out;
++ *d++ = w & 0xff;
++ w = 0;
++ i++;
++ if (c & IN6PTON_DELIM) {
++ if (i != 4)
++ goto out;
++ break;
++ }
++ goto cont;
++ }
++ w = (w * 10) + c;
++ if ((w & 0xffff) > 255) {
++ goto out;
++ }
++cont:
++ if (i >= 4)
++ goto out;
++ s++;
++ srclen--;
++ }
++ ret = 1;
++ memcpy(dst, dbuf, sizeof(dbuf));
++out:
++ if (end)
++ *end = s;
++ return ret;
++}
++
++EXPORT_SYMBOL(in4_pton);
++
++int in6_pton(const char *src, int srclen,
++ u8 *dst,
++ char delim, const char **end)
++{
++ const char *s, *tok = NULL;
++ u8 *d, *dc = NULL;
++ u8 dbuf[16];
++ int ret = 0;
++ int i;
++ int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
++ int w = 0;
++
++ memset(dbuf, 0, sizeof(dbuf));
++
++ s = src;
++ d = dbuf;
++ if (srclen < 0)
++ srclen = strlen(src);
++
++ while (1) {
++ int c;
++
++ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
++ if (!(c & state))
++ goto out;
++ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
++ /* process one 16-bit word */
++ if (!(state & IN6PTON_NULL)) {
++ *d++ = (w >> 8) & 0xff;
++ *d++ = w & 0xff;
++ }
++ w = 0;
++ if (c & IN6PTON_DELIM) {
++ /* We've processed last word */
++ break;
++ }
++ /*
++ * COLON_1 => XDIGIT
++ * COLON_2 => XDIGIT|DELIM
++ * COLON_1_2 => COLON_2
++ */
++ switch (state & IN6PTON_COLON_MASK) {
++ case IN6PTON_COLON_2:
++ dc = d;
++ state = IN6PTON_XDIGIT | IN6PTON_DELIM;
++ if (dc - dbuf >= sizeof(dbuf))
++ state |= IN6PTON_NULL;
++ break;
++ case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
++ state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
++ break;
++ case IN6PTON_COLON_1:
++ state = IN6PTON_XDIGIT;
++ break;
++ case IN6PTON_COLON_1_2:
++ state = IN6PTON_COLON_2;
++ break;
++ default:
++ state = 0;
++ }
++ tok = s + 1;
++ goto cont;
++ }
++
++ if (c & IN6PTON_DOT) {
++ ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
++ if (ret > 0) {
++ d += 4;
++ break;
++ }
++ goto out;
++ }
++
++ w = (w << 4) | (0xff & c);
++ state = IN6PTON_COLON_1 | IN6PTON_DELIM;
++ if (!(w & 0xf000)) {
++ state |= IN6PTON_XDIGIT;
++ }
++ if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
++ state |= IN6PTON_COLON_1_2;
++ state &= ~IN6PTON_DELIM;
++ }
++ if (d + 2 >= dbuf + sizeof(dbuf)) {
++ state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
++ }
++cont:
++ if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
++ d + 4 == dbuf + sizeof(dbuf)) {
++ state |= IN6PTON_DOT;
++ }
++ if (d >= dbuf + sizeof(dbuf)) {
++ state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
++ }
++ s++;
++ srclen--;
++ }
++
++ i = 15; d--;
++
++ if (dc) {
++ while(d >= dc)
++ dst[i--] = *d--;
++ while(i >= dc - dbuf)
++ dst[i--] = 0;
++ while(i >= 0)
++ dst[i--] = *d--;
++ } else
++ memcpy(dst, dbuf, sizeof(dbuf));
++
++ ret = 1;
++out:
++ if (end)
++ *end = s;
++ return ret;
++}
++
++EXPORT_SYMBOL(in6_pton);
+diff --git a/net/core/wireless.c b/net/core/wireless.c
+index de0bde4..cb1b872 100644
+--- a/net/core/wireless.c
++++ b/net/core/wireless.c
+@@ -68,11 +68,18 @@
+ *
+ * v8 - 17.02.06 - Jean II
+ * o RtNetlink requests support (SET/GET)
++ *
++ * v8b - 03.08.06 - Herbert Xu
++ * o Fix Wireless Event locking issues.
++ *
++ * v9 - 14.3.06 - Jean II
++ * o Change length in ESSID and NICK to strlen() instead of strlen()+1
++ * o Make standard_ioctl_num and standard_event_num unsigned
++ * o Remove (struct net_device *)->get_wireless_stats()
+ */
+
+ /***************************** INCLUDES *****************************/
+
+-#include <linux/config.h> /* Not needed ??? */
+ #include <linux/module.h>
+ #include <linux/types.h> /* off_t */
+ #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
+@@ -86,6 +93,7 @@
+
+ #include <linux/wireless.h> /* Pretty obvious */
+ #include <net/iw_handler.h> /* New driver API */
++#include <net/netlink.h>
+
+ #include <asm/uaccess.h> /* copy_to_user() */
+
+@@ -234,24 +242,24 @@ static const struct iw_ioctl_description
+ [SIOCSIWESSID - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+- .max_tokens = IW_ESSID_MAX_SIZE + 1,
++ .max_tokens = IW_ESSID_MAX_SIZE,
+ .flags = IW_DESCR_FLAG_EVENT,
+ },
+ [SIOCGIWESSID - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+- .max_tokens = IW_ESSID_MAX_SIZE + 1,
++ .max_tokens = IW_ESSID_MAX_SIZE,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWNICKN - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+- .max_tokens = IW_ESSID_MAX_SIZE + 1,
++ .max_tokens = IW_ESSID_MAX_SIZE,
+ },
+ [SIOCGIWNICKN - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+- .max_tokens = IW_ESSID_MAX_SIZE + 1,
++ .max_tokens = IW_ESSID_MAX_SIZE,
+ },
+ [SIOCSIWRATE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+@@ -338,8 +346,8 @@ static const struct iw_ioctl_description
+ .max_tokens = sizeof(struct iw_pmksa),
+ },
+ };
+-static const int standard_ioctl_num = (sizeof(standard_ioctl) /
+- sizeof(struct iw_ioctl_description));
++static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) /
++ sizeof(struct iw_ioctl_description));
+
+ /*
+ * Meta-data about all the additional standard Wireless Extension events
+@@ -389,8 +397,8 @@ static const struct iw_ioctl_description
+ .max_tokens = sizeof(struct iw_pmkid_cand),
+ },
+ };
+-static const int standard_event_num = (sizeof(standard_event) /
+- sizeof(struct iw_ioctl_description));
++static const unsigned standard_event_num = (sizeof(standard_event) /
++ sizeof(struct iw_ioctl_description));
+
+ /* Size (in bytes) of the various private data types */
+ static const char iw_priv_type_size[] = {
+@@ -465,17 +473,6 @@ static inline struct iw_statistics *get_
+ (dev->wireless_handlers->get_wireless_stats != NULL))
+ return dev->wireless_handlers->get_wireless_stats(dev);
+
+- /* Old location, field to be removed in next WE */
+- if(dev->get_wireless_stats) {
+- static int printed_message;
+-
+- if (!printed_message++)
+- printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n",
+- dev->name);
+-
+- return dev->get_wireless_stats(dev);
+- }
+-
+ /* Not found */
+ return (struct iw_statistics *) NULL;
+ }
+@@ -751,11 +748,39 @@ static int ioctl_standard_call(struct ne
+ int extra_size;
+ int user_length = 0;
+ int err;
++ int essid_compat = 0;
+
+ /* Calculate space needed by arguments. Always allocate
+ * for max space. Easier, and won't last long... */
+ extra_size = descr->max_tokens * descr->token_size;
+
++ /* Check need for ESSID compatibility for WE < 21 */
++ switch (cmd) {
++ case SIOCSIWESSID:
++ case SIOCGIWESSID:
++ case SIOCSIWNICKN:
++ case SIOCGIWNICKN:
++ if (iwr->u.data.length == descr->max_tokens + 1)
++ essid_compat = 1;
++ else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++ char essid[IW_ESSID_MAX_SIZE + 1];
++
++ err = copy_from_user(essid, iwr->u.data.pointer,
++ iwr->u.data.length *
++ descr->token_size);
++ if (err)
++ return -EFAULT;
++
++ if (essid[iwr->u.data.length - 1] == '\0')
++ essid_compat = 1;
++ }
++ break;
++ default:
++ break;
++ }
++
++ iwr->u.data.length -= essid_compat;
++
+ /* Check what user space is giving us */
+ if(IW_IS_SET(cmd)) {
+ /* Check NULL pointer */
+@@ -798,7 +823,8 @@ static int ioctl_standard_call(struct ne
+ #endif /* WE_IOCTL_DEBUG */
+
+ /* Create the kernel buffer */
+- extra = kmalloc(extra_size, GFP_KERNEL);
++ /* kzalloc ensures NULL-termination for essid_compat */
++ extra = kzalloc(extra_size, GFP_KERNEL);
+ if (extra == NULL) {
+ return -ENOMEM;
+ }
+@@ -822,6 +848,8 @@ static int ioctl_standard_call(struct ne
+ /* Call the handler */
+ ret = handler(dev, &info, &(iwr->u), extra);
+
++ iwr->u.data.length += essid_compat;
++
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
+ /* Check if there is enough buffer up there */
+@@ -1843,14 +1871,39 @@ int wireless_rtnetlink_set(struct net_de
+ */
+
+ #ifdef WE_EVENT_RTNETLINK
++/* ---------------------------------------------------------------- */
++/*
++ * Locking...
++ * ----------
++ *
++ * Thanks to Herbert Xu <herbert at gondor.apana.org.au> for fixing
++ * the locking issue in here and implementing this code !
++ *
++ * The issue : wireless_send_event() is often called in interrupt context,
++ * while the Netlink layer can never be called in interrupt context.
++ * The fully formed RtNetlink events are queued, and then a tasklet is run
++ * to feed those to Netlink.
++ * The skb_queue is interrupt safe, and its lock is not held while calling
++ * Netlink, so there is no possibility of dealock.
++ * Jean II
++ */
++
+ static struct sk_buff_head wireless_nlevent_queue;
+
++static int __init wireless_nlevent_init(void)
++{
++ skb_queue_head_init(&wireless_nlevent_queue);
++ return 0;
++}
++
++subsys_initcall(wireless_nlevent_init);
++
+ static void wireless_nlevent_process(unsigned long data)
+ {
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&wireless_nlevent_queue)))
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
++ rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+ }
+
+ static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
+@@ -1921,13 +1974,6 @@ static inline void rtmsg_iwinfo(struct n
+ tasklet_schedule(&wireless_nlevent_tasklet);
+ }
+
+-static int __init wireless_nlevent_init(void)
+-{
+- skb_queue_head_init(&wireless_nlevent_queue);
+- return 0;
+-}
+-
+-subsys_initcall(wireless_nlevent_init);
+ #endif /* WE_EVENT_RTNETLINK */
+
+ /* ---------------------------------------------------------------- */
+diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig
+index 859e335..ef8919c 100644
+--- a/net/dccp/Kconfig
++++ b/net/dccp/Kconfig
+@@ -4,15 +4,15 @@ menu "DCCP Configuration (EXPERIMENTAL)"
+ config IP_DCCP
+ tristate "The DCCP Protocol (EXPERIMENTAL)"
+ ---help---
+- Datagram Congestion Control Protocol
++ Datagram Congestion Control Protocol (RFC 4340)
+
+- From draft-ietf-dccp-spec-11 <http://www.icir.org/kohler/dcp/draft-ietf-dccp-spec-11.txt>.
++ From http://www.ietf.org/rfc/rfc4340.txt:
+
+ The Datagram Congestion Control Protocol (DCCP) is a transport
+ protocol that implements bidirectional, unicast connections of
+ congestion-controlled, unreliable datagrams. It should be suitable
+ for use by applications such as streaming media, Internet telephony,
+- and on-line games
++ and on-line games.
+
+ To compile this protocol support as a module, choose M here: the
+ module will be called dccp.
+@@ -40,6 +40,22 @@ config IP_DCCP_DEBUG
+
+ Just say N.
+
++config NET_DCCPPROBE
++ tristate "DCCP connection probing"
++ depends on PROC_FS && KPROBES
++ ---help---
++ This module allows for capturing the changes to DCCP connection
++ state in response to incoming packets. It is used for debugging
++ DCCP congestion avoidance modules. If you don't understand
++ what was just said, you don't need it: say N.
++
++ Documentation on how to use the packet generator can be found
++ at http://linux-net.osdl.org/index.php/DccpProbe
++
++ To compile this code as a module, choose M here: the
++ module will be called dccp_probe.
++
++
+ endmenu
+
+ endmenu
+diff --git a/net/dccp/Makefile b/net/dccp/Makefile
+index 7696e21..17ed99c 100644
+--- a/net/dccp/Makefile
++++ b/net/dccp/Makefile
+@@ -11,9 +11,11 @@ dccp_ipv4-y := ipv4.o
+ dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
+
+ obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
++obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
+
+ dccp-$(CONFIG_SYSCTL) += sysctl.o
+
+ dccp_diag-y := diag.o
++dccp_probe-y := probe.o
+
+ obj-y += ccids/
+diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
+index 8c211c5..f820887 100644
+--- a/net/dccp/ackvec.c
++++ b/net/dccp/ackvec.c
+@@ -113,7 +113,7 @@ int dccp_insert_option_ackvec(struct soc
+
+ memcpy(to, from, len);
+ /*
+- * From draft-ietf-dccp-spec-11.txt:
++ * From RFC 4340, A.2:
+ *
+ * For each acknowledgement it sends, the HC-Receiver will add an
+ * acknowledgement record. ack_seqno will equal the HC-Receiver
+@@ -142,14 +142,13 @@ struct dccp_ackvec *dccp_ackvec_alloc(co
+ struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
+
+ if (av != NULL) {
+- av->dccpav_buf_head =
+- av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
++ av->dccpav_buf_head = DCCP_MAX_ACKVEC_LEN - 1;
+ av->dccpav_buf_ackno = DCCP_MAX_SEQNO + 1;
+ av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
+ av->dccpav_ack_ptr = 0;
+ av->dccpav_time.tv_sec = 0;
+ av->dccpav_time.tv_usec = 0;
+- av->dccpav_sent_len = av->dccpav_vec_len = 0;
++ av->dccpav_vec_len = 0;
+ INIT_LIST_HEAD(&av->dccpav_records);
+ }
+
+@@ -225,7 +224,7 @@ static inline int dccp_ackvec_set_buf_he
+ }
+
+ /*
+- * Implements the draft-ietf-dccp-spec-11.txt Appendix A
++ * Implements the RFC 4340, Appendix A
+ */
+ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
+ const u64 ackno, const u8 state)
+@@ -238,7 +237,7 @@ int dccp_ackvec_add(struct dccp_ackvec *
+ * We may well decide to do buffer compression, etc, but for now lets
+ * just drop.
+ *
+- * From Appendix A:
++ * From Appendix A.1.1 (`New Packets'):
+ *
+ * Of course, the circular buffer may overflow, either when the
+ * HC-Sender is sending data at a very high rate, when the
+@@ -275,9 +274,9 @@ int dccp_ackvec_add(struct dccp_ackvec *
+ /*
+ * A.1.2. Old Packets
+ *
+- * When a packet with Sequence Number S arrives, and
+- * S <= buf_ackno, the HC-Receiver will scan the table
+- * for the byte corresponding to S. (Indexing structures
++ * When a packet with Sequence Number S <= buf_ackno
++ * arrives, the HC-Receiver will scan the table for
++ * the byte corresponding to S. (Indexing structures
+ * could reduce the complexity of this scan.)
+ */
+ u64 delta = dccp_delta_seqno(ackno, av->dccpav_buf_ackno);
+@@ -353,11 +352,13 @@ static void dccp_ackvec_throw_record(str
+ {
+ struct dccp_ackvec_record *next;
+
+- av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1;
+- if (av->dccpav_buf_tail == 0)
+- av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+-
+- av->dccpav_vec_len -= avr->dccpavr_sent_len;
++ /* sort out vector length */
++ if (av->dccpav_buf_head <= avr->dccpavr_ack_ptr)
++ av->dccpav_vec_len = avr->dccpavr_ack_ptr - av->dccpav_buf_head;
++ else
++ av->dccpav_vec_len = DCCP_MAX_ACKVEC_LEN - 1
++ - av->dccpav_buf_head
++ + avr->dccpavr_ack_ptr;
+
+ /* free records */
+ list_for_each_entry_safe_from(avr, next, &av->dccpav_records,
+@@ -434,8 +435,7 @@ static void dccp_ackvec_check_rcv_ackvec
+ break;
+ found:
+ if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) {
+- const u8 state = (*vector &
+- DCCP_ACKVEC_STATE_MASK) >> 6;
++ const u8 state = *vector & DCCP_ACKVEC_STATE_MASK;
+ if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) {
+ #ifdef CONFIG_IP_DCCP_DEBUG
+ struct dccp_sock *dp = dccp_sk(sk);
+diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
+index 0adf4b5..cf8f20c 100644
+--- a/net/dccp/ackvec.h
++++ b/net/dccp/ackvec.h
+@@ -28,8 +28,7 @@
+
+ /** struct dccp_ackvec - ack vector
+ *
+- * This data structure is the one defined in the DCCP draft
+- * Appendix A.
++ * This data structure is the one defined in RFC 4340, Appendix A.
+ *
+ * @dccpav_buf_head - circular buffer head
+ * @dccpav_buf_tail - circular buffer tail
+@@ -54,9 +53,7 @@ struct dccp_ackvec {
+ struct list_head dccpav_records;
+ struct timeval dccpav_time;
+ u8 dccpav_buf_head;
+- u8 dccpav_buf_tail;
+ u8 dccpav_ack_ptr;
+- u8 dccpav_sent_len;
+ u8 dccpav_vec_len;
+ u8 dccpav_buf_nonce;
+ u8 dccpav_ack_nonce;
+@@ -107,7 +104,7 @@ extern int dccp_insert_option_ackvec(str
+
+ static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
+ {
+- return av->dccpav_sent_len != av->dccpav_vec_len;
++ return av->dccpav_vec_len;
+ }
+ #else /* CONFIG_IP_DCCP_ACKVEC */
+ static inline int dccp_ackvec_init(void)
+diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig
+index ca00191..8533dab 100644
+--- a/net/dccp/ccids/Kconfig
++++ b/net/dccp/ccids/Kconfig
+@@ -22,14 +22,22 @@ config IP_DCCP_CCID2
+ for lost packets, would prefer CCID 2 to CCID 3. On-line games may
+ also prefer CCID 2.
+
+- CCID 2 is further described in:
+- http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid2-10.txt
++ CCID 2 is further described in RFC 4341,
++ http://www.ietf.org/rfc/rfc4341.txt
+
+- This text was extracted from:
+- http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
++ This text was extracted from RFC 4340 (sec. 10.1),
++ http://www.ietf.org/rfc/rfc4340.txt
+
+ If in doubt, say M.
+
++config IP_DCCP_CCID2_DEBUG
++ bool "CCID2 debug"
++ depends on IP_DCCP_CCID2
++ ---help---
++ Enable CCID2 debug messages.
++
++ If in doubt, say N.
++
+ config IP_DCCP_CCID3
+ tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)"
+ depends on IP_DCCP
+@@ -45,15 +53,14 @@ config IP_DCCP_CCID3
+ suitable than CCID 2 for applications such streaming media where a
+ relatively smooth sending rate is of importance.
+
+- CCID 3 is further described in:
+-
+- http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid3-11.txt.
++ CCID 3 is further described in RFC 4342,
++ http://www.ietf.org/rfc/rfc4342.txt
+
+ The TFRC congestion control algorithms were initially described in
+ RFC 3448.
+
+- This text was extracted from:
+- http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
++ This text was extracted from RFC 4340 (sec. 10.2),
++ http://www.ietf.org/rfc/rfc4340.txt
+
+ If in doubt, say M.
+
+diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
+index e961562..162032b 100644
+--- a/net/dccp/ccids/ccid2.c
++++ b/net/dccp/ccids/ccid2.c
+@@ -23,11 +23,10 @@
+ */
+
+ /*
+- * This implementation should follow: draft-ietf-dccp-ccid2-10.txt
++ * This implementation should follow RFC 4341
+ *
+ * BUGS:
+ * - sequence number wrapping
+- * - jiffies wrapping
+ */
+
+ #include "../ccid.h"
+@@ -36,8 +35,7 @@
+
+ static int ccid2_debug;
+
+-#undef CCID2_DEBUG
+-#ifdef CCID2_DEBUG
++#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
+ #define ccid2_pr_debug(format, a...) \
+ do { if (ccid2_debug) \
+ printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
+@@ -46,9 +44,7 @@ static int ccid2_debug;
+ #define ccid2_pr_debug(format, a...)
+ #endif
+
+-static const int ccid2_seq_len = 128;
+-
+-#ifdef CCID2_DEBUG
++#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
+ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
+ {
+ int len = 0;
+@@ -71,8 +67,8 @@ static void ccid2_hc_tx_check_sanity(con
+
+ /* packets are sent sequentially */
+ BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq);
+- BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent);
+- BUG_ON(len > ccid2_seq_len);
++ BUG_ON(time_before(seqp->ccid2s_sent,
++ prev->ccid2s_sent));
+
+ seqp = prev;
+ }
+@@ -84,16 +80,57 @@ static void ccid2_hc_tx_check_sanity(con
+ do {
+ seqp = seqp->ccid2s_prev;
+ len++;
+- BUG_ON(len > ccid2_seq_len);
+ } while (seqp != hctx->ccid2hctx_seqh);
+
+- BUG_ON(len != ccid2_seq_len);
+ ccid2_pr_debug("total len=%d\n", len);
++ BUG_ON(len != hctx->ccid2hctx_seqbufc * CCID2_SEQBUF_LEN);
+ }
+ #else
+ #define ccid2_hc_tx_check_sanity(hctx) do {} while (0)
+ #endif
+
++static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx, int num,
++ gfp_t gfp)
++{
++ struct ccid2_seq *seqp;
++ int i;
++
++ /* check if we have space to preserve the pointer to the buffer */
++ if (hctx->ccid2hctx_seqbufc >= (sizeof(hctx->ccid2hctx_seqbuf) /
++ sizeof(struct ccid2_seq*)))
++ return -ENOMEM;
++
++ /* allocate buffer and initialize linked list */
++ seqp = kmalloc(sizeof(*seqp) * num, gfp);
++ if (seqp == NULL)
++ return -ENOMEM;
++
++ for (i = 0; i < (num - 1); i++) {
++ seqp[i].ccid2s_next = &seqp[i + 1];
++ seqp[i + 1].ccid2s_prev = &seqp[i];
++ }
++ seqp[num - 1].ccid2s_next = seqp;
++ seqp->ccid2s_prev = &seqp[num - 1];
++
++ /* This is the first allocation. Initiate the head and tail. */
++ if (hctx->ccid2hctx_seqbufc == 0)
++ hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqt = seqp;
++ else {
++ /* link the existing list with the one we just created */
++ hctx->ccid2hctx_seqh->ccid2s_next = seqp;
++ seqp->ccid2s_prev = hctx->ccid2hctx_seqh;
++
++ hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[num - 1];
++ seqp[num - 1].ccid2s_next = hctx->ccid2hctx_seqt;
++ }
++
++ /* store the original pointer to the buffer so we can free it */
++ hctx->ccid2hctx_seqbuf[hctx->ccid2hctx_seqbufc] = seqp;
++ hctx->ccid2hctx_seqbufc++;
++
++ return 0;
++}
++
+ static int ccid2_hc_tx_send_packet(struct sock *sk,
+ struct sk_buff *skb, int len)
+ {
+@@ -122,7 +159,7 @@ static int ccid2_hc_tx_send_packet(struc
+ }
+ }
+
+- return 100; /* XXX */
++ return 1; /* XXX CCID should dequeue when ready instead of polling */
+ }
+
+ static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
+@@ -150,10 +187,8 @@ static void ccid2_change_l_ack_ratio(str
+ dp->dccps_l_ack_ratio = val;
+ }
+
+-static void ccid2_change_cwnd(struct sock *sk, int val)
++static void ccid2_change_cwnd(struct ccid2_hc_tx_sock *hctx, int val)
+ {
+- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+-
+ if (val == 0)
+ val = 1;
+
+@@ -164,6 +199,17 @@ static void ccid2_change_cwnd(struct soc
+ hctx->ccid2hctx_cwnd = val;
+ }
+
++static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hctx, long val)
++{
++ ccid2_pr_debug("change SRTT to %ld\n", val);
++ hctx->ccid2hctx_srtt = val;
++}
++
++static void ccid2_change_pipe(struct ccid2_hc_tx_sock *hctx, long val)
++{
++ hctx->ccid2hctx_pipe = val;
++}
++
+ static void ccid2_start_rto_timer(struct sock *sk);
+
+ static void ccid2_hc_tx_rto_expire(unsigned long data)
+@@ -193,11 +239,11 @@ static void ccid2_hc_tx_rto_expire(unsig
+ ccid2_start_rto_timer(sk);
+
+ /* adjust pipe, cwnd etc */
+- hctx->ccid2hctx_pipe = 0;
++ ccid2_change_pipe(hctx, 0);
+ hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1;
+ if (hctx->ccid2hctx_ssthresh < 2)
+ hctx->ccid2hctx_ssthresh = 2;
+- ccid2_change_cwnd(sk, 1);
++ ccid2_change_cwnd(hctx, 1);
+
+ /* clear state about stuff we sent */
+ hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh;
+@@ -232,13 +278,14 @@ static void ccid2_hc_tx_packet_sent(stru
+ {
+ struct dccp_sock *dp = dccp_sk(sk);
+ struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
++ struct ccid2_seq *next;
+ u64 seq;
+
+ ccid2_hc_tx_check_sanity(hctx);
+
+ BUG_ON(!hctx->ccid2hctx_sendwait);
+ hctx->ccid2hctx_sendwait = 0;
+- hctx->ccid2hctx_pipe++;
++ ccid2_change_pipe(hctx, hctx->ccid2hctx_pipe + 1);
+ BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+ /* There is an issue. What if another packet is sent between
+@@ -251,15 +298,23 @@ static void ccid2_hc_tx_packet_sent(stru
+ hctx->ccid2hctx_seqh->ccid2s_seq = seq;
+ hctx->ccid2hctx_seqh->ccid2s_acked = 0;
+ hctx->ccid2hctx_seqh->ccid2s_sent = jiffies;
+- hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next;
+
+- ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
+- hctx->ccid2hctx_pipe);
++ next = hctx->ccid2hctx_seqh->ccid2s_next;
++ /* check if we need to alloc more space */
++ if (next == hctx->ccid2hctx_seqt) {
++ int rc;
++
++ ccid2_pr_debug("allocating more space in history\n");
++ rc = ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_KERNEL);
++ BUG_ON(rc); /* XXX what do we do? */
+
+- if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) {
+- /* XXX allocate more space */
+- WARN_ON(1);
++ next = hctx->ccid2hctx_seqh->ccid2s_next;
++ BUG_ON(next == hctx->ccid2hctx_seqt);
+ }
++ hctx->ccid2hctx_seqh = next;
++
++ ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
++ hctx->ccid2hctx_pipe);
+
+ hctx->ccid2hctx_sent++;
+
+@@ -295,16 +350,16 @@ static void ccid2_hc_tx_packet_sent(stru
+ if (!timer_pending(&hctx->ccid2hctx_rtotimer))
+ ccid2_start_rto_timer(sk);
+
+-#ifdef CCID2_DEBUG
++#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
+ ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe);
+- ccid2_pr_debug("Sent: seq=%llu\n", seq);
++ ccid2_pr_debug("Sent: seq=%llu\n", (unsigned long long)seq);
+ do {
+ struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+
+ while (seqp != hctx->ccid2hctx_seqh) {
+ ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+- seqp->ccid2s_seq, seqp->ccid2s_acked,
+- seqp->ccid2s_sent);
++ (unsigned long long)seqp->ccid2s_seq,
++ seqp->ccid2s_acked, seqp->ccid2s_sent);
+ seqp = seqp->ccid2s_next;
+ }
+ } while (0);
+@@ -398,7 +453,7 @@ static inline void ccid2_new_ack(struct
+ /* increase every 2 acks */
+ hctx->ccid2hctx_ssacks++;
+ if (hctx->ccid2hctx_ssacks == 2) {
+- ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
++ ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd+1);
+ hctx->ccid2hctx_ssacks = 0;
+ *maxincr = *maxincr - 1;
+ }
+@@ -411,26 +466,29 @@ static inline void ccid2_new_ack(struct
+ hctx->ccid2hctx_acks++;
+
+ if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) {
+- ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
++ ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd + 1);
+ hctx->ccid2hctx_acks = 0;
+ }
+ }
+
+ /* update RTO */
+ if (hctx->ccid2hctx_srtt == -1 ||
+- (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) {
+- unsigned long r = jiffies - seqp->ccid2s_sent;
++ time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) {
++ unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent;
+ int s;
+
+ /* first measurement */
+ if (hctx->ccid2hctx_srtt == -1) {
+ ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
+- r, jiffies, seqp->ccid2s_seq);
+- hctx->ccid2hctx_srtt = r;
++ r, jiffies,
++ (unsigned long long)seqp->ccid2s_seq);
++ ccid2_change_srtt(hctx, r);
+ hctx->ccid2hctx_rttvar = r >> 1;
+ } else {
+ /* RTTVAR */
+ long tmp = hctx->ccid2hctx_srtt - r;
++ long srtt;
++
+ if (tmp < 0)
+ tmp *= -1;
+
+@@ -440,10 +498,12 @@ static inline void ccid2_new_ack(struct
+ hctx->ccid2hctx_rttvar += tmp;
+
+ /* SRTT */
+- hctx->ccid2hctx_srtt *= 7;
+- hctx->ccid2hctx_srtt >>= 3;
++ srtt = hctx->ccid2hctx_srtt;
++ srtt *= 7;
++ srtt >>= 3;
+ tmp = r >> 3;
+- hctx->ccid2hctx_srtt += tmp;
++ srtt += tmp;
++ ccid2_change_srtt(hctx, srtt);
+ }
+ s = hctx->ccid2hctx_rttvar << 2;
+ /* clock granularity is 1 when based on jiffies */
+@@ -479,13 +539,29 @@ static void ccid2_hc_tx_dec_pipe(struct
+ {
+ struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+- hctx->ccid2hctx_pipe--;
++ ccid2_change_pipe(hctx, hctx->ccid2hctx_pipe-1);
+ BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+ if (hctx->ccid2hctx_pipe == 0)
+ ccid2_hc_tx_kill_rto_timer(sk);
+ }
+
++static void ccid2_congestion_event(struct ccid2_hc_tx_sock *hctx,
++ struct ccid2_seq *seqp)
++{
++ if (time_before(seqp->ccid2s_sent, hctx->ccid2hctx_last_cong)) {
++ ccid2_pr_debug("Multiple losses in an RTT---treating as one\n");
++ return;
++ }
++
++ hctx->ccid2hctx_last_cong = jiffies;
++
++ ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd >> 1);
++ hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
++ if (hctx->ccid2hctx_ssthresh < 2)
++ hctx->ccid2hctx_ssthresh = 2;
++}
++
+ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
+ {
+ struct dccp_sock *dp = dccp_sk(sk);
+@@ -496,7 +572,6 @@ static void ccid2_hc_tx_packet_recv(stru
+ unsigned char veclen;
+ int offset = 0;
+ int done = 0;
+- int loss = 0;
+ unsigned int maxincr = 0;
+
+ ccid2_hc_tx_check_sanity(hctx);
+@@ -562,8 +637,9 @@ static void ccid2_hc_tx_packet_recv(stru
+ u64 ackno_end_rl;
+
+ dccp_set_seqno(&ackno_end_rl, ackno - rl);
+- ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno,
+- ackno_end_rl);
++ ccid2_pr_debug("ackvec start:%llu end:%llu\n",
++ (unsigned long long)ackno,
++ (unsigned long long)ackno_end_rl);
+ /* if the seqno we are analyzing is larger than the
+ * current ackno, then move towards the tail of our
+ * seqnos.
+@@ -582,22 +658,23 @@ static void ccid2_hc_tx_packet_recv(stru
+ * run length
+ */
+ while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
+- const u8 state = (*vector &
+- DCCP_ACKVEC_STATE_MASK) >> 6;
++ const u8 state = *vector &
++ DCCP_ACKVEC_STATE_MASK;
+
+ /* new packet received or marked */
+ if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+ !seqp->ccid2s_acked) {
+ if (state ==
+ DCCP_ACKVEC_STATE_ECN_MARKED) {
+- loss = 1;
++ ccid2_congestion_event(hctx,
++ seqp);
+ } else
+ ccid2_new_ack(sk, seqp,
+ &maxincr);
+
+ seqp->ccid2s_acked = 1;
+ ccid2_pr_debug("Got ack for %llu\n",
+- seqp->ccid2s_seq);
++ (unsigned long long)seqp->ccid2s_seq);
+ ccid2_hc_tx_dec_pipe(sk);
+ }
+ if (seqp == hctx->ccid2hctx_seqt) {
+@@ -642,7 +719,13 @@ static void ccid2_hc_tx_packet_recv(stru
+ /* check for lost packets */
+ while (1) {
+ if (!seqp->ccid2s_acked) {
+- loss = 1;
++ ccid2_pr_debug("Packet lost: %llu\n",
++ (unsigned long long)seqp->ccid2s_seq);
++ /* XXX need to traverse from tail -> head in
++ * order to detect multiple congestion events in
++ * one ack vector.
++ */
++ ccid2_congestion_event(hctx, seqp);
+ ccid2_hc_tx_dec_pipe(sk);
+ }
+ if (seqp == hctx->ccid2hctx_seqt)
+@@ -661,53 +744,33 @@ static void ccid2_hc_tx_packet_recv(stru
+ hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+ }
+
+- if (loss) {
+- /* XXX do bit shifts guarantee a 0 as the new bit? */
+- ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1);
+- hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
+- if (hctx->ccid2hctx_ssthresh < 2)
+- hctx->ccid2hctx_ssthresh = 2;
+- }
+-
+ ccid2_hc_tx_check_sanity(hctx);
+ }
+
+ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
+ {
+ struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid);
+- int seqcount = ccid2_seq_len;
+- int i;
+
+- /* XXX init variables with proper values */
+- hctx->ccid2hctx_cwnd = 1;
+- hctx->ccid2hctx_ssthresh = 10;
++ ccid2_change_cwnd(hctx, 1);
++ /* Initialize ssthresh to infinity. This means that we will exit the
++ * initial slow-start after the first packet loss. This is what we
++ * want.
++ */
++ hctx->ccid2hctx_ssthresh = ~0;
+ hctx->ccid2hctx_numdupack = 3;
++ hctx->ccid2hctx_seqbufc = 0;
+
+ /* XXX init ~ to window size... */
+- hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) *
+- seqcount, gfp_any());
+- if (hctx->ccid2hctx_seqbuf == NULL)
++ if (ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_ATOMIC) != 0)
+ return -ENOMEM;
+
+- for (i = 0; i < (seqcount - 1); i++) {
+- hctx->ccid2hctx_seqbuf[i].ccid2s_next =
+- &hctx->ccid2hctx_seqbuf[i + 1];
+- hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev =
+- &hctx->ccid2hctx_seqbuf[i];
+- }
+- hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next =
+- hctx->ccid2hctx_seqbuf;
+- hctx->ccid2hctx_seqbuf->ccid2s_prev =
+- &hctx->ccid2hctx_seqbuf[seqcount - 1];
+-
+- hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqbuf;
+- hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh;
+ hctx->ccid2hctx_sent = 0;
+ hctx->ccid2hctx_rto = 3 * HZ;
+- hctx->ccid2hctx_srtt = -1;
++ ccid2_change_srtt(hctx, -1);
+ hctx->ccid2hctx_rttvar = -1;
+ hctx->ccid2hctx_lastrtt = 0;
+ hctx->ccid2hctx_rpdupack = -1;
++ hctx->ccid2hctx_last_cong = jiffies;
+
+ hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire;
+ hctx->ccid2hctx_rtotimer.data = (unsigned long)sk;
+@@ -720,10 +783,13 @@ static int ccid2_hc_tx_init(struct ccid
+ static void ccid2_hc_tx_exit(struct sock *sk)
+ {
+ struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
++ int i;
+
+ ccid2_hc_tx_kill_rto_timer(sk);
+- kfree(hctx->ccid2hctx_seqbuf);
+- hctx->ccid2hctx_seqbuf = NULL;
++
++ for (i = 0; i < hctx->ccid2hctx_seqbufc; i++)
++ kfree(hctx->ccid2hctx_seqbuf[i]);
++ hctx->ccid2hctx_seqbufc = 0;
+ }
+
+ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
+@@ -744,7 +810,7 @@ static void ccid2_hc_rx_packet_recv(stru
+ }
+
+ static struct ccid_operations ccid2 = {
+- .ccid_id = 2,
++ .ccid_id = DCCPC_CCID2,
+ .ccid_name = "ccid2",
+ .ccid_owner = THIS_MODULE,
+ .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock),
+diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
+index 451a874..5b2ef4a 100644
+--- a/net/dccp/ccids/ccid2.h
++++ b/net/dccp/ccids/ccid2.h
+@@ -35,6 +35,9 @@ struct ccid2_seq {
+ struct ccid2_seq *ccid2s_next;
+ };
+
++#define CCID2_SEQBUF_LEN 256
++#define CCID2_SEQBUF_MAX 128
++
+ /** struct ccid2_hc_tx_sock - CCID2 TX half connection
+ *
+ * @ccid2hctx_ssacks - ACKs recv in slow start
+@@ -50,10 +53,11 @@ struct ccid2_hc_tx_sock {
+ int ccid2hctx_cwnd;
+ int ccid2hctx_ssacks;
+ int ccid2hctx_acks;
+- int ccid2hctx_ssthresh;
++ unsigned int ccid2hctx_ssthresh;
+ int ccid2hctx_pipe;
+ int ccid2hctx_numdupack;
+- struct ccid2_seq *ccid2hctx_seqbuf;
++ struct ccid2_seq *ccid2hctx_seqbuf[CCID2_SEQBUF_MAX];
++ int ccid2hctx_seqbufc;
+ struct ccid2_seq *ccid2hctx_seqh;
+ struct ccid2_seq *ccid2hctx_seqt;
+ long ccid2hctx_rto;
+@@ -67,6 +71,7 @@ struct ccid2_hc_tx_sock {
+ u64 ccid2hctx_rpseq;
+ int ccid2hctx_rpdupack;
+ int ccid2hctx_sendwait;
++ unsigned long ccid2hctx_last_cong;
+ };
+
+ struct ccid2_hc_rx_sock {
+diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
+index 090bc39..cec23ad 100644
+--- a/net/dccp/ccids/ccid3.c
++++ b/net/dccp/ccids/ccid3.c
+@@ -379,8 +379,7 @@ static void ccid3_hc_tx_packet_sent(stru
+ packet->dccphtx_seqno = dp->dccps_gss;
+ /*
+ * Check if win_count have changed
+- * Algorithm in "8.1. Window Counter Valuer" in
+- * draft-ietf-dccp-ccid3-11.txt
++ * Algorithm in "8.1. Window Counter Value" in RFC 4342.
+ */
+ quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count);
+ if (likely(hctx->ccid3hctx_rtt > 8))
+@@ -900,7 +899,7 @@ found:
+ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
+ {
+ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+- struct dccp_li_hist_entry *next, *head;
++ struct dccp_li_hist_entry *head;
+ u64 seq_temp;
+
+ if (list_empty(&hcrx->ccid3hcrx_li_hist)) {
+@@ -908,15 +907,15 @@ static void ccid3_hc_rx_update_li(struct
+ &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss))
+ return;
+
+- next = (struct dccp_li_hist_entry *)
+- hcrx->ccid3hcrx_li_hist.next;
+- next->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
++ head = list_entry(hcrx->ccid3hcrx_li_hist.next,
++ struct dccp_li_hist_entry, dccplih_node);
++ head->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
+ } else {
+ struct dccp_li_hist_entry *entry;
+ struct list_head *tail;
+
+- head = (struct dccp_li_hist_entry *)
+- hcrx->ccid3hcrx_li_hist.next;
++ head = list_entry(hcrx->ccid3hcrx_li_hist.next,
++ struct dccp_li_hist_entry, dccplih_node);
+ /* FIXME win count check removed as was wrong */
+ /* should make this check with receive history */
+ /* and compare there as per section 10.2 of RFC4342 */
+@@ -1240,7 +1239,7 @@ static int ccid3_hc_tx_getsockopt(struct
+ }
+
+ static struct ccid_operations ccid3 = {
+- .ccid_id = 3,
++ .ccid_id = DCCPC_CCID3,
+ .ccid_name = "ccid3",
+ .ccid_owner = THIS_MODULE,
+ .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock),
+diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
+index a5c5475..272e858 100644
+--- a/net/dccp/dccp.h
++++ b/net/dccp/dccp.h
+@@ -50,7 +50,7 @@ extern void dccp_time_wait(struct sock *
+ #define DCCP_TIMEWAIT_LEN (60 * HZ) /* how long to wait to destroy TIME-WAIT
+ * state, about 60 seconds */
+
+-/* draft-ietf-dccp-spec-11.txt initial RTO value */
++/* RFC 1122, 4.2.3.1 initial RTO value */
+ #define DCCP_TIMEOUT_INIT ((unsigned)(3 * HZ))
+
+ /* Maximal interval between probes for local resources. */
+@@ -130,7 +130,7 @@ extern void dccp_send_delayed_ack(struct
+ extern void dccp_send_sync(struct sock *sk, const u64 seq,
+ const enum dccp_pkt_type pkt_type);
+
+-extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo);
++extern void dccp_write_xmit(struct sock *sk, int block);
+ extern void dccp_write_space(struct sock *sk);
+
+ extern void dccp_init_xmit_timers(struct sock *sk);
+diff --git a/net/dccp/feat.h b/net/dccp/feat.h
+index b44c455..cee553d 100644
+--- a/net/dccp/feat.h
++++ b/net/dccp/feat.h
+@@ -27,5 +27,10 @@ extern int dccp_feat_clone(struct sock
+ extern int dccp_feat_init(struct dccp_minisock *dmsk);
+
+ extern int dccp_feat_default_sequence_window;
++extern int dccp_feat_default_rx_ccid;
++extern int dccp_feat_default_tx_ccid;
++extern int dccp_feat_default_ack_ratio;
++extern int dccp_feat_default_send_ack_vector;
++extern int dccp_feat_default_send_ndp_count;
+
+ #endif /* _DCCP_FEAT_H */
+diff --git a/net/dccp/input.c b/net/dccp/input.c
+index 7f9dc6a..1d24881 100644
+--- a/net/dccp/input.c
++++ b/net/dccp/input.c
+@@ -216,11 +216,11 @@ send_sync:
+ dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
+ DCCP_PKT_SYNCACK);
+ /*
+- * From the draft:
++ * From RFC 4340, sec. 5.7
+ *
+ * As with DCCP-Ack packets, DCCP-Sync and DCCP-SyncAck packets
+ * MAY have non-zero-length application data areas, whose
+- * contents * receivers MUST ignore.
++ * contents receivers MUST ignore.
+ */
+ goto discard;
+ }
+diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
+index 7f56f7e..e08e768 100644
+--- a/net/dccp/ipv4.c
++++ b/net/dccp/ipv4.c
+@@ -50,15 +50,12 @@ int dccp_v4_connect(struct sock *sk, str
+ struct dccp_sock *dp = dccp_sk(sk);
+ const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
+ struct rtable *rt;
+- u32 daddr, nexthop;
++ __be32 daddr, nexthop;
+ int tmp;
+ int err;
+
+ dp->dccps_role = DCCP_ROLE_CLIENT;
+
+- if (dccp_service_not_initialized(sk))
+- return -EPROTO;
+-
+ if (addr_len < sizeof(struct sockaddr_in))
+ return -EINVAL;
+
+@@ -186,7 +183,7 @@ static inline void dccp_do_pmtu_discover
+ dccp_sync_mss(sk, mtu);
+
+ /*
+- * From: draft-ietf-dccp-spec-11.txt
++ * From RFC 4340, sec. 14.1:
+ *
+ * DCCP-Sync packets are the best choice for upward
+ * probing, since DCCP-Sync probes do not risk application
+@@ -314,7 +311,7 @@ static void dccp_v4_err(struct sk_buff *
+ }
+
+ if (sk->sk_state == DCCP_TIME_WAIT) {
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ return;
+ }
+
+@@ -452,6 +449,8 @@ static inline u64 dccp_v4_init_sequence(
+ dccp_hdr(skb)->dccph_sport);
+ }
+
++static struct request_sock_ops dccp_request_sock_ops;
++
+ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
+ {
+ struct inet_request_sock *ireq;
+@@ -492,7 +491,7 @@ int dccp_v4_conn_request(struct sock *sk
+ if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
+ goto drop;
+
+- req = reqsk_alloc(sk->sk_prot->rsk_prot);
++ req = reqsk_alloc(&dccp_request_sock_ops);
+ if (req == NULL)
+ goto drop;
+
+@@ -501,6 +500,9 @@ int dccp_v4_conn_request(struct sock *sk
+
+ dccp_openreq_init(req, &dp, skb);
+
++ if (security_inet_conn_request(sk, skb, req))
++ goto drop_and_free;
++
+ ireq = inet_rsk(req);
+ ireq->loc_addr = daddr;
+ ireq->rmt_addr = saddr;
+@@ -605,16 +607,16 @@ static struct sock *dccp_v4_hnd_req(stru
+ if (req != NULL)
+ return dccp_check_req(sk, skb, req, prev);
+
+- nsk = __inet_lookup_established(&dccp_hashinfo,
+- iph->saddr, dh->dccph_sport,
+- iph->daddr, ntohs(dh->dccph_dport),
+- inet_iif(skb));
++ nsk = inet_lookup_established(&dccp_hashinfo,
++ iph->saddr, dh->dccph_sport,
++ iph->daddr, dh->dccph_dport,
++ inet_iif(skb));
+ if (nsk != NULL) {
+ if (nsk->sk_state != DCCP_TIME_WAIT) {
+ bh_lock_sock(nsk);
+ return nsk;
+ }
+- inet_twsk_put((struct inet_timewait_sock *)nsk);
++ inet_twsk_put(inet_twsk(nsk));
+ return NULL;
+ }
+
+@@ -678,6 +680,7 @@ static struct dst_entry* dccp_v4_route_s
+ }
+ };
+
++ security_skb_classify_flow(skb, &fl);
+ if (ip_route_output_flow(&rt, &fl, sk, 0)) {
+ IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+ return NULL;
+@@ -730,7 +733,7 @@ static void dccp_v4_ctl_send_reset(struc
+ dccp_hdr_reset(skb)->dccph_reset_code =
+ DCCP_SKB_CB(rxskb)->dccpd_reset_code;
+
+- /* See "8.3.1. Abnormal Termination" in draft-ietf-dccp-spec-11 */
++ /* See "8.3.1. Abnormal Termination" in RFC 4340 */
+ seqno = 0;
+ if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+ dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
+@@ -921,7 +924,7 @@ static int dccp_v4_rcv(struct sk_buff *s
+ * Look up flow ID in table and get corresponding socket */
+ sk = __inet_lookup(&dccp_hashinfo,
+ skb->nh.iph->saddr, dh->dccph_sport,
+- skb->nh.iph->daddr, ntohs(dh->dccph_dport),
++ skb->nh.iph->daddr, dh->dccph_dport,
+ inet_iif(skb));
+
+ /*
+@@ -979,7 +982,7 @@ discard_and_relse:
+ goto discard_it;
+
+ do_time_wait:
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ goto no_dccp_socket;
+ }
+
+diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
+index 610c722..eb0ff7a 100644
+--- a/net/dccp/ipv6.c
++++ b/net/dccp/ipv6.c
+@@ -201,6 +201,7 @@ static int dccp_v6_connect(struct sock *
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = usin->sin6_port;
+ fl.fl_ip_sport = inet->sport;
++ security_sk_classify_flow(sk, &fl);
+
+ if (np->opt != NULL && np->opt->srcrt != NULL) {
+ const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
+@@ -230,7 +231,7 @@ static int dccp_v6_connect(struct sock *
+ ipv6_addr_copy(&np->saddr, saddr);
+ inet->rcv_saddr = LOOPBACK4_IPV6;
+
+- __ip6_dst_store(sk, dst, NULL);
++ __ip6_dst_store(sk, dst, NULL, NULL);
+
+ icsk->icsk_ext_hdr_len = 0;
+ if (np->opt != NULL)
+@@ -284,7 +285,7 @@ static void dccp_v6_err(struct sk_buff *
+ }
+
+ if (sk->sk_state == DCCP_TIME_WAIT) {
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ return;
+ }
+
+@@ -322,6 +323,7 @@ static void dccp_v6_err(struct sk_buff *
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet->dport;
+ fl.fl_ip_sport = inet->sport;
++ security_sk_classify_flow(sk, &fl);
+
+ err = ip6_dst_lookup(sk, &dst, &fl);
+ if (err) {
+@@ -422,6 +424,7 @@ static int dccp_v6_send_response(struct
+ fl.oif = ireq6->iif;
+ fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+ fl.fl_ip_sport = inet_sk(sk)->sport;
++ security_req_classify_flow(req, &fl);
+
+ if (dst == NULL) {
+ opt = np->opt;
+@@ -547,7 +550,7 @@ static void dccp_v6_ctl_send_reset(struc
+ dccp_hdr_reset(skb)->dccph_reset_code =
+ DCCP_SKB_CB(rxskb)->dccpd_reset_code;
+
+- /* See "8.3.1. Abnormal Termination" in draft-ietf-dccp-spec-11 */
++ /* See "8.3.1. Abnormal Termination" in RFC 4340 */
+ seqno = 0;
+ if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+ dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
+@@ -566,6 +569,7 @@ static void dccp_v6_ctl_send_reset(struc
+ fl.oif = inet6_iif(rxskb);
+ fl.fl_ip_dport = dh->dccph_dport;
+ fl.fl_ip_sport = dh->dccph_sport;
++ security_skb_classify_flow(rxskb, &fl);
+
+ /* sk = NULL, but it is safe for now. RST socket required. */
+ if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
+@@ -622,6 +626,7 @@ static void dccp_v6_reqsk_send_ack(struc
+ fl.oif = inet6_iif(rxskb);
+ fl.fl_ip_dport = dh->dccph_dport;
+ fl.fl_ip_sport = dh->dccph_sport;
++ security_req_classify_flow(req, &fl);
+
+ if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
+ if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
+@@ -658,7 +663,7 @@ static struct sock *dccp_v6_hnd_req(stru
+ bh_lock_sock(nsk);
+ return nsk;
+ }
+- inet_twsk_put((struct inet_timewait_sock *)nsk);
++ inet_twsk_put(inet_twsk(nsk));
+ return NULL;
+ }
+
+@@ -667,7 +672,6 @@ static struct sock *dccp_v6_hnd_req(stru
+
+ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
+ {
+- struct inet_request_sock *ireq;
+ struct dccp_sock dp;
+ struct request_sock *req;
+ struct dccp_request_sock *dreq;
+@@ -696,7 +700,7 @@ static int dccp_v6_conn_request(struct s
+ if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
+ goto drop;
+
+- req = inet6_reqsk_alloc(sk->sk_prot->rsk_prot);
++ req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
+ if (req == NULL)
+ goto drop;
+
+@@ -704,8 +708,10 @@ static int dccp_v6_conn_request(struct s
+
+ dccp_openreq_init(req, &dp, skb);
+
++ if (security_inet_conn_request(sk, skb, req))
++ goto drop_and_free;
++
+ ireq6 = inet6_rsk(req);
+- ireq = inet_rsk(req);
+ ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
+ ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr);
+ req->rcv_wnd = dccp_feat_default_sequence_window;
+@@ -842,6 +848,7 @@ static struct sock *dccp_v6_request_recv
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+ fl.fl_ip_sport = inet_sk(sk)->sport;
++ security_sk_classify_flow(sk, &fl);
+
+ if (ip6_dst_lookup(sk, &dst, &fl))
+ goto out;
+@@ -863,7 +870,7 @@ static struct sock *dccp_v6_request_recv
+ * comment in that function for the gory details. -acme
+ */
+
+- __ip6_dst_store(newsk, dst, NULL);
++ __ip6_dst_store(newsk, dst, NULL, NULL);
+ newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
+ NETIF_F_TSO);
+ newdp6 = (struct dccp6_sock *)newsk;
+@@ -961,7 +968,7 @@ static int dccp_v6_do_rcv(struct sock *s
+ if (skb->protocol == htons(ETH_P_IP))
+ return dccp_v4_do_rcv(sk, skb);
+
+- if (sk_filter(sk, skb, 0))
++ if (sk_filter(sk, skb))
+ goto discard;
+
+ /*
+@@ -988,6 +995,10 @@ static int dccp_v6_do_rcv(struct sock *s
+ if (sk->sk_state == DCCP_OPEN) { /* Fast path */
+ if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
+ goto reset;
++ if (opt_skb) {
++ /* This is where we would goto ipv6_pktoptions. */
++ __kfree_skb(opt_skb);
++ }
+ return 0;
+ }
+
+@@ -1012,6 +1023,10 @@ static int dccp_v6_do_rcv(struct sock *s
+
+ if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
+ goto reset;
++ if (opt_skb) {
++ /* This is where we would goto ipv6_pktoptions. */
++ __kfree_skb(opt_skb);
++ }
+ return 0;
+
+ reset:
+@@ -1100,7 +1115,7 @@ discard_and_relse:
+ goto discard_it;
+
+ do_time_wait:
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ goto no_dccp_socket;
+ }
+
+diff --git a/net/dccp/options.c b/net/dccp/options.c
+index 07a3469..fb0db1f 100644
+--- a/net/dccp/options.c
++++ b/net/dccp/options.c
+@@ -215,7 +215,7 @@ int dccp_parse_options(struct sock *sk,
+ elapsed_time);
+ break;
+ /*
+- * From draft-ietf-dccp-spec-11.txt:
++ * From RFC 4340, sec. 10.3:
+ *
+ * Option numbers 128 through 191 are for
+ * options sent from the HC-Sender to the
+diff --git a/net/dccp/output.c b/net/dccp/output.c
+index 58669be..7102e3a 100644
+--- a/net/dccp/output.c
++++ b/net/dccp/output.c
+@@ -198,7 +198,7 @@ static int dccp_wait_for_ccid(struct soc
+ while (1) {
+ prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+
+- if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
++ if (sk->sk_err)
+ goto do_error;
+ if (!*timeo)
+ goto do_nonblock;
+@@ -234,37 +234,72 @@ do_interrupted:
+ goto out;
+ }
+
+-int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo)
++static void dccp_write_xmit_timer(unsigned long data) {
++ struct sock *sk = (struct sock *)data;
++ struct dccp_sock *dp = dccp_sk(sk);
++
++ bh_lock_sock(sk);
++ if (sock_owned_by_user(sk))
++ sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1);
++ else
++ dccp_write_xmit(sk, 0);
++ bh_unlock_sock(sk);
++ sock_put(sk);
++}
++
++void dccp_write_xmit(struct sock *sk, int block)
+ {
+- const struct dccp_sock *dp = dccp_sk(sk);
+- int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
++ struct dccp_sock *dp = dccp_sk(sk);
++ struct sk_buff *skb;
++ long timeo = 30000; /* If a packet is taking longer than 2 secs
++ we have other issues */
++
++ while ((skb = skb_peek(&sk->sk_write_queue))) {
++ int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
+ skb->len);
+
+- if (err > 0)
+- err = dccp_wait_for_ccid(sk, skb, timeo);
++ if (err > 0) {
++ if (!block) {
++ sk_reset_timer(sk, &dp->dccps_xmit_timer,
++ msecs_to_jiffies(err)+jiffies);
++ break;
++ } else
++ err = dccp_wait_for_ccid(sk, skb, &timeo);
++ if (err) {
++ printk(KERN_CRIT "%s:err at dccp_wait_for_ccid"
++ " %d\n", __FUNCTION__, err);
++ dump_stack();
++ }
++ }
+
+- if (err == 0) {
+- struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+- const int len = skb->len;
++ skb_dequeue(&sk->sk_write_queue);
++ if (err == 0) {
++ struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
++ const int len = skb->len;
+
+- if (sk->sk_state == DCCP_PARTOPEN) {
+- /* See 8.1.5. Handshake Completion */
+- inet_csk_schedule_ack(sk);
+- inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
++ if (sk->sk_state == DCCP_PARTOPEN) {
++ /* See 8.1.5. Handshake Completion */
++ inet_csk_schedule_ack(sk);
++ inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+ inet_csk(sk)->icsk_rto,
+ DCCP_RTO_MAX);
+- dcb->dccpd_type = DCCP_PKT_DATAACK;
+- } else if (dccp_ack_pending(sk))
+- dcb->dccpd_type = DCCP_PKT_DATAACK;
+- else
+- dcb->dccpd_type = DCCP_PKT_DATA;
+-
+- err = dccp_transmit_skb(sk, skb);
+- ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
+- } else
+- kfree_skb(skb);
+-
+- return err;
++ dcb->dccpd_type = DCCP_PKT_DATAACK;
++ } else if (dccp_ack_pending(sk))
++ dcb->dccpd_type = DCCP_PKT_DATAACK;
++ else
++ dcb->dccpd_type = DCCP_PKT_DATA;
++
++ err = dccp_transmit_skb(sk, skb);
++ ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
++ if (err) {
++ printk(KERN_CRIT "%s:err from "
++ "ccid_hc_tx_packet_sent %d\n",
++ __FUNCTION__, err);
++ dump_stack();
++ }
++ } else
++ kfree(skb);
++ }
+ }
+
+ int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+@@ -426,6 +461,9 @@ static inline void dccp_connect_init(str
+ dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
+
+ icsk->icsk_retransmits = 0;
++ init_timer(&dp->dccps_xmit_timer);
++ dp->dccps_xmit_timer.data = (unsigned long)sk;
++ dp->dccps_xmit_timer.function = dccp_write_xmit_timer;
+ }
+
+ int dccp_connect(struct sock *sk)
+@@ -560,8 +598,10 @@ void dccp_send_close(struct sock *sk, co
+ DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
+
+ if (active) {
++ dccp_write_xmit(sk, 1);
+ dccp_skb_entail(sk, skb);
+ dccp_transmit_skb(sk, skb_clone(skb, prio));
++ /* FIXME do we need a retransmit timer here? */
+ } else
+ dccp_transmit_skb(sk, skb);
+ }
+diff --git a/net/dccp/probe.c b/net/dccp/probe.c
+new file mode 100644
+index 0000000..146496f
+--- /dev/null
++++ b/net/dccp/probe.c
+@@ -0,0 +1,198 @@
++/*
++ * dccp_probe - Observe the DCCP flow with kprobes.
++ *
++ * The idea for this came from Werner Almesberger's umlsim
++ * Copyright (C) 2004, Stephen Hemminger <shemminger at osdl.org>
++ *
++ * Modified for DCCP from Stephen Hemminger's code
++ * Copyright (C) 2006, Ian McDonald <ian.mcdonald at jandi.co.nz>
++ *
++ * 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/kprobes.h>
++#include <linux/socket.h>
++#include <linux/dccp.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++#include <linux/kfifo.h>
++#include <linux/vmalloc.h>
++
++#include "dccp.h"
++#include "ccid.h"
++#include "ccids/ccid3.h"
++
++static int port;
++
++static int bufsize = 64 * 1024;
++
++static const char procname[] = "dccpprobe";
++
++struct {
++ struct kfifo *fifo;
++ spinlock_t lock;
++ wait_queue_head_t wait;
++ struct timeval tstart;
++} dccpw;
++
++static void printl(const char *fmt, ...)
++{
++ va_list args;
++ int len;
++ struct timeval now;
++ char tbuf[256];
++
++ va_start(args, fmt);
++ do_gettimeofday(&now);
++
++ now.tv_sec -= dccpw.tstart.tv_sec;
++ now.tv_usec -= dccpw.tstart.tv_usec;
++ if (now.tv_usec < 0) {
++ --now.tv_sec;
++ now.tv_usec += 1000000;
++ }
++
++ len = sprintf(tbuf, "%lu.%06lu ",
++ (unsigned long) now.tv_sec,
++ (unsigned long) now.tv_usec);
++ len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
++ va_end(args);
++
++ kfifo_put(dccpw.fifo, tbuf, len);
++ wake_up(&dccpw.wait);
++}
++
++static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
++ struct msghdr *msg, size_t size)
++{
++ const struct dccp_minisock *dmsk = dccp_msk(sk);
++ const struct inet_sock *inet = inet_sk(sk);
++ const struct ccid3_hc_tx_sock *hctx;
++
++ if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
++ hctx = ccid3_hc_tx_sk(sk);
++ else
++ hctx = NULL;
++
++ if (port == 0 || ntohs(inet->dport) == port ||
++ ntohs(inet->sport) == port) {
++ if (hctx)
++ printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %d\n",
++ NIPQUAD(inet->saddr), ntohs(inet->sport),
++ NIPQUAD(inet->daddr), ntohs(inet->dport), size,
++ hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
++ hctx->ccid3hctx_p, hctx->ccid3hctx_t_ipi);
++ else
++ printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n",
++ NIPQUAD(inet->saddr), ntohs(inet->sport),
++ NIPQUAD(inet->daddr), ntohs(inet->dport), size);
++ }
++
++ jprobe_return();
++ return 0;
++}
++
++static struct jprobe dccp_send_probe = {
++ .kp = { .addr = (kprobe_opcode_t *)&dccp_sendmsg, },
++ .entry = (kprobe_opcode_t *)&jdccp_sendmsg,
++};
++
++static int dccpprobe_open(struct inode *inode, struct file *file)
++{
++ kfifo_reset(dccpw.fifo);
++ do_gettimeofday(&dccpw.tstart);
++ return 0;
++}
++
++static ssize_t dccpprobe_read(struct file *file, char __user *buf,
++ size_t len, loff_t *ppos)
++{
++ int error = 0, cnt = 0;
++ unsigned char *tbuf;
++
++ if (!buf || len < 0)
++ return -EINVAL;
++
++ if (len == 0)
++ return 0;
++
++ tbuf = vmalloc(len);
++ if (!tbuf)
++ return -ENOMEM;
++
++ error = wait_event_interruptible(dccpw.wait,
++ __kfifo_len(dccpw.fifo) != 0);
++ if (error)
++ goto out_free;
++
++ cnt = kfifo_get(dccpw.fifo, tbuf, len);
++ error = copy_to_user(buf, tbuf, cnt);
++
++out_free:
++ vfree(tbuf);
++
++ return error ? error : cnt;
++}
++
++static struct file_operations dccpprobe_fops = {
++ .owner = THIS_MODULE,
++ .open = dccpprobe_open,
++ .read = dccpprobe_read,
++};
++
++static __init int dccpprobe_init(void)
++{
++ int ret = -ENOMEM;
++
++ init_waitqueue_head(&dccpw.wait);
++ spin_lock_init(&dccpw.lock);
++ dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock);
++
++ if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops))
++ goto err0;
++
++ ret = register_jprobe(&dccp_send_probe);
++ if (ret)
++ goto err1;
++
++ pr_info("DCCP watch registered (port=%d)\n", port);
++ return 0;
++err1:
++ proc_net_remove(procname);
++err0:
++ kfifo_free(dccpw.fifo);
++ return ret;
++}
++module_init(dccpprobe_init);
++
++static __exit void dccpprobe_exit(void)
++{
++ kfifo_free(dccpw.fifo);
++ proc_net_remove(procname);
++ unregister_jprobe(&dccp_send_probe);
++
++}
++module_exit(dccpprobe_exit);
++
++MODULE_PARM_DESC(port, "Port to match (0=all)");
++module_param(port, int, 0);
++
++MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
++module_param(bufsize, int, 0);
++
++MODULE_AUTHOR("Ian McDonald <ian.mcdonald at jandi.co.nz>");
++MODULE_DESCRIPTION("DCCP snooper");
++MODULE_LICENSE("GPL");
+diff --git a/net/dccp/proto.c b/net/dccp/proto.c
+index 6f14bb5..72cbdcf 100644
+--- a/net/dccp/proto.c
++++ b/net/dccp/proto.c
+@@ -217,7 +217,7 @@ int dccp_init_sock(struct sock *sk, cons
+ icsk->icsk_sync_mss = dccp_sync_mss;
+ dp->dccps_mss_cache = 536;
+ dp->dccps_role = DCCP_ROLE_UNDEFINED;
+- dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
++ dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
+ dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
+
+ return 0;
+@@ -267,12 +267,6 @@ static inline int dccp_listen_start(stru
+ struct dccp_sock *dp = dccp_sk(sk);
+
+ dp->dccps_role = DCCP_ROLE_LISTEN;
+- /*
+- * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
+- * before calling listen()
+- */
+- if (dccp_service_not_initialized(sk))
+- return -EPROTO;
+ return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
+ }
+
+@@ -540,9 +534,6 @@ static int dccp_getsockopt_service(struc
+ int err = -ENOENT, slen = 0, total_len = sizeof(u32);
+
+ lock_sock(sk);
+- if (dccp_service_not_initialized(sk))
+- goto out;
+-
+ if ((sl = dp->dccps_service_list) != NULL) {
+ slen = sl->dccpsl_nr * sizeof(u32);
+ total_len += slen;
+@@ -662,17 +653,8 @@ int dccp_sendmsg(struct kiocb *iocb, str
+ if (rc != 0)
+ goto out_discard;
+
+- rc = dccp_write_xmit(sk, skb, &timeo);
+- /*
+- * XXX we don't use sk_write_queue, so just discard the packet.
+- * Current plan however is to _use_ sk_write_queue with
+- * an algorith similar to tcp_sendmsg, where the main difference
+- * is that in DCCP we have to respect packet boundaries, so
+- * no coalescing of skbs.
+- *
+- * This bug was _quickly_ found & fixed by just looking at an OSTRA
+- * generated callgraph 8) -acme
+- */
++ skb_queue_tail(&sk->sk_write_queue, skb);
++ dccp_write_xmit(sk,0);
+ out_release:
+ release_sock(sk);
+ return rc ? : len;
+@@ -846,6 +828,7 @@ static int dccp_close_state(struct sock
+
+ void dccp_close(struct sock *sk, long timeout)
+ {
++ struct dccp_sock *dp = dccp_sk(sk);
+ struct sk_buff *skb;
+ int state;
+
+@@ -862,6 +845,8 @@ void dccp_close(struct sock *sk, long ti
+ goto adjudge_to_death;
+ }
+
++ sk_stop_timer(sk, &dp->dccps_xmit_timer);
++
+ /*
+ * We need to flush the recv. buffs. We do this only on the
+ * descriptor close, not protocol-sourced closes, because the
+diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
+index c1ba945..38bc157 100644
+--- a/net/dccp/sysctl.c
++++ b/net/dccp/sysctl.c
+@@ -11,18 +11,12 @@
+
+ #include <linux/mm.h>
+ #include <linux/sysctl.h>
++#include "feat.h"
+
+ #ifndef CONFIG_SYSCTL
+ #error This file should not be compiled without CONFIG_SYSCTL defined
+ #endif
+
+-extern int dccp_feat_default_sequence_window;
+-extern int dccp_feat_default_rx_ccid;
+-extern int dccp_feat_default_tx_ccid;
+-extern int dccp_feat_default_ack_ratio;
+-extern int dccp_feat_default_send_ack_vector;
+-extern int dccp_feat_default_send_ndp_count;
+-
+ static struct ctl_table dccp_default_table[] = {
+ {
+ .ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW,
+diff --git a/net/decnet/Kconfig b/net/decnet/Kconfig
+index 92f2ec4..36e72cb 100644
+--- a/net/decnet/Kconfig
++++ b/net/decnet/Kconfig
+@@ -27,6 +27,7 @@ config DECNET
+ config DECNET_ROUTER
+ bool "DECnet: router support (EXPERIMENTAL)"
+ depends on DECNET && EXPERIMENTAL
++ select FIB_RULES
+ ---help---
+ Add support for turning your DECnet Endnode into a level 1 or 2
+ router. This is an experimental, but functional option. If you
+diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
+index 5486247..3456cd3 100644
+--- a/net/decnet/af_decnet.c
++++ b/net/decnet/af_decnet.c
+@@ -130,6 +130,7 @@ Version 0.0.6 2.1.110 07-aug-98 E
+ #include <linux/poll.h>
+ #include <net/neighbour.h>
+ #include <net/dst.h>
++#include <net/fib_rules.h>
+ #include <net/dn.h>
+ #include <net/dn_nsp.h>
+ #include <net/dn_dev.h>
+@@ -1177,8 +1178,10 @@ static int dn_getname(struct socket *soc
+ if (peer) {
+ if ((sock->state != SS_CONNECTED &&
+ sock->state != SS_CONNECTING) &&
+- scp->accept_mode == ACC_IMMED)
++ scp->accept_mode == ACC_IMMED) {
++ release_sock(sk);
+ return -ENOTCONN;
++ }
+
+ memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn));
+ } else {
+diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
+index 476455f..01861fe 100644
+--- a/net/decnet/dn_dev.c
++++ b/net/decnet/dn_dev.c
+@@ -34,6 +34,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/timer.h>
+ #include <linux/string.h>
++#include <linux/if_addr.h>
+ #include <linux/if_arp.h>
+ #include <linux/if_ether.h>
+ #include <linux/skbuff.h>
+@@ -45,6 +46,7 @@
+ #include <net/neighbour.h>
+ #include <net/dst.h>
+ #include <net/flow.h>
++#include <net/fib_rules.h>
+ #include <net/dn.h>
+ #include <net/dn_dev.h>
+ #include <net/dn_route.h>
+@@ -744,20 +746,23 @@ rtattr_failure:
+ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa)
+ {
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);
++ int payload = sizeof(struct ifaddrmsg) + 128;
++ int err = -ENOBUFS;
+
+- skb = alloc_skb(size, GFP_KERNEL);
+- if (!skb) {
+- netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, ENOBUFS);
+- return;
+- }
+- if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
++ skb = alloc_skb(nlmsg_total_size(payload), GFP_KERNEL);
++ if (skb == NULL)
++ goto errout;
++
++ err = dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, EINVAL);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_IFADDR;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_DECnet_IFADDR, GFP_KERNEL);
++
++ err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err);
+ }
+
+ static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
+@@ -1417,8 +1422,6 @@ static struct rtnetlink_link dnet_rtnetl
+ [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, },
+ [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute,
+ .dumpit = dn_fib_dump, },
+- [RTM_NEWRULE - RTM_BASE] = { .doit = dn_fib_rtm_newrule, },
+- [RTM_DELRULE - RTM_BASE] = { .doit = dn_fib_rtm_delrule, },
+ [RTM_GETRULE - RTM_BASE] = { .dumpit = dn_fib_dump_rules, },
+ #else
+ [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute,
+diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
+index fa20e2e..1cf0101 100644
+--- a/net/decnet/dn_fib.c
++++ b/net/decnet/dn_fib.c
+@@ -34,6 +34,7 @@
+ #include <net/neighbour.h>
+ #include <net/dst.h>
+ #include <net/flow.h>
++#include <net/fib_rules.h>
+ #include <net/dn.h>
+ #include <net/dn_route.h>
+ #include <net/dn_fib.h>
+@@ -54,11 +55,9 @@
+
+ #define endfor_nexthops(fi) }
+
+-extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
+-
+ static DEFINE_SPINLOCK(dn_fib_multipath_lock);
+ static struct dn_fib_info *dn_fib_info_list;
+-static DEFINE_RWLOCK(dn_fib_info_lock);
++static DEFINE_SPINLOCK(dn_fib_info_lock);
+
+ static struct
+ {
+@@ -79,6 +78,9 @@ static struct
+ [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+ };
+
++static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
++static int dn_fib_sync_up(struct net_device *dev);
++
+ void dn_fib_free_info(struct dn_fib_info *fi)
+ {
+ if (fi->fib_dead == 0) {
+@@ -96,7 +98,7 @@ void dn_fib_free_info(struct dn_fib_info
+
+ void dn_fib_release_info(struct dn_fib_info *fi)
+ {
+- write_lock(&dn_fib_info_lock);
++ spin_lock(&dn_fib_info_lock);
+ if (fi && --fi->fib_treeref == 0) {
+ if (fi->fib_next)
+ fi->fib_next->fib_prev = fi->fib_prev;
+@@ -107,7 +109,7 @@ void dn_fib_release_info(struct dn_fib_i
+ fi->fib_dead = 1;
+ dn_fib_info_put(fi);
+ }
+- write_unlock(&dn_fib_info_lock);
++ spin_unlock(&dn_fib_info_lock);
+ }
+
+ static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
+@@ -378,13 +380,13 @@ link_it:
+
+ fi->fib_treeref++;
+ atomic_inc(&fi->fib_clntref);
+- write_lock(&dn_fib_info_lock);
++ spin_lock(&dn_fib_info_lock);
+ fi->fib_next = dn_fib_info_list;
+ fi->fib_prev = NULL;
+ if (dn_fib_info_list)
+ dn_fib_info_list->fib_prev = fi;
+ dn_fib_info_list = fi;
+- write_unlock(&dn_fib_info_lock);
++ spin_unlock(&dn_fib_info_lock);
+ return fi;
+
+ err_inval:
+@@ -490,7 +492,8 @@ static int dn_fib_check_attr(struct rtms
+ if (attr) {
+ if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
+ return -EINVAL;
+- if (i != RTA_MULTIPATH && i != RTA_METRICS)
++ if (i != RTA_MULTIPATH && i != RTA_METRICS &&
++ i != RTA_TABLE)
+ rta[i-1] = (struct rtattr *)RTA_DATA(attr);
+ }
+ }
+@@ -507,7 +510,7 @@ int dn_fib_rtm_delroute(struct sk_buff *
+ if (dn_fib_check_attr(r, rta))
+ return -EINVAL;
+
+- tb = dn_fib_get_table(r->rtm_table, 0);
++ tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);
+ if (tb)
+ return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
+
+@@ -523,46 +526,13 @@ int dn_fib_rtm_newroute(struct sk_buff *
+ if (dn_fib_check_attr(r, rta))
+ return -EINVAL;
+
+- tb = dn_fib_get_table(r->rtm_table, 1);
++ tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);
+ if (tb)
+ return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
+
+ return -ENOBUFS;
+ }
+
+-
+-int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
+-{
+- int t;
+- int s_t;
+- struct dn_fib_table *tb;
+-
+- if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
+- ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
+- return dn_cache_dump(skb, cb);
+-
+- s_t = cb->args[0];
+- if (s_t == 0)
+- s_t = cb->args[0] = RT_MIN_TABLE;
+-
+- for(t = s_t; t <= RT_TABLE_MAX; t++) {
+- if (t < s_t)
+- continue;
+- if (t > s_t)
+- memset(&cb->args[1], 0,
+- sizeof(cb->args) - sizeof(cb->args[0]));
+- tb = dn_fib_get_table(t, 0);
+- if (tb == NULL)
+- continue;
+- if (tb->dump(tb, skb, cb) < 0)
+- break;
+- }
+-
+- cb->args[0] = t;
+-
+- return skb->len;
+-}
+-
+ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
+ {
+ struct dn_fib_table *tb;
+@@ -682,7 +652,7 @@ static int dn_fib_dnaddr_event(struct no
+ return NOTIFY_DONE;
+ }
+
+-int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
++static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
+ {
+ int ret = 0;
+ int scope = RT_SCOPE_NOWHERE;
+@@ -726,7 +696,7 @@ int dn_fib_sync_down(__le16 local, struc
+ }
+
+
+-int dn_fib_sync_up(struct net_device *dev)
++static int dn_fib_sync_up(struct net_device *dev)
+ {
+ int ret = 0;
+
+@@ -760,22 +730,6 @@ int dn_fib_sync_up(struct net_device *de
+ return ret;
+ }
+
+-void dn_fib_flush(void)
+-{
+- int flushed = 0;
+- struct dn_fib_table *tb;
+- int id;
+-
+- for(id = RT_TABLE_MAX; id > 0; id--) {
+- if ((tb = dn_fib_get_table(id, 0)) == NULL)
+- continue;
+- flushed += tb->flush(tb);
+- }
+-
+- if (flushed)
+- dn_rt_cache_flush(-1);
+-}
+-
+ static struct notifier_block dn_fib_dnaddr_notifier = {
+ .notifier_call = dn_fib_dnaddr_event,
+ };
+diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
+index 86f7f3b..72ecc6e 100644
+--- a/net/decnet/dn_nsp_in.c
++++ b/net/decnet/dn_nsp_in.c
+@@ -586,7 +586,7 @@ static __inline__ int dn_queue_skb(struc
+ goto out;
+ }
+
+- err = sk_filter(sk, skb, 0);
++ err = sk_filter(sk, skb);
+ if (err)
+ goto out;
+
+diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
+index 743e9fc..23489f7 100644
+--- a/net/decnet/dn_route.c
++++ b/net/decnet/dn_route.c
+@@ -80,6 +80,7 @@
+ #include <net/neighbour.h>
+ #include <net/dst.h>
+ #include <net/flow.h>
++#include <net/fib_rules.h>
+ #include <net/dn.h>
+ #include <net/dn_dev.h>
+ #include <net/dn_nsp.h>
+@@ -266,9 +267,14 @@ static void dn_dst_link_failure(struct s
+
+ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
+ {
+- return memcmp(&fl1->nl_u.dn_u, &fl2->nl_u.dn_u, sizeof(fl1->nl_u.dn_u)) == 0 &&
+- fl1->oif == fl2->oif &&
+- fl1->iif == fl2->iif;
++ return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) |
++ (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) |
++#ifdef CONFIG_DECNET_ROUTE_FWMARK
++ (fl1->nl_u.dn_u.fwmark ^ fl2->nl_u.dn_u.fwmark) |
++#endif
++ (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) |
++ (fl1->oif ^ fl2->oif) |
++ (fl1->iif ^ fl2->iif)) == 0;
+ }
+
+ static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
+@@ -1269,7 +1275,6 @@ static int dn_route_input_slow(struct sk
+ goto e_inval;
+
+ res.type = RTN_LOCAL;
+- flags |= RTCF_DIRECTSRC;
+ } else {
+ __le16 src_map = fl.fld_src;
+ free_res = 1;
+@@ -1284,7 +1289,7 @@ static int dn_route_input_slow(struct sk
+ dev_hold(out_dev);
+
+ if (res.r)
+- src_map = dn_fib_rules_policy(fl.fld_src, &res, &flags);
++ src_map = fl.fld_src; /* no NAT support for now */
+
+ gateway = DN_FIB_RES_GW(res);
+ if (res.type == RTN_NAT) {
+@@ -1340,7 +1345,7 @@ static int dn_route_input_slow(struct sk
+ goto make_route;
+
+ /* Packet was intra-ethernet, so we know its on-link */
+- if (cb->rt_flags | DN_RT_F_IE) {
++ if (cb->rt_flags & DN_RT_F_IE) {
+ gateway = cb->src;
+ flags |= RTCF_DIRECTSRC;
+ goto make_route;
+@@ -1485,6 +1490,7 @@ static int dn_rt_fill_info(struct sk_buf
+ r->rtm_src_len = 0;
+ r->rtm_tos = 0;
+ r->rtm_table = RT_TABLE_MAIN;
++ RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
+ r->rtm_type = rt->rt_type;
+ r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
+ r->rtm_scope = RT_SCOPE_UNIVERSE;
+@@ -1609,9 +1615,7 @@ int dn_cache_getroute(struct sk_buff *in
+ goto out_free;
+ }
+
+- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+-
+- return err;
++ return rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
+
+ out_free:
+ kfree_skb(skb);
+@@ -1781,14 +1785,9 @@ void __init dn_route_init(void)
+ {
+ int i, goal, order;
+
+- dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache",
+- sizeof(struct dn_route),
+- 0, SLAB_HWCACHE_ALIGN,
+- NULL, NULL);
+-
+- if (!dn_dst_ops.kmem_cachep)
+- panic("DECnet: Failed to allocate dn_dst_cache\n");
+-
++ dn_dst_ops.kmem_cachep =
++ kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ init_timer(&dn_route_timer);
+ dn_route_timer.function = dn_dst_check_expire;
+ dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;
+diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
+index 6986be7..3e0c882 100644
+--- a/net/decnet/dn_rules.c
++++ b/net/decnet/dn_rules.c
+@@ -11,259 +11,213 @@
+ *
+ *
+ * Changes:
++ * Steve Whitehouse <steve at chygwyn.com>
++ * Updated for Thomas Graf's generic rules
+ *
+ */
+-#include <linux/string.h>
+ #include <linux/net.h>
+-#include <linux/socket.h>
+-#include <linux/sockios.h>
+ #include <linux/init.h>
+-#include <linux/skbuff.h>
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
+-#include <linux/proc_fs.h>
+ #include <linux/netdevice.h>
+-#include <linux/timer.h>
+ #include <linux/spinlock.h>
+-#include <linux/in_route.h>
+ #include <linux/list.h>
+ #include <linux/rcupdate.h>
+-#include <asm/atomic.h>
+-#include <asm/uaccess.h>
+ #include <net/neighbour.h>
+ #include <net/dst.h>
+ #include <net/flow.h>
++#include <net/fib_rules.h>
+ #include <net/dn.h>
+ #include <net/dn_fib.h>
+ #include <net/dn_neigh.h>
+ #include <net/dn_dev.h>
+
++static struct fib_rules_ops dn_fib_rules_ops;
++
+ struct dn_fib_rule
+ {
+- struct hlist_node r_hlist;
+- atomic_t r_clntref;
+- u32 r_preference;
+- unsigned char r_table;
+- unsigned char r_action;
+- unsigned char r_dst_len;
+- unsigned char r_src_len;
+- __le16 r_src;
+- __le16 r_srcmask;
+- __le16 r_dst;
+- __le16 r_dstmask;
+- __le16 r_srcmap;
+- u8 r_flags;
++ struct fib_rule common;
++ unsigned char dst_len;
++ unsigned char src_len;
++ __le16 src;
++ __le16 srcmask;
++ __le16 dst;
++ __le16 dstmask;
++ __le16 srcmap;
++ u8 flags;
+ #ifdef CONFIG_DECNET_ROUTE_FWMARK
+- u32 r_fwmark;
++ u32 fwmark;
++ u32 fwmask;
+ #endif
+- int r_ifindex;
+- char r_ifname[IFNAMSIZ];
+- int r_dead;
+- struct rcu_head rcu;
+ };
+
+ static struct dn_fib_rule default_rule = {
+- .r_clntref = ATOMIC_INIT(2),
+- .r_preference = 0x7fff,
+- .r_table = RT_TABLE_MAIN,
+- .r_action = RTN_UNICAST
++ .common = {
++ .refcnt = ATOMIC_INIT(2),
++ .pref = 0x7fff,
++ .table = RT_TABLE_MAIN,
++ .action = FR_ACT_TO_TBL,
++ },
+ };
+
+-static struct hlist_head dn_fib_rules;
++static LIST_HEAD(dn_fib_rules);
++
+
+-int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
++int dn_fib_lookup(struct flowi *flp, struct dn_fib_res *res)
+ {
+- struct rtattr **rta = arg;
+- struct rtmsg *rtm = NLMSG_DATA(nlh);
+- struct dn_fib_rule *r;
+- struct hlist_node *node;
+- int err = -ESRCH;
+-
+- hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+- if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
+- rtm->rtm_src_len == r->r_src_len &&
+- rtm->rtm_dst_len == r->r_dst_len &&
+- (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) &&
+-#ifdef CONFIG_DECNET_ROUTE_FWMARK
+- (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
+-#endif
+- (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
+- (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
+- (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) &&
+- (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
+-
+- err = -EPERM;
+- if (r == &default_rule)
+- break;
+-
+- hlist_del_rcu(&r->r_hlist);
+- r->r_dead = 1;
+- dn_fib_rule_put(r);
+- err = 0;
+- break;
+- }
+- }
++ struct fib_lookup_arg arg = {
++ .result = res,
++ };
++ int err;
++
++ err = fib_rules_lookup(&dn_fib_rules_ops, flp, 0, &arg);
++ res->r = arg.rule;
+
+ return err;
+ }
+
+-static inline void dn_fib_rule_put_rcu(struct rcu_head *head)
++static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp,
++ int flags, struct fib_lookup_arg *arg)
+ {
+- struct dn_fib_rule *r = container_of(head, struct dn_fib_rule, rcu);
+- kfree(r);
+-}
++ int err = -EAGAIN;
++ struct dn_fib_table *tbl;
+
+-void dn_fib_rule_put(struct dn_fib_rule *r)
+-{
+- if (atomic_dec_and_test(&r->r_clntref)) {
+- if (r->r_dead)
+- call_rcu(&r->rcu, dn_fib_rule_put_rcu);
+- else
+- printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n");
++ switch(rule->action) {
++ case FR_ACT_TO_TBL:
++ break;
++
++ case FR_ACT_UNREACHABLE:
++ err = -ENETUNREACH;
++ goto errout;
++
++ case FR_ACT_PROHIBIT:
++ err = -EACCES;
++ goto errout;
++
++ case FR_ACT_BLACKHOLE:
++ default:
++ err = -EINVAL;
++ goto errout;
+ }
++
++ tbl = dn_fib_get_table(rule->table, 0);
++ if (tbl == NULL)
++ goto errout;
++
++ err = tbl->lookup(tbl, flp, (struct dn_fib_res *)arg->result);
++ if (err > 0)
++ err = -EAGAIN;
++errout:
++ return err;
+ }
+
++static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = {
++ [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
++ [FRA_PRIORITY] = { .type = NLA_U32 },
++ [FRA_SRC] = { .type = NLA_U16 },
++ [FRA_DST] = { .type = NLA_U16 },
++ [FRA_FWMARK] = { .type = NLA_U32 },
++ [FRA_FWMASK] = { .type = NLA_U32 },
++ [FRA_TABLE] = { .type = NLA_U32 },
++};
+
+-int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
++static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
+ {
+- struct rtattr **rta = arg;
+- struct rtmsg *rtm = NLMSG_DATA(nlh);
+- struct dn_fib_rule *r, *new_r, *last = NULL;
+- struct hlist_node *node = NULL;
+- unsigned char table_id;
+-
+- if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
+- return -EINVAL;
+-
+- if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
+- return -EINVAL;
+-
+- if (rtm->rtm_type == RTN_NAT)
+- return -EINVAL;
+-
+- table_id = rtm->rtm_table;
+- if (table_id == RT_TABLE_UNSPEC) {
+- struct dn_fib_table *tb;
+- if (rtm->rtm_type == RTN_UNICAST) {
+- if ((tb = dn_fib_empty_table()) == NULL)
+- return -ENOBUFS;
+- table_id = tb->n;
+- }
+- }
++ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
++ u16 daddr = fl->fld_dst;
++ u16 saddr = fl->fld_src;
++
++ if (((saddr ^ r->src) & r->srcmask) ||
++ ((daddr ^ r->dst) & r->dstmask))
++ return 0;
+
+- new_r = kzalloc(sizeof(*new_r), GFP_KERNEL);
+- if (!new_r)
+- return -ENOMEM;
+-
+- if (rta[RTA_SRC-1])
+- memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
+- if (rta[RTA_DST-1])
+- memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2);
+- if (rta[RTA_GATEWAY-1])
+- memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 2);
+- new_r->r_src_len = rtm->rtm_src_len;
+- new_r->r_dst_len = rtm->rtm_dst_len;
+- new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len);
+- new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len);
+ #ifdef CONFIG_DECNET_ROUTE_FWMARK
+- if (rta[RTA_PROTOINFO-1])
+- memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
++ if ((r->fwmark ^ fl->fld_fwmark) & r->fwmask)
++ return 0;
+ #endif
+- new_r->r_action = rtm->rtm_type;
+- new_r->r_flags = rtm->rtm_flags;
+- if (rta[RTA_PRIORITY-1])
+- memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
+- new_r->r_table = table_id;
+- if (rta[RTA_IIF-1]) {
+- struct net_device *dev;
+- rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ);
+- new_r->r_ifindex = -1;
+- dev = dev_get_by_name(new_r->r_ifname);
+- if (dev) {
+- new_r->r_ifindex = dev->ifindex;
+- dev_put(dev);
+- }
+- }
+
+- r = container_of(dn_fib_rules.first, struct dn_fib_rule, r_hlist);
+- if (!new_r->r_preference) {
+- if (r && r->r_hlist.next != NULL) {
+- r = container_of(r->r_hlist.next, struct dn_fib_rule, r_hlist);
+- if (r->r_preference)
+- new_r->r_preference = r->r_preference - 1;
++ return 1;
++}
++
++static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
++ struct nlmsghdr *nlh, struct fib_rule_hdr *frh,
++ struct nlattr **tb)
++{
++ int err = -EINVAL;
++ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
++
++ if (frh->src_len > 16 || frh->dst_len > 16 || frh->tos)
++ goto errout;
++
++ if (rule->table == RT_TABLE_UNSPEC) {
++ if (rule->action == FR_ACT_TO_TBL) {
++ struct dn_fib_table *table;
++
++ table = dn_fib_empty_table();
++ if (table == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
++
++ rule->table = table->n;
+ }
+ }
+
+- hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+- if (r->r_preference > new_r->r_preference)
+- break;
+- last = r;
++ if (tb[FRA_SRC])
++ r->src = nla_get_u16(tb[FRA_SRC]);
++
++ if (tb[FRA_DST])
++ r->dst = nla_get_u16(tb[FRA_DST]);
++
++#ifdef CONFIG_DECNET_ROUTE_FWMARK
++ if (tb[FRA_FWMARK]) {
++ r->fwmark = nla_get_u32(tb[FRA_FWMARK]);
++ if (r->fwmark)
++ /* compatibility: if the mark value is non-zero all bits
++ * are compared unless a mask is explicitly specified.
++ */
++ r->fwmask = 0xFFFFFFFF;
+ }
+- atomic_inc(&new_r->r_clntref);
+
+- if (last)
+- hlist_add_after_rcu(&last->r_hlist, &new_r->r_hlist);
+- else
+- hlist_add_before_rcu(&new_r->r_hlist, &r->r_hlist);
+- return 0;
+-}
++ if (tb[FRA_FWMASK])
++ r->fwmask = nla_get_u32(tb[FRA_FWMASK]);
++#endif
+
++ r->src_len = frh->src_len;
++ r->srcmask = dnet_make_mask(r->src_len);
++ r->dst_len = frh->dst_len;
++ r->dstmask = dnet_make_mask(r->dst_len);
++ err = 0;
++errout:
++ return err;
++}
+
+-int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
++static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
++ struct nlattr **tb)
+ {
+- struct dn_fib_rule *r, *policy;
+- struct dn_fib_table *tb;
+- __le16 saddr = flp->fld_src;
+- __le16 daddr = flp->fld_dst;
+- struct hlist_node *node;
+- int err;
++ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
++
++ if (frh->src_len && (r->src_len != frh->src_len))
++ return 0;
+
+- rcu_read_lock();
++ if (frh->dst_len && (r->dst_len != frh->dst_len))
++ return 0;
+
+- hlist_for_each_entry_rcu(r, node, &dn_fib_rules, r_hlist) {
+- if (((saddr^r->r_src) & r->r_srcmask) ||
+- ((daddr^r->r_dst) & r->r_dstmask) ||
+ #ifdef CONFIG_DECNET_ROUTE_FWMARK
+- (r->r_fwmark && r->r_fwmark != flp->fld_fwmark) ||
++ if (tb[FRA_FWMARK] && (r->fwmark != nla_get_u32(tb[FRA_FWMARK])))
++ return 0;
++
++ if (tb[FRA_FWMASK] && (r->fwmask != nla_get_u32(tb[FRA_FWMASK])))
++ return 0;
+ #endif
+- (r->r_ifindex && r->r_ifindex != flp->iif))
+- continue;
+-
+- switch(r->r_action) {
+- case RTN_UNICAST:
+- case RTN_NAT:
+- policy = r;
+- break;
+- case RTN_UNREACHABLE:
+- rcu_read_unlock();
+- return -ENETUNREACH;
+- default:
+- case RTN_BLACKHOLE:
+- rcu_read_unlock();
+- return -EINVAL;
+- case RTN_PROHIBIT:
+- rcu_read_unlock();
+- return -EACCES;
+- }
+
+- if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
+- continue;
+- err = tb->lookup(tb, flp, res);
+- if (err == 0) {
+- res->r = policy;
+- if (policy)
+- atomic_inc(&policy->r_clntref);
+- rcu_read_unlock();
+- return 0;
+- }
+- if (err < 0 && err != -EAGAIN) {
+- rcu_read_unlock();
+- return err;
+- }
+- }
++ if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC])))
++ return 0;
++
++ if (tb[FRA_DST] && (r->dst != nla_get_u16(tb[FRA_DST])))
++ return 0;
+
+- rcu_read_unlock();
+- return -ESRCH;
++ return 1;
+ }
+
+ unsigned dnet_addr_type(__le16 addr)
+@@ -271,7 +225,7 @@ unsigned dnet_addr_type(__le16 addr)
+ struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
+ struct dn_fib_res res;
+ unsigned ret = RTN_UNICAST;
+- struct dn_fib_table *tb = dn_fib_tables[RT_TABLE_LOCAL];
++ struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0);
+
+ res.r = NULL;
+
+@@ -284,142 +238,79 @@ unsigned dnet_addr_type(__le16 addr)
+ return ret;
+ }
+
+-__le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags)
++static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
++ struct nlmsghdr *nlh, struct fib_rule_hdr *frh)
+ {
+- struct dn_fib_rule *r = res->r;
++ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
+
+- if (r->r_action == RTN_NAT) {
+- int addrtype = dnet_addr_type(r->r_srcmap);
++ frh->family = AF_DECnet;
++ frh->dst_len = r->dst_len;
++ frh->src_len = r->src_len;
++ frh->tos = 0;
+
+- if (addrtype == RTN_NAT) {
+- saddr = (saddr&~r->r_srcmask)|r->r_srcmap;
+- *flags |= RTCF_SNAT;
+- } else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) {
+- saddr = r->r_srcmap;
+- *flags |= RTCF_MASQ;
+- }
+- }
+- return saddr;
+-}
+-
+-static void dn_fib_rules_detach(struct net_device *dev)
+-{
+- struct hlist_node *node;
+- struct dn_fib_rule *r;
+-
+- hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+- if (r->r_ifindex == dev->ifindex)
+- r->r_ifindex = -1;
+- }
+-}
++#ifdef CONFIG_DECNET_ROUTE_FWMARK
++ if (r->fwmark)
++ NLA_PUT_U32(skb, FRA_FWMARK, r->fwmark);
++ if (r->fwmask || r->fwmark)
++ NLA_PUT_U32(skb, FRA_FWMASK, r->fwmask);
++#endif
++ if (r->dst_len)
++ NLA_PUT_U16(skb, FRA_DST, r->dst);
++ if (r->src_len)
++ NLA_PUT_U16(skb, FRA_SRC, r->src);
+
+-static void dn_fib_rules_attach(struct net_device *dev)
+-{
+- struct hlist_node *node;
+- struct dn_fib_rule *r;
++ return 0;
+
+- hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+- if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
+- r->r_ifindex = dev->ifindex;
+- }
++nla_put_failure:
++ return -ENOBUFS;
+ }
+
+-static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
++static u32 dn_fib_rule_default_pref(void)
+ {
+- struct net_device *dev = ptr;
+-
+- switch(event) {
+- case NETDEV_UNREGISTER:
+- dn_fib_rules_detach(dev);
+- dn_fib_sync_down(0, dev, 1);
+- case NETDEV_REGISTER:
+- dn_fib_rules_attach(dev);
+- dn_fib_sync_up(dev);
++ struct list_head *pos;
++ struct fib_rule *rule;
++
++ if (!list_empty(&dn_fib_rules)) {
++ pos = dn_fib_rules.next;
++ if (pos->next != &dn_fib_rules) {
++ rule = list_entry(pos->next, struct fib_rule, list);
++ if (rule->pref)
++ return rule->pref - 1;
++ }
+ }
+
+- return NOTIFY_DONE;
+-}
+-
+-
+-static struct notifier_block dn_fib_rules_notifier = {
+- .notifier_call = dn_fib_rules_event,
+-};
+-
+-static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r,
+- struct netlink_callback *cb, unsigned int flags)
+-{
+- struct rtmsg *rtm;
+- struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
+-
+-
+- nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags);
+- rtm = NLMSG_DATA(nlh);
+- rtm->rtm_family = AF_DECnet;
+- rtm->rtm_dst_len = r->r_dst_len;
+- rtm->rtm_src_len = r->r_src_len;
+- rtm->rtm_tos = 0;
+-#ifdef CONFIG_DECNET_ROUTE_FWMARK
+- if (r->r_fwmark)
+- RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
+-#endif
+- rtm->rtm_table = r->r_table;
+- rtm->rtm_protocol = 0;
+- rtm->rtm_scope = 0;
+- rtm->rtm_type = r->r_action;
+- rtm->rtm_flags = r->r_flags;
+-
+- if (r->r_dst_len)
+- RTA_PUT(skb, RTA_DST, 2, &r->r_dst);
+- if (r->r_src_len)
+- RTA_PUT(skb, RTA_SRC, 2, &r->r_src);
+- if (r->r_ifname[0])
+- RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
+- if (r->r_preference)
+- RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
+- if (r->r_srcmap)
+- RTA_PUT(skb, RTA_GATEWAY, 2, &r->r_srcmap);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
+-
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ return 0;
+ }
+
+ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+- int idx = 0;
+- int s_idx = cb->args[0];
+- struct dn_fib_rule *r;
+- struct hlist_node *node;
+-
+- rcu_read_lock();
+- hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+- if (idx < s_idx)
+- goto next;
+- if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
+- break;
+-next:
+- idx++;
+- }
+- rcu_read_unlock();
+- cb->args[0] = idx;
+-
+- return skb->len;
++ return fib_rules_dump(skb, cb, AF_DECnet);
+ }
+
++static struct fib_rules_ops dn_fib_rules_ops = {
++ .family = AF_DECnet,
++ .rule_size = sizeof(struct dn_fib_rule),
++ .action = dn_fib_rule_action,
++ .match = dn_fib_rule_match,
++ .configure = dn_fib_rule_configure,
++ .compare = dn_fib_rule_compare,
++ .fill = dn_fib_rule_fill,
++ .default_pref = dn_fib_rule_default_pref,
++ .nlgroup = RTNLGRP_DECnet_RULE,
++ .policy = dn_fib_rule_policy,
++ .rules_list = &dn_fib_rules,
++ .owner = THIS_MODULE,
++};
++
+ void __init dn_fib_rules_init(void)
+ {
+- INIT_HLIST_HEAD(&dn_fib_rules);
+- hlist_add_head(&default_rule.r_hlist, &dn_fib_rules);
+- register_netdevice_notifier(&dn_fib_rules_notifier);
++ list_add_tail(&default_rule.common.list, &dn_fib_rules);
++ fib_rules_register(&dn_fib_rules_ops);
+ }
+
+ void __exit dn_fib_rules_cleanup(void)
+ {
+- unregister_netdevice_notifier(&dn_fib_rules_notifier);
++ fib_rules_unregister(&dn_fib_rules_ops);
+ }
+
+
+diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
+index e926c95..317904b 100644
+--- a/net/decnet/dn_table.c
++++ b/net/decnet/dn_table.c
+@@ -30,6 +30,7 @@
+ #include <net/neighbour.h>
+ #include <net/dst.h>
+ #include <net/flow.h>
++#include <net/fib_rules.h>
+ #include <net/dn.h>
+ #include <net/dn_route.h>
+ #include <net/dn_fib.h>
+@@ -74,9 +75,9 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f
+ for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
+
+ #define RT_TABLE_MIN 1
+-
++#define DN_FIB_TABLE_HASHSZ 256
++static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
+ static DEFINE_RWLOCK(dn_fib_tables_lock);
+-struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
+
+ static kmem_cache_t *dn_hash_kmem __read_mostly;
+ static int dn_fib_hash_zombies;
+@@ -263,7 +264,7 @@ static int dn_fib_nh_match(struct rtmsg
+ }
+
+ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+- u8 tb_id, u8 type, u8 scope, void *dst, int dst_len,
++ u32 tb_id, u8 type, u8 scope, void *dst, int dst_len,
+ struct dn_fib_info *fi, unsigned int flags)
+ {
+ struct rtmsg *rtm;
+@@ -277,6 +278,7 @@ static int dn_fib_dump_info(struct sk_bu
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = 0;
+ rtm->rtm_table = tb_id;
++ RTA_PUT_U32(skb, RTA_TABLE, tb_id);
+ rtm->rtm_flags = fi->fib_flags;
+ rtm->rtm_scope = scope;
+ rtm->rtm_type = type;
+@@ -326,29 +328,29 @@ rtattr_failure:
+ }
+
+
+-static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id,
++static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
+ struct nlmsghdr *nlh, struct netlink_skb_parms *req)
+ {
+ struct sk_buff *skb;
+ u32 pid = req ? req->pid : 0;
+- int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256);
++ int err = -ENOBUFS;
+
+- skb = alloc_skb(size, GFP_KERNEL);
+- if (!skb)
+- return;
++ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (skb == NULL)
++ goto errout;
+
+- if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
+- f->fn_type, f->fn_scope, &f->fn_key, z,
+- DN_FIB_INFO(f), 0) < 0) {
++ err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
++ f->fn_type, f->fn_scope, &f->fn_key, z,
++ DN_FIB_INFO(f), 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_ROUTE;
+- if (nlh->nlmsg_flags & NLM_F_ECHO)
+- atomic_inc(&skb->users);
+- netlink_broadcast(rtnl, skb, pid, RTNLGRP_DECnet_ROUTE, GFP_KERNEL);
+- if (nlh->nlmsg_flags & NLM_F_ECHO)
+- netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
++
++ err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_DECnet_ROUTE, err);
+ }
+
+ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
+@@ -359,7 +361,7 @@ static __inline__ int dn_hash_dump_bucke
+ {
+ int i, s_i;
+
+- s_i = cb->args[3];
++ s_i = cb->args[4];
+ for(i = 0; f; i++, f = f->fn_next) {
+ if (i < s_i)
+ continue;
+@@ -372,11 +374,11 @@ static __inline__ int dn_hash_dump_bucke
+ (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
+ f->fn_scope, &f->fn_key, dz->dz_order,
+ f->fn_info, NLM_F_MULTI) < 0) {
+- cb->args[3] = i;
++ cb->args[4] = i;
+ return -1;
+ }
+ }
+- cb->args[3] = i;
++ cb->args[4] = i;
+ return skb->len;
+ }
+
+@@ -387,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(
+ {
+ int h, s_h;
+
+- s_h = cb->args[2];
++ s_h = cb->args[3];
+ for(h = 0; h < dz->dz_divisor; h++) {
+ if (h < s_h)
+ continue;
+ if (h > s_h)
+- memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
++ memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
+ if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
+ continue;
+ if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
+- cb->args[2] = h;
++ cb->args[3] = h;
+ return -1;
+ }
+ }
+- cb->args[2] = h;
++ cb->args[3] = h;
+ return skb->len;
+ }
+
+@@ -411,26 +413,63 @@ static int dn_fib_table_dump(struct dn_f
+ struct dn_zone *dz;
+ struct dn_hash *table = (struct dn_hash *)tb->data;
+
+- s_m = cb->args[1];
++ s_m = cb->args[2];
+ read_lock(&dn_fib_tables_lock);
+ for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
+ if (m < s_m)
+ continue;
+ if (m > s_m)
+- memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
++ memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
+
+ if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
+- cb->args[1] = m;
++ cb->args[2] = m;
+ read_unlock(&dn_fib_tables_lock);
+ return -1;
+ }
+ }
+ read_unlock(&dn_fib_tables_lock);
+- cb->args[1] = m;
++ cb->args[2] = m;
+
+ return skb->len;
+ }
+
++int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
++{
++ unsigned int h, s_h;
++ unsigned int e = 0, s_e;
++ struct dn_fib_table *tb;
++ struct hlist_node *node;
++ int dumped = 0;
++
++ if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
++ ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
++ return dn_cache_dump(skb, cb);
++
++ s_h = cb->args[0];
++ s_e = cb->args[1];
++
++ for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
++ e = 0;
++ hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) {
++ if (e < s_e)
++ goto next;
++ if (dumped)
++ memset(&cb->args[2], 0, sizeof(cb->args) -
++ 2 * sizeof(cb->args[0]));
++ if (tb->dump(tb, skb, cb) < 0)
++ goto out;
++ dumped = 1;
++next:
++ e++;
++ }
++ }
++out:
++ cb->args[1] = e;
++ cb->args[0] = h;
++
++ return skb->len;
++}
++
+ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+ {
+ struct dn_hash *table = (struct dn_hash *)tb->data;
+@@ -739,9 +778,11 @@ out:
+ }
+
+
+-struct dn_fib_table *dn_fib_get_table(int n, int create)
++struct dn_fib_table *dn_fib_get_table(u32 n, int create)
+ {
+ struct dn_fib_table *t;
++ struct hlist_node *node;
++ unsigned int h;
+
+ if (n < RT_TABLE_MIN)
+ return NULL;
+@@ -749,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(in
+ if (n > RT_TABLE_MAX)
+ return NULL;
+
+- if (dn_fib_tables[n])
+- return dn_fib_tables[n];
++ h = n & (DN_FIB_TABLE_HASHSZ - 1);
++ rcu_read_lock();
++ hlist_for_each_entry_rcu(t, node, &dn_fib_table_hash[h], hlist) {
++ if (t->n == n) {
++ rcu_read_unlock();
++ return t;
++ }
++ }
++ rcu_read_unlock();
+
+ if (!create)
+ return NULL;
+@@ -771,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(in
+ t->flush = dn_fib_table_flush;
+ t->dump = dn_fib_table_dump;
+ memset(t->data, 0, sizeof(struct dn_hash));
+- dn_fib_tables[n] = t;
++ hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
+
+ return t;
+ }
+
+-static void dn_fib_del_tree(int n)
+-{
+- struct dn_fib_table *t;
+-
+- write_lock(&dn_fib_tables_lock);
+- t = dn_fib_tables[n];
+- dn_fib_tables[n] = NULL;
+- write_unlock(&dn_fib_tables_lock);
+-
+- kfree(t);
+-}
+-
+ struct dn_fib_table *dn_fib_empty_table(void)
+ {
+- int id;
++ u32 id;
+
+ for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
+- if (dn_fib_tables[id] == NULL)
++ if (dn_fib_get_table(id, 0) == NULL)
+ return dn_fib_get_table(id, 1);
+ return NULL;
+ }
+
++void dn_fib_flush(void)
++{
++ int flushed = 0;
++ struct dn_fib_table *tb;
++ struct hlist_node *node;
++ unsigned int h;
++
++ for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
++ hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist)
++ flushed += tb->flush(tb);
++ }
++
++ if (flushed)
++ dn_rt_cache_flush(-1);
++}
++
+ void __init dn_fib_table_init(void)
+ {
+ dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
+@@ -808,10 +860,17 @@ void __init dn_fib_table_init(void)
+
+ void __exit dn_fib_table_cleanup(void)
+ {
+- int i;
+-
+- for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i)
+- dn_fib_del_tree(i);
++ struct dn_fib_table *t;
++ struct hlist_node *node, *next;
++ unsigned int h;
+
+- return;
++ write_lock(&dn_fib_tables_lock);
++ for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
++ hlist_for_each_entry_safe(t, node, next, &dn_fib_table_hash[h],
++ hlist) {
++ hlist_del(&t->hlist);
++ kfree(t);
++ }
++ }
++ write_unlock(&dn_fib_tables_lock);
+ }
+diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
+index 387c71c..4bd78c8 100644
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -64,81 +64,79 @@
+
+ __setup("ether=", netdev_boot_setup);
+
+-/*
+- * Create the Ethernet MAC header for an arbitrary protocol layer
++/**
++ * eth_header - create the Ethernet header
++ * @skb: buffer to alter
++ * @dev: source device
++ * @type: Ethernet type field
++ * @daddr: destination address (NULL leave destination address)
++ * @saddr: source address (NULL use device source address)
++ * @len: packet length (<= skb->len)
+ *
+- * saddr=NULL means use device source address
+- * daddr=NULL means leave destination address (eg unresolved arp)
++ *
++ * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
++ * in here instead. It is up to the 802.2 layer to carry protocol information.
+ */
+-
+ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+- void *daddr, void *saddr, unsigned len)
++ void *daddr, void *saddr, unsigned len)
+ {
+- struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
++ struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+
+- /*
+- * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
+- * in here instead. It is up to the 802.2 layer to carry protocol information.
+- */
+-
+- if(type!=ETH_P_802_3)
++ if (type != ETH_P_802_3)
+ eth->h_proto = htons(type);
+ else
+ eth->h_proto = htons(len);
+
+ /*
+- * Set the source hardware address.
++ * Set the source hardware address.
+ */
+-
+- if(!saddr)
++
++ if (!saddr)
+ saddr = dev->dev_addr;
+- memcpy(eth->h_source,saddr,dev->addr_len);
++ memcpy(eth->h_source, saddr, dev->addr_len);
+
+- if(daddr)
+- {
+- memcpy(eth->h_dest,daddr,dev->addr_len);
++ if (daddr) {
++ memcpy(eth->h_dest, daddr, dev->addr_len);
+ return ETH_HLEN;
+ }
+-
++
+ /*
+- * Anyway, the loopback-device should never use this function...
++ * Anyway, the loopback-device should never use this function...
+ */
+
+- if (dev->flags & (IFF_LOOPBACK|IFF_NOARP))
+- {
++ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+ memset(eth->h_dest, 0, dev->addr_len);
+ return ETH_HLEN;
+ }
+-
++
+ return -ETH_HLEN;
+ }
+
+-
+-/*
+- * Rebuild the Ethernet MAC header. This is called after an ARP
+- * (or in future other address resolution) has completed on this
+- * sk_buff. We now let ARP fill in the other fields.
++/**
++ * eth_rebuild_header- rebuild the Ethernet MAC header.
++ * @skb: socket buffer to update
+ *
+- * This routine CANNOT use cached dst->neigh!
+- * Really, it is used only when dst->neigh is wrong.
++ * This is called after an ARP or IPV6 ndisc it's resolution on this
++ * sk_buff. We now let protocol (ARP) fill in the other fields.
++ *
++ * This routine CANNOT use cached dst->neigh!
++ * Really, it is used only when dst->neigh is wrong.
+ */
+-
+ int eth_rebuild_header(struct sk_buff *skb)
+ {
+ struct ethhdr *eth = (struct ethhdr *)skb->data;
+ struct net_device *dev = skb->dev;
+
+- switch (eth->h_proto)
+- {
++ switch (eth->h_proto) {
+ #ifdef CONFIG_INET
+ case __constant_htons(ETH_P_IP):
+- return arp_find(eth->h_dest, skb);
+-#endif
++ return arp_find(eth->h_dest, skb);
++#endif
+ default:
+ printk(KERN_DEBUG
+- "%s: unable to resolve type %X addresses.\n",
++ "%s: unable to resolve type %X addresses.\n",
+ dev->name, (int)eth->h_proto);
+-
++
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ break;
+ }
+@@ -146,62 +144,70 @@ int eth_rebuild_header(struct sk_buff *s
+ return 0;
+ }
+
+-
+-/*
+- * Determine the packet's protocol ID. The rule here is that we
+- * 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.
++/**
++ * eth_type_trans - determine the packet's protocol ID.
++ * @skb: received socket data
++ * @dev: receiving network device
++ *
++ * The rule here is that we
++ * 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.
+ */
+-
+ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct ethhdr *eth;
+ unsigned char *rawp;
+-
++
+ skb->mac.raw = skb->data;
+- skb_pull(skb,ETH_HLEN);
++ skb_pull(skb, ETH_HLEN);
+ eth = eth_hdr(skb);
+-
++
+ if (is_multicast_ether_addr(eth->h_dest)) {
+ if (!compare_ether_addr(eth->h_dest, dev->broadcast))
+ skb->pkt_type = PACKET_BROADCAST;
+ else
+ skb->pkt_type = PACKET_MULTICAST;
+ }
+-
++
+ /*
+- * This ALLMULTI check should be redundant by 1.4
+- * so don't forget to remove it.
++ * This ALLMULTI check should be redundant by 1.4
++ * so don't forget to remove it.
+ *
+- * Seems, you forgot to remove it. All silly devices
+- * seems to set IFF_PROMISC.
++ * Seems, you forgot to remove it. All silly devices
++ * seems to set IFF_PROMISC.
+ */
+-
+- else if(1 /*dev->flags&IFF_PROMISC*/) {
++
++ else if (1 /*dev->flags&IFF_PROMISC */ ) {
+ if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))
+ skb->pkt_type = PACKET_OTHERHOST;
+ }
+-
++
+ if (ntohs(eth->h_proto) >= 1536)
+ return eth->h_proto;
+-
++
+ rawp = skb->data;
+-
++
+ /*
+- * This is a magic hack to spot IPX packets. Older Novell breaks
+- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+- * won't work for fault tolerant netware but does for the rest.
++ * This is a magic hack to spot IPX packets. Older Novell breaks
++ * the protocol design and runs IPX over 802.3 without an 802.2 LLC
++ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
++ * won't work for fault tolerant netware but does for the rest.
+ */
+ if (*(unsigned short *)rawp == 0xFFFF)
+ return htons(ETH_P_802_3);
+-
++
+ /*
+- * Real 802.2 LLC
++ * Real 802.2 LLC
+ */
+ return htons(ETH_P_802_2);
+ }
++EXPORT_SYMBOL(eth_type_trans);
+
++/**
++ * eth_header_parse - extract hardware address from packet
++ * @skb: packet to extract header from
++ * @haddr: destination buffer
++ */
+ static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr)
+ {
+ struct ethhdr *eth = eth_hdr(skb);
+@@ -209,14 +215,20 @@ static int eth_header_parse(struct sk_bu
+ return ETH_ALEN;
+ }
+
++/**
++ * eth_header_cache - fill cache entry from neighbour
++ * @neigh: source neighbour
++ * @hh: destination cache entry
++ * Create an Ethernet header template from the neighbour.
++ */
+ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+ {
+- unsigned short type = hh->hh_type;
++ __be16 type = hh->hh_type;
+ struct ethhdr *eth;
+ struct net_device *dev = neigh->dev;
+
+- eth = (struct ethhdr*)
+- (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
++ eth = (struct ethhdr *)
++ (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
+
+ if (type == __constant_htons(ETH_P_802_3))
+ return -1;
+@@ -228,27 +240,47 @@ int eth_header_cache(struct neighbour *n
+ return 0;
+ }
+
+-/*
++/**
++ * eth_header_cache_update - update cache entry
++ * @hh: destination cache entry
++ * @dev: network device
++ * @haddr: new hardware address
++ *
+ * Called by Address Resolution module to notify changes in address.
+ */
+-
+-void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
++void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev,
++ unsigned char *haddr)
+ {
+- memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
++ memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
+ haddr, dev->addr_len);
+ }
+
+-EXPORT_SYMBOL(eth_type_trans);
+-
++/**
++ * eth_mac_addr - set new Ethernet hardware address
++ * @dev: network device
++ * @p: socket address
++ * Change hardware address of device.
++ *
++ * This doesn't change hardware matching, so needs to be overridden
++ * for most real devices.
++ */
+ static int eth_mac_addr(struct net_device *dev, void *p)
+ {
+- struct sockaddr *addr=p;
++ struct sockaddr *addr = p;
+ if (netif_running(dev))
+ return -EBUSY;
+- memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ return 0;
+ }
+
++/**
++ * eth_change_mtu - set new MTU size
++ * @dev: network device
++ * @new_mtu: new Maximum Transfer Unit
++ *
++ * Allow changing MTU size. Needs to be overridden for devices
++ * supporting jumbo frames.
++ */
+ static int eth_change_mtu(struct net_device *dev, int new_mtu)
+ {
+ if (new_mtu < 68 || new_mtu > ETH_DATA_LEN)
+@@ -257,8 +289,10 @@ static int eth_change_mtu(struct net_dev
+ return 0;
+ }
+
+-/*
+- * Fill in the fields of the device structure with ethernet-generic values.
++/**
++ * ether_setup - setup Ethernet network device
++ * @dev: network device
++ * Fill in the fields of the device structure with Ethernet-generic values.
+ */
+ void ether_setup(struct net_device *dev)
+ {
+@@ -277,21 +311,21 @@ void ether_setup(struct net_device *dev)
+ dev->tx_queue_len = 1000; /* Ethernet wants good queues */
+ dev->flags = IFF_BROADCAST|IFF_MULTICAST;
+
+- memset(dev->broadcast,0xFF, ETH_ALEN);
++ memset(dev->broadcast, 0xFF, ETH_ALEN);
+
+ }
+ EXPORT_SYMBOL(ether_setup);
+
+ /**
+- * alloc_etherdev - Allocates and sets up an ethernet device
++ * alloc_etherdev - Allocates and sets up an Ethernet device
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+- * for this ethernet device
++ * for this Ethernet device
+ *
+- * Fill in the fields of the device structure with ethernet-generic
++ * Fill in the fields of the device structure with Ethernet-generic
+ * values. Basically does everything except registering the device.
+ *
+ * Constructs a new net device, complete with a private data area of
+- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
++ * size (sizeof_priv). A 32-byte (not bit) alignment is enforced for
+ * this private data area.
+ */
+
+diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
+index f7e84e9..a64be6c 100644
+--- a/net/ieee80211/Kconfig
++++ b/net/ieee80211/Kconfig
+@@ -32,6 +32,7 @@ config IEEE80211_CRYPT_WEP
+ depends on IEEE80211
+ select CRYPTO
+ select CRYPTO_ARC4
++ select CRYPTO_ECB
+ select CRC32
+ ---help---
+ Include software based cipher suites in support of IEEE
+@@ -58,6 +59,7 @@ config IEEE80211_CRYPT_TKIP
+ depends on IEEE80211 && NET_RADIO
+ select CRYPTO
+ select CRYPTO_MICHAEL_MIC
++ select CRYPTO_ECB
+ select CRC32
+ ---help---
+ Include software based cipher suites in support of IEEE 802.11i
+diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
+index ed90a8a..35aa342 100644
+--- a/net/ieee80211/ieee80211_crypt_ccmp.c
++++ b/net/ieee80211/ieee80211_crypt_ccmp.c
+@@ -9,6 +9,7 @@
+ * more details.
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -48,7 +49,7 @@ struct ieee80211_ccmp_data {
+
+ int key_idx;
+
+- struct crypto_tfm *tfm;
++ struct crypto_cipher *tfm;
+
+ /* scratch buffers for virt_to_page() (crypto API) */
+ u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
+@@ -56,20 +57,10 @@ struct ieee80211_ccmp_data {
+ u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
+ };
+
+-static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
+- const u8 pt[16], u8 ct[16])
++static inline void ieee80211_ccmp_aes_encrypt(struct crypto_cipher *tfm,
++ const u8 pt[16], u8 ct[16])
+ {
+- struct scatterlist src, dst;
+-
+- src.page = virt_to_page(pt);
+- src.offset = offset_in_page(pt);
+- src.length = AES_BLOCK_LEN;
+-
+- dst.page = virt_to_page(ct);
+- dst.offset = offset_in_page(ct);
+- dst.length = AES_BLOCK_LEN;
+-
+- crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
++ crypto_cipher_encrypt_one(tfm, ct, pt);
+ }
+
+ static void *ieee80211_ccmp_init(int key_idx)
+@@ -81,10 +72,11 @@ static void *ieee80211_ccmp_init(int key
+ goto fail;
+ priv->key_idx = key_idx;
+
+- priv->tfm = crypto_alloc_tfm("aes", 0);
+- if (priv->tfm == NULL) {
++ priv->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->tfm)) {
+ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
+ "crypto API aes\n");
++ priv->tfm = NULL;
+ goto fail;
+ }
+
+@@ -93,7 +85,7 @@ static void *ieee80211_ccmp_init(int key
+ fail:
+ if (priv) {
+ if (priv->tfm)
+- crypto_free_tfm(priv->tfm);
++ crypto_free_cipher(priv->tfm);
+ kfree(priv);
+ }
+
+@@ -104,7 +96,7 @@ static void ieee80211_ccmp_deinit(void *
+ {
+ struct ieee80211_ccmp_data *_priv = priv;
+ if (_priv && _priv->tfm)
+- crypto_free_tfm(_priv->tfm);
++ crypto_free_cipher(_priv->tfm);
+ kfree(priv);
+ }
+
+@@ -115,7 +107,7 @@ static inline void xor_block(u8 * b, u8
+ b[i] ^= a[i];
+ }
+
+-static void ccmp_init_blocks(struct crypto_tfm *tfm,
++static void ccmp_init_blocks(struct crypto_cipher *tfm,
+ struct ieee80211_hdr_4addr *hdr,
+ u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0)
+ {
+@@ -271,6 +263,27 @@ static int ieee80211_ccmp_encrypt(struct
+ return 0;
+ }
+
++/*
++ * deal with seq counter wrapping correctly.
++ * refer to timer_after() for jiffies wrapping handling
++ */
++static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
++{
++ u32 iv32_n, iv16_n;
++ u32 iv32_o, iv16_o;
++
++ iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3];
++ iv16_n = (pn_n[4] << 8) | pn_n[5];
++
++ iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3];
++ iv16_o = (pn_o[4] << 8) | pn_o[5];
++
++ if ((s32)iv32_n - (s32)iv32_o < 0 ||
++ (iv32_n == iv32_o && iv16_n <= iv16_o))
++ return 1;
++ return 0;
++}
++
+ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+ {
+ struct ieee80211_ccmp_data *key = priv;
+@@ -323,7 +336,7 @@ static int ieee80211_ccmp_decrypt(struct
+ pn[5] = pos[0];
+ pos += 8;
+
+- if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
++ if (ccmp_replay_check(pn, key->rx_pn)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+ " previous PN %02x%02x%02x%02x%02x%02x "
+@@ -377,7 +390,7 @@ static int ieee80211_ccmp_set_key(void *
+ {
+ struct ieee80211_ccmp_data *data = priv;
+ int keyidx;
+- struct crypto_tfm *tfm = data->tfm;
++ struct crypto_cipher *tfm = data->tfm;
+
+ keyidx = data->key_idx;
+ memset(data, 0, sizeof(*data));
+diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
+index 34dba0b..4200ec5 100644
+--- a/net/ieee80211/ieee80211_crypt_tkip.c
++++ b/net/ieee80211/ieee80211_crypt_tkip.c
+@@ -9,6 +9,7 @@
+ * more details.
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -52,8 +53,10 @@ struct ieee80211_tkip_data {
+
+ int key_idx;
+
+- struct crypto_tfm *tfm_arc4;
+- struct crypto_tfm *tfm_michael;
++ struct crypto_blkcipher *rx_tfm_arc4;
++ struct crypto_hash *rx_tfm_michael;
++ struct crypto_blkcipher *tx_tfm_arc4;
++ struct crypto_hash *tx_tfm_michael;
+
+ /* scratch buffers for virt_to_page() (crypto API) */
+ u8 rx_hdr[16], tx_hdr[16];
+@@ -85,17 +88,39 @@ static void *ieee80211_tkip_init(int key
+
+ priv->key_idx = key_idx;
+
+- priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
+- if (priv->tfm_arc4 == NULL) {
++ priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->tx_tfm_arc4)) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API arc4\n");
++ priv->tx_tfm_arc4 = NULL;
+ goto fail;
+ }
+
+- priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
+- if (priv->tfm_michael == NULL) {
++ priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->tx_tfm_michael)) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API michael_mic\n");
++ priv->tx_tfm_michael = NULL;
++ goto fail;
++ }
++
++ priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->rx_tfm_arc4)) {
++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
++ "crypto API arc4\n");
++ priv->rx_tfm_arc4 = NULL;
++ goto fail;
++ }
++
++ priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->rx_tfm_michael)) {
++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
++ "crypto API michael_mic\n");
++ priv->rx_tfm_michael = NULL;
+ goto fail;
+ }
+
+@@ -103,10 +128,14 @@ static void *ieee80211_tkip_init(int key
+
+ fail:
+ if (priv) {
+- if (priv->tfm_michael)
+- crypto_free_tfm(priv->tfm_michael);
+- if (priv->tfm_arc4)
+- crypto_free_tfm(priv->tfm_arc4);
++ if (priv->tx_tfm_michael)
++ crypto_free_hash(priv->tx_tfm_michael);
++ if (priv->tx_tfm_arc4)
++ crypto_free_blkcipher(priv->tx_tfm_arc4);
++ if (priv->rx_tfm_michael)
++ crypto_free_hash(priv->rx_tfm_michael);
++ if (priv->rx_tfm_arc4)
++ crypto_free_blkcipher(priv->rx_tfm_arc4);
+ kfree(priv);
+ }
+
+@@ -116,10 +145,16 @@ static void *ieee80211_tkip_init(int key
+ static void ieee80211_tkip_deinit(void *priv)
+ {
+ struct ieee80211_tkip_data *_priv = priv;
+- if (_priv && _priv->tfm_michael)
+- crypto_free_tfm(_priv->tfm_michael);
+- if (_priv && _priv->tfm_arc4)
+- crypto_free_tfm(_priv->tfm_arc4);
++ if (_priv) {
++ if (_priv->tx_tfm_michael)
++ crypto_free_hash(_priv->tx_tfm_michael);
++ if (_priv->tx_tfm_arc4)
++ crypto_free_blkcipher(_priv->tx_tfm_arc4);
++ if (_priv->rx_tfm_michael)
++ crypto_free_hash(_priv->rx_tfm_michael);
++ if (_priv->rx_tfm_arc4)
++ crypto_free_blkcipher(_priv->rx_tfm_arc4);
++ }
+ kfree(priv);
+ }
+
+@@ -318,6 +353,7 @@ static int ieee80211_tkip_hdr(struct sk_
+ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+ {
+ struct ieee80211_tkip_data *tkey = priv;
++ struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
+ int len;
+ u8 rc4key[16], *pos, *icv;
+ u32 crc;
+@@ -351,18 +387,30 @@ static int ieee80211_tkip_encrypt(struct
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+
+- crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
++ crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = len + 4;
+- crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
++ return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
++}
+
++/*
++ * deal with seq counter wrapping correctly.
++ * refer to timer_after() for jiffies wrapping handling
++ */
++static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
++ u32 iv32_o, u16 iv16_o)
++{
++ if ((s32)iv32_n - (s32)iv32_o < 0 ||
++ (iv32_n == iv32_o && iv16_n <= iv16_o))
++ return 1;
+ return 0;
+ }
+
+ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+ {
+ struct ieee80211_tkip_data *tkey = priv;
++ struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
+ u8 rc4key[16];
+ u8 keyidx, *pos;
+ u32 iv32;
+@@ -414,8 +462,7 @@ static int ieee80211_tkip_decrypt(struct
+ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+ pos += 8;
+
+- if (iv32 < tkey->rx_iv32 ||
+- (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
++ if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ " previous TSC %08x%04x received TSC "
+@@ -434,11 +481,18 @@ static int ieee80211_tkip_decrypt(struct
+
+ plen = skb->len - hdr_len - 12;
+
+- crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
++ crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = plen + 4;
+- crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
++ if (net_ratelimit()) {
++ printk(KERN_DEBUG ": TKIP: failed to decrypt "
++ "received packet from " MAC_FMT "\n",
++ MAC_ARG(hdr->addr2));
++ }
++ return -7;
++ }
+
+ crc = ~crc32_le(~0, pos, plen);
+ icv[0] = crc;
+@@ -472,12 +526,13 @@ static int ieee80211_tkip_decrypt(struct
+ return keyidx;
+ }
+
+-static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
++static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
+ u8 * data, size_t data_len, u8 * mic)
+ {
++ struct hash_desc desc;
+ struct scatterlist sg[2];
+
+- if (tkey->tfm_michael == NULL) {
++ if (tfm_michael == NULL) {
+ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+ return -1;
+ }
+@@ -489,12 +544,12 @@ static int michael_mic(struct ieee80211_
+ sg[1].offset = offset_in_page(data);
+ sg[1].length = data_len;
+
+- crypto_digest_init(tkey->tfm_michael);
+- crypto_digest_setkey(tkey->tfm_michael, key, 8);
+- crypto_digest_update(tkey->tfm_michael, sg, 2);
+- crypto_digest_final(tkey->tfm_michael, mic);
++ if (crypto_hash_setkey(tfm_michael, key, 8))
++ return -1;
+
+- return 0;
++ desc.tfm = tfm_michael;
++ desc.flags = 0;
++ return crypto_hash_digest(&desc, sg, data_len + 16, mic);
+ }
+
+ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
+@@ -528,7 +583,7 @@ static void michael_mic_hdr(struct sk_bu
+ if (stype & IEEE80211_STYPE_QOS_DATA) {
+ const struct ieee80211_hdr_3addrqos *qoshdr =
+ (struct ieee80211_hdr_3addrqos *)skb->data;
+- hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID;
++ hdr[12] = qoshdr->qos_ctl & cpu_to_le16(IEEE80211_QCTL_TID);
+ } else
+ hdr[12] = 0; /* priority */
+
+@@ -550,7 +605,7 @@ static int ieee80211_michael_mic_add(str
+
+ michael_mic_hdr(skb, tkey->tx_hdr);
+ pos = skb_put(skb, 8);
+- if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
++ if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
+ return -1;
+
+@@ -588,7 +643,7 @@ static int ieee80211_michael_mic_verify(
+ return -1;
+
+ michael_mic_hdr(skb, tkey->rx_hdr);
+- if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
++ if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
+ return -1;
+ if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+@@ -618,14 +673,18 @@ static int ieee80211_tkip_set_key(void *
+ {
+ struct ieee80211_tkip_data *tkey = priv;
+ int keyidx;
+- struct crypto_tfm *tfm = tkey->tfm_michael;
+- struct crypto_tfm *tfm2 = tkey->tfm_arc4;
++ struct crypto_hash *tfm = tkey->tx_tfm_michael;
++ struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
++ struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
++ struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
+
+ keyidx = tkey->key_idx;
+ memset(tkey, 0, sizeof(*tkey));
+ tkey->key_idx = keyidx;
+- tkey->tfm_michael = tfm;
+- tkey->tfm_arc4 = tfm2;
++ tkey->tx_tfm_michael = tfm;
++ tkey->tx_tfm_arc4 = tfm2;
++ tkey->rx_tfm_michael = tfm3;
++ tkey->rx_tfm_arc4 = tfm4;
+ if (len == TKIP_KEY_LEN) {
+ memcpy(tkey->key, key, TKIP_KEY_LEN);
+ tkey->key_set = 1;
+diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
+index 0ebf235..1b2efff 100644
+--- a/net/ieee80211/ieee80211_crypt_wep.c
++++ b/net/ieee80211/ieee80211_crypt_wep.c
+@@ -9,6 +9,7 @@
+ * more details.
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -32,7 +33,8 @@ struct prism2_wep_data {
+ u8 key[WEP_KEY_LEN + 1];
+ u8 key_len;
+ u8 key_idx;
+- struct crypto_tfm *tfm;
++ struct crypto_blkcipher *tx_tfm;
++ struct crypto_blkcipher *rx_tfm;
+ };
+
+ static void *prism2_wep_init(int keyidx)
+@@ -44,13 +46,21 @@ static void *prism2_wep_init(int keyidx)
+ goto fail;
+ priv->key_idx = keyidx;
+
+- priv->tfm = crypto_alloc_tfm("arc4", 0);
+- if (priv->tfm == NULL) {
++ priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->tx_tfm)) {
+ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
+ "crypto API arc4\n");
++ priv->tx_tfm = NULL;
+ goto fail;
+ }
+
++ priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(priv->rx_tfm)) {
++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
++ "crypto API arc4\n");
++ priv->rx_tfm = NULL;
++ goto fail;
++ }
+ /* start WEP IV from a random value */
+ get_random_bytes(&priv->iv, 4);
+
+@@ -58,8 +68,10 @@ static void *prism2_wep_init(int keyidx)
+
+ fail:
+ if (priv) {
+- if (priv->tfm)
+- crypto_free_tfm(priv->tfm);
++ if (priv->tx_tfm)
++ crypto_free_blkcipher(priv->tx_tfm);
++ if (priv->rx_tfm)
++ crypto_free_blkcipher(priv->rx_tfm);
+ kfree(priv);
+ }
+ return NULL;
+@@ -68,8 +80,12 @@ static void *prism2_wep_init(int keyidx)
+ static void prism2_wep_deinit(void *priv)
+ {
+ struct prism2_wep_data *_priv = priv;
+- if (_priv && _priv->tfm)
+- crypto_free_tfm(_priv->tfm);
++ if (_priv) {
++ if (_priv->tx_tfm)
++ crypto_free_blkcipher(_priv->tx_tfm);
++ if (_priv->rx_tfm)
++ crypto_free_blkcipher(_priv->rx_tfm);
++ }
+ kfree(priv);
+ }
+
+@@ -120,6 +136,7 @@ static int prism2_wep_build_iv(struct sk
+ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+ {
+ struct prism2_wep_data *wep = priv;
++ struct blkcipher_desc desc = { .tfm = wep->tx_tfm };
+ u32 crc, klen, len;
+ u8 *pos, *icv;
+ struct scatterlist sg;
+@@ -151,13 +168,11 @@ static int prism2_wep_encrypt(struct sk_
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+
+- crypto_cipher_setkey(wep->tfm, key, klen);
++ crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = len + 4;
+- crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
+-
+- return 0;
++ return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ }
+
+ /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
+@@ -170,6 +185,7 @@ static int prism2_wep_encrypt(struct sk_
+ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+ {
+ struct prism2_wep_data *wep = priv;
++ struct blkcipher_desc desc = { .tfm = wep->rx_tfm };
+ u32 crc, klen, plen;
+ u8 key[WEP_KEY_LEN + 3];
+ u8 keyidx, *pos, icv[4];
+@@ -194,11 +210,12 @@ static int prism2_wep_decrypt(struct sk_
+ /* Apply RC4 to data and compute CRC32 over decrypted data */
+ plen = skb->len - hdr_len - 8;
+
+- crypto_cipher_setkey(wep->tfm, key, klen);
++ crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = plen + 4;
+- crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
++ return -7;
+
+ crc = ~crc32_le(~0, pos, plen);
+ icv[0] = crc;
+diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
+index 72d4d4e..2759312 100644
+--- a/net/ieee80211/ieee80211_rx.c
++++ b/net/ieee80211/ieee80211_rx.c
+@@ -779,33 +779,44 @@ int ieee80211_rx(struct ieee80211_device
+ return 0;
+ }
+
+-/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
+-int ieee80211_rx_any(struct ieee80211_device *ieee,
++/* Filter out unrelated packets, call ieee80211_rx[_mgt]
++ * This function takes over the skb, it should not be used again after calling
++ * this function. */
++void ieee80211_rx_any(struct ieee80211_device *ieee,
+ struct sk_buff *skb, struct ieee80211_rx_stats *stats)
+ {
+ struct ieee80211_hdr_4addr *hdr;
+ int is_packet_for_us;
+ u16 fc;
+
+- if (ieee->iw_mode == IW_MODE_MONITOR)
+- return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
++ if (ieee->iw_mode == IW_MODE_MONITOR) {
++ if (!ieee80211_rx(ieee, skb, stats))
++ dev_kfree_skb_irq(skb);
++ return;
++ }
++
++ if (skb->len < sizeof(struct ieee80211_hdr))
++ goto drop_free;
+
+ hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ if ((fc & IEEE80211_FCTL_VERS) != 0)
+- return -EINVAL;
++ goto drop_free;
+
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_MGMT:
++ if (skb->len < sizeof(struct ieee80211_hdr_3addr))
++ goto drop_free;
+ ieee80211_rx_mgt(ieee, hdr, stats);
+- return 0;
++ dev_kfree_skb_irq(skb);
++ return;
+ case IEEE80211_FTYPE_DATA:
+ break;
+ case IEEE80211_FTYPE_CTL:
+- return 0;
++ return;
+ default:
+- return -EINVAL;
++ return;
+ }
+
+ is_packet_for_us = 0;
+@@ -849,8 +860,14 @@ int ieee80211_rx_any(struct ieee80211_de
+ }
+
+ if (is_packet_for_us)
+- return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
+- return 0;
++ if (!ieee80211_rx(ieee, skb, stats))
++ dev_kfree_skb_irq(skb);
++ return;
++
++drop_free:
++ dev_kfree_skb_irq(skb);
++ ieee->stats.rx_dropped++;
++ return;
+ }
+
+ #define MGMT_FRAME_FIXED_PART_LENGTH 0x24
+@@ -1067,7 +1084,10 @@ static int ieee80211_parse_info_param(st
+ info_element->len +
+ sizeof(*info_element),
+ length, info_element->id);
+- return 1;
++ /* We stop processing but don't return an error here
++ * because some misbehaviour APs break this rule. ie.
++ * Orinoco AP1000. */
++ break;
+ }
+
+ switch (info_element->id) {
+@@ -1166,6 +1186,7 @@ static int ieee80211_parse_info_param(st
+
+ case MFIE_TYPE_ERP_INFO:
+ network->erp_value = info_element->data[0];
++ network->flags |= NETWORK_HAS_ERP_VALUE;
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
+ network->erp_value);
+ break;
+@@ -1729,5 +1750,6 @@ void ieee80211_rx_mgt(struct ieee80211_d
+ }
+ }
+
++EXPORT_SYMBOL_GPL(ieee80211_rx_any);
+ EXPORT_SYMBOL(ieee80211_rx_mgt);
+ EXPORT_SYMBOL(ieee80211_rx);
+diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
+index bf04213..ae25449 100644
+--- a/net/ieee80211/ieee80211_tx.c
++++ b/net/ieee80211/ieee80211_tx.c
+@@ -337,7 +337,7 @@ int ieee80211_xmit(struct sk_buff *skb,
+ hdr_len += 2;
+
+ skb->priority = ieee80211_classify(skb);
+- header.qos_ctl |= skb->priority & IEEE80211_QCTL_TID;
++ header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID);
+ }
+ header.frame_ctl = cpu_to_le16(fc);
+
+@@ -532,13 +532,6 @@ int ieee80211_xmit(struct sk_buff *skb,
+ return 0;
+ }
+
+- if (ret == NETDEV_TX_BUSY) {
+- printk(KERN_ERR "%s: NETDEV_TX_BUSY returned; "
+- "driver should report queue full via "
+- "ieee_device->is_queue_full.\n",
+- ieee->dev->name);
+- }
+-
+ ieee80211_txb_free(txb);
+ }
+
+diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
+index 44215ce..cf51c87 100644
+--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
++++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
+@@ -48,7 +48,7 @@ ieee80211softmac_assoc(struct ieee80211s
+ dprintk(KERN_INFO PFX "sent association request!\n");
+
+ spin_lock_irqsave(&mac->lock, flags);
+- mac->associated = 0; /* just to make sure */
++ mac->associnfo.associated = 0; /* just to make sure */
+
+ /* Set a timer for timeout */
+ /* FIXME: make timeout configurable */
+@@ -62,24 +62,22 @@ ieee80211softmac_assoc_timeout(void *d)
+ {
+ struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+ struct ieee80211softmac_network *n;
+- unsigned long flags;
+
+- spin_lock_irqsave(&mac->lock, flags);
++ mutex_lock(&mac->associnfo.mutex);
+ /* we might race against ieee80211softmac_handle_assoc_response,
+ * so make sure only one of us does something */
+- if (!mac->associnfo.associating) {
+- spin_unlock_irqrestore(&mac->lock, flags);
+- return;
+- }
++ if (!mac->associnfo.associating)
++ goto out;
+ mac->associnfo.associating = 0;
+ mac->associnfo.bssvalid = 0;
+- mac->associated = 0;
++ mac->associnfo.associated = 0;
+
+ n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
+- spin_unlock_irqrestore(&mac->lock, flags);
+
+ dprintk(KERN_INFO PFX "assoc request timed out!\n");
+ ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
++out:
++ mutex_unlock(&mac->associnfo.mutex);
+ }
+
+ void
+@@ -93,10 +91,10 @@ ieee80211softmac_disassoc(struct ieee802
+
+ netif_carrier_off(mac->dev);
+
+- mac->associated = 0;
++ mac->associnfo.associated = 0;
+ mac->associnfo.bssvalid = 0;
+ mac->associnfo.associating = 0;
+- ieee80211softmac_init_txrates(mac);
++ ieee80211softmac_init_bss(mac);
+ ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
+ spin_unlock_irqrestore(&mac->lock, flags);
+ }
+@@ -107,7 +105,7 @@ ieee80211softmac_send_disassoc_req(struc
+ {
+ struct ieee80211softmac_network *found;
+
+- if (mac->associnfo.bssvalid && mac->associated) {
++ if (mac->associnfo.bssvalid && mac->associnfo.associated) {
+ found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
+ if (found)
+ ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
+@@ -196,17 +194,18 @@ ieee80211softmac_assoc_work(void *d)
+ int bssvalid;
+ unsigned long flags;
+
++ mutex_lock(&mac->associnfo.mutex);
++
++ if (!mac->associnfo.associating)
++ goto out;
++
+ /* ieee80211_disassoc might clear this */
+ bssvalid = mac->associnfo.bssvalid;
+
+ /* meh */
+- if (mac->associated)
++ if (mac->associnfo.associated)
+ ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
+
+- spin_lock_irqsave(&mac->lock, flags);
+- mac->associnfo.associating = 1;
+- spin_unlock_irqrestore(&mac->lock, flags);
+-
+ /* try to find the requested network in our list, if we found one already */
+ if (bssvalid || mac->associnfo.bssfixed)
+ found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
+@@ -260,10 +259,8 @@ ieee80211softmac_assoc_work(void *d)
+
+ if (!found) {
+ if (mac->associnfo.scan_retry > 0) {
+- spin_lock_irqsave(&mac->lock, flags);
+ mac->associnfo.scan_retry--;
+- spin_unlock_irqrestore(&mac->lock, flags);
+-
++
+ /* We know of no such network. Let's scan.
+ * NB: this also happens if we had no memory to copy the network info...
+ * Maybe we can hope to have more memory after scanning finishes ;)
+@@ -272,19 +269,17 @@ ieee80211softmac_assoc_work(void *d)
+ ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
+ if (ieee80211softmac_start_scan(mac))
+ dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
+- return;
++ goto out;
+ } else {
+- spin_lock_irqsave(&mac->lock, flags);
+ mac->associnfo.associating = 0;
+- mac->associated = 0;
+- spin_unlock_irqrestore(&mac->lock, flags);
++ mac->associnfo.associated = 0;
+
+ dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
+ /* reset the retry counter for the next user request since we
+ * break out and don't reschedule ourselves after this point. */
+ mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
+ ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
+- return;
++ goto out;
+ }
+ }
+
+@@ -297,7 +292,7 @@ ieee80211softmac_assoc_work(void *d)
+ /* copy the ESSID for displaying it */
+ mac->associnfo.associate_essid.len = found->essid.len;
+ memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
+-
++
+ /* we found a network! authenticate (if necessary) and associate to it. */
+ if (found->authenticating) {
+ dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
+@@ -305,7 +300,7 @@ ieee80211softmac_assoc_work(void *d)
+ mac->associnfo.assoc_wait = 1;
+ ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ }
+- return;
++ goto out;
+ }
+ if (!found->authenticated && !found->authenticating) {
+ /* This relies on the fact that _auth_req only queues the work,
+@@ -321,11 +316,14 @@ ieee80211softmac_assoc_work(void *d)
+ mac->associnfo.assoc_wait = 0;
+ ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
+ }
+- return;
++ goto out;
+ }
+ /* finally! now we can start associating */
+ mac->associnfo.assoc_wait = 0;
+ ieee80211softmac_assoc(mac, found);
++
++out:
++ mutex_unlock(&mac->associnfo.mutex);
+ }
+
+ /* call this to do whatever is necessary when we're associated */
+@@ -334,11 +332,19 @@ ieee80211softmac_associated(struct ieee8
+ struct ieee80211_assoc_response * resp,
+ struct ieee80211softmac_network *net)
+ {
++ u16 cap = le16_to_cpu(resp->capability);
++ u8 erp_value = net->erp_value;
++
+ mac->associnfo.associating = 0;
+- mac->associnfo.supported_rates = net->supported_rates;
++ mac->bssinfo.supported_rates = net->supported_rates;
+ ieee80211softmac_recalc_txrates(mac);
+
+- mac->associated = 1;
++ mac->associnfo.associated = 1;
++
++ mac->associnfo.short_preamble_available =
++ (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
++ ieee80211softmac_process_erp(mac, erp_value);
++
+ if (mac->set_bssid_filter)
+ mac->set_bssid_filter(mac->dev, net->bssid);
+ memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
+@@ -351,9 +357,9 @@ ieee80211softmac_associated(struct ieee8
+ int
+ ieee80211softmac_handle_assoc_response(struct net_device * dev,
+ struct ieee80211_assoc_response * resp,
+- struct ieee80211_network * _ieee80211_network_do_not_use)
++ struct ieee80211_network * _ieee80211_network)
+ {
+- /* NOTE: the network parameter has to be ignored by
++ /* NOTE: the network parameter has to be mostly ignored by
+ * this code because it is the ieee80211's pointer
+ * to the struct, not ours (we made a copy)
+ */
+@@ -385,6 +391,11 @@ ieee80211softmac_handle_assoc_response(s
+ /* now that we know it was for us, we can cancel the timeout */
+ cancel_delayed_work(&mac->associnfo.timeout);
+
++ /* if the association response included an ERP IE, update our saved
++ * copy */
++ if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
++ network->erp_value = _ieee80211_network->erp_value;
++
+ switch (status) {
+ case 0:
+ dprintk(KERN_INFO PFX "associated!\n");
+@@ -408,7 +419,7 @@ ieee80211softmac_handle_assoc_response(s
+ dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
+ mac->associnfo.associating = 0;
+ mac->associnfo.bssvalid = 0;
+- mac->associated = 0;
++ mac->associnfo.associated = 0;
+ ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
+ }
+
+diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
+index 6ae5a1d..b969310 100644
+--- a/net/ieee80211/softmac/ieee80211softmac_io.c
++++ b/net/ieee80211/softmac/ieee80211softmac_io.c
+@@ -304,7 +304,7 @@ ieee80211softmac_auth(struct ieee80211_a
+ 2 + /* Auth Transaction Seq */
+ 2 + /* Status Code */
+ /* Challenge Text IE */
+- is_shared_response ? 0 : 1 + 1 + net->challenge_len
++ (is_shared_response ? 1 + 1 + net->challenge_len : 0)
+ );
+ if (unlikely((*pkt) == NULL))
+ return 0;
+@@ -467,3 +467,22 @@ ieee80211softmac_send_mgt_frame(struct i
+ kfree(pkt);
+ return 0;
+ }
++
++/* Beacon handling */
++int ieee80211softmac_handle_beacon(struct net_device *dev,
++ struct ieee80211_beacon *beacon,
++ struct ieee80211_network *network)
++{
++ struct ieee80211softmac_device *mac = ieee80211_priv(dev);
++
++ /* This might race, but we don't really care and it's not worth
++ * adding heavyweight locking in this fastpath.
++ */
++ if (mac->associnfo.associated) {
++ if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
++ ieee80211softmac_process_erp(mac, network->erp_value);
++ }
++
++ return 0;
++}
++
+diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
+index 4b2e57d..33aff4f 100644
+--- a/net/ieee80211/softmac/ieee80211softmac_module.c
++++ b/net/ieee80211/softmac/ieee80211softmac_module.c
+@@ -44,6 +44,7 @@ struct net_device *alloc_ieee80211softma
+ softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
+ softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
+ softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
++ softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
+ softmac->scaninfo = NULL;
+
+ softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
+@@ -56,6 +57,7 @@ struct net_device *alloc_ieee80211softma
+ INIT_LIST_HEAD(&softmac->network_list);
+ INIT_LIST_HEAD(&softmac->events);
+
++ mutex_init(&softmac->associnfo.mutex);
+ INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
+ INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
+ softmac->start_scan = ieee80211softmac_start_scan_implementation;
+@@ -178,21 +180,14 @@ int ieee80211softmac_ratesinfo_rate_supp
+ return 0;
+ }
+
+-/* Finds the highest rate which is:
+- * 1. Present in ri (optionally a basic rate)
+- * 2. Supported by the device
+- * 3. Less than or equal to the user-defined rate
+- */
+-static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
++u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
+ struct ieee80211softmac_ratesinfo *ri, int basic_only)
+ {
+ u8 user_rate = mac->txrates.user_rate;
+ int i;
+
+- if (ri->count == 0) {
+- dprintk(KERN_ERR PFX "empty ratesinfo?\n");
++ if (ri->count == 0)
+ return IEEE80211_CCK_RATE_1MB;
+- }
+
+ for (i = ri->count - 1; i >= 0; i--) {
+ u8 rate = ri->rates[i];
+@@ -208,36 +203,61 @@ static u8 highest_supported_rate(struct
+ /* If we haven't found a suitable rate by now, just trust the user */
+ return user_rate;
+ }
++EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
++
++void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
++ u8 erp_value)
++{
++ int use_protection;
++ int short_preamble;
++ u32 changes = 0;
++
++ /* Barker preamble mode */
++ short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
++ && mac->associnfo.short_preamble_available) ? 1 : 0;
++
++ /* Protection needed? */
++ use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
++
++ if (mac->bssinfo.short_preamble != short_preamble) {
++ changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
++ mac->bssinfo.short_preamble = short_preamble;
++ }
++
++ if (mac->bssinfo.use_protection != use_protection) {
++ changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
++ mac->bssinfo.use_protection = use_protection;
++ }
++
++ if (mac->bssinfo_change && changes)
++ mac->bssinfo_change(mac->dev, changes);
++}
+
+ void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
+ {
+ struct ieee80211softmac_txrates *txrates = &mac->txrates;
+- struct ieee80211softmac_txrates oldrates;
+ u32 change = 0;
+
+- if (mac->txrates_change)
+- oldrates = mac->txrates;
+-
+ change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
+- txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
++ txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
+
+ change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
+ txrates->default_fallback = lower_rate(mac, txrates->default_rate);
+
+ change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
+- txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
++ txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
+
+ if (mac->txrates_change)
+- mac->txrates_change(mac->dev, change, &oldrates);
++ mac->txrates_change(mac->dev, change);
+
+ }
+
+-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
++void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
+ {
+ struct ieee80211_device *ieee = mac->ieee;
+ u32 change = 0;
+ struct ieee80211softmac_txrates *txrates = &mac->txrates;
+- struct ieee80211softmac_txrates oldrates;
++ struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
+
+ /* TODO: We need some kind of state machine to lower the default rates
+ * if we loose too many packets.
+@@ -245,8 +265,6 @@ void ieee80211softmac_init_txrates(struc
+ /* Change the default txrate to the highest possible value.
+ * The txrate machine will lower it, if it is too high.
+ */
+- if (mac->txrates_change)
+- oldrates = mac->txrates;
+ /* FIXME: We don't correctly handle backing down to lower
+ rates, so 801.11g devices start off at 11M for now. People
+ can manually change it if they really need to, but 11M is
+@@ -272,7 +290,23 @@ void ieee80211softmac_init_txrates(struc
+ change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
+
+ if (mac->txrates_change)
+- mac->txrates_change(mac->dev, change, &oldrates);
++ mac->txrates_change(mac->dev, change);
++
++ change = 0;
++
++ bssinfo->supported_rates.count = 0;
++ memset(bssinfo->supported_rates.rates, 0,
++ sizeof(bssinfo->supported_rates.rates));
++ change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
++
++ bssinfo->short_preamble = 0;
++ change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
++
++ bssinfo->use_protection = 0;
++ change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
++
++ if (mac->bssinfo_change)
++ mac->bssinfo_change(mac->dev, change);
+
+ mac->running = 1;
+ }
+@@ -282,7 +316,7 @@ void ieee80211softmac_start(struct net_d
+ struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+
+ ieee80211softmac_start_check_rates(mac);
+- ieee80211softmac_init_txrates(mac);
++ ieee80211softmac_init_bss(mac);
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_start);
+
+@@ -335,7 +369,6 @@ u8 ieee80211softmac_lower_rate_delta(str
+ static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
+ int amount)
+ {
+- struct ieee80211softmac_txrates oldrates;
+ u8 default_rate = mac->txrates.default_rate;
+ u8 default_fallback = mac->txrates.default_fallback;
+ u32 changes = 0;
+@@ -348,8 +381,6 @@ printk("badness %d\n", mac->txrate_badne
+ mac->txrate_badness += amount;
+ if (mac->txrate_badness <= -1000) {
+ /* Very small badness. Try a faster bitrate. */
+- if (mac->txrates_change)
+- memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
+ default_rate = raise_rate(mac, default_rate);
+ changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
+ default_fallback = get_fallback_rate(mac, default_rate);
+@@ -358,8 +389,6 @@ printk("badness %d\n", mac->txrate_badne
+ printk("Bitrate raised to %u\n", default_rate);
+ } else if (mac->txrate_badness >= 10000) {
+ /* Very high badness. Try a slower bitrate. */
+- if (mac->txrates_change)
+- memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
+ default_rate = lower_rate(mac, default_rate);
+ changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
+ default_fallback = get_fallback_rate(mac, default_rate);
+@@ -372,7 +401,7 @@ printk("Bitrate lowered to %u\n", defaul
+ mac->txrates.default_fallback = default_fallback;
+
+ if (changes && mac->txrates_change)
+- mac->txrates_change(mac->dev, changes, &oldrates);
++ mac->txrates_change(mac->dev, changes);
+ }
+
+ void ieee80211softmac_fragment_lost(struct net_device *dev,
+@@ -416,7 +445,11 @@ ieee80211softmac_create_network(struct i
+ memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
+ softnet->supported_rates.count += net->rates_ex_len;
+ sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
+-
++
++ /* we save the ERP value because it is needed at association time, and
++ * many AP's do not include an ERP IE in the association response. */
++ softnet->erp_value = net->erp_value;
++
+ softnet->capabilities = net->capability;
+ return softnet;
+ }
+diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
+index fa1f8e3..0642e09 100644
+--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
++++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
+@@ -116,9 +116,11 @@ ieee80211softmac_get_network_by_essid(st
+ struct ieee80211softmac_essid *essid);
+
+ /* Rates related */
++void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
++ u8 erp_value);
+ int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
+ u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
+-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
++void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
+ void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
+ static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
+ return ieee80211softmac_lower_rate_delta(mac, rate, 1);
+@@ -133,6 +135,9 @@ static inline u8 get_fallback_rate(struc
+ /*** prototypes from _io.c */
+ int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
+ void* ptrarg, u32 type, u32 arg);
++int ieee80211softmac_handle_beacon(struct net_device *dev,
++ struct ieee80211_beacon *beacon,
++ struct ieee80211_network *network);
+
+ /*** prototypes from _auth.c */
+ /* do these have to go into the public header? */
+@@ -189,6 +194,7 @@ struct ieee80211softmac_network {
+ authenticated:1,
+ auth_desynced_once:1;
+
++ u8 erp_value; /* Saved ERP value */
+ u16 capabilities; /* Capabilities bitfield */
+ u8 challenge_len; /* Auth Challenge length */
+ char *challenge; /* Challenge Text */
+diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
+index 75320b6..23068a8 100644
+--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
++++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
+@@ -73,24 +73,24 @@ ieee80211softmac_wx_set_essid(struct net
+ struct ieee80211softmac_network *n;
+ struct ieee80211softmac_auth_queue_item *authptr;
+ int length = 0;
+- unsigned long flags;
++
++ mutex_lock(&sm->associnfo.mutex);
+
+ /* Check if we're already associating to this or another network
+ * If it's another network, cancel and start over with our new network
+ * If it's our network, ignore the change, we're already doing it!
+ */
+- if((sm->associnfo.associating || sm->associated) &&
+- (data->essid.flags && data->essid.length && extra)) {
++ if((sm->associnfo.associating || sm->associnfo.associated) &&
++ (data->essid.flags && data->essid.length)) {
+ /* Get the associating network */
+ n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
+- if(n && n->essid.len == (data->essid.length - 1) &&
++ if(n && n->essid.len == data->essid.length &&
+ !memcmp(n->essid.data, extra, n->essid.len)) {
+ dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
+ MAC_ARG(sm->associnfo.bssid));
+- return 0;
++ goto out;
+ } else {
+ dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
+- spin_lock_irqsave(&sm->lock,flags);
+ /* Cancel assoc work */
+ cancel_delayed_work(&sm->associnfo.work);
+ /* We don't have to do this, but it's a little cleaner */
+@@ -98,19 +98,18 @@ ieee80211softmac_wx_set_essid(struct net
+ cancel_delayed_work(&authptr->work);
+ sm->associnfo.bssvalid = 0;
+ sm->associnfo.bssfixed = 0;
+- spin_unlock_irqrestore(&sm->lock,flags);
+ flush_scheduled_work();
++ sm->associnfo.associating = 0;
++ sm->associnfo.associated = 0;
+ }
+ }
+
+
+- spin_lock_irqsave(&sm->lock, flags);
+-
+ sm->associnfo.static_essid = 0;
+ sm->associnfo.assoc_wait = 0;
+
+- if (data->essid.flags && data->essid.length && extra /*required?*/) {
+- length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
++ if (data->essid.flags && data->essid.length) {
++ length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
+ if (length) {
+ memcpy(sm->associnfo.req_essid.data, extra, length);
+ sm->associnfo.static_essid = 1;
+@@ -121,10 +120,12 @@ ieee80211softmac_wx_set_essid(struct net
+ * If applicable, we have already copied the data in */
+ sm->associnfo.req_essid.len = length;
+
++ sm->associnfo.associating = 1;
+ /* queue lower level code to do work (if necessary) */
+ schedule_work(&sm->associnfo.work);
++out:
++ mutex_unlock(&sm->associnfo.mutex);
+
+- spin_unlock_irqrestore(&sm->lock, flags);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
+@@ -136,10 +137,8 @@ ieee80211softmac_wx_get_essid(struct net
+ char *extra)
+ {
+ struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+- unsigned long flags;
+
+- /* avoid getting inconsistent information */
+- spin_lock_irqsave(&sm->lock, flags);
++ mutex_lock(&sm->associnfo.mutex);
+ /* If all fails, return ANY (empty) */
+ data->essid.length = 0;
+ data->essid.flags = 0; /* active */
+@@ -152,12 +151,13 @@ ieee80211softmac_wx_get_essid(struct net
+ }
+
+ /* If we're associating/associated, return that */
+- if (sm->associated || sm->associnfo.associating) {
++ if (sm->associnfo.associated || sm->associnfo.associating) {
+ data->essid.length = sm->associnfo.associate_essid.len;
+ data->essid.flags = 1; /* active */
+ memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
+ }
+- spin_unlock_irqrestore(&sm->lock, flags);
++ mutex_unlock(&sm->associnfo.mutex);
++
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
+@@ -322,15 +322,15 @@ ieee80211softmac_wx_get_wap(struct net_d
+ {
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+ int err = 0;
+- unsigned long flags;
+
+- spin_lock_irqsave(&mac->lock, flags);
++ mutex_lock(&mac->associnfo.mutex);
+ if (mac->associnfo.bssvalid)
+ memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
+ else
+ memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
+ data->ap_addr.sa_family = ARPHRD_ETHER;
+- spin_unlock_irqrestore(&mac->lock, flags);
++ mutex_unlock(&mac->associnfo.mutex);
++
+ return err;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
+@@ -342,28 +342,27 @@ ieee80211softmac_wx_set_wap(struct net_d
+ char *extra)
+ {
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+- unsigned long flags;
+
+ /* sanity check */
+ if (data->ap_addr.sa_family != ARPHRD_ETHER) {
+ return -EINVAL;
+ }
+
+- spin_lock_irqsave(&mac->lock, flags);
++ mutex_lock(&mac->associnfo.mutex);
+ if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
+ /* the bssid we have is not to be fixed any longer,
+ * and we should reassociate to the best AP. */
+ mac->associnfo.bssfixed = 0;
+ /* force reassociation */
+ mac->associnfo.bssvalid = 0;
+- if (mac->associated)
++ if (mac->associnfo.associated)
+ schedule_work(&mac->associnfo.work);
+ } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
+ /* the bssid we have is no longer fixed */
+ mac->associnfo.bssfixed = 0;
+ } else {
+ if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
+- if (mac->associnfo.associating || mac->associated) {
++ if (mac->associnfo.associating || mac->associnfo.associated) {
+ /* bssid unchanged and associated or associating - just return */
+ goto out;
+ }
+@@ -378,7 +377,8 @@ ieee80211softmac_wx_set_wap(struct net_d
+ }
+
+ out:
+- spin_unlock_irqrestore(&mac->lock, flags);
++ mutex_unlock(&mac->associnfo.mutex);
++
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
+@@ -394,7 +394,8 @@ ieee80211softmac_wx_set_genie(struct net
+ int err = 0;
+ char *buf;
+ int i;
+-
++
++ mutex_lock(&mac->associnfo.mutex);
+ spin_lock_irqsave(&mac->lock, flags);
+ /* bleh. shouldn't be locked for that kmalloc... */
+
+@@ -432,6 +433,8 @@ ieee80211softmac_wx_set_genie(struct net
+
+ out:
+ spin_unlock_irqrestore(&mac->lock, flags);
++ mutex_unlock(&mac->associnfo.mutex);
++
+ return err;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
+@@ -446,7 +449,8 @@ ieee80211softmac_wx_get_genie(struct net
+ unsigned long flags;
+ int err = 0;
+ int space = wrqu->data.length;
+-
++
++ mutex_lock(&mac->associnfo.mutex);
+ spin_lock_irqsave(&mac->lock, flags);
+
+ wrqu->data.length = 0;
+@@ -459,6 +463,8 @@ ieee80211softmac_wx_get_genie(struct net
+ err = -E2BIG;
+ }
+ spin_unlock_irqrestore(&mac->lock, flags);
++ mutex_lock(&mac->associnfo.mutex);
++
+ return err;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
+@@ -473,10 +479,13 @@ ieee80211softmac_wx_set_mlme(struct net_
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ u16 reason = cpu_to_le16(mlme->reason_code);
+ struct ieee80211softmac_network *net;
++ int err = -EINVAL;
++
++ mutex_lock(&mac->associnfo.mutex);
+
+ if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
+ printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
+- return -EINVAL;
++ goto out;
+ }
+
+ switch (mlme->cmd) {
+@@ -484,14 +493,22 @@ ieee80211softmac_wx_set_mlme(struct net_
+ net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
+ if (!net) {
+ printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
+- return -EINVAL;
++ goto out;
+ }
+ return ieee80211softmac_deauth_req(mac, net, reason);
+ case IW_MLME_DISASSOC:
+ ieee80211softmac_send_disassoc_req(mac, reason);
+- return 0;
++ mac->associnfo.associated = 0;
++ mac->associnfo.associating = 0;
++ err = 0;
++ goto out;
+ default:
+- return -EOPNOTSUPP;
++ err = -EOPNOTSUPP;
+ }
++
++out:
++ mutex_unlock(&mac->associnfo.mutex);
++
++ return err;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);
+diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
+index 8514106..5572071 100644
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -64,7 +64,7 @@ config ASK_IP_FIB_HASH
+ config IP_FIB_TRIE
+ bool "FIB_TRIE"
+ ---help---
+- Use new experimental LC-trie as FIB lookup algoritm.
++ Use new experimental LC-trie as FIB lookup algorithm.
+ This improves lookup performance if you have a large
+ number of routes.
+
+@@ -88,6 +88,7 @@ config IP_FIB_HASH
+ config IP_MULTIPLE_TABLES
+ bool "IP: policy routing"
+ depends on IP_ADVANCED_ROUTER
++ select FIB_RULES
+ ---help---
+ Normally, a router decides what to do with a received packet based
+ solely on the packet's final destination address. If you say Y here,
+@@ -386,6 +387,7 @@ config INET_ESP
+ select CRYPTO
+ select CRYPTO_HMAC
+ select CRYPTO_MD5
++ select CRYPTO_CBC
+ select CRYPTO_SHA1
+ select CRYPTO_DES
+ ---help---
+@@ -432,6 +434,15 @@ config INET_XFRM_MODE_TUNNEL
+
+ If unsure, say Y.
+
++config INET_XFRM_MODE_BEET
++ tristate "IP: IPsec BEET mode"
++ default y
++ select XFRM
++ ---help---
++ Support for IPsec BEET mode.
++
++ If unsure, say Y.
++
+ config INET_DIAG
+ tristate "INET: socket monitoring interface"
+ default y
+@@ -446,24 +457,22 @@ config INET_TCP_DIAG
+ depends on INET_DIAG
+ def_tristate INET_DIAG
+
+-config TCP_CONG_ADVANCED
++menuconfig 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).
++ selection will be made (CUBIC 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
++if TCP_CONG_ADVANCED
+
+ config TCP_CONG_BIC
+ tristate "Binary Increase Congestion (BIC) control"
+- default y
++ default m
+ ---help---
+ BIC-TCP is a sender-side only change that ensures a linear RTT
+ fairness under large windows while offering both scalability and
+@@ -477,7 +486,7 @@ config TCP_CONG_BIC
+
+ config TCP_CONG_CUBIC
+ tristate "CUBIC TCP"
+- default m
++ default y
+ ---help---
+ This is version 2.0 of BIC-TCP which uses a cubic growth function
+ among other techniques.
+@@ -526,7 +535,7 @@ config TCP_CONG_HYBLA
+ ---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
++ involved, especially when sharing a common bottleneck with normal
+ terrestrial connections.
+
+ config TCP_CONG_VEGAS
+@@ -556,7 +565,7 @@ config TCP_CONG_LP
+ default n
+ ---help---
+ TCP Low Priority (TCP-LP), a distributed algorithm whose goal is
+- to utiliza only the excess network bandwidth as compared to the
++ to utilize only the excess network bandwidth as compared to the
+ ``fair share`` of bandwidth as targeted by TCP.
+ See http://www-ece.rice.edu/networks/TCP-LP/
+
+@@ -572,12 +581,49 @@ config TCP_CONG_VENO
+ loss packets.
+ See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf
+
+-endmenu
++choice
++ prompt "Default TCP congestion control"
++ default DEFAULT_CUBIC
++ help
++ Select the TCP congestion control that will be used by default
++ for all connections.
+
+-config TCP_CONG_BIC
++ config DEFAULT_BIC
++ bool "Bic" if TCP_CONG_BIC=y
++
++ config DEFAULT_CUBIC
++ bool "Cubic" if TCP_CONG_CUBIC=y
++
++ config DEFAULT_HTCP
++ bool "Htcp" if TCP_CONG_HTCP=y
++
++ config DEFAULT_VEGAS
++ bool "Vegas" if TCP_CONG_VEGAS=y
++
++ config DEFAULT_WESTWOOD
++ bool "Westwood" if TCP_CONG_WESTWOOD=y
++
++ config DEFAULT_RENO
++ bool "Reno"
++
++endchoice
++
++endif
++
++config TCP_CONG_CUBIC
+ tristate
+ depends on !TCP_CONG_ADVANCED
+ default y
+
++config DEFAULT_TCP_CONG
++ string
++ default "bic" if DEFAULT_BIC
++ default "cubic" if DEFAULT_CUBIC
++ default "htcp" if DEFAULT_HTCP
++ default "vegas" if DEFAULT_VEGAS
++ default "westwood" if DEFAULT_WESTWOOD
++ default "reno" if DEFAULT_RENO
++ default "cubic"
++
+ source "net/ipv4/ipvs/Kconfig"
+
+diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
+index 4878fc5..15645c5 100644
+--- a/net/ipv4/Makefile
++++ b/net/ipv4/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_INET_AH) += ah4.o
+ obj-$(CONFIG_INET_ESP) += esp4.o
+ obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
+ obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
++obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
+ obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
+ obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
+ obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
+@@ -47,6 +48,7 @@ obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vega
+ obj-$(CONFIG_TCP_CONG_VENO) += tcp_veno.o
+ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
+ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
++obj-$(CONFIG_NETLABEL) += cipso_ipv4.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 c84a320..edcf093 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -67,7 +67,6 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
+-#include <linux/config.h>
+ #include <linux/err.h>
+ #include <linux/errno.h>
+ #include <linux/types.h>
+@@ -392,7 +391,7 @@ int inet_release(struct socket *sock)
+ }
+
+ /* It is off by default, see below. */
+-int sysctl_ip_nonlocal_bind;
++int sysctl_ip_nonlocal_bind __read_mostly;
+
+ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+ {
+@@ -988,7 +987,7 @@ void inet_unregister_protosw(struct inet
+ * Shall we try to damage output packets if routing dev changes?
+ */
+
+-int sysctl_ip_dynaddr;
++int sysctl_ip_dynaddr __read_mostly;
+
+ static int inet_sk_reselect_saddr(struct sock *sk)
+ {
+@@ -997,7 +996,7 @@ static int inet_sk_reselect_saddr(struct
+ struct rtable *rt;
+ __u32 old_saddr = inet->saddr;
+ __u32 new_saddr;
+- __u32 daddr = inet->daddr;
++ __be32 daddr = inet->daddr;
+
+ if (inet->opt && inet->opt->srr)
+ daddr = inet->opt->faddr;
+@@ -1044,7 +1043,7 @@ int inet_sk_rebuild_header(struct sock *
+ {
+ struct inet_sock *inet = inet_sk(sk);
+ struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
+- u32 daddr;
++ __be32 daddr;
+ int err;
+
+ /* Route is OK, nothing to do. */
+@@ -1074,6 +1073,7 @@ int inet_sk_rebuild_header(struct sock *
+ },
+ };
+
++ security_sk_classify_flow(sk, &fl);
+ err = ip_route_output_flow(&rt, &fl, sk, 0);
+ }
+ if (!err)
+@@ -1254,10 +1254,7 @@ static int __init inet_init(void)
+ struct list_head *r;
+ int rc = -EINVAL;
+
+- if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
+- printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
+- goto out;
+- }
++ BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));
+
+ rc = proto_register(&tcp_prot, 1);
+ if (rc)
+@@ -1345,10 +1342,10 @@ static int __init inet_init(void)
+ rc = 0;
+ out:
+ return rc;
+-out_unregister_tcp_proto:
+- proto_unregister(&tcp_prot);
+ out_unregister_udp_proto:
+ proto_unregister(&udp_prot);
++out_unregister_tcp_proto:
++ proto_unregister(&tcp_prot);
+ goto out;
+ }
+
+diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
+index 1366bc6..9954297 100644
+--- a/net/ipv4/ah4.c
++++ b/net/ipv4/ah4.c
+@@ -1,3 +1,4 @@
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <net/ip.h>
+ #include <net/xfrm.h>
+@@ -34,7 +35,7 @@ static int ip_clear_mutable_options(stru
+ switch (*optptr) {
+ case IPOPT_SEC:
+ case 0x85: /* Some "Extended Security" crap. */
+- case 0x86: /* Another "Commercial Security" crap. */
++ case IPOPT_CIPSO:
+ case IPOPT_RA:
+ case 0x80|21: /* RFC1770 */
+ break;
+@@ -97,7 +98,10 @@ static int ah_output(struct xfrm_state *
+ ah->spi = x->id.spi;
+ ah->seq_no = htonl(++x->replay.oseq);
+ xfrm_aevent_doreplay(x);
+- ahp->icv(ahp, skb, ah->auth_data);
++ err = ah_mac_digest(ahp, skb, ah->auth_data);
++ if (err)
++ goto error;
++ memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
+
+ top_iph->tos = iph->tos;
+ top_iph->ttl = iph->ttl;
+@@ -119,6 +123,7 @@ static int ah_input(struct xfrm_state *x
+ {
+ int ah_hlen;
+ int ihl;
++ int err = -EINVAL;
+ struct iphdr *iph;
+ struct ip_auth_hdr *ah;
+ struct ah_data *ahp;
+@@ -166,8 +171,11 @@ static int ah_input(struct xfrm_state *x
+
+ memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
+ skb_push(skb, ihl);
+- ahp->icv(ahp, skb, ah->auth_data);
+- if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
++ err = ah_mac_digest(ahp, skb, ah->auth_data);
++ if (err)
++ goto out;
++ err = -EINVAL;
++ if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
+ x->stats.integrity_failed++;
+ goto out;
+ }
+@@ -179,7 +187,7 @@ static int ah_input(struct xfrm_state *x
+ return 0;
+
+ out:
+- return -EINVAL;
++ return err;
+ }
+
+ static void ah4_err(struct sk_buff *skb, u32 info)
+@@ -204,6 +212,7 @@ static int ah_init_state(struct xfrm_sta
+ {
+ struct ah_data *ahp = NULL;
+ struct xfrm_algo_desc *aalg_desc;
++ struct crypto_hash *tfm;
+
+ if (!x->aalg)
+ goto error;
+@@ -221,24 +230,27 @@ static int ah_init_state(struct xfrm_sta
+
+ ahp->key = x->aalg->alg_key;
+ ahp->key_len = (x->aalg->alg_key_len+7)/8;
+- ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
+- if (!ahp->tfm)
++ tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm))
++ goto error;
++
++ ahp->tfm = tfm;
++ if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))
+ goto error;
+- ahp->icv = ah_hmac_digest;
+
+ /*
+ * Lookup the algorithm description maintained by xfrm_algo,
+ * verify crypto transform properties, and store information
+ * we need for AH processing. This lookup cannot fail here
+- * after a successful crypto_alloc_tfm().
++ * after a successful crypto_alloc_hash().
+ */
+ aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
+ BUG_ON(!aalg_desc);
+
+ if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+- crypto_tfm_alg_digestsize(ahp->tfm)) {
++ crypto_hash_digestsize(tfm)) {
+ printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
+- x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm),
++ x->aalg->alg_name, crypto_hash_digestsize(tfm),
+ aalg_desc->uinfo.auth.icv_fullbits/8);
+ goto error;
+ }
+@@ -253,7 +265,7 @@ static int ah_init_state(struct xfrm_sta
+ goto error;
+
+ x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len);
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ x->props.header_len += sizeof(struct iphdr);
+ x->data = ahp;
+
+@@ -262,7 +274,7 @@ static int ah_init_state(struct xfrm_sta
+ error:
+ if (ahp) {
+ kfree(ahp->work_icv);
+- crypto_free_tfm(ahp->tfm);
++ crypto_free_hash(ahp->tfm);
+ kfree(ahp);
+ }
+ return -EINVAL;
+@@ -277,7 +289,7 @@ static void ah_destroy(struct xfrm_state
+
+ kfree(ahp->work_icv);
+ ahp->work_icv = NULL;
+- crypto_free_tfm(ahp->tfm);
++ crypto_free_hash(ahp->tfm);
+ ahp->tfm = NULL;
+ kfree(ahp);
+ }
+diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
+index c8a3723..cfb5d3d 100644
+--- a/net/ipv4/arp.c
++++ b/net/ipv4/arp.c
+@@ -1,4 +1,4 @@
+-/* linux/net/inet/arp.c
++/* linux/net/ipv4/arp.c
+ *
+ * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $
+ *
+@@ -234,7 +234,7 @@ static u32 arp_hash(const void *pkey, co
+
+ static int arp_constructor(struct neighbour *neigh)
+ {
+- u32 addr = *(u32*)neigh->primary_key;
++ __be32 addr = *(__be32*)neigh->primary_key;
+ struct net_device *dev = neigh->dev;
+ struct in_device *in_dev;
+ struct neigh_parms *parms;
+@@ -330,10 +330,10 @@ static void arp_error_report(struct neig
+
+ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+ {
+- u32 saddr = 0;
++ __be32 saddr = 0;
+ u8 *dst_ha = NULL;
+ struct net_device *dev = neigh->dev;
+- u32 target = *(u32*)neigh->primary_key;
++ __be32 target = *(__be32*)neigh->primary_key;
+ int probes = atomic_read(&neigh->probes);
+ struct in_device *in_dev = in_dev_get(dev);
+
+@@ -385,7 +385,7 @@ static void arp_solicit(struct neighbour
+ }
+
+ static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
+- u32 sip, u32 tip)
++ __be32 sip, __be32 tip)
+ {
+ int scope;
+
+@@ -420,7 +420,7 @@ static int arp_ignore(struct in_device *
+ return !inet_confirm_addr(dev, sip, tip, scope);
+ }
+
+-static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
++static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
+ {
+ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
+ .saddr = tip } } };
+@@ -449,7 +449,7 @@ static int arp_filter(__u32 sip, __u32 t
+ * is allowed to use this function, it is scheduled to be removed. --ANK
+ */
+
+-static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct net_device * dev)
++static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev)
+ {
+ switch (addr_hint) {
+ case RTN_LOCAL:
+@@ -470,7 +470,7 @@ static int arp_set_predefined(int addr_h
+ int arp_find(unsigned char *haddr, struct sk_buff *skb)
+ {
+ struct net_device *dev = skb->dev;
+- u32 paddr;
++ __be32 paddr;
+ struct neighbour *n;
+
+ if (!skb->dst) {
+@@ -511,7 +511,7 @@ int arp_bind_neighbour(struct dst_entry
+ if (dev == NULL)
+ return -EINVAL;
+ if (n == NULL) {
+- u32 nexthop = ((struct rtable*)dst)->rt_gateway;
++ __be32 nexthop = ((struct rtable*)dst)->rt_gateway;
+ if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
+ nexthop = 0;
+ n = __neigh_lookup_errno(
+@@ -560,8 +560,8 @@ static inline int arp_fwd_proxy(struct i
+ * Create an arp packet. If (dest_hw == NULL), we create a broadcast
+ * message.
+ */
+-struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
+- struct net_device *dev, u32 src_ip,
++struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
++ struct net_device *dev, __be32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw,
+ unsigned char *target_hw)
+ {
+@@ -675,8 +675,8 @@ void arp_xmit(struct sk_buff *skb)
+ /*
+ * Create and send an arp packet.
+ */
+-void arp_send(int type, int ptype, u32 dest_ip,
+- struct net_device *dev, u32 src_ip,
++void arp_send(int type, int ptype, __be32 dest_ip,
++ struct net_device *dev, __be32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw,
+ unsigned char *target_hw)
+ {
+@@ -710,7 +710,7 @@ static int arp_process(struct sk_buff *s
+ unsigned char *arp_ptr;
+ struct rtable *rt;
+ unsigned char *sha, *tha;
+- u32 sip, tip;
++ __be32 sip, tip;
+ u16 dev_type = dev->type;
+ int addr_type;
+ struct neighbour *n;
+@@ -969,13 +969,13 @@ out_of_mem:
+
+ static int arp_req_set(struct arpreq *r, struct net_device * dev)
+ {
+- u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
++ __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+ struct neighbour *neigh;
+ int err;
+
+ if (r->arp_flags&ATF_PUBL) {
+- u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
+- if (mask && mask != 0xFFFFFFFF)
++ __be32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
++ if (mask && mask != htonl(0xFFFFFFFF))
+ return -EINVAL;
+ if (!dev && (r->arp_flags & ATF_COM)) {
+ dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data);
+@@ -1063,7 +1063,7 @@ static unsigned arp_state_to_flags(struc
+
+ static int arp_req_get(struct arpreq *r, struct net_device *dev)
+ {
+- u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
++ __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+ struct neighbour *neigh;
+ int err = -ENXIO;
+
+@@ -1084,13 +1084,13 @@ static int arp_req_get(struct arpreq *r,
+ static int arp_req_delete(struct arpreq *r, struct net_device * dev)
+ {
+ int err;
+- u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
++ __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
+ struct neighbour *neigh;
+
+ if (r->arp_flags & ATF_PUBL) {
+- u32 mask =
++ __be32 mask =
+ ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
+- if (mask == 0xFFFFFFFF)
++ if (mask == htonl(0xFFFFFFFF))
+ return pneigh_delete(&arp_tbl, &ip, dev);
+ if (mask == 0) {
+ if (dev == NULL) {
+diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
+new file mode 100644
+index 0000000..6460233
+--- /dev/null
++++ b/net/ipv4/cipso_ipv4.c
+@@ -0,0 +1,1481 @@
++/*
++ * CIPSO - Commercial IP Security Option
++ *
++ * This is an implementation of the CIPSO 2.2 protocol as specified in
++ * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
++ * FIPS-188, copies of both documents can be found in the Documentation
++ * directory. While CIPSO never became a full IETF RFC standard many vendors
++ * have chosen to adopt the protocol and over the years it has become a
++ * de-facto standard for labeled networking.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/init.h>
++#include <linux/types.h>
++#include <linux/rcupdate.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/jhash.h>
++#include <net/ip.h>
++#include <net/icmp.h>
++#include <net/tcp.h>
++#include <net/netlabel.h>
++#include <net/cipso_ipv4.h>
++#include <asm/atomic.h>
++#include <asm/bug.h>
++
++struct cipso_v4_domhsh_entry {
++ char *domain;
++ u32 valid;
++ struct list_head list;
++ struct rcu_head rcu;
++};
++
++/* List of available DOI definitions */
++/* XXX - Updates should be minimal so having a single lock for the
++ * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
++ * okay. */
++/* XXX - This currently assumes a minimal number of different DOIs in use,
++ * if in practice there are a lot of different DOIs this list should
++ * probably be turned into a hash table or something similar so we
++ * can do quick lookups. */
++static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
++static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list);
++
++/* Label mapping cache */
++int cipso_v4_cache_enabled = 1;
++int cipso_v4_cache_bucketsize = 10;
++#define CIPSO_V4_CACHE_BUCKETBITS 7
++#define CIPSO_V4_CACHE_BUCKETS (1 << CIPSO_V4_CACHE_BUCKETBITS)
++#define CIPSO_V4_CACHE_REORDERLIMIT 10
++struct cipso_v4_map_cache_bkt {
++ spinlock_t lock;
++ u32 size;
++ struct list_head list;
++};
++struct cipso_v4_map_cache_entry {
++ u32 hash;
++ unsigned char *key;
++ size_t key_len;
++
++ struct netlbl_lsm_cache *lsm_data;
++
++ u32 activity;
++ struct list_head list;
++};
++static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
++
++/* Restricted bitmap (tag #1) flags */
++int cipso_v4_rbm_optfmt = 0;
++int cipso_v4_rbm_strictvalid = 1;
++
++/*
++ * Helper Functions
++ */
++
++/**
++ * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
++ * @bitmap: the bitmap
++ * @bitmap_len: length in bits
++ * @offset: starting offset
++ * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
++ *
++ * Description:
++ * Starting at @offset, walk the bitmap from left to right until either the
++ * desired bit is found or we reach the end. Return the bit offset, -1 if
++ * not found, or -2 if error.
++ */
++static int cipso_v4_bitmap_walk(const unsigned char *bitmap,
++ u32 bitmap_len,
++ u32 offset,
++ u8 state)
++{
++ u32 bit_spot;
++ u32 byte_offset;
++ unsigned char bitmask;
++ unsigned char byte;
++
++ /* gcc always rounds to zero when doing integer division */
++ byte_offset = offset / 8;
++ byte = bitmap[byte_offset];
++ bit_spot = offset;
++ bitmask = 0x80 >> (offset % 8);
++
++ while (bit_spot < bitmap_len) {
++ if ((state && (byte & bitmask) == bitmask) ||
++ (state == 0 && (byte & bitmask) == 0))
++ return bit_spot;
++
++ bit_spot++;
++ bitmask >>= 1;
++ if (bitmask == 0) {
++ byte = bitmap[++byte_offset];
++ bitmask = 0x80;
++ }
++ }
++
++ return -1;
++}
++
++/**
++ * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
++ * @bitmap: the bitmap
++ * @bit: the bit
++ * @state: if non-zero, set the bit (1) else clear the bit (0)
++ *
++ * Description:
++ * Set a single bit in the bitmask. Returns zero on success, negative values
++ * on error.
++ */
++static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
++ u32 bit,
++ u8 state)
++{
++ u32 byte_spot;
++ u8 bitmask;
++
++ /* gcc always rounds to zero when doing integer division */
++ byte_spot = bit / 8;
++ bitmask = 0x80 >> (bit % 8);
++ if (state)
++ bitmap[byte_spot] |= bitmask;
++ else
++ bitmap[byte_spot] &= ~bitmask;
++}
++
++/**
++ * cipso_v4_doi_domhsh_free - Frees a domain list entry
++ * @entry: the entry's RCU field
++ *
++ * Description:
++ * This function is designed to be used as a callback to the call_rcu()
++ * function so that the memory allocated to a domain list entry can be released
++ * safely.
++ *
++ */
++static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
++{
++ struct cipso_v4_domhsh_entry *ptr;
++
++ ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
++ kfree(ptr->domain);
++ kfree(ptr);
++}
++
++/**
++ * cipso_v4_cache_entry_free - Frees a cache entry
++ * @entry: the entry to free
++ *
++ * Description:
++ * This function frees the memory associated with a cache entry including the
++ * LSM cache data if there are no longer any users, i.e. reference count == 0.
++ *
++ */
++static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
++{
++ if (entry->lsm_data)
++ netlbl_secattr_cache_free(entry->lsm_data);
++ kfree(entry->key);
++ kfree(entry);
++}
++
++/**
++ * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache
++ * @key: the hash key
++ * @key_len: the length of the key in bytes
++ *
++ * Description:
++ * The CIPSO tag hashing function. Returns a 32-bit hash value.
++ *
++ */
++static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len)
++{
++ return jhash(key, key_len, 0);
++}
++
++/*
++ * Label Mapping Cache Functions
++ */
++
++/**
++ * cipso_v4_cache_init - Initialize the CIPSO cache
++ *
++ * Description:
++ * Initializes the CIPSO label mapping cache, this function should be called
++ * before any of the other functions defined in this file. Returns zero on
++ * success, negative values on error.
++ *
++ */
++static int cipso_v4_cache_init(void)
++{
++ u32 iter;
++
++ cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS,
++ sizeof(struct cipso_v4_map_cache_bkt),
++ GFP_KERNEL);
++ if (cipso_v4_cache == NULL)
++ return -ENOMEM;
++
++ for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
++ spin_lock_init(&cipso_v4_cache[iter].lock);
++ cipso_v4_cache[iter].size = 0;
++ INIT_LIST_HEAD(&cipso_v4_cache[iter].list);
++ }
++
++ return 0;
++}
++
++/**
++ * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
++ *
++ * Description:
++ * Invalidates and frees any entries in the CIPSO cache. Returns zero on
++ * success and negative values on failure.
++ *
++ */
++void cipso_v4_cache_invalidate(void)
++{
++ struct cipso_v4_map_cache_entry *entry, *tmp_entry;
++ u32 iter;
++
++ for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
++ spin_lock_bh(&cipso_v4_cache[iter].lock);
++ list_for_each_entry_safe(entry,
++ tmp_entry,
++ &cipso_v4_cache[iter].list, list) {
++ list_del(&entry->list);
++ cipso_v4_cache_entry_free(entry);
++ }
++ cipso_v4_cache[iter].size = 0;
++ spin_unlock_bh(&cipso_v4_cache[iter].lock);
++ }
++
++ return;
++}
++
++/**
++ * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
++ * @key: the buffer to check
++ * @key_len: buffer length in bytes
++ * @secattr: the security attribute struct to use
++ *
++ * Description:
++ * This function checks the cache to see if a label mapping already exists for
++ * the given key. If there is a match then the cache is adjusted and the
++ * @secattr struct is populated with the correct LSM security attributes. The
++ * cache is adjusted in the following manner if the entry is not already the
++ * first in the cache bucket:
++ *
++ * 1. The cache entry's activity counter is incremented
++ * 2. The previous (higher ranking) entry's activity counter is decremented
++ * 3. If the difference between the two activity counters is geater than
++ * CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped
++ *
++ * Returns zero on success, -ENOENT for a cache miss, and other negative values
++ * on error.
++ *
++ */
++static int cipso_v4_cache_check(const unsigned char *key,
++ u32 key_len,
++ struct netlbl_lsm_secattr *secattr)
++{
++ u32 bkt;
++ struct cipso_v4_map_cache_entry *entry;
++ struct cipso_v4_map_cache_entry *prev_entry = NULL;
++ u32 hash;
++
++ if (!cipso_v4_cache_enabled)
++ return -ENOENT;
++
++ hash = cipso_v4_map_cache_hash(key, key_len);
++ bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
++ spin_lock_bh(&cipso_v4_cache[bkt].lock);
++ list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
++ if (entry->hash == hash &&
++ entry->key_len == key_len &&
++ memcmp(entry->key, key, key_len) == 0) {
++ entry->activity += 1;
++ atomic_inc(&entry->lsm_data->refcount);
++ secattr->cache = entry->lsm_data;
++ if (prev_entry == NULL) {
++ spin_unlock_bh(&cipso_v4_cache[bkt].lock);
++ return 0;
++ }
++
++ if (prev_entry->activity > 0)
++ prev_entry->activity -= 1;
++ if (entry->activity > prev_entry->activity &&
++ entry->activity - prev_entry->activity >
++ CIPSO_V4_CACHE_REORDERLIMIT) {
++ __list_del(entry->list.prev, entry->list.next);
++ __list_add(&entry->list,
++ prev_entry->list.prev,
++ &prev_entry->list);
++ }
++
++ spin_unlock_bh(&cipso_v4_cache[bkt].lock);
++ return 0;
++ }
++ prev_entry = entry;
++ }
++ spin_unlock_bh(&cipso_v4_cache[bkt].lock);
++
++ return -ENOENT;
++}
++
++/**
++ * cipso_v4_cache_add - Add an entry to the CIPSO cache
++ * @skb: the packet
++ * @secattr: the packet's security attributes
++ *
++ * Description:
++ * Add a new entry into the CIPSO label mapping cache. Add the new entry to
++ * head of the cache bucket's list, if the cache bucket is out of room remove
++ * the last entry in the list first. It is important to note that there is
++ * currently no checking for duplicate keys. Returns zero on success,
++ * negative values on failure.
++ *
++ */
++int cipso_v4_cache_add(const struct sk_buff *skb,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val = -EPERM;
++ u32 bkt;
++ struct cipso_v4_map_cache_entry *entry = NULL;
++ struct cipso_v4_map_cache_entry *old_entry = NULL;
++ unsigned char *cipso_ptr;
++ u32 cipso_ptr_len;
++
++ if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
++ return 0;
++
++ cipso_ptr = CIPSO_V4_OPTPTR(skb);
++ cipso_ptr_len = cipso_ptr[1];
++
++ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
++ if (entry == NULL)
++ return -ENOMEM;
++ entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC);
++ if (entry->key == NULL) {
++ ret_val = -ENOMEM;
++ goto cache_add_failure;
++ }
++ memcpy(entry->key, cipso_ptr, cipso_ptr_len);
++ entry->key_len = cipso_ptr_len;
++ entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
++ atomic_inc(&secattr->cache->refcount);
++ entry->lsm_data = secattr->cache;
++
++ bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
++ spin_lock_bh(&cipso_v4_cache[bkt].lock);
++ if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
++ list_add(&entry->list, &cipso_v4_cache[bkt].list);
++ cipso_v4_cache[bkt].size += 1;
++ } else {
++ old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
++ struct cipso_v4_map_cache_entry, list);
++ list_del(&old_entry->list);
++ list_add(&entry->list, &cipso_v4_cache[bkt].list);
++ cipso_v4_cache_entry_free(old_entry);
++ }
++ spin_unlock_bh(&cipso_v4_cache[bkt].lock);
++
++ return 0;
++
++cache_add_failure:
++ if (entry)
++ cipso_v4_cache_entry_free(entry);
++ return ret_val;
++}
++
++/*
++ * DOI List Functions
++ */
++
++/**
++ * cipso_v4_doi_search - Searches for a DOI definition
++ * @doi: the DOI to search for
++ *
++ * Description:
++ * Search the DOI definition list for a DOI definition with a DOI value that
++ * matches @doi. The caller is responsibile for calling rcu_read_[un]lock().
++ * Returns a pointer to the DOI definition on success and NULL on failure.
++ */
++static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
++{
++ struct cipso_v4_doi *iter;
++
++ list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
++ if (iter->doi == doi && iter->valid)
++ return iter;
++ return NULL;
++}
++
++/**
++ * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
++ * @doi_def: the DOI structure
++ *
++ * Description:
++ * The caller defines a new DOI for use by the CIPSO engine and calls this
++ * function to add it to the list of acceptable domains. The caller must
++ * ensure that the mapping table specified in @doi_def->map meets all of the
++ * requirements of the mapping type (see cipso_ipv4.h for details). Returns
++ * zero on success and non-zero on failure.
++ *
++ */
++int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
++{
++ if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
++ return -EINVAL;
++
++ doi_def->valid = 1;
++ INIT_RCU_HEAD(&doi_def->rcu);
++ INIT_LIST_HEAD(&doi_def->dom_list);
++
++ rcu_read_lock();
++ if (cipso_v4_doi_search(doi_def->doi) != NULL)
++ goto doi_add_failure_rlock;
++ spin_lock(&cipso_v4_doi_list_lock);
++ if (cipso_v4_doi_search(doi_def->doi) != NULL)
++ goto doi_add_failure_slock;
++ list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
++ spin_unlock(&cipso_v4_doi_list_lock);
++ rcu_read_unlock();
++
++ return 0;
++
++doi_add_failure_slock:
++ spin_unlock(&cipso_v4_doi_list_lock);
++doi_add_failure_rlock:
++ rcu_read_unlock();
++ return -EEXIST;
++}
++
++/**
++ * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
++ * @doi: the DOI value
++ * @audit_secid: the LSM secid to use in the audit message
++ * @callback: the DOI cleanup/free callback
++ *
++ * Description:
++ * Removes a DOI definition from the CIPSO engine, @callback is called to
++ * free any memory. The NetLabel routines will be called to release their own
++ * LSM domain mappings as well as our own domain list. Returns zero on
++ * success and negative values on failure.
++ *
++ */
++int cipso_v4_doi_remove(u32 doi,
++ struct netlbl_audit *audit_info,
++ void (*callback) (struct rcu_head * head))
++{
++ struct cipso_v4_doi *doi_def;
++ struct cipso_v4_domhsh_entry *dom_iter;
++
++ rcu_read_lock();
++ if (cipso_v4_doi_search(doi) != NULL) {
++ spin_lock(&cipso_v4_doi_list_lock);
++ doi_def = cipso_v4_doi_search(doi);
++ if (doi_def == NULL) {
++ spin_unlock(&cipso_v4_doi_list_lock);
++ rcu_read_unlock();
++ return -ENOENT;
++ }
++ doi_def->valid = 0;
++ list_del_rcu(&doi_def->list);
++ spin_unlock(&cipso_v4_doi_list_lock);
++ list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
++ if (dom_iter->valid)
++ netlbl_domhsh_remove(dom_iter->domain,
++ audit_info);
++ cipso_v4_cache_invalidate();
++ rcu_read_unlock();
++
++ call_rcu(&doi_def->rcu, callback);
++ return 0;
++ }
++ rcu_read_unlock();
++
++ return -ENOENT;
++}
++
++/**
++ * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
++ * @doi: the DOI value
++ *
++ * Description:
++ * Searches for a valid DOI definition and if one is found it is returned to
++ * the caller. Otherwise NULL is returned. The caller must ensure that
++ * rcu_read_lock() is held while accessing the returned definition.
++ *
++ */
++struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
++{
++ return cipso_v4_doi_search(doi);
++}
++
++/**
++ * cipso_v4_doi_walk - Iterate through the DOI definitions
++ * @skip_cnt: skip past this number of DOI definitions, updated
++ * @callback: callback for each DOI definition
++ * @cb_arg: argument for the callback function
++ *
++ * Description:
++ * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
++ * For each entry call @callback, if @callback returns a negative value stop
++ * 'walking' through the list and return. Updates the value in @skip_cnt upon
++ * return. Returns zero on success, negative values on failure.
++ *
++ */
++int cipso_v4_doi_walk(u32 *skip_cnt,
++ int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
++ void *cb_arg)
++{
++ int ret_val = -ENOENT;
++ u32 doi_cnt = 0;
++ struct cipso_v4_doi *iter_doi;
++
++ rcu_read_lock();
++ list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
++ if (iter_doi->valid) {
++ if (doi_cnt++ < *skip_cnt)
++ continue;
++ ret_val = callback(iter_doi, cb_arg);
++ if (ret_val < 0) {
++ doi_cnt--;
++ goto doi_walk_return;
++ }
++ }
++
++doi_walk_return:
++ rcu_read_unlock();
++ *skip_cnt = doi_cnt;
++ return ret_val;
++}
++
++/**
++ * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
++ * @doi_def: the DOI definition
++ * @domain: the domain to add
++ *
++ * Description:
++ * Adds the @domain to the the DOI specified by @doi_def, this function
++ * should only be called by external functions (i.e. NetLabel). This function
++ * does allocate memory. Returns zero on success, negative values on failure.
++ *
++ */
++int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
++{
++ struct cipso_v4_domhsh_entry *iter;
++ struct cipso_v4_domhsh_entry *new_dom;
++
++ new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
++ if (new_dom == NULL)
++ return -ENOMEM;
++ if (domain) {
++ new_dom->domain = kstrdup(domain, GFP_KERNEL);
++ if (new_dom->domain == NULL) {
++ kfree(new_dom);
++ return -ENOMEM;
++ }
++ }
++ new_dom->valid = 1;
++ INIT_RCU_HEAD(&new_dom->rcu);
++
++ rcu_read_lock();
++ spin_lock(&cipso_v4_doi_list_lock);
++ list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
++ if (iter->valid &&
++ ((domain != NULL && iter->domain != NULL &&
++ strcmp(iter->domain, domain) == 0) ||
++ (domain == NULL && iter->domain == NULL))) {
++ spin_unlock(&cipso_v4_doi_list_lock);
++ rcu_read_unlock();
++ kfree(new_dom->domain);
++ kfree(new_dom);
++ return -EEXIST;
++ }
++ list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
++ spin_unlock(&cipso_v4_doi_list_lock);
++ rcu_read_unlock();
++
++ return 0;
++}
++
++/**
++ * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
++ * @doi_def: the DOI definition
++ * @domain: the domain to remove
++ *
++ * Description:
++ * Removes the @domain from the DOI specified by @doi_def, this function
++ * should only be called by external functions (i.e. NetLabel). Returns zero
++ * on success and negative values on error.
++ *
++ */
++int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
++ const char *domain)
++{
++ struct cipso_v4_domhsh_entry *iter;
++
++ rcu_read_lock();
++ spin_lock(&cipso_v4_doi_list_lock);
++ list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
++ if (iter->valid &&
++ ((domain != NULL && iter->domain != NULL &&
++ strcmp(iter->domain, domain) == 0) ||
++ (domain == NULL && iter->domain == NULL))) {
++ iter->valid = 0;
++ list_del_rcu(&iter->list);
++ spin_unlock(&cipso_v4_doi_list_lock);
++ rcu_read_unlock();
++ call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
++
++ return 0;
++ }
++ spin_unlock(&cipso_v4_doi_list_lock);
++ rcu_read_unlock();
++
++ return -ENOENT;
++}
++
++/*
++ * Label Mapping Functions
++ */
++
++/**
++ * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
++ * @doi_def: the DOI definition
++ * @level: the level to check
++ *
++ * Description:
++ * Checks the given level against the given DOI definition and returns a
++ * negative value if the level does not have a valid mapping and a zero value
++ * if the level is defined by the DOI.
++ *
++ */
++static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
++{
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ return 0;
++ case CIPSO_V4_MAP_STD:
++ if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
++ return 0;
++ break;
++ }
++
++ return -EFAULT;
++}
++
++/**
++ * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network
++ * @doi_def: the DOI definition
++ * @host_lvl: the host MLS level
++ * @net_lvl: the network/CIPSO MLS level
++ *
++ * Description:
++ * Perform a label mapping to translate a local MLS level to the correct
++ * CIPSO level using the given DOI definition. Returns zero on success,
++ * negative values otherwise.
++ *
++ */
++static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
++ u32 host_lvl,
++ u32 *net_lvl)
++{
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ *net_lvl = host_lvl;
++ return 0;
++ case CIPSO_V4_MAP_STD:
++ if (host_lvl < doi_def->map.std->lvl.local_size) {
++ *net_lvl = doi_def->map.std->lvl.local[host_lvl];
++ return 0;
++ }
++ break;
++ }
++
++ return -EINVAL;
++}
++
++/**
++ * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host
++ * @doi_def: the DOI definition
++ * @net_lvl: the network/CIPSO MLS level
++ * @host_lvl: the host MLS level
++ *
++ * Description:
++ * Perform a label mapping to translate a CIPSO level to the correct local MLS
++ * level using the given DOI definition. Returns zero on success, negative
++ * values otherwise.
++ *
++ */
++static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
++ u32 net_lvl,
++ u32 *host_lvl)
++{
++ struct cipso_v4_std_map_tbl *map_tbl;
++
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ *host_lvl = net_lvl;
++ return 0;
++ case CIPSO_V4_MAP_STD:
++ map_tbl = doi_def->map.std;
++ if (net_lvl < map_tbl->lvl.cipso_size &&
++ map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
++ *host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
++ return 0;
++ }
++ break;
++ }
++
++ return -EINVAL;
++}
++
++/**
++ * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid
++ * @doi_def: the DOI definition
++ * @bitmap: category bitmap
++ * @bitmap_len: bitmap length in bytes
++ *
++ * Description:
++ * Checks the given category bitmap against the given DOI definition and
++ * returns a negative value if any of the categories in the bitmap do not have
++ * a valid mapping and a zero value if all of the categories are valid.
++ *
++ */
++static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
++ const unsigned char *bitmap,
++ u32 bitmap_len)
++{
++ int cat = -1;
++ u32 bitmap_len_bits = bitmap_len * 8;
++ u32 cipso_cat_size;
++ u32 *cipso_array;
++
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ return 0;
++ case CIPSO_V4_MAP_STD:
++ cipso_cat_size = doi_def->map.std->cat.cipso_size;
++ cipso_array = doi_def->map.std->cat.cipso;
++ for (;;) {
++ cat = cipso_v4_bitmap_walk(bitmap,
++ bitmap_len_bits,
++ cat + 1,
++ 1);
++ if (cat < 0)
++ break;
++ if (cat >= cipso_cat_size ||
++ cipso_array[cat] >= CIPSO_V4_INV_CAT)
++ return -EFAULT;
++ }
++
++ if (cat == -1)
++ return 0;
++ break;
++ }
++
++ return -EFAULT;
++}
++
++/**
++ * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
++ * @doi_def: the DOI definition
++ * @host_cat: the category bitmap in host format
++ * @host_cat_len: the length of the host's category bitmap in bytes
++ * @net_cat: the zero'd out category bitmap in network/CIPSO format
++ * @net_cat_len: the length of the CIPSO bitmap in bytes
++ *
++ * Description:
++ * Perform a label mapping to translate a local MLS category bitmap to the
++ * correct CIPSO bitmap using the given DOI definition. Returns the minimum
++ * size in bytes of the network bitmap on success, negative values otherwise.
++ *
++ */
++static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
++ const unsigned char *host_cat,
++ u32 host_cat_len,
++ unsigned char *net_cat,
++ u32 net_cat_len)
++{
++ int host_spot = -1;
++ u32 net_spot;
++ u32 net_spot_max = 0;
++ u32 host_clen_bits = host_cat_len * 8;
++ u32 net_clen_bits = net_cat_len * 8;
++ u32 host_cat_size;
++ u32 *host_cat_array;
++
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ net_spot_max = host_cat_len;
++ while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0)
++ net_spot_max--;
++ if (net_spot_max > net_cat_len)
++ return -EINVAL;
++ memcpy(net_cat, host_cat, net_spot_max);
++ return net_spot_max;
++ case CIPSO_V4_MAP_STD:
++ host_cat_size = doi_def->map.std->cat.local_size;
++ host_cat_array = doi_def->map.std->cat.local;
++ for (;;) {
++ host_spot = cipso_v4_bitmap_walk(host_cat,
++ host_clen_bits,
++ host_spot + 1,
++ 1);
++ if (host_spot < 0)
++ break;
++ if (host_spot >= host_cat_size)
++ return -EPERM;
++
++ net_spot = host_cat_array[host_spot];
++ if (net_spot >= net_clen_bits)
++ return -ENOSPC;
++ cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
++
++ if (net_spot > net_spot_max)
++ net_spot_max = net_spot;
++ }
++
++ if (host_spot == -2)
++ return -EFAULT;
++
++ if (++net_spot_max % 8)
++ return net_spot_max / 8 + 1;
++ return net_spot_max / 8;
++ }
++
++ return -EINVAL;
++}
++
++/**
++ * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
++ * @doi_def: the DOI definition
++ * @net_cat: the category bitmap in network/CIPSO format
++ * @net_cat_len: the length of the CIPSO bitmap in bytes
++ * @host_cat: the zero'd out category bitmap in host format
++ * @host_cat_len: the length of the host's category bitmap in bytes
++ *
++ * Description:
++ * Perform a label mapping to translate a CIPSO bitmap to the correct local
++ * MLS category bitmap using the given DOI definition. Returns the minimum
++ * size in bytes of the host bitmap on success, negative values otherwise.
++ *
++ */
++static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
++ const unsigned char *net_cat,
++ u32 net_cat_len,
++ unsigned char *host_cat,
++ u32 host_cat_len)
++{
++ u32 host_spot;
++ u32 host_spot_max = 0;
++ int net_spot = -1;
++ u32 net_clen_bits = net_cat_len * 8;
++ u32 host_clen_bits = host_cat_len * 8;
++ u32 net_cat_size;
++ u32 *net_cat_array;
++
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ if (net_cat_len > host_cat_len)
++ return -EINVAL;
++ memcpy(host_cat, net_cat, net_cat_len);
++ return net_cat_len;
++ case CIPSO_V4_MAP_STD:
++ net_cat_size = doi_def->map.std->cat.cipso_size;
++ net_cat_array = doi_def->map.std->cat.cipso;
++ for (;;) {
++ net_spot = cipso_v4_bitmap_walk(net_cat,
++ net_clen_bits,
++ net_spot + 1,
++ 1);
++ if (net_spot < 0)
++ break;
++ if (net_spot >= net_cat_size ||
++ net_cat_array[net_spot] >= CIPSO_V4_INV_CAT)
++ return -EPERM;
++
++ host_spot = net_cat_array[net_spot];
++ if (host_spot >= host_clen_bits)
++ return -ENOSPC;
++ cipso_v4_bitmap_setbit(host_cat, host_spot, 1);
++
++ if (host_spot > host_spot_max)
++ host_spot_max = host_spot;
++ }
++
++ if (net_spot == -2)
++ return -EFAULT;
++
++ if (++host_spot_max % 8)
++ return host_spot_max / 8 + 1;
++ return host_spot_max / 8;
++ }
++
++ return -EINVAL;
++}
++
++/*
++ * Protocol Handling Functions
++ */
++
++#define CIPSO_V4_HDR_LEN 6
++
++/**
++ * cipso_v4_gentag_hdr - Generate a CIPSO option header
++ * @doi_def: the DOI definition
++ * @len: the total tag length in bytes
++ * @buf: the CIPSO option buffer
++ *
++ * Description:
++ * Write a CIPSO header into the beginning of @buffer. Return zero on success,
++ * negative values on failure.
++ *
++ */
++static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
++ u32 len,
++ unsigned char *buf)
++{
++ if (CIPSO_V4_HDR_LEN + len > 40)
++ return -ENOSPC;
++
++ buf[0] = IPOPT_CIPSO;
++ buf[1] = CIPSO_V4_HDR_LEN + len;
++ *(u32 *)&buf[2] = htonl(doi_def->doi);
++
++ return 0;
++}
++
++#define CIPSO_V4_TAG1_CAT_LEN 30
++
++/**
++ * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
++ * @doi_def: the DOI definition
++ * @secattr: the security attributes
++ * @buffer: the option buffer
++ * @buffer_len: length of buffer in bytes
++ *
++ * Description:
++ * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The
++ * actual buffer length may be larger than the indicated size due to
++ * translation between host and network category bitmaps. Returns zero on
++ * success, negative values on failure.
++ *
++ */
++static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
++ const struct netlbl_lsm_secattr *secattr,
++ unsigned char **buffer,
++ u32 *buffer_len)
++{
++ int ret_val = -EPERM;
++ unsigned char *buf = NULL;
++ u32 buf_len;
++ u32 level;
++
++ if (secattr->mls_cat) {
++ buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN,
++ GFP_ATOMIC);
++ if (buf == NULL)
++ return -ENOMEM;
++
++ ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
++ secattr->mls_cat,
++ secattr->mls_cat_len,
++ &buf[CIPSO_V4_HDR_LEN + 4],
++ CIPSO_V4_TAG1_CAT_LEN);
++ if (ret_val < 0)
++ goto gentag_failure;
++
++ /* This will send packets using the "optimized" format when
++ * possibile as specified in section 3.4.2.6 of the
++ * CIPSO draft. */
++ if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10))
++ ret_val = 10;
++
++ buf_len = 4 + ret_val;
++ } else {
++ buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC);
++ if (buf == NULL)
++ return -ENOMEM;
++ buf_len = 4;
++ }
++
++ ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);
++ if (ret_val != 0)
++ goto gentag_failure;
++
++ ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf);
++ if (ret_val != 0)
++ goto gentag_failure;
++
++ buf[CIPSO_V4_HDR_LEN] = 0x01;
++ buf[CIPSO_V4_HDR_LEN + 1] = buf_len;
++ buf[CIPSO_V4_HDR_LEN + 3] = level;
++
++ *buffer = buf;
++ *buffer_len = CIPSO_V4_HDR_LEN + buf_len;
++
++ return 0;
++
++gentag_failure:
++ kfree(buf);
++ return ret_val;
++}
++
++/**
++ * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag
++ * @doi_def: the DOI definition
++ * @tag: the CIPSO tag
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security
++ * attributes in @secattr. Return zero on success, negatives values on
++ * failure.
++ *
++ */
++static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
++ const unsigned char *tag,
++ struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val;
++ u8 tag_len = tag[1];
++ u32 level;
++
++ ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
++ if (ret_val != 0)
++ return ret_val;
++ secattr->mls_lvl = level;
++ secattr->mls_lvl_vld = 1;
++
++ if (tag_len > 4) {
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_PASS:
++ secattr->mls_cat_len = tag_len - 4;
++ break;
++ case CIPSO_V4_MAP_STD:
++ secattr->mls_cat_len =
++ doi_def->map.std->cat.local_size;
++ break;
++ }
++ secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC);
++ if (secattr->mls_cat == NULL)
++ return -ENOMEM;
++
++ ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
++ &tag[4],
++ tag_len - 4,
++ secattr->mls_cat,
++ secattr->mls_cat_len);
++ if (ret_val < 0) {
++ kfree(secattr->mls_cat);
++ return ret_val;
++ }
++ secattr->mls_cat_len = ret_val;
++ }
++
++ return 0;
++}
++
++/**
++ * cipso_v4_validate - Validate a CIPSO option
++ * @option: the start of the option, on error it is set to point to the error
++ *
++ * Description:
++ * This routine is called to validate a CIPSO option, it checks all of the
++ * fields to ensure that they are at least valid, see the draft snippet below
++ * for details. If the option is valid then a zero value is returned and
++ * the value of @option is unchanged. If the option is invalid then a
++ * non-zero value is returned and @option is adjusted to point to the
++ * offending portion of the option. From the IETF draft ...
++ *
++ * "If any field within the CIPSO options, such as the DOI identifier, is not
++ * recognized the IP datagram is discarded and an ICMP 'parameter problem'
++ * (type 12) is generated and returned. The ICMP code field is set to 'bad
++ * parameter' (code 0) and the pointer is set to the start of the CIPSO field
++ * that is unrecognized."
++ *
++ */
++int cipso_v4_validate(unsigned char **option)
++{
++ unsigned char *opt = *option;
++ unsigned char *tag;
++ unsigned char opt_iter;
++ unsigned char err_offset = 0;
++ u8 opt_len;
++ u8 tag_len;
++ struct cipso_v4_doi *doi_def = NULL;
++ u32 tag_iter;
++
++ /* caller already checks for length values that are too large */
++ opt_len = opt[1];
++ if (opt_len < 8) {
++ err_offset = 1;
++ goto validate_return;
++ }
++
++ rcu_read_lock();
++ doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2])));
++ if (doi_def == NULL) {
++ err_offset = 2;
++ goto validate_return_locked;
++ }
++
++ opt_iter = 6;
++ tag = opt + opt_iter;
++ while (opt_iter < opt_len) {
++ for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
++ if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
++ ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
++ err_offset = opt_iter;
++ goto validate_return_locked;
++ }
++
++ tag_len = tag[1];
++ if (tag_len > (opt_len - opt_iter)) {
++ err_offset = opt_iter + 1;
++ goto validate_return_locked;
++ }
++
++ switch (tag[0]) {
++ case CIPSO_V4_TAG_RBITMAP:
++ if (tag_len < 4) {
++ err_offset = opt_iter + 1;
++ goto validate_return_locked;
++ }
++
++ /* We are already going to do all the verification
++ * necessary at the socket layer so from our point of
++ * view it is safe to turn these checks off (and less
++ * work), however, the CIPSO draft says we should do
++ * all the CIPSO validations here but it doesn't
++ * really specify _exactly_ what we need to validate
++ * ... so, just make it a sysctl tunable. */
++ if (cipso_v4_rbm_strictvalid) {
++ if (cipso_v4_map_lvl_valid(doi_def,
++ tag[3]) < 0) {
++ err_offset = opt_iter + 3;
++ goto validate_return_locked;
++ }
++ if (tag_len > 4 &&
++ cipso_v4_map_cat_rbm_valid(doi_def,
++ &tag[4],
++ tag_len - 4) < 0) {
++ err_offset = opt_iter + 4;
++ goto validate_return_locked;
++ }
++ }
++ break;
++ default:
++ err_offset = opt_iter;
++ goto validate_return_locked;
++ }
++
++ tag += tag_len;
++ opt_iter += tag_len;
++ }
++
++validate_return_locked:
++ rcu_read_unlock();
++validate_return:
++ *option = opt + err_offset;
++ return err_offset;
++}
++
++/**
++ * cipso_v4_error - Send the correct reponse for a bad packet
++ * @skb: the packet
++ * @error: the error code
++ * @gateway: CIPSO gateway flag
++ *
++ * Description:
++ * Based on the error code given in @error, send an ICMP error message back to
++ * the originating host. From the IETF draft ...
++ *
++ * "If the contents of the CIPSO [option] are valid but the security label is
++ * outside of the configured host or port label range, the datagram is
++ * discarded and an ICMP 'destination unreachable' (type 3) is generated and
++ * returned. The code field of the ICMP is set to 'communication with
++ * destination network administratively prohibited' (code 9) or to
++ * 'communication with destination host administratively prohibited'
++ * (code 10). The value of the code is dependent on whether the originator
++ * of the ICMP message is acting as a CIPSO host or a CIPSO gateway. The
++ * recipient of the ICMP message MUST be able to handle either value. The
++ * same procedure is performed if a CIPSO [option] can not be added to an
++ * IP packet because it is too large to fit in the IP options area."
++ *
++ * "If the error is triggered by receipt of an ICMP message, the message is
++ * discarded and no response is permitted (consistent with general ICMP
++ * processing rules)."
++ *
++ */
++void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
++{
++ if (skb->nh.iph->protocol == IPPROTO_ICMP || error != -EACCES)
++ return;
++
++ if (gateway)
++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
++ else
++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
++}
++
++/**
++ * cipso_v4_socket_setattr - Add a CIPSO option to a socket
++ * @sock: the socket
++ * @doi_def: the CIPSO DOI to use
++ * @secattr: the specific security attributes of the socket
++ *
++ * Description:
++ * Set the CIPSO option on the given socket using the DOI definition and
++ * security attributes passed to the function. This function requires
++ * exclusive access to @sock->sk, which means it either needs to be in the
++ * process of being created or locked via lock_sock(sock->sk). Returns zero on
++ * success and negative values on failure.
++ *
++ */
++int cipso_v4_socket_setattr(const struct socket *sock,
++ const struct cipso_v4_doi *doi_def,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val = -EPERM;
++ u32 iter;
++ unsigned char *buf = NULL;
++ u32 buf_len = 0;
++ u32 opt_len;
++ struct ip_options *opt = NULL;
++ struct sock *sk;
++ struct inet_sock *sk_inet;
++ struct inet_connection_sock *sk_conn;
++
++ /* In the case of sock_create_lite(), the sock->sk field is not
++ * defined yet but it is not a problem as the only users of these
++ * "lite" PF_INET sockets are functions which do an accept() call
++ * afterwards so we will label the socket as part of the accept(). */
++ sk = sock->sk;
++ if (sk == NULL)
++ return 0;
++
++ /* XXX - This code assumes only one tag per CIPSO option which isn't
++ * really a good assumption to make but since we only support the MAC
++ * tags right now it is a safe assumption. */
++ iter = 0;
++ do {
++ switch (doi_def->tags[iter]) {
++ case CIPSO_V4_TAG_RBITMAP:
++ ret_val = cipso_v4_gentag_rbm(doi_def,
++ secattr,
++ &buf,
++ &buf_len);
++ break;
++ default:
++ ret_val = -EPERM;
++ goto socket_setattr_failure;
++ }
++
++ iter++;
++ } while (ret_val != 0 &&
++ iter < CIPSO_V4_TAG_MAXCNT &&
++ doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
++ if (ret_val != 0)
++ goto socket_setattr_failure;
++
++ /* We can't use ip_options_get() directly because it makes a call to
++ * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
++ * we won't always have CAP_NET_RAW even though we _always_ want to
++ * set the IPOPT_CIPSO option. */
++ opt_len = (buf_len + 3) & ~3;
++ opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
++ if (opt == NULL) {
++ ret_val = -ENOMEM;
++ goto socket_setattr_failure;
++ }
++ memcpy(opt->__data, buf, buf_len);
++ opt->optlen = opt_len;
++ opt->is_data = 1;
++ opt->cipso = sizeof(struct iphdr);
++ kfree(buf);
++ buf = NULL;
++
++ sk_inet = inet_sk(sk);
++ if (sk_inet->is_icsk) {
++ sk_conn = inet_csk(sk);
++ if (sk_inet->opt)
++ sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
++ sk_conn->icsk_ext_hdr_len += opt->optlen;
++ sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
++ }
++ opt = xchg(&sk_inet->opt, opt);
++ kfree(opt);
++
++ return 0;
++
++socket_setattr_failure:
++ kfree(buf);
++ kfree(opt);
++ return ret_val;
++}
++
++/**
++ * cipso_v4_sock_getattr - Get the security attributes from a sock
++ * @sk: the sock
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Query @sk to see if there is a CIPSO option attached to the sock and if
++ * there is return the CIPSO security attributes in @secattr. This function
++ * requires that @sk be locked, or privately held, but it does not do any
++ * locking itself. Returns zero on success and negative values on failure.
++ *
++ */
++int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val = -ENOMSG;
++ struct inet_sock *sk_inet;
++ unsigned char *cipso_ptr;
++ u32 doi;
++ struct cipso_v4_doi *doi_def;
++
++ sk_inet = inet_sk(sk);
++ if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0)
++ return -ENOMSG;
++ cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso -
++ sizeof(struct iphdr);
++ ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr);
++ if (ret_val == 0)
++ return ret_val;
++
++ doi = ntohl(*(u32 *)&cipso_ptr[2]);
++ rcu_read_lock();
++ doi_def = cipso_v4_doi_getdef(doi);
++ if (doi_def == NULL) {
++ rcu_read_unlock();
++ return -ENOMSG;
++ }
++ switch (cipso_ptr[6]) {
++ case CIPSO_V4_TAG_RBITMAP:
++ ret_val = cipso_v4_parsetag_rbm(doi_def,
++ &cipso_ptr[6],
++ secattr);
++ break;
++ }
++ rcu_read_unlock();
++
++ return ret_val;
++}
++
++/**
++ * cipso_v4_socket_getattr - Get the security attributes from a socket
++ * @sock: the socket
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Query @sock to see if there is a CIPSO option attached to the socket and if
++ * there is return the CIPSO security attributes in @secattr. Returns zero on
++ * success and negative values on failure.
++ *
++ */
++int cipso_v4_socket_getattr(const struct socket *sock,
++ struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val;
++
++ lock_sock(sock->sk);
++ ret_val = cipso_v4_sock_getattr(sock->sk, secattr);
++ release_sock(sock->sk);
++
++ return ret_val;
++}
++
++/**
++ * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
++ * @skb: the packet
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Parse the given packet's CIPSO option and return the security attributes.
++ * Returns zero on success and negative values on failure.
++ *
++ */
++int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val = -ENOMSG;
++ unsigned char *cipso_ptr;
++ u32 doi;
++ struct cipso_v4_doi *doi_def;
++
++ if (!CIPSO_V4_OPTEXIST(skb))
++ return -ENOMSG;
++ cipso_ptr = CIPSO_V4_OPTPTR(skb);
++ if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0)
++ return 0;
++
++ doi = ntohl(*(u32 *)&cipso_ptr[2]);
++ rcu_read_lock();
++ doi_def = cipso_v4_doi_getdef(doi);
++ if (doi_def == NULL)
++ goto skbuff_getattr_return;
++ switch (cipso_ptr[6]) {
++ case CIPSO_V4_TAG_RBITMAP:
++ ret_val = cipso_v4_parsetag_rbm(doi_def,
++ &cipso_ptr[6],
++ secattr);
++ break;
++ }
++
++skbuff_getattr_return:
++ rcu_read_unlock();
++ return ret_val;
++}
++
++/*
++ * Setup Functions
++ */
++
++/**
++ * cipso_v4_init - Initialize the CIPSO module
++ *
++ * Description:
++ * Initialize the CIPSO module and prepare it for use. Returns zero on success
++ * and negative values on failure.
++ *
++ */
++static int __init cipso_v4_init(void)
++{
++ int ret_val;
++
++ ret_val = cipso_v4_cache_init();
++ if (ret_val != 0)
++ panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",
++ ret_val);
++
++ return 0;
++}
++
++subsys_initcall(cipso_v4_init);
+diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
+index ec5da4f..7b068a8 100644
+--- a/net/ipv4/datagram.c
++++ b/net/ipv4/datagram.c
+@@ -25,7 +25,7 @@ int ip4_datagram_connect(struct sock *sk
+ struct inet_sock *inet = inet_sk(sk);
+ struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+ struct rtable *rt;
+- u32 saddr;
++ __be32 saddr;
+ int oif;
+ int err;
+
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index a6cc31d..7602c79 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -43,6 +43,7 @@
+ #include <linux/in.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
++#include <linux/if_addr.h>
+ #include <linux/if_ether.h>
+ #include <linux/inet.h>
+ #include <linux/netdevice.h>
+@@ -62,6 +63,7 @@
+ #include <net/ip.h>
+ #include <net/route.h>
+ #include <net/ip_fib.h>
++#include <net/netlink.h>
+
+ struct ipv4_devconf ipv4_devconf = {
+ .accept_redirects = 1,
+@@ -78,7 +80,15 @@ static struct ipv4_devconf ipv4_devconf_
+ .accept_source_route = 1,
+ };
+
+-static void rtmsg_ifa(int event, struct in_ifaddr *);
++static struct nla_policy ifa_ipv4_policy[IFA_MAX+1] __read_mostly = {
++ [IFA_LOCAL] = { .type = NLA_U32 },
++ [IFA_ADDRESS] = { .type = NLA_U32 },
++ [IFA_BROADCAST] = { .type = NLA_U32 },
++ [IFA_ANYCAST] = { .type = NLA_U32 },
++ [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
++};
++
++static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
+
+ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
+ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+@@ -214,7 +224,7 @@ static void inetdev_destroy(struct in_de
+ call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
+ }
+
+-int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
++int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
+ {
+ rcu_read_lock();
+ for_primary_ifa(in_dev) {
+@@ -229,8 +239,8 @@ int inet_addr_onlink(struct in_device *i
+ return 0;
+ }
+
+-static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+- int destroy)
++static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
++ int destroy, struct nlmsghdr *nlh, u32 pid)
+ {
+ struct in_ifaddr *promote = NULL;
+ struct in_ifaddr *ifa, *ifa1 = *ifap;
+@@ -263,7 +273,7 @@ static void inet_del_ifa(struct in_devic
+ if (!do_promote) {
+ *ifap1 = ifa->ifa_next;
+
+- rtmsg_ifa(RTM_DELADDR, ifa);
++ rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
+ blocking_notifier_call_chain(&inetaddr_chain,
+ NETDEV_DOWN, ifa);
+ inet_free_ifa(ifa);
+@@ -288,7 +298,7 @@ static void inet_del_ifa(struct in_devic
+ is valid, it will try to restore deleted routes... Grr.
+ So that, this order is correct.
+ */
+- rtmsg_ifa(RTM_DELADDR, ifa1);
++ rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
+ blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
+
+ if (promote) {
+@@ -300,7 +310,7 @@ static void inet_del_ifa(struct in_devic
+ }
+
+ promote->ifa_flags &= ~IFA_F_SECONDARY;
+- rtmsg_ifa(RTM_NEWADDR, promote);
++ rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
+ blocking_notifier_call_chain(&inetaddr_chain,
+ NETDEV_UP, promote);
+ for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
+@@ -319,7 +329,14 @@ static void inet_del_ifa(struct in_devic
+ }
+ }
+
+-static int inet_insert_ifa(struct in_ifaddr *ifa)
++static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
++ int destroy)
++{
++ __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
++}
++
++static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
++ u32 pid)
+ {
+ struct in_device *in_dev = ifa->ifa_dev;
+ struct in_ifaddr *ifa1, **ifap, **last_primary;
+@@ -364,12 +381,17 @@ static int inet_insert_ifa(struct in_ifa
+ /* Send message first, then call notifier.
+ Notifier will trigger FIB update, so that
+ listeners of netlink will know about new ifaddr */
+- rtmsg_ifa(RTM_NEWADDR, ifa);
++ rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
+ blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
+
+ return 0;
+ }
+
++static int inet_insert_ifa(struct in_ifaddr *ifa)
++{
++ return __inet_insert_ifa(ifa, NULL, 0);
++}
++
+ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
+ {
+ struct in_device *in_dev = __in_dev_get_rtnl(dev);
+@@ -407,8 +429,8 @@ struct in_device *inetdev_by_index(int i
+
+ /* Called only from RTNL semaphored context. No locks. */
+
+-struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,
+- u32 mask)
++struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
++ __be32 mask)
+ {
+ ASSERT_RTNL();
+
+@@ -421,87 +443,134 @@ struct in_ifaddr *inet_ifa_byprefix(stru
+
+ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+- struct rtattr **rta = arg;
++ struct nlattr *tb[IFA_MAX+1];
+ struct in_device *in_dev;
+- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
++ struct ifaddrmsg *ifm;
+ struct in_ifaddr *ifa, **ifap;
++ int err = -EINVAL;
+
+ ASSERT_RTNL();
+
+- if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
+- goto out;
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
++ if (err < 0)
++ goto errout;
++
++ ifm = nlmsg_data(nlh);
++ in_dev = inetdev_by_index(ifm->ifa_index);
++ if (in_dev == NULL) {
++ err = -ENODEV;
++ goto errout;
++ }
++
+ __in_dev_put(in_dev);
+
+ for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+ ifap = &ifa->ifa_next) {
+- if ((rta[IFA_LOCAL - 1] &&
+- memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),
+- &ifa->ifa_local, 4)) ||
+- (rta[IFA_LABEL - 1] &&
+- rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) ||
+- (rta[IFA_ADDRESS - 1] &&
+- (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
+- !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
+- ifa))))
++ if (tb[IFA_LOCAL] &&
++ ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
++ continue;
++
++ if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
++ continue;
++
++ if (tb[IFA_ADDRESS] &&
++ (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
++ !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
+ continue;
+- inet_del_ifa(in_dev, ifap, 1);
++
++ __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
+ return 0;
+ }
+-out:
+- return -EADDRNOTAVAIL;
++
++ err = -EADDRNOTAVAIL;
++errout:
++ return err;
+ }
+
+-static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
++static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
+ {
+- struct rtattr **rta = arg;
++ struct nlattr *tb[IFA_MAX+1];
++ struct in_ifaddr *ifa;
++ struct ifaddrmsg *ifm;
+ struct net_device *dev;
+ struct in_device *in_dev;
+- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+- struct in_ifaddr *ifa;
+- int rc = -EINVAL;
++ int err = -EINVAL;
+
+- ASSERT_RTNL();
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
++ if (err < 0)
++ goto errout;
+
+- if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])
+- goto out;
++ ifm = nlmsg_data(nlh);
++ if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
++ goto errout;
+
+- rc = -ENODEV;
+- if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
+- goto out;
++ dev = __dev_get_by_index(ifm->ifa_index);
++ if (dev == NULL) {
++ err = -ENODEV;
++ goto errout;
++ }
+
+- rc = -ENOBUFS;
+- if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
++ in_dev = __in_dev_get_rtnl(dev);
++ if (in_dev == NULL) {
+ in_dev = inetdev_init(dev);
+- if (!in_dev)
+- goto out;
++ if (in_dev == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
+ }
+
+- if ((ifa = inet_alloc_ifa()) == NULL)
+- goto out;
++ ifa = inet_alloc_ifa();
++ if (ifa == NULL) {
++ /*
++ * A potential indev allocation can be left alive, it stays
++ * assigned to its device and is destroy with it.
++ */
++ err = -ENOBUFS;
++ goto errout;
++ }
++
++ in_dev_hold(in_dev);
++
++ if (tb[IFA_ADDRESS] == NULL)
++ tb[IFA_ADDRESS] = tb[IFA_LOCAL];
+
+- if (!rta[IFA_ADDRESS - 1])
+- rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
+- memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
+- memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
+ ifa->ifa_prefixlen = ifm->ifa_prefixlen;
+ ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
+- if (rta[IFA_BROADCAST - 1])
+- memcpy(&ifa->ifa_broadcast,
+- RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
+- if (rta[IFA_ANYCAST - 1])
+- memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
+ ifa->ifa_flags = ifm->ifa_flags;
+ ifa->ifa_scope = ifm->ifa_scope;
+- in_dev_hold(in_dev);
+- ifa->ifa_dev = in_dev;
+- if (rta[IFA_LABEL - 1])
+- rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
++ ifa->ifa_dev = in_dev;
++
++ ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
++ ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
++
++ if (tb[IFA_BROADCAST])
++ ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
++
++ if (tb[IFA_ANYCAST])
++ ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
++
++ if (tb[IFA_LABEL])
++ nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
+ else
+ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+
+- rc = inet_insert_ifa(ifa);
+-out:
+- return rc;
++ return ifa;
++
++errout:
++ return ERR_PTR(err);
++}
++
++static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
++{
++ struct in_ifaddr *ifa;
++
++ ASSERT_RTNL();
++
++ ifa = rtm_to_ifaddr(nlh);
++ if (IS_ERR(ifa))
++ return PTR_ERR(ifa);
++
++ return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
+ }
+
+ /*
+@@ -736,7 +805,7 @@ int devinet_ioctl(unsigned int cmd, void
+ break;
+ ret = 0;
+ if (ifa->ifa_mask != sin->sin_addr.s_addr) {
+- u32 old_mask = ifa->ifa_mask;
++ __be32 old_mask = ifa->ifa_mask;
+ inet_del_ifa(in_dev, ifap, 0);
+ ifa->ifa_mask = sin->sin_addr.s_addr;
+ ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
+@@ -807,9 +876,9 @@ out:
+ return done;
+ }
+
+-u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
++__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
+ {
+- u32 addr = 0;
++ __be32 addr = 0;
+ struct in_device *in_dev;
+
+ rcu_read_lock();
+@@ -858,11 +927,11 @@ out:
+ return addr;
+ }
+
+-static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
+- u32 local, int scope)
++static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
++ __be32 local, int scope)
+ {
+ int same = 0;
+- u32 addr = 0;
++ __be32 addr = 0;
+
+ for_ifa(in_dev) {
+ if (!addr &&
+@@ -902,9 +971,9 @@ static u32 confirm_addr_indev(struct in_
+ * - local: address, 0=autoselect the local address
+ * - scope: maximum allowed scope value for the local address
+ */
+-u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
++__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
+ {
+- u32 addr = 0;
++ __be32 addr = 0;
+ struct in_device *in_dev;
+
+ if (dev) {
+@@ -1056,32 +1125,37 @@ static int inet_fill_ifaddr(struct sk_bu
+ {
+ struct ifaddrmsg *ifm;
+ struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
+
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
+- ifm = NLMSG_DATA(nlh);
++ nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ ifm = nlmsg_data(nlh);
+ ifm->ifa_family = AF_INET;
+ ifm->ifa_prefixlen = ifa->ifa_prefixlen;
+ ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
+ ifm->ifa_scope = ifa->ifa_scope;
+ ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
++
+ if (ifa->ifa_address)
+- RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address);
++ NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
++
+ if (ifa->ifa_local)
+- RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local);
++ NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
++
+ if (ifa->ifa_broadcast)
+- RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast);
++ NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
++
+ if (ifa->ifa_anycast)
+- RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast);
++ NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
++
+ if (ifa->ifa_label[0])
+- RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ return nlmsg_end(skb, nlh);
++
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
+ }
+
+ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
+@@ -1127,19 +1201,27 @@ done:
+ return skb->len;
+ }
+
+-static void rtmsg_ifa(int event, struct in_ifaddr* ifa)
++static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
++ u32 pid)
+ {
+- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128);
+- struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
++ struct sk_buff *skb;
++ u32 seq = nlh ? nlh->nlmsg_seq : 0;
++ int err = -ENOBUFS;
++
++ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (skb == NULL)
++ goto errout;
+
+- if (!skb)
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS);
+- else if (inet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
++ err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL);
+- } else {
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL);
++ goto errout;
+ }
++
++ err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
+ }
+
+ static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = {
+@@ -1151,9 +1233,7 @@ static struct rtnetlink_link inet_rtnetl
+ [RTM_GETROUTE - RTM_BASE] = { .doit = inet_rtm_getroute,
+ .dumpit = inet_dump_fib, },
+ #ifdef CONFIG_IP_MULTIPLE_TABLES
+- [RTM_NEWRULE - RTM_BASE] = { .doit = inet_rtm_newrule, },
+- [RTM_DELRULE - RTM_BASE] = { .doit = inet_rtm_delrule, },
+- [RTM_GETRULE - RTM_BASE] = { .dumpit = inet_dump_rules, },
++ [RTM_GETRULE - RTM_BASE] = { .dumpit = fib4_rules_dump, },
+ #endif
+ };
+
+diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
+index fc2f8ce..b5c205b 100644
+--- a/net/ipv4/esp4.c
++++ b/net/ipv4/esp4.c
+@@ -1,3 +1,4 @@
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <net/ip.h>
+ #include <net/xfrm.h>
+@@ -16,7 +17,8 @@ static int esp_output(struct xfrm_state
+ int err;
+ struct iphdr *top_iph;
+ struct ip_esp_hdr *esph;
+- struct crypto_tfm *tfm;
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
+ struct esp_data *esp;
+ struct sk_buff *trailer;
+ int blksize;
+@@ -36,7 +38,9 @@ static int esp_output(struct xfrm_state
+ esp = x->data;
+ alen = esp->auth.icv_trunc_len;
+ tfm = esp->conf.tfm;
+- blksize = ALIGN(crypto_tfm_alg_blocksize(tfm), 4);
++ desc.tfm = tfm;
++ desc.flags = 0;
++ blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+ clen = ALIGN(clen + 2, blksize);
+ if (esp->conf.padlen)
+ clen = ALIGN(clen, esp->conf.padlen);
+@@ -91,8 +95,13 @@ static int esp_output(struct xfrm_state
+ esph->seq_no = htonl(++x->replay.oseq);
+ xfrm_aevent_doreplay(x);
+
+- if (esp->conf.ivlen)
+- crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
++ if (esp->conf.ivlen) {
++ if (unlikely(!esp->conf.ivinitted)) {
++ get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
++ esp->conf.ivinitted = 1;
++ }
++ crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
++ }
+
+ do {
+ struct scatterlist *sg = &esp->sgbuf[0];
+@@ -103,26 +112,27 @@ static int esp_output(struct xfrm_state
+ goto error;
+ }
+ skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen);
+- crypto_cipher_encrypt(tfm, sg, sg, clen);
++ err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
+ if (unlikely(sg != &esp->sgbuf[0]))
+ kfree(sg);
+ } while (0);
+
++ if (unlikely(err))
++ goto error;
++
+ if (esp->conf.ivlen) {
+- memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
+- crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
++ memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
++ crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+ }
+
+ if (esp->auth.icv_full_len) {
+- esp->auth.icv(esp, skb, (u8*)esph-skb->data,
+- sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail);
+- pskb_put(skb, trailer, alen);
++ err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
++ sizeof(*esph) + esp->conf.ivlen + clen);
++ memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
+ }
+
+ ip_send_check(top_iph);
+
+- err = 0;
+-
+ error:
+ return err;
+ }
+@@ -137,8 +147,10 @@ static int esp_input(struct xfrm_state *
+ struct iphdr *iph;
+ struct ip_esp_hdr *esph;
+ struct esp_data *esp = x->data;
++ struct crypto_blkcipher *tfm = esp->conf.tfm;
++ struct blkcipher_desc desc = { .tfm = tfm };
+ struct sk_buff *trailer;
+- int blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4);
++ int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+ int alen = esp->auth.icv_trunc_len;
+ int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen;
+ int nfrags;
+@@ -146,6 +158,7 @@ static int esp_input(struct xfrm_state *
+ u8 nexthdr[2];
+ struct scatterlist *sg;
+ int padlen;
++ int err;
+
+ if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
+ goto out;
+@@ -155,15 +168,16 @@ static int esp_input(struct xfrm_state *
+
+ /* If integrity check is required, do this. */
+ if (esp->auth.icv_full_len) {
+- u8 sum[esp->auth.icv_full_len];
+- u8 sum1[alen];
+-
+- esp->auth.icv(esp, skb, 0, skb->len-alen, sum);
++ u8 sum[alen];
++
++ err = esp_mac_digest(esp, skb, 0, skb->len - alen);
++ if (err)
++ goto out;
+
+- if (skb_copy_bits(skb, skb->len-alen, sum1, alen))
++ if (skb_copy_bits(skb, skb->len - alen, sum, alen))
+ BUG();
+
+- if (unlikely(memcmp(sum, sum1, alen))) {
++ if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
+ x->stats.integrity_failed++;
+ goto out;
+ }
+@@ -178,7 +192,7 @@ static int esp_input(struct xfrm_state *
+
+ /* Get ivec. This can be wrong, check against another impls. */
+ if (esp->conf.ivlen)
+- crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm));
++ crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
+
+ sg = &esp->sgbuf[0];
+
+@@ -188,9 +202,11 @@ static int esp_input(struct xfrm_state *
+ goto out;
+ }
+ skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen);
+- crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen);
++ err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
+ if (unlikely(sg != &esp->sgbuf[0]))
+ kfree(sg);
++ if (unlikely(err))
++ return err;
+
+ if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
+ BUG();
+@@ -237,7 +253,8 @@ static int esp_input(struct xfrm_state *
+ * as per draft-ietf-ipsec-udp-encaps-06,
+ * section 3.1.2
+ */
+- if (!x->props.mode)
++ if (x->props.mode == XFRM_MODE_TRANSPORT ||
++ x->props.mode == XFRM_MODE_BEET)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+
+@@ -254,18 +271,29 @@ out:
+ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
+ {
+ struct esp_data *esp = x->data;
+- u32 blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4);
+-
+- if (x->props.mode) {
+- mtu = ALIGN(mtu + 2, blksize);
+- } else {
+- /* The worst case. */
++ u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
++ int enclen = 0;
++
++ switch (x->props.mode) {
++ case XFRM_MODE_TUNNEL:
++ mtu = ALIGN(mtu +2, blksize);
++ break;
++ default:
++ case XFRM_MODE_TRANSPORT:
++ /* The worst case */
+ mtu = ALIGN(mtu + 2, 4) + blksize - 4;
++ break;
++ case XFRM_MODE_BEET:
++ /* The worst case. */
++ enclen = IPV4_BEET_PHMAXLEN;
++ mtu = ALIGN(mtu + enclen + 2, blksize);
++ break;
+ }
++
+ if (esp->conf.padlen)
+ mtu = ALIGN(mtu, esp->conf.padlen);
+
+- return mtu + x->props.header_len + esp->auth.icv_trunc_len;
++ return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
+ }
+
+ static void esp4_err(struct sk_buff *skb, u32 info)
+@@ -293,11 +321,11 @@ static void esp_destroy(struct xfrm_stat
+ if (!esp)
+ return;
+
+- crypto_free_tfm(esp->conf.tfm);
++ crypto_free_blkcipher(esp->conf.tfm);
+ esp->conf.tfm = NULL;
+ kfree(esp->conf.ivec);
+ esp->conf.ivec = NULL;
+- crypto_free_tfm(esp->auth.tfm);
++ crypto_free_hash(esp->auth.tfm);
+ esp->auth.tfm = NULL;
+ kfree(esp->auth.work_icv);
+ esp->auth.work_icv = NULL;
+@@ -307,6 +335,7 @@ static void esp_destroy(struct xfrm_stat
+ static int esp_init_state(struct xfrm_state *x)
+ {
+ struct esp_data *esp = NULL;
++ struct crypto_blkcipher *tfm;
+
+ /* null auth and encryption can have zero length keys */
+ if (x->aalg) {
+@@ -322,22 +351,27 @@ static int esp_init_state(struct xfrm_st
+
+ if (x->aalg) {
+ struct xfrm_algo_desc *aalg_desc;
++ struct crypto_hash *hash;
+
+ esp->auth.key = x->aalg->alg_key;
+ esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
+- esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
+- if (esp->auth.tfm == NULL)
++ hash = crypto_alloc_hash(x->aalg->alg_name, 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(hash))
++ goto error;
++
++ esp->auth.tfm = hash;
++ if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))
+ goto error;
+- esp->auth.icv = esp_hmac_digest;
+
+ aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
+ BUG_ON(!aalg_desc);
+
+ if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+- crypto_tfm_alg_digestsize(esp->auth.tfm)) {
++ crypto_hash_digestsize(hash)) {
+ NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
+ x->aalg->alg_name,
+- crypto_tfm_alg_digestsize(esp->auth.tfm),
++ crypto_hash_digestsize(hash),
+ aalg_desc->uinfo.auth.icv_fullbits/8);
+ goto error;
+ }
+@@ -351,24 +385,22 @@ static int esp_init_state(struct xfrm_st
+ }
+ esp->conf.key = x->ealg->alg_key;
+ esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
+- if (x->props.ealgo == SADB_EALG_NULL)
+- esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_ECB);
+- else
+- esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC);
+- if (esp->conf.tfm == NULL)
++ tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm))
+ goto error;
+- esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm);
++ esp->conf.tfm = tfm;
++ esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
+ esp->conf.padlen = 0;
+ if (esp->conf.ivlen) {
+ esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
+ if (unlikely(esp->conf.ivec == NULL))
+ goto error;
+- get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
++ esp->conf.ivinitted = 0;
+ }
+- if (crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len))
++ if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len))
+ goto error;
+ x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ x->props.header_len += sizeof(struct iphdr);
+ if (x->encap) {
+ struct xfrm_encap_tmpl *encap = x->encap;
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index ba2a707..af0190d 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -32,10 +32,12 @@
+ #include <linux/inet.h>
+ #include <linux/inetdevice.h>
+ #include <linux/netdevice.h>
++#include <linux/if_addr.h>
+ #include <linux/if_arp.h>
+ #include <linux/skbuff.h>
+ #include <linux/netlink.h>
+ #include <linux/init.h>
++#include <linux/list.h>
+
+ #include <net/ip.h>
+ #include <net/protocol.h>
+@@ -50,48 +52,67 @@
+
+ #ifndef CONFIG_IP_MULTIPLE_TABLES
+
+-#define RT_TABLE_MIN RT_TABLE_MAIN
+-
+ struct fib_table *ip_fib_local_table;
+ struct fib_table *ip_fib_main_table;
+
+-#else
++#define FIB_TABLE_HASHSZ 1
++static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
+
+-#define RT_TABLE_MIN 1
++#else
+
+-struct fib_table *fib_tables[RT_TABLE_MAX+1];
++#define FIB_TABLE_HASHSZ 256
++static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
+
+-struct fib_table *__fib_new_table(int id)
++struct fib_table *fib_new_table(u32 id)
+ {
+ struct fib_table *tb;
++ unsigned int h;
+
++ if (id == 0)
++ id = RT_TABLE_MAIN;
++ tb = fib_get_table(id);
++ if (tb)
++ return tb;
+ tb = fib_hash_init(id);
+ if (!tb)
+ return NULL;
+- fib_tables[id] = tb;
++ h = id & (FIB_TABLE_HASHSZ - 1);
++ hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]);
+ return tb;
+ }
+
++struct fib_table *fib_get_table(u32 id)
++{
++ struct fib_table *tb;
++ struct hlist_node *node;
++ unsigned int h;
+
++ if (id == 0)
++ id = RT_TABLE_MAIN;
++ h = id & (FIB_TABLE_HASHSZ - 1);
++ rcu_read_lock();
++ hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) {
++ if (tb->tb_id == id) {
++ rcu_read_unlock();
++ return tb;
++ }
++ }
++ rcu_read_unlock();
++ return NULL;
++}
+ #endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+-
+ static void fib_flush(void)
+ {
+ int flushed = 0;
+-#ifdef CONFIG_IP_MULTIPLE_TABLES
+ struct fib_table *tb;
+- int id;
++ struct hlist_node *node;
++ unsigned int h;
+
+- for (id = RT_TABLE_MAX; id>0; id--) {
+- if ((tb = fib_get_table(id))==NULL)
+- continue;
+- flushed += tb->tb_flush(tb);
++ for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
++ hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist)
++ flushed += tb->tb_flush(tb);
+ }
+-#else /* CONFIG_IP_MULTIPLE_TABLES */
+- flushed += ip_fib_main_table->tb_flush(ip_fib_main_table);
+- flushed += ip_fib_local_table->tb_flush(ip_fib_local_table);
+-#endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+ if (flushed)
+ rt_cache_flush(-1);
+@@ -101,7 +122,7 @@ static void fib_flush(void)
+ * Find the first device with a given source address.
+ */
+
+-struct net_device * ip_dev_find(u32 addr)
++struct net_device * ip_dev_find(__be32 addr)
+ {
+ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
+ struct fib_result res;
+@@ -125,7 +146,7 @@ out:
+ return dev;
+ }
+
+-unsigned inet_addr_type(u32 addr)
++unsigned inet_addr_type(__be32 addr)
+ {
+ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
+ struct fib_result res;
+@@ -159,8 +180,8 @@ unsigned inet_addr_type(u32 addr)
+ - check, that packet arrived from expected physical interface.
+ */
+
+-int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
+- struct net_device *dev, u32 *spec_dst, u32 *itag)
++int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
++ struct net_device *dev, __be32 *spec_dst, u32 *itag)
+ {
+ struct in_device *in_dev;
+ struct flowi fl = { .nl_u = { .ip4_u =
+@@ -232,42 +253,190 @@ e_inval:
+
+ #ifndef CONFIG_IP_NOSIOCRT
+
++static inline __be32 sk_extract_addr(struct sockaddr *addr)
++{
++ return ((struct sockaddr_in *) addr)->sin_addr.s_addr;
++}
++
++static int put_rtax(struct nlattr *mx, int len, int type, u32 value)
++{
++ struct nlattr *nla;
++
++ nla = (struct nlattr *) ((char *) mx + len);
++ nla->nla_type = type;
++ nla->nla_len = nla_attr_size(4);
++ *(u32 *) nla_data(nla) = value;
++
++ return len + nla_total_size(4);
++}
++
++static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
++ struct fib_config *cfg)
++{
++ __be32 addr;
++ int plen;
++
++ memset(cfg, 0, sizeof(*cfg));
++
++ if (rt->rt_dst.sa_family != AF_INET)
++ return -EAFNOSUPPORT;
++
++ /*
++ * Check mask for validity:
++ * a) it must be contiguous.
++ * b) destination must have all host bits clear.
++ * c) if application forgot to set correct family (AF_INET),
++ * reject request unless it is absolutely clear i.e.
++ * both family and mask are zero.
++ */
++ plen = 32;
++ addr = sk_extract_addr(&rt->rt_dst);
++ if (!(rt->rt_flags & RTF_HOST)) {
++ __be32 mask = sk_extract_addr(&rt->rt_genmask);
++
++ if (rt->rt_genmask.sa_family != AF_INET) {
++ if (mask || rt->rt_genmask.sa_family)
++ return -EAFNOSUPPORT;
++ }
++
++ if (bad_mask(mask, addr))
++ return -EINVAL;
++
++ plen = inet_mask_len(mask);
++ }
++
++ cfg->fc_dst_len = plen;
++ cfg->fc_dst = addr;
++
++ if (cmd != SIOCDELRT) {
++ cfg->fc_nlflags = NLM_F_CREATE;
++ cfg->fc_protocol = RTPROT_BOOT;
++ }
++
++ if (rt->rt_metric)
++ cfg->fc_priority = rt->rt_metric - 1;
++
++ if (rt->rt_flags & RTF_REJECT) {
++ cfg->fc_scope = RT_SCOPE_HOST;
++ cfg->fc_type = RTN_UNREACHABLE;
++ return 0;
++ }
++
++ cfg->fc_scope = RT_SCOPE_NOWHERE;
++ cfg->fc_type = RTN_UNICAST;
++
++ if (rt->rt_dev) {
++ char *colon;
++ struct net_device *dev;
++ char devname[IFNAMSIZ];
++
++ if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1))
++ return -EFAULT;
++
++ devname[IFNAMSIZ-1] = 0;
++ colon = strchr(devname, ':');
++ if (colon)
++ *colon = 0;
++ dev = __dev_get_by_name(devname);
++ if (!dev)
++ return -ENODEV;
++ cfg->fc_oif = dev->ifindex;
++ if (colon) {
++ struct in_ifaddr *ifa;
++ struct in_device *in_dev = __in_dev_get_rtnl(dev);
++ if (!in_dev)
++ return -ENODEV;
++ *colon = ':';
++ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
++ if (strcmp(ifa->ifa_label, devname) == 0)
++ break;
++ if (ifa == NULL)
++ return -ENODEV;
++ cfg->fc_prefsrc = ifa->ifa_local;
++ }
++ }
++
++ addr = sk_extract_addr(&rt->rt_gateway);
++ if (rt->rt_gateway.sa_family == AF_INET && addr) {
++ cfg->fc_gw = addr;
++ if (rt->rt_flags & RTF_GATEWAY &&
++ inet_addr_type(addr) == RTN_UNICAST)
++ cfg->fc_scope = RT_SCOPE_UNIVERSE;
++ }
++
++ if (cmd == SIOCDELRT)
++ return 0;
++
++ if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw)
++ return -EINVAL;
++
++ if (cfg->fc_scope == RT_SCOPE_NOWHERE)
++ cfg->fc_scope = RT_SCOPE_LINK;
++
++ if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) {
++ struct nlattr *mx;
++ int len = 0;
++
++ mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL);
++ if (mx == NULL)
++ return -ENOMEM;
++
++ if (rt->rt_flags & RTF_MTU)
++ len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40);
++
++ if (rt->rt_flags & RTF_WINDOW)
++ len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window);
++
++ if (rt->rt_flags & RTF_IRTT)
++ len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3);
++
++ cfg->fc_mx = mx;
++ cfg->fc_mx_len = len;
++ }
++
++ return 0;
++}
++
+ /*
+ * Handle IP routing ioctl calls. These are used to manipulate the routing tables
+ */
+
+ int ip_rt_ioctl(unsigned int cmd, void __user *arg)
+ {
++ struct fib_config cfg;
++ struct rtentry rt;
+ int err;
+- struct kern_rta rta;
+- struct rtentry r;
+- struct {
+- struct nlmsghdr nlh;
+- struct rtmsg rtm;
+- } req;
+
+ switch (cmd) {
+ case SIOCADDRT: /* Add a route */
+ case SIOCDELRT: /* Delete a route */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+- if (copy_from_user(&r, arg, sizeof(struct rtentry)))
++
++ if (copy_from_user(&rt, arg, sizeof(rt)))
+ return -EFAULT;
++
+ rtnl_lock();
+- err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
++ err = rtentry_to_fib_config(cmd, &rt, &cfg);
+ if (err == 0) {
++ struct fib_table *tb;
++
+ if (cmd == SIOCDELRT) {
+- struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
+- err = -ESRCH;
++ tb = fib_get_table(cfg.fc_table);
+ if (tb)
+- err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
++ err = tb->tb_delete(tb, &cfg);
++ else
++ err = -ESRCH;
+ } else {
+- struct fib_table *tb = fib_new_table(req.rtm.rtm_table);
+- err = -ENOBUFS;
++ tb = fib_new_table(cfg.fc_table);
+ if (tb)
+- err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
++ err = tb->tb_insert(tb, &cfg);
++ else
++ err = -ENOBUFS;
+ }
+- kfree(rta.rta_mx);
++
++ /* allocated by rtentry_to_fib_config() */
++ kfree(cfg.fc_mx);
+ }
+ rtnl_unlock();
+ return err;
+@@ -284,77 +453,164 @@ int ip_rt_ioctl(unsigned int cmd, void *
+
+ #endif
+
+-static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
++struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = {
++ [RTA_DST] = { .type = NLA_U32 },
++ [RTA_SRC] = { .type = NLA_U32 },
++ [RTA_IIF] = { .type = NLA_U32 },
++ [RTA_OIF] = { .type = NLA_U32 },
++ [RTA_GATEWAY] = { .type = NLA_U32 },
++ [RTA_PRIORITY] = { .type = NLA_U32 },
++ [RTA_PREFSRC] = { .type = NLA_U32 },
++ [RTA_METRICS] = { .type = NLA_NESTED },
++ [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
++ [RTA_PROTOINFO] = { .type = NLA_U32 },
++ [RTA_FLOW] = { .type = NLA_U32 },
++ [RTA_MP_ALGO] = { .type = NLA_U32 },
++};
++
++static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
++ struct fib_config *cfg)
+ {
+- int i;
+-
+- for (i=1; i<=RTA_MAX; i++, rta++) {
+- struct rtattr *attr = *rta;
+- if (attr) {
+- if (RTA_PAYLOAD(attr) < 4)
+- return -EINVAL;
+- if (i != RTA_MULTIPATH && i != RTA_METRICS)
+- *rta = (struct rtattr*)RTA_DATA(attr);
++ struct nlattr *attr;
++ int err, remaining;
++ struct rtmsg *rtm;
++
++ err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy);
++ if (err < 0)
++ goto errout;
++
++ memset(cfg, 0, sizeof(*cfg));
++
++ rtm = nlmsg_data(nlh);
++ cfg->fc_dst_len = rtm->rtm_dst_len;
++ cfg->fc_tos = rtm->rtm_tos;
++ cfg->fc_table = rtm->rtm_table;
++ cfg->fc_protocol = rtm->rtm_protocol;
++ cfg->fc_scope = rtm->rtm_scope;
++ cfg->fc_type = rtm->rtm_type;
++ cfg->fc_flags = rtm->rtm_flags;
++ cfg->fc_nlflags = nlh->nlmsg_flags;
++
++ cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
++ cfg->fc_nlinfo.nlh = nlh;
++
++ nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) {
++ switch (attr->nla_type) {
++ case RTA_DST:
++ cfg->fc_dst = nla_get_be32(attr);
++ break;
++ case RTA_OIF:
++ cfg->fc_oif = nla_get_u32(attr);
++ break;
++ case RTA_GATEWAY:
++ cfg->fc_gw = nla_get_be32(attr);
++ break;
++ case RTA_PRIORITY:
++ cfg->fc_priority = nla_get_u32(attr);
++ break;
++ case RTA_PREFSRC:
++ cfg->fc_prefsrc = nla_get_be32(attr);
++ break;
++ case RTA_METRICS:
++ cfg->fc_mx = nla_data(attr);
++ cfg->fc_mx_len = nla_len(attr);
++ break;
++ case RTA_MULTIPATH:
++ cfg->fc_mp = nla_data(attr);
++ cfg->fc_mp_len = nla_len(attr);
++ break;
++ case RTA_FLOW:
++ cfg->fc_flow = nla_get_u32(attr);
++ break;
++ case RTA_MP_ALGO:
++ cfg->fc_mp_alg = nla_get_u32(attr);
++ break;
++ case RTA_TABLE:
++ cfg->fc_table = nla_get_u32(attr);
++ break;
+ }
+ }
++
+ return 0;
++errout:
++ return err;
+ }
+
+ int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+ {
+- struct fib_table * tb;
+- struct rtattr **rta = arg;
+- struct rtmsg *r = NLMSG_DATA(nlh);
++ struct fib_config cfg;
++ struct fib_table *tb;
++ int err;
+
+- if (inet_check_attr(r, rta))
+- return -EINVAL;
++ err = rtm_to_fib_config(skb, nlh, &cfg);
++ if (err < 0)
++ goto errout;
+
+- tb = fib_get_table(r->rtm_table);
+- if (tb)
+- return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
+- return -ESRCH;
++ tb = fib_get_table(cfg.fc_table);
++ if (tb == NULL) {
++ err = -ESRCH;
++ goto errout;
++ }
++
++ err = tb->tb_delete(tb, &cfg);
++errout:
++ return err;
+ }
+
+ int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+ {
+- struct fib_table * tb;
+- struct rtattr **rta = arg;
+- struct rtmsg *r = NLMSG_DATA(nlh);
++ struct fib_config cfg;
++ struct fib_table *tb;
++ int err;
+
+- if (inet_check_attr(r, rta))
+- return -EINVAL;
++ err = rtm_to_fib_config(skb, nlh, &cfg);
++ if (err < 0)
++ goto errout;
+
+- tb = fib_new_table(r->rtm_table);
+- if (tb)
+- return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
+- return -ENOBUFS;
++ tb = fib_new_table(cfg.fc_table);
++ if (tb == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
++
++ err = tb->tb_insert(tb, &cfg);
++errout:
++ return err;
+ }
+
+ int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+- int t;
+- int s_t;
++ unsigned int h, s_h;
++ unsigned int e = 0, s_e;
+ struct fib_table *tb;
++ struct hlist_node *node;
++ int dumped = 0;
+
+- if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
+- ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
++ if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
++ ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
+ return ip_rt_dump(skb, cb);
+
+- s_t = cb->args[0];
+- if (s_t == 0)
+- s_t = cb->args[0] = RT_TABLE_MIN;
+-
+- for (t=s_t; t<=RT_TABLE_MAX; t++) {
+- if (t < s_t) continue;
+- if (t > s_t)
+- memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
+- if ((tb = fib_get_table(t))==NULL)
+- continue;
+- if (tb->tb_dump(tb, skb, cb) < 0)
+- break;
++ s_h = cb->args[0];
++ s_e = cb->args[1];
++
++ for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
++ e = 0;
++ hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) {
++ if (e < s_e)
++ goto next;
++ if (dumped)
++ memset(&cb->args[2], 0, sizeof(cb->args) -
++ 2 * sizeof(cb->args[0]));
++ if (tb->tb_dump(tb, skb, cb) < 0)
++ goto out;
++ dumped = 1;
++next:
++ e++;
++ }
+ }
+-
+- cb->args[0] = t;
++out:
++ cb->args[1] = e;
++ cb->args[0] = h;
+
+ return skb->len;
+ }
+@@ -366,17 +622,18 @@ int inet_dump_fib(struct sk_buff *skb, s
+ only when netlink is already locked.
+ */
+
+-static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa)
++static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
+ {
+- struct fib_table * tb;
+- struct {
+- struct nlmsghdr nlh;
+- struct rtmsg rtm;
+- } req;
+- struct kern_rta rta;
+-
+- memset(&req.rtm, 0, sizeof(req.rtm));
+- memset(&rta, 0, sizeof(rta));
++ struct fib_table *tb;
++ struct fib_config cfg = {
++ .fc_protocol = RTPROT_KERNEL,
++ .fc_type = type,
++ .fc_dst = dst,
++ .fc_dst_len = dst_len,
++ .fc_prefsrc = ifa->ifa_local,
++ .fc_oif = ifa->ifa_dev->dev->ifindex,
++ .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
++ };
+
+ if (type == RTN_UNICAST)
+ tb = fib_new_table(RT_TABLE_MAIN);
+@@ -386,26 +643,17 @@ static void fib_magic(int cmd, int type,
+ if (tb == NULL)
+ return;
+
+- req.nlh.nlmsg_len = sizeof(req);
+- req.nlh.nlmsg_type = cmd;
+- req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
+- req.nlh.nlmsg_pid = 0;
+- req.nlh.nlmsg_seq = 0;
++ cfg.fc_table = tb->tb_id;
+
+- req.rtm.rtm_dst_len = dst_len;
+- req.rtm.rtm_table = tb->tb_id;
+- req.rtm.rtm_protocol = RTPROT_KERNEL;
+- req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
+- req.rtm.rtm_type = type;
+-
+- rta.rta_dst = &dst;
+- rta.rta_prefsrc = &ifa->ifa_local;
+- rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
++ if (type != RTN_LOCAL)
++ cfg.fc_scope = RT_SCOPE_LINK;
++ else
++ cfg.fc_scope = RT_SCOPE_HOST;
+
+ if (cmd == RTM_NEWROUTE)
+- tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
++ tb->tb_insert(tb, &cfg);
+ else
+- tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
++ tb->tb_delete(tb, &cfg);
+ }
+
+ void fib_add_ifaddr(struct in_ifaddr *ifa)
+@@ -413,9 +661,9 @@ void fib_add_ifaddr(struct in_ifaddr *if
+ struct in_device *in_dev = ifa->ifa_dev;
+ struct net_device *dev = in_dev->dev;
+ struct in_ifaddr *prim = ifa;
+- u32 mask = ifa->ifa_mask;
+- u32 addr = ifa->ifa_local;
+- u32 prefix = ifa->ifa_address&mask;
++ __be32 mask = ifa->ifa_mask;
++ __be32 addr = ifa->ifa_local;
++ __be32 prefix = ifa->ifa_address&mask;
+
+ if (ifa->ifa_flags&IFA_F_SECONDARY) {
+ prim = inet_ifa_byprefix(in_dev, prefix, mask);
+@@ -431,7 +679,7 @@ void fib_add_ifaddr(struct in_ifaddr *if
+ return;
+
+ /* Add broadcast address, if it is explicitly assigned. */
+- if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
++ if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
+
+ if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
+@@ -453,8 +701,8 @@ static void fib_del_ifaddr(struct in_ifa
+ struct net_device *dev = in_dev->dev;
+ struct in_ifaddr *ifa1;
+ struct in_ifaddr *prim = ifa;
+- u32 brd = ifa->ifa_address|~ifa->ifa_mask;
+- u32 any = ifa->ifa_address&ifa->ifa_mask;
++ __be32 brd = ifa->ifa_address|~ifa->ifa_mask;
++ __be32 any = ifa->ifa_address&ifa->ifa_mask;
+ #define LOCAL_OK 1
+ #define BRD_OK 2
+ #define BRD0_OK 4
+@@ -652,11 +900,17 @@ static struct notifier_block fib_netdev_
+
+ void __init ip_fib_init(void)
+ {
++ unsigned int i;
++
++ for (i = 0; i < FIB_TABLE_HASHSZ; i++)
++ INIT_HLIST_HEAD(&fib_table_hash[i]);
+ #ifndef CONFIG_IP_MULTIPLE_TABLES
+ ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);
++ hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]);
+ ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN);
++ hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]);
+ #else
+- fib_rules_init();
++ fib4_rules_init();
+ #endif
+
+ register_netdevice_notifier(&fib_netdev_notifier);
+diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
+index 72c633b..107bb6c 100644
+--- a/net/ipv4/fib_hash.c
++++ b/net/ipv4/fib_hash.c
+@@ -51,7 +51,7 @@ static kmem_cache_t *fn_alias_kmem __rea
+ struct fib_node {
+ struct hlist_node fn_hash;
+ struct list_head fn_alias;
+- u32 fn_key;
++ __be32 fn_key;
+ };
+
+ struct fn_zone {
+@@ -64,7 +64,7 @@ struct fn_zone {
+ #define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
+
+ int fz_order; /* Zone order */
+- u32 fz_mask;
++ __be32 fz_mask;
+ #define FZ_MASK(fz) ((fz)->fz_mask)
+ };
+
+@@ -77,7 +77,7 @@ struct fn_hash {
+ struct fn_zone *fn_zone_list;
+ };
+
+-static inline u32 fn_hash(u32 key, struct fn_zone *fz)
++static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
+ {
+ u32 h = ntohl(key)>>(32 - fz->fz_order);
+ h ^= (h>>20);
+@@ -87,7 +87,7 @@ static inline u32 fn_hash(u32 key, struc
+ return h;
+ }
+
+-static inline u32 fz_key(u32 dst, struct fn_zone *fz)
++static inline __be32 fz_key(__be32 dst, struct fn_zone *fz)
+ {
+ return dst & FZ_MASK(fz);
+ }
+@@ -254,7 +254,7 @@ fn_hash_lookup(struct fib_table *tb, con
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct fib_node *f;
+- u32 k = fz_key(flp->fl4_dst, fz);
++ __be32 k = fz_key(flp->fl4_dst, fz);
+
+ head = &fz->fz_hash[fn_hash(k, fz)];
+ hlist_for_each_entry(f, node, head, fn_hash) {
+@@ -365,7 +365,7 @@ static inline void fib_insert_node(struc
+ }
+
+ /* Return the node in FZ matching KEY. */
+-static struct fib_node *fib_find_node(struct fn_zone *fz, u32 key)
++static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
+ {
+ struct hlist_head *head = &fz->fz_hash[fn_hash(key, fz)];
+ struct hlist_node *node;
+@@ -379,42 +379,39 @@ static struct fib_node *fib_find_node(st
+ return NULL;
+ }
+
+-static int
+-fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
+- struct nlmsghdr *n, struct netlink_skb_parms *req)
++static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+ {
+ struct fn_hash *table = (struct fn_hash *) tb->tb_data;
+ struct fib_node *new_f, *f;
+ struct fib_alias *fa, *new_fa;
+ struct fn_zone *fz;
+ struct fib_info *fi;
+- int z = r->rtm_dst_len;
+- int type = r->rtm_type;
+- u8 tos = r->rtm_tos;
+- u32 key;
++ u8 tos = cfg->fc_tos;
++ __be32 key;
+ int err;
+
+- if (z > 32)
++ if (cfg->fc_dst_len > 32)
+ return -EINVAL;
+- fz = table->fn_zones[z];
+- if (!fz && !(fz = fn_new_zone(table, z)))
++
++ fz = table->fn_zones[cfg->fc_dst_len];
++ if (!fz && !(fz = fn_new_zone(table, cfg->fc_dst_len)))
+ return -ENOBUFS;
+
+ key = 0;
+- if (rta->rta_dst) {
+- u32 dst;
+- memcpy(&dst, rta->rta_dst, 4);
+- if (dst & ~FZ_MASK(fz))
++ if (cfg->fc_dst) {
++ if (cfg->fc_dst & ~FZ_MASK(fz))
+ return -EINVAL;
+- key = fz_key(dst, fz);
++ key = fz_key(cfg->fc_dst, fz);
+ }
+
+- if ((fi = fib_create_info(r, rta, n, &err)) == NULL)
+- return err;
++ fi = fib_create_info(cfg);
++ if (IS_ERR(fi))
++ return PTR_ERR(fi);
+
+ if (fz->fz_nent > (fz->fz_divisor<<1) &&
+ fz->fz_divisor < FZ_MAX_DIVISOR &&
+- (z==32 || (1<<z) > fz->fz_divisor))
++ (cfg->fc_dst_len == 32 ||
++ (1 << cfg->fc_dst_len) > fz->fz_divisor))
+ fn_rehash_zone(fz);
+
+ f = fib_find_node(fz, key);
+@@ -440,18 +437,18 @@ fn_hash_insert(struct fib_table *tb, str
+ struct fib_alias *fa_orig;
+
+ err = -EEXIST;
+- if (n->nlmsg_flags & NLM_F_EXCL)
++ if (cfg->fc_nlflags & NLM_F_EXCL)
+ goto out;
+
+- if (n->nlmsg_flags & NLM_F_REPLACE) {
++ if (cfg->fc_nlflags & NLM_F_REPLACE) {
+ struct fib_info *fi_drop;
+ u8 state;
+
+ write_lock_bh(&fib_hash_lock);
+ fi_drop = fa->fa_info;
+ fa->fa_info = fi;
+- fa->fa_type = type;
+- fa->fa_scope = r->rtm_scope;
++ fa->fa_type = cfg->fc_type;
++ fa->fa_scope = cfg->fc_scope;
+ state = fa->fa_state;
+ fa->fa_state &= ~FA_S_ACCESSED;
+ fib_hash_genid++;
+@@ -474,17 +471,17 @@ fn_hash_insert(struct fib_table *tb, str
+ break;
+ if (fa->fa_info->fib_priority != fi->fib_priority)
+ break;
+- if (fa->fa_type == type &&
+- fa->fa_scope == r->rtm_scope &&
++ if (fa->fa_type == cfg->fc_type &&
++ fa->fa_scope == cfg->fc_scope &&
+ fa->fa_info == fi)
+ goto out;
+ }
+- if (!(n->nlmsg_flags & NLM_F_APPEND))
++ if (!(cfg->fc_nlflags & NLM_F_APPEND))
+ fa = fa_orig;
+ }
+
+ err = -ENOENT;
+- if (!(n->nlmsg_flags&NLM_F_CREATE))
++ if (!(cfg->fc_nlflags & NLM_F_CREATE))
+ goto out;
+
+ err = -ENOBUFS;
+@@ -506,8 +503,8 @@ fn_hash_insert(struct fib_table *tb, str
+
+ new_fa->fa_info = fi;
+ new_fa->fa_tos = tos;
+- new_fa->fa_type = type;
+- new_fa->fa_scope = r->rtm_scope;
++ new_fa->fa_type = cfg->fc_type;
++ new_fa->fa_scope = cfg->fc_scope;
+ new_fa->fa_state = 0;
+
+ /*
+@@ -526,7 +523,8 @@ fn_hash_insert(struct fib_table *tb, str
+ fz->fz_nent++;
+ rt_cache_flush(-1);
+
+- rtmsg_fib(RTM_NEWROUTE, key, new_fa, z, tb->tb_id, n, req);
++ rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len, tb->tb_id,
++ &cfg->fc_nlinfo);
+ return 0;
+
+ out_free_new_fa:
+@@ -537,30 +535,25 @@ out:
+ }
+
+
+-static int
+-fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
+- struct nlmsghdr *n, struct netlink_skb_parms *req)
++static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
+ {
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+ struct fib_node *f;
+ struct fib_alias *fa, *fa_to_delete;
+- int z = r->rtm_dst_len;
+ struct fn_zone *fz;
+- u32 key;
+- u8 tos = r->rtm_tos;
++ __be32 key;
+
+- if (z > 32)
++ if (cfg->fc_dst_len > 32)
+ return -EINVAL;
+- if ((fz = table->fn_zones[z]) == NULL)
++
++ if ((fz = table->fn_zones[cfg->fc_dst_len]) == NULL)
+ return -ESRCH;
+
+ key = 0;
+- if (rta->rta_dst) {
+- u32 dst;
+- memcpy(&dst, rta->rta_dst, 4);
+- if (dst & ~FZ_MASK(fz))
++ if (cfg->fc_dst) {
++ if (cfg->fc_dst & ~FZ_MASK(fz))
+ return -EINVAL;
+- key = fz_key(dst, fz);
++ key = fz_key(cfg->fc_dst, fz);
+ }
+
+ f = fib_find_node(fz, key);
+@@ -568,7 +561,7 @@ fn_hash_delete(struct fib_table *tb, str
+ if (!f)
+ fa = NULL;
+ else
+- fa = fib_find_alias(&f->fn_alias, tos, 0);
++ fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0);
+ if (!fa)
+ return -ESRCH;
+
+@@ -577,16 +570,16 @@ fn_hash_delete(struct fib_table *tb, str
+ list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
+ struct fib_info *fi = fa->fa_info;
+
+- if (fa->fa_tos != tos)
++ if (fa->fa_tos != cfg->fc_tos)
+ break;
+
+- if ((!r->rtm_type ||
+- fa->fa_type == r->rtm_type) &&
+- (r->rtm_scope == RT_SCOPE_NOWHERE ||
+- fa->fa_scope == r->rtm_scope) &&
+- (!r->rtm_protocol ||
+- fi->fib_protocol == r->rtm_protocol) &&
+- fib_nh_match(r, n, rta, fi) == 0) {
++ if ((!cfg->fc_type ||
++ fa->fa_type == cfg->fc_type) &&
++ (cfg->fc_scope == RT_SCOPE_NOWHERE ||
++ fa->fa_scope == cfg->fc_scope) &&
++ (!cfg->fc_protocol ||
++ fi->fib_protocol == cfg->fc_protocol) &&
++ fib_nh_match(cfg, fi) == 0) {
+ fa_to_delete = fa;
+ break;
+ }
+@@ -596,7 +589,8 @@ fn_hash_delete(struct fib_table *tb, str
+ int kill_fn;
+
+ fa = fa_to_delete;
+- rtmsg_fib(RTM_DELROUTE, key, fa, z, tb->tb_id, n, req);
++ rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len,
++ tb->tb_id, &cfg->fc_nlinfo);
+
+ kill_fn = 0;
+ write_lock_bh(&fib_hash_lock);
+@@ -684,7 +678,7 @@ fn_hash_dump_bucket(struct sk_buff *skb,
+ struct fib_node *f;
+ int i, s_i;
+
+- s_i = cb->args[3];
++ s_i = cb->args[4];
+ i = 0;
+ hlist_for_each_entry(f, node, head, fn_hash) {
+ struct fib_alias *fa;
+@@ -699,19 +693,19 @@ fn_hash_dump_bucket(struct sk_buff *skb,
+ tb->tb_id,
+ fa->fa_type,
+ fa->fa_scope,
+- &f->fn_key,
++ f->fn_key,
+ fz->fz_order,
+ fa->fa_tos,
+ fa->fa_info,
+ NLM_F_MULTI) < 0) {
+- cb->args[3] = i;
++ cb->args[4] = i;
+ return -1;
+ }
+ next:
+ i++;
+ }
+ }
+- cb->args[3] = i;
++ cb->args[4] = i;
+ return skb->len;
+ }
+
+@@ -722,21 +716,21 @@ fn_hash_dump_zone(struct sk_buff *skb, s
+ {
+ int h, s_h;
+
+- s_h = cb->args[2];
++ s_h = cb->args[3];
+ for (h=0; h < fz->fz_divisor; h++) {
+ if (h < s_h) continue;
+ if (h > s_h)
+- memset(&cb->args[3], 0,
+- sizeof(cb->args) - 3*sizeof(cb->args[0]));
++ memset(&cb->args[4], 0,
++ sizeof(cb->args) - 4*sizeof(cb->args[0]));
+ if (fz->fz_hash == NULL ||
+ hlist_empty(&fz->fz_hash[h]))
+ continue;
+ if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) {
+- cb->args[2] = h;
++ cb->args[3] = h;
+ return -1;
+ }
+ }
+- cb->args[2] = h;
++ cb->args[3] = h;
+ return skb->len;
+ }
+
+@@ -746,28 +740,28 @@ static int fn_hash_dump(struct fib_table
+ struct fn_zone *fz;
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+
+- s_m = cb->args[1];
++ s_m = cb->args[2];
+ read_lock(&fib_hash_lock);
+ for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
+ if (m < s_m) continue;
+ if (m > s_m)
+- memset(&cb->args[2], 0,
+- sizeof(cb->args) - 2*sizeof(cb->args[0]));
++ memset(&cb->args[3], 0,
++ sizeof(cb->args) - 3*sizeof(cb->args[0]));
+ if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
+- cb->args[1] = m;
++ cb->args[2] = m;
+ read_unlock(&fib_hash_lock);
+ return -1;
+ }
+ }
+ read_unlock(&fib_hash_lock);
+- cb->args[1] = m;
++ cb->args[2] = m;
+ return skb->len;
+ }
+
+ #ifdef CONFIG_IP_MULTIPLE_TABLES
+-struct fib_table * fib_hash_init(int id)
++struct fib_table * fib_hash_init(u32 id)
+ #else
+-struct fib_table * __init fib_hash_init(int id)
++struct fib_table * __init fib_hash_init(u32 id)
+ #endif
+ {
+ struct fib_table *tb;
+@@ -972,7 +966,7 @@ static void fib_seq_stop(struct seq_file
+ read_unlock(&fib_hash_lock);
+ }
+
+-static unsigned fib_flag_trans(int type, u32 mask, struct fib_info *fi)
++static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
+ {
+ static const unsigned type2flags[RTN_MAX + 1] = {
+ [7] = RTF_REJECT, [8] = RTF_REJECT,
+@@ -981,7 +975,7 @@ static unsigned fib_flag_trans(int type,
+
+ if (fi && fi->fib_nh->nh_gw)
+ flags |= RTF_GATEWAY;
+- if (mask == 0xFFFFFFFF)
++ if (mask == htonl(0xFFFFFFFF))
+ flags |= RTF_HOST;
+ flags |= RTF_UP;
+ return flags;
+@@ -997,7 +991,7 @@ static int fib_seq_show(struct seq_file
+ {
+ struct fib_iter_state *iter;
+ char bf[128];
+- u32 prefix, mask;
++ __be32 prefix, mask;
+ unsigned flags;
+ struct fib_node *f;
+ struct fib_alias *fa;
+diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
+index ef6609e..0e8b70b 100644
+--- a/net/ipv4/fib_lookup.h
++++ b/net/ipv4/fib_lookup.h
+@@ -20,22 +20,17 @@ struct fib_alias {
+ /* Exported by fib_semantics.c */
+ extern int fib_semantic_match(struct list_head *head,
+ const struct flowi *flp,
+- struct fib_result *res, __u32 zone, __u32 mask,
++ struct fib_result *res, __be32 zone, __be32 mask,
+ int prefixlen);
+ extern void fib_release_info(struct fib_info *);
+-extern struct fib_info *fib_create_info(const struct rtmsg *r,
+- struct kern_rta *rta,
+- const struct nlmsghdr *,
+- int *err);
+-extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *,
+- struct kern_rta *rta, struct fib_info *fi);
++extern struct fib_info *fib_create_info(struct fib_config *cfg);
++extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
+ extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+- u8 tb_id, u8 type, u8 scope, void *dst,
++ u32 tb_id, u8 type, u8 scope, __be32 dst,
+ int dst_len, u8 tos, struct fib_info *fi,
+ unsigned int);
+-extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
+- int z, int tb_id,
+- struct nlmsghdr *n, struct netlink_skb_parms *req);
++extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
++ int dst_len, u32 tb_id, struct nl_info *info);
+ extern struct fib_alias *fib_find_alias(struct list_head *fah,
+ u8 tos, u32 prio);
+ extern int fib_detect_death(struct fib_info *fi, int order,
+diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
+index 79b0471..0852b9c 100644
+--- a/net/ipv4/fib_rules.c
++++ b/net/ipv4/fib_rules.c
+@@ -5,9 +5,8 @@
+ *
+ * IPv4 Forwarding Information Base: policy rules.
+ *
+- * Version: $Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $
+- *
+ * Authors: Alexey Kuznetsov, <kuznet at ms2.inr.ac.ru>
++ * Thomas Graf <tgraf at suug.ch>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -19,463 +18,350 @@
+ * Marc Boucher : routing by fwmark
+ */
+
+-#include <asm/uaccess.h>
+-#include <asm/system.h>
+-#include <linux/bitops.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/string.h>
+-#include <linux/socket.h>
+-#include <linux/sockios.h>
+-#include <linux/errno.h>
+-#include <linux/in.h>
+-#include <linux/inet.h>
+-#include <linux/inetdevice.h>
+ #include <linux/netdevice.h>
+-#include <linux/if_arp.h>
+-#include <linux/proc_fs.h>
+-#include <linux/skbuff.h>
+ #include <linux/netlink.h>
++#include <linux/inetdevice.h>
+ #include <linux/init.h>
+ #include <linux/list.h>
+ #include <linux/rcupdate.h>
+-
+ #include <net/ip.h>
+-#include <net/protocol.h>
+ #include <net/route.h>
+ #include <net/tcp.h>
+-#include <net/sock.h>
+ #include <net/ip_fib.h>
++#include <net/fib_rules.h>
+
+-#define FRprintk(a...)
++static struct fib_rules_ops fib4_rules_ops;
+
+-struct fib_rule
++struct fib4_rule
+ {
+- struct hlist_node hlist;
+- atomic_t r_clntref;
+- u32 r_preference;
+- unsigned char r_table;
+- unsigned char r_action;
+- unsigned char r_dst_len;
+- unsigned char r_src_len;
+- u32 r_src;
+- u32 r_srcmask;
+- u32 r_dst;
+- u32 r_dstmask;
+- u32 r_srcmap;
+- u8 r_flags;
+- u8 r_tos;
++ struct fib_rule common;
++ u8 dst_len;
++ u8 src_len;
++ u8 tos;
++ __be32 src;
++ __be32 srcmask;
++ __be32 dst;
++ __be32 dstmask;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+- u32 r_fwmark;
++ u32 fwmark;
++ u32 fwmask;
+ #endif
+- int r_ifindex;
+ #ifdef CONFIG_NET_CLS_ROUTE
+- __u32 r_tclassid;
++ u32 tclassid;
+ #endif
+- char r_ifname[IFNAMSIZ];
+- int r_dead;
+- struct rcu_head rcu;
+ };
+
+-static struct fib_rule default_rule = {
+- .r_clntref = ATOMIC_INIT(2),
+- .r_preference = 0x7FFF,
+- .r_table = RT_TABLE_DEFAULT,
+- .r_action = RTN_UNICAST,
++static struct fib4_rule default_rule = {
++ .common = {
++ .refcnt = ATOMIC_INIT(2),
++ .pref = 0x7FFF,
++ .table = RT_TABLE_DEFAULT,
++ .action = FR_ACT_TO_TBL,
++ },
+ };
+
+-static struct fib_rule main_rule = {
+- .r_clntref = ATOMIC_INIT(2),
+- .r_preference = 0x7FFE,
+- .r_table = RT_TABLE_MAIN,
+- .r_action = RTN_UNICAST,
++static struct fib4_rule main_rule = {
++ .common = {
++ .refcnt = ATOMIC_INIT(2),
++ .pref = 0x7FFE,
++ .table = RT_TABLE_MAIN,
++ .action = FR_ACT_TO_TBL,
++ },
+ };
+
+-static struct fib_rule local_rule = {
+- .r_clntref = ATOMIC_INIT(2),
+- .r_table = RT_TABLE_LOCAL,
+- .r_action = RTN_UNICAST,
++static struct fib4_rule local_rule = {
++ .common = {
++ .refcnt = ATOMIC_INIT(2),
++ .table = RT_TABLE_LOCAL,
++ .action = FR_ACT_TO_TBL,
++ .flags = FIB_RULE_PERMANENT,
++ },
+ };
+
+-static struct hlist_head fib_rules;
++static LIST_HEAD(fib4_rules);
+
+-/* writer func called from netlink -- rtnl_sem hold*/
+-
+-static void rtmsg_rule(int, struct fib_rule *);
+-
+-int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
++#ifdef CONFIG_NET_CLS_ROUTE
++u32 fib_rules_tclass(struct fib_result *res)
+ {
+- struct rtattr **rta = arg;
+- struct rtmsg *rtm = NLMSG_DATA(nlh);
+- struct fib_rule *r;
+- struct hlist_node *node;
+- int err = -ESRCH;
+-
+- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+- if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
+- rtm->rtm_src_len == r->r_src_len &&
+- rtm->rtm_dst_len == r->r_dst_len &&
+- (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) &&
+- rtm->rtm_tos == r->r_tos &&
+-#ifdef CONFIG_IP_ROUTE_FWMARK
+- (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
+-#endif
+- (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
+- (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
+- (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) &&
+- (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
+- err = -EPERM;
+- if (r == &local_rule)
+- break;
+-
+- hlist_del_rcu(&r->hlist);
+- r->r_dead = 1;
+- rtmsg_rule(RTM_DELRULE, r);
+- fib_rule_put(r);
+- err = 0;
+- break;
+- }
+- }
+- return err;
++ return res->r ? ((struct fib4_rule *) res->r)->tclassid : 0;
+ }
++#endif
+
+-/* Allocate new unique table id */
+-
+-static struct fib_table *fib_empty_table(void)
++int fib_lookup(struct flowi *flp, struct fib_result *res)
+ {
+- int id;
++ struct fib_lookup_arg arg = {
++ .result = res,
++ };
++ int err;
+
+- for (id = 1; id <= RT_TABLE_MAX; id++)
+- if (fib_tables[id] == NULL)
+- return __fib_new_table(id);
+- return NULL;
+-}
++ err = fib_rules_lookup(&fib4_rules_ops, flp, 0, &arg);
++ res->r = arg.rule;
+
+-static inline void fib_rule_put_rcu(struct rcu_head *head)
+-{
+- struct fib_rule *r = container_of(head, struct fib_rule, rcu);
+- kfree(r);
++ return err;
+ }
+
+-void fib_rule_put(struct fib_rule *r)
++static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
++ int flags, struct fib_lookup_arg *arg)
+ {
+- if (atomic_dec_and_test(&r->r_clntref)) {
+- if (r->r_dead)
+- call_rcu(&r->rcu, fib_rule_put_rcu);
+- else
+- printk("Freeing alive rule %p\n", r);
++ int err = -EAGAIN;
++ struct fib_table *tbl;
++
++ switch (rule->action) {
++ case FR_ACT_TO_TBL:
++ break;
++
++ case FR_ACT_UNREACHABLE:
++ err = -ENETUNREACH;
++ goto errout;
++
++ case FR_ACT_PROHIBIT:
++ err = -EACCES;
++ goto errout;
++
++ case FR_ACT_BLACKHOLE:
++ default:
++ err = -EINVAL;
++ goto errout;
+ }
++
++ if ((tbl = fib_get_table(rule->table)) == NULL)
++ goto errout;
++
++ err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result);
++ if (err > 0)
++ err = -EAGAIN;
++errout:
++ return err;
+ }
+
+-/* writer func called from netlink -- rtnl_sem hold*/
+
+-int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
++void fib_select_default(const struct flowi *flp, struct fib_result *res)
+ {
+- struct rtattr **rta = arg;
+- struct rtmsg *rtm = NLMSG_DATA(nlh);
+- struct fib_rule *r, *new_r, *last = NULL;
+- struct hlist_node *node = NULL;
+- unsigned char table_id;
+-
+- if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
+- (rtm->rtm_tos & ~IPTOS_TOS_MASK))
+- return -EINVAL;
+-
+- if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
+- return -EINVAL;
+-
+- table_id = rtm->rtm_table;
+- if (table_id == RT_TABLE_UNSPEC) {
+- struct fib_table *table;
+- if (rtm->rtm_type == RTN_UNICAST) {
+- if ((table = fib_empty_table()) == NULL)
+- return -ENOBUFS;
+- table_id = table->tb_id;
+- }
++ if (res->r && res->r->action == FR_ACT_TO_TBL &&
++ FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
++ struct fib_table *tb;
++ if ((tb = fib_get_table(res->r->table)) != NULL)
++ tb->tb_select_default(tb, flp, res);
+ }
++}
+
+- new_r = kzalloc(sizeof(*new_r), GFP_KERNEL);
+- if (!new_r)
+- return -ENOMEM;
+-
+- if (rta[RTA_SRC-1])
+- memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
+- if (rta[RTA_DST-1])
+- memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4);
+- if (rta[RTA_GATEWAY-1])
+- memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4);
+- new_r->r_src_len = rtm->rtm_src_len;
+- new_r->r_dst_len = rtm->rtm_dst_len;
+- new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len);
+- new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len);
+- new_r->r_tos = rtm->rtm_tos;
+-#ifdef CONFIG_IP_ROUTE_FWMARK
+- if (rta[RTA_PROTOINFO-1])
+- memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
+-#endif
+- new_r->r_action = rtm->rtm_type;
+- new_r->r_flags = rtm->rtm_flags;
+- if (rta[RTA_PRIORITY-1])
+- memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
+- new_r->r_table = table_id;
+- if (rta[RTA_IIF-1]) {
+- struct net_device *dev;
+- rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ);
+- new_r->r_ifindex = -1;
+- dev = __dev_get_by_name(new_r->r_ifname);
+- if (dev)
+- new_r->r_ifindex = dev->ifindex;
+- }
+-#ifdef CONFIG_NET_CLS_ROUTE
+- if (rta[RTA_FLOW-1])
+- memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
+-#endif
+- r = container_of(fib_rules.first, struct fib_rule, hlist);
++static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
++{
++ struct fib4_rule *r = (struct fib4_rule *) rule;
++ __be32 daddr = fl->fl4_dst;
++ __be32 saddr = fl->fl4_src;
+
+- if (!new_r->r_preference) {
+- if (r && r->hlist.next != NULL) {
+- r = container_of(r->hlist.next, struct fib_rule, hlist);
+- if (r->r_preference)
+- new_r->r_preference = r->r_preference - 1;
+- }
+- }
++ if (((saddr ^ r->src) & r->srcmask) ||
++ ((daddr ^ r->dst) & r->dstmask))
++ return 0;
+
+- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+- if (r->r_preference > new_r->r_preference)
+- break;
+- last = r;
+- }
+- atomic_inc(&new_r->r_clntref);
++ if (r->tos && (r->tos != fl->fl4_tos))
++ return 0;
+
+- if (last)
+- hlist_add_after_rcu(&last->hlist, &new_r->hlist);
+- else
+- hlist_add_before_rcu(&new_r->hlist, &r->hlist);
++#ifdef CONFIG_IP_ROUTE_FWMARK
++ if ((r->fwmark ^ fl->fl4_fwmark) & r->fwmask)
++ return 0;
++#endif
+
+- rtmsg_rule(RTM_NEWRULE, new_r);
+- return 0;
++ return 1;
+ }
+
+-#ifdef CONFIG_NET_CLS_ROUTE
+-u32 fib_rules_tclass(struct fib_result *res)
++static struct fib_table *fib_empty_table(void)
+ {
+- if (res->r)
+- return res->r->r_tclassid;
+- return 0;
++ u32 id;
++
++ for (id = 1; id <= RT_TABLE_MAX; id++)
++ if (fib_get_table(id) == NULL)
++ return fib_new_table(id);
++ return NULL;
+ }
+-#endif
+
+-/* callers should hold rtnl semaphore */
++static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = {
++ [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
++ [FRA_PRIORITY] = { .type = NLA_U32 },
++ [FRA_SRC] = { .type = NLA_U32 },
++ [FRA_DST] = { .type = NLA_U32 },
++ [FRA_FWMARK] = { .type = NLA_U32 },
++ [FRA_FWMASK] = { .type = NLA_U32 },
++ [FRA_FLOW] = { .type = NLA_U32 },
++ [FRA_TABLE] = { .type = NLA_U32 },
++};
+
+-static void fib_rules_detach(struct net_device *dev)
++static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
++ struct nlmsghdr *nlh, struct fib_rule_hdr *frh,
++ struct nlattr **tb)
+ {
+- struct hlist_node *node;
+- struct fib_rule *r;
++ int err = -EINVAL;
++ struct fib4_rule *rule4 = (struct fib4_rule *) rule;
++
++ if (frh->src_len > 32 || frh->dst_len > 32 ||
++ (frh->tos & ~IPTOS_TOS_MASK))
++ goto errout;
++
++ if (rule->table == RT_TABLE_UNSPEC) {
++ if (rule->action == FR_ACT_TO_TBL) {
++ struct fib_table *table;
+
+- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+- if (r->r_ifindex == dev->ifindex)
+- r->r_ifindex = -1;
++ table = fib_empty_table();
++ if (table == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
+
++ rule->table = table->tb_id;
++ }
+ }
+-}
+
+-/* callers should hold rtnl semaphore */
++ if (tb[FRA_SRC])
++ rule4->src = nla_get_be32(tb[FRA_SRC]);
+
+-static void fib_rules_attach(struct net_device *dev)
+-{
+- struct hlist_node *node;
+- struct fib_rule *r;
++ if (tb[FRA_DST])
++ rule4->dst = nla_get_be32(tb[FRA_DST]);
+
+- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+- if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
+- r->r_ifindex = dev->ifindex;
++#ifdef CONFIG_IP_ROUTE_FWMARK
++ if (tb[FRA_FWMARK]) {
++ rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]);
++ if (rule4->fwmark)
++ /* compatibility: if the mark value is non-zero all bits
++ * are compared unless a mask is explicitly specified.
++ */
++ rule4->fwmask = 0xFFFFFFFF;
+ }
++
++ if (tb[FRA_FWMASK])
++ rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]);
++#endif
++
++#ifdef CONFIG_NET_CLS_ROUTE
++ if (tb[FRA_FLOW])
++ rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
++#endif
++
++ rule4->src_len = frh->src_len;
++ rule4->srcmask = inet_make_mask(rule4->src_len);
++ rule4->dst_len = frh->dst_len;
++ rule4->dstmask = inet_make_mask(rule4->dst_len);
++ rule4->tos = frh->tos;
++
++ err = 0;
++errout:
++ return err;
+ }
+
+-int fib_lookup(const struct flowi *flp, struct fib_result *res)
++static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
++ struct nlattr **tb)
+ {
+- int err;
+- struct fib_rule *r, *policy;
+- struct fib_table *tb;
+- struct hlist_node *node;
++ struct fib4_rule *rule4 = (struct fib4_rule *) rule;
+
+- u32 daddr = flp->fl4_dst;
+- u32 saddr = flp->fl4_src;
++ if (frh->src_len && (rule4->src_len != frh->src_len))
++ return 0;
+
+-FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
+- NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
++ if (frh->dst_len && (rule4->dst_len != frh->dst_len))
++ return 0;
+
+- rcu_read_lock();
++ if (frh->tos && (rule4->tos != frh->tos))
++ return 0;
+
+- hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) {
+- if (((saddr^r->r_src) & r->r_srcmask) ||
+- ((daddr^r->r_dst) & r->r_dstmask) ||
+- (r->r_tos && r->r_tos != flp->fl4_tos) ||
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+- (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) ||
++ if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK])))
++ return 0;
++
++ if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK])))
++ return 0;
+ #endif
+- (r->r_ifindex && r->r_ifindex != flp->iif))
+- continue;
+-
+-FRprintk("tb %d r %d ", r->r_table, r->r_action);
+- switch (r->r_action) {
+- case RTN_UNICAST:
+- policy = r;
+- break;
+- case RTN_UNREACHABLE:
+- rcu_read_unlock();
+- return -ENETUNREACH;
+- default:
+- case RTN_BLACKHOLE:
+- rcu_read_unlock();
+- return -EINVAL;
+- case RTN_PROHIBIT:
+- rcu_read_unlock();
+- return -EACCES;
+- }
+
+- if ((tb = fib_get_table(r->r_table)) == NULL)
+- continue;
+- err = tb->tb_lookup(tb, flp, res);
+- if (err == 0) {
+- res->r = policy;
+- if (policy)
+- atomic_inc(&policy->r_clntref);
+- rcu_read_unlock();
+- return 0;
+- }
+- if (err < 0 && err != -EAGAIN) {
+- rcu_read_unlock();
+- return err;
+- }
+- }
+-FRprintk("FAILURE\n");
+- rcu_read_unlock();
+- return -ENETUNREACH;
+-}
++#ifdef CONFIG_NET_CLS_ROUTE
++ if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW])))
++ return 0;
++#endif
+
+-void fib_select_default(const struct flowi *flp, struct fib_result *res)
+-{
+- if (res->r && res->r->r_action == RTN_UNICAST &&
+- FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
+- struct fib_table *tb;
+- if ((tb = fib_get_table(res->r->r_table)) != NULL)
+- tb->tb_select_default(tb, flp, res);
+- }
+-}
++ if (tb[FRA_SRC] && (rule4->src != nla_get_be32(tb[FRA_SRC])))
++ return 0;
+
+-static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
+-{
+- struct net_device *dev = ptr;
++ if (tb[FRA_DST] && (rule4->dst != nla_get_be32(tb[FRA_DST])))
++ return 0;
+
+- if (event == NETDEV_UNREGISTER)
+- fib_rules_detach(dev);
+- else if (event == NETDEV_REGISTER)
+- fib_rules_attach(dev);
+- return NOTIFY_DONE;
++ return 1;
+ }
+
++static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
++ struct nlmsghdr *nlh, struct fib_rule_hdr *frh)
++{
++ struct fib4_rule *rule4 = (struct fib4_rule *) rule;
+
+-static struct notifier_block fib_rules_notifier = {
+- .notifier_call =fib_rules_event,
+-};
++ frh->family = AF_INET;
++ frh->dst_len = rule4->dst_len;
++ frh->src_len = rule4->src_len;
++ frh->tos = rule4->tos;
+
+-static __inline__ int inet_fill_rule(struct sk_buff *skb,
+- struct fib_rule *r,
+- u32 pid, u32 seq, int event,
+- unsigned int flags)
+-{
+- struct rtmsg *rtm;
+- struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
+-
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
+- rtm = NLMSG_DATA(nlh);
+- rtm->rtm_family = AF_INET;
+- rtm->rtm_dst_len = r->r_dst_len;
+- rtm->rtm_src_len = r->r_src_len;
+- rtm->rtm_tos = r->r_tos;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+- if (r->r_fwmark)
+- RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
++ if (rule4->fwmark)
++ NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark);
++
++ if (rule4->fwmask || rule4->fwmark)
++ NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask);
+ #endif
+- rtm->rtm_table = r->r_table;
+- rtm->rtm_protocol = 0;
+- rtm->rtm_scope = 0;
+- rtm->rtm_type = r->r_action;
+- rtm->rtm_flags = r->r_flags;
+-
+- if (r->r_dst_len)
+- RTA_PUT(skb, RTA_DST, 4, &r->r_dst);
+- if (r->r_src_len)
+- RTA_PUT(skb, RTA_SRC, 4, &r->r_src);
+- if (r->r_ifname[0])
+- RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
+- if (r->r_preference)
+- RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
+- if (r->r_srcmap)
+- RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap);
++
++ if (rule4->dst_len)
++ NLA_PUT_BE32(skb, FRA_DST, rule4->dst);
++
++ if (rule4->src_len)
++ NLA_PUT_BE32(skb, FRA_SRC, rule4->src);
++
+ #ifdef CONFIG_NET_CLS_ROUTE
+- if (r->r_tclassid)
+- RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid);
++ if (rule4->tclassid)
++ NLA_PUT_U32(skb, FRA_FLOW, rule4->tclassid);
+ #endif
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ return 0;
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++nla_put_failure:
++ return -ENOBUFS;
+ }
+
+-/* callers should hold rtnl semaphore */
+-
+-static void rtmsg_rule(int event, struct fib_rule *r)
++int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+- int size = NLMSG_SPACE(sizeof(struct rtmsg) + 128);
+- struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
+-
+- if (!skb)
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, ENOBUFS);
+- else if (inet_fill_rule(skb, r, 0, 0, event, 0) < 0) {
+- kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, EINVAL);
+- } else {
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_RULE, GFP_KERNEL);
+- }
++ return fib_rules_dump(skb, cb, AF_INET);
+ }
+
+-int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
++static u32 fib4_rule_default_pref(void)
+ {
+- int idx = 0;
+- int s_idx = cb->args[0];
+- struct fib_rule *r;
+- struct hlist_node *node;
+-
+- rcu_read_lock();
+- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+- if (idx < s_idx)
+- goto next;
+- if (inet_fill_rule(skb, r, NETLINK_CB(cb->skb).pid,
+- cb->nlh->nlmsg_seq,
+- RTM_NEWRULE, NLM_F_MULTI) < 0)
+- break;
+-next:
+- idx++;
++ struct list_head *pos;
++ struct fib_rule *rule;
++
++ if (!list_empty(&fib4_rules)) {
++ pos = fib4_rules.next;
++ if (pos->next != &fib4_rules) {
++ rule = list_entry(pos->next, struct fib_rule, list);
++ if (rule->pref)
++ return rule->pref - 1;
++ }
+ }
+- rcu_read_unlock();
+- cb->args[0] = idx;
+
+- return skb->len;
++ return 0;
+ }
+
+-void __init fib_rules_init(void)
++static struct fib_rules_ops fib4_rules_ops = {
++ .family = AF_INET,
++ .rule_size = sizeof(struct fib4_rule),
++ .action = fib4_rule_action,
++ .match = fib4_rule_match,
++ .configure = fib4_rule_configure,
++ .compare = fib4_rule_compare,
++ .fill = fib4_rule_fill,
++ .default_pref = fib4_rule_default_pref,
++ .nlgroup = RTNLGRP_IPV4_RULE,
++ .policy = fib4_rule_policy,
++ .rules_list = &fib4_rules,
++ .owner = THIS_MODULE,
++};
++
++void __init fib4_rules_init(void)
+ {
+- INIT_HLIST_HEAD(&fib_rules);
+- hlist_add_head(&local_rule.hlist, &fib_rules);
+- hlist_add_after(&local_rule.hlist, &main_rule.hlist);
+- hlist_add_after(&main_rule.hlist, &default_rule.hlist);
+- register_netdevice_notifier(&fib_rules_notifier);
++ list_add_tail(&local_rule.common.list, &fib4_rules);
++ list_add_tail(&main_rule.common.list, &fib4_rules);
++ list_add_tail(&default_rule.common.list, &fib4_rules);
++
++ fib_rules_register(&fib4_rules_ops);
+ }
+diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
+index 5173800..884d176 100644
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -33,7 +33,6 @@
+ #include <linux/if_arp.h>
+ #include <linux/proc_fs.h>
+ #include <linux/skbuff.h>
+-#include <linux/netlink.h>
+ #include <linux/init.h>
+
+ #include <net/arp.h>
+@@ -44,12 +43,14 @@
+ #include <net/sock.h>
+ #include <net/ip_fib.h>
+ #include <net/ip_mp_alg.h>
++#include <net/netlink.h>
++#include <net/nexthop.h>
+
+ #include "fib_lookup.h"
+
+ #define FSprintk(a...)
+
+-static DEFINE_RWLOCK(fib_info_lock);
++static DEFINE_SPINLOCK(fib_info_lock);
+ static struct hlist_head *fib_info_hash;
+ static struct hlist_head *fib_info_laddrhash;
+ static unsigned int fib_hash_size;
+@@ -159,7 +160,7 @@ void free_fib_info(struct fib_info *fi)
+
+ void fib_release_info(struct fib_info *fi)
+ {
+- write_lock_bh(&fib_info_lock);
++ spin_lock_bh(&fib_info_lock);
+ if (fi && --fi->fib_treeref == 0) {
+ hlist_del(&fi->fib_hash);
+ if (fi->fib_prefsrc)
+@@ -172,7 +173,7 @@ void fib_release_info(struct fib_info *f
+ fi->fib_dead = 1;
+ fib_info_put(fi);
+ }
+- write_unlock_bh(&fib_info_lock);
++ spin_unlock_bh(&fib_info_lock);
+ }
+
+ static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
+@@ -202,7 +203,7 @@ static inline unsigned int fib_info_hash
+ unsigned int val = fi->fib_nhs;
+
+ val ^= fi->fib_protocol;
+- val ^= fi->fib_prefsrc;
++ val ^= (__force u32)fi->fib_prefsrc;
+ val ^= fi->fib_priority;
+
+ return (val ^ (val >> 7) ^ (val >> 12)) & mask;
+@@ -247,14 +248,14 @@ static inline unsigned int fib_devindex_
+ Used only by redirect accept routine.
+ */
+
+-int ip_fib_check_default(u32 gw, struct net_device *dev)
++int ip_fib_check_default(__be32 gw, struct net_device *dev)
+ {
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct fib_nh *nh;
+ unsigned int hash;
+
+- read_lock(&fib_info_lock);
++ spin_lock(&fib_info_lock);
+
+ hash = fib_devindex_hashfn(dev->ifindex);
+ head = &fib_info_devhash[hash];
+@@ -262,41 +263,41 @@ int ip_fib_check_default(u32 gw, struct
+ if (nh->nh_dev == dev &&
+ nh->nh_gw == gw &&
+ !(nh->nh_flags&RTNH_F_DEAD)) {
+- read_unlock(&fib_info_lock);
++ spin_unlock(&fib_info_lock);
+ return 0;
+ }
+ }
+
+- read_unlock(&fib_info_lock);
++ spin_unlock(&fib_info_lock);
+
+ return -1;
+ }
+
+-void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
+- int z, int tb_id,
+- struct nlmsghdr *n, struct netlink_skb_parms *req)
++void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
++ int dst_len, u32 tb_id, struct nl_info *info)
+ {
+ struct sk_buff *skb;
+- u32 pid = req ? req->pid : n->nlmsg_pid;
+- int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+-
+- skb = alloc_skb(size, GFP_KERNEL);
+- if (!skb)
+- return;
+-
+- if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id,
+- fa->fa_type, fa->fa_scope, &key, z,
+- fa->fa_tos,
+- fa->fa_info, 0) < 0) {
++ int payload = sizeof(struct rtmsg) + 256;
++ u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
++ int err = -ENOBUFS;
++
++ skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
++ if (skb == NULL)
++ goto errout;
++
++ err = fib_dump_info(skb, info->pid, seq, event, tb_id,
++ fa->fa_type, fa->fa_scope, key, dst_len,
++ fa->fa_tos, fa->fa_info, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_IPV4_ROUTE;
+- if (n->nlmsg_flags&NLM_F_ECHO)
+- atomic_inc(&skb->users);
+- netlink_broadcast(rtnl, skb, pid, RTNLGRP_IPV4_ROUTE, GFP_KERNEL);
+- if (n->nlmsg_flags&NLM_F_ECHO)
+- netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
++
++ err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
++ info->nlh, GFP_KERNEL);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err);
+ }
+
+ /* Return the first fib alias matching TOS with
+@@ -342,102 +343,100 @@ int fib_detect_death(struct fib_info *fi
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+
+-static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type)
+-{
+- while (RTA_OK(attr,attrlen)) {
+- if (attr->rta_type == type)
+- return *(u32*)RTA_DATA(attr);
+- attr = RTA_NEXT(attr, attrlen);
+- }
+- return 0;
+-}
+-
+-static int
+-fib_count_nexthops(struct rtattr *rta)
++static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining)
+ {
+ int nhs = 0;
+- struct rtnexthop *nhp = RTA_DATA(rta);
+- int nhlen = RTA_PAYLOAD(rta);
+
+- while (nhlen >= (int)sizeof(struct rtnexthop)) {
+- if ((nhlen -= nhp->rtnh_len) < 0)
+- return 0;
++ while (rtnh_ok(rtnh, remaining)) {
+ nhs++;
+- nhp = RTNH_NEXT(nhp);
+- };
+- return nhs;
++ rtnh = rtnh_next(rtnh, &remaining);
++ }
++
++ /* leftover implies invalid nexthop configuration, discard it */
++ return remaining > 0 ? 0 : nhs;
+ }
+
+-static int
+-fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
++static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
++ int remaining, struct fib_config *cfg)
+ {
+- struct rtnexthop *nhp = RTA_DATA(rta);
+- int nhlen = RTA_PAYLOAD(rta);
+-
+ change_nexthops(fi) {
+- int attrlen = nhlen - sizeof(struct rtnexthop);
+- if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
++ int attrlen;
++
++ if (!rtnh_ok(rtnh, remaining))
+ return -EINVAL;
+- nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
+- nh->nh_oif = nhp->rtnh_ifindex;
+- nh->nh_weight = nhp->rtnh_hops + 1;
+- if (attrlen) {
+- nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
++
++ nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
++ nh->nh_oif = rtnh->rtnh_ifindex;
++ nh->nh_weight = rtnh->rtnh_hops + 1;
++
++ attrlen = rtnh_attrlen(rtnh);
++ if (attrlen > 0) {
++ struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
++
++ nla = nla_find(attrs, attrlen, RTA_GATEWAY);
++ nh->nh_gw = nla ? nla_get_be32(nla) : 0;
+ #ifdef CONFIG_NET_CLS_ROUTE
+- nh->nh_tclassid = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW);
++ nla = nla_find(attrs, attrlen, RTA_FLOW);
++ nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
+ #endif
+ }
+- nhp = RTNH_NEXT(nhp);
++
++ rtnh = rtnh_next(rtnh, &remaining);
+ } endfor_nexthops(fi);
++
+ return 0;
+ }
+
+ #endif
+
+-int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta,
+- struct fib_info *fi)
++int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
+ {
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- struct rtnexthop *nhp;
+- int nhlen;
++ struct rtnexthop *rtnh;
++ int remaining;
+ #endif
+
+- if (rta->rta_priority &&
+- *rta->rta_priority != fi->fib_priority)
++ if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority)
+ return 1;
+
+- if (rta->rta_oif || rta->rta_gw) {
+- if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
+- (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0))
++ if (cfg->fc_oif || cfg->fc_gw) {
++ if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
++ (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw))
+ return 0;
+ return 1;
+ }
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (rta->rta_mp == NULL)
++ if (cfg->fc_mp == NULL)
+ return 0;
+- nhp = RTA_DATA(rta->rta_mp);
+- nhlen = RTA_PAYLOAD(rta->rta_mp);
++
++ rtnh = cfg->fc_mp;
++ remaining = cfg->fc_mp_len;
+
+ for_nexthops(fi) {
+- int attrlen = nhlen - sizeof(struct rtnexthop);
+- u32 gw;
++ int attrlen;
+
+- if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
++ if (!rtnh_ok(rtnh, remaining))
+ return -EINVAL;
+- if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
++
++ if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->nh_oif)
+ return 1;
+- if (attrlen) {
+- gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+- if (gw && gw != nh->nh_gw)
++
++ attrlen = rtnh_attrlen(rtnh);
++ if (attrlen < 0) {
++ struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
++
++ nla = nla_find(attrs, attrlen, RTA_GATEWAY);
++ if (nla && nla_get_be32(nla) != nh->nh_gw)
+ return 1;
+ #ifdef CONFIG_NET_CLS_ROUTE
+- gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW);
+- if (gw && gw != nh->nh_tclassid)
++ nla = nla_find(attrs, attrlen, RTA_FLOW);
++ if (nla && nla_get_u32(nla) != nh->nh_tclassid)
+ return 1;
+ #endif
+ }
+- nhp = RTNH_NEXT(nhp);
++
++ rtnh = rtnh_next(rtnh, &remaining);
+ } endfor_nexthops(fi);
+ #endif
+ return 0;
+@@ -488,7 +487,8 @@ int fib_nh_match(struct rtmsg *r, struct
+ |-> {local prefix} (terminal node)
+ */
+
+-static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh)
++static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
++ struct fib_nh *nh)
+ {
+ int err;
+
+@@ -502,7 +502,7 @@ static int fib_check_nh(const struct rtm
+ if (nh->nh_flags&RTNH_F_ONLINK) {
+ struct net_device *dev;
+
+- if (r->rtm_scope >= RT_SCOPE_LINK)
++ if (cfg->fc_scope >= RT_SCOPE_LINK)
+ return -EINVAL;
+ if (inet_addr_type(nh->nh_gw) != RTN_UNICAST)
+ return -EINVAL;
+@@ -516,10 +516,15 @@ static int fib_check_nh(const struct rtm
+ return 0;
+ }
+ {
+- struct flowi fl = { .nl_u = { .ip4_u =
+- { .daddr = nh->nh_gw,
+- .scope = r->rtm_scope + 1 } },
+- .oif = nh->nh_oif };
++ struct flowi fl = {
++ .nl_u = {
++ .ip4_u = {
++ .daddr = nh->nh_gw,
++ .scope = cfg->fc_scope + 1,
++ },
++ },
++ .oif = nh->nh_oif,
++ };
+
+ /* It is not necessary, but requires a bit of thinking */
+ if (fl.fl4_scope < RT_SCOPE_LINK)
+@@ -563,11 +568,11 @@ out:
+ return 0;
+ }
+
+-static inline unsigned int fib_laddr_hashfn(u32 val)
++static inline unsigned int fib_laddr_hashfn(__be32 val)
+ {
+ unsigned int mask = (fib_hash_size - 1);
+
+- return (val ^ (val >> 7) ^ (val >> 14)) & mask;
++ return ((__force u32)val ^ ((__force u32)val >> 7) ^ ((__force u32)val >> 14)) & mask;
+ }
+
+ static struct hlist_head *fib_hash_alloc(int bytes)
+@@ -598,7 +603,7 @@ static void fib_hash_move(struct hlist_h
+ unsigned int old_size = fib_hash_size;
+ unsigned int i, bytes;
+
+- write_lock_bh(&fib_info_lock);
++ spin_lock_bh(&fib_info_lock);
+ old_info_hash = fib_info_hash;
+ old_laddrhash = fib_info_laddrhash;
+ fib_hash_size = new_size;
+@@ -639,46 +644,35 @@ static void fib_hash_move(struct hlist_h
+ }
+ fib_info_laddrhash = new_laddrhash;
+
+- write_unlock_bh(&fib_info_lock);
++ spin_unlock_bh(&fib_info_lock);
+
+ bytes = old_size * sizeof(struct hlist_head *);
+ fib_hash_free(old_info_hash, bytes);
+ fib_hash_free(old_laddrhash, bytes);
+ }
+
+-struct fib_info *
+-fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
+- const struct nlmsghdr *nlh, int *errp)
++struct fib_info *fib_create_info(struct fib_config *cfg)
+ {
+ int err;
+ struct fib_info *fi = NULL;
+ struct fib_info *ofi;
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ int nhs = 1;
+-#else
+- const int nhs = 1;
+-#endif
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+- u32 mp_alg = IP_MP_ALG_NONE;
+-#endif
+
+ /* Fast check to catch the most weird cases */
+- if (fib_props[r->rtm_type].scope > r->rtm_scope)
++ if (fib_props[cfg->fc_type].scope > cfg->fc_scope)
+ goto err_inval;
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (rta->rta_mp) {
+- nhs = fib_count_nexthops(rta->rta_mp);
++ if (cfg->fc_mp) {
++ nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len);
+ if (nhs == 0)
+ goto err_inval;
+ }
+ #endif
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+- if (rta->rta_mp_alg) {
+- mp_alg = *rta->rta_mp_alg;
+-
+- if (mp_alg < IP_MP_ALG_NONE ||
+- mp_alg > IP_MP_ALG_MAX)
++ if (cfg->fc_mp_alg) {
++ if (cfg->fc_mp_alg < IP_MP_ALG_NONE ||
++ cfg->fc_mp_alg > IP_MP_ALG_MAX)
+ goto err_inval;
+ }
+ #endif
+@@ -714,43 +708,42 @@ fib_create_info(const struct rtmsg *r, s
+ goto failure;
+ fib_info_cnt++;
+
+- fi->fib_protocol = r->rtm_protocol;
++ fi->fib_protocol = cfg->fc_protocol;
++ fi->fib_flags = cfg->fc_flags;
++ fi->fib_priority = cfg->fc_priority;
++ fi->fib_prefsrc = cfg->fc_prefsrc;
+
+ fi->fib_nhs = nhs;
+ change_nexthops(fi) {
+ nh->nh_parent = fi;
+ } endfor_nexthops(fi)
+
+- fi->fib_flags = r->rtm_flags;
+- if (rta->rta_priority)
+- fi->fib_priority = *rta->rta_priority;
+- if (rta->rta_mx) {
+- int attrlen = RTA_PAYLOAD(rta->rta_mx);
+- struct rtattr *attr = RTA_DATA(rta->rta_mx);
+-
+- while (RTA_OK(attr, attrlen)) {
+- unsigned flavor = attr->rta_type;
+- if (flavor) {
+- if (flavor > RTAX_MAX)
++ if (cfg->fc_mx) {
++ struct nlattr *nla;
++ int remaining;
++
++ nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
++ int type = nla->nla_type;
++
++ if (type) {
++ if (type > RTAX_MAX)
+ goto err_inval;
+- fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr);
++ fi->fib_metrics[type - 1] = nla_get_u32(nla);
+ }
+- attr = RTA_NEXT(attr, attrlen);
+ }
+ }
+- if (rta->rta_prefsrc)
+- memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4);
+
+- if (rta->rta_mp) {
++ if (cfg->fc_mp) {
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0)
++ err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg);
++ if (err != 0)
+ goto failure;
+- if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
++ if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif)
+ goto err_inval;
+- if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4))
++ if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw)
+ goto err_inval;
+ #ifdef CONFIG_NET_CLS_ROUTE
+- if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4))
++ if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow)
+ goto err_inval;
+ #endif
+ #else
+@@ -758,34 +751,32 @@ fib_create_info(const struct rtmsg *r, s
+ #endif
+ } else {
+ struct fib_nh *nh = fi->fib_nh;
+- if (rta->rta_oif)
+- nh->nh_oif = *rta->rta_oif;
+- if (rta->rta_gw)
+- memcpy(&nh->nh_gw, rta->rta_gw, 4);
++
++ nh->nh_oif = cfg->fc_oif;
++ nh->nh_gw = cfg->fc_gw;
++ nh->nh_flags = cfg->fc_flags;
+ #ifdef CONFIG_NET_CLS_ROUTE
+- if (rta->rta_flow)
+- memcpy(&nh->nh_tclassid, rta->rta_flow, 4);
++ nh->nh_tclassid = cfg->fc_flow;
+ #endif
+- nh->nh_flags = r->rtm_flags;
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ nh->nh_weight = 1;
+ #endif
+ }
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+- fi->fib_mp_alg = mp_alg;
++ fi->fib_mp_alg = cfg->fc_mp_alg;
+ #endif
+
+- if (fib_props[r->rtm_type].error) {
+- if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
++ if (fib_props[cfg->fc_type].error) {
++ if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp)
+ goto err_inval;
+ goto link_it;
+ }
+
+- if (r->rtm_scope > RT_SCOPE_HOST)
++ if (cfg->fc_scope > RT_SCOPE_HOST)
+ goto err_inval;
+
+- if (r->rtm_scope == RT_SCOPE_HOST) {
++ if (cfg->fc_scope == RT_SCOPE_HOST) {
+ struct fib_nh *nh = fi->fib_nh;
+
+ /* Local address is added. */
+@@ -798,14 +789,14 @@ fib_create_info(const struct rtmsg *r, s
+ goto failure;
+ } else {
+ change_nexthops(fi) {
+- if ((err = fib_check_nh(r, fi, nh)) != 0)
++ if ((err = fib_check_nh(cfg, fi, nh)) != 0)
+ goto failure;
+ } endfor_nexthops(fi)
+ }
+
+ if (fi->fib_prefsrc) {
+- if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
+- memcmp(&fi->fib_prefsrc, rta->rta_dst, 4))
++ if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
++ fi->fib_prefsrc != cfg->fc_dst)
+ if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
+ goto err_inval;
+ }
+@@ -820,7 +811,7 @@ link_it:
+
+ fi->fib_treeref++;
+ atomic_inc(&fi->fib_clntref);
+- write_lock_bh(&fib_info_lock);
++ spin_lock_bh(&fib_info_lock);
+ hlist_add_head(&fi->fib_hash,
+ &fib_info_hash[fib_info_hashfn(fi)]);
+ if (fi->fib_prefsrc) {
+@@ -839,24 +830,24 @@ link_it:
+ head = &fib_info_devhash[hash];
+ hlist_add_head(&nh->nh_hash, head);
+ } endfor_nexthops(fi)
+- write_unlock_bh(&fib_info_lock);
++ spin_unlock_bh(&fib_info_lock);
+ return fi;
+
+ err_inval:
+ err = -EINVAL;
+
+ failure:
+- *errp = err;
+ if (fi) {
+ fi->fib_dead = 1;
+ free_fib_info(fi);
+ }
+- return NULL;
++
++ return ERR_PTR(err);
+ }
+
+ /* Note! fib_semantic_match intentionally uses RCU list functions. */
+ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
+- struct fib_result *res, __u32 zone, __u32 mask,
++ struct fib_result *res, __be32 zone, __be32 mask,
+ int prefixlen)
+ {
+ struct fib_alias *fa;
+@@ -923,8 +914,7 @@ out_fill_res:
+ res->fi = fa->fa_info;
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+ res->netmask = mask;
+- res->network = zone &
+- (0xFFFFFFFF >> (32 - prefixlen));
++ res->network = zone & inet_make_mask(prefixlen);
+ #endif
+ atomic_inc(&res->fi->fib_clntref);
+ return 0;
+@@ -932,229 +922,94 @@ out_fill_res:
+
+ /* Find appropriate source address to this destination */
+
+-u32 __fib_res_prefsrc(struct fib_result *res)
++__be32 __fib_res_prefsrc(struct fib_result *res)
+ {
+ return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
+ }
+
+-int
+-fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+- u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos,
+- struct fib_info *fi, unsigned int flags)
++int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
++ u32 tb_id, u8 type, u8 scope, __be32 dst, int dst_len, u8 tos,
++ struct fib_info *fi, unsigned int flags)
+ {
++ struct nlmsghdr *nlh;
+ struct rtmsg *rtm;
+- struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
+
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
+- rtm = NLMSG_DATA(nlh);
++ nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ rtm = nlmsg_data(nlh);
+ rtm->rtm_family = AF_INET;
+ rtm->rtm_dst_len = dst_len;
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = tos;
+ rtm->rtm_table = tb_id;
++ NLA_PUT_U32(skb, RTA_TABLE, tb_id);
+ rtm->rtm_type = type;
+ rtm->rtm_flags = fi->fib_flags;
+ rtm->rtm_scope = scope;
+- if (rtm->rtm_dst_len)
+- RTA_PUT(skb, RTA_DST, 4, dst);
+ rtm->rtm_protocol = fi->fib_protocol;
++
++ if (rtm->rtm_dst_len)
++ NLA_PUT_BE32(skb, RTA_DST, dst);
++
+ if (fi->fib_priority)
+- RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
++ NLA_PUT_U32(skb, RTA_PRIORITY, fi->fib_priority);
++
+ if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
+- goto rtattr_failure;
++ goto nla_put_failure;
++
+ if (fi->fib_prefsrc)
+- RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc);
++ NLA_PUT_BE32(skb, RTA_PREFSRC, fi->fib_prefsrc);
++
+ if (fi->fib_nhs == 1) {
+ if (fi->fib_nh->nh_gw)
+- RTA_PUT(skb, RTA_GATEWAY, 4, &fi->fib_nh->nh_gw);
++ NLA_PUT_BE32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw);
++
+ if (fi->fib_nh->nh_oif)
+- RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
++ NLA_PUT_U32(skb, RTA_OIF, fi->fib_nh->nh_oif);
+ #ifdef CONFIG_NET_CLS_ROUTE
+ if (fi->fib_nh[0].nh_tclassid)
+- RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid);
++ NLA_PUT_U32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid);
+ #endif
+ }
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (fi->fib_nhs > 1) {
+- struct rtnexthop *nhp;
+- struct rtattr *mp_head;
+- if (skb_tailroom(skb) <= RTA_SPACE(0))
+- goto rtattr_failure;
+- mp_head = (struct rtattr*)skb_put(skb, RTA_SPACE(0));
++ struct rtnexthop *rtnh;
++ struct nlattr *mp;
++
++ mp = nla_nest_start(skb, RTA_MULTIPATH);
++ if (mp == NULL)
++ goto nla_put_failure;
+
+ for_nexthops(fi) {
+- if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
+- goto rtattr_failure;
+- nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+- nhp->rtnh_flags = nh->nh_flags & 0xFF;
+- nhp->rtnh_hops = nh->nh_weight-1;
+- nhp->rtnh_ifindex = nh->nh_oif;
++ rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
++ if (rtnh == NULL)
++ goto nla_put_failure;
++
++ rtnh->rtnh_flags = nh->nh_flags & 0xFF;
++ rtnh->rtnh_hops = nh->nh_weight - 1;
++ rtnh->rtnh_ifindex = nh->nh_oif;
++
+ if (nh->nh_gw)
+- RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw);
++ NLA_PUT_BE32(skb, RTA_GATEWAY, nh->nh_gw);
+ #ifdef CONFIG_NET_CLS_ROUTE
+ if (nh->nh_tclassid)
+- RTA_PUT(skb, RTA_FLOW, 4, &nh->nh_tclassid);
++ NLA_PUT_U32(skb, RTA_FLOW, nh->nh_tclassid);
+ #endif
+- nhp->rtnh_len = skb->tail - (unsigned char*)nhp;
++ /* length of rtnetlink header + attributes */
++ rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh;
+ } endfor_nexthops(fi);
+- mp_head->rta_type = RTA_MULTIPATH;
+- mp_head->rta_len = skb->tail - (u8*)mp_head;
+- }
+-#endif
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
+-
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
+-}
+-
+-#ifndef CONFIG_IP_NOSIOCRT
+-
+-int
+-fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
+- struct kern_rta *rta, struct rtentry *r)
+-{
+- int plen;
+- u32 *ptr;
+-
+- memset(rtm, 0, sizeof(*rtm));
+- memset(rta, 0, sizeof(*rta));
+-
+- if (r->rt_dst.sa_family != AF_INET)
+- return -EAFNOSUPPORT;
+-
+- /* Check mask for validity:
+- a) it must be contiguous.
+- b) destination must have all host bits clear.
+- c) if application forgot to set correct family (AF_INET),
+- reject request unless it is absolutely clear i.e.
+- both family and mask are zero.
+- */
+- plen = 32;
+- ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;
+- if (!(r->rt_flags&RTF_HOST)) {
+- u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
+- if (r->rt_genmask.sa_family != AF_INET) {
+- if (mask || r->rt_genmask.sa_family)
+- return -EAFNOSUPPORT;
+- }
+- if (bad_mask(mask, *ptr))
+- return -EINVAL;
+- plen = inet_mask_len(mask);
+- }
+-
+- nl->nlmsg_flags = NLM_F_REQUEST;
+- nl->nlmsg_pid = 0;
+- nl->nlmsg_seq = 0;
+- nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm));
+- if (cmd == SIOCDELRT) {
+- nl->nlmsg_type = RTM_DELROUTE;
+- nl->nlmsg_flags = 0;
+- } else {
+- nl->nlmsg_type = RTM_NEWROUTE;
+- nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
+- rtm->rtm_protocol = RTPROT_BOOT;
+- }
+-
+- rtm->rtm_dst_len = plen;
+- rta->rta_dst = ptr;
+-
+- if (r->rt_metric) {
+- *(u32*)&r->rt_pad3 = r->rt_metric - 1;
+- rta->rta_priority = (u32*)&r->rt_pad3;
+- }
+- if (r->rt_flags&RTF_REJECT) {
+- rtm->rtm_scope = RT_SCOPE_HOST;
+- rtm->rtm_type = RTN_UNREACHABLE;
+- return 0;
+- }
+- rtm->rtm_scope = RT_SCOPE_NOWHERE;
+- rtm->rtm_type = RTN_UNICAST;
+-
+- if (r->rt_dev) {
+- char *colon;
+- struct net_device *dev;
+- char devname[IFNAMSIZ];
+-
+- if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1))
+- return -EFAULT;
+- devname[IFNAMSIZ-1] = 0;
+- colon = strchr(devname, ':');
+- if (colon)
+- *colon = 0;
+- dev = __dev_get_by_name(devname);
+- if (!dev)
+- return -ENODEV;
+- rta->rta_oif = &dev->ifindex;
+- if (colon) {
+- struct in_ifaddr *ifa;
+- struct in_device *in_dev = __in_dev_get_rtnl(dev);
+- if (!in_dev)
+- return -ENODEV;
+- *colon = ':';
+- for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
+- if (strcmp(ifa->ifa_label, devname) == 0)
+- break;
+- if (ifa == NULL)
+- return -ENODEV;
+- rta->rta_prefsrc = &ifa->ifa_local;
+- }
+- }
+
+- ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr;
+- if (r->rt_gateway.sa_family == AF_INET && *ptr) {
+- rta->rta_gw = ptr;
+- if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST)
+- rtm->rtm_scope = RT_SCOPE_UNIVERSE;
++ nla_nest_end(skb, mp);
+ }
++#endif
++ return nlmsg_end(skb, nlh);
+
+- if (cmd == SIOCDELRT)
+- return 0;
+-
+- if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)
+- return -EINVAL;
+-
+- if (rtm->rtm_scope == RT_SCOPE_NOWHERE)
+- rtm->rtm_scope = RT_SCOPE_LINK;
+-
+- if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
+- struct rtattr *rec;
+- struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
+- if (mx == NULL)
+- return -ENOMEM;
+- rta->rta_mx = mx;
+- mx->rta_type = RTA_METRICS;
+- mx->rta_len = RTA_LENGTH(0);
+- if (r->rt_flags&RTF_MTU) {
+- rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+- rec->rta_type = RTAX_ADVMSS;
+- rec->rta_len = RTA_LENGTH(4);
+- mx->rta_len += RTA_LENGTH(4);
+- *(u32*)RTA_DATA(rec) = r->rt_mtu - 40;
+- }
+- if (r->rt_flags&RTF_WINDOW) {
+- rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+- rec->rta_type = RTAX_WINDOW;
+- rec->rta_len = RTA_LENGTH(4);
+- mx->rta_len += RTA_LENGTH(4);
+- *(u32*)RTA_DATA(rec) = r->rt_window;
+- }
+- if (r->rt_flags&RTF_IRTT) {
+- rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+- rec->rta_type = RTAX_RTT;
+- rec->rta_len = RTA_LENGTH(4);
+- mx->rta_len += RTA_LENGTH(4);
+- *(u32*)RTA_DATA(rec) = r->rt_irtt<<3;
+- }
+- }
+- return 0;
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
+ }
+
+-#endif
+-
+ /*
+ Update FIB if:
+ - local address disappeared -> we must delete all the entries
+@@ -1162,7 +1017,7 @@ fib_convert_rtentry(int cmd, struct nlms
+ - device went down -> we must shutdown all nexthops going via it.
+ */
+
+-int fib_sync_down(u32 local, struct net_device *dev, int force)
++int fib_sync_down(__be32 local, struct net_device *dev, int force)
+ {
+ int ret = 0;
+ int scope = RT_SCOPE_NOWHERE;
+diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
+index 01801c0..d17990e 100644
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1124,17 +1124,14 @@ err:
+ return fa_head;
+ }
+
+-static int
+-fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
+- struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
++static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+ {
+ struct trie *t = (struct trie *) tb->tb_data;
+ struct fib_alias *fa, *new_fa;
+ struct list_head *fa_head = NULL;
+ struct fib_info *fi;
+- int plen = r->rtm_dst_len;
+- int type = r->rtm_type;
+- u8 tos = r->rtm_tos;
++ int plen = cfg->fc_dst_len;
++ u8 tos = cfg->fc_tos;
+ u32 key, mask;
+ int err;
+ struct leaf *l;
+@@ -1142,13 +1139,9 @@ fn_trie_insert(struct fib_table *tb, str
+ if (plen > 32)
+ return -EINVAL;
+
+- key = 0;
+- if (rta->rta_dst)
+- memcpy(&key, rta->rta_dst, 4);
+-
+- key = ntohl(key);
++ key = ntohl(cfg->fc_dst);
+
+- pr_debug("Insert table=%d %08x/%d\n", tb->tb_id, key, plen);
++ pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
+
+ mask = ntohl(inet_make_mask(plen));
+
+@@ -1157,10 +1150,11 @@ fn_trie_insert(struct fib_table *tb, str
+
+ key = key & mask;
+
+- fi = fib_create_info(r, rta, nlhdr, &err);
+-
+- if (!fi)
++ fi = fib_create_info(cfg);
++ if (IS_ERR(fi)) {
++ err = PTR_ERR(fi);
+ goto err;
++ }
+
+ l = fib_find_node(t, key);
+ fa = NULL;
+@@ -1185,10 +1179,10 @@ fn_trie_insert(struct fib_table *tb, str
+ struct fib_alias *fa_orig;
+
+ err = -EEXIST;
+- if (nlhdr->nlmsg_flags & NLM_F_EXCL)
++ if (cfg->fc_nlflags & NLM_F_EXCL)
+ goto out;
+
+- if (nlhdr->nlmsg_flags & NLM_F_REPLACE) {
++ if (cfg->fc_nlflags & NLM_F_REPLACE) {
+ struct fib_info *fi_drop;
+ u8 state;
+
+@@ -1200,8 +1194,8 @@ fn_trie_insert(struct fib_table *tb, str
+ fi_drop = fa->fa_info;
+ new_fa->fa_tos = fa->fa_tos;
+ new_fa->fa_info = fi;
+- new_fa->fa_type = type;
+- new_fa->fa_scope = r->rtm_scope;
++ new_fa->fa_type = cfg->fc_type;
++ new_fa->fa_scope = cfg->fc_scope;
+ state = fa->fa_state;
+ new_fa->fa_state &= ~FA_S_ACCESSED;
+
+@@ -1224,17 +1218,17 @@ fn_trie_insert(struct fib_table *tb, str
+ break;
+ if (fa->fa_info->fib_priority != fi->fib_priority)
+ break;
+- if (fa->fa_type == type &&
+- fa->fa_scope == r->rtm_scope &&
++ if (fa->fa_type == cfg->fc_type &&
++ fa->fa_scope == cfg->fc_scope &&
+ fa->fa_info == fi) {
+ goto out;
+ }
+ }
+- if (!(nlhdr->nlmsg_flags & NLM_F_APPEND))
++ if (!(cfg->fc_nlflags & NLM_F_APPEND))
+ fa = fa_orig;
+ }
+ err = -ENOENT;
+- if (!(nlhdr->nlmsg_flags & NLM_F_CREATE))
++ if (!(cfg->fc_nlflags & NLM_F_CREATE))
+ goto out;
+
+ err = -ENOBUFS;
+@@ -1244,8 +1238,8 @@ fn_trie_insert(struct fib_table *tb, str
+
+ new_fa->fa_info = fi;
+ new_fa->fa_tos = tos;
+- new_fa->fa_type = type;
+- new_fa->fa_scope = r->rtm_scope;
++ new_fa->fa_type = cfg->fc_type;
++ new_fa->fa_scope = cfg->fc_scope;
+ new_fa->fa_state = 0;
+ /*
+ * Insert new entry to the list.
+@@ -1262,7 +1256,8 @@ fn_trie_insert(struct fib_table *tb, str
+ (fa ? &fa->fa_list : fa_head));
+
+ rt_cache_flush(-1);
+- rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
++ rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
++ &cfg->fc_nlinfo);
+ succeeded:
+ return 0;
+
+@@ -1548,28 +1543,21 @@ static int trie_leaf_remove(struct trie
+ return 1;
+ }
+
+-static int
+-fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
+- struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
++static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
+ {
+ struct trie *t = (struct trie *) tb->tb_data;
+ u32 key, mask;
+- int plen = r->rtm_dst_len;
+- u8 tos = r->rtm_tos;
++ int plen = cfg->fc_dst_len;
++ u8 tos = cfg->fc_tos;
+ struct fib_alias *fa, *fa_to_delete;
+ struct list_head *fa_head;
+ struct leaf *l;
+ struct leaf_info *li;
+
+-
+ if (plen > 32)
+ return -EINVAL;
+
+- key = 0;
+- if (rta->rta_dst)
+- memcpy(&key, rta->rta_dst, 4);
+-
+- key = ntohl(key);
++ key = ntohl(cfg->fc_dst);
+ mask = ntohl(inet_make_mask(plen));
+
+ if (key & ~mask)
+@@ -1598,13 +1586,12 @@ fn_trie_delete(struct fib_table *tb, str
+ if (fa->fa_tos != tos)
+ break;
+
+- if ((!r->rtm_type ||
+- fa->fa_type == r->rtm_type) &&
+- (r->rtm_scope == RT_SCOPE_NOWHERE ||
+- fa->fa_scope == r->rtm_scope) &&
+- (!r->rtm_protocol ||
+- fi->fib_protocol == r->rtm_protocol) &&
+- fib_nh_match(r, nlhdr, rta, fi) == 0) {
++ if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
++ (cfg->fc_scope == RT_SCOPE_NOWHERE ||
++ fa->fa_scope == cfg->fc_scope) &&
++ (!cfg->fc_protocol ||
++ fi->fib_protocol == cfg->fc_protocol) &&
++ fib_nh_match(cfg, fi) == 0) {
+ fa_to_delete = fa;
+ break;
+ }
+@@ -1614,7 +1601,8 @@ fn_trie_delete(struct fib_table *tb, str
+ return -ESRCH;
+
+ fa = fa_to_delete;
+- rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);
++ rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id,
++ &cfg->fc_nlinfo);
+
+ l = fib_find_node(t, key);
+ li = find_leaf_info(l, plen);
+@@ -1846,9 +1834,9 @@ static int fn_trie_dump_fa(t_key key, in
+ int i, s_i;
+ struct fib_alias *fa;
+
+- u32 xkey = htonl(key);
++ __be32 xkey = htonl(key);
+
+- s_i = cb->args[3];
++ s_i = cb->args[4];
+ i = 0;
+
+ /* rcu_read_lock is hold by caller */
+@@ -1866,16 +1854,16 @@ static int fn_trie_dump_fa(t_key key, in
+ tb->tb_id,
+ fa->fa_type,
+ fa->fa_scope,
+- &xkey,
++ xkey,
+ plen,
+ fa->fa_tos,
+ fa->fa_info, 0) < 0) {
+- cb->args[3] = i;
++ cb->args[4] = i;
+ return -1;
+ }
+ i++;
+ }
+- cb->args[3] = i;
++ cb->args[4] = i;
+ return skb->len;
+ }
+
+@@ -1886,14 +1874,14 @@ static int fn_trie_dump_plen(struct trie
+ struct list_head *fa_head;
+ struct leaf *l = NULL;
+
+- s_h = cb->args[2];
++ s_h = cb->args[3];
+
+ for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
+ if (h < s_h)
+ continue;
+ if (h > s_h)
+- memset(&cb->args[3], 0,
+- sizeof(cb->args) - 3*sizeof(cb->args[0]));
++ memset(&cb->args[4], 0,
++ sizeof(cb->args) - 4*sizeof(cb->args[0]));
+
+ fa_head = get_fa_head(l, plen);
+
+@@ -1904,11 +1892,11 @@ static int fn_trie_dump_plen(struct trie
+ continue;
+
+ if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
+- cb->args[2] = h;
++ cb->args[3] = h;
+ return -1;
+ }
+ }
+- cb->args[2] = h;
++ cb->args[3] = h;
+ return skb->len;
+ }
+
+@@ -1917,23 +1905,23 @@ static int fn_trie_dump(struct fib_table
+ int m, s_m;
+ struct trie *t = (struct trie *) tb->tb_data;
+
+- s_m = cb->args[1];
++ s_m = cb->args[2];
+
+ rcu_read_lock();
+ for (m = 0; m <= 32; m++) {
+ if (m < s_m)
+ continue;
+ if (m > s_m)
+- memset(&cb->args[2], 0,
+- sizeof(cb->args) - 2*sizeof(cb->args[0]));
++ memset(&cb->args[3], 0,
++ sizeof(cb->args) - 3*sizeof(cb->args[0]));
+
+ if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
+- cb->args[1] = m;
++ cb->args[2] = m;
+ goto out;
+ }
+ }
+ rcu_read_unlock();
+- cb->args[1] = m;
++ cb->args[2] = m;
+ return skb->len;
+ out:
+ rcu_read_unlock();
+@@ -1943,9 +1931,9 @@ out:
+ /* Fix more generic FIB names for init later */
+
+ #ifdef CONFIG_IP_MULTIPLE_TABLES
+-struct fib_table * fib_hash_init(int id)
++struct fib_table * fib_hash_init(u32 id)
+ #else
+-struct fib_table * __init fib_hash_init(int id)
++struct fib_table * __init fib_hash_init(u32 id)
+ #endif
+ {
+ struct fib_table *tb;
+@@ -2293,7 +2281,7 @@ static int fib_trie_seq_show(struct seq_
+
+ if (IS_TNODE(n)) {
+ struct tnode *tn = (struct tnode *) n;
+- t_key prf = ntohl(MASK_PFX(tn->key, tn->pos));
++ __be32 prf = htonl(MASK_PFX(tn->key, tn->pos));
+
+ if (!NODE_PARENT(n)) {
+ if (iter->trie == trie_local)
+@@ -2309,7 +2297,7 @@ static int fib_trie_seq_show(struct seq_
+ } else {
+ struct leaf *l = (struct leaf *) n;
+ int i;
+- u32 val = ntohl(l->key);
++ __be32 val = htonl(l->key);
+
+ seq_indent(seq, iter->depth);
+ seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));
+@@ -2372,7 +2360,7 @@ static struct file_operations fib_trie_f
+ .release = seq_release_private,
+ };
+
+-static unsigned fib_flag_trans(int type, u32 mask, const struct fib_info *fi)
++static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
+ {
+ static unsigned type2flags[RTN_MAX + 1] = {
+ [7] = RTF_REJECT, [8] = RTF_REJECT,
+@@ -2381,7 +2369,7 @@ static unsigned fib_flag_trans(int type,
+
+ if (fi && fi->fib_nh->nh_gw)
+ flags |= RTF_GATEWAY;
+- if (mask == 0xFFFFFFFF)
++ if (mask == htonl(0xFFFFFFFF))
+ flags |= RTF_HOST;
+ flags |= RTF_UP;
+ return flags;
+@@ -2415,7 +2403,7 @@ static int fib_route_seq_show(struct seq
+ for (i=32; i>=0; i--) {
+ struct leaf_info *li = find_leaf_info(l, i);
+ struct fib_alias *fa;
+- u32 mask, prefix;
++ __be32 mask, prefix;
+
+ if (!li)
+ continue;
+diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
+index 4c86ac3..b39a37a 100644
+--- a/net/ipv4/icmp.c
++++ b/net/ipv4/icmp.c
+@@ -104,7 +104,7 @@ struct icmp_bxm {
+
+ struct {
+ struct icmphdr icmph;
+- __u32 times[3];
++ __be32 times[3];
+ } data;
+ int head_len;
+ struct ip_options replyopts;
+@@ -187,11 +187,11 @@ struct icmp_err icmp_err_convert[] = {
+ };
+
+ /* Control parameters for ECHO replies. */
+-int sysctl_icmp_echo_ignore_all;
+-int sysctl_icmp_echo_ignore_broadcasts = 1;
++int sysctl_icmp_echo_ignore_all __read_mostly;
++int sysctl_icmp_echo_ignore_broadcasts __read_mostly = 1;
+
+ /* Control parameter - ignore bogus broadcast responses? */
+-int sysctl_icmp_ignore_bogus_error_responses = 1;
++int sysctl_icmp_ignore_bogus_error_responses __read_mostly = 1;
+
+ /*
+ * Configurable global rate limit.
+@@ -205,9 +205,9 @@ int sysctl_icmp_ignore_bogus_error_respo
+ * time exceeded (11), parameter problem (12)
+ */
+
+-int sysctl_icmp_ratelimit = 1 * HZ;
+-int sysctl_icmp_ratemask = 0x1818;
+-int sysctl_icmp_errors_use_inbound_ifaddr;
++int sysctl_icmp_ratelimit __read_mostly = 1 * HZ;
++int sysctl_icmp_ratemask __read_mostly = 0x1818;
++int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly;
+
+ /*
+ * ICMP control array. This specifies what to do with each ICMP.
+@@ -381,7 +381,7 @@ static void icmp_reply(struct icmp_bxm *
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipcm_cookie ipc;
+ struct rtable *rt = (struct rtable *)skb->dst;
+- u32 daddr;
++ __be32 daddr;
+
+ if (ip_options_echo(&icmp_param->replyopts, skb))
+ return;
+@@ -406,6 +406,7 @@ static void icmp_reply(struct icmp_bxm *
+ .saddr = rt->rt_spec_dst,
+ .tos = RT_TOS(skb->nh.iph->tos) } },
+ .proto = IPPROTO_ICMP };
++ security_skb_classify_flow(skb, &fl);
+ if (ip_route_output_key(&rt, &fl))
+ goto out_unlock;
+ }
+@@ -429,14 +430,14 @@ out_unlock:
+ * MUST reply to only the first fragment.
+ */
+
+-void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
++void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
+ {
+ struct iphdr *iph;
+ int room;
+ struct icmp_bxm icmp_param;
+ struct rtable *rt = (struct rtable *)skb_in->dst;
+ struct ipcm_cookie ipc;
+- u32 saddr;
++ __be32 saddr;
+ u8 tos;
+
+ if (!rt)
+@@ -560,6 +561,7 @@ void icmp_send(struct sk_buff *skb_in, i
+ }
+ }
+ };
++ security_skb_classify_flow(skb_in, &fl);
+ if (ip_route_output_key(&rt, &fl))
+ goto out_unlock;
+ }
+@@ -893,7 +895,7 @@ static void icmp_address_reply(struct sk
+ if (in_dev->ifa_list &&
+ IN_DEV_LOG_MARTIANS(in_dev) &&
+ IN_DEV_FORWARD(in_dev)) {
+- u32 _mask, *mp;
++ __be32 _mask, *mp;
+
+ mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
+ BUG_ON(mp == NULL);
+@@ -928,7 +930,7 @@ int icmp_rcv(struct sk_buff *skb)
+ ICMP_INC_STATS_BH(ICMP_MIB_INMSGS);
+
+ switch (skb->ip_summed) {
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (!(u16)csum_fold(skb->csum))
+ break;
+ /* fall through */
+diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
+index 8e8117c..6eee716 100644
+--- a/net/ipv4/igmp.c
++++ b/net/ipv4/igmp.c
+@@ -138,14 +138,14 @@
+ time_before(jiffies, (in_dev)->mr_v2_seen)))
+
+ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
+-static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr);
++static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
+ static void igmpv3_clear_delrec(struct in_device *in_dev);
+ static int sf_setstate(struct ip_mc_list *pmc);
+ static void sf_markstate(struct ip_mc_list *pmc);
+ #endif
+ static void ip_mc_clear_src(struct ip_mc_list *pmc);
+-static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
+- int sfcount, __u32 *psfsrc, int delta);
++static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
++ int sfcount, __be32 *psfsrc, int delta);
+
+ static void ip_ma_put(struct ip_mc_list *im)
+ {
+@@ -426,7 +426,7 @@ static struct sk_buff *add_grec(struct s
+ first = 1;
+ psf_prev = NULL;
+ for (psf=*psf_list; psf; psf=psf_next) {
+- u32 *psrc;
++ __be32 *psrc;
+
+ psf_next = psf->sf_next;
+
+@@ -439,7 +439,7 @@ static struct sk_buff *add_grec(struct s
+ if (isquery)
+ psf->sf_gsresp = 0;
+
+- if (AVAILABLE(skb) < sizeof(u32) +
++ if (AVAILABLE(skb) < sizeof(__be32) +
+ first*sizeof(struct igmpv3_grec)) {
+ if (truncate && !first)
+ break; /* truncate these */
+@@ -455,7 +455,7 @@ static struct sk_buff *add_grec(struct s
+ skb = add_grhead(skb, pmc, type, &pgr);
+ first = 0;
+ }
+- psrc = (u32 *)skb_put(skb, sizeof(u32));
++ psrc = (__be32 *)skb_put(skb, sizeof(__be32));
+ *psrc = psf->sf_inaddr;
+ scount++; stotal++;
+ if ((type == IGMPV3_ALLOW_NEW_SOURCES ||
+@@ -630,8 +630,8 @@ static int igmp_send_report(struct in_de
+ struct igmphdr *ih;
+ struct rtable *rt;
+ struct net_device *dev = in_dev->dev;
+- u32 group = pmc ? pmc->multiaddr : 0;
+- u32 dst;
++ __be32 group = pmc ? pmc->multiaddr : 0;
++ __be32 dst;
+
+ if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
+ return igmpv3_send_report(in_dev, pmc);
+@@ -748,7 +748,7 @@ static void igmp_timer_expire(unsigned l
+ }
+
+ /* mark EXCLUDE-mode sources */
+-static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
++static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
+ {
+ struct ip_sf_list *psf;
+ int i, scount;
+@@ -775,7 +775,7 @@ static int igmp_xmarksources(struct ip_m
+ return 1;
+ }
+
+-static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
++static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
+ {
+ struct ip_sf_list *psf;
+ int i, scount;
+@@ -803,7 +803,7 @@ static int igmp_marksources(struct ip_mc
+ return 1;
+ }
+
+-static void igmp_heard_report(struct in_device *in_dev, u32 group)
++static void igmp_heard_report(struct in_device *in_dev, __be32 group)
+ {
+ struct ip_mc_list *im;
+
+@@ -828,7 +828,7 @@ static void igmp_heard_query(struct in_d
+ struct igmphdr *ih = skb->h.igmph;
+ struct igmpv3_query *ih3 = (struct igmpv3_query *)ih;
+ struct ip_mc_list *im;
+- u32 group = ih->group;
++ __be32 group = ih->group;
+ int max_delay;
+ int mark = 0;
+
+@@ -862,7 +862,7 @@ static void igmp_heard_query(struct in_d
+ ih3 = (struct igmpv3_query *) skb->h.raw;
+ if (ih3->nsrcs) {
+ if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
+- + ntohs(ih3->nsrcs)*sizeof(__u32)))
++ + ntohs(ih3->nsrcs)*sizeof(__be32)))
+ return;
+ ih3 = (struct igmpv3_query *) skb->h.raw;
+ }
+@@ -931,7 +931,7 @@ int igmp_rcv(struct sk_buff *skb)
+ goto drop;
+
+ switch (skb->ip_summed) {
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (!(u16)csum_fold(skb->csum))
+ break;
+ /* fall through */
+@@ -985,7 +985,7 @@ drop:
+ * Add a filter to a device
+ */
+
+-static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
++static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr)
+ {
+ char buf[MAX_ADDR_LEN];
+ struct net_device *dev = in_dev->dev;
+@@ -1005,7 +1005,7 @@ static void ip_mc_filter_add(struct in_d
+ * Remove a filter from a device
+ */
+
+-static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
++static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr)
+ {
+ char buf[MAX_ADDR_LEN];
+ struct net_device *dev = in_dev->dev;
+@@ -1055,7 +1055,7 @@ static void igmpv3_add_delrec(struct in_
+ spin_unlock_bh(&in_dev->mc_tomb_lock);
+ }
+
+-static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
++static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
+ {
+ struct ip_mc_list *pmc, *pmc_prev;
+ struct ip_sf_list *psf, *psf_next;
+@@ -1193,7 +1193,7 @@ static void igmp_group_added(struct ip_m
+ * A socket has joined a multicast group on device dev.
+ */
+
+-void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
++void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
+ {
+ struct ip_mc_list *im;
+
+@@ -1252,7 +1252,7 @@ out:
+ * A socket has left a multicast group on device dev
+ */
+
+-void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
++void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
+ {
+ struct ip_mc_list *i, **ip;
+
+@@ -1397,12 +1397,12 @@ static struct in_device * ip_mc_find_dev
+ /*
+ * Join a socket to a group
+ */
+-int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
+-int sysctl_igmp_max_msf = IP_MAX_MSF;
++int sysctl_igmp_max_memberships __read_mostly = IP_MAX_MEMBERSHIPS;
++int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF;
+
+
+ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
+- __u32 *psfsrc)
++ __be32 *psfsrc)
+ {
+ struct ip_sf_list *psf, *psf_prev;
+ int rv = 0;
+@@ -1450,8 +1450,8 @@ static int ip_mc_del1_src(struct ip_mc_l
+ #define igmp_ifc_event(x) do { } while (0)
+ #endif
+
+-static int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
+- int sfcount, __u32 *psfsrc, int delta)
++static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
++ int sfcount, __be32 *psfsrc, int delta)
+ {
+ struct ip_mc_list *pmc;
+ int changerec = 0;
+@@ -1517,7 +1517,7 @@ out_unlock:
+ * Add multicast single-source filter to the interface list
+ */
+ static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode,
+- __u32 *psfsrc, int delta)
++ __be32 *psfsrc, int delta)
+ {
+ struct ip_sf_list *psf, *psf_prev;
+
+@@ -1623,8 +1623,8 @@ static int sf_setstate(struct ip_mc_list
+ /*
+ * Add multicast source filter list to the interface list
+ */
+-static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
+- int sfcount, __u32 *psfsrc, int delta)
++static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
++ int sfcount, __be32 *psfsrc, int delta)
+ {
+ struct ip_mc_list *pmc;
+ int isexclude;
+@@ -1717,7 +1717,7 @@ static void ip_mc_clear_src(struct ip_mc
+ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
+ {
+ int err;
+- u32 addr = imr->imr_multiaddr.s_addr;
++ __be32 addr = imr->imr_multiaddr.s_addr;
+ struct ip_mc_socklist *iml=NULL, *i;
+ struct in_device *in_dev;
+ struct inet_sock *inet = inet_sk(sk);
+@@ -1791,7 +1791,7 @@ int ip_mc_leave_group(struct sock *sk, s
+ 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;
++ __be32 group = imr->imr_multiaddr.s_addr;
+ u32 ifindex;
+ int ret = -EADDRNOTAVAIL;
+
+@@ -1829,7 +1829,7 @@ int ip_mc_source(int add, int omode, str
+ {
+ int err;
+ struct ip_mreqn imr;
+- u32 addr = mreqs->imr_multiaddr;
++ __be32 addr = mreqs->imr_multiaddr;
+ struct ip_mc_socklist *pmc;
+ struct in_device *in_dev = NULL;
+ struct inet_sock *inet = inet_sk(sk);
+@@ -1883,7 +1883,7 @@ int ip_mc_source(int add, int omode, str
+ rv = !0;
+ for (i=0; i<psl->sl_count; i++) {
+ rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
+- sizeof(__u32));
++ sizeof(__be32));
+ if (rv == 0)
+ break;
+ }
+@@ -1935,7 +1935,7 @@ int ip_mc_source(int add, int omode, str
+ rv = 1; /* > 0 for insert logic below if sl_count is 0 */
+ for (i=0; i<psl->sl_count; i++) {
+ rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
+- sizeof(__u32));
++ sizeof(__be32));
+ if (rv == 0)
+ break;
+ }
+@@ -1960,7 +1960,7 @@ int ip_mc_msfilter(struct sock *sk, stru
+ {
+ int err = 0;
+ struct ip_mreqn imr;
+- u32 addr = msf->imsf_multiaddr;
++ __be32 addr = msf->imsf_multiaddr;
+ struct ip_mc_socklist *pmc;
+ struct in_device *in_dev;
+ struct inet_sock *inet = inet_sk(sk);
+@@ -2044,7 +2044,7 @@ int ip_mc_msfget(struct sock *sk, struct
+ {
+ int err, len, count, copycount;
+ struct ip_mreqn imr;
+- u32 addr = msf->imsf_multiaddr;
++ __be32 addr = msf->imsf_multiaddr;
+ struct ip_mc_socklist *pmc;
+ struct in_device *in_dev;
+ struct inet_sock *inet = inet_sk(sk);
+@@ -2103,7 +2103,7 @@ int ip_mc_gsfget(struct sock *sk, struct
+ {
+ int err, i, count, copycount;
+ struct sockaddr_in *psin;
+- u32 addr;
++ __be32 addr;
+ struct ip_mc_socklist *pmc;
+ struct inet_sock *inet = inet_sk(sk);
+ struct ip_sf_socklist *psl;
+@@ -2156,7 +2156,7 @@ done:
+ /*
+ * check if a multicast source filter allows delivery for a given <src,dst,intf>
+ */
+-int ip_mc_sf_allow(struct sock *sk, u32 loc_addr, u32 rmt_addr, int dif)
++int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
+ {
+ struct inet_sock *inet = inet_sk(sk);
+ struct ip_mc_socklist *pmc;
+@@ -2216,7 +2216,7 @@ void ip_mc_drop_socket(struct sock *sk)
+ rtnl_unlock();
+ }
+
+-int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
++int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto)
+ {
+ struct ip_mc_list *im;
+ struct ip_sf_list *psf;
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index e50a1bf..96bbe2a 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -39,7 +39,7 @@ int sysctl_local_port_range[2] = { 1024,
+ int inet_csk_bind_conflict(const struct sock *sk,
+ const struct inet_bind_bucket *tb)
+ {
+- const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
++ const __be32 sk_rcv_saddr = inet_rcv_saddr(sk);
+ struct sock *sk2;
+ struct hlist_node *node;
+ int reuse = sk->sk_reuse;
+@@ -52,7 +52,7 @@ int inet_csk_bind_conflict(const struct
+ sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
+ if (!reuse || !sk2->sk_reuse ||
+ sk2->sk_state == TCP_LISTEN) {
+- const u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
++ const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+ if (!sk2_rcv_saddr || !sk_rcv_saddr ||
+ sk2_rcv_saddr == sk_rcv_saddr)
+ break;
+@@ -327,6 +327,7 @@ struct dst_entry* inet_csk_route_req(str
+ { .sport = inet_sk(sk)->sport,
+ .dport = ireq->rmt_port } } };
+
++ security_req_classify_flow(req, &fl);
+ if (ip_route_output_flow(&rt, &fl, sk, 0)) {
+ IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+ return NULL;
+@@ -341,10 +342,10 @@ struct dst_entry* inet_csk_route_req(str
+
+ EXPORT_SYMBOL_GPL(inet_csk_route_req);
+
+-static inline u32 inet_synq_hash(const u32 raddr, const u16 rport,
++static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
+ const u32 rnd, const u16 synq_hsize)
+ {
+- return jhash_2words(raddr, (u32)rport, rnd) & (synq_hsize - 1);
++ return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1);
+ }
+
+ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+@@ -355,8 +356,8 @@ static inline u32 inet_synq_hash(const u
+
+ struct request_sock *inet_csk_search_req(const struct sock *sk,
+ struct request_sock ***prevp,
+- const __u16 rport, const __u32 raddr,
+- const __u32 laddr)
++ const __be16 rport, const __be32 raddr,
++ const __be32 laddr)
+ {
+ const struct inet_connection_sock *icsk = inet_csk(sk);
+ struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
+@@ -509,6 +510,8 @@ struct sock *inet_csk_clone(struct sock
+
+ /* Deinitialize accept_queue to trap illegal accesses. */
+ memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue));
++
++ security_inet_csk_clone(newsk, req);
+ }
+ return newsk;
+ }
+diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
+index 492858e..77761ac 100644
+--- a/net/ipv4/inet_diag.c
++++ b/net/ipv4/inet_diag.c
+@@ -36,8 +36,8 @@
+ static const struct inet_diag_handler **inet_diag_table;
+
+ struct inet_diag_entry {
+- u32 *saddr;
+- u32 *daddr;
++ __be32 *saddr;
++ __be32 *daddr;
+ u16 sport;
+ u16 dport;
+ u16 family;
+@@ -294,7 +294,7 @@ out:
+ return err;
+ }
+
+-static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
++static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits)
+ {
+ int words = bits >> 5;
+
+@@ -305,8 +305,8 @@ static int bitstring_match(const u32 *a1
+ return 0;
+ }
+ if (bits) {
+- __u32 w1, w2;
+- __u32 mask;
++ __be32 w1, w2;
++ __be32 mask;
+
+ w1 = a1[words];
+ w2 = a2[words];
+@@ -352,7 +352,7 @@ static int inet_diag_bc_run(const void *
+ case INET_DIAG_BC_S_COND:
+ case INET_DIAG_BC_D_COND: {
+ struct inet_diag_hostcond *cond;
+- u32 *addr;
++ __be32 *addr;
+
+ cond = (struct inet_diag_hostcond *)(op + 1);
+ if (cond->port != -1 &&
+diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
+index 95fac55..244c4f4 100644
+--- a/net/ipv4/inet_hashtables.c
++++ b/net/ipv4/inet_hashtables.c
+@@ -124,8 +124,10 @@ EXPORT_SYMBOL(inet_listen_wlock);
+ * remote address for the connection. So always assume those are both
+ * wildcarded during the search since they can never be otherwise.
+ */
+-struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 daddr,
+- const unsigned short hnum, const int dif)
++static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
++ const __be32 daddr,
++ const unsigned short hnum,
++ const int dif)
+ {
+ struct sock *result = NULL, *sk;
+ const struct hlist_node *node;
+@@ -135,7 +137,7 @@ struct sock *__inet_lookup_listener(cons
+ const struct inet_sock *inet = inet_sk(sk);
+
+ if (inet->num == hnum && !ipv6_only_sock(sk)) {
+- const __u32 rcv_saddr = inet->rcv_saddr;
++ const __be32 rcv_saddr = inet->rcv_saddr;
+ int score = sk->sk_family == PF_INET ? 1 : 0;
+
+ if (rcv_saddr) {
+@@ -159,6 +161,33 @@ struct sock *__inet_lookup_listener(cons
+ return result;
+ }
+
++/* Optimize the common listener case. */
++struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
++ const __be32 daddr, const unsigned short hnum,
++ const int dif)
++{
++ struct sock *sk = NULL;
++ const struct hlist_head *head;
++
++ read_lock(&hashinfo->lhash_lock);
++ head = &hashinfo->listening_hash[inet_lhashfn(hnum)];
++ if (!hlist_empty(head)) {
++ const struct inet_sock *inet = inet_sk((sk = __sk_head(head)));
++
++ if (inet->num == hnum && !sk->sk_node.next &&
++ (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
++ (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
++ !sk->sk_bound_dev_if)
++ goto sherry_cache;
++ sk = inet_lookup_listener_slow(head, daddr, hnum, dif);
++ }
++ if (sk) {
++sherry_cache:
++ sock_hold(sk);
++ }
++ read_unlock(&hashinfo->lhash_lock);
++ return sk;
++}
+ EXPORT_SYMBOL_GPL(__inet_lookup_listener);
+
+ /* called with local bh disabled */
+@@ -168,11 +197,11 @@ static int __inet_check_established(stru
+ {
+ struct inet_hashinfo *hinfo = death_row->hashinfo;
+ struct inet_sock *inet = inet_sk(sk);
+- u32 daddr = inet->rcv_saddr;
+- u32 saddr = inet->daddr;
++ __be32 daddr = inet->rcv_saddr;
++ __be32 saddr = inet->daddr;
+ int dif = sk->sk_bound_dev_if;
+ INET_ADDR_COOKIE(acookie, saddr, daddr)
+- const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
++ const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
+ unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
+ struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
+ struct sock *sk2;
+diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
+index 03ff62e..f072f38 100644
+--- a/net/ipv4/inetpeer.c
++++ b/net/ipv4/inetpeer.c
+@@ -94,10 +94,8 @@ int inet_peer_minttl = 120 * HZ; /* TTL
+ int inet_peer_maxttl = 10 * 60 * HZ; /* usual time to live: 10 min */
+
+ static struct inet_peer *inet_peer_unused_head;
+-/* Exported for inet_putpeer inline function. */
+-struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
+-DEFINE_SPINLOCK(inet_peer_unused_lock);
+-#define PEER_MAX_CLEANUP_WORK 30
++static struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
++static DEFINE_SPINLOCK(inet_peer_unused_lock);
+
+ static void peer_check_expire(unsigned long dummy);
+ static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
+@@ -126,12 +124,9 @@ void __init inet_initpeers(void)
+
+ peer_cachep = kmem_cache_create("inet_peer_cache",
+ sizeof(struct inet_peer),
+- 0, SLAB_HWCACHE_ALIGN,
++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+
+- if (!peer_cachep)
+- panic("cannot create inet_peer_cache");
+-
+ /* All the timers, started at system startup tend
+ to synchronize. Perturb it a bit.
+ */
+@@ -166,7 +161,7 @@ static void unlink_from_unused(struct in
+ for (u = peer_root; u != peer_avl_empty; ) { \
+ if (daddr == u->v4daddr) \
+ break; \
+- if (daddr < u->v4daddr) \
++ if ((__force __u32)daddr < (__force __u32)u->v4daddr) \
+ v = &u->avl_left; \
+ else \
+ v = &u->avl_right; \
+@@ -343,7 +338,8 @@ static int cleanup_once(unsigned long tt
+ spin_lock_bh(&inet_peer_unused_lock);
+ p = inet_peer_unused_head;
+ if (p != NULL) {
+- if (time_after(p->dtime + ttl, jiffies)) {
++ __u32 delta = (__u32)jiffies - p->dtime;
++ if (delta < ttl) {
+ /* Do not prune fresh entries. */
+ spin_unlock_bh(&inet_peer_unused_lock);
+ return -1;
+@@ -371,7 +367,7 @@ static int cleanup_once(unsigned long tt
+ }
+
+ /* Called with or without local BH being disabled. */
+-struct inet_peer *inet_getpeer(__u32 daddr, int create)
++struct inet_peer *inet_getpeer(__be32 daddr, int create)
+ {
+ struct inet_peer *p, *n;
+ struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
+@@ -435,7 +431,7 @@ out_free:
+ /* Called with local BH disabled. */
+ static void peer_check_expire(unsigned long dummy)
+ {
+- int i;
++ unsigned long now = jiffies;
+ int ttl;
+
+ if (peer_total >= inet_peer_threshold)
+@@ -444,7 +440,10 @@ static void peer_check_expire(unsigned l
+ ttl = inet_peer_maxttl
+ - (inet_peer_maxttl - inet_peer_minttl) / HZ *
+ peer_total / inet_peer_threshold * HZ;
+- for (i = 0; i < PEER_MAX_CLEANUP_WORK && !cleanup_once(ttl); i++);
++ while (!cleanup_once(ttl)) {
++ if (jiffies != now)
++ break;
++ }
+
+ /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
+ * interval depending on the total number of entries (more entries,
+@@ -458,3 +457,16 @@ static void peer_check_expire(unsigned l
+ peer_total / inet_peer_threshold * HZ;
+ add_timer(&peer_periodic_timer);
+ }
++
++void inet_putpeer(struct inet_peer *p)
++{
++ spin_lock_bh(&inet_peer_unused_lock);
++ if (atomic_dec_and_test(&p->refcnt)) {
++ p->unused_prevp = inet_peer_unused_tailp;
++ p->unused_next = NULL;
++ *inet_peer_unused_tailp = p;
++ inet_peer_unused_tailp = &p->unused_next;
++ p->dtime = (__u32)jiffies;
++ }
++ spin_unlock_bh(&inet_peer_unused_lock);
++}
+diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
+index b84b53a..74046ef 100644
+--- a/net/ipv4/ip_fragment.c
++++ b/net/ipv4/ip_fragment.c
+@@ -54,15 +54,15 @@
+ * even the most extreme cases without allowing an attacker to measurably
+ * harm machine performance.
+ */
+-int sysctl_ipfrag_high_thresh = 256*1024;
+-int sysctl_ipfrag_low_thresh = 192*1024;
++int sysctl_ipfrag_high_thresh __read_mostly = 256*1024;
++int sysctl_ipfrag_low_thresh __read_mostly = 192*1024;
+
+-int sysctl_ipfrag_max_dist = 64;
++int sysctl_ipfrag_max_dist __read_mostly = 64;
+
+ /* Important NOTE! Fragment queue must be destroyed before MSL expires.
+ * RFC791 is wrong proposing to prolongate timer each fragment arrival by TTL.
+ */
+-int sysctl_ipfrag_time = IP_FRAG_TIME;
++int sysctl_ipfrag_time __read_mostly = IP_FRAG_TIME;
+
+ struct ipfrag_skb_cb
+ {
+@@ -77,9 +77,9 @@ struct ipq {
+ struct hlist_node list;
+ struct list_head lru_list; /* lru list member */
+ u32 user;
+- u32 saddr;
+- u32 daddr;
+- u16 id;
++ __be32 saddr;
++ __be32 daddr;
++ __be16 id;
+ u8 protocol;
+ u8 last_in;
+ #define COMPLETE 4
+@@ -123,14 +123,15 @@ static __inline__ void ipq_unlink(struct
+ write_unlock(&ipfrag_lock);
+ }
+
+-static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot)
++static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
+ {
+- return jhash_3words((u32)id << 16 | prot, saddr, daddr,
++ return jhash_3words((__force u32)id << 16 | prot,
++ (__force u32)saddr, (__force u32)daddr,
+ ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
+ }
+
+ static struct timer_list ipfrag_secret_timer;
+-int sysctl_ipfrag_secret_interval = 10 * 60 * HZ;
++int sysctl_ipfrag_secret_interval __read_mostly = 10 * 60 * HZ;
+
+ static void ipfrag_secret_rebuild(unsigned long dummy)
+ {
+@@ -387,8 +388,8 @@ out_nomem:
+ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
+ {
+ __be16 id = iph->id;
+- __u32 saddr = iph->saddr;
+- __u32 daddr = iph->daddr;
++ __be32 saddr = iph->saddr;
++ __be32 daddr = iph->daddr;
+ __u8 protocol = iph->protocol;
+ unsigned int hash;
+ struct ipq *qp;
+@@ -665,7 +666,7 @@ static struct sk_buff *ip_frag_reasm(str
+ head->len += fp->len;
+ if (head->ip_summed != fp->ip_summed)
+ head->ip_summed = CHECKSUM_NONE;
+- else if (head->ip_summed == CHECKSUM_HW)
++ else if (head->ip_summed == CHECKSUM_COMPLETE)
+ head->csum = csum_add(head->csum, fp->csum);
+ head->truesize += fp->truesize;
+ atomic_sub(fp->truesize, &ip_frag_mem);
+diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
+index 0f9b3a3..d5b5dec 100644
+--- a/net/ipv4/ip_gre.c
++++ b/net/ipv4/ip_gre.c
+@@ -393,7 +393,8 @@ out:
+ int code = skb->h.icmph->code;
+ int rel_type = 0;
+ int rel_code = 0;
+- int rel_info = 0;
++ __be32 rel_info = 0;
++ __u32 n = 0;
+ u16 flags;
+ int grehlen = (iph->ihl<<2) + 4;
+ struct sk_buff *skb2;
+@@ -422,14 +423,16 @@ out:
+ default:
+ return;
+ case ICMP_PARAMETERPROB:
+- if (skb->h.icmph->un.gateway < (iph->ihl<<2))
++ n = ntohl(skb->h.icmph->un.gateway) >> 24;
++ if (n < (iph->ihl<<2))
+ return;
+
+ /* So... This guy found something strange INSIDE encapsulated
+ packet. Well, he is fool, but what can we do ?
+ */
+ rel_type = ICMP_PARAMETERPROB;
+- rel_info = skb->h.icmph->un.gateway - grehlen;
++ n -= grehlen;
++ rel_info = htonl(n << 24);
+ break;
+
+ case ICMP_DEST_UNREACH:
+@@ -440,13 +443,14 @@ out:
+ return;
+ case ICMP_FRAG_NEEDED:
+ /* And it is the only really necessary thing :-) */
+- rel_info = ntohs(skb->h.icmph->un.frag.mtu);
+- if (rel_info < grehlen+68)
++ n = ntohs(skb->h.icmph->un.frag.mtu);
++ if (n < grehlen+68)
+ return;
+- rel_info -= grehlen;
++ n -= grehlen;
+ /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
+- if (rel_info > ntohs(eiph->tot_len))
++ if (n > ntohs(eiph->tot_len))
+ return;
++ rel_info = htonl(n);
+ break;
+ default:
+ /* All others are translated to HOST_UNREACH.
+@@ -508,12 +512,11 @@ out:
+
+ /* change mtu on this route */
+ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+- if (rel_info > dst_mtu(skb2->dst)) {
++ if (n > dst_mtu(skb2->dst)) {
+ kfree_skb(skb2);
+ return;
+ }
+- skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
+- rel_info = htonl(rel_info);
++ skb2->dst->ops->update_pmtu(skb2->dst, n);
+ } else if (type == ICMP_TIME_EXCEEDED) {
+ struct ip_tunnel *t = netdev_priv(skb2->dev);
+ if (t->parms.iph.ttl) {
+@@ -576,7 +579,7 @@ static int ipgre_rcv(struct sk_buff *skb
+
+ if (flags&GRE_CSUM) {
+ switch (skb->ip_summed) {
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ csum = (u16)csum_fold(skb->csum);
+ if (!csum)
+ break;
+@@ -584,7 +587,7 @@ static int ipgre_rcv(struct sk_buff *skb
+ case CHECKSUM_NONE:
+ skb->csum = 0;
+ csum = __skb_checksum_complete(skb);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+ offset += 4;
+ }
+@@ -608,8 +611,8 @@ static int ipgre_rcv(struct sk_buff *skb
+ * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
+ */
+ if (flags == 0 &&
+- skb->protocol == __constant_htons(ETH_P_WCCP)) {
+- skb->protocol = __constant_htons(ETH_P_IP);
++ skb->protocol == htons(ETH_P_WCCP)) {
++ skb->protocol = htons(ETH_P_IP);
+ if ((*(h + offset) & 0xF0) != 0x40)
+ offset += 4;
+ }
+diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
+index 406056e..9f02917 100644
+--- a/net/ipv4/ip_options.c
++++ b/net/ipv4/ip_options.c
+@@ -24,6 +24,7 @@
+ #include <net/ip.h>
+ #include <net/icmp.h>
+ #include <net/route.h>
++#include <net/cipso_ipv4.h>
+
+ /*
+ * Write options to IP header, record destination address to
+@@ -37,7 +38,7 @@
+ */
+
+ void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
+- u32 daddr, struct rtable *rt, int is_frag)
++ __be32 daddr, struct rtable *rt, int is_frag)
+ {
+ unsigned char * iph = skb->nh.raw;
+
+@@ -56,7 +57,7 @@ void ip_options_build(struct sk_buff * s
+ ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt);
+ if (opt->ts_needtime) {
+ struct timeval tv;
+- __u32 midtime;
++ __be32 midtime;
+ do_gettimeofday(&tv);
+ midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+ memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
+@@ -90,7 +91,7 @@ int ip_options_echo(struct ip_options *
+ unsigned char *sptr, *dptr;
+ int soffset, doffset;
+ int optlen;
+- u32 daddr;
++ __be32 daddr;
+
+ memset(dopt, 0, sizeof(struct ip_options));
+
+@@ -147,7 +148,7 @@ int ip_options_echo(struct ip_options *
+ dopt->ts_needtime = 0;
+
+ if (soffset + 8 <= optlen) {
+- __u32 addr;
++ __be32 addr;
+
+ memcpy(&addr, sptr+soffset-1, 4);
+ if (inet_addr_type(addr) != RTN_LOCAL) {
+@@ -164,7 +165,7 @@ int ip_options_echo(struct ip_options *
+ }
+ if (sopt->srr) {
+ unsigned char * start = sptr+sopt->srr;
+- u32 faddr;
++ __be32 faddr;
+
+ optlen = start[1];
+ soffset = start[2];
+@@ -194,6 +195,13 @@ int ip_options_echo(struct ip_options *
+ dopt->is_strictroute = sopt->is_strictroute;
+ }
+ }
++ if (sopt->cipso) {
++ optlen = sptr[sopt->cipso+1];
++ dopt->cipso = dopt->optlen+sizeof(struct iphdr);
++ memcpy(dptr, sptr+sopt->cipso, optlen);
++ dptr += optlen;
++ dopt->optlen += optlen;
++ }
+ while (dopt->optlen & 3) {
+ *dptr++ = IPOPT_END;
+ dopt->optlen++;
+@@ -354,7 +362,7 @@ int ip_options_compile(struct ip_options
+ goto error;
+ }
+ if (optptr[2] <= optlen) {
+- __u32 * timeptr = NULL;
++ __be32 *timeptr = NULL;
+ if (optptr[2]+3 > optptr[1]) {
+ pp_ptr = optptr + 2;
+ goto error;
+@@ -363,7 +371,7 @@ int ip_options_compile(struct ip_options
+ case IPOPT_TS_TSONLY:
+ opt->ts = optptr - iph;
+ if (skb)
+- timeptr = (__u32*)&optptr[optptr[2]-1];
++ timeptr = (__be32*)&optptr[optptr[2]-1];
+ opt->ts_needtime = 1;
+ optptr[2] += 4;
+ break;
+@@ -375,7 +383,7 @@ int ip_options_compile(struct ip_options
+ opt->ts = optptr - iph;
+ if (skb) {
+ memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
+- timeptr = (__u32*)&optptr[optptr[2]+3];
++ timeptr = (__be32*)&optptr[optptr[2]+3];
+ }
+ opt->ts_needaddr = 1;
+ opt->ts_needtime = 1;
+@@ -388,12 +396,12 @@ int ip_options_compile(struct ip_options
+ }
+ opt->ts = optptr - iph;
+ {
+- u32 addr;
++ __be32 addr;
+ memcpy(&addr, &optptr[optptr[2]-1], 4);
+ if (inet_addr_type(addr) == RTN_UNICAST)
+ break;
+ if (skb)
+- timeptr = (__u32*)&optptr[optptr[2]+3];
++ timeptr = (__be32*)&optptr[optptr[2]+3];
+ }
+ opt->ts_needtime = 1;
+ optptr[2] += 8;
+@@ -407,10 +415,10 @@ int ip_options_compile(struct ip_options
+ }
+ if (timeptr) {
+ struct timeval tv;
+- __u32 midtime;
++ __be32 midtime;
+ do_gettimeofday(&tv);
+ midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+- memcpy(timeptr, &midtime, sizeof(__u32));
++ memcpy(timeptr, &midtime, sizeof(__be32));
+ opt->is_changed = 1;
+ }
+ } else {
+@@ -434,6 +442,17 @@ int ip_options_compile(struct ip_options
+ if (optptr[2] == 0 && optptr[3] == 0)
+ opt->router_alert = optptr - iph;
+ break;
++ case IPOPT_CIPSO:
++ if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) {
++ pp_ptr = optptr;
++ goto error;
++ }
++ opt->cipso = optptr - iph;
++ if (cipso_v4_validate(&optptr)) {
++ pp_ptr = optptr;
++ goto error;
++ }
++ break;
+ case IPOPT_SEC:
+ case IPOPT_SID:
+ default:
+@@ -506,7 +525,6 @@ static int ip_options_get_finish(struct
+ opt->__data[optlen++] = IPOPT_END;
+ opt->optlen = optlen;
+ opt->is_data = 1;
+- opt->is_setbyuser = 1;
+ if (optlen && ip_options_compile(opt, NULL)) {
+ kfree(opt);
+ return -EINVAL;
+@@ -589,7 +607,7 @@ int ip_options_rcv_srr(struct sk_buff *s
+ {
+ struct ip_options *opt = &(IPCB(skb)->opt);
+ int srrspace, srrptr;
+- u32 nexthop;
++ __be32 nexthop;
+ struct iphdr *iph = skb->nh.iph;
+ unsigned char * optptr = skb->nh.raw + opt->srr;
+ struct rtable *rt = (struct rtable*)skb->dst;
+diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
+index a2ede16..fc195a4 100644
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -83,7 +83,7 @@
+ #include <linux/netlink.h>
+ #include <linux/tcp.h>
+
+-int sysctl_ip_default_ttl = IPDEFTTL;
++int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
+
+ /* Generate a checksum for an outgoing IP datagram. */
+ __inline__ void ip_send_check(struct iphdr *iph)
+@@ -118,7 +118,7 @@ static inline int ip_select_ttl(struct i
+ *
+ */
+ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+- u32 saddr, u32 daddr, struct ip_options *opt)
++ __be32 saddr, __be32 daddr, struct ip_options *opt)
+ {
+ struct inet_sock *inet = inet_sk(sk);
+ struct rtable *rt = (struct rtable *)skb->dst;
+@@ -306,7 +306,7 @@ int ip_queue_xmit(struct sk_buff *skb, i
+ /* Make sure we can route this packet. */
+ rt = (struct rtable *)__sk_dst_check(sk, 0);
+ if (rt == NULL) {
+- u32 daddr;
++ __be32 daddr;
+
+ /* Use correct destination address if we have options. */
+ daddr = inet->daddr;
+@@ -328,6 +328,7 @@ int ip_queue_xmit(struct sk_buff *skb, i
+ * keep trying until route appears or the connection times
+ * itself out.
+ */
++ security_sk_classify_flow(sk, &fl);
+ if (ip_route_output_flow(&rt, &fl, sk, 0))
+ goto no_route;
+ }
+@@ -425,7 +426,7 @@ int ip_fragment(struct sk_buff *skb, int
+ int ptr;
+ struct net_device *dev;
+ struct sk_buff *skb2;
+- unsigned int mtu, hlen, left, len, ll_rs;
++ unsigned int mtu, hlen, left, len, ll_rs, pad;
+ int offset;
+ __be16 not_last_frag;
+ struct rtable *rt = (struct rtable*)skb->dst;
+@@ -555,14 +556,13 @@ slow_path:
+ left = skb->len - hlen; /* Space per frame */
+ ptr = raw + hlen; /* Where to start from */
+
+-#ifdef CONFIG_BRIDGE_NETFILTER
+ /* for bridged IP traffic encapsulated inside f.e. a vlan header,
+- * we need to make room for the encapsulating header */
+- ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, nf_bridge_pad(skb));
+- mtu -= nf_bridge_pad(skb);
+-#else
+- ll_rs = LL_RESERVED_SPACE(rt->u.dst.dev);
+-#endif
++ * we need to make room for the encapsulating header
++ */
++ pad = nf_bridge_pad(skb);
++ ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, pad);
++ mtu -= pad;
++
+ /*
+ * Fragment the datagram.
+ */
+@@ -679,7 +679,7 @@ ip_generic_getfrag(void *from, char *to,
+ {
+ struct iovec *iov = from;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (memcpy_fromiovecend(to, iov, offset, len) < 0)
+ return -EFAULT;
+ } else {
+@@ -735,7 +735,7 @@ static inline int ip_ufo_append_data(str
+ /* initialize protocol header pointer */
+ skb->h.raw = skb->data + fragheaderlen;
+
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum = 0;
+ sk->sk_sndmsg_off = 0;
+ }
+@@ -843,7 +843,7 @@ int ip_append_data(struct sock *sk,
+ length + fragheaderlen <= mtu &&
+ rt->u.dst.dev->features & NETIF_F_ALL_CSUM &&
+ !exthdrlen)
+- csummode = CHECKSUM_HW;
++ csummode = CHECKSUM_PARTIAL;
+
+ inet->cork.length += length;
+ if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
+@@ -1340,7 +1340,7 @@ void ip_send_reply(struct sock *sk, stru
+ char data[40];
+ } replyopts;
+ struct ipcm_cookie ipc;
+- u32 daddr;
++ __be32 daddr;
+ struct rtable *rt = (struct rtable*)skb->dst;
+
+ if (ip_options_echo(&replyopts.opt, skb))
+@@ -1366,6 +1366,7 @@ void ip_send_reply(struct sock *sk, stru
+ { .sport = skb->h.th->dest,
+ .dport = skb->h.th->source } },
+ .proto = sk->sk_protocol };
++ security_skb_classify_flow(skb, &fl);
+ if (ip_route_output_key(&rt, &fl))
+ return;
+ }
+diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
+index 2d05c41..4b13295 100644
+--- a/net/ipv4/ip_sockglue.c
++++ b/net/ipv4/ip_sockglue.c
+@@ -254,7 +254,7 @@ int ip_ra_control(struct sock *sk, unsig
+ }
+
+ void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+- u16 port, u32 info, u8 *payload)
++ __be16 port, u32 info, u8 *payload)
+ {
+ struct inet_sock *inet = inet_sk(sk);
+ struct sock_exterr_skb *serr;
+@@ -283,7 +283,7 @@ void ip_icmp_error(struct sock *sk, stru
+ kfree_skb(skb);
+ }
+
+-void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
++void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
+ {
+ struct inet_sock *inet = inet_sk(sk);
+ struct sock_exterr_skb *serr;
+diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
+index a0c28b2..3839b70 100644
+--- a/net/ipv4/ipcomp.c
++++ b/net/ipv4/ipcomp.c
+@@ -32,7 +32,7 @@
+
+ struct ipcomp_tfms {
+ struct list_head list;
+- struct crypto_tfm **tfms;
++ struct crypto_comp **tfms;
+ int users;
+ };
+
+@@ -46,7 +46,7 @@ static int ipcomp_decompress(struct xfrm
+ int err, plen, dlen;
+ struct ipcomp_data *ipcd = x->data;
+ u8 *start, *scratch;
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+ int cpu;
+
+ plen = skb->len;
+@@ -107,7 +107,7 @@ static int ipcomp_compress(struct xfrm_s
+ struct iphdr *iph = skb->nh.iph;
+ struct ipcomp_data *ipcd = x->data;
+ u8 *start, *scratch;
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+ int cpu;
+
+ ihlen = iph->ihl * 4;
+@@ -176,14 +176,14 @@ static int ipcomp_output(struct xfrm_sta
+ return 0;
+
+ out_ok:
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ ip_send_check(iph);
+ return 0;
+ }
+
+ static void ipcomp4_err(struct sk_buff *skb, u32 info)
+ {
+- u32 spi;
++ __be32 spi;
+ struct iphdr *iph = (struct iphdr *)skb->data;
+ struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
+ struct xfrm_state *x;
+@@ -206,6 +206,7 @@ static void ipcomp4_err(struct sk_buff *
+ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
+ {
+ struct xfrm_state *t;
++ u8 mode = XFRM_MODE_TUNNEL;
+
+ t = xfrm_state_alloc();
+ if (t == NULL)
+@@ -216,7 +217,9 @@ static struct xfrm_state *ipcomp_tunnel_
+ t->id.daddr.a4 = x->id.daddr.a4;
+ memcpy(&t->sel, &x->sel, sizeof(t->sel));
+ t->props.family = AF_INET;
+- t->props.mode = 1;
++ if (x->props.mode == XFRM_MODE_BEET)
++ mode = x->props.mode;
++ t->props.mode = mode;
+ t->props.saddr.a4 = x->props.saddr.a4;
+ t->props.flags = x->props.flags;
+
+@@ -302,7 +305,7 @@ static void **ipcomp_alloc_scratches(voi
+ return scratches;
+ }
+
+-static void ipcomp_free_tfms(struct crypto_tfm **tfms)
++static void ipcomp_free_tfms(struct crypto_comp **tfms)
+ {
+ struct ipcomp_tfms *pos;
+ int cpu;
+@@ -324,28 +327,28 @@ static void ipcomp_free_tfms(struct cryp
+ return;
+
+ for_each_possible_cpu(cpu) {
+- struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu);
+- crypto_free_tfm(tfm);
++ struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
++ crypto_free_comp(tfm);
+ }
+ free_percpu(tfms);
+ }
+
+-static struct crypto_tfm **ipcomp_alloc_tfms(const char *alg_name)
++static struct crypto_comp **ipcomp_alloc_tfms(const char *alg_name)
+ {
+ struct ipcomp_tfms *pos;
+- struct crypto_tfm **tfms;
++ struct crypto_comp **tfms;
+ int cpu;
+
+ /* This can be any valid CPU ID so we don't need locking. */
+ cpu = raw_smp_processor_id();
+
+ list_for_each_entry(pos, &ipcomp_tfms_list, list) {
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+
+ tfms = pos->tfms;
+ tfm = *per_cpu_ptr(tfms, cpu);
+
+- if (!strcmp(crypto_tfm_alg_name(tfm), alg_name)) {
++ if (!strcmp(crypto_comp_name(tfm), alg_name)) {
+ pos->users++;
+ return tfms;
+ }
+@@ -359,12 +362,13 @@ static struct crypto_tfm **ipcomp_alloc_
+ INIT_LIST_HEAD(&pos->list);
+ list_add(&pos->list, &ipcomp_tfms_list);
+
+- pos->tfms = tfms = alloc_percpu(struct crypto_tfm *);
++ pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
+ if (!tfms)
+ goto error;
+
+ for_each_possible_cpu(cpu) {
+- struct crypto_tfm *tfm = crypto_alloc_tfm(alg_name, 0);
++ struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
++ CRYPTO_ALG_ASYNC);
+ if (!tfm)
+ goto error;
+ *per_cpu_ptr(tfms, cpu) = tfm;
+@@ -415,7 +419,7 @@ static int ipcomp_init_state(struct xfrm
+ goto out;
+
+ x->props.header_len = 0;
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ x->props.header_len += sizeof(struct iphdr);
+
+ mutex_lock(&ipcomp_resource_mutex);
+@@ -427,7 +431,7 @@ static int ipcomp_init_state(struct xfrm
+ goto error;
+ mutex_unlock(&ipcomp_resource_mutex);
+
+- if (x->props.mode) {
++ if (x->props.mode == XFRM_MODE_TUNNEL) {
+ err = ipcomp_tunnel_attach(x);
+ if (err)
+ goto error_tunnel;
+diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
+index cb8a92f..955a07a 100644
+--- a/net/ipv4/ipconfig.c
++++ b/net/ipv4/ipconfig.c
+@@ -31,7 +31,6 @@
+ * -- Josef Siemes <jsiemes at web.de>, Aug 2002
+ */
+
+-#include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+@@ -367,7 +366,7 @@ static int __init ic_defaults(void)
+ */
+
+ if (!ic_host_name_set)
+- sprintf(system_utsname.nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
++ sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
+
+ if (root_server_addr == INADDR_NONE)
+ root_server_addr = ic_servaddr;
+@@ -421,7 +420,7 @@ ic_rarp_recv(struct sk_buff *skb, struct
+ {
+ struct arphdr *rarp;
+ unsigned char *rarp_ptr;
+- unsigned long sip, tip;
++ u32 sip, tip;
+ unsigned char *sha, *tha; /* s for "source", t for "target" */
+ struct ic_device *d;
+
+@@ -806,7 +805,7 @@ static void __init ic_do_bootp_ext(u8 *e
+ }
+ break;
+ case 12: /* Host name */
+- ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
++ ic_bootp_string(utsname()->nodename, ext+1, *ext, __NEW_UTS_LEN);
+ ic_host_name_set = 1;
+ break;
+ case 15: /* Domain name (DNS) */
+@@ -817,7 +816,7 @@ static void __init ic_do_bootp_ext(u8 *e
+ ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
+ break;
+ case 40: /* NIS Domain name (_not_ DNS) */
+- ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
++ ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN);
+ break;
+ }
+ }
+@@ -1369,7 +1368,7 @@ static int __init ip_auto_config(void)
+ printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask));
+ printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway));
+ printk(",\n host=%s, domain=%s, nis-domain=%s",
+- system_utsname.nodename, ic_domain, system_utsname.domainname);
++ utsname()->nodename, ic_domain, utsname()->domainname);
+ printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr));
+ printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr));
+ printk(", rootpath=%s", root_server_path);
+@@ -1479,11 +1478,11 @@ static int __init ip_auto_config_setup(c
+ case 4:
+ if ((dp = strchr(ip, '.'))) {
+ *dp++ = '\0';
+- strlcpy(system_utsname.domainname, dp,
+- sizeof(system_utsname.domainname));
++ strlcpy(utsname()->domainname, dp,
++ sizeof(utsname()->domainname));
+ }
+- strlcpy(system_utsname.nodename, ip,
+- sizeof(system_utsname.nodename));
++ strlcpy(utsname()->nodename, ip,
++ sizeof(utsname()->nodename));
+ ic_host_name_set = 1;
+ break;
+ case 5:
+diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
+index 76ab50b..0c45565 100644
+--- a/net/ipv4/ipip.c
++++ b/net/ipv4/ipip.c
+@@ -341,7 +341,8 @@ out:
+ int code = skb->h.icmph->code;
+ int rel_type = 0;
+ int rel_code = 0;
+- int rel_info = 0;
++ __be32 rel_info = 0;
++ __u32 n = 0;
+ struct sk_buff *skb2;
+ struct flowi fl;
+ struct rtable *rt;
+@@ -354,14 +355,15 @@ out:
+ default:
+ return 0;
+ case ICMP_PARAMETERPROB:
+- if (skb->h.icmph->un.gateway < hlen)
++ n = ntohl(skb->h.icmph->un.gateway) >> 24;
++ if (n < hlen)
+ return 0;
+
+ /* So... This guy found something strange INSIDE encapsulated
+ packet. Well, he is fool, but what can we do ?
+ */
+ rel_type = ICMP_PARAMETERPROB;
+- rel_info = skb->h.icmph->un.gateway - hlen;
++ rel_info = htonl((n - hlen) << 24);
+ break;
+
+ case ICMP_DEST_UNREACH:
+@@ -372,13 +374,14 @@ out:
+ return 0;
+ case ICMP_FRAG_NEEDED:
+ /* And it is the only really necessary thing :-) */
+- rel_info = ntohs(skb->h.icmph->un.frag.mtu);
+- if (rel_info < hlen+68)
++ n = ntohs(skb->h.icmph->un.frag.mtu);
++ if (n < hlen+68)
+ return 0;
+- rel_info -= hlen;
++ n -= hlen;
+ /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
+- if (rel_info > ntohs(eiph->tot_len))
++ if (n > ntohs(eiph->tot_len))
+ return 0;
++ rel_info = htonl(n);
+ break;
+ default:
+ /* All others are translated to HOST_UNREACH.
+@@ -440,12 +443,11 @@ out:
+
+ /* change mtu on this route */
+ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+- if (rel_info > dst_mtu(skb2->dst)) {
++ if (n > dst_mtu(skb2->dst)) {
+ kfree_skb(skb2);
+ return 0;
+ }
+- skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
+- rel_info = htonl(rel_info);
++ skb2->dst->ops->update_pmtu(skb2->dst, n);
+ } else if (type == ICMP_TIME_EXCEEDED) {
+ struct ip_tunnel *t = netdev_priv(skb2->dev);
+ if (t->parms.iph.ttl) {
+diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
+index 85893ee..97cfa97 100644
+--- a/net/ipv4/ipmr.c
++++ b/net/ipv4/ipmr.c
+@@ -312,7 +312,8 @@ static void ipmr_destroy_unres(struct mf
+ 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);
++
++ rtnl_unicast(skb, NETLINK_CB(skb).pid);
+ } else
+ kfree_skb(skb);
+ }
+@@ -461,7 +462,7 @@ static int vif_add(struct vifctl *vifc,
+ return 0;
+ }
+
+-static struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp)
++static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp)
+ {
+ int line=MFC_HASH(mcastgrp,origin);
+ struct mfc_cache *c;
+@@ -512,7 +513,6 @@ static void ipmr_cache_resolve(struct mf
+
+ while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
+ if (skb->nh.iph->version == 0) {
+- int err;
+ struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
+
+ if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
+@@ -525,7 +525,8 @@ static void ipmr_cache_resolve(struct mf
+ e->error = -EMSGSIZE;
+ memset(&e->msg, 0, sizeof(e->msg));
+ }
+- err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
++
++ rtnl_unicast(skb, NETLINK_CB(skb).pid);
+ } else
+ ip_mr_forward(skb, c, 0);
+ }
+@@ -1096,7 +1097,7 @@ static struct notifier_block ip_mr_notif
+ * important for multicast video.
+ */
+
+-static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr)
++static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
+ {
+ struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr));
+
+@@ -1899,11 +1900,8 @@ void __init ip_mr_init(void)
+ {
+ mrt_cachep = kmem_cache_create("ip_mrt_cache",
+ sizeof(struct mfc_cache),
+- 0, SLAB_HWCACHE_ALIGN,
++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+- if (!mrt_cachep)
+- panic("cannot allocate ip_mrt_cache");
+-
+ init_timer(&ipmr_expire_timer);
+ ipmr_expire_timer.function=ipmr_expire_process;
+ register_netdevice_notifier(&ip_mr_notifier);
+diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
+index c9820bf..891b935 100644
+--- a/net/ipv4/ipvs/Kconfig
++++ b/net/ipv4/ipvs/Kconfig
+@@ -81,7 +81,7 @@ config IP_VS_PROTO_ESP
+ bool "ESP load balancing support"
+ depends on IP_VS
+ ---help---
+- This option enables support for load balancing ESP (Encapsultion
++ This option enables support for load balancing ESP (Encapsulation
+ Security Payload) transport protocol. Say Y if unsure.
+
+ config IP_VS_PROTO_AH
+@@ -204,7 +204,7 @@ config IP_VS_SED
+ connections to the server with the shortest expected delay. The
+ expected delay that the job will experience is (Ci + 1) / Ui if
+ sent to the ith server, in which Ci is the number of connections
+- on the the ith server and Ui is the fixed service rate (weight)
++ on the ith server and Ui is the fixed service rate (weight)
+ of the ith server.
+
+ If you want to compile it in kernel, say Y. To compile it as a
+diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
+index 87b8381..8832eb5 100644
+--- a/net/ipv4/ipvs/ip_vs_conn.c
++++ b/net/ipv4/ipvs/ip_vs_conn.c
+@@ -115,9 +115,9 @@ static inline void ct_write_unlock_bh(un
+ /*
+ * Returns hash value for IPVS connection entry
+ */
+-static unsigned int ip_vs_conn_hashkey(unsigned proto, __u32 addr, __u16 port)
++static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port)
+ {
+- return jhash_3words(addr, port, proto, ip_vs_conn_rnd)
++ return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd)
+ & IP_VS_CONN_TAB_MASK;
+ }
+
+@@ -188,7 +188,7 @@ static inline int ip_vs_conn_unhash(stru
+ * d_addr, d_port: pkt dest address (load balancer)
+ */
+ static inline struct ip_vs_conn *__ip_vs_conn_in_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+ {
+ unsigned hash;
+ struct ip_vs_conn *cp;
+@@ -215,7 +215,7 @@ static inline struct ip_vs_conn *__ip_vs
+ }
+
+ struct ip_vs_conn *ip_vs_conn_in_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+ {
+ struct ip_vs_conn *cp;
+
+@@ -234,7 +234,7 @@ struct ip_vs_conn *ip_vs_conn_in_get
+
+ /* Get reference to connection template */
+ struct ip_vs_conn *ip_vs_ct_in_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+ {
+ unsigned hash;
+ struct ip_vs_conn *cp;
+@@ -274,7 +274,7 @@ struct ip_vs_conn *ip_vs_ct_in_get
+ * d_addr, d_port: pkt dest address (foreign host)
+ */
+ struct ip_vs_conn *ip_vs_conn_out_get
+-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
++(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+ {
+ unsigned hash;
+ struct ip_vs_conn *cp, *ret=NULL;
+@@ -324,7 +324,7 @@ void ip_vs_conn_put(struct ip_vs_conn *c
+ /*
+ * Fill a no_client_port connection with a client port number
+ */
+-void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport)
++void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport)
+ {
+ if (ip_vs_conn_unhash(cp)) {
+ spin_lock(&cp->lock);
+@@ -508,10 +508,10 @@ int ip_vs_check_template(struct ip_vs_co
+ /*
+ * Invalidate the connection template
+ */
+- if (ct->vport != 65535) {
++ if (ct->vport != htons(0xffff)) {
+ if (ip_vs_conn_unhash(ct)) {
+- ct->dport = 65535;
+- ct->vport = 65535;
++ ct->dport = htons(0xffff);
++ ct->vport = htons(0xffff);
+ ct->cport = 0;
+ ip_vs_conn_hash(ct);
+ }
+@@ -596,8 +596,8 @@ void ip_vs_conn_expire_now(struct ip_vs_
+ * Create a new connection entry and hash it into the ip_vs_conn_tab
+ */
+ struct ip_vs_conn *
+-ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
+- __u32 daddr, __u16 dport, unsigned flags,
++ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
++ __be32 daddr, __be16 dport, unsigned flags,
+ struct ip_vs_dest *dest)
+ {
+ struct ip_vs_conn *cp;
+diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
+index 3f47ad8..1445bb4 100644
+--- a/net/ipv4/ipvs/ip_vs_core.c
++++ b/net/ipv4/ipvs/ip_vs_core.c
+@@ -209,14 +209,14 @@ int ip_vs_make_skb_writable(struct sk_bu
+ static struct ip_vs_conn *
+ ip_vs_sched_persist(struct ip_vs_service *svc,
+ const struct sk_buff *skb,
+- __u16 ports[2])
++ __be16 ports[2])
+ {
+ struct ip_vs_conn *cp = NULL;
+ struct iphdr *iph = skb->nh.iph;
+ struct ip_vs_dest *dest;
+ struct ip_vs_conn *ct;
+- __u16 dport; /* destination port to forward */
+- __u32 snet; /* source network of the client, after masking */
++ __be16 dport; /* destination port to forward */
++ __be32 snet; /* source network of the client, after masking */
+
+ /* Mask saddr with the netmask to adjust template granularity */
+ snet = iph->saddr & svc->netmask;
+@@ -383,7 +383,7 @@ ip_vs_schedule(struct ip_vs_service *svc
+ struct ip_vs_conn *cp = NULL;
+ struct iphdr *iph = skb->nh.iph;
+ struct ip_vs_dest *dest;
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, iph->ihl*4,
+ sizeof(_ports), _ports);
+@@ -446,7 +446,7 @@ ip_vs_schedule(struct ip_vs_service *svc
+ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
+ struct ip_vs_protocol *pp)
+ {
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+ struct iphdr *iph = skb->nh.iph;
+
+ pptr = skb_header_pointer(skb, iph->ihl*4,
+@@ -576,7 +576,7 @@ void ip_vs_nat_icmp(struct sk_buff *skb,
+
+ /* the TCP/UDP port */
+ if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) {
+- __u16 *ports = (void *)ciph + ciph->ihl*4;
++ __be16 *ports = (void *)ciph + ciph->ihl*4;
+
+ if (inout)
+ ports[1] = cp->vport;
+@@ -775,7 +775,7 @@ ip_vs_out(unsigned int hooknum, struct s
+ if (sysctl_ip_vs_nat_icmp_send &&
+ (pp->protocol == IPPROTO_TCP ||
+ pp->protocol == IPPROTO_UDP)) {
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, ihl,
+ sizeof(_ports), _ports);
+@@ -813,6 +813,16 @@ ip_vs_out(unsigned int hooknum, struct s
+ skb->nh.iph->saddr = cp->vaddr;
+ ip_send_check(skb->nh.iph);
+
++ /* For policy routing, packets originating from this
++ * machine itself may be routed differently to packets
++ * passing through. We want this packet to be routed as
++ * if it came from this machine itself. So re-compute
++ * the routing information.
++ */
++ if (ip_route_me_harder(pskb, RTN_LOCAL) != 0)
++ goto drop;
++ skb = *pskb;
++
+ IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
+
+ ip_vs_out_stats(cp, skb);
+diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
+index 6a28faf..f261616 100644
+--- a/net/ipv4/ipvs/ip_vs_ctl.c
++++ b/net/ipv4/ipvs/ip_vs_ctl.c
+@@ -283,7 +283,7 @@ static atomic_t ip_vs_nullsvc_counter =
+ * Returns hash value for virtual service
+ */
+ static __inline__ unsigned
+-ip_vs_svc_hashkey(unsigned proto, __u32 addr, __u16 port)
++ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port)
+ {
+ register unsigned porth = ntohs(port);
+
+@@ -365,7 +365,7 @@ static int ip_vs_svc_unhash(struct ip_vs
+ * Get service by {proto,addr,port} in the service table.
+ */
+ static __inline__ struct ip_vs_service *
+-__ip_vs_service_get(__u16 protocol, __u32 vaddr, __u16 vport)
++__ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
+ {
+ unsigned hash;
+ struct ip_vs_service *svc;
+@@ -410,7 +410,7 @@ static __inline__ struct ip_vs_service *
+ }
+
+ struct ip_vs_service *
+-ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport)
++ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
+ {
+ struct ip_vs_service *svc;
+
+@@ -480,7 +480,7 @@ __ip_vs_unbind_svc(struct ip_vs_dest *de
+ /*
+ * Returns hash value for real service
+ */
+-static __inline__ unsigned ip_vs_rs_hashkey(__u32 addr, __u16 port)
++static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
+ {
+ register unsigned porth = ntohs(port);
+
+@@ -531,7 +531,7 @@ static int ip_vs_rs_unhash(struct ip_vs_
+ * Lookup real service by <proto,addr,port> in the real service table.
+ */
+ struct ip_vs_dest *
+-ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport)
++ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
+ {
+ unsigned hash;
+ struct ip_vs_dest *dest;
+@@ -562,7 +562,7 @@ ip_vs_lookup_real_service(__u16 protocol
+ * Lookup destination by {addr,port} in the given service
+ */
+ static struct ip_vs_dest *
+-ip_vs_lookup_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
++ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
+ {
+ struct ip_vs_dest *dest;
+
+@@ -591,7 +591,7 @@ ip_vs_lookup_dest(struct ip_vs_service *
+ * scheduling.
+ */
+ static struct ip_vs_dest *
+-ip_vs_trash_get_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
++ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
+ {
+ struct ip_vs_dest *dest, *nxt;
+
+@@ -773,8 +773,8 @@ static int
+ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
+ {
+ struct ip_vs_dest *dest;
+- __u32 daddr = udest->addr;
+- __u16 dport = udest->port;
++ __be32 daddr = udest->addr;
++ __be16 dport = udest->port;
+ int ret;
+
+ EnterFunction(2);
+@@ -879,8 +879,8 @@ static int
+ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
+ {
+ struct ip_vs_dest *dest;
+- __u32 daddr = udest->addr;
+- __u16 dport = udest->port;
++ __be32 daddr = udest->addr;
++ __be16 dport = udest->port;
+
+ EnterFunction(2);
+
+@@ -991,8 +991,8 @@ static int
+ ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
+ {
+ struct ip_vs_dest *dest;
+- __u32 daddr = udest->addr;
+- __u16 dport = udest->port;
++ __be32 daddr = udest->addr;
++ __be16 dport = udest->port;
+
+ EnterFunction(2);
+
+diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
+index 9fee19c..502111f 100644
+--- a/net/ipv4/ipvs/ip_vs_dh.c
++++ b/net/ipv4/ipvs/ip_vs_dh.c
+@@ -66,7 +66,7 @@ struct ip_vs_dh_bucket {
+ /*
+ * Returns hash value for IPVS DH entry
+ */
+-static inline unsigned ip_vs_dh_hashkey(__u32 addr)
++static inline unsigned ip_vs_dh_hashkey(__be32 addr)
+ {
+ return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
+ }
+@@ -76,7 +76,7 @@ static inline unsigned ip_vs_dh_hashkey(
+ * Get ip_vs_dest associated with supplied parameters.
+ */
+ static inline struct ip_vs_dest *
+-ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __u32 addr)
++ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr)
+ {
+ return (tbl[ip_vs_dh_hashkey(addr)]).dest;
+ }
+diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
+index 37fafb1..6d398f1 100644
+--- a/net/ipv4/ipvs/ip_vs_ftp.c
++++ b/net/ipv4/ipvs/ip_vs_ftp.c
+@@ -32,6 +32,7 @@
+ #include <linux/ip.h>
+ #include <net/protocol.h>
+ #include <net/tcp.h>
++#include <asm/unaligned.h>
+
+ #include <net/ip_vs.h>
+
+@@ -44,8 +45,8 @@
+ * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+-static int ports[IP_VS_APP_MAX_PORTS] = {21, 0};
+-module_param_array(ports, int, NULL, 0);
++static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0};
++module_param_array(ports, ushort, NULL, 0);
+ MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands");
+
+
+@@ -74,7 +75,7 @@ ip_vs_ftp_done_conn(struct ip_vs_app *ap
+ */
+ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
+ const char *pattern, size_t plen, char term,
+- __u32 *addr, __u16 *port,
++ __be32 *addr, __be16 *port,
+ char **start, char **end)
+ {
+ unsigned char p[6];
+@@ -114,8 +115,8 @@ static int ip_vs_ftp_get_addrport(char *
+ if (i != 5)
+ return -1;
+
+- *addr = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
+- *port = (p[5]<<8) | p[4];
++ *addr = get_unaligned((__be32 *)p);
++ *port = get_unaligned((__be16 *)(p + 4));
+ return 1;
+ }
+
+@@ -140,8 +141,8 @@ static int ip_vs_ftp_out(struct ip_vs_ap
+ struct tcphdr *th;
+ char *data, *data_limit;
+ char *start, *end;
+- __u32 from;
+- __u16 port;
++ __be32 from;
++ __be16 port;
+ struct ip_vs_conn *n_cp;
+ char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
+ unsigned buf_len;
+@@ -199,7 +200,7 @@ static int ip_vs_ftp_out(struct ip_vs_ap
+ from = n_cp->vaddr;
+ port = n_cp->vport;
+ sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
+- port&255, (port>>8)&255);
++ ntohs(port)&255, (ntohs(port)>>8)&255);
+ buf_len = strlen(buf);
+
+ /*
+@@ -243,8 +244,8 @@ static int ip_vs_ftp_in(struct ip_vs_app
+ struct tcphdr *th;
+ char *data, *data_start, *data_limit;
+ char *start, *end;
+- __u32 to;
+- __u16 port;
++ __be32 to;
++ __be16 port;
+ struct ip_vs_conn *n_cp;
+
+ /* no diff required for incoming packets */
+@@ -273,7 +274,7 @@ static int ip_vs_ftp_in(struct ip_vs_app
+ while (data <= data_limit - 6) {
+ if (strnicmp(data, "PASV\r\n", 6) == 0) {
+ /* Passive mode on */
+- IP_VS_DBG(7, "got PASV at %zd of %zd\n",
++ IP_VS_DBG(7, "got PASV at %td of %td\n",
+ data - data_start,
+ data_limit - data_start);
+ cp->app_data = &ip_vs_ftp_pasv;
+@@ -365,12 +366,6 @@ static int __init ip_vs_ftp_init(void)
+ for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
+ if (!ports[i])
+ continue;
+- if (ports[i] < 0 || ports[i] > 0xffff) {
+- IP_VS_WARNING("ip_vs_ftp: Ignoring invalid "
+- "configuration port[%d] = %d\n",
+- i, ports[i]);
+- continue;
+- }
+ ret = register_ip_vs_app_inc(app, app->protocol, ports[i]);
+ if (ret)
+ break;
+diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
+index 6e5cb92..524751e 100644
+--- a/net/ipv4/ipvs/ip_vs_lblc.c
++++ b/net/ipv4/ipvs/ip_vs_lblc.c
+@@ -87,7 +87,7 @@ static int sysctl_ip_vs_lblc_expiration
+ */
+ struct ip_vs_lblc_entry {
+ struct list_head list;
+- __u32 addr; /* destination IP address */
++ __be32 addr; /* destination IP address */
+ struct ip_vs_dest *dest; /* real server (cache) */
+ unsigned long lastuse; /* last used time */
+ };
+@@ -160,7 +160,7 @@ static struct ctl_table_header * sysctl_
+ * IP address to a server.
+ */
+ static inline struct ip_vs_lblc_entry *
+-ip_vs_lblc_new(__u32 daddr, struct ip_vs_dest *dest)
++ip_vs_lblc_new(__be32 daddr, struct ip_vs_dest *dest)
+ {
+ struct ip_vs_lblc_entry *en;
+
+@@ -195,7 +195,7 @@ static inline void ip_vs_lblc_free(struc
+ /*
+ * Returns hash value for IPVS LBLC entry
+ */
+-static inline unsigned ip_vs_lblc_hashkey(__u32 addr)
++static inline unsigned ip_vs_lblc_hashkey(__be32 addr)
+ {
+ return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
+ }
+@@ -234,7 +234,7 @@ ip_vs_lblc_hash(struct ip_vs_lblc_table
+ * Get ip_vs_lblc_entry associated with supplied parameters.
+ */
+ static inline struct ip_vs_lblc_entry *
+-ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __u32 addr)
++ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr)
+ {
+ unsigned hash;
+ struct ip_vs_lblc_entry *en;
+diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
+index 32ba37b..0899019 100644
+--- a/net/ipv4/ipvs/ip_vs_lblcr.c
++++ b/net/ipv4/ipvs/ip_vs_lblcr.c
+@@ -276,7 +276,7 @@ static inline struct ip_vs_dest *ip_vs_d
+ */
+ struct ip_vs_lblcr_entry {
+ struct list_head list;
+- __u32 addr; /* destination IP address */
++ __be32 addr; /* destination IP address */
+ struct ip_vs_dest_set set; /* destination server set */
+ unsigned long lastuse; /* last used time */
+ };
+@@ -348,7 +348,7 @@ static struct ctl_table_header * sysctl_
+ * new/free a ip_vs_lblcr_entry, which is a mapping of a destination
+ * IP address to a server.
+ */
+-static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__u32 daddr)
++static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__be32 daddr)
+ {
+ struct ip_vs_lblcr_entry *en;
+
+@@ -381,7 +381,7 @@ static inline void ip_vs_lblcr_free(stru
+ /*
+ * Returns hash value for IPVS LBLCR entry
+ */
+-static inline unsigned ip_vs_lblcr_hashkey(__u32 addr)
++static inline unsigned ip_vs_lblcr_hashkey(__be32 addr)
+ {
+ return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
+ }
+@@ -420,7 +420,7 @@ ip_vs_lblcr_hash(struct ip_vs_lblcr_tabl
+ * Get ip_vs_lblcr_entry associated with supplied parameters.
+ */
+ static inline struct ip_vs_lblcr_entry *
+-ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __u32 addr)
++ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr)
+ {
+ unsigned hash;
+ struct ip_vs_lblcr_entry *en;
+diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
+index 867d4e9..c4528b5 100644
+--- a/net/ipv4/ipvs/ip_vs_proto.c
++++ b/net/ipv4/ipvs/ip_vs_proto.c
+@@ -176,7 +176,7 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_p
+ pp->name, NIPQUAD(ih->saddr),
+ NIPQUAD(ih->daddr));
+ else {
+- __u16 _ports[2], *pptr
++ __be16 _ports[2], *pptr
+ ;
+ pptr = skb_header_pointer(skb, offset + ih->ihl*4,
+ sizeof(_ports), _ports);
+diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
+index bc28b11..bfe779e 100644
+--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
++++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
+@@ -29,7 +29,7 @@ static struct ip_vs_conn *
+ tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
+ const struct iphdr *iph, unsigned int proto_off, int inverse)
+ {
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+@@ -50,7 +50,7 @@ static struct ip_vs_conn *
+ tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
+ const struct iphdr *iph, unsigned int proto_off, int inverse)
+ {
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+@@ -112,12 +112,12 @@ tcp_conn_schedule(struct sk_buff *skb,
+
+
+ static inline void
+-tcp_fast_csum_update(struct tcphdr *tcph, u32 oldip, u32 newip,
+- u16 oldport, u16 newport)
++tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
++ __be16 oldport, __be16 newport)
+ {
+ tcph->check =
+ ip_vs_check_diff(~oldip, newip,
+- ip_vs_check_diff(oldport ^ 0xFFFF,
++ ip_vs_check_diff(oldport ^ htonl(0xFFFF),
+ newport, tcph->check));
+ }
+
+@@ -151,7 +151,7 @@ tcp_snat_handler(struct sk_buff **pskb,
+ /* Only port and addr are changed, do fast csum update */
+ tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr,
+ cp->dport, cp->vport);
+- if ((*pskb)->ip_summed == CHECKSUM_HW)
++ if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+ } else {
+ /* full checksum calculation */
+@@ -204,7 +204,7 @@ tcp_dnat_handler(struct sk_buff **pskb,
+ /* Only port and addr are changed, do fast csum update */
+ tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
+ cp->vport, cp->dport);
+- if ((*pskb)->ip_summed == CHECKSUM_HW)
++ if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+ } else {
+ /* full checksum calculation */
+@@ -229,7 +229,7 @@ tcp_csum_check(struct sk_buff *skb, stru
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->len - tcphoff,
+ skb->nh.iph->protocol, skb->csum)) {
+@@ -239,7 +239,7 @@ tcp_csum_check(struct sk_buff *skb, stru
+ }
+ break;
+ default:
+- /* CHECKSUM_UNNECESSARY */
++ /* No need to checksum. */
+ break;
+ }
+
+diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
+index 89d9175..54aa760 100644
+--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
++++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
+@@ -29,7 +29,7 @@ udp_conn_in_get(const struct sk_buff *sk
+ const struct iphdr *iph, unsigned int proto_off, int inverse)
+ {
+ struct ip_vs_conn *cp;
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+@@ -54,7 +54,7 @@ udp_conn_out_get(const struct sk_buff *s
+ const struct iphdr *iph, unsigned int proto_off, int inverse)
+ {
+ struct ip_vs_conn *cp;
+- __u16 _ports[2], *pptr;
++ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+ sizeof(_ports), _ports);
+@@ -117,15 +117,15 @@ udp_conn_schedule(struct sk_buff *skb, s
+
+
+ static inline void
+-udp_fast_csum_update(struct udphdr *uhdr, u32 oldip, u32 newip,
+- u16 oldport, u16 newport)
++udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
++ __be16 oldport, __be16 newport)
+ {
+ uhdr->check =
+ ip_vs_check_diff(~oldip, newip,
+- ip_vs_check_diff(oldport ^ 0xFFFF,
++ ip_vs_check_diff(oldport ^ htonl(0xFFFF),
+ newport, uhdr->check));
+ if (!uhdr->check)
+- uhdr->check = 0xFFFF;
++ uhdr->check = htonl(0xFFFF);
+ }
+
+ static int
+@@ -161,7 +161,7 @@ udp_snat_handler(struct sk_buff **pskb,
+ /* Only port and addr are changed, do fast csum update */
+ udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
+ cp->dport, cp->vport);
+- if ((*pskb)->ip_summed == CHECKSUM_HW)
++ if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+ } else {
+ /* full checksum calculation */
+@@ -173,7 +173,7 @@ udp_snat_handler(struct sk_buff **pskb,
+ cp->protocol,
+ (*pskb)->csum);
+ if (udph->check == 0)
+- udph->check = 0xFFFF;
++ udph->check = htonl(0xFFFF);
+ IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
+ pp->name, udph->check,
+ (char*)&(udph->check) - (char*)udph);
+@@ -216,7 +216,7 @@ udp_dnat_handler(struct sk_buff **pskb,
+ /* Only port and addr are changed, do fast csum update */
+ udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
+ cp->vport, cp->dport);
+- if ((*pskb)->ip_summed == CHECKSUM_HW)
++ if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+ } else {
+ /* full checksum calculation */
+@@ -250,7 +250,7 @@ udp_csum_check(struct sk_buff *skb, stru
+ case CHECKSUM_NONE:
+ skb->csum = skb_checksum(skb, udphoff,
+ skb->len - udphoff, 0);
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr,
+ skb->len - udphoff,
+@@ -262,7 +262,7 @@ udp_csum_check(struct sk_buff *skb, stru
+ }
+ break;
+ default:
+- /* CHECKSUM_UNNECESSARY */
++ /* No need to checksum. */
+ break;
+ }
+ }
+diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
+index 7775e6c..338668f 100644
+--- a/net/ipv4/ipvs/ip_vs_sh.c
++++ b/net/ipv4/ipvs/ip_vs_sh.c
+@@ -63,7 +63,7 @@ struct ip_vs_sh_bucket {
+ /*
+ * Returns hash value for IPVS SH entry
+ */
+-static inline unsigned ip_vs_sh_hashkey(__u32 addr)
++static inline unsigned ip_vs_sh_hashkey(__be32 addr)
+ {
+ return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
+ }
+@@ -73,7 +73,7 @@ static inline unsigned ip_vs_sh_hashkey(
+ * Get ip_vs_dest associated with supplied parameters.
+ */
+ static inline struct ip_vs_dest *
+-ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __u32 addr)
++ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr)
+ {
+ return (tbl[ip_vs_sh_hashkey(addr)]).dest;
+ }
+diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
+index 1bca714..91a075e 100644
+--- a/net/ipv4/ipvs/ip_vs_sync.c
++++ b/net/ipv4/ipvs/ip_vs_sync.c
+@@ -48,16 +48,16 @@ struct ip_vs_sync_conn {
+
+ /* Protocol, addresses and port numbers */
+ __u8 protocol; /* Which protocol (TCP/UDP) */
+- __u16 cport;
+- __u16 vport;
+- __u16 dport;
+- __u32 caddr; /* client address */
+- __u32 vaddr; /* virtual address */
+- __u32 daddr; /* destination address */
++ __be16 cport;
++ __be16 vport;
++ __be16 dport;
++ __be32 caddr; /* client address */
++ __be32 vaddr; /* virtual address */
++ __be32 daddr; /* destination address */
+
+ /* Flags and state transition */
+- __u16 flags; /* status flags */
+- __u16 state; /* state info */
++ __be16 flags; /* status flags */
++ __be16 state; /* state info */
+
+ /* The sequence options start here */
+ };
+@@ -464,7 +464,7 @@ join_mcast_group(struct sock *sk, struct
+ static int bind_mcastif_addr(struct socket *sock, char *ifname)
+ {
+ struct net_device *dev;
+- u32 addr;
++ __be32 addr;
+ struct sockaddr_in sin;
+
+ if ((dev = __dev_get_by_name(ifname)) == NULL)
+@@ -836,7 +836,7 @@ static int fork_sync_thread(void *startu
+
+ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
+ {
+- DECLARE_COMPLETION(startup);
++ DECLARE_COMPLETION_ONSTACK(startup);
+ pid_t pid;
+
+ if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
+diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
+index 52c12e9..e1f77bd 100644
+--- a/net/ipv4/ipvs/ip_vs_xmit.c
++++ b/net/ipv4/ipvs/ip_vs_xmit.c
+@@ -232,7 +232,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, stru
+
+ /* check if it is a connection of no-client-port */
+ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+- __u16 _pt, *p;
++ __be16 _pt, *p;
+ p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
+ if (p == NULL)
+ goto tx_error;
+diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
+index d25ec4a..92b0482 100644
+--- a/net/ipv4/multipath_wrandom.c
++++ b/net/ipv4/multipath_wrandom.c
+@@ -60,8 +60,8 @@ struct multipath_dest {
+ struct list_head list;
+
+ const struct fib_nh *nh_info;
+- __u32 netmask;
+- __u32 network;
++ __be32 netmask;
++ __be32 network;
+ unsigned char prefixlen;
+
+ struct rcu_head rcu;
+@@ -76,7 +76,7 @@ struct multipath_route {
+ struct list_head list;
+
+ int oif;
+- __u32 gw;
++ __be32 gw;
+ struct list_head dests;
+
+ struct rcu_head rcu;
+@@ -128,8 +128,8 @@ static unsigned char __multipath_lookup_
+
+ /* find state entry for destination */
+ list_for_each_entry_rcu(d, &target_route->dests, list) {
+- __u32 targetnetwork = fl->fl4_dst &
+- (0xFFFFFFFF >> (32 - d->prefixlen));
++ __be32 targetnetwork = fl->fl4_dst &
++ inet_make_mask(d->prefixlen);
+
+ if ((targetnetwork & d->netmask) == d->network) {
+ weight = d->nh_info->nh_weight;
+@@ -217,8 +217,8 @@ static void wrandom_select_route(const s
+ *rp = decision;
+ }
+
+-static void wrandom_set_nhinfo(__u32 network,
+- __u32 netmask,
++static void wrandom_set_nhinfo(__be32 network,
++ __be32 netmask,
+ unsigned char prefixlen,
+ const struct fib_nh *nh)
+ {
+diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
+index 6a9e34b..e2005c6 100644
+--- a/net/ipv4/netfilter.c
++++ b/net/ipv4/netfilter.c
+@@ -8,7 +8,7 @@
+ #include <net/ip.h>
+
+ /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
+-int ip_route_me_harder(struct sk_buff **pskb)
++int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
+ {
+ struct iphdr *iph = (*pskb)->nh.iph;
+ struct rtable *rt;
+@@ -16,10 +16,13 @@ int ip_route_me_harder(struct sk_buff **
+ struct dst_entry *odst;
+ unsigned int hh_len;
+
++ if (addr_type == RTN_UNSPEC)
++ addr_type = inet_addr_type(iph->saddr);
++
+ /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
+ * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
+ */
+- if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
++ if (addr_type == RTN_LOCAL) {
+ fl.nl_u.ip4_u.daddr = iph->daddr;
+ fl.nl_u.ip4_u.saddr = iph->saddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+@@ -128,8 +131,8 @@ EXPORT_SYMBOL(ip_nat_decode_session);
+ */
+
+ struct ip_rt_info {
+- u_int32_t daddr;
+- u_int32_t saddr;
++ __be32 daddr;
++ __be32 saddr;
+ u_int8_t tos;
+ };
+
+@@ -156,7 +159,7 @@ static int nf_ip_reroute(struct sk_buff
+ if (!(iph->tos == rt_info->tos
+ && iph->daddr == rt_info->daddr
+ && iph->saddr == rt_info->saddr))
+- return ip_route_me_harder(pskb);
++ return ip_route_me_harder(pskb, RTN_UNSPEC);
+ }
+ return 0;
+ }
+@@ -168,7 +171,7 @@ unsigned int nf_ip_checksum(struct sk_bu
+ unsigned int csum = 0;
+
+ switch (skb->ip_summed) {
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN)
+ break;
+ if ((protocol == 0 && !(u16)csum_fold(skb->csum)) ||
+diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
+index ef0b5aa..d88c292 100644
+--- a/net/ipv4/netfilter/Kconfig
++++ b/net/ipv4/netfilter/Kconfig
+@@ -278,17 +278,6 @@ config IP_NF_MATCH_ECN
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+-config IP_NF_MATCH_DSCP
+- tristate "DSCP match support"
+- depends on IP_NF_IPTABLES
+- help
+- This option adds a `DSCP' match, which allows you to match against
+- the IPv4 header DSCP field (DSCP codepoint).
+-
+- The DSCP codepoint can have any value between 0x0 and 0x4f.
+-
+- To compile it as a module, choose M here. If unsure, say N.
+-
+ config IP_NF_MATCH_AH
+ tristate "AH match support"
+ depends on IP_NF_IPTABLES
+@@ -384,7 +373,7 @@ config IP_NF_TARGET_ULOG
+ daemon using netlink multicast sockets; unlike the LOG target
+ which can only be viewed through syslog.
+
+- The apropriate userspace logging daemon (ulogd) may be obtained from
++ The appropriate userspace logging daemon (ulogd) may be obtained from
+ <http://www.gnumonks.org/projects/ulogd/>
+
+ To compile it as a module, choose M here. If unsure, say N.
+@@ -568,17 +557,6 @@ config IP_NF_TARGET_ECN
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+-config IP_NF_TARGET_DSCP
+- tristate "DSCP target support"
+- depends on IP_NF_MANGLE
+- help
+- This option adds a `DSCP' match, which allows you to match against
+- the IPv4 header DSCP field (DSCP codepoint).
+-
+- The DSCP codepoint can have any value between 0x0 and 0x4f.
+-
+- To compile it as a module, choose M here. If unsure, say N.
+-
+ config IP_NF_TARGET_TTL
+ tristate 'TTL target support'
+ depends on IP_NF_MANGLE
+diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
+index 3ded4a3..09aaed1 100644
+--- a/net/ipv4/netfilter/Makefile
++++ b/net/ipv4/netfilter/Makefile
+@@ -59,7 +59,6 @@ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_o
+ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+ obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+-obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
+ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
+@@ -68,7 +67,6 @@ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ip
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+ obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+-obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+ obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
+diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
+index 8d1d7a6..413c2d0 100644
+--- a/net/ipv4/netfilter/arp_tables.c
++++ b/net/ipv4/netfilter/arp_tables.c
+@@ -56,8 +56,6 @@ do { \
+ #define ARP_NF_ASSERT(x)
+ #endif
+
+-#include <linux/netfilter_ipv4/listhelp.h>
+-
+ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
+ char *hdr_addr, int len)
+ {
+@@ -82,7 +80,7 @@ static inline int arp_packet_match(const
+ {
+ char *arpptr = (char *)(arphdr + 1);
+ char *src_devaddr, *tgt_devaddr;
+- u32 src_ipaddr, tgt_ipaddr;
++ __be32 src_ipaddr, tgt_ipaddr;
+ int i, ret;
+
+ #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg))
+@@ -208,8 +206,7 @@ static unsigned int arpt_error(struct sk
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ if (net_ratelimit())
+ printk("arp_tables: error: '%s'\n", (char *)targinfo);
+@@ -226,8 +223,7 @@ unsigned int arpt_do_table(struct sk_buf
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+- struct arpt_table *table,
+- void *userdata)
++ struct arpt_table *table)
+ {
+ static const char nulldevname[IFNAMSIZ];
+ unsigned int verdict = NF_DROP;
+@@ -302,8 +298,7 @@ unsigned int arpt_do_table(struct sk_buf
+ in, out,
+ hook,
+ t->u.kernel.target,
+- t->data,
+- userdata);
++ t->data);
+
+ /* Target might have changed stuff. */
+ arp = (*pskb)->nh.arph;
+@@ -471,7 +466,13 @@ static inline int check_entry(struct arp
+ return -EINVAL;
+ }
+
++ if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
++ return -EINVAL;
++
+ t = arpt_get_target(e);
++ if (e->target_offset + t->u.target_size > e->next_offset)
++ return -EINVAL;
++
+ target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
+ t->u.user.revision),
+ "arpt_%s", t->u.user.name);
+@@ -490,12 +491,10 @@ static inline int check_entry(struct arp
+ if (t->u.kernel.target == &arpt_standard_target) {
+ if (!standard_check(t, size)) {
+ ret = -EINVAL;
+- goto out;
++ goto err;
+ }
+ } else if (t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(name, e, target, t->data,
+- t->u.target_size
+- - sizeof(*t),
+ e->comefrom)) {
+ duprintf("arp_tables: check failed for `%s'.\n",
+ t->u.kernel.target->name);
+@@ -562,8 +561,7 @@ static inline int cleanup_entry(struct a
+
+ t = arpt_get_target(e);
+ if (t->u.kernel.target->destroy)
+- t->u.kernel.target->destroy(t->u.kernel.target, t->data,
+- t->u.target_size - sizeof(*t));
++ t->u.kernel.target->destroy(t->u.kernel.target, t->data);
+ module_put(t->u.kernel.target->me);
+ return 0;
+ }
+@@ -629,20 +627,18 @@ static int translate_table(const char *n
+ }
+ }
+
+- if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
+- duprintf("Looping hook\n");
+- return -ELOOP;
+- }
+-
+ /* Finally, each sanity check must pass */
+ i = 0;
+ ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
+ check_entry, name, size, &i);
+
+- if (ret != 0) {
+- ARPT_ENTRY_ITERATE(entry0, newinfo->size,
+- cleanup_entry, &i);
+- return ret;
++ if (ret != 0)
++ goto cleanup;
++
++ ret = -ELOOP;
++ if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
++ duprintf("Looping hook\n");
++ goto cleanup;
+ }
+
+ /* And one copy for every other CPU */
+@@ -651,6 +647,9 @@ static int translate_table(const char *n
+ memcpy(newinfo->entries[i], entry0, newinfo->size);
+ }
+
++ return 0;
++cleanup:
++ ARPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
+ return ret;
+ }
+
+@@ -1204,6 +1203,8 @@ err1:
+ static void __exit arp_tables_fini(void)
+ {
+ nf_unregister_sockopt(&arpt_sockopts);
++ xt_unregister_target(&arpt_error_target);
++ xt_unregister_target(&arpt_standard_target);
+ xt_proto_fini(NF_ARP);
+ }
+
+diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
+index a58325c..d12b1df 100644
+--- a/net/ipv4/netfilter/arpt_mangle.c
++++ b/net/ipv4/netfilter/arpt_mangle.c
+@@ -11,7 +11,7 @@ static unsigned int
+ target(struct sk_buff **pskb,
+ const struct net_device *in, const struct net_device *out,
+ unsigned int hooknum, const struct xt_target *target,
+- const void *targinfo, void *userinfo)
++ const void *targinfo)
+ {
+ const struct arpt_mangle *mangle = targinfo;
+ struct arphdr *arp;
+@@ -67,7 +67,7 @@ target(struct sk_buff **pskb,
+
+ static int
+ checkentry(const char *tablename, const void *e, const struct xt_target *target,
+- void *targinfo, unsigned int targinfosize, unsigned int hook_mask)
++ void *targinfo, unsigned int hook_mask)
+ {
+ const struct arpt_mangle *mangle = targinfo;
+
+diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
+index d7c472f..7edea2a 100644
+--- a/net/ipv4/netfilter/arptable_filter.c
++++ b/net/ipv4/netfilter/arptable_filter.c
+@@ -155,7 +155,7 @@ static unsigned int arpt_hook(unsigned i
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return arpt_do_table(pskb, hook, in, out, &packet_filter, NULL);
++ return arpt_do_table(pskb, hook, in, out, &packet_filter);
+ }
+
+ static struct nf_hook_ops arpt_ops[] = {
+diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
+index 0a7bd7f..6c7383a 100644
+--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
++++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
+@@ -155,11 +155,11 @@ static int help(struct sk_buff **pskb,
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->tuple.dst.u.tcp.port = htons(port);
+
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.protonum = 0xFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+
+ if (ip_nat_amanda_hook)
+ ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff,
+diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
+index aa45917..143c466 100644
+--- a/net/ipv4/netfilter/ip_conntrack_core.c
++++ b/net/ipv4/netfilter/ip_conntrack_core.c
+@@ -47,7 +47,6 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #define IP_CONNTRACK_VERSION "2.4"
+
+@@ -64,17 +63,17 @@ atomic_t ip_conntrack_count = ATOMIC_INI
+
+ void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
+ LIST_HEAD(ip_conntrack_expect_list);
+-struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
++struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO] __read_mostly;
+ static LIST_HEAD(helpers);
+-unsigned int ip_conntrack_htable_size = 0;
+-int ip_conntrack_max;
+-struct list_head *ip_conntrack_hash;
++unsigned int ip_conntrack_htable_size __read_mostly = 0;
++int ip_conntrack_max __read_mostly;
++struct list_head *ip_conntrack_hash __read_mostly;
+ static kmem_cache_t *ip_conntrack_cachep __read_mostly;
+ static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly;
+ struct ip_conntrack ip_conntrack_untracked;
+-unsigned int ip_ct_log_invalid;
++unsigned int ip_ct_log_invalid __read_mostly;
+ static LIST_HEAD(unconfirmed);
+-static int ip_conntrack_vmalloc;
++static int ip_conntrack_vmalloc __read_mostly;
+
+ static unsigned int ip_conntrack_next_id;
+ static unsigned int ip_conntrack_expect_next_id;
+@@ -150,8 +149,8 @@ static unsigned int ip_conntrack_hash_rn
+ static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple,
+ unsigned int size, unsigned int rnd)
+ {
+- return (jhash_3words(tuple->src.ip,
+- (tuple->dst.ip ^ tuple->dst.protonum),
++ return (jhash_3words((__force u32)tuple->src.ip,
++ ((__force u32)tuple->dst.ip ^ tuple->dst.protonum),
+ (tuple->src.u.all | (tuple->dst.u.all << 16)),
+ rnd) % size);
+ }
+@@ -294,15 +293,10 @@ void ip_ct_remove_expectations(struct ip
+ static void
+ clean_from_lists(struct ip_conntrack *ct)
+ {
+- unsigned int ho, hr;
+-
+ DEBUGP("clean_from_lists(%p)\n", ct);
+ ASSERT_WRITE_LOCK(&ip_conntrack_lock);
+-
+- ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+- hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+- LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+- LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
++ list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
++ list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list);
+
+ /* Destroy all pending expectations */
+ ip_ct_remove_expectations(ct);
+@@ -313,6 +307,7 @@ destroy_conntrack(struct nf_conntrack *n
+ {
+ struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
+ struct ip_conntrack_protocol *proto;
++ struct ip_conntrack_helper *helper;
+
+ DEBUGP("destroy_conntrack(%p)\n", ct);
+ IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
+@@ -321,6 +316,10 @@ destroy_conntrack(struct nf_conntrack *n
+ ip_conntrack_event(IPCT_DESTROY, ct);
+ set_bit(IPS_DYING_BIT, &ct->status);
+
++ helper = ct->helper;
++ if (helper && helper->destroy)
++ helper->destroy(ct);
++
+ /* To make sure we don't get any weird locking issues here:
+ * destroy_conntrack() MUST NOT be called with a write lock
+ * to ip_conntrack_lock!!! -HW */
+@@ -367,16 +366,6 @@ static void death_by_timeout(unsigned lo
+ ip_conntrack_put(ct);
+ }
+
+-static inline int
+-conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
+- const struct ip_conntrack_tuple *tuple,
+- const struct ip_conntrack *ignored_conntrack)
+-{
+- ASSERT_READ_LOCK(&ip_conntrack_lock);
+- return tuplehash_to_ctrack(i) != ignored_conntrack
+- && ip_ct_tuple_equal(tuple, &i->tuple);
+-}
+-
+ struct ip_conntrack_tuple_hash *
+ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack *ignored_conntrack)
+@@ -386,7 +375,8 @@ __ip_conntrack_find(const struct ip_conn
+
+ ASSERT_READ_LOCK(&ip_conntrack_lock);
+ list_for_each_entry(h, &ip_conntrack_hash[hash], list) {
+- if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) {
++ if (tuplehash_to_ctrack(h) != ignored_conntrack &&
++ ip_ct_tuple_equal(tuple, &h->tuple)) {
+ CONNTRACK_STAT_INC(found);
+ return h;
+ }
+@@ -417,10 +407,10 @@ static void __ip_conntrack_hash_insert(s
+ unsigned int repl_hash)
+ {
+ ct->id = ++ip_conntrack_next_id;
+- list_prepend(&ip_conntrack_hash[hash],
+- &ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+- list_prepend(&ip_conntrack_hash[repl_hash],
+- &ct->tuplehash[IP_CT_DIR_REPLY].list);
++ list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list,
++ &ip_conntrack_hash[hash]);
++ list_add(&ct->tuplehash[IP_CT_DIR_REPLY].list,
++ &ip_conntrack_hash[repl_hash]);
+ }
+
+ void ip_conntrack_hash_insert(struct ip_conntrack *ct)
+@@ -440,6 +430,7 @@ int
+ __ip_conntrack_confirm(struct sk_buff **pskb)
+ {
+ unsigned int hash, repl_hash;
++ struct ip_conntrack_tuple_hash *h;
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+
+@@ -470,43 +461,43 @@ __ip_conntrack_confirm(struct sk_buff **
+ /* See if there's one in the list already, including reverse:
+ NAT could have grabbed it without realizing, since we're
+ not in the hash. If there is, we lost race. */
+- if (!LIST_FIND(&ip_conntrack_hash[hash],
+- conntrack_tuple_cmp,
+- struct ip_conntrack_tuple_hash *,
+- &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
+- && !LIST_FIND(&ip_conntrack_hash[repl_hash],
+- conntrack_tuple_cmp,
+- struct ip_conntrack_tuple_hash *,
+- &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
+- /* Remove from unconfirmed list */
+- list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
++ list_for_each_entry(h, &ip_conntrack_hash[hash], list)
++ if (ip_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
++ &h->tuple))
++ goto out;
++ list_for_each_entry(h, &ip_conntrack_hash[repl_hash], list)
++ if (ip_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
++ &h->tuple))
++ goto out;
+
+- __ip_conntrack_hash_insert(ct, hash, repl_hash);
+- /* Timer relative to confirmation time, not original
+- setting time, otherwise we'd get timer wrap in
+- weird delay cases. */
+- ct->timeout.expires += jiffies;
+- add_timer(&ct->timeout);
+- atomic_inc(&ct->ct_general.use);
+- set_bit(IPS_CONFIRMED_BIT, &ct->status);
+- CONNTRACK_STAT_INC(insert);
+- write_unlock_bh(&ip_conntrack_lock);
+- if (ct->helper)
+- ip_conntrack_event_cache(IPCT_HELPER, *pskb);
++ /* Remove from unconfirmed list */
++ list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
++
++ __ip_conntrack_hash_insert(ct, hash, repl_hash);
++ /* Timer relative to confirmation time, not original
++ setting time, otherwise we'd get timer wrap in
++ weird delay cases. */
++ ct->timeout.expires += jiffies;
++ add_timer(&ct->timeout);
++ atomic_inc(&ct->ct_general.use);
++ set_bit(IPS_CONFIRMED_BIT, &ct->status);
++ CONNTRACK_STAT_INC(insert);
++ write_unlock_bh(&ip_conntrack_lock);
++ if (ct->helper)
++ ip_conntrack_event_cache(IPCT_HELPER, *pskb);
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+- if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
+- test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
+- ip_conntrack_event_cache(IPCT_NATINFO, *pskb);
++ if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
++ test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
++ ip_conntrack_event_cache(IPCT_NATINFO, *pskb);
+ #endif
+- ip_conntrack_event_cache(master_ct(ct) ?
+- IPCT_RELATED : IPCT_NEW, *pskb);
++ ip_conntrack_event_cache(master_ct(ct) ?
++ IPCT_RELATED : IPCT_NEW, *pskb);
+
+- return NF_ACCEPT;
+- }
++ return NF_ACCEPT;
+
++out:
+ CONNTRACK_STAT_INC(insert_failed);
+ write_unlock_bh(&ip_conntrack_lock);
+-
+ return NF_DROP;
+ }
+
+@@ -527,23 +518,21 @@ ip_conntrack_tuple_taken(const struct ip
+
+ /* There's a small race here where we may free a just-assured
+ connection. Too bad: we're in trouble anyway. */
+-static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
+-{
+- return !(test_bit(IPS_ASSURED_BIT, &tuplehash_to_ctrack(i)->status));
+-}
+-
+ static int early_drop(struct list_head *chain)
+ {
+ /* Traverse backwards: gives us oldest, which is roughly LRU */
+ struct ip_conntrack_tuple_hash *h;
+- struct ip_conntrack *ct = NULL;
++ struct ip_conntrack *ct = NULL, *tmp;
+ int dropped = 0;
+
+ read_lock_bh(&ip_conntrack_lock);
+- h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
+- if (h) {
+- ct = tuplehash_to_ctrack(h);
+- atomic_inc(&ct->ct_general.use);
++ list_for_each_entry_reverse(h, chain, list) {
++ tmp = tuplehash_to_ctrack(h);
++ if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) {
++ ct = tmp;
++ atomic_inc(&ct->ct_general.use);
++ break;
++ }
+ }
+ read_unlock_bh(&ip_conntrack_lock);
+
+@@ -559,18 +548,16 @@ static int early_drop(struct list_head *
+ return dropped;
+ }
+
+-static inline int helper_cmp(const struct ip_conntrack_helper *i,
+- const struct ip_conntrack_tuple *rtuple)
+-{
+- return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
+-}
+-
+ static struct ip_conntrack_helper *
+ __ip_conntrack_helper_find( const struct ip_conntrack_tuple *tuple)
+ {
+- return LIST_FIND(&helpers, helper_cmp,
+- struct ip_conntrack_helper *,
+- tuple);
++ struct ip_conntrack_helper *h;
++
++ list_for_each_entry(h, &helpers, list) {
++ if (ip_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask))
++ return h;
++ }
++ return NULL;
+ }
+
+ struct ip_conntrack_helper *
+@@ -640,11 +627,15 @@ struct ip_conntrack *ip_conntrack_alloc(
+ ip_conntrack_hash_rnd_initted = 1;
+ }
+
++ /* We don't want any race condition at early drop stage */
++ atomic_inc(&ip_conntrack_count);
++
+ if (ip_conntrack_max
+- && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
++ && atomic_read(&ip_conntrack_count) > ip_conntrack_max) {
+ unsigned int hash = hash_conntrack(orig);
+ /* Try dropping from this hash chain. */
+ if (!early_drop(&ip_conntrack_hash[hash])) {
++ atomic_dec(&ip_conntrack_count);
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "ip_conntrack: table full, dropping"
+@@ -656,6 +647,7 @@ struct ip_conntrack *ip_conntrack_alloc(
+ conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
+ if (!conntrack) {
+ DEBUGP("Can't allocate conntrack.\n");
++ atomic_dec(&ip_conntrack_count);
+ return ERR_PTR(-ENOMEM);
+ }
+
+@@ -669,8 +661,6 @@ struct ip_conntrack *ip_conntrack_alloc(
+ conntrack->timeout.data = (unsigned long)conntrack;
+ conntrack->timeout.function = death_by_timeout;
+
+- atomic_inc(&ip_conntrack_count);
+-
+ return conntrack;
+ }
+
+@@ -1062,7 +1052,7 @@ int ip_conntrack_helper_register(struct
+ {
+ BUG_ON(me->timeout == 0);
+ write_lock_bh(&ip_conntrack_lock);
+- list_prepend(&helpers, me);
++ list_add(&me->list, &helpers);
+ write_unlock_bh(&ip_conntrack_lock);
+
+ return 0;
+@@ -1081,24 +1071,24 @@ __ip_conntrack_helper_find_byname(const
+ return NULL;
+ }
+
+-static inline int unhelp(struct ip_conntrack_tuple_hash *i,
+- const struct ip_conntrack_helper *me)
++static inline void unhelp(struct ip_conntrack_tuple_hash *i,
++ const struct ip_conntrack_helper *me)
+ {
+ if (tuplehash_to_ctrack(i)->helper == me) {
+ ip_conntrack_event(IPCT_HELPER, tuplehash_to_ctrack(i));
+ tuplehash_to_ctrack(i)->helper = NULL;
+ }
+- return 0;
+ }
+
+ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
+ {
+ unsigned int i;
++ struct ip_conntrack_tuple_hash *h;
+ struct ip_conntrack_expect *exp, *tmp;
+
+ /* Need write lock here, to delete helper. */
+ write_lock_bh(&ip_conntrack_lock);
+- LIST_DELETE(&helpers, me);
++ list_del(&me->list);
+
+ /* Get rid of expectations */
+ list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
+@@ -1108,10 +1098,12 @@ void ip_conntrack_helper_unregister(stru
+ }
+ }
+ /* Get rid of expecteds, set helpers to NULL. */
+- LIST_FIND_W(&unconfirmed, unhelp, struct ip_conntrack_tuple_hash*, me);
+- for (i = 0; i < ip_conntrack_htable_size; i++)
+- LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
+- struct ip_conntrack_tuple_hash *, me);
++ list_for_each_entry(h, &unconfirmed, list)
++ unhelp(h, me);
++ for (i = 0; i < ip_conntrack_htable_size; i++) {
++ list_for_each_entry(h, &ip_conntrack_hash[i], list)
++ unhelp(h, me);
++ }
+ write_unlock_bh(&ip_conntrack_lock);
+
+ /* Someone could be still looking at the helper in a bh. */
+@@ -1177,9 +1169,9 @@ void __ip_ct_refresh_acct(struct ip_conn
+ int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb,
+ const struct ip_conntrack_tuple *tuple)
+ {
+- NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t),
++ NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(__be16),
+ &tuple->src.u.tcp.port);
+- NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t),
++ NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(__be16),
+ &tuple->dst.u.tcp.port);
+ return 0;
+
+@@ -1194,9 +1186,9 @@ int ip_ct_port_nfattr_to_tuple(struct nf
+ return -EINVAL;
+
+ t->src.u.tcp.port =
+- *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
++ *(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
+ t->dst.u.tcp.port =
+- *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
++ *(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
+
+ return 0;
+ }
+@@ -1237,46 +1229,43 @@ static void ip_conntrack_attach(struct s
+ nf_conntrack_get(nskb->nfct);
+ }
+
+-static inline int
+-do_iter(const struct ip_conntrack_tuple_hash *i,
+- int (*iter)(struct ip_conntrack *i, void *data),
+- void *data)
+-{
+- return iter(tuplehash_to_ctrack(i), data);
+-}
+-
+ /* Bring out ya dead! */
+-static struct ip_conntrack_tuple_hash *
++static struct ip_conntrack *
+ get_next_corpse(int (*iter)(struct ip_conntrack *i, void *data),
+ void *data, unsigned int *bucket)
+ {
+- struct ip_conntrack_tuple_hash *h = NULL;
++ struct ip_conntrack_tuple_hash *h;
++ struct ip_conntrack *ct;
+
+ write_lock_bh(&ip_conntrack_lock);
+ for (; *bucket < ip_conntrack_htable_size; (*bucket)++) {
+- h = LIST_FIND_W(&ip_conntrack_hash[*bucket], do_iter,
+- struct ip_conntrack_tuple_hash *, iter, data);
+- if (h)
+- break;
++ list_for_each_entry(h, &ip_conntrack_hash[*bucket], list) {
++ ct = tuplehash_to_ctrack(h);
++ if (iter(ct, data))
++ goto found;
++ }
++ }
++ list_for_each_entry(h, &unconfirmed, list) {
++ ct = tuplehash_to_ctrack(h);
++ if (iter(ct, data))
++ goto found;
+ }
+- if (!h)
+- h = LIST_FIND_W(&unconfirmed, do_iter,
+- struct ip_conntrack_tuple_hash *, iter, data);
+- if (h)
+- atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use);
+ write_unlock_bh(&ip_conntrack_lock);
++ return NULL;
+
+- return h;
++found:
++ atomic_inc(&ct->ct_general.use);
++ write_unlock_bh(&ip_conntrack_lock);
++ return ct;
+ }
+
+ void
+ ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *), void *data)
+ {
+- struct ip_conntrack_tuple_hash *h;
++ struct ip_conntrack *ct;
+ unsigned int bucket = 0;
+
+- while ((h = get_next_corpse(iter, data, &bucket)) != NULL) {
+- struct ip_conntrack *ct = tuplehash_to_ctrack(h);
++ while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) {
+ /* Time to push up daises... */
+ if (del_timer(&ct->timeout))
+ death_by_timeout((unsigned long)ct);
+diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
+index 1d18c86..93dcf96 100644
+--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
++++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
+@@ -425,8 +425,8 @@ static int help(struct sk_buff **pskb,
+ exp->tuple.src.u.tcp.port = 0; /* Don't care. */
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask = ((struct ip_conntrack_tuple)
+- { { 0xFFFFFFFF, { 0 } },
+- { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
++ { { htonl(0xFFFFFFFF), { 0 } },
++ { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }});
+
+ exp->expectfn = NULL;
+ exp->flags = 0;
+@@ -488,7 +488,7 @@ static int __init ip_conntrack_ftp_init(
+ for (i = 0; i < ports_c; i++) {
+ ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+ ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+- ftp[i].mask.src.u.tcp.port = 0xFFFF;
++ ftp[i].mask.src.u.tcp.port = htons(0xFFFF);
+ ftp[i].mask.dst.protonum = 0xFF;
+ ftp[i].max_expected = 1;
+ ftp[i].timeout = 5 * 60; /* 5 minutes */
+diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+index 9a39e29..7b74412 100644
+--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
++++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+@@ -49,11 +49,11 @@ MODULE_PARM_DESC(callforward_filter, "on
+ int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+- u_int32_t ip, u_int16_t port);
++ __be32 ip, u_int16_t port);
+ int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr,
+- u_int32_t ip, u_int16_t port);
++ __be32 ip, u_int16_t port);
+ int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+@@ -209,7 +209,7 @@ static int get_tpkt_data(struct sk_buff
+
+ /****************************************************************************/
+ static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
+- u_int32_t * ip, u_int16_t * port)
++ __be32 * ip, u_int16_t * port)
+ {
+ unsigned char *p;
+
+@@ -232,7 +232,7 @@ static int expect_rtp_rtcp(struct sk_buf
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ u_int16_t rtp_port;
+ struct ip_conntrack_expect *rtp_exp;
+@@ -254,10 +254,10 @@ static int expect_rtp_rtcp(struct sk_buf
+ rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ rtp_exp->tuple.dst.u.udp.port = htons(rtp_port);
+ rtp_exp->tuple.dst.protonum = IPPROTO_UDP;
+- rtp_exp->mask.src.ip = 0xFFFFFFFF;
++ rtp_exp->mask.src.ip = htonl(0xFFFFFFFF);
+ rtp_exp->mask.src.u.udp.port = 0;
+- rtp_exp->mask.dst.ip = 0xFFFFFFFF;
+- rtp_exp->mask.dst.u.udp.port = 0xFFFF;
++ rtp_exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ rtp_exp->mask.dst.u.udp.port = htons(0xFFFF);
+ rtp_exp->mask.dst.protonum = 0xFF;
+ rtp_exp->flags = 0;
+
+@@ -271,10 +271,10 @@ static int expect_rtp_rtcp(struct sk_buf
+ rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1);
+ rtcp_exp->tuple.dst.protonum = IPPROTO_UDP;
+- rtcp_exp->mask.src.ip = 0xFFFFFFFF;
++ rtcp_exp->mask.src.ip = htonl(0xFFFFFFFF);
+ rtcp_exp->mask.src.u.udp.port = 0;
+- rtcp_exp->mask.dst.ip = 0xFFFFFFFF;
+- rtcp_exp->mask.dst.u.udp.port = 0xFFFF;
++ rtcp_exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ rtcp_exp->mask.dst.u.udp.port = htons(0xFFFF);
+ rtcp_exp->mask.dst.protonum = 0xFF;
+ rtcp_exp->flags = 0;
+
+@@ -325,7 +325,7 @@ static int expect_t120(struct sk_buff **
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+@@ -342,10 +342,10 @@ static int expect_t120(struct sk_buff **
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */
+
+@@ -626,7 +626,7 @@ void ip_conntrack_h245_expect(struct ip_
+
+ /****************************************************************************/
+ int get_h225_addr(unsigned char *data, TransportAddress * addr,
+- u_int32_t * ip, u_int16_t * port)
++ __be32 * ip, u_int16_t * port)
+ {
+ unsigned char *p;
+
+@@ -648,7 +648,7 @@ static int expect_h245(struct sk_buff **
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+@@ -665,10 +665,10 @@ static int expect_h245(struct sk_buff **
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = 0;
+
+@@ -709,7 +709,7 @@ static int expect_callforwarding(struct
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+@@ -751,10 +751,10 @@ static int expect_callforwarding(struct
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = 0;
+
+@@ -791,7 +791,7 @@ static int process_setup(struct sk_buff
+ int dir = CTINFO2DIR(ctinfo);
+ int ret;
+ int i;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+
+ DEBUGP("ip_ct_q931: Setup\n");
+@@ -1188,7 +1188,7 @@ static unsigned char *get_udp_data(struc
+
+ /****************************************************************************/
+ static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
+- u_int32_t ip, u_int16_t port)
++ __be32 ip, u_int16_t port)
+ {
+ struct ip_conntrack_expect *exp;
+ struct ip_conntrack_tuple tuple;
+@@ -1228,7 +1228,7 @@ static int expect_q931(struct sk_buff **
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ int i;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp;
+
+@@ -1251,10 +1251,10 @@ static int expect_q931(struct sk_buff **
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+- exp->mask.src.ip = gkrouted_only ? 0xFFFFFFFF : 0;
++ exp->mask.src.ip = gkrouted_only ? htonl(0xFFFFFFFF) : 0;
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */
+
+@@ -1307,7 +1307,7 @@ static int process_gcf(struct sk_buff **
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp;
+
+@@ -1333,10 +1333,10 @@ static int process_gcf(struct sk_buff **
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_UDP;
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = 0;
+ exp->expectfn = ip_conntrack_ras_expect;
+@@ -1477,7 +1477,7 @@ static int process_arq(struct sk_buff **
+ {
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+
+ DEBUGP("ip_ct_ras: ARQ\n");
+@@ -1513,7 +1513,7 @@ static int process_acf(struct sk_buff **
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp;
+
+@@ -1538,10 +1538,10 @@ static int process_acf(struct sk_buff **
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = IP_CT_EXPECT_PERMANENT;
+ exp->expectfn = ip_conntrack_q931_expect;
+@@ -1581,7 +1581,7 @@ static int process_lcf(struct sk_buff **
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+@@ -1598,10 +1598,10 @@ static int process_lcf(struct sk_buff **
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.tcp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.tcp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.tcp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = IP_CT_EXPECT_PERMANENT;
+ exp->expectfn = ip_conntrack_q931_expect;
+diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
+index b020a33..a2af5e0 100644
+--- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
++++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
+@@ -20,11 +20,11 @@
+ * - We can only support one single call within each session
+ *
+ * TODO:
+- * - testing of incoming PPTP calls
++ * - testing of incoming PPTP calls
+ *
+- * Changes:
++ * Changes:
+ * 2002-02-05 - Version 1.3
+- * - Call ip_conntrack_unexpect_related() from
++ * - Call ip_conntrack_unexpect_related() from
+ * pptp_destroy_siblings() to destroy expectations in case
+ * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
+ * (Philip Craig <philipc at snapgear.com>)
+@@ -80,7 +80,7 @@ int
+ struct PptpControlHeader *ctlh,
+ union pptp_ctrl_union *pptpReq);
+
+-int
++void
+ (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig,
+ struct ip_conntrack_expect *expect_reply);
+
+@@ -141,7 +141,7 @@ static void pptp_expectfn(struct ip_conn
+ invert_tuplepr(&inv_t, &exp->tuple);
+ DEBUGP("trying to unexpect other dir: ");
+ DUMP_TUPLE(&inv_t);
+-
++
+ exp_other = ip_conntrack_expect_find(&inv_t);
+ if (exp_other) {
+ /* delete other expectation. */
+@@ -194,15 +194,16 @@ static void pptp_destroy_siblings(struct
+ {
+ struct ip_conntrack_tuple t;
+
+- /* Since ct->sibling_list has literally rusted away in 2.6.11,
++ ip_ct_gre_keymap_destroy(ct);
++ /* Since ct->sibling_list has literally rusted away in 2.6.11,
+ * we now need another way to find out about our sibling
+ * contrack and expects... -HW */
+
+ /* try original (pns->pac) tuple */
+ memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t));
+ t.dst.protonum = IPPROTO_GRE;
+- t.src.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id);
+- t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id);
++ t.src.u.gre.key = ct->help.ct_pptp_info.pns_call_id;
++ t.dst.u.gre.key = ct->help.ct_pptp_info.pac_call_id;
+
+ if (!destroy_sibling_or_exp(&t))
+ DEBUGP("failed to timeout original pns->pac ct/exp\n");
+@@ -210,8 +211,8 @@ static void pptp_destroy_siblings(struct
+ /* try reply (pac->pns) tuple */
+ memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
+ t.dst.protonum = IPPROTO_GRE;
+- t.src.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id);
+- t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id);
++ t.src.u.gre.key = ct->help.ct_pptp_info.pac_call_id;
++ t.dst.u.gre.key = ct->help.ct_pptp_info.pns_call_id;
+
+ if (!destroy_sibling_or_exp(&t))
+ DEBUGP("failed to timeout reply pac->pns ct/exp\n");
+@@ -219,94 +220,63 @@ static void pptp_destroy_siblings(struct
+
+ /* expect GRE connections (PNS->PAC and PAC->PNS direction) */
+ static inline int
+-exp_gre(struct ip_conntrack *master,
+- u_int32_t seq,
++exp_gre(struct ip_conntrack *ct,
+ __be16 callid,
+ __be16 peer_callid)
+ {
+- struct ip_conntrack_tuple inv_tuple;
+- struct ip_conntrack_tuple exp_tuples[] = {
+- /* tuple in original direction, PNS->PAC */
+- { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
+- .u = { .gre = { .key = peer_callid } }
+- },
+- .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
+- .u = { .gre = { .key = callid } },
+- .protonum = IPPROTO_GRE
+- },
+- },
+- /* tuple in reply direction, PAC->PNS */
+- { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
+- .u = { .gre = { .key = callid } }
+- },
+- .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
+- .u = { .gre = { .key = peer_callid } },
+- .protonum = IPPROTO_GRE
+- },
+- }
+- };
+ struct ip_conntrack_expect *exp_orig, *exp_reply;
+ int ret = 1;
+
+- exp_orig = ip_conntrack_expect_alloc(master);
++ exp_orig = ip_conntrack_expect_alloc(ct);
+ if (exp_orig == NULL)
+ goto out;
+
+- exp_reply = ip_conntrack_expect_alloc(master);
++ exp_reply = ip_conntrack_expect_alloc(ct);
+ if (exp_reply == NULL)
+ goto out_put_orig;
+
+- memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple));
++ /* original direction, PNS->PAC */
++ exp_orig->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ exp_orig->tuple.src.u.gre.key = peer_callid;
++ exp_orig->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ exp_orig->tuple.dst.u.gre.key = callid;
++ exp_orig->tuple.dst.protonum = IPPROTO_GRE;
+
+- exp_orig->mask.src.ip = 0xffffffff;
++ exp_orig->mask.src.ip = htonl(0xffffffff);
+ exp_orig->mask.src.u.all = 0;
+- exp_orig->mask.dst.u.all = 0;
+ exp_orig->mask.dst.u.gre.key = htons(0xffff);
+- exp_orig->mask.dst.ip = 0xffffffff;
++ exp_orig->mask.dst.ip = htonl(0xffffffff);
+ exp_orig->mask.dst.protonum = 0xff;
+-
+- exp_orig->master = master;
++
++ exp_orig->master = ct;
+ exp_orig->expectfn = pptp_expectfn;
+ exp_orig->flags = 0;
+
+ /* both expectations are identical apart from tuple */
+ memcpy(exp_reply, exp_orig, sizeof(*exp_reply));
+- memcpy(&exp_reply->tuple, &exp_tuples[1], sizeof(exp_reply->tuple));
+
+- if (ip_nat_pptp_hook_exp_gre)
+- ret = ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply);
+- else {
+-
+- DEBUGP("calling expect_related PNS->PAC");
+- DUMP_TUPLE(&exp_orig->tuple);
+-
+- if (ip_conntrack_expect_related(exp_orig) != 0) {
+- DEBUGP("cannot expect_related()\n");
+- goto out_put_both;
+- }
++ /* reply direction, PAC->PNS */
++ exp_reply->tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ exp_reply->tuple.src.u.gre.key = callid;
++ exp_reply->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ exp_reply->tuple.dst.u.gre.key = peer_callid;
++ exp_reply->tuple.dst.protonum = IPPROTO_GRE;
+
+- DEBUGP("calling expect_related PAC->PNS");
+- DUMP_TUPLE(&exp_reply->tuple);
+-
+- if (ip_conntrack_expect_related(exp_reply) != 0) {
+- DEBUGP("cannot expect_related()\n");
+- goto out_unexpect_orig;
+- }
+-
+- /* Add GRE keymap entries */
+- if (ip_ct_gre_keymap_add(master, &exp_reply->tuple, 0) != 0) {
+- DEBUGP("cannot keymap_add() exp\n");
+- goto out_unexpect_both;
+- }
+-
+- invert_tuplepr(&inv_tuple, &exp_reply->tuple);
+- if (ip_ct_gre_keymap_add(master, &inv_tuple, 1) != 0) {
+- ip_ct_gre_keymap_destroy(master);
+- DEBUGP("cannot keymap_add() exp_inv\n");
+- goto out_unexpect_both;
+- }
+- ret = 0;
++ if (ip_nat_pptp_hook_exp_gre)
++ ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply);
++ if (ip_conntrack_expect_related(exp_orig) != 0)
++ goto out_put_both;
++ if (ip_conntrack_expect_related(exp_reply) != 0)
++ goto out_unexpect_orig;
++
++ /* Add GRE keymap entries */
++ if (ip_ct_gre_keymap_add(ct, &exp_orig->tuple, 0) != 0)
++ goto out_unexpect_both;
++ if (ip_ct_gre_keymap_add(ct, &exp_reply->tuple, 1) != 0) {
++ ip_ct_gre_keymap_destroy(ct);
++ goto out_unexpect_both;
+ }
++ ret = 0;
+
+ out_put_both:
+ ip_conntrack_expect_put(exp_reply);
+@@ -322,73 +292,36 @@ out_unexpect_orig:
+ goto out_put_both;
+ }
+
+-static inline int
++static inline int
+ pptp_inbound_pkt(struct sk_buff **pskb,
+- struct tcphdr *tcph,
+- unsigned int nexthdr_off,
+- unsigned int datalen,
++ struct PptpControlHeader *ctlh,
++ union pptp_ctrl_union *pptpReq,
++ unsigned int reqlen,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+ {
+- struct PptpControlHeader _ctlh, *ctlh;
+- unsigned int reqlen;
+- union pptp_ctrl_union _pptpReq, *pptpReq;
+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+ u_int16_t msg;
+- __be16 *cid, *pcid;
+- u_int32_t seq;
+-
+- ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh);
+- if (!ctlh) {
+- DEBUGP("error during skb_header_pointer\n");
+- return NF_ACCEPT;
+- }
+- nexthdr_off += sizeof(_ctlh);
+- datalen -= sizeof(_ctlh);
+-
+- reqlen = datalen;
+- if (reqlen > sizeof(*pptpReq))
+- reqlen = sizeof(*pptpReq);
+- pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq);
+- if (!pptpReq) {
+- DEBUGP("error during skb_header_pointer\n");
+- return NF_ACCEPT;
+- }
++ __be16 cid = 0, pcid = 0;
+
+ msg = ntohs(ctlh->messageType);
+ DEBUGP("inbound control message %s\n", pptp_msg_name[msg]);
+
+ switch (msg) {
+ case PPTP_START_SESSION_REPLY:
+- if (reqlen < sizeof(_pptpReq.srep)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* server confirms new control session */
+- if (info->sstate < PPTP_SESSION_REQUESTED) {
+- DEBUGP("%s without START_SESS_REQUEST\n",
+- pptp_msg_name[msg]);
+- break;
+- }
++ if (info->sstate < PPTP_SESSION_REQUESTED)
++ goto invalid;
+ if (pptpReq->srep.resultCode == PPTP_START_OK)
+ info->sstate = PPTP_SESSION_CONFIRMED;
+- else
++ else
+ info->sstate = PPTP_SESSION_ERROR;
+ break;
+
+ case PPTP_STOP_SESSION_REPLY:
+- if (reqlen < sizeof(_pptpReq.strep)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* server confirms end of control session */
+- if (info->sstate > PPTP_SESSION_STOPREQ) {
+- DEBUGP("%s without STOP_SESS_REQUEST\n",
+- pptp_msg_name[msg]);
+- break;
+- }
++ if (info->sstate > PPTP_SESSION_STOPREQ)
++ goto invalid;
+ if (pptpReq->strep.resultCode == PPTP_STOP_OK)
+ info->sstate = PPTP_SESSION_NONE;
+ else
+@@ -396,116 +329,64 @@ pptp_inbound_pkt(struct sk_buff **pskb,
+ break;
+
+ case PPTP_OUT_CALL_REPLY:
+- if (reqlen < sizeof(_pptpReq.ocack)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* server accepted call, we now expect GRE frames */
+- if (info->sstate != PPTP_SESSION_CONFIRMED) {
+- DEBUGP("%s but no session\n", pptp_msg_name[msg]);
+- break;
+- }
++ if (info->sstate != PPTP_SESSION_CONFIRMED)
++ goto invalid;
+ if (info->cstate != PPTP_CALL_OUT_REQ &&
+- info->cstate != PPTP_CALL_OUT_CONF) {
+- DEBUGP("%s without OUTCALL_REQ\n", pptp_msg_name[msg]);
+- break;
+- }
+- if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) {
++ info->cstate != PPTP_CALL_OUT_CONF)
++ goto invalid;
++
++ cid = pptpReq->ocack.callID;
++ pcid = pptpReq->ocack.peersCallID;
++ if (info->pns_call_id != pcid)
++ goto invalid;
++ DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg],
++ ntohs(cid), ntohs(pcid));
++
++ if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) {
++ info->cstate = PPTP_CALL_OUT_CONF;
++ info->pac_call_id = cid;
++ exp_gre(ct, cid, pcid);
++ } else
+ info->cstate = PPTP_CALL_NONE;
+- break;
+- }
+-
+- cid = &pptpReq->ocack.callID;
+- pcid = &pptpReq->ocack.peersCallID;
+-
+- info->pac_call_id = ntohs(*cid);
+-
+- if (htons(info->pns_call_id) != *pcid) {
+- DEBUGP("%s for unknown callid %u\n",
+- pptp_msg_name[msg], ntohs(*pcid));
+- break;
+- }
+-
+- DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg],
+- ntohs(*cid), ntohs(*pcid));
+-
+- info->cstate = PPTP_CALL_OUT_CONF;
+-
+- seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
+- + sizeof(struct PptpControlHeader)
+- + ((void *)pcid - (void *)pptpReq);
+-
+- if (exp_gre(ct, seq, *cid, *pcid) != 0)
+- printk("ip_conntrack_pptp: error during exp_gre\n");
+ break;
+
+ case PPTP_IN_CALL_REQUEST:
+- if (reqlen < sizeof(_pptpReq.icack)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* server tells us about incoming call request */
+- if (info->sstate != PPTP_SESSION_CONFIRMED) {
+- DEBUGP("%s but no session\n", pptp_msg_name[msg]);
+- break;
+- }
+- pcid = &pptpReq->icack.peersCallID;
+- DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid));
++ if (info->sstate != PPTP_SESSION_CONFIRMED)
++ goto invalid;
++
++ cid = pptpReq->icreq.callID;
++ DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
+ info->cstate = PPTP_CALL_IN_REQ;
+- info->pac_call_id = ntohs(*pcid);
++ info->pac_call_id = cid;
+ break;
+
+ case PPTP_IN_CALL_CONNECT:
+- if (reqlen < sizeof(_pptpReq.iccon)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* server tells us about incoming call established */
+- if (info->sstate != PPTP_SESSION_CONFIRMED) {
+- DEBUGP("%s but no session\n", pptp_msg_name[msg]);
+- break;
+- }
+- if (info->cstate != PPTP_CALL_IN_REP
+- && info->cstate != PPTP_CALL_IN_CONF) {
+- DEBUGP("%s but never sent IN_CALL_REPLY\n",
+- pptp_msg_name[msg]);
+- break;
+- }
++ if (info->sstate != PPTP_SESSION_CONFIRMED)
++ goto invalid;
++ if (info->cstate != PPTP_CALL_IN_REP &&
++ info->cstate != PPTP_CALL_IN_CONF)
++ goto invalid;
+
+- pcid = &pptpReq->iccon.peersCallID;
+- cid = &info->pac_call_id;
++ pcid = pptpReq->iccon.peersCallID;
++ cid = info->pac_call_id;
+
+- if (info->pns_call_id != ntohs(*pcid)) {
+- DEBUGP("%s for unknown CallID %u\n",
+- pptp_msg_name[msg], ntohs(*pcid));
+- break;
+- }
++ if (info->pns_call_id != pcid)
++ goto invalid;
+
+- DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid));
++ DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid));
+ info->cstate = PPTP_CALL_IN_CONF;
+
+ /* we expect a GRE connection from PAC to PNS */
+- seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
+- + sizeof(struct PptpControlHeader)
+- + ((void *)pcid - (void *)pptpReq);
+-
+- if (exp_gre(ct, seq, *cid, *pcid) != 0)
+- printk("ip_conntrack_pptp: error during exp_gre\n");
+-
++ exp_gre(ct, cid, pcid);
+ break;
+
+ case PPTP_CALL_DISCONNECT_NOTIFY:
+- if (reqlen < sizeof(_pptpReq.disc)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* server confirms disconnect */
+- cid = &pptpReq->disc.callID;
+- DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid));
++ cid = pptpReq->disc.callID;
++ DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
+ info->cstate = PPTP_CALL_NONE;
+
+ /* untrack this call id, unexpect GRE packets */
+@@ -513,54 +394,39 @@ pptp_inbound_pkt(struct sk_buff **pskb,
+ break;
+
+ case PPTP_WAN_ERROR_NOTIFY:
+- break;
+-
+ case PPTP_ECHO_REQUEST:
+ case PPTP_ECHO_REPLY:
+ /* I don't have to explain these ;) */
+ break;
+ default:
+- DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
+- ? pptp_msg_name[msg]:pptp_msg_name[0], msg);
+- break;
++ goto invalid;
+ }
+
+-
+ if (ip_nat_pptp_hook_inbound)
+ return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh,
+ pptpReq);
+-
+ return NF_ACCEPT;
+
++invalid:
++ DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
++ "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
++ msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
++ msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
++ ntohs(info->pns_call_id), ntohs(info->pac_call_id));
++ return NF_ACCEPT;
+ }
+
+ static inline int
+ pptp_outbound_pkt(struct sk_buff **pskb,
+- struct tcphdr *tcph,
+- unsigned int nexthdr_off,
+- unsigned int datalen,
++ struct PptpControlHeader *ctlh,
++ union pptp_ctrl_union *pptpReq,
++ unsigned int reqlen,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+ {
+- struct PptpControlHeader _ctlh, *ctlh;
+- unsigned int reqlen;
+- union pptp_ctrl_union _pptpReq, *pptpReq;
+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+ u_int16_t msg;
+- __be16 *cid, *pcid;
+-
+- ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh);
+- if (!ctlh)
+- return NF_ACCEPT;
+- nexthdr_off += sizeof(_ctlh);
+- datalen -= sizeof(_ctlh);
+-
+- reqlen = datalen;
+- if (reqlen > sizeof(*pptpReq))
+- reqlen = sizeof(*pptpReq);
+- pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq);
+- if (!pptpReq)
+- return NF_ACCEPT;
++ __be16 cid = 0, pcid = 0;
+
+ msg = ntohs(ctlh->messageType);
+ DEBUGP("outbound control message %s\n", pptp_msg_name[msg]);
+@@ -568,10 +434,8 @@ pptp_outbound_pkt(struct sk_buff **pskb,
+ switch (msg) {
+ case PPTP_START_SESSION_REQUEST:
+ /* client requests for new control session */
+- if (info->sstate != PPTP_SESSION_NONE) {
+- DEBUGP("%s but we already have one",
+- pptp_msg_name[msg]);
+- }
++ if (info->sstate != PPTP_SESSION_NONE)
++ goto invalid;
+ info->sstate = PPTP_SESSION_REQUESTED;
+ break;
+ case PPTP_STOP_SESSION_REQUEST:
+@@ -580,123 +444,115 @@ pptp_outbound_pkt(struct sk_buff **pskb,
+ break;
+
+ case PPTP_OUT_CALL_REQUEST:
+- if (reqlen < sizeof(_pptpReq.ocreq)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- /* FIXME: break; */
+- }
+-
+ /* client initiating connection to server */
+- if (info->sstate != PPTP_SESSION_CONFIRMED) {
+- DEBUGP("%s but no session\n",
+- pptp_msg_name[msg]);
+- break;
+- }
++ if (info->sstate != PPTP_SESSION_CONFIRMED)
++ goto invalid;
+ info->cstate = PPTP_CALL_OUT_REQ;
+ /* track PNS call id */
+- cid = &pptpReq->ocreq.callID;
+- DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid));
+- info->pns_call_id = ntohs(*cid);
++ cid = pptpReq->ocreq.callID;
++ DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
++ info->pns_call_id = cid;
+ break;
+ case PPTP_IN_CALL_REPLY:
+- if (reqlen < sizeof(_pptpReq.icack)) {
+- DEBUGP("%s: short packet\n", pptp_msg_name[msg]);
+- break;
+- }
+-
+ /* client answers incoming call */
+- if (info->cstate != PPTP_CALL_IN_REQ
+- && info->cstate != PPTP_CALL_IN_REP) {
+- DEBUGP("%s without incall_req\n",
+- pptp_msg_name[msg]);
+- break;
+- }
+- if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) {
++ if (info->cstate != PPTP_CALL_IN_REQ &&
++ info->cstate != PPTP_CALL_IN_REP)
++ goto invalid;
++
++ cid = pptpReq->icack.callID;
++ pcid = pptpReq->icack.peersCallID;
++ if (info->pac_call_id != pcid)
++ goto invalid;
++ DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg],
++ ntohs(cid), ntohs(pcid));
++
++ if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) {
++ /* part two of the three-way handshake */
++ info->cstate = PPTP_CALL_IN_REP;
++ info->pns_call_id = cid;
++ } else
+ info->cstate = PPTP_CALL_NONE;
+- break;
+- }
+- pcid = &pptpReq->icack.peersCallID;
+- if (info->pac_call_id != ntohs(*pcid)) {
+- DEBUGP("%s for unknown call %u\n",
+- pptp_msg_name[msg], ntohs(*pcid));
+- break;
+- }
+- DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*pcid));
+- /* part two of the three-way handshake */
+- info->cstate = PPTP_CALL_IN_REP;
+- info->pns_call_id = ntohs(pptpReq->icack.callID);
+ break;
+
+ case PPTP_CALL_CLEAR_REQUEST:
+ /* client requests hangup of call */
+- if (info->sstate != PPTP_SESSION_CONFIRMED) {
+- DEBUGP("CLEAR_CALL but no session\n");
+- break;
+- }
++ if (info->sstate != PPTP_SESSION_CONFIRMED)
++ goto invalid;
+ /* FUTURE: iterate over all calls and check if
+ * call ID is valid. We don't do this without newnat,
+ * because we only know about last call */
+ info->cstate = PPTP_CALL_CLEAR_REQ;
+ break;
+ case PPTP_SET_LINK_INFO:
+- break;
+ case PPTP_ECHO_REQUEST:
+ case PPTP_ECHO_REPLY:
+ /* I don't have to explain these ;) */
+ break;
+ default:
+- DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
+- pptp_msg_name[msg]:pptp_msg_name[0], msg);
+- /* unknown: no need to create GRE masq table entry */
+- break;
++ goto invalid;
+ }
+-
++
+ if (ip_nat_pptp_hook_outbound)
+ return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh,
+ pptpReq);
++ return NF_ACCEPT;
+
++invalid:
++ DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
++ "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
++ msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
++ msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
++ ntohs(info->pns_call_id), ntohs(info->pac_call_id));
+ return NF_ACCEPT;
+ }
+
++static const unsigned int pptp_msg_size[] = {
++ [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest),
++ [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply),
++ [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest),
++ [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply),
++ [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest),
++ [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply),
++ [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest),
++ [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply),
++ [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected),
++ [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest),
++ [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify),
++ [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify),
++ [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo),
++};
+
+ /* track caller id inside control connection, call expect_related */
+-static int
++static int
+ conntrack_pptp_help(struct sk_buff **pskb,
+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+
+ {
+- struct pptp_pkt_hdr _pptph, *pptph;
+- struct tcphdr _tcph, *tcph;
+- u_int32_t tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
+- u_int32_t datalen;
+ int dir = CTINFO2DIR(ctinfo);
+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+- unsigned int nexthdr_off;
+-
++ struct tcphdr _tcph, *tcph;
++ struct pptp_pkt_hdr _pptph, *pptph;
++ struct PptpControlHeader _ctlh, *ctlh;
++ union pptp_ctrl_union _pptpReq, *pptpReq;
++ unsigned int tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
++ unsigned int datalen, reqlen, nexthdr_off;
+ int oldsstate, oldcstate;
+ int ret;
++ u_int16_t msg;
+
+ /* don't do any tracking before tcp handshake complete */
+- if (ctinfo != IP_CT_ESTABLISHED
++ if (ctinfo != IP_CT_ESTABLISHED
+ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
+ DEBUGP("ctinfo = %u, skipping\n", ctinfo);
+ return NF_ACCEPT;
+ }
+-
++
+ nexthdr_off = (*pskb)->nh.iph->ihl*4;
+ tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph);
+ BUG_ON(!tcph);
+ nexthdr_off += tcph->doff * 4;
+ datalen = tcplen - tcph->doff * 4;
+
+- if (tcph->fin || tcph->rst) {
+- DEBUGP("RST/FIN received, timeouting GRE\n");
+- /* can't do this after real newnat */
+- info->cstate = PPTP_CALL_NONE;
+-
+- /* untrack this call id, unexpect GRE packets */
+- pptp_destroy_siblings(ct);
+- }
+-
+ pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph);
+ if (!pptph) {
+ DEBUGP("no full PPTP header, can't track\n");
+@@ -712,6 +568,23 @@ conntrack_pptp_help(struct sk_buff **psk
+ return NF_ACCEPT;
+ }
+
++ ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh);
++ if (!ctlh)
++ return NF_ACCEPT;
++ nexthdr_off += sizeof(_ctlh);
++ datalen -= sizeof(_ctlh);
++
++ reqlen = datalen;
++ msg = ntohs(ctlh->messageType);
++ if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])
++ return NF_ACCEPT;
++ if (reqlen > sizeof(*pptpReq))
++ reqlen = sizeof(*pptpReq);
++
++ pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq);
++ if (!pptpReq)
++ return NF_ACCEPT;
++
+ oldsstate = info->sstate;
+ oldcstate = info->cstate;
+
+@@ -721,11 +594,11 @@ conntrack_pptp_help(struct sk_buff **psk
+ * established from PNS->PAC. However, RFC makes no guarantee */
+ if (dir == IP_CT_DIR_ORIGINAL)
+ /* client -> server (PNS -> PAC) */
+- ret = pptp_outbound_pkt(pskb, tcph, nexthdr_off, datalen, ct,
++ ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
+ ctinfo);
+ else
+ /* server -> client (PAC -> PNS) */
+- ret = pptp_inbound_pkt(pskb, tcph, nexthdr_off, datalen, ct,
++ ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
+ ctinfo);
+ DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
+ oldsstate, info->sstate, oldcstate, info->cstate);
+@@ -735,30 +608,31 @@ conntrack_pptp_help(struct sk_buff **psk
+ }
+
+ /* control protocol helper */
+-static struct ip_conntrack_helper pptp = {
++static struct ip_conntrack_helper pptp = {
+ .list = { NULL, NULL },
+- .name = "pptp",
++ .name = "pptp",
+ .me = THIS_MODULE,
+ .max_expected = 2,
+ .timeout = 5 * 60,
+- .tuple = { .src = { .ip = 0,
+- .u = { .tcp = { .port =
+- __constant_htons(PPTP_CONTROL_PORT) } }
+- },
+- .dst = { .ip = 0,
++ .tuple = { .src = { .ip = 0,
++ .u = { .tcp = { .port =
++ __constant_htons(PPTP_CONTROL_PORT) } }
++ },
++ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = IPPROTO_TCP
+- }
++ }
+ },
+- .mask = { .src = { .ip = 0,
+- .u = { .tcp = { .port = __constant_htons(0xffff) } }
+- },
+- .dst = { .ip = 0,
++ .mask = { .src = { .ip = 0,
++ .u = { .tcp = { .port = __constant_htons(0xffff) } }
++ },
++ .dst = { .ip = 0,
+ .u = { .all = 0 },
+- .protonum = 0xff
+- }
++ .protonum = 0xff
++ }
+ },
+- .help = conntrack_pptp_help
++ .help = conntrack_pptp_help,
++ .destroy = pptp_destroy_siblings,
+ };
+
+ extern void ip_ct_proto_gre_fini(void);
+@@ -768,7 +642,7 @@ extern int __init ip_ct_proto_gre_init(v
+ static int __init ip_conntrack_helper_pptp_init(void)
+ {
+ int retcode;
+-
++
+ retcode = ip_ct_proto_gre_init();
+ if (retcode < 0)
+ return retcode;
+diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
+index 4488907..75f7c3d 100644
+--- a/net/ipv4/netfilter/ip_conntrack_irc.c
++++ b/net/ipv4/netfilter/ip_conntrack_irc.c
+@@ -218,7 +218,8 @@ static int help(struct sk_buff **pskb,
+ IPPROTO_TCP }});
+ exp->mask = ((struct ip_conntrack_tuple)
+ { { 0, { 0 } },
+- { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
++ { htonl(0xFFFFFFFF),
++ { .tcp = { htons(0xFFFF) } }, 0xFF }});
+ exp->expectfn = NULL;
+ exp->flags = 0;
+ if (ip_nat_irc_hook)
+@@ -266,7 +267,7 @@ static int __init ip_conntrack_irc_init(
+ hlpr = &irc_helpers[i];
+ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+ hlpr->tuple.dst.protonum = IPPROTO_TCP;
+- hlpr->mask.src.u.tcp.port = 0xFFFF;
++ hlpr->mask.src.u.tcp.port = htons(0xFFFF);
+ hlpr->mask.dst.protonum = 0xFF;
+ hlpr->max_expected = max_dcc_channels;
+ hlpr->timeout = dcc_timeout;
+diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+index a566a81..a1d6a89 100644
+--- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
++++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+@@ -21,6 +21,7 @@
+ #include <linux/skbuff.h>
+ #include <linux/netdevice.h>
+ #include <linux/inetdevice.h>
++#include <linux/if_addr.h>
+ #include <linux/in.h>
+ #include <linux/ip.h>
+ #include <net/route.h>
+@@ -47,7 +48,7 @@ static int help(struct sk_buff **pskb,
+ struct iphdr *iph = (*pskb)->nh.iph;
+ struct rtable *rt = (struct rtable *)(*pskb)->dst;
+ struct in_device *in_dev;
+- u_int32_t mask = 0;
++ __be32 mask = 0;
+
+ /* we're only interested in locally generated packets */
+ if ((*pskb)->sk == NULL)
+@@ -77,12 +78,12 @@ static int help(struct sk_buff **pskb,
+ goto out;
+
+ exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+- exp->tuple.src.u.udp.port = ntohs(NMBD_PORT);
++ exp->tuple.src.u.udp.port = htons(NMBD_PORT);
+
+ exp->mask.src.ip = mask;
+- exp->mask.src.u.udp.port = 0xFFFF;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.udp.port = 0xFFFF;
++ exp->mask.src.u.udp.port = htons(0xFFFF);
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.udp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+
+ exp->expectfn = NULL;
+@@ -114,7 +115,7 @@ static struct ip_conntrack_helper helper
+ .src = {
+ .u = {
+ .udp = {
+- .port = 0xFFFF,
++ .port = __constant_htons(0xFFFF),
+ }
+ }
+ },
+diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
+index 0d4cc92..262d0d4 100644
+--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
++++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
+@@ -44,13 +44,6 @@ MODULE_LICENSE("GPL");
+
+ static char __initdata version[] = "0.90";
+
+-#if 0
+-#define DEBUGP printk
+-#else
+-#define DEBUGP(format, args...)
+-#endif
+-
+-
+ static inline int
+ ctnetlink_dump_tuples_proto(struct sk_buff *skb,
+ const struct ip_conntrack_tuple *tuple,
+@@ -78,8 +71,8 @@ ctnetlink_dump_tuples_ip(struct sk_buff
+ {
+ struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
+
+- NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
+- NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
++ NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip);
++ NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip);
+
+ NFA_NEST_END(skb, nest_parms);
+
+@@ -110,7 +103,7 @@ ctnetlink_dump_tuples(struct sk_buff *sk
+ static inline int
+ ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
+ {
+- u_int32_t status = htonl((u_int32_t) ct->status);
++ __be32 status = htonl((u_int32_t) ct->status);
+ NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
+ return 0;
+
+@@ -122,7 +115,7 @@ static inline int
+ ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
+ {
+ long timeout_l = ct->timeout.expires - jiffies;
+- u_int32_t timeout;
++ __be32 timeout;
+
+ if (timeout_l < 0)
+ timeout = 0;
+@@ -192,13 +185,13 @@ ctnetlink_dump_counters(struct sk_buff *
+ {
+ enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
+ struct nfattr *nest_count = NFA_NEST(skb, type);
+- u_int32_t tmp;
++ __be32 tmp;
+
+ tmp = htonl(ct->counters[dir].packets);
+- NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
++ NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp);
+
+ tmp = htonl(ct->counters[dir].bytes);
+- NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
++ NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp);
+
+ NFA_NEST_END(skb, nest_count);
+
+@@ -215,9 +208,9 @@ nfattr_failure:
+ static inline int
+ ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
+ {
+- u_int32_t mark = htonl(ct->mark);
++ __be32 mark = htonl(ct->mark);
+
+- NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
++ NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark);
+ return 0;
+
+ nfattr_failure:
+@@ -230,8 +223,8 @@ nfattr_failure:
+ static inline int
+ ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
+ {
+- u_int32_t id = htonl(ct->id);
+- NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
++ __be32 id = htonl(ct->id);
++ NFA_PUT(skb, CTA_ID, sizeof(__be32), &id);
+ return 0;
+
+ nfattr_failure:
+@@ -241,9 +234,9 @@ nfattr_failure:
+ static inline int
+ ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
+ {
+- u_int32_t use = htonl(atomic_read(&ct->ct_general.use));
++ __be32 use = htonl(atomic_read(&ct->ct_general.use));
+
+- NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
++ NFA_PUT(skb, CTA_USE, sizeof(__be32), &use);
+ return 0;
+
+ nfattr_failure:
+@@ -329,11 +322,7 @@ static int ctnetlink_conntrack_event(str
+ /* dump everything */
+ events = ~0UL;
+ group = NFNLGRP_CONNTRACK_NEW;
+- } else if (events & (IPCT_STATUS |
+- IPCT_PROTOINFO |
+- IPCT_HELPER |
+- IPCT_HELPINFO |
+- IPCT_NATINFO)) {
++ } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) {
+ type = IPCTNL_MSG_CT_NEW;
+ group = NFNLGRP_CONNTRACK_UPDATE;
+ } else
+@@ -385,6 +374,10 @@ static int ctnetlink_conntrack_event(str
+ ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
+ goto nfattr_failure;
+
++ if (events & IPCT_MARK
++ && ctnetlink_dump_mark(skb, ct) < 0)
++ goto nfattr_failure;
++
+ nlh->nlmsg_len = skb->tail - b;
+ nfnetlink_send(skb, 0, group, 0);
+ return NOTIFY_DONE;
+@@ -398,7 +391,6 @@ nfattr_failure:
+
+ static int ctnetlink_done(struct netlink_callback *cb)
+ {
+- DEBUGP("entered %s\n", __FUNCTION__);
+ if (cb->args[1])
+ ip_conntrack_put((struct ip_conntrack *)cb->args[1]);
+ return 0;
+@@ -411,9 +403,6 @@ ctnetlink_dump_table(struct sk_buff *skb
+ struct ip_conntrack_tuple_hash *h;
+ struct list_head *i;
+
+- DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
+- cb->args[0], *id);
+-
+ read_lock_bh(&ip_conntrack_lock);
+ last = (struct ip_conntrack *)cb->args[1];
+ for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) {
+@@ -436,6 +425,11 @@ restart:
+ cb->args[1] = (unsigned long)ct;
+ goto out;
+ }
++#ifdef CONFIG_NF_CT_ACCT
++ if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) ==
++ IPCTNL_MSG_CT_GET_CTRZERO)
++ memset(&ct->counters, 0, sizeof(ct->counters));
++#endif
+ }
+ if (cb->args[1]) {
+ cb->args[1] = 0;
+@@ -447,53 +441,12 @@ out:
+ if (last)
+ ip_conntrack_put(last);
+
+- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
+- return skb->len;
+-}
+-
+-#ifdef CONFIG_IP_NF_CT_ACCT
+-static int
+-ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
+-{
+- struct ip_conntrack *ct = NULL;
+- struct ip_conntrack_tuple_hash *h;
+- struct list_head *i;
+- u_int32_t *id = (u_int32_t *) &cb->args[1];
+-
+- DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__,
+- cb->args[0], *id);
+-
+- write_lock_bh(&ip_conntrack_lock);
+- for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
+- list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
+- h = (struct ip_conntrack_tuple_hash *) i;
+- if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+- continue;
+- ct = tuplehash_to_ctrack(h);
+- if (ct->id <= *id)
+- continue;
+- if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
+- cb->nlh->nlmsg_seq,
+- IPCTNL_MSG_CT_NEW,
+- 1, ct) < 0)
+- goto out;
+- *id = ct->id;
+-
+- memset(&ct->counters, 0, sizeof(ct->counters));
+- }
+- }
+-out:
+- write_unlock_bh(&ip_conntrack_lock);
+-
+- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
+-
+ return skb->len;
+ }
+-#endif
+
+ static const size_t cta_min_ip[CTA_IP_MAX] = {
+- [CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
+- [CTA_IP_V4_DST-1] = sizeof(u_int32_t),
++ [CTA_IP_V4_SRC-1] = sizeof(__be32),
++ [CTA_IP_V4_DST-1] = sizeof(__be32),
+ };
+
+ static inline int
+@@ -501,8 +454,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *
+ {
+ struct nfattr *tb[CTA_IP_MAX];
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_IP_MAX, attr);
+
+ if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
+@@ -510,13 +461,11 @@ ctnetlink_parse_tuple_ip(struct nfattr *
+
+ if (!tb[CTA_IP_V4_SRC-1])
+ return -EINVAL;
+- tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
++ tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
+
+ if (!tb[CTA_IP_V4_DST-1])
+ return -EINVAL;
+- tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
+-
+- DEBUGP("leaving\n");
++ tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
+
+ return 0;
+ }
+@@ -538,8 +487,6 @@ ctnetlink_parse_tuple_proto(struct nfatt
+ struct ip_conntrack_protocol *proto;
+ int ret = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
+
+ if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
+@@ -566,8 +513,6 @@ ctnetlink_parse_tuple(struct nfattr *cda
+ struct nfattr *tb[CTA_TUPLE_MAX];
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ memset(tuple, 0, sizeof(*tuple));
+
+ nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
+@@ -592,10 +537,6 @@ ctnetlink_parse_tuple(struct nfattr *cda
+ else
+ tuple->dst.dir = IP_CT_DIR_ORIGINAL;
+
+- DUMP_TUPLE(tuple);
+-
+- DEBUGP("leaving\n");
+-
+ return 0;
+ }
+
+@@ -612,8 +553,6 @@ static int ctnetlink_parse_nat_proto(str
+ struct nfattr *tb[CTA_PROTONAT_MAX];
+ struct ip_nat_protocol *npt;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
+
+ if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
+@@ -632,13 +571,12 @@ static int ctnetlink_parse_nat_proto(str
+
+ ip_nat_proto_put(npt);
+
+- DEBUGP("leaving\n");
+ return 0;
+ }
+
+ static const size_t cta_min_nat[CTA_NAT_MAX] = {
+- [CTA_NAT_MINIP-1] = sizeof(u_int32_t),
+- [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),
++ [CTA_NAT_MINIP-1] = sizeof(__be32),
++ [CTA_NAT_MAXIP-1] = sizeof(__be32),
+ };
+
+ static inline int
+@@ -648,8 +586,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
+ struct nfattr *tb[CTA_NAT_MAX];
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ memset(range, 0, sizeof(*range));
+
+ nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
+@@ -658,12 +594,12 @@ ctnetlink_parse_nat(struct nfattr *nat,
+ return -EINVAL;
+
+ if (tb[CTA_NAT_MINIP-1])
+- range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
++ range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
+
+ if (!tb[CTA_NAT_MAXIP-1])
+ range->max_ip = range->min_ip;
+ else
+- range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
++ range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
+
+ if (range->min_ip)
+ range->flags |= IP_NAT_RANGE_MAP_IPS;
+@@ -675,7 +611,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
+ if (err < 0)
+ return err;
+
+- DEBUGP("leaving\n");
+ return 0;
+ }
+ #endif
+@@ -685,8 +620,6 @@ ctnetlink_parse_help(struct nfattr *attr
+ {
+ struct nfattr *tb[CTA_HELP_MAX];
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
+
+ if (!tb[CTA_HELP_NAME-1])
+@@ -698,11 +631,11 @@ ctnetlink_parse_help(struct nfattr *attr
+ }
+
+ static const size_t cta_min[CTA_MAX] = {
+- [CTA_STATUS-1] = sizeof(u_int32_t),
+- [CTA_TIMEOUT-1] = sizeof(u_int32_t),
+- [CTA_MARK-1] = sizeof(u_int32_t),
+- [CTA_USE-1] = sizeof(u_int32_t),
+- [CTA_ID-1] = sizeof(u_int32_t)
++ [CTA_STATUS-1] = sizeof(__be32),
++ [CTA_TIMEOUT-1] = sizeof(__be32),
++ [CTA_MARK-1] = sizeof(__be32),
++ [CTA_USE-1] = sizeof(__be32),
++ [CTA_ID-1] = sizeof(__be32)
+ };
+
+ static int
+@@ -714,8 +647,6 @@ ctnetlink_del_conntrack(struct sock *ctn
+ struct ip_conntrack *ct;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
+@@ -733,15 +664,13 @@ ctnetlink_del_conntrack(struct sock *ctn
+ return err;
+
+ h = ip_conntrack_find_get(&tuple, NULL);
+- if (!h) {
+- DEBUGP("tuple not found in conntrack hash\n");
++ if (!h)
+ return -ENOENT;
+- }
+
+ ct = tuplehash_to_ctrack(h);
+
+ if (cda[CTA_ID-1]) {
+- u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
++ u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1]));
+ if (ct->id != id) {
+ ip_conntrack_put(ct);
+ return -ENOENT;
+@@ -751,7 +680,6 @@ ctnetlink_del_conntrack(struct sock *ctn
+ ct->timeout.function((unsigned long)ct);
+
+ ip_conntrack_put(ct);
+- DEBUGP("leaving\n");
+
+ return 0;
+ }
+@@ -766,8 +694,6 @@ ctnetlink_get_conntrack(struct sock *ctn
+ struct sk_buff *skb2 = NULL;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ struct nfgenmsg *msg = NLMSG_DATA(nlh);
+ u32 rlen;
+@@ -775,22 +701,14 @@ ctnetlink_get_conntrack(struct sock *ctn
+ if (msg->nfgen_family != AF_INET)
+ return -EAFNOSUPPORT;
+
+- if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
+- IPCTNL_MSG_CT_GET_CTRZERO) {
+-#ifdef CONFIG_IP_NF_CT_ACCT
+- if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+- ctnetlink_dump_table_w,
+- ctnetlink_done)) != 0)
+- return -EINVAL;
+-#else
++#ifndef CONFIG_IP_NF_CT_ACCT
++ if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO)
+ return -ENOTSUPP;
+ #endif
+- } else {
+- if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+- ctnetlink_dump_table,
+- ctnetlink_done)) != 0)
++ if ((*errp = netlink_dump_start(ctnl, skb, nlh,
++ ctnetlink_dump_table,
++ ctnetlink_done)) != 0)
+ return -EINVAL;
+- }
+
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+@@ -813,11 +731,9 @@ ctnetlink_get_conntrack(struct sock *ctn
+ return err;
+
+ h = ip_conntrack_find_get(&tuple, NULL);
+- if (!h) {
+- DEBUGP("tuple not found in conntrack hash");
++ if (!h)
+ return -ENOENT;
+- }
+- DEBUGP("tuple found\n");
++
+ ct = tuplehash_to_ctrack(h);
+
+ err = -ENOMEM;
+@@ -838,7 +754,6 @@ ctnetlink_get_conntrack(struct sock *ctn
+ if (err < 0)
+ goto out;
+
+- DEBUGP("leaving\n");
+ return 0;
+
+ free:
+@@ -851,7 +766,7 @@ static inline int
+ ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
+ {
+ unsigned long d;
+- unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
++ unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1]));
+ d = ct->status ^ status;
+
+ if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
+@@ -909,8 +824,6 @@ ctnetlink_change_helper(struct ip_conntr
+ char *helpname;
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ /* don't change helper of sibling connections */
+ if (ct->master)
+ return -EINVAL;
+@@ -946,7 +859,7 @@ ctnetlink_change_helper(struct ip_conntr
+ static inline int
+ ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
+ {
+- u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
++ u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+
+ if (!del_timer(&ct->timeout))
+ return -ETIME;
+@@ -981,8 +894,6 @@ ctnetlink_change_conntrack(struct ip_con
+ {
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (cda[CTA_HELP-1]) {
+ err = ctnetlink_change_helper(ct, cda);
+ if (err < 0)
+@@ -1009,10 +920,9 @@ ctnetlink_change_conntrack(struct ip_con
+
+ #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+ if (cda[CTA_MARK-1])
+- ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
++ ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
+ #endif
+
+- DEBUGP("all done\n");
+ return 0;
+ }
+
+@@ -1024,15 +934,13 @@ ctnetlink_create_conntrack(struct nfattr
+ struct ip_conntrack *ct;
+ int err = -EINVAL;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ ct = ip_conntrack_alloc(otuple, rtuple);
+ if (ct == NULL || IS_ERR(ct))
+ return -ENOMEM;
+
+ if (!cda[CTA_TIMEOUT-1])
+ goto err;
+- ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
++ ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+
+ ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
+ ct->status |= IPS_CONFIRMED;
+@@ -1049,7 +957,7 @@ ctnetlink_create_conntrack(struct nfattr
+
+ #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+ if (cda[CTA_MARK-1])
+- ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
++ ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
+ #endif
+
+ ct->helper = ip_conntrack_helper_find_get(rtuple);
+@@ -1060,7 +968,6 @@ ctnetlink_create_conntrack(struct nfattr
+ if (ct->helper)
+ ip_conntrack_helper_put(ct->helper);
+
+- DEBUGP("conntrack with id %u inserted\n", ct->id);
+ return 0;
+
+ err:
+@@ -1076,8 +983,6 @@ ctnetlink_new_conntrack(struct sock *ctn
+ struct ip_conntrack_tuple_hash *h = NULL;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
+@@ -1101,7 +1006,6 @@ ctnetlink_new_conntrack(struct sock *ctn
+
+ if (h == NULL) {
+ write_unlock_bh(&ip_conntrack_lock);
+- DEBUGP("no such conntrack, create new\n");
+ err = -ENOENT;
+ if (nlh->nlmsg_flags & NLM_F_CREATE)
+ err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
+@@ -1117,7 +1021,6 @@ ctnetlink_new_conntrack(struct sock *ctn
+
+ /* We manipulate the conntrack inside the global conntrack table lock,
+ * so there's no need to increase the refcount */
+- DEBUGP("conntrack found\n");
+ err = -EEXIST;
+ if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+ err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
+@@ -1181,8 +1084,8 @@ ctnetlink_exp_dump_expect(struct sk_buff
+ const struct ip_conntrack_expect *exp)
+ {
+ struct ip_conntrack *master = exp->master;
+- u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
+- u_int32_t id = htonl(exp->id);
++ __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ);
++ __be32 id = htonl(exp->id);
+
+ if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
+ goto nfattr_failure;
+@@ -1193,8 +1096,8 @@ ctnetlink_exp_dump_expect(struct sk_buff
+ CTA_EXPECT_MASTER) < 0)
+ goto nfattr_failure;
+
+- NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
+- NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
++ NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout);
++ NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id);
+
+ return 0;
+
+@@ -1253,6 +1156,9 @@ static int ctnetlink_expect_event(struct
+ } else
+ return NOTIFY_DONE;
+
++ if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW))
++ return NOTIFY_DONE;
++
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+ if (!skb)
+ return NOTIFY_DONE;
+@@ -1289,8 +1195,6 @@ ctnetlink_exp_dump_table(struct sk_buff
+ struct list_head *i;
+ u_int32_t *id = (u_int32_t *) &cb->args[0];
+
+- DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
+-
+ read_lock_bh(&ip_conntrack_lock);
+ list_for_each_prev(i, &ip_conntrack_expect_list) {
+ exp = (struct ip_conntrack_expect *) i;
+@@ -1306,14 +1210,12 @@ ctnetlink_exp_dump_table(struct sk_buff
+ out:
+ read_unlock_bh(&ip_conntrack_lock);
+
+- DEBUGP("leaving, last id=%llu\n", *id);
+-
+ return skb->len;
+ }
+
+ static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
+- [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t),
+- [CTA_EXPECT_ID-1] = sizeof(u_int32_t)
++ [CTA_EXPECT_TIMEOUT-1] = sizeof(__be32),
++ [CTA_EXPECT_ID-1] = sizeof(__be32)
+ };
+
+ static int
+@@ -1325,8 +1227,6 @@ ctnetlink_get_expect(struct sock *ctnl,
+ struct sk_buff *skb2;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
+@@ -1361,7 +1261,7 @@ ctnetlink_get_expect(struct sock *ctnl,
+ return -ENOENT;
+
+ if (cda[CTA_EXPECT_ID-1]) {
+- u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
++ __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+ if (exp->id != ntohl(id)) {
+ ip_conntrack_expect_put(exp);
+ return -ENOENT;
+@@ -1415,8 +1315,8 @@ ctnetlink_del_expect(struct sock *ctnl,
+ return -ENOENT;
+
+ if (cda[CTA_EXPECT_ID-1]) {
+- u_int32_t id =
+- *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
++ __be32 id =
++ *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+ if (exp->id != ntohl(id)) {
+ ip_conntrack_expect_put(exp);
+ return -ENOENT;
+@@ -1477,8 +1377,6 @@ ctnetlink_create_expect(struct nfattr *c
+ struct ip_conntrack *ct;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ /* caller guarantees that those three CTA_EXPECT_* exist */
+ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
+ if (err < 0)
+@@ -1530,8 +1428,6 @@ ctnetlink_new_expect(struct sock *ctnl,
+ struct ip_conntrack_expect *exp;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
+@@ -1560,8 +1456,6 @@ ctnetlink_new_expect(struct sock *ctnl,
+ err = ctnetlink_change_expect(exp, cda);
+ write_unlock_bh(&ip_conntrack_lock);
+
+- DEBUGP("leaving\n");
+-
+ return err;
+ }
+
+diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
+index f891308..36f2b5e 100644
+--- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c
++++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
+@@ -12,7 +12,7 @@
+ #include <linux/netfilter.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+
+-unsigned int ip_ct_generic_timeout = 600*HZ;
++unsigned int ip_ct_generic_timeout __read_mostly = 600*HZ;
+
+ static int generic_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
+index 4ee016c..5fe026f 100644
+--- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c
++++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
+@@ -1,15 +1,15 @@
+ /*
+- * ip_conntrack_proto_gre.c - Version 3.0
++ * ip_conntrack_proto_gre.c - Version 3.0
+ *
+ * Connection tracking protocol helper module for GRE.
+ *
+ * GRE is a generic encapsulation protocol, which is generally not very
+ * suited for NAT, as it has no protocol-specific part as port numbers.
+ *
+- * It has an optional key field, which may help us distinguishing two
++ * It has an optional key field, which may help us distinguishing two
+ * connections between the same two hosts.
+ *
+- * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
+ *
+ * PPTP is built on top of a modified version of GRE, and has a mandatory
+ * field called "CallID", which serves us for the same purpose as the key
+@@ -37,7 +37,6 @@ static DEFINE_RWLOCK(ip_ct_gre_lock);
+ #define ASSERT_READ_LOCK(x)
+ #define ASSERT_WRITE_LOCK(x)
+
+-#include <linux/netfilter_ipv4/listhelp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+@@ -62,7 +61,7 @@ MODULE_DESCRIPTION("netfilter connection
+ #define DEBUGP(x, args...)
+ #define DUMP_TUPLE_GRE(x)
+ #endif
+-
++
+ /* GRE KEYMAP HANDLING FUNCTIONS */
+ static LIST_HEAD(gre_keymap_list);
+
+@@ -82,12 +81,14 @@ static __be16 gre_keymap_lookup(struct i
+ __be16 key = 0;
+
+ read_lock_bh(&ip_ct_gre_lock);
+- km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
+- struct ip_ct_gre_keymap *, t);
+- if (km)
+- key = km->tuple.src.u.gre.key;
++ list_for_each_entry(km, &gre_keymap_list, list) {
++ if (gre_key_cmpfn(km, t)) {
++ key = km->tuple.src.u.gre.key;
++ break;
++ }
++ }
+ read_unlock_bh(&ip_ct_gre_lock);
+-
++
+ DEBUGP("lookup src key 0x%x up key for ", key);
+ DUMP_TUPLE_GRE(t);
+
+@@ -99,28 +100,25 @@ int
+ ip_ct_gre_keymap_add(struct ip_conntrack *ct,
+ struct ip_conntrack_tuple *t, int reply)
+ {
+- struct ip_ct_gre_keymap **exist_km, *km, *old;
++ struct ip_ct_gre_keymap **exist_km, *km;
+
+ if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
+ DEBUGP("refusing to add GRE keymap to non-pptp session\n");
+ return -1;
+ }
+
+- if (!reply)
++ if (!reply)
+ exist_km = &ct->help.ct_pptp_info.keymap_orig;
+ else
+ exist_km = &ct->help.ct_pptp_info.keymap_reply;
+
+ if (*exist_km) {
+ /* check whether it's a retransmission */
+- old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
+- struct ip_ct_gre_keymap *, t);
+- if (old == *exist_km) {
+- DEBUGP("retransmission\n");
+- return 0;
++ list_for_each_entry(km, &gre_keymap_list, list) {
++ if (gre_key_cmpfn(km, t) && km == *exist_km)
++ return 0;
+ }
+-
+- DEBUGP("trying to override keymap_%s for ct %p\n",
++ DEBUGP("trying to override keymap_%s for ct %p\n",
+ reply? "reply":"orig", ct);
+ return -EEXIST;
+ }
+@@ -136,7 +134,7 @@ ip_ct_gre_keymap_add(struct ip_conntrack
+ DUMP_TUPLE_GRE(&km->tuple);
+
+ write_lock_bh(&ip_ct_gre_lock);
+- list_append(&gre_keymap_list, km);
++ list_add_tail(&km->list, &gre_keymap_list);
+ write_unlock_bh(&ip_ct_gre_lock);
+
+ return 0;
+@@ -154,7 +152,7 @@ void ip_ct_gre_keymap_destroy(struct ip_
+
+ write_lock_bh(&ip_ct_gre_lock);
+ if (ct->help.ct_pptp_info.keymap_orig) {
+- DEBUGP("removing %p from list\n",
++ DEBUGP("removing %p from list\n",
+ ct->help.ct_pptp_info.keymap_orig);
+ list_del(&ct->help.ct_pptp_info.keymap_orig->list);
+ kfree(ct->help.ct_pptp_info.keymap_orig);
+@@ -222,7 +220,7 @@ static int gre_pkt_to_tuple(const struct
+ static int gre_print_tuple(struct seq_file *s,
+ const struct ip_conntrack_tuple *tuple)
+ {
+- return seq_printf(s, "srckey=0x%x dstkey=0x%x ",
++ return seq_printf(s, "srckey=0x%x dstkey=0x%x ",
+ ntohs(tuple->src.u.gre.key),
+ ntohs(tuple->dst.u.gre.key));
+ }
+@@ -252,14 +250,14 @@ static int gre_packet(struct ip_conntrac
+ } else
+ ip_ct_refresh_acct(ct, conntrackinfo, skb,
+ ct->proto.gre.timeout);
+-
++
+ return NF_ACCEPT;
+ }
+
+ /* Called when a new connection for this protocol found. */
+ static int gre_new(struct ip_conntrack *ct,
+ const struct sk_buff *skb)
+-{
++{
+ DEBUGP(": ");
+ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+
+@@ -285,9 +283,9 @@ static void gre_destroy(struct ip_conntr
+ }
+
+ /* protocol helper struct */
+-static struct ip_conntrack_protocol gre = {
++static struct ip_conntrack_protocol gre = {
+ .proto = IPPROTO_GRE,
+- .name = "gre",
++ .name = "gre",
+ .pkt_to_tuple = gre_pkt_to_tuple,
+ .invert_tuple = gre_invert_tuple,
+ .print_tuple = gre_print_tuple,
+@@ -325,7 +323,7 @@ void ip_ct_proto_gre_fini(void)
+ }
+ write_unlock_bh(&ip_ct_gre_lock);
+
+- ip_conntrack_protocol_unregister(&gre);
++ ip_conntrack_protocol_unregister(&gre);
+ }
+
+ EXPORT_SYMBOL(ip_ct_gre_keymap_add);
+diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+index 23f1c50..295b6fa 100644
+--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
++++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+@@ -21,7 +21,7 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+
+-unsigned int ip_ct_icmp_timeout = 30*HZ;
++unsigned int ip_ct_icmp_timeout __read_mostly = 30*HZ;
+
+ #if 0
+ #define DEBUGP printk
+@@ -261,7 +261,7 @@ icmp_error(struct sk_buff *skb, enum ip_
+ static int icmp_tuple_to_nfattr(struct sk_buff *skb,
+ const struct ip_conntrack_tuple *t)
+ {
+- NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t),
++ NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(__be16),
+ &t->src.u.icmp.id);
+ NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
+ &t->dst.u.icmp.type);
+@@ -287,7 +287,7 @@ static int icmp_nfattr_to_tuple(struct n
+ tuple->dst.u.icmp.code =
+ *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
+ tuple->src.u.icmp.id =
+- *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
++ *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
+
+ if (tuple->dst.u.icmp.type >= sizeof(invmap)
+ || !invmap[tuple->dst.u.icmp.type])
+diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+index 2d3612c..2443322 100644
+--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
++++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+@@ -58,13 +58,13 @@ static const char *sctp_conntrack_names[
+ #define HOURS * 60 MINS
+ #define DAYS * 24 HOURS
+
+-static unsigned int ip_ct_sctp_timeout_closed = 10 SECS;
+-static unsigned int ip_ct_sctp_timeout_cookie_wait = 3 SECS;
+-static unsigned int ip_ct_sctp_timeout_cookie_echoed = 3 SECS;
+-static unsigned int ip_ct_sctp_timeout_established = 5 DAYS;
+-static unsigned int ip_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000;
+-static unsigned int ip_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000;
+-static unsigned int ip_ct_sctp_timeout_shutdown_ack_sent = 3 SECS;
++static unsigned int ip_ct_sctp_timeout_closed __read_mostly = 10 SECS;
++static unsigned int ip_ct_sctp_timeout_cookie_wait __read_mostly = 3 SECS;
++static unsigned int ip_ct_sctp_timeout_cookie_echoed __read_mostly = 3 SECS;
++static unsigned int ip_ct_sctp_timeout_established __read_mostly = 5 DAYS;
++static unsigned int ip_ct_sctp_timeout_shutdown_sent __read_mostly = 300 SECS / 1000;
++static unsigned int ip_ct_sctp_timeout_shutdown_recd __read_mostly = 300 SECS / 1000;
++static unsigned int ip_ct_sctp_timeout_shutdown_ack_sent __read_mostly = 3 SECS;
+
+ static const unsigned int * sctp_timeouts[]
+ = { NULL, /* SCTP_CONNTRACK_NONE */
+@@ -210,7 +210,7 @@ static int sctp_print_conntrack(struct s
+ for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0; \
+ offset < skb->len && \
+ (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \
+- offset += (htons(sch->length) + 3) & ~3, count++)
++ offset += (ntohs(sch->length) + 3) & ~3, count++)
+
+ /* Some validity checks to make sure the chunks are fine */
+ static int do_basic_checks(struct ip_conntrack *conntrack,
+diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+index fb920e7..06e4e8a 100644
+--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
++++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+@@ -48,19 +48,19 @@ static DEFINE_RWLOCK(tcp_lock);
+ /* "Be conservative in what you do,
+ be liberal in what you accept from others."
+ If it's non-zero, we mark only out of window RST segments as INVALID. */
+-int ip_ct_tcp_be_liberal = 0;
++int ip_ct_tcp_be_liberal __read_mostly = 0;
+
+ /* When connection is picked up from the middle, how many packets are required
+ to pass in each direction when we assume we are in sync - if any side uses
+ window scaling, we lost the game.
+ If it is set to zero, we disable picking up already established
+ connections. */
+-int ip_ct_tcp_loose = 3;
++int ip_ct_tcp_loose __read_mostly = 3;
+
+ /* Max number of the retransmitted packets without receiving an (acceptable)
+ ACK from the destination. If this number is reached, a shorter timer
+ will be started. */
+-int ip_ct_tcp_max_retrans = 3;
++int ip_ct_tcp_max_retrans __read_mostly = 3;
+
+ /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+ closely. They're more complex. --RR */
+@@ -83,19 +83,19 @@ static const char *tcp_conntrack_names[]
+ #define HOURS * 60 MINS
+ #define DAYS * 24 HOURS
+
+-unsigned int ip_ct_tcp_timeout_syn_sent = 2 MINS;
+-unsigned int ip_ct_tcp_timeout_syn_recv = 60 SECS;
+-unsigned int ip_ct_tcp_timeout_established = 5 DAYS;
+-unsigned int ip_ct_tcp_timeout_fin_wait = 2 MINS;
+-unsigned int ip_ct_tcp_timeout_close_wait = 60 SECS;
+-unsigned int ip_ct_tcp_timeout_last_ack = 30 SECS;
+-unsigned int ip_ct_tcp_timeout_time_wait = 2 MINS;
+-unsigned int ip_ct_tcp_timeout_close = 10 SECS;
++unsigned int ip_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS;
++unsigned int ip_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS;
++unsigned int ip_ct_tcp_timeout_established __read_mostly = 5 DAYS;
++unsigned int ip_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS;
++unsigned int ip_ct_tcp_timeout_close_wait __read_mostly = 60 SECS;
++unsigned int ip_ct_tcp_timeout_last_ack __read_mostly = 30 SECS;
++unsigned int ip_ct_tcp_timeout_time_wait __read_mostly = 2 MINS;
++unsigned int ip_ct_tcp_timeout_close __read_mostly = 10 SECS;
+
+ /* RFC1122 says the R2 limit should be at least 100 seconds.
+ Linux uses 15 packets as limit, which corresponds
+ to ~13-30min depending on RTO. */
+-unsigned int ip_ct_tcp_timeout_max_retrans = 5 MINS;
++unsigned int ip_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS;
+
+ static const unsigned int * tcp_timeouts[]
+ = { NULL, /* TCP_CONNTRACK_NONE */
+@@ -519,8 +519,8 @@ static void tcp_sack(const struct sk_buf
+
+ /* Fast path for timestamp-only option */
+ if (length == TCPOLEN_TSTAMP_ALIGNED*4
+- && *(__u32 *)ptr ==
+- __constant_ntohl((TCPOPT_NOP << 24)
++ && *(__be32 *)ptr ==
++ __constant_htonl((TCPOPT_NOP << 24)
+ | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8)
+ | TCPOLEN_TIMESTAMP))
+@@ -551,7 +551,7 @@ static void tcp_sack(const struct sk_buf
+ for (i = 0;
+ i < (opsize - TCPOLEN_SACK_BASE);
+ i += TCPOLEN_SACK_PERBLOCK) {
+- tmp = ntohl(*((u_int32_t *)(ptr+i)+1));
++ tmp = ntohl(*((__be32 *)(ptr+i)+1));
+
+ if (after(tmp, *sack))
+ *sack = tmp;
+@@ -731,13 +731,15 @@ static int tcp_in_window(struct ip_ct_tc
+ if (state->last_dir == dir
+ && state->last_seq == seq
+ && state->last_ack == ack
+- && state->last_end == end)
++ && state->last_end == end
++ && state->last_win == win)
+ state->retrans++;
+ else {
+ state->last_dir = dir;
+ state->last_seq = seq;
+ state->last_ack = ack;
+ state->last_end = end;
++ state->last_win = win;
+ state->retrans = 0;
+ }
+ }
+@@ -865,8 +867,7 @@ static int tcp_error(struct sk_buff *skb
+
+ /* Checksum invalid? Ignore.
+ * We skip checking packets on the outgoing path
+- * because the semantic of CHECKSUM_HW is different there
+- * and moreover root might send raw packets.
++ * because it is assumed to be correct.
+ */
+ /* FIXME: Source route IP option packets --RR */
+ if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
+diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+index 9b2c16b..d0e8a16 100644
+--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
++++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+@@ -18,8 +18,8 @@
+ #include <linux/netfilter_ipv4.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+
+-unsigned int ip_ct_udp_timeout = 30*HZ;
+-unsigned int ip_ct_udp_timeout_stream = 180*HZ;
++unsigned int ip_ct_udp_timeout __read_mostly = 30*HZ;
++unsigned int ip_ct_udp_timeout_stream __read_mostly = 180*HZ;
+
+ static int udp_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+@@ -117,8 +117,7 @@ static int udp_error(struct sk_buff *skb
+
+ /* Checksum invalid? Ignore.
+ * We skip checking packets on the outgoing path
+- * because the semantic of CHECKSUM_HW is different there
+- * and moreover root might send raw packets.
++ * because the checksum is assumed to be correct.
+ * FIXME: Source route IP option packets --RR */
+ if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
+ nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) {
+diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c
+index 4f222d6..f4f7599 100644
+--- a/net/ipv4/netfilter/ip_conntrack_sip.c
++++ b/net/ipv4/netfilter/ip_conntrack_sip.c
+@@ -8,7 +8,6 @@
+ * published by the Free Software Foundation.
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/ctype.h>
+ #include <linux/skbuff.h>
+@@ -194,7 +193,7 @@ static int skp_digits_len(const char *dp
+
+ /* Simple ipaddr parser.. */
+ static int parse_ipaddr(const char *cp, const char **endp,
+- u_int32_t *ipaddr, const char *limit)
++ __be32 *ipaddr, const char *limit)
+ {
+ unsigned long int val;
+ int i, digit = 0;
+@@ -228,7 +227,7 @@ static int parse_ipaddr(const char *cp,
+ static int epaddr_len(const char *dptr, const char *limit, int *shift)
+ {
+ const char *aux = dptr;
+- u_int32_t ip;
++ __be32 ip;
+
+ if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) {
+ DEBUGP("ip: %s parse failed.!\n", dptr);
+@@ -303,7 +302,7 @@ int ct_sip_get_info(const char *dptr, si
+ static int set_expected_rtp(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+- u_int32_t ipaddr, u_int16_t port,
++ __be32 ipaddr, u_int16_t port,
+ const char *dptr)
+ {
+ struct ip_conntrack_expect *exp;
+@@ -320,10 +319,10 @@ static int set_expected_rtp(struct sk_bu
+ exp->tuple.dst.u.udp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_UDP;
+
+- exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.src.ip = htonl(0xFFFFFFFF);
+ exp->mask.src.u.udp.port = 0;
+- exp->mask.dst.ip = 0xFFFFFFFF;
+- exp->mask.dst.u.udp.port = 0xFFFF;
++ exp->mask.dst.ip = htonl(0xFFFFFFFF);
++ exp->mask.dst.u.udp.port = htons(0xFFFF);
+ exp->mask.dst.protonum = 0xFF;
+
+ exp->expectfn = NULL;
+@@ -350,7 +349,7 @@ static int sip_help(struct sk_buff **psk
+ const char *dptr;
+ int ret = NF_ACCEPT;
+ int matchoff, matchlen;
+- u_int32_t ipaddr;
++ __be32 ipaddr;
+ u_int16_t port;
+
+ /* No Data ? */
+@@ -440,7 +439,7 @@ static int __init init(void)
+
+ sip[i].tuple.dst.protonum = IPPROTO_UDP;
+ sip[i].tuple.src.u.udp.port = htons(ports[i]);
+- sip[i].mask.src.u.udp.port = 0xFFFF;
++ sip[i].mask.src.u.udp.port = htons(0xFFFF);
+ sip[i].mask.dst.protonum = 0xFF;
+ sip[i].max_expected = 2;
+ sip[i].timeout = 3 * 60; /* 3 minutes */
+diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
+index 7a9fa04..0213575 100644
+--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
++++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
+@@ -35,7 +35,6 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #if 0
+ #define DEBUGP printk
+@@ -534,7 +533,7 @@ static struct nf_hook_ops ip_conntrack_o
+
+ /* Sysctl support */
+
+-int ip_conntrack_checksum = 1;
++int ip_conntrack_checksum __read_mostly = 1;
+
+ #ifdef CONFIG_SYSCTL
+
+@@ -563,7 +562,7 @@ extern unsigned int ip_ct_udp_timeout_st
+ /* From ip_conntrack_proto_icmp.c */
+ extern unsigned int ip_ct_icmp_timeout;
+
+-/* From ip_conntrack_proto_icmp.c */
++/* From ip_conntrack_proto_generic.c */
+ extern unsigned int ip_ct_generic_timeout;
+
+ /* Log invalid packets of a given protocol */
+diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
+index 7e33d3b..fe0b634 100644
+--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
++++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
+@@ -70,10 +70,10 @@ static int tftp_help(struct sk_buff **ps
+ return NF_DROP;
+
+ exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+- exp->mask.src.ip = 0xffffffff;
++ exp->mask.src.ip = htonl(0xffffffff);
+ exp->mask.src.u.udp.port = 0;
+- exp->mask.dst.ip = 0xffffffff;
+- exp->mask.dst.u.udp.port = 0xffff;
++ exp->mask.dst.ip = htonl(0xffffffff);
++ exp->mask.dst.u.udp.port = htons(0xffff);
+ exp->mask.dst.protonum = 0xff;
+ exp->expectfn = NULL;
+ exp->flags = 0;
+@@ -129,7 +129,7 @@ static int __init ip_conntrack_tftp_init
+ tftp[i].tuple.dst.protonum = IPPROTO_UDP;
+ tftp[i].tuple.src.u.udp.port = htons(ports[i]);
+ tftp[i].mask.dst.protonum = 0xFF;
+- tftp[i].mask.src.u.udp.port = 0xFFFF;
++ tftp[i].mask.src.u.udp.port = htons(0xFFFF);
+ tftp[i].max_expected = 1;
+ tftp[i].timeout = 5 * 60; /* 5 minutes */
+ tftp[i].me = THIS_MODULE;
+diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
+index 1741d55..4b6260a 100644
+--- a/net/ipv4/netfilter/ip_nat_core.c
++++ b/net/ipv4/netfilter/ip_nat_core.c
+@@ -22,9 +22,6 @@
+ #include <linux/udp.h>
+ #include <linux/jhash.h>
+
+-#define ASSERT_READ_LOCK(x)
+-#define ASSERT_WRITE_LOCK(x)
+-
+ #include <linux/netfilter_ipv4/ip_conntrack.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+@@ -33,7 +30,6 @@
+ #include <linux/netfilter_ipv4/ip_nat_core.h>
+ #include <linux/netfilter_ipv4/ip_nat_helper.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #if 0
+ #define DEBUGP printk
+@@ -86,7 +82,7 @@ static inline unsigned int
+ hash_by_src(const struct ip_conntrack_tuple *tuple)
+ {
+ /* Original src, to ensure we map it consistently if poss. */
+- return jhash_3words(tuple->src.ip, tuple->src.u.all,
++ return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all,
+ tuple->dst.protonum, 0) % ip_nat_htable_size;
+ }
+
+@@ -101,18 +97,6 @@ static void ip_nat_cleanup_conntrack(str
+ write_unlock_bh(&ip_nat_lock);
+ }
+
+-/* We do checksum mangling, so if they were wrong before they're still
+- * wrong. Also works for incomplete packets (eg. ICMP dest
+- * unreachables.) */
+-u_int16_t
+-ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
+-{
+- u_int32_t diffs[] = { oldvalinv, newval };
+- return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
+- oldcheck^0xFFFF));
+-}
+-EXPORT_SYMBOL(ip_nat_cheat_check);
+-
+ /* Is this tuple already taken? (not by us) */
+ int
+ ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
+@@ -206,7 +190,7 @@ find_best_ips_proto(struct ip_conntrack_
+ const struct ip_conntrack *conntrack,
+ enum ip_nat_manip_type maniptype)
+ {
+- u_int32_t *var_ipp;
++ __be32 *var_ipp;
+ /* Host order */
+ u_int32_t minip, maxip, j;
+
+@@ -233,7 +217,7 @@ find_best_ips_proto(struct ip_conntrack_
+ * like this), even across reboots. */
+ minip = ntohl(range->min_ip);
+ maxip = ntohl(range->max_ip);
+- j = jhash_2words(tuple->src.ip, tuple->dst.ip, 0);
++ j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0);
+ *var_ipp = htonl(minip + j % (maxip - minip + 1));
+ }
+
+@@ -378,12 +362,12 @@ manip_pkt(u_int16_t proto,
+ iph = (void *)(*pskb)->data + iphdroff;
+
+ if (maniptype == IP_NAT_MANIP_SRC) {
+- iph->check = ip_nat_cheat_check(~iph->saddr, target->src.ip,
+- iph->check);
++ iph->check = nf_csum_update(~iph->saddr, target->src.ip,
++ iph->check);
+ iph->saddr = target->src.ip;
+ } else {
+- iph->check = ip_nat_cheat_check(~iph->daddr, target->dst.ip,
+- iph->check);
++ iph->check = nf_csum_update(~iph->daddr, target->dst.ip,
++ iph->check);
+ iph->daddr = target->dst.ip;
+ }
+ return 1;
+@@ -423,10 +407,10 @@ unsigned int ip_nat_packet(struct ip_con
+ EXPORT_SYMBOL_GPL(ip_nat_packet);
+
+ /* Dir is direction ICMP is coming from (opposite to packet it contains) */
+-int ip_nat_icmp_reply_translation(struct sk_buff **pskb,
+- struct ip_conntrack *ct,
+- enum ip_nat_manip_type manip,
+- enum ip_conntrack_dir dir)
++int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
+ {
+ struct {
+ struct icmphdr icmp;
+@@ -434,7 +418,9 @@ int ip_nat_icmp_reply_translation(struct
+ } *inside;
+ struct ip_conntrack_tuple inner, target;
+ int hdrlen = (*pskb)->nh.iph->ihl * 4;
++ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ unsigned long statusbit;
++ enum ip_nat_manip_type manip = HOOK2MANIP(hooknum);
+
+ if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
+ return 0;
+@@ -443,12 +429,8 @@ int ip_nat_icmp_reply_translation(struct
+
+ /* We're actually going to mangle it beyond trivial checksum
+ adjustment, so make sure the current checksum is correct. */
+- if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
+- hdrlen = (*pskb)->nh.iph->ihl * 4;
+- if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
+- (*pskb)->len - hdrlen, 0)))
+- return 0;
+- }
++ if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0))
++ return 0;
+
+ /* Must be RELATED */
+ IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
+@@ -487,12 +469,14 @@ int ip_nat_icmp_reply_translation(struct
+ !manip))
+ return 0;
+
+- /* Reloading "inside" here since manip_pkt inner. */
+- inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+- inside->icmp.checksum = 0;
+- inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
+- (*pskb)->len - hdrlen,
+- 0));
++ if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
++ /* Reloading "inside" here since manip_pkt inner. */
++ inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
++ inside->icmp.checksum = 0;
++ inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
++ (*pskb)->len - hdrlen,
++ 0));
++ }
+
+ /* Change outer to look the reply to an incoming packet
+ * (proto 0 means don't invert per-proto part). */
+@@ -550,9 +534,9 @@ int
+ ip_nat_port_range_to_nfattr(struct sk_buff *skb,
+ const struct ip_nat_range *range)
+ {
+- NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(u_int16_t),
++ NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16),
+ &range->min.tcp.port);
+- NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(u_int16_t),
++ NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),
+ &range->max.tcp.port);
+
+ return 0;
+@@ -571,7 +555,7 @@ ip_nat_port_nfattr_to_range(struct nfatt
+ if (tb[CTA_PROTONAT_PORT_MIN-1]) {
+ ret = 1;
+ range->min.tcp.port =
+- *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
++ *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
+ }
+
+ if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
+@@ -580,7 +564,7 @@ ip_nat_port_nfattr_to_range(struct nfatt
+ } else {
+ ret = 1;
+ range->max.tcp.port =
+- *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
++ *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
+ }
+
+ return ret;
+diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
+index 3328fc5..a71c233 100644
+--- a/net/ipv4/netfilter/ip_nat_ftp.c
++++ b/net/ipv4/netfilter/ip_nat_ftp.c
+@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("ftp NAT helper");
+
+ static int
+ mangle_rfc959_packet(struct sk_buff **pskb,
+- u_int32_t newip,
++ __be32 newip,
+ u_int16_t port,
+ unsigned int matchoff,
+ unsigned int matchlen,
+@@ -57,7 +57,7 @@ mangle_rfc959_packet(struct sk_buff **ps
+ /* |1|132.235.1.2|6275| */
+ static int
+ mangle_eprt_packet(struct sk_buff **pskb,
+- u_int32_t newip,
++ __be32 newip,
+ u_int16_t port,
+ unsigned int matchoff,
+ unsigned int matchlen,
+@@ -79,7 +79,7 @@ mangle_eprt_packet(struct sk_buff **pskb
+ /* |1|132.235.1.2|6275| */
+ static int
+ mangle_epsv_packet(struct sk_buff **pskb,
+- u_int32_t newip,
++ __be32 newip,
+ u_int16_t port,
+ unsigned int matchoff,
+ unsigned int matchlen,
+@@ -98,7 +98,7 @@ mangle_epsv_packet(struct sk_buff **pskb
+ matchlen, buffer, strlen(buffer));
+ }
+
+-static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
++static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
+ unsigned int,
+ unsigned int,
+ struct ip_conntrack *,
+@@ -120,7 +120,7 @@ static unsigned int ip_nat_ftp(struct sk
+ struct ip_conntrack_expect *exp,
+ u32 *seq)
+ {
+- u_int32_t newip;
++ __be32 newip;
+ u_int16_t port;
+ int dir = CTINFO2DIR(ctinfo);
+ struct ip_conntrack *ct = exp->master;
+diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
+index cbcaa45..3bf8584 100644
+--- a/net/ipv4/netfilter/ip_nat_helper.c
++++ b/net/ipv4/netfilter/ip_nat_helper.c
+@@ -27,16 +27,12 @@
+ #include <net/tcp.h>
+ #include <net/udp.h>
+
+-#define ASSERT_READ_LOCK(x)
+-#define ASSERT_WRITE_LOCK(x)
+-
+ #include <linux/netfilter_ipv4/ip_conntrack.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+ #include <linux/netfilter_ipv4/ip_nat.h>
+ #include <linux/netfilter_ipv4/ip_nat_protocol.h>
+ #include <linux/netfilter_ipv4/ip_nat_core.h>
+ #include <linux/netfilter_ipv4/ip_nat_helper.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #if 0
+ #define DEBUGP printk
+@@ -165,7 +161,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff
+ {
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+- int datalen;
++ int oldlen, datalen;
+
+ if (!skb_make_writable(pskb, (*pskb)->len))
+ return 0;
+@@ -180,13 +176,22 @@ ip_nat_mangle_tcp_packet(struct sk_buff
+ iph = (*pskb)->nh.iph;
+ tcph = (void *)iph + iph->ihl*4;
+
++ oldlen = (*pskb)->len - iph->ihl*4;
+ mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
+ match_offset, match_len, rep_buffer, rep_len);
+
+ datalen = (*pskb)->len - iph->ihl*4;
+- tcph->check = 0;
+- tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr,
+- csum_partial((char *)tcph, datalen, 0));
++ if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
++ tcph->check = 0;
++ tcph->check = tcp_v4_check(tcph, datalen,
++ iph->saddr, iph->daddr,
++ csum_partial((char *)tcph,
++ datalen, 0));
++ } else
++ tcph->check = nf_proto_csum_update(*pskb,
++ htons(oldlen) ^ htons(0xFFFF),
++ htons(datalen),
++ tcph->check, 1);
+
+ if (rep_len != match_len) {
+ set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
+@@ -221,6 +226,7 @@ ip_nat_mangle_udp_packet(struct sk_buff
+ {
+ struct iphdr *iph;
+ struct udphdr *udph;
++ int datalen, oldlen;
+
+ /* UDP helpers might accidentally mangle the wrong packet */
+ iph = (*pskb)->nh.iph;
+@@ -238,22 +244,32 @@ ip_nat_mangle_udp_packet(struct sk_buff
+
+ iph = (*pskb)->nh.iph;
+ udph = (void *)iph + iph->ihl*4;
++
++ oldlen = (*pskb)->len - iph->ihl*4;
+ mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
+ match_offset, match_len, rep_buffer, rep_len);
+
+ /* update the length of the UDP packet */
+- udph->len = htons((*pskb)->len - iph->ihl*4);
++ datalen = (*pskb)->len - iph->ihl*4;
++ udph->len = htons(datalen);
+
+ /* fix udp checksum if udp checksum was previously calculated */
+- if (udph->check) {
+- int datalen = (*pskb)->len - iph->ihl * 4;
++ if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL)
++ return 1;
++
++ if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
+ udph->check = 0;
+ udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+ datalen, IPPROTO_UDP,
+ csum_partial((char *)udph,
+ datalen, 0));
+- }
+-
++ if (!udph->check)
++ udph->check = -1;
++ } else
++ udph->check = nf_proto_csum_update(*pskb,
++ htons(oldlen) ^ htons(0xFFFF),
++ htons(datalen),
++ udph->check, 1);
+ return 1;
+ }
+ EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
+@@ -267,37 +283,38 @@ sack_adjust(struct sk_buff *skb,
+ struct ip_nat_seq *natseq)
+ {
+ while (sackoff < sackend) {
+- struct tcp_sack_block *sack;
+- u_int32_t new_start_seq, new_end_seq;
++ struct tcp_sack_block_wire *sack;
++ __be32 new_start_seq, new_end_seq;
+
+ sack = (void *)skb->data + sackoff;
+ if (after(ntohl(sack->start_seq) - natseq->offset_before,
+ natseq->correction_pos))
+- new_start_seq = ntohl(sack->start_seq)
+- - natseq->offset_after;
++ new_start_seq = htonl(ntohl(sack->start_seq)
++ - natseq->offset_after);
+ else
+- new_start_seq = ntohl(sack->start_seq)
+- - natseq->offset_before;
+- new_start_seq = htonl(new_start_seq);
++ new_start_seq = htonl(ntohl(sack->start_seq)
++ - natseq->offset_before);
+
+ if (after(ntohl(sack->end_seq) - natseq->offset_before,
+ natseq->correction_pos))
+- new_end_seq = ntohl(sack->end_seq)
+- - natseq->offset_after;
++ new_end_seq = htonl(ntohl(sack->end_seq)
++ - natseq->offset_after);
+ else
+- new_end_seq = ntohl(sack->end_seq)
+- - natseq->offset_before;
+- new_end_seq = htonl(new_end_seq);
++ new_end_seq = htonl(ntohl(sack->end_seq)
++ - natseq->offset_before);
+
+ DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+ ntohl(sack->start_seq), new_start_seq,
+ ntohl(sack->end_seq), new_end_seq);
+
+- tcph->check =
+- ip_nat_cheat_check(~sack->start_seq, new_start_seq,
+- ip_nat_cheat_check(~sack->end_seq,
+- new_end_seq,
+- tcph->check));
++ tcph->check = nf_proto_csum_update(skb,
++ ~sack->start_seq,
++ new_start_seq,
++ tcph->check, 0);
++ tcph->check = nf_proto_csum_update(skb,
++ ~sack->end_seq,
++ new_end_seq,
++ tcph->check, 0);
+ sack->start_seq = new_start_seq;
+ sack->end_seq = new_end_seq;
+ sackoff += sizeof(*sack);
+@@ -356,7 +373,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo)
+ {
+ struct tcphdr *tcph;
+- int dir, newseq, newack;
++ int dir;
++ __be32 newseq, newack;
+ struct ip_nat_seq *this_way, *other_way;
+
+ dir = CTINFO2DIR(ctinfo);
+@@ -369,22 +387,20 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
+
+ tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+ if (after(ntohl(tcph->seq), this_way->correction_pos))
+- newseq = ntohl(tcph->seq) + this_way->offset_after;
++ newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
+ else
+- newseq = ntohl(tcph->seq) + this_way->offset_before;
+- newseq = htonl(newseq);
++ newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
+
+ if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
+ other_way->correction_pos))
+- newack = ntohl(tcph->ack_seq) - other_way->offset_after;
++ newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
+ else
+- newack = ntohl(tcph->ack_seq) - other_way->offset_before;
+- newack = htonl(newack);
++ newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
+
+- tcph->check = ip_nat_cheat_check(~tcph->seq, newseq,
+- ip_nat_cheat_check(~tcph->ack_seq,
+- newack,
+- tcph->check));
++ tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq,
++ tcph->check, 0);
++ tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack,
++ tcph->check, 0);
+
+ DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
+ ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
+diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
+index 419b878..4a7d344 100644
+--- a/net/ipv4/netfilter/ip_nat_helper_h323.c
++++ b/net/ipv4/netfilter/ip_nat_helper_h323.c
+@@ -32,13 +32,13 @@
+ /****************************************************************************/
+ static int set_addr(struct sk_buff **pskb,
+ unsigned char **data, int dataoff,
+- unsigned int addroff, u_int32_t ip, u_int16_t port)
++ unsigned int addroff, __be32 ip, u_int16_t port)
+ {
+ enum ip_conntrack_info ctinfo;
+ struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
+ struct {
+- u_int32_t ip;
+- u_int16_t port;
++ __be32 ip;
++ __be16 port;
+ } __attribute__ ((__packed__)) buf;
+ struct tcphdr _tcph, *th;
+
+@@ -86,7 +86,7 @@ static int set_addr(struct sk_buff **psk
+ static int set_h225_addr(struct sk_buff **pskb,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr,
+- u_int32_t ip, u_int16_t port)
++ __be32 ip, u_int16_t port)
+ {
+ return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
+ }
+@@ -95,7 +95,7 @@ static int set_h225_addr(struct sk_buff
+ static int set_h245_addr(struct sk_buff **pskb,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+- u_int32_t ip, u_int16_t port)
++ __be32 ip, u_int16_t port)
+ {
+ return set_addr(pskb, data, dataoff,
+ addr->unicastAddress.iPAddress.network, ip, port);
+@@ -110,7 +110,7 @@ static int set_sig_addr(struct sk_buff *
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ int i;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+
+ for (i = 0; i < count; i++) {
+@@ -164,7 +164,7 @@ static int set_ras_addr(struct sk_buff *
+ {
+ int dir = CTINFO2DIR(ctinfo);
+ int i;
+- u_int32_t ip;
++ __be32 ip;
+ u_int16_t port;
+
+ for (i = 0; i < count; i++) {
+@@ -433,7 +433,7 @@ static int nat_q931(struct sk_buff **psk
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ u_int16_t nated_port = port;
+- u_int32_t ip;
++ __be32 ip;
+
+ /* Set expectations for NAT */
+ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
+index 1d14996..329fdcd 100644
+--- a/net/ipv4/netfilter/ip_nat_helper_pptp.c
++++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c
+@@ -32,7 +32,7 @@
+ * 2005-06-10 - Version 3.0
+ * - kernel >= 2.6.11 version,
+ * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)
+- *
++ *
+ */
+
+ #include <linux/module.h>
+@@ -51,7 +51,7 @@
+
+ #define IP_NAT_PPTP_VERSION "3.0"
+
+-#define REQ_CID(req, off) (*(u_int16_t *)((char *)(req) + (off)))
++#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off)))
+
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Harald Welte <laforge at gnumonks.org>");
+@@ -85,19 +85,17 @@ static void pptp_nat_expected(struct ip_
+ DEBUGP("we are PNS->PAC\n");
+ /* therefore, build tuple for PAC->PNS */
+ t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+- t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id);
++ t.src.u.gre.key = master->help.ct_pptp_info.pac_call_id;
+ t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+- t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id);
++ t.dst.u.gre.key = master->help.ct_pptp_info.pns_call_id;
+ t.dst.protonum = IPPROTO_GRE;
+ } else {
+ DEBUGP("we are PAC->PNS\n");
+ /* build tuple for PNS->PAC */
+ t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+- t.src.u.gre.key =
+- htons(master->nat.help.nat_pptp_info.pns_call_id);
++ t.src.u.gre.key = master->nat.help.nat_pptp_info.pns_call_id;
+ t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+- t.dst.u.gre.key =
+- htons(master->nat.help.nat_pptp_info.pac_call_id);
++ t.dst.u.gre.key = master->nat.help.nat_pptp_info.pac_call_id;
+ t.dst.protonum = IPPROTO_GRE;
+ }
+
+@@ -149,51 +147,52 @@ pptp_outbound_pkt(struct sk_buff **pskb,
+ {
+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
+- u_int16_t msg, new_callid;
++ u_int16_t msg;
++ __be16 new_callid;
+ unsigned int cid_off;
+
+- new_callid = htons(ct_pptp_info->pns_call_id);
+-
++ new_callid = ct_pptp_info->pns_call_id;
++
+ switch (msg = ntohs(ctlh->messageType)) {
+- case PPTP_OUT_CALL_REQUEST:
+- cid_off = offsetof(union pptp_ctrl_union, ocreq.callID);
+- /* FIXME: ideally we would want to reserve a call ID
+- * here. current netfilter NAT core is not able to do
+- * this :( For now we use TCP source port. This breaks
+- * multiple calls within one control session */
+-
+- /* save original call ID in nat_info */
+- nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
+-
+- /* don't use tcph->source since we are at a DSTmanip
+- * hook (e.g. PREROUTING) and pkt is not mangled yet */
+- new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
+-
+- /* save new call ID in ct info */
+- ct_pptp_info->pns_call_id = ntohs(new_callid);
+- break;
+- case PPTP_IN_CALL_REPLY:
+- cid_off = offsetof(union pptp_ctrl_union, icreq.callID);
+- break;
+- case PPTP_CALL_CLEAR_REQUEST:
+- cid_off = offsetof(union pptp_ctrl_union, clrreq.callID);
+- break;
+- default:
+- DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
+- (msg <= PPTP_MSG_MAX)?
+- pptp_msg_name[msg]:pptp_msg_name[0]);
+- /* fall through */
+-
+- case PPTP_SET_LINK_INFO:
+- /* only need to NAT in case PAC is behind NAT box */
+- case PPTP_START_SESSION_REQUEST:
+- case PPTP_START_SESSION_REPLY:
+- case PPTP_STOP_SESSION_REQUEST:
+- case PPTP_STOP_SESSION_REPLY:
+- case PPTP_ECHO_REQUEST:
+- case PPTP_ECHO_REPLY:
+- /* no need to alter packet */
+- return NF_ACCEPT;
++ case PPTP_OUT_CALL_REQUEST:
++ cid_off = offsetof(union pptp_ctrl_union, ocreq.callID);
++ /* FIXME: ideally we would want to reserve a call ID
++ * here. current netfilter NAT core is not able to do
++ * this :( For now we use TCP source port. This breaks
++ * multiple calls within one control session */
++
++ /* save original call ID in nat_info */
++ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
++
++ /* don't use tcph->source since we are at a DSTmanip
++ * hook (e.g. PREROUTING) and pkt is not mangled yet */
++ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
++
++ /* save new call ID in ct info */
++ ct_pptp_info->pns_call_id = new_callid;
++ break;
++ case PPTP_IN_CALL_REPLY:
++ cid_off = offsetof(union pptp_ctrl_union, icack.callID);
++ break;
++ case PPTP_CALL_CLEAR_REQUEST:
++ cid_off = offsetof(union pptp_ctrl_union, clrreq.callID);
++ break;
++ default:
++ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
++ (msg <= PPTP_MSG_MAX)?
++ pptp_msg_name[msg]:pptp_msg_name[0]);
++ /* fall through */
++
++ case PPTP_SET_LINK_INFO:
++ /* only need to NAT in case PAC is behind NAT box */
++ case PPTP_START_SESSION_REQUEST:
++ case PPTP_START_SESSION_REPLY:
++ case PPTP_STOP_SESSION_REQUEST:
++ case PPTP_STOP_SESSION_REPLY:
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* no need to alter packet */
++ return NF_ACCEPT;
+ }
+
+ /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass
+@@ -212,80 +211,28 @@ pptp_outbound_pkt(struct sk_buff **pskb,
+ return NF_ACCEPT;
+ }
+
+-static int
++static void
+ pptp_exp_gre(struct ip_conntrack_expect *expect_orig,
+ struct ip_conntrack_expect *expect_reply)
+ {
+- struct ip_ct_pptp_master *ct_pptp_info =
+- &expect_orig->master->help.ct_pptp_info;
+- struct ip_nat_pptp *nat_pptp_info =
+- &expect_orig->master->nat.help.nat_pptp_info;
+-
+ struct ip_conntrack *ct = expect_orig->master;
+-
+- struct ip_conntrack_tuple inv_t;
+- struct ip_conntrack_tuple *orig_t, *reply_t;
++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
+
+ /* save original PAC call ID in nat_info */
+ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
+
+- /* alter expectation */
+- orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+- reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+-
+ /* alter expectation for PNS->PAC direction */
+- invert_tuplepr(&inv_t, &expect_orig->tuple);
+- expect_orig->saved_proto.gre.key = htons(ct_pptp_info->pns_call_id);
+- expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id);
+- expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);
++ expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id;
++ expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id;
++ expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id;
+ expect_orig->dir = IP_CT_DIR_ORIGINAL;
+- inv_t.src.ip = reply_t->src.ip;
+- inv_t.dst.ip = reply_t->dst.ip;
+- inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id);
+- inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);
+-
+- if (!ip_conntrack_expect_related(expect_orig)) {
+- DEBUGP("successfully registered expect\n");
+- } else {
+- DEBUGP("can't expect_related(expect_orig)\n");
+- return 1;
+- }
+
+ /* alter expectation for PAC->PNS direction */
+- invert_tuplepr(&inv_t, &expect_reply->tuple);
+- expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id);
+- expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id);
+- expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);
++ expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id;
++ expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id;
++ expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id;
+ expect_reply->dir = IP_CT_DIR_REPLY;
+- inv_t.src.ip = orig_t->src.ip;
+- inv_t.dst.ip = orig_t->dst.ip;
+- inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id);
+- inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);
+-
+- if (!ip_conntrack_expect_related(expect_reply)) {
+- DEBUGP("successfully registered expect\n");
+- } else {
+- DEBUGP("can't expect_related(expect_reply)\n");
+- ip_conntrack_unexpect_related(expect_orig);
+- return 1;
+- }
+-
+- if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) {
+- DEBUGP("can't register original keymap\n");
+- ip_conntrack_unexpect_related(expect_orig);
+- ip_conntrack_unexpect_related(expect_reply);
+- return 1;
+- }
+-
+- if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) {
+- DEBUGP("can't register reply keymap\n");
+- ip_conntrack_unexpect_related(expect_orig);
+- ip_conntrack_unexpect_related(expect_reply);
+- ip_ct_gre_keymap_destroy(ct);
+- return 1;
+- }
+-
+- return 0;
+ }
+
+ /* inbound packets == from PAC to PNS */
+@@ -297,15 +244,15 @@ pptp_inbound_pkt(struct sk_buff **pskb,
+ union pptp_ctrl_union *pptpReq)
+ {
+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
+- u_int16_t msg, new_cid = 0, new_pcid;
+- unsigned int pcid_off, cid_off = 0;
++ u_int16_t msg;
++ __be16 new_pcid;
++ unsigned int pcid_off;
+
+- new_pcid = htons(nat_pptp_info->pns_call_id);
++ new_pcid = nat_pptp_info->pns_call_id;
+
+ switch (msg = ntohs(ctlh->messageType)) {
+ case PPTP_OUT_CALL_REPLY:
+ pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID);
+- cid_off = offsetof(union pptp_ctrl_union, ocack.callID);
+ break;
+ case PPTP_IN_CALL_CONNECT:
+ pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID);
+@@ -324,7 +271,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
+ break;
+
+ default:
+- DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)?
++ DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)?
+ pptp_msg_name[msg]:pptp_msg_name[0]);
+ /* fall through */
+
+@@ -351,17 +298,6 @@ pptp_inbound_pkt(struct sk_buff **pskb,
+ sizeof(new_pcid), (char *)&new_pcid,
+ sizeof(new_pcid)) == 0)
+ return NF_DROP;
+-
+- if (new_cid) {
+- DEBUGP("altering call id from 0x%04x to 0x%04x\n",
+- ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_cid));
+- if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+- cid_off + sizeof(struct pptp_pkt_hdr) +
+- sizeof(struct PptpControlHeader),
+- sizeof(new_cid), (char *)&new_cid,
+- sizeof(new_cid)) == 0)
+- return NF_DROP;
+- }
+ return NF_ACCEPT;
+ }
+
+diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c
+index 38acfdf..bf91f93 100644
+--- a/net/ipv4/netfilter/ip_nat_proto_gre.c
++++ b/net/ipv4/netfilter/ip_nat_proto_gre.c
+@@ -6,10 +6,10 @@
+ * GRE is a generic encapsulation protocol, which is generally not very
+ * suited for NAT, as it has no protocol-specific part as port numbers.
+ *
+- * It has an optional key field, which may help us distinguishing two
++ * It has an optional key field, which may help us distinguishing two
+ * connections between the same two hosts.
+ *
+- * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
+ *
+ * PPTP is built on top of a modified version of GRE, and has a mandatory
+ * field called "CallID", which serves us for the same purpose as the key
+@@ -60,14 +60,14 @@ gre_in_range(const struct ip_conntrack_t
+ }
+
+ /* generate unique tuple ... */
+-static int
++static int
+ gre_unique_tuple(struct ip_conntrack_tuple *tuple,
+ const struct ip_nat_range *range,
+ enum ip_nat_manip_type maniptype,
+ const struct ip_conntrack *conntrack)
+ {
+ static u_int16_t key;
+- u_int16_t *keyptr;
++ __be16 *keyptr;
+ unsigned int min, i, range_size;
+
+ if (maniptype == IP_NAT_MANIP_SRC)
+@@ -84,7 +84,7 @@ gre_unique_tuple(struct ip_conntrack_tup
+ range_size = ntohs(range->max.gre.key) - min + 1;
+ }
+
+- DEBUGP("min = %u, range_size = %u\n", min, range_size);
++ DEBUGP("min = %u, range_size = %u\n", min, range_size);
+
+ for (i = 0; i < range_size; i++, key++) {
+ *keyptr = htons(min + key % range_size);
+@@ -117,7 +117,7 @@ gre_manip_pkt(struct sk_buff **pskb,
+ greh = (void *)(*pskb)->data + hdroff;
+ pgreh = (struct gre_hdr_pptp *) greh;
+
+- /* we only have destination manip of a packet, since 'source key'
++ /* we only have destination manip of a packet, since 'source key'
+ * is not present in the packet itself */
+ if (maniptype == IP_NAT_MANIP_DST) {
+ /* key manipulation is always dest */
+@@ -129,15 +129,16 @@ gre_manip_pkt(struct sk_buff **pskb,
+ }
+ if (greh->csum) {
+ /* FIXME: Never tested this code... */
+- *(gre_csum(greh)) =
+- ip_nat_cheat_check(~*(gre_key(greh)),
++ *(gre_csum(greh)) =
++ nf_proto_csum_update(*pskb,
++ ~*(gre_key(greh)),
+ tuple->dst.u.gre.key,
+- *(gre_csum(greh)));
++ *(gre_csum(greh)), 0);
+ }
+ *(gre_key(greh)) = tuple->dst.u.gre.key;
+ break;
+ case GRE_VERSION_PPTP:
+- DEBUGP("call_id -> 0x%04x\n",
++ DEBUGP("call_id -> 0x%04x\n",
+ ntohs(tuple->dst.u.gre.key));
+ pgreh->call_id = tuple->dst.u.gre.key;
+ break;
+@@ -151,8 +152,8 @@ gre_manip_pkt(struct sk_buff **pskb,
+ }
+
+ /* nat helper struct */
+-static struct ip_nat_protocol gre = {
+- .name = "GRE",
++static struct ip_nat_protocol gre = {
++ .name = "GRE",
+ .protonum = IPPROTO_GRE,
+ .manip_pkt = gre_manip_pkt,
+ .in_range = gre_in_range,
+@@ -163,7 +164,7 @@ static struct ip_nat_protocol gre = {
+ .nfattr_to_range = ip_nat_port_nfattr_to_range,
+ #endif
+ };
+-
++
+ int __init ip_nat_proto_gre_init(void)
+ {
+ return ip_nat_protocol_register(&gre);
+diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c
+index 31a3f4c..3f6efc1 100644
+--- a/net/ipv4/netfilter/ip_nat_proto_icmp.c
++++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c
+@@ -66,10 +66,10 @@ icmp_manip_pkt(struct sk_buff **pskb,
+ return 0;
+
+ hdr = (struct icmphdr *)((*pskb)->data + hdroff);
+-
+- hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF,
+- tuple->src.u.icmp.id,
+- hdr->checksum);
++ hdr->checksum = nf_proto_csum_update(*pskb,
++ hdr->un.echo.id ^ htons(0xFFFF),
++ tuple->src.u.icmp.id,
++ hdr->checksum, 0);
+ hdr->un.echo.id = tuple->src.u.icmp.id;
+ return 1;
+ }
+diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
+index a3d1407..12deb13 100644
+--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c
++++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c
+@@ -24,7 +24,7 @@ tcp_in_range(const struct ip_conntrack_t
+ const union ip_conntrack_manip_proto *min,
+ const union ip_conntrack_manip_proto *max)
+ {
+- u_int16_t port;
++ __be16 port;
+
+ if (maniptype == IP_NAT_MANIP_SRC)
+ port = tuple->src.u.tcp.port;
+@@ -42,7 +42,7 @@ tcp_unique_tuple(struct ip_conntrack_tup
+ const struct ip_conntrack *conntrack)
+ {
+ static u_int16_t port;
+- u_int16_t *portptr;
++ __be16 *portptr;
+ unsigned int range_size, min, i;
+
+ if (maniptype == IP_NAT_MANIP_SRC)
+@@ -93,8 +93,8 @@ tcp_manip_pkt(struct sk_buff **pskb,
+ struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
+ struct tcphdr *hdr;
+ unsigned int hdroff = iphdroff + iph->ihl*4;
+- u32 oldip, newip;
+- u16 *portptr, newport, oldport;
++ __be32 oldip, newip;
++ __be16 *portptr, newport, oldport;
+ int hdrsize = 8; /* TCP connection tracking guarantees this much */
+
+ /* this could be a inner header returned in icmp packet; in such
+@@ -129,10 +129,9 @@ tcp_manip_pkt(struct sk_buff **pskb,
+ if (hdrsize < sizeof(*hdr))
+ return 1;
+
+- hdr->check = ip_nat_cheat_check(~oldip, newip,
+- ip_nat_cheat_check(oldport ^ 0xFFFF,
+- newport,
+- hdr->check));
++ hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1);
++ hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport,
++ hdr->check, 0);
+ return 1;
+ }
+
+diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c
+index ec6053f..4bbec77 100644
+--- a/net/ipv4/netfilter/ip_nat_proto_udp.c
++++ b/net/ipv4/netfilter/ip_nat_proto_udp.c
+@@ -24,7 +24,7 @@ udp_in_range(const struct ip_conntrack_t
+ const union ip_conntrack_manip_proto *min,
+ const union ip_conntrack_manip_proto *max)
+ {
+- u_int16_t port;
++ __be16 port;
+
+ if (maniptype == IP_NAT_MANIP_SRC)
+ port = tuple->src.u.udp.port;
+@@ -42,7 +42,7 @@ udp_unique_tuple(struct ip_conntrack_tup
+ const struct ip_conntrack *conntrack)
+ {
+ static u_int16_t port;
+- u_int16_t *portptr;
++ __be16 *portptr;
+ unsigned int range_size, min, i;
+
+ if (maniptype == IP_NAT_MANIP_SRC)
+@@ -91,8 +91,8 @@ udp_manip_pkt(struct sk_buff **pskb,
+ struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
+ struct udphdr *hdr;
+ unsigned int hdroff = iphdroff + iph->ihl*4;
+- u32 oldip, newip;
+- u16 *portptr, newport;
++ __be32 oldip, newip;
++ __be16 *portptr, newport;
+
+ if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
+ return 0;
+@@ -113,11 +113,16 @@ udp_manip_pkt(struct sk_buff **pskb,
+ newport = tuple->dst.u.udp.port;
+ portptr = &hdr->dest;
+ }
+- if (hdr->check) /* 0 is a special case meaning no checksum */
+- hdr->check = ip_nat_cheat_check(~oldip, newip,
+- ip_nat_cheat_check(*portptr ^ 0xFFFF,
+- newport,
+- hdr->check));
++
++ if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
++ hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip,
++ hdr->check, 1);
++ hdr->check = nf_proto_csum_update(*pskb,
++ *portptr ^ htons(0xFFFF), newport,
++ hdr->check, 0);
++ if (!hdr->check)
++ hdr->check = -1;
++ }
+ *portptr = newport;
+ return 1;
+ }
+diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
+index 1aba926..a176aa3 100644
+--- a/net/ipv4/netfilter/ip_nat_rule.c
++++ b/net/ipv4/netfilter/ip_nat_rule.c
+@@ -19,14 +19,10 @@
+ #include <net/route.h>
+ #include <linux/bitops.h>
+
+-#define ASSERT_READ_LOCK(x)
+-#define ASSERT_WRITE_LOCK(x)
+-
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv4/ip_nat.h>
+ #include <linux/netfilter_ipv4/ip_nat_core.h>
+ #include <linux/netfilter_ipv4/ip_nat_rule.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #if 0
+ #define DEBUGP printk
+@@ -104,8 +100,7 @@ static unsigned int ipt_snat_target(stru
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct ipt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+@@ -124,7 +119,7 @@ static unsigned int ipt_snat_target(stru
+ }
+
+ /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
+-static void warn_if_extra_mangle(u32 dstip, u32 srcip)
++static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
+ {
+ static int warned = 0;
+ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
+@@ -147,8 +142,7 @@ static unsigned int ipt_dnat_target(stru
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct ipt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+@@ -174,7 +168,6 @@ static int ipt_snat_checkentry(const cha
+ const void *entry,
+ const struct ipt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct ip_nat_multi_range_compat *mr = targinfo;
+@@ -191,7 +184,6 @@ static int ipt_dnat_checkentry(const cha
+ const void *entry,
+ const struct ipt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct ip_nat_multi_range_compat *mr = targinfo;
+@@ -213,7 +205,7 @@ alloc_null_binding(struct ip_conntrack *
+ per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
+ Use reply in case it's already been mangled (eg local packet).
+ */
+- u_int32_t ip
++ __be32 ip
+ = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+ ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+ : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
+@@ -230,7 +222,7 @@ alloc_null_binding_confirmed(struct ip_c
+ struct ip_nat_info *info,
+ unsigned int hooknum)
+ {
+- u_int32_t ip
++ __be32 ip
+ = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+ ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+ : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
+@@ -255,7 +247,7 @@ int ip_nat_rule_find(struct sk_buff **ps
+ {
+ int ret;
+
+- ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
++ ret = ipt_do_table(pskb, hooknum, in, out, &nat_table);
+
+ if (ret == NF_ACCEPT) {
+ if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
+diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c
+index 6ffba63..71fc273 100644
+--- a/net/ipv4/netfilter/ip_nat_sip.c
++++ b/net/ipv4/netfilter/ip_nat_sip.c
+@@ -60,8 +60,8 @@ static unsigned int ip_nat_sip(struct sk
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+ unsigned int bufflen, dataoff;
+- u_int32_t ip;
+- u_int16_t port;
++ __be32 ip;
++ __be16 port;
+
+ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+
+@@ -159,7 +159,7 @@ static int mangle_content_len(struct sk_
+ static unsigned int mangle_sdp(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+- u_int32_t newip, u_int16_t port,
++ __be32 newip, u_int16_t port,
+ const char *dptr)
+ {
+ char buffer[sizeof("nnn.nnn.nnn.nnn")];
+@@ -195,7 +195,7 @@ static unsigned int ip_nat_sdp(struct sk
+ {
+ struct ip_conntrack *ct = exp->master;
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+- u_int32_t newip;
++ __be32 newip;
+ u_int16_t port;
+
+ DEBUGP("ip_nat_sdp():\n");
+diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
+index 18b7fbd..168f45f 100644
+--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
++++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
+@@ -1211,7 +1211,7 @@ static int snmp_translate(struct ip_conn
+ struct sk_buff **pskb)
+ {
+ struct iphdr *iph = (*pskb)->nh.iph;
+- struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
++ struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
+ u_int16_t udplen = ntohs(udph->len);
+ u_int16_t paylen = udplen - sizeof(struct udphdr);
+ int dir = CTINFO2DIR(ctinfo);
+diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
+index 17de077..d85d2de 100644
+--- a/net/ipv4/netfilter/ip_nat_standalone.c
++++ b/net/ipv4/netfilter/ip_nat_standalone.c
+@@ -30,9 +30,6 @@
+ #include <net/checksum.h>
+ #include <linux/spinlock.h>
+
+-#define ASSERT_READ_LOCK(x)
+-#define ASSERT_WRITE_LOCK(x)
+-
+ #include <linux/netfilter_ipv4/ip_nat.h>
+ #include <linux/netfilter_ipv4/ip_nat_rule.h>
+ #include <linux/netfilter_ipv4/ip_nat_protocol.h>
+@@ -40,7 +37,6 @@
+ #include <linux/netfilter_ipv4/ip_nat_helper.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #if 0
+ #define DEBUGP printk
+@@ -110,11 +106,6 @@ ip_nat_fn(unsigned int hooknum,
+ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
+ & htons(IP_MF|IP_OFFSET)));
+
+- /* If we had a hardware checksum before, it's now invalid */
+- if ((*pskb)->ip_summed == CHECKSUM_HW)
+- if (skb_checksum_help(*pskb, (out == NULL)))
+- return NF_DROP;
+-
+ ct = ip_conntrack_get(*pskb, &ctinfo);
+ /* Can't track? It's not due to stress, or conntrack would
+ have dropped it. Hence it's the user's responsibilty to
+@@ -145,8 +136,8 @@ ip_nat_fn(unsigned int hooknum,
+ case IP_CT_RELATED:
+ case IP_CT_RELATED+IP_CT_IS_REPLY:
+ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
+- if (!ip_nat_icmp_reply_translation(pskb, ct, maniptype,
+- CTINFO2DIR(ctinfo)))
++ if (!ip_nat_icmp_reply_translation(ct, ctinfo,
++ hooknum, pskb))
+ return NF_DROP;
+ else
+ return NF_ACCEPT;
+@@ -200,7 +191,7 @@ ip_nat_in(unsigned int hooknum,
+ int (*okfn)(struct sk_buff *))
+ {
+ unsigned int ret;
+- u_int32_t daddr = (*pskb)->nh.iph->daddr;
++ __be32 daddr = (*pskb)->nh.iph->daddr;
+
+ ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+ if (ret != NF_DROP && ret != NF_STOLEN
+@@ -274,7 +265,8 @@ ip_nat_local_fn(unsigned int hooknum,
+ ct->tuplehash[!dir].tuple.src.u.all
+ #endif
+ )
+- return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
++ if (ip_route_me_harder(pskb, RTN_UNSPEC))
++ ret = NF_DROP;
+ }
+ return ret;
+ }
+diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
+index 198ac36..7edad79 100644
+--- a/net/ipv4/netfilter/ip_queue.c
++++ b/net/ipv4/netfilter/ip_queue.c
+@@ -52,15 +52,15 @@ struct ipq_queue_entry {
+
+ typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+-static unsigned char copy_mode = IPQ_COPY_NONE;
+-static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
++static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
++static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
+ static DEFINE_RWLOCK(queue_lock);
+-static int peer_pid;
+-static unsigned int copy_range;
++static int peer_pid __read_mostly;
++static unsigned int copy_range __read_mostly;
+ static unsigned int queue_total;
+ static unsigned int queue_dropped = 0;
+ static unsigned int queue_user_dropped = 0;
+-static struct sock *ipqnl;
++static struct sock *ipqnl __read_mostly;
+ static LIST_HEAD(queue_list);
+ static DEFINE_MUTEX(ipqnl_mutex);
+
+@@ -208,9 +208,9 @@ ipq_build_packet_message(struct ipq_queu
+ break;
+
+ case IPQ_COPY_PACKET:
+- if (entry->skb->ip_summed == CHECKSUM_HW &&
+- (*errp = skb_checksum_help(entry->skb,
+- entry->info->outdev == NULL))) {
++ if ((entry->skb->ip_summed == CHECKSUM_PARTIAL ||
++ entry->skb->ip_summed == CHECKSUM_COMPLETE) &&
++ (*errp = skb_checksum_help(entry->skb))) {
+ read_unlock_bh(&queue_lock);
+ return NULL;
+ }
+diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
+index 048514f..8a45543 100644
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -180,8 +180,7 @@ ipt_error(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ if (net_ratelimit())
+ printk("ip_tables: error: `%s'\n", (char *)targinfo);
+@@ -217,8 +216,7 @@ ipt_do_table(struct sk_buff **pskb,
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+- struct ipt_table *table,
+- void *userdata)
++ struct ipt_table *table)
+ {
+ static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
+ u_int16_t offset;
+@@ -308,8 +306,7 @@ ipt_do_table(struct sk_buff **pskb,
+ in, out,
+ hook,
+ t->u.kernel.target,
+- t->data,
+- userdata);
++ t->data);
+
+ #ifdef CONFIG_NETFILTER_DEBUG
+ if (((struct ipt_entry *)table_base)->comefrom
+@@ -467,8 +464,7 @@ cleanup_match(struct ipt_entry_match *m,
+ return 1;
+
+ if (m->u.kernel.match->destroy)
+- m->u.kernel.match->destroy(m->u.kernel.match, m->data,
+- m->u.match_size - sizeof(*m));
++ m->u.kernel.match->destroy(m->u.kernel.match, m->data);
+ module_put(m->u.kernel.match->me);
+ return 0;
+ }
+@@ -521,7 +517,6 @@ check_match(struct ipt_entry_match *m,
+
+ if (m->u.kernel.match->checkentry
+ && !m->u.kernel.match->checkentry(name, ip, match, m->data,
+- m->u.match_size - sizeof(*m),
+ hookmask)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ m->u.kernel.match->name);
+@@ -552,12 +547,18 @@ check_entry(struct ipt_entry *e, const c
+ return -EINVAL;
+ }
+
++ if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
++ return -EINVAL;
++
+ j = 0;
+ ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
+ if (ret != 0)
+ goto cleanup_matches;
+
+ t = ipt_get_target(e);
++ ret = -EINVAL;
++ if (e->target_offset + t->u.target_size > e->next_offset)
++ goto cleanup_matches;
+ target = try_then_request_module(xt_find_target(AF_INET,
+ t->u.user.name,
+ t->u.user.revision),
+@@ -578,12 +579,10 @@ check_entry(struct ipt_entry *e, const c
+ if (t->u.kernel.target == &ipt_standard_target) {
+ if (!standard_check(t, size)) {
+ ret = -EINVAL;
+- goto cleanup_matches;
++ goto err;
+ }
+ } else if (t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(name, e, target, t->data,
+- t->u.target_size
+- - sizeof(*t),
+ e->comefrom)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ t->u.kernel.target->name);
+@@ -655,8 +654,7 @@ cleanup_entry(struct ipt_entry *e, unsig
+ IPT_MATCH_ITERATE(e, cleanup_match, NULL);
+ t = ipt_get_target(e);
+ if (t->u.kernel.target->destroy)
+- t->u.kernel.target->destroy(t->u.kernel.target, t->data,
+- t->u.target_size - sizeof(*t));
++ t->u.kernel.target->destroy(t->u.kernel.target, t->data);
+ module_put(t->u.kernel.target->me);
+ return 0;
+ }
+@@ -720,19 +718,17 @@ translate_table(const char *name,
+ }
+ }
+
+- if (!mark_source_chains(newinfo, valid_hooks, entry0))
+- return -ELOOP;
+-
+ /* Finally, each sanity check must pass */
+ i = 0;
+ ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
+ check_entry, name, size, &i);
+
+- if (ret != 0) {
+- IPT_ENTRY_ITERATE(entry0, newinfo->size,
+- cleanup_entry, &i);
+- return ret;
+- }
++ if (ret != 0)
++ goto cleanup;
++
++ ret = -ELOOP;
++ if (!mark_source_chains(newinfo, valid_hooks, entry0))
++ goto cleanup;
+
+ /* And one copy for every other CPU */
+ for_each_possible_cpu(i) {
+@@ -740,6 +736,9 @@ translate_table(const char *name,
+ memcpy(newinfo->entries[i], entry0, newinfo->size);
+ }
+
++ return 0;
++cleanup:
++ IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
+ return ret;
+ }
+
+@@ -950,73 +949,28 @@ static short compat_calc_jump(u_int16_t
+ return delta;
+ }
+
+-struct compat_ipt_standard_target
++static void compat_standard_from_user(void *dst, void *src)
+ {
+- struct compat_xt_entry_target target;
+- compat_int_t verdict;
+-};
+-
+-struct compat_ipt_standard
+-{
+- struct compat_ipt_entry entry;
+- struct compat_ipt_standard_target target;
+-};
++ int v = *(compat_int_t *)src;
+
+-#define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target))
+-#define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target))
+-#define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN)
++ if (v > 0)
++ v += compat_calc_jump(v);
++ memcpy(dst, &v, sizeof(v));
++}
+
+-static int compat_ipt_standard_fn(void *target,
+- void **dstptr, int *size, int convert)
++static int compat_standard_to_user(void __user *dst, void *src)
+ {
+- struct compat_ipt_standard_target compat_st, *pcompat_st;
+- struct ipt_standard_target st, *pst;
+- int ret;
++ compat_int_t cv = *(int *)src;
+
+- ret = 0;
+- switch (convert) {
+- case COMPAT_TO_USER:
+- pst = target;
+- memcpy(&compat_st.target, &pst->target,
+- sizeof(compat_st.target));
+- compat_st.verdict = pst->verdict;
+- if (compat_st.verdict > 0)
+- compat_st.verdict -=
+- compat_calc_jump(compat_st.verdict);
+- compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN;
+- if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN))
+- ret = -EFAULT;
+- *size -= IPT_ST_OFFSET;
+- *dstptr += IPT_ST_COMPAT_LEN;
+- break;
+- case COMPAT_FROM_USER:
+- pcompat_st = target;
+- memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN);
+- st.verdict = pcompat_st->verdict;
+- if (st.verdict > 0)
+- st.verdict += compat_calc_jump(st.verdict);
+- st.target.u.user.target_size = IPT_ST_LEN;
+- memcpy(*dstptr, &st, IPT_ST_LEN);
+- *size += IPT_ST_OFFSET;
+- *dstptr += IPT_ST_LEN;
+- break;
+- case COMPAT_CALC_SIZE:
+- *size += IPT_ST_OFFSET;
+- break;
+- default:
+- ret = -ENOPROTOOPT;
+- break;
+- }
+- return ret;
++ if (cv > 0)
++ cv -= compat_calc_jump(cv);
++ return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
+ }
+
+ static inline int
+ compat_calc_match(struct ipt_entry_match *m, int * size)
+ {
+- if (m->u.kernel.match->compat)
+- m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
+- else
+- xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
++ *size += xt_compat_match_offset(m->u.kernel.match);
+ return 0;
+ }
+
+@@ -1031,10 +985,7 @@ static int compat_calc_entry(struct ipt_
+ entry_offset = (void *)e - base;
+ IPT_MATCH_ITERATE(e, compat_calc_match, &off);
+ t = ipt_get_target(e);
+- if (t->u.kernel.target->compat)
+- t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
+- else
+- xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
++ off += xt_compat_target_offset(t->u.kernel.target);
+ newinfo->size -= off;
+ ret = compat_add_offset(entry_offset, off);
+ if (ret)
+@@ -1422,17 +1373,13 @@ struct compat_ipt_replace {
+ static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
+ void __user **dstptr, compat_uint_t *size)
+ {
+- if (m->u.kernel.match->compat)
+- return m->u.kernel.match->compat(m, dstptr, size,
+- COMPAT_TO_USER);
+- else
+- return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
++ return xt_compat_match_to_user(m, dstptr, size);
+ }
+
+ static int compat_copy_entry_to_user(struct ipt_entry *e,
+ void __user **dstptr, compat_uint_t *size)
+ {
+- struct ipt_entry_target __user *t;
++ struct ipt_entry_target *t;
+ struct compat_ipt_entry __user *ce;
+ u_int16_t target_offset, next_offset;
+ compat_uint_t origsize;
+@@ -1450,11 +1397,7 @@ static int compat_copy_entry_to_user(str
+ if (ret)
+ goto out;
+ t = ipt_get_target(e);
+- if (t->u.kernel.target->compat)
+- ret = t->u.kernel.target->compat(t, dstptr, size,
+- COMPAT_TO_USER);
+- else
+- ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
++ ret = xt_compat_target_to_user(t, dstptr, size);
+ if (ret)
+ goto out;
+ ret = -EFAULT;
+@@ -1486,11 +1429,7 @@ compat_check_calc_match(struct ipt_entry
+ return match ? PTR_ERR(match) : -ENOENT;
+ }
+ m->u.kernel.match = match;
+-
+- if (m->u.kernel.match->compat)
+- m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
+- else
+- xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
++ *size += xt_compat_match_offset(match);
+
+ (*i)++;
+ return 0;
+@@ -1531,15 +1470,22 @@ check_compat_entry_size_and_hooks(struct
+ return -EINVAL;
+ }
+
++ if (e->target_offset + sizeof(struct compat_xt_entry_target) >
++ e->next_offset)
++ return -EINVAL;
++
+ off = 0;
+ entry_offset = (void *)e - (void *)base;
+ j = 0;
+ ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
+ e->comefrom, &off, &j);
+ if (ret != 0)
+- goto out;
++ goto cleanup_matches;
+
+ t = ipt_get_target(e);
++ ret = -EINVAL;
++ if (e->target_offset + t->u.target_size > e->next_offset)
++ goto cleanup_matches;
+ target = try_then_request_module(xt_find_target(AF_INET,
+ t->u.user.name,
+ t->u.user.revision),
+@@ -1547,14 +1493,11 @@ check_compat_entry_size_and_hooks(struct
+ if (IS_ERR(target) || !target) {
+ duprintf("check_entry: `%s' not found\n", t->u.user.name);
+ ret = target ? PTR_ERR(target) : -ENOENT;
+- goto out;
++ goto cleanup_matches;
+ }
+ t->u.kernel.target = target;
+
+- if (t->u.kernel.target->compat)
+- t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
+- else
+- xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
++ off += xt_compat_target_offset(target);
+ *size += off;
+ ret = compat_add_offset(entry_offset, off);
+ if (ret)
+@@ -1574,7 +1517,10 @@ check_compat_entry_size_and_hooks(struct
+
+ (*i)++;
+ return 0;
++
+ out:
++ module_put(t->u.kernel.target->me);
++cleanup_matches:
+ IPT_MATCH_ITERATE(e, cleanup_match, &j);
+ return ret;
+ }
+@@ -1589,26 +1535,19 @@ static inline int compat_copy_match_from
+
+ dm = (struct ipt_entry_match *)*dstptr;
+ match = m->u.kernel.match;
+- if (match->compat)
+- match->compat(m, dstptr, size, COMPAT_FROM_USER);
+- else
+- xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
++ xt_compat_match_from_user(m, dstptr, size);
+
+ ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
+ name, hookmask, ip->proto,
+ ip->invflags & IPT_INV_PROTO);
+- if (ret)
+- return ret;
+-
+- if (m->u.kernel.match->checkentry
++ if (!ret && m->u.kernel.match->checkentry
+ && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
+- dm->u.match_size - sizeof(*dm),
+ hookmask)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ m->u.kernel.match->name);
+- return -EINVAL;
++ ret = -EINVAL;
+ }
+- return 0;
++ return ret;
+ }
+
+ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
+@@ -1630,14 +1569,11 @@ static int compat_copy_entry_from_user(s
+ ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
+ name, &de->ip, de->comefrom);
+ if (ret)
+- goto out;
++ goto err;
+ de->target_offset = e->target_offset - (origsize - *size);
+ t = ipt_get_target(e);
+ target = t->u.kernel.target;
+- if (target->compat)
+- target->compat(t, dstptr, size, COMPAT_FROM_USER);
+- else
+- xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
++ xt_compat_target_from_user(t, dstptr, size);
+
+ de->next_offset = e->next_offset - (origsize - *size);
+ for (h = 0; h < NF_IP_NUMHOOKS; h++) {
+@@ -1653,22 +1589,21 @@ static int compat_copy_entry_from_user(s
+ name, e->comefrom, e->ip.proto,
+ e->ip.invflags & IPT_INV_PROTO);
+ if (ret)
+- goto out;
++ goto err;
+
+ ret = -EINVAL;
+ if (t->u.kernel.target == &ipt_standard_target) {
+ if (!standard_check(t, *size))
+- goto out;
++ goto err;
+ } else if (t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(name, de, target,
+- t->data, t->u.target_size - sizeof(*t),
+- de->comefrom)) {
++ t->data, de->comefrom)) {
+ duprintf("ip_tables: compat: check failed for `%s'.\n",
+ t->u.kernel.target->name);
+- goto out;
++ goto err;
+ }
+ ret = 0;
+-out:
++err:
+ return ret;
+ }
+
+@@ -1682,7 +1617,7 @@ translate_compat_table(const char *name,
+ unsigned int *hook_entries,
+ unsigned int *underflows)
+ {
+- unsigned int i;
++ unsigned int i, j;
+ struct xt_table_info *newinfo, *info;
+ void *pos, *entry0, *entry1;
+ unsigned int size;
+@@ -1700,21 +1635,21 @@ translate_compat_table(const char *name,
+ }
+
+ duprintf("translate_compat_table: size %u\n", info->size);
+- i = 0;
++ j = 0;
+ xt_compat_lock(AF_INET);
+ /* Walk through entries, checking offsets. */
+ ret = IPT_ENTRY_ITERATE(entry0, total_size,
+ check_compat_entry_size_and_hooks,
+ info, &size, entry0,
+ entry0 + total_size,
+- hook_entries, underflows, &i, name);
++ hook_entries, underflows, &j, name);
+ if (ret != 0)
+ goto out_unlock;
+
+ ret = -EINVAL;
+- if (i != number) {
++ if (j != number) {
+ duprintf("translate_compat_table: %u not %u entries\n",
+- i, number);
++ j, number);
+ goto out_unlock;
+ }
+
+@@ -1773,8 +1708,10 @@ translate_compat_table(const char *name,
+ free_newinfo:
+ xt_free_table_info(newinfo);
+ out:
++ IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
+ return ret;
+ out_unlock:
++ compat_flush_offsets();
+ xt_compat_unlock(AF_INET);
+ goto out;
+ }
+@@ -1989,11 +1926,16 @@ compat_get_entries(struct compat_ipt_get
+ return ret;
+ }
+
++static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
++
+ static int
+ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+ {
+ int ret;
+
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
+ switch (cmd) {
+ case IPT_SO_GET_INFO:
+ ret = get_info(user, len, 1);
+@@ -2002,8 +1944,7 @@ compat_do_ipt_get_ctl(struct sock *sk, i
+ ret = compat_get_entries(user, len);
+ break;
+ default:
+- duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd);
+- ret = -EINVAL;
++ ret = do_ipt_get_ctl(sk, cmd, user, len);
+ }
+ return ret;
+ }
+@@ -2185,7 +2126,6 @@ icmp_checkentry(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_icmp *icmpinfo = matchinfo;
+@@ -2200,7 +2140,9 @@ static struct ipt_target ipt_standard_ta
+ .targetsize = sizeof(int),
+ .family = AF_INET,
+ #ifdef CONFIG_COMPAT
+- .compat = &compat_ipt_standard_fn,
++ .compatsize = sizeof(compat_int_t),
++ .compat_from_user = compat_standard_from_user,
++ .compat_to_user = compat_standard_to_user,
+ #endif
+ };
+
+diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
+index d994c5f..7a29d6e 100644
+--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
++++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
+@@ -52,7 +52,7 @@ struct clusterip_config {
+ atomic_t entries; /* number of entries/rules
+ * referencing us */
+
+- u_int32_t clusterip; /* the IP address */
++ __be32 clusterip; /* the IP address */
+ u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
+ struct net_device *dev; /* device */
+ u_int16_t num_total_nodes; /* total number of nodes */
+@@ -119,7 +119,7 @@ clusterip_config_entry_put(struct cluste
+ }
+
+ static struct clusterip_config *
+-__clusterip_config_find(u_int32_t clusterip)
++__clusterip_config_find(__be32 clusterip)
+ {
+ struct list_head *pos;
+
+@@ -136,7 +136,7 @@ __clusterip_config_find(u_int32_t cluste
+ }
+
+ static inline struct clusterip_config *
+-clusterip_config_find_get(u_int32_t clusterip, int entry)
++clusterip_config_find_get(__be32 clusterip, int entry)
+ {
+ struct clusterip_config *c;
+
+@@ -166,7 +166,7 @@ clusterip_config_init_nodelist(struct cl
+ }
+
+ static struct clusterip_config *
+-clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip,
++clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
+ struct net_device *dev)
+ {
+ struct clusterip_config *c;
+@@ -302,8 +302,7 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+ enum ip_conntrack_info ctinfo;
+@@ -373,7 +372,6 @@ checkentry(const char *tablename,
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+@@ -389,7 +387,7 @@ checkentry(const char *tablename,
+ return 0;
+
+ }
+- if (e->ip.dmsk.s_addr != 0xffffffff
++ if (e->ip.dmsk.s_addr != htonl(0xffffffff)
+ || e->ip.dst.s_addr == 0) {
+ printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
+ return 0;
+@@ -450,8 +448,7 @@ checkentry(const char *tablename,
+ }
+
+ /* drop reference count of cluster config when rule is deleted */
+-static void destroy(const struct xt_target *target, void *targinfo,
+- unsigned int targinfosize)
++static void destroy(const struct xt_target *target, void *targinfo)
+ {
+ struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+
+@@ -479,9 +476,9 @@ static struct ipt_target clusterip_tgt =
+ /* hardcoded for 48bit ethernet and 32bit ipv4 addresses */
+ struct arp_payload {
+ u_int8_t src_hw[ETH_ALEN];
+- u_int32_t src_ip;
++ __be32 src_ip;
+ u_int8_t dst_hw[ETH_ALEN];
+- u_int32_t dst_ip;
++ __be32 dst_ip;
+ } __attribute__ ((packed));
+
+ #ifdef CLUSTERIP_DEBUG
+diff --git a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c
+deleted file mode 100644
+index c8e9712..0000000
+--- a/net/ipv4/netfilter/ipt_DSCP.c
++++ /dev/null
+@@ -1,96 +0,0 @@
+-/* iptables module for setting the IPv4 DSCP field, Version 1.8
+- *
+- * (C) 2002 by Harald Welte <laforge at netfilter.org>
+- * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm at paktronix.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.
+- *
+- * See RFC2474 for a description of the DSCP field within the IP Header.
+- *
+- * ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
+-*/
+-
+-#include <linux/module.h>
+-#include <linux/skbuff.h>
+-#include <linux/ip.h>
+-#include <net/checksum.h>
+-
+-#include <linux/netfilter_ipv4/ip_tables.h>
+-#include <linux/netfilter_ipv4/ipt_DSCP.h>
+-
+-MODULE_AUTHOR("Harald Welte <laforge at netfilter.org>");
+-MODULE_DESCRIPTION("iptables DSCP modification module");
+-MODULE_LICENSE("GPL");
+-
+-static unsigned int
+-target(struct sk_buff **pskb,
+- const struct net_device *in,
+- const struct net_device *out,
+- unsigned int hooknum,
+- const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
+-{
+- const struct ipt_DSCP_info *dinfo = targinfo;
+- u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+-
+-
+- if (((*pskb)->nh.iph->tos & IPT_DSCP_MASK) != sh_dscp) {
+- u_int16_t diffs[2];
+-
+- if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+- return NF_DROP;
+-
+- diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
+- (*pskb)->nh.iph->tos = ((*pskb)->nh.iph->tos & ~IPT_DSCP_MASK)
+- | sh_dscp;
+- diffs[1] = htons((*pskb)->nh.iph->tos);
+- (*pskb)->nh.iph->check
+- = csum_fold(csum_partial((char *)diffs,
+- sizeof(diffs),
+- (*pskb)->nh.iph->check
+- ^ 0xFFFF));
+- }
+- return IPT_CONTINUE;
+-}
+-
+-static int
+-checkentry(const char *tablename,
+- const void *e_void,
+- const struct xt_target *target,
+- void *targinfo,
+- unsigned int targinfosize,
+- unsigned int hook_mask)
+-{
+- const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
+-
+- if ((dscp > IPT_DSCP_MAX)) {
+- printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
+- return 0;
+- }
+- return 1;
+-}
+-
+-static struct ipt_target ipt_dscp_reg = {
+- .name = "DSCP",
+- .target = target,
+- .targetsize = sizeof(struct ipt_DSCP_info),
+- .table = "mangle",
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
+-};
+-
+-static int __init ipt_dscp_init(void)
+-{
+- return ipt_register_target(&ipt_dscp_reg);
+-}
+-
+-static void __exit ipt_dscp_fini(void)
+-{
+- ipt_unregister_target(&ipt_dscp_reg);
+-}
+-
+-module_init(ipt_dscp_init);
+-module_exit(ipt_dscp_fini);
+diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
+index 4adf5c9..1aa4517 100644
+--- a/net/ipv4/netfilter/ipt_ECN.c
++++ b/net/ipv4/netfilter/ipt_ECN.c
+@@ -27,32 +27,28 @@ MODULE_DESCRIPTION("iptables ECN modific
+ static inline int
+ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
+ {
+- if (((*pskb)->nh.iph->tos & IPT_ECN_IP_MASK)
+- != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
+- u_int16_t diffs[2];
++ struct iphdr *iph = (*pskb)->nh.iph;
++ u_int16_t oldtos;
+
++ if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
+ if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+ return 0;
+-
+- diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
+- (*pskb)->nh.iph->tos &= ~IPT_ECN_IP_MASK;
+- (*pskb)->nh.iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
+- diffs[1] = htons((*pskb)->nh.iph->tos);
+- (*pskb)->nh.iph->check
+- = csum_fold(csum_partial((char *)diffs,
+- sizeof(diffs),
+- (*pskb)->nh.iph->check
+- ^0xFFFF));
++ iph = (*pskb)->nh.iph;
++ oldtos = iph->tos;
++ iph->tos &= ~IPT_ECN_IP_MASK;
++ iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
++ iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
++ htons(iph->tos), iph->check);
+ }
+ return 1;
+ }
+
+ /* Return 0 if there was an error. */
+ static inline int
+-set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
++set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
+ {
+ struct tcphdr _tcph, *tcph;
+- u_int16_t diffs[2];
++ __be16 oldval;
+
+ /* Not enought header? */
+ tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
+@@ -70,22 +66,16 @@ set_ect_tcp(struct sk_buff **pskb, const
+ return 0;
+ tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4;
+
+- if ((*pskb)->ip_summed == CHECKSUM_HW &&
+- skb_checksum_help(*pskb, inward))
+- return 0;
+-
+- diffs[0] = ((u_int16_t *)tcph)[6];
++ oldval = ((__be16 *)tcph)[6];
+ if (einfo->operation & IPT_ECN_OP_SET_ECE)
+ tcph->ece = einfo->proto.tcp.ece;
+ if (einfo->operation & IPT_ECN_OP_SET_CWR)
+ tcph->cwr = einfo->proto.tcp.cwr;
+- diffs[1] = ((u_int16_t *)tcph)[6];
+- diffs[0] = diffs[0] ^ 0xFFFF;
+
+- if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY)
+- tcph->check = csum_fold(csum_partial((char *)diffs,
+- sizeof(diffs),
+- tcph->check^0xFFFF));
++ tcph->check = nf_proto_csum_update((*pskb),
++ oldval ^ htons(0xFFFF),
++ ((__be16 *)tcph)[6],
++ tcph->check, 0);
+ return 1;
+ }
+
+@@ -95,8 +85,7 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ipt_ECN_info *einfo = targinfo;
+
+@@ -106,7 +95,7 @@ target(struct sk_buff **pskb,
+
+ if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
+ && (*pskb)->nh.iph->protocol == IPPROTO_TCP)
+- if (!set_ect_tcp(pskb, einfo, (out == NULL)))
++ if (!set_ect_tcp(pskb, einfo))
+ return NF_DROP;
+
+ return IPT_CONTINUE;
+@@ -117,7 +106,6 @@ checkentry(const char *tablename,
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
+diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
+index b98f7b0..7dc820d 100644
+--- a/net/ipv4/netfilter/ipt_LOG.c
++++ b/net/ipv4/netfilter/ipt_LOG.c
+@@ -416,8 +416,7 @@ ipt_log_target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ipt_log_info *loginfo = targinfo;
+ struct nf_loginfo li;
+@@ -440,7 +439,6 @@ static int ipt_log_checkentry(const char
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_log_info *loginfo = targinfo;
+diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
+index ebd94f2..3dbfcfa 100644
+--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
++++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
+@@ -42,7 +42,6 @@ masquerade_check(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip_nat_multi_range_compat *mr = targinfo;
+@@ -64,15 +63,14 @@ masquerade_target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+ const struct ip_nat_multi_range_compat *mr;
+ struct ip_nat_range newrange;
+ struct rtable *rt;
+- u_int32_t newsrc;
++ __be32 newsrc;
+
+ IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
+index 736c4b5..58a88f2 100644
+--- a/net/ipv4/netfilter/ipt_NETMAP.c
++++ b/net/ipv4/netfilter/ipt_NETMAP.c
+@@ -33,7 +33,6 @@ check(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip_nat_multi_range_compat *mr = targinfo;
+@@ -55,12 +54,11 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+- u_int32_t new_ip, netmask;
++ __be32 new_ip, netmask;
+ const struct ip_nat_multi_range_compat *mr = targinfo;
+ struct ip_nat_range newrange;
+
+diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
+index f290463..c0dcfe9 100644
+--- a/net/ipv4/netfilter/ipt_REDIRECT.c
++++ b/net/ipv4/netfilter/ipt_REDIRECT.c
+@@ -36,7 +36,6 @@ redirect_check(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip_nat_multi_range_compat *mr = targinfo;
+@@ -58,12 +57,11 @@ redirect_target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+- u_int32_t newdst;
++ __be32 newdst;
+ const struct ip_nat_multi_range_compat *mr = targinfo;
+ struct ip_nat_range newrange;
+
+diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
+index 269bc20..ad0312d 100644
+--- a/net/ipv4/netfilter/ipt_REJECT.c
++++ b/net/ipv4/netfilter/ipt_REJECT.c
+@@ -38,75 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT targ
+ #define DEBUGP(format, args...)
+ #endif
+
+-static inline struct rtable *route_reverse(struct sk_buff *skb,
+- struct tcphdr *tcph, int hook)
+-{
+- struct iphdr *iph = skb->nh.iph;
+- struct dst_entry *odst;
+- struct flowi fl = {};
+- struct rtable *rt;
+-
+- /* We don't require ip forwarding to be enabled to be able to
+- * send a RST reply for bridged traffic. */
+- if (hook != NF_IP_FORWARD
+-#ifdef CONFIG_BRIDGE_NETFILTER
+- || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
+-#endif
+- ) {
+- fl.nl_u.ip4_u.daddr = iph->saddr;
+- if (hook == NF_IP_LOCAL_IN)
+- fl.nl_u.ip4_u.saddr = iph->daddr;
+- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+-
+- if (ip_route_output_key(&rt, &fl) != 0)
+- return NULL;
+- } else {
+- /* non-local src, find valid iif to satisfy
+- * rp-filter when calling ip_route_input. */
+- fl.nl_u.ip4_u.daddr = iph->daddr;
+- if (ip_route_output_key(&rt, &fl) != 0)
+- return NULL;
+-
+- odst = skb->dst;
+- if (ip_route_input(skb, iph->saddr, iph->daddr,
+- RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+- dst_release(&rt->u.dst);
+- return NULL;
+- }
+- dst_release(&rt->u.dst);
+- rt = (struct rtable *)skb->dst;
+- skb->dst = odst;
+-
+- fl.nl_u.ip4_u.daddr = iph->saddr;
+- fl.nl_u.ip4_u.saddr = iph->daddr;
+- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+- }
+-
+- if (rt->u.dst.error) {
+- dst_release(&rt->u.dst);
+- return NULL;
+- }
+-
+- fl.proto = IPPROTO_TCP;
+- fl.fl_ip_sport = tcph->dest;
+- fl.fl_ip_dport = tcph->source;
+-
+- xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
+-
+- return rt;
+-}
+-
+ /* Send RST reply */
+ static void send_reset(struct sk_buff *oldskb, int hook)
+ {
+ struct sk_buff *nskb;
+ struct iphdr *iph = oldskb->nh.iph;
+ struct tcphdr _otcph, *oth, *tcph;
+- struct rtable *rt;
+- u_int16_t tmp_port;
+- u_int32_t tmp_addr;
++ __be16 tmp_port;
++ __be32 tmp_addr;
+ int needs_ack;
+- int hh_len;
++ unsigned int addr_type;
+
+ /* IP header checks: fragment. */
+ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
+@@ -125,23 +66,13 @@ static void send_reset(struct sk_buff *o
+ if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
+ return;
+
+- if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
+- return;
+-
+- hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+-
+ /* We need a linear, writeable skb. We also need to expand
+ headroom in case hh_len of incoming interface < hh_len of
+ outgoing interface */
+- nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
++ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
+ GFP_ATOMIC);
+- if (!nskb) {
+- dst_release(&rt->u.dst);
++ if (!nskb)
+ return;
+- }
+-
+- dst_release(nskb->dst);
+- nskb->dst = &rt->u.dst;
+
+ /* This packet will not be the same as the other: clear nf fields */
+ nf_reset(nskb);
+@@ -183,19 +114,31 @@ static void send_reset(struct sk_buff *o
+ tcph->window = 0;
+ tcph->urg_ptr = 0;
+
++ /* Set DF, id = 0 */
++ nskb->nh.iph->frag_off = htons(IP_DF);
++ nskb->nh.iph->id = 0;
++
++ addr_type = RTN_UNSPEC;
++ if (hook != NF_IP_FORWARD
++#ifdef CONFIG_BRIDGE_NETFILTER
++ || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
++#endif
++ )
++ addr_type = RTN_LOCAL;
++
++ if (ip_route_me_harder(&nskb, addr_type))
++ goto free_nskb;
++
+ /* Adjust TCP checksum */
++ nskb->ip_summed = CHECKSUM_NONE;
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
+ nskb->nh.iph->saddr,
+ nskb->nh.iph->daddr,
+ csum_partial((char *)tcph,
+ sizeof(struct tcphdr), 0));
+-
+- /* Adjust IP TTL, DF */
++ /* Adjust IP TTL */
+ nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+- /* Set DF, id = 0 */
+- nskb->nh.iph->frag_off = htons(IP_DF);
+- nskb->nh.iph->id = 0;
+
+ /* Adjust IP checksum */
+ nskb->nh.iph->check = 0;
+@@ -226,8 +169,7 @@ static unsigned int reject(struct sk_buf
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ipt_reject_info *reject = targinfo;
+
+@@ -275,7 +217,6 @@ static int check(const char *tablename,
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_reject_info *rejinfo = targinfo;
+diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
+index 7169b09..b38b133 100644
+--- a/net/ipv4/netfilter/ipt_SAME.c
++++ b/net/ipv4/netfilter/ipt_SAME.c
+@@ -52,7 +52,6 @@ same_check(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ unsigned int count, countess, rangeip, index = 0;
+@@ -116,8 +115,7 @@ same_check(const char *tablename,
+ }
+
+ static void
+-same_destroy(const struct xt_target *target, void *targinfo,
+- unsigned int targinfosize)
++same_destroy(const struct xt_target *target, void *targinfo)
+ {
+ struct ipt_same_info *mr = targinfo;
+
+@@ -133,12 +131,12 @@ same_target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+- u_int32_t tmpip, aindex, new_ip;
++ u_int32_t tmpip, aindex;
++ __be32 new_ip;
+ const struct ipt_same_info *same = targinfo;
+ struct ip_nat_range newrange;
+ const struct ip_conntrack_tuple *t;
+diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
+index ef2fe5b..108b6b7 100644
+--- a/net/ipv4/netfilter/ipt_TCPMSS.c
++++ b/net/ipv4/netfilter/ipt_TCPMSS.c
+@@ -21,26 +21,14 @@ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Marc Boucher <marc at mbsi.ca>");
+ MODULE_DESCRIPTION("iptables TCP MSS modification module");
+
+-#if 0
+-#define DEBUGP printk
+-#else
+-#define DEBUGP(format, args...)
+-#endif
+-
+-static u_int16_t
+-cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
+-{
+- u_int32_t diffs[] = { oldvalinv, newval };
+- return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
+- oldcheck^0xFFFF));
+-}
+-
+ static inline unsigned int
+ optlen(const u_int8_t *opt, unsigned int offset)
+ {
+ /* Beware zero-length options: make finite progress */
+- if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) return 1;
+- else return opt[offset+1];
++ if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
++ return 1;
++ else
++ return opt[offset+1];
+ }
+
+ static unsigned int
+@@ -49,26 +37,21 @@ ipt_tcpmss_target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+- u_int16_t tcplen, newtotlen, oldval, newmss;
++ u_int16_t tcplen, newmss;
++ __be16 newtotlen, oldval;
+ unsigned int i;
+ u_int8_t *opt;
+
+ if (!skb_make_writable(pskb, (*pskb)->len))
+ return NF_DROP;
+
+- if ((*pskb)->ip_summed == CHECKSUM_HW &&
+- skb_checksum_help(*pskb, out == NULL))
+- return NF_DROP;
+-
+ iph = (*pskb)->nh.iph;
+ tcplen = (*pskb)->len - iph->ihl*4;
+-
+ tcph = (void *)iph + iph->ihl*4;
+
+ /* Since it passed flags test in tcp match, we know it is is
+@@ -84,54 +67,41 @@ ipt_tcpmss_target(struct sk_buff **pskb,
+ return NF_DROP;
+ }
+
+- if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
+- if(!(*pskb)->dst) {
++ if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
++ if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) +
++ sizeof(struct tcphdr)) {
+ if (net_ratelimit())
+- printk(KERN_ERR
+- "ipt_tcpmss_target: no dst?! can't determine path-MTU\n");
++ printk(KERN_ERR "ipt_tcpmss_target: "
++ "unknown or invalid path-MTU (%d)\n",
++ dst_mtu((*pskb)->dst));
+ return NF_DROP; /* or IPT_CONTINUE ?? */
+ }
+
+- if(dst_mtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
+- if (net_ratelimit())
+- printk(KERN_ERR
+- "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_mtu((*pskb)->dst));
+- return NF_DROP; /* or IPT_CONTINUE ?? */
+- }
+-
+- newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct tcphdr);
++ newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) -
++ sizeof(struct tcphdr);
+ } else
+ newmss = tcpmssinfo->mss;
+
+ opt = (u_int8_t *)tcph;
+- for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){
+- if ((opt[i] == TCPOPT_MSS) &&
+- ((tcph->doff*4 - i) >= TCPOLEN_MSS) &&
+- (opt[i+1] == TCPOLEN_MSS)) {
++ for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
++ if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
++ opt[i+1] == TCPOLEN_MSS) {
+ u_int16_t oldmss;
+
+ oldmss = (opt[i+2] << 8) | opt[i+3];
+
+- if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
+- (oldmss <= newmss))
+- return IPT_CONTINUE;
++ if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
++ oldmss <= newmss)
++ return IPT_CONTINUE;
+
+ opt[i+2] = (newmss & 0xff00) >> 8;
+ opt[i+3] = (newmss & 0x00ff);
+
+- tcph->check = cheat_check(htons(oldmss)^0xFFFF,
+- htons(newmss),
+- tcph->check);
+-
+- DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
+- "->%u.%u.%u.%u:%hu changed TCP MSS option"
+- " (from %u to %u)\n",
+- NIPQUAD((*pskb)->nh.iph->saddr),
+- ntohs(tcph->source),
+- NIPQUAD((*pskb)->nh.iph->daddr),
+- ntohs(tcph->dest),
+- oldmss, newmss);
+- goto retmodified;
++ tcph->check = nf_proto_csum_update(*pskb,
++ htons(oldmss)^htons(0xFFFF),
++ htons(newmss),
++ tcph->check, 0);
++ return IPT_CONTINUE;
+ }
+ }
+
+@@ -143,13 +113,8 @@ ipt_tcpmss_target(struct sk_buff **pskb,
+
+ newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
+ TCPOLEN_MSS, GFP_ATOMIC);
+- if (!newskb) {
+- if (net_ratelimit())
+- printk(KERN_ERR "ipt_tcpmss_target:"
+- " unable to allocate larger skb\n");
++ if (!newskb)
+ return NF_DROP;
+- }
+-
+ kfree_skb(*pskb);
+ *pskb = newskb;
+ iph = (*pskb)->nh.iph;
+@@ -161,36 +126,29 @@ ipt_tcpmss_target(struct sk_buff **pskb,
+ opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
+ memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+
+- tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF,
+- htons(tcplen + TCPOLEN_MSS), tcph->check);
+- tcplen += TCPOLEN_MSS;
+-
++ tcph->check = nf_proto_csum_update(*pskb,
++ htons(tcplen) ^ htons(0xFFFF),
++ htons(tcplen + TCPOLEN_MSS),
++ tcph->check, 1);
+ opt[0] = TCPOPT_MSS;
+ opt[1] = TCPOLEN_MSS;
+ opt[2] = (newmss & 0xff00) >> 8;
+ opt[3] = (newmss & 0x00ff);
+
+- tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check);
++ tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt),
++ tcph->check, 0);
+
+- oldval = ((u_int16_t *)tcph)[6];
++ oldval = ((__be16 *)tcph)[6];
+ tcph->doff += TCPOLEN_MSS/4;
+- tcph->check = cheat_check(oldval ^ 0xFFFF,
+- ((u_int16_t *)tcph)[6], tcph->check);
++ tcph->check = nf_proto_csum_update(*pskb,
++ oldval ^ htons(0xFFFF),
++ ((__be16 *)tcph)[6],
++ tcph->check, 0);
+
+ newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
+- iph->check = cheat_check(iph->tot_len ^ 0xFFFF,
+- newtotlen, iph->check);
++ iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF),
++ newtotlen, iph->check);
+ iph->tot_len = newtotlen;
+-
+- DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
+- "->%u.%u.%u.%u:%hu added TCP MSS option (%u)\n",
+- NIPQUAD((*pskb)->nh.iph->saddr),
+- ntohs(tcph->source),
+- NIPQUAD((*pskb)->nh.iph->daddr),
+- ntohs(tcph->dest),
+- newmss);
+-
+- retmodified:
+ return IPT_CONTINUE;
+ }
+
+@@ -200,9 +158,9 @@ static inline int find_syn_match(const s
+ {
+ const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
+
+- if (strcmp(m->u.kernel.match->name, "tcp") == 0
+- && (tcpinfo->flg_cmp & TH_SYN)
+- && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
++ if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
++ tcpinfo->flg_cmp & TH_SYN &&
++ !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
+ return 1;
+
+ return 0;
+@@ -214,17 +172,17 @@ ipt_tcpmss_checkentry(const char *tablen
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
+ const struct ipt_entry *e = e_void;
+
+- if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
+- ((hook_mask & ~((1 << NF_IP_FORWARD)
+- | (1 << NF_IP_LOCAL_OUT)
+- | (1 << NF_IP_POST_ROUTING))) != 0)) {
+- printk("TCPMSS: path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
++ if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
++ (hook_mask & ~((1 << NF_IP_FORWARD) |
++ (1 << NF_IP_LOCAL_OUT) |
++ (1 << NF_IP_POST_ROUTING))) != 0) {
++ printk("TCPMSS: path-MTU clamping only supported in "
++ "FORWARD, OUTPUT and POSTROUTING hooks\n");
+ return 0;
+ }
+
+diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
+index 1c7a5ca..83b80b3 100644
+--- a/net/ipv4/netfilter/ipt_TOS.c
++++ b/net/ipv4/netfilter/ipt_TOS.c
+@@ -26,27 +26,20 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ipt_tos_target_info *tosinfo = targinfo;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ u_int16_t oldtos;
+
+- if (((*pskb)->nh.iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
+- u_int16_t diffs[2];
+-
++ if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
+ if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+ return NF_DROP;
+-
+- diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
+- (*pskb)->nh.iph->tos
+- = ((*pskb)->nh.iph->tos & IPTOS_PREC_MASK)
+- | tosinfo->tos;
+- diffs[1] = htons((*pskb)->nh.iph->tos);
+- (*pskb)->nh.iph->check
+- = csum_fold(csum_partial((char *)diffs,
+- sizeof(diffs),
+- (*pskb)->nh.iph->check
+- ^0xFFFF));
++ iph = (*pskb)->nh.iph;
++ oldtos = iph->tos;
++ iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
++ iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
++ htons(iph->tos), iph->check);
+ }
+ return IPT_CONTINUE;
+ }
+@@ -56,7 +49,6 @@ checkentry(const char *tablename,
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos;
+diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
+index f48892a..ac9517d 100644
+--- a/net/ipv4/netfilter/ipt_TTL.c
++++ b/net/ipv4/netfilter/ipt_TTL.c
+@@ -23,11 +23,10 @@ static unsigned int
+ ipt_ttl_target(struct sk_buff **pskb,
+ const struct net_device *in, const struct net_device *out,
+ unsigned int hooknum, const struct xt_target *target,
+- const void *targinfo, void *userinfo)
++ const void *targinfo)
+ {
+ struct iphdr *iph;
+ const struct ipt_TTL_info *info = targinfo;
+- u_int16_t diffs[2];
+ int new_ttl;
+
+ if (!skb_make_writable(pskb, (*pskb)->len))
+@@ -55,12 +54,10 @@ ipt_ttl_target(struct sk_buff **pskb,
+ }
+
+ if (new_ttl != iph->ttl) {
+- diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
++ iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF),
++ htons(new_ttl << 8),
++ iph->check);
+ iph->ttl = new_ttl;
+- diffs[1] = htons(((unsigned)iph->ttl) << 8);
+- iph->check = csum_fold(csum_partial((char *)diffs,
+- sizeof(diffs),
+- iph->check^0xFFFF));
+ }
+
+ return IPT_CONTINUE;
+@@ -70,7 +67,6 @@ static int ipt_ttl_checkentry(const char
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct ipt_TTL_info *info = targinfo;
+diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
+index d46fd67..2b104ea 100644
+--- a/net/ipv4/netfilter/ipt_ULOG.c
++++ b/net/ipv4/netfilter/ipt_ULOG.c
+@@ -308,7 +308,7 @@ static unsigned int ipt_ulog_target(stru
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo, void *userinfo)
++ const void *targinfo)
+ {
+ struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+@@ -346,7 +346,6 @@ static int ipt_ulog_checkentry(const cha
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hookmask)
+ {
+ struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
+index 893dae2..7b60eb7 100644
+--- a/net/ipv4/netfilter/ipt_addrtype.c
++++ b/net/ipv4/netfilter/ipt_addrtype.c
+@@ -22,7 +22,7 @@ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
+ MODULE_DESCRIPTION("iptables addrtype match");
+
+-static inline int match_type(u_int32_t addr, u_int16_t mask)
++static inline int match_type(__be32 addr, u_int16_t mask)
+ {
+ return !!(mask & (1 << inet_addr_type(addr)));
+ }
+diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
+index 2927135..1798f86 100644
+--- a/net/ipv4/netfilter/ipt_ah.c
++++ b/net/ipv4/netfilter/ipt_ah.c
+@@ -74,7 +74,6 @@ checkentry(const char *tablename,
+ const void *ip_void,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_ah *ahinfo = matchinfo;
+diff --git a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c
+deleted file mode 100644
+index 4717759..0000000
+--- a/net/ipv4/netfilter/ipt_dscp.c
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/* IP tables module for matching the value of the IPv4 DSCP field
+- *
+- * ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
+- *
+- * (C) 2002 by Harald Welte <laforge at netfilter.org>
+- *
+- * 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/skbuff.h>
+-
+-#include <linux/netfilter_ipv4/ipt_dscp.h>
+-#include <linux/netfilter_ipv4/ip_tables.h>
+-
+-MODULE_AUTHOR("Harald Welte <laforge at netfilter.org>");
+-MODULE_DESCRIPTION("iptables DSCP matching module");
+-MODULE_LICENSE("GPL");
+-
+-static int match(const struct sk_buff *skb,
+- const struct net_device *in, const struct net_device *out,
+- const struct xt_match *match, const void *matchinfo,
+- int offset, unsigned int protoff, int *hotdrop)
+-{
+- const struct ipt_dscp_info *info = matchinfo;
+- const struct iphdr *iph = skb->nh.iph;
+-
+- u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+-
+- return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
+-}
+-
+-static struct ipt_match dscp_match = {
+- .name = "dscp",
+- .match = match,
+- .matchsize = sizeof(struct ipt_dscp_info),
+- .me = THIS_MODULE,
+-};
+-
+-static int __init ipt_dscp_init(void)
+-{
+- return ipt_register_match(&dscp_match);
+-}
+-
+-static void __exit ipt_dscp_fini(void)
+-{
+- ipt_unregister_match(&dscp_match);
+-
+-}
+-
+-module_init(ipt_dscp_init);
+-module_exit(ipt_dscp_fini);
+diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
+index b282504..dafbdec 100644
+--- a/net/ipv4/netfilter/ipt_ecn.c
++++ b/net/ipv4/netfilter/ipt_ecn.c
+@@ -88,8 +88,7 @@ static int match(const struct sk_buff *s
+
+ static int checkentry(const char *tablename, const void *ip_void,
+ const struct xt_match *match,
+- void *matchinfo, unsigned int matchsize,
+- unsigned int hook_mask)
++ void *matchinfo, unsigned int hook_mask)
+ {
+ const struct ipt_ecn_info *info = matchinfo;
+ const struct ipt_ip *ip = ip_void;
+diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
+index 3bd2368..33ccdbf 100644
+--- a/net/ipv4/netfilter/ipt_hashlimit.c
++++ b/net/ipv4/netfilter/ipt_hashlimit.c
+@@ -50,11 +50,11 @@ static struct file_operations dl_file_op
+ /* hash table crap */
+
+ struct dsthash_dst {
+- u_int32_t src_ip;
+- u_int32_t dst_ip;
++ __be32 src_ip;
++ __be32 dst_ip;
+ /* ports have to be consecutive !!! */
+- u_int16_t src_port;
+- u_int16_t dst_port;
++ __be16 src_port;
++ __be16 dst_port;
+ };
+
+ struct dsthash_ent {
+@@ -106,8 +106,10 @@ static inline int dst_cmp(const struct d
+ static inline u_int32_t
+ hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
+ {
+- return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 | dst->src_port),
+- dst->src_ip, ht->rnd) % ht->cfg.size);
++ return (jhash_3words((__force u32)dst->dst_ip,
++ ((__force u32)dst->dst_port<<16 |
++ (__force u32)dst->src_port),
++ (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size);
+ }
+
+ static inline struct dsthash_ent *
+@@ -406,7 +408,7 @@ hashlimit_match(const struct sk_buff *sk
+ dst.src_ip = skb->nh.iph->saddr;
+ if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT
+ ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) {
+- u_int16_t _ports[2], *ports;
++ __be16 _ports[2], *ports;
+
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+@@ -478,7 +480,6 @@ hashlimit_checkentry(const char *tablena
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ struct ipt_hashlimit_info *r = matchinfo;
+@@ -529,18 +530,46 @@ hashlimit_checkentry(const char *tablena
+ }
+
+ static void
+-hashlimit_destroy(const struct xt_match *match, void *matchinfo,
+- unsigned int matchsize)
++hashlimit_destroy(const struct xt_match *match, void *matchinfo)
+ {
+ struct ipt_hashlimit_info *r = matchinfo;
+
+ htable_put(r->hinfo);
+ }
+
++#ifdef CONFIG_COMPAT
++struct compat_ipt_hashlimit_info {
++ char name[IFNAMSIZ];
++ struct hashlimit_cfg cfg;
++ compat_uptr_t hinfo;
++ compat_uptr_t master;
++};
++
++static void compat_from_user(void *dst, void *src)
++{
++ int off = offsetof(struct compat_ipt_hashlimit_info, hinfo);
++
++ memcpy(dst, src, off);
++ memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off);
++}
++
++static int compat_to_user(void __user *dst, void *src)
++{
++ int off = offsetof(struct compat_ipt_hashlimit_info, hinfo);
++
++ return copy_to_user(dst, src, off) ? -EFAULT : 0;
++}
++#endif
++
+ static struct ipt_match ipt_hashlimit = {
+ .name = "hashlimit",
+ .match = hashlimit_match,
+ .matchsize = sizeof(struct ipt_hashlimit_info),
++#ifdef CONFIG_COMPAT
++ .compatsize = sizeof(struct compat_ipt_hashlimit_info),
++ .compat_from_user = compat_from_user,
++ .compat_to_user = compat_to_user,
++#endif
+ .checkentry = hashlimit_checkentry,
+ .destroy = hashlimit_destroy,
+ .me = THIS_MODULE
+diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
+index 5ac6ac0..78c336f 100644
+--- a/net/ipv4/netfilter/ipt_owner.c
++++ b/net/ipv4/netfilter/ipt_owner.c
+@@ -56,7 +56,6 @@ checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_owner_info *info = matchinfo;
+diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
+index 61a2139..126db44 100644
+--- a/net/ipv4/netfilter/ipt_recent.c
++++ b/net/ipv4/netfilter/ipt_recent.c
+@@ -35,20 +35,25 @@ static unsigned int ip_list_tot = 100;
+ static unsigned int ip_pkt_list_tot = 20;
+ static unsigned int ip_list_hash_size = 0;
+ static unsigned int ip_list_perms = 0644;
++static unsigned int ip_list_uid = 0;
++static unsigned int ip_list_gid = 0;
+ module_param(ip_list_tot, uint, 0400);
+ module_param(ip_pkt_list_tot, uint, 0400);
+ module_param(ip_list_hash_size, uint, 0400);
+ module_param(ip_list_perms, uint, 0400);
++module_param(ip_list_uid, uint, 0400);
++module_param(ip_list_gid, uint, 0400);
+ MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
+ MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)");
+ MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
+ MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files");
+-
++MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files");
++MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files");
+
+ struct recent_entry {
+ struct list_head list;
+ struct list_head lru_list;
+- u_int32_t addr;
++ __be32 addr;
+ u_int8_t ttl;
+ u_int8_t index;
+ u_int16_t nstamps;
+@@ -79,17 +84,17 @@ static struct file_operations recent_fop
+ static u_int32_t hash_rnd;
+ static int hash_rnd_initted;
+
+-static unsigned int recent_entry_hash(u_int32_t addr)
++static unsigned int recent_entry_hash(__be32 addr)
+ {
+ if (!hash_rnd_initted) {
+ get_random_bytes(&hash_rnd, 4);
+ hash_rnd_initted = 1;
+ }
+- return jhash_1word(addr, hash_rnd) & (ip_list_hash_size - 1);
++ return jhash_1word((__force u32)addr, hash_rnd) & (ip_list_hash_size - 1);
+ }
+
+ static struct recent_entry *
+-recent_entry_lookup(const struct recent_table *table, u_int32_t addr, u_int8_t ttl)
++recent_entry_lookup(const struct recent_table *table, __be32 addr, u_int8_t ttl)
+ {
+ struct recent_entry *e;
+ unsigned int h;
+@@ -110,7 +115,7 @@ static void recent_entry_remove(struct r
+ }
+
+ static struct recent_entry *
+-recent_entry_init(struct recent_table *t, u_int32_t addr, u_int8_t ttl)
++recent_entry_init(struct recent_table *t, __be32 addr, u_int8_t ttl)
+ {
+ struct recent_entry *e;
+
+@@ -172,7 +177,7 @@ ipt_recent_match(const struct sk_buff *s
+ const struct ipt_recent_info *info = matchinfo;
+ struct recent_table *t;
+ struct recent_entry *e;
+- u_int32_t addr;
++ __be32 addr;
+ u_int8_t ttl;
+ int ret = info->invert;
+
+@@ -232,7 +237,7 @@ out:
+ static int
+ ipt_recent_checkentry(const char *tablename, const void *ip,
+ const struct xt_match *match, void *matchinfo,
+- unsigned int matchsize, unsigned int hook_mask)
++ unsigned int hook_mask)
+ {
+ const struct ipt_recent_info *info = matchinfo;
+ struct recent_table *t;
+@@ -274,6 +279,8 @@ ipt_recent_checkentry(const char *tablen
+ goto out;
+ }
+ t->proc->proc_fops = &recent_fops;
++ t->proc->uid = ip_list_uid;
++ t->proc->gid = ip_list_gid;
+ t->proc->data = t;
+ #endif
+ spin_lock_bh(&recent_lock);
+@@ -286,8 +293,7 @@ out:
+ }
+
+ static void
+-ipt_recent_destroy(const struct xt_match *match, void *matchinfo,
+- unsigned int matchsize)
++ipt_recent_destroy(const struct xt_match *match, void *matchinfo)
+ {
+ const struct ipt_recent_info *info = matchinfo;
+ struct recent_table *t;
+@@ -399,7 +405,7 @@ static ssize_t recent_proc_write(struct
+ struct recent_table *t = pde->data;
+ struct recent_entry *e;
+ char buf[sizeof("+255.255.255.255")], *c = buf;
+- u_int32_t addr;
++ __be32 addr;
+ int add;
+
+ if (size > sizeof(buf))
+diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
+index 7f41748..e2e7dd8 100644
+--- a/net/ipv4/netfilter/iptable_filter.c
++++ b/net/ipv4/netfilter/iptable_filter.c
+@@ -90,7 +90,7 @@ ipt_hook(unsigned int hook,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return ipt_do_table(pskb, hook, in, out, &packet_filter, NULL);
++ return ipt_do_table(pskb, hook, in, out, &packet_filter);
+ }
+
+ static unsigned int
+@@ -108,7 +108,7 @@ ipt_local_out_hook(unsigned int hook,
+ return NF_ACCEPT;
+ }
+
+- return ipt_do_table(pskb, hook, in, out, &packet_filter, NULL);
++ return ipt_do_table(pskb, hook, in, out, &packet_filter);
+ }
+
+ static struct nf_hook_ops ipt_ops[] = {
+diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
+index 4e7998b..b91f358 100644
+--- a/net/ipv4/netfilter/iptable_mangle.c
++++ b/net/ipv4/netfilter/iptable_mangle.c
+@@ -119,7 +119,7 @@ ipt_route_hook(unsigned int hook,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
++ return ipt_do_table(pskb, hook, in, out, &packet_mangler);
+ }
+
+ static unsigned int
+@@ -131,7 +131,7 @@ ipt_local_hook(unsigned int hook,
+ {
+ unsigned int ret;
+ u_int8_t tos;
+- u_int32_t saddr, daddr;
++ __be32 saddr, daddr;
+ unsigned long nfmark;
+
+ /* root is playing with raw sockets. */
+@@ -148,7 +148,7 @@ ipt_local_hook(unsigned int hook,
+ daddr = (*pskb)->nh.iph->daddr;
+ tos = (*pskb)->nh.iph->tos;
+
+- ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
++ ret = ipt_do_table(pskb, hook, in, out, &packet_mangler);
+ /* Reroute for ANY change. */
+ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
+ && ((*pskb)->nh.iph->saddr != saddr
+@@ -157,7 +157,8 @@ ipt_local_hook(unsigned int hook,
+ || (*pskb)->nfmark != nfmark
+ #endif
+ || (*pskb)->nh.iph->tos != tos))
+- return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
++ if (ip_route_me_harder(pskb, RTN_UNSPEC))
++ ret = NF_DROP;
+
+ return ret;
+ }
+diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
+index 7912cce..bcbeb4a 100644
+--- a/net/ipv4/netfilter/iptable_raw.c
++++ b/net/ipv4/netfilter/iptable_raw.c
+@@ -95,7 +95,7 @@ ipt_hook(unsigned int hook,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
++ return ipt_do_table(pskb, hook, in, out, &packet_raw);
+ }
+
+ /* 'raw' is the very first table. */
+diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+index 663a73e..790f00d 100644
+--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
++++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+@@ -25,7 +25,7 @@
+ #include <net/netfilter/nf_conntrack_protocol.h>
+ #include <net/netfilter/nf_conntrack_core.h>
+
+-unsigned long nf_ct_icmp_timeout = 30*HZ;
++unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ;
+
+ #if 0
+ #define DEBUGP printk
+diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
+index d61e2a9..9c6cbe3 100644
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -173,6 +173,8 @@ static const struct snmp_mib snmp4_udp_l
+ SNMP_MIB_ITEM("NoPorts", UDP_MIB_NOPORTS),
+ SNMP_MIB_ITEM("InErrors", UDP_MIB_INERRORS),
+ SNMP_MIB_ITEM("OutDatagrams", UDP_MIB_OUTDATAGRAMS),
++ SNMP_MIB_ITEM("RcvbufErrors", UDP_MIB_RCVBUFERRORS),
++ SNMP_MIB_ITEM("SndbufErrors", UDP_MIB_SNDBUFERRORS),
+ SNMP_MIB_SENTINEL
+ };
+
+diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
+index 62b2762..5c31dea 100644
+--- a/net/ipv4/raw.c
++++ b/net/ipv4/raw.c
+@@ -38,8 +38,7 @@
+ * 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/types.h>
+ #include <asm/atomic.h>
+ #include <asm/byteorder.h>
+@@ -330,7 +329,7 @@ error:
+ return err;
+ }
+
+-static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
++static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
+ {
+ struct iovec *iov;
+ u8 __user *type = NULL;
+@@ -339,7 +338,7 @@ static void raw_probe_proto_opt(struct f
+ unsigned int i;
+
+ if (!msg->msg_iov)
+- return;
++ return 0;
+
+ for (i = 0; i < msg->msg_iovlen; i++) {
+ iov = &msg->msg_iov[i];
+@@ -361,8 +360,9 @@ static void raw_probe_proto_opt(struct f
+ code = iov->iov_base;
+
+ if (type && code) {
+- get_user(fl->fl_icmp_type, type);
+- get_user(fl->fl_icmp_code, code);
++ if (get_user(fl->fl_icmp_type, type) ||
++ get_user(fl->fl_icmp_code, code))
++ return -EFAULT;
+ probed = 1;
+ }
+ break;
+@@ -373,6 +373,7 @@ static void raw_probe_proto_opt(struct f
+ if (probed)
+ break;
+ }
++ return 0;
+ }
+
+ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -382,8 +383,8 @@ static int raw_sendmsg(struct kiocb *ioc
+ struct ipcm_cookie ipc;
+ struct rtable *rt = NULL;
+ int free = 0;
+- u32 daddr;
+- u32 saddr;
++ __be32 daddr;
++ __be32 saddr;
+ u8 tos;
+ int err;
+
+@@ -481,9 +482,13 @@ static int raw_sendmsg(struct kiocb *ioc
+ .proto = inet->hdrincl ? IPPROTO_RAW :
+ sk->sk_protocol,
+ };
+- if (!inet->hdrincl)
+- raw_probe_proto_opt(&fl, msg);
++ if (!inet->hdrincl) {
++ err = raw_probe_proto_opt(&fl, msg);
++ if (err)
++ goto done;
++ }
+
++ security_sk_classify_flow(sk, &fl);
+ err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+ }
+ if (err)
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index b873cbc..925ee4d 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -261,6 +261,10 @@ static unsigned int rt_hash_code(u32 dad
+ & rt_hash_mask);
+ }
+
++#define rt_hash(daddr, saddr, idx) \
++ rt_hash_code((__force u32)(__be32)(daddr),\
++ (__force u32)(__be32)(saddr) ^ ((idx) << 5))
++
+ #ifdef CONFIG_PROC_FS
+ struct rt_cache_iter_state {
+ int bucket;
+@@ -562,9 +566,15 @@ static inline u32 rt_score(struct rtable
+
+ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
+ {
+- return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 &&
+- fl1->oif == fl2->oif &&
+- fl1->iif == fl2->iif;
++ return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
++ (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) |
++#ifdef CONFIG_IP_ROUTE_FWMARK
++ (fl1->nl_u.ip4_u.fwmark ^ fl2->nl_u.ip4_u.fwmark) |
++#endif
++ (*(u16 *)&fl1->nl_u.ip4_u.tos ^
++ *(u16 *)&fl2->nl_u.ip4_u.tos) |
++ (fl1->oif ^ fl2->oif) |
++ (fl1->iif ^ fl2->iif)) == 0;
+ }
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+@@ -1074,7 +1084,7 @@ static void ip_select_fb_ident(struct ip
+ u32 salt;
+
+ spin_lock_bh(&ip_fb_id_lock);
+- salt = secure_ip_id(ip_fallback_id ^ iph->daddr);
++ salt = secure_ip_id((__force __be32)ip_fallback_id ^ iph->daddr);
+ iph->id = htons(salt & 0xFFFF);
+ ip_fallback_id = salt;
+ spin_unlock_bh(&ip_fb_id_lock);
+@@ -1118,13 +1128,13 @@ static void rt_del(unsigned hash, struct
+ spin_unlock_bh(rt_hash_lock_addr(hash));
+ }
+
+-void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
+- u32 saddr, struct net_device *dev)
++void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
++ __be32 saddr, struct net_device *dev)
+ {
+ int i, k;
+ struct in_device *in_dev = in_dev_get(dev);
+ struct rtable *rth, **rthp;
+- u32 skeys[2] = { saddr, 0 };
++ __be32 skeys[2] = { saddr, 0 };
+ int ikeys[2] = { dev->ifindex, 0 };
+ struct netevent_redirect netevent;
+
+@@ -1147,8 +1157,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
+
+ for (i = 0; i < 2; i++) {
+ for (k = 0; k < 2; k++) {
+- unsigned hash = rt_hash_code(daddr,
+- skeys[i] ^ (ikeys[k] << 5));
++ unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]);
+
+ rthp=&rt_hash_table[hash].chain;
+
+@@ -1260,9 +1269,8 @@ static struct dst_entry *ipv4_negative_a
+ ret = NULL;
+ } else if ((rt->rt_flags & RTCF_REDIRECTED) ||
+ rt->u.dst.expires) {
+- unsigned hash = rt_hash_code(rt->fl.fl4_dst,
+- rt->fl.fl4_src ^
+- (rt->fl.oif << 5));
++ unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
++ rt->fl.oif);
+ #if RT_CACHE_DEBUG >= 1
+ printk(KERN_DEBUG "ip_rt_advice: redirect to "
+ "%u.%u.%u.%u/%02x dropped\n",
+@@ -1397,15 +1405,15 @@ unsigned short ip_rt_frag_needed(struct
+ int i;
+ unsigned short old_mtu = ntohs(iph->tot_len);
+ struct rtable *rth;
+- u32 skeys[2] = { iph->saddr, 0, };
+- u32 daddr = iph->daddr;
++ __be32 skeys[2] = { iph->saddr, 0, };
++ __be32 daddr = iph->daddr;
+ unsigned short est_mtu = 0;
+
+ if (ipv4_config.no_pmtu_disc)
+ return 0;
+
+ for (i = 0; i < 2; i++) {
+- unsigned hash = rt_hash_code(daddr, skeys[i]);
++ unsigned hash = rt_hash(daddr, skeys[i], 0);
+
+ rcu_read_lock();
+ for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
+@@ -1530,7 +1538,7 @@ static int ip_rt_bug(struct sk_buff *skb
+
+ void ip_rt_get_source(u8 *addr, struct rtable *rt)
+ {
+- u32 src;
++ __be32 src;
+ struct fib_result res;
+
+ if (rt->fl.iif == 0)
+@@ -1596,12 +1604,12 @@ static void rt_set_nexthop(struct rtable
+ rt->rt_type = res->type;
+ }
+
+-static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
++static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ u8 tos, struct net_device *dev, int our)
+ {
+ unsigned hash;
+ struct rtable *rth;
+- u32 spec_dst;
++ __be32 spec_dst;
+ struct in_device *in_dev = in_dev_get(dev);
+ u32 itag = 0;
+
+@@ -1665,7 +1673,7 @@ static int ip_route_input_mc(struct sk_b
+ RT_CACHE_STAT_INC(in_slow_mc);
+
+ in_dev_put(in_dev);
+- hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5));
++ hash = rt_hash(daddr, saddr, dev->ifindex);
+ return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
+
+ e_nobufs:
+@@ -1681,8 +1689,8 @@ e_inval:
+ static void ip_handle_martian_source(struct net_device *dev,
+ struct in_device *in_dev,
+ struct sk_buff *skb,
+- u32 daddr,
+- u32 saddr)
++ __be32 daddr,
++ __be32 saddr)
+ {
+ RT_CACHE_STAT_INC(in_martian_src);
+ #ifdef CONFIG_IP_ROUTE_VERBOSE
+@@ -1712,7 +1720,7 @@ static void ip_handle_martian_source(str
+ static inline int __mkroute_input(struct sk_buff *skb,
+ struct fib_result* res,
+ struct in_device *in_dev,
+- u32 daddr, u32 saddr, u32 tos,
++ __be32 daddr, __be32 saddr, u32 tos,
+ struct rtable **result)
+ {
+
+@@ -1720,7 +1728,8 @@ static inline int __mkroute_input(struct
+ int err;
+ struct in_device *out_dev;
+ unsigned flags = 0;
+- u32 spec_dst, itag;
++ __be32 spec_dst;
++ u32 itag;
+
+ /* get a working reference to the output device */
+ out_dev = in_dev_get(FIB_RES_DEV(*res));
+@@ -1813,7 +1822,7 @@ static inline int ip_mkroute_input_def(s
+ struct fib_result* res,
+ const struct flowi *fl,
+ struct in_device *in_dev,
+- u32 daddr, u32 saddr, u32 tos)
++ __be32 daddr, __be32 saddr, u32 tos)
+ {
+ struct rtable* rth = NULL;
+ int err;
+@@ -1830,7 +1839,7 @@ static inline int ip_mkroute_input_def(s
+ return err;
+
+ /* put it into the cache */
+- hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
++ hash = rt_hash(daddr, saddr, fl->iif);
+ return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+ }
+
+@@ -1838,7 +1847,7 @@ static inline int ip_mkroute_input(struc
+ struct fib_result* res,
+ const struct flowi *fl,
+ struct in_device *in_dev,
+- u32 daddr, u32 saddr, u32 tos)
++ __be32 daddr, __be32 saddr, u32 tos)
+ {
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+ struct rtable* rth = NULL, *rtres;
+@@ -1871,7 +1880,7 @@ static inline int ip_mkroute_input(struc
+ return err;
+
+ /* put it into the cache */
+- hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
++ hash = rt_hash(daddr, saddr, fl->iif);
+ err = rt_intern_hash(hash, rth, &rtres);
+ if (err)
+ return err;
+@@ -1901,7 +1910,7 @@ static inline int ip_mkroute_input(struc
+ * 2. IP spoofing attempts are filtered with 100% of guarantee.
+ */
+
+-static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
++static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ u8 tos, struct net_device *dev)
+ {
+ struct fib_result res;
+@@ -1920,7 +1929,7 @@ static int ip_route_input_slow(struct sk
+ u32 itag = 0;
+ struct rtable * rth;
+ unsigned hash;
+- u32 spec_dst;
++ __be32 spec_dst;
+ int err = -EINVAL;
+ int free_res = 0;
+
+@@ -1936,7 +1945,7 @@ static int ip_route_input_slow(struct sk
+ if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr))
+ goto martian_source;
+
+- if (daddr == 0xFFFFFFFF || (saddr == 0 && daddr == 0))
++ if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
+ goto brd_input;
+
+ /* Accept zero addresses only to limited broadcast;
+@@ -2048,7 +2057,7 @@ local_input:
+ rth->rt_flags &= ~RTCF_LOCAL;
+ }
+ rth->rt_type = res.type;
+- hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5));
++ hash = rt_hash(daddr, saddr, fl.iif);
+ err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+ goto done;
+
+@@ -2087,7 +2096,7 @@ martian_source:
+ goto e_inval;
+ }
+
+-int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
++int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ u8 tos, struct net_device *dev)
+ {
+ struct rtable * rth;
+@@ -2095,7 +2104,7 @@ int ip_route_input(struct sk_buff *skb,
+ int iif = dev->ifindex;
+
+ tos &= IPTOS_RT_MASK;
+- hash = rt_hash_code(daddr, saddr ^ (iif << 5));
++ hash = rt_hash(daddr, saddr, iif);
+
+ rcu_read_lock();
+ for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
+@@ -2169,7 +2178,7 @@ static inline int __mkroute_output(struc
+ if (LOOPBACK(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
+ return -EINVAL;
+
+- if (fl->fl4_dst == 0xFFFFFFFF)
++ if (fl->fl4_dst == htonl(0xFFFFFFFF))
+ res->type = RTN_BROADCAST;
+ else if (MULTICAST(fl->fl4_dst))
+ res->type = RTN_MULTICAST;
+@@ -2293,8 +2302,7 @@ static inline int ip_mkroute_output_def(
+ int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
+ unsigned hash;
+ if (err == 0) {
+- hash = rt_hash_code(oldflp->fl4_dst,
+- oldflp->fl4_src ^ (oldflp->oif << 5));
++ hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif);
+ err = rt_intern_hash(hash, rth, rp);
+ }
+
+@@ -2336,9 +2344,8 @@ static inline int ip_mkroute_output(stru
+ if (err != 0)
+ goto cleanup;
+
+- hash = rt_hash_code(oldflp->fl4_dst,
+- oldflp->fl4_src ^
+- (oldflp->oif << 5));
++ hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src,
++ oldflp->oif);
+ err = rt_intern_hash(hash, rth, rp);
+
+ /* forward hop information to multipath impl. */
+@@ -2417,7 +2424,7 @@ static int ip_route_output_slow(struct r
+ */
+
+ if (oldflp->oif == 0
+- && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF)) {
++ && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
+ /* Special hack: user can direct multicasts
+ and limited broadcast via necessary interface
+ without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
+@@ -2454,7 +2461,7 @@ static int ip_route_output_slow(struct r
+ goto out; /* Wrong error code */
+ }
+
+- if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) {
++ if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF)) {
+ if (!fl.fl4_src)
+ fl.fl4_src = inet_select_addr(dev_out, 0,
+ RT_SCOPE_LINK);
+@@ -2567,7 +2574,7 @@ int __ip_route_output_key(struct rtable
+ unsigned hash;
+ struct rtable *rth;
+
+- hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5));
++ hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif);
+
+ rcu_read_lock_bh();
+ for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
+@@ -2639,51 +2646,54 @@ static int rt_fill_info(struct sk_buff *
+ {
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtmsg *r;
+- struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
++ struct nlmsghdr *nlh;
+ struct rta_cacheinfo ci;
+-#ifdef CONFIG_IP_MROUTE
+- struct rtattr *eptr;
+-#endif
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
+- r = NLMSG_DATA(nlh);
++
++ nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ r = nlmsg_data(nlh);
+ r->rtm_family = AF_INET;
+ r->rtm_dst_len = 32;
+ r->rtm_src_len = 0;
+ r->rtm_tos = rt->fl.fl4_tos;
+ r->rtm_table = RT_TABLE_MAIN;
++ NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
+ r->rtm_type = rt->rt_type;
+ r->rtm_scope = RT_SCOPE_UNIVERSE;
+ r->rtm_protocol = RTPROT_UNSPEC;
+ r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
+ if (rt->rt_flags & RTCF_NOTIFY)
+ r->rtm_flags |= RTM_F_NOTIFY;
+- RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
++
++ NLA_PUT_BE32(skb, RTA_DST, rt->rt_dst);
++
+ if (rt->fl.fl4_src) {
+ r->rtm_src_len = 32;
+- RTA_PUT(skb, RTA_SRC, 4, &rt->fl.fl4_src);
++ NLA_PUT_BE32(skb, RTA_SRC, rt->fl.fl4_src);
+ }
+ if (rt->u.dst.dev)
+- RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
++ NLA_PUT_U32(skb, RTA_OIF, rt->u.dst.dev->ifindex);
+ #ifdef CONFIG_NET_CLS_ROUTE
+ if (rt->u.dst.tclassid)
+- RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);
++ NLA_PUT_U32(skb, RTA_FLOW, rt->u.dst.tclassid);
+ #endif
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+- if (rt->rt_multipath_alg != IP_MP_ALG_NONE) {
+- __u32 alg = rt->rt_multipath_alg;
+-
+- RTA_PUT(skb, RTA_MP_ALGO, 4, &alg);
+- }
++ if (rt->rt_multipath_alg != IP_MP_ALG_NONE)
++ NLA_PUT_U32(skb, RTA_MP_ALGO, rt->rt_multipath_alg);
+ #endif
+ if (rt->fl.iif)
+- RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
++ NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
+ else if (rt->rt_src != rt->fl.fl4_src)
+- RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
++ NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_src);
++
+ if (rt->rt_dst != rt->rt_gateway)
+- RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
++ NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
++
+ if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+- goto rtattr_failure;
++ goto nla_put_failure;
++
+ ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse);
+ ci.rta_used = rt->u.dst.__use;
+ ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt);
+@@ -2700,13 +2710,10 @@ static int rt_fill_info(struct sk_buff *
+ ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp;
+ }
+ }
+-#ifdef CONFIG_IP_MROUTE
+- eptr = (struct rtattr*)skb->tail;
+-#endif
+- RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
++
+ if (rt->fl.iif) {
+ #ifdef CONFIG_IP_MROUTE
+- u32 dst = rt->rt_dst;
++ __be32 dst = rt->rt_dst;
+
+ if (MULTICAST(dst) && !LOCAL_MCAST(dst) &&
+ ipv4_devconf.mc_forwarding) {
+@@ -2715,41 +2722,48 @@ static int rt_fill_info(struct sk_buff *
+ if (!nowait) {
+ if (err == 0)
+ return 0;
+- goto nlmsg_failure;
++ goto nla_put_failure;
+ } else {
+ if (err == -EMSGSIZE)
+- goto nlmsg_failure;
+- ((struct rta_cacheinfo*)RTA_DATA(eptr))->rta_error = err;
++ goto nla_put_failure;
++ ci.rta_error = err;
+ }
+ }
+ } else
+ #endif
+- RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
++ NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif);
+ }
+
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
++
++ return nlmsg_end(skb, nlh);
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
+ }
+
+ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+ {
+- struct rtattr **rta = arg;
+- struct rtmsg *rtm = NLMSG_DATA(nlh);
++ struct rtmsg *rtm;
++ struct nlattr *tb[RTA_MAX+1];
+ struct rtable *rt = NULL;
+- u32 dst = 0;
+- u32 src = 0;
+- int iif = 0;
+- int err = -ENOBUFS;
++ __be32 dst = 0;
++ __be32 src = 0;
++ u32 iif;
++ int err;
+ struct sk_buff *skb;
+
++ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
++ if (err < 0)
++ goto errout;
++
++ rtm = nlmsg_data(nlh);
++
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+- if (!skb)
+- goto out;
++ if (skb == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
+
+ /* Reserve room for dummy headers, this skb can pass
+ through good chunk of routing engine.
+@@ -2760,62 +2774,61 @@ int inet_rtm_getroute(struct sk_buff *in
+ skb->nh.iph->protocol = IPPROTO_ICMP;
+ skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
+
+- if (rta[RTA_SRC - 1])
+- memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4);
+- if (rta[RTA_DST - 1])
+- memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4);
+- if (rta[RTA_IIF - 1])
+- memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int));
++ src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0;
++ dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0;
++ iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
+
+ if (iif) {
+- struct net_device *dev = __dev_get_by_index(iif);
+- err = -ENODEV;
+- if (!dev)
+- goto out_free;
++ struct net_device *dev;
++
++ dev = __dev_get_by_index(iif);
++ if (dev == NULL) {
++ err = -ENODEV;
++ goto errout_free;
++ }
++
+ skb->protocol = htons(ETH_P_IP);
+ skb->dev = dev;
+ local_bh_disable();
+ err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
+ local_bh_enable();
+- rt = (struct rtable*)skb->dst;
+- if (!err && rt->u.dst.error)
++
++ rt = (struct rtable*) skb->dst;
++ if (err == 0 && rt->u.dst.error)
+ err = -rt->u.dst.error;
+ } else {
+- struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
+- .saddr = src,
+- .tos = rtm->rtm_tos } } };
+- int oif = 0;
+- if (rta[RTA_OIF - 1])
+- memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
+- fl.oif = oif;
++ struct flowi fl = {
++ .nl_u = {
++ .ip4_u = {
++ .daddr = dst,
++ .saddr = src,
++ .tos = rtm->rtm_tos,
++ },
++ },
++ .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
++ };
+ err = ip_route_output_key(&rt, &fl);
+ }
++
+ if (err)
+- goto out_free;
++ goto errout_free;
+
+ skb->dst = &rt->u.dst;
+ if (rtm->rtm_flags & RTM_F_NOTIFY)
+ rt->rt_flags |= RTCF_NOTIFY;
+
+- NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+-
+ err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
+ RTM_NEWROUTE, 0, 0);
+- if (!err)
+- goto out_free;
+- if (err < 0) {
+- err = -EMSGSIZE;
+- goto out_free;
+- }
++ if (err <= 0)
++ goto errout_free;
+
+- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+- if (err > 0)
+- err = 0;
+-out: return err;
++ err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
++errout:
++ return err;
+
+-out_free:
++errout_free:
+ kfree_skb(skb);
+- goto out;
++ goto errout;
+ }
+
+ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
+@@ -3143,13 +3156,9 @@ int __init ip_rt_init(void)
+ }
+ #endif
+
+- ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache",
+- sizeof(struct rtable),
+- 0, SLAB_HWCACHE_ALIGN,
+- NULL, NULL);
+-
+- if (!ipv4_dst_ops.kmem_cachep)
+- panic("IP: failed to allocate ip_dst_cache\n");
++ ipv4_dst_ops.kmem_cachep =
++ kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+
+ rt_hash_table = (struct rt_hash_bucket *)
+ alloc_large_system_hash("IP route cache",
+diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
+index e20be33..661e0a4 100644
+--- a/net/ipv4/syncookies.c
++++ b/net/ipv4/syncookies.c
+@@ -214,6 +214,10 @@ struct sock *cookie_v4_check(struct sock
+ if (!req)
+ goto out;
+
++ if (security_inet_conn_request(sk, skb, req)) {
++ reqsk_free(req);
++ goto out;
++ }
+ ireq = inet_rsk(req);
+ treq = tcp_rsk(req);
+ treq->rcv_isn = htonl(skb->h.th->seq) - 1;
+@@ -259,6 +263,7 @@ struct sock *cookie_v4_check(struct sock
+ .uli_u = { .ports =
+ { .sport = skb->h.th->dest,
+ .dport = skb->h.th->source } } };
++ security_req_classify_flow(req, &fl);
+ if (ip_route_output_key(&rt, &fl)) {
+ reqsk_free(req);
+ goto out;
+diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
+index 70cea9d..15061b3 100644
+--- a/net/ipv4/sysctl_net_ipv4.c
++++ b/net/ipv4/sysctl_net_ipv4.c
+@@ -17,6 +17,7 @@
+ #include <net/ip.h>
+ #include <net/route.h>
+ #include <net/tcp.h>
++#include <net/cipso_ipv4.h>
+
+ /* From af_inet.c */
+ extern int sysctl_ip_nonlocal_bind;
+@@ -128,7 +129,6 @@ static int sysctl_tcp_congestion_control
+ return ret;
+ }
+
+-
+ ctl_table ipv4_table[] = {
+ {
+ .ctl_name = NET_IPV4_TCP_TIMESTAMPS,
+@@ -697,6 +697,40 @@ ctl_table ipv4_table[] = {
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
++#ifdef CONFIG_NETLABEL
++ {
++ .ctl_name = NET_CIPSOV4_CACHE_ENABLE,
++ .procname = "cipso_cache_enable",
++ .data = &cipso_v4_cache_enabled,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = NET_CIPSOV4_CACHE_BUCKET_SIZE,
++ .procname = "cipso_cache_bucket_size",
++ .data = &cipso_v4_cache_bucketsize,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = NET_CIPSOV4_RBM_OPTFMT,
++ .procname = "cipso_rbm_optfmt",
++ .data = &cipso_v4_rbm_optfmt,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = NET_CIPSOV4_RBM_STRICTVALID,
++ .procname = "cipso_rbm_strictvalid",
++ .data = &cipso_v4_rbm_strictvalid,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++#endif /* CONFIG_NETLABEL */
+ { .ctl_name = 0 }
+ };
+
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 934396b..66e9a72 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -268,7 +268,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/ioctls.h>
+
+-int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
++int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
+
+ DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics) __read_mostly;
+
+@@ -568,7 +568,7 @@ new_segment:
+ skb->truesize += copy;
+ sk->sk_wmem_queued += copy;
+ sk->sk_forward_alloc -= copy;
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+ tp->write_seq += copy;
+ TCP_SKB_CB(skb)->end_seq += copy;
+ skb_shinfo(skb)->gso_segs = 0;
+@@ -723,7 +723,7 @@ new_segment:
+ * Check whether we can use HW checksum.
+ */
+ if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ skb_entail(sk, tp, skb);
+ copy = size_goal;
+@@ -955,8 +955,11 @@ void tcp_cleanup_rbuf(struct sock *sk, i
+ * receive buffer and there was a small segment
+ * in queue.
+ */
+- (copied > 0 && (icsk->icsk_ack.pending & ICSK_ACK_PUSHED) &&
+- !icsk->icsk_ack.pingpong && !atomic_read(&sk->sk_rmem_alloc)))
++ (copied > 0 &&
++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) ||
++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) &&
++ !icsk->icsk_ack.pingpong)) &&
++ !atomic_read(&sk->sk_rmem_alloc)))
+ time_to_ack = 1;
+ }
+
+@@ -2205,7 +2208,7 @@ struct sk_buff *tcp_tso_segment(struct s
+ th->fin = th->psh = 0;
+
+ th->check = ~csum_fold(th->check + delta);
+- if (skb->ip_summed != CHECKSUM_HW)
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ th->check = csum_fold(csum_partial(skb->h.raw, thlen,
+ skb->csum));
+
+@@ -2219,7 +2222,7 @@ struct sk_buff *tcp_tso_segment(struct s
+
+ delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
+ th->check = ~csum_fold(th->check + delta);
+- if (skb->ip_summed != CHECKSUM_HW)
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ th->check = csum_fold(csum_partial(skb->h.raw, thlen,
+ skb->csum));
+
+@@ -2254,9 +2257,7 @@ void __init tcp_init(void)
+ tcp_hashinfo.bind_bucket_cachep =
+ kmem_cache_create("tcp_bind_bucket",
+ sizeof(struct inet_bind_bucket), 0,
+- SLAB_HWCACHE_ALIGN, NULL, NULL);
+- if (!tcp_hashinfo.bind_bucket_cachep)
+- panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+
+ /* Size and allocate the main established and bind bucket
+ * hash tables.
+diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
+index b0134ab..5730333 100644
+--- a/net/ipv4/tcp_bic.c
++++ b/net/ipv4/tcp_bic.c
+@@ -231,7 +231,7 @@ static struct tcp_congestion_ops bictcp
+
+ static int __init bictcp_register(void)
+ {
+- BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&bictcp);
+ }
+
+diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
+index 7ff2e42..1e2982f 100644
+--- a/net/ipv4/tcp_cong.c
++++ b/net/ipv4/tcp_cong.c
+@@ -48,7 +48,7 @@ int tcp_register_congestion_control(stru
+ printk(KERN_NOTICE "TCP %s already registered\n", ca->name);
+ ret = -EEXIST;
+ } else {
+- list_add_rcu(&ca->list, &tcp_cong_list);
++ list_add_tail_rcu(&ca->list, &tcp_cong_list);
+ printk(KERN_INFO "TCP %s registered\n", ca->name);
+ }
+ spin_unlock(&tcp_cong_list_lock);
+@@ -131,6 +131,14 @@ int tcp_set_default_congestion_control(c
+ return ret;
+ }
+
++/* Set default value from kernel configuration at bootup */
++static int __init tcp_congestion_default(void)
++{
++ return tcp_set_default_congestion_control(CONFIG_DEFAULT_TCP_CONG);
++}
++late_initcall(tcp_congestion_default);
++
++
+ /* Get current default congestion control */
+ void tcp_get_default_congestion_control(char *name)
+ {
+diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
+index 2be2798..6ad1848 100644
+--- a/net/ipv4/tcp_cubic.c
++++ b/net/ipv4/tcp_cubic.c
+@@ -190,7 +190,7 @@ static inline void bictcp_update(struct
+ */
+
+ /* change the unit from HZ to bictcp_HZ */
+- t = ((tcp_time_stamp + ca->delay_min - ca->epoch_start)
++ t = ((tcp_time_stamp + (ca->delay_min>>3) - ca->epoch_start)
+ << BICTCP_HZ) / HZ;
+
+ if (t < ca->bic_K) /* t - K */
+@@ -259,7 +259,7 @@ static inline void measure_delay(struct
+ (s32)(tcp_time_stamp - ca->epoch_start) < HZ)
+ return;
+
+- delay = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
++ delay = (tcp_time_stamp - tp->rx_opt.rcv_tsecr)<<3;
+ if (delay == 0)
+ delay = 1;
+
+@@ -358,7 +358,7 @@ static struct tcp_congestion_ops cubictc
+
+ static int __init cubictcp_register(void)
+ {
+- BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
+
+ /* Precompute a bunch of the scaling factors that are used per-packet
+ * based on SRTT of 100ms
+@@ -366,7 +366,7 @@ static int __init cubictcp_register(void
+
+ beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta);
+
+- cube_rtt_scale = (bic_scale << 3) / 10; /* 1024*c/rtt */
++ cube_rtt_scale = (bic_scale * 10); /* 1024*c/rtt */
+
+ /* calculate the "K" for (wmax-cwnd) = c/rtt * K^3
+ * so K = cubic_root( (wmax-cwnd)*rtt/c )
+diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
+index fa3e1aa..c4fc811 100644
+--- a/net/ipv4/tcp_highspeed.c
++++ b/net/ipv4/tcp_highspeed.c
+@@ -189,7 +189,7 @@ static struct tcp_congestion_ops tcp_hig
+
+ static int __init hstcp_register(void)
+ {
+- BUG_ON(sizeof(struct hstcp) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct hstcp) > ICSK_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_highspeed);
+ }
+
+diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
+index 6edfe5e..283be3c 100644
+--- a/net/ipv4/tcp_htcp.c
++++ b/net/ipv4/tcp_htcp.c
+@@ -23,7 +23,7 @@ module_param(use_bandwidth_switch, int,
+ MODULE_PARM_DESC(use_bandwidth_switch, "turn on/off bandwidth switcher");
+
+ struct htcp {
+- u16 alpha; /* Fixed point arith, << 7 */
++ u32 alpha; /* Fixed point arith, << 7 */
+ u8 beta; /* Fixed point arith, << 7 */
+ u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */
+ u32 last_cong; /* Time since last congestion event end */
+@@ -286,7 +286,7 @@ static struct tcp_congestion_ops htcp =
+
+ static int __init htcp_register(void)
+ {
+- BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE);
+ BUILD_BUG_ON(BETA_MIN >= BETA_MAX);
+ return tcp_register_congestion_control(&htcp);
+ }
+diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
+index 7406e0c..59e691d 100644
+--- a/net/ipv4/tcp_hybla.c
++++ b/net/ipv4/tcp_hybla.c
+@@ -170,7 +170,7 @@ static struct tcp_congestion_ops tcp_hyb
+
+ static int __init hybla_register(void)
+ {
+- BUG_ON(sizeof(struct hybla) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct hybla) > ICSK_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_hybla);
+ }
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 159fa3f..cf06acc 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -72,24 +72,24 @@
+ #include <asm/unaligned.h>
+ #include <net/netdma.h>
+
+-int sysctl_tcp_timestamps = 1;
+-int sysctl_tcp_window_scaling = 1;
+-int sysctl_tcp_sack = 1;
+-int sysctl_tcp_fack = 1;
+-int sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH;
+-int sysctl_tcp_ecn;
+-int sysctl_tcp_dsack = 1;
+-int sysctl_tcp_app_win = 31;
+-int sysctl_tcp_adv_win_scale = 2;
+-
+-int sysctl_tcp_stdurg;
+-int sysctl_tcp_rfc1337;
+-int sysctl_tcp_max_orphans = NR_FILE;
+-int sysctl_tcp_frto;
+-int sysctl_tcp_nometrics_save;
+-
+-int sysctl_tcp_moderate_rcvbuf = 1;
+-int sysctl_tcp_abc;
++int sysctl_tcp_timestamps __read_mostly = 1;
++int sysctl_tcp_window_scaling __read_mostly = 1;
++int sysctl_tcp_sack __read_mostly = 1;
++int sysctl_tcp_fack __read_mostly = 1;
++int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH;
++int sysctl_tcp_ecn __read_mostly;
++int sysctl_tcp_dsack __read_mostly = 1;
++int sysctl_tcp_app_win __read_mostly = 31;
++int sysctl_tcp_adv_win_scale __read_mostly = 2;
++
++int sysctl_tcp_stdurg __read_mostly;
++int sysctl_tcp_rfc1337 __read_mostly;
++int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
++int sysctl_tcp_frto __read_mostly;
++int sysctl_tcp_nometrics_save __read_mostly;
++
++int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
++int sysctl_tcp_abc __read_mostly;
+
+ #define FLAG_DATA 0x01 /* Incoming frame contained data. */
+ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
+@@ -127,7 +127,7 @@ static void tcp_measure_rcv_mss(struct s
+ /* skb->len may jitter because of SACKs, even if peer
+ * sends good full-sized frames.
+ */
+- len = skb->len;
++ len = skb_shinfo(skb)->gso_size ?: skb->len;
+ if (len >= icsk->icsk_ack.rcv_mss) {
+ icsk->icsk_ack.rcv_mss = len;
+ } else {
+@@ -156,6 +156,8 @@ static void tcp_measure_rcv_mss(struct s
+ return;
+ }
+ }
++ if (icsk->icsk_ack.pending & ICSK_ACK_PUSHED)
++ icsk->icsk_ack.pending |= ICSK_ACK_PUSHED2;
+ icsk->icsk_ack.pending |= ICSK_ACK_PUSHED;
+ }
+ }
+@@ -933,7 +935,7 @@ tcp_sacktag_write_queue(struct sock *sk,
+ const struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+ unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
+- struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
++ struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
+ int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
+ int reord = tp->packets_out;
+ int prior_fackets;
+@@ -2237,13 +2239,12 @@ static int tcp_tso_acked(struct sock *sk
+ return acked;
+ }
+
+-static u32 tcp_usrtt(const struct sk_buff *skb)
++static u32 tcp_usrtt(struct timeval *tv)
+ {
+- struct timeval tv, now;
++ struct timeval now;
+
+ do_gettimeofday(&now);
+- skb_get_timestamp(skb, &tv);
+- return (now.tv_sec - tv.tv_sec) * 1000000 + (now.tv_usec - tv.tv_usec);
++ return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - tv->tv_usec);
+ }
+
+ /* Remove acknowledged frames from the retransmission queue. */
+@@ -2258,6 +2259,7 @@ static int tcp_clean_rtx_queue(struct so
+ u32 pkts_acked = 0;
+ void (*rtt_sample)(struct sock *sk, u32 usrtt)
+ = icsk->icsk_ca_ops->rtt_sample;
++ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
+
+ while ((skb = skb_peek(&sk->sk_write_queue)) &&
+ skb != sk->sk_send_head) {
+@@ -2306,8 +2308,7 @@ static int tcp_clean_rtx_queue(struct so
+ seq_rtt = -1;
+ } else if (seq_rtt < 0) {
+ seq_rtt = now - scb->when;
+- if (rtt_sample)
+- (*rtt_sample)(sk, tcp_usrtt(skb));
++ skb_get_timestamp(skb, &tv);
+ }
+ if (sacked & TCPCB_SACKED_ACKED)
+ tp->sacked_out -= tcp_skb_pcount(skb);
+@@ -2320,8 +2321,7 @@ static int tcp_clean_rtx_queue(struct so
+ }
+ } else if (seq_rtt < 0) {
+ seq_rtt = now - scb->when;
+- if (rtt_sample)
+- (*rtt_sample)(sk, tcp_usrtt(skb));
++ skb_get_timestamp(skb, &tv);
+ }
+ tcp_dec_pcount_approx(&tp->fackets_out, skb);
+ tcp_packets_out_dec(tp, skb);
+@@ -2333,6 +2333,8 @@ static int tcp_clean_rtx_queue(struct so
+ if (acked&FLAG_ACKED) {
+ tcp_ack_update_rtt(sk, acked, seq_rtt);
+ tcp_ack_packets_out(sk, tp);
++ if (rtt_sample && !(acked & FLAG_RETRANS_DATA_ACKED))
++ (*rtt_sample)(sk, tcp_usrtt(&tv));
+
+ if (icsk->icsk_ca_ops->pkts_acked)
+ icsk->icsk_ca_ops->pkts_acked(sk, pkts_acked);
+@@ -2627,7 +2629,7 @@ void tcp_parse_options(struct sk_buff *s
+ switch(opcode) {
+ case TCPOPT_MSS:
+ if(opsize==TCPOLEN_MSS && th->syn && !estab) {
+- u16 in_mss = ntohs(get_unaligned((__u16 *)ptr));
++ u16 in_mss = ntohs(get_unaligned((__be16 *)ptr));
+ if (in_mss) {
+ if (opt_rx->user_mss && opt_rx->user_mss < in_mss)
+ in_mss = opt_rx->user_mss;
+@@ -2655,8 +2657,8 @@ void tcp_parse_options(struct sk_buff *s
+ if ((estab && opt_rx->tstamp_ok) ||
+ (!estab && sysctl_tcp_timestamps)) {
+ opt_rx->saw_tstamp = 1;
+- opt_rx->rcv_tsval = ntohl(get_unaligned((__u32 *)ptr));
+- opt_rx->rcv_tsecr = ntohl(get_unaligned((__u32 *)(ptr+4)));
++ opt_rx->rcv_tsval = ntohl(get_unaligned((__be32 *)ptr));
++ opt_rx->rcv_tsecr = ntohl(get_unaligned((__be32 *)(ptr+4)));
+ }
+ }
+ break;
+@@ -2693,8 +2695,8 @@ static int tcp_fast_parse_options(struct
+ return 0;
+ } else if (tp->rx_opt.tstamp_ok &&
+ th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
+- __u32 *ptr = (__u32 *)(th + 1);
+- if (*ptr == ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
++ __be32 *ptr = (__be32 *)(th + 1);
++ if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+ tp->rx_opt.saw_tstamp = 1;
+ ++ptr;
+@@ -3909,10 +3911,10 @@ int tcp_rcv_established(struct sock *sk,
+
+ /* Check timestamp */
+ if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
+- __u32 *ptr = (__u32 *)(th + 1);
++ __be32 *ptr = (__be32 *)(th + 1);
+
+ /* No? Slow path! */
+- if (*ptr != ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
++ if (*ptr != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
+ goto slow_path;
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 4b04c3e..22ef8bd 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -78,8 +78,8 @@
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+
+-int sysctl_tcp_tw_reuse;
+-int sysctl_tcp_low_latency;
++int sysctl_tcp_tw_reuse __read_mostly;
++int sysctl_tcp_low_latency __read_mostly;
+
+ /* Check TCP sequence numbers in ICMP packets. */
+ #define ICMP_MIN_LENGTH 8
+@@ -159,7 +159,7 @@ int tcp_v4_connect(struct sock *sk, stru
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
+ struct rtable *rt;
+- u32 daddr, nexthop;
++ __be32 daddr, nexthop;
+ int tmp;
+ int err;
+
+@@ -355,7 +355,7 @@ void tcp_v4_err(struct sk_buff *skb, u32
+ return;
+ }
+ if (sk->sk_state == TCP_TIME_WAIT) {
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ return;
+ }
+
+@@ -373,7 +373,7 @@ void tcp_v4_err(struct sk_buff *skb, u32
+ seq = ntohl(th->seq);
+ if (sk->sk_state != TCP_LISTEN &&
+ !between(seq, tp->snd_una, tp->snd_nxt)) {
+- NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
++ NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
+ goto out;
+ }
+
+@@ -484,7 +484,7 @@ void tcp_v4_send_check(struct sock *sk,
+ struct inet_sock *inet = inet_sk(sk);
+ struct tcphdr *th = skb->h.th;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0);
+ skb->csum = offsetof(struct tcphdr, check);
+ } else {
+@@ -509,7 +509,7 @@ int tcp_v4_gso_send_check(struct sk_buff
+ th->check = 0;
+ th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
+ skb->csum = offsetof(struct tcphdr, check);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+ return 0;
+ }
+
+@@ -578,7 +578,7 @@ static void tcp_v4_send_ack(struct sk_bu
+ struct tcphdr *th = skb->h.th;
+ struct {
+ struct tcphdr th;
+- u32 tsopt[3];
++ u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2];
+ } rep;
+ struct ip_reply_arg arg;
+
+@@ -734,8 +734,8 @@ int tcp_v4_conn_request(struct sock *sk,
+ struct inet_request_sock *ireq;
+ struct tcp_options_received tmp_opt;
+ struct request_sock *req;
+- __u32 saddr = skb->nh.iph->saddr;
+- __u32 daddr = skb->nh.iph->daddr;
++ __be32 saddr = skb->nh.iph->saddr;
++ __be32 daddr = skb->nh.iph->daddr;
+ __u32 isn = TCP_SKB_CB(skb)->when;
+ struct dst_entry *dst = NULL;
+ #ifdef CONFIG_SYN_COOKIES
+@@ -798,6 +798,9 @@ int tcp_v4_conn_request(struct sock *sk,
+
+ tcp_openreq_init(req, &tmp_opt, skb);
+
++ if (security_inet_conn_request(sk, skb, req))
++ goto drop_and_free;
++
+ ireq = inet_rsk(req);
+ ireq->loc_addr = daddr;
+ ireq->rmt_addr = saddr;
+@@ -948,16 +951,16 @@ static struct sock *tcp_v4_hnd_req(struc
+ if (req)
+ return tcp_check_req(sk, skb, req, prev);
+
+- nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr,
+- th->source, skb->nh.iph->daddr,
+- ntohs(th->dest), inet_iif(skb));
++ nsk = inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr,
++ th->source, skb->nh.iph->daddr,
++ th->dest, inet_iif(skb));
+
+ if (nsk) {
+ if (nsk->sk_state != TCP_TIME_WAIT) {
+ bh_lock_sock(nsk);
+ return nsk;
+ }
+- inet_twsk_put((struct inet_timewait_sock *)nsk);
++ inet_twsk_put(inet_twsk(nsk));
+ return NULL;
+ }
+
+@@ -970,7 +973,7 @@ static struct sock *tcp_v4_hnd_req(struc
+
+ static int tcp_v4_checksum_init(struct sk_buff *skb)
+ {
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
+ skb->nh.iph->daddr, skb->csum)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+@@ -1087,7 +1090,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
+ TCP_SKB_CB(skb)->sacked = 0;
+
+ sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
+- skb->nh.iph->daddr, ntohs(th->dest),
++ skb->nh.iph->daddr, th->dest,
+ inet_iif(skb));
+
+ if (!sk)
+@@ -1101,7 +1104,7 @@ process:
+ goto discard_and_relse;
+ nf_reset(skb);
+
+- if (sk_filter(sk, skb, 0))
++ if (sk_filter(sk, skb))
+ goto discard_and_relse;
+
+ skb->dev = NULL;
+@@ -1151,26 +1154,24 @@ discard_and_relse:
+
+ do_time_wait:
+ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+- inet_twsk_put((struct inet_timewait_sock *) sk);
++ inet_twsk_put(inet_twsk(sk));
+ goto discard_it;
+ }
+
+ if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
+ TCP_INC_STATS_BH(TCP_MIB_INERRS);
+- inet_twsk_put((struct inet_timewait_sock *) sk);
++ inet_twsk_put(inet_twsk(sk));
+ goto discard_it;
+ }
+- switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
+- skb, th)) {
++ switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
+ case TCP_TW_SYN: {
+ struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo,
+ skb->nh.iph->daddr,
+- ntohs(th->dest),
++ th->dest,
+ inet_iif(skb));
+ if (sk2) {
+- inet_twsk_deschedule((struct inet_timewait_sock *)sk,
+- &tcp_death_row);
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
++ inet_twsk_put(inet_twsk(sk));
+ sk = sk2;
+ goto process;
+ }
+@@ -1760,7 +1761,7 @@ static void get_tcp4_sock(struct sock *s
+
+ static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i)
+ {
+- unsigned int dest, src;
++ __be32 dest, src;
+ __u16 destp, srcp;
+ int ttd = tw->tw_ttd - jiffies;
+
+diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
+index 48f28d6..f0ebaf0 100644
+--- a/net/ipv4/tcp_lp.c
++++ b/net/ipv4/tcp_lp.c
+@@ -31,11 +31,8 @@
+ * Hung Hing Lun, Mike <hlhung3i at gmail.com>
+ * SourceForge project page:
+ * http://tcp-lp-mod.sourceforge.net/
+- *
+- * Version: $Id: tcp_lp.c,v 1.24 2006/09/05 20:22:53 hswong3i Exp $
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <net/tcp.h>
+
+@@ -165,7 +162,7 @@ static u32 tcp_lp_remote_hz_estimator(st
+
+ out:
+ /* record time for successful remote HZ calc */
+- if (rhz > 0)
++ if ((rhz >> 6) > 0)
+ lp->flag |= LP_VALID_RHZ;
+ else
+ lp->flag &= ~LP_VALID_RHZ;
+@@ -328,7 +325,7 @@ static struct tcp_congestion_ops tcp_lp
+
+ static int __init tcp_lp_register(void)
+ {
+- BUG_ON(sizeof(struct lp) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct lp) > ICSK_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_lp);
+ }
+
+diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
+index 624e2b2..0163d98 100644
+--- a/net/ipv4/tcp_minisocks.c
++++ b/net/ipv4/tcp_minisocks.c
+@@ -34,8 +34,8 @@
+ #define SYNC_INIT 1
+ #endif
+
+-int sysctl_tcp_syncookies = SYNC_INIT;
+-int sysctl_tcp_abort_on_overflow;
++int sysctl_tcp_syncookies __read_mostly = SYNC_INIT;
++int sysctl_tcp_abort_on_overflow __read_mostly;
+
+ struct inet_timewait_death_row tcp_death_row = {
+ .sysctl_max_tw_buckets = NR_FILE * 2,
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index b4f3ffe..ca40615 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -43,24 +43,24 @@
+ #include <linux/smp_lock.h>
+
+ /* People can turn this off for buggy TCP's found in printers etc. */
+-int sysctl_tcp_retrans_collapse = 1;
++int sysctl_tcp_retrans_collapse __read_mostly = 1;
+
+ /* People can turn this on to work with those rare, broken TCPs that
+ * interpret the window field as a signed quantity.
+ */
+-int sysctl_tcp_workaround_signed_windows = 0;
++int sysctl_tcp_workaround_signed_windows __read_mostly = 0;
+
+ /* This limits the percentage of the congestion window which we
+ * 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 = 3;
++int sysctl_tcp_tso_win_divisor __read_mostly = 3;
+
+-int sysctl_tcp_mtu_probing = 0;
+-int sysctl_tcp_base_mss = 512;
++int sysctl_tcp_mtu_probing __read_mostly = 0;
++int sysctl_tcp_base_mss __read_mostly = 512;
+
+ /* By default, RFC2861 behavior. */
+-int sysctl_tcp_slow_start_after_idle = 1;
++int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
+
+ static void update_send_head(struct sock *sk, struct tcp_sock *tp,
+ struct sk_buff *skb)
+@@ -269,14 +269,14 @@ static u16 tcp_select_window(struct sock
+ return new_win;
+ }
+
+-static void tcp_build_and_update_options(__u32 *ptr, struct tcp_sock *tp,
++static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp,
+ __u32 tstamp)
+ {
+ if (tp->rx_opt.tstamp_ok) {
+- *ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
+- (TCPOPT_NOP << 16) |
+- (TCPOPT_TIMESTAMP << 8) |
+- TCPOLEN_TIMESTAMP);
++ *ptr++ = htonl((TCPOPT_NOP << 24) |
++ (TCPOPT_NOP << 16) |
++ (TCPOPT_TIMESTAMP << 8) |
++ TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl(tstamp);
+ *ptr++ = htonl(tp->rx_opt.ts_recent);
+ }
+@@ -305,7 +305,7 @@ static void tcp_build_and_update_options
+ * MAX_SYN_SIZE to match the new maximum number of options that you
+ * can generate.
+ */
+-static void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
++static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack,
+ int offer_wscale, int wscale, __u32 tstamp,
+ __u32 ts_recent)
+ {
+@@ -325,18 +325,27 @@ static void tcp_syn_build_options(__u32
+ *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
+ if (ts) {
+ if(sack)
+- *ptr++ = __constant_htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) |
+- (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
++ *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
++ (TCPOLEN_SACK_PERM << 16) |
++ (TCPOPT_TIMESTAMP << 8) |
++ TCPOLEN_TIMESTAMP);
+ else
+- *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+- (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
++ *ptr++ = htonl((TCPOPT_NOP << 24) |
++ (TCPOPT_NOP << 16) |
++ (TCPOPT_TIMESTAMP << 8) |
++ TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl(tstamp); /* TSVAL */
+ *ptr++ = htonl(ts_recent); /* TSECR */
+ } else if(sack)
+- *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+- (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM);
++ *ptr++ = htonl((TCPOPT_NOP << 24) |
++ (TCPOPT_NOP << 16) |
++ (TCPOPT_SACK_PERM << 8) |
++ TCPOLEN_SACK_PERM);
+ if (offer_wscale)
+- *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale));
++ *ptr++ = htonl((TCPOPT_NOP << 24) |
++ (TCPOPT_WINDOW << 16) |
++ (TCPOLEN_WINDOW << 8) |
++ (wscale));
+ }
+
+ /* This routine actually transmits TCP packets queued in by
+@@ -424,7 +433,7 @@ static int tcp_transmit_skb(struct sock
+ th->dest = inet->dport;
+ th->seq = htonl(tcb->seq);
+ th->ack_seq = htonl(tp->rcv_nxt);
+- *(((__u16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
++ *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
+ tcb->flags);
+
+ if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
+@@ -445,7 +454,7 @@ static int tcp_transmit_skb(struct sock
+ }
+
+ if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
+- tcp_syn_build_options((__u32 *)(th + 1),
++ tcp_syn_build_options((__be32 *)(th + 1),
+ tcp_advertise_mss(sk),
+ (sysctl_flags & SYSCTL_FLAG_TSTAMPS),
+ (sysctl_flags & SYSCTL_FLAG_SACK),
+@@ -454,7 +463,7 @@ static int tcp_transmit_skb(struct sock
+ tcb->when,
+ tp->rx_opt.ts_recent);
+ } else {
+- tcp_build_and_update_options((__u32 *)(th + 1),
++ tcp_build_and_update_options((__be32 *)(th + 1),
+ tp, tcb->when);
+ TCP_ECN_send(sk, tp, skb, tcp_header_size);
+ }
+@@ -577,7 +586,7 @@ int tcp_fragment(struct sock *sk, struct
+ TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked;
+ TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL;
+
+- if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) {
++ if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_PARTIAL) {
+ /* Copy and checksum data tail into the new buffer. */
+ buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize),
+ nsize, 0);
+@@ -586,7 +595,7 @@ int tcp_fragment(struct sock *sk, struct
+
+ skb->csum = csum_block_sub(skb->csum, buff->csum, len);
+ } else {
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb_split(skb, buff, len);
+ }
+
+@@ -689,7 +698,7 @@ int tcp_trim_head(struct sock *sk, struc
+ __pskb_trim_head(skb, len - skb_headlen(skb));
+
+ TCP_SKB_CB(skb)->seq += len;
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ skb->truesize -= len;
+ sk->sk_wmem_queued -= len;
+@@ -1062,7 +1071,7 @@ static int tso_fragment(struct sock *sk,
+ /* 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;
++ buff->ip_summed = skb->ip_summed = CHECKSUM_PARTIAL;
+ skb_split(skb, buff, len);
+
+ /* Fix up tso_factor for both original and new SKB. */
+@@ -1087,10 +1096,14 @@ static int tcp_tso_should_defer(struct s
+ u32 send_win, cong_win, limit, in_flight;
+
+ if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+- return 0;
++ goto send_now;
+
+ if (icsk->icsk_ca_state != TCP_CA_Open)
+- return 0;
++ goto send_now;
++
++ /* Defer for less than two clock ticks. */
++ if (!tp->tso_deferred && ((jiffies<<1)>>1) - (tp->tso_deferred>>1) > 1)
++ goto send_now;
+
+ in_flight = tcp_packets_in_flight(tp);
+
+@@ -1106,7 +1119,7 @@ static int tcp_tso_should_defer(struct s
+
+ /* If a full-sized TSO skb can be sent, do it. */
+ if (limit >= 65536)
+- return 0;
++ goto send_now;
+
+ if (sysctl_tcp_tso_win_divisor) {
+ u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
+@@ -1116,7 +1129,7 @@ static int tcp_tso_should_defer(struct s
+ */
+ chunk /= sysctl_tcp_tso_win_divisor;
+ if (limit >= chunk)
+- return 0;
++ goto send_now;
+ } else {
+ /* Different approach, try not to defer past a single
+ * ACK. Receiver should ACK every other full sized
+@@ -1124,11 +1137,17 @@ static int tcp_tso_should_defer(struct s
+ * then send now.
+ */
+ if (limit > tcp_max_burst(tp) * tp->mss_cache)
+- return 0;
++ goto send_now;
+ }
+
+ /* Ok, it looks like it is advisable to defer. */
++ tp->tso_deferred = 1 | (jiffies<<1);
++
+ return 1;
++
++send_now:
++ tp->tso_deferred = 0;
++ return 0;
+ }
+
+ /* Create a new MTU probe if we are ready.
+@@ -1206,8 +1225,7 @@ static int tcp_mtu_probe(struct sock *sk
+ TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(nskb)->sacked = 0;
+ nskb->csum = 0;
+- if (skb->ip_summed == CHECKSUM_HW)
+- nskb->ip_summed = CHECKSUM_HW;
++ nskb->ip_summed = skb->ip_summed;
+
+ len = 0;
+ while (len < probe_size) {
+@@ -1231,7 +1249,7 @@ static int tcp_mtu_probe(struct sock *sk
+ ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+ if (!skb_shinfo(skb)->nr_frags) {
+ skb_pull(skb, copy);
+- if (skb->ip_summed != CHECKSUM_HW)
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ skb->csum = csum_partial(skb->data, skb->len, 0);
+ } else {
+ __pskb_trim_head(skb, copy);
+@@ -1572,10 +1590,9 @@ static void tcp_retrans_try_collapse(str
+
+ memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
+
+- if (next_skb->ip_summed == CHECKSUM_HW)
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = next_skb->ip_summed;
+
+- if (skb->ip_summed != CHECKSUM_HW)
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ skb->csum = csum_block_add(skb->csum, next_skb->csum, skb_size);
+
+ /* Update sequence range on original skb. */
+@@ -2072,7 +2089,7 @@ struct sk_buff * tcp_make_synack(struct
+ th->window = htons(req->rcv_wnd);
+
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+- tcp_syn_build_options((__u32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
++ tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
+ ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
+ TCP_SKB_CB(skb)->when,
+ req->ts_recent);
+diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
+index dab37d2..4be336f 100644
+--- a/net/ipv4/tcp_probe.c
++++ b/net/ipv4/tcp_probe.c
+@@ -99,8 +99,10 @@ static int jtcp_sendmsg(struct kiocb *io
+ }
+
+ static struct jprobe tcp_send_probe = {
+- .kp = { .addr = (kprobe_opcode_t *) &tcp_sendmsg, },
+- .entry = (kprobe_opcode_t *) &jtcp_sendmsg,
++ .kp = {
++ .symbol_name = "tcp_sendmsg",
++ },
++ .entry = JPROBE_ENTRY(jtcp_sendmsg),
+ };
+
+
+diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
+index 7c1bde3..fb09ade 100644
+--- a/net/ipv4/tcp_timer.c
++++ b/net/ipv4/tcp_timer.c
+@@ -23,14 +23,14 @@
+ #include <linux/module.h>
+ #include <net/tcp.h>
+
+-int sysctl_tcp_syn_retries = TCP_SYN_RETRIES;
+-int sysctl_tcp_synack_retries = TCP_SYNACK_RETRIES;
+-int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;
+-int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;
+-int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL;
+-int sysctl_tcp_retries1 = TCP_RETR1;
+-int sysctl_tcp_retries2 = TCP_RETR2;
+-int sysctl_tcp_orphan_retries;
++int sysctl_tcp_syn_retries __read_mostly = TCP_SYN_RETRIES;
++int sysctl_tcp_synack_retries __read_mostly = TCP_SYNACK_RETRIES;
++int sysctl_tcp_keepalive_time __read_mostly = TCP_KEEPALIVE_TIME;
++int sysctl_tcp_keepalive_probes __read_mostly = TCP_KEEPALIVE_PROBES;
++int sysctl_tcp_keepalive_intvl __read_mostly = TCP_KEEPALIVE_INTVL;
++int sysctl_tcp_retries1 __read_mostly = TCP_RETR1;
++int sysctl_tcp_retries2 __read_mostly = TCP_RETR2;
++int sysctl_tcp_orphan_retries __read_mostly;
+
+ static void tcp_write_timer(unsigned long);
+ static void tcp_delack_timer(unsigned long);
+diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
+index 490360b..a3b7aa0 100644
+--- a/net/ipv4/tcp_vegas.c
++++ b/net/ipv4/tcp_vegas.c
+@@ -370,7 +370,7 @@ static struct tcp_congestion_ops tcp_veg
+
+ static int __init tcp_vegas_register(void)
+ {
+- BUG_ON(sizeof(struct vegas) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct vegas) > ICSK_CA_PRIV_SIZE);
+ tcp_register_congestion_control(&tcp_vegas);
+ return 0;
+ }
+diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
+index 11b42a7..ce57bf3 100644
+--- a/net/ipv4/tcp_veno.c
++++ b/net/ipv4/tcp_veno.c
+@@ -9,7 +9,6 @@
+ * See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf
+ */
+
+-#include <linux/config.h>
+ #include <linux/mm.h>
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+@@ -213,7 +212,7 @@ static struct tcp_congestion_ops tcp_ven
+
+ static int __init tcp_veno_register(void)
+ {
+- BUG_ON(sizeof(struct veno) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct veno) > ICSK_CA_PRIV_SIZE);
+ tcp_register_congestion_control(&tcp_veno);
+ return 0;
+ }
+diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
+index 5446312..4f42a86 100644
+--- a/net/ipv4/tcp_westwood.c
++++ b/net/ipv4/tcp_westwood.c
+@@ -289,7 +289,7 @@ static struct tcp_congestion_ops tcp_wes
+
+ static int __init tcp_westwood_register(void)
+ {
+- BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE);
++ BUILD_BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_westwood);
+ }
+
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index f136cec..865d752 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -118,14 +118,33 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_sta
+ struct hlist_head udp_hash[UDP_HTABLE_SIZE];
+ DEFINE_RWLOCK(udp_hash_lock);
+
+-/* Shared by v4/v6 udp. */
+-int udp_port_rover;
++static int udp_port_rover;
+
+-static int udp_v4_get_port(struct sock *sk, unsigned short snum)
++static inline int udp_lport_inuse(u16 num)
+ {
++ struct sock *sk;
+ struct hlist_node *node;
++
++ sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)])
++ if (inet_sk(sk)->num == num)
++ return 1;
++ return 0;
++}
++
++/**
++ * udp_get_port - common port lookup for IPv4 and IPv6
++ *
++ * @sk: socket struct in question
++ * @snum: port number to look up
++ * @saddr_comp: AF-dependent comparison of bound local IP addresses
++ */
++int udp_get_port(struct sock *sk, unsigned short snum,
++ int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2))
++{
++ struct hlist_node *node;
++ struct hlist_head *head;
+ struct sock *sk2;
+- struct inet_sock *inet = inet_sk(sk);
++ int error = 1;
+
+ write_lock_bh(&udp_hash_lock);
+ if (snum == 0) {
+@@ -137,11 +156,10 @@ static int udp_v4_get_port(struct sock *
+ best_size_so_far = 32767;
+ best = result = udp_port_rover;
+ for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+- struct hlist_head *list;
+ int size;
+
+- list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+- if (hlist_empty(list)) {
++ head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)];
++ if (hlist_empty(head)) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0] +
+ ((result - sysctl_local_port_range[0]) &
+@@ -149,12 +167,11 @@ static int udp_v4_get_port(struct sock *
+ goto gotit;
+ }
+ size = 0;
+- sk_for_each(sk2, node, list)
+- if (++size >= best_size_so_far)
+- goto next;
+- best_size_so_far = size;
+- best = result;
+- next:;
++ sk_for_each(sk2, node, head)
++ if (++size < best_size_so_far) {
++ best_size_so_far = size;
++ best = result;
++ }
+ }
+ result = best;
+ for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) {
+@@ -170,38 +187,44 @@ static int udp_v4_get_port(struct sock *
+ gotit:
+ udp_port_rover = snum = result;
+ } else {
+- sk_for_each(sk2, node,
+- &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) {
+- struct inet_sock *inet2 = inet_sk(sk2);
+-
+- if (inet2->num == snum &&
+- sk2 != sk &&
+- !ipv6_only_sock(sk2) &&
+- (!sk2->sk_bound_dev_if ||
+- !sk->sk_bound_dev_if ||
+- sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+- (!inet2->rcv_saddr ||
+- !inet->rcv_saddr ||
+- inet2->rcv_saddr == inet->rcv_saddr) &&
+- (!sk2->sk_reuse || !sk->sk_reuse))
++ head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
++
++ sk_for_each(sk2, node, head)
++ if (inet_sk(sk2)->num == snum &&
++ sk2 != sk &&
++ (!sk2->sk_reuse || !sk->sk_reuse) &&
++ (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
++ || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
++ (*saddr_cmp)(sk, sk2) )
+ goto fail;
+- }
+ }
+- inet->num = snum;
++ inet_sk(sk)->num = snum;
+ if (sk_unhashed(sk)) {
+- struct hlist_head *h = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
+-
+- sk_add_node(sk, h);
++ head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
++ sk_add_node(sk, head);
+ sock_prot_inc_use(sk->sk_prot);
+ }
+- write_unlock_bh(&udp_hash_lock);
+- return 0;
+-
++ error = 0;
+ fail:
+ write_unlock_bh(&udp_hash_lock);
+- return 1;
++ return error;
++}
++
++static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
++{
++ struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
++
++ return ( !ipv6_only_sock(sk2) &&
++ (!inet1->rcv_saddr || !inet2->rcv_saddr ||
++ inet1->rcv_saddr == inet2->rcv_saddr ));
++}
++
++static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
++{
++ return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
+ }
+
++
+ static void udp_v4_hash(struct sock *sk)
+ {
+ BUG();
+@@ -220,8 +243,8 @@ static void udp_v4_unhash(struct sock *s
+ /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
+ * harder than this. -DaveM
+ */
+-static struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport,
+- u32 daddr, u16 dport, int dif)
++static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport,
++ __be32 daddr, __be16 dport, int dif)
+ {
+ struct sock *sk, *result = NULL;
+ struct hlist_node *node;
+@@ -265,8 +288,8 @@ static struct sock *udp_v4_lookup_longwa
+ return result;
+ }
+
+-static __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport,
+- u32 daddr, u16 dport, int dif)
++static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport,
++ __be32 daddr, __be16 dport, int dif)
+ {
+ struct sock *sk;
+
+@@ -279,8 +302,8 @@ static __inline__ struct sock *udp_v4_lo
+ }
+
+ static inline struct sock *udp_v4_mcast_next(struct sock *sk,
+- u16 loc_port, u32 loc_addr,
+- u16 rmt_port, u32 rmt_addr,
++ __be16 loc_port, __be32 loc_addr,
++ __be16 rmt_port, __be32 rmt_addr,
+ int dif)
+ {
+ struct hlist_node *node;
+@@ -429,7 +452,7 @@ static int udp_push_pending_frames(struc
+ /*
+ * Only one fragment on the socket.
+ */
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ skb->csum = offsetof(struct udphdr, check);
+ uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst,
+ up->len, IPPROTO_UDP, 0);
+@@ -448,7 +471,7 @@ static int udp_push_pending_frames(struc
+ * fragments on the socket so that all csums of sk_buffs
+ * should be together.
+ */
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ int offset = (unsigned char *)uh - skb->data;
+ skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
+
+@@ -475,7 +498,7 @@ out:
+ }
+
+
+-static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
++static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base)
+ {
+ return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
+ }
+@@ -490,8 +513,8 @@ int udp_sendmsg(struct kiocb *iocb, stru
+ struct rtable *rt = NULL;
+ int free = 0;
+ int connected = 0;
+- u32 daddr, faddr, saddr;
+- u16 dport;
++ __be32 daddr, faddr, saddr;
++ __be16 dport;
+ u8 tos;
+ int err;
+ int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
+@@ -603,6 +626,7 @@ int udp_sendmsg(struct kiocb *iocb, stru
+ .uli_u = { .ports =
+ { .sport = inet->sport,
+ .dport = dport } } };
++ security_sk_classify_flow(sk, &fl);
+ err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+ if (err)
+ goto out;
+@@ -651,6 +675,8 @@ do_append_data:
+ udp_flush_pending_frames(sk);
+ else if (!corkreq)
+ err = udp_push_pending_frames(sk, up);
++ else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
++ up->pending = 0;
+ release_sock(sk);
+
+ out:
+@@ -661,6 +687,16 @@ out:
+ UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS);
+ return len;
+ }
++ /*
++ * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting
++ * ENOBUFS might not be good (it's not tunable per se), but otherwise
++ * we don't have a good statistic (IpOutDiscards but it can be too many
++ * things). We could add another new stat but at least for now that
++ * seems like overkill.
++ */
++ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
++ UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS);
++ }
+ return err;
+
+ do_confirm:
+@@ -897,7 +933,7 @@ static int udp_encap_rcv(struct sock * s
+ int iphlen, len;
+
+ __u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr);
+- __u32 *udpdata32 = (__u32 *)udpdata;
++ __be32 *udpdata32 = (__be32 *)udpdata;
+ __u16 encap_type = up->encap_type;
+
+ /* if we're overly short, let UDP handle it */
+@@ -980,6 +1016,7 @@ static int udp_encap_rcv(struct sock * s
+ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
+ struct udp_sock *up = udp_sk(sk);
++ int rc;
+
+ /*
+ * Charge it to the socket, dropping if the queue is full.
+@@ -1026,7 +1063,10 @@ static int udp_queue_rcv_skb(struct sock
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+
+- if (sock_queue_rcv_skb(sk,skb)<0) {
++ if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
++ /* Note that an ENOMEM error is charged twice */
++ if (rc == -ENOMEM)
++ UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS);
+ UDP_INC_STATS_BH(UDP_MIB_INERRORS);
+ kfree_skb(skb);
+ return -1;
+@@ -1042,7 +1082,7 @@ static int udp_queue_rcv_skb(struct sock
+ * so we don't need to lock the hashes.
+ */
+ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
+- u32 saddr, u32 daddr)
++ __be32 saddr, __be32 daddr)
+ {
+ struct sock *sk;
+ int dif;
+@@ -1083,11 +1123,11 @@ static int udp_v4_mcast_deliver(struct s
+ * including udp header and folding it to skb->csum.
+ */
+ static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
+- unsigned short ulen, u32 saddr, u32 daddr)
++ unsigned short ulen, __be32 saddr, __be32 daddr)
+ {
+ if (uh->check == 0) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+- } else if (skb->ip_summed == CHECKSUM_HW) {
++ } else if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+@@ -1108,8 +1148,8 @@ int udp_rcv(struct sk_buff *skb)
+ struct udphdr *uh;
+ unsigned short ulen;
+ struct rtable *rt = (struct rtable*)skb->dst;
+- u32 saddr = skb->nh.iph->saddr;
+- u32 daddr = skb->nh.iph->daddr;
++ __be32 saddr = skb->nh.iph->saddr;
++ __be32 daddr = skb->nh.iph->daddr;
+ int len = skb->len;
+
+ /*
+@@ -1525,8 +1565,8 @@ void udp_proc_unregister(struct udp_seq_
+ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket)
+ {
+ struct inet_sock *inet = inet_sk(sp);
+- unsigned int dest = inet->daddr;
+- unsigned int src = inet->rcv_saddr;
++ __be32 dest = inet->daddr;
++ __be32 src = inet->rcv_saddr;
+ __u16 destp = ntohs(inet->dport);
+ __u16 srcp = ntohs(inet->sport);
+
+@@ -1581,7 +1621,7 @@ EXPORT_SYMBOL(udp_disconnect);
+ EXPORT_SYMBOL(udp_hash);
+ EXPORT_SYMBOL(udp_hash_lock);
+ EXPORT_SYMBOL(udp_ioctl);
+-EXPORT_SYMBOL(udp_port_rover);
++EXPORT_SYMBOL(udp_get_port);
+ EXPORT_SYMBOL(udp_prot);
+ EXPORT_SYMBOL(udp_sendmsg);
+ EXPORT_SYMBOL(udp_poll);
+diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
+index 817ed84..8655d03 100644
+--- a/net/ipv4/xfrm4_input.c
++++ b/net/ipv4/xfrm4_input.c
+@@ -23,7 +23,7 @@ int xfrm4_rcv(struct sk_buff *skb)
+
+ EXPORT_SYMBOL(xfrm4_rcv);
+
+-static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
++static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
+ {
+ switch (nexthdr) {
+ case IPPROTO_IPIP:
+@@ -55,7 +55,7 @@ drop:
+ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
+ {
+ int err;
+- u32 spi, seq;
++ __be32 spi, seq;
+ struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
+ struct xfrm_state *x;
+ int xfrm_nr = 0;
+@@ -106,7 +106,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb,
+ if (x->mode->input(x, skb))
+ goto drop;
+
+- if (x->props.mode) {
++ if (x->props.mode == XFRM_MODE_TUNNEL) {
+ decaps = 1;
+ break;
+ }
+diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
+new file mode 100644
+index 0000000..89cf59e
+--- /dev/null
++++ b/net/ipv4/xfrm4_mode_beet.c
+@@ -0,0 +1,139 @@
++/*
++ * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
++ *
++ * Copyright (c) 2006 Diego Beltrami <diego.beltrami at gmail.com>
++ * Miika Komu <miika at iki.fi>
++ * Herbert Xu <herbert at gondor.apana.org.au>
++ * Abhinav Pathak <abhinav.pathak at hiit.fi>
++ * Jeff Ahrenholz <ahrenholz at gmail.com>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/stringify.h>
++#include <net/dst.h>
++#include <net/ip.h>
++#include <net/xfrm.h>
++
++/* Add encapsulation header.
++ *
++ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
++ * The following fields in it shall be filled in by x->type->output:
++ * tot_len
++ * check
++ *
++ * On exit, skb->h will be set to the start of the payload to be processed
++ * by x->type->output and skb->nh will be set to the top IP header.
++ */
++static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct iphdr *iph, *top_iph = NULL;
++ int hdrlen, optlen;
++
++ iph = skb->nh.iph;
++ skb->h.ipiph = iph;
++
++ hdrlen = 0;
++ optlen = iph->ihl * 4 - sizeof(*iph);
++ if (unlikely(optlen))
++ hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
++
++ skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen);
++ top_iph = skb->nh.iph;
++ hdrlen = iph->ihl * 4 - optlen;
++ skb->h.raw += hdrlen;
++
++ memmove(top_iph, iph, hdrlen);
++ if (unlikely(optlen)) {
++ struct ip_beet_phdr *ph;
++
++ BUG_ON(optlen < 0);
++
++ ph = (struct ip_beet_phdr *)skb->h.raw;
++ ph->padlen = 4 - (optlen & 4);
++ ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8;
++ ph->nexthdr = top_iph->protocol;
++
++ top_iph->protocol = IPPROTO_BEETPH;
++ top_iph->ihl = sizeof(struct iphdr) / 4;
++ }
++
++ top_iph->saddr = x->props.saddr.a4;
++ top_iph->daddr = x->id.daddr.a4;
++
++ return 0;
++}
++
++static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct iphdr *iph = skb->nh.iph;
++ int phlen = 0;
++ int optlen = 0;
++ __u8 ph_nexthdr = 0, protocol = 0;
++ int err = -EINVAL;
++
++ protocol = iph->protocol;
++
++ if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
++ struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1);
++
++ if (!pskb_may_pull(skb, sizeof(*ph)))
++ goto out;
++
++ phlen = ph->hdrlen * 8;
++ optlen = phlen - ph->padlen - sizeof(*ph);
++ if (optlen < 0 || optlen & 3 || optlen > 250)
++ goto out;
++
++ if (!pskb_may_pull(skb, phlen))
++ goto out;
++
++ ph_nexthdr = ph->nexthdr;
++ }
++
++ skb_push(skb, sizeof(*iph) - phlen + optlen);
++ memmove(skb->data, skb->nh.raw, sizeof(*iph));
++ skb->nh.raw = skb->data;
++
++ iph = skb->nh.iph;
++ iph->ihl = (sizeof(*iph) + optlen) / 4;
++ iph->tot_len = htons(skb->len);
++ iph->daddr = x->sel.daddr.a4;
++ iph->saddr = x->sel.saddr.a4;
++ if (ph_nexthdr)
++ iph->protocol = ph_nexthdr;
++ else
++ iph->protocol = protocol;
++ iph->check = 0;
++ iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
++ err = 0;
++out:
++ return err;
++}
++
++static struct xfrm_mode xfrm4_beet_mode = {
++ .input = xfrm4_beet_input,
++ .output = xfrm4_beet_output,
++ .owner = THIS_MODULE,
++ .encap = XFRM_MODE_BEET,
++};
++
++static int __init xfrm4_beet_init(void)
++{
++ return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
++}
++
++static void __exit xfrm4_beet_exit(void)
++{
++ int err;
++
++ err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
++ BUG_ON(err);
++}
++
++module_init(xfrm4_beet_init);
++module_exit(xfrm4_beet_exit);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);
+diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c
+index a9e6b3d..92676b7 100644
+--- a/net/ipv4/xfrm4_mode_transport.c
++++ b/net/ipv4/xfrm4_mode_transport.c
+@@ -21,9 +21,8 @@
+ * On exit, skb->h will be set to the start of the payload to be processed
+ * by x->type->output and skb->nh will be set to the top IP header.
+ */
+-static int xfrm4_transport_output(struct sk_buff *skb)
++static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
+ {
+- struct xfrm_state *x;
+ struct iphdr *iph;
+ int ihl;
+
+@@ -33,7 +32,6 @@ static int xfrm4_transport_output(struct
+ ihl = iph->ihl * 4;
+ skb->h.raw += ihl;
+
+- x = skb->dst->xfrm;
+ skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl);
+ return 0;
+ }
+diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
+index 13cafbe..e23c21d 100644
+--- a/net/ipv4/xfrm4_mode_tunnel.c
++++ b/net/ipv4/xfrm4_mode_tunnel.c
+@@ -33,10 +33,9 @@ static inline void ipip_ecn_decapsulate(
+ * On exit, skb->h will be set to the start of the payload to be processed
+ * by x->type->output and skb->nh will be set to the top IP header.
+ */
+-static int xfrm4_tunnel_output(struct sk_buff *skb)
++static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb->dst;
+- struct xfrm_state *x = dst->xfrm;
+ struct iphdr *iph, *top_iph;
+ int flags;
+
+diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
+index d16f863..04403fb 100644
+--- a/net/ipv4/xfrm4_output.c
++++ b/net/ipv4/xfrm4_output.c
+@@ -48,13 +48,13 @@ static int xfrm4_output_one(struct sk_bu
+ struct xfrm_state *x = dst->xfrm;
+ int err;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
+- err = skb_checksum_help(skb, 0);
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
++ err = skb_checksum_help(skb);
+ if (err)
+ goto error_nolock;
+ }
+
+- if (x->props.mode) {
++ if (x->props.mode == XFRM_MODE_TUNNEL) {
+ err = xfrm4_tunnel_check_size(skb);
+ if (err)
+ goto error_nolock;
+@@ -66,7 +66,7 @@ static int xfrm4_output_one(struct sk_bu
+ if (err)
+ goto error;
+
+- err = x->mode->output(skb);
++ err = x->mode->output(x, skb);
+ if (err)
+ goto error;
+
+@@ -85,7 +85,7 @@ static int xfrm4_output_one(struct sk_bu
+ }
+ dst = skb->dst;
+ x = dst->xfrm;
+- } while (x && !x->props.mode);
++ } while (x && (x->props.mode != XFRM_MODE_TUNNEL));
+
+ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+ err = 0;
+diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
+index 8f50eae..1bed0cd 100644
+--- a/net/ipv4/xfrm4_policy.c
++++ b/net/ipv4/xfrm4_policy.c
+@@ -21,6 +21,25 @@ static int xfrm4_dst_lookup(struct xfrm_
+ return __ip_route_output_key((struct rtable**)dst, fl);
+ }
+
++static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
++{
++ struct rtable *rt;
++ struct flowi fl_tunnel = {
++ .nl_u = {
++ .ip4_u = {
++ .daddr = daddr->a4,
++ },
++ },
++ };
++
++ if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
++ saddr->a4 = rt->rt_src;
++ dst_release(&rt->u.dst);
++ return 0;
++ }
++ return -EHOSTUNREACH;
++}
++
+ static struct dst_entry *
+ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
+ {
+@@ -33,7 +52,7 @@ __xfrm4_find_bundle(struct flowi *fl, st
+ xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
+ xdst->u.rt.fl.fl4_src == fl->fl4_src &&
+ xdst->u.rt.fl.fl4_tos == fl->fl4_tos &&
+- xfrm_bundle_ok(xdst, fl, AF_INET)) {
++ xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) {
+ dst_clone(dst);
+ break;
+ }
+@@ -93,10 +112,11 @@ __xfrm4_bundle_create(struct xfrm_policy
+
+ xdst = (struct xfrm_dst *)dst1;
+ xdst->route = &rt->u.dst;
++ xdst->genid = xfrm[i]->genid;
+
+ dst1->next = dst_prev;
+ dst_prev = dst1;
+- if (xfrm[i]->props.mode) {
++ if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+ remote = xfrm[i]->id.daddr.a4;
+ local = xfrm[i]->props.saddr.a4;
+ tunnel = 1;
+@@ -135,6 +155,7 @@ __xfrm4_bundle_create(struct xfrm_policy
+ dst_prev->flags |= DST_HOST;
+ dst_prev->lastuse = jiffies;
+ dst_prev->header_len = header_len;
++ dst_prev->nfheader_len = 0;
+ dst_prev->trailer_len = trailer_len;
+ memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
+
+@@ -200,7 +221,7 @@ _decode_session4(struct sk_buff *skb, st
+
+ case IPPROTO_ESP:
+ if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
+- u32 *ehdr = (u32 *)xprth;
++ __be32 *ehdr = (__be32 *)xprth;
+
+ fl->fl_ipsec_spi = ehdr[0];
+ }
+@@ -208,7 +229,7 @@ _decode_session4(struct sk_buff *skb, st
+
+ case IPPROTO_AH:
+ if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
+- u32 *ah_hdr = (u32*)xprth;
++ __be32 *ah_hdr = (__be32*)xprth;
+
+ fl->fl_ipsec_spi = ah_hdr[1];
+ }
+@@ -216,7 +237,7 @@ _decode_session4(struct sk_buff *skb, st
+
+ case IPPROTO_COMP:
+ if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
+- u16 *ipcomp_hdr = (u16 *)xprth;
++ __be16 *ipcomp_hdr = (__be16 *)xprth;
+
+ fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
+ }
+@@ -296,6 +317,7 @@ static struct xfrm_policy_afinfo xfrm4_p
+ .family = AF_INET,
+ .dst_ops = &xfrm4_dst_ops,
+ .dst_lookup = xfrm4_dst_lookup,
++ .get_saddr = xfrm4_get_saddr,
+ .find_bundle = __xfrm4_find_bundle,
+ .bundle_create = __xfrm4_bundle_create,
+ .decode_session = _decode_session4,
+diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
+index 81e1751..3cc3df0 100644
+--- a/net/ipv4/xfrm4_state.c
++++ b/net/ipv4/xfrm4_state.c
+@@ -29,9 +29,9 @@ __xfrm4_init_tempsel(struct xfrm_state *
+ x->sel.daddr.a4 = fl->fl4_dst;
+ x->sel.saddr.a4 = fl->fl4_src;
+ x->sel.dport = xfrm_flowi_dport(fl);
+- x->sel.dport_mask = ~0;
++ x->sel.dport_mask = htons(0xffff);
+ x->sel.sport = xfrm_flowi_sport(fl);
+- x->sel.sport_mask = ~0;
++ x->sel.sport_mask = htons(0xffff);
+ x->sel.prefixlen_d = 32;
+ x->sel.prefixlen_s = 32;
+ x->sel.proto = fl->proto;
+@@ -42,99 +42,15 @@ __xfrm4_init_tempsel(struct xfrm_state *
+ x->props.saddr = tmpl->saddr;
+ if (x->props.saddr.a4 == 0)
+ x->props.saddr.a4 = saddr->a4;
+- if (tmpl->mode && x->props.saddr.a4 == 0) {
+- struct rtable *rt;
+- struct flowi fl_tunnel = {
+- .nl_u = {
+- .ip4_u = {
+- .daddr = x->id.daddr.a4,
+- }
+- }
+- };
+- if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
+- &fl_tunnel, AF_INET)) {
+- x->props.saddr.a4 = rt->rt_src;
+- dst_release(&rt->u.dst);
+- }
+- }
+ x->props.mode = tmpl->mode;
+ x->props.reqid = tmpl->reqid;
+ x->props.family = AF_INET;
+ }
+
+-static struct xfrm_state *
+-__xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
+-{
+- unsigned h = __xfrm4_spi_hash(daddr, spi, proto);
+- struct xfrm_state *x;
+-
+- list_for_each_entry(x, xfrm4_state_afinfo.state_byspi+h, byspi) {
+- if (x->props.family == AF_INET &&
+- spi == x->id.spi &&
+- daddr->a4 == x->id.daddr.a4 &&
+- proto == x->id.proto) {
+- xfrm_state_hold(x);
+- return x;
+- }
+- }
+- return NULL;
+-}
+-
+-static struct xfrm_state *
+-__xfrm4_find_acq(u8 mode, u32 reqid, u8 proto,
+- xfrm_address_t *daddr, xfrm_address_t *saddr,
+- int create)
+-{
+- struct xfrm_state *x, *x0;
+- unsigned h = __xfrm4_dst_hash(daddr);
+-
+- x0 = NULL;
+-
+- list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) {
+- if (x->props.family == AF_INET &&
+- daddr->a4 == x->id.daddr.a4 &&
+- mode == x->props.mode &&
+- proto == x->id.proto &&
+- saddr->a4 == x->props.saddr.a4 &&
+- reqid == x->props.reqid &&
+- x->km.state == XFRM_STATE_ACQ &&
+- !x->id.spi) {
+- x0 = x;
+- break;
+- }
+- }
+- if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
+- x0->sel.daddr.a4 = daddr->a4;
+- x0->sel.saddr.a4 = saddr->a4;
+- x0->sel.prefixlen_d = 32;
+- x0->sel.prefixlen_s = 32;
+- x0->props.saddr.a4 = saddr->a4;
+- x0->km.state = XFRM_STATE_ACQ;
+- x0->id.daddr.a4 = daddr->a4;
+- x0->id.proto = proto;
+- x0->props.family = AF_INET;
+- x0->props.mode = mode;
+- x0->props.reqid = reqid;
+- x0->props.family = AF_INET;
+- x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
+- xfrm_state_hold(x0);
+- x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
+- add_timer(&x0->timer);
+- xfrm_state_hold(x0);
+- list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h);
+- wake_up(&km_waitq);
+- }
+- if (x0)
+- xfrm_state_hold(x0);
+- return x0;
+-}
+-
+ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
+ .family = AF_INET,
+ .init_flags = xfrm4_init_flags,
+ .init_tempsel = __xfrm4_init_tempsel,
+- .state_lookup = __xfrm4_state_lookup,
+- .find_acq = __xfrm4_find_acq,
+ };
+
+ void __init xfrm4_state_init(void)
+diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
+index f8ceaa1..f110af5 100644
+--- a/net/ipv4/xfrm4_tunnel.c
++++ b/net/ipv4/xfrm4_tunnel.c
+@@ -28,7 +28,7 @@ static int ipip_xfrm_rcv(struct xfrm_sta
+
+ static int ipip_init_state(struct xfrm_state *x)
+ {
+- if (!x->props.mode)
++ if (x->props.mode != XFRM_MODE_TUNNEL)
+ return -EINVAL;
+
+ if (x->encap)
+diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
+index e923d4d..6e48f52 100644
+--- a/net/ipv6/Kconfig
++++ b/net/ipv6/Kconfig
+@@ -77,6 +77,7 @@ config INET6_ESP
+ select CRYPTO
+ select CRYPTO_HMAC
+ select CRYPTO_MD5
++ select CRYPTO_CBC
+ select CRYPTO_SHA1
+ select CRYPTO_DES
+ ---help---
+@@ -97,6 +98,15 @@ config INET6_IPCOMP
+
+ If unsure, say Y.
+
++config IPV6_MIP6
++ bool "IPv6: Mobility (EXPERIMENTAL)"
++ depends on IPV6 && EXPERIMENTAL
++ select XFRM
++ ---help---
++ Support for IPv6 Mobility described in RFC 3775.
++
++ If unsure, say N.
++
+ config INET6_XFRM_TUNNEL
+ tristate
+ select INET6_TUNNEL
+@@ -126,6 +136,36 @@ config INET6_XFRM_MODE_TUNNEL
+
+ If unsure, say Y.
+
++config INET6_XFRM_MODE_BEET
++ tristate "IPv6: IPsec BEET mode"
++ depends on IPV6
++ default IPV6
++ select XFRM
++ ---help---
++ Support for IPsec BEET mode.
++
++ If unsure, say Y.
++
++config INET6_XFRM_MODE_ROUTEOPTIMIZATION
++ tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)"
++ depends on IPV6 && EXPERIMENTAL
++ select XFRM
++ ---help---
++ Support for MIPv6 route optimization mode.
++
++config IPV6_SIT
++ tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)"
++ depends on IPV6
++ default y
++ ---help---
++ Tunneling means encapsulating data of one protocol type within
++ another protocol and sending it over a channel that understands the
++ encapsulating protocol. This driver implements encapsulation of IPv6
++ into IPv4 packets. This is useful if you want to connect two IPv6
++ networks over an IPv4-only path.
++
++ Saying M here will produce a module called sit.ko. If unsure, say Y.
++
+ config IPV6_TUNNEL
+ tristate "IPv6: IPv6-in-IPv6 tunnel"
+ select INET6_TUNNEL
+@@ -135,3 +175,31 @@ config IPV6_TUNNEL
+
+ If unsure, say N.
+
++config IPV6_MULTIPLE_TABLES
++ bool "IPv6: Multiple Routing Tables"
++ depends on IPV6 && EXPERIMENTAL
++ select FIB_RULES
++ ---help---
++ Support multiple routing tables.
++
++config IPV6_SUBTREES
++ bool "IPv6: source address based routing"
++ depends on IPV6_MULTIPLE_TABLES
++ ---help---
++ Enable routing by source address or prefix.
++
++ The destination address is still the primary routing key, so mixing
++ normal and source prefix specific routes in the same routing table
++ may sometimes lead to unintended routing behavior. This can be
++ avoided by defining different routing tables for the normal and
++ source prefix specific routes.
++
++ If unsure, say N.
++
++config IPV6_ROUTE_FWMARK
++ bool "IPv6: use netfilter MARK value as routing key"
++ depends on IPV6_MULTIPLE_TABLES && NETFILTER
++ ---help---
++ If you say Y here, you will be able to specify different routes for
++ packets with different mark values (see iptables(8), MARK target).
++
+diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
+index 386e0a6..addcc01 100644
+--- a/net/ipv6/Makefile
++++ b/net/ipv6/Makefile
+@@ -4,7 +4,7 @@
+
+ obj-$(CONFIG_IPV6) += ipv6.o
+
+-ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
++ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
+ route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
+ protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
+ exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
+@@ -13,6 +13,9 @@ ipv6-objs := af_inet6.o anycast.o ip6_ou
+ ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
+ xfrm6_output.o
+ ipv6-$(CONFIG_NETFILTER) += netfilter.o
++ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
++ipv6-$(CONFIG_IPV6_MIP6) += mip6.o
++
+ ipv6-objs += $(ipv6-y)
+
+ obj-$(CONFIG_INET6_AH) += ah6.o
+@@ -22,8 +25,11 @@ obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6
+ obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
+ obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
+ obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
++obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o
++obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
+ obj-$(CONFIG_NETFILTER) += netfilter/
+
++obj-$(CONFIG_IPV6_SIT) += sit.o
+ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
+
+ obj-y += exthdrs_core.o
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index c7852b3..b312a5f 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -48,6 +48,7 @@
+ #include <linux/net.h>
+ #include <linux/in6.h>
+ #include <linux/netdevice.h>
++#include <linux/if_addr.h>
+ #include <linux/if_arp.h>
+ #include <linux/if_arcnet.h>
+ #include <linux/if_infiniband.h>
+@@ -72,6 +73,7 @@
+ #include <net/addrconf.h>
+ #include <net/tcp.h>
+ #include <net/ip.h>
++#include <net/netlink.h>
+ #include <linux/if_tunnel.h>
+ #include <linux/rtnetlink.h>
+
+@@ -117,9 +119,6 @@ static int ipv6_count_addresses(struct i
+ static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE];
+ static DEFINE_RWLOCK(addrconf_hash_lock);
+
+-/* Protects inet6 devices */
+-DEFINE_RWLOCK(addrconf_lock);
+-
+ static void addrconf_verify(unsigned long);
+
+ static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0);
+@@ -144,7 +143,7 @@ static int ipv6_chk_same_addr(const stru
+
+ static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
+
+-struct ipv6_devconf ipv6_devconf = {
++struct ipv6_devconf ipv6_devconf __read_mostly = {
+ .forwarding = 0,
+ .hop_limit = IPV6_DEFAULT_HOPLIMIT,
+ .mtu6 = IPV6_MIN_MTU,
+@@ -173,9 +172,10 @@ struct ipv6_devconf ipv6_devconf = {
+ .accept_ra_rt_info_max_plen = 0,
+ #endif
+ #endif
++ .proxy_ndp = 0,
+ };
+
+-static struct ipv6_devconf ipv6_devconf_dflt = {
++static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
+ .forwarding = 0,
+ .hop_limit = IPV6_DEFAULT_HOPLIMIT,
+ .mtu6 = IPV6_MIN_MTU,
+@@ -203,6 +203,7 @@ static struct ipv6_devconf ipv6_devconf_
+ .accept_ra_rt_info_max_plen = 0,
+ #endif
+ #endif
++ .proxy_ndp = 0,
+ };
+
+ /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
+@@ -314,6 +315,12 @@ static void addrconf_mod_timer(struct in
+
+ /* Nobody refers to this device, we may destroy it. */
+
++static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
++{
++ struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
++ kfree(idev);
++}
++
+ void in6_dev_finish_destroy(struct inet6_dev *idev)
+ {
+ struct net_device *dev = idev->dev;
+@@ -328,7 +335,7 @@ void in6_dev_finish_destroy(struct inet6
+ return;
+ }
+ snmp6_free_dev(idev);
+- kfree(idev);
++ call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
+ }
+
+ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
+@@ -389,8 +396,10 @@ static struct inet6_dev * ipv6_add_dev(s
+ ndev->regen_timer.data = (unsigned long) ndev;
+ if ((dev->flags&IFF_LOOPBACK) ||
+ dev->type == ARPHRD_TUNNEL ||
+- dev->type == ARPHRD_NONE ||
+- dev->type == ARPHRD_SIT) {
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
++ dev->type == ARPHRD_SIT ||
++#endif
++ dev->type == ARPHRD_NONE) {
+ printk(KERN_INFO
+ "%s: Disabled Privacy Extensions\n",
+ dev->name);
+@@ -404,9 +413,8 @@ static struct inet6_dev * ipv6_add_dev(s
+ if (netif_carrier_ok(dev))
+ ndev->if_flags |= IF_READY;
+
+- write_lock_bh(&addrconf_lock);
+- dev->ip6_ptr = ndev;
+- write_unlock_bh(&addrconf_lock);
++ /* protected by rtnl_lock */
++ rcu_assign_pointer(dev->ip6_ptr, ndev);
+
+ ipv6_mc_init_dev(ndev);
+ ndev->tstamp = jiffies;
+@@ -470,7 +478,7 @@ static void addrconf_forward_change(void
+
+ read_lock(&dev_base_lock);
+ for (dev=dev_base; dev; dev=dev->next) {
+- read_lock(&addrconf_lock);
++ rcu_read_lock();
+ idev = __in6_dev_get(dev);
+ if (idev) {
+ int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding);
+@@ -478,7 +486,7 @@ static void addrconf_forward_change(void
+ if (changed)
+ dev_forward_change(idev);
+ }
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ }
+ read_unlock(&dev_base_lock);
+ }
+@@ -539,7 +547,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
+ int hash;
+ int err = 0;
+
+- read_lock_bh(&addrconf_lock);
++ rcu_read_lock_bh();
+ if (idev->dead) {
+ err = -ENODEV; /*XXX*/
+ goto out2;
+@@ -608,7 +616,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
+ in6_ifa_hold(ifa);
+ write_unlock(&idev->lock);
+ out2:
+- read_unlock_bh(&addrconf_lock);
++ rcu_read_unlock_bh();
+
+ if (likely(err == 0))
+ atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
+@@ -734,7 +742,7 @@ static void ipv6_del_addr(struct inet6_i
+
+ if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (onlink == 0) {
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ rt = NULL;
+ } else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
+ rt->rt6i_expires = expires;
+@@ -911,7 +919,7 @@ int ipv6_dev_get_saddr(struct net_device
+ memset(&hiscore, 0, sizeof(hiscore));
+
+ read_lock(&dev_base_lock);
+- read_lock(&addrconf_lock);
++ rcu_read_lock();
+
+ for (dev = dev_base; dev; dev=dev->next) {
+ struct inet6_dev *idev;
+@@ -1032,9 +1040,27 @@ int ipv6_dev_get_saddr(struct net_device
+ continue;
+ }
+
+- /* Rule 4: Prefer home address -- not implemented yet */
++ /* Rule 4: Prefer home address */
++#ifdef CONFIG_IPV6_MIP6
++ if (hiscore.rule < 4) {
++ if (ifa_result->flags & IFA_F_HOMEADDRESS)
++ hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
++ hiscore.rule++;
++ }
++ if (ifa->flags & IFA_F_HOMEADDRESS) {
++ score.attrs |= IPV6_SADDR_SCORE_HOA;
++ if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {
++ score.rule = 4;
++ goto record_it;
++ }
++ } else {
++ if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)
++ continue;
++ }
++#else
+ if (hiscore.rule < 4)
+ hiscore.rule++;
++#endif
+
+ /* Rule 5: Prefer outgoing interface */
+ if (hiscore.rule < 5) {
+@@ -1123,7 +1149,7 @@ record_it:
+ }
+ read_unlock_bh(&idev->lock);
+ }
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ read_unlock(&dev_base_lock);
+
+ if (!ifa_result)
+@@ -1147,7 +1173,7 @@ int ipv6_get_lladdr(struct net_device *d
+ struct inet6_dev *idev;
+ int err = -EADDRNOTAVAIL;
+
+- read_lock(&addrconf_lock);
++ rcu_read_lock();
+ if ((idev = __in6_dev_get(dev)) != NULL) {
+ struct inet6_ifaddr *ifp;
+
+@@ -1161,7 +1187,7 @@ int ipv6_get_lladdr(struct net_device *d
+ }
+ read_unlock_bh(&idev->lock);
+ }
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ return err;
+ }
+
+@@ -1234,8 +1260,8 @@ int ipv6_rcv_saddr_equal(const struct so
+ {
+ const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
+ const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
+- u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
+- u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
++ __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
++ __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+ int sk_ipv6only = ipv6_only_sock(sk);
+ int sk2_ipv6only = inet_v6_ipv6only(sk2);
+ int addr_type = ipv6_addr_type(sk_rcv_saddr6);
+@@ -1462,7 +1488,7 @@ static void ipv6_regen_rndid(unsigned lo
+ struct inet6_dev *idev = (struct inet6_dev *) data;
+ unsigned long expires;
+
+- read_lock_bh(&addrconf_lock);
++ rcu_read_lock_bh();
+ write_lock_bh(&idev->lock);
+
+ if (idev->dead)
+@@ -1486,7 +1512,7 @@ static void ipv6_regen_rndid(unsigned lo
+
+ out:
+ write_unlock_bh(&idev->lock);
+- read_unlock_bh(&addrconf_lock);
++ rcu_read_unlock_bh();
+ in6_dev_put(idev);
+ }
+
+@@ -1507,60 +1533,61 @@ static void
+ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
+ unsigned long expires, u32 flags)
+ {
+- struct in6_rtmsg rtmsg;
++ struct fib6_config cfg = {
++ .fc_table = RT6_TABLE_PREFIX,
++ .fc_metric = IP6_RT_PRIO_ADDRCONF,
++ .fc_ifindex = dev->ifindex,
++ .fc_expires = expires,
++ .fc_dst_len = plen,
++ .fc_flags = RTF_UP | flags,
++ };
+
+- memset(&rtmsg, 0, sizeof(rtmsg));
+- ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx);
+- rtmsg.rtmsg_dst_len = plen;
+- rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+- rtmsg.rtmsg_ifindex = dev->ifindex;
+- rtmsg.rtmsg_info = expires;
+- rtmsg.rtmsg_flags = RTF_UP|flags;
+- rtmsg.rtmsg_type = RTMSG_NEWROUTE;
++ ipv6_addr_copy(&cfg.fc_dst, pfx);
+
+ /* Prevent useless cloning on PtP SIT.
+ This thing is done here expecting that the whole
+ class of non-broadcast devices need not cloning.
+ */
+- if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
+- rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
++ if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT))
++ cfg.fc_flags |= RTF_NONEXTHOP;
++#endif
+
+- ip6_route_add(&rtmsg, NULL, NULL, NULL);
++ ip6_route_add(&cfg);
+ }
+
+ /* Create "default" multicast route to the interface */
+
+ static void addrconf_add_mroute(struct net_device *dev)
+ {
+- struct in6_rtmsg rtmsg;
++ struct fib6_config cfg = {
++ .fc_table = RT6_TABLE_LOCAL,
++ .fc_metric = IP6_RT_PRIO_ADDRCONF,
++ .fc_ifindex = dev->ifindex,
++ .fc_dst_len = 8,
++ .fc_flags = RTF_UP,
++ };
++
++ ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
+
+- memset(&rtmsg, 0, sizeof(rtmsg));
+- ipv6_addr_set(&rtmsg.rtmsg_dst,
+- htonl(0xFF000000), 0, 0, 0);
+- rtmsg.rtmsg_dst_len = 8;
+- rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+- rtmsg.rtmsg_ifindex = dev->ifindex;
+- rtmsg.rtmsg_flags = RTF_UP;
+- rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+- ip6_route_add(&rtmsg, NULL, NULL, NULL);
++ ip6_route_add(&cfg);
+ }
+
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ static void sit_route_add(struct net_device *dev)
+ {
+- struct in6_rtmsg rtmsg;
+-
+- memset(&rtmsg, 0, sizeof(rtmsg));
+-
+- rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+- rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
++ struct fib6_config cfg = {
++ .fc_table = RT6_TABLE_MAIN,
++ .fc_metric = IP6_RT_PRIO_ADDRCONF,
++ .fc_ifindex = dev->ifindex,
++ .fc_dst_len = 96,
++ .fc_flags = RTF_UP | RTF_NONEXTHOP,
++ };
+
+ /* prefix length - 96 bits "::d.d.d.d" */
+- rtmsg.rtmsg_dst_len = 96;
+- rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP;
+- rtmsg.rtmsg_ifindex = dev->ifindex;
+-
+- ip6_route_add(&rtmsg, NULL, NULL, NULL);
++ ip6_route_add(&cfg);
+ }
++#endif
+
+ static void addrconf_add_lroute(struct net_device *dev)
+ {
+@@ -1660,7 +1687,7 @@ void addrconf_prefix_rcv(struct net_devi
+ if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (rt->rt6i_flags&RTF_EXPIRES) {
+ if (valid_lft == 0) {
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ rt = NULL;
+ } else {
+ rt->rt6i_expires = jiffies + rt_expires;
+@@ -1831,6 +1858,7 @@ int addrconf_set_dstaddr(void __user *ar
+ if (dev == NULL)
+ goto err_exit;
+
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ if (dev->type == ARPHRD_SIT) {
+ struct ifreq ifr;
+ mm_segment_t oldfs;
+@@ -1860,6 +1888,7 @@ int addrconf_set_dstaddr(void __user *ar
+ err = dev_open(dev);
+ }
+ }
++#endif
+
+ err_exit:
+ rtnl_unlock();
+@@ -1870,12 +1899,11 @@ err_exit:
+ * Manual configuration of address on an interface
+ */
+ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
+- __u32 prefered_lft, __u32 valid_lft)
++ __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft)
+ {
+ struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev;
+ struct net_device *dev;
+- __u8 ifa_flags = 0;
+ int scope;
+
+ ASSERT_RTNL();
+@@ -1887,9 +1915,6 @@ static int inet6_addr_add(int ifindex, s
+ if ((dev = __dev_get_by_index(ifindex)) == NULL)
+ return -ENODEV;
+
+- if (!(dev->flags&IFF_UP))
+- return -ENETDOWN;
+-
+ if ((idev = addrconf_add_dev(dev)) == NULL)
+ return -ENOBUFS;
+
+@@ -1971,7 +1996,7 @@ int addrconf_add_ifaddr(void __user *arg
+
+ rtnl_lock();
+ err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
+- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
++ IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+ rtnl_unlock();
+ return err;
+ }
+@@ -1993,6 +2018,7 @@ int addrconf_del_ifaddr(void __user *arg
+ return err;
+ }
+
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ static void sit_add_v4_addrs(struct inet6_dev *idev)
+ {
+ struct inet6_ifaddr * ifp;
+@@ -2061,6 +2087,7 @@ static void sit_add_v4_addrs(struct inet
+ }
+ }
+ }
++#endif
+
+ static void init_loopback(struct net_device *dev)
+ {
+@@ -2124,6 +2151,7 @@ static void addrconf_dev_config(struct n
+ addrconf_add_linklocal(idev, &addr);
+ }
+
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ static void addrconf_sit_config(struct net_device *dev)
+ {
+ struct inet6_dev *idev;
+@@ -2149,6 +2177,7 @@ static void addrconf_sit_config(struct n
+ } else
+ sit_route_add(dev);
+ }
++#endif
+
+ static inline int
+ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
+@@ -2243,9 +2272,11 @@ static int addrconf_notify(struct notifi
+ }
+
+ switch(dev->type) {
++#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ case ARPHRD_SIT:
+ addrconf_sit_config(dev);
+ break;
++#endif
+ case ARPHRD_TUNNEL6:
+ addrconf_ip6_tnl_config(dev);
+ break;
+@@ -2344,10 +2375,10 @@ static int addrconf_ifdown(struct net_de
+ Do not dev_put!
+ */
+ if (how == 1) {
+- write_lock_bh(&addrconf_lock);
+- dev->ip6_ptr = NULL;
+ idev->dead = 1;
+- write_unlock_bh(&addrconf_lock);
++
++ /* protected by rtnl_lock */
++ rcu_assign_pointer(dev->ip6_ptr, NULL);
+
+ /* Step 1.5: remove snmp6 entry */
+ snmp6_unregister_dev(idev);
+@@ -2514,7 +2545,8 @@ static void addrconf_dad_start(struct in
+ spin_lock_bh(&ifp->lock);
+
+ if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
+- !(ifp->flags&IFA_F_TENTATIVE)) {
++ !(ifp->flags&IFA_F_TENTATIVE) ||
++ ifp->flags & IFA_F_NODAD) {
+ ifp->flags &= ~IFA_F_TENTATIVE;
+ spin_unlock_bh(&ifp->lock);
+ read_unlock_bh(&idev->lock);
+@@ -2759,6 +2791,26 @@ void if6_proc_exit(void)
+ }
+ #endif /* CONFIG_PROC_FS */
+
++#ifdef CONFIG_IPV6_MIP6
++/* Check if address is a home address configured on any interface. */
++int ipv6_chk_home_addr(struct in6_addr *addr)
++{
++ int ret = 0;
++ struct inet6_ifaddr * ifp;
++ u8 hash = ipv6_addr_hash(addr);
++ read_lock_bh(&addrconf_hash_lock);
++ for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
++ if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&
++ (ifp->flags & IFA_F_HOMEADDRESS)) {
++ ret = 1;
++ break;
++ }
++ }
++ read_unlock_bh(&addrconf_hash_lock);
++ return ret;
++}
++#endif
++
+ /*
+ * Periodic address status verification
+ */
+@@ -2869,66 +2921,68 @@ restart:
+ spin_unlock_bh(&addrconf_verify_lock);
+ }
+
++static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local)
++{
++ struct in6_addr *pfx = NULL;
++
++ if (addr)
++ pfx = nla_data(addr);
++
++ if (local) {
++ if (pfx && nla_memcmp(local, pfx, sizeof(*pfx)))
++ pfx = NULL;
++ else
++ pfx = nla_data(local);
++ }
++
++ return pfx;
++}
++
++static struct nla_policy ifa_ipv6_policy[IFA_MAX+1] __read_mostly = {
++ [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) },
++ [IFA_LOCAL] = { .len = sizeof(struct in6_addr) },
++ [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
++};
++
+ static int
+ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+- struct rtattr **rta = arg;
+- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
++ struct ifaddrmsg *ifm;
++ struct nlattr *tb[IFA_MAX+1];
+ struct in6_addr *pfx;
++ int err;
+
+- pfx = NULL;
+- if (rta[IFA_ADDRESS-1]) {
+- if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx))
+- return -EINVAL;
+- pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
+- }
+- if (rta[IFA_LOCAL-1]) {
+- if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+- (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
+- return -EINVAL;
+- pfx = RTA_DATA(rta[IFA_LOCAL-1]);
+- }
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
++ if (err < 0)
++ return err;
++
++ ifm = nlmsg_data(nlh);
++ pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]);
+ if (pfx == NULL)
+ return -EINVAL;
+
+ return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+ }
+
+-static int
+-inet6_addr_modify(int ifindex, struct in6_addr *pfx,
+- __u32 prefered_lft, __u32 valid_lft)
++static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
++ u32 prefered_lft, u32 valid_lft)
+ {
+- struct inet6_ifaddr *ifp = NULL;
+- struct net_device *dev;
+- int ifa_flags = 0;
+-
+- if ((dev = __dev_get_by_index(ifindex)) == NULL)
+- return -ENODEV;
+-
+- if (!(dev->flags&IFF_UP))
+- return -ENETDOWN;
+-
+ if (!valid_lft || (prefered_lft > valid_lft))
+ return -EINVAL;
+
+- ifp = ipv6_get_ifaddr(pfx, dev, 1);
+- if (ifp == NULL)
+- return -ENOENT;
+-
+ if (valid_lft == INFINITY_LIFE_TIME)
+- ifa_flags = IFA_F_PERMANENT;
++ ifa_flags |= IFA_F_PERMANENT;
+ else if (valid_lft >= 0x7FFFFFFF/HZ)
+ valid_lft = 0x7FFFFFFF/HZ;
+
+ if (prefered_lft == 0)
+- ifa_flags = IFA_F_DEPRECATED;
++ ifa_flags |= IFA_F_DEPRECATED;
+ else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+ (prefered_lft != INFINITY_LIFE_TIME))
+ prefered_lft = 0x7FFFFFFF/HZ;
+
+ spin_lock_bh(&ifp->lock);
+- ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags;
+-
++ ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags;
+ ifp->tstamp = jiffies;
+ ifp->valid_lft = valid_lft;
+ ifp->prefered_lft = prefered_lft;
+@@ -2936,7 +2990,6 @@ inet6_addr_modify(int ifindex, struct in
+ spin_unlock_bh(&ifp->lock);
+ if (!(ifp->flags&IFA_F_TENTATIVE))
+ ipv6_ifa_notify(0, ifp);
+- in6_ifa_put(ifp);
+
+ addrconf_verify(0);
+
+@@ -2946,172 +2999,189 @@ inet6_addr_modify(int ifindex, struct in
+ static int
+ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+ {
+- struct rtattr **rta = arg;
+- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
++ struct ifaddrmsg *ifm;
++ struct nlattr *tb[IFA_MAX+1];
+ struct in6_addr *pfx;
+- __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME;
++ struct inet6_ifaddr *ifa;
++ struct net_device *dev;
++ u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
++ u8 ifa_flags;
++ int err;
+
+- pfx = NULL;
+- if (rta[IFA_ADDRESS-1]) {
+- if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx))
+- return -EINVAL;
+- pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
+- }
+- if (rta[IFA_LOCAL-1]) {
+- if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+- (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
+- return -EINVAL;
+- pfx = RTA_DATA(rta[IFA_LOCAL-1]);
+- }
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
++ if (err < 0)
++ return err;
++
++ ifm = nlmsg_data(nlh);
++ pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]);
+ if (pfx == NULL)
+ return -EINVAL;
+
+- if (rta[IFA_CACHEINFO-1]) {
++ if (tb[IFA_CACHEINFO]) {
+ struct ifa_cacheinfo *ci;
+- if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci))
+- return -EINVAL;
+- ci = RTA_DATA(rta[IFA_CACHEINFO-1]);
++
++ ci = nla_data(tb[IFA_CACHEINFO]);
+ valid_lft = ci->ifa_valid;
+- prefered_lft = ci->ifa_prefered;
++ preferred_lft = ci->ifa_prefered;
++ } else {
++ preferred_lft = INFINITY_LIFE_TIME;
++ valid_lft = INFINITY_LIFE_TIME;
+ }
+
+- if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+- int ret;
+- ret = inet6_addr_modify(ifm->ifa_index, pfx,
+- prefered_lft, valid_lft);
+- if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE))
+- return ret;
++ dev = __dev_get_by_index(ifm->ifa_index);
++ if (dev == NULL)
++ return -ENODEV;
++
++ /* We ignore other flags so far. */
++ ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
++
++ ifa = ipv6_get_ifaddr(pfx, dev, 1);
++ if (ifa == NULL) {
++ /*
++ * It would be best to check for !NLM_F_CREATE here but
++ * userspace alreay relies on not having to provide this.
++ */
++ return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
++ ifa_flags, preferred_lft, valid_lft);
+ }
+
+- return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
+- prefered_lft, valid_lft);
++ if (nlh->nlmsg_flags & NLM_F_EXCL ||
++ !(nlh->nlmsg_flags & NLM_F_REPLACE))
++ err = -EEXIST;
++ else
++ err = inet6_addr_modify(ifa, ifa_flags, preferred_lft, valid_lft);
++
++ in6_ifa_put(ifa);
+
++ return err;
++}
++
++static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags,
++ u8 scope, int ifindex)
++{
++ struct ifaddrmsg *ifm;
++
++ ifm = nlmsg_data(nlh);
++ ifm->ifa_family = AF_INET6;
++ ifm->ifa_prefixlen = prefixlen;
++ ifm->ifa_flags = flags;
++ ifm->ifa_scope = scope;
++ ifm->ifa_index = ifindex;
+ }
+
+-/* Maximum length of ifa_cacheinfo attributes */
+-#define INET6_IFADDR_RTA_SPACE \
+- RTA_SPACE(16) /* IFA_ADDRESS */ + \
+- RTA_SPACE(sizeof(struct ifa_cacheinfo)) /* CACHEINFO */
++static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
++ unsigned long tstamp, u32 preferred, u32 valid)
++{
++ struct ifa_cacheinfo ci;
++
++ ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100
++ + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
++ ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100
++ + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
++ ci.ifa_prefered = preferred;
++ ci.ifa_valid = valid;
++
++ return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
++}
++
++static inline int rt_scope(int ifa_scope)
++{
++ if (ifa_scope & IFA_HOST)
++ return RT_SCOPE_HOST;
++ else if (ifa_scope & IFA_LINK)
++ return RT_SCOPE_LINK;
++ else if (ifa_scope & IFA_SITE)
++ return RT_SCOPE_SITE;
++ else
++ return RT_SCOPE_UNIVERSE;
++}
++
++static inline int inet6_ifaddr_msgsize(void)
++{
++ return nlmsg_total_size(sizeof(struct ifaddrmsg) +
++ nla_total_size(16) +
++ nla_total_size(sizeof(struct ifa_cacheinfo)) +
++ 128);
++}
+
+ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
+ u32 pid, u32 seq, int event, unsigned int flags)
+ {
+- struct ifaddrmsg *ifm;
+ struct nlmsghdr *nlh;
+- struct ifa_cacheinfo ci;
+- unsigned char *b = skb->tail;
++ u32 preferred, valid;
++
++ nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope),
++ ifa->idev->dev->ifindex);
+
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
+- ifm = NLMSG_DATA(nlh);
+- ifm->ifa_family = AF_INET6;
+- ifm->ifa_prefixlen = ifa->prefix_len;
+- ifm->ifa_flags = ifa->flags;
+- ifm->ifa_scope = RT_SCOPE_UNIVERSE;
+- if (ifa->scope&IFA_HOST)
+- ifm->ifa_scope = RT_SCOPE_HOST;
+- else if (ifa->scope&IFA_LINK)
+- ifm->ifa_scope = RT_SCOPE_LINK;
+- else if (ifa->scope&IFA_SITE)
+- ifm->ifa_scope = RT_SCOPE_SITE;
+- ifm->ifa_index = ifa->idev->dev->ifindex;
+- RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr);
+ if (!(ifa->flags&IFA_F_PERMANENT)) {
+- ci.ifa_prefered = ifa->prefered_lft;
+- ci.ifa_valid = ifa->valid_lft;
+- if (ci.ifa_prefered != INFINITY_LIFE_TIME) {
++ preferred = ifa->prefered_lft;
++ valid = ifa->valid_lft;
++ if (preferred != INFINITY_LIFE_TIME) {
+ long tval = (jiffies - ifa->tstamp)/HZ;
+- ci.ifa_prefered -= tval;
+- if (ci.ifa_valid != INFINITY_LIFE_TIME)
+- ci.ifa_valid -= tval;
++ preferred -= tval;
++ if (valid != INFINITY_LIFE_TIME)
++ valid -= tval;
+ }
+ } else {
+- ci.ifa_prefered = INFINITY_LIFE_TIME;
+- ci.ifa_valid = INFINITY_LIFE_TIME;
+- }
+- ci.cstamp = (__u32)(TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) / HZ * 100
+- + TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
+- ci.tstamp = (__u32)(TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) / HZ * 100
+- + TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
+- RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ preferred = INFINITY_LIFE_TIME;
++ valid = INFINITY_LIFE_TIME;
++ }
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 ||
++ put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
++ return nlmsg_cancel(skb, nlh);
++
++ return nlmsg_end(skb, nlh);
+ }
+
+ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
+ u32 pid, u32 seq, int event, u16 flags)
+ {
+- struct ifaddrmsg *ifm;
+ struct nlmsghdr *nlh;
+- struct ifa_cacheinfo ci;
+- unsigned char *b = skb->tail;
+-
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
+- ifm = NLMSG_DATA(nlh);
+- ifm->ifa_family = AF_INET6;
+- ifm->ifa_prefixlen = 128;
+- ifm->ifa_flags = IFA_F_PERMANENT;
+- ifm->ifa_scope = RT_SCOPE_UNIVERSE;
+- if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE)
+- ifm->ifa_scope = RT_SCOPE_SITE;
+- ifm->ifa_index = ifmca->idev->dev->ifindex;
+- RTA_PUT(skb, IFA_MULTICAST, 16, &ifmca->mca_addr);
+- ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ
+- * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ
+- * 100 / HZ);
+- ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ
+- * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ
+- * 100 / HZ);
+- ci.ifa_prefered = INFINITY_LIFE_TIME;
+- ci.ifa_valid = INFINITY_LIFE_TIME;
+- RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ u8 scope = RT_SCOPE_UNIVERSE;
++ int ifindex = ifmca->idev->dev->ifindex;
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE)
++ scope = RT_SCOPE_SITE;
++
++ nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
++ if (nla_put(skb, IFA_MULTICAST, 16, &ifmca->mca_addr) < 0 ||
++ put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp,
++ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
++ return nlmsg_cancel(skb, nlh);
++
++ return nlmsg_end(skb, nlh);
+ }
+
+ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
+ u32 pid, u32 seq, int event, unsigned int flags)
+ {
+- struct ifaddrmsg *ifm;
+ struct nlmsghdr *nlh;
+- struct ifa_cacheinfo ci;
+- unsigned char *b = skb->tail;
+-
+- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
+- ifm = NLMSG_DATA(nlh);
+- ifm->ifa_family = AF_INET6;
+- ifm->ifa_prefixlen = 128;
+- ifm->ifa_flags = IFA_F_PERMANENT;
+- ifm->ifa_scope = RT_SCOPE_UNIVERSE;
+- if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE)
+- ifm->ifa_scope = RT_SCOPE_SITE;
+- ifm->ifa_index = ifaca->aca_idev->dev->ifindex;
+- RTA_PUT(skb, IFA_ANYCAST, 16, &ifaca->aca_addr);
+- ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ
+- * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ
+- * 100 / HZ);
+- ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ
+- * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ
+- * 100 / HZ);
+- ci.ifa_prefered = INFINITY_LIFE_TIME;
+- ci.ifa_valid = INFINITY_LIFE_TIME;
+- RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ u8 scope = RT_SCOPE_UNIVERSE;
++ int ifindex = ifaca->aca_idev->dev->ifindex;
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE)
++ scope = RT_SCOPE_SITE;
++
++ nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
++ if (nla_put(skb, IFA_ANYCAST, 16, &ifaca->aca_addr) < 0 ||
++ put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp,
++ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
++ return nlmsg_cancel(skb, nlh);
++
++ return nlmsg_end(skb, nlh);
+ }
+
+ enum addr_type_t
+@@ -3222,79 +3292,74 @@ static int inet6_dump_ifacaddr(struct sk
+ return inet6_dump_addr(skb, cb, type);
+ }
+
+-static int inet6_rtm_getaddr(struct sk_buff *in_skb,
+- struct nlmsghdr* nlh, void *arg)
++static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
++ void *arg)
+ {
+- struct rtattr **rta = arg;
+- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
++ struct ifaddrmsg *ifm;
++ struct nlattr *tb[IFA_MAX+1];
+ struct in6_addr *addr = NULL;
+ struct net_device *dev = NULL;
+ struct inet6_ifaddr *ifa;
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
+ int err;
+
+- if (rta[IFA_ADDRESS-1]) {
+- if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr))
+- return -EINVAL;
+- addr = RTA_DATA(rta[IFA_ADDRESS-1]);
+- }
+- if (rta[IFA_LOCAL-1]) {
+- if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) ||
+- (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr))))
+- return -EINVAL;
+- addr = RTA_DATA(rta[IFA_LOCAL-1]);
++ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
++ if (err < 0)
++ goto errout;
++
++ addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]);
++ if (addr == NULL) {
++ err = -EINVAL;
++ goto errout;
+ }
+- if (addr == NULL)
+- return -EINVAL;
+
++ ifm = nlmsg_data(nlh);
+ if (ifm->ifa_index)
+ dev = __dev_get_by_index(ifm->ifa_index);
+
+- if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL)
+- return -EADDRNOTAVAIL;
++ if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) {
++ err = -EADDRNOTAVAIL;
++ goto errout;
++ }
+
+- if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) {
++ if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) {
+ err = -ENOBUFS;
+- goto out;
++ goto errout_ifa;
+ }
+
+- NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+ err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
+ nlh->nlmsg_seq, RTM_NEWADDR, 0);
+ if (err < 0) {
+- err = -EMSGSIZE;
+- goto out_free;
++ kfree_skb(skb);
++ goto errout_ifa;
+ }
+
+- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+- if (err > 0)
+- err = 0;
+-out:
++ err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
++errout_ifa:
+ in6_ifa_put(ifa);
++errout:
+ return err;
+-out_free:
+- kfree_skb(skb);
+- goto out;
+ }
+
+ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
+ {
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
++ int err = -ENOBUFS;
+
+- skb = alloc_skb(size, GFP_ATOMIC);
+- if (!skb) {
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, ENOBUFS);
+- return;
+- }
+- if (inet6_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) {
++ skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC);
++ if (skb == NULL)
++ goto errout;
++
++ err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, EINVAL);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFADDR;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFADDR, GFP_ATOMIC);
++
++ err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
+ }
+
+ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
+@@ -3329,6 +3394,7 @@ static void inline ipv6_store_devconf(st
+ array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
+ #endif
+ #endif
++ array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
+ }
+
+ /* Maximum length of ifinfomsg attributes */
+@@ -3435,20 +3501,23 @@ static int inet6_dump_ifinfo(struct sk_b
+ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
+ {
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE);
++ int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE;
++ int err = -ENOBUFS;
+
+- skb = alloc_skb(size, GFP_ATOMIC);
+- if (!skb) {
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, ENOBUFS);
+- return;
+- }
+- if (inet6_fill_ifinfo(skb, idev, current->pid, 0, event, 0) < 0) {
++ skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC);
++ if (skb == NULL)
++ goto errout;
++
++ err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, EINVAL);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFINFO;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC);
++
++ err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
+ }
+
+ /* Maximum length of prefix_cacheinfo attributes */
+@@ -3500,20 +3569,23 @@ static void inet6_prefix_notify(int even
+ struct prefix_info *pinfo)
+ {
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE);
++ int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE;
++ int err = -ENOBUFS;
+
+- skb = alloc_skb(size, GFP_ATOMIC);
+- if (!skb) {
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, ENOBUFS);
+- return;
+- }
+- if (inet6_fill_prefix(skb, idev, pinfo, current->pid, 0, event, 0) < 0) {
++ skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC);
++ if (skb == NULL)
++ goto errout;
++
++ err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, EINVAL);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_PREFIX;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_PREFIX, GFP_ATOMIC);
++
++ err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err);
+ }
+
+ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
+@@ -3528,6 +3600,9 @@ static struct rtnetlink_link inet6_rtnet
+ [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, },
+ [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute,
+ .dumpit = inet6_dump_fib, },
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++ [RTM_GETRULE - RTM_BASE] = { .dumpit = fib6_rules_dump, },
++#endif
+ };
+
+ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
+@@ -3536,7 +3611,7 @@ static void __ipv6_ifa_notify(int event,
+
+ switch (event) {
+ case RTM_NEWADDR:
+- ip6_ins_rt(ifp->rt, NULL, NULL, NULL);
++ ip6_ins_rt(ifp->rt);
+ if (ifp->idev->cnf.forwarding)
+ addrconf_join_anycast(ifp);
+ break;
+@@ -3545,7 +3620,7 @@ static void __ipv6_ifa_notify(int event,
+ addrconf_leave_anycast(ifp);
+ addrconf_leave_solict(ifp->idev, &ifp->addr);
+ dst_hold(&ifp->rt->u.dst);
+- if (ip6_del_rt(ifp->rt, NULL, NULL, NULL))
++ if (ip6_del_rt(ifp->rt))
+ dst_free(&ifp->rt->u.dst);
+ break;
+ }
+@@ -3553,10 +3628,10 @@ static void __ipv6_ifa_notify(int event,
+
+ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
+ {
+- read_lock_bh(&addrconf_lock);
++ rcu_read_lock_bh();
+ if (likely(ifp->idev->dead == 0))
+ __ipv6_ifa_notify(event, ifp);
+- read_unlock_bh(&addrconf_lock);
++ rcu_read_unlock_bh();
+ }
+
+ #ifdef CONFIG_SYSCTL
+@@ -3653,7 +3728,7 @@ static struct addrconf_sysctl_table
+ ctl_table addrconf_conf_dir[2];
+ ctl_table addrconf_proto_dir[2];
+ ctl_table addrconf_root_dir[2];
+-} addrconf_sysctl = {
++} addrconf_sysctl __read_mostly = {
+ .sysctl_header = NULL,
+ .addrconf_vars = {
+ {
+@@ -3843,6 +3918,14 @@ static struct addrconf_sysctl_table
+ #endif
+ #endif
+ {
++ .ctl_name = NET_IPV6_PROXY_NDP,
++ .procname = "proxy_ndp",
++ .data = &ipv6_devconf.proxy_ndp,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
+ .ctl_name = 0, /* sentinel */
+ }
+ },
+diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
+index ac85e9c..858cae2 100644
+--- a/net/ipv6/af_inet6.c
++++ b/net/ipv6/af_inet6.c
+@@ -59,6 +59,9 @@
+ #ifdef CONFIG_IPV6_TUNNEL
+ #include <net/ip6_tunnel.h>
+ #endif
++#ifdef CONFIG_IPV6_MIP6
++#include <net/mip6.h>
++#endif
+
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -67,7 +70,7 @@ MODULE_AUTHOR("Cast of dozens");
+ MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
+ MODULE_LICENSE("GPL");
+
+-int sysctl_ipv6_bindv6only;
++int sysctl_ipv6_bindv6only __read_mostly;
+
+ /* The inetsw table contains everything that inet_create needs to
+ * build a new socket.
+@@ -243,7 +246,7 @@ int inet6_bind(struct socket *sock, stru
+ struct sock *sk = sock->sk;
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+- __u32 v4addr = 0;
++ __be32 v4addr = 0;
+ unsigned short snum;
+ int addr_type = 0;
+ int err = 0;
+@@ -637,6 +640,7 @@ int inet6_sk_rebuild_header(struct sock
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet->dport;
+ fl.fl_ip_sport = inet->sport;
++ security_sk_classify_flow(sk, &fl);
+
+ if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+@@ -658,7 +662,7 @@ int inet6_sk_rebuild_header(struct sock
+ return err;
+ }
+
+- __ip6_dst_store(sk, dst, NULL);
++ __ip6_dst_store(sk, dst, NULL, NULL);
+ }
+
+ return 0;
+@@ -757,6 +761,8 @@ static int __init inet6_init(void)
+ struct list_head *r;
+ int err;
+
++ BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb));
++
+ #ifdef MODULE
+ #if 0 /* FIXME --RR */
+ if (!mod_member_present(&__this_module, can_unload))
+@@ -766,11 +772,6 @@ static int __init inet6_init(void)
+ #endif
+ #endif
+
+- if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)) {
+- printk(KERN_CRIT "inet6_proto_init: size fault\n");
+- return -EINVAL;
+- }
+-
+ err = proto_register(&tcpv6_prot, 1);
+ if (err)
+ goto out;
+@@ -849,13 +850,15 @@ static int __init inet6_init(void)
+ err = addrconf_init();
+ if (err)
+ goto addrconf_fail;
+- sit_init();
+
+ /* Init v6 extension headers. */
+ ipv6_rthdr_init();
+ ipv6_frag_init();
+ ipv6_nodata_init();
+ ipv6_destopt_init();
++#ifdef CONFIG_IPV6_MIP6
++ mip6_init();
++#endif
+
+ /* Init v6 transport protocols. */
+ udpv6_init();
+@@ -919,8 +922,10 @@ static void __exit inet6_exit(void)
+ tcp6_proc_exit();
+ raw6_proc_exit();
+ #endif
++#ifdef CONFIG_IPV6_MIP6
++ mip6_fini();
++#endif
+ /* Cleanup code parts. */
+- sit_cleanup();
+ ip6_flowlabel_cleanup();
+ addrconf_cleanup();
+ ip6_route_cleanup();
+diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
+index 9d4831b..b0d83e8 100644
+--- a/net/ipv6/ah6.c
++++ b/net/ipv6/ah6.c
+@@ -74,6 +74,66 @@ bad:
+ return 0;
+ }
+
++#ifdef CONFIG_IPV6_MIP6
++/**
++ * ipv6_rearrange_destopt - rearrange IPv6 destination options header
++ * @iph: IPv6 header
++ * @destopt: destionation options header
++ */
++static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt)
++{
++ u8 *opt = (u8 *)destopt;
++ int len = ipv6_optlen(destopt);
++ int off = 0;
++ int optlen = 0;
++
++ off += 2;
++ len -= 2;
++
++ while (len > 0) {
++
++ switch (opt[off]) {
++
++ case IPV6_TLV_PAD0:
++ optlen = 1;
++ break;
++ default:
++ if (len < 2)
++ goto bad;
++ optlen = opt[off+1]+2;
++ if (len < optlen)
++ goto bad;
++
++ /* Rearrange the source address in @iph and the
++ * addresses in home address option for final source.
++ * See 11.3.2 of RFC 3775 for details.
++ */
++ if (opt[off] == IPV6_TLV_HAO) {
++ struct in6_addr final_addr;
++ struct ipv6_destopt_hao *hao;
++
++ hao = (struct ipv6_destopt_hao *)&opt[off];
++ if (hao->length != sizeof(hao->addr)) {
++ if (net_ratelimit())
++ printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length);
++ goto bad;
++ }
++ ipv6_addr_copy(&final_addr, &hao->addr);
++ ipv6_addr_copy(&hao->addr, &iph->saddr);
++ ipv6_addr_copy(&iph->saddr, &final_addr);
++ }
++ break;
++ }
++
++ off += optlen;
++ len -= optlen;
++ }
++ /* Note: ok if len == 0 */
++bad:
++ return;
++}
++#endif
++
+ /**
+ * ipv6_rearrange_rthdr - rearrange IPv6 routing header
+ * @iph: IPv6 header
+@@ -113,7 +173,7 @@ static void ipv6_rearrange_rthdr(struct
+ ipv6_addr_copy(&iph->daddr, &final_addr);
+ }
+
+-static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
++static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
+ {
+ union {
+ struct ipv6hdr *iph;
+@@ -128,8 +188,12 @@ static int ipv6_clear_mutable_options(st
+
+ while (exthdr.raw < end) {
+ switch (nexthdr) {
+- case NEXTHDR_HOP:
+ case NEXTHDR_DEST:
++#ifdef CONFIG_IPV6_MIP6
++ if (dir == XFRM_POLICY_OUT)
++ ipv6_rearrange_destopt(iph, exthdr.opth);
++#endif
++ case NEXTHDR_HOP:
+ if (!zero_out_mutable_opts(exthdr.opth)) {
+ LIMIT_NETDEBUG(
+ KERN_WARNING "overrun %sopts\n",
+@@ -164,6 +228,9 @@ static int ah6_output(struct xfrm_state
+ u8 nexthdr;
+ char tmp_base[8];
+ struct {
++#ifdef CONFIG_IPV6_MIP6
++ struct in6_addr saddr;
++#endif
+ struct in6_addr daddr;
+ char hdrs[0];
+ } *tmp_ext;
+@@ -188,10 +255,15 @@ static int ah6_output(struct xfrm_state
+ err = -ENOMEM;
+ goto error;
+ }
++#ifdef CONFIG_IPV6_MIP6
++ memcpy(tmp_ext, &top_iph->saddr, extlen);
++#else
+ memcpy(tmp_ext, &top_iph->daddr, extlen);
++#endif
+ err = ipv6_clear_mutable_options(top_iph,
+ extlen - sizeof(*tmp_ext) +
+- sizeof(*top_iph));
++ sizeof(*top_iph),
++ XFRM_POLICY_OUT);
+ if (err)
+ goto error_free_iph;
+ }
+@@ -213,13 +285,20 @@ static int ah6_output(struct xfrm_state
+ ah->spi = x->id.spi;
+ ah->seq_no = htonl(++x->replay.oseq);
+ xfrm_aevent_doreplay(x);
+- ahp->icv(ahp, skb, ah->auth_data);
++ err = ah_mac_digest(ahp, skb, ah->auth_data);
++ if (err)
++ goto error_free_iph;
++ memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
+
+ err = 0;
+
+ memcpy(top_iph, tmp_base, sizeof(tmp_base));
+ if (tmp_ext) {
++#ifdef CONFIG_IPV6_MIP6
++ memcpy(&top_iph->saddr, tmp_ext, extlen);
++#else
+ memcpy(&top_iph->daddr, tmp_ext, extlen);
++#endif
+ error_free_iph:
+ kfree(tmp_ext);
+ }
+@@ -251,6 +330,7 @@ static int ah6_input(struct xfrm_state *
+ u16 hdr_len;
+ u16 ah_hlen;
+ int nexthdr;
++ int err = -EINVAL;
+
+ if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
+ goto out;
+@@ -278,7 +358,7 @@ static int ah6_input(struct xfrm_state *
+ if (!tmp_hdr)
+ goto out;
+ memcpy(tmp_hdr, skb->nh.raw, hdr_len);
+- if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len))
++ if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN))
+ goto free_out;
+ skb->nh.ipv6h->priority = 0;
+ skb->nh.ipv6h->flow_lbl[0] = 0;
+@@ -292,8 +372,11 @@ static int ah6_input(struct xfrm_state *
+ memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
+ memset(ah->auth_data, 0, ahp->icv_trunc_len);
+ skb_push(skb, hdr_len);
+- ahp->icv(ahp, skb, ah->auth_data);
+- if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
++ err = ah_mac_digest(ahp, skb, ah->auth_data);
++ if (err)
++ goto free_out;
++ err = -EINVAL;
++ if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
+ LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
+ x->stats.integrity_failed++;
+ goto free_out;
+@@ -310,7 +393,7 @@ static int ah6_input(struct xfrm_state *
+ free_out:
+ kfree(tmp_hdr);
+ out:
+- return -EINVAL;
++ return err;
+ }
+
+ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+@@ -338,6 +421,7 @@ static int ah6_init_state(struct xfrm_st
+ {
+ struct ah_data *ahp = NULL;
+ struct xfrm_algo_desc *aalg_desc;
++ struct crypto_hash *tfm;
+
+ if (!x->aalg)
+ goto error;
+@@ -355,24 +439,27 @@ static int ah6_init_state(struct xfrm_st
+
+ ahp->key = x->aalg->alg_key;
+ ahp->key_len = (x->aalg->alg_key_len+7)/8;
+- ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
+- if (!ahp->tfm)
++ tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm))
++ goto error;
++
++ ahp->tfm = tfm;
++ if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))
+ goto error;
+- ahp->icv = ah_hmac_digest;
+
+ /*
+ * Lookup the algorithm description maintained by xfrm_algo,
+ * verify crypto transform properties, and store information
+ * we need for AH processing. This lookup cannot fail here
+- * after a successful crypto_alloc_tfm().
++ * after a successful crypto_alloc_hash().
+ */
+ aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
+ BUG_ON(!aalg_desc);
+
+ if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+- crypto_tfm_alg_digestsize(ahp->tfm)) {
++ crypto_hash_digestsize(tfm)) {
+ printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
+- x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm),
++ x->aalg->alg_name, crypto_hash_digestsize(tfm),
+ aalg_desc->uinfo.auth.icv_fullbits/8);
+ goto error;
+ }
+@@ -387,7 +474,7 @@ static int ah6_init_state(struct xfrm_st
+ goto error;
+
+ x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len);
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ x->props.header_len += sizeof(struct ipv6hdr);
+ x->data = ahp;
+
+@@ -396,7 +483,7 @@ static int ah6_init_state(struct xfrm_st
+ error:
+ if (ahp) {
+ kfree(ahp->work_icv);
+- crypto_free_tfm(ahp->tfm);
++ crypto_free_hash(ahp->tfm);
+ kfree(ahp);
+ }
+ return -EINVAL;
+@@ -411,7 +498,7 @@ static void ah6_destroy(struct xfrm_stat
+
+ kfree(ahp->work_icv);
+ ahp->work_icv = NULL;
+- crypto_free_tfm(ahp->tfm);
++ crypto_free_hash(ahp->tfm);
+ ahp->tfm = NULL;
+ kfree(ahp);
+ }
+@@ -424,7 +511,8 @@ static struct xfrm_type ah6_type =
+ .init_state = ah6_init_state,
+ .destructor = ah6_destroy,
+ .input = ah6_input,
+- .output = ah6_output
++ .output = ah6_output,
++ .hdr_offset = xfrm6_find_1stfragopt,
+ };
+
+ static struct inet6_protocol ah6_protocol = {
+diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
+index f6881d7..a960476 100644
+--- a/net/ipv6/anycast.c
++++ b/net/ipv6/anycast.c
+@@ -56,7 +56,7 @@ ip6_onlink(struct in6_addr *addr, struct
+ int onlink;
+
+ onlink = 0;
+- read_lock(&addrconf_lock);
++ rcu_read_lock();
+ idev = __in6_dev_get(dev);
+ if (idev) {
+ read_lock_bh(&idev->lock);
+@@ -68,7 +68,7 @@ ip6_onlink(struct in6_addr *addr, struct
+ }
+ read_unlock_bh(&idev->lock);
+ }
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ return onlink;
+ }
+
+@@ -335,7 +335,7 @@ int ipv6_dev_ac_inc(struct net_device *d
+ write_unlock_bh(&idev->lock);
+
+ dst_hold(&rt->u.dst);
+- if (ip6_ins_rt(rt, NULL, NULL, NULL))
++ if (ip6_ins_rt(rt))
+ dst_release(&rt->u.dst);
+
+ addrconf_join_solict(dev, &aca->aca_addr);
+@@ -378,7 +378,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *
+ addrconf_leave_solict(idev, &aca->aca_addr);
+
+ dst_hold(&aca->aca_rt->u.dst);
+- if (ip6_del_rt(aca->aca_rt, NULL, NULL, NULL))
++ if (ip6_del_rt(aca->aca_rt))
+ dst_free(&aca->aca_rt->u.dst);
+ else
+ dst_release(&aca->aca_rt->u.dst);
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 3b55b4c..7206747 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -156,6 +156,8 @@ ipv4_connected:
+ if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
+ fl.oif = np->mcast_oif;
+
++ security_sk_classify_flow(sk, &fl);
++
+ if (flowlabel) {
+ if (flowlabel->opt && flowlabel->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
+@@ -191,7 +193,12 @@ ipv4_connected:
+
+ ip6_dst_store(sk, dst,
+ ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
+- &np->daddr : NULL);
++ &np->daddr : NULL,
++#ifdef CONFIG_IPV6_SUBTREES
++ ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
++ &np->saddr :
++#endif
++ NULL);
+
+ sk->sk_state = TCP_ESTABLISHED;
+ out:
+@@ -641,10 +648,13 @@ int datagram_send_ctl(struct msghdr *msg
+
+ rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
+
+- /*
+- * TYPE 0
+- */
+- if (rthdr->type) {
++ switch (rthdr->type) {
++ case IPV6_SRCRT_TYPE_0:
++#ifdef CONFIG_IPV6_MIP6
++ case IPV6_SRCRT_TYPE_2:
++#endif
++ break;
++ default:
+ err = -EINVAL;
+ goto exit_f;
+ }
+diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
+index a278d5e..e78680a 100644
+--- a/net/ipv6/esp6.c
++++ b/net/ipv6/esp6.c
+@@ -24,6 +24,7 @@
+ * This file is derived from net/ipv4/esp.c
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <net/ip.h>
+ #include <net/xfrm.h>
+@@ -44,7 +45,8 @@ static int esp6_output(struct xfrm_state
+ int hdr_len;
+ struct ipv6hdr *top_iph;
+ struct ipv6_esp_hdr *esph;
+- struct crypto_tfm *tfm;
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
+ struct esp_data *esp;
+ struct sk_buff *trailer;
+ int blksize;
+@@ -67,7 +69,9 @@ static int esp6_output(struct xfrm_state
+
+ alen = esp->auth.icv_trunc_len;
+ tfm = esp->conf.tfm;
+- blksize = ALIGN(crypto_tfm_alg_blocksize(tfm), 4);
++ desc.tfm = tfm;
++ desc.flags = 0;
++ blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+ clen = ALIGN(clen + 2, blksize);
+ if (esp->conf.padlen)
+ clen = ALIGN(clen, esp->conf.padlen);
+@@ -95,8 +99,13 @@ static int esp6_output(struct xfrm_state
+ esph->seq_no = htonl(++x->replay.oseq);
+ xfrm_aevent_doreplay(x);
+
+- if (esp->conf.ivlen)
+- crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
++ if (esp->conf.ivlen) {
++ if (unlikely(!esp->conf.ivinitted)) {
++ get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
++ esp->conf.ivinitted = 1;
++ }
++ crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
++ }
+
+ do {
+ struct scatterlist *sg = &esp->sgbuf[0];
+@@ -107,24 +116,25 @@ static int esp6_output(struct xfrm_state
+ goto error;
+ }
+ skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen);
+- crypto_cipher_encrypt(tfm, sg, sg, clen);
++ err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
+ if (unlikely(sg != &esp->sgbuf[0]))
+ kfree(sg);
+ } while (0);
+
++ if (unlikely(err))
++ goto error;
++
+ if (esp->conf.ivlen) {
+- memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
+- crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
++ memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
++ crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+ }
+
+ if (esp->auth.icv_full_len) {
+- esp->auth.icv(esp, skb, (u8*)esph-skb->data,
+- sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen+clen, trailer->tail);
+- pskb_put(skb, trailer, alen);
++ err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
++ sizeof(*esph) + esp->conf.ivlen + clen);
++ memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
+ }
+
+- err = 0;
+-
+ error:
+ return err;
+ }
+@@ -134,8 +144,10 @@ static int esp6_input(struct xfrm_state
+ struct ipv6hdr *iph;
+ struct ipv6_esp_hdr *esph;
+ struct esp_data *esp = x->data;
++ struct crypto_blkcipher *tfm = esp->conf.tfm;
++ struct blkcipher_desc desc = { .tfm = tfm };
+ struct sk_buff *trailer;
+- int blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4);
++ int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+ int alen = esp->auth.icv_trunc_len;
+ int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen;
+
+@@ -155,15 +167,16 @@ static int esp6_input(struct xfrm_state
+
+ /* If integrity check is required, do this. */
+ if (esp->auth.icv_full_len) {
+- u8 sum[esp->auth.icv_full_len];
+- u8 sum1[alen];
++ u8 sum[alen];
+
+- esp->auth.icv(esp, skb, 0, skb->len-alen, sum);
++ ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
++ if (ret)
++ goto out;
+
+- if (skb_copy_bits(skb, skb->len-alen, sum1, alen))
++ if (skb_copy_bits(skb, skb->len - alen, sum, alen))
+ BUG();
+
+- if (unlikely(memcmp(sum, sum1, alen))) {
++ if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
+ x->stats.integrity_failed++;
+ ret = -EINVAL;
+ goto out;
+@@ -182,7 +195,7 @@ static int esp6_input(struct xfrm_state
+
+ /* Get ivec. This can be wrong, check against another impls. */
+ if (esp->conf.ivlen)
+- crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm));
++ crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
+
+ {
+ u8 nexthdr[2];
+@@ -197,9 +210,11 @@ static int esp6_input(struct xfrm_state
+ }
+ }
+ skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen);
+- crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen);
++ ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
+ if (unlikely(sg != &esp->sgbuf[0]))
+ kfree(sg);
++ if (unlikely(ret))
++ goto out;
+
+ if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
+ BUG();
+@@ -225,9 +240,9 @@ out:
+ static u32 esp6_get_max_size(struct xfrm_state *x, int mtu)
+ {
+ struct esp_data *esp = x->data;
+- u32 blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4);
++ u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+
+- if (x->props.mode) {
++ if (x->props.mode == XFRM_MODE_TUNNEL) {
+ mtu = ALIGN(mtu + 2, blksize);
+ } else {
+ /* The worst case. */
+@@ -266,11 +281,11 @@ static void esp6_destroy(struct xfrm_sta
+ if (!esp)
+ return;
+
+- crypto_free_tfm(esp->conf.tfm);
++ crypto_free_blkcipher(esp->conf.tfm);
+ esp->conf.tfm = NULL;
+ kfree(esp->conf.ivec);
+ esp->conf.ivec = NULL;
+- crypto_free_tfm(esp->auth.tfm);
++ crypto_free_hash(esp->auth.tfm);
+ esp->auth.tfm = NULL;
+ kfree(esp->auth.work_icv);
+ esp->auth.work_icv = NULL;
+@@ -280,6 +295,7 @@ static void esp6_destroy(struct xfrm_sta
+ static int esp6_init_state(struct xfrm_state *x)
+ {
+ struct esp_data *esp = NULL;
++ struct crypto_blkcipher *tfm;
+
+ /* null auth and encryption can have zero length keys */
+ if (x->aalg) {
+@@ -298,24 +314,29 @@ static int esp6_init_state(struct xfrm_s
+
+ if (x->aalg) {
+ struct xfrm_algo_desc *aalg_desc;
++ struct crypto_hash *hash;
+
+ esp->auth.key = x->aalg->alg_key;
+ esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
+- esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
+- if (esp->auth.tfm == NULL)
++ hash = crypto_alloc_hash(x->aalg->alg_name, 0,
++ CRYPTO_ALG_ASYNC);
++ if (IS_ERR(hash))
++ goto error;
++
++ esp->auth.tfm = hash;
++ if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))
+ goto error;
+- esp->auth.icv = esp_hmac_digest;
+
+ aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
+ BUG_ON(!aalg_desc);
+
+ if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+- crypto_tfm_alg_digestsize(esp->auth.tfm)) {
+- printk(KERN_INFO "ESP: %s digestsize %u != %hu\n",
+- x->aalg->alg_name,
+- crypto_tfm_alg_digestsize(esp->auth.tfm),
+- aalg_desc->uinfo.auth.icv_fullbits/8);
+- goto error;
++ crypto_hash_digestsize(hash)) {
++ NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
++ x->aalg->alg_name,
++ crypto_hash_digestsize(hash),
++ aalg_desc->uinfo.auth.icv_fullbits/8);
++ goto error;
+ }
+
+ esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
+@@ -327,24 +348,22 @@ static int esp6_init_state(struct xfrm_s
+ }
+ esp->conf.key = x->ealg->alg_key;
+ esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
+- if (x->props.ealgo == SADB_EALG_NULL)
+- esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_ECB);
+- else
+- esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC);
+- if (esp->conf.tfm == NULL)
++ tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm))
+ goto error;
+- esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm);
++ esp->conf.tfm = tfm;
++ esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
+ esp->conf.padlen = 0;
+ if (esp->conf.ivlen) {
+ esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
+ if (unlikely(esp->conf.ivec == NULL))
+ goto error;
+- get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
++ esp->conf.ivinitted = 0;
+ }
+- if (crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len))
++ if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len))
+ goto error;
+ x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen;
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ x->props.header_len += sizeof(struct ipv6hdr);
+ x->data = esp;
+ return 0;
+@@ -365,7 +384,8 @@ static struct xfrm_type esp6_type =
+ .destructor = esp6_destroy,
+ .get_max_size = esp6_get_max_size,
+ .input = esp6_input,
+- .output = esp6_output
++ .output = esp6_output,
++ .hdr_offset = xfrm6_find_1stfragopt,
+ };
+
+ static struct inet6_protocol esp6_protocol = {
+diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
+index 86dac10..88c96b1 100644
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -43,9 +43,54 @@
+ #include <net/ndisc.h>
+ #include <net/ip6_route.h>
+ #include <net/addrconf.h>
++#ifdef CONFIG_IPV6_MIP6
++#include <net/xfrm.h>
++#endif
+
+ #include <asm/uaccess.h>
+
++int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
++{
++ int packet_len = skb->tail - skb->nh.raw;
++ struct ipv6_opt_hdr *hdr;
++ int len;
++
++ if (offset + 2 > packet_len)
++ goto bad;
++ hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
++ len = ((hdr->hdrlen + 1) << 3);
++
++ if (offset + len > packet_len)
++ goto bad;
++
++ offset += 2;
++ len -= 2;
++
++ while (len > 0) {
++ int opttype = skb->nh.raw[offset];
++ int optlen;
++
++ if (opttype == type)
++ return offset;
++
++ switch (opttype) {
++ case IPV6_TLV_PAD0:
++ optlen = 1;
++ break;
++ default:
++ optlen = skb->nh.raw[offset + 1] + 2;
++ if (optlen > len)
++ goto bad;
++ break;
++ }
++ offset += optlen;
++ len -= optlen;
++ }
++ /* not_found */
++ bad:
++ return -1;
++}
++
+ /*
+ * Parsing tlv encoded headers.
+ *
+@@ -56,7 +101,7 @@
+
+ struct tlvtype_proc {
+ int type;
+- int (*func)(struct sk_buff *skb, int offset);
++ int (*func)(struct sk_buff **skbp, int offset);
+ };
+
+ /*********************
+@@ -65,8 +110,10 @@ struct tlvtype_proc {
+
+ /* An unknown option is detected, decide what to do */
+
+-static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
++static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
+ {
++ struct sk_buff *skb = *skbp;
++
+ switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
+ case 0: /* ignore */
+ return 1;
+@@ -91,8 +138,9 @@ static int ip6_tlvopt_unknown(struct sk_
+
+ /* Parse tlv encoded option header (hop-by-hop or destination) */
+
+-static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
++static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
+ {
++ struct sk_buff *skb = *skbp;
+ struct tlvtype_proc *curr;
+ int off = skb->h.raw - skb->nh.raw;
+ int len = ((skb->h.raw[1]+1)<<3);
+@@ -122,13 +170,13 @@ static int ip6_parse_tlv(struct tlvtype_
+ /* type specific length/alignment
+ checks will be performed in the
+ func(). */
+- if (curr->func(skb, off) == 0)
++ if (curr->func(skbp, off) == 0)
+ return 0;
+ break;
+ }
+ }
+ if (curr->type < 0) {
+- if (ip6_tlvopt_unknown(skb, off) == 0)
++ if (ip6_tlvopt_unknown(skbp, off) == 0)
+ return 0;
+ }
+ break;
+@@ -147,8 +195,85 @@ bad:
+ Destination options header.
+ *****************************/
+
++#ifdef CONFIG_IPV6_MIP6
++static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
++{
++ struct sk_buff *skb = *skbp;
++ struct ipv6_destopt_hao *hao;
++ struct inet6_skb_parm *opt = IP6CB(skb);
++ struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw;
++ struct in6_addr tmp_addr;
++ int ret;
++
++ if (opt->dsthao) {
++ LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
++ goto discard;
++ }
++ opt->dsthao = opt->dst1;
++ opt->dst1 = 0;
++
++ hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
++
++ if (hao->length != 16) {
++ LIMIT_NETDEBUG(
++ KERN_DEBUG "hao invalid option length = %d\n", hao->length);
++ goto discard;
++ }
++
++ if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
++ LIMIT_NETDEBUG(
++ KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
++ goto discard;
++ }
++
++ ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
++ (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
++ if (unlikely(ret < 0))
++ goto discard;
++
++ if (skb_cloned(skb)) {
++ struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
++ struct inet6_skb_parm *opt2;
++
++ if (skb2 == NULL)
++ goto discard;
++
++ opt2 = IP6CB(skb2);
++ memcpy(opt2, opt, sizeof(*opt2));
++
++ kfree_skb(skb);
++
++ /* update all variable using below by copied skbuff */
++ *skbp = skb = skb2;
++ hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff);
++ ipv6h = (struct ipv6hdr *)skb2->nh.raw;
++ }
++
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
++ skb->ip_summed = CHECKSUM_NONE;
++
++ ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
++ ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
++ ipv6_addr_copy(&hao->addr, &tmp_addr);
++
++ if (skb->tstamp.off_sec == 0)
++ __net_timestamp(skb);
++
++ return 1;
++
++ discard:
++ kfree_skb(skb);
++ return 0;
++}
++#endif
++
+ static struct tlvtype_proc tlvprocdestopt_lst[] = {
+- /* No destination options are defined now */
++#ifdef CONFIG_IPV6_MIP6
++ {
++ .type = IPV6_TLV_HAO,
++ .func = ipv6_dest_hao,
++ },
++#endif
+ {-1, NULL}
+ };
+
+@@ -156,6 +281,9 @@ static int ipv6_destopt_rcv(struct sk_bu
+ {
+ struct sk_buff *skb = *skbp;
+ struct inet6_skb_parm *opt = IP6CB(skb);
++#ifdef CONFIG_IPV6_MIP6
++ __u16 dstbuf;
++#endif
+
+ if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
+ !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
+@@ -166,10 +294,19 @@ static int ipv6_destopt_rcv(struct sk_bu
+
+ opt->lastopt = skb->h.raw - skb->nh.raw;
+ opt->dst1 = skb->h.raw - skb->nh.raw;
++#ifdef CONFIG_IPV6_MIP6
++ dstbuf = opt->dst1;
++#endif
+
+- if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
++ if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
++ skb = *skbp;
+ skb->h.raw += ((skb->h.raw[1]+1)<<3);
++ opt = IP6CB(skb);
++#ifdef CONFIG_IPV6_MIP6
++ opt->nhoff = dstbuf;
++#else
+ opt->nhoff = opt->dst1;
++#endif
+ return 1;
+ }
+
+@@ -219,7 +356,7 @@ static int ipv6_rthdr_rcv(struct sk_buff
+ {
+ struct sk_buff *skb = *skbp;
+ struct inet6_skb_parm *opt = IP6CB(skb);
+- struct in6_addr *addr;
++ struct in6_addr *addr = NULL;
+ struct in6_addr daddr;
+ int n, i;
+
+@@ -244,6 +381,23 @@ static int ipv6_rthdr_rcv(struct sk_buff
+
+ looped_back:
+ if (hdr->segments_left == 0) {
++ switch (hdr->type) {
++#ifdef CONFIG_IPV6_MIP6
++ case IPV6_SRCRT_TYPE_2:
++ /* Silently discard type 2 header unless it was
++ * processed by own
++ */
++ if (!addr) {
++ IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
++ kfree_skb(skb);
++ return -1;
++ }
++ break;
++#endif
++ default:
++ break;
++ }
++
+ opt->lastopt = skb->h.raw - skb->nh.raw;
+ opt->srcrt = skb->h.raw - skb->nh.raw;
+ skb->h.raw += (hdr->hdrlen + 1) << 3;
+@@ -253,17 +407,29 @@ looped_back:
+ return 1;
+ }
+
+- if (hdr->type != IPV6_SRCRT_TYPE_0) {
++ switch (hdr->type) {
++ case IPV6_SRCRT_TYPE_0:
++ if (hdr->hdrlen & 0x01) {
++ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
++ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
++ return -1;
++ }
++ break;
++#ifdef CONFIG_IPV6_MIP6
++ case IPV6_SRCRT_TYPE_2:
++ /* Silently discard invalid RTH type 2 */
++ if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
++ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
++ kfree_skb(skb);
++ return -1;
++ }
++ break;
++#endif
++ default:
+ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
+ return -1;
+ }
+-
+- if (hdr->hdrlen & 0x01) {
+- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+- icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
+- return -1;
+- }
+
+ /*
+ * This is the routing header forwarding algorithm from
+@@ -294,7 +460,7 @@ looped_back:
+ hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
+ }
+
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_NONE;
+
+ i = n - --hdr->segments_left;
+@@ -303,6 +469,27 @@ looped_back:
+ addr = rthdr->addr;
+ addr += i - 1;
+
++ switch (hdr->type) {
++#ifdef CONFIG_IPV6_MIP6
++ case IPV6_SRCRT_TYPE_2:
++ if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
++ (xfrm_address_t *)&skb->nh.ipv6h->saddr,
++ IPPROTO_ROUTING) < 0) {
++ IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
++ kfree_skb(skb);
++ return -1;
++ }
++ if (!ipv6_chk_home_addr(addr)) {
++ IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
++ kfree_skb(skb);
++ return -1;
++ }
++ break;
++#endif
++ default:
++ break;
++ }
++
+ if (ipv6_addr_is_multicast(addr)) {
+ IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+ kfree_skb(skb);
+@@ -421,8 +608,10 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
+
+ /* Router Alert as of RFC 2711 */
+
+-static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
++static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
+ {
++ struct sk_buff *skb = *skbp;
++
+ if (skb->nh.raw[optoff+1] == 2) {
+ IP6CB(skb)->ra = optoff;
+ return 1;
+@@ -435,8 +624,9 @@ static int ipv6_hop_ra(struct sk_buff *s
+
+ /* Jumbo payload */
+
+-static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
++static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
+ {
++ struct sk_buff *skb = *skbp;
+ u32 pkt_len;
+
+ if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
+@@ -485,8 +675,9 @@ static struct tlvtype_proc tlvprochopopt
+ { -1, }
+ };
+
+-int ipv6_parse_hopopts(struct sk_buff *skb)
++int ipv6_parse_hopopts(struct sk_buff **skbp)
+ {
++ struct sk_buff *skb = *skbp;
+ struct inet6_skb_parm *opt = IP6CB(skb);
+
+ /*
+@@ -502,8 +693,10 @@ int ipv6_parse_hopopts(struct sk_buff *s
+ }
+
+ opt->hop = sizeof(struct ipv6hdr);
+- if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
++ if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
++ skb = *skbp;
+ skb->h.raw += (skb->h.raw[1]+1)<<3;
++ opt = IP6CB(skb);
+ opt->nhoff = sizeof(struct ipv6hdr);
+ return 1;
+ }
+diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
+new file mode 100644
+index 0000000..1896ecb
+--- /dev/null
++++ b/net/ipv6/fib6_rules.c
+@@ -0,0 +1,307 @@
++/*
++ * net/ipv6/fib6_rules.c IPv6 Routing Policy Rules
++ *
++ * Copyright (C)2003-2006 Helsinki University of Technology
++ * Copyright (C)2003-2006 USAGI/WIDE Project
++ *
++ * 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.
++ *
++ * Authors
++ * Thomas Graf <tgraf at suug.ch>
++ * Ville Nuorvala <vnuorval at tcs.hut.fi>
++ */
++
++#include <linux/netdevice.h>
++
++#include <net/fib_rules.h>
++#include <net/ipv6.h>
++#include <net/ip6_route.h>
++#include <net/netlink.h>
++
++struct fib6_rule
++{
++ struct fib_rule common;
++ struct rt6key src;
++ struct rt6key dst;
++#ifdef CONFIG_IPV6_ROUTE_FWMARK
++ u32 fwmark;
++ u32 fwmask;
++#endif
++ u8 tclass;
++};
++
++static struct fib_rules_ops fib6_rules_ops;
++
++static struct fib6_rule main_rule = {
++ .common = {
++ .refcnt = ATOMIC_INIT(2),
++ .pref = 0x7FFE,
++ .action = FR_ACT_TO_TBL,
++ .table = RT6_TABLE_MAIN,
++ },
++};
++
++static struct fib6_rule local_rule = {
++ .common = {
++ .refcnt = ATOMIC_INIT(2),
++ .pref = 0,
++ .action = FR_ACT_TO_TBL,
++ .table = RT6_TABLE_LOCAL,
++ .flags = FIB_RULE_PERMANENT,
++ },
++};
++
++static LIST_HEAD(fib6_rules);
++
++struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
++ pol_lookup_t lookup)
++{
++ struct fib_lookup_arg arg = {
++ .lookup_ptr = lookup,
++ };
++
++ fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg);
++ if (arg.rule)
++ fib_rule_put(arg.rule);
++
++ if (arg.result)
++ return (struct dst_entry *) arg.result;
++
++ dst_hold(&ip6_null_entry.u.dst);
++ return &ip6_null_entry.u.dst;
++}
++
++static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
++ int flags, struct fib_lookup_arg *arg)
++{
++ struct rt6_info *rt = NULL;
++ struct fib6_table *table;
++ pol_lookup_t lookup = arg->lookup_ptr;
++
++ switch (rule->action) {
++ case FR_ACT_TO_TBL:
++ break;
++ case FR_ACT_UNREACHABLE:
++ rt = &ip6_null_entry;
++ goto discard_pkt;
++ default:
++ case FR_ACT_BLACKHOLE:
++ rt = &ip6_blk_hole_entry;
++ goto discard_pkt;
++ case FR_ACT_PROHIBIT:
++ rt = &ip6_prohibit_entry;
++ goto discard_pkt;
++ }
++
++ table = fib6_get_table(rule->table);
++ if (table)
++ rt = lookup(table, flp, flags);
++
++ if (rt != &ip6_null_entry)
++ goto out;
++ dst_release(&rt->u.dst);
++ rt = NULL;
++ goto out;
++
++discard_pkt:
++ dst_hold(&rt->u.dst);
++out:
++ arg->result = rt;
++ return rt == NULL ? -EAGAIN : 0;
++}
++
++
++static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
++{
++ struct fib6_rule *r = (struct fib6_rule *) rule;
++
++ if (r->dst.plen &&
++ !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
++ return 0;
++
++ if (r->src.plen) {
++ if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
++ !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
++ return 0;
++ }
++
++ if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff))
++ return 0;
++
++#ifdef CONFIG_IPV6_ROUTE_FWMARK
++ if ((r->fwmark ^ fl->fl6_fwmark) & r->fwmask)
++ return 0;
++#endif
++
++ return 1;
++}
++
++static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = {
++ [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
++ [FRA_PRIORITY] = { .type = NLA_U32 },
++ [FRA_SRC] = { .len = sizeof(struct in6_addr) },
++ [FRA_DST] = { .len = sizeof(struct in6_addr) },
++ [FRA_FWMARK] = { .type = NLA_U32 },
++ [FRA_FWMASK] = { .type = NLA_U32 },
++ [FRA_TABLE] = { .type = NLA_U32 },
++};
++
++static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
++ struct nlmsghdr *nlh, struct fib_rule_hdr *frh,
++ struct nlattr **tb)
++{
++ int err = -EINVAL;
++ struct fib6_rule *rule6 = (struct fib6_rule *) rule;
++
++ if (frh->src_len > 128 || frh->dst_len > 128 ||
++ (frh->tos & ~IPV6_FLOWINFO_MASK))
++ goto errout;
++
++ if (rule->action == FR_ACT_TO_TBL) {
++ if (rule->table == RT6_TABLE_UNSPEC)
++ goto errout;
++
++ if (fib6_new_table(rule->table) == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
++ }
++
++ if (tb[FRA_SRC])
++ nla_memcpy(&rule6->src.addr, tb[FRA_SRC],
++ sizeof(struct in6_addr));
++
++ if (tb[FRA_DST])
++ nla_memcpy(&rule6->dst.addr, tb[FRA_DST],
++ sizeof(struct in6_addr));
++
++#ifdef CONFIG_IPV6_ROUTE_FWMARK
++ if (tb[FRA_FWMARK]) {
++ rule6->fwmark = nla_get_u32(tb[FRA_FWMARK]);
++ if (rule6->fwmark) {
++ /*
++ * if the mark value is non-zero,
++ * all bits are compared by default
++ * unless a mask is explicitly specified.
++ */
++ rule6->fwmask = 0xFFFFFFFF;
++ }
++ }
++
++ if (tb[FRA_FWMASK])
++ rule6->fwmask = nla_get_u32(tb[FRA_FWMASK]);
++#endif
++
++ rule6->src.plen = frh->src_len;
++ rule6->dst.plen = frh->dst_len;
++ rule6->tclass = frh->tos;
++
++ err = 0;
++errout:
++ return err;
++}
++
++static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
++ struct nlattr **tb)
++{
++ struct fib6_rule *rule6 = (struct fib6_rule *) rule;
++
++ if (frh->src_len && (rule6->src.plen != frh->src_len))
++ return 0;
++
++ if (frh->dst_len && (rule6->dst.plen != frh->dst_len))
++ return 0;
++
++ if (frh->tos && (rule6->tclass != frh->tos))
++ return 0;
++
++ if (tb[FRA_SRC] &&
++ nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
++ return 0;
++
++ if (tb[FRA_DST] &&
++ nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
++ return 0;
++
++#ifdef CONFIG_IPV6_ROUTE_FWMARK
++ if (tb[FRA_FWMARK] && (rule6->fwmark != nla_get_u32(tb[FRA_FWMARK])))
++ return 0;
++
++ if (tb[FRA_FWMASK] && (rule6->fwmask != nla_get_u32(tb[FRA_FWMASK])))
++ return 0;
++#endif
++
++ return 1;
++}
++
++static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
++ struct nlmsghdr *nlh, struct fib_rule_hdr *frh)
++{
++ struct fib6_rule *rule6 = (struct fib6_rule *) rule;
++
++ frh->family = AF_INET6;
++ frh->dst_len = rule6->dst.plen;
++ frh->src_len = rule6->src.plen;
++ frh->tos = rule6->tclass;
++
++ if (rule6->dst.plen)
++ NLA_PUT(skb, FRA_DST, sizeof(struct in6_addr),
++ &rule6->dst.addr);
++
++ if (rule6->src.plen)
++ NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr),
++ &rule6->src.addr);
++
++#ifdef CONFIG_IPV6_ROUTE_FWMARK
++ if (rule6->fwmark)
++ NLA_PUT_U32(skb, FRA_FWMARK, rule6->fwmark);
++
++ if (rule6->fwmask || rule6->fwmark)
++ NLA_PUT_U32(skb, FRA_FWMASK, rule6->fwmask);
++#endif
++
++ return 0;
++
++nla_put_failure:
++ return -ENOBUFS;
++}
++
++int fib6_rules_dump(struct sk_buff *skb, struct netlink_callback *cb)
++{
++ return fib_rules_dump(skb, cb, AF_INET6);
++}
++
++static u32 fib6_rule_default_pref(void)
++{
++ return 0x3FFF;
++}
++
++static struct fib_rules_ops fib6_rules_ops = {
++ .family = AF_INET6,
++ .rule_size = sizeof(struct fib6_rule),
++ .action = fib6_rule_action,
++ .match = fib6_rule_match,
++ .configure = fib6_rule_configure,
++ .compare = fib6_rule_compare,
++ .fill = fib6_rule_fill,
++ .default_pref = fib6_rule_default_pref,
++ .nlgroup = RTNLGRP_IPV6_RULE,
++ .policy = fib6_rule_policy,
++ .rules_list = &fib6_rules,
++ .owner = THIS_MODULE,
++};
++
++void __init fib6_rules_init(void)
++{
++ list_add_tail(&local_rule.common.list, &fib6_rules);
++ list_add_tail(&main_rule.common.list, &fib6_rules);
++
++ fib_rules_register(&fib6_rules_ops);
++}
++
++void fib6_rules_cleanup(void)
++{
++ fib_rules_unregister(&fib6_rules_ops);
++}
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index 356a8a7..4ec8760 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -151,7 +151,7 @@ static int is_ineligible(struct sk_buff
+ return 0;
+ }
+
+-static int sysctl_icmpv6_time = 1*HZ;
++static int sysctl_icmpv6_time __read_mostly = 1*HZ;
+
+ /*
+ * Check the ICMP output rate limit
+@@ -273,6 +273,29 @@ static int icmpv6_getfrag(void *from, ch
+ return 0;
+ }
+
++#ifdef CONFIG_IPV6_MIP6
++static void mip6_addr_swap(struct sk_buff *skb)
++{
++ struct ipv6hdr *iph = skb->nh.ipv6h;
++ struct inet6_skb_parm *opt = IP6CB(skb);
++ struct ipv6_destopt_hao *hao;
++ struct in6_addr tmp;
++ int off;
++
++ if (opt->dsthao) {
++ off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
++ if (likely(off >= 0)) {
++ hao = (struct ipv6_destopt_hao *)(skb->nh.raw + off);
++ ipv6_addr_copy(&tmp, &iph->saddr);
++ ipv6_addr_copy(&iph->saddr, &hao->addr);
++ ipv6_addr_copy(&hao->addr, &tmp);
++ }
++ }
++}
++#else
++static inline void mip6_addr_swap(struct sk_buff *skb) {}
++#endif
++
+ /*
+ * Send an ICMP message in response to a packet in error
+ */
+@@ -350,6 +373,8 @@ void icmpv6_send(struct sk_buff *skb, in
+ return;
+ }
+
++ mip6_addr_swap(skb);
++
+ memset(&fl, 0, sizeof(fl));
+ fl.proto = IPPROTO_ICMPV6;
+ ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
+@@ -358,6 +383,7 @@ void icmpv6_send(struct sk_buff *skb, in
+ fl.oif = iif;
+ fl.fl_icmp_type = type;
+ fl.fl_icmp_code = code;
++ security_skb_classify_flow(skb, &fl);
+
+ if (icmpv6_xmit_lock())
+ return;
+@@ -472,6 +498,7 @@ static void icmpv6_echo_reply(struct sk_
+ ipv6_addr_copy(&fl.fl6_src, saddr);
+ fl.oif = skb->dev->ifindex;
+ fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
++ security_skb_classify_flow(skb, &fl);
+
+ if (icmpv6_xmit_lock())
+ return;
+@@ -604,7 +631,7 @@ static int icmpv6_rcv(struct sk_buff **p
+
+ /* Perform checksum. */
+ switch (skb->ip_summed) {
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
+ skb->csum))
+ break;
+diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
+index bf49107..827f41d 100644
+--- a/net/ipv6/inet6_connection_sock.c
++++ b/net/ipv6/inet6_connection_sock.c
+@@ -157,6 +157,7 @@ int inet6_csk_xmit(struct sk_buff *skb,
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_sport = inet->sport;
+ fl.fl_ip_dport = inet->dport;
++ security_sk_classify_flow(sk, &fl);
+
+ if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
+@@ -185,7 +186,7 @@ int inet6_csk_xmit(struct sk_buff *skb,
+ return err;
+ }
+
+- __ip6_dst_store(sk, dst, NULL);
++ __ip6_dst_store(sk, dst, NULL, NULL);
+ }
+
+ skb->dst = dst_clone(dst);
+diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
+index d2f3fc9..8accd1f 100644
+--- a/net/ipv6/inet6_hashtables.c
++++ b/net/ipv6/inet6_hashtables.c
+@@ -64,7 +64,7 @@ struct sock *__inet6_lookup_established(
+ {
+ struct sock *sk;
+ const struct hlist_node *node;
+- const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
++ const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
+ /* Optimize here for direct hit, only listening connections can
+ * have wildcards anyways.
+ */
+@@ -82,7 +82,7 @@ struct sock *__inet6_lookup_established(
+ sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+ const struct inet_timewait_sock *tw = inet_twsk(sk);
+
+- if(*((__u32 *)&(tw->tw_dport)) == ports &&
++ if(*((__portpair *)&(tw->tw_dport)) == ports &&
+ sk->sk_family == PF_INET6) {
+ const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
+
+@@ -171,7 +171,7 @@ static int __inet6_check_established(str
+ const struct in6_addr *daddr = &np->rcv_saddr;
+ const struct in6_addr *saddr = &np->daddr;
+ const int dif = sk->sk_bound_dev_if;
+- const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
++ const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
+ const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr,
+ inet->dport);
+ struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
+@@ -188,7 +188,7 @@ static int __inet6_check_established(str
+
+ tw = inet_twsk(sk2);
+
+- if(*((__u32 *)&(tw->tw_dport)) == ports &&
++ if(*((__portpair *)&(tw->tw_dport)) == ports &&
+ sk2->sk_family == PF_INET6 &&
+ ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) &&
+ ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
+diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
+index 7642212..f98ca30 100644
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -18,6 +18,7 @@
+ * Yuji SEKIYA @USAGI: Support default route on router node;
+ * remove ip6_null_entry from the top of
+ * routing table.
++ * Ville Nuorvala: Fixed routing subtrees.
+ */
+ #include <linux/errno.h>
+ #include <linux/types.h>
+@@ -26,6 +27,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/in6.h>
+ #include <linux/init.h>
++#include <linux/list.h>
+
+ #ifdef CONFIG_PROC_FS
+ #include <linux/proc_fs.h>
+@@ -68,19 +70,19 @@ struct fib6_cleaner_t
+ void *arg;
+ };
+
+-DEFINE_RWLOCK(fib6_walker_lock);
+-
++static DEFINE_RWLOCK(fib6_walker_lock);
+
+ #ifdef CONFIG_IPV6_SUBTREES
+ #define FWS_INIT FWS_S
+-#define SUBTREE(fn) ((fn)->subtree)
+ #else
+ #define FWS_INIT FWS_L
+-#define SUBTREE(fn) NULL
+ #endif
+
+ static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
++static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
+ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
++static int fib6_walk(struct fib6_walker_t *w);
++static int fib6_walk_continue(struct fib6_walker_t *w);
+
+ /*
+ * A routing update causes an increase of the serial number on the
+@@ -93,13 +95,31 @@ static __u32 rt_sernum;
+
+ static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0);
+
+-struct fib6_walker_t fib6_walker_list = {
++static struct fib6_walker_t fib6_walker_list = {
+ .prev = &fib6_walker_list,
+ .next = &fib6_walker_list,
+ };
+
+ #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next)
+
++static inline void fib6_walker_link(struct fib6_walker_t *w)
++{
++ write_lock_bh(&fib6_walker_lock);
++ w->next = fib6_walker_list.next;
++ w->prev = &fib6_walker_list;
++ w->next->prev = w;
++ w->prev->next = w;
++ write_unlock_bh(&fib6_walker_lock);
++}
++
++static inline void fib6_walker_unlink(struct fib6_walker_t *w)
++{
++ write_lock_bh(&fib6_walker_lock);
++ w->next->prev = w->prev;
++ w->prev->next = w->next;
++ w->prev = w->next = w;
++ write_unlock_bh(&fib6_walker_lock);
++}
+ static __inline__ u32 fib6_new_sernum(void)
+ {
+ u32 n = ++rt_sernum;
+@@ -147,6 +167,256 @@ static __inline__ void rt6_release(struc
+ dst_free(&rt->u.dst);
+ }
+
++static struct fib6_table fib6_main_tbl = {
++ .tb6_id = RT6_TABLE_MAIN,
++ .tb6_root = {
++ .leaf = &ip6_null_entry,
++ .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
++ },
++};
++
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++#define FIB_TABLE_HASHSZ 256
++#else
++#define FIB_TABLE_HASHSZ 1
++#endif
++static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
++
++static void fib6_link_table(struct fib6_table *tb)
++{
++ unsigned int h;
++
++ /*
++ * Initialize table lock at a single place to give lockdep a key,
++ * tables aren't visible prior to being linked to the list.
++ */
++ rwlock_init(&tb->tb6_lock);
++
++ h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
++
++ /*
++ * No protection necessary, this is the only list mutatation
++ * operation, tables never disappear once they exist.
++ */
++ hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
++}
++
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++static struct fib6_table fib6_local_tbl = {
++ .tb6_id = RT6_TABLE_LOCAL,
++ .tb6_root = {
++ .leaf = &ip6_null_entry,
++ .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
++ },
++};
++
++static struct fib6_table *fib6_alloc_table(u32 id)
++{
++ struct fib6_table *table;
++
++ table = kzalloc(sizeof(*table), GFP_ATOMIC);
++ if (table != NULL) {
++ table->tb6_id = id;
++ table->tb6_root.leaf = &ip6_null_entry;
++ table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
++ }
++
++ return table;
++}
++
++struct fib6_table *fib6_new_table(u32 id)
++{
++ struct fib6_table *tb;
++
++ if (id == 0)
++ id = RT6_TABLE_MAIN;
++ tb = fib6_get_table(id);
++ if (tb)
++ return tb;
++
++ tb = fib6_alloc_table(id);
++ if (tb != NULL)
++ fib6_link_table(tb);
++
++ return tb;
++}
++
++struct fib6_table *fib6_get_table(u32 id)
++{
++ struct fib6_table *tb;
++ struct hlist_node *node;
++ unsigned int h;
++
++ if (id == 0)
++ id = RT6_TABLE_MAIN;
++ h = id & (FIB_TABLE_HASHSZ - 1);
++ rcu_read_lock();
++ hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
++ if (tb->tb6_id == id) {
++ rcu_read_unlock();
++ return tb;
++ }
++ }
++ rcu_read_unlock();
++
++ return NULL;
++}
++
++static void __init fib6_tables_init(void)
++{
++ fib6_link_table(&fib6_main_tbl);
++ fib6_link_table(&fib6_local_tbl);
++}
++
++#else
++
++struct fib6_table *fib6_new_table(u32 id)
++{
++ return fib6_get_table(id);
++}
++
++struct fib6_table *fib6_get_table(u32 id)
++{
++ return &fib6_main_tbl;
++}
++
++struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
++ pol_lookup_t lookup)
++{
++ return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags);
++}
++
++static void __init fib6_tables_init(void)
++{
++ fib6_link_table(&fib6_main_tbl);
++}
++
++#endif
++
++static int fib6_dump_node(struct fib6_walker_t *w)
++{
++ int res;
++ struct rt6_info *rt;
++
++ for (rt = w->leaf; rt; rt = rt->u.next) {
++ res = rt6_dump_route(rt, w->args);
++ if (res < 0) {
++ /* Frame is full, suspend walking */
++ w->leaf = rt;
++ return 1;
++ }
++ BUG_TRAP(res!=0);
++ }
++ w->leaf = NULL;
++ return 0;
++}
++
++static void fib6_dump_end(struct netlink_callback *cb)
++{
++ struct fib6_walker_t *w = (void*)cb->args[2];
++
++ if (w) {
++ cb->args[2] = 0;
++ kfree(w);
++ }
++ cb->done = (void*)cb->args[3];
++ cb->args[1] = 3;
++}
++
++static int fib6_dump_done(struct netlink_callback *cb)
++{
++ fib6_dump_end(cb);
++ return cb->done ? cb->done(cb) : 0;
++}
++
++static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
++ struct netlink_callback *cb)
++{
++ struct fib6_walker_t *w;
++ int res;
++
++ w = (void *)cb->args[2];
++ w->root = &table->tb6_root;
++
++ if (cb->args[4] == 0) {
++ read_lock_bh(&table->tb6_lock);
++ res = fib6_walk(w);
++ read_unlock_bh(&table->tb6_lock);
++ if (res > 0)
++ cb->args[4] = 1;
++ } else {
++ read_lock_bh(&table->tb6_lock);
++ res = fib6_walk_continue(w);
++ read_unlock_bh(&table->tb6_lock);
++ if (res != 0) {
++ if (res < 0)
++ fib6_walker_unlink(w);
++ goto end;
++ }
++ fib6_walker_unlink(w);
++ cb->args[4] = 0;
++ }
++end:
++ return res;
++}
++
++int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
++{
++ unsigned int h, s_h;
++ unsigned int e = 0, s_e;
++ struct rt6_rtnl_dump_arg arg;
++ struct fib6_walker_t *w;
++ struct fib6_table *tb;
++ struct hlist_node *node;
++ int res = 0;
++
++ s_h = cb->args[0];
++ s_e = cb->args[1];
++
++ w = (void *)cb->args[2];
++ if (w == NULL) {
++ /* New dump:
++ *
++ * 1. hook callback destructor.
++ */
++ cb->args[3] = (long)cb->done;
++ cb->done = fib6_dump_done;
++
++ /*
++ * 2. allocate and initialize walker.
++ */
++ w = kzalloc(sizeof(*w), GFP_ATOMIC);
++ if (w == NULL)
++ return -ENOMEM;
++ w->func = fib6_dump_node;
++ cb->args[2] = (long)w;
++ }
++
++ arg.skb = skb;
++ arg.cb = cb;
++ w->args = &arg;
++
++ for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
++ e = 0;
++ hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
++ if (e < s_e)
++ goto next;
++ res = fib6_dump_table(tb, skb, cb);
++ if (res != 0)
++ goto out;
++next:
++ e++;
++ }
++ }
++out:
++ cb->args[1] = e;
++ cb->args[0] = h;
++
++ res = res < 0 ? res : skb->len;
++ if (res <= 0)
++ fib6_dump_end(cb);
++ return res;
++}
+
+ /*
+ * Routing Table
+@@ -343,7 +613,7 @@ insert_above:
+ */
+
+ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
+- struct nlmsghdr *nlh, struct netlink_skb_parms *req)
++ struct nl_info *info)
+ {
+ struct rt6_info *iter = NULL;
+ struct rt6_info **ins;
+@@ -398,7 +668,7 @@ out:
+ *ins = rt;
+ rt->rt6i_node = fn;
+ atomic_inc(&rt->rt6i_ref);
+- inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req);
++ inet6_rt_notify(RTM_NEWROUTE, rt, info);
+ rt6_stats.fib_rt_entries++;
+
+ if ((fn->fn_flags & RTN_RTINFO) == 0) {
+@@ -428,10 +698,9 @@ void fib6_force_start_gc(void)
+ * with source addr info in sub-trees
+ */
+
+-int fib6_add(struct fib6_node *root, struct rt6_info *rt,
+- struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
++int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
+ {
+- struct fib6_node *fn;
++ struct fib6_node *fn, *pn = NULL;
+ int err = -ENOMEM;
+
+ fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
+@@ -440,6 +709,8 @@ int fib6_add(struct fib6_node *root, str
+ if (fn == NULL)
+ goto out;
+
++ pn = fn;
++
+ #ifdef CONFIG_IPV6_SUBTREES
+ if (rt->rt6i_src.plen) {
+ struct fib6_node *sn;
+@@ -485,10 +756,6 @@ int fib6_add(struct fib6_node *root, str
+ /* Now link new subtree to main tree */
+ sfn->parent = fn;
+ fn->subtree = sfn;
+- if (fn->leaf == NULL) {
+- fn->leaf = rt;
+- atomic_inc(&rt->rt6i_ref);
+- }
+ } else {
+ sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
+ sizeof(struct in6_addr), rt->rt6i_src.plen,
+@@ -498,21 +765,42 @@ int fib6_add(struct fib6_node *root, str
+ goto st_failure;
+ }
+
++ if (fn->leaf == NULL) {
++ fn->leaf = rt;
++ atomic_inc(&rt->rt6i_ref);
++ }
+ fn = sn;
+ }
+ #endif
+
+- err = fib6_add_rt2node(fn, rt, nlh, req);
++ err = fib6_add_rt2node(fn, rt, info);
+
+ if (err == 0) {
+ fib6_start_gc(rt);
+ if (!(rt->rt6i_flags&RTF_CACHE))
+- fib6_prune_clones(fn, rt);
++ fib6_prune_clones(pn, rt);
+ }
+
+ out:
+- if (err)
++ if (err) {
++#ifdef CONFIG_IPV6_SUBTREES
++ /*
++ * If fib6_add_1 has cleared the old leaf pointer in the
++ * super-tree leaf node we have to find a new one for it.
++ */
++ if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
++ pn->leaf = fib6_find_prefix(pn);
++#if RT6_DEBUG >= 2
++ if (!pn->leaf) {
++ BUG_TRAP(pn->leaf != NULL);
++ pn->leaf = &ip6_null_entry;
++ }
++#endif
++ atomic_inc(&pn->leaf->rt6i_ref);
++ }
++#endif
+ dst_free(&rt->u.dst);
++ }
+ return err;
+
+ #ifdef CONFIG_IPV6_SUBTREES
+@@ -543,6 +831,9 @@ static struct fib6_node * fib6_lookup_1(
+ struct fib6_node *fn;
+ int dir;
+
++ if (unlikely(args->offset == 0))
++ return NULL;
++
+ /*
+ * Descend on a tree
+ */
+@@ -564,33 +855,26 @@ static struct fib6_node * fib6_lookup_1(
+ break;
+ }
+
+- while ((fn->fn_flags & RTN_ROOT) == 0) {
+-#ifdef CONFIG_IPV6_SUBTREES
+- if (fn->subtree) {
+- struct fib6_node *st;
+- struct lookup_args *narg;
+-
+- narg = args + 1;
+-
+- if (narg->addr) {
+- st = fib6_lookup_1(fn->subtree, narg);
+-
+- if (st && !(st->fn_flags & RTN_ROOT))
+- return st;
+- }
+- }
+-#endif
+-
+- if (fn->fn_flags & RTN_RTINFO) {
++ while(fn) {
++ if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) {
+ struct rt6key *key;
+
+ key = (struct rt6key *) ((u8 *) fn->leaf +
+ args->offset);
+
+- if (ipv6_prefix_equal(&key->addr, args->addr, key->plen))
+- return fn;
++ if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) {
++#ifdef CONFIG_IPV6_SUBTREES
++ if (fn->subtree)
++ fn = fib6_lookup_1(fn->subtree, args + 1);
++#endif
++ if (!fn || fn->fn_flags & RTN_RTINFO)
++ return fn;
++ }
+ }
+
++ if (fn->fn_flags & RTN_ROOT)
++ break;
++
+ fn = fn->parent;
+ }
+
+@@ -600,18 +884,24 @@ static struct fib6_node * fib6_lookup_1(
+ struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
+ struct in6_addr *saddr)
+ {
+- struct lookup_args args[2];
+ struct fib6_node *fn;
+-
+- args[0].offset = offsetof(struct rt6_info, rt6i_dst);
+- args[0].addr = daddr;
+-
++ struct lookup_args args[] = {
++ {
++ .offset = offsetof(struct rt6_info, rt6i_dst),
++ .addr = daddr,
++ },
+ #ifdef CONFIG_IPV6_SUBTREES
+- args[1].offset = offsetof(struct rt6_info, rt6i_src);
+- args[1].addr = saddr;
++ {
++ .offset = offsetof(struct rt6_info, rt6i_src),
++ .addr = saddr,
++ },
+ #endif
++ {
++ .offset = 0, /* sentinel */
++ }
++ };
+
+- fn = fib6_lookup_1(root, args);
++ fn = fib6_lookup_1(root, daddr ? args : args + 1);
+
+ if (fn == NULL || fn->fn_flags & RTN_TL_ROOT)
+ fn = root;
+@@ -667,10 +957,8 @@ struct fib6_node * fib6_locate(struct fi
+ #ifdef CONFIG_IPV6_SUBTREES
+ if (src_len) {
+ BUG_TRAP(saddr!=NULL);
+- if (fn == NULL)
+- fn = fn->subtree;
+- if (fn)
+- fn = fib6_locate_1(fn, saddr, src_len,
++ if (fn && fn->subtree)
++ fn = fib6_locate_1(fn->subtree, saddr, src_len,
+ offsetof(struct rt6_info, rt6i_src));
+ }
+ #endif
+@@ -699,7 +987,7 @@ static struct rt6_info * fib6_find_prefi
+ if(fn->right)
+ return fn->right->leaf;
+
+- fn = SUBTREE(fn);
++ fn = FIB6_SUBTREE(fn);
+ }
+ return NULL;
+ }
+@@ -730,7 +1018,7 @@ static struct fib6_node * fib6_repair_tr
+ if (fn->right) child = fn->right, children |= 1;
+ if (fn->left) child = fn->left, children |= 2;
+
+- if (children == 3 || SUBTREE(fn)
++ if (children == 3 || FIB6_SUBTREE(fn)
+ #ifdef CONFIG_IPV6_SUBTREES
+ /* Subtree root (i.e. fn) may have one child */
+ || (children && fn->fn_flags&RTN_ROOT)
+@@ -749,9 +1037,9 @@ static struct fib6_node * fib6_repair_tr
+
+ pn = fn->parent;
+ #ifdef CONFIG_IPV6_SUBTREES
+- if (SUBTREE(pn) == fn) {
++ if (FIB6_SUBTREE(pn) == fn) {
+ BUG_TRAP(fn->fn_flags&RTN_ROOT);
+- SUBTREE(pn) = NULL;
++ FIB6_SUBTREE(pn) = NULL;
+ nstate = FWS_L;
+ } else {
+ BUG_TRAP(!(fn->fn_flags&RTN_ROOT));
+@@ -799,7 +1087,7 @@ static struct fib6_node * fib6_repair_tr
+ read_unlock(&fib6_walker_lock);
+
+ node_free(fn);
+- if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn))
++ if (pn->fn_flags&RTN_RTINFO || FIB6_SUBTREE(pn))
+ return pn;
+
+ rt6_release(pn->leaf);
+@@ -809,7 +1097,7 @@ static struct fib6_node * fib6_repair_tr
+ }
+
+ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
+- struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
++ struct nl_info *info)
+ {
+ struct fib6_walker_t *w;
+ struct rt6_info *rt = *rtp;
+@@ -865,11 +1153,11 @@ static void fib6_del_route(struct fib6_n
+ if (atomic_read(&rt->rt6i_ref) != 1) BUG();
+ }
+
+- inet6_rt_notify(RTM_DELROUTE, rt, nlh, req);
++ inet6_rt_notify(RTM_DELROUTE, rt, info);
+ rt6_release(rt);
+ }
+
+-int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
++int fib6_del(struct rt6_info *rt, struct nl_info *info)
+ {
+ struct fib6_node *fn = rt->rt6i_node;
+ struct rt6_info **rtp;
+@@ -885,8 +1173,18 @@ int fib6_del(struct rt6_info *rt, struct
+
+ BUG_TRAP(fn->fn_flags&RTN_RTINFO);
+
+- if (!(rt->rt6i_flags&RTF_CACHE))
+- fib6_prune_clones(fn, rt);
++ if (!(rt->rt6i_flags&RTF_CACHE)) {
++ struct fib6_node *pn = fn;
++#ifdef CONFIG_IPV6_SUBTREES
++ /* clones of this route might be in another subtree */
++ if (rt->rt6i_src.plen) {
++ while (!(pn->fn_flags&RTN_ROOT))
++ pn = pn->parent;
++ pn = pn->parent;
++ }
++#endif
++ fib6_prune_clones(pn, rt);
++ }
+
+ /*
+ * Walk the leaf entries looking for ourself
+@@ -894,7 +1192,7 @@ int fib6_del(struct rt6_info *rt, struct
+
+ for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {
+ if (*rtp == rt) {
+- fib6_del_route(fn, rtp, nlh, _rtattr, req);
++ fib6_del_route(fn, rtp, info);
+ return 0;
+ }
+ }
+@@ -925,7 +1223,7 @@ int fib6_del(struct rt6_info *rt, struct
+ * <0 -> walk is terminated by an error.
+ */
+
+-int fib6_walk_continue(struct fib6_walker_t *w)
++static int fib6_walk_continue(struct fib6_walker_t *w)
+ {
+ struct fib6_node *fn, *pn;
+
+@@ -942,8 +1240,8 @@ int fib6_walk_continue(struct fib6_walke
+ switch (w->state) {
+ #ifdef CONFIG_IPV6_SUBTREES
+ case FWS_S:
+- if (SUBTREE(fn)) {
+- w->node = SUBTREE(fn);
++ if (FIB6_SUBTREE(fn)) {
++ w->node = FIB6_SUBTREE(fn);
+ continue;
+ }
+ w->state = FWS_L;
+@@ -977,7 +1275,7 @@ int fib6_walk_continue(struct fib6_walke
+ pn = fn->parent;
+ w->node = pn;
+ #ifdef CONFIG_IPV6_SUBTREES
+- if (SUBTREE(pn) == fn) {
++ if (FIB6_SUBTREE(pn) == fn) {
+ BUG_TRAP(fn->fn_flags&RTN_ROOT);
+ w->state = FWS_L;
+ continue;
+@@ -999,7 +1297,7 @@ int fib6_walk_continue(struct fib6_walke
+ }
+ }
+
+-int fib6_walk(struct fib6_walker_t *w)
++static int fib6_walk(struct fib6_walker_t *w)
+ {
+ int res;
+
+@@ -1023,7 +1321,7 @@ static int fib6_clean_node(struct fib6_w
+ res = c->func(rt, c->arg);
+ if (res < 0) {
+ w->leaf = rt;
+- res = fib6_del(rt, NULL, NULL, NULL);
++ res = fib6_del(rt, NULL);
+ if (res) {
+ #if RT6_DEBUG >= 2
+ printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
+@@ -1049,9 +1347,9 @@ static int fib6_clean_node(struct fib6_w
+ * ignoring pure split nodes) will be scanned.
+ */
+
+-void fib6_clean_tree(struct fib6_node *root,
+- int (*func)(struct rt6_info *, void *arg),
+- int prune, void *arg)
++static void fib6_clean_tree(struct fib6_node *root,
++ int (*func)(struct rt6_info *, void *arg),
++ int prune, void *arg)
+ {
+ struct fib6_cleaner_t c;
+
+@@ -1064,6 +1362,25 @@ void fib6_clean_tree(struct fib6_node *r
+ fib6_walk(&c.w);
+ }
+
++void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
++ int prune, void *arg)
++{
++ struct fib6_table *table;
++ struct hlist_node *node;
++ unsigned int h;
++
++ rcu_read_lock();
++ for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
++ hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
++ tb6_hlist) {
++ write_lock_bh(&table->tb6_lock);
++ fib6_clean_tree(&table->tb6_root, func, prune, arg);
++ write_unlock_bh(&table->tb6_lock);
++ }
++ }
++ rcu_read_unlock();
++}
++
+ static int fib6_prune_clone(struct rt6_info *rt, void *arg)
+ {
+ if (rt->rt6i_flags & RTF_CACHE) {
+@@ -1142,11 +1459,8 @@ void fib6_run_gc(unsigned long dummy)
+ }
+ gc_args.more = 0;
+
+-
+- write_lock_bh(&rt6_lock);
+ ndisc_dst_gc(&gc_args.more);
+- fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL);
+- write_unlock_bh(&rt6_lock);
++ fib6_clean_all(fib6_age, 0, NULL);
+
+ if (gc_args.more)
+ mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
+@@ -1161,10 +1475,10 @@ void __init fib6_init(void)
+ {
+ fib6_node_kmem = kmem_cache_create("fib6_nodes",
+ sizeof(struct fib6_node),
+- 0, SLAB_HWCACHE_ALIGN,
++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+- if (!fib6_node_kmem)
+- panic("cannot create fib6_nodes cache");
++
++ fib6_tables_init();
+ }
+
+ void fib6_gc_cleanup(void)
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index 1d672b0..6d4533b 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -330,8 +330,10 @@ fl_create(struct in6_flowlabel_req *freq
+ fl->share = freq->flr_share;
+ addr_type = ipv6_addr_type(&freq->flr_dst);
+ if ((addr_type&IPV6_ADDR_MAPPED)
+- || addr_type == IPV6_ADDR_ANY)
++ || addr_type == IPV6_ADDR_ANY) {
++ err = -EINVAL;
+ goto done;
++ }
+ ipv6_addr_copy(&fl->dst, &freq->flr_dst);
+ atomic_set(&fl->users, 1);
+ switch (fl->share) {
+@@ -587,6 +589,8 @@ static struct ip6_flowlabel *ip6fl_get_n
+ while (!fl) {
+ if (++state->bucket <= FL_HASH_MASK)
+ fl = fl_ht[state->bucket];
++ else
++ break;
+ }
+ return fl;
+ }
+@@ -623,9 +627,13 @@ static void ip6fl_seq_stop(struct seq_fi
+ read_unlock_bh(&ip6_fl_lock);
+ }
+
+-static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl)
++static int ip6fl_seq_show(struct seq_file *seq, void *v)
+ {
+- while(fl) {
++ if (v == SEQ_START_TOKEN)
++ seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n",
++ "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
++ else {
++ struct ip6_flowlabel *fl = v;
+ seq_printf(seq,
+ "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n",
+ (unsigned)ntohl(fl->label),
+@@ -636,17 +644,7 @@ static void ip6fl_fl_seq_show(struct seq
+ (long)(fl->expires - jiffies)/HZ,
+ NIP6(fl->dst),
+ fl->opt ? fl->opt->opt_nflen : 0);
+- fl = fl->next;
+ }
+-}
+-
+-static int ip6fl_seq_show(struct seq_file *seq, void *v)
+-{
+- if (v == SEQ_START_TOKEN)
+- seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n",
+- "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
+- else
+- ip6fl_fl_seq_show(seq, v);
+ return 0;
+ }
+
+diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
+index 25c2a9e..6b8e6d7 100644
+--- a/net/ipv6/ip6_input.c
++++ b/net/ipv6/ip6_input.c
+@@ -111,7 +111,7 @@ int ipv6_rcv(struct sk_buff *skb, struct
+ }
+
+ if (hdr->nexthdr == NEXTHDR_HOP) {
+- if (ipv6_parse_hopopts(skb) < 0) {
++ if (ipv6_parse_hopopts(&skb) < 0) {
+ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+ return 0;
+ }
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 4fb47a2..6671691 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -308,6 +308,56 @@ static int ip6_call_ra_chain(struct sk_b
+ return 0;
+ }
+
++static int ip6_forward_proxy_check(struct sk_buff *skb)
++{
++ struct ipv6hdr *hdr = skb->nh.ipv6h;
++ u8 nexthdr = hdr->nexthdr;
++ int offset;
++
++ if (ipv6_ext_hdr(nexthdr)) {
++ offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr);
++ if (offset < 0)
++ return 0;
++ } else
++ offset = sizeof(struct ipv6hdr);
++
++ if (nexthdr == IPPROTO_ICMPV6) {
++ struct icmp6hdr *icmp6;
++
++ if (!pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data))
++ return 0;
++
++ icmp6 = (struct icmp6hdr *)(skb->nh.raw + offset);
++
++ switch (icmp6->icmp6_type) {
++ case NDISC_ROUTER_SOLICITATION:
++ case NDISC_ROUTER_ADVERTISEMENT:
++ case NDISC_NEIGHBOUR_SOLICITATION:
++ case NDISC_NEIGHBOUR_ADVERTISEMENT:
++ case NDISC_REDIRECT:
++ /* For reaction involving unicast neighbor discovery
++ * message destined to the proxied address, pass it to
++ * input function.
++ */
++ return 1;
++ default:
++ break;
++ }
++ }
++
++ /*
++ * The proxying router can't forward traffic sent to a link-local
++ * address, so signal the sender and discard the packet. This
++ * behavior is clarified by the MIPv6 specification.
++ */
++ if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) {
++ dst_link_failure(skb);
++ return -1;
++ }
++
++ return 0;
++}
++
+ static inline int ip6_forward_finish(struct sk_buff *skb)
+ {
+ return dst_output(skb);
+@@ -362,6 +412,18 @@ int ip6_forward(struct sk_buff *skb)
+ return -ETIMEDOUT;
+ }
+
++ /* XXX: idev->cnf.proxy_ndp? */
++ if (ipv6_devconf.proxy_ndp &&
++ pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
++ int proxied = ip6_forward_proxy_check(skb);
++ if (proxied > 0)
++ return ip6_input(skb);
++ else if (proxied < 0) {
++ IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
++ goto drop;
++ }
++ }
++
+ if (!xfrm6_route_forward(skb)) {
+ IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+ goto drop;
+@@ -475,17 +537,25 @@ int ip6_find_1stfragopt(struct sk_buff *
+ switch (**nexthdr) {
+
+ case NEXTHDR_HOP:
++ break;
+ case NEXTHDR_ROUTING:
++ found_rhdr = 1;
++ break;
+ case NEXTHDR_DEST:
+- if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1;
+- if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset;
+- offset += ipv6_optlen(exthdr);
+- *nexthdr = &exthdr->nexthdr;
+- exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
++#ifdef CONFIG_IPV6_MIP6
++ if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
++ break;
++#endif
++ if (found_rhdr)
++ return offset;
+ break;
+ default :
+ return offset;
+ }
++
++ offset += ipv6_optlen(exthdr);
++ *nexthdr = &exthdr->nexthdr;
++ exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+ }
+
+ return offset;
+@@ -726,6 +796,14 @@ fail:
+ return err;
+ }
+
++static inline int ip6_rt_check(struct rt6key *rt_key,
++ struct in6_addr *fl_addr,
++ struct in6_addr *addr_cache)
++{
++ return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
++ (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)));
++}
++
+ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
+ struct dst_entry *dst,
+ struct flowi *fl)
+@@ -741,8 +819,8 @@ static struct dst_entry *ip6_sk_dst_chec
+ * that we do not support routing by source, TOS,
+ * and MSG_DONTROUTE --ANK (980726)
+ *
+- * 1. If route was host route, check that
+- * cached destination is current.
++ * 1. ip6_rt_check(): If route was host route,
++ * check that cached destination is current.
+ * If it is network route, we still may
+ * check its validity using saved pointer
+ * to the last used address: daddr_cache.
+@@ -753,11 +831,11 @@ static struct dst_entry *ip6_sk_dst_chec
+ * sockets.
+ * 2. oif also should be the same.
+ */
+- if (((rt->rt6i_dst.plen != 128 ||
+- !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr))
+- && (np->daddr_cache == NULL ||
+- !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache)))
+- || (fl->oif && fl->oif != dst->dev->ifindex)) {
++ if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) ||
++#ifdef CONFIG_IPV6_SUBTREES
++ ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) ||
++#endif
++ (fl->oif && fl->oif != dst->dev->ifindex)) {
+ dst_release(dst);
+ dst = NULL;
+ }
+@@ -866,7 +944,7 @@ static inline int ip6_ufo_append_data(st
+ /* initialize protocol header pointer */
+ skb->h.raw = skb->data + fragheaderlen;
+
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum = 0;
+ sk->sk_sndmsg_off = 0;
+ }
+@@ -963,7 +1041,7 @@ int ip6_append_data(struct sock *sk, int
+
+ hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+
+- fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0);
++ fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0);
+ maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
+
+ if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
+diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
+index 7e4d1c1..71f59f1 100644
+--- a/net/ipv6/ipcomp6.c
++++ b/net/ipv6/ipcomp6.c
+@@ -53,7 +53,7 @@
+
+ struct ipcomp6_tfms {
+ struct list_head list;
+- struct crypto_tfm **tfms;
++ struct crypto_comp **tfms;
+ int users;
+ };
+
+@@ -70,7 +70,7 @@ static int ipcomp6_input(struct xfrm_sta
+ int plen, dlen;
+ struct ipcomp_data *ipcd = x->data;
+ u8 *start, *scratch;
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+ int cpu;
+
+ if (skb_linearize_cow(skb))
+@@ -129,7 +129,7 @@ static int ipcomp6_output(struct xfrm_st
+ struct ipcomp_data *ipcd = x->data;
+ int plen, dlen;
+ u8 *start, *scratch;
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+ int cpu;
+
+ hdr_len = skb->h.raw - skb->data;
+@@ -178,7 +178,7 @@ out_ok:
+ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int type, int code, int offset, __u32 info)
+ {
+- u32 spi;
++ __be32 spi;
+ struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+ struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset);
+ struct xfrm_state *x;
+@@ -199,6 +199,7 @@ static void ipcomp6_err(struct sk_buff *
+ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
+ {
+ struct xfrm_state *t = NULL;
++ u8 mode = XFRM_MODE_TUNNEL;
+
+ t = xfrm_state_alloc();
+ if (!t)
+@@ -212,7 +213,9 @@ static struct xfrm_state *ipcomp6_tunnel
+ memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
+ memcpy(&t->sel, &x->sel, sizeof(t->sel));
+ t->props.family = AF_INET6;
+- t->props.mode = 1;
++ if (x->props.mode == XFRM_MODE_BEET)
++ mode = x->props.mode;
++ t->props.mode = mode;
+ memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
+
+ if (xfrm_init_state(t))
+@@ -234,7 +237,7 @@ static int ipcomp6_tunnel_attach(struct
+ {
+ int err = 0;
+ struct xfrm_state *t = NULL;
+- u32 spi;
++ __be32 spi;
+
+ spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
+ if (spi)
+@@ -301,7 +304,7 @@ static void **ipcomp6_alloc_scratches(vo
+ return scratches;
+ }
+
+-static void ipcomp6_free_tfms(struct crypto_tfm **tfms)
++static void ipcomp6_free_tfms(struct crypto_comp **tfms)
+ {
+ struct ipcomp6_tfms *pos;
+ int cpu;
+@@ -323,28 +326,28 @@ static void ipcomp6_free_tfms(struct cry
+ return;
+
+ for_each_possible_cpu(cpu) {
+- struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu);
+- crypto_free_tfm(tfm);
++ struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
++ crypto_free_comp(tfm);
+ }
+ free_percpu(tfms);
+ }
+
+-static struct crypto_tfm **ipcomp6_alloc_tfms(const char *alg_name)
++static struct crypto_comp **ipcomp6_alloc_tfms(const char *alg_name)
+ {
+ struct ipcomp6_tfms *pos;
+- struct crypto_tfm **tfms;
++ struct crypto_comp **tfms;
+ int cpu;
+
+ /* This can be any valid CPU ID so we don't need locking. */
+ cpu = raw_smp_processor_id();
+
+ list_for_each_entry(pos, &ipcomp6_tfms_list, list) {
+- struct crypto_tfm *tfm;
++ struct crypto_comp *tfm;
+
+ tfms = pos->tfms;
+ tfm = *per_cpu_ptr(tfms, cpu);
+
+- if (!strcmp(crypto_tfm_alg_name(tfm), alg_name)) {
++ if (!strcmp(crypto_comp_name(tfm), alg_name)) {
+ pos->users++;
+ return tfms;
+ }
+@@ -358,12 +361,13 @@ static struct crypto_tfm **ipcomp6_alloc
+ INIT_LIST_HEAD(&pos->list);
+ list_add(&pos->list, &ipcomp6_tfms_list);
+
+- pos->tfms = tfms = alloc_percpu(struct crypto_tfm *);
++ pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
+ if (!tfms)
+ goto error;
+
+ for_each_possible_cpu(cpu) {
+- struct crypto_tfm *tfm = crypto_alloc_tfm(alg_name, 0);
++ struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
++ CRYPTO_ALG_ASYNC);
+ if (!tfm)
+ goto error;
+ *per_cpu_ptr(tfms, cpu) = tfm;
+@@ -416,7 +420,7 @@ static int ipcomp6_init_state(struct xfr
+ goto out;
+
+ x->props.header_len = 0;
+- if (x->props.mode)
++ if (x->props.mode == XFRM_MODE_TUNNEL)
+ x->props.header_len += sizeof(struct ipv6hdr);
+
+ mutex_lock(&ipcomp6_resource_mutex);
+@@ -428,7 +432,7 @@ static int ipcomp6_init_state(struct xfr
+ goto error;
+ mutex_unlock(&ipcomp6_resource_mutex);
+
+- if (x->props.mode) {
++ if (x->props.mode == XFRM_MODE_TUNNEL) {
+ err = ipcomp6_tunnel_attach(x);
+ if (err)
+ goto error_tunnel;
+@@ -460,6 +464,7 @@ static struct xfrm_type ipcomp6_type =
+ .destructor = ipcomp6_destroy,
+ .input = ipcomp6_input,
+ .output = ipcomp6_output,
++ .hdr_offset = xfrm6_find_1stfragopt,
+ };
+
+ static struct inet6_protocol ipcomp6_protocol =
+diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
+index a5eaaf6..de6b919 100644
+--- a/net/ipv6/ipv6_sockglue.c
++++ b/net/ipv6/ipv6_sockglue.c
+@@ -123,6 +123,9 @@ static struct sk_buff *ipv6_gso_segment(
+ struct ipv6hdr *ipv6h;
+ struct inet6_protocol *ops;
+
++ if (!(features & NETIF_F_HW_CSUM))
++ features &= ~NETIF_F_SG;
++
+ if (unlikely(skb_shinfo(skb)->gso_type &
+ ~(SKB_GSO_UDP |
+ SKB_GSO_DODGY |
+@@ -407,8 +410,16 @@ static int do_ipv6_setsockopt(struct soc
+ /* routing header option needs extra check */
+ if (optname == IPV6_RTHDR && opt->srcrt) {
+ struct ipv6_rt_hdr *rthdr = opt->srcrt;
+- if (rthdr->type)
++ switch (rthdr->type) {
++ case IPV6_SRCRT_TYPE_0:
++#ifdef CONFIG_IPV6_MIP6
++ case IPV6_SRCRT_TYPE_2:
++#endif
++ break;
++ default:
+ goto sticky_done;
++ }
++
+ if ((rthdr->hdrlen & 1) ||
+ (rthdr->hdrlen >> 1) != rthdr->segments_left)
+ goto sticky_done;
+diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
+index dd4d1ce..0e8e067 100644
+--- a/net/ipv6/ipv6_syms.c
++++ b/net/ipv6/ipv6_syms.c
+@@ -14,7 +14,6 @@ EXPORT_SYMBOL(ndisc_mc_map);
+ EXPORT_SYMBOL(register_inet6addr_notifier);
+ EXPORT_SYMBOL(unregister_inet6addr_notifier);
+ EXPORT_SYMBOL(ip6_route_output);
+-EXPORT_SYMBOL(addrconf_lock);
+ EXPORT_SYMBOL(ipv6_setsockopt);
+ EXPORT_SYMBOL(ipv6_getsockopt);
+ EXPORT_SYMBOL(inet6_register_protosw);
+@@ -31,6 +30,8 @@ EXPORT_SYMBOL(ipv6_chk_addr);
+ EXPORT_SYMBOL(in6_dev_finish_destroy);
+ #ifdef CONFIG_XFRM
+ EXPORT_SYMBOL(xfrm6_rcv);
++EXPORT_SYMBOL(xfrm6_input_addr);
++EXPORT_SYMBOL(xfrm6_find_1stfragopt);
+ #endif
+ EXPORT_SYMBOL(rt6_lookup);
+ EXPORT_SYMBOL(ipv6_push_nfrag_opts);
+diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
+index 639eb20..3b114e3 100644
+--- a/net/ipv6/mcast.c
++++ b/net/ipv6/mcast.c
+@@ -171,7 +171,7 @@ static int ip6_mc_leave_src(struct sock
+
+ #define IPV6_MLD_MAX_MSF 64
+
+-int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF;
++int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
+
+ /*
+ * socket join on multicast group
+diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
+new file mode 100644
+index 0000000..7ccdc8f
+--- /dev/null
++++ b/net/ipv6/mip6.c
+@@ -0,0 +1,518 @@
++/*
++ * Copyright (C)2003-2006 Helsinki University of Technology
++ * Copyright (C)2003-2006 USAGI/WIDE Project
++ *
++ * 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
++ */
++/*
++ * Authors:
++ * Noriaki TAKAMIYA @USAGI
++ * Masahide NAKAMURA @USAGI
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/time.h>
++#include <linux/ipv6.h>
++#include <linux/icmpv6.h>
++#include <net/sock.h>
++#include <net/ipv6.h>
++#include <net/ip6_checksum.h>
++#include <net/xfrm.h>
++#include <net/mip6.h>
++
++static xfrm_address_t *mip6_xfrm_addr(struct xfrm_state *x, xfrm_address_t *addr)
++{
++ return x->coaddr;
++}
++
++static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
++{
++ return (n - len + 16) & 0x7;
++}
++
++static inline void *mip6_padn(__u8 *data, __u8 padlen)
++{
++ if (!data)
++ return NULL;
++ if (padlen == 1) {
++ data[0] = MIP6_OPT_PAD_1;
++ } else if (padlen > 1) {
++ data[0] = MIP6_OPT_PAD_N;
++ data[1] = padlen - 2;
++ if (padlen > 2)
++ memset(data+2, 0, data[1]);
++ }
++ return data + padlen;
++}
++
++static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos)
++{
++ icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
++}
++
++static int mip6_mh_len(int type)
++{
++ int len = 0;
++
++ switch (type) {
++ case IP6_MH_TYPE_BRR:
++ len = 0;
++ break;
++ case IP6_MH_TYPE_HOTI:
++ case IP6_MH_TYPE_COTI:
++ case IP6_MH_TYPE_BU:
++ case IP6_MH_TYPE_BACK:
++ len = 1;
++ break;
++ case IP6_MH_TYPE_HOT:
++ case IP6_MH_TYPE_COT:
++ case IP6_MH_TYPE_BERROR:
++ len = 2;
++ break;
++ }
++ return len;
++}
++
++int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
++{
++ struct ip6_mh *mh;
++ int mhlen;
++
++ if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) ||
++ !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3)))
++ return -1;
++
++ mh = (struct ip6_mh *)skb->h.raw;
++
++ if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
++ LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n",
++ mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type));
++ mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw);
++ return -1;
++ }
++ mhlen = (mh->ip6mh_hdrlen + 1) << 3;
++
++ if (skb->ip_summed == CHECKSUM_COMPLETE) {
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
++ &skb->nh.ipv6h->daddr,
++ mhlen, IPPROTO_MH,
++ skb->csum)) {
++ LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n");
++ skb->ip_summed = CHECKSUM_NONE;
++ }
++ }
++ if (skb->ip_summed == CHECKSUM_NONE) {
++ if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
++ &skb->nh.ipv6h->daddr,
++ mhlen, IPPROTO_MH,
++ skb_checksum(skb, 0, mhlen, 0))) {
++ LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed "
++ "[" NIP6_FMT " > " NIP6_FMT "]\n",
++ NIP6(skb->nh.ipv6h->saddr),
++ NIP6(skb->nh.ipv6h->daddr));
++ return -1;
++ }
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ }
++
++ if (mh->ip6mh_proto != IPPROTO_NONE) {
++ LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
++ mh->ip6mh_proto);
++ mip6_param_prob(skb, 0, (&mh->ip6mh_proto) - skb->nh.raw);
++ return -1;
++ }
++
++ return 0;
++}
++
++struct mip6_report_rate_limiter {
++ spinlock_t lock;
++ struct timeval stamp;
++ int iif;
++ struct in6_addr src;
++ struct in6_addr dst;
++};
++
++static struct mip6_report_rate_limiter mip6_report_rl = {
++ .lock = SPIN_LOCK_UNLOCKED
++};
++
++static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct ipv6hdr *iph = skb->nh.ipv6h;
++ struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
++
++ if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
++ !ipv6_addr_any((struct in6_addr *)x->coaddr))
++ return -ENOENT;
++
++ return destopt->nexthdr;
++}
++
++/* Destination Option Header is inserted.
++ * IP Header's src address is replaced with Home Address Option in
++ * Destination Option Header.
++ */
++static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct ipv6hdr *iph;
++ struct ipv6_destopt_hdr *dstopt;
++ struct ipv6_destopt_hao *hao;
++ u8 nexthdr;
++ int len;
++
++ iph = (struct ipv6hdr *)skb->data;
++ iph->payload_len = htons(skb->len - sizeof(*iph));
++
++ nexthdr = *skb->nh.raw;
++ *skb->nh.raw = IPPROTO_DSTOPTS;
++
++ dstopt = (struct ipv6_destopt_hdr *)skb->h.raw;
++ dstopt->nexthdr = nexthdr;
++
++ hao = mip6_padn((char *)(dstopt + 1),
++ calc_padlen(sizeof(*dstopt), 6));
++
++ hao->type = IPV6_TLV_HAO;
++ hao->length = sizeof(*hao) - 2;
++ BUG_TRAP(hao->length == 16);
++
++ len = ((char *)hao - (char *)dstopt) + sizeof(*hao);
++
++ memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr));
++ memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
++
++ BUG_TRAP(len == x->props.header_len);
++ dstopt->hdrlen = (x->props.header_len >> 3) - 1;
++
++ return 0;
++}
++
++static inline int mip6_report_rl_allow(struct timeval *stamp,
++ struct in6_addr *dst,
++ struct in6_addr *src, int iif)
++{
++ int allow = 0;
++
++ spin_lock_bh(&mip6_report_rl.lock);
++ if (mip6_report_rl.stamp.tv_sec != stamp->tv_sec ||
++ mip6_report_rl.stamp.tv_usec != stamp->tv_usec ||
++ mip6_report_rl.iif != iif ||
++ !ipv6_addr_equal(&mip6_report_rl.src, src) ||
++ !ipv6_addr_equal(&mip6_report_rl.dst, dst)) {
++ mip6_report_rl.stamp.tv_sec = stamp->tv_sec;
++ mip6_report_rl.stamp.tv_usec = stamp->tv_usec;
++ mip6_report_rl.iif = iif;
++ ipv6_addr_copy(&mip6_report_rl.src, src);
++ ipv6_addr_copy(&mip6_report_rl.dst, dst);
++ allow = 1;
++ }
++ spin_unlock_bh(&mip6_report_rl.lock);
++ return allow;
++}
++
++static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl)
++{
++ struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
++ struct ipv6_destopt_hao *hao = NULL;
++ struct xfrm_selector sel;
++ int offset;
++ struct timeval stamp;
++ int err = 0;
++
++ if (unlikely(fl->proto == IPPROTO_MH &&
++ fl->fl_mh_type <= IP6_MH_TYPE_MAX))
++ goto out;
++
++ if (likely(opt->dsthao)) {
++ offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
++ if (likely(offset >= 0))
++ hao = (struct ipv6_destopt_hao *)(skb->nh.raw + offset);
++ }
++
++ skb_get_timestamp(skb, &stamp);
++
++ if (!mip6_report_rl_allow(&stamp, &skb->nh.ipv6h->daddr,
++ hao ? &hao->addr : &skb->nh.ipv6h->saddr,
++ opt->iif))
++ goto out;
++
++ memset(&sel, 0, sizeof(sel));
++ memcpy(&sel.daddr, (xfrm_address_t *)&skb->nh.ipv6h->daddr,
++ sizeof(sel.daddr));
++ sel.prefixlen_d = 128;
++ memcpy(&sel.saddr, (xfrm_address_t *)&skb->nh.ipv6h->saddr,
++ sizeof(sel.saddr));
++ sel.prefixlen_s = 128;
++ sel.family = AF_INET6;
++ sel.proto = fl->proto;
++ sel.dport = xfrm_flowi_dport(fl);
++ if (sel.dport)
++ sel.dport_mask = ~((__u16)0);
++ sel.sport = xfrm_flowi_sport(fl);
++ if (sel.sport)
++ sel.sport_mask = ~((__u16)0);
++ sel.ifindex = fl->oif;
++
++ err = km_report(IPPROTO_DSTOPTS, &sel,
++ (hao ? (xfrm_address_t *)&hao->addr : NULL));
++
++ out:
++ return err;
++}
++
++static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
++ u8 **nexthdr)
++{
++ u16 offset = sizeof(struct ipv6hdr);
++ struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
++ unsigned int packet_len = skb->tail - skb->nh.raw;
++ int found_rhdr = 0;
++
++ *nexthdr = &skb->nh.ipv6h->nexthdr;
++
++ while (offset + 1 <= packet_len) {
++
++ switch (**nexthdr) {
++ case NEXTHDR_HOP:
++ break;
++ case NEXTHDR_ROUTING:
++ found_rhdr = 1;
++ break;
++ case NEXTHDR_DEST:
++ /*
++ * HAO MUST NOT appear more than once.
++ * XXX: It is better to try to find by the end of
++ * XXX: packet if HAO exists.
++ */
++ if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
++ LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n");
++ return offset;
++ }
++
++ if (found_rhdr)
++ return offset;
++
++ break;
++ default:
++ return offset;
++ }
++
++ offset += ipv6_optlen(exthdr);
++ *nexthdr = &exthdr->nexthdr;
++ exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
++ }
++
++ return offset;
++}
++
++static int mip6_destopt_init_state(struct xfrm_state *x)
++{
++ if (x->id.spi) {
++ printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
++ x->id.spi);
++ return -EINVAL;
++ }
++ if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
++ printk(KERN_INFO "%s: state's mode is not %u: %u\n",
++ __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
++ return -EINVAL;
++ }
++
++ x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
++ calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
++ sizeof(struct ipv6_destopt_hao);
++ BUG_TRAP(x->props.header_len == 24);
++
++ return 0;
++}
++
++/*
++ * Do nothing about destroying since it has no specific operation for
++ * destination options header unlike IPsec protocols.
++ */
++static void mip6_destopt_destroy(struct xfrm_state *x)
++{
++}
++
++static struct xfrm_type mip6_destopt_type =
++{
++ .description = "MIP6DESTOPT",
++ .owner = THIS_MODULE,
++ .proto = IPPROTO_DSTOPTS,
++ .flags = XFRM_TYPE_NON_FRAGMENT,
++ .init_state = mip6_destopt_init_state,
++ .destructor = mip6_destopt_destroy,
++ .input = mip6_destopt_input,
++ .output = mip6_destopt_output,
++ .reject = mip6_destopt_reject,
++ .hdr_offset = mip6_destopt_offset,
++ .local_addr = mip6_xfrm_addr,
++};
++
++static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
++
++ if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) &&
++ !ipv6_addr_any((struct in6_addr *)x->coaddr))
++ return -ENOENT;
++
++ return rt2->rt_hdr.nexthdr;
++}
++
++/* Routing Header type 2 is inserted.
++ * IP Header's dst address is replaced with Routing Header's Home Address.
++ */
++static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct ipv6hdr *iph;
++ struct rt2_hdr *rt2;
++ u8 nexthdr;
++
++ iph = (struct ipv6hdr *)skb->data;
++ iph->payload_len = htons(skb->len - sizeof(*iph));
++
++ nexthdr = *skb->nh.raw;
++ *skb->nh.raw = IPPROTO_ROUTING;
++
++ rt2 = (struct rt2_hdr *)skb->h.raw;
++ rt2->rt_hdr.nexthdr = nexthdr;
++ rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
++ rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
++ rt2->rt_hdr.segments_left = 1;
++ memset(&rt2->reserved, 0, sizeof(rt2->reserved));
++
++ BUG_TRAP(rt2->rt_hdr.hdrlen == 2);
++
++ memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
++ memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
++
++ return 0;
++}
++
++static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
++ u8 **nexthdr)
++{
++ u16 offset = sizeof(struct ipv6hdr);
++ struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
++ unsigned int packet_len = skb->tail - skb->nh.raw;
++ int found_rhdr = 0;
++
++ *nexthdr = &skb->nh.ipv6h->nexthdr;
++
++ while (offset + 1 <= packet_len) {
++
++ switch (**nexthdr) {
++ case NEXTHDR_HOP:
++ break;
++ case NEXTHDR_ROUTING:
++ if (offset + 3 <= packet_len) {
++ struct ipv6_rt_hdr *rt;
++ rt = (struct ipv6_rt_hdr *)(skb->nh.raw + offset);
++ if (rt->type != 0)
++ return offset;
++ }
++ found_rhdr = 1;
++ break;
++ case NEXTHDR_DEST:
++ if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
++ return offset;
++
++ if (found_rhdr)
++ return offset;
++
++ break;
++ default:
++ return offset;
++ }
++
++ offset += ipv6_optlen(exthdr);
++ *nexthdr = &exthdr->nexthdr;
++ exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
++ }
++
++ return offset;
++}
++
++static int mip6_rthdr_init_state(struct xfrm_state *x)
++{
++ if (x->id.spi) {
++ printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
++ x->id.spi);
++ return -EINVAL;
++ }
++ if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
++ printk(KERN_INFO "%s: state's mode is not %u: %u\n",
++ __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
++ return -EINVAL;
++ }
++
++ x->props.header_len = sizeof(struct rt2_hdr);
++
++ return 0;
++}
++
++/*
++ * Do nothing about destroying since it has no specific operation for routing
++ * header type 2 unlike IPsec protocols.
++ */
++static void mip6_rthdr_destroy(struct xfrm_state *x)
++{
++}
++
++static struct xfrm_type mip6_rthdr_type =
++{
++ .description = "MIP6RT",
++ .owner = THIS_MODULE,
++ .proto = IPPROTO_ROUTING,
++ .flags = XFRM_TYPE_NON_FRAGMENT,
++ .init_state = mip6_rthdr_init_state,
++ .destructor = mip6_rthdr_destroy,
++ .input = mip6_rthdr_input,
++ .output = mip6_rthdr_output,
++ .hdr_offset = mip6_rthdr_offset,
++ .remote_addr = mip6_xfrm_addr,
++};
++
++int __init mip6_init(void)
++{
++ printk(KERN_INFO "Mobile IPv6\n");
++
++ if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
++ printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__);
++ goto mip6_destopt_xfrm_fail;
++ }
++ if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
++ printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__);
++ goto mip6_rthdr_xfrm_fail;
++ }
++ return 0;
++
++ mip6_rthdr_xfrm_fail:
++ xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
++ mip6_destopt_xfrm_fail:
++ return -EAGAIN;
++}
++
++void __exit mip6_fini(void)
++{
++ if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
++ printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__);
++ if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
++ printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__);
++}
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index b50055b..73eb8c3 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -62,6 +62,7 @@
+ #include <linux/sysctl.h>
+ #endif
+
++#include <linux/if_addr.h>
+ #include <linux/if_arp.h>
+ #include <linux/ipv6.h>
+ #include <linux/icmpv6.h>
+@@ -411,7 +412,8 @@ static void pndisc_destructor(struct pne
+ */
+
+ static inline void ndisc_flow_init(struct flowi *fl, u8 type,
+- struct in6_addr *saddr, struct in6_addr *daddr)
++ struct in6_addr *saddr, struct in6_addr *daddr,
++ int oif)
+ {
+ memset(fl, 0, sizeof(*fl));
+ ipv6_addr_copy(&fl->fl6_src, saddr);
+@@ -419,6 +421,8 @@ static inline void ndisc_flow_init(struc
+ fl->proto = IPPROTO_ICMPV6;
+ fl->fl_icmp_type = type;
+ fl->fl_icmp_code = 0;
++ fl->oif = oif;
++ security_sk_classify_flow(ndisc_socket->sk, fl);
+ }
+
+ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
+@@ -450,7 +454,8 @@ static void ndisc_send_na(struct net_dev
+ src_addr = &tmpaddr;
+ }
+
+- ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr);
++ ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr,
++ dev->ifindex);
+
+ dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
+ if (!dst)
+@@ -491,7 +496,7 @@ static void ndisc_send_na(struct net_dev
+ msg->icmph.icmp6_unused = 0;
+ msg->icmph.icmp6_router = router;
+ msg->icmph.icmp6_solicited = solicited;
+- msg->icmph.icmp6_override = !!override;
++ msg->icmph.icmp6_override = override;
+
+ /* Set the target address. */
+ ipv6_addr_copy(&msg->target, solicited_addr);
+@@ -540,7 +545,8 @@ void ndisc_send_ns(struct net_device *de
+ saddr = &addr_buf;
+ }
+
+- ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr);
++ ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr,
++ dev->ifindex);
+
+ dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
+ if (!dst)
+@@ -615,7 +621,8 @@ void ndisc_send_rs(struct net_device *de
+ int len;
+ int err;
+
+- ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr);
++ ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr,
++ dev->ifindex);
+
+ dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output);
+ if (!dst)
+@@ -729,8 +736,10 @@ static void ndisc_recv_ns(struct sk_buff
+ struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev = NULL;
+ struct neighbour *neigh;
++ struct pneigh_entry *pneigh = NULL;
+ int dad = ipv6_addr_any(saddr);
+ int inc;
++ int is_router;
+
+ if (ipv6_addr_is_multicast(&msg->target)) {
+ ND_PRINTK2(KERN_WARNING
+@@ -815,7 +824,9 @@ static void ndisc_recv_ns(struct sk_buff
+
+ if (ipv6_chk_acast_addr(dev, &msg->target) ||
+ (idev->cnf.forwarding &&
+- pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
++ (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
++ (pneigh = pneigh_lookup(&nd_tbl,
++ &msg->target, dev, 0)) != NULL)) {
+ if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
+ skb->pkt_type != PACKET_HOST &&
+ inc != 0 &&
+@@ -836,12 +847,14 @@ static void ndisc_recv_ns(struct sk_buff
+ goto out;
+ }
+
++ is_router = !!(pneigh ? pneigh->flags & NTF_ROUTER : idev->cnf.forwarding);
++
+ if (dad) {
+ struct in6_addr maddr;
+
+ ipv6_addr_all_nodes(&maddr);
+ ndisc_send_na(dev, NULL, &maddr, &msg->target,
+- idev->cnf.forwarding, 0, (ifp != NULL), 1);
++ is_router, 0, (ifp != NULL), 1);
+ goto out;
+ }
+
+@@ -862,7 +875,7 @@ static void ndisc_recv_ns(struct sk_buff
+ NEIGH_UPDATE_F_OVERRIDE);
+ if (neigh || !dev->hard_header) {
+ ndisc_send_na(dev, neigh, saddr, &msg->target,
+- idev->cnf.forwarding,
++ is_router,
+ 1, (ifp != NULL && inc), inc);
+ if (neigh)
+ neigh_release(neigh);
+@@ -945,6 +958,18 @@ static void ndisc_recv_na(struct sk_buff
+ if (neigh->nud_state & NUD_FAILED)
+ goto out;
+
++ /*
++ * Don't update the neighbor cache entry on a proxy NA from
++ * ourselves because either the proxied node is off link or it
++ * has already sent a NA to us.
++ */
++ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
++ ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
++ pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
++ /* XXX: idev->cnf.prixy_ndp */
++ goto out;
++ }
++
+ neigh_update(neigh, lladdr,
+ msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
+ NEIGH_UPDATE_F_WEAK_OVERRIDE|
+@@ -959,7 +984,7 @@ static void ndisc_recv_na(struct sk_buff
+ struct rt6_info *rt;
+ rt = rt6_get_dflt_router(saddr, dev);
+ if (rt)
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ }
+
+ out:
+@@ -1112,7 +1137,7 @@ static void ndisc_router_discovery(struc
+
+ if (rt && lifetime == 0) {
+ neigh_clone(neigh);
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ rt = NULL;
+ }
+
+@@ -1344,7 +1369,8 @@ static void ndisc_redirect_rcv(struct sk
+
+ neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
+ if (neigh) {
+- rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, lladdr,
++ rt6_redirect(dest, &skb->nh.ipv6h->daddr,
++ &skb->nh.ipv6h->saddr, neigh, lladdr,
+ on_link);
+ neigh_release(neigh);
+ }
+@@ -1380,7 +1406,8 @@ void ndisc_send_redirect(struct sk_buff
+ return;
+ }
+
+- ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr);
++ ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr,
++ dev->ifindex);
+
+ dst = ip6_route_output(NULL, &fl);
+ if (dst == NULL)
+@@ -1715,6 +1742,7 @@ int __init ndisc_init(struct net_proto_f
+
+ void ndisc_cleanup(void)
+ {
++ unregister_netdevice_notifier(&ndisc_netdev_notifier);
+ #ifdef CONFIG_SYSCTL
+ neigh_sysctl_unregister(&nd_tbl.parms);
+ #endif
+diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
+index 395a417..580b1ab 100644
+--- a/net/ipv6/netfilter.c
++++ b/net/ipv6/netfilter.c
+@@ -87,7 +87,7 @@ unsigned int nf_ip6_checksum(struct sk_b
+ unsigned int csum = 0;
+
+ switch (skb->ip_summed) {
+- case CHECKSUM_HW:
++ case CHECKSUM_COMPLETE:
+ if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN)
+ break;
+ if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
+index 4bc4e5b..d7c45a9 100644
+--- a/net/ipv6/netfilter/Kconfig
++++ b/net/ipv6/netfilter/Kconfig
+@@ -40,7 +40,7 @@ config IP6_NF_QUEUE
+ To compile it as a module, choose M here. If unsure, say N.
+
+ config IP6_NF_IPTABLES
+- tristate "IP6 tables support (required for filtering/masq/NAT)"
++ tristate "IP6 tables support (required for filtering)"
+ depends on NETFILTER_XTABLES
+ help
+ ip6tables is a general, extensible packet identification framework.
+diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
+index eeeb57d..ac1dfeb 100644
+--- a/net/ipv6/netfilter/Makefile
++++ b/net/ipv6/netfilter/Makefile
+@@ -5,7 +5,7 @@
+ # Link order matters here.
+ obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
+ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+-obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
++obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
+ obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
+ obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
+ obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
+diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
+index 968a14b..9510c24 100644
+--- a/net/ipv6/netfilter/ip6_queue.c
++++ b/net/ipv6/netfilter/ip6_queue.c
+@@ -56,15 +56,15 @@ struct ipq_queue_entry {
+
+ typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+-static unsigned char copy_mode = IPQ_COPY_NONE;
+-static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
++static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
++static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
+ static DEFINE_RWLOCK(queue_lock);
+-static int peer_pid;
+-static unsigned int copy_range;
++static int peer_pid __read_mostly;
++static unsigned int copy_range __read_mostly;
+ static unsigned int queue_total;
+ static unsigned int queue_dropped = 0;
+ static unsigned int queue_user_dropped = 0;
+-static struct sock *ipqnl;
++static struct sock *ipqnl __read_mostly;
+ static LIST_HEAD(queue_list);
+ static DEFINE_MUTEX(ipqnl_mutex);
+
+@@ -206,9 +206,9 @@ ipq_build_packet_message(struct ipq_queu
+ break;
+
+ case IPQ_COPY_PACKET:
+- if (entry->skb->ip_summed == CHECKSUM_HW &&
+- (*errp = skb_checksum_help(entry->skb,
+- entry->info->outdev == NULL))) {
++ if ((entry->skb->ip_summed == CHECKSUM_PARTIAL ||
++ entry->skb->ip_summed == CHECKSUM_COMPLETE) &&
++ (*errp = skb_checksum_help(entry->skb))) {
+ read_unlock_bh(&queue_lock);
+ return NULL;
+ }
+diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
+index c9d6b23..167c2ea 100644
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -70,9 +70,6 @@ do { \
+ #define IP_NF_ASSERT(x)
+ #endif
+
+-
+-#include <linux/netfilter_ipv4/listhelp.h>
+-
+ #if 0
+ /* All the better to debug you with... */
+ #define static
+@@ -114,7 +111,7 @@ ip6_packet_match(const struct sk_buff *s
+ const char *outdev,
+ const struct ip6t_ip6 *ip6info,
+ unsigned int *protoff,
+- int *fragoff)
++ int *fragoff, int *hotdrop)
+ {
+ size_t i;
+ unsigned long ret;
+@@ -172,9 +169,11 @@ ip6_packet_match(const struct sk_buff *s
+ unsigned short _frag_off;
+
+ protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
+- if (protohdr < 0)
++ if (protohdr < 0) {
++ if (_frag_off == 0)
++ *hotdrop = 1;
+ return 0;
+-
++ }
+ *fragoff = _frag_off;
+
+ dprintf("Packet protocol %hi ?= %s%hi.\n",
+@@ -220,8 +219,7 @@ ip6t_error(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ if (net_ratelimit())
+ printk("ip6_tables: error: `%s'\n", (char *)targinfo);
+@@ -258,8 +256,7 @@ ip6t_do_table(struct sk_buff **pskb,
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+- struct xt_table *table,
+- void *userdata)
++ struct xt_table *table)
+ {
+ static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
+ int offset = 0;
+@@ -295,7 +292,7 @@ ip6t_do_table(struct sk_buff **pskb,
+ IP_NF_ASSERT(e);
+ IP_NF_ASSERT(back);
+ if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
+- &protoff, &offset)) {
++ &protoff, &offset, &hotdrop)) {
+ struct ip6t_entry_target *t;
+
+ if (IP6T_MATCH_ITERATE(e, do_match,
+@@ -349,8 +346,7 @@ ip6t_do_table(struct sk_buff **pskb,
+ in, out,
+ hook,
+ t->u.kernel.target,
+- t->data,
+- userdata);
++ t->data);
+
+ #ifdef CONFIG_NETFILTER_DEBUG
+ if (((struct ip6t_entry *)table_base)->comefrom
+@@ -507,8 +503,7 @@ cleanup_match(struct ip6t_entry_match *m
+ return 1;
+
+ if (m->u.kernel.match->destroy)
+- m->u.kernel.match->destroy(m->u.kernel.match, m->data,
+- m->u.match_size - sizeof(*m));
++ m->u.kernel.match->destroy(m->u.kernel.match, m->data);
+ module_put(m->u.kernel.match->me);
+ return 0;
+ }
+@@ -561,7 +556,6 @@ check_match(struct ip6t_entry_match *m,
+
+ if (m->u.kernel.match->checkentry
+ && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
+- m->u.match_size - sizeof(*m),
+ hookmask)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ m->u.kernel.match->name);
+@@ -592,12 +586,19 @@ check_entry(struct ip6t_entry *e, const
+ return -EINVAL;
+ }
+
++ if (e->target_offset + sizeof(struct ip6t_entry_target) >
++ e->next_offset)
++ return -EINVAL;
++
+ j = 0;
+ ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
+ if (ret != 0)
+ goto cleanup_matches;
+
+ t = ip6t_get_target(e);
++ ret = -EINVAL;
++ if (e->target_offset + t->u.target_size > e->next_offset)
++ goto cleanup_matches;
+ target = try_then_request_module(xt_find_target(AF_INET6,
+ t->u.user.name,
+ t->u.user.revision),
+@@ -618,12 +619,10 @@ check_entry(struct ip6t_entry *e, const
+ if (t->u.kernel.target == &ip6t_standard_target) {
+ if (!standard_check(t, size)) {
+ ret = -EINVAL;
+- goto cleanup_matches;
++ goto err;
+ }
+ } else if (t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(name, e, target, t->data,
+- t->u.target_size
+- - sizeof(*t),
+ e->comefrom)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ t->u.kernel.target->name);
+@@ -695,8 +694,7 @@ cleanup_entry(struct ip6t_entry *e, unsi
+ IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
+ t = ip6t_get_target(e);
+ if (t->u.kernel.target->destroy)
+- t->u.kernel.target->destroy(t->u.kernel.target, t->data,
+- t->u.target_size - sizeof(*t));
++ t->u.kernel.target->destroy(t->u.kernel.target, t->data);
+ module_put(t->u.kernel.target->me);
+ return 0;
+ }
+@@ -760,19 +758,17 @@ translate_table(const char *name,
+ }
+ }
+
+- if (!mark_source_chains(newinfo, valid_hooks, entry0))
+- return -ELOOP;
+-
+ /* Finally, each sanity check must pass */
+ i = 0;
+ ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
+ check_entry, name, size, &i);
+
+- if (ret != 0) {
+- IP6T_ENTRY_ITERATE(entry0, newinfo->size,
+- cleanup_entry, &i);
+- return ret;
+- }
++ if (ret != 0)
++ goto cleanup;
++
++ ret = -ELOOP;
++ if (!mark_source_chains(newinfo, valid_hooks, entry0))
++ goto cleanup;
+
+ /* And one copy for every other CPU */
+ for_each_possible_cpu(i) {
+@@ -780,6 +776,9 @@ translate_table(const char *name,
+ memcpy(newinfo->entries[i], entry0, newinfo->size);
+ }
+
++ return 0;
++cleanup:
++ IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
+ return ret;
+ }
+
+@@ -1352,7 +1351,6 @@ icmp6_checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_icmp *icmpinfo = matchinfo;
+@@ -1450,6 +1448,9 @@ static void __exit ip6_tables_fini(void)
+ * If target header is found, its offset is set in *offset and return protocol
+ * number. Otherwise, return -1.
+ *
++ * If the first fragment doesn't contain the final protocol header or
++ * NEXTHDR_NONE it is considered invalid.
++ *
+ * Note that non-1st fragment is special case that "the protocol number
+ * of last header" is "next header" field in Fragment header. In this case,
+ * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
+@@ -1473,12 +1474,12 @@ int ipv6_find_hdr(const struct sk_buff *
+ if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
+ if (target < 0)
+ break;
+- return -1;
++ return -ENOENT;
+ }
+
+ hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
+- return -1;
++ return -EBADMSG;
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ unsigned short _frag_off, *fp;
+ fp = skb_header_pointer(skb,
+@@ -1487,7 +1488,7 @@ int ipv6_find_hdr(const struct sk_buff *
+ sizeof(_frag_off),
+ &_frag_off);
+ if (fp == NULL)
+- return -1;
++ return -EBADMSG;
+
+ _frag_off = ntohs(*fp) & ~0x7;
+ if (_frag_off) {
+@@ -1498,7 +1499,7 @@ int ipv6_find_hdr(const struct sk_buff *
+ *fragoff = _frag_off;
+ return hp->nexthdr;
+ }
+- return -1;
++ return -ENOENT;
+ }
+ hdrlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH)
+diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
+index b8eff8e..435750f 100644
+--- a/net/ipv6/netfilter/ip6t_HL.c
++++ b/net/ipv6/netfilter/ip6t_HL.c
+@@ -22,11 +22,10 @@ static unsigned int ip6t_hl_target(struc
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo, void *userinfo)
++ const void *targinfo)
+ {
+ struct ipv6hdr *ip6h;
+ const struct ip6t_HL_info *info = targinfo;
+- u_int16_t diffs[2];
+ int new_hl;
+
+ if (!skb_make_writable(pskb, (*pskb)->len))
+@@ -53,11 +52,8 @@ static unsigned int ip6t_hl_target(struc
+ break;
+ }
+
+- if (new_hl != ip6h->hop_limit) {
+- diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
++ if (new_hl != ip6h->hop_limit)
+ ip6h->hop_limit = new_hl;
+- diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
+- }
+
+ return IP6T_CONTINUE;
+ }
+@@ -66,7 +62,6 @@ static int ip6t_hl_checkentry(const char
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct ip6t_HL_info *info = targinfo;
+diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
+index 73c6300..0cf537d 100644
+--- a/net/ipv6/netfilter/ip6t_LOG.c
++++ b/net/ipv6/netfilter/ip6t_LOG.c
+@@ -427,8 +427,7 @@ ip6t_log_target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ip6t_log_info *loginfo = targinfo;
+ struct nf_loginfo li;
+@@ -452,7 +451,6 @@ static int ip6t_log_checkentry(const cha
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_log_info *loginfo = targinfo;
+diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
+index 8629ba1..311eae8 100644
+--- a/net/ipv6/netfilter/ip6t_REJECT.c
++++ b/net/ipv6/netfilter/ip6t_REJECT.c
+@@ -96,6 +96,7 @@ static void send_reset(struct sk_buff *o
+ ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
+ fl.fl_ip_sport = otcph.dest;
+ fl.fl_ip_dport = otcph.source;
++ security_skb_classify_flow(oldskb, &fl);
+ dst = ip6_route_output(NULL, &fl);
+ if (dst == NULL)
+ return;
+@@ -179,8 +180,7 @@ static unsigned int reject6_target(struc
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct ip6t_reject_info *reject = targinfo;
+
+@@ -223,7 +223,6 @@ static int check(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_reject_info *rejinfo = targinfo;
+@@ -256,9 +255,7 @@ static struct ip6t_target ip6t_reject_re
+
+ static int __init ip6t_reject_init(void)
+ {
+- if (ip6t_register_target(&ip6t_reject_reg))
+- return -EINVAL;
+- return 0;
++ return ip6t_register_target(&ip6t_reject_reg);
+ }
+
+ static void __exit ip6t_reject_fini(void)
+diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
+index 2f7bb20..4648664 100644
+--- a/net/ipv6/netfilter/ip6t_ah.c
++++ b/net/ipv6/netfilter/ip6t_ah.c
+@@ -54,9 +54,14 @@ match(const struct sk_buff *skb,
+ const struct ip6t_ah *ahinfo = matchinfo;
+ unsigned int ptr;
+ unsigned int hdrlen = 0;
++ int err;
+
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL) < 0)
++ err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
++ if (err < 0) {
++ if (err != -ENOENT)
++ *hotdrop = 1;
+ return 0;
++ }
+
+ ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
+ if (ah == NULL) {
+@@ -102,7 +107,6 @@ checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_ah *ahinfo = matchinfo;
+diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c
+deleted file mode 100644
+index 9422413..0000000
+--- a/net/ipv6/netfilter/ip6t_dst.c
++++ /dev/null
+@@ -1,220 +0,0 @@
+-/* Kernel module to match Hop-by-Hop and Destination parameters. */
+-
+-/* (C) 2001-2002 Andras Kis-Szabo <kisza at sch.bme.hu>
+- *
+- * 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/skbuff.h>
+-#include <linux/ipv6.h>
+-#include <linux/types.h>
+-#include <net/checksum.h>
+-#include <net/ipv6.h>
+-
+-#include <asm/byteorder.h>
+-
+-#include <linux/netfilter_ipv6/ip6_tables.h>
+-#include <linux/netfilter_ipv6/ip6t_opts.h>
+-
+-#define HOPBYHOP 0
+-
+-MODULE_LICENSE("GPL");
+-#if HOPBYHOP
+-MODULE_DESCRIPTION("IPv6 HbH match");
+-#else
+-MODULE_DESCRIPTION("IPv6 DST match");
+-#endif
+-MODULE_AUTHOR("Andras Kis-Szabo <kisza at sch.bme.hu>");
+-
+-#if 0
+-#define DEBUGP printk
+-#else
+-#define DEBUGP(format, args...)
+-#endif
+-
+-/*
+- * (Type & 0xC0) >> 6
+- * 0 -> ignorable
+- * 1 -> must drop the packet
+- * 2 -> send ICMP PARM PROB regardless and drop packet
+- * 3 -> Send ICMP if not a multicast address and drop packet
+- * (Type & 0x20) >> 5
+- * 0 -> invariant
+- * 1 -> can change the routing
+- * (Type & 0x1F) Type
+- * 0 -> Pad1 (only 1 byte!)
+- * 1 -> PadN LENGTH info (total length = length + 2)
+- * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
+- * 5 -> RTALERT 2 x x
+- */
+-
+-static int
+-match(const struct sk_buff *skb,
+- const struct net_device *in,
+- const struct net_device *out,
+- const struct xt_match *match,
+- const void *matchinfo,
+- int offset,
+- unsigned int protoff,
+- int *hotdrop)
+-{
+- struct ipv6_opt_hdr _optsh, *oh;
+- const struct ip6t_opts *optinfo = matchinfo;
+- unsigned int temp;
+- unsigned int ptr;
+- unsigned int hdrlen = 0;
+- unsigned int ret = 0;
+- u8 _opttype, *tp = NULL;
+- u8 _optlen, *lp = NULL;
+- unsigned int optlen;
+-
+-#if HOPBYHOP
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0)
+-#else
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0)
+-#endif
+- return 0;
+-
+- oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
+- if (oh == NULL) {
+- *hotdrop = 1;
+- return 0;
+- }
+-
+- hdrlen = ipv6_optlen(oh);
+- if (skb->len - ptr < hdrlen) {
+- /* Packet smaller than it's length field */
+- return 0;
+- }
+-
+- DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
+-
+- DEBUGP("len %02X %04X %02X ",
+- optinfo->hdrlen, hdrlen,
+- (!(optinfo->flags & IP6T_OPTS_LEN) ||
+- ((optinfo->hdrlen == hdrlen) ^
+- !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
+-
+- ret = (oh != NULL) &&
+- (!(optinfo->flags & IP6T_OPTS_LEN) ||
+- ((optinfo->hdrlen == hdrlen) ^
+- !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
+-
+- ptr += 2;
+- hdrlen -= 2;
+- if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
+- return ret;
+- } else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
+- DEBUGP("Not strict - not implemented");
+- } else {
+- DEBUGP("Strict ");
+- DEBUGP("#%d ", optinfo->optsnr);
+- for (temp = 0; temp < optinfo->optsnr; temp++) {
+- /* type field exists ? */
+- if (hdrlen < 1)
+- break;
+- tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
+- &_opttype);
+- if (tp == NULL)
+- break;
+-
+- /* Type check */
+- if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) {
+- DEBUGP("Tbad %02X %02X\n",
+- *tp,
+- (optinfo->opts[temp] & 0xFF00) >> 8);
+- return 0;
+- } else {
+- DEBUGP("Tok ");
+- }
+- /* Length check */
+- if (*tp) {
+- u16 spec_len;
+-
+- /* length field exists ? */
+- if (hdrlen < 2)
+- break;
+- lp = skb_header_pointer(skb, ptr + 1,
+- sizeof(_optlen),
+- &_optlen);
+- if (lp == NULL)
+- break;
+- spec_len = optinfo->opts[temp] & 0x00FF;
+-
+- if (spec_len != 0x00FF && spec_len != *lp) {
+- DEBUGP("Lbad %02X %04X\n", *lp,
+- spec_len);
+- return 0;
+- }
+- DEBUGP("Lok ");
+- optlen = *lp + 2;
+- } else {
+- DEBUGP("Pad1\n");
+- optlen = 1;
+- }
+-
+- /* Step to the next */
+- DEBUGP("len%04X \n", optlen);
+-
+- if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+- (temp < optinfo->optsnr - 1)) {
+- DEBUGP("new pointer is too large! \n");
+- break;
+- }
+- ptr += optlen;
+- hdrlen -= optlen;
+- }
+- if (temp == optinfo->optsnr)
+- return ret;
+- else
+- return 0;
+- }
+-
+- return 0;
+-}
+-
+-/* Called when user tries to insert an entry of this type. */
+-static int
+-checkentry(const char *tablename,
+- const void *info,
+- const struct xt_match *match,
+- void *matchinfo,
+- unsigned int matchinfosize,
+- unsigned int hook_mask)
+-{
+- const struct ip6t_opts *optsinfo = matchinfo;
+-
+- if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
+- DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
+- return 0;
+- }
+- return 1;
+-}
+-
+-static struct ip6t_match opts_match = {
+-#if HOPBYHOP
+- .name = "hbh",
+-#else
+- .name = "dst",
+-#endif
+- .match = match,
+- .matchsize = sizeof(struct ip6t_opts),
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
+-};
+-
+-static int __init ip6t_dst_init(void)
+-{
+- return ip6t_register_match(&opts_match);
+-}
+-
+-static void __exit ip6t_dst_fini(void)
+-{
+- ip6t_unregister_match(&opts_match);
+-}
+-
+-module_init(ip6t_dst_init);
+-module_exit(ip6t_dst_fini);
+diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
+index 06768c8..cd22eaa 100644
+--- a/net/ipv6/netfilter/ip6t_frag.c
++++ b/net/ipv6/netfilter/ip6t_frag.c
+@@ -52,9 +52,14 @@ match(const struct sk_buff *skb,
+ struct frag_hdr _frag, *fh;
+ const struct ip6t_frag *fraginfo = matchinfo;
+ unsigned int ptr;
++ int err;
+
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0)
++ err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
++ if (err < 0) {
++ if (err != -ENOENT)
++ *hotdrop = 1;
+ return 0;
++ }
+
+ fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
+ if (fh == NULL) {
+@@ -119,7 +124,6 @@ checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_frag *fraginfo = matchinfo;
+diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
+index 374f1be..3f25bab 100644
+--- a/net/ipv6/netfilter/ip6t_hbh.c
++++ b/net/ipv6/netfilter/ip6t_hbh.c
+@@ -19,15 +19,10 @@
+ #include <linux/netfilter_ipv6/ip6_tables.h>
+ #include <linux/netfilter_ipv6/ip6t_opts.h>
+
+-#define HOPBYHOP 1
+-
+ MODULE_LICENSE("GPL");
+-#if HOPBYHOP
+-MODULE_DESCRIPTION("IPv6 HbH match");
+-#else
+-MODULE_DESCRIPTION("IPv6 DST match");
+-#endif
++MODULE_DESCRIPTION("IPv6 opts match");
+ MODULE_AUTHOR("Andras Kis-Szabo <kisza at sch.bme.hu>");
++MODULE_ALIAS("ip6t_dst");
+
+ #if 0
+ #define DEBUGP printk
+@@ -70,13 +65,14 @@ match(const struct sk_buff *skb,
+ u8 _opttype, *tp = NULL;
+ u8 _optlen, *lp = NULL;
+ unsigned int optlen;
++ int err;
+
+-#if HOPBYHOP
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0)
+-#else
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0)
+-#endif
++ err = ipv6_find_hdr(skb, &ptr, match->data, NULL);
++ if (err < 0) {
++ if (err != -ENOENT)
++ *hotdrop = 1;
+ return 0;
++ }
+
+ oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
+ if (oh == NULL) {
+@@ -182,7 +178,6 @@ checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_opts *optsinfo = matchinfo;
+@@ -194,26 +189,35 @@ checkentry(const char *tablename,
+ return 1;
+ }
+
+-static struct ip6t_match opts_match = {
+-#if HOPBYHOP
+- .name = "hbh",
+-#else
+- .name = "dst",
+-#endif
+- .match = match,
+- .matchsize = sizeof(struct ip6t_opts),
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
++static struct xt_match opts_match[] = {
++ {
++ .name = "hbh",
++ .family = AF_INET6,
++ .match = match,
++ .matchsize = sizeof(struct ip6t_opts),
++ .checkentry = checkentry,
++ .me = THIS_MODULE,
++ .data = NEXTHDR_HOP,
++ },
++ {
++ .name = "dst",
++ .family = AF_INET6,
++ .match = match,
++ .matchsize = sizeof(struct ip6t_opts),
++ .checkentry = checkentry,
++ .me = THIS_MODULE,
++ .data = NEXTHDR_DEST,
++ },
+ };
+
+ static int __init ip6t_hbh_init(void)
+ {
+- return ip6t_register_match(&opts_match);
++ return xt_register_matches(opts_match, ARRAY_SIZE(opts_match));
+ }
+
+ static void __exit ip6t_hbh_fini(void)
+ {
+- ip6t_unregister_match(&opts_match);
++ xt_unregister_matches(opts_match, ARRAY_SIZE(opts_match));
+ }
+
+ module_init(ip6t_hbh_init);
+diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
+index 9375eeb..3093c39 100644
+--- a/net/ipv6/netfilter/ip6t_ipv6header.c
++++ b/net/ipv6/netfilter/ip6t_ipv6header.c
+@@ -128,7 +128,6 @@ ipv6header_checkentry(const char *tablen
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_ipv6header_info *info = matchinfo;
+diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
+index 5d04799..4eb9bbc 100644
+--- a/net/ipv6/netfilter/ip6t_owner.c
++++ b/net/ipv6/netfilter/ip6t_owner.c
+@@ -57,7 +57,6 @@ checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_owner_info *info = matchinfo;
+diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
+index fbb0184..54d7d14 100644
+--- a/net/ipv6/netfilter/ip6t_rt.c
++++ b/net/ipv6/netfilter/ip6t_rt.c
+@@ -58,9 +58,14 @@ match(const struct sk_buff *skb,
+ unsigned int hdrlen = 0;
+ unsigned int ret = 0;
+ struct in6_addr *ap, _addr;
++ int err;
+
+- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0)
++ err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
++ if (err < 0) {
++ if (err != -ENOENT)
++ *hotdrop = 1;
+ return 0;
++ }
+
+ rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
+ if (rh == NULL) {
+@@ -197,7 +202,6 @@ checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_rt *rtinfo = matchinfo;
+diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
+index 60976c0..2fc07c7 100644
+--- a/net/ipv6/netfilter/ip6table_filter.c
++++ b/net/ipv6/netfilter/ip6table_filter.c
+@@ -108,7 +108,7 @@ ip6t_hook(unsigned int hook,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return ip6t_do_table(pskb, hook, in, out, &packet_filter, NULL);
++ return ip6t_do_table(pskb, hook, in, out, &packet_filter);
+ }
+
+ static unsigned int
+@@ -128,7 +128,7 @@ ip6t_local_out_hook(unsigned int hook,
+ }
+ #endif
+
+- return ip6t_do_table(pskb, hook, in, out, &packet_filter, NULL);
++ return ip6t_do_table(pskb, hook, in, out, &packet_filter);
+ }
+
+ static struct nf_hook_ops ip6t_ops[] = {
+diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
+index 03a13ea..386ea26 100644
+--- a/net/ipv6/netfilter/ip6table_mangle.c
++++ b/net/ipv6/netfilter/ip6table_mangle.c
+@@ -138,7 +138,7 @@ ip6t_route_hook(unsigned int hook,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
++ return ip6t_do_table(pskb, hook, in, out, &packet_mangler);
+ }
+
+ static unsigned int
+@@ -174,18 +174,14 @@ ip6t_local_hook(unsigned int hook,
+ /* flowlabel and prio (includes version, which shouldn't change either */
+ flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
+
+- ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
++ ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler);
+
+ if (ret != NF_DROP && ret != NF_STOLEN
+ && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr))
+ || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr))
+ || (*pskb)->nfmark != nfmark
+- || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) {
+-
+- /* something which could affect routing has changed */
+-
+- DEBUGP("ip6table_mangle: we'd need to re-route a packet\n");
+- }
++ || (*pskb)->nh.ipv6h->hop_limit != hop_limit))
++ return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+
+ return ret;
+ }
+diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
+index 61a7c58..b4154da 100644
+--- a/net/ipv6/netfilter/ip6table_raw.c
++++ b/net/ipv6/netfilter/ip6table_raw.c
+@@ -122,7 +122,7 @@ ip6t_hook(unsigned int hook,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
++ return ip6t_do_table(pskb, hook, in, out, &packet_raw);
+ }
+
+ static struct nf_hook_ops ip6t_ops[] = {
+diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+index c2ab38f..e5e53ff 100644
+--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
++++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+@@ -335,7 +335,7 @@ static struct nf_hook_ops ipv6_conntrack
+ /* From nf_conntrack_proto_icmpv6.c */
+ extern unsigned int nf_ct_icmpv6_timeout;
+
+-/* From nf_conntrack_frag6.c */
++/* From nf_conntrack_reasm.c */
+ extern unsigned int nf_ct_frag6_timeout;
+ extern unsigned int nf_ct_frag6_low_thresh;
+ extern unsigned int nf_ct_frag6_high_thresh;
+diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+index ef18a7b..34d4472 100644
+--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
++++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+@@ -33,7 +33,7 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
+
+-unsigned long nf_ct_icmpv6_timeout = 30*HZ;
++unsigned long nf_ct_icmpv6_timeout __read_mostly = 30*HZ;
+
+ #if 0
+ #define DEBUGP printk
+diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
+index 00d5583..bf93c1e 100644
+--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
+@@ -54,9 +54,9 @@
+ #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */
+ #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
+
+-unsigned int nf_ct_frag6_high_thresh = 256*1024;
+-unsigned int nf_ct_frag6_low_thresh = 192*1024;
+-unsigned long nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT;
++unsigned int nf_ct_frag6_high_thresh __read_mostly = 256*1024;
++unsigned int nf_ct_frag6_low_thresh __read_mostly = 192*1024;
++unsigned long nf_ct_frag6_timeout __read_mostly = IPV6_FRAG_TIMEOUT;
+
+ struct nf_ct_frag6_skb_cb
+ {
+@@ -408,7 +408,7 @@ static int nf_ct_frag6_queue(struct nf_c
+ return -1;
+ }
+
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_sub(skb->csum,
+ csum_partial(skb->nh.raw,
+ (u8*)(fhdr + 1) - skb->nh.raw,
+@@ -640,7 +640,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
+ head->len += fp->len;
+ if (head->ip_summed != fp->ip_summed)
+ head->ip_summed = CHECKSUM_NONE;
+- else if (head->ip_summed == CHECKSUM_HW)
++ else if (head->ip_summed == CHECKSUM_COMPLETE)
+ head->csum = csum_add(head->csum, fp->csum);
+ head->truesize += fp->truesize;
+ atomic_sub(fp->truesize, &nf_ct_frag6_mem);
+@@ -652,7 +652,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
+ head->nh.ipv6h->payload_len = htons(payload_len);
+
+ /* Yes, and fold redundant checksum back. 8) */
+- if (head->ip_summed == CHECKSUM_HW)
++ if (head->ip_summed == CHECKSUM_COMPLETE)
+ head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+
+ fq->fragments = NULL;
+diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
+index 15b862d..d6dedc4 100644
+--- a/net/ipv6/raw.c
++++ b/net/ipv6/raw.c
+@@ -50,6 +50,9 @@
+ #include <net/udp.h>
+ #include <net/inet_common.h>
+ #include <net/tcp_states.h>
++#ifdef CONFIG_IPV6_MIP6
++#include <net/mip6.h>
++#endif
+
+ #include <net/rawv6.h>
+ #include <net/xfrm.h>
+@@ -169,8 +172,32 @@ int ipv6_raw_deliver(struct sk_buff *skb
+ sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
+
+ while (sk) {
++ int filtered;
++
+ delivered = 1;
+- if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
++ switch (nexthdr) {
++ case IPPROTO_ICMPV6:
++ filtered = icmpv6_filter(sk, skb);
++ break;
++#ifdef CONFIG_IPV6_MIP6
++ case IPPROTO_MH:
++ /* XXX: To validate MH only once for each packet,
++ * this is placed here. It should be after checking
++ * xfrm policy, however it doesn't. The checking xfrm
++ * policy is placed in rawv6_rcv() because it is
++ * required for each socket.
++ */
++ filtered = mip6_mh_filter(sk, skb);
++ break;
++#endif
++ default:
++ filtered = 0;
++ break;
++ }
++
++ if (filtered < 0)
++ break;
++ if (filtered == 0) {
+ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
+
+ /* Not releasing hash table! */
+@@ -334,7 +361,7 @@ int rawv6_rcv(struct sock *sk, struct sk
+ if (!rp->checksum)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ skb_postpull_rcsum(skb, skb->nh.raw,
+ skb->h.raw - skb->nh.raw);
+ if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+@@ -577,16 +604,19 @@ error:
+ return err;
+ }
+
+-static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
++static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
+ {
+ struct iovec *iov;
+ u8 __user *type = NULL;
+ u8 __user *code = NULL;
++#ifdef CONFIG_IPV6_MIP6
++ u8 len = 0;
++#endif
+ int probed = 0;
+ int i;
+
+ if (!msg->msg_iov)
+- return;
++ return 0;
+
+ for (i = 0; i < msg->msg_iovlen; i++) {
+ iov = &msg->msg_iov[i];
+@@ -608,11 +638,27 @@ static void rawv6_probe_proto_opt(struct
+ code = iov->iov_base;
+
+ if (type && code) {
+- get_user(fl->fl_icmp_type, type);
+- get_user(fl->fl_icmp_code, code);
++ if (get_user(fl->fl_icmp_type, type) ||
++ get_user(fl->fl_icmp_code, code))
++ return -EFAULT;
+ probed = 1;
+ }
+ break;
++#ifdef CONFIG_IPV6_MIP6
++ case IPPROTO_MH:
++ if (iov->iov_base && iov->iov_len < 1)
++ break;
++ /* check if type field is readable or not. */
++ if (iov->iov_len > 2 - len) {
++ u8 __user *p = iov->iov_base;
++ if (get_user(fl->fl_mh_type, &p[2 - len]))
++ return -EFAULT;
++ probed = 1;
++ } else
++ len += iov->iov_len;
++
++ break;
++#endif
+ default:
+ probed = 1;
+ break;
+@@ -620,6 +666,7 @@ static void rawv6_probe_proto_opt(struct
+ if (probed)
+ break;
+ }
++ return 0;
+ }
+
+ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+@@ -743,7 +790,9 @@ static int rawv6_sendmsg(struct kiocb *i
+ opt = ipv6_fixup_options(&opt_space, opt);
+
+ fl.proto = proto;
+- rawv6_probe_proto_opt(&fl, msg);
++ err = rawv6_probe_proto_opt(&fl, msg);
++ if (err)
++ goto out;
+
+ ipv6_addr_copy(&fl.fl6_dst, daddr);
+ if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
+@@ -759,6 +808,7 @@ static int rawv6_sendmsg(struct kiocb *i
+
+ if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
+ fl.oif = np->mcast_oif;
++ security_sk_classify_flow(sk, &fl);
+
+ err = ip6_dst_lookup(sk, &dst, &fl);
+ if (err)
+diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
+index 4e299c6..f39bbed 100644
+--- a/net/ipv6/reassembly.c
++++ b/net/ipv6/reassembly.c
+@@ -53,10 +53,10 @@
+ #include <net/ndisc.h>
+ #include <net/addrconf.h>
+
+-int sysctl_ip6frag_high_thresh = 256*1024;
+-int sysctl_ip6frag_low_thresh = 192*1024;
++int sysctl_ip6frag_high_thresh __read_mostly = 256*1024;
++int sysctl_ip6frag_low_thresh __read_mostly = 192*1024;
+
+-int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT;
++int sysctl_ip6frag_time __read_mostly = IPV6_FRAG_TIMEOUT;
+
+ struct ip6frag_skb_cb
+ {
+@@ -152,7 +152,7 @@ static unsigned int ip6qhashfn(u32 id, s
+ }
+
+ static struct timer_list ip6_frag_secret_timer;
+-int sysctl_ip6frag_secret_interval = 10 * 60 * HZ;
++int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ;
+
+ static void ip6_frag_secret_rebuild(unsigned long dummy)
+ {
+@@ -433,7 +433,7 @@ static void ip6_frag_queue(struct frag_q
+ return;
+ }
+
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_sub(skb->csum,
+ csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
+
+@@ -647,7 +647,7 @@ static int ip6_frag_reasm(struct frag_qu
+ head->len += fp->len;
+ if (head->ip_summed != fp->ip_summed)
+ head->ip_summed = CHECKSUM_NONE;
+- else if (head->ip_summed == CHECKSUM_HW)
++ else if (head->ip_summed == CHECKSUM_COMPLETE)
+ head->csum = csum_add(head->csum, fp->csum);
+ head->truesize += fp->truesize;
+ atomic_sub(fp->truesize, &ip6_frag_mem);
+@@ -662,7 +662,7 @@ static int ip6_frag_reasm(struct frag_qu
+ *skb_in = head;
+
+ /* Yes, and fold redundant checksum back. 8) */
+- if (head->ip_summed == CHECKSUM_HW)
++ if (head->ip_summed == CHECKSUM_COMPLETE)
+ head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index d9baca0..c953466 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -22,6 +22,8 @@
+ * routers in REACHABLE, STALE, DELAY or PROBE states).
+ * - always select the same router if it is (probably)
+ * reachable. otherwise, round-robin the list.
++ * Ville Nuorvala
++ * Fixed routing subtrees.
+ */
+
+ #include <linux/capability.h>
+@@ -35,7 +37,6 @@
+ #include <linux/netdevice.h>
+ #include <linux/in6.h>
+ #include <linux/init.h>
+-#include <linux/netlink.h>
+ #include <linux/if_arp.h>
+
+ #ifdef CONFIG_PROC_FS
+@@ -54,6 +55,7 @@
+ #include <net/dst.h>
+ #include <net/xfrm.h>
+ #include <net/netevent.h>
++#include <net/netlink.h>
+
+ #include <asm/uaccess.h>
+
+@@ -74,9 +76,6 @@
+
+ #define CLONE_OFFLINK_ROUTE 0
+
+-#define RT6_SELECT_F_IFACE 0x1
+-#define RT6_SELECT_F_REACHABLE 0x2
+-
+ static int ip6_rt_max_size = 4096;
+ static int ip6_rt_gc_min_interval = HZ / 2;
+ static int ip6_rt_gc_timeout = 60*HZ;
+@@ -140,15 +139,53 @@ struct rt6_info ip6_null_entry = {
+ .rt6i_ref = ATOMIC_INIT(1),
+ };
+
+-struct fib6_node ip6_routing_table = {
+- .leaf = &ip6_null_entry,
+- .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
+-};
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+
+-/* Protects all the ip6 fib */
++static int ip6_pkt_prohibit(struct sk_buff *skb);
++static int ip6_pkt_prohibit_out(struct sk_buff *skb);
++static int ip6_pkt_blk_hole(struct sk_buff *skb);
+
+-DEFINE_RWLOCK(rt6_lock);
++struct rt6_info ip6_prohibit_entry = {
++ .u = {
++ .dst = {
++ .__refcnt = ATOMIC_INIT(1),
++ .__use = 1,
++ .dev = &loopback_dev,
++ .obsolete = -1,
++ .error = -EACCES,
++ .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
++ .input = ip6_pkt_prohibit,
++ .output = ip6_pkt_prohibit_out,
++ .ops = &ip6_dst_ops,
++ .path = (struct dst_entry*)&ip6_prohibit_entry,
++ }
++ },
++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
++ .rt6i_metric = ~(u32) 0,
++ .rt6i_ref = ATOMIC_INIT(1),
++};
++
++struct rt6_info ip6_blk_hole_entry = {
++ .u = {
++ .dst = {
++ .__refcnt = ATOMIC_INIT(1),
++ .__use = 1,
++ .dev = &loopback_dev,
++ .obsolete = -1,
++ .error = -EINVAL,
++ .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
++ .input = ip6_pkt_blk_hole,
++ .output = ip6_pkt_blk_hole,
++ .ops = &ip6_dst_ops,
++ .path = (struct dst_entry*)&ip6_blk_hole_entry,
++ }
++ },
++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
++ .rt6i_metric = ~(u32) 0,
++ .rt6i_ref = ATOMIC_INIT(1),
++};
+
++#endif
+
+ /* allocate dst with ip6_dst_ops */
+ static __inline__ struct rt6_info *ip6_dst_alloc(void)
+@@ -188,8 +225,14 @@ static __inline__ int rt6_check_expired(
+ time_after(jiffies, rt->rt6i_expires));
+ }
+
++static inline int rt6_need_strict(struct in6_addr *daddr)
++{
++ return (ipv6_addr_type(daddr) &
++ (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
++}
++
+ /*
+- * Route lookup. Any rt6_lock is implied.
++ * Route lookup. Any table->tb6_lock is implied.
+ */
+
+ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
+@@ -298,7 +341,7 @@ static int rt6_score_route(struct rt6_in
+ int m, n;
+
+ m = rt6_check_dev(rt, oif);
+- if (!m && (strict & RT6_SELECT_F_IFACE))
++ if (!m && (strict & RT6_LOOKUP_F_IFACE))
+ return -1;
+ #ifdef CONFIG_IPV6_ROUTER_PREF
+ m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
+@@ -306,7 +349,7 @@ static int rt6_score_route(struct rt6_in
+ n = rt6_check_neigh(rt);
+ if (n > 1)
+ m |= 16;
+- else if (!n && strict & RT6_SELECT_F_REACHABLE)
++ else if (!n && strict & RT6_LOOKUP_F_REACHABLE)
+ return -1;
+ return m;
+ }
+@@ -346,7 +389,7 @@ static struct rt6_info *rt6_select(struc
+ }
+
+ if (!match &&
+- (strict & RT6_SELECT_F_REACHABLE) &&
++ (strict & RT6_LOOKUP_F_REACHABLE) &&
+ last && last != rt0) {
+ /* no entries matched; do round-robin */
+ static DEFINE_SPINLOCK(lock);
+@@ -417,7 +460,7 @@ int rt6_route_rcv(struct net_device *dev
+ rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex);
+
+ if (rt && !lifetime) {
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ rt = NULL;
+ }
+
+@@ -441,44 +484,99 @@ int rt6_route_rcv(struct net_device *dev
+ }
+ #endif
+
+-struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
+- int oif, int strict)
++#define BACKTRACK(saddr) \
++do { \
++ if (rt == &ip6_null_entry) { \
++ struct fib6_node *pn; \
++ while (1) { \
++ if (fn->fn_flags & RTN_TL_ROOT) \
++ goto out; \
++ pn = fn->parent; \
++ if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
++ fn = fib6_lookup(pn->subtree, NULL, saddr); \
++ else \
++ fn = pn; \
++ if (fn->fn_flags & RTN_RTINFO) \
++ goto restart; \
++ } \
++ } \
++} while(0)
++
++static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
++ struct flowi *fl, int flags)
+ {
+ struct fib6_node *fn;
+ struct rt6_info *rt;
+
+- read_lock_bh(&rt6_lock);
+- fn = fib6_lookup(&ip6_routing_table, daddr, saddr);
+- rt = rt6_device_match(fn->leaf, oif, strict);
++ read_lock_bh(&table->tb6_lock);
++ fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
++restart:
++ rt = fn->leaf;
++ rt = rt6_device_match(rt, fl->oif, flags);
++ BACKTRACK(&fl->fl6_src);
++out:
+ dst_hold(&rt->u.dst);
+- rt->u.dst.__use++;
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+
+ rt->u.dst.lastuse = jiffies;
+- if (rt->u.dst.error == 0)
+- return rt;
+- dst_release(&rt->u.dst);
++ rt->u.dst.__use++;
++
++ return rt;
++
++}
++
++struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
++ int oif, int strict)
++{
++ struct flowi fl = {
++ .oif = oif,
++ .nl_u = {
++ .ip6_u = {
++ .daddr = *daddr,
++ },
++ },
++ };
++ struct dst_entry *dst;
++ int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
++
++ if (saddr) {
++ memcpy(&fl.fl6_src, saddr, sizeof(*saddr));
++ flags |= RT6_LOOKUP_F_HAS_SADDR;
++ }
++
++ dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
++ if (dst->error == 0)
++ return (struct rt6_info *) dst;
++
++ dst_release(dst);
++
+ return NULL;
+ }
+
+-/* ip6_ins_rt is called with FREE rt6_lock.
++/* ip6_ins_rt is called with FREE table->tb6_lock.
+ It takes new route entry, the addition fails by any reason the
+ route is freed. In any case, if caller does not hold it, it may
+ be destroyed.
+ */
+
+-int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh,
+- void *_rtattr, struct netlink_skb_parms *req)
++static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
+ {
+ int err;
++ struct fib6_table *table;
+
+- write_lock_bh(&rt6_lock);
+- err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, req);
+- write_unlock_bh(&rt6_lock);
++ table = rt->rt6i_table;
++ write_lock_bh(&table->tb6_lock);
++ err = fib6_add(&table->tb6_root, rt, info);
++ write_unlock_bh(&table->tb6_lock);
+
+ return err;
+ }
+
++int ip6_ins_rt(struct rt6_info *rt)
++{
++ return __ip6_ins_rt(rt, NULL);
++}
++
+ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr,
+ struct in6_addr *saddr)
+ {
+@@ -524,59 +622,45 @@ static struct rt6_info *rt6_alloc_clone(
+ ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
+ rt->rt6i_dst.plen = 128;
+ rt->rt6i_flags |= RTF_CACHE;
+- if (rt->rt6i_flags & RTF_REJECT)
+- rt->u.dst.error = ort->u.dst.error;
+ rt->u.dst.flags |= DST_HOST;
+ rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
+ }
+ return rt;
+ }
+
+-#define BACKTRACK() \
+-if (rt == &ip6_null_entry) { \
+- while ((fn = fn->parent) != NULL) { \
+- if (fn->fn_flags & RTN_ROOT) { \
+- goto out; \
+- } \
+- if (fn->fn_flags & RTN_RTINFO) \
+- goto restart; \
+- } \
+-}
+-
+-
+-void ip6_route_input(struct sk_buff *skb)
++static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
++ struct flowi *fl, int flags)
+ {
+ struct fib6_node *fn;
+ struct rt6_info *rt, *nrt;
+- int strict;
++ int strict = 0;
+ int attempts = 3;
+ int err;
+- int reachable = RT6_SELECT_F_REACHABLE;
++ int reachable = RT6_LOOKUP_F_REACHABLE;
+
+- strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
++ strict |= flags & RT6_LOOKUP_F_IFACE;
+
+ relookup:
+- read_lock_bh(&rt6_lock);
++ read_lock_bh(&table->tb6_lock);
+
+ restart_2:
+- fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
+- &skb->nh.ipv6h->saddr);
++ fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
+
+ restart:
+- rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable);
+- BACKTRACK();
++ rt = rt6_select(&fn->leaf, fl->iif, strict | reachable);
++ BACKTRACK(&fl->fl6_src);
+ if (rt == &ip6_null_entry ||
+ rt->rt6i_flags & RTF_CACHE)
+ goto out;
+
+ dst_hold(&rt->u.dst);
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+
+ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+- nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr);
++ nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
+ else {
+ #if CLONE_OFFLINK_ROUTE
+- nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr);
++ nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
+ #else
+ goto out2;
+ #endif
+@@ -587,7 +671,7 @@ restart:
+
+ dst_hold(&rt->u.dst);
+ if (nrt) {
+- err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb));
++ err = ip6_ins_rt(nrt);
+ if (!err)
+ goto out2;
+ }
+@@ -596,7 +680,7 @@ restart:
+ goto out2;
+
+ /*
+- * Race condition! In the gap, when rt6_lock was
++ * Race condition! In the gap, when table->tb6_lock was
+ * released someone could insert this route. Relookup.
+ */
+ dst_release(&rt->u.dst);
+@@ -608,40 +692,66 @@ out:
+ goto restart_2;
+ }
+ dst_hold(&rt->u.dst);
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+ out2:
+ rt->u.dst.lastuse = jiffies;
+ rt->u.dst.__use++;
+- skb->dst = (struct dst_entry *) rt;
+- return;
++
++ return rt;
+ }
+
+-struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
++void ip6_route_input(struct sk_buff *skb)
++{
++ struct ipv6hdr *iph = skb->nh.ipv6h;
++ int flags = RT6_LOOKUP_F_HAS_SADDR;
++ struct flowi fl = {
++ .iif = skb->dev->ifindex,
++ .nl_u = {
++ .ip6_u = {
++ .daddr = iph->daddr,
++ .saddr = iph->saddr,
++#ifdef CONFIG_IPV6_ROUTE_FWMARK
++ .fwmark = skb->nfmark,
++#endif
++ .flowlabel = (* (u32 *) iph)&IPV6_FLOWINFO_MASK,
++ },
++ },
++ .proto = iph->nexthdr,
++ };
++
++ if (rt6_need_strict(&iph->daddr))
++ flags |= RT6_LOOKUP_F_IFACE;
++
++ skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
++}
++
++static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
++ struct flowi *fl, int flags)
+ {
+ struct fib6_node *fn;
+ struct rt6_info *rt, *nrt;
+- int strict;
++ int strict = 0;
+ int attempts = 3;
+ int err;
+- int reachable = RT6_SELECT_F_REACHABLE;
++ int reachable = RT6_LOOKUP_F_REACHABLE;
+
+- strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
++ strict |= flags & RT6_LOOKUP_F_IFACE;
+
+ relookup:
+- read_lock_bh(&rt6_lock);
++ read_lock_bh(&table->tb6_lock);
+
+ restart_2:
+- fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src);
++ fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
+
+ restart:
+ rt = rt6_select(&fn->leaf, fl->oif, strict | reachable);
+- BACKTRACK();
++ BACKTRACK(&fl->fl6_src);
+ if (rt == &ip6_null_entry ||
+ rt->rt6i_flags & RTF_CACHE)
+ goto out;
+
+ dst_hold(&rt->u.dst);
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+
+ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+ nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
+@@ -658,7 +768,7 @@ restart:
+
+ dst_hold(&rt->u.dst);
+ if (nrt) {
+- err = ip6_ins_rt(nrt, NULL, NULL, NULL);
++ err = ip6_ins_rt(nrt);
+ if (!err)
+ goto out2;
+ }
+@@ -667,7 +777,7 @@ restart:
+ goto out2;
+
+ /*
+- * Race condition! In the gap, when rt6_lock was
++ * Race condition! In the gap, when table->tb6_lock was
+ * released someone could insert this route. Relookup.
+ */
+ dst_release(&rt->u.dst);
+@@ -679,11 +789,24 @@ out:
+ goto restart_2;
+ }
+ dst_hold(&rt->u.dst);
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+ out2:
+ rt->u.dst.lastuse = jiffies;
+ rt->u.dst.__use++;
+- return &rt->u.dst;
++ return rt;
++}
++
++struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
++{
++ int flags = 0;
++
++ if (rt6_need_strict(&fl->fl6_dst))
++ flags |= RT6_LOOKUP_F_IFACE;
++
++ if (!ipv6_addr_any(&fl->fl6_src))
++ flags |= RT6_LOOKUP_F_HAS_SADDR;
++
++ return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
+ }
+
+
+@@ -709,7 +832,7 @@ static struct dst_entry *ip6_negative_ad
+
+ if (rt) {
+ if (rt->rt6i_flags & RTF_CACHE)
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ else
+ dst_release(dst);
+ }
+@@ -747,8 +870,6 @@ static void ip6_rt_update_pmtu(struct ds
+ }
+ }
+
+-/* Protected by rt6_lock. */
+-static struct dst_entry *ndisc_dst_gc_list;
+ static int ipv6_get_mtu(struct net_device *dev);
+
+ static inline unsigned int ipv6_advmss(unsigned int mtu)
+@@ -769,6 +890,9 @@ static inline unsigned int ipv6_advmss(u
+ return mtu;
+ }
+
++static struct dst_entry *ndisc_dst_gc_list;
++static DEFINE_SPINLOCK(ndisc_lock);
++
+ struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
+ struct neighbour *neigh,
+ struct in6_addr *addr,
+@@ -809,10 +933,10 @@ struct dst_entry *ndisc_dst_alloc(struct
+ rt->rt6i_dst.plen = 128;
+ #endif
+
+- write_lock_bh(&rt6_lock);
++ spin_lock_bh(&ndisc_lock);
+ rt->u.dst.next = ndisc_dst_gc_list;
+ ndisc_dst_gc_list = &rt->u.dst;
+- write_unlock_bh(&rt6_lock);
++ spin_unlock_bh(&ndisc_lock);
+
+ fib6_force_start_gc();
+
+@@ -826,8 +950,11 @@ int ndisc_dst_gc(int *more)
+ int freed;
+
+ next = NULL;
++ freed = 0;
++
++ spin_lock_bh(&ndisc_lock);
+ pprev = &ndisc_dst_gc_list;
+- freed = 0;
++
+ while ((dst = *pprev) != NULL) {
+ if (!atomic_read(&dst->__refcnt)) {
+ *pprev = dst->next;
+@@ -839,6 +966,8 @@ int ndisc_dst_gc(int *more)
+ }
+ }
+
++ spin_unlock_bh(&ndisc_lock);
++
+ return freed;
+ }
+
+@@ -899,28 +1028,24 @@ int ipv6_get_hoplimit(struct net_device
+ *
+ */
+
+-int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh,
+- void *_rtattr, struct netlink_skb_parms *req)
++int ip6_route_add(struct fib6_config *cfg)
+ {
+ int err;
+- struct rtmsg *r;
+- struct rtattr **rta;
+ struct rt6_info *rt = NULL;
+ struct net_device *dev = NULL;
+ struct inet6_dev *idev = NULL;
++ struct fib6_table *table;
+ int addr_type;
+
+- rta = (struct rtattr **) _rtattr;
+-
+- if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128)
++ if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
+ return -EINVAL;
+ #ifndef CONFIG_IPV6_SUBTREES
+- if (rtmsg->rtmsg_src_len)
++ if (cfg->fc_src_len)
+ return -EINVAL;
+ #endif
+- if (rtmsg->rtmsg_ifindex) {
++ if (cfg->fc_ifindex) {
+ err = -ENODEV;
+- dev = dev_get_by_index(rtmsg->rtmsg_ifindex);
++ dev = dev_get_by_index(cfg->fc_ifindex);
+ if (!dev)
+ goto out;
+ idev = in6_dev_get(dev);
+@@ -928,8 +1053,14 @@ int ip6_route_add(struct in6_rtmsg *rtms
+ goto out;
+ }
+
+- if (rtmsg->rtmsg_metric == 0)
+- rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;
++ if (cfg->fc_metric == 0)
++ cfg->fc_metric = IP6_RT_PRIO_USER;
++
++ table = fib6_new_table(cfg->fc_table);
++ if (table == NULL) {
++ err = -ENOBUFS;
++ goto out;
++ }
+
+ rt = ip6_dst_alloc();
+
+@@ -939,14 +1070,13 @@ int ip6_route_add(struct in6_rtmsg *rtms
+ }
+
+ rt->u.dst.obsolete = -1;
+- rt->rt6i_expires = jiffies + clock_t_to_jiffies(rtmsg->rtmsg_info);
+- if (nlh && (r = NLMSG_DATA(nlh))) {
+- rt->rt6i_protocol = r->rtm_protocol;
+- } else {
+- rt->rt6i_protocol = RTPROT_BOOT;
+- }
++ rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires);
++
++ if (cfg->fc_protocol == RTPROT_UNSPEC)
++ cfg->fc_protocol = RTPROT_BOOT;
++ rt->rt6i_protocol = cfg->fc_protocol;
+
+- addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);
++ addr_type = ipv6_addr_type(&cfg->fc_dst);
+
+ if (addr_type & IPV6_ADDR_MULTICAST)
+ rt->u.dst.input = ip6_mc_input;
+@@ -955,24 +1085,22 @@ int ip6_route_add(struct in6_rtmsg *rtms
+
+ rt->u.dst.output = ip6_output;
+
+- ipv6_addr_prefix(&rt->rt6i_dst.addr,
+- &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len);
+- rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;
++ ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
++ rt->rt6i_dst.plen = cfg->fc_dst_len;
+ if (rt->rt6i_dst.plen == 128)
+ rt->u.dst.flags = DST_HOST;
+
+ #ifdef CONFIG_IPV6_SUBTREES
+- ipv6_addr_prefix(&rt->rt6i_src.addr,
+- &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);
+- rt->rt6i_src.plen = rtmsg->rtmsg_src_len;
++ ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
++ rt->rt6i_src.plen = cfg->fc_src_len;
+ #endif
+
+- rt->rt6i_metric = rtmsg->rtmsg_metric;
++ rt->rt6i_metric = cfg->fc_metric;
+
+ /* We cannot add true routes via loopback here,
+ they would result in kernel looping; promote them to reject routes
+ */
+- if ((rtmsg->rtmsg_flags&RTF_REJECT) ||
++ if ((cfg->fc_flags & RTF_REJECT) ||
+ (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
+ /* hold loopback dev/idev if we haven't done so. */
+ if (dev != &loopback_dev) {
+@@ -995,12 +1123,12 @@ int ip6_route_add(struct in6_rtmsg *rtms
+ goto install_route;
+ }
+
+- if (rtmsg->rtmsg_flags & RTF_GATEWAY) {
++ if (cfg->fc_flags & RTF_GATEWAY) {
+ struct in6_addr *gw_addr;
+ int gwa_type;
+
+- gw_addr = &rtmsg->rtmsg_gateway;
+- ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway);
++ gw_addr = &cfg->fc_gateway;
++ ipv6_addr_copy(&rt->rt6i_gateway, gw_addr);
+ gwa_type = ipv6_addr_type(gw_addr);
+
+ if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
+@@ -1017,7 +1145,7 @@ int ip6_route_add(struct in6_rtmsg *rtms
+ if (!(gwa_type&IPV6_ADDR_UNICAST))
+ goto out;
+
+- grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);
++ grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1);
+
+ err = -EHOSTUNREACH;
+ if (grt == NULL)
+@@ -1049,7 +1177,7 @@ int ip6_route_add(struct in6_rtmsg *rtms
+ if (dev == NULL)
+ goto out;
+
+- if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) {
++ if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
+ rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
+ if (IS_ERR(rt->rt6i_nexthop)) {
+ err = PTR_ERR(rt->rt6i_nexthop);
+@@ -1058,24 +1186,24 @@ int ip6_route_add(struct in6_rtmsg *rtms
+ }
+ }
+
+- rt->rt6i_flags = rtmsg->rtmsg_flags;
++ rt->rt6i_flags = cfg->fc_flags;
+
+ install_route:
+- if (rta && rta[RTA_METRICS-1]) {
+- int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]);
+- struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]);
+-
+- while (RTA_OK(attr, attrlen)) {
+- unsigned flavor = attr->rta_type;
+- if (flavor) {
+- if (flavor > RTAX_MAX) {
++ if (cfg->fc_mx) {
++ struct nlattr *nla;
++ int remaining;
++
++ nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
++ int type = nla->nla_type;
++
++ if (type) {
++ if (type > RTAX_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
+- rt->u.dst.metrics[flavor-1] =
+- *(u32 *)RTA_DATA(attr);
++
++ rt->u.dst.metrics[type - 1] = nla_get_u32(nla);
+ }
+- attr = RTA_NEXT(attr, attrlen);
+ }
+ }
+
+@@ -1087,7 +1215,8 @@ install_route:
+ rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
+ rt->u.dst.dev = dev;
+ rt->rt6i_idev = idev;
+- return ip6_ins_rt(rt, nlh, _rtattr, req);
++ rt->rt6i_table = table;
++ return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
+
+ out:
+ if (dev)
+@@ -1099,51 +1228,65 @@ out:
+ return err;
+ }
+
+-int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
++static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
+ {
+ int err;
++ struct fib6_table *table;
++
++ if (rt == &ip6_null_entry)
++ return -ENOENT;
+
+- write_lock_bh(&rt6_lock);
++ table = rt->rt6i_table;
++ write_lock_bh(&table->tb6_lock);
+
+- err = fib6_del(rt, nlh, _rtattr, req);
++ err = fib6_del(rt, info);
+ dst_release(&rt->u.dst);
+
+- write_unlock_bh(&rt6_lock);
++ write_unlock_bh(&table->tb6_lock);
+
+ return err;
+ }
+
+-static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
++int ip6_del_rt(struct rt6_info *rt)
++{
++ return __ip6_del_rt(rt, NULL);
++}
++
++static int ip6_route_del(struct fib6_config *cfg)
+ {
++ struct fib6_table *table;
+ struct fib6_node *fn;
+ struct rt6_info *rt;
+ int err = -ESRCH;
+
+- read_lock_bh(&rt6_lock);
++ table = fib6_get_table(cfg->fc_table);
++ if (table == NULL)
++ return err;
++
++ read_lock_bh(&table->tb6_lock);
+
+- fn = fib6_locate(&ip6_routing_table,
+- &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len,
+- &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);
++ fn = fib6_locate(&table->tb6_root,
++ &cfg->fc_dst, cfg->fc_dst_len,
++ &cfg->fc_src, cfg->fc_src_len);
+
+ if (fn) {
+ for (rt = fn->leaf; rt; rt = rt->u.next) {
+- if (rtmsg->rtmsg_ifindex &&
++ if (cfg->fc_ifindex &&
+ (rt->rt6i_dev == NULL ||
+- rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex))
++ rt->rt6i_dev->ifindex != cfg->fc_ifindex))
+ continue;
+- if (rtmsg->rtmsg_flags&RTF_GATEWAY &&
+- !ipv6_addr_equal(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway))
++ if (cfg->fc_flags & RTF_GATEWAY &&
++ !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
+ continue;
+- if (rtmsg->rtmsg_metric &&
+- rtmsg->rtmsg_metric != rt->rt6i_metric)
++ if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
+ continue;
+ dst_hold(&rt->u.dst);
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+
+- return ip6_del_rt(rt, nlh, _rtattr, req);
++ return __ip6_del_rt(rt, &cfg->fc_nlinfo);
+ }
+ }
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
+
+ return err;
+ }
+@@ -1151,13 +1294,18 @@ static int ip6_route_del(struct in6_rtms
+ /*
+ * Handle redirects
+ */
+-void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
+- struct neighbour *neigh, u8 *lladdr, int on_link)
++struct ip6rd_flowi {
++ struct flowi fl;
++ struct in6_addr gateway;
++};
++
++static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,
++ struct flowi *fl,
++ int flags)
+ {
+- struct rt6_info *rt, *nrt = NULL;
+- int strict;
++ struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl;
++ struct rt6_info *rt;
+ struct fib6_node *fn;
+- struct netevent_redirect netevent;
+
+ /*
+ * Get the "current" route for this destination and
+@@ -1169,10 +1317,9 @@ void rt6_redirect(struct in6_addr *dest,
+ * is a bit fuzzy and one might need to check all possible
+ * routes.
+ */
+- strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
+
+- read_lock_bh(&rt6_lock);
+- fn = fib6_lookup(&ip6_routing_table, dest, NULL);
++ read_lock_bh(&table->tb6_lock);
++ fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
+ restart:
+ for (rt = fn->leaf; rt; rt = rt->u.next) {
+ /*
+@@ -1187,29 +1334,63 @@ restart:
+ continue;
+ if (!(rt->rt6i_flags & RTF_GATEWAY))
+ continue;
+- if (neigh->dev != rt->rt6i_dev)
++ if (fl->oif != rt->rt6i_dev->ifindex)
+ continue;
+- if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway))
++ if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
+ continue;
+ break;
+ }
+- if (rt)
+- dst_hold(&rt->u.dst);
+- else if (strict) {
+- while ((fn = fn->parent) != NULL) {
+- if (fn->fn_flags & RTN_ROOT)
+- break;
+- if (fn->fn_flags & RTN_RTINFO)
+- goto restart;
+- }
+- }
+- read_unlock_bh(&rt6_lock);
+
+- if (!rt) {
++ if (!rt)
++ rt = &ip6_null_entry;
++ BACKTRACK(&fl->fl6_src);
++out:
++ dst_hold(&rt->u.dst);
++
++ read_unlock_bh(&table->tb6_lock);
++
++ return rt;
++};
++
++static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
++ struct in6_addr *src,
++ struct in6_addr *gateway,
++ struct net_device *dev)
++{
++ int flags = RT6_LOOKUP_F_HAS_SADDR;
++ struct ip6rd_flowi rdfl = {
++ .fl = {
++ .oif = dev->ifindex,
++ .nl_u = {
++ .ip6_u = {
++ .daddr = *dest,
++ .saddr = *src,
++ },
++ },
++ },
++ .gateway = *gateway,
++ };
++
++ if (rt6_need_strict(dest))
++ flags |= RT6_LOOKUP_F_IFACE;
++
++ return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
++}
++
++void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
++ struct in6_addr *saddr,
++ struct neighbour *neigh, u8 *lladdr, int on_link)
++{
++ struct rt6_info *rt, *nrt = NULL;
++ struct netevent_redirect netevent;
++
++ rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
++
++ if (rt == &ip6_null_entry) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
+ "for redirect target\n");
+- return;
++ goto out;
+ }
+
+ /*
+@@ -1252,7 +1433,7 @@ restart:
+ nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
+ nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst));
+
+- if (ip6_ins_rt(nrt, NULL, NULL, NULL))
++ if (ip6_ins_rt(nrt))
+ goto out;
+
+ netevent.old = &rt->u.dst;
+@@ -1260,7 +1441,7 @@ restart:
+ call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
+
+ if (rt->rt6i_flags&RTF_CACHE) {
+- ip6_del_rt(rt, NULL, NULL, NULL);
++ ip6_del_rt(rt);
+ return;
+ }
+
+@@ -1342,7 +1523,7 @@ void rt6_pmtu_discovery(struct in6_addr
+ dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
+ nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
+
+- ip6_ins_rt(nrt, NULL, NULL, NULL);
++ ip6_ins_rt(nrt);
+ }
+ out:
+ dst_release(&rt->u.dst);
+@@ -1361,6 +1542,7 @@ static struct rt6_info * ip6_rt_copy(str
+ rt->u.dst.output = ort->u.dst.output;
+
+ memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
++ rt->u.dst.error = ort->u.dst.error;
+ rt->u.dst.dev = ort->u.dst.dev;
+ if (rt->u.dst.dev)
+ dev_hold(rt->u.dst.dev);
+@@ -1378,6 +1560,7 @@ static struct rt6_info * ip6_rt_copy(str
+ #ifdef CONFIG_IPV6_SUBTREES
+ memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
+ #endif
++ rt->rt6i_table = ort->rt6i_table;
+ }
+ return rt;
+ }
+@@ -1388,9 +1571,14 @@ static struct rt6_info *rt6_get_route_in
+ {
+ struct fib6_node *fn;
+ struct rt6_info *rt = NULL;
++ struct fib6_table *table;
++
++ table = fib6_get_table(RT6_TABLE_INFO);
++ if (table == NULL)
++ return NULL;
+
+- write_lock_bh(&rt6_lock);
+- fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0);
++ write_lock_bh(&table->tb6_lock);
++ fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
+ if (!fn)
+ goto out;
+
+@@ -1405,7 +1593,7 @@ static struct rt6_info *rt6_get_route_in
+ break;
+ }
+ out:
+- write_unlock_bh(&rt6_lock);
++ write_unlock_bh(&table->tb6_lock);
+ return rt;
+ }
+
+@@ -1413,21 +1601,23 @@ static struct rt6_info *rt6_add_route_in
+ struct in6_addr *gwaddr, int ifindex,
+ unsigned pref)
+ {
+- struct in6_rtmsg rtmsg;
++ struct fib6_config cfg = {
++ .fc_table = RT6_TABLE_INFO,
++ .fc_metric = 1024,
++ .fc_ifindex = ifindex,
++ .fc_dst_len = prefixlen,
++ .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
++ RTF_UP | RTF_PREF(pref),
++ };
++
++ ipv6_addr_copy(&cfg.fc_dst, prefix);
++ ipv6_addr_copy(&cfg.fc_gateway, gwaddr);
+
+- memset(&rtmsg, 0, sizeof(rtmsg));
+- rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+- ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix);
+- rtmsg.rtmsg_dst_len = prefixlen;
+- ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
+- rtmsg.rtmsg_metric = 1024;
+- rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref);
+ /* We should treat it as a default route if prefix length is 0. */
+ if (!prefixlen)
+- rtmsg.rtmsg_flags |= RTF_DEFAULT;
+- rtmsg.rtmsg_ifindex = ifindex;
++ cfg.fc_flags |= RTF_DEFAULT;
+
+- ip6_route_add(&rtmsg, NULL, NULL, NULL);
++ ip6_route_add(&cfg);
+
+ return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
+ }
+@@ -1436,12 +1626,14 @@ static struct rt6_info *rt6_add_route_in
+ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev)
+ {
+ struct rt6_info *rt;
+- struct fib6_node *fn;
++ struct fib6_table *table;
+
+- fn = &ip6_routing_table;
++ table = fib6_get_table(RT6_TABLE_DFLT);
++ if (table == NULL)
++ return NULL;
+
+- write_lock_bh(&rt6_lock);
+- for (rt = fn->leaf; rt; rt=rt->u.next) {
++ write_lock_bh(&table->tb6_lock);
++ for (rt = table->tb6_root.leaf; rt; rt=rt->u.next) {
+ if (dev == rt->rt6i_dev &&
+ ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
+ ipv6_addr_equal(&rt->rt6i_gateway, addr))
+@@ -1449,7 +1641,7 @@ struct rt6_info *rt6_get_dflt_router(str
+ }
+ if (rt)
+ dst_hold(&rt->u.dst);
+- write_unlock_bh(&rt6_lock);
++ write_unlock_bh(&table->tb6_lock);
+ return rt;
+ }
+
+@@ -1457,43 +1649,65 @@ struct rt6_info *rt6_add_dflt_router(str
+ struct net_device *dev,
+ unsigned int pref)
+ {
+- struct in6_rtmsg rtmsg;
++ struct fib6_config cfg = {
++ .fc_table = RT6_TABLE_DFLT,
++ .fc_metric = 1024,
++ .fc_ifindex = dev->ifindex,
++ .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
++ RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
++ };
+
+- memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
+- rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+- ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
+- rtmsg.rtmsg_metric = 1024;
+- rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
+- RTF_PREF(pref);
++ ipv6_addr_copy(&cfg.fc_gateway, gwaddr);
+
+- rtmsg.rtmsg_ifindex = dev->ifindex;
++ ip6_route_add(&cfg);
+
+- ip6_route_add(&rtmsg, NULL, NULL, NULL);
+ return rt6_get_dflt_router(gwaddr, dev);
+ }
+
+ void rt6_purge_dflt_routers(void)
+ {
+ struct rt6_info *rt;
++ struct fib6_table *table;
++
++ /* NOTE: Keep consistent with rt6_get_dflt_router */
++ table = fib6_get_table(RT6_TABLE_DFLT);
++ if (table == NULL)
++ return;
+
+ restart:
+- read_lock_bh(&rt6_lock);
+- for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) {
++ read_lock_bh(&table->tb6_lock);
++ for (rt = table->tb6_root.leaf; rt; rt = rt->u.next) {
+ if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
+ dst_hold(&rt->u.dst);
+-
+- read_unlock_bh(&rt6_lock);
+-
+- ip6_del_rt(rt, NULL, NULL, NULL);
+-
++ read_unlock_bh(&table->tb6_lock);
++ ip6_del_rt(rt);
+ goto restart;
+ }
+ }
+- read_unlock_bh(&rt6_lock);
++ read_unlock_bh(&table->tb6_lock);
++}
++
++static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg,
++ struct fib6_config *cfg)
++{
++ memset(cfg, 0, sizeof(*cfg));
++
++ cfg->fc_table = RT6_TABLE_MAIN;
++ cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
++ cfg->fc_metric = rtmsg->rtmsg_metric;
++ cfg->fc_expires = rtmsg->rtmsg_info;
++ cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
++ cfg->fc_src_len = rtmsg->rtmsg_src_len;
++ cfg->fc_flags = rtmsg->rtmsg_flags;
++
++ ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst);
++ ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src);
++ ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway);
+ }
+
+ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
+ {
++ struct fib6_config cfg;
+ struct in6_rtmsg rtmsg;
+ int err;
+
+@@ -1506,14 +1720,16 @@ int ipv6_route_ioctl(unsigned int cmd, v
+ sizeof(struct in6_rtmsg));
+ if (err)
+ return -EFAULT;
+-
++
++ rtmsg_to_fib6_config(&rtmsg, &cfg);
++
+ rtnl_lock();
+ switch (cmd) {
+ case SIOCADDRT:
+- err = ip6_route_add(&rtmsg, NULL, NULL, NULL);
++ err = ip6_route_add(&cfg);
+ break;
+ case SIOCDELRT:
+- err = ip6_route_del(&rtmsg, NULL, NULL, NULL);
++ err = ip6_route_del(&cfg);
+ break;
+ default:
+ err = -EINVAL;
+@@ -1530,24 +1746,50 @@ int ipv6_route_ioctl(unsigned int cmd, v
+ * Drop the packet on the floor
+ */
+
+-static int ip6_pkt_discard(struct sk_buff *skb)
++static inline int ip6_pkt_drop(struct sk_buff *skb, int code)
+ {
+ int type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
+ if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED)
+ IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS);
+
+ IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
+- icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
++ icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);
+ kfree_skb(skb);
+ return 0;
+ }
+
++static int ip6_pkt_discard(struct sk_buff *skb)
++{
++ return ip6_pkt_drop(skb, ICMPV6_NOROUTE);
++}
++
+ static int ip6_pkt_discard_out(struct sk_buff *skb)
+ {
+ skb->dev = skb->dst->dev;
+ return ip6_pkt_discard(skb);
+ }
+
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++
++static int ip6_pkt_prohibit(struct sk_buff *skb)
++{
++ return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED);
++}
++
++static int ip6_pkt_prohibit_out(struct sk_buff *skb)
++{
++ skb->dev = skb->dst->dev;
++ return ip6_pkt_prohibit(skb);
++}
++
++static int ip6_pkt_blk_hole(struct sk_buff *skb)
++{
++ kfree_skb(skb);
++ return 0;
++}
++
++#endif
++
+ /*
+ * Allocate a dst for local (unicast / anycast) address.
+ */
+@@ -1587,6 +1829,7 @@ struct rt6_info *addrconf_dst_alloc(stru
+
+ ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+ rt->rt6i_dst.plen = 128;
++ rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);
+
+ atomic_set(&rt->u.dst.__refcnt, 1);
+
+@@ -1605,9 +1848,7 @@ static int fib6_ifdown(struct rt6_info *
+
+ void rt6_ifdown(struct net_device *dev)
+ {
+- write_lock_bh(&rt6_lock);
+- fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev);
+- write_unlock_bh(&rt6_lock);
++ fib6_clean_all(fib6_ifdown, 0, dev);
+ }
+
+ struct rt6_mtu_change_arg
+@@ -1657,80 +1898,114 @@ static int rt6_mtu_change_route(struct r
+
+ void rt6_mtu_change(struct net_device *dev, unsigned mtu)
+ {
+- struct rt6_mtu_change_arg arg;
++ struct rt6_mtu_change_arg arg = {
++ .dev = dev,
++ .mtu = mtu,
++ };
+
+- arg.dev = dev;
+- arg.mtu = mtu;
+- read_lock_bh(&rt6_lock);
+- fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg);
+- read_unlock_bh(&rt6_lock);
++ fib6_clean_all(rt6_mtu_change_route, 0, &arg);
+ }
+
+-static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,
+- struct in6_rtmsg *rtmsg)
++static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = {
++ [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
++ [RTA_OIF] = { .type = NLA_U32 },
++ [RTA_IIF] = { .type = NLA_U32 },
++ [RTA_PRIORITY] = { .type = NLA_U32 },
++ [RTA_METRICS] = { .type = NLA_NESTED },
++};
++
++static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
++ struct fib6_config *cfg)
+ {
+- memset(rtmsg, 0, sizeof(*rtmsg));
++ struct rtmsg *rtm;
++ struct nlattr *tb[RTA_MAX+1];
++ int err;
+
+- rtmsg->rtmsg_dst_len = r->rtm_dst_len;
+- rtmsg->rtmsg_src_len = r->rtm_src_len;
+- rtmsg->rtmsg_flags = RTF_UP;
+- if (r->rtm_type == RTN_UNREACHABLE)
+- rtmsg->rtmsg_flags |= RTF_REJECT;
++ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
++ if (err < 0)
++ goto errout;
+
+- if (rta[RTA_GATEWAY-1]) {
+- if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16))
+- return -EINVAL;
+- memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16);
+- rtmsg->rtmsg_flags |= RTF_GATEWAY;
+- }
+- if (rta[RTA_DST-1]) {
+- if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3))
+- return -EINVAL;
+- memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3));
++ err = -EINVAL;
++ rtm = nlmsg_data(nlh);
++ memset(cfg, 0, sizeof(*cfg));
++
++ cfg->fc_table = rtm->rtm_table;
++ cfg->fc_dst_len = rtm->rtm_dst_len;
++ cfg->fc_src_len = rtm->rtm_src_len;
++ cfg->fc_flags = RTF_UP;
++ cfg->fc_protocol = rtm->rtm_protocol;
++
++ if (rtm->rtm_type == RTN_UNREACHABLE)
++ cfg->fc_flags |= RTF_REJECT;
++
++ cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
++ cfg->fc_nlinfo.nlh = nlh;
++
++ if (tb[RTA_GATEWAY]) {
++ nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
++ cfg->fc_flags |= RTF_GATEWAY;
+ }
+- if (rta[RTA_SRC-1]) {
+- if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3))
+- return -EINVAL;
+- memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3));
++
++ if (tb[RTA_DST]) {
++ int plen = (rtm->rtm_dst_len + 7) >> 3;
++
++ if (nla_len(tb[RTA_DST]) < plen)
++ goto errout;
++
++ nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
+ }
+- if (rta[RTA_OIF-1]) {
+- if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int)))
+- return -EINVAL;
+- memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
++
++ if (tb[RTA_SRC]) {
++ int plen = (rtm->rtm_src_len + 7) >> 3;
++
++ if (nla_len(tb[RTA_SRC]) < plen)
++ goto errout;
++
++ nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
+ }
+- if (rta[RTA_PRIORITY-1]) {
+- if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4))
+- return -EINVAL;
+- memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
++
++ if (tb[RTA_OIF])
++ cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
++
++ if (tb[RTA_PRIORITY])
++ cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
++
++ if (tb[RTA_METRICS]) {
++ cfg->fc_mx = nla_data(tb[RTA_METRICS]);
++ cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
+ }
+- return 0;
++
++ if (tb[RTA_TABLE])
++ cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
++
++ err = 0;
++errout:
++ return err;
+ }
+
+ int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+ {
+- struct rtmsg *r = NLMSG_DATA(nlh);
+- struct in6_rtmsg rtmsg;
++ struct fib6_config cfg;
++ int err;
+
+- if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
+- return -EINVAL;
+- return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb));
++ err = rtm_to_fib6_config(skb, nlh, &cfg);
++ if (err < 0)
++ return err;
++
++ return ip6_route_del(&cfg);
+ }
+
+ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+ {
+- struct rtmsg *r = NLMSG_DATA(nlh);
+- struct in6_rtmsg rtmsg;
++ struct fib6_config cfg;
++ int err;
+
+- if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
+- return -EINVAL;
+- return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb));
+-}
++ err = rtm_to_fib6_config(skb, nlh, &cfg);
++ if (err < 0)
++ return err;
+
+-struct rt6_rtnl_dump_arg
+-{
+- struct sk_buff *skb;
+- struct netlink_callback *cb;
+-};
++ return ip6_route_add(&cfg);
++}
+
+ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+ struct in6_addr *dst, struct in6_addr *src,
+@@ -1738,9 +2013,9 @@ static int rt6_fill_node(struct sk_buff
+ int prefix, unsigned int flags)
+ {
+ struct rtmsg *rtm;
+- struct nlmsghdr *nlh;
+- unsigned char *b = skb->tail;
++ struct nlmsghdr *nlh;
+ struct rta_cacheinfo ci;
++ u32 table;
+
+ if (prefix) { /* user wants prefix routes only */
+ if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
+@@ -1749,13 +2024,21 @@ static int rt6_fill_node(struct sk_buff
+ }
+ }
+
+- nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*rtm), flags);
+- rtm = NLMSG_DATA(nlh);
++ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags);
++ if (nlh == NULL)
++ return -ENOBUFS;
++
++ rtm = nlmsg_data(nlh);
+ rtm->rtm_family = AF_INET6;
+ rtm->rtm_dst_len = rt->rt6i_dst.plen;
+ rtm->rtm_src_len = rt->rt6i_src.plen;
+ rtm->rtm_tos = 0;
+- rtm->rtm_table = RT_TABLE_MAIN;
++ if (rt->rt6i_table)
++ table = rt->rt6i_table->tb6_id;
++ else
++ table = RT6_TABLE_UNSPEC;
++ rtm->rtm_table = table;
++ NLA_PUT_U32(skb, RTA_TABLE, table);
+ if (rt->rt6i_flags&RTF_REJECT)
+ rtm->rtm_type = RTN_UNREACHABLE;
+ else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))
+@@ -1776,31 +2059,35 @@ static int rt6_fill_node(struct sk_buff
+ rtm->rtm_flags |= RTM_F_CLONED;
+
+ if (dst) {
+- RTA_PUT(skb, RTA_DST, 16, dst);
++ NLA_PUT(skb, RTA_DST, 16, dst);
+ rtm->rtm_dst_len = 128;
+ } else if (rtm->rtm_dst_len)
+- RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
++ NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
+ #ifdef CONFIG_IPV6_SUBTREES
+ if (src) {
+- RTA_PUT(skb, RTA_SRC, 16, src);
++ NLA_PUT(skb, RTA_SRC, 16, src);
+ rtm->rtm_src_len = 128;
+ } else if (rtm->rtm_src_len)
+- RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
++ NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+ #endif
+ if (iif)
+- RTA_PUT(skb, RTA_IIF, 4, &iif);
++ NLA_PUT_U32(skb, RTA_IIF, iif);
+ else if (dst) {
+ struct in6_addr saddr_buf;
+ if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0)
+- RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
++ NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+ }
++
+ if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+- goto rtattr_failure;
++ goto nla_put_failure;
++
+ if (rt->u.dst.neighbour)
+- RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
++ NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
++
+ if (rt->u.dst.dev)
+- RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->rt6i_dev->ifindex);
+- RTA_PUT(skb, RTA_PRIORITY, 4, &rt->rt6i_metric);
++ NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex);
++
++ NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
+ ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse);
+ if (rt->rt6i_expires)
+ ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies);
+@@ -1812,23 +2099,21 @@ static int rt6_fill_node(struct sk_buff
+ ci.rta_id = 0;
+ ci.rta_ts = 0;
+ ci.rta_tsage = 0;
+- RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
+- nlh->nlmsg_len = skb->tail - b;
+- return skb->len;
++ NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
+
+-nlmsg_failure:
+-rtattr_failure:
+- skb_trim(skb, b - skb->data);
+- return -1;
++ return nlmsg_end(skb, nlh);
++
++nla_put_failure:
++ return nlmsg_cancel(skb, nlh);
+ }
+
+-static int rt6_dump_route(struct rt6_info *rt, void *p_arg)
++int rt6_dump_route(struct rt6_info *rt, void *p_arg)
+ {
+ struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
+ int prefix;
+
+- if (arg->cb->nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(struct rtmsg))) {
+- struct rtmsg *rtm = NLMSG_DATA(arg->cb->nlh);
++ if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
++ struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
+ prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
+ } else
+ prefix = 0;
+@@ -1838,189 +2123,108 @@ static int rt6_dump_route(struct rt6_inf
+ prefix, NLM_F_MULTI);
+ }
+
+-static int fib6_dump_node(struct fib6_walker_t *w)
++int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+ {
+- int res;
++ struct nlattr *tb[RTA_MAX+1];
+ struct rt6_info *rt;
++ struct sk_buff *skb;
++ struct rtmsg *rtm;
++ struct flowi fl;
++ int err, iif = 0;
+
+- for (rt = w->leaf; rt; rt = rt->u.next) {
+- res = rt6_dump_route(rt, w->args);
+- if (res < 0) {
+- /* Frame is full, suspend walking */
+- w->leaf = rt;
+- return 1;
+- }
+- BUG_TRAP(res!=0);
+- }
+- w->leaf = NULL;
+- return 0;
+-}
+-
+-static void fib6_dump_end(struct netlink_callback *cb)
+-{
+- struct fib6_walker_t *w = (void*)cb->args[0];
+-
+- if (w) {
+- cb->args[0] = 0;
+- fib6_walker_unlink(w);
+- kfree(w);
+- }
+- cb->done = (void*)cb->args[1];
+- cb->args[1] = 0;
+-}
+-
+-static int fib6_dump_done(struct netlink_callback *cb)
+-{
+- fib6_dump_end(cb);
+- return cb->done ? cb->done(cb) : 0;
+-}
+-
+-int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
+-{
+- struct rt6_rtnl_dump_arg arg;
+- struct fib6_walker_t *w;
+- int res;
++ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
++ if (err < 0)
++ goto errout;
+
+- arg.skb = skb;
+- arg.cb = cb;
++ err = -EINVAL;
++ memset(&fl, 0, sizeof(fl));
+
+- w = (void*)cb->args[0];
+- if (w == NULL) {
+- /* New dump:
+- *
+- * 1. hook callback destructor.
+- */
+- cb->args[1] = (long)cb->done;
+- cb->done = fib6_dump_done;
++ if (tb[RTA_SRC]) {
++ if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
++ goto errout;
+
+- /*
+- * 2. allocate and initialize walker.
+- */
+- w = kzalloc(sizeof(*w), GFP_ATOMIC);
+- if (w == NULL)
+- return -ENOMEM;
+- RT6_TRACE("dump<%p", w);
+- w->root = &ip6_routing_table;
+- w->func = fib6_dump_node;
+- w->args = &arg;
+- cb->args[0] = (long)w;
+- read_lock_bh(&rt6_lock);
+- res = fib6_walk(w);
+- read_unlock_bh(&rt6_lock);
+- } else {
+- w->args = &arg;
+- read_lock_bh(&rt6_lock);
+- res = fib6_walk_continue(w);
+- read_unlock_bh(&rt6_lock);
++ ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC]));
+ }
+-#if RT6_DEBUG >= 3
+- if (res <= 0 && skb->len == 0)
+- RT6_TRACE("%p>dump end\n", w);
+-#endif
+- res = res < 0 ? res : skb->len;
+- /* res < 0 is an error. (really, impossible)
+- res == 0 means that dump is complete, but skb still can contain data.
+- res > 0 dump is not complete, but frame is full.
+- */
+- /* Destroy walker, if dump of this table is complete. */
+- if (res <= 0)
+- fib6_dump_end(cb);
+- return res;
+-}
+
+-int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+-{
+- struct rtattr **rta = arg;
+- int iif = 0;
+- int err = -ENOBUFS;
+- struct sk_buff *skb;
+- struct flowi fl;
+- struct rt6_info *rt;
+-
+- skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+- if (skb == NULL)
+- goto out;
++ if (tb[RTA_DST]) {
++ if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
++ goto errout;
+
+- /* Reserve room for dummy headers, this skb can pass
+- through good chunk of routing engine.
+- */
+- skb->mac.raw = skb->data;
+- skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
++ ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST]));
++ }
+
+- memset(&fl, 0, sizeof(fl));
+- if (rta[RTA_SRC-1])
+- ipv6_addr_copy(&fl.fl6_src,
+- (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]));
+- if (rta[RTA_DST-1])
+- ipv6_addr_copy(&fl.fl6_dst,
+- (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]));
++ if (tb[RTA_IIF])
++ iif = nla_get_u32(tb[RTA_IIF]);
+
+- if (rta[RTA_IIF-1])
+- memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
++ if (tb[RTA_OIF])
++ fl.oif = nla_get_u32(tb[RTA_OIF]);
+
+ if (iif) {
+ struct net_device *dev;
+ dev = __dev_get_by_index(iif);
+ if (!dev) {
+ err = -ENODEV;
+- goto out_free;
++ goto errout;
+ }
+ }
+
+- fl.oif = 0;
+- if (rta[RTA_OIF-1])
+- memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
++ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (skb == NULL) {
++ err = -ENOBUFS;
++ goto errout;
++ }
+
+- rt = (struct rt6_info*)ip6_route_output(NULL, &fl);
++ /* Reserve room for dummy headers, this skb can pass
++ through good chunk of routing engine.
++ */
++ skb->mac.raw = skb->data;
++ skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
+
++ rt = (struct rt6_info*) ip6_route_output(NULL, &fl);
+ skb->dst = &rt->u.dst;
+
+- NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+- err = rt6_fill_node(skb, rt,
+- &fl.fl6_dst, &fl.fl6_src,
+- iif,
++ err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
+ RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
+ nlh->nlmsg_seq, 0, 0);
+ if (err < 0) {
+- err = -EMSGSIZE;
+- goto out_free;
++ kfree_skb(skb);
++ goto errout;
+ }
+
+- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+- if (err > 0)
+- err = 0;
+-out:
++ err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
++errout:
+ return err;
+-out_free:
+- kfree_skb(skb);
+- goto out;
+ }
+
+-void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh,
+- struct netlink_skb_parms *req)
++void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
+ {
+ struct sk_buff *skb;
+- int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+- u32 pid = current->pid;
+- u32 seq = 0;
+-
+- if (req)
+- pid = req->pid;
+- if (nlh)
+- seq = nlh->nlmsg_seq;
+-
+- skb = alloc_skb(size, gfp_any());
+- if (!skb) {
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, ENOBUFS);
+- return;
++ u32 pid = 0, seq = 0;
++ struct nlmsghdr *nlh = NULL;
++ int payload = sizeof(struct rtmsg) + 256;
++ int err = -ENOBUFS;
++
++ if (info) {
++ pid = info->pid;
++ nlh = info->nlh;
++ if (nlh)
++ seq = nlh->nlmsg_seq;
+ }
+- if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0) < 0) {
++
++ skb = nlmsg_new(nlmsg_total_size(payload), gfp_any());
++ if (skb == NULL)
++ goto errout;
++
++ err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0);
++ if (err < 0) {
+ kfree_skb(skb);
+- netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, EINVAL);
+- return;
++ goto errout;
+ }
+- NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_ROUTE;
+- netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_ROUTE, gfp_any());
++
++ err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any());
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(RTNLGRP_IPV6_ROUTE, err);
+ }
+
+ /*
+@@ -2096,16 +2300,13 @@ static int rt6_info_route(struct rt6_inf
+
+ static int rt6_proc_info(char *buffer, char **start, off_t offset, int length)
+ {
+- struct rt6_proc_arg arg;
+- arg.buffer = buffer;
+- arg.offset = offset;
+- arg.length = length;
+- arg.skip = 0;
+- arg.len = 0;
++ struct rt6_proc_arg arg = {
++ .buffer = buffer,
++ .offset = offset,
++ .length = length,
++ };
+
+- read_lock_bh(&rt6_lock);
+- fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg);
+- read_unlock_bh(&rt6_lock);
++ fib6_clean_all(rt6_info_route, 0, &arg);
+
+ *start = buffer;
+ if (offset)
+@@ -2260,13 +2461,9 @@ void __init ip6_route_init(void)
+ {
+ struct proc_dir_entry *p;
+
+- ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache",
+- sizeof(struct rt6_info),
+- 0, SLAB_HWCACHE_ALIGN,
+- NULL, NULL);
+- if (!ip6_dst_ops.kmem_cachep)
+- panic("cannot create ip6_dst_cache");
+-
++ ip6_dst_ops.kmem_cachep =
++ kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ fib6_init();
+ #ifdef CONFIG_PROC_FS
+ p = proc_net_create("ipv6_route", 0, rt6_proc_info);
+@@ -2278,10 +2475,16 @@ void __init ip6_route_init(void)
+ #ifdef CONFIG_XFRM
+ xfrm6_init();
+ #endif
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++ fib6_rules_init();
++#endif
+ }
+
+ void ip6_route_cleanup(void)
+ {
++#ifdef CONFIG_IPV6_MULTIPLE_TABLES
++ fib6_rules_cleanup();
++#endif
+ #ifdef CONFIG_PROC_FS
+ proc_net_remove("ipv6_route");
+ proc_net_remove("rt6_stats");
+diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
+index 836eecd..be699f8 100644
+--- a/net/ipv6/sit.c
++++ b/net/ipv6/sit.c
+@@ -850,3 +850,8 @@ int __init sit_init(void)
+ inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
+ goto out;
+ }
++
++module_init(sit_init);
++module_exit(sit_cleanup);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("sit0");
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 802a1a6..4c2a7c0 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -251,6 +251,8 @@ static int tcp_v6_connect(struct sock *s
+ final_p = &final;
+ }
+
++ security_sk_classify_flow(sk, &fl);
++
+ err = ip6_dst_lookup(sk, &dst, &fl);
+ if (err)
+ goto failure;
+@@ -270,7 +272,7 @@ static int tcp_v6_connect(struct sock *s
+ inet->rcv_saddr = LOOPBACK4_IPV6;
+
+ sk->sk_gso_type = SKB_GSO_TCPV6;
+- __ip6_dst_store(sk, dst, NULL);
++ __ip6_dst_store(sk, dst, NULL, NULL);
+
+ icsk->icsk_ext_hdr_len = 0;
+ if (np->opt)
+@@ -327,7 +329,7 @@ static void tcp_v6_err(struct sk_buff *s
+ }
+
+ if (sk->sk_state == TCP_TIME_WAIT) {
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ return;
+ }
+
+@@ -374,6 +376,7 @@ static void tcp_v6_err(struct sk_buff *s
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet->dport;
+ fl.fl_ip_sport = inet->sport;
++ security_skb_classify_flow(skb, &fl);
+
+ if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
+ sk->sk_err_soft = -err;
+@@ -467,6 +470,7 @@ static int tcp_v6_send_synack(struct soc
+ fl.oif = treq->iif;
+ fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+ fl.fl_ip_sport = inet_sk(sk)->sport;
++ security_req_classify_flow(req, &fl);
+
+ if (dst == NULL) {
+ opt = np->opt;
+@@ -541,7 +545,7 @@ static void tcp_v6_send_check(struct soc
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct tcphdr *th = skb->h.th;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
+ skb->csum = offsetof(struct tcphdr, check);
+ } else {
+@@ -566,7 +570,7 @@ static int tcp_v6_gso_send_check(struct
+ th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
+ IPPROTO_TCP, 0);
+ skb->csum = offsetof(struct tcphdr, check);
+- skb->ip_summed = CHECKSUM_HW;
++ skb->ip_summed = CHECKSUM_PARTIAL;
+ return 0;
+ }
+
+@@ -625,6 +629,7 @@ static void tcp_v6_send_reset(struct sk_
+ fl.oif = inet6_iif(skb);
+ fl.fl_ip_dport = t1->dest;
+ fl.fl_ip_sport = t1->source;
++ security_skb_classify_flow(skb, &fl);
+
+ /* sk = NULL, but it is safe for now. RST socket required. */
+ if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+@@ -648,7 +653,7 @@ static void tcp_v6_send_ack(struct sk_bu
+ int tot_len = sizeof(struct tcphdr);
+
+ if (ts)
+- tot_len += 3*4;
++ tot_len += TCPOLEN_TSTAMP_ALIGNED;
+
+ buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
+ GFP_ATOMIC);
+@@ -691,6 +696,7 @@ static void tcp_v6_send_ack(struct sk_bu
+ fl.oif = inet6_iif(skb);
+ fl.fl_ip_dport = t1->dest;
+ fl.fl_ip_sport = t1->source;
++ security_skb_classify_flow(skb, &fl);
+
+ if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+ if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
+@@ -743,7 +749,7 @@ static struct sock *tcp_v6_hnd_req(struc
+ bh_lock_sock(nsk);
+ return nsk;
+ }
+- inet_twsk_put((struct inet_timewait_sock *)nsk);
++ inet_twsk_put(inet_twsk(nsk));
+ return NULL;
+ }
+
+@@ -820,6 +826,8 @@ static int tcp_v6_conn_request(struct so
+
+ tcp_rsk(req)->snt_isn = isn;
+
++ security_inet_conn_request(sk, skb, req);
++
+ if (tcp_v6_send_synack(sk, req, NULL))
+ goto drop;
+
+@@ -923,6 +931,7 @@ static struct sock * tcp_v6_syn_recv_soc
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+ fl.fl_ip_sport = inet_sk(sk)->sport;
++ security_req_classify_flow(req, &fl);
+
+ if (ip6_dst_lookup(sk, &dst, &fl))
+ goto out;
+@@ -945,7 +954,7 @@ static struct sock * tcp_v6_syn_recv_soc
+ */
+
+ newsk->sk_gso_type = SKB_GSO_TCPV6;
+- __ip6_dst_store(newsk, dst, NULL);
++ __ip6_dst_store(newsk, dst, NULL, NULL);
+
+ newtcp6sk = (struct tcp6_sock *)newsk;
+ inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
+@@ -1024,7 +1033,7 @@ out:
+
+ static int tcp_v6_checksum_init(struct sk_buff *skb)
+ {
+- if (skb->ip_summed == CHECKSUM_HW) {
++ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+ &skb->nh.ipv6h->daddr,skb->csum)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+@@ -1066,7 +1075,7 @@ static int tcp_v6_do_rcv(struct sock *sk
+ if (skb->protocol == htons(ETH_P_IP))
+ return tcp_v4_do_rcv(sk, skb);
+
+- if (sk_filter(sk, skb, 0))
++ if (sk_filter(sk, skb))
+ goto discard;
+
+ /*
+@@ -1223,12 +1232,12 @@ process:
+ if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
+ goto discard_and_relse;
+
+- if (sk_filter(sk, skb, 0))
++ if (sk_filter(sk, skb))
+ goto discard_and_relse;
+
+ skb->dev = NULL;
+
+- bh_lock_sock(sk);
++ bh_lock_sock_nested(sk);
+ ret = 0;
+ if (!sock_owned_by_user(sk)) {
+ #ifdef CONFIG_NET_DMA
+@@ -1274,18 +1283,17 @@ discard_and_relse:
+
+ do_time_wait:
+ if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ goto discard_it;
+ }
+
+ if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+ TCP_INC_STATS_BH(TCP_MIB_INERRS);
+- inet_twsk_put((struct inet_timewait_sock *)sk);
++ inet_twsk_put(inet_twsk(sk));
+ goto discard_it;
+ }
+
+- switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
+- skb, th)) {
++ switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
+ case TCP_TW_SYN:
+ {
+ struct sock *sk2;
+diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
+index 3d54f24..e0c3934 100644
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -61,81 +61,9 @@
+
+ DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
+
+-/* Grrr, addr_type already calculated by caller, but I don't want
+- * to add some silly "cookie" argument to this method just for that.
+- */
+-static int udp_v6_get_port(struct sock *sk, unsigned short snum)
++static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
+ {
+- struct sock *sk2;
+- struct hlist_node *node;
+-
+- write_lock_bh(&udp_hash_lock);
+- if (snum == 0) {
+- int best_size_so_far, best, result, i;
+-
+- if (udp_port_rover > sysctl_local_port_range[1] ||
+- udp_port_rover < sysctl_local_port_range[0])
+- udp_port_rover = sysctl_local_port_range[0];
+- best_size_so_far = 32767;
+- best = result = udp_port_rover;
+- for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+- int size;
+- struct hlist_head *list;
+-
+- list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+- if (hlist_empty(list)) {
+- if (result > sysctl_local_port_range[1])
+- result = sysctl_local_port_range[0] +
+- ((result - sysctl_local_port_range[0]) &
+- (UDP_HTABLE_SIZE - 1));
+- goto gotit;
+- }
+- size = 0;
+- sk_for_each(sk2, node, list)
+- if (++size >= best_size_so_far)
+- goto next;
+- best_size_so_far = size;
+- best = result;
+- next:;
+- }
+- result = best;
+- for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) {
+- if (result > sysctl_local_port_range[1])
+- result = sysctl_local_port_range[0]
+- + ((result - sysctl_local_port_range[0]) &
+- (UDP_HTABLE_SIZE - 1));
+- if (!udp_lport_inuse(result))
+- break;
+- }
+- if (i >= (1 << 16) / UDP_HTABLE_SIZE)
+- goto fail;
+-gotit:
+- udp_port_rover = snum = result;
+- } else {
+- sk_for_each(sk2, node,
+- &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) {
+- if (inet_sk(sk2)->num == snum &&
+- sk2 != sk &&
+- (!sk2->sk_bound_dev_if ||
+- !sk->sk_bound_dev_if ||
+- sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+- (!sk2->sk_reuse || !sk->sk_reuse) &&
+- ipv6_rcv_saddr_equal(sk, sk2))
+- goto fail;
+- }
+- }
+-
+- inet_sk(sk)->num = snum;
+- if (sk_unhashed(sk)) {
+- sk_add_node(sk, &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]);
+- sock_prot_inc_use(sk->sk_prot);
+- }
+- write_unlock_bh(&udp_hash_lock);
+- return 0;
+-
+-fail:
+- write_unlock_bh(&udp_hash_lock);
+- return 1;
++ return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
+ }
+
+ static void udp_v6_hash(struct sock *sk)
+@@ -345,6 +273,8 @@ out:
+
+ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
++ int rc;
++
+ if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) {
+ kfree_skb(skb);
+ return -1;
+@@ -356,7 +286,10 @@ static inline int udpv6_queue_rcv_skb(st
+ return 0;
+ }
+
+- if (sock_queue_rcv_skb(sk,skb)<0) {
++ if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
++ /* Note that an ENOMEM error is charged twice */
++ if (rc == -ENOMEM)
++ UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS);
+ UDP6_INC_STATS_BH(UDP_MIB_INERRORS);
+ kfree_skb(skb);
+ return 0;
+@@ -475,7 +408,7 @@ static int udpv6_rcv(struct sk_buff **ps
+ uh = skb->h.uh;
+ }
+
+- if (skb->ip_summed == CHECKSUM_HW &&
++ if (skb->ip_summed == CHECKSUM_COMPLETE &&
+ !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+@@ -613,7 +546,7 @@ static int udpv6_sendmsg(struct kiocb *i
+ struct in6_addr *daddr, *final_p = NULL, final;
+ struct ipv6_txoptions *opt = NULL;
+ struct ip6_flowlabel *flowlabel = NULL;
+- struct flowi *fl = &inet->cork.fl;
++ struct flowi fl;
+ struct dst_entry *dst;
+ int addr_len = msg->msg_namelen;
+ int ulen = len;
+@@ -693,19 +626,19 @@ do_udp_sendmsg:
+ }
+ ulen += sizeof(struct udphdr);
+
+- memset(fl, 0, sizeof(*fl));
++ memset(&fl, 0, sizeof(fl));
+
+ if (sin6) {
+ if (sin6->sin6_port == 0)
+ return -EINVAL;
+
+- fl->fl_ip_dport = sin6->sin6_port;
++ fl.fl_ip_dport = sin6->sin6_port;
+ daddr = &sin6->sin6_addr;
+
+ if (np->sndflow) {
+- fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+- if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+- flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
++ fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
++ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
++ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ daddr = &flowlabel->dst;
+@@ -723,32 +656,32 @@ do_udp_sendmsg:
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ sin6->sin6_scope_id &&
+ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+- fl->oif = sin6->sin6_scope_id;
++ fl.oif = sin6->sin6_scope_id;
+ } else {
+ if (sk->sk_state != TCP_ESTABLISHED)
+ return -EDESTADDRREQ;
+
+- fl->fl_ip_dport = inet->dport;
++ fl.fl_ip_dport = inet->dport;
+ daddr = &np->daddr;
+- fl->fl6_flowlabel = np->flow_label;
++ fl.fl6_flowlabel = np->flow_label;
+ connected = 1;
+ }
+
+- if (!fl->oif)
+- fl->oif = sk->sk_bound_dev_if;
++ if (!fl.oif)
++ fl.oif = sk->sk_bound_dev_if;
+
+ if (msg->msg_controllen) {
+ opt = &opt_space;
+ memset(opt, 0, sizeof(struct ipv6_txoptions));
+ opt->tot_len = sizeof(*opt);
+
+- err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass);
++ err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
+ if (err < 0) {
+ fl6_sock_release(flowlabel);
+ return err;
+ }
+- if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+- flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
++ if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
++ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ }
+@@ -762,37 +695,39 @@ do_udp_sendmsg:
+ opt = fl6_merge_options(&opt_space, flowlabel, opt);
+ opt = ipv6_fixup_options(&opt_space, opt);
+
+- fl->proto = IPPROTO_UDP;
+- ipv6_addr_copy(&fl->fl6_dst, daddr);
+- if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr))
+- ipv6_addr_copy(&fl->fl6_src, &np->saddr);
+- fl->fl_ip_sport = inet->sport;
++ fl.proto = IPPROTO_UDP;
++ ipv6_addr_copy(&fl.fl6_dst, daddr);
++ if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
++ ipv6_addr_copy(&fl.fl6_src, &np->saddr);
++ fl.fl_ip_sport = inet->sport;
+
+ /* merge ip6_build_xmit from ip6_output */
+ if (opt && opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+- ipv6_addr_copy(&final, &fl->fl6_dst);
+- ipv6_addr_copy(&fl->fl6_dst, rt0->addr);
++ ipv6_addr_copy(&final, &fl.fl6_dst);
++ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+ final_p = &final;
+ connected = 0;
+ }
+
+- if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) {
+- fl->oif = np->mcast_oif;
++ if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
++ fl.oif = np->mcast_oif;
+ connected = 0;
+ }
+
+- err = ip6_sk_dst_lookup(sk, &dst, fl);
++ security_sk_classify_flow(sk, &fl);
++
++ err = ip6_sk_dst_lookup(sk, &dst, &fl);
+ if (err)
+ goto out;
+ if (final_p)
+- ipv6_addr_copy(&fl->fl6_dst, final_p);
++ ipv6_addr_copy(&fl.fl6_dst, final_p);
+
+- if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
++ if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+ goto out;
+
+ if (hlimit < 0) {
+- if (ipv6_addr_is_multicast(&fl->fl6_dst))
++ if (ipv6_addr_is_multicast(&fl.fl6_dst))
+ hlimit = np->mcast_hops;
+ else
+ hlimit = np->hop_limit;
+@@ -828,19 +763,26 @@ back_from_confirm:
+ do_append_data:
+ up->len += ulen;
+ err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
+- sizeof(struct udphdr), hlimit, tclass, opt, fl,
++ sizeof(struct udphdr), hlimit, tclass, opt, &fl,
+ (struct rt6_info*)dst,
+ corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+ if (err)
+ udp_v6_flush_pending_frames(sk);
+ else if (!corkreq)
+ err = udp_v6_push_pending_frames(sk, up);
++ else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
++ up->pending = 0;
+
+ if (dst) {
+ if (connected) {
+ ip6_dst_store(sk, dst,
+- ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ?
+- &np->daddr : NULL);
++ ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
++ &np->daddr : NULL,
++#ifdef CONFIG_IPV6_SUBTREES
++ ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
++ &np->saddr :
++#endif
++ NULL);
+ } else {
+ dst_release(dst);
+ }
+@@ -855,6 +797,16 @@ out:
+ UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS);
+ return len;
+ }
++ /*
++ * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting
++ * ENOBUFS might not be good (it's not tunable per se), but otherwise
++ * we don't have a good statistic (IpOutDiscards but it can be too many
++ * things). We could add another new stat but at least for now that
++ * seems like overkill.
++ */
++ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
++ UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS);
++ }
+ return err;
+
+ do_confirm:
+diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
+index 0405d74..5c8b7a5 100644
+--- a/net/ipv6/xfrm6_input.c
++++ b/net/ipv6/xfrm6_input.c
+@@ -16,10 +16,10 @@
+ #include <net/ipv6.h>
+ #include <net/xfrm.h>
+
+-int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
++int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi)
+ {
+ int err;
+- u32 seq;
++ __be32 seq;
+ struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
+ struct xfrm_state *x;
+ int xfrm_nr = 0;
+@@ -72,7 +72,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u
+ if (x->mode->input(x, skb))
+ goto drop;
+
+- if (x->props.mode) { /* XXX */
++ if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */
+ decaps = 1;
+ break;
+ }
+@@ -138,3 +138,111 @@ int xfrm6_rcv(struct sk_buff **pskb)
+ {
+ return xfrm6_rcv_spi(*pskb, 0);
+ }
++
++int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
++ xfrm_address_t *saddr, u8 proto)
++{
++ struct xfrm_state *x = NULL;
++ int wildcard = 0;
++ struct in6_addr any;
++ xfrm_address_t *xany;
++ struct xfrm_state *xfrm_vec_one = NULL;
++ int nh = 0;
++ int i = 0;
++
++ ipv6_addr_set(&any, 0, 0, 0, 0);
++ xany = (xfrm_address_t *)&any;
++
++ for (i = 0; i < 3; i++) {
++ xfrm_address_t *dst, *src;
++ switch (i) {
++ case 0:
++ dst = daddr;
++ src = saddr;
++ break;
++ case 1:
++ /* lookup state with wild-card source address */
++ wildcard = 1;
++ dst = daddr;
++ src = xany;
++ break;
++ case 2:
++ default:
++ /* lookup state with wild-card addresses */
++ wildcard = 1; /* XXX */
++ dst = xany;
++ src = xany;
++ break;
++ }
++
++ x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6);
++ if (!x)
++ continue;
++
++ spin_lock(&x->lock);
++
++ if (wildcard) {
++ if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) {
++ spin_unlock(&x->lock);
++ xfrm_state_put(x);
++ x = NULL;
++ continue;
++ }
++ }
++
++ if (unlikely(x->km.state != XFRM_STATE_VALID)) {
++ spin_unlock(&x->lock);
++ xfrm_state_put(x);
++ x = NULL;
++ continue;
++ }
++ if (xfrm_state_check_expire(x)) {
++ spin_unlock(&x->lock);
++ xfrm_state_put(x);
++ x = NULL;
++ continue;
++ }
++
++ nh = x->type->input(x, skb);
++ if (nh <= 0) {
++ spin_unlock(&x->lock);
++ xfrm_state_put(x);
++ x = NULL;
++ continue;
++ }
++
++ x->curlft.bytes += skb->len;
++ x->curlft.packets++;
++
++ spin_unlock(&x->lock);
++
++ xfrm_vec_one = x;
++ break;
++ }
++
++ if (!xfrm_vec_one)
++ goto drop;
++
++ /* Allocate new secpath or COW existing one. */
++ if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
++ struct sec_path *sp;
++ sp = secpath_dup(skb->sp);
++ if (!sp)
++ goto drop;
++ if (skb->sp)
++ secpath_put(skb->sp);
++ skb->sp = sp;
++ }
++
++ if (1 + skb->sp->len > XFRM_MAX_DEPTH)
++ goto drop;
++
++ skb->sp->xvec[skb->sp->len] = xfrm_vec_one;
++ skb->sp->len ++;
++
++ return 1;
++drop:
++ if (xfrm_vec_one)
++ xfrm_state_put(xfrm_vec_one);
++ return -1;
++}
+diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
+new file mode 100644
+index 0000000..edcfffa
+--- /dev/null
++++ b/net/ipv6/xfrm6_mode_beet.c
+@@ -0,0 +1,107 @@
++/*
++ * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6.
++ *
++ * Copyright (c) 2006 Diego Beltrami <diego.beltrami at gmail.com>
++ * Miika Komu <miika at iki.fi>
++ * Herbert Xu <herbert at gondor.apana.org.au>
++ * Abhinav Pathak <abhinav.pathak at hiit.fi>
++ * Jeff Ahrenholz <ahrenholz at gmail.com>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/stringify.h>
++#include <net/dsfield.h>
++#include <net/dst.h>
++#include <net/inet_ecn.h>
++#include <net/ipv6.h>
++#include <net/xfrm.h>
++
++/* Add encapsulation header.
++ *
++ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
++ * The following fields in it shall be filled in by x->type->output:
++ * payload_len
++ *
++ * On exit, skb->h will be set to the start of the encapsulation header to be
++ * filled in by x->type->output and skb->nh will be set to the nextheader field
++ * of the extension header directly preceding the encapsulation header, or in
++ * its absence, that of the top IP header. The value of skb->data will always
++ * point to the top IP header.
++ */
++static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct ipv6hdr *iph, *top_iph;
++ u8 *prevhdr;
++ int hdr_len;
++
++ skb_push(skb, x->props.header_len);
++ iph = skb->nh.ipv6h;
++
++ hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
++ skb->nh.raw = prevhdr - x->props.header_len;
++ skb->h.raw = skb->data + hdr_len;
++ memmove(skb->data, iph, hdr_len);
++
++ skb->nh.raw = skb->data;
++ top_iph = skb->nh.ipv6h;
++ skb->nh.raw = &top_iph->nexthdr;
++ skb->h.ipv6h = top_iph + 1;
++
++ ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
++ ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
++
++ return 0;
++}
++
++static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct ipv6hdr *ip6h;
++ int size = sizeof(struct ipv6hdr);
++ int err = -EINVAL;
++
++ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
++ goto out;
++
++ skb_push(skb, size);
++ memmove(skb->data, skb->nh.raw, size);
++ skb->nh.raw = skb->data;
++
++ skb->mac.raw = memmove(skb->data - skb->mac_len,
++ skb->mac.raw, skb->mac_len);
++
++ ip6h = skb->nh.ipv6h;
++ ip6h->payload_len = htons(skb->len - size);
++ ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
++ ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
++ err = 0;
++out:
++ return err;
++}
++
++static struct xfrm_mode xfrm6_beet_mode = {
++ .input = xfrm6_beet_input,
++ .output = xfrm6_beet_output,
++ .owner = THIS_MODULE,
++ .encap = XFRM_MODE_BEET,
++};
++
++static int __init xfrm6_beet_init(void)
++{
++ return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
++}
++
++static void __exit xfrm6_beet_exit(void)
++{
++ int err;
++
++ err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
++ BUG_ON(err);
++}
++
++module_init(xfrm6_beet_init);
++module_exit(xfrm6_beet_exit);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET);
+diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
+new file mode 100644
+index 0000000..6031c16
+--- /dev/null
++++ b/net/ipv6/xfrm6_mode_ro.c
+@@ -0,0 +1,93 @@
++/*
++ * xfrm6_mode_ro.c - Route optimization mode for IPv6.
++ *
++ * Copyright (C)2003-2006 Helsinki University of Technology
++ * Copyright (C)2003-2006 USAGI/WIDE Project
++ *
++ * 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
++ */
++/*
++ * Authors:
++ * Noriaki TAKAMIYA @USAGI
++ * Masahide NAKAMURA @USAGI
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/stringify.h>
++#include <net/ipv6.h>
++#include <net/xfrm.h>
++
++/* Add route optimization header space.
++ *
++ * The IP header and mutable extension headers will be moved forward to make
++ * space for the route optimization header.
++ *
++ * On exit, skb->h will be set to the start of the encapsulation header to be
++ * filled in by x->type->output and skb->nh will be set to the nextheader field
++ * of the extension header directly preceding the encapsulation header, or in
++ * its absence, that of the top IP header. The value of skb->data will always
++ * point to the top IP header.
++ */
++static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
++{
++ struct ipv6hdr *iph;
++ u8 *prevhdr;
++ int hdr_len;
++
++ skb_push(skb, x->props.header_len);
++ iph = skb->nh.ipv6h;
++
++ hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
++ skb->nh.raw = prevhdr - x->props.header_len;
++ skb->h.raw = skb->data + hdr_len;
++ memmove(skb->data, iph, hdr_len);
++ return 0;
++}
++
++/*
++ * Do nothing about routing optimization header unlike IPsec.
++ */
++static int xfrm6_ro_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++ return 0;
++}
++
++static struct xfrm_mode xfrm6_ro_mode = {
++ .input = xfrm6_ro_input,
++ .output = xfrm6_ro_output,
++ .owner = THIS_MODULE,
++ .encap = XFRM_MODE_ROUTEOPTIMIZATION,
++};
++
++static int __init xfrm6_ro_init(void)
++{
++ return xfrm_register_mode(&xfrm6_ro_mode, AF_INET6);
++}
++
++static void __exit xfrm6_ro_exit(void)
++{
++ int err;
++
++ err = xfrm_unregister_mode(&xfrm6_ro_mode, AF_INET6);
++ BUG_ON(err);
++}
++
++module_init(xfrm6_ro_init);
++module_exit(xfrm6_ro_exit);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_ROUTEOPTIMIZATION);
+diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c
+index 711d713..3a4b39b 100644
+--- a/net/ipv6/xfrm6_mode_transport.c
++++ b/net/ipv6/xfrm6_mode_transport.c
+@@ -25,9 +25,8 @@
+ * its absence, that of the top IP header. The value of skb->data will always
+ * point to the top IP header.
+ */
+-static int xfrm6_transport_output(struct sk_buff *skb)
++static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
+ {
+- struct xfrm_state *x = skb->dst->xfrm;
+ struct ipv6hdr *iph;
+ u8 *prevhdr;
+ int hdr_len;
+@@ -35,7 +34,7 @@ static int xfrm6_transport_output(struct
+ skb_push(skb, x->props.header_len);
+ iph = skb->nh.ipv6h;
+
+- hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
++ hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
+ skb->nh.raw = prevhdr - x->props.header_len;
+ skb->h.raw = skb->data + hdr_len;
+ memmove(skb->data, iph, hdr_len);
+diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
+index 8af79be..5e7d8a7 100644
+--- a/net/ipv6/xfrm6_mode_tunnel.c
++++ b/net/ipv6/xfrm6_mode_tunnel.c
+@@ -37,10 +37,9 @@ static inline void ipip6_ecn_decapsulate
+ * its absence, that of the top IP header. The value of skb->data will always
+ * point to the top IP header.
+ */
+-static int xfrm6_tunnel_output(struct sk_buff *skb)
++static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb->dst;
+- struct xfrm_state *x = dst->xfrm;
+ struct ipv6hdr *iph, *top_iph;
+ int dsfield;
+
+diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
+index c8c8b44..c260ea1 100644
+--- a/net/ipv6/xfrm6_output.c
++++ b/net/ipv6/xfrm6_output.c
+@@ -17,6 +17,12 @@
+ #include <net/ipv6.h>
+ #include <net/xfrm.h>
+
++int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
++ u8 **prevhdr)
++{
++ return ip6_find_1stfragopt(skb, prevhdr);
++}
++
+ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
+ {
+ int mtu, ret = 0;
+@@ -41,13 +47,13 @@ static int xfrm6_output_one(struct sk_bu
+ struct xfrm_state *x = dst->xfrm;
+ int err;
+
+- if (skb->ip_summed == CHECKSUM_HW) {
+- err = skb_checksum_help(skb, 0);
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
++ err = skb_checksum_help(skb);
+ if (err)
+ goto error_nolock;
+ }
+
+- if (x->props.mode) {
++ if (x->props.mode == XFRM_MODE_TUNNEL) {
+ err = xfrm6_tunnel_check_size(skb);
+ if (err)
+ goto error_nolock;
+@@ -59,7 +65,7 @@ static int xfrm6_output_one(struct sk_bu
+ if (err)
+ goto error;
+
+- err = x->mode->output(skb);
++ err = x->mode->output(x, skb);
+ if (err)
+ goto error;
+
+@@ -69,6 +75,8 @@ static int xfrm6_output_one(struct sk_bu
+
+ x->curlft.bytes += skb->len;
+ x->curlft.packets++;
++ if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION)
++ x->lastused = (u64)xtime.tv_sec;
+
+ spin_unlock_bh(&x->lock);
+
+@@ -80,7 +88,7 @@ static int xfrm6_output_one(struct sk_bu
+ }
+ dst = skb->dst;
+ x = dst->xfrm;
+- } while (x && !x->props.mode);
++ } while (x && (x->props.mode != XFRM_MODE_TUNNEL));
+
+ IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
+ err = 0;
+diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
+index 73cd250..d400f8f 100644
+--- a/net/ipv6/xfrm6_policy.c
++++ b/net/ipv6/xfrm6_policy.c
+@@ -18,19 +18,44 @@
+ #include <net/ip.h>
+ #include <net/ipv6.h>
+ #include <net/ip6_route.h>
++#ifdef CONFIG_IPV6_MIP6
++#include <net/mip6.h>
++#endif
+
+ static struct dst_ops xfrm6_dst_ops;
+ static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
+
+-static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
++static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
+ {
+- int err = 0;
+- *dst = (struct xfrm_dst*)ip6_route_output(NULL, fl);
+- if (!*dst)
+- err = -ENETUNREACH;
++ struct dst_entry *dst = ip6_route_output(NULL, fl);
++ int err = dst->error;
++ if (!err)
++ *xdst = (struct xfrm_dst *) dst;
++ else
++ dst_release(dst);
+ return err;
+ }
+
++static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
++{
++ struct rt6_info *rt;
++ struct flowi fl_tunnel = {
++ .nl_u = {
++ .ip6_u = {
++ .daddr = *(struct in6_addr *)&daddr->a6,
++ },
++ },
++ };
++
++ if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
++ ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
++ (struct in6_addr *)&saddr->a6);
++ dst_release(&rt->u.dst);
++ return 0;
++ }
++ return -EHOSTUNREACH;
++}
++
+ static struct dst_entry *
+ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
+ {
+@@ -50,7 +75,9 @@ __xfrm6_find_bundle(struct flowi *fl, st
+ xdst->u.rt6.rt6i_src.plen);
+ if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) &&
+ ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) &&
+- xfrm_bundle_ok(xdst, fl, AF_INET6)) {
++ xfrm_bundle_ok(policy, xdst, fl, AF_INET6,
++ (xdst->u.rt6.rt6i_dst.plen != 128 ||
++ xdst->u.rt6.rt6i_src.plen != 128))) {
+ dst_clone(dst);
+ break;
+ }
+@@ -59,6 +86,40 @@ __xfrm6_find_bundle(struct flowi *fl, st
+ return dst;
+ }
+
++static inline struct in6_addr*
++__xfrm6_bundle_addr_remote(struct xfrm_state *x, struct in6_addr *addr)
++{
++ return (x->type->remote_addr) ?
++ (struct in6_addr*)x->type->remote_addr(x, (xfrm_address_t *)addr) :
++ (struct in6_addr*)&x->id.daddr;
++}
++
++static inline struct in6_addr*
++__xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr)
++{
++ return (x->type->local_addr) ?
++ (struct in6_addr*)x->type->local_addr(x, (xfrm_address_t *)addr) :
++ (struct in6_addr*)&x->props.saddr;
++}
++
++static inline void
++__xfrm6_bundle_len_inc(int *len, int *nflen, struct xfrm_state *x)
++{
++ if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
++ *nflen += x->props.header_len;
++ else
++ *len += x->props.header_len;
++}
++
++static inline void
++__xfrm6_bundle_len_dec(int *len, int *nflen, struct xfrm_state *x)
++{
++ if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
++ *nflen -= x->props.header_len;
++ else
++ *len -= x->props.header_len;
++}
++
+ /* Allocate chain of dst_entry's, attach known xfrm's, calculate
+ * all the metrics... Shortly, bundle a bundle.
+ */
+@@ -83,6 +144,7 @@ __xfrm6_bundle_create(struct xfrm_policy
+ int i;
+ int err = 0;
+ int header_len = 0;
++ int nfheader_len = 0;
+ int trailer_len = 0;
+
+ dst = dst_prev = NULL;
+@@ -109,17 +171,18 @@ __xfrm6_bundle_create(struct xfrm_policy
+
+ xdst = (struct xfrm_dst *)dst1;
+ xdst->route = &rt->u.dst;
++ xdst->genid = xfrm[i]->genid;
+ if (rt->rt6i_node)
+ xdst->route_cookie = rt->rt6i_node->fn_sernum;
+
+ dst1->next = dst_prev;
+ dst_prev = dst1;
+- if (xfrm[i]->props.mode) {
+- remote = (struct in6_addr*)&xfrm[i]->id.daddr;
+- local = (struct in6_addr*)&xfrm[i]->props.saddr;
++ if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
++ remote = __xfrm6_bundle_addr_remote(xfrm[i], remote);
++ local = __xfrm6_bundle_addr_local(xfrm[i], local);
+ tunnel = 1;
+ }
+- header_len += xfrm[i]->props.header_len;
++ __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]);
+ trailer_len += xfrm[i]->props.trailer_len;
+
+ if (tunnel) {
+@@ -154,6 +217,7 @@ __xfrm6_bundle_create(struct xfrm_policy
+ dst_prev->flags |= DST_HOST;
+ dst_prev->lastuse = jiffies;
+ dst_prev->header_len = header_len;
++ dst_prev->nfheader_len = nfheader_len;
+ dst_prev->trailer_len = trailer_len;
+ memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
+
+@@ -172,7 +236,7 @@ __xfrm6_bundle_create(struct xfrm_policy
+ x->u.rt6.rt6i_src = rt0->rt6i_src;
+ x->u.rt6.rt6i_idev = rt0->rt6i_idev;
+ in6_dev_hold(rt0->rt6i_idev);
+- header_len -= x->u.dst.xfrm->props.header_len;
++ __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm);
+ trailer_len -= x->u.dst.xfrm->props.trailer_len;
+ }
+
+@@ -232,6 +296,18 @@ _decode_session6(struct sk_buff *skb, st
+ fl->proto = nexthdr;
+ return;
+
++#ifdef CONFIG_IPV6_MIP6
++ case IPPROTO_MH:
++ if (pskb_may_pull(skb, skb->nh.raw + offset + 3 - skb->data)) {
++ struct ip6_mh *mh;
++ mh = (struct ip6_mh *)exthdr;
++
++ fl->fl_mh_type = mh->ip6mh_type;
++ }
++ fl->proto = nexthdr;
++ return;
++#endif
++
+ /* XXX Why are there these headers? */
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+@@ -308,6 +384,7 @@ static struct xfrm_policy_afinfo xfrm6_p
+ .family = AF_INET6,
+ .dst_ops = &xfrm6_dst_ops,
+ .dst_lookup = xfrm6_dst_lookup,
++ .get_saddr = xfrm6_get_saddr,
+ .find_bundle = __xfrm6_find_bundle,
+ .bundle_create = __xfrm6_bundle_create,
+ .decode_session = _decode_session6,
+diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
+index b33296b..9ddaa9d 100644
+--- a/net/ipv6/xfrm6_state.c
++++ b/net/ipv6/xfrm6_state.c
+@@ -29,9 +29,9 @@ __xfrm6_init_tempsel(struct xfrm_state *
+ ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
+ ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
+ x->sel.dport = xfrm_flowi_dport(fl);
+- x->sel.dport_mask = ~0;
++ x->sel.dport_mask = htons(0xffff);
+ x->sel.sport = xfrm_flowi_sport(fl);
+- x->sel.sport_mask = ~0;
++ x->sel.sport_mask = htons(0xffff);
+ x->sel.prefixlen_d = 128;
+ x->sel.prefixlen_s = 128;
+ x->sel.proto = fl->proto;
+@@ -42,102 +42,135 @@ __xfrm6_init_tempsel(struct xfrm_state *
+ memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
+ if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
+ memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
+- if (tmpl->mode && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
+- struct rt6_info *rt;
+- struct flowi fl_tunnel = {
+- .nl_u = {
+- .ip6_u = {
+- .daddr = *(struct in6_addr *)daddr,
+- }
+- }
+- };
+- if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
+- &fl_tunnel, AF_INET6)) {
+- ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
+- (struct in6_addr *)&x->props.saddr);
+- dst_release(&rt->u.dst);
+- }
+- }
+ x->props.mode = tmpl->mode;
+ x->props.reqid = tmpl->reqid;
+ x->props.family = AF_INET6;
+ }
+
+-static struct xfrm_state *
+-__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
++static int
++__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
+ {
+- unsigned h = __xfrm6_spi_hash(daddr, spi, proto);
+- struct xfrm_state *x;
+-
+- list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) {
+- if (x->props.family == AF_INET6 &&
+- spi == x->id.spi &&
+- ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
+- proto == x->id.proto) {
+- xfrm_state_hold(x);
+- return x;
++ int i;
++ int j = 0;
++
++ /* Rule 1: select IPsec transport except AH */
++ for (i = 0; i < n; i++) {
++ if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
++ src[i]->id.proto != IPPROTO_AH) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
++ }
++ if (j == n)
++ goto end;
++
++ /* Rule 2: select MIPv6 RO or inbound trigger */
++#ifdef CONFIG_IPV6_MIP6
++ for (i = 0; i < n; i++) {
++ if (src[i] &&
++ (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
++ src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
++ }
++ if (j == n)
++ goto end;
++#endif
++
++ /* Rule 3: select IPsec transport AH */
++ for (i = 0; i < n; i++) {
++ if (src[i] &&
++ src[i]->props.mode == XFRM_MODE_TRANSPORT &&
++ src[i]->id.proto == IPPROTO_AH) {
++ dst[j++] = src[i];
++ src[i] = NULL;
+ }
+ }
+- return NULL;
++ if (j == n)
++ goto end;
++
++ /* Rule 4: select IPsec tunnel */
++ for (i = 0; i < n; i++) {
++ if (src[i] &&
++ src[i]->props.mode == XFRM_MODE_TUNNEL) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
++ }
++ if (likely(j == n))
++ goto end;
++
++ /* Final rule */
++ for (i = 0; i < n; i++) {
++ if (src[i]) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
++ }
++
++ end:
++ return 0;
+ }
+
+-static struct xfrm_state *
+-__xfrm6_find_acq(u8 mode, u32 reqid, u8 proto,
+- xfrm_address_t *daddr, xfrm_address_t *saddr,
+- int create)
++static int
++__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
+ {
+- struct xfrm_state *x, *x0;
+- unsigned h = __xfrm6_dst_hash(daddr);
+-
+- x0 = NULL;
+-
+- list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) {
+- if (x->props.family == AF_INET6 &&
+- ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
+- mode == x->props.mode &&
+- proto == x->id.proto &&
+- ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) &&
+- reqid == x->props.reqid &&
+- x->km.state == XFRM_STATE_ACQ &&
+- !x->id.spi) {
+- x0 = x;
+- break;
+- }
++ int i;
++ int j = 0;
++
++ /* Rule 1: select IPsec transport */
++ for (i = 0; i < n; i++) {
++ if (src[i]->mode == XFRM_MODE_TRANSPORT) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
+ }
+- if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
+- ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6,
+- (struct in6_addr *)daddr);
+- ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6,
+- (struct in6_addr *)saddr);
+- x0->sel.prefixlen_d = 128;
+- x0->sel.prefixlen_s = 128;
+- ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6,
+- (struct in6_addr *)saddr);
+- x0->km.state = XFRM_STATE_ACQ;
+- ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6,
+- (struct in6_addr *)daddr);
+- x0->id.proto = proto;
+- x0->props.family = AF_INET6;
+- x0->props.mode = mode;
+- x0->props.reqid = reqid;
+- x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
+- xfrm_state_hold(x0);
+- x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
+- add_timer(&x0->timer);
+- xfrm_state_hold(x0);
+- list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
+- wake_up(&km_waitq);
++ if (j == n)
++ goto end;
++
++ /* Rule 2: select MIPv6 RO or inbound trigger */
++#ifdef CONFIG_IPV6_MIP6
++ for (i = 0; i < n; i++) {
++ if (src[i] &&
++ (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
++ src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
+ }
+- if (x0)
+- xfrm_state_hold(x0);
+- return x0;
++ if (j == n)
++ goto end;
++#endif
++
++ /* Rule 3: select IPsec tunnel */
++ for (i = 0; i < n; i++) {
++ if (src[i] &&
++ src[i]->mode == XFRM_MODE_TUNNEL) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
++ }
++ if (likely(j == n))
++ goto end;
++
++ /* Final rule */
++ for (i = 0; i < n; i++) {
++ if (src[i]) {
++ dst[j++] = src[i];
++ src[i] = NULL;
++ }
++ }
++
++ end:
++ return 0;
+ }
+
+ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
+ .family = AF_INET6,
+ .init_tempsel = __xfrm6_init_tempsel,
+- .state_lookup = __xfrm6_state_lookup,
+- .find_acq = __xfrm6_find_acq,
++ .tmpl_sort = __xfrm6_tmpl_sort,
++ .state_sort = __xfrm6_state_sort,
+ };
+
+ void __init xfrm6_state_init(void)
+diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
+index c8f9369..7931e4f 100644
+--- a/net/ipv6/xfrm6_tunnel.c
++++ b/net/ipv6/xfrm6_tunnel.c
+@@ -135,7 +135,7 @@ u32 xfrm6_tunnel_spi_lookup(xfrm_address
+ x6spi = __xfrm6_tunnel_spi_lookup(saddr);
+ spi = x6spi ? x6spi->spi : 0;
+ read_unlock_bh(&xfrm6_tunnel_spi_lock);
+- return spi;
++ return htonl(spi);
+ }
+
+ EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
+@@ -210,7 +210,7 @@ u32 xfrm6_tunnel_alloc_spi(xfrm_address_
+ spi = __xfrm6_tunnel_alloc_spi(saddr);
+ write_unlock_bh(&xfrm6_tunnel_spi_lock);
+
+- return spi;
++ return htonl(spi);
+ }
+
+ EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
+@@ -258,7 +258,7 @@ static int xfrm6_tunnel_input(struct xfr
+ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
+ {
+ struct ipv6hdr *iph = skb->nh.ipv6h;
+- u32 spi;
++ __be32 spi;
+
+ spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
+ return xfrm6_rcv_spi(skb, spi);
+@@ -307,7 +307,7 @@ static int xfrm6_tunnel_err(struct sk_bu
+
+ static int xfrm6_tunnel_init_state(struct xfrm_state *x)
+ {
+- if (!x->props.mode)
++ if (x->props.mode != XFRM_MODE_TUNNEL)
+ return -EINVAL;
+
+ if (x->encap)
+diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
+index bef3f61..76c6615 100644
+--- a/net/ipx/af_ipx.c
++++ b/net/ipx/af_ipx.c
+@@ -83,13 +83,13 @@ DEFINE_SPINLOCK(ipx_interfaces_lock);
+ struct ipx_interface *ipx_primary_net;
+ struct ipx_interface *ipx_internal_net;
+
+-extern int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
++extern int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
+ unsigned char *node);
+ extern void ipxrtr_del_routes(struct ipx_interface *intrfc);
+ extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
+ struct iovec *iov, int len, int noblock);
+ extern int ipxrtr_route_skb(struct sk_buff *skb);
+-extern struct ipx_route *ipxrtr_lookup(__u32 net);
++extern struct ipx_route *ipxrtr_lookup(__be32 net);
+ extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
+
+ #undef IPX_REFCNT_DEBUG
+@@ -177,7 +177,7 @@ static void ipxitf_clear_primary_net(voi
+ }
+
+ static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
+- unsigned short datalink)
++ __be16 datalink)
+ {
+ struct ipx_interface *i;
+
+@@ -190,7 +190,7 @@ out:
+ }
+
+ static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
+- unsigned short datalink)
++ __be16 datalink)
+ {
+ struct ipx_interface *i;
+
+@@ -202,7 +202,7 @@ static struct ipx_interface *ipxitf_find
+ return i;
+ }
+
+-struct ipx_interface *ipxitf_find_using_net(__u32 net)
++struct ipx_interface *ipxitf_find_using_net(__be32 net)
+ {
+ struct ipx_interface *i;
+
+@@ -237,7 +237,7 @@ static void ipxitf_insert_socket(struct
+
+ /* caller must hold intrfc->if_sklist_lock */
+ static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc,
+- unsigned short port)
++ __be16 port)
+ {
+ struct sock *s;
+ struct hlist_node *node;
+@@ -252,7 +252,7 @@ found:
+
+ /* caller must hold a reference to intrfc */
+ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc,
+- unsigned short port)
++ __be16 port)
+ {
+ struct sock *s;
+
+@@ -268,7 +268,7 @@ static struct sock *ipxitf_find_socket(s
+ #ifdef CONFIG_IPX_INTERN
+ static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc,
+ unsigned char *ipx_node,
+- unsigned short port)
++ __be16 port)
+ {
+ struct sock *s;
+ struct hlist_node *node;
+@@ -600,10 +600,10 @@ int ipxitf_send(struct ipx_interface *in
+
+ /* see if we need to include the netnum in the route list */
+ if (IPX_SKB_CB(skb)->last_hop.index >= 0) {
+- u32 *last_hop = (u32 *)(((u8 *) skb->data) +
++ __be32 *last_hop = (__be32 *)(((u8 *) skb->data) +
+ sizeof(struct ipxhdr) +
+ IPX_SKB_CB(skb)->last_hop.index *
+- sizeof(u32));
++ sizeof(__be32));
+ *last_hop = IPX_SKB_CB(skb)->last_hop.netnum;
+ IPX_SKB_CB(skb)->last_hop.index = -1;
+ }
+@@ -772,7 +772,7 @@ static void ipxitf_discover_netnum(struc
+ } else {
+ printk(KERN_WARNING "IPX: Network number collision "
+ "%lx\n %s %s and %s %s\n",
+- (unsigned long) htonl(cb->ipx_source_net),
++ (unsigned long) ntohl(cb->ipx_source_net),
+ ipx_device_name(i),
+ ipx_frame_name(i->if_dlink_type),
+ ipx_device_name(intrfc),
+@@ -812,7 +812,7 @@ static int ipxitf_pprop(struct ipx_inter
+ int i, rc = -EINVAL;
+ struct ipx_interface *ifcs;
+ char *c;
+- u32 *l;
++ __be32 *l;
+
+ /* Illegal packet - too many hops or too short */
+ /* We decide to throw it away: no broadcasting, no local processing.
+@@ -833,7 +833,7 @@ static int ipxitf_pprop(struct ipx_inter
+ goto out;
+
+ c = ((u8 *) ipx) + sizeof(struct ipxhdr);
+- l = (u32 *) c;
++ l = (__be32 *) c;
+
+ /* Don't broadcast packet if already seen this net */
+ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++)
+@@ -855,7 +855,7 @@ static int ipxitf_pprop(struct ipx_inter
+ /* That aren't in the list */
+ if (ifcs == intrfc)
+ continue;
+- l = (__u32 *) c;
++ l = (__be32 *) c;
+ /* don't consider the last entry in the packet list,
+ * it is our netnum, and it is not there yet */
+ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++)
+@@ -885,8 +885,8 @@ static void ipxitf_insert(struct ipx_int
+ ipx_primary_net = intrfc;
+ }
+
+-static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum,
+- unsigned short dlink_type,
++static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __be32 netnum,
++ __be16 dlink_type,
+ struct datalink_proto *dlink,
+ unsigned char internal,
+ int ipx_offset)
+@@ -960,7 +960,7 @@ static __be16 ipx_map_frame_type(unsigne
+ static int ipxitf_create(struct ipx_interface_definition *idef)
+ {
+ struct net_device *dev;
+- unsigned short dlink_type = 0;
++ __be16 dlink_type = 0;
+ struct datalink_proto *datalink = NULL;
+ struct ipx_interface *intrfc;
+ int rc;
+@@ -1073,7 +1073,7 @@ out:
+ static int ipxitf_delete(struct ipx_interface_definition *idef)
+ {
+ struct net_device *dev = NULL;
+- unsigned short dlink_type = 0;
++ __be16 dlink_type = 0;
+ struct ipx_interface *intrfc;
+ int rc = 0;
+
+@@ -1110,7 +1110,7 @@ out:
+ }
+
+ static struct ipx_interface *ipxitf_auto_create(struct net_device *dev,
+- unsigned short dlink_type)
++ __be16 dlink_type)
+ {
+ struct ipx_interface *intrfc = NULL;
+ struct datalink_proto *datalink;
+@@ -1122,7 +1122,7 @@ static struct ipx_interface *ipxitf_auto
+ if (dev->addr_len > IPX_NODE_LEN)
+ goto out;
+
+- switch (htons(dlink_type)) {
++ switch (ntohs(dlink_type)) {
+ case ETH_P_IPX: datalink = pEII_datalink; break;
+ case ETH_P_802_2: datalink = p8022_datalink; break;
+ case ETH_P_SNAP: datalink = pSNAP_datalink; break;
+@@ -1234,27 +1234,27 @@ static int ipxitf_ioctl(unsigned int cmd
+ /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
+ /* This functions should *not* mess with packet contents */
+
+-__u16 ipx_cksum(struct ipxhdr *packet, int length)
++__be16 ipx_cksum(struct ipxhdr *packet, int length)
+ {
+ /*
+ * NOTE: sum is a net byte order quantity, which optimizes the
+ * loop. This only works on big and little endian machines. (I
+ * don't know of a machine that isn't.)
+ */
+- /* start at ipx_dest - We skip the checksum field and start with
+- * ipx_type before the loop, not considering ipx_tctrl in the calc */
+- __u16 *p = (__u16 *)&packet->ipx_dest;
+- __u32 i = (length >> 1) - 1; /* Number of complete words */
+- __u32 sum = packet->ipx_type << sizeof(packet->ipx_tctrl);
+-
+- /* Loop through all complete words except the checksum field,
+- * ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */
+- while (--i)
++ /* handle the first 3 words separately; checksum should be skipped
++ * and ipx_tctrl masked out */
++ __u16 *p = (__u16 *)packet;
++ __u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff));
++ __u32 i = (length >> 1) - 3; /* Number of remaining complete words */
++
++ /* Loop through them */
++ p += 3;
++ while (i--)
+ sum += *p++;
+
+ /* Add on the last part word if it exists */
+ if (packet->ipx_pktsize & htons(1))
+- sum += ntohs(0xff00) & *p;
++ sum += (__force u16)htons(0xff00) & *p;
+
+ /* Do final fixup */
+ sum = (sum & 0xffff) + (sum >> 16);
+@@ -1263,10 +1263,17 @@ __u16 ipx_cksum(struct ipxhdr *packet, i
+ if (sum >= 0x10000)
+ sum++;
+
+- return ~sum;
++ /*
++ * Leave 0 alone; we don't want 0xffff here. Note that we can't get
++ * here with 0x10000, so this check is the same as ((__u16)sum)
++ */
++ if (sum)
++ sum = ~sum;
++
++ return (__force __be16)sum;
+ }
+
+-const char *ipx_frame_name(unsigned short frame)
++const char *ipx_frame_name(__be16 frame)
+ {
+ char* rc = "None";
+
+@@ -1401,7 +1408,7 @@ out:
+
+ /* caller must hold a reference to intrfc */
+
+-static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc)
++static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc)
+ {
+ unsigned short socketNum = intrfc->if_sknum;
+
+@@ -1410,7 +1417,7 @@ static unsigned short ipx_first_free_soc
+ if (socketNum < IPX_MIN_EPHEMERAL_SOCKET)
+ socketNum = IPX_MIN_EPHEMERAL_SOCKET;
+
+- while (__ipxitf_find_socket(intrfc, ntohs(socketNum)))
++ while (__ipxitf_find_socket(intrfc, htons(socketNum)))
+ if (socketNum > IPX_MAX_EPHEMERAL_SOCKET)
+ socketNum = IPX_MIN_EPHEMERAL_SOCKET;
+ else
+@@ -1419,7 +1426,7 @@ static unsigned short ipx_first_free_soc
+ spin_unlock_bh(&intrfc->if_sklist_lock);
+ intrfc->if_sknum = socketNum;
+
+- return ntohs(socketNum);
++ return htons(socketNum);
+ }
+
+ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+@@ -1473,7 +1480,7 @@ static int ipx_bind(struct socket *sock,
+ ipxs->port)) {
+ SOCK_DEBUG(sk,
+ "IPX: bind failed because port %X in use.\n",
+- ntohs((int)addr->sipx_port));
++ ntohs(addr->sipx_port));
+ goto out_put;
+ }
+ } else {
+@@ -1488,7 +1495,7 @@ static int ipx_bind(struct socket *sock,
+ if (ipxitf_find_socket(intrfc, addr->sipx_port)) {
+ SOCK_DEBUG(sk,
+ "IPX: bind failed because port %X in use.\n",
+- ntohs((int)addr->sipx_port));
++ ntohs(addr->sipx_port));
+ goto out_put;
+ }
+ }
+@@ -1665,7 +1672,7 @@ static int ipx_rcv(struct sk_buff *skb,
+ intrfc = ipxitf_find_using_phys(dev, pt->type);
+ if (!intrfc) {
+ if (ipxcfg_auto_create_interfaces &&
+- ntohl(IPX_SKB_CB(skb)->ipx_dest_net)) {
++ IPX_SKB_CB(skb)->ipx_dest_net) {
+ intrfc = ipxitf_auto_create(dev, pt->type);
+ if (intrfc)
+ ipxitf_hold(intrfc);
+diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
+index 4c0c712..b7463df 100644
+--- a/net/ipx/ipx_proc.c
++++ b/net/ipx/ipx_proc.c
+@@ -260,22 +260,22 @@ static int ipx_seq_socket_show(struct se
+ ipxs = ipx_sk(s);
+ #ifdef CONFIG_IPX_INTERN
+ seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
+- (unsigned long)htonl(ipxs->intrfc->if_netnum),
++ (unsigned long)ntohl(ipxs->intrfc->if_netnum),
+ ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3],
+- ipxs->node[4], ipxs->node[5], htons(ipxs->port));
++ ipxs->node[4], ipxs->node[5], ntohs(ipxs->port));
+ #else
+- seq_printf(seq, "%08lX:%04X ", (unsigned long) htonl(ipxs->intrfc->if_netnum),
+- htons(ipxs->port));
++ seq_printf(seq, "%08lX:%04X ", (unsigned long) ntohl(ipxs->intrfc->if_netnum),
++ ntohs(ipxs->port));
+ #endif /* CONFIG_IPX_INTERN */
+ if (s->sk_state != TCP_ESTABLISHED)
+ seq_printf(seq, "%-28s", "Not_Connected");
+ else {
+ seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
+- (unsigned long)htonl(ipxs->dest_addr.net),
++ (unsigned long)ntohl(ipxs->dest_addr.net),
+ ipxs->dest_addr.node[0], ipxs->dest_addr.node[1],
+ ipxs->dest_addr.node[2], ipxs->dest_addr.node[3],
+ ipxs->dest_addr.node[4], ipxs->dest_addr.node[5],
+- htons(ipxs->dest_addr.sock));
++ ntohs(ipxs->dest_addr.sock));
+ }
+
+ seq_printf(seq, "%08X %08X %02X %03d\n",
+diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c
+index a30dbb1..68560ee 100644
+--- a/net/ipx/ipx_route.c
++++ b/net/ipx/ipx_route.c
+@@ -19,17 +19,17 @@ DEFINE_RWLOCK(ipx_routes_lock);
+
+ extern struct ipx_interface *ipx_internal_net;
+
+-extern __u16 ipx_cksum(struct ipxhdr *packet, int length);
+-extern struct ipx_interface *ipxitf_find_using_net(__u32 net);
++extern __be16 ipx_cksum(struct ipxhdr *packet, int length);
++extern struct ipx_interface *ipxitf_find_using_net(__be32 net);
+ extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
+ struct sk_buff *skb, int copy);
+ extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
+ struct sk_buff *skb, int copy);
+ extern int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb,
+ char *node);
+-extern struct ipx_interface *ipxitf_find_using_net(__u32 net);
++extern struct ipx_interface *ipxitf_find_using_net(__be32 net);
+
+-struct ipx_route *ipxrtr_lookup(__u32 net)
++struct ipx_route *ipxrtr_lookup(__be32 net)
+ {
+ struct ipx_route *r;
+
+@@ -48,7 +48,7 @@ unlock:
+ /*
+ * Caller must hold a reference to intrfc
+ */
+-int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
++int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
+ unsigned char *node)
+ {
+ struct ipx_route *rt;
+@@ -118,7 +118,7 @@ out:
+ return rc;
+ }
+
+-static int ipxrtr_delete(__u32 net)
++static int ipxrtr_delete(__be32 net)
+ {
+ struct ipx_route *r, *tmp;
+ int rc;
+@@ -238,7 +238,7 @@ int ipxrtr_route_packet(struct sock *sk,
+
+ /* Apply checksum. Not allowed on 802.3 links. */
+ if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023))
+- ipx->ipx_checksum = 0xFFFF;
++ ipx->ipx_checksum = htons(0xFFFF);
+ else
+ ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
+
+diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
+index 17699ee..7e1aea8 100644
+--- a/net/irda/af_irda.c
++++ b/net/irda/af_irda.c
+@@ -132,13 +132,14 @@ static void irda_disconnect_indication(v
+
+ /* Prevent race conditions with irda_release() and irda_shutdown() */
+ if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) {
++ lock_sock(sk);
+ sk->sk_state = TCP_CLOSE;
+ sk->sk_err = ECONNRESET;
+ sk->sk_shutdown |= SEND_SHUTDOWN;
+
+ sk->sk_state_change(sk);
+- /* Uh-oh... Should use sock_orphan ? */
+- sock_set_flag(sk, SOCK_DEAD);
++ sock_orphan(sk);
++ release_sock(sk);
+
+ /* Close our TSAP.
+ * If we leave it open, IrLMP put it back into the list of
+@@ -308,7 +309,8 @@ static void irda_connect_response(struct
+
+ IRDA_ASSERT(self != NULL, return;);
+
+- skb = alloc_skb(64, GFP_ATOMIC);
++ skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
++ GFP_ATOMIC);
+ if (skb == NULL) {
+ IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",
+ __FUNCTION__);
+@@ -1212,6 +1214,7 @@ static int irda_release(struct socket *s
+ if (sk == NULL)
+ return 0;
+
++ lock_sock(sk);
+ sk->sk_state = TCP_CLOSE;
+ sk->sk_shutdown |= SEND_SHUTDOWN;
+ sk->sk_state_change(sk);
+@@ -1221,6 +1224,7 @@ static int irda_release(struct socket *s
+
+ sock_orphan(sk);
+ sock->sk = NULL;
++ release_sock(sk);
+
+ /* Purge queues (see sock_init_data()) */
+ skb_queue_purge(&sk->sk_receive_queue);
+@@ -1353,6 +1357,7 @@ static int irda_recvmsg_dgram(struct kio
+ IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+
+ IRDA_ASSERT(self != NULL, return -1;);
++ IRDA_ASSERT(!sock_error(sk), return -1;);
+
+ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ flags & MSG_DONTWAIT, &err);
+@@ -1405,6 +1410,7 @@ static int irda_recvmsg_stream(struct ki
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+ IRDA_ASSERT(self != NULL, return -1;);
++ IRDA_ASSERT(!sock_error(sk), return -1;);
+
+ if (sock->flags & __SO_ACCEPTCON)
+ return(-EINVAL);
+diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
+index 959874b..c8e0d89 100644
+--- a/net/irda/ircomm/ircomm_lmp.c
++++ b/net/irda/ircomm/ircomm_lmp.c
+@@ -81,7 +81,7 @@ static int ircomm_lmp_connect_response(s
+
+ /* Any userdata supplied? */
+ if (userdata == NULL) {
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
+ if (!tx_skb)
+ return -ENOMEM;
+
+@@ -115,7 +115,7 @@ static int ircomm_lmp_disconnect_request
+ IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+
+ if (!userdata) {
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
+ if (!tx_skb)
+ return -ENOMEM;
+
+diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
+index 3bcdb46..d50a020 100644
+--- a/net/irda/ircomm/ircomm_tty.c
++++ b/net/irda/ircomm/ircomm_tty.c
+@@ -79,7 +79,7 @@ static struct tty_driver *driver;
+
+ hashbin_t *ircomm_tty = NULL;
+
+-static struct tty_operations ops = {
++static const struct tty_operations ops = {
+ .open = ircomm_tty_open,
+ .close = ircomm_tty_close,
+ .write = ircomm_tty_write,
+diff --git a/net/irda/iriap.c b/net/irda/iriap.c
+index 61128aa..415cf4e 100644
+--- a/net/irda/iriap.c
++++ b/net/irda/iriap.c
+@@ -345,10 +345,11 @@ static void iriap_disconnect_request(str
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
+ if (tx_skb == NULL) {
+- IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n",
+- __FUNCTION__, 64);
++ IRDA_DEBUG(0,
++ "%s(), Could not allocate an sk_buff of length %d\n",
++ __FUNCTION__, LMP_MAX_HEADER);
+ return;
+ }
+
+@@ -701,7 +702,7 @@ void iriap_send_ack(struct iriap_cb *sel
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
+
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
+index da17395..99b18dc 100644
+--- a/net/irda/iriap_event.c
++++ b/net/irda/iriap_event.c
+@@ -365,7 +365,7 @@ static void state_r_disconnect(struct ir
+
+ switch (event) {
+ case IAP_LM_CONNECT_INDICATION:
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
+ if (tx_skb == NULL) {
+ IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
+ return;
+diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
+index a154b1d..56292ab 100644
+--- a/net/irda/irias_object.c
++++ b/net/irda/irias_object.c
+@@ -43,7 +43,7 @@ struct ias_value irias_missing = { IAS_M
+ *
+ * Faster, check boundary... Jean II
+ */
+-static char *strndup(char *str, int max)
++static char *strndup(char *str, size_t max)
+ {
+ char *new_str;
+ int len;
+diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
+index 7dd0a2f..9b962f2 100644
+--- a/net/irda/irlan/irlan_common.c
++++ b/net/irda/irlan/irlan_common.c
+@@ -636,7 +636,8 @@ void irlan_get_provider_info(struct irla
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(64, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER,
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -668,7 +669,10 @@ void irlan_open_data_channel(struct irla
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(64, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3") +
++ IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "DIRECT"),
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -704,7 +708,9 @@ void irlan_close_data_channel(struct irl
+ if (self->client.tsap_ctrl == NULL)
+ return;
+
+- skb = alloc_skb(64, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN"),
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -715,7 +721,7 @@ void irlan_close_data_channel(struct irl
+
+ /* Build frame */
+ frame[0] = CMD_CLOSE_DATA_CHAN;
+- frame[1] = 0x01; /* Two parameters */
++ frame[1] = 0x01; /* One parameter */
+
+ irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
+
+@@ -739,7 +745,11 @@ static void irlan_open_unicast_addr(stru
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(128, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -777,7 +787,12 @@ void irlan_set_broadcast_filter(struct i
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(128, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") +
++ /* We may waste one byte here...*/
++ IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -816,7 +831,12 @@ void irlan_set_multicast_filter(struct i
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(128, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
++ /* We may waste one byte here...*/
++ IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "NONE"),
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -856,7 +876,12 @@ static void irlan_get_unicast_addr(struc
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(128, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_OPERATION",
++ "DYNAMIC"),
++ GFP_ATOMIC);
+ if (!skb)
+ return;
+
+@@ -891,7 +916,10 @@ void irlan_get_media_char(struct irlan_c
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(64, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3"),
++ GFP_ATOMIC);
++
+ if (!skb)
+ return;
+
+diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
+index 9c0df86..58efde9 100644
+--- a/net/irda/irlan/irlan_provider.c
++++ b/net/irda/irlan/irlan_provider.c
+@@ -296,7 +296,14 @@ void irlan_provider_send_reply(struct ir
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
+
+- skb = alloc_skb(128, GFP_ATOMIC);
++ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
++ /* Bigger param length comes from CMD_GET_MEDIA_CHAR */
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BORADCAST") +
++ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
++ IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"),
++ GFP_ATOMIC);
++
+ if (!skb)
+ return;
+
+@@ -354,8 +361,7 @@ void irlan_provider_send_reply(struct ir
+ } else
+ skb->data[1] = 0x02; /* 2 parameters */
+ irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data);
+- irlan_insert_array_param(skb, "RECONNECT_KEY", "LINUX RULES!",
+- 12);
++ irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!");
+ break;
+ case CMD_FILTER_OPERATION:
+ irlan_filter_request(self, skb);
+diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
+index ccb983b..dba349c 100644
+--- a/net/irda/irlap_frame.c
++++ b/net/irda/irlap_frame.c
+@@ -117,7 +117,9 @@ void irlap_send_snrm_frame(struct irlap_
+ IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+
+ /* Allocate frame */
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct snrm_frame) +
++ IRLAP_NEGOCIATION_PARAMS_LEN,
++ GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+@@ -136,7 +138,7 @@ void irlap_send_snrm_frame(struct irlap_
+ * If we are establishing a connection then insert QoS paramerters
+ */
+ if (qos) {
+- skb_put(tx_skb, 9); /* 21 left */
++ skb_put(tx_skb, 9); /* 25 left */
+ frame->saddr = cpu_to_le32(self->saddr);
+ frame->daddr = cpu_to_le32(self->daddr);
+
+@@ -210,7 +212,9 @@ void irlap_send_ua_response_frame(struct
+ IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+
+ /* Allocate frame */
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct ua_frame) +
++ IRLAP_NEGOCIATION_PARAMS_LEN,
++ GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+@@ -245,23 +249,23 @@ void irlap_send_ua_response_frame(struct
+ void irlap_send_dm_frame( struct irlap_cb *self)
+ {
+ struct sk_buff *tx_skb = NULL;
+- __u8 *frame;
++ struct dm_frame *frame;
+
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+
+- tx_skb = alloc_skb(32, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct dm_frame), GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+- frame = skb_put(tx_skb, 2);
++ frame = (struct dm_frame *)skb_put(tx_skb, 2);
+
+ if (self->state == LAP_NDM)
+- frame[0] = CBROADCAST;
++ frame->caddr = CBROADCAST;
+ else
+- frame[0] = self->caddr;
++ frame->caddr = self->caddr;
+
+- frame[1] = DM_RSP | PF_BIT;
++ frame->control = DM_RSP | PF_BIT;
+
+ irlap_queue_xmit(self, tx_skb);
+ }
+@@ -275,21 +279,21 @@ void irlap_send_dm_frame( struct irlap_c
+ void irlap_send_disc_frame(struct irlap_cb *self)
+ {
+ struct sk_buff *tx_skb = NULL;
+- __u8 *frame;
++ struct disc_frame *frame;
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+ IRDA_ASSERT(self != NULL, return;);
+ IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+
+- tx_skb = alloc_skb(16, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct disc_frame), GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+- frame = skb_put(tx_skb, 2);
++ frame = (struct disc_frame *)skb_put(tx_skb, 2);
+
+- frame[0] = self->caddr | CMD_FRAME;
+- frame[1] = DISC_CMD | PF_BIT;
++ frame->caddr = self->caddr | CMD_FRAME;
++ frame->control = DISC_CMD | PF_BIT;
+
+ irlap_queue_xmit(self, tx_skb);
+ }
+@@ -315,7 +319,8 @@ void irlap_send_discovery_xid_frame(stru
+ IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
+ IRDA_ASSERT(discovery != NULL, return;);
+
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct xid_frame) + IRLAP_DISCOVERY_INFO_LEN,
++ GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+@@ -573,18 +578,18 @@ static void irlap_recv_discovery_xid_cmd
+ void irlap_send_rr_frame(struct irlap_cb *self, int command)
+ {
+ struct sk_buff *tx_skb;
+- __u8 *frame;
++ struct rr_frame *frame;
+
+- tx_skb = alloc_skb(16, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct rr_frame), GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+- frame = skb_put(tx_skb, 2);
++ frame = (struct rr_frame *)skb_put(tx_skb, 2);
+
+- frame[0] = self->caddr;
+- frame[0] |= (command) ? CMD_FRAME : 0;
++ frame->caddr = self->caddr;
++ frame->caddr |= (command) ? CMD_FRAME : 0;
+
+- frame[1] = RR | PF_BIT | (self->vr << 5);
++ frame->control = RR | PF_BIT | (self->vr << 5);
+
+ irlap_queue_xmit(self, tx_skb);
+ }
+@@ -598,16 +603,16 @@ void irlap_send_rr_frame(struct irlap_cb
+ void irlap_send_rd_frame(struct irlap_cb *self)
+ {
+ struct sk_buff *tx_skb;
+- __u8 *frame;
++ struct rd_frame *frame;
+
+- tx_skb = alloc_skb(16, GFP_ATOMIC);
++ tx_skb = alloc_skb(sizeof(struct rd_frame), GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+- frame = skb_put(tx_skb, 2);
++ frame = (struct rd_frame *)skb_put(tx_skb, 2);
+
+- frame[0] = self->caddr;
+- frame[1] = RD_RSP | PF_BIT;
++ frame->caddr = self->caddr;
++ frame->caddr = RD_RSP | PF_BIT;
+
+ irlap_queue_xmit(self, tx_skb);
+ }
+@@ -1214,7 +1219,7 @@ void irlap_send_test_frame(struct irlap_
+ struct test_frame *frame;
+ __u8 *info;
+
+- tx_skb = alloc_skb(cmd->len+sizeof(struct test_frame), GFP_ATOMIC);
++ tx_skb = alloc_skb(cmd->len + sizeof(struct test_frame), GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
+index c440913..5073261 100644
+--- a/net/irda/irlmp.c
++++ b/net/irda/irlmp.c
+@@ -392,7 +392,7 @@ int irlmp_connect_request(struct lsap_cb
+
+ /* Any userdata? */
+ if (tx_skb == NULL) {
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
+ if (!tx_skb)
+ return -ENOMEM;
+
+diff --git a/net/irda/irttp.c b/net/irda/irttp.c
+index 42acf1c..3c2e70b 100644
+--- a/net/irda/irttp.c
++++ b/net/irda/irttp.c
+@@ -804,12 +804,12 @@ static inline void irttp_give_credit(str
+ self->send_credit, self->avail_credit, self->remote_credit);
+
+ /* Give credit to peer */
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC);
+ if (!tx_skb)
+ return;
+
+ /* Reserve space for LMP, and LAP header */
+- skb_reserve(tx_skb, self->max_header_size);
++ skb_reserve(tx_skb, LMP_MAX_HEADER);
+
+ /*
+ * Since we can transmit and receive frames concurrently,
+@@ -1093,7 +1093,8 @@ int irttp_connect_request(struct tsap_cb
+
+ /* Any userdata supplied? */
+ if (userdata == NULL) {
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
++ GFP_ATOMIC);
+ if (!tx_skb)
+ return -ENOMEM;
+
+@@ -1341,7 +1342,8 @@ int irttp_connect_response(struct tsap_c
+
+ /* Any userdata supplied? */
+ if (userdata == NULL) {
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
++ GFP_ATOMIC);
+ if (!tx_skb)
+ return -ENOMEM;
+
+@@ -1540,14 +1542,14 @@ int irttp_disconnect_request(struct tsap
+
+ if (!userdata) {
+ struct sk_buff *tx_skb;
+- tx_skb = alloc_skb(64, GFP_ATOMIC);
++ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
+ if (!tx_skb)
+ return -ENOMEM;
+
+ /*
+ * Reserve space for MUX and LAP header
+ */
+- skb_reserve(tx_skb, TTP_MAX_HEADER);
++ skb_reserve(tx_skb, LMP_MAX_HEADER);
+
+ userdata = tx_skb;
+ }
+diff --git a/net/key/af_key.c b/net/key/af_key.c
+index 3a95b2e..20ff7cc 100644
+--- a/net/key/af_key.c
++++ b/net/key/af_key.c
+@@ -1731,7 +1731,8 @@ static u32 gen_reqid(void)
+ ++reqid;
+ if (reqid == 0)
+ reqid = IPSEC_MANUAL_REQID_MAX+1;
+- if (xfrm_policy_walk(check_reqid, (void*)&reqid) != -EEXIST)
++ if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid,
++ (void*)&reqid) != -EEXIST)
+ return reqid;
+ } while (reqid != start);
+ return 0;
+@@ -1765,7 +1766,7 @@ parse_ipsecrequest(struct xfrm_policy *x
+ }
+
+ /* addresses present only in tunnel mode */
+- if (t->mode) {
++ if (t->mode == XFRM_MODE_TUNNEL) {
+ switch (xp->family) {
+ case AF_INET:
+ sin = (void*)(rq+1);
+@@ -1997,7 +1998,7 @@ static void pfkey_xfrm_policy2msg(struct
+ int req_size;
+
+ req_size = sizeof(struct sadb_x_ipsecrequest);
+- if (t->mode)
++ if (t->mode == XFRM_MODE_TUNNEL)
+ req_size += 2*socklen;
+ else
+ size -= 2*socklen;
+@@ -2013,7 +2014,7 @@ static void pfkey_xfrm_policy2msg(struct
+ if (t->optional)
+ rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
+ rq->sadb_x_ipsecrequest_reqid = t->reqid;
+- if (t->mode) {
++ if (t->mode == XFRM_MODE_TUNNEL) {
+ switch (xp->family) {
+ case AF_INET:
+ sin = (void*)(rq+1);
+@@ -2139,7 +2140,7 @@ static int pfkey_spdadd(struct sock *sk,
+ xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+ xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
+ if (xp->selector.sport)
+- xp->selector.sport_mask = ~0;
++ xp->selector.sport_mask = htons(0xffff);
+
+ sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
+ pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr);
+@@ -2152,7 +2153,7 @@ static int pfkey_spdadd(struct sock *sk,
+
+ xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
+ if (xp->selector.dport)
+- xp->selector.dport_mask = ~0;
++ xp->selector.dport_mask = htons(0xffff);
+
+ sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1];
+ if (sec_ctx != NULL) {
+@@ -2242,7 +2243,7 @@ static int pfkey_spddelete(struct sock *
+ sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+ sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
+ if (sel.sport)
+- sel.sport_mask = ~0;
++ sel.sport_mask = htons(0xffff);
+
+ sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
+ pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
+@@ -2250,7 +2251,7 @@ static int pfkey_spddelete(struct sock *
+ sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+ sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
+ if (sel.dport)
+- sel.dport_mask = ~0;
++ sel.dport_mask = htons(0xffff);
+
+ sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1];
+ memset(&tmp, 0, sizeof(struct xfrm_policy));
+@@ -2268,7 +2269,8 @@ static int pfkey_spddelete(struct sock *
+ return err;
+ }
+
+- xp = xfrm_policy_bysel_ctx(pol->sadb_x_policy_dir-1, &sel, tmp.security, 1);
++ xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1,
++ &sel, tmp.security, 1);
+ security_xfrm_policy_free(&tmp);
+ if (xp == NULL)
+ return -ENOENT;
+@@ -2330,7 +2332,7 @@ static int pfkey_spdget(struct sock *sk,
+ if (dir >= XFRM_POLICY_MAX)
+ return -EINVAL;
+
+- xp = xfrm_policy_byid(dir, pol->sadb_x_policy_id,
++ xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id,
+ hdr->sadb_msg_type == SADB_X_SPDDELETE2);
+ if (xp == NULL)
+ return -ENOENT;
+@@ -2378,7 +2380,7 @@ static int pfkey_spddump(struct sock *sk
+ {
+ struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+
+- return xfrm_policy_walk(dump_sp, &data);
++ return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data);
+ }
+
+ static int key_notify_policy_flush(struct km_event *c)
+@@ -2405,7 +2407,8 @@ static int pfkey_spdflush(struct sock *s
+ {
+ struct km_event c;
+
+- xfrm_policy_flush();
++ xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN);
++ c.data.type = XFRM_POLICY_TYPE_MAIN;
+ c.event = XFRM_MSG_FLUSHPOLICY;
+ c.pid = hdr->sadb_msg_pid;
+ c.seq = hdr->sadb_msg_seq;
+@@ -2667,6 +2670,9 @@ static int pfkey_send_notify(struct xfrm
+
+ static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+ {
++ if (xp && xp->type != XFRM_POLICY_TYPE_MAIN)
++ return 0;
++
+ switch (c->event) {
+ case XFRM_MSG_POLEXPIRE:
+ return key_notify_policy_expire(xp, c);
+@@ -2675,6 +2681,8 @@ static int pfkey_send_policy_notify(stru
+ case XFRM_MSG_UPDPOLICY:
+ return key_notify_policy(xp, dir, c);
+ case XFRM_MSG_FLUSHPOLICY:
++ if (c->data.type != XFRM_POLICY_TYPE_MAIN)
++ break;
+ return key_notify_policy_flush(c);
+ default:
+ printk("pfkey: Unknown policy event %d\n", c->event);
+@@ -2708,6 +2716,9 @@ static int pfkey_send_acquire(struct xfr
+ #endif
+ int sockaddr_size;
+ int size;
++ struct sadb_x_sec_ctx *sec_ctx;
++ struct xfrm_sec_ctx *xfrm_ctx;
++ int ctx_size = 0;
+
+ sockaddr_size = pfkey_sockaddr_size(x->props.family);
+ if (!sockaddr_size)
+@@ -2723,6 +2734,11 @@ static int pfkey_send_acquire(struct xfr
+ else if (x->id.proto == IPPROTO_ESP)
+ size += count_esp_combs(t);
+
++ if ((xfrm_ctx = x->security)) {
++ ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);
++ size += sizeof(struct sadb_x_sec_ctx) + ctx_size;
++ }
++
+ skb = alloc_skb(size + 16, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+@@ -2818,17 +2834,31 @@ static int pfkey_send_acquire(struct xfr
+ else if (x->id.proto == IPPROTO_ESP)
+ dump_esp_combs(skb, t);
+
++ /* security context */
++ if (xfrm_ctx) {
++ sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,
++ sizeof(struct sadb_x_sec_ctx) + ctx_size);
++ sec_ctx->sadb_x_sec_len =
++ (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);
++ sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
++ sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;
++ sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg;
++ sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len;
++ memcpy(sec_ctx + 1, xfrm_ctx->ctx_str,
++ xfrm_ctx->ctx_len);
++ }
++
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+ }
+
+-static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt,
++static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
+ u8 *data, int len, int *dir)
+ {
+ struct xfrm_policy *xp;
+ struct sadb_x_policy *pol = (struct sadb_x_policy*)data;
+ struct sadb_x_sec_ctx *sec_ctx;
+
+- switch (family) {
++ switch (sk->sk_family) {
+ case AF_INET:
+ if (opt != IP_IPSEC_POLICY) {
+ *dir = -EOPNOTSUPP;
+@@ -2869,7 +2899,7 @@ static struct xfrm_policy *pfkey_compile
+ xp->lft.hard_byte_limit = XFRM_INF;
+ xp->lft.soft_packet_limit = XFRM_INF;
+ xp->lft.hard_packet_limit = XFRM_INF;
+- xp->family = family;
++ xp->family = sk->sk_family;
+
+ xp->xfrm_nr = 0;
+ if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&
+@@ -2885,8 +2915,10 @@ static struct xfrm_policy *pfkey_compile
+ p += pol->sadb_x_policy_len*8;
+ sec_ctx = (struct sadb_x_sec_ctx *)p;
+ if (len < pol->sadb_x_policy_len*8 +
+- sec_ctx->sadb_x_sec_len)
++ sec_ctx->sadb_x_sec_len) {
++ *dir = -EINVAL;
+ goto out;
++ }
+ if ((*dir = verify_sec_ctx_len(p)))
+ goto out;
+ uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
+index a9894dd..f619c65 100644
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -148,6 +148,18 @@ config NETFILTER_XT_TARGET_CONNMARK
+ <file:Documentation/modules.txt>. The module will be called
+ ipt_CONNMARK.o. If unsure, say `N'.
+
++config NETFILTER_XT_TARGET_DSCP
++ tristate '"DSCP" target support'
++ depends on NETFILTER_XTABLES
++ depends on IP_NF_MANGLE || IP6_NF_MANGLE
++ help
++ This option adds a `DSCP' target, which allows you to manipulate
++ the IPv4/IPv6 header DSCP field (differentiated services codepoint).
++
++ The DSCP field can have any value between 0x0 and 0x3f inclusive.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ config NETFILTER_XT_TARGET_MARK
+ tristate '"MARK" target support'
+ depends on NETFILTER_XTABLES
+@@ -197,7 +209,9 @@ config NETFILTER_XT_TARGET_SECMARK
+
+ config NETFILTER_XT_TARGET_CONNSECMARK
+ tristate '"CONNSECMARK" target support'
+- depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK)
++ depends on NETFILTER_XTABLES && \
++ ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \
++ (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK))
+ help
+ The CONNSECMARK target copies security markings from packets
+ to connections, and restores security markings from connections
+@@ -263,6 +277,17 @@ config NETFILTER_XT_MATCH_DCCP
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++config NETFILTER_XT_MATCH_DSCP
++ tristate '"DSCP" match support'
++ depends on NETFILTER_XTABLES
++ help
++ This option adds a `DSCP' match, which allows you to match against
++ the IPv4/IPv6 header DSCP field (differentiated services codepoint).
++
++ The DSCP field can have any value between 0x0 and 0x3f inclusive.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ config NETFILTER_XT_MATCH_ESP
+ tristate '"ESP" match support'
+ depends on NETFILTER_XTABLES
+@@ -342,7 +367,7 @@ config NETFILTER_XT_MATCH_MULTIPORT
+
+ config NETFILTER_XT_MATCH_PHYSDEV
+ tristate '"physdev" match support'
+- depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
++ depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER
+ help
+ Physdev packet matching matches against the physical bridge ports
+ the IP packet arrived on or will leave by.
+diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
+index 6fa4b75..a74be49 100644
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tab
+ # targets
+ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
++obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
+@@ -37,6 +38,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTE
+ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
++obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
+diff --git a/net/netfilter/core.c b/net/netfilter/core.c
+index 5d29d5e..d80b935 100644
+--- a/net/netfilter/core.c
++++ b/net/netfilter/core.c
+@@ -182,7 +182,7 @@ next_hook:
+ ret = -EPERM;
+ } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
+ NFDEBUG("nf_hook: Verdict = QUEUE.\n");
+- if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
++ if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn,
+ verdict >> NF_VERDICT_BITS))
+ goto next_hook;
+ }
+@@ -222,6 +222,28 @@ copy_skb:
+ }
+ EXPORT_SYMBOL(skb_make_writable);
+
++u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, u_int32_t csum)
++{
++ u_int32_t diff[] = { oldval, newval };
++
++ return csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum));
++}
++EXPORT_SYMBOL(nf_csum_update);
++
++u_int16_t nf_proto_csum_update(struct sk_buff *skb,
++ u_int32_t oldval, u_int32_t newval,
++ u_int16_t csum, int pseudohdr)
++{
++ if (skb->ip_summed != CHECKSUM_PARTIAL) {
++ csum = nf_csum_update(oldval, newval, csum);
++ if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
++ skb->csum = nf_csum_update(oldval, newval, skb->csum);
++ } else if (pseudohdr)
++ csum = ~nf_csum_update(oldval, newval, ~csum);
++
++ return csum;
++}
++EXPORT_SYMBOL(nf_proto_csum_update);
+
+ /* This does not belong here, but locally generated errors need it if connection
+ tracking in use: without this, connection may not be in hash table, and hence
+diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
+index 8f22619..836541e 100644
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -57,7 +57,6 @@
+ #include <net/netfilter/nf_conntrack_protocol.h>
+ #include <net/netfilter/nf_conntrack_helper.h>
+ #include <net/netfilter/nf_conntrack_core.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #define NF_CONNTRACK_VERSION "0.5.0"
+
+@@ -74,17 +73,17 @@ atomic_t nf_conntrack_count = ATOMIC_INI
+
+ void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL;
+ LIST_HEAD(nf_conntrack_expect_list);
+-struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
+-struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX];
++struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly;
++struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly;
+ static LIST_HEAD(helpers);
+-unsigned int nf_conntrack_htable_size = 0;
+-int nf_conntrack_max;
+-struct list_head *nf_conntrack_hash;
+-static kmem_cache_t *nf_conntrack_expect_cachep;
++unsigned int nf_conntrack_htable_size __read_mostly = 0;
++int nf_conntrack_max __read_mostly;
++struct list_head *nf_conntrack_hash __read_mostly;
++static kmem_cache_t *nf_conntrack_expect_cachep __read_mostly;
+ struct nf_conn nf_conntrack_untracked;
+-unsigned int nf_ct_log_invalid;
++unsigned int nf_ct_log_invalid __read_mostly;
+ static LIST_HEAD(unconfirmed);
+-static int nf_conntrack_vmalloc;
++static int nf_conntrack_vmalloc __read_mostly;
+
+ static unsigned int nf_conntrack_next_id;
+ static unsigned int nf_conntrack_expect_next_id;
+@@ -539,15 +538,10 @@ void nf_ct_remove_expectations(struct nf
+ static void
+ clean_from_lists(struct nf_conn *ct)
+ {
+- unsigned int ho, hr;
+-
+ DEBUGP("clean_from_lists(%p)\n", ct);
+ ASSERT_WRITE_LOCK(&nf_conntrack_lock);
+-
+- ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+- hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+- LIST_DELETE(&nf_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+- LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
++ list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
++ list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list);
+
+ /* Destroy all pending expectations */
+ nf_ct_remove_expectations(ct);
+@@ -617,16 +611,6 @@ static void death_by_timeout(unsigned lo
+ nf_ct_put(ct);
+ }
+
+-static inline int
+-conntrack_tuple_cmp(const struct nf_conntrack_tuple_hash *i,
+- const struct nf_conntrack_tuple *tuple,
+- const struct nf_conn *ignored_conntrack)
+-{
+- ASSERT_READ_LOCK(&nf_conntrack_lock);
+- return nf_ct_tuplehash_to_ctrack(i) != ignored_conntrack
+- && nf_ct_tuple_equal(tuple, &i->tuple);
+-}
+-
+ struct nf_conntrack_tuple_hash *
+ __nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
+ const struct nf_conn *ignored_conntrack)
+@@ -636,7 +620,8 @@ __nf_conntrack_find(const struct nf_conn
+
+ ASSERT_READ_LOCK(&nf_conntrack_lock);
+ list_for_each_entry(h, &nf_conntrack_hash[hash], list) {
+- if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) {
++ if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
++ nf_ct_tuple_equal(tuple, &h->tuple)) {
+ NF_CT_STAT_INC(found);
+ return h;
+ }
+@@ -667,10 +652,10 @@ static void __nf_conntrack_hash_insert(s
+ unsigned int repl_hash)
+ {
+ ct->id = ++nf_conntrack_next_id;
+- list_prepend(&nf_conntrack_hash[hash],
+- &ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+- list_prepend(&nf_conntrack_hash[repl_hash],
+- &ct->tuplehash[IP_CT_DIR_REPLY].list);
++ list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list,
++ &nf_conntrack_hash[hash]);
++ list_add(&ct->tuplehash[IP_CT_DIR_REPLY].list,
++ &nf_conntrack_hash[repl_hash]);
+ }
+
+ void nf_conntrack_hash_insert(struct nf_conn *ct)
+@@ -690,7 +675,9 @@ int
+ __nf_conntrack_confirm(struct sk_buff **pskb)
+ {
+ unsigned int hash, repl_hash;
++ struct nf_conntrack_tuple_hash *h;
+ struct nf_conn *ct;
++ struct nf_conn_help *help;
+ enum ip_conntrack_info ctinfo;
+
+ ct = nf_ct_get(*pskb, &ctinfo);
+@@ -720,41 +707,41 @@ __nf_conntrack_confirm(struct sk_buff **
+ /* See if there's one in the list already, including reverse:
+ NAT could have grabbed it without realizing, since we're
+ not in the hash. If there is, we lost race. */
+- if (!LIST_FIND(&nf_conntrack_hash[hash],
+- conntrack_tuple_cmp,
+- struct nf_conntrack_tuple_hash *,
+- &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
+- && !LIST_FIND(&nf_conntrack_hash[repl_hash],
+- conntrack_tuple_cmp,
+- struct nf_conntrack_tuple_hash *,
+- &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
+- struct nf_conn_help *help;
+- /* Remove from unconfirmed list */
+- list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
++ list_for_each_entry(h, &nf_conntrack_hash[hash], list)
++ if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
++ &h->tuple))
++ goto out;
++ list_for_each_entry(h, &nf_conntrack_hash[repl_hash], list)
++ if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
++ &h->tuple))
++ goto out;
+
+- __nf_conntrack_hash_insert(ct, hash, repl_hash);
+- /* Timer relative to confirmation time, not original
+- setting time, otherwise we'd get timer wrap in
+- weird delay cases. */
+- ct->timeout.expires += jiffies;
+- add_timer(&ct->timeout);
+- atomic_inc(&ct->ct_general.use);
+- set_bit(IPS_CONFIRMED_BIT, &ct->status);
+- NF_CT_STAT_INC(insert);
+- write_unlock_bh(&nf_conntrack_lock);
+- help = nfct_help(ct);
+- if (help && help->helper)
+- nf_conntrack_event_cache(IPCT_HELPER, *pskb);
++ /* Remove from unconfirmed list */
++ list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
++
++ __nf_conntrack_hash_insert(ct, hash, repl_hash);
++ /* Timer relative to confirmation time, not original
++ setting time, otherwise we'd get timer wrap in
++ weird delay cases. */
++ ct->timeout.expires += jiffies;
++ add_timer(&ct->timeout);
++ atomic_inc(&ct->ct_general.use);
++ set_bit(IPS_CONFIRMED_BIT, &ct->status);
++ NF_CT_STAT_INC(insert);
++ write_unlock_bh(&nf_conntrack_lock);
++ help = nfct_help(ct);
++ if (help && help->helper)
++ nf_conntrack_event_cache(IPCT_HELPER, *pskb);
+ #ifdef CONFIG_NF_NAT_NEEDED
+- if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
+- test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
+- nf_conntrack_event_cache(IPCT_NATINFO, *pskb);
++ if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
++ test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
++ nf_conntrack_event_cache(IPCT_NATINFO, *pskb);
+ #endif
+- nf_conntrack_event_cache(master_ct(ct) ?
+- IPCT_RELATED : IPCT_NEW, *pskb);
+- return NF_ACCEPT;
+- }
++ nf_conntrack_event_cache(master_ct(ct) ?
++ IPCT_RELATED : IPCT_NEW, *pskb);
++ return NF_ACCEPT;
+
++out:
+ NF_CT_STAT_INC(insert_failed);
+ write_unlock_bh(&nf_conntrack_lock);
+ return NF_DROP;
+@@ -777,24 +764,21 @@ nf_conntrack_tuple_taken(const struct nf
+
+ /* There's a small race here where we may free a just-assured
+ connection. Too bad: we're in trouble anyway. */
+-static inline int unreplied(const struct nf_conntrack_tuple_hash *i)
+-{
+- return !(test_bit(IPS_ASSURED_BIT,
+- &nf_ct_tuplehash_to_ctrack(i)->status));
+-}
+-
+ static int early_drop(struct list_head *chain)
+ {
+ /* Traverse backwards: gives us oldest, which is roughly LRU */
+ struct nf_conntrack_tuple_hash *h;
+- struct nf_conn *ct = NULL;
++ struct nf_conn *ct = NULL, *tmp;
+ int dropped = 0;
+
+ read_lock_bh(&nf_conntrack_lock);
+- h = LIST_FIND_B(chain, unreplied, struct nf_conntrack_tuple_hash *);
+- if (h) {
+- ct = nf_ct_tuplehash_to_ctrack(h);
+- atomic_inc(&ct->ct_general.use);
++ list_for_each_entry_reverse(h, chain, list) {
++ tmp = nf_ct_tuplehash_to_ctrack(h);
++ if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) {
++ ct = tmp;
++ atomic_inc(&ct->ct_general.use);
++ break;
++ }
+ }
+ read_unlock_bh(&nf_conntrack_lock);
+
+@@ -810,18 +794,16 @@ static int early_drop(struct list_head *
+ return dropped;
+ }
+
+-static inline int helper_cmp(const struct nf_conntrack_helper *i,
+- const struct nf_conntrack_tuple *rtuple)
+-{
+- return nf_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
+-}
+-
+ static struct nf_conntrack_helper *
+ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
+ {
+- return LIST_FIND(&helpers, helper_cmp,
+- struct nf_conntrack_helper *,
+- tuple);
++ struct nf_conntrack_helper *h;
++
++ list_for_each_entry(h, &helpers, list) {
++ if (nf_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask))
++ return h;
++ }
++ return NULL;
+ }
+
+ struct nf_conntrack_helper *
+@@ -866,11 +848,15 @@ __nf_conntrack_alloc(const struct nf_con
+ nf_conntrack_hash_rnd_initted = 1;
+ }
+
++ /* We don't want any race condition at early drop stage */
++ atomic_inc(&nf_conntrack_count);
++
+ if (nf_conntrack_max
+- && atomic_read(&nf_conntrack_count) >= nf_conntrack_max) {
++ && atomic_read(&nf_conntrack_count) > nf_conntrack_max) {
+ unsigned int hash = hash_conntrack(orig);
+ /* Try dropping from this hash chain. */
+ if (!early_drop(&nf_conntrack_hash[hash])) {
++ atomic_dec(&nf_conntrack_count);
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "nf_conntrack: table full, dropping"
+@@ -921,10 +907,12 @@ __nf_conntrack_alloc(const struct nf_con
+ init_timer(&conntrack->timeout);
+ conntrack->timeout.data = (unsigned long)conntrack;
+ conntrack->timeout.function = death_by_timeout;
++ read_unlock_bh(&nf_ct_cache_lock);
+
+- atomic_inc(&nf_conntrack_count);
++ return conntrack;
+ out:
+ read_unlock_bh(&nf_ct_cache_lock);
++ atomic_dec(&nf_conntrack_count);
+ return conntrack;
+ }
+
+@@ -1323,7 +1311,7 @@ int nf_conntrack_helper_register(struct
+ return ret;
+ }
+ write_lock_bh(&nf_conntrack_lock);
+- list_prepend(&helpers, me);
++ list_add(&me->list, &helpers);
+ write_unlock_bh(&nf_conntrack_lock);
+
+ return 0;
+@@ -1342,8 +1330,8 @@ __nf_conntrack_helper_find_byname(const
+ return NULL;
+ }
+
+-static inline int unhelp(struct nf_conntrack_tuple_hash *i,
+- const struct nf_conntrack_helper *me)
++static inline void unhelp(struct nf_conntrack_tuple_hash *i,
++ const struct nf_conntrack_helper *me)
+ {
+ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
+ struct nf_conn_help *help = nfct_help(ct);
+@@ -1352,17 +1340,17 @@ static inline int unhelp(struct nf_connt
+ nf_conntrack_event(IPCT_HELPER, ct);
+ help->helper = NULL;
+ }
+- return 0;
+ }
+
+ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ {
+ unsigned int i;
++ struct nf_conntrack_tuple_hash *h;
+ struct nf_conntrack_expect *exp, *tmp;
+
+ /* Need write lock here, to delete helper. */
+ write_lock_bh(&nf_conntrack_lock);
+- LIST_DELETE(&helpers, me);
++ list_del(&me->list);
+
+ /* Get rid of expectations */
+ list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
+@@ -1374,10 +1362,12 @@ void nf_conntrack_helper_unregister(stru
+ }
+
+ /* Get rid of expecteds, set helpers to NULL. */
+- LIST_FIND_W(&unconfirmed, unhelp, struct nf_conntrack_tuple_hash*, me);
+- for (i = 0; i < nf_conntrack_htable_size; i++)
+- LIST_FIND_W(&nf_conntrack_hash[i], unhelp,
+- struct nf_conntrack_tuple_hash *, me);
++ list_for_each_entry(h, &unconfirmed, list)
++ unhelp(h, me);
++ for (i = 0; i < nf_conntrack_htable_size; i++) {
++ list_for_each_entry(h, &nf_conntrack_hash[i], list)
++ unhelp(h, me);
++ }
+ write_unlock_bh(&nf_conntrack_lock);
+
+ /* Someone could be still looking at the helper in a bh. */
+@@ -1510,37 +1500,41 @@ do_iter(const struct nf_conntrack_tuple_
+ }
+
+ /* Bring out ya dead! */
+-static struct nf_conntrack_tuple_hash *
++static struct nf_conn *
+ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
+ void *data, unsigned int *bucket)
+ {
+- struct nf_conntrack_tuple_hash *h = NULL;
++ struct nf_conntrack_tuple_hash *h;
++ struct nf_conn *ct;
+
+ write_lock_bh(&nf_conntrack_lock);
+ for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
+- h = LIST_FIND_W(&nf_conntrack_hash[*bucket], do_iter,
+- struct nf_conntrack_tuple_hash *, iter, data);
+- if (h)
+- break;
++ list_for_each_entry(h, &nf_conntrack_hash[*bucket], list) {
++ ct = nf_ct_tuplehash_to_ctrack(h);
++ if (iter(ct, data))
++ goto found;
++ }
+ }
+- if (!h)
+- h = LIST_FIND_W(&unconfirmed, do_iter,
+- struct nf_conntrack_tuple_hash *, iter, data);
+- if (h)
+- atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use);
++ list_for_each_entry(h, &unconfirmed, list) {
++ ct = nf_ct_tuplehash_to_ctrack(h);
++ if (iter(ct, data))
++ goto found;
++ }
+ write_unlock_bh(&nf_conntrack_lock);
+-
+- return h;
++ return NULL;
++found:
++ atomic_inc(&ct->ct_general.use);
++ write_unlock_bh(&nf_conntrack_lock);
++ return ct;
+ }
+
+ void
+ nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data)
+ {
+- struct nf_conntrack_tuple_hash *h;
++ struct nf_conn *ct;
+ unsigned int bucket = 0;
+
+- while ((h = get_next_corpse(iter, data, &bucket)) != NULL) {
+- struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
++ while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) {
+ /* Time to push up daises... */
+ if (del_timer(&ct->timeout))
+ death_by_timeout((unsigned long)ct);
+diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
+index 960972d..0c17a5b 100644
+--- a/net/netfilter/nf_conntrack_ftp.c
++++ b/net/netfilter/nf_conntrack_ftp.c
+@@ -21,6 +21,7 @@
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
+ #include <linux/ctype.h>
++#include <linux/inet.h>
+ #include <net/checksum.h>
+ #include <net/tcp.h>
+
+@@ -111,101 +112,14 @@ static struct ftp_search {
+ },
+ };
+
+-/* This code is based on inet_pton() in glibc-2.2.4 */
+ static int
+ get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, u_int8_t term)
+ {
+- static const char xdigits[] = "0123456789abcdef";
+- u_int8_t tmp[16], *tp, *endp, *colonp;
+- int ch, saw_xdigit;
+- u_int32_t val;
+- size_t clen = 0;
+-
+- tp = memset(tmp, '\0', sizeof(tmp));
+- endp = tp + sizeof(tmp);
+- colonp = NULL;
+-
+- /* Leading :: requires some special handling. */
+- if (*src == ':'){
+- if (*++src != ':') {
+- DEBUGP("invalid \":\" at the head of addr\n");
+- return 0;
+- }
+- clen++;
+- }
+-
+- saw_xdigit = 0;
+- val = 0;
+- while ((clen < dlen) && (*src != term)) {
+- const char *pch;
+-
+- ch = tolower(*src++);
+- clen++;
+-
+- pch = strchr(xdigits, ch);
+- if (pch != NULL) {
+- val <<= 4;
+- val |= (pch - xdigits);
+- if (val > 0xffff)
+- return 0;
+-
+- saw_xdigit = 1;
+- continue;
+- }
+- if (ch != ':') {
+- DEBUGP("get_ipv6_addr: invalid char. \'%c\'\n", ch);
+- return 0;
+- }
+-
+- if (!saw_xdigit) {
+- if (colonp) {
+- DEBUGP("invalid location of \"::\".\n");
+- return 0;
+- }
+- colonp = tp;
+- continue;
+- } else if (*src == term) {
+- DEBUGP("trancated IPv6 addr\n");
+- return 0;
+- }
+-
+- if (tp + 2 > endp)
+- return 0;
+- *tp++ = (u_int8_t) (val >> 8) & 0xff;
+- *tp++ = (u_int8_t) val & 0xff;
+-
+- saw_xdigit = 0;
+- val = 0;
+- continue;
+- }
+- if (saw_xdigit) {
+- if (tp + 2 > endp)
+- return 0;
+- *tp++ = (u_int8_t) (val >> 8) & 0xff;
+- *tp++ = (u_int8_t) val & 0xff;
+- }
+- if (colonp != NULL) {
+- /*
+- * Since some memmove()'s erroneously fail to handle
+- * overlapping regions, we'll do the shift by hand.
+- */
+- const int n = tp - colonp;
+- int i;
+-
+- if (tp == endp)
+- return 0;
+-
+- for (i = 1; i <= n; i++) {
+- endp[- i] = colonp[n - i];
+- colonp[n - i] = 0;
+- }
+- tp = endp;
+- }
+- if (tp != endp || (*src != term))
+- return 0;
+-
+- memcpy(dst->s6_addr, tmp, sizeof(dst->s6_addr));
+- return clen;
++ const char *end;
++ int ret = in6_pton(src, min_t(size_t, dlen, 0xffff), (u8 *)dst, term, &end);
++ if (ret > 0)
++ return (int)(end - src);
++ return 0;
+ }
+
+ static int try_number(const char *data, size_t dlen, u_int32_t array[],
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 6527d4e..bd0156a 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -47,13 +47,6 @@ MODULE_LICENSE("GPL");
+
+ static char __initdata version[] = "0.93";
+
+-#if 0
+-#define DEBUGP printk
+-#else
+-#define DEBUGP(format, args...)
+-#endif
+-
+-
+ static inline int
+ ctnetlink_dump_tuples_proto(struct sk_buff *skb,
+ const struct nf_conntrack_tuple *tuple,
+@@ -339,11 +332,7 @@ static int ctnetlink_conntrack_event(str
+ /* dump everything */
+ events = ~0UL;
+ group = NFNLGRP_CONNTRACK_NEW;
+- } else if (events & (IPCT_STATUS |
+- IPCT_PROTOINFO |
+- IPCT_HELPER |
+- IPCT_HELPINFO |
+- IPCT_NATINFO)) {
++ } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) {
+ type = IPCTNL_MSG_CT_NEW;
+ group = NFNLGRP_CONNTRACK_UPDATE;
+ } else
+@@ -395,6 +384,10 @@ static int ctnetlink_conntrack_event(str
+ ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
+ goto nfattr_failure;
+
++ if (events & IPCT_MARK
++ && ctnetlink_dump_mark(skb, ct) < 0)
++ goto nfattr_failure;
++
+ nlh->nlmsg_len = skb->tail - b;
+ nfnetlink_send(skb, 0, group, 0);
+ return NOTIFY_DONE;
+@@ -410,7 +403,6 @@ static int ctnetlink_done(struct netlink
+ {
+ if (cb->args[1])
+ nf_ct_put((struct nf_conn *)cb->args[1]);
+- DEBUGP("entered %s\n", __FUNCTION__);
+ return 0;
+ }
+
+@@ -425,9 +417,6 @@ ctnetlink_dump_table(struct sk_buff *skb
+ struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
+ u_int8_t l3proto = nfmsg->nfgen_family;
+
+- DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
+- cb->args[0], *id);
+-
+ read_lock_bh(&nf_conntrack_lock);
+ last = (struct nf_conn *)cb->args[1];
+ for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
+@@ -455,6 +444,11 @@ restart:
+ cb->args[1] = (unsigned long)ct;
+ goto out;
+ }
++#ifdef CONFIG_NF_CT_ACCT
++ if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) ==
++ IPCTNL_MSG_CT_GET_CTRZERO)
++ memset(&ct->counters, 0, sizeof(ct->counters));
++#endif
+ }
+ if (cb->args[1]) {
+ cb->args[1] = 0;
+@@ -466,54 +460,9 @@ out:
+ if (last)
+ nf_ct_put(last);
+
+- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
+ return skb->len;
+ }
+
+-#ifdef CONFIG_NF_CT_ACCT
+-static int
+-ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
+-{
+- struct nf_conn *ct = NULL;
+- struct nf_conntrack_tuple_hash *h;
+- struct list_head *i;
+- u_int32_t *id = (u_int32_t *) &cb->args[1];
+- struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
+- u_int8_t l3proto = nfmsg->nfgen_family;
+-
+- DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__,
+- cb->args[0], *id);
+-
+- write_lock_bh(&nf_conntrack_lock);
+- for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) {
+- list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
+- h = (struct nf_conntrack_tuple_hash *) i;
+- if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+- continue;
+- ct = nf_ct_tuplehash_to_ctrack(h);
+- if (l3proto && L3PROTO(ct) != l3proto)
+- continue;
+- if (ct->id <= *id)
+- continue;
+- if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
+- cb->nlh->nlmsg_seq,
+- IPCTNL_MSG_CT_NEW,
+- 1, ct) < 0)
+- goto out;
+- *id = ct->id;
+-
+- memset(&ct->counters, 0, sizeof(ct->counters));
+- }
+- }
+-out:
+- write_unlock_bh(&nf_conntrack_lock);
+-
+- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
+-
+- return skb->len;
+-}
+-#endif
+-
+ static inline int
+ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple)
+ {
+@@ -521,8 +470,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *
+ struct nf_conntrack_l3proto *l3proto;
+ int ret = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_IP_MAX, attr);
+
+ l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
+@@ -532,8 +479,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *
+
+ nf_ct_l3proto_put(l3proto);
+
+- DEBUGP("leaving\n");
+-
+ return ret;
+ }
+
+@@ -549,8 +494,6 @@ ctnetlink_parse_tuple_proto(struct nfatt
+ struct nf_conntrack_protocol *proto;
+ int ret = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
+
+ if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
+@@ -577,8 +520,6 @@ ctnetlink_parse_tuple(struct nfattr *cda
+ struct nfattr *tb[CTA_TUPLE_MAX];
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ memset(tuple, 0, sizeof(*tuple));
+
+ nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
+@@ -605,10 +546,6 @@ ctnetlink_parse_tuple(struct nfattr *cda
+ else
+ tuple->dst.dir = IP_CT_DIR_ORIGINAL;
+
+- NF_CT_DUMP_TUPLE(tuple);
+-
+- DEBUGP("leaving\n");
+-
+ return 0;
+ }
+
+@@ -625,8 +562,6 @@ static int ctnetlink_parse_nat_proto(str
+ struct nfattr *tb[CTA_PROTONAT_MAX];
+ struct ip_nat_protocol *npt;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
+
+ if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
+@@ -645,7 +580,6 @@ static int ctnetlink_parse_nat_proto(str
+
+ ip_nat_proto_put(npt);
+
+- DEBUGP("leaving\n");
+ return 0;
+ }
+
+@@ -661,8 +595,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
+ struct nfattr *tb[CTA_NAT_MAX];
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ memset(range, 0, sizeof(*range));
+
+ nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
+@@ -688,7 +620,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
+ if (err < 0)
+ return err;
+
+- DEBUGP("leaving\n");
+ return 0;
+ }
+ #endif
+@@ -698,8 +629,6 @@ ctnetlink_parse_help(struct nfattr *attr
+ {
+ struct nfattr *tb[CTA_HELP_MAX];
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
+
+ if (!tb[CTA_HELP_NAME-1])
+@@ -729,8 +658,6 @@ ctnetlink_del_conntrack(struct sock *ctn
+ u_int8_t u3 = nfmsg->nfgen_family;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
+@@ -748,10 +675,8 @@ ctnetlink_del_conntrack(struct sock *ctn
+ return err;
+
+ h = nf_conntrack_find_get(&tuple, NULL);
+- if (!h) {
+- DEBUGP("tuple not found in conntrack hash\n");
++ if (!h)
+ return -ENOENT;
+- }
+
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+@@ -766,7 +691,6 @@ ctnetlink_del_conntrack(struct sock *ctn
+ ct->timeout.function((unsigned long)ct);
+
+ nf_ct_put(ct);
+- DEBUGP("leaving\n");
+
+ return 0;
+ }
+@@ -783,27 +707,17 @@ ctnetlink_get_conntrack(struct sock *ctn
+ u_int8_t u3 = nfmsg->nfgen_family;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ u32 rlen;
+
+- if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
+- IPCTNL_MSG_CT_GET_CTRZERO) {
+-#ifdef CONFIG_NF_CT_ACCT
+- if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+- ctnetlink_dump_table_w,
+- ctnetlink_done)) != 0)
+- return -EINVAL;
+-#else
++#ifndef CONFIG_NF_CT_ACCT
++ if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO)
+ return -ENOTSUPP;
+ #endif
+- } else {
+- if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+- ctnetlink_dump_table,
+- ctnetlink_done)) != 0)
++ if ((*errp = netlink_dump_start(ctnl, skb, nlh,
++ ctnetlink_dump_table,
++ ctnetlink_done)) != 0)
+ return -EINVAL;
+- }
+
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+@@ -826,11 +740,9 @@ ctnetlink_get_conntrack(struct sock *ctn
+ return err;
+
+ h = nf_conntrack_find_get(&tuple, NULL);
+- if (!h) {
+- DEBUGP("tuple not found in conntrack hash");
++ if (!h)
+ return -ENOENT;
+- }
+- DEBUGP("tuple found\n");
++
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ err = -ENOMEM;
+@@ -851,7 +763,6 @@ ctnetlink_get_conntrack(struct sock *ctn
+ if (err < 0)
+ goto out;
+
+- DEBUGP("leaving\n");
+ return 0;
+
+ free:
+@@ -923,8 +834,6 @@ ctnetlink_change_helper(struct nf_conn *
+ char *helpname;
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (!help) {
+ /* FIXME: we need to reallocate and rehash */
+ return -EBUSY;
+@@ -1001,8 +910,6 @@ ctnetlink_change_conntrack(struct nf_con
+ {
+ int err;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (cda[CTA_HELP-1]) {
+ err = ctnetlink_change_helper(ct, cda);
+ if (err < 0)
+@@ -1032,7 +939,6 @@ ctnetlink_change_conntrack(struct nf_con
+ ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+ #endif
+
+- DEBUGP("all done\n");
+ return 0;
+ }
+
+@@ -1044,8 +950,6 @@ ctnetlink_create_conntrack(struct nfattr
+ struct nf_conn *ct;
+ int err = -EINVAL;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ ct = nf_conntrack_alloc(otuple, rtuple);
+ if (ct == NULL || IS_ERR(ct))
+ return -ENOMEM;
+@@ -1075,7 +979,6 @@ ctnetlink_create_conntrack(struct nfattr
+ add_timer(&ct->timeout);
+ nf_conntrack_hash_insert(ct);
+
+- DEBUGP("conntrack with id %u inserted\n", ct->id);
+ return 0;
+
+ err:
+@@ -1093,8 +996,6 @@ ctnetlink_new_conntrack(struct sock *ctn
+ u_int8_t u3 = nfmsg->nfgen_family;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
+@@ -1118,7 +1019,6 @@ ctnetlink_new_conntrack(struct sock *ctn
+
+ if (h == NULL) {
+ write_unlock_bh(&nf_conntrack_lock);
+- DEBUGP("no such conntrack, create new\n");
+ err = -ENOENT;
+ if (nlh->nlmsg_flags & NLM_F_CREATE)
+ err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
+@@ -1134,7 +1034,6 @@ ctnetlink_new_conntrack(struct sock *ctn
+
+ /* We manipulate the conntrack inside the global conntrack table lock,
+ * so there's no need to increase the refcount */
+- DEBUGP("conntrack found\n");
+ err = -EEXIST;
+ if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+ err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda);
+@@ -1274,6 +1173,9 @@ static int ctnetlink_expect_event(struct
+ } else
+ return NOTIFY_DONE;
+
++ if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW))
++ return NOTIFY_DONE;
++
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+ if (!skb)
+ return NOTIFY_DONE;
+@@ -1312,8 +1214,6 @@ ctnetlink_exp_dump_table(struct sk_buff
+ struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
+ u_int8_t l3proto = nfmsg->nfgen_family;
+
+- DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
+-
+ read_lock_bh(&nf_conntrack_lock);
+ list_for_each_prev(i, &nf_conntrack_expect_list) {
+ exp = (struct nf_conntrack_expect *) i;
+@@ -1331,8 +1231,6 @@ ctnetlink_exp_dump_table(struct sk_buff
+ out:
+ read_unlock_bh(&nf_conntrack_lock);
+
+- DEBUGP("leaving, last id=%llu\n", *id);
+-
+ return skb->len;
+ }
+
+@@ -1352,8 +1250,6 @@ ctnetlink_get_expect(struct sock *ctnl,
+ u_int8_t u3 = nfmsg->nfgen_family;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
+@@ -1504,8 +1400,6 @@ ctnetlink_create_expect(struct nfattr *c
+ struct nf_conn_help *help;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ /* caller guarantees that those three CTA_EXPECT_* exist */
+ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
+ if (err < 0)
+@@ -1560,8 +1454,6 @@ ctnetlink_new_expect(struct sock *ctnl,
+ u_int8_t u3 = nfmsg->nfgen_family;
+ int err = 0;
+
+- DEBUGP("entered %s\n", __FUNCTION__);
+-
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
+@@ -1590,8 +1482,6 @@ ctnetlink_new_expect(struct sock *ctnl,
+ err = ctnetlink_change_expect(exp, cda);
+ write_unlock_bh(&nf_conntrack_lock);
+
+- DEBUGP("leaving\n");
+-
+ return err;
+ }
+
+diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
+index 46bc27e..26408bb 100644
+--- a/net/netfilter/nf_conntrack_proto_generic.c
++++ b/net/netfilter/nf_conntrack_proto_generic.c
+@@ -17,7 +17,7 @@
+ #include <linux/netfilter.h>
+ #include <net/netfilter/nf_conntrack_protocol.h>
+
+-unsigned int nf_ct_generic_timeout = 600*HZ;
++unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
+
+ static int generic_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
+index 9bd8a78..af56877 100644
+--- a/net/netfilter/nf_conntrack_proto_sctp.c
++++ b/net/netfilter/nf_conntrack_proto_sctp.c
+@@ -64,13 +64,13 @@ static const char *sctp_conntrack_names[
+ #define HOURS * 60 MINS
+ #define DAYS * 24 HOURS
+
+-static unsigned int nf_ct_sctp_timeout_closed = 10 SECS;
+-static unsigned int nf_ct_sctp_timeout_cookie_wait = 3 SECS;
+-static unsigned int nf_ct_sctp_timeout_cookie_echoed = 3 SECS;
+-static unsigned int nf_ct_sctp_timeout_established = 5 DAYS;
+-static unsigned int nf_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000;
+-static unsigned int nf_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000;
+-static unsigned int nf_ct_sctp_timeout_shutdown_ack_sent = 3 SECS;
++static unsigned int nf_ct_sctp_timeout_closed __read_mostly = 10 SECS;
++static unsigned int nf_ct_sctp_timeout_cookie_wait __read_mostly = 3 SECS;
++static unsigned int nf_ct_sctp_timeout_cookie_echoed __read_mostly = 3 SECS;
++static unsigned int nf_ct_sctp_timeout_established __read_mostly = 5 DAYS;
++static unsigned int nf_ct_sctp_timeout_shutdown_sent __read_mostly = 300 SECS / 1000;
++static unsigned int nf_ct_sctp_timeout_shutdown_recd __read_mostly = 300 SECS / 1000;
++static unsigned int nf_ct_sctp_timeout_shutdown_ack_sent __read_mostly = 3 SECS;
+
+ static unsigned int * sctp_timeouts[]
+ = { NULL, /* SCTP_CONNTRACK_NONE */
+diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
+index af8adcb..238bbb5 100644
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -57,19 +57,19 @@ static DEFINE_RWLOCK(tcp_lock);
+ /* "Be conservative in what you do,
+ be liberal in what you accept from others."
+ If it's non-zero, we mark only out of window RST segments as INVALID. */
+-int nf_ct_tcp_be_liberal = 0;
++int nf_ct_tcp_be_liberal __read_mostly = 0;
+
+ /* When connection is picked up from the middle, how many packets are required
+ to pass in each direction when we assume we are in sync - if any side uses
+ window scaling, we lost the game.
+ If it is set to zero, we disable picking up already established
+ connections. */
+-int nf_ct_tcp_loose = 3;
++int nf_ct_tcp_loose __read_mostly = 3;
+
+ /* Max number of the retransmitted packets without receiving an (acceptable)
+ ACK from the destination. If this number is reached, a shorter timer
+ will be started. */
+-int nf_ct_tcp_max_retrans = 3;
++int nf_ct_tcp_max_retrans __read_mostly = 3;
+
+ /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+ closely. They're more complex. --RR */
+@@ -92,19 +92,19 @@ static const char *tcp_conntrack_names[]
+ #define HOURS * 60 MINS
+ #define DAYS * 24 HOURS
+
+-unsigned int nf_ct_tcp_timeout_syn_sent = 2 MINS;
+-unsigned int nf_ct_tcp_timeout_syn_recv = 60 SECS;
+-unsigned int nf_ct_tcp_timeout_established = 5 DAYS;
+-unsigned int nf_ct_tcp_timeout_fin_wait = 2 MINS;
+-unsigned int nf_ct_tcp_timeout_close_wait = 60 SECS;
+-unsigned int nf_ct_tcp_timeout_last_ack = 30 SECS;
+-unsigned int nf_ct_tcp_timeout_time_wait = 2 MINS;
+-unsigned int nf_ct_tcp_timeout_close = 10 SECS;
++unsigned int nf_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS;
++unsigned int nf_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS;
++unsigned int nf_ct_tcp_timeout_established __read_mostly = 5 DAYS;
++unsigned int nf_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS;
++unsigned int nf_ct_tcp_timeout_close_wait __read_mostly = 60 SECS;
++unsigned int nf_ct_tcp_timeout_last_ack __read_mostly = 30 SECS;
++unsigned int nf_ct_tcp_timeout_time_wait __read_mostly = 2 MINS;
++unsigned int nf_ct_tcp_timeout_close __read_mostly = 10 SECS;
+
+ /* RFC1122 says the R2 limit should be at least 100 seconds.
+ Linux uses 15 packets as limit, which corresponds
+ to ~13-30min depending on RTO. */
+-unsigned int nf_ct_tcp_timeout_max_retrans = 5 MINS;
++unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS;
+
+ static unsigned int * tcp_timeouts[]
+ = { NULL, /* TCP_CONNTRACK_NONE */
+@@ -688,13 +688,15 @@ static int tcp_in_window(struct ip_ct_tc
+ if (state->last_dir == dir
+ && state->last_seq == seq
+ && state->last_ack == ack
+- && state->last_end == end)
++ && state->last_end == end
++ && state->last_win == win)
+ state->retrans++;
+ else {
+ state->last_dir = dir;
+ state->last_seq = seq;
+ state->last_ack = ack;
+ state->last_end = end;
++ state->last_win = win;
+ state->retrans = 0;
+ }
+ }
+@@ -823,8 +825,7 @@ static int tcp_error(struct sk_buff *skb
+
+ /* Checksum invalid? Ignore.
+ * We skip checking packets on the outgoing path
+- * because the semantic of CHECKSUM_HW is different there
+- * and moreover root might send raw packets.
++ * because the checksum is assumed to be correct.
+ */
+ /* FIXME: Source route IP option packets --RR */
+ if (nf_conntrack_checksum &&
+diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
+index ae07ebe..d28981c 100644
+--- a/net/netfilter/nf_conntrack_proto_udp.c
++++ b/net/netfilter/nf_conntrack_proto_udp.c
+@@ -27,8 +27,8 @@
+ #include <linux/netfilter_ipv6.h>
+ #include <net/netfilter/nf_conntrack_protocol.h>
+
+-unsigned int nf_ct_udp_timeout = 30*HZ;
+-unsigned int nf_ct_udp_timeout_stream = 180*HZ;
++unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ;
++unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
+
+ static int udp_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+@@ -131,8 +131,7 @@ static int udp_error(struct sk_buff *skb
+
+ /* Checksum invalid? Ignore.
+ * We skip checking packets on the outgoing path
+- * because the semantic of CHECKSUM_HW is different there
+- * and moreover root might send raw packets.
++ * because the checksum is assumed to be correct.
+ * FIXME: Source route IP option packets --RR */
+ if (nf_conntrack_checksum &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
+index 4ef8366..5954f67 100644
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -37,7 +37,6 @@
+ #include <net/netfilter/nf_conntrack_protocol.h>
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_helper.h>
+-#include <linux/netfilter_ipv4/listhelp.h>
+
+ #if 0
+ #define DEBUGP printk
+@@ -428,7 +427,7 @@ static struct file_operations ct_cpu_seq
+
+ /* Sysctl support */
+
+-int nf_conntrack_checksum = 1;
++int nf_conntrack_checksum __read_mostly = 1;
+
+ #ifdef CONFIG_SYSCTL
+
+diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
+index 86e392b..a981971 100644
+--- a/net/netfilter/nf_internals.h
++++ b/net/netfilter/nf_internals.h
+@@ -23,7 +23,7 @@ extern unsigned int nf_iterate(struct li
+ int hook_thresh);
+
+ /* nf_queue.c */
+-extern int nf_queue(struct sk_buff **skb,
++extern int nf_queue(struct sk_buff *skb,
+ struct list_head *elem,
+ int pf, unsigned int hook,
+ struct net_device *indev,
+diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
+index 662a869..4d8936e 100644
+--- a/net/netfilter/nf_queue.c
++++ b/net/netfilter/nf_queue.c
+@@ -74,13 +74,13 @@ EXPORT_SYMBOL_GPL(nf_unregister_queue_ha
+ * Any packet that leaves via this function must come back
+ * through nf_reinject().
+ */
+-int nf_queue(struct sk_buff **skb,
+- struct list_head *elem,
+- int pf, unsigned int hook,
+- struct net_device *indev,
+- struct net_device *outdev,
+- int (*okfn)(struct sk_buff *),
+- unsigned int queuenum)
++static int __nf_queue(struct sk_buff *skb,
++ struct list_head *elem,
++ int pf, unsigned int hook,
++ struct net_device *indev,
++ struct net_device *outdev,
++ int (*okfn)(struct sk_buff *),
++ unsigned int queuenum)
+ {
+ int status;
+ struct nf_info *info;
+@@ -94,14 +94,14 @@ int nf_queue(struct sk_buff **skb,
+ read_lock(&queue_handler_lock);
+ if (!queue_handler[pf]) {
+ read_unlock(&queue_handler_lock);
+- kfree_skb(*skb);
++ kfree_skb(skb);
+ return 1;
+ }
+
+ afinfo = nf_get_afinfo(pf);
+ if (!afinfo) {
+ read_unlock(&queue_handler_lock);
+- kfree_skb(*skb);
++ kfree_skb(skb);
+ return 1;
+ }
+
+@@ -109,9 +109,9 @@ int nf_queue(struct sk_buff **skb,
+ if (!info) {
+ if (net_ratelimit())
+ printk(KERN_ERR "OOM queueing packet %p\n",
+- *skb);
++ skb);
+ read_unlock(&queue_handler_lock);
+- kfree_skb(*skb);
++ kfree_skb(skb);
+ return 1;
+ }
+
+@@ -130,15 +130,15 @@ int nf_queue(struct sk_buff **skb,
+ if (outdev) dev_hold(outdev);
+
+ #ifdef CONFIG_BRIDGE_NETFILTER
+- if ((*skb)->nf_bridge) {
+- physindev = (*skb)->nf_bridge->physindev;
++ if (skb->nf_bridge) {
++ physindev = skb->nf_bridge->physindev;
+ if (physindev) dev_hold(physindev);
+- physoutdev = (*skb)->nf_bridge->physoutdev;
++ physoutdev = skb->nf_bridge->physoutdev;
+ if (physoutdev) dev_hold(physoutdev);
+ }
+ #endif
+- afinfo->saveroute(*skb, info);
+- status = queue_handler[pf]->outfn(*skb, info, queuenum,
++ afinfo->saveroute(skb, info);
++ status = queue_handler[pf]->outfn(skb, info, queuenum,
+ queue_handler[pf]->data);
+
+ read_unlock(&queue_handler_lock);
+@@ -153,7 +153,7 @@ int nf_queue(struct sk_buff **skb,
+ #endif
+ module_put(info->elem->owner);
+ kfree(info);
+- kfree_skb(*skb);
++ kfree_skb(skb);
+
+ return 1;
+ }
+@@ -161,6 +161,46 @@ int nf_queue(struct sk_buff **skb,
+ return 1;
+ }
+
++int nf_queue(struct sk_buff *skb,
++ struct list_head *elem,
++ int pf, unsigned int hook,
++ struct net_device *indev,
++ struct net_device *outdev,
++ int (*okfn)(struct sk_buff *),
++ unsigned int queuenum)
++{
++ struct sk_buff *segs;
++
++ if (!skb_is_gso(skb))
++ return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
++ queuenum);
++
++ switch (pf) {
++ case AF_INET:
++ skb->protocol = htons(ETH_P_IP);
++ break;
++ case AF_INET6:
++ skb->protocol = htons(ETH_P_IPV6);
++ break;
++ }
++
++ segs = skb_gso_segment(skb, 0);
++ kfree_skb(skb);
++ if (unlikely(IS_ERR(segs)))
++ return 1;
++
++ do {
++ struct sk_buff *nskb = segs->next;
++
++ segs->next = NULL;
++ if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn,
++ queuenum))
++ kfree_skb(segs);
++ segs = nskb;
++ } while (segs);
++ return 1;
++}
++
+ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
+ unsigned int verdict)
+ {
+@@ -224,9 +264,9 @@ void nf_reinject(struct sk_buff *skb, st
+ case NF_STOLEN:
+ break;
+ case NF_QUEUE:
+- if (!nf_queue(&skb, elem, info->pf, info->hook,
+- info->indev, info->outdev, info->okfn,
+- verdict >> NF_VERDICT_BITS))
++ if (!__nf_queue(skb, elem, info->pf, info->hook,
++ info->indev, info->outdev, info->okfn,
++ verdict >> NF_VERDICT_BITS))
+ goto next_hook;
+ break;
+ default:
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index b59d3b2..b2bf8f2 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -427,7 +427,7 @@ __build_packet_message(struct nfulnl_ins
+ nfmsg->version = NFNETLINK_V0;
+ nfmsg->res_id = htons(inst->group_num);
+
+- pmsg.hw_protocol = htons(skb->protocol);
++ pmsg.hw_protocol = skb->protocol;
+ pmsg.hook = hooknum;
+
+ NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg);
+@@ -878,7 +878,7 @@ nfulnl_recv_config(struct sock *ctnl, st
+ params = NFA_DATA(nfula[NFULA_CFG_MODE-1]);
+
+ nfulnl_set_mode(inst, params->copy_mode,
+- ntohs(params->copy_range));
++ ntohl(params->copy_range));
+ }
+
+ if (nfula[NFULA_CFG_TIMEOUT-1]) {
+@@ -896,8 +896,8 @@ nfulnl_recv_config(struct sock *ctnl, st
+ }
+
+ if (nfula[NFULA_CFG_QTHRESH-1]) {
+- u_int32_t qthresh =
+- *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_QTHRESH-1]);
++ __be32 qthresh =
++ *(__be32 *)NFA_DATA(nfula[NFULA_CFG_QTHRESH-1]);
+
+ nfulnl_set_qthresh(inst, ntohl(qthresh));
+ }
+diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
+index 49ef41e..6e4ada3 100644
+--- a/net/netfilter/nfnetlink_queue.c
++++ b/net/netfilter/nfnetlink_queue.c
+@@ -377,9 +377,9 @@ nfqnl_build_packet_message(struct nfqnl_
+ break;
+
+ case NFQNL_COPY_PACKET:
+- if (entskb->ip_summed == CHECKSUM_HW &&
+- (*errp = skb_checksum_help(entskb,
+- outdev == NULL))) {
++ if ((entskb->ip_summed == CHECKSUM_PARTIAL ||
++ entskb->ip_summed == CHECKSUM_COMPLETE) &&
++ (*errp = skb_checksum_help(entskb))) {
+ spin_unlock_bh(&queue->lock);
+ return NULL;
+ }
+@@ -414,7 +414,7 @@ nfqnl_build_packet_message(struct nfqnl_
+ nfmsg->res_id = htons(queue->queue_num);
+
+ pmsg.packet_id = htonl(entry->id);
+- pmsg.hw_protocol = htons(entskb->protocol);
++ pmsg.hw_protocol = entskb->protocol;
+ pmsg.hook = entinf->hook;
+
+ NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg);
+@@ -584,7 +584,7 @@ nfqnl_enqueue_packet(struct sk_buff *skb
+ queue->queue_dropped++;
+ status = -ENOSPC;
+ if (net_ratelimit())
+- printk(KERN_WARNING "ip_queue: full at %d entries, "
++ printk(KERN_WARNING "nf_queue: full at %d entries, "
+ "dropping packets(s). Dropped: %d\n",
+ queue->queue_total, queue->queue_dropped);
+ goto err_out_free_nskb;
+@@ -635,7 +635,7 @@ nfqnl_mangle(void *data, int data_len, s
+ diff,
+ GFP_ATOMIC);
+ if (newskb == NULL) {
+- printk(KERN_WARNING "ip_queue: OOM "
++ printk(KERN_WARNING "nf_queue: OOM "
+ "in mangle, dropping packet\n");
+ return -ENOMEM;
+ }
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index 174e8f9..58522fc 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -81,12 +81,42 @@ xt_unregister_target(struct xt_target *t
+ int af = target->family;
+
+ mutex_lock(&xt[af].mutex);
+- LIST_DELETE(&xt[af].target, target);
++ list_del(&target->list);
+ mutex_unlock(&xt[af].mutex);
+ }
+ EXPORT_SYMBOL(xt_unregister_target);
+
+ int
++xt_register_targets(struct xt_target *target, unsigned int n)
++{
++ unsigned int i;
++ int err = 0;
++
++ for (i = 0; i < n; i++) {
++ err = xt_register_target(&target[i]);
++ if (err)
++ goto err;
++ }
++ return err;
++
++err:
++ if (i > 0)
++ xt_unregister_targets(target, i);
++ return err;
++}
++EXPORT_SYMBOL(xt_register_targets);
++
++void
++xt_unregister_targets(struct xt_target *target, unsigned int n)
++{
++ unsigned int i;
++
++ for (i = 0; i < n; i++)
++ xt_unregister_target(&target[i]);
++}
++EXPORT_SYMBOL(xt_unregister_targets);
++
++int
+ xt_register_match(struct xt_match *match)
+ {
+ int ret, af = match->family;
+@@ -108,11 +138,41 @@ xt_unregister_match(struct xt_match *mat
+ int af = match->family;
+
+ mutex_lock(&xt[af].mutex);
+- LIST_DELETE(&xt[af].match, match);
++ list_del(&match->list);
+ mutex_unlock(&xt[af].mutex);
+ }
+ EXPORT_SYMBOL(xt_unregister_match);
+
++int
++xt_register_matches(struct xt_match *match, unsigned int n)
++{
++ unsigned int i;
++ int err = 0;
++
++ for (i = 0; i < n; i++) {
++ err = xt_register_match(&match[i]);
++ if (err)
++ goto err;
++ }
++ return err;
++
++err:
++ if (i > 0)
++ xt_unregister_matches(match, i);
++ return err;
++}
++EXPORT_SYMBOL(xt_register_matches);
++
++void
++xt_unregister_matches(struct xt_match *match, unsigned int n)
++{
++ unsigned int i;
++
++ for (i = 0; i < n; i++)
++ xt_unregister_match(&match[i]);
++}
++EXPORT_SYMBOL(xt_unregister_matches);
++
+
+ /*
+ * These are weird, but module loading must not be done with mutex
+@@ -273,52 +333,65 @@ int xt_check_match(const struct xt_match
+ EXPORT_SYMBOL_GPL(xt_check_match);
+
+ #ifdef CONFIG_COMPAT
+-int xt_compat_match(void *match, void **dstptr, int *size, int convert)
++int xt_compat_match_offset(struct xt_match *match)
+ {
+- struct xt_match *m;
+- struct compat_xt_entry_match *pcompat_m;
+- struct xt_entry_match *pm;
+- u_int16_t msize;
+- int off, ret;
++ u_int16_t csize = match->compatsize ? : match->matchsize;
++ return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
++}
++EXPORT_SYMBOL_GPL(xt_compat_match_offset);
+
+- ret = 0;
+- m = ((struct xt_entry_match *)match)->u.kernel.match;
+- off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize);
+- switch (convert) {
+- case COMPAT_TO_USER:
+- pm = (struct xt_entry_match *)match;
+- msize = pm->u.user.match_size;
+- if (copy_to_user(*dstptr, pm, msize)) {
+- ret = -EFAULT;
+- break;
+- }
+- msize -= off;
+- if (put_user(msize, (u_int16_t *)*dstptr))
+- ret = -EFAULT;
+- *size -= off;
+- *dstptr += msize;
+- break;
+- case COMPAT_FROM_USER:
+- pcompat_m = (struct compat_xt_entry_match *)match;
+- pm = (struct xt_entry_match *)*dstptr;
+- msize = pcompat_m->u.user.match_size;
+- memcpy(pm, pcompat_m, msize);
+- msize += off;
+- pm->u.user.match_size = msize;
+- *size += off;
+- *dstptr += msize;
+- break;
+- case COMPAT_CALC_SIZE:
+- *size += off;
+- break;
+- default:
+- ret = -ENOPROTOOPT;
+- break;
++void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
++ int *size)
++{
++ struct xt_match *match = m->u.kernel.match;
++ struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
++ int pad, off = xt_compat_match_offset(match);
++ u_int16_t msize = cm->u.user.match_size;
++
++ m = *dstptr;
++ memcpy(m, cm, sizeof(*cm));
++ if (match->compat_from_user)
++ match->compat_from_user(m->data, cm->data);
++ else
++ memcpy(m->data, cm->data, msize - sizeof(*cm));
++ pad = XT_ALIGN(match->matchsize) - match->matchsize;
++ if (pad > 0)
++ memset(m->data + match->matchsize, 0, pad);
++
++ msize += off;
++ m->u.user.match_size = msize;
++
++ *size += off;
++ *dstptr += msize;
++}
++EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
++
++int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
++ int *size)
++{
++ struct xt_match *match = m->u.kernel.match;
++ struct compat_xt_entry_match __user *cm = *dstptr;
++ int off = xt_compat_match_offset(match);
++ u_int16_t msize = m->u.user.match_size - off;
++
++ if (copy_to_user(cm, m, sizeof(*cm)) ||
++ put_user(msize, &cm->u.user.match_size))
++ return -EFAULT;
++
++ if (match->compat_to_user) {
++ if (match->compat_to_user((void __user *)cm->data, m->data))
++ return -EFAULT;
++ } else {
++ if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
++ return -EFAULT;
+ }
+- return ret;
++
++ *size -= off;
++ *dstptr += msize;
++ return 0;
+ }
+-EXPORT_SYMBOL_GPL(xt_compat_match);
+-#endif
++EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
++#endif /* CONFIG_COMPAT */
+
+ int xt_check_target(const struct xt_target *target, unsigned short family,
+ unsigned int size, const char *table, unsigned int hook_mask,
+@@ -350,51 +423,64 @@ int xt_check_target(const struct xt_targ
+ EXPORT_SYMBOL_GPL(xt_check_target);
+
+ #ifdef CONFIG_COMPAT
+-int xt_compat_target(void *target, void **dstptr, int *size, int convert)
++int xt_compat_target_offset(struct xt_target *target)
+ {
+- struct xt_target *t;
+- struct compat_xt_entry_target *pcompat;
+- struct xt_entry_target *pt;
+- u_int16_t tsize;
+- int off, ret;
++ u_int16_t csize = target->compatsize ? : target->targetsize;
++ return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
++}
++EXPORT_SYMBOL_GPL(xt_compat_target_offset);
+
+- ret = 0;
+- t = ((struct xt_entry_target *)target)->u.kernel.target;
+- off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize);
+- switch (convert) {
+- case COMPAT_TO_USER:
+- pt = (struct xt_entry_target *)target;
+- tsize = pt->u.user.target_size;
+- if (copy_to_user(*dstptr, pt, tsize)) {
+- ret = -EFAULT;
+- break;
+- }
+- tsize -= off;
+- if (put_user(tsize, (u_int16_t *)*dstptr))
+- ret = -EFAULT;
+- *size -= off;
+- *dstptr += tsize;
+- break;
+- case COMPAT_FROM_USER:
+- pcompat = (struct compat_xt_entry_target *)target;
+- pt = (struct xt_entry_target *)*dstptr;
+- tsize = pcompat->u.user.target_size;
+- memcpy(pt, pcompat, tsize);
+- tsize += off;
+- pt->u.user.target_size = tsize;
+- *size += off;
+- *dstptr += tsize;
+- break;
+- case COMPAT_CALC_SIZE:
+- *size += off;
+- break;
+- default:
+- ret = -ENOPROTOOPT;
+- break;
++void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
++ int *size)
++{
++ struct xt_target *target = t->u.kernel.target;
++ struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
++ int pad, off = xt_compat_target_offset(target);
++ u_int16_t tsize = ct->u.user.target_size;
++
++ t = *dstptr;
++ memcpy(t, ct, sizeof(*ct));
++ if (target->compat_from_user)
++ target->compat_from_user(t->data, ct->data);
++ else
++ memcpy(t->data, ct->data, tsize - sizeof(*ct));
++ pad = XT_ALIGN(target->targetsize) - target->targetsize;
++ if (pad > 0)
++ memset(t->data + target->targetsize, 0, pad);
++
++ tsize += off;
++ t->u.user.target_size = tsize;
++
++ *size += off;
++ *dstptr += tsize;
++}
++EXPORT_SYMBOL_GPL(xt_compat_target_from_user);
++
++int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
++ int *size)
++{
++ struct xt_target *target = t->u.kernel.target;
++ struct compat_xt_entry_target __user *ct = *dstptr;
++ int off = xt_compat_target_offset(target);
++ u_int16_t tsize = t->u.user.target_size - off;
++
++ if (copy_to_user(ct, t, sizeof(*ct)) ||
++ put_user(tsize, &ct->u.user.target_size))
++ return -EFAULT;
++
++ if (target->compat_to_user) {
++ if (target->compat_to_user((void __user *)ct->data, t->data))
++ return -EFAULT;
++ } else {
++ if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
++ return -EFAULT;
+ }
+- return ret;
++
++ *size -= off;
++ *dstptr += tsize;
++ return 0;
+ }
+-EXPORT_SYMBOL_GPL(xt_compat_target);
++EXPORT_SYMBOL_GPL(xt_compat_target_to_user);
+ #endif
+
+ struct xt_table_info *xt_alloc_table_info(unsigned int size)
+@@ -515,15 +601,18 @@ int xt_register_table(struct xt_table *t
+ {
+ int ret;
+ struct xt_table_info *private;
++ struct xt_table *t;
+
+ ret = mutex_lock_interruptible(&xt[table->af].mutex);
+ if (ret != 0)
+ return ret;
+
+ /* Don't autoload: we'd eat our tail... */
+- if (list_named_find(&xt[table->af].tables, table->name)) {
+- ret = -EEXIST;
+- goto unlock;
++ list_for_each_entry(t, &xt[table->af].tables, list) {
++ if (strcmp(t->name, table->name) == 0) {
++ ret = -EEXIST;
++ goto unlock;
++ }
+ }
+
+ /* Simplifies replace_table code. */
+@@ -538,7 +627,7 @@ int xt_register_table(struct xt_table *t
+ /* save number of initial entries */
+ private->initial_entries = private->number;
+
+- list_prepend(&xt[table->af].tables, table);
++ list_add(&table->list, &xt[table->af].tables);
+
+ ret = 0;
+ unlock:
+@@ -553,7 +642,7 @@ void *xt_unregister_table(struct xt_tabl
+
+ mutex_lock(&xt[table->af].mutex);
+ private = table->private;
+- LIST_DELETE(&xt[table->af].tables, table);
++ list_del(&table->list);
+ mutex_unlock(&xt[table->af].mutex);
+
+ return private;
+diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
+index e54e577..50de965 100644
+--- a/net/netfilter/xt_CLASSIFY.c
++++ b/net/netfilter/xt_CLASSIFY.c
+@@ -29,8 +29,7 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct xt_classify_target_info *clinfo = targinfo;
+
+@@ -40,47 +39,41 @@ target(struct sk_buff **pskb,
+ return XT_CONTINUE;
+ }
+
+-static struct xt_target classify_reg = {
+- .name = "CLASSIFY",
+- .target = target,
+- .targetsize = sizeof(struct xt_classify_target_info),
+- .table = "mangle",
+- .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+- (1 << NF_IP_POST_ROUTING),
+- .family = AF_INET,
+- .me = THIS_MODULE,
++static struct xt_target xt_classify_target[] = {
++ {
++ .family = AF_INET,
++ .name = "CLASSIFY",
++ .target = target,
++ .targetsize = sizeof(struct xt_classify_target_info),
++ .table = "mangle",
++ .hooks = (1 << NF_IP_LOCAL_OUT) |
++ (1 << NF_IP_FORWARD) |
++ (1 << NF_IP_POST_ROUTING),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "CLASSIFY",
++ .family = AF_INET6,
++ .target = target,
++ .targetsize = sizeof(struct xt_classify_target_info),
++ .table = "mangle",
++ .hooks = (1 << NF_IP_LOCAL_OUT) |
++ (1 << NF_IP_FORWARD) |
++ (1 << NF_IP_POST_ROUTING),
++ .me = THIS_MODULE,
++ },
+ };
+-static struct xt_target classify6_reg = {
+- .name = "CLASSIFY",
+- .target = target,
+- .targetsize = sizeof(struct xt_classify_target_info),
+- .table = "mangle",
+- .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+- (1 << NF_IP_POST_ROUTING),
+- .family = AF_INET6,
+- .me = THIS_MODULE,
+-};
+-
+
+ static int __init xt_classify_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_target(&classify_reg);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_target(&classify6_reg);
+- if (ret)
+- xt_unregister_target(&classify_reg);
+-
+- return ret;
++ return xt_register_targets(xt_classify_target,
++ ARRAY_SIZE(xt_classify_target));
+ }
+
+ static void __exit xt_classify_fini(void)
+ {
+- xt_unregister_target(&classify_reg);
+- xt_unregister_target(&classify6_reg);
++ xt_unregister_targets(xt_classify_target,
++ ARRAY_SIZE(xt_classify_target));
+ }
+
+ module_init(xt_classify_init);
+diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
+index 60c375d..c01524f 100644
+--- a/net/netfilter/xt_CONNMARK.c
++++ b/net/netfilter/xt_CONNMARK.c
+@@ -38,8 +38,7 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct xt_connmark_target_info *markinfo = targinfo;
+ u_int32_t diff;
+@@ -49,24 +48,37 @@ target(struct sk_buff **pskb,
+ u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
+
+ if (ctmark) {
+- switch(markinfo->mode) {
+- case XT_CONNMARK_SET:
+- newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
+- if (newmark != *ctmark)
+- *ctmark = newmark;
+- break;
+- case XT_CONNMARK_SAVE:
+- newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
+- if (*ctmark != newmark)
+- *ctmark = newmark;
+- break;
+- case XT_CONNMARK_RESTORE:
+- nfmark = (*pskb)->nfmark;
+- diff = (*ctmark ^ nfmark) & markinfo->mask;
+- if (diff != 0)
+- (*pskb)->nfmark = nfmark ^ diff;
+- break;
+- }
++ switch(markinfo->mode) {
++ case XT_CONNMARK_SET:
++ newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
++ if (newmark != *ctmark) {
++ *ctmark = newmark;
++#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
++ ip_conntrack_event_cache(IPCT_MARK, *pskb);
++#else
++ nf_conntrack_event_cache(IPCT_MARK, *pskb);
++#endif
++ }
++ break;
++ case XT_CONNMARK_SAVE:
++ newmark = (*ctmark & ~markinfo->mask) |
++ ((*pskb)->nfmark & markinfo->mask);
++ if (*ctmark != newmark) {
++ *ctmark = newmark;
++#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
++ ip_conntrack_event_cache(IPCT_MARK, *pskb);
++#else
++ nf_conntrack_event_cache(IPCT_MARK, *pskb);
++#endif
++ }
++ break;
++ case XT_CONNMARK_RESTORE:
++ nfmark = (*pskb)->nfmark;
++ diff = (*ctmark ^ nfmark) & markinfo->mask;
++ if (diff != 0)
++ (*pskb)->nfmark = nfmark ^ diff;
++ break;
++ }
+ }
+
+ return XT_CONTINUE;
+@@ -77,65 +89,91 @@ checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct xt_connmark_target_info *matchinfo = targinfo;
+
+ if (matchinfo->mode == XT_CONNMARK_RESTORE) {
+- if (strcmp(tablename, "mangle") != 0) {
+- printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+- return 0;
+- }
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING "CONNMARK: restore can only be "
++ "called from \"mangle\" table, not \"%s\"\n",
++ tablename);
++ return 0;
++ }
+ }
+-
+ if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
+ printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
+ return 0;
+ }
+-
+ return 1;
+ }
+
+-static struct xt_target connmark_reg = {
+- .name = "CONNMARK",
+- .target = target,
+- .targetsize = sizeof(struct xt_connmark_target_info),
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE
++#ifdef CONFIG_COMPAT
++struct compat_xt_connmark_target_info {
++ compat_ulong_t mark, mask;
++ u_int8_t mode;
++ u_int8_t __pad1;
++ u_int16_t __pad2;
+ };
+
+-static struct xt_target connmark6_reg = {
+- .name = "CONNMARK",
+- .target = target,
+- .targetsize = sizeof(struct xt_connmark_target_info),
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE
++static void compat_from_user(void *dst, void *src)
++{
++ struct compat_xt_connmark_target_info *cm = src;
++ struct xt_connmark_target_info m = {
++ .mark = cm->mark,
++ .mask = cm->mask,
++ .mode = cm->mode,
++ };
++ memcpy(dst, &m, sizeof(m));
++}
++
++static int compat_to_user(void __user *dst, void *src)
++{
++ struct xt_connmark_target_info *m = src;
++ struct compat_xt_connmark_target_info cm = {
++ .mark = m->mark,
++ .mask = m->mask,
++ .mode = m->mode,
++ };
++ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
++}
++#endif /* CONFIG_COMPAT */
++
++static struct xt_target xt_connmark_target[] = {
++ {
++ .name = "CONNMARK",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_connmark_target_info),
++#ifdef CONFIG_COMPAT
++ .compatsize = sizeof(struct compat_xt_connmark_target_info),
++ .compat_from_user = compat_from_user,
++ .compat_to_user = compat_to_user,
++#endif
++ .me = THIS_MODULE
++ },
++ {
++ .name = "CONNMARK",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_connmark_target_info),
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_connmark_init(void)
+ {
+- int ret;
+-
+ need_conntrack();
+-
+- ret = xt_register_target(&connmark_reg);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_target(&connmark6_reg);
+- if (ret)
+- xt_unregister_target(&connmark_reg);
+-
+- return ret;
++ return xt_register_targets(xt_connmark_target,
++ ARRAY_SIZE(xt_connmark_target));
+ }
+
+ static void __exit xt_connmark_fini(void)
+ {
+- xt_unregister_target(&connmark_reg);
+- xt_unregister_target(&connmark6_reg);
++ xt_unregister_targets(xt_connmark_target,
++ ARRAY_SIZE(xt_connmark_target));
+ }
+
+ module_init(xt_connmark_init);
+diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
+index 8c011e0..4673862 100644
+--- a/net/netfilter/xt_CONNSECMARK.c
++++ b/net/netfilter/xt_CONNSECMARK.c
+@@ -66,7 +66,7 @@ static void secmark_restore(struct sk_bu
+ static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
+ const struct net_device *out, unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo, void *userinfo)
++ const void *targinfo)
+ {
+ struct sk_buff *skb = *pskb;
+ const struct xt_connsecmark_target_info *info = targinfo;
+@@ -89,7 +89,7 @@ static unsigned int target(struct sk_buf
+
+ static int checkentry(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+- unsigned int targinfosize, unsigned int hook_mask)
++ unsigned int hook_mask)
+ {
+ struct xt_connsecmark_target_info *info = targinfo;
+
+@@ -106,49 +106,38 @@ static int checkentry(const char *tablen
+ return 1;
+ }
+
+-static struct xt_target ipt_connsecmark_reg = {
+- .name = "CONNSECMARK",
+- .target = target,
+- .targetsize = sizeof(struct xt_connsecmark_target_info),
+- .table = "mangle",
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
+- .family = AF_INET,
+- .revision = 0,
+-};
+-
+-static struct xt_target ip6t_connsecmark_reg = {
+- .name = "CONNSECMARK",
+- .target = target,
+- .targetsize = sizeof(struct xt_connsecmark_target_info),
+- .table = "mangle",
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
+- .family = AF_INET6,
+- .revision = 0,
++static struct xt_target xt_connsecmark_target[] = {
++ {
++ .name = "CONNSECMARK",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_connsecmark_target_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "CONNSECMARK",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_connsecmark_target_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_connsecmark_init(void)
+ {
+- int err;
+-
+ need_conntrack();
+-
+- err = xt_register_target(&ipt_connsecmark_reg);
+- if (err)
+- return err;
+-
+- err = xt_register_target(&ip6t_connsecmark_reg);
+- if (err)
+- xt_unregister_target(&ipt_connsecmark_reg);
+-
+- return err;
++ return xt_register_targets(xt_connsecmark_target,
++ ARRAY_SIZE(xt_connsecmark_target));
+ }
+
+ static void __exit xt_connsecmark_fini(void)
+ {
+- xt_unregister_target(&ip6t_connsecmark_reg);
+- xt_unregister_target(&ipt_connsecmark_reg);
++ xt_unregister_targets(xt_connsecmark_target,
++ ARRAY_SIZE(xt_connsecmark_target));
+ }
+
+ module_init(xt_connsecmark_init);
+diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
+new file mode 100644
+index 0000000..a7cc75a
+--- /dev/null
++++ b/net/netfilter/xt_DSCP.c
+@@ -0,0 +1,118 @@
++/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8
++ *
++ * (C) 2002 by Harald Welte <laforge at netfilter.org>
++ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm at paktronix.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.
++ *
++ * See RFC2474 for a description of the DSCP field within the IP Header.
++ *
++ * xt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/dsfield.h>
++
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_DSCP.h>
++
++MODULE_AUTHOR("Harald Welte <laforge at netfilter.org>");
++MODULE_DESCRIPTION("x_tables DSCP modification module");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_DSCP");
++MODULE_ALIAS("ip6t_DSCP");
++
++static unsigned int target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const struct xt_target *target,
++ const void *targinfo)
++{
++ const struct xt_DSCP_info *dinfo = targinfo;
++ u_int8_t dscp = ipv4_get_dsfield((*pskb)->nh.iph) >> XT_DSCP_SHIFT;
++
++ if (dscp != dinfo->dscp) {
++ if (!skb_make_writable(pskb, sizeof(struct iphdr)))
++ return NF_DROP;
++
++ ipv4_change_dsfield((*pskb)->nh.iph, (__u8)(~XT_DSCP_MASK),
++ dinfo->dscp << XT_DSCP_SHIFT);
++
++ }
++ return XT_CONTINUE;
++}
++
++static unsigned int target6(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const struct xt_target *target,
++ const void *targinfo)
++{
++ const struct xt_DSCP_info *dinfo = targinfo;
++ u_int8_t dscp = ipv6_get_dsfield((*pskb)->nh.ipv6h) >> XT_DSCP_SHIFT;
++
++ if (dscp != dinfo->dscp) {
++ if (!skb_make_writable(pskb, sizeof(struct ipv6hdr)))
++ return NF_DROP;
++
++ ipv6_change_dsfield((*pskb)->nh.ipv6h, (__u8)(~XT_DSCP_MASK),
++ dinfo->dscp << XT_DSCP_SHIFT);
++ }
++ return XT_CONTINUE;
++}
++
++static int checkentry(const char *tablename,
++ const void *e_void,
++ const struct xt_target *target,
++ void *targinfo,
++ unsigned int hook_mask)
++{
++ const u_int8_t dscp = ((struct xt_DSCP_info *)targinfo)->dscp;
++
++ if ((dscp > XT_DSCP_MAX)) {
++ printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
++ return 0;
++ }
++ return 1;
++}
++
++static struct xt_target xt_dscp_target[] = {
++ {
++ .name = "DSCP",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_DSCP_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "DSCP",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .target = target6,
++ .targetsize = sizeof(struct xt_DSCP_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
++};
++
++static int __init xt_dscp_target_init(void)
++{
++ return xt_register_targets(xt_dscp_target, ARRAY_SIZE(xt_dscp_target));
++}
++
++static void __exit xt_dscp_target_fini(void)
++{
++ xt_unregister_targets(xt_dscp_target, ARRAY_SIZE(xt_dscp_target));
++}
++
++module_init(xt_dscp_target_init);
++module_exit(xt_dscp_target_fini);
+diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
+index ee9c34e..c6e860a 100644
+--- a/net/netfilter/xt_MARK.c
++++ b/net/netfilter/xt_MARK.c
+@@ -27,8 +27,7 @@ target_v0(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct xt_mark_target_info *markinfo = targinfo;
+
+@@ -44,8 +43,7 @@ target_v1(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct xt_mark_target_info_v1 *markinfo = targinfo;
+ int mark = 0;
+@@ -76,7 +74,6 @@ checkentry_v0(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct xt_mark_target_info *markinfo = targinfo;
+@@ -93,7 +90,6 @@ checkentry_v1(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+- unsigned int targinfosize,
+ unsigned int hook_mask)
+ {
+ struct xt_mark_target_info_v1 *markinfo = targinfo;
+@@ -112,65 +108,81 @@ checkentry_v1(const char *tablename,
+ return 1;
+ }
+
+-static struct xt_target ipt_mark_reg_v0 = {
+- .name = "MARK",
+- .target = target_v0,
+- .targetsize = sizeof(struct xt_mark_target_info),
+- .table = "mangle",
+- .checkentry = checkentry_v0,
+- .me = THIS_MODULE,
+- .family = AF_INET,
+- .revision = 0,
++#ifdef CONFIG_COMPAT
++struct compat_xt_mark_target_info_v1 {
++ compat_ulong_t mark;
++ u_int8_t mode;
++ u_int8_t __pad1;
++ u_int16_t __pad2;
+ };
+
+-static struct xt_target ipt_mark_reg_v1 = {
+- .name = "MARK",
+- .target = target_v1,
+- .targetsize = sizeof(struct xt_mark_target_info_v1),
+- .table = "mangle",
+- .checkentry = checkentry_v1,
+- .me = THIS_MODULE,
+- .family = AF_INET,
+- .revision = 1,
+-};
++static void compat_from_user_v1(void *dst, void *src)
++{
++ struct compat_xt_mark_target_info_v1 *cm = src;
++ struct xt_mark_target_info_v1 m = {
++ .mark = cm->mark,
++ .mode = cm->mode,
++ };
++ memcpy(dst, &m, sizeof(m));
++}
+
+-static struct xt_target ip6t_mark_reg_v0 = {
+- .name = "MARK",
+- .target = target_v0,
+- .targetsize = sizeof(struct xt_mark_target_info),
+- .table = "mangle",
+- .checkentry = checkentry_v0,
+- .me = THIS_MODULE,
+- .family = AF_INET6,
+- .revision = 0,
++static int compat_to_user_v1(void __user *dst, void *src)
++{
++ struct xt_mark_target_info_v1 *m = src;
++ struct compat_xt_mark_target_info_v1 cm = {
++ .mark = m->mark,
++ .mode = m->mode,
++ };
++ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
++}
++#endif /* CONFIG_COMPAT */
++
++static struct xt_target xt_mark_target[] = {
++ {
++ .name = "MARK",
++ .family = AF_INET,
++ .revision = 0,
++ .checkentry = checkentry_v0,
++ .target = target_v0,
++ .targetsize = sizeof(struct xt_mark_target_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "MARK",
++ .family = AF_INET,
++ .revision = 1,
++ .checkentry = checkentry_v1,
++ .target = target_v1,
++ .targetsize = sizeof(struct xt_mark_target_info_v1),
++#ifdef CONFIG_COMPAT
++ .compatsize = sizeof(struct compat_xt_mark_target_info_v1),
++ .compat_from_user = compat_from_user_v1,
++ .compat_to_user = compat_to_user_v1,
++#endif
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "MARK",
++ .family = AF_INET6,
++ .revision = 0,
++ .checkentry = checkentry_v0,
++ .target = target_v0,
++ .targetsize = sizeof(struct xt_mark_target_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_mark_init(void)
+ {
+- int err;
+-
+- err = xt_register_target(&ipt_mark_reg_v0);
+- if (err)
+- return err;
+-
+- err = xt_register_target(&ipt_mark_reg_v1);
+- if (err)
+- xt_unregister_target(&ipt_mark_reg_v0);
+-
+- err = xt_register_target(&ip6t_mark_reg_v0);
+- if (err) {
+- xt_unregister_target(&ipt_mark_reg_v0);
+- xt_unregister_target(&ipt_mark_reg_v1);
+- }
+-
+- return err;
++ return xt_register_targets(xt_mark_target, ARRAY_SIZE(xt_mark_target));
+ }
+
+ static void __exit xt_mark_fini(void)
+ {
+- xt_unregister_target(&ipt_mark_reg_v0);
+- xt_unregister_target(&ipt_mark_reg_v1);
+- xt_unregister_target(&ip6t_mark_reg_v0);
++ xt_unregister_targets(xt_mark_target, ARRAY_SIZE(xt_mark_target));
+ }
+
+ module_init(xt_mark_init);
+diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
+index 86ccceb..39e1175 100644
+--- a/net/netfilter/xt_NFQUEUE.c
++++ b/net/netfilter/xt_NFQUEUE.c
+@@ -29,65 +29,46 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ const struct xt_NFQ_info *tinfo = targinfo;
+
+ return NF_QUEUE_NR(tinfo->queuenum);
+ }
+
+-static struct xt_target ipt_NFQ_reg = {
+- .name = "NFQUEUE",
+- .target = target,
+- .targetsize = sizeof(struct xt_NFQ_info),
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_target ip6t_NFQ_reg = {
+- .name = "NFQUEUE",
+- .target = target,
+- .targetsize = sizeof(struct xt_NFQ_info),
+- .family = AF_INET6,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_target arpt_NFQ_reg = {
+- .name = "NFQUEUE",
+- .target = target,
+- .targetsize = sizeof(struct xt_NFQ_info),
+- .family = NF_ARP,
+- .me = THIS_MODULE,
++static struct xt_target xt_nfqueue_target[] = {
++ {
++ .name = "NFQUEUE",
++ .family = AF_INET,
++ .target = target,
++ .targetsize = sizeof(struct xt_NFQ_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "NFQUEUE",
++ .family = AF_INET6,
++ .target = target,
++ .targetsize = sizeof(struct xt_NFQ_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "NFQUEUE",
++ .family = NF_ARP,
++ .target = target,
++ .targetsize = sizeof(struct xt_NFQ_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_nfqueue_init(void)
+ {
+- int ret;
+- ret = xt_register_target(&ipt_NFQ_reg);
+- if (ret)
+- return ret;
+- ret = xt_register_target(&ip6t_NFQ_reg);
+- if (ret)
+- goto out_ip;
+- ret = xt_register_target(&arpt_NFQ_reg);
+- if (ret)
+- goto out_ip6;
+-
+- return ret;
+-out_ip6:
+- xt_unregister_target(&ip6t_NFQ_reg);
+-out_ip:
+- xt_unregister_target(&ipt_NFQ_reg);
+-
+- return ret;
++ return xt_register_targets(xt_nfqueue_target,
++ ARRAY_SIZE(xt_nfqueue_target));
+ }
+
+ static void __exit xt_nfqueue_fini(void)
+ {
+- xt_unregister_target(&arpt_NFQ_reg);
+- xt_unregister_target(&ip6t_NFQ_reg);
+- xt_unregister_target(&ipt_NFQ_reg);
++ xt_unregister_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target));
+ }
+
+ module_init(xt_nfqueue_init);
+diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
+index 98f4b53..6d00dca 100644
+--- a/net/netfilter/xt_NOTRACK.c
++++ b/net/netfilter/xt_NOTRACK.c
+@@ -16,8 +16,7 @@ target(struct sk_buff **pskb,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo,
+- void *userinfo)
++ const void *targinfo)
+ {
+ /* Previously seen (loopback)? Ignore. */
+ if ((*pskb)->nfct != NULL)
+@@ -34,43 +33,32 @@ target(struct sk_buff **pskb,
+ return XT_CONTINUE;
+ }
+
+-static struct xt_target notrack_reg = {
+- .name = "NOTRACK",
+- .target = target,
+- .targetsize = 0,
+- .table = "raw",
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_target notrack6_reg = {
+- .name = "NOTRACK",
+- .target = target,
+- .targetsize = 0,
+- .table = "raw",
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_target xt_notrack_target[] = {
++ {
++ .name = "NOTRACK",
++ .family = AF_INET,
++ .target = target,
++ .table = "raw",
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "NOTRACK",
++ .family = AF_INET6,
++ .target = target,
++ .table = "raw",
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_notrack_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_target(¬rack_reg);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_target(¬rack6_reg);
+- if (ret)
+- xt_unregister_target(¬rack_reg);
+-
+- return ret;
++ return xt_register_targets(xt_notrack_target,
++ ARRAY_SIZE(xt_notrack_target));
+ }
+
+ static void __exit xt_notrack_fini(void)
+ {
+- xt_unregister_target(¬rack6_reg);
+- xt_unregister_target(¬rack_reg);
++ xt_unregister_targets(xt_notrack_target, ARRAY_SIZE(xt_notrack_target));
+ }
+
+ module_init(xt_notrack_init);
+diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
+index de9537a..add7521 100644
+--- a/net/netfilter/xt_SECMARK.c
++++ b/net/netfilter/xt_SECMARK.c
+@@ -31,7 +31,7 @@ static u8 mode;
+ static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
+ const struct net_device *out, unsigned int hooknum,
+ const struct xt_target *target,
+- const void *targinfo, void *userinfo)
++ const void *targinfo)
+ {
+ u32 secmark = 0;
+ const struct xt_secmark_target_info *info = targinfo;
+@@ -85,7 +85,7 @@ static int checkentry_selinux(struct xt_
+
+ static int checkentry(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+- unsigned int targinfosize, unsigned int hook_mask)
++ unsigned int hook_mask)
+ {
+ struct xt_secmark_target_info *info = targinfo;
+
+@@ -111,47 +111,36 @@ static int checkentry(const char *tablen
+ return 1;
+ }
+
+-static struct xt_target ipt_secmark_reg = {
+- .name = "SECMARK",
+- .target = target,
+- .targetsize = sizeof(struct xt_secmark_target_info),
+- .table = "mangle",
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
+- .family = AF_INET,
+- .revision = 0,
+-};
+-
+-static struct xt_target ip6t_secmark_reg = {
+- .name = "SECMARK",
+- .target = target,
+- .targetsize = sizeof(struct xt_secmark_target_info),
+- .table = "mangle",
+- .checkentry = checkentry,
+- .me = THIS_MODULE,
+- .family = AF_INET6,
+- .revision = 0,
++static struct xt_target xt_secmark_target[] = {
++ {
++ .name = "SECMARK",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_secmark_target_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "SECMARK",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .target = target,
++ .targetsize = sizeof(struct xt_secmark_target_info),
++ .table = "mangle",
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_secmark_init(void)
+ {
+- int err;
+-
+- err = xt_register_target(&ipt_secmark_reg);
+- if (err)
+- return err;
+-
+- err = xt_register_target(&ip6t_secmark_reg);
+- if (err)
+- xt_unregister_target(&ipt_secmark_reg);
+-
+- return err;
++ return xt_register_targets(xt_secmark_target,
++ ARRAY_SIZE(xt_secmark_target));
+ }
+
+ static void __exit xt_secmark_fini(void)
+ {
+- xt_unregister_target(&ip6t_secmark_reg);
+- xt_unregister_target(&ipt_secmark_reg);
++ xt_unregister_targets(xt_secmark_target, ARRAY_SIZE(xt_secmark_target));
+ }
+
+ module_init(xt_secmark_init);
+diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c
+index 197609c..7db492d 100644
+--- a/net/netfilter/xt_comment.c
++++ b/net/netfilter/xt_comment.c
+@@ -29,41 +29,32 @@ match(const struct sk_buff *skb,
+ return 1;
+ }
+
+-static struct xt_match comment_match = {
+- .name = "comment",
+- .match = match,
+- .matchsize = sizeof(struct xt_comment_info),
+- .family = AF_INET,
+- .me = THIS_MODULE
+-};
+-
+-static struct xt_match comment6_match = {
+- .name = "comment",
+- .match = match,
+- .matchsize = sizeof(struct xt_comment_info),
+- .family = AF_INET6,
+- .me = THIS_MODULE
++static struct xt_match xt_comment_match[] = {
++ {
++ .name = "comment",
++ .family = AF_INET,
++ .match = match,
++ .matchsize = sizeof(struct xt_comment_info),
++ .me = THIS_MODULE
++ },
++ {
++ .name = "comment",
++ .family = AF_INET6,
++ .match = match,
++ .matchsize = sizeof(struct xt_comment_info),
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_comment_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&comment_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&comment6_match);
+- if (ret)
+- xt_unregister_match(&comment_match);
+-
+- return ret;
++ return xt_register_matches(xt_comment_match,
++ ARRAY_SIZE(xt_comment_match));
+ }
+
+ static void __exit xt_comment_fini(void)
+ {
+- xt_unregister_match(&comment_match);
+- xt_unregister_match(&comment6_match);
++ xt_unregister_matches(xt_comment_match, ARRAY_SIZE(xt_comment_match));
+ }
+
+ module_init(xt_comment_init);
+diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
+index 1396fe2..dcc497e 100644
+--- a/net/netfilter/xt_connbytes.c
++++ b/net/netfilter/xt_connbytes.c
+@@ -125,7 +125,6 @@ static int check(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_connbytes_info *sinfo = matchinfo;
+@@ -143,40 +142,35 @@ static int check(const char *tablename,
+ return 1;
+ }
+
+-static struct xt_match connbytes_match = {
+- .name = "connbytes",
+- .match = match,
+- .checkentry = check,
+- .matchsize = sizeof(struct xt_connbytes_info),
+- .family = AF_INET,
+- .me = THIS_MODULE
+-};
+-static struct xt_match connbytes6_match = {
+- .name = "connbytes",
+- .match = match,
+- .checkentry = check,
+- .matchsize = sizeof(struct xt_connbytes_info),
+- .family = AF_INET6,
+- .me = THIS_MODULE
++static struct xt_match xt_connbytes_match[] = {
++ {
++ .name = "connbytes",
++ .family = AF_INET,
++ .checkentry = check,
++ .match = match,
++ .matchsize = sizeof(struct xt_connbytes_info),
++ .me = THIS_MODULE
++ },
++ {
++ .name = "connbytes",
++ .family = AF_INET6,
++ .checkentry = check,
++ .match = match,
++ .matchsize = sizeof(struct xt_connbytes_info),
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_connbytes_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&connbytes_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&connbytes6_match);
+- if (ret)
+- xt_unregister_match(&connbytes_match);
+- return ret;
++ return xt_register_matches(xt_connbytes_match,
++ ARRAY_SIZE(xt_connbytes_match));
+ }
+
+ static void __exit xt_connbytes_fini(void)
+ {
+- xt_unregister_match(&connbytes_match);
+- xt_unregister_match(&connbytes6_match);
++ xt_unregister_matches(xt_connbytes_match,
++ ARRAY_SIZE(xt_connbytes_match));
+ }
+
+ module_init(xt_connbytes_init);
+diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
+index 56324c8..a8f0305 100644
+--- a/net/netfilter/xt_connmark.c
++++ b/net/netfilter/xt_connmark.c
+@@ -55,7 +55,6 @@ checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ struct xt_connmark_info *cm = matchinfo;
+@@ -75,53 +74,80 @@ checkentry(const char *tablename,
+ }
+
+ static void
+-destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
++destroy(const struct xt_match *match, void *matchinfo)
+ {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ nf_ct_l3proto_module_put(match->family);
+ #endif
+ }
+
+-static struct xt_match connmark_match = {
+- .name = "connmark",
+- .match = match,
+- .matchsize = sizeof(struct xt_connmark_info),
+- .checkentry = checkentry,
+- .destroy = destroy,
+- .family = AF_INET,
+- .me = THIS_MODULE
++#ifdef CONFIG_COMPAT
++struct compat_xt_connmark_info {
++ compat_ulong_t mark, mask;
++ u_int8_t invert;
++ u_int8_t __pad1;
++ u_int16_t __pad2;
+ };
+
+-static struct xt_match connmark6_match = {
+- .name = "connmark",
+- .match = match,
+- .matchsize = sizeof(struct xt_connmark_info),
+- .checkentry = checkentry,
+- .destroy = destroy,
+- .family = AF_INET6,
+- .me = THIS_MODULE
++static void compat_from_user(void *dst, void *src)
++{
++ struct compat_xt_connmark_info *cm = src;
++ struct xt_connmark_info m = {
++ .mark = cm->mark,
++ .mask = cm->mask,
++ .invert = cm->invert,
++ };
++ memcpy(dst, &m, sizeof(m));
++}
++
++static int compat_to_user(void __user *dst, void *src)
++{
++ struct xt_connmark_info *m = src;
++ struct compat_xt_connmark_info cm = {
++ .mark = m->mark,
++ .mask = m->mask,
++ .invert = m->invert,
++ };
++ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
++}
++#endif /* CONFIG_COMPAT */
++
++static struct xt_match xt_connmark_match[] = {
++ {
++ .name = "connmark",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_connmark_info),
++#ifdef CONFIG_COMPAT
++ .compatsize = sizeof(struct compat_xt_connmark_info),
++ .compat_from_user = compat_from_user,
++ .compat_to_user = compat_to_user,
++#endif
++ .me = THIS_MODULE
++ },
++ {
++ .name = "connmark",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_connmark_info),
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_connmark_init(void)
+ {
+- int ret;
+-
+ need_conntrack();
+-
+- ret = xt_register_match(&connmark_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&connmark6_match);
+- if (ret)
+- xt_unregister_match(&connmark_match);
+- return ret;
++ return xt_register_matches(xt_connmark_match,
++ ARRAY_SIZE(xt_connmark_match));
+ }
+
+ static void __exit xt_connmark_fini(void)
+ {
+- xt_unregister_match(&connmark6_match);
+- xt_unregister_match(&connmark_match);
++ xt_unregister_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match));
+ }
+
+ module_init(xt_connmark_init);
+diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
+index 145489a..0ea501a 100644
+--- a/net/netfilter/xt_conntrack.c
++++ b/net/netfilter/xt_conntrack.c
+@@ -45,7 +45,7 @@ match(const struct sk_buff *skb,
+
+ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+
+-#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
++#define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+ if (ct == &ip_conntrack_untracked)
+ statebit = XT_CONNTRACK_STATE_UNTRACKED;
+@@ -54,63 +54,72 @@ match(const struct sk_buff *skb,
+ else
+ statebit = XT_CONNTRACK_STATE_INVALID;
+
+- if(sinfo->flags & XT_CONNTRACK_STATE) {
++ if (sinfo->flags & XT_CONNTRACK_STATE) {
+ if (ct) {
+- if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
+- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
++ if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
+ statebit |= XT_CONNTRACK_STATE_SNAT;
+-
+- if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
+- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
++ if (test_bit(IPS_DST_NAT_BIT, &ct->status))
+ statebit |= XT_CONNTRACK_STATE_DNAT;
+ }
+-
+- if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
+- return 0;
+- }
+-
+- if(sinfo->flags & XT_CONNTRACK_PROTO) {
+- if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
+- return 0;
+- }
+-
+- if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
++ if (FWINV((statebit & sinfo->statemask) == 0,
++ XT_CONNTRACK_STATE))
+ return 0;
+ }
+
+- if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
++ if (ct == NULL) {
++ if (sinfo->flags & ~XT_CONNTRACK_STATE)
+ return 0;
++ return 1;
+ }
+
+- if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
+- return 0;
+- }
++ if (sinfo->flags & XT_CONNTRACK_PROTO &&
++ FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
++ sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
++ XT_CONNTRACK_PROTO))
++ return 0;
++
++ if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
++ FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip &
++ sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
++ XT_CONNTRACK_ORIGSRC))
++ return 0;
+
+- if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
+- return 0;
+- }
++ if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
++ FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip &
++ sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
++ XT_CONNTRACK_ORIGDST))
++ return 0;
+
+- if(sinfo->flags & XT_CONNTRACK_STATUS) {
+- if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
+- return 0;
+- }
++ if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
++ FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip &
++ sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
++ XT_CONNTRACK_REPLSRC))
++ return 0;
+
+- if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
+- unsigned long expires;
++ if (sinfo->flags & XT_CONNTRACK_REPLDST &&
++ FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip &
++ sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
++ XT_CONNTRACK_REPLDST))
++ return 0;
+
+- if(!ct)
+- return 0;
++ if (sinfo->flags & XT_CONNTRACK_STATUS &&
++ FWINV((ct->status & sinfo->statusmask) == 0,
++ XT_CONNTRACK_STATUS))
++ return 0;
+
+- expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
++ if (sinfo->flags & XT_CONNTRACK_EXPIRES) {
++ unsigned long expires = timer_pending(&ct->timeout) ?
++ (ct->timeout.expires - jiffies)/HZ : 0;
+
+- if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
++ if (FWINV(!(expires >= sinfo->expires_min &&
++ expires <= sinfo->expires_max),
++ XT_CONNTRACK_EXPIRES))
+ return 0;
+ }
+-
+ return 1;
+ }
+
+@@ -141,63 +150,72 @@ match(const struct sk_buff *skb,
+ else
+ statebit = XT_CONNTRACK_STATE_INVALID;
+
+- if(sinfo->flags & XT_CONNTRACK_STATE) {
++ if (sinfo->flags & XT_CONNTRACK_STATE) {
+ if (ct) {
+- if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
+- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
++ if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
+ statebit |= XT_CONNTRACK_STATE_SNAT;
+-
+- if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
+- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
++ if (test_bit(IPS_DST_NAT_BIT, &ct->status))
+ statebit |= XT_CONNTRACK_STATE_DNAT;
+ }
+-
+- if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
+- return 0;
+- }
+-
+- if(sinfo->flags & XT_CONNTRACK_PROTO) {
+- if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
+- return 0;
+- }
+-
+- if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
++ if (FWINV((statebit & sinfo->statemask) == 0,
++ XT_CONNTRACK_STATE))
+ return 0;
+ }
+
+- if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
++ if (ct == NULL) {
++ if (sinfo->flags & ~XT_CONNTRACK_STATE)
+ return 0;
++ return 1;
+ }
+
+- if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
+- return 0;
+- }
++ if (sinfo->flags & XT_CONNTRACK_PROTO &&
++ FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
++ sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
++ XT_CONNTRACK_PROTO))
++ return 0;
++
++ if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
++ FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip &
++ sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
++ XT_CONNTRACK_ORIGSRC))
++ return 0;
+
+- if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+- if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
+- return 0;
+- }
++ if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
++ FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip &
++ sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
++ XT_CONNTRACK_ORIGDST))
++ return 0;
+
+- if(sinfo->flags & XT_CONNTRACK_STATUS) {
+- if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
+- return 0;
+- }
++ if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
++ FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip &
++ sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
++ XT_CONNTRACK_REPLSRC))
++ return 0;
+
+- if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
+- unsigned long expires;
++ if (sinfo->flags & XT_CONNTRACK_REPLDST &&
++ FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip &
++ sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
++ sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
++ XT_CONNTRACK_REPLDST))
++ return 0;
+
+- if(!ct)
+- return 0;
++ if (sinfo->flags & XT_CONNTRACK_STATUS &&
++ FWINV((ct->status & sinfo->statusmask) == 0,
++ XT_CONNTRACK_STATUS))
++ return 0;
+
+- expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
++ if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
++ unsigned long expires = timer_pending(&ct->timeout) ?
++ (ct->timeout.expires - jiffies)/HZ : 0;
+
+- if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
++ if (FWINV(!(expires >= sinfo->expires_min &&
++ expires <= sinfo->expires_max),
++ XT_CONNTRACK_EXPIRES))
+ return 0;
+ }
+-
+ return 1;
+ }
+
+@@ -208,7 +226,6 @@ checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+@@ -221,8 +238,7 @@ checkentry(const char *tablename,
+ return 1;
+ }
+
+-static void
+-destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
++static void destroy(const struct xt_match *match, void *matchinfo)
+ {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ nf_ct_l3proto_module_put(match->family);
+@@ -241,11 +257,8 @@ static struct xt_match conntrack_match =
+
+ static int __init xt_conntrack_init(void)
+ {
+- int ret;
+ need_conntrack();
+- ret = xt_register_match(&conntrack_match);
+-
+- return ret;
++ return xt_register_match(&conntrack_match);
+ }
+
+ static void __exit xt_conntrack_fini(void)
+diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
+index 2e2f825..3e6cf43 100644
+--- a/net/netfilter/xt_dccp.c
++++ b/net/netfilter/xt_dccp.c
+@@ -131,7 +131,6 @@ checkentry(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_dccp_info *info = matchinfo;
+@@ -141,27 +140,26 @@ checkentry(const char *tablename,
+ && !(info->invflags & ~info->flags);
+ }
+
+-static struct xt_match dccp_match =
+-{
+- .name = "dccp",
+- .match = match,
+- .matchsize = sizeof(struct xt_dccp_info),
+- .proto = IPPROTO_DCCP,
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
++static struct xt_match xt_dccp_match[] = {
++ {
++ .name = "dccp",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_dccp_info),
++ .proto = IPPROTO_DCCP,
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "dccp",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_dccp_info),
++ .proto = IPPROTO_DCCP,
++ .me = THIS_MODULE,
++ },
+ };
+-static struct xt_match dccp6_match =
+-{
+- .name = "dccp",
+- .match = match,
+- .matchsize = sizeof(struct xt_dccp_info),
+- .proto = IPPROTO_DCCP,
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
+-};
+-
+
+ static int __init xt_dccp_init(void)
+ {
+@@ -173,27 +171,19 @@ static int __init xt_dccp_init(void)
+ dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
+ if (!dccp_optbuf)
+ return -ENOMEM;
+- ret = xt_register_match(&dccp_match);
++ ret = xt_register_matches(xt_dccp_match, ARRAY_SIZE(xt_dccp_match));
+ if (ret)
+ goto out_kfree;
+- ret = xt_register_match(&dccp6_match);
+- if (ret)
+- goto out_unreg;
+-
+ return ret;
+
+-out_unreg:
+- xt_unregister_match(&dccp_match);
+ out_kfree:
+ kfree(dccp_optbuf);
+-
+ return ret;
+ }
+
+ static void __exit xt_dccp_fini(void)
+ {
+- xt_unregister_match(&dccp6_match);
+- xt_unregister_match(&dccp_match);
++ xt_unregister_matches(xt_dccp_match, ARRAY_SIZE(xt_dccp_match));
+ kfree(dccp_optbuf);
+ }
+
+diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c
+new file mode 100644
+index 0000000..26c7f4a
+--- /dev/null
++++ b/net/netfilter/xt_dscp.c
+@@ -0,0 +1,103 @@
++/* IP tables module for matching the value of the IPv4/IPv6 DSCP field
++ *
++ * xt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
++ *
++ * (C) 2002 by Harald Welte <laforge at netfilter.org>
++ *
++ * 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/skbuff.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/dsfield.h>
++
++#include <linux/netfilter/xt_dscp.h>
++#include <linux/netfilter/x_tables.h>
++
++MODULE_AUTHOR("Harald Welte <laforge at netfilter.org>");
++MODULE_DESCRIPTION("x_tables DSCP matching module");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_dscp");
++MODULE_ALIAS("ip6t_dscp");
++
++static int match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const struct xt_match *match,
++ const void *matchinfo,
++ int offset,
++ unsigned int protoff,
++ int *hotdrop)
++{
++ const struct xt_dscp_info *info = matchinfo;
++ u_int8_t dscp = ipv4_get_dsfield(skb->nh.iph) >> XT_DSCP_SHIFT;
++
++ return (dscp == info->dscp) ^ !!info->invert;
++}
++
++static int match6(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const struct xt_match *match,
++ const void *matchinfo,
++ int offset,
++ unsigned int protoff,
++ int *hotdrop)
++{
++ const struct xt_dscp_info *info = matchinfo;
++ u_int8_t dscp = ipv6_get_dsfield(skb->nh.ipv6h) >> XT_DSCP_SHIFT;
++
++ return (dscp == info->dscp) ^ !!info->invert;
++}
++
++static int checkentry(const char *tablename,
++ const void *info,
++ const struct xt_match *match,
++ void *matchinfo,
++ unsigned int hook_mask)
++{
++ const u_int8_t dscp = ((struct xt_dscp_info *)matchinfo)->dscp;
++
++ if (dscp > XT_DSCP_MAX) {
++ printk(KERN_ERR "xt_dscp: dscp %x out of range\n", dscp);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct xt_match xt_dscp_match[] = {
++ {
++ .name = "dscp",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_dscp_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "dscp",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match6,
++ .matchsize = sizeof(struct xt_dscp_info),
++ .me = THIS_MODULE,
++ },
++};
++
++static int __init xt_dscp_match_init(void)
++{
++ return xt_register_matches(xt_dscp_match, ARRAY_SIZE(xt_dscp_match));
++}
++
++static void __exit xt_dscp_match_fini(void)
++{
++ xt_unregister_matches(xt_dscp_match, ARRAY_SIZE(xt_dscp_match));
++}
++
++module_init(xt_dscp_match_init);
++module_exit(xt_dscp_match_fini);
+diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c
+index 9dad628..7c95f14 100644
+--- a/net/netfilter/xt_esp.c
++++ b/net/netfilter/xt_esp.c
+@@ -79,7 +79,6 @@ checkentry(const char *tablename,
+ const void *ip_void,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchinfosize,
+ unsigned int hook_mask)
+ {
+ const struct xt_esp *espinfo = matchinfo;
+@@ -92,44 +91,35 @@ checkentry(const char *tablename,
+ return 1;
+ }
+
+-static struct xt_match esp_match = {
+- .name = "esp",
+- .family = AF_INET,
+- .proto = IPPROTO_ESP,
+- .match = &match,
+- .matchsize = sizeof(struct xt_esp),
+- .checkentry = &checkentry,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match esp6_match = {
+- .name = "esp",
+- .family = AF_INET6,
+- .proto = IPPROTO_ESP,
+- .match = &match,
+- .matchsize = sizeof(struct xt_esp),
+- .checkentry = &checkentry,
+- .me = THIS_MODULE,
++static struct xt_match xt_esp_match[] = {
++ {
++ .name = "esp",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_esp),
++ .proto = IPPROTO_ESP,
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "esp",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_esp),
++ .proto = IPPROTO_ESP,
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_esp_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&esp_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&esp6_match);
+- if (ret)
+- xt_unregister_match(&esp_match);
+-
+- return ret;
++ return xt_register_matches(xt_esp_match, ARRAY_SIZE(xt_esp_match));
+ }
+
+ static void __exit xt_esp_cleanup(void)
+ {
+- xt_unregister_match(&esp_match);
+- xt_unregister_match(&esp6_match);
++ xt_unregister_matches(xt_esp_match, ARRAY_SIZE(xt_esp_match));
+ }
+
+ module_init(xt_esp_init);
+diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
+index 799c2a4..5d7818b 100644
+--- a/net/netfilter/xt_helper.c
++++ b/net/netfilter/xt_helper.c
+@@ -139,7 +139,6 @@ static int check(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ struct xt_helper_info *info = matchinfo;
+@@ -156,52 +155,44 @@ static int check(const char *tablename,
+ }
+
+ static void
+-destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
++destroy(const struct xt_match *match, void *matchinfo)
+ {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ nf_ct_l3proto_module_put(match->family);
+ #endif
+ }
+
+-static struct xt_match helper_match = {
+- .name = "helper",
+- .match = match,
+- .matchsize = sizeof(struct xt_helper_info),
+- .checkentry = check,
+- .destroy = destroy,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-static struct xt_match helper6_match = {
+- .name = "helper",
+- .match = match,
+- .matchsize = sizeof(struct xt_helper_info),
+- .checkentry = check,
+- .destroy = destroy,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_helper_match[] = {
++ {
++ .name = "helper",
++ .family = AF_INET,
++ .checkentry = check,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_helper_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "helper",
++ .family = AF_INET6,
++ .checkentry = check,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_helper_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_helper_init(void)
+ {
+- int ret;
+ need_conntrack();
+-
+- ret = xt_register_match(&helper_match);
+- if (ret < 0)
+- return ret;
+-
+- ret = xt_register_match(&helper6_match);
+- if (ret < 0)
+- xt_unregister_match(&helper_match);
+-
+- return ret;
++ return xt_register_matches(xt_helper_match,
++ ARRAY_SIZE(xt_helper_match));
+ }
+
+ static void __exit xt_helper_fini(void)
+ {
+- xt_unregister_match(&helper_match);
+- xt_unregister_match(&helper6_match);
++ xt_unregister_matches(xt_helper_match, ARRAY_SIZE(xt_helper_match));
+ }
+
+ module_init(xt_helper_init);
+diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
+index 109132c..67fd30d 100644
+--- a/net/netfilter/xt_length.c
++++ b/net/netfilter/xt_length.c
+@@ -52,39 +52,32 @@ match6(const struct sk_buff *skb,
+ return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+ }
+
+-static struct xt_match length_match = {
+- .name = "length",
+- .match = match,
+- .matchsize = sizeof(struct xt_length_info),
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match length6_match = {
+- .name = "length",
+- .match = match6,
+- .matchsize = sizeof(struct xt_length_info),
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_length_match[] = {
++ {
++ .name = "length",
++ .family = AF_INET,
++ .match = match,
++ .matchsize = sizeof(struct xt_length_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "length",
++ .family = AF_INET6,
++ .match = match6,
++ .matchsize = sizeof(struct xt_length_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_length_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&length_match);
+- if (ret)
+- return ret;
+- ret = xt_register_match(&length6_match);
+- if (ret)
+- xt_unregister_match(&length_match);
+-
+- return ret;
++ return xt_register_matches(xt_length_match,
++ ARRAY_SIZE(xt_length_match));
+ }
+
+ static void __exit xt_length_fini(void)
+ {
+- xt_unregister_match(&length_match);
+- xt_unregister_match(&length6_match);
++ xt_unregister_matches(xt_length_match, ARRAY_SIZE(xt_length_match));
+ }
+
+ module_init(xt_length_init);
+diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
+index ce7fdb7..fda7b7d 100644
+--- a/net/netfilter/xt_limit.c
++++ b/net/netfilter/xt_limit.c
+@@ -110,7 +110,6 @@ ipt_limit_checkentry(const char *tablena
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ struct xt_rateinfo *r = matchinfo;
+@@ -123,55 +122,95 @@ ipt_limit_checkentry(const char *tablena
+ return 0;
+ }
+
+- /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
+- 128. */
+- r->prev = jiffies;
+- r->credit = user2credits(r->avg * r->burst); /* Credits full. */
+- r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
+- r->cost = user2credits(r->avg);
+-
+ /* For SMP, we only want to use one set of counters. */
+ r->master = r;
+-
++ if (r->cost == 0) {
++ /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
++ 128. */
++ r->prev = jiffies;
++ r->credit = user2credits(r->avg * r->burst); /* Credits full. */
++ r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
++ r->cost = user2credits(r->avg);
++ }
+ return 1;
+ }
+
+-static struct xt_match ipt_limit_reg = {
+- .name = "limit",
+- .match = ipt_limit_match,
+- .matchsize = sizeof(struct xt_rateinfo),
+- .checkentry = ipt_limit_checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
++#ifdef CONFIG_COMPAT
++struct compat_xt_rateinfo {
++ u_int32_t avg;
++ u_int32_t burst;
++
++ compat_ulong_t prev;
++ u_int32_t credit;
++ u_int32_t credit_cap, cost;
++
++ u_int32_t master;
+ };
+-static struct xt_match limit6_reg = {
+- .name = "limit",
+- .match = ipt_limit_match,
+- .matchsize = sizeof(struct xt_rateinfo),
+- .checkentry = ipt_limit_checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++
++/* To keep the full "prev" timestamp, the upper 32 bits are stored in the
++ * master pointer, which does not need to be preserved. */
++static void compat_from_user(void *dst, void *src)
++{
++ struct compat_xt_rateinfo *cm = src;
++ struct xt_rateinfo m = {
++ .avg = cm->avg,
++ .burst = cm->burst,
++ .prev = cm->prev | (unsigned long)cm->master << 32,
++ .credit = cm->credit,
++ .credit_cap = cm->credit_cap,
++ .cost = cm->cost,
++ };
++ memcpy(dst, &m, sizeof(m));
++}
++
++static int compat_to_user(void __user *dst, void *src)
++{
++ struct xt_rateinfo *m = src;
++ struct compat_xt_rateinfo cm = {
++ .avg = m->avg,
++ .burst = m->burst,
++ .prev = m->prev,
++ .credit = m->credit,
++ .credit_cap = m->credit_cap,
++ .cost = m->cost,
++ .master = m->prev >> 32,
++ };
++ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
++}
++#endif /* CONFIG_COMPAT */
++
++static struct xt_match xt_limit_match[] = {
++ {
++ .name = "limit",
++ .family = AF_INET,
++ .checkentry = ipt_limit_checkentry,
++ .match = ipt_limit_match,
++ .matchsize = sizeof(struct xt_rateinfo),
++#ifdef CONFIG_COMPAT
++ .compatsize = sizeof(struct compat_xt_rateinfo),
++ .compat_from_user = compat_from_user,
++ .compat_to_user = compat_to_user,
++#endif
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "limit",
++ .family = AF_INET6,
++ .checkentry = ipt_limit_checkentry,
++ .match = ipt_limit_match,
++ .matchsize = sizeof(struct xt_rateinfo),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_limit_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&ipt_limit_reg);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&limit6_reg);
+- if (ret)
+- xt_unregister_match(&ipt_limit_reg);
+-
+- return ret;
++ return xt_register_matches(xt_limit_match, ARRAY_SIZE(xt_limit_match));
+ }
+
+ static void __exit xt_limit_fini(void)
+ {
+- xt_unregister_match(&ipt_limit_reg);
+- xt_unregister_match(&limit6_reg);
++ xt_unregister_matches(xt_limit_match, ARRAY_SIZE(xt_limit_match));
+ }
+
+ module_init(xt_limit_init);
+diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
+index 356290f..425fc21 100644
+--- a/net/netfilter/xt_mac.c
++++ b/net/netfilter/xt_mac.c
+@@ -43,43 +43,37 @@ match(const struct sk_buff *skb,
+ ^ info->invert));
+ }
+
+-static struct xt_match mac_match = {
+- .name = "mac",
+- .match = match,
+- .matchsize = sizeof(struct xt_mac_info),
+- .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) |
+- (1 << NF_IP_FORWARD),
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-static struct xt_match mac6_match = {
+- .name = "mac",
+- .match = match,
+- .matchsize = sizeof(struct xt_mac_info),
+- .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) |
+- (1 << NF_IP_FORWARD),
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_mac_match[] = {
++ {
++ .name = "mac",
++ .family = AF_INET,
++ .match = match,
++ .matchsize = sizeof(struct xt_mac_info),
++ .hooks = (1 << NF_IP_PRE_ROUTING) |
++ (1 << NF_IP_LOCAL_IN) |
++ (1 << NF_IP_FORWARD),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "mac",
++ .family = AF_INET6,
++ .match = match,
++ .matchsize = sizeof(struct xt_mac_info),
++ .hooks = (1 << NF_IP_PRE_ROUTING) |
++ (1 << NF_IP_LOCAL_IN) |
++ (1 << NF_IP_FORWARD),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_mac_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&mac_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&mac6_match);
+- if (ret)
+- xt_unregister_match(&mac_match);
+-
+- return ret;
++ return xt_register_matches(xt_mac_match, ARRAY_SIZE(xt_mac_match));
+ }
+
+ static void __exit xt_mac_fini(void)
+ {
+- xt_unregister_match(&mac_match);
+- xt_unregister_match(&mac6_match);
++ xt_unregister_matches(xt_mac_match, ARRAY_SIZE(xt_mac_match));
+ }
+
+ module_init(xt_mac_init);
+diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
+index 876bc57..934dddf 100644
+--- a/net/netfilter/xt_mark.c
++++ b/net/netfilter/xt_mark.c
+@@ -39,7 +39,6 @@ checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_mark_info *minfo = matchinfo;
+@@ -51,42 +50,69 @@ checkentry(const char *tablename,
+ return 1;
+ }
+
+-static struct xt_match mark_match = {
+- .name = "mark",
+- .match = match,
+- .matchsize = sizeof(struct xt_mark_info),
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
++#ifdef CONFIG_COMPAT
++struct compat_xt_mark_info {
++ compat_ulong_t mark, mask;
++ u_int8_t invert;
++ u_int8_t __pad1;
++ u_int16_t __pad2;
+ };
+
+-static struct xt_match mark6_match = {
+- .name = "mark",
+- .match = match,
+- .matchsize = sizeof(struct xt_mark_info),
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
+-};
++static void compat_from_user(void *dst, void *src)
++{
++ struct compat_xt_mark_info *cm = src;
++ struct xt_mark_info m = {
++ .mark = cm->mark,
++ .mask = cm->mask,
++ .invert = cm->invert,
++ };
++ memcpy(dst, &m, sizeof(m));
++}
+
+-static int __init xt_mark_init(void)
++static int compat_to_user(void __user *dst, void *src)
+ {
+- int ret;
+- ret = xt_register_match(&mark_match);
+- if (ret)
+- return ret;
++ struct xt_mark_info *m = src;
++ struct compat_xt_mark_info cm = {
++ .mark = m->mark,
++ .mask = m->mask,
++ .invert = m->invert,
++ };
++ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
++}
++#endif /* CONFIG_COMPAT */
+
+- ret = xt_register_match(&mark6_match);
+- if (ret)
+- xt_unregister_match(&mark_match);
++static struct xt_match xt_mark_match[] = {
++ {
++ .name = "mark",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_mark_info),
++#ifdef CONFIG_COMPAT
++ .compatsize = sizeof(struct compat_xt_mark_info),
++ .compat_from_user = compat_from_user,
++ .compat_to_user = compat_to_user,
++#endif
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "mark",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_mark_info),
++ .me = THIS_MODULE,
++ },
++};
+
+- return ret;
++static int __init xt_mark_init(void)
++{
++ return xt_register_matches(xt_mark_match, ARRAY_SIZE(xt_mark_match));
+ }
+
+ static void __exit xt_mark_fini(void)
+ {
+- xt_unregister_match(&mark_match);
+- xt_unregister_match(&mark6_match);
++ xt_unregister_matches(xt_mark_match, ARRAY_SIZE(xt_mark_match));
+ }
+
+ module_init(xt_mark_init);
+diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
+index 1ff0a25..d3aefd3 100644
+--- a/net/netfilter/xt_multiport.c
++++ b/net/netfilter/xt_multiport.c
+@@ -176,7 +176,6 @@ checkentry(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_ip *ip = info;
+@@ -191,7 +190,6 @@ checkentry_v1(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ipt_ip *ip = info;
+@@ -206,7 +204,6 @@ checkentry6(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_ip6 *ip = info;
+@@ -221,7 +218,6 @@ checkentry6_v1(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct ip6t_ip6 *ip = info;
+@@ -231,84 +227,55 @@ checkentry6_v1(const char *tablename,
+ multiinfo->count);
+ }
+
+-static struct xt_match multiport_match = {
+- .name = "multiport",
+- .revision = 0,
+- .matchsize = sizeof(struct xt_multiport),
+- .match = &match,
+- .checkentry = &checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match multiport_match_v1 = {
+- .name = "multiport",
+- .revision = 1,
+- .matchsize = sizeof(struct xt_multiport_v1),
+- .match = &match_v1,
+- .checkentry = &checkentry_v1,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match multiport6_match = {
+- .name = "multiport",
+- .revision = 0,
+- .matchsize = sizeof(struct xt_multiport),
+- .match = &match,
+- .checkentry = &checkentry6,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match multiport6_match_v1 = {
+- .name = "multiport",
+- .revision = 1,
+- .matchsize = sizeof(struct xt_multiport_v1),
+- .match = &match_v1,
+- .checkentry = &checkentry6_v1,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_multiport_match[] = {
++ {
++ .name = "multiport",
++ .family = AF_INET,
++ .revision = 0,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_multiport),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "multiport",
++ .family = AF_INET,
++ .revision = 1,
++ .checkentry = checkentry_v1,
++ .match = match_v1,
++ .matchsize = sizeof(struct xt_multiport_v1),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "multiport",
++ .family = AF_INET6,
++ .revision = 0,
++ .checkentry = checkentry6,
++ .match = match,
++ .matchsize = sizeof(struct xt_multiport),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "multiport",
++ .family = AF_INET6,
++ .revision = 1,
++ .checkentry = checkentry6_v1,
++ .match = match_v1,
++ .matchsize = sizeof(struct xt_multiport_v1),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_multiport_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&multiport_match);
+- if (ret)
+- goto out;
+-
+- ret = xt_register_match(&multiport_match_v1);
+- if (ret)
+- goto out_unreg_multi_v0;
+-
+- ret = xt_register_match(&multiport6_match);
+- if (ret)
+- goto out_unreg_multi_v1;
+-
+- ret = xt_register_match(&multiport6_match_v1);
+- if (ret)
+- goto out_unreg_multi6_v0;
+-
+- return ret;
+-
+-out_unreg_multi6_v0:
+- xt_unregister_match(&multiport6_match);
+-out_unreg_multi_v1:
+- xt_unregister_match(&multiport_match_v1);
+-out_unreg_multi_v0:
+- xt_unregister_match(&multiport_match);
+-out:
+- return ret;
++ return xt_register_matches(xt_multiport_match,
++ ARRAY_SIZE(xt_multiport_match));
+ }
+
+ static void __exit xt_multiport_fini(void)
+ {
+- xt_unregister_match(&multiport_match);
+- xt_unregister_match(&multiport_match_v1);
+- xt_unregister_match(&multiport6_match);
+- xt_unregister_match(&multiport6_match_v1);
++ xt_unregister_matches(xt_multiport_match,
++ ARRAY_SIZE(xt_multiport_match));
+ }
+
+ module_init(xt_multiport_init);
+diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
+index 63a9654..fd8f954 100644
+--- a/net/netfilter/xt_physdev.c
++++ b/net/netfilter/xt_physdev.c
+@@ -106,7 +106,6 @@ checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_physdev_info *info = matchinfo;
+@@ -132,43 +131,34 @@ checkentry(const char *tablename,
+ return 1;
+ }
+
+-static struct xt_match physdev_match = {
+- .name = "physdev",
+- .match = match,
+- .matchsize = sizeof(struct xt_physdev_info),
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match physdev6_match = {
+- .name = "physdev",
+- .match = match,
+- .matchsize = sizeof(struct xt_physdev_info),
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_physdev_match[] = {
++ {
++ .name = "physdev",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_physdev_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "physdev",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_physdev_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_physdev_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&physdev_match);
+- if (ret < 0)
+- return ret;
+-
+- ret = xt_register_match(&physdev6_match);
+- if (ret < 0)
+- xt_unregister_match(&physdev_match);
+-
+- return ret;
++ return xt_register_matches(xt_physdev_match,
++ ARRAY_SIZE(xt_physdev_match));
+ }
+
+ static void __exit xt_physdev_fini(void)
+ {
+- xt_unregister_match(&physdev_match);
+- xt_unregister_match(&physdev6_match);
++ xt_unregister_matches(xt_physdev_match, ARRAY_SIZE(xt_physdev_match));
+ }
+
+ module_init(xt_physdev_init);
+diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
+index d2f5320..16e7b08 100644
+--- a/net/netfilter/xt_pkttype.c
++++ b/net/netfilter/xt_pkttype.c
+@@ -43,40 +43,32 @@ static int match(const struct sk_buff *s
+ return (type == info->pkttype) ^ info->invert;
+ }
+
+-static struct xt_match pkttype_match = {
+- .name = "pkttype",
+- .match = match,
+- .matchsize = sizeof(struct xt_pkttype_info),
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match pkttype6_match = {
+- .name = "pkttype",
+- .match = match,
+- .matchsize = sizeof(struct xt_pkttype_info),
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_pkttype_match[] = {
++ {
++ .name = "pkttype",
++ .family = AF_INET,
++ .match = match,
++ .matchsize = sizeof(struct xt_pkttype_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "pkttype",
++ .family = AF_INET6,
++ .match = match,
++ .matchsize = sizeof(struct xt_pkttype_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_pkttype_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&pkttype_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&pkttype6_match);
+- if (ret)
+- xt_unregister_match(&pkttype_match);
+-
+- return ret;
++ return xt_register_matches(xt_pkttype_match,
++ ARRAY_SIZE(xt_pkttype_match));
+ }
+
+ static void __exit xt_pkttype_fini(void)
+ {
+- xt_unregister_match(&pkttype_match);
+- xt_unregister_match(&pkttype6_match);
++ xt_unregister_matches(xt_pkttype_match, ARRAY_SIZE(xt_pkttype_match));
+ }
+
+ module_init(xt_pkttype_init);
+diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
+index ba1ca03..46bde2b 100644
+--- a/net/netfilter/xt_policy.c
++++ b/net/netfilter/xt_policy.c
+@@ -135,8 +135,7 @@ static int match(const struct sk_buff *s
+
+ static int checkentry(const char *tablename, const void *ip_void,
+ const struct xt_match *match,
+- void *matchinfo, unsigned int matchsize,
+- unsigned int hook_mask)
++ void *matchinfo, unsigned int hook_mask)
+ {
+ struct xt_policy_info *info = matchinfo;
+
+@@ -165,43 +164,34 @@ static int checkentry(const char *tablen
+ return 1;
+ }
+
+-static struct xt_match policy_match = {
+- .name = "policy",
+- .family = AF_INET,
+- .match = match,
+- .matchsize = sizeof(struct xt_policy_info),
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match policy6_match = {
+- .name = "policy",
+- .family = AF_INET6,
+- .match = match,
+- .matchsize = sizeof(struct xt_policy_info),
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_policy_match[] = {
++ {
++ .name = "policy",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_policy_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "policy",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_policy_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&policy_match);
+- if (ret)
+- return ret;
+- ret = xt_register_match(&policy6_match);
+- if (ret)
+- xt_unregister_match(&policy_match);
+- return ret;
++ return xt_register_matches(xt_policy_match,
++ ARRAY_SIZE(xt_policy_match));
+ }
+
+ static void __exit fini(void)
+ {
+- xt_unregister_match(&policy6_match);
+- xt_unregister_match(&policy_match);
++ xt_unregister_matches(xt_policy_match, ARRAY_SIZE(xt_policy_match));
+ }
+
+ module_init(init);
+diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
+index be8d3c2..b75fa2c 100644
+--- a/net/netfilter/xt_quota.c
++++ b/net/netfilter/xt_quota.c
+@@ -41,7 +41,7 @@ match(const struct sk_buff *skb,
+ static int
+ checkentry(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo,
+- unsigned int matchsize, unsigned int hook_mask)
++ unsigned int hook_mask)
+ {
+ struct xt_quota_info *q = (struct xt_quota_info *)matchinfo;
+
+@@ -52,46 +52,33 @@ checkentry(const char *tablename, const
+ return 1;
+ }
+
+-static struct xt_match quota_match = {
+- .name = "quota",
+- .family = AF_INET,
+- .match = match,
+- .matchsize = sizeof(struct xt_quota_info),
+- .checkentry = checkentry,
+- .me = THIS_MODULE
+-};
+-
+-static struct xt_match quota_match6 = {
+- .name = "quota",
+- .family = AF_INET6,
+- .match = match,
+- .matchsize = sizeof(struct xt_quota_info),
+- .checkentry = checkentry,
+- .me = THIS_MODULE
++static struct xt_match xt_quota_match[] = {
++ {
++ .name = "quota",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_quota_info),
++ .me = THIS_MODULE
++ },
++ {
++ .name = "quota",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_quota_info),
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_quota_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match("a_match);
+- if (ret)
+- goto err1;
+- ret = xt_register_match("a_match6);
+- if (ret)
+- goto err2;
+- return ret;
+-
+-err2:
+- xt_unregister_match("a_match);
+-err1:
+- return ret;
++ return xt_register_matches(xt_quota_match, ARRAY_SIZE(xt_quota_match));
+ }
+
+ static void __exit xt_quota_fini(void)
+ {
+- xt_unregister_match("a_match6);
+- xt_unregister_match("a_match);
++ xt_unregister_matches(xt_quota_match, ARRAY_SIZE(xt_quota_match));
+ }
+
+ module_init(xt_quota_init);
+diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
+index 843383e..7956aca 100644
+--- a/net/netfilter/xt_sctp.c
++++ b/net/netfilter/xt_sctp.c
+@@ -163,7 +163,6 @@ checkentry(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_sctp_info *info = matchinfo;
+@@ -178,44 +177,35 @@ checkentry(const char *tablename,
+ | SCTP_CHUNK_MATCH_ONLY)));
+ }
+
+-static struct xt_match sctp_match = {
+- .name = "sctp",
+- .match = match,
+- .matchsize = sizeof(struct xt_sctp_info),
+- .proto = IPPROTO_SCTP,
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE
+-};
+-
+-static struct xt_match sctp6_match = {
+- .name = "sctp",
+- .match = match,
+- .matchsize = sizeof(struct xt_sctp_info),
+- .proto = IPPROTO_SCTP,
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE
++static struct xt_match xt_sctp_match[] = {
++ {
++ .name = "sctp",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_sctp_info),
++ .proto = IPPROTO_SCTP,
++ .me = THIS_MODULE
++ },
++ {
++ .name = "sctp",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_sctp_info),
++ .proto = IPPROTO_SCTP,
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_sctp_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&sctp_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&sctp6_match);
+- if (ret)
+- xt_unregister_match(&sctp_match);
+-
+- return ret;
++ return xt_register_matches(xt_sctp_match, ARRAY_SIZE(xt_sctp_match));
+ }
+
+ static void __exit xt_sctp_fini(void)
+ {
+- xt_unregister_match(&sctp6_match);
+- xt_unregister_match(&sctp_match);
++ xt_unregister_matches(xt_sctp_match, ARRAY_SIZE(xt_sctp_match));
+ }
+
+ module_init(xt_sctp_init);
+diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
+index f9e304d..d9010b1 100644
+--- a/net/netfilter/xt_state.c
++++ b/net/netfilter/xt_state.c
+@@ -48,7 +48,6 @@ static int check(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+@@ -62,54 +61,43 @@ static int check(const char *tablename,
+ }
+
+ static void
+-destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
++destroy(const struct xt_match *match, void *matchinfo)
+ {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ nf_ct_l3proto_module_put(match->family);
+ #endif
+ }
+
+-static struct xt_match state_match = {
+- .name = "state",
+- .match = match,
+- .checkentry = check,
+- .destroy = destroy,
+- .matchsize = sizeof(struct xt_state_info),
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match state6_match = {
+- .name = "state",
+- .match = match,
+- .checkentry = check,
+- .destroy = destroy,
+- .matchsize = sizeof(struct xt_state_info),
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_state_match[] = {
++ {
++ .name = "state",
++ .family = AF_INET,
++ .checkentry = check,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_state_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "state",
++ .family = AF_INET6,
++ .checkentry = check,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_state_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_state_init(void)
+ {
+- int ret;
+-
+ need_conntrack();
+-
+- ret = xt_register_match(&state_match);
+- if (ret < 0)
+- return ret;
+-
+- ret = xt_register_match(&state6_match);
+- if (ret < 0)
+- xt_unregister_match(&state_match);
+-
+- return ret;
++ return xt_register_matches(xt_state_match, ARRAY_SIZE(xt_state_match));
+ }
+
+ static void __exit xt_state_fini(void)
+ {
+- xt_unregister_match(&state_match);
+- xt_unregister_match(&state6_match);
++ xt_unregister_matches(xt_state_match, ARRAY_SIZE(xt_state_match));
+ }
+
+ module_init(xt_state_init);
+diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
+index de1037f..091a9f8 100644
+--- a/net/netfilter/xt_statistic.c
++++ b/net/netfilter/xt_statistic.c
+@@ -55,7 +55,7 @@ match(const struct sk_buff *skb,
+ static int
+ checkentry(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo,
+- unsigned int matchsize, unsigned int hook_mask)
++ unsigned int hook_mask)
+ {
+ struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+
+@@ -66,46 +66,35 @@ checkentry(const char *tablename, const
+ return 1;
+ }
+
+-static struct xt_match statistic_match = {
+- .name = "statistic",
+- .match = match,
+- .matchsize = sizeof(struct xt_statistic_info),
+- .checkentry = checkentry,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match statistic_match6 = {
+- .name = "statistic",
+- .match = match,
+- .matchsize = sizeof(struct xt_statistic_info),
+- .checkentry = checkentry,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_statistic_match[] = {
++ {
++ .name = "statistic",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_statistic_info),
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "statistic",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .matchsize = sizeof(struct xt_statistic_info),
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_statistic_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&statistic_match);
+- if (ret)
+- goto err1;
+-
+- ret = xt_register_match(&statistic_match6);
+- if (ret)
+- goto err2;
+- return ret;
+-err2:
+- xt_unregister_match(&statistic_match);
+-err1:
+- return ret;
++ return xt_register_matches(xt_statistic_match,
++ ARRAY_SIZE(xt_statistic_match));
+ }
+
+ static void __exit xt_statistic_fini(void)
+ {
+- xt_unregister_match(&statistic_match6);
+- xt_unregister_match(&statistic_match);
++ xt_unregister_matches(xt_statistic_match,
++ ARRAY_SIZE(xt_statistic_match));
+ }
+
+ module_init(xt_statistic_init);
+diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
+index 275330f..4453252 100644
+--- a/net/netfilter/xt_string.c
++++ b/net/netfilter/xt_string.c
+@@ -46,7 +46,6 @@ static int checkentry(const char *tablen
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ struct xt_string_info *conf = matchinfo;
+@@ -69,49 +68,40 @@ static int checkentry(const char *tablen
+ return 1;
+ }
+
+-static void destroy(const struct xt_match *match, void *matchinfo,
+- unsigned int matchsize)
++static void destroy(const struct xt_match *match, void *matchinfo)
+ {
+ textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
+ }
+
+-static struct xt_match string_match = {
+- .name = "string",
+- .match = match,
+- .matchsize = sizeof(struct xt_string_info),
+- .checkentry = checkentry,
+- .destroy = destroy,
+- .family = AF_INET,
+- .me = THIS_MODULE
+-};
+-static struct xt_match string6_match = {
+- .name = "string",
+- .match = match,
+- .matchsize = sizeof(struct xt_string_info),
+- .checkentry = checkentry,
+- .destroy = destroy,
+- .family = AF_INET6,
+- .me = THIS_MODULE
++static struct xt_match xt_string_match[] = {
++ {
++ .name = "string",
++ .family = AF_INET,
++ .checkentry = checkentry,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_string_info),
++ .me = THIS_MODULE
++ },
++ {
++ .name = "string",
++ .family = AF_INET6,
++ .checkentry = checkentry,
++ .match = match,
++ .destroy = destroy,
++ .matchsize = sizeof(struct xt_string_info),
++ .me = THIS_MODULE
++ },
+ };
+
+ static int __init xt_string_init(void)
+ {
+- int ret;
+-
+- ret = xt_register_match(&string_match);
+- if (ret)
+- return ret;
+- ret = xt_register_match(&string6_match);
+- if (ret)
+- xt_unregister_match(&string_match);
+-
+- return ret;
++ return xt_register_matches(xt_string_match, ARRAY_SIZE(xt_string_match));
+ }
+
+ static void __exit xt_string_fini(void)
+ {
+- xt_unregister_match(&string_match);
+- xt_unregister_match(&string6_match);
++ xt_unregister_matches(xt_string_match, ARRAY_SIZE(xt_string_match));
+ }
+
+ module_init(xt_string_init);
+diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
+index cf7d335..a3682fe 100644
+--- a/net/netfilter/xt_tcpmss.c
++++ b/net/netfilter/xt_tcpmss.c
+@@ -18,21 +18,22 @@
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv6/ip6_tables.h>
+
+-#define TH_SYN 0x02
+-
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Marc Boucher <marc at mbsi.ca>");
+ MODULE_DESCRIPTION("iptables TCP MSS match module");
+ MODULE_ALIAS("ipt_tcpmss");
+
+-/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
+-static inline int
+-mssoption_match(u_int16_t min, u_int16_t max,
+- const struct sk_buff *skb,
+- unsigned int protoff,
+- int invert,
+- int *hotdrop)
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const struct xt_match *match,
++ const void *matchinfo,
++ int offset,
++ unsigned int protoff,
++ int *hotdrop)
+ {
++ const struct xt_tcpmss_match_info *info = matchinfo;
+ struct tcphdr _tcph, *th;
+ /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+ u8 _opt[15 * 4 - sizeof(_tcph)], *op;
+@@ -64,72 +65,50 @@ mssoption_match(u_int16_t min, u_int16_t
+
+ mssval = (op[i+2] << 8) | op[i+3];
+
+- return (mssval >= min && mssval <= max) ^ invert;
++ return (mssval >= info->mss_min &&
++ mssval <= info->mss_max) ^ info->invert;
+ }
+- if (op[i] < 2) i++;
+- else i += op[i+1]?:1;
++ if (op[i] < 2)
++ i++;
++ else
++ i += op[i+1] ? : 1;
+ }
+ out:
+- return invert;
++ return info->invert;
+
+- dropit:
++dropit:
+ *hotdrop = 1;
+ return 0;
+ }
+
+-static int
+-match(const struct sk_buff *skb,
+- const struct net_device *in,
+- const struct net_device *out,
+- const struct xt_match *match,
+- const void *matchinfo,
+- int offset,
+- unsigned int protoff,
+- int *hotdrop)
+-{
+- const struct xt_tcpmss_match_info *info = matchinfo;
+-
+- return mssoption_match(info->mss_min, info->mss_max, skb, protoff,
+- info->invert, hotdrop);
+-}
+-
+-static struct xt_match tcpmss_match = {
+- .name = "tcpmss",
+- .match = match,
+- .matchsize = sizeof(struct xt_tcpmss_match_info),
+- .proto = IPPROTO_TCP,
+- .family = AF_INET,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match tcpmss6_match = {
+- .name = "tcpmss",
+- .match = match,
+- .matchsize = sizeof(struct xt_tcpmss_match_info),
+- .proto = IPPROTO_TCP,
+- .family = AF_INET6,
+- .me = THIS_MODULE,
++static struct xt_match xt_tcpmss_match[] = {
++ {
++ .name = "tcpmss",
++ .family = AF_INET,
++ .match = match,
++ .matchsize = sizeof(struct xt_tcpmss_match_info),
++ .proto = IPPROTO_TCP,
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "tcpmss",
++ .family = AF_INET6,
++ .match = match,
++ .matchsize = sizeof(struct xt_tcpmss_match_info),
++ .proto = IPPROTO_TCP,
++ .me = THIS_MODULE,
++ },
+ };
+
+-
+ static int __init xt_tcpmss_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&tcpmss_match);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&tcpmss6_match);
+- if (ret)
+- xt_unregister_match(&tcpmss_match);
+-
+- return ret;
++ return xt_register_matches(xt_tcpmss_match,
++ ARRAY_SIZE(xt_tcpmss_match));
+ }
+
+ static void __exit xt_tcpmss_fini(void)
+ {
+- xt_unregister_match(&tcpmss6_match);
+- xt_unregister_match(&tcpmss_match);
++ xt_unregister_matches(xt_tcpmss_match, ARRAY_SIZE(xt_tcpmss_match));
+ }
+
+ module_init(xt_tcpmss_init);
+diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
+index a9a63aa..e76a68e 100644
+--- a/net/netfilter/xt_tcpudp.c
++++ b/net/netfilter/xt_tcpudp.c
+@@ -141,7 +141,6 @@ tcp_checkentry(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_tcp *tcpinfo = matchinfo;
+@@ -190,7 +189,6 @@ udp_checkentry(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+- unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+ const struct xt_tcp *udpinfo = matchinfo;
+@@ -199,81 +197,54 @@ udp_checkentry(const char *tablename,
+ return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
+ }
+
+-static struct xt_match tcp_matchstruct = {
+- .name = "tcp",
+- .match = tcp_match,
+- .matchsize = sizeof(struct xt_tcp),
+- .proto = IPPROTO_TCP,
+- .family = AF_INET,
+- .checkentry = tcp_checkentry,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match tcp6_matchstruct = {
+- .name = "tcp",
+- .match = tcp_match,
+- .matchsize = sizeof(struct xt_tcp),
+- .proto = IPPROTO_TCP,
+- .family = AF_INET6,
+- .checkentry = tcp_checkentry,
+- .me = THIS_MODULE,
+-};
+-
+-static struct xt_match udp_matchstruct = {
+- .name = "udp",
+- .match = udp_match,
+- .matchsize = sizeof(struct xt_udp),
+- .proto = IPPROTO_UDP,
+- .family = AF_INET,
+- .checkentry = udp_checkentry,
+- .me = THIS_MODULE,
+-};
+-static struct xt_match udp6_matchstruct = {
+- .name = "udp",
+- .match = udp_match,
+- .matchsize = sizeof(struct xt_udp),
+- .proto = IPPROTO_UDP,
+- .family = AF_INET6,
+- .checkentry = udp_checkentry,
+- .me = THIS_MODULE,
++static struct xt_match xt_tcpudp_match[] = {
++ {
++ .name = "tcp",
++ .family = AF_INET,
++ .checkentry = tcp_checkentry,
++ .match = tcp_match,
++ .matchsize = sizeof(struct xt_tcp),
++ .proto = IPPROTO_TCP,
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "tcp",
++ .family = AF_INET6,
++ .checkentry = tcp_checkentry,
++ .match = tcp_match,
++ .matchsize = sizeof(struct xt_tcp),
++ .proto = IPPROTO_TCP,
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "udp",
++ .family = AF_INET,
++ .checkentry = udp_checkentry,
++ .match = udp_match,
++ .matchsize = sizeof(struct xt_udp),
++ .proto = IPPROTO_UDP,
++ .me = THIS_MODULE,
++ },
++ {
++ .name = "udp",
++ .family = AF_INET6,
++ .checkentry = udp_checkentry,
++ .match = udp_match,
++ .matchsize = sizeof(struct xt_udp),
++ .proto = IPPROTO_UDP,
++ .me = THIS_MODULE,
++ },
+ };
+
+ static int __init xt_tcpudp_init(void)
+ {
+- int ret;
+- ret = xt_register_match(&tcp_matchstruct);
+- if (ret)
+- return ret;
+-
+- ret = xt_register_match(&tcp6_matchstruct);
+- if (ret)
+- goto out_unreg_tcp;
+-
+- ret = xt_register_match(&udp_matchstruct);
+- if (ret)
+- goto out_unreg_tcp6;
+-
+- ret = xt_register_match(&udp6_matchstruct);
+- if (ret)
+- goto out_unreg_udp;
+-
+- return ret;
+-
+-out_unreg_udp:
+- xt_unregister_match(&udp_matchstruct);
+-out_unreg_tcp6:
+- xt_unregister_match(&tcp6_matchstruct);
+-out_unreg_tcp:
+- xt_unregister_match(&tcp_matchstruct);
+- return ret;
++ return xt_register_matches(xt_tcpudp_match,
++ ARRAY_SIZE(xt_tcpudp_match));
+ }
+
+ static void __exit xt_tcpudp_fini(void)
+ {
+- xt_unregister_match(&udp6_matchstruct);
+- xt_unregister_match(&udp_matchstruct);
+- xt_unregister_match(&tcp6_matchstruct);
+- xt_unregister_match(&tcp_matchstruct);
++ xt_unregister_matches(xt_tcpudp_match, ARRAY_SIZE(xt_tcpudp_match));
+ }
+
+ module_init(xt_tcpudp_init);
+diff --git a/net/netlabel/Kconfig b/net/netlabel/Kconfig
+new file mode 100644
+index 0000000..56958c8
+--- /dev/null
++++ b/net/netlabel/Kconfig
+@@ -0,0 +1,17 @@
++#
++# NetLabel configuration
++#
++
++config NETLABEL
++ bool "NetLabel subsystem support"
++ depends on SECURITY
++ default n
++ ---help---
++ NetLabel provides support for explicit network packet labeling
++ protocols such as CIPSO and RIPSO. For more information see
++ Documentation/netlabel as well as the NetLabel SourceForge project
++ for configuration tools and additional documentation.
++
++ * http://netlabel.sf.net
++
++ If you are unsure, say N.
+diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
+new file mode 100644
+index 0000000..8af18c0
+--- /dev/null
++++ b/net/netlabel/Makefile
+@@ -0,0 +1,16 @@
++#
++# Makefile for the NetLabel subsystem.
++#
++# Feb 9, 2006, Paul Moore <paul.moore at hp.com>
++#
++
++# base objects
++obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
++
++# management objects
++obj-y += netlabel_mgmt.o
++
++# protocol modules
++obj-y += netlabel_unlabeled.o
++obj-y += netlabel_cipso_v4.o
++
+diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
+new file mode 100644
+index 0000000..a6ce1d6
+--- /dev/null
++++ b/net/netlabel/netlabel_cipso_v4.c
+@@ -0,0 +1,773 @@
++/*
++ * NetLabel CIPSO/IPv4 Support
++ *
++ * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
++ * NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/socket.h>
++#include <linux/string.h>
++#include <linux/skbuff.h>
++#include <linux/audit.h>
++#include <net/sock.h>
++#include <net/netlink.h>
++#include <net/genetlink.h>
++#include <net/netlabel.h>
++#include <net/cipso_ipv4.h>
++
++#include "netlabel_user.h"
++#include "netlabel_cipso_v4.h"
++
++/* Argument struct for cipso_v4_doi_walk() */
++struct netlbl_cipsov4_doiwalk_arg {
++ struct netlink_callback *nl_cb;
++ struct sk_buff *skb;
++ u32 seq;
++};
++
++/* NetLabel Generic NETLINK CIPSOv4 family */
++static struct genl_family netlbl_cipsov4_gnl_family = {
++ .id = GENL_ID_GENERATE,
++ .hdrsize = 0,
++ .name = NETLBL_NLTYPE_CIPSOV4_NAME,
++ .version = NETLBL_PROTO_VERSION,
++ .maxattr = NLBL_CIPSOV4_A_MAX,
++};
++
++/* NetLabel Netlink attribute policy */
++static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
++ [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
++ [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
++ [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
++ [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
++ [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
++ [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
++ [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
++ [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
++ [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
++ [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
++ [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
++ [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
++};
++
++/*
++ * Helper Functions
++ */
++
++/**
++ * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
++ * @entry: the entry's RCU field
++ *
++ * Description:
++ * This function is designed to be used as a callback to the call_rcu()
++ * function so that the memory allocated to the DOI definition can be released
++ * safely.
++ *
++ */
++static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
++{
++ struct cipso_v4_doi *ptr;
++
++ ptr = container_of(entry, struct cipso_v4_doi, rcu);
++ switch (ptr->type) {
++ case CIPSO_V4_MAP_STD:
++ kfree(ptr->map.std->lvl.cipso);
++ kfree(ptr->map.std->lvl.local);
++ kfree(ptr->map.std->cat.cipso);
++ kfree(ptr->map.std->cat.local);
++ break;
++ }
++ kfree(ptr);
++}
++
++/**
++ * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
++ * @info: the Generic NETLINK info block
++ * @doi_def: the CIPSO V4 DOI definition
++ *
++ * Description:
++ * Parse the common sections of a ADD message and fill in the related values
++ * in @doi_def. Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_cipsov4_add_common(struct genl_info *info,
++ struct cipso_v4_doi *doi_def)
++{
++ struct nlattr *nla;
++ int nla_rem;
++ u32 iter = 0;
++
++ doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
++
++ if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
++ NLBL_CIPSOV4_A_MAX,
++ netlbl_cipsov4_genl_policy) != 0)
++ return -EINVAL;
++
++ nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
++ if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
++ if (iter > CIPSO_V4_TAG_MAXCNT)
++ return -EINVAL;
++ doi_def->tags[iter++] = nla_get_u8(nla);
++ }
++ if (iter < CIPSO_V4_TAG_MAXCNT)
++ doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
++
++ return 0;
++}
++
++/*
++ * NetLabel Command Handlers
++ */
++
++/**
++ * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
++ * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
++ * error.
++ *
++ */
++static int netlbl_cipsov4_add_std(struct genl_info *info)
++{
++ int ret_val = -EINVAL;
++ struct cipso_v4_doi *doi_def = NULL;
++ struct nlattr *nla_a;
++ struct nlattr *nla_b;
++ int nla_a_rem;
++ int nla_b_rem;
++
++ if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
++ !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
++ return -EINVAL;
++
++ if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
++ NLBL_CIPSOV4_A_MAX,
++ netlbl_cipsov4_genl_policy) != 0)
++ return -EINVAL;
++
++ doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
++ if (doi_def == NULL)
++ return -ENOMEM;
++ doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
++ if (doi_def->map.std == NULL) {
++ ret_val = -ENOMEM;
++ goto add_std_failure;
++ }
++ doi_def->type = CIPSO_V4_MAP_STD;
++
++ ret_val = netlbl_cipsov4_add_common(info, doi_def);
++ if (ret_val != 0)
++ goto add_std_failure;
++
++ nla_for_each_nested(nla_a,
++ info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
++ nla_a_rem)
++ if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
++ nla_for_each_nested(nla_b, nla_a, nla_b_rem)
++ switch (nla_b->nla_type) {
++ case NLBL_CIPSOV4_A_MLSLVLLOC:
++ if (nla_get_u32(nla_b) >=
++ doi_def->map.std->lvl.local_size)
++ doi_def->map.std->lvl.local_size =
++ nla_get_u32(nla_b) + 1;
++ break;
++ case NLBL_CIPSOV4_A_MLSLVLREM:
++ if (nla_get_u32(nla_b) >=
++ doi_def->map.std->lvl.cipso_size)
++ doi_def->map.std->lvl.cipso_size =
++ nla_get_u32(nla_b) + 1;
++ break;
++ }
++ }
++ if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS ||
++ doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
++ goto add_std_failure;
++ doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
++ sizeof(u32),
++ GFP_KERNEL);
++ if (doi_def->map.std->lvl.local == NULL) {
++ ret_val = -ENOMEM;
++ goto add_std_failure;
++ }
++ doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
++ sizeof(u32),
++ GFP_KERNEL);
++ if (doi_def->map.std->lvl.cipso == NULL) {
++ ret_val = -ENOMEM;
++ goto add_std_failure;
++ }
++ nla_for_each_nested(nla_a,
++ info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
++ nla_a_rem)
++ if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
++ struct nlattr *lvl_loc;
++ struct nlattr *lvl_rem;
++
++ if (nla_validate_nested(nla_a,
++ NLBL_CIPSOV4_A_MAX,
++ netlbl_cipsov4_genl_policy) != 0)
++ goto add_std_failure;
++
++ lvl_loc = nla_find_nested(nla_a,
++ NLBL_CIPSOV4_A_MLSLVLLOC);
++ lvl_rem = nla_find_nested(nla_a,
++ NLBL_CIPSOV4_A_MLSLVLREM);
++ if (lvl_loc == NULL || lvl_rem == NULL)
++ goto add_std_failure;
++ doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
++ nla_get_u32(lvl_rem);
++ doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
++ nla_get_u32(lvl_loc);
++ }
++
++ if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
++ if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
++ NLBL_CIPSOV4_A_MAX,
++ netlbl_cipsov4_genl_policy) != 0)
++ goto add_std_failure;
++
++ nla_for_each_nested(nla_a,
++ info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
++ nla_a_rem)
++ if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
++ if (nla_validate_nested(nla_a,
++ NLBL_CIPSOV4_A_MAX,
++ netlbl_cipsov4_genl_policy) != 0)
++ goto add_std_failure;
++ nla_for_each_nested(nla_b, nla_a, nla_b_rem)
++ switch (nla_b->nla_type) {
++ case NLBL_CIPSOV4_A_MLSCATLOC:
++ if (nla_get_u32(nla_b) >=
++ doi_def->map.std->cat.local_size)
++ doi_def->map.std->cat.local_size =
++ nla_get_u32(nla_b) + 1;
++ break;
++ case NLBL_CIPSOV4_A_MLSCATREM:
++ if (nla_get_u32(nla_b) >=
++ doi_def->map.std->cat.cipso_size)
++ doi_def->map.std->cat.cipso_size =
++ nla_get_u32(nla_b) + 1;
++ break;
++ }
++ }
++ if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS ||
++ doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
++ goto add_std_failure;
++ doi_def->map.std->cat.local = kcalloc(
++ doi_def->map.std->cat.local_size,
++ sizeof(u32),
++ GFP_KERNEL);
++ if (doi_def->map.std->cat.local == NULL) {
++ ret_val = -ENOMEM;
++ goto add_std_failure;
++ }
++ doi_def->map.std->cat.cipso = kcalloc(
++ doi_def->map.std->cat.cipso_size,
++ sizeof(u32),
++ GFP_KERNEL);
++ if (doi_def->map.std->cat.cipso == NULL) {
++ ret_val = -ENOMEM;
++ goto add_std_failure;
++ }
++ nla_for_each_nested(nla_a,
++ info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
++ nla_a_rem)
++ if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
++ struct nlattr *cat_loc;
++ struct nlattr *cat_rem;
++
++ cat_loc = nla_find_nested(nla_a,
++ NLBL_CIPSOV4_A_MLSCATLOC);
++ cat_rem = nla_find_nested(nla_a,
++ NLBL_CIPSOV4_A_MLSCATREM);
++ if (cat_loc == NULL || cat_rem == NULL)
++ goto add_std_failure;
++ doi_def->map.std->cat.local[
++ nla_get_u32(cat_loc)] =
++ nla_get_u32(cat_rem);
++ doi_def->map.std->cat.cipso[
++ nla_get_u32(cat_rem)] =
++ nla_get_u32(cat_loc);
++ }
++ }
++
++ ret_val = cipso_v4_doi_add(doi_def);
++ if (ret_val != 0)
++ goto add_std_failure;
++ return 0;
++
++add_std_failure:
++ if (doi_def)
++ netlbl_cipsov4_doi_free(&doi_def->rcu);
++ return ret_val;
++}
++
++/**
++ * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
++ * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
++ * error.
++ *
++ */
++static int netlbl_cipsov4_add_pass(struct genl_info *info)
++{
++ int ret_val;
++ struct cipso_v4_doi *doi_def = NULL;
++
++ if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
++ return -EINVAL;
++
++ doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
++ if (doi_def == NULL)
++ return -ENOMEM;
++ doi_def->type = CIPSO_V4_MAP_PASS;
++
++ ret_val = netlbl_cipsov4_add_common(info, doi_def);
++ if (ret_val != 0)
++ goto add_pass_failure;
++
++ ret_val = cipso_v4_doi_add(doi_def);
++ if (ret_val != 0)
++ goto add_pass_failure;
++ return 0;
++
++add_pass_failure:
++ netlbl_cipsov4_doi_free(&doi_def->rcu);
++ return ret_val;
++}
++
++/**
++ * netlbl_cipsov4_add - Handle an ADD message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Create a new DOI definition based on the given ADD message and add it to the
++ * CIPSO V4 engine. Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
++
++{
++ int ret_val = -EINVAL;
++ u32 type;
++ u32 doi;
++ const char *type_str = "(unknown)";
++ struct audit_buffer *audit_buf;
++ struct netlbl_audit audit_info;
++
++ if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
++ !info->attrs[NLBL_CIPSOV4_A_MTYPE])
++ return -EINVAL;
++
++ doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
++ netlbl_netlink_auditinfo(skb, &audit_info);
++
++ type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
++ switch (type) {
++ case CIPSO_V4_MAP_STD:
++ type_str = "std";
++ ret_val = netlbl_cipsov4_add_std(info);
++ break;
++ case CIPSO_V4_MAP_PASS:
++ type_str = "pass";
++ ret_val = netlbl_cipsov4_add_pass(info);
++ break;
++ }
++
++ audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
++ &audit_info);
++ audit_log_format(audit_buf,
++ " cipso_doi=%u cipso_type=%s res=%u",
++ doi,
++ type_str,
++ ret_val == 0 ? 1 : 0);
++ audit_log_end(audit_buf);
++
++ return ret_val;
++}
++
++/**
++ * netlbl_cipsov4_list - Handle a LIST message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated LIST message and respond accordingly. While the
++ * response message generated by the kernel is straightforward, determining
++ * before hand the size of the buffer to allocate is not (we have to generate
++ * the message to know the size). In order to keep this function sane what we
++ * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
++ * that size, if we fail then we restart with a larger buffer and try again.
++ * We continue in this manner until we hit a limit of failed attempts then we
++ * give up and just send an error message. Returns zero on success and
++ * negative values on error.
++ *
++ */
++static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val;
++ struct sk_buff *ans_skb = NULL;
++ u32 nlsze_mult = 1;
++ void *data;
++ u32 doi;
++ struct nlattr *nla_a;
++ struct nlattr *nla_b;
++ struct cipso_v4_doi *doi_def;
++ u32 iter;
++
++ if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
++ ret_val = -EINVAL;
++ goto list_failure;
++ }
++
++list_start:
++ ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL);
++ if (ans_skb == NULL) {
++ ret_val = -ENOMEM;
++ goto list_failure;
++ }
++ data = netlbl_netlink_hdr_put(ans_skb,
++ info->snd_pid,
++ info->snd_seq,
++ netlbl_cipsov4_gnl_family.id,
++ 0,
++ NLBL_CIPSOV4_C_LIST);
++ if (data == NULL) {
++ ret_val = -ENOMEM;
++ goto list_failure;
++ }
++
++ doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
++
++ rcu_read_lock();
++ doi_def = cipso_v4_doi_getdef(doi);
++ if (doi_def == NULL) {
++ ret_val = -EINVAL;
++ goto list_failure;
++ }
++
++ ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
++ if (ret_val != 0)
++ goto list_failure_lock;
++
++ nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
++ if (nla_a == NULL) {
++ ret_val = -ENOMEM;
++ goto list_failure_lock;
++ }
++ for (iter = 0;
++ iter < CIPSO_V4_TAG_MAXCNT &&
++ doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
++ iter++) {
++ ret_val = nla_put_u8(ans_skb,
++ NLBL_CIPSOV4_A_TAG,
++ doi_def->tags[iter]);
++ if (ret_val != 0)
++ goto list_failure_lock;
++ }
++ nla_nest_end(ans_skb, nla_a);
++
++ switch (doi_def->type) {
++ case CIPSO_V4_MAP_STD:
++ nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
++ if (nla_a == NULL) {
++ ret_val = -ENOMEM;
++ goto list_failure_lock;
++ }
++ for (iter = 0;
++ iter < doi_def->map.std->lvl.local_size;
++ iter++) {
++ if (doi_def->map.std->lvl.local[iter] ==
++ CIPSO_V4_INV_LVL)
++ continue;
++
++ nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
++ if (nla_b == NULL) {
++ ret_val = -ENOMEM;
++ goto list_retry;
++ }
++ ret_val = nla_put_u32(ans_skb,
++ NLBL_CIPSOV4_A_MLSLVLLOC,
++ iter);
++ if (ret_val != 0)
++ goto list_retry;
++ ret_val = nla_put_u32(ans_skb,
++ NLBL_CIPSOV4_A_MLSLVLREM,
++ doi_def->map.std->lvl.local[iter]);
++ if (ret_val != 0)
++ goto list_retry;
++ nla_nest_end(ans_skb, nla_b);
++ }
++ nla_nest_end(ans_skb, nla_a);
++
++ nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
++ if (nla_a == NULL) {
++ ret_val = -ENOMEM;
++ goto list_retry;
++ }
++ for (iter = 0;
++ iter < doi_def->map.std->cat.local_size;
++ iter++) {
++ if (doi_def->map.std->cat.local[iter] ==
++ CIPSO_V4_INV_CAT)
++ continue;
++
++ nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
++ if (nla_b == NULL) {
++ ret_val = -ENOMEM;
++ goto list_retry;
++ }
++ ret_val = nla_put_u32(ans_skb,
++ NLBL_CIPSOV4_A_MLSCATLOC,
++ iter);
++ if (ret_val != 0)
++ goto list_retry;
++ ret_val = nla_put_u32(ans_skb,
++ NLBL_CIPSOV4_A_MLSCATREM,
++ doi_def->map.std->cat.local[iter]);
++ if (ret_val != 0)
++ goto list_retry;
++ nla_nest_end(ans_skb, nla_b);
++ }
++ nla_nest_end(ans_skb, nla_a);
++
++ break;
++ }
++ rcu_read_unlock();
++
++ genlmsg_end(ans_skb, data);
++
++ ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
++ if (ret_val != 0)
++ goto list_failure;
++
++ return 0;
++
++list_retry:
++ /* XXX - this limit is a guesstimate */
++ if (nlsze_mult < 4) {
++ rcu_read_unlock();
++ kfree_skb(ans_skb);
++ nlsze_mult++;
++ goto list_start;
++ }
++list_failure_lock:
++ rcu_read_unlock();
++list_failure:
++ kfree_skb(ans_skb);
++ return ret_val;
++}
++
++/**
++ * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
++ * @doi_def: the CIPSOv4 DOI definition
++ * @arg: the netlbl_cipsov4_doiwalk_arg structure
++ *
++ * Description:
++ * This function is designed to be used as a callback to the
++ * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
++ * message. Returns the size of the message on success, negative values on
++ * failure.
++ *
++ */
++static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
++{
++ int ret_val = -ENOMEM;
++ struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
++ void *data;
++
++ data = netlbl_netlink_hdr_put(cb_arg->skb,
++ NETLINK_CB(cb_arg->nl_cb->skb).pid,
++ cb_arg->seq,
++ netlbl_cipsov4_gnl_family.id,
++ NLM_F_MULTI,
++ NLBL_CIPSOV4_C_LISTALL);
++ if (data == NULL)
++ goto listall_cb_failure;
++
++ ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
++ if (ret_val != 0)
++ goto listall_cb_failure;
++ ret_val = nla_put_u32(cb_arg->skb,
++ NLBL_CIPSOV4_A_MTYPE,
++ doi_def->type);
++ if (ret_val != 0)
++ goto listall_cb_failure;
++
++ return genlmsg_end(cb_arg->skb, data);
++
++listall_cb_failure:
++ genlmsg_cancel(cb_arg->skb, data);
++ return ret_val;
++}
++
++/**
++ * netlbl_cipsov4_listall - Handle a LISTALL message
++ * @skb: the NETLINK buffer
++ * @cb: the NETLINK callback
++ *
++ * Description:
++ * Process a user generated LISTALL message and respond accordingly. Returns
++ * zero on success and negative values on error.
++ *
++ */
++static int netlbl_cipsov4_listall(struct sk_buff *skb,
++ struct netlink_callback *cb)
++{
++ struct netlbl_cipsov4_doiwalk_arg cb_arg;
++ int doi_skip = cb->args[0];
++
++ cb_arg.nl_cb = cb;
++ cb_arg.skb = skb;
++ cb_arg.seq = cb->nlh->nlmsg_seq;
++
++ cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
++
++ cb->args[0] = doi_skip;
++ return skb->len;
++}
++
++/**
++ * netlbl_cipsov4_remove - Handle a REMOVE message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated REMOVE message and respond accordingly. Returns
++ * zero on success, negative values on failure.
++ *
++ */
++static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val = -EINVAL;
++ u32 doi = 0;
++ struct audit_buffer *audit_buf;
++ struct netlbl_audit audit_info;
++
++ if (!info->attrs[NLBL_CIPSOV4_A_DOI])
++ return -EINVAL;
++
++ doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
++ netlbl_netlink_auditinfo(skb, &audit_info);
++
++ ret_val = cipso_v4_doi_remove(doi,
++ &audit_info,
++ netlbl_cipsov4_doi_free);
++
++ audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
++ &audit_info);
++ audit_log_format(audit_buf,
++ " cipso_doi=%u res=%u",
++ doi,
++ ret_val == 0 ? 1 : 0);
++ audit_log_end(audit_buf);
++
++ return ret_val;
++}
++
++/*
++ * NetLabel Generic NETLINK Command Definitions
++ */
++
++static struct genl_ops netlbl_cipsov4_genl_c_add = {
++ .cmd = NLBL_CIPSOV4_C_ADD,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_cipsov4_genl_policy,
++ .doit = netlbl_cipsov4_add,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_cipsov4_genl_c_remove = {
++ .cmd = NLBL_CIPSOV4_C_REMOVE,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_cipsov4_genl_policy,
++ .doit = netlbl_cipsov4_remove,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_cipsov4_genl_c_list = {
++ .cmd = NLBL_CIPSOV4_C_LIST,
++ .flags = 0,
++ .policy = netlbl_cipsov4_genl_policy,
++ .doit = netlbl_cipsov4_list,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_cipsov4_genl_c_listall = {
++ .cmd = NLBL_CIPSOV4_C_LISTALL,
++ .flags = 0,
++ .policy = netlbl_cipsov4_genl_policy,
++ .doit = NULL,
++ .dumpit = netlbl_cipsov4_listall,
++};
++
++/*
++ * NetLabel Generic NETLINK Protocol Functions
++ */
++
++/**
++ * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
++ *
++ * Description:
++ * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
++ * mechanism. Returns zero on success, negative values on failure.
++ *
++ */
++int netlbl_cipsov4_genl_init(void)
++{
++ int ret_val;
++
++ ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
++ if (ret_val != 0)
++ return ret_val;
++
++ ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
++ &netlbl_cipsov4_genl_c_add);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
++ &netlbl_cipsov4_genl_c_remove);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
++ &netlbl_cipsov4_genl_c_list);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
++ &netlbl_cipsov4_genl_c_listall);
++ if (ret_val != 0)
++ return ret_val;
++
++ return 0;
++}
+diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h
+new file mode 100644
+index 0000000..f03cf9b
+--- /dev/null
++++ b/net/netlabel/netlabel_cipso_v4.h
+@@ -0,0 +1,166 @@
++/*
++ * NetLabel CIPSO/IPv4 Support
++ *
++ * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
++ * NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _NETLABEL_CIPSO_V4
++#define _NETLABEL_CIPSO_V4
++
++#include <net/netlabel.h>
++
++/*
++ * The following NetLabel payloads are supported by the CIPSO subsystem.
++ *
++ * o ADD:
++ * Sent by an application to add a new DOI mapping table.
++ *
++ * Required attributes:
++ *
++ * NLBL_CIPSOV4_A_DOI
++ * NLBL_CIPSOV4_A_MTYPE
++ * NLBL_CIPSOV4_A_TAGLST
++ *
++ * If using CIPSO_V4_MAP_STD the following attributes are required:
++ *
++ * NLBL_CIPSOV4_A_MLSLVLLST
++ * NLBL_CIPSOV4_A_MLSCATLST
++ *
++ * If using CIPSO_V4_MAP_PASS no additional attributes are required.
++ *
++ * o REMOVE:
++ * Sent by an application to remove a specific DOI mapping table from the
++ * CIPSO V4 system.
++ *
++ * Required attributes:
++ *
++ * NLBL_CIPSOV4_A_DOI
++ *
++ * o LIST:
++ * Sent by an application to list the details of a DOI definition. On
++ * success the kernel should send a response using the following format.
++ *
++ * Required attributes:
++ *
++ * NLBL_CIPSOV4_A_DOI
++ *
++ * The valid response message format depends on the type of the DOI mapping,
++ * the defined formats are shown below.
++ *
++ * Required attributes:
++ *
++ * NLBL_CIPSOV4_A_MTYPE
++ * NLBL_CIPSOV4_A_TAGLST
++ *
++ * If using CIPSO_V4_MAP_STD the following attributes are required:
++ *
++ * NLBL_CIPSOV4_A_MLSLVLLST
++ * NLBL_CIPSOV4_A_MLSCATLST
++ *
++ * If using CIPSO_V4_MAP_PASS no additional attributes are required.
++ *
++ * o LISTALL:
++ * This message is sent by an application to list the valid DOIs on the
++ * system. When sent by an application there is no payload and the
++ * NLM_F_DUMP flag should be set. The kernel should respond with a series of
++ * the following messages.
++ *
++ * Required attributes:
++ *
++ * NLBL_CIPSOV4_A_DOI
++ * NLBL_CIPSOV4_A_MTYPE
++ *
++ */
++
++/* NetLabel CIPSOv4 commands */
++enum {
++ NLBL_CIPSOV4_C_UNSPEC,
++ NLBL_CIPSOV4_C_ADD,
++ NLBL_CIPSOV4_C_REMOVE,
++ NLBL_CIPSOV4_C_LIST,
++ NLBL_CIPSOV4_C_LISTALL,
++ __NLBL_CIPSOV4_C_MAX,
++};
++#define NLBL_CIPSOV4_C_MAX (__NLBL_CIPSOV4_C_MAX - 1)
++
++/* NetLabel CIPSOv4 attributes */
++enum {
++ NLBL_CIPSOV4_A_UNSPEC,
++ NLBL_CIPSOV4_A_DOI,
++ /* (NLA_U32)
++ * the DOI value */
++ NLBL_CIPSOV4_A_MTYPE,
++ /* (NLA_U32)
++ * the mapping table type (defined in the cipso_ipv4.h header as
++ * CIPSO_V4_MAP_*) */
++ NLBL_CIPSOV4_A_TAG,
++ /* (NLA_U8)
++ * a CIPSO tag type, meant to be used within a NLBL_CIPSOV4_A_TAGLST
++ * attribute */
++ NLBL_CIPSOV4_A_TAGLST,
++ /* (NLA_NESTED)
++ * the CIPSO tag list for the DOI, there must be at least one
++ * NLBL_CIPSOV4_A_TAG attribute, tags listed first are given higher
++ * priorirty when sending packets */
++ NLBL_CIPSOV4_A_MLSLVLLOC,
++ /* (NLA_U32)
++ * the local MLS sensitivity level */
++ NLBL_CIPSOV4_A_MLSLVLREM,
++ /* (NLA_U32)
++ * the remote MLS sensitivity level */
++ NLBL_CIPSOV4_A_MLSLVL,
++ /* (NLA_NESTED)
++ * a MLS sensitivity level mapping, must contain only one attribute of
++ * each of the following types: NLBL_CIPSOV4_A_MLSLVLLOC and
++ * NLBL_CIPSOV4_A_MLSLVLREM */
++ NLBL_CIPSOV4_A_MLSLVLLST,
++ /* (NLA_NESTED)
++ * the CIPSO level mappings, there must be at least one
++ * NLBL_CIPSOV4_A_MLSLVL attribute */
++ NLBL_CIPSOV4_A_MLSCATLOC,
++ /* (NLA_U32)
++ * the local MLS category */
++ NLBL_CIPSOV4_A_MLSCATREM,
++ /* (NLA_U32)
++ * the remote MLS category */
++ NLBL_CIPSOV4_A_MLSCAT,
++ /* (NLA_NESTED)
++ * a MLS category mapping, must contain only one attribute of each of
++ * the following types: NLBL_CIPSOV4_A_MLSCATLOC and
++ * NLBL_CIPSOV4_A_MLSCATREM */
++ NLBL_CIPSOV4_A_MLSCATLST,
++ /* (NLA_NESTED)
++ * the CIPSO category mappings, there must be at least one
++ * NLBL_CIPSOV4_A_MLSCAT attribute */
++ __NLBL_CIPSOV4_A_MAX,
++};
++#define NLBL_CIPSOV4_A_MAX (__NLBL_CIPSOV4_A_MAX - 1)
++
++/* NetLabel protocol functions */
++int netlbl_cipsov4_genl_init(void);
++
++#endif
+diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
+new file mode 100644
+index 0000000..af4371d
+--- /dev/null
++++ b/net/netlabel/netlabel_domainhash.c
+@@ -0,0 +1,448 @@
++/*
++ * NetLabel Domain Hash Table
++ *
++ * This file manages the domain hash table that NetLabel uses to determine
++ * which network labeling protocol to use for a given domain. The NetLabel
++ * system manages static and dynamic label mappings for network protocols such
++ * as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/rcupdate.h>
++#include <linux/list.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/audit.h>
++#include <net/netlabel.h>
++#include <net/cipso_ipv4.h>
++#include <asm/bug.h>
++
++#include "netlabel_mgmt.h"
++#include "netlabel_domainhash.h"
++#include "netlabel_user.h"
++
++struct netlbl_domhsh_tbl {
++ struct list_head *tbl;
++ u32 size;
++};
++
++/* Domain hash table */
++/* XXX - updates should be so rare that having one spinlock for the entire
++ * hash table should be okay */
++static DEFINE_SPINLOCK(netlbl_domhsh_lock);
++static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
++
++/* Default domain mapping */
++static DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
++static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
++
++/*
++ * Domain Hash Table Helper Functions
++ */
++
++/**
++ * netlbl_domhsh_free_entry - Frees a domain hash table entry
++ * @entry: the entry's RCU field
++ *
++ * Description:
++ * This function is designed to be used as a callback to the call_rcu()
++ * function so that the memory allocated to a hash table entry can be released
++ * safely.
++ *
++ */
++static void netlbl_domhsh_free_entry(struct rcu_head *entry)
++{
++ struct netlbl_dom_map *ptr;
++
++ ptr = container_of(entry, struct netlbl_dom_map, rcu);
++ kfree(ptr->domain);
++ kfree(ptr);
++}
++
++/**
++ * netlbl_domhsh_hash - Hashing function for the domain hash table
++ * @domain: the domain name to hash
++ *
++ * Description:
++ * This is the hashing function for the domain hash table, it returns the
++ * correct bucket number for the domain. The caller is responsibile for
++ * calling the rcu_read_[un]lock() functions.
++ *
++ */
++static u32 netlbl_domhsh_hash(const char *key)
++{
++ u32 iter;
++ u32 val;
++ u32 len;
++
++ /* This is taken (with slight modification) from
++ * security/selinux/ss/symtab.c:symhash() */
++
++ for (iter = 0, val = 0, len = strlen(key); iter < len; iter++)
++ val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter];
++ return val & (rcu_dereference(netlbl_domhsh)->size - 1);
++}
++
++/**
++ * netlbl_domhsh_search - Search for a domain entry
++ * @domain: the domain
++ * @def: return default if no match is found
++ *
++ * Description:
++ * Searches the domain hash table and returns a pointer to the hash table
++ * entry if found, otherwise NULL is returned. If @def is non-zero and a
++ * match is not found in the domain hash table the default mapping is returned
++ * if it exists. The caller is responsibile for the rcu hash table locks
++ * (i.e. the caller much call rcu_read_[un]lock()).
++ *
++ */
++static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def)
++{
++ u32 bkt;
++ struct netlbl_dom_map *iter;
++
++ if (domain != NULL) {
++ bkt = netlbl_domhsh_hash(domain);
++ list_for_each_entry_rcu(iter, &netlbl_domhsh->tbl[bkt], list)
++ if (iter->valid && strcmp(iter->domain, domain) == 0)
++ return iter;
++ }
++
++ if (def != 0) {
++ iter = rcu_dereference(netlbl_domhsh_def);
++ if (iter != NULL && iter->valid)
++ return iter;
++ }
++
++ return NULL;
++}
++
++/*
++ * Domain Hash Table Functions
++ */
++
++/**
++ * netlbl_domhsh_init - Init for the domain hash
++ * @size: the number of bits to use for the hash buckets
++ *
++ * Description:
++ * Initializes the domain hash table, should be called only by
++ * netlbl_user_init() during initialization. Returns zero on success, non-zero
++ * values on error.
++ *
++ */
++int netlbl_domhsh_init(u32 size)
++{
++ u32 iter;
++ struct netlbl_domhsh_tbl *hsh_tbl;
++
++ if (size == 0)
++ return -EINVAL;
++
++ hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
++ if (hsh_tbl == NULL)
++ return -ENOMEM;
++ hsh_tbl->size = 1 << size;
++ hsh_tbl->tbl = kcalloc(hsh_tbl->size,
++ sizeof(struct list_head),
++ GFP_KERNEL);
++ if (hsh_tbl->tbl == NULL) {
++ kfree(hsh_tbl);
++ return -ENOMEM;
++ }
++ for (iter = 0; iter < hsh_tbl->size; iter++)
++ INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
++
++ rcu_read_lock();
++ spin_lock(&netlbl_domhsh_lock);
++ rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
++ spin_unlock(&netlbl_domhsh_lock);
++ rcu_read_unlock();
++
++ return 0;
++}
++
++/**
++ * netlbl_domhsh_add - Adds a entry to the domain hash table
++ * @entry: the entry to add
++ * @audit_info: NetLabel audit information
++ *
++ * Description:
++ * Adds a new entry to the domain hash table and handles any updates to the
++ * lower level protocol handler (i.e. CIPSO). Returns zero on success,
++ * negative on failure.
++ *
++ */
++int netlbl_domhsh_add(struct netlbl_dom_map *entry,
++ struct netlbl_audit *audit_info)
++{
++ int ret_val;
++ u32 bkt;
++ struct audit_buffer *audit_buf;
++ char *audit_domain;
++
++ switch (entry->type) {
++ case NETLBL_NLTYPE_UNLABELED:
++ ret_val = 0;
++ break;
++ case NETLBL_NLTYPE_CIPSOV4:
++ ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
++ entry->domain);
++ break;
++ default:
++ return -EINVAL;
++ }
++ if (ret_val != 0)
++ return ret_val;
++
++ entry->valid = 1;
++ INIT_RCU_HEAD(&entry->rcu);
++
++ ret_val = 0;
++ rcu_read_lock();
++ if (entry->domain != NULL) {
++ bkt = netlbl_domhsh_hash(entry->domain);
++ spin_lock(&netlbl_domhsh_lock);
++ if (netlbl_domhsh_search(entry->domain, 0) == NULL)
++ list_add_tail_rcu(&entry->list,
++ &netlbl_domhsh->tbl[bkt]);
++ else
++ ret_val = -EEXIST;
++ spin_unlock(&netlbl_domhsh_lock);
++ } else if (entry->domain == NULL) {
++ INIT_LIST_HEAD(&entry->list);
++ spin_lock(&netlbl_domhsh_def_lock);
++ if (rcu_dereference(netlbl_domhsh_def) == NULL)
++ rcu_assign_pointer(netlbl_domhsh_def, entry);
++ else
++ ret_val = -EEXIST;
++ spin_unlock(&netlbl_domhsh_def_lock);
++ } else
++ ret_val = -EINVAL;
++
++ if (entry->domain != NULL)
++ audit_domain = entry->domain;
++ else
++ audit_domain = "(default)";
++ audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
++ audit_log_format(audit_buf, " nlbl_domain=%s", audit_domain);
++ switch (entry->type) {
++ case NETLBL_NLTYPE_UNLABELED:
++ audit_log_format(audit_buf, " nlbl_protocol=unlbl");
++ break;
++ case NETLBL_NLTYPE_CIPSOV4:
++ audit_log_format(audit_buf,
++ " nlbl_protocol=cipsov4 cipso_doi=%u",
++ entry->type_def.cipsov4->doi);
++ break;
++ }
++ audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
++ audit_log_end(audit_buf);
++
++ rcu_read_unlock();
++
++ if (ret_val != 0) {
++ switch (entry->type) {
++ case NETLBL_NLTYPE_CIPSOV4:
++ if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
++ entry->domain) != 0)
++ BUG();
++ break;
++ }
++ }
++
++ return ret_val;
++}
++
++/**
++ * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
++ * @entry: the entry to add
++ * @audit_info: NetLabel audit information
++ *
++ * Description:
++ * Adds a new default entry to the domain hash table and handles any updates
++ * to the lower level protocol handler (i.e. CIPSO). Returns zero on success,
++ * negative on failure.
++ *
++ */
++int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
++ struct netlbl_audit *audit_info)
++{
++ return netlbl_domhsh_add(entry, audit_info);
++}
++
++/**
++ * netlbl_domhsh_remove - Removes an entry from the domain hash table
++ * @domain: the domain to remove
++ * @audit_info: NetLabel audit information
++ *
++ * Description:
++ * Removes an entry from the domain hash table and handles any updates to the
++ * lower level protocol handler (i.e. CIPSO). Returns zero on success,
++ * negative on failure.
++ *
++ */
++int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
++{
++ int ret_val = -ENOENT;
++ struct netlbl_dom_map *entry;
++ struct audit_buffer *audit_buf;
++ char *audit_domain;
++
++ rcu_read_lock();
++ if (domain != NULL)
++ entry = netlbl_domhsh_search(domain, 0);
++ else
++ entry = netlbl_domhsh_search(domain, 1);
++ if (entry == NULL)
++ goto remove_return;
++ switch (entry->type) {
++ case NETLBL_NLTYPE_UNLABELED:
++ break;
++ case NETLBL_NLTYPE_CIPSOV4:
++ ret_val = cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
++ entry->domain);
++ if (ret_val != 0)
++ goto remove_return;
++ break;
++ }
++ ret_val = 0;
++ if (entry != rcu_dereference(netlbl_domhsh_def)) {
++ spin_lock(&netlbl_domhsh_lock);
++ if (entry->valid) {
++ entry->valid = 0;
++ list_del_rcu(&entry->list);
++ } else
++ ret_val = -ENOENT;
++ spin_unlock(&netlbl_domhsh_lock);
++ } else {
++ spin_lock(&netlbl_domhsh_def_lock);
++ if (entry->valid) {
++ entry->valid = 0;
++ rcu_assign_pointer(netlbl_domhsh_def, NULL);
++ } else
++ ret_val = -ENOENT;
++ spin_unlock(&netlbl_domhsh_def_lock);
++ }
++
++ if (entry->domain != NULL)
++ audit_domain = entry->domain;
++ else
++ audit_domain = "(default)";
++ audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
++ audit_log_format(audit_buf,
++ " nlbl_domain=%s res=%u",
++ audit_domain,
++ ret_val == 0 ? 1 : 0);
++ audit_log_end(audit_buf);
++
++ if (ret_val == 0)
++ call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
++
++remove_return:
++ rcu_read_unlock();
++ return ret_val;
++}
++
++/**
++ * netlbl_domhsh_remove_default - Removes the default entry from the table
++ * @audit_info: NetLabel audit information
++ *
++ * Description:
++ * Removes/resets the default entry for the domain hash table and handles any
++ * updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
++ * success, non-zero on failure.
++ *
++ */
++int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
++{
++ return netlbl_domhsh_remove(NULL, audit_info);
++}
++
++/**
++ * netlbl_domhsh_getentry - Get an entry from the domain hash table
++ * @domain: the domain name to search for
++ *
++ * Description:
++ * Look through the domain hash table searching for an entry to match @domain,
++ * return a pointer to a copy of the entry or NULL. The caller is responsibile
++ * for ensuring that rcu_read_[un]lock() is called.
++ *
++ */
++struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
++{
++ return netlbl_domhsh_search(domain, 1);
++}
++
++/**
++ * netlbl_domhsh_walk - Iterate through the domain mapping hash table
++ * @skip_bkt: the number of buckets to skip at the start
++ * @skip_chain: the number of entries to skip in the first iterated bucket
++ * @callback: callback for each entry
++ * @cb_arg: argument for the callback function
++ *
++ * Description:
++ * Interate over the domain mapping hash table, skipping the first @skip_bkt
++ * buckets and @skip_chain entries. For each entry in the table call
++ * @callback, if @callback returns a negative value stop 'walking' through the
++ * table and return. Updates the values in @skip_bkt and @skip_chain on
++ * return. Returns zero on succcess, negative values on failure.
++ *
++ */
++int netlbl_domhsh_walk(u32 *skip_bkt,
++ u32 *skip_chain,
++ int (*callback) (struct netlbl_dom_map *entry, void *arg),
++ void *cb_arg)
++{
++ int ret_val = -ENOENT;
++ u32 iter_bkt;
++ struct netlbl_dom_map *iter_entry;
++ u32 chain_cnt = 0;
++
++ rcu_read_lock();
++ for (iter_bkt = *skip_bkt;
++ iter_bkt < rcu_dereference(netlbl_domhsh)->size;
++ iter_bkt++, chain_cnt = 0) {
++ list_for_each_entry_rcu(iter_entry,
++ &netlbl_domhsh->tbl[iter_bkt],
++ list)
++ if (iter_entry->valid) {
++ if (chain_cnt++ < *skip_chain)
++ continue;
++ ret_val = callback(iter_entry, cb_arg);
++ if (ret_val < 0) {
++ chain_cnt--;
++ goto walk_return;
++ }
++ }
++ }
++
++walk_return:
++ rcu_read_unlock();
++ *skip_bkt = iter_bkt;
++ *skip_chain = chain_cnt;
++ return ret_val;
++}
+diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
+new file mode 100644
+index 0000000..3689956
+--- /dev/null
++++ b/net/netlabel/netlabel_domainhash.h
+@@ -0,0 +1,71 @@
++/*
++ * NetLabel Domain Hash Table
++ *
++ * This file manages the domain hash table that NetLabel uses to determine
++ * which network labeling protocol to use for a given domain. The NetLabel
++ * system manages static and dynamic label mappings for network protocols such
++ * as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _NETLABEL_DOMAINHASH_H
++#define _NETLABEL_DOMAINHASH_H
++
++#include <linux/types.h>
++#include <linux/rcupdate.h>
++#include <linux/list.h>
++
++/* Domain hash table size */
++/* XXX - currently this number is an uneducated guess */
++#define NETLBL_DOMHSH_BITSIZE 7
++
++/* Domain mapping definition struct */
++struct netlbl_dom_map {
++ char *domain;
++ u32 type;
++ union {
++ struct cipso_v4_doi *cipsov4;
++ } type_def;
++
++ u32 valid;
++ struct list_head list;
++ struct rcu_head rcu;
++};
++
++/* init function */
++int netlbl_domhsh_init(u32 size);
++
++/* Manipulate the domain hash table */
++int netlbl_domhsh_add(struct netlbl_dom_map *entry,
++ struct netlbl_audit *audit_info);
++int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
++ struct netlbl_audit *audit_info);
++int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
++struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
++int netlbl_domhsh_walk(u32 *skip_bkt,
++ u32 *skip_chain,
++ int (*callback) (struct netlbl_dom_map *entry, void *arg),
++ void *cb_arg);
++
++#endif
+diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
+new file mode 100644
+index 0000000..ff97110
+--- /dev/null
++++ b/net/netlabel/netlabel_kapi.c
+@@ -0,0 +1,254 @@
++/*
++ * NetLabel Kernel API
++ *
++ * This file defines the kernel API for the NetLabel system. The NetLabel
++ * system manages static and dynamic label mappings for network protocols such
++ * as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/init.h>
++#include <linux/types.h>
++#include <net/ip.h>
++#include <net/netlabel.h>
++#include <net/cipso_ipv4.h>
++#include <asm/bug.h>
++
++#include "netlabel_domainhash.h"
++#include "netlabel_unlabeled.h"
++#include "netlabel_user.h"
++
++/*
++ * LSM Functions
++ */
++
++/**
++ * netlbl_socket_setattr - Label a socket using the correct protocol
++ * @sock: the socket to label
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Attach the correct label to the given socket using the security attributes
++ * specified in @secattr. This function requires exclusive access to
++ * @sock->sk, which means it either needs to be in the process of being
++ * created or locked via lock_sock(sock->sk). Returns zero on success,
++ * negative values on failure.
++ *
++ */
++int netlbl_socket_setattr(const struct socket *sock,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val = -ENOENT;
++ struct netlbl_dom_map *dom_entry;
++
++ rcu_read_lock();
++ dom_entry = netlbl_domhsh_getentry(secattr->domain);
++ if (dom_entry == NULL)
++ goto socket_setattr_return;
++ switch (dom_entry->type) {
++ case NETLBL_NLTYPE_CIPSOV4:
++ ret_val = cipso_v4_socket_setattr(sock,
++ dom_entry->type_def.cipsov4,
++ secattr);
++ break;
++ case NETLBL_NLTYPE_UNLABELED:
++ ret_val = 0;
++ break;
++ default:
++ ret_val = -ENOENT;
++ }
++
++socket_setattr_return:
++ rcu_read_unlock();
++ return ret_val;
++}
++
++/**
++ * netlbl_sock_getattr - Determine the security attributes of a sock
++ * @sk: the sock
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Examines the given sock to see any NetLabel style labeling has been
++ * applied to the sock, if so it parses the socket label and returns the
++ * security attributes in @secattr. Returns zero on success, negative values
++ * on failure.
++ *
++ */
++int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val;
++
++ ret_val = cipso_v4_sock_getattr(sk, secattr);
++ if (ret_val == 0)
++ return 0;
++
++ return netlbl_unlabel_getattr(secattr);
++}
++
++/**
++ * netlbl_socket_getattr - Determine the security attributes of a socket
++ * @sock: the socket
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Examines the given socket to see any NetLabel style labeling has been
++ * applied to the socket, if so it parses the socket label and returns the
++ * security attributes in @secattr. Returns zero on success, negative values
++ * on failure.
++ *
++ */
++int netlbl_socket_getattr(const struct socket *sock,
++ struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val;
++
++ ret_val = cipso_v4_socket_getattr(sock, secattr);
++ if (ret_val == 0)
++ return 0;
++
++ return netlbl_unlabel_getattr(secattr);
++}
++
++/**
++ * netlbl_skbuff_getattr - Determine the security attributes of a packet
++ * @skb: the packet
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Examines the given packet to see if a recognized form of packet labeling
++ * is present, if so it parses the packet label and returns the security
++ * attributes in @secattr. Returns zero on success, negative values on
++ * failure.
++ *
++ */
++int netlbl_skbuff_getattr(const struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr)
++{
++ int ret_val;
++
++ ret_val = cipso_v4_skbuff_getattr(skb, secattr);
++ if (ret_val == 0)
++ return 0;
++
++ return netlbl_unlabel_getattr(secattr);
++}
++
++/**
++ * netlbl_skbuff_err - Handle a LSM error on a sk_buff
++ * @skb: the packet
++ * @error: the error code
++ *
++ * Description:
++ * Deal with a LSM problem when handling the packet in @skb, typically this is
++ * a permission denied problem (-EACCES). The correct action is determined
++ * according to the packet's labeling protocol.
++ *
++ */
++void netlbl_skbuff_err(struct sk_buff *skb, int error)
++{
++ if (CIPSO_V4_OPTEXIST(skb))
++ cipso_v4_error(skb, error, 0);
++}
++
++/**
++ * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
++ *
++ * Description:
++ * For all of the NetLabel protocols that support some form of label mapping
++ * cache, invalidate the cache. Returns zero on success, negative values on
++ * error.
++ *
++ */
++void netlbl_cache_invalidate(void)
++{
++ cipso_v4_cache_invalidate();
++}
++
++/**
++ * netlbl_cache_add - Add an entry to a NetLabel protocol cache
++ * @skb: the packet
++ * @secattr: the packet's security attributes
++ *
++ * Description:
++ * Add the LSM security attributes for the given packet to the underlying
++ * NetLabel protocol's label mapping cache. Returns zero on success, negative
++ * values on error.
++ *
++ */
++int netlbl_cache_add(const struct sk_buff *skb,
++ const struct netlbl_lsm_secattr *secattr)
++{
++ if (secattr->cache == NULL)
++ return -ENOMSG;
++
++ if (CIPSO_V4_OPTEXIST(skb))
++ return cipso_v4_cache_add(skb, secattr);
++
++ return -ENOMSG;
++}
++
++/*
++ * Setup Functions
++ */
++
++/**
++ * netlbl_init - Initialize NetLabel
++ *
++ * Description:
++ * Perform the required NetLabel initialization before first use.
++ *
++ */
++static int __init netlbl_init(void)
++{
++ int ret_val;
++
++ printk(KERN_INFO "NetLabel: Initializing\n");
++ printk(KERN_INFO "NetLabel: domain hash size = %u\n",
++ (1 << NETLBL_DOMHSH_BITSIZE));
++ printk(KERN_INFO "NetLabel: protocols ="
++ " UNLABELED"
++ " CIPSOv4"
++ "\n");
++
++ ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
++ if (ret_val != 0)
++ goto init_failure;
++
++ ret_val = netlbl_netlink_init();
++ if (ret_val != 0)
++ goto init_failure;
++
++ ret_val = netlbl_unlabel_defconf();
++ if (ret_val != 0)
++ goto init_failure;
++ printk(KERN_INFO "NetLabel: unlabeled traffic allowed by default\n");
++
++ return 0;
++
++init_failure:
++ panic("NetLabel: failed to initialize properly (%d)\n", ret_val);
++}
++
++subsys_initcall(netlbl_init);
+diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
+new file mode 100644
+index 0000000..53c9079
+--- /dev/null
++++ b/net/netlabel/netlabel_mgmt.c
+@@ -0,0 +1,648 @@
++/*
++ * NetLabel Management Support
++ *
++ * This file defines the management functions for the NetLabel system. The
++ * NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/socket.h>
++#include <linux/string.h>
++#include <linux/skbuff.h>
++#include <net/sock.h>
++#include <net/netlink.h>
++#include <net/genetlink.h>
++#include <net/netlabel.h>
++#include <net/cipso_ipv4.h>
++
++#include "netlabel_domainhash.h"
++#include "netlabel_user.h"
++#include "netlabel_mgmt.h"
++
++/* Argument struct for netlbl_domhsh_walk() */
++struct netlbl_domhsh_walk_arg {
++ struct netlink_callback *nl_cb;
++ struct sk_buff *skb;
++ u32 seq;
++};
++
++/* NetLabel Generic NETLINK CIPSOv4 family */
++static struct genl_family netlbl_mgmt_gnl_family = {
++ .id = GENL_ID_GENERATE,
++ .hdrsize = 0,
++ .name = NETLBL_NLTYPE_MGMT_NAME,
++ .version = NETLBL_PROTO_VERSION,
++ .maxattr = NLBL_MGMT_A_MAX,
++};
++
++/* NetLabel Netlink attribute policy */
++static struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
++ [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
++ [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
++ [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
++ [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
++};
++
++/*
++ * NetLabel Command Handlers
++ */
++
++/**
++ * netlbl_mgmt_add - Handle an ADD message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated ADD message and add the domains from the message
++ * to the hash table. See netlabel.h for a description of the message format.
++ * Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val = -EINVAL;
++ struct netlbl_dom_map *entry = NULL;
++ size_t tmp_size;
++ u32 tmp_val;
++ struct netlbl_audit audit_info;
++
++ if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
++ !info->attrs[NLBL_MGMT_A_PROTOCOL])
++ goto add_failure;
++
++ netlbl_netlink_auditinfo(skb, &audit_info);
++
++ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++ if (entry == NULL) {
++ ret_val = -ENOMEM;
++ goto add_failure;
++ }
++ tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
++ entry->domain = kmalloc(tmp_size, GFP_KERNEL);
++ if (entry->domain == NULL) {
++ ret_val = -ENOMEM;
++ goto add_failure;
++ }
++ entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
++ nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
++
++ switch (entry->type) {
++ case NETLBL_NLTYPE_UNLABELED:
++ ret_val = netlbl_domhsh_add(entry, &audit_info);
++ break;
++ case NETLBL_NLTYPE_CIPSOV4:
++ if (!info->attrs[NLBL_MGMT_A_CV4DOI])
++ goto add_failure;
++
++ tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
++ /* We should be holding a rcu_read_lock() here while we hold
++ * the result but since the entry will always be deleted when
++ * the CIPSO DOI is deleted we aren't going to keep the
++ * lock. */
++ rcu_read_lock();
++ entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
++ if (entry->type_def.cipsov4 == NULL) {
++ rcu_read_unlock();
++ goto add_failure;
++ }
++ ret_val = netlbl_domhsh_add(entry, &audit_info);
++ rcu_read_unlock();
++ break;
++ default:
++ goto add_failure;
++ }
++ if (ret_val != 0)
++ goto add_failure;
++
++ return 0;
++
++add_failure:
++ if (entry)
++ kfree(entry->domain);
++ kfree(entry);
++ return ret_val;
++}
++
++/**
++ * netlbl_mgmt_remove - Handle a REMOVE message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated REMOVE message and remove the specified domain
++ * mappings. Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
++{
++ char *domain;
++ struct netlbl_audit audit_info;
++
++ if (!info->attrs[NLBL_MGMT_A_DOMAIN])
++ return -EINVAL;
++
++ netlbl_netlink_auditinfo(skb, &audit_info);
++
++ domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
++ return netlbl_domhsh_remove(domain, &audit_info);
++}
++
++/**
++ * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
++ * @entry: the domain mapping hash table entry
++ * @arg: the netlbl_domhsh_walk_arg structure
++ *
++ * Description:
++ * This function is designed to be used as a callback to the
++ * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
++ * message. Returns the size of the message on success, negative values on
++ * failure.
++ *
++ */
++static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
++{
++ int ret_val = -ENOMEM;
++ struct netlbl_domhsh_walk_arg *cb_arg = arg;
++ void *data;
++
++ data = netlbl_netlink_hdr_put(cb_arg->skb,
++ NETLINK_CB(cb_arg->nl_cb->skb).pid,
++ cb_arg->seq,
++ netlbl_mgmt_gnl_family.id,
++ NLM_F_MULTI,
++ NLBL_MGMT_C_LISTALL);
++ if (data == NULL)
++ goto listall_cb_failure;
++
++ ret_val = nla_put_string(cb_arg->skb,
++ NLBL_MGMT_A_DOMAIN,
++ entry->domain);
++ if (ret_val != 0)
++ goto listall_cb_failure;
++ ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
++ if (ret_val != 0)
++ goto listall_cb_failure;
++ switch (entry->type) {
++ case NETLBL_NLTYPE_CIPSOV4:
++ ret_val = nla_put_u32(cb_arg->skb,
++ NLBL_MGMT_A_CV4DOI,
++ entry->type_def.cipsov4->doi);
++ if (ret_val != 0)
++ goto listall_cb_failure;
++ break;
++ }
++
++ cb_arg->seq++;
++ return genlmsg_end(cb_arg->skb, data);
++
++listall_cb_failure:
++ genlmsg_cancel(cb_arg->skb, data);
++ return ret_val;
++}
++
++/**
++ * netlbl_mgmt_listall - Handle a LISTALL message
++ * @skb: the NETLINK buffer
++ * @cb: the NETLINK callback
++ *
++ * Description:
++ * Process a user generated LISTALL message and dumps the domain hash table in
++ * a form suitable for use in a kernel generated LISTALL message. Returns zero
++ * on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_listall(struct sk_buff *skb,
++ struct netlink_callback *cb)
++{
++ struct netlbl_domhsh_walk_arg cb_arg;
++ u32 skip_bkt = cb->args[0];
++ u32 skip_chain = cb->args[1];
++
++ cb_arg.nl_cb = cb;
++ cb_arg.skb = skb;
++ cb_arg.seq = cb->nlh->nlmsg_seq;
++
++ netlbl_domhsh_walk(&skip_bkt,
++ &skip_chain,
++ netlbl_mgmt_listall_cb,
++ &cb_arg);
++
++ cb->args[0] = skip_bkt;
++ cb->args[1] = skip_chain;
++ return skb->len;
++}
++
++/**
++ * netlbl_mgmt_adddef - Handle an ADDDEF message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated ADDDEF message and respond accordingly. Returns
++ * zero on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val = -EINVAL;
++ struct netlbl_dom_map *entry = NULL;
++ u32 tmp_val;
++ struct netlbl_audit audit_info;
++
++ if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
++ goto adddef_failure;
++
++ netlbl_netlink_auditinfo(skb, &audit_info);
++
++ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++ if (entry == NULL) {
++ ret_val = -ENOMEM;
++ goto adddef_failure;
++ }
++ entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
++
++ switch (entry->type) {
++ case NETLBL_NLTYPE_UNLABELED:
++ ret_val = netlbl_domhsh_add_default(entry, &audit_info);
++ break;
++ case NETLBL_NLTYPE_CIPSOV4:
++ if (!info->attrs[NLBL_MGMT_A_CV4DOI])
++ goto adddef_failure;
++
++ tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
++ /* We should be holding a rcu_read_lock() here while we hold
++ * the result but since the entry will always be deleted when
++ * the CIPSO DOI is deleted we aren't going to keep the
++ * lock. */
++ rcu_read_lock();
++ entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
++ if (entry->type_def.cipsov4 == NULL) {
++ rcu_read_unlock();
++ goto adddef_failure;
++ }
++ ret_val = netlbl_domhsh_add_default(entry, &audit_info);
++ rcu_read_unlock();
++ break;
++ default:
++ goto adddef_failure;
++ }
++ if (ret_val != 0)
++ goto adddef_failure;
++
++ return 0;
++
++adddef_failure:
++ kfree(entry);
++ return ret_val;
++}
++
++/**
++ * netlbl_mgmt_removedef - Handle a REMOVEDEF message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated REMOVEDEF message and remove the default domain
++ * mapping. Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
++{
++ struct netlbl_audit audit_info;
++
++ netlbl_netlink_auditinfo(skb, &audit_info);
++
++ return netlbl_domhsh_remove_default(&audit_info);
++}
++
++/**
++ * netlbl_mgmt_listdef - Handle a LISTDEF message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated LISTDEF message and dumps the default domain
++ * mapping in a form suitable for use in a kernel generated LISTDEF message.
++ * Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val = -ENOMEM;
++ struct sk_buff *ans_skb = NULL;
++ void *data;
++ struct netlbl_dom_map *entry;
++
++ ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (ans_skb == NULL)
++ return -ENOMEM;
++ data = netlbl_netlink_hdr_put(ans_skb,
++ info->snd_pid,
++ info->snd_seq,
++ netlbl_mgmt_gnl_family.id,
++ 0,
++ NLBL_MGMT_C_LISTDEF);
++ if (data == NULL)
++ goto listdef_failure;
++
++ rcu_read_lock();
++ entry = netlbl_domhsh_getentry(NULL);
++ if (entry == NULL) {
++ ret_val = -ENOENT;
++ goto listdef_failure_lock;
++ }
++ ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
++ if (ret_val != 0)
++ goto listdef_failure_lock;
++ switch (entry->type) {
++ case NETLBL_NLTYPE_CIPSOV4:
++ ret_val = nla_put_u32(ans_skb,
++ NLBL_MGMT_A_CV4DOI,
++ entry->type_def.cipsov4->doi);
++ if (ret_val != 0)
++ goto listdef_failure_lock;
++ break;
++ }
++ rcu_read_unlock();
++
++ genlmsg_end(ans_skb, data);
++
++ ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
++ if (ret_val != 0)
++ goto listdef_failure;
++ return 0;
++
++listdef_failure_lock:
++ rcu_read_unlock();
++listdef_failure:
++ kfree_skb(ans_skb);
++ return ret_val;
++}
++
++/**
++ * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
++ * @skb: the skb to write to
++ * @seq: the NETLINK sequence number
++ * @cb: the NETLINK callback
++ * @protocol: the NetLabel protocol to use in the message
++ *
++ * Description:
++ * This function is to be used in conjunction with netlbl_mgmt_protocols() to
++ * answer a application's PROTOCOLS message. Returns the size of the message
++ * on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
++ struct netlink_callback *cb,
++ u32 protocol)
++{
++ int ret_val = -ENOMEM;
++ void *data;
++
++ data = netlbl_netlink_hdr_put(skb,
++ NETLINK_CB(cb->skb).pid,
++ cb->nlh->nlmsg_seq,
++ netlbl_mgmt_gnl_family.id,
++ NLM_F_MULTI,
++ NLBL_MGMT_C_PROTOCOLS);
++ if (data == NULL)
++ goto protocols_cb_failure;
++
++ ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
++ if (ret_val != 0)
++ goto protocols_cb_failure;
++
++ return genlmsg_end(skb, data);
++
++protocols_cb_failure:
++ genlmsg_cancel(skb, data);
++ return ret_val;
++}
++
++/**
++ * netlbl_mgmt_protocols - Handle a PROTOCOLS message
++ * @skb: the NETLINK buffer
++ * @cb: the NETLINK callback
++ *
++ * Description:
++ * Process a user generated PROTOCOLS message and respond accordingly.
++ *
++ */
++static int netlbl_mgmt_protocols(struct sk_buff *skb,
++ struct netlink_callback *cb)
++{
++ u32 protos_sent = cb->args[0];
++
++ if (protos_sent == 0) {
++ if (netlbl_mgmt_protocols_cb(skb,
++ cb,
++ NETLBL_NLTYPE_UNLABELED) < 0)
++ goto protocols_return;
++ protos_sent++;
++ }
++ if (protos_sent == 1) {
++ if (netlbl_mgmt_protocols_cb(skb,
++ cb,
++ NETLBL_NLTYPE_CIPSOV4) < 0)
++ goto protocols_return;
++ protos_sent++;
++ }
++
++protocols_return:
++ cb->args[0] = protos_sent;
++ return skb->len;
++}
++
++/**
++ * netlbl_mgmt_version - Handle a VERSION message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated VERSION message and respond accordingly. Returns
++ * zero on success, negative values on failure.
++ *
++ */
++static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val = -ENOMEM;
++ struct sk_buff *ans_skb = NULL;
++ void *data;
++
++ ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (ans_skb == NULL)
++ return -ENOMEM;
++ data = netlbl_netlink_hdr_put(ans_skb,
++ info->snd_pid,
++ info->snd_seq,
++ netlbl_mgmt_gnl_family.id,
++ 0,
++ NLBL_MGMT_C_VERSION);
++ if (data == NULL)
++ goto version_failure;
++
++ ret_val = nla_put_u32(ans_skb,
++ NLBL_MGMT_A_VERSION,
++ NETLBL_PROTO_VERSION);
++ if (ret_val != 0)
++ goto version_failure;
++
++ genlmsg_end(ans_skb, data);
++
++ ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
++ if (ret_val != 0)
++ goto version_failure;
++ return 0;
++
++version_failure:
++ kfree_skb(ans_skb);
++ return ret_val;
++}
++
++
++/*
++ * NetLabel Generic NETLINK Command Definitions
++ */
++
++static struct genl_ops netlbl_mgmt_genl_c_add = {
++ .cmd = NLBL_MGMT_C_ADD,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = netlbl_mgmt_add,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_remove = {
++ .cmd = NLBL_MGMT_C_REMOVE,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = netlbl_mgmt_remove,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_listall = {
++ .cmd = NLBL_MGMT_C_LISTALL,
++ .flags = 0,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = NULL,
++ .dumpit = netlbl_mgmt_listall,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_adddef = {
++ .cmd = NLBL_MGMT_C_ADDDEF,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = netlbl_mgmt_adddef,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_removedef = {
++ .cmd = NLBL_MGMT_C_REMOVEDEF,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = netlbl_mgmt_removedef,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_listdef = {
++ .cmd = NLBL_MGMT_C_LISTDEF,
++ .flags = 0,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = netlbl_mgmt_listdef,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_protocols = {
++ .cmd = NLBL_MGMT_C_PROTOCOLS,
++ .flags = 0,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = NULL,
++ .dumpit = netlbl_mgmt_protocols,
++};
++
++static struct genl_ops netlbl_mgmt_genl_c_version = {
++ .cmd = NLBL_MGMT_C_VERSION,
++ .flags = 0,
++ .policy = netlbl_mgmt_genl_policy,
++ .doit = netlbl_mgmt_version,
++ .dumpit = NULL,
++};
++
++/*
++ * NetLabel Generic NETLINK Protocol Functions
++ */
++
++/**
++ * netlbl_mgmt_genl_init - Register the NetLabel management component
++ *
++ * Description:
++ * Register the NetLabel management component with the Generic NETLINK
++ * mechanism. Returns zero on success, negative values on failure.
++ *
++ */
++int netlbl_mgmt_genl_init(void)
++{
++ int ret_val;
++
++ ret_val = genl_register_family(&netlbl_mgmt_gnl_family);
++ if (ret_val != 0)
++ return ret_val;
++
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_add);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_remove);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_listall);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_adddef);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_removedef);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_listdef);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_protocols);
++ if (ret_val != 0)
++ return ret_val;
++ ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
++ &netlbl_mgmt_genl_c_version);
++ if (ret_val != 0)
++ return ret_val;
++
++ return 0;
++}
+diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
+new file mode 100644
+index 0000000..3642d3b
+--- /dev/null
++++ b/net/netlabel/netlabel_mgmt.h
+@@ -0,0 +1,171 @@
++/*
++ * NetLabel Management Support
++ *
++ * This file defines the management functions for the NetLabel system. The
++ * NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _NETLABEL_MGMT_H
++#define _NETLABEL_MGMT_H
++
++#include <net/netlabel.h>
++
++/*
++ * The following NetLabel payloads are supported by the management interface.
++ *
++ * o ADD:
++ * Sent by an application to add a domain mapping to the NetLabel system.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_DOMAIN
++ * NLBL_MGMT_A_PROTOCOL
++ *
++ * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
++ *
++ * NLBL_MGMT_A_CV4DOI
++ *
++ * If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
++ *
++ * o REMOVE:
++ * Sent by an application to remove a domain mapping from the NetLabel
++ * system.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_DOMAIN
++ *
++ * o LISTALL:
++ * This message can be sent either from an application or by the kernel in
++ * response to an application generated LISTALL message. When sent by an
++ * application there is no payload and the NLM_F_DUMP flag should be set.
++ * The kernel should respond with a series of the following messages.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_DOMAIN
++ * NLBL_MGMT_A_PROTOCOL
++ *
++ * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
++ *
++ * NLBL_MGMT_A_CV4DOI
++ *
++ * If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
++ *
++ * o ADDDEF:
++ * Sent by an application to set the default domain mapping for the NetLabel
++ * system.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_PROTOCOL
++ *
++ * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
++ *
++ * NLBL_MGMT_A_CV4DOI
++ *
++ * If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
++ *
++ * o REMOVEDEF:
++ * Sent by an application to remove the default domain mapping from the
++ * NetLabel system, there is no payload.
++ *
++ * o LISTDEF:
++ * This message can be sent either from an application or by the kernel in
++ * response to an application generated LISTDEF message. When sent by an
++ * application there is no payload. On success the kernel should send a
++ * response using the following format.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_PROTOCOL
++ *
++ * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
++ *
++ * NLBL_MGMT_A_CV4DOI
++ *
++ * If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
++ *
++ * o PROTOCOLS:
++ * Sent by an application to request a list of configured NetLabel protocols
++ * in the kernel. When sent by an application there is no payload and the
++ * NLM_F_DUMP flag should be set. The kernel should respond with a series of
++ * the following messages.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_PROTOCOL
++ *
++ * o VERSION:
++ * Sent by an application to request the NetLabel version. When sent by an
++ * application there is no payload. This message type is also used by the
++ * kernel to respond to an VERSION request.
++ *
++ * Required attributes:
++ *
++ * NLBL_MGMT_A_VERSION
++ *
++ */
++
++/* NetLabel Management commands */
++enum {
++ NLBL_MGMT_C_UNSPEC,
++ NLBL_MGMT_C_ADD,
++ NLBL_MGMT_C_REMOVE,
++ NLBL_MGMT_C_LISTALL,
++ NLBL_MGMT_C_ADDDEF,
++ NLBL_MGMT_C_REMOVEDEF,
++ NLBL_MGMT_C_LISTDEF,
++ NLBL_MGMT_C_PROTOCOLS,
++ NLBL_MGMT_C_VERSION,
++ __NLBL_MGMT_C_MAX,
++};
++#define NLBL_MGMT_C_MAX (__NLBL_MGMT_C_MAX - 1)
++
++/* NetLabel Management attributes */
++enum {
++ NLBL_MGMT_A_UNSPEC,
++ NLBL_MGMT_A_DOMAIN,
++ /* (NLA_NUL_STRING)
++ * the NULL terminated LSM domain string */
++ NLBL_MGMT_A_PROTOCOL,
++ /* (NLA_U32)
++ * the NetLabel protocol type (defined by NETLBL_NLTYPE_*) */
++ NLBL_MGMT_A_VERSION,
++ /* (NLA_U32)
++ * the NetLabel protocol version number (defined by
++ * NETLBL_PROTO_VERSION) */
++ NLBL_MGMT_A_CV4DOI,
++ /* (NLA_U32)
++ * the CIPSOv4 DOI value */
++ __NLBL_MGMT_A_MAX,
++};
++#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
++
++/* NetLabel protocol functions */
++int netlbl_mgmt_genl_init(void);
++
++#endif
+diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
+new file mode 100644
+index 0000000..1833ad2
+--- /dev/null
++++ b/net/netlabel/netlabel_unlabeled.c
+@@ -0,0 +1,280 @@
++/*
++ * NetLabel Unlabeled Support
++ *
++ * This file defines functions for dealing with unlabeled packets for the
++ * NetLabel system. The NetLabel system manages static and dynamic label
++ * mappings for network protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/rcupdate.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/socket.h>
++#include <linux/string.h>
++#include <linux/skbuff.h>
++#include <net/sock.h>
++#include <net/netlink.h>
++#include <net/genetlink.h>
++
++#include <net/netlabel.h>
++#include <asm/bug.h>
++
++#include "netlabel_user.h"
++#include "netlabel_domainhash.h"
++#include "netlabel_unlabeled.h"
++
++/* Accept unlabeled packets flag */
++static atomic_t netlabel_unlabel_accept_flg = ATOMIC_INIT(0);
++
++/* NetLabel Generic NETLINK CIPSOv4 family */
++static struct genl_family netlbl_unlabel_gnl_family = {
++ .id = GENL_ID_GENERATE,
++ .hdrsize = 0,
++ .name = NETLBL_NLTYPE_UNLABELED_NAME,
++ .version = NETLBL_PROTO_VERSION,
++ .maxattr = NLBL_UNLABEL_A_MAX,
++};
++
++/* NetLabel Netlink attribute policy */
++static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
++ [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
++};
++
++/*
++ * Helper Functions
++ */
++
++/**
++ * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
++ * @value: desired value
++ * @audit_info: NetLabel audit information
++ *
++ * Description:
++ * Set the value of the unlabeled accept flag to @value.
++ *
++ */
++static void netlbl_unlabel_acceptflg_set(u8 value,
++ struct netlbl_audit *audit_info)
++{
++ struct audit_buffer *audit_buf;
++ u8 old_val;
++
++ old_val = atomic_read(&netlabel_unlabel_accept_flg);
++ atomic_set(&netlabel_unlabel_accept_flg, value);
++
++ audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
++ audit_info);
++ audit_log_format(audit_buf, " unlbl_accept=%u old=%u", value, old_val);
++ audit_log_end(audit_buf);
++}
++
++/*
++ * NetLabel Command Handlers
++ */
++
++/**
++ * netlbl_unlabel_accept - Handle an ACCEPT message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated ACCEPT message and set the accept flag accordingly.
++ * Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
++{
++ u8 value;
++ struct netlbl_audit audit_info;
++
++ if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
++ value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
++ if (value == 1 || value == 0) {
++ netlbl_netlink_auditinfo(skb, &audit_info);
++ netlbl_unlabel_acceptflg_set(value, &audit_info);
++ return 0;
++ }
++ }
++
++ return -EINVAL;
++}
++
++/**
++ * netlbl_unlabel_list - Handle a LIST message
++ * @skb: the NETLINK buffer
++ * @info: the Generic NETLINK info block
++ *
++ * Description:
++ * Process a user generated LIST message and respond with the current status.
++ * Returns zero on success, negative values on failure.
++ *
++ */
++static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
++{
++ int ret_val = -EINVAL;
++ struct sk_buff *ans_skb;
++ void *data;
++
++ ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (ans_skb == NULL)
++ goto list_failure;
++ data = netlbl_netlink_hdr_put(ans_skb,
++ info->snd_pid,
++ info->snd_seq,
++ netlbl_unlabel_gnl_family.id,
++ 0,
++ NLBL_UNLABEL_C_LIST);
++ if (data == NULL) {
++ ret_val = -ENOMEM;
++ goto list_failure;
++ }
++
++ ret_val = nla_put_u8(ans_skb,
++ NLBL_UNLABEL_A_ACPTFLG,
++ atomic_read(&netlabel_unlabel_accept_flg));
++ if (ret_val != 0)
++ goto list_failure;
++
++ genlmsg_end(ans_skb, data);
++
++ ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
++ if (ret_val != 0)
++ goto list_failure;
++ return 0;
++
++list_failure:
++ kfree(ans_skb);
++ return ret_val;
++}
++
++
++/*
++ * NetLabel Generic NETLINK Command Definitions
++ */
++
++static struct genl_ops netlbl_unlabel_genl_c_accept = {
++ .cmd = NLBL_UNLABEL_C_ACCEPT,
++ .flags = GENL_ADMIN_PERM,
++ .policy = netlbl_unlabel_genl_policy,
++ .doit = netlbl_unlabel_accept,
++ .dumpit = NULL,
++};
++
++static struct genl_ops netlbl_unlabel_genl_c_list = {
++ .cmd = NLBL_UNLABEL_C_LIST,
++ .flags = 0,
++ .policy = netlbl_unlabel_genl_policy,
++ .doit = netlbl_unlabel_list,
++ .dumpit = NULL,
++};
++
++
++/*
++ * NetLabel Generic NETLINK Protocol Functions
++ */
++
++/**
++ * netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component
++ *
++ * Description:
++ * Register the unlabeled packet NetLabel component with the Generic NETLINK
++ * mechanism. Returns zero on success, negative values on failure.
++ *
++ */
++int netlbl_unlabel_genl_init(void)
++{
++ int ret_val;
++
++ ret_val = genl_register_family(&netlbl_unlabel_gnl_family);
++ if (ret_val != 0)
++ return ret_val;
++
++ ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
++ &netlbl_unlabel_genl_c_accept);
++ if (ret_val != 0)
++ return ret_val;
++
++ ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
++ &netlbl_unlabel_genl_c_list);
++ if (ret_val != 0)
++ return ret_val;
++
++ return 0;
++}
++
++/*
++ * NetLabel KAPI Hooks
++ */
++
++/**
++ * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
++ * @secattr: the security attributes
++ *
++ * Description:
++ * Determine the security attributes, if any, for an unlabled packet and return
++ * them in @secattr. Returns zero on success and negative values on failure.
++ *
++ */
++int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr)
++{
++ if (atomic_read(&netlabel_unlabel_accept_flg) == 1)
++ return netlbl_secattr_init(secattr);
++
++ return -ENOMSG;
++}
++
++/**
++ * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
++ *
++ * Description:
++ * Set the default NetLabel configuration to allow incoming unlabeled packets
++ * and to send unlabeled network traffic by default.
++ *
++ */
++int netlbl_unlabel_defconf(void)
++{
++ int ret_val;
++ struct netlbl_dom_map *entry;
++ struct netlbl_audit audit_info;
++
++ /* Only the kernel is allowed to call this function and the only time
++ * it is called is at bootup before the audit subsystem is reporting
++ * messages so don't worry to much about these values. */
++ security_task_getsecid(current, &audit_info.secid);
++ audit_info.loginuid = 0;
++
++ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++ if (entry == NULL)
++ return -ENOMEM;
++ entry->type = NETLBL_NLTYPE_UNLABELED;
++ ret_val = netlbl_domhsh_add_default(entry, &audit_info);
++ if (ret_val != 0)
++ return ret_val;
++
++ netlbl_unlabel_acceptflg_set(1, &audit_info);
++
++ return 0;
++}
+diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h
+new file mode 100644
+index 0000000..c2917fb
+--- /dev/null
++++ b/net/netlabel/netlabel_unlabeled.h
+@@ -0,0 +1,89 @@
++/*
++ * NetLabel Unlabeled Support
++ *
++ * This file defines functions for dealing with unlabeled packets for the
++ * NetLabel system. The NetLabel system manages static and dynamic label
++ * mappings for network protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _NETLABEL_UNLABELED_H
++#define _NETLABEL_UNLABELED_H
++
++#include <net/netlabel.h>
++
++/*
++ * The following NetLabel payloads are supported by the Unlabeled subsystem.
++ *
++ * o ACCEPT
++ * This message is sent from an application to specify if the kernel should
++ * allow unlabled packets to pass if they do not match any of the static
++ * mappings defined in the unlabeled module.
++ *
++ * Required attributes:
++ *
++ * NLBL_UNLABEL_A_ACPTFLG
++ *
++ * o LIST
++ * This message can be sent either from an application or by the kernel in
++ * response to an application generated LIST message. When sent by an
++ * application there is no payload. The kernel should respond to a LIST
++ * message with a LIST message on success.
++ *
++ * Required attributes:
++ *
++ * NLBL_UNLABEL_A_ACPTFLG
++ *
++ */
++
++/* NetLabel Unlabeled commands */
++enum {
++ NLBL_UNLABEL_C_UNSPEC,
++ NLBL_UNLABEL_C_ACCEPT,
++ NLBL_UNLABEL_C_LIST,
++ __NLBL_UNLABEL_C_MAX,
++};
++#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
++
++/* NetLabel Unlabeled attributes */
++enum {
++ NLBL_UNLABEL_A_UNSPEC,
++ NLBL_UNLABEL_A_ACPTFLG,
++ /* (NLA_U8)
++ * if true then unlabeled packets are allowed to pass, else unlabeled
++ * packets are rejected */
++ __NLBL_UNLABEL_A_MAX,
++};
++#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
++
++/* NetLabel protocol functions */
++int netlbl_unlabel_genl_init(void);
++
++/* Process Unlabeled incoming network packets */
++int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr);
++
++/* Set the default configuration to allow Unlabeled packets */
++int netlbl_unlabel_defconf(void);
++
++#endif
+diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
+new file mode 100644
+index 0000000..98a4163
+--- /dev/null
++++ b/net/netlabel/netlabel_user.c
+@@ -0,0 +1,117 @@
++/*
++ * NetLabel NETLINK Interface
++ *
++ * This file defines the NETLINK interface for the NetLabel system. The
++ * NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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/init.h>
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/socket.h>
++#include <linux/audit.h>
++#include <linux/tty.h>
++#include <linux/security.h>
++#include <net/sock.h>
++#include <net/netlink.h>
++#include <net/genetlink.h>
++#include <net/netlabel.h>
++#include <asm/bug.h>
++
++#include "netlabel_mgmt.h"
++#include "netlabel_unlabeled.h"
++#include "netlabel_cipso_v4.h"
++#include "netlabel_user.h"
++
++/*
++ * NetLabel NETLINK Setup Functions
++ */
++
++/**
++ * netlbl_netlink_init - Initialize the NETLINK communication channel
++ *
++ * Description:
++ * Call out to the NetLabel components so they can register their families and
++ * commands with the Generic NETLINK mechanism. Returns zero on success and
++ * non-zero on failure.
++ *
++ */
++int netlbl_netlink_init(void)
++{
++ int ret_val;
++
++ ret_val = netlbl_mgmt_genl_init();
++ if (ret_val != 0)
++ return ret_val;
++
++ ret_val = netlbl_cipsov4_genl_init();
++ if (ret_val != 0)
++ return ret_val;
++
++ ret_val = netlbl_unlabel_genl_init();
++ if (ret_val != 0)
++ return ret_val;
++
++ return 0;
++}
++
++/*
++ * NetLabel Audit Functions
++ */
++
++/**
++ * netlbl_audit_start_common - Start an audit message
++ * @type: audit message type
++ * @audit_info: NetLabel audit information
++ *
++ * Description:
++ * Start an audit message using the type specified in @type and fill the audit
++ * message with some fields common to all NetLabel audit messages. Returns
++ * a pointer to the audit buffer on success, NULL on failure.
++ *
++ */
++struct audit_buffer *netlbl_audit_start_common(int type,
++ struct netlbl_audit *audit_info)
++{
++ struct audit_context *audit_ctx = current->audit_context;
++ struct audit_buffer *audit_buf;
++ char *secctx;
++ u32 secctx_len;
++
++ audit_buf = audit_log_start(audit_ctx, GFP_ATOMIC, type);
++ if (audit_buf == NULL)
++ return NULL;
++
++ audit_log_format(audit_buf, "netlabel: auid=%u", audit_info->loginuid);
++
++ if (audit_info->secid != 0 &&
++ security_secid_to_secctx(audit_info->secid,
++ &secctx,
++ &secctx_len) == 0)
++ audit_log_format(audit_buf, " subj=%s", secctx);
++
++ return audit_buf;
++}
+diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
+new file mode 100644
+index 0000000..47967ef
+--- /dev/null
++++ b/net/netlabel/netlabel_user.h
+@@ -0,0 +1,96 @@
++/*
++ * NetLabel NETLINK Interface
++ *
++ * This file defines the NETLINK interface for the NetLabel system. The
++ * NetLabel system manages static and dynamic label mappings for network
++ * protocols such as CIPSO and RIPSO.
++ *
++ * Author: Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _NETLABEL_USER_H
++#define _NETLABEL_USER_H
++
++#include <linux/types.h>
++#include <linux/skbuff.h>
++#include <linux/capability.h>
++#include <linux/audit.h>
++#include <net/netlink.h>
++#include <net/genetlink.h>
++#include <net/netlabel.h>
++
++/* NetLabel NETLINK helper functions */
++
++/**
++ * netlbl_netlink_hdr_put - Write the NETLINK buffers into a sk_buff
++ * @skb: the packet
++ * @pid: the PID of the receipient
++ * @seq: the sequence number
++ * @type: the generic NETLINK message family type
++ * @cmd: command
++ *
++ * Description:
++ * Write both a NETLINK nlmsghdr structure and a Generic NETLINK genlmsghdr
++ * struct to the packet. Returns a pointer to the start of the payload buffer
++ * on success or NULL on failure.
++ *
++ */
++static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb,
++ u32 pid,
++ u32 seq,
++ int type,
++ int flags,
++ u8 cmd)
++{
++ return genlmsg_put(skb,
++ pid,
++ seq,
++ type,
++ 0,
++ flags,
++ cmd,
++ NETLBL_PROTO_VERSION);
++}
++
++/**
++ * netlbl_netlink_auditinfo - Fetch the audit information from a NETLINK msg
++ * @skb: the packet
++ * @audit_info: NetLabel audit information
++ */
++static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
++ struct netlbl_audit *audit_info)
++{
++ audit_info->secid = NETLINK_CB(skb).sid;
++ audit_info->loginuid = NETLINK_CB(skb).loginuid;
++}
++
++/* NetLabel NETLINK I/O functions */
++
++int netlbl_netlink_init(void);
++
++/* NetLabel Audit Functions */
++
++struct audit_buffer *netlbl_audit_start_common(int type,
++ struct netlbl_audit *audit_info);
++
++#endif
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 8b85036..d527c89 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1075,8 +1075,9 @@ static int netlink_getsockopt(struct soc
+ return -EINVAL;
+ len = sizeof(int);
+ val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0;
+- put_user(len, optlen);
+- put_user(val, optval);
++ if (put_user(len, optlen) ||
++ put_user(val, optval))
++ return -EFAULT;
+ err = 0;
+ break;
+ default:
+@@ -1147,7 +1148,7 @@ static int netlink_sendmsg(struct kiocb
+ if (len > sk->sk_sndbuf - 32)
+ goto out;
+ err = -ENOBUFS;
+- skb = alloc_skb(len, GFP_KERNEL);
++ skb = nlmsg_new(len, GFP_KERNEL);
+ if (skb==NULL)
+ goto out;
+
+@@ -1341,19 +1342,18 @@ static int netlink_dump(struct sock *sk)
+ struct netlink_callback *cb;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+- int len;
++ int len, err = -ENOBUFS;
+
+ skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL);
+ if (!skb)
+- return -ENOBUFS;
++ goto errout;
+
+ spin_lock(&nlk->cb_lock);
+
+ cb = nlk->cb;
+ if (cb == NULL) {
+- spin_unlock(&nlk->cb_lock);
+- kfree_skb(skb);
+- return -EINVAL;
++ err = -EINVAL;
++ goto errout_skb;
+ }
+
+ len = cb->dump(skb, cb);
+@@ -1365,8 +1365,12 @@ static int netlink_dump(struct sock *sk)
+ return 0;
+ }
+
+- nlh = NLMSG_NEW_ANSWER(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI);
+- memcpy(NLMSG_DATA(nlh), &len, sizeof(len));
++ nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI);
++ if (!nlh)
++ goto errout_skb;
++
++ memcpy(nlmsg_data(nlh), &len, sizeof(len));
++
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk, skb->len);
+
+@@ -1378,8 +1382,11 @@ static int netlink_dump(struct sock *sk)
+ netlink_destroy_callback(cb);
+ return 0;
+
+-nlmsg_failure:
+- return -ENOBUFS;
++errout_skb:
++ spin_unlock(&nlk->cb_lock);
++ kfree_skb(skb);
++errout:
++ return err;
+ }
+
+ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+@@ -1431,11 +1438,11 @@ void netlink_ack(struct sk_buff *in_skb,
+ int size;
+
+ if (err == 0)
+- size = NLMSG_SPACE(sizeof(struct nlmsgerr));
++ size = nlmsg_total_size(sizeof(*errmsg));
+ else
+- size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len));
++ size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh));
+
+- skb = alloc_skb(size, GFP_KERNEL);
++ skb = nlmsg_new(size, GFP_KERNEL);
+ if (!skb) {
+ struct sock *sk;
+
+@@ -1451,16 +1458,15 @@ void netlink_ack(struct sk_buff *in_skb,
+
+ rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
+ NLMSG_ERROR, sizeof(struct nlmsgerr), 0);
+- errmsg = NLMSG_DATA(rep);
++ errmsg = nlmsg_data(rep);
+ errmsg->error = err;
+- memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr));
++ memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh));
+ netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+ }
+
+ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
+ struct nlmsghdr *, int *))
+ {
+- unsigned int total_len;
+ struct nlmsghdr *nlh;
+ int err;
+
+@@ -1470,8 +1476,6 @@ static int netlink_rcv_skb(struct sk_buf
+ if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
+ return 0;
+
+- total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len);
+-
+ if (cb(skb, nlh, &err) < 0) {
+ /* Not an error, but we have to interrupt processing
+ * here. Note: that in this case we do not pull
+@@ -1483,7 +1487,7 @@ static int netlink_rcv_skb(struct sk_buf
+ } else if (nlh->nlmsg_flags & NLM_F_ACK)
+ netlink_ack(skb, nlh, 0);
+
+- skb_pull(skb, total_len);
++ netlink_queue_skip(nlh, skb);
+ }
+
+ return 0;
+@@ -1546,6 +1550,38 @@ void netlink_queue_skip(struct nlmsghdr
+ skb_pull(skb, msglen);
+ }
+
++/**
++ * nlmsg_notify - send a notification netlink message
++ * @sk: netlink socket to use
++ * @skb: notification message
++ * @pid: destination netlink pid for reports or 0
++ * @group: destination multicast group or 0
++ * @report: 1 to report back, 0 to disable
++ * @flags: allocation flags
++ */
++int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
++ unsigned int group, int report, gfp_t flags)
++{
++ int err = 0;
++
++ if (group) {
++ int exclude_pid = 0;
++
++ if (report) {
++ atomic_inc(&skb->users);
++ exclude_pid = pid;
++ }
++
++ /* errors reported via destination sk->sk_err */
++ nlmsg_multicast(sk, skb, exclude_pid, group, flags);
++ }
++
++ if (report)
++ err = nlmsg_unicast(sk, skb, pid);
++
++ return err;
++}
++
+ #ifdef CONFIG_PROC_FS
+ struct nl_seq_iter {
+ int link;
+@@ -1727,8 +1763,6 @@ static struct net_proto_family netlink_f
+ .owner = THIS_MODULE, /* for consistency 8) */
+ };
+
+-extern void netlink_skb_parms_too_large(void);
+-
+ static int __init netlink_proto_init(void)
+ {
+ struct sk_buff *dummy_skb;
+@@ -1740,8 +1774,7 @@ static int __init netlink_proto_init(voi
+ if (err != 0)
+ goto out;
+
+- if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb))
+- netlink_skb_parms_too_large();
++ BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb));
+
+ nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);
+ if (!nl_table)
+@@ -1799,4 +1832,4 @@ EXPORT_SYMBOL(netlink_set_err);
+ EXPORT_SYMBOL(netlink_set_nonroot);
+ EXPORT_SYMBOL(netlink_unicast);
+ EXPORT_SYMBOL(netlink_unregister_notifier);
+-
++EXPORT_SYMBOL(nlmsg_notify);
+diff --git a/net/netlink/attr.c b/net/netlink/attr.c
+index dddbd15..0041395 100644
+--- a/net/netlink/attr.c
++++ b/net/netlink/attr.c
+@@ -20,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+
+ [NLA_U16] = sizeof(u16),
+ [NLA_U32] = sizeof(u32),
+ [NLA_U64] = sizeof(u64),
+- [NLA_STRING] = 1,
+ [NLA_NESTED] = NLA_HDRLEN,
+ };
+
+@@ -28,7 +27,7 @@ static int validate_nla(struct nlattr *n
+ struct nla_policy *policy)
+ {
+ struct nla_policy *pt;
+- int minlen = 0;
++ int minlen = 0, attrlen = nla_len(nla);
+
+ if (nla->nla_type <= 0 || nla->nla_type > maxtype)
+ return 0;
+@@ -37,16 +36,46 @@ static int validate_nla(struct nlattr *n
+
+ BUG_ON(pt->type > NLA_TYPE_MAX);
+
+- if (pt->minlen)
+- minlen = pt->minlen;
+- else if (pt->type != NLA_UNSPEC)
+- minlen = nla_attr_minlen[pt->type];
++ switch (pt->type) {
++ case NLA_FLAG:
++ if (attrlen > 0)
++ return -ERANGE;
++ break;
+
+- if (pt->type == NLA_FLAG && nla_len(nla) > 0)
+- return -ERANGE;
++ case NLA_NUL_STRING:
++ if (pt->len)
++ minlen = min_t(int, attrlen, pt->len + 1);
++ else
++ minlen = attrlen;
+
+- if (nla_len(nla) < minlen)
+- return -ERANGE;
++ if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
++ return -EINVAL;
++ /* fall through */
++
++ case NLA_STRING:
++ if (attrlen < 1)
++ return -ERANGE;
++
++ if (pt->len) {
++ char *buf = nla_data(nla);
++
++ if (buf[attrlen - 1] == '\0')
++ attrlen--;
++
++ if (attrlen > pt->len)
++ return -ERANGE;
++ }
++ break;
++
++ default:
++ if (pt->len)
++ minlen = pt->len;
++ else if (pt->type != NLA_UNSPEC)
++ minlen = nla_attr_minlen[pt->type];
++
++ if (attrlen < minlen)
++ return -ERANGE;
++ }
+
+ return 0;
+ }
+@@ -255,6 +284,26 @@ struct nlattr *__nla_reserve(struct sk_b
+ }
+
+ /**
++ * __nla_reserve_nohdr - reserve room for attribute without header
++ * @skb: socket buffer to reserve room on
++ * @attrlen: length of attribute payload
++ *
++ * Reserves room for attribute payload without a header.
++ *
++ * The caller is responsible to ensure that the skb provides enough
++ * tailroom for the payload.
++ */
++void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
++{
++ void *start;
++
++ start = skb_put(skb, NLA_ALIGN(attrlen));
++ memset(start, 0, NLA_ALIGN(attrlen));
++
++ return start;
++}
++
++/**
+ * nla_reserve - reserve room for attribute on the skb
+ * @skb: socket buffer to reserve room on
+ * @attrtype: attribute type
+@@ -275,6 +324,24 @@ struct nlattr *nla_reserve(struct sk_buf
+ }
+
+ /**
++ * nla_reserve - reserve room for attribute without header
++ * @skb: socket buffer to reserve room on
++ * @len: length of attribute payload
++ *
++ * Reserves room for attribute payload without a header.
++ *
++ * Returns NULL if the tailroom of the skb is insufficient to store
++ * the attribute payload.
++ */
++void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
++{
++ if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
++ return NULL;
++
++ return __nla_reserve_nohdr(skb, attrlen);
++}
++
++/**
+ * __nla_put - Add a netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+@@ -293,6 +360,22 @@ void __nla_put(struct sk_buff *skb, int
+ memcpy(nla_data(nla), data, attrlen);
+ }
+
++/**
++ * __nla_put_nohdr - Add a netlink attribute without header
++ * @skb: socket buffer to add attribute to
++ * @attrlen: length of attribute payload
++ * @data: head of attribute payload
++ *
++ * The caller is responsible to ensure that the skb provides enough
++ * tailroom for the attribute payload.
++ */
++void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
++{
++ void *start;
++
++ start = __nla_reserve_nohdr(skb, attrlen);
++ memcpy(start, data, attrlen);
++}
+
+ /**
+ * nla_put - Add a netlink attribute to a socket buffer
+@@ -313,15 +396,36 @@ int nla_put(struct sk_buff *skb, int att
+ return 0;
+ }
+
++/**
++ * nla_put_nohdr - Add a netlink attribute without header
++ * @skb: socket buffer to add attribute to
++ * @attrlen: length of attribute payload
++ * @data: head of attribute payload
++ *
++ * Returns -1 if the tailroom of the skb is insufficient to store
++ * the attribute payload.
++ */
++int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
++{
++ if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
++ return -1;
++
++ __nla_put_nohdr(skb, attrlen, data);
++ return 0;
++}
+
+ EXPORT_SYMBOL(nla_validate);
+ EXPORT_SYMBOL(nla_parse);
+ EXPORT_SYMBOL(nla_find);
+ EXPORT_SYMBOL(nla_strlcpy);
+ EXPORT_SYMBOL(__nla_reserve);
++EXPORT_SYMBOL(__nla_reserve_nohdr);
+ EXPORT_SYMBOL(nla_reserve);
++EXPORT_SYMBOL(nla_reserve_nohdr);
+ EXPORT_SYMBOL(__nla_put);
++EXPORT_SYMBOL(__nla_put_nohdr);
+ EXPORT_SYMBOL(nla_put);
++EXPORT_SYMBOL(nla_put_nohdr);
+ EXPORT_SYMBOL(nla_memcpy);
+ EXPORT_SYMBOL(nla_memcmp);
+ EXPORT_SYMBOL(nla_strcmp);
+diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
+index a298f77..49bc2db 100644
+--- a/net/netlink/genetlink.c
++++ b/net/netlink/genetlink.c
+@@ -387,7 +387,10 @@ static void genl_rcv(struct sock *sk, in
+ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
+ u32 flags, struct sk_buff *skb, u8 cmd)
+ {
++ struct nlattr *nla_ops;
++ struct genl_ops *ops;
+ void *hdr;
++ int idx = 1;
+
+ hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd,
+ family->version);
+@@ -396,6 +399,37 @@ static int ctrl_fill_info(struct genl_fa
+
+ NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
+ NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
++ NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version);
++ NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize);
++ NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr);
++
++ nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
++ if (nla_ops == NULL)
++ goto nla_put_failure;
++
++ list_for_each_entry(ops, &family->ops_list, ops_list) {
++ struct nlattr *nest;
++
++ nest = nla_nest_start(skb, idx++);
++ if (nest == NULL)
++ goto nla_put_failure;
++
++ NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd);
++ NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags);
++
++ if (ops->policy)
++ NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY);
++
++ if (ops->doit)
++ NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT);
++
++ if (ops->dumpit)
++ NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT);
++
++ nla_nest_end(skb, nest);
++ }
++
++ nla_nest_end(skb, nla_ops);
+
+ return genlmsg_end(skb, hdr);
+
+@@ -411,6 +445,9 @@ static int ctrl_dumpfamily(struct sk_buf
+ int chains_to_skip = cb->args[0];
+ int fams_to_skip = cb->args[1];
+
++ if (chains_to_skip != 0)
++ genl_lock();
++
+ for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
+ if (i < chains_to_skip)
+ continue;
+@@ -428,6 +465,9 @@ static int ctrl_dumpfamily(struct sk_buf
+ }
+
+ errout:
++ if (chains_to_skip != 0)
++ genl_unlock();
++
+ cb->args[0] = i;
+ cb->args[1] = n;
+
+@@ -440,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(st
+ struct sk_buff *skb;
+ int err;
+
+- skb = nlmsg_new(NLMSG_GOODSIZE);
++ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (skb == NULL)
+ return ERR_PTR(-ENOBUFS);
+
+@@ -455,7 +495,8 @@ static struct sk_buff *ctrl_build_msg(st
+
+ static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = {
+ [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
+- [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING },
++ [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
++ .len = GENL_NAMSIZ - 1 },
+ };
+
+ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
+@@ -470,12 +511,9 @@ static int ctrl_getfamily(struct sk_buff
+ }
+
+ if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
+- char name[GENL_NAMSIZ];
+-
+- if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME],
+- GENL_NAMSIZ) >= GENL_NAMSIZ)
+- goto errout;
++ char *name;
+
++ name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
+ res = genl_family_find_byname(name);
+ }
+
+@@ -510,7 +548,7 @@ static int genl_ctrl_event(int event, vo
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+- genlmsg_multicast(msg, 0, GENL_ID_CTRL);
++ genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+ break;
+ }
+
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index 4172a52..f4ccb90 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -427,21 +427,24 @@ out_unlock:
+ }
+ #endif
+
+-static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned res)
++static inline int run_filter(struct sk_buff *skb, struct sock *sk,
++ unsigned *snaplen)
+ {
+ struct sk_filter *filter;
++ int err = 0;
+
+- bh_lock_sock(sk);
+- filter = sk->sk_filter;
+- /*
+- * Our caller already checked that filter != NULL but we need to
+- * verify that under bh_lock_sock() to be safe
+- */
+- if (likely(filter != NULL))
+- res = sk_run_filter(skb, filter->insns, filter->len);
+- bh_unlock_sock(sk);
++ rcu_read_lock_bh();
++ filter = rcu_dereference(sk->sk_filter);
++ if (filter != NULL) {
++ err = sk_run_filter(skb, filter->insns, filter->len);
++ if (!err)
++ err = -EPERM;
++ else if (*snaplen > err)
++ *snaplen = err;
++ }
++ rcu_read_unlock_bh();
+
+- return res;
++ return err;
+ }
+
+ /*
+@@ -491,13 +494,8 @@ static int packet_rcv(struct sk_buff *sk
+
+ snaplen = skb->len;
+
+- if (sk->sk_filter) {
+- unsigned res = run_filter(skb, sk, snaplen);
+- if (res == 0)
+- goto drop_n_restore;
+- if (snaplen > res)
+- snaplen = res;
+- }
++ if (run_filter(skb, sk, &snaplen) < 0)
++ goto drop_n_restore;
+
+ if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+ (unsigned)sk->sk_rcvbuf)
+@@ -586,20 +584,15 @@ static int tpacket_rcv(struct sk_buff *s
+ else if (skb->pkt_type == PACKET_OUTGOING) {
+ /* Special case: outgoing packets have ll header at head */
+ skb_pull(skb, skb->nh.raw - skb->data);
+- if (skb->ip_summed == CHECKSUM_HW)
++ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ status |= TP_STATUS_CSUMNOTREADY;
+ }
+ }
+
+ snaplen = skb->len;
+
+- if (sk->sk_filter) {
+- unsigned res = run_filter(skb, sk, snaplen);
+- if (res == 0)
+- goto drop_n_restore;
+- if (snaplen > res)
+- snaplen = res;
+- }
++ if (run_filter(skb, sk, &snaplen) < 0)
++ goto drop_n_restore;
+
+ if (sk->sk_type == SOCK_DGRAM) {
+ macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16;
+diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c
+index 465efc8..94b2e2f 100644
+--- a/net/rxrpc/transport.c
++++ b/net/rxrpc/transport.c
+@@ -381,11 +381,10 @@ static int rxrpc_incoming_msg(struct rxr
+
+ /* allocate a new message record */
+ ret = -ENOMEM;
+- msg = kmalloc(sizeof(struct rxrpc_message), GFP_KERNEL);
++ msg = kmemdup(jumbomsg, sizeof(struct rxrpc_message), GFP_KERNEL);
+ if (!msg)
+ goto error;
+
+- memcpy(msg, jumbomsg, sizeof(*msg));
+ list_add_tail(&msg->link, msgq);
+
+ /* adjust the jumbo packet */
+diff --git a/net/sched/act_api.c b/net/sched/act_api.c
+index a2587b5..835070e 100644
+--- a/net/sched/act_api.c
++++ b/net/sched/act_api.c
+@@ -33,16 +33,230 @@
+ #include <net/sch_generic.h>
+ #include <net/act_api.h>
+
+-#if 0 /* control */
+-#define DPRINTK(format, args...) printk(KERN_DEBUG format, ##args)
+-#else
+-#define DPRINTK(format, args...)
++void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
++{
++ unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
++ struct tcf_common **p1p;
++
++ for (p1p = &hinfo->htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) {
++ if (*p1p == p) {
++ write_lock_bh(hinfo->lock);
++ *p1p = p->tcfc_next;
++ write_unlock_bh(hinfo->lock);
++#ifdef CONFIG_NET_ESTIMATOR
++ gen_kill_estimator(&p->tcfc_bstats,
++ &p->tcfc_rate_est);
+ #endif
+-#if 0 /* data */
+-#define D2PRINTK(format, args...) printk(KERN_DEBUG format, ##args)
+-#else
+-#define D2PRINTK(format, args...)
++ kfree(p);
++ return;
++ }
++ }
++ BUG_TRAP(0);
++}
++EXPORT_SYMBOL(tcf_hash_destroy);
++
++int tcf_hash_release(struct tcf_common *p, int bind,
++ struct tcf_hashinfo *hinfo)
++{
++ int ret = 0;
++
++ if (p) {
++ if (bind)
++ p->tcfc_bindcnt--;
++
++ p->tcfc_refcnt--;
++ if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
++ tcf_hash_destroy(p, hinfo);
++ ret = 1;
++ }
++ }
++ return ret;
++}
++EXPORT_SYMBOL(tcf_hash_release);
++
++static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
++ struct tc_action *a, struct tcf_hashinfo *hinfo)
++{
++ struct tcf_common *p;
++ int err = 0, index = -1,i = 0, s_i = 0, n_i = 0;
++ struct rtattr *r ;
++
++ read_lock(hinfo->lock);
++
++ s_i = cb->args[0];
++
++ for (i = 0; i < (hinfo->hmask + 1); i++) {
++ p = hinfo->htab[tcf_hash(i, hinfo->hmask)];
++
++ for (; p; p = p->tcfc_next) {
++ index++;
++ if (index < s_i)
++ continue;
++ a->priv = p;
++ a->order = n_i;
++ r = (struct rtattr*) skb->tail;
++ RTA_PUT(skb, a->order, 0, NULL);
++ err = tcf_action_dump_1(skb, a, 0, 0);
++ if (err < 0) {
++ index--;
++ skb_trim(skb, (u8*)r - skb->data);
++ goto done;
++ }
++ r->rta_len = skb->tail - (u8*)r;
++ n_i++;
++ if (n_i >= TCA_ACT_MAX_PRIO)
++ goto done;
++ }
++ }
++done:
++ read_unlock(hinfo->lock);
++ if (n_i)
++ cb->args[0] += n_i;
++ return n_i;
++
++rtattr_failure:
++ skb_trim(skb, (u8*)r - skb->data);
++ goto done;
++}
++
++static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
++ struct tcf_hashinfo *hinfo)
++{
++ struct tcf_common *p, *s_p;
++ struct rtattr *r ;
++ int i= 0, n_i = 0;
++
++ r = (struct rtattr*) skb->tail;
++ RTA_PUT(skb, a->order, 0, NULL);
++ RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind);
++ for (i = 0; i < (hinfo->hmask + 1); i++) {
++ p = hinfo->htab[tcf_hash(i, hinfo->hmask)];
++
++ while (p != NULL) {
++ s_p = p->tcfc_next;
++ if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo))
++ module_put(a->ops->owner);
++ n_i++;
++ p = s_p;
++ }
++ }
++ RTA_PUT(skb, TCA_FCNT, 4, &n_i);
++ r->rta_len = skb->tail - (u8*)r;
++
++ return n_i;
++rtattr_failure:
++ skb_trim(skb, (u8*)r - skb->data);
++ return -EINVAL;
++}
++
++int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
++ int type, struct tc_action *a)
++{
++ struct tcf_hashinfo *hinfo = a->ops->hinfo;
++
++ if (type == RTM_DELACTION) {
++ return tcf_del_walker(skb, a, hinfo);
++ } else if (type == RTM_GETACTION) {
++ return tcf_dump_walker(skb, cb, a, hinfo);
++ } else {
++ printk("tcf_generic_walker: unknown action %d\n", type);
++ return -EINVAL;
++ }
++}
++EXPORT_SYMBOL(tcf_generic_walker);
++
++struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
++{
++ struct tcf_common *p;
++
++ read_lock(hinfo->lock);
++ for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
++ p = p->tcfc_next) {
++ if (p->tcfc_index == index)
++ break;
++ }
++ read_unlock(hinfo->lock);
++
++ return p;
++}
++EXPORT_SYMBOL(tcf_hash_lookup);
++
++u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo)
++{
++ u32 val = *idx_gen;
++
++ do {
++ if (++val == 0)
++ val = 1;
++ } while (tcf_hash_lookup(val, hinfo));
++
++ return (*idx_gen = val);
++}
++EXPORT_SYMBOL(tcf_hash_new_index);
++
++int tcf_hash_search(struct tc_action *a, u32 index)
++{
++ struct tcf_hashinfo *hinfo = a->ops->hinfo;
++ struct tcf_common *p = tcf_hash_lookup(index, hinfo);
++
++ if (p) {
++ a->priv = p;
++ return 1;
++ }
++ return 0;
++}
++EXPORT_SYMBOL(tcf_hash_search);
++
++struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind,
++ struct tcf_hashinfo *hinfo)
++{
++ struct tcf_common *p = NULL;
++ if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
++ if (bind) {
++ p->tcfc_bindcnt++;
++ p->tcfc_refcnt++;
++ }
++ a->priv = p;
++ }
++ return p;
++}
++EXPORT_SYMBOL(tcf_hash_check);
++
++struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo)
++{
++ struct tcf_common *p = kzalloc(size, GFP_KERNEL);
++
++ if (unlikely(!p))
++ return p;
++ p->tcfc_refcnt = 1;
++ if (bind)
++ p->tcfc_bindcnt = 1;
++
++ spin_lock_init(&p->tcfc_lock);
++ p->tcfc_stats_lock = &p->tcfc_lock;
++ p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
++ p->tcfc_tm.install = jiffies;
++ p->tcfc_tm.lastuse = jiffies;
++#ifdef CONFIG_NET_ESTIMATOR
++ if (est)
++ gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
++ p->tcfc_stats_lock, est);
+ #endif
++ a->priv = (void *) p;
++ return p;
++}
++EXPORT_SYMBOL(tcf_hash_create);
++
++void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo)
++{
++ unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
++
++ write_lock_bh(hinfo->lock);
++ p->tcfc_next = hinfo->htab[h];
++ hinfo->htab[h] = p;
++ write_unlock_bh(hinfo->lock);
++}
++EXPORT_SYMBOL(tcf_hash_insert);
+
+ static struct tc_action_ops *act_base = NULL;
+ static DEFINE_RWLOCK(act_mod_lock);
+@@ -155,9 +369,6 @@ int tcf_action_exec(struct sk_buff *skb,
+
+ if (skb->tc_verd & TC_NCLS) {
+ skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
+- D2PRINTK("(%p)tcf_action_exec: cleared TC_NCLS in %s out %s\n",
+- skb, skb->input_dev ? skb->input_dev->name : "xxx",
+- skb->dev->name);
+ ret = TC_ACT_OK;
+ goto exec_done;
+ }
+@@ -187,8 +398,6 @@ void tcf_action_destroy(struct tc_action
+
+ for (a = act; a; a = act) {
+ if (a->ops && a->ops->cleanup) {
+- DPRINTK("tcf_action_destroy destroying %p next %p\n",
+- a, a->next);
+ if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
+ module_put(a->ops->owner);
+ act = act->next;
+@@ -331,7 +540,6 @@ struct tc_action *tcf_action_init_1(stru
+ if (*err != ACT_P_CREATED)
+ module_put(a_o->owner);
+ a->ops = a_o;
+- DPRINTK("tcf_action_init_1: successfull %s\n", act_name);
+
+ *err = 0;
+ return a;
+@@ -392,12 +600,12 @@ int tcf_action_copy_stats(struct sk_buff
+ if (compat_mode) {
+ if (a->type == TCA_OLD_COMPAT)
+ err = gnet_stats_start_copy_compat(skb, 0,
+- TCA_STATS, TCA_XSTATS, h->stats_lock, &d);
++ TCA_STATS, TCA_XSTATS, h->tcf_stats_lock, &d);
+ else
+ return 0;
+ } else
+ err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
+- h->stats_lock, &d);
++ h->tcf_stats_lock, &d);
+
+ if (err < 0)
+ goto errout;
+@@ -406,11 +614,11 @@ int tcf_action_copy_stats(struct sk_buff
+ if (a->ops->get_stats(skb, a) < 0)
+ goto errout;
+
+- if (gnet_stats_copy_basic(&d, &h->bstats) < 0 ||
++ if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
+ #ifdef CONFIG_NET_ESTIMATOR
+- gnet_stats_copy_rate_est(&d, &h->rate_est) < 0 ||
++ gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||
+ #endif
+- gnet_stats_copy_queue(&d, &h->qstats) < 0)
++ gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
+ goto errout;
+
+ if (gnet_stats_finish_copy(&d) < 0)
+@@ -459,7 +667,6 @@ static int
+ act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event)
+ {
+ struct sk_buff *skb;
+- int err = 0;
+
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!skb)
+@@ -468,10 +675,8 @@ act_get_notify(u32 pid, struct nlmsghdr
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+- err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
+- if (err > 0)
+- err = 0;
+- return err;
++
++ return rtnl_unicast(skb, pid);
+ }
+
+ static struct tc_action *
+diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
+index e75a147..6cff566 100644
+--- a/net/sched/act_gact.c
++++ b/net/sched/act_gact.c
+@@ -34,48 +34,43 @@
+ #include <linux/tc_act/tc_gact.h>
+ #include <net/tc_act/tc_gact.h>
+
+-/* use generic hash table */
+-#define MY_TAB_SIZE 16
+-#define MY_TAB_MASK 15
+-
+-static u32 idx_gen;
+-static struct tcf_gact *tcf_gact_ht[MY_TAB_SIZE];
++#define GACT_TAB_MASK 15
++static struct tcf_common *tcf_gact_ht[GACT_TAB_MASK + 1];
++static u32 gact_idx_gen;
+ static DEFINE_RWLOCK(gact_lock);
+
+-/* ovewrride the defaults */
+-#define tcf_st tcf_gact
+-#define tc_st tc_gact
+-#define tcf_t_lock gact_lock
+-#define tcf_ht tcf_gact_ht
+-
+-#define CONFIG_NET_ACT_INIT 1
+-#include <net/pkt_act.h>
++static struct tcf_hashinfo gact_hash_info = {
++ .htab = tcf_gact_ht,
++ .hmask = GACT_TAB_MASK,
++ .lock = &gact_lock,
++};
+
+ #ifdef CONFIG_GACT_PROB
+-static int gact_net_rand(struct tcf_gact *p)
++static int gact_net_rand(struct tcf_gact *gact)
+ {
+- if (net_random()%p->pval)
+- return p->action;
+- return p->paction;
++ if (net_random() % gact->tcfg_pval)
++ return gact->tcf_action;
++ return gact->tcfg_paction;
+ }
+
+-static int gact_determ(struct tcf_gact *p)
++static int gact_determ(struct tcf_gact *gact)
+ {
+- if (p->bstats.packets%p->pval)
+- return p->action;
+- return p->paction;
++ if (gact->tcf_bstats.packets % gact->tcfg_pval)
++ return gact->tcf_action;
++ return gact->tcfg_paction;
+ }
+
+-typedef int (*g_rand)(struct tcf_gact *p);
++typedef int (*g_rand)(struct tcf_gact *gact);
+ static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ };
+-#endif
++#endif /* CONFIG_GACT_PROB */
+
+ static int tcf_gact_init(struct rtattr *rta, struct rtattr *est,
+ struct tc_action *a, int ovr, int bind)
+ {
+ struct rtattr *tb[TCA_GACT_MAX];
+ struct tc_gact *parm;
+- struct tcf_gact *p;
++ struct tcf_gact *gact;
++ struct tcf_common *pc;
+ int ret = 0;
+
+ if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0)
+@@ -94,105 +89,106 @@ static int tcf_gact_init(struct rtattr *
+ return -EOPNOTSUPP;
+ #endif
+
+- p = tcf_hash_check(parm->index, a, ovr, bind);
+- if (p == NULL) {
+- p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
+- if (p == NULL)
++ pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
++ if (!pc) {
++ pc = tcf_hash_create(parm->index, est, a, sizeof(*gact),
++ bind, &gact_idx_gen, &gact_hash_info);
++ if (unlikely(!pc))
+ return -ENOMEM;
+ ret = ACT_P_CREATED;
+ } else {
+ if (!ovr) {
+- tcf_hash_release(p, bind);
++ tcf_hash_release(pc, bind, &gact_hash_info);
+ return -EEXIST;
+ }
+ }
+
+- spin_lock_bh(&p->lock);
+- p->action = parm->action;
++ gact = to_gact(pc);
++
++ spin_lock_bh(&gact->tcf_lock);
++ gact->tcf_action = parm->action;
+ #ifdef CONFIG_GACT_PROB
+ if (tb[TCA_GACT_PROB-1] != NULL) {
+ struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]);
+- p->paction = p_parm->paction;
+- p->pval = p_parm->pval;
+- p->ptype = p_parm->ptype;
++ gact->tcfg_paction = p_parm->paction;
++ gact->tcfg_pval = p_parm->pval;
++ gact->tcfg_ptype = p_parm->ptype;
+ }
+ #endif
+- spin_unlock_bh(&p->lock);
++ spin_unlock_bh(&gact->tcf_lock);
+ if (ret == ACT_P_CREATED)
+- tcf_hash_insert(p);
++ tcf_hash_insert(pc, &gact_hash_info);
+ return ret;
+ }
+
+-static int
+-tcf_gact_cleanup(struct tc_action *a, int bind)
++static int tcf_gact_cleanup(struct tc_action *a, int bind)
+ {
+- struct tcf_gact *p = PRIV(a, gact);
++ struct tcf_gact *gact = a->priv;
+
+- if (p != NULL)
+- return tcf_hash_release(p, bind);
++ if (gact)
++ return tcf_hash_release(&gact->common, bind, &gact_hash_info);
+ return 0;
+ }
+
+-static int
+-tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
++static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
+ {
+- struct tcf_gact *p = PRIV(a, gact);
++ struct tcf_gact *gact = a->priv;
+ int action = TC_ACT_SHOT;
+
+- spin_lock(&p->lock);
++ spin_lock(&gact->tcf_lock);
+ #ifdef CONFIG_GACT_PROB
+- if (p->ptype && gact_rand[p->ptype] != NULL)
+- action = gact_rand[p->ptype](p);
++ if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL)
++ action = gact_rand[gact->tcfg_ptype](gact);
+ else
+- action = p->action;
++ action = gact->tcf_action;
+ #else
+- action = p->action;
++ action = gact->tcf_action;
+ #endif
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
++ gact->tcf_bstats.bytes += skb->len;
++ gact->tcf_bstats.packets++;
+ if (action == TC_ACT_SHOT)
+- p->qstats.drops++;
+- p->tm.lastuse = jiffies;
+- spin_unlock(&p->lock);
++ gact->tcf_qstats.drops++;
++ gact->tcf_tm.lastuse = jiffies;
++ spin_unlock(&gact->tcf_lock);
+
+ return action;
+ }
+
+-static int
+-tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
++static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+ {
+ unsigned char *b = skb->tail;
+ struct tc_gact opt;
+- struct tcf_gact *p = PRIV(a, gact);
++ struct tcf_gact *gact = a->priv;
+ struct tcf_t t;
+
+- opt.index = p->index;
+- opt.refcnt = p->refcnt - ref;
+- opt.bindcnt = p->bindcnt - bind;
+- opt.action = p->action;
++ opt.index = gact->tcf_index;
++ opt.refcnt = gact->tcf_refcnt - ref;
++ opt.bindcnt = gact->tcf_bindcnt - bind;
++ opt.action = gact->tcf_action;
+ RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt);
+ #ifdef CONFIG_GACT_PROB
+- if (p->ptype) {
++ if (gact->tcfg_ptype) {
+ struct tc_gact_p p_opt;
+- p_opt.paction = p->paction;
+- p_opt.pval = p->pval;
+- p_opt.ptype = p->ptype;
++ p_opt.paction = gact->tcfg_paction;
++ p_opt.pval = gact->tcfg_pval;
++ p_opt.ptype = gact->tcfg_ptype;
+ RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt);
+ }
+ #endif
+- t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+- t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+- t.expires = jiffies_to_clock_t(p->tm.expires);
++ t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install);
++ t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse);
++ t.expires = jiffies_to_clock_t(gact->tcf_tm.expires);
+ RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t);
+ return skb->len;
+
+- rtattr_failure:
++rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+ }
+
+ static struct tc_action_ops act_gact_ops = {
+ .kind = "gact",
++ .hinfo = &gact_hash_info,
+ .type = TCA_ACT_GACT,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+@@ -208,8 +204,7 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"
+ MODULE_DESCRIPTION("Generic Classifier actions");
+ MODULE_LICENSE("GPL");
+
+-static int __init
+-gact_init_module(void)
++static int __init gact_init_module(void)
+ {
+ #ifdef CONFIG_GACT_PROB
+ printk("GACT probability on\n");
+@@ -219,8 +214,7 @@ gact_init_module(void)
+ return tcf_register_action(&act_gact_ops);
+ }
+
+-static void __exit
+-gact_cleanup_module(void)
++static void __exit gact_cleanup_module(void)
+ {
+ tcf_unregister_action(&act_gact_ops);
+ }
+diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
+index d799e01..d8c9310 100644
+--- a/net/sched/act_ipt.c
++++ b/net/sched/act_ipt.c
+@@ -38,25 +38,19 @@
+
+ #include <linux/netfilter_ipv4/ip_tables.h>
+
+-/* use generic hash table */
+-#define MY_TAB_SIZE 16
+-#define MY_TAB_MASK 15
+
+-static u32 idx_gen;
+-static struct tcf_ipt *tcf_ipt_ht[MY_TAB_SIZE];
+-/* ipt hash table lock */
++#define IPT_TAB_MASK 15
++static struct tcf_common *tcf_ipt_ht[IPT_TAB_MASK + 1];
++static u32 ipt_idx_gen;
+ static DEFINE_RWLOCK(ipt_lock);
+
+-/* ovewrride the defaults */
+-#define tcf_st tcf_ipt
+-#define tcf_t_lock ipt_lock
+-#define tcf_ht tcf_ipt_ht
+-
+-#define CONFIG_NET_ACT_INIT
+-#include <net/pkt_act.h>
++static struct tcf_hashinfo ipt_hash_info = {
++ .htab = tcf_ipt_ht,
++ .hmask = IPT_TAB_MASK,
++ .lock = &ipt_lock,
++};
+
+-static int
+-ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
++static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
+ {
+ struct ipt_target *target;
+ int ret = 0;
+@@ -65,7 +59,6 @@ ipt_init_target(struct ipt_entry_target
+ if (!target)
+ return -ENOENT;
+
+- DPRINTK("ipt_init_target: found %s\n", target->name);
+ t->u.kernel.target = target;
+
+ ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+@@ -76,10 +69,7 @@ ipt_init_target(struct ipt_entry_target
+ if (t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(table, NULL,
+ t->u.kernel.target, t->data,
+- t->u.target_size - sizeof(*t),
+ hook)) {
+- DPRINTK("ipt_init_target: check failed for `%s'.\n",
+- t->u.kernel.target->name);
+ module_put(t->u.kernel.target->me);
+ ret = -EINVAL;
+ }
+@@ -87,40 +77,37 @@ ipt_init_target(struct ipt_entry_target
+ return ret;
+ }
+
+-static void
+-ipt_destroy_target(struct ipt_entry_target *t)
++static void ipt_destroy_target(struct ipt_entry_target *t)
+ {
+ if (t->u.kernel.target->destroy)
+- t->u.kernel.target->destroy(t->u.kernel.target, t->data,
+- t->u.target_size - sizeof(*t));
++ t->u.kernel.target->destroy(t->u.kernel.target, t->data);
+ module_put(t->u.kernel.target->me);
+ }
+
+-static int
+-tcf_ipt_release(struct tcf_ipt *p, int bind)
++static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)
+ {
+ int ret = 0;
+- if (p) {
++ if (ipt) {
+ if (bind)
+- p->bindcnt--;
+- p->refcnt--;
+- if (p->bindcnt <= 0 && p->refcnt <= 0) {
+- ipt_destroy_target(p->t);
+- kfree(p->tname);
+- kfree(p->t);
+- tcf_hash_destroy(p);
++ ipt->tcf_bindcnt--;
++ ipt->tcf_refcnt--;
++ if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) {
++ ipt_destroy_target(ipt->tcfi_t);
++ kfree(ipt->tcfi_tname);
++ kfree(ipt->tcfi_t);
++ tcf_hash_destroy(&ipt->common, &ipt_hash_info);
+ ret = ACT_P_DELETED;
+ }
+ }
+ return ret;
+ }
+
+-static int
+-tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
+- int ovr, int bind)
++static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est,
++ struct tc_action *a, int ovr, int bind)
+ {
+ struct rtattr *tb[TCA_IPT_MAX];
+- struct tcf_ipt *p;
++ struct tcf_ipt *ipt;
++ struct tcf_common *pc;
+ struct ipt_entry_target *td, *t;
+ char *tname;
+ int ret = 0, err;
+@@ -144,49 +131,51 @@ tcf_ipt_init(struct rtattr *rta, struct
+ RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32))
+ index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]);
+
+- p = tcf_hash_check(index, a, ovr, bind);
+- if (p == NULL) {
+- p = tcf_hash_create(index, est, a, sizeof(*p), ovr, bind);
+- if (p == NULL)
++ pc = tcf_hash_check(index, a, bind, &ipt_hash_info);
++ if (!pc) {
++ pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
++ &ipt_idx_gen, &ipt_hash_info);
++ if (unlikely(!pc))
+ return -ENOMEM;
+ ret = ACT_P_CREATED;
+ } else {
+ if (!ovr) {
+- tcf_ipt_release(p, bind);
++ tcf_ipt_release(to_ipt(pc), bind);
+ return -EEXIST;
+ }
+ }
++ ipt = to_ipt(pc);
+
+ hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]);
+
+ err = -ENOMEM;
+ tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
+- if (tname == NULL)
++ if (unlikely(!tname))
+ goto err1;
+ if (tb[TCA_IPT_TABLE - 1] == NULL ||
+ rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ)
+ strcpy(tname, "mangle");
+
+ t = kmalloc(td->u.target_size, GFP_KERNEL);
+- if (t == NULL)
++ if (unlikely(!t))
+ goto err2;
+ memcpy(t, td, td->u.target_size);
+
+ if ((err = ipt_init_target(t, tname, hook)) < 0)
+ goto err3;
+
+- spin_lock_bh(&p->lock);
++ spin_lock_bh(&ipt->tcf_lock);
+ if (ret != ACT_P_CREATED) {
+- ipt_destroy_target(p->t);
+- kfree(p->tname);
+- kfree(p->t);
++ ipt_destroy_target(ipt->tcfi_t);
++ kfree(ipt->tcfi_tname);
++ kfree(ipt->tcfi_t);
+ }
+- p->tname = tname;
+- p->t = t;
+- p->hook = hook;
+- spin_unlock_bh(&p->lock);
++ ipt->tcfi_tname = tname;
++ ipt->tcfi_t = t;
++ ipt->tcfi_hook = hook;
++ spin_unlock_bh(&ipt->tcf_lock);
+ if (ret == ACT_P_CREATED)
+- tcf_hash_insert(p);
++ tcf_hash_insert(pc, &ipt_hash_info);
+ return ret;
+
+ err3:
+@@ -194,33 +183,32 @@ err3:
+ err2:
+ kfree(tname);
+ err1:
+- kfree(p);
++ kfree(pc);
+ return err;
+ }
+
+-static int
+-tcf_ipt_cleanup(struct tc_action *a, int bind)
++static int tcf_ipt_cleanup(struct tc_action *a, int bind)
+ {
+- struct tcf_ipt *p = PRIV(a, ipt);
+- return tcf_ipt_release(p, bind);
++ struct tcf_ipt *ipt = a->priv;
++ return tcf_ipt_release(ipt, bind);
+ }
+
+-static int
+-tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
++static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
++ struct tcf_result *res)
+ {
+ int ret = 0, result = 0;
+- struct tcf_ipt *p = PRIV(a, ipt);
++ struct tcf_ipt *ipt = a->priv;
+
+ if (skb_cloned(skb)) {
+ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ return TC_ACT_UNSPEC;
+ }
+
+- spin_lock(&p->lock);
++ spin_lock(&ipt->tcf_lock);
+
+- p->tm.lastuse = jiffies;
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
++ ipt->tcf_tm.lastuse = jiffies;
++ ipt->tcf_bstats.bytes += skb->len;
++ ipt->tcf_bstats.packets++;
+
+ /* yes, we have to worry about both in and out dev
+ worry later - danger - this API seems to have changed
+@@ -229,16 +217,17 @@ tcf_ipt(struct sk_buff *skb, struct tc_a
+ /* iptables targets take a double skb pointer in case the skb
+ * needs to be replaced. We don't own the skb, so this must not
+ * happen. The pskb_expand_head above should make sure of this */
+- ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook,
+- p->t->u.kernel.target, p->t->data,
+- NULL);
++ ret = ipt->tcfi_t->u.kernel.target->target(&skb, skb->dev, NULL,
++ ipt->tcfi_hook,
++ ipt->tcfi_t->u.kernel.target,
++ ipt->tcfi_t->data);
+ switch (ret) {
+ case NF_ACCEPT:
+ result = TC_ACT_OK;
+ break;
+ case NF_DROP:
+ result = TC_ACT_SHOT;
+- p->qstats.drops++;
++ ipt->tcf_qstats.drops++;
+ break;
+ case IPT_CONTINUE:
+ result = TC_ACT_PIPE;
+@@ -249,53 +238,46 @@ tcf_ipt(struct sk_buff *skb, struct tc_a
+ result = TC_POLICE_OK;
+ break;
+ }
+- spin_unlock(&p->lock);
++ spin_unlock(&ipt->tcf_lock);
+ return result;
+
+ }
+
+-static int
+-tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
++static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+ {
++ unsigned char *b = skb->tail;
++ struct tcf_ipt *ipt = a->priv;
+ struct ipt_entry_target *t;
+ struct tcf_t tm;
+ struct tc_cnt c;
+- unsigned char *b = skb->tail;
+- struct tcf_ipt *p = PRIV(a, ipt);
+
+ /* for simple targets kernel size == user size
+ ** user name = target name
+ ** for foolproof you need to not assume this
+ */
+
+- t = kmalloc(p->t->u.user.target_size, GFP_ATOMIC);
+- if (t == NULL)
++ t = kmalloc(ipt->tcfi_t->u.user.target_size, GFP_ATOMIC);
++ if (unlikely(!t))
+ goto rtattr_failure;
+
+- c.bindcnt = p->bindcnt - bind;
+- c.refcnt = p->refcnt - ref;
+- memcpy(t, p->t, p->t->u.user.target_size);
+- strcpy(t->u.user.name, p->t->u.kernel.target->name);
+-
+- DPRINTK("\ttcf_ipt_dump tablename %s length %d\n", p->tname,
+- strlen(p->tname));
+- DPRINTK("\tdump target name %s size %d size user %d "
+- "data[0] %x data[1] %x\n", p->t->u.kernel.target->name,
+- p->t->u.target_size, p->t->u.user.target_size,
+- p->t->data[0], p->t->data[1]);
+- RTA_PUT(skb, TCA_IPT_TARG, p->t->u.user.target_size, t);
+- RTA_PUT(skb, TCA_IPT_INDEX, 4, &p->index);
+- RTA_PUT(skb, TCA_IPT_HOOK, 4, &p->hook);
++ c.bindcnt = ipt->tcf_bindcnt - bind;
++ c.refcnt = ipt->tcf_refcnt - ref;
++ memcpy(t, ipt->tcfi_t, ipt->tcfi_t->u.user.target_size);
++ strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name);
++
++ RTA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t);
++ RTA_PUT(skb, TCA_IPT_INDEX, 4, &ipt->tcf_index);
++ RTA_PUT(skb, TCA_IPT_HOOK, 4, &ipt->tcfi_hook);
+ RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c);
+- RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, p->tname);
+- tm.install = jiffies_to_clock_t(jiffies - p->tm.install);
+- tm.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+- tm.expires = jiffies_to_clock_t(p->tm.expires);
++ RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, ipt->tcfi_tname);
++ tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install);
++ tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse);
++ tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires);
+ RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
+ kfree(t);
+ return skb->len;
+
+- rtattr_failure:
++rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ kfree(t);
+ return -1;
+@@ -303,6 +285,7 @@ tcf_ipt_dump(struct sk_buff *skb, struct
+
+ static struct tc_action_ops act_ipt_ops = {
+ .kind = "ipt",
++ .hinfo = &ipt_hash_info,
+ .type = TCA_ACT_IPT,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+@@ -318,14 +301,12 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"
+ MODULE_DESCRIPTION("Iptables target actions");
+ MODULE_LICENSE("GPL");
+
+-static int __init
+-ipt_init_module(void)
++static int __init ipt_init_module(void)
+ {
+ return tcf_register_action(&act_ipt_ops);
+ }
+
+-static void __exit
+-ipt_cleanup_module(void)
++static void __exit ipt_cleanup_module(void)
+ {
+ tcf_unregister_action(&act_ipt_ops);
+ }
+diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
+index fc56204..4838972 100644
+--- a/net/sched/act_mirred.c
++++ b/net/sched/act_mirred.c
+@@ -39,46 +39,39 @@
+ #include <linux/etherdevice.h>
+ #include <linux/if_arp.h>
+
+-
+-/* use generic hash table */
+-#define MY_TAB_SIZE 8
+-#define MY_TAB_MASK (MY_TAB_SIZE - 1)
+-static u32 idx_gen;
+-static struct tcf_mirred *tcf_mirred_ht[MY_TAB_SIZE];
++#define MIRRED_TAB_MASK 7
++static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
++static u32 mirred_idx_gen;
+ static DEFINE_RWLOCK(mirred_lock);
+
+-/* ovewrride the defaults */
+-#define tcf_st tcf_mirred
+-#define tc_st tc_mirred
+-#define tcf_t_lock mirred_lock
+-#define tcf_ht tcf_mirred_ht
+-
+-#define CONFIG_NET_ACT_INIT 1
+-#include <net/pkt_act.h>
++static struct tcf_hashinfo mirred_hash_info = {
++ .htab = tcf_mirred_ht,
++ .hmask = MIRRED_TAB_MASK,
++ .lock = &mirred_lock,
++};
+
+-static inline int
+-tcf_mirred_release(struct tcf_mirred *p, int bind)
++static inline int tcf_mirred_release(struct tcf_mirred *m, int bind)
+ {
+- if (p) {
++ if (m) {
+ if (bind)
+- p->bindcnt--;
+- p->refcnt--;
+- if(!p->bindcnt && p->refcnt <= 0) {
+- dev_put(p->dev);
+- tcf_hash_destroy(p);
++ m->tcf_bindcnt--;
++ m->tcf_refcnt--;
++ if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
++ dev_put(m->tcfm_dev);
++ tcf_hash_destroy(&m->common, &mirred_hash_info);
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+-static int
+-tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
+- int ovr, int bind)
++static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est,
++ struct tc_action *a, int ovr, int bind)
+ {
+ struct rtattr *tb[TCA_MIRRED_MAX];
+ struct tc_mirred *parm;
+- struct tcf_mirred *p;
++ struct tcf_mirred *m;
++ struct tcf_common *pc;
+ struct net_device *dev = NULL;
+ int ret = 0;
+ int ok_push = 0;
+@@ -110,64 +103,62 @@ tcf_mirred_init(struct rtattr *rta, stru
+ }
+ }
+
+- p = tcf_hash_check(parm->index, a, ovr, bind);
+- if (p == NULL) {
++ pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
++ if (!pc) {
+ if (!parm->ifindex)
+ return -EINVAL;
+- p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
+- if (p == NULL)
++ pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
++ &mirred_idx_gen, &mirred_hash_info);
++ if (unlikely(!pc))
+ return -ENOMEM;
+ ret = ACT_P_CREATED;
+ } else {
+ if (!ovr) {
+- tcf_mirred_release(p, bind);
++ tcf_mirred_release(to_mirred(pc), bind);
+ return -EEXIST;
+ }
+ }
++ m = to_mirred(pc);
+
+- spin_lock_bh(&p->lock);
+- p->action = parm->action;
+- p->eaction = parm->eaction;
++ spin_lock_bh(&m->tcf_lock);
++ m->tcf_action = parm->action;
++ m->tcfm_eaction = parm->eaction;
+ if (parm->ifindex) {
+- p->ifindex = parm->ifindex;
++ m->tcfm_ifindex = parm->ifindex;
+ if (ret != ACT_P_CREATED)
+- dev_put(p->dev);
+- p->dev = dev;
++ dev_put(m->tcfm_dev);
++ m->tcfm_dev = dev;
+ dev_hold(dev);
+- p->ok_push = ok_push;
++ m->tcfm_ok_push = ok_push;
+ }
+- spin_unlock_bh(&p->lock);
++ spin_unlock_bh(&m->tcf_lock);
+ if (ret == ACT_P_CREATED)
+- tcf_hash_insert(p);
++ tcf_hash_insert(pc, &mirred_hash_info);
+
+- DPRINTK("tcf_mirred_init index %d action %d eaction %d device %s "
+- "ifindex %d\n", parm->index, parm->action, parm->eaction,
+- dev->name, parm->ifindex);
+ return ret;
+ }
+
+-static int
+-tcf_mirred_cleanup(struct tc_action *a, int bind)
++static int tcf_mirred_cleanup(struct tc_action *a, int bind)
+ {
+- struct tcf_mirred *p = PRIV(a, mirred);
++ struct tcf_mirred *m = a->priv;
+
+- if (p != NULL)
+- return tcf_mirred_release(p, bind);
++ if (m)
++ return tcf_mirred_release(m, bind);
+ return 0;
+ }
+
+-static int
+-tcf_mirred(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
++static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
++ struct tcf_result *res)
+ {
+- struct tcf_mirred *p = PRIV(a, mirred);
++ struct tcf_mirred *m = a->priv;
+ struct net_device *dev;
+ struct sk_buff *skb2 = NULL;
+ u32 at = G_TC_AT(skb->tc_verd);
+
+- spin_lock(&p->lock);
++ spin_lock(&m->tcf_lock);
+
+- dev = p->dev;
+- p->tm.lastuse = jiffies;
++ dev = m->tcfm_dev;
++ m->tcf_tm.lastuse = jiffies;
+
+ if (!(dev->flags&IFF_UP) ) {
+ if (net_ratelimit())
+@@ -176,10 +167,10 @@ tcf_mirred(struct sk_buff *skb, struct t
+ bad_mirred:
+ if (skb2 != NULL)
+ kfree_skb(skb2);
+- p->qstats.overlimits++;
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
+- spin_unlock(&p->lock);
++ m->tcf_qstats.overlimits++;
++ m->tcf_bstats.bytes += skb->len;
++ m->tcf_bstats.packets++;
++ spin_unlock(&m->tcf_lock);
+ /* should we be asking for packet to be dropped?
+ * may make sense for redirect case only
+ */
+@@ -189,59 +180,59 @@ bad_mirred:
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ goto bad_mirred;
+- if (p->eaction != TCA_EGRESS_MIRROR && p->eaction != TCA_EGRESS_REDIR) {
++ if (m->tcfm_eaction != TCA_EGRESS_MIRROR &&
++ m->tcfm_eaction != TCA_EGRESS_REDIR) {
+ if (net_ratelimit())
+- printk("tcf_mirred unknown action %d\n", p->eaction);
++ printk("tcf_mirred unknown action %d\n",
++ m->tcfm_eaction);
+ goto bad_mirred;
+ }
+
+- p->bstats.bytes += skb2->len;
+- p->bstats.packets++;
++ m->tcf_bstats.bytes += skb2->len;
++ m->tcf_bstats.packets++;
+ if (!(at & AT_EGRESS))
+- if (p->ok_push)
++ if (m->tcfm_ok_push)
+ skb_push(skb2, skb2->dev->hard_header_len);
+
+ /* mirror is always swallowed */
+- if (p->eaction != TCA_EGRESS_MIRROR)
++ if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
+ skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
+
+ skb2->dev = dev;
+ skb2->input_dev = skb->dev;
+ dev_queue_xmit(skb2);
+- spin_unlock(&p->lock);
+- return p->action;
++ spin_unlock(&m->tcf_lock);
++ return m->tcf_action;
+ }
+
+-static int
+-tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
++static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+ {
+ unsigned char *b = skb->tail;
++ struct tcf_mirred *m = a->priv;
+ struct tc_mirred opt;
+- struct tcf_mirred *p = PRIV(a, mirred);
+ struct tcf_t t;
+
+- opt.index = p->index;
+- opt.action = p->action;
+- opt.refcnt = p->refcnt - ref;
+- opt.bindcnt = p->bindcnt - bind;
+- opt.eaction = p->eaction;
+- opt.ifindex = p->ifindex;
+- DPRINTK("tcf_mirred_dump index %d action %d eaction %d ifindex %d\n",
+- p->index, p->action, p->eaction, p->ifindex);
++ opt.index = m->tcf_index;
++ opt.action = m->tcf_action;
++ opt.refcnt = m->tcf_refcnt - ref;
++ opt.bindcnt = m->tcf_bindcnt - bind;
++ opt.eaction = m->tcfm_eaction;
++ opt.ifindex = m->tcfm_ifindex;
+ RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt);
+- t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+- t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+- t.expires = jiffies_to_clock_t(p->tm.expires);
++ t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
++ t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
++ t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
+ RTA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t);
+ return skb->len;
+
+- rtattr_failure:
++rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+ }
+
+ static struct tc_action_ops act_mirred_ops = {
+ .kind = "mirred",
++ .hinfo = &mirred_hash_info,
+ .type = TCA_ACT_MIRRED,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+@@ -257,15 +248,13 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002)");
+ MODULE_DESCRIPTION("Device Mirror/redirect actions");
+ MODULE_LICENSE("GPL");
+
+-static int __init
+-mirred_init_module(void)
++static int __init mirred_init_module(void)
+ {
+ printk("Mirror/redirect action on\n");
+ return tcf_register_action(&act_mirred_ops);
+ }
+
+-static void __exit
+-mirred_cleanup_module(void)
++static void __exit mirred_cleanup_module(void)
+ {
+ tcf_unregister_action(&act_mirred_ops);
+ }
+diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
+index f257475..8ac65c2 100644
+--- a/net/sched/act_pedit.c
++++ b/net/sched/act_pedit.c
+@@ -33,32 +33,25 @@
+ #include <linux/tc_act/tc_pedit.h>
+ #include <net/tc_act/tc_pedit.h>
+
+-
+-#define PEDIT_DEB 1
+-
+-/* use generic hash table */
+-#define MY_TAB_SIZE 16
+-#define MY_TAB_MASK 15
+-static u32 idx_gen;
+-static struct tcf_pedit *tcf_pedit_ht[MY_TAB_SIZE];
++#define PEDIT_TAB_MASK 15
++static struct tcf_common *tcf_pedit_ht[PEDIT_TAB_MASK + 1];
++static u32 pedit_idx_gen;
+ static DEFINE_RWLOCK(pedit_lock);
+
+-#define tcf_st tcf_pedit
+-#define tc_st tc_pedit
+-#define tcf_t_lock pedit_lock
+-#define tcf_ht tcf_pedit_ht
+-
+-#define CONFIG_NET_ACT_INIT 1
+-#include <net/pkt_act.h>
++static struct tcf_hashinfo pedit_hash_info = {
++ .htab = tcf_pedit_ht,
++ .hmask = PEDIT_TAB_MASK,
++ .lock = &pedit_lock,
++};
+
+-static int
+-tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
+- int ovr, int bind)
++static int tcf_pedit_init(struct rtattr *rta, struct rtattr *est,
++ struct tc_action *a, int ovr, int bind)
+ {
+ struct rtattr *tb[TCA_PEDIT_MAX];
+ struct tc_pedit *parm;
+ int ret = 0;
+ struct tcf_pedit *p;
++ struct tcf_common *pc;
+ struct tc_pedit_key *keys = NULL;
+ int ksize;
+
+@@ -73,54 +66,56 @@ tcf_pedit_init(struct rtattr *rta, struc
+ if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize)
+ return -EINVAL;
+
+- p = tcf_hash_check(parm->index, a, ovr, bind);
+- if (p == NULL) {
++ pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info);
++ if (!pc) {
+ if (!parm->nkeys)
+ return -EINVAL;
+- p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
+- if (p == NULL)
++ pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
++ &pedit_idx_gen, &pedit_hash_info);
++ if (unlikely(!pc))
+ return -ENOMEM;
++ p = to_pedit(pc);
+ keys = kmalloc(ksize, GFP_KERNEL);
+ if (keys == NULL) {
+- kfree(p);
++ kfree(pc);
+ return -ENOMEM;
+ }
+ ret = ACT_P_CREATED;
+ } else {
++ p = to_pedit(pc);
+ if (!ovr) {
+- tcf_hash_release(p, bind);
++ tcf_hash_release(pc, bind, &pedit_hash_info);
+ return -EEXIST;
+ }
+- if (p->nkeys && p->nkeys != parm->nkeys) {
++ if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
+ keys = kmalloc(ksize, GFP_KERNEL);
+ if (keys == NULL)
+ return -ENOMEM;
+ }
+ }
+
+- spin_lock_bh(&p->lock);
+- p->flags = parm->flags;
+- p->action = parm->action;
++ spin_lock_bh(&p->tcf_lock);
++ p->tcfp_flags = parm->flags;
++ p->tcf_action = parm->action;
+ if (keys) {
+- kfree(p->keys);
+- p->keys = keys;
+- p->nkeys = parm->nkeys;
++ kfree(p->tcfp_keys);
++ p->tcfp_keys = keys;
++ p->tcfp_nkeys = parm->nkeys;
+ }
+- memcpy(p->keys, parm->keys, ksize);
+- spin_unlock_bh(&p->lock);
++ memcpy(p->tcfp_keys, parm->keys, ksize);
++ spin_unlock_bh(&p->tcf_lock);
+ if (ret == ACT_P_CREATED)
+- tcf_hash_insert(p);
++ tcf_hash_insert(pc, &pedit_hash_info);
+ return ret;
+ }
+
+-static int
+-tcf_pedit_cleanup(struct tc_action *a, int bind)
++static int tcf_pedit_cleanup(struct tc_action *a, int bind)
+ {
+- struct tcf_pedit *p = PRIV(a, pedit);
++ struct tcf_pedit *p = a->priv;
+
+- if (p != NULL) {
+- struct tc_pedit_key *keys = p->keys;
+- if (tcf_hash_release(p, bind)) {
++ if (p) {
++ struct tc_pedit_key *keys = p->tcfp_keys;
++ if (tcf_hash_release(&p->common, bind, &pedit_hash_info)) {
+ kfree(keys);
+ return 1;
+ }
+@@ -128,30 +123,30 @@ tcf_pedit_cleanup(struct tc_action *a, i
+ return 0;
+ }
+
+-static int
+-tcf_pedit(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
++static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
++ struct tcf_result *res)
+ {
+- struct tcf_pedit *p = PRIV(a, pedit);
++ struct tcf_pedit *p = a->priv;
+ int i, munged = 0;
+ u8 *pptr;
+
+ if (!(skb->tc_verd & TC_OK2MUNGE)) {
+ /* should we set skb->cloned? */
+ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+- return p->action;
++ return p->tcf_action;
+ }
+ }
+
+ pptr = skb->nh.raw;
+
+- spin_lock(&p->lock);
++ spin_lock(&p->tcf_lock);
+
+- p->tm.lastuse = jiffies;
++ p->tcf_tm.lastuse = jiffies;
+
+- if (p->nkeys > 0) {
+- struct tc_pedit_key *tkey = p->keys;
++ if (p->tcfp_nkeys > 0) {
++ struct tc_pedit_key *tkey = p->tcfp_keys;
+
+- for (i = p->nkeys; i > 0; i--, tkey++) {
++ for (i = p->tcfp_nkeys; i > 0; i--, tkey++) {
+ u32 *ptr;
+ int offset = tkey->off;
+
+@@ -169,7 +164,8 @@ tcf_pedit(struct sk_buff *skb, struct tc
+ printk("offset must be on 32 bit boundaries\n");
+ goto bad;
+ }
+- if (skb->len < 0 || (offset > 0 && offset > skb->len)) {
++ if (skb->len < 0 ||
++ (offset > 0 && offset > skb->len)) {
+ printk("offset %d cant exceed pkt length %d\n",
+ offset, skb->len);
+ goto bad;
+@@ -185,63 +181,47 @@ tcf_pedit(struct sk_buff *skb, struct tc
+ skb->tc_verd = SET_TC_MUNGED(skb->tc_verd);
+ goto done;
+ } else {
+- printk("pedit BUG: index %d\n",p->index);
++ printk("pedit BUG: index %d\n", p->tcf_index);
+ }
+
+ bad:
+- p->qstats.overlimits++;
++ p->tcf_qstats.overlimits++;
+ done:
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
+- spin_unlock(&p->lock);
+- return p->action;
++ p->tcf_bstats.bytes += skb->len;
++ p->tcf_bstats.packets++;
++ spin_unlock(&p->tcf_lock);
++ return p->tcf_action;
+ }
+
+-static int
+-tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref)
++static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
++ int bind, int ref)
+ {
+ unsigned char *b = skb->tail;
++ struct tcf_pedit *p = a->priv;
+ struct tc_pedit *opt;
+- struct tcf_pedit *p = PRIV(a, pedit);
+ struct tcf_t t;
+ int s;
+
+- s = sizeof(*opt) + p->nkeys * sizeof(struct tc_pedit_key);
++ s = sizeof(*opt) + p->tcfp_nkeys * sizeof(struct tc_pedit_key);
+
+ /* netlink spinlocks held above us - must use ATOMIC */
+ opt = kzalloc(s, GFP_ATOMIC);
+- if (opt == NULL)
++ if (unlikely(!opt))
+ return -ENOBUFS;
+
+- memcpy(opt->keys, p->keys, p->nkeys * sizeof(struct tc_pedit_key));
+- opt->index = p->index;
+- opt->nkeys = p->nkeys;
+- opt->flags = p->flags;
+- opt->action = p->action;
+- opt->refcnt = p->refcnt - ref;
+- opt->bindcnt = p->bindcnt - bind;
+-
+-
+-#ifdef PEDIT_DEB
+- {
+- /* Debug - get rid of later */
+- int i;
+- struct tc_pedit_key *key = opt->keys;
+-
+- for (i=0; i<opt->nkeys; i++, key++) {
+- printk( "\n key #%d",i);
+- printk( " at %d: val %08x mask %08x",
+- (unsigned int)key->off,
+- (unsigned int)key->val,
+- (unsigned int)key->mask);
+- }
+- }
+-#endif
++ memcpy(opt->keys, p->tcfp_keys,
++ p->tcfp_nkeys * sizeof(struct tc_pedit_key));
++ opt->index = p->tcf_index;
++ opt->nkeys = p->tcfp_nkeys;
++ opt->flags = p->tcfp_flags;
++ opt->action = p->tcf_action;
++ opt->refcnt = p->tcf_refcnt - ref;
++ opt->bindcnt = p->tcf_bindcnt - bind;
+
+ RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt);
+- t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+- t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+- t.expires = jiffies_to_clock_t(p->tm.expires);
++ t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
++ t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
++ t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
+ RTA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t);
+ kfree(opt);
+ return skb->len;
+@@ -252,9 +232,9 @@ rtattr_failure:
+ return -1;
+ }
+
+-static
+-struct tc_action_ops act_pedit_ops = {
++static struct tc_action_ops act_pedit_ops = {
+ .kind = "pedit",
++ .hinfo = &pedit_hash_info,
+ .type = TCA_ACT_PEDIT,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+@@ -270,14 +250,12 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"
+ MODULE_DESCRIPTION("Generic Packet Editor actions");
+ MODULE_LICENSE("GPL");
+
+-static int __init
+-pedit_init_module(void)
++static int __init pedit_init_module(void)
+ {
+ return tcf_register_action(&act_pedit_ops);
+ }
+
+-static void __exit
+-pedit_cleanup_module(void)
++static void __exit pedit_cleanup_module(void)
+ {
+ tcf_unregister_action(&act_pedit_ops);
+ }
+diff --git a/net/sched/act_police.c b/net/sched/act_police.c
+index da905d7..fed47b6 100644
+--- a/net/sched/act_police.c
++++ b/net/sched/act_police.c
+@@ -32,43 +32,27 @@
+ #include <net/sock.h>
+ #include <net/act_api.h>
+
+-#define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log])
+-#define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log])
+-#define PRIV(a) ((struct tcf_police *) (a)->priv)
+-
+-/* use generic hash table */
+-#define MY_TAB_SIZE 16
+-#define MY_TAB_MASK 15
+-static u32 idx_gen;
+-static struct tcf_police *tcf_police_ht[MY_TAB_SIZE];
+-/* Policer hash table lock */
+-static DEFINE_RWLOCK(police_lock);
+-
+-/* Each policer is serialized by its individual spinlock */
++#define L2T(p,L) ((p)->tcfp_R_tab->data[(L)>>(p)->tcfp_R_tab->rate.cell_log])
++#define L2T_P(p,L) ((p)->tcfp_P_tab->data[(L)>>(p)->tcfp_P_tab->rate.cell_log])
+
+-static __inline__ unsigned tcf_police_hash(u32 index)
+-{
+- return index&0xF;
+-}
++#define POL_TAB_MASK 15
++static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1];
++static u32 police_idx_gen;
++static DEFINE_RWLOCK(police_lock);
+
+-static __inline__ struct tcf_police * tcf_police_lookup(u32 index)
+-{
+- struct tcf_police *p;
++static struct tcf_hashinfo police_hash_info = {
++ .htab = tcf_police_ht,
++ .hmask = POL_TAB_MASK,
++ .lock = &police_lock,
++};
+
+- read_lock(&police_lock);
+- for (p = tcf_police_ht[tcf_police_hash(index)]; p; p = p->next) {
+- if (p->index == index)
+- break;
+- }
+- read_unlock(&police_lock);
+- return p;
+-}
++/* Each policer is serialized by its individual spinlock */
+
+ #ifdef CONFIG_NET_CLS_ACT
+ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
+ int type, struct tc_action *a)
+ {
+- struct tcf_police *p;
++ struct tcf_common *p;
+ int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
+ struct rtattr *r;
+
+@@ -76,10 +60,10 @@ static int tcf_act_police_walker(struct
+
+ s_i = cb->args[0];
+
+- for (i = 0; i < MY_TAB_SIZE; i++) {
+- p = tcf_police_ht[tcf_police_hash(i)];
++ for (i = 0; i < (POL_TAB_MASK + 1); i++) {
++ p = tcf_police_ht[tcf_hash(i, POL_TAB_MASK)];
+
+- for (; p; p = p->next) {
++ for (; p; p = p->tcfc_next) {
+ index++;
+ if (index < s_i)
+ continue;
+@@ -110,48 +94,26 @@ rtattr_failure:
+ skb_trim(skb, (u8*)r - skb->data);
+ goto done;
+ }
+-
+-static inline int
+-tcf_act_police_hash_search(struct tc_action *a, u32 index)
+-{
+- struct tcf_police *p = tcf_police_lookup(index);
+-
+- if (p != NULL) {
+- a->priv = p;
+- return 1;
+- } else {
+- return 0;
+- }
+-}
+ #endif
+
+-static inline u32 tcf_police_new_index(void)
+-{
+- do {
+- if (++idx_gen == 0)
+- idx_gen = 1;
+- } while (tcf_police_lookup(idx_gen));
+-
+- return idx_gen;
+-}
+-
+ void tcf_police_destroy(struct tcf_police *p)
+ {
+- unsigned h = tcf_police_hash(p->index);
+- struct tcf_police **p1p;
++ unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
++ struct tcf_common **p1p;
+
+- for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) {
+- if (*p1p == p) {
++ for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) {
++ if (*p1p == &p->common) {
+ write_lock_bh(&police_lock);
+- *p1p = p->next;
++ *p1p = p->tcf_next;
+ write_unlock_bh(&police_lock);
+ #ifdef CONFIG_NET_ESTIMATOR
+- gen_kill_estimator(&p->bstats, &p->rate_est);
++ gen_kill_estimator(&p->tcf_bstats,
++ &p->tcf_rate_est);
+ #endif
+- if (p->R_tab)
+- qdisc_put_rtab(p->R_tab);
+- if (p->P_tab)
+- qdisc_put_rtab(p->P_tab);
++ if (p->tcfp_R_tab)
++ qdisc_put_rtab(p->tcfp_R_tab);
++ if (p->tcfp_P_tab)
++ qdisc_put_rtab(p->tcfp_P_tab);
+ kfree(p);
+ return;
+ }
+@@ -167,7 +129,7 @@ static int tcf_act_police_locate(struct
+ int ret = 0, err;
+ struct rtattr *tb[TCA_POLICE_MAX];
+ struct tc_police *parm;
+- struct tcf_police *p;
++ struct tcf_police *police;
+ struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
+
+ if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
+@@ -185,27 +147,32 @@ static int tcf_act_police_locate(struct
+ RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
+ return -EINVAL;
+
+- if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) {
+- a->priv = p;
+- if (bind) {
+- p->bindcnt += 1;
+- p->refcnt += 1;
++ if (parm->index) {
++ struct tcf_common *pc;
++
++ pc = tcf_hash_lookup(parm->index, &police_hash_info);
++ if (pc != NULL) {
++ a->priv = pc;
++ police = to_police(pc);
++ if (bind) {
++ police->tcf_bindcnt += 1;
++ police->tcf_refcnt += 1;
++ }
++ if (ovr)
++ goto override;
++ return ret;
+ }
+- if (ovr)
+- goto override;
+- return ret;
+ }
+
+- p = kzalloc(sizeof(*p), GFP_KERNEL);
+- if (p == NULL)
++ police = kzalloc(sizeof(*police), GFP_KERNEL);
++ if (police == NULL)
+ return -ENOMEM;
+-
+ ret = ACT_P_CREATED;
+- p->refcnt = 1;
+- spin_lock_init(&p->lock);
+- p->stats_lock = &p->lock;
++ police->tcf_refcnt = 1;
++ spin_lock_init(&police->tcf_lock);
++ police->tcf_stats_lock = &police->tcf_lock;
+ if (bind)
+- p->bindcnt = 1;
++ police->tcf_bindcnt = 1;
+ override:
+ if (parm->rate.rate) {
+ err = -ENOMEM;
+@@ -215,67 +182,71 @@ override:
+ if (parm->peakrate.rate) {
+ P_tab = qdisc_get_rtab(&parm->peakrate,
+ tb[TCA_POLICE_PEAKRATE-1]);
+- if (p->P_tab == NULL) {
++ if (P_tab == NULL) {
+ qdisc_put_rtab(R_tab);
+ goto failure;
+ }
+ }
+ }
+ /* No failure allowed after this point */
+- spin_lock_bh(&p->lock);
++ spin_lock_bh(&police->tcf_lock);
+ if (R_tab != NULL) {
+- qdisc_put_rtab(p->R_tab);
+- p->R_tab = R_tab;
++ qdisc_put_rtab(police->tcfp_R_tab);
++ police->tcfp_R_tab = R_tab;
+ }
+ if (P_tab != NULL) {
+- qdisc_put_rtab(p->P_tab);
+- p->P_tab = P_tab;
++ qdisc_put_rtab(police->tcfp_P_tab);
++ police->tcfp_P_tab = P_tab;
+ }
+
+ if (tb[TCA_POLICE_RESULT-1])
+- p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
+- p->toks = p->burst = parm->burst;
+- p->mtu = parm->mtu;
+- if (p->mtu == 0) {
+- p->mtu = ~0;
+- if (p->R_tab)
+- p->mtu = 255<<p->R_tab->rate.cell_log;
++ police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
++ police->tcfp_toks = police->tcfp_burst = parm->burst;
++ police->tcfp_mtu = parm->mtu;
++ if (police->tcfp_mtu == 0) {
++ police->tcfp_mtu = ~0;
++ if (police->tcfp_R_tab)
++ police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
+ }
+- if (p->P_tab)
+- p->ptoks = L2T_P(p, p->mtu);
+- p->action = parm->action;
++ if (police->tcfp_P_tab)
++ police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
++ police->tcf_action = parm->action;
+
+ #ifdef CONFIG_NET_ESTIMATOR
+ if (tb[TCA_POLICE_AVRATE-1])
+- p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
++ police->tcfp_ewma_rate =
++ *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
+ if (est)
+- gen_replace_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
++ gen_replace_estimator(&police->tcf_bstats,
++ &police->tcf_rate_est,
++ police->tcf_stats_lock, est);
+ #endif
+
+- spin_unlock_bh(&p->lock);
++ spin_unlock_bh(&police->tcf_lock);
+ if (ret != ACT_P_CREATED)
+ return ret;
+
+- PSCHED_GET_TIME(p->t_c);
+- p->index = parm->index ? : tcf_police_new_index();
+- h = tcf_police_hash(p->index);
++ PSCHED_GET_TIME(police->tcfp_t_c);
++ police->tcf_index = parm->index ? parm->index :
++ tcf_hash_new_index(&police_idx_gen, &police_hash_info);
++ h = tcf_hash(police->tcf_index, POL_TAB_MASK);
+ write_lock_bh(&police_lock);
+- p->next = tcf_police_ht[h];
+- tcf_police_ht[h] = p;
++ police->tcf_next = tcf_police_ht[h];
++ tcf_police_ht[h] = &police->common;
+ write_unlock_bh(&police_lock);
+
+- a->priv = p;
++ a->priv = police;
+ return ret;
+
+ failure:
+ if (ret == ACT_P_CREATED)
+- kfree(p);
++ kfree(police);
+ return err;
+ }
+
+ static int tcf_act_police_cleanup(struct tc_action *a, int bind)
+ {
+- struct tcf_police *p = PRIV(a);
++ struct tcf_police *p = a->priv;
+
+ if (p != NULL)
+ return tcf_police_release(p, bind);
+@@ -285,86 +256,87 @@ static int tcf_act_police_cleanup(struct
+ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
+ struct tcf_result *res)
+ {
++ struct tcf_police *police = a->priv;
+ psched_time_t now;
+- struct tcf_police *p = PRIV(a);
+ long toks;
+ long ptoks = 0;
+
+- spin_lock(&p->lock);
++ spin_lock(&police->tcf_lock);
+
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
++ police->tcf_bstats.bytes += skb->len;
++ police->tcf_bstats.packets++;
+
+ #ifdef CONFIG_NET_ESTIMATOR
+- if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) {
+- p->qstats.overlimits++;
+- spin_unlock(&p->lock);
+- return p->action;
++ if (police->tcfp_ewma_rate &&
++ police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
++ police->tcf_qstats.overlimits++;
++ spin_unlock(&police->tcf_lock);
++ return police->tcf_action;
+ }
+ #endif
+
+- if (skb->len <= p->mtu) {
+- if (p->R_tab == NULL) {
+- spin_unlock(&p->lock);
+- return p->result;
++ if (skb->len <= police->tcfp_mtu) {
++ if (police->tcfp_R_tab == NULL) {
++ spin_unlock(&police->tcf_lock);
++ return police->tcfp_result;
+ }
+
+ PSCHED_GET_TIME(now);
+
+- toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst);
+-
+- if (p->P_tab) {
+- ptoks = toks + p->ptoks;
+- if (ptoks > (long)L2T_P(p, p->mtu))
+- ptoks = (long)L2T_P(p, p->mtu);
+- ptoks -= L2T_P(p, skb->len);
++ toks = PSCHED_TDIFF_SAFE(now, police->tcfp_t_c,
++ police->tcfp_burst);
++ if (police->tcfp_P_tab) {
++ ptoks = toks + police->tcfp_ptoks;
++ if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
++ ptoks = (long)L2T_P(police, police->tcfp_mtu);
++ ptoks -= L2T_P(police, skb->len);
+ }
+- toks += p->toks;
+- if (toks > (long)p->burst)
+- toks = p->burst;
+- toks -= L2T(p, skb->len);
+-
++ toks += police->tcfp_toks;
++ if (toks > (long)police->tcfp_burst)
++ toks = police->tcfp_burst;
++ toks -= L2T(police, skb->len);
+ if ((toks|ptoks) >= 0) {
+- p->t_c = now;
+- p->toks = toks;
+- p->ptoks = ptoks;
+- spin_unlock(&p->lock);
+- return p->result;
++ police->tcfp_t_c = now;
++ police->tcfp_toks = toks;
++ police->tcfp_ptoks = ptoks;
++ spin_unlock(&police->tcf_lock);
++ return police->tcfp_result;
+ }
+ }
+
+- p->qstats.overlimits++;
+- spin_unlock(&p->lock);
+- return p->action;
++ police->tcf_qstats.overlimits++;
++ spin_unlock(&police->tcf_lock);
++ return police->tcf_action;
+ }
+
+ static int
+ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+ {
+ unsigned char *b = skb->tail;
++ struct tcf_police *police = a->priv;
+ struct tc_police opt;
+- struct tcf_police *p = PRIV(a);
+-
+- opt.index = p->index;
+- opt.action = p->action;
+- opt.mtu = p->mtu;
+- opt.burst = p->burst;
+- opt.refcnt = p->refcnt - ref;
+- opt.bindcnt = p->bindcnt - bind;
+- if (p->R_tab)
+- opt.rate = p->R_tab->rate;
++
++ opt.index = police->tcf_index;
++ opt.action = police->tcf_action;
++ opt.mtu = police->tcfp_mtu;
++ opt.burst = police->tcfp_burst;
++ opt.refcnt = police->tcf_refcnt - ref;
++ opt.bindcnt = police->tcf_bindcnt - bind;
++ if (police->tcfp_R_tab)
++ opt.rate = police->tcfp_R_tab->rate;
+ else
+ memset(&opt.rate, 0, sizeof(opt.rate));
+- if (p->P_tab)
+- opt.peakrate = p->P_tab->rate;
++ if (police->tcfp_P_tab)
++ opt.peakrate = police->tcfp_P_tab->rate;
+ else
+ memset(&opt.peakrate, 0, sizeof(opt.peakrate));
+ RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
+- if (p->result)
+- RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result);
++ if (police->tcfp_result)
++ RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
++ &police->tcfp_result);
+ #ifdef CONFIG_NET_ESTIMATOR
+- if (p->ewma_rate)
+- RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate);
++ if (police->tcfp_ewma_rate)
++ RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
+ #endif
+ return skb->len;
+
+@@ -379,13 +351,14 @@ MODULE_LICENSE("GPL");
+
+ static struct tc_action_ops act_police_ops = {
+ .kind = "police",
++ .hinfo = &police_hash_info,
+ .type = TCA_ID_POLICE,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+ .act = tcf_act_police,
+ .dump = tcf_act_police_dump,
+ .cleanup = tcf_act_police_cleanup,
+- .lookup = tcf_act_police_hash_search,
++ .lookup = tcf_hash_search,
+ .init = tcf_act_police_locate,
+ .walk = tcf_act_police_walker
+ };
+@@ -407,10 +380,39 @@ module_exit(police_cleanup_module);
+
+ #else /* CONFIG_NET_CLS_ACT */
+
+-struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est)
++static struct tcf_common *tcf_police_lookup(u32 index)
+ {
+- unsigned h;
+- struct tcf_police *p;
++ struct tcf_hashinfo *hinfo = &police_hash_info;
++ struct tcf_common *p;
++
++ read_lock(hinfo->lock);
++ for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
++ p = p->tcfc_next) {
++ if (p->tcfc_index == index)
++ break;
++ }
++ read_unlock(hinfo->lock);
++
++ return p;
++}
++
++static u32 tcf_police_new_index(void)
++{
++ u32 *idx_gen = &police_idx_gen;
++ u32 val = *idx_gen;
++
++ do {
++ if (++val == 0)
++ val = 1;
++ } while (tcf_police_lookup(val));
++
++ return (*idx_gen = val);
++}
++
++struct tcf_police *tcf_police_locate(struct rtattr *rta, struct rtattr *est)
++{
++ unsigned int h;
++ struct tcf_police *police;
+ struct rtattr *tb[TCA_POLICE_MAX];
+ struct tc_police *parm;
+
+@@ -423,149 +425,158 @@ struct tcf_police * tcf_police_locate(st
+
+ parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
+
+- if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) {
+- p->refcnt++;
+- return p;
+- }
++ if (parm->index) {
++ struct tcf_common *pc;
+
+- p = kzalloc(sizeof(*p), GFP_KERNEL);
+- if (p == NULL)
++ pc = tcf_police_lookup(parm->index);
++ if (pc) {
++ police = to_police(pc);
++ police->tcf_refcnt++;
++ return police;
++ }
++ }
++ police = kzalloc(sizeof(*police), GFP_KERNEL);
++ if (unlikely(!police))
+ return NULL;
+
+- p->refcnt = 1;
+- spin_lock_init(&p->lock);
+- p->stats_lock = &p->lock;
++ police->tcf_refcnt = 1;
++ spin_lock_init(&police->tcf_lock);
++ police->tcf_stats_lock = &police->tcf_lock;
+ if (parm->rate.rate) {
+- p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
+- if (p->R_tab == NULL)
++ police->tcfp_R_tab =
++ qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
++ if (police->tcfp_R_tab == NULL)
+ goto failure;
+ if (parm->peakrate.rate) {
+- p->P_tab = qdisc_get_rtab(&parm->peakrate,
+- tb[TCA_POLICE_PEAKRATE-1]);
+- if (p->P_tab == NULL)
++ police->tcfp_P_tab =
++ qdisc_get_rtab(&parm->peakrate,
++ tb[TCA_POLICE_PEAKRATE-1]);
++ if (police->tcfp_P_tab == NULL)
+ goto failure;
+ }
+ }
+ if (tb[TCA_POLICE_RESULT-1]) {
+ if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
+ goto failure;
+- p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
++ police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
+ }
+ #ifdef CONFIG_NET_ESTIMATOR
+ if (tb[TCA_POLICE_AVRATE-1]) {
+ if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32))
+ goto failure;
+- p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
++ police->tcfp_ewma_rate =
++ *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
+ }
+ #endif
+- p->toks = p->burst = parm->burst;
+- p->mtu = parm->mtu;
+- if (p->mtu == 0) {
+- p->mtu = ~0;
+- if (p->R_tab)
+- p->mtu = 255<<p->R_tab->rate.cell_log;
++ police->tcfp_toks = police->tcfp_burst = parm->burst;
++ police->tcfp_mtu = parm->mtu;
++ if (police->tcfp_mtu == 0) {
++ police->tcfp_mtu = ~0;
++ if (police->tcfp_R_tab)
++ police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
+ }
+- if (p->P_tab)
+- p->ptoks = L2T_P(p, p->mtu);
+- PSCHED_GET_TIME(p->t_c);
+- p->index = parm->index ? : tcf_police_new_index();
+- p->action = parm->action;
++ if (police->tcfp_P_tab)
++ police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
++ PSCHED_GET_TIME(police->tcfp_t_c);
++ police->tcf_index = parm->index ? parm->index :
++ tcf_police_new_index();
++ police->tcf_action = parm->action;
+ #ifdef CONFIG_NET_ESTIMATOR
+ if (est)
+- gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
++ gen_new_estimator(&police->tcf_bstats, &police->tcf_rate_est,
++ police->tcf_stats_lock, est);
+ #endif
+- h = tcf_police_hash(p->index);
++ h = tcf_hash(police->tcf_index, POL_TAB_MASK);
+ write_lock_bh(&police_lock);
+- p->next = tcf_police_ht[h];
+- tcf_police_ht[h] = p;
++ police->tcf_next = tcf_police_ht[h];
++ tcf_police_ht[h] = &police->common;
+ write_unlock_bh(&police_lock);
+- return p;
++ return police;
+
+ failure:
+- if (p->R_tab)
+- qdisc_put_rtab(p->R_tab);
+- kfree(p);
++ if (police->tcfp_R_tab)
++ qdisc_put_rtab(police->tcfp_R_tab);
++ kfree(police);
+ return NULL;
+ }
+
+-int tcf_police(struct sk_buff *skb, struct tcf_police *p)
++int tcf_police(struct sk_buff *skb, struct tcf_police *police)
+ {
+ psched_time_t now;
+ long toks;
+ long ptoks = 0;
+
+- spin_lock(&p->lock);
++ spin_lock(&police->tcf_lock);
+
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
++ police->tcf_bstats.bytes += skb->len;
++ police->tcf_bstats.packets++;
+
+ #ifdef CONFIG_NET_ESTIMATOR
+- if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) {
+- p->qstats.overlimits++;
+- spin_unlock(&p->lock);
+- return p->action;
++ if (police->tcfp_ewma_rate &&
++ police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
++ police->tcf_qstats.overlimits++;
++ spin_unlock(&police->tcf_lock);
++ return police->tcf_action;
+ }
+ #endif
+-
+- if (skb->len <= p->mtu) {
+- if (p->R_tab == NULL) {
+- spin_unlock(&p->lock);
+- return p->result;
++ if (skb->len <= police->tcfp_mtu) {
++ if (police->tcfp_R_tab == NULL) {
++ spin_unlock(&police->tcf_lock);
++ return police->tcfp_result;
+ }
+
+ PSCHED_GET_TIME(now);
+-
+- toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst);
+-
+- if (p->P_tab) {
+- ptoks = toks + p->ptoks;
+- if (ptoks > (long)L2T_P(p, p->mtu))
+- ptoks = (long)L2T_P(p, p->mtu);
+- ptoks -= L2T_P(p, skb->len);
++ toks = PSCHED_TDIFF_SAFE(now, police->tcfp_t_c,
++ police->tcfp_burst);
++ if (police->tcfp_P_tab) {
++ ptoks = toks + police->tcfp_ptoks;
++ if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
++ ptoks = (long)L2T_P(police, police->tcfp_mtu);
++ ptoks -= L2T_P(police, skb->len);
+ }
+- toks += p->toks;
+- if (toks > (long)p->burst)
+- toks = p->burst;
+- toks -= L2T(p, skb->len);
+-
++ toks += police->tcfp_toks;
++ if (toks > (long)police->tcfp_burst)
++ toks = police->tcfp_burst;
++ toks -= L2T(police, skb->len);
+ if ((toks|ptoks) >= 0) {
+- p->t_c = now;
+- p->toks = toks;
+- p->ptoks = ptoks;
+- spin_unlock(&p->lock);
+- return p->result;
++ police->tcfp_t_c = now;
++ police->tcfp_toks = toks;
++ police->tcfp_ptoks = ptoks;
++ spin_unlock(&police->tcf_lock);
++ return police->tcfp_result;
+ }
+ }
+
+- p->qstats.overlimits++;
+- spin_unlock(&p->lock);
+- return p->action;
++ police->tcf_qstats.overlimits++;
++ spin_unlock(&police->tcf_lock);
++ return police->tcf_action;
+ }
+ EXPORT_SYMBOL(tcf_police);
+
+-int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p)
++int tcf_police_dump(struct sk_buff *skb, struct tcf_police *police)
+ {
+- unsigned char *b = skb->tail;
++ unsigned char *b = skb->tail;
+ struct tc_police opt;
+
+- opt.index = p->index;
+- opt.action = p->action;
+- opt.mtu = p->mtu;
+- opt.burst = p->burst;
+- if (p->R_tab)
+- opt.rate = p->R_tab->rate;
++ opt.index = police->tcf_index;
++ opt.action = police->tcf_action;
++ opt.mtu = police->tcfp_mtu;
++ opt.burst = police->tcfp_burst;
++ if (police->tcfp_R_tab)
++ opt.rate = police->tcfp_R_tab->rate;
+ else
+ memset(&opt.rate, 0, sizeof(opt.rate));
+- if (p->P_tab)
+- opt.peakrate = p->P_tab->rate;
++ if (police->tcfp_P_tab)
++ opt.peakrate = police->tcfp_P_tab->rate;
+ else
+ memset(&opt.peakrate, 0, sizeof(opt.peakrate));
+ RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
+- if (p->result)
+- RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result);
++ if (police->tcfp_result)
++ RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
++ &police->tcfp_result);
+ #ifdef CONFIG_NET_ESTIMATOR
+- if (p->ewma_rate)
+- RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate);
++ if (police->tcfp_ewma_rate)
++ RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
+ #endif
+ return skb->len;
+
+@@ -574,19 +585,20 @@ rtattr_failure:
+ return -1;
+ }
+
+-int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p)
++int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *police)
+ {
+ struct gnet_dump d;
+
+ if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
+- TCA_XSTATS, p->stats_lock, &d) < 0)
++ TCA_XSTATS, police->tcf_stats_lock,
++ &d) < 0)
+ goto errout;
+
+- if (gnet_stats_copy_basic(&d, &p->bstats) < 0 ||
++ if (gnet_stats_copy_basic(&d, &police->tcf_bstats) < 0 ||
+ #ifdef CONFIG_NET_ESTIMATOR
+- gnet_stats_copy_rate_est(&d, &p->rate_est) < 0 ||
++ gnet_stats_copy_rate_est(&d, &police->tcf_rate_est) < 0 ||
+ #endif
+- gnet_stats_copy_queue(&d, &p->qstats) < 0)
++ gnet_stats_copy_queue(&d, &police->tcf_qstats) < 0)
+ goto errout;
+
+ if (gnet_stats_finish_copy(&d) < 0)
+diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
+index 17105c8..901571a 100644
+--- a/net/sched/act_simple.c
++++ b/net/sched/act_simple.c
+@@ -20,54 +20,175 @@
+
+ #define TCA_ACT_SIMP 22
+
+-/* XXX: Hide all these common elements under some macro
+- * probably
+-*/
+ #include <linux/tc_act/tc_defact.h>
+ #include <net/tc_act/tc_defact.h>
+
+-/* use generic hash table with 8 buckets */
+-#define MY_TAB_SIZE 8
+-#define MY_TAB_MASK (MY_TAB_SIZE - 1)
+-static u32 idx_gen;
+-static struct tcf_defact *tcf_simp_ht[MY_TAB_SIZE];
++#define SIMP_TAB_MASK 7
++static struct tcf_common *tcf_simp_ht[SIMP_TAB_MASK + 1];
++static u32 simp_idx_gen;
+ static DEFINE_RWLOCK(simp_lock);
+
+-/* override the defaults */
+-#define tcf_st tcf_defact
+-#define tc_st tc_defact
+-#define tcf_t_lock simp_lock
+-#define tcf_ht tcf_simp_ht
+-
+-#define CONFIG_NET_ACT_INIT 1
+-#include <net/pkt_act.h>
+-#include <net/act_generic.h>
++static struct tcf_hashinfo simp_hash_info = {
++ .htab = tcf_simp_ht,
++ .hmask = SIMP_TAB_MASK,
++ .lock = &simp_lock,
++};
+
+ static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
+ {
+- struct tcf_defact *p = PRIV(a, defact);
++ struct tcf_defact *d = a->priv;
+
+- spin_lock(&p->lock);
+- p->tm.lastuse = jiffies;
+- p->bstats.bytes += skb->len;
+- p->bstats.packets++;
++ spin_lock(&d->tcf_lock);
++ d->tcf_tm.lastuse = jiffies;
++ d->tcf_bstats.bytes += skb->len;
++ d->tcf_bstats.packets++;
+
+ /* print policy string followed by _ then packet count
+ * Example if this was the 3rd packet and the string was "hello"
+ * then it would look like "hello_3" (without quotes)
+ **/
+- printk("simple: %s_%d\n", (char *)p->defdata, p->bstats.packets);
+- spin_unlock(&p->lock);
+- return p->action;
++ printk("simple: %s_%d\n",
++ (char *)d->tcfd_defdata, d->tcf_bstats.packets);
++ spin_unlock(&d->tcf_lock);
++ return d->tcf_action;
++}
++
++static int tcf_simp_release(struct tcf_defact *d, int bind)
++{
++ int ret = 0;
++ if (d) {
++ if (bind)
++ d->tcf_bindcnt--;
++ d->tcf_refcnt--;
++ if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) {
++ kfree(d->tcfd_defdata);
++ tcf_hash_destroy(&d->common, &simp_hash_info);
++ ret = 1;
++ }
++ }
++ return ret;
++}
++
++static int alloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata)
++{
++ d->tcfd_defdata = kmalloc(datalen, GFP_KERNEL);
++ if (unlikely(!d->tcfd_defdata))
++ return -ENOMEM;
++ d->tcfd_datalen = datalen;
++ memcpy(d->tcfd_defdata, defdata, datalen);
++ return 0;
++}
++
++static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata)
++{
++ kfree(d->tcfd_defdata);
++ return alloc_defdata(d, datalen, defdata);
++}
++
++static int tcf_simp_init(struct rtattr *rta, struct rtattr *est,
++ struct tc_action *a, int ovr, int bind)
++{
++ struct rtattr *tb[TCA_DEF_MAX];
++ struct tc_defact *parm;
++ struct tcf_defact *d;
++ struct tcf_common *pc;
++ void *defdata;
++ u32 datalen = 0;
++ int ret = 0;
++
++ if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0)
++ return -EINVAL;
++
++ if (tb[TCA_DEF_PARMS - 1] == NULL ||
++ RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm))
++ return -EINVAL;
++
++ parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]);
++ defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]);
++ if (defdata == NULL)
++ return -EINVAL;
++
++ datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]);
++ if (datalen <= 0)
++ return -EINVAL;
++
++ pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info);
++ if (!pc) {
++ pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
++ &simp_idx_gen, &simp_hash_info);
++ if (unlikely(!pc))
++ return -ENOMEM;
++
++ d = to_defact(pc);
++ ret = alloc_defdata(d, datalen, defdata);
++ if (ret < 0) {
++ kfree(pc);
++ return ret;
++ }
++ ret = ACT_P_CREATED;
++ } else {
++ d = to_defact(pc);
++ if (!ovr) {
++ tcf_simp_release(d, bind);
++ return -EEXIST;
++ }
++ realloc_defdata(d, datalen, defdata);
++ }
++
++ spin_lock_bh(&d->tcf_lock);
++ d->tcf_action = parm->action;
++ spin_unlock_bh(&d->tcf_lock);
++
++ if (ret == ACT_P_CREATED)
++ tcf_hash_insert(pc, &simp_hash_info);
++ return ret;
++}
++
++static inline int tcf_simp_cleanup(struct tc_action *a, int bind)
++{
++ struct tcf_defact *d = a->priv;
++
++ if (d)
++ return tcf_simp_release(d, bind);
++ return 0;
++}
++
++static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
++ int bind, int ref)
++{
++ unsigned char *b = skb->tail;
++ struct tcf_defact *d = a->priv;
++ struct tc_defact opt;
++ struct tcf_t t;
++
++ opt.index = d->tcf_index;
++ opt.refcnt = d->tcf_refcnt - ref;
++ opt.bindcnt = d->tcf_bindcnt - bind;
++ opt.action = d->tcf_action;
++ RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt);
++ RTA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata);
++ t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
++ t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
++ t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
++ RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t);
++ return skb->len;
++
++rtattr_failure:
++ skb_trim(skb, b - skb->data);
++ return -1;
+ }
+
+ static struct tc_action_ops act_simp_ops = {
+- .kind = "simple",
+- .type = TCA_ACT_SIMP,
+- .capab = TCA_CAP_NONE,
+- .owner = THIS_MODULE,
+- .act = tcf_simp,
+- tca_use_default_ops
++ .kind = "simple",
++ .hinfo = &simp_hash_info,
++ .type = TCA_ACT_SIMP,
++ .capab = TCA_CAP_NONE,
++ .owner = THIS_MODULE,
++ .act = tcf_simp,
++ .dump = tcf_simp_dump,
++ .cleanup = tcf_simp_cleanup,
++ .init = tcf_simp_init,
++ .walk = tcf_generic_walker,
+ };
+
+ MODULE_AUTHOR("Jamal Hadi Salim(2005)");
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 7e14f14..37a1840 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -401,7 +401,7 @@ static int tc_dump_tfilter(struct sk_buf
+ if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
+ return skb->len;
+
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ if (!tcm->tcm_parent)
+ q = dev->qdisc_sleeping;
+ else
+@@ -458,7 +458,7 @@ errout:
+ if (cl)
+ cops->put(q, cl);
+ out:
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ dev_put(dev);
+ return skb->len;
+ }
+diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
+index 86cac49..09fda68 100644
+--- a/net/sched/cls_basic.c
++++ b/net/sched/cls_basic.c
+@@ -194,7 +194,7 @@ static int basic_change(struct tcf_proto
+ if (handle)
+ f->handle = handle;
+ else {
+- int i = 0x80000000;
++ unsigned int i = 0x80000000;
+ do {
+ if (++head->hgenerator == 0x7FFFFFFF)
+ head->hgenerator = 1;
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index e6973d9..e54acc6 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -50,6 +50,7 @@
+ struct fw_head
+ {
+ struct fw_filter *ht[HTSIZE];
++ u32 mask;
+ };
+
+ struct fw_filter
+@@ -101,7 +102,7 @@ static int fw_classify(struct sk_buff *s
+ struct fw_filter *f;
+ int r;
+ #ifdef CONFIG_NETFILTER
+- u32 id = skb->nfmark;
++ u32 id = skb->nfmark & head->mask;
+ #else
+ u32 id = 0;
+ #endif
+@@ -209,7 +210,9 @@ static int
+ fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
+ struct rtattr **tb, struct rtattr **tca, unsigned long base)
+ {
++ struct fw_head *head = (struct fw_head *)tp->root;
+ struct tcf_exts e;
++ u32 mask;
+ int err;
+
+ err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map);
+@@ -232,6 +235,15 @@ fw_change_attrs(struct tcf_proto *tp, st
+ }
+ #endif /* CONFIG_NET_CLS_IND */
+
++ if (tb[TCA_FW_MASK-1]) {
++ if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))
++ goto errout;
++ mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);
++ if (mask != head->mask)
++ goto errout;
++ } else if (head->mask != 0xFFFFFFFF)
++ goto errout;
++
+ tcf_exts_change(tp, &f->exts, &e);
+
+ return 0;
+@@ -267,9 +279,17 @@ static int fw_change(struct tcf_proto *t
+ return -EINVAL;
+
+ if (head == NULL) {
++ u32 mask = 0xFFFFFFFF;
++ if (tb[TCA_FW_MASK-1]) {
++ if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))
++ return -EINVAL;
++ mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);
++ }
++
+ head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);
+ if (head == NULL)
+ return -ENOBUFS;
++ head->mask = mask;
+
+ tcf_tree_lock(tp);
+ tp->root = head;
+@@ -330,6 +350,7 @@ static void fw_walk(struct tcf_proto *tp
+ static int fw_dump(struct tcf_proto *tp, unsigned long fh,
+ struct sk_buff *skb, struct tcmsg *t)
+ {
++ struct fw_head *head = (struct fw_head *)tp->root;
+ struct fw_filter *f = (struct fw_filter*)fh;
+ unsigned char *b = skb->tail;
+ struct rtattr *rta;
+@@ -351,6 +372,8 @@ static int fw_dump(struct tcf_proto *tp,
+ if (strlen(f->indev))
+ RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev);
+ #endif /* CONFIG_NET_CLS_IND */
++ if (head->mask != 0xFFFFFFFF)
++ RTA_PUT(skb, TCA_FW_MASK, 4, &head->mask);
+
+ if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0)
+ goto rtattr_failure;
+diff --git a/net/sched/estimator.c b/net/sched/estimator.c
+deleted file mode 100644
+index 0ebc98e..0000000
+--- a/net/sched/estimator.c
++++ /dev/null
+@@ -1,196 +0,0 @@
+-/*
+- * net/sched/estimator.c Simple rate estimator.
+- *
+- * 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: Alexey Kuznetsov, <kuznet at ms2.inr.ac.ru>
+- */
+-
+-#include <asm/uaccess.h>
+-#include <asm/system.h>
+-#include <linux/bitops.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/jiffies.h>
+-#include <linux/string.h>
+-#include <linux/mm.h>
+-#include <linux/socket.h>
+-#include <linux/sockios.h>
+-#include <linux/in.h>
+-#include <linux/errno.h>
+-#include <linux/interrupt.h>
+-#include <linux/netdevice.h>
+-#include <linux/skbuff.h>
+-#include <linux/rtnetlink.h>
+-#include <linux/init.h>
+-#include <net/sock.h>
+-#include <net/pkt_sched.h>
+-
+-/*
+- This code is NOT intended to be used for statistics collection,
+- its purpose is to provide a base for statistical multiplexing
+- for controlled load service.
+- If you need only statistics, run a user level daemon which
+- periodically reads byte counters.
+-
+- Unfortunately, rate estimation is not a very easy task.
+- F.e. I did not find a simple way to estimate the current peak rate
+- and even failed to formulate the problem 8)8)
+-
+- So I preferred not to built an estimator into the scheduler,
+- but run this task separately.
+- Ideally, it should be kernel thread(s), but for now it runs
+- from timers, which puts apparent top bounds on the number of rated
+- flows, has minimal overhead on small, but is enough
+- to handle controlled load service, sets of aggregates.
+-
+- We measure rate over A=(1<<interval) seconds and evaluate EWMA:
+-
+- avrate = avrate*(1-W) + rate*W
+-
+- where W is chosen as negative power of 2: W = 2^(-ewma_log)
+-
+- The resulting time constant is:
+-
+- T = A/(-ln(1-W))
+-
+-
+- NOTES.
+-
+- * The stored value for avbps is scaled by 2^5, so that maximal
+- rate is ~1Gbit, avpps is scaled by 2^10.
+-
+- * Minimal interval is HZ/4=250msec (it is the greatest common divisor
+- for HZ=100 and HZ=1024 8)), maximal interval
+- is (HZ*2^EST_MAX_INTERVAL)/4 = 8sec. Shorter intervals
+- are too expensive, longer ones can be implemented
+- at user level painlessly.
+- */
+-
+-#define EST_MAX_INTERVAL 5
+-
+-struct qdisc_estimator
+-{
+- struct qdisc_estimator *next;
+- struct tc_stats *stats;
+- spinlock_t *stats_lock;
+- unsigned interval;
+- int ewma_log;
+- u64 last_bytes;
+- u32 last_packets;
+- u32 avpps;
+- u32 avbps;
+-};
+-
+-struct qdisc_estimator_head
+-{
+- struct timer_list timer;
+- struct qdisc_estimator *list;
+-};
+-
+-static struct qdisc_estimator_head elist[EST_MAX_INTERVAL+1];
+-
+-/* Estimator array lock */
+-static DEFINE_RWLOCK(est_lock);
+-
+-static void est_timer(unsigned long arg)
+-{
+- int idx = (int)arg;
+- struct qdisc_estimator *e;
+-
+- read_lock(&est_lock);
+- for (e = elist[idx].list; e; e = e->next) {
+- struct tc_stats *st = e->stats;
+- u64 nbytes;
+- u32 npackets;
+- u32 rate;
+-
+- spin_lock(e->stats_lock);
+- nbytes = st->bytes;
+- npackets = st->packets;
+- rate = (nbytes - e->last_bytes)<<(7 - idx);
+- e->last_bytes = nbytes;
+- e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log;
+- st->bps = (e->avbps+0xF)>>5;
+-
+- rate = (npackets - e->last_packets)<<(12 - idx);
+- e->last_packets = npackets;
+- e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
+- e->stats->pps = (e->avpps+0x1FF)>>10;
+- spin_unlock(e->stats_lock);
+- }
+-
+- mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+- read_unlock(&est_lock);
+-}
+-
+-int qdisc_new_estimator(struct tc_stats *stats, spinlock_t *stats_lock, struct rtattr *opt)
+-{
+- struct qdisc_estimator *est;
+- struct tc_estimator *parm = RTA_DATA(opt);
+-
+- if (RTA_PAYLOAD(opt) < sizeof(*parm))
+- return -EINVAL;
+-
+- if (parm->interval < -2 || parm->interval > 3)
+- return -EINVAL;
+-
+- est = kzalloc(sizeof(*est), GFP_KERNEL);
+- if (est == NULL)
+- return -ENOBUFS;
+-
+- est->interval = parm->interval + 2;
+- est->stats = stats;
+- est->stats_lock = stats_lock;
+- est->ewma_log = parm->ewma_log;
+- est->last_bytes = stats->bytes;
+- est->avbps = stats->bps<<5;
+- est->last_packets = stats->packets;
+- est->avpps = stats->pps<<10;
+-
+- est->next = elist[est->interval].list;
+- if (est->next == NULL) {
+- init_timer(&elist[est->interval].timer);
+- elist[est->interval].timer.data = est->interval;
+- elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
+- elist[est->interval].timer.function = est_timer;
+- add_timer(&elist[est->interval].timer);
+- }
+- write_lock_bh(&est_lock);
+- elist[est->interval].list = est;
+- write_unlock_bh(&est_lock);
+- return 0;
+-}
+-
+-void qdisc_kill_estimator(struct tc_stats *stats)
+-{
+- int idx;
+- struct qdisc_estimator *est, **pest;
+-
+- for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
+- int killed = 0;
+- pest = &elist[idx].list;
+- while ((est=*pest) != NULL) {
+- if (est->stats != stats) {
+- pest = &est->next;
+- continue;
+- }
+-
+- write_lock_bh(&est_lock);
+- *pest = est->next;
+- write_unlock_bh(&est_lock);
+-
+- kfree(est);
+- killed++;
+- }
+- if (killed && elist[idx].list == NULL)
+- del_timer(&elist[idx].timer);
+- }
+-}
+-
+-EXPORT_SYMBOL(qdisc_kill_estimator);
+-EXPORT_SYMBOL(qdisc_new_estimator);
+diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
+index a19eff1..0b64892 100644
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -195,14 +195,14 @@ struct Qdisc *qdisc_lookup(struct net_de
+ {
+ struct Qdisc *q;
+
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ list_for_each_entry(q, &dev->qdisc_list, list) {
+ if (q->handle == handle) {
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ return q;
+ }
+ }
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ return NULL;
+ }
+
+@@ -837,7 +837,7 @@ static int tc_dump_qdisc(struct sk_buff
+ continue;
+ if (idx > s_idx)
+ s_q_idx = 0;
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ q_idx = 0;
+ list_for_each_entry(q, &dev->qdisc_list, list) {
+ if (q_idx < s_q_idx) {
+@@ -846,12 +846,12 @@ static int tc_dump_qdisc(struct sk_buff
+ }
+ if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ goto done;
+ }
+ q_idx++;
+ }
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ }
+
+ done:
+@@ -1074,7 +1074,7 @@ static int tc_dump_tclass(struct sk_buff
+ s_t = cb->args[0];
+ t = 0;
+
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ list_for_each_entry(q, &dev->qdisc_list, list) {
+ if (t < s_t || !q->ops->cl_ops ||
+ (tcm->tcm_parent &&
+@@ -1096,7 +1096,7 @@ static int tc_dump_tclass(struct sk_buff
+ break;
+ t++;
+ }
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+
+ cb->args[0] = t;
+
+diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
+index 6f91518..88c6a99 100644
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -45,11 +45,10 @@
+ The idea is the following:
+ - enqueue, dequeue are serialized via top level device
+ spinlock dev->queue_lock.
+- - tree walking is protected by read_lock_bh(qdisc_tree_lock)
++ - tree walking is protected by read_lock(qdisc_tree_lock)
+ and this lock is used only in process context.
+- - updates to tree are made under rtnl semaphore or
+- from softirq context (__qdisc_destroy rcu-callback)
+- hence this lock needs local bh disabling.
++ - updates to tree are made only under rtnl semaphore,
++ hence this lock may be made without local bh disabling.
+
+ qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!
+ */
+@@ -57,14 +56,14 @@ DEFINE_RWLOCK(qdisc_tree_lock);
+
+ void qdisc_lock_tree(struct net_device *dev)
+ {
+- write_lock_bh(&qdisc_tree_lock);
++ write_lock(&qdisc_tree_lock);
+ spin_lock_bh(&dev->queue_lock);
+ }
+
+ void qdisc_unlock_tree(struct net_device *dev)
+ {
+ spin_unlock_bh(&dev->queue_lock);
+- write_unlock_bh(&qdisc_tree_lock);
++ write_unlock(&qdisc_tree_lock);
+ }
+
+ /*
+@@ -483,20 +482,6 @@ void qdisc_reset(struct Qdisc *qdisc)
+ static void __qdisc_destroy(struct rcu_head *head)
+ {
+ struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu);
+- struct Qdisc_ops *ops = qdisc->ops;
+-
+-#ifdef CONFIG_NET_ESTIMATOR
+- gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
+-#endif
+- write_lock(&qdisc_tree_lock);
+- if (ops->reset)
+- ops->reset(qdisc);
+- if (ops->destroy)
+- ops->destroy(qdisc);
+- write_unlock(&qdisc_tree_lock);
+- module_put(ops->owner);
+-
+- dev_put(qdisc->dev);
+ kfree((char *) qdisc - qdisc->padded);
+ }
+
+@@ -504,32 +489,23 @@ static void __qdisc_destroy(struct rcu_h
+
+ void qdisc_destroy(struct Qdisc *qdisc)
+ {
+- struct list_head cql = LIST_HEAD_INIT(cql);
+- struct Qdisc *cq, *q, *n;
++ struct Qdisc_ops *ops = qdisc->ops;
+
+ if (qdisc->flags & TCQ_F_BUILTIN ||
+- !atomic_dec_and_test(&qdisc->refcnt))
++ !atomic_dec_and_test(&qdisc->refcnt))
+ return;
+
+- if (!list_empty(&qdisc->list)) {
+- if (qdisc->ops->cl_ops == NULL)
+- list_del(&qdisc->list);
+- else
+- list_move(&qdisc->list, &cql);
+- }
+-
+- /* unlink inner qdiscs from dev->qdisc_list immediately */
+- list_for_each_entry(cq, &cql, list)
+- list_for_each_entry_safe(q, n, &qdisc->dev->qdisc_list, list)
+- if (TC_H_MAJ(q->parent) == TC_H_MAJ(cq->handle)) {
+- if (q->ops->cl_ops == NULL)
+- list_del_init(&q->list);
+- else
+- list_move_tail(&q->list, &cql);
+- }
+- list_for_each_entry_safe(cq, n, &cql, list)
+- list_del_init(&cq->list);
++ list_del(&qdisc->list);
++#ifdef CONFIG_NET_ESTIMATOR
++ gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
++#endif
++ if (ops->reset)
++ ops->reset(qdisc);
++ if (ops->destroy)
++ ops->destroy(qdisc);
+
++ module_put(ops->owner);
++ dev_put(qdisc->dev);
+ call_rcu(&qdisc->q_rcu, __qdisc_destroy);
+ }
+
+@@ -549,15 +525,15 @@ void dev_activate(struct net_device *dev
+ printk(KERN_INFO "%s: activation failed\n", dev->name);
+ return;
+ }
+- write_lock_bh(&qdisc_tree_lock);
++ write_lock(&qdisc_tree_lock);
+ list_add_tail(&qdisc->list, &dev->qdisc_list);
+- write_unlock_bh(&qdisc_tree_lock);
++ write_unlock(&qdisc_tree_lock);
+ } else {
+ qdisc = &noqueue_qdisc;
+ }
+- write_lock_bh(&qdisc_tree_lock);
++ write_lock(&qdisc_tree_lock);
+ dev->qdisc_sleeping = qdisc;
+- write_unlock_bh(&qdisc_tree_lock);
++ write_unlock(&qdisc_tree_lock);
+ }
+
+ if (!netif_carrier_ok(dev))
+diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
+index 880a339..9b9c555 100644
+--- a/net/sched/sch_htb.c
++++ b/net/sched/sch_htb.c
+@@ -1,4 +1,4 @@
+-/* vim: ts=8 sw=8
++/*
+ * net/sched/sch_htb.c Hierarchical token bucket, feed tree version
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -68,218 +68,165 @@
+ one less than their parent.
+ */
+
+-#define HTB_HSIZE 16 /* classid hash size */
+-#define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */
+-#undef HTB_DEBUG /* compile debugging support (activated by tc tool) */
+-#define HTB_RATECM 1 /* whether to use rate computer */
+-#define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
+-#define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
+-#define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
+-#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */
++#define HTB_HSIZE 16 /* classid hash size */
++#define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */
++#define HTB_RATECM 1 /* whether to use rate computer */
++#define HTB_HYSTERESIS 1 /* whether to use mode hysteresis for speedup */
++#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */
+
+ #if HTB_VER >> 16 != TC_HTB_PROTOVER
+ #error "Mismatched sch_htb.c and pkt_sch.h"
+ #endif
+
+-/* debugging support; S is subsystem, these are defined:
+- 0 - netlink messages
+- 1 - enqueue
+- 2 - drop & requeue
+- 3 - dequeue main
+- 4 - dequeue one prio DRR part
+- 5 - dequeue class accounting
+- 6 - class overlimit status computation
+- 7 - hint tree
+- 8 - event queue
+- 10 - rate estimator
+- 11 - classifier
+- 12 - fast dequeue cache
+-
+- L is level; 0 = none, 1 = basic info, 2 = detailed, 3 = full
+- q->debug uint32 contains 16 2-bit fields one for subsystem starting
+- from LSB
+- */
+-#ifdef HTB_DEBUG
+-#define HTB_DBG_COND(S,L) (((q->debug>>(2*S))&3) >= L)
+-#define HTB_DBG(S,L,FMT,ARG...) if (HTB_DBG_COND(S,L)) \
+- printk(KERN_DEBUG FMT,##ARG)
+-#define HTB_CHCL(cl) BUG_TRAP((cl)->magic == HTB_CMAGIC)
+-#define HTB_PASSQ q,
+-#define HTB_ARGQ struct htb_sched *q,
+-#define static
+-#undef __inline__
+-#define __inline__
+-#undef inline
+-#define inline
+-#define HTB_CMAGIC 0xFEFAFEF1
+-#define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \
+- if ((N)->rb_color == -1) break; \
+- rb_erase(N,R); \
+- (N)->rb_color = -1; } while (0)
+-#else
+-#define HTB_DBG_COND(S,L) (0)
+-#define HTB_DBG(S,L,FMT,ARG...)
+-#define HTB_PASSQ
+-#define HTB_ARGQ
+-#define HTB_CHCL(cl)
+-#define htb_safe_rb_erase(N,R) rb_erase(N,R)
+-#endif
+-
+-
+ /* used internaly to keep status of single class */
+ enum htb_cmode {
+- HTB_CANT_SEND, /* class can't send and can't borrow */
+- HTB_MAY_BORROW, /* class can't send but may borrow */
+- HTB_CAN_SEND /* class can send */
++ HTB_CANT_SEND, /* class can't send and can't borrow */
++ HTB_MAY_BORROW, /* class can't send but may borrow */
++ HTB_CAN_SEND /* class can send */
+ };
+
+ /* interior & leaf nodes; props specific to leaves are marked L: */
+-struct htb_class
+-{
+-#ifdef HTB_DEBUG
+- unsigned magic;
+-#endif
+- /* general class parameters */
+- u32 classid;
+- struct gnet_stats_basic bstats;
+- struct gnet_stats_queue qstats;
+- struct gnet_stats_rate_est rate_est;
+- struct tc_htb_xstats xstats;/* our special stats */
+- int refcnt; /* usage count of this class */
++struct htb_class {
++ /* general class parameters */
++ u32 classid;
++ struct gnet_stats_basic bstats;
++ struct gnet_stats_queue qstats;
++ struct gnet_stats_rate_est rate_est;
++ struct tc_htb_xstats xstats; /* our special stats */
++ int refcnt; /* usage count of this class */
+
+ #ifdef HTB_RATECM
+- /* rate measurement counters */
+- unsigned long rate_bytes,sum_bytes;
+- unsigned long rate_packets,sum_packets;
++ /* rate measurement counters */
++ unsigned long rate_bytes, sum_bytes;
++ unsigned long rate_packets, sum_packets;
+ #endif
+
+- /* topology */
+- int level; /* our level (see above) */
+- struct htb_class *parent; /* parent class */
+- struct list_head hlist; /* classid hash list item */
+- struct list_head sibling; /* sibling list item */
+- struct list_head children; /* children list */
+-
+- union {
+- struct htb_class_leaf {
+- struct Qdisc *q;
+- int prio;
+- int aprio;
+- int quantum;
+- int deficit[TC_HTB_MAXDEPTH];
+- struct list_head drop_list;
+- } leaf;
+- struct htb_class_inner {
+- struct rb_root feed[TC_HTB_NUMPRIO]; /* feed trees */
+- struct rb_node *ptr[TC_HTB_NUMPRIO]; /* current class ptr */
+- /* When class changes from state 1->2 and disconnects from
+- parent's feed then we lost ptr value and start from the
+- first child again. Here we store classid of the
+- last valid ptr (used when ptr is NULL). */
+- u32 last_ptr_id[TC_HTB_NUMPRIO];
+- } inner;
+- } un;
+- struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */
+- struct rb_node pq_node; /* node for event queue */
+- unsigned long pq_key; /* the same type as jiffies global */
+-
+- int prio_activity; /* for which prios are we active */
+- enum htb_cmode cmode; /* current mode of the class */
+-
+- /* class attached filters */
+- struct tcf_proto *filter_list;
+- int filter_cnt;
+-
+- int warned; /* only one warning about non work conserving .. */
+-
+- /* token bucket parameters */
+- struct qdisc_rate_table *rate; /* rate table of the class itself */
+- struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */
+- long buffer,cbuffer; /* token bucket depth/rate */
+- psched_tdiff_t mbuffer; /* max wait time */
+- long tokens,ctokens; /* current number of tokens */
+- psched_time_t t_c; /* checkpoint time */
++ /* topology */
++ int level; /* our level (see above) */
++ struct htb_class *parent; /* parent class */
++ struct hlist_node hlist; /* classid hash list item */
++ struct list_head sibling; /* sibling list item */
++ struct list_head children; /* children list */
++
++ union {
++ struct htb_class_leaf {
++ struct Qdisc *q;
++ int prio;
++ int aprio;
++ int quantum;
++ int deficit[TC_HTB_MAXDEPTH];
++ struct list_head drop_list;
++ } leaf;
++ struct htb_class_inner {
++ struct rb_root feed[TC_HTB_NUMPRIO]; /* feed trees */
++ struct rb_node *ptr[TC_HTB_NUMPRIO]; /* current class ptr */
++ /* When class changes from state 1->2 and disconnects from
++ parent's feed then we lost ptr value and start from the
++ first child again. Here we store classid of the
++ last valid ptr (used when ptr is NULL). */
++ u32 last_ptr_id[TC_HTB_NUMPRIO];
++ } inner;
++ } un;
++ struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */
++ struct rb_node pq_node; /* node for event queue */
++ unsigned long pq_key; /* the same type as jiffies global */
++
++ int prio_activity; /* for which prios are we active */
++ enum htb_cmode cmode; /* current mode of the class */
++
++ /* class attached filters */
++ struct tcf_proto *filter_list;
++ int filter_cnt;
++
++ int warned; /* only one warning about non work conserving .. */
++
++ /* token bucket parameters */
++ struct qdisc_rate_table *rate; /* rate table of the class itself */
++ struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */
++ long buffer, cbuffer; /* token bucket depth/rate */
++ psched_tdiff_t mbuffer; /* max wait time */
++ long tokens, ctokens; /* current number of tokens */
++ psched_time_t t_c; /* checkpoint time */
+ };
+
+ /* TODO: maybe compute rate when size is too large .. or drop ? */
+-static __inline__ long L2T(struct htb_class *cl,struct qdisc_rate_table *rate,
+- int size)
+-{
+- int slot = size >> rate->rate.cell_log;
+- if (slot > 255) {
+- cl->xstats.giants++;
+- slot = 255;
+- }
+- return rate->data[slot];
++static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
++ int size)
++{
++ int slot = size >> rate->rate.cell_log;
++ if (slot > 255) {
++ cl->xstats.giants++;
++ slot = 255;
++ }
++ return rate->data[slot];
+ }
+
+-struct htb_sched
+-{
+- struct list_head root; /* root classes list */
+- struct list_head hash[HTB_HSIZE]; /* hashed by classid */
+- struct list_head drops[TC_HTB_NUMPRIO]; /* active leaves (for drops) */
+-
+- /* self list - roots of self generating tree */
+- struct rb_root row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
+- int row_mask[TC_HTB_MAXDEPTH];
+- struct rb_node *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
+- u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
+-
+- /* self wait list - roots of wait PQs per row */
+- struct rb_root wait_pq[TC_HTB_MAXDEPTH];
+-
+- /* time of nearest event per level (row) */
+- unsigned long near_ev_cache[TC_HTB_MAXDEPTH];
+-
+- /* cached value of jiffies in dequeue */
+- unsigned long jiffies;
+-
+- /* whether we hit non-work conserving class during this dequeue; we use */
+- int nwc_hit; /* this to disable mindelay complaint in dequeue */
+-
+- int defcls; /* class where unclassified flows go to */
+- u32 debug; /* subsystem debug levels */
+-
+- /* filters for qdisc itself */
+- struct tcf_proto *filter_list;
+- int filter_cnt;
+-
+- int rate2quantum; /* quant = rate / rate2quantum */
+- psched_time_t now; /* cached dequeue time */
+- struct timer_list timer; /* send delay timer */
++struct htb_sched {
++ struct list_head root; /* root classes list */
++ struct hlist_head hash[HTB_HSIZE]; /* hashed by classid */
++ struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */
++
++ /* self list - roots of self generating tree */
++ struct rb_root row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
++ int row_mask[TC_HTB_MAXDEPTH];
++ struct rb_node *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
++ u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
++
++ /* self wait list - roots of wait PQs per row */
++ struct rb_root wait_pq[TC_HTB_MAXDEPTH];
++
++ /* time of nearest event per level (row) */
++ unsigned long near_ev_cache[TC_HTB_MAXDEPTH];
++
++ /* cached value of jiffies in dequeue */
++ unsigned long jiffies;
++
++ /* whether we hit non-work conserving class during this dequeue; we use */
++ int nwc_hit; /* this to disable mindelay complaint in dequeue */
++
++ int defcls; /* class where unclassified flows go to */
++
++ /* filters for qdisc itself */
++ struct tcf_proto *filter_list;
++ int filter_cnt;
++
++ int rate2quantum; /* quant = rate / rate2quantum */
++ psched_time_t now; /* cached dequeue time */
++ struct timer_list timer; /* send delay timer */
+ #ifdef HTB_RATECM
+- struct timer_list rttim; /* rate computer timer */
+- int recmp_bucket; /* which hash bucket to recompute next */
++ struct timer_list rttim; /* rate computer timer */
++ int recmp_bucket; /* which hash bucket to recompute next */
+ #endif
+-
+- /* non shaped skbs; let them go directly thru */
+- struct sk_buff_head direct_queue;
+- int direct_qlen; /* max qlen of above */
+
+- long direct_pkts;
++ /* non shaped skbs; let them go directly thru */
++ struct sk_buff_head direct_queue;
++ int direct_qlen; /* max qlen of above */
++
++ long direct_pkts;
+ };
+
+ /* compute hash of size HTB_HSIZE for given handle */
+-static __inline__ int htb_hash(u32 h)
++static inline int htb_hash(u32 h)
+ {
+ #if HTB_HSIZE != 16
+- #error "Declare new hash for your HTB_HSIZE"
++#error "Declare new hash for your HTB_HSIZE"
+ #endif
+- h ^= h>>8; /* stolen from cbq_hash */
+- h ^= h>>4;
+- return h & 0xf;
++ h ^= h >> 8; /* stolen from cbq_hash */
++ h ^= h >> 4;
++ return h & 0xf;
+ }
+
+ /* find class in global hash table using given handle */
+-static __inline__ struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
++static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- struct list_head *p;
+- if (TC_H_MAJ(handle) != sch->handle)
++ struct hlist_node *p;
++ struct htb_class *cl;
++
++ if (TC_H_MAJ(handle) != sch->handle)
+ return NULL;
+-
+- list_for_each (p,q->hash+htb_hash(handle)) {
+- struct htb_class *cl = list_entry(p,struct htb_class,hlist);
++
++ hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) {
+ if (cl->classid == handle)
+ return cl;
+ }
+@@ -304,7 +251,8 @@ static inline u32 htb_classid(struct htb
+ return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC;
+ }
+
+-static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
++static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
++ int *qerr)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+ struct htb_class *cl;
+@@ -316,8 +264,8 @@ static struct htb_class *htb_classify(st
+ note that nfmark can be used too by attaching filter fw with no
+ rules in it */
+ if (skb->priority == sch->handle)
+- return HTB_DIRECT; /* X:0 (direct flow) selected */
+- if ((cl = htb_find(skb->priority,sch)) != NULL && cl->level == 0)
++ return HTB_DIRECT; /* X:0 (direct flow) selected */
++ if ((cl = htb_find(skb->priority, sch)) != NULL && cl->level == 0)
+ return cl;
+
+ *qerr = NET_XMIT_BYPASS;
+@@ -326,7 +274,7 @@ static struct htb_class *htb_classify(st
+ #ifdef CONFIG_NET_CLS_ACT
+ switch (result) {
+ case TC_ACT_QUEUED:
+- case TC_ACT_STOLEN:
++ case TC_ACT_STOLEN:
+ *qerr = NET_XMIT_SUCCESS;
+ case TC_ACT_SHOT:
+ return NULL;
+@@ -335,97 +283,44 @@ static struct htb_class *htb_classify(st
+ if (result == TC_POLICE_SHOT)
+ return HTB_DIRECT;
+ #endif
+- if ((cl = (void*)res.class) == NULL) {
++ if ((cl = (void *)res.class) == NULL) {
+ if (res.classid == sch->handle)
+- return HTB_DIRECT; /* X:0 (direct flow) */
+- if ((cl = htb_find(res.classid,sch)) == NULL)
+- break; /* filter selected invalid classid */
++ return HTB_DIRECT; /* X:0 (direct flow) */
++ if ((cl = htb_find(res.classid, sch)) == NULL)
++ break; /* filter selected invalid classid */
+ }
+ if (!cl->level)
+- return cl; /* we hit leaf; return it */
++ return cl; /* we hit leaf; return it */
+
+ /* we have got inner class; apply inner filter chain */
+ tcf = cl->filter_list;
+ }
+ /* classification failed; try to use default class */
+- cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle),q->defcls),sch);
++ cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch);
+ if (!cl || cl->level)
+- return HTB_DIRECT; /* bad default .. this is safe bet */
++ return HTB_DIRECT; /* bad default .. this is safe bet */
+ return cl;
+ }
+
+-#ifdef HTB_DEBUG
+-static void htb_next_rb_node(struct rb_node **n);
+-#define HTB_DUMTREE(root,memb) if(root) { \
+- struct rb_node *n = (root)->rb_node; \
+- while (n->rb_left) n = n->rb_left; \
+- while (n) { \
+- struct htb_class *cl = rb_entry(n, struct htb_class, memb); \
+- printk(" %x",cl->classid); htb_next_rb_node (&n); \
+- } }
+-
+-static void htb_debug_dump (struct htb_sched *q)
+-{
+- int i,p;
+- printk(KERN_DEBUG "htb*g j=%lu lj=%lu\n",jiffies,q->jiffies);
+- /* rows */
+- for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) {
+- printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]);
+- for (p=0;p<TC_HTB_NUMPRIO;p++) {
+- if (!q->row[i][p].rb_node) continue;
+- printk(" p%d:",p);
+- HTB_DUMTREE(q->row[i]+p,node[p]);
+- }
+- printk("\n");
+- }
+- /* classes */
+- for (i = 0; i < HTB_HSIZE; i++) {
+- struct list_head *l;
+- list_for_each (l,q->hash+i) {
+- struct htb_class *cl = list_entry(l,struct htb_class,hlist);
+- long diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer);
+- printk(KERN_DEBUG "htb*c%x m=%d t=%ld c=%ld pq=%lu df=%ld ql=%d "
+- "pa=%x f:",
+- cl->classid,cl->cmode,cl->tokens,cl->ctokens,
+- cl->pq_node.rb_color==-1?0:cl->pq_key,diff,
+- cl->level?0:cl->un.leaf.q->q.qlen,cl->prio_activity);
+- if (cl->level)
+- for (p=0;p<TC_HTB_NUMPRIO;p++) {
+- if (!cl->un.inner.feed[p].rb_node) continue;
+- printk(" p%d a=%x:",p,cl->un.inner.ptr[p]?rb_entry(cl->un.inner.ptr[p], struct htb_class,node[p])->classid:0);
+- HTB_DUMTREE(cl->un.inner.feed+p,node[p]);
+- }
+- printk("\n");
+- }
+- }
+-}
+-#endif
+ /**
+ * htb_add_to_id_tree - adds class to the round robin list
+ *
+ * Routine adds class to the list (actually tree) sorted by classid.
+ * Make sure that class is not already on such list for given prio.
+ */
+-static void htb_add_to_id_tree (HTB_ARGQ struct rb_root *root,
+- struct htb_class *cl,int prio)
++static void htb_add_to_id_tree(struct rb_root *root,
++ struct htb_class *cl, int prio)
+ {
+ struct rb_node **p = &root->rb_node, *parent = NULL;
+- HTB_DBG(7,3,"htb_add_id_tree cl=%X prio=%d\n",cl->classid,prio);
+-#ifdef HTB_DEBUG
+- if (cl->node[prio].rb_color != -1) { BUG_TRAP(0); return; }
+- HTB_CHCL(cl);
+- if (*p) {
+- struct htb_class *x = rb_entry(*p,struct htb_class,node[prio]);
+- HTB_CHCL(x);
+- }
+-#endif
++
+ while (*p) {
+- struct htb_class *c; parent = *p;
++ struct htb_class *c;
++ parent = *p;
+ c = rb_entry(parent, struct htb_class, node[prio]);
+- HTB_CHCL(c);
++
+ if (cl->classid > c->classid)
+ p = &parent->rb_right;
+- else
++ else
+ p = &parent->rb_left;
+ }
+ rb_link_node(&cl->node[prio], parent, p);
+@@ -439,17 +334,11 @@ static void htb_add_to_id_tree (HTB_ARGQ
+ * change its mode in cl->pq_key microseconds. Make sure that class is not
+ * already in the queue.
+ */
+-static void htb_add_to_wait_tree (struct htb_sched *q,
+- struct htb_class *cl,long delay,int debug_hint)
++static void htb_add_to_wait_tree(struct htb_sched *q,
++ struct htb_class *cl, long delay)
+ {
+ struct rb_node **p = &q->wait_pq[cl->level].rb_node, *parent = NULL;
+- HTB_DBG(7,3,"htb_add_wt cl=%X key=%lu\n",cl->classid,cl->pq_key);
+-#ifdef HTB_DEBUG
+- if (cl->pq_node.rb_color != -1) { BUG_TRAP(0); return; }
+- HTB_CHCL(cl);
+- if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit())
+- printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint);
+-#endif
++
+ cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay);
+ if (cl->pq_key == q->jiffies)
+ cl->pq_key++;
+@@ -457,13 +346,14 @@ static void htb_add_to_wait_tree (struct
+ /* update the nearest event cache */
+ if (time_after(q->near_ev_cache[cl->level], cl->pq_key))
+ q->near_ev_cache[cl->level] = cl->pq_key;
+-
++
+ while (*p) {
+- struct htb_class *c; parent = *p;
++ struct htb_class *c;
++ parent = *p;
+ c = rb_entry(parent, struct htb_class, pq_node);
+ if (time_after_eq(cl->pq_key, c->pq_key))
+ p = &parent->rb_right;
+- else
++ else
+ p = &parent->rb_left;
+ }
+ rb_link_node(&cl->pq_node, parent, p);
+@@ -476,7 +366,7 @@ static void htb_add_to_wait_tree (struct
+ * When we are past last key we return NULL.
+ * Average complexity is 2 steps per call.
+ */
+-static void htb_next_rb_node(struct rb_node **n)
++static inline void htb_next_rb_node(struct rb_node **n)
+ {
+ *n = rb_next(*n);
+ }
+@@ -487,42 +377,51 @@ static void htb_next_rb_node(struct rb_n
+ * The class is added to row at priorities marked in mask.
+ * It does nothing if mask == 0.
+ */
+-static inline void htb_add_class_to_row(struct htb_sched *q,
+- struct htb_class *cl,int mask)
++static inline void htb_add_class_to_row(struct htb_sched *q,
++ struct htb_class *cl, int mask)
+ {
+- HTB_DBG(7,2,"htb_addrow cl=%X mask=%X rmask=%X\n",
+- cl->classid,mask,q->row_mask[cl->level]);
+- HTB_CHCL(cl);
+ q->row_mask[cl->level] |= mask;
+ while (mask) {
+ int prio = ffz(~mask);
+ mask &= ~(1 << prio);
+- htb_add_to_id_tree(HTB_PASSQ q->row[cl->level]+prio,cl,prio);
++ htb_add_to_id_tree(q->row[cl->level] + prio, cl, prio);
+ }
+ }
+
++/* If this triggers, it is a bug in this code, but it need not be fatal */
++static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root)
++{
++ if (RB_EMPTY_NODE(rb)) {
++ WARN_ON(1);
++ } else {
++ rb_erase(rb, root);
++ RB_CLEAR_NODE(rb);
++ }
++}
++
++
+ /**
+ * htb_remove_class_from_row - removes class from its row
+ *
+ * The class is removed from row at priorities marked in mask.
+ * It does nothing if mask == 0.
+ */
+-static __inline__ void htb_remove_class_from_row(struct htb_sched *q,
+- struct htb_class *cl,int mask)
++static inline void htb_remove_class_from_row(struct htb_sched *q,
++ struct htb_class *cl, int mask)
+ {
+ int m = 0;
+- HTB_CHCL(cl);
++
+ while (mask) {
+ int prio = ffz(~mask);
++
+ mask &= ~(1 << prio);
+- if (q->ptr[cl->level][prio] == cl->node+prio)
+- htb_next_rb_node(q->ptr[cl->level]+prio);
+- htb_safe_rb_erase(cl->node + prio,q->row[cl->level]+prio);
+- if (!q->row[cl->level][prio].rb_node)
++ if (q->ptr[cl->level][prio] == cl->node + prio)
++ htb_next_rb_node(q->ptr[cl->level] + prio);
++
++ htb_safe_rb_erase(cl->node + prio, q->row[cl->level] + prio);
++ if (!q->row[cl->level][prio].rb_node)
+ m |= 1 << prio;
+ }
+- HTB_DBG(7,2,"htb_delrow cl=%X mask=%X rmask=%X maskdel=%X\n",
+- cl->classid,mask,q->row_mask[cl->level],m);
+ q->row_mask[cl->level] &= ~m;
+ }
+
+@@ -533,34 +432,31 @@ static __inline__ void htb_remove_class_
+ * for priorities it is participating on. cl->cmode must be new
+ * (activated) mode. It does nothing if cl->prio_activity == 0.
+ */
+-static void htb_activate_prios(struct htb_sched *q,struct htb_class *cl)
++static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl)
+ {
+ struct htb_class *p = cl->parent;
+- long m,mask = cl->prio_activity;
+- HTB_DBG(7,2,"htb_act_prios cl=%X mask=%lX cmode=%d\n",cl->classid,mask,cl->cmode);
+- HTB_CHCL(cl);
++ long m, mask = cl->prio_activity;
+
+ while (cl->cmode == HTB_MAY_BORROW && p && mask) {
+- HTB_CHCL(p);
+- m = mask; while (m) {
++ m = mask;
++ while (m) {
+ int prio = ffz(~m);
+ m &= ~(1 << prio);
+-
++
+ if (p->un.inner.feed[prio].rb_node)
+ /* parent already has its feed in use so that
+ reset bit in mask as parent is already ok */
+ mask &= ~(1 << prio);
+-
+- htb_add_to_id_tree(HTB_PASSQ p->un.inner.feed+prio,cl,prio);
++
++ htb_add_to_id_tree(p->un.inner.feed + prio, cl, prio);
+ }
+- HTB_DBG(7,3,"htb_act_pr_aft p=%X pact=%X mask=%lX pmode=%d\n",
+- p->classid,p->prio_activity,mask,p->cmode);
+ p->prio_activity |= mask;
+- cl = p; p = cl->parent;
+- HTB_CHCL(cl);
++ cl = p;
++ p = cl->parent;
++
+ }
+ if (cl->cmode == HTB_CAN_SEND && mask)
+- htb_add_class_to_row(q,cl,mask);
++ htb_add_class_to_row(q, cl, mask);
+ }
+
+ /**
+@@ -573,39 +469,52 @@ static void htb_activate_prios(struct ht
+ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl)
+ {
+ struct htb_class *p = cl->parent;
+- long m,mask = cl->prio_activity;
+- HTB_DBG(7,2,"htb_deact_prios cl=%X mask=%lX cmode=%d\n",cl->classid,mask,cl->cmode);
+- HTB_CHCL(cl);
++ long m, mask = cl->prio_activity;
+
+ while (cl->cmode == HTB_MAY_BORROW && p && mask) {
+- m = mask; mask = 0;
++ m = mask;
++ mask = 0;
+ while (m) {
+ int prio = ffz(~m);
+ m &= ~(1 << prio);
+-
+- if (p->un.inner.ptr[prio] == cl->node+prio) {
++
++ if (p->un.inner.ptr[prio] == cl->node + prio) {
+ /* we are removing child which is pointed to from
+ parent feed - forget the pointer but remember
+ classid */
+ p->un.inner.last_ptr_id[prio] = cl->classid;
+ p->un.inner.ptr[prio] = NULL;
+ }
+-
+- htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio);
+-
+- if (!p->un.inner.feed[prio].rb_node)
++
++ htb_safe_rb_erase(cl->node + prio, p->un.inner.feed + prio);
++
++ if (!p->un.inner.feed[prio].rb_node)
+ mask |= 1 << prio;
+ }
+- HTB_DBG(7,3,"htb_deact_pr_aft p=%X pact=%X mask=%lX pmode=%d\n",
+- p->classid,p->prio_activity,mask,p->cmode);
++
+ p->prio_activity &= ~mask;
+- cl = p; p = cl->parent;
+- HTB_CHCL(cl);
++ cl = p;
++ p = cl->parent;
++
+ }
+- if (cl->cmode == HTB_CAN_SEND && mask)
+- htb_remove_class_from_row(q,cl,mask);
++ if (cl->cmode == HTB_CAN_SEND && mask)
++ htb_remove_class_from_row(q, cl, mask);
+ }
+
++#if HTB_HYSTERESIS
++static inline long htb_lowater(const struct htb_class *cl)
++{
++ return cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : 0;
++}
++static inline long htb_hiwater(const struct htb_class *cl)
++{
++ return cl->cmode == HTB_CAN_SEND ? -cl->buffer : 0;
++}
++#else
++#define htb_lowater(cl) (0)
++#define htb_hiwater(cl) (0)
++#endif
++
+ /**
+ * htb_class_mode - computes and returns current class mode
+ *
+@@ -617,28 +526,21 @@ static void htb_deactivate_prios(struct
+ * 0 .. -cl->{c,}buffer range. It is meant to limit number of
+ * mode transitions per time unit. The speed gain is about 1/6.
+ */
+-static __inline__ enum htb_cmode
+-htb_class_mode(struct htb_class *cl,long *diff)
++static inline enum htb_cmode
++htb_class_mode(struct htb_class *cl, long *diff)
+ {
+- long toks;
++ long toks;
+
+- if ((toks = (cl->ctokens + *diff)) < (
+-#if HTB_HYSTERESIS
+- cl->cmode != HTB_CANT_SEND ? -cl->cbuffer :
+-#endif
+- 0)) {
+- *diff = -toks;
+- return HTB_CANT_SEND;
+- }
+- if ((toks = (cl->tokens + *diff)) >= (
+-#if HTB_HYSTERESIS
+- cl->cmode == HTB_CAN_SEND ? -cl->buffer :
+-#endif
+- 0))
+- return HTB_CAN_SEND;
++ if ((toks = (cl->ctokens + *diff)) < htb_lowater(cl)) {
++ *diff = -toks;
++ return HTB_CANT_SEND;
++ }
+
+- *diff = -toks;
+- return HTB_MAY_BORROW;
++ if ((toks = (cl->tokens + *diff)) >= htb_hiwater(cl))
++ return HTB_CAN_SEND;
++
++ *diff = -toks;
++ return HTB_MAY_BORROW;
+ }
+
+ /**
+@@ -650,24 +552,21 @@ htb_class_mode(struct htb_class *cl,long
+ * be different from old one and cl->pq_key has to be valid if changing
+ * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree).
+ */
+-static void
++static void
+ htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long *diff)
+-{
+- enum htb_cmode new_mode = htb_class_mode(cl,diff);
+-
+- HTB_CHCL(cl);
+- HTB_DBG(7,1,"htb_chging_clmode %d->%d cl=%X\n",cl->cmode,new_mode,cl->classid);
++{
++ enum htb_cmode new_mode = htb_class_mode(cl, diff);
+
+ if (new_mode == cl->cmode)
+- return;
+-
+- if (cl->prio_activity) { /* not necessary: speed optimization */
+- if (cl->cmode != HTB_CANT_SEND)
+- htb_deactivate_prios(q,cl);
++ return;
++
++ if (cl->prio_activity) { /* not necessary: speed optimization */
++ if (cl->cmode != HTB_CANT_SEND)
++ htb_deactivate_prios(q, cl);
+ cl->cmode = new_mode;
+- if (new_mode != HTB_CANT_SEND)
+- htb_activate_prios(q,cl);
+- } else
++ if (new_mode != HTB_CANT_SEND)
++ htb_activate_prios(q, cl);
++ } else
+ cl->cmode = new_mode;
+ }
+
+@@ -678,14 +577,15 @@ htb_change_class_mode(struct htb_sched *
+ * for the prio. It can be called on already active leaf safely.
+ * It also adds leaf into droplist.
+ */
+-static __inline__ void htb_activate(struct htb_sched *q,struct htb_class *cl)
++static inline void htb_activate(struct htb_sched *q, struct htb_class *cl)
+ {
+ BUG_TRAP(!cl->level && cl->un.leaf.q && cl->un.leaf.q->q.qlen);
+- HTB_CHCL(cl);
++
+ if (!cl->prio_activity) {
+ cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio);
+- htb_activate_prios(q,cl);
+- list_add_tail(&cl->un.leaf.drop_list,q->drops+cl->un.leaf.aprio);
++ htb_activate_prios(q, cl);
++ list_add_tail(&cl->un.leaf.drop_list,
++ q->drops + cl->un.leaf.aprio);
+ }
+ }
+
+@@ -695,120 +595,120 @@ static __inline__ void htb_activate(stru
+ * Make sure that leaf is active. In the other words it can't be called
+ * with non-active leaf. It also removes class from the drop list.
+ */
+-static __inline__ void
+-htb_deactivate(struct htb_sched *q,struct htb_class *cl)
++static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl)
+ {
+ BUG_TRAP(cl->prio_activity);
+- HTB_CHCL(cl);
+- htb_deactivate_prios(q,cl);
++
++ htb_deactivate_prios(q, cl);
+ cl->prio_activity = 0;
+ list_del_init(&cl->un.leaf.drop_list);
+ }
+
+ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+- int ret;
+- struct htb_sched *q = qdisc_priv(sch);
+- struct htb_class *cl = htb_classify(skb,sch,&ret);
+-
+- if (cl == HTB_DIRECT) {
+- /* enqueue to helper queue */
+- if (q->direct_queue.qlen < q->direct_qlen) {
+- __skb_queue_tail(&q->direct_queue, skb);
+- q->direct_pkts++;
+- } else {
+- kfree_skb(skb);
+- sch->qstats.drops++;
+- return NET_XMIT_DROP;
+- }
++ int ret;
++ struct htb_sched *q = qdisc_priv(sch);
++ struct htb_class *cl = htb_classify(skb, sch, &ret);
++
++ if (cl == HTB_DIRECT) {
++ /* enqueue to helper queue */
++ if (q->direct_queue.qlen < q->direct_qlen) {
++ __skb_queue_tail(&q->direct_queue, skb);
++ q->direct_pkts++;
++ } else {
++ kfree_skb(skb);
++ sch->qstats.drops++;
++ return NET_XMIT_DROP;
++ }
+ #ifdef CONFIG_NET_CLS_ACT
+- } else if (!cl) {
+- if (ret == NET_XMIT_BYPASS)
+- sch->qstats.drops++;
+- kfree_skb (skb);
+- return ret;
++ } else if (!cl) {
++ if (ret == NET_XMIT_BYPASS)
++ sch->qstats.drops++;
++ kfree_skb(skb);
++ return ret;
+ #endif
+- } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
+- sch->qstats.drops++;
+- cl->qstats.drops++;
+- return NET_XMIT_DROP;
+- } else {
+- cl->bstats.packets++; cl->bstats.bytes += skb->len;
+- htb_activate (q,cl);
+- }
+-
+- sch->q.qlen++;
+- sch->bstats.packets++; sch->bstats.bytes += skb->len;
+- HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb);
+- return NET_XMIT_SUCCESS;
++ } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) !=
++ NET_XMIT_SUCCESS) {
++ sch->qstats.drops++;
++ cl->qstats.drops++;
++ return NET_XMIT_DROP;
++ } else {
++ cl->bstats.packets++;
++ cl->bstats.bytes += skb->len;
++ htb_activate(q, cl);
++ }
++
++ sch->q.qlen++;
++ sch->bstats.packets++;
++ sch->bstats.bytes += skb->len;
++ return NET_XMIT_SUCCESS;
+ }
+
+ /* TODO: requeuing packet charges it to policers again !! */
+ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+- struct htb_sched *q = qdisc_priv(sch);
+- int ret = NET_XMIT_SUCCESS;
+- struct htb_class *cl = htb_classify(skb,sch, &ret);
+- struct sk_buff *tskb;
+-
+- if (cl == HTB_DIRECT || !cl) {
+- /* enqueue to helper queue */
+- if (q->direct_queue.qlen < q->direct_qlen && cl) {
+- __skb_queue_head(&q->direct_queue, skb);
+- } else {
+- __skb_queue_head(&q->direct_queue, skb);
+- tskb = __skb_dequeue_tail(&q->direct_queue);
+- kfree_skb (tskb);
+- sch->qstats.drops++;
+- return NET_XMIT_CN;
+- }
+- } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
+- sch->qstats.drops++;
+- cl->qstats.drops++;
+- return NET_XMIT_DROP;
+- } else
+- htb_activate (q,cl);
+-
+- sch->q.qlen++;
+- sch->qstats.requeues++;
+- HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb);
+- return NET_XMIT_SUCCESS;
++ struct htb_sched *q = qdisc_priv(sch);
++ int ret = NET_XMIT_SUCCESS;
++ struct htb_class *cl = htb_classify(skb, sch, &ret);
++ struct sk_buff *tskb;
++
++ if (cl == HTB_DIRECT || !cl) {
++ /* enqueue to helper queue */
++ if (q->direct_queue.qlen < q->direct_qlen && cl) {
++ __skb_queue_head(&q->direct_queue, skb);
++ } else {
++ __skb_queue_head(&q->direct_queue, skb);
++ tskb = __skb_dequeue_tail(&q->direct_queue);
++ kfree_skb(tskb);
++ sch->qstats.drops++;
++ return NET_XMIT_CN;
++ }
++ } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) !=
++ NET_XMIT_SUCCESS) {
++ sch->qstats.drops++;
++ cl->qstats.drops++;
++ return NET_XMIT_DROP;
++ } else
++ htb_activate(q, cl);
++
++ sch->q.qlen++;
++ sch->qstats.requeues++;
++ return NET_XMIT_SUCCESS;
+ }
+
+ static void htb_timer(unsigned long arg)
+ {
+- struct Qdisc *sch = (struct Qdisc*)arg;
+- sch->flags &= ~TCQ_F_THROTTLED;
+- wmb();
+- netif_schedule(sch->dev);
++ struct Qdisc *sch = (struct Qdisc *)arg;
++ sch->flags &= ~TCQ_F_THROTTLED;
++ wmb();
++ netif_schedule(sch->dev);
+ }
+
+ #ifdef HTB_RATECM
+ #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
+ static void htb_rate_timer(unsigned long arg)
+ {
+- struct Qdisc *sch = (struct Qdisc*)arg;
++ struct Qdisc *sch = (struct Qdisc *)arg;
+ struct htb_sched *q = qdisc_priv(sch);
+- struct list_head *p;
++ struct hlist_node *p;
++ struct htb_class *cl;
++
+
+ /* lock queue so that we can muck with it */
+- HTB_QLOCK(sch);
+- HTB_DBG(10,1,"htb_rttmr j=%ld\n",jiffies);
++ spin_lock_bh(&sch->dev->queue_lock);
+
+ q->rttim.expires = jiffies + HZ;
+ add_timer(&q->rttim);
+
+ /* scan and recompute one bucket at time */
+- if (++q->recmp_bucket >= HTB_HSIZE)
++ if (++q->recmp_bucket >= HTB_HSIZE)
+ q->recmp_bucket = 0;
+- list_for_each (p,q->hash+q->recmp_bucket) {
+- struct htb_class *cl = list_entry(p,struct htb_class,hlist);
+- HTB_DBG(10,2,"htb_rttmr_cl cl=%X sbyte=%lu spkt=%lu\n",
+- cl->classid,cl->sum_bytes,cl->sum_packets);
+- RT_GEN (cl->sum_bytes,cl->rate_bytes);
+- RT_GEN (cl->sum_packets,cl->rate_packets);
++
++ hlist_for_each_entry(cl,p, q->hash + q->recmp_bucket, hlist) {
++ RT_GEN(cl->sum_bytes, cl->rate_bytes);
++ RT_GEN(cl->sum_packets, cl->rate_packets);
+ }
+- HTB_QUNLOCK(sch);
++ spin_unlock_bh(&sch->dev->queue_lock);
+ }
+ #endif
+
+@@ -823,12 +723,11 @@ static void htb_rate_timer(unsigned long
+ * CAN_SEND) because we can use more precise clock that event queue here.
+ * In such case we remove class from event queue first.
+ */
+-static void htb_charge_class(struct htb_sched *q,struct htb_class *cl,
+- int level,int bytes)
+-{
+- long toks,diff;
++static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
++ int level, int bytes)
++{
++ long toks, diff;
+ enum htb_cmode old_mode;
+- HTB_DBG(5,1,"htb_chrg_cl cl=%X lev=%d len=%d\n",cl->classid,level,bytes);
+
+ #define HTB_ACCNT(T,B,R) toks = diff + cl->T; \
+ if (toks > cl->B) toks = cl->B; \
+@@ -837,47 +736,31 @@ static void htb_charge_class(struct htb_
+ cl->T = toks
+
+ while (cl) {
+- HTB_CHCL(cl);
+- diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer);
+-#ifdef HTB_DEBUG
+- if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) {
+- if (net_ratelimit())
+- printk(KERN_ERR "HTB: bad diff in charge, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n",
+- cl->classid, diff,
+-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
+- q->now.tv_sec * 1000000ULL + q->now.tv_usec,
+- cl->t_c.tv_sec * 1000000ULL + cl->t_c.tv_usec,
+-#else
+- (unsigned long long) q->now,
+- (unsigned long long) cl->t_c,
+-#endif
+- q->jiffies);
+- diff = 1000;
+- }
+-#endif
++ diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
+ if (cl->level >= level) {
+- if (cl->level == level) cl->xstats.lends++;
+- HTB_ACCNT (tokens,buffer,rate);
++ if (cl->level == level)
++ cl->xstats.lends++;
++ HTB_ACCNT(tokens, buffer, rate);
+ } else {
+ cl->xstats.borrows++;
+- cl->tokens += diff; /* we moved t_c; update tokens */
++ cl->tokens += diff; /* we moved t_c; update tokens */
+ }
+- HTB_ACCNT (ctokens,cbuffer,ceil);
++ HTB_ACCNT(ctokens, cbuffer, ceil);
+ cl->t_c = q->now;
+- HTB_DBG(5,2,"htb_chrg_clp cl=%X diff=%ld tok=%ld ctok=%ld\n",cl->classid,diff,cl->tokens,cl->ctokens);
+
+- old_mode = cl->cmode; diff = 0;
+- htb_change_class_mode(q,cl,&diff);
++ old_mode = cl->cmode;
++ diff = 0;
++ htb_change_class_mode(q, cl, &diff);
+ if (old_mode != cl->cmode) {
+ if (old_mode != HTB_CAN_SEND)
+- htb_safe_rb_erase(&cl->pq_node,q->wait_pq+cl->level);
++ htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level);
+ if (cl->cmode != HTB_CAN_SEND)
+- htb_add_to_wait_tree (q,cl,diff,1);
++ htb_add_to_wait_tree(q, cl, diff);
+ }
+-
+ #ifdef HTB_RATECM
+ /* update rate counters */
+- cl->sum_bytes += bytes; cl->sum_packets++;
++ cl->sum_bytes += bytes;
++ cl->sum_packets++;
+ #endif
+
+ /* update byte stats except for leaves which are already updated */
+@@ -896,60 +779,45 @@ static void htb_charge_class(struct htb_
+ * next pending event (0 for no event in pq).
+ * Note: Aplied are events whose have cl->pq_key <= jiffies.
+ */
+-static long htb_do_events(struct htb_sched *q,int level)
++static long htb_do_events(struct htb_sched *q, int level)
+ {
+ int i;
+- HTB_DBG(8,1,"htb_do_events l=%d root=%p rmask=%X\n",
+- level,q->wait_pq[level].rb_node,q->row_mask[level]);
++
+ for (i = 0; i < 500; i++) {
+ struct htb_class *cl;
+ long diff;
+- struct rb_node *p = q->wait_pq[level].rb_node;
+- if (!p) return 0;
+- while (p->rb_left) p = p->rb_left;
++ struct rb_node *p = rb_first(&q->wait_pq[level]);
++
++ if (!p)
++ return 0;
+
+ cl = rb_entry(p, struct htb_class, pq_node);
+ if (time_after(cl->pq_key, q->jiffies)) {
+- HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies);
+ return cl->pq_key - q->jiffies;
+ }
+- htb_safe_rb_erase(p,q->wait_pq+level);
+- diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer);
+-#ifdef HTB_DEBUG
+- if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) {
+- if (net_ratelimit())
+- printk(KERN_ERR "HTB: bad diff in events, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n",
+- cl->classid, diff,
+-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
+- q->now.tv_sec * 1000000ULL + q->now.tv_usec,
+- cl->t_c.tv_sec * 1000000ULL + cl->t_c.tv_usec,
+-#else
+- (unsigned long long) q->now,
+- (unsigned long long) cl->t_c,
+-#endif
+- q->jiffies);
+- diff = 1000;
+- }
+-#endif
+- htb_change_class_mode(q,cl,&diff);
++ htb_safe_rb_erase(p, q->wait_pq + level);
++ diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
++ htb_change_class_mode(q, cl, &diff);
+ if (cl->cmode != HTB_CAN_SEND)
+- htb_add_to_wait_tree (q,cl,diff,2);
++ htb_add_to_wait_tree(q, cl, diff);
+ }
+ if (net_ratelimit())
+ printk(KERN_WARNING "htb: too many events !\n");
+- return HZ/10;
++ return HZ / 10;
+ }
+
+ /* Returns class->node+prio from id-tree where classe's id is >= id. NULL
+ is no such one exists. */
+-static struct rb_node *
+-htb_id_find_next_upper(int prio,struct rb_node *n,u32 id)
++static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n,
++ u32 id)
+ {
+ struct rb_node *r = NULL;
+ while (n) {
+- struct htb_class *cl = rb_entry(n,struct htb_class,node[prio]);
+- if (id == cl->classid) return n;
+-
++ struct htb_class *cl =
++ rb_entry(n, struct htb_class, node[prio]);
++ if (id == cl->classid)
++ return n;
++
+ if (id > cl->classid) {
+ n = n->rb_right;
+ } else {
+@@ -965,49 +833,49 @@ htb_id_find_next_upper(int prio,struct r
+ *
+ * Find leaf where current feed pointers points to.
+ */
+-static struct htb_class *
+-htb_lookup_leaf(HTB_ARGQ struct rb_root *tree,int prio,struct rb_node **pptr,u32 *pid)
++static struct htb_class *htb_lookup_leaf(struct rb_root *tree, int prio,
++ struct rb_node **pptr, u32 * pid)
+ {
+ int i;
+ struct {
+ struct rb_node *root;
+ struct rb_node **pptr;
+ u32 *pid;
+- } stk[TC_HTB_MAXDEPTH],*sp = stk;
+-
++ } stk[TC_HTB_MAXDEPTH], *sp = stk;
++
+ BUG_TRAP(tree->rb_node);
+ sp->root = tree->rb_node;
+ sp->pptr = pptr;
+ sp->pid = pid;
+
+ for (i = 0; i < 65535; i++) {
+- HTB_DBG(4,2,"htb_lleaf ptr=%p pid=%X\n",*sp->pptr,*sp->pid);
+-
+- if (!*sp->pptr && *sp->pid) {
++ if (!*sp->pptr && *sp->pid) {
+ /* ptr was invalidated but id is valid - try to recover
+ the original or next ptr */
+- *sp->pptr = htb_id_find_next_upper(prio,sp->root,*sp->pid);
++ *sp->pptr =
++ htb_id_find_next_upper(prio, sp->root, *sp->pid);
+ }
+- *sp->pid = 0; /* ptr is valid now so that remove this hint as it
+- can become out of date quickly */
+- if (!*sp->pptr) { /* we are at right end; rewind & go up */
++ *sp->pid = 0; /* ptr is valid now so that remove this hint as it
++ can become out of date quickly */
++ if (!*sp->pptr) { /* we are at right end; rewind & go up */
+ *sp->pptr = sp->root;
+- while ((*sp->pptr)->rb_left)
++ while ((*sp->pptr)->rb_left)
+ *sp->pptr = (*sp->pptr)->rb_left;
+ if (sp > stk) {
+ sp--;
+- BUG_TRAP(*sp->pptr); if(!*sp->pptr) return NULL;
+- htb_next_rb_node (sp->pptr);
++ BUG_TRAP(*sp->pptr);
++ if (!*sp->pptr)
++ return NULL;
++ htb_next_rb_node(sp->pptr);
+ }
+ } else {
+ struct htb_class *cl;
+- cl = rb_entry(*sp->pptr,struct htb_class,node[prio]);
+- HTB_CHCL(cl);
+- if (!cl->level)
++ cl = rb_entry(*sp->pptr, struct htb_class, node[prio]);
++ if (!cl->level)
+ return cl;
+ (++sp)->root = cl->un.inner.feed[prio].rb_node;
+- sp->pptr = cl->un.inner.ptr+prio;
+- sp->pid = cl->un.inner.last_ptr_id+prio;
++ sp->pptr = cl->un.inner.ptr + prio;
++ sp->pid = cl->un.inner.last_ptr_id + prio;
+ }
+ }
+ BUG_TRAP(0);
+@@ -1016,21 +884,21 @@ htb_lookup_leaf(HTB_ARGQ struct rb_root
+
+ /* dequeues packet at given priority and level; call only if
+ you are sure that there is active class at prio/level */
+-static struct sk_buff *
+-htb_dequeue_tree(struct htb_sched *q,int prio,int level)
++static struct sk_buff *htb_dequeue_tree(struct htb_sched *q, int prio,
++ int level)
+ {
+ struct sk_buff *skb = NULL;
+- struct htb_class *cl,*start;
++ struct htb_class *cl, *start;
+ /* look initial class up in the row */
+- start = cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,
+- q->ptr[level]+prio,q->last_ptr_id[level]+prio);
+-
++ start = cl = htb_lookup_leaf(q->row[level] + prio, prio,
++ q->ptr[level] + prio,
++ q->last_ptr_id[level] + prio);
++
+ do {
+ next:
+- BUG_TRAP(cl);
+- if (!cl) return NULL;
+- HTB_DBG(4,1,"htb_deq_tr prio=%d lev=%d cl=%X defic=%d\n",
+- prio,level,cl->classid,cl->un.leaf.deficit[level]);
++ BUG_TRAP(cl);
++ if (!cl)
++ return NULL;
+
+ /* class can be empty - it is unlikely but can be true if leaf
+ qdisc drops packets in enqueue routine or if someone used
+@@ -1038,64 +906,69 @@ next:
+ simply deactivate and skip such class */
+ if (unlikely(cl->un.leaf.q->q.qlen == 0)) {
+ struct htb_class *next;
+- htb_deactivate(q,cl);
++ htb_deactivate(q, cl);
+
+ /* row/level might become empty */
+ if ((q->row_mask[level] & (1 << prio)) == 0)
+- return NULL;
+-
+- next = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,
+- prio,q->ptr[level]+prio,q->last_ptr_id[level]+prio);
++ return NULL;
++
++ next = htb_lookup_leaf(q->row[level] + prio,
++ prio, q->ptr[level] + prio,
++ q->last_ptr_id[level] + prio);
+
+- if (cl == start) /* fix start if we just deleted it */
++ if (cl == start) /* fix start if we just deleted it */
+ start = next;
+ cl = next;
+ goto next;
+ }
+-
+- if (likely((skb = cl->un.leaf.q->dequeue(cl->un.leaf.q)) != NULL))
++
++ skb = cl->un.leaf.q->dequeue(cl->un.leaf.q);
++ if (likely(skb != NULL))
+ break;
+ if (!cl->warned) {
+- printk(KERN_WARNING "htb: class %X isn't work conserving ?!\n",cl->classid);
++ printk(KERN_WARNING
++ "htb: class %X isn't work conserving ?!\n",
++ cl->classid);
+ cl->warned = 1;
+ }
+ q->nwc_hit++;
+- htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio);
+- cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,q->ptr[level]+prio,
+- q->last_ptr_id[level]+prio);
++ htb_next_rb_node((level ? cl->parent->un.inner.ptr : q->
++ ptr[0]) + prio);
++ cl = htb_lookup_leaf(q->row[level] + prio, prio,
++ q->ptr[level] + prio,
++ q->last_ptr_id[level] + prio);
+
+ } while (cl != start);
+
+ if (likely(skb != NULL)) {
+ if ((cl->un.leaf.deficit[level] -= skb->len) < 0) {
+- HTB_DBG(4,2,"htb_next_cl oldptr=%p quant_add=%d\n",
+- level?cl->parent->un.inner.ptr[prio]:q->ptr[0][prio],cl->un.leaf.quantum);
+ cl->un.leaf.deficit[level] += cl->un.leaf.quantum;
+- htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio);
++ htb_next_rb_node((level ? cl->parent->un.inner.ptr : q->
++ ptr[0]) + prio);
+ }
+ /* this used to be after charge_class but this constelation
+ gives us slightly better performance */
+ if (!cl->un.leaf.q->q.qlen)
+- htb_deactivate (q,cl);
+- htb_charge_class (q,cl,level,skb->len);
++ htb_deactivate(q, cl);
++ htb_charge_class(q, cl, level, skb->len);
+ }
+ return skb;
+ }
+
+-static void htb_delay_by(struct Qdisc *sch,long delay)
++static void htb_delay_by(struct Qdisc *sch, long delay)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- if (delay <= 0) delay = 1;
+- if (unlikely(delay > 5*HZ)) {
++ if (delay <= 0)
++ delay = 1;
++ if (unlikely(delay > 5 * HZ)) {
+ if (net_ratelimit())
+ printk(KERN_INFO "HTB delay %ld > 5sec\n", delay);
+- delay = 5*HZ;
++ delay = 5 * HZ;
+ }
+ /* why don't use jiffies here ? because expires can be in past */
+ mod_timer(&q->timer, q->jiffies + delay);
+ sch->flags |= TCQ_F_THROTTLED;
+ sch->qstats.overlimits++;
+- HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay);
+ }
+
+ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
+@@ -1104,22 +977,19 @@ static struct sk_buff *htb_dequeue(struc
+ struct htb_sched *q = qdisc_priv(sch);
+ int level;
+ long min_delay;
+-#ifdef HTB_DEBUG
+- int evs_used = 0;
+-#endif
+
+ q->jiffies = jiffies;
+- HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue),
+- sch->q.qlen);
+
+ /* try to dequeue direct packets as high prio (!) to minimize cpu work */
+- if ((skb = __skb_dequeue(&q->direct_queue)) != NULL) {
++ skb = __skb_dequeue(&q->direct_queue);
++ if (skb != NULL) {
+ sch->flags &= ~TCQ_F_THROTTLED;
+ sch->q.qlen--;
+ return skb;
+ }
+
+- if (!sch->q.qlen) goto fin;
++ if (!sch->q.qlen)
++ goto fin;
+ PSCHED_GET_TIME(q->now);
+
+ min_delay = LONG_MAX;
+@@ -1129,21 +999,19 @@ static struct sk_buff *htb_dequeue(struc
+ int m;
+ long delay;
+ if (time_after_eq(q->jiffies, q->near_ev_cache[level])) {
+- delay = htb_do_events(q,level);
+- q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ);
+-#ifdef HTB_DEBUG
+- evs_used++;
+-#endif
++ delay = htb_do_events(q, level);
++ q->near_ev_cache[level] =
++ q->jiffies + (delay ? delay : HZ);
+ } else
+- delay = q->near_ev_cache[level] - q->jiffies;
+-
+- if (delay && min_delay > delay)
++ delay = q->near_ev_cache[level] - q->jiffies;
++
++ if (delay && min_delay > delay)
+ min_delay = delay;
+ m = ~q->row_mask[level];
+ while (m != (int)(-1)) {
+- int prio = ffz (m);
++ int prio = ffz(m);
+ m |= 1 << prio;
+- skb = htb_dequeue_tree(q,prio,level);
++ skb = htb_dequeue_tree(q, prio, level);
+ if (likely(skb != NULL)) {
+ sch->q.qlen--;
+ sch->flags &= ~TCQ_F_THROTTLED;
+@@ -1151,40 +1019,28 @@ static struct sk_buff *htb_dequeue(struc
+ }
+ }
+ }
+-#ifdef HTB_DEBUG
+- if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) {
+- if (min_delay == LONG_MAX) {
+- printk(KERN_ERR "HTB: dequeue bug (%d,%lu,%lu), report it please !\n",
+- evs_used,q->jiffies,jiffies);
+- htb_debug_dump(q);
+- } else
+- printk(KERN_WARNING "HTB: mindelay=%ld, some class has "
+- "too small rate\n",min_delay);
+- }
+-#endif
+- htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay);
++ htb_delay_by(sch, min_delay > 5 * HZ ? 5 * HZ : min_delay);
+ fin:
+- HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,q->jiffies,skb);
+ return skb;
+ }
+
+ /* try to drop from each class (by prio) until one succeed */
+-static unsigned int htb_drop(struct Qdisc* sch)
++static unsigned int htb_drop(struct Qdisc *sch)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+ int prio;
+
+ for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) {
+ struct list_head *p;
+- list_for_each (p,q->drops+prio) {
++ list_for_each(p, q->drops + prio) {
+ struct htb_class *cl = list_entry(p, struct htb_class,
+ un.leaf.drop_list);
+ unsigned int len;
+- if (cl->un.leaf.q->ops->drop &&
+- (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) {
++ if (cl->un.leaf.q->ops->drop &&
++ (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) {
+ sch->q.qlen--;
+ if (!cl->un.leaf.q->q.qlen)
+- htb_deactivate (q,cl);
++ htb_deactivate(q, cl);
+ return len;
+ }
+ }
+@@ -1194,29 +1050,25 @@ static unsigned int htb_drop(struct Qdis
+
+ /* reset all classes */
+ /* always caled under BH & queue lock */
+-static void htb_reset(struct Qdisc* sch)
++static void htb_reset(struct Qdisc *sch)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+ int i;
+- HTB_DBG(0,1,"htb_reset sch=%p, handle=%X\n",sch,sch->handle);
+
+ for (i = 0; i < HTB_HSIZE; i++) {
+- struct list_head *p;
+- list_for_each (p,q->hash+i) {
+- struct htb_class *cl = list_entry(p,struct htb_class,hlist);
++ struct hlist_node *p;
++ struct htb_class *cl;
++
++ hlist_for_each_entry(cl, p, q->hash + i, hlist) {
+ if (cl->level)
+- memset(&cl->un.inner,0,sizeof(cl->un.inner));
++ memset(&cl->un.inner, 0, sizeof(cl->un.inner));
+ else {
+- if (cl->un.leaf.q)
++ if (cl->un.leaf.q)
+ qdisc_reset(cl->un.leaf.q);
+ INIT_LIST_HEAD(&cl->un.leaf.drop_list);
+ }
+ cl->prio_activity = 0;
+ cl->cmode = HTB_CAN_SEND;
+-#ifdef HTB_DEBUG
+- cl->pq_node.rb_color = -1;
+- memset(cl->node,255,sizeof(cl->node));
+-#endif
+
+ }
+ }
+@@ -1224,12 +1076,12 @@ static void htb_reset(struct Qdisc* sch)
+ del_timer(&q->timer);
+ __skb_queue_purge(&q->direct_queue);
+ sch->q.qlen = 0;
+- memset(q->row,0,sizeof(q->row));
+- memset(q->row_mask,0,sizeof(q->row_mask));
+- memset(q->wait_pq,0,sizeof(q->wait_pq));
+- memset(q->ptr,0,sizeof(q->ptr));
++ memset(q->row, 0, sizeof(q->row));
++ memset(q->row_mask, 0, sizeof(q->row_mask));
++ memset(q->wait_pq, 0, sizeof(q->wait_pq));
++ memset(q->ptr, 0, sizeof(q->ptr));
+ for (i = 0; i < TC_HTB_NUMPRIO; i++)
+- INIT_LIST_HEAD(q->drops+i);
++ INIT_LIST_HEAD(q->drops + i);
+ }
+
+ static int htb_init(struct Qdisc *sch, struct rtattr *opt)
+@@ -1238,36 +1090,31 @@ static int htb_init(struct Qdisc *sch, s
+ struct rtattr *tb[TCA_HTB_INIT];
+ struct tc_htb_glob *gopt;
+ int i;
+-#ifdef HTB_DEBUG
+- printk(KERN_INFO "HTB init, kernel part version %d.%d\n",
+- HTB_VER >> 16,HTB_VER & 0xffff);
+-#endif
+ if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) ||
+- tb[TCA_HTB_INIT-1] == NULL ||
+- RTA_PAYLOAD(tb[TCA_HTB_INIT-1]) < sizeof(*gopt)) {
++ tb[TCA_HTB_INIT - 1] == NULL ||
++ RTA_PAYLOAD(tb[TCA_HTB_INIT - 1]) < sizeof(*gopt)) {
+ printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n");
+ return -EINVAL;
+ }
+- gopt = RTA_DATA(tb[TCA_HTB_INIT-1]);
++ gopt = RTA_DATA(tb[TCA_HTB_INIT - 1]);
+ if (gopt->version != HTB_VER >> 16) {
+- printk(KERN_ERR "HTB: need tc/htb version %d (minor is %d), you have %d\n",
+- HTB_VER >> 16,HTB_VER & 0xffff,gopt->version);
++ printk(KERN_ERR
++ "HTB: need tc/htb version %d (minor is %d), you have %d\n",
++ HTB_VER >> 16, HTB_VER & 0xffff, gopt->version);
+ return -EINVAL;
+ }
+- q->debug = gopt->debug;
+- HTB_DBG(0,1,"htb_init sch=%p handle=%X r2q=%d\n",sch,sch->handle,gopt->rate2quantum);
+
+ INIT_LIST_HEAD(&q->root);
+ for (i = 0; i < HTB_HSIZE; i++)
+- INIT_LIST_HEAD(q->hash+i);
++ INIT_HLIST_HEAD(q->hash + i);
+ for (i = 0; i < TC_HTB_NUMPRIO; i++)
+- INIT_LIST_HEAD(q->drops+i);
++ INIT_LIST_HEAD(q->drops + i);
+
+ init_timer(&q->timer);
+ skb_queue_head_init(&q->direct_queue);
+
+ q->direct_qlen = sch->dev->tx_queue_len;
+- if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
++ if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
+ q->direct_qlen = 2;
+ q->timer.function = htb_timer;
+ q->timer.data = (unsigned long)sch;
+@@ -1289,80 +1136,72 @@ static int htb_init(struct Qdisc *sch, s
+ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- unsigned char *b = skb->tail;
++ unsigned char *b = skb->tail;
+ struct rtattr *rta;
+ struct tc_htb_glob gopt;
+- HTB_DBG(0,1,"htb_dump sch=%p, handle=%X\n",sch,sch->handle);
+- HTB_QLOCK(sch);
++ spin_lock_bh(&sch->dev->queue_lock);
+ gopt.direct_pkts = q->direct_pkts;
+
+-#ifdef HTB_DEBUG
+- if (HTB_DBG_COND(0,2))
+- htb_debug_dump(q);
+-#endif
+ gopt.version = HTB_VER;
+ gopt.rate2quantum = q->rate2quantum;
+ gopt.defcls = q->defcls;
+- gopt.debug = q->debug;
+- rta = (struct rtattr*)b;
++ gopt.debug = 0;
++ rta = (struct rtattr *)b;
+ RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+ RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
+ rta->rta_len = skb->tail - b;
+- HTB_QUNLOCK(sch);
++ spin_unlock_bh(&sch->dev->queue_lock);
+ return skb->len;
+ rtattr_failure:
+- HTB_QUNLOCK(sch);
++ spin_unlock_bh(&sch->dev->queue_lock);
+ skb_trim(skb, skb->tail - skb->data);
+ return -1;
+ }
+
+ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
+- struct sk_buff *skb, struct tcmsg *tcm)
++ struct sk_buff *skb, struct tcmsg *tcm)
+ {
+-#ifdef HTB_DEBUG
+- struct htb_sched *q = qdisc_priv(sch);
+-#endif
+- struct htb_class *cl = (struct htb_class*)arg;
+- unsigned char *b = skb->tail;
++ struct htb_class *cl = (struct htb_class *)arg;
++ unsigned char *b = skb->tail;
+ struct rtattr *rta;
+ struct tc_htb_opt opt;
+
+- HTB_DBG(0,1,"htb_dump_class handle=%X clid=%X\n",sch->handle,cl->classid);
+-
+- HTB_QLOCK(sch);
++ spin_lock_bh(&sch->dev->queue_lock);
+ tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT;
+ tcm->tcm_handle = cl->classid;
+ if (!cl->level && cl->un.leaf.q)
+ tcm->tcm_info = cl->un.leaf.q->handle;
+
+- rta = (struct rtattr*)b;
++ rta = (struct rtattr *)b;
+ RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+
+- memset (&opt,0,sizeof(opt));
++ memset(&opt, 0, sizeof(opt));
+
+- opt.rate = cl->rate->rate; opt.buffer = cl->buffer;
+- opt.ceil = cl->ceil->rate; opt.cbuffer = cl->cbuffer;
+- opt.quantum = cl->un.leaf.quantum; opt.prio = cl->un.leaf.prio;
+- opt.level = cl->level;
++ opt.rate = cl->rate->rate;
++ opt.buffer = cl->buffer;
++ opt.ceil = cl->ceil->rate;
++ opt.cbuffer = cl->cbuffer;
++ opt.quantum = cl->un.leaf.quantum;
++ opt.prio = cl->un.leaf.prio;
++ opt.level = cl->level;
+ RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
+ rta->rta_len = skb->tail - b;
+- HTB_QUNLOCK(sch);
++ spin_unlock_bh(&sch->dev->queue_lock);
+ return skb->len;
+ rtattr_failure:
+- HTB_QUNLOCK(sch);
++ spin_unlock_bh(&sch->dev->queue_lock);
+ skb_trim(skb, b - skb->data);
+ return -1;
+ }
+
+ static int
+-htb_dump_class_stats(struct Qdisc *sch, unsigned long arg,
+- struct gnet_dump *d)
++htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
+ {
+- struct htb_class *cl = (struct htb_class*)arg;
++ struct htb_class *cl = (struct htb_class *)arg;
+
+ #ifdef HTB_RATECM
+- cl->rate_est.bps = cl->rate_bytes/(HTB_EWMAC*HTB_HSIZE);
+- cl->rate_est.pps = cl->rate_packets/(HTB_EWMAC*HTB_HSIZE);
++ cl->rate_est.bps = cl->rate_bytes / (HTB_EWMAC * HTB_HSIZE);
++ cl->rate_est.pps = cl->rate_packets / (HTB_EWMAC * HTB_HSIZE);
+ #endif
+
+ if (!cl->level && cl->un.leaf.q)
+@@ -1379,21 +1218,22 @@ htb_dump_class_stats(struct Qdisc *sch,
+ }
+
+ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+- struct Qdisc **old)
++ struct Qdisc **old)
+ {
+- struct htb_class *cl = (struct htb_class*)arg;
++ struct htb_class *cl = (struct htb_class *)arg;
+
+ if (cl && !cl->level) {
+- if (new == NULL && (new = qdisc_create_dflt(sch->dev,
+- &pfifo_qdisc_ops)) == NULL)
+- return -ENOBUFS;
++ if (new == NULL && (new = qdisc_create_dflt(sch->dev,
++ &pfifo_qdisc_ops))
++ == NULL)
++ return -ENOBUFS;
+ sch_tree_lock(sch);
+ if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) {
+ if (cl->prio_activity)
+- htb_deactivate (qdisc_priv(sch),cl);
++ htb_deactivate(qdisc_priv(sch), cl);
+
+ /* TODO: is it correct ? Why CBQ doesn't do it ? */
+- sch->q.qlen -= (*old)->q.qlen;
++ sch->q.qlen -= (*old)->q.qlen;
+ qdisc_reset(*old);
+ }
+ sch_tree_unlock(sch);
+@@ -1402,20 +1242,16 @@ static int htb_graft(struct Qdisc *sch,
+ return -ENOENT;
+ }
+
+-static struct Qdisc * htb_leaf(struct Qdisc *sch, unsigned long arg)
++static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg)
+ {
+- struct htb_class *cl = (struct htb_class*)arg;
++ struct htb_class *cl = (struct htb_class *)arg;
+ return (cl && !cl->level) ? cl->un.leaf.q : NULL;
+ }
+
+ static unsigned long htb_get(struct Qdisc *sch, u32 classid)
+ {
+-#ifdef HTB_DEBUG
+- struct htb_sched *q = qdisc_priv(sch);
+-#endif
+- struct htb_class *cl = htb_find(classid,sch);
+- HTB_DBG(0,1,"htb_get clid=%X q=%p cl=%p ref=%d\n",classid,q,cl,cl?cl->refcnt:0);
+- if (cl)
++ struct htb_class *cl = htb_find(classid, sch);
++ if (cl)
+ cl->refcnt++;
+ return (unsigned long)cl;
+ }
+@@ -1430,10 +1266,9 @@ static void htb_destroy_filters(struct t
+ }
+ }
+
+-static void htb_destroy_class(struct Qdisc* sch,struct htb_class *cl)
++static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- HTB_DBG(0,1,"htb_destrycls clid=%X ref=%d\n", cl?cl->classid:0,cl?cl->refcnt:0);
+ if (!cl->level) {
+ BUG_TRAP(cl->un.leaf.q);
+ sch->q.qlen -= cl->un.leaf.q->q.qlen;
+@@ -1441,45 +1276,45 @@ static void htb_destroy_class(struct Qdi
+ }
+ qdisc_put_rtab(cl->rate);
+ qdisc_put_rtab(cl->ceil);
+-
+- htb_destroy_filters (&cl->filter_list);
+-
+- while (!list_empty(&cl->children))
+- htb_destroy_class (sch,list_entry(cl->children.next,
+- struct htb_class,sibling));
++
++ htb_destroy_filters(&cl->filter_list);
++
++ while (!list_empty(&cl->children))
++ htb_destroy_class(sch, list_entry(cl->children.next,
++ struct htb_class, sibling));
+
+ /* note: this delete may happen twice (see htb_delete) */
+- list_del(&cl->hlist);
++ if (!hlist_unhashed(&cl->hlist))
++ hlist_del(&cl->hlist);
+ list_del(&cl->sibling);
+-
++
+ if (cl->prio_activity)
+- htb_deactivate (q,cl);
+-
++ htb_deactivate(q, cl);
++
+ if (cl->cmode != HTB_CAN_SEND)
+- htb_safe_rb_erase(&cl->pq_node,q->wait_pq+cl->level);
+-
++ htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level);
++
+ kfree(cl);
+ }
+
+ /* always caled under BH & queue lock */
+-static void htb_destroy(struct Qdisc* sch)
++static void htb_destroy(struct Qdisc *sch)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- HTB_DBG(0,1,"htb_destroy q=%p\n",q);
+
+- del_timer_sync (&q->timer);
++ del_timer_sync(&q->timer);
+ #ifdef HTB_RATECM
+- del_timer_sync (&q->rttim);
++ del_timer_sync(&q->rttim);
+ #endif
+ /* This line used to be after htb_destroy_class call below
+ and surprisingly it worked in 2.4. But it must precede it
+ because filter need its target class alive to be able to call
+ unbind_filter on it (without Oops). */
+ htb_destroy_filters(&q->filter_list);
+-
+- while (!list_empty(&q->root))
+- htb_destroy_class (sch,list_entry(q->root.next,
+- struct htb_class,sibling));
++
++ while (!list_empty(&q->root))
++ htb_destroy_class(sch, list_entry(q->root.next,
++ struct htb_class, sibling));
+
+ __skb_queue_purge(&q->direct_queue);
+ }
+@@ -1487,24 +1322,25 @@ static void htb_destroy(struct Qdisc* sc
+ static int htb_delete(struct Qdisc *sch, unsigned long arg)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- struct htb_class *cl = (struct htb_class*)arg;
+- HTB_DBG(0,1,"htb_delete q=%p cl=%X ref=%d\n",q,cl?cl->classid:0,cl?cl->refcnt:0);
++ struct htb_class *cl = (struct htb_class *)arg;
+
+ // TODO: why don't allow to delete subtree ? references ? does
+ // tc subsys quarantee us that in htb_destroy it holds no class
+ // refs so that we can remove children safely there ?
+ if (!list_empty(&cl->children) || cl->filter_cnt)
+ return -EBUSY;
+-
++
+ sch_tree_lock(sch);
+-
++
+ /* delete from hash and active; remainder in destroy_class */
+- list_del_init(&cl->hlist);
++ if (!hlist_unhashed(&cl->hlist))
++ hlist_del(&cl->hlist);
++
+ if (cl->prio_activity)
+- htb_deactivate (q,cl);
++ htb_deactivate(q, cl);
+
+ if (--cl->refcnt == 0)
+- htb_destroy_class(sch,cl);
++ htb_destroy_class(sch, cl);
+
+ sch_tree_unlock(sch);
+ return 0;
+@@ -1512,45 +1348,46 @@ static int htb_delete(struct Qdisc *sch,
+
+ static void htb_put(struct Qdisc *sch, unsigned long arg)
+ {
+-#ifdef HTB_DEBUG
+- struct htb_sched *q = qdisc_priv(sch);
+-#endif
+- struct htb_class *cl = (struct htb_class*)arg;
+- HTB_DBG(0,1,"htb_put q=%p cl=%X ref=%d\n",q,cl?cl->classid:0,cl?cl->refcnt:0);
++ struct htb_class *cl = (struct htb_class *)arg;
+
+ if (--cl->refcnt == 0)
+- htb_destroy_class(sch,cl);
++ htb_destroy_class(sch, cl);
+ }
+
+-static int htb_change_class(struct Qdisc *sch, u32 classid,
+- u32 parentid, struct rtattr **tca, unsigned long *arg)
++static int htb_change_class(struct Qdisc *sch, u32 classid,
++ u32 parentid, struct rtattr **tca,
++ unsigned long *arg)
+ {
+ int err = -EINVAL;
+ struct htb_sched *q = qdisc_priv(sch);
+- struct htb_class *cl = (struct htb_class*)*arg,*parent;
+- struct rtattr *opt = tca[TCA_OPTIONS-1];
++ struct htb_class *cl = (struct htb_class *)*arg, *parent;
++ struct rtattr *opt = tca[TCA_OPTIONS - 1];
+ struct qdisc_rate_table *rtab = NULL, *ctab = NULL;
+ struct rtattr *tb[TCA_HTB_RTAB];
+ struct tc_htb_opt *hopt;
+
+ /* extract all subattrs from opt attr */
+ if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) ||
+- tb[TCA_HTB_PARMS-1] == NULL ||
+- RTA_PAYLOAD(tb[TCA_HTB_PARMS-1]) < sizeof(*hopt))
++ tb[TCA_HTB_PARMS - 1] == NULL ||
++ RTA_PAYLOAD(tb[TCA_HTB_PARMS - 1]) < sizeof(*hopt))
+ goto failure;
+-
+- parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch);
+
+- hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]);
+- HTB_DBG(0,1,"htb_chg cl=%p(%X), clid=%X, parid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,classid,parentid,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum);
+- rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]);
+- ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]);
+- if (!rtab || !ctab) goto failure;
++ parent = parentid == TC_H_ROOT ? NULL : htb_find(parentid, sch);
++
++ hopt = RTA_DATA(tb[TCA_HTB_PARMS - 1]);
++
++ rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB - 1]);
++ ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB - 1]);
++ if (!rtab || !ctab)
++ goto failure;
+
+- if (!cl) { /* new class */
++ if (!cl) { /* new class */
+ struct Qdisc *new_q;
++ int prio;
++
+ /* check for valid classid */
+- if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch))
++ if (!classid || TC_H_MAJ(classid ^ sch->handle)
++ || htb_find(classid, sch))
+ goto failure;
+
+ /* check maximal depth */
+@@ -1561,15 +1398,16 @@ static int htb_change_class(struct Qdisc
+ err = -ENOBUFS;
+ if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
+ goto failure;
+-
++
+ cl->refcnt = 1;
+ INIT_LIST_HEAD(&cl->sibling);
+- INIT_LIST_HEAD(&cl->hlist);
++ INIT_HLIST_NODE(&cl->hlist);
+ INIT_LIST_HEAD(&cl->children);
+ INIT_LIST_HEAD(&cl->un.leaf.drop_list);
+-#ifdef HTB_DEBUG
+- cl->magic = HTB_CMAGIC;
+-#endif
++ RB_CLEAR_NODE(&cl->pq_node);
++
++ for (prio = 0; prio < TC_HTB_NUMPRIO; prio++)
++ RB_CLEAR_NODE(&cl->node[prio]);
+
+ /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
+ so that can't be used inside of sch_tree_lock
+@@ -1579,53 +1417,53 @@ static int htb_change_class(struct Qdisc
+ if (parent && !parent->level) {
+ /* turn parent into inner node */
+ sch->q.qlen -= parent->un.leaf.q->q.qlen;
+- qdisc_destroy (parent->un.leaf.q);
+- if (parent->prio_activity)
+- htb_deactivate (q,parent);
++ qdisc_destroy(parent->un.leaf.q);
++ if (parent->prio_activity)
++ htb_deactivate(q, parent);
+
+ /* remove from evt list because of level change */
+ if (parent->cmode != HTB_CAN_SEND) {
+- htb_safe_rb_erase(&parent->pq_node,q->wait_pq /*+0*/);
++ htb_safe_rb_erase(&parent->pq_node, q->wait_pq);
+ parent->cmode = HTB_CAN_SEND;
+ }
+ parent->level = (parent->parent ? parent->parent->level
+- : TC_HTB_MAXDEPTH) - 1;
+- memset (&parent->un.inner,0,sizeof(parent->un.inner));
++ : TC_HTB_MAXDEPTH) - 1;
++ memset(&parent->un.inner, 0, sizeof(parent->un.inner));
+ }
+ /* leaf (we) needs elementary qdisc */
+ cl->un.leaf.q = new_q ? new_q : &noop_qdisc;
+
+- cl->classid = classid; cl->parent = parent;
++ cl->classid = classid;
++ cl->parent = parent;
+
+ /* set class to be in HTB_CAN_SEND state */
+ cl->tokens = hopt->buffer;
+ cl->ctokens = hopt->cbuffer;
+- cl->mbuffer = PSCHED_JIFFIE2US(HZ*60); /* 1min */
++ cl->mbuffer = PSCHED_JIFFIE2US(HZ * 60); /* 1min */
+ PSCHED_GET_TIME(cl->t_c);
+ cl->cmode = HTB_CAN_SEND;
+
+ /* attach to the hash list and parent's family */
+- list_add_tail(&cl->hlist, q->hash+htb_hash(classid));
+- list_add_tail(&cl->sibling, parent ? &parent->children : &q->root);
+-#ifdef HTB_DEBUG
+- {
+- int i;
+- for (i = 0; i < TC_HTB_NUMPRIO; i++) cl->node[i].rb_color = -1;
+- cl->pq_node.rb_color = -1;
+- }
+-#endif
+- } else sch_tree_lock(sch);
++ hlist_add_head(&cl->hlist, q->hash + htb_hash(classid));
++ list_add_tail(&cl->sibling,
++ parent ? &parent->children : &q->root);
++ } else
++ sch_tree_lock(sch);
+
+ /* it used to be a nasty bug here, we have to check that node
+- is really leaf before changing cl->un.leaf ! */
++ is really leaf before changing cl->un.leaf ! */
+ if (!cl->level) {
+ cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum;
+ if (!hopt->quantum && cl->un.leaf.quantum < 1000) {
+- printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", cl->classid);
++ printk(KERN_WARNING
++ "HTB: quantum of class %X is small. Consider r2q change.\n",
++ cl->classid);
+ cl->un.leaf.quantum = 1000;
+ }
+ if (!hopt->quantum && cl->un.leaf.quantum > 200000) {
+- printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", cl->classid);
++ printk(KERN_WARNING
++ "HTB: quantum of class %X is big. Consider r2q change.\n",
++ cl->classid);
+ cl->un.leaf.quantum = 200000;
+ }
+ if (hopt->quantum)
+@@ -1636,16 +1474,22 @@ static int htb_change_class(struct Qdisc
+
+ cl->buffer = hopt->buffer;
+ cl->cbuffer = hopt->cbuffer;
+- if (cl->rate) qdisc_put_rtab(cl->rate); cl->rate = rtab;
+- if (cl->ceil) qdisc_put_rtab(cl->ceil); cl->ceil = ctab;
++ if (cl->rate)
++ qdisc_put_rtab(cl->rate);
++ cl->rate = rtab;
++ if (cl->ceil)
++ qdisc_put_rtab(cl->ceil);
++ cl->ceil = ctab;
+ sch_tree_unlock(sch);
+
+ *arg = (unsigned long)cl;
+ return 0;
+
+ failure:
+- if (rtab) qdisc_put_rtab(rtab);
+- if (ctab) qdisc_put_rtab(ctab);
++ if (rtab)
++ qdisc_put_rtab(rtab);
++ if (ctab)
++ qdisc_put_rtab(ctab);
+ return err;
+ }
+
+@@ -1654,28 +1498,28 @@ static struct tcf_proto **htb_find_tcf(s
+ struct htb_sched *q = qdisc_priv(sch);
+ struct htb_class *cl = (struct htb_class *)arg;
+ struct tcf_proto **fl = cl ? &cl->filter_list : &q->filter_list;
+- HTB_DBG(0,2,"htb_tcf q=%p clid=%X fref=%d fl=%p\n",q,cl?cl->classid:0,cl?cl->filter_cnt:q->filter_cnt,*fl);
++
+ return fl;
+ }
+
+ static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent,
+- u32 classid)
++ u32 classid)
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+- struct htb_class *cl = htb_find (classid,sch);
+- HTB_DBG(0,2,"htb_bind q=%p clid=%X cl=%p fref=%d\n",q,classid,cl,cl?cl->filter_cnt:q->filter_cnt);
++ struct htb_class *cl = htb_find(classid, sch);
++
+ /*if (cl && !cl->level) return 0;
+- The line above used to be there to prevent attaching filters to
+- leaves. But at least tc_index filter uses this just to get class
+- for other reasons so that we have to allow for it.
+- ----
+- 19.6.2002 As Werner explained it is ok - bind filter is just
+- another way to "lock" the class - unlike "get" this lock can
+- be broken by class during destroy IIUC.
++ The line above used to be there to prevent attaching filters to
++ leaves. But at least tc_index filter uses this just to get class
++ for other reasons so that we have to allow for it.
++ ----
++ 19.6.2002 As Werner explained it is ok - bind filter is just
++ another way to "lock" the class - unlike "get" this lock can
++ be broken by class during destroy IIUC.
+ */
+- if (cl)
+- cl->filter_cnt++;
+- else
++ if (cl)
++ cl->filter_cnt++;
++ else
+ q->filter_cnt++;
+ return (unsigned long)cl;
+ }
+@@ -1684,10 +1528,10 @@ static void htb_unbind_filter(struct Qdi
+ {
+ struct htb_sched *q = qdisc_priv(sch);
+ struct htb_class *cl = (struct htb_class *)arg;
+- HTB_DBG(0,2,"htb_unbind q=%p cl=%p fref=%d\n",q,cl,cl?cl->filter_cnt:q->filter_cnt);
+- if (cl)
+- cl->filter_cnt--;
+- else
++
++ if (cl)
++ cl->filter_cnt--;
++ else
+ q->filter_cnt--;
+ }
+
+@@ -1700,9 +1544,10 @@ static void htb_walk(struct Qdisc *sch,
+ return;
+
+ for (i = 0; i < HTB_HSIZE; i++) {
+- struct list_head *p;
+- list_for_each (p,q->hash+i) {
+- struct htb_class *cl = list_entry(p,struct htb_class,hlist);
++ struct hlist_node *p;
++ struct htb_class *cl;
++
++ hlist_for_each_entry(cl, p, q->hash + i, hlist) {
+ if (arg->count < arg->skip) {
+ arg->count++;
+ continue;
+@@ -1750,12 +1595,13 @@ static struct Qdisc_ops htb_qdisc_ops =
+
+ static int __init htb_module_init(void)
+ {
+- return register_qdisc(&htb_qdisc_ops);
++ return register_qdisc(&htb_qdisc_ops);
+ }
+-static void __exit htb_module_exit(void)
++static void __exit htb_module_exit(void)
+ {
+- unregister_qdisc(&htb_qdisc_ops);
++ unregister_qdisc(&htb_qdisc_ops);
+ }
++
+ module_init(htb_module_init)
+ module_exit(htb_module_exit)
+ MODULE_LICENSE("GPL");
+diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
+index a08ec4c..0441876 100644
+--- a/net/sched/sch_netem.c
++++ b/net/sched/sch_netem.c
+@@ -4,7 +4,7 @@
+ * 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.
++ * 2 of the License.
+ *
+ * Many of the algorithms and ideas for this came from
+ * NIST Net which is not copyrighted.
+@@ -170,6 +170,8 @@ static int netem_enqueue(struct sk_buff
+ return NET_XMIT_BYPASS;
+ }
+
++ skb_orphan(skb);
++
+ /*
+ * If we need to duplicate packet, then re-insert at top of the
+ * qdisc tree, since parent queuer expects that only one
+@@ -192,8 +194,8 @@ static int netem_enqueue(struct sk_buff
+ */
+ if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
+ if (!(skb = skb_unshare(skb, GFP_ATOMIC))
+- || (skb->ip_summed == CHECKSUM_HW
+- && skb_checksum_help(skb, 0))) {
++ || (skb->ip_summed == CHECKSUM_PARTIAL
++ && skb_checksum_help(skb))) {
+ sch->qstats.drops++;
+ return NET_XMIT_DROP;
+ }
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index 27329ce..ed0445f 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_a
+ struct list_head *pos, *temp;
+ int i;
+
+- list_del(&asoc->asocs);
++ /* Only real associations count against the endpoint, so
++ * don't bother for if this is a temporary association.
++ */
++ if (!asoc->temp) {
++ list_del(&asoc->asocs);
+
+- /* Decrement the backlog value for a TCP-style listening socket. */
+- if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
+- sk->sk_ack_backlog--;
++ /* Decrement the backlog value for a TCP-style listening
++ * socket.
++ */
++ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
++ sk->sk_ack_backlog--;
++ }
+
+ /* Mark as dead, so other users can know this structure is
+ * going away.
+diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
+index ffda1d6..9b6b394 100644
+--- a/net/sctp/endpointola.c
++++ b/net/sctp/endpointola.c
+@@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_
+ {
+ struct sock *sk = ep->base.sk;
+
++ /* If this is a temporary association, don't bother
++ * since we'll be removing it shortly and don't
++ * want anyone to find it anyway.
++ */
++ if (asoc->temp)
++ return;
++
+ /* Now just add it to our list of asocs */
+ list_add_tail(&asoc->asocs, &ep->asocs);
+
+@@ -173,7 +180,7 @@ static void sctp_endpoint_destroy(struct
+ SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
+
+ /* Free up the HMAC transform. */
+- sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
++ crypto_free_hash(sctp_sk(ep->base.sk)->hmac);
+
+ /* Cleanup. */
+ sctp_inq_free(&ep->base.inqueue);
+diff --git a/net/sctp/input.c b/net/sctp/input.c
+index 42b66e7..6d82f40 100644
+--- a/net/sctp/input.c
++++ b/net/sctp/input.c
+@@ -135,6 +135,9 @@ int sctp_rcv(struct sk_buff *skb)
+
+ SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS);
+
++ if (skb_linearize(skb))
++ goto discard_it;
++
+ sh = (struct sctphdr *) skb->h.raw;
+
+ /* Pull up the IP and SCTP headers. */
+@@ -218,17 +221,11 @@ int sctp_rcv(struct sk_buff *skb)
+ }
+ }
+
+- /* SCTP seems to always need a timestamp right now (FIXME) */
+- if (skb->tstamp.off_sec == 0) {
+- __net_timestamp(skb);
+- sock_enable_timestamp(sk);
+- }
+-
+ if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
+ goto discard_release;
+ nf_reset(skb);
+
+- if (sk_filter(sk, skb, 1))
++ if (sk_filter(sk, skb))
+ goto discard_release;
+
+ /* Create an SCTP packet structure. */
+@@ -255,10 +252,13 @@ int sctp_rcv(struct sk_buff *skb)
+ */
+ sctp_bh_lock_sock(sk);
+
+- if (sock_owned_by_user(sk))
++ if (sock_owned_by_user(sk)) {
++ SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG);
+ sctp_add_backlog(sk, skb);
+- else
++ } else {
++ SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_SOFTIRQ);
+ sctp_inq_push(&chunk->rcvr->inqueue, chunk);
++ }
+
+ sctp_bh_unlock_sock(sk);
+
+@@ -271,6 +271,7 @@ int sctp_rcv(struct sk_buff *skb)
+ return 0;
+
+ discard_it:
++ SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_DISCARDS);
+ kfree_skb(skb);
+ return 0;
+
+@@ -384,7 +385,7 @@ void sctp_icmp_frag_needed(struct sock *
+ * pmtu discovery on this transport.
+ */
+ t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
+- t->param_flags = (t->param_flags & ~SPP_HB) |
++ t->param_flags = (t->param_flags & ~SPP_PMTUD) |
+ SPP_PMTUD_DISABLE;
+ } else {
+ t->pathmtu = pmtu;
+@@ -770,6 +771,9 @@ static void __sctp_hash_established(stru
+ /* Add an association to the hash. Local BH-safe. */
+ void sctp_hash_established(struct sctp_association *asoc)
+ {
++ if (asoc->temp)
++ return;
++
+ sctp_local_bh_disable();
+ __sctp_hash_established(asoc);
+ sctp_local_bh_enable();
+@@ -803,6 +807,9 @@ static void __sctp_unhash_established(st
+ /* Remove association from the hash table. Local BH-safe. */
+ void sctp_unhash_established(struct sctp_association *asoc)
+ {
++ if (asoc->temp)
++ return;
++
+ sctp_local_bh_disable();
+ __sctp_unhash_established(asoc);
+ sctp_local_bh_enable();
+diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
+index cf0c767..cf6deed 100644
+--- a/net/sctp/inqueue.c
++++ b/net/sctp/inqueue.c
+@@ -87,7 +87,7 @@ void sctp_inq_free(struct sctp_inq *queu
+ /* Put a new packet in an SCTP inqueue.
+ * We assume that packet->sctp_hdr is set and in host byte order.
+ */
+-void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet)
++void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk)
+ {
+ /* Directly call the packet handling routine. */
+
+@@ -96,7 +96,7 @@ void sctp_inq_push(struct sctp_inq *q, s
+ * Eventually, we should clean up inqueue to not rely
+ * on the BH related data structures.
+ */
+- list_add_tail(&packet->list, &q->in_chunk_list);
++ list_add_tail(&chunk->list, &q->in_chunk_list);
+ q->immediate.func(q->immediate.data);
+ }
+
+diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
+index 99c0cef..78071c6 100644
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -78,7 +78,6 @@
+
+ #include <asm/uaccess.h>
+
+-extern int sctp_inetaddr_event(struct notifier_block *, unsigned long, void *);
+ static struct notifier_block sctp_inet6addr_notifier = {
+ .notifier_call = sctp_inetaddr_event,
+ };
+@@ -216,17 +215,17 @@ static struct dst_entry *sctp_v6_get_dst
+ }
+
+ dst = ip6_route_output(NULL, &fl);
+- if (dst) {
++ if (!dst->error) {
+ struct rt6_info *rt;
+ rt = (struct rt6_info *)dst;
+ SCTP_DEBUG_PRINTK(
+ "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
+ NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
+- } else {
+- SCTP_DEBUG_PRINTK("NO ROUTE\n");
++ return dst;
+ }
+-
+- return dst;
++ SCTP_DEBUG_PRINTK("NO ROUTE\n");
++ dst_release(dst);
++ return NULL;
+ }
+
+ /* Returns the number of consecutive initial bits that match in the 2 ipv6
+@@ -322,9 +321,9 @@ static void sctp_v6_copy_addrlist(struct
+ struct inet6_ifaddr *ifp;
+ struct sctp_sockaddr_entry *addr;
+
+- read_lock(&addrconf_lock);
++ rcu_read_lock();
+ if ((in6_dev = __in6_dev_get(dev)) == NULL) {
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ return;
+ }
+
+@@ -343,7 +342,7 @@ static void sctp_v6_copy_addrlist(struct
+ }
+
+ read_unlock(&in6_dev->lock);
+- read_unlock(&addrconf_lock);
++ rcu_read_unlock();
+ }
+
+ /* Initialize a sockaddr_storage from in incoming skb. */
+diff --git a/net/sctp/output.c b/net/sctp/output.c
+index cdc5a39..3ef4351 100644
+--- a/net/sctp/output.c
++++ b/net/sctp/output.c
+@@ -633,7 +633,7 @@ static sctp_xmit_t sctp_packet_append_da
+ * data will fit or delay in hopes of bundling a full
+ * sized packet.
+ */
+- if (len < asoc->pathmtu - packet->overhead) {
++ if (len < asoc->frag_point) {
+ retval = SCTP_XMIT_NAGLE_DELAY;
+ goto finish;
+ }
+@@ -645,7 +645,13 @@ static sctp_xmit_t sctp_packet_append_da
+ /* Keep track of how many bytes are in flight to the receiver. */
+ asoc->outqueue.outstanding_bytes += datasize;
+
+- /* Update our view of the receiver's rwnd. */
++ /* Update our view of the receiver's rwnd. Include sk_buff overhead
++ * while updating peer.rwnd so that it reduces the chances of a
++ * receiver running out of receive buffer space even when receive
++ * window is still open. This can happen when a sender is sending
++ * sending small messages.
++ */
++ datasize += sizeof(struct sk_buff);
+ if (datasize < rwnd)
+ rwnd -= datasize;
+ else
+diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
+index 30b710c..7395824 100644
+--- a/net/sctp/outqueue.c
++++ b/net/sctp/outqueue.c
+@@ -416,7 +416,8 @@ void sctp_retransmit_mark(struct sctp_ou
+ * (Section 7.2.4)), add the data size of those
+ * chunks to the rwnd.
+ */
+- q->asoc->peer.rwnd += sctp_data_size(chunk);
++ q->asoc->peer.rwnd += (sctp_data_size(chunk) +
++ sizeof(struct sk_buff));
+ q->outstanding_bytes -= sctp_data_size(chunk);
+ transport->flight_size -= sctp_data_size(chunk);
+
+@@ -467,6 +468,7 @@ void sctp_retransmit(struct sctp_outq *q
+
+ switch(reason) {
+ case SCTP_RTXR_T3_RTX:
++ SCTP_INC_STATS(SCTP_MIB_T3_RETRANSMITS);
+ sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
+ /* Update the retran path if the T3-rtx timer has expired for
+ * the current retran path.
+@@ -475,12 +477,15 @@ void sctp_retransmit(struct sctp_outq *q
+ sctp_assoc_update_retran_path(transport->asoc);
+ break;
+ case SCTP_RTXR_FAST_RTX:
++ SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
+ sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
+ fast_retransmit = 1;
+ break;
+ case SCTP_RTXR_PMTUD:
+- default:
++ SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
+ break;
++ default:
++ BUG();
+ }
+
+ sctp_retransmit_mark(q, transport, fast_retransmit);
+diff --git a/net/sctp/proc.c b/net/sctp/proc.c
+index 5b3b0e0..7f49e76 100644
+--- a/net/sctp/proc.c
++++ b/net/sctp/proc.c
+@@ -57,6 +57,21 @@ static struct snmp_mib sctp_snmp_list[]
+ SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS),
+ SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS),
+ SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS),
++ SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS),
++ SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS),
++ SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS),
++ SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS),
++ SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS),
++ SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS),
++ SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS),
++ SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS),
++ SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS),
++ SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS),
++ SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS),
++ SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ),
++ SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG),
++ SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS),
++ SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS),
+ SNMP_MIB_SENTINEL
+ };
+
+@@ -328,8 +343,8 @@ static int sctp_assocs_seq_show(struct s
+ "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
+ assoc, sk, sctp_sk(sk)->type, sk->sk_state,
+ assoc->state, hash, assoc->assoc_id,
+- (sk->sk_rcvbuf - assoc->rwnd),
+ assoc->sndbuf_used,
++ atomic_read(&assoc->rmem_alloc),
+ sock_i_uid(sk), sock_i_ino(sk),
+ epb->bind_addr.port,
+ assoc->peer.port);
+diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
+index 1ab03a2..5b4f82f 100644
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -61,7 +61,7 @@
+ #include <net/inet_ecn.h>
+
+ /* Global data structures. */
+-struct sctp_globals sctp_globals;
++struct sctp_globals sctp_globals __read_mostly;
+ struct proc_dir_entry *proc_net_sctp;
+ DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly;
+
+@@ -82,13 +82,6 @@ static struct sctp_af *sctp_af_v6_specif
+ kmem_cache_t *sctp_chunk_cachep __read_mostly;
+ kmem_cache_t *sctp_bucket_cachep __read_mostly;
+
+-extern int sctp_snmp_proc_init(void);
+-extern int sctp_snmp_proc_exit(void);
+-extern int sctp_eps_proc_init(void);
+-extern int sctp_eps_proc_exit(void);
+-extern int sctp_assocs_proc_init(void);
+-extern int sctp_assocs_proc_exit(void);
+-
+ /* Return the address of the control sock. */
+ struct sock *sctp_get_ctl_sock(void)
+ {
+@@ -598,7 +591,7 @@ static struct sock *sctp_v4_create_accep
+ newinet->dport = htons(asoc->peer.port);
+ newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
+ newinet->pmtudisc = inet->pmtudisc;
+- newinet->id = 0;
++ newinet->id = asoc->next_tsn ^ jiffies;
+
+ newinet->uc_ttl = -1;
+ newinet->mc_loop = 1;
+@@ -1049,7 +1042,7 @@ SCTP_STATIC __init int sctp_init(void)
+ sctp_rto_beta = SCTP_RTO_BETA;
+
+ /* Valid.Cookie.Life - 60 seconds */
+- sctp_valid_cookie_life = 60 * HZ;
++ sctp_valid_cookie_life = SCTP_DEFAULT_COOKIE_LIFE;
+
+ /* Whether Cookie Preservative is enabled(1) or not(0) */
+ sctp_cookie_preserve_enable = 1;
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 17b5092..507dff7 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -1282,10 +1282,8 @@ static sctp_cookie_param_t *sctp_pack_co
+
+ retval = kmalloc(*cookie_len, GFP_ATOMIC);
+
+- if (!retval) {
+- *cookie_len = 0;
++ if (!retval)
+ goto nodata;
+- }
+
+ /* Clear this memory since we are sending this data structure
+ * out on the network.
+@@ -1321,19 +1319,29 @@ static sctp_cookie_param_t *sctp_pack_co
+ ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
+
+ if (sctp_sk(ep->base.sk)->hmac) {
++ struct hash_desc desc;
++
+ /* Sign the message. */
+ sg.page = virt_to_page(&cookie->c);
+ sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE;
+ sg.length = bodysize;
+ keylen = SCTP_SECRET_SIZE;
+ key = (char *)ep->secret_key[ep->current_key];
++ desc.tfm = sctp_sk(ep->base.sk)->hmac;
++ desc.flags = 0;
+
+- sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
+- &sg, 1, cookie->signature);
++ if (crypto_hash_setkey(desc.tfm, key, keylen) ||
++ crypto_hash_digest(&desc, &sg, bodysize, cookie->signature))
++ goto free_cookie;
+ }
+
+-nodata:
+ return retval;
++
++free_cookie:
++ kfree(retval);
++nodata:
++ *cookie_len = 0;
++ return NULL;
+ }
+
+ /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */
+@@ -1354,6 +1362,7 @@ struct sctp_association *sctp_unpack_coo
+ sctp_scope_t scope;
+ struct sk_buff *skb = chunk->skb;
+ struct timeval tv;
++ struct hash_desc desc;
+
+ /* Header size is static data prior to the actual cookie, including
+ * any padding.
+@@ -1389,17 +1398,25 @@ struct sctp_association *sctp_unpack_coo
+ sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE;
+ sg.length = bodysize;
+ key = (char *)ep->secret_key[ep->current_key];
++ desc.tfm = sctp_sk(ep->base.sk)->hmac;
++ desc.flags = 0;
+
+ memset(digest, 0x00, SCTP_SIGNATURE_SIZE);
+- sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg,
+- 1, digest);
++ if (crypto_hash_setkey(desc.tfm, key, keylen) ||
++ crypto_hash_digest(&desc, &sg, bodysize, digest)) {
++ *error = -SCTP_IERROR_NOMEM;
++ goto fail;
++ }
+
+ if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
+ /* Try the previous key. */
+ key = (char *)ep->secret_key[ep->last_key];
+ memset(digest, 0x00, SCTP_SIGNATURE_SIZE);
+- sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
+- &sg, 1, digest);
++ if (crypto_hash_setkey(desc.tfm, key, keylen) ||
++ crypto_hash_digest(&desc, &sg, bodysize, digest)) {
++ *error = -SCTP_IERROR_NOMEM;
++ goto fail;
++ }
+
+ if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
+ /* Yikes! Still bad signature! */
+@@ -1430,8 +1447,16 @@ no_hmac:
+ /* Check to see if the cookie is stale. If there is already
+ * an association, there is no need to check cookie's expiration
+ * for init collision case of lost COOKIE ACK.
++ * If skb has been timestamped, then use the stamp, otherwise
++ * use current time. This introduces a small possibility that
++ * that a cookie may be considered expired, but his would only slow
++ * down the new association establishment instead of every packet.
+ */
+- skb_get_timestamp(skb, &tv);
++ if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
++ skb_get_timestamp(skb, &tv);
++ else
++ do_gettimeofday(&tv);
++
+ if (!asoc && tv_lt(bear_cookie->expiration, tv)) {
+ __u16 len;
+ /*
+diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
+index 5b5ae79..1c42fe9 100644
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -187,10 +187,9 @@ sctp_disposition_t sctp_sf_do_4_C(const
+ */
+ ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
+ 0, 0, 0, GFP_ATOMIC);
+- if (!ev)
+- goto nomem;
+-
+- sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
++ if (ev)
++ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
++ SCTP_ULPEVENT(ev));
+
+ /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint
+ * will verify that it is in SHUTDOWN-ACK-SENT state, if it is
+@@ -215,9 +214,6 @@ sctp_disposition_t sctp_sf_do_4_C(const
+ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
+
+ return SCTP_DISPOSITION_DELETE_TCB;
+-
+-nomem:
+- return SCTP_DISPOSITION_NOMEM;
+ }
+
+ /*
+@@ -347,8 +343,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(
+ GFP_ATOMIC))
+ goto nomem_init;
+
+- sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
+-
+ /* B) "Z" shall respond immediately with an INIT ACK chunk. */
+
+ /* If there are errors need to be reported for unknown parameters,
+@@ -360,11 +354,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(
+ sizeof(sctp_chunkhdr_t);
+
+ if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)
+- goto nomem_ack;
++ goto nomem_init;
+
+ repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
+ if (!repl)
+- goto nomem_ack;
++ goto nomem_init;
+
+ /* If there are errors need to be reported for unknown parameters,
+ * include them in the outgoing INIT ACK as "Unrecognized parameter"
+@@ -388,6 +382,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(
+ sctp_chunk_free(err_chunk);
+ }
+
++ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
++
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+
+ /*
+@@ -400,12 +396,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(
+
+ return SCTP_DISPOSITION_DELETE_TCB;
+
+-nomem_ack:
+- if (err_chunk)
+- sctp_chunk_free(err_chunk);
+ nomem_init:
+ sctp_association_free(new_asoc);
+ nomem:
++ if (err_chunk)
++ sctp_chunk_free(err_chunk);
+ return SCTP_DISPOSITION_NOMEM;
+ }
+
+@@ -600,7 +595,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co
+ struct sctp_association *new_asoc;
+ sctp_init_chunk_t *peer_init;
+ struct sctp_chunk *repl;
+- struct sctp_ulpevent *ev;
++ struct sctp_ulpevent *ev, *ai_ev = NULL;
+ int error = 0;
+ struct sctp_chunk *err_chk_p;
+
+@@ -659,20 +654,10 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co
+ };
+ }
+
+- sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
+- sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+- SCTP_STATE(SCTP_STATE_ESTABLISHED));
+- SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
+- SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS);
+- sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
+
+- if (new_asoc->autoclose)
+- sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
+- SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
+-
+- sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
+-
+- /* Re-build the bind address for the association is done in
++ /* Delay state machine commands until later.
++ *
++ * Re-build the bind address for the association is done in
+ * the sctp_unpack_cookie() already.
+ */
+ /* This is a brand-new association, so these are not yet side
+@@ -687,9 +672,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co
+
+ repl = sctp_make_cookie_ack(new_asoc, chunk);
+ if (!repl)
+- goto nomem_repl;
+-
+- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
++ goto nomem_init;
+
+ /* RFC 2960 5.1 Normal Establishment of an Association
+ *
+@@ -704,28 +687,53 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co
+ if (!ev)
+ goto nomem_ev;
+
+- sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+-
+ /* Sockets API Draft Section 5.3.1.6
+ * When a peer sends a Adaption Layer Indication parameter , SCTP
+ * delivers this notification to inform the application that of the
+ * peers requested adaption layer.
+ */
+ if (new_asoc->peer.adaption_ind) {
+- ev = sctp_ulpevent_make_adaption_indication(new_asoc,
++ ai_ev = sctp_ulpevent_make_adaption_indication(new_asoc,
+ GFP_ATOMIC);
+- if (!ev)
+- goto nomem_ev;
++ if (!ai_ev)
++ goto nomem_aiev;
++ }
++
++ /* Add all the state machine commands now since we've created
++ * everything. This way we don't introduce memory corruptions
++ * during side-effect processing and correclty count established
++ * associations.
++ */
++ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
++ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
++ SCTP_STATE(SCTP_STATE_ESTABLISHED));
++ SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
++ SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS);
++ sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
++
++ if (new_asoc->autoclose)
++ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
++ SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
+
++ sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
++
++ /* This will send the COOKIE ACK */
++ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
++
++ /* Queue the ASSOC_CHANGE event */
++ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
++
++ /* Send up the Adaptation Layer Indication event */
++ if (ai_ev)
+ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+- SCTP_ULPEVENT(ev));
+- }
++ SCTP_ULPEVENT(ai_ev));
+
+ return SCTP_DISPOSITION_CONSUME;
+
++nomem_aiev:
++ sctp_ulpevent_free(ev);
+ nomem_ev:
+ sctp_chunk_free(repl);
+-nomem_repl:
+ nomem_init:
+ sctp_association_free(new_asoc);
+ nomem:
+@@ -1360,10 +1368,8 @@ static sctp_disposition_t sctp_sf_do_une
+ if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
+ sctp_source(chunk),
+ (sctp_init_chunk_t *)chunk->chunk_hdr,
+- GFP_ATOMIC)) {
+- retval = SCTP_DISPOSITION_NOMEM;
+- goto nomem_init;
+- }
++ GFP_ATOMIC))
++ goto nomem;
+
+ /* Make sure no new addresses are being added during the
+ * restart. Do not do this check for COOKIE-WAIT state,
+@@ -1374,7 +1380,7 @@ static sctp_disposition_t sctp_sf_do_une
+ if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
+ commands)) {
+ retval = SCTP_DISPOSITION_CONSUME;
+- goto cleanup_asoc;
++ goto nomem_retval;
+ }
+ }
+
+@@ -1430,17 +1436,17 @@ static sctp_disposition_t sctp_sf_do_une
+ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
+ retval = SCTP_DISPOSITION_CONSUME;
+
++ return retval;
++
++nomem:
++ retval = SCTP_DISPOSITION_NOMEM;
++nomem_retval:
++ if (new_asoc)
++ sctp_association_free(new_asoc);
+ cleanup:
+ if (err_chunk)
+ sctp_chunk_free(err_chunk);
+ return retval;
+-nomem:
+- retval = SCTP_DISPOSITION_NOMEM;
+- goto cleanup;
+-nomem_init:
+-cleanup_asoc:
+- sctp_association_free(new_asoc);
+- goto cleanup;
+ }
+
+ /*
+@@ -1611,15 +1617,10 @@ static sctp_disposition_t sctp_sf_do_dup
+ */
+ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL());
+
+- /* Update the content of current association. */
+- sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
+-
+ repl = sctp_make_cookie_ack(new_asoc, chunk);
+ if (!repl)
+ goto nomem;
+
+- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+-
+ /* Report association restart to upper layer. */
+ ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
+ new_asoc->c.sinit_num_ostreams,
+@@ -1628,6 +1629,9 @@ static sctp_disposition_t sctp_sf_do_dup
+ if (!ev)
+ goto nomem_ev;
+
++ /* Update the content of current association. */
++ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
++ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+ return SCTP_DISPOSITION_CONSUME;
+
+@@ -1751,7 +1755,7 @@ static sctp_disposition_t sctp_sf_do_dup
+ sctp_cmd_seq_t *commands,
+ struct sctp_association *new_asoc)
+ {
+- struct sctp_ulpevent *ev = NULL;
++ struct sctp_ulpevent *ev = NULL, *ai_ev = NULL;
+ struct sctp_chunk *repl;
+
+ /* Clarification from Implementor's Guide:
+@@ -1778,29 +1782,25 @@ static sctp_disposition_t sctp_sf_do_dup
+ * SCTP user upon reception of a valid COOKIE
+ * ECHO chunk.
+ */
+- ev = sctp_ulpevent_make_assoc_change(new_asoc, 0,
++ ev = sctp_ulpevent_make_assoc_change(asoc, 0,
+ SCTP_COMM_UP, 0,
+- new_asoc->c.sinit_num_ostreams,
+- new_asoc->c.sinit_max_instreams,
++ asoc->c.sinit_num_ostreams,
++ asoc->c.sinit_max_instreams,
+ GFP_ATOMIC);
+ if (!ev)
+ goto nomem;
+- sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+- SCTP_ULPEVENT(ev));
+
+ /* Sockets API Draft Section 5.3.1.6
+ * When a peer sends a Adaption Layer Indication parameter,
+ * SCTP delivers this notification to inform the application
+ * that of the peers requested adaption layer.
+ */
+- if (new_asoc->peer.adaption_ind) {
+- ev = sctp_ulpevent_make_adaption_indication(new_asoc,
++ if (asoc->peer.adaption_ind) {
++ ai_ev = sctp_ulpevent_make_adaption_indication(asoc,
+ GFP_ATOMIC);
+- if (!ev)
++ if (!ai_ev)
+ goto nomem;
+
+- sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+- SCTP_ULPEVENT(ev));
+ }
+ }
+ sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
+@@ -1809,12 +1809,21 @@ static sctp_disposition_t sctp_sf_do_dup
+ if (!repl)
+ goto nomem;
+
++ if (ev)
++ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
++ SCTP_ULPEVENT(ev));
++ if (ai_ev)
++ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
++ SCTP_ULPEVENT(ai_ev));
++
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+ sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
+
+ return SCTP_DISPOSITION_CONSUME;
+
+ nomem:
++ if (ai_ev)
++ sctp_ulpevent_free(ai_ev);
+ if (ev)
+ sctp_ulpevent_free(ev);
+ return SCTP_DISPOSITION_NOMEM;
+@@ -2663,9 +2672,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(
+ break;
+ case SCTP_IERROR_HIGH_TSN:
+ case SCTP_IERROR_BAD_STREAM:
++ SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
+ goto discard_noforce;
+ case SCTP_IERROR_DUP_TSN:
+ case SCTP_IERROR_IGNORE_TSN:
++ SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
+ goto discard_force;
+ case SCTP_IERROR_NO_DATA:
+ goto consume;
+@@ -3017,7 +3028,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(
+ if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+ return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+ commands);
+-
+ /* 10.2 H) SHUTDOWN COMPLETE notification
+ *
+ * When SCTP completes the shutdown procedures (section 9.2) this
+@@ -3028,6 +3038,14 @@ sctp_disposition_t sctp_sf_do_9_2_final(
+ if (!ev)
+ goto nomem;
+
++ /* ...send a SHUTDOWN COMPLETE chunk to its peer, */
++ reply = sctp_make_shutdown_complete(asoc, chunk);
++ if (!reply)
++ goto nomem_chunk;
++
++ /* Do all the commands now (after allocation), so that we
++ * have consistent state if memory allocation failes
++ */
+ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+
+ /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall
+@@ -3039,11 +3057,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(
+ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+ SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
+
+- /* ...send a SHUTDOWN COMPLETE chunk to its peer, */
+- reply = sctp_make_shutdown_complete(asoc, chunk);
+- if (!reply)
+- goto nomem;
+-
+ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+ SCTP_STATE(SCTP_STATE_CLOSED));
+ SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
+@@ -3054,6 +3067,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(
+ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
+ return SCTP_DISPOSITION_DELETE_TCB;
+
++nomem_chunk:
++ sctp_ulpevent_free(ev);
+ nomem:
+ return SCTP_DISPOSITION_NOMEM;
+ }
+@@ -3652,6 +3667,7 @@ sctp_disposition_t sctp_sf_pdiscard(cons
+ void *arg,
+ sctp_cmd_seq_t *commands)
+ {
++ SCTP_INC_STATS(SCTP_MIB_IN_PKT_DISCARDS);
+ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
+
+ return SCTP_DISPOSITION_CONSUME;
+@@ -4548,6 +4564,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(
+ {
+ struct sctp_transport *transport = arg;
+
++ SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS);
++
+ if (asoc->overall_error_count >= asoc->max_retrans) {
+ sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+ SCTP_ERROR(ETIMEDOUT));
+@@ -4616,6 +4634,7 @@ sctp_disposition_t sctp_sf_do_6_2_sack(c
+ void *arg,
+ sctp_cmd_seq_t *commands)
+ {
++ SCTP_INC_STATS(SCTP_MIB_DELAY_SACK_EXPIREDS);
+ sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
+ return SCTP_DISPOSITION_CONSUME;
+ }
+@@ -4650,6 +4669,7 @@ sctp_disposition_t sctp_sf_t1_init_timer
+ int attempts = asoc->init_err_counter + 1;
+
+ SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n");
++ SCTP_INC_STATS(SCTP_MIB_T1_INIT_EXPIREDS);
+
+ if (attempts <= asoc->max_init_attempts) {
+ bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
+@@ -4709,6 +4729,7 @@ sctp_disposition_t sctp_sf_t1_cookie_tim
+ int attempts = asoc->init_err_counter + 1;
+
+ SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n");
++ SCTP_INC_STATS(SCTP_MIB_T1_COOKIE_EXPIREDS);
+
+ if (attempts <= asoc->max_init_attempts) {
+ repl = sctp_make_cookie_echo(asoc, NULL);
+@@ -4753,6 +4774,8 @@ sctp_disposition_t sctp_sf_t2_timer_expi
+ struct sctp_chunk *reply = NULL;
+
+ SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
++ SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
++
+ if (asoc->overall_error_count >= asoc->max_retrans) {
+ sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+ SCTP_ERROR(ETIMEDOUT));
+@@ -4814,6 +4837,8 @@ sctp_disposition_t sctp_sf_t4_timer_expi
+ struct sctp_chunk *chunk = asoc->addip_last_asconf;
+ struct sctp_transport *transport = chunk->transport;
+
++ SCTP_INC_STATS(SCTP_MIB_T4_RTO_EXPIREDS);
++
+ /* ADDIP 4.1 B1) Increment the error counters and perform path failure
+ * detection on the appropriate destination address as defined in
+ * RFC2960 [5] section 8.1 and 8.2.
+@@ -4880,6 +4905,7 @@ sctp_disposition_t sctp_sf_t5_timer_expi
+ struct sctp_chunk *reply = NULL;
+
+ SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
++ SCTP_INC_STATS(SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS);
+
+ reply = sctp_make_abort(asoc, NULL, 0);
+ if (!reply)
+@@ -4910,6 +4936,8 @@ sctp_disposition_t sctp_sf_autoclose_tim
+ {
+ int disposition;
+
++ SCTP_INC_STATS(SCTP_MIB_AUTOCLOSE_EXPIREDS);
++
+ /* From 9.2 Shutdown of an Association
+ * Upon receipt of the SHUTDOWN primitive from its upper
+ * layer, the endpoint enters SHUTDOWN-PENDING state and
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index dab1594..935bc91 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -821,7 +821,7 @@ out:
+ * addrs is a pointer to an array of one or more socket addresses. Each
+ * address is contained in its appropriate structure (i.e. struct
+ * sockaddr_in or struct sockaddr_in6) the family of the address type
+- * must be used to distengish the address length (note that this
++ * must be used to distinguish the address length (note that this
+ * representation is termed a "packed array" of addresses). The caller
+ * specifies the number of addresses in the array with addrcnt.
+ *
+@@ -2081,13 +2081,13 @@ static int sctp_setsockopt_autoclose(str
+ * SPP_SACKDELAY_ENABLE, setting both will have undefined
+ * results.
+ */
+-int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
+- struct sctp_transport *trans,
+- struct sctp_association *asoc,
+- struct sctp_sock *sp,
+- int hb_change,
+- int pmtud_change,
+- int sackdelay_change)
++static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
++ struct sctp_transport *trans,
++ struct sctp_association *asoc,
++ struct sctp_sock *sp,
++ int hb_change,
++ int pmtud_change,
++ int sackdelay_change)
+ {
+ int error;
+
+@@ -2970,7 +2970,7 @@ SCTP_STATIC struct sock *sctp_accept(str
+ goto out;
+ }
+
+- timeo = sock_rcvtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+ error = sctp_wait_for_accept(sk, timeo);
+ if (error)
+@@ -3045,14 +3045,14 @@ SCTP_STATIC int sctp_init_sock(struct so
+ sp->initmsg.sinit_num_ostreams = sctp_max_outstreams;
+ sp->initmsg.sinit_max_instreams = sctp_max_instreams;
+ sp->initmsg.sinit_max_attempts = sctp_max_retrans_init;
+- sp->initmsg.sinit_max_init_timeo = jiffies_to_msecs(sctp_rto_max);
++ sp->initmsg.sinit_max_init_timeo = sctp_rto_max;
+
+ /* Initialize default RTO related parameters. These parameters can
+ * be modified for with the SCTP_RTOINFO socket option.
+ */
+- sp->rtoinfo.srto_initial = jiffies_to_msecs(sctp_rto_initial);
+- sp->rtoinfo.srto_max = jiffies_to_msecs(sctp_rto_max);
+- sp->rtoinfo.srto_min = jiffies_to_msecs(sctp_rto_min);
++ sp->rtoinfo.srto_initial = sctp_rto_initial;
++ sp->rtoinfo.srto_max = sctp_rto_max;
++ sp->rtoinfo.srto_min = sctp_rto_min;
+
+ /* Initialize default association related parameters. These parameters
+ * can be modified with the SCTP_ASSOCINFO socket option.
+@@ -3061,8 +3061,7 @@ SCTP_STATIC int sctp_init_sock(struct so
+ sp->assocparams.sasoc_number_peer_destinations = 0;
+ sp->assocparams.sasoc_peer_rwnd = 0;
+ sp->assocparams.sasoc_local_rwnd = 0;
+- sp->assocparams.sasoc_cookie_life =
+- jiffies_to_msecs(sctp_valid_cookie_life);
++ sp->assocparams.sasoc_cookie_life = sctp_valid_cookie_life;
+
+ /* Initialize default event subscriptions. By default, all the
+ * options are off.
+@@ -3072,10 +3071,10 @@ SCTP_STATIC int sctp_init_sock(struct so
+ /* Default Peer Address Parameters. These defaults can
+ * be modified via SCTP_PEER_ADDR_PARAMS
+ */
+- sp->hbinterval = jiffies_to_msecs(sctp_hb_interval);
++ sp->hbinterval = sctp_hb_interval;
+ sp->pathmaxrxt = sctp_max_retrans_path;
+ sp->pathmtu = 0; // allow default discovery
+- sp->sackdelay = jiffies_to_msecs(sctp_sack_timeout);
++ sp->sackdelay = sctp_sack_timeout;
+ sp->param_flags = SPP_HB_ENABLE |
+ SPP_PMTUD_ENABLE |
+ SPP_SACKDELAY_ENABLE;
+@@ -3085,8 +3084,8 @@ SCTP_STATIC int sctp_init_sock(struct so
+ */
+ sp->disable_fragments = 0;
+
+- /* Turn on/off any Nagle-like algorithm. */
+- sp->nodelay = 1;
++ /* Enable Nagle algorithm by default. */
++ sp->nodelay = 0;
+
+ /* Enable by default. */
+ sp->v4mapped = 1;
+@@ -3373,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct s
+ {
+ struct sock *sk = asoc->base.sk;
+ struct socket *sock;
++ struct inet_sock *inetsk;
+ int err = 0;
+
+ /* An association cannot be branched off from an already peeled-off
+@@ -3390,6 +3390,14 @@ SCTP_STATIC int sctp_do_peeloff(struct s
+ * asoc to the newsk.
+ */
+ sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
++
++ /* Make peeled-off sockets more like 1-1 accepted sockets.
++ * Set the daddr and initialize id to something more random
++ */
++ inetsk = inet_sk(sock->sk);
++ inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
++ inetsk->id = asoc->next_tsn ^ jiffies;
++
+ *sockp = sock;
+
+ return err;
+@@ -4898,7 +4906,7 @@ SCTP_STATIC int sctp_stream_listen(struc
+ int sctp_inet_listen(struct socket *sock, int backlog)
+ {
+ struct sock *sk = sock->sk;
+- struct crypto_tfm *tfm=NULL;
++ struct crypto_hash *tfm = NULL;
+ int err = -EINVAL;
+
+ if (unlikely(backlog < 0))
+@@ -4911,7 +4919,7 @@ int sctp_inet_listen(struct socket *sock
+
+ /* Allocate HMAC for generating cookie. */
+ if (sctp_hmac_alg) {
+- tfm = sctp_crypto_alloc_tfm(sctp_hmac_alg, 0);
++ tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
+ if (!tfm) {
+ err = -ENOSYS;
+ goto out;
+@@ -4937,7 +4945,7 @@ out:
+ sctp_release_sock(sk);
+ return err;
+ cleanup:
+- sctp_crypto_free_tfm(tfm);
++ crypto_free_hash(tfm);
+ goto out;
+ }
+
+@@ -5363,6 +5371,20 @@ static void sctp_wfree(struct sk_buff *s
+ sctp_association_put(asoc);
+ }
+
++/* Do accounting for the receive space on the socket.
++ * Accounting for the association is done in ulpevent.c
++ * We set this as a destructor for the cloned data skbs so that
++ * accounting is done at the correct time.
++ */
++void sctp_sock_rfree(struct sk_buff *skb)
++{
++ struct sock *sk = skb->sk;
++ struct sctp_ulpevent *event = sctp_skb2event(skb);
++
++ atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
++}
++
++
+ /* Helper function to wait for space in the sndbuf. */
+ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
+ size_t msg_len)
+@@ -5619,6 +5641,8 @@ static void sctp_sock_migrate(struct soc
+ /* Copy the bind_addr list from the original endpoint to the new
+ * endpoint so that we can handle restarts properly
+ */
++ if (PF_INET6 == assoc->base.sk->sk_family)
++ flags = SCTP_ADDR6_ALLOWED;
+ if (assoc->peer.ipv4_address)
+ flags |= SCTP_ADDR4_PEERSUPP;
+ if (assoc->peer.ipv6_address)
+@@ -5633,10 +5657,10 @@ static void sctp_sock_migrate(struct soc
+ sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
+ event = sctp_skb2event(skb);
+ if (event->asoc == assoc) {
+- sock_rfree(skb);
++ sctp_sock_rfree(skb);
+ __skb_unlink(skb, &oldsk->sk_receive_queue);
+ __skb_queue_tail(&newsk->sk_receive_queue, skb);
+- skb_set_owner_r(skb, newsk);
++ sctp_skb_set_owner_r(skb, newsk);
+ }
+ }
+
+@@ -5664,10 +5688,10 @@ static void sctp_sock_migrate(struct soc
+ sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
+ event = sctp_skb2event(skb);
+ if (event->asoc == assoc) {
+- sock_rfree(skb);
++ sctp_sock_rfree(skb);
+ __skb_unlink(skb, &oldsp->pd_lobby);
+ __skb_queue_tail(queue, skb);
+- skb_set_owner_r(skb, newsk);
++ sctp_skb_set_owner_r(skb, newsk);
+ }
+ }
+
+diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
+index dc6f3ff..633cd17 100644
+--- a/net/sctp/sysctl.c
++++ b/net/sctp/sysctl.c
+@@ -45,9 +45,10 @@
+ #include <net/sctp/sctp.h>
+ #include <linux/sysctl.h>
+
+-static ctl_handler sctp_sysctl_jiffies_ms;
+-static long rto_timer_min = 1;
+-static long rto_timer_max = 86400000; /* One day */
++static int zero = 0;
++static int one = 1;
++static int timer_max = 86400000; /* ms in one day */
++static int int_max = INT_MAX;
+ static long sack_timer_min = 1;
+ static long sack_timer_max = 500;
+
+@@ -56,45 +57,45 @@ static ctl_table sctp_table[] = {
+ .ctl_name = NET_SCTP_RTO_INITIAL,
+ .procname = "rto_initial",
+ .data = &sctp_rto_initial,
+- .maxlen = sizeof(long),
++ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+- .strategy = &sctp_sysctl_jiffies_ms,
+- .extra1 = &rto_timer_min,
+- .extra2 = &rto_timer_max
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &timer_max
+ },
+ {
+ .ctl_name = NET_SCTP_RTO_MIN,
+ .procname = "rto_min",
+ .data = &sctp_rto_min,
+- .maxlen = sizeof(long),
++ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+- .strategy = &sctp_sysctl_jiffies_ms,
+- .extra1 = &rto_timer_min,
+- .extra2 = &rto_timer_max
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &timer_max
+ },
+ {
+ .ctl_name = NET_SCTP_RTO_MAX,
+ .procname = "rto_max",
+ .data = &sctp_rto_max,
+- .maxlen = sizeof(long),
++ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+- .strategy = &sctp_sysctl_jiffies_ms,
+- .extra1 = &rto_timer_min,
+- .extra2 = &rto_timer_max
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &timer_max
+ },
+ {
+ .ctl_name = NET_SCTP_VALID_COOKIE_LIFE,
+ .procname = "valid_cookie_life",
+ .data = &sctp_valid_cookie_life,
+- .maxlen = sizeof(long),
++ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+- .strategy = &sctp_sysctl_jiffies_ms,
+- .extra1 = &rto_timer_min,
+- .extra2 = &rto_timer_max
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &timer_max
+ },
+ {
+ .ctl_name = NET_SCTP_MAX_BURST,
+@@ -102,7 +103,10 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_max_burst,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &zero,
++ .extra2 = &int_max
+ },
+ {
+ .ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS,
+@@ -110,7 +114,10 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_max_retrans_association,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &int_max
+ },
+ {
+ .ctl_name = NET_SCTP_SNDBUF_POLICY,
+@@ -118,7 +125,8 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_sndbuf_policy,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_RCVBUF_POLICY,
+@@ -126,7 +134,8 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_rcvbuf_policy,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_PATH_MAX_RETRANS,
+@@ -134,7 +143,10 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_max_retrans_path,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &int_max
+ },
+ {
+ .ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS,
+@@ -142,18 +154,21 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_max_retrans_init,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &int_max
+ },
+ {
+ .ctl_name = NET_SCTP_HB_INTERVAL,
+ .procname = "hb_interval",
+ .data = &sctp_hb_interval,
+- .maxlen = sizeof(long),
++ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+- .strategy = &sctp_sysctl_jiffies_ms,
+- .extra1 = &rto_timer_min,
+- .extra2 = &rto_timer_max
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
++ .extra1 = &one,
++ .extra2 = &timer_max
+ },
+ {
+ .ctl_name = NET_SCTP_PRESERVE_ENABLE,
+@@ -161,23 +176,26 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_cookie_preserve_enable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_RTO_ALPHA,
+ .procname = "rto_alpha_exp_divisor",
+ .data = &sctp_rto_alpha,
+ .maxlen = sizeof(int),
+- .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .mode = 0444,
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_RTO_BETA,
+ .procname = "rto_beta_exp_divisor",
+ .data = &sctp_rto_beta,
+ .maxlen = sizeof(int),
+- .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .mode = 0444,
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_ADDIP_ENABLE,
+@@ -185,7 +203,8 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_addip_enable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_PRSCTP_ENABLE,
+@@ -193,7 +212,8 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_prsctp_enable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = &proc_dointvec
++ .proc_handler = &proc_dointvec,
++ .strategy = &sysctl_intvec
+ },
+ {
+ .ctl_name = NET_SCTP_SACK_TIMEOUT,
+@@ -201,8 +221,8 @@ static ctl_table sctp_table[] = {
+ .data = &sctp_sack_timeout,
+ .maxlen = sizeof(long),
+ .mode = 0644,
+- .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+- .strategy = &sctp_sysctl_jiffies_ms,
++ .proc_handler = &proc_dointvec_minmax,
++ .strategy = &sysctl_intvec,
+ .extra1 = &sack_timer_min,
+ .extra2 = &sack_timer_max,
+ },
+@@ -242,37 +262,3 @@ void sctp_sysctl_unregister(void)
+ {
+ unregister_sysctl_table(sctp_sysctl_header);
+ }
+-
+-/* Strategy function to convert jiffies to milliseconds. */
+-static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
+- void __user *oldval, size_t __user *oldlenp,
+- void __user *newval, size_t newlen, void **context) {
+-
+- if (oldval) {
+- size_t olen;
+-
+- if (oldlenp) {
+- if (get_user(olen, oldlenp))
+- return -EFAULT;
+-
+- if (olen != sizeof (int))
+- return -EINVAL;
+- }
+- if (put_user((*(int *)(table->data) * 1000) / HZ,
+- (int __user *)oldval) ||
+- (oldlenp && put_user(sizeof (int), oldlenp)))
+- return -EFAULT;
+- }
+- if (newval && newlen) {
+- int new;
+-
+- if (newlen != sizeof (int))
+- return -EINVAL;
+-
+- if (get_user(new, (int __user *)newval))
+- return -EFAULT;
+-
+- *(int *)(table->data) = (new * HZ) / 1000;
+- }
+- return 1;
+-}
+diff --git a/net/sctp/transport.c b/net/sctp/transport.c
+index 2763aa9..3e5936a 100644
+--- a/net/sctp/transport.c
++++ b/net/sctp/transport.c
+@@ -75,7 +75,7 @@ static struct sctp_transport *sctp_trans
+ * parameter 'RTO.Initial'.
+ */
+ peer->rtt = 0;
+- peer->rto = sctp_rto_initial;
++ peer->rto = msecs_to_jiffies(sctp_rto_initial);
+ peer->rttvar = 0;
+ peer->srtt = 0;
+ peer->rto_pending = 0;
+diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
+index ee23678..a015283 100644
+--- a/net/sctp/ulpevent.c
++++ b/net/sctp/ulpevent.c
+@@ -55,10 +55,13 @@ static void sctp_ulpevent_release_frag_d
+
+
+ /* Initialize an ULP event from an given skb. */
+-SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
++SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event,
++ int msg_flags,
++ unsigned int len)
+ {
+ memset(event, 0, sizeof(struct sctp_ulpevent));
+ event->msg_flags = msg_flags;
++ event->rmem_len = len;
+ }
+
+ /* Create a new sctp_ulpevent. */
+@@ -73,7 +76,7 @@ SCTP_STATIC struct sctp_ulpevent *sctp_u
+ goto fail;
+
+ event = sctp_skb2event(skb);
+- sctp_ulpevent_init(event, msg_flags);
++ sctp_ulpevent_init(event, msg_flags, skb->truesize);
+
+ return event;
+
+@@ -101,17 +104,16 @@ static inline void sctp_ulpevent_set_own
+ sctp_association_hold((struct sctp_association *)asoc);
+ skb = sctp_event2skb(event);
+ event->asoc = (struct sctp_association *)asoc;
+- atomic_add(skb->truesize, &event->asoc->rmem_alloc);
+- skb_set_owner_r(skb, asoc->base.sk);
++ atomic_add(event->rmem_len, &event->asoc->rmem_alloc);
++ sctp_skb_set_owner_r(skb, asoc->base.sk);
+ }
+
+ /* A simple destructor to give up the reference to the association. */
+ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
+ {
+ struct sctp_association *asoc = event->asoc;
+- struct sk_buff *skb = sctp_event2skb(event);
+
+- atomic_sub(skb->truesize, &asoc->rmem_alloc);
++ atomic_sub(event->rmem_len, &asoc->rmem_alloc);
+ sctp_association_put(asoc);
+ }
+
+@@ -372,7 +374,7 @@ struct sctp_ulpevent *sctp_ulpevent_make
+
+ /* Embed the event fields inside the cloned skb. */
+ event = sctp_skb2event(skb);
+- sctp_ulpevent_init(event, MSG_NOTIFICATION);
++ sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
+
+ sre = (struct sctp_remote_error *)
+ skb_push(skb, sizeof(struct sctp_remote_error));
+@@ -464,7 +466,7 @@ struct sctp_ulpevent *sctp_ulpevent_make
+
+ /* Embed the event fields inside the cloned skb. */
+ event = sctp_skb2event(skb);
+- sctp_ulpevent_init(event, MSG_NOTIFICATION);
++ sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
+
+ ssf = (struct sctp_send_failed *)
+ skb_push(skb, sizeof(struct sctp_send_failed));
+@@ -682,8 +684,11 @@ struct sctp_ulpevent *sctp_ulpevent_make
+ /* Embed the event fields inside the cloned skb. */
+ event = sctp_skb2event(skb);
+
+- /* Initialize event with flags 0. */
+- sctp_ulpevent_init(event, 0);
++ /* Initialize event with flags 0 and correct length
++ * Since this is a clone of the original skb, only account for
++ * the data of this chunk as other chunks will be accounted separately.
++ */
++ sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff));
+
+ sctp_ulpevent_receive_data(event, asoc);
+
+diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
+index 575e556..e1d1442 100644
+--- a/net/sctp/ulpqueue.c
++++ b/net/sctp/ulpqueue.c
+@@ -309,7 +309,7 @@ static struct sctp_ulpevent *sctp_make_r
+ if (!new)
+ return NULL; /* try again later */
+
+- new->sk = f_frag->sk;
++ sctp_skb_set_owner_r(new, f_frag->sk);
+
+ skb_shinfo(new)->frag_list = pos;
+ } else
+diff --git a/net/socket.c b/net/socket.c
+index 6d261bf..6c9b9b3 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -42,7 +42,7 @@
+ * Andi Kleen : Some small cleanups, optimizations,
+ * and fixed a copy_from_user() bug.
+ * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0)
+- * Tigran Aivazian : Made listen(2) backlog sanity checks
++ * Tigran Aivazian : Made listen(2) backlog sanity checks
+ * protocol-independent
+ *
+ *
+@@ -53,17 +53,17 @@
+ *
+ *
+ * This module is effectively the top level interface to the BSD socket
+- * paradigm.
++ * paradigm.
+ *
+ * Based upon Swansea University Computer Society NET3.039
+ */
+
+ #include <linux/mm.h>
+-#include <linux/smp_lock.h>
+ #include <linux/socket.h>
+ #include <linux/file.h>
+ #include <linux/net.h>
+ #include <linux/interrupt.h>
++#include <linux/rcupdate.h>
+ #include <linux/netdevice.h>
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+@@ -95,26 +95,21 @@
+ #include <linux/netfilter.h>
+
+ static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
+-static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf,
+- size_t size, loff_t pos);
+-static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf,
+- size_t size, loff_t pos);
+-static int sock_mmap(struct file *file, struct vm_area_struct * vma);
++static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos);
++static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos);
++static int sock_mmap(struct file *file, struct vm_area_struct *vma);
+
+ static int sock_close(struct inode *inode, struct file *file);
+ static unsigned int sock_poll(struct file *file,
+ struct poll_table_struct *wait);
+-static long sock_ioctl(struct file *file,
+- unsigned int cmd, unsigned long arg);
++static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+ #ifdef CONFIG_COMPAT
+ static long compat_sock_ioctl(struct file *file,
+- unsigned int cmd, unsigned long arg);
++ unsigned int cmd, unsigned long arg);
+ #endif
+ static int sock_fasync(int fd, struct file *filp, int on);
+-static ssize_t sock_readv(struct file *file, const struct iovec *vector,
+- unsigned long count, loff_t *ppos);
+-static ssize_t sock_writev(struct file *file, const struct iovec *vector,
+- unsigned long count, loff_t *ppos);
+ static ssize_t sock_sendpage(struct file *file, struct page *page,
+ int offset, size_t size, loff_t *ppos, int more);
+
+@@ -137,8 +132,6 @@ static struct file_operations socket_fil
+ .open = sock_no_open, /* special open code to disallow open via /proc */
+ .release = sock_close,
+ .fasync = sock_fasync,
+- .readv = sock_readv,
+- .writev = sock_writev,
+ .sendpage = sock_sendpage,
+ .splice_write = generic_splice_sendpage,
+ };
+@@ -147,52 +140,8 @@ static struct file_operations socket_fil
+ * The protocol list. Each protocol is registered in here.
+ */
+
+-static struct net_proto_family *net_families[NPROTO];
+-
+-#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+-static atomic_t net_family_lockct = ATOMIC_INIT(0);
+ static DEFINE_SPINLOCK(net_family_lock);
+-
+-/* The strategy is: modifications net_family vector are short, do not
+- sleep and veeery rare, but read access should be free of any exclusive
+- locks.
+- */
+-
+-static void net_family_write_lock(void)
+-{
+- spin_lock(&net_family_lock);
+- while (atomic_read(&net_family_lockct) != 0) {
+- spin_unlock(&net_family_lock);
+-
+- yield();
+-
+- spin_lock(&net_family_lock);
+- }
+-}
+-
+-static __inline__ void net_family_write_unlock(void)
+-{
+- spin_unlock(&net_family_lock);
+-}
+-
+-static __inline__ void net_family_read_lock(void)
+-{
+- atomic_inc(&net_family_lockct);
+- spin_unlock_wait(&net_family_lock);
+-}
+-
+-static __inline__ void net_family_read_unlock(void)
+-{
+- atomic_dec(&net_family_lockct);
+-}
+-
+-#else
+-#define net_family_write_lock() do { } while(0)
+-#define net_family_write_unlock() do { } while(0)
+-#define net_family_read_lock() do { } while(0)
+-#define net_family_read_unlock() do { } while(0)
+-#endif
+-
++static const struct net_proto_family *net_families[NPROTO] __read_mostly;
+
+ /*
+ * Statistics counters of the socket lists
+@@ -201,19 +150,20 @@ static __inline__ void net_family_read_u
+ static DEFINE_PER_CPU(int, sockets_in_use) = 0;
+
+ /*
+- * Support routines. Move socket addresses back and forth across the kernel/user
+- * divide and look after the messy bits.
++ * Support routines.
++ * Move socket addresses back and forth across the kernel/user
++ * divide and look after the messy bits.
+ */
+
+-#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
++#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
+ 16 for IP, 16 for IPX,
+ 24 for IPv6,
+- about 80 for AX.25
++ about 80 for AX.25
+ must be at least one bigger than
+ the AF_UNIX size (see net/unix/af_unix.c
+- :unix_mkname()).
++ :unix_mkname()).
+ */
+-
++
+ /**
+ * move_addr_to_kernel - copy a socket address into kernel space
+ * @uaddr: Address in user space
+@@ -227,11 +177,11 @@ static DEFINE_PER_CPU(int, sockets_in_us
+
+ int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr)
+ {
+- if(ulen<0||ulen>MAX_SOCK_ADDR)
++ if (ulen < 0 || ulen > MAX_SOCK_ADDR)
+ return -EINVAL;
+- if(ulen==0)
++ if (ulen == 0)
+ return 0;
+- if(copy_from_user(kaddr,uaddr,ulen))
++ if (copy_from_user(kaddr, uaddr, ulen))
+ return -EFAULT;
+ return audit_sockaddr(ulen, kaddr);
+ }
+@@ -252,51 +202,52 @@ int move_addr_to_kernel(void __user *uad
+ * length of the data is written over the length limit the user
+ * specified. Zero is returned for a success.
+ */
+-
+-int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen)
++
++int move_addr_to_user(void *kaddr, int klen, void __user *uaddr,
++ int __user *ulen)
+ {
+ int err;
+ int len;
+
+- if((err=get_user(len, ulen)))
++ err = get_user(len, ulen);
++ if (err)
+ return err;
+- if(len>klen)
+- len=klen;
+- if(len<0 || len> MAX_SOCK_ADDR)
++ if (len > klen)
++ len = klen;
++ if (len < 0 || len > MAX_SOCK_ADDR)
+ return -EINVAL;
+- if(len)
+- {
++ if (len) {
+ if (audit_sockaddr(klen, kaddr))
+ return -ENOMEM;
+- if(copy_to_user(uaddr,kaddr,len))
++ if (copy_to_user(uaddr, kaddr, len))
+ return -EFAULT;
+ }
+ /*
+- * "fromlen shall refer to the value before truncation.."
+- * 1003.1g
++ * "fromlen shall refer to the value before truncation.."
++ * 1003.1g
+ */
+ return __put_user(klen, ulen);
+ }
+
+ #define SOCKFS_MAGIC 0x534F434B
+
+-static kmem_cache_t * sock_inode_cachep __read_mostly;
++static kmem_cache_t *sock_inode_cachep __read_mostly;
+
+ static struct inode *sock_alloc_inode(struct super_block *sb)
+ {
+ struct socket_alloc *ei;
+- ei = (struct socket_alloc *)kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL);
++
++ ei = kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ init_waitqueue_head(&ei->socket.wait);
+-
++
+ ei->socket.fasync_list = NULL;
+ ei->socket.state = SS_UNCONNECTED;
+ ei->socket.flags = 0;
+ ei->socket.ops = NULL;
+ ei->socket.sk = NULL;
+ ei->socket.file = NULL;
+- ei->socket.flags = 0;
+
+ return &ei->vfs_inode;
+ }
+@@ -307,22 +258,25 @@ static void sock_destroy_inode(struct in
+ container_of(inode, struct socket_alloc, vfs_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 socket_alloc *ei = (struct socket_alloc *) foo;
++ struct socket_alloc *ei = (struct socket_alloc *)foo;
+
+- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+- SLAB_CTOR_CONSTRUCTOR)
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR))
++ == SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+ }
+-
++
+ static int init_inodecache(void)
+ {
+ sock_inode_cachep = kmem_cache_create("sock_inode_cache",
+- sizeof(struct socket_alloc),
+- 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
+- SLAB_MEM_SPREAD),
+- init_once, NULL);
++ sizeof(struct socket_alloc),
++ 0,
++ (SLAB_HWCACHE_ALIGN |
++ SLAB_RECLAIM_ACCOUNT |
++ SLAB_MEM_SPREAD),
++ init_once,
++ NULL);
+ if (sock_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+@@ -335,7 +289,8 @@ static struct super_operations sockfs_op
+ };
+
+ static int sockfs_get_sb(struct file_system_type *fs_type,
+- int flags, const char *dev_name, void *data, struct vfsmount *mnt)
++ int flags, const char *dev_name, void *data,
++ struct vfsmount *mnt)
+ {
+ return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC,
+ mnt);
+@@ -348,12 +303,13 @@ static struct file_system_type sock_fs_t
+ .get_sb = sockfs_get_sb,
+ .kill_sb = kill_anon_super,
+ };
++
+ static int sockfs_delete_dentry(struct dentry *dentry)
+ {
+ return 1;
+ }
+ static struct dentry_operations sockfs_dentry_operations = {
+- .d_delete = sockfs_delete_dentry,
++ .d_delete = sockfs_delete_dentry,
+ };
+
+ /*
+@@ -477,10 +433,12 @@ struct socket *sockfd_lookup(int fd, int
+ struct file *file;
+ struct socket *sock;
+
+- if (!(file = fget(fd))) {
++ file = fget(fd);
++ if (!file) {
+ *err = -EBADF;
+ return NULL;
+ }
++
+ sock = sock_from_file(file, err);
+ if (!sock)
+ fput(file);
+@@ -505,7 +463,7 @@ static struct socket *sockfd_lookup_ligh
+
+ /**
+ * sock_alloc - allocate a socket
+- *
++ *
+ * Allocate a new inode and socket object. The two are bound together
+ * and initialised. The socket is then returned. If we are out of inodes
+ * NULL is returned.
+@@ -513,8 +471,8 @@ static struct socket *sockfd_lookup_ligh
+
+ static struct socket *sock_alloc(void)
+ {
+- struct inode * inode;
+- struct socket * sock;
++ struct inode *inode;
++ struct socket *sock;
+
+ inode = new_inode(sock_mnt->mnt_sb);
+ if (!inode)
+@@ -522,7 +480,7 @@ static struct socket *sock_alloc(void)
+
+ sock = SOCKET_I(inode);
+
+- inode->i_mode = S_IFSOCK|S_IRWXUGO;
++ inode->i_mode = S_IFSOCK | S_IRWXUGO;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+
+@@ -536,7 +494,7 @@ static struct socket *sock_alloc(void)
+ * a back door. Remember to keep it shut otherwise you'll let the
+ * creepy crawlies in.
+ */
+-
++
+ static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
+ {
+ return -ENXIO;
+@@ -553,9 +511,9 @@ const struct file_operations bad_sock_fo
+ *
+ * The socket is released from the protocol stack if it has a release
+ * callback, and the inode is then released if the socket is bound to
+- * an inode not a file.
++ * an inode not a file.
+ */
+-
++
+ void sock_release(struct socket *sock)
+ {
+ if (sock->ops) {
+@@ -575,10 +533,10 @@ void sock_release(struct socket *sock)
+ iput(SOCK_INODE(sock));
+ return;
+ }
+- sock->file=NULL;
++ sock->file = NULL;
+ }
+
+-static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
++static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size)
+ {
+ struct sock_iocb *si = kiocb_to_siocb(iocb);
+@@ -621,14 +579,14 @@ int kernel_sendmsg(struct socket *sock,
+ * the following is safe, since for compiler definitions of kvec and
+ * iovec are identical, yielding the same in-core layout and alignment
+ */
+- msg->msg_iov = (struct iovec *)vec,
++ msg->msg_iov = (struct iovec *)vec;
+ msg->msg_iovlen = num;
+ result = sock_sendmsg(sock, msg, size);
+ set_fs(oldfs);
+ return result;
+ }
+
+-static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
++static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
+ {
+ int err;
+@@ -647,14 +605,14 @@ static inline int __sock_recvmsg(struct
+ return sock->ops->recvmsg(iocb, sock, msg, size, flags);
+ }
+
+-int sock_recvmsg(struct socket *sock, struct msghdr *msg,
++int sock_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t size, int flags)
+ {
+ struct kiocb iocb;
+ struct sock_iocb siocb;
+ int ret;
+
+- init_sync_kiocb(&iocb, NULL);
++ init_sync_kiocb(&iocb, NULL);
+ iocb.private = &siocb;
+ ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
+ if (-EIOCBQUEUED == ret)
+@@ -662,9 +620,8 @@ int sock_recvmsg(struct socket *sock, st
+ return ret;
+ }
+
+-int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
+- struct kvec *vec, size_t num,
+- size_t size, int flags)
++int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
++ struct kvec *vec, size_t num, size_t size, int flags)
+ {
+ mm_segment_t oldfs = get_fs();
+ int result;
+@@ -674,8 +631,7 @@ int kernel_recvmsg(struct socket *sock,
+ * the following is safe, since for compiler definitions of kvec and
+ * iovec are identical, yielding the same in-core layout and alignment
+ */
+- msg->msg_iov = (struct iovec *)vec,
+- msg->msg_iovlen = num;
++ msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num;
+ result = sock_recvmsg(sock, msg, size, flags);
+ set_fs(oldfs);
+ return result;
+@@ -702,7 +658,7 @@ static ssize_t sock_sendpage(struct file
+ }
+
+ static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
+- char __user *ubuf, size_t size, struct sock_iocb *siocb)
++ struct sock_iocb *siocb)
+ {
+ if (!is_sync_kiocb(iocb)) {
+ siocb = kmalloc(sizeof(*siocb), GFP_KERNEL);
+@@ -712,83 +668,66 @@ static struct sock_iocb *alloc_sock_iocb
+ }
+
+ siocb->kiocb = iocb;
+- siocb->async_iov.iov_base = ubuf;
+- siocb->async_iov.iov_len = size;
+-
+ iocb->private = siocb;
+ return siocb;
+ }
+
+ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
+- struct file *file, struct iovec *iov, unsigned long nr_segs)
++ struct file *file, const struct iovec *iov,
++ unsigned long nr_segs)
+ {
+ struct socket *sock = file->private_data;
+ size_t size = 0;
+ int i;
+
+- for (i = 0 ; i < nr_segs ; i++)
+- size += iov[i].iov_len;
++ for (i = 0; i < nr_segs; i++)
++ size += iov[i].iov_len;
+
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+- msg->msg_iov = (struct iovec *) iov;
++ msg->msg_iov = (struct iovec *)iov;
+ msg->msg_iovlen = nr_segs;
+ msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
+
+ return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
+ }
+
+-static ssize_t sock_readv(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct kiocb iocb;
+- struct sock_iocb siocb;
+- struct msghdr msg;
+- int ret;
+-
+- init_sync_kiocb(&iocb, NULL);
+- iocb.private = &siocb;
+-
+- ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
+- if (-EIOCBQUEUED == ret)
+- ret = wait_on_sync_kiocb(&iocb);
+- return ret;
+-}
+-
+-static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
+- size_t count, loff_t pos)
++static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct sock_iocb siocb, *x;
+
+ if (pos != 0)
+ return -ESPIPE;
+- if (count == 0) /* Match SYS5 behaviour */
++
++ if (iocb->ki_left == 0) /* Match SYS5 behaviour */
+ return 0;
+
+- x = alloc_sock_iocb(iocb, ubuf, count, &siocb);
++
++ x = alloc_sock_iocb(iocb, &siocb);
+ if (!x)
+ return -ENOMEM;
+- return do_sock_read(&x->async_msg, iocb, iocb->ki_filp,
+- &x->async_iov, 1);
++ return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
+ }
+
+ static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
+- struct file *file, struct iovec *iov, unsigned long nr_segs)
++ struct file *file, const struct iovec *iov,
++ unsigned long nr_segs)
+ {
+ struct socket *sock = file->private_data;
+ size_t size = 0;
+ int i;
+
+- for (i = 0 ; i < nr_segs ; i++)
+- size += iov[i].iov_len;
++ for (i = 0; i < nr_segs; i++)
++ size += iov[i].iov_len;
+
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+- msg->msg_iov = (struct iovec *) iov;
++ msg->msg_iov = (struct iovec *)iov;
+ msg->msg_iovlen = nr_segs;
+ msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
+ if (sock->type == SOCK_SEQPACKET)
+@@ -797,78 +736,63 @@ static ssize_t do_sock_write(struct msgh
+ return __sock_sendmsg(iocb, sock, msg, size);
+ }
+
+-static ssize_t sock_writev(struct file *file, const struct iovec *iov,
+- unsigned long nr_segs, loff_t *ppos)
+-{
+- struct msghdr msg;
+- struct kiocb iocb;
+- struct sock_iocb siocb;
+- int ret;
+-
+- init_sync_kiocb(&iocb, NULL);
+- iocb.private = &siocb;
+-
+- ret = do_sock_write(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
+- if (-EIOCBQUEUED == ret)
+- ret = wait_on_sync_kiocb(&iocb);
+- return ret;
+-}
+-
+-static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
+- size_t count, loff_t pos)
++static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct sock_iocb siocb, *x;
+
+ if (pos != 0)
+ return -ESPIPE;
+- if (count == 0) /* Match SYS5 behaviour */
++
++ if (iocb->ki_left == 0) /* Match SYS5 behaviour */
+ return 0;
+
+- x = alloc_sock_iocb(iocb, (void __user *)ubuf, count, &siocb);
++ x = alloc_sock_iocb(iocb, &siocb);
+ if (!x)
+ return -ENOMEM;
+
+- return do_sock_write(&x->async_msg, iocb, iocb->ki_filp,
+- &x->async_iov, 1);
++ return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
+ }
+
+-
+ /*
+ * Atomic setting of ioctl hooks to avoid race
+ * with module unload.
+ */
+
+ static DEFINE_MUTEX(br_ioctl_mutex);
+-static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
++static int (*br_ioctl_hook) (unsigned int cmd, void __user *arg) = NULL;
+
+-void brioctl_set(int (*hook)(unsigned int, void __user *))
++void brioctl_set(int (*hook) (unsigned int, void __user *))
+ {
+ mutex_lock(&br_ioctl_mutex);
+ br_ioctl_hook = hook;
+ mutex_unlock(&br_ioctl_mutex);
+ }
++
+ EXPORT_SYMBOL(brioctl_set);
+
+ static DEFINE_MUTEX(vlan_ioctl_mutex);
+-static int (*vlan_ioctl_hook)(void __user *arg);
++static int (*vlan_ioctl_hook) (void __user *arg);
+
+-void vlan_ioctl_set(int (*hook)(void __user *))
++void vlan_ioctl_set(int (*hook) (void __user *))
+ {
+ mutex_lock(&vlan_ioctl_mutex);
+ vlan_ioctl_hook = hook;
+ mutex_unlock(&vlan_ioctl_mutex);
+ }
++
+ EXPORT_SYMBOL(vlan_ioctl_set);
+
+ static DEFINE_MUTEX(dlci_ioctl_mutex);
+-static int (*dlci_ioctl_hook)(unsigned int, void __user *);
++static int (*dlci_ioctl_hook) (unsigned int, void __user *);
+
+-void dlci_ioctl_set(int (*hook)(unsigned int, void __user *))
++void dlci_ioctl_set(int (*hook) (unsigned int, void __user *))
+ {
+ mutex_lock(&dlci_ioctl_mutex);
+ dlci_ioctl_hook = hook;
+ mutex_unlock(&dlci_ioctl_mutex);
+ }
++
+ EXPORT_SYMBOL(dlci_ioctl_set);
+
+ /*
+@@ -890,8 +814,8 @@ static long sock_ioctl(struct file *file
+ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+ err = dev_ioctl(cmd, argp);
+ } else
+-#endif /* CONFIG_WIRELESS_EXT */
+- switch (cmd) {
++#endif /* CONFIG_WIRELESS_EXT */
++ switch (cmd) {
+ case FIOSETOWN:
+ case SIOCSPGRP:
+ err = -EFAULT;
+@@ -901,7 +825,8 @@ static long sock_ioctl(struct file *file
+ break;
+ case FIOGETOWN:
+ case SIOCGPGRP:
+- err = put_user(sock->file->f_owner.pid, (int __user *)argp);
++ err = put_user(f_getown(sock->file),
++ (int __user *)argp);
+ break;
+ case SIOCGIFBR:
+ case SIOCSIFBR:
+@@ -912,7 +837,7 @@ static long sock_ioctl(struct file *file
+ request_module("bridge");
+
+ mutex_lock(&br_ioctl_mutex);
+- if (br_ioctl_hook)
++ if (br_ioctl_hook)
+ err = br_ioctl_hook(cmd, argp);
+ mutex_unlock(&br_ioctl_mutex);
+ break;
+@@ -929,7 +854,7 @@ static long sock_ioctl(struct file *file
+ break;
+ case SIOCGIFDIVERT:
+ case SIOCSIFDIVERT:
+- /* Convert this to call through a hook */
++ /* Convert this to call through a hook */
+ err = divert_ioctl(cmd, argp);
+ break;
+ case SIOCADDDLCI:
+@@ -954,7 +879,7 @@ static long sock_ioctl(struct file *file
+ if (err == -ENOIOCTLCMD)
+ err = dev_ioctl(cmd, argp);
+ break;
+- }
++ }
+ return err;
+ }
+
+@@ -962,7 +887,7 @@ int sock_create_lite(int family, int typ
+ {
+ int err;
+ struct socket *sock = NULL;
+-
++
+ err = security_socket_create(family, type, protocol, 1);
+ if (err)
+ goto out;
+@@ -973,26 +898,33 @@ int sock_create_lite(int family, int typ
+ goto out;
+ }
+
+- security_socket_post_create(sock, family, type, protocol, 1);
+ sock->type = type;
++ err = security_socket_post_create(sock, family, type, protocol, 1);
++ if (err)
++ goto out_release;
++
+ out:
+ *res = sock;
+ return err;
++out_release:
++ sock_release(sock);
++ sock = NULL;
++ goto out;
+ }
+
+ /* No kernel lock held - perfect */
+-static unsigned int sock_poll(struct file *file, poll_table * wait)
++static unsigned int sock_poll(struct file *file, poll_table *wait)
+ {
+ struct socket *sock;
+
+ /*
+- * We can't return errors to poll, so it's either yes or no.
++ * We can't return errors to poll, so it's either yes or no.
+ */
+ sock = file->private_data;
+ return sock->ops->poll(file, sock, wait);
+ }
+
+-static int sock_mmap(struct file * file, struct vm_area_struct * vma)
++static int sock_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+ struct socket *sock = file->private_data;
+
+@@ -1002,12 +934,11 @@ static int sock_mmap(struct file * file,
+ static int sock_close(struct inode *inode, struct file *filp)
+ {
+ /*
+- * It was possible the inode is NULL we were
+- * closing an unfinished socket.
++ * It was possible the inode is NULL we were
++ * closing an unfinished socket.
+ */
+
+- if (!inode)
+- {
++ if (!inode) {
+ printk(KERN_DEBUG "sock_close: NULL inode\n");
+ return 0;
+ }
+@@ -1033,57 +964,52 @@ static int sock_close(struct inode *inod
+
+ static int sock_fasync(int fd, struct file *filp, int on)
+ {
+- struct fasync_struct *fa, *fna=NULL, **prev;
++ struct fasync_struct *fa, *fna = NULL, **prev;
+ struct socket *sock;
+ struct sock *sk;
+
+- if (on)
+- {
++ if (on) {
+ fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
+- if(fna==NULL)
++ if (fna == NULL)
+ return -ENOMEM;
+ }
+
+ sock = filp->private_data;
+
+- if ((sk=sock->sk) == NULL) {
++ sk = sock->sk;
++ if (sk == NULL) {
+ kfree(fna);
+ return -EINVAL;
+ }
+
+ lock_sock(sk);
+
+- prev=&(sock->fasync_list);
++ prev = &(sock->fasync_list);
+
+- for (fa=*prev; fa!=NULL; prev=&fa->fa_next,fa=*prev)
+- if (fa->fa_file==filp)
++ for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev)
++ if (fa->fa_file == filp)
+ break;
+
+- if(on)
+- {
+- if(fa!=NULL)
+- {
++ if (on) {
++ if (fa != NULL) {
+ write_lock_bh(&sk->sk_callback_lock);
+- fa->fa_fd=fd;
++ fa->fa_fd = fd;
+ write_unlock_bh(&sk->sk_callback_lock);
+
+ kfree(fna);
+ goto out;
+ }
+- fna->fa_file=filp;
+- fna->fa_fd=fd;
+- fna->magic=FASYNC_MAGIC;
+- fna->fa_next=sock->fasync_list;
++ fna->fa_file = filp;
++ fna->fa_fd = fd;
++ fna->magic = FASYNC_MAGIC;
++ fna->fa_next = sock->fasync_list;
+ write_lock_bh(&sk->sk_callback_lock);
+- sock->fasync_list=fna;
++ sock->fasync_list = fna;
+ write_unlock_bh(&sk->sk_callback_lock);
+- }
+- else
+- {
+- if (fa!=NULL)
+- {
++ } else {
++ if (fa != NULL) {
+ write_lock_bh(&sk->sk_callback_lock);
+- *prev=fa->fa_next;
++ *prev = fa->fa_next;
+ write_unlock_bh(&sk->sk_callback_lock);
+ kfree(fa);
+ }
+@@ -1100,10 +1026,9 @@ int sock_wake_async(struct socket *sock,
+ {
+ if (!sock || !sock->fasync_list)
+ return -1;
+- switch (how)
+- {
++ switch (how) {
+ case 1:
+-
++
+ if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
+ break;
+ goto call_kill;
+@@ -1112,7 +1037,7 @@ int sock_wake_async(struct socket *sock,
+ break;
+ /* fall through */
+ case 0:
+- call_kill:
++call_kill:
+ __kill_fasync(sock->fasync_list, SIGIO, band);
+ break;
+ case 3:
+@@ -1121,13 +1046,15 @@ int sock_wake_async(struct socket *sock,
+ return 0;
+ }
+
+-static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
++static int __sock_create(int family, int type, int protocol,
++ struct socket **res, int kern)
+ {
+ int err;
+ struct socket *sock;
++ const struct net_proto_family *pf;
+
+ /*
+- * Check protocol is in range
++ * Check protocol is in range
+ */
+ if (family < 0 || family >= NPROTO)
+ return -EAFNOSUPPORT;
+@@ -1140,10 +1067,11 @@ static int __sock_create(int family, int
+ deadlock in module load.
+ */
+ if (family == PF_INET && type == SOCK_PACKET) {
+- static int warned;
++ static int warned;
+ if (!warned) {
+ warned = 1;
+- printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
++ printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",
++ current->comm);
+ }
+ family = PF_PACKET;
+ }
+@@ -1151,79 +1079,84 @@ static int __sock_create(int family, int
+ err = security_socket_create(family, type, protocol, kern);
+ if (err)
+ return err;
+-
++
++ /*
++ * Allocate the socket and allow the family to set things up. if
++ * the protocol is 0, the family is instructed to select an appropriate
++ * default.
++ */
++ sock = sock_alloc();
++ if (!sock) {
++ if (net_ratelimit())
++ printk(KERN_WARNING "socket: no more sockets\n");
++ return -ENFILE; /* Not exactly a match, but its the
++ closest posix thing */
++ }
++
++ sock->type = type;
++
+ #if defined(CONFIG_KMOD)
+- /* Attempt to load a protocol module if the find failed.
+- *
+- * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
++ /* Attempt to load a protocol module if the find failed.
++ *
++ * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
+ * requested real, full-featured networking support upon configuration.
+ * Otherwise module support will break!
+ */
+- if (net_families[family]==NULL)
+- {
+- request_module("net-pf-%d",family);
+- }
++ if (net_families[family] == NULL)
++ request_module("net-pf-%d", family);
+ #endif
+
+- net_family_read_lock();
+- if (net_families[family] == NULL) {
+- err = -EAFNOSUPPORT;
+- goto out;
+- }
+-
+-/*
+- * Allocate the socket and allow the family to set things up. if
+- * the protocol is 0, the family is instructed to select an appropriate
+- * default.
+- */
+-
+- if (!(sock = sock_alloc())) {
+- if (net_ratelimit())
+- printk(KERN_WARNING "socket: no more sockets\n");
+- err = -ENFILE; /* Not exactly a match, but its the
+- closest posix thing */
+- goto out;
+- }
+-
+- sock->type = type;
++ rcu_read_lock();
++ pf = rcu_dereference(net_families[family]);
++ err = -EAFNOSUPPORT;
++ if (!pf)
++ goto out_release;
+
+ /*
+ * We will call the ->create function, that possibly is in a loadable
+ * module, so we have to bump that loadable module refcnt first.
+ */
+- err = -EAFNOSUPPORT;
+- if (!try_module_get(net_families[family]->owner))
++ if (!try_module_get(pf->owner))
+ goto out_release;
+
+- if ((err = net_families[family]->create(sock, protocol)) < 0) {
+- sock->ops = NULL;
++ /* Now protected by module ref count */
++ rcu_read_unlock();
++
++ err = pf->create(sock, protocol);
++ if (err < 0)
+ goto out_module_put;
+- }
+
+ /*
+ * Now to bump the refcnt of the [loadable] module that owns this
+ * socket at sock_release time we decrement its refcnt.
+ */
+- if (!try_module_get(sock->ops->owner)) {
+- sock->ops = NULL;
+- goto out_module_put;
+- }
++ if (!try_module_get(sock->ops->owner))
++ goto out_module_busy;
++
+ /*
+ * Now that we're done with the ->create function, the [loadable]
+ * module can have its refcnt decremented
+ */
+- module_put(net_families[family]->owner);
++ module_put(pf->owner);
++ err = security_socket_post_create(sock, family, type, protocol, kern);
++ if (err)
++ goto out_release;
+ *res = sock;
+- security_socket_post_create(sock, family, type, protocol, kern);
+
+-out:
+- net_family_read_unlock();
+- return err;
++ return 0;
++
++out_module_busy:
++ err = -EAFNOSUPPORT;
+ out_module_put:
+- module_put(net_families[family]->owner);
+-out_release:
++ sock->ops = NULL;
++ module_put(pf->owner);
++out_sock_release:
+ sock_release(sock);
+- goto out;
++ return err;
++
++out_release:
++ rcu_read_unlock();
++ goto out_sock_release;
+ }
+
+ int sock_create(int family, int type, int protocol, struct socket **res)
+@@ -1262,7 +1195,8 @@ out_release:
+ * Create a pair of connected sockets.
+ */
+
+-asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *usockvec)
++asmlinkage long sys_socketpair(int family, int type, int protocol,
++ int __user *usockvec)
+ {
+ struct socket *sock1, *sock2;
+ int fd1, fd2, err;
+@@ -1281,7 +1215,7 @@ asmlinkage long sys_socketpair(int famil
+ goto out_release_1;
+
+ err = sock1->ops->socketpair(sock1, sock2);
+- if (err < 0)
++ if (err < 0)
+ goto out_release_both;
+
+ fd1 = fd2 = -1;
+@@ -1300,7 +1234,7 @@ asmlinkage long sys_socketpair(int famil
+ * Not kernel problem.
+ */
+
+- err = put_user(fd1, &usockvec[0]);
++ err = put_user(fd1, &usockvec[0]);
+ if (!err)
+ err = put_user(fd2, &usockvec[1]);
+ if (!err)
+@@ -1311,19 +1245,18 @@ asmlinkage long sys_socketpair(int famil
+ return err;
+
+ out_close_1:
+- sock_release(sock2);
++ sock_release(sock2);
+ sys_close(fd1);
+ return err;
+
+ out_release_both:
+- sock_release(sock2);
++ sock_release(sock2);
+ out_release_1:
+- sock_release(sock1);
++ sock_release(sock1);
+ out:
+ return err;
+ }
+
+-
+ /*
+ * Bind a name to a socket. Nothing much to do here since it's
+ * the protocol's responsibility to handle the local address.
+@@ -1338,35 +1271,39 @@ asmlinkage long sys_bind(int fd, struct
+ char address[MAX_SOCK_ADDR];
+ int err, fput_needed;
+
+- if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
+- {
+- if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
+- err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
++ sock = sockfd_lookup_light(fd, &err, &fput_needed);
++ if(sock) {
++ err = move_addr_to_kernel(umyaddr, addrlen, address);
++ if (err >= 0) {
++ err = security_socket_bind(sock,
++ (struct sockaddr *)address,
++ addrlen);
+ if (!err)
+ err = sock->ops->bind(sock,
+- (struct sockaddr *)address, addrlen);
++ (struct sockaddr *)
++ address, addrlen);
+ }
+ fput_light(sock->file, fput_needed);
+- }
++ }
+ return err;
+ }
+
+-
+ /*
+ * Perform a listen. Basically, we allow the protocol to do anything
+ * necessary for a listen, and if that works, we mark the socket as
+ * ready for listening.
+ */
+
+-int sysctl_somaxconn = SOMAXCONN;
++int sysctl_somaxconn __read_mostly = SOMAXCONN;
+
+ asmlinkage long sys_listen(int fd, int backlog)
+ {
+ struct socket *sock;
+ int err, fput_needed;
+-
+- if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
+- if ((unsigned) backlog > sysctl_somaxconn)
++
++ sock = sockfd_lookup_light(fd, &err, &fput_needed);
++ if (sock) {
++ if ((unsigned)backlog > sysctl_somaxconn)
+ backlog = sysctl_somaxconn;
+
+ err = security_socket_listen(sock, backlog);
+@@ -1378,7 +1315,6 @@ asmlinkage long sys_listen(int fd, int b
+ return err;
+ }
+
+-
+ /*
+ * For accept, we attempt to create a new socket, set up the link
+ * with the client, wake up the client, then return the new
+@@ -1391,7 +1327,8 @@ asmlinkage long sys_listen(int fd, int b
+ * clean when we restucture accept also.
+ */
+
+-asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen)
++asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
++ int __user *upeer_addrlen)
+ {
+ struct socket *sock, *newsock;
+ struct file *newfile;
+@@ -1403,7 +1340,7 @@ asmlinkage long sys_accept(int fd, struc
+ goto out;
+
+ err = -ENFILE;
+- if (!(newsock = sock_alloc()))
++ if (!(newsock = sock_alloc()))
+ goto out_put;
+
+ newsock->type = sock->type;
+@@ -1435,11 +1372,13 @@ asmlinkage long sys_accept(int fd, struc
+ goto out_fd;
+
+ if (upeer_sockaddr) {
+- if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
++ if (newsock->ops->getname(newsock, (struct sockaddr *)address,
++ &len, 2) < 0) {
+ err = -ECONNABORTED;
+ goto out_fd;
+ }
+- err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
++ err = move_addr_to_user(address, len, upeer_sockaddr,
++ upeer_addrlen);
+ if (err < 0)
+ goto out_fd;
+ }
+@@ -1461,7 +1400,6 @@ out_fd:
+ goto out_put;
+ }
+
+-
+ /*
+ * Attempt to connect to a socket with the server address. The address
+ * is in user space so we verify it is OK and move it to kernel space.
+@@ -1474,7 +1412,8 @@ out_fd:
+ * include the -EINPROGRESS status for such sockets.
+ */
+
+-asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
++asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr,
++ int addrlen)
+ {
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+@@ -1487,11 +1426,12 @@ asmlinkage long sys_connect(int fd, stru
+ if (err < 0)
+ goto out_put;
+
+- err = security_socket_connect(sock, (struct sockaddr *)address, addrlen);
++ err =
++ security_socket_connect(sock, (struct sockaddr *)address, addrlen);
+ if (err)
+ goto out_put;
+
+- err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
++ err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
+ sock->file->f_flags);
+ out_put:
+ fput_light(sock->file, fput_needed);
+@@ -1504,12 +1444,13 @@ out:
+ * name to user space.
+ */
+
+-asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len)
++asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr,
++ int __user *usockaddr_len)
+ {
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+ int len, err, fput_needed;
+-
++
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+ goto out;
+@@ -1534,22 +1475,27 @@ out:
+ * name to user space.
+ */
+
+-asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len)
++asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr,
++ int __user *usockaddr_len)
+ {
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+ int len, err, fput_needed;
+
+- if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
++ sock = sockfd_lookup_light(fd, &err, &fput_needed);
++ if (sock != NULL) {
+ err = security_socket_getpeername(sock);
+ if (err) {
+ fput_light(sock->file, fput_needed);
+ return err;
+ }
+
+- err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
++ err =
++ sock->ops->getname(sock, (struct sockaddr *)address, &len,
++ 1);
+ if (!err)
+- err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
++ err = move_addr_to_user(address, len, usockaddr,
++ usockaddr_len);
+ fput_light(sock->file, fput_needed);
+ }
+ return err;
+@@ -1561,8 +1507,9 @@ asmlinkage long sys_getpeername(int fd,
+ * the protocol.
+ */
+
+-asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags,
+- struct sockaddr __user *addr, int addr_len)
++asmlinkage long sys_sendto(int fd, void __user *buff, size_t len,
++ unsigned flags, struct sockaddr __user *addr,
++ int addr_len)
+ {
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+@@ -1579,54 +1526,55 @@ asmlinkage long sys_sendto(int fd, void
+ sock = sock_from_file(sock_file, &err);
+ if (!sock)
+ goto out_put;
+- iov.iov_base=buff;
+- iov.iov_len=len;
+- msg.msg_name=NULL;
+- msg.msg_iov=&iov;
+- msg.msg_iovlen=1;
+- msg.msg_control=NULL;
+- msg.msg_controllen=0;
+- msg.msg_namelen=0;
++ iov.iov_base = buff;
++ iov.iov_len = len;
++ msg.msg_name = NULL;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_namelen = 0;
+ if (addr) {
+ err = move_addr_to_kernel(addr, addr_len, address);
+ if (err < 0)
+ goto out_put;
+- msg.msg_name=address;
+- msg.msg_namelen=addr_len;
++ msg.msg_name = address;
++ msg.msg_namelen = addr_len;
+ }
+ if (sock->file->f_flags & O_NONBLOCK)
+ flags |= MSG_DONTWAIT;
+ msg.msg_flags = flags;
+ err = sock_sendmsg(sock, &msg, len);
+
+-out_put:
++out_put:
+ fput_light(sock_file, fput_needed);
+ return err;
+ }
+
+ /*
+- * Send a datagram down a socket.
++ * Send a datagram down a socket.
+ */
+
+-asmlinkage long sys_send(int fd, void __user * buff, size_t len, unsigned flags)
++asmlinkage long sys_send(int fd, void __user *buff, size_t len, unsigned flags)
+ {
+ return sys_sendto(fd, buff, len, flags, NULL, 0);
+ }
+
+ /*
+- * Receive a frame from the socket and optionally record the address of the
++ * Receive a frame from the socket and optionally record the address of the
+ * sender. We verify the buffers are writable and if needed move the
+ * sender address from kernel to user space.
+ */
+
+-asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags,
+- struct sockaddr __user *addr, int __user *addr_len)
++asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size,
++ unsigned flags, struct sockaddr __user *addr,
++ int __user *addr_len)
+ {
+ struct socket *sock;
+ struct iovec iov;
+ struct msghdr msg;
+ char address[MAX_SOCK_ADDR];
+- int err,err2;
++ int err, err2;
+ struct file *sock_file;
+ int fput_needed;
+
+@@ -1638,23 +1586,22 @@ asmlinkage long sys_recvfrom(int fd, voi
+ if (!sock)
+ goto out;
+
+- msg.msg_control=NULL;
+- msg.msg_controllen=0;
+- msg.msg_iovlen=1;
+- msg.msg_iov=&iov;
+- iov.iov_len=size;
+- iov.iov_base=ubuf;
+- msg.msg_name=address;
+- msg.msg_namelen=MAX_SOCK_ADDR;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_iovlen = 1;
++ msg.msg_iov = &iov;
++ iov.iov_len = size;
++ iov.iov_base = ubuf;
++ msg.msg_name = address;
++ msg.msg_namelen = MAX_SOCK_ADDR;
+ if (sock->file->f_flags & O_NONBLOCK)
+ flags |= MSG_DONTWAIT;
+- err=sock_recvmsg(sock, &msg, size, flags);
++ err = sock_recvmsg(sock, &msg, size, flags);
+
+- if(err >= 0 && addr != NULL)
+- {
+- err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
+- if(err2<0)
+- err=err2;
++ if (err >= 0 && addr != NULL) {
++ err2 = move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
++ if (err2 < 0)
++ err = err2;
+ }
+ out:
+ fput_light(sock_file, fput_needed);
+@@ -1662,10 +1609,11 @@ out:
+ }
+
+ /*
+- * Receive a datagram from a socket.
++ * Receive a datagram from a socket.
+ */
+
+-asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags)
++asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size,
++ unsigned flags)
+ {
+ return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
+ }
+@@ -1675,24 +1623,29 @@ asmlinkage long sys_recv(int fd, void __
+ * to pass the user mode parameter for the protocols to sort out.
+ */
+
+-asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen)
++asmlinkage long sys_setsockopt(int fd, int level, int optname,
++ char __user *optval, int optlen)
+ {
+ int err, fput_needed;
+ struct socket *sock;
+
+ if (optlen < 0)
+ return -EINVAL;
+-
+- if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL)
+- {
+- err = security_socket_setsockopt(sock,level,optname);
++
++ sock = sockfd_lookup_light(fd, &err, &fput_needed);
++ if (sock != NULL) {
++ err = security_socket_setsockopt(sock, level, optname);
+ if (err)
+ goto out_put;
+
+ if (level == SOL_SOCKET)
+- err=sock_setsockopt(sock,level,optname,optval,optlen);
++ err =
++ sock_setsockopt(sock, level, optname, optval,
++ optlen);
+ else
+- err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
++ err =
++ sock->ops->setsockopt(sock, level, optname, optval,
++ optlen);
+ out_put:
+ fput_light(sock->file, fput_needed);
+ }
+@@ -1704,27 +1657,32 @@ out_put:
+ * to pass a user mode parameter for the protocols to sort out.
+ */
+
+-asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen)
++asmlinkage long sys_getsockopt(int fd, int level, int optname,
++ char __user *optval, int __user *optlen)
+ {
+ int err, fput_needed;
+ struct socket *sock;
+
+- if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
++ sock = sockfd_lookup_light(fd, &err, &fput_needed);
++ if (sock != NULL) {
+ err = security_socket_getsockopt(sock, level, optname);
+ if (err)
+ goto out_put;
+
+ if (level == SOL_SOCKET)
+- err=sock_getsockopt(sock,level,optname,optval,optlen);
++ err =
++ sock_getsockopt(sock, level, optname, optval,
++ optlen);
+ else
+- err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
++ err =
++ sock->ops->getsockopt(sock, level, optname, optval,
++ optlen);
+ out_put:
+ fput_light(sock->file, fput_needed);
+ }
+ return err;
+ }
+
+-
+ /*
+ * Shutdown a socket.
+ */
+@@ -1734,8 +1692,8 @@ asmlinkage long sys_shutdown(int fd, int
+ int err, fput_needed;
+ struct socket *sock;
+
+- if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
+- {
++ sock = sockfd_lookup_light(fd, &err, &fput_needed);
++ if (sock != NULL) {
+ err = security_socket_shutdown(sock, how);
+ if (!err)
+ err = sock->ops->shutdown(sock, how);
+@@ -1744,41 +1702,42 @@ asmlinkage long sys_shutdown(int fd, int
+ return err;
+ }
+
+-/* A couple of helpful macros for getting the address of the 32/64 bit
++/* A couple of helpful macros for getting the address of the 32/64 bit
+ * fields which are the same type (int / unsigned) on our platforms.
+ */
+ #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member)
+ #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen)
+ #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags)
+
+-
+ /*
+ * BSD sendmsg interface
+ */
+
+ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
+ {
+- struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg;
++ struct compat_msghdr __user *msg_compat =
++ (struct compat_msghdr __user *)msg;
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+ struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+ unsigned char ctl[sizeof(struct cmsghdr) + 20]
+- __attribute__ ((aligned (sizeof(__kernel_size_t))));
+- /* 20 is size of ipv6_pktinfo */
++ __attribute__ ((aligned(sizeof(__kernel_size_t))));
++ /* 20 is size of ipv6_pktinfo */
+ unsigned char *ctl_buf = ctl;
+ struct msghdr msg_sys;
+ int err, ctl_len, iov_size, total_len;
+ int fput_needed;
+-
++
+ err = -EFAULT;
+ if (MSG_CMSG_COMPAT & flags) {
+ if (get_compat_msghdr(&msg_sys, msg_compat))
+ return -EFAULT;
+- } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
++ }
++ else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ return -EFAULT;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+- if (!sock)
++ if (!sock)
+ goto out;
+
+ /* do not move before msg_sys is valid */
+@@ -1786,7 +1745,7 @@ asmlinkage long sys_sendmsg(int fd, stru
+ if (msg_sys.msg_iovlen > UIO_MAXIOV)
+ goto out_put;
+
+- /* Check whether to allocate the iovec area*/
++ /* Check whether to allocate the iovec area */
+ err = -ENOMEM;
+ iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+ if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+@@ -1800,7 +1759,7 @@ asmlinkage long sys_sendmsg(int fd, stru
+ err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ);
+ } else
+ err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
+- if (err < 0)
++ if (err < 0)
+ goto out_freeiov;
+ total_len = err;
+
+@@ -1808,18 +1767,19 @@ asmlinkage long sys_sendmsg(int fd, stru
+
+ if (msg_sys.msg_controllen > INT_MAX)
+ goto out_freeiov;
+- ctl_len = msg_sys.msg_controllen;
++ ctl_len = msg_sys.msg_controllen;
+ if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
+- err = cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, sizeof(ctl));
++ err =
++ cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl,
++ sizeof(ctl));
+ if (err)
+ goto out_freeiov;
+ ctl_buf = msg_sys.msg_control;
+ ctl_len = msg_sys.msg_controllen;
+ } else if (ctl_len) {
+- if (ctl_len > sizeof(ctl))
+- {
++ if (ctl_len > sizeof(ctl)) {
+ ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
+- if (ctl_buf == NULL)
++ if (ctl_buf == NULL)
+ goto out_freeiov;
+ }
+ err = -EFAULT;
+@@ -1828,7 +1788,8 @@ asmlinkage long sys_sendmsg(int fd, stru
+ * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
+ * checking falls down on this.
+ */
+- if (copy_from_user(ctl_buf, (void __user *) msg_sys.msg_control, ctl_len))
++ if (copy_from_user(ctl_buf, (void __user *)msg_sys.msg_control,
++ ctl_len))
+ goto out_freectl;
+ msg_sys.msg_control = ctl_buf;
+ }
+@@ -1839,14 +1800,14 @@ asmlinkage long sys_sendmsg(int fd, stru
+ err = sock_sendmsg(sock, &msg_sys, total_len);
+
+ out_freectl:
+- if (ctl_buf != ctl)
++ if (ctl_buf != ctl)
+ sock_kfree_s(sock->sk, ctl_buf, ctl_len);
+ out_freeiov:
+ if (iov != iovstack)
+ sock_kfree_s(sock->sk, iov, iov_size);
+ out_put:
+ fput_light(sock->file, fput_needed);
+-out:
++out:
+ return err;
+ }
+
+@@ -1854,12 +1815,14 @@ out:
+ * BSD recvmsg interface
+ */
+
+-asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags)
++asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg,
++ unsigned int flags)
+ {
+- struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg;
++ struct compat_msghdr __user *msg_compat =
++ (struct compat_msghdr __user *)msg;
+ struct socket *sock;
+ struct iovec iovstack[UIO_FASTIOV];
+- struct iovec *iov=iovstack;
++ struct iovec *iov = iovstack;
+ struct msghdr msg_sys;
+ unsigned long cmsg_ptr;
+ int err, iov_size, total_len, len;
+@@ -1871,13 +1834,13 @@ asmlinkage long sys_recvmsg(int fd, stru
+ /* user mode address pointers */
+ struct sockaddr __user *uaddr;
+ int __user *uaddr_len;
+-
++
+ if (MSG_CMSG_COMPAT & flags) {
+ if (get_compat_msghdr(&msg_sys, msg_compat))
+ return -EFAULT;
+- } else
+- if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
+- return -EFAULT;
++ }
++ else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
++ return -EFAULT;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+@@ -1886,8 +1849,8 @@ asmlinkage long sys_recvmsg(int fd, stru
+ err = -EMSGSIZE;
+ if (msg_sys.msg_iovlen > UIO_MAXIOV)
+ goto out_put;
+-
+- /* Check whether to allocate the iovec area*/
++
++ /* Check whether to allocate the iovec area */
+ err = -ENOMEM;
+ iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+ if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+@@ -1897,11 +1860,11 @@ asmlinkage long sys_recvmsg(int fd, stru
+ }
+
+ /*
+- * Save the user-mode address (verify_iovec will change the
+- * kernel msghdr to use the kernel address space)
++ * Save the user-mode address (verify_iovec will change the
++ * kernel msghdr to use the kernel address space)
+ */
+-
+- uaddr = (void __user *) msg_sys.msg_name;
++
++ uaddr = (void __user *)msg_sys.msg_name;
+ uaddr_len = COMPAT_NAMELEN(msg);
+ if (MSG_CMSG_COMPAT & flags) {
+ err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
+@@ -1909,13 +1872,13 @@ asmlinkage long sys_recvmsg(int fd, stru
+ err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
+ if (err < 0)
+ goto out_freeiov;
+- total_len=err;
++ total_len = err;
+
+ cmsg_ptr = (unsigned long)msg_sys.msg_control;
+ msg_sys.msg_flags = 0;
+ if (MSG_CMSG_COMPAT & flags)
+ msg_sys.msg_flags = MSG_CMSG_COMPAT;
+-
++
+ if (sock->file->f_flags & O_NONBLOCK)
+ flags |= MSG_DONTWAIT;
+ err = sock_recvmsg(sock, &msg_sys, total_len, flags);
+@@ -1924,7 +1887,8 @@ asmlinkage long sys_recvmsg(int fd, stru
+ len = err;
+
+ if (uaddr != NULL) {
+- err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
++ err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr,
++ uaddr_len);
+ if (err < 0)
+ goto out_freeiov;
+ }
+@@ -1933,10 +1897,10 @@ asmlinkage long sys_recvmsg(int fd, stru
+ if (err)
+ goto out_freeiov;
+ if (MSG_CMSG_COMPAT & flags)
+- err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
++ err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ &msg_compat->msg_controllen);
+ else
+- err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
++ err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ &msg->msg_controllen);
+ if (err)
+ goto out_freeiov;
+@@ -1955,163 +1919,187 @@ out:
+
+ /* Argument list sizes for sys_socketcall */
+ #define AL(x) ((x) * sizeof(unsigned long))
+-static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+- AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
++static const unsigned char nargs[18]={
++ AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
++ AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
++ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)
++};
++
+ #undef AL
+
+ /*
+- * System call vectors.
++ * System call vectors.
+ *
+ * Argument checking cleaned up. Saved 20% in size.
+ * This function doesn't need to set the kernel lock because
+- * it is set by the callees.
++ * it is set by the callees.
+ */
+
+ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
+ {
+ unsigned long a[6];
+- unsigned long a0,a1;
++ unsigned long a0, a1;
+ int err;
+
+- if(call<1||call>SYS_RECVMSG)
++ if (call < 1 || call > SYS_RECVMSG)
+ return -EINVAL;
+
+ /* copy_from_user should be SMP safe. */
+ if (copy_from_user(a, args, nargs[call]))
+ return -EFAULT;
+
+- err = audit_socketcall(nargs[call]/sizeof(unsigned long), a);
++ err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
+ if (err)
+ return err;
+
+- a0=a[0];
+- a1=a[1];
+-
+- switch(call)
+- {
+- case SYS_SOCKET:
+- err = sys_socket(a0,a1,a[2]);
+- break;
+- case SYS_BIND:
+- err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
+- break;
+- case SYS_CONNECT:
+- err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
+- break;
+- case SYS_LISTEN:
+- err = sys_listen(a0,a1);
+- break;
+- case SYS_ACCEPT:
+- err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
+- break;
+- case SYS_GETSOCKNAME:
+- err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
+- break;
+- case SYS_GETPEERNAME:
+- err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
+- break;
+- case SYS_SOCKETPAIR:
+- err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);
+- break;
+- case SYS_SEND:
+- err = sys_send(a0, (void __user *)a1, a[2], a[3]);
+- break;
+- case SYS_SENDTO:
+- err = sys_sendto(a0,(void __user *)a1, a[2], a[3],
+- (struct sockaddr __user *)a[4], a[5]);
+- break;
+- case SYS_RECV:
+- err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
+- break;
+- case SYS_RECVFROM:
+- err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
+- (struct sockaddr __user *)a[4], (int __user *)a[5]);
+- break;
+- case SYS_SHUTDOWN:
+- err = sys_shutdown(a0,a1);
+- break;
+- case SYS_SETSOCKOPT:
+- err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
+- break;
+- case SYS_GETSOCKOPT:
+- err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);
+- break;
+- case SYS_SENDMSG:
+- err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);
+- break;
+- case SYS_RECVMSG:
+- err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);
+- break;
+- default:
+- err = -EINVAL;
+- break;
++ a0 = a[0];
++ a1 = a[1];
++
++ switch (call) {
++ case SYS_SOCKET:
++ err = sys_socket(a0, a1, a[2]);
++ break;
++ case SYS_BIND:
++ err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
++ break;
++ case SYS_CONNECT:
++ err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
++ break;
++ case SYS_LISTEN:
++ err = sys_listen(a0, a1);
++ break;
++ case SYS_ACCEPT:
++ err =
++ sys_accept(a0, (struct sockaddr __user *)a1,
++ (int __user *)a[2]);
++ break;
++ case SYS_GETSOCKNAME:
++ err =
++ sys_getsockname(a0, (struct sockaddr __user *)a1,
++ (int __user *)a[2]);
++ break;
++ case SYS_GETPEERNAME:
++ err =
++ sys_getpeername(a0, (struct sockaddr __user *)a1,
++ (int __user *)a[2]);
++ break;
++ case SYS_SOCKETPAIR:
++ err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
++ break;
++ case SYS_SEND:
++ err = sys_send(a0, (void __user *)a1, a[2], a[3]);
++ break;
++ case SYS_SENDTO:
++ err = sys_sendto(a0, (void __user *)a1, a[2], a[3],
++ (struct sockaddr __user *)a[4], a[5]);
++ break;
++ case SYS_RECV:
++ err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
++ break;
++ case SYS_RECVFROM:
++ err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
++ (struct sockaddr __user *)a[4],
++ (int __user *)a[5]);
++ break;
++ case SYS_SHUTDOWN:
++ err = sys_shutdown(a0, a1);
++ break;
++ case SYS_SETSOCKOPT:
++ err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
++ break;
++ case SYS_GETSOCKOPT:
++ err =
++ sys_getsockopt(a0, a1, a[2], (char __user *)a[3],
++ (int __user *)a[4]);
++ break;
++ case SYS_SENDMSG:
++ err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
++ break;
++ case SYS_RECVMSG:
++ err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
++ break;
++ default:
++ err = -EINVAL;
++ break;
+ }
+ return err;
+ }
+
+-#endif /* __ARCH_WANT_SYS_SOCKETCALL */
++#endif /* __ARCH_WANT_SYS_SOCKETCALL */
+
+-/*
++/**
++ * sock_register - add a socket protocol handler
++ * @ops: description of protocol
++ *
+ * This function is called by a protocol handler that wants to
+ * advertise its address family, and have it linked into the
+- * SOCKET module.
++ * socket interface. The value ops->family coresponds to the
++ * socket system call protocol family.
+ */
+-
+-int sock_register(struct net_proto_family *ops)
++int sock_register(const struct net_proto_family *ops)
+ {
+ int err;
+
+ if (ops->family >= NPROTO) {
+- printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);
++ printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
++ NPROTO);
+ return -ENOBUFS;
+ }
+- net_family_write_lock();
+- err = -EEXIST;
+- if (net_families[ops->family] == NULL) {
+- net_families[ops->family]=ops;
++
++ spin_lock(&net_family_lock);
++ if (net_families[ops->family])
++ err = -EEXIST;
++ else {
++ net_families[ops->family] = ops;
+ err = 0;
+ }
+- net_family_write_unlock();
+- printk(KERN_INFO "NET: Registered protocol family %d\n",
+- ops->family);
++ spin_unlock(&net_family_lock);
++
++ printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
+ return err;
+ }
+
+-/*
++/**
++ * sock_unregister - remove a protocol handler
++ * @family: protocol family to remove
++ *
+ * This function is called by a protocol handler that wants to
+ * remove its address family, and have it unlinked from the
+- * SOCKET module.
++ * new socket creation.
++ *
++ * If protocol handler is a module, then it can use module reference
++ * counts to protect against new references. If protocol handler is not
++ * a module then it needs to provide its own protection in
++ * the ops->create routine.
+ */
+-
+-int sock_unregister(int family)
++void sock_unregister(int family)
+ {
+- if (family < 0 || family >= NPROTO)
+- return -1;
++ BUG_ON(family < 0 || family >= NPROTO);
+
+- net_family_write_lock();
+- net_families[family]=NULL;
+- net_family_write_unlock();
+- printk(KERN_INFO "NET: Unregistered protocol family %d\n",
+- family);
+- return 0;
++ spin_lock(&net_family_lock);
++ net_families[family] = NULL;
++ spin_unlock(&net_family_lock);
++
++ synchronize_rcu();
++
++ printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
+ }
+
+ static int __init sock_init(void)
+ {
+ /*
+- * Initialize sock SLAB cache.
++ * Initialize sock SLAB cache.
+ */
+-
++
+ sk_init();
+
+ /*
+- * Initialize skbuff SLAB cache
++ * Initialize skbuff SLAB cache
+ */
+ skb_init();
+
+ /*
+- * Initialize the protocols module.
++ * Initialize the protocols module.
+ */
+
+ init_inodecache();
+@@ -2137,7 +2125,7 @@ void socket_seq_show(struct seq_file *se
+ int counter = 0;
+
+ for_each_possible_cpu(cpu)
+- counter += per_cpu(sockets_in_use, cpu);
++ counter += per_cpu(sockets_in_use, cpu);
+
+ /* It can be negative, by the way. 8) */
+ if (counter < 0)
+@@ -2145,11 +2133,11 @@ void socket_seq_show(struct seq_file *se
+
+ seq_printf(seq, "sockets: used %d\n", counter);
+ }
+-#endif /* CONFIG_PROC_FS */
++#endif /* CONFIG_PROC_FS */
+
+ #ifdef CONFIG_COMPAT
+ static long compat_sock_ioctl(struct file *file, unsigned cmd,
+- unsigned long arg)
++ unsigned long arg)
+ {
+ struct socket *sock = file->private_data;
+ int ret = -ENOIOCTLCMD;
+@@ -2161,6 +2149,109 @@ static long compat_sock_ioctl(struct fil
+ }
+ #endif
+
++int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
++{
++ return sock->ops->bind(sock, addr, addrlen);
++}
++
++int kernel_listen(struct socket *sock, int backlog)
++{
++ return sock->ops->listen(sock, backlog);
++}
++
++int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
++{
++ struct sock *sk = sock->sk;
++ int err;
++
++ err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol,
++ newsock);
++ if (err < 0)
++ goto done;
++
++ err = sock->ops->accept(sock, *newsock, flags);
++ if (err < 0) {
++ sock_release(*newsock);
++ goto done;
++ }
++
++ (*newsock)->ops = sock->ops;
++
++done:
++ return err;
++}
++
++int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
++ int flags)
++{
++ return sock->ops->connect(sock, addr, addrlen, flags);
++}
++
++int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
++ int *addrlen)
++{
++ return sock->ops->getname(sock, addr, addrlen, 0);
++}
++
++int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
++ int *addrlen)
++{
++ return sock->ops->getname(sock, addr, addrlen, 1);
++}
++
++int kernel_getsockopt(struct socket *sock, int level, int optname,
++ char *optval, int *optlen)
++{
++ mm_segment_t oldfs = get_fs();
++ int err;
++
++ set_fs(KERNEL_DS);
++ if (level == SOL_SOCKET)
++ err = sock_getsockopt(sock, level, optname, optval, optlen);
++ else
++ err = sock->ops->getsockopt(sock, level, optname, optval,
++ optlen);
++ set_fs(oldfs);
++ return err;
++}
++
++int kernel_setsockopt(struct socket *sock, int level, int optname,
++ char *optval, int optlen)
++{
++ mm_segment_t oldfs = get_fs();
++ int err;
++
++ set_fs(KERNEL_DS);
++ if (level == SOL_SOCKET)
++ err = sock_setsockopt(sock, level, optname, optval, optlen);
++ else
++ err = sock->ops->setsockopt(sock, level, optname, optval,
++ optlen);
++ set_fs(oldfs);
++ return err;
++}
++
++int kernel_sendpage(struct socket *sock, struct page *page, int offset,
++ size_t size, int flags)
++{
++ if (sock->ops->sendpage)
++ return sock->ops->sendpage(sock, page, offset, size, flags);
++
++ return sock_no_sendpage(sock, page, offset, size, flags);
++}
++
++int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
++{
++ mm_segment_t oldfs = get_fs();
++ int err;
++
++ set_fs(KERNEL_DS);
++ err = sock->ops->ioctl(sock, cmd, arg);
++ set_fs(oldfs);
++
++ return err;
++}
++
+ /* ABI emulation layers need these two */
+ EXPORT_SYMBOL(move_addr_to_kernel);
+ EXPORT_SYMBOL(move_addr_to_user);
+@@ -2177,3 +2268,13 @@ EXPORT_SYMBOL(sock_wake_async);
+ EXPORT_SYMBOL(sockfd_lookup);
+ EXPORT_SYMBOL(kernel_sendmsg);
+ EXPORT_SYMBOL(kernel_recvmsg);
++EXPORT_SYMBOL(kernel_bind);
++EXPORT_SYMBOL(kernel_listen);
++EXPORT_SYMBOL(kernel_accept);
++EXPORT_SYMBOL(kernel_connect);
++EXPORT_SYMBOL(kernel_getsockname);
++EXPORT_SYMBOL(kernel_getpeername);
++EXPORT_SYMBOL(kernel_getsockopt);
++EXPORT_SYMBOL(kernel_setsockopt);
++EXPORT_SYMBOL(kernel_sendpage);
++EXPORT_SYMBOL(kernel_sock_ioctl);
+diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
+index 55163af..993ff1a 100644
+--- a/net/sunrpc/auth.c
++++ b/net/sunrpc/auth.c
+@@ -331,8 +331,8 @@ rpcauth_unbindcred(struct rpc_task *task
+ task->tk_msg.rpc_cred = NULL;
+ }
+
+-u32 *
+-rpcauth_marshcred(struct rpc_task *task, u32 *p)
++__be32 *
++rpcauth_marshcred(struct rpc_task *task, __be32 *p)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
+@@ -342,8 +342,8 @@ rpcauth_marshcred(struct rpc_task *task,
+ return cred->cr_ops->crmarshal(task, p);
+ }
+
+-u32 *
+-rpcauth_checkverf(struct rpc_task *task, u32 *p)
++__be32 *
++rpcauth_checkverf(struct rpc_task *task, __be32 *p)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
+@@ -355,7 +355,7 @@ rpcauth_checkverf(struct rpc_task *task,
+
+ int
+ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
+- u32 *data, void *obj)
++ __be32 *data, void *obj)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
+@@ -369,7 +369,7 @@ rpcauth_wrap_req(struct rpc_task *task,
+
+ int
+ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
+- u32 *data, void *obj)
++ __be32 *data, void *obj)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
+diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
+index ef1cf5b..b36b946 100644
+--- a/net/sunrpc/auth_gss/auth_gss.c
++++ b/net/sunrpc/auth_gss/auth_gss.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/net/sunrpc/auth_gss.c
++ * linux/net/sunrpc/auth_gss/auth_gss.c
+ *
+ * RPCSEC_GSS client authentication.
+ *
+@@ -88,7 +88,6 @@ struct gss_auth {
+ struct list_head upcalls;
+ struct rpc_clnt *client;
+ struct dentry *dentry;
+- char path[48];
+ spinlock_t lock;
+ };
+
+@@ -690,10 +689,8 @@ gss_create(struct rpc_clnt *clnt, rpc_au
+ if (err)
+ goto err_put_mech;
+
+- snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",
+- clnt->cl_pathname,
+- gss_auth->mech->gm_name);
+- gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
++ gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name,
++ clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
+ if (IS_ERR(gss_auth->dentry)) {
+ err = PTR_ERR(gss_auth->dentry);
+ goto err_put_mech;
+@@ -829,14 +826,14 @@ out:
+ * Marshal credentials.
+ * Maybe we should keep a cached credential for performance reasons.
+ */
+-static u32 *
+-gss_marshal(struct rpc_task *task, u32 *p)
++static __be32 *
++gss_marshal(struct rpc_task *task, __be32 *p)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
+ gc_base);
+ struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
+- u32 *cred_len;
++ __be32 *cred_len;
+ struct rpc_rqst *req = task->tk_rqstp;
+ u32 maj_stat = 0;
+ struct xdr_netobj mic;
+@@ -897,12 +894,12 @@ gss_refresh(struct rpc_task *task)
+ return 0;
+ }
+
+-static u32 *
+-gss_validate(struct rpc_task *task, u32 *p)
++static __be32 *
++gss_validate(struct rpc_task *task, __be32 *p)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
+- u32 seq;
++ __be32 seq;
+ struct kvec iov;
+ struct xdr_buf verf_buf;
+ struct xdr_netobj mic;
+@@ -943,13 +940,14 @@ out_bad:
+
+ static inline int
+ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
+- kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
++ kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
+ {
+ struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
+ struct xdr_buf integ_buf;
+- u32 *integ_len = NULL;
++ __be32 *integ_len = NULL;
+ struct xdr_netobj mic;
+- u32 offset, *q;
++ u32 offset;
++ __be32 *q;
+ struct kvec *iov;
+ u32 maj_stat = 0;
+ int status = -EIO;
+@@ -1035,13 +1033,13 @@ out:
+
+ static inline int
+ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
+- kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
++ kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
+ {
+ struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
+ u32 offset;
+ u32 maj_stat;
+ int status;
+- u32 *opaque_len;
++ __be32 *opaque_len;
+ struct page **inpages;
+ int first;
+ int pad;
+@@ -1098,7 +1096,7 @@ gss_wrap_req_priv(struct rpc_cred *cred,
+
+ static int
+ gss_wrap_req(struct rpc_task *task,
+- kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
++ kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
+@@ -1135,7 +1133,7 @@ out:
+
+ static inline int
+ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
+- struct rpc_rqst *rqstp, u32 **p)
++ struct rpc_rqst *rqstp, __be32 **p)
+ {
+ struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
+ struct xdr_buf integ_buf;
+@@ -1172,7 +1170,7 @@ gss_unwrap_resp_integ(struct rpc_cred *c
+
+ static inline int
+ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
+- struct rpc_rqst *rqstp, u32 **p)
++ struct rpc_rqst *rqstp, __be32 **p)
+ {
+ struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
+ u32 offset;
+@@ -1201,13 +1199,13 @@ gss_unwrap_resp_priv(struct rpc_cred *cr
+
+ static int
+ gss_unwrap_resp(struct rpc_task *task,
+- kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
++ kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
+ {
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
+ gc_base);
+ struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
+- u32 *savedp = p;
++ __be32 *savedp = p;
+ struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
+ int savedlen = head->iov_len;
+ int status = -EIO;
+diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
+index 76b969e..e11a40b 100644
+--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
++++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
+@@ -34,6 +34,7 @@
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
++#include <linux/err.h>
+ #include <linux/types.h>
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+@@ -49,7 +50,7 @@
+
+ u32
+ krb5_encrypt(
+- struct crypto_tfm *tfm,
++ struct crypto_blkcipher *tfm,
+ void * iv,
+ void * in,
+ void * out,
+@@ -58,26 +59,27 @@ krb5_encrypt(
+ u32 ret = -EINVAL;
+ struct scatterlist sg[1];
+ u8 local_iv[16] = {0};
++ struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };
+
+ dprintk("RPC: krb5_encrypt: input data:\n");
+ print_hexl((u32 *)in, length, 0);
+
+- if (length % crypto_tfm_alg_blocksize(tfm) != 0)
++ if (length % crypto_blkcipher_blocksize(tfm) != 0)
+ goto out;
+
+- if (crypto_tfm_alg_ivsize(tfm) > 16) {
++ if (crypto_blkcipher_ivsize(tfm) > 16) {
+ dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
+- crypto_tfm_alg_ivsize(tfm));
++ crypto_blkcipher_ivsize(tfm));
+ goto out;
+ }
+
+ if (iv)
+- memcpy(local_iv, iv, crypto_tfm_alg_ivsize(tfm));
++ memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
+
+ memcpy(out, in, length);
+ sg_set_buf(sg, out, length);
+
+- ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
++ ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, length);
+
+ dprintk("RPC: krb5_encrypt: output data:\n");
+ print_hexl((u32 *)out, length, 0);
+@@ -90,7 +92,7 @@ EXPORT_SYMBOL(krb5_encrypt);
+
+ u32
+ krb5_decrypt(
+- struct crypto_tfm *tfm,
++ struct crypto_blkcipher *tfm,
+ void * iv,
+ void * in,
+ void * out,
+@@ -99,25 +101,26 @@ krb5_decrypt(
+ u32 ret = -EINVAL;
+ struct scatterlist sg[1];
+ u8 local_iv[16] = {0};
++ struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };
+
+ dprintk("RPC: krb5_decrypt: input data:\n");
+ print_hexl((u32 *)in, length, 0);
+
+- if (length % crypto_tfm_alg_blocksize(tfm) != 0)
++ if (length % crypto_blkcipher_blocksize(tfm) != 0)
+ goto out;
+
+- if (crypto_tfm_alg_ivsize(tfm) > 16) {
++ if (crypto_blkcipher_ivsize(tfm) > 16) {
+ dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
+- crypto_tfm_alg_ivsize(tfm));
++ crypto_blkcipher_ivsize(tfm));
+ goto out;
+ }
+ if (iv)
+- memcpy(local_iv,iv, crypto_tfm_alg_ivsize(tfm));
++ memcpy(local_iv,iv, crypto_blkcipher_ivsize(tfm));
+
+ memcpy(out, in, length);
+ sg_set_buf(sg, out, length);
+
+- ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
++ ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, length);
+
+ dprintk("RPC: krb5_decrypt: output_data:\n");
+ print_hexl((u32 *)out, length, 0);
+@@ -197,11 +200,9 @@ out:
+ static int
+ checksummer(struct scatterlist *sg, void *data)
+ {
+- struct crypto_tfm *tfm = (struct crypto_tfm *)data;
++ struct hash_desc *desc = data;
+
+- crypto_digest_update(tfm, sg, 1);
+-
+- return 0;
++ return crypto_hash_update(desc, sg, sg->length);
+ }
+
+ /* checksum the plaintext data and hdrlen bytes of the token header */
+@@ -210,8 +211,9 @@ make_checksum(s32 cksumtype, char *heade
+ int body_offset, struct xdr_netobj *cksum)
+ {
+ char *cksumname;
+- struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */
++ struct hash_desc desc; /* XXX add to ctx? */
+ struct scatterlist sg[1];
++ int err;
+
+ switch (cksumtype) {
+ case CKSUMTYPE_RSA_MD5:
+@@ -222,25 +224,35 @@ make_checksum(s32 cksumtype, char *heade
+ " unsupported checksum %d", cksumtype);
+ return GSS_S_FAILURE;
+ }
+- if (!(tfm = crypto_alloc_tfm(cksumname, CRYPTO_TFM_REQ_MAY_SLEEP)))
++ desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(desc.tfm))
+ return GSS_S_FAILURE;
+- cksum->len = crypto_tfm_alg_digestsize(tfm);
++ cksum->len = crypto_hash_digestsize(desc.tfm);
++ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+- crypto_digest_init(tfm);
++ err = crypto_hash_init(&desc);
++ if (err)
++ goto out;
+ sg_set_buf(sg, header, hdrlen);
+- crypto_digest_update(tfm, sg, 1);
+- process_xdr_buf(body, body_offset, body->len - body_offset,
+- checksummer, tfm);
+- crypto_digest_final(tfm, cksum->data);
+- crypto_free_tfm(tfm);
+- return 0;
++ err = crypto_hash_update(&desc, sg, hdrlen);
++ if (err)
++ goto out;
++ err = process_xdr_buf(body, body_offset, body->len - body_offset,
++ checksummer, &desc);
++ if (err)
++ goto out;
++ err = crypto_hash_final(&desc, cksum->data);
++
++out:
++ crypto_free_hash(desc.tfm);
++ return err ? GSS_S_FAILURE : 0;
+ }
+
+ EXPORT_SYMBOL(make_checksum);
+
+ struct encryptor_desc {
+ u8 iv[8]; /* XXX hard-coded blocksize */
+- struct crypto_tfm *tfm;
++ struct blkcipher_desc desc;
+ int pos;
+ struct xdr_buf *outbuf;
+ struct page **pages;
+@@ -285,8 +297,8 @@ encryptor(struct scatterlist *sg, void *
+ if (thislen == 0)
+ return 0;
+
+- ret = crypto_cipher_encrypt_iv(desc->tfm, desc->outfrags, desc->infrags,
+- thislen, desc->iv);
++ ret = crypto_blkcipher_encrypt_iv(&desc->desc, desc->outfrags,
++ desc->infrags, thislen);
+ if (ret)
+ return ret;
+ if (fraglen) {
+@@ -305,16 +317,18 @@ encryptor(struct scatterlist *sg, void *
+ }
+
+ int
+-gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset,
+- struct page **pages)
++gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
++ int offset, struct page **pages)
+ {
+ int ret;
+ struct encryptor_desc desc;
+
+- BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);
++ BUG_ON((buf->len - offset) % crypto_blkcipher_blocksize(tfm) != 0);
+
+ memset(desc.iv, 0, sizeof(desc.iv));
+- desc.tfm = tfm;
++ desc.desc.tfm = tfm;
++ desc.desc.info = desc.iv;
++ desc.desc.flags = 0;
+ desc.pos = offset;
+ desc.outbuf = buf;
+ desc.pages = pages;
+@@ -329,7 +343,7 @@ EXPORT_SYMBOL(gss_encrypt_xdr_buf);
+
+ struct decryptor_desc {
+ u8 iv[8]; /* XXX hard-coded blocksize */
+- struct crypto_tfm *tfm;
++ struct blkcipher_desc desc;
+ struct scatterlist frags[4];
+ int fragno;
+ int fraglen;
+@@ -355,8 +369,8 @@ decryptor(struct scatterlist *sg, void *
+ if (thislen == 0)
+ return 0;
+
+- ret = crypto_cipher_decrypt_iv(desc->tfm, desc->frags, desc->frags,
+- thislen, desc->iv);
++ ret = crypto_blkcipher_decrypt_iv(&desc->desc, desc->frags,
++ desc->frags, thislen);
+ if (ret)
+ return ret;
+ if (fraglen) {
+@@ -373,15 +387,18 @@ decryptor(struct scatterlist *sg, void *
+ }
+
+ int
+-gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset)
++gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
++ int offset)
+ {
+ struct decryptor_desc desc;
+
+ /* XXXJBF: */
+- BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);
++ BUG_ON((buf->len - offset) % crypto_blkcipher_blocksize(tfm) != 0);
+
+ memset(desc.iv, 0, sizeof(desc.iv));
+- desc.tfm = tfm;
++ desc.desc.tfm = tfm;
++ desc.desc.info = desc.iv;
++ desc.desc.flags = 0;
+ desc.fragno = 0;
+ desc.fraglen = 0;
+ return process_xdr_buf(buf, offset, buf->len - offset, decryptor, &desc);
+diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
+index 70e1e53..325e72e 100644
+--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
++++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
+@@ -34,6 +34,7 @@
+ *
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+@@ -78,10 +79,10 @@ simple_get_netobj(const void *p, const v
+ }
+
+ static inline const void *
+-get_key(const void *p, const void *end, struct crypto_tfm **res)
++get_key(const void *p, const void *end, struct crypto_blkcipher **res)
+ {
+ struct xdr_netobj key;
+- int alg, alg_mode;
++ int alg;
+ char *alg_name;
+
+ p = simple_get_bytes(p, end, &alg, sizeof(alg));
+@@ -93,18 +94,19 @@ get_key(const void *p, const void *end,
+
+ switch (alg) {
+ case ENCTYPE_DES_CBC_RAW:
+- alg_name = "des";
+- alg_mode = CRYPTO_TFM_MODE_CBC;
++ alg_name = "cbc(des)";
+ break;
+ default:
+ printk("gss_kerberos_mech: unsupported algorithm %d\n", alg);
+ goto out_err_free_key;
+ }
+- if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) {
++ *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(*res)) {
+ printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name);
++ *res = NULL;
+ goto out_err_free_key;
+ }
+- if (crypto_cipher_setkey(*res, key.data, key.len)) {
++ if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
+ printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name);
+ goto out_err_free_tfm;
+ }
+@@ -113,7 +115,7 @@ get_key(const void *p, const void *end,
+ return p;
+
+ out_err_free_tfm:
+- crypto_free_tfm(*res);
++ crypto_free_blkcipher(*res);
+ out_err_free_key:
+ kfree(key.data);
+ p = ERR_PTR(-EINVAL);
+@@ -172,9 +174,9 @@ gss_import_sec_context_kerberos(const vo
+ return 0;
+
+ out_err_free_key2:
+- crypto_free_tfm(ctx->seq);
++ crypto_free_blkcipher(ctx->seq);
+ out_err_free_key1:
+- crypto_free_tfm(ctx->enc);
++ crypto_free_blkcipher(ctx->enc);
+ out_err_free_mech:
+ kfree(ctx->mech_used.data);
+ out_err_free_ctx:
+@@ -187,8 +189,8 @@ static void
+ gss_delete_sec_context_kerberos(void *internal_ctx) {
+ struct krb5_ctx *kctx = internal_ctx;
+
+- crypto_free_tfm(kctx->seq);
+- crypto_free_tfm(kctx->enc);
++ crypto_free_blkcipher(kctx->seq);
++ crypto_free_blkcipher(kctx->enc);
+ kfree(kctx->mech_used.data);
+ kfree(kctx);
+ }
+diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
+index 2f31216..08601ee 100644
+--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
++++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
+@@ -115,7 +115,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss
+ krb5_hdr = ptr - 2;
+ msg_start = krb5_hdr + 24;
+
+- *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
++ *(__be16 *)(krb5_hdr + 2) = htons(ctx->signalg);
+ memset(krb5_hdr + 4, 0xff, 4);
+
+ if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
+diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+index c53ead3..c604baf 100644
+--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
++++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+@@ -41,7 +41,7 @@
+ #endif
+
+ s32
+-krb5_make_seq_num(struct crypto_tfm *key,
++krb5_make_seq_num(struct crypto_blkcipher *key,
+ int direction,
+ s32 seqnum,
+ unsigned char *cksum, unsigned char *buf)
+@@ -62,7 +62,7 @@ krb5_make_seq_num(struct crypto_tfm *key
+ }
+
+ s32
+-krb5_get_seq_num(struct crypto_tfm *key,
++krb5_get_seq_num(struct crypto_blkcipher *key,
+ unsigned char *cksum,
+ unsigned char *buf,
+ int *direction, s32 * seqnum)
+diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
+index 89d1f3e..cc45c16 100644
+--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
++++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
+@@ -149,7 +149,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, i
+ goto out_err;
+ }
+
+- blocksize = crypto_tfm_alg_blocksize(kctx->enc);
++ blocksize = crypto_blkcipher_blocksize(kctx->enc);
+ gss_krb5_add_padding(buf, offset, blocksize);
+ BUG_ON((buf->len - offset) % blocksize);
+ plainlen = blocksize + buf->len - offset;
+@@ -177,9 +177,9 @@ gss_wrap_kerberos(struct gss_ctx *ctx, i
+ msg_start = krb5_hdr + 24;
+ /* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize);
+
+- *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg);
++ *(__be16 *)(krb5_hdr + 2) = htons(kctx->signalg);
+ memset(krb5_hdr + 4, 0xff, 4);
+- *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
++ *(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
+
+ make_confounder(msg_start, blocksize);
+
+@@ -346,7 +346,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx,
+ /* Copy the data back to the right position. XXX: Would probably be
+ * better to copy and encrypt at the same time. */
+
+- blocksize = crypto_tfm_alg_blocksize(kctx->enc);
++ blocksize = crypto_blkcipher_blocksize(kctx->enc);
+ data_start = ptr + 22 + blocksize;
+ orig_start = buf->head[0].iov_base + offset;
+ data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start;
+diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
+index 88dcb52..bdedf45 100644
+--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
++++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
+@@ -34,6 +34,7 @@
+ *
+ */
+
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+@@ -83,10 +84,11 @@ simple_get_netobj(const void *p, const v
+ }
+
+ static inline const void *
+-get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
++get_key(const void *p, const void *end, struct crypto_blkcipher **res,
++ int *resalg)
+ {
+ struct xdr_netobj key = { 0 };
+- int alg_mode,setkey = 0;
++ int setkey = 0;
+ char *alg_name;
+
+ p = simple_get_bytes(p, end, resalg, sizeof(*resalg));
+@@ -98,14 +100,12 @@ get_key(const void *p, const void *end,
+
+ switch (*resalg) {
+ case NID_des_cbc:
+- alg_name = "des";
+- alg_mode = CRYPTO_TFM_MODE_CBC;
++ alg_name = "cbc(des)";
+ setkey = 1;
+ break;
+ case NID_cast5_cbc:
+ /* XXXX here in name only, not used */
+- alg_name = "cast5";
+- alg_mode = CRYPTO_TFM_MODE_CBC;
++ alg_name = "cbc(cast5)";
+ setkey = 0; /* XXX will need to set to 1 */
+ break;
+ case NID_md5:
+@@ -113,19 +113,20 @@ get_key(const void *p, const void *end,
+ dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
+ }
+ alg_name = "md5";
+- alg_mode = 0;
+ setkey = 0;
+ break;
+ default:
+ dprintk("gss_spkm3_mech: unsupported algorithm %d\n", *resalg);
+ goto out_err_free_key;
+ }
+- if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) {
++ *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(*res)) {
+ printk("gss_spkm3_mech: unable to initialize crypto algorthm %s\n", alg_name);
++ *res = NULL;
+ goto out_err_free_key;
+ }
+ if (setkey) {
+- if (crypto_cipher_setkey(*res, key.data, key.len)) {
++ if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
+ printk("gss_spkm3_mech: error setting key for crypto algorthm %s\n", alg_name);
+ goto out_err_free_tfm;
+ }
+@@ -136,7 +137,7 @@ get_key(const void *p, const void *end,
+ return p;
+
+ out_err_free_tfm:
+- crypto_free_tfm(*res);
++ crypto_free_blkcipher(*res);
+ out_err_free_key:
+ if(key.len > 0)
+ kfree(key.data);
+@@ -204,9 +205,9 @@ gss_import_sec_context_spkm3(const void
+ return 0;
+
+ out_err_free_key2:
+- crypto_free_tfm(ctx->derived_integ_key);
++ crypto_free_blkcipher(ctx->derived_integ_key);
+ out_err_free_key1:
+- crypto_free_tfm(ctx->derived_conf_key);
++ crypto_free_blkcipher(ctx->derived_conf_key);
+ out_err_free_s_key:
+ kfree(ctx->share_key.data);
+ out_err_free_mech:
+@@ -223,8 +224,8 @@ static void
+ gss_delete_sec_context_spkm3(void *internal_ctx) {
+ struct spkm3_ctx *sctx = internal_ctx;
+
+- crypto_free_tfm(sctx->derived_integ_key);
+- crypto_free_tfm(sctx->derived_conf_key);
++ crypto_free_blkcipher(sctx->derived_integ_key);
++ crypto_free_blkcipher(sctx->derived_conf_key);
+ kfree(sctx->share_key.data);
+ kfree(sctx->mech_used.data);
+ kfree(sctx);
+diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
+index 94217ec..1f0f079 100644
+--- a/net/sunrpc/auth_gss/svcauth_gss.c
++++ b/net/sunrpc/auth_gss/svcauth_gss.c
+@@ -607,7 +607,7 @@ svc_safe_getnetobj(struct kvec *argv, st
+
+ if (argv->iov_len < 4)
+ return -1;
+- o->len = ntohl(svc_getu32(argv));
++ o->len = svc_getnl(argv);
+ l = round_up_to_quad(o->len);
+ if (argv->iov_len < l)
+ return -1;
+@@ -620,17 +620,17 @@ svc_safe_getnetobj(struct kvec *argv, st
+ static inline int
+ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
+ {
+- u32 *p;
++ u8 *p;
+
+ if (resv->iov_len + 4 > PAGE_SIZE)
+ return -1;
+- svc_putu32(resv, htonl(o->len));
++ svc_putnl(resv, o->len);
+ p = resv->iov_base + resv->iov_len;
+ resv->iov_len += round_up_to_quad(o->len);
+ if (resv->iov_len > PAGE_SIZE)
+ return -1;
+ memcpy(p, o->data, o->len);
+- memset((u8 *)p + o->len, 0, round_up_to_quad(o->len) - o->len);
++ memset(p + o->len, 0, round_up_to_quad(o->len) - o->len);
+ return 0;
+ }
+
+@@ -640,7 +640,7 @@ svc_safe_putnetobj(struct kvec *resv, st
+ */
+ static int
+ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
+- u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp)
++ __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
+ {
+ struct gss_ctx *ctx_id = rsci->mechctx;
+ struct xdr_buf rpchdr;
+@@ -657,7 +657,7 @@ gss_verify_header(struct svc_rqst *rqstp
+ *authp = rpc_autherr_badverf;
+ if (argv->iov_len < 4)
+ return SVC_DENIED;
+- flavor = ntohl(svc_getu32(argv));
++ flavor = svc_getnl(argv);
+ if (flavor != RPC_AUTH_GSS)
+ return SVC_DENIED;
+ if (svc_safe_getnetobj(argv, &checksum))
+@@ -687,9 +687,9 @@ gss_verify_header(struct svc_rqst *rqstp
+ static int
+ gss_write_null_verf(struct svc_rqst *rqstp)
+ {
+- u32 *p;
++ __be32 *p;
+
+- svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_NULL));
++ svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL);
+ p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
+ /* don't really need to check if head->iov_len > PAGE_SIZE ... */
+ *p++ = 0;
+@@ -701,14 +701,14 @@ gss_write_null_verf(struct svc_rqst *rqs
+ static int
+ gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
+ {
+- u32 xdr_seq;
++ __be32 xdr_seq;
+ u32 maj_stat;
+ struct xdr_buf verf_data;
+ struct xdr_netobj mic;
+- u32 *p;
++ __be32 *p;
+ struct kvec iov;
+
+- svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS));
++ svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
+ xdr_seq = htonl(seq);
+
+ iov.iov_base = &xdr_seq;
+@@ -782,7 +782,7 @@ EXPORT_SYMBOL(svcauth_gss_register_pseud
+ static inline int
+ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
+ {
+- u32 raw;
++ __be32 raw;
+ int status;
+
+ status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
+@@ -805,7 +805,7 @@ unwrap_integ_data(struct xdr_buf *buf, u
+ struct xdr_netobj mic;
+ struct xdr_buf integ_buf;
+
+- integ_len = ntohl(svc_getu32(&buf->head[0]));
++ integ_len = svc_getnl(&buf->head[0]);
+ if (integ_len & 3)
+ goto out;
+ if (integ_len > buf->len)
+@@ -825,7 +825,7 @@ unwrap_integ_data(struct xdr_buf *buf, u
+ maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
+ if (maj_stat != GSS_S_COMPLETE)
+ goto out;
+- if (ntohl(svc_getu32(&buf->head[0])) != seq)
++ if (svc_getnl(&buf->head[0]) != seq)
+ goto out;
+ stat = 0;
+ out:
+@@ -857,7 +857,7 @@ unwrap_priv_data(struct svc_rqst *rqstp,
+
+ rqstp->rq_sendfile_ok = 0;
+
+- priv_len = ntohl(svc_getu32(&buf->head[0]));
++ priv_len = svc_getnl(&buf->head[0]);
+ if (rqstp->rq_deferred) {
+ /* Already decrypted last time through! The sequence number
+ * check at out_seq is unnecessary but harmless: */
+@@ -895,7 +895,7 @@ unwrap_priv_data(struct svc_rqst *rqstp,
+ if (maj_stat != GSS_S_COMPLETE)
+ return -EINVAL;
+ out_seq:
+- if (ntohl(svc_getu32(&buf->head[0])) != seq)
++ if (svc_getnl(&buf->head[0]) != seq)
+ return -EINVAL;
+ return 0;
+ }
+@@ -903,9 +903,9 @@ out_seq:
+ struct gss_svc_data {
+ /* decoded gss client cred: */
+ struct rpc_gss_wire_cred clcred;
+- /* pointer to the beginning of the procedure-specific results,
+- * which may be encrypted/checksummed in svcauth_gss_release: */
+- u32 *body_start;
++ /* save a pointer to the beginning of the encoded verifier,
++ * for use in encryption/checksumming in svcauth_gss_release: */
++ __be32 *verf_start;
+ struct rsc *rsci;
+ };
+
+@@ -946,7 +946,7 @@ gss_write_init_verf(struct svc_rqst *rqs
+ * response here and return SVC_COMPLETE.
+ */
+ static int
+-svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
++svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
+ {
+ struct kvec *argv = &rqstp->rq_arg.head[0];
+ struct kvec *resv = &rqstp->rq_res.head[0];
+@@ -956,8 +956,8 @@ svcauth_gss_accept(struct svc_rqst *rqst
+ struct rpc_gss_wire_cred *gc;
+ struct rsc *rsci = NULL;
+ struct rsi *rsip, rsikey;
+- u32 *rpcstart;
+- u32 *reject_stat = resv->iov_base + resv->iov_len;
++ __be32 *rpcstart;
++ __be32 *reject_stat = resv->iov_base + resv->iov_len;
+ int ret;
+
+ dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len);
+@@ -968,7 +968,7 @@ svcauth_gss_accept(struct svc_rqst *rqst
+ if (!svcdata)
+ goto auth_err;
+ rqstp->rq_auth_data = svcdata;
+- svcdata->body_start = NULL;
++ svcdata->verf_start = NULL;
+ svcdata->rsci = NULL;
+ gc = &svcdata->clcred;
+
+@@ -985,12 +985,12 @@ svcauth_gss_accept(struct svc_rqst *rqst
+
+ if (argv->iov_len < 5 * 4)
+ goto auth_err;
+- crlen = ntohl(svc_getu32(argv));
+- if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION)
++ crlen = svc_getnl(argv);
++ if (svc_getnl(argv) != RPC_GSS_VERSION)
+ goto auth_err;
+- gc->gc_proc = ntohl(svc_getu32(argv));
+- gc->gc_seq = ntohl(svc_getu32(argv));
+- gc->gc_svc = ntohl(svc_getu32(argv));
++ gc->gc_proc = svc_getnl(argv);
++ gc->gc_seq = svc_getnl(argv);
++ gc->gc_svc = svc_getnl(argv);
+ if (svc_safe_getnetobj(argv, &gc->gc_ctx))
+ goto auth_err;
+ if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
+@@ -1016,9 +1016,9 @@ svcauth_gss_accept(struct svc_rqst *rqst
+ case RPC_GSS_PROC_CONTINUE_INIT:
+ if (argv->iov_len < 2 * 4)
+ goto auth_err;
+- if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL)
++ if (svc_getnl(argv) != RPC_AUTH_NULL)
+ goto auth_err;
+- if (ntohl(svc_getu32(argv)) != 0)
++ if (svc_getnl(argv) != 0)
+ goto auth_err;
+ break;
+ case RPC_GSS_PROC_DATA:
+@@ -1076,14 +1076,14 @@ svcauth_gss_accept(struct svc_rqst *rqst
+ goto drop;
+ if (resv->iov_len + 4 > PAGE_SIZE)
+ goto drop;
+- svc_putu32(resv, rpc_success);
++ svc_putnl(resv, RPC_SUCCESS);
+ if (svc_safe_putnetobj(resv, &rsip->out_handle))
+ goto drop;
+ if (resv->iov_len + 3 * 4 > PAGE_SIZE)
+ goto drop;
+- svc_putu32(resv, htonl(rsip->major_status));
+- svc_putu32(resv, htonl(rsip->minor_status));
+- svc_putu32(resv, htonl(GSS_SEQ_WIN));
++ svc_putnl(resv, rsip->major_status);
++ svc_putnl(resv, rsip->minor_status);
++ svc_putnl(resv, GSS_SEQ_WIN);
+ if (svc_safe_putnetobj(resv, &rsip->out_token))
+ goto drop;
+ rqstp->rq_client = NULL;
+@@ -1093,10 +1093,11 @@ svcauth_gss_accept(struct svc_rqst *rqst
+ set_bit(CACHE_NEGATIVE, &rsci->h.flags);
+ if (resv->iov_len + 4 > PAGE_SIZE)
+ goto drop;
+- svc_putu32(resv, rpc_success);
++ svc_putnl(resv, RPC_SUCCESS);
+ goto complete;
+ case RPC_GSS_PROC_DATA:
+ *authp = rpcsec_gsserr_ctxproblem;
++ svcdata->verf_start = resv->iov_base + resv->iov_len;
+ if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
+ goto auth_err;
+ rqstp->rq_cred = rsci->cred;
+@@ -1110,18 +1111,16 @@ svcauth_gss_accept(struct svc_rqst *rqst
+ gc->gc_seq, rsci->mechctx))
+ goto auth_err;
+ /* placeholders for length and seq. number: */
+- svcdata->body_start = resv->iov_base + resv->iov_len;
+- svc_putu32(resv, 0);
+- svc_putu32(resv, 0);
++ svc_putnl(resv, 0);
++ svc_putnl(resv, 0);
+ break;
+ case RPC_GSS_SVC_PRIVACY:
+ if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
+ gc->gc_seq, rsci->mechctx))
+ goto auth_err;
+ /* placeholders for length and seq. number: */
+- svcdata->body_start = resv->iov_base + resv->iov_len;
+- svc_putu32(resv, 0);
+- svc_putu32(resv, 0);
++ svc_putnl(resv, 0);
++ svc_putnl(resv, 0);
+ break;
+ default:
+ goto auth_err;
+@@ -1147,6 +1146,33 @@ out:
+ return ret;
+ }
+
++static __be32 *
++svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
++{
++ __be32 *p;
++ u32 verf_len;
++
++ p = gsd->verf_start;
++ gsd->verf_start = NULL;
++
++ /* If the reply stat is nonzero, don't wrap: */
++ if (*(p-1) != rpc_success)
++ return NULL;
++ /* Skip the verifier: */
++ p += 1;
++ verf_len = ntohl(*p++);
++ p += XDR_QUADLEN(verf_len);
++ /* move accept_stat to right place: */
++ memcpy(p, p + 2, 4);
++ /* Also don't wrap if the accept stat is nonzero: */
++ if (*p != rpc_success) {
++ resbuf->head[0].iov_len -= 2 * 4;
++ return NULL;
++ }
++ p++;
++ return p;
++}
++
+ static inline int
+ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
+ {
+@@ -1156,21 +1182,13 @@ svcauth_gss_wrap_resp_integ(struct svc_r
+ struct xdr_buf integ_buf;
+ struct xdr_netobj mic;
+ struct kvec *resv;
+- u32 *p;
++ __be32 *p;
+ int integ_offset, integ_len;
+ int stat = -EINVAL;
+
+- p = gsd->body_start;
+- gsd->body_start = NULL;
+- /* move accept_stat to right place: */
+- memcpy(p, p + 2, 4);
+- /* Don't wrap in failure case: */
+- /* Counting on not getting here if call was not even accepted! */
+- if (*p != rpc_success) {
+- resbuf->head[0].iov_len -= 2 * 4;
++ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
++ if (p == NULL)
+ goto out;
+- }
+- p++;
+ integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
+ integ_len = resbuf->len - integ_offset;
+ BUG_ON(integ_len % 4);
+@@ -1191,7 +1209,6 @@ svcauth_gss_wrap_resp_integ(struct svc_r
+ resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ + resbuf->head[0].iov_len;
+ resbuf->tail[0].iov_len = 0;
+- rqstp->rq_restailpage = 0;
+ resv = &resbuf->tail[0];
+ } else {
+ resv = &resbuf->tail[0];
+@@ -1199,7 +1216,7 @@ svcauth_gss_wrap_resp_integ(struct svc_r
+ mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
+ if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
+ goto out_err;
+- svc_putu32(resv, htonl(mic.len));
++ svc_putnl(resv, mic.len);
+ memset(mic.data + mic.len, 0,
+ round_up_to_quad(mic.len) - mic.len);
+ resv->iov_len += XDR_QUADLEN(mic.len) << 2;
+@@ -1219,28 +1236,20 @@ svcauth_gss_wrap_resp_priv(struct svc_rq
+ struct rpc_gss_wire_cred *gc = &gsd->clcred;
+ struct xdr_buf *resbuf = &rqstp->rq_res;
+ struct page **inpages = NULL;
+- u32 *p;
+- int offset, *len;
++ __be32 *p, *len;
++ int offset;
+ int pad;
+
+- p = gsd->body_start;
+- gsd->body_start = NULL;
+- /* move accept_stat to right place: */
+- memcpy(p, p + 2, 4);
+- /* Don't wrap in failure case: */
+- /* Counting on not getting here if call was not even accepted! */
+- if (*p != rpc_success) {
+- resbuf->head[0].iov_len -= 2 * 4;
++ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
++ if (p == NULL)
+ return 0;
+- }
+- p++;
+ len = p++;
+ offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
+ *p++ = htonl(gc->gc_seq);
+ inpages = resbuf->pages;
+ /* XXX: Would be better to write some xdr helper functions for
+ * nfs{2,3,4}xdr.c that place the data right, instead of copying: */
+- if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) {
++ if (resbuf->tail[0].iov_base) {
+ BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ + PAGE_SIZE);
+ BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
+@@ -1258,13 +1267,12 @@ svcauth_gss_wrap_resp_priv(struct svc_rq
+ resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
+ resbuf->tail[0].iov_len = 0;
+- rqstp->rq_restailpage = 0;
+ }
+ if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
+ return -ENOMEM;
+ *len = htonl(resbuf->len - offset);
+ pad = 3 - ((resbuf->len - offset - 1)&3);
+- p = (u32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
++ p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
+ memset(p, 0, pad);
+ resbuf->tail[0].iov_len += pad;
+ resbuf->len += pad;
+@@ -1282,7 +1290,7 @@ svcauth_gss_release(struct svc_rqst *rqs
+ if (gc->gc_proc != RPC_GSS_PROC_DATA)
+ goto out;
+ /* Release can be called twice, but we only wrap once. */
+- if (gsd->body_start == NULL)
++ if (gsd->verf_start == NULL)
+ goto out;
+ /* normally not set till svc_send, but we need it here: */
+ /* XXX: what for? Do we mess it up the moment we call svc_putu32
+diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
+index 2eccffa..3be257d 100644
+--- a/net/sunrpc/auth_null.c
++++ b/net/sunrpc/auth_null.c
+@@ -60,8 +60,8 @@ nul_match(struct auth_cred *acred, struc
+ /*
+ * Marshal credential.
+ */
+-static u32 *
+-nul_marshal(struct rpc_task *task, u32 *p)
++static __be32 *
++nul_marshal(struct rpc_task *task, __be32 *p)
+ {
+ *p++ = htonl(RPC_AUTH_NULL);
+ *p++ = 0;
+@@ -81,8 +81,8 @@ nul_refresh(struct rpc_task *task)
+ return 0;
+ }
+
+-static u32 *
+-nul_validate(struct rpc_task *task, u32 *p)
++static __be32 *
++nul_validate(struct rpc_task *task, __be32 *p)
+ {
+ rpc_authflavor_t flavor;
+ u32 size;
+diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
+index 74c7406..f7f990c 100644
+--- a/net/sunrpc/auth_unix.c
++++ b/net/sunrpc/auth_unix.c
+@@ -137,12 +137,12 @@ unx_match(struct auth_cred *acred, struc
+ * Marshal credentials.
+ * Maybe we should keep a cached credential for performance reasons.
+ */
+-static u32 *
+-unx_marshal(struct rpc_task *task, u32 *p)
++static __be32 *
++unx_marshal(struct rpc_task *task, __be32 *p)
+ {
+ struct rpc_clnt *clnt = task->tk_client;
+ struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
+- u32 *base, *hold;
++ __be32 *base, *hold;
+ int i;
+
+ *p++ = htonl(RPC_AUTH_UNIX);
+@@ -178,8 +178,8 @@ unx_refresh(struct rpc_task *task)
+ return 0;
+ }
+
+-static u32 *
+-unx_validate(struct rpc_task *task, u32 *p)
++static __be32 *
++unx_validate(struct rpc_task *task, __be32 *p)
+ {
+ rpc_authflavor_t flavor;
+ u32 size;
+diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
+index 3e19d32..78696f2 100644
+--- a/net/sunrpc/clnt.c
++++ b/net/sunrpc/clnt.c
+@@ -60,8 +60,8 @@ static void call_refreshresult(struct rp
+ static void call_timeout(struct rpc_task *task);
+ static void call_connect(struct rpc_task *task);
+ static void call_connect_status(struct rpc_task *task);
+-static u32 * call_header(struct rpc_task *task);
+-static u32 * call_verify(struct rpc_task *task);
++static __be32 * call_header(struct rpc_task *task);
++static __be32 * call_verify(struct rpc_task *task);
+
+
+ static int
+@@ -97,17 +97,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt,
+ }
+ }
+
+-/*
+- * Create an RPC client
+- * FIXME: This should also take a flags argument (as in task->tk_flags).
+- * It's called (among others) from pmap_create_client, which may in
+- * turn be called by an async task. In this case, rpciod should not be
+- * made to sleep too long.
+- */
+-struct rpc_clnt *
+-rpc_new_client(struct rpc_xprt *xprt, char *servname,
+- struct rpc_program *program, u32 vers,
+- rpc_authflavor_t flavor)
++static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *program, u32 vers, rpc_authflavor_t flavor)
+ {
+ struct rpc_version *version;
+ struct rpc_clnt *clnt = NULL;
+@@ -147,16 +137,12 @@ rpc_new_client(struct rpc_xprt *xprt, ch
+ clnt->cl_procinfo = version->procs;
+ clnt->cl_maxproc = version->nrprocs;
+ clnt->cl_protname = program->name;
+- clnt->cl_pmap = &clnt->cl_pmap_default;
+- clnt->cl_port = xprt->addr.sin_port;
+ clnt->cl_prog = program->number;
+ clnt->cl_vers = version->number;
+- clnt->cl_prot = xprt->prot;
+ clnt->cl_stats = program->stats;
+ clnt->cl_metrics = rpc_alloc_iostats(clnt);
+- rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
+
+- if (!clnt->cl_port)
++ if (!xprt_bound(clnt->cl_xprt))
+ clnt->cl_autobind = 1;
+
+ clnt->cl_rtt = &clnt->cl_rtt_default;
+@@ -175,10 +161,10 @@ rpc_new_client(struct rpc_xprt *xprt, ch
+ }
+
+ /* save the nodename */
+- clnt->cl_nodelen = strlen(system_utsname.nodename);
++ clnt->cl_nodelen = strlen(utsname()->nodename);
+ if (clnt->cl_nodelen > UNX_MAXNODENAME)
+ clnt->cl_nodelen = UNX_MAXNODENAME;
+- memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen);
++ memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen);
+ return clnt;
+
+ out_no_auth:
+@@ -191,40 +177,71 @@ out_no_path:
+ kfree(clnt->cl_server);
+ kfree(clnt);
+ out_err:
+- xprt_destroy(xprt);
++ xprt_put(xprt);
+ out_no_xprt:
+ return ERR_PTR(err);
+ }
+
+-/**
+- * Create an RPC client
+- * @xprt - pointer to xprt struct
+- * @servname - name of server
+- * @info - rpc_program
+- * @version - rpc_program version
+- * @authflavor - rpc_auth flavour to use
++/*
++ * rpc_create - create an RPC client and transport with one call
++ * @args: rpc_clnt create argument structure
+ *
+- * Creates an RPC client structure, then pings the server in order to
+- * determine if it is up, and if it supports this program and version.
++ * Creates and initializes an RPC transport and an RPC client.
+ *
+- * This function should never be called by asynchronous tasks such as
+- * the portmapper.
++ * It can ping the server in order to determine if it is up, and to see if
++ * it supports this program and version. RPC_CLNT_CREATE_NOPING disables
++ * this behavior so asynchronous tasks can also use rpc_create.
+ */
+-struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
+- struct rpc_program *info, u32 version, rpc_authflavor_t authflavor)
++struct rpc_clnt *rpc_create(struct rpc_create_args *args)
+ {
++ struct rpc_xprt *xprt;
+ struct rpc_clnt *clnt;
+- int err;
+-
+- clnt = rpc_new_client(xprt, servname, info, version, authflavor);
++
++ xprt = xprt_create_transport(args->protocol, args->address,
++ args->addrsize, args->timeout);
++ if (IS_ERR(xprt))
++ return (struct rpc_clnt *)xprt;
++
++ /*
++ * By default, kernel RPC client connects from a reserved port.
++ * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
++ * but it is always enabled for rpciod, which handles the connect
++ * operation.
++ */
++ xprt->resvport = 1;
++ if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
++ xprt->resvport = 0;
++
++ dprintk("RPC: creating %s client for %s (xprt %p)\n",
++ args->program->name, args->servername, xprt);
++
++ clnt = rpc_new_client(xprt, args->servername, args->program,
++ args->version, args->authflavor);
+ if (IS_ERR(clnt))
+ return clnt;
+- err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
+- if (err == 0)
+- return clnt;
+- rpc_shutdown_client(clnt);
+- return ERR_PTR(err);
++
++ if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
++ int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
++ if (err != 0) {
++ rpc_shutdown_client(clnt);
++ return ERR_PTR(err);
++ }
++ }
++
++ clnt->cl_softrtry = 1;
++ if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
++ clnt->cl_softrtry = 0;
++
++ if (args->flags & RPC_CLNT_CREATE_INTR)
++ clnt->cl_intr = 1;
++ if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
++ clnt->cl_autobind = 1;
++ if (args->flags & RPC_CLNT_CREATE_ONESHOT)
++ clnt->cl_oneshot = 1;
++
++ return clnt;
+ }
++EXPORT_SYMBOL_GPL(rpc_create);
+
+ /*
+ * This function clones the RPC client structure. It allows us to share the
+@@ -244,8 +261,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
+ atomic_set(&new->cl_users, 0);
+ new->cl_parent = clnt;
+ atomic_inc(&clnt->cl_count);
+- /* Duplicate portmapper */
+- rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
++ new->cl_xprt = xprt_get(clnt->cl_xprt);
+ /* Turn off autobind on clones */
+ new->cl_autobind = 0;
+ new->cl_oneshot = 0;
+@@ -255,8 +271,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
+ rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
+ if (new->cl_auth)
+ atomic_inc(&new->cl_auth->au_count);
+- new->cl_pmap = &new->cl_pmap_default;
+- new->cl_metrics = rpc_alloc_iostats(clnt);
++ new->cl_metrics = rpc_alloc_iostats(clnt);
+ return new;
+ out_no_clnt:
+ printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
+@@ -323,15 +338,12 @@ rpc_destroy_client(struct rpc_clnt *clnt
+ rpc_rmdir(clnt->cl_dentry);
+ rpc_put_mount();
+ }
+- if (clnt->cl_xprt) {
+- xprt_destroy(clnt->cl_xprt);
+- clnt->cl_xprt = NULL;
+- }
+ if (clnt->cl_server != clnt->cl_inline_name)
+ kfree(clnt->cl_server);
+ out_free:
+ rpc_free_iostats(clnt->cl_metrics);
+ clnt->cl_metrics = NULL;
++ xprt_put(clnt->cl_xprt);
+ kfree(clnt);
+ return 0;
+ }
+@@ -540,6 +552,40 @@ rpc_call_setup(struct rpc_task *task, st
+ task->tk_action = rpc_exit_task;
+ }
+
++/**
++ * rpc_peeraddr - extract remote peer address from clnt's xprt
++ * @clnt: RPC client structure
++ * @buf: target buffer
++ * @size: length of target buffer
++ *
++ * Returns the number of bytes that are actually in the stored address.
++ */
++size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
++{
++ size_t bytes;
++ struct rpc_xprt *xprt = clnt->cl_xprt;
++
++ bytes = sizeof(xprt->addr);
++ if (bytes > bufsize)
++ bytes = bufsize;
++ memcpy(buf, &clnt->cl_xprt->addr, bytes);
++ return xprt->addrlen;
++}
++EXPORT_SYMBOL_GPL(rpc_peeraddr);
++
++/**
++ * rpc_peeraddr2str - return remote peer address in printable format
++ * @clnt: RPC client structure
++ * @format: address format
++ *
++ */
++char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format)
++{
++ struct rpc_xprt *xprt = clnt->cl_xprt;
++ return xprt->ops->print_addr(xprt, format);
++}
++EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
++
+ void
+ rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
+ {
+@@ -560,7 +606,7 @@ size_t rpc_max_payload(struct rpc_clnt *
+ {
+ return clnt->cl_xprt->max_payload;
+ }
+-EXPORT_SYMBOL(rpc_max_payload);
++EXPORT_SYMBOL_GPL(rpc_max_payload);
+
+ /**
+ * rpc_force_rebind - force transport to check that remote port is unchanged
+@@ -570,9 +616,9 @@ EXPORT_SYMBOL(rpc_max_payload);
+ void rpc_force_rebind(struct rpc_clnt *clnt)
+ {
+ if (clnt->cl_autobind)
+- clnt->cl_port = 0;
++ xprt_clear_bound(clnt->cl_xprt);
+ }
+-EXPORT_SYMBOL(rpc_force_rebind);
++EXPORT_SYMBOL_GPL(rpc_force_rebind);
+
+ /*
+ * Restart an (async) RPC call. Usually called from within the
+@@ -736,7 +782,7 @@ call_encode(struct rpc_task *task)
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ unsigned int bufsiz;
+ kxdrproc_t encode;
+- u32 *p;
++ __be32 *p;
+
+ dprintk("RPC: %4d call_encode (status %d)\n",
+ task->tk_pid, task->tk_status);
+@@ -781,16 +827,16 @@ call_encode(struct rpc_task *task)
+ static void
+ call_bind(struct rpc_task *task)
+ {
+- struct rpc_clnt *clnt = task->tk_client;
++ struct rpc_xprt *xprt = task->tk_xprt;
+
+ dprintk("RPC: %4d call_bind (status %d)\n",
+ task->tk_pid, task->tk_status);
+
+ task->tk_action = call_connect;
+- if (!clnt->cl_port) {
++ if (!xprt_bound(xprt)) {
+ task->tk_action = call_bind_status;
+- task->tk_timeout = task->tk_xprt->bind_timeout;
+- rpc_getport(task, clnt);
++ task->tk_timeout = xprt->bind_timeout;
++ xprt->ops->rpcbind(task);
+ }
+ }
+
+@@ -815,15 +861,11 @@ call_bind_status(struct rpc_task *task)
+ dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n",
+ task->tk_pid);
+ rpc_delay(task, 3*HZ);
+- goto retry_bind;
++ goto retry_timeout;
+ case -ETIMEDOUT:
+ dprintk("RPC: %4d rpcbind request timed out\n",
+ task->tk_pid);
+- if (RPC_IS_SOFT(task)) {
+- status = -EIO;
+- break;
+- }
+- goto retry_bind;
++ goto retry_timeout;
+ case -EPFNOSUPPORT:
+ dprintk("RPC: %4d remote rpcbind service unavailable\n",
+ task->tk_pid);
+@@ -836,16 +878,13 @@ call_bind_status(struct rpc_task *task)
+ dprintk("RPC: %4d unrecognized rpcbind error (%d)\n",
+ task->tk_pid, -task->tk_status);
+ status = -EIO;
+- break;
+ }
+
+ rpc_exit(task, status);
+ return;
+
+-retry_bind:
+- task->tk_status = 0;
+- task->tk_action = call_bind;
+- return;
++retry_timeout:
++ task->tk_action = call_timeout;
+ }
+
+ /*
+@@ -893,14 +932,16 @@ call_connect_status(struct rpc_task *tas
+
+ switch (status) {
+ case -ENOTCONN:
+- case -ETIMEDOUT:
+ case -EAGAIN:
+ task->tk_action = call_bind;
+- break;
+- default:
+- rpc_exit(task, -EIO);
+- break;
++ if (!RPC_IS_SOFT(task))
++ return;
++ /* if soft mounted, test if we've timed out */
++ case -ETIMEDOUT:
++ task->tk_action = call_timeout;
++ return;
+ }
++ rpc_exit(task, -EIO);
+ }
+
+ /*
+@@ -982,6 +1023,14 @@ call_status(struct rpc_task *task)
+
+ task->tk_status = 0;
+ switch(status) {
++ case -EHOSTDOWN:
++ case -EHOSTUNREACH:
++ case -ENETUNREACH:
++ /*
++ * Delay any retries for 3 seconds, then handle as if it
++ * were a timeout.
++ */
++ rpc_delay(task, 3*HZ);
+ case -ETIMEDOUT:
+ task->tk_action = call_timeout;
+ break;
+@@ -1001,7 +1050,6 @@ call_status(struct rpc_task *task)
+ printk("%s: RPC call returned error %d\n",
+ clnt->cl_protname, -status);
+ rpc_exit(task, status);
+- break;
+ }
+ }
+
+@@ -1052,7 +1100,7 @@ call_decode(struct rpc_task *task)
+ struct rpc_clnt *clnt = task->tk_client;
+ struct rpc_rqst *req = task->tk_rqstp;
+ kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode;
+- u32 *p;
++ __be32 *p;
+
+ dprintk("RPC: %4d call_decode (status %d)\n",
+ task->tk_pid, task->tk_status);
+@@ -1069,10 +1117,10 @@ call_decode(struct rpc_task *task)
+ clnt->cl_stats->rpcretrans++;
+ goto out_retry;
+ }
+- printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
++ dprintk("%s: too small RPC reply size (%d bytes)\n",
+ clnt->cl_protname, task->tk_status);
+- rpc_exit(task, -EIO);
+- return;
++ task->tk_action = call_timeout;
++ goto out_retry;
+ }
+
+ /*
+@@ -1149,12 +1197,12 @@ call_refreshresult(struct rpc_task *task
+ /*
+ * Call header serialization
+ */
+-static u32 *
++static __be32 *
+ call_header(struct rpc_task *task)
+ {
+ struct rpc_clnt *clnt = task->tk_client;
+ struct rpc_rqst *req = task->tk_rqstp;
+- u32 *p = req->rq_svec[0].iov_base;
++ __be32 *p = req->rq_svec[0].iov_base;
+
+ /* FIXME: check buffer size? */
+
+@@ -1173,12 +1221,13 @@ call_header(struct rpc_task *task)
+ /*
+ * Reply header verification
+ */
+-static u32 *
++static __be32 *
+ call_verify(struct rpc_task *task)
+ {
+ struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
+ int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
+- u32 *p = iov->iov_base, n;
++ __be32 *p = iov->iov_base;
++ u32 n;
+ int error = -EACCES;
+
+ if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
+@@ -1255,7 +1304,7 @@ call_verify(struct rpc_task *task)
+ printk(KERN_WARNING "call_verify: auth check failed\n");
+ goto out_garbage; /* bad verifier, retry */
+ }
+- len = p - (u32 *)iov->iov_base - 1;
++ len = p - (__be32 *)iov->iov_base - 1;
+ if (len < 0)
+ goto out_overflow;
+ switch ((n = ntohl(*p++))) {
+@@ -1310,12 +1359,12 @@ out_overflow:
+ goto out_garbage;
+ }
+
+-static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)
++static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj)
+ {
+ return 0;
+ }
+
+-static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj)
++static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj)
+ {
+ return 0;
+ }
+diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
+index 623180f..e52afab 100644
+--- a/net/sunrpc/pmap_clnt.c
++++ b/net/sunrpc/pmap_clnt.c
+@@ -1,7 +1,9 @@
+ /*
+- * linux/net/sunrpc/pmap.c
++ * linux/net/sunrpc/pmap_clnt.c
+ *
+- * Portmapper client.
++ * In-kernel RPC portmapper client.
++ *
++ * Portmapper supports version 2 of the rpcbind protocol (RFC 1833).
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir at monad.swb.de>
+ */
+@@ -13,7 +15,6 @@
+ #include <linux/uio.h>
+ #include <linux/in.h>
+ #include <linux/sunrpc/clnt.h>
+-#include <linux/sunrpc/xprt.h>
+ #include <linux/sunrpc/sched.h>
+
+ #ifdef RPC_DEBUG
+@@ -24,80 +25,141 @@
+ #define PMAP_UNSET 2
+ #define PMAP_GETPORT 3
+
++struct portmap_args {
++ u32 pm_prog;
++ u32 pm_vers;
++ u32 pm_prot;
++ unsigned short pm_port;
++ struct rpc_xprt * pm_xprt;
++};
++
+ static struct rpc_procinfo pmap_procedures[];
+ static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int, int);
+-static void pmap_getport_done(struct rpc_task *);
++static void pmap_getport_done(struct rpc_task *, void *);
+ static struct rpc_program pmap_program;
+-static DEFINE_SPINLOCK(pmap_lock);
+
+-/*
+- * Obtain the port for a given RPC service on a given host. This one can
+- * be called for an ongoing RPC request.
+- */
+-void
+-rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
++static void pmap_getport_prepare(struct rpc_task *task, void *calldata)
+ {
+- struct rpc_portmap *map = clnt->cl_pmap;
+- struct sockaddr_in *sap = &clnt->cl_xprt->addr;
++ struct portmap_args *map = calldata;
+ struct rpc_message msg = {
+ .rpc_proc = &pmap_procedures[PMAP_GETPORT],
+ .rpc_argp = map,
+- .rpc_resp = &clnt->cl_port,
+- .rpc_cred = NULL
++ .rpc_resp = &map->pm_port,
+ };
++
++ rpc_call_setup(task, &msg, 0);
++}
++
++static inline struct portmap_args *pmap_map_alloc(void)
++{
++ return kmalloc(sizeof(struct portmap_args), GFP_NOFS);
++}
++
++static inline void pmap_map_free(struct portmap_args *map)
++{
++ kfree(map);
++}
++
++static void pmap_map_release(void *data)
++{
++ pmap_map_free(data);
++}
++
++static const struct rpc_call_ops pmap_getport_ops = {
++ .rpc_call_prepare = pmap_getport_prepare,
++ .rpc_call_done = pmap_getport_done,
++ .rpc_release = pmap_map_release,
++};
++
++static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt, int status)
++{
++ xprt_clear_binding(xprt);
++ rpc_wake_up_status(&xprt->binding, status);
++}
++
++/**
++ * rpc_getport - obtain the port for a given RPC service on a given host
++ * @task: task that is waiting for portmapper request
++ *
++ * This one can be called for an ongoing RPC request, and can be used in
++ * an async (rpciod) context.
++ */
++void rpc_getport(struct rpc_task *task)
++{
++ struct rpc_clnt *clnt = task->tk_client;
++ struct rpc_xprt *xprt = task->tk_xprt;
++ struct sockaddr_in addr;
++ struct portmap_args *map;
+ struct rpc_clnt *pmap_clnt;
+- struct rpc_task *child;
++ struct rpc_task *child;
++ int status;
+
+- dprintk("RPC: %4d rpc_getport(%s, %d, %d, %d)\n",
++ dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n",
+ task->tk_pid, clnt->cl_server,
+- map->pm_prog, map->pm_vers, map->pm_prot);
++ clnt->cl_prog, clnt->cl_vers, xprt->prot);
+
+ /* Autobind on cloned rpc clients is discouraged */
+ BUG_ON(clnt->cl_parent != clnt);
+
+- spin_lock(&pmap_lock);
+- if (map->pm_binding) {
+- rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL);
+- spin_unlock(&pmap_lock);
+- return;
+- }
+- map->pm_binding = 1;
+- spin_unlock(&pmap_lock);
+-
+- pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot, 0);
+- if (IS_ERR(pmap_clnt)) {
+- task->tk_status = PTR_ERR(pmap_clnt);
++ /* Put self on queue before sending rpcbind request, in case
++ * pmap_getport_done completes before we return from rpc_run_task */
++ rpc_sleep_on(&xprt->binding, task, NULL, NULL);
++
++ status = -EACCES; /* tell caller to check again */
++ if (xprt_test_and_set_binding(xprt))
++ goto bailout_nofree;
++
++ /* Someone else may have bound if we slept */
++ status = 0;
++ if (xprt_bound(xprt))
++ goto bailout_nofree;
++
++ status = -ENOMEM;
++ map = pmap_map_alloc();
++ if (!map)
++ goto bailout_nofree;
++ map->pm_prog = clnt->cl_prog;
++ map->pm_vers = clnt->cl_vers;
++ map->pm_prot = xprt->prot;
++ map->pm_port = 0;
++ map->pm_xprt = xprt_get(xprt);
++
++ rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr));
++ pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0);
++ status = PTR_ERR(pmap_clnt);
++ if (IS_ERR(pmap_clnt))
+ goto bailout;
+- }
+- task->tk_status = 0;
+
+- /*
+- * Note: rpc_new_child will release client after a failure.
+- */
+- if (!(child = rpc_new_child(pmap_clnt, task)))
++ status = -EIO;
++ child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
++ if (IS_ERR(child))
+ goto bailout;
++ rpc_release_task(child);
+
+- /* Setup the call info struct */
+- rpc_call_setup(child, &msg, 0);
+-
+- /* ... and run the child task */
+ task->tk_xprt->stat.bind_count++;
+- rpc_run_child(task, child, pmap_getport_done);
+ return;
+
+ bailout:
+- spin_lock(&pmap_lock);
+- map->pm_binding = 0;
+- rpc_wake_up(&map->pm_bindwait);
+- spin_unlock(&pmap_lock);
+- rpc_exit(task, -EIO);
++ pmap_map_free(map);
++ xprt_put(xprt);
++bailout_nofree:
++ task->tk_status = status;
++ pmap_wake_portmap_waiters(xprt, status);
+ }
+
+ #ifdef CONFIG_ROOT_NFS
+-int
+-rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
++/**
++ * rpc_getport_external - obtain the port for a given RPC service on a given host
++ * @sin: address of remote peer
++ * @prog: RPC program number to bind
++ * @vers: RPC version number to bind
++ * @prot: transport protocol to use to make this request
++ *
++ * This one is called from outside the RPC client in a synchronous task context.
++ */
++int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
+ {
+- struct rpc_portmap map = {
++ struct portmap_args map = {
+ .pm_prog = prog,
+ .pm_vers = vers,
+ .pm_prot = prot,
+@@ -112,7 +174,7 @@ rpc_getport_external(struct sockaddr_in
+ char hostname[32];
+ int status;
+
+- dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n",
++ dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
+ NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+
+ sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
+@@ -132,45 +194,53 @@ rpc_getport_external(struct sockaddr_in
+ }
+ #endif
+
+-static void
+-pmap_getport_done(struct rpc_task *task)
++/*
++ * Portmapper child task invokes this callback via tk_exit.
++ */
++static void pmap_getport_done(struct rpc_task *child, void *data)
+ {
+- struct rpc_clnt *clnt = task->tk_client;
+- struct rpc_xprt *xprt = task->tk_xprt;
+- struct rpc_portmap *map = clnt->cl_pmap;
+-
+- dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
+- task->tk_pid, task->tk_status, clnt->cl_port);
+-
+- xprt->ops->set_port(xprt, 0);
+- if (task->tk_status < 0) {
+- /* Make the calling task exit with an error */
+- task->tk_action = rpc_exit_task;
+- } else if (clnt->cl_port == 0) {
+- /* Program not registered */
+- rpc_exit(task, -EACCES);
++ struct portmap_args *map = data;
++ struct rpc_xprt *xprt = map->pm_xprt;
++ int status = child->tk_status;
++
++ if (status < 0) {
++ /* Portmapper not available */
++ xprt->ops->set_port(xprt, 0);
++ } else if (map->pm_port == 0) {
++ /* Requested RPC service wasn't registered */
++ xprt->ops->set_port(xprt, 0);
++ status = -EACCES;
+ } else {
+- xprt->ops->set_port(xprt, clnt->cl_port);
+- clnt->cl_port = htons(clnt->cl_port);
++ /* Succeeded */
++ xprt->ops->set_port(xprt, map->pm_port);
++ xprt_set_bound(xprt);
++ status = 0;
+ }
+- spin_lock(&pmap_lock);
+- map->pm_binding = 0;
+- rpc_wake_up(&map->pm_bindwait);
+- spin_unlock(&pmap_lock);
++
++ dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n",
++ child->tk_pid, status, map->pm_port);
++
++ pmap_wake_portmap_waiters(xprt, status);
++ xprt_put(xprt);
+ }
+
+-/*
+- * Set or unset a port registration with the local portmapper.
++/**
++ * rpc_register - set or unset a port registration with the local portmapper
++ * @prog: RPC program number to bind
++ * @vers: RPC version number to bind
++ * @prot: transport protocol to use to make this request
++ * @port: port value to register
++ * @okay: result code
++ *
+ * port == 0 means unregister, port != 0 means register.
+ */
+-int
+-rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
++int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+ {
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+- struct rpc_portmap map = {
++ struct portmap_args map = {
+ .pm_prog = prog,
+ .pm_vers = vers,
+ .pm_prot = prot,
+@@ -184,7 +254,7 @@ rpc_register(u32 prog, u32 vers, int pro
+ struct rpc_clnt *pmap_clnt;
+ int error = 0;
+
+- dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n",
++ dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n",
+ prog, vers, prot, port);
+
+ pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
+@@ -207,38 +277,32 @@ rpc_register(u32 prog, u32 vers, int pro
+ return error;
+ }
+
+-static struct rpc_clnt *
+-pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
++static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
+ {
+- struct rpc_xprt *xprt;
+- struct rpc_clnt *clnt;
+-
+- /* printk("pmap: create xprt\n"); */
+- xprt = xprt_create_proto(proto, srvaddr, NULL);
+- if (IS_ERR(xprt))
+- return (struct rpc_clnt *)xprt;
+- xprt->ops->set_port(xprt, RPC_PMAP_PORT);
++ struct rpc_create_args args = {
++ .protocol = proto,
++ .address = (struct sockaddr *)srvaddr,
++ .addrsize = sizeof(*srvaddr),
++ .servername = hostname,
++ .program = &pmap_program,
++ .version = RPC_PMAP_VERSION,
++ .authflavor = RPC_AUTH_UNIX,
++ .flags = (RPC_CLNT_CREATE_ONESHOT |
++ RPC_CLNT_CREATE_NOPING),
++ };
++
++ srvaddr->sin_port = htons(RPC_PMAP_PORT);
+ if (!privileged)
+- xprt->resvport = 0;
+-
+- /* printk("pmap: create clnt\n"); */
+- clnt = rpc_new_client(xprt, hostname,
+- &pmap_program, RPC_PMAP_VERSION,
+- RPC_AUTH_UNIX);
+- if (!IS_ERR(clnt)) {
+- clnt->cl_softrtry = 1;
+- clnt->cl_oneshot = 1;
+- }
+- return clnt;
++ args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
++ return rpc_create(&args);
+ }
+
+ /*
+ * XDR encode/decode functions for PMAP
+ */
+-static int
+-xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map)
++static int xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct portmap_args *map)
+ {
+- dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)\n",
++ dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n",
+ map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port);
+ *p++ = htonl(map->pm_prog);
+ *p++ = htonl(map->pm_vers);
+@@ -249,15 +313,13 @@ xdr_encode_mapping(struct rpc_rqst *req,
+ return 0;
+ }
+
+-static int
+-xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
++static int xdr_decode_port(struct rpc_rqst *req, __be32 *p, unsigned short *portp)
+ {
+ *portp = (unsigned short) ntohl(*p++);
+ return 0;
+ }
+
+-static int
+-xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
++static int xdr_decode_bool(struct rpc_rqst *req, __be32 *p, unsigned int *boolp)
+ {
+ *boolp = (unsigned int) ntohl(*p++);
+ return 0;
+diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
+index 0b1a1ac..9a0b41a 100644
+--- a/net/sunrpc/rpc_pipe.c
++++ b/net/sunrpc/rpc_pipe.c
+@@ -327,10 +327,8 @@ rpc_show_info(struct seq_file *m, void *
+ seq_printf(m, "RPC server: %s\n", clnt->cl_server);
+ seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
+ clnt->cl_prog, clnt->cl_vers);
+- seq_printf(m, "address: %u.%u.%u.%u\n",
+- NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr));
+- seq_printf(m, "protocol: %s\n",
+- clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
++ seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
++ seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
+ return 0;
+ }
+
+@@ -490,14 +488,13 @@ rpc_get_inode(struct super_block *sb, in
+ return NULL;
+ inode->i_mode = mode;
+ inode->i_uid = inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch(mode & S_IFMT) {
+ case S_IFDIR:
+ inode->i_fop = &simple_dir_operations;
+ inode->i_op = &simple_dir_inode_operations;
+- inode->i_nlink++;
++ inc_nlink(inode);
+ default:
+ break;
+ }
+@@ -574,7 +571,7 @@ rpc_populate(struct dentry *parent,
+ if (private)
+ rpc_inode_setowner(inode, private);
+ if (S_ISDIR(mode))
+- dir->i_nlink++;
++ inc_nlink(dir);
+ d_add(dentry, inode);
+ }
+ mutex_unlock(&dir->i_mutex);
+@@ -596,7 +593,7 @@ __rpc_mkdir(struct inode *dir, struct de
+ goto out_err;
+ inode->i_ino = iunique(dir->i_sb, 100);
+ d_instantiate(dentry, inode);
+- dir->i_nlink++;
++ inc_nlink(dir);
+ inode_dir_notify(dir, DN_CREATE);
+ return 0;
+ out_err:
+@@ -623,17 +620,13 @@ __rpc_rmdir(struct inode *dir, struct de
+ }
+
+ static struct dentry *
+-rpc_lookup_negative(char *path, struct nameidata *nd)
++rpc_lookup_create(struct dentry *parent, const char *name, int len)
+ {
++ struct inode *dir = parent->d_inode;
+ struct dentry *dentry;
+- struct inode *dir;
+- int error;
+
+- if ((error = rpc_lookup_parent(path, nd)) != 0)
+- return ERR_PTR(error);
+- dir = nd->dentry->d_inode;
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+- dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
++ dentry = lookup_one_len(name, parent, len);
+ if (IS_ERR(dentry))
+ goto out_err;
+ if (dentry->d_inode) {
+@@ -644,7 +637,20 @@ rpc_lookup_negative(char *path, struct n
+ return dentry;
+ out_err:
+ mutex_unlock(&dir->i_mutex);
+- rpc_release_path(nd);
++ return dentry;
++}
++
++static struct dentry *
++rpc_lookup_negative(char *path, struct nameidata *nd)
++{
++ struct dentry *dentry;
++ int error;
++
++ if ((error = rpc_lookup_parent(path, nd)) != 0)
++ return ERR_PTR(error);
++ dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len);
++ if (IS_ERR(dentry))
++ rpc_release_path(nd);
+ return dentry;
+ }
+
+@@ -703,18 +709,17 @@ rpc_rmdir(struct dentry *dentry)
+ }
+
+ struct dentry *
+-rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
++rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags)
+ {
+- struct nameidata nd;
+ struct dentry *dentry;
+ struct inode *dir, *inode;
+ struct rpc_inode *rpci;
+
+- dentry = rpc_lookup_negative(path, &nd);
++ dentry = rpc_lookup_create(parent, name, strlen(name));
+ if (IS_ERR(dentry))
+ return dentry;
+- dir = nd.dentry->d_inode;
+- inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR);
++ dir = parent->d_inode;
++ inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR);
+ if (!inode)
+ goto err_dput;
+ inode->i_ino = iunique(dir->i_sb, 100);
+@@ -728,13 +733,13 @@ rpc_mkpipe(char *path, void *private, st
+ dget(dentry);
+ out:
+ mutex_unlock(&dir->i_mutex);
+- rpc_release_path(&nd);
+ return dentry;
+ err_dput:
+ dput(dentry);
+ dentry = ERR_PTR(-ENOMEM);
+- printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n",
+- __FILE__, __FUNCTION__, path, -ENOMEM);
++ printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
++ __FILE__, __FUNCTION__, parent->d_name.name, name,
++ -ENOMEM);
+ goto out;
+ }
+
+@@ -852,7 +857,6 @@ int register_rpc_pipefs(void)
+
+ void unregister_rpc_pipefs(void)
+ {
+- if (kmem_cache_destroy(rpc_inode_cachep))
+- printk(KERN_WARNING "RPC: unable to free inode cache\n");
++ kmem_cache_destroy(rpc_inode_cachep);
+ unregister_filesystem(&rpc_pipe_fs_type);
+ }
+diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
+index 5c3eee7..a1ab4ee 100644
+--- a/net/sunrpc/sched.c
++++ b/net/sunrpc/sched.c
+@@ -21,7 +21,6 @@
+ #include <linux/mutex.h>
+
+ #include <linux/sunrpc/clnt.h>
+-#include <linux/sunrpc/xprt.h>
+
+ #ifdef RPC_DEBUG
+ #define RPCDBG_FACILITY RPCDBG_SCHED
+@@ -45,12 +44,6 @@ static void rpciod_killall(void);
+ static void rpc_async_schedule(void *);
+
+ /*
+- * RPC tasks that create another task (e.g. for contacting the portmapper)
+- * will wait on this queue for their child's completion
+- */
+-static RPC_WAITQ(childq, "childq");
+-
+-/*
+ * RPC tasks sit here while waiting for conditions to improve.
+ */
+ static RPC_WAITQ(delay_queue, "delayq");
+@@ -324,16 +317,6 @@ static void rpc_make_runnable(struct rpc
+ }
+
+ /*
+- * Place a newly initialized task on the workqueue.
+- */
+-static inline void
+-rpc_schedule_run(struct rpc_task *task)
+-{
+- rpc_set_active(task);
+- rpc_make_runnable(task);
+-}
+-
+-/*
+ * Prepare for sleeping on a wait queue.
+ * By always appending tasks to the list we ensure FIFO behavior.
+ * NB: An RPC task will only receive interrupt-driven events as long
+@@ -559,24 +542,20 @@ void rpc_wake_up_status(struct rpc_wait_
+ spin_unlock_bh(&queue->lock);
+ }
+
++static void __rpc_atrun(struct rpc_task *task)
++{
++ rpc_wake_up_task(task);
++}
++
+ /*
+ * Run a task at a later time
+ */
+-static void __rpc_atrun(struct rpc_task *);
+-void
+-rpc_delay(struct rpc_task *task, unsigned long delay)
++void rpc_delay(struct rpc_task *task, unsigned long delay)
+ {
+ task->tk_timeout = delay;
+ rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun);
+ }
+
+-static void
+-__rpc_atrun(struct rpc_task *task)
+-{
+- task->tk_status = 0;
+- rpc_wake_up_task(task);
+-}
+-
+ /*
+ * Helper to call task->tk_ops->rpc_call_prepare
+ */
+@@ -933,72 +912,6 @@ struct rpc_task *rpc_run_task(struct rpc
+ }
+ EXPORT_SYMBOL(rpc_run_task);
+
+-/**
+- * rpc_find_parent - find the parent of a child task.
+- * @child: child task
+- * @parent: parent task
+- *
+- * Checks that the parent task is still sleeping on the
+- * queue 'childq'. If so returns a pointer to the parent.
+- * Upon failure returns NULL.
+- *
+- * Caller must hold childq.lock
+- */
+-static inline struct rpc_task *rpc_find_parent(struct rpc_task *child, struct rpc_task *parent)
+-{
+- struct rpc_task *task;
+- struct list_head *le;
+-
+- task_for_each(task, le, &childq.tasks[0])
+- if (task == parent)
+- return parent;
+-
+- return NULL;
+-}
+-
+-static void rpc_child_exit(struct rpc_task *child, void *calldata)
+-{
+- struct rpc_task *parent;
+-
+- spin_lock_bh(&childq.lock);
+- if ((parent = rpc_find_parent(child, calldata)) != NULL) {
+- parent->tk_status = child->tk_status;
+- __rpc_wake_up_task(parent);
+- }
+- spin_unlock_bh(&childq.lock);
+-}
+-
+-static const struct rpc_call_ops rpc_child_ops = {
+- .rpc_call_done = rpc_child_exit,
+-};
+-
+-/*
+- * Note: rpc_new_task releases the client after a failure.
+- */
+-struct rpc_task *
+-rpc_new_child(struct rpc_clnt *clnt, struct rpc_task *parent)
+-{
+- struct rpc_task *task;
+-
+- task = rpc_new_task(clnt, RPC_TASK_ASYNC | RPC_TASK_CHILD, &rpc_child_ops, parent);
+- if (!task)
+- goto fail;
+- return task;
+-
+-fail:
+- parent->tk_status = -ENOMEM;
+- return NULL;
+-}
+-
+-void rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
+-{
+- spin_lock_bh(&childq.lock);
+- /* N.B. Is it possible for the child to have already finished? */
+- __rpc_sleep_on(&childq, task, func, NULL);
+- rpc_schedule_run(child);
+- spin_unlock_bh(&childq.lock);
+-}
+-
+ /*
+ * Kill all tasks for the given client.
+ * XXX: kill their descendants as well?
+@@ -1146,10 +1059,10 @@ rpc_destroy_mempool(void)
+ mempool_destroy(rpc_buffer_mempool);
+ if (rpc_task_mempool)
+ mempool_destroy(rpc_task_mempool);
+- if (rpc_task_slabp && kmem_cache_destroy(rpc_task_slabp))
+- printk(KERN_INFO "rpc_task: not all structures were freed\n");
+- if (rpc_buffer_slabp && kmem_cache_destroy(rpc_buffer_slabp))
+- printk(KERN_INFO "rpc_buffers: not all structures were freed\n");
++ if (rpc_task_slabp)
++ kmem_cache_destroy(rpc_task_slabp);
++ if (rpc_buffer_slabp)
++ kmem_cache_destroy(rpc_buffer_slabp);
+ }
+
+ int
+diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
+index eb330d4..6f17527 100644
+--- a/net/sunrpc/socklib.c
++++ b/net/sunrpc/socklib.c
+@@ -168,7 +168,7 @@ int csum_partial_copy_to_xdr(struct xdr_
+ return -1;
+ if ((unsigned short)csum_fold(desc.csum))
+ return -1;
+- if (unlikely(skb->ip_summed == CHECKSUM_HW))
++ if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
+ netdev_rx_csum_fault(skb->dev);
+ return 0;
+ no_checksum:
+diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
+index f38f939..192dff5 100644
+--- a/net/sunrpc/sunrpc_syms.c
++++ b/net/sunrpc/sunrpc_syms.c
+@@ -36,8 +36,6 @@ EXPORT_SYMBOL(rpc_wake_up_status);
+ 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);
+@@ -57,7 +55,6 @@ EXPORT_SYMBOL(rpc_queue_upcall);
+ EXPORT_SYMBOL(rpc_mkpipe);
+
+ /* Client transport */
+-EXPORT_SYMBOL(xprt_create_proto);
+ EXPORT_SYMBOL(xprt_set_timeout);
+
+ /* Client credential cache */
+@@ -73,6 +70,8 @@ EXPORT_SYMBOL(put_rpccred);
+ /* RPC server stuff */
+ EXPORT_SYMBOL(svc_create);
+ EXPORT_SYMBOL(svc_create_thread);
++EXPORT_SYMBOL(svc_create_pooled);
++EXPORT_SYMBOL(svc_set_num_threads);
+ EXPORT_SYMBOL(svc_exit_thread);
+ EXPORT_SYMBOL(svc_destroy);
+ EXPORT_SYMBOL(svc_drop);
+diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
+index b76a227..eb44ec9 100644
+--- a/net/sunrpc/svc.c
++++ b/net/sunrpc/svc.c
+@@ -4,6 +4,10 @@
+ * High-level RPC service routines
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir at monad.swb.de>
++ *
++ * Multiple threads pools and NUMAisation
++ * Copyright (c) 2006 Silicon Graphics, Inc.
++ * by Greg Banks <gnb at melbourne.sgi.com>
+ */
+
+ #include <linux/linkage.h>
+@@ -12,6 +16,8 @@
+ #include <linux/net.h>
+ #include <linux/in.h>
+ #include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
+
+ #include <linux/sunrpc/types.h>
+ #include <linux/sunrpc/xdr.h>
+@@ -23,14 +29,252 @@
+ #define RPC_PARANOIA 1
+
+ /*
++ * Mode for mapping cpus to pools.
++ */
++enum {
++ SVC_POOL_NONE = -1, /* uninitialised, choose one of the others */
++ SVC_POOL_GLOBAL, /* no mapping, just a single global pool
++ * (legacy & UP mode) */
++ SVC_POOL_PERCPU, /* one pool per cpu */
++ SVC_POOL_PERNODE /* one pool per numa node */
++};
++
++/*
++ * Structure for mapping cpus to pools and vice versa.
++ * Setup once during sunrpc initialisation.
++ */
++static struct svc_pool_map {
++ int mode; /* Note: int not enum to avoid
++ * warnings about "enumeration value
++ * not handled in switch" */
++ unsigned int npools;
++ unsigned int *pool_to; /* maps pool id to cpu or node */
++ unsigned int *to_pool; /* maps cpu or node to pool id */
++} svc_pool_map = {
++ .mode = SVC_POOL_NONE
++};
++
++
++/*
++ * Detect best pool mapping mode heuristically,
++ * according to the machine's topology.
++ */
++static int
++svc_pool_map_choose_mode(void)
++{
++ unsigned int node;
++
++ if (num_online_nodes() > 1) {
++ /*
++ * Actually have multiple NUMA nodes,
++ * so split pools on NUMA node boundaries
++ */
++ return SVC_POOL_PERNODE;
++ }
++
++ node = any_online_node(node_online_map);
++ if (nr_cpus_node(node) > 2) {
++ /*
++ * Non-trivial SMP, or CONFIG_NUMA on
++ * non-NUMA hardware, e.g. with a generic
++ * x86_64 kernel on Xeons. In this case we
++ * want to divide the pools on cpu boundaries.
++ */
++ return SVC_POOL_PERCPU;
++ }
++
++ /* default: one global pool */
++ return SVC_POOL_GLOBAL;
++}
++
++/*
++ * Allocate the to_pool[] and pool_to[] arrays.
++ * Returns 0 on success or an errno.
++ */
++static int
++svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
++{
++ m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
++ if (!m->to_pool)
++ goto fail;
++ m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
++ if (!m->pool_to)
++ goto fail_free;
++
++ return 0;
++
++fail_free:
++ kfree(m->to_pool);
++fail:
++ return -ENOMEM;
++}
++
++/*
++ * Initialise the pool map for SVC_POOL_PERCPU mode.
++ * Returns number of pools or <0 on error.
++ */
++static int
++svc_pool_map_init_percpu(struct svc_pool_map *m)
++{
++ unsigned int maxpools = highest_possible_processor_id()+1;
++ unsigned int pidx = 0;
++ unsigned int cpu;
++ int err;
++
++ err = svc_pool_map_alloc_arrays(m, maxpools);
++ if (err)
++ return err;
++
++ for_each_online_cpu(cpu) {
++ BUG_ON(pidx > maxpools);
++ m->to_pool[cpu] = pidx;
++ m->pool_to[pidx] = cpu;
++ pidx++;
++ }
++ /* cpus brought online later all get mapped to pool0, sorry */
++
++ return pidx;
++};
++
++
++/*
++ * Initialise the pool map for SVC_POOL_PERNODE mode.
++ * Returns number of pools or <0 on error.
++ */
++static int
++svc_pool_map_init_pernode(struct svc_pool_map *m)
++{
++ unsigned int maxpools = highest_possible_node_id()+1;
++ unsigned int pidx = 0;
++ unsigned int node;
++ int err;
++
++ err = svc_pool_map_alloc_arrays(m, maxpools);
++ if (err)
++ return err;
++
++ for_each_node_with_cpus(node) {
++ /* some architectures (e.g. SN2) have cpuless nodes */
++ BUG_ON(pidx > maxpools);
++ m->to_pool[node] = pidx;
++ m->pool_to[pidx] = node;
++ pidx++;
++ }
++ /* nodes brought online later all get mapped to pool0, sorry */
++
++ return pidx;
++}
++
++
++/*
++ * Build the global map of cpus to pools and vice versa.
++ */
++static unsigned int
++svc_pool_map_init(void)
++{
++ struct svc_pool_map *m = &svc_pool_map;
++ int npools = -1;
++
++ if (m->mode != SVC_POOL_NONE)
++ return m->npools;
++
++ m->mode = svc_pool_map_choose_mode();
++
++ switch (m->mode) {
++ case SVC_POOL_PERCPU:
++ npools = svc_pool_map_init_percpu(m);
++ break;
++ case SVC_POOL_PERNODE:
++ npools = svc_pool_map_init_pernode(m);
++ break;
++ }
++
++ if (npools < 0) {
++ /* default, or memory allocation failure */
++ npools = 1;
++ m->mode = SVC_POOL_GLOBAL;
++ }
++ m->npools = npools;
++
++ return m->npools;
++}
++
++/*
++ * Set the current thread's cpus_allowed mask so that it
++ * will only run on cpus in the given pool.
++ *
++ * Returns 1 and fills in oldmask iff a cpumask was applied.
++ */
++static inline int
++svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask)
++{
++ struct svc_pool_map *m = &svc_pool_map;
++ unsigned int node; /* or cpu */
++
++ /*
++ * The caller checks for sv_nrpools > 1, which
++ * implies that we've been initialized and the
++ * map mode is not NONE.
++ */
++ BUG_ON(m->mode == SVC_POOL_NONE);
++
++ switch (m->mode)
++ {
++ default:
++ return 0;
++ case SVC_POOL_PERCPU:
++ node = m->pool_to[pidx];
++ *oldmask = current->cpus_allowed;
++ set_cpus_allowed(current, cpumask_of_cpu(node));
++ return 1;
++ case SVC_POOL_PERNODE:
++ node = m->pool_to[pidx];
++ *oldmask = current->cpus_allowed;
++ set_cpus_allowed(current, node_to_cpumask(node));
++ return 1;
++ }
++}
++
++/*
++ * Use the mapping mode to choose a pool for a given CPU.
++ * Used when enqueueing an incoming RPC. Always returns
++ * a non-NULL pool pointer.
++ */
++struct svc_pool *
++svc_pool_for_cpu(struct svc_serv *serv, int cpu)
++{
++ struct svc_pool_map *m = &svc_pool_map;
++ unsigned int pidx = 0;
++
++ /*
++ * SVC_POOL_NONE happens in a pure client when
++ * lockd is brought up, so silently treat it the
++ * same as SVC_POOL_GLOBAL.
++ */
++
++ switch (m->mode) {
++ case SVC_POOL_PERCPU:
++ pidx = m->to_pool[cpu];
++ break;
++ case SVC_POOL_PERNODE:
++ pidx = m->to_pool[cpu_to_node(cpu)];
++ break;
++ }
++ return &serv->sv_pools[pidx % serv->sv_nrpools];
++}
++
++
++/*
+ * Create an RPC service
+ */
+-struct svc_serv *
+-svc_create(struct svc_program *prog, unsigned int bufsize)
++static struct svc_serv *
++__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
++ void (*shutdown)(struct svc_serv *serv))
+ {
+ struct svc_serv *serv;
+ int vers;
+ unsigned int xdrsize;
++ unsigned int i;
+
+ if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
+ return NULL;
+@@ -38,7 +282,11 @@ svc_create(struct svc_program *prog, uns
+ serv->sv_program = prog;
+ serv->sv_nrthreads = 1;
+ serv->sv_stats = prog->pg_stats;
+- serv->sv_bufsz = bufsize? bufsize : 4096;
++ if (bufsize > RPCSVC_MAXPAYLOAD)
++ bufsize = RPCSVC_MAXPAYLOAD;
++ serv->sv_max_payload = bufsize? bufsize : 4096;
++ serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE);
++ serv->sv_shutdown = shutdown;
+ xdrsize = 0;
+ while (prog) {
+ prog->pg_lovers = prog->pg_nvers-1;
+@@ -53,20 +301,68 @@ svc_create(struct svc_program *prog, uns
+ prog = prog->pg_next;
+ }
+ serv->sv_xdrsize = xdrsize;
+- INIT_LIST_HEAD(&serv->sv_threads);
+- INIT_LIST_HEAD(&serv->sv_sockets);
+ INIT_LIST_HEAD(&serv->sv_tempsocks);
+ INIT_LIST_HEAD(&serv->sv_permsocks);
++ init_timer(&serv->sv_temptimer);
+ spin_lock_init(&serv->sv_lock);
+
++ serv->sv_nrpools = npools;
++ serv->sv_pools =
++ kcalloc(sizeof(struct svc_pool), serv->sv_nrpools,
++ GFP_KERNEL);
++ if (!serv->sv_pools) {
++ kfree(serv);
++ return NULL;
++ }
++
++ for (i = 0; i < serv->sv_nrpools; i++) {
++ struct svc_pool *pool = &serv->sv_pools[i];
++
++ dprintk("initialising pool %u for %s\n",
++ i, serv->sv_name);
++
++ pool->sp_id = i;
++ INIT_LIST_HEAD(&pool->sp_threads);
++ INIT_LIST_HEAD(&pool->sp_sockets);
++ INIT_LIST_HEAD(&pool->sp_all_threads);
++ spin_lock_init(&pool->sp_lock);
++ }
++
++
+ /* Remove any stale portmap registrations */
+ svc_register(serv, 0, 0);
+
+ return serv;
+ }
+
++struct svc_serv *
++svc_create(struct svc_program *prog, unsigned int bufsize,
++ void (*shutdown)(struct svc_serv *serv))
++{
++ return __svc_create(prog, bufsize, /*npools*/1, shutdown);
++}
++
++struct svc_serv *
++svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
++ void (*shutdown)(struct svc_serv *serv),
++ svc_thread_fn func, int sig, struct module *mod)
++{
++ struct svc_serv *serv;
++ unsigned int npools = svc_pool_map_init();
++
++ serv = __svc_create(prog, bufsize, npools, shutdown);
++
++ if (serv != NULL) {
++ serv->sv_function = func;
++ serv->sv_kill_signal = sig;
++ serv->sv_module = mod;
++ }
++
++ return serv;
++}
++
+ /*
+- * Destroy an RPC service
++ * Destroy an RPC service. Should be called with the BKL held
+ */
+ void
+ svc_destroy(struct svc_serv *serv)
+@@ -85,12 +381,17 @@ svc_destroy(struct svc_serv *serv)
+ } else
+ printk("svc_destroy: no threads for serv=%p!\n", serv);
+
++ del_timer_sync(&serv->sv_temptimer);
++
+ while (!list_empty(&serv->sv_tempsocks)) {
+ svsk = list_entry(serv->sv_tempsocks.next,
+ struct svc_sock,
+ sk_list);
+ svc_delete_socket(svsk);
+ }
++ if (serv->sv_shutdown)
++ serv->sv_shutdown(serv);
++
+ while (!list_empty(&serv->sv_permsocks)) {
+ svsk = list_entry(serv->sv_permsocks.next,
+ struct svc_sock,
+@@ -102,6 +403,7 @@ svc_destroy(struct svc_serv *serv)
+
+ /* Unregister service with the portmapper */
+ svc_register(serv, 0, 0);
++ kfree(serv->sv_pools);
+ kfree(serv);
+ }
+
+@@ -115,21 +417,18 @@ svc_init_buffer(struct svc_rqst *rqstp,
+ int pages;
+ int arghi;
+
+- if (size > RPCSVC_MAXPAYLOAD)
+- size = RPCSVC_MAXPAYLOAD;
+- pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE;
+- rqstp->rq_argused = 0;
+- rqstp->rq_resused = 0;
++ pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
++ * We assume one is at most one page
++ */
+ arghi = 0;
+ BUG_ON(pages > RPCSVC_MAXPAGES);
+ while (pages) {
+ struct page *p = alloc_page(GFP_KERNEL);
+ if (!p)
+ break;
+- rqstp->rq_argpages[arghi++] = p;
++ rqstp->rq_pages[arghi++] = p;
+ pages--;
+ }
+- rqstp->rq_arghi = arghi;
+ return ! pages;
+ }
+
+@@ -139,24 +438,25 @@ svc_init_buffer(struct svc_rqst *rqstp,
+ static void
+ svc_release_buffer(struct svc_rqst *rqstp)
+ {
+- while (rqstp->rq_arghi)
+- put_page(rqstp->rq_argpages[--rqstp->rq_arghi]);
+- while (rqstp->rq_resused) {
+- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
+- continue;
+- put_page(rqstp->rq_respages[rqstp->rq_resused]);
+- }
+- rqstp->rq_argused = 0;
++ int i;
++ for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
++ if (rqstp->rq_pages[i])
++ put_page(rqstp->rq_pages[i]);
+ }
+
+ /*
+- * Create a server thread
++ * Create a thread in the given pool. Caller must hold BKL.
++ * On a NUMA or SMP machine, with a multi-pool serv, the thread
++ * will be restricted to run on the cpus belonging to the pool.
+ */
+-int
+-svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
++static int
++__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
++ struct svc_pool *pool)
+ {
+ struct svc_rqst *rqstp;
+ int error = -ENOMEM;
++ int have_oldmask = 0;
++ cpumask_t oldmask;
+
+ rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
+ if (!rqstp)
+@@ -166,12 +466,25 @@ svc_create_thread(svc_thread_fn func, st
+
+ if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
+ || !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
+- || !svc_init_buffer(rqstp, serv->sv_bufsz))
++ || !svc_init_buffer(rqstp, serv->sv_max_mesg))
+ goto out_thread;
+
+ serv->sv_nrthreads++;
++ spin_lock_bh(&pool->sp_lock);
++ pool->sp_nrthreads++;
++ list_add(&rqstp->rq_all, &pool->sp_all_threads);
++ spin_unlock_bh(&pool->sp_lock);
+ rqstp->rq_server = serv;
++ rqstp->rq_pool = pool;
++
++ if (serv->sv_nrpools > 1)
++ have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask);
++
+ error = kernel_thread((int (*)(void *)) func, rqstp, 0);
++
++ if (have_oldmask)
++ set_cpus_allowed(current, oldmask);
++
+ if (error < 0)
+ goto out_thread;
+ svc_sock_update_bufs(serv);
+@@ -185,17 +498,136 @@ out_thread:
+ }
+
+ /*
+- * Destroy an RPC server thread
++ * Create a thread in the default pool. Caller must hold BKL.
++ */
++int
++svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
++{
++ return __svc_create_thread(func, serv, &serv->sv_pools[0]);
++}
++
++/*
++ * Choose a pool in which to create a new thread, for svc_set_num_threads
++ */
++static inline struct svc_pool *
++choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
++{
++ if (pool != NULL)
++ return pool;
++
++ return &serv->sv_pools[(*state)++ % serv->sv_nrpools];
++}
++
++/*
++ * Choose a thread to kill, for svc_set_num_threads
++ */
++static inline struct task_struct *
++choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
++{
++ unsigned int i;
++ struct task_struct *task = NULL;
++
++ if (pool != NULL) {
++ spin_lock_bh(&pool->sp_lock);
++ } else {
++ /* choose a pool in round-robin fashion */
++ for (i = 0; i < serv->sv_nrpools; i++) {
++ pool = &serv->sv_pools[--(*state) % serv->sv_nrpools];
++ spin_lock_bh(&pool->sp_lock);
++ if (!list_empty(&pool->sp_all_threads))
++ goto found_pool;
++ spin_unlock_bh(&pool->sp_lock);
++ }
++ return NULL;
++ }
++
++found_pool:
++ if (!list_empty(&pool->sp_all_threads)) {
++ struct svc_rqst *rqstp;
++
++ /*
++ * Remove from the pool->sp_all_threads list
++ * so we don't try to kill it again.
++ */
++ rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
++ list_del_init(&rqstp->rq_all);
++ task = rqstp->rq_task;
++ }
++ spin_unlock_bh(&pool->sp_lock);
++
++ return task;
++}
++
++/*
++ * Create or destroy enough new threads to make the number
++ * of threads the given number. If `pool' is non-NULL, applies
++ * only to threads in that pool, otherwise round-robins between
++ * all pools. Must be called with a svc_get() reference and
++ * the BKL held.
++ *
++ * Destroying threads relies on the service threads filling in
++ * rqstp->rq_task, which only the nfs ones do. Assumes the serv
++ * has been created using svc_create_pooled().
++ *
++ * Based on code that used to be in nfsd_svc() but tweaked
++ * to be pool-aware.
++ */
++int
++svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
++{
++ struct task_struct *victim;
++ int error = 0;
++ unsigned int state = serv->sv_nrthreads-1;
++
++ if (pool == NULL) {
++ /* The -1 assumes caller has done a svc_get() */
++ nrservs -= (serv->sv_nrthreads-1);
++ } else {
++ spin_lock_bh(&pool->sp_lock);
++ nrservs -= pool->sp_nrthreads;
++ spin_unlock_bh(&pool->sp_lock);
++ }
++
++ /* create new threads */
++ while (nrservs > 0) {
++ nrservs--;
++ __module_get(serv->sv_module);
++ error = __svc_create_thread(serv->sv_function, serv,
++ choose_pool(serv, pool, &state));
++ if (error < 0) {
++ module_put(serv->sv_module);
++ break;
++ }
++ }
++ /* destroy old threads */
++ while (nrservs < 0 &&
++ (victim = choose_victim(serv, pool, &state)) != NULL) {
++ send_sig(serv->sv_kill_signal, victim, 1);
++ nrservs++;
++ }
++
++ return error;
++}
++
++/*
++ * Called from a server thread as it's exiting. Caller must hold BKL.
+ */
+ void
+ svc_exit_thread(struct svc_rqst *rqstp)
+ {
+ struct svc_serv *serv = rqstp->rq_server;
++ struct svc_pool *pool = rqstp->rq_pool;
+
+ svc_release_buffer(rqstp);
+ kfree(rqstp->rq_resp);
+ kfree(rqstp->rq_argp);
+ kfree(rqstp->rq_auth_data);
++
++ spin_lock_bh(&pool->sp_lock);
++ pool->sp_nrthreads--;
++ list_del(&rqstp->rq_all);
++ spin_unlock_bh(&pool->sp_lock);
++
+ kfree(rqstp);
+
+ /* Release the server */
+@@ -215,23 +647,32 @@ svc_register(struct svc_serv *serv, int
+ unsigned long flags;
+ int i, error = 0, dummy;
+
+- progp = serv->sv_program;
+-
+- dprintk("RPC: svc_register(%s, %s, %d)\n",
+- progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
+-
+ if (!port)
+ clear_thread_flag(TIF_SIGPENDING);
+
+- for (i = 0; i < progp->pg_nvers; i++) {
+- if (progp->pg_vers[i] == NULL)
+- continue;
+- error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+- if (error < 0)
+- break;
+- if (port && !dummy) {
+- error = -EACCES;
+- break;
++ for (progp = serv->sv_program; progp; progp = progp->pg_next) {
++ for (i = 0; i < progp->pg_nvers; i++) {
++ if (progp->pg_vers[i] == NULL)
++ continue;
++
++ dprintk("RPC: svc_register(%s, %s, %d, %d)%s\n",
++ progp->pg_name,
++ proto == IPPROTO_UDP? "udp" : "tcp",
++ port,
++ i,
++ progp->pg_vers[i]->vs_hidden?
++ " (but not telling portmap)" : "");
++
++ if (progp->pg_vers[i]->vs_hidden)
++ continue;
++
++ error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
++ if (error < 0)
++ break;
++ if (port && !dummy) {
++ error = -EACCES;
++ break;
++ }
+ }
+ }
+
+@@ -248,19 +689,20 @@ svc_register(struct svc_serv *serv, int
+ * Process the RPC request.
+ */
+ int
+-svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
++svc_process(struct svc_rqst *rqstp)
+ {
+ struct svc_program *progp;
+ struct svc_version *versp = NULL; /* compiler food */
+ struct svc_procedure *procp = NULL;
+ struct kvec * argv = &rqstp->rq_arg.head[0];
+ struct kvec * resv = &rqstp->rq_res.head[0];
++ struct svc_serv *serv = rqstp->rq_server;
+ kxdrproc_t xdr;
+- u32 *statp;
+- u32 dir, prog, vers, proc,
+- auth_stat, rpc_stat;
++ __be32 *statp;
++ u32 dir, prog, vers, proc;
++ __be32 auth_stat, rpc_stat;
+ int auth_res;
+- u32 *accept_statp;
++ __be32 *reply_statp;
+
+ rpc_stat = rpc_success;
+
+@@ -270,10 +712,10 @@ svc_process(struct svc_serv *serv, struc
+ /* setup response xdr_buf.
+ * Initially it has just one page
+ */
+- svc_take_page(rqstp); /* must succeed */
++ rqstp->rq_resused = 1;
+ resv->iov_base = page_address(rqstp->rq_respages[0]);
+ resv->iov_len = 0;
+- rqstp->rq_res.pages = rqstp->rq_respages+1;
++ rqstp->rq_res.pages = rqstp->rq_respages + 1;
+ rqstp->rq_res.len = 0;
+ rqstp->rq_res.page_base = 0;
+ rqstp->rq_res.page_len = 0;
+@@ -284,16 +726,16 @@ svc_process(struct svc_serv *serv, struc
+ rqstp->rq_sendfile_ok = 1;
+ /* tcp needs a space for the record length... */
+ if (rqstp->rq_prot == IPPROTO_TCP)
+- svc_putu32(resv, 0);
++ svc_putnl(resv, 0);
+
+ rqstp->rq_xid = svc_getu32(argv);
+ svc_putu32(resv, rqstp->rq_xid);
+
+- dir = ntohl(svc_getu32(argv));
+- vers = ntohl(svc_getu32(argv));
++ dir = svc_getnl(argv);
++ vers = svc_getnl(argv);
+
+ /* First words of reply: */
+- svc_putu32(resv, xdr_one); /* REPLY */
++ svc_putnl(resv, 1); /* REPLY */
+
+ if (dir != 0) /* direction != CALL */
+ goto err_bad_dir;
+@@ -301,13 +743,13 @@ svc_process(struct svc_serv *serv, struc
+ goto err_bad_rpc;
+
+ /* Save position in case we later decide to reject: */
+- accept_statp = resv->iov_base + resv->iov_len;
++ reply_statp = resv->iov_base + resv->iov_len;
+
+- svc_putu32(resv, xdr_zero); /* ACCEPT */
++ svc_putnl(resv, 0); /* ACCEPT */
+
+- rqstp->rq_prog = prog = ntohl(svc_getu32(argv)); /* program number */
+- rqstp->rq_vers = vers = ntohl(svc_getu32(argv)); /* version number */
+- rqstp->rq_proc = proc = ntohl(svc_getu32(argv)); /* procedure number */
++ rqstp->rq_prog = prog = svc_getnl(argv); /* program number */
++ rqstp->rq_vers = vers = svc_getnl(argv); /* version number */
++ rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */
+
+ progp = serv->sv_program;
+
+@@ -361,7 +803,7 @@ svc_process(struct svc_serv *serv, struc
+
+ /* Build the reply header. */
+ statp = resv->iov_base +resv->iov_len;
+- svc_putu32(resv, rpc_success); /* RPC_SUCCESS */
++ svc_putnl(resv, RPC_SUCCESS);
+
+ /* Bump per-procedure stats counter */
+ procp->pc_count++;
+@@ -386,6 +828,11 @@ svc_process(struct svc_serv *serv, struc
+ *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+
+ /* Encode reply */
++ if (*statp == rpc_drop_reply) {
++ if (procp->pc_release)
++ procp->pc_release(rqstp, NULL, rqstp->rq_resp);
++ goto dropit;
++ }
+ if (*statp == rpc_success && (xdr = procp->pc_encode)
+ && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
+ dprintk("svc: failed to encode reply\n");
+@@ -439,26 +886,26 @@ err_bad_dir:
+
+ err_bad_rpc:
+ serv->sv_stats->rpcbadfmt++;
+- svc_putu32(resv, xdr_one); /* REJECT */
+- svc_putu32(resv, xdr_zero); /* RPC_MISMATCH */
+- svc_putu32(resv, xdr_two); /* Only RPCv2 supported */
+- svc_putu32(resv, xdr_two);
++ svc_putnl(resv, 1); /* REJECT */
++ svc_putnl(resv, 0); /* RPC_MISMATCH */
++ svc_putnl(resv, 2); /* Only RPCv2 supported */
++ svc_putnl(resv, 2);
+ goto sendit;
+
+ err_bad_auth:
+ dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
+ serv->sv_stats->rpcbadauth++;
+ /* Restore write pointer to location of accept status: */
+- xdr_ressize_check(rqstp, accept_statp);
+- svc_putu32(resv, xdr_one); /* REJECT */
+- svc_putu32(resv, xdr_one); /* AUTH_ERROR */
+- svc_putu32(resv, auth_stat); /* status */
++ xdr_ressize_check(rqstp, reply_statp);
++ svc_putnl(resv, 1); /* REJECT */
++ svc_putnl(resv, 1); /* AUTH_ERROR */
++ svc_putnl(resv, ntohl(auth_stat)); /* status */
+ goto sendit;
+
+ err_bad_prog:
+ dprintk("svc: unknown program %d\n", prog);
+ serv->sv_stats->rpcbadfmt++;
+- svc_putu32(resv, rpc_prog_unavail);
++ svc_putnl(resv, RPC_PROG_UNAVAIL);
+ goto sendit;
+
+ err_bad_vers:
+@@ -466,9 +913,9 @@ err_bad_vers:
+ printk("svc: unknown version (%d)\n", vers);
+ #endif
+ serv->sv_stats->rpcbadfmt++;
+- svc_putu32(resv, rpc_prog_mismatch);
+- svc_putu32(resv, htonl(progp->pg_lovers));
+- svc_putu32(resv, htonl(progp->pg_hivers));
++ svc_putnl(resv, RPC_PROG_MISMATCH);
++ svc_putnl(resv, progp->pg_lovers);
++ svc_putnl(resv, progp->pg_hivers);
+ goto sendit;
+
+ err_bad_proc:
+@@ -476,7 +923,7 @@ err_bad_proc:
+ printk("svc: unknown procedure (%d)\n", proc);
+ #endif
+ serv->sv_stats->rpcbadfmt++;
+- svc_putu32(resv, rpc_proc_unavail);
++ svc_putnl(resv, RPC_PROC_UNAVAIL);
+ goto sendit;
+
+ err_garbage:
+@@ -486,6 +933,21 @@ err_garbage:
+ rpc_stat = rpc_garbage_args;
+ err_bad:
+ serv->sv_stats->rpcbadfmt++;
+- svc_putu32(resv, rpc_stat);
++ svc_putnl(resv, ntohl(rpc_stat));
+ goto sendit;
+ }
++
++/*
++ * Return (transport-specific) limit on the rpc payload.
++ */
++u32 svc_max_payload(const struct svc_rqst *rqstp)
++{
++ int max = RPCSVC_MAXPAYLOAD_TCP;
++
++ if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
++ max = RPCSVC_MAXPAYLOAD_UDP;
++ if (rqstp->rq_server->sv_max_payload < max)
++ max = rqstp->rq_server->sv_max_payload;
++ return max;
++}
++EXPORT_SYMBOL_GPL(svc_max_payload);
+diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
+index 5b28c61..ee9bb15 100644
+--- a/net/sunrpc/svcauth.c
++++ b/net/sunrpc/svcauth.c
+@@ -35,14 +35,14 @@ static struct auth_ops *authtab[RPC_AUTH
+ };
+
+ int
+-svc_authenticate(struct svc_rqst *rqstp, u32 *authp)
++svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
+ {
+ rpc_authflavor_t flavor;
+ struct auth_ops *aops;
+
+ *authp = rpc_auth_ok;
+
+- flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0]));
++ flavor = svc_getnl(&rqstp->rq_arg.head[0]);
+
+ dprintk("svc: svc_authenticate (%d)\n", flavor);
+
+@@ -126,6 +126,7 @@ void auth_domain_put(struct auth_domain
+ if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
+ hlist_del(&dom->hash);
+ dom->flavour->domain_release(dom);
++ spin_unlock(&auth_domain_lock);
+ }
+ }
+
+@@ -147,10 +148,8 @@ auth_domain_lookup(char *name, struct au
+ return hp;
+ }
+ }
+- if (new) {
++ if (new)
+ hlist_add_head(&new->hash, head);
+- kref_get(&new->ref);
+- }
+ spin_unlock(&auth_domain_lock);
+ return new;
+ }
+diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
+index 7e5707e..e1bd933 100644
+--- a/net/sunrpc/svcauth_unix.c
++++ b/net/sunrpc/svcauth_unix.c
+@@ -9,6 +9,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/hash.h>
+ #include <linux/string.h>
++#include <net/sock.h>
+
+ #define RPCDBG_FACILITY RPCDBG_AUTH
+
+@@ -145,7 +146,7 @@ static void ip_map_request(struct cache_
+ {
+ char text_addr[20];
+ struct ip_map *im = container_of(h, struct ip_map, h);
+- __u32 addr = im->m_addr.s_addr;
++ __be32 addr = im->m_addr.s_addr;
+
+ snprintf(text_addr, 20, "%u.%u.%u.%u",
+ ntohl(addr) >> 24 & 0xff,
+@@ -249,10 +250,10 @@ static int ip_map_show(struct seq_file *
+
+ seq_printf(m, "%s %d.%d.%d.%d %s\n",
+ im->m_class,
+- htonl(addr.s_addr) >> 24 & 0xff,
+- htonl(addr.s_addr) >> 16 & 0xff,
+- htonl(addr.s_addr) >> 8 & 0xff,
+- htonl(addr.s_addr) >> 0 & 0xff,
++ ntohl(addr.s_addr) >> 24 & 0xff,
++ ntohl(addr.s_addr) >> 16 & 0xff,
++ ntohl(addr.s_addr) >> 8 & 0xff,
++ ntohl(addr.s_addr) >> 0 & 0xff,
+ dom
+ );
+ return 0;
+@@ -348,12 +349,9 @@ int auth_unix_forget_old(struct auth_dom
+
+ struct auth_domain *auth_unix_lookup(struct in_addr addr)
+ {
+- struct ip_map key, *ipm;
++ struct ip_map *ipm;
+ struct auth_domain *rv;
+
+- strcpy(key.m_class, "nfsd");
+- key.m_addr = addr;
+-
+ ipm = ip_map_lookup("nfsd", addr);
+
+ if (!ipm)
+@@ -378,6 +376,44 @@ void svcauth_unix_purge(void)
+ cache_purge(&ip_map_cache);
+ }
+
++static inline struct ip_map *
++ip_map_cached_get(struct svc_rqst *rqstp)
++{
++ struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix;
++ if (ipm != NULL) {
++ if (!cache_valid(&ipm->h)) {
++ /*
++ * The entry has been invalidated since it was
++ * remembered, e.g. by a second mount from the
++ * same IP address.
++ */
++ rqstp->rq_sock->sk_info_authunix = NULL;
++ cache_put(&ipm->h, &ip_map_cache);
++ return NULL;
++ }
++ cache_get(&ipm->h);
++ }
++ return ipm;
++}
++
++static inline void
++ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
++{
++ struct svc_sock *svsk = rqstp->rq_sock;
++
++ if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL)
++ svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */
++ else
++ cache_put(&ipm->h, &ip_map_cache);
++}
++
++void
++svcauth_unix_info_release(void *info)
++{
++ struct ip_map *ipm = info;
++ cache_put(&ipm->h, &ip_map_cache);
++}
++
+ static int
+ svcauth_unix_set_client(struct svc_rqst *rqstp)
+ {
+@@ -387,8 +423,10 @@ svcauth_unix_set_client(struct svc_rqst
+ if (rqstp->rq_proc == 0)
+ return SVC_OK;
+
+- ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+- rqstp->rq_addr.sin_addr);
++ ipm = ip_map_cached_get(rqstp);
++ if (ipm == NULL)
++ ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
++ rqstp->rq_addr.sin_addr);
+
+ if (ipm == NULL)
+ return SVC_DENIED;
+@@ -403,14 +441,14 @@ svcauth_unix_set_client(struct svc_rqst
+ case 0:
+ rqstp->rq_client = &ipm->m_client->h;
+ kref_get(&rqstp->rq_client->ref);
+- cache_put(&ipm->h, &ip_map_cache);
++ ip_map_cached_put(rqstp, ipm);
+ break;
+ }
+ return SVC_OK;
+ }
+
+ static int
+-svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
++svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
+ {
+ struct kvec *argv = &rqstp->rq_arg.head[0];
+ struct kvec *resv = &rqstp->rq_res.head[0];
+@@ -427,7 +465,7 @@ svcauth_null_accept(struct svc_rqst *rqs
+ *authp = rpc_autherr_badcred;
+ return SVC_DENIED;
+ }
+- if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
++ if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
+ dprintk("svc: bad null verf\n");
+ *authp = rpc_autherr_badverf;
+ return SVC_DENIED;
+@@ -441,8 +479,8 @@ svcauth_null_accept(struct svc_rqst *rqs
+ return SVC_DROP; /* kmalloc failure - client must retry */
+
+ /* Put NULL verifier */
+- svc_putu32(resv, RPC_AUTH_NULL);
+- svc_putu32(resv, 0);
++ svc_putnl(resv, RPC_AUTH_NULL);
++ svc_putnl(resv, 0);
+
+ return SVC_OK;
+ }
+@@ -472,7 +510,7 @@ struct auth_ops svcauth_null = {
+
+
+ static int
+-svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
++svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
+ {
+ struct kvec *argv = &rqstp->rq_arg.head[0];
+ struct kvec *resv = &rqstp->rq_res.head[0];
+@@ -488,31 +526,31 @@ svcauth_unix_accept(struct svc_rqst *rqs
+
+ svc_getu32(argv); /* length */
+ svc_getu32(argv); /* time stamp */
+- slen = XDR_QUADLEN(ntohl(svc_getu32(argv))); /* machname length */
++ slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */
+ if (slen > 64 || (len -= (slen + 3)*4) < 0)
+ goto badcred;
+- argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */
++ argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */
+ argv->iov_len -= slen*4;
+
+- cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */
+- cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */
+- slen = ntohl(svc_getu32(argv)); /* gids length */
++ cred->cr_uid = svc_getnl(argv); /* uid */
++ cred->cr_gid = svc_getnl(argv); /* gid */
++ slen = svc_getnl(argv); /* gids length */
+ if (slen > 16 || (len -= (slen + 2)*4) < 0)
+ goto badcred;
+ cred->cr_group_info = groups_alloc(slen);
+ if (cred->cr_group_info == NULL)
+ return SVC_DROP;
+ for (i = 0; i < slen; i++)
+- GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
++ GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
+
+- if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
++ if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
+ *authp = rpc_autherr_badverf;
+ return SVC_DENIED;
+ }
+
+ /* Put NULL verifier */
+- svc_putu32(resv, RPC_AUTH_NULL);
+- svc_putu32(resv, 0);
++ svc_putnl(resv, RPC_AUTH_NULL);
++ svc_putnl(resv, 0);
+
+ return SVC_OK;
+
+diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
+index d9a9573..64ca1f6 100644
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -31,6 +31,7 @@
+ #include <linux/slab.h>
+ #include <linux/netdevice.h>
+ #include <linux/skbuff.h>
++#include <linux/file.h>
+ #include <net/sock.h>
+ #include <net/checksum.h>
+ #include <net/ip.h>
+@@ -45,13 +46,16 @@
+
+ /* SMP locking strategy:
+ *
+- * svc_serv->sv_lock protects most stuff for that service.
++ * svc_pool->sp_lock protects most of the fields of that pool.
++ * svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
++ * when both need to be taken (rare), svc_serv->sv_lock is first.
++ * BKL protects svc_serv->sv_nrthread.
++ * svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list
++ * svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
+ *
+ * Some flags can be set to certain values at any time
+ * providing that certain rules are followed:
+ *
+- * SK_BUSY can be set to 0 at any time.
+- * svc_sock_enqueue must be called afterwards
+ * SK_CONN, SK_DATA, can be set or cleared at any time.
+ * after a set, svc_sock_enqueue must be called.
+ * after a clear, the socket must be read/accepted
+@@ -73,23 +77,30 @@ static struct svc_deferred_req *svc_defe
+ static int svc_deferred_recv(struct svc_rqst *rqstp);
+ static struct cache_deferred_req *svc_defer(struct cache_req *req);
+
++/* apparently the "standard" is that clients close
++ * idle connections after 5 minutes, servers after
++ * 6 minutes
++ * http://www.connectathon.org/talks96/nfstcp.pdf
++ */
++static int svc_conn_age_period = 6*60;
++
+ /*
+- * Queue up an idle server thread. Must have serv->sv_lock held.
++ * Queue up an idle server thread. Must have pool->sp_lock held.
+ * Note: this is really a stack rather than a queue, so that we only
+- * use as many different threads as we need, and the rest don't polute
++ * use as many different threads as we need, and the rest don't pollute
+ * the cache.
+ */
+ static inline void
+-svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp)
++svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
+ {
+- list_add(&rqstp->rq_list, &serv->sv_threads);
++ list_add(&rqstp->rq_list, &pool->sp_threads);
+ }
+
+ /*
+- * Dequeue an nfsd thread. Must have serv->sv_lock held.
++ * Dequeue an nfsd thread. Must have pool->sp_lock held.
+ */
+ static inline void
+-svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp)
++svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
+ {
+ list_del(&rqstp->rq_list);
+ }
+@@ -140,7 +151,9 @@ static void
+ svc_sock_enqueue(struct svc_sock *svsk)
+ {
+ struct svc_serv *serv = svsk->sk_server;
++ struct svc_pool *pool;
+ struct svc_rqst *rqstp;
++ int cpu;
+
+ if (!(svsk->sk_flags &
+ ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))
+@@ -148,10 +161,14 @@ svc_sock_enqueue(struct svc_sock *svsk)
+ if (test_bit(SK_DEAD, &svsk->sk_flags))
+ return;
+
+- spin_lock_bh(&serv->sv_lock);
++ cpu = get_cpu();
++ pool = svc_pool_for_cpu(svsk->sk_server, cpu);
++ put_cpu();
++
++ spin_lock_bh(&pool->sp_lock);
+
+- if (!list_empty(&serv->sv_threads) &&
+- !list_empty(&serv->sv_sockets))
++ if (!list_empty(&pool->sp_threads) &&
++ !list_empty(&pool->sp_sockets))
+ printk(KERN_ERR
+ "svc_sock_enqueue: threads and sockets both waiting??\n");
+
+@@ -161,73 +178,79 @@ svc_sock_enqueue(struct svc_sock *svsk)
+ goto out_unlock;
+ }
+
+- if (test_bit(SK_BUSY, &svsk->sk_flags)) {
+- /* Don't enqueue socket while daemon is receiving */
++ /* Mark socket as busy. It will remain in this state until the
++ * server has processed all pending data and put the socket back
++ * on the idle list. We update SK_BUSY atomically because
++ * it also guards against trying to enqueue the svc_sock twice.
++ */
++ if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) {
++ /* Don't enqueue socket while already enqueued */
+ dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
+ goto out_unlock;
+ }
++ BUG_ON(svsk->sk_pool != NULL);
++ svsk->sk_pool = pool;
+
+ set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+- if (((svsk->sk_reserved + serv->sv_bufsz)*2
++ if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2
+ > svc_sock_wspace(svsk))
+ && !test_bit(SK_CLOSE, &svsk->sk_flags)
+ && !test_bit(SK_CONN, &svsk->sk_flags)) {
+ /* Don't enqueue while not enough space for reply */
+ dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n",
+- svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
++ svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg,
+ svc_sock_wspace(svsk));
++ svsk->sk_pool = NULL;
++ clear_bit(SK_BUSY, &svsk->sk_flags);
+ goto out_unlock;
+ }
+ clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+
+- /* Mark socket as busy. It will remain in this state until the
+- * server has processed all pending data and put the socket back
+- * on the idle list.
+- */
+- set_bit(SK_BUSY, &svsk->sk_flags);
+
+- if (!list_empty(&serv->sv_threads)) {
+- rqstp = list_entry(serv->sv_threads.next,
++ if (!list_empty(&pool->sp_threads)) {
++ rqstp = list_entry(pool->sp_threads.next,
+ struct svc_rqst,
+ rq_list);
+ dprintk("svc: socket %p served by daemon %p\n",
+ svsk->sk_sk, rqstp);
+- svc_serv_dequeue(serv, rqstp);
++ svc_thread_dequeue(pool, rqstp);
+ if (rqstp->rq_sock)
+ printk(KERN_ERR
+ "svc_sock_enqueue: server %p, rq_sock=%p!\n",
+ rqstp, rqstp->rq_sock);
+ rqstp->rq_sock = svsk;
+- svsk->sk_inuse++;
+- rqstp->rq_reserved = serv->sv_bufsz;
+- svsk->sk_reserved += rqstp->rq_reserved;
++ atomic_inc(&svsk->sk_inuse);
++ rqstp->rq_reserved = serv->sv_max_mesg;
++ atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
++ BUG_ON(svsk->sk_pool != pool);
+ wake_up(&rqstp->rq_wait);
+ } else {
+ dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
+- list_add_tail(&svsk->sk_ready, &serv->sv_sockets);
++ list_add_tail(&svsk->sk_ready, &pool->sp_sockets);
++ BUG_ON(svsk->sk_pool != pool);
+ }
+
+ out_unlock:
+- spin_unlock_bh(&serv->sv_lock);
++ spin_unlock_bh(&pool->sp_lock);
+ }
+
+ /*
+- * Dequeue the first socket. Must be called with the serv->sv_lock held.
++ * Dequeue the first socket. Must be called with the pool->sp_lock held.
+ */
+ static inline struct svc_sock *
+-svc_sock_dequeue(struct svc_serv *serv)
++svc_sock_dequeue(struct svc_pool *pool)
+ {
+ struct svc_sock *svsk;
+
+- if (list_empty(&serv->sv_sockets))
++ if (list_empty(&pool->sp_sockets))
+ return NULL;
+
+- svsk = list_entry(serv->sv_sockets.next,
++ svsk = list_entry(pool->sp_sockets.next,
+ struct svc_sock, sk_ready);
+ list_del_init(&svsk->sk_ready);
+
+ dprintk("svc: socket %p dequeued, inuse=%d\n",
+- svsk->sk_sk, svsk->sk_inuse);
++ svsk->sk_sk, atomic_read(&svsk->sk_inuse));
+
+ return svsk;
+ }
+@@ -241,6 +264,7 @@ svc_sock_dequeue(struct svc_serv *serv)
+ static inline void
+ svc_sock_received(struct svc_sock *svsk)
+ {
++ svsk->sk_pool = NULL;
+ clear_bit(SK_BUSY, &svsk->sk_flags);
+ svc_sock_enqueue(svsk);
+ }
+@@ -262,10 +286,8 @@ void svc_reserve(struct svc_rqst *rqstp,
+
+ if (space < rqstp->rq_reserved) {
+ struct svc_sock *svsk = rqstp->rq_sock;
+- spin_lock_bh(&svsk->sk_server->sv_lock);
+- svsk->sk_reserved -= (rqstp->rq_reserved - space);
++ atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved);
+ rqstp->rq_reserved = space;
+- spin_unlock_bh(&svsk->sk_server->sv_lock);
+
+ svc_sock_enqueue(svsk);
+ }
+@@ -277,17 +299,17 @@ void svc_reserve(struct svc_rqst *rqstp,
+ static inline void
+ svc_sock_put(struct svc_sock *svsk)
+ {
+- struct svc_serv *serv = svsk->sk_server;
+-
+- spin_lock_bh(&serv->sv_lock);
+- if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
+- spin_unlock_bh(&serv->sv_lock);
++ if (atomic_dec_and_test(&svsk->sk_inuse) &&
++ test_bit(SK_DEAD, &svsk->sk_flags)) {
+ dprintk("svc: releasing dead socket\n");
+- sock_release(svsk->sk_sock);
++ if (svsk->sk_sock->file)
++ sockfd_put(svsk->sk_sock);
++ else
++ sock_release(svsk->sk_sock);
++ if (svsk->sk_info_authunix != NULL)
++ svcauth_unix_info_release(svsk->sk_info_authunix);
+ kfree(svsk);
+ }
+- else
+- spin_unlock_bh(&serv->sv_lock);
+ }
+
+ static void
+@@ -297,7 +319,7 @@ svc_sock_release(struct svc_rqst *rqstp)
+
+ svc_release_skb(rqstp);
+
+- svc_free_allpages(rqstp);
++ svc_free_res_pages(rqstp);
+ rqstp->rq_res.page_len = 0;
+ rqstp->rq_res.page_base = 0;
+
+@@ -321,25 +343,33 @@ svc_sock_release(struct svc_rqst *rqstp)
+
+ /*
+ * External function to wake up a server waiting for data
++ * This really only makes sense for services like lockd
++ * which have exactly one thread anyway.
+ */
+ void
+ svc_wake_up(struct svc_serv *serv)
+ {
+ struct svc_rqst *rqstp;
+-
+- spin_lock_bh(&serv->sv_lock);
+- if (!list_empty(&serv->sv_threads)) {
+- rqstp = list_entry(serv->sv_threads.next,
+- struct svc_rqst,
+- rq_list);
+- dprintk("svc: daemon %p woken up.\n", rqstp);
+- /*
+- svc_serv_dequeue(serv, rqstp);
+- rqstp->rq_sock = NULL;
+- */
+- wake_up(&rqstp->rq_wait);
++ unsigned int i;
++ struct svc_pool *pool;
++
++ for (i = 0; i < serv->sv_nrpools; i++) {
++ pool = &serv->sv_pools[i];
++
++ spin_lock_bh(&pool->sp_lock);
++ if (!list_empty(&pool->sp_threads)) {
++ rqstp = list_entry(pool->sp_threads.next,
++ struct svc_rqst,
++ rq_list);
++ dprintk("svc: daemon %p woken up.\n", rqstp);
++ /*
++ svc_thread_dequeue(pool, rqstp);
++ rqstp->rq_sock = NULL;
++ */
++ wake_up(&rqstp->rq_wait);
++ }
++ spin_unlock_bh(&pool->sp_lock);
+ }
+- spin_unlock_bh(&serv->sv_lock);
+ }
+
+ /*
+@@ -388,7 +418,8 @@ svc_sendto(struct svc_rqst *rqstp, struc
+ /* send head */
+ if (slen == xdr->head[0].iov_len)
+ flags = 0;
+- len = sock->ops->sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags);
++ len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
++ xdr->head[0].iov_len, flags);
+ if (len != xdr->head[0].iov_len)
+ goto out;
+ slen -= xdr->head[0].iov_len;
+@@ -400,7 +431,7 @@ svc_sendto(struct svc_rqst *rqstp, struc
+ while (pglen > 0) {
+ if (slen == size)
+ flags = 0;
+- result = sock->ops->sendpage(sock, *ppage, base, size, flags);
++ result = kernel_sendpage(sock, *ppage, base, size, flags);
+ if (result > 0)
+ len += result;
+ if (result != size)
+@@ -413,8 +444,9 @@ svc_sendto(struct svc_rqst *rqstp, struc
+ }
+ /* send tail */
+ if (xdr->tail[0].iov_len) {
+- result = sock->ops->sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage],
+- ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),
++ result = kernel_sendpage(sock, rqstp->rq_respages[0],
++ ((unsigned long)xdr->tail[0].iov_base)
++ & (PAGE_SIZE-1),
+ xdr->tail[0].iov_len, 0);
+
+ if (result > 0)
+@@ -429,18 +461,65 @@ out:
+ }
+
+ /*
++ * Report socket names for nfsdfs
++ */
++static int one_sock_name(char *buf, struct svc_sock *svsk)
++{
++ int len;
++
++ switch(svsk->sk_sk->sk_family) {
++ case AF_INET:
++ len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n",
++ svsk->sk_sk->sk_protocol==IPPROTO_UDP?
++ "udp" : "tcp",
++ NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr),
++ inet_sk(svsk->sk_sk)->num);
++ break;
++ default:
++ len = sprintf(buf, "*unknown-%d*\n",
++ svsk->sk_sk->sk_family);
++ }
++ return len;
++}
++
++int
++svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
++{
++ struct svc_sock *svsk, *closesk = NULL;
++ int len = 0;
++
++ if (!serv)
++ return 0;
++ spin_lock(&serv->sv_lock);
++ list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
++ int onelen = one_sock_name(buf+len, svsk);
++ if (toclose && strcmp(toclose, buf+len) == 0)
++ closesk = svsk;
++ else
++ len += onelen;
++ }
++ spin_unlock(&serv->sv_lock);
++ if (closesk)
++ /* Should unregister with portmap, but you cannot
++ * unregister just one protocol...
++ */
++ svc_delete_socket(closesk);
++ else if (toclose)
++ return -ENOENT;
++ return len;
++}
++EXPORT_SYMBOL(svc_sock_names);
++
++/*
+ * Check input queue length
+ */
+ static int
+ svc_recv_available(struct svc_sock *svsk)
+ {
+- mm_segment_t oldfs;
+ struct socket *sock = svsk->sk_sock;
+ int avail, err;
+
+- oldfs = get_fs(); set_fs(KERNEL_DS);
+- err = sock->ops->ioctl(sock, TIOCINQ, (unsigned long) &avail);
+- set_fs(oldfs);
++ err = kernel_sock_ioctl(sock, TIOCINQ, (unsigned long) &avail);
+
+ return (err >= 0)? avail : err;
+ }
+@@ -472,7 +551,7 @@ svc_recvfrom(struct svc_rqst *rqstp, str
+ * at accept time. FIXME
+ */
+ alen = sizeof(rqstp->rq_addr);
+- sock->ops->getname(sock, (struct sockaddr *)&rqstp->rq_addr, &alen, 1);
++ kernel_getpeername(sock, (struct sockaddr *)&rqstp->rq_addr, &alen);
+
+ dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
+ rqstp->rq_sock, iov[0].iov_base, iov[0].iov_len, len);
+@@ -560,11 +639,14 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
+ /* udp sockets need large rcvbuf as all pending
+ * requests are still in that buffer. sndbuf must
+ * also be large enough that there is enough space
+- * for one reply per thread.
++ * for one reply per thread. We count all threads
++ * rather than threads in a particular pool, which
++ * provides an upper bound on the number of threads
++ * which will access the socket.
+ */
+ svc_sock_setbufsize(svsk->sk_sock,
+- (serv->sv_nrthreads+3) * serv->sv_bufsz,
+- (serv->sv_nrthreads+3) * serv->sv_bufsz);
++ (serv->sv_nrthreads+3) * serv->sv_max_mesg,
++ (serv->sv_nrthreads+3) * serv->sv_max_mesg);
+
+ if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
+ svc_sock_received(svsk);
+@@ -634,9 +716,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
+ if (len <= rqstp->rq_arg.head[0].iov_len) {
+ rqstp->rq_arg.head[0].iov_len = len;
+ rqstp->rq_arg.page_len = 0;
++ rqstp->rq_respages = rqstp->rq_pages+1;
+ } else {
+ rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
+- rqstp->rq_argused += (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
++ rqstp->rq_respages = rqstp->rq_pages + 1 +
++ (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
+ }
+
+ if (serv->sv_stats)
+@@ -671,8 +755,8 @@ svc_udp_init(struct svc_sock *svsk)
+ * svc_udp_recvfrom will re-adjust if necessary
+ */
+ svc_sock_setbufsize(svsk->sk_sock,
+- 3 * svsk->sk_server->sv_bufsz,
+- 3 * svsk->sk_server->sv_bufsz);
++ 3 * svsk->sk_server->sv_max_mesg,
++ 3 * svsk->sk_server->sv_max_mesg);
+
+ set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
+ set_bit(SK_CHNGBUF, &svsk->sk_flags);
+@@ -758,7 +842,6 @@ svc_tcp_accept(struct svc_sock *svsk)
+ struct svc_serv *serv = svsk->sk_server;
+ struct socket *sock = svsk->sk_sock;
+ struct socket *newsock;
+- const struct proto_ops *ops;
+ struct svc_sock *newsvsk;
+ int err, slen;
+
+@@ -766,29 +849,23 @@ svc_tcp_accept(struct svc_sock *svsk)
+ if (!sock)
+ return;
+
+- err = sock_create_lite(PF_INET, SOCK_STREAM, IPPROTO_TCP, &newsock);
+- if (err) {
++ clear_bit(SK_CONN, &svsk->sk_flags);
++ err = kernel_accept(sock, &newsock, O_NONBLOCK);
++ if (err < 0) {
+ if (err == -ENOMEM)
+ printk(KERN_WARNING "%s: no more sockets!\n",
+ serv->sv_name);
+- return;
+- }
+-
+- dprintk("svc: tcp_accept %p allocated\n", newsock);
+- newsock->ops = ops = sock->ops;
+-
+- clear_bit(SK_CONN, &svsk->sk_flags);
+- if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) {
+- if (err != -EAGAIN && net_ratelimit())
++ else if (err != -EAGAIN && net_ratelimit())
+ printk(KERN_WARNING "%s: accept failed (err %d)!\n",
+ serv->sv_name, -err);
+- goto failed; /* aborted connection or whatever */
++ return;
+ }
++
+ set_bit(SK_CONN, &svsk->sk_flags);
+ svc_sock_enqueue(svsk);
+
+ slen = sizeof(sin);
+- err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1);
++ err = kernel_getpeername(newsock, (struct sockaddr *) &sin, &slen);
+ if (err < 0) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: peername failed (err %d)!\n",
+@@ -854,7 +931,7 @@ svc_tcp_accept(struct svc_sock *svsk)
+ struct svc_sock,
+ sk_list);
+ set_bit(SK_CLOSE, &svsk->sk_flags);
+- svsk->sk_inuse ++;
++ atomic_inc(&svsk->sk_inuse);
+ }
+ spin_unlock_bh(&serv->sv_lock);
+
+@@ -884,7 +961,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ struct svc_sock *svsk = rqstp->rq_sock;
+ struct svc_serv *serv = svsk->sk_server;
+ int len;
+- struct kvec vec[RPCSVC_MAXPAGES];
++ struct kvec *vec;
+ int pnum, vlen;
+
+ dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
+@@ -902,7 +979,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ return 0;
+ }
+
+- if (test_bit(SK_CONN, &svsk->sk_flags)) {
++ if (svsk->sk_sk->sk_state == TCP_LISTEN) {
+ svc_tcp_accept(svsk);
+ svc_sock_received(svsk);
+ return 0;
+@@ -912,13 +989,18 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ /* sndbuf needs to have room for one request
+ * per thread, otherwise we can stall even when the
+ * network isn't a bottleneck.
++ *
++ * We count all threads rather than threads in a
++ * particular pool, which provides an upper bound
++ * on the number of threads which will access the socket.
++ *
+ * rcvbuf just needs to be able to hold a few requests.
+ * Normally they will be removed from the queue
+ * as soon a a complete request arrives.
+ */
+ svc_sock_setbufsize(svsk->sk_sock,
+- (serv->sv_nrthreads+3) * serv->sv_bufsz,
+- 3 * serv->sv_bufsz);
++ (serv->sv_nrthreads+3) * serv->sv_max_mesg,
++ 3 * serv->sv_max_mesg);
+
+ clear_bit(SK_DATA, &svsk->sk_flags);
+
+@@ -956,7 +1038,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ }
+ svsk->sk_reclen &= 0x7fffffff;
+ dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
+- if (svsk->sk_reclen > serv->sv_bufsz) {
++ if (svsk->sk_reclen > serv->sv_max_mesg) {
+ printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
+ (unsigned long) svsk->sk_reclen);
+ goto err_delete;
+@@ -977,15 +1059,17 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ len = svsk->sk_reclen;
+ set_bit(SK_DATA, &svsk->sk_flags);
+
++ vec = rqstp->rq_vec;
+ vec[0] = rqstp->rq_arg.head[0];
+ vlen = PAGE_SIZE;
+ pnum = 1;
+ while (vlen < len) {
+- vec[pnum].iov_base = page_address(rqstp->rq_argpages[rqstp->rq_argused++]);
++ vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]);
+ vec[pnum].iov_len = PAGE_SIZE;
+ pnum++;
+ vlen += PAGE_SIZE;
+ }
++ rqstp->rq_respages = &rqstp->rq_pages[pnum];
+
+ /* Now receive data */
+ len = svc_recvfrom(rqstp, vec, pnum, len);
+@@ -1040,7 +1124,7 @@ svc_tcp_sendto(struct svc_rqst *rqstp)
+ {
+ struct xdr_buf *xbufp = &rqstp->rq_res;
+ int sent;
+- u32 reclen;
++ __be32 reclen;
+
+ /* Set up the first element of the reply kvec.
+ * Any other kvecs that may be in use have been taken
+@@ -1093,8 +1177,8 @@ svc_tcp_init(struct svc_sock *svsk)
+ * svc_tcp_recvfrom will re-adjust if necessary
+ */
+ svc_sock_setbufsize(svsk->sk_sock,
+- 3 * svsk->sk_server->sv_bufsz,
+- 3 * svsk->sk_server->sv_bufsz);
++ 3 * svsk->sk_server->sv_max_mesg,
++ 3 * svsk->sk_server->sv_max_mesg);
+
+ set_bit(SK_CHNGBUF, &svsk->sk_flags);
+ set_bit(SK_DATA, &svsk->sk_flags);
+@@ -1127,13 +1211,17 @@ svc_sock_update_bufs(struct svc_serv *se
+ }
+
+ /*
+- * Receive the next request on any socket.
++ * Receive the next request on any socket. This code is carefully
++ * organised not to touch any cachelines in the shared svc_serv
++ * structure, only cachelines in the local svc_pool.
+ */
+ int
+-svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
++svc_recv(struct svc_rqst *rqstp, long timeout)
+ {
+ struct svc_sock *svsk =NULL;
+- int len;
++ struct svc_serv *serv = rqstp->rq_server;
++ struct svc_pool *pool = rqstp->rq_pool;
++ int len, i;
+ int pages;
+ struct xdr_buf *arg;
+ DECLARE_WAITQUEUE(wait, current);
+@@ -1150,27 +1238,22 @@ svc_recv(struct svc_serv *serv, struct s
+ "svc_recv: service %p, wait queue active!\n",
+ rqstp);
+
+- /* Initialize the buffers */
+- /* first reclaim pages that were moved to response list */
+- svc_pushback_allpages(rqstp);
+
+ /* now allocate needed pages. If we get a failure, sleep briefly */
+- pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
+- while (rqstp->rq_arghi < pages) {
+- struct page *p = alloc_page(GFP_KERNEL);
+- if (!p) {
+- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+- continue;
++ pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
++ for (i=0; i < pages ; i++)
++ while (rqstp->rq_pages[i] == NULL) {
++ struct page *p = alloc_page(GFP_KERNEL);
++ if (!p)
++ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
++ rqstp->rq_pages[i] = p;
+ }
+- rqstp->rq_argpages[rqstp->rq_arghi++] = p;
+- }
+
+ /* Make arg->head point to first page and arg->pages point to rest */
+ arg = &rqstp->rq_arg;
+- arg->head[0].iov_base = page_address(rqstp->rq_argpages[0]);
++ arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
+ arg->head[0].iov_len = PAGE_SIZE;
+- rqstp->rq_argused = 1;
+- arg->pages = rqstp->rq_argpages + 1;
++ arg->pages = rqstp->rq_pages + 1;
+ arg->page_base = 0;
+ /* save at least one page for response */
+ arg->page_len = (pages-2)*PAGE_SIZE;
+@@ -1182,32 +1265,15 @@ svc_recv(struct svc_serv *serv, struct s
+ if (signalled())
+ return -EINTR;
+
+- spin_lock_bh(&serv->sv_lock);
+- if (!list_empty(&serv->sv_tempsocks)) {
+- svsk = list_entry(serv->sv_tempsocks.next,
+- struct svc_sock, sk_list);
+- /* apparently the "standard" is that clients close
+- * idle connections after 5 minutes, servers after
+- * 6 minutes
+- * http://www.connectathon.org/talks96/nfstcp.pdf
+- */
+- if (get_seconds() - svsk->sk_lastrecv < 6*60
+- || test_bit(SK_BUSY, &svsk->sk_flags))
+- svsk = NULL;
+- }
+- if (svsk) {
+- set_bit(SK_BUSY, &svsk->sk_flags);
+- set_bit(SK_CLOSE, &svsk->sk_flags);
++ spin_lock_bh(&pool->sp_lock);
++ if ((svsk = svc_sock_dequeue(pool)) != NULL) {
+ rqstp->rq_sock = svsk;
+- svsk->sk_inuse++;
+- } else if ((svsk = svc_sock_dequeue(serv)) != NULL) {
+- rqstp->rq_sock = svsk;
+- svsk->sk_inuse++;
+- rqstp->rq_reserved = serv->sv_bufsz;
+- svsk->sk_reserved += rqstp->rq_reserved;
++ atomic_inc(&svsk->sk_inuse);
++ rqstp->rq_reserved = serv->sv_max_mesg;
++ atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
+ } else {
+ /* No data pending. Go to sleep */
+- svc_serv_enqueue(serv, rqstp);
++ svc_thread_enqueue(pool, rqstp);
+
+ /*
+ * We have to be able to interrupt this wait
+@@ -1215,26 +1281,26 @@ svc_recv(struct svc_serv *serv, struct s
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&rqstp->rq_wait, &wait);
+- spin_unlock_bh(&serv->sv_lock);
++ spin_unlock_bh(&pool->sp_lock);
+
+ schedule_timeout(timeout);
+
+ try_to_freeze();
+
+- spin_lock_bh(&serv->sv_lock);
++ spin_lock_bh(&pool->sp_lock);
+ remove_wait_queue(&rqstp->rq_wait, &wait);
+
+ if (!(svsk = rqstp->rq_sock)) {
+- svc_serv_dequeue(serv, rqstp);
+- spin_unlock_bh(&serv->sv_lock);
++ svc_thread_dequeue(pool, rqstp);
++ spin_unlock_bh(&pool->sp_lock);
+ dprintk("svc: server %p, no data yet\n", rqstp);
+ return signalled()? -EINTR : -EAGAIN;
+ }
+ }
+- spin_unlock_bh(&serv->sv_lock);
++ spin_unlock_bh(&pool->sp_lock);
+
+- dprintk("svc: server %p, socket %p, inuse=%d\n",
+- rqstp, svsk, svsk->sk_inuse);
++ dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n",
++ rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse));
+ len = svsk->sk_recvfrom(rqstp);
+ dprintk("svc: got len=%d\n", len);
+
+@@ -1245,13 +1311,7 @@ svc_recv(struct svc_serv *serv, struct s
+ return -EAGAIN;
+ }
+ svsk->sk_lastrecv = get_seconds();
+- if (test_bit(SK_TEMP, &svsk->sk_flags)) {
+- /* push active sockets to end of list */
+- spin_lock_bh(&serv->sv_lock);
+- if (!list_empty(&svsk->sk_list))
+- list_move_tail(&svsk->sk_list, &serv->sv_tempsocks);
+- spin_unlock_bh(&serv->sv_lock);
+- }
++ clear_bit(SK_OLD, &svsk->sk_flags);
+
+ rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024;
+ rqstp->rq_chandle.defer = svc_defer;
+@@ -1311,6 +1371,58 @@ svc_send(struct svc_rqst *rqstp)
+ }
+
+ /*
++ * Timer function to close old temporary sockets, using
++ * a mark-and-sweep algorithm.
++ */
++static void
++svc_age_temp_sockets(unsigned long closure)
++{
++ struct svc_serv *serv = (struct svc_serv *)closure;
++ struct svc_sock *svsk;
++ struct list_head *le, *next;
++ LIST_HEAD(to_be_aged);
++
++ dprintk("svc_age_temp_sockets\n");
++
++ if (!spin_trylock_bh(&serv->sv_lock)) {
++ /* busy, try again 1 sec later */
++ dprintk("svc_age_temp_sockets: busy\n");
++ mod_timer(&serv->sv_temptimer, jiffies + HZ);
++ return;
++ }
++
++ list_for_each_safe(le, next, &serv->sv_tempsocks) {
++ svsk = list_entry(le, struct svc_sock, sk_list);
++
++ if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
++ continue;
++ if (atomic_read(&svsk->sk_inuse) || test_bit(SK_BUSY, &svsk->sk_flags))
++ continue;
++ atomic_inc(&svsk->sk_inuse);
++ list_move(le, &to_be_aged);
++ set_bit(SK_CLOSE, &svsk->sk_flags);
++ set_bit(SK_DETACHED, &svsk->sk_flags);
++ }
++ spin_unlock_bh(&serv->sv_lock);
++
++ while (!list_empty(&to_be_aged)) {
++ le = to_be_aged.next;
++ /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */
++ list_del_init(le);
++ svsk = list_entry(le, struct svc_sock, sk_list);
++
++ dprintk("queuing svsk %p for closing, %lu seconds old\n",
++ svsk, get_seconds() - svsk->sk_lastrecv);
++
++ /* a thread will dequeue and close it soon */
++ svc_sock_enqueue(svsk);
++ svc_sock_put(svsk);
++ }
++
++ mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
++}
++
++/*
+ * Initialize socket for RPC use and create svc_sock struct
+ * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
+ */
+@@ -1347,7 +1459,9 @@ svc_setup_socket(struct svc_serv *serv,
+ svsk->sk_odata = inet->sk_data_ready;
+ svsk->sk_owspace = inet->sk_write_space;
+ svsk->sk_server = serv;
++ atomic_set(&svsk->sk_inuse, 0);
+ svsk->sk_lastrecv = get_seconds();
++ spin_lock_init(&svsk->sk_defer_lock);
+ INIT_LIST_HEAD(&svsk->sk_deferred);
+ INIT_LIST_HEAD(&svsk->sk_ready);
+ mutex_init(&svsk->sk_mutex);
+@@ -1363,6 +1477,13 @@ svc_setup_socket(struct svc_serv *serv,
+ set_bit(SK_TEMP, &svsk->sk_flags);
+ list_add(&svsk->sk_list, &serv->sv_tempsocks);
+ serv->sv_tmpcnt++;
++ if (serv->sv_temptimer.function == NULL) {
++ /* setup timer to age temp sockets */
++ setup_timer(&serv->sv_temptimer, svc_age_temp_sockets,
++ (unsigned long)serv);
++ mod_timer(&serv->sv_temptimer,
++ jiffies + svc_conn_age_period * HZ);
++ }
+ } else {
+ clear_bit(SK_TEMP, &svsk->sk_flags);
+ list_add(&svsk->sk_list, &serv->sv_permsocks);
+@@ -1377,6 +1498,38 @@ svc_setup_socket(struct svc_serv *serv,
+ return svsk;
+ }
+
++int svc_addsock(struct svc_serv *serv,
++ int fd,
++ char *name_return,
++ int *proto)
++{
++ int err = 0;
++ struct socket *so = sockfd_lookup(fd, &err);
++ struct svc_sock *svsk = NULL;
++
++ if (!so)
++ return err;
++ if (so->sk->sk_family != AF_INET)
++ err = -EAFNOSUPPORT;
++ else if (so->sk->sk_protocol != IPPROTO_TCP &&
++ so->sk->sk_protocol != IPPROTO_UDP)
++ err = -EPROTONOSUPPORT;
++ else if (so->state > SS_UNCONNECTED)
++ err = -EISCONN;
++ else {
++ svsk = svc_setup_socket(serv, so, &err, 1);
++ if (svsk)
++ err = 0;
++ }
++ if (err) {
++ sockfd_put(so);
++ return err;
++ }
++ if (proto) *proto = so->sk->sk_protocol;
++ return one_sock_name(name_return, svsk);
++}
++EXPORT_SYMBOL_GPL(svc_addsock);
++
+ /*
+ * Create socket for RPC service.
+ */
+@@ -1403,17 +1556,15 @@ svc_create_socket(struct svc_serv *serv,
+ if ((error = sock_create_kern(PF_INET, type, protocol, &sock)) < 0)
+ return error;
+
+- if (sin != NULL) {
+- if (type == SOCK_STREAM)
+- sock->sk->sk_reuse = 1; /* allow address reuse */
+- error = sock->ops->bind(sock, (struct sockaddr *) sin,
+- sizeof(*sin));
+- if (error < 0)
+- goto bummer;
+- }
++ if (type == SOCK_STREAM)
++ sock->sk->sk_reuse = 1; /* allow address reuse */
++ error = kernel_bind(sock, (struct sockaddr *) sin,
++ sizeof(*sin));
++ if (error < 0)
++ goto bummer;
+
+ if (protocol == IPPROTO_TCP) {
+- if ((error = sock->ops->listen(sock, 64)) < 0)
++ if ((error = kernel_listen(sock, 64)) < 0)
+ goto bummer;
+ }
+
+@@ -1446,21 +1597,26 @@ svc_delete_socket(struct svc_sock *svsk)
+
+ spin_lock_bh(&serv->sv_lock);
+
+- list_del_init(&svsk->sk_list);
+- list_del_init(&svsk->sk_ready);
++ if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags))
++ list_del_init(&svsk->sk_list);
++ /*
++ * We used to delete the svc_sock from whichever list
++ * it's sk_ready node was on, but we don't actually
++ * need to. This is because the only time we're called
++ * while still attached to a queue, the queue itself
++ * is about to be destroyed (in svc_destroy).
++ */
+ if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags))
+ if (test_bit(SK_TEMP, &svsk->sk_flags))
+ serv->sv_tmpcnt--;
+
+- if (!svsk->sk_inuse) {
+- spin_unlock_bh(&serv->sv_lock);
+- sock_release(svsk->sk_sock);
+- kfree(svsk);
+- } else {
+- spin_unlock_bh(&serv->sv_lock);
+- dprintk(KERN_NOTICE "svc: server socket destroy delayed\n");
+- /* svsk->sk_server = NULL; */
+- }
++ /* This atomic_inc should be needed - svc_delete_socket
++ * should have the semantic of dropping a reference.
++ * But it doesn't yet....
++ */
++ atomic_inc(&svsk->sk_inuse);
++ spin_unlock_bh(&serv->sv_lock);
++ svc_sock_put(svsk);
+ }
+
+ /*
+@@ -1485,7 +1641,6 @@ svc_makesock(struct svc_serv *serv, int
+ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
+ {
+ struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle);
+- struct svc_serv *serv = dreq->owner;
+ struct svc_sock *svsk;
+
+ if (too_many) {
+@@ -1496,9 +1651,9 @@ static void svc_revisit(struct cache_def
+ dprintk("revisit queued\n");
+ svsk = dr->svsk;
+ dr->svsk = NULL;
+- spin_lock_bh(&serv->sv_lock);
++ spin_lock_bh(&svsk->sk_defer_lock);
+ list_add(&dr->handle.recent, &svsk->sk_deferred);
+- spin_unlock_bh(&serv->sv_lock);
++ spin_unlock_bh(&svsk->sk_defer_lock);
+ set_bit(SK_DEFERRED, &svsk->sk_flags);
+ svc_sock_enqueue(svsk);
+ svc_sock_put(svsk);
+@@ -1530,10 +1685,8 @@ svc_defer(struct cache_req *req)
+ dr->argslen = rqstp->rq_arg.len >> 2;
+ memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2);
+ }
+- spin_lock_bh(&rqstp->rq_server->sv_lock);
+- rqstp->rq_sock->sk_inuse++;
++ atomic_inc(&rqstp->rq_sock->sk_inuse);
+ dr->svsk = rqstp->rq_sock;
+- spin_unlock_bh(&rqstp->rq_server->sv_lock);
+
+ dr->handle.revisit = svc_revisit;
+ return &dr->handle;
+@@ -1553,6 +1706,7 @@ static int svc_deferred_recv(struct svc_
+ rqstp->rq_prot = dr->prot;
+ rqstp->rq_addr = dr->addr;
+ rqstp->rq_daddr = dr->daddr;
++ rqstp->rq_respages = rqstp->rq_pages;
+ return dr->argslen<<2;
+ }
+
+@@ -1560,11 +1714,10 @@ static int svc_deferred_recv(struct svc_
+ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
+ {
+ struct svc_deferred_req *dr = NULL;
+- struct svc_serv *serv = svsk->sk_server;
+
+ if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
+ return NULL;
+- spin_lock_bh(&serv->sv_lock);
++ spin_lock_bh(&svsk->sk_defer_lock);
+ clear_bit(SK_DEFERRED, &svsk->sk_flags);
+ if (!list_empty(&svsk->sk_deferred)) {
+ dr = list_entry(svsk->sk_deferred.next,
+@@ -1573,6 +1726,6 @@ static struct svc_deferred_req *svc_defe
+ list_del_init(&dr->handle.recent);
+ set_bit(SK_DEFERRED, &svsk->sk_flags);
+ }
+- spin_unlock_bh(&serv->sv_lock);
++ spin_unlock_bh(&svsk->sk_defer_lock);
+ return dr;
+ }
+diff --git a/net/sunrpc/timer.c b/net/sunrpc/timer.c
+index bcbdf64..8142fdb 100644
+--- a/net/sunrpc/timer.c
++++ b/net/sunrpc/timer.c
+@@ -19,8 +19,6 @@
+ #include <linux/unistd.h>
+
+ #include <linux/sunrpc/clnt.h>
+-#include <linux/sunrpc/xprt.h>
+-#include <linux/sunrpc/timer.h>
+
+ #define RPC_RTO_MAX (60*HZ)
+ #define RPC_RTO_INIT (HZ/5)
+diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
+index 6ac4510..9022eb8 100644
+--- a/net/sunrpc/xdr.c
++++ b/net/sunrpc/xdr.c
+@@ -18,8 +18,8 @@
+ /*
+ * XDR functions for basic NFS types
+ */
+-u32 *
+-xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
++__be32 *
++xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
+ {
+ unsigned int quadlen = XDR_QUADLEN(obj->len);
+
+@@ -29,8 +29,8 @@ xdr_encode_netobj(u32 *p, const struct x
+ return p + XDR_QUADLEN(obj->len);
+ }
+
+-u32 *
+-xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
++__be32 *
++xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
+ {
+ unsigned int len;
+
+@@ -55,7 +55,7 @@ xdr_decode_netobj(u32 *p, struct xdr_net
+ * Returns the updated current XDR buffer position
+ *
+ */
+-u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes)
++__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes)
+ {
+ if (likely(nbytes != 0)) {
+ unsigned int quadlen = XDR_QUADLEN(nbytes);
+@@ -79,21 +79,21 @@ EXPORT_SYMBOL(xdr_encode_opaque_fixed);
+ *
+ * Returns the updated current XDR buffer position
+ */
+-u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes)
++__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes)
+ {
+ *p++ = htonl(nbytes);
+ return xdr_encode_opaque_fixed(p, ptr, nbytes);
+ }
+ EXPORT_SYMBOL(xdr_encode_opaque);
+
+-u32 *
+-xdr_encode_string(u32 *p, const char *string)
++__be32 *
++xdr_encode_string(__be32 *p, const char *string)
+ {
+ return xdr_encode_array(p, string, strlen(string));
+ }
+
+-u32 *
+-xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
++__be32 *
++xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
+ {
+ unsigned int len;
+
+@@ -432,7 +432,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_
+ * of the buffer length, and takes care of adjusting the kvec
+ * length for us.
+ */
+-void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
++void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
+ {
+ struct kvec *iov = buf->head;
+ int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
+@@ -440,8 +440,8 @@ void xdr_init_encode(struct xdr_stream *
+ BUG_ON(scratch_len < 0);
+ xdr->buf = buf;
+ xdr->iov = iov;
+- xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
+- xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len);
++ xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);
++ xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);
+ BUG_ON(iov->iov_len > scratch_len);
+
+ if (p != xdr->p && p != NULL) {
+@@ -465,10 +465,10 @@ EXPORT_SYMBOL(xdr_init_encode);
+ * bytes of data. If so, update the total xdr_buf length, and
+ * adjust the length of the current kvec.
+ */
+-uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
++__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
+ {
+- uint32_t *p = xdr->p;
+- uint32_t *q;
++ __be32 *p = xdr->p;
++ __be32 *q;
+
+ /* align nbytes on the next 32-bit boundary */
+ nbytes += 3;
+@@ -524,7 +524,7 @@ EXPORT_SYMBOL(xdr_write_pages);
+ * @buf: pointer to XDR buffer from which to decode data
+ * @p: current pointer inside XDR buffer
+ */
+-void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
++void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
+ {
+ struct kvec *iov = buf->head;
+ unsigned int len = iov->iov_len;
+@@ -534,7 +534,7 @@ void xdr_init_decode(struct xdr_stream *
+ xdr->buf = buf;
+ xdr->iov = iov;
+ xdr->p = p;
+- xdr->end = (uint32_t *)((char *)iov->iov_base + len);
++ xdr->end = (__be32 *)((char *)iov->iov_base + len);
+ }
+ EXPORT_SYMBOL(xdr_init_decode);
+
+@@ -548,10 +548,10 @@ EXPORT_SYMBOL(xdr_init_decode);
+ * If so return the current pointer, then update the current
+ * pointer position.
+ */
+-uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
++__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
+ {
+- uint32_t *p = xdr->p;
+- uint32_t *q = p + XDR_QUADLEN(nbytes);
++ __be32 *p = xdr->p;
++ __be32 *q = p + XDR_QUADLEN(nbytes);
+
+ if (unlikely(q > xdr->end || q < p))
+ return NULL;
+@@ -599,8 +599,8 @@ void xdr_read_pages(struct xdr_stream *x
+ * Position current pointer at beginning of tail, and
+ * set remaining message length.
+ */
+- xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
+- xdr->end = (uint32_t *)((char *)iov->iov_base + end);
++ xdr->p = (__be32 *)((char *)iov->iov_base + padding);
++ xdr->end = (__be32 *)((char *)iov->iov_base + end);
+ }
+ EXPORT_SYMBOL(xdr_read_pages);
+
+@@ -624,8 +624,8 @@ void xdr_enter_page(struct xdr_stream *x
+ */
+ if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
+ len = PAGE_CACHE_SIZE - xdr->buf->page_base;
+- xdr->p = (uint32_t *)(kaddr + xdr->buf->page_base);
+- xdr->end = (uint32_t *)((char *)xdr->p + len);
++ xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);
++ xdr->end = (__be32 *)((char *)xdr->p + len);
+ }
+ EXPORT_SYMBOL(xdr_enter_page);
+
+@@ -743,7 +743,7 @@ out:
+ int
+ xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj)
+ {
+- u32 raw;
++ __be32 raw;
+ int status;
+
+ status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
+@@ -756,7 +756,7 @@ xdr_decode_word(struct xdr_buf *buf, int
+ int
+ xdr_encode_word(struct xdr_buf *buf, int base, u32 obj)
+ {
+- u32 raw = htonl(obj);
++ __be32 raw = htonl(obj);
+
+ return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
+ }
+diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
+index e8c2bc4..8085747 100644
+--- a/net/sunrpc/xprt.c
++++ b/net/sunrpc/xprt.c
+@@ -534,7 +534,7 @@ void xprt_connect(struct rpc_task *task)
+ dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
+ xprt, (xprt_connected(xprt) ? "is" : "is not"));
+
+- if (!xprt->addr.sin_port) {
++ if (!xprt_bound(xprt)) {
+ task->tk_status = -EIO;
+ return;
+ }
+@@ -585,13 +585,6 @@ static void xprt_connect_status(struct r
+ task->tk_pid, -task->tk_status, task->tk_client->cl_server);
+ xprt_release_write(xprt, task);
+ task->tk_status = -EIO;
+- return;
+- }
+-
+- /* if soft mounted, just cause this RPC to fail */
+- if (RPC_IS_SOFT(task)) {
+- xprt_release_write(xprt, task);
+- task->tk_status = -EIO;
+ }
+ }
+
+@@ -601,7 +594,7 @@ static void xprt_connect_status(struct r
+ * @xid: RPC XID of incoming reply
+ *
+ */
+-struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
++struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
+ {
+ struct list_head *pos;
+
+@@ -808,7 +801,7 @@ void xprt_reserve(struct rpc_task *task)
+ spin_unlock(&xprt->reserve_lock);
+ }
+
+-static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
++static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
+ {
+ return xprt->xid++;
+ }
+@@ -829,6 +822,7 @@ static void xprt_request_init(struct rpc
+ req->rq_bufsize = 0;
+ req->rq_xid = xprt_alloc_xid(xprt);
+ req->rq_release_snd_buf = NULL;
++ xprt_reset_majortimeo(req);
+ dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
+ req, ntohl(req->rq_xid));
+ }
+@@ -887,16 +881,32 @@ void xprt_set_timeout(struct rpc_timeout
+ to->to_exponential = 0;
+ }
+
+-static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
++/**
++ * xprt_create_transport - create an RPC transport
++ * @proto: requested transport protocol
++ * @ap: remote peer address
++ * @size: length of address
++ * @to: timeout parameters
++ *
++ */
++struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to)
+ {
+ int result;
+ struct rpc_xprt *xprt;
+ struct rpc_rqst *req;
+
+- if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
++ if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) {
++ dprintk("RPC: xprt_create_transport: no memory\n");
+ return ERR_PTR(-ENOMEM);
+-
+- xprt->addr = *ap;
++ }
++ if (size <= sizeof(xprt->addr)) {
++ memcpy(&xprt->addr, ap, size);
++ xprt->addrlen = size;
++ } else {
++ kfree(xprt);
++ dprintk("RPC: xprt_create_transport: address too large\n");
++ return ERR_PTR(-EBADF);
++ }
+
+ switch (proto) {
+ case IPPROTO_UDP:
+@@ -908,14 +918,15 @@ static struct rpc_xprt *xprt_setup(int p
+ default:
+ printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
+ proto);
+- result = -EIO;
+- break;
++ return ERR_PTR(-EIO);
+ }
+ if (result) {
+ kfree(xprt);
++ dprintk("RPC: xprt_create_transport: failed, %d\n", result);
+ return ERR_PTR(result);
+ }
+
++ kref_init(&xprt->kref);
+ spin_lock_init(&xprt->transport_lock);
+ spin_lock_init(&xprt->reserve_lock);
+
+@@ -928,6 +939,7 @@ static struct rpc_xprt *xprt_setup(int p
+ xprt->last_used = jiffies;
+ xprt->cwnd = RPC_INITCWND;
+
++ rpc_init_wait_queue(&xprt->binding, "xprt_binding");
+ rpc_init_wait_queue(&xprt->pending, "xprt_pending");
+ rpc_init_wait_queue(&xprt->sending, "xprt_sending");
+ rpc_init_wait_queue(&xprt->resend, "xprt_resend");
+@@ -941,41 +953,43 @@ static struct rpc_xprt *xprt_setup(int p
+
+ dprintk("RPC: created transport %p with %u slots\n", xprt,
+ xprt->max_reqs);
+-
+- return xprt;
+-}
+
+-/**
+- * xprt_create_proto - create an RPC client transport
+- * @proto: requested transport protocol
+- * @sap: remote peer's address
+- * @to: timeout parameters for new transport
+- *
+- */
+-struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
+-{
+- struct rpc_xprt *xprt;
+-
+- xprt = xprt_setup(proto, sap, to);
+- if (IS_ERR(xprt))
+- dprintk("RPC: xprt_create_proto failed\n");
+- else
+- dprintk("RPC: xprt_create_proto created xprt %p\n", xprt);
+ return xprt;
+ }
+
+ /**
+ * xprt_destroy - destroy an RPC transport, killing off all requests.
+- * @xprt: transport to destroy
++ * @kref: kref for the transport to destroy
+ *
+ */
+-int xprt_destroy(struct rpc_xprt *xprt)
++static void xprt_destroy(struct kref *kref)
+ {
++ struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref);
++
+ dprintk("RPC: destroying transport %p\n", xprt);
+ xprt->shutdown = 1;
+ del_timer_sync(&xprt->timer);
+ xprt->ops->destroy(xprt);
+ kfree(xprt);
++}
+
+- return 0;
++/**
++ * xprt_put - release a reference to an RPC transport.
++ * @xprt: pointer to the transport
++ *
++ */
++void xprt_put(struct rpc_xprt *xprt)
++{
++ kref_put(&xprt->kref, xprt_destroy);
++}
++
++/**
++ * xprt_get - return a reference to an RPC transport.
++ * @xprt: pointer to the transport
++ *
++ */
++struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
++{
++ kref_get(&xprt->kref);
++ return xprt;
+ }
+diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
+index 441bd53..757fc91 100644
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -125,6 +125,47 @@ static inline void xs_pktdump(char *msg,
+ }
+ #endif
+
++static void xs_format_peer_addresses(struct rpc_xprt *xprt)
++{
++ struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
++ char *buf;
++
++ buf = kzalloc(20, GFP_KERNEL);
++ if (buf) {
++ snprintf(buf, 20, "%u.%u.%u.%u",
++ NIPQUAD(addr->sin_addr.s_addr));
++ }
++ xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
++
++ buf = kzalloc(8, GFP_KERNEL);
++ if (buf) {
++ snprintf(buf, 8, "%u",
++ ntohs(addr->sin_port));
++ }
++ xprt->address_strings[RPC_DISPLAY_PORT] = buf;
++
++ if (xprt->prot == IPPROTO_UDP)
++ xprt->address_strings[RPC_DISPLAY_PROTO] = "udp";
++ else
++ xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp";
++
++ buf = kzalloc(48, GFP_KERNEL);
++ if (buf) {
++ snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s",
++ NIPQUAD(addr->sin_addr.s_addr),
++ ntohs(addr->sin_port),
++ xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
++ }
++ xprt->address_strings[RPC_DISPLAY_ALL] = buf;
++}
++
++static void xs_free_peer_addresses(struct rpc_xprt *xprt)
++{
++ kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
++ kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
++ kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
++}
++
+ #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL)
+
+ static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len)
+@@ -174,7 +215,6 @@ static inline int xs_sendpages(struct so
+ struct page **ppage = xdr->pages;
+ unsigned int len, pglen = xdr->page_len;
+ int err, ret = 0;
+- ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
+
+ if (unlikely(!sock))
+ return -ENOTCONN;
+@@ -207,7 +247,6 @@ static inline int xs_sendpages(struct so
+ base &= ~PAGE_CACHE_MASK;
+ }
+
+- sendpage = sock->ops->sendpage ? : sock_no_sendpage;
+ do {
+ int flags = XS_SENDMSG_FLAGS;
+
+@@ -220,10 +259,7 @@ static inline int xs_sendpages(struct so
+ if (pglen != len || xdr->tail[0].iov_len != 0)
+ flags |= MSG_MORE;
+
+- /* Hmm... We might be dealing with highmem pages */
+- if (PageHighMem(*ppage))
+- sendpage = sock_no_sendpage;
+- err = sendpage(sock, *ppage, base, len, flags);
++ err = kernel_sendpage(sock, *ppage, base, len, flags);
+ if (ret == 0)
+ ret = err;
+ else if (err > 0)
+@@ -300,7 +336,7 @@ static int xs_udp_send_request(struct rp
+
+ req->rq_xtime = jiffies;
+ status = xs_sendpages(xprt->sock, (struct sockaddr *) &xprt->addr,
+- sizeof(xprt->addr), xdr, req->rq_bytes_sent);
++ xprt->addrlen, xdr, req->rq_bytes_sent);
+
+ dprintk("RPC: xs_udp_send_request(%u) = %d\n",
+ xdr->len - req->rq_bytes_sent, status);
+@@ -490,6 +526,7 @@ static void xs_destroy(struct rpc_xprt *
+
+ xprt_disconnect(xprt);
+ xs_close(xprt);
++ xs_free_peer_addresses(xprt);
+ kfree(xprt->slot);
+ }
+
+@@ -511,7 +548,8 @@ static void xs_udp_data_ready(struct soc
+ struct rpc_rqst *rovr;
+ struct sk_buff *skb;
+ int err, repsize, copied;
+- u32 _xid, *xp;
++ u32 _xid;
++ __be32 *xp;
+
+ read_lock(&sk->sk_callback_lock);
+ dprintk("RPC: xs_udp_data_ready...\n");
+@@ -965,6 +1003,19 @@ static unsigned short xs_get_random_port
+ }
+
+ /**
++ * xs_print_peer_address - format an IPv4 address for printing
++ * @xprt: generic transport
++ * @format: flags field indicating which parts of the address to render
++ */
++static char *xs_print_peer_address(struct rpc_xprt *xprt, enum rpc_display_format_t format)
++{
++ if (xprt->address_strings[format] != NULL)
++ return xprt->address_strings[format];
++ else
++ return "unprintable";
++}
++
++/**
+ * xs_set_port - reset the port number in the remote endpoint address
+ * @xprt: generic transport
+ * @port: new port number
+@@ -972,8 +1023,11 @@ static unsigned short xs_get_random_port
+ */
+ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
+ {
++ struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
++
+ dprintk("RPC: setting port for xprt %p to %u\n", xprt, port);
+- xprt->addr.sin_port = htons(port);
++
++ sap->sin_port = htons(port);
+ }
+
+ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
+@@ -986,7 +1040,7 @@ static int xs_bindresvport(struct rpc_xp
+
+ do {
+ myaddr.sin_port = htons(port);
+- err = sock->ops->bind(sock, (struct sockaddr *) &myaddr,
++ err = kernel_bind(sock, (struct sockaddr *) &myaddr,
+ sizeof(myaddr));
+ if (err == 0) {
+ xprt->port = port;
+@@ -1016,11 +1070,9 @@ static void xs_udp_connect_worker(void *
+ struct socket *sock = xprt->sock;
+ int err, status = -EIO;
+
+- if (xprt->shutdown || xprt->addr.sin_port == 0)
++ if (xprt->shutdown || !xprt_bound(xprt))
+ goto out;
+
+- dprintk("RPC: xs_udp_connect_worker for xprt %p\n", xprt);
+-
+ /* Start by resetting any existing state */
+ xs_close(xprt);
+
+@@ -1034,6 +1086,9 @@ static void xs_udp_connect_worker(void *
+ goto out;
+ }
+
++ dprintk("RPC: worker connecting xprt %p to address: %s\n",
++ xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
++
+ if (!xprt->inet) {
+ struct sock *sk = sock->sk;
+
+@@ -1081,7 +1136,7 @@ static void xs_tcp_reuse_connection(stru
+ */
+ memset(&any, 0, sizeof(any));
+ any.sa_family = AF_UNSPEC;
+- result = sock->ops->connect(sock, &any, sizeof(any), 0);
++ result = kernel_connect(sock, &any, sizeof(any), 0);
+ if (result)
+ dprintk("RPC: AF_UNSPEC connect return code %d\n",
+ result);
+@@ -1099,11 +1154,9 @@ static void xs_tcp_connect_worker(void *
+ struct socket *sock = xprt->sock;
+ int err, status = -EIO;
+
+- if (xprt->shutdown || xprt->addr.sin_port == 0)
++ if (xprt->shutdown || !xprt_bound(xprt))
+ goto out;
+
+- dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt);
+-
+ if (!xprt->sock) {
+ /* start from scratch */
+ if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
+@@ -1119,6 +1172,9 @@ static void xs_tcp_connect_worker(void *
+ /* "close" the socket, preserving the local port */
+ xs_tcp_reuse_connection(xprt);
+
++ dprintk("RPC: worker connecting xprt %p to address: %s\n",
++ xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
++
+ if (!xprt->inet) {
+ struct sock *sk = sock->sk;
+
+@@ -1151,8 +1207,8 @@ static void xs_tcp_connect_worker(void *
+ /* Tell the socket layer to start connecting... */
+ xprt->stat.connect_count++;
+ xprt->stat.connect_start = jiffies;
+- status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
+- sizeof(xprt->addr), O_NONBLOCK);
++ status = kernel_connect(sock, (struct sockaddr *) &xprt->addr,
++ xprt->addrlen, O_NONBLOCK);
+ dprintk("RPC: %p connect status %d connected %d sock state %d\n",
+ xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
+ if (status < 0) {
+@@ -1260,8 +1316,10 @@ static void xs_tcp_print_stats(struct rp
+
+ static struct rpc_xprt_ops xs_udp_ops = {
+ .set_buffer_size = xs_udp_set_buffer_size,
++ .print_addr = xs_print_peer_address,
+ .reserve_xprt = xprt_reserve_xprt_cong,
+ .release_xprt = xprt_release_xprt_cong,
++ .rpcbind = rpc_getport,
+ .set_port = xs_set_port,
+ .connect = xs_connect,
+ .buf_alloc = rpc_malloc,
+@@ -1276,8 +1334,10 @@ static struct rpc_xprt_ops xs_udp_ops =
+ };
+
+ static struct rpc_xprt_ops xs_tcp_ops = {
++ .print_addr = xs_print_peer_address,
+ .reserve_xprt = xprt_reserve_xprt,
+ .release_xprt = xs_tcp_release_xprt,
++ .rpcbind = rpc_getport,
+ .set_port = xs_set_port,
+ .connect = xs_connect,
+ .buf_alloc = rpc_malloc,
+@@ -1298,8 +1358,7 @@ static struct rpc_xprt_ops xs_tcp_ops =
+ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
+ {
+ size_t slot_table_size;
+-
+- dprintk("RPC: setting up udp-ipv4 transport...\n");
++ struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
+
+ xprt->max_reqs = xprt_udp_slot_table_entries;
+ slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]);
+@@ -1307,10 +1366,12 @@ int xs_setup_udp(struct rpc_xprt *xprt,
+ if (xprt->slot == NULL)
+ return -ENOMEM;
+
+- xprt->prot = IPPROTO_UDP;
++ if (ntohs(addr->sin_port) != 0)
++ xprt_set_bound(xprt);
+ xprt->port = xs_get_random_port();
++
++ xprt->prot = IPPROTO_UDP;
+ xprt->tsh_size = 0;
+- xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
+ /* XXX: header size can vary due to auth type, IPv6, etc. */
+ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
+
+@@ -1327,6 +1388,10 @@ int xs_setup_udp(struct rpc_xprt *xprt,
+ else
+ xprt_set_timeout(&xprt->timeout, 5, 5 * HZ);
+
++ xs_format_peer_addresses(xprt);
++ dprintk("RPC: set up transport to address %s\n",
++ xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
++
+ return 0;
+ }
+
+@@ -1339,8 +1404,7 @@ int xs_setup_udp(struct rpc_xprt *xprt,
+ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
+ {
+ size_t slot_table_size;
+-
+- dprintk("RPC: setting up tcp-ipv4 transport...\n");
++ struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
+
+ xprt->max_reqs = xprt_tcp_slot_table_entries;
+ slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]);
+@@ -1348,10 +1412,12 @@ int xs_setup_tcp(struct rpc_xprt *xprt,
+ if (xprt->slot == NULL)
+ return -ENOMEM;
+
+- xprt->prot = IPPROTO_TCP;
++ if (ntohs(addr->sin_port) != 0)
++ xprt_set_bound(xprt);
+ xprt->port = xs_get_random_port();
++
++ xprt->prot = IPPROTO_TCP;
+ xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
+- xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
+ xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
+
+ INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt);
+@@ -1367,5 +1433,9 @@ int xs_setup_tcp(struct rpc_xprt *xprt,
+ else
+ xprt_set_timeout(&xprt->timeout, 2, 60 * HZ);
+
++ xs_format_peer_addresses(xprt);
++ dprintk("RPC: set up transport to address %s\n",
++ xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
++
+ return 0;
+ }
+diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
+index 75a5968..39744a3 100644
+--- a/net/tipc/bearer.c
++++ b/net/tipc/bearer.c
+@@ -2,7 +2,7 @@
+ * net/tipc/bearer.c: TIPC bearer code
+ *
+ * Copyright (c) 1996-2006, Ericsson AB
+- * Copyright (c) 2004-2005, Wind River Systems
++ * Copyright (c) 2004-2006, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+@@ -191,14 +191,14 @@ void tipc_media_addr_printf(struct print
+ if ((i < media_count) && (m_ptr->addr2str != NULL)) {
+ char addr_str[MAX_ADDR_STR];
+
+- tipc_printf(pb, "%s(%s) ", m_ptr->name,
++ tipc_printf(pb, "%s(%s)", m_ptr->name,
+ m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
+ } else {
+ unchar *addr = (unchar *)&a->dev_addr;
+
+- tipc_printf(pb, "UNKNOWN(%u):", media_type);
++ tipc_printf(pb, "UNKNOWN(%u)", media_type);
+ for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
+- tipc_printf(pb, "%02x ", addr[i]);
++ tipc_printf(pb, "-%02x", addr[i]);
+ }
+ }
+ }
+diff --git a/net/tipc/config.c b/net/tipc/config.c
+index 285e1bc..ed1351e 100644
+--- a/net/tipc/config.c
++++ b/net/tipc/config.c
+@@ -2,7 +2,7 @@
+ * net/tipc/config.c: TIPC configuration management code
+ *
+ * Copyright (c) 2002-2006, Ericsson AB
+- * Copyright (c) 2004-2005, Wind River Systems
++ * Copyright (c) 2004-2006, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+@@ -613,7 +613,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig
+ rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
+ break;
+ default:
+- rep_tlv_buf = NULL;
++ rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
++ " (unknown command)");
+ break;
+ }
+
+diff --git a/net/tipc/core.c b/net/tipc/core.c
+index 0539a83..6f5b7ee 100644
+--- a/net/tipc/core.c
++++ b/net/tipc/core.c
+@@ -57,7 +57,7 @@ void tipc_socket_stop(void);
+ int tipc_netlink_start(void);
+ void tipc_netlink_stop(void);
+
+-#define TIPC_MOD_VER "1.6.1"
++#define TIPC_MOD_VER "1.6.2"
+
+ #ifndef CONFIG_TIPC_ZONES
+ #define CONFIG_TIPC_ZONES 3
+@@ -90,7 +90,7 @@ int tipc_random;
+ atomic_t tipc_user_count = ATOMIC_INIT(0);
+
+ const char tipc_alphabet[] =
+- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
+
+ /* configurable TIPC parameters */
+
+diff --git a/net/tipc/core.h b/net/tipc/core.h
+index 762aac2..4638947 100644
+--- a/net/tipc/core.h
++++ b/net/tipc/core.h
+@@ -65,7 +65,7 @@
+ #define assert(i) BUG_ON(!(i))
+
+ struct tipc_msg;
+-extern struct print_buf *TIPC_CONS, *TIPC_LOG;
++extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
+ extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
+ void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
+ void tipc_printf(struct print_buf *, const char *fmt, ...);
+@@ -83,9 +83,9 @@ void tipc_dump(struct print_buf*,const c
+ #define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
+ #define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
+
+-#define dbg(fmt, arg...) do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
+-#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
+-#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
++#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
++#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
++#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+
+
+ /*
+@@ -94,11 +94,11 @@ void tipc_dump(struct print_buf*,const c
+ * here, or on a per .c file basis, by redefining these symbols. The following
+ * print buffer options are available:
+ *
+- * NULL : Output to null print buffer (i.e. print nowhere)
+- * TIPC_CONS : Output to system console
+- * TIPC_LOG : Output to TIPC log buffer
+- * &buf : Output to user-defined buffer (struct print_buf *)
+- * TIPC_TEE(&buf_a,&buf_b) : Output to two print buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG) )
++ * TIPC_NULL : null buffer (i.e. print nowhere)
++ * TIPC_CONS : system console
++ * TIPC_LOG : TIPC log buffer
++ * &buf : user-defined buffer (struct print_buf *)
++ * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
+ */
+
+ #ifndef TIPC_OUTPUT
+@@ -106,7 +106,7 @@ void tipc_dump(struct print_buf*,const c
+ #endif
+
+ #ifndef DBG_OUTPUT
+-#define DBG_OUTPUT NULL
++#define DBG_OUTPUT TIPC_NULL
+ #endif
+
+ #else
+@@ -136,7 +136,7 @@ void tipc_dump(struct print_buf*,const c
+ #define TIPC_OUTPUT TIPC_CONS
+
+ #undef DBG_OUTPUT
+-#define DBG_OUTPUT NULL
++#define DBG_OUTPUT TIPC_NULL
+
+ #endif
+
+@@ -275,11 +275,15 @@ static inline void k_term_timer(struct t
+ /*
+ * TIPC message buffer code
+ *
+- * TIPC message buffer headroom leaves room for 14 byte Ethernet header,
++ * TIPC message buffer headroom reserves space for a link-level header
++ * (in case the message is sent off-node),
+ * while ensuring TIPC header is word aligned for quicker access
++ *
++ * The largest header currently supported is 18 bytes, which is used when
++ * the standard 14 byte Ethernet header has 4 added bytes for VLAN info
+ */
+
+-#define BUF_HEADROOM 16u
++#define BUF_HEADROOM 20u
+
+ struct tipc_skb_cb {
+ void *handle;
+diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
+index 5513065..d8af4c2 100644
+--- a/net/tipc/dbg.c
++++ b/net/tipc/dbg.c
+@@ -1,8 +1,8 @@
+ /*
+- * net/tipc/dbg.c: TIPC print buffer routines for debuggign
++ * net/tipc/dbg.c: TIPC print buffer routines for debugging
+ *
+ * Copyright (c) 1996-2006, Ericsson AB
+- * Copyright (c) 2005, Wind River Systems
++ * Copyright (c) 2005-2006, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+@@ -38,11 +38,12 @@
+ #include "config.h"
+ #include "dbg.h"
+
+-#define MAX_STRING 512
+-
+-static char print_string[MAX_STRING];
++static char print_string[TIPC_PB_MAX_STR];
+ static DEFINE_SPINLOCK(print_lock);
+
++static struct print_buf null_buf = { NULL, 0, NULL, NULL };
++struct print_buf *TIPC_NULL = &null_buf;
++
+ static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
+ struct print_buf *TIPC_CONS = &cons_buf;
+
+@@ -62,68 +63,83 @@ struct print_buf *TIPC_LOG = &log_buf;
+ /*
+ * Locking policy when using print buffers.
+ *
+- * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
+- * simultaneous use of the print buffer(s) being manipulated.
+- * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
+- * 'print_string' and to protect its print buffer(s).
+- * 3) TIPC_TEE() uses 'print_lock' to protect its print buffer(s).
+- * 4) Routines of the form log_XXX() uses 'print_lock' to protect TIPC_LOG.
++ * The following routines use 'print_lock' for protection:
++ * 1) tipc_printf() - to protect its print buffer(s) and 'print_string'
++ * 2) TIPC_TEE() - to protect its print buffer(s)
++ * 3) tipc_dump() - to protect its print buffer(s) and 'print_string'
++ * 4) tipc_log_XXX() - to protect TIPC_LOG
++ *
++ * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
++ * simultaneous use of the print buffer(s) being manipulated.
+ */
+
+ /**
+ * tipc_printbuf_init - initialize print buffer to empty
++ * @pb: pointer to print buffer structure
++ * @raw: pointer to character array used by print buffer
++ * @size: size of character array
++ *
++ * Makes the print buffer a null device that discards anything written to it
++ * if the character array is too small (or absent).
+ */
+
+-void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz)
++void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
+ {
+- if (!pb || !raw || (sz < (MAX_STRING + 1)))
+- return;
+-
+- pb->crs = pb->buf = raw;
+- pb->size = sz;
++ pb->buf = raw;
++ pb->crs = raw;
++ pb->size = size;
+ pb->next = NULL;
+- pb->buf[0] = 0;
+- pb->buf[sz-1] = ~0;
++
++ if (size < TIPC_PB_MIN_SIZE) {
++ pb->buf = NULL;
++ } else if (raw) {
++ pb->buf[0] = 0;
++ pb->buf[size-1] = ~0;
++ }
+ }
+
+ /**
+ * tipc_printbuf_reset - reinitialize print buffer to empty state
++ * @pb: pointer to print buffer structure
+ */
+
+ void tipc_printbuf_reset(struct print_buf *pb)
+ {
+- if (pb && pb->buf)
+- tipc_printbuf_init(pb, pb->buf, pb->size);
++ tipc_printbuf_init(pb, pb->buf, pb->size);
+ }
+
+ /**
+ * tipc_printbuf_empty - test if print buffer is in empty state
++ * @pb: pointer to print buffer structure
++ *
++ * Returns non-zero if print buffer is empty.
+ */
+
+ int tipc_printbuf_empty(struct print_buf *pb)
+ {
+- return (!pb || !pb->buf || (pb->crs == pb->buf));
++ return (!pb->buf || (pb->crs == pb->buf));
+ }
+
+ /**
+ * tipc_printbuf_validate - check for print buffer overflow
++ * @pb: pointer to print buffer structure
+ *
+ * Verifies that a print buffer has captured all data written to it.
+ * If data has been lost, linearize buffer and prepend an error message
+ *
+- * Returns length of print buffer data string (including trailing NULL)
++ * Returns length of print buffer data string (including trailing NUL)
+ */
+
+ int tipc_printbuf_validate(struct print_buf *pb)
+ {
+- char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n";
++ char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n";
+ char *cp_buf;
+ struct print_buf cb;
+
+- if (!pb || !pb->buf)
++ if (!pb->buf)
+ return 0;
+
+- if (pb->buf[pb->size - 1] == '\0') {
++ if (pb->buf[pb->size - 1] == 0) {
+ cp_buf = kmalloc(pb->size, GFP_ATOMIC);
+ if (cp_buf != NULL){
+ tipc_printbuf_init(&cb, cp_buf, pb->size);
+@@ -141,6 +157,8 @@ int tipc_printbuf_validate(struct print_
+
+ /**
+ * tipc_printbuf_move - move print buffer contents to another print buffer
++ * @pb_to: pointer to destination print buffer structure
++ * @pb_from: pointer to source print buffer structure
+ *
+ * Current contents of destination print buffer (if any) are discarded.
+ * Source print buffer becomes empty if a successful move occurs.
+@@ -152,21 +170,22 @@ void tipc_printbuf_move(struct print_buf
+
+ /* Handle the cases where contents can't be moved */
+
+- if (!pb_to || !pb_to->buf)
++ if (!pb_to->buf)
+ return;
+
+- if (!pb_from || !pb_from->buf) {
++ if (!pb_from->buf) {
+ tipc_printbuf_reset(pb_to);
+ return;
+ }
+
+ if (pb_to->size < pb_from->size) {
+ tipc_printbuf_reset(pb_to);
+- tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
++ tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
+ return;
+ }
+
+ /* Copy data from char after cursor to end (if used) */
++
+ len = pb_from->buf + pb_from->size - pb_from->crs - 2;
+ if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
+ strcpy(pb_to->buf, pb_from->crs + 1);
+@@ -175,6 +194,7 @@ void tipc_printbuf_move(struct print_buf
+ pb_to->crs = pb_to->buf;
+
+ /* Copy data from start to cursor (always) */
++
+ len = pb_from->crs - pb_from->buf;
+ strcpy(pb_to->crs, pb_from->buf);
+ pb_to->crs += len;
+@@ -184,6 +204,8 @@ void tipc_printbuf_move(struct print_buf
+
+ /**
+ * tipc_printf - append formatted output to print buffer chain
++ * @pb: pointer to chain of print buffers (may be NULL)
++ * @fmt: formatted info to be printed
+ */
+
+ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
+@@ -195,8 +217,8 @@ void tipc_printf(struct print_buf *pb, c
+
+ spin_lock_bh(&print_lock);
+ FORMAT(print_string, chars_to_add, fmt);
+- if (chars_to_add >= MAX_STRING)
+- strcpy(print_string, "*** STRING TOO LONG ***");
++ if (chars_to_add >= TIPC_PB_MAX_STR)
++ strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
+
+ while (pb) {
+ if (pb == TIPC_CONS)
+@@ -206,6 +228,10 @@ void tipc_printf(struct print_buf *pb, c
+ if (chars_to_add <= chars_left) {
+ strcpy(pb->crs, print_string);
+ pb->crs += chars_to_add;
++ } else if (chars_to_add >= (pb->size - 1)) {
++ strcpy(pb->buf, print_string + chars_to_add + 1
++ - pb->size);
++ pb->crs = pb->buf + pb->size - 1;
+ } else {
+ strcpy(pb->buf, print_string + chars_left);
+ save_char = print_string[chars_left];
+@@ -224,6 +250,10 @@ void tipc_printf(struct print_buf *pb, c
+
+ /**
+ * TIPC_TEE - perform next output operation on both print buffers
++ * @b0: pointer to chain of print buffers (may be NULL)
++ * @b1: pointer to print buffer to add to chain
++ *
++ * Returns pointer to print buffer chain.
+ */
+
+ struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
+@@ -232,8 +262,6 @@ struct print_buf *TIPC_TEE(struct print_
+
+ if (!b0 || (b0 == b1))
+ return b1;
+- if (!b1)
+- return b0;
+
+ spin_lock_bh(&print_lock);
+ while (pb->next) {
+@@ -256,7 +284,7 @@ static void print_to_console(char *crs,
+ int rest = len;
+
+ while (rest > 0) {
+- int sz = rest < MAX_STRING ? rest : MAX_STRING;
++ int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR;
+ char c = crs[sz];
+
+ crs[sz] = 0;
+@@ -275,36 +303,48 @@ static void printbuf_dump(struct print_b
+ {
+ int len;
+
++ if (!pb->buf) {
++ printk("*** PRINT BUFFER NOT ALLOCATED ***");
++ return;
++ }
++
+ /* Dump print buffer from char after cursor to end (if used) */
++
+ len = pb->buf + pb->size - pb->crs - 2;
+ if ((pb->buf[pb->size - 1] == 0) && (len > 0))
+ print_to_console(pb->crs + 1, len);
+
+ /* Dump print buffer from start to cursor (always) */
++
+ len = pb->crs - pb->buf;
+ print_to_console(pb->buf, len);
+ }
+
+ /**
+ * tipc_dump - dump non-console print buffer(s) to console
++ * @pb: pointer to chain of print buffers
+ */
+
+ void tipc_dump(struct print_buf *pb, const char *fmt, ...)
+ {
++ struct print_buf *pb_next;
+ int len;
+
+ spin_lock_bh(&print_lock);
+- FORMAT(TIPC_CONS->buf, len, fmt);
+- printk(TIPC_CONS->buf);
++ FORMAT(print_string, len, fmt);
++ printk(print_string);
+
+ for (; pb; pb = pb->next) {
+- if (pb == TIPC_CONS)
+- continue;
+- printk("\n---- Start of dump,%s log ----\n\n",
+- (pb == TIPC_LOG) ? "global" : "local");
+- printbuf_dump(pb);
+- tipc_printbuf_reset(pb);
+- printk("\n-------- End of dump --------\n");
++ if (pb != TIPC_CONS) {
++ printk("\n---- Start of %s log dump ----\n\n",
++ (pb == TIPC_LOG) ? "global" : "local");
++ printbuf_dump(pb);
++ tipc_printbuf_reset(pb);
++ printk("\n---- End of dump ----\n");
++ }
++ pb_next = pb->next;
++ pb->next = NULL;
++ pb = pb_next;
+ }
+ spin_unlock_bh(&print_lock);
+ }
+@@ -324,7 +364,8 @@ void tipc_log_stop(void)
+ }
+
+ /**
+- * tipc_log_reinit - set TIPC log print buffer to specified size
++ * tipc_log_reinit - (re)initialize TIPC log print buffer
++ * @log_size: print buffer size to use
+ */
+
+ void tipc_log_reinit(int log_size)
+@@ -332,10 +373,11 @@ void tipc_log_reinit(int log_size)
+ tipc_log_stop();
+
+ if (log_size) {
+- if (log_size <= MAX_STRING)
+- log_size = MAX_STRING + 1;
++ if (log_size < TIPC_PB_MIN_SIZE)
++ log_size = TIPC_PB_MIN_SIZE;
+ spin_lock_bh(&print_lock);
+- tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
++ tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
++ log_size);
+ spin_unlock_bh(&print_lock);
+ }
+ }
+diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
+index 227f050..467c0bc 100644
+--- a/net/tipc/dbg.h
++++ b/net/tipc/dbg.h
+@@ -2,7 +2,7 @@
+ * net/tipc/dbg.h: Include file for TIPC print buffer routines
+ *
+ * Copyright (c) 1997-2006, Ericsson AB
+- * Copyright (c) 2005, Wind River Systems
++ * Copyright (c) 2005-2006, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+@@ -37,6 +37,14 @@
+ #ifndef _TIPC_DBG_H
+ #define _TIPC_DBG_H
+
++/**
++ * struct print_buf - TIPC print buffer structure
++ * @buf: pointer to character array containing print buffer contents
++ * @size: size of character array
++ * @crs: pointer to first unused space in character array (i.e. final NUL)
++ * @next: used to link print buffers when printing to more than one at a time
++ */
++
+ struct print_buf {
+ char *buf;
+ u32 size;
+@@ -44,7 +52,10 @@ struct print_buf {
+ struct print_buf *next;
+ };
+
+-void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 sz);
++#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
++#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */
++
++void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size);
+ void tipc_printbuf_reset(struct print_buf *pb);
+ int tipc_printbuf_empty(struct print_buf *pb);
+ int tipc_printbuf_validate(struct print_buf *pb);
+diff --git a/net/tipc/discover.c b/net/tipc/discover.c
+index ee94de9..3b0cd12 100644
+--- a/net/tipc/discover.c
++++ b/net/tipc/discover.c
+@@ -132,6 +132,28 @@ static struct sk_buff *tipc_disc_init_ms
+ }
+
+ /**
++ * disc_dupl_alert - issue node address duplication alert
++ * @b_ptr: pointer to bearer detecting duplication
++ * @node_addr: duplicated node address
++ * @media_addr: media address advertised by duplicated node
++ */
++
++static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
++ struct tipc_media_addr *media_addr)
++{
++ char node_addr_str[16];
++ char media_addr_str[64];
++ struct print_buf pb;
++
++ addr_string_fill(node_addr_str, node_addr);
++ tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str));
++ tipc_media_addr_printf(&pb, media_addr);
++ tipc_printbuf_validate(&pb);
++ warn("Duplicate %s using %s seen on <%s>\n",
++ node_addr_str, media_addr_str, b_ptr->publ.name);
++}
++
++/**
+ * tipc_disc_recv_msg - handle incoming link setup message (request or response)
+ * @buf: buffer containing message
+ */
+@@ -157,8 +179,11 @@ void tipc_disc_recv_msg(struct sk_buff *
+ return;
+ if (!tipc_addr_node_valid(orig))
+ return;
+- if (orig == tipc_own_addr)
++ if (orig == tipc_own_addr) {
++ if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr)))
++ disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
+ return;
++ }
+ if (!in_scope(dest, tipc_own_addr))
+ return;
+ if (is_slave(tipc_own_addr) && is_slave(orig))
+@@ -170,7 +195,8 @@ void tipc_disc_recv_msg(struct sk_buff *
+ struct sk_buff *rbuf;
+ struct tipc_media_addr *addr;
+ struct node *n_ptr = tipc_node_find(orig);
+- int link_up;
++ int link_fully_up;
++
+ dbg(" in own cluster\n");
+ if (n_ptr == NULL) {
+ n_ptr = tipc_node_create(orig);
+@@ -190,14 +216,19 @@ void tipc_disc_recv_msg(struct sk_buff *
+ }
+ addr = &link->media_addr;
+ if (memcmp(addr, &media_addr, sizeof(*addr))) {
++ if (tipc_link_is_up(link) || (!link->started)) {
++ disc_dupl_alert(b_ptr, orig, &media_addr);
++ spin_unlock_bh(&n_ptr->lock);
++ return;
++ }
+ warn("Resetting link <%s>, peer interface address changed\n",
+ link->name);
+ memcpy(addr, &media_addr, sizeof(*addr));
+ tipc_link_reset(link);
+ }
+- link_up = tipc_link_is_up(link);
++ link_fully_up = (link->state == WORKING_WORKING);
+ spin_unlock_bh(&n_ptr->lock);
+- if ((type == DSC_RESP_MSG) || link_up)
++ if ((type == DSC_RESP_MSG) || link_fully_up)
+ return;
+ rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
+ if (rbuf != NULL) {
+diff --git a/net/tipc/link.c b/net/tipc/link.c
+index 693f02e..1bb983c 100644
+--- a/net/tipc/link.c
++++ b/net/tipc/link.c
+@@ -132,7 +132,7 @@ static void link_print(struct link *l_pt
+ * allow the output from multiple links to be intermixed. For this reason
+ * routines of the form "dbg_link_XXX()" have been created that will capture
+ * debug info into a link's personal print buffer, which can then be dumped
+- * into the TIPC system log (LOG) upon request.
++ * into the TIPC system log (TIPC_LOG) upon request.
+ *
+ * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
+ * of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
+@@ -141,7 +141,7 @@ static void link_print(struct link *l_pt
+ * when there is only a single link in the system being debugged.
+ *
+ * Notes:
+- * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
++ * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
+ * - "l_ptr" must be valid when using dbg_link_XXX() macros
+ */
+
+@@ -159,13 +159,13 @@ static void link_print(struct link *l_pt
+
+ static void dbg_print_link(struct link *l_ptr, const char *str)
+ {
+- if (DBG_OUTPUT)
++ if (DBG_OUTPUT != TIPC_NULL)
+ link_print(l_ptr, DBG_OUTPUT, str);
+ }
+
+ static void dbg_print_buf_chain(struct sk_buff *root_buf)
+ {
+- if (DBG_OUTPUT) {
++ if (DBG_OUTPUT != TIPC_NULL) {
+ struct sk_buff *buf = root_buf;
+
+ while (buf) {
+@@ -1666,8 +1666,9 @@ static void link_retransmit_failure(stru
+ char addr_string[16];
+
+ tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
+- tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle);
+-
++ tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
++ (unsigned long) TIPC_SKB_CB(buf)->handle);
++
+ n_ptr = l_ptr->owner->next;
+ tipc_node_lock(n_ptr);
+
+diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
+index f0b063b..03bd659 100644
+--- a/net/tipc/name_distr.c
++++ b/net/tipc/name_distr.c
+@@ -122,7 +122,7 @@ void tipc_named_publish(struct publicati
+ struct sk_buff *buf;
+ struct distr_item *item;
+
+- list_add(&publ->local_list, &publ_root);
++ list_add_tail(&publ->local_list, &publ_root);
+ publ_cnt++;
+
+ buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
+diff --git a/net/tipc/node.c b/net/tipc/node.c
+index fc6d096..886bda5 100644
+--- a/net/tipc/node.c
++++ b/net/tipc/node.c
+@@ -648,7 +648,7 @@ struct sk_buff *tipc_node_get_links(cons
+ return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+ " (network address)");
+
+- if (!tipc_nodes)
++ if (tipc_mode != TIPC_NET_MODE)
+ return tipc_cfg_reply_none();
+
+ /* Get space for all unicast links + multicast link */
+diff --git a/net/tipc/port.c b/net/tipc/port.c
+index b9c8c6b..b7f3199 100644
+--- a/net/tipc/port.c
++++ b/net/tipc/port.c
+@@ -505,8 +505,13 @@ static void port_timeout(unsigned long r
+ struct port *p_ptr = tipc_port_lock(ref);
+ struct sk_buff *buf = NULL;
+
+- if (!p_ptr || !p_ptr->publ.connected)
++ if (!p_ptr)
++ return;
++
++ if (!p_ptr->publ.connected) {
++ tipc_port_unlock(p_ptr);
+ return;
++ }
+
+ /* Last probe answered ? */
+ if (p_ptr->probing_state == PROBING) {
+@@ -1131,11 +1136,12 @@ int tipc_publish(u32 ref, unsigned int s
+ int res = -EINVAL;
+
+ p_ptr = tipc_port_lock(ref);
++ if (!p_ptr)
++ return -EINVAL;
++
+ dbg("tipc_publ %u, p_ptr = %x, conn = %x, scope = %x, "
+ "lower = %u, upper = %u\n",
+ ref, p_ptr, p_ptr->publ.connected, scope, seq->lower, seq->upper);
+- if (!p_ptr)
+- return -EINVAL;
+ if (p_ptr->publ.connected)
+ goto exit;
+ if (seq->lower > seq->upper)
+diff --git a/net/tipc/socket.c b/net/tipc/socket.c
+index 32d7784..2a6a5a6 100644
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -2,7 +2,7 @@
+ * net/tipc/socket.c: TIPC socket API
+ *
+ * Copyright (c) 2001-2006, Ericsson AB
+- * Copyright (c) 2004-2005, Wind River Systems
++ * Copyright (c) 2004-2006, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+@@ -629,6 +629,9 @@ static int send_stream(struct kiocb *ioc
+ return -ENOTCONN;
+ }
+
++ if (unlikely(m->msg_name))
++ return -EISCONN;
++
+ /*
+ * Send each iovec entry using one or more messages
+ *
+@@ -641,6 +644,8 @@ static int send_stream(struct kiocb *ioc
+ curr_iovlen = m->msg_iovlen;
+ my_msg.msg_iov = &my_iov;
+ my_msg.msg_iovlen = 1;
++ my_msg.msg_flags = m->msg_flags;
++ my_msg.msg_name = NULL;
+ bytes_sent = 0;
+
+ while (curr_iovlen--) {
+@@ -941,7 +946,7 @@ static int recv_stream(struct kiocb *ioc
+ int sz_to_copy;
+ int sz_copied = 0;
+ int needed;
+- char *crs = m->msg_iov->iov_base;
++ char __user *crs = m->msg_iov->iov_base;
+ unsigned char *buf_crs;
+ u32 err;
+ int res;
+@@ -1203,7 +1208,8 @@ static u32 dispatch(struct tipc_port *tp
+ atomic_inc(&tipc_queue_size);
+ skb_queue_tail(&sock->sk->sk_receive_queue, buf);
+
+- wake_up_interruptible(sock->sk->sk_sleep);
++ if (waitqueue_active(sock->sk->sk_sleep))
++ wake_up_interruptible(sock->sk->sk_sleep);
+ return TIPC_OK;
+ }
+
+@@ -1218,7 +1224,8 @@ static void wakeupdispatch(struct tipc_p
+ {
+ struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
+
+- wake_up_interruptible(tsock->sk.sk_sleep);
++ if (waitqueue_active(tsock->sk.sk_sleep))
++ wake_up_interruptible(tsock->sk.sk_sleep);
+ }
+
+ /**
+@@ -1496,7 +1503,7 @@ static int setsockopt(struct socket *soc
+ return -ENOPROTOOPT;
+ if (ol < sizeof(value))
+ return -EINVAL;
+- if ((res = get_user(value, (u32 *)ov)))
++ if ((res = get_user(value, (u32 __user *)ov)))
+ return res;
+
+ if (down_interruptible(&tsock->sem))
+@@ -1541,7 +1548,7 @@ static int setsockopt(struct socket *soc
+ */
+
+ static int getsockopt(struct socket *sock,
+- int lvl, int opt, char __user *ov, int *ol)
++ int lvl, int opt, char __user *ov, int __user *ol)
+ {
+ struct tipc_sock *tsock = tipc_sk(sock->sk);
+ int len;
+diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
+index c51600b..7a918f1 100644
+--- a/net/tipc/subscr.c
++++ b/net/tipc/subscr.c
+@@ -155,7 +155,7 @@ void tipc_subscr_report_overlap(struct s
+ sub->seq.upper, found_lower, found_upper);
+ if (!tipc_subscr_overlap(sub, found_lower, found_upper))
+ return;
+- if (!must && (sub->filter != TIPC_SUB_PORTS))
++ if (!must && !(sub->filter & TIPC_SUB_PORTS))
+ return;
+ subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+ }
+@@ -176,6 +176,13 @@ static void subscr_timeout(struct subscr
+ if (subscriber == NULL)
+ return;
+
++ /* Validate timeout (in case subscription is being cancelled) */
++
++ if (sub->timeout == TIPC_WAIT_FOREVER) {
++ tipc_ref_unlock(subscriber_ref);
++ return;
++ }
++
+ /* Unlink subscription from name table */
+
+ tipc_nametbl_unsubscribe(sub);
+@@ -199,6 +206,20 @@ static void subscr_timeout(struct subscr
+ }
+
+ /**
++ * subscr_del - delete a subscription within a subscription list
++ *
++ * Called with subscriber locked.
++ */
++
++static void subscr_del(struct subscription *sub)
++{
++ tipc_nametbl_unsubscribe(sub);
++ list_del(&sub->subscription_list);
++ kfree(sub);
++ atomic_dec(&topsrv.subscription_count);
++}
++
++/**
+ * subscr_terminate - terminate communication with a subscriber
+ *
+ * Called with subscriber locked. Routine must temporarily release this lock
+@@ -227,12 +248,9 @@ static void subscr_terminate(struct subs
+ k_cancel_timer(&sub->timer);
+ k_term_timer(&sub->timer);
+ }
+- tipc_nametbl_unsubscribe(sub);
+- list_del(&sub->subscription_list);
+- dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
++ dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n",
+ sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
+- kfree(sub);
+- atomic_dec(&topsrv.subscription_count);
++ subscr_del(sub);
+ }
+
+ /* Sever connection to subscriber */
+@@ -253,6 +271,49 @@ static void subscr_terminate(struct subs
+ }
+
+ /**
++ * subscr_cancel - handle subscription cancellation request
++ *
++ * Called with subscriber locked. Routine must temporarily release this lock
++ * to enable the subscription timeout routine to finish without deadlocking;
++ * the lock is then reclaimed to allow caller to release it upon return.
++ *
++ * Note that fields of 's' use subscriber's endianness!
++ */
++
++static void subscr_cancel(struct tipc_subscr *s,
++ struct subscriber *subscriber)
++{
++ struct subscription *sub;
++ struct subscription *sub_temp;
++ int found = 0;
++
++ /* Find first matching subscription, exit if not found */
++
++ list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
++ subscription_list) {
++ if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
++ found = 1;
++ break;
++ }
++ }
++ if (!found)
++ return;
++
++ /* Cancel subscription timer (if used), then delete subscription */
++
++ if (sub->timeout != TIPC_WAIT_FOREVER) {
++ sub->timeout = TIPC_WAIT_FOREVER;
++ spin_unlock_bh(subscriber->lock);
++ k_cancel_timer(&sub->timer);
++ k_term_timer(&sub->timer);
++ spin_lock_bh(subscriber->lock);
++ }
++ dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
++ sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
++ subscr_del(sub);
++}
++
++/**
+ * subscr_subscribe - create subscription for subscriber
+ *
+ * Called with subscriber locked
+@@ -263,6 +324,21 @@ static void subscr_subscribe(struct tipc
+ {
+ struct subscription *sub;
+
++ /* Determine/update subscriber's endianness */
++
++ if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
++ subscriber->swap = 0;
++ else
++ subscriber->swap = 1;
++
++ /* Detect & process a subscription cancellation request */
++
++ if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
++ s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
++ subscr_cancel(s, subscriber);
++ return;
++ }
++
+ /* Refuse subscription if global limit exceeded */
+
+ if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
+@@ -281,13 +357,6 @@ static void subscr_subscribe(struct tipc
+ return;
+ }
+
+- /* Determine/update subscriber's endianness */
+-
+- if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
+- subscriber->swap = 0;
+- else
+- subscriber->swap = 1;
+-
+ /* Initialize subscription object */
+
+ memset(sub, 0, sizeof(*sub));
+@@ -296,8 +365,8 @@ static void subscr_subscribe(struct tipc
+ sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
+ sub->timeout = htohl(s->timeout, subscriber->swap);
+ sub->filter = htohl(s->filter, subscriber->swap);
+- if ((((sub->filter != TIPC_SUB_PORTS)
+- && (sub->filter != TIPC_SUB_SERVICE)))
++ if ((!(sub->filter & TIPC_SUB_PORTS)
++ == !(sub->filter & TIPC_SUB_SERVICE))
+ || (sub->seq.lower > sub->seq.upper)) {
+ warn("Subscription rejected, illegal request\n");
+ kfree(sub);
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index de6ec51..b43a278 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -117,7 +117,7 @@
+ #include <net/checksum.h>
+ #include <linux/security.h>
+
+-int sysctl_unix_max_dgram_qlen = 10;
++int sysctl_unix_max_dgram_qlen __read_mostly = 10;
+
+ struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
+ DEFINE_SPINLOCK(unix_table_lock);
+@@ -2060,10 +2060,7 @@ static int __init af_unix_init(void)
+ int rc = -1;
+ struct sk_buff *dummy_skb;
+
+- if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)) {
+- printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
+- goto out;
+- }
++ BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb));
+
+ rc = proto_register(&unix_proto, 1);
+ if (rc != 0) {
+diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
+index 0c1c043..0faab63 100644
+--- a/net/xfrm/Kconfig
++++ b/net/xfrm/Kconfig
+@@ -6,14 +6,24 @@ config XFRM
+ depends on NET
+
+ config XFRM_USER
+- tristate "IPsec user configuration interface"
++ tristate "Transformation user configuration interface"
+ depends on INET && XFRM
+ ---help---
+- Support for IPsec user configuration interface used
+- by native Linux tools.
++ Support for Transformation(XFRM) user configuration interface
++ like IPsec used by native Linux tools.
+
+ If unsure, say Y.
+
++config XFRM_SUB_POLICY
++ bool "Transformation sub policy support (EXPERIMENTAL)"
++ depends on XFRM && EXPERIMENTAL
++ ---help---
++ Support sub policy for developers. By using sub policy with main
++ one, two policies can be applied to the same packet at once.
++ Policy which lives shorter time in kernel should be a sub.
++
++ If unsure, say N.
++
+ config NET_KEY
+ tristate "PF_KEY sockets"
+ select XFRM
+diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile
+index 693aac1..de3c1a6 100644
+--- a/net/xfrm/Makefile
++++ b/net/xfrm/Makefile
+@@ -2,6 +2,7 @@
+ # Makefile for the XFRM subsystem.
+ #
+
+-obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o
++obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
++ xfrm_input.o xfrm_algo.o
+ obj-$(CONFIG_XFRM_USER) += xfrm_user.o
+
+diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
+index 04e1aea..5a0dbeb 100644
+--- a/net/xfrm/xfrm_algo.c
++++ b/net/xfrm/xfrm_algo.c
+@@ -30,7 +30,8 @@
+ */
+ static struct xfrm_algo_desc aalg_list[] = {
+ {
+- .name = "digest_null",
++ .name = "hmac(digest_null)",
++ .compat = "digest_null",
+
+ .uinfo = {
+ .auth = {
+@@ -47,7 +48,8 @@ static struct xfrm_algo_desc aalg_list[]
+ }
+ },
+ {
+- .name = "md5",
++ .name = "hmac(md5)",
++ .compat = "md5",
+
+ .uinfo = {
+ .auth = {
+@@ -64,7 +66,8 @@ static struct xfrm_algo_desc aalg_list[]
+ }
+ },
+ {
+- .name = "sha1",
++ .name = "hmac(sha1)",
++ .compat = "sha1",
+
+ .uinfo = {
+ .auth = {
+@@ -81,7 +84,8 @@ static struct xfrm_algo_desc aalg_list[]
+ }
+ },
+ {
+- .name = "sha256",
++ .name = "hmac(sha256)",
++ .compat = "sha256",
+
+ .uinfo = {
+ .auth = {
+@@ -98,7 +102,8 @@ static struct xfrm_algo_desc aalg_list[]
+ }
+ },
+ {
+- .name = "ripemd160",
++ .name = "hmac(ripemd160)",
++ .compat = "ripemd160",
+
+ .uinfo = {
+ .auth = {
+@@ -118,7 +123,8 @@ static struct xfrm_algo_desc aalg_list[]
+
+ static struct xfrm_algo_desc ealg_list[] = {
+ {
+- .name = "cipher_null",
++ .name = "ecb(cipher_null)",
++ .compat = "cipher_null",
+
+ .uinfo = {
+ .encr = {
+@@ -135,7 +141,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "des",
++ .name = "cbc(des)",
++ .compat = "des",
+
+ .uinfo = {
+ .encr = {
+@@ -152,7 +159,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "des3_ede",
++ .name = "cbc(des3_ede)",
++ .compat = "des3_ede",
+
+ .uinfo = {
+ .encr = {
+@@ -169,7 +177,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "cast128",
++ .name = "cbc(cast128)",
++ .compat = "cast128",
+
+ .uinfo = {
+ .encr = {
+@@ -186,7 +195,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "blowfish",
++ .name = "cbc(blowfish)",
++ .compat = "blowfish",
+
+ .uinfo = {
+ .encr = {
+@@ -203,7 +213,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "aes",
++ .name = "cbc(aes)",
++ .compat = "aes",
+
+ .uinfo = {
+ .encr = {
+@@ -220,7 +231,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "serpent",
++ .name = "cbc(serpent)",
++ .compat = "serpent",
+
+ .uinfo = {
+ .encr = {
+@@ -237,7 +249,8 @@ static struct xfrm_algo_desc ealg_list[]
+ }
+ },
+ {
+- .name = "twofish",
++ .name = "cbc(twofish)",
++ .compat = "twofish",
+
+ .uinfo = {
+ .encr = {
+@@ -350,8 +363,8 @@ struct xfrm_algo_desc *xfrm_calg_get_byi
+ EXPORT_SYMBOL_GPL(xfrm_calg_get_byid);
+
+ static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list,
+- int entries, char *name,
+- int probe)
++ int entries, u32 type, u32 mask,
++ char *name, int probe)
+ {
+ int i, status;
+
+@@ -359,7 +372,8 @@ static struct xfrm_algo_desc *xfrm_get_b
+ return NULL;
+
+ for (i = 0; i < entries; i++) {
+- if (strcmp(name, list[i].name))
++ if (strcmp(name, list[i].name) &&
++ (!list[i].compat || strcmp(name, list[i].compat)))
+ continue;
+
+ if (list[i].available)
+@@ -368,7 +382,7 @@ static struct xfrm_algo_desc *xfrm_get_b
+ if (!probe)
+ break;
+
+- status = crypto_alg_available(name, 0);
++ status = crypto_has_alg(name, type, mask | CRYPTO_ALG_ASYNC);
+ if (!status)
+ break;
+
+@@ -380,19 +394,25 @@ static struct xfrm_algo_desc *xfrm_get_b
+
+ struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe)
+ {
+- return xfrm_get_byname(aalg_list, aalg_entries(), name, probe);
++ return xfrm_get_byname(aalg_list, aalg_entries(),
++ CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_HASH_MASK,
++ name, probe);
+ }
+ EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname);
+
+ struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe)
+ {
+- return xfrm_get_byname(ealg_list, ealg_entries(), name, probe);
++ return xfrm_get_byname(ealg_list, ealg_entries(),
++ CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_MASK,
++ name, probe);
+ }
+ EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname);
+
+ struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
+ {
+- return xfrm_get_byname(calg_list, calg_entries(), name, probe);
++ return xfrm_get_byname(calg_list, calg_entries(),
++ CRYPTO_ALG_TYPE_COMPRESS, CRYPTO_ALG_TYPE_MASK,
++ name, probe);
+ }
+ EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
+
+@@ -427,19 +447,22 @@ void xfrm_probe_algs(void)
+ BUG_ON(in_softirq());
+
+ for (i = 0; i < aalg_entries(); i++) {
+- status = crypto_alg_available(aalg_list[i].name, 0);
++ status = crypto_has_hash(aalg_list[i].name, 0,
++ CRYPTO_ALG_ASYNC);
+ if (aalg_list[i].available != status)
+ aalg_list[i].available = status;
+ }
+
+ for (i = 0; i < ealg_entries(); i++) {
+- status = crypto_alg_available(ealg_list[i].name, 0);
++ status = crypto_has_blkcipher(ealg_list[i].name, 0,
++ CRYPTO_ALG_ASYNC);
+ if (ealg_list[i].available != status)
+ ealg_list[i].available = status;
+ }
+
+ for (i = 0; i < calg_entries(); i++) {
+- status = crypto_alg_available(calg_list[i].name, 0);
++ status = crypto_has_comp(calg_list[i].name, 0,
++ CRYPTO_ALG_ASYNC);
+ if (calg_list[i].available != status)
+ calg_list[i].available = status;
+ }
+@@ -471,11 +494,12 @@ EXPORT_SYMBOL_GPL(xfrm_count_enc_support
+
+ /* Move to common area: it is shared with AH. */
+
+-void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
+- int offset, int len, icv_update_fn_t icv_update)
++int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
++ int offset, int len, icv_update_fn_t icv_update)
+ {
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
++ int err;
+ struct scatterlist sg;
+
+ /* Checksum header. */
+@@ -487,10 +511,12 @@ void skb_icv_walk(const struct sk_buff *
+ sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
+ sg.length = copy;
+
+- icv_update(tfm, &sg, 1);
++ err = icv_update(desc, &sg, copy);
++ if (unlikely(err))
++ return err;
+
+ if ((len -= copy) == 0)
+- return;
++ return 0;
+ offset += copy;
+ }
+
+@@ -510,10 +536,12 @@ void skb_icv_walk(const struct sk_buff *
+ sg.offset = frag->page_offset + offset-start;
+ sg.length = copy;
+
+- icv_update(tfm, &sg, 1);
++ err = icv_update(desc, &sg, copy);
++ if (unlikely(err))
++ return err;
+
+ if (!(len -= copy))
+- return;
++ return 0;
+ offset += copy;
+ }
+ start = end;
+@@ -531,15 +559,19 @@ void skb_icv_walk(const struct sk_buff *
+ if ((copy = end - offset) > 0) {
+ if (copy > len)
+ copy = len;
+- skb_icv_walk(list, tfm, offset-start, copy, icv_update);
++ err = skb_icv_walk(list, desc, offset-start,
++ copy, icv_update);
++ if (unlikely(err))
++ return err;
+ if ((len -= copy) == 0)
+- return;
++ return 0;
+ offset += copy;
+ }
+ start = end;
+ }
+ }
+ BUG_ON(len);
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(skb_icv_walk);
+
+diff --git a/net/xfrm/xfrm_hash.c b/net/xfrm/xfrm_hash.c
+new file mode 100644
+index 0000000..37643bb
+--- /dev/null
++++ b/net/xfrm/xfrm_hash.c
+@@ -0,0 +1,41 @@
++/* xfrm_hash.c: Common hash table code.
++ *
++ * Copyright (C) 2006 David S. Miller (davem at davemloft.net)
++ */
++
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/bootmem.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
++#include <linux/xfrm.h>
++
++#include "xfrm_hash.h"
++
++struct hlist_head *xfrm_hash_alloc(unsigned int sz)
++{
++ struct hlist_head *n;
++
++ if (sz <= PAGE_SIZE)
++ n = kmalloc(sz, GFP_KERNEL);
++ else if (hashdist)
++ n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);
++ else
++ n = (struct hlist_head *)
++ __get_free_pages(GFP_KERNEL, get_order(sz));
++
++ if (n)
++ memset(n, 0, sz);
++
++ return n;
++}
++
++void xfrm_hash_free(struct hlist_head *n, unsigned int sz)
++{
++ if (sz <= PAGE_SIZE)
++ kfree(n);
++ else if (hashdist)
++ vfree(n);
++ else
++ free_pages((unsigned long)n, get_order(sz));
++}
+diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
+new file mode 100644
+index 0000000..d401dc8
+--- /dev/null
++++ b/net/xfrm/xfrm_hash.h
+@@ -0,0 +1,129 @@
++#ifndef _XFRM_HASH_H
++#define _XFRM_HASH_H
++
++#include <linux/xfrm.h>
++#include <linux/socket.h>
++
++static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
++{
++ return ntohl(addr->a4);
++}
++
++static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
++{
++ return ntohl(addr->a6[2] ^ addr->a6[3]);
++}
++
++static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
++{
++ return ntohl(daddr->a4 ^ saddr->a4);
++}
++
++static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
++{
++ return ntohl(daddr->a6[2] ^ daddr->a6[3] ^
++ saddr->a6[2] ^ saddr->a6[3]);
++}
++
++static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr,
++ u32 reqid, unsigned short family,
++ unsigned int hmask)
++{
++ unsigned int h = family ^ reqid;
++ switch (family) {
++ case AF_INET:
++ h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
++ break;
++ case AF_INET6:
++ h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
++ break;
++ }
++ return (h ^ (h >> 16)) & hmask;
++}
++
++static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
++ xfrm_address_t *saddr,
++ unsigned short family,
++ unsigned int hmask)
++{
++ unsigned int h = family;
++ switch (family) {
++ case AF_INET:
++ h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
++ break;
++ case AF_INET6:
++ h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
++ break;
++ };
++ return (h ^ (h >> 16)) & hmask;
++}
++
++static inline unsigned int
++__xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,
++ unsigned int hmask)
++{
++ unsigned int h = (__force u32)spi ^ proto;
++ switch (family) {
++ case AF_INET:
++ h ^= __xfrm4_addr_hash(daddr);
++ break;
++ case AF_INET6:
++ h ^= __xfrm6_addr_hash(daddr);
++ break;
++ }
++ return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
++}
++
++static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
++{
++ return (index ^ (index >> 8)) & hmask;
++}
++
++static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask)
++{
++ xfrm_address_t *daddr = &sel->daddr;
++ xfrm_address_t *saddr = &sel->saddr;
++ unsigned int h = 0;
++
++ switch (family) {
++ case AF_INET:
++ if (sel->prefixlen_d != 32 ||
++ sel->prefixlen_s != 32)
++ return hmask + 1;
++
++ h = __xfrm4_daddr_saddr_hash(daddr, saddr);
++ break;
++
++ case AF_INET6:
++ if (sel->prefixlen_d != 128 ||
++ sel->prefixlen_s != 128)
++ return hmask + 1;
++
++ h = __xfrm6_daddr_saddr_hash(daddr, saddr);
++ break;
++ };
++ h ^= (h >> 16);
++ return h & hmask;
++}
++
++static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask)
++{
++ unsigned int h = 0;
++
++ switch (family) {
++ case AF_INET:
++ h = __xfrm4_daddr_saddr_hash(daddr, saddr);
++ break;
++
++ case AF_INET6:
++ h = __xfrm6_daddr_saddr_hash(daddr, saddr);
++ break;
++ };
++ h ^= (h >> 16);
++ return h & hmask;
++}
++
++extern struct hlist_head *xfrm_hash_alloc(unsigned int sz);
++extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz);
++
++#endif /* _XFRM_HASH_H */
+diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
+index 891a609..e8198a2 100644
+--- a/net/xfrm/xfrm_input.c
++++ b/net/xfrm/xfrm_input.c
+@@ -46,7 +46,7 @@ EXPORT_SYMBOL(secpath_dup);
+
+ /* Fetch spi and seq from ipsec header */
+
+-int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
++int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
+ {
+ int offset, offset_seq;
+
+@@ -62,7 +62,7 @@ int xfrm_parse_spi(struct sk_buff *skb,
+ case IPPROTO_COMP:
+ if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
+ return -EINVAL;
+- *spi = htonl(ntohs(*(u16*)(skb->h.raw + 2)));
++ *spi = htonl(ntohs(*(__be16*)(skb->h.raw + 2)));
+ *seq = 0;
+ return 0;
+ default:
+@@ -72,8 +72,8 @@ int xfrm_parse_spi(struct sk_buff *skb,
+ if (!pskb_may_pull(skb, 16))
+ return -EINVAL;
+
+- *spi = *(u32*)(skb->h.raw + offset);
+- *seq = *(u32*)(skb->h.raw + offset_seq);
++ *spi = *(__be32*)(skb->h.raw + offset);
++ *seq = *(__be32*)(skb->h.raw + offset_seq);
+ return 0;
+ }
+ EXPORT_SYMBOL(xfrm_parse_spi);
+@@ -82,8 +82,6 @@ void __init xfrm_input_init(void)
+ {
+ secpath_cachep = kmem_cache_create("secpath_cache",
+ sizeof(struct sec_path),
+- 0, SLAB_HWCACHE_ALIGN,
++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+- if (!secpath_cachep)
+- panic("XFRM: failed to allocate secpath_cache\n");
+ }
+diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
+index 3da67ca..7736b23 100644
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -22,16 +22,19 @@
+ #include <linux/netdevice.h>
+ #include <linux/netfilter.h>
+ #include <linux/module.h>
++#include <linux/cache.h>
+ #include <net/xfrm.h>
+ #include <net/ip.h>
+
++#include "xfrm_hash.h"
++
+ DEFINE_MUTEX(xfrm_cfg_mutex);
+ EXPORT_SYMBOL(xfrm_cfg_mutex);
+
+ static DEFINE_RWLOCK(xfrm_policy_lock);
+
+-struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2];
+-EXPORT_SYMBOL(xfrm_policy_list);
++unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
++EXPORT_SYMBOL(xfrm_policy_count);
+
+ static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
+ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
+@@ -39,8 +42,7 @@ static struct xfrm_policy_afinfo *xfrm_p
+ static kmem_cache_t *xfrm_dst_cache __read_mostly;
+
+ static struct work_struct xfrm_policy_gc_work;
+-static struct list_head xfrm_policy_gc_list =
+- LIST_HEAD_INIT(xfrm_policy_gc_list);
++static HLIST_HEAD(xfrm_policy_gc_list);
+ static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
+
+ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
+@@ -310,8 +312,10 @@ struct xfrm_policy *xfrm_policy_alloc(gf
+ policy = kzalloc(sizeof(struct xfrm_policy), gfp);
+
+ if (policy) {
+- atomic_set(&policy->refcnt, 1);
++ INIT_HLIST_NODE(&policy->bydst);
++ INIT_HLIST_NODE(&policy->byidx);
+ rwlock_init(&policy->lock);
++ atomic_set(&policy->refcnt, 1);
+ init_timer(&policy->timer);
+ policy->timer.data = (unsigned long)policy;
+ policy->timer.function = xfrm_policy_timer;
+@@ -357,17 +361,16 @@ static void xfrm_policy_gc_kill(struct x
+ static void xfrm_policy_gc_task(void *data)
+ {
+ struct xfrm_policy *policy;
+- struct list_head *entry, *tmp;
+- struct list_head gc_list = LIST_HEAD_INIT(gc_list);
++ struct hlist_node *entry, *tmp;
++ struct hlist_head gc_list;
+
+ spin_lock_bh(&xfrm_policy_gc_lock);
+- list_splice_init(&xfrm_policy_gc_list, &gc_list);
++ gc_list.first = xfrm_policy_gc_list.first;
++ INIT_HLIST_HEAD(&xfrm_policy_gc_list);
+ spin_unlock_bh(&xfrm_policy_gc_lock);
+
+- list_for_each_safe(entry, tmp, &gc_list) {
+- policy = list_entry(entry, struct xfrm_policy, list);
++ hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst)
+ xfrm_policy_gc_kill(policy);
+- }
+ }
+
+ /* Rule must be locked. Release descentant resources, announce
+@@ -389,70 +392,275 @@ static void xfrm_policy_kill(struct xfrm
+ }
+
+ spin_lock(&xfrm_policy_gc_lock);
+- list_add(&policy->list, &xfrm_policy_gc_list);
++ hlist_add_head(&policy->bydst, &xfrm_policy_gc_list);
+ spin_unlock(&xfrm_policy_gc_lock);
+
+ schedule_work(&xfrm_policy_gc_work);
+ }
+
++struct xfrm_policy_hash {
++ struct hlist_head *table;
++ unsigned int hmask;
++};
++
++static struct hlist_head xfrm_policy_inexact[XFRM_POLICY_MAX*2];
++static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly;
++static struct hlist_head *xfrm_policy_byidx __read_mostly;
++static unsigned int xfrm_idx_hmask __read_mostly;
++static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
++
++static inline unsigned int idx_hash(u32 index)
++{
++ return __idx_hash(index, xfrm_idx_hmask);
++}
++
++static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir)
++{
++ unsigned int hmask = xfrm_policy_bydst[dir].hmask;
++ unsigned int hash = __sel_hash(sel, family, hmask);
++
++ return (hash == hmask + 1 ?
++ &xfrm_policy_inexact[dir] :
++ xfrm_policy_bydst[dir].table + hash);
++}
++
++static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir)
++{
++ unsigned int hmask = xfrm_policy_bydst[dir].hmask;
++ unsigned int hash = __addr_hash(daddr, saddr, family, hmask);
++
++ return xfrm_policy_bydst[dir].table + hash;
++}
++
++static void xfrm_dst_hash_transfer(struct hlist_head *list,
++ struct hlist_head *ndsttable,
++ unsigned int nhashmask)
++{
++ struct hlist_node *entry, *tmp;
++ struct xfrm_policy *pol;
++
++ hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) {
++ unsigned int h;
++
++ h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
++ pol->family, nhashmask);
++ hlist_add_head(&pol->bydst, ndsttable+h);
++ }
++}
++
++static void xfrm_idx_hash_transfer(struct hlist_head *list,
++ struct hlist_head *nidxtable,
++ unsigned int nhashmask)
++{
++ struct hlist_node *entry, *tmp;
++ struct xfrm_policy *pol;
++
++ hlist_for_each_entry_safe(pol, entry, tmp, list, byidx) {
++ unsigned int h;
++
++ h = __idx_hash(pol->index, nhashmask);
++ hlist_add_head(&pol->byidx, nidxtable+h);
++ }
++}
++
++static unsigned long xfrm_new_hash_mask(unsigned int old_hmask)
++{
++ return ((old_hmask + 1) << 1) - 1;
++}
++
++static void xfrm_bydst_resize(int dir)
++{
++ unsigned int hmask = xfrm_policy_bydst[dir].hmask;
++ unsigned int nhashmask = xfrm_new_hash_mask(hmask);
++ unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
++ struct hlist_head *odst = xfrm_policy_bydst[dir].table;
++ struct hlist_head *ndst = xfrm_hash_alloc(nsize);
++ int i;
++
++ if (!ndst)
++ return;
++
++ write_lock_bh(&xfrm_policy_lock);
++
++ for (i = hmask; i >= 0; i--)
++ xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
++
++ xfrm_policy_bydst[dir].table = ndst;
++ xfrm_policy_bydst[dir].hmask = nhashmask;
++
++ write_unlock_bh(&xfrm_policy_lock);
++
++ xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
++}
++
++static void xfrm_byidx_resize(int total)
++{
++ unsigned int hmask = xfrm_idx_hmask;
++ unsigned int nhashmask = xfrm_new_hash_mask(hmask);
++ unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
++ struct hlist_head *oidx = xfrm_policy_byidx;
++ struct hlist_head *nidx = xfrm_hash_alloc(nsize);
++ int i;
++
++ if (!nidx)
++ return;
++
++ write_lock_bh(&xfrm_policy_lock);
++
++ for (i = hmask; i >= 0; i--)
++ xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
++
++ xfrm_policy_byidx = nidx;
++ xfrm_idx_hmask = nhashmask;
++
++ write_unlock_bh(&xfrm_policy_lock);
++
++ xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
++}
++
++static inline int xfrm_bydst_should_resize(int dir, int *total)
++{
++ unsigned int cnt = xfrm_policy_count[dir];
++ unsigned int hmask = xfrm_policy_bydst[dir].hmask;
++
++ if (total)
++ *total += cnt;
++
++ if ((hmask + 1) < xfrm_policy_hashmax &&
++ cnt > hmask)
++ return 1;
++
++ return 0;
++}
++
++static inline int xfrm_byidx_should_resize(int total)
++{
++ unsigned int hmask = xfrm_idx_hmask;
++
++ if ((hmask + 1) < xfrm_policy_hashmax &&
++ total > hmask)
++ return 1;
++
++ return 0;
++}
++
++static DEFINE_MUTEX(hash_resize_mutex);
++
++static void xfrm_hash_resize(void *__unused)
++{
++ int dir, total;
++
++ mutex_lock(&hash_resize_mutex);
++
++ total = 0;
++ for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
++ if (xfrm_bydst_should_resize(dir, &total))
++ xfrm_bydst_resize(dir);
++ }
++ if (xfrm_byidx_should_resize(total))
++ xfrm_byidx_resize(total);
++
++ mutex_unlock(&hash_resize_mutex);
++}
++
++static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL);
++
+ /* Generate new index... KAME seems to generate them ordered by cost
+ * of an absolute inpredictability of ordering of rules. This will not pass. */
+-static u32 xfrm_gen_index(int dir)
++static u32 xfrm_gen_index(u8 type, int dir)
+ {
+- u32 idx;
+- struct xfrm_policy *p;
+ static u32 idx_generator;
+
+ for (;;) {
++ struct hlist_node *entry;
++ struct hlist_head *list;
++ struct xfrm_policy *p;
++ u32 idx;
++ int found;
++
+ idx = (idx_generator | dir);
+ idx_generator += 8;
+ if (idx == 0)
+ idx = 8;
+- for (p = xfrm_policy_list[dir]; p; p = p->next) {
+- if (p->index == idx)
++ list = xfrm_policy_byidx + idx_hash(idx);
++ found = 0;
++ hlist_for_each_entry(p, entry, list, byidx) {
++ if (p->index == idx) {
++ found = 1;
+ break;
++ }
+ }
+- if (!p)
++ if (!found)
+ return idx;
+ }
+ }
+
++static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2)
++{
++ u32 *p1 = (u32 *) s1;
++ u32 *p2 = (u32 *) s2;
++ int len = sizeof(struct xfrm_selector) / sizeof(u32);
++ int i;
++
++ for (i = 0; i < len; i++) {
++ if (p1[i] != p2[i])
++ return 1;
++ }
++
++ return 0;
++}
++
+ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
+ {
+- struct xfrm_policy *pol, **p;
+- struct xfrm_policy *delpol = NULL;
+- struct xfrm_policy **newpos = NULL;
++ struct xfrm_policy *pol;
++ struct xfrm_policy *delpol;
++ struct hlist_head *chain;
++ struct hlist_node *entry, *newpos, *last;
+ struct dst_entry *gc_list;
+
+ write_lock_bh(&xfrm_policy_lock);
+- for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) {
+- if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 &&
++ chain = policy_hash_bysel(&policy->selector, policy->family, dir);
++ delpol = NULL;
++ newpos = NULL;
++ last = NULL;
++ hlist_for_each_entry(pol, entry, chain, bydst) {
++ if (!delpol &&
++ pol->type == policy->type &&
++ !selector_cmp(&pol->selector, &policy->selector) &&
+ xfrm_sec_ctx_match(pol->security, policy->security)) {
+ if (excl) {
+ write_unlock_bh(&xfrm_policy_lock);
+ return -EEXIST;
+ }
+- *p = pol->next;
+ delpol = pol;
+ if (policy->priority > pol->priority)
+ continue;
+ } else if (policy->priority >= pol->priority) {
+- p = &pol->next;
++ last = &pol->bydst;
+ continue;
+ }
+ if (!newpos)
+- newpos = p;
++ newpos = &pol->bydst;
+ if (delpol)
+ break;
+- p = &pol->next;
++ last = &pol->bydst;
+ }
++ if (!newpos)
++ newpos = last;
+ if (newpos)
+- p = newpos;
++ hlist_add_after(newpos, &policy->bydst);
++ else
++ hlist_add_head(&policy->bydst, chain);
+ xfrm_pol_hold(policy);
+- policy->next = *p;
+- *p = policy;
++ xfrm_policy_count[dir]++;
+ atomic_inc(&flow_cache_genid);
+- policy->index = delpol ? delpol->index : xfrm_gen_index(dir);
++ if (delpol) {
++ hlist_del(&delpol->bydst);
++ hlist_del(&delpol->byidx);
++ xfrm_policy_count[dir]--;
++ }
++ policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);
++ hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index));
+ policy->curlft.add_time = (unsigned long)xtime.tv_sec;
+ policy->curlft.use_time = 0;
+ if (!mod_timer(&policy->timer, jiffies + HZ))
+@@ -461,10 +669,13 @@ int xfrm_policy_insert(int dir, struct x
+
+ if (delpol)
+ xfrm_policy_kill(delpol);
++ else if (xfrm_bydst_should_resize(dir, NULL))
++ schedule_work(&xfrm_hash_work);
+
+ read_lock_bh(&xfrm_policy_lock);
+ gc_list = NULL;
+- for (policy = policy->next; policy; policy = policy->next) {
++ entry = &policy->bydst;
++ hlist_for_each_entry_continue(policy, entry, bydst) {
+ struct dst_entry *dst;
+
+ write_lock(&policy->lock);
+@@ -493,87 +704,149 @@ int xfrm_policy_insert(int dir, struct x
+ }
+ EXPORT_SYMBOL(xfrm_policy_insert);
+
+-struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel,
++struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
++ struct xfrm_selector *sel,
+ struct xfrm_sec_ctx *ctx, int delete)
+ {
+- struct xfrm_policy *pol, **p;
++ struct xfrm_policy *pol, *ret;
++ struct hlist_head *chain;
++ struct hlist_node *entry;
+
+ write_lock_bh(&xfrm_policy_lock);
+- for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
+- if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) &&
+- (xfrm_sec_ctx_match(ctx, pol->security))) {
++ chain = policy_hash_bysel(sel, sel->family, dir);
++ ret = NULL;
++ hlist_for_each_entry(pol, entry, chain, bydst) {
++ if (pol->type == type &&
++ !selector_cmp(sel, &pol->selector) &&
++ xfrm_sec_ctx_match(ctx, pol->security)) {
+ xfrm_pol_hold(pol);
+- if (delete)
+- *p = pol->next;
++ if (delete) {
++ hlist_del(&pol->bydst);
++ hlist_del(&pol->byidx);
++ xfrm_policy_count[dir]--;
++ }
++ ret = pol;
+ break;
+ }
+ }
+ write_unlock_bh(&xfrm_policy_lock);
+
+- if (pol && delete) {
++ if (ret && delete) {
+ atomic_inc(&flow_cache_genid);
+- xfrm_policy_kill(pol);
++ xfrm_policy_kill(ret);
+ }
+- return pol;
++ return ret;
+ }
+ EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
+
+-struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete)
++struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete)
+ {
+- struct xfrm_policy *pol, **p;
++ struct xfrm_policy *pol, *ret;
++ struct hlist_head *chain;
++ struct hlist_node *entry;
+
+ write_lock_bh(&xfrm_policy_lock);
+- for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
+- if (pol->index == id) {
++ chain = xfrm_policy_byidx + idx_hash(id);
++ ret = NULL;
++ hlist_for_each_entry(pol, entry, chain, byidx) {
++ if (pol->type == type && pol->index == id) {
+ xfrm_pol_hold(pol);
+- if (delete)
+- *p = pol->next;
++ if (delete) {
++ hlist_del(&pol->bydst);
++ hlist_del(&pol->byidx);
++ xfrm_policy_count[dir]--;
++ }
++ ret = pol;
+ break;
+ }
+ }
+ write_unlock_bh(&xfrm_policy_lock);
+
+- if (pol && delete) {
++ if (ret && delete) {
+ atomic_inc(&flow_cache_genid);
+- xfrm_policy_kill(pol);
++ xfrm_policy_kill(ret);
+ }
+- return pol;
++ return ret;
+ }
+ EXPORT_SYMBOL(xfrm_policy_byid);
+
+-void xfrm_policy_flush(void)
++void xfrm_policy_flush(u8 type)
+ {
+- struct xfrm_policy *xp;
+ int dir;
+
+ write_lock_bh(&xfrm_policy_lock);
+ for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
+- while ((xp = xfrm_policy_list[dir]) != NULL) {
+- xfrm_policy_list[dir] = xp->next;
++ struct xfrm_policy *pol;
++ struct hlist_node *entry;
++ int i, killed;
++
++ killed = 0;
++ again1:
++ hlist_for_each_entry(pol, entry,
++ &xfrm_policy_inexact[dir], bydst) {
++ if (pol->type != type)
++ continue;
++ hlist_del(&pol->bydst);
++ hlist_del(&pol->byidx);
+ write_unlock_bh(&xfrm_policy_lock);
+
+- xfrm_policy_kill(xp);
++ xfrm_policy_kill(pol);
++ killed++;
+
+ write_lock_bh(&xfrm_policy_lock);
++ goto again1;
++ }
++
++ for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
++ again2:
++ hlist_for_each_entry(pol, entry,
++ xfrm_policy_bydst[dir].table + i,
++ bydst) {
++ if (pol->type != type)
++ continue;
++ hlist_del(&pol->bydst);
++ hlist_del(&pol->byidx);
++ write_unlock_bh(&xfrm_policy_lock);
++
++ xfrm_policy_kill(pol);
++ killed++;
++
++ write_lock_bh(&xfrm_policy_lock);
++ goto again2;
++ }
+ }
++
++ xfrm_policy_count[dir] -= killed;
+ }
+ atomic_inc(&flow_cache_genid);
+ write_unlock_bh(&xfrm_policy_lock);
+ }
+ EXPORT_SYMBOL(xfrm_policy_flush);
+
+-int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*),
++int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),
+ void *data)
+ {
+- struct xfrm_policy *xp;
+- int dir;
+- int count = 0;
+- int error = 0;
++ struct xfrm_policy *pol;
++ struct hlist_node *entry;
++ int dir, count, error;
+
+ read_lock_bh(&xfrm_policy_lock);
++ count = 0;
+ for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
+- for (xp = xfrm_policy_list[dir]; xp; xp = xp->next)
+- count++;
++ struct hlist_head *table = xfrm_policy_bydst[dir].table;
++ int i;
++
++ hlist_for_each_entry(pol, entry,
++ &xfrm_policy_inexact[dir], bydst) {
++ if (pol->type == type)
++ count++;
++ }
++ for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
++ hlist_for_each_entry(pol, entry, table + i, bydst) {
++ if (pol->type == type)
++ count++;
++ }
++ }
+ }
+
+ if (count == 0) {
+@@ -582,46 +855,138 @@ int xfrm_policy_walk(int (*func)(struct
+ }
+
+ for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
+- for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) {
+- error = func(xp, dir%XFRM_POLICY_MAX, --count, data);
++ struct hlist_head *table = xfrm_policy_bydst[dir].table;
++ int i;
++
++ hlist_for_each_entry(pol, entry,
++ &xfrm_policy_inexact[dir], bydst) {
++ if (pol->type != type)
++ continue;
++ error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
+ if (error)
+ goto out;
+ }
++ for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
++ hlist_for_each_entry(pol, entry, table + i, bydst) {
++ if (pol->type != type)
++ continue;
++ error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
++ if (error)
++ goto out;
++ }
++ }
+ }
+-
++ error = 0;
+ out:
+ read_unlock_bh(&xfrm_policy_lock);
+ return error;
+ }
+ EXPORT_SYMBOL(xfrm_policy_walk);
+
+-/* Find policy to apply to this flow. */
+-
+-static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir,
+- void **objp, atomic_t **obj_refp)
++/*
++ * Find policy to apply to this flow.
++ *
++ * Returns 0 if policy found, else an -errno.
++ */
++static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
++ u8 type, u16 family, int dir)
+ {
+- struct xfrm_policy *pol;
++ struct xfrm_selector *sel = &pol->selector;
++ int match, ret = -ESRCH;
+
+- read_lock_bh(&xfrm_policy_lock);
+- for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) {
+- struct xfrm_selector *sel = &pol->selector;
+- int match;
++ if (pol->family != family ||
++ pol->type != type)
++ return ret;
+
+- if (pol->family != family)
+- continue;
++ match = xfrm_selector_match(sel, fl, family);
++ if (match)
++ ret = security_xfrm_policy_lookup(pol, fl->secid, dir);
+
+- match = xfrm_selector_match(sel, fl, family);
++ return ret;
++}
+
+- if (match) {
+- if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) {
+- xfrm_pol_hold(pol);
+- break;
++static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
++ u16 family, u8 dir)
++{
++ int err;
++ struct xfrm_policy *pol, *ret;
++ xfrm_address_t *daddr, *saddr;
++ struct hlist_node *entry;
++ struct hlist_head *chain;
++ u32 priority = ~0U;
++
++ daddr = xfrm_flowi_daddr(fl, family);
++ saddr = xfrm_flowi_saddr(fl, family);
++ if (unlikely(!daddr || !saddr))
++ return NULL;
++
++ read_lock_bh(&xfrm_policy_lock);
++ chain = policy_hash_direct(daddr, saddr, family, dir);
++ ret = NULL;
++ hlist_for_each_entry(pol, entry, chain, bydst) {
++ err = xfrm_policy_match(pol, fl, type, family, dir);
++ if (err) {
++ if (err == -ESRCH)
++ continue;
++ else {
++ ret = ERR_PTR(err);
++ goto fail;
+ }
++ } else {
++ ret = pol;
++ priority = ret->priority;
++ break;
+ }
+ }
++ chain = &xfrm_policy_inexact[dir];
++ hlist_for_each_entry(pol, entry, chain, bydst) {
++ err = xfrm_policy_match(pol, fl, type, family, dir);
++ if (err) {
++ if (err == -ESRCH)
++ continue;
++ else {
++ ret = ERR_PTR(err);
++ goto fail;
++ }
++ } else if (pol->priority < priority) {
++ ret = pol;
++ break;
++ }
++ }
++ if (ret)
++ xfrm_pol_hold(ret);
++fail:
+ read_unlock_bh(&xfrm_policy_lock);
++
++ return ret;
++}
++
++static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
++ void **objp, atomic_t **obj_refp)
++{
++ struct xfrm_policy *pol;
++ int err = 0;
++
++#ifdef CONFIG_XFRM_SUB_POLICY
++ pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir);
++ if (IS_ERR(pol)) {
++ err = PTR_ERR(pol);
++ pol = NULL;
++ }
++ if (pol || err)
++ goto end;
++#endif
++ pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir);
++ if (IS_ERR(pol)) {
++ err = PTR_ERR(pol);
++ pol = NULL;
++ }
++#ifdef CONFIG_XFRM_SUB_POLICY
++end:
++#endif
+ if ((*objp = (void *) pol) != NULL)
+ *obj_refp = &pol->refcnt;
++ return err;
+ }
+
+ static inline int policy_to_flow_dir(int dir)
+@@ -641,7 +1006,7 @@ static inline int policy_to_flow_dir(int
+ };
+ }
+
+-static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid)
++static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
+ {
+ struct xfrm_policy *pol;
+
+@@ -651,12 +1016,16 @@ static struct xfrm_policy *xfrm_sk_polic
+ sk->sk_family);
+ int err = 0;
+
+- if (match)
+- err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir));
+-
+- if (match && !err)
+- xfrm_pol_hold(pol);
+- else
++ if (match) {
++ err = security_xfrm_policy_lookup(pol, fl->secid,
++ policy_to_flow_dir(dir));
++ if (!err)
++ xfrm_pol_hold(pol);
++ else if (err == -ESRCH)
++ pol = NULL;
++ else
++ pol = ERR_PTR(err);
++ } else
+ pol = NULL;
+ }
+ read_unlock_bh(&xfrm_policy_lock);
+@@ -665,24 +1034,29 @@ static struct xfrm_policy *xfrm_sk_polic
+
+ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
+ {
+- pol->next = xfrm_policy_list[dir];
+- xfrm_policy_list[dir] = pol;
++ struct hlist_head *chain = policy_hash_bysel(&pol->selector,
++ pol->family, dir);
++
++ hlist_add_head(&pol->bydst, chain);
++ hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
++ xfrm_policy_count[dir]++;
+ xfrm_pol_hold(pol);
++
++ if (xfrm_bydst_should_resize(dir, NULL))
++ schedule_work(&xfrm_hash_work);
+ }
+
+ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
+ int dir)
+ {
+- struct xfrm_policy **polp;
++ if (hlist_unhashed(&pol->bydst))
++ return NULL;
+
+- for (polp = &xfrm_policy_list[dir];
+- *polp != NULL; polp = &(*polp)->next) {
+- if (*polp == pol) {
+- *polp = pol->next;
+- return pol;
+- }
+- }
+- return NULL;
++ hlist_del(&pol->bydst);
++ hlist_del(&pol->byidx);
++ xfrm_policy_count[dir]--;
++
++ return pol;
+ }
+
+ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
+@@ -704,12 +1078,17 @@ int xfrm_sk_policy_insert(struct sock *s
+ {
+ struct xfrm_policy *old_pol;
+
++#ifdef CONFIG_XFRM_SUB_POLICY
++ if (pol && pol->type != XFRM_POLICY_TYPE_MAIN)
++ return -EINVAL;
++#endif
++
+ write_lock_bh(&xfrm_policy_lock);
+ old_pol = sk->sk_policy[dir];
+ sk->sk_policy[dir] = pol;
+ if (pol) {
+ pol->curlft.add_time = (unsigned long)xtime.tv_sec;
+- pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir);
++ pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir);
+ __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
+ }
+ if (old_pol)
+@@ -738,6 +1117,7 @@ static struct xfrm_policy *clone_policy(
+ newp->flags = old->flags;
+ newp->xfrm_nr = old->xfrm_nr;
+ newp->index = old->index;
++ newp->type = old->type;
+ memcpy(newp->xfrm_vec, old->xfrm_vec,
+ newp->xfrm_nr*sizeof(struct xfrm_tmpl));
+ write_lock_bh(&xfrm_policy_lock);
+@@ -761,17 +1141,32 @@ int __xfrm_sk_clone_policy(struct sock *
+ return 0;
+ }
+
++static int
++xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,
++ unsigned short family)
++{
++ int err;
++ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
++
++ if (unlikely(afinfo == NULL))
++ return -EINVAL;
++ err = afinfo->get_saddr(local, remote);
++ xfrm_policy_put_afinfo(afinfo);
++ return err;
++}
++
+ /* Resolve list of templates for the flow, given policy. */
+
+ static int
+-xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl,
+- struct xfrm_state **xfrm,
+- unsigned short family)
++xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
++ struct xfrm_state **xfrm,
++ unsigned short family)
+ {
+ int nx;
+ int i, error;
+ xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
+ xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
++ xfrm_address_t tmp;
+
+ for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
+ struct xfrm_state *x;
+@@ -779,9 +1174,15 @@ xfrm_tmpl_resolve(struct xfrm_policy *po
+ xfrm_address_t *local = saddr;
+ struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
+
+- if (tmpl->mode) {
++ if (tmpl->mode == XFRM_MODE_TUNNEL) {
+ remote = &tmpl->id.daddr;
+ local = &tmpl->saddr;
++ if (xfrm_addr_any(local, family)) {
++ error = xfrm_get_saddr(&tmp, remote, family);
++ if (error)
++ goto fail;
++ local = &tmp;
++ }
+ }
+
+ x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
+@@ -809,6 +1210,45 @@ fail:
+ return error;
+ }
+
++static int
++xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl,
++ struct xfrm_state **xfrm,
++ unsigned short family)
++{
++ struct xfrm_state *tp[XFRM_MAX_DEPTH];
++ struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
++ int cnx = 0;
++ int error;
++ int ret;
++ int i;
++
++ for (i = 0; i < npols; i++) {
++ if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) {
++ error = -ENOBUFS;
++ goto fail;
++ }
++
++ ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
++ if (ret < 0) {
++ error = ret;
++ goto fail;
++ } else
++ cnx += ret;
++ }
++
++ /* found states are sorted for outbound processing */
++ if (npols > 1)
++ xfrm_state_sort(xfrm, tpp, cnx, family);
++
++ return cnx;
++
++ fail:
++ for (cnx--; cnx>=0; cnx--)
++ xfrm_state_put(tpp[cnx]);
++ return error;
++
++}
++
+ /* Check that the bundle accepts the flow and its components are
+ * still valid.
+ */
+@@ -855,6 +1295,11 @@ int xfrm_lookup(struct dst_entry **dst_p
+ struct sock *sk, int flags)
+ {
+ struct xfrm_policy *policy;
++ struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
++ int npols;
++ int pol_dead;
++ int xfrm_nr;
++ int pi;
+ struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
+ struct dst_entry *dst, *dst_orig = *dst_p;
+ int nx = 0;
+@@ -862,20 +1307,32 @@ int xfrm_lookup(struct dst_entry **dst_p
+ u32 genid;
+ u16 family;
+ u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
+- u32 sk_sid = security_sk_sid(sk, fl, dir);
++
+ restart:
+ genid = atomic_read(&flow_cache_genid);
+ policy = NULL;
+- if (sk && sk->sk_policy[1])
+- policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid);
++ for (pi = 0; pi < ARRAY_SIZE(pols); pi++)
++ pols[pi] = NULL;
++ npols = 0;
++ pol_dead = 0;
++ xfrm_nr = 0;
++
++ if (sk && sk->sk_policy[1]) {
++ policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
++ if (IS_ERR(policy))
++ return PTR_ERR(policy);
++ }
+
+ if (!policy) {
+ /* To accelerate a bit... */
+- if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
++ if ((dst_orig->flags & DST_NOXFRM) ||
++ !xfrm_policy_count[XFRM_POLICY_OUT])
+ return 0;
+
+- policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family,
++ policy = flow_cache_lookup(fl, dst_orig->ops->family,
+ dir, xfrm_policy_lookup);
++ if (IS_ERR(policy))
++ return PTR_ERR(policy);
+ }
+
+ if (!policy)
+@@ -883,6 +1340,9 @@ restart:
+
+ family = dst_orig->ops->family;
+ policy->curlft.use_time = (unsigned long)xtime.tv_sec;
++ pols[0] = policy;
++ npols ++;
++ xfrm_nr += pols[0]->xfrm_nr;
+
+ switch (policy->action) {
+ case XFRM_POLICY_BLOCK:
+@@ -891,11 +1351,13 @@ restart:
+ goto error;
+
+ case XFRM_POLICY_ALLOW:
++#ifndef CONFIG_XFRM_SUB_POLICY
+ if (policy->xfrm_nr == 0) {
+ /* Flow passes not transformed. */
+ xfrm_pol_put(policy);
+ return 0;
+ }
++#endif
+
+ /* Try to find matching bundle.
+ *
+@@ -911,7 +1373,40 @@ restart:
+ if (dst)
+ break;
+
+- nx = xfrm_tmpl_resolve(policy, fl, xfrm, family);
++#ifdef CONFIG_XFRM_SUB_POLICY
++ if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
++ pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
++ fl, family,
++ XFRM_POLICY_OUT);
++ if (pols[1]) {
++ if (IS_ERR(pols[1])) {
++ err = PTR_ERR(pols[1]);
++ goto error;
++ }
++ if (pols[1]->action == XFRM_POLICY_BLOCK) {
++ err = -EPERM;
++ goto error;
++ }
++ npols ++;
++ xfrm_nr += pols[1]->xfrm_nr;
++ }
++ }
++
++ /*
++ * Because neither flowi nor bundle information knows about
++ * transformation template size. On more than one policy usage
++ * we can realize whether all of them is bypass or not after
++ * they are searched. See above not-transformed bypass
++ * is surrounded by non-sub policy configuration, too.
++ */
++ if (xfrm_nr == 0) {
++ /* Flow passes not transformed. */
++ xfrm_pols_put(pols, npols);
++ return 0;
++ }
++
++#endif
++ nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
+
+ if (unlikely(nx<0)) {
+ err = nx;
+@@ -924,7 +1419,7 @@ restart:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&km_waitq, &wait);
+
+- nx = xfrm_tmpl_resolve(policy, fl, xfrm, family);
++ nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
+
+ if (nx == -EAGAIN && signal_pending(current)) {
+ err = -ERESTART;
+@@ -932,7 +1427,7 @@ restart:
+ }
+ if (nx == -EAGAIN ||
+ genid != atomic_read(&flow_cache_genid)) {
+- xfrm_pol_put(policy);
++ xfrm_pols_put(pols, npols);
+ goto restart;
+ }
+ err = nx;
+@@ -942,7 +1437,7 @@ restart:
+ }
+ if (nx == 0) {
+ /* Flow passes not transformed. */
+- xfrm_pol_put(policy);
++ xfrm_pols_put(pols, npols);
+ return 0;
+ }
+
+@@ -956,8 +1451,14 @@ restart:
+ goto error;
+ }
+
++ for (pi = 0; pi < npols; pi++) {
++ read_lock_bh(&pols[pi]->lock);
++ pol_dead |= pols[pi]->dead;
++ read_unlock_bh(&pols[pi]->lock);
++ }
++
+ write_lock_bh(&policy->lock);
+- if (unlikely(policy->dead || stale_bundle(dst))) {
++ if (unlikely(pol_dead || stale_bundle(dst))) {
+ /* Wow! While we worked on resolving, this
+ * policy has gone. Retry. It is not paranoia,
+ * we just cannot enlist new bundle to dead object.
+@@ -977,17 +1478,34 @@ restart:
+ }
+ *dst_p = dst;
+ dst_release(dst_orig);
+- xfrm_pol_put(policy);
++ xfrm_pols_put(pols, npols);
+ return 0;
+
+ error:
+ dst_release(dst_orig);
+- xfrm_pol_put(policy);
++ xfrm_pols_put(pols, npols);
+ *dst_p = NULL;
+ return err;
+ }
+ EXPORT_SYMBOL(xfrm_lookup);
+
++static inline int
++xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl)
++{
++ struct xfrm_state *x;
++ int err;
++
++ if (!skb->sp || idx < 0 || idx >= skb->sp->len)
++ return 0;
++ x = skb->sp->xvec[idx];
++ if (!x->type->reject)
++ return 0;
++ xfrm_state_hold(x);
++ err = x->type->reject(x, skb, fl);
++ xfrm_state_put(x);
++ return err;
++}
++
+ /* When skb is transformed back to its "native" form, we have to
+ * check policy restrictions. At the moment we make this in maximally
+ * stupid way. Shame on me. :-) Of course, connected sockets must
+@@ -1004,10 +1522,19 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, st
+ (x->id.spi == tmpl->id.spi || !tmpl->id.spi) &&
+ (x->props.reqid == tmpl->reqid || !tmpl->reqid) &&
+ x->props.mode == tmpl->mode &&
+- (tmpl->aalgos & (1<<x->props.aalgo)) &&
+- !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family));
++ ((tmpl->aalgos & (1<<x->props.aalgo)) ||
++ !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
++ !(x->props.mode != XFRM_MODE_TRANSPORT &&
++ xfrm_state_addr_cmp(tmpl, x, family));
+ }
+
++/*
++ * 0 or more than 0 is returned when validation is succeeded (either bypass
++ * because of optional transport mode, or next index of the mathced secpath
++ * state with the template.
++ * -1 is returned when no matching template is found.
++ * Otherwise "-2 - errored_index" is returned.
++ */
+ static inline int
+ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
+ unsigned short family)
+@@ -1015,15 +1542,18 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, s
+ int idx = start;
+
+ if (tmpl->optional) {
+- if (!tmpl->mode)
++ if (tmpl->mode == XFRM_MODE_TRANSPORT)
+ return start;
+ } else
+ start = -1;
+ for (; idx < sp->len; idx++) {
+ if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
+ return ++idx;
+- if (sp->xvec[idx]->props.mode)
++ if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
++ if (start == -1)
++ start = -2-idx;
+ break;
++ }
+ }
+ return start;
+ }
+@@ -1032,21 +1562,25 @@ int
+ xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
+ {
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
++ int err;
+
+ if (unlikely(afinfo == NULL))
+ return -EAFNOSUPPORT;
+
+ afinfo->decode_session(skb, fl);
++ err = security_xfrm_decode_session(skb, &fl->secid);
+ xfrm_policy_put_afinfo(afinfo);
+- return 0;
++ return err;
+ }
+ EXPORT_SYMBOL(xfrm_decode_session);
+
+-static inline int secpath_has_tunnel(struct sec_path *sp, int k)
++static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp)
+ {
+ for (; k < sp->len; k++) {
+- if (sp->xvec[k]->props.mode)
++ if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
++ *idxp = k;
+ return 1;
++ }
+ }
+
+ return 0;
+@@ -1056,16 +1590,18 @@ int __xfrm_policy_check(struct sock *sk,
+ unsigned short family)
+ {
+ struct xfrm_policy *pol;
++ struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
++ int npols = 0;
++ int xfrm_nr;
++ int pi;
+ struct flowi fl;
+ u8 fl_dir = policy_to_flow_dir(dir);
+- u32 sk_sid;
++ int xerr_idx = -1;
+
+ if (xfrm_decode_session(skb, &fl, family) < 0)
+ return 0;
+ nf_nat_decode_session(skb, &fl, family);
+
+- sk_sid = security_sk_sid(sk, &fl, fl_dir);
+-
+ /* First, check used SA against their selectors. */
+ if (skb->sp) {
+ int i;
+@@ -1078,47 +1614,99 @@ int __xfrm_policy_check(struct sock *sk,
+ }
+
+ pol = NULL;
+- if (sk && sk->sk_policy[dir])
+- pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid);
++ if (sk && sk->sk_policy[dir]) {
++ pol = xfrm_sk_policy_lookup(sk, dir, &fl);
++ if (IS_ERR(pol))
++ return 0;
++ }
+
+ if (!pol)
+- pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir,
++ pol = flow_cache_lookup(&fl, family, fl_dir,
+ xfrm_policy_lookup);
+
+- if (!pol)
+- return !skb->sp || !secpath_has_tunnel(skb->sp, 0);
++ if (IS_ERR(pol))
++ return 0;
++
++ if (!pol) {
++ if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
++ xfrm_secpath_reject(xerr_idx, skb, &fl);
++ return 0;
++ }
++ return 1;
++ }
+
+ pol->curlft.use_time = (unsigned long)xtime.tv_sec;
+
++ pols[0] = pol;
++ npols ++;
++#ifdef CONFIG_XFRM_SUB_POLICY
++ if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
++ pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
++ &fl, family,
++ XFRM_POLICY_IN);
++ if (pols[1]) {
++ if (IS_ERR(pols[1]))
++ return 0;
++ pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec;
++ npols ++;
++ }
++ }
++#endif
++
+ if (pol->action == XFRM_POLICY_ALLOW) {
+ struct sec_path *sp;
+ static struct sec_path dummy;
++ struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
++ struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
++ struct xfrm_tmpl **tpp = tp;
++ int ti = 0;
+ int i, k;
+
+ if ((sp = skb->sp) == NULL)
+ sp = &dummy;
+
++ for (pi = 0; pi < npols; pi++) {
++ if (pols[pi] != pol &&
++ pols[pi]->action != XFRM_POLICY_ALLOW)
++ goto reject;
++ if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH)
++ goto reject_error;
++ for (i = 0; i < pols[pi]->xfrm_nr; i++)
++ tpp[ti++] = &pols[pi]->xfrm_vec[i];
++ }
++ xfrm_nr = ti;
++ if (npols > 1) {
++ xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
++ tpp = stp;
++ }
++
+ /* For each tunnel xfrm, find the first matching tmpl.
+ * For each tmpl before that, find corresponding xfrm.
+ * Order is _important_. Later we will implement
+ * some barriers, but at the moment barriers
+ * are implied between each two transformations.
+ */
+- for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) {
+- k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family);
+- if (k < 0)
++ for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
++ k = xfrm_policy_ok(tpp[i], sp, k, family);
++ if (k < 0) {
++ if (k < -1)
++ /* "-2 - errored_index" returned */
++ xerr_idx = -(2+k);
+ goto reject;
++ }
+ }
+
+- if (secpath_has_tunnel(sp, k))
++ if (secpath_has_nontransport(sp, k, &xerr_idx))
+ goto reject;
+
+- xfrm_pol_put(pol);
++ xfrm_pols_put(pols, npols);
+ return 1;
+ }
+
+ reject:
+- xfrm_pol_put(pol);
++ xfrm_secpath_reject(xerr_idx, skb, &fl);
++reject_error:
++ xfrm_pols_put(pols, npols);
+ return 0;
+ }
+ EXPORT_SYMBOL(__xfrm_policy_check);
+@@ -1166,7 +1754,7 @@ static struct dst_entry *xfrm_dst_check(
+
+ static int stale_bundle(struct dst_entry *dst)
+ {
+- return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC);
++ return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0);
+ }
+
+ void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
+@@ -1196,33 +1784,50 @@ static struct dst_entry *xfrm_negative_a
+ return dst;
+ }
+
++static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p)
++{
++ struct dst_entry *dst, **dstp;
++
++ write_lock(&pol->lock);
++ dstp = &pol->bundles;
++ while ((dst=*dstp) != NULL) {
++ if (func(dst)) {
++ *dstp = dst->next;
++ dst->next = *gc_list_p;
++ *gc_list_p = dst;
++ } else {
++ dstp = &dst->next;
++ }
++ }
++ write_unlock(&pol->lock);
++}
++
+ static void xfrm_prune_bundles(int (*func)(struct dst_entry *))
+ {
+- int i;
+- struct xfrm_policy *pol;
+- struct dst_entry *dst, **dstp, *gc_list = NULL;
++ struct dst_entry *gc_list = NULL;
++ int dir;
+
+ read_lock_bh(&xfrm_policy_lock);
+- for (i=0; i<2*XFRM_POLICY_MAX; i++) {
+- for (pol = xfrm_policy_list[i]; pol; pol = pol->next) {
+- write_lock(&pol->lock);
+- dstp = &pol->bundles;
+- while ((dst=*dstp) != NULL) {
+- if (func(dst)) {
+- *dstp = dst->next;
+- dst->next = gc_list;
+- gc_list = dst;
+- } else {
+- dstp = &dst->next;
+- }
+- }
+- write_unlock(&pol->lock);
++ for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
++ struct xfrm_policy *pol;
++ struct hlist_node *entry;
++ struct hlist_head *table;
++ int i;
++
++ hlist_for_each_entry(pol, entry,
++ &xfrm_policy_inexact[dir], bydst)
++ prune_one_bundle(pol, func, &gc_list);
++
++ table = xfrm_policy_bydst[dir].table;
++ for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
++ hlist_for_each_entry(pol, entry, table + i, bydst)
++ prune_one_bundle(pol, func, &gc_list);
+ }
+ }
+ read_unlock_bh(&xfrm_policy_lock);
+
+ while (gc_list) {
+- dst = gc_list;
++ struct dst_entry *dst = gc_list;
+ gc_list = dst->next;
+ dst_free(dst);
+ }
+@@ -1238,22 +1843,12 @@ static void __xfrm_garbage_collect(void)
+ xfrm_prune_bundles(unused_bundle);
+ }
+
+-int xfrm_flush_bundles(void)
++static int xfrm_flush_bundles(void)
+ {
+ xfrm_prune_bundles(stale_bundle);
+ return 0;
+ }
+
+-static int always_true(struct dst_entry *dst)
+-{
+- return 1;
+-}
+-
+-void xfrm_flush_all_bundles(void)
+-{
+- xfrm_prune_bundles(always_true);
+-}
+-
+ void xfrm_init_pmtu(struct dst_entry *dst)
+ {
+ do {
+@@ -1281,7 +1876,8 @@ EXPORT_SYMBOL(xfrm_init_pmtu);
+ * still valid.
+ */
+
+-int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family)
++int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
++ struct flowi *fl, int family, int strict)
+ {
+ struct dst_entry *dst = &first->u.dst;
+ struct xfrm_dst *last;
+@@ -1298,8 +1894,16 @@ int xfrm_bundle_ok(struct xfrm_dst *firs
+
+ if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
+ return 0;
++ if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol))
++ return 0;
+ if (dst->xfrm->km.state != XFRM_STATE_VALID)
+ return 0;
++ if (xdst->genid != dst->xfrm->genid)
++ return 0;
++
++ if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL &&
++ !xfrm_state_addr_flow_check(dst->xfrm, fl, family))
++ return 0;
+
+ mtu = dst_mtu(dst->child);
+ if (xdst->child_mtu_cached != mtu) {
+@@ -1448,12 +2052,33 @@ static struct notifier_block xfrm_dev_no
+
+ static void __init xfrm_policy_init(void)
+ {
++ unsigned int hmask, sz;
++ int dir;
++
+ xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
+ sizeof(struct xfrm_dst),
+- 0, SLAB_HWCACHE_ALIGN,
++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ NULL, NULL);
+- if (!xfrm_dst_cache)
+- panic("XFRM: failed to allocate xfrm_dst_cache\n");
++
++ hmask = 8 - 1;
++ sz = (hmask+1) * sizeof(struct hlist_head);
++
++ xfrm_policy_byidx = xfrm_hash_alloc(sz);
++ xfrm_idx_hmask = hmask;
++ if (!xfrm_policy_byidx)
++ panic("XFRM: failed to allocate byidx hash\n");
++
++ for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
++ struct xfrm_policy_hash *htab;
++
++ INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]);
++
++ htab = &xfrm_policy_bydst[dir];
++ htab->table = xfrm_hash_alloc(sz);
++ htab->hmask = hmask;
++ if (!htab->table)
++ panic("XFRM: failed to allocate bydst hash\n");
++ }
+
+ INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL);
+ register_netdevice_notifier(&xfrm_dev_notifier);
+diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
+index 0021aad..899de9e 100644
+--- a/net/xfrm/xfrm_state.c
++++ b/net/xfrm/xfrm_state.c
+@@ -18,8 +18,11 @@
+ #include <linux/pfkeyv2.h>
+ #include <linux/ipsec.h>
+ #include <linux/module.h>
++#include <linux/cache.h>
+ #include <asm/uaccess.h>
+
++#include "xfrm_hash.h"
++
+ struct sock *xfrm_nl;
+ EXPORT_SYMBOL(xfrm_nl);
+
+@@ -32,7 +35,7 @@ EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth)
+ /* Each xfrm_state may be linked to two tables:
+
+ 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
+- 2. Hash table by daddr to find what SAs exist for given
++ 2. Hash table by (daddr,family,reqid) to find what SAs exist for given
+ destination/tunnel endpoint. (output)
+ */
+
+@@ -44,8 +47,128 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
+ * Main use is finding SA after policy selected tunnel or transport mode.
+ * Also, it can be used by ah/esp icmp error handler to find offending SA.
+ */
+-static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
+-static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
++static struct hlist_head *xfrm_state_bydst __read_mostly;
++static struct hlist_head *xfrm_state_bysrc __read_mostly;
++static struct hlist_head *xfrm_state_byspi __read_mostly;
++static unsigned int xfrm_state_hmask __read_mostly;
++static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
++static unsigned int xfrm_state_num;
++static unsigned int xfrm_state_genid;
++
++static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
++ xfrm_address_t *saddr,
++ u32 reqid,
++ unsigned short family)
++{
++ return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
++}
++
++static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
++ xfrm_address_t *saddr,
++ unsigned short family)
++{
++ return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
++}
++
++static inline unsigned int
++xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
++{
++ return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
++}
++
++static void xfrm_hash_transfer(struct hlist_head *list,
++ struct hlist_head *ndsttable,
++ struct hlist_head *nsrctable,
++ struct hlist_head *nspitable,
++ unsigned int nhashmask)
++{
++ struct hlist_node *entry, *tmp;
++ struct xfrm_state *x;
++
++ hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
++ unsigned int h;
++
++ h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
++ x->props.reqid, x->props.family,
++ nhashmask);
++ hlist_add_head(&x->bydst, ndsttable+h);
++
++ h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
++ x->props.family,
++ nhashmask);
++ hlist_add_head(&x->bysrc, nsrctable+h);
++
++ if (x->id.spi) {
++ h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
++ x->id.proto, x->props.family,
++ nhashmask);
++ hlist_add_head(&x->byspi, nspitable+h);
++ }
++ }
++}
++
++static unsigned long xfrm_hash_new_size(void)
++{
++ return ((xfrm_state_hmask + 1) << 1) *
++ sizeof(struct hlist_head);
++}
++
++static DEFINE_MUTEX(hash_resize_mutex);
++
++static void xfrm_hash_resize(void *__unused)
++{
++ struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
++ unsigned long nsize, osize;
++ unsigned int nhashmask, ohashmask;
++ int i;
++
++ mutex_lock(&hash_resize_mutex);
++
++ nsize = xfrm_hash_new_size();
++ ndst = xfrm_hash_alloc(nsize);
++ if (!ndst)
++ goto out_unlock;
++ nsrc = xfrm_hash_alloc(nsize);
++ if (!nsrc) {
++ xfrm_hash_free(ndst, nsize);
++ goto out_unlock;
++ }
++ nspi = xfrm_hash_alloc(nsize);
++ if (!nspi) {
++ xfrm_hash_free(ndst, nsize);
++ xfrm_hash_free(nsrc, nsize);
++ goto out_unlock;
++ }
++
++ spin_lock_bh(&xfrm_state_lock);
++
++ nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
++ for (i = xfrm_state_hmask; i >= 0; i--)
++ xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,
++ nhashmask);
++
++ odst = xfrm_state_bydst;
++ osrc = xfrm_state_bysrc;
++ ospi = xfrm_state_byspi;
++ ohashmask = xfrm_state_hmask;
++
++ xfrm_state_bydst = ndst;
++ xfrm_state_bysrc = nsrc;
++ xfrm_state_byspi = nspi;
++ xfrm_state_hmask = nhashmask;
++
++ spin_unlock_bh(&xfrm_state_lock);
++
++ osize = (ohashmask + 1) * sizeof(struct hlist_head);
++ xfrm_hash_free(odst, osize);
++ xfrm_hash_free(osrc, osize);
++ xfrm_hash_free(ospi, osize);
++
++out_unlock:
++ mutex_unlock(&hash_resize_mutex);
++}
++
++static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL);
+
+ DECLARE_WAIT_QUEUE_HEAD(km_waitq);
+ EXPORT_SYMBOL(km_waitq);
+@@ -54,11 +177,9 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_l
+ static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
+
+ static struct work_struct xfrm_state_gc_work;
+-static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
++static HLIST_HEAD(xfrm_state_gc_list);
+ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
+
+-static int xfrm_state_gc_flush_bundles;
+-
+ int __xfrm_state_delete(struct xfrm_state *x);
+
+ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
+@@ -69,14 +190,13 @@ void km_state_expired(struct xfrm_state
+
+ static void xfrm_state_gc_destroy(struct xfrm_state *x)
+ {
+- if (del_timer(&x->timer))
+- BUG();
+- if (del_timer(&x->rtimer))
+- BUG();
++ del_timer_sync(&x->timer);
++ del_timer_sync(&x->rtimer);
+ kfree(x->aalg);
+ kfree(x->ealg);
+ kfree(x->calg);
+ kfree(x->encap);
++ kfree(x->coaddr);
+ if (x->mode)
+ xfrm_put_mode(x->mode);
+ if (x->type) {
+@@ -90,22 +210,17 @@ static void xfrm_state_gc_destroy(struct
+ static void xfrm_state_gc_task(void *data)
+ {
+ struct xfrm_state *x;
+- struct list_head *entry, *tmp;
+- struct list_head gc_list = LIST_HEAD_INIT(gc_list);
+-
+- if (xfrm_state_gc_flush_bundles) {
+- xfrm_state_gc_flush_bundles = 0;
+- xfrm_flush_bundles();
+- }
++ struct hlist_node *entry, *tmp;
++ struct hlist_head gc_list;
+
+ spin_lock_bh(&xfrm_state_gc_lock);
+- list_splice_init(&xfrm_state_gc_list, &gc_list);
++ gc_list.first = xfrm_state_gc_list.first;
++ INIT_HLIST_HEAD(&xfrm_state_gc_list);
+ spin_unlock_bh(&xfrm_state_gc_lock);
+
+- list_for_each_safe(entry, tmp, &gc_list) {
+- x = list_entry(entry, struct xfrm_state, bydst);
++ hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst)
+ xfrm_state_gc_destroy(x);
+- }
++
+ wake_up(&km_waitq);
+ }
+
+@@ -168,9 +283,9 @@ static void xfrm_timer_handler(unsigned
+ if (warn)
+ km_state_expired(x, 0, 0);
+ resched:
+- if (next != LONG_MAX &&
+- !mod_timer(&x->timer, jiffies + make_jiffies(next)))
+- xfrm_state_hold(x);
++ if (next != LONG_MAX)
++ mod_timer(&x->timer, jiffies + make_jiffies(next));
++
+ goto out;
+
+ expired:
+@@ -185,7 +300,6 @@ expired:
+
+ out:
+ spin_unlock(&x->lock);
+- xfrm_state_put(x);
+ }
+
+ static void xfrm_replay_timer_handler(unsigned long data);
+@@ -199,8 +313,9 @@ struct xfrm_state *xfrm_state_alloc(void
+ if (x) {
+ atomic_set(&x->refcnt, 1);
+ atomic_set(&x->tunnel_users, 0);
+- INIT_LIST_HEAD(&x->bydst);
+- INIT_LIST_HEAD(&x->byspi);
++ INIT_HLIST_NODE(&x->bydst);
++ INIT_HLIST_NODE(&x->bysrc);
++ INIT_HLIST_NODE(&x->byspi);
+ init_timer(&x->timer);
+ x->timer.function = xfrm_timer_handler;
+ x->timer.data = (unsigned long)x;
+@@ -225,7 +340,7 @@ void __xfrm_state_destroy(struct xfrm_st
+ BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
+
+ spin_lock_bh(&xfrm_state_gc_lock);
+- list_add(&x->bydst, &xfrm_state_gc_list);
++ hlist_add_head(&x->bydst, &xfrm_state_gc_list);
+ spin_unlock_bh(&xfrm_state_gc_lock);
+ schedule_work(&xfrm_state_gc_work);
+ }
+@@ -238,27 +353,12 @@ int __xfrm_state_delete(struct xfrm_stat
+ if (x->km.state != XFRM_STATE_DEAD) {
+ x->km.state = XFRM_STATE_DEAD;
+ spin_lock(&xfrm_state_lock);
+- list_del(&x->bydst);
+- __xfrm_state_put(x);
+- if (x->id.spi) {
+- list_del(&x->byspi);
+- __xfrm_state_put(x);
+- }
++ hlist_del(&x->bydst);
++ hlist_del(&x->bysrc);
++ if (x->id.spi)
++ hlist_del(&x->byspi);
++ xfrm_state_num--;
+ spin_unlock(&xfrm_state_lock);
+- if (del_timer(&x->timer))
+- __xfrm_state_put(x);
+- if (del_timer(&x->rtimer))
+- __xfrm_state_put(x);
+-
+- /* The number two in this test is the reference
+- * mentioned in the comment below plus the reference
+- * our caller holds. A larger value means that
+- * there are DSTs attached to this xfrm_state.
+- */
+- if (atomic_read(&x->refcnt) > 2) {
+- xfrm_state_gc_flush_bundles = 1;
+- schedule_work(&xfrm_state_gc_work);
+- }
+
+ /* All xfrm_state objects are created by xfrm_state_alloc.
+ * The xfrm_state_alloc call gives a reference, and that
+@@ -287,14 +387,15 @@ EXPORT_SYMBOL(xfrm_state_delete);
+ void xfrm_state_flush(u8 proto)
+ {
+ int i;
+- struct xfrm_state *x;
+
+ spin_lock_bh(&xfrm_state_lock);
+- for (i = 0; i < XFRM_DST_HSIZE; i++) {
++ for (i = 0; i <= xfrm_state_hmask; i++) {
++ struct hlist_node *entry;
++ struct xfrm_state *x;
+ restart:
+- list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
+ if (!xfrm_state_kern(x) &&
+- (proto == IPSEC_PROTO_ANY || x->id.proto == proto)) {
++ xfrm_id_proto_match(x->id.proto, proto)) {
+ xfrm_state_hold(x);
+ spin_unlock_bh(&xfrm_state_lock);
+
+@@ -325,29 +426,111 @@ xfrm_init_tempsel(struct xfrm_state *x,
+ return 0;
+ }
+
++static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
++{
++ unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
++ struct xfrm_state *x;
++ struct hlist_node *entry;
++
++ hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
++ if (x->props.family != family ||
++ x->id.spi != spi ||
++ x->id.proto != proto)
++ continue;
++
++ switch (family) {
++ case AF_INET:
++ if (x->id.daddr.a4 != daddr->a4)
++ continue;
++ break;
++ case AF_INET6:
++ if (!ipv6_addr_equal((struct in6_addr *)daddr,
++ (struct in6_addr *)
++ x->id.daddr.a6))
++ continue;
++ break;
++ };
++
++ xfrm_state_hold(x);
++ return x;
++ }
++
++ return NULL;
++}
++
++static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
++{
++ unsigned int h = xfrm_src_hash(daddr, saddr, family);
++ struct xfrm_state *x;
++ struct hlist_node *entry;
++
++ hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
++ if (x->props.family != family ||
++ x->id.proto != proto)
++ continue;
++
++ switch (family) {
++ case AF_INET:
++ if (x->id.daddr.a4 != daddr->a4 ||
++ x->props.saddr.a4 != saddr->a4)
++ continue;
++ break;
++ case AF_INET6:
++ if (!ipv6_addr_equal((struct in6_addr *)daddr,
++ (struct in6_addr *)
++ x->id.daddr.a6) ||
++ !ipv6_addr_equal((struct in6_addr *)saddr,
++ (struct in6_addr *)
++ x->props.saddr.a6))
++ continue;
++ break;
++ };
++
++ xfrm_state_hold(x);
++ return x;
++ }
++
++ return NULL;
++}
++
++static inline struct xfrm_state *
++__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
++{
++ if (use_spi)
++ return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
++ x->id.proto, family);
++ else
++ return __xfrm_state_lookup_byaddr(&x->id.daddr,
++ &x->props.saddr,
++ x->id.proto, family);
++}
++
++static void xfrm_hash_grow_check(int have_hash_collision)
++{
++ if (have_hash_collision &&
++ (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
++ xfrm_state_num > xfrm_state_hmask)
++ schedule_work(&xfrm_hash_work);
++}
++
+ struct xfrm_state *
+ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
+ struct flowi *fl, struct xfrm_tmpl *tmpl,
+ struct xfrm_policy *pol, int *err,
+ unsigned short family)
+ {
+- unsigned h = xfrm_dst_hash(daddr, family);
++ unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
++ struct hlist_node *entry;
+ struct xfrm_state *x, *x0;
+ int acquire_in_progress = 0;
+ int error = 0;
+ struct xfrm_state *best = NULL;
+- struct xfrm_state_afinfo *afinfo;
+
+- afinfo = xfrm_state_get_afinfo(family);
+- if (afinfo == NULL) {
+- *err = -EAFNOSUPPORT;
+- return NULL;
+- }
+-
+ spin_lock_bh(&xfrm_state_lock);
+- list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+ if (x->props.family == family &&
+ x->props.reqid == tmpl->reqid &&
++ !(x->props.flags & XFRM_STATE_WILDRECV) &&
+ xfrm_state_addr_check(x, daddr, saddr, family) &&
+ tmpl->mode == x->props.mode &&
+ tmpl->id.proto == x->id.proto &&
+@@ -367,7 +550,7 @@ xfrm_state_find(xfrm_address_t *daddr, x
+ */
+ if (x->km.state == XFRM_STATE_VALID) {
+ if (!xfrm_selector_match(&x->sel, fl, family) ||
+- !xfrm_sec_ctx_match(pol->security, x->security))
++ !security_xfrm_state_pol_flow_match(x, pol, fl))
+ continue;
+ if (!best ||
+ best->km.dying > x->km.dying ||
+@@ -379,7 +562,7 @@ xfrm_state_find(xfrm_address_t *daddr, x
+ } else if (x->km.state == XFRM_STATE_ERROR ||
+ x->km.state == XFRM_STATE_EXPIRED) {
+ if (xfrm_selector_match(&x->sel, fl, family) &&
+- xfrm_sec_ctx_match(pol->security, x->security))
++ security_xfrm_state_pol_flow_match(x, pol, fl))
+ error = -ESRCH;
+ }
+ }
+@@ -388,8 +571,8 @@ xfrm_state_find(xfrm_address_t *daddr, x
+ x = best;
+ if (!x && !error && !acquire_in_progress) {
+ if (tmpl->id.spi &&
+- (x0 = afinfo->state_lookup(daddr, tmpl->id.spi,
+- tmpl->id.proto)) != NULL) {
++ (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
++ tmpl->id.proto, family)) != NULL) {
+ xfrm_state_put(x0);
+ error = -EEXIST;
+ goto out;
+@@ -403,19 +586,28 @@ xfrm_state_find(xfrm_address_t *daddr, x
+ * to current session. */
+ xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
+
++ error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
++ if (error) {
++ x->km.state = XFRM_STATE_DEAD;
++ xfrm_state_put(x);
++ x = NULL;
++ goto out;
++ }
++
+ if (km_query(x, tmpl, pol) == 0) {
+ x->km.state = XFRM_STATE_ACQ;
+- list_add_tail(&x->bydst, xfrm_state_bydst+h);
+- xfrm_state_hold(x);
++ hlist_add_head(&x->bydst, xfrm_state_bydst+h);
++ h = xfrm_src_hash(daddr, saddr, family);
++ hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
+ if (x->id.spi) {
+ h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
+- list_add(&x->byspi, xfrm_state_byspi+h);
+- xfrm_state_hold(x);
++ hlist_add_head(&x->byspi, xfrm_state_byspi+h);
+ }
+ x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
+- xfrm_state_hold(x);
+ x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
+ add_timer(&x->timer);
++ xfrm_state_num++;
++ xfrm_hash_grow_check(x->bydst.next != NULL);
+ } else {
+ x->km.state = XFRM_STATE_DEAD;
+ xfrm_state_put(x);
+@@ -429,59 +621,168 @@ out:
+ else
+ *err = acquire_in_progress ? -EAGAIN : error;
+ spin_unlock_bh(&xfrm_state_lock);
+- xfrm_state_put_afinfo(afinfo);
+ return x;
+ }
+
+ static void __xfrm_state_insert(struct xfrm_state *x)
+ {
+- unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family);
++ unsigned int h;
+
+- list_add(&x->bydst, xfrm_state_bydst+h);
+- xfrm_state_hold(x);
++ x->genid = ++xfrm_state_genid;
+
+- h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
++ h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
++ x->props.reqid, x->props.family);
++ hlist_add_head(&x->bydst, xfrm_state_bydst+h);
+
+- list_add(&x->byspi, xfrm_state_byspi+h);
+- xfrm_state_hold(x);
++ h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
++ hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
+
+- if (!mod_timer(&x->timer, jiffies + HZ))
+- xfrm_state_hold(x);
++ if (x->id.spi) {
++ h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
++ x->props.family);
+
+- if (x->replay_maxage &&
+- !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+- xfrm_state_hold(x);
++ hlist_add_head(&x->byspi, xfrm_state_byspi+h);
++ }
++
++ mod_timer(&x->timer, jiffies + HZ);
++ if (x->replay_maxage)
++ mod_timer(&x->rtimer, jiffies + x->replay_maxage);
+
+ wake_up(&km_waitq);
++
++ xfrm_state_num++;
++
++ xfrm_hash_grow_check(x->bydst.next != NULL);
++}
++
++/* xfrm_state_lock is held */
++static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
++{
++ unsigned short family = xnew->props.family;
++ u32 reqid = xnew->props.reqid;
++ struct xfrm_state *x;
++ struct hlist_node *entry;
++ unsigned int h;
++
++ h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
++ if (x->props.family == family &&
++ x->props.reqid == reqid &&
++ !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
++ !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
++ x->genid = xfrm_state_genid;
++ }
+ }
+
+ void xfrm_state_insert(struct xfrm_state *x)
+ {
+ spin_lock_bh(&xfrm_state_lock);
++ __xfrm_state_bump_genids(x);
+ __xfrm_state_insert(x);
+ spin_unlock_bh(&xfrm_state_lock);
+-
+- xfrm_flush_all_bundles();
+ }
+ EXPORT_SYMBOL(xfrm_state_insert);
+
++/* xfrm_state_lock is held */
++static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
++{
++ unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
++ struct hlist_node *entry;
++ struct xfrm_state *x;
++
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
++ if (x->props.reqid != reqid ||
++ x->props.mode != mode ||
++ x->props.family != family ||
++ x->km.state != XFRM_STATE_ACQ ||
++ x->id.spi != 0)
++ continue;
++
++ switch (family) {
++ case AF_INET:
++ if (x->id.daddr.a4 != daddr->a4 ||
++ x->props.saddr.a4 != saddr->a4)
++ continue;
++ break;
++ case AF_INET6:
++ if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
++ (struct in6_addr *)daddr) ||
++ !ipv6_addr_equal((struct in6_addr *)
++ x->props.saddr.a6,
++ (struct in6_addr *)saddr))
++ continue;
++ break;
++ };
++
++ xfrm_state_hold(x);
++ return x;
++ }
++
++ if (!create)
++ return NULL;
++
++ x = xfrm_state_alloc();
++ if (likely(x)) {
++ switch (family) {
++ case AF_INET:
++ x->sel.daddr.a4 = daddr->a4;
++ x->sel.saddr.a4 = saddr->a4;
++ x->sel.prefixlen_d = 32;
++ x->sel.prefixlen_s = 32;
++ x->props.saddr.a4 = saddr->a4;
++ x->id.daddr.a4 = daddr->a4;
++ break;
++
++ case AF_INET6:
++ ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
++ (struct in6_addr *)daddr);
++ ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
++ (struct in6_addr *)saddr);
++ x->sel.prefixlen_d = 128;
++ x->sel.prefixlen_s = 128;
++ ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
++ (struct in6_addr *)saddr);
++ ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
++ (struct in6_addr *)daddr);
++ break;
++ };
++
++ x->km.state = XFRM_STATE_ACQ;
++ x->id.proto = proto;
++ x->props.family = family;
++ x->props.mode = mode;
++ x->props.reqid = reqid;
++ x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
++ xfrm_state_hold(x);
++ x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
++ add_timer(&x->timer);
++ hlist_add_head(&x->bydst, xfrm_state_bydst+h);
++ h = xfrm_src_hash(daddr, saddr, family);
++ hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
++ wake_up(&km_waitq);
++
++ xfrm_state_num++;
++
++ xfrm_hash_grow_check(x->bydst.next != NULL);
++ }
++
++ return x;
++}
++
+ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
+ int xfrm_state_add(struct xfrm_state *x)
+ {
+- struct xfrm_state_afinfo *afinfo;
+ struct xfrm_state *x1;
+ int family;
+ int err;
++ int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+
+ family = x->props.family;
+- afinfo = xfrm_state_get_afinfo(family);
+- if (unlikely(afinfo == NULL))
+- return -EAFNOSUPPORT;
+
+ spin_lock_bh(&xfrm_state_lock);
+
+- x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
++ x1 = __xfrm_state_locate(x, use_spi, family);
+ if (x1) {
+ xfrm_state_put(x1);
+ x1 = NULL;
+@@ -489,7 +790,7 @@ int xfrm_state_add(struct xfrm_state *x)
+ goto out;
+ }
+
+- if (x->km.seq) {
++ if (use_spi && x->km.seq) {
+ x1 = __xfrm_find_acq_byseq(x->km.seq);
+ if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) {
+ xfrm_state_put(x1);
+@@ -497,20 +798,17 @@ int xfrm_state_add(struct xfrm_state *x)
+ }
+ }
+
+- if (!x1)
+- x1 = afinfo->find_acq(
+- x->props.mode, x->props.reqid, x->id.proto,
+- &x->id.daddr, &x->props.saddr, 0);
++ if (use_spi && !x1)
++ x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
++ x->id.proto,
++ &x->id.daddr, &x->props.saddr, 0);
+
++ __xfrm_state_bump_genids(x);
+ __xfrm_state_insert(x);
+ err = 0;
+
+ out:
+ spin_unlock_bh(&xfrm_state_lock);
+- xfrm_state_put_afinfo(afinfo);
+-
+- if (!err)
+- xfrm_flush_all_bundles();
+
+ if (x1) {
+ xfrm_state_delete(x1);
+@@ -523,16 +821,12 @@ EXPORT_SYMBOL(xfrm_state_add);
+
+ int xfrm_state_update(struct xfrm_state *x)
+ {
+- struct xfrm_state_afinfo *afinfo;
+ struct xfrm_state *x1;
+ int err;
+-
+- afinfo = xfrm_state_get_afinfo(x->props.family);
+- if (unlikely(afinfo == NULL))
+- return -EAFNOSUPPORT;
++ int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+
+ spin_lock_bh(&xfrm_state_lock);
+- x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
++ x1 = __xfrm_state_locate(x, use_spi, x->props.family);
+
+ err = -ESRCH;
+ if (!x1)
+@@ -552,7 +846,6 @@ int xfrm_state_update(struct xfrm_state
+
+ out:
+ spin_unlock_bh(&xfrm_state_lock);
+- xfrm_state_put_afinfo(afinfo);
+
+ if (err)
+ return err;
+@@ -568,11 +861,15 @@ out:
+ if (likely(x1->km.state == XFRM_STATE_VALID)) {
+ if (x->encap && x1->encap)
+ memcpy(x1->encap, x->encap, sizeof(*x1->encap));
++ if (x->coaddr && x1->coaddr) {
++ memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
++ }
++ if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
++ memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
+ memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
+ x1->km.dying = 0;
+
+- if (!mod_timer(&x1->timer, jiffies + HZ))
+- xfrm_state_hold(x1);
++ mod_timer(&x1->timer, jiffies + HZ);
+ if (x1->curlft.use_time)
+ xfrm_state_check_expire(x1);
+
+@@ -597,8 +894,7 @@ int xfrm_state_check_expire(struct xfrm_
+ if (x->curlft.bytes >= x->lft.hard_byte_limit ||
+ x->curlft.packets >= x->lft.hard_packet_limit) {
+ x->km.state = XFRM_STATE_EXPIRED;
+- if (!mod_timer(&x->timer, jiffies))
+- xfrm_state_hold(x);
++ mod_timer(&x->timer, jiffies);
+ return -EINVAL;
+ }
+
+@@ -636,50 +932,97 @@ err:
+ EXPORT_SYMBOL(xfrm_state_check);
+
+ struct xfrm_state *
+-xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
++xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
+ unsigned short family)
+ {
+ struct xfrm_state *x;
+- struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
+- if (!afinfo)
+- return NULL;
+
+ spin_lock_bh(&xfrm_state_lock);
+- x = afinfo->state_lookup(daddr, spi, proto);
++ x = __xfrm_state_lookup(daddr, spi, proto, family);
+ spin_unlock_bh(&xfrm_state_lock);
+- xfrm_state_put_afinfo(afinfo);
+ return x;
+ }
+ EXPORT_SYMBOL(xfrm_state_lookup);
+
+ struct xfrm_state *
++xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
++ u8 proto, unsigned short family)
++{
++ struct xfrm_state *x;
++
++ spin_lock_bh(&xfrm_state_lock);
++ x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
++ spin_unlock_bh(&xfrm_state_lock);
++ return x;
++}
++EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
++
++struct xfrm_state *
+ xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
+ xfrm_address_t *daddr, xfrm_address_t *saddr,
+ int create, unsigned short family)
+ {
+ struct xfrm_state *x;
++
++ spin_lock_bh(&xfrm_state_lock);
++ x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
++ spin_unlock_bh(&xfrm_state_lock);
++
++ return x;
++}
++EXPORT_SYMBOL(xfrm_find_acq);
++
++#ifdef CONFIG_XFRM_SUB_POLICY
++int
++xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
++ unsigned short family)
++{
++ int err = 0;
+ struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
+ if (!afinfo)
+- return NULL;
++ return -EAFNOSUPPORT;
+
+ spin_lock_bh(&xfrm_state_lock);
+- x = afinfo->find_acq(mode, reqid, proto, daddr, saddr, create);
++ if (afinfo->tmpl_sort)
++ err = afinfo->tmpl_sort(dst, src, n);
+ spin_unlock_bh(&xfrm_state_lock);
+ xfrm_state_put_afinfo(afinfo);
+- return x;
++ return err;
+ }
+-EXPORT_SYMBOL(xfrm_find_acq);
++EXPORT_SYMBOL(xfrm_tmpl_sort);
++
++int
++xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
++ unsigned short family)
++{
++ int err = 0;
++ struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
++ if (!afinfo)
++ return -EAFNOSUPPORT;
++
++ spin_lock_bh(&xfrm_state_lock);
++ if (afinfo->state_sort)
++ err = afinfo->state_sort(dst, src, n);
++ spin_unlock_bh(&xfrm_state_lock);
++ xfrm_state_put_afinfo(afinfo);
++ return err;
++}
++EXPORT_SYMBOL(xfrm_state_sort);
++#endif
+
+ /* Silly enough, but I'm lazy to build resolution list */
+
+ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
+ {
+ int i;
+- struct xfrm_state *x;
+
+- for (i = 0; i < XFRM_DST_HSIZE; i++) {
+- list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+- if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) {
++ for (i = 0; i <= xfrm_state_hmask; i++) {
++ struct hlist_node *entry;
++ struct xfrm_state *x;
++
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
++ if (x->km.seq == seq &&
++ x->km.state == XFRM_STATE_ACQ) {
+ xfrm_state_hold(x);
+ return x;
+ }
+@@ -713,9 +1056,9 @@ u32 xfrm_get_acqseq(void)
+ EXPORT_SYMBOL(xfrm_get_acqseq);
+
+ void
+-xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
++xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi)
+ {
+- u32 h;
++ unsigned int h;
+ struct xfrm_state *x0;
+
+ if (x->id.spi)
+@@ -730,10 +1073,10 @@ xfrm_alloc_spi(struct xfrm_state *x, u32
+ x->id.spi = minspi;
+ } else {
+ u32 spi = 0;
+- minspi = ntohl(minspi);
+- maxspi = ntohl(maxspi);
+- for (h=0; h<maxspi-minspi+1; h++) {
+- spi = minspi + net_random()%(maxspi-minspi+1);
++ u32 low = ntohl(minspi);
++ u32 high = ntohl(maxspi);
++ for (h=0; h<high-low+1; h++) {
++ spi = low + net_random()%(high-low+1);
+ x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
+ if (x0 == NULL) {
+ x->id.spi = htonl(spi);
+@@ -745,8 +1088,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32
+ if (x->id.spi) {
+ spin_lock_bh(&xfrm_state_lock);
+ h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
+- list_add(&x->byspi, xfrm_state_byspi+h);
+- xfrm_state_hold(x);
++ hlist_add_head(&x->byspi, xfrm_state_byspi+h);
+ spin_unlock_bh(&xfrm_state_lock);
+ wake_up(&km_waitq);
+ }
+@@ -758,13 +1100,14 @@ int xfrm_state_walk(u8 proto, int (*func
+ {
+ int i;
+ struct xfrm_state *x;
++ struct hlist_node *entry;
+ int count = 0;
+ int err = 0;
+
+ spin_lock_bh(&xfrm_state_lock);
+- for (i = 0; i < XFRM_DST_HSIZE; i++) {
+- list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+- if (proto == IPSEC_PROTO_ANY || x->id.proto == proto)
++ for (i = 0; i <= xfrm_state_hmask; i++) {
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
++ if (xfrm_id_proto_match(x->id.proto, proto))
+ count++;
+ }
+ }
+@@ -773,9 +1116,9 @@ int xfrm_state_walk(u8 proto, int (*func
+ goto out;
+ }
+
+- for (i = 0; i < XFRM_DST_HSIZE; i++) {
+- list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+- if (proto != IPSEC_PROTO_ANY && x->id.proto != proto)
++ for (i = 0; i <= xfrm_state_hmask; i++) {
++ hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
++ if (!xfrm_id_proto_match(x->id.proto, proto))
+ continue;
+ err = func(x, --count, data);
+ if (err)
+@@ -832,10 +1175,8 @@ void xfrm_replay_notify(struct xfrm_stat
+ km_state_notify(x, &c);
+
+ if (x->replay_maxage &&
+- !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) {
+- xfrm_state_hold(x);
++ !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+ x->xflags &= ~XFRM_TIME_DEFER;
+- }
+ }
+ EXPORT_SYMBOL(xfrm_replay_notify);
+
+@@ -853,14 +1194,12 @@ static void xfrm_replay_timer_handler(un
+ }
+
+ spin_unlock(&x->lock);
+- xfrm_state_put(x);
+ }
+
+-int xfrm_replay_check(struct xfrm_state *x, u32 seq)
++int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
+ {
+ u32 diff;
+-
+- seq = ntohl(seq);
++ u32 seq = ntohl(net_seq);
+
+ if (unlikely(seq == 0))
+ return -EINVAL;
+@@ -882,11 +1221,10 @@ int xfrm_replay_check(struct xfrm_state
+ }
+ EXPORT_SYMBOL(xfrm_replay_check);
+
+-void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
++void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
+ {
+ u32 diff;
+-
+- seq = ntohl(seq);
++ u32 seq = ntohl(net_seq);
+
+ if (seq > x->replay.seq) {
+ diff = seq - x->replay.seq;
+@@ -997,6 +1335,25 @@ void km_policy_expired(struct xfrm_polic
+ }
+ EXPORT_SYMBOL(km_policy_expired);
+
++int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
++{
++ int err = -EINVAL;
++ int ret;
++ struct xfrm_mgr *km;
++
++ read_lock(&xfrm_km_lock);
++ list_for_each_entry(km, &xfrm_km_list, list) {
++ if (km->report) {
++ ret = km->report(proto, sel, addr);
++ if (!ret)
++ err = ret;
++ }
++ }
++ read_unlock(&xfrm_km_lock);
++ return err;
++}
++EXPORT_SYMBOL(km_report);
++
+ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
+ {
+ int err;
+@@ -1018,7 +1375,7 @@ int xfrm_user_policy(struct sock *sk, in
+ err = -EINVAL;
+ read_lock(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list) {
+- pol = km->compile_policy(sk->sk_family, optname, data,
++ pol = km->compile_policy(sk, optname, data,
+ optlen, &err);
+ if (err >= 0)
+ break;
+@@ -1065,11 +1422,8 @@ int xfrm_state_register_afinfo(struct xf
+ write_lock_bh(&xfrm_state_afinfo_lock);
+ if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
+ err = -ENOBUFS;
+- else {
+- afinfo->state_bydst = xfrm_state_bydst;
+- afinfo->state_byspi = xfrm_state_byspi;
++ else
+ xfrm_state_afinfo[afinfo->family] = afinfo;
+- }
+ write_unlock_bh(&xfrm_state_afinfo_lock);
+ return err;
+ }
+@@ -1086,11 +1440,8 @@ int xfrm_state_unregister_afinfo(struct
+ if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
+ if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
+ err = -EINVAL;
+- else {
++ else
+ xfrm_state_afinfo[afinfo->family] = NULL;
+- afinfo->state_byspi = NULL;
+- afinfo->state_bydst = NULL;
+- }
+ }
+ write_unlock_bh(&xfrm_state_afinfo_lock);
+ return err;
+@@ -1206,12 +1557,17 @@ EXPORT_SYMBOL(xfrm_init_state);
+
+ void __init xfrm_state_init(void)
+ {
+- int i;
++ unsigned int sz;
++
++ sz = sizeof(struct hlist_head) * 8;
++
++ xfrm_state_bydst = xfrm_hash_alloc(sz);
++ xfrm_state_bysrc = xfrm_hash_alloc(sz);
++ xfrm_state_byspi = xfrm_hash_alloc(sz);
++ if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
++ panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
++ xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
+
+- for (i=0; i<XFRM_DST_HSIZE; i++) {
+- INIT_LIST_HEAD(&xfrm_state_bydst[i]);
+- INIT_LIST_HEAD(&xfrm_state_byspi[i]);
+- }
+ INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
+ }
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index 3e6a722..b43e764 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -10,6 +10,7 @@
+ *
+ */
+
++#include <linux/crypto.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+@@ -27,6 +28,9 @@
+ #include <net/xfrm.h>
+ #include <net/netlink.h>
+ #include <asm/uaccess.h>
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++#include <linux/in6.h>
++#endif
+
+ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
+ {
+@@ -86,6 +90,22 @@ static int verify_encap_tmpl(struct rtat
+ return 0;
+ }
+
++static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type,
++ xfrm_address_t **addrp)
++{
++ struct rtattr *rt = xfrma[type - 1];
++
++ if (!rt)
++ return 0;
++
++ if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp))
++ return -EINVAL;
++
++ if (addrp)
++ *addrp = RTA_DATA(rt);
++
++ return 0;
++}
+
+ static inline int verify_sec_ctx_len(struct rtattr **xfrma)
+ {
+@@ -156,6 +176,19 @@ static int verify_newsa_info(struct xfrm
+ goto out;
+ break;
+
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++ case IPPROTO_DSTOPTS:
++ case IPPROTO_ROUTING:
++ if (xfrma[XFRMA_ALG_COMP-1] ||
++ xfrma[XFRMA_ALG_AUTH-1] ||
++ xfrma[XFRMA_ALG_CRYPT-1] ||
++ xfrma[XFRMA_ENCAP-1] ||
++ xfrma[XFRMA_SEC_CTX-1] ||
++ !xfrma[XFRMA_COADDR-1])
++ goto out;
++ break;
++#endif
++
+ default:
+ goto out;
+ };
+@@ -170,11 +203,15 @@ static int verify_newsa_info(struct xfrm
+ goto out;
+ if ((err = verify_sec_ctx_len(xfrma)))
+ goto out;
++ if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL)))
++ goto out;
+
+ err = -EINVAL;
+ switch (p->mode) {
+- case 0:
+- case 1:
++ case XFRM_MODE_TRANSPORT:
++ case XFRM_MODE_TUNNEL:
++ case XFRM_MODE_ROUTEOPTIMIZATION:
++ case XFRM_MODE_BEET:
+ break;
+
+ default:
+@@ -212,6 +249,7 @@ static int attach_one_algo(struct xfrm_a
+ return -ENOMEM;
+
+ memcpy(p, ualg, len);
++ strcpy(p->alg_name, algo->name);
+ *algpp = p;
+ return 0;
+ }
+@@ -258,6 +296,24 @@ static int attach_sec_ctx(struct xfrm_st
+ return security_xfrm_state_alloc(x, uctx);
+ }
+
++static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg)
++{
++ struct rtattr *rta = u_arg;
++ xfrm_address_t *p, *uaddrp;
++
++ if (!rta)
++ return 0;
++
++ uaddrp = RTA_DATA(rta);
++ p = kmalloc(sizeof(*p), GFP_KERNEL);
++ if (!p)
++ return -ENOMEM;
++
++ memcpy(p, uaddrp, sizeof(*p));
++ *addrpp = p;
++ return 0;
++}
++
+ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
+ {
+ memcpy(&x->id, &p->id, sizeof(x->id));
+@@ -267,7 +323,7 @@ static void copy_from_user_state(struct
+ x->props.replay_window = p->replay_window;
+ x->props.reqid = p->reqid;
+ x->props.family = p->family;
+- x->props.saddr = p->saddr;
++ memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
+ x->props.flags = p->flags;
+ }
+
+@@ -347,7 +403,8 @@ static struct xfrm_state *xfrm_state_con
+ goto error;
+ if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1])))
+ goto error;
+-
++ if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1])))
++ goto error;
+ err = xfrm_init_state(x);
+ if (err)
+ goto error;
+@@ -416,16 +473,48 @@ out:
+ return err;
+ }
+
++static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p,
++ struct rtattr **xfrma,
++ int *errp)
++{
++ struct xfrm_state *x = NULL;
++ int err;
++
++ if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
++ err = -ESRCH;
++ x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
++ } else {
++ xfrm_address_t *saddr = NULL;
++
++ err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr);
++ if (err)
++ goto out;
++
++ if (!saddr) {
++ err = -EINVAL;
++ goto out;
++ }
++
++ x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto,
++ p->family);
++ }
++
++ out:
++ if (!x && errp)
++ *errp = err;
++ return x;
++}
++
+ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+ {
+ struct xfrm_state *x;
+- int err;
++ int err = -ESRCH;
+ struct km_event c;
+ struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
+
+- x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
++ x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err);
+ if (x == NULL)
+- return -ESRCH;
++ return err;
+
+ if ((err = security_xfrm_state_delete(x)) != 0)
+ goto out;
+@@ -456,7 +545,7 @@ static void copy_to_user_state(struct xf
+ memcpy(&p->lft, &x->lft, sizeof(p->lft));
+ memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
+ memcpy(&p->stats, &x->stats, sizeof(p->stats));
+- p->saddr = x->props.saddr;
++ memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr));
+ p->mode = x->props.mode;
+ p->replay_window = x->props.replay_window;
+ p->reqid = x->props.reqid;
+@@ -519,6 +608,13 @@ static int dump_one_state(struct xfrm_st
+ uctx->ctx_len = x->security->ctx_len;
+ memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len);
+ }
++
++ if (x->coaddr)
++ RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
++
++ if (x->lastused)
++ RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused);
++
+ nlh->nlmsg_len = skb->tail - b;
+ out:
+ sp->this_idx++;
+@@ -540,7 +636,7 @@ static int xfrm_dump_sa(struct sk_buff *
+ info.nlmsg_flags = NLM_F_MULTI;
+ info.this_idx = 0;
+ info.start_idx = cb->args[0];
+- (void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info);
++ (void) xfrm_state_walk(0, dump_one_state, &info);
+ cb->args[0] = info.this_idx;
+
+ return skb->len;
+@@ -576,10 +672,9 @@ static int xfrm_get_sa(struct sk_buff *s
+ struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
+ struct xfrm_state *x;
+ struct sk_buff *resp_skb;
+- int err;
++ int err = -ESRCH;
+
+- x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
+- err = -ESRCH;
++ x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err);
+ if (x == NULL)
+ goto out_noput;
+
+@@ -692,6 +787,22 @@ static int verify_policy_dir(__u8 dir)
+ return 0;
+ }
+
++static int verify_policy_type(__u8 type)
++{
++ switch (type) {
++ case XFRM_POLICY_TYPE_MAIN:
++#ifdef CONFIG_XFRM_SUB_POLICY
++ case XFRM_POLICY_TYPE_SUB:
++#endif
++ break;
++
++ default:
++ return -EINVAL;
++ };
++
++ return 0;
++}
++
+ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
+ {
+ switch (p->share) {
+@@ -785,6 +896,29 @@ static int copy_from_user_tmpl(struct xf
+ return 0;
+ }
+
++static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma)
++{
++ struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1];
++ struct xfrm_userpolicy_type *upt;
++ __u8 type = XFRM_POLICY_TYPE_MAIN;
++ int err;
++
++ if (rt) {
++ if (rt->rta_len < sizeof(*upt))
++ return -EINVAL;
++
++ upt = RTA_DATA(rt);
++ type = upt->type;
++ }
++
++ err = verify_policy_type(type);
++ if (err)
++ return err;
++
++ *tp = type;
++ return 0;
++}
++
+ static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p)
+ {
+ xp->priority = p->priority;
+@@ -823,16 +957,20 @@ static struct xfrm_policy *xfrm_policy_c
+
+ copy_from_user_policy(xp, p);
+
++ err = copy_from_user_policy_type(&xp->type, xfrma);
++ if (err)
++ goto error;
++
+ if (!(err = copy_from_user_tmpl(xp, xfrma)))
+ err = copy_from_user_sec_ctx(xp, xfrma);
+-
+- if (err) {
+- *errp = err;
+- kfree(xp);
+- xp = NULL;
+- }
++ if (err)
++ goto error;
+
+ return xp;
++ error:
++ *errp = err;
++ kfree(xp);
++ return NULL;
+ }
+
+ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+@@ -909,27 +1047,63 @@ rtattr_failure:
+ return -1;
+ }
+
+-static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
++static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
+ {
+- if (xp->security) {
+- int ctx_size = sizeof(struct xfrm_sec_ctx) +
+- xp->security->ctx_len;
+- struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size);
+- struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
++ int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len;
++ struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size);
++ struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
++
++ uctx->exttype = XFRMA_SEC_CTX;
++ uctx->len = ctx_size;
++ uctx->ctx_doi = s->ctx_doi;
++ uctx->ctx_alg = s->ctx_alg;
++ uctx->ctx_len = s->ctx_len;
++ memcpy(uctx + 1, s->ctx_str, s->ctx_len);
++ return 0;
+
+- uctx->exttype = XFRMA_SEC_CTX;
+- uctx->len = ctx_size;
+- uctx->ctx_doi = xp->security->ctx_doi;
+- uctx->ctx_alg = xp->security->ctx_alg;
+- uctx->ctx_len = xp->security->ctx_len;
+- memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len);
++ rtattr_failure:
++ return -1;
++}
++
++static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb)
++{
++ if (x->security) {
++ return copy_sec_ctx(x->security, skb);
+ }
+ return 0;
++}
+
+- rtattr_failure:
++static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
++{
++ if (xp->security) {
++ return copy_sec_ctx(xp->security, skb);
++ }
++ return 0;
++}
++
++#ifdef CONFIG_XFRM_SUB_POLICY
++static int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb)
++{
++ struct xfrm_userpolicy_type upt;
++
++ memset(&upt, 0, sizeof(upt));
++ upt.type = xp->type;
++
++ RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
++
++ return 0;
++
++rtattr_failure:
+ return -1;
+ }
+
++#else
++static inline int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb)
++{
++ return 0;
++}
++#endif
++
+ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr)
+ {
+ struct xfrm_dump_info *sp = ptr;
+@@ -953,6 +1127,8 @@ static int dump_one_policy(struct xfrm_p
+ goto nlmsg_failure;
+ if (copy_to_user_sec_ctx(xp, skb))
+ goto nlmsg_failure;
++ if (copy_to_user_policy_type(xp, skb) < 0)
++ goto nlmsg_failure;
+
+ nlh->nlmsg_len = skb->tail - b;
+ out:
+@@ -974,7 +1150,10 @@ static int xfrm_dump_policy(struct sk_bu
+ info.nlmsg_flags = NLM_F_MULTI;
+ info.this_idx = 0;
+ info.start_idx = cb->args[0];
+- (void) xfrm_policy_walk(dump_one_policy, &info);
++ (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info);
++#ifdef CONFIG_XFRM_SUB_POLICY
++ (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info);
++#endif
+ cb->args[0] = info.this_idx;
+
+ return skb->len;
+@@ -1010,6 +1189,7 @@ static int xfrm_get_policy(struct sk_buf
+ {
+ struct xfrm_policy *xp;
+ struct xfrm_userpolicy_id *p;
++ __u8 type = XFRM_POLICY_TYPE_MAIN;
+ int err;
+ struct km_event c;
+ int delete;
+@@ -1017,12 +1197,16 @@ static int xfrm_get_policy(struct sk_buf
+ p = NLMSG_DATA(nlh);
+ delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
+
++ err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
++ if (err)
++ return err;
++
+ err = verify_policy_dir(p->dir);
+ if (err)
+ return err;
+
+ if (p->index)
+- xp = xfrm_policy_byid(p->dir, p->index, delete);
++ xp = xfrm_policy_byid(type, p->dir, p->index, delete);
+ else {
+ struct rtattr **rtattrs = (struct rtattr **)xfrma;
+ struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+@@ -1039,7 +1223,7 @@ static int xfrm_get_policy(struct sk_buf
+ if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
+ return err;
+ }
+- xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete);
++ xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete);
+ security_xfrm_policy_free(&tmp);
+ }
+ if (xp == NULL)
+@@ -1222,9 +1406,16 @@ out:
+
+ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+ {
+-struct km_event c;
++ struct km_event c;
++ __u8 type = XFRM_POLICY_TYPE_MAIN;
++ int err;
++
++ err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
++ if (err)
++ return err;
+
+- xfrm_policy_flush();
++ xfrm_policy_flush(type);
++ c.data.type = type;
+ c.event = nlh->nlmsg_type;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+@@ -1237,10 +1428,15 @@ static int xfrm_add_pol_expire(struct sk
+ struct xfrm_policy *xp;
+ struct xfrm_user_polexpire *up = NLMSG_DATA(nlh);
+ struct xfrm_userpolicy_info *p = &up->pol;
++ __u8 type = XFRM_POLICY_TYPE_MAIN;
+ int err = -ENOENT;
+
++ err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
++ if (err)
++ return err;
++
+ if (p->index)
+- xp = xfrm_policy_byid(p->dir, p->index, 0);
++ xp = xfrm_policy_byid(type, p->dir, p->index, 0);
+ else {
+ struct rtattr **rtattrs = (struct rtattr **)xfrma;
+ struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+@@ -1257,7 +1453,7 @@ static int xfrm_add_pol_expire(struct sk
+ if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
+ return err;
+ }
+- xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0);
++ xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0);
+ security_xfrm_policy_free(&tmp);
+ }
+
+@@ -1384,6 +1580,7 @@ static const int xfrm_msg_min[XFRM_NR_MS
+ [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
+ [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
+ [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
++ [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
+ };
+
+ #undef XMSGSIZE
+@@ -1708,7 +1905,9 @@ static int build_acquire(struct sk_buff
+
+ if (copy_to_user_tmpl(xp, skb) < 0)
+ goto nlmsg_failure;
+- if (copy_to_user_sec_ctx(xp, skb))
++ if (copy_to_user_state_sec_ctx(x, skb))
++ goto nlmsg_failure;
++ if (copy_to_user_policy_type(xp, skb) < 0)
+ goto nlmsg_failure;
+
+ nlh->nlmsg_len = skb->tail - b;
+@@ -1742,7 +1941,7 @@ static int xfrm_send_acquire(struct xfrm
+ /* User gives us xfrm_user_policy_info followed by an array of 0
+ * or more templates.
+ */
+-static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt,
++static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
+ u8 *data, int len, int *dir)
+ {
+ struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data;
+@@ -1750,7 +1949,7 @@ static struct xfrm_policy *xfrm_compile_
+ struct xfrm_policy *xp;
+ int nr;
+
+- switch (family) {
++ switch (sk->sk_family) {
+ case AF_INET:
+ if (opt != IP_XFRM_POLICY) {
+ *dir = -EOPNOTSUPP;
+@@ -1790,6 +1989,7 @@ static struct xfrm_policy *xfrm_compile_
+ }
+
+ copy_from_user_policy(xp, p);
++ xp->type = XFRM_POLICY_TYPE_MAIN;
+ copy_templates(xp, ut, nr);
+
+ *dir = p->dir;
+@@ -1814,6 +2014,8 @@ static int build_polexpire(struct sk_buf
+ goto nlmsg_failure;
+ if (copy_to_user_sec_ctx(xp, skb))
+ goto nlmsg_failure;
++ if (copy_to_user_policy_type(xp, skb) < 0)
++ goto nlmsg_failure;
+ upe->hard = !!hard;
+
+ nlh->nlmsg_len = skb->tail - b;
+@@ -1885,6 +2087,8 @@ static int xfrm_notify_policy(struct xfr
+ copy_to_user_policy(xp, p, dir);
+ if (copy_to_user_tmpl(xp, skb) < 0)
+ goto nlmsg_failure;
++ if (copy_to_user_policy_type(xp, skb) < 0)
++ goto nlmsg_failure;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+@@ -1902,6 +2106,9 @@ static int xfrm_notify_policy_flush(stru
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
++#ifdef CONFIG_XFRM_SUB_POLICY
++ struct xfrm_userpolicy_type upt;
++#endif
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+@@ -1911,6 +2118,13 @@ static int xfrm_notify_policy_flush(stru
+
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
++ nlh->nlmsg_flags = 0;
++
++#ifdef CONFIG_XFRM_SUB_POLICY
++ memset(&upt, 0, sizeof(upt));
++ upt.type = c->data.type;
++ RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
++#endif
+
+ nlh->nlmsg_len = skb->tail - b;
+
+@@ -1918,6 +2132,9 @@ static int xfrm_notify_policy_flush(stru
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
+
+ nlmsg_failure:
++#ifdef CONFIG_XFRM_SUB_POLICY
++rtattr_failure:
++#endif
+ kfree_skb(skb);
+ return -1;
+ }
+@@ -1942,19 +2159,64 @@ static int xfrm_send_policy_notify(struc
+
+ }
+
++static int build_report(struct sk_buff *skb, u8 proto,
++ struct xfrm_selector *sel, xfrm_address_t *addr)
++{
++ struct xfrm_user_report *ur;
++ struct nlmsghdr *nlh;
++ unsigned char *b = skb->tail;
++
++ nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur));
++ ur = NLMSG_DATA(nlh);
++ nlh->nlmsg_flags = 0;
++
++ ur->proto = proto;
++ memcpy(&ur->sel, sel, sizeof(ur->sel));
++
++ if (addr)
++ RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
++
++ nlh->nlmsg_len = skb->tail - b;
++ return skb->len;
++
++nlmsg_failure:
++rtattr_failure:
++ skb_trim(skb, b - skb->data);
++ return -1;
++}
++
++static int xfrm_send_report(u8 proto, struct xfrm_selector *sel,
++ xfrm_address_t *addr)
++{
++ struct sk_buff *skb;
++ size_t len;
++
++ len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report)));
++ skb = alloc_skb(len, GFP_ATOMIC);
++ if (skb == NULL)
++ return -ENOMEM;
++
++ if (build_report(skb, proto, sel, addr) < 0)
++ BUG();
++
++ NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT;
++ return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);
++}
++
+ static struct xfrm_mgr netlink_mgr = {
+ .id = "netlink",
+ .notify = xfrm_send_state_notify,
+ .acquire = xfrm_send_acquire,
+ .compile_policy = xfrm_compile_policy,
+ .notify_policy = xfrm_send_policy_notify,
++ .report = xfrm_send_report,
+ };
+
+ static int __init xfrm_user_init(void)
+ {
+ struct sock *nlsk;
+
+- printk(KERN_INFO "Initializing IPsec netlink socket\n");
++ printk(KERN_INFO "Initializing XFRM netlink socket\n");
+
+ nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
+ xfrm_netlink_rcv, THIS_MODULE);
+diff --git a/scripts/.gitignore b/scripts/.gitignore
+index a234e52..a1f52cb 100644
+--- a/scripts/.gitignore
++++ b/scripts/.gitignore
+@@ -5,3 +5,4 @@ conmakehash
+ kallsyms
+ pnmtologo
+ bin2c
++unifdef
+diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
+index bb19c15..4f5ff19 100644
+--- a/scripts/Kbuild.include
++++ b/scripts/Kbuild.include
+@@ -8,9 +8,13 @@ empty :=
+ space := $(empty) $(empty)
+
+ ###
++# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
++dot-target = $(dir $@).$(notdir $@)
++
++###
+ # The temporary file to save gcc -MD generated dependencies must not
+ # contain a comma
+-depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
++depfile = $(subst $(comma),_,$(dot-target).d)
+
+ ###
+ # filename of target with directory and extension stripped
+@@ -59,6 +63,13 @@ as-option = $(shell if $(CC) $(CFLAGS) $
+ -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
+ else echo "$(2)"; fi ;)
+
++# as-instr
++# Usage: cflags-y += $(call as-instr, instr, option1, option2)
++
++as-instr = $(shell if echo -e "$(1)" | $(AS) >/dev/null 2>&1 -W -Z -o astest$$$$.out ; \
++ then echo "$(2)"; else echo "$(3)"; fi; \
++ rm -f astest$$$$.out)
++
+ # cc-option
+ # Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
+
+@@ -119,40 +130,83 @@ objectify = $(foreach o,$(1),$(if $(filt
+ ifneq ($(KBUILD_NOCMDDEP),1)
+ # Check if both arguments has same arguments. Result in empty string if equal
+ # User may override this check using make KBUILD_NOCMDDEP=1
+-arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
++arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
++ $(filter-out $(cmd_$@), $(cmd_$(1))) )
+ endif
+
+ # echo command. Short version is $(quiet) equals quiet, otherwise full command
+ echo-cmd = $(if $($(quiet)cmd_$(1)), \
+- echo ' $(call escsq,$($(quiet)cmd_$(1)))';)
++ echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+
++# >'< substitution is for echo to work,
++# >$< substitution to preserve $ when reloading .cmd file
++# note: when using inline perl scripts [perl -e '...$$t=1;...']
++# in $(cmd_xxx) double $$ your perl vars
+ make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
+
+-# function to only execute the passed command if necessary
+-# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
+-# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
++# Find any prerequisites that is newer than target or that does not exist.
++# PHONY targets skipped in both cases.
++any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
++
++# Execute command if command has changed or prerequisitei(s) are updated
+ #
+-if_changed = $(if $(strip $(filter-out $(PHONY),$?) \
+- $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
+- @set -e; \
+- $(echo-cmd) $(cmd_$(1)); \
+- echo 'cmd_$@ := $(make-cmd)' > $(@D)/.$(@F).cmd)
++if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
++ @set -e; \
++ $(echo-cmd) $(cmd_$(1)); \
++ echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+
+ # execute the command and also postprocess generated .d dependencies
+ # file
+-if_changed_dep = $(if $(strip $(filter-out $(PHONY),$?) \
+- $(filter-out FORCE $(wildcard $^),$^) \
+- $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
+- @set -e; \
+- $(echo-cmd) $(cmd_$(1)); \
+- scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(@D)/.$(@F).tmp; \
+- rm -f $(depfile); \
+- mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
++if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
++ @set -e; \
++ $(echo-cmd) $(cmd_$(1)); \
++ scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
++ rm -f $(depfile); \
++ mv -f $(dot-target).tmp $(dot-target).cmd)
+
+ # Usage: $(call if_changed_rule,foo)
+ # will check if $(cmd_foo) changed, or any of the prequisites changed,
+ # and if so will execute $(rule_foo)
+-if_changed_rule = $(if $(strip $(filter-out $(PHONY),$?) \
+- $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
+- @set -e; \
+- $(rule_$(1)))
++if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
++ @set -e; \
++ $(rule_$(1)))
++
++###
++# why - tell why a a target got build
++# enabled by make V=2
++# Output (listed in the order they are checked):
++# (1) - due to target is PHONY
++# (2) - due to target missing
++# (3) - due to: file1.h file2.h
++# (4) - due to command line change
++# (5) - due to missing .cmd file
++# (6) - due to target not in $(targets)
++# (1) PHONY targets are always build
++# (2) No target, so we better build it
++# (3) Prerequisite is newer than target
++# (4) The command line stored in the file named dir/.target.cmd
++# differed from actual command line. This happens when compiler
++# options changes
++# (5) No dir/.target.cmd file (used to store command line)
++# (6) No dir/.target.cmd file and target not listed in $(targets)
++# This is a good hint that there is a bug in the kbuild file
++ifeq ($(KBUILD_VERBOSE),2)
++why = \
++ $(if $(filter $@, $(PHONY)),- due to target is PHONY, \
++ $(if $(wildcard $@), \
++ $(if $(strip $(any-prereq)),- due to: $(any-prereq), \
++ $(if $(arg-check), \
++ $(if $(cmd_$@),- due to command line change, \
++ $(if $(filter $@, $(targets)), \
++ - due to missing .cmd file, \
++ - due to $(notdir $@) not in $$(targets) \
++ ) \
++ ) \
++ ) \
++ ), \
++ - due to target missing \
++ ) \
++ )
++
++echo-why = $(call escsq, $(strip $(why)))
++endif
+diff --git a/scripts/Makefile b/scripts/Makefile
+index 6f6b48f..1c73c5a 100644
+--- a/scripts/Makefile
++++ b/scripts/Makefile
+@@ -13,10 +13,13 @@ hostprogs-$(CONFIG_VT) += conm
+ hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash
+ hostprogs-$(CONFIG_IKCONFIG) += bin2c
+
+-always := $(hostprogs-y)
++always := $(hostprogs-y) $(hostprogs-m)
++
++# The following hostprogs-y programs are only build on demand
++hostprogs-y += unifdef
+
+ subdir-$(CONFIG_MODVERSIONS) += genksyms
+-subdir-$(CONFIG_MODULES) += mod
++subdir-y += mod
+
+ # Let clean descend into subdirs
+ subdir- += basic kconfig package
+diff --git a/scripts/Makefile.build b/scripts/Makefile.build
+index 3cb445c..e2ad2dc 100644
+--- a/scripts/Makefile.build
++++ b/scripts/Makefile.build
+@@ -191,9 +191,10 @@ define rule_cc_o_c
+ $(call echo-cmd,checksrc) $(cmd_checksrc) \
+ $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
+ $(cmd_modversions) \
+- scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > $(@D)/.$(@F).tmp; \
++ scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
++ $(dot-target).tmp; \
+ rm -f $(depfile); \
+- mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd
++ mv -f $(dot-target).tmp $(dot-target).cmd
+ endef
+
+ # Built-in and composite module parts
+diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
+index 12e1daf..4241e0d 100644
+--- a/scripts/Makefile.headersinst
++++ b/scripts/Makefile.headersinst
+@@ -7,7 +7,7 @@
+ #
+ # ==========================================================================
+
+-UNIFDEF := unifdef -U__KERNEL__
++UNIFDEF := scripts/unifdef -U__KERNEL__
+
+ # Eliminate the contents of (and inclusions of) compiler.h
+ HDRSED := sed -e "s/ inline / __inline__ /g" \
+@@ -23,30 +23,30 @@ HDRSED := sed -e "s/ inline / __inline
+
+ _dst := $(if $(dst),$(dst),$(obj))
+
+-.PHONY: __headersinst
+-__headersinst:
+-
+-
+ ifeq (,$(patsubst include/asm/%,,$(obj)/))
+ # For producing the generated stuff in include/asm for biarch builds, include
+ # both sets of Kbuild files; we'll generate anything which is mentioned in
+ # _either_ arch, and recurse into subdirectories which are mentioned in either
+ # arch. Since some directories may exist in one but not the other, we must
+-# use '-include'.
++# use $(wildcard...).
+ GENASM := 1
+ archasm := $(subst include/asm,asm-$(ARCH),$(obj))
+ altarchasm := $(subst include/asm,asm-$(ALTARCH),$(obj))
+--include $(srctree)/include/$(archasm)/Kbuild
+--include $(srctree)/include/$(altarchasm)/Kbuild
++KBUILDFILES := $(wildcard $(srctree)/include/$(archasm)/Kbuild $(srctree)/include/$(altarchasm)/Kbuild)
+ else
+-include $(srctree)/$(obj)/Kbuild
++KBUILDFILES := $(srctree)/$(obj)/Kbuild
+ endif
+
+-include scripts/Kbuild.include
++include $(KBUILDFILES)
++
++include scripts/Kbuild.include
+
+ # If this is include/asm-$(ARCH) and there's no $(ALTARCH), then
+ # override $(_dst) so that we install to include/asm directly.
+-ifeq ($(obj)$(ALTARCH),include/asm-$(ARCH))
++# Unless $(BIASMDIR) is set, in which case we're probably doing
++# a 'headers_install_all' build and we should keep the -$(ARCH)
++# in the directory name.
++ifeq ($(obj)$(ALTARCH),include/asm-$(ARCH)$(BIASMDIR))
+ _dst := include/asm
+ endif
+
+@@ -56,6 +56,23 @@ subdir-y := $(patsubst %/,%,$(filter %/,
+ header-y := $(filter-out %/, $(header-y))
+ header-y := $(filter-out $(unifdef-y),$(header-y))
+
++# stamp files for header checks
++check-y := $(patsubst %,.check.%,$(header-y) $(unifdef-y) $(objhdr-y))
++
++# Work out what needs to be removed
++oldheaders := $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,%,$(wildcard $(INSTALL_HDR_PATH)/$(_dst)/*.h))
++unwanted := $(filter-out $(header-y) $(unifdef-y) $(objhdr-y),$(oldheaders))
++
++oldcheckstamps := $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,%,$(wildcard $(INSTALL_HDR_PATH)/$(_dst)/.check.*.h))
++unwanted += $(filter-out $(check-y),$(oldcheckstamps))
++
++# Prefix them all with full paths to $(INSTALL_HDR_PATH)
++header-y := $(patsubst %,$(INSTALL_HDR_PATH)/$(_dst)/%,$(header-y))
++unifdef-y := $(patsubst %,$(INSTALL_HDR_PATH)/$(_dst)/%,$(unifdef-y))
++objhdr-y := $(patsubst %,$(INSTALL_HDR_PATH)/$(_dst)/%,$(objhdr-y))
++check-y := $(patsubst %,$(INSTALL_HDR_PATH)/$(_dst)/%,$(check-y))
++
++
+ ifdef ALTARCH
+ ifeq ($(obj),include/asm-$(ARCH))
+ altarch-y := altarch-dir
+@@ -67,43 +84,47 @@ export ALTARCH
+ export ARCHDEF
+ export ALTARCHDEF
+
+-quiet_cmd_o_hdr_install = INSTALL $(_dst)/$@
+- cmd_o_hdr_install = cp $(objtree)/$(obj)/$@ $(INSTALL_HDR_PATH)/$(_dst)
++quiet_cmd_o_hdr_install = INSTALL $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
++ cmd_o_hdr_install = cp $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,$(objtree)/$(obj)/%,$@) \
++ $(INSTALL_HDR_PATH)/$(_dst)
++
++quiet_cmd_headers_install = INSTALL $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
++ cmd_headers_install = $(HDRSED) $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,$(srctree)/$(obj)/%,$@) \
++ > $@
+
+-quiet_cmd_headers_install = INSTALL $(_dst)/$@
+- cmd_headers_install = $(HDRSED) $(srctree)/$(obj)/$@ \
+- > $(INSTALL_HDR_PATH)/$(_dst)/$@
++quiet_cmd_unifdef = UNIFDEF $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
++ cmd_unifdef = $(UNIFDEF) $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,$(srctree)/$(obj)/%,$@) \
++ | $(HDRSED) > $@ || :
+
+-quiet_cmd_unifdef = UNIFDEF $(_dst)/$@
+- cmd_unifdef = $(UNIFDEF) $(srctree)/$(obj)/$@ | $(HDRSED) \
+- > $(INSTALL_HDR_PATH)/$(_dst)/$@ || :
++quiet_cmd_check = CHECK $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/.check.%,$(_dst)/%,$@)
++ cmd_check = $(CONFIG_SHELL) $(srctree)/scripts/hdrcheck.sh \
++ $(INSTALL_HDR_PATH)/include $(subst /.check.,/,$@) $@
+
+-quiet_cmd_check = CHECK $(_dst)/$@
+- cmd_check = $(srctree)/scripts/hdrcheck.sh \
+- $(INSTALL_HDR_PATH)/include \
+- $(INSTALL_HDR_PATH)/$(_dst)/$@
++quiet_cmd_remove = REMOVE $(_dst)/$@
++ cmd_remove = rm -f $(INSTALL_HDR_PATH)/$(_dst)/$@
+
+-quiet_cmd_mkdir = MKDIR $@
+- cmd_mkdir = mkdir -p $(INSTALL_HDR_PATH)/$@
++quiet_cmd_mkdir = MKDIR $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
++ cmd_mkdir = mkdir -p $@
+
+-quiet_cmd_gen = GEN $(_dst)/$@
++quiet_cmd_gen = GEN $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
+ cmd_gen = \
+-STUBDEF=__ASM_STUB_`echo $@ | tr a-z. A-Z_`; \
++FNAME=$(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,%,$@) \
++STUBDEF=__ASM_STUB_`echo $$FNAME | tr a-z. A-Z_`; \
+ (echo "/* File autogenerated by 'make headers_install' */" ; \
+ echo "\#ifndef $$STUBDEF" ; \
+ echo "\#define $$STUBDEF" ; \
+ echo "\# if $(ARCHDEF)" ; \
+-if [ -r $(INSTALL_HDR_PATH)/include/$(archasm)/$@ ]; then \
+- echo "\# include <$(archasm)/$@>" ; \
++if [ -r $(subst /$(_dst)/,/include/$(archasm)/,$@) ]; then \
++ echo "\# include <$(archasm)/$$FNAME>" ; \
+ else \
+- echo "\# error $(archasm)/$@ does not exist in" \
++ echo "\# error $(archasm)/$$FNAME does not exist in" \
+ "the $(ARCH) architecture" ; \
+ fi ; \
+ echo "\# elif $(ALTARCHDEF)" ; \
+-if [ -r $(INSTALL_HDR_PATH)/include/$(altarchasm)/$@ ]; then \
+- echo "\# include <$(altarchasm)/$@>" ; \
++if [ -r $(subst /$(_dst)/,/include/$(altarchasm)/,$@) ]; then \
++ echo "\# include <$(altarchasm)/$$FNAME>" ; \
+ else \
+- echo "\# error $(altarchasm)/$@ does not exist in" \
++ echo "\# error $(altarchasm)/$$FNAME does not exist in" \
+ "the $(ALTARCH) architecture" ; \
+ fi ; \
+ echo "\# else" ; \
+@@ -111,37 +132,49 @@ echo "\# warning This machine appears t
+ "neither $(ARCH) nor $(ALTARCH)." ; \
+ echo "\# endif" ; \
+ echo "\#endif /* $$STUBDEF */" ; \
+-) > $(INSTALL_HDR_PATH)/$(_dst)/$@
++) > $@
+
+-__headersinst: $(subdir-y) $(header-y) $(unifdef-y) $(altarch-y) $(objhdr-y)
+-
+-.PHONY: $(header-y) $(unifdef-y) $(subdir-y)
++.PHONY: __headersinst __headerscheck
+
+ ifdef HDRCHECK
+-# Rules for checking headers
+-$(objhdr-y) $(header-y) $(unifdef-y):
++__headerscheck: $(subdir-y) $(check-y)
++ @true
++
++$(check-y) : $(INSTALL_HDR_PATH)/$(_dst)/.check.%.h : $(INSTALL_HDR_PATH)/$(_dst)/%.h
+ $(call cmd,check)
++
++# Other dependencies for $(check-y)
++-include /dev/null $(check-y)
++
++# ... but leave $(check-y) as .PHONY for now until those deps are actually correct.
++.PHONY: $(check-y)
++
+ else
+ # Rules for installing headers
++__headersinst: $(subdir-y) $(header-y) $(unifdef-y) $(altarch-y) $(objhdr-y)
++ @true
+
+-$(objhdr-y) $(subdir-y) $(header-y) $(unifdef-y): $(_dst)
++$(objhdr-y) $(subdir-y) $(header-y) $(unifdef-y): | $(INSTALL_HDR_PATH)/$(_dst) $(unwanted)
+
+-.PHONY: $(_dst)
+-$(_dst):
++$(INSTALL_HDR_PATH)/$(_dst):
+ $(call cmd,mkdir)
+
++.PHONY: $(unwanted)
++$(unwanted):
++ $(call cmd,remove)
++
+ ifdef GENASM
+-$(objhdr-y) $(header-y) $(unifdef-y):
++$(objhdr-y) $(header-y) $(unifdef-y): $(KBUILDFILES)
+ $(call cmd,gen)
+
+ else
+-$(objhdr-y):
++$(objhdr-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(objtree)/$(obj)/%.h $(KBUILDFILES)
+ $(call cmd,o_hdr_install)
+
+-$(header-y):
++$(header-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(srctree)/$(obj)/%.h $(KBUILDFILES)
+ $(call cmd,headers_install)
+
+-$(unifdef-y):
++$(unifdef-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(srctree)/$(obj)/%.h $(KBUILDFILES)
+ $(call cmd,unifdef)
+ endif
+ endif
+@@ -153,8 +186,9 @@ hdrinst := -rR -f $(srctree)/scripts/Mak
+ # for their existence.
+ altarch-dir: $(subdir-y) $(header-y) $(unifdef-y) $(objhdr-y)
+ $(Q)$(MAKE) $(hdrinst)=include/asm-$(ALTARCH) dst=include/asm-$(ALTARCH)
+- $(Q)$(MAKE) $(hdrinst)=include/asm dst=include/asm
++ $(Q)$(MAKE) $(hdrinst)=include/asm dst=include/asm$(BIASMDIR)
+
+ # Recursion
++.PHONY: $(subdir-y)
+ $(subdir-y):
+ $(Q)$(MAKE) $(hdrinst)=$(obj)/$@ dst=$(_dst)/$@ rel=../$(rel)
+diff --git a/scripts/Makefile.host b/scripts/Makefile.host
+index 060f4c5..575afbe 100644
+--- a/scripts/Makefile.host
++++ b/scripts/Makefile.host
+@@ -32,11 +32,6 @@
+
+ __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
+
+-# hostprogs-y := tools/build may have been specified. Retreive directory
+-host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
+-host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
+-
+-
+ # C code
+ # Executables compiled from a single .c file
+ host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
+@@ -65,6 +60,21 @@ host-cobjs := $(filter-out %.so,$(host-c
+ #Object (.o) files used by the shared libaries
+ host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+
++# output directory for programs/.o files
++# hostprogs-y := tools/build may have been specified. Retreive directory
++host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
++# directory of .o files from prog-objs notation
++host-objdirs += $(foreach f,$(host-cmulti), \
++ $(foreach m,$($(f)-objs), \
++ $(if $(dir $(m)),$(dir $(m)))))
++# directory of .o files from prog-cxxobjs notation
++host-objdirs += $(foreach f,$(host-cxxmulti), \
++ $(foreach m,$($(f)-cxxobjs), \
++ $(if $(dir $(m)),$(dir $(m)))))
++
++host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
++
++
+ __hostprogs := $(addprefix $(obj)/,$(__hostprogs))
+ host-csingle := $(addprefix $(obj)/,$(host-csingle))
+ host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
+diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
+index 0a64688..65e0a79 100644
+--- a/scripts/Makefile.modpost
++++ b/scripts/Makefile.modpost
+@@ -32,6 +32,10 @@
+ # Step 4 is solely used to allow module versioning in external modules,
+ # where the CRC of each module is retrieved from the Module.symers file.
+
++# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
++# symbols in the final module linking stage
++# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
++# This is solely usefull to speed up test compiles
+ PHONY := _modpost
+ _modpost: __modpost
+
+@@ -40,30 +44,38 @@ include scripts/Kbuild.include
+ include scripts/Makefile.lib
+
+ kernelsymfile := $(objtree)/Module.symvers
+-modulesymfile := $(KBUILD_EXTMOD)/Module.symvers
++modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+
+ # Step 1), find all modules listed in $(MODVERDIR)/
+ __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+ modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o)))
+
+-_modpost: $(modules)
++# Stop after building .o files if NOFINAL is set. Makes compile tests quicker
++_modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules))
+
+
+ # Step 2), invoke modpost
+ # Includes step 3,4
+-quiet_cmd_modpost = MODPOST
++quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
+ cmd_modpost = scripts/mod/modpost \
+ $(if $(CONFIG_MODVERSIONS),-m) \
+ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
+ $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
+ $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
+ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
+- $(filter-out FORCE,$^)
++ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
++ $(wildcard vmlinux) $(filter-out FORCE,$^)
+
+ PHONY += __modpost
+-__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
++__modpost: $(modules:.ko=.o) FORCE
+ $(call cmd,modpost)
+
++quiet_cmd_kernel-mod = MODPOST $@
++ cmd_kernel-mod = $(cmd_modpost)
++
++vmlinux: FORCE
++ $(call cmd,kernel-mod)
++
+ # Declare generated files as targets for modpost
+ $(symverfile): __modpost ;
+ $(modules:.ko=.mod.c): __modpost ;
+@@ -85,7 +97,7 @@ targets += $(modules:.ko=.mod.o)
+
+ # Step 6), final link of the modules
+ quiet_cmd_ld_ko_o = LD [M] $@
+- cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
++ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
+ $(filter-out FORCE,$^)
+
+ $(modules): %.ko :%.o %.mod.o FORCE
+diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
+index cb02baa..d6071cb 100644
+--- a/scripts/basic/docproc.c
++++ b/scripts/basic/docproc.c
+@@ -177,6 +177,7 @@ void find_export_symbols(char * filename
+ {
+ fprintf(stderr, "docproc: ");
+ perror(real_filename);
++ exit(1);
+ }
+ while(fgets(line, MAXLINESZ, fp)) {
+ char *p;
+@@ -249,7 +250,7 @@ void intfunc(char * filename) { docfunct
+ void extfunc(char * filename) { docfunctions(filename, FUNCTION); }
+
+ /*
+- * Document spåecific function(s) in a file.
++ * Document specific function(s) in a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function function1 [-function function2]
+ */
+diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
+index b349246..f7844f6 100755
+--- a/scripts/checkstack.pl
++++ b/scripts/checkstack.pl
+@@ -62,6 +62,8 @@ my (@stack, $re, $x, $xs);
+ } elsif ($arch eq 'ppc64') {
+ #XXX
+ $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
++ } elsif ($arch eq 'powerpc') {
++ $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
+ } elsif ($arch =~ /^s390x?$/) {
+ # 11160: a7 fb ff 60 aghi %r15,-160
+ $re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh
+new file mode 100644
+index 0000000..325c0a1
+--- /dev/null
++++ b/scripts/gcc-x86_64-has-stack-protector.sh
+@@ -0,0 +1,6 @@
++#!/bin/sh
++
++echo "int foo(void) { char X[200]; return 3; }" | $1 -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
++if [ "$?" -eq "0" ] ; then
++ echo $2
++fi
+diff --git a/scripts/hdrcheck.sh b/scripts/hdrcheck.sh
+index b5ca35a..3159858 100755
+--- a/scripts/hdrcheck.sh
++++ b/scripts/hdrcheck.sh
+@@ -6,3 +6,5 @@ for FILE in `grep '^[ \t]*#[ \t]*include
+ exit 1
+ fi
+ done
++# FIXME: List dependencies into $3
++touch $3
+diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
+index e6499db..7e7e147 100644
+--- a/scripts/kconfig/Makefile
++++ b/scripts/kconfig/Makefile
+@@ -11,7 +11,6 @@ gconfig: $(obj)/gconf
+ $< arch/$(ARCH)/Kconfig
+
+ menuconfig: $(obj)/mconf
+- $(Q)$(MAKE) $(build)=scripts/kconfig/lxdialog
+ $< arch/$(ARCH)/Kconfig
+
+ config: $(obj)/conf
+@@ -74,12 +73,30 @@ help:
+ @echo ' xconfig - Update current config utilising a QT based front-end'
+ @echo ' gconfig - Update current config utilising a GTK based front-end'
+ @echo ' oldconfig - Update current config utilising a provided .config as base'
++ @echo ' silentoldconfig - Same as oldconfig, but quietly'
+ @echo ' randconfig - New config with random answer to all options'
+ @echo ' defconfig - New config with default answer to all options'
+ @echo ' allmodconfig - New config selecting modules when possible'
+ @echo ' allyesconfig - New config where all options are accepted with yes'
+ @echo ' allnoconfig - New config where all options are answered with no'
+
++# lxdialog stuff
++check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
++
++# Use reursively expanded variables so we do not call gcc unless
++# we really need to do so. (Do not call gcc as part of make mrproper)
++HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
++HOST_LOADLIBES = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
++
++HOST_EXTRACFLAGS += -DLOCALE
++
++PHONY += $(obj)/dochecklxdialog
++$(obj)/dochecklxdialog:
++ $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_LOADLIBES)
++
++always := dochecklxdialog
++
++
+ # ===========================================================================
+ # Shared Makefile for the various kconfig executables:
+ # conf: Used for defconfig, oldconfig and related targets
+@@ -91,11 +108,19 @@ help:
+ # Based on GTK which needs to be installed to compile it
+ # object files used by all kconfig flavours
+
+-hostprogs-y := conf mconf qconf gconf kxgettext
++lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
++lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
++
+ conf-objs := conf.o zconf.tab.o
+-mconf-objs := mconf.o zconf.tab.o
++mconf-objs := mconf.o zconf.tab.o $(lxdialog)
+ kxgettext-objs := kxgettext.o zconf.tab.o
+
++hostprogs-y := conf qconf gconf kxgettext
++
++ifeq ($(MAKECMDGOALS),menuconfig)
++ hostprogs-y += mconf
++endif
++
+ ifeq ($(MAKECMDGOALS),xconfig)
+ qconf-target := 1
+ endif
+@@ -115,7 +140,6 @@ endif
+
+ clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
+ .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
+-subdir- += lxdialog
+
+ # Needed for systems without gettext
+ KBUILD_HAVE_NLS := $(shell \
+diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
+index a69d8ac..66b15ef 100644
+--- a/scripts/kconfig/confdata.c
++++ b/scripts/kconfig/confdata.c
+@@ -193,8 +193,11 @@ load:
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+- if (p2)
+- *p2 = 0;
++ if (p2) {
++ *p2-- = 0;
++ if (*p2 == '\r')
++ *p2 = 0;
++ }
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 7);
+ if (!sym) {
+@@ -266,6 +269,7 @@ load:
+ ;
+ }
+ break;
++ case '\r':
+ case '\n':
+ break;
+ default:
+@@ -513,7 +517,7 @@ int conf_write(const char *name)
+ fclose(out);
+
+ if (*tmpname) {
+- strcat(dirname, name ? name : conf_get_configname());
++ strcat(dirname, basename);
+ strcat(dirname, ".old");
+ rename(newname, dirname);
+ if (rename(tmpname, newname))
+diff --git a/scripts/kconfig/lxdialog/Makefile b/scripts/kconfig/lxdialog/Makefile
+deleted file mode 100644
+index a8b0263..0000000
+--- a/scripts/kconfig/lxdialog/Makefile
++++ /dev/null
+@@ -1,21 +0,0 @@
+-# Makefile to build lxdialog package
+-#
+-
+-check-lxdialog := $(srctree)/$(src)/check-lxdialog.sh
+-
+-# Use reursively expanded variables so we do not call gcc unless
+-# we really need to do so. (Do not call gcc as part of make mrproper)
+-HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
+-HOST_LOADLIBES = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+-
+-HOST_EXTRACFLAGS += -DLOCALE
+-
+-PHONY += dochecklxdialog
+-$(obj)/dochecklxdialog:
+- $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_LOADLIBES)
+-
+-hostprogs-y := lxdialog
+-always := $(hostprogs-y) dochecklxdialog
+-
+-lxdialog-objs := checklist.o menubox.o textbox.o yesno.o inputbox.o \
+- util.o lxdialog.o msgbox.o
+diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
+index 7988641..cf69708 100644
+--- a/scripts/kconfig/lxdialog/checklist.c
++++ b/scripts/kconfig/lxdialog/checklist.c
+@@ -28,25 +28,25 @@ static int list_width, check_x, item_x;
+ /*
+ * Print list item
+ */
+-static void print_item(WINDOW * win, const char *item, int status, int choice,
+- int selected)
++static void print_item(WINDOW * win, int choice, int selected)
+ {
+ int i;
+
+ /* Clear 'residue' of last item */
+- wattrset(win, menubox_attr);
++ wattrset(win, dlg.menubox.atr);
+ wmove(win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch(win, ' ');
+
+ wmove(win, choice, check_x);
+- wattrset(win, selected ? check_selected_attr : check_attr);
+- wprintw(win, "(%c)", status ? 'X' : ' ');
+-
+- wattrset(win, selected ? tag_selected_attr : tag_attr);
+- mvwaddch(win, choice, item_x, item[0]);
+- wattrset(win, selected ? item_selected_attr : item_attr);
+- waddstr(win, (char *)item + 1);
++ wattrset(win, selected ? dlg.check_selected.atr
++ : dlg.check.atr);
++ wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
++
++ wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
++ mvwaddch(win, choice, item_x, item_str()[0]);
++ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
++ waddstr(win, (char *)item_str() + 1);
+ if (selected) {
+ wmove(win, choice, check_x + 1);
+ wrefresh(win);
+@@ -62,11 +62,11 @@ static void print_arrows(WINDOW * win, i
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+- wattrset(win, uarrow_attr);
++ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+- wattrset(win, menubox_attr);
++ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+@@ -77,11 +77,11 @@ static void print_arrows(WINDOW * win, i
+ wmove(win, y, x);
+
+ if ((height < item_no) && (scroll + choice < item_no - 1)) {
+- wattrset(win, darrow_attr);
++ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+- wattrset(win, menubox_border_attr);
++ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+@@ -109,32 +109,29 @@ static void print_buttons(WINDOW * dialo
+ * in the style of radiolist (only one option turned on at a time).
+ */
+ int dialog_checklist(const char *title, const char *prompt, int height,
+- int width, int list_height, int item_no,
+- const char *const *items)
++ int width, int list_height)
+ {
+ int i, x, y, box_x, box_y;
+- int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
++ int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+ WINDOW *dialog, *list;
+
+- /* Allocate space for storing item on/off status */
+- if ((status = malloc(sizeof(int) * item_no)) == NULL) {
+- endwin();
+- fprintf(stderr,
+- "\nCan't allocate memory in dialog_checklist().\n");
+- exit(-1);
++ /* which item to highlight */
++ item_foreach() {
++ if (item_is_tag('X'))
++ choice = item_n();
++ if (item_is_selected()) {
++ choice = item_n();
++ break;
++ }
+ }
+
+- /* Initializes status */
+- for (i = 0; i < item_no; i++) {
+- status[i] = !strcasecmp(items[i * 3 + 2], "on");
+- if ((!choice && status[i])
+- || !strcasecmp(items[i * 3 + 2], "selected"))
+- choice = i + 1;
+- }
+- if (choice)
+- choice--;
++do_resize:
++ if (getmaxy(stdscr) < (height + 6))
++ return -ERRDISPLAYTOOSMALL;
++ if (getmaxx(stdscr) < (width + 6))
++ return -ERRDISPLAYTOOSMALL;
+
+- max_choice = MIN(list_height, item_no);
++ max_choice = MIN(list_height, item_count());
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+@@ -145,17 +142,18 @@ int dialog_checklist(const char *title,
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+- wattrset(dialog, border_attr);
++ draw_box(dialog, 0, 0, height, width,
++ dlg.dialog.atr, dlg.border.atr);
++ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ list_width = width - 6;
+@@ -170,12 +168,12 @@ int dialog_checklist(const char *title,
+
+ /* draw a box around the list items */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+- menubox_border_attr, menubox_attr);
++ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ /* Find length of longest item in order to center checklist */
+ check_x = 0;
+- for (i = 0; i < item_no; i++)
+- check_x = MAX(check_x, +strlen(items[i * 3 + 1]) + 4);
++ item_foreach()
++ check_x = MAX(check_x, strlen(item_str()) + 4);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + 4;
+@@ -187,14 +185,11 @@ int dialog_checklist(const char *title,
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++) {
+- if (i != choice)
+- print_item(list, items[(scroll + i) * 3 + 1],
+- status[i + scroll], i, 0);
++ item_set(scroll + i);
++ print_item(list, i, i == choice);
+ }
+- print_item(list, items[(scroll + choice) * 3 + 1],
+- status[choice + scroll], choice, 1);
+
+- print_arrows(dialog, choice, item_no, scroll,
++ print_arrows(dialog, choice, item_count(), scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ print_buttons(dialog, height, width, 0);
+@@ -203,13 +198,14 @@ int dialog_checklist(const char *title,
+ wnoutrefresh(list);
+ doupdate();
+
+- while (key != ESC) {
++ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+- for (i = 0; i < max_choice; i++)
+- if (toupper(key) ==
+- toupper(items[(scroll + i) * 3 + 1][0]))
++ for (i = 0; i < max_choice; i++) {
++ item_set(i + scroll);
++ if (toupper(key) == toupper(item_str()[0]))
+ break;
++ }
+
+ if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+ key == '+' || key == '-') {
+@@ -220,15 +216,16 @@ int dialog_checklist(const char *title,
+ /* Scroll list down */
+ if (list_height > 1) {
+ /* De-highlight current first item */
+- print_item(list, items[scroll * 3 + 1],
+- status[scroll], 0, FALSE);
++ item_set(scroll);
++ print_item(list, 0, FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, -1);
+ scrollok(list, FALSE);
+ }
+ scroll--;
+- print_item(list, items[scroll * 3 + 1], status[scroll], 0, TRUE);
+- print_arrows(dialog, choice, item_no,
++ item_set(scroll);
++ print_item(list, 0, TRUE);
++ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+@@ -239,23 +236,24 @@ int dialog_checklist(const char *title,
+ i = choice - 1;
+ } else if (key == KEY_DOWN || key == '+') {
+ if (choice == max_choice - 1) {
+- if (scroll + choice >= item_no - 1)
++ if (scroll + choice >= item_count() - 1)
+ continue;
+ /* Scroll list up */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+- print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
+- status[scroll + max_choice - 1],
+- max_choice - 1, FALSE);
++ item_set(scroll + max_choice - 1);
++ print_item(list,
++ max_choice - 1,
++ FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, 1);
+ scrollok(list, FALSE);
+ }
+ scroll++;
+- print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
+- status[scroll + max_choice - 1], max_choice - 1, TRUE);
++ item_set(scroll + max_choice - 1);
++ print_item(list, max_choice - 1, TRUE);
+
+- print_arrows(dialog, choice, item_no,
++ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+@@ -267,12 +265,12 @@ int dialog_checklist(const char *title,
+ }
+ if (i != choice) {
+ /* De-highlight current item */
+- print_item(list, items[(scroll + choice) * 3 + 1],
+- status[scroll + choice], choice, FALSE);
++ item_set(scroll + choice);
++ print_item(list, choice, FALSE);
+ /* Highlight new item */
+ choice = i;
+- print_item(list, items[(scroll + choice) * 3 + 1],
+- status[scroll + choice], choice, TRUE);
++ item_set(scroll + choice);
++ print_item(list, choice, TRUE);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+@@ -282,10 +280,19 @@ int dialog_checklist(const char *title,
+ case 'H':
+ case 'h':
+ case '?':
+- fprintf(stderr, "%s", items[(scroll + choice) * 3]);
++ button = 1;
++ /* fall-through */
++ case 'S':
++ case 's':
++ case ' ':
++ case '\n':
++ item_foreach()
++ item_set_selected(0);
++ item_set(scroll + choice);
++ item_set_selected(1);
++ delwin(list);
+ delwin(dialog);
+- free(status);
+- return 1;
++ return button;
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+@@ -295,42 +302,24 @@ int dialog_checklist(const char *title,
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+- case 'S':
+- case 's':
+- case ' ':
+- case '\n':
+- if (!button) {
+- if (!status[scroll + choice]) {
+- for (i = 0; i < item_no; i++)
+- status[i] = 0;
+- status[scroll + choice] = 1;
+- for (i = 0; i < max_choice; i++)
+- print_item(list, items[(scroll + i) * 3 + 1],
+- status[scroll + i], i, i == choice);
+- }
+- wnoutrefresh(dialog);
+- wrefresh(list);
+-
+- for (i = 0; i < item_no; i++)
+- if (status[i])
+- fprintf(stderr, "%s", items[i * 3]);
+- } else
+- fprintf(stderr, "%s", items[(scroll + choice) * 3]);
+- delwin(dialog);
+- free(status);
+- return button;
+ case 'X':
+ case 'x':
+- key = ESC;
+- case ESC:
++ key = KEY_ESC;
++ break;
++ case KEY_ESC:
++ key = on_key_esc(dialog);
+ break;
++ case KEY_RESIZE:
++ delwin(list);
++ delwin(dialog);
++ on_key_resize();
++ goto do_resize;
+ }
+
+ /* Now, update everything... */
+ doupdate();
+ }
+-
++ delwin(list);
+ delwin(dialog);
+- free(status);
+- return -1; /* ESC pressed */
++ return key; /* ESC pressed */
+ }
+diff --git a/scripts/kconfig/lxdialog/colors.h b/scripts/kconfig/lxdialog/colors.h
+deleted file mode 100644
+index db071df..0000000
+--- a/scripts/kconfig/lxdialog/colors.h
++++ /dev/null
+@@ -1,154 +0,0 @@
+-/*
+- * colors.h -- color attribute definitions
+- *
+- * AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+- *
+- * 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.
+- */
+-
+-/*
+- * Default color definitions
+- *
+- * *_FG = foreground
+- * *_BG = background
+- * *_HL = highlight?
+- */
+-#define SCREEN_FG COLOR_CYAN
+-#define SCREEN_BG COLOR_BLUE
+-#define SCREEN_HL TRUE
+-
+-#define SHADOW_FG COLOR_BLACK
+-#define SHADOW_BG COLOR_BLACK
+-#define SHADOW_HL TRUE
+-
+-#define DIALOG_FG COLOR_BLACK
+-#define DIALOG_BG COLOR_WHITE
+-#define DIALOG_HL FALSE
+-
+-#define TITLE_FG COLOR_YELLOW
+-#define TITLE_BG COLOR_WHITE
+-#define TITLE_HL TRUE
+-
+-#define BORDER_FG COLOR_WHITE
+-#define BORDER_BG COLOR_WHITE
+-#define BORDER_HL TRUE
+-
+-#define BUTTON_ACTIVE_FG COLOR_WHITE
+-#define BUTTON_ACTIVE_BG COLOR_BLUE
+-#define BUTTON_ACTIVE_HL TRUE
+-
+-#define BUTTON_INACTIVE_FG COLOR_BLACK
+-#define BUTTON_INACTIVE_BG COLOR_WHITE
+-#define BUTTON_INACTIVE_HL FALSE
+-
+-#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE
+-#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE
+-#define BUTTON_KEY_ACTIVE_HL TRUE
+-
+-#define BUTTON_KEY_INACTIVE_FG COLOR_RED
+-#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE
+-#define BUTTON_KEY_INACTIVE_HL FALSE
+-
+-#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW
+-#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE
+-#define BUTTON_LABEL_ACTIVE_HL TRUE
+-
+-#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK
+-#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE
+-#define BUTTON_LABEL_INACTIVE_HL TRUE
+-
+-#define INPUTBOX_FG COLOR_BLACK
+-#define INPUTBOX_BG COLOR_WHITE
+-#define INPUTBOX_HL FALSE
+-
+-#define INPUTBOX_BORDER_FG COLOR_BLACK
+-#define INPUTBOX_BORDER_BG COLOR_WHITE
+-#define INPUTBOX_BORDER_HL FALSE
+-
+-#define SEARCHBOX_FG COLOR_BLACK
+-#define SEARCHBOX_BG COLOR_WHITE
+-#define SEARCHBOX_HL FALSE
+-
+-#define SEARCHBOX_TITLE_FG COLOR_YELLOW
+-#define SEARCHBOX_TITLE_BG COLOR_WHITE
+-#define SEARCHBOX_TITLE_HL TRUE
+-
+-#define SEARCHBOX_BORDER_FG COLOR_WHITE
+-#define SEARCHBOX_BORDER_BG COLOR_WHITE
+-#define SEARCHBOX_BORDER_HL TRUE
+-
+-#define POSITION_INDICATOR_FG COLOR_YELLOW
+-#define POSITION_INDICATOR_BG COLOR_WHITE
+-#define POSITION_INDICATOR_HL TRUE
+-
+-#define MENUBOX_FG COLOR_BLACK
+-#define MENUBOX_BG COLOR_WHITE
+-#define MENUBOX_HL FALSE
+-
+-#define MENUBOX_BORDER_FG COLOR_WHITE
+-#define MENUBOX_BORDER_BG COLOR_WHITE
+-#define MENUBOX_BORDER_HL TRUE
+-
+-#define ITEM_FG COLOR_BLACK
+-#define ITEM_BG COLOR_WHITE
+-#define ITEM_HL FALSE
+-
+-#define ITEM_SELECTED_FG COLOR_WHITE
+-#define ITEM_SELECTED_BG COLOR_BLUE
+-#define ITEM_SELECTED_HL TRUE
+-
+-#define TAG_FG COLOR_YELLOW
+-#define TAG_BG COLOR_WHITE
+-#define TAG_HL TRUE
+-
+-#define TAG_SELECTED_FG COLOR_YELLOW
+-#define TAG_SELECTED_BG COLOR_BLUE
+-#define TAG_SELECTED_HL TRUE
+-
+-#define TAG_KEY_FG COLOR_YELLOW
+-#define TAG_KEY_BG COLOR_WHITE
+-#define TAG_KEY_HL TRUE
+-
+-#define TAG_KEY_SELECTED_FG COLOR_YELLOW
+-#define TAG_KEY_SELECTED_BG COLOR_BLUE
+-#define TAG_KEY_SELECTED_HL TRUE
+-
+-#define CHECK_FG COLOR_BLACK
+-#define CHECK_BG COLOR_WHITE
+-#define CHECK_HL FALSE
+-
+-#define CHECK_SELECTED_FG COLOR_WHITE
+-#define CHECK_SELECTED_BG COLOR_BLUE
+-#define CHECK_SELECTED_HL TRUE
+-
+-#define UARROW_FG COLOR_GREEN
+-#define UARROW_BG COLOR_WHITE
+-#define UARROW_HL TRUE
+-
+-#define DARROW_FG COLOR_GREEN
+-#define DARROW_BG COLOR_WHITE
+-#define DARROW_HL TRUE
+-
+-/* End of default color definitions */
+-
+-#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
+-#define COLOR_NAME_LEN 10
+-#define COLOR_COUNT 8
+-
+-/*
+- * Global variables
+- */
+-
+-extern int color_table[][3];
+diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
+index af3cf71..fd695e1 100644
+--- a/scripts/kconfig/lxdialog/dialog.h
++++ b/scripts/kconfig/lxdialog/dialog.h
+@@ -24,6 +24,7 @@
+ #include <ctype.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <stdbool.h>
+
+ #ifdef __sun__
+ #define CURS_MACROS
+@@ -48,7 +49,7 @@
+
+ #define TR(params) _tracef params
+
+-#define ESC 27
++#define KEY_ESC 27
+ #define TAB 9
+ #define MAX_LEN 2048
+ #define BUF_SIZE (10*1024)
+@@ -86,63 +87,111 @@
+ #define ACS_DARROW 'v'
+ #endif
+
++/* error return codes */
++#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
++
+ /*
+- * Attribute names
++ * Color definitions
+ */
+-#define screen_attr attributes[0]
+-#define shadow_attr attributes[1]
+-#define dialog_attr attributes[2]
+-#define title_attr attributes[3]
+-#define border_attr attributes[4]
+-#define button_active_attr attributes[5]
+-#define button_inactive_attr attributes[6]
+-#define button_key_active_attr attributes[7]
+-#define button_key_inactive_attr attributes[8]
+-#define button_label_active_attr attributes[9]
+-#define button_label_inactive_attr attributes[10]
+-#define inputbox_attr attributes[11]
+-#define inputbox_border_attr attributes[12]
+-#define searchbox_attr attributes[13]
+-#define searchbox_title_attr attributes[14]
+-#define searchbox_border_attr attributes[15]
+-#define position_indicator_attr attributes[16]
+-#define menubox_attr attributes[17]
+-#define menubox_border_attr attributes[18]
+-#define item_attr attributes[19]
+-#define item_selected_attr attributes[20]
+-#define tag_attr attributes[21]
+-#define tag_selected_attr attributes[22]
+-#define tag_key_attr attributes[23]
+-#define tag_key_selected_attr attributes[24]
+-#define check_attr attributes[25]
+-#define check_selected_attr attributes[26]
+-#define uarrow_attr attributes[27]
+-#define darrow_attr attributes[28]
+-
+-/* number of attributes */
+-#define ATTRIBUTE_COUNT 29
++struct dialog_color {
++ chtype atr; /* Color attribute */
++ int fg; /* foreground */
++ int bg; /* background */
++ int hl; /* highlight this item */
++};
++
++struct dialog_info {
++ const char *backtitle;
++ struct dialog_color screen;
++ struct dialog_color shadow;
++ struct dialog_color dialog;
++ struct dialog_color title;
++ struct dialog_color border;
++ struct dialog_color button_active;
++ struct dialog_color button_inactive;
++ struct dialog_color button_key_active;
++ struct dialog_color button_key_inactive;
++ struct dialog_color button_label_active;
++ struct dialog_color button_label_inactive;
++ struct dialog_color inputbox;
++ struct dialog_color inputbox_border;
++ struct dialog_color searchbox;
++ struct dialog_color searchbox_title;
++ struct dialog_color searchbox_border;
++ struct dialog_color position_indicator;
++ struct dialog_color menubox;
++ struct dialog_color menubox_border;
++ struct dialog_color item;
++ struct dialog_color item_selected;
++ struct dialog_color tag;
++ struct dialog_color tag_selected;
++ struct dialog_color tag_key;
++ struct dialog_color tag_key_selected;
++ struct dialog_color check;
++ struct dialog_color check_selected;
++ struct dialog_color uarrow;
++ struct dialog_color darrow;
++};
+
+ /*
+ * Global variables
+ */
+-extern bool use_colors;
+-extern bool use_shadow;
+-
+-extern chtype attributes[];
+-
+-extern const char *backtitle;
++extern struct dialog_info dlg;
++extern char dialog_input_result[];
+
+ /*
+ * Function prototypes
+ */
+-extern void create_rc(const char *filename);
+-extern int parse_rc(void);
+
+-void init_dialog(void);
++/* item list as used by checklist and menubox */
++void item_reset(void);
++void item_make(const char *fmt, ...);
++void item_add_str(const char *fmt, ...);
++void item_set_tag(char tag);
++void item_set_data(void *p);
++void item_set_selected(int val);
++int item_activate_selected(void);
++void *item_data(void);
++char item_tag(void);
++
++/* item list manipulation for lxdialog use */
++#define MAXITEMSTR 200
++struct dialog_item {
++ char str[MAXITEMSTR]; /* promtp displayed */
++ char tag;
++ void *data; /* pointer to menu item - used by menubox+checklist */
++ int selected; /* Set to 1 by dialog_*() function if selected. */
++};
++
++/* list of lialog_items */
++struct dialog_list {
++ struct dialog_item node;
++ struct dialog_list *next;
++};
++
++extern struct dialog_list *item_cur;
++extern struct dialog_list item_nil;
++extern struct dialog_list *item_head;
++
++int item_count(void);
++void item_set(int n);
++int item_n(void);
++const char *item_str(void);
++int item_is_selected(void);
++int item_is_tag(char tag);
++#define item_foreach() \
++ for (item_cur = item_head ? item_head: item_cur; \
++ item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
++
++/* generic key handlers */
++int on_key_esc(WINDOW *win);
++int on_key_resize(void);
++
++void init_dialog(const char *backtitle);
++void reset_dialog(void);
+ void end_dialog(void);
+ void attr_clear(WINDOW * win, int height, int width, chtype attr);
+ void dialog_clear(void);
+-void color_setup(void);
+ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+ void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+ void print_title(WINDOW *dialog, const char *title, int width);
+@@ -155,12 +204,10 @@ int dialog_yesno(const char *title, cons
+ int dialog_msgbox(const char *title, const char *prompt, int height,
+ int width, int pause);
+ int dialog_textbox(const char *title, const char *file, int height, int width);
+-int dialog_menu(const char *title, const char *prompt, int height, int width,
+- int menu_height, const char *choice, int item_no,
+- const char *const *items);
++int dialog_menu(const char *title, const char *prompt,
++ const void *selected, int *s_scroll);
+ int dialog_checklist(const char *title, const char *prompt, int height,
+- int width, int list_height, int item_no,
+- const char *const *items);
++ int width, int list_height);
+ extern char dialog_input_result[];
+ int dialog_inputbox(const char *title, const char *prompt, int height,
+ int width, const char *init);
+diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
+index 7795037..05e7206 100644
+--- a/scripts/kconfig/lxdialog/inputbox.c
++++ b/scripts/kconfig/lxdialog/inputbox.c
+@@ -49,6 +49,17 @@ int dialog_inputbox(const char *title, c
+ char *instr = dialog_input_result;
+ WINDOW *dialog;
+
++ if (!init)
++ instr[0] = '\0';
++ else
++ strcpy(instr, init);
++
++do_resize:
++ if (getmaxy(stdscr) <= (height - 2))
++ return -ERRDISPLAYTOOSMALL;
++ if (getmaxx(stdscr) <= (width - 2))
++ return -ERRDISPLAYTOOSMALL;
++
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+@@ -58,17 +69,18 @@ int dialog_inputbox(const char *title, c
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+- wattrset(dialog, border_attr);
++ draw_box(dialog, 0, 0, height, width,
++ dlg.dialog.atr, dlg.border.atr);
++ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ /* Draw the input field box */
+@@ -76,18 +88,14 @@ int dialog_inputbox(const char *title, c
+ getyx(dialog, y, x);
+ box_y = y + 2;
+ box_x = (width - box_width) / 2;
+- draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, border_attr, dialog_attr);
++ draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
++ dlg.border.atr, dlg.dialog.atr);
+
+ print_buttons(dialog, height, width, 0);
+
+ /* Set up the initial value */
+ wmove(dialog, box_y, box_x);
+- wattrset(dialog, inputbox_attr);
+-
+- if (!init)
+- instr[0] = '\0';
+- else
+- strcpy(instr, init);
++ wattrset(dialog, dlg.inputbox.atr);
+
+ input_x = strlen(instr);
+
+@@ -104,7 +112,7 @@ int dialog_inputbox(const char *title, c
+
+ wrefresh(dialog);
+
+- while (key != ESC) {
++ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ if (button == -1) { /* Input box selected */
+@@ -120,7 +128,7 @@ int dialog_inputbox(const char *title, c
+ case KEY_BACKSPACE:
+ case 127:
+ if (input_x || scroll) {
+- wattrset(dialog, inputbox_attr);
++ wattrset(dialog, dlg.inputbox.atr);
+ if (!input_x) {
+ scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+ wmove(dialog, box_y, box_x);
+@@ -140,7 +148,7 @@ int dialog_inputbox(const char *title, c
+ default:
+ if (key < 0x100 && isprint(key)) {
+ if (scroll + input_x < MAX_LEN) {
+- wattrset(dialog, inputbox_attr);
++ wattrset(dialog, dlg.inputbox.atr);
+ instr[scroll + input_x] = key;
+ instr[scroll + input_x + 1] = '\0';
+ if (input_x == box_width - 1) {
+@@ -213,12 +221,18 @@ int dialog_inputbox(const char *title, c
+ return (button == -1 ? 0 : button);
+ case 'X':
+ case 'x':
+- key = ESC;
+- case ESC:
++ key = KEY_ESC;
++ break;
++ case KEY_ESC:
++ key = on_key_esc(dialog);
+ break;
++ case KEY_RESIZE:
++ delwin(dialog);
++ on_key_resize();
++ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+- return -1; /* ESC pressed */
++ return KEY_ESC; /* ESC pressed */
+ }
+diff --git a/scripts/kconfig/lxdialog/lxdialog.c b/scripts/kconfig/lxdialog/lxdialog.c
+deleted file mode 100644
+index 79f6c5f..0000000
+--- a/scripts/kconfig/lxdialog/lxdialog.c
++++ /dev/null
+@@ -1,204 +0,0 @@
+-/*
+- * dialog - Display simple dialog boxes from shell scripts
+- *
+- * ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+- * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-static void Usage(const char *name);
+-
+-typedef int (jumperFn) (const char *title, int argc, const char *const *argv);
+-
+-struct Mode {
+- char *name;
+- int argmin, argmax, argmod;
+- jumperFn *jumper;
+-};
+-
+-jumperFn j_menu, j_radiolist, j_yesno, j_textbox, j_inputbox;
+-jumperFn j_msgbox, j_infobox;
+-
+-static struct Mode modes[] = {
+- {"--menu", 9, 0, 3, j_menu},
+- {"--radiolist", 9, 0, 3, j_radiolist},
+- {"--yesno", 5, 5, 1, j_yesno},
+- {"--textbox", 5, 5, 1, j_textbox},
+- {"--inputbox", 5, 6, 1, j_inputbox},
+- {"--msgbox", 5, 5, 1, j_msgbox},
+- {"--infobox", 5, 5, 1, j_infobox},
+- {NULL, 0, 0, 0, NULL}
+-};
+-
+-static struct Mode *modePtr;
+-
+-#ifdef LOCALE
+-#include <locale.h>
+-#endif
+-
+-int main(int argc, const char *const *argv)
+-{
+- int offset = 0, opt_clear = 0, end_common_opts = 0, retval;
+- const char *title = NULL;
+-
+-#ifdef LOCALE
+- (void)setlocale(LC_ALL, "");
+-#endif
+-
+-#ifdef TRACE
+- trace(TRACE_CALLS | TRACE_UPDATE);
+-#endif
+- if (argc < 2) {
+- Usage(argv[0]);
+- exit(-1);
+- }
+-
+- while (offset < argc - 1 && !end_common_opts) { /* Common options */
+- if (!strcmp(argv[offset + 1], "--title")) {
+- if (argc - offset < 3 || title != NULL) {
+- Usage(argv[0]);
+- exit(-1);
+- } else {
+- title = argv[offset + 2];
+- offset += 2;
+- }
+- } else if (!strcmp(argv[offset + 1], "--backtitle")) {
+- if (backtitle != NULL) {
+- Usage(argv[0]);
+- exit(-1);
+- } else {
+- backtitle = argv[offset + 2];
+- offset += 2;
+- }
+- } else if (!strcmp(argv[offset + 1], "--clear")) {
+- if (opt_clear) { /* Hey, "--clear" can't appear twice! */
+- Usage(argv[0]);
+- exit(-1);
+- } else if (argc == 2) { /* we only want to clear the screen */
+- init_dialog();
+- refresh(); /* init_dialog() will clear the screen for us */
+- end_dialog();
+- return 0;
+- } else {
+- opt_clear = 1;
+- offset++;
+- }
+- } else /* no more common options */
+- end_common_opts = 1;
+- }
+-
+- if (argc - 1 == offset) { /* no more options */
+- Usage(argv[0]);
+- exit(-1);
+- }
+- /* use a table to look for the requested mode, to avoid code duplication */
+-
+- for (modePtr = modes; modePtr->name; modePtr++) /* look for the mode */
+- if (!strcmp(argv[offset + 1], modePtr->name))
+- break;
+-
+- if (!modePtr->name)
+- Usage(argv[0]);
+- if (argc - offset < modePtr->argmin)
+- Usage(argv[0]);
+- if (modePtr->argmax && argc - offset > modePtr->argmax)
+- Usage(argv[0]);
+-
+- init_dialog();
+- retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset);
+-
+- if (opt_clear) { /* clear screen before exit */
+- attr_clear(stdscr, LINES, COLS, screen_attr);
+- refresh();
+- }
+- end_dialog();
+-
+- exit(retval);
+-}
+-
+-/*
+- * Print program usage
+- */
+-static void Usage(const char *name)
+-{
+- fprintf(stderr, "\
+-\ndialog, by Savio Lam (lam836 at cs.cuhk.hk).\
+-\n patched by Stuart Herbert (S.Herbert at shef.ac.uk)\
+-\n modified/gutted for use as a Linux kernel config tool by \
+-\n William Roadcap (roadcapw at cfw.com)\
+-\n\
+-\n* Display dialog boxes from shell scripts *\
+-\n\
+-\nUsage: %s --clear\
+-\n %s [--title <title>] [--backtitle <backtitle>] --clear <Box options>\
+-\n\
+-\nBox options:\
+-\n\
+-\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\
+-\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
+-\n --textbox <file> <height> <width>\
+-\n --inputbox <text> <height> <width> [<init>]\
+-\n --yesno <text> <height> <width>\
+-\n", name, name);
+- exit(-1);
+-}
+-
+-/*
+- * These are the program jumpers
+- */
+-
+-int j_menu(const char *t, int ac, const char *const *av)
+-{
+- return dialog_menu(t, av[2], atoi(av[3]), atoi(av[4]),
+- atoi(av[5]), av[6], (ac - 6) / 2, av + 7);
+-}
+-
+-int j_radiolist(const char *t, int ac, const char *const *av)
+-{
+- return dialog_checklist(t, av[2], atoi(av[3]), atoi(av[4]),
+- atoi(av[5]), (ac - 6) / 3, av + 6);
+-}
+-
+-int j_textbox(const char *t, int ac, const char *const *av)
+-{
+- return dialog_textbox(t, av[2], atoi(av[3]), atoi(av[4]));
+-}
+-
+-int j_yesno(const char *t, int ac, const char *const *av)
+-{
+- return dialog_yesno(t, av[2], atoi(av[3]), atoi(av[4]));
+-}
+-
+-int j_inputbox(const char *t, int ac, const char *const *av)
+-{
+- int ret = dialog_inputbox(t, av[2], atoi(av[3]), atoi(av[4]),
+- ac == 6 ? av[5] : (char *)NULL);
+- if (ret == 0)
+- fprintf(stderr, dialog_input_result);
+- return ret;
+-}
+-
+-int j_msgbox(const char *t, int ac, const char *const *av)
+-{
+- return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 1);
+-}
+-
+-int j_infobox(const char *t, int ac, const char *const *av)
+-{
+- return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 0);
+-}
+diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
+index bf8052f..0d83159 100644
+--- a/scripts/kconfig/lxdialog/menubox.c
++++ b/scripts/kconfig/lxdialog/menubox.c
+@@ -63,19 +63,19 @@ static int menu_width, item_x;
+ /*
+ * Print menu item
+ */
+-static void do_print_item(WINDOW * win, const char *item, int choice,
++static void do_print_item(WINDOW * win, const char *item, int line_y,
+ int selected, int hotkey)
+ {
+ int j;
+ char *menu_item = malloc(menu_width + 1);
+
+ strncpy(menu_item, item, menu_width - item_x);
+- menu_item[menu_width] = 0;
++ menu_item[menu_width - item_x] = '\0';
+ j = first_alpha(menu_item, "YyNnMmHh");
+
+ /* Clear 'residue' of last item */
+- wattrset(win, menubox_attr);
+- wmove(win, choice, 0);
++ wattrset(win, dlg.menubox.atr);
++ wmove(win, line_y, 0);
+ #if OLD_NCURSES
+ {
+ int i;
+@@ -85,23 +85,24 @@ static void do_print_item(WINDOW * win,
+ #else
+ wclrtoeol(win);
+ #endif
+- wattrset(win, selected ? item_selected_attr : item_attr);
+- mvwaddstr(win, choice, item_x, menu_item);
++ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
++ mvwaddstr(win, line_y, item_x, menu_item);
+ if (hotkey) {
+- wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
+- mvwaddch(win, choice, item_x + j, menu_item[j]);
++ wattrset(win, selected ? dlg.tag_key_selected.atr
++ : dlg.tag_key.atr);
++ mvwaddch(win, line_y, item_x + j, menu_item[j]);
+ }
+ if (selected) {
+- wmove(win, choice, item_x + 1);
++ wmove(win, line_y, item_x + 1);
+ }
+ free(menu_item);
+ wrefresh(win);
+ }
+
+-#define print_item(index, choice, selected) \
+-do {\
+- int hotkey = (items[(index) * 2][0] != ':'); \
+- do_print_item(menu, items[(index) * 2 + 1], choice, selected, hotkey); \
++#define print_item(index, choice, selected) \
++do { \
++ item_set(index); \
++ do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+ } while (0)
+
+ /*
+@@ -117,11 +118,11 @@ static void print_arrows(WINDOW * win, i
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+- wattrset(win, uarrow_attr);
++ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+- wattrset(win, menubox_attr);
++ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+@@ -133,11 +134,11 @@ static void print_arrows(WINDOW * win, i
+ wrefresh(win);
+
+ if ((height < item_no) && (scroll + height < item_no)) {
+- wattrset(win, darrow_attr);
++ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+- wattrset(win, menubox_border_attr);
++ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+@@ -178,17 +179,26 @@ static void do_scroll(WINDOW *win, int *
+ /*
+ * Display a menu for choosing among a number of options
+ */
+-int dialog_menu(const char *title, const char *prompt, int height, int width,
+- int menu_height, const char *current, int item_no,
+- const char *const *items)
++int dialog_menu(const char *title, const char *prompt,
++ const void *selected, int *s_scroll)
+ {
+ int i, j, x, y, box_x, box_y;
++ int height, width, menu_height;
+ int key = 0, button = 0, scroll = 0, choice = 0;
+ int first_item = 0, max_choice;
+ WINDOW *dialog, *menu;
+- FILE *f;
+
+- max_choice = MIN(menu_height, item_no);
++do_resize:
++ height = getmaxy(stdscr);
++ width = getmaxx(stdscr);
++ if (height < 15 || width < 65)
++ return -ERRDISPLAYTOOSMALL;
++
++ height -= 4;
++ width -= 5;
++ menu_height = height - 10;
++
++ max_choice = MIN(menu_height, item_count());
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+@@ -199,18 +209,19 @@ int dialog_menu(const char *title, const
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+- wattrset(dialog, border_attr);
++ draw_box(dialog, 0, 0, height, width,
++ dlg.dialog.atr, dlg.border.atr);
++ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+- wattrset(dialog, dialog_attr);
+- wbkgdset(dialog, dialog_attr & A_COLOR);
++ wattrset(dialog, dlg.dialog.atr);
++ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ menu_width = width - 6;
+@@ -224,33 +235,29 @@ int dialog_menu(const char *title, const
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+- menubox_border_attr, menubox_attr);
++ dlg.menubox_border.atr, dlg.menubox.atr);
+
+- item_x = (menu_width - 70) / 2;
++ if (menu_width >= 80)
++ item_x = (menu_width - 70) / 2;
++ else
++ item_x = 4;
+
+ /* Set choice to default item */
+- for (i = 0; i < item_no; i++)
+- if (strcmp(current, items[i * 2]) == 0)
+- choice = i;
+-
+- /* get the scroll info from the temp file */
+- if ((f = fopen("lxdialog.scrltmp", "r")) != NULL) {
+- if ((fscanf(f, "%d\n", &scroll) == 1) && (scroll <= choice) &&
+- (scroll + max_choice > choice) && (scroll >= 0) &&
+- (scroll + max_choice <= item_no)) {
+- first_item = scroll;
+- choice = choice - scroll;
+- fclose(f);
+- } else {
+- scroll = 0;
+- remove("lxdialog.scrltmp");
+- fclose(f);
+- f = NULL;
+- }
++ item_foreach()
++ if (selected && (selected == item_data()))
++ choice = item_n();
++ /* get the saved scroll info */
++ scroll = *s_scroll;
++ if ((scroll <= choice) && (scroll + max_choice > choice) &&
++ (scroll >= 0) && (scroll + max_choice <= item_count())) {
++ first_item = scroll;
++ choice = choice - scroll;
++ } else {
++ scroll = 0;
+ }
+- if ((choice >= max_choice) || (f == NULL && choice >= max_choice / 2)) {
+- if (choice >= item_no - max_choice / 2)
+- scroll = first_item = item_no - max_choice;
++ if ((choice >= max_choice)) {
++ if (choice >= item_count() - max_choice / 2)
++ scroll = first_item = item_count() - max_choice;
+ else
+ scroll = first_item = choice - max_choice / 2;
+ choice = choice - scroll;
+@@ -263,14 +270,14 @@ int dialog_menu(const char *title, const
+
+ wnoutrefresh(menu);
+
+- print_arrows(dialog, item_no, scroll,
++ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ print_buttons(dialog, height, width, 0);
+ wmove(menu, choice, item_x + 1);
+ wrefresh(menu);
+
+- while (key != ESC) {
++ while (key != KEY_ESC) {
+ key = wgetch(menu);
+
+ if (key < 256 && isalpha(key))
+@@ -280,14 +287,16 @@ int dialog_menu(const char *title, const
+ i = max_choice;
+ else {
+ for (i = choice + 1; i < max_choice; i++) {
+- j = first_alpha(items[(scroll + i) * 2 + 1], "YyNnMmHh");
+- if (key == tolower(items[(scroll + i) * 2 + 1][j]))
++ item_set(scroll + i);
++ j = first_alpha(item_str(), "YyNnMmHh");
++ if (key == tolower(item_str()[j]))
+ break;
+ }
+ if (i == max_choice)
+ for (i = 0; i < max_choice; i++) {
+- j = first_alpha(items [(scroll + i) * 2 + 1], "YyNnMmHh");
+- if (key == tolower(items[(scroll + i) * 2 + 1][j]))
++ item_set(scroll + i);
++ j = first_alpha(item_str(), "YyNnMmHh");
++ if (key == tolower(item_str()[j]))
+ break;
+ }
+ }
+@@ -312,7 +321,7 @@ int dialog_menu(const char *title, const
+ print_item(scroll+choice, choice, FALSE);
+
+ if ((choice > max_choice - 3) &&
+- (scroll + max_choice < item_no)) {
++ (scroll + max_choice < item_count())) {
+ /* Scroll menu up */
+ do_scroll(menu, &scroll, 1);
+
+@@ -335,7 +344,7 @@ int dialog_menu(const char *title, const
+
+ } else if (key == KEY_NPAGE) {
+ for (i = 0; (i < max_choice); i++) {
+- if (scroll + max_choice < item_no) {
++ if (scroll + max_choice < item_count()) {
+ do_scroll(menu, &scroll, 1);
+ print_item(scroll+max_choice-1,
+ max_choice - 1, FALSE);
+@@ -349,7 +358,7 @@ int dialog_menu(const char *title, const
+
+ print_item(scroll + choice, choice, TRUE);
+
+- print_arrows(dialog, item_no, scroll,
++ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ wnoutrefresh(dialog);
+@@ -375,12 +384,11 @@ int dialog_menu(const char *title, const
+ case 'm':
+ case '/':
+ /* save scroll info */
+- if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) {
+- fprintf(f, "%d\n", scroll);
+- fclose(f);
+- }
++ *s_scroll = scroll;
++ delwin(menu);
+ delwin(dialog);
+- fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
++ item_set(scroll + choice);
++ item_set_selected(1);
+ switch (key) {
+ case 's':
+ return 3;
+@@ -400,27 +408,27 @@ int dialog_menu(const char *title, const
+ case '?':
+ button = 2;
+ case '\n':
++ *s_scroll = scroll;
++ delwin(menu);
+ delwin(dialog);
+- if (button == 2)
+- fprintf(stderr, "%s \"%s\"\n",
+- items[(scroll + choice) * 2],
+- items[(scroll + choice) * 2 + 1] +
+- first_alpha(items [(scroll + choice) * 2 + 1], ""));
+- else
+- fprintf(stderr, "%s\n",
+- items[(scroll + choice) * 2]);
+-
+- remove("lxdialog.scrltmp");
++ item_set(scroll + choice);
++ item_set_selected(1);
+ return button;
+ case 'e':
+ case 'x':
+- key = ESC;
+- case ESC:
++ key = KEY_ESC;
++ break;
++ case KEY_ESC:
++ key = on_key_esc(menu);
+ break;
++ case KEY_RESIZE:
++ on_key_resize();
++ delwin(menu);
++ delwin(dialog);
++ goto do_resize;
+ }
+ }
+-
++ delwin(menu);
+ delwin(dialog);
+- remove("lxdialog.scrltmp");
+- return -1; /* ESC pressed */
++ return key; /* ESC pressed */
+ }
+diff --git a/scripts/kconfig/lxdialog/msgbox.c b/scripts/kconfig/lxdialog/msgbox.c
+deleted file mode 100644
+index 7323f54..0000000
+--- a/scripts/kconfig/lxdialog/msgbox.c
++++ /dev/null
+@@ -1,71 +0,0 @@
+-/*
+- * msgbox.c -- implements the message box and info box
+- *
+- * ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+- * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw at cfw.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-/*
+- * Display a message box. Program will pause and display an "OK" button
+- * if the parameter 'pause' is non-zero.
+- */
+-int dialog_msgbox(const char *title, const char *prompt, int height, int width,
+- int pause)
+-{
+- int i, x, y, key = 0;
+- WINDOW *dialog;
+-
+- /* center dialog box on screen */
+- x = (COLS - width) / 2;
+- y = (LINES - height) / 2;
+-
+- draw_shadow(stdscr, y, x, height, width);
+-
+- dialog = newwin(height, width, y, x);
+- keypad(dialog, TRUE);
+-
+- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+-
+- print_title(dialog, title, width);
+-
+- wattrset(dialog, dialog_attr);
+- print_autowrap(dialog, prompt, width - 2, 1, 2);
+-
+- if (pause) {
+- wattrset(dialog, border_attr);
+- mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+- for (i = 0; i < width - 2; i++)
+- waddch(dialog, ACS_HLINE);
+- wattrset(dialog, dialog_attr);
+- waddch(dialog, ACS_RTEE);
+-
+- print_button(dialog, " Ok ", height - 2, width / 2 - 4, TRUE);
+-
+- wrefresh(dialog);
+- while (key != ESC && key != '\n' && key != ' ' &&
+- key != 'O' && key != 'o' && key != 'X' && key != 'x')
+- key = wgetch(dialog);
+- } else {
+- key = '\n';
+- wrefresh(dialog);
+- }
+-
+- delwin(dialog);
+- return key == ESC ? -1 : 0;
+-}
+diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
+index 77848bb..fabfc1a 100644
+--- a/scripts/kconfig/lxdialog/textbox.c
++++ b/scripts/kconfig/lxdialog/textbox.c
+@@ -25,56 +25,62 @@ static void back_lines(int n);
+ static void print_page(WINDOW * win, int height, int width);
+ static void print_line(WINDOW * win, int row, int width);
+ static char *get_line(void);
+-static void print_position(WINDOW * win, int height, int width);
++static void print_position(WINDOW * win);
++
++static int hscroll;
++static int begin_reached, end_reached, page_length;
++static const char *buf;
++static const char *page;
++
++/*
++ * refresh window content
++ */
++static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
++ int cur_y, int cur_x)
++{
++ print_page(box, boxh, boxw);
++ print_position(dialog);
++ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
++ wrefresh(dialog);
++}
+
+-static int hscroll, fd, file_size, bytes_read;
+-static int begin_reached = 1, end_reached, page_length;
+-static char *buf, *page;
+
+ /*
+ * Display text from a file in a dialog box.
+ */
+-int dialog_textbox(const char *title, const char *file, int height, int width)
++int dialog_textbox(const char *title, const char *tbuf,
++ int initial_height, int initial_width)
+ {
+- int i, x, y, cur_x, cur_y, fpos, key = 0;
++ int i, x, y, cur_x, cur_y, key = 0;
++ int height, width, boxh, boxw;
+ int passed_end;
+- char search_term[MAX_LEN + 1];
+- WINDOW *dialog, *text;
+-
+- search_term[0] = '\0'; /* no search term entered yet */
++ WINDOW *dialog, *box;
+
+- /* Open input file for reading */
+- if ((fd = open(file, O_RDONLY)) == -1) {
+- endwin();
+- fprintf(stderr, "\nCan't open input file in dialog_textbox().\n");
+- exit(-1);
+- }
+- /* Get file size. Actually, 'file_size' is the real file size - 1,
+- since it's only the last byte offset from the beginning */
+- if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
+- exit(-1);
+- }
+- /* Restore file pointer to beginning of file after getting file size */
+- if (lseek(fd, 0, SEEK_SET) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+- exit(-1);
+- }
+- /* Allocate space for read buffer */
+- if ((buf = malloc(BUF_SIZE + 1)) == NULL) {
+- endwin();
+- fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
+- exit(-1);
+- }
+- if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+- exit(-1);
+- }
+- buf[bytes_read] = '\0'; /* mark end of valid data */
+- page = buf; /* page is pointer to start of page to be displayed */
++ begin_reached = 1;
++ end_reached = 0;
++ page_length = 0;
++ hscroll = 0;
++ buf = tbuf;
++ page = buf; /* page is pointer to start of page to be displayed */
++
++do_resize:
++ getmaxyx(stdscr, height, width);
++ if (height < 8 || width < 8)
++ return -ERRDISPLAYTOOSMALL;
++ if (initial_height != 0)
++ height = initial_height;
++ else
++ if (height > 4)
++ height -= 4;
++ else
++ height = 0;
++ if (initial_width != 0)
++ width = initial_width;
++ else
++ if (width > 5)
++ width -= 5;
++ else
++ width = 0;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+@@ -85,22 +91,25 @@ int dialog_textbox(const char *title, co
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+- /* Create window for text region, used for scrolling text */
+- text = subwin(dialog, height - 4, width - 2, y + 1, x + 1);
+- wattrset(text, dialog_attr);
+- wbkgdset(text, dialog_attr & A_COLOR);
++ /* Create window for box region, used for scrolling text */
++ boxh = height - 4;
++ boxw = width - 2;
++ box = subwin(dialog, boxh, boxw, y + 1, x + 1);
++ wattrset(box, dlg.dialog.atr);
++ wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+- keypad(text, TRUE);
++ keypad(box, TRUE);
+
+ /* register the new window, along with its borders */
+- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
++ draw_box(dialog, 0, 0, height, width,
++ dlg.dialog.atr, dlg.border.atr);
+
+- wattrset(dialog, border_attr);
++ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+- wattrset(dialog, dialog_attr);
+- wbkgdset(dialog, dialog_attr & A_COLOR);
++ wattrset(dialog, dlg.dialog.atr);
++ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+@@ -110,85 +119,37 @@ int dialog_textbox(const char *title, co
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+
+ /* Print first page of text */
+- attr_clear(text, height - 4, width - 2, dialog_attr);
+- print_page(text, height - 4, width - 2);
+- print_position(dialog, height, width);
+- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+- wrefresh(dialog);
++ attr_clear(box, boxh, boxw, dlg.dialog.atr);
++ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+- while ((key != ESC) && (key != '\n')) {
++ while ((key != KEY_ESC) && (key != '\n')) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ case 'X':
+ case 'x':
++ delwin(box);
+ delwin(dialog);
+- free(buf);
+- close(fd);
+ return 0;
+ case 'g': /* First page */
+ case KEY_HOME:
+ if (!begin_reached) {
+ begin_reached = 1;
+- /* First page not in buffer? */
+- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+- exit(-1);
+- }
+- if (fpos > bytes_read) { /* Yes, we have to read it in */
+- if (lseek(fd, 0, SEEK_SET) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in "
+- "dialog_textbox().\n");
+- exit(-1);
+- }
+- if ((bytes_read =
+- read(fd, buf, BUF_SIZE)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+- exit(-1);
+- }
+- buf[bytes_read] = '\0';
+- }
+ page = buf;
+- print_page(text, height - 4, width - 2);
+- print_position(dialog, height, width);
+- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+- wrefresh(dialog);
++ refresh_text_box(dialog, box, boxh, boxw,
++ cur_y, cur_x);
+ }
+ break;
+ case 'G': /* Last page */
+ case KEY_END:
+
+ end_reached = 1;
+- /* Last page not in buffer? */
+- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+- exit(-1);
+- }
+- if (fpos < file_size) { /* Yes, we have to read it in */
+- if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+- exit(-1);
+- }
+- if ((bytes_read =
+- read(fd, buf, BUF_SIZE)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+- exit(-1);
+- }
+- buf[bytes_read] = '\0';
+- }
+- page = buf + bytes_read;
+- back_lines(height - 4);
+- print_page(text, height - 4, width - 2);
+- print_position(dialog, height, width);
+- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+- wrefresh(dialog);
++ /* point to last char in buf */
++ page = buf + strlen(buf);
++ back_lines(boxh);
++ refresh_text_box(dialog, box, boxh, boxw,
++ cur_y, cur_x);
+ break;
+ case 'K': /* Previous line */
+ case 'k':
+@@ -196,21 +157,23 @@ int dialog_textbox(const char *title, co
+ if (!begin_reached) {
+ back_lines(page_length + 1);
+
+- /* We don't call print_page() here but use scrolling to ensure
+- faster screen update. However, 'end_reached' and
+- 'page_length' should still be updated, and 'page' should
+- point to start of next page. This is done by calling
+- get_line() in the following 'for' loop. */
+- scrollok(text, TRUE);
+- wscrl(text, -1); /* Scroll text region down one line */
+- scrollok(text, FALSE);
++ /* We don't call print_page() here but use
++ * scrolling to ensure faster screen update.
++ * However, 'end_reached' and 'page_length'
++ * should still be updated, and 'page' should
++ * point to start of next page. This is done
++ * by calling get_line() in the following
++ * 'for' loop. */
++ scrollok(box, TRUE);
++ wscrl(box, -1); /* Scroll box region down one line */
++ scrollok(box, FALSE);
+ page_length = 0;
+ passed_end = 0;
+- for (i = 0; i < height - 4; i++) {
++ for (i = 0; i < boxh; i++) {
+ if (!i) {
+ /* print first line of page */
+- print_line(text, 0, width - 2);
+- wnoutrefresh(text);
++ print_line(box, 0, boxw);
++ wnoutrefresh(box);
+ } else
+ /* Called to update 'end_reached' and 'page' */
+ get_line();
+@@ -220,7 +183,7 @@ int dialog_textbox(const char *title, co
+ passed_end = 1;
+ }
+
+- print_position(dialog, height, width);
++ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+@@ -230,23 +193,21 @@ int dialog_textbox(const char *title, co
+ case KEY_PPAGE:
+ if (begin_reached)
+ break;
+- back_lines(page_length + height - 4);
+- print_page(text, height - 4, width - 2);
+- print_position(dialog, height, width);
+- wmove(dialog, cur_y, cur_x);
+- wrefresh(dialog);
++ back_lines(page_length + boxh);
++ refresh_text_box(dialog, box, boxh, boxw,
++ cur_y, cur_x);
+ break;
+ case 'J': /* Next line */
+ case 'j':
+ case KEY_DOWN:
+ if (!end_reached) {
+ begin_reached = 0;
+- scrollok(text, TRUE);
+- scroll(text); /* Scroll text region up one line */
+- scrollok(text, FALSE);
+- print_line(text, height - 5, width - 2);
+- wnoutrefresh(text);
+- print_position(dialog, height, width);
++ scrollok(box, TRUE);
++ scroll(box); /* Scroll box region up one line */
++ scrollok(box, FALSE);
++ print_line(box, boxh - 1, boxw);
++ wnoutrefresh(box);
++ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+@@ -257,10 +218,8 @@ int dialog_textbox(const char *title, co
+ break;
+
+ begin_reached = 0;
+- print_page(text, height - 4, width - 2);
+- print_position(dialog, height, width);
+- wmove(dialog, cur_y, cur_x);
+- wrefresh(dialog);
++ refresh_text_box(dialog, box, boxh, boxw,
++ cur_y, cur_x);
+ break;
+ case '0': /* Beginning of line */
+ case 'H': /* Scroll left */
+@@ -275,9 +234,8 @@ int dialog_textbox(const char *title, co
+ hscroll--;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+- print_page(text, height - 4, width - 2);
+- wmove(dialog, cur_y, cur_x);
+- wrefresh(dialog);
++ refresh_text_box(dialog, box, boxh, boxw,
++ cur_y, cur_x);
+ break;
+ case 'L': /* Scroll right */
+ case 'l':
+@@ -287,131 +245,56 @@ int dialog_textbox(const char *title, co
+ hscroll++;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+- print_page(text, height - 4, width - 2);
+- wmove(dialog, cur_y, cur_x);
+- wrefresh(dialog);
++ refresh_text_box(dialog, box, boxh, boxw,
++ cur_y, cur_x);
+ break;
+- case ESC:
++ case KEY_ESC:
++ key = on_key_esc(dialog);
+ break;
++ case KEY_RESIZE:
++ back_lines(height);
++ delwin(box);
++ delwin(dialog);
++ on_key_resize();
++ goto do_resize;
+ }
+ }
+-
++ delwin(box);
+ delwin(dialog);
+- free(buf);
+- close(fd);
+- return -1; /* ESC pressed */
++ return key; /* ESC pressed */
+ }
+
+ /*
+- * Go back 'n' lines in text file. Called by dialog_textbox().
++ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+ static void back_lines(int n)
+ {
+- int i, fpos;
++ int i;
+
+ begin_reached = 0;
+- /* We have to distinguish between end_reached and !end_reached
+- since at end of file, the line is not ended by a '\n'.
+- The code inside 'if' basically does a '--page' to move one
+- character backward so as to skip '\n' of the previous line */
+- if (!end_reached) {
+- /* Either beginning of buffer or beginning of file reached? */
+- if (page == buf) {
+- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in "
+- "back_lines().\n");
+- exit(-1);
+- }
+- if (fpos > bytes_read) { /* Not beginning of file yet */
+- /* We've reached beginning of buffer, but not beginning of
+- file yet, so read previous part of file into buffer.
+- Note that we only move backward for BUF_SIZE/2 bytes,
+- but not BUF_SIZE bytes to avoid re-reading again in
+- print_page() later */
+- /* Really possible to move backward BUF_SIZE/2 bytes? */
+- if (fpos < BUF_SIZE / 2 + bytes_read) {
+- /* No, move less then */
+- if (lseek(fd, 0, SEEK_SET) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in "
+- "back_lines().\n");
+- exit(-1);
+- }
+- page = buf + fpos - bytes_read;
+- } else { /* Move backward BUF_SIZE/2 bytes */
+- if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer "
+- "in back_lines().\n");
+- exit(-1);
+- }
+- page = buf + BUF_SIZE / 2;
+- }
+- if ((bytes_read =
+- read(fd, buf, BUF_SIZE)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError reading file in back_lines().\n");
+- exit(-1);
+- }
+- buf[bytes_read] = '\0';
+- } else { /* Beginning of file reached */
+- begin_reached = 1;
+- return;
++ /* Go back 'n' lines */
++ for (i = 0; i < n; i++) {
++ if (*page == '\0') {
++ if (end_reached) {
++ end_reached = 0;
++ continue;
+ }
+ }
+- if (*(--page) != '\n') { /* '--page' here */
+- /* Something's wrong... */
+- endwin();
+- fprintf(stderr, "\nInternal error in back_lines().\n");
+- exit(-1);
++ if (page == buf) {
++ begin_reached = 1;
++ return;
+ }
+- }
+- /* Go back 'n' lines */
+- for (i = 0; i < n; i++)
++ page--;
+ do {
+ if (page == buf) {
+- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+- exit(-1);
+- }
+- if (fpos > bytes_read) {
+- /* Really possible to move backward BUF_SIZE/2 bytes? */
+- if (fpos < BUF_SIZE / 2 + bytes_read) {
+- /* No, move less then */
+- if (lseek(fd, 0, SEEK_SET) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer "
+- "in back_lines().\n");
+- exit(-1);
+- }
+- page = buf + fpos - bytes_read;
+- } else { /* Move backward BUF_SIZE/2 bytes */
+- if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer"
+- " in back_lines().\n");
+- exit(-1);
+- }
+- page = buf + BUF_SIZE / 2;
+- }
+- if ((bytes_read =
+- read(fd, buf, BUF_SIZE)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError reading file in "
+- "back_lines().\n");
+- exit(-1);
+- }
+- buf[bytes_read] = '\0';
+- } else { /* Beginning of file reached */
+- begin_reached = 1;
+- return;
+- }
++ begin_reached = 1;
++ return;
+ }
+- } while (*(--page) != '\n');
+- page++;
++ page--;
++ } while (*page != '\n');
++ page++;
++ }
+ }
+
+ /*
+@@ -466,33 +349,14 @@ static void print_line(WINDOW * win, int
+ */
+ static char *get_line(void)
+ {
+- int i = 0, fpos;
++ int i = 0;
+ static char line[MAX_LEN + 1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') {
+- /* Either end of file or end of buffer reached */
+- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in "
+- "get_line().\n");
+- exit(-1);
+- }
+- if (fpos < file_size) { /* Not end of file yet */
+- /* We've reached end of buffer, but not end of file yet,
+- so read next part of file into buffer */
+- if ((bytes_read =
+- read(fd, buf, BUF_SIZE)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError reading file in get_line().\n");
+- exit(-1);
+- }
+- buf[bytes_read] = '\0';
+- page = buf;
+- } else {
+- if (!end_reached)
+- end_reached = 1;
++ if (!end_reached) {
++ end_reached = 1;
+ break;
+ }
+ } else if (i < MAX_LEN)
+@@ -515,19 +379,13 @@ static char *get_line(void)
+ /*
+ * Print current position
+ */
+-static void print_position(WINDOW * win, int height, int width)
++static void print_position(WINDOW * win)
+ {
+- int fpos, percent;
++ int percent;
+
+- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+- endwin();
+- fprintf(stderr, "\nError moving file pointer in print_position().\n");
+- exit(-1);
+- }
+- wattrset(win, position_indicator_attr);
+- wbkgdset(win, position_indicator_attr & A_COLOR);
+- percent = !file_size ?
+- 100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
+- wmove(win, height - 3, width - 9);
++ wattrset(win, dlg.position_indicator.atr);
++ wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
++ percent = (page - buf) * 100 / strlen(buf);
++ wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+ wprintw(win, "(%3d%%)", percent);
+ }
+diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
+index f82cebb..ebc781b 100644
+--- a/scripts/kconfig/lxdialog/util.c
++++ b/scripts/kconfig/lxdialog/util.c
+@@ -21,85 +21,217 @@
+
+ #include "dialog.h"
+
+-/* use colors by default? */
+-bool use_colors = 1;
++struct dialog_info dlg;
+
+-const char *backtitle = NULL;
++static void set_mono_theme(void)
++{
++ dlg.screen.atr = A_NORMAL;
++ dlg.shadow.atr = A_NORMAL;
++ dlg.dialog.atr = A_NORMAL;
++ dlg.title.atr = A_BOLD;
++ dlg.border.atr = A_NORMAL;
++ dlg.button_active.atr = A_REVERSE;
++ dlg.button_inactive.atr = A_DIM;
++ dlg.button_key_active.atr = A_REVERSE;
++ dlg.button_key_inactive.atr = A_BOLD;
++ dlg.button_label_active.atr = A_REVERSE;
++ dlg.button_label_inactive.atr = A_NORMAL;
++ dlg.inputbox.atr = A_NORMAL;
++ dlg.inputbox_border.atr = A_NORMAL;
++ dlg.searchbox.atr = A_NORMAL;
++ dlg.searchbox_title.atr = A_BOLD;
++ dlg.searchbox_border.atr = A_NORMAL;
++ dlg.position_indicator.atr = A_BOLD;
++ dlg.menubox.atr = A_NORMAL;
++ dlg.menubox_border.atr = A_NORMAL;
++ dlg.item.atr = A_NORMAL;
++ dlg.item_selected.atr = A_REVERSE;
++ dlg.tag.atr = A_BOLD;
++ dlg.tag_selected.atr = A_REVERSE;
++ dlg.tag_key.atr = A_BOLD;
++ dlg.tag_key_selected.atr = A_REVERSE;
++ dlg.check.atr = A_BOLD;
++ dlg.check_selected.atr = A_REVERSE;
++ dlg.uarrow.atr = A_BOLD;
++ dlg.darrow.atr = A_BOLD;
++}
++
++#define DLG_COLOR(dialog, f, b, h) \
++do { \
++ dlg.dialog.fg = (f); \
++ dlg.dialog.bg = (b); \
++ dlg.dialog.hl = (h); \
++} while (0)
++
++static void set_classic_theme(void)
++{
++ DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
++ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
++ DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
++ DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
++ DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
++ DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
++ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
++ DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
++ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
++ DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
++ DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
++ DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
++ DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
++ DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
++ DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
++ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
++ DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
++ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
++ DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
++ DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
++ DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
++ DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
++}
++
++static void set_blackbg_theme(void)
++{
++ DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
++ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
++ DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
++ DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
++ DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
++
++ DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
++ DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
++ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
++ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
++ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
++ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
++
++ DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
++ DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
++
++ DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
++ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
++ DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
++
++ DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
++
++ DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
++ DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
++
++ DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
++ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
++
++ DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
++ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
++ DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
++ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
++
++ DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
++ DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
++
++ DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
++ DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
++}
++
++static void set_bluetitle_theme(void)
++{
++ set_classic_theme();
++ DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
++ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
++ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
++ DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
++ DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
++ DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
++ DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
++
++}
+
+ /*
+- * Attribute values, default is for mono display
++ * Select color theme
+ */
+-chtype attributes[] = {
+- A_NORMAL, /* screen_attr */
+- A_NORMAL, /* shadow_attr */
+- A_NORMAL, /* dialog_attr */
+- A_BOLD, /* title_attr */
+- A_NORMAL, /* border_attr */
+- A_REVERSE, /* button_active_attr */
+- A_DIM, /* button_inactive_attr */
+- A_REVERSE, /* button_key_active_attr */
+- A_BOLD, /* button_key_inactive_attr */
+- A_REVERSE, /* button_label_active_attr */
+- A_NORMAL, /* button_label_inactive_attr */
+- A_NORMAL, /* inputbox_attr */
+- A_NORMAL, /* inputbox_border_attr */
+- A_NORMAL, /* searchbox_attr */
+- A_BOLD, /* searchbox_title_attr */
+- A_NORMAL, /* searchbox_border_attr */
+- A_BOLD, /* position_indicator_attr */
+- A_NORMAL, /* menubox_attr */
+- A_NORMAL, /* menubox_border_attr */
+- A_NORMAL, /* item_attr */
+- A_REVERSE, /* item_selected_attr */
+- A_BOLD, /* tag_attr */
+- A_REVERSE, /* tag_selected_attr */
+- A_BOLD, /* tag_key_attr */
+- A_REVERSE, /* tag_key_selected_attr */
+- A_BOLD, /* check_attr */
+- A_REVERSE, /* check_selected_attr */
+- A_BOLD, /* uarrow_attr */
+- A_BOLD /* darrow_attr */
+-};
+-
+-#include "colors.h"
++static int set_theme(const char *theme)
++{
++ int use_color = 1;
++ if (!theme)
++ set_bluetitle_theme();
++ else if (strcmp(theme, "classic") == 0)
++ set_classic_theme();
++ else if (strcmp(theme, "bluetitle") == 0)
++ set_bluetitle_theme();
++ else if (strcmp(theme, "blackbg") == 0)
++ set_blackbg_theme();
++ else if (strcmp(theme, "mono") == 0)
++ use_color = 0;
++
++ return use_color;
++}
++
++static void init_one_color(struct dialog_color *color)
++{
++ static int pair = 0;
++
++ pair++;
++ init_pair(pair, color->fg, color->bg);
++ if (color->hl)
++ color->atr = A_BOLD | COLOR_PAIR(pair);
++ else
++ color->atr = COLOR_PAIR(pair);
++}
++
++static void init_dialog_colors(void)
++{
++ init_one_color(&dlg.screen);
++ init_one_color(&dlg.shadow);
++ init_one_color(&dlg.dialog);
++ init_one_color(&dlg.title);
++ init_one_color(&dlg.border);
++ init_one_color(&dlg.button_active);
++ init_one_color(&dlg.button_inactive);
++ init_one_color(&dlg.button_key_active);
++ init_one_color(&dlg.button_key_inactive);
++ init_one_color(&dlg.button_label_active);
++ init_one_color(&dlg.button_label_inactive);
++ init_one_color(&dlg.inputbox);
++ init_one_color(&dlg.inputbox_border);
++ init_one_color(&dlg.searchbox);
++ init_one_color(&dlg.searchbox_title);
++ init_one_color(&dlg.searchbox_border);
++ init_one_color(&dlg.position_indicator);
++ init_one_color(&dlg.menubox);
++ init_one_color(&dlg.menubox_border);
++ init_one_color(&dlg.item);
++ init_one_color(&dlg.item_selected);
++ init_one_color(&dlg.tag);
++ init_one_color(&dlg.tag_selected);
++ init_one_color(&dlg.tag_key);
++ init_one_color(&dlg.tag_key_selected);
++ init_one_color(&dlg.check);
++ init_one_color(&dlg.check_selected);
++ init_one_color(&dlg.uarrow);
++ init_one_color(&dlg.darrow);
++}
+
+ /*
+- * Table of color values
++ * Setup for color display
+ */
+-int color_table[][3] = {
+- {SCREEN_FG, SCREEN_BG, SCREEN_HL},
+- {SHADOW_FG, SHADOW_BG, SHADOW_HL},
+- {DIALOG_FG, DIALOG_BG, DIALOG_HL},
+- {TITLE_FG, TITLE_BG, TITLE_HL},
+- {BORDER_FG, BORDER_BG, BORDER_HL},
+- {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
+- {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
+- {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
+- {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG,
+- BUTTON_KEY_INACTIVE_HL},
+- {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG,
+- BUTTON_LABEL_ACTIVE_HL},
+- {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
+- BUTTON_LABEL_INACTIVE_HL},
+- {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
+- {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
+- {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
+- {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
+- {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
+- {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
+- {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
+- {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
+- {ITEM_FG, ITEM_BG, ITEM_HL},
+- {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
+- {TAG_FG, TAG_BG, TAG_HL},
+- {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
+- {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
+- {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
+- {CHECK_FG, CHECK_BG, CHECK_HL},
+- {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
+- {UARROW_FG, UARROW_BG, UARROW_HL},
+- {DARROW_FG, DARROW_BG, DARROW_HL},
+-}; /* color_table */
++static void color_setup(const char *theme)
++{
++ if (set_theme(theme)) {
++ if (has_colors()) { /* Terminal supports color? */
++ start_color();
++ init_dialog_colors();
++ }
++ }
++ else
++ {
++ set_mono_theme();
++ }
++}
+
+ /*
+ * Set window to attribute 'attr'
+@@ -119,13 +251,13 @@ void attr_clear(WINDOW * win, int height
+
+ void dialog_clear(void)
+ {
+- attr_clear(stdscr, LINES, COLS, screen_attr);
++ attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+ /* Display background title if it exists ... - SLH */
+- if (backtitle != NULL) {
++ if (dlg.backtitle != NULL) {
+ int i;
+
+- wattrset(stdscr, screen_attr);
+- mvwaddstr(stdscr, 0, 1, (char *)backtitle);
++ wattrset(stdscr, dlg.screen.atr);
++ mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+ wmove(stdscr, 1, 1);
+ for (i = 1; i < COLS - 1; i++)
+ waddch(stdscr, ACS_HLINE);
+@@ -136,40 +268,22 @@ void dialog_clear(void)
+ /*
+ * Do some initialization for dialog
+ */
+-void init_dialog(void)
++void init_dialog(const char *backtitle)
++{
++ dlg.backtitle = backtitle;
++ color_setup(getenv("MENUCONFIG_COLOR"));
++}
++
++void reset_dialog(void)
+ {
+ initscr(); /* Init curses */
+ keypad(stdscr, TRUE);
+ cbreak();
+ noecho();
+-
+- if (use_colors) /* Set up colors */
+- color_setup();
+-
+ dialog_clear();
+ }
+
+ /*
+- * Setup for color display
+- */
+-void color_setup(void)
+-{
+- int i;
+-
+- if (has_colors()) { /* Terminal supports color? */
+- start_color();
+-
+- /* Initialize color pairs */
+- for (i = 0; i < ATTRIBUTE_COUNT; i++)
+- init_pair(i + 1, color_table[i][0], color_table[i][1]);
+-
+- /* Setup color attributes */
+- for (i = 0; i < ATTRIBUTE_COUNT; i++)
+- attributes[i] = C_ATTR(color_table[i][2], i + 1);
+- }
+-}
+-
+-/*
+ * End using dialog functions.
+ */
+ void end_dialog(void)
+@@ -184,7 +298,7 @@ void print_title(WINDOW *dialog, const c
+ {
+ if (title) {
+ int tlen = MIN(width - 2, strlen(title));
+- wattrset(dialog, title_attr);
++ wattrset(dialog, dlg.title.atr);
+ mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+ mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+ waddch(dialog, ' ');
+@@ -264,21 +378,23 @@ void print_button(WINDOW * win, const ch
+ int i, temp;
+
+ wmove(win, y, x);
+- wattrset(win, selected ? button_active_attr : button_inactive_attr);
++ wattrset(win, selected ? dlg.button_active.atr
++ : dlg.button_inactive.atr);
+ waddstr(win, "<");
+ temp = strspn(label, " ");
+ label += temp;
+- wattrset(win, selected ? button_label_active_attr
+- : button_label_inactive_attr);
++ wattrset(win, selected ? dlg.button_label_active.atr
++ : dlg.button_label_inactive.atr);
+ for (i = 0; i < temp; i++)
+ waddch(win, ' ');
+- wattrset(win, selected ? button_key_active_attr
+- : button_key_inactive_attr);
++ wattrset(win, selected ? dlg.button_key_active.atr
++ : dlg.button_key_inactive.atr);
+ waddch(win, label[0]);
+- wattrset(win, selected ? button_label_active_attr
+- : button_label_inactive_attr);
++ wattrset(win, selected ? dlg.button_label_active.atr
++ : dlg.button_label_inactive.atr);
+ waddstr(win, (char *)label + 1);
+- wattrset(win, selected ? button_active_attr : button_inactive_attr);
++ wattrset(win, selected ? dlg.button_active.atr
++ : dlg.button_inactive.atr);
+ waddstr(win, ">");
+ wmove(win, y, x + temp + 1);
+ }
+@@ -326,7 +442,7 @@ void draw_shadow(WINDOW * win, int y, in
+ int i;
+
+ if (has_colors()) { /* Whether terminal supports color? */
+- wattrset(win, shadow_attr);
++ wattrset(win, dlg.shadow.atr);
+ wmove(win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ waddch(win, winch(win) & A_CHARTEXT);
+@@ -360,3 +476,167 @@ int first_alpha(const char *string, cons
+
+ return 0;
+ }
++
++/*
++ * ncurses uses ESC to detect escaped char sequences. This resutl in
++ * a small timeout before ESC is actually delivered to the application.
++ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
++ * times esc. But then we need to ignore the second esc to avoid stepping
++ * out one menu too much. Filter away all escaped key sequences since
++ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
++ * needed to make notimeout() do as expected.
++ */
++int on_key_esc(WINDOW *win)
++{
++ int key;
++ int key2;
++ int key3;
++
++ nodelay(win, TRUE);
++ keypad(win, FALSE);
++ key = wgetch(win);
++ key2 = wgetch(win);
++ do {
++ key3 = wgetch(win);
++ } while (key3 != ERR);
++ nodelay(win, FALSE);
++ keypad(win, TRUE);
++ if (key == KEY_ESC && key2 == ERR)
++ return KEY_ESC;
++ else if (key != ERR && key != KEY_ESC && key2 == ERR)
++ ungetch(key);
++
++ return -1;
++}
++
++/* redraw screen in new size */
++int on_key_resize(void)
++{
++ dialog_clear();
++ return KEY_RESIZE;
++}
++
++struct dialog_list *item_cur;
++struct dialog_list item_nil;
++struct dialog_list *item_head;
++
++void item_reset(void)
++{
++ struct dialog_list *p, *next;
++
++ for (p = item_head; p; p = next) {
++ next = p->next;
++ free(p);
++ }
++ item_head = NULL;
++ item_cur = &item_nil;
++}
++
++void item_make(const char *fmt, ...)
++{
++ va_list ap;
++ struct dialog_list *p = malloc(sizeof(*p));
++
++ if (item_head)
++ item_cur->next = p;
++ else
++ item_head = p;
++ item_cur = p;
++ memset(p, 0, sizeof(*p));
++
++ va_start(ap, fmt);
++ vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
++ va_end(ap);
++}
++
++void item_add_str(const char *fmt, ...)
++{
++ va_list ap;
++ size_t avail;
++
++ avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
++
++ va_start(ap, fmt);
++ vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
++ avail, fmt, ap);
++ item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
++ va_end(ap);
++}
++
++void item_set_tag(char tag)
++{
++ item_cur->node.tag = tag;
++}
++void item_set_data(void *ptr)
++{
++ item_cur->node.data = ptr;
++}
++
++void item_set_selected(int val)
++{
++ item_cur->node.selected = val;
++}
++
++int item_activate_selected(void)
++{
++ item_foreach()
++ if (item_is_selected())
++ return 1;
++ return 0;
++}
++
++void *item_data(void)
++{
++ return item_cur->node.data;
++}
++
++char item_tag(void)
++{
++ return item_cur->node.tag;
++}
++
++int item_count(void)
++{
++ int n = 0;
++ struct dialog_list *p;
++
++ for (p = item_head; p; p = p->next)
++ n++;
++ return n;
++}
++
++void item_set(int n)
++{
++ int i = 0;
++ item_foreach()
++ if (i++ == n)
++ return;
++}
++
++int item_n(void)
++{
++ int n = 0;
++ struct dialog_list *p;
++
++ for (p = item_head; p; p = p->next) {
++ if (p == item_cur)
++ return n;
++ n++;
++ }
++ return 0;
++}
++
++const char *item_str(void)
++{
++ return item_cur->node.str;
++}
++
++int item_is_selected(void)
++{
++ return (item_cur->node.selected != 0);
++}
++
++int item_is_tag(char tag)
++{
++ return (item_cur->node.tag == tag);
++}
+diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c
+index cb2568a..ee0a04e 100644
+--- a/scripts/kconfig/lxdialog/yesno.c
++++ b/scripts/kconfig/lxdialog/yesno.c
+@@ -44,6 +44,12 @@ int dialog_yesno(const char *title, cons
+ int i, x, y, key = 0, button = 0;
+ WINDOW *dialog;
+
++do_resize:
++ if (getmaxy(stdscr) < (height + 4))
++ return -ERRDISPLAYTOOSMALL;
++ if (getmaxx(stdscr) < (width + 4))
++ return -ERRDISPLAYTOOSMALL;
++
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+@@ -53,22 +59,23 @@ int dialog_yesno(const char *title, cons
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+- wattrset(dialog, border_attr);
++ draw_box(dialog, 0, 0, height, width,
++ dlg.dialog.atr, dlg.border.atr);
++ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+- wattrset(dialog, dialog_attr);
++ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ print_buttons(dialog, height, width, 0);
+
+- while (key != ESC) {
++ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'Y':
+@@ -92,11 +99,16 @@ int dialog_yesno(const char *title, cons
+ case '\n':
+ delwin(dialog);
+ return button;
+- case ESC:
++ case KEY_ESC:
++ key = on_key_esc(dialog);
+ break;
++ case KEY_RESIZE:
++ delwin(dialog);
++ on_key_resize();
++ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+- return -1; /* ESC pressed */
++ return key; /* ESC pressed */
+ }
+diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
+index 7f97319..08a4c7a 100644
+--- a/scripts/kconfig/mconf.c
++++ b/scripts/kconfig/mconf.c
+@@ -24,6 +24,7 @@
+
+ #define LKC_DIRECT_LINK
+ #include "lkc.h"
++#include "lxdialog/dialog.h"
+
+ static char menu_backtitle[128];
+ static const char mconf_readme[] = N_(
+@@ -159,7 +160,21 @@ static const char mconf_readme[] = N_(
+ "\n"
+ "Note that this mode can eventually be a little more CPU expensive\n"
+ "(especially with a larger number of unrolled categories) than the\n"
+-"default mode.\n"),
++"default mode.\n"
++"\n"
++"Different color themes available\n"
++"--------------------------------\n"
++"It is possible to select different color themes using the variable\n"
++"MENUCONFIG_COLOR. To select a theme use:\n"
++"\n"
++"make MENUCONFIG_COLOR=<theme> menuconfig\n"
++"\n"
++"Available themes are\n"
++" mono => selects colors suitable for monochrome displays\n"
++" blackbg => selects a color scheme with black background\n"
++" classic => theme with blue background. The classic look\n"
++" bluetitle => a LCD friendly version of classic. (default)\n"
++"\n"),
+ menu_instructions[] = N_(
+ "Arrow keys navigate the menu. "
+ "<Enter> selects submenus --->. "
+@@ -256,16 +271,12 @@ search_help[] = N_(
+ " USB$ => find all CONFIG_ symbols ending with USB\n"
+ "\n");
+
+-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;
+ static struct termios ios_org;
+ static int rows = 0, cols = 0;
+ static struct menu *current_menu;
+ static int child_count;
+-static int do_resize;
+ static int single_menu_mode;
+
+ static void conf(struct menu *menu);
+@@ -276,12 +287,6 @@ static void conf_save(void);
+ static void show_textbox(const char *title, const char *text, int r, int c);
+ static void show_helptext(const char *title, const char *text);
+ static void show_help(struct menu *menu);
+-static void show_file(const char *filename, const char *title, int r, int c);
+-
+-static void cprint_init(void);
+-static int cprint1(const char *fmt, ...);
+-static void cprint_done(void);
+-static int cprint(const char *fmt, ...);
+
+ static void init_wsize(void)
+ {
+@@ -318,54 +323,6 @@ static void init_wsize(void)
+ cols -= 5;
+ }
+
+-static void cprint_init(void)
+-{
+- bufptr = buf;
+- argptr = args;
+- memset(args, 0, sizeof(args));
+- indent = 0;
+- child_count = 0;
+- cprint("./scripts/kconfig/lxdialog/lxdialog");
+- cprint("--backtitle");
+- cprint(menu_backtitle);
+-}
+-
+-static int cprint1(const char *fmt, ...)
+-{
+- va_list ap;
+- int res;
+-
+- if (!*argptr)
+- *argptr = bufptr;
+- va_start(ap, fmt);
+- res = vsprintf(bufptr, fmt, ap);
+- va_end(ap);
+- bufptr += res;
+-
+- return res;
+-}
+-
+-static void cprint_done(void)
+-{
+- *bufptr++ = 0;
+- argptr++;
+-}
+-
+-static int cprint(const char *fmt, ...)
+-{
+- va_list ap;
+- int res;
+-
+- *argptr++ = bufptr;
+- va_start(ap, fmt);
+- res = vsprintf(bufptr, fmt, ap);
+- va_end(ap);
+- bufptr += res;
+- *bufptr++ = 0;
+-
+- return res;
+-}
+-
+ static void get_prompt_str(struct gstr *r, struct property *prop)
+ {
+ int i, j;
+@@ -438,108 +395,17 @@ static struct gstr get_relations_str(str
+ return res;
+ }
+
+-pid_t pid;
+-
+-static void winch_handler(int sig)
+-{
+- if (!do_resize) {
+- kill(pid, SIGINT);
+- do_resize = 1;
+- }
+-}
+-
+-static int exec_conf(void)
+-{
+- int pipefd[2], stat, size;
+- struct sigaction sa;
+- sigset_t sset, osset;
+-
+- sigemptyset(&sset);
+- sigaddset(&sset, SIGINT);
+- sigprocmask(SIG_BLOCK, &sset, &osset);
+-
+- signal(SIGINT, SIG_DFL);
+-
+- sa.sa_handler = winch_handler;
+- sigemptyset(&sa.sa_mask);
+- sa.sa_flags = SA_RESTART;
+- sigaction(SIGWINCH, &sa, NULL);
+-
+- *argptr++ = NULL;
+-
+- pipe(pipefd);
+- pid = fork();
+- if (pid == 0) {
+- sigprocmask(SIG_SETMASK, &osset, NULL);
+- dup2(pipefd[1], 2);
+- close(pipefd[0]);
+- close(pipefd[1]);
+- execv(args[0], args);
+- _exit(EXIT_FAILURE);
+- }
+-
+- close(pipefd[1]);
+- bufptr = input_buf;
+- while (1) {
+- size = input_buf + sizeof(input_buf) - bufptr;
+- size = read(pipefd[0], bufptr, size);
+- if (size <= 0) {
+- if (size < 0) {
+- if (errno == EINTR || errno == EAGAIN)
+- continue;
+- perror("read");
+- }
+- break;
+- }
+- bufptr += size;
+- }
+- *bufptr++ = 0;
+- close(pipefd[0]);
+- waitpid(pid, &stat, 0);
+-
+- if (do_resize) {
+- init_wsize();
+- do_resize = 0;
+- sigprocmask(SIG_SETMASK, &osset, NULL);
+- return -1;
+- }
+- if (WIFSIGNALED(stat)) {
+- printf("\finterrupted(%d)\n", WTERMSIG(stat));
+- exit(1);
+- }
+-#if 0
+- printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
+- sleep(1);
+-#endif
+- sigpending(&sset);
+- if (sigismember(&sset, SIGINT)) {
+- printf("\finterrupted\n");
+- exit(1);
+- }
+- sigprocmask(SIG_SETMASK, &osset, NULL);
+-
+- return WEXITSTATUS(stat);
+-}
+-
+ static void search_conf(void)
+ {
+ struct symbol **sym_arr;
+- int stat;
+ struct gstr res;
+-
++ int dres;
+ again:
+- cprint_init();
+- cprint("--title");
+- cprint(_("Search Configuration Parameter"));
+- cprint("--inputbox");
+- cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
+- cprint("10");
+- cprint("75");
+- cprint("");
+- stat = exec_conf();
+- if (stat < 0)
+- goto again;
+- switch (stat) {
++ dialog_clear();
++ dres = dialog_inputbox(_("Search Configuration Parameter"),
++ _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
++ 10, 75, "");
++ switch (dres) {
+ case 0:
+ break;
+ case 1:
+@@ -549,7 +415,7 @@ again:
+ return;
+ }
+
+- sym_arr = sym_re_search(input_buf);
++ sym_arr = sym_re_search(dialog_input_result);
+ res = get_relations_str(sym_arr);
+ free(sym_arr);
+ show_textbox(_("Search Results"), str_get(&res), 0, 0);
+@@ -576,24 +442,24 @@ static void build_conf(struct menu *menu
+ switch (prop->type) {
+ case P_MENU:
+ child_count++;
+- cprint("m%p", menu);
+-
+ if (single_menu_mode) {
+- cprint1("%s%*c%s",
+- menu->data ? "-->" : "++>",
+- indent + 1, ' ', prompt);
++ item_make("%s%*c%s",
++ menu->data ? "-->" : "++>",
++ indent + 1, ' ', prompt);
+ } else
+- cprint1(" %*c%s --->", indent + 1, ' ', prompt);
++ item_make(" %*c%s --->", indent + 1, ' ', prompt);
+
+- cprint_done();
++ item_set_tag('m');
++ item_set_data(menu);
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ default:
+ if (prompt) {
+ child_count++;
+- cprint(":%p", menu);
+- cprint("---%*c%s", indent + 1, ' ', prompt);
++ item_make("---%*c%s", indent + 1, ' ', prompt);
++ item_set_tag(':');
++ item_set_data(menu);
+ }
+ }
+ } else
+@@ -614,10 +480,9 @@ static void build_conf(struct menu *menu
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+- cprint("t%p", menu);
+ switch (type) {
+ case S_BOOLEAN:
+- cprint1("[%c]", val == no ? ' ' : '*');
++ item_make("[%c]", val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+@@ -625,84 +490,87 @@ static void build_conf(struct menu *menu
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+- cprint1("<%c>", ch);
++ item_make("<%c>", ch);
+ break;
+ }
++ item_set_tag('t');
++ item_set_data(menu);
+ } else {
+- cprint("%c%p", def_menu ? 't' : ':', menu);
+- cprint1(" ");
++ item_make(" ");
++ item_set_tag(def_menu ? 't' : ':');
++ item_set_data(menu);
+ }
+
+- cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
++ item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ if (val == yes) {
+ if (def_menu) {
+- cprint1(" (%s)", menu_get_prompt(def_menu));
+- cprint1(" --->");
+- cprint_done();
++ item_add_str(" (%s)", menu_get_prompt(def_menu));
++ item_add_str(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+- } else
+- cprint_done();
++ }
+ return;
+ }
+- cprint_done();
+ } else {
+ if (menu == current_menu) {
+- cprint(":%p", menu);
+- cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
++ item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
++ item_set_tag(':');
++ item_set_data(menu);
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+- cprint(":%p", menu);
+- cprint1(" ");
++ item_make(" ");
++ item_set_tag(':');
++ item_set_data(menu);
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+- cprint("t%p", menu);
+ if (sym_is_changable(sym))
+- cprint1("[%c]", val == no ? ' ' : '*');
++ item_make("[%c]", val == no ? ' ' : '*');
+ else
+- cprint1("---");
++ item_make("---");
++ item_set_tag('t');
++ item_set_data(menu);
+ break;
+ case S_TRISTATE:
+- cprint("t%p", menu);
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ if (sym_is_changable(sym))
+- cprint1("<%c>", ch);
++ item_make("<%c>", ch);
+ else
+- cprint1("---");
++ item_make("---");
++ item_set_tag('t');
++ item_set_data(menu);
+ break;
+ default:
+- cprint("s%p", menu);
+- tmp = cprint1("(%s)", sym_get_string_value(sym));
++ tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
++ item_make("(%s)", sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+- cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+- (sym_has_value(sym) || !sym_is_changable(sym)) ?
+- "" : " (NEW)");
+- cprint_done();
++ item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
++ (sym_has_value(sym) || !sym_is_changable(sym)) ?
++ "" : " (NEW)");
++ item_set_tag('s');
++ item_set_data(menu);
+ goto conf_childs;
+ }
+ }
+- cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+- (sym_has_value(sym) || !sym_is_changable(sym)) ?
+- "" : " (NEW)");
++ item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
++ (sym_has_value(sym) || !sym_is_changable(sym)) ?
++ "" : " (NEW)");
+ if (menu->prompt->type == P_MENU) {
+- cprint1(" --->");
+- cprint_done();
++ item_add_str(" --->");
+ return;
+ }
+- cprint_done();
+ }
+
+ conf_childs:
+@@ -717,59 +585,45 @@ static void conf(struct menu *menu)
+ struct menu *submenu;
+ const char *prompt = menu_get_prompt(menu);
+ struct symbol *sym;
+- char active_entry[40];
+- int stat, type, i;
++ struct menu *active_menu = NULL;
++ int res;
++ int s_scroll = 0;
+
+- unlink("lxdialog.scrltmp");
+- active_entry[0] = 0;
+ while (1) {
+- cprint_init();
+- cprint("--title");
+- cprint("%s", prompt ? prompt : _("Main Menu"));
+- cprint("--menu");
+- cprint(_(menu_instructions));
+- cprint("%d", rows);
+- cprint("%d", cols);
+- cprint("%d", rows - 10);
+- cprint("%s", active_entry);
++ item_reset();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+ if (menu == &rootmenu) {
+- cprint(":");
+- cprint("--- ");
+- cprint("L");
+- cprint(_(" Load an Alternate Configuration File"));
+- cprint("S");
+- cprint(_(" Save Configuration to an Alternate File"));
++ item_make("--- ");
++ item_set_tag(':');
++ item_make(_(" Load an Alternate Configuration File"));
++ item_set_tag('L');
++ item_make(_(" Save an Alternate Configuration File"));
++ item_set_tag('S');
+ }
+- stat = exec_conf();
+- if (stat < 0)
+- continue;
+-
+- if (stat == 1 || stat == 255)
++ dialog_clear();
++ res = dialog_menu(prompt ? prompt : _("Main Menu"),
++ _(menu_instructions),
++ active_menu, &s_scroll);
++ if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+ break;
+-
+- type = input_buf[0];
+- if (!type)
++ if (!item_activate_selected())
++ continue;
++ if (!item_tag())
+ continue;
+
+- for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
+- ;
+- if (i >= sizeof(active_entry))
+- i = sizeof(active_entry) - 1;
+- input_buf[i] = 0;
+- strcpy(active_entry, input_buf);
+-
+- sym = NULL;
+- submenu = NULL;
+- if (sscanf(input_buf + 1, "%p", &submenu) == 1)
++ submenu = item_data();
++ active_menu = item_data();
++ if (submenu)
+ sym = submenu->sym;
++ else
++ sym = NULL;
+
+- switch (stat) {
++ switch (res) {
+ case 0:
+- switch (type) {
++ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data = (void *) (long) !submenu->data;
+@@ -800,7 +654,7 @@ static void conf(struct menu *menu)
+ show_helptext("README", _(mconf_readme));
+ break;
+ case 3:
+- if (type == 't') {
++ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+@@ -808,17 +662,17 @@ static void conf(struct menu *menu)
+ }
+ break;
+ case 4:
+- if (type == 't')
++ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 5:
+- if (type == 't')
++ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ case 6:
+- if (type == 't')
++ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+- else if (type == 'm')
++ else if (item_is_tag('m'))
+ conf(submenu);
+ break;
+ case 7:
+@@ -830,13 +684,8 @@ static void conf(struct menu *menu)
+
+ static void show_textbox(const char *title, const char *text, int r, int c)
+ {
+- int fd;
+-
+- fd = creat(".help.tmp", 0777);
+- write(fd, text, strlen(text));
+- close(fd);
+- show_file(".help.tmp", title, r, c);
+- unlink(".help.tmp");
++ dialog_clear();
++ dialog_textbox(title, text, r, c);
+ }
+
+ static void show_helptext(const char *title, const char *text)
+@@ -864,68 +713,52 @@ static void show_help(struct menu *menu)
+ str_free(&help);
+ }
+
+-static void show_file(const char *filename, const char *title, int r, int c)
+-{
+- do {
+- cprint_init();
+- if (title) {
+- cprint("--title");
+- cprint("%s", title);
+- }
+- cprint("--textbox");
+- cprint("%s", filename);
+- cprint("%d", r ? r : rows);
+- cprint("%d", c ? c : cols);
+- } while (exec_conf() < 0);
+-}
+-
+ static void conf_choice(struct menu *menu)
+ {
+ const char *prompt = menu_get_prompt(menu);
+ struct menu *child;
+ struct symbol *active;
+- int stat;
+
+ active = sym_get_choice_value(menu->sym);
+ while (1) {
+- cprint_init();
+- cprint("--title");
+- cprint("%s", prompt ? prompt : _("Main Menu"));
+- cprint("--radiolist");
+- cprint(_(radiolist_instructions));
+- cprint("15");
+- cprint("70");
+- cprint("6");
++ int res;
++ int selected;
++ item_reset();
+
+ current_menu = menu;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+- cprint("%p", child);
+- cprint("%s", menu_get_prompt(child));
++ item_make("%s", menu_get_prompt(child));
++ item_set_data(child);
++ if (child->sym == active)
++ item_set_selected(1);
+ if (child->sym == sym_get_choice_value(menu->sym))
+- cprint("ON");
+- else if (child->sym == active)
+- cprint("SELECTED");
+- else
+- cprint("OFF");
++ item_set_tag('X');
+ }
+-
+- stat = exec_conf();
+- switch (stat) {
++ dialog_clear();
++ res = dialog_checklist(prompt ? prompt : _("Main Menu"),
++ _(radiolist_instructions),
++ 15, 70, 6);
++ selected = item_activate_selected();
++ switch (res) {
+ case 0:
+- if (sscanf(input_buf, "%p", &child) != 1)
+- break;
+- sym_set_tristate_value(child->sym, yes);
++ if (selected) {
++ child = item_data();
++ sym_set_tristate_value(child->sym, yes);
++ }
+ return;
+ case 1:
+- if (sscanf(input_buf, "%p", &child) == 1) {
++ if (selected) {
++ child = item_data();
+ show_help(child);
+ active = child->sym;
+ } else
+ show_help(menu);
+ break;
+- case 255:
++ case KEY_ESC:
++ return;
++ case -ERRDISPLAYTOOSMALL:
+ return;
+ }
+ }
+@@ -934,40 +767,38 @@ static void conf_choice(struct menu *men
+ static void conf_string(struct menu *menu)
+ {
+ const char *prompt = menu_get_prompt(menu);
+- int stat;
+
+ while (1) {
+- cprint_init();
+- cprint("--title");
+- cprint("%s", prompt ? prompt : _("Main Menu"));
+- cprint("--inputbox");
++ int res;
++ char *heading;
++
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+- cprint(_(inputbox_instructions_int));
++ heading = _(inputbox_instructions_int);
+ break;
+ case S_HEX:
+- cprint(_(inputbox_instructions_hex));
++ heading = _(inputbox_instructions_hex);
+ break;
+ case S_STRING:
+- cprint(_(inputbox_instructions_string));
++ heading = _(inputbox_instructions_string);
+ break;
+ default:
+- /* panic? */;
++ heading = "Internal mconf error!";
+ }
+- cprint("10");
+- cprint("75");
+- cprint("%s", sym_get_string_value(menu->sym));
+- stat = exec_conf();
+- switch (stat) {
++ dialog_clear();
++ res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
++ heading, 10, 75,
++ sym_get_string_value(menu->sym));
++ switch (res) {
+ case 0:
+- if (sym_set_string_value(menu->sym, input_buf))
++ if (sym_set_string_value(menu->sym, dialog_input_result))
+ return;
+ show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+- case 255:
++ case KEY_ESC:
+ return;
+ }
+ }
+@@ -975,28 +806,24 @@ static void conf_string(struct menu *men
+
+ static void conf_load(void)
+ {
+- int stat;
+
+ while (1) {
+- cprint_init();
+- cprint("--inputbox");
+- cprint(load_config_text);
+- cprint("11");
+- cprint("55");
+- cprint("%s", filename);
+- stat = exec_conf();
+- switch(stat) {
++ int res;
++ dialog_clear();
++ res = dialog_inputbox(NULL, load_config_text,
++ 11, 55, filename);
++ switch(res) {
+ case 0:
+- if (!input_buf[0])
++ if (!dialog_input_result[0])
+ return;
+- if (!conf_read(input_buf))
++ if (!conf_read(dialog_input_result))
+ return;
+ show_textbox(NULL, _("File does not exist!"), 5, 38);
+ break;
+ case 1:
+ show_helptext(_("Load Alternate Configuration"), load_config_help);
+ break;
+- case 255:
++ case KEY_ESC:
+ return;
+ }
+ }
+@@ -1004,28 +831,23 @@ static void conf_load(void)
+
+ static void conf_save(void)
+ {
+- int stat;
+-
+ while (1) {
+- cprint_init();
+- cprint("--inputbox");
+- cprint(save_config_text);
+- cprint("11");
+- cprint("55");
+- cprint("%s", filename);
+- stat = exec_conf();
+- switch(stat) {
++ int res;
++ dialog_clear();
++ res = dialog_inputbox(NULL, save_config_text,
++ 11, 55, filename);
++ switch(res) {
+ case 0:
+- if (!input_buf[0])
++ if (!dialog_input_result[0])
+ return;
+- if (!conf_write(input_buf))
++ if (!conf_write(dialog_input_result))
+ return;
+ show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
+ break;
+ case 1:
+ show_helptext(_("Save Alternate Configuration"), save_config_help);
+ break;
+- case 255:
++ case KEY_ESC:
+ return;
+ }
+ }
+@@ -1034,15 +856,13 @@ static void conf_save(void)
+ static void conf_cleanup(void)
+ {
+ tcsetattr(1, TCSAFLUSH, &ios_org);
+- unlink(".help.tmp");
+- unlink("lxdialog.scrltmp");
+ }
+
+ int main(int ac, char **av)
+ {
+ struct symbol *sym;
+ char *mode;
+- int stat;
++ int res;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+@@ -1065,18 +885,19 @@ int main(int ac, char **av)
+ tcgetattr(1, &ios_org);
+ atexit(conf_cleanup);
+ init_wsize();
+- conf(&rootmenu);
+-
++ reset_dialog();
++ init_dialog(menu_backtitle);
+ do {
+- cprint_init();
+- cprint("--yesno");
+- cprint(_("Do you wish to save your new kernel configuration?"));
+- cprint("5");
+- cprint("60");
+- stat = exec_conf();
+- } while (stat < 0);
+-
+- if (stat == 0) {
++ conf(&rootmenu);
++ dialog_clear();
++ res = dialog_yesno(NULL,
++ _("Do you wish to save your "
++ "new kernel configuration?\n"
++ "<ESC><ESC> to continue."),
++ 6, 60);
++ } while (res == KEY_ESC);
++ end_dialog();
++ if (res == 0) {
+ if (conf_write(NULL)) {
+ fprintf(stderr, _("\n\n"
+ "Error during writing of the kernel configuration.\n"
+diff --git a/scripts/kernel-doc b/scripts/kernel-doc
+index c9ca0c2..187f5de 100755
+--- a/scripts/kernel-doc
++++ b/scripts/kernel-doc
+@@ -57,8 +57,8 @@ use strict;
+ # other functions are ignored.
+ #
+ # -nofunction funcname
+-# If set, then only generate documentation for the other function(s). All
+-# other functions are ignored. Cannot be used with -function together
++# If set, then only generate documentation for the other function(s).
++# Cannot be used together with -function
+ # (yes, that's a bug -- perl hackers can fix it 8))
+ #
+ # c files - list of 'c' files to process
+@@ -1262,7 +1262,9 @@ sub output_intro_text(%) {
+ }
+
+ ##
+-# generic output function for typedefs
++# generic output function for all types (function, struct/union, typedef, enum);
++# calls the generated, variable output_ function name based on
++# functype and output_mode
+ sub output_declaration {
+ no strict 'refs';
+ my $name = shift;
+@@ -1278,8 +1280,7 @@ sub output_declaration {
+ }
+
+ ##
+-# generic output function - calls the right one based
+-# on current output mode.
++# generic output function - calls the right one based on current output mode.
+ sub output_intro {
+ no strict 'refs';
+ my $func = "output_intro_".$output_mode;
+@@ -1518,6 +1519,9 @@ sub dump_function($$) {
+ $prototype =~ s/^asmlinkage +//;
+ $prototype =~ s/^inline +//;
+ $prototype =~ s/^__inline__ +//;
++ $prototype =~ s/^__inline +//;
++ $prototype =~ s/^__always_inline +//;
++ $prototype =~ s/^noinline +//;
+ $prototype =~ s/__devinit +//;
+ $prototype =~ s/^#define +//; #ak added
+ $prototype =~ s/__attribute__ \(\([a-z,]*\)\)//;
+@@ -1778,8 +1782,9 @@ sub process_file($) {
+ $in_doc_sect = 1;
+ $contents = $newcontents;
+ if ($contents ne "") {
+- if (substr($contents, 0, 1) eq " ") {
+- $contents = substr($contents, 1);
++ while ((substr($contents, 0, 1) eq " ") ||
++ substr($contents, 0, 1) eq "\t") {
++ $contents = substr($contents, 1);
+ }
+ $contents .= "\n";
+ }
+diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
+index e2de650..f61c9cc 100644
+--- a/scripts/mod/file2alias.c
++++ b/scripts/mod/file2alias.c
+@@ -265,6 +265,14 @@ static int do_ccw_entry(const char *file
+ return 1;
+ }
+
++/* looks like: "ap:tN" */
++static int do_ap_entry(const char *filename,
++ struct ap_device_id *id, char *alias)
++{
++ sprintf(alias, "ap:t%02X", id->dev_type);
++ return 1;
++}
++
+ /* Looks like: "serio:tyNprNidNexN" */
+ static int do_serio_entry(const char *filename,
+ struct serio_device_id *id, char *alias)
+@@ -436,6 +444,14 @@ static int do_input_entry(const char *fi
+ return 1;
+ }
+
++static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa,
++ char *alias)
++{
++ if (eisa->sig[0])
++ sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig);
++ return 1;
++}
++
+ /* Ignore any prefix, eg. v850 prepends _ */
+ static inline int sym_is(const char *symbol, const char *name)
+ {
+@@ -503,6 +519,10 @@ void handle_moddevtable(struct module *m
+ do_table(symval, sym->st_size,
+ sizeof(struct ccw_device_id), "ccw",
+ do_ccw_entry, mod);
++ else if (sym_is(symname, "__mod_ap_device_table"))
++ do_table(symval, sym->st_size,
++ sizeof(struct ap_device_id), "ap",
++ do_ap_entry, mod);
+ else if (sym_is(symname, "__mod_serio_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct serio_device_id), "serio",
+@@ -535,6 +555,10 @@ void handle_moddevtable(struct module *m
+ do_table(symval, sym->st_size,
+ sizeof(struct input_device_id), "input",
+ do_input_entry, mod);
++ else if (sym_is(symname, "__mod_eisa_device_table"))
++ do_table(symval, sym->st_size,
++ sizeof(struct eisa_device_id), "eisa",
++ do_eisa_entry, mod);
+ }
+
+ /* Now add out buffered information to the generated C source */
+diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
+index dfde0e8..2e11416 100644
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -23,6 +23,8 @@ int have_vmlinux = 0;
+ static int all_versions = 0;
+ /* If we are modposting external module set to 1 */
+ static int external_module = 0;
++/* Only warn about unresolved symbols */
++static int warn_unresolved = 0;
+ /* How a symbol is exported */
+ enum export {
+ export_plain, export_unused, export_gpl,
+@@ -581,8 +583,8 @@ static int strrcmp(const char *s, const
+ * fromsec = .data
+ * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
+ **/
+-static int secref_whitelist(const char *tosec, const char *fromsec,
+- const char *atsym)
++static int secref_whitelist(const char *modname, const char *tosec,
++ const char *fromsec, const char *atsym)
+ {
+ int f1 = 1, f2 = 1;
+ const char **s;
+@@ -618,8 +620,16 @@ static int secref_whitelist(const char *
+ for (s = pat2sym; *s; s++)
+ if (strrcmp(atsym, *s) == 0)
+ f1 = 1;
++ if (f1 && f2)
++ return 1;
+
+- return f1 && f2;
++ /* Whitelist all references from .pci_fixup section if vmlinux */
++ if (is_vmlinux(modname)) {
++ if ((strcmp(fromsec, ".pci_fixup") == 0) &&
++ (strcmp(tosec, ".init.text") == 0))
++ return 1;
++ }
++ return 0;
+ }
+
+ /**
+@@ -726,7 +736,8 @@ static void warn_sec_mismatch(const char
+
+ /* check whitelist - we may ignore it */
+ if (before &&
+- secref_whitelist(secname, fromsec, elf->strtab + before->st_name))
++ secref_whitelist(modname, secname, fromsec,
++ elf->strtab + before->st_name))
+ return;
+
+ if (before && after) {
+@@ -910,6 +921,8 @@ static int init_section_ref_ok(const cha
+ ".fixup",
+ ".smp_locks",
+ ".plt", /* seen on ARCH=um build on x86_64. Harmless */
++ "__ftr_fixup", /* powerpc cpu feature fixup */
++ "__fw_ftr_fixup", /* powerpc firmware feature fixup */
+ NULL
+ };
+ /* Start of section names */
+@@ -1187,16 +1200,19 @@ static void add_header(struct buffer *b,
+ /**
+ * Record CRCs for unresolved symbols
+ **/
+-static void add_versions(struct buffer *b, struct module *mod)
++static int add_versions(struct buffer *b, struct module *mod)
+ {
+ struct symbol *s, *exp;
++ int err = 0;
+
+ for (s = mod->unres; s; s = s->next) {
+ exp = find_symbol(s->name);
+ if (!exp || exp->module == mod) {
+- if (have_vmlinux && !s->weak)
++ if (have_vmlinux && !s->weak) {
+ warn("\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
++ err = warn_unresolved ? 0 : 1;
++ }
+ continue;
+ }
+ s->module = exp->module;
+@@ -1205,7 +1221,7 @@ static void add_versions(struct buffer *
+ }
+
+ if (!modversions)
+- return;
++ return err;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "static const struct modversion_info ____versions[]\n");
+@@ -1225,6 +1241,8 @@ static void add_versions(struct buffer *
+ }
+
+ buf_printf(b, "};\n");
++
++ return err;
+ }
+
+ static void add_depends(struct buffer *b, struct module *mod,
+@@ -1402,8 +1420,9 @@ int main(int argc, char **argv)
+ char *kernel_read = NULL, *module_read = NULL;
+ char *dump_write = NULL;
+ int opt;
++ int err;
+
+- while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) {
++ while ((opt = getopt(argc, argv, "i:I:mo:aw")) != -1) {
+ switch(opt) {
+ case 'i':
+ kernel_read = optarg;
+@@ -1421,6 +1440,9 @@ int main(int argc, char **argv)
+ case 'a':
+ all_versions = 1;
+ break;
++ case 'w':
++ warn_unresolved = 1;
++ break;
+ default:
+ exit(1);
+ }
+@@ -1441,6 +1463,8 @@ int main(int argc, char **argv)
+ check_exports(mod);
+ }
+
++ err = 0;
++
+ for (mod = modules; mod; mod = mod->next) {
+ if (mod->skip)
+ continue;
+@@ -1448,7 +1472,7 @@ int main(int argc, char **argv)
+ buf.pos = 0;
+
+ add_header(&buf, mod);
+- add_versions(&buf, mod);
++ err |= add_versions(&buf, mod);
+ add_depends(&buf, mod, modules);
+ add_moddevtable(&buf, mod);
+ add_srcversion(&buf, mod);
+@@ -1460,5 +1484,5 @@ int main(int argc, char **argv)
+ if (dump_write)
+ write_dump(dump_write);
+
+- return 0;
++ return err;
+ }
+diff --git a/scripts/package/mkspec b/scripts/package/mkspec
+index df89284..ffd61fe 100755
+--- a/scripts/package/mkspec
++++ b/scripts/package/mkspec
+@@ -63,9 +63,9 @@ fi
+
+ echo "%install"
+ echo "%ifarch ia64"
+-echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
++echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
+ echo "%else"
+-echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
++echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
+ echo "%endif"
+
+ echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install'
+diff --git a/scripts/unifdef.c b/scripts/unifdef.c
+new file mode 100644
+index 0000000..552025e
+--- /dev/null
++++ b/scripts/unifdef.c
+@@ -0,0 +1,1005 @@
++/*
++ * Copyright (c) 2002 - 2005 Tony Finch <dot at dotat.at>. All rights reserved.
++ *
++ * This code is derived from software contributed to Berkeley by Dave Yost.
++ * It was rewritten to support ANSI C by Tony Finch. The original version of
++ * unifdef carried the following copyright notice. None of its code remains
++ * in this version (though some of the names remain).
++ *
++ * Copyright (c) 1985, 1993
++ * The Regents of the University of California. 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.
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 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 <sys/cdefs.h>
++
++#ifndef lint
++#if 0
++static const char copyright[] =
++"@(#) Copyright (c) 1985, 1993\n\
++ The Regents of the University of California. All rights reserved.\n";
++#endif
++#ifdef __IDSTRING
++__IDSTRING(Berkeley, "@(#)unifdef.c 8.1 (Berkeley) 6/6/93");
++__IDSTRING(NetBSD, "$NetBSD: unifdef.c,v 1.8 2000/07/03 02:51:36 matt Exp $");
++__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.171 2005/03/08 12:38:48 fanf2 Exp $");
++#endif
++#endif /* not lint */
++#ifdef __FBSDID
++__FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.bin/unifdef/unifdef.c,v 1.20 2005/05/21 09:55:09 ru Exp $");
++#endif
++
++/*
++ * unifdef - remove ifdef'ed lines
++ *
++ * Wishlist:
++ * provide an option which will append the name of the
++ * appropriate symbol after #else's and #endif's
++ * provide an option which will check symbols after
++ * #else's and #endif's to see that they match their
++ * corresponding #ifdef or #ifndef
++ *
++ * The first two items above require better buffer handling, which would
++ * also make it possible to handle all "dodgy" directives correctly.
++ */
++
++#include <ctype.h>
++#include <err.h>
++#include <stdarg.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++size_t strlcpy(char *dst, const char *src, size_t siz);
++
++/* types of input lines: */
++typedef enum {
++ LT_TRUEI, /* a true #if with ignore flag */
++ LT_FALSEI, /* a false #if with ignore flag */
++ LT_IF, /* an unknown #if */
++ LT_TRUE, /* a true #if */
++ LT_FALSE, /* a false #if */
++ LT_ELIF, /* an unknown #elif */
++ LT_ELTRUE, /* a true #elif */
++ LT_ELFALSE, /* a false #elif */
++ LT_ELSE, /* #else */
++ LT_ENDIF, /* #endif */
++ LT_DODGY, /* flag: directive is not on one line */
++ LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
++ LT_PLAIN, /* ordinary line */
++ LT_EOF, /* end of file */
++ LT_COUNT
++} Linetype;
++
++static char const * const linetype_name[] = {
++ "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
++ "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
++ "DODGY TRUEI", "DODGY FALSEI",
++ "DODGY IF", "DODGY TRUE", "DODGY FALSE",
++ "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
++ "DODGY ELSE", "DODGY ENDIF",
++ "PLAIN", "EOF"
++};
++
++/* state of #if processing */
++typedef enum {
++ IS_OUTSIDE,
++ IS_FALSE_PREFIX, /* false #if followed by false #elifs */
++ IS_TRUE_PREFIX, /* first non-false #(el)if is true */
++ IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */
++ IS_FALSE_MIDDLE, /* a false #elif after a pass state */
++ IS_TRUE_MIDDLE, /* a true #elif after a pass state */
++ IS_PASS_ELSE, /* an else after a pass state */
++ IS_FALSE_ELSE, /* an else after a true state */
++ IS_TRUE_ELSE, /* an else after only false states */
++ IS_FALSE_TRAILER, /* #elifs after a true are false */
++ IS_COUNT
++} Ifstate;
++
++static char const * const ifstate_name[] = {
++ "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
++ "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
++ "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
++ "FALSE_TRAILER"
++};
++
++/* state of comment parser */
++typedef enum {
++ NO_COMMENT = false, /* outside a comment */
++ C_COMMENT, /* in a comment like this one */
++ CXX_COMMENT, /* between // and end of line */
++ STARTING_COMMENT, /* just after slash-backslash-newline */
++ FINISHING_COMMENT, /* star-backslash-newline in a C comment */
++ CHAR_LITERAL, /* inside '' */
++ STRING_LITERAL /* inside "" */
++} Comment_state;
++
++static char const * const comment_name[] = {
++ "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING"
++};
++
++/* state of preprocessor line parser */
++typedef enum {
++ LS_START, /* only space and comments on this line */
++ LS_HASH, /* only space, comments, and a hash */
++ LS_DIRTY /* this line can't be a preprocessor line */
++} Line_state;
++
++static char const * const linestate_name[] = {
++ "START", "HASH", "DIRTY"
++};
++
++/*
++ * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1
++ */
++#define MAXDEPTH 64 /* maximum #if nesting */
++#define MAXLINE 4096 /* maximum length of line */
++#define MAXSYMS 4096 /* maximum number of symbols */
++
++/*
++ * Sometimes when editing a keyword the replacement text is longer, so
++ * we leave some space at the end of the tline buffer to accommodate this.
++ */
++#define EDITSLOP 10
++
++/*
++ * Globals.
++ */
++
++static bool complement; /* -c: do the complement */
++static bool debugging; /* -d: debugging reports */
++static bool iocccok; /* -e: fewer IOCCC errors */
++static bool killconsts; /* -k: eval constant #ifs */
++static bool lnblank; /* -l: blank deleted lines */
++static bool lnnum; /* -n: add #line directives */
++static bool symlist; /* -s: output symbol list */
++static bool text; /* -t: this is a text file */
++
++static const char *symname[MAXSYMS]; /* symbol name */
++static const char *value[MAXSYMS]; /* -Dsym=value */
++static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */
++static int nsyms; /* number of symbols */
++
++static FILE *input; /* input file pointer */
++static const char *filename; /* input file name */
++static int linenum; /* current line number */
++
++static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
++static char *keyword; /* used for editing #elif's */
++
++static Comment_state incomment; /* comment parser state */
++static Line_state linestate; /* #if line parser state */
++static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
++static bool ignoring[MAXDEPTH]; /* ignore comments state */
++static int stifline[MAXDEPTH]; /* start of current #if */
++static int depth; /* current #if nesting */
++static int delcount; /* count of deleted lines */
++static bool keepthis; /* don't delete constant #if */
++
++static int exitstat; /* program exit status */
++
++static void addsym(bool, bool, char *);
++static void debug(const char *, ...);
++static void done(void);
++static void error(const char *);
++static int findsym(const char *);
++static void flushline(bool);
++static Linetype getline(void);
++static Linetype ifeval(const char **);
++static void ignoreoff(void);
++static void ignoreon(void);
++static void keywordedit(const char *);
++static void nest(void);
++static void process(void);
++static const char *skipcomment(const char *);
++static const char *skipsym(const char *);
++static void state(Ifstate);
++static int strlcmp(const char *, const char *, size_t);
++static void unnest(void);
++static void usage(void);
++
++#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
++
++/*
++ * The main program.
++ */
++int
++main(int argc, char *argv[])
++{
++ int opt;
++
++ while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1)
++ switch (opt) {
++ case 'i': /* treat stuff controlled by these symbols as text */
++ /*
++ * For strict backwards-compatibility the U or D
++ * should be immediately after the -i but it doesn't
++ * matter much if we relax that requirement.
++ */
++ opt = *optarg++;
++ if (opt == 'D')
++ addsym(true, true, optarg);
++ else if (opt == 'U')
++ addsym(true, false, optarg);
++ else
++ usage();
++ break;
++ case 'D': /* define a symbol */
++ addsym(false, true, optarg);
++ break;
++ case 'U': /* undef a symbol */
++ addsym(false, false, optarg);
++ break;
++ case 'I':
++ /* no-op for compatibility with cpp */
++ break;
++ case 'c': /* treat -D as -U and vice versa */
++ complement = true;
++ break;
++ case 'd':
++ debugging = true;
++ break;
++ case 'e': /* fewer errors from dodgy lines */
++ iocccok = true;
++ break;
++ case 'k': /* process constant #ifs */
++ killconsts = true;
++ break;
++ case 'l': /* blank deleted lines instead of omitting them */
++ lnblank = true;
++ break;
++ case 'n': /* add #line directive after deleted lines */
++ lnnum = true;
++ break;
++ case 's': /* only output list of symbols that control #ifs */
++ symlist = true;
++ break;
++ case 't': /* don't parse C comments */
++ text = true;
++ break;
++ default:
++ usage();
++ }
++ argc -= optind;
++ argv += optind;
++ if (argc > 1) {
++ errx(2, "can only do one file");
++ } else if (argc == 1 && strcmp(*argv, "-") != 0) {
++ filename = *argv;
++ input = fopen(filename, "r");
++ if (input == NULL)
++ err(2, "can't open %s", filename);
++ } else {
++ filename = "[stdin]";
++ input = stdin;
++ }
++ process();
++ abort(); /* bug */
++}
++
++static void
++usage(void)
++{
++ fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]"
++ " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
++ exit(2);
++}
++
++/*
++ * A state transition function alters the global #if processing state
++ * in a particular way. The table below is indexed by the current
++ * processing state and the type of the current line.
++ *
++ * Nesting is handled by keeping a stack of states; some transition
++ * functions increase or decrease the depth. They also maintain the
++ * ignore state on a stack. In some complicated cases they have to
++ * alter the preprocessor directive, as follows.
++ *
++ * When we have processed a group that starts off with a known-false
++ * #if/#elif sequence (which has therefore been deleted) followed by a
++ * #elif that we don't understand and therefore must keep, we edit the
++ * latter into a #if to keep the nesting correct.
++ *
++ * When we find a true #elif in a group, the following block will
++ * always be kept and the rest of the sequence after the next #elif or
++ * #else will be discarded. We edit the #elif into a #else and the
++ * following directive to #endif since this has the desired behaviour.
++ *
++ * "Dodgy" directives are split across multiple lines, the most common
++ * example being a multi-line comment hanging off the right of the
++ * directive. We can handle them correctly only if there is no change
++ * from printing to dropping (or vice versa) caused by that directive.
++ * If the directive is the first of a group we have a choice between
++ * failing with an error, or passing it through unchanged instead of
++ * evaluating it. The latter is not the default to avoid questions from
++ * users about unifdef unexpectedly leaving behind preprocessor directives.
++ */
++typedef void state_fn(void);
++
++/* report an error */
++static void Eelif (void) { error("Inappropriate #elif"); }
++static void Eelse (void) { error("Inappropriate #else"); }
++static void Eendif(void) { error("Inappropriate #endif"); }
++static void Eeof (void) { error("Premature EOF"); }
++static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
++/* plain line handling */
++static void print (void) { flushline(true); }
++static void drop (void) { flushline(false); }
++/* output lacks group's start line */
++static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); }
++static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); }
++static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
++/* print/pass this block */
++static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
++static void Pelse (void) { print(); state(IS_PASS_ELSE); }
++static void Pendif(void) { print(); unnest(); }
++/* discard this block */
++static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); }
++static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); }
++static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
++static void Dendif(void) { drop(); unnest(); }
++/* first line of group */
++static void Fdrop (void) { nest(); Dfalse(); }
++static void Fpass (void) { nest(); Pelif(); }
++static void Ftrue (void) { nest(); Strue(); }
++static void Ffalse(void) { nest(); Sfalse(); }
++/* variable pedantry for obfuscated lines */
++static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); }
++static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); }
++static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
++/* ignore comments in this block */
++static void Idrop (void) { Fdrop(); ignoreon(); }
++static void Itrue (void) { Ftrue(); ignoreon(); }
++static void Ifalse(void) { Ffalse(); ignoreon(); }
++/* edit this line */
++static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
++static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); }
++static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); }
++static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); }
++
++static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
++/* IS_OUTSIDE */
++{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
++ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
++ print, done },
++/* IS_FALSE_PREFIX */
++{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
++ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
++ drop, Eeof },
++/* IS_TRUE_PREFIX */
++{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
++ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
++ print, Eeof },
++/* IS_PASS_MIDDLE */
++{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
++ Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
++ print, Eeof },
++/* IS_FALSE_MIDDLE */
++{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
++ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
++ drop, Eeof },
++/* IS_TRUE_MIDDLE */
++{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
++ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
++ print, Eeof },
++/* IS_PASS_ELSE */
++{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
++ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
++ print, Eeof },
++/* IS_FALSE_ELSE */
++{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
++ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
++ drop, Eeof },
++/* IS_TRUE_ELSE */
++{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
++ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
++ print, Eeof },
++/* IS_FALSE_TRAILER */
++{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
++ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
++ drop, Eeof }
++/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
++ TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
++ PLAIN EOF */
++};
++
++/*
++ * State machine utility functions
++ */
++static void
++done(void)
++{
++ if (incomment)
++ error("EOF in comment");
++ exit(exitstat);
++}
++static void
++ignoreoff(void)
++{
++ if (depth == 0)
++ abort(); /* bug */
++ ignoring[depth] = ignoring[depth-1];
++}
++static void
++ignoreon(void)
++{
++ ignoring[depth] = true;
++}
++static void
++keywordedit(const char *replacement)
++{
++ size_t size = tline + sizeof(tline) - keyword;
++ char *dst = keyword;
++ const char *src = replacement;
++ if (size != 0) {
++ while ((--size != 0) && (*src != '\0'))
++ *dst++ = *src++;
++ *dst = '\0';
++ }
++ print();
++}
++static void
++nest(void)
++{
++ depth += 1;
++ if (depth >= MAXDEPTH)
++ error("Too many levels of nesting");
++ stifline[depth] = linenum;
++}
++static void
++unnest(void)
++{
++ if (depth == 0)
++ abort(); /* bug */
++ depth -= 1;
++}
++static void
++state(Ifstate is)
++{
++ ifstate[depth] = is;
++}
++
++/*
++ * Write a line to the output or not, according to command line options.
++ */
++static void
++flushline(bool keep)
++{
++ if (symlist)
++ return;
++ if (keep ^ complement) {
++ if (lnnum && delcount > 0)
++ printf("#line %d\n", linenum);
++ fputs(tline, stdout);
++ delcount = 0;
++ } else {
++ if (lnblank)
++ putc('\n', stdout);
++ exitstat = 1;
++ delcount += 1;
++ }
++}
++
++/*
++ * The driver for the state machine.
++ */
++static void
++process(void)
++{
++ Linetype lineval;
++
++ for (;;) {
++ linenum++;
++ lineval = getline();
++ trans_table[ifstate[depth]][lineval]();
++ debug("process %s -> %s depth %d",
++ linetype_name[lineval],
++ ifstate_name[ifstate[depth]], depth);
++ }
++}
++
++/*
++ * Parse a line and determine its type. We keep the preprocessor line
++ * parser state between calls in the global variable linestate, with
++ * help from skipcomment().
++ */
++static Linetype
++getline(void)
++{
++ const char *cp;
++ int cursym;
++ int kwlen;
++ Linetype retval;
++ Comment_state wascomment;
++
++ if (fgets(tline, MAXLINE, input) == NULL)
++ return (LT_EOF);
++ retval = LT_PLAIN;
++ wascomment = incomment;
++ cp = skipcomment(tline);
++ if (linestate == LS_START) {
++ if (*cp == '#') {
++ linestate = LS_HASH;
++ cp = skipcomment(cp + 1);
++ } else if (*cp != '\0')
++ linestate = LS_DIRTY;
++ }
++ if (!incomment && linestate == LS_HASH) {
++ keyword = tline + (cp - tline);
++ cp = skipsym(cp);
++ kwlen = cp - keyword;
++ /* no way can we deal with a continuation inside a keyword */
++ if (strncmp(cp, "\\\n", 2) == 0)
++ Eioccc();
++ if (strlcmp("ifdef", keyword, kwlen) == 0 ||
++ strlcmp("ifndef", keyword, kwlen) == 0) {
++ cp = skipcomment(cp);
++ if ((cursym = findsym(cp)) < 0)
++ retval = LT_IF;
++ else {
++ retval = (keyword[2] == 'n')
++ ? LT_FALSE : LT_TRUE;
++ if (value[cursym] == NULL)
++ retval = (retval == LT_TRUE)
++ ? LT_FALSE : LT_TRUE;
++ if (ignore[cursym])
++ retval = (retval == LT_TRUE)
++ ? LT_TRUEI : LT_FALSEI;
++ }
++ cp = skipsym(cp);
++ } else if (strlcmp("if", keyword, kwlen) == 0)
++ retval = ifeval(&cp);
++ else if (strlcmp("elif", keyword, kwlen) == 0)
++ retval = ifeval(&cp) - LT_IF + LT_ELIF;
++ else if (strlcmp("else", keyword, kwlen) == 0)
++ retval = LT_ELSE;
++ else if (strlcmp("endif", keyword, kwlen) == 0)
++ retval = LT_ENDIF;
++ else {
++ linestate = LS_DIRTY;
++ retval = LT_PLAIN;
++ }
++ cp = skipcomment(cp);
++ if (*cp != '\0') {
++ linestate = LS_DIRTY;
++ if (retval == LT_TRUE || retval == LT_FALSE ||
++ retval == LT_TRUEI || retval == LT_FALSEI)
++ retval = LT_IF;
++ if (retval == LT_ELTRUE || retval == LT_ELFALSE)
++ retval = LT_ELIF;
++ }
++ if (retval != LT_PLAIN && (wascomment || incomment)) {
++ retval += LT_DODGY;
++ if (incomment)
++ linestate = LS_DIRTY;
++ }
++ /* skipcomment should have changed the state */
++ if (linestate == LS_HASH)
++ abort(); /* bug */
++ }
++ if (linestate == LS_DIRTY) {
++ while (*cp != '\0')
++ cp = skipcomment(cp + 1);
++ }
++ debug("parser %s comment %s line",
++ comment_name[incomment], linestate_name[linestate]);
++ return (retval);
++}
++
++/*
++ * These are the binary operators that are supported by the expression
++ * evaluator. Note that if support for division is added then we also
++ * need short-circuiting booleans because of divide-by-zero.
++ */
++static int op_lt(int a, int b) { return (a < b); }
++static int op_gt(int a, int b) { return (a > b); }
++static int op_le(int a, int b) { return (a <= b); }
++static int op_ge(int a, int b) { return (a >= b); }
++static int op_eq(int a, int b) { return (a == b); }
++static int op_ne(int a, int b) { return (a != b); }
++static int op_or(int a, int b) { return (a || b); }
++static int op_and(int a, int b) { return (a && b); }
++
++/*
++ * An evaluation function takes three arguments, as follows: (1) a pointer to
++ * an element of the precedence table which lists the operators at the current
++ * level of precedence; (2) a pointer to an integer which will receive the
++ * value of the expression; and (3) a pointer to a char* that points to the
++ * expression to be evaluated and that is updated to the end of the expression
++ * when evaluation is complete. The function returns LT_FALSE if the value of
++ * the expression is zero, LT_TRUE if it is non-zero, or LT_IF if the
++ * expression could not be evaluated.
++ */
++struct ops;
++
++typedef Linetype eval_fn(const struct ops *, int *, const char **);
++
++static eval_fn eval_table, eval_unary;
++
++/*
++ * The precedence table. Expressions involving binary operators are evaluated
++ * in a table-driven way by eval_table. When it evaluates a subexpression it
++ * calls the inner function with its first argument pointing to the next
++ * element of the table. Innermost expressions have special non-table-driven
++ * handling.
++ */
++static const struct ops {
++ eval_fn *inner;
++ struct op {
++ const char *str;
++ int (*fn)(int, int);
++ } op[5];
++} eval_ops[] = {
++ { eval_table, { { "||", op_or } } },
++ { eval_table, { { "&&", op_and } } },
++ { eval_table, { { "==", op_eq },
++ { "!=", op_ne } } },
++ { eval_unary, { { "<=", op_le },
++ { ">=", op_ge },
++ { "<", op_lt },
++ { ">", op_gt } } }
++};
++
++/*
++ * Function for evaluating the innermost parts of expressions,
++ * viz. !expr (expr) defined(symbol) symbol number
++ * We reset the keepthis flag when we find a non-constant subexpression.
++ */
++static Linetype
++eval_unary(const struct ops *ops, int *valp, const char **cpp)
++{
++ const char *cp;
++ char *ep;
++ int sym;
++
++ cp = skipcomment(*cpp);
++ if (*cp == '!') {
++ debug("eval%d !", ops - eval_ops);
++ cp++;
++ if (eval_unary(ops, valp, &cp) == LT_IF)
++ return (LT_IF);
++ *valp = !*valp;
++ } else if (*cp == '(') {
++ cp++;
++ debug("eval%d (", ops - eval_ops);
++ if (eval_table(eval_ops, valp, &cp) == LT_IF)
++ return (LT_IF);
++ cp = skipcomment(cp);
++ if (*cp++ != ')')
++ return (LT_IF);
++ } else if (isdigit((unsigned char)*cp)) {
++ debug("eval%d number", ops - eval_ops);
++ *valp = strtol(cp, &ep, 0);
++ cp = skipsym(cp);
++ } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
++ cp = skipcomment(cp+7);
++ debug("eval%d defined", ops - eval_ops);
++ if (*cp++ != '(')
++ return (LT_IF);
++ cp = skipcomment(cp);
++ sym = findsym(cp);
++ if (sym < 0)
++ return (LT_IF);
++ *valp = (value[sym] != NULL);
++ cp = skipsym(cp);
++ cp = skipcomment(cp);
++ if (*cp++ != ')')
++ return (LT_IF);
++ keepthis = false;
++ } else if (!endsym(*cp)) {
++ debug("eval%d symbol", ops - eval_ops);
++ sym = findsym(cp);
++ if (sym < 0)
++ return (LT_IF);
++ if (value[sym] == NULL)
++ *valp = 0;
++ else {
++ *valp = strtol(value[sym], &ep, 0);
++ if (*ep != '\0' || ep == value[sym])
++ return (LT_IF);
++ }
++ cp = skipsym(cp);
++ keepthis = false;
++ } else {
++ debug("eval%d bad expr", ops - eval_ops);
++ return (LT_IF);
++ }
++
++ *cpp = cp;
++ debug("eval%d = %d", ops - eval_ops, *valp);
++ return (*valp ? LT_TRUE : LT_FALSE);
++}
++
++/*
++ * Table-driven evaluation of binary operators.
++ */
++static Linetype
++eval_table(const struct ops *ops, int *valp, const char **cpp)
++{
++ const struct op *op;
++ const char *cp;
++ int val;
++
++ debug("eval%d", ops - eval_ops);
++ cp = *cpp;
++ if (ops->inner(ops+1, valp, &cp) == LT_IF)
++ return (LT_IF);
++ for (;;) {
++ cp = skipcomment(cp);
++ for (op = ops->op; op->str != NULL; op++)
++ if (strncmp(cp, op->str, strlen(op->str)) == 0)
++ break;
++ if (op->str == NULL)
++ break;
++ cp += strlen(op->str);
++ debug("eval%d %s", ops - eval_ops, op->str);
++ if (ops->inner(ops+1, &val, &cp) == LT_IF)
++ return (LT_IF);
++ *valp = op->fn(*valp, val);
++ }
++
++ *cpp = cp;
++ debug("eval%d = %d", ops - eval_ops, *valp);
++ return (*valp ? LT_TRUE : LT_FALSE);
++}
++
++/*
++ * Evaluate the expression on a #if or #elif line. If we can work out
++ * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we
++ * return just a generic LT_IF.
++ */
++static Linetype
++ifeval(const char **cpp)
++{
++ int ret;
++ int val;
++
++ debug("eval %s", *cpp);
++ keepthis = killconsts ? false : true;
++ ret = eval_table(eval_ops, &val, cpp);
++ debug("eval = %d", val);
++ return (keepthis ? LT_IF : ret);
++}
++
++/*
++ * Skip over comments, strings, and character literals and stop at the
++ * next character position that is not whitespace. Between calls we keep
++ * the comment state in the global variable incomment, and we also adjust
++ * the global variable linestate when we see a newline.
++ * XXX: doesn't cope with the buffer splitting inside a state transition.
++ */
++static const char *
++skipcomment(const char *cp)
++{
++ if (text || ignoring[depth]) {
++ for (; isspace((unsigned char)*cp); cp++)
++ if (*cp == '\n')
++ linestate = LS_START;
++ return (cp);
++ }
++ while (*cp != '\0')
++ /* don't reset to LS_START after a line continuation */
++ if (strncmp(cp, "\\\n", 2) == 0)
++ cp += 2;
++ else switch (incomment) {
++ case NO_COMMENT:
++ if (strncmp(cp, "/\\\n", 3) == 0) {
++ incomment = STARTING_COMMENT;
++ cp += 3;
++ } else if (strncmp(cp, "/*", 2) == 0) {
++ incomment = C_COMMENT;
++ cp += 2;
++ } else if (strncmp(cp, "//", 2) == 0) {
++ incomment = CXX_COMMENT;
++ cp += 2;
++ } else if (strncmp(cp, "\'", 1) == 0) {
++ incomment = CHAR_LITERAL;
++ linestate = LS_DIRTY;
++ cp += 1;
++ } else if (strncmp(cp, "\"", 1) == 0) {
++ incomment = STRING_LITERAL;
++ linestate = LS_DIRTY;
++ cp += 1;
++ } else if (strncmp(cp, "\n", 1) == 0) {
++ linestate = LS_START;
++ cp += 1;
++ } else if (strchr(" \t", *cp) != NULL) {
++ cp += 1;
++ } else
++ return (cp);
++ continue;
++ case CXX_COMMENT:
++ if (strncmp(cp, "\n", 1) == 0) {
++ incomment = NO_COMMENT;
++ linestate = LS_START;
++ }
++ cp += 1;
++ continue;
++ case CHAR_LITERAL:
++ case STRING_LITERAL:
++ if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
++ (incomment == STRING_LITERAL && cp[0] == '\"')) {
++ incomment = NO_COMMENT;
++ cp += 1;
++ } else if (cp[0] == '\\') {
++ if (cp[1] == '\0')
++ cp += 1;
++ else
++ cp += 2;
++ } else if (strncmp(cp, "\n", 1) == 0) {
++ if (incomment == CHAR_LITERAL)
++ error("unterminated char literal");
++ else
++ error("unterminated string literal");
++ } else
++ cp += 1;
++ continue;
++ case C_COMMENT:
++ if (strncmp(cp, "*\\\n", 3) == 0) {
++ incomment = FINISHING_COMMENT;
++ cp += 3;
++ } else if (strncmp(cp, "*/", 2) == 0) {
++ incomment = NO_COMMENT;
++ cp += 2;
++ } else
++ cp += 1;
++ continue;
++ case STARTING_COMMENT:
++ if (*cp == '*') {
++ incomment = C_COMMENT;
++ cp += 1;
++ } else if (*cp == '/') {
++ incomment = CXX_COMMENT;
++ cp += 1;
++ } else {
++ incomment = NO_COMMENT;
++ linestate = LS_DIRTY;
++ }
++ continue;
++ case FINISHING_COMMENT:
++ if (*cp == '/') {
++ incomment = NO_COMMENT;
++ cp += 1;
++ } else
++ incomment = C_COMMENT;
++ continue;
++ default:
++ abort(); /* bug */
++ }
++ return (cp);
++}
++
++/*
++ * Skip over an identifier.
++ */
++static const char *
++skipsym(const char *cp)
++{
++ while (!endsym(*cp))
++ ++cp;
++ return (cp);
++}
++
++/*
++ * Look for the symbol in the symbol table. If is is found, we return
++ * the symbol table index, else we return -1.
++ */
++static int
++findsym(const char *str)
++{
++ const char *cp;
++ int symind;
++
++ cp = skipsym(str);
++ if (cp == str)
++ return (-1);
++ if (symlist) {
++ printf("%.*s\n", (int)(cp-str), str);
++ /* we don't care about the value of the symbol */
++ return (0);
++ }
++ for (symind = 0; symind < nsyms; ++symind) {
++ if (strlcmp(symname[symind], str, cp-str) == 0) {
++ debug("findsym %s %s", symname[symind],
++ value[symind] ? value[symind] : "");
++ return (symind);
++ }
++ }
++ return (-1);
++}
++
++/*
++ * Add a symbol to the symbol table.
++ */
++static void
++addsym(bool ignorethis, bool definethis, char *sym)
++{
++ int symind;
++ char *val;
++
++ symind = findsym(sym);
++ if (symind < 0) {
++ if (nsyms >= MAXSYMS)
++ errx(2, "too many symbols");
++ symind = nsyms++;
++ }
++ symname[symind] = sym;
++ ignore[symind] = ignorethis;
++ val = sym + (skipsym(sym) - sym);
++ if (definethis) {
++ if (*val == '=') {
++ value[symind] = val+1;
++ *val = '\0';
++ } else if (*val == '\0')
++ value[symind] = "";
++ else
++ usage();
++ } else {
++ if (*val != '\0')
++ usage();
++ value[symind] = NULL;
++ }
++}
++
++/*
++ * Compare s with n characters of t.
++ * The same as strncmp() except that it checks that s[n] == '\0'.
++ */
++static int
++strlcmp(const char *s, const char *t, size_t n)
++{
++ while (n-- && *t != '\0')
++ if (*s != *t)
++ return ((unsigned char)*s - (unsigned char)*t);
++ else
++ ++s, ++t;
++ return ((unsigned char)*s);
++}
++
++/*
++ * Diagnostics.
++ */
++static void
++debug(const char *msg, ...)
++{
++ va_list ap;
++
++ if (debugging) {
++ va_start(ap, msg);
++ vwarnx(msg, ap);
++ va_end(ap);
++ }
++}
++
++static void
++error(const char *msg)
++{
++ if (depth == 0)
++ warnx("%s: %d: %s", filename, linenum, msg);
++ else
++ warnx("%s: %d: %s (#if line %d depth %d)",
++ filename, linenum, msg, stifline[depth], depth);
++ errx(2, "output may be truncated");
++}
+diff --git a/security/Kconfig b/security/Kconfig
+index 67785df..460e5c9 100644
+--- a/security/Kconfig
++++ b/security/Kconfig
+@@ -93,18 +93,6 @@ config SECURITY_ROOTPLUG
+
+ If you are unsure how to answer this question, answer N.
+
+-config SECURITY_SECLVL
+- tristate "BSD Secure Levels"
+- depends on SECURITY
+- select CRYPTO
+- select CRYPTO_SHA1
+- help
+- Implements BSD Secure Levels as an LSM. See
+- <file:Documentation/seclvl.txt> for instructions on how to use this
+- module.
+-
+- If you are unsure how to answer this question, answer N.
+-
+ source security/selinux/Kconfig
+
+ endmenu
+diff --git a/security/Makefile b/security/Makefile
+index 8cbbf2f..ef87df2 100644
+--- a/security/Makefile
++++ b/security/Makefile
+@@ -16,4 +16,3 @@ obj-$(CONFIG_SECURITY) += security.o d
+ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
+ obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
+ obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+-obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
+diff --git a/security/commoncap.c b/security/commoncap.c
+index f50fc29..5a5ef5c 100644
+--- a/security/commoncap.c
++++ b/security/commoncap.c
+@@ -169,7 +169,7 @@ void cap_bprm_apply_creds (struct linux_
+ /* For init, we want to retain the capabilities set
+ * in the init_task struct. Thus we skip the usual
+ * capability rules */
+- if (current->pid != 1) {
++ if (!is_init(current)) {
+ current->cap_permitted = new_permitted;
+ current->cap_effective =
+ cap_intersect (new_permitted, bprm->cap_effective);
+diff --git a/security/dummy.c b/security/dummy.c
+index 58c6d39..43874c1 100644
+--- a/security/dummy.c
++++ b/security/dummy.c
+@@ -709,10 +709,10 @@ static int dummy_socket_create (int fami
+ return 0;
+ }
+
+-static void dummy_socket_post_create (struct socket *sock, int family, int type,
+- int protocol, int kern)
++static int dummy_socket_post_create (struct socket *sock, int family, int type,
++ int protocol, int kern)
+ {
+- return;
++ return 0;
+ }
+
+ static int dummy_socket_bind (struct socket *sock, struct sockaddr *address,
+@@ -805,14 +805,38 @@ static inline void dummy_sk_free_securit
+ {
+ }
+
+-static unsigned int dummy_sk_getsid(struct sock *sk, struct flowi *fl, u8 dir)
++static inline void dummy_sk_clone_security (const struct sock *sk, struct sock *newsk)
++{
++}
++
++static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid)
++{
++}
++
++static inline void dummy_sock_graft(struct sock* sk, struct socket *parent)
++{
++}
++
++static inline int dummy_inet_conn_request(struct sock *sk,
++ struct sk_buff *skb, struct request_sock *req)
+ {
+ return 0;
+ }
++
++static inline void dummy_inet_csk_clone(struct sock *newsk,
++ const struct request_sock *req)
++{
++}
++
++static inline void dummy_req_classify_flow(const struct request_sock *req,
++ struct flowi *fl)
++{
++}
+ #endif /* CONFIG_SECURITY_NETWORK */
+
+ #ifdef CONFIG_SECURITY_NETWORK_XFRM
+-static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx)
++static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp,
++ struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk)
+ {
+ return 0;
+ }
+@@ -831,7 +855,8 @@ static int dummy_xfrm_policy_delete_secu
+ return 0;
+ }
+
+-static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx)
++static int dummy_xfrm_state_alloc_security(struct xfrm_state *x,
++ struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid)
+ {
+ return 0;
+ }
+@@ -849,6 +874,24 @@ static int dummy_xfrm_policy_lookup(stru
+ {
+ return 0;
+ }
++
++static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x,
++ struct xfrm_policy *xp, struct flowi *fl)
++{
++ return 1;
++}
++
++static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
++ struct xfrm_policy *xp)
++{
++ return 1;
++}
++
++static int dummy_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall)
++{
++ return 0;
++}
++
+ #endif /* CONFIG_SECURITY_NETWORK_XFRM */
+ static int dummy_register_security (const char *name, struct security_operations *ops)
+ {
+@@ -1060,7 +1103,12 @@ void security_fixup_ops (struct security
+ set_to_dummy_if_null(ops, socket_getpeersec_dgram);
+ set_to_dummy_if_null(ops, sk_alloc_security);
+ set_to_dummy_if_null(ops, sk_free_security);
+- set_to_dummy_if_null(ops, sk_getsid);
++ set_to_dummy_if_null(ops, sk_clone_security);
++ set_to_dummy_if_null(ops, sk_getsecid);
++ set_to_dummy_if_null(ops, sock_graft);
++ set_to_dummy_if_null(ops, inet_conn_request);
++ set_to_dummy_if_null(ops, inet_csk_clone);
++ set_to_dummy_if_null(ops, req_classify_flow);
+ #endif /* CONFIG_SECURITY_NETWORK */
+ #ifdef CONFIG_SECURITY_NETWORK_XFRM
+ set_to_dummy_if_null(ops, xfrm_policy_alloc_security);
+@@ -1071,6 +1119,9 @@ void security_fixup_ops (struct security
+ set_to_dummy_if_null(ops, xfrm_state_free_security);
+ set_to_dummy_if_null(ops, xfrm_state_delete_security);
+ set_to_dummy_if_null(ops, xfrm_policy_lookup);
++ set_to_dummy_if_null(ops, xfrm_state_pol_flow_match);
++ set_to_dummy_if_null(ops, xfrm_flow_state_match);
++ set_to_dummy_if_null(ops, xfrm_decode_session);
+ #endif /* CONFIG_SECURITY_NETWORK_XFRM */
+ #ifdef CONFIG_KEYS
+ set_to_dummy_if_null(ops, key_alloc);
+diff --git a/security/inode.c b/security/inode.c
+index 47eb634..9b16e14 100644
+--- a/security/inode.c
++++ b/security/inode.c
+@@ -44,8 +44,8 @@ static ssize_t default_write_file(struct
+
+ static int default_open(struct inode *inode, struct file *file)
+ {
+- if (inode->u.generic_ip)
+- file->private_data = inode->u.generic_ip;
++ if (inode->i_private)
++ file->private_data = inode->i_private;
+
+ return 0;
+ }
+@@ -64,7 +64,6 @@ static struct inode *get_inode(struct su
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+- inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+@@ -79,7 +78,7 @@ static struct inode *get_inode(struct su
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ break;
+ }
+ }
+@@ -112,7 +111,7 @@ static int mkdir(struct inode *dir, stru
+ mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+ res = mknod(dir, dentry, mode, 0);
+ if (!res)
+- dir->i_nlink++;
++ inc_nlink(dir);
+ return res;
+ }
+
+@@ -194,7 +193,7 @@ static int create_by_name(const char *na
+ * directory dentry if set. If this paramater is NULL, then the
+ * file will be created in the root of the securityfs filesystem.
+ * @data: a pointer to something that the caller will want to get to later
+- * on. The inode.u.generic_ip pointer will point to this value on
++ * on. The inode.i_private pointer will point to this value on
+ * the open() call.
+ * @fops: a pointer to a struct file_operations that should be used for
+ * this file.
+@@ -240,7 +239,7 @@ struct dentry *securityfs_create_file(co
+ if (fops)
+ dentry->d_inode->i_fop = fops;
+ if (data)
+- dentry->d_inode->u.generic_ip = data;
++ dentry->d_inode->i_private = data;
+ }
+ exit:
+ return dentry;
+diff --git a/security/seclvl.c b/security/seclvl.c
+deleted file mode 100644
+index c26dd7d..0000000
+--- a/security/seclvl.c
++++ /dev/null
+@@ -1,669 +0,0 @@
+-/**
+- * BSD Secure Levels LSM
+- *
+- * Maintainers:
+- * Michael A. Halcrow <mike at halcrow.us>
+- * Serge Hallyn <hallyn at cs.wm.edu>
+- *
+- * Copyright (c) 2001 WireX Communications, Inc <chris at wirex.com>
+- * Copyright (c) 2001 Greg Kroah-Hartman <greg at kroah.com>
+- * Copyright (c) 2002 International Business Machines <robb at austin.ibm.com>
+- * Copyright (c) 2006 Davi E. M. Arnaut <davi.arnaut at gmail.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/moduleparam.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/security.h>
+-#include <linux/netlink.h>
+-#include <linux/fs.h>
+-#include <linux/namei.h>
+-#include <linux/mount.h>
+-#include <linux/capability.h>
+-#include <linux/time.h>
+-#include <linux/proc_fs.h>
+-#include <linux/kobject.h>
+-#include <linux/crypto.h>
+-#include <asm/scatterlist.h>
+-#include <linux/scatterlist.h>
+-#include <linux/gfp.h>
+-#include <linux/sysfs.h>
+-
+-#define SHA1_DIGEST_SIZE 20
+-
+-/**
+- * Module parameter that defines the initial secure level.
+- *
+- * When built as a module, it defaults to seclvl 1, which is the
+- * behavior of BSD secure levels. Note that this default behavior
+- * wrecks havoc on a machine when the seclvl module is compiled into
+- * the kernel. In that case, we default to seclvl 0.
+- */
+-#ifdef CONFIG_SECURITY_SECLVL_MODULE
+-static int initlvl = 1;
+-#else
+-static int initlvl;
+-#endif
+-module_param(initlvl, int, 0);
+-MODULE_PARM_DESC(initlvl, "Initial secure level (defaults to 1)");
+-
+-/* Module parameter that defines the verbosity level */
+-static int verbosity;
+-module_param(verbosity, int, 0);
+-MODULE_PARM_DESC(verbosity, "Initial verbosity level (0 or 1; defaults to "
+- "0, which is Quiet)");
+-
+-/**
+- * Optional password which can be passed in to bring seclvl to 0
+- * (i.e., for halt/reboot). Defaults to NULL (the passwd attribute
+- * file will not be registered in sysfs).
+- *
+- * This gets converted to its SHA1 hash when stored. It's probably
+- * not a good idea to use this parameter when loading seclvl from a
+- * script; use sha1_passwd instead.
+- */
+-
+-#define MAX_PASSWD_SIZE 32
+-static char passwd[MAX_PASSWD_SIZE];
+-module_param_string(passwd, passwd, sizeof(passwd), 0);
+-MODULE_PARM_DESC(passwd,
+- "Plaintext of password that sets seclvl=0 when written to "
+- "(sysfs mount point)/seclvl/passwd\n");
+-
+-/**
+- * SHA1 hashed version of the optional password which can be passed in
+- * to bring seclvl to 0 (i.e., for halt/reboot). Must be in
+- * hexadecimal format (40 characters). Defaults to NULL (the passwd
+- * attribute file will not be registered in sysfs).
+- *
+- * Use the sha1sum utility to generate the SHA1 hash of a password:
+- *
+- * echo -n "secret" | sha1sum
+- */
+-#define MAX_SHA1_PASSWD 41
+-static char sha1_passwd[MAX_SHA1_PASSWD];
+-module_param_string(sha1_passwd, sha1_passwd, sizeof(sha1_passwd), 0);
+-MODULE_PARM_DESC(sha1_passwd,
+- "SHA1 hash (40 hexadecimal characters) of password that "
+- "sets seclvl=0 when plaintext password is written to "
+- "(sysfs mount point)/seclvl/passwd\n");
+-
+-static int hideHash = 1;
+-module_param(hideHash, int, 0);
+-MODULE_PARM_DESC(hideHash, "When set to 0, reading seclvl/passwd from sysfs "
+- "will return the SHA1-hashed value of the password that "
+- "lowers the secure level to 0.\n");
+-
+-#define MY_NAME "seclvl"
+-
+-/**
+- * This time-limits log writes to one per second.
+- */
+-#define seclvl_printk(verb, type, fmt, arg...) \
+- do { \
+- if (verbosity >= verb) { \
+- static unsigned long _prior; \
+- unsigned long _now = jiffies; \
+- if ((_now - _prior) > HZ) { \
+- printk(type "%s: %s: " fmt, \
+- MY_NAME, __FUNCTION__ , \
+- ## arg); \
+- _prior = _now; \
+- } \
+- } \
+- } while (0)
+-
+-/**
+- * The actual security level. Ranges between -1 and 2 inclusive.
+- */
+-static int seclvl;
+-
+-/**
+- * flag to keep track of how we were registered
+- */
+-static int secondary;
+-
+-/**
+- * Verifies that the requested secure level is valid, given the current
+- * secure level.
+- */
+-static int seclvl_sanity(int reqlvl)
+-{
+- if ((reqlvl < -1) || (reqlvl > 2)) {
+- seclvl_printk(1, KERN_WARNING, "Attempt to set seclvl out of "
+- "range: [%d]\n", reqlvl);
+- return -EINVAL;
+- }
+- if ((seclvl == 0) && (reqlvl == -1))
+- return 0;
+- if (reqlvl < seclvl) {
+- seclvl_printk(1, KERN_WARNING, "Attempt to lower seclvl to "
+- "[%d]\n", reqlvl);
+- return -EPERM;
+- }
+- return 0;
+-}
+-
+-/**
+- * security level advancement rules:
+- * Valid levels are -1 through 2, inclusive.
+- * From -1, stuck. [ in case compiled into kernel ]
+- * From 0 or above, can only increment.
+- */
+-static void do_seclvl_advance(void *data, u64 val)
+-{
+- int ret;
+- int newlvl = (int)val;
+-
+- ret = seclvl_sanity(newlvl);
+- if (ret)
+- return;
+-
+- if (newlvl > 2) {
+- seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
+- "[%d]\n", newlvl);
+- return;
+- }
+- if (seclvl == -1) {
+- seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
+- "seclvl [%d]\n", seclvl);
+- return;
+- }
+- seclvl = newlvl; /* would it be more "correct" to set *data? */
+- return;
+-}
+-
+-static u64 seclvl_int_get(void *data)
+-{
+- return *(int *)data;
+-}
+-
+-DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%lld\n");
+-
+-static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
+-
+-/**
+- * Converts a block of plaintext of into its SHA1 hashed value.
+- *
+- * It would be nice if crypto had a wrapper to do this for us linear
+- * people...
+- */
+-static int
+-plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
+-{
+- struct crypto_tfm *tfm;
+- struct scatterlist sg;
+- if (len > PAGE_SIZE) {
+- seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
+- "characters). Largest possible is %lu "
+- "bytes.\n", len, PAGE_SIZE);
+- return -EINVAL;
+- }
+- tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
+- if (tfm == NULL) {
+- seclvl_printk(0, KERN_ERR,
+- "Failed to load transform for SHA1\n");
+- return -EINVAL;
+- }
+- sg_init_one(&sg, (u8 *)plaintext, len);
+- crypto_digest_init(tfm);
+- crypto_digest_update(tfm, &sg, 1);
+- crypto_digest_final(tfm, hash);
+- crypto_free_tfm(tfm);
+- return 0;
+-}
+-
+-/**
+- * Called whenever the user writes to the sysfs passwd handle to this kernel
+- * object. It hashes the password and compares the hashed results.
+- */
+-static ssize_t
+-passwd_write_file(struct file * file, const char __user * buf,
+- size_t count, loff_t *ppos)
+-{
+- char *p;
+- int len;
+- unsigned char tmp[SHA1_DIGEST_SIZE];
+-
+- if (!*passwd && !*sha1_passwd) {
+- seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
+- "seclvl module, but neither a plain text "
+- "password nor a SHA1 hashed password was "
+- "passed in as a module parameter! This is a "
+- "bug, since it should not be possible to be in "
+- "this part of the module; please tell a "
+- "maintainer about this event.\n");
+- return -EINVAL;
+- }
+-
+- if (count >= PAGE_SIZE)
+- return -EINVAL;
+- if (*ppos != 0)
+- return -EINVAL;
+- p = kmalloc(count, GFP_KERNEL);
+- if (!p)
+- return -ENOMEM;
+- len = -EFAULT;
+- if (copy_from_user(p, buf, count))
+- goto out;
+-
+- len = count;
+- /* ``echo "secret" > seclvl/passwd'' includes a newline */
+- if (p[len - 1] == '\n')
+- len--;
+- /* Hash the password, then compare the hashed values */
+- if ((len = plaintext_to_sha1(tmp, p, len))) {
+- seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
+- "[%d]\n", len);
+- goto out;
+- }
+-
+- len = -EPERM;
+- if (memcmp(hashedPassword, tmp, SHA1_DIGEST_SIZE))
+- goto out;
+-
+- seclvl_printk(0, KERN_INFO,
+- "Password accepted; seclvl reduced to 0.\n");
+- seclvl = 0;
+- len = count;
+-
+-out:
+- kfree (p);
+- return len;
+-}
+-
+-static struct file_operations passwd_file_ops = {
+- .write = passwd_write_file,
+-};
+-
+-/**
+- * Explicitely disallow ptrace'ing the init process.
+- */
+-static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
+-{
+- if (seclvl >= 0 && child->pid == 1) {
+- seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
+- "the init process dissallowed in "
+- "secure level %d\n", seclvl);
+- return -EPERM;
+- }
+- return 0;
+-}
+-
+-/**
+- * Capability checks for seclvl. The majority of the policy
+- * enforcement for seclvl takes place here.
+- */
+-static int seclvl_capable(struct task_struct *tsk, int cap)
+-{
+- int rc = 0;
+-
+- /* init can do anything it wants */
+- if (tsk->pid == 1)
+- return 0;
+-
+- if (seclvl > 0) {
+- rc = -EPERM;
+-
+- if (cap == CAP_LINUX_IMMUTABLE)
+- seclvl_printk(1, KERN_WARNING, "Attempt to modify "
+- "the IMMUTABLE and/or APPEND extended "
+- "attribute on a file with the IMMUTABLE "
+- "and/or APPEND extended attribute set "
+- "denied in seclvl [%d]\n", seclvl);
+- else if (cap == CAP_SYS_RAWIO)
+- seclvl_printk(1, KERN_WARNING, "Attempt to perform "
+- "raw I/O while in secure level [%d] "
+- "denied\n", seclvl);
+- else if (cap == CAP_NET_ADMIN)
+- seclvl_printk(1, KERN_WARNING, "Attempt to perform "
+- "network administrative task while "
+- "in secure level [%d] denied\n", seclvl);
+- else if (cap == CAP_SETUID)
+- seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
+- "while in secure level [%d] denied\n",
+- seclvl);
+- else if (cap == CAP_SETGID)
+- seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
+- "while in secure level [%d] denied\n",
+- seclvl);
+- else if (cap == CAP_SYS_MODULE)
+- seclvl_printk(1, KERN_WARNING, "Attempt to perform "
+- "a module operation while in secure "
+- "level [%d] denied\n", seclvl);
+- else
+- rc = 0;
+- }
+-
+- if (!rc) {
+- if (!(cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0))
+- rc = -EPERM;
+- }
+-
+- if (rc)
+- seclvl_printk(1, KERN_WARNING, "Capability denied\n");
+-
+- return rc;
+-}
+-
+-/**
+- * Disallow reversing the clock in seclvl > 1
+- */
+-static int seclvl_settime(struct timespec *tv, struct timezone *tz)
+-{
+- if (tv && seclvl > 1) {
+- struct timespec now;
+- now = current_kernel_time();
+- if (tv->tv_sec < now.tv_sec ||
+- (tv->tv_sec == now.tv_sec && tv->tv_nsec < now.tv_nsec)) {
+- seclvl_printk(1, KERN_WARNING, "Attempt to decrement "
+- "time in secure level %d denied: "
+- "current->pid = [%d], "
+- "current->group_leader->pid = [%d]\n",
+- seclvl, current->pid,
+- current->group_leader->pid);
+- return -EPERM;
+- } /* if attempt to decrement time */
+- } /* if seclvl > 1 */
+- return 0;
+-}
+-
+-/* claim the blockdev to exclude mounters, release on file close */
+-static int seclvl_bd_claim(struct inode *inode)
+-{
+- int holder;
+- struct block_device *bdev = NULL;
+- dev_t dev = inode->i_rdev;
+- bdev = open_by_devnum(dev, FMODE_WRITE);
+- if (bdev) {
+- if (bd_claim(bdev, &holder)) {
+- blkdev_put(bdev);
+- return -EPERM;
+- }
+- /* claimed, mark it to release on close */
+- inode->i_security = current;
+- }
+- return 0;
+-}
+-
+-/* release the blockdev if you claimed it */
+-static void seclvl_bd_release(struct inode *inode)
+-{
+- if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
+- struct block_device *bdev = inode->i_bdev;
+- if (bdev) {
+- bd_release(bdev);
+- blkdev_put(bdev);
+- inode->i_security = NULL;
+- }
+- }
+-}
+-
+-/**
+- * Security for writes to block devices is regulated by this seclvl
+- * function. Deny all writes to block devices in seclvl 2. In
+- * seclvl 1, we only deny writes to *mounted* block devices.
+- */
+-static int
+-seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
+-{
+- if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
+- switch (seclvl) {
+- case 2:
+- seclvl_printk(1, KERN_WARNING, "Write to block device "
+- "denied in secure level [%d]\n", seclvl);
+- return -EPERM;
+- case 1:
+- if (seclvl_bd_claim(inode)) {
+- seclvl_printk(1, KERN_WARNING,
+- "Write to mounted block device "
+- "denied in secure level [%d]\n",
+- seclvl);
+- return -EPERM;
+- }
+- }
+- }
+- return 0;
+-}
+-
+-/**
+- * The SUID and SGID bits cannot be set in seclvl >= 1
+- */
+-static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+-{
+- if (seclvl > 0) {
+- if (iattr->ia_valid & ATTR_MODE)
+- if (iattr->ia_mode & S_ISUID ||
+- iattr->ia_mode & S_ISGID) {
+- seclvl_printk(1, KERN_WARNING, "Attempt to "
+- "modify SUID or SGID bit "
+- "denied in seclvl [%d]\n",
+- seclvl);
+- return -EPERM;
+- }
+- }
+- return 0;
+-}
+-
+-/* release busied block devices */
+-static void seclvl_file_free_security(struct file *filp)
+-{
+- struct dentry *dentry = filp->f_dentry;
+-
+- if (dentry)
+- seclvl_bd_release(dentry->d_inode);
+-}
+-
+-/**
+- * Cannot unmount in secure level 2
+- */
+-static int seclvl_umount(struct vfsmount *mnt, int flags)
+-{
+- if (current->pid != 1 && seclvl == 2) {
+- seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
+- "level %d\n", seclvl);
+- return -EPERM;
+- }
+- return 0;
+-}
+-
+-static struct security_operations seclvl_ops = {
+- .ptrace = seclvl_ptrace,
+- .capable = seclvl_capable,
+- .inode_permission = seclvl_inode_permission,
+- .inode_setattr = seclvl_inode_setattr,
+- .file_free_security = seclvl_file_free_security,
+- .settime = seclvl_settime,
+- .sb_umount = seclvl_umount,
+-};
+-
+-/**
+- * Process the password-related module parameters
+- */
+-static int processPassword(void)
+-{
+- int rc = 0;
+- if (*passwd) {
+- char *p;
+-
+- if (*sha1_passwd) {
+- seclvl_printk(0, KERN_ERR, "Error: Both "
+- "passwd and sha1_passwd "
+- "were set, but they are mutually "
+- "exclusive.\n");
+- return -EINVAL;
+- }
+-
+- p = kstrdup(passwd, GFP_KERNEL);
+- if (p == NULL)
+- return -ENOMEM;
+-
+- if ((rc = plaintext_to_sha1(hashedPassword, p, strlen(p))))
+- seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
+- "in kernel\n");
+-
+- kfree (p);
+- /* All static data goes to the BSS, which zero's the
+- * plaintext password out for us. */
+- } else if (*sha1_passwd) { // Base 16
+- int i;
+- i = strlen(sha1_passwd);
+- if (i != (SHA1_DIGEST_SIZE * 2)) {
+- seclvl_printk(0, KERN_ERR, "Received [%d] bytes; "
+- "expected [%d] for the hexadecimal "
+- "representation of the SHA1 hash of "
+- "the password.\n",
+- i, (SHA1_DIGEST_SIZE * 2));
+- return -EINVAL;
+- }
+- while ((i -= 2) + 2) {
+- unsigned char tmp;
+- tmp = sha1_passwd[i + 2];
+- sha1_passwd[i + 2] = '\0';
+- hashedPassword[i / 2] = (unsigned char)
+- simple_strtol(&sha1_passwd[i], NULL, 16);
+- sha1_passwd[i + 2] = tmp;
+- }
+- }
+- return rc;
+-}
+-
+-/**
+- * securityfs registrations
+- */
+-struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
+-
+-static int seclvlfs_register(void)
+-{
+- int rc = 0;
+-
+- dir_ino = securityfs_create_dir("seclvl", NULL);
+-
+- if (IS_ERR(dir_ino))
+- return PTR_ERR(dir_ino);
+-
+- seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
+- dir_ino, &seclvl, &seclvl_file_ops);
+- if (IS_ERR(seclvl_ino)) {
+- rc = PTR_ERR(seclvl_ino);
+- goto out_deldir;
+- }
+- if (*passwd || *sha1_passwd) {
+- passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
+- dir_ino, NULL, &passwd_file_ops);
+- if (IS_ERR(passwd_ino)) {
+- rc = PTR_ERR(passwd_ino);
+- goto out_delf;
+- }
+- }
+- return rc;
+-
+-out_delf:
+- securityfs_remove(seclvl_ino);
+-
+-out_deldir:
+- securityfs_remove(dir_ino);
+-
+- return rc;
+-}
+-
+-static void seclvlfs_unregister(void)
+-{
+- securityfs_remove(seclvl_ino);
+-
+- if (*passwd || *sha1_passwd)
+- securityfs_remove(passwd_ino);
+-
+- securityfs_remove(dir_ino);
+-}
+-
+-/**
+- * Initialize the seclvl module.
+- */
+-static int __init seclvl_init(void)
+-{
+- int rc = 0;
+- static char once;
+-
+- if (verbosity < 0 || verbosity > 1) {
+- printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 "
+- "are valid values\n", verbosity);
+- rc = -EINVAL;
+- goto exit;
+- }
+- if (initlvl < -1 || initlvl > 2) {
+- seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
+- "[%d].\n", initlvl);
+- rc = -EINVAL;
+- goto exit;
+- }
+- seclvl = initlvl;
+- if ((rc = processPassword())) {
+- seclvl_printk(0, KERN_ERR, "Error processing the password "
+- "module parameter(s): rc = [%d]\n", rc);
+- goto exit;
+- }
+-
+- if ((rc = seclvlfs_register())) {
+- seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
+- goto exit;
+- }
+- /* register ourselves with the security framework */
+- if (register_security(&seclvl_ops)) {
+- seclvl_printk(0, KERN_ERR,
+- "seclvl: Failure registering with the "
+- "kernel.\n");
+- /* try registering with primary module */
+- rc = mod_reg_security(MY_NAME, &seclvl_ops);
+- if (rc) {
+- seclvl_printk(0, KERN_ERR, "seclvl: Failure "
+- "registering with primary security "
+- "module.\n");
+- seclvlfs_unregister();
+- goto exit;
+- } /* if primary module registered */
+- secondary = 1;
+- } /* if we registered ourselves with the security framework */
+-
+- seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
+-
+- if (once) {
+- once = 1;
+- seclvl_printk(0, KERN_INFO, "seclvl is going away. It has been "
+- "buggy for ages. Also, be warned that "
+- "Securelevels are useless.");
+- }
+- exit:
+- if (rc)
+- printk(KERN_ERR "seclvl: Error during initialization: rc = "
+- "[%d]\n", rc);
+- return rc;
+-}
+-
+-/**
+- * Remove the seclvl module.
+- */
+-static void __exit seclvl_exit(void)
+-{
+- seclvlfs_unregister();
+-
+- if (secondary)
+- mod_unreg_security(MY_NAME, &seclvl_ops);
+- else if (unregister_security(&seclvl_ops))
+- seclvl_printk(0, KERN_INFO,
+- "seclvl: Failure unregistering with the "
+- "kernel\n");
+-}
+-
+-module_init(seclvl_init);
+-module_exit(seclvl_exit);
+-
+-MODULE_AUTHOR("Michael A. Halcrow <mike at halcrow.us>");
+-MODULE_DESCRIPTION("LSM implementation of the BSD Secure Levels");
+-MODULE_LICENSE("GPL");
+diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
+index 814ddc4..23b5104 100644
+--- a/security/selinux/Kconfig
++++ b/security/selinux/Kconfig
+@@ -112,7 +112,7 @@ config SECURITY_SELINUX_ENABLE_SECMARK_D
+ your distribution will provide these and enable the new controls
+ in the kernel they also distribute.
+
+- Note that this option can be overriden at boot with the
++ Note that this option can be overridden at boot with the
+ selinux_compat_net parameter, and after boot via
+ /selinux/compat_net. See Documentation/kernel-parameters.txt
+ for details on this parameter.
+@@ -122,5 +122,42 @@ config SECURITY_SELINUX_ENABLE_SECMARK_D
+ well as any conntrack helpers for protocols which you
+ wish to control.
+
+- If you are unsure what do do here, select N.
++ If you are unsure what to do here, select N.
++
++config SECURITY_SELINUX_POLICYDB_VERSION_MAX
++ bool "NSA SELinux maximum supported policy format version"
++ depends on SECURITY_SELINUX
++ default n
++ help
++ This option enables the maximum policy format version supported
++ by SELinux to be set to a particular value. This value is reported
++ to userspace via /selinux/policyvers and used at policy load time.
++ It can be adjusted downward to support legacy userland (init) that
++ does not correctly handle kernels that support newer policy versions.
++
++ Examples:
++ For the Fedora Core 3 or 4 Linux distributions, enable this option
++ and set the value via the next option. For Fedore Core 5 and later,
++ do not enable this option.
++
++ If you are unsure how to answer this question, answer N.
++
++config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
++ int "NSA SELinux maximum supported policy format version value"
++ depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
++ range 15 21
++ default 19
++ help
++ This option sets the value for the maximum policy format version
++ supported by SELinux.
++
++ Examples:
++ For Fedora Core 3, use 18.
++ For Fedora Core 4, use 19.
++
++ If you are unsure how to answer this question, look for the
++ policy format version supported by your policy toolchain, by
++ running 'checkpolicy -V'. Or look at what policy you have
++ installed under /etc/selinux/$SELINUXTYPE/policy, where
++ SELINUXTYPE is defined in your /etc/selinux/config.
+
+diff --git a/security/selinux/exports.c b/security/selinux/exports.c
+index 9d7737d..b6f9694 100644
+--- a/security/selinux/exports.c
++++ b/security/selinux/exports.c
+@@ -21,19 +21,10 @@
+ #include "security.h"
+ #include "objsec.h"
+
+-void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
++int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
+ {
+- struct task_security_struct *tsec = tsk->security;
+ if (selinux_enabled)
+- *ctxid = tsec->sid;
+- else
+- *ctxid = 0;
+-}
+-
+-int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen)
+-{
+- if (selinux_enabled)
+- return security_sid_to_context(ctxid, ctx, ctxlen);
++ return security_sid_to_context(sid, ctx, ctxlen);
+ else {
+ *ctx = NULL;
+ *ctxlen = 0;
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index 5d1b8c7..8ab5679 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -12,6 +12,8 @@
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris at redhat.com>
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * <dgoeddel at trustedcs.com>
++ * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
++ * Paul Moore, <paul.moore at hp.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,
+@@ -49,7 +51,6 @@
+ #include <net/ip.h> /* for sysctl_local_port_range[] */
+ #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
+ #include <asm/uaccess.h>
+-#include <asm/semaphore.h>
+ #include <asm/ioctls.h>
+ #include <linux/bitops.h>
+ #include <linux/interrupt.h>
+@@ -69,11 +70,13 @@
+ #include <linux/audit.h>
+ #include <linux/string.h>
+ #include <linux/selinux.h>
++#include <linux/mutex.h>
+
+ #include "avc.h"
+ #include "objsec.h"
+ #include "netif.h"
+ #include "xfrm.h"
++#include "selinux_netlabel.h"
+
+ #define XATTR_SELINUX_SUFFIX "selinux"
+ #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+@@ -182,7 +185,7 @@ static int inode_alloc_security(struct i
+ return -ENOMEM;
+
+ memset(isec, 0, sizeof(*isec));
+- init_MUTEX(&isec->sem);
++ mutex_init(&isec->lock);
+ INIT_LIST_HEAD(&isec->list);
+ isec->inode = inode;
+ isec->sid = SECINITSID_UNLABELED;
+@@ -239,7 +242,7 @@ static int superblock_alloc_security(str
+ if (!sbsec)
+ return -ENOMEM;
+
+- init_MUTEX(&sbsec->sem);
++ mutex_init(&sbsec->lock);
+ INIT_LIST_HEAD(&sbsec->list);
+ INIT_LIST_HEAD(&sbsec->isec_head);
+ spin_lock_init(&sbsec->isec_lock);
+@@ -269,17 +272,17 @@ static int sk_alloc_security(struct sock
+ {
+ struct sk_security_struct *ssec;
+
+- if (family != PF_UNIX)
+- return 0;
+-
+ ssec = kzalloc(sizeof(*ssec), priority);
+ if (!ssec)
+ return -ENOMEM;
+
+ ssec->sk = sk;
+ ssec->peer_sid = SECINITSID_UNLABELED;
++ ssec->sid = SECINITSID_UNLABELED;
+ sk->sk_security = ssec;
+
++ selinux_netlbl_sk_security_init(ssec, family);
++
+ return 0;
+ }
+
+@@ -287,9 +290,6 @@ static void sk_free_security(struct sock
+ {
+ struct sk_security_struct *ssec = sk->sk_security;
+
+- if (sk->sk_family != PF_UNIX)
+- return;
+-
+ sk->sk_security = NULL;
+ kfree(ssec);
+ }
+@@ -398,7 +398,7 @@ static int try_context_mount(struct supe
+ /* Standard string-based options. */
+ char *p, *options = data;
+
+- while ((p = strsep(&options, ",")) != NULL) {
++ while ((p = strsep(&options, "|")) != NULL) {
+ int token;
+ substring_t args[MAX_OPT_ARGS];
+
+@@ -594,7 +594,7 @@ static int superblock_doinit(struct supe
+ struct inode *inode = root->d_inode;
+ int rc = 0;
+
+- down(&sbsec->sem);
++ mutex_lock(&sbsec->lock);
+ if (sbsec->initialized)
+ goto out;
+
+@@ -689,7 +689,7 @@ next_inode:
+ }
+ spin_unlock(&sbsec->isec_lock);
+ out:
+- up(&sbsec->sem);
++ mutex_unlock(&sbsec->lock);
+ return rc;
+ }
+
+@@ -843,15 +843,13 @@ static int inode_doinit_with_dentry(stru
+ char *context = NULL;
+ unsigned len = 0;
+ int rc = 0;
+- int hold_sem = 0;
+
+ if (isec->initialized)
+ goto out;
+
+- down(&isec->sem);
+- hold_sem = 1;
++ mutex_lock(&isec->lock);
+ if (isec->initialized)
+- goto out;
++ goto out_unlock;
+
+ sbsec = inode->i_sb->s_security;
+ if (!sbsec->initialized) {
+@@ -862,7 +860,7 @@ static int inode_doinit_with_dentry(stru
+ if (list_empty(&isec->list))
+ list_add(&isec->list, &sbsec->isec_head);
+ spin_unlock(&sbsec->isec_lock);
+- goto out;
++ goto out_unlock;
+ }
+
+ switch (sbsec->behavior) {
+@@ -885,7 +883,7 @@ static int inode_doinit_with_dentry(stru
+ printk(KERN_WARNING "%s: no dentry for dev=%s "
+ "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id,
+ inode->i_ino);
+- goto out;
++ goto out_unlock;
+ }
+
+ len = INITCONTEXTLEN;
+@@ -893,7 +891,7 @@ static int inode_doinit_with_dentry(stru
+ if (!context) {
+ rc = -ENOMEM;
+ dput(dentry);
+- goto out;
++ goto out_unlock;
+ }
+ rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
+ context, len);
+@@ -903,7 +901,7 @@ static int inode_doinit_with_dentry(stru
+ NULL, 0);
+ if (rc < 0) {
+ dput(dentry);
+- goto out;
++ goto out_unlock;
+ }
+ kfree(context);
+ len = rc;
+@@ -911,7 +909,7 @@ static int inode_doinit_with_dentry(stru
+ if (!context) {
+ rc = -ENOMEM;
+ dput(dentry);
+- goto out;
++ goto out_unlock;
+ }
+ rc = inode->i_op->getxattr(dentry,
+ XATTR_NAME_SELINUX,
+@@ -924,7 +922,7 @@ static int inode_doinit_with_dentry(stru
+ "%d for dev=%s ino=%ld\n", __FUNCTION__,
+ -rc, inode->i_sb->s_id, inode->i_ino);
+ kfree(context);
+- goto out;
++ goto out_unlock;
+ }
+ /* Map ENODATA to the default file SID */
+ sid = sbsec->def_sid;
+@@ -960,7 +958,7 @@ static int inode_doinit_with_dentry(stru
+ isec->sclass,
+ &sid);
+ if (rc)
+- goto out;
++ goto out_unlock;
+ isec->sid = sid;
+ break;
+ case SECURITY_FS_USE_MNTPOINT:
+@@ -978,7 +976,7 @@ static int inode_doinit_with_dentry(stru
+ isec->sclass,
+ &sid);
+ if (rc)
+- goto out;
++ goto out_unlock;
+ isec->sid = sid;
+ }
+ }
+@@ -987,12 +985,11 @@ static int inode_doinit_with_dentry(stru
+
+ isec->initialized = 1;
+
++out_unlock:
++ mutex_unlock(&isec->lock);
+ out:
+ if (isec->sclass == SECCLASS_FILE)
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
+-
+- if (hold_sem)
+- up(&isec->sem);
+ return rc;
+ }
+
+@@ -1364,25 +1361,6 @@ static inline u32 file_to_av(struct file
+ return av;
+ }
+
+-/* Set an inode's SID to a specified value. */
+-static int inode_security_set_sid(struct inode *inode, u32 sid)
+-{
+- struct inode_security_struct *isec = inode->i_security;
+- struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+-
+- if (!sbsec->initialized) {
+- /* Defer initialization to selinux_complete_init. */
+- return 0;
+- }
+-
+- down(&isec->sem);
+- isec->sclass = inode_mode_to_security_class(inode->i_mode);
+- isec->sid = sid;
+- isec->initialized = 1;
+- up(&isec->sem);
+- return 0;
+-}
+-
+ /* Hook functions begin here. */
+
+ static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
+@@ -1711,10 +1689,12 @@ static inline void flush_unauthorized_fi
+ {
+ struct avc_audit_data ad;
+ struct file *file, *devnull = NULL;
+- struct tty_struct *tty = current->signal->tty;
++ struct tty_struct *tty;
+ struct fdtable *fdt;
+ long j = -1;
+
++ mutex_lock(&tty_mutex);
++ tty = current->signal->tty;
+ if (tty) {
+ file_list_lock();
+ file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
+@@ -1734,6 +1714,7 @@ static inline void flush_unauthorized_fi
+ }
+ file_list_unlock();
+ }
++ mutex_unlock(&tty_mutex);
+
+ /* Revalidate access to inherited open files. */
+
+@@ -1942,18 +1923,40 @@ static inline void take_option(char **to
+ if (!*first) {
+ **to = ',';
+ *to += 1;
+- }
+- else
++ } else
+ *first = 0;
+ memcpy(*to, from, len);
+ *to += len;
+ }
+
++static inline void take_selinux_option(char **to, char *from, int *first,
++ int len)
++{
++ int current_size = 0;
++
++ if (!*first) {
++ **to = '|';
++ *to += 1;
++ }
++ else
++ *first = 0;
++
++ while (current_size < len) {
++ if (*from != '"') {
++ **to = *from;
++ *to += 1;
++ }
++ from += 1;
++ current_size += 1;
++ }
++}
++
+ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
+ {
+ int fnosec, fsec, rc = 0;
+ char *in_save, *in_curr, *in_end;
+ char *sec_curr, *nosec_save, *nosec;
++ int open_quote = 0;
+
+ in_curr = orig;
+ sec_curr = copy;
+@@ -1975,11 +1978,14 @@ static int selinux_sb_copy_data(struct f
+ in_save = in_end = orig;
+
+ do {
+- if (*in_end == ',' || *in_end == '\0') {
++ if (*in_end == '"')
++ open_quote = !open_quote;
++ if ((*in_end == ',' && open_quote == 0) ||
++ *in_end == '\0') {
+ int len = in_end - in_curr;
+
+ if (selinux_option(in_curr, len))
+- take_option(&sec_curr, in_curr, &fsec, len);
++ take_selinux_option(&sec_curr, in_curr, &fsec, len);
+ else
+ take_option(&nosec, in_curr, &fnosec, len);
+
+@@ -2091,7 +2097,13 @@ static int selinux_inode_init_security(s
+ }
+ }
+
+- inode_security_set_sid(inode, newsid);
++ /* Possibly defer initialization to selinux_complete_init. */
++ if (sbsec->initialized) {
++ struct inode_security_struct *isec = inode->i_security;
++ isec->sclass = inode_mode_to_security_class(inode->i_mode);
++ isec->sid = newsid;
++ isec->initialized = 1;
++ }
+
+ if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+ return -EOPNOTSUPP;
+@@ -2400,6 +2412,7 @@ static int selinux_inode_listsecurity(st
+
+ static int selinux_file_permission(struct file *file, int mask)
+ {
++ int rc;
+ struct inode *inode = file->f_dentry->d_inode;
+
+ if (!mask) {
+@@ -2411,8 +2424,12 @@ static int selinux_file_permission(struc
+ if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
+ mask |= MAY_APPEND;
+
+- return file_has_perm(current, file,
+- file_mask_to_av(inode->i_mode, mask));
++ rc = file_has_perm(current, file,
++ file_mask_to_av(inode->i_mode, mask));
++ if (rc)
++ return rc;
++
++ return selinux_netlbl_inode_permission(inode, mask);
+ }
+
+ static int selinux_file_alloc_security(struct file *file)
+@@ -3063,11 +3080,13 @@ out:
+ return err;
+ }
+
+-static void selinux_socket_post_create(struct socket *sock, int family,
+- int type, int protocol, int kern)
++static int selinux_socket_post_create(struct socket *sock, int family,
++ int type, int protocol, int kern)
+ {
++ int err = 0;
+ struct inode_security_struct *isec;
+ struct task_security_struct *tsec;
++ struct sk_security_struct *sksec;
+ u32 newsid;
+
+ isec = SOCK_INODE(sock)->i_security;
+@@ -3078,7 +3097,15 @@ static void selinux_socket_post_create(s
+ isec->sid = kern ? SECINITSID_KERNEL : newsid;
+ isec->initialized = 1;
+
+- return;
++ if (sock->sk) {
++ sksec = sock->sk->sk_security;
++ sksec->sid = isec->sid;
++ err = selinux_netlbl_socket_post_create(sock,
++ family,
++ isec->sid);
++ }
++
++ return err;
+ }
+
+ /* Range of port numbers used to automatically bind.
+@@ -3259,7 +3286,13 @@ static int selinux_socket_accept(struct
+ static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+ int size)
+ {
+- return socket_has_perm(current, sock, SOCKET__WRITE);
++ int rc;
++
++ rc = socket_has_perm(current, sock, SOCKET__WRITE);
++ if (rc)
++ return rc;
++
++ return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
+ }
+
+ static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
+@@ -3280,7 +3313,13 @@ static int selinux_socket_getpeername(st
+
+ static int selinux_socket_setsockopt(struct socket *sock,int level,int optname)
+ {
+- return socket_has_perm(current, sock, SOCKET__SETOPT);
++ int err;
++
++ err = socket_has_perm(current, sock, SOCKET__SETOPT);
++ if (err)
++ return err;
++
++ return selinux_netlbl_socket_setsockopt(sock, level, optname);
+ }
+
+ static int selinux_socket_getsockopt(struct socket *sock, int level,
+@@ -3327,8 +3366,9 @@ static int selinux_socket_unix_stream_co
+ /* server child socket */
+ ssec = newsk->sk_security;
+ ssec->peer_sid = isec->sid;
+-
+- return 0;
++ err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
++
++ return err;
+ }
+
+ static int selinux_socket_unix_may_send(struct socket *sock,
+@@ -3354,11 +3394,29 @@ static int selinux_socket_unix_may_send(
+ }
+
+ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+- struct avc_audit_data *ad, u32 sock_sid, u16 sock_class,
+- u16 family, char *addrp, int len)
++ struct avc_audit_data *ad, u16 family, char *addrp, int len)
+ {
+ int err = 0;
+ u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0;
++ struct socket *sock;
++ u16 sock_class = 0;
++ u32 sock_sid = 0;
++
++ read_lock_bh(&sk->sk_callback_lock);
++ sock = sk->sk_socket;
++ if (sock) {
++ struct inode *inode;
++ inode = SOCK_INODE(sock);
++ if (inode) {
++ struct inode_security_struct *isec;
++ isec = inode->i_security;
++ sock_sid = isec->sid;
++ sock_class = isec->sclass;
++ }
++ }
++ read_unlock_bh(&sk->sk_callback_lock);
++ if (!sock_sid)
++ goto out;
+
+ if (!skb->dev)
+ goto out;
+@@ -3418,12 +3476,10 @@ out:
+ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+ u16 family;
+- u16 sock_class = 0;
+ char *addrp;
+ int len, err = 0;
+- u32 sock_sid = 0;
+- struct socket *sock;
+ struct avc_audit_data ad;
++ struct sk_security_struct *sksec = sk->sk_security;
+
+ family = sk->sk_family;
+ if (family != PF_INET && family != PF_INET6)
+@@ -3433,22 +3489,6 @@ static int selinux_socket_sock_rcv_skb(s
+ if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
+ family = PF_INET;
+
+- read_lock_bh(&sk->sk_callback_lock);
+- sock = sk->sk_socket;
+- if (sock) {
+- struct inode *inode;
+- inode = SOCK_INODE(sock);
+- if (inode) {
+- struct inode_security_struct *isec;
+- isec = inode->i_security;
+- sock_sid = isec->sid;
+- sock_class = isec->sclass;
+- }
+- }
+- read_unlock_bh(&sk->sk_callback_lock);
+- if (!sock_sid)
+- goto out;
+-
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]";
+ ad.u.net.family = family;
+@@ -3458,16 +3498,19 @@ static int selinux_socket_sock_rcv_skb(s
+ goto out;
+
+ if (selinux_compat_net)
+- err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid,
+- sock_class, family,
++ err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family,
+ addrp, len);
+ else
+- err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET,
++ err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
+ PACKET__RECV, &ad);
+ if (err)
+ goto out;
+
+- err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
++ err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad);
++ if (err)
++ goto out;
++
++ err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
+ out:
+ return err;
+ }
+@@ -3490,8 +3533,9 @@ static int selinux_socket_getpeersec_str
+ peer_sid = ssec->peer_sid;
+ }
+ else if (isec->sclass == SECCLASS_TCP_SOCKET) {
+- peer_sid = selinux_socket_getpeer_stream(sock->sk);
+-
++ peer_sid = selinux_netlbl_socket_getpeersec_stream(sock);
++ if (peer_sid == SECSID_NULL)
++ peer_sid = selinux_socket_getpeer_stream(sock->sk);
+ if (peer_sid == SECSID_NULL) {
+ err = -ENOPROTOOPT;
+ goto out;
+@@ -3531,8 +3575,11 @@ static int selinux_socket_getpeersec_dgr
+
+ if (sock && (sock->sk->sk_family == PF_UNIX))
+ selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
+- else if (skb)
+- peer_secid = selinux_socket_getpeer_dgram(skb);
++ else if (skb) {
++ peer_secid = selinux_netlbl_socket_getpeersec_dgram(skb);
++ if (peer_secid == SECSID_NULL)
++ peer_secid = selinux_socket_getpeer_dgram(skb);
++ }
+
+ if (peer_secid == SECSID_NULL)
+ err = -EINVAL;
+@@ -3551,22 +3598,88 @@ static void selinux_sk_free_security(str
+ sk_free_security(sk);
+ }
+
+-static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir)
++static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
+ {
+- struct inode_security_struct *isec;
+- u32 sock_sid = SECINITSID_ANY_SOCKET;
++ struct sk_security_struct *ssec = sk->sk_security;
++ struct sk_security_struct *newssec = newsk->sk_security;
++
++ newssec->sid = ssec->sid;
++ newssec->peer_sid = ssec->peer_sid;
++
++ selinux_netlbl_sk_clone_security(ssec, newssec);
++}
+
++static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
++{
+ if (!sk)
+- return selinux_no_sk_sid(fl);
++ *secid = SECINITSID_ANY_SOCKET;
++ else {
++ struct sk_security_struct *sksec = sk->sk_security;
++
++ *secid = sksec->sid;
++ }
++}
++
++static void selinux_sock_graft(struct sock* sk, struct socket *parent)
++{
++ struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
++ struct sk_security_struct *sksec = sk->sk_security;
++
++ if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
++ sk->sk_family == PF_UNIX)
++ isec->sid = sksec->sid;
++
++ selinux_netlbl_sock_graft(sk, parent);
++}
++
++static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
++ struct request_sock *req)
++{
++ struct sk_security_struct *sksec = sk->sk_security;
++ int err;
++ u32 newsid;
++ u32 peersid;
++
++ newsid = selinux_netlbl_inet_conn_request(skb, sksec->sid);
++ if (newsid != SECSID_NULL) {
++ req->secid = newsid;
++ return 0;
++ }
++
++ err = selinux_xfrm_decode_session(skb, &peersid, 0);
++ BUG_ON(err);
++
++ if (peersid == SECSID_NULL) {
++ req->secid = sksec->sid;
++ return 0;
++ }
++
++ err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
++ if (err)
++ return err;
++
++ req->secid = newsid;
++ return 0;
++}
++
++static void selinux_inet_csk_clone(struct sock *newsk,
++ const struct request_sock *req)
++{
++ struct sk_security_struct *newsksec = newsk->sk_security;
+
+- read_lock_bh(&sk->sk_callback_lock);
+- isec = get_sock_isec(sk);
++ newsksec->sid = req->secid;
++ /* NOTE: Ideally, we should also get the isec->sid for the
++ new socket in sync, but we don't have the isec available yet.
++ So we will wait until sock_graft to do it, by which
++ time it will have been created and available. */
+
+- if (isec)
+- sock_sid = isec->sid;
++ selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family);
++}
+
+- read_unlock_bh(&sk->sk_callback_lock);
+- return sock_sid;
++static void selinux_req_classify_flow(const struct request_sock *req,
++ struct flowi *fl)
++{
++ fl->secid = req->secid;
+ }
+
+ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
+@@ -3608,12 +3721,24 @@ out:
+ #ifdef CONFIG_NETFILTER
+
+ static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev,
+- struct inode_security_struct *isec,
+ struct avc_audit_data *ad,
+ u16 family, char *addrp, int len)
+ {
+- int err;
++ int err = 0;
+ u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0;
++ struct socket *sock;
++ struct inode *inode;
++ struct inode_security_struct *isec;
++
++ sock = sk->sk_socket;
++ if (!sock)
++ goto out;
++
++ inode = SOCK_INODE(sock);
++ if (!inode)
++ goto out;
++
++ isec = inode->i_security;
+
+ err = sel_netif_sids(dev, &if_sid, NULL);
+ if (err)
+@@ -3678,26 +3803,16 @@ static unsigned int selinux_ip_postroute
+ char *addrp;
+ int len, err = 0;
+ struct sock *sk;
+- struct socket *sock;
+- struct inode *inode;
+ struct sk_buff *skb = *pskb;
+- struct inode_security_struct *isec;
+ struct avc_audit_data ad;
+ struct net_device *dev = (struct net_device *)out;
++ struct sk_security_struct *sksec;
+
+ sk = skb->sk;
+ if (!sk)
+ goto out;
+
+- sock = sk->sk_socket;
+- if (!sock)
+- goto out;
+-
+- inode = SOCK_INODE(sock);
+- if (!inode)
+- goto out;
+-
+- isec = inode->i_security;
++ sksec = sk->sk_security;
+
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = dev->name;
+@@ -3708,16 +3823,16 @@ static unsigned int selinux_ip_postroute
+ goto out;
+
+ if (selinux_compat_net)
+- err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad,
++ err = selinux_ip_postroute_last_compat(sk, dev, &ad,
+ family, addrp, len);
+ else
+- err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET,
++ err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
+ PACKET__SEND, &ad);
+
+ if (err)
+ goto out;
+
+- err = selinux_xfrm_postroute_last(isec->sid, skb);
++ err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad);
+ out:
+ return err ? NF_DROP : NF_ACCEPT;
+ }
+@@ -4618,7 +4733,12 @@ static struct security_operations selinu
+ .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
+ .sk_alloc_security = selinux_sk_alloc_security,
+ .sk_free_security = selinux_sk_free_security,
+- .sk_getsid = selinux_sk_getsid_security,
++ .sk_clone_security = selinux_sk_clone_security,
++ .sk_getsecid = selinux_sk_getsecid,
++ .sock_graft = selinux_sock_graft,
++ .inet_conn_request = selinux_inet_conn_request,
++ .inet_csk_clone = selinux_inet_csk_clone,
++ .req_classify_flow = selinux_req_classify_flow,
+
+ #ifdef CONFIG_SECURITY_NETWORK_XFRM
+ .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
+@@ -4629,6 +4749,9 @@ static struct security_operations selinu
+ .xfrm_state_free_security = selinux_xfrm_state_free,
+ .xfrm_state_delete_security = selinux_xfrm_state_delete,
+ .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
++ .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
++ .xfrm_flow_state_match = selinux_xfrm_flow_state_match,
++ .xfrm_decode_session = selinux_xfrm_decode_session,
+ #endif
+
+ #ifdef CONFIG_KEYS
+diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
+index 7c9b583..09fc8a2 100644
+--- a/security/selinux/include/av_perm_to_string.h
++++ b/security/selinux/include/av_perm_to_string.h
+@@ -241,6 +241,7 @@
+ S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
+ S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
+ S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
++ S_(SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, "polmatch")
+ S_(SECCLASS_PACKET, PACKET__SEND, "send")
+ S_(SECCLASS_PACKET, PACKET__RECV, "recv")
+ S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
+diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
+index 69fd4b4..81f4f52 100644
+--- a/security/selinux/include/av_permissions.h
++++ b/security/selinux/include/av_permissions.h
+@@ -911,6 +911,7 @@
+ #define ASSOCIATION__SENDTO 0x00000001UL
+ #define ASSOCIATION__RECVFROM 0x00000002UL
+ #define ASSOCIATION__SETCONTEXT 0x00000004UL
++#define ASSOCIATION__POLMATCH 0x00000008UL
+
+ #define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL
+ #define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL
+diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
+index 9401788..ef2267f 100644
+--- a/security/selinux/include/objsec.h
++++ b/security/selinux/include/objsec.h
+@@ -44,7 +44,7 @@ struct inode_security_struct {
+ u32 sid; /* SID of this object */
+ u16 sclass; /* security class of this object */
+ unsigned char initialized; /* initialization flag */
+- struct semaphore sem;
++ struct mutex lock;
+ unsigned char inherit; /* inherit SID from parent entry */
+ };
+
+@@ -63,7 +63,7 @@ struct superblock_security_struct {
+ unsigned int behavior; /* labeling behavior */
+ unsigned char initialized; /* initialization flag */
+ unsigned char proc; /* proc fs */
+- struct semaphore sem;
++ struct mutex lock;
+ struct list_head isec_head;
+ spinlock_t isec_lock;
+ };
+@@ -99,7 +99,16 @@ struct netif_security_struct {
+
+ struct sk_security_struct {
+ struct sock *sk; /* back pointer to sk object */
++ u32 sid; /* SID of this object */
+ u32 peer_sid; /* SID of peer */
++#ifdef CONFIG_NETLABEL
++ u16 sclass; /* sock security class */
++ enum { /* NetLabel state */
++ NLBL_UNSET = 0,
++ NLBL_REQUIRE,
++ NLBL_LABELED,
++ } nlbl_state;
++#endif
+ };
+
+ struct key_security_struct {
+diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
+index 063af47..1ef7917 100644
+--- a/security/selinux/include/security.h
++++ b/security/selinux/include/security.h
+@@ -24,10 +24,15 @@
+ #define POLICYDB_VERSION_VALIDATETRANS 19
+ #define POLICYDB_VERSION_MLS 19
+ #define POLICYDB_VERSION_AVTAB 20
++#define POLICYDB_VERSION_RANGETRANS 21
+
+ /* Range of policy versions we understand*/
+ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
+-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB
++#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
++#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
++#else
++#define POLICYDB_VERSION_MAX POLICYDB_VERSION_RANGETRANS
++#endif
+
+ extern int selinux_enabled;
+ extern int selinux_mls_enabled;
+@@ -78,6 +83,8 @@ int security_node_sid(u16 domain, void *
+ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 tclass);
+
++int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
++
+ #define SECURITY_FS_USE_XATTR 1 /* use xattr */
+ #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
+ #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */
+diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h
+new file mode 100644
+index 0000000..9de10cc
+--- /dev/null
++++ b/security/selinux/include/selinux_netlabel.h
+@@ -0,0 +1,129 @@
++/*
++ * SELinux interface to the NetLabel subsystem
++ *
++ * Author : Paul Moore <paul.moore at hp.com>
++ *
++ */
++
++/*
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ *
++ * 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 _SELINUX_NETLABEL_H_
++#define _SELINUX_NETLABEL_H_
++
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/net.h>
++#include <linux/skbuff.h>
++#include <net/sock.h>
++
++#include "avc.h"
++#include "objsec.h"
++
++#ifdef CONFIG_NETLABEL
++void selinux_netlbl_cache_invalidate(void);
++int selinux_netlbl_socket_post_create(struct socket *sock,
++ int sock_family,
++ u32 sid);
++void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
++u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid);
++int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
++ struct sk_buff *skb,
++ struct avc_audit_data *ad);
++u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock);
++u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb);
++void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
++ int family);
++void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec,
++ struct sk_security_struct *newssec);
++int selinux_netlbl_inode_permission(struct inode *inode, int mask);
++int selinux_netlbl_socket_setsockopt(struct socket *sock,
++ int level,
++ int optname);
++#else
++static inline void selinux_netlbl_cache_invalidate(void)
++{
++ return;
++}
++
++static inline int selinux_netlbl_socket_post_create(struct socket *sock,
++ int sock_family,
++ u32 sid)
++{
++ return 0;
++}
++
++static inline void selinux_netlbl_sock_graft(struct sock *sk,
++ struct socket *sock)
++{
++ return;
++}
++
++static inline u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb,
++ u32 sock_sid)
++{
++ return SECSID_NULL;
++}
++
++static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
++ struct sk_buff *skb,
++ struct avc_audit_data *ad)
++{
++ return 0;
++}
++
++static inline u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
++{
++ return SECSID_NULL;
++}
++
++static inline u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
++{
++ return SECSID_NULL;
++}
++
++static inline void selinux_netlbl_sk_security_init(
++ struct sk_security_struct *ssec,
++ int family)
++{
++ return;
++}
++
++static inline void selinux_netlbl_sk_clone_security(
++ struct sk_security_struct *ssec,
++ struct sk_security_struct *newssec)
++{
++ return;
++}
++
++static inline int selinux_netlbl_inode_permission(struct inode *inode,
++ int mask)
++{
++ return 0;
++}
++
++static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
++ int level,
++ int optname)
++{
++ return 0;
++}
++#endif /* CONFIG_NETLABEL */
++
++#endif
+diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
+index c96498a..526b280 100644
+--- a/security/selinux/include/xfrm.h
++++ b/security/selinux/include/xfrm.h
+@@ -2,18 +2,26 @@
+ * SELinux support for the XFRM LSM hooks
+ *
+ * Author : Trent Jaeger, <jaegert at us.ibm.com>
++ * Updated : Venkat Yekkirala, <vyekkirala at TrustedCS.com>
+ */
+ #ifndef _SELINUX_XFRM_H_
+ #define _SELINUX_XFRM_H_
+
+-int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx);
++int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
++ struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk);
+ int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new);
+ void selinux_xfrm_policy_free(struct xfrm_policy *xp);
+ int selinux_xfrm_policy_delete(struct xfrm_policy *xp);
+-int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx);
++int selinux_xfrm_state_alloc(struct xfrm_state *x,
++ struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid);
+ void selinux_xfrm_state_free(struct xfrm_state *x);
+ int selinux_xfrm_state_delete(struct xfrm_state *x);
+-int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir);
++int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir);
++int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
++ struct xfrm_policy *xp, struct flowi *fl);
++int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
++ struct xfrm_policy *xp);
++
+
+ /*
+ * Extract the security blob from the sock (it's actually on the socket)
+@@ -26,30 +34,23 @@ static inline struct inode_security_stru
+ return SOCK_INODE(sk->sk_socket)->i_security;
+ }
+
+-
+-static inline u32 selinux_no_sk_sid(struct flowi *fl)
+-{
+- /* NOTE: no sock occurs on ICMP reply, forwards, ... */
+- /* icmp_reply: authorize as kernel packet */
+- if (fl && fl->proto == IPPROTO_ICMP) {
+- return SECINITSID_KERNEL;
+- }
+-
+- return SECINITSID_ANY_SOCKET;
+-}
+-
+ #ifdef CONFIG_SECURITY_NETWORK_XFRM
+-int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb);
+-int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb);
++int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
++ struct avc_audit_data *ad);
++int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
++ struct avc_audit_data *ad);
+ u32 selinux_socket_getpeer_stream(struct sock *sk);
+ u32 selinux_socket_getpeer_dgram(struct sk_buff *skb);
++int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
+ #else
+-static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
++static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
++ struct avc_audit_data *ad)
+ {
+ return 0;
+ }
+
+-static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
++static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
++ struct avc_audit_data *ad)
+ {
+ return 0;
+ }
+@@ -63,6 +64,11 @@ static inline int selinux_socket_getpeer
+ {
+ return SECSID_NULL;
+ }
++static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
++{
++ *sid = SECSID_NULL;
++ return 0;
++}
+ #endif
+
+ #endif /* _SELINUX_XFRM_H_ */
+diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
+index 00534c3..cd24441 100644
+--- a/security/selinux/selinuxfs.c
++++ b/security/selinux/selinuxfs.c
+@@ -771,7 +771,6 @@ static struct inode *sel_make_inode(stru
+ if (ret) {
+ ret->i_mode = mode;
+ ret->i_uid = ret->i_gid = 0;
+- ret->i_blksize = PAGE_CACHE_SIZE;
+ ret->i_blocks = 0;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ }
+@@ -1254,10 +1253,10 @@ static int sel_make_dir(struct inode *di
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+- inode->i_nlink++;
++ inc_nlink(inode);
+ d_add(dentry, inode);
+ /* bump link count on parent directory, too */
+- dir->i_nlink++;
++ inc_nlink(dir);
+ out:
+ return ret;
+ }
+diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
+index 47024a6..d539346 100644
+--- a/security/selinux/ss/ebitmap.c
++++ b/security/selinux/ss/ebitmap.c
+@@ -3,6 +3,14 @@
+ *
+ * Author : Stephen Smalley, <sds at epoch.ncsc.mil>
+ */
++/*
++ * Updated: Hewlett-Packard <paul.moore at hp.com>
++ *
++ * Added ebitmap_export() and ebitmap_import()
++ *
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ */
++
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/errno.h>
+@@ -59,6 +67,142 @@ int ebitmap_cpy(struct ebitmap *dst, str
+ return 0;
+ }
+
++/**
++ * ebitmap_export - Export an ebitmap to a unsigned char bitmap string
++ * @src: the ebitmap to export
++ * @dst: the resulting bitmap string
++ * @dst_len: length of dst in bytes
++ *
++ * Description:
++ * Allocate a buffer at least src->highbit bits long and export the extensible
++ * bitmap into the buffer. The bitmap string will be in little endian format,
++ * i.e. LSB first. The value returned in dst_len may not the true size of the
++ * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE.
++ * The caller must free the buffer when finished. Returns zero on success,
++ * negative values on failure.
++ *
++ */
++int ebitmap_export(const struct ebitmap *src,
++ unsigned char **dst,
++ size_t *dst_len)
++{
++ size_t bitmap_len;
++ unsigned char *bitmap;
++ struct ebitmap_node *iter_node;
++ MAPTYPE node_val;
++ size_t bitmap_byte;
++ unsigned char bitmask;
++
++ if (src->highbit == 0) {
++ *dst = NULL;
++ *dst_len = 0;
++ return 0;
++ }
++
++ bitmap_len = src->highbit / 8;
++ if (src->highbit % 7)
++ bitmap_len += 1;
++
++ bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) +
++ sizeof(MAPTYPE),
++ GFP_ATOMIC);
++ if (bitmap == NULL)
++ return -ENOMEM;
++
++ iter_node = src->node;
++ do {
++ bitmap_byte = iter_node->startbit / 8;
++ bitmask = 0x80;
++ node_val = iter_node->map;
++ do {
++ if (bitmask == 0) {
++ bitmap_byte++;
++ bitmask = 0x80;
++ }
++ if (node_val & (MAPTYPE)0x01)
++ bitmap[bitmap_byte] |= bitmask;
++ node_val >>= 1;
++ bitmask >>= 1;
++ } while (node_val > 0);
++ iter_node = iter_node->next;
++ } while (iter_node);
++
++ *dst = bitmap;
++ *dst_len = bitmap_len;
++ return 0;
++}
++
++/**
++ * ebitmap_import - Import an unsigned char bitmap string into an ebitmap
++ * @src: the bitmap string
++ * @src_len: the bitmap length in bytes
++ * @dst: the empty ebitmap
++ *
++ * Description:
++ * This function takes a little endian bitmap string in src and imports it into
++ * the ebitmap pointed to by dst. Returns zero on success, negative values on
++ * failure.
++ *
++ */
++int ebitmap_import(const unsigned char *src,
++ size_t src_len,
++ struct ebitmap *dst)
++{
++ size_t src_off = 0;
++ size_t node_limit;
++ struct ebitmap_node *node_new;
++ struct ebitmap_node *node_last = NULL;
++ u32 i_byte;
++ u32 i_bit;
++ unsigned char src_byte;
++
++ while (src_off < src_len) {
++ if (src_len - src_off >= sizeof(MAPTYPE)) {
++ if (*(MAPTYPE *)&src[src_off] == 0) {
++ src_off += sizeof(MAPTYPE);
++ continue;
++ }
++ node_limit = sizeof(MAPTYPE);
++ } else {
++ for (src_byte = 0, i_byte = src_off;
++ i_byte < src_len && src_byte == 0;
++ i_byte++)
++ src_byte |= src[i_byte];
++ if (src_byte == 0)
++ break;
++ node_limit = src_len - src_off;
++ }
++
++ node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC);
++ if (unlikely(node_new == NULL)) {
++ ebitmap_destroy(dst);
++ return -ENOMEM;
++ }
++ node_new->startbit = src_off * 8;
++ for (i_byte = 0; i_byte < node_limit; i_byte++) {
++ src_byte = src[src_off++];
++ for (i_bit = i_byte * 8; src_byte != 0; i_bit++) {
++ if (src_byte & 0x80)
++ node_new->map |= MAPBIT << i_bit;
++ src_byte <<= 1;
++ }
++ }
++
++ if (node_last != NULL)
++ node_last->next = node_new;
++ else
++ dst->node = node_new;
++ node_last = node_new;
++ }
++
++ if (likely(node_last != NULL))
++ dst->highbit = node_last->startbit + MAPSIZE;
++ else
++ ebitmap_init(dst);
++
++ return 0;
++}
++
+ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
+ {
+ struct ebitmap_node *n1, *n2;
+diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
+index 8bf4105..da2d465 100644
+--- a/security/selinux/ss/ebitmap.h
++++ b/security/selinux/ss/ebitmap.h
+@@ -69,6 +69,12 @@ static inline int ebitmap_node_get_bit(s
+
+ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
+ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
++int ebitmap_export(const struct ebitmap *src,
++ unsigned char **dst,
++ size_t *dst_len);
++int ebitmap_import(const unsigned char *src,
++ size_t src_len,
++ struct ebitmap *dst);
+ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
+ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
+ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
+diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
+index 7bc5b64..2cca8e2 100644
+--- a/security/selinux/ss/mls.c
++++ b/security/selinux/ss/mls.c
+@@ -10,6 +10,13 @@
+ *
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
+ */
++/*
++ * Updated: Hewlett-Packard <paul.moore at hp.com>
++ *
++ * Added support to import/export the MLS label
++ *
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ */
+
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+@@ -212,26 +219,6 @@ int mls_context_isvalid(struct policydb
+ }
+
+ /*
+- * Copies the MLS range from `src' into `dst'.
+- */
+-static inline int mls_copy_context(struct context *dst,
+- struct context *src)
+-{
+- int l, rc = 0;
+-
+- /* Copy the MLS range from the source context */
+- for (l = 0; l < 2; l++) {
+- dst->range.level[l].sens = src->range.level[l].sens;
+- rc = ebitmap_cpy(&dst->range.level[l].cat,
+- &src->range.level[l].cat);
+- if (rc)
+- break;
+- }
+-
+- return rc;
+-}
+-
+-/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `*scontext'. Update `*scontext' to
+@@ -543,22 +530,21 @@ int mls_compute_sid(struct context *scon
+ u32 specified,
+ struct context *newcontext)
+ {
++ struct range_trans *rtr;
++
+ if (!selinux_mls_enabled)
+ return 0;
+
+ switch (specified) {
+ case AVTAB_TRANSITION:
+- if (tclass == SECCLASS_PROCESS) {
+- struct range_trans *rangetr;
+- /* Look for a range transition rule. */
+- for (rangetr = policydb.range_tr; rangetr;
+- rangetr = rangetr->next) {
+- if (rangetr->dom == scontext->type &&
+- rangetr->type == tcontext->type) {
+- /* Set the range from the rule */
+- return mls_range_set(newcontext,
+- &rangetr->range);
+- }
++ /* Look for a range transition rule. */
++ for (rtr = policydb.range_tr; rtr; rtr = rtr->next) {
++ if (rtr->source_type == scontext->type &&
++ rtr->target_type == tcontext->type &&
++ rtr->target_class == tclass) {
++ /* Set the range from the rule */
++ return mls_range_set(newcontext,
++ &rtr->target_range);
+ }
+ }
+ /* Fallthrough */
+@@ -585,3 +571,163 @@ int mls_compute_sid(struct context *scon
+ return -EINVAL;
+ }
+
++/**
++ * mls_export_lvl - Export the MLS sensitivity levels
++ * @context: the security context
++ * @low: the low sensitivity level
++ * @high: the high sensitivity level
++ *
++ * Description:
++ * Given the security context copy the low MLS sensitivity level into lvl_low
++ * and the high sensitivity level in lvl_high. The MLS levels are only
++ * exported if the pointers are not NULL, if they are NULL then that level is
++ * not exported.
++ *
++ */
++void mls_export_lvl(const struct context *context, u32 *low, u32 *high)
++{
++ if (!selinux_mls_enabled)
++ return;
++
++ if (low != NULL)
++ *low = context->range.level[0].sens - 1;
++ if (high != NULL)
++ *high = context->range.level[1].sens - 1;
++}
++
++/**
++ * mls_import_lvl - Import the MLS sensitivity levels
++ * @context: the security context
++ * @low: the low sensitivity level
++ * @high: the high sensitivity level
++ *
++ * Description:
++ * Given the security context and the two sensitivty levels, set the MLS levels
++ * in the context according the two given as parameters. Returns zero on
++ * success, negative values on failure.
++ *
++ */
++void mls_import_lvl(struct context *context, u32 low, u32 high)
++{
++ if (!selinux_mls_enabled)
++ return;
++
++ context->range.level[0].sens = low + 1;
++ context->range.level[1].sens = high + 1;
++}
++
++/**
++ * mls_export_cat - Export the MLS categories
++ * @context: the security context
++ * @low: the low category
++ * @low_len: length of the cat_low bitmap in bytes
++ * @high: the high category
++ * @high_len: length of the cat_high bitmap in bytes
++ *
++ * Description:
++ * Given the security context export the low MLS category bitmap into cat_low
++ * and the high category bitmap into cat_high. The MLS categories are only
++ * exported if the pointers are not NULL, if they are NULL then that level is
++ * not exported. The caller is responsibile for freeing the memory when
++ * finished. Returns zero on success, negative values on failure.
++ *
++ */
++int mls_export_cat(const struct context *context,
++ unsigned char **low,
++ size_t *low_len,
++ unsigned char **high,
++ size_t *high_len)
++{
++ int rc = -EPERM;
++
++ if (!selinux_mls_enabled) {
++ *low = NULL;
++ *low_len = 0;
++ *high = NULL;
++ *high_len = 0;
++ return 0;
++ }
++
++ if (low != NULL) {
++ rc = ebitmap_export(&context->range.level[0].cat,
++ low,
++ low_len);
++ if (rc != 0)
++ goto export_cat_failure;
++ }
++ if (high != NULL) {
++ rc = ebitmap_export(&context->range.level[1].cat,
++ high,
++ high_len);
++ if (rc != 0)
++ goto export_cat_failure;
++ }
++
++ return 0;
++
++export_cat_failure:
++ if (low != NULL) {
++ kfree(*low);
++ *low = NULL;
++ *low_len = 0;
++ }
++ if (high != NULL) {
++ kfree(*high);
++ *high = NULL;
++ *high_len = 0;
++ }
++ return rc;
++}
++
++/**
++ * mls_import_cat - Import the MLS categories
++ * @context: the security context
++ * @low: the low category
++ * @low_len: length of the cat_low bitmap in bytes
++ * @high: the high category
++ * @high_len: length of the cat_high bitmap in bytes
++ *
++ * Description:
++ * Given the security context and the two category bitmap strings import the
++ * categories into the security context. The MLS categories are only imported
++ * if the pointers are not NULL, if they are NULL they are skipped. Returns
++ * zero on success, negative values on failure.
++ *
++ */
++int mls_import_cat(struct context *context,
++ const unsigned char *low,
++ size_t low_len,
++ const unsigned char *high,
++ size_t high_len)
++{
++ int rc = -EPERM;
++
++ if (!selinux_mls_enabled)
++ return 0;
++
++ if (low != NULL) {
++ rc = ebitmap_import(low,
++ low_len,
++ &context->range.level[0].cat);
++ if (rc != 0)
++ goto import_cat_failure;
++ }
++ if (high != NULL) {
++ if (high == low)
++ rc = ebitmap_cpy(&context->range.level[1].cat,
++ &context->range.level[0].cat);
++ else
++ rc = ebitmap_import(high,
++ high_len,
++ &context->range.level[1].cat);
++ if (rc != 0)
++ goto import_cat_failure;
++ }
++
++ return 0;
++
++import_cat_failure:
++ ebitmap_destroy(&context->range.level[0].cat);
++ ebitmap_destroy(&context->range.level[1].cat);
++ return rc;
++}
+diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
+index fbb42f0..df6032c 100644
+--- a/security/selinux/ss/mls.h
++++ b/security/selinux/ss/mls.h
+@@ -10,6 +10,13 @@
+ *
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
+ */
++/*
++ * Updated: Hewlett-Packard <paul.moore at hp.com>
++ *
++ * Added support to import/export the MLS label
++ *
++ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
++ */
+
+ #ifndef _SS_MLS_H_
+ #define _SS_MLS_H_
+@@ -17,6 +24,26 @@
+ #include "context.h"
+ #include "policydb.h"
+
++/*
++ * Copies the MLS range from `src' into `dst'.
++ */
++static inline int mls_copy_context(struct context *dst,
++ struct context *src)
++{
++ int l, rc = 0;
++
++ /* Copy the MLS range from the source context */
++ for (l = 0; l < 2; l++) {
++ dst->range.level[l].sens = src->range.level[l].sens;
++ rc = ebitmap_cpy(&dst->range.level[l].cat,
++ &src->range.level[l].cat);
++ if (rc)
++ break;
++ }
++
++ return rc;
++}
++
+ int mls_compute_context_len(struct context *context);
+ void mls_sid_to_context(struct context *context, char **scontext);
+ int mls_context_isvalid(struct policydb *p, struct context *c);
+@@ -42,5 +69,19 @@ int mls_compute_sid(struct context *scon
+ int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+ struct context *usercon);
+
++void mls_export_lvl(const struct context *context, u32 *low, u32 *high);
++void mls_import_lvl(struct context *context, u32 low, u32 high);
++
++int mls_export_cat(const struct context *context,
++ unsigned char **low,
++ size_t *low_len,
++ unsigned char **high,
++ size_t *high_len);
++int mls_import_cat(struct context *context,
++ const unsigned char *low,
++ size_t low_len,
++ const unsigned char *high,
++ size_t high_len);
++
+ #endif /* _SS_MLS_H */
+
+diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
+index f03960e..ba48961 100644
+--- a/security/selinux/ss/policydb.c
++++ b/security/selinux/ss/policydb.c
+@@ -96,6 +96,11 @@ static struct policydb_compat_info polic
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
++ {
++ .version = POLICYDB_VERSION_RANGETRANS,
++ .sym_num = SYM_NUM,
++ .ocon_num = OCON_NUM,
++ },
+ };
+
+ static struct policydb_compat_info *policydb_lookup_compat(int version)
+@@ -613,6 +618,7 @@ void policydb_destroy(struct policydb *p
+ c = c->next;
+ ocontext_destroy(ctmp,i);
+ }
++ p->ocontexts[i] = NULL;
+ }
+
+ g = p->genfs;
+@@ -628,6 +634,7 @@ void policydb_destroy(struct policydb *p
+ g = g->next;
+ kfree(gtmp);
+ }
++ p->genfs = NULL;
+
+ cond_policydb_destroy(p);
+
+@@ -645,15 +652,15 @@ void policydb_destroy(struct policydb *p
+
+ for (rt = p->range_tr; rt; rt = rt -> next) {
+ if (lrt) {
+- ebitmap_destroy(&lrt->range.level[0].cat);
+- ebitmap_destroy(&lrt->range.level[1].cat);
++ ebitmap_destroy(&lrt->target_range.level[0].cat);
++ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ kfree(lrt);
+ }
+ lrt = rt;
+ }
+ if (lrt) {
+- ebitmap_destroy(&lrt->range.level[0].cat);
+- ebitmap_destroy(&lrt->range.level[1].cat);
++ ebitmap_destroy(&lrt->target_range.level[0].cat);
++ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ kfree(lrt);
+ }
+
+@@ -1829,6 +1836,7 @@ int policydb_read(struct policydb *p, vo
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_MLS) {
++ int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc < 0)
+ goto bad;
+@@ -1847,9 +1855,16 @@ int policydb_read(struct policydb *p, vo
+ rc = next_entry(buf, fp, (sizeof(u32) * 2));
+ if (rc < 0)
+ goto bad;
+- rt->dom = le32_to_cpu(buf[0]);
+- rt->type = le32_to_cpu(buf[1]);
+- rc = mls_read_range_helper(&rt->range, fp);
++ rt->source_type = le32_to_cpu(buf[0]);
++ rt->target_type = le32_to_cpu(buf[1]);
++ if (new_rangetr) {
++ rc = next_entry(buf, fp, sizeof(u32));
++ if (rc < 0)
++ goto bad;
++ rt->target_class = le32_to_cpu(buf[0]);
++ } else
++ rt->target_class = SECCLASS_PROCESS;
++ rc = mls_read_range_helper(&rt->target_range, fp);
+ if (rc)
+ goto bad;
+ lrt = rt;
+diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
+index b134071..8319d5f 100644
+--- a/security/selinux/ss/policydb.h
++++ b/security/selinux/ss/policydb.h
+@@ -106,9 +106,10 @@ struct cat_datum {
+ };
+
+ struct range_trans {
+- u32 dom; /* current process domain */
+- u32 type; /* program executable type */
+- struct mls_range range; /* new range */
++ u32 source_type;
++ u32 target_type;
++ u32 target_class;
++ struct mls_range target_range;
+ struct range_trans *next;
+ };
+
+diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
+index 85e4298..bfe1227 100644
+--- a/security/selinux/ss/services.c
++++ b/security/selinux/ss/services.c
+@@ -13,6 +13,11 @@
+ *
+ * Added conditional policy language extensions
+ *
++ * Updated: Hewlett-Packard <paul.moore at hp.com>
++ *
++ * Added support for NetLabel
++ *
++ * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris at redhat.com>
+@@ -29,6 +34,8 @@
+ #include <linux/sched.h>
+ #include <linux/audit.h>
+ #include <linux/mutex.h>
++#include <net/sock.h>
++#include <net/netlabel.h>
+
+ #include "flask.h"
+ #include "avc.h"
+@@ -40,6 +47,8 @@
+ #include "services.h"
+ #include "conditional.h"
+ #include "mls.h"
++#include "objsec.h"
++#include "selinux_netlabel.h"
+
+ extern void selnl_notify_policyload(u32 seqno);
+ unsigned int policydb_loaded_version;
+@@ -1241,6 +1250,7 @@ int security_load_policy(void *data, siz
+ selinux_complete_init();
+ avc_ss_reset(seqno);
+ selnl_notify_policyload(seqno);
++ selinux_netlbl_cache_invalidate();
+ return 0;
+ }
+
+@@ -1295,6 +1305,7 @@ int security_load_policy(void *data, siz
+
+ avc_ss_reset(seqno);
+ selnl_notify_policyload(seqno);
++ selinux_netlbl_cache_invalidate();
+
+ return 0;
+
+@@ -1817,6 +1828,75 @@ out:
+ return rc;
+ }
+
++/*
++ * security_sid_mls_copy() - computes a new sid based on the given
++ * sid and the mls portion of mls_sid.
++ */
++int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
++{
++ struct context *context1;
++ struct context *context2;
++ struct context newcon;
++ char *s;
++ u32 len;
++ int rc = 0;
++
++ if (!ss_initialized || !selinux_mls_enabled) {
++ *new_sid = sid;
++ goto out;
++ }
++
++ context_init(&newcon);
++
++ POLICY_RDLOCK;
++ context1 = sidtab_search(&sidtab, sid);
++ if (!context1) {
++ printk(KERN_ERR "security_sid_mls_copy: unrecognized SID "
++ "%d\n", sid);
++ rc = -EINVAL;
++ goto out_unlock;
++ }
++
++ context2 = sidtab_search(&sidtab, mls_sid);
++ if (!context2) {
++ printk(KERN_ERR "security_sid_mls_copy: unrecognized SID "
++ "%d\n", mls_sid);
++ rc = -EINVAL;
++ goto out_unlock;
++ }
++
++ newcon.user = context1->user;
++ newcon.role = context1->role;
++ newcon.type = context1->type;
++ rc = mls_copy_context(&newcon, context2);
++ if (rc)
++ goto out_unlock;
++
++
++ /* Check the validity of the new context. */
++ if (!policydb_context_isvalid(&policydb, &newcon)) {
++ rc = convert_context_handle_invalid_context(&newcon);
++ if (rc)
++ goto bad;
++ }
++
++ rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
++ goto out_unlock;
++
++bad:
++ if (!context_struct_to_string(&newcon, &s, &len)) {
++ audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
++ "security_sid_mls_copy: invalid context %s", s);
++ kfree(s);
++ }
++
++out_unlock:
++ POLICY_RDUNLOCK;
++ context_destroy(&newcon);
++out:
++ return rc;
++}
++
+ struct selinux_audit_rule {
+ u32 au_seqno;
+ struct context au_ctxt;
+@@ -1923,7 +2003,7 @@ int selinux_audit_rule_init(u32 field, u
+ return rc;
+ }
+
+-int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
++int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
+ struct selinux_audit_rule *rule,
+ struct audit_context *actx)
+ {
+@@ -1946,11 +2026,11 @@ int selinux_audit_rule_match(u32 ctxid,
+ goto out;
+ }
+
+- ctxt = sidtab_search(&sidtab, ctxid);
++ ctxt = sidtab_search(&sidtab, sid);
+ if (!ctxt) {
+ audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+ "selinux_audit_rule_match: unrecognized SID %d\n",
+- ctxid);
++ sid);
+ match = -ENOENT;
+ goto out;
+ }
+@@ -2064,3 +2144,579 @@ void selinux_audit_set_callback(int (*ca
+ {
+ aurule_callback = callback;
+ }
++
++#ifdef CONFIG_NETLABEL
++/*
++ * This is the structure we store inside the NetLabel cache block.
++ */
++#define NETLBL_CACHE(x) ((struct netlbl_cache *)(x))
++#define NETLBL_CACHE_T_NONE 0
++#define NETLBL_CACHE_T_SID 1
++#define NETLBL_CACHE_T_MLS 2
++struct netlbl_cache {
++ u32 type;
++ union {
++ u32 sid;
++ struct mls_range mls_label;
++ } data;
++};
++
++/**
++ * selinux_netlbl_cache_free - Free the NetLabel cached data
++ * @data: the data to free
++ *
++ * Description:
++ * This function is intended to be used as the free() callback inside the
++ * netlbl_lsm_cache structure.
++ *
++ */
++static void selinux_netlbl_cache_free(const void *data)
++{
++ struct netlbl_cache *cache;
++
++ if (data == NULL)
++ return;
++
++ cache = NETLBL_CACHE(data);
++ switch (cache->type) {
++ case NETLBL_CACHE_T_MLS:
++ ebitmap_destroy(&cache->data.mls_label.level[0].cat);
++ break;
++ }
++ kfree(data);
++}
++
++/**
++ * selinux_netlbl_cache_add - Add an entry to the NetLabel cache
++ * @skb: the packet
++ * @ctx: the SELinux context
++ *
++ * Description:
++ * Attempt to cache the context in @ctx, which was derived from the packet in
++ * @skb, in the NetLabel subsystem cache.
++ *
++ */
++static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
++{
++ struct netlbl_cache *cache = NULL;
++ struct netlbl_lsm_secattr secattr;
++
++ netlbl_secattr_init(&secattr);
++ secattr.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
++ if (secattr.cache == NULL)
++ goto netlbl_cache_add_return;
++
++ cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
++ if (cache == NULL)
++ goto netlbl_cache_add_return;
++ secattr.cache->free = selinux_netlbl_cache_free;
++ secattr.cache->data = (void *)cache;
++
++ cache->type = NETLBL_CACHE_T_MLS;
++ if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
++ &ctx->range.level[0].cat) != 0)
++ goto netlbl_cache_add_return;
++ cache->data.mls_label.level[1].cat.highbit =
++ cache->data.mls_label.level[0].cat.highbit;
++ cache->data.mls_label.level[1].cat.node =
++ cache->data.mls_label.level[0].cat.node;
++ cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
++ cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
++
++ netlbl_cache_add(skb, &secattr);
++
++netlbl_cache_add_return:
++ netlbl_secattr_destroy(&secattr);
++}
++
++/**
++ * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
++ *
++ * Description:
++ * Invalidate the NetLabel security attribute mapping cache.
++ *
++ */
++void selinux_netlbl_cache_invalidate(void)
++{
++ netlbl_cache_invalidate();
++}
++
++/**
++ * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
++ * @skb: the network packet
++ * @secattr: the NetLabel packet security attributes
++ * @base_sid: the SELinux SID to use as a context for MLS only attributes
++ * @sid: the SELinux SID
++ *
++ * Description:
++ * Convert the given NetLabel packet security attributes in @secattr into a
++ * SELinux SID. If the @secattr field does not contain a full SELinux
++ * SID/context then use the context in @base_sid as the foundation. If @skb
++ * is not NULL attempt to cache as much data as possibile. Returns zero on
++ * success, negative values on failure.
++ *
++ */
++static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
++ struct netlbl_lsm_secattr *secattr,
++ u32 base_sid,
++ u32 *sid)
++{
++ int rc = -EIDRM;
++ struct context *ctx;
++ struct context ctx_new;
++ struct netlbl_cache *cache;
++
++ POLICY_RDLOCK;
++
++ if (secattr->cache) {
++ cache = NETLBL_CACHE(secattr->cache->data);
++ switch (cache->type) {
++ case NETLBL_CACHE_T_SID:
++ *sid = cache->data.sid;
++ rc = 0;
++ break;
++ case NETLBL_CACHE_T_MLS:
++ ctx = sidtab_search(&sidtab, base_sid);
++ if (ctx == NULL)
++ goto netlbl_secattr_to_sid_return;
++
++ ctx_new.user = ctx->user;
++ ctx_new.role = ctx->role;
++ ctx_new.type = ctx->type;
++ ctx_new.range.level[0].sens =
++ cache->data.mls_label.level[0].sens;
++ ctx_new.range.level[0].cat.highbit =
++ cache->data.mls_label.level[0].cat.highbit;
++ ctx_new.range.level[0].cat.node =
++ cache->data.mls_label.level[0].cat.node;
++ ctx_new.range.level[1].sens =
++ cache->data.mls_label.level[1].sens;
++ ctx_new.range.level[1].cat.highbit =
++ cache->data.mls_label.level[1].cat.highbit;
++ ctx_new.range.level[1].cat.node =
++ cache->data.mls_label.level[1].cat.node;
++
++ rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
++ break;
++ default:
++ goto netlbl_secattr_to_sid_return;
++ }
++ } else if (secattr->mls_lvl_vld) {
++ ctx = sidtab_search(&sidtab, base_sid);
++ if (ctx == NULL)
++ goto netlbl_secattr_to_sid_return;
++
++ ctx_new.user = ctx->user;
++ ctx_new.role = ctx->role;
++ ctx_new.type = ctx->type;
++ mls_import_lvl(&ctx_new, secattr->mls_lvl, secattr->mls_lvl);
++ if (secattr->mls_cat) {
++ if (mls_import_cat(&ctx_new,
++ secattr->mls_cat,
++ secattr->mls_cat_len,
++ NULL,
++ 0) != 0)
++ goto netlbl_secattr_to_sid_return;
++ ctx_new.range.level[1].cat.highbit =
++ ctx_new.range.level[0].cat.highbit;
++ ctx_new.range.level[1].cat.node =
++ ctx_new.range.level[0].cat.node;
++ } else {
++ ebitmap_init(&ctx_new.range.level[0].cat);
++ ebitmap_init(&ctx_new.range.level[1].cat);
++ }
++ if (mls_context_isvalid(&policydb, &ctx_new) != 1)
++ goto netlbl_secattr_to_sid_return_cleanup;
++
++ rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
++ if (rc != 0)
++ goto netlbl_secattr_to_sid_return_cleanup;
++
++ if (skb != NULL)
++ selinux_netlbl_cache_add(skb, &ctx_new);
++ ebitmap_destroy(&ctx_new.range.level[0].cat);
++ } else {
++ *sid = SECSID_NULL;
++ rc = 0;
++ }
++
++netlbl_secattr_to_sid_return:
++ POLICY_RDUNLOCK;
++ return rc;
++netlbl_secattr_to_sid_return_cleanup:
++ ebitmap_destroy(&ctx_new.range.level[0].cat);
++ goto netlbl_secattr_to_sid_return;
++}
++
++/**
++ * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
++ * @skb: the packet
++ * @base_sid: the SELinux SID to use as a context for MLS only attributes
++ * @sid: the SID
++ *
++ * Description:
++ * Call the NetLabel mechanism to get the security attributes of the given
++ * packet and use those attributes to determine the correct context/SID to
++ * assign to the packet. Returns zero on success, negative values on failure.
++ *
++ */
++static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
++ u32 base_sid,
++ u32 *sid)
++{
++ int rc;
++ struct netlbl_lsm_secattr secattr;
++
++ netlbl_secattr_init(&secattr);
++ rc = netlbl_skbuff_getattr(skb, &secattr);
++ if (rc == 0)
++ rc = selinux_netlbl_secattr_to_sid(skb,
++ &secattr,
++ base_sid,
++ sid);
++ netlbl_secattr_destroy(&secattr);
++
++ return rc;
++}
++
++/**
++ * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
++ * @sock: the socket to label
++ * @sid: the SID to use
++ *
++ * Description:
++ * Attempt to label a socket using the NetLabel mechanism using the given
++ * SID. Returns zero values on success, negative values on failure.
++ *
++ */
++static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
++{
++ int rc = -ENOENT;
++ struct sk_security_struct *sksec = sock->sk->sk_security;
++ struct netlbl_lsm_secattr secattr;
++ struct context *ctx;
++
++ if (!ss_initialized)
++ return 0;
++
++ netlbl_secattr_init(&secattr);
++
++ POLICY_RDLOCK;
++
++ ctx = sidtab_search(&sidtab, sid);
++ if (ctx == NULL)
++ goto netlbl_socket_setsid_return;
++
++ secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
++ GFP_ATOMIC);
++ mls_export_lvl(ctx, &secattr.mls_lvl, NULL);
++ secattr.mls_lvl_vld = 1;
++ rc = mls_export_cat(ctx,
++ &secattr.mls_cat,
++ &secattr.mls_cat_len,
++ NULL,
++ NULL);
++ if (rc != 0)
++ goto netlbl_socket_setsid_return;
++
++ rc = netlbl_socket_setattr(sock, &secattr);
++ if (rc == 0)
++ sksec->nlbl_state = NLBL_LABELED;
++
++netlbl_socket_setsid_return:
++ POLICY_RDUNLOCK;
++ netlbl_secattr_destroy(&secattr);
++ return rc;
++}
++
++/**
++ * selinux_netlbl_sk_security_init - Setup the NetLabel fields
++ * @ssec: the sk_security_struct
++ * @family: the socket family
++ *
++ * Description:
++ * Called when a new sk_security_struct is allocated to initialize the NetLabel
++ * fields.
++ *
++ */
++void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
++ int family)
++{
++ if (family == PF_INET)
++ ssec->nlbl_state = NLBL_REQUIRE;
++ else
++ ssec->nlbl_state = NLBL_UNSET;
++}
++
++/**
++ * selinux_netlbl_sk_clone_security - Copy the NetLabel fields
++ * @ssec: the original sk_security_struct
++ * @newssec: the cloned sk_security_struct
++ *
++ * Description:
++ * Clone the NetLabel specific sk_security_struct fields from @ssec to
++ * @newssec.
++ *
++ */
++void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec,
++ struct sk_security_struct *newssec)
++{
++ newssec->sclass = ssec->sclass;
++ if (ssec->nlbl_state != NLBL_UNSET)
++ newssec->nlbl_state = NLBL_REQUIRE;
++ else
++ newssec->nlbl_state = NLBL_UNSET;
++}
++
++/**
++ * selinux_netlbl_socket_post_create - Label a socket using NetLabel
++ * @sock: the socket to label
++ * @sock_family: the socket family
++ * @sid: the SID to use
++ *
++ * Description:
++ * Attempt to label a socket using the NetLabel mechanism using the given
++ * SID. Returns zero values on success, negative values on failure.
++ *
++ */
++int selinux_netlbl_socket_post_create(struct socket *sock,
++ int sock_family,
++ u32 sid)
++{
++ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
++ struct sk_security_struct *sksec = sock->sk->sk_security;
++
++ sksec->sclass = isec->sclass;
++
++ if (sock_family != PF_INET)
++ return 0;
++
++ sksec->nlbl_state = NLBL_REQUIRE;
++ return selinux_netlbl_socket_setsid(sock, sid);
++}
++
++/**
++ * selinux_netlbl_sock_graft - Netlabel the new socket
++ * @sk: the new connection
++ * @sock: the new socket
++ *
++ * Description:
++ * The connection represented by @sk is being grafted onto @sock so set the
++ * socket's NetLabel to match the SID of @sk.
++ *
++ */
++void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
++{
++ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
++ struct sk_security_struct *sksec = sk->sk_security;
++ struct netlbl_lsm_secattr secattr;
++ u32 nlbl_peer_sid;
++
++ sksec->sclass = isec->sclass;
++
++ if (sk->sk_family != PF_INET)
++ return;
++
++ netlbl_secattr_init(&secattr);
++ if (netlbl_sock_getattr(sk, &secattr) == 0 &&
++ selinux_netlbl_secattr_to_sid(NULL,
++ &secattr,
++ SECINITSID_UNLABELED,
++ &nlbl_peer_sid) == 0)
++ sksec->peer_sid = nlbl_peer_sid;
++ netlbl_secattr_destroy(&secattr);
++
++ sksec->nlbl_state = NLBL_REQUIRE;
++
++ /* Try to set the NetLabel on the socket to save time later, if we fail
++ * here we will pick up the pieces in later calls to
++ * selinux_netlbl_inode_permission(). */
++ selinux_netlbl_socket_setsid(sock, sksec->sid);
++}
++
++/**
++ * selinux_netlbl_inet_conn_request - Handle a new connection request
++ * @skb: the packet
++ * @sock_sid: the SID of the parent socket
++ *
++ * Description:
++ * If present, use the security attributes of the packet in @skb and the
++ * parent sock's SID to arrive at a SID for the new child sock. Returns the
++ * SID of the connection or SECSID_NULL on failure.
++ *
++ */
++u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid)
++{
++ int rc;
++ u32 peer_sid;
++
++ rc = selinux_netlbl_skbuff_getsid(skb, sock_sid, &peer_sid);
++ if (rc != 0)
++ return SECSID_NULL;
++
++ return peer_sid;
++}
++
++/**
++ * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
++ * @inode: the file descriptor's inode
++ * @mask: the permission mask
++ *
++ * Description:
++ * Looks at a file's inode and if it is marked as a socket protected by
++ * NetLabel then verify that the socket has been labeled, if not try to label
++ * the socket now with the inode's SID. Returns zero on success, negative
++ * values on failure.
++ *
++ */
++int selinux_netlbl_inode_permission(struct inode *inode, int mask)
++{
++ int rc;
++ struct inode_security_struct *isec;
++ struct sk_security_struct *sksec;
++ struct socket *sock;
++
++ if (!S_ISSOCK(inode->i_mode))
++ return 0;
++
++ sock = SOCKET_I(inode);
++ isec = inode->i_security;
++ sksec = sock->sk->sk_security;
++ mutex_lock(&isec->lock);
++ if (unlikely(sksec->nlbl_state == NLBL_REQUIRE &&
++ (mask & (MAY_WRITE | MAY_APPEND)))) {
++ lock_sock(sock->sk);
++ rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
++ release_sock(sock->sk);
++ } else
++ rc = 0;
++ mutex_unlock(&isec->lock);
++
++ return rc;
++}
++
++/**
++ * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
++ * @sksec: the sock's sk_security_struct
++ * @skb: the packet
++ * @ad: the audit data
++ *
++ * Description:
++ * Fetch the NetLabel security attributes from @skb and perform an access check
++ * against the receiving socket. Returns zero on success, negative values on
++ * error.
++ *
++ */
++int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
++ struct sk_buff *skb,
++ struct avc_audit_data *ad)
++{
++ int rc;
++ u32 netlbl_sid;
++ u32 recv_perm;
++
++ rc = selinux_netlbl_skbuff_getsid(skb,
++ SECINITSID_UNLABELED,
++ &netlbl_sid);
++ if (rc != 0)
++ return rc;
++
++ if (netlbl_sid == SECSID_NULL)
++ return 0;
++
++ switch (sksec->sclass) {
++ case SECCLASS_UDP_SOCKET:
++ recv_perm = UDP_SOCKET__RECVFROM;
++ break;
++ case SECCLASS_TCP_SOCKET:
++ recv_perm = TCP_SOCKET__RECVFROM;
++ break;
++ default:
++ recv_perm = RAWIP_SOCKET__RECVFROM;
++ }
++
++ rc = avc_has_perm(sksec->sid,
++ netlbl_sid,
++ sksec->sclass,
++ recv_perm,
++ ad);
++ if (rc == 0)
++ return 0;
++
++ netlbl_skbuff_err(skb, rc);
++ return rc;
++}
++
++/**
++ * selinux_netlbl_socket_getpeersec_stream - Return the connected peer's SID
++ * @sock: the socket
++ *
++ * Description:
++ * Examine @sock to find the connected peer's SID. Returns the SID on success
++ * or SECSID_NULL on error.
++ *
++ */
++u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
++{
++ struct sk_security_struct *sksec = sock->sk->sk_security;
++ return sksec->peer_sid;
++}
++
++/**
++ * selinux_netlbl_socket_getpeersec_dgram - Return the SID of a NetLabel packet
++ * @skb: the packet
++ *
++ * Description:
++ * Examine @skb to find the SID assigned to it by NetLabel. Returns the SID on
++ * success, SECSID_NULL on error.
++ *
++ */
++u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
++{
++ int peer_sid;
++
++ if (selinux_netlbl_skbuff_getsid(skb,
++ SECINITSID_UNLABELED,
++ &peer_sid) != 0)
++ return SECSID_NULL;
++
++ return peer_sid;
++}
++
++/**
++ * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
++ * @sock: the socket
++ * @level: the socket level or protocol
++ * @optname: the socket option name
++ *
++ * Description:
++ * Check the setsockopt() call and if the user is trying to replace the IP
++ * options on a socket and a NetLabel is in place for the socket deny the
++ * access; otherwise allow the access. Returns zero when the access is
++ * allowed, -EACCES when denied, and other negative values on error.
++ *
++ */
++int selinux_netlbl_socket_setsockopt(struct socket *sock,
++ int level,
++ int optname)
++{
++ int rc = 0;
++ struct inode *inode = SOCK_INODE(sock);
++ struct sk_security_struct *sksec = sock->sk->sk_security;
++ struct inode_security_struct *isec = inode->i_security;
++ struct netlbl_lsm_secattr secattr;
++
++ mutex_lock(&isec->lock);
++ if (level == IPPROTO_IP && optname == IP_OPTIONS &&
++ sksec->nlbl_state == NLBL_LABELED) {
++ netlbl_secattr_init(&secattr);
++ rc = netlbl_socket_getattr(sock, &secattr);
++ if (rc == 0 && (secattr.cache || secattr.mls_lvl_vld))
++ rc = -EACCES;
++ netlbl_secattr_destroy(&secattr);
++ }
++ mutex_unlock(&isec->lock);
++
++ return rc;
++}
++#endif /* CONFIG_NETLABEL */
+diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
+index 6c985ce..675b995 100644
+--- a/security/selinux/xfrm.c
++++ b/security/selinux/xfrm.c
+@@ -6,7 +6,12 @@
+ * Authors: Serge Hallyn <sergeh at us.ibm.com>
+ * Trent Jaeger <jaegert at us.ibm.com>
+ *
++ * Updated: Venkat Yekkirala <vyekkirala at TrustedCS.com>
++ *
++ * Granular IPSec Associations for use in MLS environments.
++ *
+ * Copyright (C) 2005 International Business Machines Corporation
++ * Copyright (C) 2006 Trusted Computer Solutions, 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,
+@@ -67,13 +72,13 @@ static inline int selinux_authorizable_x
+ }
+
+ /*
+- * LSM hook implementation that authorizes that a socket can be used
+- * with the corresponding xfrm_sec_ctx and direction.
++ * LSM hook implementation that authorizes that a flow can use
++ * a xfrm policy rule.
+ */
+-int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
++int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
+ {
+- int rc = 0;
+- u32 sel_sid = SECINITSID_UNLABELED;
++ int rc;
++ u32 sel_sid;
+ struct xfrm_sec_ctx *ctx;
+
+ /* Context sid is either set to label or ANY_ASSOC */
+@@ -83,28 +88,160 @@ int selinux_xfrm_policy_lookup(struct xf
+
+ sel_sid = ctx->ctx_sid;
+ }
++ else
++ /*
++ * All flows should be treated as polmatch'ing an
++ * otherwise applicable "non-labeled" policy. This
++ * would prevent inadvertent "leaks".
++ */
++ return 0;
+
+- rc = avc_has_perm(sk_sid, sel_sid, SECCLASS_ASSOCIATION,
+- ((dir == FLOW_DIR_IN) ? ASSOCIATION__RECVFROM :
+- ((dir == FLOW_DIR_OUT) ? ASSOCIATION__SENDTO :
+- (ASSOCIATION__SENDTO | ASSOCIATION__RECVFROM))),
++ rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION,
++ ASSOCIATION__POLMATCH,
+ NULL);
+
++ if (rc == -EACCES)
++ rc = -ESRCH;
++
++ return rc;
++}
++
++/*
++ * LSM hook implementation that authorizes that a state matches
++ * the given policy, flow combo.
++ */
++
++int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp,
++ struct flowi *fl)
++{
++ u32 state_sid;
++ u32 pol_sid;
++ int err;
++
++ if (xp->security) {
++ if (!x->security)
++ /* unlabeled SA and labeled policy can't match */
++ return 0;
++ else
++ state_sid = x->security->ctx_sid;
++ pol_sid = xp->security->ctx_sid;
++ } else
++ if (x->security)
++ /* unlabeled policy and labeled SA can't match */
++ return 0;
++ else
++ /* unlabeled policy and unlabeled SA match all flows */
++ return 1;
++
++ err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION,
++ ASSOCIATION__POLMATCH,
++ NULL);
++
++ if (err)
++ return 0;
++
++ err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION,
++ ASSOCIATION__SENDTO,
++ NULL)? 0:1;
++
++ return err;
++}
++
++/*
++ * LSM hook implementation that authorizes that a particular outgoing flow
++ * can use a given security association.
++ */
++
++int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
++ struct xfrm_policy *xp)
++{
++ int rc = 0;
++ u32 sel_sid = SECINITSID_UNLABELED;
++ struct xfrm_sec_ctx *ctx;
++
++ if (!xp->security)
++ if (!xfrm->security)
++ return 1;
++ else
++ return 0;
++ else
++ if (!xfrm->security)
++ return 0;
++
++ /* Context sid is either set to label or ANY_ASSOC */
++ if ((ctx = xfrm->security)) {
++ if (!selinux_authorizable_ctx(ctx))
++ return 0;
++
++ sel_sid = ctx->ctx_sid;
++ }
++
++ rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION,
++ ASSOCIATION__SENDTO,
++ NULL)? 0:1;
++
+ return rc;
+ }
+
+ /*
++ * LSM hook implementation that determines the sid for the session.
++ */
++
++int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
++{
++ struct sec_path *sp;
++
++ *sid = SECSID_NULL;
++
++ if (skb == NULL)
++ return 0;
++
++ sp = skb->sp;
++ if (sp) {
++ int i, sid_set = 0;
++
++ for (i = sp->len-1; i >= 0; i--) {
++ struct xfrm_state *x = sp->xvec[i];
++ if (selinux_authorizable_xfrm(x)) {
++ struct xfrm_sec_ctx *ctx = x->security;
++
++ if (!sid_set) {
++ *sid = ctx->ctx_sid;
++ sid_set = 1;
++
++ if (!ckall)
++ break;
++ }
++ else if (*sid != ctx->ctx_sid)
++ return -EINVAL;
++ }
++ }
++ }
++
++ return 0;
++}
++
++/*
+ * Security blob allocation for xfrm_policy and xfrm_state
+ * CTX does not have a meaningful value on input
+ */
+-static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx)
++static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
++ struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid)
+ {
+ int rc = 0;
+ struct task_security_struct *tsec = current->security;
+- struct xfrm_sec_ctx *ctx;
++ struct xfrm_sec_ctx *ctx = NULL;
++ char *ctx_str = NULL;
++ u32 str_len;
++ u32 ctx_sid;
++
++ BUG_ON(uctx && pol);
++
++ if (!uctx)
++ goto not_from_user;
+
+- BUG_ON(!uctx);
+- BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX);
++ if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX)
++ return -EINVAL;
+
+ if (uctx->ctx_len >= PAGE_SIZE)
+ return -ENOMEM;
+@@ -141,9 +278,43 @@ static int selinux_xfrm_sec_ctx_alloc(st
+
+ return rc;
+
++not_from_user:
++ if (pol) {
++ rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid);
++ if (rc)
++ goto out;
++ }
++ else
++ ctx_sid = sid;
++
++ rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len);
++ if (rc)
++ goto out;
++
++ *ctxp = ctx = kmalloc(sizeof(*ctx) +
++ str_len,
++ GFP_ATOMIC);
++
++ if (!ctx) {
++ rc = -ENOMEM;
++ goto out;
++ }
++
++ ctx->ctx_doi = XFRM_SC_DOI_LSM;
++ ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
++ ctx->ctx_sid = ctx_sid;
++ ctx->ctx_len = str_len;
++ memcpy(ctx->ctx_str,
++ ctx_str,
++ str_len);
++
++ goto out2;
++
+ out:
+ *ctxp = NULL;
+ kfree(ctx);
++out2:
++ kfree(ctx_str);
+ return rc;
+ }
+
+@@ -151,13 +322,23 @@ out:
+ * LSM hook implementation that allocs and transfers uctx spec to
+ * xfrm_policy.
+ */
+-int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx)
++int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
++ struct xfrm_user_sec_ctx *uctx, struct sock *sk)
+ {
+ int err;
++ u32 sid;
+
+ BUG_ON(!xp);
++ BUG_ON(uctx && sk);
+
+- err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx);
++ if (sk) {
++ struct sk_security_struct *ssec = sk->sk_security;
++ sid = ssec->sid;
++ }
++ else
++ sid = SECSID_NULL;
++
++ err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid);
+ return err;
+ }
+
+@@ -217,13 +398,14 @@ int selinux_xfrm_policy_delete(struct xf
+ * LSM hook implementation that allocs and transfers sec_ctx spec to
+ * xfrm_state.
+ */
+-int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx)
++int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx,
++ struct xfrm_sec_ctx *pol, u32 secid)
+ {
+ int err;
+
+ BUG_ON(!x);
+
+- err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx);
++ err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid);
+ return err;
+ }
+
+@@ -329,38 +511,30 @@ int selinux_xfrm_state_delete(struct xfr
+ * we need to check for unlabelled access since this may not have
+ * gone thru the IPSec process.
+ */
+-int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
++int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
++ struct avc_audit_data *ad)
+ {
+ int i, rc = 0;
+ struct sec_path *sp;
++ u32 sel_sid = SECINITSID_UNLABELED;
+
+ sp = skb->sp;
+
+ if (sp) {
+- /*
+- * __xfrm_policy_check does not approve unless xfrm_policy_ok
+- * says that spi's match for policy and the socket.
+- *
+- * Only need to verify the existence of an authorizable sp.
+- */
+ for (i = 0; i < sp->len; i++) {
+ struct xfrm_state *x = sp->xvec[i];
+
+- if (x && selinux_authorizable_xfrm(x))
+- goto accept;
++ if (x && selinux_authorizable_xfrm(x)) {
++ struct xfrm_sec_ctx *ctx = x->security;
++ sel_sid = ctx->ctx_sid;
++ break;
++ }
+ }
+ }
+
+- /* check SELinux sock for unlabelled access */
+- rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
+- ASSOCIATION__RECVFROM, NULL);
+- if (rc)
+- goto drop;
+-
+-accept:
+- return 0;
++ rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION,
++ ASSOCIATION__RECVFROM, ad);
+
+-drop:
+ return rc;
+ }
+
+@@ -371,7 +545,8 @@ drop:
+ * If we do have a authorizable security association, then it has already been
+ * checked in xfrm_policy_lookup hook.
+ */
+-int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
++int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
++ struct avc_audit_data *ad)
+ {
+ struct dst_entry *dst;
+ int rc = 0;
+@@ -391,7 +566,7 @@ int selinux_xfrm_postroute_last(u32 isec
+ }
+
+ rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
+- ASSOCIATION__SENDTO, NULL);
++ ASSOCIATION__SENDTO, ad);
+ out:
+ return rc;
+ }
+diff --git a/sound/Makefile b/sound/Makefile
+index 1f60797..5f6bef5 100644
+--- a/sound/Makefile
++++ b/sound/Makefile
+@@ -2,6 +2,7 @@
+ #
+
+ obj-$(CONFIG_SOUND) += soundcore.o
++obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
+ obj-$(CONFIG_SOUND_PRIME) += oss/
+ obj-$(CONFIG_DMASOUND) += oss/
+ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
+@@ -11,4 +12,4 @@ ifeq ($(CONFIG_SND),y)
+ obj-y += last.o
+ endif
+
+-soundcore-objs := sound_core.o sound_firmware.o
++soundcore-objs := sound_core.o
+diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig
+index 2f4334d..5d5813c 100644
+--- a/sound/aoa/Kconfig
++++ b/sound/aoa/Kconfig
+@@ -1,5 +1,5 @@
+ menu "Apple Onboard Audio driver"
+- depends on SND!=n && PPC
++ depends on SND!=n && PPC_PMAC
+
+ config SND_AOA
+ tristate "Apple Onboard Audio driver"
+diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig
+index 90cf58f..d5fbd60 100644
+--- a/sound/aoa/codecs/Kconfig
++++ b/sound/aoa/codecs/Kconfig
+@@ -1,6 +1,8 @@
+ config SND_AOA_ONYX
+ tristate "support Onyx chip"
+ depends on SND_AOA
++ select I2C
++ select I2C_POWERMAC
+ ---help---
+ This option enables support for the Onyx (pcm3052)
+ codec chip found in the latest Apple machines
+@@ -18,6 +20,8 @@ config SND_AOA_ONYX
+ config SND_AOA_TAS
+ tristate "support TAS chips"
+ depends on SND_AOA
++ select I2C
++ select I2C_POWERMAC
+ ---help---
+ This option enables support for the tas chips
+ found in a lot of Apple Machines, especially
+diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
+index 16c0b6b..2ef55a1 100644
+--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
++++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
+@@ -66,6 +66,8 @@
+ #include <asm/prom.h>
+ #include <linux/delay.h>
+ #include <linux/module.h>
++#include <linux/mutex.h>
++
+ MODULE_AUTHOR("Johannes Berg <johannes at sipsolutions.net>");
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("tas codec driver for snd-aoa");
+@@ -91,6 +93,10 @@ struct tas {
+ u8 bass, treble;
+ u8 acr;
+ int drc_range;
++ /* protects hardware access against concurrency from
++ * userspace when hitting controls and during
++ * codec init/suspend/resume */
++ struct mutex mtx;
+ };
+
+ static int tas_reset_init(struct tas *tas);
+@@ -231,8 +237,10 @@ static int tas_snd_vol_get(struct snd_kc
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->cached_volume_l;
+ ucontrol->value.integer.value[1] = tas->cached_volume_r;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -241,14 +249,18 @@ static int tas_snd_vol_put(struct snd_kc
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ if (tas->cached_volume_l == ucontrol->value.integer.value[0]
+- && tas->cached_volume_r == ucontrol->value.integer.value[1])
++ && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->cached_volume_l = ucontrol->value.integer.value[0];
+ tas->cached_volume_r = ucontrol->value.integer.value[1];
+ if (tas->hw_enabled)
+ tas_set_volume(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -276,8 +288,10 @@ static int tas_snd_mute_get(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = !tas->mute_l;
+ ucontrol->value.integer.value[1] = !tas->mute_r;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -286,14 +300,18 @@ static int tas_snd_mute_put(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ if (tas->mute_l == !ucontrol->value.integer.value[0]
+- && tas->mute_r == !ucontrol->value.integer.value[1])
++ && tas->mute_r == !ucontrol->value.integer.value[1]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->mute_l = !ucontrol->value.integer.value[0];
+ tas->mute_r = !ucontrol->value.integer.value[1];
+ if (tas->hw_enabled)
+ tas_set_volume(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -322,8 +340,10 @@ static int tas_snd_mixer_get(struct snd_
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->mixer_l[idx];
+ ucontrol->value.integer.value[1] = tas->mixer_r[idx];
++ mutex_unlock(&tas->mtx);
+
+ return 0;
+ }
+@@ -334,15 +354,19 @@ static int tas_snd_mixer_put(struct snd_
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+
++ mutex_lock(&tas->mtx);
+ if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
+- && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
++ && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->mixer_l[idx] = ucontrol->value.integer.value[0];
+ tas->mixer_r[idx] = ucontrol->value.integer.value[1];
+
+ if (tas->hw_enabled)
+ tas_set_mixer(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -375,7 +399,9 @@ static int tas_snd_drc_range_get(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->drc_range;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -384,12 +410,16 @@ static int tas_snd_drc_range_put(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- if (tas->drc_range == ucontrol->value.integer.value[0])
++ mutex_lock(&tas->mtx);
++ if (tas->drc_range == ucontrol->value.integer.value[0]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->drc_range = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas3004_set_drc(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -417,7 +447,9 @@ static int tas_snd_drc_switch_get(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->drc_enabled;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -426,12 +458,16 @@ static int tas_snd_drc_switch_put(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- if (tas->drc_enabled == ucontrol->value.integer.value[0])
++ mutex_lock(&tas->mtx);
++ if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->drc_enabled = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas3004_set_drc(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -463,7 +499,9 @@ static int tas_snd_capture_source_get(st
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -471,15 +509,21 @@ static int tas_snd_capture_source_put(st
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+- int oldacr = tas->acr;
++ int oldacr;
++
++ mutex_lock(&tas->mtx);
++ oldacr = tas->acr;
+
+ tas->acr &= ~TAS_ACR_INPUT_B;
+ if (ucontrol->value.enumerated.item[0])
+ tas->acr |= TAS_ACR_INPUT_B;
+- if (oldacr == tas->acr)
++ if (oldacr == tas->acr) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+ if (tas->hw_enabled)
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -518,7 +562,9 @@ static int tas_snd_treble_get(struct snd
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->treble;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -527,12 +573,16 @@ static int tas_snd_treble_put(struct snd
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- if (tas->treble == ucontrol->value.integer.value[0])
++ mutex_lock(&tas->mtx);
++ if (tas->treble == ucontrol->value.integer.value[0]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->treble = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas_set_treble(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -560,7 +610,9 @@ static int tas_snd_bass_get(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
++ mutex_lock(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->bass;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -569,12 +621,16 @@ static int tas_snd_bass_put(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- if (tas->bass == ucontrol->value.integer.value[0])
++ mutex_lock(&tas->mtx);
++ if (tas->bass == ucontrol->value.integer.value[0]) {
++ mutex_unlock(&tas->mtx);
+ return 0;
++ }
+
+ tas->bass = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas_set_bass(tas);
++ mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -628,16 +684,16 @@ static int tas_reset_init(struct tas *ta
+
+ tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
+ if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
+- return -ENODEV;
++ goto outerr;
+
+ tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL |
+ TAS_ACR_B_MON_SEL_RIGHT;
+ if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+- return -ENODEV;
++ goto outerr;
+
+ tmp = 0;
+ if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
+- return -ENODEV;
++ goto outerr;
+
+ tas3004_set_drc(tas);
+
+@@ -649,9 +705,11 @@ static int tas_reset_init(struct tas *ta
+
+ tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
+ if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+- return -ENODEV;
++ goto outerr;
+
+ return 0;
++ outerr:
++ return -ENODEV;
+ }
+
+ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock)
+@@ -666,11 +724,13 @@ static int tas_switch_clock(struct codec
+ break;
+ case CLOCK_SWITCH_SLAVE:
+ /* Clocks are back, re-init the codec */
++ mutex_lock(&tas->mtx);
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ tas->hw_enabled = 1;
+ tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
++ mutex_unlock(&tas->mtx);
+ break;
+ default:
+ /* doesn't happen as of now */
+@@ -684,19 +744,23 @@ static int tas_switch_clock(struct codec
+ * our i2c device is suspended, and then take note of that! */
+ static int tas_suspend(struct tas *tas)
+ {
++ mutex_lock(&tas->mtx);
+ tas->hw_enabled = 0;
+ tas->acr |= TAS_ACR_ANALOG_PDOWN;
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+ static int tas_resume(struct tas *tas)
+ {
+ /* reset codec */
++ mutex_lock(&tas->mtx);
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ tas->hw_enabled = 1;
++ mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -739,11 +803,14 @@ static int tas_init_codec(struct aoa_cod
+ return -EINVAL;
+ }
+
++ mutex_lock(&tas->mtx);
+ if (tas_reset_init(tas)) {
+ printk(KERN_ERR PFX "tas failed to initialise\n");
++ mutex_unlock(&tas->mtx);
+ return -ENXIO;
+ }
+ tas->hw_enabled = 1;
++ mutex_unlock(&tas->mtx);
+
+ if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
+ aoa_get_card(),
+@@ -822,6 +889,7 @@ static int tas_create(struct i2c_adapter
+ if (!tas)
+ return -ENOMEM;
+
++ mutex_init(&tas->mtx);
+ tas->i2c.driver = &tas_driver;
+ tas->i2c.adapter = adapter;
+ tas->i2c.addr = addr;
+@@ -850,6 +918,7 @@ static int tas_create(struct i2c_adapter
+ detach:
+ i2c_detach_client(&tas->i2c);
+ fail:
++ mutex_destroy(&tas->mtx);
+ kfree(tas);
+ return -EINVAL;
+ }
+@@ -908,6 +977,7 @@ static int tas_i2c_detach(struct i2c_cli
+ /* power down codec chip */
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tmp);
+
++ mutex_destroy(&tas->mtx);
+ kfree(tas);
+ return 0;
+ }
+diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
+index f69d333..40eb47e 100644
+--- a/sound/aoa/core/snd-aoa-gpio-feature.c
++++ b/sound/aoa/core/snd-aoa-gpio-feature.c
+@@ -56,7 +56,7 @@ static struct device_node *get_gpio(char
+ {
+ struct device_node *np, *gpio;
+ u32 *reg;
+- char *audio_gpio;
++ const char *audio_gpio;
+
+ *gpioptr = -1;
+
+@@ -283,9 +283,7 @@ static void ftr_gpio_exit(struct gpio_ru
+ mutex_destroy(&rt->line_out_notify.mutex);
+ }
+
+-static irqreturn_t ftr_handle_notify_irq(int xx,
+- void *data,
+- struct pt_regs *regs)
++static irqreturn_t ftr_handle_notify_irq(int xx, void *data)
+ {
+ struct gpio_notification *notif = data;
+
+diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+index 23190aa..e593a13 100644
+--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
++++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+@@ -93,7 +93,7 @@ static void i2sbus_release_dev(struct de
+ kfree(i2sdev);
+ }
+
+-static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t i2sbus_bus_intr(int irq, void *devid)
+ {
+ struct i2sbus_dev *dev = devid;
+ u32 intreg;
+@@ -165,8 +165,7 @@ static int i2sbus_add_dev(struct macio_d
+ static const char *rnames[] = { "i2sbus: %s (control)",
+ "i2sbus: %s (tx)",
+ "i2sbus: %s (rx)" };
+- static irqreturn_t (*ints[])(int irq, void *devid,
+- struct pt_regs *regs) = {
++ static irq_handler_t ints[] = {
+ i2sbus_bus_intr,
+ i2sbus_tx_intr,
+ i2sbus_rx_intr
+diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+index 3049015..5eff30b 100644
+--- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
++++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+@@ -642,13 +642,13 @@ static inline void handle_interrupt(stru
+ spin_unlock(&i2sdev->low_lock);
+ }
+
+-irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs)
++irqreturn_t i2sbus_tx_intr(int irq, void *devid)
+ {
+ handle_interrupt((struct i2sbus_dev *)devid, 0);
+ return IRQ_HANDLED;
+ }
+
+-irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs)
++irqreturn_t i2sbus_rx_intr(int irq, void *devid)
+ {
+ handle_interrupt((struct i2sbus_dev *)devid, 1);
+ return IRQ_HANDLED;
+diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
+index 0c69d20..ec20ee6 100644
+--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
++++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
+@@ -97,9 +97,9 @@ i2sbus_attach_codec(struct soundbus_dev
+ extern void
+ i2sbus_detach_codec(struct soundbus_dev *dev, void *data);
+ extern irqreturn_t
+-i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs);
++i2sbus_tx_intr(int irq, void *devid);
+ extern irqreturn_t
+-i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs);
++i2sbus_rx_intr(int irq, void *devid);
+
+ /* control specific functions */
+ extern int i2sbus_control_init(struct macio_dev* dev,
+diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
+index d31f814..f580942 100644
+--- a/sound/aoa/soundbus/sysfs.c
++++ b/sound/aoa/soundbus/sysfs.c
+@@ -1,4 +1,3 @@
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/stat.h>
+ /* FIX UP */
+diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
+index 8435fdd..53675cf 100644
+--- a/sound/arm/aaci.c
++++ b/sound/arm/aaci.c
+@@ -221,7 +221,7 @@ static void aaci_fifo_irq(struct aaci *a
+ }
+ }
+
+-static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t aaci_irq(int irq, void *devid)
+ {
+ struct aaci *aaci = devid;
+ u32 mask;
+diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
+index 599aff8..dede954 100644
+--- a/sound/arm/pxa2xx-ac97.c
++++ b/sound/arm/pxa2xx-ac97.c
+@@ -152,7 +152,7 @@ static void pxa2xx_ac97_reset(struct snd
+ GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+ }
+
+-static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
+ {
+ long status;
+
+diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
+index 4938ef1..e8cf904 100644
+--- a/sound/arm/pxa2xx-pcm.c
++++ b/sound/arm/pxa2xx-pcm.c
+@@ -137,7 +137,7 @@ static int pxa2xx_pcm_trigger(struct snd
+ return ret;
+ }
+
+-static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id, struct pt_regs *regs)
++static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
+ {
+ struct snd_pcm_substream *substream = dev_id;
+ struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+diff --git a/sound/core/control.c b/sound/core/control.c
+index bb397ea..48ef0a0 100644
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -75,6 +75,8 @@ static int snd_ctl_open(struct inode *in
+ init_waitqueue_head(&ctl->change_sleep);
+ spin_lock_init(&ctl->read_lock);
+ ctl->card = card;
++ ctl->prefer_pcm_subdevice = -1;
++ ctl->prefer_rawmidi_subdevice = -1;
+ ctl->pid = current->pid;
+ file->private_data = ctl;
+ write_lock_irqsave(&card->ctl_files_rwlock, flags);
+@@ -236,11 +238,16 @@ struct snd_kcontrol *snd_ctl_new1(const
+ kctl.id.index = ncontrol->index;
+ kctl.count = ncontrol->count ? ncontrol->count : 1;
+ access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+- (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+- SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));
++ (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
++ SNDRV_CTL_ELEM_ACCESS_INACTIVE|
++ SNDRV_CTL_ELEM_ACCESS_DINDIRECT|
++ SNDRV_CTL_ELEM_ACCESS_INDIRECT|
++ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
+ kctl.info = ncontrol->info;
+ kctl.get = ncontrol->get;
+ kctl.put = ncontrol->put;
++ kctl.tlv.p = ncontrol->tlv.p;
+ kctl.private_value = ncontrol->private_value;
+ kctl.private_data = private_data;
+ return snd_ctl_new(&kctl, access);
+@@ -882,6 +889,8 @@ struct user_element {
+ struct snd_ctl_elem_info info;
+ void *elem_data; /* element data */
+ unsigned long elem_data_size; /* size of element data in bytes */
++ void *tlv_data; /* TLV data */
++ unsigned long tlv_data_size; /* TLV data size */
+ void *priv_data; /* private data (like strings for enumerated type) */
+ unsigned long priv_data_size; /* size of private data in bytes */
+ };
+@@ -916,9 +925,48 @@ static int snd_ctl_elem_user_put(struct
+ return change;
+ }
+
++static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
++ int op_flag,
++ unsigned int size,
++ unsigned int __user *tlv)
++{
++ struct user_element *ue = kcontrol->private_data;
++ int change = 0;
++ void *new_data;
++
++ if (op_flag > 0) {
++ if (size > 1024 * 128) /* sane value */
++ return -EINVAL;
++ new_data = kmalloc(size, GFP_KERNEL);
++ if (new_data == NULL)
++ return -ENOMEM;
++ if (copy_from_user(new_data, tlv, size)) {
++ kfree(new_data);
++ return -EFAULT;
++ }
++ change = ue->tlv_data_size != size;
++ if (!change)
++ change = memcmp(ue->tlv_data, new_data, size);
++ kfree(ue->tlv_data);
++ ue->tlv_data = new_data;
++ ue->tlv_data_size = size;
++ } else {
++ if (! ue->tlv_data_size || ! ue->tlv_data)
++ return -ENXIO;
++ if (size < ue->tlv_data_size)
++ return -ENOSPC;
++ if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
++ return -EFAULT;
++ }
++ return change;
++}
++
+ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
+ {
+- kfree(kcontrol->private_data);
++ struct user_element *ue = kcontrol->private_data;
++ if (ue->tlv_data)
++ kfree(ue->tlv_data);
++ kfree(ue);
+ }
+
+ static int snd_ctl_elem_add(struct snd_ctl_file *file,
+@@ -937,7 +985,8 @@ static int snd_ctl_elem_add(struct snd_c
+ return -EINVAL;
+ access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+ (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+- SNDRV_CTL_ELEM_ACCESS_INACTIVE));
++ SNDRV_CTL_ELEM_ACCESS_INACTIVE|
++ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
+ info->id.numid = 0;
+ memset(&kctl, 0, sizeof(kctl));
+ down_write(&card->controls_rwsem);
+@@ -963,12 +1012,12 @@ static int snd_ctl_elem_add(struct snd_c
+ kctl.get = snd_ctl_elem_user_get;
+ if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
+ kctl.put = snd_ctl_elem_user_put;
++ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
++ kctl.tlv.c = snd_ctl_elem_user_tlv;
++ access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
++ }
+ switch (info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+- private_size = sizeof(char);
+- if (info->count > 128)
+- return -EINVAL;
+- break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ private_size = sizeof(long);
+ if (info->count > 128)
+@@ -997,6 +1046,7 @@ static int snd_ctl_elem_add(struct snd_c
+ if (ue == NULL)
+ return -ENOMEM;
+ ue->info = *info;
++ ue->info.access = 0;
+ ue->elem_data = (char *)ue + sizeof(*ue);
+ ue->elem_data_size = private_size;
+ kctl.private_free = snd_ctl_elem_user_free;
+@@ -1067,6 +1117,67 @@ static int snd_ctl_subscribe_events(stru
+ return 0;
+ }
+
++static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
++ struct snd_ctl_tlv __user *_tlv,
++ int op_flag)
++{
++ struct snd_card *card = file->card;
++ struct snd_ctl_tlv tlv;
++ struct snd_kcontrol *kctl;
++ struct snd_kcontrol_volatile *vd;
++ unsigned int len;
++ int err = 0;
++
++ if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
++ return -EFAULT;
++ if (tlv.length < sizeof(unsigned int) * 3)
++ return -EINVAL;
++ down_read(&card->controls_rwsem);
++ kctl = snd_ctl_find_numid(card, tlv.numid);
++ if (kctl == NULL) {
++ err = -ENOENT;
++ goto __kctl_end;
++ }
++ if (kctl->tlv.p == NULL) {
++ err = -ENXIO;
++ goto __kctl_end;
++ }
++ vd = &kctl->vd[tlv.numid - kctl->id.numid];
++ if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
++ (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
++ (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
++ err = -ENXIO;
++ goto __kctl_end;
++ }
++ if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
++ if (file && vd->owner != NULL && vd->owner != file) {
++ err = -EPERM;
++ goto __kctl_end;
++ }
++ err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
++ if (err > 0) {
++ up_read(&card->controls_rwsem);
++ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
++ return 0;
++ }
++ } else {
++ if (op_flag) {
++ err = -ENXIO;
++ goto __kctl_end;
++ }
++ len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
++ if (tlv.length < len) {
++ err = -ENOMEM;
++ goto __kctl_end;
++ }
++ if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
++ err = -EFAULT;
++ }
++ __kctl_end:
++ up_read(&card->controls_rwsem);
++ return err;
++}
++
+ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ struct snd_ctl_file *ctl;
+@@ -1086,11 +1197,11 @@ static long snd_ctl_ioctl(struct file *f
+ case SNDRV_CTL_IOCTL_CARD_INFO:
+ return snd_ctl_card_info(card, ctl, cmd, argp);
+ case SNDRV_CTL_IOCTL_ELEM_LIST:
+- return snd_ctl_elem_list(ctl->card, argp);
++ return snd_ctl_elem_list(card, argp);
+ case SNDRV_CTL_IOCTL_ELEM_INFO:
+ return snd_ctl_elem_info_user(ctl, argp);
+ case SNDRV_CTL_IOCTL_ELEM_READ:
+- return snd_ctl_elem_read_user(ctl->card, argp);
++ return snd_ctl_elem_read_user(card, argp);
+ case SNDRV_CTL_IOCTL_ELEM_WRITE:
+ return snd_ctl_elem_write_user(ctl, argp);
+ case SNDRV_CTL_IOCTL_ELEM_LOCK:
+@@ -1105,6 +1216,12 @@ static long snd_ctl_ioctl(struct file *f
+ return snd_ctl_elem_remove(ctl, argp);
+ case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
+ return snd_ctl_subscribe_events(ctl, ip);
++ case SNDRV_CTL_IOCTL_TLV_READ:
++ return snd_ctl_tlv_ioctl(ctl, argp, 0);
++ case SNDRV_CTL_IOCTL_TLV_WRITE:
++ return snd_ctl_tlv_ioctl(ctl, argp, 1);
++ case SNDRV_CTL_IOCTL_TLV_COMMAND:
++ return snd_ctl_tlv_ioctl(ctl, argp, -1);
+ case SNDRV_CTL_IOCTL_POWER:
+ return -ENOPROTOOPT;
+ case SNDRV_CTL_IOCTL_POWER_STATE:
+@@ -1338,6 +1455,11 @@ static int snd_ctl_dev_disconnect(struct
+ struct snd_card *card = device->device_data;
+ struct list_head *flist;
+ struct snd_ctl_file *ctl;
++ int err, cardnum;
++
++ snd_assert(card != NULL, return -ENXIO);
++ cardnum = card->number;
++ snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+
+ down_read(&card->controls_rwsem);
+ list_for_each(flist, &card->ctl_files) {
+@@ -1346,6 +1468,10 @@ static int snd_ctl_dev_disconnect(struct
+ kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
+ }
+ up_read(&card->controls_rwsem);
++
++ if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
++ card, -1)) < 0)
++ return err;
+ return 0;
+ }
+
+@@ -1367,23 +1493,6 @@ static int snd_ctl_dev_free(struct snd_d
+ }
+
+ /*
+- * de-registration of the control device
+- */
+-static int snd_ctl_dev_unregister(struct snd_device *device)
+-{
+- struct snd_card *card = device->device_data;
+- int err, cardnum;
+-
+- snd_assert(card != NULL, return -ENXIO);
+- cardnum = card->number;
+- snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+- if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
+- card, -1)) < 0)
+- return err;
+- return snd_ctl_dev_free(device);
+-}
+-
+-/*
+ * create control core:
+ * called from init.c
+ */
+@@ -1393,7 +1502,6 @@ int snd_ctl_create(struct snd_card *card
+ .dev_free = snd_ctl_dev_free,
+ .dev_register = snd_ctl_dev_register,
+ .dev_disconnect = snd_ctl_dev_disconnect,
+- .dev_unregister = snd_ctl_dev_unregister
+ };
+
+ snd_assert(card != NULL, return -ENXIO);
+diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
+index 3c0161b..ab48962 100644
+--- a/sound/core/control_compat.c
++++ b/sound/core/control_compat.c
+@@ -407,6 +407,10 @@ static inline long snd_ctl_ioctl_compat(
+ case SNDRV_CTL_IOCTL_POWER_STATE:
+ case SNDRV_CTL_IOCTL_ELEM_LOCK:
+ case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
++ case SNDRV_CTL_IOCTL_ELEM_REMOVE:
++ case SNDRV_CTL_IOCTL_TLV_READ:
++ case SNDRV_CTL_IOCTL_TLV_WRITE:
++ case SNDRV_CTL_IOCTL_TLV_COMMAND:
+ return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
+ case SNDRV_CTL_IOCTL_ELEM_LIST32:
+ return snd_ctl_elem_list_compat(ctl->card, argp);
+diff --git a/sound/core/device.c b/sound/core/device.c
+index 6ce4da4..ccb2581 100644
+--- a/sound/core/device.c
++++ b/sound/core/device.c
+@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new);
+ * @device_data: the data pointer to release
+ *
+ * Removes the device from the list on the card and invokes the
+- * callback, dev_unregister or dev_free, corresponding to the state.
++ * callbacks, dev_disconnect and dev_free, corresponding to the state.
+ * Then release the device.
+ *
+ * Returns zero if successful, or a negative error code on failure or if the
+@@ -90,16 +90,14 @@ int snd_device_free(struct snd_card *car
+ continue;
+ /* unlink */
+ list_del(&dev->list);
+- if ((dev->state == SNDRV_DEV_REGISTERED ||
+- dev->state == SNDRV_DEV_DISCONNECTED) &&
+- dev->ops->dev_unregister) {
+- if (dev->ops->dev_unregister(dev))
+- snd_printk(KERN_ERR "device unregister failure\n");
+- } else {
+- if (dev->ops->dev_free) {
+- if (dev->ops->dev_free(dev))
+- snd_printk(KERN_ERR "device free failure\n");
+- }
++ if (dev->state == SNDRV_DEV_REGISTERED &&
++ dev->ops->dev_disconnect)
++ if (dev->ops->dev_disconnect(dev))
++ snd_printk(KERN_ERR
++ "device disconnect failure\n");
++ if (dev->ops->dev_free) {
++ if (dev->ops->dev_free(dev))
++ snd_printk(KERN_ERR "device free failure\n");
+ }
+ kfree(dev);
+ return 0;
+diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
+index 8bd0dcc..46b4768 100644
+--- a/sound/core/hwdep.c
++++ b/sound/core/hwdep.c
+@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex);
+ static int snd_hwdep_free(struct snd_hwdep *hwdep);
+ static int snd_hwdep_dev_free(struct snd_device *device);
+ static int snd_hwdep_dev_register(struct snd_device *device);
+-static int snd_hwdep_dev_unregister(struct snd_device *device);
++static int snd_hwdep_dev_disconnect(struct snd_device *device);
+
+
+ static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
+@@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inod
+ {
+ int err = -ENXIO;
+ struct snd_hwdep *hw = file->private_data;
++ struct module *mod = hw->card->module;
+ mutex_lock(&hw->open_mutex);
+ if (hw->ops.release) {
+ err = hw->ops.release(hw, file);
+@@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inod
+ hw->used--;
+ snd_card_file_remove(hw->card, file);
+ mutex_unlock(&hw->open_mutex);
+- module_put(hw->card->module);
++ module_put(mod);
+ return err;
+ }
+
+@@ -353,7 +354,7 @@ int snd_hwdep_new(struct snd_card *card,
+ static struct snd_device_ops ops = {
+ .dev_free = snd_hwdep_dev_free,
+ .dev_register = snd_hwdep_dev_register,
+- .dev_unregister = snd_hwdep_dev_unregister
++ .dev_disconnect = snd_hwdep_dev_disconnect,
+ };
+
+ snd_assert(rhwdep != NULL, return -EINVAL);
+@@ -439,7 +440,7 @@ static int snd_hwdep_dev_register(struct
+ return 0;
+ }
+
+-static int snd_hwdep_dev_unregister(struct snd_device *device)
++static int snd_hwdep_dev_disconnect(struct snd_device *device)
+ {
+ struct snd_hwdep *hwdep = device->device_data;
+
+@@ -454,9 +455,9 @@ static int snd_hwdep_dev_unregister(stru
+ snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
+ #endif
+ snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
+- list_del(&hwdep->list);
++ list_del_init(&hwdep->list);
+ mutex_unlock(®ister_mutex);
+- return snd_hwdep_free(hwdep);
++ return 0;
+ }
+
+ #ifdef CONFIG_PROC_FS
+@@ -497,7 +498,7 @@ static void __init snd_hwdep_proc_init(v
+
+ static void __exit snd_hwdep_proc_done(void)
+ {
+- snd_info_unregister(snd_hwdep_proc_entry);
++ snd_info_free_entry(snd_hwdep_proc_entry);
+ }
+ #else /* !CONFIG_PROC_FS */
+ #define snd_hwdep_proc_init()
+diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c
+index 938f775..3827c0c 100644
+--- a/sound/core/hwdep_compat.c
++++ b/sound/core/hwdep_compat.c
+@@ -33,7 +33,7 @@ struct snd_hwdep_dsp_image32 {
+ static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw,
+ struct snd_hwdep_dsp_image32 __user *src)
+ {
+- struct snd_hwdep_dsp_image *dst;
++ struct snd_hwdep_dsp_image __user *dst;
+ compat_caddr_t ptr;
+ u32 val;
+
+diff --git a/sound/core/info.c b/sound/core/info.c
+index 340332c..0b4aab3 100644
+--- a/sound/core/info.c
++++ b/sound/core/info.c
+@@ -78,6 +78,7 @@ struct snd_info_private_data {
+
+ static int snd_info_version_init(void);
+ static int snd_info_version_done(void);
++static void snd_info_disconnect(struct snd_info_entry *entry);
+
+
+ /* resize the proc r/w buffer */
+@@ -119,7 +120,10 @@ int snd_iprintf(struct snd_info_buffer *
+ len = buffer->len - buffer->size;
+ va_start(args, fmt);
+ for (;;) {
+- res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args);
++ va_list ap;
++ va_copy(ap, args);
++ res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, ap);
++ va_end(ap);
+ if (res < len)
+ break;
+ err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
+@@ -174,15 +178,15 @@ static loff_t snd_info_entry_llseek(stru
+ switch (entry->content) {
+ case SNDRV_INFO_CONTENT_TEXT:
+ switch (orig) {
+- case 0: /* SEEK_SET */
++ case SEEK_SET:
+ file->f_pos = offset;
+ ret = file->f_pos;
+ goto out;
+- case 1: /* SEEK_CUR */
++ case SEEK_CUR:
+ file->f_pos += offset;
+ ret = file->f_pos;
+ goto out;
+- case 2: /* SEEK_END */
++ case SEEK_END:
+ default:
+ ret = -EINVAL;
+ goto out;
+@@ -304,7 +308,7 @@ static int snd_info_entry_open(struct in
+ mutex_lock(&info_mutex);
+ p = PDE(inode);
+ entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
+- if (entry == NULL || entry->disconnected) {
++ if (entry == NULL || ! entry->p) {
+ mutex_unlock(&info_mutex);
+ return -ENODEV;
+ }
+@@ -586,10 +590,10 @@ int __exit snd_info_done(void)
+ snd_info_version_done();
+ if (snd_proc_root) {
+ #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+- snd_info_unregister(snd_seq_root);
++ snd_info_free_entry(snd_seq_root);
+ #endif
+ #ifdef CONFIG_SND_OSSEMUL
+- snd_info_unregister(snd_oss_root);
++ snd_info_free_entry(snd_oss_root);
+ #endif
+ snd_remove_proc_entry(&proc_root, snd_proc_root);
+ }
+@@ -648,17 +652,28 @@ int snd_info_card_register(struct snd_ca
+ * de-register the card proc file
+ * called from init.c
+ */
+-int snd_info_card_free(struct snd_card *card)
++void snd_info_card_disconnect(struct snd_card *card)
+ {
+- snd_assert(card != NULL, return -ENXIO);
++ snd_assert(card != NULL, return);
++ mutex_lock(&info_mutex);
+ if (card->proc_root_link) {
+ snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
+ card->proc_root_link = NULL;
+ }
+- if (card->proc_root) {
+- snd_info_unregister(card->proc_root);
+- card->proc_root = NULL;
+- }
++ if (card->proc_root)
++ snd_info_disconnect(card->proc_root);
++ mutex_unlock(&info_mutex);
++}
++
++/*
++ * release the card proc file resources
++ * called from init.c
++ */
++int snd_info_card_free(struct snd_card *card)
++{
++ snd_assert(card != NULL, return -ENXIO);
++ snd_info_free_entry(card->proc_root);
++ card->proc_root = NULL;
+ return 0;
+ }
+
+@@ -767,6 +782,8 @@ static struct snd_info_entry *snd_info_c
+ entry->mode = S_IFREG | S_IRUGO;
+ entry->content = SNDRV_INFO_CONTENT_TEXT;
+ mutex_init(&entry->access);
++ INIT_LIST_HEAD(&entry->children);
++ INIT_LIST_HEAD(&entry->list);
+ return entry;
+ }
+
+@@ -819,30 +836,35 @@ struct snd_info_entry *snd_info_create_c
+
+ EXPORT_SYMBOL(snd_info_create_card_entry);
+
+-static int snd_info_dev_free_entry(struct snd_device *device)
++static void snd_info_disconnect(struct snd_info_entry *entry)
+ {
+- struct snd_info_entry *entry = device->device_data;
+- snd_info_free_entry(entry);
+- return 0;
+-}
++ struct list_head *p, *n;
++ struct proc_dir_entry *root;
+
+-static int snd_info_dev_register_entry(struct snd_device *device)
+-{
+- struct snd_info_entry *entry = device->device_data;
+- return snd_info_register(entry);
++ list_for_each_safe(p, n, &entry->children) {
++ snd_info_disconnect(list_entry(p, struct snd_info_entry, list));
++ }
++
++ if (! entry->p)
++ return;
++ list_del_init(&entry->list);
++ root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
++ snd_assert(root, return);
++ snd_remove_proc_entry(root, entry->p);
++ entry->p = NULL;
+ }
+
+-static int snd_info_dev_disconnect_entry(struct snd_device *device)
++static int snd_info_dev_free_entry(struct snd_device *device)
+ {
+ struct snd_info_entry *entry = device->device_data;
+- entry->disconnected = 1;
++ snd_info_free_entry(entry);
+ return 0;
+ }
+
+-static int snd_info_dev_unregister_entry(struct snd_device *device)
++static int snd_info_dev_register_entry(struct snd_device *device)
+ {
+ struct snd_info_entry *entry = device->device_data;
+- return snd_info_unregister(entry);
++ return snd_info_register(entry);
+ }
+
+ /**
+@@ -871,8 +893,7 @@ int snd_card_proc_new(struct snd_card *c
+ static struct snd_device_ops ops = {
+ .dev_free = snd_info_dev_free_entry,
+ .dev_register = snd_info_dev_register_entry,
+- .dev_disconnect = snd_info_dev_disconnect_entry,
+- .dev_unregister = snd_info_dev_unregister_entry
++ /* disconnect is done via snd_info_card_disconnect() */
+ };
+ struct snd_info_entry *entry;
+ int err;
+@@ -901,6 +922,11 @@ void snd_info_free_entry(struct snd_info
+ {
+ if (entry == NULL)
+ return;
++ if (entry->p) {
++ mutex_lock(&info_mutex);
++ snd_info_disconnect(entry);
++ mutex_unlock(&info_mutex);
++ }
+ kfree(entry->name);
+ if (entry->private_free)
+ entry->private_free(entry);
+@@ -935,38 +961,14 @@ int snd_info_register(struct snd_info_en
+ p->size = entry->size;
+ p->data = entry;
+ entry->p = p;
++ if (entry->parent)
++ list_add_tail(&entry->list, &entry->parent->children);
+ mutex_unlock(&info_mutex);
+ return 0;
+ }
+
+ EXPORT_SYMBOL(snd_info_register);
+
+-/**
+- * snd_info_unregister - de-register the info entry
+- * @entry: the info entry
+- *
+- * De-registers the info entry and releases the instance.
+- *
+- * Returns zero if successful, or a negative error code on failure.
+- */
+-int snd_info_unregister(struct snd_info_entry * entry)
+-{
+- struct proc_dir_entry *root;
+-
+- if (! entry)
+- return 0;
+- snd_assert(entry->p != NULL, return -ENXIO);
+- root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
+- snd_assert(root, return -ENXIO);
+- mutex_lock(&info_mutex);
+- snd_remove_proc_entry(root, entry->p);
+- mutex_unlock(&info_mutex);
+- snd_info_free_entry(entry);
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(snd_info_unregister);
+-
+ /*
+
+ */
+@@ -999,8 +1001,7 @@ static int __init snd_info_version_init(
+
+ static int __exit snd_info_version_done(void)
+ {
+- if (snd_info_version_entry)
+- snd_info_unregister(snd_info_version_entry);
++ snd_info_free_entry(snd_info_version_entry);
+ return 0;
+ }
+
+diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
+index bb2c40d..a444bfe 100644
+--- a/sound/core/info_oss.c
++++ b/sound/core/info_oss.c
+@@ -96,11 +96,11 @@ static void snd_sndstat_proc_read(struct
+ {
+ snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
+ snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
+- system_utsname.sysname,
+- system_utsname.nodename,
+- system_utsname.release,
+- system_utsname.version,
+- system_utsname.machine);
++ init_utsname()->sysname,
++ init_utsname()->nodename,
++ init_utsname()->release,
++ init_utsname()->version,
++ init_utsname()->machine);
+ snd_iprintf(buffer, "Config options: 0\n");
+ snd_iprintf(buffer, "\nInstalled drivers: \n");
+ snd_iprintf(buffer, "Type 10: ALSA emulation\n");
+@@ -131,10 +131,8 @@ int snd_info_minor_register(void)
+
+ int snd_info_minor_unregister(void)
+ {
+- if (snd_sndstat_proc_entry) {
+- snd_info_unregister(snd_sndstat_proc_entry);
+- snd_sndstat_proc_entry = NULL;
+- }
++ snd_info_free_entry(snd_sndstat_proc_entry);
++ snd_sndstat_proc_entry = NULL;
+ return 0;
+ }
+
+diff --git a/sound/core/init.c b/sound/core/init.c
+index 4d92588..3058d62 100644
+--- a/sound/core/init.c
++++ b/sound/core/init.c
+@@ -33,10 +33,10 @@
+ #include <sound/control.h>
+ #include <sound/info.h>
+
+-struct snd_shutdown_f_ops {
+- struct file_operations f_ops;
+- struct snd_shutdown_f_ops *next;
+-};
++static DEFINE_SPINLOCK(shutdown_lock);
++static LIST_HEAD(shutdown_files);
++
++static struct file_operations snd_shutdown_f_ops;
+
+ static unsigned int snd_cards_lock; /* locked for registering/using */
+ struct snd_card *snd_cards[SNDRV_CARDS];
+@@ -81,8 +81,6 @@ static inline int init_info_for_card(str
+ #define init_info_for_card(card)
+ #endif
+
+-static void snd_card_free_thread(void * __card);
+-
+ /**
+ * snd_card_new - create and initialize a soundcard structure
+ * @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
+@@ -145,7 +143,6 @@ struct snd_card *snd_card_new(int idx, c
+ INIT_LIST_HEAD(&card->ctl_files);
+ spin_lock_init(&card->files_lock);
+ init_waitqueue_head(&card->shutdown_sleep);
+- INIT_WORK(&card->free_workq, snd_card_free_thread, card);
+ #ifdef CONFIG_PM
+ mutex_init(&card->power_lock);
+ init_waitqueue_head(&card->power_sleep);
+@@ -201,6 +198,25 @@ static ssize_t snd_disconnect_write(stru
+ return -ENODEV;
+ }
+
++static int snd_disconnect_release(struct inode *inode, struct file *file)
++{
++ struct snd_monitor_file *df = NULL, *_df;
++
++ spin_lock(&shutdown_lock);
++ list_for_each_entry(_df, &shutdown_files, shutdown_list) {
++ if (_df->file == file) {
++ df = _df;
++ break;
++ }
++ }
++ spin_unlock(&shutdown_lock);
++
++ if (likely(df))
++ return df->disconnected_f_op->release(inode, file);
++
++ panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
++}
++
+ static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
+ {
+ return POLLERR | POLLNVAL;
+@@ -222,6 +238,22 @@ static int snd_disconnect_fasync(int fd,
+ return -ENODEV;
+ }
+
++static struct file_operations snd_shutdown_f_ops =
++{
++ .owner = THIS_MODULE,
++ .llseek = snd_disconnect_llseek,
++ .read = snd_disconnect_read,
++ .write = snd_disconnect_write,
++ .release = snd_disconnect_release,
++ .poll = snd_disconnect_poll,
++ .unlocked_ioctl = snd_disconnect_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = snd_disconnect_ioctl,
++#endif
++ .mmap = snd_disconnect_mmap,
++ .fasync = snd_disconnect_fasync
++};
++
+ /**
+ * snd_card_disconnect - disconnect all APIs from the file-operations (user space)
+ * @card: soundcard structure
+@@ -237,9 +269,6 @@ int snd_card_disconnect(struct snd_card
+ {
+ struct snd_monitor_file *mfile;
+ struct file *file;
+- struct snd_shutdown_f_ops *s_f_ops;
+- struct file_operations *f_ops;
+- const struct file_operations *old_f_ops;
+ int err;
+
+ spin_lock(&card->files_lock);
+@@ -264,34 +293,14 @@ int snd_card_disconnect(struct snd_card
+
+ /* it's critical part, use endless loop */
+ /* we have no room to fail */
+- s_f_ops = kmalloc(sizeof(struct snd_shutdown_f_ops), GFP_ATOMIC);
+- if (s_f_ops == NULL)
+- panic("Atomic allocation failed for snd_shutdown_f_ops!");
+-
+- f_ops = &s_f_ops->f_ops;
+-
+- memset(f_ops, 0, sizeof(*f_ops));
+- f_ops->owner = file->f_op->owner;
+- f_ops->release = file->f_op->release;
+- f_ops->llseek = snd_disconnect_llseek;
+- f_ops->read = snd_disconnect_read;
+- f_ops->write = snd_disconnect_write;
+- f_ops->poll = snd_disconnect_poll;
+- f_ops->unlocked_ioctl = snd_disconnect_ioctl;
+-#ifdef CONFIG_COMPAT
+- f_ops->compat_ioctl = snd_disconnect_ioctl;
+-#endif
+- f_ops->mmap = snd_disconnect_mmap;
+- f_ops->fasync = snd_disconnect_fasync;
++ mfile->disconnected_f_op = mfile->file->f_op;
+
+- s_f_ops->next = card->s_f_ops;
+- card->s_f_ops = s_f_ops;
+-
+- f_ops = fops_get(f_ops);
++ spin_lock(&shutdown_lock);
++ list_add(&mfile->shutdown_list, &shutdown_files);
++ spin_unlock(&shutdown_lock);
+
+- old_f_ops = file->f_op;
+- file->f_op = f_ops; /* must be atomic */
+- fops_put(old_f_ops);
++ fops_get(&snd_shutdown_f_ops);
++ mfile->file->f_op = &snd_shutdown_f_ops;
+
+ mfile = mfile->next;
+ }
+@@ -310,6 +319,7 @@ int snd_card_disconnect(struct snd_card
+ if (err < 0)
+ snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
+
++ snd_info_card_disconnect(card);
+ return 0;
+ }
+
+@@ -326,22 +336,8 @@ EXPORT_SYMBOL(snd_card_disconnect);
+ * Returns zero. Frees all associated devices and frees the control
+ * interface associated to given soundcard.
+ */
+-int snd_card_free(struct snd_card *card)
++static int snd_card_do_free(struct snd_card *card)
+ {
+- struct snd_shutdown_f_ops *s_f_ops;
+-
+- if (card == NULL)
+- return -EINVAL;
+- mutex_lock(&snd_card_mutex);
+- snd_cards[card->number] = NULL;
+- mutex_unlock(&snd_card_mutex);
+-
+-#ifdef CONFIG_PM
+- wake_up(&card->power_sleep);
+-#endif
+- /* wait, until all devices are ready for the free operation */
+- wait_event(card->shutdown_sleep, card->files == NULL);
+-
+ #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+ if (snd_mixer_oss_notify_callback)
+ snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
+@@ -360,71 +356,64 @@ int snd_card_free(struct snd_card *card)
+ }
+ if (card->private_free)
+ card->private_free(card);
+- snd_info_unregister(card->proc_id);
++ snd_info_free_entry(card->proc_id);
+ if (snd_info_card_free(card) < 0) {
+ snd_printk(KERN_WARNING "unable to free card info\n");
+ /* Not fatal error */
+ }
+- while (card->s_f_ops) {
+- s_f_ops = card->s_f_ops;
+- card->s_f_ops = s_f_ops->next;
+- kfree(s_f_ops);
+- }
++ kfree(card);
++ return 0;
++}
++
++static int snd_card_free_prepare(struct snd_card *card)
++{
++ if (card == NULL)
++ return -EINVAL;
++ (void) snd_card_disconnect(card);
+ mutex_lock(&snd_card_mutex);
++ snd_cards[card->number] = NULL;
+ snd_cards_lock &= ~(1 << card->number);
+ mutex_unlock(&snd_card_mutex);
+- kfree(card);
++#ifdef CONFIG_PM
++ wake_up(&card->power_sleep);
++#endif
+ return 0;
+ }
+
+-EXPORT_SYMBOL(snd_card_free);
+-
+-static void snd_card_free_thread(void * __card)
++int snd_card_free_when_closed(struct snd_card *card)
+ {
+- struct snd_card *card = __card;
+- struct module * module = card->module;
+-
+- if (!try_module_get(module)) {
+- snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
+- module = NULL;
+- }
++ int free_now = 0;
++ int ret = snd_card_free_prepare(card);
++ if (ret)
++ return ret;
+
+- snd_card_free(card);
++ spin_lock(&card->files_lock);
++ if (card->files == NULL)
++ free_now = 1;
++ else
++ card->free_on_last_close = 1;
++ spin_unlock(&card->files_lock);
+
+- module_put(module);
++ if (free_now)
++ snd_card_do_free(card);
++ return 0;
+ }
+
+-/**
+- * snd_card_free_in_thread - call snd_card_free() in thread
+- * @card: soundcard structure
+- *
+- * This function schedules the call of snd_card_free() function in a
+- * work queue. When all devices are released (non-busy), the work
+- * is woken up and calls snd_card_free().
+- *
+- * When a card can be disconnected at any time by hotplug service,
+- * this function should be used in disconnect (or detach) callback
+- * instead of calling snd_card_free() directly.
+- *
+- * Returns - zero otherwise a negative error code if the start of thread failed.
+- */
+-int snd_card_free_in_thread(struct snd_card *card)
+-{
+- if (card->files == NULL) {
+- snd_card_free(card);
+- return 0;
+- }
++EXPORT_SYMBOL(snd_card_free_when_closed);
+
+- if (schedule_work(&card->free_workq))
+- return 0;
++int snd_card_free(struct snd_card *card)
++{
++ int ret = snd_card_free_prepare(card);
++ if (ret)
++ return ret;
+
+- snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number);
+- /* try to free the structure immediately */
+- snd_card_free(card);
+- return -EFAULT;
++ /* wait, until all devices are ready for the free operation */
++ wait_event(card->shutdown_sleep, card->files == NULL);
++ snd_card_do_free(card);
++ return 0;
+ }
+
+-EXPORT_SYMBOL(snd_card_free_in_thread);
++EXPORT_SYMBOL(snd_card_free);
+
+ static void choose_default_id(struct snd_card *card)
+ {
+@@ -625,9 +614,9 @@ int __init snd_card_info_init(void)
+
+ int __exit snd_card_info_done(void)
+ {
+- snd_info_unregister(snd_card_info_entry);
++ snd_info_free_entry(snd_card_info_entry);
+ #ifdef MODULE
+- snd_info_unregister(snd_card_module_info_entry);
++ snd_info_free_entry(snd_card_module_info_entry);
+ #endif
+ return 0;
+ }
+@@ -686,6 +675,7 @@ int snd_card_file_add(struct snd_card *c
+ if (mfile == NULL)
+ return -ENOMEM;
+ mfile->file = file;
++ mfile->disconnected_f_op = NULL;
+ mfile->next = NULL;
+ spin_lock(&card->files_lock);
+ if (card->shutdown) {
+@@ -708,15 +698,16 @@ EXPORT_SYMBOL(snd_card_file_add);
+ *
+ * This function removes the file formerly added to the card via
+ * snd_card_file_add() function.
+- * If all files are removed and the release of the card is
+- * scheduled, it will wake up the the thread to call snd_card_free()
+- * (see snd_card_free_in_thread() function).
++ * If all files are removed and snd_card_free_when_closed() was
++ * called beforehand, it processes the pending release of
++ * resources.
+ *
+ * Returns zero or a negative error code.
+ */
+ int snd_card_file_remove(struct snd_card *card, struct file *file)
+ {
+ struct snd_monitor_file *mfile, *pfile = NULL;
++ int last_close = 0;
+
+ spin_lock(&card->files_lock);
+ mfile = card->files;
+@@ -731,9 +722,20 @@ int snd_card_file_remove(struct snd_card
+ pfile = mfile;
+ mfile = mfile->next;
+ }
+- spin_unlock(&card->files_lock);
++ if (mfile && mfile->disconnected_f_op) {
++ fops_put(mfile->disconnected_f_op);
++ spin_lock(&shutdown_lock);
++ list_del(&mfile->shutdown_list);
++ spin_unlock(&shutdown_lock);
++ }
+ if (card->files == NULL)
++ last_close = 1;
++ spin_unlock(&card->files_lock);
++ if (last_close) {
+ wake_up(&card->shutdown_sleep);
++ if (card->free_on_last_close)
++ snd_card_do_free(card);
++ }
+ if (!mfile) {
+ snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
+ return -ENOENT;
+diff --git a/sound/core/memory.c b/sound/core/memory.c
+index fe59850..93537ab 100644
+--- a/sound/core/memory.c
++++ b/sound/core/memory.c
+@@ -20,7 +20,6 @@
+ *
+ */
+
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
+index 75a9505..f4c6704 100644
+--- a/sound/core/oss/mixer_oss.c
++++ b/sound/core/oss/mixer_oss.c
+@@ -1193,10 +1193,8 @@ static void snd_mixer_oss_proc_init(stru
+
+ static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
+ {
+- if (mixer->proc_entry) {
+- snd_info_unregister(mixer->proc_entry);
+- mixer->proc_entry = NULL;
+- }
++ snd_info_free_entry(mixer->proc_entry);
++ mixer->proc_entry = NULL;
+ }
+ #else /* !CONFIG_PROC_FS */
+ #define snd_mixer_oss_proc_init(mix)
+@@ -1312,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(
+ card->mixer_oss = mixer;
+ snd_mixer_oss_build(mixer);
+ snd_mixer_oss_proc_init(mixer);
+- } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
+- mixer = card->mixer_oss;
+- if (mixer == NULL || !mixer->oss_dev_alloc)
+- return 0;
+- snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
+- mixer->oss_dev_alloc = 0;
+- } else { /* free */
++ } else {
+ mixer = card->mixer_oss;
+ if (mixer == NULL)
+ return 0;
++ if (mixer->oss_dev_alloc) {
+ #ifdef SNDRV_OSS_INFO_DEV_MIXERS
+- snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
++ snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
+ #endif
+- if (mixer->oss_dev_alloc)
+ snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
++ mixer->oss_dev_alloc = 0;
++ }
++ if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
++ return 0;
+ snd_mixer_oss_proc_done(mixer);
+ return snd_mixer_oss_free1(mixer);
+ }
+diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
+index 472fce0..505b23e 100644
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -2846,11 +2846,9 @@ static void snd_pcm_oss_proc_done(struct
+ int stream;
+ for (stream = 0; stream < 2; ++stream) {
+ struct snd_pcm_str *pstr = &pcm->streams[stream];
+- if (pstr->oss.proc_entry) {
+- snd_info_unregister(pstr->oss.proc_entry);
+- pstr->oss.proc_entry = NULL;
+- snd_pcm_oss_proc_free_setup_list(pstr);
+- }
++ snd_info_free_entry(pstr->oss.proc_entry);
++ pstr->oss.proc_entry = NULL;
++ snd_pcm_oss_proc_free_setup_list(pstr);
+ }
+ }
+ #else /* !CONFIG_SND_VERBOSE_PROCFS */
+@@ -2931,25 +2929,23 @@ static int snd_pcm_oss_disconnect_minor(
+ snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
+ pcm->card, 1);
+ }
+- }
+- return 0;
+-}
+-
+-static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
+-{
+- snd_pcm_oss_disconnect_minor(pcm);
+- if (pcm->oss.reg) {
+ if (dsp_map[pcm->card->number] == (int)pcm->device) {
+ #ifdef SNDRV_OSS_INFO_DEV_AUDIO
+ snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
+ #endif
+ }
+ pcm->oss.reg = 0;
+- snd_pcm_oss_proc_done(pcm);
+ }
+ return 0;
+ }
+
++static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
++{
++ snd_pcm_oss_disconnect_minor(pcm);
++ snd_pcm_oss_proc_done(pcm);
++ return 0;
++}
++
+ static struct snd_pcm_notify snd_pcm_oss_notify =
+ {
+ .n_register = snd_pcm_oss_register_minor,
+diff --git a/sound/core/pcm.c b/sound/core/pcm.c
+index 7581edd..fbbbcd2 100644
+--- a/sound/core/pcm.c
++++ b/sound/core/pcm.c
+@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *
+ static int snd_pcm_dev_free(struct snd_device *device);
+ static int snd_pcm_dev_register(struct snd_device *device);
+ static int snd_pcm_dev_disconnect(struct snd_device *device);
+-static int snd_pcm_dev_unregister(struct snd_device *device);
+
+ static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
+ {
+@@ -494,19 +493,13 @@ static int snd_pcm_stream_proc_init(stru
+ static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
+ {
+ #ifdef CONFIG_SND_PCM_XRUN_DEBUG
+- if (pstr->proc_xrun_debug_entry) {
+- snd_info_unregister(pstr->proc_xrun_debug_entry);
+- pstr->proc_xrun_debug_entry = NULL;
+- }
++ snd_info_free_entry(pstr->proc_xrun_debug_entry);
++ pstr->proc_xrun_debug_entry = NULL;
+ #endif
+- if (pstr->proc_info_entry) {
+- snd_info_unregister(pstr->proc_info_entry);
+- pstr->proc_info_entry = NULL;
+- }
+- if (pstr->proc_root) {
+- snd_info_unregister(pstr->proc_root);
+- pstr->proc_root = NULL;
+- }
++ snd_info_free_entry(pstr->proc_info_entry);
++ pstr->proc_info_entry = NULL;
++ snd_info_free_entry(pstr->proc_root);
++ pstr->proc_root = NULL;
+ return 0;
+ }
+
+@@ -570,29 +563,19 @@ static int snd_pcm_substream_proc_init(s
+
+ return 0;
+ }
+-
++
+ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
+ {
+- if (substream->proc_info_entry) {
+- snd_info_unregister(substream->proc_info_entry);
+- substream->proc_info_entry = NULL;
+- }
+- if (substream->proc_hw_params_entry) {
+- snd_info_unregister(substream->proc_hw_params_entry);
+- substream->proc_hw_params_entry = NULL;
+- }
+- if (substream->proc_sw_params_entry) {
+- snd_info_unregister(substream->proc_sw_params_entry);
+- substream->proc_sw_params_entry = NULL;
+- }
+- if (substream->proc_status_entry) {
+- snd_info_unregister(substream->proc_status_entry);
+- substream->proc_status_entry = NULL;
+- }
+- if (substream->proc_root) {
+- snd_info_unregister(substream->proc_root);
+- substream->proc_root = NULL;
+- }
++ snd_info_free_entry(substream->proc_info_entry);
++ substream->proc_info_entry = NULL;
++ snd_info_free_entry(substream->proc_hw_params_entry);
++ substream->proc_hw_params_entry = NULL;
++ snd_info_free_entry(substream->proc_sw_params_entry);
++ substream->proc_sw_params_entry = NULL;
++ snd_info_free_entry(substream->proc_status_entry);
++ substream->proc_status_entry = NULL;
++ snd_info_free_entry(substream->proc_root);
++ substream->proc_root = NULL;
+ return 0;
+ }
+ #else /* !CONFIG_SND_VERBOSE_PROCFS */
+@@ -646,6 +629,9 @@ int snd_pcm_new_stream(struct snd_pcm *p
+ substream->number = idx;
+ substream->stream = stream;
+ sprintf(substream->name, "subdevice #%i", idx);
++ snprintf(substream->latency_id, sizeof(substream->latency_id),
++ "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
++ (stream ? 'c' : 'p'), idx);
+ substream->buffer_bytes_max = UINT_MAX;
+ if (prev == NULL)
+ pstr->substream = substream;
+@@ -696,7 +682,6 @@ int snd_pcm_new(struct snd_card *card, c
+ .dev_free = snd_pcm_dev_free,
+ .dev_register = snd_pcm_dev_register,
+ .dev_disconnect = snd_pcm_dev_disconnect,
+- .dev_unregister = snd_pcm_dev_unregister
+ };
+
+ snd_assert(rpcm != NULL, return -EINVAL);
+@@ -740,6 +725,7 @@ static void snd_pcm_free_stream(struct s
+ substream = pstr->substream;
+ while (substream) {
+ substream_next = substream->next;
++ snd_pcm_timer_done(substream);
+ snd_pcm_substream_proc_done(substream);
+ kfree(substream);
+ substream = substream_next;
+@@ -756,7 +742,12 @@ static void snd_pcm_free_stream(struct s
+
+ static int snd_pcm_free(struct snd_pcm *pcm)
+ {
++ struct snd_pcm_notify *notify;
++
+ snd_assert(pcm != NULL, return -ENXIO);
++ list_for_each_entry(notify, &snd_pcm_notify_list, list) {
++ notify->n_unregister(pcm);
++ }
+ if (pcm->private_free)
+ pcm->private_free(pcm);
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+@@ -804,7 +795,8 @@ int snd_pcm_attach_substream(struct snd_
+ kctl = snd_ctl_file(list);
+ if (kctl->pid == current->pid) {
+ prefer_subdevice = kctl->prefer_pcm_subdevice;
+- break;
++ if (prefer_subdevice != -1)
++ break;
+ }
+ }
+ up_read(&card->controls_rwsem);
+@@ -918,6 +910,28 @@ void snd_pcm_detach_substream(struct snd
+ substream->pstr->substream_opened--;
+ }
+
++static ssize_t show_pcm_class(struct class_device *class_device, char *buf)
++{
++ struct snd_pcm *pcm;
++ const char *str;
++ static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
++ [SNDRV_PCM_CLASS_GENERIC] = "generic",
++ [SNDRV_PCM_CLASS_MULTI] = "multi",
++ [SNDRV_PCM_CLASS_MODEM] = "modem",
++ [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
++ };
++
++ if (! (pcm = class_get_devdata(class_device)) ||
++ pcm->dev_class > SNDRV_PCM_CLASS_LAST)
++ str = "none";
++ else
++ str = strs[pcm->dev_class];
++ return snprintf(buf, PAGE_SIZE, "%s\n", str);
++}
++
++static struct class_device_attribute pcm_attrs =
++ __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
++
+ static int snd_pcm_dev_register(struct snd_device *device)
+ {
+ int cidx, err;
+@@ -956,6 +970,8 @@ static int snd_pcm_dev_register(struct s
+ mutex_unlock(®ister_mutex);
+ return err;
+ }
++ snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
++ &pcm_attrs);
+ for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
+ snd_pcm_timer_init(substream);
+ }
+@@ -971,35 +987,22 @@ static int snd_pcm_dev_register(struct s
+ static int snd_pcm_dev_disconnect(struct snd_device *device)
+ {
+ struct snd_pcm *pcm = device->device_data;
+- struct list_head *list;
++ struct snd_pcm_notify *notify;
+ struct snd_pcm_substream *substream;
+- int cidx;
++ int cidx, devtype;
+
+ mutex_lock(®ister_mutex);
++ if (list_empty(&pcm->list))
++ goto unlock;
++
+ list_del_init(&pcm->list);
+ for (cidx = 0; cidx < 2; cidx++)
+ for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
+ if (substream->runtime)
+ substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
+- list_for_each(list, &snd_pcm_notify_list) {
+- struct snd_pcm_notify *notify;
+- notify = list_entry(list, struct snd_pcm_notify, list);
++ list_for_each_entry(notify, &snd_pcm_notify_list, list) {
+ notify->n_disconnect(pcm);
+ }
+- mutex_unlock(®ister_mutex);
+- return 0;
+-}
+-
+-static int snd_pcm_dev_unregister(struct snd_device *device)
+-{
+- int cidx, devtype;
+- struct snd_pcm_substream *substream;
+- struct list_head *list;
+- struct snd_pcm *pcm = device->device_data;
+-
+- snd_assert(pcm != NULL, return -ENXIO);
+- mutex_lock(®ister_mutex);
+- list_del(&pcm->list);
+ for (cidx = 0; cidx < 2; cidx++) {
+ devtype = -1;
+ switch (cidx) {
+@@ -1011,23 +1014,20 @@ static int snd_pcm_dev_unregister(struct
+ break;
+ }
+ snd_unregister_device(devtype, pcm->card, pcm->device);
+- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
+- snd_pcm_timer_done(substream);
+- }
+- list_for_each(list, &snd_pcm_notify_list) {
+- struct snd_pcm_notify *notify;
+- notify = list_entry(list, struct snd_pcm_notify, list);
+- notify->n_unregister(pcm);
+ }
++ unlock:
+ mutex_unlock(®ister_mutex);
+- return snd_pcm_free(pcm);
++ return 0;
+ }
+
+ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
+ {
+ struct list_head *p;
+
+- snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
++ snd_assert(notify != NULL &&
++ notify->n_register != NULL &&
++ notify->n_unregister != NULL &&
++ notify->n_disconnect, return -EINVAL);
+ mutex_lock(®ister_mutex);
+ if (nfree) {
+ list_del(¬ify->list);
+@@ -1090,8 +1090,7 @@ static void snd_pcm_proc_init(void)
+
+ static void snd_pcm_proc_done(void)
+ {
+- if (snd_pcm_proc_entry)
+- snd_info_unregister(snd_pcm_proc_entry);
++ snd_info_free_entry(snd_pcm_proc_entry);
+ }
+
+ #else /* !CONFIG_PROC_FS */
+diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
+index 2b8aab6..2b53979 100644
+--- a/sound/core/pcm_compat.c
++++ b/sound/core/pcm_compat.c
+@@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct
+ * mmap of PCM status/control records because of the size
+ * incompatibility.
+ */
+- substream->no_mmap_ctrl = 1;
++ pcm_file->no_compat_mmap = 1;
+
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL_PVERSION:
+diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
+index 067d205..be030cb 100644
+--- a/sound/core/pcm_memory.c
++++ b/sound/core/pcm_memory.c
+@@ -101,7 +101,7 @@ int snd_pcm_lib_preallocate_free(struct
+ {
+ snd_pcm_lib_preallocate_dma_free(substream);
+ #ifdef CONFIG_SND_VERBOSE_PROCFS
+- snd_info_unregister(substream->proc_prealloc_entry);
++ snd_info_free_entry(substream->proc_prealloc_entry);
+ substream->proc_prealloc_entry = NULL;
+ #endif
+ return 0;
+diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
+index 439f047..37b4b10 100644
+--- a/sound/core/pcm_native.c
++++ b/sound/core/pcm_native.c
+@@ -25,6 +25,7 @@
+ #include <linux/file.h>
+ #include <linux/slab.h>
+ #include <linux/time.h>
++#include <linux/latency.h>
+ #include <linux/uio.h>
+ #include <sound/core.h>
+ #include <sound/control.h>
+@@ -347,11 +348,26 @@ out:
+ return err;
+ }
+
++static int period_to_usecs(struct snd_pcm_runtime *runtime)
++{
++ int usecs;
++
++ if (! runtime->rate)
++ return -1; /* invalid */
++
++ /* take 75% of period time as the deadline */
++ usecs = (750000 / runtime->rate) * runtime->period_size;
++ usecs += ((750000 % runtime->rate) * runtime->period_size) /
++ runtime->rate;
++
++ return usecs;
++}
++
+ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+ {
+ struct snd_pcm_runtime *runtime;
+- int err;
++ int err, usecs;
+ unsigned int bits;
+ snd_pcm_uframes_t frames;
+
+@@ -431,6 +447,10 @@ static int snd_pcm_hw_params(struct snd_
+
+ snd_pcm_timer_resolution_change(substream);
+ runtime->status->state = SNDRV_PCM_STATE_SETUP;
++
++ remove_acceptable_latency(substream->latency_id);
++ if ((usecs = period_to_usecs(runtime)) >= 0)
++ set_acceptable_latency(substream->latency_id, usecs);
+ return 0;
+ _error:
+ /* hardware might be unuseable from this time,
+@@ -490,6 +510,7 @@ static int snd_pcm_hw_free(struct snd_pc
+ if (substream->ops->hw_free)
+ result = substream->ops->hw_free(substream);
+ runtime->status->state = SNDRV_PCM_STATE_OPEN;
++ remove_acceptable_latency(substream->latency_id);
+ return result;
+ }
+
+@@ -1992,35 +2013,9 @@ int snd_pcm_hw_constraints_complete(stru
+ return 0;
+ }
+
+-static void snd_pcm_add_file(struct snd_pcm_str *str,
+- struct snd_pcm_file *pcm_file)
+-{
+- pcm_file->next = str->files;
+- str->files = pcm_file;
+-}
+-
+-static void snd_pcm_remove_file(struct snd_pcm_str *str,
+- struct snd_pcm_file *pcm_file)
+-{
+- struct snd_pcm_file * pcm_file1;
+- if (str->files == pcm_file) {
+- str->files = pcm_file->next;
+- } else {
+- pcm_file1 = str->files;
+- while (pcm_file1 && pcm_file1->next != pcm_file)
+- pcm_file1 = pcm_file1->next;
+- if (pcm_file1 != NULL)
+- pcm_file1->next = pcm_file->next;
+- }
+-}
+-
+ static void pcm_release_private(struct snd_pcm_substream *substream)
+ {
+- struct snd_pcm_file *pcm_file = substream->file;
+-
+ snd_pcm_unlink(substream);
+- snd_pcm_remove_file(substream->pstr, pcm_file);
+- kfree(pcm_file);
+ }
+
+ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
+@@ -2060,7 +2055,6 @@ int snd_pcm_open_substream(struct snd_pc
+ return 0;
+ }
+
+- substream->no_mmap_ctrl = 0;
+ err = snd_pcm_hw_constraints_init(substream);
+ if (err < 0) {
+ snd_printd("snd_pcm_hw_constraints_init failed\n");
+@@ -2105,19 +2099,16 @@ static int snd_pcm_open_file(struct file
+ if (err < 0)
+ return err;
+
+- if (substream->ref_count > 1)
+- pcm_file = substream->file;
+- else {
+- pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
+- if (pcm_file == NULL) {
+- snd_pcm_release_substream(substream);
+- return -ENOMEM;
+- }
++ pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
++ if (pcm_file == NULL) {
++ snd_pcm_release_substream(substream);
++ return -ENOMEM;
++ }
++ pcm_file->substream = substream;
++ if (substream->ref_count == 1) {
+ str = substream->pstr;
+ substream->file = pcm_file;
+ substream->pcm_release = pcm_release_private;
+- pcm_file->substream = substream;
+- snd_pcm_add_file(str, pcm_file);
+ }
+ file->private_data = pcm_file;
+ *rpcm_file = pcm_file;
+@@ -2209,6 +2200,7 @@ static int snd_pcm_release(struct inode
+ fasync_helper(-1, file, 0, &substream->runtime->fasync);
+ mutex_lock(&pcm->open_mutex);
+ snd_pcm_release_substream(substream);
++ kfree(pcm_file);
+ mutex_unlock(&pcm->open_mutex);
+ wake_up(&pcm->open_wait);
+ module_put(pcm->card->module);
+@@ -2860,8 +2852,8 @@ static ssize_t snd_pcm_write(struct file
+ return result;
+ }
+
+-static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
+- unsigned long count, loff_t * offset)
++static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+
+ {
+ struct snd_pcm_file *pcm_file;
+@@ -2872,22 +2864,22 @@ static ssize_t snd_pcm_readv(struct file
+ void __user **bufs;
+ snd_pcm_uframes_t frames;
+
+- pcm_file = file->private_data;
++ pcm_file = iocb->ki_filp->private_data;
+ substream = pcm_file->substream;
+ snd_assert(substream != NULL, return -ENXIO);
+ runtime = substream->runtime;
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+- if (count > 1024 || count != runtime->channels)
++ if (nr_segs > 1024 || nr_segs != runtime->channels)
+ return -EINVAL;
+- if (!frame_aligned(runtime, _vector->iov_len))
++ if (!frame_aligned(runtime, iov->iov_len))
+ return -EINVAL;
+- frames = bytes_to_samples(runtime, _vector->iov_len);
+- bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
++ frames = bytes_to_samples(runtime, iov->iov_len);
++ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
+ if (bufs == NULL)
+ return -ENOMEM;
+- for (i = 0; i < count; ++i)
+- bufs[i] = _vector[i].iov_base;
++ for (i = 0; i < nr_segs; ++i)
++ bufs[i] = iov[i].iov_base;
+ result = snd_pcm_lib_readv(substream, bufs, frames);
+ if (result > 0)
+ result = frames_to_bytes(runtime, result);
+@@ -2895,8 +2887,8 @@ static ssize_t snd_pcm_readv(struct file
+ return result;
+ }
+
+-static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector,
+- unsigned long count, loff_t * offset)
++static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
++ unsigned long nr_segs, loff_t pos)
+ {
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+@@ -2906,7 +2898,7 @@ static ssize_t snd_pcm_writev(struct fil
+ void __user **bufs;
+ snd_pcm_uframes_t frames;
+
+- pcm_file = file->private_data;
++ pcm_file = iocb->ki_filp->private_data;
+ substream = pcm_file->substream;
+ snd_assert(substream != NULL, result = -ENXIO; goto end);
+ runtime = substream->runtime;
+@@ -2914,17 +2906,17 @@ static ssize_t snd_pcm_writev(struct fil
+ result = -EBADFD;
+ goto end;
+ }
+- if (count > 128 || count != runtime->channels ||
+- !frame_aligned(runtime, _vector->iov_len)) {
++ if (nr_segs > 128 || nr_segs != runtime->channels ||
++ !frame_aligned(runtime, iov->iov_len)) {
+ result = -EINVAL;
+ goto end;
+ }
+- frames = bytes_to_samples(runtime, _vector->iov_len);
+- bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
++ frames = bytes_to_samples(runtime, iov->iov_len);
++ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
+ if (bufs == NULL)
+ return -ENOMEM;
+- for (i = 0; i < count; ++i)
+- bufs[i] = _vector[i].iov_base;
++ for (i = 0; i < nr_segs; ++i)
++ bufs[i] = iov[i].iov_base;
+ result = snd_pcm_lib_writev(substream, bufs, frames);
+ if (result > 0)
+ result = frames_to_bytes(runtime, result);
+@@ -3270,11 +3262,11 @@ static int snd_pcm_mmap(struct file *fil
+ offset = area->vm_pgoff << PAGE_SHIFT;
+ switch (offset) {
+ case SNDRV_PCM_MMAP_OFFSET_STATUS:
+- if (substream->no_mmap_ctrl)
++ if (pcm_file->no_compat_mmap)
+ return -ENXIO;
+ return snd_pcm_mmap_status(substream, file, area);
+ case SNDRV_PCM_MMAP_OFFSET_CONTROL:
+- if (substream->no_mmap_ctrl)
++ if (pcm_file->no_compat_mmap)
+ return -ENXIO;
+ return snd_pcm_mmap_control(substream, file, area);
+ default:
+@@ -3434,7 +3426,7 @@ struct file_operations snd_pcm_f_ops[2]
+ {
+ .owner = THIS_MODULE,
+ .write = snd_pcm_write,
+- .writev = snd_pcm_writev,
++ .aio_write = snd_pcm_aio_write,
+ .open = snd_pcm_playback_open,
+ .release = snd_pcm_release,
+ .poll = snd_pcm_playback_poll,
+@@ -3446,7 +3438,7 @@ struct file_operations snd_pcm_f_ops[2]
+ {
+ .owner = THIS_MODULE,
+ .read = snd_pcm_read,
+- .readv = snd_pcm_readv,
++ .aio_read = snd_pcm_aio_read,
+ .open = snd_pcm_capture_open,
+ .release = snd_pcm_release,
+ .poll = snd_pcm_capture_poll,
+diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
+index 8c15c66..269c467 100644
+--- a/sound/core/rawmidi.c
++++ b/sound/core/rawmidi.c
+@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_r
+ static int snd_rawmidi_dev_free(struct snd_device *device);
+ static int snd_rawmidi_dev_register(struct snd_device *device);
+ static int snd_rawmidi_dev_disconnect(struct snd_device *device);
+-static int snd_rawmidi_dev_unregister(struct snd_device *device);
+
+ static LIST_HEAD(snd_rawmidi_devices);
+ static DEFINE_MUTEX(register_mutex);
+@@ -431,7 +430,8 @@ static int snd_rawmidi_open(struct inode
+ kctl = snd_ctl_file(list);
+ if (kctl->pid == current->pid) {
+ subdevice = kctl->prefer_rawmidi_subdevice;
+- break;
++ if (subdevice != -1)
++ break;
+ }
+ }
+ up_read(&card->controls_rwsem);
+@@ -1426,7 +1426,6 @@ int snd_rawmidi_new(struct snd_card *car
+ .dev_free = snd_rawmidi_dev_free,
+ .dev_register = snd_rawmidi_dev_register,
+ .dev_disconnect = snd_rawmidi_dev_disconnect,
+- .dev_unregister = snd_rawmidi_dev_unregister
+ };
+
+ snd_assert(rrawmidi != NULL, return -EINVAL);
+@@ -1479,6 +1478,14 @@ static void snd_rawmidi_free_substreams(
+ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
+ {
+ snd_assert(rmidi != NULL, return -ENXIO);
++
++ snd_info_free_entry(rmidi->proc_entry);
++ rmidi->proc_entry = NULL;
++ mutex_lock(®ister_mutex);
++ if (rmidi->ops && rmidi->ops->dev_unregister)
++ rmidi->ops->dev_unregister(rmidi);
++ mutex_unlock(®ister_mutex);
++
+ snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
+ snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
+ if (rmidi->private_free)
+@@ -1587,21 +1594,6 @@ static int snd_rawmidi_dev_disconnect(st
+
+ mutex_lock(®ister_mutex);
+ list_del_init(&rmidi->list);
+- mutex_unlock(®ister_mutex);
+- return 0;
+-}
+-
+-static int snd_rawmidi_dev_unregister(struct snd_device *device)
+-{
+- struct snd_rawmidi *rmidi = device->device_data;
+-
+- snd_assert(rmidi != NULL, return -ENXIO);
+- mutex_lock(®ister_mutex);
+- list_del(&rmidi->list);
+- if (rmidi->proc_entry) {
+- snd_info_unregister(rmidi->proc_entry);
+- rmidi->proc_entry = NULL;
+- }
+ #ifdef CONFIG_SND_OSSEMUL
+ if (rmidi->ossreg) {
+ if ((int)rmidi->device == midi_map[rmidi->card->number]) {
+@@ -1615,17 +1607,9 @@ static int snd_rawmidi_dev_unregister(st
+ rmidi->ossreg = 0;
+ }
+ #endif /* CONFIG_SND_OSSEMUL */
+- if (rmidi->ops && rmidi->ops->dev_unregister)
+- rmidi->ops->dev_unregister(rmidi);
+ snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+ mutex_unlock(®ister_mutex);
+-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
+- if (rmidi->seq_dev) {
+- snd_device_free(rmidi->card, rmidi->seq_dev);
+- rmidi->seq_dev = NULL;
+- }
+-#endif
+- return snd_rawmidi_free(rmidi);
++ return 0;
+ }
+
+ /**
+diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
+index 84704cc..412dd62 100644
+--- a/sound/core/rtctimer.c
++++ b/sound/core/rtctimer.c
+@@ -156,7 +156,7 @@ static int __init rtctimer_init(void)
+ static void __exit rtctimer_exit(void)
+ {
+ if (rtctimer) {
+- snd_timer_global_unregister(rtctimer);
++ snd_timer_global_free(rtctimer);
+ rtctimer = NULL;
+ }
+ }
+diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
+index e723413..92858cf 100644
+--- a/sound/core/seq/oss/seq_oss.c
++++ b/sound/core/seq/oss/seq_oss.c
+@@ -303,8 +303,7 @@ register_proc(void)
+ static void
+ unregister_proc(void)
+ {
+- if (info_entry)
+- snd_info_unregister(info_entry);
++ snd_info_free_entry(info_entry);
+ info_entry = NULL;
+ }
+ #endif /* CONFIG_PROC_FS */
+diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
+index 102ff54..b79d011 100644
+--- a/sound/core/seq/seq_device.c
++++ b/sound/core/seq/seq_device.c
+@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct sn
+ static int snd_seq_device_dev_free(struct snd_device *device);
+ static int snd_seq_device_dev_register(struct snd_device *device);
+ static int snd_seq_device_dev_disconnect(struct snd_device *device);
+-static int snd_seq_device_dev_unregister(struct snd_device *device);
+
+ static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
+ static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
+@@ -189,7 +188,6 @@ int snd_seq_device_new(struct snd_card *
+ .dev_free = snd_seq_device_dev_free,
+ .dev_register = snd_seq_device_dev_register,
+ .dev_disconnect = snd_seq_device_dev_disconnect,
+- .dev_unregister = snd_seq_device_dev_unregister
+ };
+
+ if (result)
+@@ -309,15 +307,6 @@ static int snd_seq_device_dev_disconnect
+ }
+
+ /*
+- * unregister the existing device
+- */
+-static int snd_seq_device_dev_unregister(struct snd_device *device)
+-{
+- struct snd_seq_device *dev = device->device_data;
+- return snd_seq_device_free(dev);
+-}
+-
+-/*
+ * register device driver
+ * id = driver id
+ * entry = driver operators - duplicated to each instance
+@@ -573,7 +562,7 @@ static void __exit alsa_seq_device_exit(
+ {
+ remove_drivers();
+ #ifdef CONFIG_PROC_FS
+- snd_info_unregister(info_entry);
++ snd_info_free_entry(info_entry);
+ #endif
+ if (num_ops)
+ snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
+diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
+index 142e9e6..8a7fe5c 100644
+--- a/sound/core/seq/seq_info.c
++++ b/sound/core/seq/seq_info.c
+@@ -64,9 +64,9 @@ int __init snd_seq_info_init(void)
+
+ int __exit snd_seq_info_done(void)
+ {
+- snd_info_unregister(queues_entry);
+- snd_info_unregister(clients_entry);
+- snd_info_unregister(timer_entry);
++ snd_info_free_entry(queues_entry);
++ snd_info_free_entry(clients_entry);
++ snd_info_free_entry(timer_entry);
+ return 0;
+ }
+ #endif
+diff --git a/sound/core/sound.c b/sound/core/sound.c
+index 7edd1fc..efa476c 100644
+--- a/sound/core/sound.c
++++ b/sound/core/sound.c
+@@ -268,7 +268,11 @@ int snd_register_device(int type, struct
+ snd_minors[minor] = preg;
+ if (card)
+ device = card->dev;
+- class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
++ preg->class_dev = class_device_create(sound_class, NULL,
++ MKDEV(major, minor),
++ device, "%s", name);
++ if (preg->class_dev)
++ class_set_devdata(preg->class_dev, private_data);
+
+ mutex_unlock(&sound_mutex);
+ return 0;
+@@ -276,6 +280,24 @@ int snd_register_device(int type, struct
+
+ EXPORT_SYMBOL(snd_register_device);
+
++/* find the matching minor record
++ * return the index of snd_minor, or -1 if not found
++ */
++static int find_snd_minor(int type, struct snd_card *card, int dev)
++{
++ int cardnum, minor;
++ struct snd_minor *mptr;
++
++ cardnum = card ? card->number : -1;
++ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
++ if ((mptr = snd_minors[minor]) != NULL &&
++ mptr->type == type &&
++ mptr->card == cardnum &&
++ mptr->device == dev)
++ return minor;
++ return -1;
++}
++
+ /**
+ * snd_unregister_device - unregister the device on the given card
+ * @type: the device type, SNDRV_DEVICE_TYPE_XXX
+@@ -289,32 +311,42 @@ EXPORT_SYMBOL(snd_register_device);
+ */
+ int snd_unregister_device(int type, struct snd_card *card, int dev)
+ {
+- int cardnum, minor;
+- struct snd_minor *mptr;
++ int minor;
+
+- cardnum = card ? card->number : -1;
+ mutex_lock(&sound_mutex);
+- for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
+- if ((mptr = snd_minors[minor]) != NULL &&
+- mptr->type == type &&
+- mptr->card == cardnum &&
+- mptr->device == dev)
+- break;
+- if (minor == ARRAY_SIZE(snd_minors)) {
++ minor = find_snd_minor(type, card, dev);
++ if (minor < 0) {
+ mutex_unlock(&sound_mutex);
+ return -EINVAL;
+ }
+
+ class_device_destroy(sound_class, MKDEV(major, minor));
+
++ kfree(snd_minors[minor]);
+ snd_minors[minor] = NULL;
+ mutex_unlock(&sound_mutex);
+- kfree(mptr);
+ return 0;
+ }
+
+ EXPORT_SYMBOL(snd_unregister_device);
+
++int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
++ const struct class_device_attribute *attr)
++{
++ int minor, ret = -EINVAL;
++ struct class_device *cdev;
++
++ mutex_lock(&sound_mutex);
++ minor = find_snd_minor(type, card, dev);
++ if (minor >= 0 && (cdev = snd_minors[minor]->class_dev) != NULL)
++ ret = class_device_create_file(cdev, attr);
++ mutex_unlock(&sound_mutex);
++ return ret;
++
++}
++
++EXPORT_SYMBOL(snd_add_device_sysfs_file);
++
+ #ifdef CONFIG_PROC_FS
+ /*
+ * INFO PART
+@@ -387,8 +419,7 @@ int __init snd_minor_info_init(void)
+
+ int __exit snd_minor_info_done(void)
+ {
+- if (snd_minor_info_entry)
+- snd_info_unregister(snd_minor_info_entry);
++ snd_info_free_entry(snd_minor_info_entry);
+ return 0;
+ }
+ #endif /* CONFIG_PROC_FS */
+diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
+index 74f0fe5..b2fc40a 100644
+--- a/sound/core/sound_oss.c
++++ b/sound/core/sound_oss.c
+@@ -270,8 +270,7 @@ int __init snd_minor_info_oss_init(void)
+
+ int __exit snd_minor_info_oss_done(void)
+ {
+- if (snd_minor_info_oss_entry)
+- snd_info_unregister(snd_minor_info_oss_entry);
++ snd_info_free_entry(snd_minor_info_oss_entry);
+ return 0;
+ }
+ #endif /* CONFIG_PROC_FS */
+diff --git a/sound/core/timer.c b/sound/core/timer.c
+index 0a984e8..10a79ae 100644
+--- a/sound/core/timer.c
++++ b/sound/core/timer.c
+@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex);
+ static int snd_timer_free(struct snd_timer *timer);
+ static int snd_timer_dev_free(struct snd_device *device);
+ static int snd_timer_dev_register(struct snd_device *device);
+-static int snd_timer_dev_unregister(struct snd_device *device);
++static int snd_timer_dev_disconnect(struct snd_device *device);
+
+ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
+
+@@ -718,7 +718,7 @@ void snd_timer_interrupt(struct snd_time
+ }
+ }
+ if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
+- snd_timer_reschedule(timer, ticks_left);
++ snd_timer_reschedule(timer, timer->sticks);
+ if (timer->running) {
+ if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
+ timer->hw.stop(timer);
+@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card,
+ static struct snd_device_ops ops = {
+ .dev_free = snd_timer_dev_free,
+ .dev_register = snd_timer_dev_register,
+- .dev_unregister = snd_timer_dev_unregister
++ .dev_disconnect = snd_timer_dev_disconnect,
+ };
+
+ snd_assert(tid != NULL, return -EINVAL);
+@@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card,
+ static int snd_timer_free(struct snd_timer *timer)
+ {
+ snd_assert(timer != NULL, return -ENXIO);
++
++ mutex_lock(®ister_mutex);
++ if (! list_empty(&timer->open_list_head)) {
++ struct list_head *p, *n;
++ struct snd_timer_instance *ti;
++ snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
++ list_for_each_safe(p, n, &timer->open_list_head) {
++ list_del_init(p);
++ ti = list_entry(p, struct snd_timer_instance, open_list);
++ ti->timer = NULL;
++ }
++ }
++ list_del(&timer->device_list);
++ mutex_unlock(®ister_mutex);
++
+ if (timer->private_free)
+ timer->private_free(timer);
+ kfree(timer);
+@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct
+ return 0;
+ }
+
+-static int snd_timer_unregister(struct snd_timer *timer)
++static int snd_timer_dev_disconnect(struct snd_device *device)
+ {
+- struct list_head *p, *n;
+- struct snd_timer_instance *ti;
+-
+- snd_assert(timer != NULL, return -ENXIO);
++ struct snd_timer *timer = device->device_data;
+ mutex_lock(®ister_mutex);
+- if (! list_empty(&timer->open_list_head)) {
+- snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
+- list_for_each_safe(p, n, &timer->open_list_head) {
+- list_del_init(p);
+- ti = list_entry(p, struct snd_timer_instance, open_list);
+- ti->timer = NULL;
+- }
+- }
+- list_del(&timer->device_list);
++ list_del_init(&timer->device_list);
+ mutex_unlock(®ister_mutex);
+- return snd_timer_free(timer);
+-}
+-
+-static int snd_timer_dev_unregister(struct snd_device *device)
+-{
+- struct snd_timer *timer = device->device_data;
+- return snd_timer_unregister(timer);
++ return 0;
+ }
+
+ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
+@@ -955,18 +953,12 @@ int snd_timer_global_register(struct snd
+ return snd_timer_dev_register(&dev);
+ }
+
+-int snd_timer_global_unregister(struct snd_timer *timer)
+-{
+- return snd_timer_unregister(timer);
+-}
+-
+ /*
+ * System timer
+ */
+
+ struct snd_timer_system_private {
+ struct timer_list tlist;
+- struct timer * timer;
+ unsigned long last_expires;
+ unsigned long last_jiffies;
+ unsigned long correction;
+@@ -978,7 +970,7 @@ static void snd_timer_s_function(unsigne
+ struct snd_timer_system_private *priv = timer->private_data;
+ unsigned long jiff = jiffies;
+ if (time_after(jiff, priv->last_expires))
+- priv->correction = (long)jiff - (long)priv->last_expires;
++ priv->correction += (long)jiff - (long)priv->last_expires;
+ snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
+ }
+
+@@ -994,7 +986,7 @@ static int snd_timer_s_start(struct snd_
+ njiff++;
+ } else {
+ njiff += timer->sticks - priv->correction;
+- priv->correction -= timer->sticks;
++ priv->correction = 0;
+ }
+ priv->last_expires = priv->tlist.expires = njiff;
+ add_timer(&priv->tlist);
+@@ -1013,6 +1005,7 @@ static int snd_timer_s_stop(struct snd_t
+ timer->sticks = priv->last_expires - jiff;
+ else
+ timer->sticks = 1;
++ priv->correction = 0;
+ return 0;
+ }
+
+@@ -1126,7 +1119,7 @@ static void __init snd_timer_proc_init(v
+
+ static void __exit snd_timer_proc_done(void)
+ {
+- snd_info_unregister(snd_timer_proc_entry);
++ snd_info_free_entry(snd_timer_proc_entry);
+ }
+ #else /* !CONFIG_PROC_FS */
+ #define snd_timer_proc_init()
+@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void)
+ /* unregister the system timer */
+ list_for_each_safe(p, n, &snd_timer_list) {
+ struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
+- snd_timer_unregister(timer);
++ snd_timer_free(timer);
+ }
+ snd_timer_proc_done();
+ #ifdef SNDRV_OSS_INFO_DEV_TIMERS
+@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify);
+ EXPORT_SYMBOL(snd_timer_global_new);
+ EXPORT_SYMBOL(snd_timer_global_free);
+ EXPORT_SYMBOL(snd_timer_global_register);
+-EXPORT_SYMBOL(snd_timer_global_unregister);
+ EXPORT_SYMBOL(snd_timer_interrupt);
+diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
+index 395c4ef..7971285 100644
+--- a/sound/drivers/Kconfig
++++ b/sound/drivers/Kconfig
+@@ -73,6 +73,19 @@ config SND_MTPAV
+ To compile this driver as a module, choose M here: the module
+ will be called snd-mtpav.
+
++config SND_MTS64
++ tristate "ESI Miditerminal 4140 driver"
++ depends on SND && PARPORT
++ select SND_RAWMIDI
++ help
++ The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with
++ additional SMPTE Timecode capabilities for the parallel port.
++
++ Say 'Y' to include support for this device.
++
++ To compile this driver as a module, chose 'M' here: the module
++ will be called snd-mts64.
++
+ config SND_SERIAL_U16550
+ tristate "UART16550 serial MIDI driver"
+ depends on SND
+diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
+index cb98c3d..c9bad6d 100644
+--- a/sound/drivers/Makefile
++++ b/sound/drivers/Makefile
+@@ -5,6 +5,7 @@
+
+ snd-dummy-objs := dummy.o
+ snd-mtpav-objs := mtpav.o
++snd-mts64-objs := mts64.o
+ snd-serial-u16550-objs := serial-u16550.o
+ snd-virmidi-objs := virmidi.o
+
+@@ -13,5 +14,6 @@ obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
+ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
+ obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
+ obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
++obj-$(CONFIG_SND_MTS64) += snd-mts64.o
+
+ obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
+diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
+index ffeafaf..42001ef 100644
+--- a/sound/drivers/dummy.c
++++ b/sound/drivers/dummy.c
+@@ -29,6 +29,7 @@
+ #include <linux/moduleparam.h>
+ #include <sound/core.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/pcm.h>
+ #include <sound/rawmidi.h>
+ #include <sound/initval.h>
+@@ -285,7 +286,7 @@ static struct snd_pcm_hardware snd_card_
+ .channels_max = USE_CHANNELS_MAX,
+ .buffer_bytes_max = MAX_BUFFER_SIZE,
+ .period_bytes_min = 64,
+- .period_bytes_max = MAX_BUFFER_SIZE,
++ .period_bytes_max = MAX_PERIOD_SIZE,
+ .periods_min = USE_PERIODS_MIN,
+ .periods_max = USE_PERIODS_MAX,
+ .fifo_size = 0,
+@@ -443,10 +444,13 @@ static int __init snd_card_dummy_pcm(str
+ }
+
+ #define DUMMY_VOLUME(xname, xindex, addr) \
+-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .index = xindex, \
+ .info = snd_dummy_volume_info, \
+ .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
+- .private_value = addr }
++ .private_value = addr, \
++ .tlv = { .p = db_scale_dummy } }
+
+ static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+@@ -497,6 +501,8 @@ static int snd_dummy_volume_put(struct s
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
++
+ #define DUMMY_CAPSRC(xname, xindex, addr) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_dummy_capsrc_info, \
+@@ -547,13 +553,13 @@ static struct snd_kcontrol_new snd_dummy
+ DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
+ DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
+ DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
+-DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER),
++DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
+ DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
+-DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER),
++DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
+ DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
+-DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER),
++DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
+ DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
+-DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER)
++DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD)
+ };
+
+ static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy)
+diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
+index 17cc105..2de181a 100644
+--- a/sound/drivers/mpu401/mpu401.c
++++ b/sound/drivers/mpu401/mpu401.c
+@@ -211,7 +211,7 @@ static void __devexit snd_mpu401_pnp_rem
+ struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev);
+
+ snd_card_disconnect(card);
+- snd_card_free_in_thread(card);
++ snd_card_free_when_closed(card);
+ }
+
+ static struct pnp_driver snd_mpu401_pnp_driver = {
+diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
+index 4bf07ca..3daa9fa 100644
+--- a/sound/drivers/mpu401/mpu401_uart.c
++++ b/sound/drivers/mpu401/mpu401_uart.c
+@@ -125,12 +125,10 @@ static void _snd_mpu401_uart_interrupt(s
+ * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
+ * @irq: the irq number
+ * @dev_id: mpu401 instance
+- * @regs: the reigster
+ *
+ * Processes the interrupt for MPU401-UART i/o.
+ */
+-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
+ {
+ struct snd_mpu401 *mpu = dev_id;
+
+@@ -146,12 +144,10 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt)
+ * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
+ * @irq: the irq number
+ * @dev_id: mpu401 instance
+- * @regs: the reigster
+ *
+ * Processes the interrupt for MPU401-UART output.
+ */
+-irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
+- struct pt_regs *regs)
++irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
+ {
+ struct snd_mpu401 *mpu = dev_id;
+
+diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
+index e064d6c..a9ff391 100644
+--- a/sound/drivers/mtpav.c
++++ b/sound/drivers/mtpav.c
+@@ -570,7 +570,7 @@ static void snd_mtpav_read_bytes(struct
+ } while (sbyt & SIGS_BYTE);
+ }
+
+-static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
+ {
+ struct mtpav *mcard = dev_id;
+
+diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
+new file mode 100644
+index 0000000..5327c6f
+--- /dev/null
++++ b/sound/drivers/mts64.c
+@@ -0,0 +1,1091 @@
++/*
++ * ALSA Driver for Ego Systems Inc. (ESI) Miditerminal 4140
++ * Copyright (c) 2006 by Matthias König <mk at phasorlab.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <sound/driver.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/parport.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/rawmidi.h>
++#include <sound/control.h>
++
++#define CARD_NAME "Miditerminal 4140"
++#define DRIVER_NAME "MTS64"
++#define PLATFORM_DRIVER "snd_mts64"
++
++static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
++static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
++static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
++
++static struct platform_device *platform_devices[SNDRV_CARDS];
++static int device_count;
++
++module_param_array(index, int, NULL, S_IRUGO);
++MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
++module_param_array(id, charp, NULL, S_IRUGO);
++MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
++module_param_array(enable, bool, NULL, S_IRUGO);
++MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
++
++MODULE_AUTHOR("Matthias Koenig <mk at phasorlab.de>");
++MODULE_DESCRIPTION("ESI Miditerminal 4140");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("{{ESI,Miditerminal 4140}}");
++
++/*********************************************************************
++ * Chip specific
++ *********************************************************************/
++#define MTS64_NUM_INPUT_PORTS 5
++#define MTS64_NUM_OUTPUT_PORTS 4
++#define MTS64_SMPTE_SUBSTREAM 4
++
++struct mts64 {
++ spinlock_t lock;
++ struct snd_card *card;
++ struct snd_rawmidi *rmidi;
++ struct pardevice *pardev;
++ int pardev_claimed;
++
++ int open_count;
++ int current_midi_output_port;
++ int current_midi_input_port;
++ u8 mode[MTS64_NUM_INPUT_PORTS];
++ struct snd_rawmidi_substream *midi_input_substream[MTS64_NUM_INPUT_PORTS];
++ int smpte_switch;
++ u8 time[4]; /* [0]=hh, [1]=mm, [2]=ss, [3]=ff */
++ u8 fps;
++};
++
++static int snd_mts64_free(struct mts64 *mts)
++{
++ kfree(mts);
++ return 0;
++}
++
++static int __devinit snd_mts64_create(struct snd_card *card,
++ struct pardevice *pardev,
++ struct mts64 **rchip)
++{
++ struct mts64 *mts;
++
++ *rchip = NULL;
++
++ mts = kzalloc(sizeof(struct mts64), GFP_KERNEL);
++ if (mts == NULL)
++ return -ENOMEM;
++
++ /* Init chip specific data */
++ spin_lock_init(&mts->lock);
++ mts->card = card;
++ mts->pardev = pardev;
++ mts->current_midi_output_port = -1;
++ mts->current_midi_input_port = -1;
++
++ *rchip = mts;
++
++ return 0;
++}
++
++/*********************************************************************
++ * HW register related constants
++ *********************************************************************/
++
++/* Status Bits */
++#define MTS64_STAT_BSY 0x80
++#define MTS64_STAT_BIT_SET 0x20 /* readout process, bit is set */
++#define MTS64_STAT_PORT 0x10 /* read byte is a port number */
++
++/* Control Bits */
++#define MTS64_CTL_READOUT 0x08 /* enable readout */
++#define MTS64_CTL_WRITE_CMD 0x06
++#define MTS64_CTL_WRITE_DATA 0x02
++#define MTS64_CTL_STROBE 0x01
++
++/* Command */
++#define MTS64_CMD_RESET 0xfe
++#define MTS64_CMD_PROBE 0x8f /* Used in probing procedure */
++#define MTS64_CMD_SMPTE_SET_TIME 0xe8
++#define MTS64_CMD_SMPTE_SET_FPS 0xee
++#define MTS64_CMD_SMPTE_STOP 0xef
++#define MTS64_CMD_SMPTE_FPS_24 0xe3
++#define MTS64_CMD_SMPTE_FPS_25 0xe2
++#define MTS64_CMD_SMPTE_FPS_2997 0xe4
++#define MTS64_CMD_SMPTE_FPS_30D 0xe1
++#define MTS64_CMD_SMPTE_FPS_30 0xe0
++#define MTS64_CMD_COM_OPEN 0xf8 /* setting the communication mode */
++#define MTS64_CMD_COM_CLOSE1 0xff /* clearing communication mode */
++#define MTS64_CMD_COM_CLOSE2 0xf5
++
++/*********************************************************************
++ * Hardware specific functions
++ *********************************************************************/
++static void mts64_enable_readout(struct parport *p);
++static void mts64_disable_readout(struct parport *p);
++static int mts64_device_ready(struct parport *p);
++static int mts64_device_init(struct parport *p);
++static int mts64_device_open(struct mts64 *mts);
++static int mts64_device_close(struct mts64 *mts);
++static u8 mts64_map_midi_input(u8 c);
++static int mts64_probe(struct parport *p);
++static u16 mts64_read(struct parport *p);
++static u8 mts64_read_char(struct parport *p);
++static void mts64_smpte_start(struct parport *p,
++ u8 hours, u8 minutes,
++ u8 seconds, u8 frames,
++ u8 idx);
++static void mts64_smpte_stop(struct parport *p);
++static void mts64_write_command(struct parport *p, u8 c);
++static void mts64_write_data(struct parport *p, u8 c);
++static void mts64_write_midi(struct mts64 *mts, u8 c, int midiport);
++
++
++/* Enables the readout procedure
++ *
++ * Before we can read a midi byte from the device, we have to set
++ * bit 3 of control port.
++ */
++static void mts64_enable_readout(struct parport *p)
++{
++ u8 c;
++
++ c = parport_read_control(p);
++ c |= MTS64_CTL_READOUT;
++ parport_write_control(p, c);
++}
++
++/* Disables readout
++ *
++ * Readout is disabled by clearing bit 3 of control
++ */
++static void mts64_disable_readout(struct parport *p)
++{
++ u8 c;
++
++ c = parport_read_control(p);
++ c &= ~MTS64_CTL_READOUT;
++ parport_write_control(p, c);
++}
++
++/* waits for device ready
++ *
++ * Checks if BUSY (Bit 7 of status) is clear
++ * 1 device ready
++ * 0 failure
++ */
++static int mts64_device_ready(struct parport *p)
++{
++ int i;
++ u8 c;
++
++ for (i = 0; i < 0xffff; ++i) {
++ c = parport_read_status(p);
++ c &= MTS64_STAT_BSY;
++ if (c != 0)
++ return 1;
++ }
++
++ return 0;
++}
++
++/* Init device (LED blinking startup magic)
++ *
++ * Returns:
++ * 0 init ok
++ * -EIO failure
++ */
++static int __devinit mts64_device_init(struct parport *p)
++{
++ int i;
++
++ mts64_write_command(p, MTS64_CMD_RESET);
++
++ for (i = 0; i < 64; ++i) {
++ msleep(100);
++
++ if (mts64_probe(p) == 0) {
++ /* success */
++ mts64_disable_readout(p);
++ return 0;
++ }
++ }
++ mts64_disable_readout(p);
++
++ return -EIO;
++}
++
++/*
++ * Opens the device (set communication mode)
++ */
++static int mts64_device_open(struct mts64 *mts)
++{
++ int i;
++ struct parport *p = mts->pardev->port;
++
++ for (i = 0; i < 5; ++i)
++ mts64_write_command(p, MTS64_CMD_COM_OPEN);
++
++ return 0;
++}
++
++/*
++ * Close device (clear communication mode)
++ */
++static int mts64_device_close(struct mts64 *mts)
++{
++ int i;
++ struct parport *p = mts->pardev->port;
++
++ for (i = 0; i < 5; ++i) {
++ mts64_write_command(p, MTS64_CMD_COM_CLOSE1);
++ mts64_write_command(p, MTS64_CMD_COM_CLOSE2);
++ }
++
++ return 0;
++}
++
++/* map hardware port to substream number
++ *
++ * When reading a byte from the device, the device tells us
++ * on what port the byte is. This HW port has to be mapped to
++ * the midiport (substream number).
++ * substream 0-3 are Midiports 1-4
++ * substream 4 is SMPTE Timecode
++ * The mapping is done by the table:
++ * HW | 0 | 1 | 2 | 3 | 4
++ * SW | 0 | 1 | 4 | 2 | 3
++ */
++static u8 mts64_map_midi_input(u8 c)
++{
++ static u8 map[] = { 0, 1, 4, 2, 3 };
++
++ return map[c];
++}
++
++
++/* Probe parport for device
++ *
++ * Do we have a Miditerminal 4140 on parport?
++ * Returns:
++ * 0 device found
++ * -ENODEV no device
++ */
++static int __devinit mts64_probe(struct parport *p)
++{
++ u8 c;
++
++ mts64_smpte_stop(p);
++ mts64_write_command(p, MTS64_CMD_PROBE);
++
++ msleep(50);
++
++ c = mts64_read(p);
++
++ c &= 0x00ff;
++ if (c != MTS64_CMD_PROBE)
++ return -ENODEV;
++ else
++ return 0;
++
++}
++
++/* Read byte incl. status from device
++ *
++ * Returns:
++ * data in lower 8 bits and status in upper 8 bits
++ */
++static u16 mts64_read(struct parport *p)
++{
++ u8 data, status;
++
++ mts64_device_ready(p);
++ mts64_enable_readout(p);
++ status = parport_read_status(p);
++ data = mts64_read_char(p);
++ mts64_disable_readout(p);
++
++ return (status << 8) | data;
++}
++
++/* Read a byte from device
++ *
++ * Note, that readout mode has to be enabled.
++ * readout procedure is as follows:
++ * - Write number of the Bit to read to DATA
++ * - Read STATUS
++ * - Bit 5 of STATUS indicates if Bit is set
++ *
++ * Returns:
++ * Byte read from device
++ */
++static u8 mts64_read_char(struct parport *p)
++{
++ u8 c = 0;
++ u8 status;
++ u8 i;
++
++ for (i = 0; i < 8; ++i) {
++ parport_write_data(p, i);
++ c >>= 1;
++ status = parport_read_status(p);
++ if (status & MTS64_STAT_BIT_SET)
++ c |= 0x80;
++ }
++
++ return c;
++}
++
++/* Starts SMPTE Timecode generation
++ *
++ * The device creates SMPTE Timecode by hardware.
++ * 0 24 fps
++ * 1 25 fps
++ * 2 29.97 fps
++ * 3 30 fps (Drop-frame)
++ * 4 30 fps
++ */
++static void mts64_smpte_start(struct parport *p,
++ u8 hours, u8 minutes,
++ u8 seconds, u8 frames,
++ u8 idx)
++{
++ static u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24,
++ MTS64_CMD_SMPTE_FPS_25,
++ MTS64_CMD_SMPTE_FPS_2997,
++ MTS64_CMD_SMPTE_FPS_30D,
++ MTS64_CMD_SMPTE_FPS_30 };
++
++ mts64_write_command(p, MTS64_CMD_SMPTE_SET_TIME);
++ mts64_write_command(p, frames);
++ mts64_write_command(p, seconds);
++ mts64_write_command(p, minutes);
++ mts64_write_command(p, hours);
++
++ mts64_write_command(p, MTS64_CMD_SMPTE_SET_FPS);
++ mts64_write_command(p, fps[idx]);
++}
++
++/* Stops SMPTE Timecode generation
++ */
++static void mts64_smpte_stop(struct parport *p)
++{
++ mts64_write_command(p, MTS64_CMD_SMPTE_STOP);
++}
++
++/* Write a command byte to device
++ */
++static void mts64_write_command(struct parport *p, u8 c)
++{
++ mts64_device_ready(p);
++
++ parport_write_data(p, c);
++
++ parport_write_control(p, MTS64_CTL_WRITE_CMD);
++ parport_write_control(p, MTS64_CTL_WRITE_CMD | MTS64_CTL_STROBE);
++ parport_write_control(p, MTS64_CTL_WRITE_CMD);
++}
++
++/* Write a data byte to device
++ */
++static void mts64_write_data(struct parport *p, u8 c)
++{
++ mts64_device_ready(p);
++
++ parport_write_data(p, c);
++
++ parport_write_control(p, MTS64_CTL_WRITE_DATA);
++ parport_write_control(p, MTS64_CTL_WRITE_DATA | MTS64_CTL_STROBE);
++ parport_write_control(p, MTS64_CTL_WRITE_DATA);
++}
++
++/* Write a MIDI byte to midiport
++ *
++ * midiport ranges from 0-3 and maps to Ports 1-4
++ * assumptions: communication mode is on
++ */
++static void mts64_write_midi(struct mts64 *mts, u8 c,
++ int midiport)
++{
++ struct parport *p = mts->pardev->port;
++
++ /* check current midiport */
++ if (mts->current_midi_output_port != midiport)
++ mts64_write_command(p, midiport);
++
++ /* write midi byte */
++ mts64_write_data(p, c);
++}
++
++/*********************************************************************
++ * Control elements
++ *********************************************************************/
++
++/* SMPTE Switch */
++static int snd_mts64_ctl_smpte_switch_info(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 1;
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl,
++ struct snd_ctl_elem_value *uctl)
++{
++ struct mts64 *mts = snd_kcontrol_chip(kctl);
++
++ spin_lock_irq(&mts->lock);
++ uctl->value.integer.value[0] = mts->smpte_switch;
++ spin_unlock_irq(&mts->lock);
++
++ return 0;
++}
++
++/* smpte_switch is not accessed from IRQ handler, so we just need
++ to protect the HW access */
++static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl,
++ struct snd_ctl_elem_value *uctl)
++{
++ struct mts64 *mts = snd_kcontrol_chip(kctl);
++ int changed = 0;
++
++ spin_lock_irq(&mts->lock);
++ if (mts->smpte_switch == uctl->value.integer.value[0])
++ goto __out;
++
++ changed = 1;
++ mts->smpte_switch = uctl->value.integer.value[0];
++ if (mts->smpte_switch) {
++ mts64_smpte_start(mts->pardev->port,
++ mts->time[0], mts->time[1],
++ mts->time[2], mts->time[3],
++ mts->fps);
++ } else {
++ mts64_smpte_stop(mts->pardev->port);
++ }
++__out:
++ spin_unlock_irq(&mts->lock);
++ return changed;
++}
++
++static struct snd_kcontrol_new mts64_ctl_smpte_switch __devinitdata = {
++ .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
++ .name = "SMPTE Playback Switch",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = 0,
++ .info = snd_mts64_ctl_smpte_switch_info,
++ .get = snd_mts64_ctl_smpte_switch_get,
++ .put = snd_mts64_ctl_smpte_switch_put
++};
++
++/* Time */
++static int snd_mts64_ctl_smpte_time_h_info(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 23;
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_time_f_info(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 99;
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_time_info(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 59;
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_value *uctl)
++{
++ struct mts64 *mts = snd_kcontrol_chip(kctl);
++ int idx = kctl->private_value;
++
++ spin_lock_irq(&mts->lock);
++ uctl->value.integer.value[0] = mts->time[idx];
++ spin_unlock_irq(&mts->lock);
++
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_value *uctl)
++{
++ struct mts64 *mts = snd_kcontrol_chip(kctl);
++ int idx = kctl->private_value;
++ int changed = 0;
++
++ spin_lock_irq(&mts->lock);
++ if (mts->time[idx] != uctl->value.integer.value[0]) {
++ changed = 1;
++ mts->time[idx] = uctl->value.integer.value[0];
++ }
++ spin_unlock_irq(&mts->lock);
++
++ return changed;
++}
++
++static struct snd_kcontrol_new mts64_ctl_smpte_time_hours __devinitdata = {
++ .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
++ .name = "SMPTE Time Hours",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = 0,
++ .info = snd_mts64_ctl_smpte_time_h_info,
++ .get = snd_mts64_ctl_smpte_time_get,
++ .put = snd_mts64_ctl_smpte_time_put
++};
++
++static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes __devinitdata = {
++ .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
++ .name = "SMPTE Time Minutes",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = 1,
++ .info = snd_mts64_ctl_smpte_time_info,
++ .get = snd_mts64_ctl_smpte_time_get,
++ .put = snd_mts64_ctl_smpte_time_put
++};
++
++static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds __devinitdata = {
++ .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
++ .name = "SMPTE Time Seconds",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = 2,
++ .info = snd_mts64_ctl_smpte_time_info,
++ .get = snd_mts64_ctl_smpte_time_get,
++ .put = snd_mts64_ctl_smpte_time_put
++};
++
++static struct snd_kcontrol_new mts64_ctl_smpte_time_frames __devinitdata = {
++ .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
++ .name = "SMPTE Time Frames",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = 3,
++ .info = snd_mts64_ctl_smpte_time_f_info,
++ .get = snd_mts64_ctl_smpte_time_get,
++ .put = snd_mts64_ctl_smpte_time_put
++};
++
++/* FPS */
++static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_info *uinfo)
++{
++ static char *texts[5] = { "24",
++ "25",
++ "29.97",
++ "30D",
++ "30" };
++
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
++ uinfo->count = 1;
++ uinfo->value.enumerated.items = 5;
++ if (uinfo->value.enumerated.item > 4)
++ uinfo->value.enumerated.item = 4;
++ strcpy(uinfo->value.enumerated.name,
++ texts[uinfo->value.enumerated.item]);
++
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_value *uctl)
++{
++ struct mts64 *mts = snd_kcontrol_chip(kctl);
++
++ spin_lock_irq(&mts->lock);
++ uctl->value.enumerated.item[0] = mts->fps;
++ spin_unlock_irq(&mts->lock);
++
++ return 0;
++}
++
++static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl,
++ struct snd_ctl_elem_value *uctl)
++{
++ struct mts64 *mts = snd_kcontrol_chip(kctl);
++ int changed = 0;
++
++ spin_lock_irq(&mts->lock);
++ if (mts->fps != uctl->value.enumerated.item[0]) {
++ changed = 1;
++ mts->fps = uctl->value.enumerated.item[0];
++ }
++ spin_unlock_irq(&mts->lock);
++
++ return changed;
++}
++
++static struct snd_kcontrol_new mts64_ctl_smpte_fps __devinitdata = {
++ .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
++ .name = "SMPTE Fps",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = 0,
++ .info = snd_mts64_ctl_smpte_fps_info,
++ .get = snd_mts64_ctl_smpte_fps_get,
++ .put = snd_mts64_ctl_smpte_fps_put
++};
++
++
++static int __devinit snd_mts64_ctl_create(struct snd_card *card,
++ struct mts64 *mts)
++{
++ int err, i;
++ static struct snd_kcontrol_new *control[] = {
++ &mts64_ctl_smpte_switch,
++ &mts64_ctl_smpte_time_hours,
++ &mts64_ctl_smpte_time_minutes,
++ &mts64_ctl_smpte_time_seconds,
++ &mts64_ctl_smpte_time_frames,
++ &mts64_ctl_smpte_fps,
++ NULL };
++
++ for (i = 0; control[i]; ++i) {
++ err = snd_ctl_add(card, snd_ctl_new1(control[i], mts));
++ if (err < 0) {
++ snd_printd("Cannot create control: %s\n",
++ control[i]->name);
++ return err;
++ }
++ }
++
++ return 0;
++}
++
++/*********************************************************************
++ * Rawmidi
++ *********************************************************************/
++#define MTS64_MODE_INPUT_TRIGGERED 0x01
++
++static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream)
++{
++ struct mts64 *mts = substream->rmidi->private_data;
++
++ if (mts->open_count == 0) {
++ /* We don't need a spinlock here, because this is just called
++ if the device has not been opened before.
++ So there aren't any IRQs from the device */
++ mts64_device_open(mts);
++
++ msleep(50);
++ }
++ ++(mts->open_count);
++
++ return 0;
++}
++
++static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream)
++{
++ struct mts64 *mts = substream->rmidi->private_data;
++ unsigned long flags;
++
++ --(mts->open_count);
++ if (mts->open_count == 0) {
++ /* We need the spinlock_irqsave here because we can still
++ have IRQs at this point */
++ spin_lock_irqsave(&mts->lock, flags);
++ mts64_device_close(mts);
++ spin_unlock_irqrestore(&mts->lock, flags);
++
++ msleep(500);
++
++ } else if (mts->open_count < 0)
++ mts->open_count = 0;
++
++ return 0;
++}
++
++static void snd_mts64_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,
++ int up)
++{
++ struct mts64 *mts = substream->rmidi->private_data;
++ u8 data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&mts->lock, flags);
++ while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) {
++ mts64_write_midi(mts, data, substream->number+1);
++ snd_rawmidi_transmit_ack(substream, 1);
++ }
++ spin_unlock_irqrestore(&mts->lock, flags);
++}
++
++static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substream,
++ int up)
++{
++ struct mts64 *mts = substream->rmidi->private_data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&mts->lock, flags);
++ if (up)
++ mts->mode[substream->number] |= MTS64_MODE_INPUT_TRIGGERED;
++ else
++ mts->mode[substream->number] &= ~MTS64_MODE_INPUT_TRIGGERED;
++
++ spin_unlock_irqrestore(&mts->lock, flags);
++}
++
++static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
++ .open = snd_mts64_rawmidi_open,
++ .close = snd_mts64_rawmidi_close,
++ .trigger = snd_mts64_rawmidi_output_trigger
++};
++
++static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
++ .open = snd_mts64_rawmidi_open,
++ .close = snd_mts64_rawmidi_close,
++ .trigger = snd_mts64_rawmidi_input_trigger
++};
++
++/* Create and initialize the rawmidi component */
++static int __devinit snd_mts64_rawmidi_create(struct snd_card *card)
++{
++ struct mts64 *mts = card->private_data;
++ struct snd_rawmidi *rmidi;
++ struct snd_rawmidi_substream *substream;
++ struct list_head *list;
++ int err;
++
++ err = snd_rawmidi_new(card, CARD_NAME, 0,
++ MTS64_NUM_OUTPUT_PORTS,
++ MTS64_NUM_INPUT_PORTS,
++ &rmidi);
++ if (err < 0)
++ return err;
++
++ rmidi->private_data = mts;
++ strcpy(rmidi->name, CARD_NAME);
++ rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
++ SNDRV_RAWMIDI_INFO_INPUT |
++ SNDRV_RAWMIDI_INFO_DUPLEX;
++
++ mts->rmidi = rmidi;
++
++ /* register rawmidi ops */
++ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
++ &snd_mts64_rawmidi_output_ops);
++ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
++ &snd_mts64_rawmidi_input_ops);
++
++ /* name substreams */
++ /* output */
++ list_for_each(list,
++ &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
++ substream = list_entry(list, struct snd_rawmidi_substream, list);
++ sprintf(substream->name,
++ "Miditerminal %d", substream->number+1);
++ }
++ /* input */
++ list_for_each(list,
++ &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
++ substream = list_entry(list, struct snd_rawmidi_substream, list);
++ mts->midi_input_substream[substream->number] = substream;
++ switch(substream->number) {
++ case MTS64_SMPTE_SUBSTREAM:
++ strcpy(substream->name, "Miditerminal SMPTE");
++ break;
++ default:
++ sprintf(substream->name,
++ "Miditerminal %d", substream->number+1);
++ }
++ }
++
++ /* controls */
++ err = snd_mts64_ctl_create(card, mts);
++
++ return err;
++}
++
++/*********************************************************************
++ * parport stuff
++ *********************************************************************/
++static void snd_mts64_interrupt(int irq, void *private)
++{
++ struct mts64 *mts = ((struct snd_card*)private)->private_data;
++ u16 ret;
++ u8 status, data;
++ struct snd_rawmidi_substream *substream;
++
++ spin_lock(&mts->lock);
++ ret = mts64_read(mts->pardev->port);
++ data = ret & 0x00ff;
++ status = ret >> 8;
++
++ if (status & MTS64_STAT_PORT) {
++ mts->current_midi_input_port = mts64_map_midi_input(data);
++ } else {
++ if (mts->current_midi_input_port == -1)
++ goto __out;
++ substream = mts->midi_input_substream[mts->current_midi_input_port];
++ if (mts->mode[substream->number] & MTS64_MODE_INPUT_TRIGGERED)
++ snd_rawmidi_receive(substream, &data, 1);
++ }
++__out:
++ spin_unlock(&mts->lock);
++}
++
++static int __devinit snd_mts64_probe_port(struct parport *p)
++{
++ struct pardevice *pardev;
++ int res;
++
++ pardev = parport_register_device(p, DRIVER_NAME,
++ NULL, NULL, NULL,
++ 0, NULL);
++ if (!pardev)
++ return -EIO;
++
++ if (parport_claim(pardev)) {
++ parport_unregister_device(pardev);
++ return -EIO;
++ }
++
++ res = mts64_probe(p);
++
++ parport_release(pardev);
++ parport_unregister_device(pardev);
++
++ return res;
++}
++
++static void __devinit snd_mts64_attach(struct parport *p)
++{
++ struct platform_device *device;
++
++ device = platform_device_alloc(PLATFORM_DRIVER, device_count);
++ if (!device)
++ return;
++
++ /* Temporary assignment to forward the parport */
++ platform_set_drvdata(device, p);
++
++ if (platform_device_register(device) < 0) {
++ platform_device_put(device);
++ return;
++ }
++
++ /* Since we dont get the return value of probe
++ * We need to check if device probing succeeded or not */
++ if (!platform_get_drvdata(device)) {
++ platform_device_unregister(device);
++ return;
++ }
++
++ /* register device in global table */
++ platform_devices[device_count] = device;
++ device_count++;
++}
++
++static void snd_mts64_detach(struct parport *p)
++{
++ /* nothing to do here */
++}
++
++static struct parport_driver mts64_parport_driver = {
++ .name = "mts64",
++ .attach = snd_mts64_attach,
++ .detach = snd_mts64_detach
++};
++
++/*********************************************************************
++ * platform stuff
++ *********************************************************************/
++static void snd_mts64_card_private_free(struct snd_card *card)
++{
++ struct mts64 *mts = card->private_data;
++ struct pardevice *pardev = mts->pardev;
++
++ if (pardev) {
++ if (mts->pardev_claimed)
++ parport_release(pardev);
++ parport_unregister_device(pardev);
++ }
++
++ snd_mts64_free(mts);
++}
++
++static int __devinit snd_mts64_probe(struct platform_device *pdev)
++{
++ struct pardevice *pardev;
++ struct parport *p;
++ int dev = pdev->id;
++ struct snd_card *card = NULL;
++ struct mts64 *mts = NULL;
++ int err;
++
++ p = platform_get_drvdata(pdev);
++ platform_set_drvdata(pdev, NULL);
++
++ if (dev >= SNDRV_CARDS)
++ return -ENODEV;
++ if (!enable[dev])
++ return -ENOENT;
++ if ((err = snd_mts64_probe_port(p)) < 0)
++ return err;
++
++ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
++ if (card == NULL) {
++ snd_printd("Cannot create card\n");
++ return -ENOMEM;
++ }
++ strcpy(card->driver, DRIVER_NAME);
++ strcpy(card->shortname, "ESI " CARD_NAME);
++ sprintf(card->longname, "%s at 0x%lx, irq %i",
++ card->shortname, p->base, p->irq);
++
++ pardev = parport_register_device(p, /* port */
++ DRIVER_NAME, /* name */
++ NULL, /* preempt */
++ NULL, /* wakeup */
++ snd_mts64_interrupt, /* ISR */
++ PARPORT_DEV_EXCL, /* flags */
++ (void *)card); /* private */
++ if (pardev == NULL) {
++ snd_printd("Cannot register pardevice\n");
++ err = -EIO;
++ goto __err;
++ }
++
++ if ((err = snd_mts64_create(card, pardev, &mts)) < 0) {
++ snd_printd("Cannot create main component\n");
++ parport_unregister_device(pardev);
++ goto __err;
++ }
++ card->private_data = mts;
++ card->private_free = snd_mts64_card_private_free;
++
++ if ((err = snd_mts64_rawmidi_create(card)) < 0) {
++ snd_printd("Creating Rawmidi component failed\n");
++ goto __err;
++ }
++
++ /* claim parport */
++ if (parport_claim(pardev)) {
++ snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
++ err = -EIO;
++ goto __err;
++ }
++ mts->pardev_claimed = 1;
++
++ /* init device */
++ if ((err = mts64_device_init(p)) < 0)
++ goto __err;
++
++ platform_set_drvdata(pdev, card);
++
++ /* At this point card will be usable */
++ if ((err = snd_card_register(card)) < 0) {
++ snd_printd("Cannot register card\n");
++ goto __err;
++ }
++
++ snd_printk("ESI Miditerminal 4140 on 0x%lx\n", p->base);
++ return 0;
++
++__err:
++ snd_card_free(card);
++ return err;
++}
++
++static int snd_mts64_remove(struct platform_device *pdev)
++{
++ struct snd_card *card = platform_get_drvdata(pdev);
++
++ if (card)
++ snd_card_free(card);
++
++ return 0;
++}
++
++
++static struct platform_driver snd_mts64_driver = {
++ .probe = snd_mts64_probe,
++ .remove = snd_mts64_remove,
++ .driver = {
++ .name = PLATFORM_DRIVER
++ }
++};
++
++/*********************************************************************
++ * module init stuff
++ *********************************************************************/
++static void snd_mts64_unregister_all(void)
++{
++ int i;
++
++ for (i = 0; i < SNDRV_CARDS; ++i) {
++ if (platform_devices[i]) {
++ platform_device_unregister(platform_devices[i]);
++ platform_devices[i] = NULL;
++ }
++ }
++ platform_driver_unregister(&snd_mts64_driver);
++ parport_unregister_driver(&mts64_parport_driver);
++}
++
++static int __init snd_mts64_module_init(void)
++{
++ int err;
++
++ if ((err = platform_driver_register(&snd_mts64_driver)) < 0)
++ return err;
++
++ if (parport_register_driver(&mts64_parport_driver) != 0) {
++ platform_driver_unregister(&snd_mts64_driver);
++ return -EIO;
++ }
++
++ if (device_count == 0) {
++ snd_mts64_unregister_all();
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static void __exit snd_mts64_module_exit(void)
++{
++ snd_mts64_unregister_all();
++}
++
++module_init(snd_mts64_module_init);
++module_exit(snd_mts64_module_exit);
+diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c
+index e552ec3..1679300 100644
+--- a/sound/drivers/opl4/opl4_proc.c
++++ b/sound/drivers/opl4/opl4_proc.c
+@@ -105,13 +105,13 @@ static long long snd_opl4_mem_proc_llsee
+ struct file *file, long long offset, int orig)
+ {
+ switch (orig) {
+- case 0: /* SEEK_SET */
++ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+- case 1: /* SEEK_CUR */
++ case SEEK_CUR:
+ file->f_pos += offset;
+ break;
+- case 2: /* SEEK_END, offset is negative */
++ case SEEK_END: /* offset is negative */
+ file->f_pos = entry->size + offset;
+ break;
+ default:
+@@ -159,8 +159,7 @@ int snd_opl4_create_proc(struct snd_opl4
+
+ void snd_opl4_free_proc(struct snd_opl4 *opl4)
+ {
+- if (opl4->proc_entry)
+- snd_info_unregister(opl4->proc_entry);
++ snd_info_free_entry(opl4->proc_entry);
+ }
+
+ #endif /* CONFIG_PROC_FS */
+diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
+index 52afb4b..74028b2 100644
+--- a/sound/drivers/serial-u16550.c
++++ b/sound/drivers/serial-u16550.c
+@@ -292,7 +292,7 @@ static void snd_uart16550_io_loop(snd_ua
+ * Note that some devices need OUT2 to be set before they will generate
+ * interrupts at all. (Possibly tied to an internal pull-up on CTS?)
+ */
+-static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
+ {
+ snd_uart16550_t *uart;
+
+diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
+index a601682..ed19bc1 100644
+--- a/sound/drivers/vx/vx_core.c
++++ b/sound/drivers/vx/vx_core.c
+@@ -537,7 +537,7 @@ static void vx_interrupt(unsigned long p
+ /**
+ * snd_vx_irq_handler - interrupt handler
+ */
+-irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs)
++irqreturn_t snd_vx_irq_handler(int irq, void *dev)
+ {
+ struct vx_core *chip = dev;
+
+diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
+index c1d7fcd..1613ed8 100644
+--- a/sound/drivers/vx/vx_mixer.c
++++ b/sound/drivers/vx/vx_mixer.c
+@@ -23,6 +23,7 @@
+ #include <sound/driver.h>
+ #include <sound/core.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/vx_core.h>
+ #include "vx_cmd.h"
+
+@@ -455,10 +456,13 @@ static int vx_output_level_put(struct sn
+
+ static struct snd_kcontrol_new vx_control_output_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Master Playback Volume",
+ .info = vx_output_level_info,
+ .get = vx_output_level_get,
+ .put = vx_output_level_put,
++ /* tlv will be filled later */
+ };
+
+ /*
+@@ -712,12 +716,17 @@ static int vx_monitor_sw_put(struct snd_
+ return 0;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
++
+ static struct snd_kcontrol_new vx_control_audio_gain = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ /* name will be filled later */
+ .info = vx_audio_gain_info,
+ .get = vx_audio_gain_get,
+- .put = vx_audio_gain_put
++ .put = vx_audio_gain_put,
++ .tlv = { .p = db_scale_audio_gain },
+ };
+ static struct snd_kcontrol_new vx_control_output_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -729,9 +738,12 @@ static struct snd_kcontrol_new vx_contro
+ static struct snd_kcontrol_new vx_control_monitor_gain = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Monitoring Volume",
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .info = vx_audio_gain_info, /* shared */
+ .get = vx_audio_monitor_get,
+- .put = vx_audio_monitor_put
++ .put = vx_audio_monitor_put,
++ .tlv = { .p = db_scale_audio_gain },
+ };
+ static struct snd_kcontrol_new vx_control_monitor_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -918,6 +930,7 @@ int snd_vx_mixer_new(struct vx_core *chi
+ for (i = 0; i < chip->hw->num_outs; i++) {
+ temp = vx_control_output_level;
+ temp.index = i;
++ temp.tlv.p = chip->hw->output_level_db_scale;
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
+ return err;
+ }
+diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
+index dc7cc20..5da49e2 100644
+--- a/sound/i2c/other/ak4xxx-adda.c
++++ b/sound/i2c/other/ak4xxx-adda.c
+@@ -28,12 +28,14 @@
+ #include <linux/init.h>
+ #include <sound/core.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/ak4xxx-adda.h>
+
+ MODULE_AUTHOR("Jaroslav Kysela <perex at suse.cz>, Takashi Iwai <tiwai at suse.de>");
+ MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
+ MODULE_LICENSE("GPL");
+
++/* write the given register and save the data to the cache */
+ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+ unsigned char val)
+ {
+@@ -41,15 +43,7 @@ void snd_akm4xxx_write(struct snd_akm4xx
+ ak->ops.write(ak, chip, reg, val);
+
+ /* save the data */
+- if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
+- if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0)
+- snd_akm4xxx_set(ak, chip, reg, val);
+- else
+- snd_akm4xxx_set_ipga(ak, chip, reg, val);
+- } else {
+- /* AK4529, or else */
+- snd_akm4xxx_set(ak, chip, reg, val);
+- }
++ snd_akm4xxx_set(ak, chip, reg, val);
+ ak->ops.unlock(ak, chip);
+ }
+
+@@ -73,12 +67,6 @@ static void ak4524_reset(struct snd_akm4
+ for (reg = 0x04; reg < maxreg; reg++)
+ snd_akm4xxx_write(ak, chip, reg,
+ snd_akm4xxx_get(ak, chip, reg));
+- if (ak->type == SND_AK4528)
+- continue;
+- /* IPGA */
+- for (reg = 0x04; reg < 0x06; reg++)
+- snd_akm4xxx_write(ak, chip, reg,
+- snd_akm4xxx_get_ipga(ak, chip, reg));
+ }
+ }
+
+@@ -137,11 +125,48 @@ void snd_akm4xxx_reset(struct snd_akm4xx
+ case SND_AK4381:
+ ak4381_reset(ak, state);
+ break;
++ default:
++ break;
+ }
+ }
+
+ EXPORT_SYMBOL(snd_akm4xxx_reset);
+
++
++/*
++ * Volume conversion table for non-linear volumes
++ * from -63.5dB (mute) to 0dB step 0.5dB
++ *
++ * Used for AK4524 input/ouput attenuation, AK4528, and
++ * AK5365 input attenuation
++ */
++static unsigned char vol_cvt_datt[128] = {
++ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
++ 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
++ 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
++ 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
++ 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
++ 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
++ 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
++ 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
++ 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
++ 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
++ 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
++ 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
++ 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
++ 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
++ 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
++ 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
++};
++
++/*
++ * dB tables
++ */
++static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
++static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
++static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
++static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
++
+ /*
+ * initialize all the ak4xxx chips
+ */
+@@ -155,8 +180,6 @@ void snd_akm4xxx_init(struct snd_akm4xxx
+ 0x01, 0x03, /* 1: ADC/DAC enable */
+ 0x04, 0x00, /* 4: ADC left muted */
+ 0x05, 0x00, /* 5: ADC right muted */
+- 0x04, 0x80, /* 4: ADC IPGA gain 0dB */
+- 0x05, 0x80, /* 5: ADC IPGA gain 0dB */
+ 0x06, 0x00, /* 6: DAC left muted */
+ 0x07, 0x00, /* 7: DAC right muted */
+ 0xff, 0xff
+@@ -238,6 +261,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx
+ int chip, num_chips;
+ unsigned char *ptr, reg, data, *inits;
+
++ memset(ak->images, 0, sizeof(ak->images));
++ memset(ak->volumes, 0, sizeof(ak->volumes));
++
+ switch (ak->type) {
+ case SND_AK4524:
+ inits = inits_ak4524;
+@@ -263,6 +289,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx
+ inits = inits_ak4381;
+ num_chips = ak->num_dacs / 2;
+ break;
++ case SND_AK5365:
++ /* FIXME: any init sequence? */
++ return;
+ default:
+ snd_BUG();
+ return;
+@@ -280,14 +309,23 @@ void snd_akm4xxx_init(struct snd_akm4xxx
+
+ EXPORT_SYMBOL(snd_akm4xxx_init);
+
++/*
++ * Mixer callbacks
++ */
++#define AK_IPGA (1<<20) /* including IPGA */
++#define AK_VOL_CVT (1<<21) /* need dB conversion */
++#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
++#define AK_INVERT (1<<23) /* data is inverted */
+ #define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
+ #define AK_GET_ADDR(val) ((val) & 0xff)
+-#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f)
++#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
++#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
++#define AK_GET_IPGA(val) (((val) >> 20) & 1)
++#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
+ #define AK_GET_INVERT(val) (((val) >> 23) & 1)
+ #define AK_GET_MASK(val) (((val) >> 24) & 0xff)
+ #define AK_COMPOSE(chip,addr,shift,mask) \
+ (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
+-#define AK_INVERT (1<<23)
+
+ static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+@@ -307,31 +345,39 @@ static int snd_akm4xxx_volume_get(struct
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+- int invert = AK_GET_INVERT(kcontrol->private_value);
+- unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+- unsigned char val = snd_akm4xxx_get(ak, chip, addr);
+-
+- ucontrol->value.integer.value[0] = invert ? mask - val : val;
++
++ ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
+ return 0;
+ }
+
+-static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
++ unsigned char nval)
+ {
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+- int chip = AK_GET_CHIP(kcontrol->private_value);
+- int addr = AK_GET_ADDR(kcontrol->private_value);
+- int invert = AK_GET_INVERT(kcontrol->private_value);
+ unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+- unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
+- int change;
++ int chip = AK_GET_CHIP(kcontrol->private_value);
+
+- if (invert)
++ if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
++ return 0;
++
++ snd_akm4xxx_set_vol(ak, chip, addr, nval);
++ if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
++ nval = vol_cvt_datt[nval];
++ if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
++ nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
++ if (AK_GET_INVERT(kcontrol->private_value))
+ nval = mask - nval;
+- change = snd_akm4xxx_get(ak, chip, addr) != nval;
+- if (change)
+- snd_akm4xxx_write(ak, chip, addr, nval);
+- return change;
++ if (AK_GET_NEEDSMSB(kcontrol->private_value))
++ nval |= 0x80;
++ snd_akm4xxx_write(ak, chip, addr, nval);
++ return 1;
++}
++
++static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
++ ucontrol->value.integer.value[0]);
+ }
+
+ static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
+@@ -352,77 +398,21 @@ static int snd_akm4xxx_stereo_volume_get
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+- int invert = AK_GET_INVERT(kcontrol->private_value);
+- unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+- unsigned char val = snd_akm4xxx_get(ak, chip, addr);
+-
+- ucontrol->value.integer.value[0] = invert ? mask - val : val;
+-
+- val = snd_akm4xxx_get(ak, chip, addr+1);
+- ucontrol->value.integer.value[1] = invert ? mask - val : val;
+
++ ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
++ ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
+ return 0;
+ }
+
+ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+- struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+- int chip = AK_GET_CHIP(kcontrol->private_value);
+- int addr = AK_GET_ADDR(kcontrol->private_value);
+- int invert = AK_GET_INVERT(kcontrol->private_value);
+- unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+- unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
+- int change0, change1;
+-
+- if (invert)
+- nval = mask - nval;
+- change0 = snd_akm4xxx_get(ak, chip, addr) != nval;
+- if (change0)
+- snd_akm4xxx_write(ak, chip, addr, nval);
+-
+- nval = ucontrol->value.integer.value[1] % (mask+1);
+- if (invert)
+- nval = mask - nval;
+- change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval;
+- if (change1)
+- snd_akm4xxx_write(ak, chip, addr+1, nval);
+-
+-
+- return change0 || change1;
+-}
+-
+-static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_info *uinfo)
+-{
+- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+- uinfo->count = 1;
+- uinfo->value.integer.min = 0;
+- uinfo->value.integer.max = 36;
+- return 0;
+-}
+-
+-static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+- int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+- ucontrol->value.integer.value[0] =
+- snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
+- return 0;
+-}
++ int change;
+
+-static int snd_akm4xxx_ipga_gain_put(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+- int chip = AK_GET_CHIP(kcontrol->private_value);
+- int addr = AK_GET_ADDR(kcontrol->private_value);
+- unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
+- int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval;
+- if (change)
+- snd_akm4xxx_write(ak, chip, addr, nval);
++ change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
++ change |= put_ak_reg(kcontrol, addr + 1,
++ ucontrol->value.integer.value[1]);
+ return change;
+ }
+
+@@ -472,179 +462,280 @@ static int snd_akm4xxx_deemphasis_put(st
+ return change;
+ }
+
++static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 1;
++ return 0;
++}
++
++static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
++ int chip = AK_GET_CHIP(kcontrol->private_value);
++ int addr = AK_GET_ADDR(kcontrol->private_value);
++ int shift = AK_GET_SHIFT(kcontrol->private_value);
++ int invert = AK_GET_INVERT(kcontrol->private_value);
++ unsigned char val = snd_akm4xxx_get(ak, chip, addr);
++
++ if (invert)
++ val = ! val;
++ ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
++ return 0;
++}
++
++static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
++ int chip = AK_GET_CHIP(kcontrol->private_value);
++ int addr = AK_GET_ADDR(kcontrol->private_value);
++ int shift = AK_GET_SHIFT(kcontrol->private_value);
++ int invert = AK_GET_INVERT(kcontrol->private_value);
++ long flag = ucontrol->value.integer.value[0];
++ unsigned char val, oval;
++ int change;
++
++ if (invert)
++ flag = ! flag;
++ oval = snd_akm4xxx_get(ak, chip, addr);
++ if (flag)
++ val = oval | (1<<shift);
++ else
++ val = oval & ~(1<<shift);
++ change = (oval != val);
++ if (change)
++ snd_akm4xxx_write(ak, chip, addr, val);
++ return change;
++}
++
+ /*
+ * build AK4xxx controls
+ */
+
+-int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
++static int build_dac_controls(struct snd_akm4xxx *ak)
+ {
+- unsigned int idx, num_emphs;
+- struct snd_kcontrol *ctl;
+- int err;
+- int mixer_ch = 0;
+- int num_stereo;
+-
+- ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
+- if (! ctl)
+- return -ENOMEM;
++ int idx, err, mixer_ch, num_stereo;
++ struct snd_kcontrol_new knew;
+
++ mixer_ch = 0;
+ for (idx = 0; idx < ak->num_dacs; ) {
+- memset(ctl, 0, sizeof(*ctl));
+- if (ak->channel_names == NULL) {
+- strcpy(ctl->id.name, "DAC Volume");
++ memset(&knew, 0, sizeof(knew));
++ if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
++ knew.name = "DAC Volume";
++ knew.index = mixer_ch + ak->idx_offset * 2;
+ num_stereo = 1;
+- ctl->id.index = mixer_ch + ak->idx_offset * 2;
+ } else {
+- strcpy(ctl->id.name, ak->channel_names[mixer_ch]);
+- num_stereo = ak->num_stereo[mixer_ch];
+- ctl->id.index = 0;
++ knew.name = ak->dac_info[mixer_ch].name;
++ num_stereo = ak->dac_info[mixer_ch].num_channels;
+ }
+- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+- ctl->count = 1;
++ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
++ knew.count = 1;
++ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ if (num_stereo == 2) {
+- ctl->info = snd_akm4xxx_stereo_volume_info;
+- ctl->get = snd_akm4xxx_stereo_volume_get;
+- ctl->put = snd_akm4xxx_stereo_volume_put;
++ knew.info = snd_akm4xxx_stereo_volume_info;
++ knew.get = snd_akm4xxx_stereo_volume_get;
++ knew.put = snd_akm4xxx_stereo_volume_put;
+ } else {
+- ctl->info = snd_akm4xxx_volume_info;
+- ctl->get = snd_akm4xxx_volume_get;
+- ctl->put = snd_akm4xxx_volume_put;
++ knew.info = snd_akm4xxx_volume_info;
++ knew.get = snd_akm4xxx_volume_get;
++ knew.put = snd_akm4xxx_volume_put;
+ }
+ switch (ak->type) {
+ case SND_AK4524:
+ /* register 6 & 7 */
+- ctl->private_value =
+- AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127);
++ knew.private_value =
++ AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
++ AK_VOL_CVT;
++ knew.tlv.p = db_scale_vol_datt;
+ break;
+ case SND_AK4528:
+ /* register 4 & 5 */
+- ctl->private_value =
+- AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
++ knew.private_value =
++ AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
++ AK_VOL_CVT;
++ knew.tlv.p = db_scale_vol_datt;
+ break;
+ case SND_AK4529: {
+ /* registers 2-7 and b,c */
+ int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
+- ctl->private_value =
++ knew.private_value =
+ AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
++ knew.tlv.p = db_scale_8bit;
+ break;
+ }
+ case SND_AK4355:
+ /* register 4-9, chip #0 only */
+- ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255);
++ knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
++ knew.tlv.p = db_scale_8bit;
+ break;
+- case SND_AK4358:
+- if (idx >= 6)
+- /* register 4-9, chip #0 only */
+- ctl->private_value =
+- AK_COMPOSE(0, idx + 5, 0, 255);
+- else
+- /* register 4-9, chip #0 only */
+- ctl->private_value =
+- AK_COMPOSE(0, idx + 4, 0, 255);
++ case SND_AK4358: {
++ /* register 4-9 and 11-12, chip #0 only */
++ int addr = idx < 6 ? idx + 4 : idx + 5;
++ knew.private_value =
++ AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
++ knew.tlv.p = db_scale_7bit;
+ break;
++ }
+ case SND_AK4381:
+ /* register 3 & 4 */
+- ctl->private_value =
++ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
++ knew.tlv.p = db_scale_linear;
+ break;
+ default:
+- err = -EINVAL;
+- goto __error;
++ return -EINVAL;
+ }
+
+- ctl->private_data = ak;
+- err = snd_ctl_add(ak->card,
+- snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+- SNDRV_CTL_ELEM_ACCESS_WRITE));
++ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+- goto __error;
++ return err;
+
+ idx += num_stereo;
+ mixer_ch++;
+ }
+- for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
+- memset(ctl, 0, sizeof(*ctl));
+- strcpy(ctl->id.name, "ADC Volume");
+- ctl->id.index = idx + ak->idx_offset * 2;
+- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+- ctl->count = 1;
+- ctl->info = snd_akm4xxx_volume_info;
+- ctl->get = snd_akm4xxx_volume_get;
+- ctl->put = snd_akm4xxx_volume_put;
+- /* register 4 & 5 */
+- ctl->private_value =
+- AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
+- ctl->private_data = ak;
+- err = snd_ctl_add(ak->card,
+- snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+- SNDRV_CTL_ELEM_ACCESS_WRITE));
+- if (err < 0)
+- goto __error;
+-
+- memset(ctl, 0, sizeof(*ctl));
+- strcpy(ctl->id.name, "IPGA Analog Capture Volume");
+- ctl->id.index = idx + ak->idx_offset * 2;
+- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+- ctl->count = 1;
+- ctl->info = snd_akm4xxx_ipga_gain_info;
+- ctl->get = snd_akm4xxx_ipga_gain_get;
+- ctl->put = snd_akm4xxx_ipga_gain_put;
++ return 0;
++}
++
++static int build_adc_controls(struct snd_akm4xxx *ak)
++{
++ int idx, err, mixer_ch, num_stereo;
++ struct snd_kcontrol_new knew;
++
++ mixer_ch = 0;
++ for (idx = 0; idx < ak->num_adcs;) {
++ memset(&knew, 0, sizeof(knew));
++ if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
++ knew.name = "ADC Volume";
++ knew.index = mixer_ch + ak->idx_offset * 2;
++ num_stereo = 1;
++ } else {
++ knew.name = ak->adc_info[mixer_ch].name;
++ num_stereo = ak->adc_info[mixer_ch].num_channels;
++ }
++ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
++ knew.count = 1;
++ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ;
++ if (num_stereo == 2) {
++ knew.info = snd_akm4xxx_stereo_volume_info;
++ knew.get = snd_akm4xxx_stereo_volume_get;
++ knew.put = snd_akm4xxx_stereo_volume_put;
++ } else {
++ knew.info = snd_akm4xxx_volume_info;
++ knew.get = snd_akm4xxx_volume_get;
++ knew.put = snd_akm4xxx_volume_put;
++ }
+ /* register 4 & 5 */
+- ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0);
+- ctl->private_data = ak;
+- err = snd_ctl_add(ak->card,
+- snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+- SNDRV_CTL_ELEM_ACCESS_WRITE));
++ if (ak->type == SND_AK5365)
++ knew.private_value =
++ AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
++ AK_VOL_CVT | AK_IPGA;
++ else
++ knew.private_value =
++ AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
++ AK_VOL_CVT | AK_IPGA;
++ knew.tlv.p = db_scale_vol_datt;
++ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+- goto __error;
++ return err;
++
++ if (ak->type == SND_AK5365 && (idx % 2) == 0) {
++ if (! ak->adc_info ||
++ ! ak->adc_info[mixer_ch].switch_name)
++ knew.name = "Capture Switch";
++ else
++ knew.name = ak->adc_info[mixer_ch].switch_name;
++ knew.info = ak4xxx_switch_info;
++ knew.get = ak4xxx_switch_get;
++ knew.put = ak4xxx_switch_put;
++ knew.access = 0;
++ /* register 2, bit 0 (SMUTE): 0 = normal operation,
++ 1 = mute */
++ knew.private_value =
++ AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
++ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
++ if (err < 0)
++ return err;
++ }
++
++ idx += num_stereo;
++ mixer_ch++;
+ }
+- if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
+- num_emphs = 1;
+- else
+- num_emphs = ak->num_dacs / 2;
++ return 0;
++}
++
++static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
++{
++ int idx, err;
++ struct snd_kcontrol_new knew;
++
+ for (idx = 0; idx < num_emphs; idx++) {
+- memset(ctl, 0, sizeof(*ctl));
+- strcpy(ctl->id.name, "Deemphasis");
+- ctl->id.index = idx + ak->idx_offset;
+- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+- ctl->count = 1;
+- ctl->info = snd_akm4xxx_deemphasis_info;
+- ctl->get = snd_akm4xxx_deemphasis_get;
+- ctl->put = snd_akm4xxx_deemphasis_put;
++ memset(&knew, 0, sizeof(knew));
++ knew.name = "Deemphasis";
++ knew.index = idx + ak->idx_offset;
++ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
++ knew.count = 1;
++ knew.info = snd_akm4xxx_deemphasis_info;
++ knew.get = snd_akm4xxx_deemphasis_get;
++ knew.put = snd_akm4xxx_deemphasis_put;
+ switch (ak->type) {
+ case SND_AK4524:
+ case SND_AK4528:
+ /* register 3 */
+- ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
++ knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
+ break;
+ case SND_AK4529: {
+ int shift = idx == 3 ? 6 : (2 - idx) * 2;
+ /* register 8 with shift */
+- ctl->private_value = AK_COMPOSE(0, 8, shift, 0);
++ knew.private_value = AK_COMPOSE(0, 8, shift, 0);
+ break;
+ }
+ case SND_AK4355:
+ case SND_AK4358:
+- ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
++ knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
+ break;
+ case SND_AK4381:
+- ctl->private_value = AK_COMPOSE(idx, 1, 1, 0);
++ knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
+ break;
++ default:
++ return -EINVAL;
+ }
+- ctl->private_data = ak;
+- err = snd_ctl_add(ak->card,
+- snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+- SNDRV_CTL_ELEM_ACCESS_WRITE));
++ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+- goto __error;
++ return err;
+ }
+- err = 0;
+-
+- __error:
+- kfree(ctl);
+- return err;
++ return 0;
+ }
+
++int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
++{
++ int err, num_emphs;
++
++ err = build_dac_controls(ak);
++ if (err < 0)
++ return err;
++
++ err = build_adc_controls(ak);
++ if (err < 0)
++ return err;
++
++ if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
++ num_emphs = 1;
++ else
++ num_emphs = ak->num_dacs / 2;
++ err = build_deemphasis(ak, num_emphs);
++ if (err < 0)
++ return err;
++
++ return 0;
++}
++
+ EXPORT_SYMBOL(snd_akm4xxx_build_controls);
+
+ static int __init alsa_akm4xxx_module_init(void)
+diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
+index 557c4de..57371f1 100644
+--- a/sound/isa/Kconfig
++++ b/sound/isa/Kconfig
+@@ -13,6 +13,7 @@ config SND_CS4231_LIB
+
+ config SND_ADLIB
+ tristate "AdLib FM card"
++ depends on SND
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for AdLib FM cards.
+diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
+index b33a5fb..5903450 100644
+--- a/sound/isa/ad1816a/ad1816a.c
++++ b/sound/isa/ad1816a/ad1816a.c
+@@ -120,6 +120,8 @@ static int __devinit snd_card_ad1816a_pn
+ struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+ int err;
+
++ if (!cfg)
++ return -ENOMEM;
+ acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (acard->dev == NULL) {
+ kfree(cfg);
+diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
+index 8fcf2c1..b524e0d 100644
+--- a/sound/isa/ad1816a/ad1816a_lib.c
++++ b/sound/isa/ad1816a/ad1816a_lib.c
+@@ -24,6 +24,7 @@
+ #include <linux/slab.h>
+ #include <linux/ioport.h>
+ #include <sound/core.h>
++#include <sound/tlv.h>
+ #include <sound/ad1816a.h>
+
+ #include <asm/io.h>
+@@ -314,7 +315,7 @@ static snd_pcm_uframes_t snd_ad1816a_cap
+ }
+
+
+-static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id)
+ {
+ struct snd_ad1816a *chip = dev_id;
+ unsigned char status;
+@@ -765,6 +766,13 @@ static int snd_ad1816a_put_mux(struct sn
+ return change;
+ }
+
++#define AD1816A_SINGLE_TLV(xname, reg, shift, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .info = snd_ad1816a_info_single, \
++ .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
++ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
++ .tlv = { .p = (xtlv) } }
+ #define AD1816A_SINGLE(xname, reg, shift, mask, invert) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \
+ .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
+@@ -822,6 +830,14 @@ static int snd_ad1816a_put_single(struct
+ return change;
+ }
+
++#define AD1816A_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .info = snd_ad1816a_info_double, \
++ .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
++ .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \
++ .tlv = { .p = (xtlv) } }
++
+ #define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \
+ .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
+@@ -890,28 +906,44 @@ static int snd_ad1816a_put_double(struct
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
++
+ static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
+ AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1),
++AD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1,
++ db_scale_5bit),
+ AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1),
++AD1816A_DOUBLE_TLV("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1,
++ db_scale_6bit),
+ AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1),
++AD1816A_DOUBLE_TLV("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1,
++ db_scale_5bit_12db_max),
+ AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1),
++AD1816A_DOUBLE_TLV("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1,
++ db_scale_5bit_12db_max),
+ AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1),
++AD1816A_DOUBLE_TLV("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1,
++ db_scale_5bit_12db_max),
+ AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1),
++AD1816A_DOUBLE_TLV("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1,
++ db_scale_6bit),
+ AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
+-AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1),
++AD1816A_SINGLE_TLV("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1,
++ db_scale_5bit_12db_max),
+ AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
+ AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
+-AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1),
++AD1816A_DOUBLE_TLV("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1,
++ db_scale_5bit_12db_max),
+ AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1),
+-AD1816A_SINGLE("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1),
++AD1816A_SINGLE_TLV("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1,
++ db_scale_4bit),
+ AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1),
+-AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1),
++AD1816A_SINGLE_TLV("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1,
++ db_scale_5bit),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+@@ -920,7 +952,8 @@ AD1816A_SINGLE("Phone Playback Volume",
+ .put = snd_ad1816a_put_mux,
+ },
+ AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1),
+-AD1816A_DOUBLE("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0),
++AD1816A_DOUBLE_TLV("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0,
++ db_scale_rec_gain),
+ AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1),
+ AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0),
+ };
+diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
+index e711f87..666b3bc 100644
+--- a/sound/isa/ad1848/ad1848_lib.c
++++ b/sound/isa/ad1848/ad1848_lib.c
+@@ -29,6 +29,7 @@
+ #include <sound/core.h>
+ #include <sound/ad1848.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/pcm_params.h>
+
+ #include <asm/io.h>
+@@ -118,6 +119,8 @@ void snd_ad1848_out(struct snd_ad1848 *c
+ #endif
+ }
+
++EXPORT_SYMBOL(snd_ad1848_out);
++
+ static void snd_ad1848_dout(struct snd_ad1848 *chip,
+ unsigned char reg, unsigned char value)
+ {
+@@ -580,7 +583,7 @@ static int snd_ad1848_capture_prepare(st
+ return 0;
+ }
+
+-static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id)
+ {
+ struct snd_ad1848 *chip = dev_id;
+
+@@ -941,6 +944,8 @@ int snd_ad1848_create(struct snd_card *c
+ return 0;
+ }
+
++EXPORT_SYMBOL(snd_ad1848_create);
++
+ static struct snd_pcm_ops snd_ad1848_playback_ops = {
+ .open = snd_ad1848_playback_open,
+ .close = snd_ad1848_playback_close,
+@@ -988,12 +993,16 @@ int snd_ad1848_pcm(struct snd_ad1848 *ch
+ return 0;
+ }
+
++EXPORT_SYMBOL(snd_ad1848_pcm);
++
+ const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
+ {
+ return direction == SNDRV_PCM_STREAM_PLAYBACK ?
+ &snd_ad1848_playback_ops : &snd_ad1848_capture_ops;
+ }
+
++EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
++
+ /*
+ * MIXER part
+ */
+@@ -1171,7 +1180,8 @@ static int snd_ad1848_put_double(struct
+
+ /*
+ */
+-int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value)
++int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip,
++ const struct ad1848_mix_elem *c)
+ {
+ static struct snd_kcontrol_new newctls[] = {
+ [AD1848_MIX_SINGLE] = {
+@@ -1196,32 +1206,46 @@ int snd_ad1848_add_ctl(struct snd_ad1848
+ struct snd_kcontrol *ctl;
+ int err;
+
+- ctl = snd_ctl_new1(&newctls[type], chip);
++ ctl = snd_ctl_new1(&newctls[c->type], chip);
+ if (! ctl)
+ return -ENOMEM;
+- strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
+- ctl->id.index = index;
+- ctl->private_value = value;
++ strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name));
++ ctl->id.index = c->index;
++ ctl->private_value = c->private_value;
++ if (c->tlv) {
++ ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
++ ctl->tlv.p = c->tlv;
++ }
+ if ((err = snd_ctl_add(chip->card, ctl)) < 0)
+ return err;
+ return 0;
+ }
+
++EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
++
++static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+
+ static struct ad1848_mix_elem snd_ad1848_controls[] = {
+ AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
+-AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
++AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1,
++ db_scale_6bit),
+ AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+-AD1848_DOUBLE("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
++AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
++ db_scale_5bit_12db_max),
+ AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+-AD1848_DOUBLE("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+-AD1848_DOUBLE("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0),
++AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
++ db_scale_5bit_12db_max),
++AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0,
++ db_scale_rec_gain),
+ {
+ .name = "Capture Source",
+ .type = AD1848_MIX_CAPTURE,
+ },
+ AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
+-AD1848_SINGLE("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0)
++AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0,
++ db_scale_6bit),
+ };
+
+ int snd_ad1848_mixer(struct snd_ad1848 *chip)
+@@ -1245,12 +1269,7 @@ int snd_ad1848_mixer(struct snd_ad1848 *
+ return 0;
+ }
+
+-EXPORT_SYMBOL(snd_ad1848_out);
+-EXPORT_SYMBOL(snd_ad1848_create);
+-EXPORT_SYMBOL(snd_ad1848_pcm);
+-EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
+ EXPORT_SYMBOL(snd_ad1848_mixer);
+-EXPORT_SYMBOL(snd_ad1848_add_ctl);
+
+ /*
+ * INIT part
+diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
+index 3c1e9fd..d1f6dfc 100644
+--- a/sound/isa/cmi8330.c
++++ b/sound/isa/cmi8330.c
+@@ -289,6 +289,8 @@ static int __devinit snd_cmi8330_pnp(int
+ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+ int err;
+
++ if (!cfg)
++ return -ENOMEM;
+ acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (acard->cap == NULL) {
+ kfree(cfg);
+diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
+index fbb2017..75c7c5f 100644
+--- a/sound/isa/cs423x/cs4231_lib.c
++++ b/sound/isa/cs423x/cs4231_lib.c
+@@ -920,7 +920,7 @@ static void snd_cs4231_overrange(struct
+ chip->capture_substream->runtime->overrange++;
+ }
+
+-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id)
+ {
+ struct snd_cs4231 *chip = dev_id;
+ unsigned char status;
+diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
+index 7e985d3..a2ab99f 100644
+--- a/sound/isa/es1688/es1688_lib.c
++++ b/sound/isa/es1688/es1688_lib.c
+@@ -479,7 +479,7 @@ static int snd_es1688_capture_trigger(st
+ return snd_es1688_trigger(chip, cmd, 0x0f);
+ }
+
+-static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id)
+ {
+ struct snd_es1688 *chip = dev_id;
+
+diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
+index 34998de..725c115 100644
+--- a/sound/isa/es18xx.c
++++ b/sound/isa/es18xx.c
+@@ -754,7 +754,7 @@ static int snd_es18xx_playback_trigger(s
+ return snd_es18xx_playback2_trigger(chip, substream, cmd);
+ }
+
+-static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
+ {
+ struct snd_es18xx *chip = dev_id;
+ unsigned char status;
+@@ -799,7 +799,7 @@ static irqreturn_t snd_es18xx_interrupt(
+
+ /* MPU */
+ if ((status & MPU_IRQ) && chip->rmidi)
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+
+ /* Hardware volume */
+ if (status & HWV_IRQ) {
+@@ -2038,7 +2038,80 @@ MODULE_PARM_DESC(dma2, "DMA 2 # for ES18
+ static struct platform_device *platform_devices[SNDRV_CARDS];
+
+ #ifdef CONFIG_PNP
+-static int pnp_registered;
++static int pnp_registered, pnpc_registered;
++
++static struct pnp_device_id snd_audiodrive_pnpbiosids[] = {
++ { .id = "ESS1869" },
++ { .id = "" } /* end */
++};
++
++MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);
++
++/* PnP main device initialization */
++static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev,
++ struct pnp_resource_table *cfg)
++{
++ int err;
++
++ pnp_init_resource_table(cfg);
++ if (port[dev] != SNDRV_AUTO_PORT)
++ pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
++ if (fm_port[dev] != SNDRV_AUTO_PORT)
++ pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
++ if (mpu_port[dev] != SNDRV_AUTO_PORT)
++ pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
++ if (dma1[dev] != SNDRV_AUTO_DMA)
++ pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
++ if (dma2[dev] != SNDRV_AUTO_DMA)
++ pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
++ if (irq[dev] != SNDRV_AUTO_IRQ)
++ pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
++ if (pnp_device_is_isapnp(pdev)) {
++ err = pnp_manual_config_dev(pdev, cfg, 0);
++ if (err < 0)
++ snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
++ }
++ err = pnp_activate_dev(pdev);
++ if (err < 0) {
++ snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
++ return -EBUSY;
++ }
++ /* ok. hack using Vendor-Defined Card-Level registers */
++ /* skip csn and logdev initialization - already done in isapnp_configure */
++ if (pnp_device_is_isapnp(pdev)) {
++ isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
++ isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */
++ if (mpu_port[dev] != SNDRV_AUTO_PORT)
++ isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
++ isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */
++ isapnp_cfg_end();
++ }
++ port[dev] = pnp_port_start(pdev, 0);
++ fm_port[dev] = pnp_port_start(pdev, 1);
++ mpu_port[dev] = pnp_port_start(pdev, 2);
++ dma1[dev] = pnp_dma(pdev, 0);
++ dma2[dev] = pnp_dma(pdev, 1);
++ irq[dev] = pnp_irq(pdev, 0);
++ snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
++ snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
++ return 0;
++}
++
++static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
++ struct pnp_dev *pdev)
++{
++ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
++
++ if (!cfg)
++ return -ENOMEM;
++ acard->dev = pdev;
++ if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) {
++ kfree(cfg);
++ return -EBUSY;
++ }
++ kfree(cfg);
++ return 0;
++}
+
+ static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
+ /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */
+@@ -2061,13 +2134,11 @@ static struct pnp_card_device_id snd_aud
+
+ MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
+
+-static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
++static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
+ {
+- struct pnp_dev *pdev;
+ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+- int err;
+
+ if (!cfg)
+ return -ENOMEM;
+@@ -2082,58 +2153,17 @@ static int __devinit snd_audiodrive_pnp(
+ return -EBUSY;
+ }
+ /* Control port initialization */
+- err = pnp_activate_dev(acard->devc);
+- if (err < 0) {
+- snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
++ if (pnp_activate_dev(acard->devc) < 0) {
+ kfree(cfg);
++ snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
+ return -EAGAIN;
+ }
+ snd_printdd("pnp: port=0x%llx\n",
+ (unsigned long long)pnp_port_start(acard->devc, 0));
+- /* PnP initialization */
+- pdev = acard->dev;
+- pnp_init_resource_table(cfg);
+- if (port[dev] != SNDRV_AUTO_PORT)
+- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
+- if (fm_port[dev] != SNDRV_AUTO_PORT)
+- pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
+- if (mpu_port[dev] != SNDRV_AUTO_PORT)
+- pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
+- if (dma1[dev] != SNDRV_AUTO_DMA)
+- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
+- if (dma2[dev] != SNDRV_AUTO_DMA)
+- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
+- if (irq[dev] != SNDRV_AUTO_IRQ)
+- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
+- err = pnp_manual_config_dev(pdev, cfg, 0);
+- if (err < 0)
+- snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
+- err = pnp_activate_dev(pdev);
+- if (err < 0) {
+- snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
++ if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) {
+ kfree(cfg);
+ return -EBUSY;
+ }
+- /* ok. hack using Vendor-Defined Card-Level registers */
+- /* skip csn and logdev initialization - already done in isapnp_configure */
+- if (pnp_device_is_isapnp(pdev)) {
+- isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
+- isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */
+- if (mpu_port[dev] != SNDRV_AUTO_PORT)
+- isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
+- isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */
+- isapnp_cfg_end();
+- } else {
+- snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n");
+- }
+- port[dev] = pnp_port_start(pdev, 0);
+- fm_port[dev] = pnp_port_start(pdev, 1);
+- mpu_port[dev] = pnp_port_start(pdev, 2);
+- dma1[dev] = pnp_dma(pdev, 0);
+- dma2[dev] = pnp_dma(pdev, 1);
+- irq[dev] = pnp_irq(pdev, 0);
+- snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
+- snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
+ kfree(cfg);
+ return 0;
+ }
+@@ -2302,7 +2332,69 @@ static struct platform_driver snd_es18xx
+ #ifdef CONFIG_PNP
+ static unsigned int __devinitdata es18xx_pnp_devices;
+
+-static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
++static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
++ const struct pnp_device_id *id)
++{
++ static int dev;
++ int err;
++ struct snd_card *card;
++
++ if (pnp_device_is_isapnp(pdev))
++ return -ENOENT; /* we have another procedure - card */
++ for (; dev < SNDRV_CARDS; dev++) {
++ if (enable[dev] && isapnp[dev])
++ break;
++ }
++ if (dev >= SNDRV_CARDS)
++ return -ENODEV;
++
++ card = snd_es18xx_card_new(dev);
++ if (! card)
++ return -ENOMEM;
++ if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
++ snd_card_free(card);
++ return err;
++ }
++ snd_card_set_dev(card, &pdev->dev);
++ if ((err = snd_audiodrive_probe(card, dev)) < 0) {
++ snd_card_free(card);
++ return err;
++ }
++ pnp_set_drvdata(pdev, card);
++ dev++;
++ es18xx_pnp_devices++;
++ return 0;
++}
++
++static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev)
++{
++ snd_card_free(pnp_get_drvdata(pdev));
++ pnp_set_drvdata(pdev, NULL);
++}
++
++#ifdef CONFIG_PM
++static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
++{
++ return snd_es18xx_suspend(pnp_get_drvdata(pdev), state);
++}
++static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev)
++{
++ return snd_es18xx_resume(pnp_get_drvdata(pdev));
++}
++#endif
++
++static struct pnp_driver es18xx_pnp_driver = {
++ .name = "es18xx-pnpbios",
++ .id_table = snd_audiodrive_pnpbiosids,
++ .probe = snd_audiodrive_pnp_detect,
++ .remove = __devexit_p(snd_audiodrive_pnp_remove),
++#ifdef CONFIG_PM
++ .suspend = snd_audiodrive_pnp_suspend,
++ .resume = snd_audiodrive_pnp_resume,
++#endif
++};
++
++static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+ {
+ static int dev;
+@@ -2320,7 +2412,7 @@ static int __devinit snd_audiodrive_pnp_
+ if (! card)
+ return -ENOMEM;
+
+- if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) {
++ if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
+ snd_card_free(card);
+ return res;
+ }
+@@ -2336,19 +2428,19 @@ static int __devinit snd_audiodrive_pnp_
+ return 0;
+ }
+
+-static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard)
++static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard)
+ {
+ snd_card_free(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+ }
+
+ #ifdef CONFIG_PM
+-static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
++static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
+ {
+ return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state);
+ }
+
+-static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard)
++static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard)
+ {
+ return snd_es18xx_resume(pnp_get_card_drvdata(pcard));
+ }
+@@ -2359,11 +2451,11 @@ static struct pnp_card_driver es18xx_pnp
+ .flags = PNP_DRIVER_RES_DISABLE,
+ .name = "es18xx",
+ .id_table = snd_audiodrive_pnpids,
+- .probe = snd_audiodrive_pnp_detect,
+- .remove = __devexit_p(snd_audiodrive_pnp_remove),
++ .probe = snd_audiodrive_pnpc_detect,
++ .remove = __devexit_p(snd_audiodrive_pnpc_remove),
+ #ifdef CONFIG_PM
+- .suspend = snd_audiodrive_pnp_suspend,
+- .resume = snd_audiodrive_pnp_resume,
++ .suspend = snd_audiodrive_pnpc_suspend,
++ .resume = snd_audiodrive_pnpc_resume,
+ #endif
+ };
+ #endif /* CONFIG_PNP */
+@@ -2373,8 +2465,10 @@ static void __init_or_module snd_es18xx_
+ int i;
+
+ #ifdef CONFIG_PNP
+- if (pnp_registered)
++ if (pnpc_registered)
+ pnp_unregister_card_driver(&es18xx_pnpc_driver);
++ if (pnp_registered)
++ pnp_unregister_driver(&es18xx_pnp_driver);
+ #endif
+ for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
+ platform_device_unregister(platform_devices[i]);
+@@ -2405,11 +2499,13 @@ static int __init alsa_card_es18xx_init(
+ }
+
+ #ifdef CONFIG_PNP
+- err = pnp_register_card_driver(&es18xx_pnpc_driver);
+- if (!err) {
++ err = pnp_register_driver(&es18xx_pnp_driver);
++ if (!err)
+ pnp_registered = 1;
+- cards += es18xx_pnp_devices;
+- }
++ err = pnp_register_card_driver(&es18xx_pnpc_driver);
++ if (!err)
++ pnpc_registered = 1;
++ cards += es18xx_pnp_devices;
+ #endif
+
+ if(!cards) {
+diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
+index 42db375..537d3cf 100644
+--- a/sound/isa/gus/gus_irq.c
++++ b/sound/isa/gus/gus_irq.c
+@@ -30,7 +30,7 @@
+ #define STAT_ADD(x) while (0) { ; }
+ #endif
+
+-irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t snd_gus_interrupt(int irq, void *dev_id)
+ {
+ struct snd_gus_card * gus = dev_id;
+ unsigned char status;
+diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c
+index 4080255..80f0a83 100644
+--- a/sound/isa/gus/gus_mem_proc.c
++++ b/sound/isa/gus/gus_mem_proc.c
+@@ -61,13 +61,13 @@ static long long snd_gf1_mem_proc_llseek
+ struct gus_proc_private *priv = entry->private_data;
+
+ switch (orig) {
+- case 0: /* SEEK_SET */
++ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+- case 1: /* SEEK_CUR */
++ case SEEK_CUR:
+ file->f_pos += offset;
+ break;
+- case 2: /* SEEK_END, offset is negative */
++ case SEEK_END: /* offset is negative */
+ file->f_pos = priv->size + offset;
+ break;
+ default:
+diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
+index ac11cae..c1c69e3 100644
+--- a/sound/isa/gus/gusmax.c
++++ b/sound/isa/gus/gusmax.c
+@@ -105,9 +105,9 @@ static int __init snd_gusmax_detect(stru
+ return 0;
+ }
+
+-static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id)
+ {
+- struct snd_gusmax *maxcard = (struct snd_gusmax *) dev_id;
++ struct snd_gusmax *maxcard = dev_id;
+ int loop, max = 5;
+ int handled = 0;
+
+@@ -115,12 +115,12 @@ static irqreturn_t snd_gusmax_interrupt(
+ loop = 0;
+ if (inb(maxcard->gus_status_reg)) {
+ handled = 1;
+- snd_gus_interrupt(irq, maxcard->gus, regs);
++ snd_gus_interrupt(irq, maxcard->gus);
+ loop++;
+ }
+ if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
+ handled = 1;
+- snd_cs4231_interrupt(irq, maxcard->cs4231, regs);
++ snd_cs4231_interrupt(irq, maxcard->cs4231);
+ loop++;
+ }
+ } while (loop && --max > 0);
+diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
+index ea69f25..4ec2d79 100644
+--- a/sound/isa/gus/interwave.c
++++ b/sound/isa/gus/interwave.c
+@@ -299,9 +299,9 @@ static int __devinit snd_interwave_detec
+ return -ENODEV;
+ }
+
+-static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id)
+ {
+- struct snd_interwave *iwcard = (struct snd_interwave *) dev_id;
++ struct snd_interwave *iwcard = dev_id;
+ int loop, max = 5;
+ int handled = 0;
+
+@@ -309,12 +309,12 @@ static irqreturn_t snd_interwave_interru
+ loop = 0;
+ if (inb(iwcard->gus_status_reg)) {
+ handled = 1;
+- snd_gus_interrupt(irq, iwcard->gus, regs);
++ snd_gus_interrupt(irq, iwcard->gus);
+ loop++;
+ }
+ if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
+ handled = 1;
+- snd_cs4231_interrupt(irq, iwcard->cs4231, regs);
++ snd_cs4231_interrupt(irq, iwcard->cs4231);
+ loop++;
+ }
+ } while (loop && --max > 0);
+@@ -564,6 +564,8 @@ static int __devinit snd_interwave_pnp(i
+ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+ int err;
+
++ if (!cfg)
++ return -ENOMEM;
+ iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (iwcard->dev == NULL) {
+ kfree(cfg);
+diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
+index 4031b61..419b4eb 100644
+--- a/sound/isa/opl3sa2.c
++++ b/sound/isa/opl3sa2.c
+@@ -33,6 +33,7 @@
+ #include <sound/mpu401.h>
+ #include <sound/opl3.h>
+ #include <sound/initval.h>
++#include <sound/tlv.h>
+
+ #include <asm/io.h>
+
+@@ -293,7 +294,7 @@ static int __devinit snd_opl3sa2_detect(
+ return 0;
+ }
+
+-static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
+ {
+ unsigned short status;
+ struct snd_opl3sa2 *chip = dev_id;
+@@ -311,12 +312,12 @@ static irqreturn_t snd_opl3sa2_interrupt
+
+ if ((status & 0x10) && chip->rmidi != NULL) {
+ handled = 1;
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+ }
+
+ if (status & 0x07) { /* TI,CI,PI */
+ handled = 1;
+- snd_cs4231_interrupt(irq, chip->cs4231, regs);
++ snd_cs4231_interrupt(irq, chip->cs4231);
+ }
+
+ if (status & 0x40) { /* hardware volume change */
+@@ -337,6 +338,14 @@ static irqreturn_t snd_opl3sa2_interrupt
+ .info = snd_opl3sa2_info_single, \
+ .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
+ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
++#define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .index = xindex, \
++ .info = snd_opl3sa2_info_single, \
++ .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
++ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
++ .tlv = { .p = (xtlv) } }
+
+ static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+@@ -395,6 +404,14 @@ static int snd_opl3sa2_put_single(struct
+ .info = snd_opl3sa2_info_double, \
+ .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
++#define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .index = xindex, \
++ .info = snd_opl3sa2_info_double, \
++ .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
++ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
++ .tlv = { .p = (xtlv) } }
+
+ static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+@@ -469,11 +486,16 @@ static int snd_opl3sa2_put_double(struct
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
++
+ static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
+ OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),
+-OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1),
++OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1,
++ db_scale_master),
+ OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1),
+-OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1)
++OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1,
++ db_scale_5bit_12db_max),
+ };
+
+ static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = {
+diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
+index 9d528ae..df22737 100644
+--- a/sound/isa/opti9xx/opti92x-ad1848.c
++++ b/sound/isa/opti9xx/opti92x-ad1848.c
+@@ -1090,7 +1090,7 @@ static void snd_opti93x_overrange(struct
+ spin_unlock_irqrestore(&chip->lock, flags);
+ }
+
+-static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
+ {
+ struct snd_opti93x *codec = dev_id;
+ unsigned char status;
+@@ -1683,6 +1683,8 @@ static int __init snd_card_opti9xx_pnp(s
+ struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+ int err;
+
++ if (!cfg)
++ return -ENOMEM;
+ chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+ if (chip->dev == NULL) {
+ kfree(cfg);
+diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
+index d4d65b8..d4b2187 100644
+--- a/sound/isa/sb/es968.c
++++ b/sound/isa/sb/es968.c
+@@ -70,8 +70,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_es968_
+
+ #define DRIVER_NAME "snd-card-es968"
+
+-static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id)
+ {
+ struct snd_sb *chip = dev_id;
+
+diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
+index f183f18..383911b 100644
+--- a/sound/isa/sb/sb16_main.c
++++ b/sound/isa/sb/sb16_main.c
+@@ -395,7 +395,7 @@ static int snd_sb16_capture_trigger(stru
+ return result;
+ }
+
+-irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
+ {
+ struct snd_sb *chip = dev_id;
+ unsigned char status;
+@@ -405,7 +405,7 @@ irqreturn_t snd_sb16dsp_interrupt(int ir
+ status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
+ spin_unlock(&chip->mixer_lock);
+ if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)
+- chip->rmidi_callback(irq, chip->rmidi->private_data, regs);
++ chip->rmidi_callback(irq, chip->rmidi->private_data);
+ if (status & SB_IRQTYPE_8BIT) {
+ ok = 0;
+ if (chip->mode & SB_MODE_PLAYBACK_8) {
+diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
+index 141400c..268ebd3 100644
+--- a/sound/isa/sb/sb8.c
++++ b/sound/isa/sb/sb8.c
+@@ -63,7 +63,7 @@ struct snd_sb8 {
+ struct snd_sb *chip;
+ };
+
+-static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
+ {
+ struct snd_sb *chip = dev_id;
+
+diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
+index f17de2b..c62a9e3 100644
+--- a/sound/isa/sb/sb_common.c
++++ b/sound/isa/sb/sb_common.c
+@@ -205,7 +205,7 @@ static int snd_sbdsp_dev_free(struct snd
+ int snd_sbdsp_create(struct snd_card *card,
+ unsigned long port,
+ int irq,
+- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
++ irq_handler_t irq_handler,
+ int dma8,
+ int dma16,
+ unsigned short hardware,
+diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
+index 8742fa5..4fcd0f4 100644
+--- a/sound/isa/sgalaxy.c
++++ b/sound/isa/sgalaxy.c
+@@ -109,7 +109,7 @@ static int __init snd_sgalaxy_sbdsp_comm
+ return 0;
+ }
+
+-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
+ {
+ return IRQ_NONE;
+ }
+diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
+index a8f8d2f..85db535 100644
+--- a/sound/isa/wavefront/wavefront.c
++++ b/sound/isa/wavefront/wavefront.c
+@@ -263,9 +263,7 @@ snd_wavefront_pnp (int dev, snd_wavefron
+
+ #endif /* CONFIG_PNP */
+
+-static irqreturn_t snd_wavefront_ics2115_interrupt(int irq,
+- void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, void *dev_id)
+ {
+ snd_wavefront_card_t *acard;
+
+diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
+index c31b386..8a61a11 100644
+--- a/sound/mips/au1x00.c
++++ b/sound/mips/au1x00.c
+@@ -220,7 +220,7 @@ au1000_dma_start(struct audio_stream *st
+ }
+
+ static irqreturn_t
+-au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++au1000_dma_interrupt(int irq, void *dev_id)
+ {
+ struct audio_stream *stream = (struct audio_stream *) dev_id;
+ struct snd_pcm_substream *substream = stream->substream;
+@@ -258,7 +258,7 @@ au1000_dma_interrupt(int irq, void *dev_
+
+ static unsigned int rates[] = {8000, 11025, 16000, 22050};
+ static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+- .count = sizeof(rates) / sizeof(rates[0]),
++ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+diff --git a/sound/oss/COPYING b/sound/oss/COPYING
+deleted file mode 100644
+index 916d1f0..0000000
+--- a/sound/oss/COPYING
++++ /dev/null
+@@ -1,339 +0,0 @@
+- GNU GENERAL PUBLIC LICENSE
+- Version 2, June 1991
+-
+- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+- Everyone is permitted to copy and distribute verbatim copies
+- of this license document, but changing it is not allowed.
+-
+- Preamble
+-
+- The licenses for most software are designed to take away your
+-freedom to share and change it. By contrast, the GNU General Public
+-License is intended to guarantee your freedom to share and change free
+-software--to make sure the software is free for all its users. This
+-General Public License applies to most of the Free Software
+-Foundation's software and to any other program whose authors commit to
+-using it. (Some other Free Software Foundation software is covered by
+-the GNU Library General Public License instead.) You can apply it to
+-your programs, too.
+-
+- When we speak of free software, we are referring to freedom, not
+-price. Our General Public Licenses are designed to make sure that you
+-have the freedom to distribute copies of free software (and charge for
+-this service if you wish), that you receive source code or can get it
+-if you want it, that you can change the software or use pieces of it
+-in new free programs; and that you know you can do these things.
+-
+- To protect your rights, we need to make restrictions that forbid
+-anyone to deny you these rights or to ask you to surrender the rights.
+-These restrictions translate to certain responsibilities for you if you
+-distribute copies of the software, or if you modify it.
+-
+- For example, if you distribute copies of such a program, whether
+-gratis or for a fee, you must give the recipients all the rights that
+-you have. You must make sure that they, too, receive or can get the
+-source code. And you must show them these terms so they know their
+-rights.
+-
+- We protect your rights with two steps: (1) copyright the software, and
+-(2) offer you this license which gives you legal permission to copy,
+-distribute and/or modify the software.
+-
+- Also, for each author's protection and ours, we want to make certain
+-that everyone understands that there is no warranty for this free
+-software. If the software is modified by someone else and passed on, we
+-want its recipients to know that what they have is not the original, so
+-that any problems introduced by others will not reflect on the original
+-authors' reputations.
+-
+- Finally, any free program is threatened constantly by software
+-patents. We wish to avoid the danger that redistributors of a free
+-program will individually obtain patent licenses, in effect making the
+-program proprietary. To prevent this, we have made it clear that any
+-patent must be licensed for everyone's free use or not licensed at all.
+-
+- The precise terms and conditions for copying, distribution and
+-modification follow.
+-
+- GNU GENERAL PUBLIC LICENSE
+- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+-
+- 0. This License applies to any program or other work which contains
+-a notice placed by the copyright holder saying it may be distributed
+-under the terms of this General Public License. The "Program", below,
+-refers to any such program or work, and a "work based on the Program"
+-means either the Program or any derivative work under copyright law:
+-that is to say, a work containing the Program or a portion of it,
+-either verbatim or with modifications and/or translated into another
+-language. (Hereinafter, translation is included without limitation in
+-the term "modification".) Each licensee is addressed as "you".
+-
+-Activities other than copying, distribution and modification are not
+-covered by this License; they are outside its scope. The act of
+-running the Program is not restricted, and the output from the Program
+-is covered only if its contents constitute a work based on the
+-Program (independent of having been made by running the Program).
+-Whether that is true depends on what the Program does.
+-
+- 1. You may copy and distribute verbatim copies of the Program's
+-source code as you receive it, in any medium, provided that you
+-conspicuously and appropriately publish on each copy an appropriate
+-copyright notice and disclaimer of warranty; keep intact all the
+-notices that refer to this License and to the absence of any warranty;
+-and give any other recipients of the Program a copy of this License
+-along with the Program.
+-
+-You may charge a fee for the physical act of transferring a copy, and
+-you may at your option offer warranty protection in exchange for a fee.
+-
+- 2. You may modify your copy or copies of the Program or any portion
+-of it, thus forming a work based on the Program, and copy and
+-distribute such modifications or work under the terms of Section 1
+-above, provided that you also meet all of these conditions:
+-
+- a) You must cause the modified files to carry prominent notices
+- stating that you changed the files and the date of any change.
+-
+- b) You must cause any work that you distribute or publish, that in
+- whole or in part contains or is derived from the Program or any
+- part thereof, to be licensed as a whole at no charge to all third
+- parties under the terms of this License.
+-
+- c) If the modified program normally reads commands interactively
+- when run, you must cause it, when started running for such
+- interactive use in the most ordinary way, to print or display an
+- announcement including an appropriate copyright notice and a
+- notice that there is no warranty (or else, saying that you provide
+- a warranty) and that users may redistribute the program under
+- these conditions, and telling the user how to view a copy of this
+- License. (Exception: if the Program itself is interactive but
+- does not normally print such an announcement, your work based on
+- the Program is not required to print an announcement.)
+-
+-These requirements apply to the modified work as a whole. If
+-identifiable sections of that work are not derived from the Program,
+-and can be reasonably considered independent and separate works in
+-themselves, then this License, and its terms, do not apply to those
+-sections when you distribute them as separate works. But when you
+-distribute the same sections as part of a whole which is a work based
+-on the Program, the distribution of the whole must be on the terms of
+-this License, whose permissions for other licensees extend to the
+-entire whole, and thus to each and every part regardless of who wrote it.
+-
+-Thus, it is not the intent of this section to claim rights or contest
+-your rights to work written entirely by you; rather, the intent is to
+-exercise the right to control the distribution of derivative or
+-collective works based on the Program.
+-
+-In addition, mere aggregation of another work not based on the Program
+-with the Program (or with a work based on the Program) on a volume of
+-a storage or distribution medium does not bring the other work under
+-the scope of this License.
+-
+- 3. You may copy and distribute the Program (or a work based on it,
+-under Section 2) in object code or executable form under the terms of
+-Sections 1 and 2 above provided that you also do one of the following:
+-
+- a) Accompany it with the complete corresponding machine-readable
+- source code, which must be distributed under the terms of Sections
+- 1 and 2 above on a medium customarily used for software interchange; or,
+-
+- b) Accompany it with a written offer, valid for at least three
+- years, to give any third party, for a charge no more than your
+- cost of physically performing source distribution, a complete
+- machine-readable copy of the corresponding source code, to be
+- distributed under the terms of Sections 1 and 2 above on a medium
+- customarily used for software interchange; or,
+-
+- c) Accompany it with the information you received as to the offer
+- to distribute corresponding source code. (This alternative is
+- allowed only for noncommercial distribution and only if you
+- received the program in object code or executable form with such
+- an offer, in accord with Subsection b above.)
+-
+-The source code for a work means the preferred form of the work for
+-making modifications to it. For an executable work, complete source
+-code means all the source code for all modules it contains, plus any
+-associated interface definition files, plus the scripts used to
+-control compilation and installation of the executable. However, as a
+-special exception, the source code distributed need not include
+-anything that is normally distributed (in either source or binary
+-form) with the major components (compiler, kernel, and so on) of the
+-operating system on which the executable runs, unless that component
+-itself accompanies the executable.
+-
+-If distribution of executable or object code is made by offering
+-access to copy from a designated place, then offering equivalent
+-access to copy the source code from the same place counts as
+-distribution of the source code, even though third parties are not
+-compelled to copy the source along with the object code.
+-
+- 4. You may not copy, modify, sublicense, or distribute the Program
+-except as expressly provided under this License. Any attempt
+-otherwise to copy, modify, sublicense or distribute the Program is
+-void, and will automatically terminate your rights under this License.
+-However, parties who have received copies, or rights, from you under
+-this License will not have their licenses terminated so long as such
+-parties remain in full compliance.
+-
+- 5. You are not required to accept this License, since you have not
+-signed it. However, nothing else grants you permission to modify or
+-distribute the Program or its derivative works. These actions are
+-prohibited by law if you do not accept this License. Therefore, by
+-modifying or distributing the Program (or any work based on the
+-Program), you indicate your acceptance of this License to do so, and
+-all its terms and conditions for copying, distributing or modifying
+-the Program or works based on it.
+-
+- 6. Each time you redistribute the Program (or any work based on the
+-Program), the recipient automatically receives a license from the
+-original licensor to copy, distribute or modify the Program subject to
+-these terms and conditions. You may not impose any further
+-restrictions on the recipients' exercise of the rights granted herein.
+-You are not responsible for enforcing compliance by third parties to
+-this License.
+-
+- 7. If, as a consequence of a court judgment or allegation of patent
+-infringement or for any other reason (not limited to patent issues),
+-conditions are imposed on you (whether by court order, agreement or
+-otherwise) that contradict the conditions of this License, they do not
+-excuse you from the conditions of this License. If you cannot
+-distribute so as to satisfy simultaneously your obligations under this
+-License and any other pertinent obligations, then as a consequence you
+-may not distribute the Program at all. For example, if a patent
+-license would not permit royalty-free redistribution of the Program by
+-all those who receive copies directly or indirectly through you, then
+-the only way you could satisfy both it and this License would be to
+-refrain entirely from distribution of the Program.
+-
+-If any portion of this section is held invalid or unenforceable under
+-any particular circumstance, the balance of the section is intended to
+-apply and the section as a whole is intended to apply in other
+-circumstances.
+-
+-It is not the purpose of this section to induce you to infringe any
+-patents or other property right claims or to contest validity of any
+-such claims; this section has the sole purpose of protecting the
+-integrity of the free software distribution system, which is
+-implemented by public license practices. Many people have made
+-generous contributions to the wide range of software distributed
+-through that system in reliance on consistent application of that
+-system; it is up to the author/donor to decide if he or she is willing
+-to distribute software through any other system and a licensee cannot
+-impose that choice.
+-
+-This section is intended to make thoroughly clear what is believed to
+-be a consequence of the rest of this License.
+-
+- 8. If the distribution and/or use of the Program is restricted in
+-certain countries either by patents or by copyrighted interfaces, the
+-original copyright holder who places the Program under this License
+-may add an explicit geographical distribution limitation excluding
+-those countries, so that distribution is permitted only in or among
+-countries not thus excluded. In such case, this License incorporates
+-the limitation as if written in the body of this License.
+-
+- 9. The Free Software Foundation may publish revised and/or new versions
+-of the General Public License from time to time. Such new versions will
+-be similar in spirit to the present version, but may differ in detail to
+-address new problems or concerns.
+-
+-Each version is given a distinguishing version number. If the Program
+-specifies a version number of this License which applies to it and "any
+-later version", you have the option of following the terms and conditions
+-either of that version or of any later version published by the Free
+-Software Foundation. If the Program does not specify a version number of
+-this License, you may choose any version ever published by the Free Software
+-Foundation.
+-
+- 10. If you wish to incorporate parts of the Program into other free
+-programs whose distribution conditions are different, write to the author
+-to ask for permission. For software which is copyrighted by the Free
+-Software Foundation, write to the Free Software Foundation; we sometimes
+-make exceptions for this. Our decision will be guided by the two goals
+-of preserving the free status of all derivatives of our free software and
+-of promoting the sharing and reuse of software generally.
+-
+- NO WARRANTY
+-
+- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+-REPAIR OR CORRECTION.
+-
+- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+-POSSIBILITY OF SUCH DAMAGES.
+-
+- END OF TERMS AND CONDITIONS
+-
+- Appendix: How to Apply These Terms to Your New Programs
+-
+- If you develop a new program, and you want it to be of the greatest
+-possible use to the public, the best way to achieve this is to make it
+-free software which everyone can redistribute and change under these terms.
+-
+- To do so, attach the following notices to the program. It is safest
+-to attach them to the start of each source file to most effectively
+-convey the exclusion of warranty; and each file should have at least
+-the "copyright" line and a pointer to where the full notice is found.
+-
+- <one line to give the program's name and a brief idea of what it does.>
+- Copyright (C) 19yy <name of author>
+-
+- 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
+-
+-Also add information on how to contact you by electronic and paper mail.
+-
+-If the program is interactive, make it output a short notice like this
+-when it starts in an interactive mode:
+-
+- Gnomovision version 69, Copyright (C) 19yy name of author
+- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+- This is free software, and you are welcome to redistribute it
+- under certain conditions; type `show c' for details.
+-
+-The hypothetical commands `show w' and `show c' should show the appropriate
+-parts of the General Public License. Of course, the commands you use may
+-be called something other than `show w' and `show c'; they could even be
+-mouse-clicks or menu items--whatever suits your program.
+-
+-You should also get your employer (if you work as a programmer) or your
+-school, if any, to sign a "copyright disclaimer" for the program, if
+-necessary. Here is a sample; alter the names:
+-
+- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+- `Gnomovision' (which makes passes at compilers) written by James Hacker.
+-
+- <signature of Ty Coon>, 1 April 1989
+- Ty Coon, President of Vice
+-
+-This General Public License does not permit incorporating your program into
+-proprietary programs. If your program is a subroutine library, you may
+-consider it more useful to permit linking proprietary applications with the
+-library. If this is what you want to do, use the GNU Library General
+-Public License instead of this License.
+diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
+index 97e38b6..cc2b9ab 100644
+--- a/sound/oss/Kconfig
++++ b/sound/oss/Kconfig
+@@ -115,10 +115,6 @@ config SOUND_HAL2
+ Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to
+ use its on-board A2 audio system.
+
+-config SOUND_IT8172
+- tristate "IT8172G Sound"
+- depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR)
+-
+ config SOUND_VRC5477
+ tristate "NEC Vrc5477 AC97 sound"
+ depends on SOUND_PRIME && DDB5477
+@@ -647,7 +643,7 @@ config SOUND_PSS
+ command line.
+
+ config PSS_MIXER
+- bool "Enable PSS mixer (Beethoven ADSP-16 and other compatibile)"
++ bool "Enable PSS mixer (Beethoven ADSP-16 and other compatible)"
+ depends on SOUND_PSS
+ help
+ Answer Y for Beethoven ADSP-16. You may try to say Y also for other
+diff --git a/sound/oss/Makefile b/sound/oss/Makefile
+index 9bf3ee5..2489bd6 100644
+--- a/sound/oss/Makefile
++++ b/sound/oss/Makefile
+@@ -15,72 +15,42 @@ obj-$(CONFIG_SOUND_HAL2) += hal2.o
+ obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
+ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
+ obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
+-obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
+ obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
+-obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o
+ obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
+ obj-$(CONFIG_SOUND_MSS) += ad1848.o
+ obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o
+ obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
+ obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
+ obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o
+-obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
+-obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
+ obj-$(CONFIG_SOUND_MPU401) += mpu401.o
+ obj-$(CONFIG_SOUND_UART6850) += uart6850.o
+-obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o
+ obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o
+ obj-$(CONFIG_SOUND_YM3812) += opl3.o
+ obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
+ obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
+ obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
+-obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o
+ obj-$(CONFIG_SOUND_AD1816) += ad1816.o
+ obj-$(CONFIG_SOUND_AD1889) += ad1889.o ac97_codec.o
+ obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
+-obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o
+
+ obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
+ ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
+ obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
+ endif
+-obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o
+-ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y)
+- obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o
+-endif
+ obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
+ obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
+ obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
+ obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o
+ obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
+-obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
+-obj-$(CONFIG_SOUND_CMPCI) += cmpci.o
+-ifeq ($(CONFIG_SOUND_CMPCI_FM),y)
+- obj-$(CONFIG_SOUND_CMPCI) += sound.o opl3.o
+-endif
+-ifeq ($(CONFIG_SOUND_CMPCI_MIDI),y)
+- obj-$(CONFIG_SOUND_CMPCI) += sound.o mpu401.o
+-endif
+-obj-$(CONFIG_SOUND_ES1370) += es1370.o
+ obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
+ obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o
+-obj-$(CONFIG_SOUND_AU1000) += au1000.o ac97_codec.o
+ obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
+-obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
+ obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
+-obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
+-obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o
+ obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
+-obj-$(CONFIG_SOUND_HARMONY) += harmony.o
+ obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
+ obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
+-obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o
+ obj-$(CONFIG_SOUND_BT878) += btaudio.o
+-obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o
+-obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o
+-obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o
+
+-obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o
+ obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
+
+ ifeq ($(CONFIG_MIDI_EMU10K1),y)
+@@ -88,28 +58,25 @@ ifeq ($(CONFIG_MIDI_EMU10K1),y)
+ endif
+
+ obj-$(CONFIG_SOUND_EMU10K1) += emu10k1/
+-obj-$(CONFIG_SOUND_CS4281) += cs4281/
+ obj-$(CONFIG_DMASOUND) += dmasound/
+
+ # Declare multi-part drivers.
+
+ sound-objs := \
+- dev_table.o soundcard.o sound_syms.o \
+- audio.o audio_syms.o dmabuf.o \
+- midi_syms.o midi_synth.o midibuf.o \
+- sequencer.o sequencer_syms.o sound_timer.o sys_timer.o
++ dev_table.o soundcard.o \
++ audio.o dmabuf.o \
++ midi_synth.o midibuf.o \
++ sequencer.o sound_timer.o sys_timer.o
+
+-gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
+ pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
+ sb-objs := sb_card.o
+ sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o
+ vidc_mod-objs := vidc.o vidc_fill.o
+-wavefront-objs := wavfront.o wf_midi.o yss225.o
+
+ hostprogs-y := bin2hex hex2hex
+
+ # Files generated that shall be removed upon make clean
+-clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \
++clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \
+ pss_boot.h trix_boot.h
+
+ # Firmware files that need translation
+@@ -119,21 +86,6 @@ clean-files := maui_boot.h msndperm.c ms
+ # will be forced to be remade.
+ #
+
+-# Turtle Beach Maui / Tropez
+-
+-$(obj)/maui.o: $(obj)/maui_boot.h
+-
+-ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
+- $(obj)/maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) $(obj)/bin2hex
+- $(obj)/bin2hex -i maui_os < $< > $@
+-else
+- $(obj)/maui_boot.h:
+- ( \
+- echo 'static unsigned char * maui_os = NULL;'; \
+- echo 'static int maui_osLen = 0;'; \
+- ) > $@
+-endif
+-
+ # Turtle Beach MultiSound
+
+ ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y)
+diff --git a/sound/oss/ac97.c b/sound/oss/ac97.c
+index 3ba6d91..72cf4ed 100644
+--- a/sound/oss/ac97.c
++++ b/sound/oss/ac97.c
+@@ -112,25 +112,6 @@ ac97_init (struct ac97_hwint *dev)
+ return 0;
+ }
+
+-/* Reset the mixer to the currently saved settings. */
+-int
+-ac97_reset (struct ac97_hwint *dev)
+-{
+- int x;
+-
+- if (dev->reset_device (dev))
+- return -1;
+-
+- /* Now set the registers back to their last-written values. */
+- for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
+- int regnum = mixerRegs[x].ac97_regnum;
+- int value = dev->last_written_mixer_values [regnum / 2];
+- if (value >= 0)
+- ac97_put_register (dev, regnum, value);
+- }
+- return 0;
+-}
+-
+ /* Return the contents of register REG; use the cache if the value in it
+ is valid. Returns a negative error code on failure. */
+ static int
+@@ -441,7 +422,6 @@ EXPORT_SYMBOL(ac97_init);
+ EXPORT_SYMBOL(ac97_set_values);
+ EXPORT_SYMBOL(ac97_put_register);
+ EXPORT_SYMBOL(ac97_mixer_ioctl);
+-EXPORT_SYMBOL(ac97_reset);
+ MODULE_LICENSE("GPL");
+
+
+diff --git a/sound/oss/ac97.h b/sound/oss/ac97.h
+index 77d454e..01837a9 100644
+--- a/sound/oss/ac97.h
++++ b/sound/oss/ac97.h
+@@ -192,9 +192,6 @@ extern int ac97_put_register (struct ac9
+ extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
+ void __user * arg);
+
+-/* Do a complete reset on the AC97 mixer, restoring all mixer registers to
+- the current values. Normally used after an APM resume event. */
+-extern int ac97_reset (struct ac97_hwint *dev);
+ #endif
+
+ /*
+diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
+index 972327c..602db49 100644
+--- a/sound/oss/ac97_codec.c
++++ b/sound/oss/ac97_codec.c
+@@ -1399,95 +1399,6 @@ unsigned int ac97_set_adc_rate(struct ac
+
+ EXPORT_SYMBOL(ac97_set_adc_rate);
+
+-int ac97_save_state(struct ac97_codec *codec)
+-{
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(ac97_save_state);
+-
+-int ac97_restore_state(struct ac97_codec *codec)
+-{
+- int i;
+- unsigned int left, right, val;
+-
+- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if (!supported_mixer(codec, i))
+- continue;
+-
+- val = codec->mixer_state[i];
+- right = val >> 8;
+- left = val & 0xff;
+- codec->write_mixer(codec, i, left, right);
+- }
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(ac97_restore_state);
+-
+-/**
+- * ac97_register_driver - register a codec helper
+- * @driver: Driver handler
+- *
+- * Register a handler for codecs matching the codec id. The handler
+- * attach function is called for all present codecs and will be
+- * called when new codecs are discovered.
+- */
+-
+-int ac97_register_driver(struct ac97_driver *driver)
+-{
+- struct list_head *l;
+- struct ac97_codec *c;
+-
+- mutex_lock(&codec_mutex);
+- INIT_LIST_HEAD(&driver->list);
+- list_add(&driver->list, &codec_drivers);
+-
+- list_for_each(l, &codecs)
+- {
+- c = list_entry(l, struct ac97_codec, list);
+- if(c->driver != NULL || ((c->model ^ driver->codec_id) & driver->codec_mask))
+- continue;
+- if(driver->probe(c, driver))
+- continue;
+- c->driver = driver;
+- }
+- mutex_unlock(&codec_mutex);
+- return 0;
+-}
+-
+-EXPORT_SYMBOL_GPL(ac97_register_driver);
+-
+-/**
+- * ac97_unregister_driver - unregister a codec helper
+- * @driver: Driver handler
+- *
+- * Unregister a handler for codecs matching the codec id. The handler
+- * remove function is called for all matching codecs.
+- */
+-
+-void ac97_unregister_driver(struct ac97_driver *driver)
+-{
+- struct list_head *l;
+- struct ac97_codec *c;
+-
+- mutex_lock(&codec_mutex);
+- list_del_init(&driver->list);
+-
+- list_for_each(l, &codecs)
+- {
+- c = list_entry(l, struct ac97_codec, list);
+- if (c->driver == driver) {
+- driver->remove(c, driver);
+- c->driver = NULL;
+- }
+- }
+-
+- mutex_unlock(&codec_mutex);
+-}
+-
+-EXPORT_SYMBOL_GPL(ac97_unregister_driver);
+-
+ static int swap_headphone(int remove_master)
+ {
+ struct list_head *l;
+diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c
+deleted file mode 100644
+index 24a9acd..0000000
+--- a/sound/oss/ac97_plugin_ad1980.c
++++ /dev/null
+@@ -1,126 +0,0 @@
+-/*
+- ac97_plugin_ad1980.c Copyright (C) 2003 Red Hat, Inc. All rights reserved.
+-
+- The contents of this file are subject to the Open Software License version 1.1
+- that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is
+- included herein by reference.
+-
+- Alternatively, the contents of this file may be used under the
+- terms of the GNU General Public License version 2 (the "GPL") as
+- distributed in the kernel source COPYING file, in which
+- case the provisions of the GPL are applicable instead of the
+- above. If you wish to allow the use of your version of this file
+- only under the terms of the GPL and not to allow others to use
+- your version of this file under the OSL, indicate your decision
+- by deleting the provisions above and replace them with the notice
+- and other provisions required by the GPL. If you do not delete
+- the provisions above, a recipient may use your version of this
+- file under either the OSL or the GPL.
+-
+- Authors: Alan Cox <alan at redhat.com>
+-
+- This is an example codec plugin. This one switches the connections
+- around to match the setups some vendors use with audio switched to
+- non standard front connectors not the normal rear ones
+-
+- This code primarily exists to demonstrate how to use the codec
+- interface
+-
+-*/
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <linux/ac97_codec.h>
+-
+-/**
+- * ad1980_remove - codec remove callback
+- * @codec: The codec that is being removed
+- *
+- * This callback occurs when an AC97 codec is being removed. A
+- * codec remove call will not occur for a codec during that codec
+- * probe callback.
+- *
+- * Most drivers will need to lock their remove versus their
+- * use of the codec after the probe function.
+- */
+-
+-static void __devexit ad1980_remove(struct ac97_codec *codec, struct ac97_driver *driver)
+-{
+- /* Nothing to do in the simple example */
+-}
+-
+-
+-/**
+- * ad1980_probe - codec found callback
+- * @codec: ac97 codec matching the idents
+- * @driver: ac97_driver it matched
+- *
+- * This entry point is called when a codec is found which matches
+- * the driver. At the point it is called the codec is basically
+- * operational, mixer operations have been initialised and can
+- * be overriden. Called in process context. The field driver_private
+- * is available for the driver to use to store stuff.
+- *
+- * The caller can claim the device by returning zero, or return
+- * a negative error code.
+- */
+-
+-static int ad1980_probe(struct ac97_codec *codec, struct ac97_driver *driver)
+-{
+- u16 control;
+-
+-#define AC97_AD_MISC 0x76
+-
+- /* Switch the inputs/outputs over (from Dell code) */
+- control = codec->codec_read(codec, AC97_AD_MISC);
+- codec->codec_write(codec, AC97_AD_MISC, control | 0x4420);
+-
+- /* We could refuse the device since we dont need to hang around,
+- but we will claim it */
+- return 0;
+-}
+-
+-
+-static struct ac97_driver ad1980_driver = {
+- .codec_id = 0x41445370,
+- .codec_mask = 0xFFFFFFFF,
+- .name = "AD1980 example",
+- .probe = ad1980_probe,
+- .remove = __devexit_p(ad1980_remove),
+-};
+-
+-/**
+- * ad1980_exit - module exit path
+- *
+- * Our module is being unloaded. At this point unregister_driver
+- * will call back our remove handler for any existing codecs. You
+- * may not unregister_driver from interrupt context or from a
+- * probe/remove callback.
+- */
+-
+-static void ad1980_exit(void)
+-{
+- ac97_unregister_driver(&ad1980_driver);
+-}
+-
+-/**
+- * ad1980_init - set up ad1980 handlers
+- *
+- * After we call the register function it will call our probe
+- * function for each existing matching device before returning to us.
+- * Any devices appearing afterwards whose id's match the codec_id
+- * will also cause the probe function to be called.
+- * You may not register_driver from interrupt context or from a
+- * probe/remove callback.
+- */
+-
+-static int ad1980_init(void)
+-{
+- return ac97_register_driver(&ad1980_driver);
+-}
+-
+-module_init(ad1980_init);
+-module_exit(ad1980_exit);
+-MODULE_LICENSE("GPL");
+diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c
+index 2905783..caabf31 100644
+--- a/sound/oss/ad1816.c
++++ b/sound/oss/ad1816.c
+@@ -521,7 +521,7 @@ static struct audio_driver ad1816_audio_
+ /* Interrupt handler */
+
+
+-static irqreturn_t ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
++static irqreturn_t ad1816_interrupt (int irq, void *dev_id)
+ {
+ unsigned char status;
+ ad1816_info *devc = (ad1816_info *)dev_id;
+diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
+index 3b45e11..0ffa997 100644
+--- a/sound/oss/ad1848.c
++++ b/sound/oss/ad1848.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/ad1848.c
++ * sound/oss/ad1848.c
+ *
+ * The low level driver for the AD1848/CS4248 codec chip which
+ * is used for example in the MS Sound System.
+@@ -195,6 +195,7 @@ static void ad1848_halt(int dev);
+ static void ad1848_halt_input(int dev);
+ static void ad1848_halt_output(int dev);
+ static void ad1848_trigger(int dev, int bits);
++static irqreturn_t adintr(int irq, void *dev_id);
+
+ #ifndef EXCLUDE_TIMERS
+ static int ad1848_tmr_install(int dev);
+@@ -2195,7 +2196,7 @@ void ad1848_unload(int io_base, int irq,
+ printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
+ }
+
+-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
++static irqreturn_t adintr(int irq, void *dev_id)
+ {
+ unsigned char status;
+ ad1848_info *devc;
+@@ -2802,7 +2803,6 @@ EXPORT_SYMBOL(ad1848_detect);
+ EXPORT_SYMBOL(ad1848_init);
+ EXPORT_SYMBOL(ad1848_unload);
+ EXPORT_SYMBOL(ad1848_control);
+-EXPORT_SYMBOL(adintr);
+ EXPORT_SYMBOL(probe_ms_sound);
+ EXPORT_SYMBOL(attach_ms_sound);
+ EXPORT_SYMBOL(unload_ms_sound);
+diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h
+index d0573b0..b95ebe2 100644
+--- a/sound/oss/ad1848.h
++++ b/sound/oss/ad1848.h
+@@ -18,7 +18,6 @@ void ad1848_unload (int io_base, int irq
+ int ad1848_detect (struct resource *ports, int *flags, int *osp);
+ int ad1848_control(int cmd, int arg);
+
+-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs * dummy);
+ void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner);
+
+ int probe_ms_sound(struct address_info *hw_config, struct resource *ports);
+diff --git a/sound/oss/ad1848_mixer.h b/sound/oss/ad1848_mixer.h
+index f9231c6..2cf719b 100644
+--- a/sound/oss/ad1848_mixer.h
++++ b/sound/oss/ad1848_mixer.h
+@@ -1,5 +1,5 @@
+ /*
+- * sound/ad1848_mixer.h
++ * sound/oss/ad1848_mixer.h
+ *
+ * Definitions for the mixer of AD1848 and compatible codecs.
+ */
+diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c
+index f56f870..09263d7 100644
+--- a/sound/oss/ad1889.c
++++ b/sound/oss/ad1889.c
+@@ -929,7 +929,7 @@ static struct pci_device_id ad1889_id_tb
+ };
+ MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
+
+-static irqreturn_t ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t ad1889_interrupt(int irq, void *dev_id)
+ {
+ u32 stat;
+ ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
+diff --git a/sound/oss/adlib_card.c b/sound/oss/adlib_card.c
+index 6414ceb..c9a7c9b 100644
+--- a/sound/oss/adlib_card.c
++++ b/sound/oss/adlib_card.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/adlib_card.c
++ * sound/oss/adlib_card.c
+ *
+ * Detection routine for the AdLib card.
+ *
+diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c
+deleted file mode 100644
+index 70dcd70..0000000
+--- a/sound/oss/ali5455.c
++++ /dev/null
+@@ -1,3735 +0,0 @@
+-/*
+- * ALI ali5455 and friends ICH driver for Linux
+- * LEI HU <Lei_Hu at ali.com.tw>
+- *
+- * Built from:
+- * drivers/sound/i810_audio
+- *
+- * The ALi 5455 is similar but not quite identical to the Intel ICH
+- * series of controllers. Its easier to keep the driver separated from
+- * the i810 driver.
+- *
+- * 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.
+- *
+- *
+- * ALi 5455 theory of operation
+- *
+- * The chipset provides three DMA channels that talk to an AC97
+- * CODEC (AC97 is a digital/analog mixer standard). At its simplest
+- * you get 48Khz audio with basic volume and mixer controls. At the
+- * best you get rate adaption in the codec. We set the card up so
+- * that we never take completion interrupts but instead keep the card
+- * chasing its tail around a ring buffer. This is needed for mmap
+- * mode audio and happens to work rather well for non-mmap modes too.
+- *
+- * The board has one output channel for PCM audio (supported) and
+- * a stereo line in and mono microphone input. Again these are normally
+- * locked to 48Khz only. Right now recording is not finished.
+- *
+- * There is no midi support, no synth support. Use timidity. To get
+- * esd working you need to use esd -r 48000 as it won't probe 48KHz
+- * by default. mpg123 can't handle 48Khz only audio so use xmms.
+- *
+- * If you need to force a specific rate set the clocking= option
+- *
+- */
+-
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ctype.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <asm/io.h>
+-#include <asm/dma.h>
+-#include <linux/init.h>
+-#include <linux/poll.h>
+-#include <linux/spinlock.h>
+-#include <linux/smp_lock.h>
+-#include <linux/ac97_codec.h>
+-#include <linux/interrupt.h>
+-#include <linux/mutex.h>
+-
+-#include <asm/uaccess.h>
+-
+-#ifndef PCI_DEVICE_ID_ALI_5455
+-#define PCI_DEVICE_ID_ALI_5455 0x5455
+-#endif
+-
+-#ifndef PCI_VENDOR_ID_ALI
+-#define PCI_VENDOR_ID_ALI 0x10b9
+-#endif
+-
+-static int strict_clocking = 0;
+-static unsigned int clocking = 0;
+-static unsigned int codec_pcmout_share_spdif_locked = 0;
+-static unsigned int codec_independent_spdif_locked = 0;
+-static unsigned int controller_pcmout_share_spdif_locked = 0;
+-static unsigned int controller_independent_spdif_locked = 0;
+-static unsigned int globel = 0;
+-
+-#define ADC_RUNNING 1
+-#define DAC_RUNNING 2
+-#define CODEC_SPDIFOUT_RUNNING 8
+-#define CONTROLLER_SPDIFOUT_RUNNING 4
+-
+-#define SPDIF_ENABLE_OUTPUT 4 /* bits 0,1 are PCM */
+-
+-#define ALI5455_FMT_16BIT 1
+-#define ALI5455_FMT_STEREO 2
+-#define ALI5455_FMT_MASK 3
+-
+-#define SPDIF_ON 0x0004
+-#define SURR_ON 0x0010
+-#define CENTER_LFE_ON 0x0020
+-#define VOL_MUTED 0x8000
+-
+-
+-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
+-/* the 810's array of pointers to data buffers */
+-
+-struct sg_item {
+-#define BUSADDR_MASK 0xFFFFFFFE
+- u32 busaddr;
+-#define CON_IOC 0x80000000 /* interrupt on completion */
+-#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */
+-#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */
+- u32 control;
+-};
+-
+-/* an instance of the ali channel */
+-#define SG_LEN 32
+-struct ali_channel {
+- /* these sg guys should probably be allocated
+- separately as nocache. Must be 8 byte aligned */
+- struct sg_item sg[SG_LEN]; /* 32*8 */
+- u32 offset; /* 4 */
+- u32 port; /* 4 */
+- u32 used;
+- u32 num;
+-};
+-
+-/*
+- * we have 3 separate dma engines. pcm in, pcm out, and mic.
+- * each dma engine has controlling registers. These goofy
+- * names are from the datasheet, but make it easy to write
+- * code while leafing through it.
+- */
+-
+-#define ENUM_ENGINE(PRE,DIG) \
+-enum { \
+- PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \
+- PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \
+- PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \
+- PRE##_SR = 0x##DIG##6, /* Status Register */ \
+- PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \
+- PRE##_CR = 0x##DIG##b /* Control Register */ \
+-}
+-
+-ENUM_ENGINE(OFF, 0); /* Offsets */
+-ENUM_ENGINE(PI, 4); /* PCM In */
+-ENUM_ENGINE(PO, 5); /* PCM Out */
+-ENUM_ENGINE(MC, 6); /* Mic In */
+-ENUM_ENGINE(CODECSPDIFOUT, 7); /* CODEC SPDIF OUT */
+-ENUM_ENGINE(CONTROLLERSPDIFIN, A); /* CONTROLLER SPDIF In */
+-ENUM_ENGINE(CONTROLLERSPDIFOUT, B); /* CONTROLLER SPDIF OUT */
+-
+-
+-enum {
+- ALI_SCR = 0x00, /* System Control Register */
+- ALI_SSR = 0x04, /* System Status Register */
+- ALI_DMACR = 0x08, /* DMA Control Register */
+- ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */
+- ALI_INTERFACECR = 0x10, /* Interface Control Register */
+- ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */
+- ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */
+- ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */
+- ALI_CPR = 0x20, /* Command Port Register */
+- ALI_SPR = 0x24, /* Status Port Register */
+- ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */
+- ALI_TTSR = 0x30, /* Transmit Tag Slot Register */
+- ALI_RTSR = 0x34, /* Receive Tag Slot Register */
+- ALI_CSPSR = 0x38, /* Command/Status Port Status Register */
+- ALI_CAS = 0x3c, /* Codec Write Semaphore Register */
+- ALI_SPDIFCSR = 0xf8, /* spdif channel status register */
+- ALI_SPDIFICS = 0xfc /* spdif interface control/status */
+-};
+-
+-// x-status register(x:pcm in ,pcm out, mic in,)
+-/* interrupts for a dma engine */
+-#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */
+-#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */
+-#define DMA_INT_LVI (1<<2) /* last valid done */
+-#define DMA_INT_CELV (1<<1) /* last valid is current */
+-#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ //not eqult intel
+-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
+-
+-/* interrupts for the whole chip */// by interrupt status register finish
+-
+-#define INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */
+-#define INT_SPDIFIN (1<<22)
+-#define INT_CODECSPDIFOUT (1<<19)
+-#define INT_MICIN (1<<18)
+-#define INT_PCMOUT (1<<17)
+-#define INT_PCMIN (1<<16)
+-#define INT_CPRAIS (1<<7)
+-#define INT_SPRAIS (1<<5)
+-#define INT_GPIO (1<<1)
+-#define INT_MASK (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
+-
+-#define DRIVER_VERSION "0.02ac"
+-
+-/* magic numbers to protect our data structures */
+-#define ALI5455_CARD_MAGIC 0x5072696E /* "Prin" */
+-#define ALI5455_STATE_MAGIC 0x63657373 /* "cess" */
+-#define ALI5455_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
+-#define NR_HW_CH 5 //I think 5 channel
+-
+-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+-#define NR_AC97 2
+-
+-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
+-/* stream at a minimum for this card to be happy */
+-static const unsigned sample_size[] = { 1, 2, 2, 4 };
+-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
+-/* values are one less than might be expected */
+-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
+-
+-#define ALI5455
+-static char *card_names[] = {
+- "ALI 5455"
+-};
+-
+-static struct pci_device_id ali_pci_tbl[] = {
+- {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
+- {0,}
+-};
+-
+-MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
+-
+-#ifdef CONFIG_PM
+-#define PM_SUSPENDED(card) (card->pm_suspended)
+-#else
+-#define PM_SUSPENDED(card) (0)
+-#endif
+-
+-/* "software" or virtual channel, an instance of opened /dev/dsp */
+-struct ali_state {
+- unsigned int magic;
+- struct ali_card *card; /* Card info */
+-
+- /* single open lock mechanism, only used for recording */
+- struct mutex open_mutex;
+- wait_queue_head_t open_wait;
+-
+- /* file mode */
+- mode_t open_mode;
+-
+- /* virtual channel number */
+- int virt;
+-
+-#ifdef CONFIG_PM
+- unsigned int pm_saved_dac_rate, pm_saved_adc_rate;
+-#endif
+- struct dmabuf {
+- /* wave sample stuff */
+- unsigned int rate;
+- unsigned char fmt, enable, trigger;
+-
+- /* hardware channel */
+- struct ali_channel *read_channel;
+- struct ali_channel *write_channel;
+- struct ali_channel *codec_spdifout_channel;
+- struct ali_channel *controller_spdifout_channel;
+-
+- /* OSS buffer management stuff */
+- void *rawbuf;
+- dma_addr_t dma_handle;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+-
+- /* our buffer acts like a circular ring */
+- unsigned hwptr; /* where dma last started, updated by update_ptr */
+- unsigned swptr; /* where driver last clear/filled, updated by read/write */
+- int count; /* bytes to be consumed or been generated by dma machine */
+- unsigned total_bytes; /* total bytes dmaed by hardware */
+-
+- unsigned error; /* number of over/underruns */
+- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
+-
+- /* redundant, but makes calculations easier */
+- /* what the hardware uses */
+- unsigned dmasize;
+- unsigned fragsize;
+- unsigned fragsamples;
+-
+- /* what we tell the user to expect */
+- unsigned userfrags;
+- unsigned userfragsize;
+-
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned update_flag;
+- unsigned ossfragsize;
+- unsigned ossmaxfrags;
+- unsigned subdivision;
+- } dmabuf;
+-};
+-
+-
+-struct ali_card {
+- struct ali_channel channel[5];
+- unsigned int magic;
+-
+- /* We keep ali5455 cards in a linked list */
+- struct ali_card *next;
+-
+- /* The ali has a certain amount of cross channel interaction
+- so we use a single per card lock */
+- spinlock_t lock;
+- spinlock_t ac97_lock;
+-
+- /* PCI device stuff */
+- struct pci_dev *pci_dev;
+- u16 pci_id;
+-#ifdef CONFIG_PM
+- u16 pm_suspended;
+- int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
+-#endif
+- /* soundcore stuff */
+- int dev_audio;
+-
+- /* structures for abstraction of hardware facilities, codecs, banks and channels */
+- struct ac97_codec *ac97_codec[NR_AC97];
+- struct ali_state *states[NR_HW_CH];
+-
+- u16 ac97_features;
+- u16 ac97_status;
+- u16 channels;
+-
+- /* hardware resources */
+- unsigned long iobase;
+-
+- u32 irq;
+-
+- /* Function support */
+- struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
+- struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
+- struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
+- struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
+- struct ali_channel *(*alloc_controller_spdifout_channel) (struct ali_card *);
+- void (*free_pcm_channel) (struct ali_card *, int chan);
+-
+- /* We have a *very* long init time possibly, so use this to block */
+- /* attempts to open our devices before we are ready (stops oops'es) */
+- int initializing;
+-};
+-
+-
+-static struct ali_card *devs = NULL;
+-
+-static int ali_open_mixdev(struct inode *inode, struct file *file);
+-static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg);
+-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
+-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+-
+-static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
+-{
+- if (card->channel[1].used == 1)
+- return NULL;
+- card->channel[1].used = 1;
+- return &card->channel[1];
+-}
+-
+-static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
+-{
+- if (card->channel[0].used == 1)
+- return NULL;
+- card->channel[0].used = 1;
+- return &card->channel[0];
+-}
+-
+-static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
+-{
+- if (card->channel[2].used == 1)
+- return NULL;
+- card->channel[2].used = 1;
+- return &card->channel[2];
+-}
+-
+-static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
+-{
+- if (card->channel[3].used == 1)
+- return NULL;
+- card->channel[3].used = 1;
+- return &card->channel[3];
+-}
+-
+-static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
+-{
+- if (card->channel[4].used == 1)
+- return NULL;
+- card->channel[4].used = 1;
+- return &card->channel[4];
+-}
+-static void ali_free_pcm_channel(struct ali_card *card, int channel)
+-{
+- card->channel[channel].used = 0;
+-}
+-
+-
+-//add support codec spdif out
+-static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
+-{
+- unsigned long id = 0L;
+-
+- id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
+- id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
+- switch (id) {
+- case 0x41445361: /* AD1886 */
+- if (rate == 48000) {
+- return 1;
+- }
+- break;
+- case 0x414c4720: /* ALC650 */
+- if (rate == 48000) {
+- return 1;
+- }
+- break;
+- default: /* all other codecs, until we know otherwiae */
+- if (rate == 48000 || rate == 44100 || rate == 32000) {
+- return 1;
+- }
+- break;
+- }
+- return (0);
+-}
+-
+-/* ali_set_spdif_output
+- *
+- * Configure the S/PDIF output transmitter. When we turn on
+- * S/PDIF, we turn off the analog output. This may not be
+- * the right thing to do.
+- *
+- * Assumptions:
+- * The DSP sample rate must already be set to a supported
+- * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
+- */
+-static void ali_set_spdif_output(struct ali_state *state, int slots,
+- int rate)
+-{
+- int vol;
+- int aud_reg;
+- struct ac97_codec *codec = state->card->ac97_codec[0];
+-
+- if (!(state->card->ac97_features & 4)) {
+- state->card->ac97_status &= ~SPDIF_ON;
+- } else {
+- if (slots == -1) { /* Turn off S/PDIF */
+- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+-
+- /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
+- if (!(state->card->ac97_status & VOL_MUTED)) {
+- aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
+- (aud_reg & ~VOL_MUTED));
+- }
+- state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
+- return;
+- }
+-
+- vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+- state->card->ac97_status = vol & VOL_MUTED;
+-
+- /* Set S/PDIF transmitter sample rate */
+- aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+- switch (rate) {
+- case 32000:
+- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
+- break;
+- case 44100:
+- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
+- break;
+- case 48000:
+- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
+- break;
+- default:
+- /* turn off S/PDIF */
+- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+- state->card->ac97_status &= ~SPDIF_ON;
+- return;
+- }
+-
+- ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
+-
+- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+- aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+-
+- aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
+- aud_reg |= 0x0002;
+- ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
+- udelay(1);
+-
+- state->card->ac97_status |= SPDIF_ON;
+-
+- /* Check to make sure the configuration is valid */
+- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+- if (!(aud_reg & 0x0400)) {
+- /* turn off S/PDIF */
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+- state->card->ac97_status &= ~SPDIF_ON;
+- return;
+- }
+- if (codec_independent_spdif_locked > 0) {
+- aud_reg = ali_ac97_get(codec, 0x6a);
+- ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
+- }
+- /* Mute the analog output */
+- /* Should this only mute the PCM volume??? */
+- }
+-}
+-
+-/* ali_set_dac_channels
+- *
+- * Configure the codec's multi-channel DACs
+- *
+- * The logic is backwards. Setting the bit to 1 turns off the DAC.
+- *
+- * What about the ICH? We currently configure it using the
+- * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC,
+- * does that imply that we want the ICH set to support
+- * these channels?
+- *
+- * TODO:
+- * vailidate that the codec really supports these DACs
+- * before turning them on.
+- */
+-static void ali_set_dac_channels(struct ali_state *state, int channel)
+-{
+- int aud_reg;
+- struct ac97_codec *codec = state->card->ac97_codec[0];
+-
+- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+- aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
+- state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
+-
+- switch (channel) {
+- case 2: /* always enabled */
+- break;
+- case 4:
+- aud_reg &= ~AC97_EA_PRJ;
+- state->card->ac97_status |= SURR_ON;
+- break;
+- case 6:
+- aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
+- state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
+- break;
+- default:
+- break;
+- }
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+-
+-}
+-
+-/* set playback sample rate */
+-static unsigned int ali_set_dac_rate(struct ali_state *state,
+- unsigned int rate)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- u32 new_rate;
+- struct ac97_codec *codec = state->card->ac97_codec[0];
+-
+- if (!(state->card->ac97_features & 0x0001)) {
+- dmabuf->rate = clocking;
+- return clocking;
+- }
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+- dmabuf->rate = rate;
+-
+- /*
+- * Adjust for misclocked crap
+- */
+-
+- rate = (rate * clocking) / 48000;
+-
+- if (strict_clocking && rate < 8000) {
+- rate = 8000;
+- dmabuf->rate = (rate * 48000) / clocking;
+- }
+-
+- new_rate = ac97_set_dac_rate(codec, rate);
+- if (new_rate != rate) {
+- dmabuf->rate = (new_rate * 48000) / clocking;
+- }
+- rate = new_rate;
+- return dmabuf->rate;
+-}
+-
+-/* set recording sample rate */
+-static unsigned int ali_set_adc_rate(struct ali_state *state,
+- unsigned int rate)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- u32 new_rate;
+- struct ac97_codec *codec = state->card->ac97_codec[0];
+-
+- if (!(state->card->ac97_features & 0x0001)) {
+- dmabuf->rate = clocking;
+- return clocking;
+- }
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+- dmabuf->rate = rate;
+-
+- /*
+- * Adjust for misclocked crap
+- */
+-
+- rate = (rate * clocking) / 48000;
+- if (strict_clocking && rate < 8000) {
+- rate = 8000;
+- dmabuf->rate = (rate * 48000) / clocking;
+- }
+-
+- new_rate = ac97_set_adc_rate(codec, rate);
+-
+- if (new_rate != rate) {
+- dmabuf->rate = (new_rate * 48000) / clocking;
+- rate = new_rate;
+- }
+- return dmabuf->rate;
+-}
+-
+-/* set codec independent spdifout sample rate */
+-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
+- unsigned int rate)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+-
+- if (!(state->card->ac97_features & 0x0001)) {
+- dmabuf->rate = clocking;
+- return clocking;
+- }
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+- dmabuf->rate = rate;
+-
+- return dmabuf->rate;
+-}
+-
+-/* set controller independent spdif out function sample rate */
+-static void ali_set_spdifout_rate(struct ali_state *state,
+- unsigned int rate)
+-{
+- unsigned char ch_st_sel;
+- unsigned short status_rate;
+-
+- switch (rate) {
+- case 44100:
+- status_rate = 0;
+- break;
+- case 32000:
+- status_rate = 0x300;
+- break;
+- case 48000:
+- default:
+- status_rate = 0x200;
+- break;
+- }
+-
+- ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out
+-
+- ch_st_sel |= 0x80; //select right
+- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
+- outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
+-
+- ch_st_sel &= (~0x80); //select left
+- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
+- outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
+-}
+-
+-/* get current playback/recording dma buffer pointer (byte offset from LBA),
+- called with spinlock held! */
+-
+-static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned int civ, offset, port, port_picb;
+- unsigned int data;
+-
+- if (!dmabuf->enable)
+- return 0;
+-
+- if (rec == 1)
+- port = state->card->iobase + dmabuf->read_channel->port;
+- else if (rec == 2)
+- port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
+- else if (rec == 3)
+- port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
+- else
+- port = state->card->iobase + dmabuf->write_channel->port;
+-
+- port_picb = port + OFF_PICB;
+-
+- do {
+- civ = inb(port + OFF_CIV) & 31;
+- offset = inw(port_picb);
+- /* Must have a delay here! */
+- if (offset == 0)
+- udelay(1);
+-
+- /* Reread both registers and make sure that that total
+- * offset from the first reading to the second is 0.
+- * There is an issue with SiS hardware where it will count
+- * picb down to 0, then update civ to the next value,
+- * then set the new picb to fragsize bytes. We can catch
+- * it between the civ update and the picb update, making
+- * it look as though we are 1 fragsize ahead of where we
+- * are. The next to we get the address though, it will
+- * be back in thdelay is more than long enough
+- * that we won't have to worry about the chip still being
+- * out of sync with reality ;-)
+- */
+- } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
+-
+- data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
+- if (inw(port_picb) == 0)
+- data -= 2048;
+-
+- return data;
+-}
+-
+-/* Stop recording (lock held) */
+-static inline void __stop_adc(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- struct ali_card *card = state->card;
+-
+- dmabuf->enable &= ~ADC_RUNNING;
+-
+- outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
+- udelay(1);
+-
+- outb(0, card->iobase + PI_CR);
+- while (inb(card->iobase + PI_CR) != 0);
+-
+- // now clear any latent interrupt bits (like the halt bit)
+- outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
+- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
+-}
+-
+-static void stop_adc(struct ali_state *state)
+-{
+- struct ali_card *card = state->card;
+- unsigned long flags;
+- spin_lock_irqsave(&card->lock, flags);
+- __stop_adc(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-static inline void __start_adc(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+-
+- if (dmabuf->count < dmabuf->dmasize && dmabuf->ready
+- && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+- dmabuf->enable |= ADC_RUNNING;
+- outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
+- if (state->card->channel[0].used == 1)
+- outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER
+- udelay(100);
+- if (state->card->channel[2].used == 1)
+- outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER
+- udelay(100);
+- }
+-}
+-
+-static void start_adc(struct ali_state *state)
+-{
+- struct ali_card *card = state->card;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&card->lock, flags);
+- __start_adc(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-/* stop playback (lock held) */
+-static inline void __stop_dac(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- struct ali_card *card = state->card;
+-
+- dmabuf->enable &= ~DAC_RUNNING;
+- outl(0x00020000, card->iobase + 0x08);
+- outb(0, card->iobase + PO_CR);
+- while (inb(card->iobase + PO_CR) != 0)
+- cpu_relax();
+-
+- outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
+-
+- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
+-}
+-
+-static void stop_dac(struct ali_state *state)
+-{
+- struct ali_card *card = state->card;
+- unsigned long flags;
+- spin_lock_irqsave(&card->lock, flags);
+- __stop_dac(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-static inline void __start_dac(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+- (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+- dmabuf->enable |= DAC_RUNNING;
+- outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
+- outl((1 << 1), state->card->iobase + 0x08); //dma control register
+- }
+-}
+-
+-static void start_dac(struct ali_state *state)
+-{
+- struct ali_card *card = state->card;
+- unsigned long flags;
+- spin_lock_irqsave(&card->lock, flags);
+- __start_dac(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-/* stop codec and controller spdif out (lock held) */
+-static inline void __stop_spdifout(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- struct ali_card *card = state->card;
+-
+- if (codec_independent_spdif_locked > 0) {
+- dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
+- outl((1 << 19), card->iobase + 0x08);
+- outb(0, card->iobase + CODECSPDIFOUT_CR);
+-
+- while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
+- cpu_relax();
+-
+- outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
+- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
+- outl((1 << 23), card->iobase + 0x08);
+- outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
+- while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
+- cpu_relax();
+- outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
+- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
+- }
+- }
+-}
+-
+-static void stop_spdifout(struct ali_state *state)
+-{
+- struct ali_card *card = state->card;
+- unsigned long flags;
+- spin_lock_irqsave(&card->lock, flags);
+- __stop_spdifout(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-static inline void __start_spdifout(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+- (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+- if (codec_independent_spdif_locked > 0) {
+- dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
+- outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
+- outl((1 << 3), state->card->iobase + 0x08); //dma control register
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
+- outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
+- outl((1 << 7), state->card->iobase + 0x08); //dma control register
+- }
+- }
+- }
+-}
+-
+-static void start_spdifout(struct ali_state *state)
+-{
+- struct ali_card *card = state->card;
+- unsigned long flags;
+- spin_lock_irqsave(&card->lock, flags);
+- __start_spdifout(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-/* allocate DMA buffer, playback , recording,spdif out buffer should be allocated separately */
+-static int alloc_dmabuf(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- void *rawbuf = NULL;
+- int order, size;
+- struct page *page, *pend;
+-
+- /* If we don't have any oss frag params, then use our default ones */
+- if (dmabuf->ossmaxfrags == 0)
+- dmabuf->ossmaxfrags = 4;
+- if (dmabuf->ossfragsize == 0)
+- dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;
+- size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+-
+- if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
+- return 0;
+- /* alloc enough to satisfy the oss params */
+- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+- if ((PAGE_SIZE << order) > size)
+- continue;
+- if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
+- PAGE_SIZE << order,
+- &dmabuf->dma_handle)))
+- break;
+- }
+- if (!rawbuf)
+- return -ENOMEM;
+-
+- dmabuf->ready = dmabuf->mapped = 0;
+- dmabuf->rawbuf = rawbuf;
+- dmabuf->buforder = order;
+-
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
+- for (page = virt_to_page(rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- return 0;
+-}
+-
+-/* free DMA buffer */
+-static void dealloc_dmabuf(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- struct page *page, *pend;
+-
+- if (dmabuf->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+- for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- pci_free_consistent(state->card->pci_dev,
+- PAGE_SIZE << dmabuf->buforder,
+- dmabuf->rawbuf, dmabuf->dma_handle);
+- }
+- dmabuf->rawbuf = NULL;
+- dmabuf->mapped = dmabuf->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct ali_state *state, unsigned rec)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- struct ali_channel *c = NULL;
+- struct sg_item *sg;
+- unsigned long flags;
+- int ret;
+- unsigned fragint;
+- int i;
+-
+- spin_lock_irqsave(&state->card->lock, flags);
+- if (dmabuf->enable & DAC_RUNNING)
+- __stop_dac(state);
+- if (dmabuf->enable & ADC_RUNNING)
+- __stop_adc(state);
+- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- __stop_spdifout(state);
+- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- __stop_spdifout(state);
+-
+- dmabuf->total_bytes = 0;
+- dmabuf->count = dmabuf->error = 0;
+- dmabuf->swptr = dmabuf->hwptr = 0;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-
+- /* allocate DMA buffer, let alloc_dmabuf determine if we are already
+- * allocated well enough or if we should replace the current buffer
+- * (assuming one is already allocated, if it isn't, then allocate it).
+- */
+- if ((ret = alloc_dmabuf(state)))
+- return ret;
+-
+- /* FIXME: figure out all this OSS fragment stuff */
+- /* I did, it now does what it should according to the OSS API. DL */
+- /* We may not have realloced our dmabuf, but the fragment size to
+- * fragment number ratio may have changed, so go ahead and reprogram
+- * things
+- */
+-
+- dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
+- dmabuf->numfrag = SG_LEN;
+- dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;
+- dmabuf->fragsamples = dmabuf->fragsize >> 1;
+- dmabuf->userfragsize = dmabuf->ossfragsize;
+- dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
+-
+- memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
+-
+- if (dmabuf->ossmaxfrags == 4) {
+- fragint = 8;
+- dmabuf->fragshift = 2;
+- } else if (dmabuf->ossmaxfrags == 8) {
+- fragint = 4;
+- dmabuf->fragshift = 3;
+- } else if (dmabuf->ossmaxfrags == 16) {
+- fragint = 2;
+- dmabuf->fragshift = 4;
+- } else {
+- fragint = 1;
+- dmabuf->fragshift = 5;
+- }
+- /*
+- * Now set up the ring
+- */
+-
+- if (rec == 1)
+- c = dmabuf->read_channel;
+- else if (rec == 2)
+- c = dmabuf->codec_spdifout_channel;
+- else if (rec == 3)
+- c = dmabuf->controller_spdifout_channel;
+- else if (rec == 0)
+- c = dmabuf->write_channel;
+- if (c != NULL) {
+- sg = &c->sg[0];
+- /*
+- * Load up 32 sg entries and take an interrupt at half
+- * way (we might want more interrupts later..)
+- */
+- for (i = 0; i < dmabuf->numfrag; i++) {
+- sg->busaddr =
+- virt_to_bus(dmabuf->rawbuf +
+- dmabuf->fragsize * i);
+- // the card will always be doing 16bit stereo
+- sg->control = dmabuf->fragsamples;
+- sg->control |= CON_BUFPAD; //I modify
+- // set us up to get IOC interrupts as often as needed to
+- // satisfy numfrag requirements, no more
+- if (((i + 1) % fragint) == 0) {
+- sg->control |= CON_IOC;
+- }
+- sg++;
+- }
+- spin_lock_irqsave(&state->card->lock, flags);
+- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
+- outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
+- outb(0, state->card->iobase + c->port + OFF_CIV);
+- outb(0, state->card->iobase + c->port + OFF_LVI);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- }
+- /* set the ready flag for the dma buffer */
+- dmabuf->ready = 1;
+- return 0;
+-}
+-
+-static void __ali_update_lvi(struct ali_state *state, int rec)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- int x, port;
+- port = state->card->iobase;
+- if (rec == 1)
+- port += dmabuf->read_channel->port;
+- else if (rec == 2)
+- port += dmabuf->codec_spdifout_channel->port;
+- else if (rec == 3)
+- port += dmabuf->controller_spdifout_channel->port;
+- else if (rec == 0)
+- port += dmabuf->write_channel->port;
+- /* if we are currently stopped, then our CIV is actually set to our
+- * *last* sg segment and we are ready to wrap to the next. However,
+- * if we set our LVI to the last sg segment, then it won't wrap to
+- * the next sg segment, it won't even get a start. So, instead, when
+- * we are stopped, we set both the LVI value and also we increment
+- * the CIV value to the next sg segment to be played so that when
+- * we call start_{dac,adc}, things will operate properly
+- */
+- if (!dmabuf->enable && dmabuf->ready) {
+- if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+- __start_adc(state);
+- while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+- cpu_relax();
+- } else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+- __start_dac(state);
+- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+- cpu_relax();
+- } else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+- if (codec_independent_spdif_locked > 0) {
+- // outb((inb(port+OFF_CIV))&31, port+OFF_LVI);
+- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+- __start_spdifout(state);
+- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+- cpu_relax();
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+- __start_spdifout(state);
+- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+- cpu_relax();
+- }
+- }
+- }
+- }
+-
+- /* swptr - 1 is the tail of our transfer */
+- x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
+- x /= dmabuf->fragsize;
+- outb(x, port + OFF_LVI);
+-}
+-
+-static void ali_update_lvi(struct ali_state *state, int rec)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned long flags;
+- if (!dmabuf->ready)
+- return;
+- spin_lock_irqsave(&state->card->lock, flags);
+- __ali_update_lvi(state, rec);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-}
+-
+-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
+-static void ali_update_ptr(struct ali_state *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned hwptr;
+- int diff;
+-
+- /* error handling and process wake up for DAC */
+- if (dmabuf->enable == ADC_RUNNING) {
+- /* update hardware pointer */
+- hwptr = ali_get_dma_addr(state, 1);
+- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+- dmabuf->hwptr = hwptr;
+- dmabuf->total_bytes += diff;
+- dmabuf->count += diff;
+- if (dmabuf->count > dmabuf->dmasize) {
+- /* buffer underrun or buffer overrun */
+- /* this is normal for the end of a read */
+- /* only give an error if we went past the */
+- /* last valid sg entry */
+- if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {
+- printk(KERN_WARNING "ali_audio: DMA overrun on read\n");
+- dmabuf->error++;
+- }
+- }
+- if (dmabuf->count > dmabuf->userfragsize)
+- wake_up(&dmabuf->wait);
+- }
+- /* error handling and process wake up for DAC */
+- if (dmabuf->enable == DAC_RUNNING) {
+- /* update hardware pointer */
+- hwptr = ali_get_dma_addr(state, 0);
+- diff =
+- (dmabuf->dmasize + hwptr -
+- dmabuf->hwptr) % dmabuf->dmasize;
+-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+- printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+-#endif
+- dmabuf->hwptr = hwptr;
+- dmabuf->total_bytes += diff;
+- dmabuf->count -= diff;
+- if (dmabuf->count < 0) {
+- /* buffer underrun or buffer overrun */
+- /* this is normal for the end of a write */
+- /* only give an error if we went past the */
+- /* last valid sg entry */
+- if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {
+- printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
+- printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
+- inb(state->card->iobase + PO_CIV) & 31,
+- inb(state->card->iobase + PO_LVI) & 31,
+- dmabuf->hwptr,
+- dmabuf->count);
+- dmabuf->error++;
+- }
+- }
+- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+- wake_up(&dmabuf->wait);
+- }
+-
+- /* error handling and process wake up for CODEC SPDIF OUT */
+- if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+- /* update hardware pointer */
+- hwptr = ali_get_dma_addr(state, 2);
+- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+- dmabuf->hwptr = hwptr;
+- dmabuf->total_bytes += diff;
+- dmabuf->count -= diff;
+- if (dmabuf->count < 0) {
+- /* buffer underrun or buffer overrun */
+- /* this is normal for the end of a write */
+- /* only give an error if we went past the */
+- /* last valid sg entry */
+- if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {
+- printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
+- printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
+- inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,
+- inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,
+- dmabuf->hwptr, dmabuf->count);
+- dmabuf->error++;
+- }
+- }
+- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+- wake_up(&dmabuf->wait);
+- }
+- /* error handling and process wake up for CONTROLLER SPDIF OUT */
+- if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+- /* update hardware pointer */
+- hwptr = ali_get_dma_addr(state, 3);
+- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+- dmabuf->hwptr = hwptr;
+- dmabuf->total_bytes += diff;
+- dmabuf->count -= diff;
+- if (dmabuf->count < 0) {
+- /* buffer underrun or buffer overrun */
+- /* this is normal for the end of a write */
+- /* only give an error if we went past the */
+- /* last valid sg entry */
+- if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {
+- printk(KERN_WARNING
+- "ali_audio: DMA overrun on write\n");
+- printk("ali_audio: CIV %d, LVI %d, hwptr %x, "
+- "count %d\n",
+- inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,
+- inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,
+- dmabuf->hwptr, dmabuf->count);
+- dmabuf->error++;
+- }
+- }
+- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+- wake_up(&dmabuf->wait);
+- }
+-}
+-
+-static inline int ali_get_free_write_space(struct
+- ali_state
+- *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- int free;
+-
+- if (dmabuf->count < 0) {
+- dmabuf->count = 0;
+- dmabuf->swptr = dmabuf->hwptr;
+- }
+- free = dmabuf->dmasize - dmabuf->swptr;
+- if ((dmabuf->count + free) > dmabuf->dmasize){
+- free = dmabuf->dmasize - dmabuf->count;
+- }
+- return free;
+-}
+-
+-static inline int ali_get_available_read_data(struct
+- ali_state
+- *state)
+-{
+- struct dmabuf *dmabuf = &state->dmabuf;
+- int avail;
+- ali_update_ptr(state);
+- // catch overruns during record
+- if (dmabuf->count > dmabuf->dmasize) {
+- dmabuf->count = dmabuf->dmasize;
+- dmabuf->swptr = dmabuf->hwptr;
+- }
+- avail = dmabuf->count;
+- avail -= (dmabuf->hwptr % dmabuf->fragsize);
+- if (avail < 0)
+- return (0);
+- return (avail);
+-}
+-
+-static int drain_dac(struct ali_state *state, int signals_allowed)
+-{
+-
+- DECLARE_WAITQUEUE(wait, current);
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned long flags;
+- unsigned long tmo;
+- int count;
+- if (!dmabuf->ready)
+- return 0;
+- if (dmabuf->mapped) {
+- stop_dac(state);
+- return 0;
+- }
+- add_wait_queue(&dmabuf->wait, &wait);
+- for (;;) {
+-
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- count = dmabuf->count;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- if (count <= 0)
+- break;
+- /*
+- * This will make sure that our LVI is correct, that our
+- * pointer is updated, and that the DAC is running. We
+- * have to force the setting of dmabuf->trigger to avoid
+- * any possible deadlocks.
+- */
+- if (!dmabuf->enable) {
+- dmabuf->trigger = PCM_ENABLE_OUTPUT;
+- ali_update_lvi(state, 0);
+- }
+- if (signal_pending(current) && signals_allowed) {
+- break;
+- }
+-
+- /* It seems that we have to set the current state to
+- * TASK_INTERRUPTIBLE every time to make the process
+- * really go to sleep. This also has to be *after* the
+- * update_ptr() call because update_ptr is likely to
+- * do a wake_up() which will unset this before we ever
+- * try to sleep, resuling in a tight loop in this code
+- * instead of actually sleeping and waiting for an
+- * interrupt to wake us up!
+- */
+- set_current_state(TASK_INTERRUPTIBLE);
+- /*
+- * set the timeout to significantly longer than it *should*
+- * take for the DAC to drain the DMA buffer
+- */
+- tmo = (count * HZ) / (dmabuf->rate);
+- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+- printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n");
+- count = 0;
+- break;
+- }
+- }
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&dmabuf->wait, &wait);
+- if (count > 0 && signal_pending(current) && signals_allowed)
+- return -ERESTARTSYS;
+- stop_dac(state);
+- return 0;
+-}
+-
+-
+-static int drain_spdifout(struct ali_state *state, int signals_allowed)
+-{
+-
+- DECLARE_WAITQUEUE(wait, current);
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned long flags;
+- unsigned long tmo;
+- int count;
+- if (!dmabuf->ready)
+- return 0;
+- if (dmabuf->mapped) {
+- stop_spdifout(state);
+- return 0;
+- }
+- add_wait_queue(&dmabuf->wait, &wait);
+- for (;;) {
+-
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- count = dmabuf->count;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- if (count <= 0)
+- break;
+- /*
+- * This will make sure that our LVI is correct, that our
+- * pointer is updated, and that the DAC is running. We
+- * have to force the setting of dmabuf->trigger to avoid
+- * any possible deadlocks.
+- */
+- if (!dmabuf->enable) {
+- if (codec_independent_spdif_locked > 0) {
+- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+- ali_update_lvi(state, 2);
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+- ali_update_lvi(state, 3);
+- }
+- }
+- }
+- if (signal_pending(current) && signals_allowed) {
+- break;
+- }
+-
+- /* It seems that we have to set the current state to
+- * TASK_INTERRUPTIBLE every time to make the process
+- * really go to sleep. This also has to be *after* the
+- * update_ptr() call because update_ptr is likely to
+- * do a wake_up() which will unset this before we ever
+- * try to sleep, resuling in a tight loop in this code
+- * instead of actually sleeping and waiting for an
+- * interrupt to wake us up!
+- */
+- set_current_state(TASK_INTERRUPTIBLE);
+- /*
+- * set the timeout to significantly longer than it *should*
+- * take for the DAC to drain the DMA buffer
+- */
+- tmo = (count * HZ) / (dmabuf->rate);
+- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+- printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n");
+- count = 0;
+- break;
+- }
+- }
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&dmabuf->wait, &wait);
+- if (count > 0 && signal_pending(current) && signals_allowed)
+- return -ERESTARTSYS;
+- stop_spdifout(state);
+- return 0;
+-}
+-
+-static void ali_channel_interrupt(struct ali_card *card)
+-{
+- int i, count;
+-
+- for (i = 0; i < NR_HW_CH; i++) {
+- struct ali_state *state = card->states[i];
+- struct ali_channel *c = NULL;
+- struct dmabuf *dmabuf;
+- unsigned long port = card->iobase;
+- u16 status;
+- if (!state)
+- continue;
+- if (!state->dmabuf.ready)
+- continue;
+- dmabuf = &state->dmabuf;
+- if (codec_independent_spdif_locked > 0) {
+- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+- c = dmabuf->codec_spdifout_channel;
+- }
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- c = dmabuf->controller_spdifout_channel;
+- } else {
+- if (dmabuf->enable & DAC_RUNNING) {
+- c = dmabuf->write_channel;
+- } else if (dmabuf->enable & ADC_RUNNING) {
+- c = dmabuf->read_channel;
+- } else
+- continue;
+- }
+- }
+- port += c->port;
+-
+- status = inw(port + OFF_SR);
+-
+- if (status & DMA_INT_COMPLETE) {
+- /* only wake_up() waiters if this interrupt signals
+- * us being beyond a userfragsize of data open or
+- * available, and ali_update_ptr() does that for
+- * us
+- */
+- ali_update_ptr(state);
+- }
+-
+- if (status & DMA_INT_LVI) {
+- ali_update_ptr(state);
+- wake_up(&dmabuf->wait);
+-
+- if (dmabuf->enable & DAC_RUNNING)
+- count = dmabuf->count;
+- else if (dmabuf->enable & ADC_RUNNING)
+- count = dmabuf->dmasize - dmabuf->count;
+- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- count = dmabuf->count;
+- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- count = dmabuf->count;
+- else count = 0;
+-
+- if (count > 0) {
+- if (dmabuf->enable & DAC_RUNNING)
+- outl((1 << 1), state->card->iobase + ALI_DMACR);
+- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- outl((1 << 3), state->card->iobase + ALI_DMACR);
+- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- outl((1 << 7), state->card->iobase + ALI_DMACR);
+- } else {
+- if (dmabuf->enable & DAC_RUNNING)
+- __stop_dac(state);
+- if (dmabuf->enable & ADC_RUNNING)
+- __stop_adc(state);
+- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- __stop_spdifout(state);
+- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- __stop_spdifout(state);
+- dmabuf->enable = 0;
+- wake_up(&dmabuf->wait);
+- }
+-
+- }
+- if (!(status & DMA_INT_DCH)) {
+- ali_update_ptr(state);
+- wake_up(&dmabuf->wait);
+- if (dmabuf->enable & DAC_RUNNING)
+- count = dmabuf->count;
+- else if (dmabuf->enable & ADC_RUNNING)
+- count = dmabuf->dmasize - dmabuf->count;
+- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- count = dmabuf->count;
+- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- count = dmabuf->count;
+- else
+- count = 0;
+-
+- if (count > 0) {
+- if (dmabuf->enable & DAC_RUNNING)
+- outl((1 << 1), state->card->iobase + ALI_DMACR);
+- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- outl((1 << 3), state->card->iobase + ALI_DMACR);
+- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- outl((1 << 7), state->card->iobase + ALI_DMACR);
+- } else {
+- if (dmabuf->enable & DAC_RUNNING)
+- __stop_dac(state);
+- if (dmabuf->enable & ADC_RUNNING)
+- __stop_adc(state);
+- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+- __stop_spdifout(state);
+- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+- __stop_spdifout(state);
+- dmabuf->enable = 0;
+- wake_up(&dmabuf->wait);
+- }
+- }
+- outw(status & DMA_INT_MASK, port + OFF_SR);
+- }
+-}
+-
+-static irqreturn_t ali_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct ali_card *card = (struct ali_card *) dev_id;
+- u32 status;
+- u16 status2;
+-
+- spin_lock(&card->lock);
+- status = inl(card->iobase + ALI_INTERRUPTSR);
+- if (!(status & INT_MASK)) {
+- spin_unlock(&card->lock);
+- return IRQ_NONE; /* not for us */
+- }
+-
+- if (codec_independent_spdif_locked > 0) {
+- if (globel == 0) {
+- globel += 1;
+- status2 = inw(card->iobase + 0x76);
+- outw(status2 | 0x000c, card->iobase + 0x76);
+- } else {
+- if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+- ali_channel_interrupt(card);
+- }
+- } else {
+- if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+- ali_channel_interrupt(card);
+- }
+-
+- /* clear 'em */
+- outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
+- spin_unlock(&card->lock);
+- return IRQ_HANDLED;
+-}
+-
+-/* in this loop, dmabuf.count signifies the amount of data that is
+- waiting to be copied to the user's buffer. It is filled by the dma
+- machine and drained by this loop. */
+-
+-static ssize_t ali_read(struct file *file, char __user *buffer,
+- size_t count, loff_t * ppos)
+-{
+- struct ali_state *state = (struct ali_state *) file->private_data;
+- struct ali_card *card = state ? state->card : NULL;
+- struct dmabuf *dmabuf = &state->dmabuf;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned int swptr;
+- int cnt;
+- DECLARE_WAITQUEUE(waita, current);
+-#ifdef DEBUG2
+- printk("ali_audio: ali_read called, count = %d\n", count);
+-#endif
+- if (dmabuf->mapped)
+- return -ENXIO;
+- if (dmabuf->enable & DAC_RUNNING)
+- return -ENODEV;
+- if (!dmabuf->read_channel) {
+- dmabuf->ready = 0;
+- dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
+- if (!dmabuf->read_channel) {
+- return -EBUSY;
+- }
+- }
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+- add_wait_queue(&dmabuf->wait, &waita);
+- while (count > 0) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&card->lock, flags);
+- if (PM_SUSPENDED(card)) {
+- spin_unlock_irqrestore(&card->lock, flags);
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- continue;
+- }
+- swptr = dmabuf->swptr;
+- cnt = ali_get_available_read_data(state);
+- // this is to make the copy_to_user simpler below
+- if (cnt > (dmabuf->dmasize - swptr))
+- cnt = dmabuf->dmasize - swptr;
+- spin_unlock_irqrestore(&card->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- /* Lop off the last two bits to force the code to always
+- * write in full samples. This keeps software that sets
+- * O_NONBLOCK but doesn't check the return value of the
+- * write call from getting things out of state where they
+- * think a full 4 byte sample was written when really only
+- * a portion was, resulting in odd sound and stereo
+- * hysteresis.
+- */
+- cnt &= ~0x3;
+- if (cnt <= 0) {
+- unsigned long tmo;
+- /*
+- * Don't let us deadlock. The ADC won't start if
+- * dmabuf->trigger isn't set. A call to SETTRIGGER
+- * could have turned it off after we set it to on
+- * previously.
+- */
+- dmabuf->trigger = PCM_ENABLE_INPUT;
+- /*
+- * This does three things. Updates LVI to be correct,
+- * makes sure the ADC is running, and updates the
+- * hwptr.
+- */
+- ali_update_lvi(state, 1);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto done;
+- }
+- /* Set the timeout to how long it would take to fill
+- * two of our buffers. If we haven't been woke up
+- * by then, then we know something is wrong.
+- */
+- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
+-
+- /* There are two situations when sleep_on_timeout returns, one is when
+- the interrupt is serviced correctly and the process is waked up by
+- ISR ON TIME. Another is when timeout is expired, which means that
+- either interrupt is NOT serviced correctly (pending interrupt) or it
+- is TOO LATE for the process to be scheduled to run (scheduler latency)
+- which results in a (potential) buffer overrun. And worse, there is
+- NOTHING we can do to prevent it. */
+- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+- printk(KERN_ERR
+- "ali_audio: recording schedule timeout, "
+- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- dmabuf->dmasize, dmabuf->fragsize,
+- dmabuf->count, dmabuf->hwptr,
+- dmabuf->swptr);
+- /* a buffer overrun, we delay the recovery until next time the
+- while loop begin and we REALLY have space to record */
+- }
+- if (signal_pending(current)) {
+- ret = ret ? ret : -ERESTARTSYS;
+- goto done;
+- }
+- continue;
+- }
+-
+- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- goto done;
+- }
+-
+- swptr = (swptr + cnt) % dmabuf->dmasize;
+- spin_lock_irqsave(&card->lock, flags);
+- if (PM_SUSPENDED(card)) {
+- spin_unlock_irqrestore(&card->lock, flags);
+- continue;
+- }
+- dmabuf->swptr = swptr;
+- dmabuf->count -= cnt;
+- spin_unlock_irqrestore(&card->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- }
+-done:
+- ali_update_lvi(state, 1);
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&dmabuf->wait, &waita);
+- return ret;
+-}
+-
+-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+- the soundcard. it is drained by the dma machine and filled by this loop. */
+-static ssize_t ali_write(struct file *file,
+- const char __user *buffer, size_t count, loff_t * ppos)
+-{
+- struct ali_state *state = (struct ali_state *) file->private_data;
+- struct ali_card *card = state ? state->card : NULL;
+- struct dmabuf *dmabuf = &state->dmabuf;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned int swptr = 0;
+- int cnt, x;
+- DECLARE_WAITQUEUE(waita, current);
+-#ifdef DEBUG2
+- printk("ali_audio: ali_write called, count = %d\n", count);
+-#endif
+- if (dmabuf->mapped)
+- return -ENXIO;
+- if (dmabuf->enable & ADC_RUNNING)
+- return -ENODEV;
+- if (codec_independent_spdif_locked > 0) {
+- if (!dmabuf->codec_spdifout_channel) {
+- dmabuf->ready = 0;
+- dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card);
+- if (!dmabuf->codec_spdifout_channel)
+- return -EBUSY;
+- }
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (!dmabuf->controller_spdifout_channel) {
+- dmabuf->ready = 0;
+- dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card);
+- if (!dmabuf->controller_spdifout_channel)
+- return -EBUSY;
+- }
+- } else {
+- if (!dmabuf->write_channel) {
+- dmabuf->ready = 0;
+- dmabuf->write_channel =
+- card->alloc_pcm_channel(card);
+- if (!dmabuf->write_channel)
+- return -EBUSY;
+- }
+- }
+- }
+-
+- if (codec_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
+- return ret;
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
+- return ret;
+- } else {
+-
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+- return ret;
+- }
+- }
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+- add_wait_queue(&dmabuf->wait, &waita);
+- while (count > 0) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&state->card->lock, flags);
+- if (PM_SUSPENDED(card)) {
+- spin_unlock_irqrestore(&card->lock, flags);
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- continue;
+- }
+-
+- swptr = dmabuf->swptr;
+- cnt = ali_get_free_write_space(state);
+- /* Bound the maximum size to how much we can copy to the
+- * dma buffer before we hit the end. If we have more to
+- * copy then it will get done in a second pass of this
+- * loop starting from the beginning of the buffer.
+- */
+- if (cnt > (dmabuf->dmasize - swptr))
+- cnt = dmabuf->dmasize - swptr;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-#ifdef DEBUG2
+- printk(KERN_INFO
+- "ali_audio: ali_write: %d bytes available space\n",
+- cnt);
+-#endif
+- if (cnt > count)
+- cnt = count;
+- /* Lop off the last two bits to force the code to always
+- * write in full samples. This keeps software that sets
+- * O_NONBLOCK but doesn't check the return value of the
+- * write call from getting things out of state where they
+- * think a full 4 byte sample was written when really only
+- * a portion was, resulting in odd sound and stereo
+- * hysteresis.
+- */
+- cnt &= ~0x3;
+- if (cnt <= 0) {
+- unsigned long tmo;
+- // There is data waiting to be played
+- /*
+- * Force the trigger setting since we would
+- * deadlock with it set any other way
+- */
+- if (codec_independent_spdif_locked > 0) {
+- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+- ali_update_lvi(state, 2);
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+- ali_update_lvi(state, 3);
+- } else {
+-
+- dmabuf->trigger = PCM_ENABLE_OUTPUT;
+- ali_update_lvi(state, 0);
+- }
+- }
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto ret;
+- }
+- /* Not strictly correct but works */
+- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
+- /* There are two situations when sleep_on_timeout returns, one is when
+- the interrupt is serviced correctly and the process is waked up by
+- ISR ON TIME. Another is when timeout is expired, which means that
+- either interrupt is NOT serviced correctly (pending interrupt) or it
+- is TOO LATE for the process to be scheduled to run (scheduler latency)
+- which results in a (potential) buffer underrun. And worse, there is
+- NOTHING we can do to prevent it. */
+-
+- /* FIXME - do timeout handling here !! */
+- schedule_timeout(tmo >= 2 ? tmo : 2);
+-
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto ret;
+- }
+- continue;
+- }
+- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- goto ret;
+- }
+-
+- swptr = (swptr + cnt) % dmabuf->dmasize;
+- spin_lock_irqsave(&state->card->lock, flags);
+- if (PM_SUSPENDED(card)) {
+- spin_unlock_irqrestore(&card->lock, flags);
+- continue;
+- }
+-
+- dmabuf->swptr = swptr;
+- dmabuf->count += cnt;
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- }
+- if (swptr % dmabuf->fragsize) {
+- x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
+- memset(dmabuf->rawbuf + swptr, '\0', x);
+- }
+-ret:
+- if (codec_independent_spdif_locked > 0) {
+- ali_update_lvi(state, 2);
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- ali_update_lvi(state, 3);
+- } else {
+- ali_update_lvi(state, 0);
+- }
+- }
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&dmabuf->wait, &waita);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int ali_poll(struct file *file, struct poll_table_struct
+- *wait)
+-{
+- struct ali_state *state = (struct ali_state *) file->private_data;
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned long flags;
+- unsigned int mask = 0;
+- if (!dmabuf->ready)
+- return 0;
+- poll_wait(file, &dmabuf->wait, wait);
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
+- if (dmabuf->count >= (signed) dmabuf->fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) {
+- if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- return mask;
+-}
+-
+-static int ali_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct ali_state *state = (struct ali_state *) file->private_data;
+- struct dmabuf *dmabuf = &state->dmabuf;
+- int ret = -EINVAL;
+- unsigned long size;
+- lock_kernel();
+- if (vma->vm_flags & VM_WRITE) {
+- if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) {
+- ret = -EBUSY;
+- goto out;
+- }
+- }
+- if (vma->vm_flags & VM_READ) {
+- if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
+- ret = -EBUSY;
+- goto out;
+- }
+- }
+- if ((ret = prog_dmabuf(state, 0)) != 0)
+- goto out;
+- ret = -EINVAL;
+- if (vma->vm_pgoff != 0)
+- goto out;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << dmabuf->buforder))
+- goto out;
+- ret = -EAGAIN;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+- dmabuf->mapped = 1;
+- dmabuf->trigger = 0;
+- ret = 0;
+-out:
+- unlock_kernel();
+- return ret;
+-}
+-
+-static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct ali_state *state = (struct ali_state *) file->private_data;
+- struct ali_channel *c = NULL;
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- unsigned int i_scr;
+- int val = 0, ret;
+- struct ac97_codec *codec = state->card->ac97_codec[0];
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+-#ifdef DEBUG
+- printk("ali_audio: ali_ioctl, arg=0x%x, cmd=",
+- arg ? *p : 0);
+-#endif
+- switch (cmd) {
+- case OSS_GETVERSION:
+-#ifdef DEBUG
+- printk("OSS_GETVERSION\n");
+-#endif
+- return put_user(SOUND_VERSION, p);
+- case SNDCTL_DSP_RESET:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_RESET\n");
+-#endif
+- spin_lock_irqsave(&state->card->lock, flags);
+- if (dmabuf->enable == DAC_RUNNING) {
+- c = dmabuf->write_channel;
+- __stop_dac(state);
+- }
+- if (dmabuf->enable == ADC_RUNNING) {
+- c = dmabuf->read_channel;
+- __stop_adc(state);
+- }
+- if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+- c = dmabuf->codec_spdifout_channel;
+- __stop_spdifout(state);
+- }
+- if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+- c = dmabuf->controller_spdifout_channel;
+- __stop_spdifout(state);
+- }
+- if (c != NULL) {
+- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
+- outl(virt_to_bus(&c->sg[0]),
+- state->card->iobase + c->port + OFF_BDBAR);
+- outb(0, state->card->iobase + c->port + OFF_CIV);
+- outb(0, state->card->iobase + c->port + OFF_LVI);
+- }
+-
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- synchronize_irq(state->card->pci_dev->irq);
+- dmabuf->ready = 0;
+- dmabuf->swptr = dmabuf->hwptr = 0;
+- dmabuf->count = dmabuf->total_bytes = 0;
+- return 0;
+- case SNDCTL_DSP_SYNC:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SYNC\n");
+-#endif
+- if (codec_independent_spdif_locked > 0) {
+- if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING
+- || file->f_flags & O_NONBLOCK)
+- return 0;
+- if ((val = drain_spdifout(state, 1)))
+- return val;
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (dmabuf->enable !=
+- CONTROLLER_SPDIFOUT_RUNNING
+- || file->f_flags & O_NONBLOCK)
+- return 0;
+- if ((val = drain_spdifout(state, 1)))
+- return val;
+- } else {
+- if (dmabuf->enable != DAC_RUNNING
+- || file->f_flags & O_NONBLOCK)
+- return 0;
+- if ((val = drain_dac(state, 1)))
+- return val;
+- }
+- }
+- dmabuf->total_bytes = 0;
+- return 0;
+- case SNDCTL_DSP_SPEED: /* set smaple rate */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SPEED\n");
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- if (file->f_mode & FMODE_WRITE) {
+- if ((state->card->ac97_status & SPDIF_ON)) { /* S/PDIF Enabled */
+- /* RELTEK ALC650 only support 48000, need to check that */
+- if (ali_valid_spdif_rate(codec, val)) {
+- if (codec_independent_spdif_locked > 0) {
+- ali_set_spdif_output(state, -1, 0);
+- stop_spdifout(state);
+- dmabuf->ready = 0;
+- /* I add test codec independent spdif out */
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_set_codecspdifout_rate(state, val); // I modified
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- /* Set S/PDIF transmitter rate. */
+- i_scr = inl(state->card->iobase + ALI_SCR);
+- if ((i_scr & 0x00300000) == 0x00100000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+- } else {
+- if ((i_scr&0x00300000) == 0x00200000)
+- {
+- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+- } else {
+- if ((i_scr & 0x00300000) == 0x00300000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+- } else {
+- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+- }
+- }
+- }
+-
+- if (!(state->card->ac97_status & SPDIF_ON)) {
+- val = dmabuf->rate;
+- }
+- } else {
+- if (controller_independent_spdif_locked > 0)
+- {
+- stop_spdifout(state);
+- dmabuf->ready = 0;
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_set_spdifout_rate(state, controller_independent_spdif_locked);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- } else {
+- /* Set DAC rate */
+- ali_set_spdif_output(state, -1, 0);
+- stop_dac(state);
+- dmabuf->ready = 0;
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_set_dac_rate(state, val);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- /* Set S/PDIF transmitter rate. */
+- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val);
+- if (!(state->card->ac97_status & SPDIF_ON))
+- {
+- val = dmabuf->rate;
+- }
+- }
+- }
+- } else { /* Not a valid rate for S/PDIF, ignore it */
+- val = dmabuf->rate;
+- }
+- } else {
+- stop_dac(state);
+- dmabuf->ready = 0;
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_set_dac_rate(state, val);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- }
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(state);
+- dmabuf->ready = 0;
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_set_adc_rate(state, val);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- }
+- }
+- return put_user(dmabuf->rate, p);
+- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_STEREO\n");
+-#endif
+- if (dmabuf->enable & DAC_RUNNING) {
+- stop_dac(state);
+- }
+- if (dmabuf->enable & ADC_RUNNING) {
+- stop_adc(state);
+- }
+- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+- stop_spdifout(state);
+- }
+- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
+- stop_spdifout(state);
+- }
+- return put_user(1, p);
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if (codec_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)))
+- return val;
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)))
+- return val;
+- } else {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
+- return val;
+- }
+- }
+- }
+-
+- if (file->f_mode & FMODE_READ) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
+- return val;
+- }
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
+-#endif
+- return put_user(dmabuf->userfragsize, p);
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETFMTS\n");
+-#endif
+- return put_user(AFMT_S16_LE, p);
+- case SNDCTL_DSP_SETFMT: /* Select sample format */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SETFMT\n");
+-#endif
+- return put_user(AFMT_S16_LE, p);
+- case SNDCTL_DSP_CHANNELS: // add support 4,6 channel
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_CHANNELS\n");
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val > 0) {
+- if (dmabuf->enable & DAC_RUNNING) {
+- stop_dac(state);
+- }
+- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+- stop_spdifout(state);
+- }
+- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
+- stop_spdifout(state);
+- }
+- if (dmabuf->enable & ADC_RUNNING) {
+- stop_adc(state);
+- }
+- } else {
+- return put_user(state->card->channels, p);
+- }
+-
+- i_scr = inl(state->card->iobase + ALI_SCR);
+- /* Current # of channels enabled */
+- if (i_scr & 0x00000100)
+- ret = 4;
+- else if (i_scr & 0x00000200)
+- ret = 6;
+- else
+- ret = 2;
+- switch (val) {
+- case 2: /* 2 channels is always supported */
+- if (codec_independent_spdif_locked > 0) {
+- outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR));
+- } else
+- outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR));
+- /* Do we need to change mixer settings???? */
+- break;
+- case 4: /* Supported on some chipsets, better check first */
+- if (codec_independent_spdif_locked > 0) {
+- outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR));
+- } else
+- outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR));
+- break;
+- case 6: /* Supported on some chipsets, better check first */
+- if (codec_independent_spdif_locked > 0) {
+- outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR));
+- } else
+- outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR));
+- break;
+- default: /* nothing else is ever supported by the chipset */
+- val = ret;
+- break;
+- }
+- return put_user(val, p);
+- case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
+- /* we update the swptr to the end of the last sg segment then return */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_POST\n");
+-#endif
+- if (codec_independent_spdif_locked > 0) {
+- if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING))
+- return 0;
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING))
+- return 0;
+- } else {
+- if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
+- return 0;
+- }
+- }
+- if ((dmabuf->swptr % dmabuf->fragsize) != 0) {
+- val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
+- dmabuf->swptr += val;
+- dmabuf->count += val;
+- }
+- return 0;
+- case SNDCTL_DSP_SUBDIVIDE:
+- if (dmabuf->subdivision)
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
+-#endif
+- dmabuf->subdivision = val;
+- dmabuf->ready = 0;
+- return 0;
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- dmabuf->ossfragsize = 1 << (val & 0xffff);
+- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+- if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
+- return -EINVAL;
+- /*
+- * Bound the frag size into our allowed range of 256 - 4096
+- */
+- if (dmabuf->ossfragsize < 256)
+- dmabuf->ossfragsize = 256;
+- else if (dmabuf->ossfragsize > 4096)
+- dmabuf->ossfragsize = 4096;
+- /*
+- * The numfrags could be something reasonable, or it could
+- * be 0xffff meaning "Give me as much as possible". So,
+- * we check the numfrags * fragsize doesn't exceed our
+- * 64k buffer limit, nor is it less than our 8k minimum.
+- * If it fails either one of these checks, then adjust the
+- * number of fragments, not the size of them. It's OK if
+- * our number of fragments doesn't equal 32 or anything
+- * like our hardware based number now since we are using
+- * a different frag count for the hardware. Before we get
+- * into this though, bound the maxfrags to avoid overflow
+- * issues. A reasonable bound would be 64k / 256 since our
+- * maximum buffer size is 64k and our minimum frag size is
+- * 256. On the other end, our minimum buffer size is 8k and
+- * our maximum frag size is 4k, so the lower bound should
+- * be 2.
+- */
+- if (dmabuf->ossmaxfrags > 256)
+- dmabuf->ossmaxfrags = 256;
+- else if (dmabuf->ossmaxfrags < 2)
+- dmabuf->ossmaxfrags = 2;
+- val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+- while (val < 8192) {
+- val <<= 1;
+- dmabuf->ossmaxfrags <<= 1;
+- }
+- while (val > 65536) {
+- val >>= 1;
+- dmabuf->ossmaxfrags >>= 1;
+- }
+- dmabuf->ready = 0;
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
+- dmabuf->ossfragsize, dmabuf->ossmaxfrags);
+-#endif
+- return 0;
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (codec_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
+- return val;
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
+- return val;
+- } else {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+- return val;
+- }
+- }
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- abinfo.fragsize = dmabuf->userfragsize;
+- abinfo.fragstotal = dmabuf->userfrags;
+- if (dmabuf->mapped)
+- abinfo.bytes = dmabuf->dmasize;
+- else
+- abinfo.bytes = ali_get_free_write_space(state);
+- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-#if defined(DEBUG) || defined(DEBUG_MMAP)
+- printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n",
+- abinfo.bytes, abinfo.fragsize, abinfo.fragments,
+- abinfo.fragstotal);
+-#endif
+- return copy_to_user(argp, &abinfo,
+- sizeof(abinfo)) ? -EFAULT : 0;
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (codec_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
+- return val;
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
+- return val;
+- } else {
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+- return val;
+- }
+- }
+- spin_lock_irqsave(&state->card->lock, flags);
+- val = ali_get_free_write_space(state);
+- cinfo.bytes = dmabuf->total_bytes;
+- cinfo.ptr = dmabuf->hwptr;
+- cinfo.blocks = val / dmabuf->userfragsize;
+- if (codec_independent_spdif_locked > 0) {
+- if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+- dmabuf->count += val;
+- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+- __ali_update_lvi(state, 2);
+- }
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+- dmabuf->count += val;
+- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+- __ali_update_lvi(state, 3);
+- }
+- } else {
+- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+- dmabuf->count += val;
+- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+- __ali_update_lvi(state, 0);
+- }
+- }
+- }
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-#if defined(DEBUG) || defined(DEBUG_MMAP)
+- printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
+- cinfo.blocks, cinfo.ptr, dmabuf->count);
+-#endif
+- return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT : 0;
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
+- return val;
+- spin_lock_irqsave(&state->card->lock, flags);
+- abinfo.bytes = ali_get_available_read_data(state);
+- abinfo.fragsize = dmabuf->userfragsize;
+- abinfo.fragstotal = dmabuf->userfrags;
+- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-#if defined(DEBUG) || defined(DEBUG_MMAP)
+- printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n",
+- abinfo.bytes, abinfo.fragsize, abinfo.fragments,
+- abinfo.fragstotal);
+-#endif
+- return copy_to_user(argp, &abinfo,
+- sizeof(abinfo)) ? -EFAULT : 0;
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+- return val;
+- spin_lock_irqsave(&state->card->lock, flags);
+- val = ali_get_available_read_data(state);
+- cinfo.bytes = dmabuf->total_bytes;
+- cinfo.blocks = val / dmabuf->userfragsize;
+- cinfo.ptr = dmabuf->hwptr;
+- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+- dmabuf->count -= val;
+- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+- __ali_update_lvi(state, 1);
+- }
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-#if defined(DEBUG) || defined(DEBUG_MMAP)
+- printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
+- cinfo.blocks, cinfo.ptr, dmabuf->count);
+-#endif
+- return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT: 0;
+- case SNDCTL_DSP_NONBLOCK:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_NONBLOCK\n");
+-#endif
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+- case SNDCTL_DSP_GETCAPS:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETCAPS\n");
+-#endif
+- return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
+- DSP_CAP_MMAP | DSP_CAP_BIND, p);
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
+-#endif
+- return put_user(dmabuf->trigger, p);
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+-#if defined(DEBUG) || defined(DEBUG_MMAP)
+- printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
+-#endif
+- if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+- stop_adc(state);
+- }
+- if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+- stop_dac(state);
+- }
+- if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+- stop_spdifout(state);
+- }
+- if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+- stop_spdifout(state);
+- }
+- dmabuf->trigger = val;
+- if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
+- if (!dmabuf->write_channel) {
+- dmabuf->ready = 0;
+- dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
+- if (!dmabuf->write_channel)
+- return -EBUSY;
+- }
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+- return ret;
+- if (dmabuf->mapped) {
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- dmabuf->count = 0;
+- dmabuf->swptr = dmabuf->hwptr;
+- dmabuf->count = ali_get_free_write_space(state);
+- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+- __ali_update_lvi(state, 0);
+- spin_unlock_irqrestore(&state->card->lock,
+- flags);
+- } else
+- start_dac(state);
+- }
+- if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) {
+- if (!dmabuf->codec_spdifout_channel) {
+- dmabuf->ready = 0;
+- dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card);
+- if (!dmabuf->codec_spdifout_channel)
+- return -EBUSY;
+- }
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
+- return ret;
+- if (dmabuf->mapped) {
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- dmabuf->count = 0;
+- dmabuf->swptr = dmabuf->hwptr;
+- dmabuf->count = ali_get_free_write_space(state);
+- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+- __ali_update_lvi(state, 2);
+- spin_unlock_irqrestore(&state->card->lock,
+- flags);
+- } else
+- start_spdifout(state);
+- }
+- if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) {
+- if (!dmabuf->controller_spdifout_channel) {
+- dmabuf->ready = 0;
+- dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card);
+- if (!dmabuf->controller_spdifout_channel)
+- return -EBUSY;
+- }
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
+- return ret;
+- if (dmabuf->mapped) {
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- dmabuf->count = 0;
+- dmabuf->swptr = dmabuf->hwptr;
+- dmabuf->count = ali_get_free_write_space(state);
+- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+- __ali_update_lvi(state, 3);
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- } else
+- start_spdifout(state);
+- }
+- if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
+- if (!dmabuf->read_channel) {
+- dmabuf->ready = 0;
+- dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
+- if (!dmabuf->read_channel)
+- return -EBUSY;
+- }
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+- return ret;
+- if (dmabuf->mapped) {
+- spin_lock_irqsave(&state->card->lock,
+- flags);
+- ali_update_ptr(state);
+- dmabuf->swptr = dmabuf->hwptr;
+- dmabuf->count = 0;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+- }
+- ali_update_lvi(state, 1);
+- start_adc(state);
+- }
+- return 0;
+- case SNDCTL_DSP_SETDUPLEX:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SETDUPLEX\n");
+-#endif
+- return -EINVAL;
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&state->card->lock, flags);
+- ali_update_ptr(state);
+- val = dmabuf->count;
+- spin_unlock_irqrestore(&state->card->lock, flags);
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
+-#endif
+- return put_user(val, p);
+- case SOUND_PCM_READ_RATE:
+-#ifdef DEBUG
+- printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
+-#endif
+- return put_user(dmabuf->rate, p);
+- case SOUND_PCM_READ_CHANNELS:
+-#ifdef DEBUG
+- printk("SOUND_PCM_READ_CHANNELS\n");
+-#endif
+- return put_user(2, p);
+- case SOUND_PCM_READ_BITS:
+-#ifdef DEBUG
+- printk("SOUND_PCM_READ_BITS\n");
+-#endif
+- return put_user(AFMT_S16_LE, p);
+- case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_SETSPDIF\n");
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- /* Check to make sure the codec supports S/PDIF transmitter */
+- if ((state->card->ac97_features & 4)) {
+- /* mask out the transmitter speed bits so the user can't set them */
+- val &= ~0x3000;
+- /* Add the current transmitter speed bits to the passed value */
+- ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+- val |= (ret & 0x3000);
+- ali_ac97_set(codec, AC97_SPDIF_CONTROL, val);
+- if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) {
+- printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
+- return -EFAULT;
+- }
+- }
+-#ifdef DEBUG
+- else
+- printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
+-#endif
+- return put_user(val, p);
+- case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETSPDIF\n");
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- /* Check to make sure the codec supports S/PDIF transmitter */
+- if (!(state->card->ac97_features & 4)) {
+-#ifdef DEBUG
+- printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
+-#endif
+- val = 0;
+- } else {
+- val = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+- }
+-
+- return put_user(val, p);
+-//end add support spdif out
+-//add support 4,6 channel
+- case SNDCTL_DSP_GETCHANNELMASK:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_GETCHANNELMASK\n");
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- /* Based on AC'97 DAC support, not ICH hardware */
+- val = DSP_BIND_FRONT;
+- if (state->card->ac97_features & 0x0004)
+- val |= DSP_BIND_SPDIF;
+- if (state->card->ac97_features & 0x0080)
+- val |= DSP_BIND_SURR;
+- if (state->card->ac97_features & 0x0140)
+- val |= DSP_BIND_CENTER_LFE;
+- return put_user(val, p);
+- case SNDCTL_DSP_BIND_CHANNEL:
+-#ifdef DEBUG
+- printk("SNDCTL_DSP_BIND_CHANNEL\n");
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val == DSP_BIND_QUERY) {
+- val = DSP_BIND_FRONT; /* Always report this as being enabled */
+- if (state->card->ac97_status & SPDIF_ON)
+- val |= DSP_BIND_SPDIF;
+- else {
+- if (state->card->ac97_status & SURR_ON)
+- val |= DSP_BIND_SURR;
+- if (state->card->
+- ac97_status & CENTER_LFE_ON)
+- val |= DSP_BIND_CENTER_LFE;
+- }
+- } else { /* Not a query, set it */
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (dmabuf->enable == DAC_RUNNING) {
+- stop_dac(state);
+- }
+- if (val & DSP_BIND_SPDIF) { /* Turn on SPDIF */
+- /* Ok, this should probably define what slots
+- * to use. For now, we'll only set it to the
+- * defaults:
+- *
+- * non multichannel codec maps to slots 3&4
+- * 2 channel codec maps to slots 7&8
+- * 4 channel codec maps to slots 6&9
+- * 6 channel codec maps to slots 10&11
+- *
+- * there should be some way for the app to
+- * select the slot assignment.
+- */
+- i_scr = inl(state->card->iobase + ALI_SCR);
+- if (codec_independent_spdif_locked > 0) {
+-
+- if ((i_scr & 0x00300000) == 0x00100000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+- } else {
+- if ((i_scr & 0x00300000) == 0x00200000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+- } else {
+- if ((i_scr & 0x00300000) == 0x00300000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+- }
+- }
+- }
+- } else { /* codec spdif out (pcm out share ) */
+- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate); //I do not modify
+- }
+-
+- if (!(state->card->ac97_status & SPDIF_ON))
+- val &= ~DSP_BIND_SPDIF;
+- } else {
+- int mask;
+- int channels;
+- /* Turn off S/PDIF if it was on */
+- if (state->card->ac97_status & SPDIF_ON)
+- ali_set_spdif_output(state, -1, 0);
+- mask =
+- val & (DSP_BIND_FRONT | DSP_BIND_SURR |
+- DSP_BIND_CENTER_LFE);
+- switch (mask) {
+- case DSP_BIND_FRONT:
+- channels = 2;
+- break;
+- case DSP_BIND_FRONT | DSP_BIND_SURR:
+- channels = 4;
+- break;
+- case DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE:
+- channels = 6;
+- break;
+- default:
+- val = DSP_BIND_FRONT;
+- channels = 2;
+- break;
+- }
+- ali_set_dac_channels(state, channels);
+- /* check that they really got turned on */
+- if (!state->card->ac97_status & SURR_ON)
+- val &= ~DSP_BIND_SURR;
+- if (!state->card->
+- ac97_status & CENTER_LFE_ON)
+- val &= ~DSP_BIND_CENTER_LFE;
+- }
+- }
+- return put_user(val, p);
+- case SNDCTL_DSP_MAPINBUF:
+- case SNDCTL_DSP_MAPOUTBUF:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_WRITE_FILTER:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+- }
+- return -EINVAL;
+-}
+-
+-static int ali_open(struct inode *inode, struct file *file)
+-{
+- int i = 0;
+- struct ali_card *card = devs;
+- struct ali_state *state = NULL;
+- struct dmabuf *dmabuf = NULL;
+- unsigned int i_scr;
+-
+- /* find an available virtual channel (instance of /dev/dsp) */
+-
+- while (card != NULL) {
+-
+- /*
+- * If we are initializing and then fail, card could go
+- * away unuexpectedly while we are in the for() loop.
+- * So, check for card on each iteration before we check
+- * for card->initializing to avoid a possible oops.
+- * This usually only matters for times when the driver is
+- * autoloaded by kmod.
+- */
+- for (i = 0; i < 50 && card && card->initializing; i++) {
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout(HZ / 20);
+- }
+-
+- for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
+- if (card->states[i] == NULL) {
+- state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL);
+- if (state == NULL)
+- return -ENOMEM;
+- memset(state, 0, sizeof(struct ali_state));
+- dmabuf = &state->dmabuf;
+- goto found_virt;
+- }
+- }
+- card = card->next;
+- }
+-
+- /* no more virtual channel avaiable */
+- if (!state)
+- return -ENODEV;
+-found_virt:
+- /* initialize the virtual channel */
+-
+- state->virt = i;
+- state->card = card;
+- state->magic = ALI5455_STATE_MAGIC;
+- init_waitqueue_head(&dmabuf->wait);
+- mutex_init(&state->open_mutex);
+- file->private_data = state;
+- dmabuf->trigger = 0;
+- /* allocate hardware channels */
+- if (file->f_mode & FMODE_READ) {
+- if ((dmabuf->read_channel =
+- card->alloc_rec_pcm_channel(card)) == NULL) {
+- kfree(card->states[i]);
+- card->states[i] = NULL;
+- return -EBUSY;
+- }
+- dmabuf->trigger |= PCM_ENABLE_INPUT;
+- ali_set_adc_rate(state, 8000);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (codec_independent_spdif_locked > 0) {
+- if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) {
+- kfree(card->states[i]);
+- card->states[i] = NULL;
+- return -EBUSY;
+- }
+- dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
+- ali_set_codecspdifout_rate(state, codec_independent_spdif_locked); //It must add
+- i_scr = inl(state->card->iobase + ALI_SCR);
+- if ((i_scr & 0x00300000) == 0x00100000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+- } else {
+- if ((i_scr & 0x00300000) == 0x00200000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+- } else {
+- if ((i_scr & 0x00300000) == 0x00300000) {
+- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+- } else {
+- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+- }
+- }
+-
+- }
+- } else {
+- if (controller_independent_spdif_locked > 0) {
+- if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) {
+- kfree(card->states[i]);
+- card->states[i] = NULL;
+- return -EBUSY;
+- }
+- dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
+- ali_set_spdifout_rate(state, controller_independent_spdif_locked);
+- } else {
+- if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
+- kfree(card->states[i]);
+- card->states[i] = NULL;
+- return -EBUSY;
+- }
+- /* Initialize to 8kHz? What if we don't support 8kHz? */
+- /* Let's change this to check for S/PDIF stuff */
+-
+- dmabuf->trigger |= PCM_ENABLE_OUTPUT;
+- if (codec_pcmout_share_spdif_locked) {
+- ali_set_dac_rate(state, codec_pcmout_share_spdif_locked);
+- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked);
+- } else {
+- ali_set_dac_rate(state, 8000);
+- }
+- }
+-
+- }
+- }
+-
+- /* set default sample format. According to OSS Programmer's Guide /dev/dsp
+- should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+- /dev/dspW will accept 16-bits sample, but we don't support those so we
+- set it immediately to stereo and 16bit, which is all we do support */
+- dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO;
+- dmabuf->ossfragsize = 0;
+- dmabuf->ossmaxfrags = 0;
+- dmabuf->subdivision = 0;
+- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
+- outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int ali_release(struct inode *inode, struct file *file)
+-{
+- struct ali_state *state = (struct ali_state *) file->private_data;
+- struct ali_card *card = state->card;
+- struct dmabuf *dmabuf = &state->dmabuf;
+- unsigned long flags;
+- lock_kernel();
+-
+- /* stop DMA state machine and free DMA buffers/channels */
+- if (dmabuf->trigger & PCM_ENABLE_OUTPUT)
+- drain_dac(state, 0);
+-
+- if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)
+- drain_spdifout(state, 0);
+-
+- if (dmabuf->trigger & PCM_ENABLE_INPUT)
+- stop_adc(state);
+-
+- spin_lock_irqsave(&card->lock, flags);
+- dealloc_dmabuf(state);
+- if (file->f_mode & FMODE_WRITE) {
+- if (codec_independent_spdif_locked > 0) {
+- state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num);
+- } else {
+- if (controller_independent_spdif_locked > 0)
+- state->card->free_pcm_channel(state->card,
+- dmabuf->controller_spdifout_channel->num);
+- else state->card->free_pcm_channel(state->card,
+- dmabuf->write_channel->num);
+- }
+- }
+- if (file->f_mode & FMODE_READ)
+- state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
+-
+- state->card->states[state->virt] = NULL;
+- kfree(state);
+- spin_unlock_irqrestore(&card->lock, flags);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const */ struct file_operations ali_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = ali_read,
+- .write = ali_write,
+- .poll = ali_poll,
+- .ioctl = ali_ioctl,
+- .mmap = ali_mmap,
+- .open = ali_open,
+- .release = ali_release,
+-};
+-
+-/* Read AC97 codec registers */
+-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg)
+-{
+- struct ali_card *card = dev->private_data;
+- int count1 = 100;
+- char val;
+- unsigned short int data = 0, count, addr1, addr2 = 0;
+-
+- spin_lock(&card->ac97_lock);
+- while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
+- udelay(1);
+-
+- addr1 = reg;
+- reg |= 0x0080;
+- for (count = 0; count < 0x7f; count++) {
+- val = inb(card->iobase + ALI_CSPSR);
+- if (val & 0x08)
+- break;
+- }
+- if (count == 0x7f)
+- {
+- spin_unlock(&card->ac97_lock);
+- return -1;
+- }
+- outw(reg, (card->iobase + ALI_CPR) + 2);
+- for (count = 0; count < 0x7f; count++) {
+- val = inb(card->iobase + ALI_CSPSR);
+- if (val & 0x02) {
+- data = inw(card->iobase + ALI_SPR);
+- addr2 = inw((card->iobase + ALI_SPR) + 2);
+- break;
+- }
+- }
+- spin_unlock(&card->ac97_lock);
+- if (count == 0x7f)
+- return -1;
+- if (addr2 != addr1)
+- return -1;
+- return ((u16) data);
+-}
+-
+-/* write ac97 codec register */
+-
+-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+-{
+- struct ali_card *card = dev->private_data;
+- int count1 = 100;
+- char val;
+- unsigned short int count;
+-
+- spin_lock(&card->ac97_lock);
+- while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
+- udelay(1);
+-
+- for (count = 0; count < 0x7f; count++) {
+- val = inb(card->iobase + ALI_CSPSR);
+- if (val & 0x08)
+- break;
+- }
+- if (count == 0x7f) {
+- printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
+- spin_unlock(&card->ac97_lock);
+- return;
+- }
+- outw(data, (card->iobase + ALI_CPR));
+- outb(reg, (card->iobase + ALI_CPR) + 2);
+- for (count = 0; count < 0x7f; count++) {
+- val = inb(card->iobase + ALI_CSPSR);
+- if (val & 0x01)
+- break;
+- }
+- spin_unlock(&card->ac97_lock);
+- if (count == 0x7f)
+- printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
+- return;
+-}
+-
+-/* OSS /dev/mixer file operation methods */
+-
+-static int ali_open_mixdev(struct inode *inode, struct file *file)
+-{
+- int i;
+- int minor = iminor(inode);
+- struct ali_card *card = devs;
+- for (card = devs; card != NULL; card = card->next) {
+- /*
+- * If we are initializing and then fail, card could go
+- * away unuexpectedly while we are in the for() loop.
+- * So, check for card on each iteration before we check
+- * for card->initializing to avoid a possible oops.
+- * This usually only matters for times when the driver is
+- * autoloaded by kmod.
+- */
+- for (i = 0; i < 50 && card && card->initializing; i++) {
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout(HZ / 20);
+- }
+- for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+- if (card->ac97_codec[i] != NULL
+- && card->ac97_codec[i]->dev_mixer == minor) {
+- file->private_data = card->ac97_codec[i];
+- return nonseekable_open(inode, file);
+- }
+- }
+- return -ENODEV;
+-}
+-
+-static int ali_ioctl_mixdev(struct inode *inode,
+- struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
+- return codec->mixer_ioctl(codec, cmd, arg);
+-}
+-
+-static /*const */ struct file_operations ali_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = ali_ioctl_mixdev,
+- .open = ali_open_mixdev,
+-};
+-
+-/* AC97 codec initialisation. These small functions exist so we don't
+- duplicate code between module init and apm resume */
+-
+-static inline int ali_ac97_exists(struct ali_card *card, int ac97_number)
+-{
+- unsigned int i = 1;
+- u32 reg = inl(card->iobase + ALI_RTSR);
+- if (ac97_number) {
+- while (i < 100) {
+-
+- reg = inl(card->iobase + ALI_RTSR);
+- if (reg & 0x40) {
+- break;
+- } else {
+- outl(reg | 0x00000040,
+- card->iobase + 0x34);
+- udelay(1);
+- }
+- i++;
+- }
+-
+- } else {
+- while (i < 100) {
+- reg = inl(card->iobase + ALI_RTSR);
+- if (reg & 0x80) {
+- break;
+- } else {
+- outl(reg | 0x00000080,
+- card->iobase + 0x34);
+- udelay(1);
+- }
+- i++;
+- }
+- }
+-
+- if (ac97_number)
+- return reg & 0x40;
+- else
+- return reg & 0x80;
+-}
+-
+-static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec)
+-{
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
+- ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800);
+- return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1);
+-}
+-
+-
+-static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec)
+-{
+- /* Returns 0 on failure */
+- int i;
+- u16 addr;
+- if (ac97_probe_codec(codec) == 0)
+- return 0;
+- /* ac97_probe_codec is success ,then begin to init codec */
+- ali_ac97_set(codec, AC97_RESET, 0xffff);
+- if (card->channel[0].used == 1) {
+- ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
+- ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808);
+- ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
+- }
+-
+- if (card->channel[2].used == 1) //if MICin then init codec
+- {
+- ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
+- ali_ac97_set(codec, AC97_MIC_VOL, 0x8808);
+- ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
+- ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000);
+- }
+-
+- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000);
+- ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000);
+- ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000);
+- ali_ac97_set(codec, AC97_CD_VOL, 0x0808);
+- ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808);
+- ali_ac97_set(codec, AC97_AUX_VOL, 0x0808);
+- ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048);
+- ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000);
+- ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX);
+- ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000);
+- ali_ac97_set(codec, 0x38, 0x0000);
+- addr = ali_ac97_get(codec, 0x2a);
+- ali_ac97_set(codec, 0x2a, addr | 0x0001);
+- addr = ali_ac97_get(codec, 0x2a);
+- addr = ali_ac97_get(codec, 0x28);
+- ali_ac97_set(codec, 0x2c, 0xbb80);
+- addr = ali_ac97_get(codec, 0x2c);
+- /* power it all up */
+- ali_ac97_set(codec, AC97_POWER_CONTROL,
+- ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+- /* wait for analog ready */
+- for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout(HZ / 20);
+- }
+- /* FIXME !! */
+- i++;
+- return i;
+-}
+-
+-
+-/* I clone ali5455(2.4.7 ) not clone i810_audio(2.4.18) */
+-
+-static int ali_reset_5455(struct ali_card *card)
+-{
+- outl(0x80000003, card->iobase + ALI_SCR);
+- outl(0x83838383, card->iobase + ALI_FIFOCR1);
+- outl(0x83838383, card->iobase + ALI_FIFOCR2);
+- if (controller_pcmout_share_spdif_locked > 0) {
+- outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
+- card->iobase + ALI_SPDIFICS);
+- outl(0x0408000a, card->iobase + ALI_INTERFACECR);
+- } else {
+- if (codec_independent_spdif_locked > 0) {
+- outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR); // now I select slot 7 & 8
+- outl(0x00200000, card->iobase + ALI_INTERFACECR); //enable codec independent spdifout
+- } else
+- outl(0x04080002, card->iobase + ALI_INTERFACECR);
+- }
+-
+- outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
+- outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
+- if (controller_independent_spdif_locked > 0)
+- outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
+- card->iobase + ALI_SPDIFICS);
+- return 1;
+-}
+-
+-
+-static int ali_ac97_random_init_stuff(struct ali_card
+- *card)
+-{
+- u32 reg = inl(card->iobase + ALI_SCR);
+- int i = 0;
+- reg = inl(card->iobase + ALI_SCR);
+- if ((reg & 2) == 0) /* Cold required */
+- reg |= 2;
+- else
+- reg |= 1; /* Warm */
+- reg &= ~0x80000000; /* ACLink on */
+- outl(reg, card->iobase + ALI_SCR);
+-
+- while (i < 10) {
+- if ((inl(card->iobase + 0x18) & (1 << 1)) == 0)
+- break;
+- current->state = TASK_UNINTERRUPTIBLE;
+- schedule_timeout(HZ / 20);
+- i++;
+- }
+- if (i == 10) {
+- printk(KERN_ERR "ali_audio: AC'97 reset failed.\n");
+- return 0;
+- }
+-
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout(HZ / 2);
+- return 1;
+-}
+-
+-/* AC97 codec initialisation. */
+-
+-static int __devinit ali_ac97_init(struct ali_card *card)
+-{
+- int num_ac97 = 0;
+- int total_channels = 0;
+- struct ac97_codec *codec;
+- u16 eid;
+-
+- if (!ali_ac97_random_init_stuff(card))
+- return 0;
+-
+- /* Number of channels supported */
+- /* What about the codec? Just because the ICH supports */
+- /* multiple channels doesn't mean the codec does. */
+- /* we'll have to modify this in the codec section below */
+- /* to reflect what the codec has. */
+- /* ICH and ICH0 only support 2 channels so don't bother */
+- /* to check.... */
+- inl(card->iobase + ALI_CPR);
+- card->channels = 2;
+-
+- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+-
+- /* Assume codec isn't available until we go through the
+- * gauntlet below */
+- card->ac97_codec[num_ac97] = NULL;
+- /* The ICH programmer's reference says you should */
+- /* check the ready status before probing. So we chk */
+- /* What do we do if it's not ready? Wait and try */
+- /* again, or abort? */
+- if (!ali_ac97_exists(card, num_ac97)) {
+- if (num_ac97 == 0)
+- printk(KERN_ERR "ali_audio: Primary codec not ready.\n");
+- break;
+- }
+-
+- if ((codec = ac97_alloc_codec()) == NULL)
+- return -ENOMEM;
+- /* initialize some basic codec information, other fields will be filled
+- in ac97_probe_codec */
+- codec->private_data = card;
+- codec->id = num_ac97;
+- codec->codec_read = ali_ac97_get;
+- codec->codec_write = ali_ac97_set;
+- if (!ali_ac97_probe_and_powerup(card, codec)) {
+- printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready",
+- num_ac97);
+- kfree(codec);
+- break; /* it didn't work */
+- }
+-
+- /* Store state information about S/PDIF transmitter */
+- card->ac97_status = 0;
+- /* Don't attempt to get eid until powerup is complete */
+- eid = ali_ac97_get(codec, AC97_EXTENDED_ID);
+- if (eid == 0xFFFF) {
+- printk(KERN_ERR "ali_audio: no codec attached ?\n");
+- kfree(codec);
+- break;
+- }
+-
+- card->ac97_features = eid;
+- /* Now check the codec for useful features to make up for
+- the dumbness of the ali5455 hardware engine */
+- if (!(eid & 0x0001))
+- printk(KERN_WARNING
+- "ali_audio: only 48Khz playback available.\n");
+- else {
+- if (!ali_ac97_enable_variable_rate(codec)) {
+- printk(KERN_WARNING
+- "ali_audio: Codec refused to allow VRA, using 48Khz only.\n");
+- card->ac97_features &= ~1;
+- }
+- }
+-
+- /* Determine how many channels the codec(s) support */
+- /* - The primary codec always supports 2 */
+- /* - If the codec supports AMAP, surround DACs will */
+- /* automaticlly get assigned to slots. */
+- /* * Check for surround DACs and increment if */
+- /* found. */
+- /* - Else check if the codec is revision 2.2 */
+- /* * If surround DACs exist, assign them to slots */
+- /* and increment channel count. */
+-
+- /* All of this only applies to ICH2 and above. ICH */
+- /* and ICH0 only support 2 channels. ICH2 will only */
+- /* support multiple codecs in a "split audio" config. */
+- /* as described above. */
+-
+- /* TODO: Remove all the debugging messages! */
+-
+- if ((eid & 0xc000) == 0) /* primary codec */
+- total_channels += 2;
+- if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) {
+- printk(KERN_ERR "ali_audio: couldn't register mixer!\n");
+- kfree(codec);
+- break;
+- }
+- card->ac97_codec[num_ac97] = codec;
+- }
+- /* pick the minimum of channels supported by ICHx or codec(s) */
+- card->channels = (card->channels > total_channels) ? total_channels : card->channels;
+- return num_ac97;
+-}
+-
+-static void __devinit ali_configure_clocking(void)
+-{
+- struct ali_card *card;
+- struct ali_state *state;
+- struct dmabuf *dmabuf;
+- unsigned int i, offset, new_offset;
+- unsigned long flags;
+- card = devs;
+-
+- /* We could try to set the clocking for multiple cards, but can you even have
+- * more than one ali in a machine? Besides, clocking is global, so unless
+- * someone actually thinks more than one ali in a machine is possible and
+- * decides to rewrite that little bit, setting the rate for more than one card
+- * is a waste of time.
+- */
+- if (card != NULL) {
+- state = card->states[0] = (struct ali_state *)
+- kmalloc(sizeof(struct ali_state), GFP_KERNEL);
+- if (state == NULL)
+- return;
+- memset(state, 0, sizeof(struct ali_state));
+- dmabuf = &state->dmabuf;
+- dmabuf->write_channel = card->alloc_pcm_channel(card);
+- state->virt = 0;
+- state->card = card;
+- state->magic = ALI5455_STATE_MAGIC;
+- init_waitqueue_head(&dmabuf->wait);
+- mutex_init(&state->open_mutex);
+- dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
+- dmabuf->trigger = PCM_ENABLE_OUTPUT;
+- ali_set_dac_rate(state, 48000);
+- if (prog_dmabuf(state, 0) != 0)
+- goto config_out_nodmabuf;
+-
+- if (dmabuf->dmasize < 16384)
+- goto config_out;
+-
+- dmabuf->count = dmabuf->dmasize;
+- outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI);
+-
+- local_irq_save(flags);
+- start_dac(state);
+- offset = ali_get_dma_addr(state, 0);
+- mdelay(50);
+- new_offset = ali_get_dma_addr(state, 0);
+- stop_dac(state);
+-
+- outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR);
+- local_irq_restore(flags);
+-
+- i = new_offset - offset;
+-
+- if (i == 0)
+- goto config_out;
+- i = i / 4 * 20;
+- if (i > 48500 || i < 47500) {
+- clocking = clocking * clocking / i;
+- }
+-config_out:
+- dealloc_dmabuf(state);
+-config_out_nodmabuf:
+- state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num);
+- kfree(state);
+- card->states[0] = NULL;
+- }
+-}
+-
+-/* 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) */
+-
+-static int __devinit ali_probe(struct pci_dev *pci_dev,
+- const struct pci_device_id *pci_id)
+-{
+- struct ali_card *card;
+- if (pci_enable_device(pci_dev))
+- return -EIO;
+- if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) {
+- printk(KERN_ERR "ali5455: architecture does not support"
+- " 32bit PCI busmaster DMA\n");
+- return -ENODEV;
+- }
+-
+- if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) {
+- printk(KERN_ERR "ali_audio: out of memory\n");
+- return -ENOMEM;
+- }
+- memset(card, 0, sizeof(*card));
+- card->initializing = 1;
+- card->iobase = pci_resource_start(pci_dev, 0);
+- card->pci_dev = pci_dev;
+- card->pci_id = pci_id->device;
+- card->irq = pci_dev->irq;
+- card->next = devs;
+- card->magic = ALI5455_CARD_MAGIC;
+-#ifdef CONFIG_PM
+- card->pm_suspended = 0;
+-#endif
+- spin_lock_init(&card->lock);
+- spin_lock_init(&card->ac97_lock);
+- devs = card;
+- pci_set_master(pci_dev);
+- printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n",
+- card_names[pci_id->driver_data], card->iobase, card->irq);
+- card->alloc_pcm_channel = ali_alloc_pcm_channel;
+- card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
+- card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel;
+- card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel;
+- card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel;
+- card->free_pcm_channel = ali_free_pcm_channel;
+- card->channel[0].offset = 0;
+- card->channel[0].port = 0x40;
+- card->channel[0].num = 0;
+- card->channel[1].offset = 0;
+- card->channel[1].port = 0x50;
+- card->channel[1].num = 1;
+- card->channel[2].offset = 0;
+- card->channel[2].port = 0x60;
+- card->channel[2].num = 2;
+- card->channel[3].offset = 0;
+- card->channel[3].port = 0x70;
+- card->channel[3].num = 3;
+- card->channel[4].offset = 0;
+- card->channel[4].port = 0xb0;
+- card->channel[4].num = 4;
+- /* claim our iospace and irq */
+- request_region(card->iobase, 256, card_names[pci_id->driver_data]);
+- if (request_irq(card->irq, &ali_interrupt, IRQF_SHARED,
+- card_names[pci_id->driver_data], card)) {
+- printk(KERN_ERR "ali_audio: unable to allocate irq %d\n",
+- card->irq);
+- release_region(card->iobase, 256);
+- kfree(card);
+- return -ENODEV;
+- }
+-
+- if (ali_reset_5455(card) <= 0) {
+- unregister_sound_dsp(card->dev_audio);
+- release_region(card->iobase, 256);
+- free_irq(card->irq, card);
+- kfree(card);
+- return -ENODEV;
+- }
+-
+- /* initialize AC97 codec and register /dev/mixer */
+- if (ali_ac97_init(card) < 0) {
+- release_region(card->iobase, 256);
+- free_irq(card->irq, card);
+- kfree(card);
+- return -ENODEV;
+- }
+-
+- pci_set_drvdata(pci_dev, card);
+-
+- if (clocking == 0) {
+- clocking = 48000;
+- ali_configure_clocking();
+- }
+-
+- /* register /dev/dsp */
+- if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) {
+- int i;
+- printk(KERN_ERR"ali_audio: couldn't register DSP device!\n");
+- release_region(card->iobase, 256);
+- free_irq(card->irq, card);
+- for (i = 0; i < NR_AC97; i++)
+- if (card->ac97_codec[i] != NULL) {
+- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
+- kfree(card->ac97_codec[i]);
+- }
+- kfree(card);
+- return -ENODEV;
+- }
+- card->initializing = 0;
+- return 0;
+-}
+-
+-static void __devexit ali_remove(struct pci_dev *pci_dev)
+-{
+- int i;
+- struct ali_card *card = pci_get_drvdata(pci_dev);
+- /* free hardware resources */
+- free_irq(card->irq, devs);
+- release_region(card->iobase, 256);
+- /* unregister audio devices */
+- for (i = 0; i < NR_AC97; i++)
+- if (card->ac97_codec[i] != NULL) {
+- unregister_sound_mixer(card->ac97_codec[i]->
+- dev_mixer);
+- ac97_release_codec(card->ac97_codec[i]);
+- card->ac97_codec[i] = NULL;
+- }
+- unregister_sound_dsp(card->dev_audio);
+- kfree(card);
+-}
+-
+-#ifdef CONFIG_PM
+-static int ali_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
+-{
+- struct ali_card *card = pci_get_drvdata(dev);
+- struct ali_state *state;
+- unsigned long flags;
+- struct dmabuf *dmabuf;
+- int i, num_ac97;
+-
+- if (!card)
+- return 0;
+- spin_lock_irqsave(&card->lock, flags);
+- card->pm_suspended = 1;
+- for (i = 0; i < NR_HW_CH; i++) {
+- state = card->states[i];
+- if (!state)
+- continue;
+- /* this happens only if there are open files */
+- dmabuf = &state->dmabuf;
+- if (dmabuf->enable & DAC_RUNNING ||
+- (dmabuf->count
+- && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
+- state->pm_saved_dac_rate = dmabuf->rate;
+- stop_dac(state);
+- } else {
+- state->pm_saved_dac_rate = 0;
+- }
+- if (dmabuf->enable & ADC_RUNNING) {
+- state->pm_saved_adc_rate = dmabuf->rate;
+- stop_adc(state);
+- } else {
+- state->pm_saved_adc_rate = 0;
+- }
+- dmabuf->ready = 0;
+- dmabuf->swptr = dmabuf->hwptr = 0;
+- dmabuf->count = dmabuf->total_bytes = 0;
+- }
+-
+- spin_unlock_irqrestore(&card->lock, flags);
+- /* save mixer settings */
+- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+- struct ac97_codec *codec = card->ac97_codec[num_ac97];
+- if (!codec)
+- continue;
+- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if ((supported_mixer(codec, i)) && (codec->read_mixer)) {
+- card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i);
+- }
+- }
+- }
+- pci_save_state(dev); /* XXX do we need this? */
+- pci_disable_device(dev); /* disable busmastering */
+- pci_set_power_state(dev, 3); /* Zzz. */
+- return 0;
+-}
+-
+-
+-static int ali_pm_resume(struct pci_dev *dev)
+-{
+- int num_ac97, i = 0;
+- struct ali_card *card = pci_get_drvdata(dev);
+- pci_enable_device(dev);
+- pci_restore_state(dev);
+- /* observation of a toshiba portege 3440ct suggests that the
+- hardware has to be more or less completely reinitialized from
+- scratch after an apm suspend. Works For Me. -dan */
+- ali_ac97_random_init_stuff(card);
+- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+- struct ac97_codec *codec = card->ac97_codec[num_ac97];
+- /* check they haven't stolen the hardware while we were
+- away */
+- if (!codec || !ali_ac97_exists(card, num_ac97)) {
+- if (num_ac97)
+- continue;
+- else
+- BUG();
+- }
+- if (!ali_ac97_probe_and_powerup(card, codec))
+- BUG();
+- if ((card->ac97_features & 0x0001)) {
+- /* at probe time we found we could do variable
+- rates, but APM suspend has made it forget
+- its magical powers */
+- if (!ali_ac97_enable_variable_rate(codec))
+- BUG();
+- }
+- /* we lost our mixer settings, so restore them */
+- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if (supported_mixer(codec, i)) {
+- int val = card->pm_saved_mixer_settings[i][num_ac97];
+- codec->mixer_state[i] = val;
+- codec->write_mixer(codec, i,
+- (val & 0xff),
+- ((val >> 8) & 0xff));
+- }
+- }
+- }
+-
+- /* we need to restore the sample rate from whatever it was */
+- for (i = 0; i < NR_HW_CH; i++) {
+- struct ali_state *state = card->states[i];
+- if (state) {
+- if (state->pm_saved_adc_rate)
+- ali_set_adc_rate(state, state->pm_saved_adc_rate);
+- if (state->pm_saved_dac_rate)
+- ali_set_dac_rate(state, state->pm_saved_dac_rate);
+- }
+- }
+-
+- card->pm_suspended = 0;
+- /* any processes that were reading/writing during the suspend
+- probably ended up here */
+- for (i = 0; i < NR_HW_CH; i++) {
+- struct ali_state *state = card->states[i];
+- if (state)
+- wake_up(&state->dmabuf.wait);
+- }
+- return 0;
+-}
+-#endif /* CONFIG_PM */
+-
+-MODULE_AUTHOR("");
+-MODULE_DESCRIPTION("ALI 5455 audio support");
+-MODULE_LICENSE("GPL");
+-module_param(clocking, int, 0);
+-/* FIXME: bool? */
+-module_param(strict_clocking, uint, 0);
+-module_param(codec_pcmout_share_spdif_locked, uint, 0);
+-module_param(codec_independent_spdif_locked, uint, 0);
+-module_param(controller_pcmout_share_spdif_locked, uint, 0);
+-module_param(controller_independent_spdif_locked, uint, 0);
+-#define ALI5455_MODULE_NAME "ali5455"
+-static struct pci_driver ali_pci_driver = {
+- .name = ALI5455_MODULE_NAME,
+- .id_table = ali_pci_tbl,
+- .probe = ali_probe,
+- .remove = __devexit_p(ali_remove),
+-#ifdef CONFIG_PM
+- .suspend = ali_pm_suspend,
+- .resume = ali_pm_resume,
+-#endif /* CONFIG_PM */
+-};
+-
+-static int __init ali_init_module(void)
+-{
+- printk(KERN_INFO "ALI 5455 + AC97 Audio, version "
+- DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+-
+- if (codec_independent_spdif_locked > 0) {
+- if (codec_independent_spdif_locked == 32000
+- || codec_independent_spdif_locked == 44100
+- || codec_independent_spdif_locked == 48000) {
+- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked);
+- } else {
+- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+- codec_independent_spdif_locked = 0;
+- }
+- }
+- if (controller_independent_spdif_locked > 0) {
+- if (controller_independent_spdif_locked == 32000
+- || controller_independent_spdif_locked == 44100
+- || controller_independent_spdif_locked == 48000) {
+- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked);
+- } else {
+- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+- controller_independent_spdif_locked = 0;
+- }
+- }
+-
+- if (codec_pcmout_share_spdif_locked > 0) {
+- if (codec_pcmout_share_spdif_locked == 32000
+- || codec_pcmout_share_spdif_locked == 44100
+- || codec_pcmout_share_spdif_locked == 48000) {
+- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked);
+- } else {
+- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+- codec_pcmout_share_spdif_locked = 0;
+- }
+- }
+- if (controller_pcmout_share_spdif_locked > 0) {
+- if (controller_pcmout_share_spdif_locked == 32000
+- || controller_pcmout_share_spdif_locked == 44100
+- || controller_pcmout_share_spdif_locked == 48000) {
+- printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked);
+- } else {
+- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+- controller_pcmout_share_spdif_locked = 0;
+- }
+- }
+- return pci_register_driver(&ali_pci_driver);
+-}
+-
+-static void __exit ali_cleanup_module(void)
+-{
+- pci_unregister_driver(&ali_pci_driver);
+-}
+-
+-module_init(ali_init_module);
+-module_exit(ali_cleanup_module);
+-/*
+-Local Variables:
+-c-basic-offset: 8
+-End:
+-*/
+diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c
+deleted file mode 100644
+index e379623..0000000
+--- a/sound/oss/au1000.c
++++ /dev/null
+@@ -1,2216 +0,0 @@
+-/*
+- * au1000.c -- Sound driver for Alchemy Au1000 MIPS Internet Edge
+- * Processor.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at 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.
+- *
+- * 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.
+- *
+- *
+- * Module command line parameters:
+- *
+- * Supported devices:
+- * /dev/dsp standard OSS /dev/dsp device
+- * /dev/mixer standard OSS /dev/mixer device
+- *
+- * Notes:
+- *
+- * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are
+- * taken, slightly modified or not at all, from the ES1371 driver,
+- * so refer to the credits in es1371.c for those. The rest of the
+- * code (probe, open, read, write, the ISR, etc.) is new.
+- *
+- * Revision history
+- * 06.27.2001 Initial version
+- * 03.20.2002 Added mutex locks around read/write methods, to prevent
+- * simultaneous access on SMP or preemptible kernels. Also
+- * removed the counter/pointer fragment aligning at the end
+- * of read/write methods [stevel].
+- * 03.21.2002 Add support for coherent DMA on the audio read/write DMA
+- * channels [stevel].
+- *
+- */
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/init.h>
+-#include <linux/page-flags.h>
+-#include <linux/poll.h>
+-#include <linux/pci.h>
+-#include <linux/bitops.h>
+-#include <linux/proc_fs.h>
+-#include <linux/spinlock.h>
+-#include <linux/smp_lock.h>
+-#include <linux/ac97_codec.h>
+-#include <linux/interrupt.h>
+-#include <linux/mutex.h>
+-
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/mach-au1x00/au1000.h>
+-#include <asm/mach-au1x00/au1000_dma.h>
+-
+-/* --------------------------------------------------------------------- */
+-
+-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+-#undef AU1000_DEBUG
+-#undef AU1000_VERBOSE_DEBUG
+-
+-#define AU1000_MODULE_NAME "Au1000 audio"
+-#define PFX AU1000_MODULE_NAME
+-
+-#ifdef AU1000_DEBUG
+-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+-#else
+-#define dbg(format, arg...) do {} while (0)
+-#endif
+-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+-
+-
+-/* misc stuff */
+-#define POLL_COUNT 0x5000
+-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
+-
+-/* Boot options */
+-static int vra = 0; // 0 = no VRA, 1 = use VRA if codec supports it
+-module_param(vra, bool, 0);
+-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-struct au1000_state {
+- /* soundcore stuff */
+- int dev_audio;
+-
+-#ifdef AU1000_DEBUG
+- /* debug /proc entry */
+- struct proc_dir_entry *ps;
+- struct proc_dir_entry *ac97_ps;
+-#endif /* AU1000_DEBUG */
+-
+- struct ac97_codec codec;
+- unsigned codec_base_caps;// AC'97 reg 00h, "Reset Register"
+- unsigned codec_ext_caps; // AC'97 reg 28h, "Extended Audio ID"
+- int no_vra; // do not use VRA
+-
+- spinlock_t lock;
+- struct mutex open_mutex;
+- struct mutex sem;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+-
+- struct dmabuf {
+- unsigned int dmanr; // DMA Channel number
+- unsigned sample_rate; // Hz
+- unsigned src_factor; // SRC interp/decimation (no vra)
+- unsigned sample_size; // 8 or 16
+- int num_channels; // 1 = mono, 2 = stereo, 4, 6
+- int dma_bytes_per_sample;// DMA bytes per audio sample frame
+- int user_bytes_per_sample;// User bytes per audio sample frame
+- int cnt_factor; // user-to-DMA bytes per audio
+- // sample frame
+- void *rawbuf;
+- dma_addr_t dmaaddr;
+- unsigned buforder;
+- unsigned numfrag; // # of DMA fragments in DMA buffer
+- unsigned fragshift;
+- void *nextIn; // ptr to next-in to DMA buffer
+- void *nextOut;// ptr to next-out from DMA buffer
+- int count; // current byte count in DMA buffer
+- unsigned total_bytes; // total bytes written or read
+- unsigned error; // over/underrun
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize; // user perception of fragment size
+- unsigned dma_fragsize; // DMA (real) fragment size
+- unsigned dmasize; // Total DMA buffer size
+- // (mult. of DMA fragsize)
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned stopped:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac , dma_adc;
+-} au1000_state;
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-static inline unsigned ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static void au1000_delay(int msec)
+-{
+- unsigned long tmo;
+- signed long tmo2;
+-
+- if (in_interrupt())
+- return;
+-
+- tmo = jiffies + (msec * HZ) / 1000;
+- for (;;) {
+- tmo2 = tmo - jiffies;
+- if (tmo2 <= 0)
+- break;
+- schedule_timeout(tmo2);
+- }
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static u16 rdcodec(struct ac97_codec *codec, u8 addr)
+-{
+- struct au1000_state *s = (struct au1000_state *)codec->private_data;
+- unsigned long flags;
+- u32 cmd;
+- u16 data;
+- int i;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- for (i = 0; i < POLL_COUNT; i++)
+- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
+- break;
+- if (i == POLL_COUNT)
+- err("rdcodec: codec cmd pending expired!");
+-
+- cmd = (u32) addr & AC97C_INDEX_MASK;
+- cmd |= AC97C_READ; // read command
+- au_writel(cmd, AC97C_CMD);
+-
+- /* now wait for the data */
+- for (i = 0; i < POLL_COUNT; i++)
+- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
+- break;
+- if (i == POLL_COUNT) {
+- err("rdcodec: read poll expired!");
+- return 0;
+- }
+-
+- data = au_readl(AC97C_CMD) & 0xffff;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- return data;
+-}
+-
+-
+-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
+-{
+- struct au1000_state *s = (struct au1000_state *)codec->private_data;
+- unsigned long flags;
+- u32 cmd;
+- int i;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- for (i = 0; i < POLL_COUNT; i++)
+- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
+- break;
+- if (i == POLL_COUNT)
+- err("wrcodec: codec cmd pending expired!");
+-
+- cmd = (u32) addr & AC97C_INDEX_MASK;
+- cmd &= ~AC97C_READ; // write command
+- cmd |= ((u32) data << AC97C_WD_BIT); // OR in the data word
+- au_writel(cmd, AC97C_CMD);
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void waitcodec(struct ac97_codec *codec)
+-{
+- u16 temp;
+- int i;
+-
+- /* codec_wait is used to wait for a ready state after
+- an AC97C_RESET. */
+- au1000_delay(10);
+-
+- // first poll the CODEC_READY tag bit
+- for (i = 0; i < POLL_COUNT; i++)
+- if (au_readl(AC97C_STATUS) & AC97C_READY)
+- break;
+- if (i == POLL_COUNT) {
+- err("waitcodec: CODEC_READY poll expired!");
+- return;
+- }
+- // get AC'97 powerdown control/status register
+- temp = rdcodec(codec, AC97_POWER_CONTROL);
+-
+- // If anything is powered down, power'em up
+- if (temp & 0x7f00) {
+- // Power on
+- wrcodec(codec, AC97_POWER_CONTROL, 0);
+- au1000_delay(100);
+- // Reread
+- temp = rdcodec(codec, AC97_POWER_CONTROL);
+- }
+-
+- // Check if Codec REF,ANL,DAC,ADC ready
+- if ((temp & 0x7f0f) != 0x000f)
+- err("codec reg 26 status (0x%x) not ready!!", temp);
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-/* stop the ADC before calling */
+-static void set_adc_rate(struct au1000_state *s, unsigned rate)
+-{
+- struct dmabuf *adc = &s->dma_adc;
+- struct dmabuf *dac = &s->dma_dac;
+- unsigned adc_rate, dac_rate;
+- u16 ac97_extstat;
+-
+- if (s->no_vra) {
+- // calc SRC factor
+- adc->src_factor = ((96000 / rate) + 1) >> 1;
+- adc->sample_rate = 48000 / adc->src_factor;
+- return;
+- }
+-
+- adc->src_factor = 1;
+-
+- ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
+-
+- rate = rate > 48000 ? 48000 : rate;
+-
+- // enable VRA
+- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
+- ac97_extstat | AC97_EXTSTAT_VRA);
+- // now write the sample rate
+- wrcodec(&s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
+- // read it back for actual supported rate
+- adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("%s: set to %d Hz", __FUNCTION__, adc_rate);
+-#endif
+-
+- // some codec's don't allow unequal DAC and ADC rates, in which case
+- // writing one rate reg actually changes both.
+- dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
+- if (dac->num_channels > 2)
+- wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
+- if (dac->num_channels > 4)
+- wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
+-
+- adc->sample_rate = adc_rate;
+- dac->sample_rate = dac_rate;
+-}
+-
+-/* stop the DAC before calling */
+-static void set_dac_rate(struct au1000_state *s, unsigned rate)
+-{
+- struct dmabuf *dac = &s->dma_dac;
+- struct dmabuf *adc = &s->dma_adc;
+- unsigned adc_rate, dac_rate;
+- u16 ac97_extstat;
+-
+- if (s->no_vra) {
+- // calc SRC factor
+- dac->src_factor = ((96000 / rate) + 1) >> 1;
+- dac->sample_rate = 48000 / dac->src_factor;
+- return;
+- }
+-
+- dac->src_factor = 1;
+-
+- ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
+-
+- rate = rate > 48000 ? 48000 : rate;
+-
+- // enable VRA
+- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
+- ac97_extstat | AC97_EXTSTAT_VRA);
+- // now write the sample rate
+- wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
+- // I don't support different sample rates for multichannel,
+- // so make these channels the same.
+- if (dac->num_channels > 2)
+- wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
+- if (dac->num_channels > 4)
+- wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
+- // read it back for actual supported rate
+- dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("%s: set to %d Hz", __FUNCTION__, dac_rate);
+-#endif
+-
+- // some codec's don't allow unequal DAC and ADC rates, in which case
+- // writing one rate reg actually changes both.
+- adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
+-
+- dac->sample_rate = dac_rate;
+- adc->sample_rate = adc_rate;
+-}
+-
+-static void stop_dac(struct au1000_state *s)
+-{
+- struct dmabuf *db = &s->dma_dac;
+- unsigned long flags;
+-
+- if (db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- disable_dma(db->dmanr);
+-
+- db->stopped = 1;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void stop_adc(struct au1000_state *s)
+-{
+- struct dmabuf *db = &s->dma_adc;
+- unsigned long flags;
+-
+- if (db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- disable_dma(db->dmanr);
+-
+- db->stopped = 1;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-
+-static void set_xmit_slots(int num_channels)
+-{
+- u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_XMIT_SLOTS_MASK;
+-
+- switch (num_channels) {
+- case 1: // mono
+- case 2: // stereo, slots 3,4
+- ac97_config |= (0x3 << AC97C_XMIT_SLOTS_BIT);
+- break;
+- case 4: // stereo with surround, slots 3,4,7,8
+- ac97_config |= (0x33 << AC97C_XMIT_SLOTS_BIT);
+- break;
+- case 6: // stereo with surround and center/LFE, slots 3,4,6,7,8,9
+- ac97_config |= (0x7b << AC97C_XMIT_SLOTS_BIT);
+- break;
+- }
+-
+- au_writel(ac97_config, AC97C_CONFIG);
+-}
+-
+-static void set_recv_slots(int num_channels)
+-{
+- u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_RECV_SLOTS_MASK;
+-
+- /*
+- * Always enable slots 3 and 4 (stereo). Slot 6 is
+- * optional Mic ADC, which I don't support yet.
+- */
+- ac97_config |= (0x3 << AC97C_RECV_SLOTS_BIT);
+-
+- au_writel(ac97_config, AC97C_CONFIG);
+-}
+-
+-static void start_dac(struct au1000_state *s)
+-{
+- struct dmabuf *db = &s->dma_dac;
+- unsigned long flags;
+- unsigned long buf1, buf2;
+-
+- if (!db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- au_readl(AC97C_STATUS); // read status to clear sticky bits
+-
+- // reset Buffer 1 and 2 pointers to nextOut and nextOut+dma_fragsize
+- buf1 = virt_to_phys(db->nextOut);
+- buf2 = buf1 + db->dma_fragsize;
+- if (buf2 >= db->dmaaddr + db->dmasize)
+- buf2 -= db->dmasize;
+-
+- set_xmit_slots(db->num_channels);
+-
+- init_dma(db->dmanr);
+- if (get_dma_active_buffer(db->dmanr) == 0) {
+- clear_dma_done0(db->dmanr); // clear DMA done bit
+- set_dma_addr0(db->dmanr, buf1);
+- set_dma_addr1(db->dmanr, buf2);
+- } else {
+- clear_dma_done1(db->dmanr); // clear DMA done bit
+- set_dma_addr1(db->dmanr, buf1);
+- set_dma_addr0(db->dmanr, buf2);
+- }
+- set_dma_count(db->dmanr, db->dma_fragsize>>1);
+- enable_dma_buffers(db->dmanr);
+-
+- start_dma(db->dmanr);
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- dump_au1000_dma_channel(db->dmanr);
+-#endif
+-
+- db->stopped = 0;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_adc(struct au1000_state *s)
+-{
+- struct dmabuf *db = &s->dma_adc;
+- unsigned long flags;
+- unsigned long buf1, buf2;
+-
+- if (!db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- au_readl(AC97C_STATUS); // read status to clear sticky bits
+-
+- // reset Buffer 1 and 2 pointers to nextIn and nextIn+dma_fragsize
+- buf1 = virt_to_phys(db->nextIn);
+- buf2 = buf1 + db->dma_fragsize;
+- if (buf2 >= db->dmaaddr + db->dmasize)
+- buf2 -= db->dmasize;
+-
+- set_recv_slots(db->num_channels);
+-
+- init_dma(db->dmanr);
+- if (get_dma_active_buffer(db->dmanr) == 0) {
+- clear_dma_done0(db->dmanr); // clear DMA done bit
+- set_dma_addr0(db->dmanr, buf1);
+- set_dma_addr1(db->dmanr, buf2);
+- } else {
+- clear_dma_done1(db->dmanr); // clear DMA done bit
+- set_dma_addr1(db->dmanr, buf1);
+- set_dma_addr0(db->dmanr, buf2);
+- }
+- set_dma_count(db->dmanr, db->dma_fragsize>>1);
+- enable_dma_buffers(db->dmanr);
+-
+- start_dma(db->dmanr);
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- dump_au1000_dma_channel(db->dmanr);
+-#endif
+-
+- db->stopped = 0;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-static inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db)
+-{
+- struct page *page, *pend;
+-
+- if (db->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(db->rawbuf +
+- (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- dma_free_noncoherent(NULL,
+- PAGE_SIZE << db->buforder,
+- db->rawbuf,
+- db->dmaaddr);
+- }
+- db->rawbuf = db->nextIn = db->nextOut = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db)
+-{
+- int order;
+- unsigned user_bytes_per_sec;
+- unsigned bufs;
+- struct page *page, *pend;
+- unsigned rate = db->sample_rate;
+-
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = DMABUF_DEFAULTORDER;
+- order >= DMABUF_MINORDER; order--)
+- if ((db->rawbuf = dma_alloc_noncoherent(NULL,
+- PAGE_SIZE << order,
+- &db->dmaaddr,
+- 0)))
+- break;
+- if (!db->rawbuf)
+- return -ENOMEM;
+- db->buforder = order;
+- /* now mark the pages as reserved;
+- otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(db->rawbuf +
+- (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- }
+-
+- db->cnt_factor = 1;
+- if (db->sample_size == 8)
+- db->cnt_factor *= 2;
+- if (db->num_channels == 1)
+- db->cnt_factor *= 2;
+- db->cnt_factor *= db->src_factor;
+-
+- db->count = 0;
+- db->nextIn = db->nextOut = db->rawbuf;
+-
+- db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
+- db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
+- 2 : db->num_channels);
+-
+- user_bytes_per_sec = rate * db->user_bytes_per_sample;
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < user_bytes_per_sec)
+- db->fragshift = ld2(user_bytes_per_sec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(user_bytes_per_sec / 100 /
+- (db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+-
+- db->fragsize = 1 << db->fragshift;
+- db->dma_fragsize = db->fragsize * db->cnt_factor;
+- db->numfrag = bufs / db->dma_fragsize;
+-
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->fragsize = 1 << db->fragshift;
+- db->dma_fragsize = db->fragsize * db->cnt_factor;
+- db->numfrag = bufs / db->dma_fragsize;
+- }
+-
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+-
+- db->dmasize = db->dma_fragsize * db->numfrag;
+- memset(db->rawbuf, 0, bufs);
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("rate=%d, samplesize=%d, channels=%d",
+- rate, db->sample_size, db->num_channels);
+- dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d",
+- db->fragsize, db->cnt_factor, db->dma_fragsize);
+- dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize);
+-#endif
+-
+- db->ready = 1;
+- return 0;
+-}
+-
+-static inline int prog_dmabuf_adc(struct au1000_state *s)
+-{
+- stop_adc(s);
+- return prog_dmabuf(s, &s->dma_adc);
+-
+-}
+-
+-static inline int prog_dmabuf_dac(struct au1000_state *s)
+-{
+- stop_dac(s);
+- return prog_dmabuf(s, &s->dma_dac);
+-}
+-
+-
+-/* hold spinlock for the following */
+-static irqreturn_t dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct au1000_state *s = (struct au1000_state *) dev_id;
+- struct dmabuf *dac = &s->dma_dac;
+- unsigned long newptr;
+- u32 ac97c_stat, buff_done;
+-
+- ac97c_stat = au_readl(AC97C_STATUS);
+-#ifdef AU1000_VERBOSE_DEBUG
+- if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
+- dbg("AC97C status = 0x%08x", ac97c_stat);
+-#endif
+-
+- if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) {
+- /* fastpath out, to ease interrupt sharing */
+- return IRQ_HANDLED;
+- }
+-
+- spin_lock(&s->lock);
+-
+- if (buff_done != (DMA_D0 | DMA_D1)) {
+- dac->nextOut += dac->dma_fragsize;
+- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
+- dac->nextOut -= dac->dmasize;
+-
+- /* update playback pointers */
+- newptr = virt_to_phys(dac->nextOut) + dac->dma_fragsize;
+- if (newptr >= dac->dmaaddr + dac->dmasize)
+- newptr -= dac->dmasize;
+-
+- dac->count -= dac->dma_fragsize;
+- dac->total_bytes += dac->dma_fragsize;
+-
+- if (dac->count <= 0) {
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("dac underrun");
+-#endif
+- spin_unlock(&s->lock);
+- stop_dac(s);
+- spin_lock(&s->lock);
+- dac->count = 0;
+- dac->nextIn = dac->nextOut;
+- } else if (buff_done == DMA_D0) {
+- clear_dma_done0(dac->dmanr); // clear DMA done bit
+- set_dma_count0(dac->dmanr, dac->dma_fragsize>>1);
+- set_dma_addr0(dac->dmanr, newptr);
+- enable_dma_buffer0(dac->dmanr); // reenable
+- } else {
+- clear_dma_done1(dac->dmanr); // clear DMA done bit
+- set_dma_count1(dac->dmanr, dac->dma_fragsize>>1);
+- set_dma_addr1(dac->dmanr, newptr);
+- enable_dma_buffer1(dac->dmanr); // reenable
+- }
+- } else {
+- // both done bits set, we missed an interrupt
+- spin_unlock(&s->lock);
+- stop_dac(s);
+- spin_lock(&s->lock);
+-
+- dac->nextOut += 2*dac->dma_fragsize;
+- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
+- dac->nextOut -= dac->dmasize;
+-
+- dac->count -= 2*dac->dma_fragsize;
+- dac->total_bytes += 2*dac->dma_fragsize;
+-
+- if (dac->count > 0) {
+- spin_unlock(&s->lock);
+- start_dac(s);
+- spin_lock(&s->lock);
+- }
+- }
+-
+- /* wake up anybody listening */
+- if (waitqueue_active(&dac->wait))
+- wake_up(&dac->wait);
+-
+- spin_unlock(&s->lock);
+-
+- return IRQ_HANDLED;
+-}
+-
+-
+-static irqreturn_t adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct au1000_state *s = (struct au1000_state *) dev_id;
+- struct dmabuf *adc = &s->dma_adc;
+- unsigned long newptr;
+- u32 ac97c_stat, buff_done;
+-
+- ac97c_stat = au_readl(AC97C_STATUS);
+-#ifdef AU1000_VERBOSE_DEBUG
+- if (ac97c_stat & (AC97C_RU | AC97C_RO))
+- dbg("AC97C status = 0x%08x", ac97c_stat);
+-#endif
+-
+- if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) {
+- /* fastpath out, to ease interrupt sharing */
+- return IRQ_HANDLED;
+- }
+-
+- spin_lock(&s->lock);
+-
+- if (buff_done != (DMA_D0 | DMA_D1)) {
+- if (adc->count + adc->dma_fragsize > adc->dmasize) {
+- // Overrun. Stop ADC and log the error
+- spin_unlock(&s->lock);
+- stop_adc(s);
+- adc->error++;
+- err("adc overrun");
+- return IRQ_NONE;
+- }
+-
+- adc->nextIn += adc->dma_fragsize;
+- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
+- adc->nextIn -= adc->dmasize;
+-
+- /* update capture pointers */
+- newptr = virt_to_phys(adc->nextIn) + adc->dma_fragsize;
+- if (newptr >= adc->dmaaddr + adc->dmasize)
+- newptr -= adc->dmasize;
+-
+- adc->count += adc->dma_fragsize;
+- adc->total_bytes += adc->dma_fragsize;
+-
+- if (buff_done == DMA_D0) {
+- clear_dma_done0(adc->dmanr); // clear DMA done bit
+- set_dma_count0(adc->dmanr, adc->dma_fragsize>>1);
+- set_dma_addr0(adc->dmanr, newptr);
+- enable_dma_buffer0(adc->dmanr); // reenable
+- } else {
+- clear_dma_done1(adc->dmanr); // clear DMA done bit
+- set_dma_count1(adc->dmanr, adc->dma_fragsize>>1);
+- set_dma_addr1(adc->dmanr, newptr);
+- enable_dma_buffer1(adc->dmanr); // reenable
+- }
+- } else {
+- // both done bits set, we missed an interrupt
+- spin_unlock(&s->lock);
+- stop_adc(s);
+- spin_lock(&s->lock);
+-
+- if (adc->count + 2*adc->dma_fragsize > adc->dmasize) {
+- // Overrun. Log the error
+- adc->error++;
+- err("adc overrun");
+- spin_unlock(&s->lock);
+- return IRQ_NONE;
+- }
+-
+- adc->nextIn += 2*adc->dma_fragsize;
+- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
+- adc->nextIn -= adc->dmasize;
+-
+- adc->count += 2*adc->dma_fragsize;
+- adc->total_bytes += 2*adc->dma_fragsize;
+-
+- spin_unlock(&s->lock);
+- start_adc(s);
+- spin_lock(&s->lock);
+- }
+-
+- /* wake up anybody listening */
+- if (waitqueue_active(&adc->wait))
+- wake_up(&adc->wait);
+-
+- spin_unlock(&s->lock);
+-
+- return IRQ_HANDLED;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static loff_t au1000_llseek(struct file *file, loff_t offset, int origin)
+-{
+- return -ESPIPE;
+-}
+-
+-
+-static int au1000_open_mixdev(struct inode *inode, struct file *file)
+-{
+- file->private_data = &au1000_state;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int au1000_release_mixdev(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
+- unsigned long arg)
+-{
+- return codec->mixer_ioctl(codec, cmd, arg);
+-}
+-
+-static int au1000_ioctl_mixdev(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+- struct ac97_codec *codec = &s->codec;
+-
+- return mixdev_ioctl(codec, cmd, arg);
+-}
+-
+-static /*const */ struct file_operations au1000_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = au1000_llseek,
+- .ioctl = au1000_ioctl_mixdev,
+- .open = au1000_open_mixdev,
+- .release = au1000_release_mixdev,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct au1000_state *s, int nonblock)
+-{
+- unsigned long flags;
+- int count, tmo;
+-
+- if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
+- return 0;
+-
+- for (;;) {
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock)
+- return -EBUSY;
+- tmo = 1000 * count / (s->no_vra ?
+- 48000 : s->dma_dac.sample_rate);
+- tmo /= s->dma_dac.dma_bytes_per_sample;
+- au1000_delay(tmo);
+- }
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline u8 S16_TO_U8(s16 ch)
+-{
+- return (u8) (ch >> 8) + 0x80;
+-}
+-static inline s16 U8_TO_S16(u8 ch)
+-{
+- return (s16) (ch - 0x80) << 8;
+-}
+-
+-/*
+- * Translates user samples to dma buffer suitable for AC'97 DAC data:
+- * If mono, copy left channel to right channel in dma buffer.
+- * If 8 bit samples, cvt to 16-bit before writing to dma buffer.
+- * If interpolating (no VRA), duplicate every audio frame src_factor times.
+- */
+-static int translate_from_user(struct dmabuf *db,
+- char* dmabuf,
+- char* userbuf,
+- int dmacount)
+-{
+- int sample, i;
+- int interp_bytes_per_sample;
+- int num_samples;
+- int mono = (db->num_channels == 1);
+- char usersample[12];
+- s16 ch, dmasample[6];
+-
+- if (db->sample_size == 16 && !mono && db->src_factor == 1) {
+- // no translation necessary, just copy
+- if (copy_from_user(dmabuf, userbuf, dmacount))
+- return -EFAULT;
+- return dmacount;
+- }
+-
+- interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
+- num_samples = dmacount / interp_bytes_per_sample;
+-
+- for (sample = 0; sample < num_samples; sample++) {
+- if (copy_from_user(usersample, userbuf,
+- db->user_bytes_per_sample)) {
+- dbg("%s: fault", __FUNCTION__);
+- return -EFAULT;
+- }
+-
+- for (i = 0; i < db->num_channels; i++) {
+- if (db->sample_size == 8)
+- ch = U8_TO_S16(usersample[i]);
+- else
+- ch = *((s16 *) (&usersample[i * 2]));
+- dmasample[i] = ch;
+- if (mono)
+- dmasample[i + 1] = ch; // right channel
+- }
+-
+- // duplicate every audio frame src_factor times
+- for (i = 0; i < db->src_factor; i++)
+- memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
+-
+- userbuf += db->user_bytes_per_sample;
+- dmabuf += interp_bytes_per_sample;
+- }
+-
+- return num_samples * interp_bytes_per_sample;
+-}
+-
+-/*
+- * Translates AC'97 ADC samples to user buffer:
+- * If mono, send only left channel to user buffer.
+- * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
+- * If decimating (no VRA), skip over src_factor audio frames.
+- */
+-static int translate_to_user(struct dmabuf *db,
+- char* userbuf,
+- char* dmabuf,
+- int dmacount)
+-{
+- int sample, i;
+- int interp_bytes_per_sample;
+- int num_samples;
+- int mono = (db->num_channels == 1);
+- char usersample[12];
+-
+- if (db->sample_size == 16 && !mono && db->src_factor == 1) {
+- // no translation necessary, just copy
+- if (copy_to_user(userbuf, dmabuf, dmacount))
+- return -EFAULT;
+- return dmacount;
+- }
+-
+- interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
+- num_samples = dmacount / interp_bytes_per_sample;
+-
+- for (sample = 0; sample < num_samples; sample++) {
+- for (i = 0; i < db->num_channels; i++) {
+- if (db->sample_size == 8)
+- usersample[i] =
+- S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
+- else
+- *((s16 *) (&usersample[i * 2])) =
+- *((s16 *) (&dmabuf[i * 2]));
+- }
+-
+- if (copy_to_user(userbuf, usersample,
+- db->user_bytes_per_sample)) {
+- dbg("%s: fault", __FUNCTION__);
+- return -EFAULT;
+- }
+-
+- userbuf += db->user_bytes_per_sample;
+- dmabuf += interp_bytes_per_sample;
+- }
+-
+- return num_samples * interp_bytes_per_sample;
+-}
+-
+-/*
+- * Copy audio data to/from user buffer from/to dma buffer, taking care
+- * that we wrap when reading/writing the dma buffer. Returns actual byte
+- * count written to or read from the dma buffer.
+- */
+-static int copy_dmabuf_user(struct dmabuf *db, char* userbuf,
+- int count, int to_user)
+-{
+- char *bufptr = to_user ? db->nextOut : db->nextIn;
+- char *bufend = db->rawbuf + db->dmasize;
+- int cnt, ret;
+-
+- if (bufptr + count > bufend) {
+- int partial = (int) (bufend - bufptr);
+- if (to_user) {
+- if ((cnt = translate_to_user(db, userbuf,
+- bufptr, partial)) < 0)
+- return cnt;
+- ret = cnt;
+- if ((cnt = translate_to_user(db, userbuf + partial,
+- db->rawbuf,
+- count - partial)) < 0)
+- return cnt;
+- ret += cnt;
+- } else {
+- if ((cnt = translate_from_user(db, bufptr, userbuf,
+- partial)) < 0)
+- return cnt;
+- ret = cnt;
+- if ((cnt = translate_from_user(db, db->rawbuf,
+- userbuf + partial,
+- count - partial)) < 0)
+- return cnt;
+- ret += cnt;
+- }
+- } else {
+- if (to_user)
+- ret = translate_to_user(db, userbuf, bufptr, count);
+- else
+- ret = translate_from_user(db, bufptr, userbuf, count);
+- }
+-
+- return ret;
+-}
+-
+-
+-static ssize_t au1000_read(struct file *file, char *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+- struct dmabuf *db = &s->dma_adc;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- int cnt, usercnt, avail;
+-
+- if (db->mapped)
+- return -ENXIO;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- count *= db->cnt_factor;
+-
+- mutex_lock(&s->sem);
+- add_wait_queue(&db->wait, &wait);
+-
+- while (count > 0) {
+- // wait for samples in ADC dma buffer
+- do {
+- if (db->stopped)
+- start_adc(s);
+- spin_lock_irqsave(&s->lock, flags);
+- avail = db->count;
+- if (avail <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (avail <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto out;
+- }
+- mutex_unlock(&s->sem);
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto out2;
+- }
+- mutex_lock(&s->sem);
+- }
+- } while (avail <= 0);
+-
+- // copy from nextOut to user
+- if ((cnt = copy_dmabuf_user(db, buffer,
+- count > avail ?
+- avail : count, 1)) < 0) {
+- if (!ret)
+- ret = -EFAULT;
+- goto out;
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+- db->count -= cnt;
+- db->nextOut += cnt;
+- if (db->nextOut >= db->rawbuf + db->dmasize)
+- db->nextOut -= db->dmasize;
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- count -= cnt;
+- usercnt = cnt / db->cnt_factor;
+- buffer += usercnt;
+- ret += usercnt;
+- } // while (count > 0)
+-
+-out:
+- mutex_unlock(&s->sem);
+-out2:
+- remove_wait_queue(&db->wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-static ssize_t au1000_write(struct file *file, const char *buffer,
+- size_t count, loff_t * ppos)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+- struct dmabuf *db = &s->dma_dac;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret = 0;
+- unsigned long flags;
+- int cnt, usercnt, avail;
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("write: count=%d", count);
+-#endif
+-
+- if (db->mapped)
+- return -ENXIO;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+-
+- count *= db->cnt_factor;
+-
+- mutex_lock(&s->sem);
+- add_wait_queue(&db->wait, &wait);
+-
+- while (count > 0) {
+- // wait for space in playback buffer
+- do {
+- spin_lock_irqsave(&s->lock, flags);
+- avail = (int) db->dmasize - db->count;
+- if (avail <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (avail <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto out;
+- }
+- mutex_unlock(&s->sem);
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto out2;
+- }
+- mutex_lock(&s->sem);
+- }
+- } while (avail <= 0);
+-
+- // copy from user to nextIn
+- if ((cnt = copy_dmabuf_user(db, (char *) buffer,
+- count > avail ?
+- avail : count, 0)) < 0) {
+- if (!ret)
+- ret = -EFAULT;
+- goto out;
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+- db->count += cnt;
+- db->nextIn += cnt;
+- if (db->nextIn >= db->rawbuf + db->dmasize)
+- db->nextIn -= db->dmasize;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (db->stopped)
+- start_dac(s);
+-
+- count -= cnt;
+- usercnt = cnt / db->cnt_factor;
+- buffer += usercnt;
+- ret += usercnt;
+- } // while (count > 0)
+-
+-out:
+- mutex_unlock(&s->sem);
+-out2:
+- remove_wait_queue(&db->wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int au1000_poll(struct file *file,
+- struct poll_table_struct *wait)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac.ready)
+- return 0;
+- poll_wait(file, &s->dma_dac.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready)
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >=
+- (signed)s->dma_dac.dma_fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed) s->dma_dac.dmasize >=
+- s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int au1000_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+- struct dmabuf *db;
+- unsigned long size;
+- int ret = 0;
+-
+- dbg("%s", __FUNCTION__);
+-
+- lock_kernel();
+- mutex_lock(&s->sem);
+- if (vma->vm_flags & VM_WRITE)
+- db = &s->dma_dac;
+- else if (vma->vm_flags & VM_READ)
+- db = &s->dma_adc;
+- else {
+- ret = -EINVAL;
+- goto out;
+- }
+- if (vma->vm_pgoff != 0) {
+- ret = -EINVAL;
+- goto out;
+- }
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder)) {
+- ret = -EINVAL;
+- goto out;
+- }
+- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
+- size, vma->vm_page_prot)) {
+- ret = -EAGAIN;
+- goto out;
+- }
+- vma->vm_flags &= ~VM_IO;
+- db->mapped = 1;
+-out:
+- mutex_unlock(&s->sem);
+- unlock_kernel();
+- return ret;
+-}
+-
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+-static struct ioctl_str_t {
+- unsigned int cmd;
+- const char *str;
+-} ioctl_str[] = {
+- {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
+- {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
+- {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
+- {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
+- {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
+- {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
+- {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
+- {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
+- {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
+- {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
+- {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
+- {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
+- {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
+- {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
+- {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
+- {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
+- {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
+- {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
+- {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
+- {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
+- {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
+- {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
+- {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
+- {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
+- {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
+- {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
+- {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
+- {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
+- {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
+- {OSS_GETVERSION, "OSS_GETVERSION"},
+- {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
+- {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
+- {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
+- {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
+-};
+-#endif
+-
+-// Need to hold a spin-lock before calling this!
+-static int dma_count_done(struct dmabuf *db)
+-{
+- if (db->stopped)
+- return 0;
+-
+- return db->dma_fragsize - get_dma_residue(db->dmanr);
+-}
+-
+-
+-static int au1000_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int count;
+- int val, mapped, ret, diff;
+-
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
+- if (ioctl_str[count].cmd == cmd)
+- break;
+- }
+- if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
+- dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);
+- else
+- dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg);
+-#endif
+-
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, (int *) arg);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, file->f_flags & O_NONBLOCK);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+- DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq();
+- s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- s->dma_dac.nextIn = s->dma_dac.nextOut =
+- s->dma_dac.rawbuf;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq();
+- s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- s->dma_adc.nextIn = s->dma_adc.nextOut =
+- s->dma_adc.rawbuf;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (val >= 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- set_adc_rate(s, val);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- set_dac_rate(s, val);
+- }
+- if (s->open_mode & FMODE_READ)
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- if (s->open_mode & FMODE_WRITE)
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return put_user((file->f_mode & FMODE_READ) ?
+- s->dma_adc.sample_rate :
+- s->dma_dac.sample_rate,
+- (int *)arg);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.num_channels = val ? 2 : 1;
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.num_channels = val ? 2 : 1;
+- if (s->codec_ext_caps & AC97_EXT_DACS) {
+- // disable surround and center/lfe in AC'97
+- u16 ext_stat = rdcodec(&s->codec,
+- AC97_EXTENDED_STATUS);
+- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
+- ext_stat | (AC97_EXTSTAT_PRI |
+- AC97_EXTSTAT_PRJ |
+- AC97_EXTSTAT_PRK));
+- }
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (val != 0) {
+- if (file->f_mode & FMODE_READ) {
+- if (val < 0 || val > 2)
+- return -EINVAL;
+- stop_adc(s);
+- s->dma_adc.num_channels = val;
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- switch (val) {
+- case 1:
+- case 2:
+- break;
+- case 3:
+- case 5:
+- return -EINVAL;
+- case 4:
+- if (!(s->codec_ext_caps &
+- AC97_EXTID_SDAC))
+- return -EINVAL;
+- break;
+- case 6:
+- if ((s->codec_ext_caps &
+- AC97_EXT_DACS) != AC97_EXT_DACS)
+- return -EINVAL;
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- stop_dac(s);
+- if (val <= 2 &&
+- (s->codec_ext_caps & AC97_EXT_DACS)) {
+- // disable surround and center/lfe
+- // channels in AC'97
+- u16 ext_stat =
+- rdcodec(&s->codec,
+- AC97_EXTENDED_STATUS);
+- wrcodec(&s->codec,
+- AC97_EXTENDED_STATUS,
+- ext_stat | (AC97_EXTSTAT_PRI |
+- AC97_EXTSTAT_PRJ |
+- AC97_EXTSTAT_PRK));
+- } else if (val >= 4) {
+- // enable surround, center/lfe
+- // channels in AC'97
+- u16 ext_stat =
+- rdcodec(&s->codec,
+- AC97_EXTENDED_STATUS);
+- ext_stat &= ~AC97_EXTSTAT_PRJ;
+- if (val == 6)
+- ext_stat &=
+- ~(AC97_EXTSTAT_PRI |
+- AC97_EXTSTAT_PRK);
+- wrcodec(&s->codec,
+- AC97_EXTENDED_STATUS,
+- ext_stat);
+- }
+-
+- s->dma_dac.num_channels = val;
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- }
+- return put_user(val, (int *) arg);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- if (val == AFMT_S16_LE)
+- s->dma_adc.sample_size = 16;
+- else {
+- val = AFMT_U8;
+- s->dma_adc.sample_size = 8;
+- }
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- if (val == AFMT_S16_LE)
+- s->dma_dac.sample_size = 16;
+- else {
+- val = AFMT_U8;
+- s->dma_dac.sample_size = 8;
+- }
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- } else {
+- if (file->f_mode & FMODE_READ)
+- val = (s->dma_adc.sample_size == 16) ?
+- AFMT_S16_LE : AFMT_U8;
+- else
+- val = (s->dma_dac.sample_size == 16) ?
+- AFMT_S16_LE : AFMT_U8;
+- }
+- return put_user(val, (int *) arg);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
+- val |= PCM_ENABLE_OUTPUT;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return put_user(val, (int *) arg);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT)
+- start_adc(s);
+- else
+- stop_adc(s);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT)
+- start_dac(s);
+- else
+- stop_dac(s);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- abinfo.fragsize = s->dma_dac.fragsize;
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- count -= dma_count_done(&s->dma_dac);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = (s->dma_dac.dmasize - count) /
+- s->dma_dac.cnt_factor;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
+-#endif
+- return copy_to_user((void *) arg, &abinfo,
+- sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- abinfo.fragsize = s->dma_adc.fragsize;
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_adc.count;
+- count += dma_count_done(&s->dma_adc);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = count / s->dma_adc.cnt_factor;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- return copy_to_user((void *) arg, &abinfo,
+- sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- count -= dma_count_done(&s->dma_dac);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- count /= s->dma_dac.cnt_factor;
+- return put_user(count, (int *) arg);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- count = s->dma_adc.count;
+- if (!s->dma_adc.stopped) {
+- diff = dma_count_done(&s->dma_adc);
+- count += diff;
+- cinfo.bytes += diff;
+- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff -
+- s->dma_adc.dmaaddr;
+- } else
+- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
+- s->dma_adc.dmaaddr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_adc.fragshift;
+- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- count = s->dma_dac.count;
+- if (!s->dma_dac.stopped) {
+- diff = dma_count_done(&s->dma_dac);
+- count -= diff;
+- cinfo.bytes += diff;
+- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
+- s->dma_dac.dmaaddr;
+- } else
+- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
+- s->dma_dac.dmaaddr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_dac.fragshift;
+- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE)
+- return put_user(s->dma_dac.fragsize, (int *) arg);
+- else
+- return put_user(s->dma_adc.fragsize, (int *) arg);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- if (get_user(val, (int *) arg))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.subdivision = val;
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.subdivision = val;
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user((file->f_mode & FMODE_READ) ?
+- s->dma_adc.sample_rate :
+- s->dma_dac.sample_rate,
+- (int *)arg);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- if (file->f_mode & FMODE_READ)
+- return put_user(s->dma_adc.num_channels, (int *)arg);
+- else
+- return put_user(s->dma_dac.num_channels, (int *)arg);
+-
+- case SOUND_PCM_READ_BITS:
+- if (file->f_mode & FMODE_READ)
+- return put_user(s->dma_adc.sample_size, (int *)arg);
+- else
+- return put_user(s->dma_dac.sample_size, (int *)arg);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+- }
+-
+- return mixdev_ioctl(&s->codec, cmd, arg);
+-}
+-
+-
+-static int au1000_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- struct au1000_state *s = &au1000_state;
+- int ret;
+-
+-#ifdef AU1000_VERBOSE_DEBUG
+- if (file->f_flags & O_NONBLOCK)
+- dbg("%s: non-blocking", __FUNCTION__);
+- else
+- dbg("%s: blocking", __FUNCTION__);
+-#endif
+-
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+-
+- stop_dac(s);
+- stop_adc(s);
+-
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
+- s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
+- s->dma_adc.num_channels = 1;
+- s->dma_adc.sample_size = 8;
+- set_adc_rate(s, 8000);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->dma_adc.sample_size = 16;
+- }
+-
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
+- s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
+- s->dma_dac.num_channels = 1;
+- s->dma_dac.sample_size = 8;
+- set_dac_rate(s, 8000);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->dma_dac.sample_size = 16;
+- }
+-
+- if (file->f_mode & FMODE_READ) {
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+-
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- mutex_unlock(&s->open_mutex);
+- mutex_init(&s->sem);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int au1000_release(struct inode *inode, struct file *file)
+-{
+- struct au1000_state *s = (struct au1000_state *)file->private_data;
+-
+- lock_kernel();
+-
+- if (file->f_mode & FMODE_WRITE) {
+- unlock_kernel();
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- lock_kernel();
+- }
+-
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- dealloc_dmabuf(s, &s->dma_dac);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- dealloc_dmabuf(s, &s->dma_adc);
+- }
+- s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
+- mutex_unlock(&s->open_mutex);
+- wake_up(&s->open_wait);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const */ struct file_operations au1000_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = au1000_llseek,
+- .read = au1000_read,
+- .write = au1000_write,
+- .poll = au1000_poll,
+- .ioctl = au1000_ioctl,
+- .mmap = au1000_mmap,
+- .open = au1000_open,
+- .release = au1000_release,
+-};
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-/*
+- * for debugging purposes, we'll create a proc device that dumps the
+- * CODEC chipstate
+- */
+-
+-#ifdef AU1000_DEBUG
+-static int proc_au1000_dump(char *buf, char **start, off_t fpos,
+- int length, int *eof, void *data)
+-{
+- struct au1000_state *s = &au1000_state;
+- int cnt, len = 0;
+-
+- /* print out header */
+- len += sprintf(buf + len, "\n\t\tAU1000 Audio Debug\n\n");
+-
+- // print out digital controller state
+- len += sprintf(buf + len, "AU1000 Audio Controller registers\n");
+- len += sprintf(buf + len, "---------------------------------\n");
+- len += sprintf (buf + len, "AC97C_CONFIG = %08x\n",
+- au_readl(AC97C_CONFIG));
+- len += sprintf (buf + len, "AC97C_STATUS = %08x\n",
+- au_readl(AC97C_STATUS));
+- len += sprintf (buf + len, "AC97C_CNTRL = %08x\n",
+- au_readl(AC97C_CNTRL));
+-
+- /* print out CODEC state */
+- len += sprintf(buf + len, "\nAC97 CODEC registers\n");
+- len += sprintf(buf + len, "----------------------\n");
+- for (cnt = 0; cnt <= 0x7e; cnt += 2)
+- len += sprintf(buf + len, "reg %02x = %04x\n",
+- cnt, rdcodec(&s->codec, cnt));
+-
+- if (fpos >= len) {
+- *start = buf;
+- *eof = 1;
+- return 0;
+- }
+- *start = buf + fpos;
+- if ((len -= fpos) > length)
+- return length;
+- *eof = 1;
+- return len;
+-
+-}
+-#endif /* AU1000_DEBUG */
+-
+-/* --------------------------------------------------------------------- */
+-
+-MODULE_AUTHOR("Monta Vista Software, stevel at mvista.com");
+-MODULE_DESCRIPTION("Au1000 Audio Driver");
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int __devinit au1000_probe(void)
+-{
+- struct au1000_state *s = &au1000_state;
+- int val;
+-#ifdef AU1000_DEBUG
+- char proc_str[80];
+-#endif
+-
+- memset(s, 0, sizeof(struct au1000_state));
+-
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- mutex_init(&s->open_mutex);
+- spin_lock_init(&s->lock);
+- s->codec.private_data = s;
+- s->codec.id = 0;
+- s->codec.codec_read = rdcodec;
+- s->codec.codec_write = wrcodec;
+- s->codec.codec_wait = waitcodec;
+-
+- if (!request_mem_region(CPHYSADDR(AC97C_CONFIG),
+- 0x14, AU1000_MODULE_NAME)) {
+- err("AC'97 ports in use");
+- return -1;
+- }
+- // Allocate the DMA Channels
+- if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX,
+- "audio DAC",
+- dac_dma_interrupt,
+- IRQF_DISABLED, s)) < 0) {
+- err("Can't get DAC DMA");
+- goto err_dma1;
+- }
+- if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX,
+- "audio ADC",
+- adc_dma_interrupt,
+- IRQF_DISABLED, s)) < 0) {
+- err("Can't get ADC DMA");
+- goto err_dma2;
+- }
+-
+- info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d",
+- s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr),
+- s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr));
+-
+- // enable DMA coherency in read/write DMA channels
+- set_dma_mode(s->dma_dac.dmanr,
+- get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC);
+- set_dma_mode(s->dma_adc.dmanr,
+- get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC);
+-
+- /* register devices */
+-
+- if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0)
+- goto err_dev1;
+- if ((s->codec.dev_mixer =
+- register_sound_mixer(&au1000_mixer_fops, -1)) < 0)
+- goto err_dev2;
+-
+-#ifdef AU1000_DEBUG
+- /* intialize the debug proc device */
+- s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL,
+- proc_au1000_dump, NULL);
+-#endif /* AU1000_DEBUG */
+-
+- // configure pins for AC'97
+- au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
+-
+- // Assert reset for 10msec to the AC'97 controller, and enable clock
+- au_writel(AC97C_RS | AC97C_CE, AC97C_CNTRL);
+- au1000_delay(10);
+- au_writel(AC97C_CE, AC97C_CNTRL);
+- au1000_delay(10); // wait for clock to stabilize
+-
+- /* cold reset the AC'97 */
+- au_writel(AC97C_RESET, AC97C_CONFIG);
+- au1000_delay(10);
+- au_writel(0, AC97C_CONFIG);
+- /* need to delay around 500msec(bleech) to give
+- some CODECs enough time to wakeup */
+- au1000_delay(500);
+-
+- /* warm reset the AC'97 to start the bitclk */
+- au_writel(AC97C_SG | AC97C_SYNC, AC97C_CONFIG);
+- udelay(100);
+- au_writel(0, AC97C_CONFIG);
+-
+- /* codec init */
+- if (!ac97_probe_codec(&s->codec))
+- goto err_dev3;
+-
+- s->codec_base_caps = rdcodec(&s->codec, AC97_RESET);
+- s->codec_ext_caps = rdcodec(&s->codec, AC97_EXTENDED_ID);
+- info("AC'97 Base/Extended ID = %04x/%04x",
+- s->codec_base_caps, s->codec_ext_caps);
+-
+- /*
+- * On the Pb1000, audio playback is on the AUX_OUT
+- * channel (which defaults to LNLVL_OUT in AC'97
+- * rev 2.2) so make sure this channel is listed
+- * as supported (soundcard.h calls this channel
+- * ALTPCM). ac97_codec.c does not handle detection
+- * of this channel correctly.
+- */
+- s->codec.supported_mixers |= SOUND_MASK_ALTPCM;
+- /*
+- * Now set AUX_OUT's default volume.
+- */
+- val = 0x4343;
+- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM,
+- (unsigned long) &val);
+-
+- if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
+- // codec does not support VRA
+- s->no_vra = 1;
+- } else if (!vra) {
+- // Boot option says disable VRA
+- u16 ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
+- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
+- ac97_extstat & ~AC97_EXTSTAT_VRA);
+- s->no_vra = 1;
+- }
+- if (s->no_vra)
+- info("no VRA, interpolating and decimating");
+-
+- /* set mic to be the recording source */
+- val = SOUND_MASK_MIC;
+- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC,
+- (unsigned long) &val);
+-
+-#ifdef AU1000_DEBUG
+- sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME,
+- s->codec.id);
+- s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
+- ac97_read_proc, &s->codec);
+-#endif
+-
+-#ifdef CONFIG_MIPS_XXS1500
+- /* deassert eapd */
+- wrcodec(&s->codec, AC97_POWER_CONTROL,
+- rdcodec(&s->codec, AC97_POWER_CONTROL) & ~0x8000);
+- /* mute a number of signals which seem to be causing problems
+- * if not muted.
+- */
+- wrcodec(&s->codec, AC97_PCBEEP_VOL, 0x8000);
+- wrcodec(&s->codec, AC97_PHONE_VOL, 0x8008);
+- wrcodec(&s->codec, AC97_MIC_VOL, 0x8008);
+- wrcodec(&s->codec, AC97_LINEIN_VOL, 0x8808);
+- wrcodec(&s->codec, AC97_CD_VOL, 0x8808);
+- wrcodec(&s->codec, AC97_VIDEO_VOL, 0x8808);
+- wrcodec(&s->codec, AC97_AUX_VOL, 0x8808);
+- wrcodec(&s->codec, AC97_PCMOUT_VOL, 0x0808);
+- wrcodec(&s->codec, AC97_GENERAL_PURPOSE, 0x2000);
+-#endif
+-
+- return 0;
+-
+- err_dev3:
+- unregister_sound_mixer(s->codec.dev_mixer);
+- err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+- err_dev1:
+- free_au1000_dma(s->dma_adc.dmanr);
+- err_dma2:
+- free_au1000_dma(s->dma_dac.dmanr);
+- err_dma1:
+- release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
+- return -1;
+-}
+-
+-static void au1000_remove(void)
+-{
+- struct au1000_state *s = &au1000_state;
+-
+- if (!s)
+- return;
+-#ifdef AU1000_DEBUG
+- if (s->ps)
+- remove_proc_entry(AU1000_MODULE_NAME, NULL);
+-#endif /* AU1000_DEBUG */
+- synchronize_irq();
+- free_au1000_dma(s->dma_adc.dmanr);
+- free_au1000_dma(s->dma_dac.dmanr);
+- release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->codec.dev_mixer);
+-}
+-
+-static int __init init_au1000(void)
+-{
+- info("stevel at mvista.com, built " __TIME__ " on " __DATE__);
+- return au1000_probe();
+-}
+-
+-static void __exit cleanup_au1000(void)
+-{
+- info("unloading");
+- au1000_remove();
+-}
+-
+-module_init(init_au1000);
+-module_exit(cleanup_au1000);
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef MODULE
+-
+-static int __init au1000_setup(char *options)
+-{
+- char *this_opt;
+-
+- if (!options || !*options)
+- return 0;
+-
+- while ((this_opt = strsep(&options, ","))) {
+- if (!*this_opt)
+- continue;
+- if (!strncmp(this_opt, "vra", 3)) {
+- vra = 1;
+- }
+- }
+-
+- return 1;
+-}
+-
+-__setup("au1000_audio=", au1000_setup);
+-
+-#endif /* MODULE */
+diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
+index 4cdb862..2197951 100644
+--- a/sound/oss/au1550_ac97.c
++++ b/sound/oss/au1550_ac97.c
+@@ -719,8 +719,7 @@ prog_dmabuf_dac(struct au1550_state *s)
+ }
+
+
+-static void
+-dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void dac_dma_interrupt(int irq, void *dev_id)
+ {
+ struct au1550_state *s = (struct au1550_state *) dev_id;
+ struct dmabuf *db = &s->dma_dac;
+@@ -754,8 +753,7 @@ dac_dma_interrupt(int irq, void *dev_id,
+ }
+
+
+-static void
+-adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void adc_dma_interrupt(int irq, void *dev_id)
+ {
+ struct au1550_state *s = (struct au1550_state *)dev_id;
+ struct dmabuf *dp = &s->dma_adc;
+diff --git a/sound/oss/audio.c b/sound/oss/audio.c
+index 22dd63c..89bd27a 100644
+--- a/sound/oss/audio.c
++++ b/sound/oss/audio.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/audio.c
++ * sound/oss/audio.c
+ *
+ * Device file manager for /dev/audio
+ */
+diff --git a/sound/oss/audio_syms.c b/sound/oss/audio_syms.c
+deleted file mode 100644
+index 5da217f..0000000
+--- a/sound/oss/audio_syms.c
++++ /dev/null
+@@ -1,16 +0,0 @@
+-/*
+- * Exported symbols for audio driver.
+- */
+-
+-#include <linux/module.h>
+-
+-char audio_syms_symbol;
+-
+-#include "sound_config.h"
+-#include "sound_calls.h"
+-
+-EXPORT_SYMBOL(DMAbuf_start_dma);
+-EXPORT_SYMBOL(DMAbuf_open_dma);
+-EXPORT_SYMBOL(DMAbuf_close_dma);
+-EXPORT_SYMBOL(DMAbuf_inputintr);
+-EXPORT_SYMBOL(DMAbuf_outputintr);
+diff --git a/sound/oss/awe_hw.h b/sound/oss/awe_hw.h
+deleted file mode 100644
+index 7e403ad..0000000
+--- a/sound/oss/awe_hw.h
++++ /dev/null
+@@ -1,99 +0,0 @@
+-/*
+- * sound/awe_hw.h
+- *
+- * Access routines and definitions for the low level driver for the
+- * Creative AWE32/SB32/AWE64 wave table synth.
+- * version 0.4.4; Jan. 4, 2000
+- *
+- * Copyright (C) 1996-2000 Takashi Iwai
+- *
+- * 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 AWE_HW_H_DEF
+-#define AWE_HW_H_DEF
+-
+-/*
+- * Emu-8000 control registers
+- * name(channel) reg, port
+- */
+-
+-#define awe_cmd_idx(reg,ch) (((reg)<< 5) | (ch))
+-
+-#define Data0 0 /* 0x620: doubleword r/w */
+-#define Data1 1 /* 0xA20: doubleword r/w */
+-#define Data2 2 /* 0xA22: word r/w */
+-#define Data3 3 /* 0xE20: word r/w */
+-#define Pointer 4 /* 0xE22 register pointer r/w */
+-
+-#define AWE_CPF(ch) awe_cmd_idx(0,ch), Data0 /* DW: current pitch and fractional address */
+-#define AWE_PTRX(ch) awe_cmd_idx(1,ch), Data0 /* DW: pitch target and reverb send */
+-#define AWE_CVCF(ch) awe_cmd_idx(2,ch), Data0 /* DW: current volume and filter cutoff */
+-#define AWE_VTFT(ch) awe_cmd_idx(3,ch), Data0 /* DW: volume and filter cutoff targets */
+-#define AWE_0080(ch) awe_cmd_idx(4,ch), Data0 /* DW: ?? */
+-#define AWE_00A0(ch) awe_cmd_idx(5,ch), Data0 /* DW: ?? */
+-#define AWE_PSST(ch) awe_cmd_idx(6,ch), Data0 /* DW: pan send and loop start address */
+-#define AWE_CSL(ch) awe_cmd_idx(7,ch), Data0 /* DW: chorus send and loop end address */
+-#define AWE_CCCA(ch) awe_cmd_idx(0,ch), Data1 /* DW: Q, control bits, and current address */
+-#define AWE_HWCF4 awe_cmd_idx(1,9), Data1 /* DW: config dw 4 */
+-#define AWE_HWCF5 awe_cmd_idx(1,10), Data1 /* DW: config dw 5 */
+-#define AWE_HWCF6 awe_cmd_idx(1,13), Data1 /* DW: config dw 6 */
+-#define AWE_HWCF7 awe_cmd_idx(1,14), Data1 /* DW: config dw 7? (not documented) */
+-#define AWE_SMALR awe_cmd_idx(1,20), Data1 /* DW: sound memory address for left read */
+-#define AWE_SMARR awe_cmd_idx(1,21), Data1 /* DW: for right read */
+-#define AWE_SMALW awe_cmd_idx(1,22), Data1 /* DW: sound memory address for left write */
+-#define AWE_SMARW awe_cmd_idx(1,23), Data1 /* DW: for right write */
+-#define AWE_SMLD awe_cmd_idx(1,26), Data1 /* W: sound memory left data */
+-#define AWE_SMRD awe_cmd_idx(1,26), Data2 /* W: right data */
+-#define AWE_WC awe_cmd_idx(1,27), Data2 /* W: sample counter */
+-#define AWE_WC_Cmd awe_cmd_idx(1,27)
+-#define AWE_WC_Port Data2
+-#define AWE_HWCF1 awe_cmd_idx(1,29), Data1 /* W: config w 1 */
+-#define AWE_HWCF2 awe_cmd_idx(1,30), Data1 /* W: config w 2 */
+-#define AWE_HWCF3 awe_cmd_idx(1,31), Data1 /* W: config w 3 */
+-#define AWE_INIT1(ch) awe_cmd_idx(2,ch), Data1 /* W: init array 1 */
+-#define AWE_INIT2(ch) awe_cmd_idx(2,ch), Data2 /* W: init array 2 */
+-#define AWE_INIT3(ch) awe_cmd_idx(3,ch), Data1 /* W: init array 3 */
+-#define AWE_INIT4(ch) awe_cmd_idx(3,ch), Data2 /* W: init array 4 */
+-#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1 /* W: volume envelope delay */
+-#define AWE_DCYSUSV(ch) awe_cmd_idx(5,ch), Data1 /* W: volume envelope sustain and decay */
+-#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1 /* W: modulation envelope delay */
+-#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1 /* W: modulation envelope sustain and decay */
+-#define AWE_ATKHLDV(ch) awe_cmd_idx(4,ch), Data2 /* W: volume envelope attack and hold */
+-#define AWE_LFO1VAL(ch) awe_cmd_idx(5,ch), Data2 /* W: LFO#1 Delay */
+-#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2 /* W: modulation envelope attack and hold */
+-#define AWE_LFO2VAL(ch) awe_cmd_idx(7,ch), Data2 /* W: LFO#2 Delay */
+-#define AWE_IP(ch) awe_cmd_idx(0,ch), Data3 /* W: initial pitch */
+-#define AWE_IFATN(ch) awe_cmd_idx(1,ch), Data3 /* W: initial filter cutoff and attenuation */
+-#define AWE_PEFE(ch) awe_cmd_idx(2,ch), Data3 /* W: pitch and filter envelope heights */
+-#define AWE_FMMOD(ch) awe_cmd_idx(3,ch), Data3 /* W: vibrato and filter modulation freq */
+-#define AWE_TREMFRQ(ch) awe_cmd_idx(4,ch), Data3 /* W: LFO#1 tremolo amount and freq */
+-#define AWE_FM2FRQ2(ch) awe_cmd_idx(5,ch), Data3 /* W: LFO#2 vibrato amount and freq */
+-
+-/* used during detection (returns ROM version?; not documented in ADIP) */
+-#define AWE_U1 0xE0, Data3 /* (R)(W) used in initialization */
+-#define AWE_U2(ch) 0xC0+(ch), Data3 /* (W)(W) used in init envelope */
+-
+-
+-#define AWE_MAX_VOICES 32
+-#define AWE_NORMAL_VOICES 30 /*30&31 are reserved for DRAM refresh*/
+-
+-#define AWE_MAX_CHANNELS 32 /* max midi channels (must >= voices) */
+-#define AWE_MAX_LAYERS AWE_MAX_VOICES /* maximum number of multiple layers */
+-
+-#define AWE_DRAM_OFFSET 0x200000
+-#define AWE_MAX_DRAM_SIZE (28 * 1024) /* 28 MB is max onboard memory */
+-
+-#endif
+diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c
+deleted file mode 100644
+index d1a0eb2..0000000
+--- a/sound/oss/awe_wave.c
++++ /dev/null
+@@ -1,6149 +0,0 @@
+-/*
+- * sound/awe_wave.c
+- *
+- * The low level driver for the AWE32/SB32/AWE64 wave table synth.
+- * version 0.4.4; Jan. 4, 2000
+- *
+- * Copyright (C) 1996-2000 Takashi Iwai
+- *
+- * 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.
+- */
+-
+-/*
+- * Changelog:
+- * Aug 18, 2003, Adam Belay <ambx1 at neo.rr.com>
+- * - detection code rewrite
+- */
+-
+-#include <linux/awe_voice.h>
+-#include <linux/config.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/pnp.h>
+-
+-#include "sound_config.h"
+-
+-#include "awe_wave.h"
+-#include "awe_hw.h"
+-
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-#include "tuning.h"
+-#include <linux/ultrasound.h>
+-#endif
+-
+-/*
+- * debug message
+- */
+-
+-#ifdef AWE_DEBUG_ON
+-#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
+-#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
+-#define FATALERR(XXX) XXX
+-#else
+-#define DEBUG(LVL,XXX) /**/
+-#define ERRMSG(XXX) XXX
+-#define FATALERR(XXX) XXX
+-#endif
+-
+-/*
+- * bank and voice record
+- */
+-
+-typedef struct _sf_list sf_list;
+-typedef struct _awe_voice_list awe_voice_list;
+-typedef struct _awe_sample_list awe_sample_list;
+-
+-/* soundfont record */
+-struct _sf_list {
+- unsigned short sf_id; /* id number */
+- unsigned short type; /* lock & shared flags */
+- int num_info; /* current info table index */
+- int num_sample; /* current sample table index */
+- int mem_ptr; /* current word byte pointer */
+- awe_voice_list *infos, *last_infos; /* instruments */
+- awe_sample_list *samples, *last_samples; /* samples */
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- sf_list *shared; /* shared list */
+- unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */
+-#endif
+- sf_list *next, *prev;
+-};
+-
+-/* instrument list */
+-struct _awe_voice_list {
+- awe_voice_info v; /* instrument information */
+- sf_list *holder; /* parent sf_list of this record */
+- unsigned char bank, instr; /* preset number information */
+- char type, disabled; /* type=normal/mapped, disabled=boolean */
+- awe_voice_list *next; /* linked list with same sf_id */
+- awe_voice_list *next_instr; /* instrument list */
+- awe_voice_list *next_bank; /* hash table list */
+-};
+-
+-/* voice list type */
+-#define V_ST_NORMAL 0
+-#define V_ST_MAPPED 1
+-
+-/* sample list */
+-struct _awe_sample_list {
+- awe_sample_info v; /* sample information */
+- sf_list *holder; /* parent sf_list of this record */
+- awe_sample_list *next; /* linked list with same sf_id */
+-};
+-
+-/* sample and information table */
+-static int current_sf_id; /* current number of fonts */
+-static int locked_sf_id; /* locked position */
+-static sf_list *sfhead, *sftail; /* linked-lists */
+-
+-#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)
+-#define awe_free_info() (sftail ? sftail->num_info : 0)
+-#define awe_free_sample() (sftail ? sftail->num_sample : 0)
+-
+-#define AWE_MAX_PRESETS 256
+-#define AWE_DEFAULT_PRESET 0
+-#define AWE_DEFAULT_BANK 0
+-#define AWE_DEFAULT_DRUM 0
+-#define AWE_DRUM_BANK 128
+-
+-#define MAX_LAYERS AWE_MAX_VOICES
+-
+-/* preset table index */
+-static awe_voice_list *preset_table[AWE_MAX_PRESETS];
+-
+-/*
+- * voice table
+- */
+-
+-/* effects table */
+-typedef struct FX_Rec { /* channel effects */
+- unsigned char flags[AWE_FX_END];
+- short val[AWE_FX_END];
+-} FX_Rec;
+-
+-
+-/* channel parameters */
+-typedef struct _awe_chan_info {
+- int channel; /* channel number */
+- int bank; /* current tone bank */
+- int instr; /* current program */
+- int bender; /* midi pitchbend (-8192 - 8192) */
+- int bender_range; /* midi bender range (x100) */
+- int panning; /* panning (0-127) */
+- int main_vol; /* channel volume (0-127) */
+- int expression_vol; /* midi expression (0-127) */
+- int chan_press; /* channel pressure */
+- int sustained; /* sustain status in MIDI */
+- FX_Rec fx; /* effects */
+- FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
+-} awe_chan_info;
+-
+-/* voice parameters */
+-typedef struct _voice_info {
+- int state;
+-#define AWE_ST_OFF (1<<0) /* no sound */
+-#define AWE_ST_ON (1<<1) /* playing */
+-#define AWE_ST_STANDBY (1<<2) /* stand by for playing */
+-#define AWE_ST_SUSTAINED (1<<3) /* sustained */
+-#define AWE_ST_MARK (1<<4) /* marked for allocation */
+-#define AWE_ST_DRAM (1<<5) /* DRAM read/write */
+-#define AWE_ST_FM (1<<6) /* reserved for FM */
+-#define AWE_ST_RELEASED (1<<7) /* released */
+-
+- int ch; /* midi channel */
+- int key; /* internal key for search */
+- int layer; /* layer number (for channel mode only) */
+- int time; /* allocated time */
+- awe_chan_info *cinfo; /* channel info */
+-
+- int note; /* midi key (0-127) */
+- int velocity; /* midi velocity (0-127) */
+- int sostenuto; /* sostenuto on/off */
+- awe_voice_info *sample; /* assigned voice */
+-
+- /* EMU8000 parameters */
+- int apitch; /* pitch parameter */
+- int avol; /* volume parameter */
+- int apan; /* panning parameter */
+- int acutoff; /* cutoff parameter */
+- short aaux; /* aux word */
+-} voice_info;
+-
+-/* voice information */
+-static voice_info voices[AWE_MAX_VOICES];
+-
+-#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
+-#define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON)
+-#define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
+-#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
+-
+-
+-/* MIDI channel effects information (for hw control) */
+-static awe_chan_info channels[AWE_MAX_CHANNELS];
+-
+-
+-/*
+- * global variables
+- */
+-
+-#ifndef AWE_DEFAULT_BASE_ADDR
+-#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */
+-#endif
+-
+-#ifndef AWE_DEFAULT_MEM_SIZE
+-#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */
+-#endif
+-
+-static int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
+-static int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
+-#ifdef CONFIG_PNP
+-static int isapnp = -1;
+-#else
+-static int isapnp;
+-#endif
+-
+-MODULE_AUTHOR("Takashi Iwai <iwai at ww.uni-erlangen.de>");
+-MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "base i/o port of Emu8000");
+-module_param(memsize, int, 0);
+-MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
+-module_param(isapnp, bool, 0);
+-MODULE_PARM_DESC(isapnp, "use ISAPnP detection");
+-
+-/* DRAM start offset */
+-static int awe_mem_start = AWE_DRAM_OFFSET;
+-
+-/* maximum channels for playing */
+-static int awe_max_voices = AWE_MAX_VOICES;
+-
+-static int patch_opened; /* sample already loaded? */
+-
+-static char atten_relative = FALSE;
+-static short atten_offset;
+-
+-static int awe_present = FALSE; /* awe device present? */
+-static int awe_busy = FALSE; /* awe device opened? */
+-
+-static int my_dev = -1;
+-
+-#define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25))
+-#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c)))
+-#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c)))
+-#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c)))
+-static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
+-
+-static int playing_mode = AWE_PLAY_INDIRECT;
+-#define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)
+-#define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)
+-
+-static int current_alloc_time; /* voice allocation index for channel mode */
+-
+-static struct synth_info awe_info = {
+- "AWE32 Synth", /* name */
+- 0, /* device */
+- SYNTH_TYPE_SAMPLE, /* synth_type */
+- SAMPLE_TYPE_AWE32, /* synth_subtype */
+- 0, /* perc_mode (obsolete) */
+- AWE_MAX_VOICES, /* nr_voices */
+- 0, /* nr_drums (obsolete) */
+- 400 /* instr_bank_size */
+-};
+-
+-
+-static struct voice_alloc_info *voice_alloc; /* set at initialization */
+-
+-
+-/*
+- * function prototypes
+- */
+-
+-static int awe_request_region(void);
+-static void awe_release_region(void);
+-
+-static void awe_reset_samples(void);
+-/* emu8000 chip i/o access */
+-static void setup_ports(int p1, int p2, int p3);
+-static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
+-static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);
+-static unsigned short awe_peek(unsigned short cmd, unsigned short port);
+-static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);
+-static void awe_wait(unsigned short delay);
+-
+-/* initialize emu8000 chip */
+-static void awe_initialize(void);
+-
+-/* set voice parameters */
+-static void awe_init_ctrl_parms(int init_all);
+-static void awe_init_voice_info(awe_voice_info *vp);
+-static void awe_init_voice_parm(awe_voice_parm *pp);
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-static int freq_to_note(int freq);
+-static int calc_rate_offset(int Hz);
+-/*static int calc_parm_delay(int msec);*/
+-static int calc_parm_hold(int msec);
+-static int calc_parm_attack(int msec);
+-static int calc_parm_decay(int msec);
+-static int calc_parm_search(int msec, short *table);
+-#endif /* gus compat */
+-
+-/* turn on/off note */
+-static void awe_note_on(int voice);
+-static void awe_note_off(int voice);
+-static void awe_terminate(int voice);
+-static void awe_exclusive_off(int voice);
+-static void awe_note_off_all(int do_sustain);
+-
+-/* calculate voice parameters */
+-typedef void (*fx_affect_func)(int voice, int forced);
+-static void awe_set_pitch(int voice, int forced);
+-static void awe_set_voice_pitch(int voice, int forced);
+-static void awe_set_volume(int voice, int forced);
+-static void awe_set_voice_vol(int voice, int forced);
+-static void awe_set_pan(int voice, int forced);
+-static void awe_fx_fmmod(int voice, int forced);
+-static void awe_fx_tremfrq(int voice, int forced);
+-static void awe_fx_fm2frq2(int voice, int forced);
+-static void awe_fx_filterQ(int voice, int forced);
+-static void awe_calc_pitch(int voice);
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-static void awe_calc_pitch_from_freq(int voice, int freq);
+-#endif
+-static void awe_calc_volume(int voice);
+-static void awe_update_volume(void);
+-static void awe_change_master_volume(short val);
+-static void awe_voice_init(int voice, int init_all);
+-static void awe_channel_init(int ch, int init_all);
+-static void awe_fx_init(int ch);
+-static void awe_send_effect(int voice, int layer, int type, int val);
+-static void awe_modwheel_change(int voice, int value);
+-
+-/* sequencer interface */
+-static int awe_open(int dev, int mode);
+-static void awe_close(int dev);
+-static int awe_ioctl(int dev, unsigned int cmd, void __user * arg);
+-static int awe_kill_note(int dev, int voice, int note, int velocity);
+-static int awe_start_note(int dev, int v, int note_num, int volume);
+-static int awe_set_instr(int dev, int voice, int instr_no);
+-static int awe_set_instr_2(int dev, int voice, int instr_no);
+-static void awe_reset(int dev);
+-static void awe_hw_control(int dev, unsigned char *event);
+-static int awe_load_patch(int dev, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag);
+-static void awe_aftertouch(int dev, int voice, int pressure);
+-static void awe_controller(int dev, int voice, int ctrl_num, int value);
+-static void awe_panning(int dev, int voice, int value);
+-static void awe_volume_method(int dev, int mode);
+-static void awe_bender(int dev, int voice, int value);
+-static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
+-static void awe_setup_voice(int dev, int voice, int chn);
+-
+-#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)
+-
+-/* hardware controls */
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
+-#endif
+-static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
+-static void awe_voice_change(int voice, fx_affect_func func);
+-static void awe_sostenuto_on(int voice, int forced);
+-static void awe_sustain_off(int voice, int forced);
+-static void awe_terminate_and_init(int voice, int forced);
+-
+-/* voice search */
+-static int awe_search_key(int bank, int preset, int note);
+-static awe_voice_list *awe_search_instr(int bank, int preset, int note);
+-static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);
+-static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
+-static void awe_alloc_one_voice(int voice, int note, int velocity);
+-static int awe_clear_voice(void);
+-
+-/* load / remove patches */
+-static int awe_open_patch(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_close_patch(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_load_info(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_remove_info(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_load_data(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_replace_data(awe_patch_info *patch, const char __user *addr, int count);
+-static int awe_load_map(awe_patch_info *patch, const char __user *addr, int count);
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-static int awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag);
+-#endif
+-/*static int awe_probe_info(awe_patch_info *patch, const char __user *addr, int count);*/
+-static int awe_probe_data(awe_patch_info *patch, const char __user *addr, int count);
+-static sf_list *check_patch_opened(int type, char *name);
+-static int awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *sp, int channels);
+-static int awe_create_sf(int type, char *name);
+-static void awe_free_sf(sf_list *sf);
+-static void add_sf_info(sf_list *sf, awe_voice_list *rec);
+-static void add_sf_sample(sf_list *sf, awe_sample_list *smp);
+-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);
+-static void add_info_list(awe_voice_list *rec);
+-static void awe_remove_samples(int sf_id);
+-static void rebuild_preset_list(void);
+-static short awe_set_sample(awe_voice_list *rec);
+-static awe_sample_list *search_sample_index(sf_list *sf, int sample);
+-
+-static int is_identical_holder(sf_list *sf1, sf_list *sf2);
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+-static int is_identical_name(unsigned char *name, sf_list *p);
+-static int is_shared_sf(unsigned char *name);
+-static int info_duplicated(sf_list *sf, awe_voice_list *rec);
+-#endif /* allow sharing */
+-
+-/* lowlevel functions */
+-static void awe_init_audio(void);
+-static void awe_init_dma(void);
+-static void awe_init_array(void);
+-static void awe_send_array(unsigned short *data);
+-static void awe_tweak_voice(int voice);
+-static void awe_tweak(void);
+-static void awe_init_fm(void);
+-static int awe_open_dram_for_write(int offset, int channels);
+-static void awe_open_dram_for_check(void);
+-static void awe_close_dram(void);
+-/*static void awe_write_dram(unsigned short c);*/
+-static int awe_detect_base(int addr);
+-static int awe_detect(void);
+-static void awe_check_dram(void);
+-static int awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count);
+-static void awe_set_chorus_mode(int mode);
+-static void awe_update_chorus_mode(void);
+-static int awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count);
+-static void awe_set_reverb_mode(int mode);
+-static void awe_update_reverb_mode(void);
+-static void awe_equalizer(int bass, int treble);
+-static void awe_update_equalizer(void);
+-
+-#ifdef CONFIG_AWE32_MIXER
+-static void attach_mixer(void);
+-static void unload_mixer(void);
+-#endif
+-
+-#ifdef CONFIG_AWE32_MIDIEMU
+-static void attach_midiemu(void);
+-static void unload_midiemu(void);
+-#endif
+-
+-#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
+-
+-/*
+- * control parameters
+- */
+-
+-
+-#ifdef AWE_USE_NEW_VOLUME_CALC
+-#define DEF_VOLUME_CALC TRUE
+-#else
+-#define DEF_VOLUME_CALC FALSE
+-#endif /* new volume */
+-
+-#define DEF_ZERO_ATTEN 32 /* 12dB below */
+-#define DEF_MOD_SENSE 18
+-#define DEF_CHORUS_MODE 2
+-#define DEF_REVERB_MODE 4
+-#define DEF_BASS_LEVEL 5
+-#define DEF_TREBLE_LEVEL 9
+-
+-static struct CtrlParmsDef {
+- int value;
+- int init_each_time;
+- void (*update)(void);
+-} ctrl_parms[AWE_MD_END] = {
+- {0,0, NULL}, {0,0, NULL}, /* <-- not used */
+- {AWE_VERSION_NUMBER, FALSE, NULL},
+- {TRUE, FALSE, NULL}, /* exclusive */
+- {TRUE, FALSE, NULL}, /* realpan */
+- {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */
+- {FALSE, TRUE, NULL}, /* keep effect */
+- {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */
+- {FALSE, FALSE, NULL}, /* chn_prior */
+- {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */
+- {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */
+- {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */
+- {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */
+- {FALSE, FALSE, NULL}, /* toggle_drum_bank */
+- {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */
+- {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */
+- {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */
+- {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */
+- {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */
+- {0, FALSE, NULL}, /* debug mode */
+- {FALSE, FALSE, NULL}, /* pan exchange */
+-};
+-
+-static int ctrls[AWE_MD_END];
+-
+-
+-/*
+- * synth operation table
+- */
+-
+-static struct synth_operations awe_operations =
+-{
+- .owner = THIS_MODULE,
+- .id = "EMU8K",
+- .info = &awe_info,
+- .midi_dev = 0,
+- .synth_type = SYNTH_TYPE_SAMPLE,
+- .synth_subtype = SAMPLE_TYPE_AWE32,
+- .open = awe_open,
+- .close = awe_close,
+- .ioctl = awe_ioctl,
+- .kill_note = awe_kill_note,
+- .start_note = awe_start_note,
+- .set_instr = awe_set_instr_2,
+- .reset = awe_reset,
+- .hw_control = awe_hw_control,
+- .load_patch = awe_load_patch,
+- .aftertouch = awe_aftertouch,
+- .controller = awe_controller,
+- .panning = awe_panning,
+- .volume_method = awe_volume_method,
+- .bender = awe_bender,
+- .alloc_voice = awe_alloc,
+- .setup_voice = awe_setup_voice
+-};
+-
+-static void free_tables(void)
+-{
+- if (sftail) {
+- sf_list *p, *prev;
+- for (p = sftail; p; p = prev) {
+- prev = p->prev;
+- awe_free_sf(p);
+- }
+- }
+- sfhead = sftail = NULL;
+-}
+-
+-/*
+- * clear sample tables
+- */
+-
+-static void
+-awe_reset_samples(void)
+-{
+- /* free all bank tables */
+- memset(preset_table, 0, sizeof(preset_table));
+- free_tables();
+-
+- current_sf_id = 0;
+- locked_sf_id = 0;
+- patch_opened = 0;
+-}
+-
+-
+-/*
+- * EMU register access
+- */
+-
+-/* select a given AWE32 pointer */
+-static int awe_ports[5];
+-static int port_setuped = FALSE;
+-static int awe_cur_cmd = -1;
+-#define awe_set_cmd(cmd) \
+-if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
+-
+-/* write 16bit data */
+-static void
+-awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
+-{
+- awe_set_cmd(cmd);
+- outw(data, awe_ports[port]);
+-}
+-
+-/* write 32bit data */
+-static void
+-awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
+-{
+- unsigned short addr = awe_ports[port];
+- awe_set_cmd(cmd);
+- outw(data, addr); /* write lower 16 bits */
+- outw(data >> 16, addr + 2); /* write higher 16 bits */
+-}
+-
+-/* read 16bit data */
+-static unsigned short
+-awe_peek(unsigned short cmd, unsigned short port)
+-{
+- unsigned short k;
+- awe_set_cmd(cmd);
+- k = inw(awe_ports[port]);
+- return k;
+-}
+-
+-/* read 32bit data */
+-static unsigned int
+-awe_peek_dw(unsigned short cmd, unsigned short port)
+-{
+- unsigned int k1, k2;
+- unsigned short addr = awe_ports[port];
+- awe_set_cmd(cmd);
+- k1 = inw(addr);
+- k2 = inw(addr + 2);
+- k1 |= k2 << 16;
+- return k1;
+-}
+-
+-/* wait delay number of AWE32 44100Hz clocks */
+-#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */
+-static void
+-awe_wait(unsigned short delay)
+-{
+- unsigned short clock, target;
+- unsigned short port = awe_ports[AWE_WC_Port];
+- int counter;
+-
+- /* sample counter */
+- awe_set_cmd(AWE_WC_Cmd);
+- clock = (unsigned short)inw(port);
+- target = clock + delay;
+- counter = 0;
+- if (target < clock) {
+- for (; (unsigned short)inw(port) > target; counter++)
+- if (counter > 65536)
+- break;
+- }
+- for (; (unsigned short)inw(port) < target; counter++)
+- if (counter > 65536)
+- break;
+-}
+-#else
+-
+-static void awe_wait(unsigned short delay)
+-{
+- current->state = TASK_INTERRUPTIBLE;
+- schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
+-}
+-/*
+-static void awe_wait(unsigned short delay)
+-{
+- udelay(((unsigned long)delay * 1000000L + 44099) / 44100);
+-}
+-*/
+-#endif /* wait by loop */
+-
+-/* write a word data */
+-#define awe_write_dram(c) awe_poke(AWE_SMLD, c)
+-
+-/*
+- * AWE32 voice parameters
+- */
+-
+-/* initialize voice_info record */
+-static void
+-awe_init_voice_info(awe_voice_info *vp)
+-{
+- vp->sample = 0;
+- vp->rate_offset = 0;
+-
+- vp->start = 0;
+- vp->end = 0;
+- vp->loopstart = 0;
+- vp->loopend = 0;
+- vp->mode = 0;
+- vp->root = 60;
+- vp->tune = 0;
+- vp->low = 0;
+- vp->high = 127;
+- vp->vellow = 0;
+- vp->velhigh = 127;
+-
+- vp->fixkey = -1;
+- vp->fixvel = -1;
+- vp->fixpan = -1;
+- vp->pan = -1;
+-
+- vp->exclusiveClass = 0;
+- vp->amplitude = 127;
+- vp->attenuation = 0;
+- vp->scaleTuning = 100;
+-
+- awe_init_voice_parm(&vp->parm);
+-}
+-
+-/* initialize voice_parm record:
+- * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
+- * Vibrato and Tremolo effects are zero.
+- * Cutoff is maximum.
+- * Chorus and Reverb effects are zero.
+- */
+-static void
+-awe_init_voice_parm(awe_voice_parm *pp)
+-{
+- pp->moddelay = 0x8000;
+- pp->modatkhld = 0x7f7f;
+- pp->moddcysus = 0x7f7f;
+- pp->modrelease = 0x807f;
+- pp->modkeyhold = 0;
+- pp->modkeydecay = 0;
+-
+- pp->voldelay = 0x8000;
+- pp->volatkhld = 0x7f7f;
+- pp->voldcysus = 0x7f7f;
+- pp->volrelease = 0x807f;
+- pp->volkeyhold = 0;
+- pp->volkeydecay = 0;
+-
+- pp->lfo1delay = 0x8000;
+- pp->lfo2delay = 0x8000;
+- pp->pefe = 0;
+-
+- pp->fmmod = 0;
+- pp->tremfrq = 0;
+- pp->fm2frq2 = 0;
+-
+- pp->cutoff = 0xff;
+- pp->filterQ = 0;
+-
+- pp->chorus = 0;
+- pp->reverb = 0;
+-}
+-
+-
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-
+-/* convert frequency mHz to abstract cents (= midi key * 100) */
+-static int
+-freq_to_note(int mHz)
+-{
+- /* abscents = log(mHz/8176) / log(2) * 1200 */
+- unsigned int max_val = (unsigned int)0xffffffff / 10000;
+- int i, times;
+- unsigned int base;
+- unsigned int freq;
+- int note, tune;
+-
+- if (mHz == 0)
+- return 0;
+- if (mHz < 0)
+- return 12799; /* maximum */
+-
+- freq = mHz;
+- note = 0;
+- for (base = 8176 * 2; freq >= base; base *= 2) {
+- note += 12;
+- if (note >= 128) /* over maximum */
+- return 12799;
+- }
+- base /= 2;
+-
+- /* to avoid overflow... */
+- times = 10000;
+- while (freq > max_val) {
+- max_val *= 10;
+- times /= 10;
+- base /= 10;
+- }
+-
+- freq = freq * times / base;
+- for (i = 0; i < 12; i++) {
+- if (freq < semitone_tuning[i+1])
+- break;
+- note++;
+- }
+-
+- tune = 0;
+- freq = freq * 10000 / semitone_tuning[i];
+- for (i = 0; i < 100; i++) {
+- if (freq < cent_tuning[i+1])
+- break;
+- tune++;
+- }
+-
+- return note * 100 + tune;
+-}
+-
+-
+-/* convert Hz to AWE32 rate offset:
+- * sample pitch offset for the specified sample rate
+- * rate=44100 is no offset, each 4096 is 1 octave (twice).
+- * eg, when rate is 22050, this offset becomes -4096.
+- */
+-static int
+-calc_rate_offset(int Hz)
+-{
+- /* offset = log(Hz / 44100) / log(2) * 4096 */
+- int freq, base, i;
+-
+- /* maybe smaller than max (44100Hz) */
+- if (Hz <= 0 || Hz >= 44100) return 0;
+-
+- base = 0;
+- for (freq = Hz * 2; freq < 44100; freq *= 2)
+- base++;
+- base *= 1200;
+-
+- freq = 44100 * 10000 / (freq/2);
+- for (i = 0; i < 12; i++) {
+- if (freq < semitone_tuning[i+1])
+- break;
+- base += 100;
+- }
+- freq = freq * 10000 / semitone_tuning[i];
+- for (i = 0; i < 100; i++) {
+- if (freq < cent_tuning[i+1])
+- break;
+- base++;
+- }
+- return -base * 4096 / 1200;
+-}
+-
+-
+-/*
+- * convert envelope time parameter to AWE32 raw parameter
+- */
+-
+-/* attack & decay/release time table (msec) */
+-static short attack_time_tbl[128] = {
+-32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
+-707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
+-361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
+-180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
+-90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
+-45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
+-22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
+-11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
+-};
+-
+-static short decay_time_tbl[128] = {
+-32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
+-2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
+-1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
+-691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
+-345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
+-172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
+-86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
+-43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
+-};
+-
+-#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725);
+-
+-/* delay time = 0x8000 - msec/92 */
+-static int
+-calc_parm_hold(int msec)
+-{
+- int val = (0x7f * 92 - msec) / 92;
+- if (val < 1) val = 1;
+- if (val > 127) val = 127;
+- return val;
+-}
+-
+-/* attack time: search from time table */
+-static int
+-calc_parm_attack(int msec)
+-{
+- return calc_parm_search(msec, attack_time_tbl);
+-}
+-
+-/* decay/release time: search from time table */
+-static int
+-calc_parm_decay(int msec)
+-{
+- return calc_parm_search(msec, decay_time_tbl);
+-}
+-
+-/* search an index for specified time from given time table */
+-static int
+-calc_parm_search(int msec, short *table)
+-{
+- int left = 1, right = 127, mid;
+- while (left < right) {
+- mid = (left + right) / 2;
+- if (msec < (int)table[mid])
+- left = mid + 1;
+- else
+- right = mid;
+- }
+- return left;
+-}
+-#endif /* AWE_HAS_GUS_COMPATIBILITY */
+-
+-
+-/*
+- * effects table
+- */
+-
+-/* set an effect value */
+-#define FX_FLAG_OFF 0
+-#define FX_FLAG_SET 1
+-#define FX_FLAG_ADD 2
+-
+-#define FX_SET(rec,type,value) \
+- ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
+-#define FX_ADD(rec,type,value) \
+- ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
+-#define FX_UNSET(rec,type) \
+- ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
+-
+-/* check the effect value is set */
+-#define FX_ON(rec,type) ((rec)->flags[type])
+-
+-#define PARM_BYTE 0
+-#define PARM_WORD 1
+-#define PARM_SIGN 2
+-
+-static struct PARM_DEFS {
+- int type; /* byte or word */
+- int low, high; /* value range */
+- fx_affect_func realtime; /* realtime paramater change */
+-} parm_defs[] = {
+- {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */
+- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */
+- {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */
+- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */
+- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */
+- {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */
+- {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */
+- {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */
+-
+- {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */
+- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */
+- {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */
+- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */
+- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */
+- {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */
+-
+- {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */
+- {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */
+- {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */
+- {PARM_SIGN, -128, 127, awe_fx_fmmod}, /* lfo1 pitch */
+- {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff */
+-
+- {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */
+- {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */
+- {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */
+-
+- {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */
+- {PARM_BYTE, 0, 0xff, NULL}, /* chorus */
+- {PARM_BYTE, 0, 0xff, NULL}, /* reverb */
+- {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */
+- {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */
+-
+- {PARM_WORD, 0, 0xffff, NULL}, /* sample start */
+- {PARM_WORD, 0, 0xffff, NULL}, /* loop start */
+- {PARM_WORD, 0, 0xffff, NULL}, /* loop end */
+- {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */
+- {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */
+- {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */
+- {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */
+-};
+-
+-
+-static unsigned char
+-FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
+-{
+- int effect = 0;
+- int on = 0;
+- if (lay && (on = FX_ON(lay, type)) != 0)
+- effect = lay->val[type];
+- if (!on && (on = FX_ON(rec, type)) != 0)
+- effect = rec->val[type];
+- if (on == FX_FLAG_ADD) {
+- if (parm_defs[type].type == PARM_SIGN) {
+- if (value > 0x7f)
+- effect += (int)value - 0x100;
+- else
+- effect += (int)value;
+- } else {
+- effect += (int)value;
+- }
+- }
+- if (on) {
+- if (effect < parm_defs[type].low)
+- effect = parm_defs[type].low;
+- else if (effect > parm_defs[type].high)
+- effect = parm_defs[type].high;
+- return (unsigned char)effect;
+- }
+- return value;
+-}
+-
+-/* get word effect value */
+-static unsigned short
+-FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value)
+-{
+- int effect = 0;
+- int on = 0;
+- if (lay && (on = FX_ON(lay, type)) != 0)
+- effect = lay->val[type];
+- if (!on && (on = FX_ON(rec, type)) != 0)
+- effect = rec->val[type];
+- if (on == FX_FLAG_ADD)
+- effect += (int)value;
+- if (on) {
+- if (effect < parm_defs[type].low)
+- effect = parm_defs[type].low;
+- else if (effect > parm_defs[type].high)
+- effect = parm_defs[type].high;
+- return (unsigned short)effect;
+- }
+- return value;
+-}
+-
+-/* get word (upper=type1/lower=type2) effect value */
+-static unsigned short
+-FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value)
+-{
+- unsigned short tmp;
+- tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8));
+- tmp <<= 8;
+- tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff));
+- return tmp;
+-}
+-
+-/* address offset */
+-static int
+-FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
+-{
+- int addr = 0;
+- if (lay && FX_ON(lay, hi))
+- addr = (short)lay->val[hi];
+- else if (FX_ON(rec, hi))
+- addr = (short)rec->val[hi];
+- addr = addr << 15;
+- if (lay && FX_ON(lay, lo))
+- addr += (short)lay->val[lo];
+- else if (FX_ON(rec, lo))
+- addr += (short)rec->val[lo];
+- if (!(mode & AWE_SAMPLE_8BITS))
+- addr /= 2;
+- return addr;
+-}
+-
+-
+-/*
+- * turn on/off sample
+- */
+-
+-/* table for volume target calculation */
+-static unsigned short voltarget[16] = {
+- 0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58,
+- 0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90
+-};
+-
+-static void
+-awe_note_on(int voice)
+-{
+- unsigned int temp;
+- int addr;
+- int vtarget, ftarget, ptarget, pitch;
+- awe_voice_info *vp;
+- awe_voice_parm_block *parm;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- /* A voice sample must assigned before calling */
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+-
+- parm = (awe_voice_parm_block*)&vp->parm;
+-
+- /* channel to be silent and idle */
+- awe_poke(AWE_DCYSUSV(voice), 0x0080);
+- awe_poke(AWE_VTFT(voice), 0x0000FFFF);
+- awe_poke(AWE_CVCF(voice), 0x0000FFFF);
+- awe_poke(AWE_PTRX(voice), 0);
+- awe_poke(AWE_CPF(voice), 0);
+-
+- /* set pitch offset */
+- awe_set_pitch(voice, TRUE);
+-
+- /* modulation & volume envelope */
+- if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) {
+- awe_poke(AWE_ENVVAL(voice), 0xBFFF);
+- pitch = (parm->env1pit<<4) + voices[voice].apitch;
+- if (pitch > 0xffff) pitch = 0xffff;
+- /* calculate filter target */
+- ftarget = parm->cutoff + parm->env1fc;
+- limitvalue(ftarget, 0, 255);
+- ftarget <<= 8;
+- } else {
+- awe_poke(AWE_ENVVAL(voice),
+- FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay));
+- ftarget = parm->cutoff;
+- ftarget <<= 8;
+- pitch = voices[voice].apitch;
+- }
+-
+- /* calcualte pitch target */
+- if (pitch != 0xffff) {
+- ptarget = 1 << (pitch >> 12);
+- if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710;
+- if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710;
+- if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710;
+- ptarget += (ptarget>>1);
+- if (ptarget > 0xffff) ptarget = 0xffff;
+-
+- } else ptarget = 0xffff;
+- if (parm->modatk >= 0x80)
+- awe_poke(AWE_ATKHLD(voice),
+- FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f);
+- else
+- awe_poke(AWE_ATKHLD(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK,
+- vp->parm.modatkhld));
+- awe_poke(AWE_DCYSUS(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
+- vp->parm.moddcysus));
+-
+- if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) {
+- awe_poke(AWE_ENVVOL(voice), 0xBFFF);
+- vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4);
+- } else {
+- awe_poke(AWE_ENVVOL(voice),
+- FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
+- vtarget = 0;
+- }
+- if (parm->volatk >= 0x80)
+- awe_poke(AWE_ATKHLDV(voice),
+- FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f);
+- else
+- awe_poke(AWE_ATKHLDV(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK,
+- vp->parm.volatkhld));
+- /* decay/sustain parameter for volume envelope must be set at last */
+-
+- /* cutoff and volume */
+- awe_set_volume(voice, TRUE);
+-
+- /* modulation envelope heights */
+- awe_poke(AWE_PEFE(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
+- vp->parm.pefe));
+-
+- /* lfo1/2 delay */
+- awe_poke(AWE_LFO1VAL(voice),
+- FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
+- awe_poke(AWE_LFO2VAL(voice),
+- FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
+-
+- /* lfo1 pitch & cutoff shift */
+- awe_fx_fmmod(voice, TRUE);
+- /* lfo1 volume & freq */
+- awe_fx_tremfrq(voice, TRUE);
+- /* lfo2 pitch & freq */
+- awe_fx_fm2frq2(voice, TRUE);
+- /* pan & loop start */
+- awe_set_pan(voice, TRUE);
+-
+- /* chorus & loop end (chorus 8bit, MSB) */
+- addr = vp->loopend - 1;
+- addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END,
+- AWE_FX_COARSE_LOOP_END, vp->mode);
+- temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus);
+- temp = (temp <<24) | (unsigned int)addr;
+- awe_poke_dw(AWE_CSL(voice), temp);
+- DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr));
+-
+- /* Q & current address (Q 4bit value, MSB) */
+- addr = vp->start - 1;
+- addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START,
+- AWE_FX_COARSE_SAMPLE_START, vp->mode);
+- temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ);
+- temp = (temp<<28) | (unsigned int)addr;
+- awe_poke_dw(AWE_CCCA(voice), temp);
+- DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr));
+-
+- /* clear unknown registers */
+- awe_poke_dw(AWE_00A0(voice), 0);
+- awe_poke_dw(AWE_0080(voice), 0);
+-
+- /* reset volume */
+- awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
+- awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
+-
+- /* set reverb */
+- temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
+- temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
+- awe_poke_dw(AWE_PTRX(voice), temp);
+- awe_poke_dw(AWE_CPF(voice), ptarget << 16);
+- /* turn on envelope */
+- awe_poke(AWE_DCYSUSV(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
+- vp->parm.voldcysus));
+-
+- voices[voice].state = AWE_ST_ON;
+-
+- /* clear voice position for the next note on this channel */
+- if (SINGLE_LAYER_MODE()) {
+- FX_UNSET(fx, AWE_FX_SAMPLE_START);
+- FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
+- }
+-}
+-
+-
+-/* turn off the voice */
+-static void
+-awe_note_off(int voice)
+-{
+- awe_voice_info *vp;
+- unsigned short tmp;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if ((vp = voices[voice].sample) == NULL) {
+- voices[voice].state = AWE_ST_OFF;
+- return;
+- }
+-
+- tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE,
+- (unsigned char)vp->parm.modrelease);
+- awe_poke(AWE_DCYSUS(voice), tmp);
+- tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
+- (unsigned char)vp->parm.volrelease);
+- awe_poke(AWE_DCYSUSV(voice), tmp);
+- voices[voice].state = AWE_ST_RELEASED;
+-}
+-
+-/* force to terminate the voice (no releasing echo) */
+-static void
+-awe_terminate(int voice)
+-{
+- awe_poke(AWE_DCYSUSV(voice), 0x807F);
+- awe_tweak_voice(voice);
+- voices[voice].state = AWE_ST_OFF;
+-}
+-
+-/* turn off other voices with the same exclusive class (for drums) */
+-static void
+-awe_exclusive_off(int voice)
+-{
+- int i, exclass;
+-
+- if (voices[voice].sample == NULL)
+- return;
+- if ((exclass = voices[voice].sample->exclusiveClass) == 0)
+- return; /* not exclusive */
+-
+- /* turn off voices with the same class */
+- for (i = 0; i < awe_max_voices; i++) {
+- if (i != voice && IS_PLAYING(i) &&
+- voices[i].sample && voices[i].ch == voices[voice].ch &&
+- voices[i].sample->exclusiveClass == exclass) {
+- DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
+- awe_terminate(i);
+- awe_voice_init(i, TRUE);
+- }
+- }
+-}
+-
+-
+-/*
+- * change the parameters of an audible voice
+- */
+-
+-/* change pitch */
+-static void
+-awe_set_pitch(int voice, int forced)
+-{
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- awe_poke(AWE_IP(voice), voices[voice].apitch);
+- DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
+-}
+-
+-/* calculate & change pitch */
+-static void
+-awe_set_voice_pitch(int voice, int forced)
+-{
+- awe_calc_pitch(voice);
+- awe_set_pitch(voice, forced);
+-}
+-
+-/* change volume & cutoff */
+-static void
+-awe_set_volume(int voice, int forced)
+-{
+- awe_voice_info *vp;
+- unsigned short tmp2;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if (!IS_PLAYING(voice) && !forced) return;
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+-
+- tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
+- (unsigned char)voices[voice].acutoff);
+- tmp2 = (tmp2 << 8);
+- tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN,
+- (unsigned char)voices[voice].avol);
+- awe_poke(AWE_IFATN(voice), tmp2);
+-}
+-
+-/* calculate & change volume */
+-static void
+-awe_set_voice_vol(int voice, int forced)
+-{
+- if (IS_EMPTY(voice))
+- return;
+- awe_calc_volume(voice);
+- awe_set_volume(voice, forced);
+-}
+-
+-
+-/* change pan; this could make a click noise.. */
+-static void
+-awe_set_pan(int voice, int forced)
+-{
+- unsigned int temp;
+- int addr;
+- awe_voice_info *vp;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+-
+- /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
+- if (vp->fixpan > 0) /* 0-127 */
+- temp = 255 - (int)vp->fixpan * 2;
+- else {
+- int pos = 0;
+- if (vp->pan >= 0) /* 0-127 */
+- pos = (int)vp->pan * 2 - 128;
+- pos += voices[voice].cinfo->panning; /* -128 - 127 */
+- temp = 127 - pos;
+- }
+- limitvalue(temp, 0, 255);
+- if (ctrls[AWE_MD_PAN_EXCHANGE]) {
+- temp = 255 - temp;
+- }
+- if (forced || temp != voices[voice].apan) {
+- voices[voice].apan = temp;
+- if (temp == 0)
+- voices[voice].aaux = 0xff;
+- else
+- voices[voice].aaux = (-temp) & 0xff;
+- addr = vp->loopstart - 1;
+- addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
+- AWE_FX_COARSE_LOOP_START, vp->mode);
+- temp = (temp<<24) | (unsigned int)addr;
+- awe_poke_dw(AWE_PSST(voice), temp);
+- DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
+- }
+-}
+-
+-/* effects change during playing */
+-static void
+-awe_fx_fmmod(int voice, int forced)
+-{
+- awe_voice_info *vp;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+- awe_poke(AWE_FMMOD(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
+- vp->parm.fmmod));
+-}
+-
+-/* set tremolo (lfo1) volume & frequency */
+-static void
+-awe_fx_tremfrq(int voice, int forced)
+-{
+- awe_voice_info *vp;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+- awe_poke(AWE_TREMFRQ(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
+- vp->parm.tremfrq));
+-}
+-
+-/* set lfo2 pitch & frequency */
+-static void
+-awe_fx_fm2frq2(int voice, int forced)
+-{
+- awe_voice_info *vp;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+- awe_poke(AWE_FM2FRQ2(voice),
+- FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
+- vp->parm.fm2frq2));
+-}
+-
+-
+-/* Q & current address (Q 4bit value, MSB) */
+-static void
+-awe_fx_filterQ(int voice, int forced)
+-{
+- unsigned int addr;
+- awe_voice_info *vp;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
+- return;
+-
+- addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
+- addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
+- awe_poke_dw(AWE_CCCA(voice), addr);
+-}
+-
+-/*
+- * calculate pitch offset
+- *
+- * 0xE000 is no pitch offset at 44100Hz sample.
+- * Every 4096 is one octave.
+- */
+-
+-static void
+-awe_calc_pitch(int voice)
+-{
+- voice_info *vp = &voices[voice];
+- awe_voice_info *ap;
+- awe_chan_info *cp = voices[voice].cinfo;
+- int offset;
+-
+- /* search voice information */
+- if ((ap = vp->sample) == NULL)
+- return;
+- if (ap->index == 0) {
+- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
+- if (awe_set_sample((awe_voice_list*)ap) == 0)
+- return;
+- }
+-
+- /* calculate offset */
+- if (ap->fixkey >= 0) {
+- DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
+- offset = (ap->fixkey - ap->root) * 4096 / 12;
+- } else {
+- DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
+- offset = (vp->note - ap->root) * 4096 / 12;
+- DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
+- }
+- offset = (offset * ap->scaleTuning) / 100;
+- DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
+- offset += ap->tune * 4096 / 1200;
+- DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
+- if (cp->bender != 0) {
+- DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender));
+- /* (819200: 1 semitone) ==> (4096: 12 semitones) */
+- offset += cp->bender * cp->bender_range / 2400;
+- }
+-
+- /* add initial pitch correction */
+- if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
+- offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH];
+- else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH))
+- offset += cp->fx.val[AWE_FX_INIT_PITCH];
+-
+- /* 0xe000: root pitch */
+- vp->apitch = 0xe000 + ap->rate_offset + offset;
+- DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
+- if (vp->apitch > 0xffff)
+- vp->apitch = 0xffff;
+- if (vp->apitch < 0)
+- vp->apitch = 0;
+-}
+-
+-
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-/* calculate MIDI key and semitone from the specified frequency */
+-static void
+-awe_calc_pitch_from_freq(int voice, int freq)
+-{
+- voice_info *vp = &voices[voice];
+- awe_voice_info *ap;
+- FX_Rec *fx = &voices[voice].cinfo->fx;
+- FX_Rec *fx_lay = NULL;
+- int offset;
+- int note;
+-
+- if (voices[voice].layer < MAX_LAYERS)
+- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+-
+- /* search voice information */
+- if ((ap = vp->sample) == NULL)
+- return;
+- if (ap->index == 0) {
+- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
+- if (awe_set_sample((awe_voice_list*)ap) == 0)
+- return;
+- }
+- note = freq_to_note(freq);
+- offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
+- offset = (offset * ap->scaleTuning) / 100;
+- if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH))
+- offset += fx_lay->val[AWE_FX_INIT_PITCH];
+- else if (FX_ON(fx, AWE_FX_INIT_PITCH))
+- offset += fx->val[AWE_FX_INIT_PITCH];
+- vp->apitch = 0xe000 + ap->rate_offset + offset;
+- if (vp->apitch > 0xffff)
+- vp->apitch = 0xffff;
+- if (vp->apitch < 0)
+- vp->apitch = 0;
+-}
+-#endif /* AWE_HAS_GUS_COMPATIBILITY */
+-
+-
+-/*
+- * calculate volume attenuation
+- *
+- * Voice volume is controlled by volume attenuation parameter.
+- * So volume becomes maximum when avol is 0 (no attenuation), and
+- * minimum when 255 (-96dB or silence).
+- */
+-
+-static int vol_table[128] = {
+- 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
+- 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
+- 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
+- 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
+- 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
+- 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
+- 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
+- 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
+-};
+-
+-/* tables for volume->attenuation calculation */
+-static unsigned char voltab1[128] = {
+- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+- 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
+- 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
+- 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
+- 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
+- 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
+- 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
+- 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+- 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
+- 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
+- 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
+- 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
+-
+-static unsigned char voltab2[128] = {
+- 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
+- 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
+- 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
+- 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
+- 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
+- 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
+- 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
+- 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
+- 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
+- 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
+- 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
+- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
+-
+-static unsigned char expressiontab[128] = {
+- 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
+- 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
+- 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
+- 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
+- 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
+- 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
+- 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
+- 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
+- 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
+- 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
+- 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
+- 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
+- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
+-
+-static void
+-awe_calc_volume(int voice)
+-{
+- voice_info *vp = &voices[voice];
+- awe_voice_info *ap;
+- awe_chan_info *cp = voices[voice].cinfo;
+- int vol;
+-
+- /* search voice information */
+- if ((ap = vp->sample) == NULL)
+- return;
+-
+- ap = vp->sample;
+- if (ap->index == 0) {
+- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
+- if (awe_set_sample((awe_voice_list*)ap) == 0)
+- return;
+- }
+-
+- if (ctrls[AWE_MD_NEW_VOLUME_CALC]) {
+- int main_vol = cp->main_vol * ap->amplitude / 127;
+- limitvalue(vp->velocity, 0, 127);
+- limitvalue(main_vol, 0, 127);
+- limitvalue(cp->expression_vol, 0, 127);
+-
+- vol = voltab1[main_vol] + voltab2[vp->velocity];
+- vol = (vol * 8) / 3;
+- vol += ap->attenuation;
+- if (cp->expression_vol < 127)
+- vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128;
+- vol += atten_offset;
+- if (atten_relative)
+- vol += ctrls[AWE_MD_ZERO_ATTEN];
+- limitvalue(vol, 0, 255);
+- vp->avol = vol;
+-
+- } else {
+- /* 0 - 127 */
+- vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127);
+- vol = vol * ap->amplitude / 127;
+-
+- if (vol < 0) vol = 0;
+- if (vol > 127) vol = 127;
+-
+- /* calc to attenuation */
+- vol = vol_table[vol];
+- vol += (int)ap->attenuation;
+- vol += atten_offset;
+- if (atten_relative)
+- vol += ctrls[AWE_MD_ZERO_ATTEN];
+- if (vol > 255) vol = 255;
+-
+- vp->avol = vol;
+- }
+- if (cp->bank != AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) {
+- int atten;
+- if (vp->velocity < 70) atten = 70;
+- else atten = vp->velocity;
+- vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7;
+- } else {
+- vp->acutoff = ap->parm.cutoff;
+- }
+- DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
+-}
+-
+-/* change master volume */
+-static void
+-awe_change_master_volume(short val)
+-{
+- limitvalue(val, 0, 127);
+- atten_offset = vol_table[val];
+- atten_relative = TRUE;
+- awe_update_volume();
+-}
+-
+-/* update volumes of all available channels */
+-static void awe_update_volume(void)
+-{
+- int i;
+- for (i = 0; i < awe_max_voices; i++)
+- awe_set_voice_vol(i, TRUE);
+-}
+-
+-/* set sostenuto on */
+-static void awe_sostenuto_on(int voice, int forced)
+-{
+- if (IS_NO_EFFECT(voice) && !forced) return;
+- voices[voice].sostenuto = 127;
+-}
+-
+-
+-/* drop sustain */
+-static void awe_sustain_off(int voice, int forced)
+-{
+- if (voices[voice].state == AWE_ST_SUSTAINED) {
+- awe_note_off(voice);
+- awe_fx_init(voices[voice].ch);
+- awe_voice_init(voice, FALSE);
+- }
+-}
+-
+-
+-/* terminate and initialize voice */
+-static void awe_terminate_and_init(int voice, int forced)
+-{
+- awe_terminate(voice);
+- awe_fx_init(voices[voice].ch);
+- awe_voice_init(voice, TRUE);
+-}
+-
+-
+-/*
+- * synth operation routines
+- */
+-
+-#define AWE_VOICE_KEY(v) (0x8000 | (v))
+-#define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1))
+-#define KEY_CHAN_MATCH(key,c) (((key) >> 8) == (c))
+-
+-/* initialize the voice */
+-static void
+-awe_voice_init(int voice, int init_all)
+-{
+- voice_info *vp = &voices[voice];
+-
+- /* reset voice search key */
+- if (playing_mode == AWE_PLAY_DIRECT)
+- vp->key = AWE_VOICE_KEY(voice);
+- else
+- vp->key = 0;
+-
+- /* clear voice mapping */
+- voice_alloc->map[voice] = 0;
+-
+- /* touch the timing flag */
+- vp->time = current_alloc_time;
+-
+- /* initialize other parameters if necessary */
+- if (init_all) {
+- vp->note = -1;
+- vp->velocity = 0;
+- vp->sostenuto = 0;
+-
+- vp->sample = NULL;
+- vp->cinfo = &channels[voice];
+- vp->ch = voice;
+- vp->state = AWE_ST_OFF;
+-
+- /* emu8000 parameters */
+- vp->apitch = 0;
+- vp->avol = 255;
+- vp->apan = -1;
+- }
+-}
+-
+-/* clear effects */
+-static void awe_fx_init(int ch)
+-{
+- if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
+- memset(&channels[ch].fx, 0, sizeof(channels[ch].fx));
+- memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer));
+- }
+-}
+-
+-/* initialize channel info */
+-static void awe_channel_init(int ch, int init_all)
+-{
+- awe_chan_info *cp = &channels[ch];
+- cp->channel = ch;
+- if (init_all) {
+- cp->panning = 0; /* zero center */
+- cp->bender_range = 200; /* sense * 100 */
+- cp->main_vol = 127;
+- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) {
+- cp->instr = ctrls[AWE_MD_DEF_DRUM];
+- cp->bank = AWE_DRUM_BANK;
+- } else {
+- cp->instr = ctrls[AWE_MD_DEF_PRESET];
+- cp->bank = ctrls[AWE_MD_DEF_BANK];
+- }
+- }
+-
+- cp->bender = 0; /* zero tune skew */
+- cp->expression_vol = 127;
+- cp->chan_press = 0;
+- cp->sustained = 0;
+-
+- if (! ctrls[AWE_MD_KEEP_EFFECT]) {
+- memset(&cp->fx, 0, sizeof(cp->fx));
+- memset(&cp->fx_layer, 0, sizeof(cp->fx_layer));
+- }
+-}
+-
+-
+-/* change the voice parameters; voice = channel */
+-static void awe_voice_change(int voice, fx_affect_func func)
+-{
+- int i;
+- switch (playing_mode) {
+- case AWE_PLAY_DIRECT:
+- func(voice, FALSE);
+- break;
+- case AWE_PLAY_INDIRECT:
+- for (i = 0; i < awe_max_voices; i++)
+- if (voices[i].key == AWE_VOICE_KEY(voice))
+- func(i, FALSE);
+- break;
+- default:
+- for (i = 0; i < awe_max_voices; i++)
+- if (KEY_CHAN_MATCH(voices[i].key, voice))
+- func(i, FALSE);
+- break;
+- }
+-}
+-
+-
+-/*
+- * device open / close
+- */
+-
+-/* open device:
+- * reset status of all voices, and clear sample position flag
+- */
+-static int
+-awe_open(int dev, int mode)
+-{
+- if (awe_busy)
+- return -EBUSY;
+-
+- awe_busy = TRUE;
+-
+- /* set default mode */
+- awe_init_ctrl_parms(FALSE);
+- atten_relative = TRUE;
+- atten_offset = 0;
+- drum_flags = DEFAULT_DRUM_FLAGS;
+- playing_mode = AWE_PLAY_INDIRECT;
+-
+- /* reset voices & channels */
+- awe_reset(dev);
+-
+- patch_opened = 0;
+-
+- return 0;
+-}
+-
+-
+-/* close device:
+- * reset all voices again (terminate sounds)
+- */
+-static void
+-awe_close(int dev)
+-{
+- awe_reset(dev);
+- awe_busy = FALSE;
+-}
+-
+-
+-/* set miscellaneous mode parameters
+- */
+-static void
+-awe_init_ctrl_parms(int init_all)
+-{
+- int i;
+- for (i = 0; i < AWE_MD_END; i++) {
+- if (init_all || ctrl_parms[i].init_each_time)
+- ctrls[i] = ctrl_parms[i].value;
+- }
+-}
+-
+-
+-/* sequencer I/O control:
+- */
+-static int
+-awe_ioctl(int dev, unsigned int cmd, void __user *arg)
+-{
+- switch (cmd) {
+- case SNDCTL_SYNTH_INFO:
+- if (playing_mode == AWE_PLAY_DIRECT)
+- awe_info.nr_voices = awe_max_voices;
+- else
+- awe_info.nr_voices = AWE_MAX_CHANNELS;
+- if (copy_to_user(arg, &awe_info, sizeof(awe_info)))
+- return -EFAULT;
+- return 0;
+- break;
+-
+- case SNDCTL_SEQ_RESETSAMPLES:
+- awe_reset(dev);
+- awe_reset_samples();
+- return 0;
+- break;
+-
+- case SNDCTL_SEQ_PERCMODE:
+- /* what's this? */
+- return 0;
+- break;
+-
+- case SNDCTL_SYNTH_MEMAVL:
+- return memsize - awe_free_mem_ptr() * 2;
+- break;
+-
+- default:
+- printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd);
+- return -EINVAL;
+- break;
+- }
+-}
+-
+-
+-static int voice_in_range(int voice)
+-{
+- if (playing_mode == AWE_PLAY_DIRECT) {
+- if (voice < 0 || voice >= awe_max_voices)
+- return FALSE;
+- } else {
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return FALSE;
+- }
+- return TRUE;
+-}
+-
+-static void release_voice(int voice, int do_sustain)
+-{
+- if (IS_NO_SOUND(voice))
+- return;
+- if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
+- voices[voice].sostenuto == 127))
+- voices[voice].state = AWE_ST_SUSTAINED;
+- else {
+- awe_note_off(voice);
+- awe_fx_init(voices[voice].ch);
+- awe_voice_init(voice, FALSE);
+- }
+-}
+-
+-/* release all notes */
+-static void awe_note_off_all(int do_sustain)
+-{
+- int i;
+- for (i = 0; i < awe_max_voices; i++)
+- release_voice(i, do_sustain);
+-}
+-
+-/* kill a voice:
+- * not terminate, just release the voice.
+- */
+-static int
+-awe_kill_note(int dev, int voice, int note, int velocity)
+-{
+- int i, v2, key;
+-
+- DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
+- if (! voice_in_range(voice))
+- return -EINVAL;
+-
+- switch (playing_mode) {
+- case AWE_PLAY_DIRECT:
+- case AWE_PLAY_INDIRECT:
+- key = AWE_VOICE_KEY(voice);
+- break;
+-
+- case AWE_PLAY_MULTI2:
+- v2 = voice_alloc->map[voice] >> 8;
+- voice_alloc->map[voice] = 0;
+- voice = v2;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return -EINVAL;
+- /* continue to below */
+- default:
+- key = AWE_CHAN_KEY(voice, note);
+- break;
+- }
+-
+- for (i = 0; i < awe_max_voices; i++) {
+- if (voices[i].key == key)
+- release_voice(i, TRUE);
+- }
+- return 0;
+-}
+-
+-
+-static void start_or_volume_change(int voice, int velocity)
+-{
+- voices[voice].velocity = velocity;
+- awe_calc_volume(voice);
+- if (voices[voice].state == AWE_ST_STANDBY)
+- awe_note_on(voice);
+- else if (voices[voice].state == AWE_ST_ON)
+- awe_set_volume(voice, FALSE);
+-}
+-
+-static void set_and_start_voice(int voice, int state)
+-{
+- /* calculate pitch & volume parameters */
+- voices[voice].state = state;
+- awe_calc_pitch(voice);
+- awe_calc_volume(voice);
+- if (state == AWE_ST_ON)
+- awe_note_on(voice);
+-}
+-
+-/* start a voice:
+- * if note is 255, identical with aftertouch function.
+- * Otherwise, start a voice with specified not and volume.
+- */
+-static int
+-awe_start_note(int dev, int voice, int note, int velocity)
+-{
+- int i, key, state, volonly;
+-
+- DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
+- if (! voice_in_range(voice))
+- return -EINVAL;
+-
+- if (velocity == 0)
+- state = AWE_ST_STANDBY; /* stand by for playing */
+- else
+- state = AWE_ST_ON; /* really play */
+- volonly = FALSE;
+-
+- switch (playing_mode) {
+- case AWE_PLAY_DIRECT:
+- case AWE_PLAY_INDIRECT:
+- key = AWE_VOICE_KEY(voice);
+- if (note == 255)
+- volonly = TRUE;
+- break;
+-
+- case AWE_PLAY_MULTI2:
+- voice = voice_alloc->map[voice] >> 8;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return -EINVAL;
+- /* continue to below */
+- default:
+- if (note >= 128) { /* key volume mode */
+- note -= 128;
+- volonly = TRUE;
+- }
+- key = AWE_CHAN_KEY(voice, note);
+- break;
+- }
+-
+- /* dynamic volume change */
+- if (volonly) {
+- for (i = 0; i < awe_max_voices; i++) {
+- if (voices[i].key == key)
+- start_or_volume_change(i, velocity);
+- }
+- return 0;
+- }
+-
+- /* if the same note still playing, stop it */
+- if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) {
+- for (i = 0; i < awe_max_voices; i++)
+- if (voices[i].key == key) {
+- if (voices[i].state == AWE_ST_ON) {
+- awe_note_off(i);
+- awe_voice_init(i, FALSE);
+- } else if (voices[i].state == AWE_ST_STANDBY)
+- awe_voice_init(i, TRUE);
+- }
+- }
+-
+- /* allocate voices */
+- if (playing_mode == AWE_PLAY_DIRECT)
+- awe_alloc_one_voice(voice, note, velocity);
+- else
+- awe_alloc_multi_voices(voice, note, velocity, key);
+-
+- /* turn off other voices exlusively (for drums) */
+- for (i = 0; i < awe_max_voices; i++)
+- if (voices[i].key == key)
+- awe_exclusive_off(i);
+-
+- /* set up pitch and volume parameters */
+- for (i = 0; i < awe_max_voices; i++) {
+- if (voices[i].key == key && voices[i].state == AWE_ST_OFF)
+- set_and_start_voice(i, state);
+- }
+-
+- return 0;
+-}
+-
+-
+-/* calculate hash key */
+-static int
+-awe_search_key(int bank, int preset, int note)
+-{
+- unsigned int key;
+-
+-#if 1 /* new hash table */
+- if (bank == AWE_DRUM_BANK)
+- key = preset + note + 128;
+- else
+- key = bank + preset;
+-#else
+- key = preset;
+-#endif
+- key %= AWE_MAX_PRESETS;
+-
+- return (int)key;
+-}
+-
+-
+-/* search instrument from hash table */
+-static awe_voice_list *
+-awe_search_instr(int bank, int preset, int note)
+-{
+- awe_voice_list *p;
+- int key, key2;
+-
+- key = awe_search_key(bank, preset, note);
+- for (p = preset_table[key]; p; p = p->next_bank) {
+- if (p->instr == preset && p->bank == bank)
+- return p;
+- }
+- key2 = awe_search_key(bank, preset, 0); /* search default */
+- if (key == key2)
+- return NULL;
+- for (p = preset_table[key2]; p; p = p->next_bank) {
+- if (p->instr == preset && p->bank == bank)
+- return p;
+- }
+- return NULL;
+-}
+-
+-
+-/* assign the instrument to a voice */
+-static int
+-awe_set_instr_2(int dev, int voice, int instr_no)
+-{
+- if (playing_mode == AWE_PLAY_MULTI2) {
+- voice = voice_alloc->map[voice] >> 8;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return -EINVAL;
+- }
+- return awe_set_instr(dev, voice, instr_no);
+-}
+-
+-/* assign the instrument to a channel; voice is the channel number */
+-static int
+-awe_set_instr(int dev, int voice, int instr_no)
+-{
+- awe_chan_info *cinfo;
+-
+- if (! voice_in_range(voice))
+- return -EINVAL;
+-
+- if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
+- return -EINVAL;
+-
+- cinfo = &channels[voice];
+- cinfo->instr = instr_no;
+- DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no));
+-
+- return 0;
+-}
+-
+-
+-/* reset all voices; terminate sounds and initialize parameters */
+-static void
+-awe_reset(int dev)
+-{
+- int i;
+- current_alloc_time = 0;
+- /* don't turn off voice 31 and 32. they are used also for FM voices */
+- for (i = 0; i < awe_max_voices; i++) {
+- awe_terminate(i);
+- awe_voice_init(i, TRUE);
+- }
+- for (i = 0; i < AWE_MAX_CHANNELS; i++)
+- awe_channel_init(i, TRUE);
+- for (i = 0; i < 16; i++) {
+- awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127;
+- awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127;
+- }
+- awe_init_fm();
+- awe_tweak();
+-}
+-
+-
+-/* hardware specific control:
+- * GUS specific and AWE32 specific controls are available.
+- */
+-static void
+-awe_hw_control(int dev, unsigned char *event)
+-{
+- int cmd = event[2];
+- if (cmd & _AWE_MODE_FLAG)
+- awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+- else
+- awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
+-#endif
+-}
+-
+-
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-
+-/* GUS compatible controls */
+-static void
+-awe_hw_gus_control(int dev, int cmd, unsigned char *event)
+-{
+- int voice, i, key;
+- unsigned short p1;
+- short p2;
+- int plong;
+-
+- if (MULTI_LAYER_MODE())
+- return;
+- if (cmd == _GUS_NUMVOICES)
+- return;
+-
+- voice = event[3];
+- if (! voice_in_range(voice))
+- return;
+-
+- p1 = *(unsigned short *) &event[4];
+- p2 = *(short *) &event[6];
+- plong = *(int*) &event[4];
+-
+- switch (cmd) {
+- case _GUS_VOICESAMPLE:
+- awe_set_instr(dev, voice, p1);
+- return;
+-
+- case _GUS_VOICEBALA:
+- /* 0 to 15 --> -128 to 127 */
+- awe_panning(dev, voice, ((int)p1 << 4) - 128);
+- return;
+-
+- case _GUS_VOICEVOL:
+- case _GUS_VOICEVOL2:
+- /* not supported yet */
+- return;
+-
+- case _GUS_RAMPRANGE:
+- case _GUS_RAMPRATE:
+- case _GUS_RAMPMODE:
+- case _GUS_RAMPON:
+- case _GUS_RAMPOFF:
+- /* volume ramping not supported */
+- return;
+-
+- case _GUS_VOLUME_SCALE:
+- return;
+-
+- case _GUS_VOICE_POS:
+- FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START,
+- (short)(plong & 0x7fff));
+- FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START,
+- (plong >> 15) & 0xffff);
+- return;
+- }
+-
+- key = AWE_VOICE_KEY(voice);
+- for (i = 0; i < awe_max_voices; i++) {
+- if (voices[i].key == key) {
+- switch (cmd) {
+- case _GUS_VOICEON:
+- awe_note_on(i);
+- break;
+-
+- case _GUS_VOICEOFF:
+- awe_terminate(i);
+- awe_fx_init(voices[i].ch);
+- awe_voice_init(i, TRUE);
+- break;
+-
+- case _GUS_VOICEFADE:
+- awe_note_off(i);
+- awe_fx_init(voices[i].ch);
+- awe_voice_init(i, FALSE);
+- break;
+-
+- case _GUS_VOICEFREQ:
+- awe_calc_pitch_from_freq(i, plong);
+- break;
+- }
+- }
+- }
+-}
+-
+-#endif /* gus_compat */
+-
+-
+-/* AWE32 specific controls */
+-static void
+-awe_hw_awe_control(int dev, int cmd, unsigned char *event)
+-{
+- int voice;
+- unsigned short p1;
+- short p2;
+- int i;
+-
+- voice = event[3];
+- if (! voice_in_range(voice))
+- return;
+-
+- if (playing_mode == AWE_PLAY_MULTI2) {
+- voice = voice_alloc->map[voice] >> 8;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return;
+- }
+-
+- p1 = *(unsigned short *) &event[4];
+- p2 = *(short *) &event[6];
+-
+- switch (cmd) {
+- case _AWE_DEBUG_MODE:
+- ctrls[AWE_MD_DEBUG_MODE] = p1;
+- printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
+- break;
+- case _AWE_REVERB_MODE:
+- ctrls[AWE_MD_REVERB_MODE] = p1;
+- awe_update_reverb_mode();
+- break;
+-
+- case _AWE_CHORUS_MODE:
+- ctrls[AWE_MD_CHORUS_MODE] = p1;
+- awe_update_chorus_mode();
+- break;
+-
+- case _AWE_REMOVE_LAST_SAMPLES:
+- DEBUG(0,printk("AWE32: remove last samples\n"));
+- awe_reset(0);
+- if (locked_sf_id > 0)
+- awe_remove_samples(locked_sf_id);
+- break;
+-
+- case _AWE_INITIALIZE_CHIP:
+- awe_initialize();
+- break;
+-
+- case _AWE_SEND_EFFECT:
+- i = -1;
+- if (p1 >= 0x100) {
+- i = (p1 >> 8);
+- if (i < 0 || i >= MAX_LAYERS)
+- break;
+- }
+- awe_send_effect(voice, i, p1, p2);
+- break;
+-
+- case _AWE_RESET_CHANNEL:
+- awe_channel_init(voice, !p1);
+- break;
+-
+- case _AWE_TERMINATE_ALL:
+- awe_reset(0);
+- break;
+-
+- case _AWE_TERMINATE_CHANNEL:
+- awe_voice_change(voice, awe_terminate_and_init);
+- break;
+-
+- case _AWE_RELEASE_ALL:
+- awe_note_off_all(FALSE);
+- break;
+- case _AWE_NOTEOFF_ALL:
+- awe_note_off_all(TRUE);
+- break;
+-
+- case _AWE_INITIAL_VOLUME:
+- DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
+- atten_relative = (char)p2;
+- atten_offset = (short)p1;
+- awe_update_volume();
+- break;
+-
+- case _AWE_CHN_PRESSURE:
+- channels[voice].chan_press = p1;
+- awe_modwheel_change(voice, p1);
+- break;
+-
+- case _AWE_CHANNEL_MODE:
+- DEBUG(0,printk("AWE32: channel mode = %d\n", p1));
+- playing_mode = p1;
+- awe_reset(0);
+- break;
+-
+- case _AWE_DRUM_CHANNELS:
+- DEBUG(0,printk("AWE32: drum flags = %x\n", p1));
+- drum_flags = *(unsigned int*)&event[4];
+- break;
+-
+- case _AWE_MISC_MODE:
+- DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2));
+- if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) {
+- ctrls[p1] = p2;
+- if (ctrl_parms[p1].update)
+- ctrl_parms[p1].update();
+- }
+- break;
+-
+- case _AWE_EQUALIZER:
+- ctrls[AWE_MD_BASS_LEVEL] = p1;
+- ctrls[AWE_MD_TREBLE_LEVEL] = p2;
+- awe_update_equalizer();
+- break;
+-
+- default:
+- DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
+- break;
+- }
+-}
+-
+-
+-/* change effects */
+-static void
+-awe_send_effect(int voice, int layer, int type, int val)
+-{
+- awe_chan_info *cinfo;
+- FX_Rec *fx;
+- int mode;
+-
+- cinfo = &channels[voice];
+- if (layer >= 0 && layer < MAX_LAYERS)
+- fx = &cinfo->fx_layer[layer];
+- else
+- fx = &cinfo->fx;
+-
+- if (type & 0x40)
+- mode = FX_FLAG_OFF;
+- else if (type & 0x80)
+- mode = FX_FLAG_ADD;
+- else
+- mode = FX_FLAG_SET;
+- type &= 0x3f;
+-
+- if (type >= 0 && type < AWE_FX_END) {
+- DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val));
+- if (mode == FX_FLAG_SET)
+- FX_SET(fx, type, val);
+- else if (mode == FX_FLAG_ADD)
+- FX_ADD(fx, type, val);
+- else
+- FX_UNSET(fx, type);
+- if (mode != FX_FLAG_OFF && parm_defs[type].realtime) {
+- DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice));
+- awe_voice_change(voice, parm_defs[type].realtime);
+- }
+- }
+-}
+-
+-
+-/* change modulation wheel; voice is already mapped on multi2 mode */
+-static void
+-awe_modwheel_change(int voice, int value)
+-{
+- int i;
+- awe_chan_info *cinfo;
+-
+- cinfo = &channels[voice];
+- i = value * ctrls[AWE_MD_MOD_SENSE] / 1200;
+- FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i);
+- awe_voice_change(voice, awe_fx_fmmod);
+- FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i);
+- awe_voice_change(voice, awe_fx_fm2frq2);
+-}
+-
+-
+-/* voice pressure change */
+-static void
+-awe_aftertouch(int dev, int voice, int pressure)
+-{
+- int note;
+-
+- DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
+- if (! voice_in_range(voice))
+- return;
+-
+- switch (playing_mode) {
+- case AWE_PLAY_DIRECT:
+- case AWE_PLAY_INDIRECT:
+- awe_start_note(dev, voice, 255, pressure);
+- break;
+- case AWE_PLAY_MULTI2:
+- note = (voice_alloc->map[voice] & 0xff) - 1;
+- awe_key_pressure(dev, voice, note + 0x80, pressure);
+- break;
+- }
+-}
+-
+-
+-/* voice control change */
+-static void
+-awe_controller(int dev, int voice, int ctrl_num, int value)
+-{
+- awe_chan_info *cinfo;
+-
+- if (! voice_in_range(voice))
+- return;
+-
+- if (playing_mode == AWE_PLAY_MULTI2) {
+- voice = voice_alloc->map[voice] >> 8;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return;
+- }
+-
+- cinfo = &channels[voice];
+-
+- switch (ctrl_num) {
+- case CTL_BANK_SELECT: /* MIDI control #0 */
+- DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
+- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
+- !ctrls[AWE_MD_TOGGLE_DRUM_BANK])
+- break;
+- if (value < 0 || value > 255)
+- break;
+- cinfo->bank = value;
+- if (cinfo->bank == AWE_DRUM_BANK)
+- DRUM_CHANNEL_ON(cinfo->channel);
+- else
+- DRUM_CHANNEL_OFF(cinfo->channel);
+- awe_set_instr(dev, voice, cinfo->instr);
+- break;
+-
+- case CTL_MODWHEEL: /* MIDI control #1 */
+- DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value));
+- awe_modwheel_change(voice, value);
+- break;
+-
+- case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */
+- DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
+- /* zero centered */
+- cinfo->bender = value;
+- awe_voice_change(voice, awe_set_voice_pitch);
+- break;
+-
+- case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */
+- DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
+- /* value = sense x 100 */
+- cinfo->bender_range = value;
+- /* no audible pitch change yet.. */
+- break;
+-
+- case CTL_EXPRESSION: /* MIDI control #11 */
+- if (SINGLE_LAYER_MODE())
+- value /= 128;
+- case CTRL_EXPRESSION: /* SEQ1 V2 control */
+- DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
+- /* 0 - 127 */
+- cinfo->expression_vol = value;
+- awe_voice_change(voice, awe_set_voice_vol);
+- break;
+-
+- case CTL_PAN: /* MIDI control #10 */
+- DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
+- /* (0-127) -> signed 8bit */
+- cinfo->panning = value * 2 - 128;
+- if (ctrls[AWE_MD_REALTIME_PAN])
+- awe_voice_change(voice, awe_set_pan);
+- break;
+-
+- case CTL_MAIN_VOLUME: /* MIDI control #7 */
+- if (SINGLE_LAYER_MODE())
+- value = (value * 100) / 16383;
+- case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */
+- DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
+- /* 0 - 127 */
+- cinfo->main_vol = value;
+- awe_voice_change(voice, awe_set_voice_vol);
+- break;
+-
+- case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
+- DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
+- FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2);
+- break;
+-
+- case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
+- DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
+- FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2);
+- break;
+-
+- case 120: /* all sounds off */
+- awe_note_off_all(FALSE);
+- break;
+- case 123: /* all notes off */
+- awe_note_off_all(TRUE);
+- break;
+-
+- case CTL_SUSTAIN: /* MIDI control #64 */
+- cinfo->sustained = value;
+- if (value != 127)
+- awe_voice_change(voice, awe_sustain_off);
+- break;
+-
+- case CTL_SOSTENUTO: /* MIDI control #66 */
+- if (value == 127)
+- awe_voice_change(voice, awe_sostenuto_on);
+- else
+- awe_voice_change(voice, awe_sustain_off);
+- break;
+-
+- default:
+- DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
+- voice, ctrl_num, value));
+- break;
+- }
+-}
+-
+-
+-/* voice pan change (value = -128 - 127) */
+-static void
+-awe_panning(int dev, int voice, int value)
+-{
+- awe_chan_info *cinfo;
+-
+- if (! voice_in_range(voice))
+- return;
+-
+- if (playing_mode == AWE_PLAY_MULTI2) {
+- voice = voice_alloc->map[voice] >> 8;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return;
+- }
+-
+- cinfo = &channels[voice];
+- cinfo->panning = value;
+- DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning));
+- if (ctrls[AWE_MD_REALTIME_PAN])
+- awe_voice_change(voice, awe_set_pan);
+-}
+-
+-
+-/* volume mode change */
+-static void
+-awe_volume_method(int dev, int mode)
+-{
+- /* not impremented */
+- DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
+-}
+-
+-
+-/* pitch wheel change: 0-16384 */
+-static void
+-awe_bender(int dev, int voice, int value)
+-{
+- awe_chan_info *cinfo;
+-
+- if (! voice_in_range(voice))
+- return;
+-
+- if (playing_mode == AWE_PLAY_MULTI2) {
+- voice = voice_alloc->map[voice] >> 8;
+- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+- return;
+- }
+-
+- /* convert to zero centered value */
+- cinfo = &channels[voice];
+- cinfo->bender = value - 8192;
+- DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender));
+- awe_voice_change(voice, awe_set_voice_pitch);
+-}
+-
+-
+-/*
+- * load a sound patch:
+- * three types of patches are accepted: AWE, GUS, and SYSEX.
+- */
+-
+-static int
+-awe_load_patch(int dev, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag)
+-{
+- awe_patch_info patch;
+- int rc = 0;
+-
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+- if (format == GUS_PATCH) {
+- return awe_load_guspatch(addr, offs, count, pmgr_flag);
+- } else
+-#endif
+- if (format == SYSEX_PATCH) {
+- /* no system exclusive message supported yet */
+- return 0;
+- } else if (format != AWE_PATCH) {
+- printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format);
+- return -EINVAL;
+- }
+-
+- if (count < AWE_PATCH_INFO_SIZE) {
+- printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
+- return -EINVAL;
+- }
+- if (copy_from_user(((char*)&patch) + offs, addr + offs,
+- AWE_PATCH_INFO_SIZE - offs))
+- return -EFAULT;
+-
+- count -= AWE_PATCH_INFO_SIZE;
+- if (count < patch.len) {
+- printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n",
+- count, patch.len);
+- return -EINVAL;
+- }
+-
+- switch (patch.type) {
+- case AWE_LOAD_INFO:
+- rc = awe_load_info(&patch, addr, count);
+- break;
+- case AWE_LOAD_DATA:
+- rc = awe_load_data(&patch, addr, count);
+- break;
+- case AWE_OPEN_PATCH:
+- rc = awe_open_patch(&patch, addr, count);
+- break;
+- case AWE_CLOSE_PATCH:
+- rc = awe_close_patch(&patch, addr, count);
+- break;
+- case AWE_UNLOAD_PATCH:
+- rc = awe_unload_patch(&patch, addr, count);
+- break;
+- case AWE_REPLACE_DATA:
+- rc = awe_replace_data(&patch, addr, count);
+- break;
+- case AWE_MAP_PRESET:
+- rc = awe_load_map(&patch, addr, count);
+- break;
+- /* case AWE_PROBE_INFO:
+- rc = awe_probe_info(&patch, addr, count);
+- break;*/
+- case AWE_PROBE_DATA:
+- rc = awe_probe_data(&patch, addr, count);
+- break;
+- case AWE_REMOVE_INFO:
+- rc = awe_remove_info(&patch, addr, count);
+- break;
+- case AWE_LOAD_CHORUS_FX:
+- rc = awe_load_chorus_fx(&patch, addr, count);
+- break;
+- case AWE_LOAD_REVERB_FX:
+- rc = awe_load_reverb_fx(&patch, addr, count);
+- break;
+-
+- default:
+- printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n",
+- patch.type);
+- rc = -EINVAL;
+- }
+-
+- return rc;
+-}
+-
+-
+-/* create an sf list record */
+-static int
+-awe_create_sf(int type, char *name)
+-{
+- sf_list *rec;
+-
+- /* terminate sounds */
+- awe_reset(0);
+- rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL);
+- if (rec == NULL)
+- return 1; /* no memory */
+- rec->sf_id = current_sf_id + 1;
+- rec->type = type;
+- if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0)
+- locked_sf_id = current_sf_id + 1;
+- rec->num_info = awe_free_info();
+- rec->num_sample = awe_free_sample();
+- rec->mem_ptr = awe_free_mem_ptr();
+- rec->infos = rec->last_infos = NULL;
+- rec->samples = rec->last_samples = NULL;
+-
+- /* add to linked-list */
+- rec->next = NULL;
+- rec->prev = sftail;
+- if (sftail)
+- sftail->next = rec;
+- else
+- sfhead = rec;
+- sftail = rec;
+- current_sf_id++;
+-
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- rec->shared = NULL;
+- if (name)
+- memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
+- else
+- strcpy(rec->name, "*TEMPORARY*");
+- if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) {
+- /* is the current font really a shared font? */
+- if (is_shared_sf(rec->name)) {
+- /* check if the shared font is already installed */
+- sf_list *p;
+- for (p = rec->prev; p; p = p->prev) {
+- if (is_identical_name(rec->name, p)) {
+- rec->shared = p;
+- break;
+- }
+- }
+- }
+- }
+-#endif /* allow sharing */
+-
+- return 0;
+-}
+-
+-
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+-
+-/* check if the given name is a valid shared name */
+-#define ASC_TO_KEY(c) ((c) - 'A' + 1)
+-static int is_shared_sf(unsigned char *name)
+-{
+- static unsigned char id_head[4] = {
+- ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
+- AWE_MAJOR_VERSION,
+- };
+- if (memcmp(name, id_head, 4) == 0)
+- return TRUE;
+- return FALSE;
+-}
+-
+-/* check if the given name matches to the existing list */
+-static int is_identical_name(unsigned char *name, sf_list *p)
+-{
+- char *id = p->name;
+- if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
+- return TRUE;
+- return FALSE;
+-}
+-
+-/* check if the given voice info exists */
+-static int info_duplicated(sf_list *sf, awe_voice_list *rec)
+-{
+- /* search for all sharing lists */
+- for (; sf; sf = sf->shared) {
+- awe_voice_list *p;
+- for (p = sf->infos; p; p = p->next) {
+- if (p->type == V_ST_NORMAL &&
+- p->bank == rec->bank &&
+- p->instr == rec->instr &&
+- p->v.low == rec->v.low &&
+- p->v.high == rec->v.high &&
+- p->v.sample == rec->v.sample)
+- return TRUE;
+- }
+- }
+- return FALSE;
+-}
+-
+-#endif /* AWE_ALLOW_SAMPLE_SHARING */
+-
+-
+-/* free sf_list record */
+-/* linked-list in this function is not cared */
+-static void
+-awe_free_sf(sf_list *sf)
+-{
+- if (sf->infos) {
+- awe_voice_list *p, *next;
+- for (p = sf->infos; p; p = next) {
+- next = p->next;
+- kfree(p);
+- }
+- }
+- if (sf->samples) {
+- awe_sample_list *p, *next;
+- for (p = sf->samples; p; p = next) {
+- next = p->next;
+- kfree(p);
+- }
+- }
+- kfree(sf);
+-}
+-
+-
+-/* open patch; create sf list and set opened flag */
+-static int
+-awe_open_patch(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- awe_open_parm parm;
+- int shared;
+-
+- if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)))
+- return -EFAULT;
+- shared = FALSE;
+-
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- if (sftail && (parm.type & AWE_PAT_SHARED) != 0) {
+- /* is the previous font the same font? */
+- if (is_identical_name(parm.name, sftail)) {
+- /* then append to the previous */
+- shared = TRUE;
+- awe_reset(0);
+- if (parm.type & AWE_PAT_LOCKED)
+- locked_sf_id = current_sf_id;
+- }
+- }
+-#endif /* allow sharing */
+- if (! shared) {
+- if (awe_create_sf(parm.type, parm.name)) {
+- printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n");
+- return -ENOMEM;
+- }
+- }
+- patch_opened = TRUE;
+- return current_sf_id;
+-}
+-
+-/* check if the patch is already opened */
+-static sf_list *
+-check_patch_opened(int type, char *name)
+-{
+- if (! patch_opened) {
+- if (awe_create_sf(type, name)) {
+- printk(KERN_ERR "AWE32: failed to alloc new list\n");
+- return NULL;
+- }
+- patch_opened = TRUE;
+- return sftail;
+- }
+- return sftail;
+-}
+-
+-/* close the patch; if no voice is loaded, remove the patch */
+-static int
+-awe_close_patch(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- if (patch_opened && sftail) {
+- /* if no voice is loaded, release the current patch */
+- if (sftail->infos == NULL) {
+- awe_reset(0);
+- awe_remove_samples(current_sf_id - 1);
+- }
+- }
+- patch_opened = 0;
+- return 0;
+-}
+-
+-
+-/* remove the latest patch */
+-static int
+-awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- if (current_sf_id > 0 && current_sf_id > locked_sf_id) {
+- awe_reset(0);
+- awe_remove_samples(current_sf_id - 1);
+- }
+- return 0;
+-}
+-
+-/* allocate voice info list records */
+-static awe_voice_list *
+-alloc_new_info(void)
+-{
+- awe_voice_list *newlist;
+-
+- newlist = kmalloc(sizeof(*newlist), GFP_KERNEL);
+- if (newlist == NULL) {
+- printk(KERN_ERR "AWE32: can't alloc info table\n");
+- return NULL;
+- }
+- return newlist;
+-}
+-
+-/* allocate sample info list records */
+-static awe_sample_list *
+-alloc_new_sample(void)
+-{
+- awe_sample_list *newlist;
+-
+- newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
+- if (newlist == NULL) {
+- printk(KERN_ERR "AWE32: can't alloc sample table\n");
+- return NULL;
+- }
+- return newlist;
+-}
+-
+-/* load voice map */
+-static int
+-awe_load_map(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- awe_voice_map map;
+- awe_voice_list *rec, *p;
+- sf_list *sf;
+-
+- /* get the link info */
+- if (count < sizeof(map)) {
+- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
+- return -EINVAL;
+- }
+- if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
+- return -EFAULT;
+-
+- /* check if the identical mapping already exists */
+- p = awe_search_instr(map.map_bank, map.map_instr, map.map_key);
+- for (; p; p = p->next_instr) {
+- if (p->type == V_ST_MAPPED &&
+- p->v.start == map.src_instr &&
+- p->v.end == map.src_bank &&
+- p->v.fixkey == map.src_key)
+- return 0; /* already present! */
+- }
+-
+- if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL)
+- return -ENOMEM;
+-
+- if ((rec = alloc_new_info()) == NULL)
+- return -ENOMEM;
+-
+- rec->bank = map.map_bank;
+- rec->instr = map.map_instr;
+- rec->type = V_ST_MAPPED;
+- rec->disabled = FALSE;
+- awe_init_voice_info(&rec->v);
+- if (map.map_key >= 0) {
+- rec->v.low = map.map_key;
+- rec->v.high = map.map_key;
+- }
+- rec->v.start = map.src_instr;
+- rec->v.end = map.src_bank;
+- rec->v.fixkey = map.src_key;
+- add_sf_info(sf, rec);
+- add_info_list(rec);
+-
+- return 0;
+-}
+-
+-#if 0
+-/* probe preset in the current list -- nothing to be loaded */
+-static int
+-awe_probe_info(awe_patch_info *patch, const char __user *addr, int count)
+-{
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- awe_voice_map map;
+- awe_voice_list *p;
+-
+- if (! patch_opened)
+- return -EINVAL;
+-
+- /* get the link info */
+- if (count < sizeof(map)) {
+- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
+- return -EINVAL;
+- }
+- if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
+- return -EFAULT;
+-
+- /* check if the identical mapping already exists */
+- if (sftail == NULL)
+- return -EINVAL;
+- p = awe_search_instr(map.src_bank, map.src_instr, map.src_key);
+- for (; p; p = p->next_instr) {
+- if (p->type == V_ST_NORMAL &&
+- is_identical_holder(p->holder, sftail) &&
+- p->v.low <= map.src_key &&
+- p->v.high >= map.src_key)
+- return 0; /* already present! */
+- }
+-#endif /* allow sharing */
+- return -EINVAL;
+-}
+-#endif
+-
+-/* probe sample in the current list -- nothing to be loaded */
+-static int
+-awe_probe_data(awe_patch_info *patch, const char __user *addr, int count)
+-{
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- if (! patch_opened)
+- return -EINVAL;
+-
+- /* search the specified sample by optarg */
+- if (search_sample_index(sftail, patch->optarg) != NULL)
+- return 0;
+-#endif /* allow sharing */
+- return -EINVAL;
+-}
+-
+-
+-/* remove the present instrument layers */
+-static int
+-remove_info(sf_list *sf, int bank, int instr)
+-{
+- awe_voice_list *prev, *next, *p;
+- int removed = 0;
+-
+- prev = NULL;
+- for (p = sf->infos; p; p = next) {
+- next = p->next;
+- if (p->type == V_ST_NORMAL &&
+- p->bank == bank && p->instr == instr) {
+- /* remove this layer */
+- if (prev)
+- prev->next = next;
+- else
+- sf->infos = next;
+- if (p == sf->last_infos)
+- sf->last_infos = prev;
+- sf->num_info--;
+- removed++;
+- kfree(p);
+- } else
+- prev = p;
+- }
+- if (removed)
+- rebuild_preset_list();
+- return removed;
+-}
+-
+-/* load voice information data */
+-static int
+-awe_load_info(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- int offset;
+- awe_voice_rec_hdr hdr;
+- int i;
+- int total_size;
+- sf_list *sf;
+- awe_voice_list *rec;
+-
+- if (count < AWE_VOICE_REC_SIZE) {
+- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
+- return -EINVAL;
+- }
+-
+- offset = AWE_PATCH_INFO_SIZE;
+- if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE))
+- return -EFAULT;
+- offset += AWE_VOICE_REC_SIZE;
+-
+- if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
+- printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices);
+- return -EINVAL;
+- }
+- total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
+- if (count < total_size) {
+- printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
+- count, hdr.nvoices);
+- return -EINVAL;
+- }
+-
+- if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
+- return -ENOMEM;
+-
+- switch (hdr.write_mode) {
+- case AWE_WR_EXCLUSIVE:
+- /* exclusive mode - if the instrument already exists,
+- return error */
+- for (rec = sf->infos; rec; rec = rec->next) {
+- if (rec->type == V_ST_NORMAL &&
+- rec->bank == hdr.bank &&
+- rec->instr == hdr.instr)
+- return -EINVAL;
+- }
+- break;
+- case AWE_WR_REPLACE:
+- /* replace mode - remove the instrument if it already exists */
+- remove_info(sf, hdr.bank, hdr.instr);
+- break;
+- }
+-
+- /* append new layers */
+- for (i = 0; i < hdr.nvoices; i++) {
+- rec = alloc_new_info();
+- if (rec == NULL)
+- return -ENOMEM;
+-
+- rec->bank = hdr.bank;
+- rec->instr = hdr.instr;
+- rec->type = V_ST_NORMAL;
+- rec->disabled = FALSE;
+-
+- /* copy awe_voice_info parameters */
+- if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) {
+- kfree(rec);
+- return -EFAULT;
+- }
+- offset += AWE_VOICE_INFO_SIZE;
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- if (sf && sf->shared) {
+- if (info_duplicated(sf, rec)) {
+- kfree(rec);
+- continue;
+- }
+- }
+-#endif /* allow sharing */
+- if (rec->v.mode & AWE_MODE_INIT_PARM)
+- awe_init_voice_parm(&rec->v.parm);
+- add_sf_info(sf, rec);
+- awe_set_sample(rec);
+- add_info_list(rec);
+- }
+-
+- return 0;
+-}
+-
+-
+-/* remove instrument layers */
+-static int
+-awe_remove_info(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- unsigned char bank, instr;
+- sf_list *sf;
+-
+- if (! patch_opened || (sf = sftail) == NULL) {
+- printk(KERN_WARNING "AWE32: remove_info: patch not opened\n");
+- return -EINVAL;
+- }
+-
+- bank = ((unsigned short)patch->optarg >> 8) & 0xff;
+- instr = (unsigned short)patch->optarg & 0xff;
+- if (! remove_info(sf, bank, instr))
+- return -EINVAL;
+- return 0;
+-}
+-
+-
+-/* load wave sample data */
+-static int
+-awe_load_data(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- int offset, size;
+- int rc;
+- awe_sample_info tmprec;
+- awe_sample_list *rec;
+- sf_list *sf;
+-
+- if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
+- return -ENOMEM;
+-
+- size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
+- offset = AWE_PATCH_INFO_SIZE;
+- if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE))
+- return -EFAULT;
+- offset += AWE_SAMPLE_INFO_SIZE;
+- if (size != tmprec.size) {
+- printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n",
+- tmprec.size, size);
+- return -EINVAL;
+- }
+-
+- if (search_sample_index(sf, tmprec.sample) != NULL) {
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- /* if shared sample, skip this data */
+- if (sf->type & AWE_PAT_SHARED)
+- return 0;
+-#endif /* allow sharing */
+- DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
+- return -EINVAL;
+- }
+-
+- if ((rec = alloc_new_sample()) == NULL)
+- return -ENOMEM;
+-
+- memcpy(&rec->v, &tmprec, sizeof(tmprec));
+-
+- if (rec->v.size > 0) {
+- if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) {
+- kfree(rec);
+- return rc;
+- }
+- sf->mem_ptr += rc;
+- }
+-
+- add_sf_sample(sf, rec);
+- return 0;
+-}
+-
+-
+-/* replace wave sample data */
+-static int
+-awe_replace_data(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- int offset;
+- int size;
+- int rc;
+- int channels;
+- awe_sample_info cursmp;
+- int save_mem_ptr;
+- sf_list *sf;
+- awe_sample_list *rec;
+-
+- if (! patch_opened || (sf = sftail) == NULL) {
+- printk(KERN_WARNING "AWE32: replace: patch not opened\n");
+- return -EINVAL;
+- }
+-
+- size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
+- offset = AWE_PATCH_INFO_SIZE;
+- if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE))
+- return -EFAULT;
+- offset += AWE_SAMPLE_INFO_SIZE;
+- if (cursmp.size == 0 || size != cursmp.size) {
+- printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n",
+- cursmp.size, size);
+- return -EINVAL;
+- }
+- channels = patch->optarg;
+- if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
+- printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels);
+- return -EINVAL;
+- }
+-
+- for (rec = sf->samples; rec; rec = rec->next) {
+- if (rec->v.sample == cursmp.sample)
+- break;
+- }
+- if (rec == NULL) {
+- printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n",
+- cursmp.sample);
+- return -EINVAL;
+- }
+-
+- if (rec->v.size != cursmp.size) {
+- printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n",
+- rec->v.size, cursmp.size);
+- return -EINVAL;
+- }
+-
+- save_mem_ptr = awe_free_mem_ptr();
+- sftail->mem_ptr = rec->v.start - awe_mem_start;
+- memcpy(&rec->v, &cursmp, sizeof(cursmp));
+- rec->v.sf_id = current_sf_id;
+- if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0)
+- return rc;
+- sftail->mem_ptr = save_mem_ptr;
+-
+- return 0;
+-}
+-
+-
+-/*----------------------------------------------------------------*/
+-
+-static const char __user *readbuf_addr;
+-static int readbuf_offs;
+-static int readbuf_flags;
+-
+-/* initialize read buffer */
+-static int
+-readbuf_init(const char __user *addr, int offset, awe_sample_info *sp)
+-{
+- readbuf_addr = addr;
+- readbuf_offs = offset;
+- readbuf_flags = sp->mode_flags;
+- return 0;
+-}
+-
+-/* read directly from user buffer */
+-static unsigned short
+-readbuf_word(int pos)
+-{
+- unsigned short c;
+- /* read from user buffer */
+- if (readbuf_flags & AWE_SAMPLE_8BITS) {
+- unsigned char cc;
+- get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos));
+- c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */
+- } else {
+- get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2));
+- }
+- if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
+- c ^= 0x8000; /* unsigned -> signed */
+- return c;
+-}
+-
+-#define readbuf_word_cache readbuf_word
+-#define readbuf_end() /**/
+-
+-/*----------------------------------------------------------------*/
+-
+-#define BLANK_LOOP_START 8
+-#define BLANK_LOOP_END 40
+-#define BLANK_LOOP_SIZE 48
+-
+-/* loading onto memory - return the actual written size */
+-static int
+-awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *list, int channels)
+-{
+- int i, truesize, dram_offset;
+- awe_sample_info *sp = &list->v;
+- int rc;
+-
+- /* be sure loop points start < end */
+- if (sp->loopstart > sp->loopend) {
+- int tmp = sp->loopstart;
+- sp->loopstart = sp->loopend;
+- sp->loopend = tmp;
+- }
+-
+- /* compute true data size to be loaded */
+- truesize = sp->size;
+- if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))
+- truesize += sp->loopend - sp->loopstart;
+- if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
+- truesize += BLANK_LOOP_SIZE;
+- if (awe_free_mem_ptr() + truesize >= memsize/2) {
+- DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
+- return -ENOSPC;
+- }
+-
+- /* recalculate address offset */
+- sp->end -= sp->start;
+- sp->loopstart -= sp->start;
+- sp->loopend -= sp->start;
+-
+- dram_offset = awe_free_mem_ptr() + awe_mem_start;
+- sp->start = dram_offset;
+- sp->end += dram_offset;
+- sp->loopstart += dram_offset;
+- sp->loopend += dram_offset;
+-
+- /* set the total size (store onto obsolete checksum value) */
+- if (sp->size == 0)
+- sp->checksum = 0;
+- else
+- sp->checksum = truesize;
+-
+- if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0)
+- return rc;
+-
+- if (readbuf_init(addr, offset, sp) < 0)
+- return -ENOSPC;
+-
+- for (i = 0; i < sp->size; i++) {
+- unsigned short c;
+- c = readbuf_word(i);
+- awe_write_dram(c);
+- if (i == sp->loopend &&
+- (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) {
+- int looplen = sp->loopend - sp->loopstart;
+- /* copy reverse loop */
+- int k;
+- for (k = 1; k <= looplen; k++) {
+- c = readbuf_word_cache(i - k);
+- awe_write_dram(c);
+- }
+- if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) {
+- sp->end += looplen;
+- } else {
+- sp->start += looplen;
+- sp->end += looplen;
+- }
+- }
+- }
+- readbuf_end();
+-
+- /* if no blank loop is attached in the sample, add it */
+- if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
+- for (i = 0; i < BLANK_LOOP_SIZE; i++)
+- awe_write_dram(0);
+- if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
+- sp->loopstart = sp->end + BLANK_LOOP_START;
+- sp->loopend = sp->end + BLANK_LOOP_END;
+- }
+- }
+-
+- awe_close_dram();
+-
+- /* initialize FM */
+- awe_init_fm();
+-
+- return truesize;
+-}
+-
+-
+-/*----------------------------------------------------------------*/
+-
+-#ifdef AWE_HAS_GUS_COMPATIBILITY
+-
+-/* calculate GUS envelope time:
+- * is this correct? i have no idea..
+- */
+-static int
+-calc_gus_envelope_time(int rate, int start, int end)
+-{
+- int r, p, t;
+- r = (3 - ((rate >> 6) & 3)) * 3;
+- p = rate & 0x3f;
+- t = end - start;
+- if (t < 0) t = -t;
+- if (13 > r)
+- t = t << (13 - r);
+- else
+- t = t >> (r - 13);
+- return (t * 10) / (p * 441);
+-}
+-
+-#define calc_gus_sustain(val) (0x7f - vol_table[(val)/2])
+-#define calc_gus_attenuation(val) vol_table[(val)/2]
+-
+-/* load GUS patch */
+-static int
+-awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag)
+-{
+- struct patch_info patch;
+- awe_voice_info *rec;
+- awe_sample_info *smp;
+- awe_voice_list *vrec;
+- awe_sample_list *smprec;
+- int sizeof_patch;
+- int note, rc;
+- sf_list *sf;
+-
+- sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
+- if (size < sizeof_patch) {
+- printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
+- return -EINVAL;
+- }
+- if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs))
+- return -EFAULT;
+- size -= sizeof_patch;
+- if (size < patch.len) {
+- printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n",
+- size, patch.len);
+- return -EINVAL;
+- }
+- if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL)
+- return -ENOMEM;
+- if ((smprec = alloc_new_sample()) == NULL)
+- return -ENOMEM;
+- if ((vrec = alloc_new_info()) == NULL) {
+- kfree(smprec);
+- return -ENOMEM;
+- }
+-
+- smp = &smprec->v;
+- smp->sample = sf->num_sample;
+- smp->start = 0;
+- smp->end = patch.len;
+- smp->loopstart = patch.loop_start;
+- smp->loopend = patch.loop_end;
+- smp->size = patch.len;
+-
+- /* set up mode flags */
+- smp->mode_flags = 0;
+- if (!(patch.mode & WAVE_16_BITS))
+- smp->mode_flags |= AWE_SAMPLE_8BITS;
+- if (patch.mode & WAVE_UNSIGNED)
+- smp->mode_flags |= AWE_SAMPLE_UNSIGNED;
+- smp->mode_flags |= AWE_SAMPLE_NO_BLANK;
+- if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
+- smp->mode_flags |= AWE_SAMPLE_SINGLESHOT;
+- if (patch.mode & WAVE_BIDIR_LOOP)
+- smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
+- if (patch.mode & WAVE_LOOP_BACK)
+- smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP;
+-
+- DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags));
+- if (patch.mode & WAVE_16_BITS) {
+- /* convert to word offsets */
+- smp->size /= 2;
+- smp->end /= 2;
+- smp->loopstart /= 2;
+- smp->loopend /= 2;
+- }
+- smp->checksum_flag = 0;
+- smp->checksum = 0;
+-
+- if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) {
+- kfree(vrec);
+- return rc;
+- }
+- sf->mem_ptr += rc;
+- add_sf_sample(sf, smprec);
+-
+- /* set up voice info */
+- rec = &vrec->v;
+- awe_init_voice_info(rec);
+- rec->sample = sf->num_info; /* the last sample */
+- rec->rate_offset = calc_rate_offset(patch.base_freq);
+- note = freq_to_note(patch.base_note);
+- rec->root = note / 100;
+- rec->tune = -(note % 100);
+- rec->low = freq_to_note(patch.low_note) / 100;
+- rec->high = freq_to_note(patch.high_note) / 100;
+- DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
+- rec->rate_offset, note,
+- rec->low, rec->high,
+- patch.low_note, patch.high_note));
+- /* panning position; -128 - 127 => 0-127 */
+- rec->pan = (patch.panning + 128) / 2;
+-
+- /* detuning is ignored */
+- /* 6points volume envelope */
+- if (patch.mode & WAVE_ENVELOPES) {
+- int attack, hold, decay, release;
+- attack = calc_gus_envelope_time
+- (patch.env_rate[0], 0, patch.env_offset[0]);
+- hold = calc_gus_envelope_time
+- (patch.env_rate[1], patch.env_offset[0],
+- patch.env_offset[1]);
+- decay = calc_gus_envelope_time
+- (patch.env_rate[2], patch.env_offset[1],
+- patch.env_offset[2]);
+- release = calc_gus_envelope_time
+- (patch.env_rate[3], patch.env_offset[1],
+- patch.env_offset[4]);
+- release += calc_gus_envelope_time
+- (patch.env_rate[4], patch.env_offset[3],
+- patch.env_offset[4]);
+- release += calc_gus_envelope_time
+- (patch.env_rate[5], patch.env_offset[4],
+- patch.env_offset[5]);
+- rec->parm.volatkhld = (calc_parm_hold(hold) << 8) |
+- calc_parm_attack(attack);
+- rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
+- calc_parm_decay(decay);
+- rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
+- DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
+- rec->attenuation = calc_gus_attenuation(patch.env_offset[0]);
+- }
+-
+- /* tremolo effect */
+- if (patch.mode & WAVE_TREMOLO) {
+- int rate = (patch.tremolo_rate * 1000 / 38) / 42;
+- rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
+- DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
+- patch.tremolo_rate, patch.tremolo_depth,
+- rec->parm.tremfrq));
+- }
+- /* vibrato effect */
+- if (patch.mode & WAVE_VIBRATO) {
+- int rate = (patch.vibrato_rate * 1000 / 38) / 42;
+- rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
+- DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
+- patch.tremolo_rate, patch.tremolo_depth,
+- rec->parm.tremfrq));
+- }
+-
+- /* scale_freq, scale_factor, volume, and fractions not implemented */
+-
+- /* append to the tail of the list */
+- vrec->bank = ctrls[AWE_MD_GUS_BANK];
+- vrec->instr = patch.instr_no;
+- vrec->disabled = FALSE;
+- vrec->type = V_ST_NORMAL;
+-
+- add_sf_info(sf, vrec);
+- add_info_list(vrec);
+-
+- /* set the voice index */
+- awe_set_sample(vrec);
+-
+- return 0;
+-}
+-
+-#endif /* AWE_HAS_GUS_COMPATIBILITY */
+-
+-/*
+- * sample and voice list handlers
+- */
+-
+-/* append this to the current sf list */
+-static void add_sf_info(sf_list *sf, awe_voice_list *rec)
+-{
+- if (sf == NULL)
+- return;
+- rec->holder = sf;
+- rec->v.sf_id = sf->sf_id;
+- if (sf->last_infos)
+- sf->last_infos->next = rec;
+- else
+- sf->infos = rec;
+- sf->last_infos = rec;
+- rec->next = NULL;
+- sf->num_info++;
+-}
+-
+-/* prepend this sample to sf list */
+-static void add_sf_sample(sf_list *sf, awe_sample_list *rec)
+-{
+- if (sf == NULL)
+- return;
+- rec->holder = sf;
+- rec->v.sf_id = sf->sf_id;
+- if (sf->last_samples)
+- sf->last_samples->next = rec;
+- else
+- sf->samples = rec;
+- sf->last_samples = rec;
+- rec->next = NULL;
+- sf->num_sample++;
+-}
+-
+-/* purge the old records which don't belong with the same file id */
+-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next)
+-{
+- rec->next_instr = next;
+- if (rec->bank == AWE_DRUM_BANK) {
+- /* remove samples with the same note range */
+- awe_voice_list *cur, *prev = rec;
+- int low = rec->v.low;
+- int high = rec->v.high;
+- for (cur = next; cur; cur = cur->next_instr) {
+- if (cur->v.low == low &&
+- cur->v.high == high &&
+- ! is_identical_holder(cur->holder, rec->holder))
+- prev->next_instr = cur->next_instr;
+- else
+- prev = cur;
+- }
+- } else {
+- if (! is_identical_holder(next->holder, rec->holder))
+- /* remove all samples */
+- rec->next_instr = NULL;
+- }
+-}
+-
+-/* prepend to top of the preset table */
+-static void add_info_list(awe_voice_list *rec)
+-{
+- awe_voice_list *prev, *cur;
+- int key;
+-
+- if (rec->disabled)
+- return;
+-
+- key = awe_search_key(rec->bank, rec->instr, rec->v.low);
+- prev = NULL;
+- for (cur = preset_table[key]; cur; cur = cur->next_bank) {
+- /* search the first record with the same bank number */
+- if (cur->instr == rec->instr && cur->bank == rec->bank) {
+- /* replace the list with the new record */
+- rec->next_bank = cur->next_bank;
+- if (prev)
+- prev->next_bank = rec;
+- else
+- preset_table[key] = rec;
+- purge_old_list(rec, cur);
+- return;
+- }
+- prev = cur;
+- }
+-
+- /* this is the first bank record.. just add this */
+- rec->next_instr = NULL;
+- rec->next_bank = preset_table[key];
+- preset_table[key] = rec;
+-}
+-
+-/* remove samples later than the specified sf_id */
+-static void
+-awe_remove_samples(int sf_id)
+-{
+- sf_list *p, *prev;
+-
+- if (sf_id <= 0) {
+- awe_reset_samples();
+- return;
+- }
+- /* already removed? */
+- if (current_sf_id <= sf_id)
+- return;
+-
+- for (p = sftail; p; p = prev) {
+- if (p->sf_id <= sf_id)
+- break;
+- prev = p->prev;
+- awe_free_sf(p);
+- }
+- sftail = p;
+- if (sftail) {
+- sf_id = sftail->sf_id;
+- sftail->next = NULL;
+- } else {
+- sf_id = 0;
+- sfhead = NULL;
+- }
+- current_sf_id = sf_id;
+- if (locked_sf_id > sf_id)
+- locked_sf_id = sf_id;
+-
+- rebuild_preset_list();
+-}
+-
+-/* rebuild preset search list */
+-static void rebuild_preset_list(void)
+-{
+- sf_list *p;
+- awe_voice_list *rec;
+-
+- memset(preset_table, 0, sizeof(preset_table));
+-
+- for (p = sfhead; p; p = p->next) {
+- for (rec = p->infos; rec; rec = rec->next)
+- add_info_list(rec);
+- }
+-}
+-
+-/* compare the given sf_id pair */
+-static int is_identical_holder(sf_list *sf1, sf_list *sf2)
+-{
+- if (sf1 == NULL || sf2 == NULL)
+- return FALSE;
+- if (sf1 == sf2)
+- return TRUE;
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- {
+- /* compare with the sharing id */
+- sf_list *p;
+- int counter = 0;
+- if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */
+- sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp;
+- }
+- for (p = sf1->shared; p; p = p->shared) {
+- if (counter++ > current_sf_id)
+- break; /* strange sharing loop.. quit */
+- if (p == sf2)
+- return TRUE;
+- }
+- }
+-#endif /* allow sharing */
+- return FALSE;
+-}
+-
+-/* search the sample index matching with the given sample id */
+-static awe_sample_list *
+-search_sample_index(sf_list *sf, int sample)
+-{
+- awe_sample_list *p;
+-#ifdef AWE_ALLOW_SAMPLE_SHARING
+- int counter = 0;
+- while (sf) {
+- for (p = sf->samples; p; p = p->next) {
+- if (p->v.sample == sample)
+- return p;
+- }
+- sf = sf->shared;
+- if (counter++ > current_sf_id)
+- break; /* strange sharing loop.. quit */
+- }
+-#else
+- if (sf) {
+- for (p = sf->samples; p; p = p->next) {
+- if (p->v.sample == sample)
+- return p;
+- }
+- }
+-#endif
+- return NULL;
+-}
+-
+-/* search the specified sample */
+-/* non-zero = found */
+-static short
+-awe_set_sample(awe_voice_list *rec)
+-{
+- awe_sample_list *smp;
+- awe_voice_info *vp = &rec->v;
+-
+- vp->index = 0;
+- if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL)
+- return 0;
+-
+- /* set the actual sample offsets */
+- vp->start += smp->v.start;
+- vp->end += smp->v.end;
+- vp->loopstart += smp->v.loopstart;
+- vp->loopend += smp->v.loopend;
+- /* copy mode flags */
+- vp->mode = smp->v.mode_flags;
+- /* set flag */
+- vp->index = 1;
+-
+- return 1;
+-}
+-
+-
+-/*
+- * voice allocation
+- */
+-
+-/* look for all voices associated with the specified note & velocity */
+-static int
+-awe_search_multi_voices(awe_voice_list *rec, int note, int velocity,
+- awe_voice_info **vlist)
+-{
+- int nvoices;
+-
+- nvoices = 0;
+- for (; rec; rec = rec->next_instr) {
+- if (note >= rec->v.low &&
+- note <= rec->v.high &&
+- velocity >= rec->v.vellow &&
+- velocity <= rec->v.velhigh) {
+- if (rec->type == V_ST_MAPPED) {
+- /* mapper */
+- vlist[0] = &rec->v;
+- return -1;
+- }
+- vlist[nvoices++] = &rec->v;
+- if (nvoices >= AWE_MAX_VOICES)
+- break;
+- }
+- }
+- return nvoices;
+-}
+-
+-/* store the voice list from the specified note and velocity.
+- if the preset is mapped, seek for the destination preset, and rewrite
+- the note number if necessary.
+- */
+-static int
+-really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist)
+-{
+- int nvoices;
+- awe_voice_list *vrec;
+- int level = 0;
+-
+- for (;;) {
+- vrec = awe_search_instr(bank, instr, *note);
+- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+- if (nvoices == 0) {
+- if (bank == AWE_DRUM_BANK)
+- /* search default drumset */
+- vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note);
+- else
+- /* search default preset */
+- vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note);
+- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+- }
+- if (nvoices == 0) {
+- if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0)
+- /* search default drumset */
+- vrec = awe_search_instr(bank, 0, *note);
+- else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0)
+- /* search default preset */
+- vrec = awe_search_instr(0, instr, *note);
+- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+- }
+- if (nvoices < 0) { /* mapping */
+- int key = vlist[0]->fixkey;
+- instr = vlist[0]->start;
+- bank = vlist[0]->end;
+- if (level++ > 5) {
+- printk(KERN_ERR "AWE32: too deep mapping level\n");
+- return 0;
+- }
+- if (key >= 0)
+- *note = key;
+- } else
+- break;
+- }
+-
+- return nvoices;
+-}
+-
+-/* allocate voices corresponding note and velocity; supports multiple insts. */
+-static void
+-awe_alloc_multi_voices(int ch, int note, int velocity, int key)
+-{
+- int i, v, nvoices, bank;
+- awe_voice_info *vlist[AWE_MAX_VOICES];
+-
+- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch))
+- bank = AWE_DRUM_BANK; /* always search drumset */
+- else
+- bank = channels[ch].bank;
+-
+- /* check the possible voices; note may be changeable if mapped */
+- nvoices = really_alloc_voices(bank, channels[ch].instr,
+- ¬e, velocity, vlist);
+-
+- /* set the voices */
+- current_alloc_time++;
+- for (i = 0; i < nvoices; i++) {
+- v = awe_clear_voice();
+- voices[v].key = key;
+- voices[v].ch = ch;
+- voices[v].note = note;
+- voices[v].velocity = velocity;
+- voices[v].time = current_alloc_time;
+- voices[v].cinfo = &channels[ch];
+- voices[v].sample = vlist[i];
+- voices[v].state = AWE_ST_MARK;
+- voices[v].layer = nvoices - i - 1; /* in reverse order */
+- }
+-
+- /* clear the mark in allocated voices */
+- for (i = 0; i < awe_max_voices; i++) {
+- if (voices[i].state == AWE_ST_MARK)
+- voices[i].state = AWE_ST_OFF;
+-
+- }
+-}
+-
+-
+-/* search an empty voice.
+- if no empty voice is found, at least terminate a voice
+- */
+-static int
+-awe_clear_voice(void)
+-{
+- enum {
+- OFF=0, RELEASED, SUSTAINED, PLAYING, END
+- };
+- struct voice_candidate_t {
+- int best;
+- int time;
+- int vtarget;
+- } candidate[END];
+- int i, type, vtarget;
+-
+- vtarget = 0xffff;
+- for (type = OFF; type < END; type++) {
+- candidate[type].best = -1;
+- candidate[type].time = current_alloc_time + 1;
+- candidate[type].vtarget = vtarget;
+- }
+-
+- for (i = 0; i < awe_max_voices; i++) {
+- if (voices[i].state & AWE_ST_OFF)
+- type = OFF;
+- else if (voices[i].state & AWE_ST_RELEASED)
+- type = RELEASED;
+- else if (voices[i].state & AWE_ST_SUSTAINED)
+- type = SUSTAINED;
+- else if (voices[i].state & ~AWE_ST_MARK)
+- type = PLAYING;
+- else
+- continue;
+-#ifdef AWE_CHECK_VTARGET
+- /* get current volume */
+- vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
+-#endif
+- if (candidate[type].best < 0 ||
+- vtarget < candidate[type].vtarget ||
+- (vtarget == candidate[type].vtarget &&
+- voices[i].time < candidate[type].time)) {
+- candidate[type].best = i;
+- candidate[type].time = voices[i].time;
+- candidate[type].vtarget = vtarget;
+- }
+- }
+-
+- for (type = OFF; type < END; type++) {
+- if ((i = candidate[type].best) >= 0) {
+- if (voices[i].state != AWE_ST_OFF)
+- awe_terminate(i);
+- awe_voice_init(i, TRUE);
+- return i;
+- }
+- }
+- return 0;
+-}
+-
+-
+-/* search sample for the specified note & velocity and set it on the voice;
+- * note that voice is the voice index (not channel index)
+- */
+-static void
+-awe_alloc_one_voice(int voice, int note, int velocity)
+-{
+- int ch, nvoices, bank;
+- awe_voice_info *vlist[AWE_MAX_VOICES];
+-
+- ch = voices[voice].ch;
+- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
+- bank = AWE_DRUM_BANK; /* always search drumset */
+- else
+- bank = voices[voice].cinfo->bank;
+-
+- nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr,
+- ¬e, velocity, vlist);
+- if (nvoices > 0) {
+- voices[voice].time = ++current_alloc_time;
+- voices[voice].sample = vlist[0]; /* use the first one */
+- voices[voice].layer = 0;
+- voices[voice].note = note;
+- voices[voice].velocity = velocity;
+- }
+-}
+-
+-
+-/*
+- * sequencer2 functions
+- */
+-
+-/* search an empty voice; used by sequencer2 */
+-static int
+-awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
+-{
+- playing_mode = AWE_PLAY_MULTI2;
+- awe_info.nr_voices = AWE_MAX_CHANNELS;
+- return awe_clear_voice();
+-}
+-
+-
+-/* set up voice; used by sequencer2 */
+-static void
+-awe_setup_voice(int dev, int voice, int chn)
+-{
+- struct channel_info *info;
+- if (synth_devs[dev] == NULL ||
+- (info = &synth_devs[dev]->chn_info[chn]) == NULL)
+- return;
+-
+- if (voice < 0 || voice >= awe_max_voices)
+- return;
+-
+- DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
+- channels[chn].expression_vol = info->controllers[CTL_EXPRESSION];
+- channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME];
+- channels[chn].panning =
+- info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
+- channels[chn].bender = info->bender_value; /* zero center */
+- channels[chn].bank = info->controllers[CTL_BANK_SELECT];
+- channels[chn].sustained = info->controllers[CTL_SUSTAIN];
+- if (info->controllers[CTL_EXT_EFF_DEPTH]) {
+- FX_SET(&channels[chn].fx, AWE_FX_REVERB,
+- info->controllers[CTL_EXT_EFF_DEPTH] * 2);
+- }
+- if (info->controllers[CTL_CHORUS_DEPTH]) {
+- FX_SET(&channels[chn].fx, AWE_FX_CHORUS,
+- info->controllers[CTL_CHORUS_DEPTH] * 2);
+- }
+- awe_set_instr(dev, chn, info->pgm_num);
+-}
+-
+-
+-#ifdef CONFIG_AWE32_MIXER
+-/*
+- * AWE32 mixer device control
+- */
+-
+-static int awe_mixer_ioctl(int dev, unsigned int cmd, void __user *arg);
+-
+-static int my_mixerdev = -1;
+-
+-static struct mixer_operations awe_mixer_operations = {
+- .owner = THIS_MODULE,
+- .id = "AWE",
+- .name = "AWE32 Equalizer",
+- .ioctl = awe_mixer_ioctl,
+-};
+-
+-static void __init attach_mixer(void)
+-{
+- if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
+- mixer_devs[my_mixerdev] = &awe_mixer_operations;
+- }
+-}
+-
+-static void unload_mixer(void)
+-{
+- if (my_mixerdev >= 0)
+- sound_unload_mixerdev(my_mixerdev);
+-}
+-
+-static int
+-awe_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
+-{
+- int i, level, value;
+-
+- if (((cmd >> 8) & 0xff) != 'M')
+- return -EINVAL;
+-
+- if (get_user(level, (int __user *)arg))
+- return -EFAULT;
+- level = ((level & 0xff) + (level >> 8)) / 2;
+- DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
+-
+- if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+- switch (cmd & 0xff) {
+- case SOUND_MIXER_BASS:
+- value = level * 12 / 100;
+- if (value >= 12)
+- value = 11;
+- ctrls[AWE_MD_BASS_LEVEL] = value;
+- awe_update_equalizer();
+- break;
+- case SOUND_MIXER_TREBLE:
+- value = level * 12 / 100;
+- if (value >= 12)
+- value = 11;
+- ctrls[AWE_MD_TREBLE_LEVEL] = value;
+- awe_update_equalizer();
+- break;
+- case SOUND_MIXER_VOLUME:
+- level = level * 127 / 100;
+- if (level >= 128) level = 127;
+- atten_relative = FALSE;
+- atten_offset = vol_table[level];
+- awe_update_volume();
+- break;
+- }
+- }
+- switch (cmd & 0xff) {
+- case SOUND_MIXER_BASS:
+- level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24;
+- level = (level << 8) | level;
+- break;
+- case SOUND_MIXER_TREBLE:
+- level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24;
+- level = (level << 8) | level;
+- break;
+- case SOUND_MIXER_VOLUME:
+- value = atten_offset;
+- if (atten_relative)
+- value += ctrls[AWE_MD_ZERO_ATTEN];
+- for (i = 127; i > 0; i--) {
+- if (value <= vol_table[i])
+- break;
+- }
+- level = i * 100 / 127;
+- level = (level << 8) | level;
+- break;
+- case SOUND_MIXER_DEVMASK:
+- level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME;
+- break;
+- default:
+- level = 0;
+- break;
+- }
+- if (put_user(level, (int __user *)arg))
+- return -EFAULT;
+- return level;
+-}
+-#endif /* CONFIG_AWE32_MIXER */
+-
+-
+-/*
+- * initialization of Emu8000
+- */
+-
+-/* intiailize audio channels */
+-static void
+-awe_init_audio(void)
+-{
+- int ch;
+-
+- /* turn off envelope engines */
+- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+- awe_poke(AWE_DCYSUSV(ch), 0x80);
+- }
+-
+- /* reset all other parameters to zero */
+- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+- awe_poke(AWE_ENVVOL(ch), 0);
+- awe_poke(AWE_ENVVAL(ch), 0);
+- awe_poke(AWE_DCYSUS(ch), 0);
+- awe_poke(AWE_ATKHLDV(ch), 0);
+- awe_poke(AWE_LFO1VAL(ch), 0);
+- awe_poke(AWE_ATKHLD(ch), 0);
+- awe_poke(AWE_LFO2VAL(ch), 0);
+- awe_poke(AWE_IP(ch), 0);
+- awe_poke(AWE_IFATN(ch), 0);
+- awe_poke(AWE_PEFE(ch), 0);
+- awe_poke(AWE_FMMOD(ch), 0);
+- awe_poke(AWE_TREMFRQ(ch), 0);
+- awe_poke(AWE_FM2FRQ2(ch), 0);
+- awe_poke_dw(AWE_PTRX(ch), 0);
+- awe_poke_dw(AWE_VTFT(ch), 0);
+- awe_poke_dw(AWE_PSST(ch), 0);
+- awe_poke_dw(AWE_CSL(ch), 0);
+- awe_poke_dw(AWE_CCCA(ch), 0);
+- }
+-
+- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+- awe_poke_dw(AWE_CPF(ch), 0);
+- awe_poke_dw(AWE_CVCF(ch), 0);
+- }
+-}
+-
+-
+-/* initialize DMA address */
+-static void
+-awe_init_dma(void)
+-{
+- awe_poke_dw(AWE_SMALR, 0);
+- awe_poke_dw(AWE_SMARR, 0);
+- awe_poke_dw(AWE_SMALW, 0);
+- awe_poke_dw(AWE_SMARW, 0);
+-}
+-
+-
+-/* initialization arrays; from ADIP */
+-
+-static unsigned short init1[128] = {
+- 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
+- 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
+- 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
+- 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
+-
+- 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
+- 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
+- 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
+- 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
+-
+- 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
+- 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
+- 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
+- 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
+-
+- 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
+- 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
+- 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
+- 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
+-};
+-
+-static unsigned short init2[128] = {
+- 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
+- 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
+- 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
+- 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
+-
+- 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
+- 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
+- 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
+- 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
+-
+- 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
+- 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
+- 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
+- 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
+-
+- 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
+- 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
+- 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
+- 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
+-};
+-
+-static unsigned short init3[128] = {
+- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
+- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
+- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
+- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
+-
+- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
+- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
+- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
+- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
+-
+- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
+- 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
+- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
+- 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
+-
+- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
+- 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
+- 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
+- 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
+-};
+-
+-static unsigned short init4[128] = {
+- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
+- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
+- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
+- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
+-
+- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
+- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
+- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
+- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
+-
+- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
+- 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
+- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
+- 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
+-
+- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
+- 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
+- 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
+- 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
+-};
+-
+-
+-/* send initialization arrays to start up */
+-static void
+-awe_init_array(void)
+-{
+- awe_send_array(init1);
+- awe_wait(1024);
+- awe_send_array(init2);
+- awe_send_array(init3);
+- awe_poke_dw(AWE_HWCF4, 0);
+- awe_poke_dw(AWE_HWCF5, 0x83);
+- awe_poke_dw(AWE_HWCF6, 0x8000);
+- awe_send_array(init4);
+-}
+-
+-/* send an initialization array */
+-static void
+-awe_send_array(unsigned short *data)
+-{
+- int i;
+- unsigned short *p;
+-
+- p = data;
+- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+- awe_poke(AWE_INIT1(i), *p);
+- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+- awe_poke(AWE_INIT2(i), *p);
+- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+- awe_poke(AWE_INIT3(i), *p);
+- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+- awe_poke(AWE_INIT4(i), *p);
+-}
+-
+-
+-/*
+- * set up awe32 channels to some known state.
+- */
+-
+-/* set the envelope & LFO parameters to the default values; see ADIP */
+-static void
+-awe_tweak_voice(int i)
+-{
+- /* set all mod/vol envelope shape to minimum */
+- awe_poke(AWE_ENVVOL(i), 0x8000);
+- awe_poke(AWE_ENVVAL(i), 0x8000);
+- awe_poke(AWE_DCYSUS(i), 0x7F7F);
+- awe_poke(AWE_ATKHLDV(i), 0x7F7F);
+- awe_poke(AWE_ATKHLD(i), 0x7F7F);
+- awe_poke(AWE_PEFE(i), 0); /* mod envelope height to zero */
+- awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */
+- awe_poke(AWE_LFO2VAL(i), 0x8000);
+- awe_poke(AWE_IP(i), 0xE000); /* no pitch shift */
+- awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */
+- awe_poke(AWE_FMMOD(i), 0);
+- awe_poke(AWE_TREMFRQ(i), 0);
+- awe_poke(AWE_FM2FRQ2(i), 0);
+-}
+-
+-static void
+-awe_tweak(void)
+-{
+- int i;
+- /* reset all channels */
+- for (i = 0; i < awe_max_voices; i++)
+- awe_tweak_voice(i);
+-}
+-
+-
+-/*
+- * initializes the FM section of AWE32;
+- * see Vince Vu's unofficial AWE32 programming guide
+- */
+-
+-static void
+-awe_init_fm(void)
+-{
+-#ifndef AWE_ALWAYS_INIT_FM
+- /* if no extended memory is on board.. */
+- if (memsize <= 0)
+- return;
+-#endif
+- DEBUG(3,printk("AWE32: initializing FM\n"));
+-
+- /* Initialize the last two channels for DRAM refresh and producing
+- the reverb and chorus effects for Yamaha OPL-3 synthesizer */
+-
+- /* 31: FM left channel, 0xffffe0-0xffffe8 */
+- awe_poke(AWE_DCYSUSV(30), 0x80);
+- awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */
+- awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 |
+- (DEF_FM_CHORUS_DEPTH << 24));
+- awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8));
+- awe_poke_dw(AWE_CPF(30), 0);
+- awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3);
+-
+- /* 32: FM right channel, 0xfffff0-0xfffff8 */
+- awe_poke(AWE_DCYSUSV(31), 0x80);
+- awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */
+- awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 |
+- (DEF_FM_CHORUS_DEPTH << 24));
+- awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8));
+- awe_poke_dw(AWE_CPF(31), 0x8000);
+- awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3);
+-
+- /* skew volume & cutoff */
+- awe_poke_dw(AWE_VTFT(30), 0x8000FFFF);
+- awe_poke_dw(AWE_VTFT(31), 0x8000FFFF);
+-
+- voices[30].state = AWE_ST_FM;
+- voices[31].state = AWE_ST_FM;
+-
+- /* change maximum channels to 30 */
+- awe_max_voices = AWE_NORMAL_VOICES;
+- if (playing_mode == AWE_PLAY_DIRECT)
+- awe_info.nr_voices = awe_max_voices;
+- else
+- awe_info.nr_voices = AWE_MAX_CHANNELS;
+- voice_alloc->max_voice = awe_max_voices;
+-}
+-
+-/*
+- * AWE32 DRAM access routines
+- */
+-
+-/* open DRAM write accessing mode */
+-static int
+-awe_open_dram_for_write(int offset, int channels)
+-{
+- int vidx[AWE_NORMAL_VOICES];
+- int i;
+-
+- if (channels < 0 || channels >= AWE_NORMAL_VOICES) {
+- channels = AWE_NORMAL_VOICES;
+- for (i = 0; i < AWE_NORMAL_VOICES; i++)
+- vidx[i] = i;
+- } else {
+- for (i = 0; i < channels; i++) {
+- vidx[i] = awe_clear_voice();
+- voices[vidx[i]].state = AWE_ST_MARK;
+- }
+- }
+-
+- /* use all channels for DMA transfer */
+- for (i = 0; i < channels; i++) {
+- if (vidx[i] < 0) continue;
+- awe_poke(AWE_DCYSUSV(vidx[i]), 0x80);
+- awe_poke_dw(AWE_VTFT(vidx[i]), 0);
+- awe_poke_dw(AWE_CVCF(vidx[i]), 0);
+- awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000);
+- awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000);
+- awe_poke_dw(AWE_PSST(vidx[i]), 0);
+- awe_poke_dw(AWE_CSL(vidx[i]), 0);
+- awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000);
+- voices[vidx[i]].state = AWE_ST_DRAM;
+- }
+- /* point channels 31 & 32 to ROM samples for DRAM refresh */
+- awe_poke_dw(AWE_VTFT(30), 0);
+- awe_poke_dw(AWE_PSST(30), 0x1d8);
+- awe_poke_dw(AWE_CSL(30), 0x1e0);
+- awe_poke_dw(AWE_CCCA(30), 0x1d8);
+- awe_poke_dw(AWE_VTFT(31), 0);
+- awe_poke_dw(AWE_PSST(31), 0x1d8);
+- awe_poke_dw(AWE_CSL(31), 0x1e0);
+- awe_poke_dw(AWE_CCCA(31), 0x1d8);
+- voices[30].state = AWE_ST_FM;
+- voices[31].state = AWE_ST_FM;
+-
+- /* if full bit is on, not ready to write on */
+- if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
+- for (i = 0; i < channels; i++) {
+- awe_poke_dw(AWE_CCCA(vidx[i]), 0);
+- voices[vidx[i]].state = AWE_ST_OFF;
+- }
+- printk("awe: not ready to write..\n");
+- return -EPERM;
+- }
+-
+- /* set address to write */
+- awe_poke_dw(AWE_SMALW, offset);
+-
+- return 0;
+-}
+-
+-/* open DRAM for RAM size detection */
+-static void
+-awe_open_dram_for_check(void)
+-{
+- int i;
+- for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+- awe_poke(AWE_DCYSUSV(i), 0x80);
+- awe_poke_dw(AWE_VTFT(i), 0);
+- awe_poke_dw(AWE_CVCF(i), 0);
+- awe_poke_dw(AWE_PTRX(i), 0x40000000);
+- awe_poke_dw(AWE_CPF(i), 0x40000000);
+- awe_poke_dw(AWE_PSST(i), 0);
+- awe_poke_dw(AWE_CSL(i), 0);
+- if (i & 1) /* DMA write */
+- awe_poke_dw(AWE_CCCA(i), 0x06000000);
+- else /* DMA read */
+- awe_poke_dw(AWE_CCCA(i), 0x04000000);
+- voices[i].state = AWE_ST_DRAM;
+- }
+-}
+-
+-
+-/* close dram access */
+-static void
+-awe_close_dram(void)
+-{
+- int i;
+- /* wait until FULL bit in SMAxW register be false */
+- for (i = 0; i < 10000; i++) {
+- if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
+- break;
+- awe_wait(10);
+- }
+-
+- for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+- if (voices[i].state == AWE_ST_DRAM) {
+- awe_poke_dw(AWE_CCCA(i), 0);
+- awe_poke(AWE_DCYSUSV(i), 0x807F);
+- voices[i].state = AWE_ST_OFF;
+- }
+- }
+-}
+-
+-
+-/*
+- * check dram size on AWE board
+- */
+-
+-/* any three numbers you like */
+-#define UNIQUE_ID1 0x1234
+-#define UNIQUE_ID2 0x4321
+-#define UNIQUE_ID3 0xABCD
+-
+-static void __init
+-awe_check_dram(void)
+-{
+- if (awe_present) /* already initialized */
+- return;
+-
+- if (memsize >= 0) { /* given by config file or module option */
+- memsize *= 1024; /* convert to Kbytes */
+- return;
+- }
+-
+- awe_open_dram_for_check();
+-
+- memsize = 0;
+-
+- /* set up unique two id numbers */
+- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
+- awe_poke(AWE_SMLD, UNIQUE_ID1);
+- awe_poke(AWE_SMLD, UNIQUE_ID2);
+-
+- while (memsize < AWE_MAX_DRAM_SIZE) {
+- awe_wait(5);
+- /* read a data on the DRAM start address */
+- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
+- awe_peek(AWE_SMLD); /* discard stale data */
+- if (awe_peek(AWE_SMLD) != UNIQUE_ID1)
+- break;
+- if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
+- break;
+- memsize += 512; /* increment 512kbytes */
+- /* Write a unique data on the test address;
+- * if the address is out of range, the data is written on
+- * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are
+- * broken by this data.
+- */
+- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L);
+- awe_poke(AWE_SMLD, UNIQUE_ID3);
+- awe_wait(5);
+- /* read a data on the just written DRAM address */
+- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L);
+- awe_peek(AWE_SMLD); /* discard stale data */
+- if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
+- break;
+- }
+- awe_close_dram();
+-
+- DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize));
+-
+- /* convert to Kbytes */
+- memsize *= 1024;
+-}
+-
+-
+-/*----------------------------------------------------------------*/
+-
+-/*
+- * chorus and reverb controls; from VV's guide
+- */
+-
+-/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
+-static char chorus_defined[AWE_CHORUS_NUMBERS];
+-static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = {
+- {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
+- {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
+- {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
+- {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
+- {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
+- {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
+- {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */
+- {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */
+-};
+-
+-static int
+-awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
+- printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg);
+- return -EINVAL;
+- }
+- if (count < sizeof(awe_chorus_fx_rec)) {
+- printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n");
+- return -EINVAL;
+- }
+- if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+- sizeof(awe_chorus_fx_rec)))
+- return -EFAULT;
+- chorus_defined[patch->optarg] = TRUE;
+- return 0;
+-}
+-
+-static void
+-awe_set_chorus_mode(int effect)
+-{
+- if (effect < 0 || effect >= AWE_CHORUS_NUMBERS ||
+- (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect]))
+- return;
+- awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback);
+- awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset);
+- awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth);
+- awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay);
+- awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq);
+- awe_poke_dw(AWE_HWCF6, 0x8000);
+- awe_poke_dw(AWE_HWCF7, 0x0000);
+-}
+-
+-static void
+-awe_update_chorus_mode(void)
+-{
+- awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]);
+-}
+-
+-/*----------------------------------------------------------------*/
+-
+-/* reverb mode settings; write the following 28 data of 16 bit length
+- * on the corresponding ports in the reverb_cmds array
+- */
+-static char reverb_defined[AWE_CHORUS_NUMBERS];
+-static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = {
+-{{ /* room 1 */
+- 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
+- 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
+- 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+-}},
+-{{ /* room 2 */
+- 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
+- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
+- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+-}},
+-{{ /* room 3 */
+- 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
+- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
+- 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
+- 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
+-}},
+-{{ /* hall 1 */
+- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
+- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
+- 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
+- 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
+-}},
+-{{ /* hall 2 */
+- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
+- 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
+- 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+-}},
+-{{ /* plate */
+- 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
+- 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
+- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+-}},
+-{{ /* delay */
+- 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
+- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
+- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
+- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
+-}},
+-{{ /* panning delay */
+- 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
+- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
+- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
+- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
+-}},
+-};
+-
+-static struct ReverbCmdPair {
+- unsigned short cmd, port;
+-} reverb_cmds[28] = {
+- {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
+- {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
+- {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
+- {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
+- {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
+- {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
+- {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
+-};
+-
+-static int
+-awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count)
+-{
+- if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
+- printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg);
+- return -EINVAL;
+- }
+- if (count < sizeof(awe_reverb_fx_rec)) {
+- printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n");
+- return -EINVAL;
+- }
+- if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+- sizeof(awe_reverb_fx_rec)))
+- return -EFAULT;
+- reverb_defined[patch->optarg] = TRUE;
+- return 0;
+-}
+-
+-static void
+-awe_set_reverb_mode(int effect)
+-{
+- int i;
+- if (effect < 0 || effect >= AWE_REVERB_NUMBERS ||
+- (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect]))
+- return;
+- for (i = 0; i < 28; i++)
+- awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port,
+- reverb_parm[effect].parms[i]);
+-}
+-
+-static void
+-awe_update_reverb_mode(void)
+-{
+- awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
+-}
+-
+-/*
+- * treble/bass equalizer control
+- */
+-
+-static unsigned short bass_parm[12][3] = {
+- {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
+- {0xD25B, 0xD35B, 0x0000}, /* -8 */
+- {0xD24C, 0xD34C, 0x0000}, /* -6 */
+- {0xD23D, 0xD33D, 0x0000}, /* -4 */
+- {0xD21F, 0xD31F, 0x0000}, /* -2 */
+- {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
+- {0xC219, 0xC319, 0x0001}, /* +2 */
+- {0xC22A, 0xC32A, 0x0001}, /* +4 */
+- {0xC24C, 0xC34C, 0x0001}, /* +6 */
+- {0xC26E, 0xC36E, 0x0001}, /* +8 */
+- {0xC248, 0xC348, 0x0002}, /* +10 */
+- {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
+-};
+-
+-static unsigned short treble_parm[12][9] = {
+- {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
+- {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+- {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+- {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+- {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+- {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
+- {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
+- {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
+- {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
+- {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
+- {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
+- {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */
+-};
+-
+-
+-/*
+- * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
+- */
+-static void
+-awe_equalizer(int bass, int treble)
+-{
+- unsigned short w;
+-
+- if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
+- return;
+- awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]);
+- awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]);
+- awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]);
+- awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]);
+- awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]);
+- awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]);
+- awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]);
+- awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]);
+- awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]);
+- awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]);
+- w = bass_parm[bass][2] + treble_parm[treble][8];
+- awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262));
+- awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362));
+-}
+-
+-static void awe_update_equalizer(void)
+-{
+- awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]);
+-}
+-
+-
+-/*----------------------------------------------------------------*/
+-
+-#ifdef CONFIG_AWE32_MIDIEMU
+-
+-/*
+- * Emu8000 MIDI Emulation
+- */
+-
+-/*
+- * midi queue record
+- */
+-
+-/* queue type */
+-enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
+-
+-#define MAX_MIDIBUF 64
+-
+-/* midi status */
+-typedef struct MidiStatus {
+- int queue; /* queue type */
+- int qlen; /* queue length */
+- int read; /* chars read */
+- int status; /* current status */
+- int chan; /* current channel */
+- unsigned char buf[MAX_MIDIBUF];
+-} MidiStatus;
+-
+-/* MIDI mode type */
+-enum { MODE_GM, MODE_GS, MODE_XG, };
+-
+-/* NRPN / CC -> Emu8000 parameter converter */
+-typedef struct {
+- int control;
+- int awe_effect;
+- unsigned short (*convert)(int val);
+-} ConvTable;
+-
+-
+-/*
+- * prototypes
+- */
+-
+-static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
+-static void awe_midi_close(int dev);
+-static int awe_midi_ioctl(int dev, unsigned cmd, void __user * arg);
+-static int awe_midi_outputc(int dev, unsigned char midi_byte);
+-
+-static void init_midi_status(MidiStatus *st);
+-static void clear_rpn(void);
+-static void get_midi_char(MidiStatus *st, int c);
+-/*static void queue_varlen(MidiStatus *st, int c);*/
+-static void special_event(MidiStatus *st, int c);
+-static void queue_read(MidiStatus *st, int c);
+-static void midi_note_on(MidiStatus *st);
+-static void midi_note_off(MidiStatus *st);
+-static void midi_key_pressure(MidiStatus *st);
+-static void midi_channel_pressure(MidiStatus *st);
+-static void midi_pitch_wheel(MidiStatus *st);
+-static void midi_program_change(MidiStatus *st);
+-static void midi_control_change(MidiStatus *st);
+-static void midi_select_bank(MidiStatus *st, int val);
+-static void midi_nrpn_event(MidiStatus *st);
+-static void midi_rpn_event(MidiStatus *st);
+-static void midi_detune(int chan, int coarse, int fine);
+-static void midi_system_exclusive(MidiStatus *st);
+-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
+-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
+-static int xg_control_change(MidiStatus *st, int cmd, int val);
+-
+-#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
+-
+-
+-/*
+- * OSS Midi device record
+- */
+-
+-static struct midi_operations awe_midi_operations =
+-{
+- .owner = THIS_MODULE,
+- .info = {"AWE Midi Emu", 0, 0, SNDCARD_SB},
+- .in_info = {0},
+- .open = awe_midi_open, /*open*/
+- .close = awe_midi_close, /*close*/
+- .ioctl = awe_midi_ioctl, /*ioctl*/
+- .outputc = awe_midi_outputc, /*outputc*/
+-};
+-
+-static int my_mididev = -1;
+-
+-static void __init attach_midiemu(void)
+-{
+- if ((my_mididev = sound_alloc_mididev()) < 0)
+- printk ("Sound: Too many midi devices detected\n");
+- else
+- midi_devs[my_mididev] = &awe_midi_operations;
+-}
+-
+-static void unload_midiemu(void)
+-{
+- if (my_mididev >= 0)
+- sound_unload_mididev(my_mididev);
+-}
+-
+-
+-/*
+- * open/close midi device
+- */
+-
+-static int midi_opened = FALSE;
+-
+-static int midi_mode;
+-static int coarsetune, finetune;
+-
+-static int xg_mapping = TRUE;
+-static int xg_bankmode;
+-
+-/* effect sensitivity */
+-
+-#define FX_CUTOFF 0
+-#define FX_RESONANCE 1
+-#define FX_ATTACK 2
+-#define FX_RELEASE 3
+-#define FX_VIBRATE 4
+-#define FX_VIBDEPTH 5
+-#define FX_VIBDELAY 6
+-#define FX_NUMS 7
+-
+-#define DEF_FX_CUTOFF 170
+-#define DEF_FX_RESONANCE 6
+-#define DEF_FX_ATTACK 50
+-#define DEF_FX_RELEASE 50
+-#define DEF_FX_VIBRATE 30
+-#define DEF_FX_VIBDEPTH 4
+-#define DEF_FX_VIBDELAY 1500
+-
+-/* effect sense: */
+-static int gs_sense[] =
+-{
+- DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
+- DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
+-};
+-static int xg_sense[] =
+-{
+- DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
+- DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
+-};
+-
+-
+-/* current status */
+-static MidiStatus curst;
+-
+-
+-static int
+-awe_midi_open (int dev, int mode,
+- void (*input)(int,unsigned char),
+- void (*output)(int))
+-{
+- if (midi_opened)
+- return -EBUSY;
+-
+- midi_opened = TRUE;
+-
+- midi_mode = MODE_GM;
+-
+- curst.queue = Q_NONE;
+- curst.qlen = 0;
+- curst.read = 0;
+- curst.status = 0;
+- curst.chan = 0;
+- memset(curst.buf, 0, sizeof(curst.buf));
+-
+- init_midi_status(&curst);
+-
+- return 0;
+-}
+-
+-static void
+-awe_midi_close (int dev)
+-{
+- midi_opened = FALSE;
+-}
+-
+-
+-static int
+-awe_midi_ioctl (int dev, unsigned cmd, void __user *arg)
+-{
+- return -EPERM;
+-}
+-
+-static int
+-awe_midi_outputc (int dev, unsigned char midi_byte)
+-{
+- if (! midi_opened)
+- return 1;
+-
+- /* force to change playing mode */
+- playing_mode = AWE_PLAY_MULTI;
+-
+- get_midi_char(&curst, midi_byte);
+- return 1;
+-}
+-
+-
+-/*
+- * initialize
+- */
+-
+-static void init_midi_status(MidiStatus *st)
+-{
+- clear_rpn();
+- coarsetune = 0;
+- finetune = 0;
+-}
+-
+-
+-/*
+- * RPN & NRPN
+- */
+-
+-#define MAX_MIDI_CHANNELS 16
+-
+-/* RPN & NRPN */
+-static unsigned char nrpn[MAX_MIDI_CHANNELS]; /* current event is NRPN? */
+-static int msb_bit; /* current event is msb for RPN/NRPN */
+-/* RPN & NRPN indeces */
+-static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS];
+-/* RPN & NRPN values */
+-static int rpn_val[MAX_MIDI_CHANNELS];
+-
+-static void clear_rpn(void)
+-{
+- int i;
+- for (i = 0; i < MAX_MIDI_CHANNELS; i++) {
+- nrpn[i] = 0;
+- rpn_msb[i] = 127;
+- rpn_lsb[i] = 127;
+- rpn_val[i] = 0;
+- }
+- msb_bit = 0;
+-}
+-
+-
+-/*
+- * process midi queue
+- */
+-
+-/* status event types */
+-typedef void (*StatusEvent)(MidiStatus *st);
+-static struct StatusEventList {
+- StatusEvent process;
+- int qlen;
+-} status_event[8] = {
+- {midi_note_off, 2},
+- {midi_note_on, 2},
+- {midi_key_pressure, 2},
+- {midi_control_change, 2},
+- {midi_program_change, 1},
+- {midi_channel_pressure, 1},
+- {midi_pitch_wheel, 2},
+- {NULL, 0},
+-};
+-
+-
+-/* read a char from fifo and process it */
+-static void get_midi_char(MidiStatus *st, int c)
+-{
+- if (c == 0xfe) {
+- /* ignore active sense */
+- st->queue = Q_NONE;
+- return;
+- }
+-
+- switch (st->queue) {
+- /* case Q_VARLEN: queue_varlen(st, c); break;*/
+- case Q_READ:
+- case Q_SYSEX:
+- queue_read(st, c);
+- break;
+- case Q_NONE:
+- st->read = 0;
+- if ((c & 0xf0) == 0xf0) {
+- special_event(st, c);
+- } else if (c & 0x80) { /* status change */
+- st->status = (c >> 4) & 0x07;
+- st->chan = c & 0x0f;
+- st->queue = Q_READ;
+- st->qlen = status_event[st->status].qlen;
+- if (st->qlen == 0)
+- st->queue = Q_NONE;
+- }
+- break;
+- }
+-}
+-
+-/* 0xfx events */
+-static void special_event(MidiStatus *st, int c)
+-{
+- switch (c) {
+- case 0xf0: /* system exclusive */
+- st->queue = Q_SYSEX;
+- st->qlen = 0;
+- break;
+- case 0xf1: /* MTC quarter frame */
+- case 0xf3: /* song select */
+- st->queue = Q_READ;
+- st->qlen = 1;
+- break;
+- case 0xf2: /* song position */
+- st->queue = Q_READ;
+- st->qlen = 2;
+- break;
+- }
+-}
+-
+-#if 0
+-/* read variable length value */
+-static void queue_varlen(MidiStatus *st, int c)
+-{
+- st->qlen += (c & 0x7f);
+- if (c & 0x80) {
+- st->qlen <<= 7;
+- return;
+- }
+- if (st->qlen <= 0) {
+- st->qlen = 0;
+- st->queue = Q_NONE;
+- }
+- st->queue = Q_READ;
+- st->read = 0;
+-}
+-#endif
+-
+-
+-/* read a char */
+-static void queue_read(MidiStatus *st, int c)
+-{
+- if (st->read < MAX_MIDIBUF) {
+- if (st->queue != Q_SYSEX)
+- c &= 0x7f;
+- st->buf[st->read] = (unsigned char)c;
+- }
+- st->read++;
+- if (st->queue == Q_SYSEX && c == 0xf7) {
+- midi_system_exclusive(st);
+- st->queue = Q_NONE;
+- } else if (st->queue == Q_READ && st->read >= st->qlen) {
+- if (status_event[st->status].process)
+- status_event[st->status].process(st);
+- st->queue = Q_NONE;
+- }
+-}
+-
+-
+-/*
+- * status events
+- */
+-
+-/* note on */
+-static void midi_note_on(MidiStatus *st)
+-{
+- DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
+- if (st->buf[1] == 0)
+- midi_note_off(st);
+- else
+- awe_start_note(0, st->chan, st->buf[0], st->buf[1]);
+-}
+-
+-/* note off */
+-static void midi_note_off(MidiStatus *st)
+-{
+- DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
+- awe_kill_note(0, st->chan, st->buf[0], st->buf[1]);
+-}
+-
+-/* key pressure change */
+-static void midi_key_pressure(MidiStatus *st)
+-{
+- awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]);
+-}
+-
+-/* channel pressure change */
+-static void midi_channel_pressure(MidiStatus *st)
+-{
+- channels[st->chan].chan_press = st->buf[0];
+- awe_modwheel_change(st->chan, st->buf[0]);
+-}
+-
+-/* pitch wheel change */
+-static void midi_pitch_wheel(MidiStatus *st)
+-{
+- int val = (int)st->buf[1] * 128 + st->buf[0];
+- awe_bender(0, st->chan, val);
+-}
+-
+-/* program change */
+-static void midi_program_change(MidiStatus *st)
+-{
+- int preset;
+- preset = st->buf[0];
+- if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127)
+- preset = 0;
+- else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan))
+- preset += 64;
+-
+- awe_set_instr(0, st->chan, preset);
+-}
+-
+-#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val)
+-#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val)
+-#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0)
+-
+-/* midi control change */
+-static void midi_control_change(MidiStatus *st)
+-{
+- int cmd = st->buf[0];
+- int val = st->buf[1];
+-
+- DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val));
+- if (midi_mode == MODE_XG) {
+- if (xg_control_change(st, cmd, val))
+- return;
+- }
+-
+- /* controls #31 - #64 are LSB of #0 - #31 */
+- msb_bit = 1;
+- if (cmd >= 0x20 && cmd < 0x40) {
+- msb_bit = 0;
+- cmd -= 0x20;
+- }
+-
+- switch (cmd) {
+- case CTL_SOFT_PEDAL:
+- if (val == 127)
+- add_effect(st->chan, AWE_FX_CUTOFF, -160);
+- else
+- unset_effect(st->chan, AWE_FX_CUTOFF);
+- break;
+-
+- case CTL_BANK_SELECT:
+- midi_select_bank(st, val);
+- break;
+-
+- /* set RPN/NRPN parameter */
+- case CTL_REGIST_PARM_NUM_MSB:
+- nrpn[st->chan]=0; rpn_msb[st->chan]=val;
+- break;
+- case CTL_REGIST_PARM_NUM_LSB:
+- nrpn[st->chan]=0; rpn_lsb[st->chan]=val;
+- break;
+- case CTL_NONREG_PARM_NUM_MSB:
+- nrpn[st->chan]=1; rpn_msb[st->chan]=val;
+- break;
+- case CTL_NONREG_PARM_NUM_LSB:
+- nrpn[st->chan]=1; rpn_lsb[st->chan]=val;
+- break;
+-
+- /* send RPN/NRPN entry */
+- case CTL_DATA_ENTRY:
+- if (msb_bit)
+- rpn_val[st->chan] = val * 128;
+- else
+- rpn_val[st->chan] |= val;
+- if (nrpn[st->chan])
+- midi_nrpn_event(st);
+- else
+- midi_rpn_event(st);
+- break;
+-
+- /* increase/decrease data entry */
+- case CTL_DATA_INCREMENT:
+- rpn_val[st->chan]++;
+- midi_rpn_event(st);
+- break;
+- case CTL_DATA_DECREMENT:
+- rpn_val[st->chan]--;
+- midi_rpn_event(st);
+- break;
+-
+- /* default */
+- default:
+- awe_controller(0, st->chan, cmd, val);
+- break;
+- }
+-}
+-
+-/* tone bank change */
+-static void midi_select_bank(MidiStatus *st, int val)
+-{
+- if (midi_mode == MODE_XG && msb_bit) {
+- xg_bankmode = val;
+- /* XG MSB value; not normal bank selection */
+- switch (val) {
+- case 127: /* remap to drum channel */
+- awe_controller(0, st->chan, CTL_BANK_SELECT, 128);
+- break;
+- default: /* remap to normal channel */
+- awe_controller(0, st->chan, CTL_BANK_SELECT, val);
+- break;
+- }
+- return;
+- } else if (midi_mode == MODE_GS && !msb_bit)
+- /* ignore LSB bank in GS mode (used for mapping) */
+- return;
+-
+- /* normal bank controls; accept both MSB and LSB */
+- if (! IS_DRUM_CHANNEL(st->chan)) {
+- if (midi_mode == MODE_XG) {
+- if (xg_bankmode) return;
+- if (val == 64 || val == 126)
+- val = 0;
+- } else if (midi_mode == MODE_GS && val == 127)
+- val = 0;
+- awe_controller(0, st->chan, CTL_BANK_SELECT, val);
+- }
+-}
+-
+-
+-/*
+- * RPN events
+- */
+-
+-static void midi_rpn_event(MidiStatus *st)
+-{
+- int type;
+- type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan];
+- switch (type) {
+- case 0x0000: /* Pitch bend sensitivity */
+- /* MSB only / 1 semitone per 128 */
+- if (msb_bit) {
+- channels[st->chan].bender_range =
+- rpn_val[st->chan] * 100 / 128;
+- }
+- break;
+-
+- case 0x0001: /* fine tuning: */
+- /* MSB/LSB, 8192=center, 100/8192 cent step */
+- finetune = rpn_val[st->chan] - 8192;
+- midi_detune(st->chan, coarsetune, finetune);
+- break;
+-
+- case 0x0002: /* coarse tuning */
+- /* MSB only / 8192=center, 1 semitone per 128 */
+- if (msb_bit) {
+- coarsetune = rpn_val[st->chan] - 8192;
+- midi_detune(st->chan, coarsetune, finetune);
+- }
+- break;
+-
+- case 0x7F7F: /* "lock-in" RPN */
+- break;
+- }
+-}
+-
+-
+-/* tuning:
+- * coarse = -8192 to 8192 (100 cent per 128)
+- * fine = -8192 to 8192 (max=100cent)
+- */
+-static void midi_detune(int chan, int coarse, int fine)
+-{
+- /* 4096 = 1200 cents in AWE parameter */
+- int val;
+- val = coarse * 4096 / (12 * 128);
+- val += fine / 24;
+- if (val)
+- send_effect(chan, AWE_FX_INIT_PITCH, val);
+- else
+- unset_effect(chan, AWE_FX_INIT_PITCH);
+-}
+-
+-
+-/*
+- * system exclusive message
+- * GM/GS/XG macros are accepted
+- */
+-
+-static void midi_system_exclusive(MidiStatus *st)
+-{
+- /* GM on */
+- static unsigned char gm_on_macro[] = {
+- 0x7e,0x7f,0x09,0x01,
+- };
+- /* XG on */
+- static unsigned char xg_on_macro[] = {
+- 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
+- };
+- /* GS prefix
+- * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
+- * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
+- * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
+- */
+- static unsigned char gs_pfx_macro[] = {
+- 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
+- };
+-
+-#if 0
+- /* SC88 system mode set
+- * single module mode: XX=1
+- * double module mode: XX=0
+- */
+- static unsigned char gs_mode_macro[] = {
+- 0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/
+- };
+- /* SC88 display macro: XX=01:bitmap, 00:text
+- */
+- static unsigned char gs_disp_macro[] = {
+- 0x41,0x10,0x45,0x12,0x10,/*XX,00*/
+- };
+-#endif
+-
+- /* GM on */
+- if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
+- if (midi_mode != MODE_GS && midi_mode != MODE_XG)
+- midi_mode = MODE_GM;
+- init_midi_status(st);
+- }
+-
+- /* GS macros */
+- else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
+- if (midi_mode != MODE_GS && midi_mode != MODE_XG)
+- midi_mode = MODE_GS;
+-
+- if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) {
+- /* GS reset */
+- init_midi_status(st);
+- }
+-
+- else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) {
+- /* drum pattern */
+- int p = st->buf[5] & 0x0f;
+- if (p == 0) p = 9;
+- else if (p < 10) p--;
+- if (st->buf[7] == 0)
+- DRUM_CHANNEL_OFF(p);
+- else
+- DRUM_CHANNEL_ON(p);
+-
+- } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) {
+- /* program */
+- int p = st->buf[5] & 0x0f;
+- if (p == 0) p = 9;
+- else if (p < 10) p--;
+- if (! IS_DRUM_CHANNEL(p))
+- awe_set_instr(0, p, st->buf[7]);
+-
+- } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) {
+- /* reverb mode */
+- awe_set_reverb_mode(st->buf[7]);
+-
+- } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) {
+- /* chorus mode */
+- awe_set_chorus_mode(st->buf[7]);
+-
+- } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) {
+- /* master volume */
+- awe_change_master_volume(st->buf[7]);
+-
+- }
+- }
+-
+- /* XG on */
+- else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
+- midi_mode = MODE_XG;
+- xg_mapping = TRUE;
+- xg_bankmode = 0;
+- }
+-}
+-
+-
+-/*----------------------------------------------------------------*/
+-
+-/*
+- * convert NRPN/control values
+- */
+-
+-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
+-{
+- int i, cval;
+- for (i = 0; i < num_tables; i++) {
+- if (table[i].control == type) {
+- cval = table[i].convert(val);
+- send_effect(st->chan, table[i].awe_effect, cval);
+- return TRUE;
+- }
+- }
+- return FALSE;
+-}
+-
+-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
+-{
+- int i, cval;
+- for (i = 0; i < num_tables; i++) {
+- if (table[i].control == type) {
+- cval = table[i].convert(val);
+- add_effect(st->chan, table[i].awe_effect|0x80, cval);
+- return TRUE;
+- }
+- }
+- return FALSE;
+-}
+-
+-
+-/*
+- * AWE32 NRPN effects
+- */
+-
+-static unsigned short fx_delay(int val);
+-static unsigned short fx_attack(int val);
+-static unsigned short fx_hold(int val);
+-static unsigned short fx_decay(int val);
+-static unsigned short fx_the_value(int val);
+-static unsigned short fx_twice_value(int val);
+-static unsigned short fx_conv_pitch(int val);
+-static unsigned short fx_conv_Q(int val);
+-
+-/* function for each NRPN */ /* [range] units */
+-#define fx_env1_delay fx_delay /* [0,5900] 4msec */
+-#define fx_env1_attack fx_attack /* [0,5940] 1msec */
+-#define fx_env1_hold fx_hold /* [0,8191] 1msec */
+-#define fx_env1_decay fx_decay /* [0,5940] 4msec */
+-#define fx_env1_release fx_decay /* [0,5940] 4msec */
+-#define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */
+-#define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */
+-#define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */
+-
+-#define fx_env2_delay fx_delay /* [0,5900] 4msec */
+-#define fx_env2_attack fx_attack /* [0,5940] 1msec */
+-#define fx_env2_hold fx_hold /* [0,8191] 1msec */
+-#define fx_env2_decay fx_decay /* [0,5940] 4msec */
+-#define fx_env2_release fx_decay /* [0,5940] 4msec */
+-#define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */
+-
+-#define fx_lfo1_delay fx_delay /* [0,5900] 4msec */
+-#define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */
+-#define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */
+-#define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */
+-#define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */
+-
+-#define fx_lfo2_delay fx_delay /* [0,5900] 4msec */
+-#define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */
+-#define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */
+-
+-#define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */
+-#define fx_chorus fx_the_value /* [0,255] -- */
+-#define fx_reverb fx_the_value /* [0,255] -- */
+-#define fx_cutoff fx_twice_value /* [0,127] 62Hz */
+-#define fx_filterQ fx_conv_Q /* [0,127] -- */
+-
+-static unsigned short fx_delay(int val)
+-{
+- return (unsigned short)calc_parm_delay(val);
+-}
+-
+-static unsigned short fx_attack(int val)
+-{
+- return (unsigned short)calc_parm_attack(val);
+-}
+-
+-static unsigned short fx_hold(int val)
+-{
+- return (unsigned short)calc_parm_hold(val);
+-}
+-
+-static unsigned short fx_decay(int val)
+-{
+- return (unsigned short)calc_parm_decay(val);
+-}
+-
+-static unsigned short fx_the_value(int val)
+-{
+- return (unsigned short)(val & 0xff);
+-}
+-
+-static unsigned short fx_twice_value(int val)
+-{
+- return (unsigned short)((val * 2) & 0xff);
+-}
+-
+-static unsigned short fx_conv_pitch(int val)
+-{
+- return (short)(val * 4096 / 1200);
+-}
+-
+-static unsigned short fx_conv_Q(int val)
+-{
+- return (unsigned short)((val / 8) & 0xff);
+-}
+-
+-
+-static ConvTable awe_effects[] =
+-{
+- { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay},
+- { 1, AWE_FX_LFO1_FREQ, fx_lfo1_freq},
+- { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay},
+- { 3, AWE_FX_LFO2_FREQ, fx_lfo2_freq},
+-
+- { 4, AWE_FX_ENV1_DELAY, fx_env1_delay},
+- { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack},
+- { 6, AWE_FX_ENV1_HOLD, fx_env1_hold},
+- { 7, AWE_FX_ENV1_DECAY, fx_env1_decay},
+- { 8, AWE_FX_ENV1_SUSTAIN, fx_env1_sustain},
+- { 9, AWE_FX_ENV1_RELEASE, fx_env1_release},
+-
+- {10, AWE_FX_ENV2_DELAY, fx_env2_delay},
+- {11, AWE_FX_ENV2_ATTACK, fx_env2_attack},
+- {12, AWE_FX_ENV2_HOLD, fx_env2_hold},
+- {13, AWE_FX_ENV2_DECAY, fx_env2_decay},
+- {14, AWE_FX_ENV2_SUSTAIN, fx_env2_sustain},
+- {15, AWE_FX_ENV2_RELEASE, fx_env2_release},
+-
+- {16, AWE_FX_INIT_PITCH, fx_init_pitch},
+- {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch},
+- {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch},
+- {19, AWE_FX_ENV1_PITCH, fx_env1_pitch},
+- {20, AWE_FX_LFO1_VOLUME, fx_lfo1_volume},
+- {21, AWE_FX_CUTOFF, fx_cutoff},
+- {22, AWE_FX_FILTERQ, fx_filterQ},
+- {23, AWE_FX_LFO1_CUTOFF, fx_lfo1_cutoff},
+- {24, AWE_FX_ENV1_CUTOFF, fx_env1_cutoff},
+- {25, AWE_FX_CHORUS, fx_chorus},
+- {26, AWE_FX_REVERB, fx_reverb},
+-};
+-
+-static int num_awe_effects = numberof(awe_effects);
+-
+-
+-/*
+- * GS(SC88) NRPN effects; still experimental
+- */
+-
+-/* cutoff: quarter semitone step, max=255 */
+-static unsigned short gs_cutoff(int val)
+-{
+- return (val - 64) * gs_sense[FX_CUTOFF] / 50;
+-}
+-
+-/* resonance: 0 to 15(max) */
+-static unsigned short gs_filterQ(int val)
+-{
+- return (val - 64) * gs_sense[FX_RESONANCE] / 50;
+-}
+-
+-/* attack: */
+-static unsigned short gs_attack(int val)
+-{
+- return -(val - 64) * gs_sense[FX_ATTACK] / 50;
+-}
+-
+-/* decay: */
+-static unsigned short gs_decay(int val)
+-{
+- return -(val - 64) * gs_sense[FX_RELEASE] / 50;
+-}
+-
+-/* release: */
+-static unsigned short gs_release(int val)
+-{
+- return -(val - 64) * gs_sense[FX_RELEASE] / 50;
+-}
+-
+-/* vibrato freq: 0.042Hz step, max=255 */
+-static unsigned short gs_vib_rate(int val)
+-{
+- return (val - 64) * gs_sense[FX_VIBRATE] / 50;
+-}
+-
+-/* vibrato depth: max=127, 1 octave */
+-static unsigned short gs_vib_depth(int val)
+-{
+- return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;
+-}
+-
+-/* vibrato delay: -0.725msec step */
+-static unsigned short gs_vib_delay(int val)
+-{
+- return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
+-}
+-
+-static ConvTable gs_effects[] =
+-{
+- {32, AWE_FX_CUTOFF, gs_cutoff},
+- {33, AWE_FX_FILTERQ, gs_filterQ},
+- {99, AWE_FX_ENV2_ATTACK, gs_attack},
+- {100, AWE_FX_ENV2_DECAY, gs_decay},
+- {102, AWE_FX_ENV2_RELEASE, gs_release},
+- {8, AWE_FX_LFO1_FREQ, gs_vib_rate},
+- {9, AWE_FX_LFO1_VOLUME, gs_vib_depth},
+- {10, AWE_FX_LFO1_DELAY, gs_vib_delay},
+-};
+-
+-static int num_gs_effects = numberof(gs_effects);
+-
+-
+-/*
+- * NRPN events: accept as AWE32/SC88 specific controls
+- */
+-
+-static void midi_nrpn_event(MidiStatus *st)
+-{
+- if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) {
+- if (! msb_bit) /* both MSB/LSB necessary */
+- send_converted_effect(awe_effects, num_awe_effects,
+- st, rpn_lsb[st->chan],
+- rpn_val[st->chan] - 8192);
+- } else if (rpn_msb[st->chan] == 1) {
+- if (msb_bit) /* only MSB is valid */
+- add_converted_effect(gs_effects, num_gs_effects,
+- st, rpn_lsb[st->chan],
+- rpn_val[st->chan] / 128);
+- }
+-}
+-
+-
+-/*
+- * XG control effects; still experimental
+- */
+-
+-/* cutoff: quarter semitone step, max=255 */
+-static unsigned short xg_cutoff(int val)
+-{
+- return (val - 64) * xg_sense[FX_CUTOFF] / 64;
+-}
+-
+-/* resonance: 0(open) to 15(most nasal) */
+-static unsigned short xg_filterQ(int val)
+-{
+- return (val - 64) * xg_sense[FX_RESONANCE] / 64;
+-}
+-
+-/* attack: */
+-static unsigned short xg_attack(int val)
+-{
+- return -(val - 64) * xg_sense[FX_ATTACK] / 64;
+-}
+-
+-/* release: */
+-static unsigned short xg_release(int val)
+-{
+- return -(val - 64) * xg_sense[FX_RELEASE] / 64;
+-}
+-
+-static ConvTable xg_effects[] =
+-{
+- {71, AWE_FX_CUTOFF, xg_cutoff},
+- {74, AWE_FX_FILTERQ, xg_filterQ},
+- {72, AWE_FX_ENV2_RELEASE, xg_release},
+- {73, AWE_FX_ENV2_ATTACK, xg_attack},
+-};
+-
+-static int num_xg_effects = numberof(xg_effects);
+-
+-static int xg_control_change(MidiStatus *st, int cmd, int val)
+-{
+- return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val);
+-}
+-
+-#endif /* CONFIG_AWE32_MIDIEMU */
+-
+-
+-/*----------------------------------------------------------------*/
+-
+-
+-/*
+- * initialization of AWE driver
+- */
+-
+-static void
+-awe_initialize(void)
+-{
+- DEBUG(0,printk("AWE32: initializing..\n"));
+-
+- /* initialize hardware configuration */
+- awe_poke(AWE_HWCF1, 0x0059);
+- awe_poke(AWE_HWCF2, 0x0020);
+-
+- /* disable audio; this seems to reduce a clicking noise a bit.. */
+- awe_poke(AWE_HWCF3, 0);
+-
+- /* initialize audio channels */
+- awe_init_audio();
+-
+- /* initialize DMA */
+- awe_init_dma();
+-
+- /* initialize init array */
+- awe_init_array();
+-
+- /* check DRAM memory size */
+- awe_check_dram();
+-
+- /* initialize the FM section of the AWE32 */
+- awe_init_fm();
+-
+- /* set up voice envelopes */
+- awe_tweak();
+-
+- /* enable audio */
+- awe_poke(AWE_HWCF3, 0x0004);
+-
+- /* set default values */
+- awe_init_ctrl_parms(TRUE);
+-
+- /* set equalizer */
+- awe_update_equalizer();
+-
+- /* set reverb & chorus modes */
+- awe_update_reverb_mode();
+- awe_update_chorus_mode();
+-}
+-
+-
+-/*
+- * Core Device Management Functions
+- */
+-
+-/* store values to i/o port array */
+-static void setup_ports(int port1, int port2, int port3)
+-{
+- awe_ports[0] = port1;
+- if (port2 == 0)
+- port2 = port1 + 0x400;
+- awe_ports[1] = port2;
+- awe_ports[2] = port2 + 2;
+- if (port3 == 0)
+- port3 = port1 + 0x800;
+- awe_ports[3] = port3;
+- awe_ports[4] = port3 + 2;
+-
+- port_setuped = TRUE;
+-}
+-
+-/*
+- * port request
+- * 0x620-623, 0xA20-A23, 0xE20-E23
+- */
+-
+-static int
+-awe_request_region(void)
+-{
+- if (! port_setuped)
+- return 0;
+- if (! request_region(awe_ports[0], 4, "sound driver (AWE32)"))
+- return 0;
+- if (! request_region(awe_ports[1], 4, "sound driver (AWE32)"))
+- goto err_out;
+- if (! request_region(awe_ports[3], 4, "sound driver (AWE32)"))
+- goto err_out1;
+- return 1;
+-err_out1:
+- release_region(awe_ports[1], 4);
+-err_out:
+- release_region(awe_ports[0], 4);
+- return 0;
+-}
+-
+-static void
+-awe_release_region(void)
+-{
+- if (! port_setuped) return;
+- release_region(awe_ports[0], 4);
+- release_region(awe_ports[1], 4);
+- release_region(awe_ports[3], 4);
+-}
+-
+-static int awe_attach_device(void)
+-{
+- if (awe_present) return 0; /* for OSS38.. called twice? */
+-
+- /* reserve I/O ports for awedrv */
+- if (! awe_request_region()) {
+- printk(KERN_ERR "AWE32: I/O area already used.\n");
+- return 0;
+- }
+-
+- /* set buffers to NULL */
+- sfhead = sftail = NULL;
+-
+- my_dev = sound_alloc_synthdev();
+- if (my_dev == -1) {
+- printk(KERN_ERR "AWE32 Error: too many synthesizers\n");
+- awe_release_region();
+- return 0;
+- }
+-
+- voice_alloc = &awe_operations.alloc;
+- voice_alloc->max_voice = awe_max_voices;
+- synth_devs[my_dev] = &awe_operations;
+-
+-#ifdef CONFIG_AWE32_MIXER
+- attach_mixer();
+-#endif
+-#ifdef CONFIG_AWE32_MIDIEMU
+- attach_midiemu();
+-#endif
+-
+- /* clear all samples */
+- awe_reset_samples();
+-
+- /* initialize AWE32 hardware */
+- awe_initialize();
+-
+- sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
+- AWEDRV_VERSION, memsize/1024);
+- printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024);
+-
+- awe_present = TRUE;
+-
+- return 1;
+-}
+-
+-static void awe_dettach_device(void)
+-{
+- if (awe_present) {
+- awe_reset_samples();
+- awe_release_region();
+- free_tables();
+-#ifdef CONFIG_AWE32_MIXER
+- unload_mixer();
+-#endif
+-#ifdef CONFIG_AWE32_MIDIEMU
+- unload_midiemu();
+-#endif
+- sound_unload_synthdev(my_dev);
+- awe_present = FALSE;
+- }
+-}
+-
+-
+-/*
+- * Legacy device Probing
+- */
+-
+-/* detect emu8000 chip on the specified address; from VV's guide */
+-
+-static int __init
+-awe_detect_base(int addr)
+-{
+- setup_ports(addr, 0, 0);
+- if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
+- return 0;
+- if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
+- return 0;
+- if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
+- return 0;
+- DEBUG(0,printk("AWE32 found at %x\n", addr));
+- return 1;
+-}
+-
+-static int __init awe_detect_legacy_devices(void)
+-{
+- int base;
+- for (base = 0x620; base <= 0x680; base += 0x20)
+- if (awe_detect_base(base)) {
+- awe_attach_device();
+- return 1;
+- }
+- DEBUG(0,printk("AWE32 Legacy detection failed\n"));
+- return 0;
+-}
+-
+-
+-/*
+- * PnP device Probing
+- */
+-
+-static struct pnp_device_id awe_pnp_ids[] = {
+- {.id = "CTL0021", .driver_data = 0}, /* AWE32 WaveTable */
+- {.id = "CTL0022", .driver_data = 0}, /* AWE64 WaveTable */
+- {.id = "CTL0023", .driver_data = 0}, /* AWE64 Gold WaveTable */
+- { } /* terminator */
+-};
+-
+-MODULE_DEVICE_TABLE(pnp, awe_pnp_ids);
+-
+-static int awe_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+-{
+- int io1, io2, io3;
+-
+- if (awe_present) {
+- printk(KERN_ERR "AWE32: This driver only supports one AWE32 device, skipping.\n");
+- }
+-
+- if (!pnp_port_valid(dev,0) ||
+- !pnp_port_valid(dev,1) ||
+- !pnp_port_valid(dev,2)) {
+- printk(KERN_ERR "AWE32: The PnP device does not have the required resources.\n");
+- return -EINVAL;
+- }
+- io1 = pnp_port_start(dev,0);
+- io2 = pnp_port_start(dev,1);
+- io3 = pnp_port_start(dev,2);
+- printk(KERN_INFO "AWE32: A PnP Wave Table was detected at IO's %#x,%#x,%#x.\n",
+- io1, io2, io3);
+- setup_ports(io1, io2, io3);
+-
+- awe_attach_device();
+- return 0;
+-}
+-
+-static void awe_pnp_remove(struct pnp_dev *dev)
+-{
+- awe_dettach_device();
+-}
+-
+-static struct pnp_driver awe_pnp_driver = {
+- .name = "AWE32",
+- .id_table = awe_pnp_ids,
+- .probe = awe_pnp_probe,
+- .remove = awe_pnp_remove,
+-};
+-
+-static int __init awe_detect_pnp_devices(void)
+-{
+- int ret;
+-
+- ret = pnp_register_driver(&awe_pnp_driver);
+- if (ret<0)
+- printk(KERN_ERR "AWE32: PnP support is unavailable.\n");
+- return ret;
+-}
+-
+-
+-/*
+- * device / lowlevel (module) interface
+- */
+-
+-static int __init
+-awe_detect(void)
+-{
+- printk(KERN_INFO "AWE32: Probing for WaveTable...\n");
+- if (isapnp) {
+- if (awe_detect_pnp_devices()>=0)
+- return 1;
+- } else
+- printk(KERN_INFO "AWE32: Skipping PnP detection.\n");
+-
+- if (awe_detect_legacy_devices())
+- return 1;
+-
+- return 0;
+-}
+-
+-static int __init attach_awe(void)
+-{
+- return awe_detect() ? 0 : -ENODEV;
+-}
+-
+-static void __exit unload_awe(void)
+-{
+- pnp_unregister_driver(&awe_pnp_driver);
+- awe_dettach_device();
+-}
+-
+-
+-module_init(attach_awe);
+-module_exit(unload_awe);
+-
+-#ifndef MODULE
+-static int __init setup_awe(char *str)
+-{
+- /* io, memsize, isapnp */
+- int ints[4];
+-
+- str = get_options(str, ARRAY_SIZE(ints), ints);
+-
+- io = ints[1];
+- memsize = ints[2];
+- isapnp = ints[3];
+-
+- return 1;
+-}
+-
+-__setup("awe=", setup_awe);
+-#endif
+diff --git a/sound/oss/awe_wave.h b/sound/oss/awe_wave.h
+deleted file mode 100644
+index a3aa018..0000000
+--- a/sound/oss/awe_wave.h
++++ /dev/null
+@@ -1,77 +0,0 @@
+-/*
+- * sound/awe_config.h
+- *
+- * Configuration of AWE32/SB32/AWE64 wave table synth driver.
+- * version 0.4.4; Jan. 4, 2000
+- *
+- * Copyright (C) 1996-1998 Takashi Iwai
+- *
+- * 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.
+- */
+-
+-/*
+- * chorus & reverb effects send for FM chip: from 0 to 0xff
+- * larger numbers often cause weird sounds.
+- */
+-
+-#define DEF_FM_CHORUS_DEPTH 0x10
+-#define DEF_FM_REVERB_DEPTH 0x10
+-
+-
+-/*
+- * other compile conditions
+- */
+-
+-/* initialize FM passthrough even without extended RAM */
+-#undef AWE_ALWAYS_INIT_FM
+-
+-/* debug on */
+-#define AWE_DEBUG_ON
+-
+-/* GUS compatible mode */
+-#define AWE_HAS_GUS_COMPATIBILITY
+-
+-/* add MIDI emulation by wavetable */
+-#define CONFIG_AWE32_MIDIEMU
+-
+-/* add mixer control of emu8000 equalizer */
+-#undef CONFIG_AWE32_MIXER
+-
+-/* use new volume calculation method as default */
+-#define AWE_USE_NEW_VOLUME_CALC
+-
+-/* check current volume target for searching empty voices */
+-#define AWE_CHECK_VTARGET
+-
+-/* allow sample sharing */
+-#define AWE_ALLOW_SAMPLE_SHARING
+-
+-/*
+- * AWE32 card configuration:
+- * uncomment the following lines *ONLY* when auto detection doesn't
+- * work properly on your machine.
+- */
+-
+-/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */
+-/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
+-
+-/*
+- * AWE driver version number
+- */
+-#define AWE_MAJOR_VERSION 0
+-#define AWE_MINOR_VERSION 4
+-#define AWE_TINY_VERSION 4
+-#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
+-#define AWEDRV_VERSION "0.4.4"
+diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
+index 324a81f..6ad3841 100644
+--- a/sound/oss/btaudio.c
++++ b/sound/oss/btaudio.c
+@@ -824,7 +824,7 @@ static char *irq_name[] = { "", "", "",
+ "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
+ "RIPERR", "PABORT", "OCERR", "SCERR" };
+
+-static irqreturn_t btaudio_irq(int irq, void *dev_id, struct pt_regs * regs)
++static irqreturn_t btaudio_irq(int irq, void *dev_id)
+ {
+ int count = 0;
+ u32 stat,astat;
+diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
+deleted file mode 100644
+index ea51aaf..0000000
+--- a/sound/oss/cmpci.c
++++ /dev/null
+@@ -1,3381 +0,0 @@
+-/*
+- * cmpci.c -- C-Media PCI audio driver.
+- *
+- * Copyright (C) 1999 C-media support (support at cmedia.com.tw)
+- *
+- * Based on the PCI drivers by Thomas Sailer (sailer at ife.ee.ethz.ch)
+- *
+- * For update, visit:
+- * http://www.cmedia.com.tw
+- *
+- * 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.
+- *
+- * Special thanks to David C. Niemi, Jan Pfeifer
+- *
+- *
+- * Module command line parameters:
+- * none so far
+- *
+- *
+- * Supported devices:
+- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+- * /dev/midi simple MIDI UART interface, no ioctl
+- *
+- * The card has both an FM and a Wavetable synth, but I have to figure
+- * out first how to drive them...
+- *
+- * Revision history
+- * 06.05.98 0.1 Initial release
+- * 10.05.98 0.2 Fixed many bugs, esp. ADC rate calculation
+- * First stab at a simple midi interface (no bells&whistles)
+- * 13.05.98 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
+- * set_dac_rate in the FMODE_WRITE case in cm_open
+- * Fix hwptr out of bounds (now mpg123 works)
+- * 14.05.98 0.4 Don't allow excessive interrupt rates
+- * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice
+- * 03.08.98 0.6 Do not include modversions.h
+- * Now mixer behaviour can basically be selected between
+- * "OSS documented" and "OSS actual" behaviour
+- * 31.08.98 0.7 Fix realplayer problems - dac.count issues
+- * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA
+- * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs
+- * 06.01.99 0.10 remove the silly SA_INTERRUPT flag.
+- * hopefully killed the egcs section type conflict
+- * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
+- * reported by Johan Maes <joma at telindus.be>
+- * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
+- * read/write cannot be executed
+- * 18.08.99 1.5 Only deallocate DMA buffer when unloading.
+- * 02.09.99 1.6 Enable SPDIF LOOP
+- * Change the mixer read back
+- * 21.09.99 2.33 Use RCS version as driver version.
+- * Add support for modem, S/PDIF loop and 4 channels.
+- * (8738 only)
+- * Fix bug cause x11amp cannot play.
+- *
+- * Fixes:
+- * Arnaldo Carvalho de Melo <acme at conectiva.com.br>
+- * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
+- * was calling prog_dmabuf with s->lock held, call missing
+- * unlock_kernel in cm_midi_release
+- * 08/10/2001 - use set_current_state in some more places
+- *
+- * Carlos Eduardo Gorges <carlos at techlinux.com.br>
+- * Fri May 25 2001
+- * - SMP support ( spin[un]lock* revision )
+- * - speaker mixer support
+- * Mon Aug 13 2001
+- * - optimizations and cleanups
+- *
+- * 03/01/2003 - open_mode fixes from Georg Acher <acher at in.tum.de>
+- * Simon Braunschmidt <brasimon at web.de>
+- * Sat Jan 31 2004
+- * - provide support for opl3 FM by releasing IO range after initialization
+- *
+- * ChenLi Tien <cltien at cmedia.com.tw>
+- * Mar 9 2004
+- * - Fix S/PDIF out if spdif_loop enabled
+- * - Load opl3 driver if enabled (fmio in proper range)
+- * - Load mpu401 if enabled (mpuio in proper range)
+- * Apr 5 2004
+- * - Fix DUAL_DAC dma synchronization bug
+- * - Check exist FM/MPU401 I/O before activate.
+- * - Add AFTM_S16_BE format support, so MPlayer/Xine can play AC3/mutlichannel
+- * on Mac
+- * - Change to support kernel 2.6 so only small patch needed
+- * - All parameters default to 0
+- * - Add spdif_out to send PCM through S/PDIF out jack
+- * - Add hw_copy to get 4-spaker output for general PCM/analog output
+- *
+- * Stefan Thater <stefan.thaeter at gmx.de>
+- * Apr 5 2004
+- * - Fix mute single channel for CD/Line-in/AUX-in
+- */
+-/*****************************************************************************/
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/interrupt.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/poll.h>
+-#include <linux/spinlock.h>
+-#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>
+-#include <asm/uaccess.h>
+-
+-#ifdef CONFIG_SOUND_CMPCI_MIDI
+-#include "sound_config.h"
+-#include "mpu401.h"
+-#endif
+-#ifdef CONFIG_SOUND_CMPCI_FM
+-#include "opl3.h"
+-#endif
+-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+-#include <linux/gameport.h>
+-#include <linux/mutex.h>
+-
+-#endif
+-
+-/* --------------------------------------------------------------------- */
+-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+-#undef DMABYTEIO
+-#define DBG(x) {}
+-/* --------------------------------------------------------------------- */
+-
+-#define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
+-
+-/* CM8338 registers definition ****************/
+-
+-#define CODEC_CMI_FUNCTRL0 (0x00)
+-#define CODEC_CMI_FUNCTRL1 (0x04)
+-#define CODEC_CMI_CHFORMAT (0x08)
+-#define CODEC_CMI_INT_HLDCLR (0x0C)
+-#define CODEC_CMI_INT_STATUS (0x10)
+-#define CODEC_CMI_LEGACY_CTRL (0x14)
+-#define CODEC_CMI_MISC_CTRL (0x18)
+-#define CODEC_CMI_TDMA_POS (0x1C)
+-#define CODEC_CMI_MIXER (0x20)
+-#define CODEC_SB16_DATA (0x22)
+-#define CODEC_SB16_ADDR (0x23)
+-#define CODEC_CMI_MIXER1 (0x24)
+-#define CODEC_CMI_MIXER2 (0x25)
+-#define CODEC_CMI_AUX_VOL (0x26)
+-#define CODEC_CMI_MISC (0x27)
+-#define CODEC_CMI_AC97 (0x28)
+-
+-#define CODEC_CMI_CH0_FRAME1 (0x80)
+-#define CODEC_CMI_CH0_FRAME2 (0x84)
+-#define CODEC_CMI_CH1_FRAME1 (0x88)
+-#define CODEC_CMI_CH1_FRAME2 (0x8C)
+-
+-#define CODEC_CMI_SPDIF_CTRL (0x90)
+-#define CODEC_CMI_MISC_CTRL2 (0x92)
+-
+-#define CODEC_CMI_EXT_REG (0xF0)
+-
+-/* Mixer registers for SB16 ******************/
+-
+-#define DSP_MIX_DATARESETIDX ((unsigned char)(0x00))
+-
+-#define DSP_MIX_MASTERVOLIDX_L ((unsigned char)(0x30))
+-#define DSP_MIX_MASTERVOLIDX_R ((unsigned char)(0x31))
+-#define DSP_MIX_VOICEVOLIDX_L ((unsigned char)(0x32))
+-#define DSP_MIX_VOICEVOLIDX_R ((unsigned char)(0x33))
+-#define DSP_MIX_FMVOLIDX_L ((unsigned char)(0x34))
+-#define DSP_MIX_FMVOLIDX_R ((unsigned char)(0x35))
+-#define DSP_MIX_CDVOLIDX_L ((unsigned char)(0x36))
+-#define DSP_MIX_CDVOLIDX_R ((unsigned char)(0x37))
+-#define DSP_MIX_LINEVOLIDX_L ((unsigned char)(0x38))
+-#define DSP_MIX_LINEVOLIDX_R ((unsigned char)(0x39))
+-
+-#define DSP_MIX_MICVOLIDX ((unsigned char)(0x3A))
+-#define DSP_MIX_SPKRVOLIDX ((unsigned char)(0x3B))
+-
+-#define DSP_MIX_OUTMIXIDX ((unsigned char)(0x3C))
+-
+-#define DSP_MIX_ADCMIXIDX_L ((unsigned char)(0x3D))
+-#define DSP_MIX_ADCMIXIDX_R ((unsigned char)(0x3E))
+-
+-#define DSP_MIX_INGAINIDX_L ((unsigned char)(0x3F))
+-#define DSP_MIX_INGAINIDX_R ((unsigned char)(0x40))
+-#define DSP_MIX_OUTGAINIDX_L ((unsigned char)(0x41))
+-#define DSP_MIX_OUTGAINIDX_R ((unsigned char)(0x42))
+-
+-#define DSP_MIX_AGCIDX ((unsigned char)(0x43))
+-
+-#define DSP_MIX_TREBLEIDX_L ((unsigned char)(0x44))
+-#define DSP_MIX_TREBLEIDX_R ((unsigned char)(0x45))
+-#define DSP_MIX_BASSIDX_L ((unsigned char)(0x46))
+-#define DSP_MIX_BASSIDX_R ((unsigned char)(0x47))
+-#define DSP_MIX_EXTENSION ((unsigned char)(0xf0))
+-// pseudo register for AUX
+-#define DSP_MIX_AUXVOL_L ((unsigned char)(0x50))
+-#define DSP_MIX_AUXVOL_R ((unsigned char)(0x51))
+-
+-// I/O length
+-#define CM_EXTENT_CODEC 0x100
+-#define CM_EXTENT_MIDI 0x2
+-#define CM_EXTENT_SYNTH 0x4
+-#define CM_EXTENT_GAME 0x8
+-
+-// Function Control Register 0 (00h)
+-#define CHADC0 0x01
+-#define CHADC1 0x02
+-#define PAUSE0 0x04
+-#define PAUSE1 0x08
+-
+-// Function Control Register 0+2 (02h)
+-#define CHEN0 0x01
+-#define CHEN1 0x02
+-#define RST_CH0 0x04
+-#define RST_CH1 0x08
+-
+-// Function Control Register 1 (04h)
+-#define JYSTK_EN 0x02
+-#define UART_EN 0x04
+-#define SPDO2DAC 0x40
+-#define SPDFLOOP 0x80
+-
+-// Function Control Register 1+1 (05h)
+-#define SPDF_0 0x01
+-#define SPDF_1 0x02
+-#define ASFC 0x1c
+-#define DSFC 0xe0
+-#define SPDIF2DAC (SPDF_1 << 8 | SPDO2DAC)
+-
+-// Channel Format Register (08h)
+-#define CM_CFMT_STEREO 0x01
+-#define CM_CFMT_16BIT 0x02
+-#define CM_CFMT_MASK 0x03
+-#define POLVALID 0x20
+-#define INVSPDIFI 0x80
+-
+-// Channel Format Register+2 (0ah)
+-#define SPD24SEL 0x20
+-
+-// Channel Format Register+3 (0bh)
+-#define CHB3D 0x20
+-#define CHB3D5C 0x80
+-
+-// Interrupt Hold/Clear Register+2 (0eh)
+-#define CH0_INT_EN 0x01
+-#define CH1_INT_EN 0x02
+-
+-// Interrupt Register (10h)
+-#define CHINT0 0x01
+-#define CHINT1 0x02
+-#define CH0BUSY 0x04
+-#define CH1BUSY 0x08
+-
+-// Legacy Control/Status Register+1 (15h)
+-#define EXBASEN 0x10
+-#define BASE2LIN 0x20
+-#define CENTR2LIN 0x40
+-#define CB2LIN (BASE2LIN | CENTR2LIN)
+-#define CHB3D6C 0x80
+-
+-// Legacy Control/Status Register+2 (16h)
+-#define DAC2SPDO 0x20
+-#define SPDCOPYRHT 0x40
+-#define ENSPDOUT 0x80
+-
+-// Legacy Control/Status Register+3 (17h)
+-#define FMSEL 0x03
+-#define VSBSEL 0x0c
+-#define VMPU 0x60
+-#define NXCHG 0x80
+-
+-// Miscellaneous Control Register (18h)
+-#define REAR2LIN 0x20
+-#define MUTECH1 0x40
+-#define ENCENTER 0x80
+-
+-// Miscellaneous Control Register+1 (19h)
+-#define SELSPDIFI2 0x01
+-#define SPDF_AC97 0x80
+-
+-// Miscellaneous Control Register+2 (1ah)
+-#define AC3_EN 0x04
+-#define FM_EN 0x08
+-#define SPD32SEL 0x20
+-#define XCHGDAC 0x40
+-#define ENDBDAC 0x80
+-
+-// Miscellaneous Control Register+3 (1bh)
+-#define SPDIFI48K 0x01
+-#define SPDO5V 0x02
+-#define N4SPK3D 0x04
+-#define RESET 0x40
+-#define PWD 0x80
+-#define SPDIF48K (SPDIFI48K << 24 | SPDF_AC97 << 8)
+-
+-// Mixer1 (24h)
+-#define CDPLAY 0x01
+-#define X3DEN 0x02
+-#define REAR2FRONT 0x10
+-#define SPK4 0x20
+-#define WSMUTE 0x40
+-#define FMMUTE 0x80
+-
+-// Miscellaneous Register (27h)
+-#define SPDVALID 0x02
+-#define CENTR2MIC 0x04
+-
+-// Miscellaneous Register2 (92h)
+-#define SPD32KFMT 0x10
+-
+-#define CM_CFMT_DACSHIFT 2
+-#define CM_CFMT_ADCSHIFT 0
+-#define CM_FREQ_DACSHIFT 5
+-#define CM_FREQ_ADCSHIFT 2
+-#define RSTDAC RST_CH1
+-#define RSTADC RST_CH0
+-#define ENDAC CHEN1
+-#define ENADC CHEN0
+-#define PAUSEDAC PAUSE1
+-#define PAUSEADC PAUSE0
+-#define CODEC_CMI_ADC_FRAME1 CODEC_CMI_CH0_FRAME1
+-#define CODEC_CMI_ADC_FRAME2 CODEC_CMI_CH0_FRAME2
+-#define CODEC_CMI_DAC_FRAME1 CODEC_CMI_CH1_FRAME1
+-#define CODEC_CMI_DAC_FRAME2 CODEC_CMI_CH1_FRAME2
+-#define DACINT CHINT1
+-#define ADCINT CHINT0
+-#define DACBUSY CH1BUSY
+-#define ADCBUSY CH0BUSY
+-#define ENDACINT CH1_INT_EN
+-#define ENADCINT CH0_INT_EN
+-
+-static const unsigned sample_size[] = { 1, 2, 2, 4 };
+-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+-
+-#define SND_DEV_DSP16 5
+-
+-#define NR_DEVICE 3 /* maximum number of devices */
+-
+-#define set_dac1_rate set_adc_rate
+-#define set_dac1_rate_unlocked set_adc_rate_unlocked
+-#define stop_dac1 stop_adc
+-#define stop_dac1_unlocked stop_adc_unlocked
+-#define get_dmadac1 get_dmaadc
+-
+-static unsigned int devindex = 0;
+-
+-//*********************************************/
+-
+-struct cm_state {
+- /* magic */
+- unsigned int magic;
+-
+- /* list of cmedia devices */
+- struct list_head devs;
+-
+- /* the corresponding pci_dev structure */
+- struct pci_dev *dev;
+-
+- int dev_audio; /* soundcore stuff */
+- int dev_mixer;
+-
+- unsigned int iosb, iobase, iosynth,
+- iomidi, iogame, irq; /* hardware resources */
+- unsigned short deviceid; /* pci_id */
+-
+- struct { /* mixer stuff */
+- unsigned int modcnt;
+- unsigned short vol[13];
+- } mix;
+-
+- unsigned int rateadc, ratedac; /* wave stuff */
+- unsigned char fmt, enable;
+-
+- spinlock_t lock;
+- struct mutex open_mutex;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+-
+- struct dmabuf {
+- void *rawbuf;
+- dma_addr_t dmaaddr;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- unsigned hwptr, swptr;
+- unsigned total_bytes;
+- int count;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+-
+- unsigned fragsize; /* redundant, but makes calculations easier */
+- unsigned dmasize;
+- unsigned fragsamples;
+- unsigned dmasamples;
+-
+- unsigned mapped:1; /* OSS stuff */
+- unsigned ready:1;
+- unsigned endcleared:1;
+- unsigned enabled:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac, dma_adc;
+-
+-#ifdef CONFIG_SOUND_CMPCI_MIDI
+- int midi_devc;
+- struct address_info mpu_data;
+-#endif
+-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+- struct gameport *gameport;
+-#endif
+-
+- int chip_version;
+- int max_channels;
+- int curr_channels;
+- int capability; /* HW capability, various for chip versions */
+-
+- int status; /* HW or SW state */
+-
+- int spdif_counter; /* spdif frame counter */
+-};
+-
+-/* flags used for capability */
+-#define CAN_AC3_HW 0x00000001 /* 037 or later */
+-#define CAN_AC3_SW 0x00000002 /* 033 or later */
+-#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW)
+-#define CAN_DUAL_DAC 0x00000004 /* 033 or later */
+-#define CAN_MULTI_CH_HW 0x00000008 /* 039 or later */
+-#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC)
+-#define CAN_LINE_AS_REAR 0x00000010 /* 033 or later */
+-#define CAN_LINE_AS_BASS 0x00000020 /* 039 or later */
+-#define CAN_MIC_AS_BASS 0x00000040 /* 039 or later */
+-
+-/* flags used for status */
+-#define DO_AC3_HW 0x00000001
+-#define DO_AC3_SW 0x00000002
+-#define DO_AC3 (DO_AC3_HW | DO_AC3_SW)
+-#define DO_DUAL_DAC 0x00000004
+-#define DO_MULTI_CH_HW 0x00000008
+-#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC)
+-#define DO_LINE_AS_REAR 0x00000010 /* 033 or later */
+-#define DO_LINE_AS_BASS 0x00000020 /* 039 or later */
+-#define DO_MIC_AS_BASS 0x00000040 /* 039 or later */
+-#define DO_SPDIF_OUT 0x00000100
+-#define DO_SPDIF_IN 0x00000200
+-#define DO_SPDIF_LOOP 0x00000400
+-#define DO_BIGENDIAN_W 0x00001000 /* used in PowerPC */
+-#define DO_BIGENDIAN_R 0x00002000 /* used in PowerPC */
+-
+-static LIST_HEAD(devs);
+-
+-static int mpuio;
+-static int fmio;
+-static int joystick;
+-static int spdif_inverse;
+-static int spdif_loop;
+-static int spdif_out;
+-static int use_line_as_rear;
+-static int use_line_as_bass;
+-static int use_mic_as_bass;
+-static int mic_boost;
+-static int hw_copy;
+-module_param(mpuio, int, 0);
+-module_param(fmio, int, 0);
+-module_param(joystick, bool, 0);
+-module_param(spdif_inverse, bool, 0);
+-module_param(spdif_loop, bool, 0);
+-module_param(spdif_out, bool, 0);
+-module_param(use_line_as_rear, bool, 0);
+-module_param(use_line_as_bass, bool, 0);
+-module_param(use_mic_as_bass, bool, 0);
+-module_param(mic_boost, bool, 0);
+-module_param(hw_copy, bool, 0);
+-MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
+-MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
+-MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
+-MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
+-MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
+-MODULE_PARM_DESC(spdif_out, "(1/0) Send PCM to S/PDIF-out (PCM volume will not function)");
+-MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
+-MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
+-MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center");
+-MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost");
+-MODULE_PARM_DESC(hw_copy, "Copy front channel to surround channel");
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline unsigned ld2(unsigned int x)
+-{
+- unsigned exp=16,l=5,r=0;
+- static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000};
+-
+- /* num: 2, 4, 16, 256, 65536 */
+- /* exp: 1, 2, 4, 8, 16 */
+-
+- while(l--) {
+- if( x >= num[l] ) {
+- if(num[l]>2) x >>= exp;
+- r+=exp;
+- }
+- exp>>=1;
+- }
+-
+- return r;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
+-{
+- outb((inb(addr) & mask) | value, addr);
+-}
+-
+-static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
+-{
+- outw((inw(addr) & mask) | value, addr);
+-}
+-
+-static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
+-{
+- outl((inl(addr) & mask) | value, addr);
+-}
+-
+-static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
+-{
+- if (addr)
+- outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
+- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0);
+-}
+-
+-static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
+-{
+- outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
+- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC0);
+-}
+-
+-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+-{
+- outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1);
+- outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2);
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0);
+- if (s->status & DO_DUAL_DAC)
+- set_dmadac1(s, 0, count);
+-}
+-
+-static void set_countadc(struct cm_state *s, unsigned count)
+-{
+- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2);
+-}
+-
+-static void set_countdac(struct cm_state *s, unsigned count)
+-{
+- outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2);
+- if (s->status & DO_DUAL_DAC)
+- set_countadc(s, count);
+-}
+-
+-static unsigned get_dmadac(struct cm_state *s)
+-{
+- unsigned int curr_addr;
+-
+- curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1;
+- curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
+- curr_addr = s->dma_dac.dmasize - curr_addr;
+-
+- return curr_addr;
+-}
+-
+-static unsigned get_dmaadc(struct cm_state *s)
+-{
+- unsigned int curr_addr;
+-
+- curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1;
+- curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
+- curr_addr = s->dma_adc.dmasize - curr_addr;
+-
+- return curr_addr;
+-}
+-
+-static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
+-{
+- unsigned char regval, pseudo;
+-
+- // pseudo register
+- if (idx == DSP_MIX_AUXVOL_L) {
+- data >>= 4;
+- data &= 0x0f;
+- regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f;
+- outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
+- return;
+- }
+- if (idx == DSP_MIX_AUXVOL_R) {
+- data &= 0xf0;
+- regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0;
+- outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
+- return;
+- }
+- outb(idx, s->iobase + CODEC_SB16_ADDR);
+- udelay(10);
+- // pseudo bits
+- if (idx == DSP_MIX_OUTMIXIDX) {
+- pseudo = data & ~0x1f;
+- pseudo >>= 1;
+- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30;
+- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
+- }
+- if (idx == DSP_MIX_ADCMIXIDX_L) {
+- pseudo = data & 0x80;
+- pseudo >>= 1;
+- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40;
+- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
+- }
+- if (idx == DSP_MIX_ADCMIXIDX_R) {
+- pseudo = data & 0x80;
+- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80;
+- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
+- }
+- outb(data, s->iobase + CODEC_SB16_DATA);
+- udelay(10);
+-}
+-
+-static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
+-{
+- unsigned char v, pseudo;
+-
+- // pseudo register
+- if (idx == DSP_MIX_AUXVOL_L) {
+- v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f;
+- v <<= 4;
+- return v;
+- }
+- if (idx == DSP_MIX_AUXVOL_L) {
+- v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0;
+- return v;
+- }
+- outb(idx, s->iobase + CODEC_SB16_ADDR);
+- udelay(10);
+- v = inb(s->iobase + CODEC_SB16_DATA);
+- udelay(10);
+- // pseudo bits
+- if (idx == DSP_MIX_OUTMIXIDX) {
+- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30;
+- pseudo <<= 1;
+- v |= pseudo;
+- }
+- if (idx == DSP_MIX_ADCMIXIDX_L) {
+- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40;
+- pseudo <<= 1;
+- v |= pseudo;
+- }
+- if (idx == DSP_MIX_ADCMIXIDX_R) {
+- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80;
+- v |= pseudo;
+- }
+- return v;
+-}
+-
+-static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
+-{
+- if (mask && s->chip_version > 0) { /* 8338 cannot keep this */
+- s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
+- udelay(10);
+- }
+- s->fmt = (s->fmt & mask) | data;
+- outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+- udelay(10);
+-}
+-
+-static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- set_fmt_unlocked(s,mask,data);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
+-{
+- outb(idx, s->iobase + CODEC_SB16_ADDR);
+- udelay(10);
+- outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
+- udelay(10);
+-}
+-
+-static struct {
+- unsigned rate;
+- unsigned lower;
+- unsigned upper;
+- unsigned char freq;
+-} rate_lookup[] =
+-{
+- { 5512, (0 + 5512) / 2, (5512 + 8000) / 2, 0 },
+- { 8000, (5512 + 8000) / 2, (8000 + 11025) / 2, 4 },
+- { 11025, (8000 + 11025) / 2, (11025 + 16000) / 2, 1 },
+- { 16000, (11025 + 16000) / 2, (16000 + 22050) / 2, 5 },
+- { 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 },
+- { 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 },
+- { 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 },
+- { 48000, (44100 + 48000) / 2, 48000, 7 }
+-};
+-
+-static void set_spdif_copyright(struct cm_state *s, int spdif_copyright)
+-{
+- /* enable SPDIF-in Copyright */
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0);
+-}
+-
+-static void set_spdif_loop(struct cm_state *s, int spdif_loop)
+-{
+- /* enable SPDIF loop */
+- if (spdif_loop) {
+- s->status |= DO_SPDIF_LOOP;
+- /* turn on spdif-in to spdif-out */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP);
+- } else {
+- s->status &= ~DO_SPDIF_LOOP;
+- /* turn off spdif-in to spdif-out */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0);
+- }
+-}
+-
+-static void set_spdif_monitor(struct cm_state *s, int channel)
+-{
+- // SPDO2DAC
+- maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0);
+- // CDPLAY
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0);
+-}
+-
+-static void set_spdifout_level(struct cm_state *s, int level5v)
+-{
+- /* SPDO5V */
+- if (s->chip_version > 0)
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0);
+-}
+-
+-static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse)
+-{
+- if (s->chip_version == 0) /* 8338 has not this feature */
+- return;
+- if (spdif_inverse) {
+- /* turn on spdif-in inverse */
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI);
+- else
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
+- } else {
+- /* turn off spdif-ininverse */
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0);
+- else
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
+- }
+-}
+-
+-static void set_spdifin_channel2(struct cm_state *s, int channel2)
+-{
+- /* SELSPDIFI2 */
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0);
+-}
+-
+-static void set_spdifin_valid(struct cm_state *s, int valid)
+-{
+- /* SPDVALID */
+- maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0);
+-}
+-
+-static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
+-{
+- if (rate != 48000 && rate != 44100)
+- rate = 0;
+- if (rate == 48000 || rate == 44100) {
+- set_spdif_loop(s, 0);
+- // SPDF_1
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
+- // SPDIFI48K SPDF_AC97
+- maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
+- if (s->chip_version >= 55)
+- // SPD32KFMT
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL2, ~SPD32KFMT, rate == 48000 ? SPD32KFMT : 0);
+- if (s->chip_version > 0)
+- // ENSPDOUT
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT);
+- // monitor SPDIF out
+- set_spdif_monitor(s, 2);
+- s->status |= DO_SPDIF_OUT;
+- } else {
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0);
+- // monitor none
+- set_spdif_monitor(s, 0);
+- s->status &= ~DO_SPDIF_OUT;
+- }
+-}
+-
+-static void set_spdifout(struct cm_state *s, unsigned rate)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- set_spdifout_unlocked(s,rate);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void set_spdifin_unlocked(struct cm_state *s, unsigned rate)
+-{
+- if (rate == 48000 || rate == 44100) {
+- // SPDF_1
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
+- // SPDIFI48K SPDF_AC97
+- maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
+- s->status |= DO_SPDIF_IN;
+- } else {
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
+- s->status &= ~DO_SPDIF_IN;
+- }
+-}
+-
+-static void set_spdifin(struct cm_state *s, unsigned rate)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- set_spdifin_unlocked(s,rate);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* find parity for bit 4~30 */
+-static unsigned parity(unsigned data)
+-{
+- unsigned parity = 0;
+- int counter = 4;
+-
+- data >>= 4; // start from bit 4
+- while (counter <= 30) {
+- if (data & 1)
+- parity++;
+- data >>= 1;
+- counter++;
+- }
+- return parity & 1;
+-}
+-
+-static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
+-{
+- if (!(s->capability & CAN_AC3))
+- return;
+- /* enable AC3 */
+- if (rate && rate != 44100)
+- rate = 48000;
+- if (rate == 48000 || rate == 44100) {
+- // mute DAC
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE);
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0, MUTECH1);
+- // AC3EN for 039, 0x04
+- if (s->chip_version >= 39) {
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN);
+- if (s->chip_version == 55)
+- maskb(s->iobase + CODEC_CMI_SPDIF_CTRL, ~2, 0);
+- // AC3EN for 037, 0x10
+- } else if (s->chip_version == 37)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
+- if (s->capability & CAN_AC3_HW) {
+- // SPD24SEL for 039, 0x20, but cannot be set
+- if (s->chip_version == 39)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL);
+- // SPD24SEL for 037, 0x02
+- else if (s->chip_version == 37)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0);
+-
+- s->status |= DO_AC3_HW;
+- } else {
+- // SPD32SEL for 037 & 039
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL);
+- // set 176K sample rate to fix 033 HW bug
+- if (s->chip_version == 33) {
+- if (rate == 48000)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
+- else
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+- }
+- s->status |= DO_AC3_SW;
+- }
+- } else {
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0);
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~MUTECH1, 0);
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~(SPD24SEL|0x12), 0);
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0);
+- if (s->chip_version == 33)
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+- if (s->chip_version >= 39)
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY);
+- s->status &= ~DO_AC3;
+- }
+- s->spdif_counter = 0;
+-}
+-
+-static void set_line_as_rear(struct cm_state *s, int use_line_as_rear)
+-{
+- if (!(s->capability & CAN_LINE_AS_REAR))
+- return;
+- if (use_line_as_rear) {
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4);
+- s->status |= DO_LINE_AS_REAR;
+- } else {
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0);
+- s->status &= ~DO_LINE_AS_REAR;
+- }
+-}
+-
+-static void set_line_as_bass(struct cm_state *s, int use_line_as_bass)
+-{
+- if (!(s->capability & CAN_LINE_AS_BASS))
+- return;
+- if (use_line_as_bass) {
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN);
+- s->status |= DO_LINE_AS_BASS;
+- } else {
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0);
+- s->status &= ~DO_LINE_AS_BASS;
+- }
+-}
+-
+-static void set_mic_as_bass(struct cm_state *s, int use_mic_as_bass)
+-{
+- if (!(s->capability & CAN_MIC_AS_BASS))
+- return;
+- if (use_mic_as_bass) {
+- maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04);
+- s->status |= DO_MIC_AS_BASS;
+- } else {
+- maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0);
+- s->status &= ~DO_MIC_AS_BASS;
+- }
+-}
+-
+-static void set_hw_copy(struct cm_state *s, int hw_copy)
+-{
+- if (s->max_channels > 2 && hw_copy)
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D);
+- else
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0);
+-}
+-
+-static void set_ac3(struct cm_state *s, unsigned rate)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- set_spdifout_unlocked(s, rate);
+- set_ac3_unlocked(s, rate);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size)
+-{
+- int i = size / 2;
+- unsigned long data;
+- unsigned short data16;
+- unsigned long *dst = (unsigned long *) dest;
+- unsigned short __user *src = (unsigned short __user *)source;
+- int err;
+-
+- do {
+- if ((err = __get_user(data16, src++)))
+- return err;
+- data = (unsigned long)le16_to_cpu(data16);
+- data <<= 12; // ok for 16-bit data
+- if (s->spdif_counter == 2 || s->spdif_counter == 3)
+- data |= 0x40000000; // indicate AC-3 raw data
+- if (parity(data))
+- data |= 0x80000000; // parity
+- if (s->spdif_counter == 0)
+- data |= 3; // preamble 'M'
+- else if (s->spdif_counter & 1)
+- data |= 5; // odd, 'W'
+- else
+- data |= 9; // even, 'M'
+- *dst++ = cpu_to_le32(data);
+- s->spdif_counter++;
+- if (s->spdif_counter == 384)
+- s->spdif_counter = 0;
+- } while (--i);
+-
+- return 0;
+-}
+-
+-static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
+-{
+- unsigned char freq = 4;
+- int i;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
+- rate = rate_lookup[i].rate;
+- freq = rate_lookup[i].freq;
+- break;
+- }
+- }
+- s->rateadc = rate;
+- freq <<= CM_FREQ_ADCSHIFT;
+-
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
+-}
+-
+-static void set_adc_rate(struct cm_state *s, unsigned rate)
+-{
+- unsigned long flags;
+- unsigned char freq = 4;
+- int i;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
+- rate = rate_lookup[i].rate;
+- freq = rate_lookup[i].freq;
+- break;
+- }
+- }
+- s->rateadc = rate;
+- freq <<= CM_FREQ_ADCSHIFT;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void set_dac_rate(struct cm_state *s, unsigned rate)
+-{
+- unsigned long flags;
+- unsigned char freq = 4;
+- int i;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
+- rate = rate_lookup[i].rate;
+- freq = rate_lookup[i].freq;
+- break;
+- }
+- }
+- s->ratedac = rate;
+- freq <<= CM_FREQ_DACSHIFT;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq);
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- if (s->curr_channels <= 2 && spdif_out)
+- set_spdifout(s, rate);
+- if (s->status & DO_DUAL_DAC)
+- set_dac1_rate(s, rate);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-static inline void reset_adc(struct cm_state *s)
+-{
+- /* reset bus master */
+- outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- udelay(10);
+- outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+-}
+-
+-static inline void reset_dac(struct cm_state *s)
+-{
+- /* reset bus master */
+- outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- udelay(10);
+- outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- if (s->status & DO_DUAL_DAC)
+- reset_adc(s);
+-}
+-
+-static inline void pause_adc(struct cm_state *s)
+-{
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC);
+-}
+-
+-static inline void pause_dac(struct cm_state *s)
+-{
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC);
+- if (s->status & DO_DUAL_DAC)
+- pause_adc(s);
+-}
+-
+-static inline void disable_adc(struct cm_state *s)
+-{
+- /* disable channel */
+- s->enable &= ~ENADC;
+- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- reset_adc(s);
+-}
+-
+-static inline void disable_dac(struct cm_state *s)
+-{
+- /* disable channel */
+- s->enable &= ~ENDAC;
+- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- reset_dac(s);
+- if (s->status & DO_DUAL_DAC)
+- disable_adc(s);
+-}
+-
+-static inline void enable_adc(struct cm_state *s)
+-{
+- if (!(s->enable & ENADC)) {
+- /* enable channel */
+- s->enable |= ENADC;
+- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- }
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0);
+-}
+-
+-static inline void enable_dac_unlocked(struct cm_state *s)
+-{
+- if (!(s->enable & ENDAC)) {
+- /* enable channel */
+- s->enable |= ENDAC;
+- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+- }
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0);
+-
+- if (s->status & DO_DUAL_DAC)
+- enable_adc(s);
+-}
+-
+-static inline void stop_adc_unlocked(struct cm_state *s)
+-{
+- if (s->enable & ENADC) {
+- /* disable interrupt */
+- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0);
+- disable_adc(s);
+- }
+-}
+-
+-static inline void stop_adc(struct cm_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- stop_adc_unlocked(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+-}
+-
+-static inline void stop_dac_unlocked(struct cm_state *s)
+-{
+- if (s->enable & ENDAC) {
+- /* disable interrupt */
+- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0);
+- disable_dac(s);
+- }
+- if (s->status & DO_DUAL_DAC)
+- stop_dac1_unlocked(s);
+-}
+-
+-static inline void stop_dac(struct cm_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- stop_dac_unlocked(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static inline void start_adc_unlocked(struct cm_state *s)
+-{
+- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+- && s->dma_adc.ready) {
+- /* enable interrupt */
+- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
+- enable_adc(s);
+- }
+-}
+-
+-static void start_adc(struct cm_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- start_adc_unlocked(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_dac1_unlocked(struct cm_state *s)
+-{
+- if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
+- /* enable interrupt */
+- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
+- enable_dac_unlocked(s);
+- }
+-}
+-
+-static void start_dac_unlocked(struct cm_state *s)
+-{
+- if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+- /* enable interrupt */
+- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT);
+- enable_dac_unlocked(s);
+- }
+- if (s->status & DO_DUAL_DAC)
+- start_dac1_unlocked(s);
+-}
+-
+-static void start_dac(struct cm_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- start_dac_unlocked(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static int prog_dmabuf(struct cm_state *s, unsigned rec);
+-
+-static int set_dac_channels(struct cm_state *s, int channels)
+-{
+- unsigned long flags;
+- static unsigned int fmmute = 0;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- if ((channels > 2) && (channels <= s->max_channels)
+- && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
+- set_spdifout_unlocked(s, 0);
+- if (s->capability & CAN_MULTI_CH_HW) {
+- // NXCHG
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG);
+- // CHB3D or CHB3D5C
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D);
+- // CHB3D6C
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0);
+- // ENCENTER
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0);
+- s->status |= DO_MULTI_CH_HW;
+- } else if (s->capability & CAN_DUAL_DAC) {
+- unsigned char fmtm = ~0, fmts = 0;
+- ssize_t ret;
+-
+- // ENDBDAC, turn on double DAC mode
+- // XCHGDAC, CH0 -> back, CH1->front
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC);
+- // mute FM
+- fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE;
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE);
+- s->status |= DO_DUAL_DAC;
+- // prepare secondary buffer
+- spin_unlock_irqrestore(&s->lock, flags);
+- ret = prog_dmabuf(s, 1);
+- if (ret) return ret;
+- spin_lock_irqsave(&s->lock, flags);
+-
+- // copy the hw state
+- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
+- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
+- // the HW only support 16-bit stereo
+- fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
+- fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
+- fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+- fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+-
+- set_fmt_unlocked(s, fmtm, fmts);
+- set_adc_rate_unlocked(s, s->ratedac);
+- }
+- // disable 4 speaker mode (analog duplicate)
+- set_hw_copy(s, 0);
+- s->curr_channels = channels;
+-
+- // enable jack redirect
+- set_line_as_rear(s, use_line_as_rear);
+- if (channels > 4) {
+- set_line_as_bass(s, use_line_as_bass);
+- set_mic_as_bass(s, use_mic_as_bass);
+- }
+- } else {
+- if (s->status & DO_MULTI_CH_HW) {
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0);
+- maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0);
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0);
+- } else if (s->status & DO_DUAL_DAC) {
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0);
+- maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute);
+- }
+- // enable 4 speaker mode (analog duplicate)
+- set_hw_copy(s, hw_copy);
+- s->status &= ~DO_MULTI_CH;
+- s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
+- // disable jack redirect
+- set_line_as_rear(s, hw_copy ? use_line_as_rear : 0);
+- set_line_as_bass(s, 0);
+- set_mic_as_bass(s, 0);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return s->curr_channels;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-static void dealloc_dmabuf(struct cm_state *s, struct dmabuf *db)
+-{
+- struct page *pstart, *pend;
+-
+- if (db->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
+- ClearPageReserved(pstart);
+- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
+- }
+- db->rawbuf = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-/* Ch1 is used for playback, Ch0 is used for recording */
+-
+-static int prog_dmabuf(struct cm_state *s, unsigned rec)
+-{
+- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+- unsigned rate = rec ? s->rateadc : s->ratedac;
+- int order;
+- unsigned bytepersec;
+- unsigned bufs;
+- struct page *pstart, *pend;
+- unsigned char fmt;
+- unsigned long flags;
+-
+- fmt = s->fmt;
+- if (rec) {
+- stop_adc(s);
+- fmt >>= CM_CFMT_ADCSHIFT;
+- } else {
+- stop_dac(s);
+- fmt >>= CM_CFMT_DACSHIFT;
+- }
+-
+- fmt &= CM_CFMT_MASK;
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
+- break;
+- if (!db->rawbuf || !db->dmaaddr)
+- return -ENOMEM;
+- db->buforder = order;
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
+- SetPageReserved(pstart);
+- }
+- bytepersec = rate << sample_shift[fmt];
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytepersec)
+- db->fragshift = ld2(bytepersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- /* to make fragsize >= 4096 */
+- db->fragsamples = db->fragsize >> sample_shift[fmt];
+- db->dmasize = db->numfrag << db->fragshift;
+- db->dmasamples = db->dmasize >> sample_shift[fmt];
+- memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
+- spin_lock_irqsave(&s->lock, flags);
+- if (rec) {
+- if (s->status & DO_DUAL_DAC)
+- set_dmadac1(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
+- else
+- set_dmaadc(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
+- /* program sample counts */
+- set_countdac(s, db->fragsamples);
+- } else {
+- set_dmadac(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
+- /* program sample counts */
+- set_countdac(s, db->fragsamples);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- db->enabled = 1;
+- db->ready = 1;
+- return 0;
+-}
+-
+-static inline void clear_advance(struct cm_state *s)
+-{
+- unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
+- unsigned char *buf = s->dma_dac.rawbuf;
+- unsigned char *buf1 = s->dma_adc.rawbuf;
+- unsigned bsize = s->dma_dac.dmasize;
+- unsigned bptr = s->dma_dac.swptr;
+- unsigned len = s->dma_dac.fragsize;
+-
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(buf + bptr, c, x);
+- if (s->status & DO_DUAL_DAC)
+- memset(buf1 + bptr, c, x);
+- bptr = 0;
+- len -= x;
+- }
+- memset(buf + bptr, c, len);
+- if (s->status & DO_DUAL_DAC)
+- memset(buf1 + bptr, c, len);
+-}
+-
+-/* call with spinlock held! */
+-static void cm_update_ptr(struct cm_state *s)
+-{
+- unsigned hwptr;
+- int diff;
+-
+- /* update ADC pointer */
+- if (s->dma_adc.ready) {
+- if (s->status & DO_DUAL_DAC) {
+- /* the dac part will finish for this */
+- } else {
+- hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
+- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- wake_up(&s->dma_adc.wait);
+- if (!s->dma_adc.mapped) {
+- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+- pause_adc(s);
+- s->dma_adc.error++;
+- }
+- }
+- }
+- }
+- /* update DAC pointer */
+- if (s->dma_dac.ready) {
+- hwptr = get_dmadac(s) % s->dma_dac.dmasize;
+- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+- s->dma_dac.hwptr = hwptr;
+- s->dma_dac.total_bytes += diff;
+- if (s->status & DO_DUAL_DAC) {
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- }
+- if (s->dma_dac.mapped) {
+- s->dma_dac.count += diff;
+- if (s->status & DO_DUAL_DAC)
+- s->dma_adc.count += diff;
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- wake_up(&s->dma_dac.wait);
+- } else {
+- s->dma_dac.count -= diff;
+- if (s->status & DO_DUAL_DAC)
+- s->dma_adc.count -= diff;
+- if (s->dma_dac.count <= 0) {
+- pause_dac(s);
+- s->dma_dac.error++;
+- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+- clear_advance(s);
+- s->dma_dac.endcleared = 1;
+- if (s->status & DO_DUAL_DAC)
+- s->dma_adc.endcleared = 1;
+- }
+- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
+- wake_up(&s->dma_dac.wait);
+- }
+- }
+-}
+-
+-static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct cm_state *s = (struct cm_state *)dev_id;
+- unsigned int intsrc, intstat;
+- unsigned char mask = 0;
+-
+- /* fastpath out, to ease interrupt sharing */
+- intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
+- if (!(intsrc & 0x80000000))
+- return IRQ_NONE;
+- spin_lock(&s->lock);
+- intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+- /* acknowledge interrupt */
+- if (intsrc & ADCINT)
+- mask |= ENADCINT;
+- if (intsrc & DACINT)
+- mask |= ENDACINT;
+- outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+- outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+- cm_update_ptr(s);
+- spin_unlock(&s->lock);
+-#ifdef CONFIG_SOUND_CMPCI_MIDI
+- if (intsrc & 0x00010000) { // UART interrupt
+- if (s->midi_devc && intchk_mpu401((void *)s->midi_devc))
+- mpuintr(irq, (void *)s->midi_devc, regs);
+- else
+- inb(s->iomidi);// dummy read
+- }
+-#endif
+- return IRQ_HANDLED;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
+-
+-#define VALIDATE_STATE(s) \
+-({ \
+- if (!(s) || (s)->magic != CM_MAGIC) { \
+- printk(invalid_magic); \
+- return -ENXIO; \
+- } \
+-})
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define MT_4 1
+-#define MT_5MUTE 2
+-#define MT_4MUTEMONO 3
+-#define MT_6MUTE 4
+-#define MT_5MUTEMONO 5
+-
+-static const struct {
+- unsigned left;
+- unsigned right;
+- unsigned type;
+- unsigned rec;
+- unsigned play;
+-} mixtable[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_CD] = { DSP_MIX_CDVOLIDX_L, DSP_MIX_CDVOLIDX_R, MT_5MUTE, 0x04, 0x06 },
+- [SOUND_MIXER_LINE] = { DSP_MIX_LINEVOLIDX_L, DSP_MIX_LINEVOLIDX_R, MT_5MUTE, 0x10, 0x18 },
+- [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 },
+- [SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 },
+- [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
+- [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
+- [SOUND_MIXER_LINE1] = { DSP_MIX_AUXVOL_L, DSP_MIX_AUXVOL_R, MT_5MUTE, 0x80, 0x60 },
+- [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX, DSP_MIX_SPKRVOLIDX, MT_5MUTEMONO, 0x00, 0x01 }
+-};
+-
+-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
+-{
+- [SOUND_MIXER_CD] = 1,
+- [SOUND_MIXER_LINE] = 2,
+- [SOUND_MIXER_MIC] = 3,
+- [SOUND_MIXER_SYNTH] = 4,
+- [SOUND_MIXER_VOLUME] = 5,
+- [SOUND_MIXER_PCM] = 6,
+- [SOUND_MIXER_LINE1] = 7,
+- [SOUND_MIXER_SPEAKER]= 8
+-};
+-
+-static unsigned mixer_outmask(struct cm_state *s)
+-{
+- unsigned long flags;
+- int i, j, k;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- j = rdmixer(s, DSP_MIX_OUTMIXIDX);
+- spin_unlock_irqrestore(&s->lock, flags);
+- for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (j & mixtable[i].play)
+- k |= 1 << i;
+- return k;
+-}
+-
+-static unsigned mixer_recmask(struct cm_state *s)
+-{
+- unsigned long flags;
+- int i, j, k;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- j = rdmixer(s, DSP_MIX_ADCMIXIDX_L);
+- spin_unlock_irqrestore(&s->lock, flags);
+- for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (j & mixtable[i].rec)
+- k |= 1 << i;
+- return k;
+-}
+-
+-static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
+-{
+- unsigned long flags;
+- int i, val, j;
+- unsigned char l, r, rl, rr;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.id, "cmpci", sizeof(info.id));
+- strlcpy(info.name, "C-Media PCI", sizeof(info.name));
+- info.modify_counter = s->mix.modcnt;
+- if (copy_to_user(argp, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == SOUND_OLD_MIXER_INFO) {
+- _old_mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.id, "cmpci", sizeof(info.id));
+- strlcpy(info.name, "C-Media cmpci", sizeof(info.name));
+- if (copy_to_user(argp, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, p);
+- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+- return -EINVAL;
+- if (_SIOC_DIR(cmd) == _SIOC_READ) {
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- val = mixer_recmask(s);
+- return put_user(val, p);
+-
+- case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
+- val = mixer_outmask(s);
+- return put_user(val, p);
+-
+- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].type)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].rec)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].play)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_CAPS:
+- return put_user(0, p);
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
+- return -EINVAL;
+- if (!volidx[i])
+- return -EINVAL;
+- return put_user(s->mix.vol[volidx[i]-1], p);
+- }
+- }
+- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
+- return -EINVAL;
+- s->mix.modcnt++;
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- if (get_user(val, p))
+- return -EFAULT;
+- i = hweight32(val);
+- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if (!(val & (1 << i)))
+- continue;
+- if (!mixtable[i].rec) {
+- val &= ~(1 << i);
+- continue;
+- }
+- j |= mixtable[i].rec;
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
+- wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80));
+- spin_unlock_irqrestore(&s->lock, flags);
+- return 0;
+-
+- case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
+- if (get_user(val, p))
+- return -EFAULT;
+- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if (!(val & (1 << i)))
+- continue;
+- if (!mixtable[i].play) {
+- val &= ~(1 << i);
+- continue;
+- }
+- j |= mixtable[i].play;
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- wrmixer(s, DSP_MIX_OUTMIXIDX, j);
+- spin_unlock_irqrestore(&s->lock, flags);
+- return 0;
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- l = val & 0xff;
+- r = (val >> 8) & 0xff;
+- if (l > 100)
+- l = 100;
+- if (r > 100)
+- r = 100;
+- spin_lock_irqsave(&s->lock, flags);
+- switch (mixtable[i].type) {
+- case MT_4:
+- if (l >= 10)
+- l -= 10;
+- if (r >= 10)
+- r -= 10;
+- frobindir(s, mixtable[i].left, 0xf0, l / 6);
+- frobindir(s, mixtable[i].right, 0xf0, l / 6);
+- break;
+-
+- case MT_4MUTEMONO:
+- rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
+- rr = (rl >> 2) & 7;
+- wrmixer(s, mixtable[i].left, rl<<3);
+- if (i == SOUND_MIXER_MIC)
+- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
+- break;
+-
+- case MT_5MUTEMONO:
+- rl = l < 4 ? 0 : (l - 5) / 3;
+- wrmixer(s, mixtable[i].left, rl<<3);
+- l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play;
+- r = rl ? mixtable[i].play : 0;
+- wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
+- /* for recording */
+- if (i == SOUND_MIXER_MIC) {
+- if (s->chip_version >= 37) {
+- rr = rl >> 1;
+- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, (rr&0x07)<<1);
+- frobindir(s, DSP_MIX_EXTENSION, ~0x01, rr>>3);
+- } else {
+- rr = rl >> 2;
+- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
+- }
+- }
+- break;
+-
+- case MT_5MUTE:
+- rl = l < 4 ? 0 : (l - 5) / 3;
+- rr = r < 4 ? 0 : (r - 5) / 3;
+- wrmixer(s, mixtable[i].left, rl<<3);
+- wrmixer(s, mixtable[i].right, rr<<3);
+- l = rdmixer(s, DSP_MIX_OUTMIXIDX);
+- l &= ~mixtable[i].play;
+- r = (rl|rr) ? mixtable[i].play : 0;
+- wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
+- break;
+-
+- case MT_6MUTE:
+- if (l < 6)
+- rl = 0x00;
+- else
+- rl = l * 2 / 3;
+- if (r < 6)
+- rr = 0x00;
+- else
+- rr = r * 2 / 3;
+- wrmixer(s, mixtable[i].left, rl);
+- wrmixer(s, mixtable[i].right, rr);
+- break;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- if (!volidx[i])
+- return -EINVAL;
+- s->mix.vol[volidx[i]-1] = val;
+- return put_user(s->mix.vol[volidx[i]-1], p);
+- }
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int cm_open_mixdev(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- struct list_head *list;
+- struct cm_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct cm_state, devs);
+- if (s->dev_mixer == minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int cm_release_mixdev(struct inode *inode, struct file *file)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- return 0;
+-}
+-
+-static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg);
+-}
+-
+-static /*const*/ struct file_operations cm_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = cm_ioctl_mixdev,
+- .open = cm_open_mixdev,
+- .release = cm_release_mixdev,
+-};
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct cm_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count, tmo;
+-
+- if (s->dma_dac.mapped || !s->dma_dac.ready)
+- return 0;
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return -EBUSY;
+- }
+- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
+- tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
+- if (!schedule_timeout(tmo + 1))
+- DBG(printk(KERN_DEBUG "cmpci: dma timed out??\n");)
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- add_wait_queue(&s->dma_adc.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- swptr = s->dma_adc.swptr;
+- cnt = s->dma_adc.dmasize-swptr;
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_adc.enabled)
+- start_adc(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto out;
+- }
+- if (!schedule_timeout(HZ)) {
+- printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+- s->dma_adc.hwptr, s->dma_adc.swptr);
+- spin_lock_irqsave(&s->lock, flags);
+- stop_adc_unlocked(s);
+- set_dmaadc(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
+- /* program sample counts */
+- set_countadc(s, s->dma_adc.fragsamples);
+- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto out;
+- }
+- continue;
+- }
+- if (s->status & DO_BIGENDIAN_R) {
+- int i, err;
+- unsigned char *src;
+- char __user *dst = buffer;
+- unsigned char data[2];
+-
+- src = (unsigned char *) (s->dma_adc.rawbuf + swptr);
+- // copy left/right sample at one time
+- for (i = 0; i < cnt / 2; i++) {
+- data[0] = src[1];
+- data[1] = src[0];
+- if ((err = __put_user(data[0], dst++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __put_user(data[1], dst++))) {
+- ret = err;
+- goto out;
+- }
+- src += 2;
+- }
+- } else if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- goto out;
+- }
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_adc.enabled)
+- start_adc_unlocked(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+-out:
+- remove_wait_queue(&s->dma_adc.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac.mapped)
+- return -ENXIO;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- if (s->status & DO_DUAL_DAC) {
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- }
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = s->dma_dac.hwptr;
+- }
+- if (s->status & DO_DUAL_DAC) {
+- s->dma_adc.swptr = s->dma_dac.swptr;
+- s->dma_adc.count = s->dma_dac.count;
+- s->dma_adc.endcleared = s->dma_dac.endcleared;
+- }
+- swptr = s->dma_dac.swptr;
+- cnt = s->dma_dac.dmasize-swptr;
+- if (s->status & DO_AC3_SW) {
+- if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
+- cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
+- } else {
+- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+- }
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
+- cnt = count / 2;
+- if (cnt <= 0) {
+- if (s->dma_dac.enabled)
+- start_dac(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto out;
+- }
+- if (!schedule_timeout(HZ)) {
+- printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+- s->dma_dac.hwptr, s->dma_dac.swptr);
+- spin_lock_irqsave(&s->lock, flags);
+- stop_dac_unlocked(s);
+- set_dmadac(s, s->dma_dac.dmaaddr, s->dma_dac.dmasamples);
+- /* program sample counts */
+- set_countdac(s, s->dma_dac.fragsamples);
+- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+- if (s->status & DO_DUAL_DAC) {
+- set_dmadac1(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
+- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto out;
+- }
+- continue;
+- }
+- if (s->status & DO_AC3_SW) {
+- int err;
+-
+- // clip exceeded data, caught by 033 and 037
+- if (swptr + 2 * cnt > s->dma_dac.dmasize)
+- cnt = (s->dma_dac.dmasize - swptr) / 2;
+- if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) {
+- ret = err;
+- goto out;
+- }
+- swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
+- } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) {
+- int i, err;
+- const char __user *src = buffer;
+- unsigned char *dst0, *dst1;
+- unsigned char data[8];
+-
+- dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr);
+- dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr);
+- // copy left/right sample at one time
+- for (i = 0; i < cnt / 4; i++) {
+- if ((err = __get_user(data[0], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[1], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[2], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[3], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[4], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[5], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[6], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[7], src++))) {
+- ret = err;
+- goto out;
+- }
+- dst0[0] = data[1];
+- dst0[1] = data[0];
+- dst0[2] = data[3];
+- dst0[3] = data[2];
+- dst1[0] = data[5];
+- dst1[1] = data[4];
+- dst1[2] = data[7];
+- dst1[3] = data[6];
+- dst0 += 4;
+- dst1 += 4;
+- }
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- } else if (s->status & DO_DUAL_DAC) {
+- int i, err;
+- unsigned long __user *src = (unsigned long __user *) buffer;
+- unsigned long *dst0, *dst1;
+-
+- dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
+- dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
+- // copy left/right sample at one time
+- for (i = 0; i < cnt / 4; i++) {
+- if ((err = __get_user(*dst0++, src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(*dst1++, src++))) {
+- ret = err;
+- goto out;
+- }
+- }
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- } else if (s->status & DO_BIGENDIAN_W) {
+- int i, err;
+- const char __user *src = buffer;
+- unsigned char *dst;
+- unsigned char data[2];
+-
+- dst = (unsigned char *) (s->dma_dac.rawbuf + swptr);
+- // swap hi/lo bytes for each sample
+- for (i = 0; i < cnt / 2; i++) {
+- if ((err = __get_user(data[0], src++))) {
+- ret = err;
+- goto out;
+- }
+- if ((err = __get_user(data[1], src++))) {
+- ret = err;
+- goto out;
+- }
+- dst[0] = data[1];
+- dst[1] = data[0];
+- dst += 2;
+- }
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- } else {
+- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- goto out;
+- }
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac.swptr = swptr;
+- s->dma_dac.count += cnt;
+- if (s->status & DO_AC3_SW)
+- s->dma_dac.count += cnt;
+- s->dma_dac.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->status & DO_DUAL_DAC) {
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- }
+- if (s->dma_dac.enabled)
+- start_dac(s);
+- }
+-out:
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
+- return 0;
+- poll_wait(file, &s->dma_dac.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- cm_update_ptr(s);
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int cm_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+- struct dmabuf *db;
+- int ret = -EINVAL;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf(s, 0)) != 0)
+- goto out;
+- db = &s->dma_dac;
+- } else if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf(s, 1)) != 0)
+- goto out;
+- db = &s->dma_adc;
+- } else
+- goto out;
+- ret = -EINVAL;
+- if (vma->vm_pgoff != 0)
+- goto out;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder))
+- goto out;
+- ret = -EINVAL;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+- db->mapped = 1;
+- ret = 0;
+-out:
+- unlock_kernel();
+- return ret;
+-}
+-
+-#define SNDCTL_SPDIF_COPYRIGHT _SIOW('S', 0, int) // set/reset S/PDIF copy protection
+-#define SNDCTL_SPDIF_LOOP _SIOW('S', 1, int) // set/reset S/PDIF loop
+-#define SNDCTL_SPDIF_MONITOR _SIOW('S', 2, int) // set S/PDIF monitor
+-#define SNDCTL_SPDIF_LEVEL _SIOW('S', 3, int) // set/reset S/PDIF out level
+-#define SNDCTL_SPDIF_INV _SIOW('S', 4, int) // set/reset S/PDIF in inverse
+-#define SNDCTL_SPDIF_SEL2 _SIOW('S', 5, int) // set S/PDIF in #2
+-#define SNDCTL_SPDIF_VALID _SIOW('S', 6, int) // set S/PDIF valid
+-#define SNDCTL_SPDIFOUT _SIOW('S', 7, int) // set S/PDIF out
+-#define SNDCTL_SPDIFIN _SIOW('S', 8, int) // set S/PDIF out
+-
+-static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int val, mapped, ret;
+- unsigned char fmtm, fmtd;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, p);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->irq);
+- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- if (s->status & DO_DUAL_DAC)
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- if (file->f_mode & FMODE_READ) {
+- spin_lock_irqsave(&s->lock, flags);
+- stop_adc_unlocked(s);
+- s->dma_adc.ready = 0;
+- set_adc_rate_unlocked(s, val);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (s->status & DO_DUAL_DAC)
+- s->dma_adc.ready = 0;
+- set_dac_rate(s, val);
+- }
+- }
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+- if (s->status & DO_DUAL_DAC) {
+- s->dma_adc.ready = 0;
+- if (val)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+- }
+- }
+- set_fmt(s, fmtm, fmtd);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 0) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val >= 2)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val >= 2)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+- if (s->status & DO_DUAL_DAC) {
+- s->dma_adc.ready = 0;
+- if (val >= 2)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+- }
+- }
+- set_fmt(s, fmtm, fmtd);
+- if ((s->capability & CAN_MULTI_CH)
+- && (file->f_mode & FMODE_WRITE)) {
+- val = set_dac_channels(s, val);
+- return put_user(val, p);
+- }
+- }
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT)
+- : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8|
+- ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val == AFMT_S16_BE || val == AFMT_S16_LE)
+- fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT);
+- if (val == AFMT_S16_BE)
+- s->status |= DO_BIGENDIAN_R;
+- else
+- s->status &= ~DO_BIGENDIAN_R;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3)
+- fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
+- if (val == AFMT_AC3) {
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+- set_ac3(s, 48000);
+- } else
+- set_ac3(s, 0);
+- if (s->status & DO_DUAL_DAC) {
+- s->dma_adc.ready = 0;
+- if (val == AFMT_S16_BE || val == AFMT_S16_LE)
+- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+- else
+- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+- }
+- if (val == AFMT_S16_BE)
+- s->status |= DO_BIGENDIAN_W;
+- else
+- s->status &= ~DO_BIGENDIAN_W;
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- if (s->status & DO_AC3) return put_user(AFMT_AC3, p);
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
+- : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if (s->status & DO_DUAL_DAC) {
+- if (file->f_mode & FMODE_WRITE &&
+- (s->enable & ENDAC) &&
+- (s->enable & ENADC))
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+- }
+- if (file->f_mode & FMODE_READ && s->enable & ENADC)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & FMODE_WRITE && s->enable & ENDAC)
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- s->dma_adc.enabled = 1;
+- start_adc(s);
+- } else {
+- s->dma_adc.enabled = 0;
+- stop_adc(s);
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- if (s->status & DO_DUAL_DAC) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- }
+- s->dma_dac.enabled = 1;
+- start_dac(s);
+- } else {
+- s->dma_dac.enabled = 0;
+- stop_dac(s);
+- }
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- cm_update_ptr(s);
+- abinfo.fragsize = s->dma_dac.fragsize;
+- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!(s->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- cm_update_ptr(s);
+- abinfo.fragsize = s->dma_adc.fragsize;
+- abinfo.bytes = s->dma_adc.count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cm_update_ptr(s);
+- val = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cm_update_ptr(s);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cm_update_ptr(s);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+- cinfo.ptr = s->dma_dac.hwptr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize-1;
+- if (s->status & DO_DUAL_DAC) {
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf(s, 0)))
+- return val;
+- if (s->status & DO_DUAL_DAC) {
+- if ((val = prog_dmabuf(s, 1)))
+- return val;
+- return put_user(2 * s->dma_dac.fragsize, p);
+- }
+- return put_user(s->dma_dac.fragsize, p);
+- }
+- if ((val = prog_dmabuf(s, 1)))
+- return val;
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- if (s->status & DO_DUAL_DAC) {
+- s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
+- s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
+- }
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.subdivision = val;
+- if (s->status & DO_DUAL_DAC)
+- s->dma_adc.subdivision = val;
+- }
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p);
+-
+- case SOUND_PCM_READ_FILTER:
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SNDCTL_DSP_GETCHANNELMASK:
+- return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p);
+-
+- case SNDCTL_DSP_BIND_CHANNEL:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val == DSP_BIND_QUERY) {
+- val = DSP_BIND_FRONT;
+- if (s->status & DO_SPDIF_OUT)
+- val |= DSP_BIND_SPDIF;
+- else {
+- if (s->curr_channels == 4)
+- val |= DSP_BIND_SURR;
+- if (s->curr_channels > 4)
+- val |= DSP_BIND_CENTER_LFE;
+- }
+- } else {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val & DSP_BIND_SPDIF) {
+- set_spdifin(s, s->rateadc);
+- if (!(s->status & DO_SPDIF_OUT))
+- val &= ~DSP_BIND_SPDIF;
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val & DSP_BIND_SPDIF) {
+- set_spdifout(s, s->ratedac);
+- set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
+- if (!(s->status & DO_SPDIF_OUT))
+- val &= ~DSP_BIND_SPDIF;
+- } else {
+- int channels;
+- int mask;
+-
+- mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
+- switch (mask) {
+- case DSP_BIND_FRONT:
+- channels = 2;
+- break;
+- case DSP_BIND_FRONT|DSP_BIND_SURR:
+- channels = 4;
+- break;
+- case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
+- channels = 6;
+- break;
+- default:
+- channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
+- break;
+- }
+- set_dac_channels(s, channels);
+- }
+- }
+- }
+- return put_user(val, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_MAPINBUF:
+- case SNDCTL_DSP_MAPOUTBUF:
+- case SNDCTL_DSP_SETSYNCRO:
+- return -EINVAL;
+- case SNDCTL_SPDIF_COPYRIGHT:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdif_copyright(s, val);
+- return 0;
+- case SNDCTL_SPDIF_LOOP:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdif_loop(s, val);
+- return 0;
+- case SNDCTL_SPDIF_MONITOR:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdif_monitor(s, val);
+- return 0;
+- case SNDCTL_SPDIF_LEVEL:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdifout_level(s, val);
+- return 0;
+- case SNDCTL_SPDIF_INV:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdifin_inverse(s, val);
+- return 0;
+- case SNDCTL_SPDIF_SEL2:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdifin_channel2(s, val);
+- return 0;
+- case SNDCTL_SPDIF_VALID:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdifin_valid(s, val);
+- return 0;
+- case SNDCTL_SPDIFOUT:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdifout(s, val ? s->ratedac : 0);
+- return 0;
+- case SNDCTL_SPDIFIN:
+- if (get_user(val, p))
+- return -EFAULT;
+- set_spdifin(s, val ? s->rateadc : 0);
+- return 0;
+- }
+- return mixer_ioctl(s, cmd, arg);
+-}
+-
+-static int cm_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned char fmtm = ~0, fmts = 0;
+- struct list_head *list;
+- struct cm_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct cm_state, devs);
+- if (!((s->dev_audio ^ minor) & ~0xf))
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- if (file->f_mode & FMODE_READ) {
+- s->status &= ~DO_BIGENDIAN_R;
+- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+- s->dma_adc.enabled = 1;
+- set_adc_rate(s, 8000);
+- // spdif-in is turnned off by default
+- set_spdifin(s, 0);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->status &= ~DO_BIGENDIAN_W;
+- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+- s->dma_dac.enabled = 1;
+- set_dac_rate(s, 8000);
+- // clear previous multichannel, spdif, ac3 state
+- set_spdifout(s, 0);
+- set_ac3(s, 0);
+- set_dac_channels(s, 1);
+- }
+- set_fmt(s, fmtm, fmts);
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int cm_release(struct inode *inode, struct file *file)
+-{
+- struct cm_state *s = (struct cm_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+-
+- dealloc_dmabuf(s, &s->dma_dac);
+- if (s->status & DO_DUAL_DAC)
+- dealloc_dmabuf(s, &s->dma_adc);
+-
+- if (s->status & DO_MULTI_CH)
+- set_dac_channels(s, 1);
+- if (s->status & DO_AC3)
+- set_ac3(s, 0);
+- if (s->status & DO_SPDIF_OUT)
+- set_spdifout(s, 0);
+- /* enable SPDIF loop */
+- set_spdif_loop(s, spdif_loop);
+- s->status &= ~DO_BIGENDIAN_W;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- dealloc_dmabuf(s, &s->dma_adc);
+- s->status &= ~DO_BIGENDIAN_R;
+- }
+- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
+- mutex_unlock(&s->open_mutex);
+- wake_up(&s->open_wait);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations cm_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = cm_read,
+- .write = cm_write,
+- .poll = cm_poll,
+- .ioctl = cm_ioctl,
+- .mmap = cm_mmap,
+- .open = cm_open,
+- .release = cm_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static struct initvol {
+- int mixch;
+- int vol;
+-} initvol[] __devinitdata = {
+- { SOUND_MIXER_WRITE_CD, 0x4f4f },
+- { SOUND_MIXER_WRITE_LINE, 0x4f4f },
+- { SOUND_MIXER_WRITE_MIC, 0x4f4f },
+- { SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
+- { SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
+- { SOUND_MIXER_WRITE_PCM, 0x4f4f }
+-};
+-
+-/* check chip version and capability */
+-static int query_chip(struct cm_state *s)
+-{
+- int ChipVersion = -1;
+- unsigned char RegValue;
+-
+- // check reg 0Ch, bit 24-31
+- RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
+- if (RegValue == 0) {
+- // check reg 08h, bit 24-28
+- RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
+- RegValue &= 0x1f;
+- if (RegValue == 0) {
+- ChipVersion = 33;
+- s->max_channels = 4;
+- s->capability |= CAN_AC3_SW;
+- s->capability |= CAN_DUAL_DAC;
+- } else {
+- ChipVersion = 37;
+- s->max_channels = 4;
+- s->capability |= CAN_AC3_HW;
+- s->capability |= CAN_DUAL_DAC;
+- }
+- } else {
+- // check reg 0Ch, bit 26
+- if (RegValue & (1 << (26-24))) {
+- ChipVersion = 39;
+- if (RegValue & (1 << (24-24)))
+- s->max_channels = 6;
+- else
+- s->max_channels = 4;
+- s->capability |= CAN_AC3_HW;
+- s->capability |= CAN_DUAL_DAC;
+- s->capability |= CAN_MULTI_CH_HW;
+- s->capability |= CAN_LINE_AS_BASS;
+- s->capability |= CAN_MIC_AS_BASS;
+- } else {
+- ChipVersion = 55; // 4 or 6 channels
+- s->max_channels = 6;
+- s->capability |= CAN_AC3_HW;
+- s->capability |= CAN_DUAL_DAC;
+- s->capability |= CAN_MULTI_CH_HW;
+- s->capability |= CAN_LINE_AS_BASS;
+- s->capability |= CAN_MIC_AS_BASS;
+- }
+- }
+- s->capability |= CAN_LINE_AS_REAR;
+- return ChipVersion;
+-}
+-
+-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+-static int __devinit cm_create_gameport(struct cm_state *s, int io_port)
+-{
+- struct gameport *gp;
+-
+- if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) {
+- printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port);
+- return -EBUSY;
+- }
+-
+- if (!(s->gameport = gp = gameport_allocate_port())) {
+- printk(KERN_ERR "cmpci: can not allocate memory for gameport\n");
+- release_region(io_port, CM_EXTENT_GAME);
+- return -ENOMEM;
+- }
+-
+- gameport_set_name(gp, "C-Media GP");
+- gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+- gp->dev.parent = &s->dev->dev;
+- gp->io = io_port;
+-
+- /* enable joystick */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
+-
+- gameport_register_port(gp);
+-
+- return 0;
+-}
+-
+-static void __devexit cm_free_gameport(struct cm_state *s)
+-{
+- if (s->gameport) {
+- int gpio = s->gameport->io;
+-
+- gameport_unregister_port(s->gameport);
+- s->gameport = NULL;
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+- release_region(gpio, CM_EXTENT_GAME);
+- }
+-}
+-#else
+-static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; }
+-static inline void cm_free_gameport(struct cm_state *s) { }
+-#endif
+-
+-#define echo_option(x)\
+-if (x) strcat(options, "" #x " ")
+-
+-static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+-{
+- struct cm_state *s;
+- mm_segment_t fs;
+- int i, val, ret;
+- unsigned char reg_mask;
+- int timeout;
+- struct resource *ports;
+- struct {
+- unsigned short deviceid;
+- char *devicename;
+- } devicetable[] = {
+- { PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
+- { PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
+- { PCI_DEVICE_ID_CMEDIA_CM8738, "CM8738" },
+- { PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
+- };
+- char *devicename = "unknown";
+- char options[256];
+-
+- if ((ret = pci_enable_device(pcidev)))
+- return ret;
+- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO))
+- return -ENODEV;
+- if (pcidev->irq == 0)
+- return -ENODEV;
+- 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;
+- }
+- s = kmalloc(sizeof(*s), GFP_KERNEL);
+- if (!s) {
+- printk(KERN_WARNING "cmpci: out of memory\n");
+- return -ENOMEM;
+- }
+- /* search device name */
+- for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
+- if (devicetable[i].deviceid == pcidev->device) {
+- devicename = devicetable[i].devicename;
+- break;
+- }
+- }
+- memset(s, 0, sizeof(struct cm_state));
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- mutex_init(&s->open_mutex);
+- spin_lock_init(&s->lock);
+- s->magic = CM_MAGIC;
+- s->dev = pcidev;
+- s->iobase = pci_resource_start(pcidev, 0);
+- s->iosynth = fmio;
+- s->iomidi = mpuio;
+-#ifdef CONFIG_SOUND_CMPCI_MIDI
+- s->midi_devc = 0;
+-#endif
+- s->status = 0;
+- if (s->iobase == 0)
+- return -ENODEV;
+- s->irq = pcidev->irq;
+-
+- if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
+- printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+- ret = -EBUSY;
+- goto err_region5;
+- }
+- /* dump parameters */
+- strcpy(options, "cmpci: ");
+- echo_option(joystick);
+- echo_option(spdif_inverse);
+- echo_option(spdif_loop);
+- echo_option(spdif_out);
+- echo_option(use_line_as_rear);
+- echo_option(use_line_as_bass);
+- echo_option(use_mic_as_bass);
+- echo_option(mic_boost);
+- echo_option(hw_copy);
+- printk(KERN_INFO "%s\n", options);
+-
+- /* initialize codec registers */
+- outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
+- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
+- /* reset mixer */
+- wrmixer(s, DSP_MIX_DATARESETIDX, 0);
+-
+- /* request irq */
+- if ((ret = request_irq(s->irq, cm_interrupt, IRQF_SHARED, "cmpci", s))) {
+- printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
+- goto err_irq;
+- }
+- printk(KERN_INFO "cmpci: found %s adapter at io %#x irq %u\n",
+- devicename, s->iobase, s->irq);
+- /* register devices */
+- if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) {
+- ret = s->dev_audio;
+- goto err_dev1;
+- }
+- if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) {
+- ret = s->dev_mixer;
+- goto err_dev2;
+- }
+- pci_set_master(pcidev); /* enable bus mastering */
+- /* initialize the chips */
+- fs = get_fs();
+- set_fs(KERNEL_DS);
+- /* set mixer output */
+- frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f);
+- /* set mixer input */
+- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC;
+- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+- val = initvol[i].vol;
+- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+- }
+- set_fs(fs);
+- /* use channel 1 for playback, channel 0 for record */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, CHADC0);
+- /* turn off VMIC3 - mic boost */
+- if (mic_boost)
+- maskb(s->iobase + CODEC_CMI_MIXER2, ~1, 0);
+- else
+- maskb(s->iobase + CODEC_CMI_MIXER2, ~0, 1);
+- s->deviceid = pcidev->device;
+-
+- if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738
+- || pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738B) {
+-
+- /* chip version and hw capability check */
+- s->chip_version = query_chip(s);
+- printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version);
+-
+- /* set SPDIF-in inverse before enable SPDIF loop */
+- set_spdifin_inverse(s, spdif_inverse);
+-
+- /* use SPDIF in #1 */
+- set_spdifin_channel2(s, 0);
+- } else {
+- s->chip_version = 0;
+- /* 8338 will fall here */
+- s->max_channels = 4;
+- s->capability |= CAN_DUAL_DAC;
+- s->capability |= CAN_LINE_AS_REAR;
+- }
+- /* enable SPDIF loop */
+- set_spdif_loop(s, spdif_loop);
+-
+- // enable 4 speaker mode (analog duplicate)
+- set_hw_copy(s, hw_copy);
+-
+- reg_mask = 0;
+-#ifdef CONFIG_SOUND_CMPCI_FM
+- /* disable FM */
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+- if (s->iosynth) {
+- /* don't enable OPL3 if there is one */
+- if (opl3_detect(s->iosynth, NULL)) {
+- s->iosynth = 0;
+- } else {
+- /* set IO based at 0x388 */
+- switch (s->iosynth) {
+- case 0x388:
+- reg_mask = 0;
+- break;
+- case 0x3C8:
+- reg_mask = 0x01;
+- break;
+- case 0x3E0:
+- reg_mask = 0x02;
+- break;
+- case 0x3E8:
+- reg_mask = 0x03;
+- break;
+- default:
+- s->iosynth = 0;
+- break;
+- }
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
+- /* enable FM */
+- if (s->iosynth) {
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
+- if (opl3_detect(s->iosynth, NULL))
+- ret = opl3_init(s->iosynth, NULL, THIS_MODULE);
+- else {
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+- s->iosynth = 0;
+- }
+- }
+- }
+- }
+-#endif
+-#ifdef CONFIG_SOUND_CMPCI_MIDI
+- switch (s->iomidi) {
+- case 0x330:
+- reg_mask = 0;
+- break;
+- case 0x320:
+- reg_mask = 0x20;
+- break;
+- case 0x310:
+- reg_mask = 0x40;
+- break;
+- case 0x300:
+- reg_mask = 0x60;
+- break;
+- default:
+- s->iomidi = 0;
+- goto skip_mpu;
+- }
+- ports = request_region(s->iomidi, 2, "mpu401");
+- if (!ports)
+- goto skip_mpu;
+- /* disable MPU-401 */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
+- s->mpu_data.name = "cmpci mpu";
+- s->mpu_data.io_base = s->iomidi;
+- s->mpu_data.irq = -s->irq; // tell mpu401 to share irq
+- if (probe_mpu401(&s->mpu_data, ports)) {
+- release_region(s->iomidi, 2);
+- s->iomidi = 0;
+- goto skip_mpu;
+- }
+- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x60, reg_mask);
+- /* enable MPU-401 */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
+- /* clear all previously received interrupt */
+- for (timeout = 900000; timeout > 0; timeout--) {
+- if ((inb(s->iomidi + 1) && 0x80) == 0)
+- inb(s->iomidi);
+- else
+- break;
+- }
+- if (!probe_mpu401(&s->mpu_data, ports)) {
+- release_region(s->iomidi, 2);
+- s->iomidi = 0;
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
+- } else {
+- attach_mpu401(&s->mpu_data, THIS_MODULE);
+- s->midi_devc = s->mpu_data.slots[1];
+- }
+-skip_mpu:
+-#endif
+- /* disable joystick port */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+- if (joystick)
+- cm_create_gameport(s, 0x200);
+-
+- /* store it in the driver field */
+- pci_set_drvdata(pcidev, s);
+- /* put it into driver list */
+- list_add_tail(&s->devs, &devs);
+- /* increment devindex */
+- if (devindex < NR_DEVICE-1)
+- devindex++;
+- return 0;
+-
+-err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+-err_dev1:
+- printk(KERN_ERR "cmpci: cannot register misc device\n");
+- free_irq(s->irq, s);
+-err_irq:
+- release_region(s->iobase, CM_EXTENT_CODEC);
+-err_region5:
+- kfree(s);
+- return ret;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-MODULE_AUTHOR("ChenLi Tien, cltien at cmedia.com.tw");
+-MODULE_DESCRIPTION("CM8x38 Audio Driver");
+-MODULE_LICENSE("GPL");
+-
+-static void __devexit cm_remove(struct pci_dev *dev)
+-{
+- struct cm_state *s = pci_get_drvdata(dev);
+-
+- if (!s)
+- return;
+-
+- cm_free_gameport(s);
+-
+-#ifdef CONFIG_SOUND_CMPCI_FM
+- if (s->iosynth) {
+- /* disable FM */
+- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+- }
+-#endif
+-#ifdef CONFIG_SOUND_CMPCI_MIDI
+- if (s->iomidi) {
+- unload_mpu401(&s->mpu_data);
+- /* disable MPU-401 */
+- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
+- }
+-#endif
+- set_spdif_loop(s, 0);
+- list_del(&s->devs);
+- outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
+- synchronize_irq(s->irq);
+- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
+- free_irq(s->irq, s);
+-
+- /* reset mixer */
+- wrmixer(s, DSP_MIX_DATARESETIDX, 0);
+-
+- release_region(s->iobase, CM_EXTENT_CODEC);
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->dev_mixer);
+- kfree(s);
+- pci_set_drvdata(dev, NULL);
+-}
+-
+-static struct pci_device_id id_table[] __devinitdata = {
+- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, id_table);
+-
+-static struct pci_driver cm_driver = {
+- .name = "cmpci",
+- .id_table = id_table,
+- .probe = cm_probe,
+- .remove = __devexit_p(cm_remove)
+-};
+-
+-static int __init init_cmpci(void)
+-{
+- printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n");
+- return pci_register_driver(&cm_driver);
+-}
+-
+-static void __exit cleanup_cmpci(void)
+-{
+- printk(KERN_INFO "cmpci: unloading\n");
+- pci_unregister_driver(&cm_driver);
+-}
+-
+-module_init(init_cmpci);
+-module_exit(cleanup_cmpci);
+diff --git a/sound/oss/cs4281/Makefile b/sound/oss/cs4281/Makefile
+deleted file mode 100644
+index 6d527e8..0000000
+--- a/sound/oss/cs4281/Makefile
++++ /dev/null
+@@ -1,6 +0,0 @@
+-# Makefile for Cirrus Logic-Crystal CS4281
+-#
+-
+-obj-$(CONFIG_SOUND_CS4281) += cs4281.o
+-
+-cs4281-objs += cs4281m.o
+diff --git a/sound/oss/cs4281/cs4281_hwdefs.h b/sound/oss/cs4281/cs4281_hwdefs.h
+deleted file mode 100644
+index 701d595..0000000
+--- a/sound/oss/cs4281/cs4281_hwdefs.h
++++ /dev/null
+@@ -1,1234 +0,0 @@
+-//****************************************************************************
+-//
+-// HWDEFS.H - Definitions of the registers and data structures used by the
+-// CS4281
+-//
+-// Copyright (c) 1999,2000,2001 Crystal Semiconductor Corp.
+-//
+-//****************************************************************************
+-
+-#ifndef _H_HWDEFS
+-#define _H_HWDEFS
+-
+-//****************************************************************************
+-//
+-// The following define the offsets of the registers located in the PCI
+-// configuration space of the CS4281 part.
+-//
+-//****************************************************************************
+-#define PCICONFIG_DEVID_VENID 0x00000000L
+-#define PCICONFIG_STATUS_COMMAND 0x00000004L
+-#define PCICONFIG_CLASS_REVISION 0x00000008L
+-#define PCICONFIG_LATENCY_TIMER 0x0000000CL
+-#define PCICONFIG_BA0 0x00000010L
+-#define PCICONFIG_BA1 0x00000014L
+-#define PCICONFIG_SUBSYSID_SUBSYSVENID 0x0000002CL
+-#define PCICONFIG_INTERRUPT 0x0000003CL
+-
+-//****************************************************************************
+-//
+-// The following define the offsets of the registers accessed via base address
+-// register zero on the CS4281 part.
+-//
+-//****************************************************************************
+-#define BA0_HISR 0x00000000L
+-#define BA0_HICR 0x00000008L
+-#define BA0_HIMR 0x0000000CL
+-#define BA0_IIER 0x00000010L
+-#define BA0_HDSR0 0x000000F0L
+-#define BA0_HDSR1 0x000000F4L
+-#define BA0_HDSR2 0x000000F8L
+-#define BA0_HDSR3 0x000000FCL
+-#define BA0_DCA0 0x00000110L
+-#define BA0_DCC0 0x00000114L
+-#define BA0_DBA0 0x00000118L
+-#define BA0_DBC0 0x0000011CL
+-#define BA0_DCA1 0x00000120L
+-#define BA0_DCC1 0x00000124L
+-#define BA0_DBA1 0x00000128L
+-#define BA0_DBC1 0x0000012CL
+-#define BA0_DCA2 0x00000130L
+-#define BA0_DCC2 0x00000134L
+-#define BA0_DBA2 0x00000138L
+-#define BA0_DBC2 0x0000013CL
+-#define BA0_DCA3 0x00000140L
+-#define BA0_DCC3 0x00000144L
+-#define BA0_DBA3 0x00000148L
+-#define BA0_DBC3 0x0000014CL
+-#define BA0_DMR0 0x00000150L
+-#define BA0_DCR0 0x00000154L
+-#define BA0_DMR1 0x00000158L
+-#define BA0_DCR1 0x0000015CL
+-#define BA0_DMR2 0x00000160L
+-#define BA0_DCR2 0x00000164L
+-#define BA0_DMR3 0x00000168L
+-#define BA0_DCR3 0x0000016CL
+-#define BA0_DLMR 0x00000170L
+-#define BA0_DLSR 0x00000174L
+-#define BA0_FCR0 0x00000180L
+-#define BA0_FCR1 0x00000184L
+-#define BA0_FCR2 0x00000188L
+-#define BA0_FCR3 0x0000018CL
+-#define BA0_FPDR0 0x00000190L
+-#define BA0_FPDR1 0x00000194L
+-#define BA0_FPDR2 0x00000198L
+-#define BA0_FPDR3 0x0000019CL
+-#define BA0_FCHS 0x0000020CL
+-#define BA0_FSIC0 0x00000210L
+-#define BA0_FSIC1 0x00000214L
+-#define BA0_FSIC2 0x00000218L
+-#define BA0_FSIC3 0x0000021CL
+-#define BA0_PCICFG00 0x00000300L
+-#define BA0_PCICFG04 0x00000304L
+-#define BA0_PCICFG08 0x00000308L
+-#define BA0_PCICFG0C 0x0000030CL
+-#define BA0_PCICFG10 0x00000310L
+-#define BA0_PCICFG14 0x00000314L
+-#define BA0_PCICFG18 0x00000318L
+-#define BA0_PCICFG1C 0x0000031CL
+-#define BA0_PCICFG20 0x00000320L
+-#define BA0_PCICFG24 0x00000324L
+-#define BA0_PCICFG28 0x00000328L
+-#define BA0_PCICFG2C 0x0000032CL
+-#define BA0_PCICFG30 0x00000330L
+-#define BA0_PCICFG34 0x00000334L
+-#define BA0_PCICFG38 0x00000338L
+-#define BA0_PCICFG3C 0x0000033CL
+-#define BA0_PCICFG40 0x00000340L
+-#define BA0_PMCS 0x00000344L
+-#define BA0_CWPR 0x000003E0L
+-#define BA0_EPPMC 0x000003E4L
+-#define BA0_GPIOR 0x000003E8L
+-#define BA0_SPMC 0x000003ECL
+-#define BA0_CFLR 0x000003F0L
+-#define BA0_IISR 0x000003F4L
+-#define BA0_TMS 0x000003F8L
+-#define BA0_SSVID 0x000003FCL
+-#define BA0_CLKCR1 0x00000400L
+-#define BA0_FRR 0x00000410L
+-#define BA0_SLT12O 0x0000041CL
+-#define BA0_SERMC 0x00000420L
+-#define BA0_SERC1 0x00000428L
+-#define BA0_SERC2 0x0000042CL
+-#define BA0_SLT12M 0x0000045CL
+-#define BA0_ACCTL 0x00000460L
+-#define BA0_ACSTS 0x00000464L
+-#define BA0_ACOSV 0x00000468L
+-#define BA0_ACCAD 0x0000046CL
+-#define BA0_ACCDA 0x00000470L
+-#define BA0_ACISV 0x00000474L
+-#define BA0_ACSAD 0x00000478L
+-#define BA0_ACSDA 0x0000047CL
+-#define BA0_JSPT 0x00000480L
+-#define BA0_JSCTL 0x00000484L
+-#define BA0_MIDCR 0x00000490L
+-#define BA0_MIDCMD 0x00000494L
+-#define BA0_MIDSR 0x00000494L
+-#define BA0_MIDWP 0x00000498L
+-#define BA0_MIDRP 0x0000049CL
+-#define BA0_AODSD1 0x000004A8L
+-#define BA0_AODSD2 0x000004ACL
+-#define BA0_CFGI 0x000004B0L
+-#define BA0_SLT12M2 0x000004DCL
+-#define BA0_ACSTS2 0x000004E4L
+-#define BA0_ACISV2 0x000004F4L
+-#define BA0_ACSAD2 0x000004F8L
+-#define BA0_ACSDA2 0x000004FCL
+-#define BA0_IOTGP 0x00000500L
+-#define BA0_IOTSB 0x00000504L
+-#define BA0_IOTFM 0x00000508L
+-#define BA0_IOTDMA 0x0000050CL
+-#define BA0_IOTAC0 0x00000500L
+-#define BA0_IOTAC1 0x00000504L
+-#define BA0_IOTAC2 0x00000508L
+-#define BA0_IOTAC3 0x0000050CL
+-#define BA0_IOTPCP 0x0000052CL
+-#define BA0_IOTCC 0x00000530L
+-#define BA0_IOTCR 0x0000058CL
+-#define BA0_PCPRR 0x00000600L
+-#define BA0_PCPGR 0x00000604L
+-#define BA0_PCPCR 0x00000608L
+-#define BA0_PCPCIEN 0x00000608L
+-#define BA0_SBMAR 0x00000700L
+-#define BA0_SBMDR 0x00000704L
+-#define BA0_SBRR 0x00000708L
+-#define BA0_SBRDP 0x0000070CL
+-#define BA0_SBWDP 0x00000710L
+-#define BA0_SBWBS 0x00000710L
+-#define BA0_SBRBS 0x00000714L
+-#define BA0_FMSR 0x00000730L
+-#define BA0_B0AP 0x00000730L
+-#define BA0_FMDP 0x00000734L
+-#define BA0_B1AP 0x00000738L
+-#define BA0_B1DP 0x0000073CL
+-#define BA0_SSPM 0x00000740L
+-#define BA0_DACSR 0x00000744L
+-#define BA0_ADCSR 0x00000748L
+-#define BA0_SSCR 0x0000074CL
+-#define BA0_FMLVC 0x00000754L
+-#define BA0_FMRVC 0x00000758L
+-#define BA0_SRCSA 0x0000075CL
+-#define BA0_PPLVC 0x00000760L
+-#define BA0_PPRVC 0x00000764L
+-#define BA0_PASR 0x00000768L
+-#define BA0_CASR 0x0000076CL
+-
+-//****************************************************************************
+-//
+-// The following define the offsets of the AC97 shadow registers, which appear
+-// as a virtual extension to the base address register zero memory range.
+-//
+-//****************************************************************************
+-#define AC97_REG_OFFSET_MASK 0x0000007EL
+-#define AC97_CODEC_NUMBER_MASK 0x00003000L
+-
+-#define BA0_AC97_RESET 0x00001000L
+-#define BA0_AC97_MASTER_VOLUME 0x00001002L
+-#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L
+-#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L
+-#define BA0_AC97_MASTER_TONE 0x00001008L
+-#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL
+-#define BA0_AC97_PHONE_VOLUME 0x0000100CL
+-#define BA0_AC97_MIC_VOLUME 0x0000100EL
+-#define BA0_AC97_LINE_IN_VOLUME 0x00001010L
+-#define BA0_AC97_CD_VOLUME 0x00001012L
+-#define BA0_AC97_VIDEO_VOLUME 0x00001014L
+-#define BA0_AC97_AUX_VOLUME 0x00001016L
+-#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L
+-#define BA0_AC97_RECORD_SELECT 0x0000101AL
+-#define BA0_AC97_RECORD_GAIN 0x0000101CL
+-#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL
+-#define BA0_AC97_GENERAL_PURPOSE 0x00001020L
+-#define BA0_AC97_3D_CONTROL 0x00001022L
+-#define BA0_AC97_MODEM_RATE 0x00001024L
+-#define BA0_AC97_POWERDOWN 0x00001026L
+-#define BA0_AC97_EXT_AUDIO_ID 0x00001028L
+-#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL
+-#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL
+-#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL
+-#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L
+-#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L
+-#define BA0_AC97_MIC_ADC_RATE 0x00001034L
+-#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L
+-#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L
+-#define BA0_AC97_RESERVED_3A 0x0000103AL
+-#define BA0_AC97_EXT_MODEM_ID 0x0000103CL
+-#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL
+-#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L
+-#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L
+-#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L
+-#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L
+-#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L
+-#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL
+-#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL
+-#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL
+-#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L
+-#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L
+-#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L
+-#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L
+-#define BA0_AC97_RESERVED_58 0x00001058L
+-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL
+-#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL
+-#define BA0_AC97_AC_MODE 0x0000105EL
+-#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L
+-#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L
+-#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L
+-#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L
+-#define BA0_AC97_SPDIF_CONTROL 0x00001068L
+-#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL
+-#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL
+-#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL
+-#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L
+-#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L
+-#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L
+-#define BA0_AC97_CAL_ADDRESS 0x00001076L
+-#define BA0_AC97_CAL_DATA 0x00001078L
+-#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL
+-#define BA0_AC97_VENDOR_ID1 0x0000107CL
+-#define BA0_AC97_VENDOR_ID2 0x0000107EL
+-
+-//****************************************************************************
+-//
+-// The following define the offsets of the registers and memories accessed via
+-// base address register one on the CS4281 part.
+-//
+-//****************************************************************************
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI device ID/vendor ID
+-// register.
+-//
+-//****************************************************************************
+-#define PDV_VENID_MASK 0x0000FFFFL
+-#define PDV_DEVID_MASK 0xFFFF0000L
+-#define PDV_VENID_SHIFT 0L
+-#define PDV_DEVID_SHIFT 16L
+-#define VENID_CIRRUS_LOGIC 0x1013L
+-#define DEVID_CS4281 0x6005L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI status and command
+-// register.
+-//
+-//****************************************************************************
+-#define PSC_IO_SPACE_ENABLE 0x00000001L
+-#define PSC_MEMORY_SPACE_ENABLE 0x00000002L
+-#define PSC_BUS_MASTER_ENABLE 0x00000004L
+-#define PSC_SPECIAL_CYCLES 0x00000008L
+-#define PSC_MWI_ENABLE 0x00000010L
+-#define PSC_VGA_PALETTE_SNOOP 0x00000020L
+-#define PSC_PARITY_RESPONSE 0x00000040L
+-#define PSC_WAIT_CONTROL 0x00000080L
+-#define PSC_SERR_ENABLE 0x00000100L
+-#define PSC_FAST_B2B_ENABLE 0x00000200L
+-#define PSC_UDF_MASK 0x007F0000L
+-#define PSC_FAST_B2B_CAPABLE 0x00800000L
+-#define PSC_PARITY_ERROR_DETECTED 0x01000000L
+-#define PSC_DEVSEL_TIMING_MASK 0x06000000L
+-#define PSC_TARGET_ABORT_SIGNALLED 0x08000000L
+-#define PSC_RECEIVED_TARGET_ABORT 0x10000000L
+-#define PSC_RECEIVED_MASTER_ABORT 0x20000000L
+-#define PSC_SIGNALLED_SERR 0x40000000L
+-#define PSC_DETECTED_PARITY_ERROR 0x80000000L
+-#define PSC_UDF_SHIFT 16L
+-#define PSC_DEVSEL_TIMING_SHIFT 25L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI class/revision ID
+-// register.
+-//
+-//****************************************************************************
+-#define PCR_REVID_MASK 0x000000FFL
+-#define PCR_INTERFACE_MASK 0x0000FF00L
+-#define PCR_SUBCLASS_MASK 0x00FF0000L
+-#define PCR_CLASS_MASK 0xFF000000L
+-#define PCR_REVID_SHIFT 0L
+-#define PCR_INTERFACE_SHIFT 8L
+-#define PCR_SUBCLASS_SHIFT 16L
+-#define PCR_CLASS_SHIFT 24L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI latency timer register.
+-//
+-//****************************************************************************
+-#define PLT_CACHE_LINE_SIZE_MASK 0x000000FFL
+-#define PLT_LATENCY_TIMER_MASK 0x0000FF00L
+-#define PLT_HEADER_TYPE_MASK 0x00FF0000L
+-#define PLT_BIST_MASK 0xFF000000L
+-#define PLT_CACHE_LINE_SIZE_SHIFT 0L
+-#define PLT_LATENCY_TIMER_SHIFT 8L
+-#define PLT_HEADER_TYPE_SHIFT 16L
+-#define PLT_BIST_SHIFT 24L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI base address registers.
+-//
+-//****************************************************************************
+-#define PBAR_MEMORY_SPACE_INDICATOR 0x00000001L
+-#define PBAR_LOCATION_TYPE_MASK 0x00000006L
+-#define PBAR_NOT_PREFETCHABLE 0x00000008L
+-#define PBAR_ADDRESS_MASK 0xFFFFFFF0L
+-#define PBAR_LOCATION_TYPE_SHIFT 1L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI subsystem ID/subsystem
+-// vendor ID register.
+-//
+-//****************************************************************************
+-#define PSS_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFFL
+-#define PSS_SUBSYSTEM_ID_MASK 0xFFFF0000L
+-#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT 0L
+-#define PSS_SUBSYSTEM_ID_SHIFT 16L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PCI interrupt register.
+-//
+-//****************************************************************************
+-#define PI_LINE_MASK 0x000000FFL
+-#define PI_PIN_MASK 0x0000FF00L
+-#define PI_MIN_GRANT_MASK 0x00FF0000L
+-#define PI_MAX_LATENCY_MASK 0xFF000000L
+-#define PI_LINE_SHIFT 0L
+-#define PI_PIN_SHIFT 8L
+-#define PI_MIN_GRANT_SHIFT 16L
+-#define PI_MAX_LATENCY_SHIFT 24L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the host interrupt status
+-// register.
+-//
+-//****************************************************************************
+-#define HISR_HVOLMASK 0x00000003L
+-#define HISR_VDNI 0x00000001L
+-#define HISR_VUPI 0x00000002L
+-#define HISR_GP1I 0x00000004L
+-#define HISR_GP3I 0x00000008L
+-#define HISR_GPSI 0x00000010L
+-#define HISR_GPPI 0x00000020L
+-#define HISR_DMAI 0x00040000L
+-#define HISR_FIFOI 0x00100000L
+-#define HISR_HVOL 0x00200000L
+-#define HISR_MIDI 0x00400000L
+-#define HISR_SBINT 0x00800000L
+-#define HISR_INTENA 0x80000000L
+-#define HISR_DMA_MASK 0x00000F00L
+-#define HISR_FIFO_MASK 0x0000F000L
+-#define HISR_DMA_SHIFT 8L
+-#define HISR_FIFO_SHIFT 12L
+-#define HISR_FIFO0 0x00001000L
+-#define HISR_FIFO1 0x00002000L
+-#define HISR_FIFO2 0x00004000L
+-#define HISR_FIFO3 0x00008000L
+-#define HISR_DMA0 0x00000100L
+-#define HISR_DMA1 0x00000200L
+-#define HISR_DMA2 0x00000400L
+-#define HISR_DMA3 0x00000800L
+-#define HISR_RESERVED 0x40000000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the host interrupt control
+-// register.
+-//
+-//****************************************************************************
+-#define HICR_IEV 0x00000001L
+-#define HICR_CHGM 0x00000002L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the DMA Mode Register n
+-// (DMRn)
+-//
+-//****************************************************************************
+-#define DMRn_TR_MASK 0x0000000CL
+-#define DMRn_TR_SHIFT 2L
+-#define DMRn_AUTO 0x00000010L
+-#define DMRn_TR_READ 0x00000008L
+-#define DMRn_TR_WRITE 0x00000004L
+-#define DMRn_TYPE_MASK 0x000000C0L
+-#define DMRn_TYPE_SHIFT 6L
+-#define DMRn_SIZE8 0x00010000L
+-#define DMRn_MONO 0x00020000L
+-#define DMRn_BEND 0x00040000L
+-#define DMRn_USIGN 0x00080000L
+-#define DMRn_SIZE20 0x00100000L
+-#define DMRn_SWAPC 0x00400000L
+-#define DMRn_CBC 0x01000000L
+-#define DMRn_TBC 0x02000000L
+-#define DMRn_POLL 0x10000000L
+-#define DMRn_DMA 0x20000000L
+-#define DMRn_FSEL_MASK 0xC0000000L
+-#define DMRn_FSEL_SHIFT 30L
+-#define DMRn_FSEL0 0x00000000L
+-#define DMRn_FSEL1 0x40000000L
+-#define DMRn_FSEL2 0x80000000L
+-#define DMRn_FSEL3 0xC0000000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the DMA Command Register n
+-// (DCRn)
+-//
+-//****************************************************************************
+-#define DCRn_HTCIE 0x00020000L
+-#define DCRn_TCIE 0x00010000L
+-#define DCRn_MSK 0x00000001L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the FIFO Control
+-// register n.(FCRn)
+-//
+-//****************************************************************************
+-#define FCRn_OF_MASK 0x0000007FL
+-#define FCRn_OF_SHIFT 0L
+-#define FCRn_SZ_MASK 0x00007F00L
+-#define FCRn_SZ_SHIFT 8L
+-#define FCRn_LS_MASK 0x001F0000L
+-#define FCRn_LS_SHIFT 16L
+-#define FCRn_RS_MASK 0x1F000000L
+-#define FCRn_RS_SHIFT 24L
+-#define FCRn_FEN 0x80000000L
+-#define FCRn_PSH 0x20000000L
+-#define FCRn_DACZ 0x40000000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the serial port Power Management
+-// control register.(SPMC)
+-//
+-//****************************************************************************
+-#define SPMC_RSTN 0x00000001L
+-#define SPMC_ASYN 0x00000002L
+-#define SPMC_WUP1 0x00000004L
+-#define SPMC_WUP2 0x00000008L
+-#define SPMC_ASDI2E 0x00000100L
+-#define SPMC_ESSPD 0x00000200L
+-#define SPMC_GISPEN 0x00004000L
+-#define SPMC_GIPPEN 0x00008000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the Configuration Load register.
+-// (CFLR)
+-//
+-//****************************************************************************
+-#define CFLR_CLOCK_SOURCE_MASK 0x00000003L
+-#define CFLR_CLOCK_SOURCE_AC97 0x00000001L
+-
+-#define CFLR_CB0_MASK 0x000000FFL
+-#define CFLR_CB1_MASK 0x0000FF00L
+-#define CFLR_CB2_MASK 0x00FF0000L
+-#define CFLR_CB3_MASK 0xFF000000L
+-#define CFLR_CB0_SHIFT 0L
+-#define CFLR_CB1_SHIFT 8L
+-#define CFLR_CB2_SHIFT 16L
+-#define CFLR_CB3_SHIFT 24L
+-
+-#define IOTCR_DMA0 0x00000000L
+-#define IOTCR_DMA1 0x00000400L
+-#define IOTCR_DMA2 0x00000800L
+-#define IOTCR_DMA3 0x00000C00L
+-#define IOTCR_CCLS 0x00000100L
+-#define IOTCR_PCPCI 0x00000200L
+-#define IOTCR_DDMA 0x00000300L
+-
+-#define SBWBS_WBB 0x00000080L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the SRC Slot Assignment Register
+-// (SRCSA)
+-//
+-//****************************************************************************
+-#define SRCSA_PLSS_MASK 0x0000001FL
+-#define SRCSA_PLSS_SHIFT 0L
+-#define SRCSA_PRSS_MASK 0x00001F00L
+-#define SRCSA_PRSS_SHIFT 8L
+-#define SRCSA_CLSS_MASK 0x001F0000L
+-#define SRCSA_CLSS_SHIFT 16L
+-#define SRCSA_CRSS_MASK 0x1F000000L
+-#define SRCSA_CRSS_SHIFT 24L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the Sound System Power Management
+-// register.(SSPM)
+-//
+-//****************************************************************************
+-#define SSPM_FPDN 0x00000080L
+-#define SSPM_MIXEN 0x00000040L
+-#define SSPM_CSRCEN 0x00000020L
+-#define SSPM_PSRCEN 0x00000010L
+-#define SSPM_JSEN 0x00000008L
+-#define SSPM_ACLEN 0x00000004L
+-#define SSPM_FMEN 0x00000002L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the Sound System Control
+-// Register. (SSCR)
+-//
+-//****************************************************************************
+-#define SSCR_SB 0x00000004L
+-#define SSCR_HVC 0x00000008L
+-#define SSCR_LPFIFO 0x00000040L
+-#define SSCR_LPSRC 0x00000080L
+-#define SSCR_XLPSRC 0x00000100L
+-#define SSCR_MVMD 0x00010000L
+-#define SSCR_MVAD 0x00020000L
+-#define SSCR_MVLD 0x00040000L
+-#define SSCR_MVCS 0x00080000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the Clock Control Register 1.
+-// (CLKCR1)
+-//
+-//****************************************************************************
+-#define CLKCR1_DLLSS_MASK 0x0000000CL
+-#define CLKCR1_DLLSS_SHIFT 2L
+-#define CLKCR1_DLLP 0x00000010L
+-#define CLKCR1_SWCE 0x00000020L
+-#define CLKCR1_DLLOS 0x00000040L
+-#define CLKCR1_CKRA 0x00010000L
+-#define CLKCR1_CKRN 0x00020000L
+-#define CLKCR1_DLLRDY 0x01000000L
+-#define CLKCR1_CLKON 0x02000000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the Sound Blaster Read Buffer
+-// Status.(SBRBS)
+-//
+-//****************************************************************************
+-#define SBRBS_RD_MASK 0x0000007FL
+-#define SBRBS_RD_SHIFT 0L
+-#define SBRBS_RBF 0x00000080L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the serial port master control
+-// register.(SERMC)
+-//
+-//****************************************************************************
+-#define SERMC_MSPE 0x00000001L
+-#define SERMC_PTC_MASK 0x0000000EL
+-#define SERMC_PTC_SHIFT 1L
+-#define SERMC_PTC_AC97 0x00000002L
+-#define SERMC_PLB 0x00000010L
+-#define SERMC_PXLB 0x00000020L
+-#define SERMC_LOFV 0x00080000L
+-#define SERMC_SLB 0x00100000L
+-#define SERMC_SXLB 0x00200000L
+-#define SERMC_ODSEN1 0x01000000L
+-#define SERMC_ODSEN2 0x02000000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the General Purpose I/O Register.
+-// (GPIOR)
+-//
+-//****************************************************************************
+-#define GPIOR_VDNS 0x00000001L
+-#define GPIOR_VUPS 0x00000002L
+-#define GPIOR_GP1S 0x00000004L
+-#define GPIOR_GP3S 0x00000008L
+-#define GPIOR_GPSS 0x00000010L
+-#define GPIOR_GPPS 0x00000020L
+-#define GPIOR_GP1D 0x00000400L
+-#define GPIOR_GP3D 0x00000800L
+-#define GPIOR_VDNLT 0x00010000L
+-#define GPIOR_VDNPO 0x00020000L
+-#define GPIOR_VDNST 0x00040000L
+-#define GPIOR_VDNW 0x00080000L
+-#define GPIOR_VUPLT 0x00100000L
+-#define GPIOR_VUPPO 0x00200000L
+-#define GPIOR_VUPST 0x00400000L
+-#define GPIOR_VUPW 0x00800000L
+-#define GPIOR_GP1OE 0x01000000L
+-#define GPIOR_GP1PT 0x02000000L
+-#define GPIOR_GP1ST 0x04000000L
+-#define GPIOR_GP1W 0x08000000L
+-#define GPIOR_GP3OE 0x10000000L
+-#define GPIOR_GP3PT 0x20000000L
+-#define GPIOR_GP3ST 0x40000000L
+-#define GPIOR_GP3W 0x80000000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the clock control register 1.
+-//
+-//****************************************************************************
+-#define CLKCR1_PLLSS_MASK 0x0000000CL
+-#define CLKCR1_PLLSS_SERIAL 0x00000000L
+-#define CLKCR1_PLLSS_CRYSTAL 0x00000004L
+-#define CLKCR1_PLLSS_PCI 0x00000008L
+-#define CLKCR1_PLLSS_RESERVED 0x0000000CL
+-#define CLKCR1_PLLP 0x00000010L
+-#define CLKCR1_SWCE 0x00000020L
+-#define CLKCR1_PLLOS 0x00000040L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the feature reporting register.
+-//
+-//****************************************************************************
+-#define FRR_FAB_MASK 0x00000003L
+-#define FRR_MASK_MASK 0x0000001CL
+-#define FRR_ID_MASK 0x00003000L
+-#define FRR_FAB_SHIFT 0L
+-#define FRR_MASK_SHIFT 2L
+-#define FRR_ID_SHIFT 12L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the serial port 1 configuration
+-// register.
+-//
+-//****************************************************************************
+-#define SERC1_VALUE 0x00000003L
+-#define SERC1_SO1EN 0x00000001L
+-#define SERC1_SO1F_MASK 0x0000000EL
+-#define SERC1_SO1F_CS423X 0x00000000L
+-#define SERC1_SO1F_AC97 0x00000002L
+-#define SERC1_SO1F_DAC 0x00000004L
+-#define SERC1_SO1F_SPDIF 0x00000006L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the serial port 2 configuration
+-// register.
+-//
+-//****************************************************************************
+-#define SERC2_VALUE 0x00000003L
+-#define SERC2_SI1EN 0x00000001L
+-#define SERC2_SI1F_MASK 0x0000000EL
+-#define SERC2_SI1F_CS423X 0x00000000L
+-#define SERC2_SI1F_AC97 0x00000002L
+-#define SERC2_SI1F_ADC 0x00000004L
+-#define SERC2_SI1F_SPDIF 0x00000006L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 control register.
+-//
+-//****************************************************************************
+-#define ACCTL_ESYN 0x00000002L
+-#define ACCTL_VFRM 0x00000004L
+-#define ACCTL_DCV 0x00000008L
+-#define ACCTL_CRW 0x00000010L
+-#define ACCTL_TC 0x00000040L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 status register.
+-//
+-//****************************************************************************
+-#define ACSTS_CRDY 0x00000001L
+-#define ACSTS_VSTS 0x00000002L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 output slot valid
+-// register.
+-//
+-//****************************************************************************
+-#define ACOSV_SLV3 0x00000001L
+-#define ACOSV_SLV4 0x00000002L
+-#define ACOSV_SLV5 0x00000004L
+-#define ACOSV_SLV6 0x00000008L
+-#define ACOSV_SLV7 0x00000010L
+-#define ACOSV_SLV8 0x00000020L
+-#define ACOSV_SLV9 0x00000040L
+-#define ACOSV_SLV10 0x00000080L
+-#define ACOSV_SLV11 0x00000100L
+-#define ACOSV_SLV12 0x00000200L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 command address
+-// register.
+-//
+-//****************************************************************************
+-#define ACCAD_CI_MASK 0x0000007FL
+-#define ACCAD_CI_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 command data register.
+-//
+-//****************************************************************************
+-#define ACCDA_CD_MASK 0x0000FFFFL
+-#define ACCDA_CD_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 input slot valid
+-// register.
+-//
+-//****************************************************************************
+-#define ACISV_ISV3 0x00000001L
+-#define ACISV_ISV4 0x00000002L
+-#define ACISV_ISV5 0x00000004L
+-#define ACISV_ISV6 0x00000008L
+-#define ACISV_ISV7 0x00000010L
+-#define ACISV_ISV8 0x00000020L
+-#define ACISV_ISV9 0x00000040L
+-#define ACISV_ISV10 0x00000080L
+-#define ACISV_ISV11 0x00000100L
+-#define ACISV_ISV12 0x00000200L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 status address
+-// register.
+-//
+-//****************************************************************************
+-#define ACSAD_SI_MASK 0x0000007FL
+-#define ACSAD_SI_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 status data register.
+-//
+-//****************************************************************************
+-#define ACSDA_SD_MASK 0x0000FFFFL
+-#define ACSDA_SD_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the I/O trap address and control
+-// registers (all 12).
+-//
+-//****************************************************************************
+-#define IOTAC_SA_MASK 0x0000FFFFL
+-#define IOTAC_MSK_MASK 0x000F0000L
+-#define IOTAC_IODC_MASK 0x06000000L
+-#define IOTAC_IODC_16_BIT 0x00000000L
+-#define IOTAC_IODC_10_BIT 0x02000000L
+-#define IOTAC_IODC_12_BIT 0x04000000L
+-#define IOTAC_WSPI 0x08000000L
+-#define IOTAC_RSPI 0x10000000L
+-#define IOTAC_WSE 0x20000000L
+-#define IOTAC_WE 0x40000000L
+-#define IOTAC_RE 0x80000000L
+-#define IOTAC_SA_SHIFT 0L
+-#define IOTAC_MSK_SHIFT 16L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PC/PCI master enable
+-// register.
+-//
+-//****************************************************************************
+-#define PCPCIEN_EN 0x00000001L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the joystick poll/trigger
+-// register.
+-//
+-//****************************************************************************
+-#define JSPT_CAX 0x00000001L
+-#define JSPT_CAY 0x00000002L
+-#define JSPT_CBX 0x00000004L
+-#define JSPT_CBY 0x00000008L
+-#define JSPT_BA1 0x00000010L
+-#define JSPT_BA2 0x00000020L
+-#define JSPT_BB1 0x00000040L
+-#define JSPT_BB2 0x00000080L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the joystick control register.
+-// The TBF bit has been moved from MIDSR register to JSCTL register bit 8.
+-//
+-//****************************************************************************
+-#define JSCTL_SP_MASK 0x00000003L
+-#define JSCTL_SP_SLOW 0x00000000L
+-#define JSCTL_SP_MEDIUM_SLOW 0x00000001L
+-#define JSCTL_SP_MEDIUM_FAST 0x00000002L
+-#define JSCTL_SP_FAST 0x00000003L
+-#define JSCTL_ARE 0x00000004L
+-#define JSCTL_TBF 0x00000100L
+-
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the MIDI control register.
+-//
+-//****************************************************************************
+-#define MIDCR_TXE 0x00000001L
+-#define MIDCR_RXE 0x00000002L
+-#define MIDCR_RIE 0x00000004L
+-#define MIDCR_TIE 0x00000008L
+-#define MIDCR_MLB 0x00000010L
+-#define MIDCR_MRST 0x00000020L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the MIDI status register.
+-//
+-//****************************************************************************
+-#define MIDSR_RBE 0x00000080L
+-#define MIDSR_RDA 0x00008000L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the MIDI write port register.
+-//
+-//****************************************************************************
+-#define MIDWP_MWD_MASK 0x000000FFL
+-#define MIDWP_MWD_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the MIDI read port register.
+-//
+-//****************************************************************************
+-#define MIDRP_MRD_MASK 0x000000FFL
+-#define MIDRP_MRD_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the configuration interface
+-// register.
+-//
+-//****************************************************************************
+-#define CFGI_CLK 0x00000001L
+-#define CFGI_DOUT 0x00000002L
+-#define CFGI_DIN_EEN 0x00000004L
+-#define CFGI_EELD 0x00000008L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the subsystem ID and vendor ID
+-// register.
+-//
+-//****************************************************************************
+-#define SSVID_VID_MASK 0x0000FFFFL
+-#define SSVID_SID_MASK 0xFFFF0000L
+-#define SSVID_VID_SHIFT 0L
+-#define SSVID_SID_SHIFT 16L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the GPIO pin interface register.
+-//
+-//****************************************************************************
+-#define GPIOR_VOLDN 0x00000001L
+-#define GPIOR_VOLUP 0x00000002L
+-#define GPIOR_SI2D 0x00000004L
+-#define GPIOR_SI2OE 0x00000008L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 status register 2.
+-//
+-//****************************************************************************
+-#define ACSTS2_CRDY 0x00000001L
+-#define ACSTS2_VSTS 0x00000002L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 input slot valid
+-// register 2.
+-//
+-//****************************************************************************
+-#define ACISV2_ISV3 0x00000001L
+-#define ACISV2_ISV4 0x00000002L
+-#define ACISV2_ISV5 0x00000004L
+-#define ACISV2_ISV6 0x00000008L
+-#define ACISV2_ISV7 0x00000010L
+-#define ACISV2_ISV8 0x00000020L
+-#define ACISV2_ISV9 0x00000040L
+-#define ACISV2_ISV10 0x00000080L
+-#define ACISV2_ISV11 0x00000100L
+-#define ACISV2_ISV12 0x00000200L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 status address
+-// register 2.
+-//
+-//****************************************************************************
+-#define ACSAD2_SI_MASK 0x0000007FL
+-#define ACSAD2_SI_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 status data register 2.
+-//
+-//****************************************************************************
+-#define ACSDA2_SD_MASK 0x0000FFFFL
+-#define ACSDA2_SD_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the I/O trap control register.
+-//
+-//****************************************************************************
+-#define IOTCR_ITD 0x00000001L
+-#define IOTCR_HRV 0x00000002L
+-#define IOTCR_SRV 0x00000004L
+-#define IOTCR_DTI 0x00000008L
+-#define IOTCR_DFI 0x00000010L
+-#define IOTCR_DDP 0x00000020L
+-#define IOTCR_JTE 0x00000040L
+-#define IOTCR_PPE 0x00000080L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the I/O trap address and control
+-// registers for Hardware Master Volume.
+-//
+-//****************************************************************************
+-#define IOTGP_SA_MASK 0x0000FFFFL
+-#define IOTGP_MSK_MASK 0x000F0000L
+-#define IOTGP_IODC_MASK 0x06000000L
+-#define IOTGP_IODC_16_BIT 0x00000000L
+-#define IOTGP_IODC_10_BIT 0x02000000L
+-#define IOTGP_IODC_12_BIT 0x04000000L
+-#define IOTGP_WSPI 0x08000000L
+-#define IOTGP_RSPI 0x10000000L
+-#define IOTGP_WSE 0x20000000L
+-#define IOTGP_WE 0x40000000L
+-#define IOTGP_RE 0x80000000L
+-#define IOTGP_SA_SHIFT 0L
+-#define IOTGP_MSK_SHIFT 16L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the I/O trap address and control
+-// registers for Sound Blaster
+-//
+-//****************************************************************************
+-#define IOTSB_SA_MASK 0x0000FFFFL
+-#define IOTSB_MSK_MASK 0x000F0000L
+-#define IOTSB_IODC_MASK 0x06000000L
+-#define IOTSB_IODC_16_BIT 0x00000000L
+-#define IOTSB_IODC_10_BIT 0x02000000L
+-#define IOTSB_IODC_12_BIT 0x04000000L
+-#define IOTSB_WSPI 0x08000000L
+-#define IOTSB_RSPI 0x10000000L
+-#define IOTSB_WSE 0x20000000L
+-#define IOTSB_WE 0x40000000L
+-#define IOTSB_RE 0x80000000L
+-#define IOTSB_SA_SHIFT 0L
+-#define IOTSB_MSK_SHIFT 16L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the I/O trap address and control
+-// registers for FM.
+-//
+-//****************************************************************************
+-#define IOTFM_SA_MASK 0x0000FFFFL
+-#define IOTFM_MSK_MASK 0x000F0000L
+-#define IOTFM_IODC_MASK 0x06000000L
+-#define IOTFM_IODC_16_BIT 0x00000000L
+-#define IOTFM_IODC_10_BIT 0x02000000L
+-#define IOTFM_IODC_12_BIT 0x04000000L
+-#define IOTFM_WSPI 0x08000000L
+-#define IOTFM_RSPI 0x10000000L
+-#define IOTFM_WSE 0x20000000L
+-#define IOTFM_WE 0x40000000L
+-#define IOTFM_RE 0x80000000L
+-#define IOTFM_SA_SHIFT 0L
+-#define IOTFM_MSK_SHIFT 16L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PC/PCI request register.
+-//
+-//****************************************************************************
+-#define PCPRR_RDC_MASK 0x00000007L
+-#define PCPRR_REQ 0x00008000L
+-#define PCPRR_RDC_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PC/PCI grant register.
+-//
+-//****************************************************************************
+-#define PCPGR_GDC_MASK 0x00000007L
+-#define PCPGR_VL 0x00008000L
+-#define PCPGR_GDC_SHIFT 0L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the PC/PCI Control Register.
+-//
+-//****************************************************************************
+-#define PCPCR_EN 0x00000001L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the debug index register.
+-//
+-//****************************************************************************
+-#define DREG_REGID_MASK 0x0000007FL
+-#define DREG_DEBUG 0x00000080L
+-#define DREG_RGBK_MASK 0x00000700L
+-#define DREG_TRAP 0x00000800L
+-#if !defined(NO_CS4612)
+-#if !defined(NO_CS4615)
+-#define DREG_TRAPX 0x00001000L
+-#endif
+-#endif
+-#define DREG_REGID_SHIFT 0L
+-#define DREG_RGBK_SHIFT 8L
+-#define DREG_RGBK_REGID_MASK 0x0000077FL
+-#define DREG_REGID_R0 0x00000010L
+-#define DREG_REGID_R1 0x00000011L
+-#define DREG_REGID_R2 0x00000012L
+-#define DREG_REGID_R3 0x00000013L
+-#define DREG_REGID_R4 0x00000014L
+-#define DREG_REGID_R5 0x00000015L
+-#define DREG_REGID_R6 0x00000016L
+-#define DREG_REGID_R7 0x00000017L
+-#define DREG_REGID_R8 0x00000018L
+-#define DREG_REGID_R9 0x00000019L
+-#define DREG_REGID_RA 0x0000001AL
+-#define DREG_REGID_RB 0x0000001BL
+-#define DREG_REGID_RC 0x0000001CL
+-#define DREG_REGID_RD 0x0000001DL
+-#define DREG_REGID_RE 0x0000001EL
+-#define DREG_REGID_RF 0x0000001FL
+-#define DREG_REGID_RA_BUS_LOW 0x00000020L
+-#define DREG_REGID_RA_BUS_HIGH 0x00000038L
+-#define DREG_REGID_YBUS_LOW 0x00000050L
+-#define DREG_REGID_YBUS_HIGH 0x00000058L
+-#define DREG_REGID_TRAP_0 0x00000100L
+-#define DREG_REGID_TRAP_1 0x00000101L
+-#define DREG_REGID_TRAP_2 0x00000102L
+-#define DREG_REGID_TRAP_3 0x00000103L
+-#define DREG_REGID_TRAP_4 0x00000104L
+-#define DREG_REGID_TRAP_5 0x00000105L
+-#define DREG_REGID_TRAP_6 0x00000106L
+-#define DREG_REGID_TRAP_7 0x00000107L
+-#define DREG_REGID_INDIRECT_ADDRESS 0x0000010EL
+-#define DREG_REGID_TOP_OF_STACK 0x0000010FL
+-#if !defined(NO_CS4612)
+-#if !defined(NO_CS4615)
+-#define DREG_REGID_TRAP_8 0x00000110L
+-#define DREG_REGID_TRAP_9 0x00000111L
+-#define DREG_REGID_TRAP_10 0x00000112L
+-#define DREG_REGID_TRAP_11 0x00000113L
+-#define DREG_REGID_TRAP_12 0x00000114L
+-#define DREG_REGID_TRAP_13 0x00000115L
+-#define DREG_REGID_TRAP_14 0x00000116L
+-#define DREG_REGID_TRAP_15 0x00000117L
+-#define DREG_REGID_TRAP_16 0x00000118L
+-#define DREG_REGID_TRAP_17 0x00000119L
+-#define DREG_REGID_TRAP_18 0x0000011AL
+-#define DREG_REGID_TRAP_19 0x0000011BL
+-#define DREG_REGID_TRAP_20 0x0000011CL
+-#define DREG_REGID_TRAP_21 0x0000011DL
+-#define DREG_REGID_TRAP_22 0x0000011EL
+-#define DREG_REGID_TRAP_23 0x0000011FL
+-#endif
+-#endif
+-#define DREG_REGID_RSA0_LOW 0x00000200L
+-#define DREG_REGID_RSA0_HIGH 0x00000201L
+-#define DREG_REGID_RSA1_LOW 0x00000202L
+-#define DREG_REGID_RSA1_HIGH 0x00000203L
+-#define DREG_REGID_RSA2 0x00000204L
+-#define DREG_REGID_RSA3 0x00000205L
+-#define DREG_REGID_RSI0_LOW 0x00000206L
+-#define DREG_REGID_RSI0_HIGH 0x00000207L
+-#define DREG_REGID_RSI1 0x00000208L
+-#define DREG_REGID_RSI2 0x00000209L
+-#define DREG_REGID_SAGUSTATUS 0x0000020AL
+-#define DREG_REGID_RSCONFIG01_LOW 0x0000020BL
+-#define DREG_REGID_RSCONFIG01_HIGH 0x0000020CL
+-#define DREG_REGID_RSCONFIG23_LOW 0x0000020DL
+-#define DREG_REGID_RSCONFIG23_HIGH 0x0000020EL
+-#define DREG_REGID_RSDMA01E 0x0000020FL
+-#define DREG_REGID_RSDMA23E 0x00000210L
+-#define DREG_REGID_RSD0_LOW 0x00000211L
+-#define DREG_REGID_RSD0_HIGH 0x00000212L
+-#define DREG_REGID_RSD1_LOW 0x00000213L
+-#define DREG_REGID_RSD1_HIGH 0x00000214L
+-#define DREG_REGID_RSD2_LOW 0x00000215L
+-#define DREG_REGID_RSD2_HIGH 0x00000216L
+-#define DREG_REGID_RSD3_LOW 0x00000217L
+-#define DREG_REGID_RSD3_HIGH 0x00000218L
+-#define DREG_REGID_SRAR_HIGH 0x0000021AL
+-#define DREG_REGID_SRAR_LOW 0x0000021BL
+-#define DREG_REGID_DMA_STATE 0x0000021CL
+-#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021DL
+-#define DREG_REGID_NEXT_DMA_STREAM 0x0000021EL
+-#define DREG_REGID_CPU_STATUS 0x00000300L
+-#define DREG_REGID_MAC_MODE 0x00000301L
+-#define DREG_REGID_STACK_AND_REPEAT 0x00000302L
+-#define DREG_REGID_INDEX0 0x00000304L
+-#define DREG_REGID_INDEX1 0x00000305L
+-#define DREG_REGID_DMA_STATE_0_3 0x00000400L
+-#define DREG_REGID_DMA_STATE_4_7 0x00000404L
+-#define DREG_REGID_DMA_STATE_8_11 0x00000408L
+-#define DREG_REGID_DMA_STATE_12_15 0x0000040CL
+-#define DREG_REGID_DMA_STATE_16_19 0x00000410L
+-#define DREG_REGID_DMA_STATE_20_23 0x00000414L
+-#define DREG_REGID_DMA_STATE_24_27 0x00000418L
+-#define DREG_REGID_DMA_STATE_28_31 0x0000041CL
+-#define DREG_REGID_DMA_STATE_32_35 0x00000420L
+-#define DREG_REGID_DMA_STATE_36_39 0x00000424L
+-#define DREG_REGID_DMA_STATE_40_43 0x00000428L
+-#define DREG_REGID_DMA_STATE_44_47 0x0000042CL
+-#define DREG_REGID_DMA_STATE_48_51 0x00000430L
+-#define DREG_REGID_DMA_STATE_52_55 0x00000434L
+-#define DREG_REGID_DMA_STATE_56_59 0x00000438L
+-#define DREG_REGID_DMA_STATE_60_63 0x0000043CL
+-#define DREG_REGID_DMA_STATE_64_67 0x00000440L
+-#define DREG_REGID_DMA_STATE_68_71 0x00000444L
+-#define DREG_REGID_DMA_STATE_72_75 0x00000448L
+-#define DREG_REGID_DMA_STATE_76_79 0x0000044CL
+-#define DREG_REGID_DMA_STATE_80_83 0x00000450L
+-#define DREG_REGID_DMA_STATE_84_87 0x00000454L
+-#define DREG_REGID_DMA_STATE_88_91 0x00000458L
+-#define DREG_REGID_DMA_STATE_92_95 0x0000045CL
+-#define DREG_REGID_TRAP_SELECT 0x00000500L
+-#define DREG_REGID_TRAP_WRITE_0 0x00000500L
+-#define DREG_REGID_TRAP_WRITE_1 0x00000501L
+-#define DREG_REGID_TRAP_WRITE_2 0x00000502L
+-#define DREG_REGID_TRAP_WRITE_3 0x00000503L
+-#define DREG_REGID_TRAP_WRITE_4 0x00000504L
+-#define DREG_REGID_TRAP_WRITE_5 0x00000505L
+-#define DREG_REGID_TRAP_WRITE_6 0x00000506L
+-#define DREG_REGID_TRAP_WRITE_7 0x00000507L
+-#if !defined(NO_CS4612)
+-#if !defined(NO_CS4615)
+-#define DREG_REGID_TRAP_WRITE_8 0x00000510L
+-#define DREG_REGID_TRAP_WRITE_9 0x00000511L
+-#define DREG_REGID_TRAP_WRITE_10 0x00000512L
+-#define DREG_REGID_TRAP_WRITE_11 0x00000513L
+-#define DREG_REGID_TRAP_WRITE_12 0x00000514L
+-#define DREG_REGID_TRAP_WRITE_13 0x00000515L
+-#define DREG_REGID_TRAP_WRITE_14 0x00000516L
+-#define DREG_REGID_TRAP_WRITE_15 0x00000517L
+-#define DREG_REGID_TRAP_WRITE_16 0x00000518L
+-#define DREG_REGID_TRAP_WRITE_17 0x00000519L
+-#define DREG_REGID_TRAP_WRITE_18 0x0000051AL
+-#define DREG_REGID_TRAP_WRITE_19 0x0000051BL
+-#define DREG_REGID_TRAP_WRITE_20 0x0000051CL
+-#define DREG_REGID_TRAP_WRITE_21 0x0000051DL
+-#define DREG_REGID_TRAP_WRITE_22 0x0000051EL
+-#define DREG_REGID_TRAP_WRITE_23 0x0000051FL
+-#endif
+-#endif
+-#define DREG_REGID_MAC0_ACC0_LOW 0x00000600L
+-#define DREG_REGID_MAC0_ACC1_LOW 0x00000601L
+-#define DREG_REGID_MAC0_ACC2_LOW 0x00000602L
+-#define DREG_REGID_MAC0_ACC3_LOW 0x00000603L
+-#define DREG_REGID_MAC1_ACC0_LOW 0x00000604L
+-#define DREG_REGID_MAC1_ACC1_LOW 0x00000605L
+-#define DREG_REGID_MAC1_ACC2_LOW 0x00000606L
+-#define DREG_REGID_MAC1_ACC3_LOW 0x00000607L
+-#define DREG_REGID_MAC0_ACC0_MID 0x00000608L
+-#define DREG_REGID_MAC0_ACC1_MID 0x00000609L
+-#define DREG_REGID_MAC0_ACC2_MID 0x0000060AL
+-#define DREG_REGID_MAC0_ACC3_MID 0x0000060BL
+-#define DREG_REGID_MAC1_ACC0_MID 0x0000060CL
+-#define DREG_REGID_MAC1_ACC1_MID 0x0000060DL
+-#define DREG_REGID_MAC1_ACC2_MID 0x0000060EL
+-#define DREG_REGID_MAC1_ACC3_MID 0x0000060FL
+-#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610L
+-#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611L
+-#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612L
+-#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613L
+-#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614L
+-#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615L
+-#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616L
+-#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617L
+-#define DREG_REGID_RSHOUT_LOW 0x00000620L
+-#define DREG_REGID_RSHOUT_MID 0x00000628L
+-#define DREG_REGID_RSHOUT_HIGH 0x00000630L
+-
+-//****************************************************************************
+-//
+-// The following defines are for the flags in the AC97 S/PDIF Control register.
+-//
+-//****************************************************************************
+-#define SPDIF_CONTROL_SPDIF_EN 0x00008000L
+-#define SPDIF_CONTROL_VAL 0x00004000L
+-#define SPDIF_CONTROL_COPY 0x00000004L
+-#define SPDIF_CONTROL_CC0 0x00000010L
+-#define SPDIF_CONTROL_CC1 0x00000020L
+-#define SPDIF_CONTROL_CC2 0x00000040L
+-#define SPDIF_CONTROL_CC3 0x00000080L
+-#define SPDIF_CONTROL_CC4 0x00000100L
+-#define SPDIF_CONTROL_CC5 0x00000200L
+-#define SPDIF_CONTROL_CC6 0x00000400L
+-#define SPDIF_CONTROL_L 0x00000800L
+-
+-#endif // _H_HWDEFS
+diff --git a/sound/oss/cs4281/cs4281_wrapper-24.c b/sound/oss/cs4281/cs4281_wrapper-24.c
+deleted file mode 100644
+index 4559f02..0000000
+--- a/sound/oss/cs4281/cs4281_wrapper-24.c
++++ /dev/null
+@@ -1,41 +0,0 @@
+-/*******************************************************************************
+-*
+-* "cs4281_wrapper.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
+-*
+-* Copyright (C) 2000,2001 Cirrus Logic Corp.
+-* -- tom woller (twoller at crystal.cirrus.com) or
+-* (audio at crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+-*
+-* 12/20/00 trw - new file.
+-*
+-*******************************************************************************/
+-
+-#include <linux/spinlock.h>
+-
+-static int cs4281_resume_null(struct pci_dev *pcidev) { return 0; }
+-static int cs4281_suspend_null(struct pci_dev *pcidev, pm_message_t state) { return 0; }
+-
+-#define free_dmabuf(state, dmabuf) \
+- pci_free_consistent(state->pcidev, \
+- PAGE_SIZE << (dmabuf)->buforder, \
+- (dmabuf)->rawbuf, (dmabuf)->dmaaddr);
+-#define free_dmabuf2(state, dmabuf) \
+- pci_free_consistent((state)->pcidev, \
+- PAGE_SIZE << (state)->buforder_tmpbuff, \
+- (state)->tmpbuff, (state)->dmaaddr_tmpbuff);
+-#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
+-
+diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
+deleted file mode 100644
+index 0400a41..0000000
+--- a/sound/oss/cs4281/cs4281m.c
++++ /dev/null
+@@ -1,4487 +0,0 @@
+-/*******************************************************************************
+-*
+-* "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
+-*
+-* Copyright (C) 2000,2001 Cirrus Logic Corp.
+-* -- adapted from drivers by Thomas Sailer,
+-* -- but don't bug him; Problems should go to:
+-* -- tom woller (twoller at crystal.cirrus.com) or
+-* (audio at crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+-*
+-* Module command line parameters:
+-* none
+-*
+-* Supported devices:
+-* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+-* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+-* /dev/midi simple MIDI UART interface, no ioctl
+-*
+-* Modification History
+-* 08/20/00 trw - silence and no stopping DAC until release
+-* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop.
+-* 09/18/00 trw - added 16bit only record with conversion
+-* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous
+-* capture/playback rates)
+-* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin
+-* libOSSm.so)
+-* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal)
+-* 11/03/00 trw - fixed interrupt loss/stutter, added debug.
+-* 11/10/00 bkz - added __devinit to cs4281_hw_init()
+-* 11/10/00 trw - fixed SMP and capture spinlock hang.
+-* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm.
+-* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix.
+-* 12/08/00 trw - added PM support.
+-* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8
+-* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident.
+-* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup.
+-* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use
+-* defaultorder-100 as power of 2 for the buffer size. example:
+-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
+-*
+-*******************************************************************************/
+-
+-/* uncomment the following line to disable building PM support into the driver */
+-//#define NOT_CS4281_PM 1
+-
+-#include <linux/list.h>
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/bitops.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/poll.h>
+-#include <linux/fs.h>
+-#include <linux/wait.h>
+-
+-#include <asm/current.h>
+-#include <asm/io.h>
+-#include <asm/dma.h>
+-#include <asm/page.h>
+-#include <asm/uaccess.h>
+-
+-//#include "cs_dm.h"
+-#include "cs4281_hwdefs.h"
+-#include "cs4281pm.h"
+-
+-struct cs4281_state;
+-
+-static void stop_dac(struct cs4281_state *s);
+-static void stop_adc(struct cs4281_state *s);
+-static void start_dac(struct cs4281_state *s);
+-static void start_adc(struct cs4281_state *s);
+-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+-
+-// ---------------------------------------------------------------------
+-
+-#ifndef PCI_VENDOR_ID_CIRRUS
+-#define PCI_VENDOR_ID_CIRRUS 0x1013
+-#endif
+-#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281
+-#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005
+-#endif
+-
+-#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
+-#define CS4281_CFLR_DEFAULT 0x00000001 /* CFLR must be in AC97 link mode */
+-
+-// buffer order determines the size of the dma buffer for the driver.
+-// under Linux, a smaller buffer allows more responsiveness from many of the
+-// applications (e.g. games). A larger buffer allows some of the apps (esound)
+-// to not underrun the dma buffer as easily. As default, use 32k (order=3)
+-// rather than 64k as some of the games work more responsively.
+-// log base 2( buff sz = 32k).
+-static unsigned long defaultorder = 3;
+-module_param(defaultorder, ulong, 0);
+-
+-//
+-// Turn on/off debugging compilation by commenting out "#define CSDEBUG"
+-//
+-#define CSDEBUG 1
+-#if CSDEBUG
+-#define CSDEBUG_INTERFACE 1
+-#else
+-#undef CSDEBUG_INTERFACE
+-#endif
+-//
+-// cs_debugmask areas
+-//
+-#define CS_INIT 0x00000001 // initialization and probe functions
+-#define CS_ERROR 0x00000002 // tmp debugging bit placeholder
+-#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other)
+-#define CS_FUNCTION 0x00000008 // enter/leave functions
+-#define CS_WAVE_WRITE 0x00000010 // write information for wave
+-#define CS_WAVE_READ 0x00000020 // read information for wave
+-#define CS_MIDI_WRITE 0x00000040 // write information for midi
+-#define CS_MIDI_READ 0x00000080 // read information for midi
+-#define CS_MPU401_WRITE 0x00000100 // write information for mpu401
+-#define CS_MPU401_READ 0x00000200 // read information for mpu401
+-#define CS_OPEN 0x00000400 // all open functions in the driver
+-#define CS_RELEASE 0x00000800 // all release functions in the driver
+-#define CS_PARMS 0x00001000 // functional and operational parameters
+-#define CS_IOCTL 0x00002000 // ioctl (non-mixer)
+-#define CS_PM 0x00004000 // power management
+-#define CS_TMP 0x10000000 // tmp debug mask bit
+-
+-#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend
+-#define CS_IOCTL_CMD_RESUME 0x2 // resume
+-//
+-// CSDEBUG is usual mode is set to 1, then use the
+-// cs_debuglevel and cs_debugmask to turn on or off debugging.
+-// Debug level of 1 has been defined to be kernel errors and info
+-// that should be printed on any released driver.
+-//
+-#if CSDEBUG
+-#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}
+-#else
+-#define CS_DBGOUT(mask,level,x)
+-#endif
+-
+-#if CSDEBUG
+-static unsigned long cs_debuglevel = 1; // levels range from 1-9
+-static unsigned long cs_debugmask = CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values
+-module_param(cs_debuglevel, ulong, 0);
+-module_param(cs_debugmask, ulong, 0);
+-#endif
+-#define CS_TRUE 1
+-#define CS_FALSE 0
+-
+-// MIDI buffer sizes
+-#define MIDIINBUF 500
+-#define MIDIOUTBUF 500
+-
+-#define FMODE_MIDI_SHIFT 3
+-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
+-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+-
+-#define CS4281_MAJOR_VERSION 1
+-#define CS4281_MINOR_VERSION 13
+-#ifdef __ia64__
+-#define CS4281_ARCH 64 //architecture key
+-#else
+-#define CS4281_ARCH 32 //architecture key
+-#endif
+-
+-#define CS_TYPE_ADC 0
+-#define CS_TYPE_DAC 1
+-
+-
+-static const char invalid_magic[] =
+- KERN_CRIT "cs4281: invalid magic value\n";
+-
+-#define VALIDATE_STATE(s) \
+-({ \
+- if (!(s) || (s)->magic != CS4281_MAGIC) { \
+- printk(invalid_magic); \
+- return -ENXIO; \
+- } \
+-})
+-
+-//LIST_HEAD(cs4281_devs);
+-static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs };
+-
+-struct cs4281_state;
+-
+-#include "cs4281_wrapper-24.c"
+-
+-struct cs4281_state {
+- // magic
+- unsigned int magic;
+-
+- // we keep the cards in a linked list
+- struct cs4281_state *next;
+-
+- // pcidev is needed to turn off the DDMA controller at driver shutdown
+- struct pci_dev *pcidev;
+- struct list_head list;
+-
+- // soundcore stuff
+- int dev_audio;
+- int dev_mixer;
+- int dev_midi;
+-
+- // hardware resources
+- unsigned int pBA0phys, pBA1phys;
+- char __iomem *pBA0;
+- char __iomem *pBA1;
+- unsigned int irq;
+-
+- // mixer registers
+- struct {
+- unsigned short vol[10];
+- unsigned int recsrc;
+- unsigned int modcnt;
+- unsigned short micpreamp;
+- } mix;
+-
+- // wave stuff
+- struct properties {
+- unsigned fmt;
+- unsigned fmt_original; // original requested format
+- unsigned channels;
+- unsigned rate;
+- unsigned char clkdiv;
+- } prop_dac, prop_adc;
+- unsigned conversion:1; // conversion from 16 to 8 bit in progress
+- void *tmpbuff; // tmp buffer for sample conversions
+- unsigned ena;
+- spinlock_t lock;
+- struct mutex open_sem;
+- struct mutex open_sem_adc;
+- struct mutex open_sem_dac;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+- wait_queue_head_t open_wait_adc;
+- wait_queue_head_t open_wait_dac;
+-
+- dma_addr_t dmaaddr_tmpbuff;
+- unsigned buforder_tmpbuff; // Log base 2 of 'rawbuf' size in bytes..
+- struct dmabuf {
+- void *rawbuf; // Physical address of
+- dma_addr_t dmaaddr;
+- unsigned buforder; // Log base 2 of 'rawbuf' size in bytes..
+- unsigned numfrag; // # of 'fragments' in the buffer.
+- unsigned fragshift; // Log base 2 of fragment size.
+- unsigned hwptr, swptr;
+- unsigned total_bytes; // # bytes process since open.
+- unsigned blocks; // last returned blocks value GETOPTR
+- unsigned wakeup; // interrupt occurred on block
+- int count;
+- unsigned underrun; // underrun flag
+- unsigned error; // over/underrun
+- wait_queue_head_t wait;
+- // redundant, but makes calculations easier
+- unsigned fragsize; // 2**fragshift..
+- unsigned dmasize; // 2**buforder.
+- unsigned fragsamples;
+- // OSS stuff
+- unsigned mapped:1; // Buffer mapped in cs4281_mmap()?
+- unsigned ready:1; // prog_dmabuf_dac()/adc() successful?
+- unsigned endcleared:1;
+- unsigned type:1; // adc or dac buffer (CS_TYPE_XXX)
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac, dma_adc;
+-
+- // midi stuff
+- struct {
+- unsigned ird, iwr, icnt;
+- unsigned ord, owr, ocnt;
+- wait_queue_head_t iwait;
+- wait_queue_head_t owait;
+- struct timer_list timer;
+- unsigned char ibuf[MIDIINBUF];
+- unsigned char obuf[MIDIOUTBUF];
+- } midi;
+-
+- struct cs4281_pm pm;
+- struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];
+-};
+-
+-#include "cs4281pm-24.c"
+-
+-#if CSDEBUG
+-
+-// DEBUG ROUTINES
+-
+-#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
+-#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
+-#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
+-#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
+-
+-#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
+-
+-
+-static void cs_printioctl(unsigned int x)
+-{
+- unsigned int i;
+- unsigned char vidx;
+- // Index of mixtable1[] member is Device ID
+- // and must be <= SOUND_MIXER_NRDEVICES.
+- // Value of array member is index into s->mix.vol[]
+- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_PCM] = 1, // voice
+- [SOUND_MIXER_LINE1] = 2, // AUX
+- [SOUND_MIXER_CD] = 3, // CD
+- [SOUND_MIXER_LINE] = 4, // Line
+- [SOUND_MIXER_SYNTH] = 5, // FM
+- [SOUND_MIXER_MIC] = 6, // Mic
+- [SOUND_MIXER_SPEAKER] = 7, // Speaker
+- [SOUND_MIXER_RECLEV] = 8, // Recording level
+- [SOUND_MIXER_VOLUME] = 9 // Master Volume
+- };
+-
+- switch (x) {
+- case SOUND_MIXER_CS_GETDBGMASK:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_CS_GETDBGMASK:\n"));
+- break;
+- case SOUND_MIXER_CS_GETDBGLEVEL:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_CS_GETDBGLEVEL:\n"));
+- break;
+- case SOUND_MIXER_CS_SETDBGMASK:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_CS_SETDBGMASK:\n"));
+- break;
+- case SOUND_MIXER_CS_SETDBGLEVEL:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_CS_SETDBGLEVEL:\n"));
+- break;
+- case OSS_GETVERSION:
+- CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n"));
+- break;
+- case SNDCTL_DSP_SYNC:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n"));
+- break;
+- case SNDCTL_DSP_SETDUPLEX:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n"));
+- break;
+- case SNDCTL_DSP_GETCAPS:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n"));
+- break;
+- case SNDCTL_DSP_RESET:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n"));
+- break;
+- case SNDCTL_DSP_SPEED:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n"));
+- break;
+- case SNDCTL_DSP_STEREO:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n"));
+- break;
+- case SNDCTL_DSP_CHANNELS:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n"));
+- break;
+- case SNDCTL_DSP_GETFMTS:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n"));
+- break;
+- case SNDCTL_DSP_SETFMT:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n"));
+- break;
+- case SNDCTL_DSP_POST:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n"));
+- break;
+- case SNDCTL_DSP_GETTRIGGER:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n"));
+- break;
+- case SNDCTL_DSP_SETTRIGGER:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n"));
+- break;
+- case SNDCTL_DSP_GETOSPACE:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n"));
+- break;
+- case SNDCTL_DSP_GETISPACE:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n"));
+- break;
+- case SNDCTL_DSP_NONBLOCK:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n"));
+- break;
+- case SNDCTL_DSP_GETODELAY:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n"));
+- break;
+- case SNDCTL_DSP_GETIPTR:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n"));
+- break;
+- case SNDCTL_DSP_GETOPTR:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n"));
+- break;
+- case SNDCTL_DSP_GETBLKSIZE:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n"));
+- break;
+- case SNDCTL_DSP_SETFRAGMENT:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SNDCTL_DSP_SETFRAGMENT:\n"));
+- break;
+- case SNDCTL_DSP_SUBDIVIDE:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n"));
+- break;
+- case SOUND_PCM_READ_RATE:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n"));
+- break;
+- case SOUND_PCM_READ_CHANNELS:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_PCM_READ_CHANNELS:\n"));
+- break;
+- case SOUND_PCM_READ_BITS:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n"));
+- break;
+- case SOUND_PCM_WRITE_FILTER:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_PCM_WRITE_FILTER:\n"));
+- break;
+- case SNDCTL_DSP_SETSYNCRO:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n"));
+- break;
+- case SOUND_PCM_READ_FILTER:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n"));
+- break;
+- case SOUND_MIXER_PRIVATE1:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n"));
+- break;
+- case SOUND_MIXER_PRIVATE2:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n"));
+- break;
+- case SOUND_MIXER_PRIVATE3:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n"));
+- break;
+- case SOUND_MIXER_PRIVATE4:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n"));
+- break;
+- case SOUND_MIXER_PRIVATE5:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n"));
+- break;
+- case SOUND_MIXER_INFO:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n"));
+- break;
+- case SOUND_OLD_MIXER_INFO:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n"));
+- break;
+-
+- default:
+- switch (_IOC_NR(x)) {
+- case SOUND_MIXER_VOLUME:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_VOLUME:\n"));
+- break;
+- case SOUND_MIXER_SPEAKER:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_SPEAKER:\n"));
+- break;
+- case SOUND_MIXER_RECLEV:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_RECLEV:\n"));
+- break;
+- case SOUND_MIXER_MIC:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_MIC:\n"));
+- break;
+- case SOUND_MIXER_SYNTH:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_SYNTH:\n"));
+- break;
+- case SOUND_MIXER_RECSRC:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_RECSRC:\n"));
+- break;
+- case SOUND_MIXER_DEVMASK:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_DEVMASK:\n"));
+- break;
+- case SOUND_MIXER_RECMASK:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_RECMASK:\n"));
+- break;
+- case SOUND_MIXER_STEREODEVS:
+- CS_DBGOUT(CS_IOCTL, 4,
+- printk("SOUND_MIXER_STEREODEVS:\n"));
+- break;
+- case SOUND_MIXER_CAPS:
+- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n"));
+- break;
+- default:
+- i = _IOC_NR(x);
+- if (i >= SOUND_MIXER_NRDEVICES
+- || !(vidx = mixtable1[i])) {
+- CS_DBGOUT(CS_IOCTL, 4, printk
+- ("UNKNOWN IOCTL: 0x%.8x NR=%d\n",
+- x, i));
+- } else {
+- CS_DBGOUT(CS_IOCTL, 4, printk
+- ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n",
+- x, i));
+- }
+- break;
+- }
+- }
+-}
+-#endif
+-static int prog_dmabuf_adc(struct cs4281_state *s);
+-static void prog_codec(struct cs4281_state *s, unsigned type);
+-
+-// ---------------------------------------------------------------------
+-//
+-// Hardware Interfaces For the CS4281
+-//
+-
+-
+-//******************************************************************************
+-// "delayus()-- Delay for the specified # of microseconds.
+-//******************************************************************************
+-static void delayus(struct cs4281_state *s, u32 delay)
+-{
+- u32 j;
+- if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) {
+- j = (delay * HZ) / 1000000; /* calculate delay in jiffies */
+- if (j < 1)
+- j = 1; /* minimum one jiffy. */
+- current->state = TASK_UNINTERRUPTIBLE;
+- schedule_timeout(j);
+- } else
+- udelay(delay);
+- return;
+-}
+-
+-
+-//******************************************************************************
+-// "cs4281_read_ac97" -- Reads a word from the specified location in the
+-// CS4281's address space(based on the BA0 register).
+-//
+-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
+-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register,
+-// 0h for reads.
+-// 3. Write ACCTL = Control Register = 460h for initiating the write
+-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
+-// 5. if DCV not cleared, break and return error
+-// 6. Read ACSTS = Status Register = 464h, check VSTS bit
+-//****************************************************************************
+-static int cs4281_read_ac97(struct cs4281_state *card, u32 offset,
+- u32 * value)
+-{
+- u32 count, status;
+-
+- // Make sure that there is not data sitting
+- // around from a previous uncompleted access.
+- // ACSDA = Status Data Register = 47Ch
+- status = readl(card->pBA0 + BA0_ACSDA);
+-
+- // Setup the AC97 control registers on the CS4281 to send the
+- // appropriate command to the AC97 to perform the read.
+- // ACCAD = Command Address Register = 46Ch
+- // ACCDA = Command Data Register = 470h
+- // ACCTL = Control Register = 460h
+- // bit DCV - will clear when process completed
+- // bit CRW - Read command
+- // bit VFRM - valid frame enabled
+- // bit ESYN - ASYNC generation enabled
+-
+- // Get the actual AC97 register from the offset
+- writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
+- writel(0, card->pBA0 + BA0_ACCDA);
+- writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN,
+- card->pBA0 + BA0_ACCTL);
+-
+- // Wait for the read to occur.
+- for (count = 0; count < 10; count++) {
+- // First, we want to wait for a short time.
+- udelay(25);
+-
+- // Now, check to see if the read has completed.
+- // ACCTL = 460h, DCV should be reset by now and 460h = 17h
+- if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV))
+- break;
+- }
+-
+- // Make sure the read completed.
+- if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)
+- return 1;
+-
+- // Wait for the valid status bit to go active.
+- for (count = 0; count < 10; count++) {
+- // Read the AC97 status register.
+- // ACSTS = Status Register = 464h
+- status = readl(card->pBA0 + BA0_ACSTS);
+-
+- // See if we have valid status.
+- // VSTS - Valid Status
+- if (status & ACSTS_VSTS)
+- break;
+- // Wait for a short while.
+- udelay(25);
+- }
+-
+- // Make sure we got valid status.
+- if (!(status & ACSTS_VSTS))
+- return 1;
+-
+- // Read the data returned from the AC97 register.
+- // ACSDA = Status Data Register = 474h
+- *value = readl(card->pBA0 + BA0_ACSDA);
+-
+- // Success.
+- return (0);
+-}
+-
+-
+-//****************************************************************************
+-//
+-// "cs4281_write_ac97()"-- writes a word to the specified location in the
+-// CS461x's address space (based on the part's base address zero register).
+-//
+-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
+-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg.
+-// 3. Write ACCTL = Control Register = 460h for initiating the write
+-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
+-// 5. if DCV not cleared, break and return error
+-//
+-//****************************************************************************
+-static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,
+- u32 value)
+-{
+- u32 count, status=0;
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n"));
+-
+- // Setup the AC97 control registers on the CS4281 to send the
+- // appropriate command to the AC97 to perform the read.
+- // ACCAD = Command Address Register = 46Ch
+- // ACCDA = Command Data Register = 470h
+- // ACCTL = Control Register = 460h
+- // set DCV - will clear when process completed
+- // reset CRW - Write command
+- // set VFRM - valid frame enabled
+- // set ESYN - ASYNC generation enabled
+- // set RSTN - ARST# inactive, AC97 codec not reset
+-
+- // Get the actual AC97 register from the offset
+-
+- writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
+- writel(value, card->pBA0 + BA0_ACCDA);
+- writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN,
+- card->pBA0 + BA0_ACCTL);
+-
+- // Wait for the write to occur.
+- for (count = 0; count < 100; count++) {
+- // First, we want to wait for a short time.
+- udelay(25);
+- // Now, check to see if the write has completed.
+- // ACCTL = 460h, DCV should be reset by now and 460h = 07h
+- status = readl(card->pBA0 + BA0_ACCTL);
+- if (!(status & ACCTL_DCV))
+- break;
+- }
+-
+- // Make sure the write completed.
+- if (status & ACCTL_DCV) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+- "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n"));
+- return 1;
+- }
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n"));
+- // Success.
+- return 0;
+-}
+-
+-
+-//******************************************************************************
+-// "Init4281()" -- Bring up the part.
+-//******************************************************************************
+-static __devinit int cs4281_hw_init(struct cs4281_state *card)
+-{
+- u32 ac97_slotid;
+- u32 temp1, temp2;
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n"));
+-#ifndef NOT_CS4281_PM
+- if(!card)
+- return 1;
+-#endif
+- temp2 = readl(card->pBA0 + BA0_CFLR);
+- CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2));
+- if(temp2 != CS4281_CFLR_DEFAULT)
+- {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
+- "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n",
+- temp2,CS4281_CFLR_DEFAULT));
+- writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR);
+- temp2 = readl(card->pBA0 + BA0_CFLR);
+- if(temp2 != CS4281_CFLR_DEFAULT)
+- {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
+- "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n"));
+- return 1;
+- }
+- }
+-
+- //***************************************7
+- // Set up the Sound System Configuration
+- //***************************************
+-
+- // Set the 'Configuration Write Protect' register
+- // to 4281h. Allows vendor-defined configuration
+- // space between 0e4h and 0ffh to be written.
+-
+- writel(0x4281, card->pBA0 + BA0_CWPR); // (3e0h)
+-
+- // (0), Blast the clock control register to zero so that the
+- // PLL starts out in a known state, and blast the master serial
+- // port control register to zero so that the serial ports also
+- // start out in a known state.
+-
+- writel(0, card->pBA0 + BA0_CLKCR1); // (400h)
+- writel(0, card->pBA0 + BA0_SERMC); // (420h)
+-
+-
+- // (1), Make ESYN go to zero to turn off
+- // the Sync pulse on the AC97 link.
+-
+- writel(0, card->pBA0 + BA0_ACCTL);
+- udelay(50);
+-
+-
+- // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
+- // the AC97 spec) and then drive it high. This is done for non
+- // AC97 modes since there might be logic external to the CS461x
+- // that uses the ARST# line for a reset.
+-
+- writel(0, card->pBA0 + BA0_SPMC); // (3ech)
+- udelay(100);
+- writel(SPMC_RSTN, card->pBA0 + BA0_SPMC);
+- delayus(card,50000); // Wait 50 ms for ABITCLK to become stable.
+-
+- // (3) Turn on the Sound System Clocks.
+- writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1); // (400h)
+- delayus(card,50000); // Wait for the PLL to stabilize.
+- // Turn on clocking of the core (CLKCR1(400h) = 0x00000030)
+- writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1);
+-
+- // (4) Power on everything for now..
+- writel(0x7E, card->pBA0 + BA0_SSPM); // (740h)
+-
+- // (5) Wait for clock stabilization.
+- for (temp1 = 0; temp1 < 1000; temp1++) {
+- udelay(1000);
+- if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)
+- break;
+- }
+- if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: DLLRDY failed!\n"));
+- return -EIO;
+- }
+- // (6) Enable ASYNC generation.
+- writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
+-
+- // Now wait 'for a short while' to allow the AC97
+- // part to start generating bit clock. (so we don't
+- // Try to start the PLL without an input clock.)
+- delayus(card,50000);
+-
+- // Set the serial port timing configuration, so that the
+- // clock control circuit gets its clock from the right place.
+- writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
+-
+- // (7) Wait for the codec ready signal from the AC97 codec.
+-
+- for (temp1 = 0; temp1 < 1000; temp1++) {
+- // Delay a mil to let things settle out and
+- // to prevent retrying the read too quickly.
+- udelay(1000);
+- if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY) // If ready, (464h)
+- break; // exit the 'for' loop.
+- }
+- if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)) // If never came ready,
+- {
+- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
+- "cs4281: ACSTS never came ready!\n"));
+- return -EIO; // exit initialization.
+- }
+- // (8) Assert the 'valid frame' signal so we can
+- // begin sending commands to the AC97 codec.
+- writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
+-
+- // (9), Wait until CODEC calibration is finished.
+- // Print an error message if it doesn't.
+- for (temp1 = 0; temp1 < 1000; temp1++) {
+- delayus(card,10000);
+- // Read the AC97 Powerdown Control/Status Register.
+- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);
+- if ((temp2 & 0x0000000F) == 0x0000000F)
+- break;
+- }
+- if ((temp2 & 0x0000000F) != 0x0000000F) {
+- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
+- "cs4281: Codec failed to calibrate. Status = %.8x.\n",
+- temp2));
+- return -EIO;
+- }
+- // (10), Set the serial port timing configuration, so that the
+- // clock control circuit gets its clock from the right place.
+- writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
+-
+-
+- // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
+- // that the codec is pumping ADC data across the AC link.
+- for (temp1 = 0; temp1 < 1000; temp1++) {
+- // Delay a mil to let things settle out and
+- // to prevent retrying the read too quickly.
+- delayus(card,1000); //(test)
+-
+- // Read the input slot valid register; See
+- // if input slots 3 and 4 are valid yet.
+- if (
+- (readl(card->pBA0 + BA0_ACISV) &
+- (ACISV_ISV3 | ACISV_ISV4)) ==
+- (ACISV_ISV3 | ACISV_ISV4)) break; // Exit the 'for' if slots are valid.
+- }
+- // If we never got valid data, exit initialization.
+- if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4))
+- != (ACISV_ISV3 | ACISV_ISV4)) {
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_ERR
+- "cs4281: Never got valid data!\n"));
+- return -EIO; // If no valid data, exit initialization.
+- }
+- // (12), Start digital data transfer of audio data to the codec.
+- writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV); // (468h)
+-
+-
+- //**************************************
+- // Unmute the Master and Alternate
+- // (headphone) volumes. Set to max.
+- //**************************************
+- cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0);
+- cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0);
+-
+- //******************************************
+- // Power on the DAC(AddDACUser()from main())
+- //******************************************
+- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+- cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
+-
+- // Wait until we sample a DAC ready state.
+- for (temp2 = 0; temp2 < 32; temp2++) {
+- // Let's wait a mil to let things settle.
+- delayus(card,1000);
+- // Read the current state of the power control reg.
+- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+- // If the DAC ready state bit is set, stop waiting.
+- if (temp1 & 0x2)
+- break;
+- }
+-
+- //******************************************
+- // Power on the ADC(AddADCUser()from main())
+- //******************************************
+- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+- cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);
+-
+- // Wait until we sample ADC ready state.
+- for (temp2 = 0; temp2 < 32; temp2++) {
+- // Let's wait a mil to let things settle.
+- delayus(card,1000);
+- // Read the current state of the power control reg.
+- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+- // If the ADC ready state bit is set, stop waiting.
+- if (temp1 & 0x1)
+- break;
+- }
+- // Set up 4281 Register contents that
+- // don't change for boot duration.
+-
+- // For playback, we map AC97 slot 3 and 4(Left
+- // & Right PCM playback) to DMA Channel 0.
+- // Set the fifo to be 15 bytes at offset zero.
+-
+- ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback).
+- // FCR0.LS[4:0]=0(=>slot3, left PCM playback).
+- // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
+- writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h)
+- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable.
+-
+- // For capture, we map AC97 slot 10 and 11(Left
+- // and Right PCM Record) to DMA Channel 1.
+- // Set the fifo to be 15 bytes at offset sixteen.
+- ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record).
+- // FCR1.LS[4:0]=10(=>slot10, left PCM record).
+- // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
+- writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h)
+- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable.
+-
+- // Map the Playback SRC to the same AC97 slots(3 & 4--
+- // --Playback left & right)as DMA channel 0.
+- // Map the record SRC to the same AC97 slots(10 & 11--
+- // -- Record left & right) as DMA channel 1.
+-
+- ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).
+- // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
+- // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
+- // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
+- writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch)
+-
+- // Set 'Half Terminal Count Interrupt Enable' and 'Terminal
+- // Count Interrupt Enable' in DMA Control Registers 0 & 1.
+- // Set 'MSK' flag to 1 to keep the DMA engines paused.
+- temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h)
+- writel(temp1, card->pBA0 + BA0_DCR0); // (154h
+- writel(temp1, card->pBA0 + BA0_DCR1); // (15ch)
+-
+- // Set 'Auto-Initialize Control' to 'enabled'; For playback,
+- // set 'Transfer Type Control'(TR[1:0]) to 'read transfer',
+- // for record, set Transfer Type Control to 'write transfer'.
+- // All other bits set to zero; Some will be changed @ transfer start.
+- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h)
+- writel(temp1, card->pBA0 + BA0_DMR0); // (150h)
+- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h)
+- writel(temp1, card->pBA0 + BA0_DMR1); // (158h)
+-
+- // Enable DMA interrupts generally, and
+- // DMA0 & DMA1 interrupts specifically.
+- temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
+- writel(temp1, card->pBA0 + BA0_HIMR);
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n"));
+- return 0;
+-}
+-
+-#ifndef NOT_CS4281_PM
+-static void printpm(struct cs4281_state *s)
+-{
+- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
+- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
+- (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
+- CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
+- s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
+- CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
+- s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
+- CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
+- s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
+- CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
+- s->pm.u32SSCR,s->pm.u32SRCSA));
+- CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
+- s->pm.u32DacASR,s->pm.u32AdcASR));
+- CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
+- s->pm.u32DacSR,s->pm.u32AdcSR));
+- CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
+- s->pm.u32MIDCR_Save));
+-
+-}
+-static void printpipe(struct cs4281_pipeline *pl)
+-{
+-
+- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
+- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x number: 0%x\n",
+- (unsigned)pl->flags,pl->number));
+- CS_DBGOUT(CS_PM, 9, printk("u32DBAnValue: 0%x u32DBCnValue: 0x%x\n",
+- pl->u32DBAnValue,pl->u32DBCnValue));
+- CS_DBGOUT(CS_PM, 9, printk("u32DMRnValue: 0x%x u32DCRnValue: 0x%x\n",
+- pl->u32DMRnValue,pl->u32DCRnValue));
+- CS_DBGOUT(CS_PM, 9, printk("u32DBAnAddress: 0x%x u32DBCnAddress: 0x%x\n",
+- pl->u32DBAnAddress,pl->u32DBCnAddress));
+- CS_DBGOUT(CS_PM, 9, printk("u32DCAnAddress: 0x%x u32DCCnAddress: 0x%x\n",
+- pl->u32DCCnAddress,pl->u32DCCnAddress));
+- CS_DBGOUT(CS_PM, 9, printk("u32DMRnAddress: 0x%x u32DCRnAddress: 0x%x\n",
+- pl->u32DMRnAddress,pl->u32DCRnAddress));
+- CS_DBGOUT(CS_PM, 9, printk("u32HDSRnAddress: 0x%x u32DBAn_Save: 0x%x\n",
+- pl->u32HDSRnAddress,pl->u32DBAn_Save));
+- CS_DBGOUT(CS_PM, 9, printk("u32DBCn_Save: 0x%x u32DMRn_Save: 0x%x\n",
+- pl->u32DBCn_Save,pl->u32DMRn_Save));
+- CS_DBGOUT(CS_PM, 9, printk("u32DCRn_Save: 0x%x u32DCCn_Save: 0x%x\n",
+- pl->u32DCRn_Save,pl->u32DCCn_Save));
+- CS_DBGOUT(CS_PM, 9, printk("u32DCAn_Save: 0x%x\n",
+- pl->u32DCAn_Save));
+- CS_DBGOUT(CS_PM, 9, printk("u32FCRn_Save: 0x%x u32FSICn_Save: 0x%x\n",
+- pl->u32FCRn_Save,pl->u32FSICn_Save));
+- CS_DBGOUT(CS_PM, 9, printk("u32FCRnValue: 0x%x u32FSICnValue: 0x%x\n",
+- pl->u32FCRnValue,pl->u32FSICnValue));
+- CS_DBGOUT(CS_PM, 9, printk("u32FCRnAddress: 0x%x u32FSICnAddress: 0x%x\n",
+- pl->u32FCRnAddress,pl->u32FSICnAddress));
+- CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n",
+- pl->u32FPDRnValue,pl->u32FPDRnAddress));
+-}
+-static void printpipelines(struct cs4281_state *s)
+-{
+- int i;
+- for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
+- {
+- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
+- {
+- printpipe(&s->pl[i]);
+- }
+- }
+-}
+-/****************************************************************************
+-*
+-* Suspend - save the ac97 regs, mute the outputs and power down the part.
+-*
+-****************************************************************************/
+-static void cs4281_ac97_suspend(struct cs4281_state *s)
+-{
+- int Count,i;
+-
+- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n"));
+-/*
+-* change the state, save the current hwptr, then stop the dac/adc
+-*/
+- s->pm.flags &= ~CS4281_PM_IDLE;
+- s->pm.flags |= CS4281_PM_SUSPENDING;
+- s->pm.u32hwptr_playback = readl(s->pBA0 + BA0_DCA0);
+- s->pm.u32hwptr_capture = readl(s->pBA0 + BA0_DCA1);
+- stop_dac(s);
+- stop_adc(s);
+-
+- for(Count = 0x2, i=0; (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
+- && (i < CS4281_AC97_NUMBER_RESTORE_REGS);
+- Count += 2, i++)
+- {
+- cs4281_read_ac97(s, BA0_AC97_RESET + Count, &s->pm.ac97[i]);
+- }
+-/*
+-* Save the ac97 volume registers as well as the current powerdown state.
+-* Now, mute the all the outputs (master, headphone, and mono), as well
+-* as the PCM volume, in preparation for powering down the entire part.
+-*/
+- cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME, &s->pm.u32AC97_master_volume);
+- cs4281_read_ac97(s, BA0_AC97_HEADPHONE_VOLUME, &s->pm.u32AC97_headphone_volume);
+- cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, &s->pm.u32AC97_master_volume_mono);
+- cs4281_read_ac97(s, BA0_AC97_PCM_OUT_VOLUME, &s->pm.u32AC97_pcm_out_volume);
+-
+- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, 0x8000);
+- cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, 0x8000);
+- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
+- cs4281_write_ac97(s, BA0_AC97_PCM_OUT_VOLUME, 0x8000);
+-
+- cs4281_read_ac97(s, BA0_AC97_POWERDOWN, &s->pm.u32AC97_powerdown);
+- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &s->pm.u32AC97_general_purpose);
+-
+-/*
+-* And power down everything on the AC97 codec.
+-*/
+- cs4281_write_ac97(s, BA0_AC97_POWERDOWN, 0xff00);
+- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()-\n"));
+-}
+-
+-/****************************************************************************
+-*
+-* Resume - power up the part and restore its registers..
+-*
+-****************************************************************************/
+-static void cs4281_ac97_resume(struct cs4281_state *s)
+-{
+- int Count,i;
+-
+- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()+\n"));
+-
+-/* do not save the power state registers at this time
+- //
+- // If we saved away the power control registers, write them into the
+- // shadows so those saved values get restored instead of the current
+- // shadowed value.
+- //
+- if( bPowerStateSaved )
+- {
+- PokeShadow( 0x26, ulSaveReg0x26 );
+- bPowerStateSaved = FALSE;
+- }
+-*/
+-
+-//
+-// First, we restore the state of the general purpose register. This
+-// contains the mic select (mic1 or mic2) and if we restore this after
+-// we restore the mic volume/boost state and mic2 was selected at
+-// suspend time, we will end up with a brief period of time where mic1
+-// is selected with the volume/boost settings for mic2, causing
+-// acoustic feedback. So we restore the general purpose register
+-// first, thereby getting the correct mic selected before we restore
+-// the mic volume/boost.
+-//
+- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE, s->pm.u32AC97_general_purpose);
+-
+-//
+-// Now, while the outputs are still muted, restore the state of power
+-// on the AC97 part.
+-//
+- cs4281_write_ac97(s, BA0_AC97_POWERDOWN, s->pm.u32AC97_powerdown);
+-
+-/*
+-* Restore just the first set of registers, from register number
+-* 0x02 to the register number that ulHighestRegToRestore specifies.
+-*/
+- for( Count = 0x2, i=0;
+- (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
+- && (i < CS4281_AC97_NUMBER_RESTORE_REGS);
+- Count += 2, i++)
+- {
+- cs4281_write_ac97(s, BA0_AC97_RESET + Count, s->pm.ac97[i]);
+- }
+- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()-\n"));
+-}
+-
+-/* do not save the power state registers at this time
+-****************************************************************************
+-*
+-* SavePowerState - Save the power registers away.
+-*
+-****************************************************************************
+-void
+-HWAC97codec::SavePowerState(void)
+-{
+- ENTRY(TM_OBJECTCALLS, "HWAC97codec::SavePowerState()\r\n");
+-
+- ulSaveReg0x26 = PeekShadow(0x26);
+-
+- //
+- // Note that we have saved registers that need to be restored during a
+- // resume instead of ulAC97Regs[].
+- //
+- bPowerStateSaved = TRUE;
+-
+-} // SavePowerState
+-*/
+-
+-static void cs4281_SuspendFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
+-{
+- /*
+- * We need to save the contents of the BASIC FIFO Registers.
+- */
+- pl->u32FCRn_Save = readl(s->pBA0 + pl->u32FCRnAddress);
+- pl->u32FSICn_Save = readl(s->pBA0 + pl->u32FSICnAddress);
+-}
+-static void cs4281_ResumeFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
+-{
+- /*
+- * We need to restore the contents of the BASIC FIFO Registers.
+- */
+- writel(pl->u32FCRn_Save,s->pBA0 + pl->u32FCRnAddress);
+- writel(pl->u32FSICn_Save,s->pBA0 + pl->u32FSICnAddress);
+-}
+-static void cs4281_SuspendDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
+-{
+- //
+- // We need to save the contents of the BASIC DMA Registers.
+- //
+- pl->u32DBAn_Save = readl(s->pBA0 + pl->u32DBAnAddress);
+- pl->u32DBCn_Save = readl(s->pBA0 + pl->u32DBCnAddress);
+- pl->u32DMRn_Save = readl(s->pBA0 + pl->u32DMRnAddress);
+- pl->u32DCRn_Save = readl(s->pBA0 + pl->u32DCRnAddress);
+- pl->u32DCCn_Save = readl(s->pBA0 + pl->u32DCCnAddress);
+- pl->u32DCAn_Save = readl(s->pBA0 + pl->u32DCAnAddress);
+-}
+-static void cs4281_ResumeDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
+-{
+- //
+- // We need to save the contents of the BASIC DMA Registers.
+- //
+- writel( pl->u32DBAn_Save, s->pBA0 + pl->u32DBAnAddress);
+- writel( pl->u32DBCn_Save, s->pBA0 + pl->u32DBCnAddress);
+- writel( pl->u32DMRn_Save, s->pBA0 + pl->u32DMRnAddress);
+- writel( pl->u32DCRn_Save, s->pBA0 + pl->u32DCRnAddress);
+- writel( pl->u32DCCn_Save, s->pBA0 + pl->u32DCCnAddress);
+- writel( pl->u32DCAn_Save, s->pBA0 + pl->u32DCAnAddress);
+-}
+-
+-static int cs4281_suspend(struct cs4281_state *s)
+-{
+- int i;
+- u32 u32CLKCR1;
+- struct cs4281_pm *pm = &s->pm;
+- CS_DBGOUT(CS_PM | CS_FUNCTION, 9,
+- printk("cs4281: cs4281_suspend()+ flags=%d\n",
+- (unsigned)s->pm.flags));
+-/*
+-* check the current state, only suspend if IDLE
+-*/
+- if(!(s->pm.flags & CS4281_PM_IDLE))
+- {
+- CS_DBGOUT(CS_PM | CS_ERROR, 2,
+- printk("cs4281: cs4281_suspend() unable to suspend, not IDLE\n"));
+- return 1;
+- }
+- s->pm.flags &= ~CS4281_PM_IDLE;
+- s->pm.flags |= CS4281_PM_SUSPENDING;
+-
+-//
+-// Gershwin CLKRUN - Set CKRA
+-//
+- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
+-
+- pm->u32CLKCR1_SAVE = u32CLKCR1;
+- if(!(u32CLKCR1 & 0x00010000 ) )
+- writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
+-
+-//
+-// First, turn on the clocks (yikes) to the devices, so that they will
+-// respond when we try to save their state.
+-//
+- if(!(u32CLKCR1 & CLKCR1_SWCE))
+- {
+- writel(u32CLKCR1 | CLKCR1_SWCE , s->pBA0 + BA0_CLKCR1);
+- }
+-
+- //
+- // Save the power state
+- //
+- pm->u32SSPMValue = readl(s->pBA0 + BA0_SSPM);
+-
+- //
+- // Disable interrupts.
+- //
+- writel(HICR_CHGM, s->pBA0 + BA0_HICR);
+-
+- //
+- // Save the PCM Playback Left and Right Volume Control.
+- //
+- pm->u32PPLVCvalue = readl(s->pBA0 + BA0_PPLVC);
+- pm->u32PPRVCvalue = readl(s->pBA0 + BA0_PPRVC);
+-
+- //
+- // Save the FM Synthesis Left and Right Volume Control.
+- //
+- pm->u32FMLVCvalue = readl(s->pBA0 + BA0_FMLVC);
+- pm->u32FMRVCvalue = readl(s->pBA0 + BA0_FMRVC);
+-
+- //
+- // Save the GPIOR value.
+- //
+- pm->u32GPIORvalue = readl(s->pBA0 + BA0_GPIOR);
+-
+- //
+- // Save the JSCTL value.
+- //
+- pm->u32JSCTLvalue = readl(s->pBA0 + BA0_GPIOR);
+-
+- //
+- // Save Sound System Control Register
+- //
+- pm->u32SSCR = readl(s->pBA0 + BA0_SSCR);
+-
+- //
+- // Save SRC Slot Assinment register
+- //
+- pm->u32SRCSA = readl(s->pBA0 + BA0_SRCSA);
+-
+- //
+- // Save sample rate
+- //
+- pm->u32DacASR = readl(s->pBA0 + BA0_PASR);
+- pm->u32AdcASR = readl(s->pBA0 + BA0_CASR);
+- pm->u32DacSR = readl(s->pBA0 + BA0_DACSR);
+- pm->u32AdcSR = readl(s->pBA0 + BA0_ADCSR);
+-
+- //
+- // Loop through all of the PipeLines
+- //
+- for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
+- {
+- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
+- {
+- //
+- // Ask the DMAengines and FIFOs to Suspend.
+- //
+- cs4281_SuspendDMAengine(s,&s->pl[i]);
+- cs4281_SuspendFIFO(s,&s->pl[i]);
+- }
+- }
+- //
+- // We need to save the contents of the Midi Control Register.
+- //
+- pm->u32MIDCR_Save = readl(s->pBA0 + BA0_MIDCR);
+-/*
+-* save off the AC97 part information
+-*/
+- cs4281_ac97_suspend(s);
+-
+- //
+- // Turn off the serial ports.
+- //
+- writel(0, s->pBA0 + BA0_SERMC);
+-
+- //
+- // Power off FM, Joystick, AC link,
+- //
+- writel(0, s->pBA0 + BA0_SSPM);
+-
+- //
+- // DLL off.
+- //
+- writel(0, s->pBA0 + BA0_CLKCR1);
+-
+- //
+- // AC link off.
+- //
+- writel(0, s->pBA0 + BA0_SPMC);
+-
+- //
+- // Put the chip into D3(hot) state.
+- //
+- // PokeBA0(BA0_PMCS, 0x00000003);
+-
+- //
+- // Gershwin CLKRUN - Clear CKRA
+- //
+- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
+- writel(u32CLKCR1 & 0xFFFEFFFF, s->pBA0 + BA0_CLKCR1);
+-
+-#ifdef CSDEBUG
+- printpm(s);
+- printpipelines(s);
+-#endif
+-
+- s->pm.flags &= ~CS4281_PM_SUSPENDING;
+- s->pm.flags |= CS4281_PM_SUSPENDED;
+-
+- CS_DBGOUT(CS_PM | CS_FUNCTION, 9,
+- printk("cs4281: cs4281_suspend()- flags=%d\n",
+- (unsigned)s->pm.flags));
+- return 0;
+-}
+-
+-static int cs4281_resume(struct cs4281_state *s)
+-{
+- int i;
+- unsigned temp1;
+- u32 u32CLKCR1;
+- struct cs4281_pm *pm = &s->pm;
+- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
+- printk( "cs4281: cs4281_resume()+ flags=%d\n",
+- (unsigned)s->pm.flags));
+- if(!(s->pm.flags & CS4281_PM_SUSPENDED))
+- {
+- CS_DBGOUT(CS_PM | CS_ERROR, 2,
+- printk("cs4281: cs4281_resume() unable to resume, not SUSPENDED\n"));
+- return 1;
+- }
+- s->pm.flags &= ~CS4281_PM_SUSPENDED;
+- s->pm.flags |= CS4281_PM_RESUMING;
+-
+-//
+-// Gershwin CLKRUN - Set CKRA
+-//
+- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
+- writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
+-
+- //
+- // set the power state.
+- //
+- //old PokeBA0(BA0_PMCS, 0);
+-
+- //
+- // Program the clock circuit and serial ports.
+- //
+- temp1 = cs4281_hw_init(s);
+- if (temp1) {
+- CS_DBGOUT(CS_ERROR | CS_INIT, 1,
+- printk(KERN_ERR
+- "cs4281: resume cs4281_hw_init() error.\n"));
+- return -1;
+- }
+-
+- //
+- // restore the Power state
+- //
+- writel(pm->u32SSPMValue, s->pBA0 + BA0_SSPM);
+-
+- //
+- // Set post SRC mix setting (FM or ALT48K)
+- //
+- writel(pm->u32SSPM_BITS, s->pBA0 + BA0_SSPM);
+-
+- //
+- // Loop through all of the PipeLines
+- //
+- for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
+- {
+- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
+- {
+- //
+- // Ask the DMAengines and FIFOs to Resume.
+- //
+- cs4281_ResumeDMAengine(s,&s->pl[i]);
+- cs4281_ResumeFIFO(s,&s->pl[i]);
+- }
+- }
+- //
+- // We need to restore the contents of the Midi Control Register.
+- //
+- writel(pm->u32MIDCR_Save, s->pBA0 + BA0_MIDCR);
+-
+- cs4281_ac97_resume(s);
+- //
+- // Restore the PCM Playback Left and Right Volume Control.
+- //
+- writel(pm->u32PPLVCvalue, s->pBA0 + BA0_PPLVC);
+- writel(pm->u32PPRVCvalue, s->pBA0 + BA0_PPRVC);
+-
+- //
+- // Restore the FM Synthesis Left and Right Volume Control.
+- //
+- writel(pm->u32FMLVCvalue, s->pBA0 + BA0_FMLVC);
+- writel(pm->u32FMRVCvalue, s->pBA0 + BA0_FMRVC);
+-
+- //
+- // Restore the JSCTL value.
+- //
+- writel(pm->u32JSCTLvalue, s->pBA0 + BA0_JSCTL);
+-
+- //
+- // Restore the GPIOR register value.
+- //
+- writel(pm->u32GPIORvalue, s->pBA0 + BA0_GPIOR);
+-
+- //
+- // Restore Sound System Control Register
+- //
+- writel(pm->u32SSCR, s->pBA0 + BA0_SSCR);
+-
+- //
+- // Restore SRC Slot Assignment register
+- //
+- writel(pm->u32SRCSA, s->pBA0 + BA0_SRCSA);
+-
+- //
+- // Restore sample rate
+- //
+- writel(pm->u32DacASR, s->pBA0 + BA0_PASR);
+- writel(pm->u32AdcASR, s->pBA0 + BA0_CASR);
+- writel(pm->u32DacSR, s->pBA0 + BA0_DACSR);
+- writel(pm->u32AdcSR, s->pBA0 + BA0_ADCSR);
+-
+- //
+- // Restore CFL1/2 registers we saved to compensate for OEM bugs.
+- //
+- // PokeBA0(BA0_CFLR, ulConfig);
+-
+- //
+- // Gershwin CLKRUN - Clear CKRA
+- //
+- writel(pm->u32CLKCR1_SAVE, s->pBA0 + BA0_CLKCR1);
+-
+- //
+- // Enable interrupts on the part.
+- //
+- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
+-
+-#ifdef CSDEBUG
+- printpm(s);
+- printpipelines(s);
+-#endif
+-/*
+-* change the state, restore the current hwptrs, then stop the dac/adc
+-*/
+- s->pm.flags |= CS4281_PM_IDLE;
+- s->pm.flags &= ~(CS4281_PM_SUSPENDING | CS4281_PM_SUSPENDED
+- | CS4281_PM_RESUMING | CS4281_PM_RESUMED);
+-
+- writel(s->pm.u32hwptr_playback, s->pBA0 + BA0_DCA0);
+- writel(s->pm.u32hwptr_capture, s->pBA0 + BA0_DCA1);
+- start_dac(s);
+- start_adc(s);
+-
+- CS_DBGOUT(CS_PM | CS_FUNCTION, 9, printk("cs4281: cs4281_resume()- flags=%d\n",
+- (unsigned)s->pm.flags));
+- return 0;
+-}
+-
+-#endif
+-
+-//******************************************************************************
+-// "cs4281_play_rate()" --
+-//******************************************************************************
+-static void cs4281_play_rate(struct cs4281_state *card, u32 playrate)
+-{
+- u32 DACSRvalue = 1;
+-
+- // Based on the sample rate, program the DACSR register.
+- if (playrate == 8000)
+- DACSRvalue = 5;
+- if (playrate == 11025)
+- DACSRvalue = 4;
+- else if (playrate == 22050)
+- DACSRvalue = 2;
+- else if (playrate == 44100)
+- DACSRvalue = 1;
+- else if ((playrate <= 48000) && (playrate >= 6023))
+- DACSRvalue = 24576000 / (playrate * 16);
+- else if (playrate < 6023)
+- // Not allowed by open.
+- return;
+- else if (playrate > 48000)
+- // Not allowed by open.
+- return;
+- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
+- "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
+- DACSRvalue, playrate));
+- // Write the 'sample rate select code'
+- // to the 'DAC Sample Rate' register.
+- writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)
+-}
+-
+-//******************************************************************************
+-// "cs4281_record_rate()" -- Initialize the record sample rate converter.
+-//******************************************************************************
+-static void cs4281_record_rate(struct cs4281_state *card, u32 outrate)
+-{
+- u32 ADCSRvalue = 1;
+-
+- //
+- // Based on the sample rate, program the ADCSR register
+- //
+- if (outrate == 8000)
+- ADCSRvalue = 5;
+- if (outrate == 11025)
+- ADCSRvalue = 4;
+- else if (outrate == 22050)
+- ADCSRvalue = 2;
+- else if (outrate == 44100)
+- ADCSRvalue = 1;
+- else if ((outrate <= 48000) && (outrate >= 6023))
+- ADCSRvalue = 24576000 / (outrate * 16);
+- else if (outrate < 6023) {
+- // Not allowed by open.
+- return;
+- } else if (outrate > 48000) {
+- // Not allowed by open.
+- return;
+- }
+- CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
+- "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
+- ADCSRvalue, outrate));
+- // Write the 'sample rate select code
+- // to the 'ADC Sample Rate' register.
+- writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)
+-}
+-
+-
+-
+-static void stop_dac(struct cs4281_state *s)
+-{
+- unsigned long flags;
+- unsigned temp1;
+-
+- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n"));
+- spin_lock_irqsave(&s->lock, flags);
+- s->ena &= ~FMODE_WRITE;
+- temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK;
+- writel(temp1, s->pBA0 + BA0_DCR0);
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-
+-static void start_dac(struct cs4281_state *s)
+-{
+- unsigned long flags;
+- unsigned temp1;
+-
+- CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()+\n"));
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||
+- (s->dma_dac.count > 0
+- && s->dma_dac.ready))
+-#ifndef NOT_CS4281_PM
+- && (s->pm.flags & CS4281_PM_IDLE))
+-#else
+-)
+-#endif
+- {
+- s->ena |= FMODE_WRITE;
+- temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask.
+- writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing.
+- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
+-
+- writel(7, s->pBA0 + BA0_PPRVC);
+- writel(7, s->pBA0 + BA0_PPLVC);
+- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO
+- "cs4281: start_dac(): writel 0x%x start dma\n", temp1));
+-
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- CS_DBGOUT(CS_FUNCTION, 3,
+- printk(KERN_INFO "cs4281: start_dac()-\n"));
+-}
+-
+-
+-static void stop_adc(struct cs4281_state *s)
+-{
+- unsigned long flags;
+- unsigned temp1;
+-
+- CS_DBGOUT(CS_FUNCTION, 3,
+- printk(KERN_INFO "cs4281: stop_adc()+\n"));
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->ena &= ~FMODE_READ;
+-
+- if (s->conversion == 1) {
+- s->conversion = 0;
+- s->prop_adc.fmt = s->prop_adc.fmt_original;
+- }
+- temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK;
+- writel(temp1, s->pBA0 + BA0_DCR1);
+- spin_unlock_irqrestore(&s->lock, flags);
+- CS_DBGOUT(CS_FUNCTION, 3,
+- printk(KERN_INFO "cs4281: stop_adc()-\n"));
+-}
+-
+-
+-static void start_adc(struct cs4281_state *s)
+-{
+- unsigned long flags;
+- unsigned temp1;
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: start_adc()+\n"));
+-
+- if (!(s->ena & FMODE_READ) &&
+- (s->dma_adc.mapped || s->dma_adc.count <=
+- (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize))
+- && s->dma_adc.ready
+-#ifndef NOT_CS4281_PM
+- && (s->pm.flags & CS4281_PM_IDLE))
+-#else
+-)
+-#endif
+- {
+- if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) {
+- //
+- // now only use 16 bit capture, due to truncation issue
+- // in the chip, noticable distortion occurs.
+- // allocate buffer and then convert from 16 bit to
+- // 8 bit for the user buffer.
+- //
+- s->prop_adc.fmt_original = s->prop_adc.fmt;
+- if (s->prop_adc.fmt & AFMT_S8) {
+- s->prop_adc.fmt &= ~AFMT_S8;
+- s->prop_adc.fmt |= AFMT_S16_LE;
+- }
+- if (s->prop_adc.fmt & AFMT_U8) {
+- s->prop_adc.fmt &= ~AFMT_U8;
+- s->prop_adc.fmt |= AFMT_U16_LE;
+- }
+- //
+- // prog_dmabuf_adc performs a stop_adc() but that is
+- // ok since we really haven't started the DMA yet.
+- //
+- prog_codec(s, CS_TYPE_ADC);
+-
+- if (prog_dmabuf_adc(s) != 0) {
+- CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
+- "cs4281: start_adc(): error in prog_dmabuf_adc\n"));
+- }
+- s->conversion = 1;
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- s->ena |= FMODE_READ;
+- temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK; // Clear DMA1 channel mask bit.
+- writel(temp1, s->pBA0 + BA0_DCR1); // Start recording
+- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO
+- "cs4281: start_adc(): writel 0x%x \n", temp1));
+- }
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: start_adc()-\n"));
+-
+-}
+-
+-
+-// ---------------------------------------------------------------------
+-
+-#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.
+-
+-
+-static void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
+-{
+- struct page *map, *mapend;
+-
+- if (db->rawbuf) {
+- // Undo prog_dmabuf()'s marking the pages as reserved
+- mapend =
+- virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -
+- 1);
+- for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
+- ClearPageReserved(map);
+- free_dmabuf(s, db);
+- }
+- if (s->tmpbuff && (db->type == CS_TYPE_ADC)) {
+- // Undo prog_dmabuf()'s marking the pages as reserved
+- mapend =
+- virt_to_page(s->tmpbuff +
+- (PAGE_SIZE << s->buforder_tmpbuff) - 1);
+- for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
+- ClearPageReserved(map);
+- free_dmabuf2(s, db);
+- }
+- s->tmpbuff = NULL;
+- db->rawbuf = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
+-{
+- int order;
+- unsigned bytespersec, temp1;
+- unsigned bufs, sample_shift = 0;
+- struct page *map, *mapend;
+- unsigned long df;
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: prog_dmabuf()+\n"));
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error =
+- db->endcleared = db->blocks = db->wakeup = db->underrun = 0;
+-/*
+-* check for order within limits, but do not overwrite value, check
+-* later for a fractional defaultorder (i.e. 100+).
+-*/
+- if((defaultorder > 0) && (defaultorder < 12))
+- df = defaultorder;
+- else
+- df = 1;
+-
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = df; order >= DMABUF_MINORDER; order--)
+- if ( (db->rawbuf = (void *) pci_alloc_consistent(
+- s->pcidev, PAGE_SIZE << order, &db-> dmaaddr)))
+- break;
+- if (!db->rawbuf) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: prog_dmabuf(): unable to allocate rawbuf\n"));
+- return -ENOMEM;
+- }
+- db->buforder = order;
+- // Now mark the pages as reserved; otherwise the
+- // remap_pfn_range() in cs4281_mmap doesn't work.
+- // 1. get index to last page in mem_map array for rawbuf.
+- mapend = virt_to_page(db->rawbuf +
+- (PAGE_SIZE << db->buforder) - 1);
+-
+- // 2. mark each physical page in range as 'reserved'.
+- for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
+- SetPageReserved(map);
+- }
+- if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {
+- for (order = df; order >= DMABUF_MINORDER;
+- order--)
+- if ( (s->tmpbuff = (void *) pci_alloc_consistent(
+- s->pcidev, PAGE_SIZE << order,
+- &s->dmaaddr_tmpbuff)))
+- break;
+- if (!s->tmpbuff) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n"));
+- return -ENOMEM;
+- }
+- s->buforder_tmpbuff = order;
+- // Now mark the pages as reserved; otherwise the
+- // remap_pfn_range() in cs4281_mmap doesn't work.
+- // 1. get index to last page in mem_map array for rawbuf.
+- mapend = virt_to_page(s->tmpbuff +
+- (PAGE_SIZE << s->buforder_tmpbuff) - 1);
+-
+- // 2. mark each physical page in range as 'reserved'.
+- for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
+- SetPageReserved(map);
+- }
+- if (db->type == CS_TYPE_DAC) {
+- if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- sample_shift++;
+- if (s->prop_dac.channels > 1)
+- sample_shift++;
+- bytespersec = s->prop_dac.rate << sample_shift;
+- } else // CS_TYPE_ADC
+- {
+- if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- sample_shift++;
+- if (s->prop_adc.channels > 1)
+- sample_shift++;
+- bytespersec = s->prop_adc.rate << sample_shift;
+- }
+- bufs = PAGE_SIZE << db->buforder;
+-
+-/*
+-* added fractional "defaultorder" inputs. if >100 then use
+-* defaultorder-100 as power of 2 for the buffer size. example:
+-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
+-*/
+- if(defaultorder >= 100)
+- {
+- bufs = 1 << (defaultorder-100);
+- }
+-
+-#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds.
+- db->numfrag = 2;
+-/*
+-* Nominal frag size(bytes/interrupt)
+-*/
+- temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS);
+- db->fragshift = 8; // Min 256 bytes.
+- while (1 << db->fragshift < temp1) // Calc power of 2 frag size.
+- db->fragshift += 1;
+- db->fragsize = 1 << db->fragshift;
+- db->dmasize = db->fragsize * 2;
+- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
+-
+-// If the calculated size is larger than the allocated
+-// buffer, divide the allocated buffer into 2 fragments.
+- if (db->dmasize > bufs) {
+-
+- db->numfrag = 2; // Two fragments.
+- db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer.
+- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
+- db->dmasize = bufs; // Use all the alloc'ed buffer.
+-
+- db->fragshift = 0; // Calculate 'fragshift'.
+- temp1 = db->fragsize; // update_ptr() uses it
+- while ((temp1 >>= 1) > 1) // to calc 'total-bytes'
+- db->fragshift += 1; // returned in DSP_GETI/OPTR.
+- }
+- CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO
+- "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n",
+- db->numfrag, db->fragsize, db->fragsamples,
+- db->fragshift, bufs,
+- (db->type == CS_TYPE_DAC) ? s->prop_dac.fmt :
+- s->prop_adc.fmt,
+- (db->type == CS_TYPE_DAC) ? s->prop_dac.channels :
+- s->prop_adc.channels));
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));
+- return 0;
+-}
+-
+-
+-static int prog_dmabuf_adc(struct cs4281_state *s)
+-{
+- unsigned long va;
+- unsigned count;
+- int c;
+- stop_adc(s);
+- s->dma_adc.type = CS_TYPE_ADC;
+- if ((c = prog_dmabuf(s, &s->dma_adc)))
+- return c;
+-
+- if (s->dma_adc.rawbuf) {
+- memset(s->dma_adc.rawbuf,
+- (s->prop_adc.
+- fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+- s->dma_adc.dmasize);
+- }
+- if (s->tmpbuff) {
+- memset(s->tmpbuff,
+- (s->prop_adc.
+- fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+- PAGE_SIZE << s->buforder_tmpbuff);
+- }
+-
+- va = virt_to_bus(s->dma_adc.rawbuf);
+-
+- count = s->dma_adc.dmasize;
+-
+- if (s->prop_adc.
+- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
+- count /= 2; // 16-bit.
+-
+- if (s->prop_adc.channels > 1)
+- count /= 2; // Assume stereo.
+-
+- CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
+- "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n",
+- count, (unsigned) va));
+-
+- writel(va, s->pBA0 + BA0_DBA1); // Set buffer start address.
+- writel(count - 1, s->pBA0 + BA0_DBC1); // Set count.
+- s->dma_adc.ready = 1;
+- return 0;
+-}
+-
+-
+-static int prog_dmabuf_dac(struct cs4281_state *s)
+-{
+- unsigned long va;
+- unsigned count;
+- int c;
+- stop_dac(s);
+- s->dma_dac.type = CS_TYPE_DAC;
+- if ((c = prog_dmabuf(s, &s->dma_dac)))
+- return c;
+- memset(s->dma_dac.rawbuf,
+- (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+- s->dma_dac.dmasize);
+-
+- va = virt_to_bus(s->dma_dac.rawbuf);
+-
+- count = s->dma_dac.dmasize;
+- if (s->prop_dac.
+- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
+- count /= 2; // 16-bit.
+-
+- if (s->prop_dac.channels > 1)
+- count /= 2; // Assume stereo.
+-
+- writel(va, s->pBA0 + BA0_DBA0); // Set buffer start address.
+- writel(count - 1, s->pBA0 + BA0_DBC0); // Set count.
+-
+- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
+- "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",
+- count, (unsigned) va));
+-
+- s->dma_dac.ready = 1;
+- return 0;
+-}
+-
+-
+-static void clear_advance(void *buf, unsigned bsize, unsigned bptr,
+- unsigned len, unsigned char c)
+-{
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(((char *) buf) + bptr, c, x);
+- bptr = 0;
+- len -= x;
+- }
+- CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
+- "cs4281: clear_advance(): memset %d at %p for %d size \n",
+- (unsigned)c, ((char *) buf) + bptr, len));
+- memset(((char *) buf) + bptr, c, len);
+-}
+-
+-
+-
+-// call with spinlock held!
+-static void cs4281_update_ptr(struct cs4281_state *s, int intflag)
+-{
+- int diff;
+- unsigned hwptr, va;
+-
+- // update ADC pointer
+- if (s->ena & FMODE_READ) {
+- hwptr = readl(s->pBA0 + BA0_DCA1); // Read capture DMA address.
+- va = virt_to_bus(s->dma_adc.rawbuf);
+- hwptr -= (unsigned) va;
+- diff =
+- (s->dma_adc.dmasize + hwptr -
+- s->dma_adc.hwptr) % s->dma_adc.dmasize;
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+- if (s->dma_adc.count > s->dma_adc.dmasize)
+- s->dma_adc.count = s->dma_adc.dmasize;
+- if (s->dma_adc.mapped) {
+- if (s->dma_adc.count >=
+- (signed) s->dma_adc.fragsize) wake_up(&s->
+- dma_adc.
+- wait);
+- } else {
+- if (s->dma_adc.count > 0)
+- wake_up(&s->dma_adc.wait);
+- }
+- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
+- "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
+- s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count));
+- }
+- // update DAC pointer
+- //
+- // check for end of buffer, means that we are going to wait for another interrupt
+- // to allow silence to fill the fifos on the part, to keep pops down to a minimum.
+- //
+- if (s->ena & FMODE_WRITE) {
+- hwptr = readl(s->pBA0 + BA0_DCA0); // Read play DMA address.
+- va = virt_to_bus(s->dma_dac.rawbuf);
+- hwptr -= (unsigned) va;
+- diff = (s->dma_dac.dmasize + hwptr -
+- s->dma_dac.hwptr) % s->dma_dac.dmasize;
+- s->dma_dac.hwptr = hwptr;
+- s->dma_dac.total_bytes += diff;
+- if (s->dma_dac.mapped) {
+- s->dma_dac.count += diff;
+- if (s->dma_dac.count >= s->dma_dac.fragsize) {
+- s->dma_dac.wakeup = 1;
+- wake_up(&s->dma_dac.wait);
+- if (s->dma_dac.count > s->dma_dac.dmasize)
+- s->dma_dac.count &=
+- s->dma_dac.dmasize - 1;
+- }
+- } else {
+- s->dma_dac.count -= diff;
+- if (s->dma_dac.count <= 0) {
+- //
+- // fill with silence, and do not shut down the DAC.
+- // Continue to play silence until the _release.
+- //
+- CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
+- "cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n",
+- (unsigned)(s->prop_dac.fmt &
+- (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+- s->dma_dac.rawbuf, s->dma_dac.dmasize));
+- memset(s->dma_dac.rawbuf,
+- (s->prop_dac.
+- fmt & (AFMT_U8 | AFMT_U16_LE)) ?
+- 0x80 : 0, s->dma_dac.dmasize);
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.underrun = 1;
+- s->dma_dac.count = 0;
+- CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO
+- "cs4281: cs4281_update_ptr(): underrun\n"));
+- }
+- } else if (s->dma_dac.count <=
+- (signed) s->dma_dac.fragsize
+- && !s->dma_dac.endcleared) {
+- clear_advance(s->dma_dac.rawbuf,
+- s->dma_dac.dmasize,
+- s->dma_dac.swptr,
+- s->dma_dac.fragsize,
+- (s->prop_dac.
+- fmt & (AFMT_U8 |
+- AFMT_U16_LE)) ? 0x80
+- : 0);
+- s->dma_dac.endcleared = 1;
+- }
+- if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) ||
+- intflag)
+- {
+- wake_up(&s->dma_dac.wait);
+- }
+- }
+- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
+- "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
+- s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count));
+- }
+-}
+-
+-
+-// ---------------------------------------------------------------------
+-
+-static void prog_codec(struct cs4281_state *s, unsigned type)
+-{
+- unsigned long flags;
+- unsigned temp1, format;
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: prog_codec()+ \n"));
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (type == CS_TYPE_ADC) {
+- temp1 = readl(s->pBA0 + BA0_DCR1);
+- writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1); // Stop capture DMA, if active.
+-
+- // program sampling rates
+- // Note, for CS4281, capture & play rates can be set independently.
+- cs4281_record_rate(s, s->prop_adc.rate);
+-
+- // program ADC parameters
+- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
+- if (s->prop_adc.
+- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
+- if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian?
+- format |= DMRn_BEND;
+- if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))
+- format |= DMRn_USIGN; // Unsigned.
+- } else
+- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
+- if (s->prop_adc.channels < 2)
+- format |= DMRn_MONO;
+-
+- writel(format, s->pBA0 + BA0_DMR1);
+-
+- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
+- "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",
+- (format & DMRn_SIZE8) ? "8" : "16",
+- (format & DMRn_USIGN) ? "Unsigned" : "Signed",
+- (format & DMRn_MONO) ? "Mono" : "Stereo",
+- s->prop_adc.rate, format));
+-
+- s->ena &= ~FMODE_READ; // not capturing data yet
+- }
+-
+-
+- if (type == CS_TYPE_DAC) {
+- temp1 = readl(s->pBA0 + BA0_DCR0);
+- writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0); // Stop play DMA, if active.
+-
+- // program sampling rates
+- // Note, for CS4281, capture & play rates can be set independently.
+- cs4281_play_rate(s, s->prop_dac.rate);
+-
+- // program DAC parameters
+- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
+- if (s->prop_dac.
+- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
+- if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE))
+- format |= DMRn_BEND; // Big Endian.
+- if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE))
+- format |= DMRn_USIGN; // Unsigned.
+- } else
+- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
+-
+- if (s->prop_dac.channels < 2)
+- format |= DMRn_MONO;
+-
+- writel(format, s->pBA0 + BA0_DMR0);
+-
+-
+- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
+- "cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n",
+- (format & DMRn_SIZE8) ? "8" : "16",
+- (format & DMRn_USIGN) ? "Unsigned" : "Signed",
+- (format & DMRn_MONO) ? "Mono" : "Stereo",
+- s->prop_dac.rate, format));
+-
+- s->ena &= ~FMODE_WRITE; // not capturing data yet
+-
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: prog_codec()- \n"));
+-}
+-
+-
+-static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
+- unsigned long arg)
+-{
+- // Index to mixer_src[] is value of AC97 Input Mux Select Reg.
+- // Value of array member is recording source Device ID Mask.
+- static const unsigned int mixer_src[8] = {
+- SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,
+- SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0
+- };
+- void __user *argp = (void __user *)arg;
+-
+- // Index of mixtable1[] member is Device ID
+- // and must be <= SOUND_MIXER_NRDEVICES.
+- // Value of array member is index into s->mix.vol[]
+- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_PCM] = 1, // voice
+- [SOUND_MIXER_LINE1] = 2, // AUX
+- [SOUND_MIXER_CD] = 3, // CD
+- [SOUND_MIXER_LINE] = 4, // Line
+- [SOUND_MIXER_SYNTH] = 5, // FM
+- [SOUND_MIXER_MIC] = 6, // Mic
+- [SOUND_MIXER_SPEAKER] = 7, // Speaker
+- [SOUND_MIXER_RECLEV] = 8, // Recording level
+- [SOUND_MIXER_VOLUME] = 9 // Master Volume
+- };
+-
+-
+- static const unsigned mixreg[] = {
+- BA0_AC97_PCM_OUT_VOLUME,
+- BA0_AC97_AUX_VOLUME,
+- BA0_AC97_CD_VOLUME,
+- BA0_AC97_LINE_IN_VOLUME
+- };
+- unsigned char l, r, rl, rr, vidx;
+- unsigned char attentbl[11] =
+- { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 };
+- unsigned temp1;
+- int i, val;
+-
+- VALIDATE_STATE(s);
+- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
+- "cs4281: mixer_ioctl(): s=%p cmd=0x%.8x\n", s, cmd));
+-#if CSDEBUG
+- cs_printioctl(cmd);
+-#endif
+-#if CSDEBUG_INTERFACE
+-
+- if ((cmd == SOUND_MIXER_CS_GETDBGMASK) ||
+- (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
+- (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
+- (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
+- (cmd == SOUND_MIXER_CS_APM))
+- {
+- switch (cmd) {
+-
+- case SOUND_MIXER_CS_GETDBGMASK:
+- return put_user(cs_debugmask,
+- (unsigned long __user *) argp);
+-
+- case SOUND_MIXER_CS_GETDBGLEVEL:
+- return put_user(cs_debuglevel,
+- (unsigned long __user *) argp);
+-
+- case SOUND_MIXER_CS_SETDBGMASK:
+- if (get_user(val, (unsigned long __user *) argp))
+- return -EFAULT;
+- cs_debugmask = val;
+- return 0;
+-
+- case SOUND_MIXER_CS_SETDBGLEVEL:
+- if (get_user(val, (unsigned long __user *) argp))
+- return -EFAULT;
+- cs_debuglevel = val;
+- return 0;
+-#ifndef NOT_CS4281_PM
+- case SOUND_MIXER_CS_APM:
+- if (get_user(val, (unsigned long __user *) argp))
+- return -EFAULT;
+- if(val == CS_IOCTL_CMD_SUSPEND)
+- cs4281_suspend(s);
+- else if(val == CS_IOCTL_CMD_RESUME)
+- cs4281_resume(s);
+- else
+- {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+- "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n",
+- val));
+- }
+- return 0;
+-#endif
+- default:
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+- "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n"));
+- return 0;
+- }
+- }
+-#endif
+-
+- if (cmd == SOUND_MIXER_PRIVATE1) {
+- // enable/disable/query mixer preamp
+- if (get_user(val, (int __user *) argp))
+- return -EFAULT;
+- if (val != -1) {
+- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
+- temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf);
+- cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
+- }
+- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
+- val = (temp1 & 0x40) ? 1 : 0;
+- return put_user(val, (int __user *) argp);
+- }
+- if (cmd == SOUND_MIXER_PRIVATE2) {
+- // enable/disable/query spatializer
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- if (val != -1) {
+- temp1 = (val & 0x3f) >> 2;
+- cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);
+- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE,
+- &temp1);
+- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,
+- temp1 | 0x2000);
+- }
+- cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);
+- return put_user((temp1 << 2) | 3, (int __user *)argp);
+- }
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- strlcpy(info.id, "CS4281", sizeof(info.id));
+- strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
+- info.modify_counter = s->mix.modcnt;
+- if (copy_to_user(argp, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == SOUND_OLD_MIXER_INFO) {
+- _old_mixer_info info;
+- strlcpy(info.id, "CS4281", sizeof(info.id));
+- strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
+- if (copy_to_user(argp, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, (int __user *) argp);
+-
+- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+- return -EINVAL;
+-
+- // If ioctl has only the SIOC_READ bit(bit 31)
+- // on, process the only-read commands.
+- if (_SIOC_DIR(cmd) == _SIOC_READ) {
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
+- cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1);
+- return put_user(mixer_src[temp1&7], (int __user *)argp);
+-
+- case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device
+- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
+- SOUND_MASK_CD | SOUND_MASK_LINE |
+- SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+- SOUND_MASK_VOLUME |
+- SOUND_MASK_RECLEV |
+- SOUND_MASK_SPEAKER, (int __user *)argp);
+-
+- case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source
+- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC |
+- SOUND_MASK_CD | SOUND_MASK_VOLUME |
+- SOUND_MASK_LINE1, (int __user *) argp);
+-
+- case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo
+- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
+- SOUND_MASK_CD | SOUND_MASK_LINE |
+- SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+- SOUND_MASK_VOLUME |
+- SOUND_MASK_RECLEV, (int __user *)argp);
+-
+- case SOUND_MIXER_CAPS:
+- return put_user(SOUND_CAP_EXCL_INPUT, (int __user *)argp);
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES
+- || !(vidx = mixtable1[i]))
+- return -EINVAL;
+- return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
+- }
+- }
+- // If ioctl doesn't have both the SIOC_READ and
+- // the SIOC_WRITE bit set, return invalid.
+- if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE))
+- return -EINVAL;
+-
+- // Increment the count of volume writes.
+- s->mix.modcnt++;
+-
+- // Isolate the command; it must be a write.
+- switch (_IOC_NR(cmd)) {
+-
+- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- i = hweight32(val); // i = # bits on in val.
+- if (i != 1) // One & only 1 bit must be on.
+- return 0;
+- for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) {
+- if (val == mixer_src[i]) {
+- temp1 = (i << 8) | i;
+- cs4281_write_ac97(s,
+- BA0_AC97_RECORD_SELECT,
+- temp1);
+- return 0;
+- }
+- }
+- return 0;
+-
+- case SOUND_MIXER_VOLUME:
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100; // Max soundcard.h vol is 100.
+- if (l < 6) {
+- rl = 63;
+- l = 0;
+- } else
+- rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten.
+-
+- r = (val >> 8) & 0xff;
+- if (r > 100)
+- r = 100; // Max right volume is 100, too
+- if (r < 6) {
+- rr = 63;
+- r = 0;
+- } else
+- rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation.
+-
+- if ((rl > 60) && (rr > 60)) // If both l & r are 'low',
+- temp1 = 0x8000; // turn on the mute bit.
+- else
+- temp1 = 0;
+-
+- temp1 |= (rl << 8) | rr;
+-
+- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1);
+- cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1);
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[8] = ((unsigned int) r << 8) | l;
+-#else
+- s->mix.vol[8] = val;
+-#endif
+- return put_user(s->mix.vol[8], (int __user *)argp);
+-
+- case SOUND_MIXER_SPEAKER:
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- if (l < 3) {
+- rl = 0;
+- l = 0;
+- } else {
+- rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15.
+- l = (rl * 13 + 5) / 2;
+- }
+-
+- if (rl < 3) {
+- temp1 = 0x8000;
+- rl = 0;
+- } else
+- temp1 = 0;
+- rl = 15 - rl; // Convert volume to attenuation.
+- temp1 |= rl << 1;
+- cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1);
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[6] = l << 8;
+-#else
+- s->mix.vol[6] = val;
+-#endif
+- return put_user(s->mix.vol[6], (int __user *)argp);
+-
+- case SOUND_MIXER_RECLEV:
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- r = (val >> 8) & 0xff;
+- if (r > 100)
+- r = 100;
+- rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15.
+- rr = (r * 2 - 5) / 13;
+- if (rl < 3 && rr < 3)
+- temp1 = 0x8000;
+- else
+- temp1 = 0;
+-
+- temp1 = temp1 | (rl << 8) | rr;
+- cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[7] = ((unsigned int) r << 8) | l;
+-#else
+- s->mix.vol[7] = val;
+-#endif
+- return put_user(s->mix.vol[7], (int __user *)argp);
+-
+- case SOUND_MIXER_MIC:
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- if (l < 1) {
+- l = 0;
+- rl = 0;
+- } else {
+- rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31.
+- l = (rl * 16 + 4) / 5;
+- }
+- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
+- temp1 &= 0x40; // Isolate 20db gain bit.
+- if (rl < 3) {
+- temp1 |= 0x8000;
+- rl = 0;
+- }
+- rl = 31 - rl; // Convert volume to attenuation.
+- temp1 |= rl;
+- cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[5] = val << 8;
+-#else
+- s->mix.vol[5] = val;
+-#endif
+- return put_user(s->mix.vol[5], (int __user *)argp);
+-
+-
+- case SOUND_MIXER_SYNTH:
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- r = (val >> 8) & 0xff;
+- if (r > 100)
+- r = 100;
+- rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63.
+- rr = (r * 2 - 11) / 3;
+- if (rl < 3) // If l is low, turn on
+- temp1 = 0x0080; // the mute bit.
+- else
+- temp1 = 0;
+-
+- rl = 63 - rl; // Convert vol to attenuation.
+- writel(temp1 | rl, s->pBA0 + BA0_FMLVC);
+- if (rr < 3) // If rr is low, turn on
+- temp1 = 0x0080; // the mute bit.
+- else
+- temp1 = 0;
+- rr = 63 - rr; // Convert vol to attenuation.
+- writel(temp1 | rr, s->pBA0 + BA0_FMRVC);
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[4] = (r << 8) | l;
+-#else
+- s->mix.vol[4] = val;
+-#endif
+- return put_user(s->mix.vol[4], (int __user *)argp);
+-
+-
+- default:
+- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
+- "cs4281: mixer_ioctl(): default\n"));
+-
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
+- return -EINVAL;
+- if (get_user(val, (int __user *)argp))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- if (l < 1) {
+- l = 0;
+- rl = 31;
+- } else
+- rl = (attentbl[(l * 10) / 100]) >> 1;
+-
+- r = (val >> 8) & 0xff;
+- if (r > 100)
+- r = 100;
+- if (r < 1) {
+- r = 0;
+- rr = 31;
+- } else
+- rr = (attentbl[(r * 10) / 100]) >> 1;
+- if ((rl > 30) && (rr > 30))
+- temp1 = 0x8000;
+- else
+- temp1 = 0;
+- temp1 = temp1 | (rl << 8) | rr;
+- cs4281_write_ac97(s, mixreg[vidx - 1], temp1);
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l;
+-#else
+- s->mix.vol[vidx - 1] = val;
+-#endif
+-#ifndef NOT_CS4281_PM
+- CS_DBGOUT(CS_PM, 9, printk(KERN_INFO
+- "write ac97 mixreg[%d]=0x%x mix.vol[]=0x%x\n",
+- vidx-1,temp1,s->mix.vol[vidx-1]));
+-#endif
+- return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
+- }
+-}
+-
+-
+-// ---------------------------------------------------------------------
+-
+-static int cs4281_open_mixdev(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct cs4281_state *s=NULL;
+- struct list_head *entry;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
+- printk(KERN_INFO "cs4281: cs4281_open_mixdev()+\n"));
+-
+- list_for_each(entry, &cs4281_devs)
+- {
+- s = list_entry(entry, struct cs4281_state, list);
+- if(s->dev_mixer == minor)
+- break;
+- }
+- if (!s)
+- {
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
+- printk(KERN_INFO "cs4281: cs4281_open_mixdev()- -ENODEV\n"));
+- return -ENODEV;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
+- printk(KERN_INFO "cs4281: cs4281_open_mixdev()- 0\n"));
+-
+- return nonseekable_open(inode, file);
+-}
+-
+-
+-static int cs4281_release_mixdev(struct inode *inode, struct file *file)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+-
+- VALIDATE_STATE(s);
+- return 0;
+-}
+-
+-
+-static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- return mixer_ioctl((struct cs4281_state *) file->private_data, cmd,
+- arg);
+-}
+-
+-
+-// ******************************************************************************************
+-// Mixer file operations struct.
+-// ******************************************************************************************
+-static /*const */ struct file_operations cs4281_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = cs4281_ioctl_mixdev,
+- .open = cs4281_open_mixdev,
+- .release = cs4281_release_mixdev,
+-};
+-
+-// ---------------------------------------------------------------------
+-
+-
+-static int drain_adc(struct cs4281_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count;
+- unsigned tmo;
+-
+- if (s->dma_adc.mapped)
+- return 0;
+- add_wait_queue(&s->dma_adc.wait, &wait);
+- for (;;) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_adc.count;
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: drain_adc() %d\n", count));
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0) {
+- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
+- "cs4281: drain_adc() count<0\n"));
+- break;
+- }
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_adc.wait, &wait);
+- current->state = TASK_RUNNING;
+- return -EBUSY;
+- }
+- tmo =
+- 3 * HZ * (count +
+- s->dma_adc.fragsize) / 2 / s->prop_adc.rate;
+- if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- tmo >>= 1;
+- if (s->prop_adc.channels > 1)
+- tmo >>= 1;
+- if (!schedule_timeout(tmo + 1))
+- printk(KERN_DEBUG "cs4281: dma timed out??\n");
+- }
+- remove_wait_queue(&s->dma_adc.wait, &wait);
+- current->state = TASK_RUNNING;
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-static int drain_dac(struct cs4281_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count;
+- unsigned tmo;
+-
+- if (s->dma_dac.mapped)
+- return 0;
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- for (;;) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- current->state = TASK_RUNNING;
+- return -EBUSY;
+- }
+- tmo =
+- 3 * HZ * (count +
+- s->dma_dac.fragsize) / 2 / s->prop_dac.rate;
+- if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- tmo >>= 1;
+- if (s->prop_dac.channels > 1)
+- tmo >>= 1;
+- if (!schedule_timeout(tmo + 1))
+- printk(KERN_DEBUG "cs4281: dma timed out??\n");
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- current->state = TASK_RUNNING;
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-//****************************************************************************
+-//
+-// CopySamples copies 16-bit stereo samples from the source to the
+-// destination, possibly converting down to either 8-bit or mono or both.
+-// count specifies the number of output bytes to write.
+-//
+-// Arguments:
+-//
+-// dst - Pointer to a destination buffer.
+-// src - Pointer to a source buffer
+-// count - The number of bytes to copy into the destination buffer.
+-// iChannels - Stereo - 2
+-// Mono - 1
+-// fmt - AFMT_xxx (soundcard.h formats)
+-//
+-// NOTES: only call this routine for conversion to 8bit from 16bit
+-//
+-//****************************************************************************
+-static void CopySamples(char *dst, char *src, int count, int iChannels,
+- unsigned fmt)
+-{
+-
+- unsigned short *psSrc;
+- long lAudioSample;
+-
+- CS_DBGOUT(CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: CopySamples()+ "));
+- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
+- " dst=%p src=%p count=%d iChannels=%d fmt=0x%x\n",
+- dst, src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt));
+-
+- // Gershwin does format conversion in hardware so normally
+- // we don't do any host based coversion. The data formatter
+- // truncates 16 bit data to 8 bit and that causes some hiss.
+- // We have already forced the HW to do 16 bit sampling and
+- // 2 channel so that we can use software to round instead
+- // of truncate
+-
+- //
+- // See if the data should be output as 8-bit unsigned stereo.
+- // or if the data should be output at 8-bit unsigned mono.
+- //
+- if ( ((iChannels == 2) && (fmt & AFMT_U8)) ||
+- ((iChannels == 1) && (fmt & AFMT_U8)) ) {
+- //
+- // Convert each 16-bit unsigned stereo sample to 8-bit unsigned
+- // stereo using rounding.
+- //
+- psSrc = (unsigned short *) src;
+- count = count / 2;
+- while (count--) {
+- lAudioSample = (long) psSrc[count] + (long) 0x80;
+- if (lAudioSample > 0xffff) {
+- lAudioSample = 0xffff;
+- }
+- dst[count] = (char) (lAudioSample >> 8);
+- }
+- }
+- //
+- // check for 8-bit signed stereo.
+- //
+- else if ((iChannels == 2) && (fmt & AFMT_S8)) {
+- //
+- // Convert each 16-bit stereo sample to 8-bit stereo using rounding.
+- //
+- psSrc = (short *) src;
+- while (count--) {
+- lAudioSample =
+- (((long) psSrc[0] + (long) psSrc[1]) / 2);
+- psSrc += 2;
+- *dst++ = (char) ((short) lAudioSample >> 8);
+- }
+- }
+- //
+- // Otherwise, the data should be output as 8-bit signed mono.
+- //
+- else if ((iChannels == 1) && (fmt & AFMT_S8)) {
+- //
+- // Convert each 16-bit signed mono sample to 8-bit signed mono
+- // using rounding.
+- //
+- psSrc = (short *) src;
+- count = count / 2;
+- while (count--) {
+- lAudioSample =
+- (((long) psSrc[0] + (long) psSrc[1]) / 2);
+- if (lAudioSample > 0x7fff) {
+- lAudioSample = 0x7fff;
+- }
+- psSrc += 2;
+- *dst++ = (char) ((short) lAudioSample >> 8);
+- }
+- }
+-}
+-
+-//
+-// cs_copy_to_user()
+-// replacement for the standard copy_to_user, to allow for a conversion from
+-// 16 bit to 8 bit if the record conversion is active. the cs4281 has some
+-// issues with 8 bit capture, so the driver always captures data in 16 bit
+-// and then if the user requested 8 bit, converts from 16 to 8 bit.
+-//
+-static unsigned cs_copy_to_user(struct cs4281_state *s, void __user *dest,
+- unsigned *hwsrc, unsigned cnt,
+- unsigned *copied)
+-{
+- void *src = hwsrc; //default to the standard destination buffer addr
+-
+- CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
+- "cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=%p\n",
+- s->prop_adc.fmt, s->prop_adc.fmt_original,
+- (unsigned) cnt, dest));
+-
+- if (cnt > s->dma_adc.dmasize) {
+- cnt = s->dma_adc.dmasize;
+- }
+- if (!cnt) {
+- *copied = 0;
+- return 0;
+- }
+- if (s->conversion) {
+- if (!s->tmpbuff) {
+- *copied = cnt / 2;
+- return 0;
+- }
+- CopySamples(s->tmpbuff, (void *) hwsrc, cnt,
+- (unsigned) s->prop_adc.channels,
+- s->prop_adc.fmt_original);
+- src = s->tmpbuff;
+- cnt = cnt / 2;
+- }
+-
+- if (copy_to_user(dest, src, cnt)) {
+- *copied = 0;
+- return -EFAULT;
+- }
+- *copied = cnt;
+- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
+- "cs4281: cs_copy_to_user()- copied bytes is %d \n", cnt));
+- return 0;
+-}
+-
+-// ---------------------------------------------------------------------
+-
+-static ssize_t cs4281_read(struct file *file, char __user *buffer, size_t count,
+- loff_t * ppos)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+- unsigned copied = 0;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
+- printk(KERN_INFO "cs4281: cs4281_read()+ %Zu \n", count));
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-//
+-// "count" is the amount of bytes to read (from app), is decremented each loop
+-// by the amount of bytes that have been returned to the user buffer.
+-// "cnt" is the running total of each read from the buffer (changes each loop)
+-// "buffer" points to the app's buffer
+-// "ret" keeps a running total of the amount of bytes that have been copied
+-// to the user buffer.
+-// "copied" is the total bytes copied into the user buffer for each loop.
+-//
+- while (count > 0) {
+- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
+- "_read() count>0 count=%Zu .count=%d .swptr=%d .hwptr=%d \n",
+- count, s->dma_adc.count,
+- s->dma_adc.swptr, s->dma_adc.hwptr));
+- spin_lock_irqsave(&s->lock, flags);
+-
+- // get the current copy point of the sw buffer
+- swptr = s->dma_adc.swptr;
+-
+- // cnt is the amount of unread bytes from the end of the
+- // hw buffer to the current sw pointer
+- cnt = s->dma_adc.dmasize - swptr;
+-
+- // dma_adc.count is the current total bytes that have not been read.
+- // if the amount of unread bytes from the current sw pointer to the
+- // end of the buffer is greater than the current total bytes that
+- // have not been read, then set the "cnt" (unread bytes) to the
+- // amount of unread bytes.
+-
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- //
+- // if we are converting from 8/16 then we need to copy
+- // twice the number of 16 bit bytes then 8 bit bytes.
+- //
+- if (s->conversion) {
+- if (cnt > (count * 2))
+- cnt = (count * 2);
+- } else {
+- if (cnt > count)
+- cnt = count;
+- }
+- //
+- // "cnt" NOW is the smaller of the amount that will be read,
+- // and the amount that is requested in this read (or partial).
+- // if there are no bytes in the buffer to read, then start the
+- // ADC and wait for the interrupt handler to wake us up.
+- //
+- if (cnt <= 0) {
+-
+- // start up the dma engine and then continue back to the top of
+- // the loop when wake up occurs.
+- start_adc(s);
+- if (file->f_flags & O_NONBLOCK)
+- return ret ? ret : -EAGAIN;
+- interruptible_sleep_on(&s->dma_adc.wait);
+- if (signal_pending(current))
+- return ret ? ret : -ERESTARTSYS;
+- continue;
+- }
+- // there are bytes in the buffer to read.
+- // copy from the hw buffer over to the user buffer.
+- // user buffer is designated by "buffer"
+- // virtual address to copy from is rawbuf+swptr
+- // the "cnt" is the number of bytes to read.
+-
+- CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
+- "_read() copy_to cnt=%d count=%Zu ", cnt, count));
+- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
+- " .dmasize=%d .count=%d buffer=%p ret=%Zd\n",
+- s->dma_adc.dmasize, s->dma_adc.count, buffer, ret));
+-
+- if (cs_copy_to_user
+- (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied))
+- return ret ? ret : -EFAULT;
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= copied;
+- buffer += copied;
+- ret += copied;
+- start_adc(s);
+- }
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
+- printk(KERN_INFO "cs4281: cs4281_read()- %Zd\n", ret));
+- return ret;
+-}
+-
+-
+-static ssize_t cs4281_write(struct file *file, const char __user *buffer,
+- size_t count, loff_t * ppos)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr, hwptr, busaddr;
+- int cnt;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
+- printk(KERN_INFO "cs4281: cs4281_write()+ count=%Zu\n",
+- count));
+- VALIDATE_STATE(s);
+-
+- if (s->dma_dac.mapped)
+- return -ENXIO;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = s->dma_dac.hwptr;
+- }
+- if (s->dma_dac.underrun) {
+- s->dma_dac.underrun = 0;
+- hwptr = readl(s->pBA0 + BA0_DCA0);
+- busaddr = virt_to_bus(s->dma_dac.rawbuf);
+- hwptr -= (unsigned) busaddr;
+- s->dma_dac.swptr = s->dma_dac.hwptr = hwptr;
+- }
+- swptr = s->dma_dac.swptr;
+- cnt = s->dma_dac.dmasize - swptr;
+- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- start_dac(s);
+- if (file->f_flags & O_NONBLOCK)
+- return ret ? ret : -EAGAIN;
+- interruptible_sleep_on(&s->dma_dac.wait);
+- if (signal_pending(current))
+- return ret ? ret : -ERESTARTSYS;
+- continue;
+- }
+- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+- return ret ? ret : -EFAULT;
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac.swptr = swptr;
+- s->dma_dac.count += cnt;
+- s->dma_dac.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- start_dac(s);
+- }
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
+- printk(KERN_INFO "cs4281: cs4281_write()- %Zd\n", ret));
+- return ret;
+-}
+-
+-
+-static unsigned int cs4281_poll(struct file *file,
+- struct poll_table_struct *wait)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+- printk(KERN_INFO "cs4281: cs4281_poll()+\n"));
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE) {
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+- printk(KERN_INFO
+- "cs4281: cs4281_poll() wait on FMODE_WRITE\n"));
+- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
+- return 0;
+- poll_wait(file, &s->dma_dac.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+- printk(KERN_INFO
+- "cs4281: cs4281_poll() wait on FMODE_READ\n"));
+- if(!s->dma_dac.ready && prog_dmabuf_adc(s))
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_update_ptr(s,CS_FALSE);
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >=
+- (signed) s->dma_dac.fragsize) {
+- if (s->dma_dac.wakeup)
+- mask |= POLLOUT | POLLWRNORM;
+- else
+- mask = 0;
+- s->dma_dac.wakeup = 0;
+- }
+- } else {
+- if ((signed) (s->dma_dac.dmasize/2) >= s->dma_dac.count)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- } else if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.mapped) {
+- if (s->dma_adc.count >= (signed) s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- } else {
+- if (s->dma_adc.count > 0)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+- printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",
+- mask));
+- return mask;
+-}
+-
+-
+-static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- struct dmabuf *db;
+- int ret;
+- unsigned long size;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
+- printk(KERN_INFO "cs4281: cs4281_mmap()+\n"));
+-
+- VALIDATE_STATE(s);
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf_dac(s)) != 0)
+- return ret;
+- db = &s->dma_dac;
+- } else if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf_adc(s)) != 0)
+- return ret;
+- db = &s->dma_adc;
+- } else
+- return -EINVAL;
+-//
+-// only support PLAYBACK for now
+-//
+- db = &s->dma_dac;
+-
+- if (cs4x_pgoff(vma) != 0)
+- return -EINVAL;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder))
+- return -EINVAL;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- return -EAGAIN;
+- db->mapped = 1;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
+- printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
+- (unsigned) size));
+-
+- return 0;
+-}
+-
+-
+-static int cs4281_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int val, mapped, ret;
+- int __user *p = (int __user *)arg;
+-
+- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): file=%p cmd=0x%.8x\n", file, cmd));
+-#if CSDEBUG
+- cs_printioctl(cmd);
+-#endif
+- VALIDATE_STATE(s);
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n",
+- SOUND_VERSION));
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_SYNC\n"));
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s,
+- 0 /*file->f_flags & O_NONBLOCK */
+- );
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+- DSP_CAP_TRIGGER | DSP_CAP_MMAP,
+- p);
+-
+- case SNDCTL_DSP_RESET:
+- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_RESET\n"));
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->irq);
+- s->dma_dac.swptr = s->dma_dac.hwptr =
+- s->dma_dac.count = s->dma_dac.total_bytes =
+- s->dma_dac.blocks = s->dma_dac.wakeup = 0;
+- prog_codec(s, CS_TYPE_DAC);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr =
+- s->dma_adc.count = s->dma_adc.total_bytes =
+- s->dma_adc.blocks = s->dma_dac.wakeup = 0;
+- prog_codec(s, CS_TYPE_ADC);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_SPEED val=%d\n", val));
+- //
+- // support independent capture and playback channels
+- // assume that the file mode bit determines the
+- // direction of the data flow.
+- //
+- if (file->f_mode & FMODE_READ) {
+- if (val >= 0) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- // program sampling rates
+- if (val > 48000)
+- val = 48000;
+- if (val < 6300)
+- val = 6300;
+- s->prop_adc.rate = val;
+- prog_codec(s, CS_TYPE_ADC);
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val >= 0) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- // program sampling rates
+- if (val > 48000)
+- val = 48000;
+- if (val < 6300)
+- val = 6300;
+- s->prop_dac.rate = val;
+- prog_codec(s, CS_TYPE_DAC);
+- }
+- }
+-
+- if (file->f_mode & FMODE_WRITE)
+- val = s->prop_dac.rate;
+- else if (file->f_mode & FMODE_READ)
+- val = s->prop_adc.rate;
+-
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_STEREO val=%d\n", val));
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- s->prop_adc.channels = val ? 2 : 1;
+- prog_codec(s, CS_TYPE_ADC);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- s->prop_dac.channels = val ? 2 : 1;
+- prog_codec(s, CS_TYPE_DAC);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_CHANNELS val=%d\n",
+- val));
+- if (val != 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val >= 2)
+- s->prop_adc.channels = 2;
+- else
+- s->prop_adc.channels = 1;
+- prog_codec(s, CS_TYPE_ADC);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val >= 2)
+- s->prop_dac.channels = 2;
+- else
+- s->prop_dac.channels = 1;
+- prog_codec(s, CS_TYPE_DAC);
+- }
+- }
+-
+- if (file->f_mode & FMODE_WRITE)
+- val = s->prop_dac.channels;
+- else if (file->f_mode & FMODE_READ)
+- val = s->prop_adc.channels;
+-
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_GETFMTS: // Returns a mask
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_GETFMT val=0x%.8x\n",
+- AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
+- AFMT_U8));
+- return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
+- AFMT_U8, p);
+-
+- case SNDCTL_DSP_SETFMT:
+- if (get_user(val, p))
+- return -EFAULT;
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_SETFMT val=0x%.8x\n",
+- val));
+- if (val != AFMT_QUERY) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val != AFMT_S16_LE
+- && val != AFMT_U16_LE && val != AFMT_S8
+- && val != AFMT_U8)
+- val = AFMT_U8;
+- s->prop_adc.fmt = val;
+- s->prop_adc.fmt_original = s->prop_adc.fmt;
+- prog_codec(s, CS_TYPE_ADC);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val != AFMT_S16_LE
+- && val != AFMT_U16_LE && val != AFMT_S8
+- && val != AFMT_U8)
+- val = AFMT_U8;
+- s->prop_dac.fmt = val;
+- s->prop_dac.fmt_original = s->prop_dac.fmt;
+- prog_codec(s, CS_TYPE_DAC);
+- }
+- } else {
+- if (file->f_mode & FMODE_WRITE)
+- val = s->prop_dac.fmt_original;
+- else if (file->f_mode & FMODE_READ)
+- val = s->prop_adc.fmt_original;
+- }
+- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_SETFMT return val=0x%.8x\n",
+- val));
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_POST:
+- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): DSP_POST\n"));
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if (file->f_mode & s->ena & FMODE_READ)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & s->ena & FMODE_WRITE)
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready
+- && (ret = prog_dmabuf_adc(s)))
+- return ret;
+- start_adc(s);
+- } else
+- stop_adc(s);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac.ready
+- && (ret = prog_dmabuf_dac(s)))
+- return ret;
+- start_dac(s);
+- } else
+- stop_dac(s);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)))
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_update_ptr(s,CS_FALSE);
+- abinfo.fragsize = s->dma_dac.fragsize;
+- if (s->dma_dac.mapped)
+- abinfo.bytes = s->dma_dac.dmasize;
+- else
+- abinfo.bytes =
+- s->dma_dac.dmasize - s->dma_dac.count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
+- "cs4281: cs4281_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n",
+- abinfo.fragsize,abinfo.bytes,abinfo.fragstotal,
+- abinfo.fragments));
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(p, &abinfo,
+- sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)))
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_update_ptr(s,CS_FALSE);
+- if (s->conversion) {
+- abinfo.fragsize = s->dma_adc.fragsize / 2;
+- abinfo.bytes = s->dma_adc.count / 2;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments =
+- abinfo.bytes >> (s->dma_adc.fragshift - 1);
+- } else {
+- abinfo.fragsize = s->dma_adc.fragsize;
+- abinfo.bytes = s->dma_adc.count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments =
+- abinfo.bytes >> s->dma_adc.fragshift;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(p, &abinfo,
+- sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
+- return 0;
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_update_ptr(s,CS_FALSE);
+- val = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if(!s->dma_adc.ready && prog_dmabuf_adc(s))
+- return 0;
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_update_ptr(s,CS_FALSE);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- if (s->dma_adc.mapped) {
+- cinfo.blocks =
+- (cinfo.bytes >> s->dma_adc.fragshift) -
+- s->dma_adc.blocks;
+- s->dma_adc.blocks =
+- cinfo.bytes >> s->dma_adc.fragshift;
+- } else {
+- if (s->conversion) {
+- cinfo.blocks =
+- s->dma_adc.count /
+- 2 >> (s->dma_adc.fragshift - 1);
+- } else
+- cinfo.blocks =
+- s->dma_adc.count >> s->dma_adc.
+- fragshift;
+- }
+- if (s->conversion)
+- cinfo.ptr = s->dma_adc.hwptr / 2;
+- else
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize - 1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
+- return 0;
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_update_ptr(s,CS_FALSE);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- if (s->dma_dac.mapped) {
+- cinfo.blocks =
+- (cinfo.bytes >> s->dma_dac.fragshift) -
+- s->dma_dac.blocks;
+- s->dma_dac.blocks =
+- cinfo.bytes >> s->dma_dac.fragshift;
+- } else {
+- cinfo.blocks =
+- s->dma_dac.count >> s->dma_dac.fragshift;
+- }
+- cinfo.ptr = s->dma_dac.hwptr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize - 1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf_dac(s)))
+- return val;
+- return put_user(s->dma_dac.fragsize, p);
+- }
+- if ((val = prog_dmabuf_adc(s)))
+- return val;
+- if (s->conversion)
+- return put_user(s->dma_adc.fragsize / 2, p);
+- else
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- return 0; // Say OK, but do nothing.
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision)
+- || (file->f_mode & FMODE_WRITE
+- && s->dma_dac.subdivision)) return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- else if (file->f_mode & FMODE_WRITE)
+- s->dma_dac.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- if (file->f_mode & FMODE_READ)
+- return put_user(s->prop_adc.rate, p);
+- else if (file->f_mode & FMODE_WRITE)
+- return put_user(s->prop_dac.rate, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- if (file->f_mode & FMODE_READ)
+- return put_user(s->prop_adc.channels, p);
+- else if (file->f_mode & FMODE_WRITE)
+- return put_user(s->prop_dac.channels, p);
+-
+- case SOUND_PCM_READ_BITS:
+- if (file->f_mode & FMODE_READ)
+- return
+- put_user(
+- (s->prop_adc.
+- fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
+- p);
+- else if (file->f_mode & FMODE_WRITE)
+- return
+- put_user(
+- (s->prop_dac.
+- fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
+- p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+- }
+- return mixer_ioctl(s, cmd, arg);
+-}
+-
+-
+-static int cs4281_release(struct inode *inode, struct file *file)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO
+- "cs4281: cs4281_release(): inode=%p file=%p f_mode=%d\n",
+- inode, file, file->f_mode));
+-
+- VALIDATE_STATE(s);
+-
+- if (file->f_mode & FMODE_WRITE) {
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_sem_dac);
+- stop_dac(s);
+- dealloc_dmabuf(s, &s->dma_dac);
+- s->open_mode &= ~FMODE_WRITE;
+- mutex_unlock(&s->open_sem_dac);
+- wake_up(&s->open_wait_dac);
+- }
+- if (file->f_mode & FMODE_READ) {
+- drain_adc(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_sem_adc);
+- stop_adc(s);
+- dealloc_dmabuf(s, &s->dma_adc);
+- s->open_mode &= ~FMODE_READ;
+- mutex_unlock(&s->open_sem_adc);
+- wake_up(&s->open_wait_adc);
+- }
+- return 0;
+-}
+-
+-static int cs4281_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct cs4281_state *s=NULL;
+- struct list_head *entry;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+- "cs4281: cs4281_open(): inode=%p file=%p f_mode=0x%x\n",
+- inode, file, file->f_mode));
+-
+- list_for_each(entry, &cs4281_devs)
+- {
+- s = list_entry(entry, struct cs4281_state, list);
+-
+- if (!((s->dev_audio ^ minor) & ~0xf))
+- break;
+- }
+- if (entry == &cs4281_devs)
+- return -ENODEV;
+- if (!s) {
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+- "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
+- return -ENODEV;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+-
+- // wait for device to become free
+- if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO
+- "cs4281: cs4281_open(): Error - must open READ and/or WRITE\n"));
+- return -ENODEV;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- mutex_lock(&s->open_sem_dac);
+- while (s->open_mode & FMODE_WRITE) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_sem_dac);
+- return -EBUSY;
+- }
+- mutex_unlock(&s->open_sem_dac);
+- interruptible_sleep_on(&s->open_wait_dac);
+-
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_sem_dac);
+- }
+- }
+- if (file->f_mode & FMODE_READ) {
+- mutex_lock(&s->open_sem_adc);
+- while (s->open_mode & FMODE_READ) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_sem_adc);
+- return -EBUSY;
+- }
+- mutex_unlock(&s->open_sem_adc);
+- interruptible_sleep_on(&s->open_wait_adc);
+-
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_sem_adc);
+- }
+- }
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- if (file->f_mode & FMODE_READ) {
+- s->prop_adc.fmt = AFMT_U8;
+- s->prop_adc.fmt_original = s->prop_adc.fmt;
+- s->prop_adc.channels = 1;
+- s->prop_adc.rate = 8000;
+- s->prop_adc.clkdiv = 96 | 0x80;
+- s->conversion = 0;
+- s->ena &= ~FMODE_READ;
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
+- s->dma_adc.subdivision = 0;
+- mutex_unlock(&s->open_sem_adc);
+-
+- if (prog_dmabuf_adc(s)) {
+- CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
+- "cs4281: adc Program dmabufs failed.\n"));
+- cs4281_release(inode, file);
+- return -ENOMEM;
+- }
+- prog_codec(s, CS_TYPE_ADC);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->prop_dac.fmt = AFMT_U8;
+- s->prop_dac.fmt_original = s->prop_dac.fmt;
+- s->prop_dac.channels = 1;
+- s->prop_dac.rate = 8000;
+- s->prop_dac.clkdiv = 96 | 0x80;
+- s->conversion = 0;
+- s->ena &= ~FMODE_WRITE;
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
+- s->dma_dac.subdivision = 0;
+- mutex_unlock(&s->open_sem_dac);
+-
+- if (prog_dmabuf_dac(s)) {
+- CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
+- "cs4281: dac Program dmabufs failed.\n"));
+- cs4281_release(inode, file);
+- return -ENOMEM;
+- }
+- prog_codec(s, CS_TYPE_DAC);
+- }
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
+- printk(KERN_INFO "cs4281: cs4281_open()- 0\n"));
+- return nonseekable_open(inode, file);
+-}
+-
+-
+-// ******************************************************************************************
+-// Wave (audio) file operations struct.
+-// ******************************************************************************************
+-static /*const */ struct file_operations cs4281_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = cs4281_read,
+- .write = cs4281_write,
+- .poll = cs4281_poll,
+- .ioctl = cs4281_ioctl,
+- .mmap = cs4281_mmap,
+- .open = cs4281_open,
+- .release = cs4281_release,
+-};
+-
+-// ---------------------------------------------------------------------
+-
+-// hold spinlock for the following!
+-static void cs4281_handle_midi(struct cs4281_state *s)
+-{
+- unsigned char ch;
+- int wake;
+- unsigned temp1;
+-
+- wake = 0;
+- while (!(readl(s->pBA0 + BA0_MIDSR) & 0x80)) {
+- ch = readl(s->pBA0 + BA0_MIDRP);
+- if (s->midi.icnt < MIDIINBUF) {
+- s->midi.ibuf[s->midi.iwr] = ch;
+- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+- s->midi.icnt++;
+- }
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.iwait);
+- wake = 0;
+- while (!(readl(s->pBA0 + BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
+- temp1 = (s->midi.obuf[s->midi.ord]) & 0x000000ff;
+- writel(temp1, s->pBA0 + BA0_MIDWP);
+- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+- s->midi.ocnt--;
+- if (s->midi.ocnt < MIDIOUTBUF - 16)
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.owait);
+-}
+-
+-
+-
+-static irqreturn_t cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct cs4281_state *s = (struct cs4281_state *) dev_id;
+- unsigned int temp1;
+-
+- // fastpath out, to ease interrupt sharing
+- temp1 = readl(s->pBA0 + BA0_HISR); // Get Int Status reg.
+-
+- CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
+- "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n", temp1));
+-/*
+-* If not DMA or MIDI interrupt, then just return.
+-*/
+- if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) {
+- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
+- CS_DBGOUT(CS_INTERRUPT, 9, printk(KERN_INFO
+- "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n"));
+- return IRQ_NONE;
+- }
+-
+- if (temp1 & HISR_DMA0) // If play interrupt,
+- readl(s->pBA0 + BA0_HDSR0); // clear the source.
+-
+- if (temp1 & HISR_DMA1) // Same for play.
+- readl(s->pBA0 + BA0_HDSR1);
+- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Local EOI
+-
+- spin_lock(&s->lock);
+- cs4281_update_ptr(s,CS_TRUE);
+- cs4281_handle_midi(s);
+- spin_unlock(&s->lock);
+- return IRQ_HANDLED;
+-}
+-
+-// **************************************************************************
+-
+-static void cs4281_midi_timer(unsigned long data)
+-{
+- struct cs4281_state *s = (struct cs4281_state *) data;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->midi.timer.expires = jiffies + 1;
+- add_timer(&s->midi.timer);
+-}
+-
+-
+-// ---------------------------------------------------------------------
+-
+-static ssize_t cs4281_midi_read(struct file *file, char __user *buffer,
+- size_t count, loff_t * ppos)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.ird;
+- cnt = MIDIINBUF - ptr;
+- if (s->midi.icnt < cnt)
+- cnt = s->midi.icnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK)
+- return ret ? ret : -EAGAIN;
+- interruptible_sleep_on(&s->midi.iwait);
+- if (signal_pending(current))
+- return ret ? ret : -ERESTARTSYS;
+- continue;
+- }
+- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+- return ret ? ret : -EFAULT;
+- ptr = (ptr + cnt) % MIDIINBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.ird = ptr;
+- s->midi.icnt -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- }
+- return ret;
+-}
+-
+-
+-static ssize_t cs4281_midi_write(struct file *file, const char __user *buffer,
+- size_t count, loff_t * ppos)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.owr;
+- cnt = MIDIOUTBUF - ptr;
+- if (s->midi.ocnt + cnt > MIDIOUTBUF)
+- cnt = MIDIOUTBUF - s->midi.ocnt;
+- if (cnt <= 0)
+- cs4281_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK)
+- return ret ? ret : -EAGAIN;
+- interruptible_sleep_on(&s->midi.owait);
+- if (signal_pending(current))
+- return ret ? ret : -ERESTARTSYS;
+- continue;
+- }
+- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+- return ret ? ret : -EFAULT;
+- ptr = (ptr + cnt) % MIDIOUTBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.owr = ptr;
+- s->midi.ocnt += cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- spin_lock_irqsave(&s->lock, flags);
+- cs4281_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return ret;
+-}
+-
+-
+-static unsigned int cs4281_midi_poll(struct file *file,
+- struct poll_table_struct *wait)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_flags & FMODE_WRITE)
+- poll_wait(file, &s->midi.owait, wait);
+- if (file->f_flags & FMODE_READ)
+- poll_wait(file, &s->midi.iwait, wait);
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_flags & FMODE_READ) {
+- if (s->midi.icnt > 0)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_flags & FMODE_WRITE) {
+- if (s->midi.ocnt < MIDIOUTBUF)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-
+-static int cs4281_midi_open(struct inode *inode, struct file *file)
+-{
+- unsigned long flags, temp1;
+- unsigned int minor = iminor(inode);
+- struct cs4281_state *s=NULL;
+- struct list_head *entry;
+- list_for_each(entry, &cs4281_devs)
+- {
+- s = list_entry(entry, struct cs4281_state, list);
+-
+- if (s->dev_midi == minor)
+- break;
+- }
+-
+- if (entry == &cs4281_devs)
+- return -ENODEV;
+- if (!s)
+- {
+- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+- "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
+- return -ENODEV;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- // wait for device to become free
+- mutex_lock(&s->open_sem);
+- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_sem);
+- return -EBUSY;
+- }
+- mutex_unlock(&s->open_sem);
+- interruptible_sleep_on(&s->open_wait);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_sem);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- writel(1, s->pBA0 + BA0_MIDCR); // Reset the interface.
+- writel(0, s->pBA0 + BA0_MIDCR); // Return to normal mode.
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- writel(0x0000000f, s->pBA0 + BA0_MIDCR); // Enable transmit, record, ints.
+- temp1 = readl(s->pBA0 + BA0_HIMR);
+- writel(temp1 & 0xffbfffff, s->pBA0 + BA0_HIMR); // Enable midi int. recognition.
+- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts
+- init_timer(&s->midi.timer);
+- s->midi.timer.expires = jiffies + 1;
+- s->midi.timer.data = (unsigned long) s;
+- s->midi.timer.function = cs4281_midi_timer;
+- add_timer(&s->midi.timer);
+- }
+- if (file->f_mode & FMODE_READ) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->open_mode |=
+- (file->
+- f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ |
+- FMODE_MIDI_WRITE);
+- mutex_unlock(&s->open_sem);
+- return nonseekable_open(inode, file);
+-}
+-
+-
+-static int cs4281_midi_release(struct inode *inode, struct file *file)
+-{
+- struct cs4281_state *s =
+- (struct cs4281_state *) file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- unsigned count, tmo;
+-
+- VALIDATE_STATE(s);
+-
+- if (file->f_mode & FMODE_WRITE) {
+- add_wait_queue(&s->midi.owait, &wait);
+- for (;;) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->midi.ocnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (file->f_flags & O_NONBLOCK) {
+- remove_wait_queue(&s->midi.owait, &wait);
+- current->state = TASK_RUNNING;
+- return -EBUSY;
+- }
+- tmo = (count * HZ) / 3100;
+- if (!schedule_timeout(tmo ? : 1) && tmo)
+- printk(KERN_DEBUG
+- "cs4281: midi timed out??\n");
+- }
+- remove_wait_queue(&s->midi.owait, &wait);
+- current->state = TASK_RUNNING;
+- }
+- mutex_lock(&s->open_sem);
+- s->open_mode &=
+- (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ |
+- FMODE_MIDI_WRITE);
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- writel(0, s->pBA0 + BA0_MIDCR); // Disable Midi interrupts.
+- del_timer(&s->midi.timer);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- mutex_unlock(&s->open_sem);
+- wake_up(&s->open_wait);
+- return 0;
+-}
+-
+-// ******************************************************************************************
+-// Midi file operations struct.
+-// ******************************************************************************************
+-static /*const */ struct file_operations cs4281_midi_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = cs4281_midi_read,
+- .write = cs4281_midi_write,
+- .poll = cs4281_midi_poll,
+- .open = cs4281_midi_open,
+- .release = cs4281_midi_release,
+-};
+-
+-
+-// ---------------------------------------------------------------------
+-
+-// maximum number of devices
+-#define NR_DEVICE 8 // Only eight devices supported currently.
+-
+-// ---------------------------------------------------------------------
+-
+-static struct initvol {
+- int mixch;
+- int vol;
+-} initvol[] __devinitdata = {
+-
+- {
+- SOUND_MIXER_WRITE_VOLUME, 0x4040}, {
+- SOUND_MIXER_WRITE_PCM, 0x4040}, {
+- SOUND_MIXER_WRITE_SYNTH, 0x4040}, {
+- SOUND_MIXER_WRITE_CD, 0x4040}, {
+- SOUND_MIXER_WRITE_LINE, 0x4040}, {
+- SOUND_MIXER_WRITE_LINE1, 0x4040}, {
+- SOUND_MIXER_WRITE_RECLEV, 0x0000}, {
+- SOUND_MIXER_WRITE_SPEAKER, 0x4040}, {
+- SOUND_MIXER_WRITE_MIC, 0x0000}
+-};
+-
+-
+-#ifndef NOT_CS4281_PM
+-static void __devinit cs4281_BuildFIFO(
+- struct cs4281_pipeline *p,
+- struct cs4281_state *s)
+-{
+- switch(p->number)
+- {
+- case 0: /* playback */
+- {
+- p->u32FCRnAddress = BA0_FCR0;
+- p->u32FSICnAddress = BA0_FSIC0;
+- p->u32FPDRnAddress = BA0_FPDR0;
+- break;
+- }
+- case 1: /* capture */
+- {
+- p->u32FCRnAddress = BA0_FCR1;
+- p->u32FSICnAddress = BA0_FSIC1;
+- p->u32FPDRnAddress = BA0_FPDR1;
+- break;
+- }
+-
+- case 2:
+- {
+- p->u32FCRnAddress = BA0_FCR2;
+- p->u32FSICnAddress = BA0_FSIC2;
+- p->u32FPDRnAddress = BA0_FPDR2;
+- break;
+- }
+- case 3:
+- {
+- p->u32FCRnAddress = BA0_FCR3;
+- p->u32FSICnAddress = BA0_FSIC3;
+- p->u32FPDRnAddress = BA0_FPDR3;
+- break;
+- }
+- default:
+- break;
+- }
+- //
+- // first read the hardware to initialize the member variables
+- //
+- p->u32FCRnValue = readl(s->pBA0 + p->u32FCRnAddress);
+- p->u32FSICnValue = readl(s->pBA0 + p->u32FSICnAddress);
+- p->u32FPDRnValue = readl(s->pBA0 + p->u32FPDRnAddress);
+-
+-}
+-
+-static void __devinit cs4281_BuildDMAengine(
+- struct cs4281_pipeline *p,
+- struct cs4281_state *s)
+-{
+-/*
+-* initialize all the addresses of this pipeline dma info.
+-*/
+- switch(p->number)
+- {
+- case 0: /* playback */
+- {
+- p->u32DBAnAddress = BA0_DBA0;
+- p->u32DCAnAddress = BA0_DCA0;
+- p->u32DBCnAddress = BA0_DBC0;
+- p->u32DCCnAddress = BA0_DCC0;
+- p->u32DMRnAddress = BA0_DMR0;
+- p->u32DCRnAddress = BA0_DCR0;
+- p->u32HDSRnAddress = BA0_HDSR0;
+- break;
+- }
+-
+- case 1: /* capture */
+- {
+- p->u32DBAnAddress = BA0_DBA1;
+- p->u32DCAnAddress = BA0_DCA1;
+- p->u32DBCnAddress = BA0_DBC1;
+- p->u32DCCnAddress = BA0_DCC1;
+- p->u32DMRnAddress = BA0_DMR1;
+- p->u32DCRnAddress = BA0_DCR1;
+- p->u32HDSRnAddress = BA0_HDSR1;
+- break;
+- }
+-
+- case 2:
+- {
+- p->u32DBAnAddress = BA0_DBA2;
+- p->u32DCAnAddress = BA0_DCA2;
+- p->u32DBCnAddress = BA0_DBC2;
+- p->u32DCCnAddress = BA0_DCC2;
+- p->u32DMRnAddress = BA0_DMR2;
+- p->u32DCRnAddress = BA0_DCR2;
+- p->u32HDSRnAddress = BA0_HDSR2;
+- break;
+- }
+-
+- case 3:
+- {
+- p->u32DBAnAddress = BA0_DBA3;
+- p->u32DCAnAddress = BA0_DCA3;
+- p->u32DBCnAddress = BA0_DBC3;
+- p->u32DCCnAddress = BA0_DCC3;
+- p->u32DMRnAddress = BA0_DMR3;
+- p->u32DCRnAddress = BA0_DCR3;
+- p->u32HDSRnAddress = BA0_HDSR3;
+- break;
+- }
+- default:
+- break;
+- }
+-
+-//
+-// Initialize the dma values for this pipeline
+-//
+- p->u32DBAnValue = readl(s->pBA0 + p->u32DBAnAddress);
+- p->u32DBCnValue = readl(s->pBA0 + p->u32DBCnAddress);
+- p->u32DMRnValue = readl(s->pBA0 + p->u32DMRnAddress);
+- p->u32DCRnValue = readl(s->pBA0 + p->u32DCRnAddress);
+-
+-}
+-
+-static void __devinit cs4281_InitPM(struct cs4281_state *s)
+-{
+- int i;
+- struct cs4281_pipeline *p;
+-
+- for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
+- {
+- p = &s->pl[i];
+- p->number = i;
+- cs4281_BuildDMAengine(p,s);
+- cs4281_BuildFIFO(p,s);
+- /*
+- * currently only 2 pipelines are used
+- * so, only set the valid bit on the playback and capture.
+- */
+- if( (i == CS4281_PLAYBACK_PIPELINE_NUMBER) ||
+- (i == CS4281_CAPTURE_PIPELINE_NUMBER))
+- p->flags |= CS4281_PIPELINE_VALID;
+- }
+- s->pm.u32SSPM_BITS = 0x7e; /* rev c, use 0x7c for rev a or b */
+-}
+-#endif
+-
+-static int __devinit cs4281_probe(struct pci_dev *pcidev,
+- const struct pci_device_id *pciid)
+-{
+- struct cs4281_state *s;
+- dma_addr_t dma_mask;
+- mm_segment_t fs;
+- int i, val;
+- unsigned int temp1, temp2;
+-
+- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
+- printk(KERN_INFO "cs4281: probe()+\n"));
+-
+- if (pci_enable_device(pcidev)) {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: pci_enable_device() failed\n"));
+- return -1;
+- }
+- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) ||
+- !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe()- Memory region not assigned\n"));
+- return -ENODEV;
+- }
+- if (pcidev->irq == 0) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe() IRQ not assigned\n"));
+- return -ENODEV;
+- }
+- dma_mask = 0xffffffff; /* this enables playback and recording */
+- i = pci_set_dma_mask(pcidev, dma_mask);
+- if (i) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n"));
+- return i;
+- }
+- if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
+- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe() no memory for state struct.\n"));
+- return -1;
+- }
+- memset(s, 0, sizeof(struct cs4281_state));
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- init_waitqueue_head(&s->open_wait_adc);
+- init_waitqueue_head(&s->open_wait_dac);
+- init_waitqueue_head(&s->midi.iwait);
+- init_waitqueue_head(&s->midi.owait);
+- mutex_init(&s->open_sem);
+- mutex_init(&s->open_sem_adc);
+- mutex_init(&s->open_sem_dac);
+- spin_lock_init(&s->lock);
+- s->pBA0phys = pci_resource_start(pcidev, 0);
+- s->pBA1phys = pci_resource_start(pcidev, 1);
+-
+- /* Convert phys to linear. */
+- s->pBA0 = ioremap_nocache(s->pBA0phys, 4096);
+- if (!s->pBA0) {
+- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
+- "cs4281: BA0 I/O mapping failed. Skipping part.\n"));
+- goto err_free;
+- }
+- s->pBA1 = ioremap_nocache(s->pBA1phys, 65536);
+- if (!s->pBA1) {
+- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
+- "cs4281: BA1 I/O mapping failed. Skipping part.\n"));
+- goto err_unmap;
+- }
+-
+- temp1 = readl(s->pBA0 + BA0_PCICFG00);
+- temp2 = readl(s->pBA0 + BA0_PCICFG04);
+-
+- CS_DBGOUT(CS_INIT, 2,
+- printk(KERN_INFO
+- "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=%p pBA1=%p \n",
+- (unsigned) temp1, (unsigned) temp2, s->pBA0, s->pBA1));
+- CS_DBGOUT(CS_INIT, 2,
+- printk(KERN_INFO
+- "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
+- (unsigned) s->pBA0phys, (unsigned) s->pBA1phys));
+-
+-#ifndef NOT_CS4281_PM
+- s->pm.flags = CS4281_PM_IDLE;
+-#endif
+- temp1 = cs4281_hw_init(s);
+- if (temp1) {
+- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
+- "cs4281: cs4281_hw_init() failed. Skipping part.\n"));
+- goto err_irq;
+- }
+- s->magic = CS4281_MAGIC;
+- s->pcidev = pcidev;
+- s->irq = pcidev->irq;
+- if (request_irq
+- (s->irq, cs4281_interrupt, IRQF_SHARED, "Crystal CS4281", s)) {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+- printk(KERN_ERR "cs4281: irq %u in use\n", s->irq));
+- goto err_irq;
+- }
+- if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) <
+- 0) {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe() register_sound_dsp() failed.\n"));
+- goto err_dev1;
+- }
+- if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) <
+- 0) {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe() register_sound_mixer() failed.\n"));
+- goto err_dev2;
+- }
+- if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) {
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+- "cs4281: probe() register_sound_midi() failed.\n"));
+- goto err_dev3;
+- }
+-#ifndef NOT_CS4281_PM
+- cs4281_InitPM(s);
+- s->pm.flags |= CS4281_PM_NOT_REGISTERED;
+-#endif
+-
+- pci_set_master(pcidev); // enable bus mastering
+-
+- fs = get_fs();
+- set_fs(KERNEL_DS);
+- val = SOUND_MASK_LINE;
+- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val);
+- for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) {
+- val = initvol[i].vol;
+- mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val);
+- }
+- val = 1; // enable mic preamp
+- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val);
+- set_fs(fs);
+-
+- pci_set_drvdata(pcidev, s);
+- list_add(&s->list, &cs4281_devs);
+- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+- "cs4281: probe()- device allocated successfully\n"));
+- return 0;
+-
+- err_dev3:
+- unregister_sound_mixer(s->dev_mixer);
+- err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+- err_dev1:
+- free_irq(s->irq, s);
+- err_irq:
+- iounmap(s->pBA1);
+- err_unmap:
+- iounmap(s->pBA0);
+- err_free:
+- kfree(s);
+-
+- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
+- "cs4281: probe()- no device allocated\n"));
+- return -ENODEV;
+-} // probe_cs4281
+-
+-
+-// ---------------------------------------------------------------------
+-
+-static void __devexit cs4281_remove(struct pci_dev *pci_dev)
+-{
+- struct cs4281_state *s = pci_get_drvdata(pci_dev);
+- // stop DMA controller
+- synchronize_irq(s->irq);
+- free_irq(s->irq, s);
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->dev_mixer);
+- unregister_sound_midi(s->dev_midi);
+- iounmap(s->pBA1);
+- iounmap(s->pBA0);
+- pci_set_drvdata(pci_dev,NULL);
+- list_del(&s->list);
+- kfree(s);
+- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+- "cs4281: cs4281_remove()-: remove successful\n"));
+-}
+-
+-static struct pci_device_id cs4281_pci_tbl[] = {
+- {
+- .vendor = PCI_VENDOR_ID_CIRRUS,
+- .device = PCI_DEVICE_ID_CRYSTAL_CS4281,
+- .subvendor = PCI_ANY_ID,
+- .subdevice = PCI_ANY_ID,
+- },
+- { 0, },
+-};
+-
+-MODULE_DEVICE_TABLE(pci, cs4281_pci_tbl);
+-
+-static struct pci_driver cs4281_pci_driver = {
+- .name = "cs4281",
+- .id_table = cs4281_pci_tbl,
+- .probe = cs4281_probe,
+- .remove = __devexit_p(cs4281_remove),
+- .suspend = CS4281_SUSPEND_TBL,
+- .resume = CS4281_RESUME_TBL,
+-};
+-
+-static int __init cs4281_init_module(void)
+-{
+- int rtn = 0;
+- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+- "cs4281: cs4281_init_module()+ \n"));
+- printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
+- __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
+- CS4281_ARCH);
+- rtn = pci_register_driver(&cs4281_pci_driver);
+-
+- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn));
+- return rtn;
+-}
+-
+-static void __exit cs4281_cleanup_module(void)
+-{
+- pci_unregister_driver(&cs4281_pci_driver);
+- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+- printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n"));
+-}
+-// ---------------------------------------------------------------------
+-
+-MODULE_AUTHOR("gw boynton, audio at crystal.cirrus.com");
+-MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver");
+-MODULE_LICENSE("GPL");
+-
+-// ---------------------------------------------------------------------
+-
+-module_init(cs4281_init_module);
+-module_exit(cs4281_cleanup_module);
+-
+diff --git a/sound/oss/cs4281/cs4281pm-24.c b/sound/oss/cs4281/cs4281pm-24.c
+deleted file mode 100644
+index 90cbd76..0000000
+--- a/sound/oss/cs4281/cs4281pm-24.c
++++ /dev/null
+@@ -1,45 +0,0 @@
+-/*******************************************************************************
+-*
+-* "cs4281pm.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
+-*
+-* Copyright (C) 2000,2001 Cirrus Logic Corp.
+-* -- tom woller (twoller at crystal.cirrus.com) or
+-* (audio at crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+-*
+-* 12/22/00 trw - new file.
+-*
+-*******************************************************************************/
+-
+-#ifndef NOT_CS4281_PM
+-#include <linux/pm.h>
+-
+-static int cs4281_suspend(struct cs4281_state *s);
+-static int cs4281_resume(struct cs4281_state *s);
+-/*
+-* for now (12/22/00) only enable the pm_register PM support.
+-* allow these table entries to be null.
+-#define CS4281_SUSPEND_TBL cs4281_suspend_tbl
+-#define CS4281_RESUME_TBL cs4281_resume_tbl
+-*/
+-#define CS4281_SUSPEND_TBL cs4281_suspend_null
+-#define CS4281_RESUME_TBL cs4281_resume_null
+-
+-#else /* CS4281_PM */
+-#define CS4281_SUSPEND_TBL cs4281_suspend_null
+-#define CS4281_RESUME_TBL cs4281_resume_null
+-#endif /* CS4281_PM */
+-
+diff --git a/sound/oss/cs4281/cs4281pm.h b/sound/oss/cs4281/cs4281pm.h
+deleted file mode 100644
+index b44fdc9..0000000
+--- a/sound/oss/cs4281/cs4281pm.h
++++ /dev/null
+@@ -1,74 +0,0 @@
+-#ifndef NOT_CS4281_PM
+-/*******************************************************************************
+-*
+-* "cs4281pm.h" -- Cirrus Logic-Crystal CS4281 linux audio driver.
+-*
+-* Copyright (C) 2000,2001 Cirrus Logic Corp.
+-* -- tom woller (twoller at crystal.cirrus.com) or
+-* (audio at crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+-*
+-* 12/22/00 trw - new file.
+-*
+-*******************************************************************************/
+-/* general pm definitions */
+-#define CS4281_AC97_HIGHESTREGTORESTORE 0x26
+-#define CS4281_AC97_NUMBER_RESTORE_REGS (CS4281_AC97_HIGHESTREGTORESTORE/2-1)
+-
+-/* pipeline definitions */
+-#define CS4281_NUMBER_OF_PIPELINES 4
+-#define CS4281_PIPELINE_VALID 0x0001
+-#define CS4281_PLAYBACK_PIPELINE_NUMBER 0x0000
+-#define CS4281_CAPTURE_PIPELINE_NUMBER 0x0001
+-
+-/* PM state defintions */
+-#define CS4281_PM_NOT_REGISTERED 0x1000
+-#define CS4281_PM_IDLE 0x0001
+-#define CS4281_PM_SUSPENDING 0x0002
+-#define CS4281_PM_SUSPENDED 0x0004
+-#define CS4281_PM_RESUMING 0x0008
+-#define CS4281_PM_RESUMED 0x0010
+-
+-struct cs4281_pm {
+- unsigned long flags;
+- u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
+- u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
+- u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
+- u32 u32SSPM_BITS;
+- u32 ac97[CS4281_AC97_NUMBER_RESTORE_REGS];
+- u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
+- u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
+- u32 u32hwptr_playback,u32hwptr_capture;
+-};
+-
+-struct cs4281_pipeline {
+- unsigned flags;
+- unsigned number;
+- u32 u32DBAnValue,u32DBCnValue,u32DMRnValue,u32DCRnValue;
+- u32 u32DBAnAddress,u32DCAnAddress,u32DBCnAddress,u32DCCnAddress;
+- u32 u32DMRnAddress,u32DCRnAddress,u32HDSRnAddress;
+- u32 u32DBAn_Save,u32DBCn_Save,u32DMRn_Save,u32DCRn_Save;
+- u32 u32DCCn_Save,u32DCAn_Save;
+-/*
+-* technically, these are fifo variables, but just map the
+-* first fifo with the first pipeline and then use the fifo
+-* variables inside of the pipeline struct.
+-*/
+- u32 u32FCRn_Save,u32FSICn_Save;
+- u32 u32FCRnValue,u32FCRnAddress,u32FSICnValue,u32FSICnAddress;
+- u32 u32FPDRnValue,u32FPDRnAddress;
+-};
+-#endif
+diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
+index 5195bf9..6e3c41f 100644
+--- a/sound/oss/cs46xx.c
++++ b/sound/oss/cs46xx.c
+@@ -96,7 +96,7 @@
+ #include <asm/dma.h>
+ #include <asm/uaccess.h>
+
+-#include "cs46xxpm-24.h"
++#include "cs46xxpm.h"
+ #include "cs46xx_wrapper-24.h"
+ #include "cs461x.h"
+
+@@ -389,8 +389,10 @@ static int cs_hardware_init(struct cs_ca
+ static int cs46xx_powerup(struct cs_card *card, unsigned int type);
+ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
+ static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
++#ifdef CONFIG_PM
+ static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
+ static int cs46xx_resume_tbl(struct pci_dev *pcidev);
++#endif
+
+ #if CSDEBUG
+
+@@ -1611,7 +1613,7 @@ static void cs_handle_midi(struct cs_car
+ wake_up(&card->midi.owait);
+ }
+
+-static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t cs_interrupt(int irq, void *dev_id)
+ {
+ struct cs_card *card = (struct cs_card *)dev_id;
+ /* Single channel card */
+@@ -2980,7 +2982,7 @@ static void clkrun_hack(struct cs_card *
+
+ card->active+=change;
+
+- acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
++ acpi_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ if (acpi_dev == NULL)
+ return; /* Not a thinkpad thats for sure */
+
+@@ -3006,6 +3008,7 @@ static void clkrun_hack(struct cs_card *
+ change,card->active));
+ outw(control&~0x2000, port+0x10);
+ }
++ pci_dev_put(acpi_dev);
+ }
+
+
+@@ -5389,8 +5392,10 @@ static struct pci_driver cs46xx_pci_driv
+ .id_table = cs46xx_pci_tbl,
+ .probe = cs46xx_probe,
+ .remove = __devexit_p(cs46xx_remove),
+- .suspend = CS46XX_SUSPEND_TBL,
+- .resume = CS46XX_RESUME_TBL,
++#ifdef CONFIG_PM
++ .suspend = cs46xx_suspend_tbl,
++ .resume = cs46xx_resume_tbl,
++#endif
+ };
+
+ static int __init cs46xx_init_module(void)
+@@ -5420,7 +5425,7 @@ static void __exit cs46xx_cleanup_module
+ module_init(cs46xx_init_module);
+ module_exit(cs46xx_cleanup_module);
+
+-#if CS46XX_ACPI_SUPPORT
++#ifdef CONFIG_PM
+ static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
+ {
+ struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
+diff --git a/sound/oss/cs46xxpm-24.h b/sound/oss/cs46xxpm-24.h
+deleted file mode 100644
+index ad82db8..0000000
+--- a/sound/oss/cs46xxpm-24.h
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/*******************************************************************************
+-*
+-* "cs46xxpm-24.h" -- Cirrus Logic-Crystal CS46XX linux audio driver.
+-*
+-* Copyright (C) 2000,2001 Cirrus Logic Corp.
+-* -- tom woller (twoller at crystal.cirrus.com) or
+-* (pcaudio at crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+-*
+-* 12/22/00 trw - new file.
+-*
+-*******************************************************************************/
+-#ifndef __CS46XXPM24_H
+-#define __CS46XXPM24_H
+-
+-#include <linux/pm.h>
+-#include "cs46xxpm.h"
+-
+-
+-#define CS46XX_ACPI_SUPPORT 1
+-#ifdef CS46XX_ACPI_SUPPORT
+-/*
+-* for now (12/22/00) only enable the pm_register PM support.
+-* allow these table entries to be null.
+-*/
+-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
+-static int cs46xx_resume_tbl(struct pci_dev *pcidev);
+-#define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl
+-#define CS46XX_RESUME_TBL cs46xx_resume_tbl
+-#else
+-#define CS46XX_SUSPEND_TBL cs46xx_null
+-#define CS46XX_RESUME_TBL cs46xx_null
+-#endif
+-
+-#endif
+diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
+index f65a904..08274c9 100644
+--- a/sound/oss/dev_table.c
++++ b/sound/oss/dev_table.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/dev_table.c
++ * sound/oss/dev_table.c
+ *
+ * Device call tables.
+ *
+@@ -13,9 +13,39 @@
+
+ #include <linux/init.h>
+
+-#define _DEV_TABLE_C_
+ #include "sound_config.h"
+
++struct audio_operations *audio_devs[MAX_AUDIO_DEV];
++EXPORT_SYMBOL(audio_devs);
++
++int num_audiodevs;
++EXPORT_SYMBOL(num_audiodevs);
++
++struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
++EXPORT_SYMBOL(mixer_devs);
++
++int num_mixers;
++EXPORT_SYMBOL(num_mixers);
++
++struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
++EXPORT_SYMBOL(synth_devs);
++
++int num_synths;
++
++struct midi_operations *midi_devs[MAX_MIDI_DEV];
++EXPORT_SYMBOL(midi_devs);
++
++int num_midis;
++EXPORT_SYMBOL(num_midis);
++
++struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
++ &default_sound_timer, NULL
++};
++EXPORT_SYMBOL(sound_timer_devs);
++
++int num_sound_timers = 1;
++
++
+ static int sound_alloc_audiodev(void);
+
+ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
+@@ -75,6 +105,7 @@ int sound_install_audiodrv(int vers, cha
+ audio_init_devices();
+ return num;
+ }
++EXPORT_SYMBOL(sound_install_audiodrv);
+
+ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
+ int driver_size, void *devc)
+@@ -113,6 +144,7 @@ int sound_install_mixer(int vers, char *
+ mixer_devs[n] = op;
+ return n;
+ }
++EXPORT_SYMBOL(sound_install_mixer);
+
+ void sound_unload_audiodev(int dev)
+ {
+@@ -122,6 +154,7 @@ void sound_unload_audiodev(int dev)
+ unregister_sound_dsp((dev<<4)+3);
+ }
+ }
++EXPORT_SYMBOL(sound_unload_audiodev);
+
+ static int sound_alloc_audiodev(void)
+ {
+@@ -144,6 +177,7 @@ int sound_alloc_mididev(void)
+ num_midis = i + 1;
+ return i;
+ }
++EXPORT_SYMBOL(sound_alloc_mididev);
+
+ int sound_alloc_synthdev(void)
+ {
+@@ -158,6 +192,7 @@ int sound_alloc_synthdev(void)
+ }
+ return -1;
+ }
++EXPORT_SYMBOL(sound_alloc_synthdev);
+
+ int sound_alloc_mixerdev(void)
+ {
+@@ -169,6 +204,7 @@ int sound_alloc_mixerdev(void)
+ num_mixers = i + 1;
+ return i;
+ }
++EXPORT_SYMBOL(sound_alloc_mixerdev);
+
+ int sound_alloc_timerdev(void)
+ {
+@@ -183,6 +219,7 @@ int sound_alloc_timerdev(void)
+ }
+ return -1;
+ }
++EXPORT_SYMBOL(sound_alloc_timerdev);
+
+ void sound_unload_mixerdev(int dev)
+ {
+@@ -192,6 +229,7 @@ void sound_unload_mixerdev(int dev)
+ num_mixers--;
+ }
+ }
++EXPORT_SYMBOL(sound_unload_mixerdev);
+
+ void sound_unload_mididev(int dev)
+ {
+@@ -200,15 +238,19 @@ void sound_unload_mididev(int dev)
+ unregister_sound_midi((dev<<4)+2);
+ }
+ }
++EXPORT_SYMBOL(sound_unload_mididev);
+
+ void sound_unload_synthdev(int dev)
+ {
+ if (dev != -1)
+ synth_devs[dev] = NULL;
+ }
++EXPORT_SYMBOL(sound_unload_synthdev);
+
+ void sound_unload_timerdev(int dev)
+ {
+ if (dev != -1)
+ sound_timer_devs[dev] = NULL;
+ }
++EXPORT_SYMBOL(sound_unload_timerdev);
++
+diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h
+index adf1d62..b7617be 100644
+--- a/sound/oss/dev_table.h
++++ b/sound/oss/dev_table.h
+@@ -352,22 +352,8 @@ struct sound_timer_operations
+ void (*arm_timer)(int dev, long time);
+ };
+
+-#ifdef _DEV_TABLE_C_
+-struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+-int num_audiodevs;
+-struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+-int num_mixers;
+-struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
+-int num_synths;
+-struct midi_operations *midi_devs[MAX_MIDI_DEV];
+-int num_midis;
+-
+ extern struct sound_timer_operations default_sound_timer;
+-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
+- &default_sound_timer, NULL
+-};
+-int num_sound_timers = 1;
+-#else
++
+ extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+ extern int num_audiodevs;
+ extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+@@ -378,7 +364,6 @@ extern struct midi_operations *midi_devs
+ extern int num_midis;
+ extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV];
+ extern int num_sound_timers;
+-#endif /* _DEV_TABLE_C_ */
+
+ extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
+ void sound_timer_init (struct sound_lowlev_timer *t, char *name);
+diff --git a/sound/oss/dm.h b/sound/oss/dm.h
+deleted file mode 100644
+index 14a9059..0000000
+--- a/sound/oss/dm.h
++++ /dev/null
+@@ -1,79 +0,0 @@
+-#ifndef _DRIVERS_SOUND_DM_H
+-#define _DRIVERS_SOUND_DM_H
+-
+-/*
+- * Definitions of the 'direct midi sound' interface used
+- * by the newer commercial OSS package. We should export
+- * this to userland somewhere in glibc later.
+- */
+-
+-/*
+- * Data structure composing an FM "note" or sound event.
+- */
+-
+-struct dm_fm_voice
+-{
+- u8 op;
+- u8 voice;
+- u8 am;
+- u8 vibrato;
+- u8 do_sustain;
+- u8 kbd_scale;
+- u8 harmonic;
+- u8 scale_level;
+- u8 volume;
+- u8 attack;
+- u8 decay;
+- u8 sustain;
+- u8 release;
+- u8 feedback;
+- u8 connection;
+- u8 left;
+- u8 right;
+- u8 waveform;
+-};
+-
+-/*
+- * This describes an FM note by its voice, octave, frequency number (10bit)
+- * and key on/off.
+- */
+-
+-struct dm_fm_note
+-{
+- u8 voice;
+- u8 octave;
+- u32 fnum;
+- u8 key_on;
+-};
+-
+-/*
+- * FM parameters that apply globally to all voices, and thus are not "notes"
+- */
+-
+-struct dm_fm_params
+-{
+- u8 am_depth;
+- u8 vib_depth;
+- u8 kbd_split;
+- u8 rhythm;
+-
+- /* This block is the percussion instrument data */
+- u8 bass;
+- u8 snare;
+- u8 tomtom;
+- u8 cymbal;
+- u8 hihat;
+-};
+-
+-/*
+- * FM mode ioctl settings
+- */
+-
+-#define FM_IOCTL_RESET 0x20
+-#define FM_IOCTL_PLAY_NOTE 0x21
+-#define FM_IOCTL_SET_VOICE 0x22
+-#define FM_IOCTL_SET_PARAMS 0x23
+-#define FM_IOCTL_SET_MODE 0x24
+-#define FM_IOCTL_SET_OPL 0x25
+-
+-#endif
+diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
+index 15ce711..b256c04 100644
+--- a/sound/oss/dmabuf.c
++++ b/sound/oss/dmabuf.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/dmabuf.c
++ * sound/oss/dmabuf.c
+ *
+ * The DMA buffer manager for digitized voice applications
+ */
+@@ -926,6 +926,7 @@ int DMAbuf_start_dma(int dev, unsigned l
+ sound_start_dma(dmap, physaddr, count, dma_mode);
+ return count;
+ }
++EXPORT_SYMBOL(DMAbuf_start_dma);
+
+ static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode)
+ {
+@@ -1055,6 +1056,8 @@ void DMAbuf_outputintr(int dev, int noti
+ do_outputintr(dev, notify_only);
+ spin_unlock_irqrestore(&dmap->lock,flags);
+ }
++EXPORT_SYMBOL(DMAbuf_outputintr);
++
+ /* called with dmap->lock held in irq context */
+ static void do_inputintr(int dev)
+ {
+@@ -1154,36 +1157,7 @@ void DMAbuf_inputintr(int dev)
+ do_inputintr(dev);
+ spin_unlock_irqrestore(&dmap->lock,flags);
+ }
+-
+-int DMAbuf_open_dma(int dev)
+-{
+- /*
+- * NOTE! This routine opens only the primary DMA channel (output).
+- */
+- struct audio_operations *adev = audio_devs[dev];
+- int err;
+-
+- if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0)
+- return -EBUSY;
+- dma_init_buffers(adev->dmap_out);
+- adev->dmap_out->flags |= DMA_ALLOC_DONE;
+- adev->dmap_out->fragment_size = adev->dmap_out->buffsize;
+-
+- if (adev->dmap_out->dma >= 0) {
+- unsigned long flags;
+-
+- flags=claim_dma_lock();
+- clear_dma_ff(adev->dmap_out->dma);
+- disable_dma(adev->dmap_out->dma);
+- release_dma_lock(flags);
+- }
+- return 0;
+-}
+-
+-void DMAbuf_close_dma(int dev)
+-{
+- close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out);
+-}
++EXPORT_SYMBOL(DMAbuf_inputintr);
+
+ void DMAbuf_init(int dev, int dma1, int dma2)
+ {
+@@ -1192,12 +1166,6 @@ void DMAbuf_init(int dev, int dma1, int
+ * NOTE! This routine could be called several times.
+ */
+
+- /* drag in audio_syms.o */
+- {
+- extern char audio_syms_symbol;
+- audio_syms_symbol = 0;
+- }
+-
+ if (adev && adev->dmap_out == NULL) {
+ if (adev->d == NULL)
+ panic("OSS: audio_devs[%d]->d == NULL\n", dev);
+diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
+index dc31373..285239d 100644
+--- a/sound/oss/dmasound/dmasound_atari.c
++++ b/sound/oss/dmasound/dmasound_atari.c
+@@ -133,7 +133,7 @@ static int FalconSetFormat(int format);
+ static int FalconSetVolume(int volume);
+ static void AtaPlayNextFrame(int index);
+ static void AtaPlay(void);
+-static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t AtaInterrupt(int irq, void *dummy);
+
+ /*** Mid level stuff *********************************************************/
+
+@@ -1257,7 +1257,7 @@ static void AtaPlay(void)
+ }
+
+
+-static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t AtaInterrupt(int irq, void *dummy)
+ {
+ #if 0
+ /* ++TeSche: if you should want to test this... */
+diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
+index 4359903..37773b1 100644
+--- a/sound/oss/dmasound/dmasound_awacs.c
++++ b/sound/oss/dmasound/dmasound_awacs.c
+@@ -281,9 +281,9 @@ static int PMacSetFormat(int format);
+ static int PMacSetVolume(int volume);
+ static void PMacPlay(void);
+ static void PMacRecord(void);
+-static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+-static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
+-static irqreturn_t pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
++static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid);
++static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid);
++static irqreturn_t pmac_awacs_intr(int irq, void *devid);
+ static void awacs_write(int val);
+ static int awacs_get_volume(int reg, int lshift);
+ static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+@@ -347,8 +347,8 @@ int
+ setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
+ {
+ struct device_node *np;
+- u32* pp;
+-
++ const u32* pp;
++
+ np = find_devices("gpio");
+ if (!np)
+ return -ENODEV;
+@@ -356,7 +356,8 @@ setup_audio_gpio(const char *name, const
+ np = np->child;
+ while(np != 0) {
+ if (name) {
+- char *property = get_property(np,"audio-gpio",NULL);
++ const char *property =
++ get_property(np,"audio-gpio",NULL);
+ if (property != 0 && strcmp(property,name) == 0)
+ break;
+ } else if (compatible && device_is_compatible(np, compatible))
+@@ -365,11 +366,11 @@ setup_audio_gpio(const char *name, const
+ }
+ if (!np)
+ return -ENODEV;
+- pp = (u32 *)get_property(np, "AAPL,address", NULL);
++ pp = get_property(np, "AAPL,address", NULL);
+ if (!pp)
+ return -ENODEV;
+ *gpio_addr = (*pp) & 0x0000ffff;
+- pp = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
++ pp = get_property(np, "audio-gpio-active-state", NULL);
+ if (pp)
+ *gpio_pol = *pp;
+ else
+@@ -397,7 +398,7 @@ read_audio_gpio(int gpio_addr)
+ * Headphone interrupt via GPIO (Tumbler, Snapper, DACA)
+ */
+ static irqreturn_t
+-headphone_intr(int irq, void *devid, struct pt_regs *regs)
++headphone_intr(int irq, void *devid)
+ {
+ unsigned long flags;
+
+@@ -464,7 +465,7 @@ tas_dmasound_init(void)
+ val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0);
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80);
+ /* Trigger it */
+- headphone_intr(0,NULL,NULL);
++ headphone_intr(0, NULL);
+ }
+ }
+ if (!gpio_headphone_irq) {
+@@ -1036,7 +1037,7 @@ static void PMacRecord(void)
+ */
+
+ static irqreturn_t
+-pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
++pmac_awacs_tx_intr(int irq, void *devid)
+ {
+ int i = write_sq.front;
+ int stat;
+@@ -1128,7 +1129,7 @@ printk("dmasound_pmac: tx-irq: xfer died
+
+
+ static irqreturn_t
+-pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
++pmac_awacs_rx_intr(int irq, void *devid)
+ {
+ int stat ;
+ /* For some reason on my PowerBook G3, I get one interrupt
+@@ -1211,7 +1212,7 @@ printk("dmasound_pmac: rx-irq: DIED - at
+
+
+ static irqreturn_t
+-pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
++pmac_awacs_intr(int irq, void *devid)
+ {
+ int ctrl;
+ int status;
+@@ -1498,7 +1499,7 @@ static int awacs_sleep_notify(struct pmu
+ write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);
+ msleep(150);
+ tas_leave_sleep(); /* Stub for now */
+- headphone_intr(0,NULL,NULL);
++ headphone_intr(0, NULL);
+ break;
+ case AWACS_DACA:
+ msleep(10); /* Check this !!! */
+diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
+index 68e1d8f..90fc058 100644
+--- a/sound/oss/dmasound/dmasound_paula.c
++++ b/sound/oss/dmasound/dmasound_paula.c
+@@ -82,7 +82,7 @@ static int AmiSetVolume(int volume);
+ static int AmiSetTreble(int treble);
+ static void AmiPlayNextFrame(int index);
+ static void AmiPlay(void);
+-static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t AmiInterrupt(int irq, void *dummy);
+
+ #ifdef CONFIG_HEARTBEAT
+
+@@ -556,7 +556,7 @@ static void AmiPlay(void)
+ }
+
+
+-static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t AmiInterrupt(int irq, void *dummy)
+ {
+ int minframes = 1;
+
+diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
+index e2081f3..b3379dd 100644
+--- a/sound/oss/dmasound/dmasound_q40.c
++++ b/sound/oss/dmasound/dmasound_q40.c
+@@ -48,8 +48,8 @@ static int Q40SetFormat(int format);
+ static int Q40SetVolume(int volume);
+ static void Q40PlayNextFrame(int index);
+ static void Q40Play(void);
+-static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+-static irqreturn_t Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp);
++static irqreturn_t Q40StereoInterrupt(int irq, void *dummy);
++static irqreturn_t Q40MonoInterrupt(int irq, void *dummy);
+ static void Q40Interrupt(void);
+
+
+@@ -451,7 +451,7 @@ static void Q40Play(void)
+ spin_unlock_irqrestore(&dmasound.lock, flags);
+ }
+
+-static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t Q40StereoInterrupt(int irq, void *dummy)
+ {
+ spin_lock(&dmasound.lock);
+ if (q40_sc>1){
+@@ -463,7 +463,7 @@ static irqreturn_t Q40StereoInterrupt(in
+ spin_unlock(&dmasound.lock);
+ return IRQ_HANDLED;
+ }
+-static irqreturn_t Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
++static irqreturn_t Q40MonoInterrupt(int irq, void *dummy)
+ {
+ spin_lock(&dmasound.lock);
+ if (q40_sc>0){
+diff --git a/sound/oss/emu10k1/irqmgr.c b/sound/oss/emu10k1/irqmgr.c
+index d19b464..fb2ce63 100644
+--- a/sound/oss/emu10k1/irqmgr.c
++++ b/sound/oss/emu10k1/irqmgr.c
+@@ -37,7 +37,7 @@
+
+ /* Interrupt handler */
+
+-irqreturn_t emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t emu10k1_interrupt(int irq, void *dev_id)
+ {
+ struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
+ u32 irqstatus, irqstatus_tmp;
+diff --git a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c
+index c4ce94d..6c59df7 100644
+--- a/sound/oss/emu10k1/main.c
++++ b/sound/oss/emu10k1/main.c
+@@ -167,7 +167,7 @@ extern struct file_operations emu10k1_mi
+ static struct midi_operations emu10k1_midi_operations;
+ #endif
+
+-extern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s);
++extern irqreturn_t emu10k1_interrupt(int, void *);
+
+ static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
+ {
+diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
+deleted file mode 100644
+index 13f4831..0000000
+--- a/sound/oss/es1370.c
++++ /dev/null
+@@ -1,2819 +0,0 @@
+-/*****************************************************************************/
+-
+-/*
+- * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
+- *
+- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer at alumni.ethz.ch)
+- *
+- * 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.
+- *
+- * Special thanks to David C. Niemi
+- *
+- *
+- * Module command line parameters:
+- * lineout if 1 the LINE jack is used as an output instead of an input.
+- * LINE then contains the unmixed dsp output. This can be used
+- * to make the card a four channel one: use dsp to output two
+- * channels to LINE and dac to output the other two channels to
+- * SPKR. Set the mixer to only output synth to SPKR.
+- * micbias sets the +5V bias to the mic if using an electretmic.
+- *
+- *
+- * Note: sync mode is not yet supported (i.e. running dsp and dac from the same
+- * clock source)
+- *
+- * Supported devices:
+- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+- * /dev/dsp1 additional DAC, like /dev/dsp, but output only,
+- * only 5512, 11025, 22050 and 44100 samples/s,
+- * outputs to mixer "SYNTH" setting
+- * /dev/midi simple MIDI UART interface, no ioctl
+- *
+- * NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed
+- * to be done in software. That is what /dev/dac is for. By now (Q2 1998)
+- * there are several MIDI to PCM (WAV) packages, one of them is timidity.
+- *
+- * Revision history
+- * 26.03.1998 0.1 Initial release
+- * 31.03.1998 0.2 Fix bug in GETOSPACE
+- * 04.04.1998 0.3 Make it work (again) under 2.0.33
+- * Fix mixer write operation not returning the actual
+- * settings
+- * 05.04.1998 0.4 First attempt at using the new PCI stuff
+- * 29.04.1998 0.5 Fix hang when ^C is pressed on amp
+- * 07.05.1998 0.6 Don't double lock around stop_*() in *_release()
+- * 10.05.1998 0.7 First stab at a simple midi interface (no bells&whistles)
+- * 14.05.1998 0.8 Don't allow excessive interrupt rates
+- * 08.06.1998 0.9 First release using Alan Cox' soundcore instead of
+- * miscdevice
+- * 05.07.1998 0.10 Fixed the driver to correctly maintin OSS style volume
+- * settings (not sure if this should be standard)
+- * Fixed many references: f_flags should be f_mode
+- * -- Gerald Britton <gbritton at mit.edu>
+- * 03.08.1998 0.11 Now mixer behaviour can basically be selected between
+- * "OSS documented" and "OSS actual" behaviour
+- * Fixed mixer table thanks to Hakan.Lennestal at lu.erisoft.se
+- * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
+- * as it produces an annoying ssssh in the lower sampling rate
+- * Do not include modversions.h
+- * 22.08.1998 0.12 Mixer registers actually have 5 instead of 4 bits
+- * pointed out by Itai Nahshon
+- * 31.08.1998 0.13 Fix realplayer problems - dac.count issues
+- * 08.10.1998 0.14 Joystick support fixed
+- * -- Oliver Neukum <c188 at org.chemie.uni-muenchen.de>
+- * 10.12.1998 0.15 Fix drain_dac trying to wait on not yet initialized DMA
+- * 16.12.1998 0.16 Don't wake up app until there are fragsize bytes to read/write
+- * 06.01.1999 0.17 remove the silly SA_INTERRUPT flag.
+- * hopefully killed the egcs section type conflict
+- * 12.03.1999 0.18 cinfo.blocks should be reset after GETxPTR ioctl.
+- * reported by Johan Maes <joma at telindus.be>
+- * 22.03.1999 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK
+- * read/write cannot be executed
+- * 07.04.1999 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+- * Alpha fixes reported by Peter Jones <pjones at redhat.com>
+- * Note: joystick address handling might still be wrong on archs
+- * other than i386
+- * 10.05.1999 0.21 Added support for an electret mic for SB PCI64
+- * to the Linux kernel sound driver. This mod also straighten
+- * out the question marks around the mic impedance setting
+- * (micz). From Kim.Berts at fisub.mail.abb.com
+- * 11.05.1999 0.22 Implemented the IMIX call to mute recording monitor.
+- * Guenter Geiger <geiger at epy.co.at>
+- * 15.06.1999 0.23 Fix bad allocation bug.
+- * Thanks to Deti Fliegl <fliegl at in.tum.de>
+- * 28.06.1999 0.24 Add pci_set_master
+- * 02.08.1999 0.25 Added workaround for the "phantom write" bug first
+- * documented by Dave Sharpless from Anchor Games
+- * 03.08.1999 0.26 adapt to Linus' new __setup/__initcall
+- * added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+- * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
+- * 12.08.1999 0.27 module_init/__setup fixes
+- * 19.08.1999 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca at mail.tiscalinet.it>
+- * 31.08.1999 0.29 add spin_lock_init
+- * replaced current->state = x with set_current_state(x)
+- * 03.09.1999 0.30 change read semantics for MIDI to match
+- * OSS more closely; remove possible wakeup race
+- * 28.10.1999 0.31 More waitqueue races fixed
+- * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun;
+- * Tim Janik's BSE (Bedevilled Sound Engine) found this
+- * 07.02.2000 0.33 Use pci_alloc_consistent and pci_register_driver
+- * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+- * 12.12.2000 0.35 More dma buffer initializations, patch from
+- * Tjeerd Mulder <tjeerd.mulder at fujitsu-siemens.com>
+- * 07.01.2001 0.36 Timeout change in wrcodec as requested by Frank Klemm <pfk at fuchs.offl.uni-jena.de>
+- * 31.01.2001 0.37 Register/Unregister gameport
+- * Fix SETTRIGGER non OSS API conformity
+- * 03.01.2003 0.38 open_mode fixes from Georg Acher <acher at in.tum.de>
+- *
+- * some important things missing in Ensoniq documentation:
+- *
+- * Experimental PCLKDIV results: play the same waveforms on both DAC1 and DAC2
+- * and vary PCLKDIV to obtain zero beat.
+- * 5512sps: 254
+- * 44100sps: 30
+- * seems to be fs = 1411200/(PCLKDIV+2)
+- *
+- * should find out when curr_sample_ct is cleared and
+- * where exactly the CCB fetches data
+- *
+- * The card uses a 22.5792 MHz crystal.
+- * The LINEIN jack may be converted to an AOUT jack by
+- * setting pin 47 (XCTL0) of the ES1370 to high.
+- * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic
+- *
+- *
+- */
+-
+-/*****************************************************************************/
+-
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/smp_lock.h>
+-#include <linux/init.h>
+-#include <linux/poll.h>
+-#include <linux/spinlock.h>
+-#include <linux/gameport.h>
+-#include <linux/wait.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/mutex.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
+-#define DBG(x) {}
+-/*#define DBG(x) {x}*/
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef PCI_VENDOR_ID_ENSONIQ
+-#define PCI_VENDOR_ID_ENSONIQ 0x1274
+-#endif
+-
+-#ifndef PCI_DEVICE_ID_ENSONIQ_ES1370
+-#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
+-#endif
+-
+-#define ES1370_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1370)
+-
+-#define ES1370_EXTENT 0x40
+-#define JOY_EXTENT 8
+-
+-#define ES1370_REG_CONTROL 0x00
+-#define ES1370_REG_STATUS 0x04
+-#define ES1370_REG_UART_DATA 0x08
+-#define ES1370_REG_UART_STATUS 0x09
+-#define ES1370_REG_UART_CONTROL 0x09
+-#define ES1370_REG_UART_TEST 0x0a
+-#define ES1370_REG_MEMPAGE 0x0c
+-#define ES1370_REG_CODEC 0x10
+-#define ES1370_REG_SERIAL_CONTROL 0x20
+-#define ES1370_REG_DAC1_SCOUNT 0x24
+-#define ES1370_REG_DAC2_SCOUNT 0x28
+-#define ES1370_REG_ADC_SCOUNT 0x2c
+-
+-#define ES1370_REG_DAC1_FRAMEADR 0xc30
+-#define ES1370_REG_DAC1_FRAMECNT 0xc34
+-#define ES1370_REG_DAC2_FRAMEADR 0xc38
+-#define ES1370_REG_DAC2_FRAMECNT 0xc3c
+-#define ES1370_REG_ADC_FRAMEADR 0xd30
+-#define ES1370_REG_ADC_FRAMECNT 0xd34
+-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
+-
+-#define ES1370_FMT_U8_MONO 0
+-#define ES1370_FMT_U8_STEREO 1
+-#define ES1370_FMT_S16_MONO 2
+-#define ES1370_FMT_S16_STEREO 3
+-#define ES1370_FMT_STEREO 1
+-#define ES1370_FMT_S16 2
+-#define ES1370_FMT_MASK 3
+-
+-static const unsigned sample_size[] = { 1, 2, 2, 4 };
+-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+-
+-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
+-
+-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
+-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
+-
+-#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
+-#define CTRL_XCTL1 0x40000000 /* electret mic bias */
+-#define CTRL_OPEN 0x20000000 /* no function, can be read and written */
+-#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
+-#define CTRL_SH_PCLKDIV 16
+-#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
+-#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
+-#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
+-#define CTRL_SH_WTSRSEL 12
+-#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
+-#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
+-#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */
+-#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
+-#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
+-#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
+-#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
+-#define CTRL_ADC_EN 0x00000010 /* enable ADC */
+-#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
+-#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */
+-#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
+-#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
+-
+-#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
+-#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */
+-#define STAT_CBUSY 0x00000200 /* 1 = codec busy */
+-#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
+-#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
+-#define STAT_SH_VC 5
+-#define STAT_MCCB 0x00000010 /* CCB int pending */
+-#define STAT_UART 0x00000008 /* UART int pending */
+-#define STAT_DAC1 0x00000004 /* DAC1 int pending */
+-#define STAT_DAC2 0x00000002 /* DAC2 int pending */
+-#define STAT_ADC 0x00000001 /* ADC int pending */
+-
+-#define USTAT_RXINT 0x80 /* UART rx int pending */
+-#define USTAT_TXINT 0x04 /* UART tx int pending */
+-#define USTAT_TXRDY 0x02 /* UART tx ready */
+-#define USTAT_RXRDY 0x01 /* UART rx ready */
+-
+-#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */
+-#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */
+-#define UCTRL_ENA_TXINT 0x20 /* enable TX int */
+-#define UCTRL_CNTRL 0x03 /* control field */
+-#define UCTRL_CNTRL_SWR 0x03 /* software reset command */
+-
+-#define SCTRL_P2ENDINC 0x00380000 /* */
+-#define SCTRL_SH_P2ENDINC 19
+-#define SCTRL_P2STINC 0x00070000 /* */
+-#define SCTRL_SH_P2STINC 16
+-#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
+-#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
+-#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
+-#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
+-#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
+-#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
+-#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
+-#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
+-#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */
+-#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */
+-#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
+-#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
+-#define SCTRL_R1FMT 0x00000030 /* format mask */
+-#define SCTRL_SH_R1FMT 4
+-#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
+-#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
+-#define SCTRL_P2FMT 0x0000000c /* format mask */
+-#define SCTRL_SH_P2FMT 2
+-#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
+-#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
+-#define SCTRL_P1FMT 0x00000003 /* format mask */
+-#define SCTRL_SH_P1FMT 0
+-
+-/* misc stuff */
+-
+-#define FMODE_DAC 4 /* slight misuse of mode_t */
+-
+-/* MIDI buffer sizes */
+-
+-#define MIDIINBUF 256
+-#define MIDIOUTBUF 256
+-
+-#define FMODE_MIDI_SHIFT 3
+-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
+-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+-
+-/* --------------------------------------------------------------------- */
+-
+-struct es1370_state {
+- /* magic */
+- unsigned int magic;
+-
+- /* list of es1370 devices */
+- struct list_head devs;
+-
+- /* the corresponding pci_dev structure */
+- struct pci_dev *dev;
+-
+- /* soundcore stuff */
+- int dev_audio;
+- int dev_mixer;
+- int dev_dac;
+- int dev_midi;
+-
+- /* hardware resources */
+- unsigned long io; /* long for SPARC */
+- unsigned int irq;
+-
+- /* mixer registers; there is no HW readback */
+- struct {
+- unsigned short vol[10];
+- unsigned int recsrc;
+- unsigned int modcnt;
+- unsigned short micpreamp;
+- unsigned int imix;
+- } mix;
+-
+- /* wave stuff */
+- unsigned ctrl;
+- unsigned sctrl;
+-
+- spinlock_t lock;
+- struct mutex open_mutex;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+-
+- struct dmabuf {
+- void *rawbuf;
+- dma_addr_t dmaaddr;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- unsigned hwptr, swptr;
+- unsigned total_bytes;
+- int count;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize;
+- unsigned fragsamples;
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned endcleared:1;
+- unsigned enabled:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac1, dma_dac2, dma_adc;
+-
+- /* The following buffer is used to point the phantom write channel to. */
+- unsigned char *bugbuf_cpu;
+- dma_addr_t bugbuf_dma;
+-
+- /* midi stuff */
+- struct {
+- unsigned ird, iwr, icnt;
+- unsigned ord, owr, ocnt;
+- wait_queue_head_t iwait;
+- wait_queue_head_t owait;
+- unsigned char ibuf[MIDIINBUF];
+- unsigned char obuf[MIDIOUTBUF];
+- } midi;
+-
+-#ifdef SUPPORT_JOYSTICK
+- struct gameport *gameport;
+-#endif
+-
+- struct mutex mutex;
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static LIST_HEAD(devs);
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline unsigned ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data)
+-{
+- unsigned long tmo = jiffies + HZ/10, j;
+-
+- do {
+- j = jiffies;
+- if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) {
+- outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC);
+- return;
+- }
+- schedule();
+- } while ((signed)(tmo-j) > 0);
+- printk(KERN_ERR "es1370: write to codec register timeout\n");
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline void stop_adc(struct es1370_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->ctrl &= ~CTRL_ADC_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static inline void stop_dac1(struct es1370_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->ctrl &= ~CTRL_DAC1_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static inline void stop_dac2(struct es1370_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->ctrl &= ~CTRL_DAC2_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_dac1(struct es1370_state *s)
+-{
+- unsigned long flags;
+- unsigned fragremain, fshift;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0)
+- && s->dma_dac1.ready) {
+- s->ctrl |= CTRL_DAC1_EN;
+- s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1));
+- fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
+- if (fragremain < 2*fshift)
+- fragremain = s->dma_dac1.fragsize;
+- outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_dac2(struct es1370_state *s)
+-{
+- unsigned long flags;
+- unsigned fragremain, fshift;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0)
+- && s->dma_dac2.ready) {
+- s->ctrl |= CTRL_DAC2_EN;
+- s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN |
+- SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN |
+- (((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) |
+- (0 << SCTRL_SH_P2STINC);
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1));
+- fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
+- if (fragremain < 2*fshift)
+- fragremain = s->dma_dac2.fragsize;
+- outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_adc(struct es1370_state *s)
+-{
+- unsigned long flags;
+- unsigned fragremain, fshift;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+- && s->dma_adc.ready) {
+- s->ctrl |= CTRL_ADC_EN;
+- s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1));
+- fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT];
+- if (fragremain < 2*fshift)
+- fragremain = s->dma_adc.fragsize;
+- outl((fragremain >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-static inline void dealloc_dmabuf(struct es1370_state *s, struct dmabuf *db)
+-{
+- struct page *page, *pend;
+-
+- if (db->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
+- }
+- db->rawbuf = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg)
+-{
+- int order;
+- unsigned bytepersec;
+- unsigned bufs;
+- struct page *page, *pend;
+-
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
+- break;
+- if (!db->rawbuf)
+- return -ENOMEM;
+- db->buforder = order;
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- }
+- fmt &= ES1370_FMT_MASK;
+- bytepersec = rate << sample_shift[fmt];
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytepersec)
+- db->fragshift = ld2(bytepersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- db->fragsamples = db->fragsize >> sample_shift[fmt];
+- db->dmasize = db->numfrag << db->fragshift;
+- memset(db->rawbuf, (fmt & ES1370_FMT_S16) ? 0 : 0x80, db->dmasize);
+- outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+- outl(db->dmaaddr, s->io+(reg & 0xff));
+- outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
+- db->enabled = 1;
+- db->ready = 1;
+- return 0;
+-}
+-
+-static inline int prog_dmabuf_adc(struct es1370_state *s)
+-{
+- stop_adc(s);
+- return prog_dmabuf(s, &s->dma_adc, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
+- (s->sctrl >> SCTRL_SH_R1FMT) & ES1370_FMT_MASK, ES1370_REG_ADC_FRAMEADR);
+-}
+-
+-static inline int prog_dmabuf_dac2(struct es1370_state *s)
+-{
+- stop_dac2(s);
+- return prog_dmabuf(s, &s->dma_dac2, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
+- (s->sctrl >> SCTRL_SH_P2FMT) & ES1370_FMT_MASK, ES1370_REG_DAC2_FRAMEADR);
+-}
+-
+-static inline int prog_dmabuf_dac1(struct es1370_state *s)
+-{
+- stop_dac1(s);
+- return prog_dmabuf(s, &s->dma_dac1, dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
+- (s->sctrl >> SCTRL_SH_P1FMT) & ES1370_FMT_MASK, ES1370_REG_DAC1_FRAMEADR);
+-}
+-
+-static inline unsigned get_hwptr(struct es1370_state *s, struct dmabuf *db, unsigned reg)
+-{
+- unsigned hwptr, diff;
+-
+- outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+- hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc;
+- diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize;
+- db->hwptr = hwptr;
+- return diff;
+-}
+-
+-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
+-{
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(((char *)buf) + bptr, c, x);
+- bptr = 0;
+- len -= x;
+- }
+- memset(((char *)buf) + bptr, c, len);
+-}
+-
+-/* call with spinlock held! */
+-static void es1370_update_ptr(struct es1370_state *s)
+-{
+- int diff;
+-
+- /* update ADC pointer */
+- if (s->ctrl & CTRL_ADC_EN) {
+- diff = get_hwptr(s, &s->dma_adc, ES1370_REG_ADC_FRAMECNT);
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- wake_up(&s->dma_adc.wait);
+- if (!s->dma_adc.mapped) {
+- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+- s->ctrl &= ~CTRL_ADC_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- s->dma_adc.error++;
+- }
+- }
+- }
+- /* update DAC1 pointer */
+- if (s->ctrl & CTRL_DAC1_EN) {
+- diff = get_hwptr(s, &s->dma_dac1, ES1370_REG_DAC1_FRAMECNT);
+- s->dma_dac1.total_bytes += diff;
+- if (s->dma_dac1.mapped) {
+- s->dma_dac1.count += diff;
+- if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
+- wake_up(&s->dma_dac1.wait);
+- } else {
+- s->dma_dac1.count -= diff;
+- if (s->dma_dac1.count <= 0) {
+- s->ctrl &= ~CTRL_DAC1_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- s->dma_dac1.error++;
+- } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) {
+- clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr,
+- s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80);
+- s->dma_dac1.endcleared = 1;
+- }
+- if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize)
+- wake_up(&s->dma_dac1.wait);
+- }
+- }
+- /* update DAC2 pointer */
+- if (s->ctrl & CTRL_DAC2_EN) {
+- diff = get_hwptr(s, &s->dma_dac2, ES1370_REG_DAC2_FRAMECNT);
+- s->dma_dac2.total_bytes += diff;
+- if (s->dma_dac2.mapped) {
+- s->dma_dac2.count += diff;
+- if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
+- wake_up(&s->dma_dac2.wait);
+- } else {
+- s->dma_dac2.count -= diff;
+- if (s->dma_dac2.count <= 0) {
+- s->ctrl &= ~CTRL_DAC2_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- s->dma_dac2.error++;
+- } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) {
+- clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr,
+- s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80);
+- s->dma_dac2.endcleared = 1;
+- }
+- if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize)
+- wake_up(&s->dma_dac2.wait);
+- }
+- }
+-}
+-
+-/* hold spinlock for the following! */
+-static void es1370_handle_midi(struct es1370_state *s)
+-{
+- unsigned char ch;
+- int wake;
+-
+- if (!(s->ctrl & CTRL_UART_EN))
+- return;
+- wake = 0;
+- while (inb(s->io+ES1370_REG_UART_STATUS) & USTAT_RXRDY) {
+- ch = inb(s->io+ES1370_REG_UART_DATA);
+- if (s->midi.icnt < MIDIINBUF) {
+- s->midi.ibuf[s->midi.iwr] = ch;
+- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+- s->midi.icnt++;
+- }
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.iwait);
+- wake = 0;
+- while ((inb(s->io+ES1370_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) {
+- outb(s->midi.obuf[s->midi.ord], s->io+ES1370_REG_UART_DATA);
+- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+- s->midi.ocnt--;
+- if (s->midi.ocnt < MIDIOUTBUF-16)
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.owait);
+- outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1370_REG_UART_CONTROL);
+-}
+-
+-static irqreturn_t es1370_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct es1370_state *s = (struct es1370_state *)dev_id;
+- unsigned int intsrc, sctl;
+-
+- /* fastpath out, to ease interrupt sharing */
+- intsrc = inl(s->io+ES1370_REG_STATUS);
+- if (!(intsrc & 0x80000000))
+- return IRQ_NONE;
+- spin_lock(&s->lock);
+- /* clear audio interrupts first */
+- sctl = s->sctrl;
+- if (intsrc & STAT_ADC)
+- sctl &= ~SCTRL_R1INTEN;
+- if (intsrc & STAT_DAC1)
+- sctl &= ~SCTRL_P1INTEN;
+- if (intsrc & STAT_DAC2)
+- sctl &= ~SCTRL_P2INTEN;
+- outl(sctl, s->io+ES1370_REG_SERIAL_CONTROL);
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- es1370_update_ptr(s);
+- es1370_handle_midi(s);
+- spin_unlock(&s->lock);
+- return IRQ_HANDLED;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT "es1370: invalid magic value\n";
+-
+-#define VALIDATE_STATE(s) \
+-({ \
+- if (!(s) || (s)->magic != ES1370_MAGIC) { \
+- printk(invalid_magic); \
+- return -ENXIO; \
+- } \
+-})
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const struct {
+- unsigned volidx:4;
+- unsigned left:4;
+- unsigned right:4;
+- unsigned stereo:1;
+- unsigned recmask:13;
+- unsigned avail:1;
+-} mixtable[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 }, /* master */
+- [SOUND_MIXER_PCM] = { 1, 0x2, 0x3, 1, 0x0400, 1 }, /* voice */
+- [SOUND_MIXER_SYNTH] = { 2, 0x4, 0x5, 1, 0x0060, 1 }, /* FM */
+- [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, /* CD */
+- [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, /* Line */
+- [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, /* AUX */
+- [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, /* Mono1 */
+- [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, /* Mono2 */
+- [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, /* Mic */
+- [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */
+-};
+-
+-static void set_recsrc(struct es1370_state *s, unsigned int val)
+-{
+- unsigned int i, j;
+-
+- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if (!(val & (1 << i)))
+- continue;
+- if (!mixtable[i].recmask) {
+- val &= ~(1 << i);
+- continue;
+- }
+- j |= mixtable[i].recmask;
+- }
+- s->mix.recsrc = val;
+- wrcodec(s, 0x12, j & 0xd5);
+- wrcodec(s, 0x13, j & 0xaa);
+- wrcodec(s, 0x14, (j >> 8) & 0x17);
+- wrcodec(s, 0x15, (j >> 8) & 0x0f);
+- i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
+- if (!s->mix.imix) {
+- i &= 0xff60; /* mute record and line monitor */
+- }
+- wrcodec(s, 0x10, i);
+- wrcodec(s, 0x11, i >> 8);
+-}
+-
+-static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
+-{
+- unsigned long flags;
+- int i, val;
+- unsigned char l, r, rl, rr;
+- int __user *p = (int __user *)arg;
+-
+- VALIDATE_STATE(s);
+- if (cmd == SOUND_MIXER_PRIVATE1) {
+- /* enable/disable/query mixer preamp */
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != -1) {
+- s->mix.micpreamp = !!val;
+- wrcodec(s, 0x19, s->mix.micpreamp);
+- }
+- return put_user(s->mix.micpreamp, p);
+- }
+- if (cmd == SOUND_MIXER_PRIVATE2) {
+- /* enable/disable/query use of linein as second lineout */
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != -1) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (val)
+- s->ctrl |= CTRL_XCTL0;
+- else
+- s->ctrl &= ~CTRL_XCTL0;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, p);
+- }
+- if (cmd == SOUND_MIXER_PRIVATE3) {
+- /* enable/disable/query microphone impedance setting */
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != -1) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (val)
+- s->ctrl |= CTRL_XCTL1;
+- else
+- s->ctrl &= ~CTRL_XCTL1;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, p);
+- }
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- strncpy(info.id, "ES1370", sizeof(info.id));
+- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
+- info.modify_counter = s->mix.modcnt;
+- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == SOUND_OLD_MIXER_INFO) {
+- _old_mixer_info info;
+- strncpy(info.id, "ES1370", sizeof(info.id));
+- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
+- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, p);
+- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+- return -EINVAL;
+- if (_SIOC_DIR(cmd) == _SIOC_READ) {
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- return put_user(s->mix.recsrc, p);
+-
+- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+- val = SOUND_MASK_IMIX;
+- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].avail)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].recmask)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].stereo)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_CAPS:
+- return put_user(0, p);
+-
+- case SOUND_MIXER_IMIX:
+- return put_user(s->mix.imix, p);
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
+- return -EINVAL;
+- return put_user(s->mix.vol[mixtable[i].volidx], p);
+- }
+- }
+- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
+- return -EINVAL;
+- s->mix.modcnt++;
+- switch (_IOC_NR(cmd)) {
+-
+- case SOUND_MIXER_IMIX:
+- if (get_user(s->mix.imix, p))
+- return -EFAULT;
+- set_recsrc(s, s->mix.recsrc);
+- return 0;
+-
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- if (get_user(val, p))
+- return -EFAULT;
+- set_recsrc(s, val);
+- return 0;
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- if (mixtable[i].stereo) {
+- r = (val >> 8) & 0xff;
+- if (r > 100)
+- r = 100;
+- if (l < 7) {
+- rl = 0x80;
+- l = 0;
+- } else {
+- rl = 31 - ((l - 7) / 3);
+- l = (31 - rl) * 3 + 7;
+- }
+- if (r < 7) {
+- rr = 0x80;
+- r = 0;
+- } else {
+- rr = 31 - ((r - 7) / 3);
+- r = (31 - rr) * 3 + 7;
+- }
+- wrcodec(s, mixtable[i].right, rr);
+- } else {
+- if (mixtable[i].left == 15) {
+- if (l < 2) {
+- rr = rl = 0x80;
+- r = l = 0;
+- } else {
+- rl = 7 - ((l - 2) / 14);
+- r = l = (7 - rl) * 14 + 2;
+- }
+- } else {
+- if (l < 7) {
+- rl = 0x80;
+- r = l = 0;
+- } else {
+- rl = 31 - ((l - 7) / 3);
+- r = l = (31 - rl) * 3 + 7;
+- }
+- }
+- }
+- wrcodec(s, mixtable[i].left, rl);
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l;
+-#else
+- s->mix.vol[mixtable[i].volidx] = val;
+-#endif
+- return put_user(s->mix.vol[mixtable[i].volidx], p);
+- }
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int es1370_open_mixdev(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct list_head *list;
+- struct es1370_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct es1370_state, devs);
+- if (s->dev_mixer == minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int es1370_release_mixdev(struct inode *inode, struct file *file)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- return 0;
+-}
+-
+-static int es1370_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- return mixer_ioctl((struct es1370_state *)file->private_data, cmd, arg);
+-}
+-
+-static /*const*/ struct file_operations es1370_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = es1370_ioctl_mixdev,
+- .open = es1370_open_mixdev,
+- .release = es1370_release_mixdev,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac1(struct es1370_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count, tmo;
+-
+- if (s->dma_dac1.mapped || !s->dma_dac1.ready)
+- return 0;
+- add_wait_queue(&s->dma_dac1.wait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac1.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac1.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return -EBUSY;
+- }
+- tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
+- / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+- tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
+- if (!schedule_timeout(tmo + 1))
+- DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
+- }
+- remove_wait_queue(&s->dma_dac1.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-static int drain_dac2(struct es1370_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count, tmo;
+-
+- if (s->dma_dac2.mapped || !s->dma_dac2.ready)
+- return 0;
+- add_wait_queue(&s->dma_dac2.wait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac2.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac2.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return -EBUSY;
+- }
+- tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
+- / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
+- tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
+- if (!schedule_timeout(tmo + 1))
+- DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
+- }
+- remove_wait_queue(&s->dma_dac2.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t es1370_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret = 0;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- mutex_lock(&s->mutex);
+- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+- goto out;
+-
+- add_wait_queue(&s->dma_adc.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- swptr = s->dma_adc.swptr;
+- cnt = s->dma_adc.dmasize-swptr;
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_adc.enabled)
+- start_adc(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto out;
+- }
+- mutex_unlock(&s->mutex);
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto out;
+- }
+- mutex_lock(&s->mutex);
+- if (s->dma_adc.mapped)
+- {
+- ret = -ENXIO;
+- goto out;
+- }
+- continue;
+- }
+- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- goto out;
+- }
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_adc.enabled)
+- start_adc(s);
+- }
+-out:
+- mutex_unlock(&s->mutex);
+- remove_wait_queue(&s->dma_adc.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-static ssize_t es1370_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret = 0;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac2.mapped)
+- return -ENXIO;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- mutex_lock(&s->mutex);
+- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+- goto out;
+- ret = 0;
+- add_wait_queue(&s->dma_dac2.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (s->dma_dac2.count < 0) {
+- s->dma_dac2.count = 0;
+- s->dma_dac2.swptr = s->dma_dac2.hwptr;
+- }
+- swptr = s->dma_dac2.swptr;
+- cnt = s->dma_dac2.dmasize-swptr;
+- if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize)
+- cnt = s->dma_dac2.dmasize - s->dma_dac2.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_dac2.enabled)
+- start_dac2(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- goto out;
+- }
+- mutex_unlock(&s->mutex);
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- goto out;
+- }
+- mutex_lock(&s->mutex);
+- if (s->dma_dac2.mapped)
+- {
+- ret = -ENXIO;
+- goto out;
+- }
+- continue;
+- }
+- if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- goto out;
+- }
+- swptr = (swptr + cnt) % s->dma_dac2.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac2.swptr = swptr;
+- s->dma_dac2.count += cnt;
+- s->dma_dac2.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_dac2.enabled)
+- start_dac2(s);
+- }
+-out:
+- mutex_unlock(&s->mutex);
+- remove_wait_queue(&s->dma_dac2.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac2.ready && prog_dmabuf_dac2(s))
+- return 0;
+- poll_wait(file, &s->dma_dac2.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready && prog_dmabuf_adc(s))
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac2.mapped) {
+- if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int es1370_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- struct dmabuf *db;
+- int ret = 0;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- mutex_lock(&s->mutex);
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf_dac2(s)) != 0) {
+- goto out;
+- }
+- db = &s->dma_dac2;
+- } else if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf_adc(s)) != 0) {
+- goto out;
+- }
+- db = &s->dma_adc;
+- } else {
+- ret = -EINVAL;
+- goto out;
+- }
+- if (vma->vm_pgoff != 0) {
+- ret = -EINVAL;
+- goto out;
+- }
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder)) {
+- ret = -EINVAL;
+- goto out;
+- }
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot)) {
+- ret = -EAGAIN;
+- goto out;
+- }
+- db->mapped = 1;
+-out:
+- mutex_unlock(&s->mutex);
+- unlock_kernel();
+- return ret;
+-}
+-
+-static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int count;
+- int val, mapped, ret;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac2(s);
+- synchronize_irq(s->irq);
+- s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
+- return -EINVAL;
+- if (val < 4000)
+- val = 4000;
+- if (val > 50000)
+- val = 50000;
+- stop_adc(s);
+- stop_dac2(s);
+- s->dma_adc.ready = s->dma_dac2.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val)
+- s->sctrl |= SCTRL_R1SMB;
+- else
+- s->sctrl &= ~SCTRL_R1SMB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac2(s);
+- s->dma_dac2.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val)
+- s->sctrl |= SCTRL_P2SMB;
+- else
+- s->sctrl &= ~SCTRL_P2SMB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val >= 2)
+- s->sctrl |= SCTRL_R1SMB;
+- else
+- s->sctrl &= ~SCTRL_R1SMB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac2(s);
+- s->dma_dac2.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val >= 2)
+- s->sctrl |= SCTRL_P2SMB;
+- else
+- s->sctrl &= ~SCTRL_P2SMB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- }
+- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_LE|AFMT_U8, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val == AFMT_S16_LE)
+- s->sctrl |= SCTRL_R1SEB;
+- else
+- s->sctrl &= ~SCTRL_R1SEB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac2(s);
+- s->dma_dac2.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val == AFMT_S16_LE)
+- s->sctrl |= SCTRL_P2SEB;
+- else
+- s->sctrl &= ~SCTRL_P2SEB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- }
+- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ?
+- AFMT_S16_LE : AFMT_U8, p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN)
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+- return ret;
+- s->dma_adc.enabled = 1;
+- start_adc(s);
+- } else {
+- s->dma_adc.enabled = 0;
+- stop_adc(s);
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+- return ret;
+- s->dma_dac2.enabled = 1;
+- start_dac2(s);
+- } else {
+- s->dma_dac2.enabled = 0;
+- stop_dac2(s);
+- }
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- abinfo.fragsize = s->dma_dac2.fragsize;
+- count = s->dma_dac2.count;
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = s->dma_dac2.dmasize - count;
+- abinfo.fragstotal = s->dma_dac2.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- abinfo.fragsize = s->dma_adc.fragsize;
+- count = s->dma_adc.count;
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- count = s->dma_dac2.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- return put_user(count, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- count = s->dma_adc.count;
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_adc.fragshift;
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- cinfo.bytes = s->dma_dac2.total_bytes;
+- count = s->dma_dac2.count;
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_dac2.fragshift;
+- cinfo.ptr = s->dma_dac2.hwptr;
+- if (s->dma_dac2.mapped)
+- s->dma_dac2.count &= s->dma_dac2.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf_dac2(s)))
+- return val;
+- return put_user(s->dma_dac2.fragsize, p);
+- }
+- if ((val = prog_dmabuf_adc(s)))
+- return val;
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac2.ossfragshift = val & 0xffff;
+- s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac2.ossfragshift < 4)
+- s->dma_dac2.ossfragshift = 4;
+- if (s->dma_dac2.ossfragshift > 15)
+- s->dma_dac2.ossfragshift = 15;
+- if (s->dma_dac2.ossmaxfrags < 4)
+- s->dma_dac2.ossmaxfrags = 4;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE)
+- s->dma_dac2.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ?
+- 2 : 1, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ?
+- 16 : 8, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+- return mixer_ioctl(s, cmd, arg);
+-}
+-
+-static int es1370_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- struct list_head *list;
+- struct es1370_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct es1370_state, devs);
+- if (!((s->dev_audio ^ minor) & ~0xf))
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_READ|FMODE_WRITE)))
+- s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV);
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+- s->dma_adc.enabled = 1;
+- s->sctrl &= ~SCTRL_R1FMT;
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT;
+- else
+- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_R1FMT;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
+- s->dma_dac2.enabled = 1;
+- s->sctrl &= ~SCTRL_P2FMT;
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT;
+- else
+- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P2FMT;
+- }
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- mutex_unlock(&s->open_mutex);
+- mutex_init(&s->mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int es1370_release(struct inode *inode, struct file *file)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac2(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac2(s);
+- synchronize_irq(s->irq);
+- dealloc_dmabuf(s, &s->dma_dac2);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- dealloc_dmabuf(s, &s->dma_adc);
+- }
+- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations es1370_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = es1370_read,
+- .write = es1370_write,
+- .poll = es1370_poll,
+- .ioctl = es1370_ioctl,
+- .mmap = es1370_mmap,
+- .open = es1370_open,
+- .release = es1370_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t es1370_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret = 0;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac1.mapped)
+- return -ENXIO;
+- if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- add_wait_queue(&s->dma_dac1.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (s->dma_dac1.count < 0) {
+- s->dma_dac1.count = 0;
+- s->dma_dac1.swptr = s->dma_dac1.hwptr;
+- }
+- swptr = s->dma_dac1.swptr;
+- cnt = s->dma_dac1.dmasize-swptr;
+- if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize)
+- cnt = s->dma_dac1.dmasize - s->dma_dac1.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_dac1.enabled)
+- start_dac1(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- swptr = (swptr + cnt) % s->dma_dac1.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac1.swptr = swptr;
+- s->dma_dac1.count += cnt;
+- s->dma_dac1.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_dac1.enabled)
+- start_dac1(s);
+- }
+- remove_wait_queue(&s->dma_dac1.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct *wait)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (!s->dma_dac1.ready && prog_dmabuf_dac1(s))
+- return 0;
+- poll_wait(file, &s->dma_dac1.wait, wait);
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- if (s->dma_dac1.mapped) {
+- if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- int ret;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- if (!(vma->vm_flags & VM_WRITE))
+- return -EINVAL;
+- lock_kernel();
+- if ((ret = prog_dmabuf_dac1(s)) != 0)
+- goto out;
+- ret = -EINVAL;
+- if (vma->vm_pgoff != 0)
+- goto out;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << s->dma_dac1.buforder))
+- goto out;
+- ret = -EAGAIN;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+- s->dma_dac1.mapped = 1;
+- ret = 0;
+-out:
+- unlock_kernel();
+- return ret;
+-}
+-
+-static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int count;
+- unsigned ctrl;
+- int val, ret;
+- int __user *p = (int __user *)arg;
+-
+- VALIDATE_STATE(s);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/);
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return -EINVAL;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+- stop_dac1(s);
+- synchronize_irq(s->irq);
+- s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0;
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- stop_dac1(s);
+- s->dma_dac1.ready = 0;
+- for (ctrl = 0; ctrl <= 2; ctrl++)
+- if (val < (dac1_samplerate[ctrl] + dac1_samplerate[ctrl+1]) / 2)
+- break;
+- spin_lock_irqsave(&s->lock, flags);
+- s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (ctrl << CTRL_SH_WTSRSEL);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- stop_dac1(s);
+- s->dma_dac1.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val)
+- s->sctrl |= SCTRL_P1SMB;
+- else
+- s->sctrl &= ~SCTRL_P1SMB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 0) {
+- if (s->dma_dac1.mapped)
+- return -EINVAL;
+- stop_dac1(s);
+- s->dma_dac1.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val >= 2)
+- s->sctrl |= SCTRL_P1SMB;
+- else
+- s->sctrl &= ~SCTRL_P1SMB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_LE|AFMT_U8, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- stop_dac1(s);
+- s->dma_dac1.ready = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val == AFMT_S16_LE)
+- s->sctrl |= SCTRL_P1SEB;
+- else
+- s->sctrl &= ~SCTRL_P1SEB;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
+- return ret;
+- s->dma_dac1.enabled = 1;
+- start_dac1(s);
+- } else {
+- s->dma_dac1.enabled = 0;
+- stop_dac1(s);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- abinfo.fragsize = s->dma_dac1.fragsize;
+- count = s->dma_dac1.count;
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = s->dma_dac1.dmasize - count;
+- abinfo.fragstotal = s->dma_dac1.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- count = s->dma_dac1.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- return put_user(count, p);
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_update_ptr(s);
+- cinfo.bytes = s->dma_dac1.total_bytes;
+- count = s->dma_dac1.count;
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_dac1.fragshift;
+- cinfo.ptr = s->dma_dac1.hwptr;
+- if (s->dma_dac1.mapped)
+- s->dma_dac1.count &= s->dma_dac1.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if ((val = prog_dmabuf_dac1(s)))
+- return val;
+- return put_user(s->dma_dac1.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- s->dma_dac1.ossfragshift = val & 0xffff;
+- s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac1.ossfragshift < 4)
+- s->dma_dac1.ossfragshift = 4;
+- if (s->dma_dac1.ossfragshift > 15)
+- s->dma_dac1.ossfragshift = 15;
+- if (s->dma_dac1.ossmaxfrags < 4)
+- s->dma_dac1.ossmaxfrags = 4;
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if (s->dma_dac1.subdivision)
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- s->dma_dac1.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+- return mixer_ioctl(s, cmd, arg);
+-}
+-
+-static int es1370_open_dac(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- struct list_head *list;
+- struct es1370_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct es1370_state, devs);
+- if (!((s->dev_dac ^ minor) & ~0xf))
+- break;
+- }
+- VALIDATE_STATE(s);
+- /* we allow opening with O_RDWR, most programs do it although they will only write */
+-#if 0
+- if (file->f_mode & FMODE_READ)
+- return -EPERM;
+-#endif
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & FMODE_DAC) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
+- s->dma_dac1.enabled = 1;
+- spin_lock_irqsave(&s->lock, flags);
+- s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL);
+- s->sctrl &= ~SCTRL_P1FMT;
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P1FMT;
+- else
+- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P1FMT;
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->open_mode |= FMODE_DAC;
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int es1370_release_dac(struct inode *inode, struct file *file)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- drain_dac1(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- stop_dac1(s);
+- dealloc_dmabuf(s, &s->dma_dac1);
+- s->open_mode &= ~FMODE_DAC;
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations es1370_dac_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .write = es1370_write_dac,
+- .poll = es1370_poll_dac,
+- .ioctl = es1370_ioctl_dac,
+- .mmap = es1370_mmap_dac,
+- .open = es1370_open_dac,
+- .release = es1370_release_dac,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t es1370_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- if (count == 0)
+- return 0;
+- ret = 0;
+- add_wait_queue(&s->midi.iwait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.ird;
+- cnt = MIDIINBUF - ptr;
+- if (s->midi.icnt < cnt)
+- cnt = s->midi.icnt;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- ptr = (ptr + cnt) % MIDIINBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.ird = ptr;
+- s->midi.icnt -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- break;
+- }
+- __set_current_state(TASK_RUNNING);
+- remove_wait_queue(&s->midi.iwait, &wait);
+- return ret;
+-}
+-
+-static ssize_t es1370_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- if (count == 0)
+- return 0;
+- ret = 0;
+- add_wait_queue(&s->midi.owait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.owr;
+- cnt = MIDIOUTBUF - ptr;
+- if (s->midi.ocnt + cnt > MIDIOUTBUF)
+- cnt = MIDIOUTBUF - s->midi.ocnt;
+- if (cnt <= 0) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- es1370_handle_midi(s);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- ptr = (ptr + cnt) % MIDIOUTBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.owr = ptr;
+- s->midi.ocnt += cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- spin_lock_irqsave(&s->lock, flags);
+- es1370_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- __set_current_state(TASK_RUNNING);
+- remove_wait_queue(&s->midi.owait, &wait);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE)
+- poll_wait(file, &s->midi.owait, wait);
+- if (file->f_mode & FMODE_READ)
+- poll_wait(file, &s->midi.iwait, wait);
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_mode & FMODE_READ) {
+- if (s->midi.icnt > 0)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->midi.ocnt < MIDIOUTBUF)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int es1370_midi_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- struct list_head *list;
+- struct es1370_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct es1370_state, devs);
+- if (s->dev_midi == minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- outb(UCTRL_CNTRL_SWR, s->io+ES1370_REG_UART_CONTROL);
+- outb(0, s->io+ES1370_REG_UART_CONTROL);
+- outb(0, s->io+ES1370_REG_UART_TEST);
+- }
+- if (file->f_mode & FMODE_READ) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- }
+- s->ctrl |= CTRL_UART_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- es1370_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int es1370_midi_release(struct inode *inode, struct file *file)
+-{
+- struct es1370_state *s = (struct es1370_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- unsigned count, tmo;
+-
+- VALIDATE_STATE(s);
+-
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE) {
+- add_wait_queue(&s->midi.owait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->midi.ocnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (file->f_flags & O_NONBLOCK)
+- break;
+- tmo = (count * HZ) / 3100;
+- if (!schedule_timeout(tmo ? : 1) && tmo)
+- DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");)
+- }
+- remove_wait_queue(&s->midi.owait, &wait);
+- set_current_state(TASK_RUNNING);
+- }
+- mutex_lock(&s->open_mutex);
+- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- s->ctrl &= ~CTRL_UART_EN;
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations es1370_midi_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = es1370_midi_read,
+- .write = es1370_midi_write,
+- .poll = es1370_midi_poll,
+- .open = es1370_midi_open,
+- .release = es1370_midi_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-/* maximum number of devices; only used for command line params */
+-#define NR_DEVICE 5
+-
+-static int lineout[NR_DEVICE];
+-static int micbias[NR_DEVICE];
+-
+-static unsigned int devindex;
+-
+-module_param_array(lineout, bool, NULL, 0);
+-MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
+-module_param_array(micbias, bool, NULL, 0);
+-MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone");
+-
+-MODULE_AUTHOR("Thomas M. Sailer, sailer at ife.ee.ethz.ch, hb9jnx at hb9w.che.eu");
+-MODULE_DESCRIPTION("ES1370 AudioPCI Driver");
+-MODULE_LICENSE("GPL");
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static struct initvol {
+- int mixch;
+- int vol;
+-} initvol[] __devinitdata = {
+- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
+- { SOUND_MIXER_WRITE_PCM, 0x4040 },
+- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
+- { SOUND_MIXER_WRITE_CD, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE3, 0x4040 },
+- { SOUND_MIXER_WRITE_MIC, 0x4040 },
+- { 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;
+- mm_segment_t fs;
+- int i, val, ret;
+-
+- if ((ret=pci_enable_device(pcidev)))
+- return ret;
+-
+- if ( !(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
+- !pci_resource_start(pcidev, 0)
+- )
+- return -ENODEV;
+- if (pcidev->irq == 0)
+- return -ENODEV;
+- 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;
+- }
+- if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
+- printk(KERN_WARNING "es1370: out of memory\n");
+- return -ENOMEM;
+- }
+- memset(s, 0, sizeof(struct es1370_state));
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac1.wait);
+- init_waitqueue_head(&s->dma_dac2.wait);
+- init_waitqueue_head(&s->open_wait);
+- init_waitqueue_head(&s->midi.iwait);
+- init_waitqueue_head(&s->midi.owait);
+- mutex_init(&s->open_mutex);
+- spin_lock_init(&s->lock);
+- s->magic = ES1370_MAGIC;
+- s->dev = pcidev;
+- s->io = pci_resource_start(pcidev, 0);
+- s->irq = pcidev->irq;
+- if (!request_region(s->io, ES1370_EXTENT, "es1370")) {
+- printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
+- ret = -EBUSY;
+- goto err_region;
+- }
+- if ((ret=request_irq(s->irq, es1370_interrupt, IRQF_SHARED, "es1370",s))) {
+- printk(KERN_ERR "es1370: irq %u in use\n", s->irq);
+- goto err_irq;
+- }
+-
+- /* initialize codec registers */
+- /* note: setting CTRL_SERR_DIS is reported to break
+- * mic bias setting (by Kim.Berts at fisub.mail.abb.com) */
+- s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
+- if (lineout[devindex])
+- s->ctrl |= CTRL_XCTL0;
+- if (micbias[devindex])
+- s->ctrl |= CTRL_XCTL1;
+- s->sctrl = 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;
+- goto err_dev1;
+- }
+- if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) {
+- ret = s->dev_mixer;
+- goto err_dev2;
+- }
+- if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) {
+- ret = s->dev_dac;
+- goto err_dev3;
+- }
+- if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) {
+- ret = s->dev_midi;
+- goto err_dev4;
+- }
+- /* initialize the chips */
+- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
+- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+- /* point phantom write channel to "bugbuf" */
+- s->bugbuf_cpu = pci_alloc_consistent(pcidev,16,&s->bugbuf_dma);
+- if (!s->bugbuf_cpu) {
+- ret = -ENOMEM;
+- goto err_dev5;
+- }
+- outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+- outl(s->bugbuf_dma, s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
+- outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
+- pci_set_master(pcidev); /* enable bus mastering */
+- wrcodec(s, 0x16, 3); /* no RST, PD */
+- wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */
+- wrcodec(s, 0x18, 0); /* recording source is mixer */
+- wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */
+- s->mix.imix = 1;
+- fs = get_fs();
+- set_fs(KERNEL_DS);
+- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD;
+- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+- val = initvol[i].vol;
+- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+- }
+- set_fs(fs);
+-
+- es1370_register_gameport(s);
+-
+- /* store it in the driver field */
+- pci_set_drvdata(pcidev, s);
+- /* put it into driver list */
+- list_add_tail(&s->devs, &devs);
+- /* increment devindex */
+- if (devindex < NR_DEVICE-1)
+- devindex++;
+- return 0;
+-
+- err_dev5:
+- unregister_sound_midi(s->dev_midi);
+- err_dev4:
+- unregister_sound_dsp(s->dev_dac);
+- err_dev3:
+- unregister_sound_mixer(s->dev_mixer);
+- err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+- err_dev1:
+- printk(KERN_ERR "es1370: cannot register misc device\n");
+- free_irq(s->irq, s);
+- err_irq:
+- release_region(s->io, ES1370_EXTENT);
+- err_region:
+- kfree(s);
+- return ret;
+-}
+-
+-static void __devexit es1370_remove(struct pci_dev *dev)
+-{
+- struct es1370_state *s = pci_get_drvdata(dev);
+-
+- if (!s)
+- return;
+- list_del(&s->devs);
+- outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */
+- outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
+- synchronize_irq(s->irq);
+- free_irq(s->irq, s);
+- es1370_unregister_gameport(s);
+- release_region(s->io, ES1370_EXTENT);
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->dev_mixer);
+- unregister_sound_dsp(s->dev_dac);
+- unregister_sound_midi(s->dev_midi);
+- pci_free_consistent(dev, 16, s->bugbuf_cpu, s->bugbuf_dma);
+- kfree(s);
+- pci_set_drvdata(dev, NULL);
+-}
+-
+-static struct pci_device_id id_table[] = {
+- { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, id_table);
+-
+-static struct pci_driver es1370_driver = {
+- .name = "es1370",
+- .id_table = id_table,
+- .probe = es1370_probe,
+- .remove = __devexit_p(es1370_remove),
+-};
+-
+-static int __init init_es1370(void)
+-{
+- printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n");
+- return pci_register_driver(&es1370_driver);
+-}
+-
+-static void __exit cleanup_es1370(void)
+-{
+- printk(KERN_INFO "es1370: unloading\n");
+- pci_unregister_driver(&es1370_driver);
+-}
+-
+-module_init(init_es1370);
+-module_exit(cleanup_es1370);
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef MODULE
+-
+-/* format is: es1370=lineout[,micbias]] */
+-
+-static int __init es1370_setup(char *str)
+-{
+- static unsigned __initdata nr_dev = 0;
+-
+- if (nr_dev >= NR_DEVICE)
+- return 0;
+-
+- (void)
+- ((get_option(&str,&lineout [nr_dev]) == 2)
+- && get_option(&str,&micbias [nr_dev])
+- );
+-
+- nr_dev++;
+- return 1;
+-}
+-
+-__setup("es1370=", es1370_setup);
+-
+-#endif /* MODULE */
+diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
+index a2ffe72..ddf6b0a 100644
+--- a/sound/oss/es1371.c
++++ b/sound/oss/es1371.c
+@@ -1100,9 +1100,9 @@ static void es1371_handle_midi(struct es
+ outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1371_REG_UART_CONTROL);
+ }
+
+-static irqreturn_t es1371_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t es1371_interrupt(int irq, void *dev_id)
+ {
+- struct es1371_state *s = (struct es1371_state *)dev_id;
++ struct es1371_state *s = dev_id;
+ unsigned int intsrc, sctl;
+
+ /* fastpath out, to ease interrupt sharing */
+diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
+deleted file mode 100644
+index 82f40a0..0000000
+--- a/sound/oss/esssolo1.c
++++ /dev/null
+@@ -1,2516 +0,0 @@
+-/****************************************************************************/
+-
+-/*
+- * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver.
+- *
+- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer at alumni.ethz.ch)
+- *
+- * 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.
+- *
+- * Module command line parameters:
+- * none so far
+- *
+- * Supported devices:
+- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+- * /dev/midi simple MIDI UART interface, no ioctl
+- *
+- * Revision history
+- * 10.11.1998 0.1 Initial release (without any hardware)
+- * 22.03.1999 0.2 cinfo.blocks should be reset after GETxPTR ioctl.
+- * reported by Johan Maes <joma at telindus.be>
+- * return EAGAIN instead of EBUSY when O_NONBLOCK
+- * read/write cannot be executed
+- * 07.04.1999 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+- * Alpha fixes reported by Peter Jones <pjones at redhat.com>
+- * 15.06.1999 0.4 Fix bad allocation bug.
+- * Thanks to Deti Fliegl <fliegl at in.tum.de>
+- * 28.06.1999 0.5 Add pci_set_master
+- * 12.08.1999 0.6 Fix MIDI UART crashing the driver
+- * Changed mixer semantics from OSS documented
+- * behaviour to OSS "code behaviour".
+- * Recording might actually work now.
+- * The real DDMA controller address register is at PCI config
+- * 0x60, while the register at 0x18 is used as a placeholder
+- * register for BIOS address allocation. This register
+- * is supposed to be copied into 0x60, according
+- * to the Solo1 datasheet. When I do that, I can access
+- * the DDMA registers except the mask bit, which
+- * is stuck at 1. When I copy the contents of 0x18 +0x10
+- * to the DDMA base register, everything seems to work.
+- * The fun part is that the Windows Solo1 driver doesn't
+- * seem to do these tricks.
+- * Bugs remaining: plops and clicks when starting/stopping playback
+- * 31.08.1999 0.7 add spin_lock_init
+- * replaced current->state = x with set_current_state(x)
+- * 03.09.1999 0.8 change read semantics for MIDI to match
+- * OSS more closely; remove possible wakeup race
+- * 07.10.1999 0.9 Fix initialization; complain if sequencer writes time out
+- * Revised resource grabbing for the FM synthesizer
+- * 28.10.1999 0.10 More waitqueue races fixed
+- * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
+- * Disabling recording on Alpha
+- * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun;
+- * Tim Janik's BSE (Bedevilled Sound Engine) found this
+- * Integrated (aka redid 8-)) APM support patch by Zach Brown
+- * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver
+- * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled
+- * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers
+- * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+- * 12.12.2000 0.17 More dma buffer initializations, patch from
+- * Tjeerd Mulder <tjeerd.mulder at fujitsu-siemens.com>
+- * 31.01.2001 0.18 Register/Unregister gameport, original patch from
+- * Nathaniel Daw <daw at cs.cmu.edu>
+- * Fix SETTRIGGER non OSS API conformity
+- * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro
+- * for abs. Bug report by Andrew Morton <andrewm at uow.edu.au>
+- * 15.05.2001 pci_enable_device moved, return values in probe cleaned
+- * up. Marcus Meissner <mm at caldera.de>
+- * 22.05.2001 0.19 more cleanups, changed PM to PCI 2.4 style, got rid
+- * of global list of devices, using pci device data.
+- * Marcus Meissner <mm at caldera.de>
+- * 03.01.2003 0.20 open_mode fixes from Georg Acher <acher at in.tum.de>
+- */
+-
+-/*****************************************************************************/
+-
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/bitops.h>
+-#include <linux/init.h>
+-#include <linux/poll.h>
+-#include <linux/spinlock.h>
+-#include <linux/smp_lock.h>
+-#include <linux/gameport.h>
+-#include <linux/wait.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/mutex.h>
+-
+-
+-#include <asm/io.h>
+-#include <asm/page.h>
+-#include <asm/uaccess.h>
+-
+-#include "dm.h"
+-
+-/* --------------------------------------------------------------------- */
+-
+-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef PCI_VENDOR_ID_ESS
+-#define PCI_VENDOR_ID_ESS 0x125d
+-#endif
+-#ifndef PCI_DEVICE_ID_ESS_SOLO1
+-#define PCI_DEVICE_ID_ESS_SOLO1 0x1969
+-#endif
+-
+-#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
+-
+-#define DDMABASE_OFFSET 0 /* chip bug workaround kludge */
+-#define DDMABASE_EXTENT 16
+-
+-#define IOBASE_EXTENT 16
+-#define SBBASE_EXTENT 16
+-#define VCBASE_EXTENT (DDMABASE_EXTENT+DDMABASE_OFFSET)
+-#define MPUBASE_EXTENT 4
+-#define GPBASE_EXTENT 4
+-#define GAMEPORT_EXTENT 4
+-
+-#define FMSYNTH_EXTENT 4
+-
+-/* MIDI buffer sizes */
+-
+-#define MIDIINBUF 256
+-#define MIDIOUTBUF 256
+-
+-#define FMODE_MIDI_SHIFT 3
+-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
+-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+-
+-#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;
+-
+-/* --------------------------------------------------------------------- */
+-
+-struct solo1_state {
+- /* magic */
+- unsigned int magic;
+-
+- /* the corresponding pci_dev structure */
+- struct pci_dev *dev;
+-
+- /* soundcore stuff */
+- int dev_audio;
+- int dev_mixer;
+- int dev_midi;
+- int dev_dmfm;
+-
+- /* hardware resources */
+- unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */
+- unsigned int irq;
+-
+- /* mixer registers */
+- struct {
+- unsigned short vol[10];
+- unsigned int recsrc;
+- unsigned int modcnt;
+- unsigned short micpreamp;
+- } mix;
+-
+- /* wave stuff */
+- unsigned fmt;
+- unsigned channels;
+- unsigned rate;
+- unsigned char clkdiv;
+- unsigned ena;
+-
+- spinlock_t lock;
+- struct mutex open_mutex;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+-
+- struct dmabuf {
+- void *rawbuf;
+- dma_addr_t dmaaddr;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- unsigned hwptr, swptr;
+- unsigned total_bytes;
+- int count;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize;
+- unsigned fragsamples;
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned endcleared:1;
+- unsigned enabled:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac, dma_adc;
+-
+- /* midi stuff */
+- struct {
+- unsigned ird, iwr, icnt;
+- unsigned ord, owr, ocnt;
+- wait_queue_head_t iwait;
+- wait_queue_head_t owait;
+- struct timer_list timer;
+- unsigned char ibuf[MIDIINBUF];
+- unsigned char obuf[MIDIOUTBUF];
+- } midi;
+-
+-#if SUPPORT_JOYSTICK
+- struct gameport *gameport;
+-#endif
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline void write_seq(struct solo1_state *s, unsigned char data)
+-{
+- int i;
+- unsigned long flags;
+-
+- /* the local_irq_save stunt is to send the data within the command window */
+- for (i = 0; i < 0xffff; i++) {
+- local_irq_save(flags);
+- if (!(inb(s->sbbase+0xc) & 0x80)) {
+- outb(data, s->sbbase+0xc);
+- local_irq_restore(flags);
+- return;
+- }
+- local_irq_restore(flags);
+- }
+- printk(KERN_ERR "esssolo1: write_seq timeout\n");
+- outb(data, s->sbbase+0xc);
+-}
+-
+-static inline int read_seq(struct solo1_state *s, unsigned char *data)
+-{
+- int i;
+-
+- if (!data)
+- return 0;
+- for (i = 0; i < 0xffff; i++)
+- if (inb(s->sbbase+0xe) & 0x80) {
+- *data = inb(s->sbbase+0xa);
+- return 1;
+- }
+- printk(KERN_ERR "esssolo1: read_seq timeout\n");
+- return 0;
+-}
+-
+-static inline int reset_ctrl(struct solo1_state *s)
+-{
+- int i;
+-
+- outb(3, s->sbbase+6); /* clear sequencer and FIFO */
+- udelay(10);
+- outb(0, s->sbbase+6);
+- for (i = 0; i < 0xffff; i++)
+- if (inb(s->sbbase+0xe) & 0x80)
+- if (inb(s->sbbase+0xa) == 0xaa) {
+- write_seq(s, 0xc6); /* enter enhanced mode */
+- return 1;
+- }
+- return 0;
+-}
+-
+-static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data)
+-{
+- write_seq(s, reg);
+- write_seq(s, data);
+-}
+-
+-#if 0 /* unused */
+-static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
+-{
+- unsigned char r;
+-
+- write_seq(s, 0xc0);
+- write_seq(s, reg);
+- read_seq(s, &r);
+- return r;
+-}
+-#endif /* unused */
+-
+-static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
+-{
+- outb(reg, s->sbbase+4);
+- outb(data, s->sbbase+5);
+-}
+-
+-static unsigned char read_mixer(struct solo1_state *s, unsigned char reg)
+-{
+- outb(reg, s->sbbase+4);
+- return inb(s->sbbase+5);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline unsigned ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline void stop_dac(struct solo1_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->ena &= ~FMODE_WRITE;
+- write_mixer(s, 0x78, 0x10);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_dac(struct solo1_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+- s->ena |= FMODE_WRITE;
+- write_mixer(s, 0x78, 0x12);
+- udelay(10);
+- write_mixer(s, 0x78, 0x13);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static inline void stop_adc(struct solo1_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->ena &= ~FMODE_READ;
+- write_ctrl(s, 0xb8, 0xe);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_adc(struct solo1_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+- && s->dma_adc.ready) {
+- s->ena |= FMODE_READ;
+- write_ctrl(s, 0xb8, 0xf);
+-#if 0
+- printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
+- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
+- inb(s->ddmabase+0xf), inw(s->ddmabase+4), inl(s->ddmabase), inb(s->ddmabase+8));
+-#endif
+- outb(0, s->ddmabase+0xd); /* master reset */
+- outb(1, s->ddmabase+0xf); /* mask */
+- outb(0x54/*0x14*/, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+- outl(virt_to_bus(s->dma_adc.rawbuf), s->ddmabase);
+- outw(s->dma_adc.dmasize-1, s->ddmabase+4);
+- outb(0, s->ddmabase+0xf);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-#if 0
+- printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x SBstat: 0x%02x\n"
+- KERN_DEBUG "solo1: DMA: stat: 0x%02x cnt: 0x%04x mask: 0x%02x\n",
+- read_ctrl(s, 0xb8), inb(s->sbbase+0xc),
+- inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->ddmabase+0xf));
+- printk(KERN_DEBUG "solo1: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
+- KERN_DEBUG "solo1: B1: 0x%02x B2: 0x%02x B4: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n",
+- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
+- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8),
+- read_ctrl(s, 0xb9));
+-#endif
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-static inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db)
+-{
+- struct page *page, *pend;
+-
+- if (db->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
+- }
+- db->rawbuf = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
+-{
+- int order;
+- unsigned bytespersec;
+- unsigned bufs, sample_shift = 0;
+- struct page *page, *pend;
+-
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
+- break;
+- if (!db->rawbuf)
+- return -ENOMEM;
+- db->buforder = order;
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- }
+- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- sample_shift++;
+- if (s->channels > 1)
+- sample_shift++;
+- bytespersec = s->rate << sample_shift;
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytespersec)
+- db->fragshift = ld2(bytespersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- db->fragsamples = db->fragsize >> sample_shift;
+- db->dmasize = db->numfrag << db->fragshift;
+- db->enabled = 1;
+- return 0;
+-}
+-
+-static inline int prog_dmabuf_adc(struct solo1_state *s)
+-{
+- unsigned long va;
+- int c;
+-
+- stop_adc(s);
+- /* check if PCI implementation supports 24bit busmaster DMA */
+- if (s->dev->dma_mask > 0xffffff)
+- return -EIO;
+- if ((c = prog_dmabuf(s, &s->dma_adc)))
+- return c;
+- va = s->dma_adc.dmaaddr;
+- if ((va & ~((1<<24)-1)))
+- panic("solo1: buffer above 16M boundary");
+- outb(0, s->ddmabase+0xd); /* clear */
+- outb(1, s->ddmabase+0xf); /* mask */
+- /*outb(0, s->ddmabase+8);*/ /* enable (enable is active low!) */
+- outb(0x54, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+- outl(va, s->ddmabase);
+- outw(s->dma_adc.dmasize-1, s->ddmabase+4);
+- c = - s->dma_adc.fragsamples;
+- write_ctrl(s, 0xa4, c);
+- write_ctrl(s, 0xa5, c >> 8);
+- outb(0, s->ddmabase+0xf);
+- s->dma_adc.ready = 1;
+- return 0;
+-}
+-
+-static int prog_dmabuf_dac(struct solo1_state *s)
+-{
+- unsigned long va;
+- int c;
+-
+- stop_dac(s);
+- if ((c = prog_dmabuf(s, &s->dma_dac)))
+- return c;
+- memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
+- va = s->dma_dac.dmaaddr;
+- if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
+- panic("solo1: buffer crosses 1M boundary");
+- outl(va, s->iobase);
+- /* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */
+- outw(s->dma_dac.dmasize, s->iobase+4);
+- c = - s->dma_dac.fragsamples;
+- write_mixer(s, 0x74, c);
+- write_mixer(s, 0x76, c >> 8);
+- outb(0xa, s->iobase+6);
+- s->dma_dac.ready = 1;
+- return 0;
+-}
+-
+-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
+-{
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(((char *)buf) + bptr, c, x);
+- bptr = 0;
+- len -= x;
+- }
+- memset(((char *)buf) + bptr, c, len);
+-}
+-
+-/* call with spinlock held! */
+-
+-static void solo1_update_ptr(struct solo1_state *s)
+-{
+- int diff;
+- unsigned hwptr;
+-
+- /* update ADC pointer */
+- if (s->ena & FMODE_READ) {
+- hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize;
+- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+-#if 0
+- printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
+- s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
+-#endif
+- if (s->dma_adc.mapped) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- wake_up(&s->dma_adc.wait);
+- } else {
+- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+- s->ena &= ~FMODE_READ;
+- write_ctrl(s, 0xb8, 0xe);
+- s->dma_adc.error++;
+- }
+- if (s->dma_adc.count > 0)
+- wake_up(&s->dma_adc.wait);
+- }
+- }
+- /* update DAC pointer */
+- if (s->ena & FMODE_WRITE) {
+- hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize;
+- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+- s->dma_dac.hwptr = hwptr;
+- s->dma_dac.total_bytes += diff;
+-#if 0
+- printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",
+- s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);
+-#endif
+- if (s->dma_dac.mapped) {
+- s->dma_dac.count += diff;
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- wake_up(&s->dma_dac.wait);
+- } else {
+- s->dma_dac.count -= diff;
+- if (s->dma_dac.count <= 0) {
+- s->ena &= ~FMODE_WRITE;
+- write_mixer(s, 0x78, 0x12);
+- s->dma_dac.error++;
+- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+- clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr,
+- s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);
+- s->dma_dac.endcleared = 1;
+- }
+- if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+- wake_up(&s->dma_dac.wait);
+- }
+- }
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static void prog_codec(struct solo1_state *s)
+-{
+- unsigned long flags;
+- int fdiv, filter;
+- unsigned char c;
+-
+- reset_ctrl(s);
+- write_seq(s, 0xd3);
+- /* program sampling rates */
+- filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */
+- fdiv = 256 - 7160000 / (filter * 82);
+- spin_lock_irqsave(&s->lock, flags);
+- write_ctrl(s, 0xa1, s->clkdiv);
+- write_ctrl(s, 0xa2, fdiv);
+- write_mixer(s, 0x70, s->clkdiv);
+- write_mixer(s, 0x72, fdiv);
+- /* program ADC parameters */
+- write_ctrl(s, 0xb8, 0xe);
+- write_ctrl(s, 0xb9, /*0x1*/0);
+- write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);
+- c = 0xd0;
+- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- c |= 0x04;
+- if (s->fmt & (AFMT_S16_LE | AFMT_S8))
+- c |= 0x20;
+- if (s->channels > 1)
+- c ^= 0x48;
+- write_ctrl(s, 0xb7, (c & 0x70) | 1);
+- write_ctrl(s, 0xb7, c);
+- write_ctrl(s, 0xb1, 0x50);
+- write_ctrl(s, 0xb2, 0x50);
+- /* program DAC parameters */
+- c = 0x40;
+- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- c |= 1;
+- if (s->fmt & (AFMT_S16_LE | AFMT_S8))
+- c |= 4;
+- if (s->channels > 1)
+- c |= 2;
+- write_mixer(s, 0x7a, c);
+- write_mixer(s, 0x78, 0x10);
+- s->ena = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";
+-
+-#define VALIDATE_STATE(s) \
+-({ \
+- if (!(s) || (s)->magic != SOLO1_MAGIC) { \
+- printk(invalid_magic); \
+- return -ENXIO; \
+- } \
+-})
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg)
+-{
+- static const unsigned int mixer_src[8] = {
+- SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
+- SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
+- };
+- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_PCM] = 1, /* voice */
+- [SOUND_MIXER_SYNTH] = 2, /* FM */
+- [SOUND_MIXER_CD] = 3, /* CD */
+- [SOUND_MIXER_LINE] = 4, /* Line */
+- [SOUND_MIXER_LINE1] = 5, /* AUX */
+- [SOUND_MIXER_MIC] = 6, /* Mic */
+- [SOUND_MIXER_LINE2] = 7, /* Mono in */
+- [SOUND_MIXER_SPEAKER] = 8, /* Speaker */
+- [SOUND_MIXER_RECLEV] = 9, /* Recording level */
+- [SOUND_MIXER_VOLUME] = 10 /* Master Volume */
+- };
+- static const unsigned char mixreg[] = {
+- 0x7c, /* voice */
+- 0x36, /* FM */
+- 0x38, /* CD */
+- 0x3e, /* Line */
+- 0x3a, /* AUX */
+- 0x1a, /* Mic */
+- 0x6d /* Mono in */
+- };
+- unsigned char l, r, rl, rr, vidx;
+- int i, val;
+- int __user *p = (int __user *)arg;
+-
+- VALIDATE_STATE(s);
+-
+- if (cmd == SOUND_MIXER_PRIVATE1) {
+- /* enable/disable/query mixer preamp */
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != -1) {
+- val = val ? 0xff : 0xf7;
+- write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
+- }
+- val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
+- return put_user(val, p);
+- }
+- if (cmd == SOUND_MIXER_PRIVATE2) {
+- /* enable/disable/query spatializer */
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != -1) {
+- val &= 0x3f;
+- write_mixer(s, 0x52, val);
+- write_mixer(s, 0x50, val ? 0x08 : 0);
+- }
+- return put_user(read_mixer(s, 0x52), p);
+- }
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- strncpy(info.id, "Solo1", sizeof(info.id));
+- strncpy(info.name, "ESS Solo1", sizeof(info.name));
+- info.modify_counter = s->mix.modcnt;
+- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == SOUND_OLD_MIXER_INFO) {
+- _old_mixer_info info;
+- strncpy(info.id, "Solo1", sizeof(info.id));
+- strncpy(info.name, "ESS Solo1", sizeof(info.name));
+- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, p);
+- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+- return -EINVAL;
+- if (_SIOC_DIR(cmd) == _SIOC_READ) {
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- return put_user(mixer_src[read_mixer(s, 0x1c) & 7], p);
+-
+- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+- SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
+- SOUND_MASK_SPEAKER, p);
+-
+- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, p);
+-
+- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+- SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, p);
+-
+- case SOUND_MIXER_CAPS:
+- return put_user(SOUND_CAP_EXCL_INPUT, p);
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
+- return -EINVAL;
+- return put_user(s->mix.vol[vidx-1], p);
+- }
+- }
+- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
+- return -EINVAL;
+- s->mix.modcnt++;
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+-#if 0
+- {
+- static const unsigned char regs[] = {
+- 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
+- };
+- int i;
+-
+- for (i = 0; i < sizeof(regs); i++)
+- printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
+- regs[i], read_mixer(s, regs[i]));
+- printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
+- 0xb4, read_ctrl(s, 0xb4));
+- }
+-#endif
+- if (get_user(val, p))
+- return -EFAULT;
+- i = hweight32(val);
+- if (i == 0)
+- return 0;
+- else if (i > 1)
+- val &= ~mixer_src[read_mixer(s, 0x1c) & 7];
+- for (i = 0; i < 8; i++) {
+- if (mixer_src[i] & val)
+- break;
+- }
+- if (i > 7)
+- return 0;
+- write_mixer(s, 0x1c, i);
+- return 0;
+-
+- case SOUND_MIXER_VOLUME:
+- if (get_user(val, p))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- r = (val >> 8) & 0xff;
+- if (r > 100)
+- r = 100;
+- if (l < 6) {
+- rl = 0x40;
+- l = 0;
+- } else {
+- rl = (l * 2 - 11) / 3;
+- l = (rl * 3 + 11) / 2;
+- }
+- if (r < 6) {
+- rr = 0x40;
+- r = 0;
+- } else {
+- rr = (r * 2 - 11) / 3;
+- r = (rr * 3 + 11) / 2;
+- }
+- write_mixer(s, 0x60, rl);
+- write_mixer(s, 0x62, rr);
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[9] = ((unsigned int)r << 8) | l;
+-#else
+- s->mix.vol[9] = val;
+-#endif
+- return put_user(s->mix.vol[9], p);
+-
+- case SOUND_MIXER_SPEAKER:
+- if (get_user(val, p))
+- return -EFAULT;
+- l = val & 0xff;
+- if (l > 100)
+- l = 100;
+- else if (l < 2)
+- l = 2;
+- rl = (l - 2) / 14;
+- l = rl * 14 + 2;
+- write_mixer(s, 0x3c, rl);
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[7] = l * 0x101;
+-#else
+- s->mix.vol[7] = val;
+-#endif
+- return put_user(s->mix.vol[7], p);
+-
+- case SOUND_MIXER_RECLEV:
+- if (get_user(val, p))
+- return -EFAULT;
+- l = (val << 1) & 0x1fe;
+- if (l > 200)
+- l = 200;
+- else if (l < 5)
+- l = 5;
+- r = (val >> 7) & 0x1fe;
+- if (r > 200)
+- r = 200;
+- else if (r < 5)
+- r = 5;
+- rl = (l - 5) / 13;
+- rr = (r - 5) / 13;
+- r = (rl * 13 + 5) / 2;
+- l = (rr * 13 + 5) / 2;
+- write_ctrl(s, 0xb4, (rl << 4) | rr);
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[8] = ((unsigned int)r << 8) | l;
+-#else
+- s->mix.vol[8] = val;
+-#endif
+- return put_user(s->mix.vol[8], p);
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- l = (val << 1) & 0x1fe;
+- if (l > 200)
+- l = 200;
+- else if (l < 5)
+- l = 5;
+- r = (val >> 7) & 0x1fe;
+- if (r > 200)
+- r = 200;
+- else if (r < 5)
+- r = 5;
+- rl = (l - 5) / 13;
+- rr = (r - 5) / 13;
+- r = (rl * 13 + 5) / 2;
+- l = (rr * 13 + 5) / 2;
+- write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
+-#else
+- s->mix.vol[vidx-1] = val;
+-#endif
+- return put_user(s->mix.vol[vidx-1], p);
+- }
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int solo1_open_mixdev(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct solo1_state *s = NULL;
+- struct pci_dev *pci_dev = NULL;
+-
+- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+- struct pci_driver *drvr;
+- drvr = pci_dev_driver (pci_dev);
+- if (drvr != &solo1_driver)
+- continue;
+- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
+- if (!s)
+- continue;
+- if (s->dev_mixer == minor)
+- break;
+- }
+- if (!s)
+- return -ENODEV;
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int solo1_release_mixdev(struct inode *inode, struct file *file)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- return 0;
+-}
+-
+-static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);
+-}
+-
+-static /*const*/ struct file_operations solo1_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = solo1_ioctl_mixdev,
+- .open = solo1_open_mixdev,
+- .release = solo1_release_mixdev,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct solo1_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count;
+- unsigned tmo;
+-
+- if (s->dma_dac.mapped)
+- return 0;
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- for (;;) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return -EBUSY;
+- }
+- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
+- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+- tmo >>= 1;
+- if (s->channels > 1)
+- tmo >>= 1;
+- if (!schedule_timeout(tmo + 1))
+- printk(KERN_DEBUG "solo1: dma timed out??\n");
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t solo1_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+- add_wait_queue(&s->dma_adc.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- swptr = s->dma_adc.swptr;
+- cnt = s->dma_adc.dmasize-swptr;
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+-#ifdef DEBUGREC
+- printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n",
+- read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);
+-#endif
+- if (cnt <= 0) {
+- if (s->dma_adc.enabled)
+- start_adc(s);
+-#ifdef DEBUGREC
+- printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
+- KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
+- KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
+- KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
+- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
+- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
+- inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
+-#endif
+- if (inb(s->ddmabase+15) & 1)
+- printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+-#ifdef DEBUGREC
+- printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
+- KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
+- KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
+- KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
+- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
+- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
+- inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
+-#endif
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_adc.enabled)
+- start_adc(s);
+-#ifdef DEBUGREC
+- printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
+- read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
+-#endif
+- }
+- remove_wait_queue(&s->dma_adc.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-static ssize_t solo1_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac.mapped)
+- return -ENXIO;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+-#if 0
+- printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x 71: 0x%02x 72: 0x%02x 74: 0x%02x 76: 0x%02x 78: 0x%02x 7A: 0x%02x\n"
+- KERN_DEBUG "solo1_write: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x SBstat: 0x%02x\n",
+- read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),
+- read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
+- printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x reg 7A: 0x%02x DMAcnt: 0x%04x DMAstat: 0x%02x SBstat: 0x%02x\n",
+- read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
+-#endif
+- ret = 0;
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = s->dma_dac.hwptr;
+- }
+- swptr = s->dma_dac.swptr;
+- cnt = s->dma_dac.dmasize-swptr;
+- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_dac.enabled)
+- start_dac(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac.swptr = swptr;
+- s->dma_dac.count += cnt;
+- s->dma_dac.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_dac.enabled)
+- start_dac(s);
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac.ready && prog_dmabuf_dac(s))
+- return 0;
+- poll_wait(file, &s->dma_dac.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready && prog_dmabuf_adc(s))
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_update_ptr(s);
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.mapped) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- } else {
+- if (s->dma_adc.count > 0)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-
+-static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- struct dmabuf *db;
+- int ret = -EINVAL;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf_dac(s)) != 0)
+- goto out;
+- db = &s->dma_dac;
+- } else if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf_adc(s)) != 0)
+- goto out;
+- db = &s->dma_adc;
+- } else
+- goto out;
+- ret = -EINVAL;
+- if (vma->vm_pgoff != 0)
+- goto out;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder))
+- goto out;
+- ret = -EAGAIN;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+- db->mapped = 1;
+- ret = 0;
+-out:
+- unlock_kernel();
+- return ret;
+-}
+-
+-static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int val, mapped, ret, count;
+- int div1, div2;
+- unsigned rate1, rate2;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->irq);
+- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- prog_codec(s);
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- stop_adc(s);
+- stop_dac(s);
+- s->dma_adc.ready = s->dma_dac.ready = 0;
+- /* program sampling rates */
+- if (val > 48000)
+- val = 48000;
+- if (val < 6300)
+- val = 6300;
+- div1 = (768000 + val / 2) / val;
+- rate1 = (768000 + div1 / 2) / div1;
+- div1 = -div1;
+- div2 = (793800 + val / 2) / val;
+- rate2 = (793800 + div2 / 2) / div2;
+- div2 = (-div2) & 0x7f;
+- if (abs(val - rate2) < abs(val - rate1)) {
+- rate1 = rate2;
+- div1 = div2;
+- }
+- s->rate = rate1;
+- s->clkdiv = div1;
+- prog_codec(s);
+- }
+- return put_user(s->rate, p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- stop_adc(s);
+- stop_dac(s);
+- s->dma_adc.ready = s->dma_dac.ready = 0;
+- /* program channels */
+- s->channels = val ? 2 : 1;
+- prog_codec(s);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 0) {
+- stop_adc(s);
+- stop_dac(s);
+- s->dma_adc.ready = s->dma_dac.ready = 0;
+- /* program channels */
+- s->channels = (val >= 2) ? 2 : 1;
+- prog_codec(s);
+- }
+- return put_user(s->channels, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- stop_adc(s);
+- stop_dac(s);
+- s->dma_adc.ready = s->dma_dac.ready = 0;
+- /* program format */
+- if (val != AFMT_S16_LE && val != AFMT_U16_LE &&
+- val != AFMT_S8 && val != AFMT_U8)
+- val = AFMT_U8;
+- s->fmt = val;
+- prog_codec(s);
+- }
+- return put_user(s->fmt, p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if (file->f_mode & s->ena & FMODE_READ)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & s->ena & FMODE_WRITE)
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+- return ret;
+- s->dma_dac.enabled = 1;
+- start_adc(s);
+- if (inb(s->ddmabase+15) & 1)
+- printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
+- } else {
+- s->dma_dac.enabled = 0;
+- stop_adc(s);
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+- return ret;
+- s->dma_dac.enabled = 1;
+- start_dac(s);
+- } else {
+- s->dma_dac.enabled = 0;
+- stop_dac(s);
+- }
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_update_ptr(s);
+- abinfo.fragsize = s->dma_dac.fragsize;
+- count = s->dma_dac.count;
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = s->dma_dac.dmasize - count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_update_ptr(s);
+- abinfo.fragsize = s->dma_adc.fragsize;
+- abinfo.bytes = s->dma_adc.count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_update_ptr(s);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- return put_user(count, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_update_ptr(s);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_update_ptr(s);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- count = s->dma_dac.count;
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_dac.fragshift;
+- cinfo.ptr = s->dma_dac.hwptr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+-#if 0
+- printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n"
+- KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n",
+- cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
+- s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
+-#endif
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf_dac(s)))
+- return val;
+- return put_user(s->dma_dac.fragsize, p);
+- }
+- if ((val = prog_dmabuf_adc(s)))
+- return val;
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE)
+- s->dma_dac.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user(s->rate, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user(s->channels, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+- return mixer_ioctl(s, cmd, arg);
+-}
+-
+-static int solo1_release(struct inode *inode, struct file *file)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- outb(0, s->iobase+6); /* disable DMA */
+- dealloc_dmabuf(s, &s->dma_dac);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- outb(1, s->ddmabase+0xf); /* mask DMA channel */
+- outb(0, s->ddmabase+0xd); /* DMA master clear */
+- dealloc_dmabuf(s, &s->dma_adc);
+- }
+- s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static int solo1_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- struct solo1_state *s = NULL;
+- struct pci_dev *pci_dev = NULL;
+-
+- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+- struct pci_driver *drvr;
+-
+- drvr = pci_dev_driver(pci_dev);
+- if (drvr != &solo1_driver)
+- continue;
+- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
+- if (!s)
+- continue;
+- if (!((s->dev_audio ^ minor) & ~0xf))
+- break;
+- }
+- if (!s)
+- return -ENODEV;
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- s->fmt = AFMT_U8;
+- s->channels = 1;
+- s->rate = 8000;
+- s->clkdiv = 96 | 0x80;
+- s->ena = 0;
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+- s->dma_adc.enabled = 1;
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+- s->dma_dac.enabled = 1;
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- mutex_unlock(&s->open_mutex);
+- prog_codec(s);
+- return nonseekable_open(inode, file);
+-}
+-
+-static /*const*/ struct file_operations solo1_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = solo1_read,
+- .write = solo1_write,
+- .poll = solo1_poll,
+- .ioctl = solo1_ioctl,
+- .mmap = solo1_mmap,
+- .open = solo1_open,
+- .release = solo1_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-/* hold spinlock for the following! */
+-static void solo1_handle_midi(struct solo1_state *s)
+-{
+- unsigned char ch;
+- int wake;
+-
+- if (!(s->mpubase))
+- return;
+- wake = 0;
+- while (!(inb(s->mpubase+1) & 0x80)) {
+- ch = inb(s->mpubase);
+- if (s->midi.icnt < MIDIINBUF) {
+- s->midi.ibuf[s->midi.iwr] = ch;
+- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+- s->midi.icnt++;
+- }
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.iwait);
+- wake = 0;
+- while (!(inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
+- outb(s->midi.obuf[s->midi.ord], s->mpubase);
+- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+- s->midi.ocnt--;
+- if (s->midi.ocnt < MIDIOUTBUF-16)
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.owait);
+-}
+-
+-static irqreturn_t solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct solo1_state *s = (struct solo1_state *)dev_id;
+- unsigned int intsrc;
+-
+- /* fastpath out, to ease interrupt sharing */
+- intsrc = inb(s->iobase+7); /* get interrupt source(s) */
+- if (!intsrc)
+- return IRQ_NONE;
+- (void)inb(s->sbbase+0xe); /* clear interrupt */
+- spin_lock(&s->lock);
+- /* clear audio interrupts first */
+- if (intsrc & 0x20)
+- write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f);
+- solo1_update_ptr(s);
+- solo1_handle_midi(s);
+- spin_unlock(&s->lock);
+- return IRQ_HANDLED;
+-}
+-
+-static void solo1_midi_timer(unsigned long data)
+-{
+- struct solo1_state *s = (struct solo1_state *)data;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->midi.timer.expires = jiffies+1;
+- add_timer(&s->midi.timer);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t solo1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- if (count == 0)
+- return 0;
+- ret = 0;
+- add_wait_queue(&s->midi.iwait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.ird;
+- cnt = MIDIINBUF - ptr;
+- if (s->midi.icnt < cnt)
+- cnt = s->midi.icnt;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- ptr = (ptr + cnt) % MIDIINBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.ird = ptr;
+- s->midi.icnt -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- break;
+- }
+- __set_current_state(TASK_RUNNING);
+- remove_wait_queue(&s->midi.iwait, &wait);
+- return ret;
+-}
+-
+-static ssize_t solo1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- if (count == 0)
+- return 0;
+- ret = 0;
+- add_wait_queue(&s->midi.owait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.owr;
+- cnt = MIDIOUTBUF - ptr;
+- if (s->midi.ocnt + cnt > MIDIOUTBUF)
+- cnt = MIDIOUTBUF - s->midi.ocnt;
+- if (cnt <= 0) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- solo1_handle_midi(s);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- ptr = (ptr + cnt) % MIDIOUTBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.owr = ptr;
+- s->midi.ocnt += cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- spin_lock_irqsave(&s->lock, flags);
+- solo1_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- __set_current_state(TASK_RUNNING);
+- remove_wait_queue(&s->midi.owait, &wait);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_flags & FMODE_WRITE)
+- poll_wait(file, &s->midi.owait, wait);
+- if (file->f_flags & FMODE_READ)
+- poll_wait(file, &s->midi.iwait, wait);
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_flags & FMODE_READ) {
+- if (s->midi.icnt > 0)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_flags & FMODE_WRITE) {
+- if (s->midi.ocnt < MIDIOUTBUF)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int solo1_midi_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- struct solo1_state *s = NULL;
+- struct pci_dev *pci_dev = NULL;
+-
+- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+- struct pci_driver *drvr;
+-
+- drvr = pci_dev_driver(pci_dev);
+- if (drvr != &solo1_driver)
+- continue;
+- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
+- if (!s)
+- continue;
+- if (s->dev_midi == minor)
+- break;
+- }
+- if (!s)
+- return -ENODEV;
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- outb(0xff, s->mpubase+1); /* reset command */
+- outb(0x3f, s->mpubase+1); /* uart command */
+- if (!(inb(s->mpubase+1) & 0x80))
+- inb(s->mpubase);
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */
+- init_timer(&s->midi.timer);
+- s->midi.timer.expires = jiffies+1;
+- s->midi.timer.data = (unsigned long)s;
+- s->midi.timer.function = solo1_midi_timer;
+- add_timer(&s->midi.timer);
+- }
+- if (file->f_mode & FMODE_READ) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int solo1_midi_release(struct inode *inode, struct file *file)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- unsigned count, tmo;
+-
+- VALIDATE_STATE(s);
+-
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE) {
+- add_wait_queue(&s->midi.owait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->midi.ocnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (file->f_flags & O_NONBLOCK)
+- break;
+- tmo = (count * HZ) / 3100;
+- if (!schedule_timeout(tmo ? : 1) && tmo)
+- printk(KERN_DEBUG "solo1: midi timed out??\n");
+- }
+- remove_wait_queue(&s->midi.owait, &wait);
+- set_current_state(TASK_RUNNING);
+- }
+- mutex_lock(&s->open_mutex);
+- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
+- del_timer(&s->midi.timer);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations solo1_midi_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = solo1_midi_read,
+- .write = solo1_midi_write,
+- .poll = solo1_midi_poll,
+- .open = solo1_midi_open,
+- .release = solo1_midi_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- static const unsigned char op_offset[18] = {
+- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
+- };
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- struct dm_fm_voice v;
+- struct dm_fm_note n;
+- struct dm_fm_params p;
+- unsigned int io;
+- unsigned int regb;
+-
+- switch (cmd) {
+- case FM_IOCTL_RESET:
+- for (regb = 0xb0; regb < 0xb9; regb++) {
+- outb(regb, s->sbbase);
+- outb(0, s->sbbase+1);
+- outb(regb, s->sbbase+2);
+- outb(0, s->sbbase+3);
+- }
+- return 0;
+-
+- case FM_IOCTL_PLAY_NOTE:
+- if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
+- return -EFAULT;
+- if (n.voice >= 18)
+- return -EINVAL;
+- if (n.voice >= 9) {
+- regb = n.voice - 9;
+- io = s->sbbase+2;
+- } else {
+- regb = n.voice;
+- io = s->sbbase;
+- }
+- outb(0xa0 + regb, io);
+- outb(n.fnum & 0xff, io+1);
+- outb(0xb0 + regb, io);
+- outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
+- return 0;
+-
+- case FM_IOCTL_SET_VOICE:
+- if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
+- return -EFAULT;
+- if (v.voice >= 18)
+- return -EINVAL;
+- regb = op_offset[v.voice];
+- io = s->sbbase + ((v.op & 1) << 1);
+- outb(0x20 + regb, io);
+- outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
+- ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
+- outb(0x40 + regb, io);
+- outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
+- outb(0x60 + regb, io);
+- outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
+- outb(0x80 + regb, io);
+- outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
+- outb(0xe0 + regb, io);
+- outb(v.waveform & 0x7, io+1);
+- if (n.voice >= 9) {
+- regb = n.voice - 9;
+- io = s->sbbase+2;
+- } else {
+- regb = n.voice;
+- io = s->sbbase;
+- }
+- outb(0xc0 + regb, io);
+- outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
+- (v.connection & 1), io+1);
+- return 0;
+-
+- case FM_IOCTL_SET_PARAMS:
+- if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
+- return -EFAULT;
+- outb(0x08, s->sbbase);
+- outb((p.kbd_split & 1) << 6, s->sbbase+1);
+- outb(0xbd, s->sbbase);
+- outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
+- ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);
+- return 0;
+-
+- case FM_IOCTL_SET_OPL:
+- outb(4, s->sbbase+2);
+- outb(arg, s->sbbase+3);
+- return 0;
+-
+- case FM_IOCTL_SET_MODE:
+- outb(5, s->sbbase+2);
+- outb(arg & 1, s->sbbase+3);
+- return 0;
+-
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static int solo1_dmfm_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- struct solo1_state *s = NULL;
+- struct pci_dev *pci_dev = NULL;
+-
+- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+- struct pci_driver *drvr;
+-
+- drvr = pci_dev_driver(pci_dev);
+- if (drvr != &solo1_driver)
+- continue;
+- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
+- if (!s)
+- continue;
+- if (s->dev_dmfm == minor)
+- break;
+- }
+- if (!s)
+- return -ENODEV;
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & FMODE_DMFM) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {
+- mutex_unlock(&s->open_mutex);
+- printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
+- return -EBUSY;
+- }
+- /* init the stuff */
+- outb(1, s->sbbase);
+- outb(0x20, s->sbbase+1); /* enable waveforms */
+- outb(4, s->sbbase+2);
+- outb(0, s->sbbase+3); /* no 4op enabled */
+- outb(5, s->sbbase+2);
+- outb(1, s->sbbase+3); /* enable OPL3 */
+- s->open_mode |= FMODE_DMFM;
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int solo1_dmfm_release(struct inode *inode, struct file *file)
+-{
+- struct solo1_state *s = (struct solo1_state *)file->private_data;
+- unsigned int regb;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- mutex_lock(&s->open_mutex);
+- s->open_mode &= ~FMODE_DMFM;
+- for (regb = 0xb0; regb < 0xb9; regb++) {
+- outb(regb, s->sbbase);
+- outb(0, s->sbbase+1);
+- outb(regb, s->sbbase+2);
+- outb(0, s->sbbase+3);
+- }
+- release_region(s->sbbase, FMSYNTH_EXTENT);
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations solo1_dmfm_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = solo1_dmfm_ioctl,
+- .open = solo1_dmfm_open,
+- .release = solo1_dmfm_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static struct initvol {
+- int mixch;
+- int vol;
+-} initvol[] __devinitdata = {
+- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
+- { SOUND_MIXER_WRITE_PCM, 0x4040 },
+- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
+- { SOUND_MIXER_WRITE_CD, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
+- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
+- { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
+- { SOUND_MIXER_WRITE_MIC, 0x4040 }
+-};
+-
+-static int setup_solo1(struct solo1_state *s)
+-{
+- struct pci_dev *pcidev = s->dev;
+- mm_segment_t fs;
+- int i, val;
+-
+- /* initialize DDMA base address */
+- printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
+- pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);
+- /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
+- pci_write_config_dword(pcidev, 0x50, 0);
+- /* disable legacy audio address decode */
+- pci_write_config_word(pcidev, 0x40, 0x907f);
+-
+- /* initialize the chips */
+- if (!reset_ctrl(s)) {
+- printk(KERN_ERR "esssolo1: cannot reset controller\n");
+- return -1;
+- }
+- outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
+-
+- /* initialize mixer regs */
+- write_mixer(s, 0x7f, 0); /* disable music digital recording */
+- write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
+- write_mixer(s, 0x64, 0x45); /* volume control */
+- write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
+- write_mixer(s, 0x50, 0); /* disable spatializer */
+- write_mixer(s, 0x52, 0);
+- write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
+- write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
+- outb(0, s->ddmabase+0xd); /* DMA master clear */
+- outb(1, s->ddmabase+0xf); /* mask channel */
+- /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
+-
+- pci_set_master(pcidev); /* enable bus mastering */
+-
+- fs = get_fs();
+- set_fs(KERNEL_DS);
+- val = SOUND_MASK_LINE;
+- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+- val = initvol[i].vol;
+- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+- }
+- val = 1; /* enable mic preamp */
+- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
+- set_fs(fs);
+- return 0;
+-}
+-
+-static int
+-solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) {
+- struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
+- if (!s)
+- return 1;
+- outb(0, s->iobase+6);
+- /* DMA master clear */
+- outb(0, s->ddmabase+0xd);
+- /* reset sequencer and FIFO */
+- outb(3, s->sbbase+6);
+- /* turn off DDMA controller address space */
+- pci_write_config_word(s->dev, 0x60, 0);
+- return 0;
+-}
+-
+-static int
+-solo1_resume(struct pci_dev *pci_dev) {
+- struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
+- if (!s)
+- return 1;
+- setup_solo1(s);
+- return 0;
+-}
+-
+-#ifdef SUPPORT_JOYSTICK
+-static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
+-{
+- struct gameport *gp;
+-
+- if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
+- printk(KERN_ERR "solo1: gameport io ports are in use\n");
+- return -EBUSY;
+- }
+-
+- s->gameport = gp = gameport_allocate_port();
+- if (!gp) {
+- printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
+- release_region(io_port, GAMEPORT_EXTENT);
+- return -ENOMEM;
+- }
+-
+- gameport_set_name(gp, "ESS Solo1 Gameport");
+- gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+- gp->dev.parent = &s->dev->dev;
+- gp->io = io_port;
+-
+- gameport_register_port(gp);
+-
+- 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;
+- int gpio;
+- int ret;
+-
+- if ((ret=pci_enable_device(pcidev)))
+- return ret;
+- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
+- !(pci_resource_flags(pcidev, 1) & IORESOURCE_IO) ||
+- !(pci_resource_flags(pcidev, 2) & IORESOURCE_IO) ||
+- !(pci_resource_flags(pcidev, 3) & IORESOURCE_IO))
+- return -ENODEV;
+- if (pcidev->irq == 0)
+- return -ENODEV;
+-
+- /* Recording requires 24-bit DMA, so attempt to set dma mask
+- * to 24 bits first, then 32 bits (playback only) if that fails.
+- */
+- if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) &&
+- 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;
+- }
+-
+- if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
+- printk(KERN_WARNING "solo1: out of memory\n");
+- return -ENOMEM;
+- }
+- memset(s, 0, sizeof(struct solo1_state));
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- init_waitqueue_head(&s->midi.iwait);
+- init_waitqueue_head(&s->midi.owait);
+- mutex_init(&s->open_mutex);
+- spin_lock_init(&s->lock);
+- s->magic = SOLO1_MAGIC;
+- s->dev = pcidev;
+- s->iobase = pci_resource_start(pcidev, 0);
+- s->sbbase = pci_resource_start(pcidev, 1);
+- s->vcbase = pci_resource_start(pcidev, 2);
+- s->ddmabase = s->vcbase + DDMABASE_OFFSET;
+- s->mpubase = pci_resource_start(pcidev, 3);
+- gpio = pci_resource_start(pcidev, 4);
+- s->irq = pcidev->irq;
+- ret = -EBUSY;
+- if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
+- printk(KERN_ERR "solo1: io ports in use\n");
+- goto err_region1;
+- }
+- if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) {
+- printk(KERN_ERR "solo1: io ports in use\n");
+- goto err_region2;
+- }
+- if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) {
+- printk(KERN_ERR "solo1: io ports in use\n");
+- goto err_region3;
+- }
+- if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) {
+- printk(KERN_ERR "solo1: io ports in use\n");
+- goto err_region4;
+- }
+- if ((ret=request_irq(s->irq,solo1_interrupt,IRQF_SHARED,"ESS Solo1",s))) {
+- printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
+- goto err_irq;
+- }
+- /* register devices */
+- if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
+- ret = s->dev_audio;
+- goto err_dev1;
+- }
+- if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) {
+- ret = s->dev_mixer;
+- goto err_dev2;
+- }
+- if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) {
+- ret = s->dev_midi;
+- goto err_dev3;
+- }
+- if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) {
+- ret = s->dev_dmfm;
+- goto err_dev4;
+- }
+- if (setup_solo1(s)) {
+- ret = -EIO;
+- goto err;
+- }
+- /* register gameport */
+- solo1_register_gameport(s, gpio);
+- /* store it in the driver field */
+- pci_set_drvdata(pcidev, s);
+- return 0;
+-
+- err:
+- unregister_sound_special(s->dev_dmfm);
+- err_dev4:
+- unregister_sound_midi(s->dev_midi);
+- err_dev3:
+- unregister_sound_mixer(s->dev_mixer);
+- err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+- err_dev1:
+- printk(KERN_ERR "solo1: initialisation error\n");
+- free_irq(s->irq, s);
+- err_irq:
+- release_region(s->mpubase, MPUBASE_EXTENT);
+- err_region4:
+- release_region(s->ddmabase, DDMABASE_EXTENT);
+- err_region3:
+- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
+- err_region2:
+- release_region(s->iobase, IOBASE_EXTENT);
+- err_region1:
+- kfree(s);
+- return ret;
+-}
+-
+-static void __devexit solo1_remove(struct pci_dev *dev)
+-{
+- struct solo1_state *s = pci_get_drvdata(dev);
+-
+- if (!s)
+- return;
+- /* stop DMA controller */
+- outb(0, s->iobase+6);
+- outb(0, s->ddmabase+0xd); /* DMA master clear */
+- outb(3, s->sbbase+6); /* reset sequencer and FIFO */
+- synchronize_irq(s->irq);
+- pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
+- free_irq(s->irq, s);
+- 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);
+- release_region(s->mpubase, MPUBASE_EXTENT);
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->dev_mixer);
+- unregister_sound_midi(s->dev_midi);
+- unregister_sound_special(s->dev_dmfm);
+- kfree(s);
+- pci_set_drvdata(dev, NULL);
+-}
+-
+-static struct pci_device_id id_table[] = {
+- { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, id_table);
+-
+-static struct pci_driver solo1_driver = {
+- .name = "ESS Solo1",
+- .id_table = id_table,
+- .probe = solo1_probe,
+- .remove = __devexit_p(solo1_remove),
+- .suspend = solo1_suspend,
+- .resume = solo1_resume,
+-};
+-
+-
+-static int __init init_solo1(void)
+-{
+- printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
+- return pci_register_driver(&solo1_driver);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-MODULE_AUTHOR("Thomas M. Sailer, sailer at ife.ee.ethz.ch, hb9jnx at hb9w.che.eu");
+-MODULE_DESCRIPTION("ESS Solo1 Driver");
+-MODULE_LICENSE("GPL");
+-
+-
+-static void __exit cleanup_solo1(void)
+-{
+- printk(KERN_INFO "solo1: unloading\n");
+- pci_unregister_driver(&solo1_driver);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-module_init(init_solo1);
+-module_exit(cleanup_solo1);
+-
+diff --git a/sound/oss/forte.c b/sound/oss/forte.c
+deleted file mode 100644
+index ea1c020..0000000
+--- a/sound/oss/forte.c
++++ /dev/null
+@@ -1,2139 +0,0 @@
+-/*
+- * forte.c - ForteMedia FM801 OSS Driver
+- *
+- * Written by Martin K. Petersen <mkp at mkp.net>
+- * Copyright (C) 2002 Hewlett-Packard Company
+- * Portions Copyright (C) 2003 Martin K. Petersen
+- *
+- * Latest version: http://mkp.net/forte/
+- *
+- * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers
+- * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik. Thanks
+- * guys!
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License version
+- * 2 as published by the Free Software Foundation.
+- *
+- * This 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/module.h>
+-#include <linux/kernel.h>
+-
+-#include <linux/init.h>
+-#include <linux/spinlock.h>
+-#include <linux/pci.h>
+-
+-#include <linux/delay.h>
+-#include <linux/poll.h>
+-
+-#include <linux/sound.h>
+-#include <linux/ac97_codec.h>
+-#include <linux/interrupt.h>
+-
+-#include <linux/proc_fs.h>
+-#include <linux/mutex.h>
+-
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-
+-#define DRIVER_NAME "forte"
+-#define DRIVER_VERSION "$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $"
+-#define PFX DRIVER_NAME ": "
+-
+-#undef M_DEBUG
+-
+-#ifdef M_DEBUG
+-#define DPRINTK(args...) printk(KERN_WARNING args)
+-#else
+-#define DPRINTK(args...)
+-#endif
+-
+-/* Card capabilities */
+-#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER)
+-
+-/* Supported audio formats */
+-#define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE)
+-
+-/* Buffers */
+-#define FORTE_MIN_FRAG_SIZE 256
+-#define FORTE_MAX_FRAG_SIZE PAGE_SIZE
+-#define FORTE_DEF_FRAG_SIZE 256
+-#define FORTE_MIN_FRAGMENTS 2
+-#define FORTE_MAX_FRAGMENTS 256
+-#define FORTE_DEF_FRAGMENTS 2
+-#define FORTE_MIN_BUF_MSECS 500
+-#define FORTE_MAX_BUF_MSECS 1000
+-
+-/* PCI BARs */
+-#define FORTE_PCM_VOL 0x00 /* PCM Output Volume */
+-#define FORTE_FM_VOL 0x02 /* FM Output Volume */
+-#define FORTE_I2S_VOL 0x04 /* I2S Volume */
+-#define FORTE_REC_SRC 0x06 /* Record Source */
+-#define FORTE_PLY_CTRL 0x08 /* Playback Control */
+-#define FORTE_PLY_COUNT 0x0a /* Playback Count */
+-#define FORTE_PLY_BUF1 0x0c /* Playback Buffer I */
+-#define FORTE_PLY_BUF2 0x10 /* Playback Buffer II */
+-#define FORTE_CAP_CTRL 0x14 /* Capture Control */
+-#define FORTE_CAP_COUNT 0x16 /* Capture Count */
+-#define FORTE_CAP_BUF1 0x18 /* Capture Buffer I */
+-#define FORTE_CAP_BUF2 0x1c /* Capture Buffer II */
+-#define FORTE_CODEC_CTRL 0x22 /* Codec Control */
+-#define FORTE_I2S_MODE 0x24 /* I2S Mode Control */
+-#define FORTE_VOLUME 0x26 /* Volume Up/Down/Mute Status */
+-#define FORTE_I2C_CTRL 0x29 /* I2C Control */
+-#define FORTE_AC97_CMD 0x2a /* AC'97 Command */
+-#define FORTE_AC97_DATA 0x2c /* AC'97 Data */
+-#define FORTE_MPU401_DATA 0x30 /* MPU401 Data */
+-#define FORTE_MPU401_CMD 0x31 /* MPU401 Command */
+-#define FORTE_GPIO_CTRL 0x52 /* General Purpose I/O Control */
+-#define FORTE_GEN_CTRL 0x54 /* General Control */
+-#define FORTE_IRQ_MASK 0x56 /* Interrupt Mask */
+-#define FORTE_IRQ_STATUS 0x5a /* Interrupt Status */
+-#define FORTE_OPL3_BANK0 0x68 /* OPL3 Status Read / Bank 0 Write */
+-#define FORTE_OPL3_DATA0 0x69 /* OPL3 Data 0 Write */
+-#define FORTE_OPL3_BANK1 0x6a /* OPL3 Bank 1 Write */
+-#define FORTE_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */
+-#define FORTE_POWERDOWN 0x70 /* Blocks Power Down Control */
+-
+-#define FORTE_CAP_OFFSET FORTE_CAP_CTRL - FORTE_PLY_CTRL
+-
+-#define FORTE_AC97_ADDR_SHIFT 10
+-
+-/* Playback and record control register bits */
+-#define FORTE_BUF1_LAST (1<<1)
+-#define FORTE_BUF2_LAST (1<<2)
+-#define FORTE_START (1<<5)
+-#define FORTE_PAUSE (1<<6)
+-#define FORTE_IMMED_STOP (1<<7)
+-#define FORTE_RATE_SHIFT 8
+-#define FORTE_RATE_MASK (15 << FORTE_RATE_SHIFT)
+-#define FORTE_CHANNELS_4 (1<<12) /* Playback only */
+-#define FORTE_CHANNELS_6 (2<<12) /* Playback only */
+-#define FORTE_CHANNELS_6MS (3<<12) /* Playback only */
+-#define FORTE_CHANNELS_MASK (3<<12)
+-#define FORTE_16BIT (1<<14)
+-#define FORTE_STEREO (1<<15)
+-
+-/* IRQ status bits */
+-#define FORTE_IRQ_PLAYBACK (1<<8)
+-#define FORTE_IRQ_CAPTURE (1<<9)
+-#define FORTE_IRQ_VOLUME (1<<14)
+-#define FORTE_IRQ_MPU (1<<15)
+-
+-/* CODEC control */
+-#define FORTE_CC_CODEC_RESET (1<<5)
+-#define FORTE_CC_AC97_RESET (1<<6)
+-
+-/* AC97 cmd */
+-#define FORTE_AC97_WRITE (0<<7)
+-#define FORTE_AC97_READ (1<<7)
+-#define FORTE_AC97_DP_INVALID (0<<8)
+-#define FORTE_AC97_DP_VALID (1<<8)
+-#define FORTE_AC97_PORT_RDY (0<<9)
+-#define FORTE_AC97_PORT_BSY (1<<9)
+-
+-
+-struct forte_channel {
+- const char *name;
+-
+- unsigned short ctrl; /* Ctrl BAR contents */
+- unsigned long iobase; /* Ctrl BAR address */
+-
+- wait_queue_head_t wait;
+-
+- void *buf; /* Buffer */
+- dma_addr_t buf_handle; /* Buffer handle */
+-
+- unsigned int record;
+- unsigned int format;
+- unsigned int rate;
+- unsigned int stereo;
+-
+- unsigned int frag_sz; /* Current fragment size */
+- unsigned int frag_num; /* Current # of fragments */
+- unsigned int frag_msecs; /* Milliseconds per frag */
+- unsigned int buf_sz; /* Current buffer size */
+-
+- unsigned int hwptr; /* Tail */
+- unsigned int swptr; /* Head */
+- unsigned int filled_frags; /* Fragments currently full */
+- unsigned int next_buf; /* Index of next buffer */
+-
+- unsigned int active; /* Channel currently in use */
+- unsigned int mapped; /* mmap */
+-
+- unsigned int buf_pages; /* Real size of buffer */
+- unsigned int nr_irqs; /* Number of interrupts */
+- unsigned int bytes; /* Total bytes */
+- unsigned int residue; /* Partial fragment */
+-};
+-
+-
+-struct forte_chip {
+- struct pci_dev *pci_dev;
+- unsigned long iobase;
+- int irq;
+-
+- struct mutex open_mutex; /* Device access */
+- spinlock_t lock; /* State */
+-
+- spinlock_t ac97_lock;
+- struct ac97_codec *ac97;
+-
+- int multichannel;
+- int dsp; /* OSS handle */
+- int trigger; /* mmap I/O trigger */
+-
+- struct forte_channel play;
+- struct forte_channel rec;
+-};
+-
+-
+-static int channels[] = { 2, 4, 6, };
+-static int rates[] = { 5500, 8000, 9600, 11025, 16000, 19200,
+- 22050, 32000, 38400, 44100, 48000, };
+-
+-static struct forte_chip *forte;
+-static int found;
+-
+-
+-/* AC97 Codec -------------------------------------------------------------- */
+-
+-
+-/**
+- * forte_ac97_wait:
+- * @chip: fm801 instance whose AC97 codec to wait on
+- *
+- * FIXME:
+- * Stop busy-waiting
+- */
+-
+-static inline int
+-forte_ac97_wait (struct forte_chip *chip)
+-{
+- int i = 10000;
+-
+- while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY)
+- && i-- )
+- cpu_relax();
+-
+- return i == 0;
+-}
+-
+-
+-/**
+- * forte_ac97_read:
+- * @codec: AC97 codec to read from
+- * @reg: register to read
+- */
+-
+-static u16
+-forte_ac97_read (struct ac97_codec *codec, u8 reg)
+-{
+- u16 ret = 0;
+- struct forte_chip *chip = codec->private_data;
+-
+- spin_lock (&chip->ac97_lock);
+-
+- /* Knock, knock */
+- if (forte_ac97_wait (chip)) {
+- printk (KERN_ERR PFX "ac97_read: Serial bus busy\n");
+- goto out;
+- }
+-
+- /* Send read command */
+- outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD);
+-
+- if (forte_ac97_wait (chip)) {
+- printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n",
+- reg);
+- goto out;
+- }
+-
+- /* Sanity checking */
+- if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) {
+- printk (KERN_ERR PFX "ac97_read: Invalid data port");
+- goto out;
+- }
+-
+- /* Fetch result */
+- ret = inw (chip->iobase + FORTE_AC97_DATA);
+-
+- out:
+- spin_unlock (&chip->ac97_lock);
+- return ret;
+-}
+-
+-
+-/**
+- * forte_ac97_write:
+- * @codec: AC97 codec to send command to
+- * @reg: register to write
+- * @val: value to write
+- */
+-
+-static void
+-forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val)
+-{
+- struct forte_chip *chip = codec->private_data;
+-
+- spin_lock (&chip->ac97_lock);
+-
+- /* Knock, knock */
+- if (forte_ac97_wait (chip)) {
+- printk (KERN_ERR PFX "ac97_write: Serial bus busy\n");
+- goto out;
+- }
+-
+- outw (val, chip->iobase + FORTE_AC97_DATA);
+- outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD);
+-
+- /* Wait for completion */
+- if (forte_ac97_wait (chip)) {
+- printk (KERN_ERR PFX "ac97_write: Bus busy after write\n");
+- goto out;
+- }
+-
+- out:
+- spin_unlock (&chip->ac97_lock);
+-}
+-
+-
+-/* Mixer ------------------------------------------------------------------- */
+-
+-
+-/**
+- * forte_mixer_open:
+- * @inode:
+- * @file:
+- */
+-
+-static int
+-forte_mixer_open (struct inode *inode, struct file *file)
+-{
+- struct forte_chip *chip = forte;
+- file->private_data = chip->ac97;
+- return 0;
+-}
+-
+-
+-/**
+- * forte_mixer_release:
+- * @inode:
+- * @file:
+- */
+-
+-static int
+-forte_mixer_release (struct inode *inode, struct file *file)
+-{
+- /* We will welease Wodewick */
+- return 0;
+-}
+-
+-
+-/**
+- * forte_mixer_ioctl:
+- * @inode:
+- * @file:
+- */
+-
+-static int
+-forte_mixer_ioctl (struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
+-
+- return codec->mixer_ioctl (codec, cmd, arg);
+-}
+-
+-
+-static struct file_operations forte_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = forte_mixer_ioctl,
+- .open = forte_mixer_open,
+- .release = forte_mixer_release,
+-};
+-
+-
+-/* Channel ----------------------------------------------------------------- */
+-
+-/**
+- * forte_channel_reset:
+- * @channel: Channel to reset
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static void
+-forte_channel_reset (struct forte_channel *channel)
+-{
+- if (!channel || !channel->iobase)
+- return;
+-
+- DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
+-
+- channel->ctrl &= ~FORTE_START;
+- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+-
+- /* We always play at least two fragments, hence these defaults */
+- channel->hwptr = channel->frag_sz;
+- channel->next_buf = 1;
+- channel->swptr = 0;
+- channel->filled_frags = 0;
+- channel->active = 0;
+- channel->bytes = 0;
+- channel->nr_irqs = 0;
+- channel->mapped = 0;
+- channel->residue = 0;
+-}
+-
+-
+-/**
+- * forte_channel_start:
+- * @channel: Channel to start (record/playback)
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static void inline
+-forte_channel_start (struct forte_channel *channel)
+-{
+- if (!channel || !channel->iobase || channel->active)
+- return;
+-
+- channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST
+- | FORTE_IMMED_STOP);
+- channel->ctrl |= FORTE_START;
+- channel->active = 1;
+- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+-}
+-
+-
+-/**
+- * forte_channel_stop:
+- * @channel: Channel to stop
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static void inline
+-forte_channel_stop (struct forte_channel *channel)
+-{
+- if (!channel || !channel->iobase)
+- return;
+-
+- channel->ctrl &= ~(FORTE_START | FORTE_PAUSE);
+- channel->ctrl |= FORTE_IMMED_STOP;
+-
+- channel->active = 0;
+- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+-}
+-
+-
+-/**
+- * forte_channel_pause:
+- * @channel: Channel to pause
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static void inline
+-forte_channel_pause (struct forte_channel *channel)
+-{
+- if (!channel || !channel->iobase)
+- return;
+-
+- channel->ctrl |= FORTE_PAUSE;
+-
+- channel->active = 0;
+- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+-}
+-
+-
+-/**
+- * forte_channel_rate:
+- * @channel: Channel whose rate to set. Playback and record are
+- * independent.
+- * @rate: Channel rate in Hz
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static int
+-forte_channel_rate (struct forte_channel *channel, unsigned int rate)
+-{
+- int new_rate;
+-
+- if (!channel || !channel->iobase)
+- return -EINVAL;
+-
+- /* The FM801 only supports a handful of fixed frequencies.
+- * We find the value closest to what userland requested.
+- */
+- if (rate <= 6250) { rate = 5500; new_rate = 0; }
+- else if (rate <= 8800) { rate = 8000; new_rate = 1; }
+- else if (rate <= 10312) { rate = 9600; new_rate = 2; }
+- else if (rate <= 13512) { rate = 11025; new_rate = 3; }
+- else if (rate <= 17600) { rate = 16000; new_rate = 4; }
+- else if (rate <= 20625) { rate = 19200; new_rate = 5; }
+- else if (rate <= 27025) { rate = 22050; new_rate = 6; }
+- else if (rate <= 35200) { rate = 32000; new_rate = 7; }
+- else if (rate <= 41250) { rate = 38400; new_rate = 8; }
+- else if (rate <= 46050) { rate = 44100; new_rate = 9; }
+- else { rate = 48000; new_rate = 10; }
+-
+- channel->ctrl &= ~FORTE_RATE_MASK;
+- channel->ctrl |= new_rate << FORTE_RATE_SHIFT;
+- channel->rate = rate;
+-
+- DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate);
+-
+- return rate;
+-}
+-
+-
+-/**
+- * forte_channel_format:
+- * @channel: Channel whose audio format to set
+- * @format: OSS format ID
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static int
+-forte_channel_format (struct forte_channel *channel, int format)
+-{
+- if (!channel || !channel->iobase)
+- return -EINVAL;
+-
+- switch (format) {
+-
+- case AFMT_QUERY:
+- break;
+-
+- case AFMT_U8:
+- channel->ctrl &= ~FORTE_16BIT;
+- channel->format = AFMT_U8;
+- break;
+-
+- case AFMT_S16_LE:
+- default:
+- channel->ctrl |= FORTE_16BIT;
+- channel->format = AFMT_S16_LE;
+- break;
+- }
+-
+- DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name,
+- format, channel->format);
+-
+- return channel->format;
+-}
+-
+-
+-/**
+- * forte_channel_stereo:
+- * @channel: Channel to toggle
+- * @stereo: 0 for Mono, 1 for Stereo
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static int
+-forte_channel_stereo (struct forte_channel *channel, unsigned int stereo)
+-{
+- int ret;
+-
+- if (!channel || !channel->iobase)
+- return -EINVAL;
+-
+- DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo);
+-
+- switch (stereo) {
+-
+- case 0:
+- channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK);
+- channel-> stereo = stereo;
+- ret = stereo;
+- break;
+-
+- case 1:
+- channel->ctrl &= ~FORTE_CHANNELS_MASK;
+- channel->ctrl |= FORTE_STEREO;
+- channel-> stereo = stereo;
+- ret = stereo;
+- break;
+-
+- default:
+- DPRINTK ("Unsupported channel format");
+- ret = -EINVAL;
+- break;
+- }
+-
+- return ret;
+-}
+-
+-
+-/**
+- * forte_channel_buffer:
+- * @channel: Channel whose buffer to set up
+- *
+- * Locking: Must be called with lock held.
+- */
+-
+-static void
+-forte_channel_buffer (struct forte_channel *channel, int sz, int num)
+-{
+- unsigned int msecs, shift;
+-
+- /* Go away, I'm busy */
+- if (channel->filled_frags || channel->bytes)
+- return;
+-
+- /* Fragment size must be a power of 2 */
+- shift = 0; sz++;
+- while (sz >>= 1)
+- shift++;
+- channel->frag_sz = 1 << shift;
+-
+- /* Round fragment size to something reasonable */
+- if (channel->frag_sz < FORTE_MIN_FRAG_SIZE)
+- channel->frag_sz = FORTE_MIN_FRAG_SIZE;
+-
+- if (channel->frag_sz > FORTE_MAX_FRAG_SIZE)
+- channel->frag_sz = FORTE_MAX_FRAG_SIZE;
+-
+- /* Find fragment length in milliseconds */
+- msecs = channel->frag_sz /
+- (channel->format == AFMT_S16_LE ? 2 : 1) /
+- (channel->stereo ? 2 : 1) /
+- (channel->rate / 1000);
+-
+- channel->frag_msecs = msecs;
+-
+- /* Pick a suitable number of fragments */
+- if (msecs * num < FORTE_MIN_BUF_MSECS)
+- num = FORTE_MIN_BUF_MSECS / msecs;
+-
+- if (msecs * num > FORTE_MAX_BUF_MSECS)
+- num = FORTE_MAX_BUF_MSECS / msecs;
+-
+- /* Fragment number must be a power of 2 */
+- shift = 0;
+- while (num >>= 1)
+- shift++;
+- channel->frag_num = 1 << (shift + 1);
+-
+- /* Round fragment number to something reasonable */
+- if (channel->frag_num < FORTE_MIN_FRAGMENTS)
+- channel->frag_num = FORTE_MIN_FRAGMENTS;
+-
+- if (channel->frag_num > FORTE_MAX_FRAGMENTS)
+- channel->frag_num = FORTE_MAX_FRAGMENTS;
+-
+- channel->buf_sz = channel->frag_sz * channel->frag_num;
+-
+- DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n",
+- __FUNCTION__, channel->name, channel->frag_sz,
+- channel->frag_num, channel->buf_sz);
+-}
+-
+-
+-/**
+- * forte_channel_prep:
+- * @channel: Channel whose buffer to prepare
+- *
+- * Locking: Lock held.
+- */
+-
+-static void
+-forte_channel_prep (struct forte_channel *channel)
+-{
+- struct page *page;
+- int i;
+-
+- if (channel->buf)
+- return;
+-
+- forte_channel_buffer (channel, channel->frag_sz, channel->frag_num);
+- channel->buf_pages = channel->buf_sz >> PAGE_SHIFT;
+-
+- if (channel->buf_sz % PAGE_SIZE)
+- channel->buf_pages++;
+-
+- DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n",
+- __FUNCTION__, channel->name, channel->frag_sz,
+- channel->frag_num, channel->buf_sz, channel->buf_pages);
+-
+- /* DMA buffer */
+- channel->buf = pci_alloc_consistent (forte->pci_dev,
+- channel->buf_pages * PAGE_SIZE,
+- &channel->buf_handle);
+-
+- if (!channel->buf || !channel->buf_handle)
+- BUG();
+-
+- page = virt_to_page (channel->buf);
+-
+- /* FIXME: can this go away ? */
+- for (i = 0 ; i < channel->buf_pages ; i++)
+- SetPageReserved(page++);
+-
+- /* Prep buffer registers */
+- outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT);
+- outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1);
+- outl (channel->buf_handle + channel->frag_sz,
+- channel->iobase + FORTE_PLY_BUF2);
+-
+- /* Reset hwptr */
+- channel->hwptr = channel->frag_sz;
+- channel->next_buf = 1;
+-
+- DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name,
+- channel->buf, channel->buf_handle);
+-}
+-
+-
+-/**
+- * forte_channel_drain:
+- * @chip:
+- * @channel:
+- *
+- * Locking: Don't hold the lock.
+- */
+-
+-static inline int
+-forte_channel_drain (struct forte_channel *channel)
+-{
+- DECLARE_WAITQUEUE (wait, current);
+- unsigned long flags;
+-
+- DPRINTK ("%s\n", __FUNCTION__);
+-
+- if (channel->mapped) {
+- spin_lock_irqsave (&forte->lock, flags);
+- forte_channel_stop (channel);
+- spin_unlock_irqrestore (&forte->lock, flags);
+- return 0;
+- }
+-
+- spin_lock_irqsave (&forte->lock, flags);
+- add_wait_queue (&channel->wait, &wait);
+-
+- for (;;) {
+- if (channel->active == 0 || channel->filled_frags == 1)
+- break;
+-
+- spin_unlock_irqrestore (&forte->lock, flags);
+-
+- __set_current_state (TASK_INTERRUPTIBLE);
+- schedule();
+-
+- spin_lock_irqsave (&forte->lock, flags);
+- }
+-
+- forte_channel_stop (channel);
+- forte_channel_reset (channel);
+- set_current_state (TASK_RUNNING);
+- remove_wait_queue (&channel->wait, &wait);
+- spin_unlock_irqrestore (&forte->lock, flags);
+-
+- return 0;
+-}
+-
+-
+-/**
+- * forte_channel_init:
+- * @chip: Forte chip instance the channel hangs off
+- * @channel: Channel to initialize
+- *
+- * Description:
+- * Initializes a channel, sets defaults, and allocates
+- * buffers.
+- *
+- * Locking: No lock held.
+- */
+-
+-static int
+-forte_channel_init (struct forte_chip *chip, struct forte_channel *channel)
+-{
+- DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase);
+-
+- spin_lock_irq (&chip->lock);
+- memset (channel, 0x0, sizeof (*channel));
+-
+- if (channel == &chip->play) {
+- channel->name = "PCM_OUT";
+- channel->iobase = chip->iobase;
+- DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__,
+- (void *) channel->iobase);
+- }
+- else if (channel == &chip->rec) {
+- channel->name = "PCM_IN";
+- channel->iobase = chip->iobase + FORTE_CAP_OFFSET;
+- channel->record = 1;
+- DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__,
+- (void *) channel->iobase);
+- }
+- else
+- BUG();
+-
+- init_waitqueue_head (&channel->wait);
+-
+- /* Defaults: 48kHz, 16-bit, stereo */
+- channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL);
+- forte_channel_reset (channel);
+- forte_channel_stereo (channel, 1);
+- forte_channel_format (channel, AFMT_S16_LE);
+- forte_channel_rate (channel, 48000);
+- channel->frag_sz = FORTE_DEF_FRAG_SIZE;
+- channel->frag_num = FORTE_DEF_FRAGMENTS;
+-
+- chip->trigger = 0;
+- spin_unlock_irq (&chip->lock);
+-
+- return 0;
+-}
+-
+-
+-/**
+- * forte_channel_free:
+- * @chip: Chip this channel hangs off
+- * @channel: Channel to nuke
+- *
+- * Description:
+- * Resets channel and frees buffers.
+- *
+- * Locking: Hold your horses.
+- */
+-
+-static void
+-forte_channel_free (struct forte_chip *chip, struct forte_channel *channel)
+-{
+- DPRINTK ("%s: %s\n", __FUNCTION__, channel->name);
+-
+- if (!channel->buf_handle)
+- return;
+-
+- pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE,
+- channel->buf, channel->buf_handle);
+-
+- memset (channel, 0x0, sizeof (*channel));
+-}
+-
+-
+-/* DSP --------------------------------------------------------------------- */
+-
+-
+-/**
+- * forte_dsp_ioctl:
+- */
+-
+-static int
+-forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+- unsigned long arg)
+-{
+- int ival=0, ret, rval=0, rd, wr, count;
+- struct forte_chip *chip;
+- struct audio_buf_info abi;
+- struct count_info cinfo;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- chip = file->private_data;
+-
+- if (file->f_mode & FMODE_WRITE)
+- wr = 1;
+- else
+- wr = 0;
+-
+- if (file->f_mode & FMODE_READ)
+- rd = 1;
+- else
+- rd = 0;
+-
+- switch (cmd) {
+-
+- case OSS_GETVERSION:
+- return put_user (SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_GETCAPS:
+- DPRINTK ("%s: GETCAPS\n", __FUNCTION__);
+-
+- ival = FORTE_CAPS; /* DUPLEX */
+- return put_user (ival, p);
+-
+- case SNDCTL_DSP_GETFMTS:
+- DPRINTK ("%s: GETFMTS\n", __FUNCTION__);
+-
+- ival = FORTE_FMTS; /* U8, 16LE */
+- return put_user (ival, p);
+-
+- case SNDCTL_DSP_SETFMT: /* U8, 16LE */
+- DPRINTK ("%s: SETFMT\n", __FUNCTION__);
+-
+- if (get_user (ival, p))
+- return -EFAULT;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd) {
+- forte_channel_stop (&chip->rec);
+- rval = forte_channel_format (&chip->rec, ival);
+- }
+-
+- if (wr) {
+- forte_channel_stop (&chip->rec);
+- rval = forte_channel_format (&chip->play, ival);
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user (rval, p);
+-
+- case SNDCTL_DSP_STEREO: /* 0 - mono, 1 - stereo */
+- DPRINTK ("%s: STEREO\n", __FUNCTION__);
+-
+- if (get_user (ival, p))
+- return -EFAULT;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd) {
+- forte_channel_stop (&chip->rec);
+- rval = forte_channel_stereo (&chip->rec, ival);
+- }
+-
+- if (wr) {
+- forte_channel_stop (&chip->rec);
+- rval = forte_channel_stereo (&chip->play, ival);
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user (rval, p);
+-
+- case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */
+- DPRINTK ("%s: CHANNELS\n", __FUNCTION__);
+-
+- if (get_user (ival, p))
+- return -EFAULT;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd) {
+- forte_channel_stop (&chip->rec);
+- rval = forte_channel_stereo (&chip->rec, ival-1) + 1;
+- }
+-
+- if (wr) {
+- forte_channel_stop (&chip->play);
+- rval = forte_channel_stereo (&chip->play, ival-1) + 1;
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user (rval, p);
+-
+- case SNDCTL_DSP_SPEED:
+- DPRINTK ("%s: SPEED\n", __FUNCTION__);
+-
+- if (get_user (ival, p))
+- return -EFAULT;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd) {
+- forte_channel_stop (&chip->rec);
+- rval = forte_channel_rate (&chip->rec, ival);
+- }
+-
+- if (wr) {
+- forte_channel_stop (&chip->play);
+- rval = forte_channel_rate (&chip->play, ival);
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user(rval, p);
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__);
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd)
+- ival = chip->rec.frag_sz;
+-
+- if (wr)
+- ival = chip->play.frag_sz;
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user (ival, p);
+-
+- case SNDCTL_DSP_RESET:
+- DPRINTK ("%s: RESET\n", __FUNCTION__);
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd)
+- forte_channel_reset (&chip->rec);
+-
+- if (wr)
+- forte_channel_reset (&chip->play);
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return 0;
+-
+- case SNDCTL_DSP_SYNC:
+- DPRINTK ("%s: SYNC\n", __FUNCTION__);
+-
+- if (wr)
+- ret = forte_channel_drain (&chip->play);
+-
+- return 0;
+-
+- case SNDCTL_DSP_POST:
+- DPRINTK ("%s: POST\n", __FUNCTION__);
+-
+- if (wr) {
+- spin_lock_irq (&chip->lock);
+-
+- if (chip->play.filled_frags)
+- forte_channel_start (&chip->play);
+-
+- spin_unlock_irq (&chip->lock);
+- }
+-
+- return 0;
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__);
+-
+- if (get_user (ival, p))
+- return -EFAULT;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (rd) {
+- forte_channel_buffer (&chip->rec, ival & 0xffff,
+- (ival >> 16) & 0xffff);
+- ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz;
+- }
+-
+- if (wr) {
+- forte_channel_buffer (&chip->play, ival & 0xffff,
+- (ival >> 16) & 0xffff);
+- ival = (chip->play.frag_num << 16) +chip->play.frag_sz;
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user (ival, p);
+-
+- case SNDCTL_DSP_GETISPACE:
+- DPRINTK ("%s: GETISPACE\n", __FUNCTION__);
+-
+- if (!rd)
+- return -EINVAL;
+-
+- spin_lock_irq (&chip->lock);
+-
+- abi.fragstotal = chip->rec.frag_num;
+- abi.fragsize = chip->rec.frag_sz;
+-
+- if (chip->rec.mapped) {
+- abi.fragments = chip->rec.frag_num - 2;
+- abi.bytes = abi.fragments * abi.fragsize;
+- }
+- else {
+- abi.fragments = chip->rec.filled_frags;
+- abi.bytes = abi.fragments * abi.fragsize;
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETIPTR:
+- DPRINTK ("%s: GETIPTR\n", __FUNCTION__);
+-
+- if (!rd)
+- return -EINVAL;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (chip->rec.active)
+- cinfo.ptr = chip->rec.hwptr;
+- else
+- cinfo.ptr = 0;
+-
+- cinfo.bytes = chip->rec.bytes;
+- cinfo.blocks = chip->rec.nr_irqs;
+- chip->rec.nr_irqs = 0;
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!wr)
+- return -EINVAL;
+-
+- spin_lock_irq (&chip->lock);
+-
+- abi.fragstotal = chip->play.frag_num;
+- abi.fragsize = chip->play.frag_sz;
+-
+- if (chip->play.mapped) {
+- abi.fragments = chip->play.frag_num - 2;
+- abi.bytes = chip->play.buf_sz;
+- }
+- else {
+- abi.fragments = chip->play.frag_num -
+- chip->play.filled_frags;
+-
+- if (chip->play.residue)
+- abi.fragments--;
+-
+- abi.bytes = abi.fragments * abi.fragsize +
+- chip->play.residue;
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!wr)
+- return -EINVAL;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (chip->play.active)
+- cinfo.ptr = chip->play.hwptr;
+- else
+- cinfo.ptr = 0;
+-
+- cinfo.bytes = chip->play.bytes;
+- cinfo.blocks = chip->play.nr_irqs;
+- chip->play.nr_irqs = 0;
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!wr)
+- return -EINVAL;
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (!chip->play.active) {
+- ival = 0;
+- }
+- else if (chip->play.mapped) {
+- count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1;
+- ival = chip->play.frag_sz - count;
+- }
+- else {
+- ival = chip->play.filled_frags * chip->play.frag_sz;
+-
+- if (chip->play.residue)
+- ival += chip->play.frag_sz - chip->play.residue;
+- }
+-
+- spin_unlock_irq (&chip->lock);
+-
+- return put_user (ival, p);
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__);
+-
+- return -EINVAL;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__);
+-
+- return put_user (chip->trigger, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+-
+- if (get_user (ival, p))
+- return -EFAULT;
+-
+- DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival);
+-
+- if (wr) {
+- spin_lock_irq (&chip->lock);
+-
+- if (ival & PCM_ENABLE_OUTPUT)
+- forte_channel_start (&chip->play);
+- else {
+- chip->trigger = 1;
+- forte_channel_prep (&chip->play);
+- forte_channel_stop (&chip->play);
+- }
+-
+- spin_unlock_irq (&chip->lock);
+- }
+- else if (rd) {
+- spin_lock_irq (&chip->lock);
+-
+- if (ival & PCM_ENABLE_INPUT)
+- forte_channel_start (&chip->rec);
+- else {
+- chip->trigger = 1;
+- forte_channel_prep (&chip->rec);
+- forte_channel_stop (&chip->rec);
+- }
+-
+- spin_unlock_irq (&chip->lock);
+- }
+-
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__);
+- return put_user (chip->play.rate, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__);
+- return put_user (chip->play.stereo, p);
+-
+- case SOUND_PCM_READ_BITS:
+- DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__);
+- return put_user (chip->play.format, p);
+-
+- case SNDCTL_DSP_NONBLOCK:
+- DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__);
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- default:
+- DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, argp);
+- break;
+- }
+-
+- return -EINVAL;
+-}
+-
+-
+-/**
+- * forte_dsp_open:
+- */
+-
+-static int
+-forte_dsp_open (struct inode *inode, struct file *file)
+-{
+- struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
+-
+- if (file->f_flags & O_NONBLOCK) {
+- if (!mutex_trylock(&chip->open_mutex)) {
+- DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__);
+- return -EAGAIN;
+- }
+- }
+- else {
+- if (mutex_lock_interruptible(&chip->open_mutex)) {
+- DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
+- return -ERESTARTSYS;
+- }
+- }
+-
+- file->private_data = forte;
+-
+- DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid);
+-
+- if (file->f_mode & FMODE_WRITE)
+- forte_channel_init (forte, &forte->play);
+-
+- if (file->f_mode & FMODE_READ)
+- forte_channel_init (forte, &forte->rec);
+-
+- return nonseekable_open(inode, file);
+-}
+-
+-
+-/**
+- * forte_dsp_release:
+- */
+-
+-static int
+-forte_dsp_release (struct inode *inode, struct file *file)
+-{
+- struct forte_chip *chip = file->private_data;
+- int ret = 0;
+-
+- DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip);
+-
+- if (file->f_mode & FMODE_WRITE) {
+- forte_channel_drain (&chip->play);
+-
+- spin_lock_irq (&chip->lock);
+-
+- forte_channel_free (chip, &chip->play);
+-
+- spin_unlock_irq (&chip->lock);
+- }
+-
+- if (file->f_mode & FMODE_READ) {
+- while (chip->rec.filled_frags > 0)
+- interruptible_sleep_on (&chip->rec.wait);
+-
+- spin_lock_irq (&chip->lock);
+-
+- forte_channel_stop (&chip->rec);
+- forte_channel_free (chip, &chip->rec);
+-
+- spin_unlock_irq (&chip->lock);
+- }
+-
+- mutex_unlock(&chip->open_mutex);
+-
+- return ret;
+-}
+-
+-
+-/**
+- * forte_dsp_poll:
+- *
+- */
+-
+-static unsigned int
+-forte_dsp_poll (struct file *file, struct poll_table_struct *wait)
+-{
+- struct forte_chip *chip;
+- struct forte_channel *channel;
+- unsigned int mask = 0;
+-
+- chip = file->private_data;
+-
+- if (file->f_mode & FMODE_WRITE) {
+- channel = &chip->play;
+-
+- if (channel->active)
+- poll_wait (file, &channel->wait, wait);
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (channel->frag_num - channel->filled_frags > 0)
+- mask |= POLLOUT | POLLWRNORM;
+-
+- spin_unlock_irq (&chip->lock);
+- }
+-
+- if (file->f_mode & FMODE_READ) {
+- channel = &chip->rec;
+-
+- if (channel->active)
+- poll_wait (file, &channel->wait, wait);
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (channel->filled_frags > 0)
+- mask |= POLLIN | POLLRDNORM;
+-
+- spin_unlock_irq (&chip->lock);
+- }
+-
+- return mask;
+-}
+-
+-
+-/**
+- * forte_dsp_mmap:
+- */
+-
+-static int
+-forte_dsp_mmap (struct file *file, struct vm_area_struct *vma)
+-{
+- struct forte_chip *chip;
+- struct forte_channel *channel;
+- unsigned long size;
+- int ret;
+-
+- chip = file->private_data;
+-
+- DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__,
+- vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff);
+-
+- spin_lock_irq (&chip->lock);
+-
+- if (vma->vm_flags & VM_WRITE && chip->play.active) {
+- ret = -EBUSY;
+- goto out;
+- }
+-
+- if (vma->vm_flags & VM_READ && chip->rec.active) {
+- ret = -EBUSY;
+- goto out;
+- }
+-
+- if (file->f_mode & FMODE_WRITE)
+- channel = &chip->play;
+- else if (file->f_mode & FMODE_READ)
+- channel = &chip->rec;
+- else {
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- forte_channel_prep (channel);
+- channel->mapped = 1;
+-
+- if (vma->vm_pgoff != 0) {
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- size = vma->vm_end - vma->vm_start;
+-
+- if (size > channel->buf_pages * PAGE_SIZE) {
+- DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__,
+- size, channel->buf_sz);
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(channel->buf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot)) {
+- DPRINTK ("%s: remap el a no worko\n", __FUNCTION__);
+- ret = -EAGAIN;
+- goto out;
+- }
+-
+- ret = 0;
+-
+- out:
+- spin_unlock_irq (&chip->lock);
+- return ret;
+-}
+-
+-
+-/**
+- * forte_dsp_write:
+- */
+-
+-static ssize_t
+-forte_dsp_write (struct file *file, const char __user *buffer, size_t bytes,
+- loff_t *ppos)
+-{
+- struct forte_chip *chip;
+- struct forte_channel *channel;
+- unsigned int i = bytes, sz = 0;
+- unsigned long flags;
+-
+- if (!access_ok (VERIFY_READ, buffer, bytes))
+- return -EFAULT;
+-
+- chip = (struct forte_chip *) file->private_data;
+-
+- if (!chip)
+- BUG();
+-
+- channel = &chip->play;
+-
+- if (!channel)
+- BUG();
+-
+- spin_lock_irqsave (&chip->lock, flags);
+-
+- /* Set up buffers with the right fragment size */
+- forte_channel_prep (channel);
+-
+- while (i) {
+- /* All fragment buffers in use -> wait */
+- if (channel->frag_num - channel->filled_frags == 0) {
+- DECLARE_WAITQUEUE (wait, current);
+-
+- /* For trigger or non-blocking operation, get out */
+- if (chip->trigger || file->f_flags & O_NONBLOCK) {
+- spin_unlock_irqrestore (&chip->lock, flags);
+- return -EAGAIN;
+- }
+-
+- /* Otherwise wait for buffers */
+- add_wait_queue (&channel->wait, &wait);
+-
+- for (;;) {
+- spin_unlock_irqrestore (&chip->lock, flags);
+-
+- set_current_state (TASK_INTERRUPTIBLE);
+- schedule();
+-
+- spin_lock_irqsave (&chip->lock, flags);
+-
+- if (channel->frag_num - channel->filled_frags)
+- break;
+- }
+-
+- remove_wait_queue (&channel->wait, &wait);
+- set_current_state (TASK_RUNNING);
+-
+- if (signal_pending (current)) {
+- spin_unlock_irqrestore (&chip->lock, flags);
+- return -ERESTARTSYS;
+- }
+- }
+-
+- if (channel->residue)
+- sz = channel->residue;
+- else if (i > channel->frag_sz)
+- sz = channel->frag_sz;
+- else
+- sz = i;
+-
+- spin_unlock_irqrestore (&chip->lock, flags);
+-
+- if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz))
+- return -EFAULT;
+-
+- spin_lock_irqsave (&chip->lock, flags);
+-
+- /* Advance software pointer */
+- buffer += sz;
+- channel->swptr += sz;
+- channel->swptr %= channel->buf_sz;
+- i -= sz;
+-
+- /* Only bump filled_frags if a full fragment has been written */
+- if (channel->swptr % channel->frag_sz == 0) {
+- channel->filled_frags++;
+- channel->residue = 0;
+- }
+- else
+- channel->residue = channel->frag_sz - sz;
+-
+- /* If playback isn't active, start it */
+- if (channel->active == 0 && chip->trigger == 0)
+- forte_channel_start (channel);
+- }
+-
+- spin_unlock_irqrestore (&chip->lock, flags);
+-
+- return bytes - i;
+-}
+-
+-
+-/**
+- * forte_dsp_read:
+- */
+-
+-static ssize_t
+-forte_dsp_read (struct file *file, char __user *buffer, size_t bytes,
+- loff_t *ppos)
+-{
+- struct forte_chip *chip;
+- struct forte_channel *channel;
+- unsigned int i = bytes, sz;
+- unsigned long flags;
+-
+- if (!access_ok (VERIFY_WRITE, buffer, bytes))
+- return -EFAULT;
+-
+- chip = (struct forte_chip *) file->private_data;
+-
+- if (!chip)
+- BUG();
+-
+- channel = &chip->rec;
+-
+- if (!channel)
+- BUG();
+-
+- spin_lock_irqsave (&chip->lock, flags);
+-
+- /* Set up buffers with the right fragment size */
+- forte_channel_prep (channel);
+-
+- /* Start recording */
+- if (!chip->trigger)
+- forte_channel_start (channel);
+-
+- while (i) {
+- /* No fragment buffers in use -> wait */
+- if (channel->filled_frags == 0) {
+- DECLARE_WAITQUEUE (wait, current);
+-
+- /* For trigger mode operation, get out */
+- if (chip->trigger) {
+- spin_unlock_irqrestore (&chip->lock, flags);
+- return -EAGAIN;
+- }
+-
+- add_wait_queue (&channel->wait, &wait);
+-
+- for (;;) {
+- if (channel->active == 0)
+- break;
+-
+- if (channel->filled_frags)
+- break;
+-
+- spin_unlock_irqrestore (&chip->lock, flags);
+-
+- set_current_state (TASK_INTERRUPTIBLE);
+- schedule();
+-
+- spin_lock_irqsave (&chip->lock, flags);
+- }
+-
+- set_current_state (TASK_RUNNING);
+- remove_wait_queue (&channel->wait, &wait);
+- }
+-
+- if (i > channel->frag_sz)
+- sz = channel->frag_sz;
+- else
+- sz = i;
+-
+- spin_unlock_irqrestore (&chip->lock, flags);
+-
+- if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) {
+- DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__);
+- return -EFAULT;
+- }
+-
+- spin_lock_irqsave (&chip->lock, flags);
+-
+- /* Advance software pointer */
+- buffer += sz;
+- if (channel->filled_frags > 0)
+- channel->filled_frags--;
+- channel->swptr += channel->frag_sz;
+- channel->swptr %= channel->buf_sz;
+- i -= sz;
+- }
+-
+- spin_unlock_irqrestore (&chip->lock, flags);
+-
+- return bytes - i;
+-}
+-
+-
+-static struct file_operations forte_dsp_fops = {
+- .owner = THIS_MODULE,
+- .llseek = &no_llseek,
+- .read = &forte_dsp_read,
+- .write = &forte_dsp_write,
+- .poll = &forte_dsp_poll,
+- .ioctl = &forte_dsp_ioctl,
+- .open = &forte_dsp_open,
+- .release = &forte_dsp_release,
+- .mmap = &forte_dsp_mmap,
+-};
+-
+-
+-/* Common ------------------------------------------------------------------ */
+-
+-
+-/**
+- * forte_interrupt:
+- */
+-
+-static irqreturn_t
+-forte_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct forte_chip *chip = dev_id;
+- struct forte_channel *channel = NULL;
+- u16 status, count;
+-
+- status = inw (chip->iobase + FORTE_IRQ_STATUS);
+-
+- /* If this is not for us, get outta here ASAP */
+- if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0)
+- return IRQ_NONE;
+-
+- if (status & FORTE_IRQ_PLAYBACK) {
+- channel = &chip->play;
+-
+- spin_lock (&chip->lock);
+-
+- if (channel->frag_sz == 0)
+- goto pack;
+-
+- /* Declare a fragment done */
+- if (channel->filled_frags > 0)
+- channel->filled_frags--;
+- channel->bytes += channel->frag_sz;
+- channel->nr_irqs++;
+-
+- /* Flip-flop between buffer I and II */
+- channel->next_buf ^= 1;
+-
+- /* Advance hardware pointer by fragment size and wrap around */
+- channel->hwptr += channel->frag_sz;
+- channel->hwptr %= channel->buf_sz;
+-
+- /* Buffer I or buffer II BAR */
+- outl (channel->buf_handle + channel->hwptr,
+- channel->next_buf == 0 ?
+- channel->iobase + FORTE_PLY_BUF1 :
+- channel->iobase + FORTE_PLY_BUF2);
+-
+- /* If the currently playing fragment is last, schedule pause */
+- if (channel->filled_frags == 1)
+- forte_channel_pause (channel);
+-
+- pack:
+- /* Acknowledge interrupt */
+- outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS);
+-
+- if (waitqueue_active (&channel->wait))
+- wake_up_all (&channel->wait);
+-
+- spin_unlock (&chip->lock);
+- }
+-
+- if (status & FORTE_IRQ_CAPTURE) {
+- channel = &chip->rec;
+- spin_lock (&chip->lock);
+-
+- /* One fragment filled */
+- channel->filled_frags++;
+-
+- /* Get # of completed bytes */
+- count = inw (channel->iobase + FORTE_PLY_COUNT) + 1;
+-
+- if (count == 0) {
+- DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__,
+- channel->filled_frags);
+- channel->filled_frags = 0;
+- goto rack;
+- }
+-
+- /* Buffer I or buffer II BAR */
+- outl (channel->buf_handle + channel->hwptr,
+- channel->next_buf == 0 ?
+- channel->iobase + FORTE_PLY_BUF1 :
+- channel->iobase + FORTE_PLY_BUF2);
+-
+- /* Flip-flop between buffer I and II */
+- channel->next_buf ^= 1;
+-
+- /* Advance hardware pointer by fragment size and wrap around */
+- channel->hwptr += channel->frag_sz;
+- channel->hwptr %= channel->buf_sz;
+-
+- /* Out of buffers */
+- if (channel->filled_frags == channel->frag_num - 1)
+- forte_channel_stop (channel);
+- rack:
+- /* Acknowledge interrupt */
+- outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS);
+-
+- spin_unlock (&chip->lock);
+-
+- if (waitqueue_active (&channel->wait))
+- wake_up_all (&channel->wait);
+- }
+-
+- return IRQ_HANDLED;
+-}
+-
+-
+-/**
+- * forte_proc_read:
+- */
+-
+-static int
+-forte_proc_read (char *page, char **start, off_t off, int count,
+- int *eof, void *data)
+-{
+- int i = 0, p_rate, p_chan, r_rate;
+- unsigned short p_reg, r_reg;
+-
+- i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n",
+- DRIVER_VERSION);
+-
+- if (!forte->iobase)
+- return i;
+-
+- p_rate = p_chan = -1;
+- p_reg = inw (forte->iobase + FORTE_PLY_CTRL);
+- p_rate = (p_reg >> 8) & 15;
+- p_chan = (p_reg >> 12) & 3;
+-
+- if (p_rate >= 0 || p_rate <= 10)
+- p_rate = rates[p_rate];
+-
+- if (p_chan >= 0 || p_chan <= 2)
+- p_chan = channels[p_chan];
+-
+- r_rate = -1;
+- r_reg = inw (forte->iobase + FORTE_CAP_CTRL);
+- r_rate = (r_reg >> 8) & 15;
+-
+- if (r_rate >= 0 || r_rate <= 10)
+- r_rate = rates[r_rate];
+-
+- i += sprintf (page + i,
+- " Playback Capture\n"
+- "FIFO empty : %-3s %-3s\n"
+- "Buf1 Last : %-3s %-3s\n"
+- "Buf2 Last : %-3s %-3s\n"
+- "Started : %-3s %-3s\n"
+- "Paused : %-3s %-3s\n"
+- "Immed Stop : %-3s %-3s\n"
+- "Rate : %-5d %-5d\n"
+- "Channels : %-5d -\n"
+- "16-bit : %-3s %-3s\n"
+- "Stereo : %-3s %-3s\n"
+- " \n"
+- "Buffer Sz : %-6d %-6d\n"
+- "Frag Sz : %-6d %-6d\n"
+- "Frag Num : %-6d %-6d\n"
+- "Frag msecs : %-6d %-6d\n"
+- "Used Frags : %-6d %-6d\n"
+- "Mapped : %-3s %-3s\n",
+- p_reg & 1<<0 ? "yes" : "no",
+- r_reg & 1<<0 ? "yes" : "no",
+- p_reg & 1<<1 ? "yes" : "no",
+- r_reg & 1<<1 ? "yes" : "no",
+- p_reg & 1<<2 ? "yes" : "no",
+- r_reg & 1<<2 ? "yes" : "no",
+- p_reg & 1<<5 ? "yes" : "no",
+- r_reg & 1<<5 ? "yes" : "no",
+- p_reg & 1<<6 ? "yes" : "no",
+- r_reg & 1<<6 ? "yes" : "no",
+- p_reg & 1<<7 ? "yes" : "no",
+- r_reg & 1<<7 ? "yes" : "no",
+- p_rate, r_rate,
+- p_chan,
+- p_reg & 1<<14 ? "yes" : "no",
+- r_reg & 1<<14 ? "yes" : "no",
+- p_reg & 1<<15 ? "yes" : "no",
+- r_reg & 1<<15 ? "yes" : "no",
+- forte->play.buf_sz, forte->rec.buf_sz,
+- forte->play.frag_sz, forte->rec.frag_sz,
+- forte->play.frag_num, forte->rec.frag_num,
+- forte->play.frag_msecs, forte->rec.frag_msecs,
+- forte->play.filled_frags, forte->rec.filled_frags,
+- forte->play.mapped ? "yes" : "no",
+- forte->rec.mapped ? "yes" : "no"
+- );
+-
+- return i;
+-}
+-
+-
+-/**
+- * forte_proc_init:
+- *
+- * Creates driver info entries in /proc
+- */
+-
+-static int __init
+-forte_proc_init (void)
+-{
+- if (!proc_mkdir ("driver/forte", NULL))
+- return -EIO;
+-
+- if (!create_proc_read_entry ("driver/forte/chip", 0, NULL, forte_proc_read, forte)) {
+- remove_proc_entry ("driver/forte", NULL);
+- return -EIO;
+- }
+-
+- if (!create_proc_read_entry("driver/forte/ac97", 0, NULL, ac97_read_proc, forte->ac97)) {
+- remove_proc_entry ("driver/forte/chip", NULL);
+- remove_proc_entry ("driver/forte", NULL);
+- return -EIO;
+- }
+-
+- return 0;
+-}
+-
+-
+-/**
+- * forte_proc_remove:
+- *
+- * Removes driver info entries in /proc
+- */
+-
+-static void
+-forte_proc_remove (void)
+-{
+- remove_proc_entry ("driver/forte/ac97", NULL);
+- remove_proc_entry ("driver/forte/chip", NULL);
+- remove_proc_entry ("driver/forte", NULL);
+-}
+-
+-
+-/**
+- * forte_chip_init:
+- * @chip: Chip instance to initialize
+- *
+- * Description:
+- * Resets chip, configures codec and registers the driver with
+- * the sound subsystem.
+- *
+- * Press and hold Start for 8 secs, then switch on Run
+- * and hold for 4 seconds. Let go of Start. Numbers
+- * assume a properly oiled TWG.
+- */
+-
+-static int __devinit
+-forte_chip_init (struct forte_chip *chip)
+-{
+- u8 revision;
+- u16 cmdw;
+- struct ac97_codec *codec;
+-
+- pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision);
+-
+- if (revision >= 0xB1) {
+- chip->multichannel = 1;
+- printk (KERN_INFO PFX "Multi-channel device detected.\n");
+- }
+-
+- /* Reset chip */
+- outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET,
+- chip->iobase + FORTE_CODEC_CTRL);
+- udelay(100);
+- outw (0, chip->iobase + FORTE_CODEC_CTRL);
+-
+- /* Request read from AC97 */
+- outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT),
+- chip->iobase + FORTE_AC97_CMD);
+- mdelay(750);
+-
+- if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) {
+- printk (KERN_INFO PFX "AC97 codec not responding");
+- return -EIO;
+- }
+-
+- /* Init volume */
+- outw (0x0808, chip->iobase + FORTE_PCM_VOL);
+- outw (0x9f1f, chip->iobase + FORTE_FM_VOL);
+- outw (0x8808, chip->iobase + FORTE_I2S_VOL);
+-
+- /* I2S control - I2S mode */
+- outw (0x0003, chip->iobase + FORTE_I2S_MODE);
+-
+- /* Interrupt setup - unmask PLAYBACK & CAPTURE */
+- cmdw = inw (chip->iobase + FORTE_IRQ_MASK);
+- cmdw &= ~0x0003;
+- outw (cmdw, chip->iobase + FORTE_IRQ_MASK);
+-
+- /* Interrupt clear */
+- outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE,
+- chip->iobase + FORTE_IRQ_STATUS);
+-
+- /* Set up the AC97 codec */
+- if ((codec = ac97_alloc_codec()) == NULL)
+- return -ENOMEM;
+- codec->private_data = chip;
+- codec->codec_read = forte_ac97_read;
+- codec->codec_write = forte_ac97_write;
+- codec->id = 0;
+-
+- if (ac97_probe_codec (codec) == 0) {
+- printk (KERN_ERR PFX "codec probe failed\n");
+- ac97_release_codec(codec);
+- return -1;
+- }
+-
+- /* Register mixer */
+- if ((codec->dev_mixer =
+- register_sound_mixer (&forte_mixer_fops, -1)) < 0) {
+- printk (KERN_ERR PFX "couldn't register mixer!\n");
+- ac97_release_codec(codec);
+- return -1;
+- }
+-
+- chip->ac97 = codec;
+-
+- /* Register DSP */
+- if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) {
+- printk (KERN_ERR PFX "couldn't register dsp!\n");
+- return -1;
+- }
+-
+- /* Register with /proc */
+- if (forte_proc_init()) {
+- printk (KERN_ERR PFX "couldn't add entries to /proc!\n");
+- return -1;
+- }
+-
+- return 0;
+-}
+-
+-
+-/**
+- * forte_probe:
+- * @pci_dev: PCI struct for probed device
+- * @pci_id:
+- *
+- * Description:
+- * Allocates chip instance, I/O region, and IRQ
+- */
+-static int __init
+-forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+-{
+- struct forte_chip *chip;
+- int ret = 0;
+-
+- /* FIXME: Support more than one chip */
+- if (found++)
+- return -EIO;
+-
+- /* Ignition */
+- if (pci_enable_device (pci_dev))
+- return -EIO;
+-
+- pci_set_master (pci_dev);
+-
+- /* Allocate chip instance and configure */
+- forte = (struct forte_chip *)
+- kmalloc (sizeof (struct forte_chip), GFP_KERNEL);
+- chip = forte;
+-
+- if (chip == NULL) {
+- printk (KERN_WARNING PFX "Out of memory");
+- return -ENOMEM;
+- }
+-
+- memset (chip, 0, sizeof (struct forte_chip));
+- chip->pci_dev = pci_dev;
+-
+- mutex_init(&chip->open_mutex);
+- spin_lock_init (&chip->lock);
+- spin_lock_init (&chip->ac97_lock);
+-
+- if (! request_region (pci_resource_start (pci_dev, 0),
+- pci_resource_len (pci_dev, 0), DRIVER_NAME)) {
+- printk (KERN_WARNING PFX "Unable to reserve I/O space");
+- ret = -ENOMEM;
+- goto error;
+- }
+-
+- chip->iobase = pci_resource_start (pci_dev, 0);
+- chip->irq = pci_dev->irq;
+-
+- if (request_irq (chip->irq, forte_interrupt, IRQF_SHARED, DRIVER_NAME,
+- chip)) {
+- printk (KERN_WARNING PFX "Unable to reserve IRQ");
+- ret = -EIO;
+- goto error;
+- }
+-
+- pci_set_drvdata (pci_dev, chip);
+-
+- printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n",
+- chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0),
+- chip->irq);
+-
+- /* Power it up */
+- if ((ret = forte_chip_init (chip)) == 0)
+- return 0;
+-
+- error:
+- if (chip->irq)
+- free_irq (chip->irq, chip);
+-
+- if (chip->iobase)
+- release_region (pci_resource_start (pci_dev, 0),
+- pci_resource_len (pci_dev, 0));
+-
+- kfree (chip);
+-
+- return ret;
+-}
+-
+-
+-/**
+- * forte_remove:
+- * @pci_dev: PCI device to unclaim
+- *
+- */
+-
+-static void
+-forte_remove (struct pci_dev *pci_dev)
+-{
+- struct forte_chip *chip = pci_get_drvdata (pci_dev);
+-
+- if (chip == NULL)
+- return;
+-
+- /* Turn volume down to avoid popping */
+- outw (0x1f1f, chip->iobase + FORTE_PCM_VOL);
+- outw (0x1f1f, chip->iobase + FORTE_FM_VOL);
+- outw (0x1f1f, chip->iobase + FORTE_I2S_VOL);
+-
+- forte_proc_remove();
+- free_irq (chip->irq, chip);
+- release_region (chip->iobase, pci_resource_len (pci_dev, 0));
+-
+- unregister_sound_dsp (chip->dsp);
+- unregister_sound_mixer (chip->ac97->dev_mixer);
+- ac97_release_codec(chip->ac97);
+- kfree (chip);
+-
+- printk (KERN_INFO PFX "driver released\n");
+-}
+-
+-
+-static struct pci_device_id forte_pci_ids[] = {
+- { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+- { 0, }
+-};
+-
+-
+-static struct pci_driver forte_pci_driver = {
+- .name = DRIVER_NAME,
+- .id_table = forte_pci_ids,
+- .probe = forte_probe,
+- .remove = forte_remove,
+-
+-};
+-
+-
+-/**
+- * forte_init_module:
+- *
+- */
+-
+-static int __init
+-forte_init_module (void)
+-{
+- printk (KERN_INFO PFX DRIVER_VERSION "\n");
+-
+- return pci_register_driver (&forte_pci_driver);
+-}
+-
+-
+-/**
+- * forte_cleanup_module:
+- *
+- */
+-
+-static void __exit
+-forte_cleanup_module (void)
+-{
+- pci_unregister_driver (&forte_pci_driver);
+-}
+-
+-
+-module_init(forte_init_module);
+-module_exit(forte_cleanup_module);
+-
+-MODULE_AUTHOR("Martin K. Petersen <mkp at mkp.net>");
+-MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE (pci, forte_pci_ids);
+diff --git a/sound/oss/gus.h b/sound/oss/gus.h
+deleted file mode 100644
+index 3d5271b..0000000
+--- a/sound/oss/gus.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-
+-#include "ad1848.h"
+-
+-/* From gus_card.c */
+-int gus_set_midi_irq(int num);
+-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs * dummy);
+-
+-/* From gus_wave.c */
+-int gus_wave_detect(int baseaddr);
+-void gus_wave_init(struct address_info *hw_config);
+-void gus_wave_unload (struct address_info *hw_config);
+-void gus_voice_irq(void);
+-void gus_write8(int reg, unsigned int data);
+-void guswave_dma_irq(void);
+-void gus_delay(void);
+-int gus_default_mixer_ioctl (int dev, unsigned int cmd, void __user *arg);
+-void gus_timer_command (unsigned int addr, unsigned int val);
+-
+-/* From gus_midi.c */
+-void gus_midi_init(struct address_info *hw_config);
+-void gus_midi_interrupt(int dummy);
+-
+-/* From ics2101.c */
+-int ics2101_mixer_init(void);
+diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c
+deleted file mode 100644
+index dbb2977..0000000
+--- a/sound/oss/gus_card.c
++++ /dev/null
+@@ -1,293 +0,0 @@
+-/*
+- * sound/gus_card.c
+- *
+- * Detection routine for the Gravis Ultrasound.
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- *
+- * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
+- * usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
+- * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups.
+- *
+- * Status:
+- * Tested...
+- */
+-
+-
+-#include <linux/config.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-
+-#include "sound_config.h"
+-
+-#include "gus.h"
+-#include "gus_hw.h"
+-
+-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy);
+-
+-int gus_base = 0, gus_irq = 0, gus_dma = 0;
+-int gus_no_wave_dma = 0;
+-extern int gus_wave_volume;
+-extern int gus_pcm_volume;
+-extern int have_gus_max;
+-int gus_pnp_flag = 0;
+-#ifdef CONFIG_SOUND_GUS16
+-static int db16; /* Has a Gus16 AD1848 on it */
+-#endif
+-
+-static void __init attach_gus(struct address_info *hw_config)
+-{
+- gus_wave_init(hw_config);
+-
+- if (sound_alloc_dma(hw_config->dma, "GUS"))
+- printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma);
+- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+- if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
+- printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
+- gus_midi_init(hw_config);
+- if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0)
+- printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
+-
+- return;
+-}
+-
+-static int __init probe_gus(struct address_info *hw_config)
+-{
+- int irq;
+- int io_addr;
+-
+- if (hw_config->card_subtype == 1)
+- gus_pnp_flag = 1;
+-
+- irq = hw_config->irq;
+-
+- if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */
+- if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
+- irq != 11 && irq != 12 && irq != 15)
+- {
+- printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq);
+- return 0;
+- }
+- if (gus_wave_detect(hw_config->io_base))
+- return 1;
+-
+-#ifndef EXCLUDE_GUS_IODETECT
+-
+- /*
+- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+- */
+-
+- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) {
+- if (io_addr == hw_config->io_base) /* Already tested */
+- continue;
+- if (gus_wave_detect(io_addr)) {
+- hw_config->io_base = io_addr;
+- return 1;
+- }
+- }
+-#endif
+-
+- printk("NO GUS card found !\n");
+- return 0;
+-}
+-
+-static void __exit unload_gus(struct address_info *hw_config)
+-{
+- DDB(printk("unload_gus(%x)\n", hw_config->io_base));
+-
+- gus_wave_unload(hw_config);
+-
+- release_region(hw_config->io_base, 16);
+- release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */
+- free_irq(hw_config->irq, hw_config);
+-
+- sound_free_dma(hw_config->dma);
+-
+- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+- sound_free_dma(hw_config->dma2);
+-}
+-
+-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy)
+-{
+- unsigned char src;
+- extern int gus_timer_enabled;
+- int handled = 0;
+-
+-#ifdef CONFIG_SOUND_GUSMAX
+- if (have_gus_max) {
+- struct address_info *hw_config = dev_id;
+- adintr(irq, (void *)hw_config->slots[1], NULL);
+- }
+-#endif
+-#ifdef CONFIG_SOUND_GUS16
+- if (db16) {
+- struct address_info *hw_config = dev_id;
+- adintr(irq, (void *)hw_config->slots[3], NULL);
+- }
+-#endif
+-
+- while (1)
+- {
+- if (!(src = inb(u_IrqStatus)))
+- break;
+- handled = 1;
+- if (src & DMA_TC_IRQ)
+- {
+- guswave_dma_irq();
+- }
+- if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
+- {
+- gus_midi_interrupt(0);
+- }
+- if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
+- {
+- if (gus_timer_enabled)
+- sound_timer_interrupt();
+- gus_write8(0x45, 0); /* Ack IRQ */
+- gus_timer_command(4, 0x80); /* Reset IRQ flags */
+- }
+- if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
+- gus_voice_irq();
+- }
+- return IRQ_RETVAL(handled);
+-}
+-
+-/*
+- * Some extra code for the 16 bit sampling option
+- */
+-
+-#ifdef CONFIG_SOUND_GUS16
+-
+-static int __init init_gus_db16(struct address_info *hw_config)
+-{
+- struct resource *ports;
+-
+- ports = request_region(hw_config->io_base, 4, "ad1848");
+- if (!ports)
+- return 0;
+-
+- if (!ad1848_detect(ports, NULL, hw_config->osp)) {
+- release_region(hw_config->io_base, 4);
+- return 0;
+- }
+-
+- gus_pcm_volume = 100;
+- gus_wave_volume = 90;
+-
+- hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports,
+- hw_config->irq,
+- hw_config->dma,
+- hw_config->dma, 0,
+- hw_config->osp,
+- THIS_MODULE);
+- return 1;
+-}
+-
+-static void __exit unload_gus_db16(struct address_info *hw_config)
+-{
+-
+- ad1848_unload(hw_config->io_base,
+- hw_config->irq,
+- hw_config->dma,
+- hw_config->dma, 0);
+- sound_unload_audiodev(hw_config->slots[3]);
+-}
+-#endif
+-
+-#ifdef CONFIG_SOUND_GUS16
+-static int gus16;
+-#endif
+-#ifdef CONFIG_SOUND_GUSMAX
+-static int no_wave_dma; /* Set if no dma is to be used for the
+- wave table (GF1 chip) */
+-#endif
+-
+-
+-/*
+- * Note DMA2 of -1 has the right meaning in the GUS driver as well
+- * as here.
+- */
+-
+-static struct address_info cfg;
+-
+-static int __initdata io = -1;
+-static int __initdata irq = -1;
+-static int __initdata dma = -1;
+-static int __initdata dma16 = -1; /* Set this for modules that need it */
+-static int __initdata type = 0; /* 1 for PnP */
+-
+-module_param(io, int, 0);
+-module_param(irq, int, 0);
+-module_param(dma, int, 0);
+-module_param(dma16, int, 0);
+-module_param(type, int, 0);
+-#ifdef CONFIG_SOUND_GUSMAX
+-module_param(no_wave_dma, int, 0);
+-#endif
+-#ifdef CONFIG_SOUND_GUS16
+-module_param(db16, int, 0);
+-module_param(gus16, int, 0);
+-#endif
+-MODULE_LICENSE("GPL");
+-
+-static int __init init_gus(void)
+-{
+- printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+-
+- cfg.io_base = io;
+- cfg.irq = irq;
+- cfg.dma = dma;
+- cfg.dma2 = dma16;
+- cfg.card_subtype = type;
+-#ifdef CONFIG_SOUND_GUSMAX
+- gus_no_wave_dma = no_wave_dma;
+-#endif
+-
+- if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
+- printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n");
+- return -EINVAL;
+- }
+-
+-#ifdef CONFIG_SOUND_GUS16
+- if (gus16 && init_gus_db16(&cfg))
+- db16 = 1;
+-#endif
+- if (!probe_gus(&cfg))
+- return -ENODEV;
+- attach_gus(&cfg);
+-
+- return 0;
+-}
+-
+-static void __exit cleanup_gus(void)
+-{
+-#ifdef CONFIG_SOUND_GUS16
+- if (db16)
+- unload_gus_db16(&cfg);
+-#endif
+- unload_gus(&cfg);
+-}
+-
+-module_init(init_gus);
+-module_exit(cleanup_gus);
+-
+-#ifndef MODULE
+-static int __init setup_gus(char *str)
+-{
+- /* io, irq, dma, dma2 */
+- int ints[5];
+-
+- str = get_options(str, ARRAY_SIZE(ints), ints);
+-
+- io = ints[1];
+- irq = ints[2];
+- dma = ints[3];
+- dma16 = ints[4];
+-
+- return 1;
+-}
+-
+-__setup("gus=", setup_gus);
+-#endif
+diff --git a/sound/oss/gus_hw.h b/sound/oss/gus_hw.h
+deleted file mode 100644
+index f97a0b8..0000000
+--- a/sound/oss/gus_hw.h
++++ /dev/null
+@@ -1,50 +0,0 @@
+-
+-/*
+- * I/O addresses
+- */
+-
+-#define u_Base (gus_base + 0x000)
+-#define u_Mixer u_Base
+-#define u_Status (gus_base + 0x006)
+-#define u_TimerControl (gus_base + 0x008)
+-#define u_TimerData (gus_base + 0x009)
+-#define u_IRQDMAControl (gus_base + 0x00b)
+-#define u_MidiControl (gus_base + 0x100)
+-#define MIDI_RESET 0x03
+-#define MIDI_ENABLE_XMIT 0x20
+-#define MIDI_ENABLE_RCV 0x80
+-#define u_MidiStatus u_MidiControl
+-#define MIDI_RCV_FULL 0x01
+-#define MIDI_XMIT_EMPTY 0x02
+-#define MIDI_FRAME_ERR 0x10
+-#define MIDI_OVERRUN 0x20
+-#define MIDI_IRQ_PEND 0x80
+-#define u_MidiData (gus_base + 0x101)
+-#define u_Voice (gus_base + 0x102)
+-#define u_Command (gus_base + 0x103)
+-#define u_DataLo (gus_base + 0x104)
+-#define u_DataHi (gus_base + 0x105)
+-#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
+-#define u_MixSelect (gus_base + 0x506) /* registers. */
+-#define u_IrqStatus u_Status
+-# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
+-# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
+-# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */
+-# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */
+-# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
+-# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
+-# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
+-
+-#define ICS2101 1
+-# define ICS_MIXDEVS 6
+-# define DEV_MIC 0
+-# define DEV_LINE 1
+-# define DEV_CD 2
+-# define DEV_GF1 3
+-# define DEV_UNUSED 4
+-# define DEV_VOL 5
+-
+-# define CHN_LEFT 0
+-# define CHN_RIGHT 1
+-#define CS4231 2
+-#define u_DRAMIO (gus_base + 0x107)
+diff --git a/sound/oss/gus_linearvol.h b/sound/oss/gus_linearvol.h
+deleted file mode 100644
+index 7ad0c30..0000000
+--- a/sound/oss/gus_linearvol.h
++++ /dev/null
+@@ -1,18 +0,0 @@
+-static unsigned short gus_linearvol[128] = {
+- 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
+- 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
+- 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
+- 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
+- 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
+- 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
+- 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
+- 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
+- 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
+- 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
+- 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
+- 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
+- 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
+- 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
+- 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
+- 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
+-};
+diff --git a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c
+deleted file mode 100644
+index b48f57c..0000000
+--- a/sound/oss/gus_midi.c
++++ /dev/null
+@@ -1,256 +0,0 @@
+-/*
+- * sound/gus2_midi.c
+- *
+- * The low level driver for the GUS Midi Interface.
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- * Changes:
+- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz at linux-ide.org>
+- * Added __init to gus_midi_init()
+- */
+-
+-#include <linux/init.h>
+-#include <linux/spinlock.h>
+-#include "sound_config.h"
+-
+-#include "gus.h"
+-#include "gus_hw.h"
+-
+-static int midi_busy, input_opened;
+-static int my_dev;
+-static int output_used;
+-static volatile unsigned char gus_midi_control;
+-static void (*midi_input_intr) (int dev, unsigned char data);
+-
+-static unsigned char tmp_queue[256];
+-extern int gus_pnp_flag;
+-static volatile int qlen;
+-static volatile unsigned char qhead, qtail;
+-extern int gus_base, gus_irq, gus_dma;
+-extern int *gus_osp;
+-extern spinlock_t gus_lock;
+-
+-static int GUS_MIDI_STATUS(void)
+-{
+- return inb(u_MidiStatus);
+-}
+-
+-static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev))
+-{
+- if (midi_busy)
+- {
+-/* printk("GUS: Midi busy\n");*/
+- return -EBUSY;
+- }
+- outb((MIDI_RESET), u_MidiControl);
+- gus_delay();
+-
+- gus_midi_control = 0;
+- input_opened = 0;
+-
+- if (mode == OPEN_READ || mode == OPEN_READWRITE)
+- if (!gus_pnp_flag)
+- {
+- gus_midi_control |= MIDI_ENABLE_RCV;
+- input_opened = 1;
+- }
+- outb((gus_midi_control), u_MidiControl); /* Enable */
+-
+- midi_busy = 1;
+- qlen = qhead = qtail = output_used = 0;
+- midi_input_intr = input;
+-
+- return 0;
+-}
+-
+-static int dump_to_midi(unsigned char midi_byte)
+-{
+- unsigned long flags;
+- int ok = 0;
+-
+- output_used = 1;
+-
+- spin_lock_irqsave(&gus_lock, flags);
+-
+- if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY)
+- {
+- ok = 1;
+- outb((midi_byte), u_MidiData);
+- }
+- else
+- {
+- /*
+- * Enable Midi xmit interrupts (again)
+- */
+- gus_midi_control |= MIDI_ENABLE_XMIT;
+- outb((gus_midi_control), u_MidiControl);
+- }
+-
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return ok;
+-}
+-
+-static void gus_midi_close(int dev)
+-{
+- /*
+- * Reset FIFO pointers, disable intrs
+- */
+-
+- outb((MIDI_RESET), u_MidiControl);
+- midi_busy = 0;
+-}
+-
+-static int gus_midi_out(int dev, unsigned char midi_byte)
+-{
+- unsigned long flags;
+-
+- /*
+- * Drain the local queue first
+- */
+- spin_lock_irqsave(&gus_lock, flags);
+-
+- while (qlen && dump_to_midi(tmp_queue[qhead]))
+- {
+- qlen--;
+- qhead++;
+- }
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+- /*
+- * Output the byte if the local queue is empty.
+- */
+-
+- if (!qlen)
+- if (dump_to_midi(midi_byte))
+- return 1; /*
+- * OK
+- */
+-
+- /*
+- * Put to the local queue
+- */
+-
+- if (qlen >= 256)
+- return 0; /*
+- * Local queue full
+- */
+- spin_lock_irqsave(&gus_lock, flags);
+-
+- tmp_queue[qtail] = midi_byte;
+- qlen++;
+- qtail++;
+-
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return 1;
+-}
+-
+-static int gus_midi_start_read(int dev)
+-{
+- return 0;
+-}
+-
+-static int gus_midi_end_read(int dev)
+-{
+- return 0;
+-}
+-
+-static void gus_midi_kick(int dev)
+-{
+-}
+-
+-static int gus_midi_buffer_status(int dev)
+-{
+- unsigned long flags;
+-
+- if (!output_used)
+- return 0;
+-
+- spin_lock_irqsave(&gus_lock, flags);
+-
+- if (qlen && dump_to_midi(tmp_queue[qhead]))
+- {
+- qlen--;
+- qhead++;
+- }
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
+-}
+-
+-#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
+-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
+-#include "midi_synth.h"
+-
+-static struct midi_operations gus_midi_operations =
+-{
+- .owner = THIS_MODULE,
+- .info = {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
+- .converter = &std_midi_synth,
+- .in_info = {0},
+- .open = gus_midi_open,
+- .close = gus_midi_close,
+- .outputc = gus_midi_out,
+- .start_read = gus_midi_start_read,
+- .end_read = gus_midi_end_read,
+- .kick = gus_midi_kick,
+- .buffer_status = gus_midi_buffer_status,
+-};
+-
+-void __init gus_midi_init(struct address_info *hw_config)
+-{
+- int dev = sound_alloc_mididev();
+-
+- if (dev == -1)
+- {
+- printk(KERN_INFO "gus_midi: Too many midi devices detected\n");
+- return;
+- }
+- outb((MIDI_RESET), u_MidiControl);
+-
+- std_midi_synth.midi_dev = my_dev = dev;
+- hw_config->slots[2] = dev;
+- midi_devs[dev] = &gus_midi_operations;
+- sequencer_init();
+- return;
+-}
+-
+-void gus_midi_interrupt(int dummy)
+-{
+- volatile unsigned char stat, data;
+- int timeout = 10;
+-
+- spin_lock(&gus_lock);
+-
+- while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
+- {
+- if (stat & MIDI_RCV_FULL)
+- {
+- data = inb(u_MidiData);
+- if (input_opened)
+- midi_input_intr(my_dev, data);
+- }
+- if (stat & MIDI_XMIT_EMPTY)
+- {
+- while (qlen && dump_to_midi(tmp_queue[qhead]))
+- {
+- qlen--;
+- qhead++;
+- }
+- if (!qlen)
+- {
+- /*
+- * Disable Midi output interrupts, since no data in the buffer
+- */
+- gus_midi_control &= ~MIDI_ENABLE_XMIT;
+- outb((gus_midi_control), u_MidiControl);
+- outb((gus_midi_control), u_MidiControl);
+- }
+- }
+- }
+- spin_unlock(&gus_lock);
+-}
+diff --git a/sound/oss/gus_vol.c b/sound/oss/gus_vol.c
+deleted file mode 100644
+index 6ae6924..0000000
+--- a/sound/oss/gus_vol.c
++++ /dev/null
+@@ -1,153 +0,0 @@
+-
+-/*
+- * gus_vol.c - Compute volume for GUS.
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- */
+-#include "sound_config.h"
+-
+-#include "gus.h"
+-#include "gus_linearvol.h"
+-
+-#define GUS_VOLUME gus_wave_volume
+-
+-
+-extern int gus_wave_volume;
+-
+-/*
+- * Calculate gus volume from note velocity, main volume, expression, and
+- * intrinsic patch volume given in patch library. Expression is multiplied
+- * in, so it emphasizes differences in note velocity, while main volume is
+- * added in -- I don't know whether this is right, but it seems reasonable to
+- * me. (In the previous stage, main volume controller messages were changed
+- * to expression controller messages, if they were found to be used for
+- * dynamic volume adjustments, so here, main volume can be assumed to be
+- * constant throughout a song.)
+- *
+- * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
+- * we can give a big boost to very weak voices like nylon guitar and the
+- * basses. The normal value is 64. Strings are assigned lower values.
+- */
+-
+-unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
+-{
+- int i, m, n, x;
+-
+-
+- /*
+- * A voice volume of 64 is considered neutral, so adjust the main volume if
+- * something other than this neutral value was assigned in the patch
+- * library.
+- */
+- x = 256 + 6 * (voicev - 64);
+-
+- /*
+- * Boost expression by voice volume above neutral.
+- */
+-
+- if (voicev > 65)
+- xpn += voicev - 64;
+- xpn += (voicev - 64) / 2;
+-
+- /*
+- * Combine multiplicative and level components.
+- */
+- x = vel * xpn * 6 + (voicev / 4) * x;
+-
+-#ifdef GUS_VOLUME
+- /*
+- * Further adjustment by installation-specific master volume control
+- * (default 60).
+- */
+- x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
+-#endif
+-
+-#ifdef GUS_USE_CHN_MAIN_VOLUME
+- /*
+- * Experimental support for the channel main volume
+- */
+-
+- mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
+- x = (x * mainv * mainv) / 16384;
+-#endif
+-
+- if (x < 2)
+- return (0);
+- else if (x >= 65535)
+- return ((15 << 8) | 255);
+-
+- /*
+- * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit
+- * mantissa m.
+- */
+-
+- n = x;
+- i = 7;
+- if (n < 128)
+- {
+- while (i > 0 && n < (1 << i))
+- i--;
+- }
+- else
+- {
+- while (n > 255)
+- {
+- n >>= 1;
+- i++;
+- }
+- }
+- /*
+- * Mantissa is part of linear volume not expressed in exponent. (This is
+- * not quite like real logs -- I wonder if it's right.)
+- */
+- m = x - (1 << i);
+-
+- /*
+- * Adjust mantissa to 8 bits.
+- */
+- if (m > 0)
+- {
+- if (i > 8)
+- m >>= i - 8;
+- else if (i < 8)
+- m <<= 8 - i;
+- }
+- return ((i << 8) + m);
+-}
+-
+-/*
+- * Volume-values are interpreted as linear values. Volume is based on the
+- * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
+- * and the volume set by the mixer-device (default 60%).
+- */
+-
+-unsigned short gus_linear_vol(int vol, int mainvol)
+-{
+- int mixer_mainvol;
+-
+- if (vol <= 0)
+- vol = 0;
+- else if (vol >= 127)
+- vol = 127;
+-
+-#ifdef GUS_VOLUME
+- mixer_mainvol = GUS_VOLUME;
+-#else
+- mixer_mainvol = 100;
+-#endif
+-
+-#ifdef GUS_USE_CHN_MAIN_VOLUME
+- if (mainvol <= 0)
+- mainvol = 0;
+- else if (mainvol >= 127)
+- mainvol = 127;
+-#else
+- mainvol = 127;
+-#endif
+- return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
+-}
+diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
+deleted file mode 100644
+index 942d518..0000000
+--- a/sound/oss/gus_wave.c
++++ /dev/null
+@@ -1,3464 +0,0 @@
+-/*
+- * sound/gus_wave.c
+- *
+- * Driver for the Gravis UltraSound wave table synth.
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- *
+- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+- * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
+- * usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
+- * Bartlomiej Zolnierkiewicz : added some __init/__exit
+- */
+-
+-#include <linux/init.h>
+-#include <linux/config.h>
+-#include <linux/spinlock.h>
+-
+-#define GUSPNP_AUTODETECT
+-
+-#include "sound_config.h"
+-#include <linux/ultrasound.h>
+-
+-#include "gus.h"
+-#include "gus_hw.h"
+-
+-#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
+-
+-#define MAX_SAMPLE 150
+-#define MAX_PATCH 256
+-
+-#define NOT_SAMPLE 0xffff
+-
+-struct voice_info
+-{
+- unsigned long orig_freq;
+- unsigned long current_freq;
+- unsigned long mode;
+- int fixed_pitch;
+- int bender;
+- int bender_range;
+- int panning;
+- int midi_volume;
+- unsigned int initial_volume;
+- unsigned int current_volume;
+- int loop_irq_mode, loop_irq_parm;
+-#define LMODE_FINISH 1
+-#define LMODE_PCM 2
+-#define LMODE_PCM_STOP 3
+- int volume_irq_mode, volume_irq_parm;
+-#define VMODE_HALT 1
+-#define VMODE_ENVELOPE 2
+-#define VMODE_START_NOTE 3
+-
+- int env_phase;
+- unsigned char env_rate[6];
+- unsigned char env_offset[6];
+-
+- /*
+- * Volume computation parameters for gus_adagio_vol()
+- */
+- int main_vol, expression_vol, patch_vol;
+-
+- /* Variables for "Ultraclick" removal */
+- int dev_pending, note_pending, volume_pending,
+- sample_pending;
+- char kill_pending;
+- long offset_pending;
+-
+-};
+-
+-static struct voice_alloc_info *voice_alloc;
+-static struct address_info *gus_hw_config;
+-extern int gus_base;
+-extern int gus_irq, gus_dma;
+-extern int gus_pnp_flag;
+-extern int gus_no_wave_dma;
+-static int gus_dma2 = -1;
+-static int dual_dma_mode;
+-static long gus_mem_size;
+-static long free_mem_ptr;
+-static int gus_busy;
+-static int gus_no_dma;
+-static int nr_voices;
+-static int gus_devnum;
+-static int volume_base, volume_scale, volume_method;
+-static int gus_recmask = SOUND_MASK_MIC;
+-static int recording_active;
+-static int only_read_access;
+-static int only_8_bits;
+-
+-static int iw_mode = 0;
+-int gus_wave_volume = 60;
+-int gus_pcm_volume = 80;
+-int have_gus_max = 0;
+-static int gus_line_vol = 100, gus_mic_vol;
+-static unsigned char mix_image = 0x00;
+-
+-int gus_timer_enabled = 0;
+-
+-/*
+- * Current version of this driver doesn't allow synth and PCM functions
+- * at the same time. The active_device specifies the active driver
+- */
+-
+-static int active_device;
+-
+-#define GUS_DEV_WAVE 1 /* Wave table synth */
+-#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */
+-#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer done ch. 1/2 */
+-
+-static int gus_audio_speed;
+-static int gus_audio_channels;
+-static int gus_audio_bits;
+-static int gus_audio_bsize;
+-static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */
+-
+-static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper);
+-
+-/*
+- * Variables and buffers for PCM output
+- */
+-
+-#define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */
+-
+-static int pcm_bsize, pcm_nblk, pcm_banksize;
+-static int pcm_datasize[MAX_PCM_BUFFERS];
+-static volatile int pcm_head, pcm_tail, pcm_qlen;
+-static volatile int pcm_active;
+-static volatile int dma_active;
+-static int pcm_opened;
+-static int pcm_current_dev;
+-static int pcm_current_block;
+-static unsigned long pcm_current_buf;
+-static int pcm_current_count;
+-static int pcm_current_intrflag;
+-DEFINE_SPINLOCK(gus_lock);
+-
+-extern int *gus_osp;
+-
+-static struct voice_info voices[32];
+-
+-static int freq_div_table[] =
+-{
+- 44100, /* 14 */
+- 41160, /* 15 */
+- 38587, /* 16 */
+- 36317, /* 17 */
+- 34300, /* 18 */
+- 32494, /* 19 */
+- 30870, /* 20 */
+- 29400, /* 21 */
+- 28063, /* 22 */
+- 26843, /* 23 */
+- 25725, /* 24 */
+- 24696, /* 25 */
+- 23746, /* 26 */
+- 22866, /* 27 */
+- 22050, /* 28 */
+- 21289, /* 29 */
+- 20580, /* 30 */
+- 19916, /* 31 */
+- 19293 /* 32 */
+-};
+-
+-static struct patch_info *samples;
+-static long sample_ptrs[MAX_SAMPLE + 1];
+-static int sample_map[32];
+-static int free_sample;
+-static int mixer_type;
+-
+-
+-static int patch_table[MAX_PATCH];
+-static int patch_map[32];
+-
+-static struct synth_info gus_info = {
+- "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS,
+- 0, 16, 0, MAX_PATCH
+-};
+-
+-static void gus_poke(long addr, unsigned char data);
+-static void compute_and_set_volume(int voice, int volume, int ramp_time);
+-extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
+-extern unsigned short gus_linear_vol(int vol, int mainvol);
+-static void compute_volume(int voice, int volume);
+-static void do_volume_irq(int voice);
+-static void set_input_volumes(void);
+-static void gus_tmr_install(int io_base);
+-
+-#define INSTANT_RAMP -1 /* Instant change. No ramping */
+-#define FAST_RAMP 0 /* Fastest possible ramp */
+-
+-static void reset_sample_memory(void)
+-{
+- int i;
+-
+- for (i = 0; i <= MAX_SAMPLE; i++)
+- sample_ptrs[i] = -1;
+- for (i = 0; i < 32; i++)
+- sample_map[i] = -1;
+- for (i = 0; i < 32; i++)
+- patch_map[i] = -1;
+-
+- gus_poke(0, 0); /* Put a silent sample to the beginning */
+- gus_poke(1, 0);
+- free_mem_ptr = 2;
+-
+- free_sample = 0;
+-
+- for (i = 0; i < MAX_PATCH; i++)
+- patch_table[i] = NOT_SAMPLE;
+-}
+-
+-void gus_delay(void)
+-{
+- int i;
+-
+- for (i = 0; i < 7; i++)
+- inb(u_DRAMIO);
+-}
+-
+-static void gus_poke(long addr, unsigned char data)
+-{ /* Writes a byte to the DRAM */
+- outb((0x43), u_Command);
+- outb((addr & 0xff), u_DataLo);
+- outb(((addr >> 8) & 0xff), u_DataHi);
+-
+- outb((0x44), u_Command);
+- outb(((addr >> 16) & 0xff), u_DataHi);
+- outb((data), u_DRAMIO);
+-}
+-
+-static unsigned char gus_peek(long addr)
+-{ /* Reads a byte from the DRAM */
+- unsigned char tmp;
+-
+- outb((0x43), u_Command);
+- outb((addr & 0xff), u_DataLo);
+- outb(((addr >> 8) & 0xff), u_DataHi);
+-
+- outb((0x44), u_Command);
+- outb(((addr >> 16) & 0xff), u_DataHi);
+- tmp = inb(u_DRAMIO);
+-
+- return tmp;
+-}
+-
+-void gus_write8(int reg, unsigned int data)
+-{ /* Writes to an indirect register (8 bit) */
+- outb((reg), u_Command);
+- outb(((unsigned char) (data & 0xff)), u_DataHi);
+-}
+-
+-static unsigned char gus_read8(int reg)
+-{
+- /* Reads from an indirect register (8 bit). Offset 0x80. */
+- unsigned char val;
+-
+- outb((reg | 0x80), u_Command);
+- val = inb(u_DataHi);
+-
+- return val;
+-}
+-
+-static unsigned char gus_look8(int reg)
+-{
+- /* Reads from an indirect register (8 bit). No additional offset. */
+- unsigned char val;
+-
+- outb((reg), u_Command);
+- val = inb(u_DataHi);
+-
+- return val;
+-}
+-
+-static void gus_write16(int reg, unsigned int data)
+-{
+- /* Writes to an indirect register (16 bit) */
+- outb((reg), u_Command);
+-
+- outb(((unsigned char) (data & 0xff)), u_DataLo);
+- outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
+-}
+-
+-static unsigned short gus_read16(int reg)
+-{
+- /* Reads from an indirect register (16 bit). Offset 0x80. */
+- unsigned char hi, lo;
+-
+- outb((reg | 0x80), u_Command);
+-
+- lo = inb(u_DataLo);
+- hi = inb(u_DataHi);
+-
+- return ((hi << 8) & 0xff00) | lo;
+-}
+-
+-static unsigned short gus_look16(int reg)
+-{
+- /* Reads from an indirect register (16 bit). No additional offset. */
+- unsigned char hi, lo;
+-
+- outb((reg), u_Command);
+-
+- lo = inb(u_DataLo);
+- hi = inb(u_DataHi);
+-
+- return ((hi << 8) & 0xff00) | lo;
+-}
+-
+-static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit)
+-{
+- /* Writes an 24 bit memory address */
+- unsigned long hold_address;
+-
+- if (is16bit)
+- {
+- if (iw_mode)
+- {
+- /* Interwave spesific address translations */
+- address >>= 1;
+- }
+- else
+- {
+- /*
+- * Special processing required for 16 bit patches
+- */
+-
+- hold_address = address;
+- address = address >> 1;
+- address &= 0x0001ffffL;
+- address |= (hold_address & 0x000c0000L);
+- }
+- }
+- gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
+- gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
+- + (frac << 5));
+- /* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */
+- gus_delay();
+- gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
+- gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
+- + (frac << 5));
+-}
+-
+-static void gus_select_voice(int voice)
+-{
+- if (voice < 0 || voice > 31)
+- return;
+- outb((voice), u_Voice);
+-}
+-
+-static void gus_select_max_voices(int nvoices)
+-{
+- if (iw_mode)
+- nvoices = 32;
+- if (nvoices < 14)
+- nvoices = 14;
+- if (nvoices > 32)
+- nvoices = 32;
+-
+- voice_alloc->max_voice = nr_voices = nvoices;
+- gus_write8(0x0e, (nvoices - 1) | 0xc0);
+-}
+-
+-static void gus_voice_on(unsigned int mode)
+-{
+- gus_write8(0x00, (unsigned char) (mode & 0xfc));
+- gus_delay();
+- gus_write8(0x00, (unsigned char) (mode & 0xfc));
+-}
+-
+-static void gus_voice_off(void)
+-{
+- gus_write8(0x00, gus_read8(0x00) | 0x03);
+-}
+-
+-static void gus_voice_mode(unsigned int m)
+-{
+- unsigned char mode = (unsigned char) (m & 0xff);
+-
+- gus_write8(0x00, (gus_read8(0x00) & 0x03) |
+- (mode & 0xfc)); /* Don't touch last two bits */
+- gus_delay();
+- gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc));
+-}
+-
+-static void gus_voice_freq(unsigned long freq)
+-{
+- unsigned long divisor = freq_div_table[nr_voices - 14];
+- unsigned short fc;
+-
+- /* Interwave plays at 44100 Hz with any number of voices */
+- if (iw_mode)
+- fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100);
+- else
+- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
+- fc = fc << 1;
+-
+- gus_write16(0x01, fc);
+-}
+-
+-static void gus_voice_volume(unsigned int vol)
+-{
+- gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */
+- gus_write16(0x09, (unsigned short) (vol << 4));
+-}
+-
+-static void gus_voice_balance(unsigned int balance)
+-{
+- gus_write8(0x0c, (unsigned char) (balance & 0xff));
+-}
+-
+-static void gus_ramp_range(unsigned int low, unsigned int high)
+-{
+- gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff));
+- gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff));
+-}
+-
+-static void gus_ramp_rate(unsigned int scale, unsigned int rate)
+-{
+- gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
+-}
+-
+-static void gus_rampon(unsigned int m)
+-{
+- unsigned char mode = (unsigned char) (m & 0xff);
+-
+- gus_write8(0x0d, mode & 0xfc);
+- gus_delay();
+- gus_write8(0x0d, mode & 0xfc);
+-}
+-
+-static void gus_ramp_mode(unsigned int m)
+-{
+- unsigned char mode = (unsigned char) (m & 0xff);
+-
+- gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |
+- (mode & 0xfc)); /* Leave the last 2 bits alone */
+- gus_delay();
+- gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));
+-}
+-
+-static void gus_rampoff(void)
+-{
+- gus_write8(0x0d, 0x03);
+-}
+-
+-static void gus_set_voice_pos(int voice, long position)
+-{
+- int sample_no;
+-
+- if ((sample_no = sample_map[voice]) != -1) {
+- if (position < samples[sample_no].len) {
+- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+- voices[voice].offset_pending = position;
+- else
+- gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0,
+- samples[sample_no].mode & WAVE_16_BITS);
+- }
+- }
+-}
+-
+-static void gus_voice_init(int voice)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_volume(0);
+- gus_voice_off();
+- gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */
+- gus_write8(0x00, 0x03); /* Voice off */
+- gus_write8(0x0d, 0x03); /* Ramping off */
+- voice_alloc->map[voice] = 0;
+- voice_alloc->alloc_times[voice] = 0;
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+-}
+-
+-static void gus_voice_init2(int voice)
+-{
+- voices[voice].panning = 0;
+- voices[voice].mode = 0;
+- voices[voice].orig_freq = 20000;
+- voices[voice].current_freq = 20000;
+- voices[voice].bender = 0;
+- voices[voice].bender_range = 200;
+- voices[voice].initial_volume = 0;
+- voices[voice].current_volume = 0;
+- voices[voice].loop_irq_mode = 0;
+- voices[voice].loop_irq_parm = 0;
+- voices[voice].volume_irq_mode = 0;
+- voices[voice].volume_irq_parm = 0;
+- voices[voice].env_phase = 0;
+- voices[voice].main_vol = 127;
+- voices[voice].patch_vol = 127;
+- voices[voice].expression_vol = 127;
+- voices[voice].sample_pending = -1;
+- voices[voice].fixed_pitch = 0;
+-}
+-
+-static void step_envelope(int voice)
+-{
+- unsigned vol, prev_vol, phase;
+- unsigned char rate;
+- unsigned long flags;
+-
+- if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
+- {
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_rampoff();
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return;
+- /*
+- * Sustain phase begins. Continue envelope after receiving note off.
+- */
+- }
+- if (voices[voice].env_phase >= 5)
+- {
+- /* Envelope finished. Shoot the voice down */
+- gus_voice_init(voice);
+- return;
+- }
+- prev_vol = voices[voice].current_volume;
+- phase = ++voices[voice].env_phase;
+- compute_volume(voice, voices[voice].midi_volume);
+- vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
+- rate = voices[voice].env_rate[phase];
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+-
+- gus_voice_volume(prev_vol);
+-
+-
+- gus_write8(0x06, rate); /* Ramping rate */
+-
+- voices[voice].volume_irq_mode = VMODE_ENVELOPE;
+-
+- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
+- {
+- spin_unlock_irqrestore(&gus_lock,flags);
+- step_envelope(voice); /* Continue the envelope on the next step */
+- return;
+- }
+- if (vol > prev_vol)
+- {
+- if (vol >= (4096 - 64))
+- vol = 4096 - 65;
+- gus_ramp_range(0, vol);
+- gus_rampon(0x20); /* Increasing volume, with IRQ */
+- }
+- else
+- {
+- if (vol <= 64)
+- vol = 65;
+- gus_ramp_range(vol, 4030);
+- gus_rampon(0x60); /* Decreasing volume, with IRQ */
+- }
+- voices[voice].current_volume = vol;
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static void init_envelope(int voice)
+-{
+- voices[voice].env_phase = -1;
+- voices[voice].current_volume = 64;
+-
+- step_envelope(voice);
+-}
+-
+-static void start_release(int voice)
+-{
+- if (gus_read8(0x00) & 0x03)
+- return; /* Voice already stopped */
+-
+- voices[voice].env_phase = 2; /* Will be incremented by step_envelope */
+-
+- voices[voice].current_volume = voices[voice].initial_volume =
+- gus_read16(0x09) >> 4; /* Get current volume */
+-
+- voices[voice].mode &= ~WAVE_SUSTAIN_ON;
+- gus_rampoff();
+- step_envelope(voice);
+-}
+-
+-static void gus_voice_fade(int voice)
+-{
+- int instr_no = sample_map[voice], is16bits;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+-
+- if (instr_no < 0 || instr_no > MAX_SAMPLE)
+- {
+- gus_write8(0x00, 0x03); /* Hard stop */
+- voice_alloc->map[voice] = 0;
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return;
+- }
+- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
+-
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- {
+- start_release(voice);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return;
+- }
+- /*
+- * Ramp the volume down but not too quickly.
+- */
+- if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */
+- {
+- gus_voice_off();
+- gus_rampoff();
+- gus_voice_init(voice);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return;
+- }
+- gus_ramp_range(65, 4030);
+- gus_ramp_rate(2, 4);
+- gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */
+- voices[voice].volume_irq_mode = VMODE_HALT;
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static void gus_reset(void)
+-{
+- int i;
+-
+- gus_select_max_voices(24);
+- volume_base = 3071;
+- volume_scale = 4;
+- volume_method = VOL_METHOD_ADAGIO;
+-
+- for (i = 0; i < 32; i++)
+- {
+- gus_voice_init(i); /* Turn voice off */
+- gus_voice_init2(i);
+- }
+-}
+-
+-static void gus_initialize(void)
+-{
+- unsigned long flags;
+- unsigned char dma_image, irq_image, tmp;
+-
+- static unsigned char gus_irq_map[16] = {
+- 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7
+- };
+-
+- static unsigned char gus_dma_map[8] = {
+- 0, 1, 0, 2, 0, 3, 4, 5
+- };
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_write8(0x4c, 0); /* Reset GF1 */
+- gus_delay();
+- gus_delay();
+-
+- gus_write8(0x4c, 1); /* Release Reset */
+- gus_delay();
+- gus_delay();
+-
+- /*
+- * Clear all interrupts
+- */
+-
+- gus_write8(0x41, 0); /* DMA control */
+- gus_write8(0x45, 0); /* Timer control */
+- gus_write8(0x49, 0); /* Sample control */
+-
+- gus_select_max_voices(24);
+-
+- inb(u_Status); /* Touch the status register */
+-
+- gus_look8(0x41); /* Clear any pending DMA IRQs */
+- gus_look8(0x49); /* Clear any pending sample IRQs */
+- gus_read8(0x0f); /* Clear pending IRQs */
+-
+- gus_reset(); /* Resets all voices */
+-
+- gus_look8(0x41); /* Clear any pending DMA IRQs */
+- gus_look8(0x49); /* Clear any pending sample IRQs */
+- gus_read8(0x0f); /* Clear pending IRQs */
+-
+- gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */
+-
+- /*
+- * Set up for Digital ASIC
+- */
+-
+- outb((0x05), gus_base + 0x0f);
+-
+- mix_image |= 0x02; /* Disable line out (for a moment) */
+- outb((mix_image), u_Mixer);
+-
+- outb((0x00), u_IRQDMAControl);
+-
+- outb((0x00), gus_base + 0x0f);
+-
+- /*
+- * Now set up the DMA and IRQ interface
+- *
+- * The GUS supports two IRQs and two DMAs.
+- *
+- * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
+- * Adding this support requires significant changes to the dmabuf.c, dsp.c
+- * and audio.c also.
+- */
+-
+- irq_image = 0;
+- tmp = gus_irq_map[gus_irq];
+- if (!gus_pnp_flag && !tmp)
+- printk(KERN_WARNING "Warning! GUS IRQ not selected\n");
+- irq_image |= tmp;
+- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
+-
+- dual_dma_mode = 1;
+- if (gus_dma2 == gus_dma || gus_dma2 == -1)
+- {
+- dual_dma_mode = 0;
+- dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
+-
+- tmp = gus_dma_map[gus_dma];
+- if (!tmp)
+- printk(KERN_WARNING "Warning! GUS DMA not selected\n");
+-
+- dma_image |= tmp;
+- }
+- else
+- {
+- /* Setup dual DMA channel mode for GUS MAX */
+-
+- dma_image = gus_dma_map[gus_dma];
+- if (!dma_image)
+- printk(KERN_WARNING "Warning! GUS DMA not selected\n");
+-
+- tmp = gus_dma_map[gus_dma2] << 3;
+- if (!tmp)
+- {
+- printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n");
+- tmp = 0x40; /* Combine DMA channels */
+- dual_dma_mode = 0;
+- }
+- dma_image |= tmp;
+- }
+-
+- /*
+- * For some reason the IRQ and DMA addresses must be written twice
+- */
+-
+- /*
+- * Doing it first time
+- */
+-
+- outb((mix_image), u_Mixer); /* Select DMA control */
+- outb((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */
+-
+- outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */
+- outb((irq_image), u_IRQDMAControl); /* Set IRQ address */
+-
+- /*
+- * Doing it second time
+- */
+-
+- outb((mix_image), u_Mixer); /* Select DMA control */
+- outb((dma_image), u_IRQDMAControl); /* Set DMA address */
+-
+- outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */
+- outb((irq_image), u_IRQDMAControl); /* Set IRQ address */
+-
+- gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
+-
+- mix_image &= ~0x02; /* Enable line out */
+- mix_image |= 0x08; /* Enable IRQ */
+- outb((mix_image), u_Mixer); /*
+- * Turn mixer channels on
+- * Note! Mic in is left off.
+- */
+-
+- gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
+-
+- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
+-
+- inb(u_Status); /* Touch the status register */
+-
+- gus_look8(0x41); /* Clear any pending DMA IRQs */
+- gus_look8(0x49); /* Clear any pending sample IRQs */
+-
+- gus_read8(0x0f); /* Clear pending IRQs */
+-
+- if (iw_mode)
+- gus_write8(0x19, gus_read8(0x19) | 0x01);
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-
+-static void __init pnp_mem_init(void)
+-{
+-#include "iwmem.h"
+-#define CHUNK_SIZE (256*1024)
+-#define BANK_SIZE (4*1024*1024)
+-#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)
+-
+- int bank, chunk, addr, total = 0;
+- int bank_sizes[4];
+- int i, j, bits = -1, testbits = -1, nbanks = 0;
+-
+- /*
+- * This routine determines what kind of RAM is installed in each of the four
+- * SIMM banks and configures the DRAM address decode logic accordingly.
+- */
+-
+- /*
+- * Place the chip into enhanced mode
+- */
+- gus_write8(0x19, gus_read8(0x19) | 0x01);
+- gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */
+-
+- /*
+- * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
+- */
+-
+- gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);
+-
+- /*
+- * Perform the DRAM size detection for each bank individually.
+- */
+- for (bank = 0; bank < 4; bank++)
+- {
+- int size = 0;
+-
+- addr = bank * BANK_SIZE;
+-
+- /* Clean check points of each chunk */
+- for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
+- {
+- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
+- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
+- }
+-
+- /* Write a value to each chunk point and verify the result */
+- for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
+- {
+- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55);
+- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA);
+-
+- if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&
+- gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA)
+- {
+- /* OK. There is RAM. Now check for possible shadows */
+- int ok = 1, chunk2;
+-
+- for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)
+- if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) ||
+- gus_peek(addr + chunk2 * CHUNK_SIZE + 1L))
+- ok = 0; /* Addressing wraps */
+-
+- if (ok)
+- size = (chunk + 1) * CHUNK_SIZE;
+- }
+- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
+- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
+- }
+- bank_sizes[bank] = size;
+- if (size)
+- nbanks = bank + 1;
+- DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024));
+- }
+-
+- if (nbanks == 0) /* No RAM - Give up */
+- {
+- printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n");
+- printk(KERN_ERR "Sound: Unable to work with this card.\n");
+- gus_write8(0x19, gus_read8(0x19) & ~0x01);
+- gus_mem_size = 0;
+- return;
+- }
+-
+- /*
+- * Now we know how much DRAM there is in each bank. The next step is
+- * to find a DRAM size encoding (0 to 12) which is best for the combination
+- * we have.
+- *
+- * First try if any of the possible alternatives matches exactly the amount
+- * of memory we have.
+- */
+-
+- for (i = 0; bits == -1 && i < 13; i++)
+- {
+- bits = i;
+-
+- for (j = 0; bits != -1 && j < 4; j++)
+- if (mem_decode[i][j] != bank_sizes[j])
+- bits = -1; /* No hit */
+- }
+-
+- /*
+- * If necessary, try to find a combination where other than the last
+- * bank matches our configuration and the last bank is left oversized.
+- * In this way we don't leave holes in the middle of memory.
+- */
+-
+- if (bits == -1) /* No luck yet */
+- {
+- for (i = 0; bits == -1 && i < 13; i++)
+- {
+- bits = i;
+-
+- for (j = 0; bits != -1 && j < nbanks - 1; j++)
+- if (mem_decode[i][j] != bank_sizes[j])
+- bits = -1; /* No hit */
+- if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])
+- bits = -1; /* The last bank is too small */
+- }
+- }
+- /*
+- * The last resort is to search for a combination where the banks are
+- * smaller than the actual SIMMs. This leaves some memory in the banks
+- * unused but doesn't leave holes in the DRAM address space.
+- */
+- if (bits == -1) /* No luck yet */
+- {
+- for (i = 0; i < 13; i++)
+- {
+- testbits = i;
+- for (j = 0; testbits != -1 && j < nbanks - 1; j++)
+- if (mem_decode[i][j] > bank_sizes[j]) {
+- testbits = -1;
+- }
+- if(testbits > bits) bits = testbits;
+- }
+- if (bits != -1)
+- {
+- printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");
+- printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");
+- }
+- printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");
+- printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
+- bits = 0;
+- }
+- DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits));
+-
+- for (bank = 0; bank < 4; bank++)
+- {
+- DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024));
+-
+- if (bank_sizes[bank] > mem_decode[bits][bank])
+- total += mem_decode[bits][bank];
+- else
+- total += bank_sizes[bank];
+- }
+-
+- DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024));
+-
+- /*
+- * Set the memory addressing mode.
+- */
+- gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits);
+-
+-/* Leave the chip into enhanced mode. Disable LFO */
+- gus_mem_size = total;
+- iw_mode = 1;
+- gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);
+-}
+-
+-int __init gus_wave_detect(int baseaddr)
+-{
+- unsigned long i, max_mem = 1024L;
+- unsigned long loc;
+- unsigned char val;
+-
+- if (!request_region(baseaddr, 16, "GUS"))
+- return 0;
+- if (!request_region(baseaddr + 0x100, 12, "GUS")) { /* 0x10c-> is MAX */
+- release_region(baseaddr, 16);
+- return 0;
+- }
+-
+- gus_base = baseaddr;
+-
+- gus_write8(0x4c, 0); /* Reset GF1 */
+- gus_delay();
+- gus_delay();
+-
+- gus_write8(0x4c, 1); /* Release Reset */
+- gus_delay();
+- gus_delay();
+-
+-#ifdef GUSPNP_AUTODETECT
+- val = gus_look8(0x5b); /* Version number register */
+- gus_write8(0x5b, ~val); /* Invert all bits */
+-
+- if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */
+- {
+- if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */
+- {
+- DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
+- gus_pnp_flag = 1;
+- }
+- else
+- {
+- DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b)));
+- gus_pnp_flag = 0;
+- }
+- }
+- gus_write8(0x5b, val); /* Restore all bits */
+-#endif
+-
+- if (gus_pnp_flag)
+- pnp_mem_init();
+- if (iw_mode)
+- return 1;
+-
+- /* See if there is first block there.... */
+- gus_poke(0L, 0xaa);
+- if (gus_peek(0L) != 0xaa) {
+- release_region(baseaddr + 0x100, 12);
+- release_region(baseaddr, 16);
+- return 0;
+- }
+-
+- /* Now zero it out so that I can check for mirroring .. */
+- gus_poke(0L, 0x00);
+- for (i = 1L; i < max_mem; i++)
+- {
+- int n, failed;
+-
+- /* check for mirroring ... */
+- if (gus_peek(0L) != 0)
+- break;
+- loc = i << 10;
+-
+- for (n = loc - 1, failed = 0; n <= loc; n++)
+- {
+- gus_poke(loc, 0xaa);
+- if (gus_peek(loc) != 0xaa)
+- failed = 1;
+- gus_poke(loc, 0x55);
+- if (gus_peek(loc) != 0x55)
+- failed = 1;
+- }
+- if (failed)
+- break;
+- }
+- gus_mem_size = i << 10;
+- return 1;
+-}
+-
+-static int guswave_ioctl(int dev, unsigned int cmd, void __user *arg)
+-{
+-
+- switch (cmd)
+- {
+- case SNDCTL_SYNTH_INFO:
+- gus_info.nr_voices = nr_voices;
+- if (copy_to_user(arg, &gus_info, sizeof(gus_info)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_SEQ_RESETSAMPLES:
+- reset_sample_memory();
+- return 0;
+-
+- case SNDCTL_SEQ_PERCMODE:
+- return 0;
+-
+- case SNDCTL_SYNTH_MEMAVL:
+- return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
+-
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static int guswave_set_instr(int dev, int voice, int instr_no)
+-{
+- int sample_no;
+-
+- if (instr_no < 0 || instr_no > MAX_PATCH)
+- instr_no = 0; /* Default to acoustic piano */
+-
+- if (voice < 0 || voice > 31)
+- return -EINVAL;
+-
+- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+- {
+- voices[voice].sample_pending = instr_no;
+- return 0;
+- }
+- sample_no = patch_table[instr_no];
+- patch_map[voice] = -1;
+-
+- if (sample_no == NOT_SAMPLE)
+- {
+-/* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/
+- return -EINVAL; /* Patch not defined */
+- }
+- if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
+- {
+-/* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/
+- return -EINVAL;
+- }
+- sample_map[voice] = sample_no;
+- patch_map[voice] = instr_no;
+- return 0;
+-}
+-
+-static int guswave_kill_note(int dev, int voice, int note, int velocity)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- /* voice_alloc->map[voice] = 0xffff; */
+- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+- {
+- voices[voice].kill_pending = 1;
+- spin_unlock_irqrestore(&gus_lock,flags);
+- }
+- else
+- {
+- spin_unlock_irqrestore(&gus_lock,flags);
+- gus_voice_fade(voice);
+- }
+-
+- return 0;
+-}
+-
+-static void guswave_aftertouch(int dev, int voice, int pressure)
+-{
+-}
+-
+-static void guswave_panning(int dev, int voice, int value)
+-{
+- if (voice >= 0 || voice < 32)
+- voices[voice].panning = value;
+-}
+-
+-static void guswave_volume_method(int dev, int mode)
+-{
+- if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+- volume_method = mode;
+-}
+-
+-static void compute_volume(int voice, int volume)
+-{
+- if (volume < 128)
+- voices[voice].midi_volume = volume;
+-
+- switch (volume_method)
+- {
+- case VOL_METHOD_ADAGIO:
+- voices[voice].initial_volume =
+- gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol,
+- voices[voice].expression_vol,
+- voices[voice].patch_vol);
+- break;
+-
+- case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
+- voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol);
+- break;
+-
+- default:
+- voices[voice].initial_volume = volume_base +
+- (voices[voice].midi_volume * volume_scale);
+- }
+-
+- if (voices[voice].initial_volume > 4030)
+- voices[voice].initial_volume = 4030;
+-}
+-
+-static void compute_and_set_volume(int voice, int volume, int ramp_time)
+-{
+- int curr, target, rate;
+- unsigned long flags;
+-
+- compute_volume(voice, volume);
+- voices[voice].current_volume = voices[voice].initial_volume;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- /*
+- * CAUTION! Interrupts disabled. Enable them before returning
+- */
+-
+- gus_select_voice(voice);
+-
+- curr = gus_read16(0x09) >> 4;
+- target = voices[voice].initial_volume;
+-
+- if (ramp_time == INSTANT_RAMP)
+- {
+- gus_rampoff();
+- gus_voice_volume(target);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return;
+- }
+- if (ramp_time == FAST_RAMP)
+- rate = 63;
+- else
+- rate = 16;
+- gus_ramp_rate(0, rate);
+-
+- if ((target - curr) / 64 == 0) /* Close enough to target. */
+- {
+- gus_rampoff();
+- gus_voice_volume(target);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return;
+- }
+- if (target > curr)
+- {
+- if (target > (4095 - 65))
+- target = 4095 - 65;
+- gus_ramp_range(curr, target);
+- gus_rampon(0x00); /* Ramp up, once, no IRQ */
+- }
+- else
+- {
+- if (target < 65)
+- target = 65;
+-
+- gus_ramp_range(target, curr);
+- gus_rampon(0x40); /* Ramp down, once, no irq */
+- }
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static void dynamic_volume_change(int voice)
+-{
+- unsigned char status;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- status = gus_read8(0x00); /* Get voice status */
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+- if (status & 0x03)
+- return; /* Voice was not running */
+-
+- if (!(voices[voice].mode & WAVE_ENVELOPES))
+- {
+- compute_and_set_volume(voice, voices[voice].midi_volume, 1);
+- return;
+- }
+-
+- /*
+- * Voice is running and has envelopes.
+- */
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- status = gus_read8(0x0d); /* Ramping status */
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+- if (status & 0x03) /* Sustain phase? */
+- {
+- compute_and_set_volume(voice, voices[voice].midi_volume, 1);
+- return;
+- }
+- if (voices[voice].env_phase < 0)
+- return;
+-
+- compute_volume(voice, voices[voice].midi_volume);
+-
+-}
+-
+-static void guswave_controller(int dev, int voice, int ctrl_num, int value)
+-{
+- unsigned long flags;
+- unsigned long freq;
+-
+- if (voice < 0 || voice > 31)
+- return;
+-
+- switch (ctrl_num)
+- {
+- case CTRL_PITCH_BENDER:
+- voices[voice].bender = value;
+-
+- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+- {
+- freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);
+- voices[voice].current_freq = freq;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_freq(freq);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- }
+- break;
+-
+- case CTRL_PITCH_BENDER_RANGE:
+- voices[voice].bender_range = value;
+- break;
+- case CTL_EXPRESSION:
+- value /= 128;
+- case CTRL_EXPRESSION:
+- if (volume_method == VOL_METHOD_ADAGIO)
+- {
+- voices[voice].expression_vol = value;
+- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+- dynamic_volume_change(voice);
+- }
+- break;
+-
+- case CTL_PAN:
+- voices[voice].panning = (value * 2) - 128;
+- break;
+-
+- case CTL_MAIN_VOLUME:
+- value = (value * 100) / 16383;
+-
+- case CTRL_MAIN_VOLUME:
+- voices[voice].main_vol = value;
+- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+- dynamic_volume_change(voice);
+- break;
+-
+- default:
+- break;
+- }
+-}
+-
+-static int guswave_start_note2(int dev, int voice, int note_num, int volume)
+-{
+- int sample, best_sample, best_delta, delta_freq;
+- int is16bits, samplep, patch, pan;
+- unsigned long note_freq, base_note, freq, flags;
+- unsigned char mode = 0;
+-
+- if (voice < 0 || voice > 31)
+- {
+-/* printk("GUS: Invalid voice\n");*/
+- return -EINVAL;
+- }
+- if (note_num == 255)
+- {
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- {
+- voices[voice].midi_volume = volume;
+- dynamic_volume_change(voice);
+- return 0;
+- }
+- compute_and_set_volume(voice, volume, 1);
+- return 0;
+- }
+- if ((patch = patch_map[voice]) == -1)
+- return -EINVAL;
+- if ((samplep = patch_table[patch]) == NOT_SAMPLE)
+- {
+- return -EINVAL;
+- }
+- note_freq = note_to_freq(note_num);
+-
+- /*
+- * Find a sample within a patch so that the note_freq is between low_note
+- * and high_note.
+- */
+- sample = -1;
+-
+- best_sample = samplep;
+- best_delta = 1000000;
+- while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)
+- {
+- delta_freq = note_freq - samples[samplep].base_note;
+- if (delta_freq < 0)
+- delta_freq = -delta_freq;
+- if (delta_freq < best_delta)
+- {
+- best_sample = samplep;
+- best_delta = delta_freq;
+- }
+- if (samples[samplep].low_note <= note_freq &&
+- note_freq <= samples[samplep].high_note)
+- {
+- sample = samplep;
+- }
+- else
+- samplep = samples[samplep].key; /* Link to next sample */
+- }
+- if (sample == -1)
+- sample = best_sample;
+-
+- if (sample == -1)
+- {
+-/* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/
+- return 0; /* Should play default patch ??? */
+- }
+- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
+- voices[voice].mode = samples[sample].mode;
+- voices[voice].patch_vol = samples[sample].volume;
+-
+- if (iw_mode)
+- gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */
+-
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- {
+- int i;
+-
+- for (i = 0; i < 6; i++)
+- {
+- voices[voice].env_rate[i] = samples[sample].env_rate[i];
+- voices[voice].env_offset[i] = samples[sample].env_offset[i];
+- }
+- }
+- sample_map[voice] = sample;
+-
+- if (voices[voice].fixed_pitch) /* Fixed pitch */
+- {
+- freq = samples[sample].base_freq;
+- }
+- else
+- {
+- base_note = samples[sample].base_note / 100;
+- note_freq /= 100;
+-
+- freq = samples[sample].base_freq * note_freq / base_note;
+- }
+-
+- voices[voice].orig_freq = freq;
+-
+- /*
+- * Since the pitch bender may have been set before playing the note, we
+- * have to calculate the bending now.
+- */
+-
+- freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,
+- voices[voice].bender_range, 0);
+- voices[voice].current_freq = freq;
+-
+- pan = (samples[sample].panning + voices[voice].panning) / 32;
+- pan += 7;
+- if (pan < 0)
+- pan = 0;
+- if (pan > 15)
+- pan = 15;
+-
+- if (samples[sample].mode & WAVE_16_BITS)
+- {
+- mode |= 0x04; /* 16 bits */
+- if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=
+- ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
+- printk(KERN_ERR "GUS: Sample address error\n");
+- }
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_off();
+- gus_rampoff();
+-
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- {
+- compute_volume(voice, volume);
+- init_envelope(voice);
+- }
+- else
+- {
+- compute_and_set_volume(voice, volume, 0);
+- }
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+-
+- if (samples[sample].mode & WAVE_LOOP_BACK)
+- gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
+- voices[voice].offset_pending, 0, is16bits); /* start=end */
+- else
+- gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */
+-
+- if (samples[sample].mode & WAVE_LOOPING)
+- {
+- mode |= 0x08;
+-
+- if (samples[sample].mode & WAVE_BIDIR_LOOP)
+- mode |= 0x10;
+-
+- if (samples[sample].mode & WAVE_LOOP_BACK)
+- {
+- gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end -
+- voices[voice].offset_pending,
+- (samples[sample].fractions >> 4) & 0x0f, is16bits);
+- mode |= 0x40;
+- }
+- gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start,
+- samples[sample].fractions & 0x0f, is16bits); /* Loop start location */
+- gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end,
+- (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */
+- }
+- else
+- {
+- mode |= 0x20; /* Loop IRQ at the end */
+- voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */
+- voices[voice].loop_irq_parm = 1;
+- gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */
+- gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,
+- (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */
+- }
+- gus_voice_freq(freq);
+- gus_voice_balance(pan);
+- gus_voice_on(mode);
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+- return 0;
+-}
+-
+-/*
+- * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
+- * when the note playing on the voice is changed. It uses volume
+- * ramping.
+- */
+-
+-static int guswave_start_note(int dev, int voice, int note_num, int volume)
+-{
+- unsigned long flags;
+- int mode;
+- int ret_val = 0;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- if (note_num == 255)
+- {
+- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+- {
+- voices[voice].volume_pending = volume;
+- }
+- else
+- {
+- ret_val = guswave_start_note2(dev, voice, note_num, volume);
+- }
+- }
+- else
+- {
+- gus_select_voice(voice);
+- mode = gus_read8(0x00);
+- if (mode & 0x20)
+- gus_write8(0x00, mode & 0xdf); /* No interrupt! */
+-
+- voices[voice].offset_pending = 0;
+- voices[voice].kill_pending = 0;
+- voices[voice].volume_irq_mode = 0;
+- voices[voice].loop_irq_mode = 0;
+-
+- if (voices[voice].sample_pending >= 0)
+- {
+- spin_unlock_irqrestore(&gus_lock,flags); /* Run temporarily with interrupts enabled */
+- guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);
+- voices[voice].sample_pending = -1;
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice); /* Reselect the voice (just to be sure) */
+- }
+- if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))
+- {
+- ret_val = guswave_start_note2(dev, voice, note_num, volume);
+- }
+- else
+- {
+- voices[voice].dev_pending = dev;
+- voices[voice].note_pending = note_num;
+- voices[voice].volume_pending = volume;
+- voices[voice].volume_irq_mode = VMODE_START_NOTE;
+-
+- gus_rampoff();
+- gus_ramp_range(2000, 4065);
+- gus_ramp_rate(0, 63); /* Fastest possible rate */
+- gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */
+- }
+- }
+- spin_unlock_irqrestore(&gus_lock,flags);
+- return ret_val;
+-}
+-
+-static void guswave_reset(int dev)
+-{
+- int i;
+-
+- for (i = 0; i < 32; i++)
+- {
+- gus_voice_init(i);
+- gus_voice_init2(i);
+- }
+-}
+-
+-static int guswave_open(int dev, int mode)
+-{
+- int err;
+-
+- if (gus_busy)
+- return -EBUSY;
+-
+- voice_alloc->timestamp = 0;
+-
+- if (gus_no_wave_dma) {
+- gus_no_dma = 1;
+- } else {
+- if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
+- {
+- /* printk( "GUS: Loading samples without DMA\n"); */
+- gus_no_dma = 1; /* Upload samples using PIO */
+- }
+- else
+- gus_no_dma = 0;
+- }
+-
+- init_waitqueue_head(&dram_sleeper);
+- gus_busy = 1;
+- active_device = GUS_DEV_WAVE;
+-
+- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
+- gus_initialize();
+- gus_reset();
+- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
+-
+- return 0;
+-}
+-
+-static void guswave_close(int dev)
+-{
+- gus_busy = 0;
+- active_device = 0;
+- gus_reset();
+-
+- if (!gus_no_dma)
+- DMAbuf_close_dma(gus_devnum);
+-}
+-
+-static int guswave_load_patch(int dev, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag)
+-{
+- struct patch_info patch;
+- int instr;
+- long sizeof_patch;
+-
+- unsigned long blk_sz, blk_end, left, src_offs, target;
+-
+- sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
+-
+- if (format != GUS_PATCH)
+- {
+-/* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/
+- return -EINVAL;
+- }
+- if (count < sizeof_patch)
+- {
+-/* printk("GUS Error: Patch header too short\n");*/
+- return -EINVAL;
+- }
+- count -= sizeof_patch;
+-
+- if (free_sample >= MAX_SAMPLE)
+- {
+-/* printk("GUS: Sample table full\n");*/
+- return -ENOSPC;
+- }
+- /*
+- * Copy the header from user space but ignore the first bytes which have
+- * been transferred already.
+- */
+-
+- if (copy_from_user(&((char *) &patch)[offs], &(addr)[offs],
+- sizeof_patch - offs))
+- return -EFAULT;
+-
+- if (patch.mode & WAVE_ROM)
+- return -EINVAL;
+- if (gus_mem_size == 0)
+- return -ENOSPC;
+-
+- instr = patch.instr_no;
+-
+- if (instr < 0 || instr > MAX_PATCH)
+- {
+-/* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/
+- return -EINVAL;
+- }
+- if (count < patch.len)
+- {
+-/* printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/
+- patch.len = count;
+- }
+- if (patch.len <= 0 || patch.len > gus_mem_size)
+- {
+-/* printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/
+- return -EINVAL;
+- }
+- if (patch.mode & WAVE_LOOPING)
+- {
+- if (patch.loop_start < 0 || patch.loop_start >= patch.len)
+- {
+-/* printk(KERN_ERR "GUS: Invalid loop start\n");*/
+- return -EINVAL;
+- }
+- if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
+- {
+-/* printk(KERN_ERR "GUS: Invalid loop end\n");*/
+- return -EINVAL;
+- }
+- }
+- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
+-
+- if (patch.mode & WAVE_16_BITS)
+- {
+- /*
+- * 16 bit samples must fit one 256k bank.
+- */
+- if (patch.len >= GUS_BANK_SIZE)
+- {
+-/* printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/
+- return -ENOSPC;
+- }
+- if ((free_mem_ptr / GUS_BANK_SIZE) !=
+- ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
+- {
+- unsigned long tmp_mem =
+- /* Align to 256K */
+- ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
+-
+- if ((tmp_mem + patch.len) > gus_mem_size)
+- return -ENOSPC;
+-
+- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
+- }
+- }
+- if ((free_mem_ptr + patch.len) > gus_mem_size)
+- return -ENOSPC;
+-
+- sample_ptrs[free_sample] = free_mem_ptr;
+-
+- /*
+- * Tremolo is not possible with envelopes
+- */
+-
+- if (patch.mode & WAVE_ENVELOPES)
+- patch.mode &= ~WAVE_TREMOLO;
+-
+- if (!(patch.mode & WAVE_FRACTIONS))
+- {
+- patch.fractions = 0;
+- }
+- memcpy((char *) &samples[free_sample], &patch, sizeof_patch);
+-
+- /*
+- * Link this_one sample to the list of samples for patch 'instr'.
+- */
+-
+- samples[free_sample].key = patch_table[instr];
+- patch_table[instr] = free_sample;
+-
+- /*
+- * Use DMA to transfer the wave data to the DRAM
+- */
+-
+- left = patch.len;
+- src_offs = 0;
+- target = free_mem_ptr;
+-
+- while (left) /* Not completely transferred yet */
+- {
+- blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
+- if (blk_sz > left)
+- blk_sz = left;
+-
+- /*
+- * DMA cannot cross bank (256k) boundaries. Check for that.
+- */
+-
+- blk_end = target + blk_sz;
+-
+- if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))
+- {
+- /* Split the block */
+- blk_end &= ~(GUS_BANK_SIZE - 1);
+- blk_sz = blk_end - target;
+- }
+- if (gus_no_dma)
+- {
+- /*
+- * For some reason the DMA is not possible. We have to use PIO.
+- */
+- long i;
+- unsigned char data;
+-
+- for (i = 0; i < blk_sz; i++)
+- {
+- get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[sizeof_patch + i]));
+- if (patch.mode & WAVE_UNSIGNED)
+- if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+- data ^= 0x80; /* Convert to signed */
+- gus_poke(target + i, data);
+- }
+- }
+- else
+- {
+- unsigned long address, hold_address;
+- unsigned char dma_command;
+- unsigned long flags;
+-
+- if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
+- {
+- printk(KERN_ERR "GUS: DMA buffer == NULL\n");
+- return -ENOSPC;
+- }
+- /*
+- * OK, move now. First in and then out.
+- */
+-
+- if (copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf,
+- &(addr)[sizeof_patch + src_offs],
+- blk_sz))
+- return -EFAULT;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_write8(0x41, 0); /* Disable GF1 DMA */
+- DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
+- blk_sz, DMA_MODE_WRITE);
+-
+- /*
+- * Set the DRAM address for the wave data
+- */
+-
+- if (iw_mode)
+- {
+- /* Different address translation in enhanced mode */
+-
+- unsigned char hi;
+-
+- if (gus_dma > 4)
+- address = target >> 1; /* Convert to 16 bit word address */
+- else
+- address = target;
+-
+- hi = (unsigned char) ((address >> 16) & 0xf0);
+- hi += (unsigned char) (address & 0x0f);
+-
+- gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */
+- gus_write8(0x50, hi);
+- }
+- else
+- {
+- address = target;
+- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
+- {
+- hold_address = address;
+- address = address >> 1;
+- address &= 0x0001ffffL;
+- address |= (hold_address & 0x000c0000L);
+- }
+- gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+- }
+-
+- /*
+- * Start the DMA transfer
+- */
+-
+- dma_command = 0x21; /* IRQ enable, DMA start */
+- if (patch.mode & WAVE_UNSIGNED)
+- dma_command |= 0x80; /* Invert MSB */
+- if (patch.mode & WAVE_16_BITS)
+- dma_command |= 0x40; /* 16 bit _DATA_ */
+- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
+- dma_command |= 0x04; /* 16 bit DMA _channel_ */
+-
+- /*
+- * Sleep here until the DRAM DMA done interrupt is served
+- */
+- active_device = GUS_DEV_WAVE;
+- gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */
+-
+- spin_unlock_irqrestore(&gus_lock,flags); /* opens a race */
+- if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
+- printk("GUS: DMA Transfer timed out\n");
+- }
+-
+- /*
+- * Now the next part
+- */
+-
+- left -= blk_sz;
+- src_offs += blk_sz;
+- target += blk_sz;
+-
+- gus_write8(0x41, 0); /* Stop DMA */
+- }
+-
+- free_mem_ptr += patch.len;
+- free_sample++;
+- return 0;
+-}
+-
+-static void guswave_hw_control(int dev, unsigned char *event_rec)
+-{
+- int voice, cmd;
+- unsigned short p1, p2;
+- unsigned int plong;
+- unsigned long flags;
+-
+- cmd = event_rec[2];
+- voice = event_rec[3];
+- p1 = *(unsigned short *) &event_rec[4];
+- p2 = *(unsigned short *) &event_rec[6];
+- plong = *(unsigned int *) &event_rec[4];
+-
+- if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
+- (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
+- do_volume_irq(voice);
+-
+- switch (cmd)
+- {
+- case _GUS_NUMVOICES:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_select_max_voices(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICESAMPLE:
+- guswave_set_instr(dev, voice, p1);
+- break;
+-
+- case _GUS_VOICEON:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- p1 &= ~0x20; /* Don't allow interrupts */
+- gus_voice_on(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICEOFF:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_off();
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICEFADE:
+- gus_voice_fade(voice);
+- break;
+-
+- case _GUS_VOICEMODE:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- p1 &= ~0x20; /* Don't allow interrupts */
+- gus_voice_mode(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICEBALA:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_balance(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICEFREQ:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_freq(plong);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICEVOL:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_volume(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOICEVOL2: /* Just update the software voice level */
+- voices[voice].initial_volume = voices[voice].current_volume = p1;
+- break;
+-
+- case _GUS_RAMPRANGE:
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- break; /* NO-NO */
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_ramp_range(p1, p2);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_RAMPRATE:
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- break; /* NJET-NJET */
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_ramp_rate(p1, p2);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_RAMPMODE:
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- break; /* NO-NO */
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- p1 &= ~0x20; /* Don't allow interrupts */
+- gus_ramp_mode(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_RAMPON:
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- break; /* EI-EI */
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- p1 &= ~0x20; /* Don't allow interrupts */
+- gus_rampon(p1);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_RAMPOFF:
+- if (voices[voice].mode & WAVE_ENVELOPES)
+- break; /* NEJ-NEJ */
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_rampoff();
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- case _GUS_VOLUME_SCALE:
+- volume_base = p1;
+- volume_scale = p2;
+- break;
+-
+- case _GUS_VOICE_POS:
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_set_voice_pos(voice, plong);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- break;
+-
+- default:
+- break;
+- }
+-}
+-
+-static int gus_audio_set_speed(int speed)
+-{
+- if (speed <= 0)
+- speed = gus_audio_speed;
+-
+- if (speed < 4000)
+- speed = 4000;
+-
+- if (speed > 44100)
+- speed = 44100;
+-
+- gus_audio_speed = speed;
+-
+- if (only_read_access)
+- {
+- /* Compute nearest valid recording speed and return it */
+-
+- /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */
+- speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
+- speed = (9878400 / (speed * 16)) - 2;
+- }
+- return speed;
+-}
+-
+-static int gus_audio_set_channels(int channels)
+-{
+- if (!channels)
+- return gus_audio_channels;
+- if (channels > 2)
+- channels = 2;
+- if (channels < 1)
+- channels = 1;
+- gus_audio_channels = channels;
+- return channels;
+-}
+-
+-static int gus_audio_set_bits(int bits)
+-{
+- if (!bits)
+- return gus_audio_bits;
+-
+- if (bits != 8 && bits != 16)
+- bits = 8;
+-
+- if (only_8_bits)
+- bits = 8;
+-
+- gus_audio_bits = bits;
+- return bits;
+-}
+-
+-static int gus_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
+-{
+- int val;
+-
+- switch (cmd)
+- {
+- case SOUND_PCM_WRITE_RATE:
+- if (get_user(val, (int __user*)arg))
+- return -EFAULT;
+- val = gus_audio_set_speed(val);
+- break;
+-
+- case SOUND_PCM_READ_RATE:
+- val = gus_audio_speed;
+- break;
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, (int __user *)arg))
+- return -EFAULT;
+- val = gus_audio_set_channels(val + 1) - 1;
+- break;
+-
+- case SOUND_PCM_WRITE_CHANNELS:
+- if (get_user(val, (int __user *)arg))
+- return -EFAULT;
+- val = gus_audio_set_channels(val);
+- break;
+-
+- case SOUND_PCM_READ_CHANNELS:
+- val = gus_audio_channels;
+- break;
+-
+- case SNDCTL_DSP_SETFMT:
+- if (get_user(val, (int __user *)arg))
+- return -EFAULT;
+- val = gus_audio_set_bits(val);
+- break;
+-
+- case SOUND_PCM_READ_BITS:
+- val = gus_audio_bits;
+- break;
+-
+- case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
+- case SOUND_PCM_READ_FILTER:
+- val = -EINVAL;
+- break;
+- default:
+- return -EINVAL;
+- }
+- return put_user(val, (int __user *)arg);
+-}
+-
+-static void gus_audio_reset(int dev)
+-{
+- if (recording_active)
+- {
+- gus_write8(0x49, 0x00); /* Halt recording */
+- set_input_volumes();
+- }
+-}
+-
+-static int saved_iw_mode; /* A hack hack hack */
+-
+-static int gus_audio_open(int dev, int mode)
+-{
+- if (gus_busy)
+- return -EBUSY;
+-
+- if (gus_pnp_flag && mode & OPEN_READ)
+- {
+-/* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/
+- return -EIO;
+- }
+- gus_initialize();
+-
+- gus_busy = 1;
+- active_device = 0;
+-
+- saved_iw_mode = iw_mode;
+- if (iw_mode)
+- {
+- /* There are some problems with audio in enhanced mode so disable it */
+- gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */
+- iw_mode = 0;
+- }
+-
+- gus_reset();
+- reset_sample_memory();
+- gus_select_max_voices(14);
+-
+- pcm_active = 0;
+- dma_active = 0;
+- pcm_opened = 1;
+- if (mode & OPEN_READ)
+- {
+- recording_active = 1;
+- set_input_volumes();
+- }
+- only_read_access = !(mode & OPEN_WRITE);
+- only_8_bits = mode & OPEN_READ;
+- if (only_8_bits)
+- audio_devs[dev]->format_mask = AFMT_U8;
+- else
+- audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
+-
+- return 0;
+-}
+-
+-static void gus_audio_close(int dev)
+-{
+- iw_mode = saved_iw_mode;
+- gus_reset();
+- gus_busy = 0;
+- pcm_opened = 0;
+- active_device = 0;
+-
+- if (recording_active)
+- {
+- gus_write8(0x49, 0x00); /* Halt recording */
+- set_input_volumes();
+- }
+- recording_active = 0;
+-}
+-
+-static void gus_audio_update_volume(void)
+-{
+- unsigned long flags;
+- int voice;
+-
+- if (pcm_active && pcm_opened)
+- for (voice = 0; voice < gus_audio_channels; voice++)
+- {
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_rampoff();
+- gus_voice_volume(1530 + (25 * gus_pcm_volume));
+- gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
+- spin_unlock_irqrestore(&gus_lock,flags);
+- }
+-}
+-
+-static void play_next_pcm_block(void)
+-{
+- unsigned long flags;
+- int speed = gus_audio_speed;
+- int this_one, is16bits, chn;
+- unsigned long dram_loc;
+- unsigned char mode[2], ramp_mode[2];
+-
+- if (!pcm_qlen)
+- return;
+-
+- this_one = pcm_head;
+-
+- for (chn = 0; chn < gus_audio_channels; chn++)
+- {
+- mode[chn] = 0x00;
+- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
+-
+- if (chn == 0)
+- {
+- mode[chn] |= 0x20; /* Loop IRQ */
+- voices[chn].loop_irq_mode = LMODE_PCM;
+- }
+- if (gus_audio_bits != 8)
+- {
+- is16bits = 1;
+- mode[chn] |= 0x04; /* 16 bit data */
+- }
+- else
+- is16bits = 0;
+-
+- dram_loc = this_one * pcm_bsize;
+- dram_loc += chn * pcm_banksize;
+-
+- if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */
+- {
+- mode[chn] |= 0x08; /* Enable loop */
+- ramp_mode[chn] = 0x03; /* Disable rollover bit */
+- }
+- else
+- {
+- if (chn == 0)
+- ramp_mode[chn] = 0x04; /* Enable rollover bit */
+- }
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(chn);
+- gus_voice_freq(speed);
+-
+- if (gus_audio_channels == 1)
+- gus_voice_balance(7); /* mono */
+- else if (chn == 0)
+- gus_voice_balance(0); /* left */
+- else
+- gus_voice_balance(15); /* right */
+-
+- if (!pcm_active) /* Playback not already active */
+- {
+- /*
+- * The playback was not started yet (or there has been a pause).
+- * Start the voice (again) and ask for a rollover irq at the end of
+- * this_one block. If this_one one is last of the buffers, use just
+- * the normal loop with irq.
+- */
+-
+- gus_voice_off();
+- gus_rampoff();
+- gus_voice_volume(1530 + (25 * gus_pcm_volume));
+- gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
+-
+- gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */
+- gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */
+-
+- if (chn != 0)
+- gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
+- 0, is16bits); /* Loop end location */
+- }
+- if (chn == 0)
+- gus_write_addr(0x04, dram_loc + pcm_bsize - 1,
+- 0, is16bits); /* Loop end location */
+- else
+- mode[chn] |= 0x08; /* Enable looping */
+- spin_unlock_irqrestore(&gus_lock,flags);
+- }
+- for (chn = 0; chn < gus_audio_channels; chn++)
+- {
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(chn);
+- gus_write8(0x0d, ramp_mode[chn]);
+- if (iw_mode)
+- gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */
+- gus_voice_on(mode[chn]);
+- spin_unlock_irqrestore(&gus_lock,flags);
+- }
+- pcm_active = 1;
+-}
+-
+-static void gus_transfer_output_block(int dev, unsigned long buf,
+- int total_count, int intrflag, int chn)
+-{
+- /*
+- * This routine transfers one block of audio data to the DRAM. In mono mode
+- * it's called just once. When in stereo mode, this_one routine is called
+- * once for both channels.
+- *
+- * The left/mono channel data is transferred to the beginning of dram and the
+- * right data to the area pointed by gus_page_size.
+- */
+-
+- int this_one, count;
+- unsigned long flags;
+- unsigned char dma_command;
+- unsigned long address, hold_address;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+-
+- count = total_count / gus_audio_channels;
+-
+- if (chn == 0)
+- {
+- if (pcm_qlen >= pcm_nblk)
+- printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n");
+-
+- this_one = pcm_current_block = pcm_tail;
+- pcm_qlen++;
+- pcm_tail = (pcm_tail + 1) % pcm_nblk;
+- pcm_datasize[this_one] = count;
+- }
+- else
+- this_one = pcm_current_block;
+-
+- gus_write8(0x41, 0); /* Disable GF1 DMA */
+- DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE);
+-
+- address = this_one * pcm_bsize;
+- address += chn * pcm_banksize;
+-
+- if (audio_devs[dev]->dmap_out->dma > 3)
+- {
+- hold_address = address;
+- address = address >> 1;
+- address &= 0x0001ffffL;
+- address |= (hold_address & 0x000c0000L);
+- }
+- gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+-
+- dma_command = 0x21; /* IRQ enable, DMA start */
+-
+- if (gus_audio_bits != 8)
+- dma_command |= 0x40; /* 16 bit _DATA_ */
+- else
+- dma_command |= 0x80; /* Invert MSB */
+-
+- if (audio_devs[dev]->dmap_out->dma > 3)
+- dma_command |= 0x04; /* 16 bit DMA channel */
+-
+- gus_write8(0x41, dma_command); /* Kick start */
+-
+- if (chn == (gus_audio_channels - 1)) /* Last channel */
+- {
+- /*
+- * Last (right or mono) channel data
+- */
+- dma_active = 1; /* DMA started. There is a unacknowledged buffer */
+- active_device = GUS_DEV_PCM_DONE;
+- if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize))
+- {
+- play_next_pcm_block();
+- }
+- }
+- else
+- {
+- /*
+- * Left channel data. The right channel
+- * is transferred after DMA interrupt
+- */
+- active_device = GUS_DEV_PCM_CONTINUE;
+- }
+-
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static void gus_uninterleave8(char *buf, int l)
+-{
+-/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */
+- int i, p = 0, halfsize = l / 2;
+- char *buf2 = buf + halfsize, *src = bounce_buf;
+-
+- memcpy(bounce_buf, buf, l);
+-
+- for (i = 0; i < halfsize; i++)
+- {
+- buf[i] = src[p++]; /* Left channel */
+- buf2[i] = src[p++]; /* Right channel */
+- }
+-}
+-
+-static void gus_uninterleave16(short *buf, int l)
+-{
+-/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */
+- int i, p = 0, halfsize = l / 2;
+- short *buf2 = buf + halfsize, *src = (short *) bounce_buf;
+-
+- memcpy(bounce_buf, (char *) buf, l * 2);
+-
+- for (i = 0; i < halfsize; i++)
+- {
+- buf[i] = src[p++]; /* Left channel */
+- buf2[i] = src[p++]; /* Right channel */
+- }
+-}
+-
+-static void gus_audio_output_block(int dev, unsigned long buf, int total_count,
+- int intrflag)
+-{
+- struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+-
+- dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT;
+-
+- pcm_current_buf = buf;
+- pcm_current_count = total_count;
+- pcm_current_intrflag = intrflag;
+- pcm_current_dev = dev;
+- if (gus_audio_channels == 2)
+- {
+- char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys);
+-
+- if (gus_audio_bits == 8)
+- gus_uninterleave8(b, total_count);
+- else
+- gus_uninterleave16((short *) b, total_count / 2);
+- }
+- gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
+-}
+-
+-static void gus_audio_start_input(int dev, unsigned long buf, int count,
+- int intrflag)
+-{
+- unsigned long flags;
+- unsigned char mode;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+-
+- DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ);
+- mode = 0xa0; /* DMA IRQ enabled, invert MSB */
+-
+- if (audio_devs[dev]->dmap_in->dma > 3)
+- mode |= 0x04; /* 16 bit DMA channel */
+- if (gus_audio_channels > 1)
+- mode |= 0x02; /* Stereo */
+- mode |= 0x01; /* DMA enable */
+-
+- gus_write8(0x49, mode);
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static int gus_audio_prepare_for_input(int dev, int bsize, int bcount)
+-{
+- unsigned int rate;
+-
+- gus_audio_bsize = bsize;
+- audio_devs[dev]->dmap_in->flags |= DMA_NODMA;
+- rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
+-
+- gus_write8(0x48, rate & 0xff); /* Set sampling rate */
+-
+- if (gus_audio_bits != 8)
+- {
+-/* printk("GUS Error: 16 bit recording not supported\n");*/
+- return -EINVAL;
+- }
+- return 0;
+-}
+-
+-static int gus_audio_prepare_for_output(int dev, int bsize, int bcount)
+-{
+- int i;
+-
+- long mem_ptr, mem_size;
+-
+- audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT;
+- mem_ptr = 0;
+- mem_size = gus_mem_size / gus_audio_channels;
+-
+- if (mem_size > (256 * 1024))
+- mem_size = 256 * 1024;
+-
+- pcm_bsize = bsize / gus_audio_channels;
+- pcm_head = pcm_tail = pcm_qlen = 0;
+-
+- pcm_nblk = 2; /* MAX_PCM_BUFFERS; */
+- if ((pcm_bsize * pcm_nblk) > mem_size)
+- pcm_nblk = mem_size / pcm_bsize;
+-
+- for (i = 0; i < pcm_nblk; i++)
+- pcm_datasize[i] = 0;
+-
+- pcm_banksize = pcm_nblk * pcm_bsize;
+-
+- if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024))
+- pcm_nblk--;
+- gus_write8(0x41, 0); /* Disable GF1 DMA */
+- return 0;
+-}
+-
+-static int gus_local_qlen(int dev)
+-{
+- return pcm_qlen;
+-}
+-
+-
+-static struct audio_driver gus_audio_driver =
+-{
+- .owner = THIS_MODULE,
+- .open = gus_audio_open,
+- .close = gus_audio_close,
+- .output_block = gus_audio_output_block,
+- .start_input = gus_audio_start_input,
+- .ioctl = gus_audio_ioctl,
+- .prepare_for_input = gus_audio_prepare_for_input,
+- .prepare_for_output = gus_audio_prepare_for_output,
+- .halt_io = gus_audio_reset,
+- .local_qlen = gus_local_qlen,
+-};
+-
+-static void guswave_setup_voice(int dev, int voice, int chn)
+-{
+- struct channel_info *info = &synth_devs[dev]->chn_info[chn];
+-
+- guswave_set_instr(dev, voice, info->pgm_num);
+- voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */
+- voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
+- voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
+- voices[voice].bender = 0;
+- voices[voice].bender_range = info->bender_range;
+-
+- if (chn == 9)
+- voices[voice].fixed_pitch = 1;
+-}
+-
+-static void guswave_bender(int dev, int voice, int value)
+-{
+- int freq;
+- unsigned long flags;
+-
+- voices[voice].bender = value - 8192;
+- freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0);
+- voices[voice].current_freq = freq;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- gus_select_voice(voice);
+- gus_voice_freq(freq);
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
+-{
+- int i, p, best = -1, best_time = 0x7fffffff;
+-
+- p = alloc->ptr;
+- /*
+- * First look for a completely stopped voice
+- */
+-
+- for (i = 0; i < alloc->max_voice; i++)
+- {
+- if (alloc->map[p] == 0)
+- {
+- alloc->ptr = p;
+- return p;
+- }
+- if (alloc->alloc_times[p] < best_time)
+- {
+- best = p;
+- best_time = alloc->alloc_times[p];
+- }
+- p = (p + 1) % alloc->max_voice;
+- }
+-
+- /*
+- * Then look for a releasing voice
+- */
+-
+- for (i = 0; i < alloc->max_voice; i++)
+- {
+- if (alloc->map[p] == 0xffff)
+- {
+- alloc->ptr = p;
+- return p;
+- }
+- p = (p + 1) % alloc->max_voice;
+- }
+- if (best >= 0)
+- p = best;
+-
+- alloc->ptr = p;
+- return p;
+-}
+-
+-static struct synth_operations guswave_operations =
+-{
+- .owner = THIS_MODULE,
+- .id = "GUS",
+- .info = &gus_info,
+- .midi_dev = 0,
+- .synth_type = SYNTH_TYPE_SAMPLE,
+- .synth_subtype = SAMPLE_TYPE_GUS,
+- .open = guswave_open,
+- .close = guswave_close,
+- .ioctl = guswave_ioctl,
+- .kill_note = guswave_kill_note,
+- .start_note = guswave_start_note,
+- .set_instr = guswave_set_instr,
+- .reset = guswave_reset,
+- .hw_control = guswave_hw_control,
+- .load_patch = guswave_load_patch,
+- .aftertouch = guswave_aftertouch,
+- .controller = guswave_controller,
+- .panning = guswave_panning,
+- .volume_method = guswave_volume_method,
+- .bender = guswave_bender,
+- .alloc_voice = guswave_alloc,
+- .setup_voice = guswave_setup_voice
+-};
+-
+-static void set_input_volumes(void)
+-{
+- unsigned long flags;
+- unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+-
+- if (have_gus_max) /* Don't disturb GUS MAX */
+- return;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+-
+- /*
+- * Enable channels having vol > 10%
+- * Note! bit 0x01 means the line in DISABLED while 0x04 means
+- * the mic in ENABLED.
+- */
+- if (gus_line_vol > 10)
+- mask &= ~0x01;
+- if (gus_mic_vol > 10)
+- mask |= 0x04;
+-
+- if (recording_active)
+- {
+- /*
+- * Disable channel, if not selected for recording
+- */
+- if (!(gus_recmask & SOUND_MASK_LINE))
+- mask |= 0x01;
+- if (!(gus_recmask & SOUND_MASK_MIC))
+- mask &= ~0x04;
+- }
+- mix_image &= ~0x07;
+- mix_image |= mask & 0x07;
+- outb((mix_image), u_Mixer);
+-
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+- SOUND_MASK_SYNTH|SOUND_MASK_PCM)
+-
+-int gus_default_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
+-{
+- int vol, val;
+-
+- if (((cmd >> 8) & 0xff) != 'M')
+- return -EINVAL;
+-
+- if (!access_ok(VERIFY_WRITE, arg, sizeof(int)))
+- return -EFAULT;
+-
+- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+- {
+- if (__get_user(val, (int __user *) arg))
+- return -EFAULT;
+-
+- switch (cmd & 0xff)
+- {
+- case SOUND_MIXER_RECSRC:
+- gus_recmask = val & MIX_DEVS;
+- if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+- gus_recmask = SOUND_MASK_MIC;
+- /* Note! Input volumes are updated during next open for recording */
+- val = gus_recmask;
+- break;
+-
+- case SOUND_MIXER_MIC:
+- vol = val & 0xff;
+- if (vol < 0)
+- vol = 0;
+- if (vol > 100)
+- vol = 100;
+- gus_mic_vol = vol;
+- set_input_volumes();
+- val = vol | (vol << 8);
+- break;
+-
+- case SOUND_MIXER_LINE:
+- vol = val & 0xff;
+- if (vol < 0)
+- vol = 0;
+- if (vol > 100)
+- vol = 100;
+- gus_line_vol = vol;
+- set_input_volumes();
+- val = vol | (vol << 8);
+- break;
+-
+- case SOUND_MIXER_PCM:
+- gus_pcm_volume = val & 0xff;
+- if (gus_pcm_volume < 0)
+- gus_pcm_volume = 0;
+- if (gus_pcm_volume > 100)
+- gus_pcm_volume = 100;
+- gus_audio_update_volume();
+- val = gus_pcm_volume | (gus_pcm_volume << 8);
+- break;
+-
+- case SOUND_MIXER_SYNTH:
+- gus_wave_volume = val & 0xff;
+- if (gus_wave_volume < 0)
+- gus_wave_volume = 0;
+- if (gus_wave_volume > 100)
+- gus_wave_volume = 100;
+- if (active_device == GUS_DEV_WAVE)
+- {
+- int voice;
+- for (voice = 0; voice < nr_voices; voice++)
+- dynamic_volume_change(voice); /* Apply the new vol */
+- }
+- val = gus_wave_volume | (gus_wave_volume << 8);
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- }
+- else
+- {
+- switch (cmd & 0xff)
+- {
+- /*
+- * Return parameters
+- */
+- case SOUND_MIXER_RECSRC:
+- val = gus_recmask;
+- break;
+-
+- case SOUND_MIXER_DEVMASK:
+- val = MIX_DEVS;
+- break;
+-
+- case SOUND_MIXER_STEREODEVS:
+- val = 0;
+- break;
+-
+- case SOUND_MIXER_RECMASK:
+- val = SOUND_MASK_MIC | SOUND_MASK_LINE;
+- break;
+-
+- case SOUND_MIXER_CAPS:
+- val = 0;
+- break;
+-
+- case SOUND_MIXER_MIC:
+- val = gus_mic_vol | (gus_mic_vol << 8);
+- break;
+-
+- case SOUND_MIXER_LINE:
+- val = gus_line_vol | (gus_line_vol << 8);
+- break;
+-
+- case SOUND_MIXER_PCM:
+- val = gus_pcm_volume | (gus_pcm_volume << 8);
+- break;
+-
+- case SOUND_MIXER_SYNTH:
+- val = gus_wave_volume | (gus_wave_volume << 8);
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- }
+- return __put_user(val, (int __user *)arg);
+-}
+-
+-static struct mixer_operations gus_mixer_operations =
+-{
+- .owner = THIS_MODULE,
+- .id = "GUS",
+- .name = "Gravis Ultrasound",
+- .ioctl = gus_default_mixer_ioctl
+-};
+-
+-static int __init gus_default_mixer_init(void)
+-{
+- int n;
+-
+- if ((n = sound_alloc_mixerdev()) != -1)
+- {
+- /*
+- * Don't install if there is another
+- * mixer
+- */
+- mixer_devs[n] = &gus_mixer_operations;
+- }
+- if (have_gus_max)
+- {
+- /*
+- * Enable all mixer channels on the GF1 side. Otherwise recording will
+- * not be possible using GUS MAX.
+- */
+- mix_image &= ~0x07;
+- mix_image |= 0x04; /* All channels enabled */
+- outb((mix_image), u_Mixer);
+- }
+- return n;
+-}
+-
+-void __init gus_wave_init(struct address_info *hw_config)
+-{
+- unsigned long flags;
+- unsigned char val;
+- char *model_num = "2.4";
+- char tmp[64];
+- int gus_type = 0x24; /* 2.4 */
+-
+- int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
+- int sdev;
+-
+- hw_config->slots[0] = -1; /* No wave */
+- hw_config->slots[1] = -1; /* No ad1848 */
+- hw_config->slots[4] = -1; /* No audio */
+- hw_config->slots[5] = -1; /* No mixer */
+-
+- if (!gus_pnp_flag)
+- {
+- if (irq < 0 || irq > 15)
+- {
+- printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+- return;
+- }
+- }
+-
+- if (dma < 0 || dma > 7 || dma == 4)
+- {
+- printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma);
+- return;
+- }
+- gus_irq = irq;
+- gus_dma = dma;
+- gus_dma2 = dma2;
+- gus_hw_config = hw_config;
+-
+- if (gus_dma2 == -1)
+- gus_dma2 = dma;
+-
+- /*
+- * Try to identify the GUS model.
+- *
+- * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+- */
+-
+- spin_lock_irqsave(&gus_lock,flags);
+- outb((0x20), gus_base + 0x0f);
+- val = inb(gus_base + 0x0f);
+- spin_unlock_irqrestore(&gus_lock,flags);
+-
+- if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */
+- {
+- int ad_flags = 0;
+-
+- if (gus_pnp_flag)
+- ad_flags = 0x12345678; /* Interwave "magic" */
+- /*
+- * It has the digital ASIC so the card is at least v3.4.
+- * Next try to detect the true model.
+- */
+-
+- if (gus_pnp_flag) /* Hack hack hack */
+- val = 10;
+- else
+- val = inb(u_MixSelect);
+-
+- /*
+- * Value 255 means pre-3.7 which don't have mixer.
+- * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
+- * 10 and above is GUS MAX which has the CS4231 codec/mixer.
+- *
+- */
+-
+- if (val == 255 || val < 5)
+- {
+- model_num = "3.4";
+- gus_type = 0x34;
+- }
+- else if (val < 10)
+- {
+- model_num = "3.7";
+- gus_type = 0x37;
+- mixer_type = ICS2101;
+- request_region(u_MixSelect, 1, "GUS mixer");
+- }
+- else
+- {
+- struct resource *ports;
+- ports = request_region(gus_base + 0x10c, 4, "ad1848");
+- model_num = "MAX";
+- gus_type = 0x40;
+- mixer_type = CS4231;
+-#ifdef CONFIG_SOUND_GUSMAX
+- {
+- unsigned char max_config = 0x40; /* Codec enable */
+-
+- if (gus_dma2 == -1)
+- gus_dma2 = gus_dma;
+-
+- if (gus_dma > 3)
+- max_config |= 0x10; /* 16 bit capture DMA */
+-
+- if (gus_dma2 > 3)
+- max_config |= 0x20; /* 16 bit playback DMA */
+-
+- max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
+-
+- outb((max_config), gus_base + 0x106); /* UltraMax control */
+- }
+-
+- if (!ports)
+- goto no_cs4231;
+-
+- if (ad1848_detect(ports, &ad_flags, hw_config->osp))
+- {
+- char *name = "GUS MAX";
+- int old_num_mixers = num_mixers;
+-
+- if (gus_pnp_flag)
+- name = "GUS PnP";
+-
+- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+- gus_wave_volume = 90;
+- have_gus_max = 1;
+- if (hw_config->name)
+- name = hw_config->name;
+-
+- hw_config->slots[1] = ad1848_init(name, ports,
+- -irq, gus_dma2, /* Playback DMA */
+- gus_dma, /* Capture DMA */
+- 1, /* Share DMA channels with GF1 */
+- hw_config->osp,
+- THIS_MODULE);
+-
+- if (num_mixers > old_num_mixers)
+- {
+- /* GUS has it's own mixer map */
+- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
+- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
+- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+- }
+- }
+- else {
+- release_region(gus_base + 0x10c, 4);
+- no_cs4231:
+- printk(KERN_WARNING "GUS: No CS4231 ??");
+- }
+-#else
+- printk(KERN_ERR "GUS MAX found, but not compiled in\n");
+-#endif
+- }
+- }
+- else
+- {
+- /*
+- * ASIC not detected so the card must be 2.2 or 2.4.
+- * There could still be the 16-bit/mixer daughter card.
+- */
+- }
+-
+- if (hw_config->name)
+- snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name,
+- (int) gus_mem_size / 1024);
+- else if (gus_pnp_flag)
+- snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)",
+- (int) gus_mem_size / 1024);
+- else
+- snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num,
+- (int) gus_mem_size / 1024);
+-
+-
+- samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
+- if (samples == NULL)
+- {
+- printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
+- return;
+- }
+- conf_printf(tmp, hw_config);
+- strlcpy(gus_info.name, tmp, sizeof(gus_info.name));
+-
+- if ((sdev = sound_alloc_synthdev()) == -1)
+- printk(KERN_WARNING "gus_init: Too many synthesizers\n");
+- else
+- {
+- voice_alloc = &guswave_operations.alloc;
+- if (iw_mode)
+- guswave_operations.id = "IWAVE";
+- hw_config->slots[0] = sdev;
+- synth_devs[sdev] = &guswave_operations;
+- sequencer_init();
+- gus_tmr_install(gus_base + 8);
+- }
+-
+- reset_sample_memory();
+-
+- gus_initialize();
+-
+- if ((gus_mem_size > 0) && !gus_no_wave_dma)
+- {
+- hw_config->slots[4] = -1;
+- if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
+- "Ultrasound",
+- &gus_audio_driver,
+- sizeof(struct audio_driver),
+- NEEDS_RESTART |
+- ((!iw_mode && dma2 != dma && dma2 != -1) ?
+- DMA_DUPLEX : 0),
+- AFMT_U8 | AFMT_S16_LE,
+- NULL, dma, dma2)) < 0)
+- {
+- return;
+- }
+-
+- hw_config->slots[4] = gus_devnum;
+- audio_devs[gus_devnum]->min_fragment = 9; /* 512k */
+- audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */
+- audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
+- audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
+- }
+-
+- /*
+- * Mixer dependent initialization.
+- */
+-
+- switch (mixer_type)
+- {
+- case ICS2101:
+- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+- gus_wave_volume = 90;
+- request_region(u_MixSelect, 1, "GUS mixer");
+- hw_config->slots[5] = ics2101_mixer_init();
+- audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */
+- return;
+-
+- case CS4231:
+- /* Initialized elsewhere (ad1848.c) */
+- default:
+- hw_config->slots[5] = gus_default_mixer_init();
+- audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */
+- return;
+- }
+-}
+-
+-void __exit gus_wave_unload(struct address_info *hw_config)
+-{
+-#ifdef CONFIG_SOUND_GUSMAX
+- if (have_gus_max)
+- {
+- ad1848_unload(gus_base + 0x10c,
+- -gus_irq,
+- gus_dma2, /* Playback DMA */
+- gus_dma, /* Capture DMA */
+- 1); /* Share DMA channels with GF1 */
+- }
+-#endif
+-
+- if (mixer_type == ICS2101)
+- {
+- release_region(u_MixSelect, 1);
+- }
+- if (hw_config->slots[0] != -1)
+- sound_unload_synthdev(hw_config->slots[0]);
+- if (hw_config->slots[1] != -1)
+- sound_unload_audiodev(hw_config->slots[1]);
+- if (hw_config->slots[2] != -1)
+- sound_unload_mididev(hw_config->slots[2]);
+- if (hw_config->slots[4] != -1)
+- sound_unload_audiodev(hw_config->slots[4]);
+- if (hw_config->slots[5] != -1)
+- sound_unload_mixerdev(hw_config->slots[5]);
+-
+- vfree(samples);
+- samples=NULL;
+-}
+-/* called in interrupt context */
+-static void do_loop_irq(int voice)
+-{
+- unsigned char tmp;
+- int mode, parm;
+-
+- spin_lock(&gus_lock);
+- gus_select_voice(voice);
+-
+- tmp = gus_read8(0x00);
+- tmp &= ~0x20; /*
+- * Disable wave IRQ for this_one voice
+- */
+- gus_write8(0x00, tmp);
+-
+- if (tmp & 0x03) /* Voice stopped */
+- voice_alloc->map[voice] = 0;
+-
+- mode = voices[voice].loop_irq_mode;
+- voices[voice].loop_irq_mode = 0;
+- parm = voices[voice].loop_irq_parm;
+-
+- switch (mode)
+- {
+- case LMODE_FINISH: /*
+- * Final loop finished, shoot volume down
+- */
+-
+- if ((int) (gus_read16(0x09) >> 4) < 100) /*
+- * Get current volume
+- */
+- {
+- gus_voice_off();
+- gus_rampoff();
+- gus_voice_init(voice);
+- break;
+- }
+- gus_ramp_range(65, 4065);
+- gus_ramp_rate(0, 63); /*
+- * Fastest possible rate
+- */
+- gus_rampon(0x20 | 0x40); /*
+- * Ramp down, once, irq
+- */
+- voices[voice].volume_irq_mode = VMODE_HALT;
+- break;
+-
+- case LMODE_PCM_STOP:
+- pcm_active = 0; /* Signal to the play_next_pcm_block routine */
+- case LMODE_PCM:
+- {
+- pcm_qlen--;
+- pcm_head = (pcm_head + 1) % pcm_nblk;
+- if (pcm_qlen && pcm_active)
+- {
+- play_next_pcm_block();
+- }
+- else
+- {
+- /* Underrun. Just stop the voice */
+- gus_select_voice(0); /* Left channel */
+- gus_voice_off();
+- gus_rampoff();
+- gus_select_voice(1); /* Right channel */
+- gus_voice_off();
+- gus_rampoff();
+- pcm_active = 0;
+- }
+-
+- /*
+- * If the queue was full before this interrupt, the DMA transfer was
+- * suspended. Let it continue now.
+- */
+-
+- if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
+- DMAbuf_outputintr(gus_devnum, 0);
+- }
+- break;
+-
+- default:
+- break;
+- }
+- spin_unlock(&gus_lock);
+-}
+-
+-static void do_volume_irq(int voice)
+-{
+- unsigned char tmp;
+- int mode, parm;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&gus_lock,flags);
+-
+- gus_select_voice(voice);
+- tmp = gus_read8(0x0d);
+- tmp &= ~0x20; /*
+- * Disable volume ramp IRQ
+- */
+- gus_write8(0x0d, tmp);
+-
+- mode = voices[voice].volume_irq_mode;
+- voices[voice].volume_irq_mode = 0;
+- parm = voices[voice].volume_irq_parm;
+-
+- switch (mode)
+- {
+- case VMODE_HALT: /* Decay phase finished */
+- if (iw_mode)
+- gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */
+- spin_unlock_irqrestore(&gus_lock,flags);
+- gus_voice_init(voice);
+- break;
+-
+- case VMODE_ENVELOPE:
+- gus_rampoff();
+- spin_unlock_irqrestore(&gus_lock,flags);
+- step_envelope(voice);
+- break;
+-
+- case VMODE_START_NOTE:
+- spin_unlock_irqrestore(&gus_lock,flags);
+- guswave_start_note2(voices[voice].dev_pending, voice,
+- voices[voice].note_pending, voices[voice].volume_pending);
+- if (voices[voice].kill_pending)
+- guswave_kill_note(voices[voice].dev_pending, voice,
+- voices[voice].note_pending, 0);
+-
+- if (voices[voice].sample_pending >= 0)
+- {
+- guswave_set_instr(voices[voice].dev_pending, voice,
+- voices[voice].sample_pending);
+- voices[voice].sample_pending = -1;
+- }
+- break;
+-
+- default:
+- spin_unlock_irqrestore(&gus_lock,flags);
+- }
+-}
+-/* called in irq context */
+-void gus_voice_irq(void)
+-{
+- unsigned long wave_ignore = 0, volume_ignore = 0;
+- unsigned long voice_bit;
+-
+- unsigned char src, voice;
+-
+- while (1)
+- {
+- src = gus_read8(0x0f); /*
+- * Get source info
+- */
+- voice = src & 0x1f;
+- src &= 0xc0;
+-
+- if (src == (0x80 | 0x40))
+- return; /*
+- * No interrupt
+- */
+-
+- voice_bit = 1 << voice;
+-
+- if (!(src & 0x80)) /*
+- * Wave IRQ pending
+- */
+- if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /*
+- * Not done
+- * yet
+- */
+- {
+- wave_ignore |= voice_bit;
+- do_loop_irq(voice);
+- }
+- if (!(src & 0x40)) /*
+- * Volume IRQ pending
+- */
+- if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /*
+- * Not done
+- * yet
+- */
+- {
+- volume_ignore |= voice_bit;
+- do_volume_irq(voice);
+- }
+- }
+-}
+-
+-void guswave_dma_irq(void)
+-{
+- unsigned char status;
+-
+- status = gus_look8(0x41); /* Get DMA IRQ Status */
+- if (status & 0x40) /* DMA interrupt pending */
+- switch (active_device)
+- {
+- case GUS_DEV_WAVE:
+- wake_up(&dram_sleeper);
+- break;
+-
+- case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */
+- gus_write8(0x41, 0); /* Disable GF1 DMA */
+- gus_transfer_output_block(pcm_current_dev, pcm_current_buf,
+- pcm_current_count,
+- pcm_current_intrflag, 1);
+- break;
+-
+- case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
+- gus_write8(0x41, 0); /* Disable GF1 DMA */
+- if (pcm_qlen < pcm_nblk)
+- {
+- dma_active = 0;
+- if (gus_busy)
+- {
+- if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
+- DMAbuf_outputintr(gus_devnum, 0);
+- }
+- }
+- break;
+-
+- default:
+- break;
+- }
+- status = gus_look8(0x49); /*
+- * Get Sampling IRQ Status
+- */
+- if (status & 0x40) /*
+- * Sampling Irq pending
+- */
+- {
+- DMAbuf_inputintr(gus_devnum);
+- }
+-}
+-
+-/*
+- * Timer stuff
+- */
+-
+-static volatile int select_addr, data_addr;
+-static volatile int curr_timer;
+-
+-void gus_timer_command(unsigned int addr, unsigned int val)
+-{
+- int i;
+-
+- outb(((unsigned char) (addr & 0xff)), select_addr);
+-
+- for (i = 0; i < 2; i++)
+- inb(select_addr);
+-
+- outb(((unsigned char) (val & 0xff)), data_addr);
+-
+- for (i = 0; i < 2; i++)
+- inb(select_addr);
+-}
+-
+-static void arm_timer(int timer, unsigned int interval)
+-{
+- curr_timer = timer;
+-
+- if (timer == 1)
+- {
+- gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */
+- gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */
+- gus_timer_command(0x04, 0x01); /* Start timer 1 */
+- }
+- else
+- {
+- gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */
+- gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */
+- gus_timer_command(0x04, 0x02); /* Start timer 2 */
+- }
+-
+- gus_timer_enabled = 1;
+-}
+-
+-static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick)
+-{
+- int timer_no, resolution;
+- int divisor;
+-
+- if (usecs_per_tick > (256 * 80))
+- {
+- timer_no = 2;
+- resolution = 320; /* usec */
+- }
+- else
+- {
+- timer_no = 1;
+- resolution = 80; /* usec */
+- }
+- divisor = (usecs_per_tick + (resolution / 2)) / resolution;
+- arm_timer(timer_no, divisor);
+-
+- return divisor * resolution;
+-}
+-
+-static void gus_tmr_disable(int dev)
+-{
+- gus_write8(0x45, 0); /* Disable both timers */
+- gus_timer_enabled = 0;
+-}
+-
+-static void gus_tmr_restart(int dev)
+-{
+- if (curr_timer == 1)
+- gus_write8(0x45, 0x04); /* Start timer 1 again */
+- else
+- gus_write8(0x45, 0x08); /* Start timer 2 again */
+- gus_timer_enabled = 1;
+-}
+-
+-static struct sound_lowlev_timer gus_tmr =
+-{
+- 0,
+- 1,
+- gus_tmr_start,
+- gus_tmr_disable,
+- gus_tmr_restart
+-};
+-
+-static void gus_tmr_install(int io_base)
+-{
+- struct sound_lowlev_timer *tmr;
+-
+- select_addr = io_base;
+- data_addr = io_base + 1;
+-
+- tmr = &gus_tmr;
+-
+-#ifdef THIS_GETS_FIXED
+- sound_timer_init(&gus_tmr, "GUS");
+-#endif
+-}
+diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
+index 80ab402..784bdd7 100644
+--- a/sound/oss/hal2.c
++++ b/sound/oss/hal2.c
+@@ -370,9 +370,9 @@ static void hal2_adc_interrupt(struct ha
+ wake_up(&adc->dma_wait);
+ }
+
+-static irqreturn_t hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t hal2_interrupt(int irq, void *dev_id)
+ {
+- struct hal2_card *hal2 = (struct hal2_card*)dev_id;
++ struct hal2_card *hal2 = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+
+ /* decide what caused this interrupt */
+diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
+deleted file mode 100644
+index 591683c..0000000
+--- a/sound/oss/harmony.c
++++ /dev/null
+@@ -1,1330 +0,0 @@
+-/*
+- drivers/sound/harmony.c
+-
+- This is a sound driver for ASP's and Lasi's Harmony sound chip
+- and is unlikely to be used for anything other than on a HP PA-RISC.
+-
+- Harmony is found in HP 712s, 715/new and many other GSC based machines.
+- On older 715 machines you'll find the technically identical chip
+- called 'Vivace'. Both Harmony and Vicace are supported by this driver.
+-
+- Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex at onefishtwo.ca>
+- Copyright 2000-2003 (c) Helge Deller <deller at gmx.de>
+- Copyright 2001 (c) Matthieu Delahaye <delahaym at esiee.fr>
+- Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij at esiee.fr>
+- Copyright 2004 (c) Stuart Brady <sdbrady at ntlworld.com>
+-
+-
+-TODO:
+- - fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to
+- return the real values
+- - add private ioctl for selecting line- or microphone input
+- (only one of them is available at the same time)
+- - add module parameters
+- - implement mmap functionality
+- - implement gain meter ?
+- - ...
+-*/
+-
+-#include <linux/delay.h>
+-#include <linux/errno.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/ioport.h>
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/pci.h>
+-
+-#include <asm/parisc-device.h>
+-#include <asm/io.h>
+-
+-#include "sound_config.h"
+-
+-
+-#define PFX "harmony: "
+-#define HARMONY_VERSION "V0.9a"
+-
+-#undef DEBUG
+-#ifdef DEBUG
+-# define DPRINTK printk
+-#else
+-# define DPRINTK(x,...)
+-#endif
+-
+-
+-#define MAX_BUFS 10 /* maximum number of rotating buffers */
+-#define HARMONY_BUF_SIZE 4096 /* needs to be a multiple of PAGE_SIZE (4096)! */
+-
+-#define CNTL_C 0x80000000
+-#define CNTL_ST 0x00000020
+-#define CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */
+-#define CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */
+-
+-#define GAINCTL_HE 0x08000000
+-#define GAINCTL_LE 0x04000000
+-#define GAINCTL_SE 0x02000000
+-
+-#define DSTATUS_PN 0x00000200
+-#define DSTATUS_RN 0x00000002
+-
+-#define DSTATUS_IE 0x80000000
+-
+-#define HARMONY_DF_16BIT_LINEAR 0
+-#define HARMONY_DF_8BIT_ULAW 1
+-#define HARMONY_DF_8BIT_ALAW 2
+-
+-#define HARMONY_SS_MONO 0
+-#define HARMONY_SS_STEREO 1
+-
+-#define HARMONY_SR_8KHZ 0x08
+-#define HARMONY_SR_16KHZ 0x09
+-#define HARMONY_SR_27KHZ 0x0A
+-#define HARMONY_SR_32KHZ 0x0B
+-#define HARMONY_SR_48KHZ 0x0E
+-#define HARMONY_SR_9KHZ 0x0F
+-#define HARMONY_SR_5KHZ 0x10
+-#define HARMONY_SR_11KHZ 0x11
+-#define HARMONY_SR_18KHZ 0x12
+-#define HARMONY_SR_22KHZ 0x13
+-#define HARMONY_SR_37KHZ 0x14
+-#define HARMONY_SR_44KHZ 0x15
+-#define HARMONY_SR_33KHZ 0x16
+-#define HARMONY_SR_6KHZ 0x17
+-
+-/*
+- * Some magics numbers used to auto-detect file formats
+- */
+-
+-#define HARMONY_MAGIC_8B_ULAW 1
+-#define HARMONY_MAGIC_8B_ALAW 27
+-#define HARMONY_MAGIC_16B_LINEAR 3
+-#define HARMONY_MAGIC_MONO 1
+-#define HARMONY_MAGIC_STEREO 2
+-
+-/*
+- * Channels Positions in mixer register
+- */
+-
+-#define GAIN_HE_SHIFT 27
+-#define GAIN_HE_MASK ( 1 << GAIN_HE_SHIFT)
+-#define GAIN_LE_SHIFT 26
+-#define GAIN_LE_MASK ( 1 << GAIN_LE_SHIFT)
+-#define GAIN_SE_SHIFT 25
+-#define GAIN_SE_MASK ( 1 << GAIN_SE_SHIFT)
+-#define GAIN_IS_SHIFT 24
+-#define GAIN_IS_MASK ( 1 << GAIN_IS_SHIFT)
+-#define GAIN_MA_SHIFT 20
+-#define GAIN_MA_MASK ( 0x0f << GAIN_MA_SHIFT)
+-#define GAIN_LI_SHIFT 16
+-#define GAIN_LI_MASK ( 0x0f << GAIN_LI_SHIFT)
+-#define GAIN_RI_SHIFT 12
+-#define GAIN_RI_MASK ( 0x0f << GAIN_RI_SHIFT)
+-#define GAIN_LO_SHIFT 6
+-#define GAIN_LO_MASK ( 0x3f << GAIN_LO_SHIFT)
+-#define GAIN_RO_SHIFT 0
+-#define GAIN_RO_MASK ( 0x3f << GAIN_RO_SHIFT)
+-
+-
+-#define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT)
+-#define MAX_INPUT_LEVEL (GAIN_RI_MASK >> GAIN_RI_SHIFT)
+-#define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT)
+-
+-#define MIXER_INTERNAL SOUND_MIXER_LINE1
+-#define MIXER_LINEOUT SOUND_MIXER_LINE2
+-#define MIXER_HEADPHONES SOUND_MIXER_LINE3
+-
+-#define MASK_INTERNAL SOUND_MASK_LINE1
+-#define MASK_LINEOUT SOUND_MASK_LINE2
+-#define MASK_HEADPHONES SOUND_MASK_LINE3
+-
+-/*
+- * Channels Mask in mixer register
+- */
+-
+-#define GAIN_TOTAL_SILENCE 0x00F00FFF
+-#define GAIN_DEFAULT 0x0FF00000
+-
+-
+-struct harmony_hpa {
+- u8 unused000;
+- u8 id;
+- u8 teleshare_id;
+- u8 unused003;
+- u32 reset;
+- u32 cntl;
+- u32 gainctl;
+- u32 pnxtadd;
+- u32 pcuradd;
+- u32 rnxtadd;
+- u32 rcuradd;
+- u32 dstatus;
+- u32 ov;
+- u32 pio;
+- u32 unused02c;
+- u32 unused030[3];
+- u32 diag;
+-};
+-
+-struct harmony_dev {
+- struct harmony_hpa *hpa;
+- struct parisc_device *dev;
+- u32 current_gain;
+- u32 dac_rate; /* 8000 ... 48000 (Hz) */
+- u8 data_format; /* HARMONY_DF_xx_BIT_xxx */
+- u8 sample_rate; /* HARMONY_SR_xx_KHZ */
+- u8 stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */
+- int format_initialized :1;
+- int suspended_playing :1;
+- int suspended_recording :1;
+-
+- int blocked_playing :1;
+- int blocked_recording :1;
+- int audio_open :1;
+- int mixer_open :1;
+-
+- wait_queue_head_t wq_play, wq_record;
+- int first_filled_play; /* first buffer containing data (next to play) */
+- int nb_filled_play;
+- int play_offset;
+- int first_filled_record;
+- int nb_filled_record;
+-
+- int dsp_unit, mixer_unit;
+-};
+-
+-
+-static struct harmony_dev harmony;
+-
+-
+-/*
+- * Dynamic sound buffer allocation and DMA memory
+- */
+-
+-struct harmony_buffer {
+- unsigned char *addr;
+- dma_addr_t dma_handle;
+- int dma_coherent; /* Zero if dma_alloc_coherent() fails */
+- unsigned int len;
+-};
+-
+-/*
+- * Harmony memory buffers
+- */
+-
+-static struct harmony_buffer played_buf, recorded_buf, silent, graveyard;
+-
+-
+-#define CHECK_WBACK_INV_OFFSET(b,offset,len) \
+- do { if (!b.dma_coherent) \
+- dma_cache_wback_inv((unsigned long)b.addr+offset,len); \
+- } while (0)
+-
+-
+-static int __init harmony_alloc_buffer(struct harmony_buffer *b,
+- unsigned int buffer_count)
+-{
+- b->len = buffer_count * HARMONY_BUF_SIZE;
+- b->addr = dma_alloc_coherent(&harmony.dev->dev,
+- b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA);
+- if (b->addr && b->dma_handle) {
+- b->dma_coherent = 1;
+- DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n",
+- (unsigned long)b->dma_handle, (unsigned long)b->addr);
+- } else {
+- b->dma_coherent = 0;
+- /* kmalloc()ed memory will HPMC on ccio machines ! */
+- b->addr = kmalloc(b->len, GFP_KERNEL);
+- if (!b->addr) {
+- printk(KERN_ERR PFX "couldn't allocate memory\n");
+- return -EBUSY;
+- }
+- b->dma_handle = __pa(b->addr);
+- }
+- return 0;
+-}
+-
+-static void __exit harmony_free_buffer(struct harmony_buffer *b)
+-{
+- if (!b->addr)
+- return;
+-
+- if (b->dma_coherent)
+- dma_free_coherent(&harmony.dev->dev,
+- b->len, b->addr, b->dma_handle);
+- else
+- kfree(b->addr);
+-
+- memset(b, 0, sizeof(*b));
+-}
+-
+-
+-
+-/*
+- * Low-Level sound-chip programming
+- */
+-
+-static void __inline__ harmony_wait_CNTL(void)
+-{
+- /* Wait until we're out of control mode */
+- while (gsc_readl(&harmony.hpa->cntl) & CNTL_C)
+- /* wait */ ;
+-}
+-
+-
+-static void harmony_update_control(void)
+-{
+- u32 default_cntl;
+-
+- /* Set CNTL */
+- default_cntl = (CNTL_C | /* The C bit */
+- (harmony.data_format << 6) | /* Set the data format */
+- (harmony.stereo_select << 5) | /* Stereo select */
+- (harmony.sample_rate)); /* Set sample rate */
+- harmony.format_initialized = 1;
+-
+- /* initialize CNTL */
+- gsc_writel(default_cntl, &harmony.hpa->cntl);
+-}
+-
+-static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select)
+-{
+- harmony.sample_rate = sample_rate;
+- harmony.data_format = data_format;
+- harmony.stereo_select = stereo_select;
+- harmony_update_control();
+-}
+-
+-static void harmony_set_rate(u8 data_rate)
+-{
+- harmony.sample_rate = data_rate;
+- harmony_update_control();
+-}
+-
+-static int harmony_detect_rate(int *freq)
+-{
+- int newrate;
+- switch (*freq) {
+- case 8000: newrate = HARMONY_SR_8KHZ; break;
+- case 16000: newrate = HARMONY_SR_16KHZ; break;
+- case 27428: newrate = HARMONY_SR_27KHZ; break;
+- case 32000: newrate = HARMONY_SR_32KHZ; break;
+- case 48000: newrate = HARMONY_SR_48KHZ; break;
+- case 9600: newrate = HARMONY_SR_9KHZ; break;
+- case 5512: newrate = HARMONY_SR_5KHZ; break;
+- case 11025: newrate = HARMONY_SR_11KHZ; break;
+- case 18900: newrate = HARMONY_SR_18KHZ; break;
+- case 22050: newrate = HARMONY_SR_22KHZ; break;
+- case 37800: newrate = HARMONY_SR_37KHZ; break;
+- case 44100: newrate = HARMONY_SR_44KHZ; break;
+- case 33075: newrate = HARMONY_SR_33KHZ; break;
+- case 6615: newrate = HARMONY_SR_6KHZ; break;
+- default: newrate = HARMONY_SR_8KHZ;
+- *freq = 8000; break;
+- }
+- return newrate;
+-}
+-
+-static void harmony_set_format(u8 data_format)
+-{
+- harmony.data_format = data_format;
+- harmony_update_control();
+-}
+-
+-static void harmony_set_stereo(u8 stereo_select)
+-{
+- harmony.stereo_select = stereo_select;
+- harmony_update_control();
+-}
+-
+-static void harmony_disable_interrupts(void)
+-{
+- harmony_wait_CNTL();
+- gsc_writel(0, &harmony.hpa->dstatus);
+-}
+-
+-static void harmony_enable_interrupts(void)
+-{
+- harmony_wait_CNTL();
+- gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus);
+-}
+-
+-/*
+- * harmony_silence()
+- *
+- * This subroutine fills in a buffer starting at location start and
+- * silences for length bytes. This references the current
+- * configuration of the audio format.
+- *
+- */
+-
+-static void harmony_silence(struct harmony_buffer *buffer, int start, int length)
+-{
+- u8 silence_char;
+-
+- /* Despite what you hear, silence is different in
+- different audio formats. */
+- switch (harmony.data_format) {
+- case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break;
+- case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break;
+- case HARMONY_DF_16BIT_LINEAR: /* fall through */
+- default: silence_char = 0;
+- }
+-
+- memset(buffer->addr+start, silence_char, length);
+-}
+-
+-
+-static int harmony_audio_open(struct inode *inode, struct file *file)
+-{
+- if (harmony.audio_open)
+- return -EBUSY;
+-
+- harmony.audio_open = 1;
+- harmony.suspended_playing = harmony.suspended_recording = 1;
+- harmony.blocked_playing = harmony.blocked_recording = 0;
+- harmony.first_filled_play = harmony.first_filled_record = 0;
+- harmony.nb_filled_play = harmony.nb_filled_record = 0;
+- harmony.play_offset = 0;
+- init_waitqueue_head(&harmony.wq_play);
+- init_waitqueue_head(&harmony.wq_record);
+-
+- /* Start off in a balanced mode. */
+- harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
+- harmony_update_control();
+- harmony.format_initialized = 0;
+-
+- /* Clear out all the buffers and flush to cache */
+- harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+- CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+-
+- return 0;
+-}
+-
+-/*
+- * Release (close) the audio device.
+- */
+-
+-static int harmony_audio_release(struct inode *inode, struct file *file)
+-{
+- if (!harmony.audio_open)
+- return -EBUSY;
+-
+- harmony.audio_open = 0;
+-
+- return 0;
+-}
+-
+-/*
+- * Read recorded data off the audio device.
+- */
+-
+-static ssize_t harmony_audio_read(struct file *file,
+- char *buffer,
+- size_t size_count,
+- loff_t *ppos)
+-{
+- int total_count = (int) size_count;
+- int count = 0;
+- int buf_to_read;
+-
+- while (count<total_count) {
+- /* Wait until we're out of control mode */
+- harmony_wait_CNTL();
+-
+- /* Figure out which buffer to fill in */
+- if (harmony.nb_filled_record <= 2) {
+- harmony.blocked_recording = 1;
+- if (harmony.suspended_recording) {
+- harmony.suspended_recording = 0;
+- harmony_enable_interrupts();
+- }
+-
+- interruptible_sleep_on(&harmony.wq_record);
+- harmony.blocked_recording = 0;
+- }
+-
+- if (harmony.nb_filled_record < 2)
+- return -EBUSY;
+-
+- buf_to_read = harmony.first_filled_record;
+-
+- /* Copy the page to an aligned buffer */
+- if (copy_to_user(buffer+count, recorded_buf.addr +
+- (HARMONY_BUF_SIZE*buf_to_read),
+- HARMONY_BUF_SIZE)) {
+- count = -EFAULT;
+- break;
+- }
+-
+- harmony.nb_filled_record--;
+- harmony.first_filled_record++;
+- harmony.first_filled_record %= MAX_BUFS;
+-
+- count += HARMONY_BUF_SIZE;
+- }
+- return count;
+-}
+-
+-
+-
+-
+-/*
+- * Here is the place where we try to recognize file format.
+- * Sun/NeXT .au files begin with the string .snd
+- * At offset 12 is specified the encoding.
+- * At offset 16 is specified speed rate
+- * At Offset 20 is specified the numbers of voices
+- */
+-
+-#define four_bytes_to_u32(start) (file_header[start] << 24)|\
+- (file_header[start+1] << 16)|\
+- (file_header[start+2] << 8)|\
+- (file_header[start+3]);
+-
+-#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\
+-
+-
+-static int harmony_format_auto_detect(const char *buffer, int block_size)
+-{
+- u8 file_header[24];
+- u32 start_string;
+- int ret = 0;
+-
+- if (block_size>24) {
+- if (copy_from_user(file_header, buffer, sizeof(file_header)))
+- ret = -EFAULT;
+-
+- start_string = four_bytes_to_u32(0);
+-
+- if ((file_header[4]==0) && (start_string==0x2E736E64)) {
+- u32 format;
+- u32 nb_voices;
+- u32 speed;
+-
+- format = four_bytes_to_u32(12);
+- nb_voices = four_bytes_to_u32(20);
+- speed = four_bytes_to_u32(16);
+-
+- switch (format) {
+- case HARMONY_MAGIC_8B_ULAW:
+- harmony.data_format = HARMONY_DF_8BIT_ULAW;
+- break;
+- case HARMONY_MAGIC_8B_ALAW:
+- harmony.data_format = HARMONY_DF_8BIT_ALAW;
+- break;
+- case HARMONY_MAGIC_16B_LINEAR:
+- harmony.data_format = HARMONY_DF_16BIT_LINEAR;
+- break;
+- default:
+- harmony_set_control(HARMONY_DF_16BIT_LINEAR,
+- HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
+- goto out;
+- }
+- switch (nb_voices) {
+- case HARMONY_MAGIC_MONO:
+- harmony.stereo_select = HARMONY_SS_MONO;
+- break;
+- case HARMONY_MAGIC_STEREO:
+- harmony.stereo_select = HARMONY_SS_STEREO;
+- break;
+- default:
+- harmony.stereo_select = HARMONY_SS_MONO;
+- break;
+- }
+- harmony_set_rate(harmony_detect_rate(&speed));
+- harmony.dac_rate = speed;
+- goto out;
+- }
+- }
+- harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
+-out:
+- return ret;
+-}
+-#undef four_bytes_to_u32
+-
+-
+-static ssize_t harmony_audio_write(struct file *file,
+- const char *buffer,
+- size_t size_count,
+- loff_t *ppos)
+-{
+- int total_count = (int) size_count;
+- int count = 0;
+- int frame_size;
+- int buf_to_fill;
+- int fresh_buffer;
+-
+- if (!harmony.format_initialized) {
+- if (harmony_format_auto_detect(buffer, total_count))
+- return -EFAULT;
+- }
+-
+- while (count<total_count) {
+- /* Wait until we're out of control mode */
+- harmony_wait_CNTL();
+-
+- /* Figure out which buffer to fill in */
+- if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {
+- harmony.blocked_playing = 1;
+- interruptible_sleep_on(&harmony.wq_play);
+- harmony.blocked_playing = 0;
+- }
+- if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)
+- return -EBUSY;
+-
+-
+- buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play);
+- if (harmony.play_offset) {
+- buf_to_fill--;
+- buf_to_fill += MAX_BUFS;
+- }
+- buf_to_fill %= MAX_BUFS;
+-
+- fresh_buffer = (harmony.play_offset == 0);
+-
+- /* Figure out the size of the frame */
+- if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) {
+- frame_size = HARMONY_BUF_SIZE - harmony.play_offset;
+- } else {
+- frame_size = total_count - count;
+- /* Clear out the buffer, since there we'll only be
+- overlaying part of the old buffer with the new one */
+- harmony_silence(&played_buf,
+- HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,
+- HARMONY_BUF_SIZE-frame_size-harmony.play_offset);
+- }
+-
+- /* Copy the page to an aligned buffer */
+- if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset,
+- buffer+count, frame_size))
+- return -EFAULT;
+- CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset),
+- frame_size);
+-
+- if (fresh_buffer)
+- harmony.nb_filled_play++;
+-
+- count += frame_size;
+- harmony.play_offset += frame_size;
+- harmony.play_offset %= HARMONY_BUF_SIZE;
+- if (harmony.suspended_playing && (harmony.nb_filled_play>=4))
+- harmony_enable_interrupts();
+- }
+-
+- return count;
+-}
+-
+-static unsigned int harmony_audio_poll(struct file *file,
+- struct poll_table_struct *wait)
+-{
+- unsigned int mask = 0;
+-
+- if (file->f_mode & FMODE_READ) {
+- if (!harmony.suspended_recording)
+- poll_wait(file, &harmony.wq_record, wait);
+- if (harmony.nb_filled_record)
+- mask |= POLLIN | POLLRDNORM;
+- }
+-
+- if (file->f_mode & FMODE_WRITE) {
+- if (!harmony.suspended_playing)
+- poll_wait(file, &harmony.wq_play, wait);
+- if (harmony.nb_filled_play)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+-
+- return mask;
+-}
+-
+-static int harmony_audio_ioctl(struct inode *inode,
+- struct file *file,
+- unsigned int cmd,
+- unsigned long arg)
+-{
+- int ival, new_format;
+- int frag_size, frag_buf;
+- struct audio_buf_info info;
+-
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, (int *) arg);
+-
+- case SNDCTL_DSP_GETCAPS:
+- ival = DSP_CAP_DUPLEX;
+- return put_user(ival, (int *) arg);
+-
+- case SNDCTL_DSP_GETFMTS:
+- ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW );
+- return put_user(ival, (int *) arg);
+-
+- case SNDCTL_DSP_SETFMT:
+- if (get_user(ival, (int *) arg))
+- return -EFAULT;
+- if (ival != AFMT_QUERY) {
+- switch (ival) {
+- case AFMT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break;
+- case AFMT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break;
+- case AFMT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR; break;
+- default: {
+- DPRINTK(KERN_WARNING PFX
+- "unsupported sound format 0x%04x requested.\n",
+- ival);
+- ival = AFMT_S16_BE;
+- return put_user(ival, (int *) arg);
+- }
+- }
+- harmony_set_format(new_format);
+- return 0;
+- } else {
+- switch (harmony.data_format) {
+- case HARMONY_DF_8BIT_ULAW: ival = AFMT_MU_LAW; break;
+- case HARMONY_DF_8BIT_ALAW: ival = AFMT_A_LAW; break;
+- case HARMONY_DF_16BIT_LINEAR: ival = AFMT_U16_BE; break;
+- default: ival = 0;
+- }
+- return put_user(ival, (int *) arg);
+- }
+-
+- case SOUND_PCM_READ_RATE:
+- ival = harmony.dac_rate;
+- return put_user(ival, (int *) arg);
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(ival, (int *) arg))
+- return -EFAULT;
+- harmony_set_rate(harmony_detect_rate(&ival));
+- harmony.dac_rate = ival;
+- return put_user(ival, (int*) arg);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(ival, (int *) arg))
+- return -EFAULT;
+- if (ival != 0 && ival != 1)
+- return -EINVAL;
+- harmony_set_stereo(ival);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(ival, (int *) arg))
+- return -EFAULT;
+- if (ival != 1 && ival != 2) {
+- ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2;
+- return put_user(ival, (int *) arg);
+- }
+- harmony_set_stereo(ival-1);
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- ival = HARMONY_BUF_SIZE;
+- return put_user(ival, (int *) arg);
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_RESET:
+- if (!harmony.suspended_recording) {
+- /* TODO: stop_recording() */
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(ival, (int *)arg))
+- return -EFAULT;
+- frag_size = ival & 0xffff;
+- frag_buf = (ival>>16) & 0xffff;
+- /* TODO: We use hardcoded fragment sizes and numbers for now */
+- frag_size = 12; /* 4096 == 2^12 */
+- frag_buf = MAX_BUFS;
+- ival = (frag_buf << 16) + frag_size;
+- return put_user(ival, (int *) arg);
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- info.fragstotal = MAX_BUFS;
+- info.fragments = MAX_BUFS - harmony.nb_filled_play;
+- info.fragsize = HARMONY_BUF_SIZE;
+- info.bytes = info.fragments * info.fragsize;
+- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- info.fragstotal = MAX_BUFS;
+- info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;
+- info.fragsize = HARMONY_BUF_SIZE;
+- info.bytes = info.fragments * info.fragsize;
+- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_SYNC:
+- return 0;
+- }
+-
+- return -EINVAL;
+-}
+-
+-
+-/*
+- * harmony_interrupt()
+- *
+- * harmony interruption service routine
+- *
+- */
+-
+-static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+-{
+- u32 dstatus;
+- struct harmony_hpa *hpa;
+-
+- /* Setup the hpa */
+- hpa = ((struct harmony_dev *)dev)->hpa;
+- harmony_wait_CNTL();
+-
+- /* Read dstatus and pcuradd (the current address) */
+- dstatus = gsc_readl(&hpa->dstatus);
+-
+- /* Turn off interrupts */
+- harmony_disable_interrupts();
+-
+- /* Check if this is a request to get the next play buffer */
+- if (dstatus & DSTATUS_PN) {
+- if (!harmony.nb_filled_play) {
+- harmony.suspended_playing = 1;
+- gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);
+-
+- if (!harmony.suspended_recording)
+- harmony_enable_interrupts();
+- } else {
+- harmony.suspended_playing = 0;
+- gsc_writel((unsigned long)played_buf.dma_handle +
+- (HARMONY_BUF_SIZE*harmony.first_filled_play),
+- &hpa->pnxtadd);
+- harmony.first_filled_play++;
+- harmony.first_filled_play %= MAX_BUFS;
+- harmony.nb_filled_play--;
+-
+- harmony_enable_interrupts();
+- }
+-
+- if (harmony.blocked_playing)
+- wake_up_interruptible(&harmony.wq_play);
+- }
+-
+- /* Check if we're being asked to fill in a recording buffer */
+- if (dstatus & DSTATUS_RN) {
+- if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
+- {
+- harmony.nb_filled_record = 0;
+- harmony.first_filled_record = 0;
+- harmony.suspended_recording = 1;
+- gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);
+- if (!harmony.suspended_playing)
+- harmony_enable_interrupts();
+- } else {
+- int buf_to_fill;
+- buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;
+- CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);
+- gsc_writel((unsigned long)recorded_buf.dma_handle +
+- HARMONY_BUF_SIZE*buf_to_fill,
+- &hpa->rnxtadd);
+- harmony.nb_filled_record++;
+- harmony_enable_interrupts();
+- }
+-
+- if (harmony.blocked_recording && harmony.nb_filled_record>3)
+- wake_up_interruptible(&harmony.wq_record);
+- }
+- return IRQ_HANDLED;
+-}
+-
+-/*
+- * Sound playing functions
+- */
+-
+-static struct file_operations harmony_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = harmony_audio_read,
+- .write = harmony_audio_write,
+- .poll = harmony_audio_poll,
+- .ioctl = harmony_audio_ioctl,
+- .open = harmony_audio_open,
+- .release = harmony_audio_release,
+-};
+-
+-static int harmony_audio_init(void)
+-{
+- /* Request that IRQ */
+- if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) {
+- printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq);
+- return -EFAULT;
+- }
+-
+- harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);
+- if (harmony.dsp_unit < 0) {
+- printk(KERN_ERR PFX "Error registering dsp\n");
+- free_irq(harmony.dev->irq, &harmony);
+- return -EFAULT;
+- }
+-
+- /* Clear the buffers so you don't end up with crap in the buffers. */
+- harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+-
+- /* Make sure this makes it to cache */
+- CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+-
+- /* Clear out the silent buffer and flush to cache */
+- harmony_silence(&silent, 0, HARMONY_BUF_SIZE);
+- CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);
+-
+- harmony.audio_open = 0;
+-
+- return 0;
+-}
+-
+-
+-/*
+- * mixer functions
+- */
+-
+-static void harmony_mixer_set_gain(void)
+-{
+- harmony_wait_CNTL();
+- gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);
+-}
+-
+-/*
+- * Read gain of selected channel.
+- * The OSS rate is from 0 (silent) to 100 -> need some conversions
+- *
+- * The harmony gain are attenuation for output and monitor gain.
+- * is amplifaction for input gain
+- */
+-#define to_harmony_level(level,max) ((level)*max/100)
+-#define to_oss_level(level,max) ((level)*100/max)
+-
+-static int harmony_mixer_get_level(int channel)
+-{
+- int left_level;
+- int right_level;
+-
+- switch (channel) {
+- case SOUND_MIXER_VOLUME:
+- left_level = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;
+- right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;
+- left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
+- right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
+- return (right_level << 8)+left_level;
+-
+- case SOUND_MIXER_IGAIN:
+- left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;
+- right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;
+- left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
+- right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);
+- return (right_level << 8)+left_level;
+-
+- case SOUND_MIXER_MONITOR:
+- left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;
+- left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
+- return (left_level << 8)+left_level;
+- }
+- return -EINVAL;
+-}
+-
+-
+-
+-/*
+- * Some conversions for the same reasons.
+- * We give back the new real value(s) due to
+- * the rescale.
+- */
+-
+-static int harmony_mixer_set_level(int channel, int value)
+-{
+- int left_level;
+- int right_level;
+- int new_left_level;
+- int new_right_level;
+-
+- right_level = (value & 0x0000ff00) >> 8;
+- left_level = value & 0x000000ff;
+- if (right_level > 100) right_level = 100;
+- if (left_level > 100) left_level = 100;
+-
+- switch (channel) {
+- case SOUND_MIXER_VOLUME:
+- right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);
+- left_level = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);
+- new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
+- new_left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
+- harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK))
+- | (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);
+- harmony_mixer_set_gain();
+- return (new_right_level << 8) + new_left_level;
+-
+- case SOUND_MIXER_IGAIN:
+- right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);
+- left_level = to_harmony_level(left_level, MAX_INPUT_LEVEL);
+- new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);
+- new_left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
+- harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))
+- | (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);
+- harmony_mixer_set_gain();
+- return (new_right_level << 8) + new_left_level;
+-
+- case SOUND_MIXER_MONITOR:
+- left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL);
+- new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
+- harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT);
+- harmony_mixer_set_gain();
+- return (new_left_level << 8) + new_left_level;
+- }
+-
+- return -EINVAL;
+-}
+-
+-#undef to_harmony_level
+-#undef to_oss_level
+-
+-/*
+- * Return the selected input device (mic or line)
+- */
+-
+-static int harmony_mixer_get_recmask(void)
+-{
+- int current_input_line;
+-
+- current_input_line = (harmony.current_gain & GAIN_IS_MASK)
+- >> GAIN_IS_SHIFT;
+- if (current_input_line)
+- return SOUND_MASK_MIC;
+-
+- return SOUND_MASK_LINE;
+-}
+-
+-/*
+- * Set the input (only one at time, arbitrary priority to line in)
+- */
+-
+-static int harmony_mixer_set_recmask(int recmask)
+-{
+- int new_input_line;
+- int new_input_mask;
+- int current_input_line;
+-
+- current_input_line = (harmony.current_gain & GAIN_IS_MASK)
+- >> GAIN_IS_SHIFT;
+- if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) ||
+- (!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) {
+- new_input_line = 0;
+- new_input_mask = SOUND_MASK_LINE;
+- } else {
+- new_input_line = 1;
+- new_input_mask = SOUND_MASK_MIC;
+- }
+- harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) |
+- (new_input_line << GAIN_IS_SHIFT ));
+- harmony_mixer_set_gain();
+- return new_input_mask;
+-}
+-
+-
+-/*
+- * give the active outlines
+- */
+-
+-static int harmony_mixer_get_outmask(void)
+-{
+- int outmask = 0;
+-
+- if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL;
+- if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT;
+- if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES;
+-
+- return outmask;
+-}
+-
+-
+-static int harmony_mixer_set_outmask(int outmask)
+-{
+- if (outmask & MASK_INTERNAL)
+- harmony.current_gain |= GAIN_SE_MASK;
+- else
+- harmony.current_gain &= ~GAIN_SE_MASK;
+-
+- if (outmask & MASK_LINEOUT)
+- harmony.current_gain |= GAIN_LE_MASK;
+- else
+- harmony.current_gain &= ~GAIN_LE_MASK;
+-
+- if (outmask & MASK_HEADPHONES)
+- harmony.current_gain |= GAIN_HE_MASK;
+- else
+- harmony.current_gain &= ~GAIN_HE_MASK;
+-
+- harmony_mixer_set_gain();
+-
+- return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES));
+-}
+-
+-/*
+- * This code is inspired from sb_mixer.c
+- */
+-
+-static int harmony_mixer_ioctl(struct inode * inode, struct file * file,
+- unsigned int cmd, unsigned long arg)
+-{
+- int val;
+- int ret;
+-
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strncpy(info.id, "harmony", sizeof(info.id)-1);
+- strncpy(info.name, "Harmony audio", sizeof(info.name)-1);
+- info.modify_counter = 1; /* ? */
+- if (copy_to_user((void *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+-
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, (int *)arg);
+-
+- /* read */
+- val = 0;
+- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+-
+- switch (cmd) {
+- case MIXER_READ(SOUND_MIXER_CAPS):
+- ret = SOUND_CAP_EXCL_INPUT;
+- break;
+- case MIXER_READ(SOUND_MIXER_STEREODEVS):
+- ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
+- break;
+-
+- case MIXER_READ(SOUND_MIXER_RECMASK):
+- ret = SOUND_MASK_MIC | SOUND_MASK_LINE;
+- break;
+- case MIXER_READ(SOUND_MIXER_DEVMASK):
+- ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN |
+- SOUND_MASK_MONITOR;
+- break;
+- case MIXER_READ(SOUND_MIXER_OUTMASK):
+- ret = MASK_INTERNAL | MASK_LINEOUT |
+- MASK_HEADPHONES;
+- break;
+-
+- case MIXER_WRITE(SOUND_MIXER_RECSRC):
+- ret = harmony_mixer_set_recmask(val);
+- break;
+- case MIXER_READ(SOUND_MIXER_RECSRC):
+- ret = harmony_mixer_get_recmask();
+- break;
+-
+- case MIXER_WRITE(SOUND_MIXER_OUTSRC):
+- ret = harmony_mixer_set_outmask(val);
+- break;
+- case MIXER_READ(SOUND_MIXER_OUTSRC):
+- ret = harmony_mixer_get_outmask();
+- break;
+-
+- case MIXER_WRITE(SOUND_MIXER_VOLUME):
+- case MIXER_WRITE(SOUND_MIXER_IGAIN):
+- case MIXER_WRITE(SOUND_MIXER_MONITOR):
+- ret = harmony_mixer_set_level(cmd & 0xff, val);
+- break;
+-
+- case MIXER_READ(SOUND_MIXER_VOLUME):
+- case MIXER_READ(SOUND_MIXER_IGAIN):
+- case MIXER_READ(SOUND_MIXER_MONITOR):
+- ret = harmony_mixer_get_level(cmd & 0xff);
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+-
+- if (put_user(ret, (int *)arg))
+- return -EFAULT;
+- return 0;
+-}
+-
+-
+-static int harmony_mixer_open(struct inode *inode, struct file *file)
+-{
+- if (harmony.mixer_open)
+- return -EBUSY;
+- harmony.mixer_open = 1;
+- return 0;
+-}
+-
+-static int harmony_mixer_release(struct inode *inode, struct file *file)
+-{
+- if (!harmony.mixer_open)
+- return -EBUSY;
+- harmony.mixer_open = 0;
+- return 0;
+-}
+-
+-static struct file_operations harmony_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .open = harmony_mixer_open,
+- .release = harmony_mixer_release,
+- .ioctl = harmony_mixer_ioctl,
+-};
+-
+-
+-/*
+- * Mute all the output and reset Harmony.
+- */
+-
+-static void __init harmony_mixer_reset(void)
+-{
+- harmony.current_gain = GAIN_TOTAL_SILENCE;
+- harmony_mixer_set_gain();
+- harmony_wait_CNTL();
+- gsc_writel(1, &harmony.hpa->reset);
+- mdelay(50); /* wait 50 ms */
+- gsc_writel(0, &harmony.hpa->reset);
+- harmony.current_gain = GAIN_DEFAULT;
+- harmony_mixer_set_gain();
+-}
+-
+-static int __init harmony_mixer_init(void)
+-{
+- /* Register the device file operations */
+- harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);
+- if (harmony.mixer_unit < 0) {
+- printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");
+- return -EFAULT;
+- }
+-
+- harmony_mixer_reset();
+- harmony.mixer_open = 0;
+-
+- return 0;
+-}
+-
+-
+-
+-/*
+- * This is the callback that's called by the inventory hardware code
+- * if it finds a match to the registered driver.
+- */
+-static int __devinit
+-harmony_driver_probe(struct parisc_device *dev)
+-{
+- u8 id;
+- u8 rev;
+- u32 cntl;
+- int ret;
+-
+- if (harmony.hpa) {
+- /* We only support one Harmony at this time */
+- printk(KERN_ERR PFX "driver already registered\n");
+- return -EBUSY;
+- }
+-
+- if (!dev->irq) {
+- printk(KERN_ERR PFX "no irq found\n");
+- return -ENODEV;
+- }
+-
+- /* Set the HPA of harmony */
+- harmony.hpa = (struct harmony_hpa *)dev->hpa.start;
+- harmony.dev = dev;
+-
+- /* Grab the ID and revision from the device */
+- id = gsc_readb(&harmony.hpa->id);
+- if ((id | 1) != 0x15) {
+- printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);
+- return -EBUSY;
+- }
+- cntl = gsc_readl(&harmony.hpa->cntl);
+- rev = (cntl>>20) & 0xff;
+-
+- printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "
+- "h/w id %i, rev. %i at 0x%lx, IRQ %i\n",
+- id, rev, dev->hpa.start, harmony.dev->irq);
+-
+- /* Make sure the control bit isn't set, although I don't think it
+- ever is. */
+- if (cntl & CNTL_C) {
+- printk(KERN_WARNING PFX "CNTL busy\n");
+- harmony.hpa = 0;
+- return -EBUSY;
+- }
+-
+- /* Initialize the memory buffers */
+- if (harmony_alloc_buffer(&played_buf, MAX_BUFS) ||
+- harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||
+- harmony_alloc_buffer(&graveyard, 1) ||
+- harmony_alloc_buffer(&silent, 1)) {
+- ret = -EBUSY;
+- goto out_err;
+- }
+-
+- /* Initialize /dev/mixer and /dev/audio */
+- if ((ret=harmony_mixer_init()))
+- goto out_err;
+- if ((ret=harmony_audio_init()))
+- goto out_err;
+-
+- return 0;
+-
+-out_err:
+- harmony.hpa = 0;
+- harmony_free_buffer(&played_buf);
+- harmony_free_buffer(&recorded_buf);
+- harmony_free_buffer(&graveyard);
+- harmony_free_buffer(&silent);
+- return ret;
+-}
+-
+-
+-static struct parisc_device_id harmony_tbl[] = {
+- /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */
+- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */
+- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */
+- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(parisc, harmony_tbl);
+-
+-static struct parisc_driver harmony_driver = {
+- .name = "Lasi Harmony",
+- .id_table = harmony_tbl,
+- .probe = harmony_driver_probe,
+-};
+-
+-static int __init init_harmony(void)
+-{
+- return register_parisc_driver(&harmony_driver);
+-}
+-
+-static void __exit cleanup_harmony(void)
+-{
+- free_irq(harmony.dev->irq, &harmony);
+- unregister_sound_mixer(harmony.mixer_unit);
+- unregister_sound_dsp(harmony.dsp_unit);
+- harmony_free_buffer(&played_buf);
+- harmony_free_buffer(&recorded_buf);
+- harmony_free_buffer(&graveyard);
+- harmony_free_buffer(&silent);
+- unregister_parisc_driver(&harmony_driver);
+-}
+-
+-
+-MODULE_AUTHOR("Alex DeVries <alex at onefishtwo.ca>");
+-MODULE_DESCRIPTION("Harmony sound driver");
+-MODULE_LICENSE("GPL");
+-
+-module_init(init_harmony);
+-module_exit(cleanup_harmony);
+-
+diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
+index ddcddc2..240cc79 100644
+--- a/sound/oss/i810_audio.c
++++ b/sound/oss/i810_audio.c
+@@ -1523,9 +1523,9 @@ static void i810_channel_interrupt(struc
+ #endif
+ }
+
+-static irqreturn_t i810_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t i810_interrupt(int irq, void *dev_id)
+ {
+- struct i810_card *card = (struct i810_card *)dev_id;
++ struct i810_card *card = dev_id;
+ u32 status;
+
+ spin_lock(&card->lock);
+diff --git a/sound/oss/ics2101.c b/sound/oss/ics2101.c
+deleted file mode 100644
+index d5f3be8..0000000
+--- a/sound/oss/ics2101.c
++++ /dev/null
+@@ -1,247 +0,0 @@
+-/*
+- * sound/ics2101.c
+- *
+- * Driver for the ICS2101 mixer of GUS v3.7.
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- *
+- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+- * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
+- */
+-#include <linux/init.h>
+-#include <linux/spinlock.h>
+-#include "sound_config.h"
+-
+-#include <linux/ultrasound.h>
+-
+-#include "gus.h"
+-#include "gus_hw.h"
+-
+-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+- SOUND_MASK_SYNTH| \
+- SOUND_MASK_CD | SOUND_MASK_VOLUME)
+-
+-extern int *gus_osp;
+-extern int gus_base;
+-extern spinlock_t gus_lock;
+-static int volumes[ICS_MIXDEVS];
+-static int left_fix[ICS_MIXDEVS] =
+-{1, 1, 1, 2, 1, 2};
+-static int right_fix[ICS_MIXDEVS] =
+-{2, 2, 2, 1, 2, 1};
+-
+-static int scale_vol(int vol)
+-{
+- /*
+- * Experimental volume scaling by Risto Kankkunen.
+- * This should give smoother volume response than just
+- * a plain multiplication.
+- */
+-
+- int e;
+-
+- if (vol < 0)
+- vol = 0;
+- if (vol > 100)
+- vol = 100;
+- vol = (31 * vol + 50) / 100;
+- e = 0;
+- if (vol)
+- {
+- while (vol < 16)
+- {
+- vol <<= 1;
+- e--;
+- }
+- vol -= 16;
+- e += 7;
+- }
+- return ((e << 4) + vol);
+-}
+-
+-static void write_mix(int dev, int chn, int vol)
+-{
+- int *selector;
+- unsigned long flags;
+- int ctrl_addr = dev << 3;
+- int attn_addr = dev << 3;
+-
+- vol = scale_vol(vol);
+-
+- if (chn == CHN_LEFT)
+- {
+- selector = left_fix;
+- ctrl_addr |= 0x00;
+- attn_addr |= 0x02;
+- }
+- else
+- {
+- selector = right_fix;
+- ctrl_addr |= 0x01;
+- attn_addr |= 0x03;
+- }
+-
+- spin_lock_irqsave(&gus_lock, flags);
+- outb((ctrl_addr), u_MixSelect);
+- outb((selector[dev]), u_MixData);
+- outb((attn_addr), u_MixSelect);
+- outb(((unsigned char) vol), u_MixData);
+- spin_unlock_irqrestore(&gus_lock,flags);
+-}
+-
+-static int set_volumes(int dev, int vol)
+-{
+- int left = vol & 0x00ff;
+- int right = (vol >> 8) & 0x00ff;
+-
+- if (left < 0)
+- left = 0;
+- if (left > 100)
+- left = 100;
+- if (right < 0)
+- right = 0;
+- if (right > 100)
+- right = 100;
+-
+- write_mix(dev, CHN_LEFT, left);
+- write_mix(dev, CHN_RIGHT, right);
+-
+- vol = left + (right << 8);
+- volumes[dev] = vol;
+- return vol;
+-}
+-
+-static int ics2101_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
+-{
+- int val;
+-
+- if (((cmd >> 8) & 0xff) == 'M') {
+- if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+-
+- if (get_user(val, (int __user *)arg))
+- return -EFAULT;
+- switch (cmd & 0xff) {
+- case SOUND_MIXER_RECSRC:
+- return gus_default_mixer_ioctl(dev, cmd, arg);
+-
+- case SOUND_MIXER_MIC:
+- val = set_volumes(DEV_MIC, val);
+- break;
+-
+- case SOUND_MIXER_CD:
+- val = set_volumes(DEV_CD, val);
+- break;
+-
+- case SOUND_MIXER_LINE:
+- val = set_volumes(DEV_LINE, val);
+- break;
+-
+- case SOUND_MIXER_SYNTH:
+- val = set_volumes(DEV_GF1, val);
+- break;
+-
+- case SOUND_MIXER_VOLUME:
+- val = set_volumes(DEV_VOL, val);
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- return put_user(val, (int __user *)arg);
+- } else {
+- switch (cmd & 0xff) {
+- /*
+- * Return parameters
+- */
+- case SOUND_MIXER_RECSRC:
+- return gus_default_mixer_ioctl(dev, cmd, arg);
+-
+- case SOUND_MIXER_DEVMASK:
+- val = MIX_DEVS;
+- break;
+-
+- case SOUND_MIXER_STEREODEVS:
+- val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC;
+- break;
+-
+- case SOUND_MIXER_RECMASK:
+- val = SOUND_MASK_MIC | SOUND_MASK_LINE;
+- break;
+-
+- case SOUND_MIXER_CAPS:
+- val = 0;
+- break;
+-
+- case SOUND_MIXER_MIC:
+- val = volumes[DEV_MIC];
+- break;
+-
+- case SOUND_MIXER_LINE:
+- val = volumes[DEV_LINE];
+- break;
+-
+- case SOUND_MIXER_CD:
+- val = volumes[DEV_CD];
+- break;
+-
+- case SOUND_MIXER_VOLUME:
+- val = volumes[DEV_VOL];
+- break;
+-
+- case SOUND_MIXER_SYNTH:
+- val = volumes[DEV_GF1];
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- return put_user(val, (int __user *)arg);
+- }
+- }
+- return -EINVAL;
+-}
+-
+-static struct mixer_operations ics2101_mixer_operations =
+-{
+- .owner = THIS_MODULE,
+- .id = "ICS2101",
+- .name = "ICS2101 Multimedia Mixer",
+- .ioctl = ics2101_mixer_ioctl
+-};
+-
+-int __init ics2101_mixer_init(void)
+-{
+- int i;
+- int n;
+-
+- if ((n = sound_alloc_mixerdev()) != -1)
+- {
+- mixer_devs[n] = &ics2101_mixer_operations;
+-
+- /*
+- * Some GUS v3.7 cards had some channels flipped. Disable
+- * the flipping feature if the model id is other than 5.
+- */
+-
+- if (inb(u_MixSelect) != 5)
+- {
+- for (i = 0; i < ICS_MIXDEVS; i++)
+- left_fix[i] = 1;
+- for (i = 0; i < ICS_MIXDEVS; i++)
+- right_fix[i] = 2;
+- }
+- set_volumes(DEV_GF1, 0x5a5a);
+- set_volumes(DEV_CD, 0x5a5a);
+- set_volumes(DEV_MIC, 0x0000);
+- set_volumes(DEV_LINE, 0x5a5a);
+- set_volumes(DEV_VOL, 0x5a5a);
+- set_volumes(DEV_UNUSED, 0x0000);
+- }
+- return n;
+-}
+diff --git a/sound/oss/ite8172.c b/sound/oss/ite8172.c
+deleted file mode 100644
+index 68aab36..0000000
+--- a/sound/oss/ite8172.c
++++ /dev/null
+@@ -1,2261 +0,0 @@
+-/*
+- * ite8172.c -- ITE IT8172G Sound Driver.
+- *
+- * Copyright 2001 MontaVista Software Inc.
+- * Author: MontaVista Software, Inc.
+- * stevel at mvista.com or source at 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.
+- *
+- * 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.
+- *
+- *
+- * Module command line parameters:
+- *
+- * Supported devices:
+- * /dev/dsp standard OSS /dev/dsp device
+- * /dev/mixer standard OSS /dev/mixer device
+- *
+- * Notes:
+- *
+- * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are
+- * taken, slightly modified or not at all, from the ES1371 driver,
+- * so refer to the credits in es1371.c for those. The rest of the
+- * code (probe, open, read, write, the ISR, etc.) is new.
+- * 2. The following support is untested:
+- * * Memory mapping the audio buffers, and the ioctl controls that go
+- * with it.
+- * * S/PDIF output.
+- * * I2S support.
+- * 3. The following is not supported:
+- * * legacy audio mode.
+- * 4. Support for volume button interrupts is implemented but doesn't
+- * work yet.
+- *
+- * Revision history
+- * 02.08.2001 Initial release
+- * 06.22.2001 Added I2S support
+- * 07.30.2003 Removed initialisation to zero for static variables
+- * (spdif[NR_DEVICE], i2s_fmt[NR_DEVICE], and devindex)
+- */
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/poll.h>
+-#include <linux/bitops.h>
+-#include <linux/proc_fs.h>
+-#include <linux/spinlock.h>
+-#include <linux/smp_lock.h>
+-#include <linux/ac97_codec.h>
+-#include <linux/interrupt.h>
+-#include <linux/mutex.h>
+-
+-#include <asm/io.h>
+-#include <asm/dma.h>
+-#include <asm/uaccess.h>
+-#include <asm/it8172/it8172.h>
+-
+-/* --------------------------------------------------------------------- */
+-
+-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+-#define IT8172_DEBUG
+-#undef IT8172_VERBOSE_DEBUG
+-#define DBG(x) {}
+-
+-#define IT8172_MODULE_NAME "IT8172 audio"
+-#define PFX IT8172_MODULE_NAME
+-
+-#ifdef IT8172_DEBUG
+-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+-#else
+-#define dbg(format, arg...) do {} while (0)
+-#endif
+-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+-
+-
+-#define IT8172_MODULE_NAME "IT8172 audio"
+-#define PFX IT8172_MODULE_NAME
+-
+-#ifdef IT8172_DEBUG
+-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+-#else
+-#define dbg(format, arg...) do {} while (0)
+-#endif
+-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+-
+-
+-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+-
+-
+-/*
+- * Audio Controller register bit definitions follow. See
+- * include/asm/it8172/it8172.h for register offsets.
+- */
+-
+-/* PCM Out Volume Reg */
+-#define PCMOV_PCMOM (1<<15) /* PCM Out Mute default 1: mute */
+-#define PCMOV_PCMRCG_BIT 8 /* PCM Right channel Gain */
+-#define PCMOV_PCMRCG_MASK (0x1f<<PCMOV_PCMRCG_BIT)
+-#define PCMOV_PCMLCG_BIT 0 /* PCM Left channel gain */
+-#define PCMOV_PCMLCG_MASK 0x1f
+-
+-/* FM Out Volume Reg */
+-#define FMOV_FMOM (1<<15) /* FM Out Mute default 1: mute */
+-#define FMOV_FMRCG_BIT 8 /* FM Right channel Gain */
+-#define FMOV_FMRCG_MASK (0x1f<<FMOV_FMRCG_BIT)
+-#define FMOV_FMLCG_BIT 0 /* FM Left channel gain */
+-#define FMOV_FMLCG_MASK 0x1f
+-
+-/* I2S Out Volume Reg */
+-#define I2SV_I2SOM (1<<15) /* I2S Out Mute default 1: mute */
+-#define I2SV_I2SRCG_BIT 8 /* I2S Right channel Gain */
+-#define I2SV_I2SRCG_MASK (0x1f<<I2SV_I2SRCG_BIT)
+-#define I2SV_I2SLCG_BIT 0 /* I2S Left channel gain */
+-#define I2SV_I2SLCG_MASK 0x1f
+-
+-/* Digital Recording Source Select Reg */
+-#define DRSS_BIT 0
+-#define DRSS_MASK 0x07
+-#define DRSS_AC97_PRIM 0
+-#define DRSS_FM 1
+-#define DRSS_I2S 2
+-#define DRSS_PCM 3
+-#define DRSS_AC97_SEC 4
+-
+-/* Playback/Capture Channel Control Registers */
+-#define CC_SM (1<<15) /* Stereo, Mone 0: mono 1: stereo */
+-#define CC_DF (1<<14) /* Data Format 0: 8 bit 1: 16 bit */
+-#define CC_FMT_BIT 14
+-#define CC_FMT_MASK (0x03<<CC_FMT_BIT)
+-#define CC_CF_BIT 12 /* Channel format (Playback only) */
+-#define CC_CF_MASK (0x03<<CC_CF_BIT)
+-#define CC_CF_2 0
+-#define CC_CF_4 (1<<CC_CF_BIT)
+-#define CC_CF_6 (2<<CC_CF_BIT)
+-#define CC_SR_BIT 8 /* sample Rate */
+-#define CC_SR_MASK (0x0f<<CC_SR_BIT)
+-#define CC_SR_5500 0
+-#define CC_SR_8000 (1<<CC_SR_BIT)
+-#define CC_SR_9600 (2<<CC_SR_BIT)
+-#define CC_SR_11025 (3<<CC_SR_BIT)
+-#define CC_SR_16000 (4<<CC_SR_BIT)
+-#define CC_SR_19200 (5<<CC_SR_BIT)
+-#define CC_SR_22050 (6<<CC_SR_BIT)
+-#define CC_SR_32000 (7<<CC_SR_BIT)
+-#define CC_SR_38400 (8<<CC_SR_BIT)
+-#define CC_SR_44100 (9<<CC_SR_BIT)
+-#define CC_SR_48000 (10<<CC_SR_BIT)
+-#define CC_CSP (1<<7) /* Channel stop
+- * 0: End of Current buffer
+- * 1: Immediately stop when rec stop */
+-#define CC_CP (1<<6) /* Channel pause 0: normal, 1: pause */
+-#define CC_CA (1<<5) /* Channel Action 0: Stop , 1: start */
+-#define CC_CB2L (1<<2) /* Cur. buf. 2 xfr is last 0: No, 1: Yes */
+-#define CC_CB1L (1<<1) /* Cur. buf. 1 xfr is last 0: No, 1: Yes */
+-#define CC_DE 1 /* DFC/DFIFO Data Empty 1: empty, 0: not empty
+- * (Playback only)
+- */
+-
+-/* Codec Control Reg */
+-#define CODECC_GME (1<<9) /* AC97 GPIO Mode enable */
+-#define CODECC_ATM (1<<8) /* AC97 ATE test mode 0: test 1: normal */
+-#define CODECC_WR (1<<6) /* AC97 Warn reset 1: warm reset , 0: Normal */
+-#define CODECC_CR (1<<5) /* AC97 Cold reset 1: Cold reset , 0: Normal */
+-
+-
+-/* I2S Control Reg */
+-#define I2SMC_SR_BIT 6 /* I2S Sampling rate
+- * 00: 48KHz, 01: 44.1 KHz, 10: 32 32 KHz */
+-#define I2SMC_SR_MASK (0x03<<I2SMC_SR_BIT)
+-#define I2SMC_SR_48000 0
+-#define I2SMC_SR_44100 (1<<I2SMC_SR_BIT)
+-#define I2SMC_SR_32000 (2<<I2SMC_SR_BIT)
+-#define I2SMC_SRSS (1<<5) /* Sample Rate Source Select 1:S/W, 0: H/W */
+-#define I2SMC_I2SF_BIT 0 /* I2S Format */
+-#define I2SMC_I2SF_MASK 0x03
+-#define I2SMC_I2SF_DAC 0
+-#define I2SMC_I2SF_ADC 2
+-#define I2SMC_I2SF_I2S 3
+-
+-
+-/* Volume up, Down, Mute */
+-#define VS_VMP (1<<2) /* Volume mute 1: pushed, 0: not */
+-#define VS_VDP (1<<1) /* Volume Down 1: pushed, 0: not */
+-#define VS_VUP 1 /* Volime Up 1: pushed, 0: not */
+-
+-/* SRC, Mixer test control/DFC status reg */
+-#define SRCS_DPUSC (1<<5) /* DFC Playback underrun Status/clear */
+-#define SRCS_DCOSC (1<<4) /* DFC Capture Overrun Status/clear */
+-#define SRCS_SIS (1<<3) /* SRC input select 1: Mixer, 0: Codec I/F */
+-#define SRCS_CDIS_BIT 0 /* Codec Data Input Select */
+-#define SRCS_CDIS_MASK 0x07
+-#define SRCS_CDIS_MIXER 0
+-#define SRCS_CDIS_PCM 1
+-#define SRCS_CDIS_I2S 2
+-#define SRCS_CDIS_FM 3
+-#define SRCS_CDIS_DFC 4
+-
+-
+-/* Codec Index Reg command Port */
+-#define CIRCP_CID_BIT 10
+-#define CIRCP_CID_MASK (0x03<<CIRCP_CID_BIT)
+-#define CIRCP_CPS (1<<9) /* Command Port Status 0: ready, 1: busy */
+-#define CIRCP_DPVF (1<<8) /* Data Port Valid Flag 0: invalis, 1: valid */
+-#define CIRCP_RWC (1<<7) /* Read/write command */
+-#define CIRCP_CIA_BIT 0
+-#define CIRCP_CIA_MASK 0x007F /* Codec Index Address */
+-
+-/* Test Mode Control/Test group Select Control */
+-
+-/* General Control Reg */
+-#define GC_VDC_BIT 6 /* Volume Division Control */
+-#define GC_VDC_MASK (0x03<<GC_VDC_BIT)
+-#define GC_VDC_NONE 0
+-#define GC_VDC_DIV2 (1<<GC_VDC_BIT)
+-#define GC_VDC_DIV4 (2<<GC_VDC_BIT)
+-#define GC_SOE (1<<2) /* S/PDIF Output enable */
+-#define GC_SWR 1 /* Software warn reset */
+-
+-/* Interrupt mask Control Reg */
+-#define IMC_VCIM (1<<6) /* Volume CNTL interrupt mask */
+-#define IMC_CCIM (1<<1) /* Capture Chan. iterrupt mask */
+-#define IMC_PCIM 1 /* Playback Chan. interrupt mask */
+-
+-/* Interrupt status/clear reg */
+-#define ISC_VCI (1<<6) /* Volume CNTL interrupt 1: clears */
+-#define ISC_CCI (1<<1) /* Capture Chan. interrupt 1: clears */
+-#define ISC_PCI 1 /* Playback Chan. interrupt 1: clears */
+-
+-/* misc stuff */
+-#define POLL_COUNT 0x5000
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-/*
+- * Define DIGITAL1 as the I2S channel, since it is not listed in
+- * soundcard.h.
+- */
+-#define SOUND_MIXER_I2S SOUND_MIXER_DIGITAL1
+-#define SOUND_MASK_I2S SOUND_MASK_DIGITAL1
+-#define SOUND_MIXER_READ_I2S MIXER_READ(SOUND_MIXER_I2S)
+-#define SOUND_MIXER_WRITE_I2S MIXER_WRITE(SOUND_MIXER_I2S)
+-
+-/* --------------------------------------------------------------------- */
+-
+-struct it8172_state {
+- /* list of it8172 devices */
+- struct list_head devs;
+-
+- /* the corresponding pci_dev structure */
+- struct pci_dev *dev;
+-
+- /* soundcore stuff */
+- int dev_audio;
+-
+- /* hardware resources */
+- unsigned long io;
+- unsigned int irq;
+-
+- /* PCI ID's */
+- u16 vendor;
+- u16 device;
+- u8 rev; /* the chip revision */
+-
+- /* options */
+- int spdif_volume; /* S/PDIF output is enabled if != -1 */
+- int i2s_volume; /* current I2S out volume, in OSS format */
+- int i2s_recording;/* 1 = recording from I2S, 0 = not */
+-
+-#ifdef IT8172_DEBUG
+- /* debug /proc entry */
+- struct proc_dir_entry *ps;
+- struct proc_dir_entry *ac97_ps;
+-#endif /* IT8172_DEBUG */
+-
+- struct ac97_codec codec;
+-
+- unsigned short pcc, capcc;
+- unsigned dacrate, adcrate;
+-
+- spinlock_t lock;
+- struct mutex open_mutex;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+-
+- struct dmabuf {
+- void *rawbuf;
+- dma_addr_t dmaaddr;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- void* nextIn;
+- void* nextOut;
+- int count;
+- int curBufPtr;
+- unsigned total_bytes;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize;
+- unsigned fragsamples;
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned stopped:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac, dma_adc;
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static LIST_HEAD(devs);
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline unsigned ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static void it8172_delay(int msec)
+-{
+- unsigned long tmo;
+- signed long tmo2;
+-
+- if (in_interrupt())
+- return;
+-
+- tmo = jiffies + (msec*HZ)/1000;
+- for (;;) {
+- tmo2 = tmo - jiffies;
+- if (tmo2 <= 0)
+- break;
+- schedule_timeout(tmo2);
+- }
+-}
+-
+-
+-static unsigned short
+-get_compat_rate(unsigned* rate)
+-{
+- unsigned rate_out = *rate;
+- unsigned short sr;
+-
+- if (rate_out >= 46050) {
+- sr = CC_SR_48000; rate_out = 48000;
+- } else if (rate_out >= 41250) {
+- sr = CC_SR_44100; rate_out = 44100;
+- } else if (rate_out >= 35200) {
+- sr = CC_SR_38400; rate_out = 38400;
+- } else if (rate_out >= 27025) {
+- sr = CC_SR_32000; rate_out = 32000;
+- } else if (rate_out >= 20625) {
+- sr = CC_SR_22050; rate_out = 22050;
+- } else if (rate_out >= 17600) {
+- sr = CC_SR_19200; rate_out = 19200;
+- } else if (rate_out >= 13513) {
+- sr = CC_SR_16000; rate_out = 16000;
+- } else if (rate_out >= 10313) {
+- sr = CC_SR_11025; rate_out = 11025;
+- } else if (rate_out >= 8800) {
+- sr = CC_SR_9600; rate_out = 9600;
+- } else if (rate_out >= 6750) {
+- sr = CC_SR_8000; rate_out = 8000;
+- } else {
+- sr = CC_SR_5500; rate_out = 5500;
+- }
+-
+- *rate = rate_out;
+- return sr;
+-}
+-
+-static void set_adc_rate(struct it8172_state *s, unsigned rate)
+-{
+- unsigned long flags;
+- unsigned short sr;
+-
+- sr = get_compat_rate(&rate);
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->capcc &= ~CC_SR_MASK;
+- s->capcc |= sr;
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- s->adcrate = rate;
+-}
+-
+-
+-static void set_dac_rate(struct it8172_state *s, unsigned rate)
+-{
+- unsigned long flags;
+- unsigned short sr;
+-
+- sr = get_compat_rate(&rate);
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->pcc &= ~CC_SR_MASK;
+- s->pcc |= sr;
+- outw(s->pcc, s->io+IT_AC_PCC);
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- s->dacrate = rate;
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static u16 rdcodec(struct ac97_codec *codec, u8 addr)
+-{
+- struct it8172_state *s = (struct it8172_state *)codec->private_data;
+- unsigned long flags;
+- unsigned short circp, data;
+- int i;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- for (i = 0; i < POLL_COUNT; i++)
+- if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS))
+- break;
+- if (i == POLL_COUNT)
+- err("rdcodec: codec ready poll expired!");
+-
+- circp = addr & CIRCP_CIA_MASK;
+- circp |= (codec->id << CIRCP_CID_BIT);
+- circp |= CIRCP_RWC; // read command
+- outw(circp, s->io+IT_AC_CIRCP);
+-
+- /* now wait for the data */
+- for (i = 0; i < POLL_COUNT; i++)
+- if (inw(s->io+IT_AC_CIRCP) & CIRCP_DPVF)
+- break;
+- if (i == POLL_COUNT)
+- err("rdcodec: read poll expired!");
+-
+- data = inw(s->io+IT_AC_CIRDP);
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- return data;
+-}
+-
+-
+-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
+-{
+- struct it8172_state *s = (struct it8172_state *)codec->private_data;
+- unsigned long flags;
+- unsigned short circp;
+- int i;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- for (i = 0; i < POLL_COUNT; i++)
+- if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS))
+- break;
+- if (i == POLL_COUNT)
+- err("wrcodec: codec ready poll expired!");
+-
+- circp = addr & CIRCP_CIA_MASK;
+- circp |= (codec->id << CIRCP_CID_BIT);
+- circp &= ~CIRCP_RWC; // write command
+-
+- outw(data, s->io+IT_AC_CIRDP); // send data first
+- outw(circp, s->io+IT_AC_CIRCP);
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-
+-static void waitcodec(struct ac97_codec *codec)
+-{
+- unsigned short temp;
+-
+- /* codec_wait is used to wait for a ready state after
+- an AC97_RESET. */
+- it8172_delay(10);
+-
+- temp = rdcodec(codec, 0x26);
+-
+- // If power down, power up
+- if (temp & 0x3f00) {
+- // Power on
+- wrcodec(codec, 0x26, 0);
+- it8172_delay(100);
+- // Reread
+- temp = rdcodec(codec, 0x26);
+- }
+-
+- // Check if Codec REF,ANL,DAC,ADC ready***/
+- if ((temp & 0x3f0f) != 0x000f) {
+- err("codec reg 26 status (0x%x) not ready!!", temp);
+- return;
+- }
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline void stop_adc(struct it8172_state *s)
+-{
+- struct dmabuf* db = &s->dma_adc;
+- unsigned long flags;
+- unsigned char imc;
+-
+- if (db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- s->capcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L);
+- s->capcc |= CC_CSP;
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+-
+- // disable capture interrupt
+- imc = inb(s->io+IT_AC_IMC);
+- outb(imc | IMC_CCIM, s->io+IT_AC_IMC);
+-
+- db->stopped = 1;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static inline void stop_dac(struct it8172_state *s)
+-{
+- struct dmabuf* db = &s->dma_dac;
+- unsigned long flags;
+- unsigned char imc;
+-
+- if (db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- s->pcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L);
+- s->pcc |= CC_CSP;
+- outw(s->pcc, s->io+IT_AC_PCC);
+-
+- // disable playback interrupt
+- imc = inb(s->io+IT_AC_IMC);
+- outb(imc | IMC_PCIM, s->io+IT_AC_IMC);
+-
+- db->stopped = 1;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_dac(struct it8172_state *s)
+-{
+- struct dmabuf* db = &s->dma_dac;
+- unsigned long flags;
+- unsigned char imc;
+- unsigned long buf1, buf2;
+-
+- if (!db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- // reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize
+- buf1 = virt_to_bus(db->nextOut);
+- buf2 = buf1 + db->fragsize;
+- if (buf2 >= db->dmaaddr + db->dmasize)
+- buf2 -= db->dmasize;
+-
+- outl(buf1, s->io+IT_AC_PCB1STA);
+- outl(buf2, s->io+IT_AC_PCB2STA);
+- db->curBufPtr = IT_AC_PCB1STA;
+-
+- // enable playback interrupt
+- imc = inb(s->io+IT_AC_IMC);
+- outb(imc & ~IMC_PCIM, s->io+IT_AC_IMC);
+-
+- s->pcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L);
+- s->pcc |= CC_CA;
+- outw(s->pcc, s->io+IT_AC_PCC);
+-
+- db->stopped = 0;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_adc(struct it8172_state *s)
+-{
+- struct dmabuf* db = &s->dma_adc;
+- unsigned long flags;
+- unsigned char imc;
+- unsigned long buf1, buf2;
+-
+- if (!db->stopped)
+- return;
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- // reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize
+- buf1 = virt_to_bus(db->nextIn);
+- buf2 = buf1 + db->fragsize;
+- if (buf2 >= db->dmaaddr + db->dmasize)
+- buf2 -= db->dmasize;
+-
+- outl(buf1, s->io+IT_AC_CAPB1STA);
+- outl(buf2, s->io+IT_AC_CAPB2STA);
+- db->curBufPtr = IT_AC_CAPB1STA;
+-
+- // enable capture interrupt
+- imc = inb(s->io+IT_AC_IMC);
+- outb(imc & ~IMC_CCIM, s->io+IT_AC_IMC);
+-
+- s->capcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L);
+- s->capcc |= CC_CA;
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+-
+- db->stopped = 0;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-static inline void dealloc_dmabuf(struct it8172_state *s, struct dmabuf *db)
+-{
+- struct page *page, *pend;
+-
+- if (db->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(db->rawbuf +
+- (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder,
+- db->rawbuf, db->dmaaddr);
+- }
+- db->rawbuf = db->nextIn = db->nextOut = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct it8172_state *s, struct dmabuf *db,
+- unsigned rate, unsigned fmt, unsigned reg)
+-{
+- int order;
+- unsigned bytepersec;
+- unsigned bufs;
+- struct page *page, *pend;
+-
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = DMABUF_DEFAULTORDER;
+- order >= DMABUF_MINORDER; order--)
+- if ((db->rawbuf =
+- pci_alloc_consistent(s->dev,
+- PAGE_SIZE << order,
+- &db->dmaaddr)))
+- break;
+- if (!db->rawbuf)
+- return -ENOMEM;
+- db->buforder = order;
+- /* now mark the pages as reserved;
+- otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(db->rawbuf +
+- (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- }
+-
+- db->count = 0;
+- db->nextIn = db->nextOut = db->rawbuf;
+-
+- bytepersec = rate << sample_shift[fmt];
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytepersec)
+- db->fragshift = ld2(bytepersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytepersec/100/(db->subdivision ?
+- db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- db->fragsamples = db->fragsize >> sample_shift[fmt];
+- db->dmasize = db->numfrag << db->fragshift;
+- memset(db->rawbuf, (fmt & (CC_DF>>CC_FMT_BIT)) ? 0 : 0x80, bufs);
+-
+-#ifdef IT8172_VERBOSE_DEBUG
+- dbg("rate=%d, fragsize=%d, numfrag=%d, dmasize=%d",
+- rate, db->fragsize, db->numfrag, db->dmasize);
+-#endif
+-
+- // set data length register
+- outw(db->fragsize, s->io+reg+2);
+- db->ready = 1;
+-
+- return 0;
+-}
+-
+-static inline int prog_dmabuf_adc(struct it8172_state *s)
+-{
+- stop_adc(s);
+- return prog_dmabuf(s, &s->dma_adc, s->adcrate,
+- (s->capcc & CC_FMT_MASK) >> CC_FMT_BIT,
+- IT_AC_CAPCC);
+-}
+-
+-static inline int prog_dmabuf_dac(struct it8172_state *s)
+-{
+- stop_dac(s);
+- return prog_dmabuf(s, &s->dma_dac, s->dacrate,
+- (s->pcc & CC_FMT_MASK) >> CC_FMT_BIT,
+- IT_AC_PCC);
+-}
+-
+-
+-/* hold spinlock for the following! */
+-
+-static irqreturn_t it8172_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct it8172_state *s = (struct it8172_state *)dev_id;
+- struct dmabuf* dac = &s->dma_dac;
+- struct dmabuf* adc = &s->dma_adc;
+- unsigned char isc, vs;
+- unsigned short vol, mute;
+- unsigned long newptr;
+-
+- spin_lock(&s->lock);
+-
+- isc = inb(s->io+IT_AC_ISC);
+-
+- /* fastpath out, to ease interrupt sharing */
+- if (!(isc & (ISC_VCI | ISC_CCI | ISC_PCI))) {
+- spin_unlock(&s->lock);
+- return IRQ_NONE;
+- }
+-
+- /* clear audio interrupts first */
+- outb(isc | ISC_VCI | ISC_CCI | ISC_PCI, s->io+IT_AC_ISC);
+-
+- /* handle volume button events (ignore if S/PDIF enabled) */
+- if ((isc & ISC_VCI) && s->spdif_volume == -1) {
+- vs = inb(s->io+IT_AC_VS);
+- outb(0, s->io+IT_AC_VS);
+- vol = inw(s->io+IT_AC_PCMOV);
+- mute = vol & PCMOV_PCMOM;
+- vol &= PCMOV_PCMLCG_MASK;
+- if ((vs & VS_VUP) && vol > 0)
+- vol--;
+- if ((vs & VS_VDP) && vol < 0x1f)
+- vol++;
+- vol |= (vol << PCMOV_PCMRCG_BIT);
+- if (vs & VS_VMP)
+- vol |= (mute ^ PCMOV_PCMOM);
+- outw(vol, s->io+IT_AC_PCMOV);
+- }
+-
+- /* update capture pointers */
+- if (isc & ISC_CCI) {
+- if (adc->count > adc->dmasize - adc->fragsize) {
+- // Overrun. Stop ADC and log the error
+- stop_adc(s);
+- adc->error++;
+- dbg("adc overrun");
+- } else {
+- newptr = virt_to_bus(adc->nextIn) + 2*adc->fragsize;
+- if (newptr >= adc->dmaaddr + adc->dmasize)
+- newptr -= adc->dmasize;
+-
+- outl(newptr, s->io+adc->curBufPtr);
+- adc->curBufPtr = (adc->curBufPtr == IT_AC_CAPB1STA) ?
+- IT_AC_CAPB2STA : IT_AC_CAPB1STA;
+-
+- adc->nextIn += adc->fragsize;
+- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
+- adc->nextIn -= adc->dmasize;
+-
+- adc->count += adc->fragsize;
+- adc->total_bytes += adc->fragsize;
+-
+- /* wake up anybody listening */
+- if (waitqueue_active(&adc->wait))
+- wake_up_interruptible(&adc->wait);
+- }
+- }
+-
+- /* update playback pointers */
+- if (isc & ISC_PCI) {
+- newptr = virt_to_bus(dac->nextOut) + 2*dac->fragsize;
+- if (newptr >= dac->dmaaddr + dac->dmasize)
+- newptr -= dac->dmasize;
+-
+- outl(newptr, s->io+dac->curBufPtr);
+- dac->curBufPtr = (dac->curBufPtr == IT_AC_PCB1STA) ?
+- IT_AC_PCB2STA : IT_AC_PCB1STA;
+-
+- dac->nextOut += dac->fragsize;
+- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
+- dac->nextOut -= dac->dmasize;
+-
+- dac->count -= dac->fragsize;
+- dac->total_bytes += dac->fragsize;
+-
+- /* wake up anybody listening */
+- if (waitqueue_active(&dac->wait))
+- wake_up_interruptible(&dac->wait);
+-
+- if (dac->count <= 0)
+- stop_dac(s);
+- }
+-
+- spin_unlock(&s->lock);
+- return IRQ_HANDLED;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int it8172_open_mixdev(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- struct list_head *list;
+- struct it8172_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct it8172_state, devs);
+- if (s->codec.dev_mixer == minor)
+- break;
+- }
+- file->private_data = s;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int it8172_release_mixdev(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-
+-static u16
+-cvt_ossvol(unsigned int gain)
+-{
+- u16 ret;
+-
+- if (gain == 0)
+- return 0;
+-
+- if (gain > 100)
+- gain = 100;
+-
+- ret = (100 - gain + 32) / 4;
+- ret = ret > 31 ? 31 : ret;
+- return ret;
+-}
+-
+-
+-static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
+- unsigned long arg)
+-{
+- struct it8172_state *s = (struct it8172_state *)codec->private_data;
+- unsigned int left, right;
+- unsigned long flags;
+- int val;
+- u16 vol;
+-
+- /*
+- * When we are in S/PDIF mode, we want to disable any analog output so
+- * we filter the master/PCM channel volume ioctls.
+- *
+- * Also filter I2S channel, which AC'97 knows nothing about.
+- */
+-
+- switch (cmd) {
+- case SOUND_MIXER_WRITE_VOLUME:
+- // if not in S/PDIF mode, pass to AC'97
+- if (s->spdif_volume == -1)
+- break;
+- return 0;
+- case SOUND_MIXER_WRITE_PCM:
+- // if not in S/PDIF mode, pass to AC'97
+- if (s->spdif_volume == -1)
+- break;
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- right = ((val >> 8) & 0xff);
+- left = (val & 0xff);
+- if (right > 100)
+- right = 100;
+- if (left > 100)
+- left = 100;
+- s->spdif_volume = (right << 8) | left;
+- vol = cvt_ossvol(left);
+- vol |= (cvt_ossvol(right) << PCMOV_PCMRCG_BIT);
+- if (vol == 0)
+- vol = PCMOV_PCMOM; // mute
+- spin_lock_irqsave(&s->lock, flags);
+- outw(vol, s->io+IT_AC_PCMOV);
+- spin_unlock_irqrestore(&s->lock, flags);
+- return put_user(s->spdif_volume, (int *)arg);
+- case SOUND_MIXER_READ_PCM:
+- // if not in S/PDIF mode, pass to AC'97
+- if (s->spdif_volume == -1)
+- break;
+- return put_user(s->spdif_volume, (int *)arg);
+- case SOUND_MIXER_WRITE_I2S:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- right = ((val >> 8) & 0xff);
+- left = (val & 0xff);
+- if (right > 100)
+- right = 100;
+- if (left > 100)
+- left = 100;
+- s->i2s_volume = (right << 8) | left;
+- vol = cvt_ossvol(left);
+- vol |= (cvt_ossvol(right) << I2SV_I2SRCG_BIT);
+- if (vol == 0)
+- vol = I2SV_I2SOM; // mute
+- outw(vol, s->io+IT_AC_I2SV);
+- return put_user(s->i2s_volume, (int *)arg);
+- case SOUND_MIXER_READ_I2S:
+- return put_user(s->i2s_volume, (int *)arg);
+- case SOUND_MIXER_WRITE_RECSRC:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (val & SOUND_MASK_I2S) {
+- s->i2s_recording = 1;
+- outb(DRSS_I2S, s->io+IT_AC_DRSS);
+- return 0;
+- } else {
+- s->i2s_recording = 0;
+- outb(DRSS_AC97_PRIM, s->io+IT_AC_DRSS);
+- // now let AC'97 select record source
+- break;
+- }
+- case SOUND_MIXER_READ_RECSRC:
+- if (s->i2s_recording)
+- return put_user(SOUND_MASK_I2S, (int *)arg);
+- else
+- // let AC'97 report recording source
+- break;
+- }
+-
+- return codec->mixer_ioctl(codec, cmd, arg);
+-}
+-
+-static int it8172_ioctl_mixdev(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+- struct ac97_codec *codec = &s->codec;
+-
+- return mixdev_ioctl(codec, cmd, arg);
+-}
+-
+-static /*const*/ struct file_operations it8172_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = it8172_ioctl_mixdev,
+- .open = it8172_open_mixdev,
+- .release = it8172_release_mixdev,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct it8172_state *s, int nonblock)
+-{
+- unsigned long flags;
+- int count, tmo;
+-
+- if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
+- return 0;
+-
+- for (;;) {
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- //if (nonblock)
+- //return -EBUSY;
+- tmo = 1000 * count / s->dacrate;
+- tmo >>= sample_shift[(s->pcc & CC_FMT_MASK) >> CC_FMT_BIT];
+- it8172_delay(tmo);
+- }
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-/*
+- * Copy audio data to/from user buffer from/to dma buffer, taking care
+- * that we wrap when reading/writing the dma buffer. Returns actual byte
+- * count written to or read from the dma buffer.
+- */
+-static int copy_dmabuf_user(struct dmabuf *db, char* userbuf,
+- int count, int to_user)
+-{
+- char* bufptr = to_user ? db->nextOut : db->nextIn;
+- char* bufend = db->rawbuf + db->dmasize;
+-
+- if (bufptr + count > bufend) {
+- int partial = (int)(bufend - bufptr);
+- if (to_user) {
+- if (copy_to_user(userbuf, bufptr, partial))
+- return -EFAULT;
+- if (copy_to_user(userbuf + partial, db->rawbuf,
+- count - partial))
+- return -EFAULT;
+- } else {
+- if (copy_from_user(bufptr, userbuf, partial))
+- return -EFAULT;
+- if (copy_from_user(db->rawbuf,
+- userbuf + partial,
+- count - partial))
+- return -EFAULT;
+- }
+- } else {
+- if (to_user) {
+- if (copy_to_user(userbuf, bufptr, count))
+- return -EFAULT;
+- } else {
+- if (copy_from_user(bufptr, userbuf, count))
+- return -EFAULT;
+- }
+- }
+-
+- return count;
+-}
+-
+-
+-static ssize_t it8172_read(struct file *file, char *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+- struct dmabuf *db = &s->dma_adc;
+- ssize_t ret;
+- unsigned long flags;
+- int cnt, remainder, avail;
+-
+- if (db->mapped)
+- return -ENXIO;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- while (count > 0) {
+- // wait for samples in capture buffer
+- do {
+- spin_lock_irqsave(&s->lock, flags);
+- if (db->stopped)
+- start_adc(s);
+- avail = db->count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (avail <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- return ret;
+- }
+- interruptible_sleep_on(&db->wait);
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- return ret;
+- }
+- }
+- } while (avail <= 0);
+-
+- // copy from nextOut to user
+- if ((cnt = copy_dmabuf_user(db, buffer, count > avail ?
+- avail : count, 1)) < 0) {
+- if (!ret)
+- ret = -EFAULT;
+- return ret;
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+- db->count -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- db->nextOut += cnt;
+- if (db->nextOut >= db->rawbuf + db->dmasize)
+- db->nextOut -= db->dmasize;
+-
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- } // while (count > 0)
+-
+- /*
+- * See if the dma buffer count after this read call is
+- * aligned on a fragsize boundary. If not, read from
+- * buffer until we reach a boundary, and let's hope this
+- * is just the last remainder of an audio record. If not
+- * it means the user is not reading in fragsize chunks, in
+- * which case it's his/her fault that there are audio gaps
+- * in their record.
+- */
+- spin_lock_irqsave(&s->lock, flags);
+- remainder = db->count % db->fragsize;
+- if (remainder) {
+- db->nextOut += remainder;
+- if (db->nextOut >= db->rawbuf + db->dmasize)
+- db->nextOut -= db->dmasize;
+- db->count -= remainder;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- return ret;
+-}
+-
+-static ssize_t it8172_write(struct file *file, const char *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+- struct dmabuf *db = &s->dma_dac;
+- ssize_t ret;
+- unsigned long flags;
+- int cnt, remainder, avail;
+-
+- if (db->mapped)
+- return -ENXIO;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- while (count > 0) {
+- // wait for space in playback buffer
+- do {
+- spin_lock_irqsave(&s->lock, flags);
+- avail = db->dmasize - db->count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (avail <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- return ret;
+- }
+- interruptible_sleep_on(&db->wait);
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- return ret;
+- }
+- }
+- } while (avail <= 0);
+-
+- // copy to nextIn
+- if ((cnt = copy_dmabuf_user(db, (char*)buffer,
+- count > avail ?
+- avail : count, 0)) < 0) {
+- if (!ret)
+- ret = -EFAULT;
+- return ret;
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+- db->count += cnt;
+- if (db->stopped)
+- start_dac(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- db->nextIn += cnt;
+- if (db->nextIn >= db->rawbuf + db->dmasize)
+- db->nextIn -= db->dmasize;
+-
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- } // while (count > 0)
+-
+- /*
+- * See if the dma buffer count after this write call is
+- * aligned on a fragsize boundary. If not, fill buffer
+- * with silence to the next boundary, and let's hope this
+- * is just the last remainder of an audio playback. If not
+- * it means the user is not sending us fragsize chunks, in
+- * which case it's his/her fault that there are audio gaps
+- * in their playback.
+- */
+- spin_lock_irqsave(&s->lock, flags);
+- remainder = db->count % db->fragsize;
+- if (remainder) {
+- int fill_cnt = db->fragsize - remainder;
+- memset(db->nextIn, 0, fill_cnt);
+- db->nextIn += fill_cnt;
+- if (db->nextIn >= db->rawbuf + db->dmasize)
+- db->nextIn -= db->dmasize;
+- db->count += fill_cnt;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int it8172_poll(struct file *file,
+- struct poll_table_struct *wait)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac.ready)
+- return 0;
+- poll_wait(file, &s->dma_dac.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready)
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac.dmasize >=
+- s->dma_dac.count + (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int it8172_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+- struct dmabuf *db;
+- unsigned long size;
+-
+- lock_kernel();
+- if (vma->vm_flags & VM_WRITE)
+- db = &s->dma_dac;
+- else if (vma->vm_flags & VM_READ)
+- db = &s->dma_adc;
+- else {
+- unlock_kernel();
+- return -EINVAL;
+- }
+- if (vma->vm_pgoff != 0) {
+- unlock_kernel();
+- return -EINVAL;
+- }
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder)) {
+- unlock_kernel();
+- return -EINVAL;
+- }
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot)) {
+- unlock_kernel();
+- return -EAGAIN;
+- }
+- db->mapped = 1;
+- unlock_kernel();
+- return 0;
+-}
+-
+-
+-#ifdef IT8172_VERBOSE_DEBUG
+-static struct ioctl_str_t {
+- unsigned int cmd;
+- const char* str;
+-} ioctl_str[] = {
+- {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
+- {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
+- {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
+- {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
+- {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
+- {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
+- {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
+- {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
+- {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
+- {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
+- {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
+- {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
+- {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
+- {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
+- {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
+- {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
+- {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
+- {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
+- {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
+- {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
+- {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
+- {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
+- {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
+- {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
+- {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
+- {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
+- {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
+- {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
+- {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
+- {OSS_GETVERSION, "OSS_GETVERSION"},
+- {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
+- {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
+- {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
+- {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
+-};
+-#endif
+-
+-static int it8172_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int count;
+- int val, mapped, ret, diff;
+-
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+-
+-#ifdef IT8172_VERBOSE_DEBUG
+- for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
+- if (ioctl_str[count].cmd == cmd)
+- break;
+- }
+- if (count < sizeof(ioctl_str)/sizeof(ioctl_str[0]))
+- dbg("ioctl %s, arg=0x%08x",
+- ioctl_str[count].str, (unsigned int)arg);
+- else
+- dbg("ioctl unknown, 0x%x", cmd);
+-#endif
+-
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, (int *)arg);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, file->f_flags & O_NONBLOCK);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+- DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->irq);
+- s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- s->dma_dac.nextIn = s->dma_dac.nextOut =
+- s->dma_dac.rawbuf;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->irq);
+- s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- s->dma_adc.nextIn = s->dma_adc.nextOut =
+- s->dma_adc.rawbuf;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (val >= 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- set_adc_rate(s, val);
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- set_dac_rate(s, val);
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- }
+- return put_user((file->f_mode & FMODE_READ) ?
+- s->adcrate : s->dacrate, (int *)arg);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- if (val)
+- s->capcc |= CC_SM;
+- else
+- s->capcc &= ~CC_SM;
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- if (val)
+- s->pcc |= CC_SM;
+- else
+- s->pcc &= ~CC_SM;
+- outw(s->pcc, s->io+IT_AC_PCC);
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (val != 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- if (val >= 2) {
+- val = 2;
+- s->capcc |= CC_SM;
+- }
+- else
+- s->capcc &= ~CC_SM;
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- switch (val) {
+- case 1:
+- s->pcc &= ~CC_SM;
+- break;
+- case 2:
+- s->pcc |= CC_SM;
+- break;
+- default:
+- // FIX! support multichannel???
+- val = 2;
+- s->pcc |= CC_SM;
+- break;
+- }
+- outw(s->pcc, s->io+IT_AC_PCC);
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- }
+- return put_user(val, (int *)arg);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- if (val == AFMT_S16_LE)
+- s->capcc |= CC_DF;
+- else {
+- val = AFMT_U8;
+- s->capcc &= ~CC_DF;
+- }
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- if (val == AFMT_S16_LE)
+- s->pcc |= CC_DF;
+- else {
+- val = AFMT_U8;
+- s->pcc &= ~CC_DF;
+- }
+- outw(s->pcc, s->io+IT_AC_PCC);
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- } else {
+- if (file->f_mode & FMODE_READ)
+- val = (s->capcc & CC_DF) ?
+- AFMT_S16_LE : AFMT_U8;
+- else
+- val = (s->pcc & CC_DF) ?
+- AFMT_S16_LE : AFMT_U8;
+- }
+- return put_user(val, (int *)arg);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
+- val |= PCM_ENABLE_OUTPUT;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return put_user(val, (int *)arg);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT)
+- start_adc(s);
+- else
+- stop_adc(s);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT)
+- start_dac(s);
+- else
+- stop_dac(s);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- abinfo.fragsize = s->dma_dac.fragsize;
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- if (!s->dma_dac.stopped)
+- count -= (s->dma_dac.fragsize -
+- inw(s->io+IT_AC_PCDL));
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = s->dma_dac.dmasize - count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ?
+- -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- abinfo.fragsize = s->dma_adc.fragsize;
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_adc.count;
+- if (!s->dma_adc.stopped)
+- count += (s->dma_adc.fragsize -
+- inw(s->io+IT_AC_CAPCDL));
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ?
+- -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- if (!s->dma_dac.stopped)
+- count -= (s->dma_dac.fragsize -
+- inw(s->io+IT_AC_PCDL));
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- return put_user(count, (int *)arg);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- count = s->dma_adc.count;
+- if (!s->dma_adc.stopped) {
+- diff = s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL);
+- count += diff;
+- cinfo.bytes += diff;
+- cinfo.ptr = inl(s->io+s->dma_adc.curBufPtr) -
+- s->dma_adc.dmaaddr;
+- } else
+- cinfo.ptr = virt_to_bus(s->dma_adc.nextIn) -
+- s->dma_adc.dmaaddr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_adc.fragshift;
+- if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- spin_lock_irqsave(&s->lock, flags);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- count = s->dma_dac.count;
+- if (!s->dma_dac.stopped) {
+- diff = s->dma_dac.fragsize - inw(s->io+IT_AC_CAPCDL);
+- count -= diff;
+- cinfo.bytes += diff;
+- cinfo.ptr = inl(s->io+s->dma_dac.curBufPtr) -
+- s->dma_dac.dmaaddr;
+- } else
+- cinfo.ptr = virt_to_bus(s->dma_dac.nextOut) -
+- s->dma_dac.dmaaddr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_dac.fragshift;
+- if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE)
+- return put_user(s->dma_dac.fragsize, (int *)arg);
+- else
+- return put_user(s->dma_adc.fragsize, (int *)arg);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- if (get_user(val, (int *)arg))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.subdivision = val;
+- if ((ret = prog_dmabuf_adc(s)))
+- return ret;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.subdivision = val;
+- if ((ret = prog_dmabuf_dac(s)))
+- return ret;
+- }
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user((file->f_mode & FMODE_READ) ?
+- s->adcrate : s->dacrate, (int *)arg);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- if (file->f_mode & FMODE_READ)
+- return put_user((s->capcc & CC_SM) ? 2 : 1,
+- (int *)arg);
+- else
+- return put_user((s->pcc & CC_SM) ? 2 : 1,
+- (int *)arg);
+-
+- case SOUND_PCM_READ_BITS:
+- if (file->f_mode & FMODE_READ)
+- return put_user((s->capcc & CC_DF) ? 16 : 8,
+- (int *)arg);
+- else
+- return put_user((s->pcc & CC_DF) ? 16 : 8,
+- (int *)arg);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+- }
+-
+- return mixdev_ioctl(&s->codec, cmd, arg);
+-}
+-
+-
+-static int it8172_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- struct list_head *list;
+- struct it8172_state *s;
+- int ret;
+-
+-#ifdef IT8172_VERBOSE_DEBUG
+- if (file->f_flags & O_NONBLOCK)
+- dbg("%s: non-blocking", __FUNCTION__);
+- else
+- dbg("%s: blocking", __FUNCTION__);
+-#endif
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct it8172_state, devs);
+- if (!((s->dev_audio ^ minor) & ~0xf))
+- break;
+- }
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+-
+- spin_lock_irqsave(&s->lock, flags);
+-
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
+- s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
+- s->capcc &= ~(CC_SM | CC_DF);
+- set_adc_rate(s, 8000);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->capcc |= CC_DF;
+- outw(s->capcc, s->io+IT_AC_CAPCC);
+- if ((ret = prog_dmabuf_adc(s))) {
+- spin_unlock_irqrestore(&s->lock, flags);
+- return ret;
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
+- s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
+- s->pcc &= ~(CC_SM | CC_DF);
+- set_dac_rate(s, 8000);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- s->pcc |= CC_DF;
+- outw(s->pcc, s->io+IT_AC_PCC);
+- if ((ret = prog_dmabuf_dac(s))) {
+- spin_unlock_irqrestore(&s->lock, flags);
+- return ret;
+- }
+- }
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int it8172_release(struct inode *inode, struct file *file)
+-{
+- struct it8172_state *s = (struct it8172_state *)file->private_data;
+-
+-#ifdef IT8172_VERBOSE_DEBUG
+- dbg("%s", __FUNCTION__);
+-#endif
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- dealloc_dmabuf(s, &s->dma_dac);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- dealloc_dmabuf(s, &s->dma_adc);
+- }
+- s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
+- mutex_unlock(&s->open_mutex);
+- wake_up(&s->open_wait);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations it8172_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = it8172_read,
+- .write = it8172_write,
+- .poll = it8172_poll,
+- .ioctl = it8172_ioctl,
+- .mmap = it8172_mmap,
+- .open = it8172_open,
+- .release = it8172_release,
+-};
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-/*
+- * for debugging purposes, we'll create a proc device that dumps the
+- * CODEC chipstate
+- */
+-
+-#ifdef IT8172_DEBUG
+-static int proc_it8172_dump (char *buf, char **start, off_t fpos,
+- int length, int *eof, void *data)
+-{
+- struct it8172_state *s;
+- int cnt, len = 0;
+-
+- if (list_empty(&devs))
+- return 0;
+- s = list_entry(devs.next, struct it8172_state, devs);
+-
+- /* print out header */
+- len += sprintf(buf + len, "\n\t\tIT8172 Audio Debug\n\n");
+-
+- // print out digital controller state
+- len += sprintf (buf + len, "IT8172 Audio Controller registers\n");
+- len += sprintf (buf + len, "---------------------------------\n");
+- cnt=0;
+- while (cnt < 0x72) {
+- if (cnt == IT_AC_PCB1STA || cnt == IT_AC_PCB2STA ||
+- cnt == IT_AC_CAPB1STA || cnt == IT_AC_CAPB2STA ||
+- cnt == IT_AC_PFDP) {
+- len+= sprintf (buf + len, "reg %02x = %08x\n",
+- cnt, inl(s->io+cnt));
+- cnt += 4;
+- } else {
+- len+= sprintf (buf + len, "reg %02x = %04x\n",
+- cnt, inw(s->io+cnt));
+- cnt += 2;
+- }
+- }
+-
+- /* print out CODEC state */
+- len += sprintf (buf + len, "\nAC97 CODEC registers\n");
+- len += sprintf (buf + len, "----------------------\n");
+- for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
+- len+= sprintf (buf + len, "reg %02x = %04x\n",
+- cnt, rdcodec(&s->codec, cnt));
+-
+- if (fpos >=len){
+- *start = buf;
+- *eof =1;
+- return 0;
+- }
+- *start = buf + fpos;
+- if ((len -= fpos) > length)
+- return length;
+- *eof =1;
+- return len;
+-
+-}
+-#endif /* IT8172_DEBUG */
+-
+-/* --------------------------------------------------------------------- */
+-
+-/* maximum number of devices; only used for command line params */
+-#define NR_DEVICE 5
+-
+-static int spdif[NR_DEVICE];
+-static int i2s_fmt[NR_DEVICE];
+-
+-static unsigned int devindex;
+-
+-module_param_array(spdif, int, NULL, 0);
+-MODULE_PARM_DESC(spdif, "if 1 the S/PDIF digital output is enabled");
+-module_param_array(i2s_fmt, int, NULL, 0);
+-MODULE_PARM_DESC(i2s_fmt, "the format of I2S");
+-
+-MODULE_AUTHOR("Monta Vista Software, stevel at mvista.com");
+-MODULE_DESCRIPTION("IT8172 Audio Driver");
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int __devinit it8172_probe(struct pci_dev *pcidev,
+- const struct pci_device_id *pciid)
+-{
+- struct it8172_state *s;
+- int i, val;
+- unsigned short pcisr, vol;
+- unsigned char legacy, imc;
+- char proc_str[80];
+-
+- if (pcidev->irq == 0)
+- return -1;
+-
+- if (!(s = kmalloc(sizeof(struct it8172_state), GFP_KERNEL))) {
+- err("alloc of device struct failed");
+- return -1;
+- }
+-
+- memset(s, 0, sizeof(struct it8172_state));
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- mutex_init(&s->open_mutex);
+- spin_lock_init(&s->lock);
+- s->dev = pcidev;
+- s->io = pci_resource_start(pcidev, 0);
+- s->irq = pcidev->irq;
+- s->vendor = pcidev->vendor;
+- s->device = pcidev->device;
+- pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
+- s->codec.private_data = s;
+- s->codec.id = 0;
+- s->codec.codec_read = rdcodec;
+- s->codec.codec_write = wrcodec;
+- s->codec.codec_wait = waitcodec;
+-
+- if (!request_region(s->io, pci_resource_len(pcidev,0),
+- IT8172_MODULE_NAME)) {
+- err("io ports %#lx->%#lx in use",
+- s->io, s->io + pci_resource_len(pcidev,0)-1);
+- goto err_region;
+- }
+- if (request_irq(s->irq, it8172_interrupt, IRQF_DISABLED,
+- IT8172_MODULE_NAME, s)) {
+- err("irq %u in use", s->irq);
+- goto err_irq;
+- }
+-
+- info("IO at %#lx, IRQ %d", s->io, s->irq);
+-
+- /* register devices */
+- if ((s->dev_audio = register_sound_dsp(&it8172_audio_fops, -1)) < 0)
+- goto err_dev1;
+- if ((s->codec.dev_mixer =
+- register_sound_mixer(&it8172_mixer_fops, -1)) < 0)
+- goto err_dev2;
+-
+-#ifdef IT8172_DEBUG
+- /* initialize the debug proc device */
+- s->ps = create_proc_read_entry(IT8172_MODULE_NAME, 0, NULL,
+- proc_it8172_dump, NULL);
+-#endif /* IT8172_DEBUG */
+-
+- /*
+- * Reset the Audio device using the IT8172 PCI Reset register. This
+- * creates an audible double click on a speaker connected to Line-out.
+- */
+- IT_IO_READ16(IT_PM_PCISR, pcisr);
+- pcisr |= IT_PM_PCISR_ACSR;
+- IT_IO_WRITE16(IT_PM_PCISR, pcisr);
+- /* wait up to 100msec for reset to complete */
+- for (i=0; pcisr & IT_PM_PCISR_ACSR; i++) {
+- it8172_delay(10);
+- if (i == 10)
+- break;
+- IT_IO_READ16(IT_PM_PCISR, pcisr);
+- }
+- if (i == 10) {
+- err("chip reset timeout!");
+- goto err_dev3;
+- }
+-
+- /* enable pci io and bus mastering */
+- if (pci_enable_device(pcidev))
+- goto err_dev3;
+- pci_set_master(pcidev);
+-
+- /* get out of legacy mode */
+- pci_read_config_byte (pcidev, 0x40, &legacy);
+- pci_write_config_byte (pcidev, 0x40, legacy & ~1);
+-
+- s->spdif_volume = -1;
+- /* check to see if s/pdif mode is being requested */
+- if (spdif[devindex]) {
+- info("enabling S/PDIF output");
+- s->spdif_volume = 0;
+- outb(GC_SOE, s->io+IT_AC_GC);
+- } else {
+- info("disabling S/PDIF output");
+- outb(0, s->io+IT_AC_GC);
+- }
+-
+- /* check to see if I2S format requested */
+- if (i2s_fmt[devindex]) {
+- info("setting I2S format to 0x%02x", i2s_fmt[devindex]);
+- outb(i2s_fmt[devindex], s->io+IT_AC_I2SMC);
+- } else {
+- outb(I2SMC_I2SF_I2S, s->io+IT_AC_I2SMC);
+- }
+-
+- /* cold reset the AC97 */
+- outw(CODECC_CR, s->io+IT_AC_CODECC);
+- udelay(1000);
+- outw(0, s->io+IT_AC_CODECC);
+- /* need to delay around 500msec(bleech) to give
+- some CODECs enough time to wakeup */
+- it8172_delay(500);
+-
+- /* AC97 warm reset to start the bitclk */
+- outw(CODECC_WR, s->io+IT_AC_CODECC);
+- udelay(1000);
+- outw(0, s->io+IT_AC_CODECC);
+-
+- /* codec init */
+- if (!ac97_probe_codec(&s->codec))
+- goto err_dev3;
+-
+- /* add I2S as allowable recording source */
+- s->codec.record_sources |= SOUND_MASK_I2S;
+-
+- /* Enable Volume button interrupts */
+- imc = inb(s->io+IT_AC_IMC);
+- outb(imc & ~IMC_VCIM, s->io+IT_AC_IMC);
+-
+- /* Un-mute PCM and FM out on the controller */
+- vol = inw(s->io+IT_AC_PCMOV);
+- outw(vol & ~PCMOV_PCMOM, s->io+IT_AC_PCMOV);
+- vol = inw(s->io+IT_AC_FMOV);
+- outw(vol & ~FMOV_FMOM, s->io+IT_AC_FMOV);
+-
+- /* set channel defaults to 8-bit, mono, 8 Khz */
+- s->pcc = 0;
+- s->capcc = 0;
+- set_dac_rate(s, 8000);
+- set_adc_rate(s, 8000);
+-
+- /* set mic to be the recording source */
+- val = SOUND_MASK_MIC;
+- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC,
+- (unsigned long)&val);
+-
+- /* mute AC'97 master and PCM when in S/PDIF mode */
+- if (s->spdif_volume != -1) {
+- val = 0x0000;
+- s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME,
+- (unsigned long)&val);
+- s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM,
+- (unsigned long)&val);
+- }
+-
+-#ifdef IT8172_DEBUG
+- sprintf(proc_str, "driver/%s/%d/ac97", IT8172_MODULE_NAME,
+- s->codec.id);
+- s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
+- ac97_read_proc, &s->codec);
+-#endif
+-
+- /* store it in the driver field */
+- pci_set_drvdata(pcidev, s);
+- pcidev->dma_mask = 0xffffffff;
+- /* put it into driver list */
+- list_add_tail(&s->devs, &devs);
+- /* increment devindex */
+- if (devindex < NR_DEVICE-1)
+- devindex++;
+- return 0;
+-
+- err_dev3:
+- unregister_sound_mixer(s->codec.dev_mixer);
+- err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+- err_dev1:
+- err("cannot register misc device");
+- free_irq(s->irq, s);
+- err_irq:
+- release_region(s->io, pci_resource_len(pcidev,0));
+- err_region:
+- kfree(s);
+- return -1;
+-}
+-
+-static void __devexit it8172_remove(struct pci_dev *dev)
+-{
+- struct it8172_state *s = pci_get_drvdata(dev);
+-
+- if (!s)
+- return;
+- list_del(&s->devs);
+-#ifdef IT8172_DEBUG
+- if (s->ps)
+- remove_proc_entry(IT8172_MODULE_NAME, NULL);
+-#endif /* IT8172_DEBUG */
+- synchronize_irq(s->irq);
+- free_irq(s->irq, s);
+- release_region(s->io, pci_resource_len(dev,0));
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->codec.dev_mixer);
+- kfree(s);
+- pci_set_drvdata(dev, NULL);
+-}
+-
+-
+-
+-static struct pci_device_id id_table[] = {
+- { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G_AUDIO, PCI_ANY_ID,
+- PCI_ANY_ID, 0, 0 },
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, id_table);
+-
+-static struct pci_driver it8172_driver = {
+- .name = IT8172_MODULE_NAME,
+- .id_table = id_table,
+- .probe = it8172_probe,
+- .remove = __devexit_p(it8172_remove)
+-};
+-
+-static int __init init_it8172(void)
+-{
+- info("version v0.5 time " __TIME__ " " __DATE__);
+- return pci_register_driver(&it8172_driver);
+-}
+-
+-static void __exit cleanup_it8172(void)
+-{
+- info("unloading");
+- pci_unregister_driver(&it8172_driver);
+-}
+-
+-module_init(init_it8172);
+-module_exit(cleanup_it8172);
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef MODULE
+-
+-/* format is: it8172=[spdif],[i2s:<I2S format>] */
+-
+-static int __init it8172_setup(char *options)
+-{
+- char* this_opt;
+- static unsigned __initdata nr_dev = 0;
+-
+- if (nr_dev >= NR_DEVICE)
+- return 0;
+-
+- if (!options || !*options)
+- return 0;
+-
+- while (this_opt = strsep(&options, ",")) {
+- if (!*this_opt)
+- continue;
+- if (!strncmp(this_opt, "spdif", 5)) {
+- spdif[nr_dev] = 1;
+- } else if (!strncmp(this_opt, "i2s:", 4)) {
+- if (!strncmp(this_opt+4, "dac", 3))
+- i2s_fmt[nr_dev] = I2SMC_I2SF_DAC;
+- else if (!strncmp(this_opt+4, "adc", 3))
+- i2s_fmt[nr_dev] = I2SMC_I2SF_ADC;
+- else if (!strncmp(this_opt+4, "i2s", 3))
+- i2s_fmt[nr_dev] = I2SMC_I2SF_I2S;
+- }
+- }
+-
+- nr_dev++;
+- return 1;
+-}
+-
+-__setup("it8172=", it8172_setup);
+-
+-#endif /* MODULE */
+diff --git a/sound/oss/iwmem.h b/sound/oss/iwmem.h
+deleted file mode 100644
+index 84745fb..0000000
+--- a/sound/oss/iwmem.h
++++ /dev/null
+@@ -1,36 +0,0 @@
+-/*
+- * sound/iwmem.h
+- *
+- * DRAM size encoding table for AMD Interwave chip.
+- */
+-/*
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- * Changes:
+- * Bartlomiej Zolnierkiewicz : added __initdata to mem_decode
+- */
+-
+-
+-#define K 1024
+-#define M (1024*K)
+-static int mem_decode[][4] __initdata =
+-{
+-/* Bank0 Bank1 Bank2 Bank3 Encoding bits */
+- {256*K, 0, 0, 0}, /* 0 */
+- {256*K, 256*K, 0, 0}, /* 1 */
+- {256*K, 256*K, 256*K, 256*K}, /* 2 */
+- {256*K, 1*M, 0, 0}, /* 3 */
+- {256*K, 1*M, 1*M, 1*M}, /* 4 */
+- {256*K, 256*K, 1*M, 0}, /* 5 */
+- {256*K, 256*K, 1*M, 1*M}, /* 6 */
+- {1*M, 0, 0, 0}, /* 7 */
+- {1*M, 1*M, 0, 0}, /* 8 */
+- {1*M, 1*M, 1*M, 1*M}, /* 9 */
+- {4*M, 0, 0, 0}, /* 10 */
+- {4*M, 4*M, 0, 0}, /* 11 */
+- {4*M, 4*M, 4*M, 4*M} /* 12 */
+-};
+diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
+deleted file mode 100644
+index aa3c50d..0000000
+--- a/sound/oss/mad16.c
++++ /dev/null
+@@ -1,1113 +0,0 @@
+-/*
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * mad16.c
+- *
+- * Initialization code for OPTi MAD16 compatible audio chips. Including
+- *
+- * OPTi 82C928 MAD16 (replaced by C929)
+- * OAK OTI-601D Mozart
+- * OAK OTI-605 Mozart (later version with MPU401 Midi)
+- * OPTi 82C929 MAD16 Pro
+- * OPTi 82C930
+- * OPTi 82C924
+- *
+- * These audio interface chips don't produce sound themselves. They just
+- * connect some other components (OPL-[234] and a WSS compatible codec)
+- * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
+- * also a UART for the MPU-401 mode (not 82C928/Mozart).
+- * The Mozart chip appears to be compatible with the 82C928, although later
+- * issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi
+- * port. This port is configured differently to that of the OPTi audio chips.
+- *
+- * Changes
+- *
+- * Alan Cox Clean up, added module selections.
+- *
+- * A. Wik Added support for Opti924 PnP.
+- * Improved debugging support. 16-May-1998
+- * Fixed bug. 16-Jun-1998
+- *
+- * Torsten Duwe Made Opti924 PnP support non-destructive
+- * 23-Dec-1998
+- *
+- * Paul Grayson Added support for Midi on later Mozart cards.
+- * 25-Nov-1999
+- * Christoph Hellwig Adapted to module_init/module_exit.
+- * Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000
+- *
+- * Pavel Rabel Clean up Nov-2000
+- */
+-
+-#include <linux/config.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/gameport.h>
+-#include <linux/spinlock.h>
+-#include "sound_config.h"
+-
+-#include "ad1848.h"
+-#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 DEFINE_SPINLOCK(lock);
+-
+-#define C928 1
+-#define MOZART 2
+-#define C929 3
+-#define C930 4
+-#define C924 5
+-
+-/*
+- * Registers
+- *
+- * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations).
+- * All ports are inactive by default. They can be activated by
+- * writing 0xE2 or 0xE3 to the password register. The password is valid
+- * only until the next I/O read or write.
+- *
+- * 82C930 uses 0xE4 as the password and indirect addressing to access
+- * the config registers.
+- */
+-
+-#define MC0_PORT 0xf8c /* Dummy port */
+-#define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */
+-#define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */
+-#define MC3_PORT 0xf8f
+-#define PASSWD_REG 0xf8f
+-#define MC4_PORT 0xf90
+-#define MC5_PORT 0xf91
+-#define MC6_PORT 0xf92
+-#define MC7_PORT 0xf93
+-#define MC8_PORT 0xf94
+-#define MC9_PORT 0xf95
+-#define MC10_PORT 0xf96
+-#define MC11_PORT 0xf97
+-#define MC12_PORT 0xf98
+-
+-static int board_type = C928;
+-
+-static int *mad16_osp;
+-static int c931_detected; /* minor differences from C930 */
+-static char c924pnp; /* " " " C924 */
+-static int debug; /* debugging output */
+-
+-#ifdef DDB
+-#undef DDB
+-#endif
+-#define DDB(x) do {if (debug) x;} while (0)
+-
+-static unsigned char mad_read(int port)
+-{
+- unsigned long flags;
+- unsigned char tmp;
+-
+- spin_lock_irqsave(&lock,flags);
+-
+- switch (board_type) /* Output password */
+- {
+- case C928:
+- case MOZART:
+- outb((0xE2), PASSWD_REG);
+- break;
+-
+- case C929:
+- outb((0xE3), PASSWD_REG);
+- break;
+-
+- case C930:
+- /* outb(( 0xE4), PASSWD_REG); */
+- break;
+-
+- case C924:
+- /* the c924 has its ports relocated by -128 if
+- PnP is enabled -aw */
+- if (!c924pnp)
+- outb((0xE5), PASSWD_REG); else
+- outb((0xE5), PASSWD_REG - 0x80);
+- break;
+- }
+-
+- if (board_type == C930)
+- {
+- outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
+- tmp = inb(0xe0f); /* Read from data reg */
+- }
+- else
+- if (!c924pnp)
+- tmp = inb(port); else
+- tmp = inb(port-0x80);
+- spin_unlock_irqrestore(&lock,flags);
+-
+- return tmp;
+-}
+-
+-static void mad_write(int port, int value)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&lock,flags);
+-
+- switch (board_type) /* Output password */
+- {
+- case C928:
+- case MOZART:
+- outb((0xE2), PASSWD_REG);
+- break;
+-
+- case C929:
+- outb((0xE3), PASSWD_REG);
+- break;
+-
+- case C930:
+- /* outb(( 0xE4), PASSWD_REG); */
+- break;
+-
+- case C924:
+- if (!c924pnp)
+- outb((0xE5), PASSWD_REG); else
+- outb((0xE5), PASSWD_REG - 0x80);
+- break;
+- }
+-
+- if (board_type == C930)
+- {
+- outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
+- outb(((unsigned char) (value & 0xff)), 0xe0f);
+- }
+- else
+- if (!c924pnp)
+- outb(((unsigned char) (value & 0xff)), port); else
+- outb(((unsigned char) (value & 0xff)), port-0x80);
+- spin_unlock_irqrestore(&lock,flags);
+-}
+-
+-static int __init detect_c930(void)
+-{
+- unsigned char tmp = mad_read(MC1_PORT);
+-
+- if ((tmp & 0x06) != 0x06)
+- {
+- DDB(printk("Wrong C930 signature (%x)\n", tmp));
+- /* return 0; */
+- }
+- mad_write(MC1_PORT, 0);
+-
+- if (mad_read(MC1_PORT) != 0x06)
+- {
+- DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
+- /* return 0; */
+- }
+- mad_write(MC1_PORT, tmp); /* Restore bits */
+-
+- mad_write(MC7_PORT, 0);
+- if ((tmp = mad_read(MC7_PORT)) != 0)
+- {
+- DDB(printk("MC7 not writable (%x)\n", tmp));
+- return 0;
+- }
+- mad_write(MC7_PORT, 0xcb);
+- if ((tmp = mad_read(MC7_PORT)) != 0xcb)
+- {
+- DDB(printk("MC7 not writable2 (%x)\n", tmp));
+- return 0;
+- }
+-
+- tmp = mad_read(MC0_PORT+18);
+- if (tmp == 0xff || tmp == 0x00)
+- return 1;
+- /* We probably have a C931 */
+- DDB(printk("Detected C931 config=0x%02x\n", tmp));
+- c931_detected = 1;
+-
+- /*
+- * We cannot configure the chip if it is in PnP mode.
+- * If we have a CSN assigned (bit 8 in MC13) we first try
+- * a software reset, then a software power off, finally
+- * Clearing PnP mode. The last option is not
+- * Bit 8 in MC13
+- */
+- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
+- return 1;
+-
+- /* Software reset */
+- mad_write(MC9_PORT, 0x02);
+- mad_write(MC9_PORT, 0x00);
+-
+- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
+- return 1;
+-
+- /* Power off, and on again */
+- mad_write(MC9_PORT, 0xc2);
+- mad_write(MC9_PORT, 0xc0);
+-
+- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
+- return 1;
+-
+-#if 0
+- /* Force off PnP mode. This is not recommended because
+- * the PnP bios will not recognize the chip on the next
+- * warm boot and may assignd different resources to other
+- * PnP/PCI cards.
+- */
+- mad_write(MC0_PORT+17, 0x04);
+-#endif
+- return 1;
+-}
+-
+-static int __init detect_mad16(void)
+-{
+- unsigned char tmp, tmp2, bit;
+- int i, port;
+-
+- /*
+- * Check that reading a register doesn't return bus float (0xff)
+- * when the card is accessed using password. This may fail in case
+- * the card is in low power mode. Normally at least the power saving
+- * mode bit should be 0.
+- */
+-
+- if ((tmp = mad_read(MC1_PORT)) == 0xff)
+- {
+- DDB(printk("MC1_PORT returned 0xff\n"));
+- return 0;
+- }
+- for (i = 0xf8d; i <= 0xf98; i++)
+- if (!c924pnp)
+- DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i)));
+- else
+- DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i)));
+-
+- if (board_type == C930)
+- return detect_c930();
+-
+- /*
+- * Now check that the gate is closed on first I/O after writing
+- * the password. (This is how a MAD16 compatible card works).
+- */
+-
+- if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */
+- {
+- DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
+- return 0;
+- }
+-
+- bit = (c924pnp) ? 0x20 : 0x80;
+- port = (c924pnp) ? MC2_PORT : MC1_PORT;
+-
+- tmp = mad_read(port);
+- mad_write(port, tmp ^ bit); /* Toggle a bit */
+- if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */
+- {
+- mad_write(port, tmp); /* Restore */
+- DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
+- return 0;
+- }
+- mad_write(port, tmp); /* Restore */
+- return 1; /* Bingo */
+-}
+-
+-static int __init wss_init(struct address_info *hw_config)
+-{
+- /*
+- * Check if the IO port returns valid signature. The original MS Sound
+- * system returns 0x04 while some cards (AudioTrix Pro for example)
+- * return 0x00.
+- */
+-
+- if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
+- (inb(hw_config->io_base + 3) & 0x3f) != 0x00)
+- {
+- DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
+- return 0;
+- }
+- /*
+- * Check that DMA0 is not in use with a 8 bit board.
+- */
+- if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
+- {
+- printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
+- return 0;
+- }
+- if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80)
+- printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
+- return 1;
+-}
+-
+-static void __init init_c930(struct address_info *hw_config, int base)
+-{
+- unsigned char cfg = 0;
+-
+- cfg |= (0x0f & mad16_conf);
+-
+- if(c931_detected)
+- {
+- /* Bit 0 has reversd meaning. Bits 1 and 2 sese
+- reversed on write.
+- Support only IDE cdrom. IDE port programmed
+- somewhere else. */
+- cfg = (cfg & 0x09) ^ 0x07;
+- }
+- cfg |= base << 4;
+- mad_write(MC1_PORT, cfg);
+-
+- /* MC2 is CD configuration. Don't touch it. */
+-
+- mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
+-
+- /* bit 2 of MC4 reverses it's meaning between the C930
+- and the C931. */
+- cfg = c931_detected ? 0x04 : 0x00;
+-
+- if(mad16_cdsel & 0x20)
+- mad_write(MC4_PORT, 0x62|cfg); /* opl4 */
+- else
+- mad_write(MC4_PORT, 0x52|cfg); /* opl3 */
+-
+- mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */
+- mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
+- mad_write(MC7_PORT, 0xCB);
+- mad_write(MC10_PORT, 0x11);
+-}
+-
+-static int __init chip_detect(void)
+-{
+- int i;
+-
+- /*
+- * Then try to detect with the old password
+- */
+- board_type = C924;
+-
+- DDB(printk("Detect using password = 0xE5\n"));
+-
+- if (detect_mad16()) {
+- return 1;
+- }
+-
+- board_type = C928;
+-
+- DDB(printk("Detect using password = 0xE2\n"));
+-
+- if (detect_mad16())
+- {
+- unsigned char model;
+-
+- if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
+- DDB(printk("mad16.c: Mozart detected\n"));
+- board_type = MOZART;
+- } else {
+- DDB(printk("mad16.c: 82C928 detected???\n"));
+- board_type = C928;
+- }
+- return 1;
+- }
+-
+- board_type = C929;
+-
+- DDB(printk("Detect using password = 0xE3\n"));
+-
+- if (detect_mad16())
+- {
+- DDB(printk("mad16.c: 82C929 detected\n"));
+- return 1;
+- }
+-
+- if (inb(PASSWD_REG) != 0xff)
+- return 0;
+-
+- /*
+- * First relocate MC# registers to 0xe0e/0xe0f, disable password
+- */
+-
+- outb((0xE4), PASSWD_REG);
+- outb((0x80), PASSWD_REG);
+-
+- board_type = C930;
+-
+- DDB(printk("Detect using password = 0xE4\n"));
+-
+- for (i = 0xf8d; i <= 0xf93; i++)
+- DDB(printk("port %03x = %02x\n", i, mad_read(i)));
+-
+- if(detect_mad16()) {
+- DDB(printk("mad16.c: 82C930 detected\n"));
+- return 1;
+- }
+-
+- /* The C931 has the password reg at F8D */
+- outb((0xE4), 0xF8D);
+- outb((0x80), 0xF8D);
+- DDB(printk("Detect using password = 0xE4 for C931\n"));
+-
+- if (detect_mad16()) {
+- return 1;
+- }
+-
+- board_type = C924;
+- c924pnp++;
+- DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
+- if (detect_mad16()) {
+- DDB(printk("mad16.c: 82C924 PnP detected\n"));
+- return 1;
+- }
+-
+- c924pnp=0;
+-
+- return 0;
+-}
+-
+-static int __init probe_mad16(struct address_info *hw_config)
+-{
+- int i;
+- unsigned char tmp;
+- unsigned char cs4231_mode = 0;
+-
+- int ad_flags = 0;
+-
+- signed char bits;
+-
+- static char dma_bits[4] = {
+- 1, 2, 0, 3
+- };
+-
+- int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+- int dma = hw_config->dma, dma2 = hw_config->dma2;
+- unsigned char dma2_bit = 0;
+- int base;
+- struct resource *ports;
+-
+- mad16_osp = hw_config->osp;
+-
+- switch (hw_config->io_base) {
+- case 0x530:
+- base = 0;
+- break;
+- case 0xe80:
+- base = 1;
+- break;
+- case 0xf40:
+- base = 2;
+- break;
+- case 0x604:
+- base = 3;
+- break;
+- default:
+- printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
+- return 0;
+- }
+-
+- if (dma != 0 && dma != 1 && dma != 3) {
+- printk(KERN_ERR "MSS: Bad DMA %d\n", dma);
+- return 0;
+- }
+-
+- /*
+- * Check that all ports return 0xff (bus float) when no password
+- * is written to the password register.
+- */
+-
+- DDB(printk("--- Detecting MAD16 / Mozart ---\n"));
+- if (!chip_detect())
+- return 0;
+-
+- switch (hw_config->irq) {
+- case 7:
+- bits = 8;
+- break;
+- case 9:
+- bits = 0x10;
+- break;
+- case 10:
+- bits = 0x18;
+- break;
+- case 12:
+- bits = 0x20;
+- break;
+- case 5: /* Also IRQ5 is possible on C930 */
+- if (board_type == C930 || c924pnp) {
+- bits = 0x28;
+- break;
+- }
+- default:
+- printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq);
+- return 0;
+- }
+-
+- ports = request_region(hw_config->io_base + 4, 4, "ad1848");
+- if (!ports) {
+- printk(KERN_ERR "MSS: I/O port conflict\n");
+- return 0;
+- }
+- if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) {
+- release_region(hw_config->io_base + 4, 4);
+- printk(KERN_ERR "MSS: I/O port conflict\n");
+- return 0;
+- }
+-
+- if (board_type == C930) {
+- init_c930(hw_config, base);
+- goto got_it;
+- }
+-
+- for (i = 0xf8d; i <= 0xf93; i++) {
+- if (!c924pnp)
+- DDB(printk("port %03x = %02x\n", i, mad_read(i)));
+- else
+- DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i)));
+- }
+-
+-/*
+- * Set the WSS address
+- */
+-
+- tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */
+- tmp |= base << 4; /* WSS port select bits */
+-
+- /*
+- * Set optional CD-ROM and joystick settings.
+- */
+-
+- tmp &= ~0x0f;
+- tmp |= (mad16_conf & 0x0f); /* CD-ROM and joystick bits */
+- mad_write(MC1_PORT, tmp);
+-
+- tmp = mad16_cdsel;
+- mad_write(MC2_PORT, tmp);
+- mad_write(MC3_PORT, 0xf0); /* Disable SB */
+-
+- if (board_type == C924) /* Specific C924 init values */
+- {
+- mad_write(MC4_PORT, 0xA0);
+- mad_write(MC5_PORT, 0x05);
+- mad_write(MC6_PORT, 0x03);
+- }
+- if (!ad1848_detect(ports, &ad_flags, mad16_osp))
+- goto fail;
+-
+- if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
+- cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */
+-
+- if (board_type == C929)
+- {
+- mad_write(MC4_PORT, 0xa2);
+- mad_write(MC5_PORT, 0xA5 | cs4231_mode);
+- mad_write(MC6_PORT, 0x03); /* Disable MPU401 */
+- }
+- else
+- {
+- mad_write(MC4_PORT, 0x02);
+- mad_write(MC5_PORT, 0x30 | cs4231_mode);
+- }
+-
+- for (i = 0xf8d; i <= 0xf93; i++) {
+- if (!c924pnp)
+- DDB(printk("port %03x after init = %02x\n", i, mad_read(i)));
+- else
+- DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i)));
+- }
+-
+-got_it:
+- ad_flags = 0;
+- if (!ad1848_detect(ports, &ad_flags, mad16_osp))
+- goto fail;
+-
+- if (!wss_init(hw_config))
+- goto fail;
+-
+- /*
+- * Set the IRQ and DMA addresses.
+- */
+-
+- outb((bits | 0x40), config_port);
+- if ((inb(version_port) & 0x40) == 0)
+- printk(KERN_ERR "[IRQ Conflict?]\n");
+-
+- /*
+- * Handle the capture DMA channel
+- */
+-
+- if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
+- {
+- if (!((dma == 0 && dma2 == 1) ||
+- (dma == 1 && dma2 == 0) ||
+- (dma == 3 && dma2 == 0)))
+- { /* Unsupported combination. Try to swap channels */
+- int tmp = dma;
+-
+- dma = dma2;
+- dma2 = tmp;
+- }
+- if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) ||
+- (dma == 3 && dma2 == 0))
+- {
+- dma2_bit = 0x04; /* Enable capture DMA */
+- }
+- else
+- {
+- printk("MAD16: Invalid capture DMA\n");
+- dma2 = dma;
+- }
+- }
+- else dma2 = dma;
+-
+- outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
+-
+- hw_config->slots[0] = ad1848_init("mad16 WSS", ports,
+- hw_config->irq,
+- dma,
+- dma2, 0,
+- hw_config->osp,
+- THIS_MODULE);
+- return 1;
+-
+-fail:
+- release_region(hw_config->io_base + 4, 4);
+- release_region(hw_config->io_base, 4);
+- return 0;
+-}
+-
+-static int __init probe_mad16_mpu(struct address_info *hw_config)
+-{
+- unsigned char tmp;
+-
+- if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
+- {
+-
+-#ifdef CONFIG_MAD16_OLDCARD
+-
+- tmp = mad_read(MC3_PORT);
+-
+- /*
+- * MAD16 SB base is defined by the WSS base. It cannot be changed
+- * alone.
+- * Ignore configured I/O base. Use the active setting.
+- */
+-
+- if (mad_read(MC1_PORT) & 0x20)
+- hw_config->io_base = 0x240;
+- else
+- hw_config->io_base = 0x220;
+-
+- switch (hw_config->irq)
+- {
+- case 5:
+- tmp = (tmp & 0x3f) | 0x80;
+- break;
+- case 7:
+- tmp = (tmp & 0x3f);
+- break;
+- case 11:
+- tmp = (tmp & 0x3f) | 0x40;
+- break;
+- default:
+- printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n");
+- return 0;
+- }
+-
+- mad_write(MC3_PORT, tmp | 0x04);
+- hw_config->driver_use_1 = SB_MIDI_ONLY;
+- if (!request_region(hw_config->io_base, 16, "soundblaster"))
+- return 0;
+- if (!sb_dsp_detect(hw_config, 0, 0, NULL)) {
+- release_region(hw_config->io_base, 16);
+- return 0;
+- }
+-
+- if (mad_read(MC1_PORT) & 0x20)
+- hw_config->io_base = 0x240;
+- else
+- hw_config->io_base = 0x220;
+-
+- hw_config->name = "Mad16/Mozart";
+- sb_dsp_init(hw_config, THIS_MODULE);
+- return 1;
+-#else
+- /* assuming all later Mozart cards are identified as
+- * either 82C928 or Mozart. If so, following code attempts
+- * to set MPU register. TODO - add probing
+- */
+-
+- tmp = mad_read(MC8_PORT);
+-
+- switch (hw_config->irq)
+- {
+- case 5:
+- tmp |= 0x08;
+- break;
+- case 7:
+- tmp |= 0x10;
+- break;
+- case 9:
+- tmp |= 0x18;
+- break;
+- case 10:
+- tmp |= 0x20;
+- break;
+- case 11:
+- tmp |= 0x28;
+- break;
+- default:
+- printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n");
+- return 0;
+- }
+-
+- switch (hw_config->io_base)
+- {
+- case 0x300:
+- tmp |= 0x01;
+- break;
+- case 0x310:
+- tmp |= 0x03;
+- break;
+- case 0x320:
+- tmp |= 0x05;
+- break;
+- case 0x330:
+- tmp |= 0x07;
+- break;
+- default:
+- printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n");
+- return 0;
+- }
+-
+- mad_write(MC8_PORT, tmp); /* write MPU port parameters */
+- goto probe_401;
+-#endif
+- }
+- tmp = mad_read(MC6_PORT) & 0x83;
+- tmp |= 0x80; /* MPU-401 enable */
+-
+- /* Set the MPU base bits */
+-
+- switch (hw_config->io_base)
+- {
+- case 0x300:
+- tmp |= 0x60;
+- break;
+- case 0x310:
+- tmp |= 0x40;
+- break;
+- case 0x320:
+- tmp |= 0x20;
+- break;
+- case 0x330:
+- tmp |= 0x00;
+- break;
+- default:
+- printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base);
+- return 0;
+- }
+-
+- /* Set the MPU IRQ bits */
+-
+- switch (hw_config->irq)
+- {
+- case 5:
+- tmp |= 0x10;
+- break;
+- case 7:
+- tmp |= 0x18;
+- break;
+- case 9:
+- tmp |= 0x00;
+- break;
+- case 10:
+- tmp |= 0x08;
+- break;
+- default:
+- printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq);
+- break;
+- }
+-
+- mad_write(MC6_PORT, tmp); /* Write MPU401 config */
+-
+-#ifndef CONFIG_MAD16_OLDCARD
+-probe_401:
+-#endif
+- hw_config->driver_use_1 = SB_MIDI_ONLY;
+- hw_config->name = "Mad16/Mozart";
+- return probe_uart401(hw_config, THIS_MODULE);
+-}
+-
+-static void __exit unload_mad16(struct address_info *hw_config)
+-{
+- ad1848_unload(hw_config->io_base + 4,
+- hw_config->irq,
+- hw_config->dma,
+- hw_config->dma2, 0);
+- release_region(hw_config->io_base, 4);
+- sound_unload_audiodev(hw_config->slots[0]);
+-}
+-
+-static void __exit unload_mad16_mpu(struct address_info *hw_config)
+-{
+-#ifdef CONFIG_MAD16_OLDCARD
+- if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
+- {
+- sb_dsp_unload(hw_config, 0);
+- return;
+- }
+-#endif
+-
+- unload_uart401(hw_config);
+-}
+-
+-static struct address_info cfg;
+-static struct address_info cfg_mpu;
+-
+-static int found_mpu;
+-
+-static int __initdata mpu_io = 0;
+-static int __initdata mpu_irq = 0;
+-static int __initdata io = -1;
+-static int __initdata dma = -1;
+-static int __initdata dma16 = -1; /* Set this for modules that need it */
+-static int __initdata irq = -1;
+-static int __initdata cdtype = 0;
+-static int __initdata cdirq = 0;
+-static int __initdata cdport = 0x340;
+-static int __initdata cddma = -1;
+-static int __initdata opl4 = 0;
+-static int __initdata joystick = 0;
+-
+-module_param(mpu_io, int, 0);
+-module_param(mpu_irq, int, 0);
+-module_param(io, int, 0);
+-module_param(dma, int, 0);
+-module_param(dma16, int, 0);
+-module_param(irq, int, 0);
+-module_param(cdtype, int, 0);
+-module_param(cdirq, int, 0);
+-module_param(cdport, int, 0);
+-module_param(cddma, int, 0);
+-module_param(opl4, int, 0);
+-module_param(joystick, bool, 0);
+-module_param(debug, bool, 0644);
+-
+-static int __initdata dma_map[2][8] =
+-{
+- {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
+- {0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
+-};
+-
+-static int __initdata irq_map[16] =
+-{
+- 0x00, -1, -1, 0x0A,
+- -1, 0x04, -1, 0x08,
+- -1, 0x10, 0x14, 0x18,
+- -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")) {
+- printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
+- return -EBUSY;
+- }
+-
+- gameport = gameport_allocate_port();
+- if (!gameport) {
+- printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
+- release_region(io_port, 1);
+- return -ENOMEM;
+- }
+-
+- gameport_set_name(gameport, "MAD16 Gameport");
+- gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
+- gameport->io = io_port;
+-
+- gameport_register_port(gameport);
+-
+- 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;
+-
+- printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+-
+- printk(KERN_INFO "CDROM ");
+- switch (cdtype)
+- {
+- case 0x00:
+- printk("Disabled");
+- cdirq = 0;
+- break;
+- case 0x02:
+- printk("Sony CDU31A");
+- dmatype = 1;
+- if(cddma == -1) cddma = 3;
+- break;
+- case 0x04:
+- printk("Mitsumi");
+- dmatype = 0;
+- if(cddma == -1) cddma = 5;
+- break;
+- case 0x06:
+- printk("Panasonic Lasermate");
+- dmatype = 1;
+- if(cddma == -1) cddma = 3;
+- break;
+- case 0x08:
+- printk("Secondary IDE");
+- dmatype = 0;
+- if(cddma == -1) cddma = 5;
+- break;
+- case 0x0A:
+- printk("Primary IDE");
+- dmatype = 0;
+- if(cddma == -1) cddma = 5;
+- break;
+- default:
+- printk("\n");
+- printk(KERN_ERR "Invalid CDROM type\n");
+- return -EINVAL;
+- }
+-
+- /*
+- * Build the config words
+- */
+-
+- mad16_conf = (joystick ^ 1) | cdtype;
+- mad16_cdsel = 0;
+- if (opl4)
+- mad16_cdsel |= 0x20;
+-
+- if(cdtype){
+- if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
+- {
+- printk("\n");
+- printk(KERN_ERR "Invalid CDROM DMA\n");
+- return -EINVAL;
+- }
+- if (cddma)
+- printk(", DMA %d", cddma);
+- else
+- printk(", no DMA");
+-
+- if (!cdirq)
+- printk(", no IRQ");
+- else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1)
+- {
+- printk(", invalid IRQ (disabling)");
+- cdirq = 0;
+- }
+- else printk(", IRQ %d", cdirq);
+-
+- mad16_cdsel |= dma_map[dmatype][cddma];
+-
+- if (cdtype < 0x08)
+- {
+- switch (cdport)
+- {
+- case 0x340:
+- mad16_cdsel |= 0x00;
+- break;
+- case 0x330:
+- mad16_cdsel |= 0x40;
+- break;
+- case 0x360:
+- mad16_cdsel |= 0x80;
+- break;
+- case 0x320:
+- mad16_cdsel |= 0xC0;
+- break;
+- default:
+- printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport);
+- return -EINVAL;
+- }
+- }
+- mad16_cdsel |= irq_map[cdirq];
+- }
+-
+- printk(".\n");
+-
+- cfg.io_base = io;
+- cfg.irq = irq;
+- cfg.dma = dma;
+- cfg.dma2 = dma16;
+-
+- if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
+- printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
+- return -EINVAL;
+- }
+-
+- if (!request_region(MC0_PORT, 12, "mad16"))
+- return -EBUSY;
+-
+- if (!probe_mad16(&cfg)) {
+- release_region(MC0_PORT, 12);
+- return -ENODEV;
+- }
+-
+- cfg_mpu.io_base = mpu_io;
+- cfg_mpu.irq = mpu_irq;
+-
+- found_mpu = probe_mad16_mpu(&cfg_mpu);
+-
+- if (joystick)
+- mad16_register_gameport(0x201);
+-
+- return 0;
+-}
+-
+-static void __exit cleanup_mad16(void)
+-{
+- if (found_mpu)
+- unload_mad16_mpu(&cfg_mpu);
+- mad16_unregister_gameport();
+- unload_mad16(&cfg);
+- release_region(MC0_PORT, 12);
+-}
+-
+-module_init(init_mad16);
+-module_exit(cleanup_mad16);
+-
+-#ifndef MODULE
+-static int __init setup_mad16(char *str)
+-{
+- /* io, irq */
+- int ints[8];
+-
+- str = get_options(str, ARRAY_SIZE(ints), ints);
+-
+- io = ints[1];
+- irq = ints[2];
+- dma = ints[3];
+- dma16 = ints[4];
+- mpu_io = ints[5];
+- mpu_irq = ints[6];
+- joystick = ints[7];
+-
+- return 1;
+-}
+-
+-__setup("mad16=", setup_mad16);
+-#endif
+-MODULE_LICENSE("GPL");
+diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
+deleted file mode 100644
+index 1d98d10..0000000
+--- a/sound/oss/maestro.c
++++ /dev/null
+@@ -1,3686 +0,0 @@
+-/*****************************************************************************
+- *
+- * ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
+- *
+- * 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.
+- *
+- * (c) Copyright 1999 Alan Cox <alan.cox at linux.org>
+- *
+- * Based heavily on SonicVibes.c:
+- * Copyright (C) 1998-1999 Thomas Sailer (sailer at ife.ee.ethz.ch)
+- *
+- * Heavily modified by Zach Brown <zab at zabbo.net> based on lunch
+- * with ESS engineers. Many thanks to Howard Kim for providing
+- * contacts and hardware. Honorable mention goes to Eric
+- * Brombaugh for all sorts of things. Best regards to the
+- * proprietors of Hack Central for fine lodging.
+- *
+- * Supported devices:
+- * /dev/dsp0-3 standard /dev/dsp device, (mostly) OSS compatible
+- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+- *
+- * Hardware Description
+- *
+- * A working Maestro setup contains the Maestro chip wired to a
+- * codec or 2. In the Maestro we have the APUs, the ASSP, and the
+- * Wavecache. The APUs can be though of as virtual audio routing
+- * channels. They can take data from a number of sources and perform
+- * basic encodings of the data. The wavecache is a storehouse for
+- * PCM data. Typically it deals with PCI and interracts with the
+- * APUs. The ASSP is a wacky DSP like device that ESS is loth
+- * to release docs on. Thankfully it isn't required on the Maestro
+- * until you start doing insane things like FM emulation and surround
+- * encoding. The codecs are almost always AC-97 compliant codecs,
+- * but it appears that early Maestros may have had PT101 (an ESS
+- * part?) wired to them. The only real difference in the Maestro
+- * families is external goop like docking capability, memory for
+- * the ASSP, and initialization differences.
+- *
+- * Driver Operation
+- *
+- * We only drive the APU/Wavecache as typical DACs and drive the
+- * mixers in the codecs. There are 64 APUs. We assign 6 to each
+- * /dev/dsp? device. 2 channels for output, and 4 channels for
+- * input.
+- *
+- * Each APU can do a number of things, but we only really use
+- * 3 basic functions. For playback we use them to convert PCM
+- * data fetched over PCI by the wavecahche into analog data that
+- * is handed to the codec. One APU for mono, and a pair for stereo.
+- * When in stereo, the combination of smarts in the APU and Wavecache
+- * decide which wavecache gets the left or right channel.
+- *
+- * For record we still use the old overly mono system. For each in
+- * coming channel the data comes in from the codec, through a 'input'
+- * APU, through another rate converter APU, and then into memory via
+- * the wavecache and PCI. If its stereo, we mash it back into LRLR in
+- * software. The pass between the 2 APUs is supposedly what requires us
+- * to have a 512 byte buffer sitting around in wavecache/memory.
+- *
+- * The wavecache makes our life even more fun. First off, it can
+- * only address the first 28 bits of PCI address space, making it
+- * useless on quite a few architectures. Secondly, its insane.
+- * It claims to fetch from 4 regions of PCI space, each 4 meg in length.
+- * But that doesn't really work. You can only use 1 region. So all our
+- * allocations have to be in 4meg of each other. Booo. Hiss.
+- * So we have a module parameter, dsps_order, that is the order of
+- * the number of dsps to provide. All their buffer space is allocated
+- * on open time. The sonicvibes OSS routines we inherited really want
+- * power of 2 buffers, so we have all those next to each other, then
+- * 512 byte regions for the recording wavecaches. This ends up
+- * wasting quite a bit of memory. The only fixes I can see would be
+- * getting a kernel allocator that could work in zones, or figuring out
+- * just how to coerce the WP into doing what we want.
+- *
+- * The indirection of the various registers means we have to spinlock
+- * nearly all register accesses. We have the main register indirection
+- * like the wave cache, maestro registers, etc. Then we have beasts
+- * like the APU interface that is indirect registers gotten at through
+- * the main maestro indirection. Ouch. We spinlock around the actual
+- * ports on a per card basis. This means spinlock activity at each IO
+- * operation, but the only IO operation clusters are in non critical
+- * paths and it makes the code far easier to follow. Interrupts are
+- * blocked while holding the locks because the int handler has to
+- * get at some of them :(. The mixer interface doesn't, however.
+- * We also have an OSS state lock that is thrown around in a few
+- * places.
+- *
+- * This driver has brute force APM suspend support. We catch suspend
+- * notifications and stop all work being done on the chip. Any people
+- * that try between this shutdown and the real suspend operation will
+- * be put to sleep. When we resume we restore our software state on
+- * the chip and wake up the people that were using it. The code thats
+- * being used now is quite dirty and assumes we're on a uni-processor
+- * machine. Much of it will need to be cleaned up for SMP ACPI or
+- * similar.
+- *
+- * We also pay attention to PCI power management now. The driver
+- * will power down units of the chip that it knows aren't needed.
+- * The WaveProcessor and company are only powered on when people
+- * have /dev/dsp*s open. On removal the driver will
+- * power down the maestro entirely. There could still be
+- * trouble with BIOSen that magically change power states
+- * themselves, but we'll see.
+- *
+- * History
+- * v0.15 - May 21 2001 - Marcus Meissner <mm at caldera.de>
+- * Ported to Linux 2.4 PCI API. Some clean ups, global devs list
+- * removed (now using pci device driver data).
+- * PM needs to be polished still. Bumped version.
+- * (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben at msu.edu>
+- * Add support for 978 docking and basic hardware volume control
+- * (still kind of v0.14) Nov 23 - Alan Cox <alan at redhat.com>
+- * Add clocking= for people with seriously warped hardware
+- * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz at linux-ide.org>
+- * add __init to maestro_ac97_init() and maestro_install()
+- * (still based on v0.14) Mar 29 2000 - Zach Brown <zab at redhat.com>
+- * move to 2.3 power management interface, which
+- * required hacking some suspend/resume/check paths
+- * make static compilation work
+- * v0.14 - Jan 28 2000 - Zach Brown <zab at redhat.com>
+- * add PCI power management through ACPI regs.
+- * we now shut down on machine reboot/halt
+- * leave scary PCI config items alone (isa stuff, mostly)
+- * enable 1921s, it seems only mine was broke.
+- * fix swapped left/right pcm dac. har har.
+- * up bob freq, increase buffers, fix pointers at underflow
+- * silly compilation problems
+- * v0.13 - Nov 18 1999 - Zach Brown <zab at redhat.com>
+- * fix nec Versas? man would that be cool.
+- * v0.12 - Nov 12 1999 - Zach Brown <zab at redhat.com>
+- * brown bag volume max fix..
+- * v0.11 - Nov 11 1999 - Zach Brown <zab at redhat.com>
+- * use proper stereo apu decoding, mmap/write should work.
+- * make volume sliders more useful, tweak rate calculation.
+- * fix lame 8bit format reporting bug. duh. apm apu saving buglet also
+- * fix maestro 1 clock freq "bug", remove pt101 support
+- * v0.10 - Oct 28 1999 - Zach Brown <zab at redhat.com>
+- * aha, so, sometimes the WP writes a status word to offset 0
+- * from one of the PCMBARs. rearrange allocation accordingly..
+- * cheers again to Eric for being a good hacker in investigating this.
+- * Jeroen Hoogervorst submits 7500 fix out of nowhere. yay. :)
+- * v0.09 - Oct 23 1999 - Zach Brown <zab at redhat.com>
+- * added APM support.
+- * re-order something such that some 2Es now work. Magic!
+- * new codec reset routine. made some codecs come to life.
+- * fix clear_advance, sync some control with ESS.
+- * now write to all base regs to be paranoid.
+- * v0.08 - Oct 20 1999 - Zach Brown <zab at redhat.com>
+- * Fix initial buflen bug. I am so smart. also smp compiling..
+- * I owe Eric yet another beer: fixed recmask, igain,
+- * muting, and adc sync consistency. Go Team.
+- * v0.07 - Oct 4 1999 - Zach Brown <zab at redhat.com>
+- * tweak adc/dac, formating, and stuff to allow full duplex
+- * allocate dsps memory at open() so we can fit in the wavecache window
+- * fix wavecache braindamage. again. no more scribbling?
+- * fix ess 1921 codec bug on some laptops.
+- * fix dumb pci scanning bug
+- * started 2.3 cleanup, redid spinlocks, little cleanups
+- * v0.06 - Sep 20 1999 - Zach Brown <zab at redhat.com>
+- * fix wavecache thinkos. limit to 1 /dev/dsp.
+- * eric is wearing his thinking toque this week.
+- * spotted apu mode bugs and gain ramping problem
+- * don't touch weird mixer regs, make recmask optional
+- * fixed igain inversion, defaults for mixers, clean up rec_start
+- * make mono recording work.
+- * report subsystem stuff, please send reports.
+- * littles: parallel out, amp now
+- * v0.05 - Sep 17 1999 - Zach Brown <zab at redhat.com>
+- * merged and fixed up Eric's initial recording code
+- * munged format handling to catch misuse, needs rewrite.
+- * revert ring bus init, fixup shared int, add pci busmaster setting
+- * fix mixer oss interface, fix mic mute and recmask
+- * mask off unsupported mixers, reset with all 1s, modularize defaults
+- * make sure bob is running while we need it
+- * got rid of device limit, initial minimal apm hooks
+- * pull out dead code/includes, only allow multimedia/audio maestros
+- * v0.04 - Sep 01 1999 - Zach Brown <zab at redhat.com>
+- * copied memory leak fix from sonicvibes driver
+- * different ac97 reset, play with 2.0 ac97, simplify ring bus setup
+- * bob freq code, region sanity, jitter sync fix; all from Eric
+- *
+- * TODO
+- * fix bob frequency
+- * endianness
+- * do smart things with ac97 2.0 bits.
+- * dual codecs
+- * leave 54->61 open
+- *
+- * it also would be fun to have a mode that would not use pci dma at all
+- * but would copy into the wavecache on board memory and use that
+- * on architectures that don't like the maestro's pci dma ickiness.
+- */
+-
+-/*****************************************************************************/
+-
+-#include <linux/module.h>
+-#include <linux/sched.h>
+-#include <linux/smp_lock.h>
+-#include <linux/string.h>
+-#include <linux/ctype.h>
+-#include <linux/ioport.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/spinlock.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/poll.h>
+-#include <linux/reboot.h>
+-#include <linux/bitops.h>
+-#include <linux/wait.h>
+-#include <linux/mutex.h>
+-
+-
+-#include <asm/current.h>
+-#include <asm/dma.h>
+-#include <asm/io.h>
+-#include <asm/page.h>
+-#include <asm/uaccess.h>
+-
+-#include "maestro.h"
+-
+-static struct pci_driver maestro_pci_driver;
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define M_DEBUG 1
+-
+-#ifdef M_DEBUG
+-static int debug;
+-#define M_printk(args...) {if (debug) printk(args);}
+-#else
+-#define M_printk(x)
+-#endif
+-
+-/* we try to setup 2^(dsps_order) /dev/dsp devices */
+-static int dsps_order;
+-/* whether or not we mess around with power management */
+-static int use_pm=2; /* set to 1 for force */
+-/* clocking for broken hardware - a few laptops seem to use a 50Khz clock
+- ie insmod with clocking=50000 or so */
+-
+-static int clocking=48000;
+-
+-MODULE_AUTHOR("Zach Brown <zab at zabbo.net>, Alan Cox <alan at redhat.com>");
+-MODULE_DESCRIPTION("ESS Maestro Driver");
+-MODULE_LICENSE("GPL");
+-
+-#ifdef M_DEBUG
+-module_param(debug, bool, 0644);
+-#endif
+-module_param(dsps_order, int, 0);
+-module_param(use_pm, int, 0);
+-module_param(clocking, int, 0);
+-
+-/* --------------------------------------------------------------------- */
+-#define DRIVER_VERSION "0.15"
+-
+-#ifndef PCI_VENDOR_ESS
+-#define PCI_VENDOR_ESS 0x125D
+-#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */
+-#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */
+-
+-#define PCI_VENDOR_ESS_OLD 0x1285 /* Platform Tech,
+- the people the maestro
+- was bought from */
+-#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 /* maestro 1 */
+-#endif /* PCI_VENDOR_ESS */
+-
+-#define ESS_CHAN_HARD 0x100
+-
+-/* NEC Versas ? */
+-#define NEC_VERSA_SUBID1 0x80581033
+-#define NEC_VERSA_SUBID2 0x803c1033
+-
+-
+-/* changed so that I could actually find all the
+- references and fix them up. it's a little more readable now. */
+-#define ESS_FMT_STEREO 0x01
+-#define ESS_FMT_16BIT 0x02
+-#define ESS_FMT_MASK 0x03
+-#define ESS_DAC_SHIFT 0
+-#define ESS_ADC_SHIFT 4
+-
+-#define ESS_STATE_MAGIC 0x125D1968
+-#define ESS_CARD_MAGIC 0x19283746
+-
+-#define DAC_RUNNING 1
+-#define ADC_RUNNING 2
+-
+-#define MAX_DSP_ORDER 2
+-#define MAX_DSPS (1<<MAX_DSP_ORDER)
+-#define NR_DSPS (1<<dsps_order)
+-#define NR_IDRS 32
+-
+-#define NR_APUS 64
+-#define NR_APU_REGS 16
+-
+-/* acpi states */
+-enum {
+- ACPI_D0=0,
+- ACPI_D1,
+- ACPI_D2,
+- ACPI_D3
+-};
+-
+-/* bits in the acpi masks */
+-#define ACPI_12MHZ ( 1 << 15)
+-#define ACPI_24MHZ ( 1 << 14)
+-#define ACPI_978 ( 1 << 13)
+-#define ACPI_SPDIF ( 1 << 12)
+-#define ACPI_GLUE ( 1 << 11)
+-#define ACPI__10 ( 1 << 10) /* reserved */
+-#define ACPI_PCIINT ( 1 << 9)
+-#define ACPI_HV ( 1 << 8) /* hardware volume */
+-#define ACPI_GPIO ( 1 << 7)
+-#define ACPI_ASSP ( 1 << 6)
+-#define ACPI_SB ( 1 << 5) /* sb emul */
+-#define ACPI_FM ( 1 << 4) /* fm emul */
+-#define ACPI_RB ( 1 << 3) /* ringbus / aclink */
+-#define ACPI_MIDI ( 1 << 2)
+-#define ACPI_GP ( 1 << 1) /* game port */
+-#define ACPI_WP ( 1 << 0) /* wave processor */
+-
+-#define ACPI_ALL (0xffff)
+-#define ACPI_SLEEP (~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
+- ACPI_MIDI|ACPI_GP|ACPI_WP))
+-#define ACPI_NONE (ACPI__10)
+-
+-/* these masks indicate which units we care about at
+- which states */
+-static u16 acpi_state_mask[] = {
+- [ACPI_D0] = ACPI_ALL,
+- [ACPI_D1] = ACPI_SLEEP,
+- [ACPI_D2] = ACPI_SLEEP,
+- [ACPI_D3] = ACPI_NONE
+-};
+-
+-static char version[] __devinitdata =
+-KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n";
+-
+-
+-
+-static const unsigned sample_size[] = { 1, 2, 2, 4 };
+-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+-
+-enum card_types_t {
+- TYPE_MAESTRO,
+- TYPE_MAESTRO2,
+- TYPE_MAESTRO2E
+-};
+-
+-static const char *card_names[]={
+- [TYPE_MAESTRO] = "ESS Maestro",
+- [TYPE_MAESTRO2] = "ESS Maestro 2",
+- [TYPE_MAESTRO2E] = "ESS Maestro 2E"
+-};
+-
+-static int clock_freq[]={
+- [TYPE_MAESTRO] = (49152000L / 1024L),
+- [TYPE_MAESTRO2] = (50000000L / 1024L),
+- [TYPE_MAESTRO2E] = (50000000L / 1024L)
+-};
+-
+-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
+-
+-static struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
+-
+-/* --------------------------------------------------------------------- */
+-
+-struct ess_state {
+- unsigned int magic;
+- /* FIXME: we probably want submixers in here, but only one record pair */
+- u8 apu[6]; /* l/r output, l/r intput converters, l/r input apus */
+- u8 apu_mode[6]; /* Running mode for this APU */
+- u8 apu_pan[6]; /* Panning setup for this APU */
+- u32 apu_base[6]; /* base address for this apu */
+- struct ess_card *card; /* Card info */
+- /* wave stuff */
+- unsigned int rateadc, ratedac;
+- unsigned char fmt, enable;
+-
+- int index;
+-
+- /* this locks around the oss state in the driver */
+- spinlock_t lock;
+- /* only let 1 be opening at a time */
+- struct mutex open_mutex;
+- wait_queue_head_t open_wait;
+- mode_t open_mode;
+-
+- /* soundcore stuff */
+- int dev_audio;
+-
+- struct dmabuf {
+- void *rawbuf;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- /* XXX zab - swptr only in here so that it can be referenced by
+- clear_advance, as far as I can tell :( */
+- unsigned hwptr, swptr;
+- unsigned total_bytes;
+- int count;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize;
+- unsigned fragsamples;
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1; /* our oss buffers are ready to go */
+- unsigned endcleared:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- u16 base; /* Offset for ptr */
+- } dma_dac, dma_adc;
+-
+- /* pointer to each dsp?s piece of the apu->src buffer page */
+- void *mixbuf;
+-
+-};
+-
+-struct ess_card {
+- unsigned int magic;
+-
+- /* We keep maestro cards in a linked list */
+- struct ess_card *next;
+-
+- int dev_mixer;
+-
+- int card_type;
+-
+- /* as most of this is static,
+- perhaps it should be a pointer to a global struct */
+- struct mixer_goo {
+- int modcnt;
+- int supported_mixers;
+- int stereo_mixers;
+- int record_sources;
+- /* the caller must guarantee arg sanity before calling these */
+-/* int (*read_mixer)(struct ess_card *card, int index);*/
+- void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right);
+- int (*recmask_io)(struct ess_card *card,int rw,int mask);
+- unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+- } mix;
+-
+- int power_regs;
+-
+- int in_suspend;
+- wait_queue_head_t suspend_queue;
+-
+- struct ess_state channels[MAX_DSPS];
+- u16 maestro_map[NR_IDRS]; /* Register map */
+- /* we have to store this junk so that we can come back from a
+- suspend */
+- u16 apu_map[NR_APUS][NR_APU_REGS]; /* contents of apu regs */
+-
+- /* this locks around the physical registers on the card */
+- spinlock_t lock;
+-
+- /* memory for this card.. wavecache limited :(*/
+- void *dmapages;
+- int dmaorder;
+-
+- /* hardware resources */
+- struct pci_dev *pcidev;
+- u32 iobase;
+- u32 irq;
+-
+- int bob_freq;
+- char dsps_open;
+-
+- int dock_mute_vol;
+-};
+-
+-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val );
+-
+-static unsigned
+-ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static void check_suspend(struct ess_card *card);
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-/*
+- * ESS Maestro AC97 codec programming interface.
+- */
+-
+-static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val)
+-{
+- int io = card->iobase;
+- int i;
+- /*
+- * Wait for the codec bus to be free
+- */
+-
+- check_suspend(card);
+-
+- for(i=0;i<10000;i++)
+- {
+- if(!(inb(io+ESS_AC97_INDEX)&1))
+- break;
+- }
+- /*
+- * Write the bus
+- */
+- outw(val, io+ESS_AC97_DATA);
+- mdelay(1);
+- outb(cmd, io+ESS_AC97_INDEX);
+- mdelay(1);
+-}
+-
+-static u16 maestro_ac97_get(struct ess_card *card, u8 cmd)
+-{
+- int io = card->iobase;
+- int sanity=10000;
+- u16 data;
+- int i;
+-
+- check_suspend(card);
+- /*
+- * Wait for the codec bus to be free
+- */
+-
+- for(i=0;i<10000;i++)
+- {
+- if(!(inb(io+ESS_AC97_INDEX)&1))
+- break;
+- }
+-
+- outb(cmd|0x80, io+ESS_AC97_INDEX);
+- mdelay(1);
+-
+- while(inb(io+ESS_AC97_INDEX)&1)
+- {
+- sanity--;
+- if(!sanity)
+- {
+- printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd);
+- return 0;
+- }
+- }
+- data=inw(io+ESS_AC97_DATA);
+- mdelay(1);
+- return data;
+-}
+-
+-/* OSS interface to the ac97s.. */
+-
+-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
+- SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
+- SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
+-
+-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
+- SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
+- SOUND_MASK_SPEAKER)
+-
+-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
+- SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+- SOUND_MASK_PHONEIN)
+-
+-#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
+-
+-/* this table has default mixer values for all OSS mixers.
+- be sure to fill it in if you add oss mixers
+- to anyone's supported mixer defines */
+-
+-static unsigned int mixer_defaults[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_VOLUME] = 0x3232,
+- [SOUND_MIXER_BASS] = 0x3232,
+- [SOUND_MIXER_TREBLE] = 0x3232,
+- [SOUND_MIXER_SPEAKER] = 0x3232,
+- [SOUND_MIXER_MIC] = 0x8000, /* annoying */
+- [SOUND_MIXER_LINE] = 0x3232,
+- [SOUND_MIXER_CD] = 0x3232,
+- [SOUND_MIXER_VIDEO] = 0x3232,
+- [SOUND_MIXER_LINE1] = 0x3232,
+- [SOUND_MIXER_PCM] = 0x3232,
+- [SOUND_MIXER_IGAIN] = 0x3232
+-};
+-
+-static struct ac97_mixer_hw {
+- unsigned char offset;
+- int scale;
+-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
+- [SOUND_MIXER_VOLUME] = {0x02,63},
+- [SOUND_MIXER_BASS] = {0x08,15},
+- [SOUND_MIXER_TREBLE] = {0x08,15},
+- [SOUND_MIXER_SPEAKER] = {0x0a,15},
+- [SOUND_MIXER_MIC] = {0x0e,31},
+- [SOUND_MIXER_LINE] = {0x10,31},
+- [SOUND_MIXER_CD] = {0x12,31},
+- [SOUND_MIXER_VIDEO] = {0x14,31},
+- [SOUND_MIXER_LINE1] = {0x16,31},
+- [SOUND_MIXER_PCM] = {0x18,31},
+- [SOUND_MIXER_IGAIN] = {0x1c,15}
+-};
+-
+-#if 0 /* *shrug* removed simply because we never used it.
+- feel free to implement again if needed */
+-
+-/* reads the given OSS mixer from the ac97
+- the caller must have insured that the ac97 knows
+- about that given mixer, and should be holding a
+- spinlock for the card */
+-static int ac97_read_mixer(struct ess_card *card, int mixer)
+-{
+- u16 val;
+- int ret=0;
+- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
+-
+- val = maestro_ac97_get(card, mh->offset);
+-
+- if(AC97_STEREO_MASK & (1<<mixer)) {
+- /* nice stereo mixers .. */
+- int left,right;
+-
+- left = (val >> 8) & 0x7f;
+- right = val & 0x7f;
+-
+- if (mixer == SOUND_MIXER_IGAIN) {
+- right = (right * 100) / mh->scale;
+- left = (left * 100) / mh->scale;
+- } else {
+- right = 100 - ((right * 100) / mh->scale);
+- left = 100 - ((left * 100) / mh->scale);
+- }
+-
+- ret = left | (right << 8);
+- } else if (mixer == SOUND_MIXER_SPEAKER) {
+- ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+- } else if (mixer == SOUND_MIXER_MIC) {
+- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+- /* the low bit is optional in the tone sliders and masking
+- it lets is avoid the 0xf 'bypass'.. */
+- } else if (mixer == SOUND_MIXER_BASS) {
+- ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
+- } else if (mixer == SOUND_MIXER_TREBLE) {
+- ret = 100 - (((val & 0xe) * 100) / mh->scale);
+- }
+-
+- M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
+-
+- return ret;
+-}
+-#endif
+-
+-/* write the OSS encoded volume to the given OSS encoded mixer,
+- again caller's job to make sure all is well in arg land,
+- call with spinlock held */
+-
+-/* linear scale -> log */
+-static unsigned char lin2log[101] =
+-{
+-0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
+-50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
+-63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
+-72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
+-78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
+-83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
+-87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
+-90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
+-93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
+-95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
+-97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99
+-};
+-
+-static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
+-{
+- u16 val=0;
+- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
+-
+- M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
+-
+- if(AC97_STEREO_MASK & (1<<mixer)) {
+- /* stereo mixers, mute them if we can */
+-
+- if (mixer == SOUND_MIXER_IGAIN) {
+- /* igain's slider is reversed.. */
+- right = (right * mh->scale) / 100;
+- left = (left * mh->scale) / 100;
+- if ((left == 0) && (right == 0))
+- val |= 0x8000;
+- } else if (mixer == SOUND_MIXER_PCM || mixer == SOUND_MIXER_CD) {
+- /* log conversion seems bad for them */
+- if ((left == 0) && (right == 0))
+- val = 0x8000;
+- right = ((100 - right) * mh->scale) / 100;
+- left = ((100 - left) * mh->scale) / 100;
+- } else {
+- /* log conversion for the stereo controls */
+- if((left == 0) && (right == 0))
+- val = 0x8000;
+- right = ((100 - lin2log[right]) * mh->scale) / 100;
+- left = ((100 - lin2log[left]) * mh->scale) / 100;
+- }
+-
+- val |= (left << 8) | right;
+-
+- } else if (mixer == SOUND_MIXER_SPEAKER) {
+- val = (((100 - left) * mh->scale) / 100) << 1;
+- } else if (mixer == SOUND_MIXER_MIC) {
+- val = maestro_ac97_get(card, mh->offset) & ~0x801f;
+- val |= (((100 - left) * mh->scale) / 100);
+- /* the low bit is optional in the tone sliders and masking
+- it lets is avoid the 0xf 'bypass'.. */
+- } else if (mixer == SOUND_MIXER_BASS) {
+- val = maestro_ac97_get(card , mh->offset) & ~0x0f00;
+- val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
+- } else if (mixer == SOUND_MIXER_TREBLE) {
+- val = maestro_ac97_get(card , mh->offset) & ~0x000f;
+- val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+- }
+-
+- maestro_ac97_set(card , mh->offset, val);
+-
+- M_printk(" -> %x\n",val);
+-}
+-
+-/* the following tables allow us to go from
+- OSS <-> ac97 quickly. */
+-
+-enum ac97_recsettings {
+- AC97_REC_MIC=0,
+- AC97_REC_CD,
+- AC97_REC_VIDEO,
+- AC97_REC_AUX,
+- AC97_REC_LINE,
+- AC97_REC_STEREO, /* combination of all enabled outputs.. */
+- AC97_REC_MONO, /*.. or the mono equivalent */
+- AC97_REC_PHONE
+-};
+-
+-static unsigned int ac97_oss_mask[] = {
+- [AC97_REC_MIC] = SOUND_MASK_MIC,
+- [AC97_REC_CD] = SOUND_MASK_CD,
+- [AC97_REC_VIDEO] = SOUND_MASK_VIDEO,
+- [AC97_REC_AUX] = SOUND_MASK_LINE1,
+- [AC97_REC_LINE] = SOUND_MASK_LINE,
+- [AC97_REC_PHONE] = SOUND_MASK_PHONEIN
+-};
+-
+-/* indexed by bit position */
+-static unsigned int ac97_oss_rm[] = {
+- [SOUND_MIXER_MIC] = AC97_REC_MIC,
+- [SOUND_MIXER_CD] = AC97_REC_CD,
+- [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
+- [SOUND_MIXER_LINE1] = AC97_REC_AUX,
+- [SOUND_MIXER_LINE] = AC97_REC_LINE,
+- [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
+-};
+-
+-/* read or write the recmask
+- the ac97 can really have left and right recording
+- inputs independently set, but OSS doesn't seem to
+- want us to express that to the user.
+- the caller guarantees that we have a supported bit set,
+- and they must be holding the card's spinlock */
+-static int
+-ac97_recmask_io(struct ess_card *card, int read, int mask)
+-{
+- unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ];
+-
+- if (read) return val;
+-
+- /* oss can have many inputs, maestro can't. try
+- to pick the 'new' one */
+-
+- if (mask != val) mask &= ~val;
+-
+- val = ffs(mask) - 1;
+- val = ac97_oss_rm[val];
+- val |= val << 8; /* set both channels */
+-
+- M_printk("maestro: setting ac97 recmask to 0x%x\n",val);
+-
+- maestro_ac97_set(card,0x1a,val);
+-
+- return 0;
+-};
+-
+-/*
+- * The Maestro can be wired to a standard AC97 compliant codec
+- * (see www.intel.com for the pdf's on this), or to a PT101 codec
+- * which appears to be the ES1918 (data sheet on the esstech.com.tw site)
+- *
+- * The PT101 setup is untested.
+- */
+-
+-static u16 __init maestro_ac97_init(struct ess_card *card)
+-{
+- u16 vend1, vend2, caps;
+-
+- card->mix.supported_mixers = AC97_SUPPORTED_MASK;
+- card->mix.stereo_mixers = AC97_STEREO_MASK;
+- card->mix.record_sources = AC97_RECORD_MASK;
+-/* card->mix.read_mixer = ac97_read_mixer;*/
+- card->mix.write_mixer = ac97_write_mixer;
+- card->mix.recmask_io = ac97_recmask_io;
+-
+- vend1 = maestro_ac97_get(card, 0x7c);
+- vend2 = maestro_ac97_get(card, 0x7e);
+-
+- caps = maestro_ac97_get(card, 0x00);
+-
+- printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n",
+- vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf);
+-
+- if (! (caps & 0x4) ) {
+- /* no bass/treble nobs */
+- card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
+- }
+-
+- /* XXX endianness, dork head. */
+- /* vendor specifc bits.. */
+- switch ((long)(vend1 << 16) | vend2) {
+- case 0x545200ff: /* TriTech */
+- /* no idea what this does */
+- maestro_ac97_set(card,0x2a,0x0001);
+- maestro_ac97_set(card,0x2c,0x0000);
+- maestro_ac97_set(card,0x2c,0xffff);
+- break;
+-#if 0 /* i thought the problems I was seeing were with
+- the 1921, but apparently they were with the pci board
+- it was on, so this code is commented out.
+- lets see if this holds true. */
+- case 0x83847609: /* ESS 1921 */
+- /* writing to 0xe (mic) or 0x1a (recmask) seems
+- to hang this codec */
+- card->mix.supported_mixers &= ~(SOUND_MASK_MIC);
+- card->mix.record_sources = 0;
+- card->mix.recmask_io = NULL;
+-#if 0 /* don't ask. I have yet to see what these actually do. */
+- maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
+- udelay(20);
+- maestro_ac97_set(card,0x78,0x3002);
+- udelay(20);
+- maestro_ac97_set(card,0x78,0x3802);
+- udelay(20);
+-#endif
+- break;
+-#endif
+- default: break;
+- }
+-
+- maestro_ac97_set(card, 0x1E, 0x0404);
+- /* null misc stuff */
+- maestro_ac97_set(card, 0x20, 0x0000);
+-
+- return 0;
+-}
+-
+-#if 0 /* there has been 1 person on the planet with a pt101 that we
+- know of. If they care, they can put this back in :) */
+-static u16 maestro_pt101_init(struct ess_card *card,int iobase)
+-{
+- printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
+- /* who knows.. */
+- maestro_ac97_set(iobase, 0x2A, 0x0001);
+- maestro_ac97_set(iobase, 0x2C, 0x0000);
+- maestro_ac97_set(iobase, 0x2C, 0xFFFF);
+- maestro_ac97_set(iobase, 0x10, 0x9F1F);
+- maestro_ac97_set(iobase, 0x12, 0x0808);
+- maestro_ac97_set(iobase, 0x14, 0x9F1F);
+- maestro_ac97_set(iobase, 0x16, 0x9F1F);
+- maestro_ac97_set(iobase, 0x18, 0x0404);
+- maestro_ac97_set(iobase, 0x1A, 0x0000);
+- maestro_ac97_set(iobase, 0x1C, 0x0000);
+- maestro_ac97_set(iobase, 0x02, 0x0404);
+- maestro_ac97_set(iobase, 0x04, 0x0808);
+- maestro_ac97_set(iobase, 0x0C, 0x801F);
+- maestro_ac97_set(iobase, 0x0E, 0x801F);
+- return 0;
+-}
+-#endif
+-
+-/* this is very magic, and very slow.. */
+-static void
+-maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
+-{
+- u16 save_68;
+- u16 w;
+- u32 vend;
+-
+- outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
+- outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
+- outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
+-
+- /* reset the first codec */
+- outw(0x0000, ioaddr+0x36);
+- save_68 = inw(ioaddr+0x68);
+- pci_read_config_word(pcidev, 0x58, &w); /* something magical with gpio and bus arb. */
+- pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
+- if( w & 0x1)
+- save_68 |= 0x10;
+- outw(0xfffe, ioaddr + 0x64); /* tickly gpio 0.. */
+- outw(0x0001, ioaddr + 0x68);
+- outw(0x0000, ioaddr + 0x60);
+- udelay(20);
+- outw(0x0001, ioaddr + 0x60);
+- mdelay(20);
+-
+- outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */
+- outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38);
+- outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a);
+- outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c);
+-
+- /* now the second codec */
+- outw(0x0000, ioaddr+0x36);
+- outw(0xfff7, ioaddr + 0x64);
+- save_68 = inw(ioaddr+0x68);
+- outw(0x0009, ioaddr + 0x68);
+- outw(0x0001, ioaddr + 0x60);
+- udelay(20);
+- outw(0x0009, ioaddr + 0x60);
+- mdelay(500); /* .. ouch.. */
+- outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
+- outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
+- outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
+-
+-#if 0 /* the loop here needs to be much better if we want it.. */
+- M_printk("trying software reset\n");
+- /* try and do a software reset */
+- outb(0x80|0x7c, ioaddr + 0x30);
+- for (w=0; ; w++) {
+- if ((inw(ioaddr+ 0x30) & 1) == 0) {
+- if(inb(ioaddr + 0x32) !=0) break;
+-
+- outb(0x80|0x7d, ioaddr + 0x30);
+- if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
+- outb(0x80|0x7f, ioaddr + 0x30);
+- if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
+- }
+-
+- if( w > 10000) {
+- outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */
+- mdelay(500); /* oh my.. */
+- outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37);
+- udelay(1);
+- outw( 0x80, ioaddr+0x30);
+- for(w = 0 ; w < 10000; w++) {
+- if((inw(ioaddr + 0x30) & 1) ==0) break;
+- }
+- }
+- }
+-#endif
+- if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
+- /* turn on external amp? */
+- outw(0xf9ff, ioaddr + 0x64);
+- outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
+- outw(0x0209, ioaddr + 0x60);
+- }
+-
+- /* Turn on the 978 docking chip.
+- First frob the "master output enable" bit,
+- then set most of the playback volume control registers to max. */
+- outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);
+- outb(0xff, ioaddr+0xc3);
+- outb(0xff, ioaddr+0xc4);
+- outb(0xff, ioaddr+0xc6);
+- outb(0xff, ioaddr+0xc8);
+- outb(0x3f, ioaddr+0xcf);
+- outb(0x3f, ioaddr+0xd0);
+-}
+-/*
+- * Indirect register access. Not all registers are readable so we
+- * need to keep register state ourselves
+- */
+-
+-#define WRITEABLE_MAP 0xEFFFFF
+-#define READABLE_MAP 0x64003F
+-
+-/*
+- * The Maestro engineers were a little indirection happy. These indirected
+- * registers themselves include indirect registers at another layer
+- */
+-
+-static void __maestro_write(struct ess_card *card, u16 reg, u16 data)
+-{
+- long ioaddr = card->iobase;
+-
+- outw(reg, ioaddr+0x02);
+- outw(data, ioaddr+0x00);
+- if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg);
+- else card->maestro_map[reg]=data;
+-
+-}
+-
+-static void maestro_write(struct ess_state *s, u16 reg, u16 data)
+-{
+- unsigned long flags;
+-
+- check_suspend(s->card);
+- spin_lock_irqsave(&s->card->lock,flags);
+-
+- __maestro_write(s->card,reg,data);
+-
+- spin_unlock_irqrestore(&s->card->lock,flags);
+-}
+-
+-static u16 __maestro_read(struct ess_card *card, u16 reg)
+-{
+- long ioaddr = card->iobase;
+-
+- outw(reg, ioaddr+0x02);
+- return card->maestro_map[reg]=inw(ioaddr+0x00);
+-}
+-
+-static u16 maestro_read(struct ess_state *s, u16 reg)
+-{
+- if(READABLE_MAP & (1<<reg))
+- {
+- unsigned long flags;
+- check_suspend(s->card);
+- spin_lock_irqsave(&s->card->lock,flags);
+-
+- __maestro_read(s->card,reg);
+-
+- spin_unlock_irqrestore(&s->card->lock,flags);
+- }
+- return s->card->maestro_map[reg];
+-}
+-
+-/*
+- * These routines handle accessing the second level indirections to the
+- * wave ram.
+- */
+-
+-/*
+- * The register names are the ones ESS uses (see 104T31.ZIP)
+- */
+-
+-#define IDR0_DATA_PORT 0x00
+-#define IDR1_CRAM_POINTER 0x01
+-#define IDR2_CRAM_DATA 0x02
+-#define IDR3_WAVE_DATA 0x03
+-#define IDR4_WAVE_PTR_LOW 0x04
+-#define IDR5_WAVE_PTR_HI 0x05
+-#define IDR6_TIMER_CTRL 0x06
+-#define IDR7_WAVE_ROMRAM 0x07
+-
+-static void apu_index_set(struct ess_card *card, u16 index)
+-{
+- int i;
+- __maestro_write(card, IDR1_CRAM_POINTER, index);
+- for(i=0;i<1000;i++)
+- if(__maestro_read(card, IDR1_CRAM_POINTER)==index)
+- return;
+- printk(KERN_WARNING "maestro: APU register select failed.\n");
+-}
+-
+-static void apu_data_set(struct ess_card *card, u16 data)
+-{
+- int i;
+- for(i=0;i<1000;i++)
+- {
+- if(__maestro_read(card, IDR0_DATA_PORT)==data)
+- return;
+- __maestro_write(card, IDR0_DATA_PORT, data);
+- }
+-}
+-
+-/*
+- * This is the public interface for APU manipulation. It handles the
+- * interlock to avoid two APU writes in parallel etc. Don't diddle
+- * directly with the stuff above.
+- */
+-
+-static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data)
+-{
+- unsigned long flags;
+-
+- check_suspend(s->card);
+-
+- if(channel&ESS_CHAN_HARD)
+- channel&=~ESS_CHAN_HARD;
+- else
+- {
+- if(channel>5)
+- printk("BAD CHANNEL %d.\n",channel);
+- else
+- channel = s->apu[channel];
+- /* store based on real hardware apu/reg */
+- s->card->apu_map[channel][reg]=data;
+- }
+- reg|=(channel<<4);
+-
+- /* hooray for double indirection!! */
+- spin_lock_irqsave(&s->card->lock,flags);
+-
+- apu_index_set(s->card, reg);
+- apu_data_set(s->card, data);
+-
+- spin_unlock_irqrestore(&s->card->lock,flags);
+-}
+-
+-static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg)
+-{
+- unsigned long flags;
+- u16 v;
+-
+- check_suspend(s->card);
+-
+- if(channel&ESS_CHAN_HARD)
+- channel&=~ESS_CHAN_HARD;
+- else
+- channel = s->apu[channel];
+-
+- reg|=(channel<<4);
+-
+- spin_lock_irqsave(&s->card->lock,flags);
+-
+- apu_index_set(s->card, reg);
+- v=__maestro_read(s->card, IDR0_DATA_PORT);
+-
+- spin_unlock_irqrestore(&s->card->lock,flags);
+- return v;
+-}
+-
+-
+-/*
+- * The wavecache buffers between the APUs and
+- * pci bus mastering
+- */
+-
+-static void wave_set_register(struct ess_state *s, u16 reg, u16 value)
+-{
+- long ioaddr = s->card->iobase;
+- unsigned long flags;
+- check_suspend(s->card);
+-
+- spin_lock_irqsave(&s->card->lock,flags);
+-
+- outw(reg, ioaddr+0x10);
+- outw(value, ioaddr+0x12);
+-
+- spin_unlock_irqrestore(&s->card->lock,flags);
+-}
+-
+-static u16 wave_get_register(struct ess_state *s, u16 reg)
+-{
+- long ioaddr = s->card->iobase;
+- unsigned long flags;
+- u16 value;
+- check_suspend(s->card);
+-
+- spin_lock_irqsave(&s->card->lock,flags);
+- outw(reg, ioaddr+0x10);
+- value=inw(ioaddr+0x12);
+- spin_unlock_irqrestore(&s->card->lock,flags);
+-
+- return value;
+-}
+-
+-static void sound_reset(int ioaddr)
+-{
+- outw(0x2000, 0x18+ioaddr);
+- udelay(1);
+- outw(0x0000, 0x18+ioaddr);
+- udelay(1);
+-}
+-
+-/* sets the play formats of these apus, should be passed the already shifted format */
+-static void set_apu_fmt(struct ess_state *s, int apu, int mode)
+-{
+- int apu_fmt = 0x10;
+-
+- if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20;
+- if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10;
+- s->apu_mode[apu] = apu_fmt;
+- s->apu_mode[apu+1] = apu_fmt;
+-}
+-
+-/* this only fixes the output apu mode to be later set by start_dac and
+- company. output apu modes are set in ess_rec_setup */
+-static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
+-{
+- s->fmt = (s->fmt & mask) | data;
+- set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
+-}
+-
+-/* this is off by a little bit.. */
+-static u32 compute_rate(struct ess_state *s, u32 freq)
+-{
+- u32 clock = clock_freq[s->card->card_type];
+-
+- freq = (freq * clocking)/48000;
+-
+- if (freq == 48000)
+- return 0x10000;
+-
+- return ((freq / clock) <<16 )+
+- (((freq % clock) << 16) / clock);
+-}
+-
+-static void set_dac_rate(struct ess_state *s, unsigned int rate)
+-{
+- u32 freq;
+- int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 4000)
+- rate = 4000;
+-
+- s->ratedac = rate;
+-
+- if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
+- rate >>= 1;
+-
+-/* M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
+-
+- freq = compute_rate(s, rate);
+-
+- /* Load the frequency, turn on 6dB */
+- apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
+- ( ((freq&0xFF)<<8)|0x10 ));
+- apu_set_register(s, 0, 3, freq>>8);
+- apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)|
+- ( ((freq&0xFF)<<8)|0x10 ));
+- apu_set_register(s, 1, 3, freq>>8);
+-}
+-
+-static void set_adc_rate(struct ess_state *s, unsigned rate)
+-{
+- u32 freq;
+-
+- /* Sample Rate conversion APUs don't like 0x10000 for their rate */
+- if (rate > 47999)
+- rate = 47999;
+- if (rate < 4000)
+- rate = 4000;
+-
+- s->rateadc = rate;
+-
+- freq = compute_rate(s, rate);
+-
+- /* Load the frequency, turn on 6dB */
+- apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
+- ( ((freq&0xFF)<<8)|0x10 ));
+- apu_set_register(s, 2, 3, freq>>8);
+- apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)|
+- ( ((freq&0xFF)<<8)|0x10 ));
+- apu_set_register(s, 3, 3, freq>>8);
+-
+- /* fix mixer rate at 48khz. and its _must_ be 0x10000. */
+- freq = 0x10000;
+-
+- apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)|
+- ( ((freq&0xFF)<<8)|0x10 ));
+- apu_set_register(s, 4, 3, freq>>8);
+- apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)|
+- ( ((freq&0xFF)<<8)|0x10 ));
+- apu_set_register(s, 5, 3, freq>>8);
+-}
+-
+-/* Stop our host of recording apus */
+-static inline void stop_adc(struct ess_state *s)
+-{
+- /* XXX lets hope we don't have to lock around this */
+- if (! (s->enable & ADC_RUNNING)) return;
+-
+- s->enable &= ~ADC_RUNNING;
+- apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);
+- apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);
+- apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F);
+- apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F);
+-}
+-
+-/* stop output apus */
+-static void stop_dac(struct ess_state *s)
+-{
+- /* XXX have to lock around this? */
+- if (! (s->enable & DAC_RUNNING)) return;
+-
+- s->enable &= ~DAC_RUNNING;
+- apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);
+- apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);
+-}
+-
+-static void start_dac(struct ess_state *s)
+-{
+- /* XXX locks? */
+- if ( (s->dma_dac.mapped || s->dma_dac.count > 0) &&
+- s->dma_dac.ready &&
+- (! (s->enable & DAC_RUNNING)) ) {
+-
+- s->enable |= DAC_RUNNING;
+-
+- apu_set_register(s, 0, 0,
+- (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]);
+-
+- if((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_STEREO)
+- apu_set_register(s, 1, 0,
+- (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);
+- }
+-}
+-
+-static void start_adc(struct ess_state *s)
+-{
+- /* XXX locks? */
+- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+- && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) {
+-
+- s->enable |= ADC_RUNNING;
+- apu_set_register(s, 2, 0,
+- (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]);
+- apu_set_register(s, 4, 0,
+- (apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]);
+-
+- if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
+- apu_set_register(s, 3, 0,
+- (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);
+- apu_set_register(s, 5, 0,
+- (apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]);
+- }
+-
+- }
+-}
+-
+-
+-/*
+- * Native play back driver
+- */
+-
+-/* the mode passed should be already shifted and masked */
+-static void
+-ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
+-{
+- u32 pa;
+- u32 tmpval;
+- int high_apu = 0;
+- int channel;
+-
+- M_printk("mode=%d rate=%d buf=%p len=%d.\n",
+- mode, rate, buffer, size);
+-
+- /* all maestro sizes are in 16bit words */
+- size >>=1;
+-
+- if(mode&ESS_FMT_STEREO) {
+- high_apu++;
+- /* only 16/stereo gets size divided */
+- if(mode&ESS_FMT_16BIT)
+- size>>=1;
+- }
+-
+- for(channel=0; channel <= high_apu; channel++)
+- {
+- pa = virt_to_bus(buffer);
+-
+- /* set the wavecache control reg */
+- tmpval = (pa - 0x10) & 0xFFF8;
+- if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
+- if(mode & ESS_FMT_STEREO) tmpval |= 2;
+- ess->apu_base[channel]=tmpval;
+- wave_set_register(ess, ess->apu[channel]<<3, tmpval);
+-
+- pa -= virt_to_bus(ess->card->dmapages);
+- pa>>=1; /* words */
+-
+- /* base offset of dma calcs when reading the pointer
+- on the left one */
+- if(!channel) ess->dma_dac.base = pa&0xFFFF;
+-
+- pa|=0x00400000; /* System RAM */
+-
+- /* XXX the 16bit here might not be needed.. */
+- if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
+- if(channel)
+- pa|=0x00800000; /* Stereo */
+- pa>>=1;
+- }
+-
+-/* XXX think about endianess when writing these registers */
+- M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
+- /* start of sample */
+- apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
+- apu_set_register(ess, channel, 5, pa&0xFFFF);
+- /* sample end */
+- apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
+- /* setting loop len == sample len */
+- apu_set_register(ess, channel, 7, size);
+-
+- /* clear effects/env.. */
+- apu_set_register(ess, channel, 8, 0x0000);
+- /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */
+- apu_set_register(ess, channel, 9, 0xD000);
+-
+- /* clear routing stuff */
+- apu_set_register(ess, channel, 11, 0x0000);
+- /* dma on, no envelopes, filter to all 1s) */
+- apu_set_register(ess, channel, 0, 0x400F);
+-
+- if(mode&ESS_FMT_16BIT)
+- ess->apu_mode[channel]=0x10;
+- else
+- ess->apu_mode[channel]=0x30;
+-
+- if(mode&ESS_FMT_STEREO) {
+- /* set panning: left or right */
+- apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));
+- ess->apu_mode[channel] += 0x10;
+- } else
+- apu_set_register(ess, channel, 10, 0x8F08);
+- }
+-
+- /* clear WP interrupts */
+- outw(1, ess->card->iobase+0x04);
+- /* enable WP ints */
+- outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
+-
+- /* go team! */
+- set_dac_rate(ess,rate);
+- start_dac(ess);
+-}
+-
+-/*
+- * Native record driver
+- */
+-
+-/* again, passed mode is alrady shifted/masked */
+-static void
+-ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
+-{
+- int apu_step = 2;
+- int channel;
+-
+- M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n",
+- mode, rate, buffer, size);
+-
+- /* all maestro sizes are in 16bit words */
+- size >>=1;
+-
+- /* we're given the full size of the buffer, but
+- in stereo each channel will only use its half */
+- if(mode&ESS_FMT_STEREO) {
+- size >>=1;
+- apu_step = 1;
+- }
+-
+- /* APU assignments: 2 = mono/left SRC
+- 3 = right SRC
+- 4 = mono/left Input Mixer
+- 5 = right Input Mixer */
+- for(channel=2;channel<6;channel+=apu_step)
+- {
+- int i;
+- int bsize, route;
+- u32 pa;
+- u32 tmpval;
+-
+- /* data seems to flow from the codec, through an apu into
+- the 'mixbuf' bit of page, then through the SRC apu
+- and out to the real 'buffer'. ok. sure. */
+-
+- if(channel & 0x04) {
+- /* ok, we're an input mixer going from adc
+- through the mixbuf to the other apus */
+-
+- if(!(channel & 0x01)) {
+- pa = virt_to_bus(ess->mixbuf);
+- } else {
+- pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4));
+- }
+-
+- /* we source from a 'magic' apu */
+- bsize = PAGE_SIZE >> 5; /* half of this channels alloc, in words */
+- route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */
+- ess->apu_mode[channel] = 0x90; /* Input Mixer */
+-
+- } else {
+- /* we're a rate converter taking
+- input from the input apus and outputing it to
+- system memory */
+- if(!(channel & 0x01)) {
+- pa = virt_to_bus(buffer);
+- } else {
+- /* right channel records its split half.
+- *2 accommodates for rampant shifting earlier */
+- pa = virt_to_bus(buffer + size*2);
+- }
+-
+- ess->apu_mode[channel] = 0xB0; /* Sample Rate Converter */
+-
+- bsize = size;
+- /* get input from inputing apu */
+- route = channel + 2;
+- }
+-
+- M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel);
+-
+- /* set the wavecache control reg */
+- tmpval = (pa - 0x10) & 0xFFF8;
+- ess->apu_base[channel]=tmpval;
+- wave_set_register(ess, ess->apu[channel]<<3, tmpval);
+-
+- pa -= virt_to_bus(ess->card->dmapages);
+- pa>>=1; /* words */
+-
+- /* base offset of dma calcs when reading the pointer
+- on this left one */
+- if(channel==2) ess->dma_adc.base = pa&0xFFFF;
+-
+- pa|=0x00400000; /* bit 22 -> System RAM */
+-
+- M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n",
+- ess->apu[channel], pa, bsize, route);
+-
+- /* Begin loading the APU */
+- for(i=0;i<15;i++) /* clear all PBRs */
+- apu_set_register(ess, channel, i, 0x0000);
+-
+- apu_set_register(ess, channel, 0, 0x400F);
+-
+- /* need to enable subgroups.. and we should probably
+- have different groups for different /dev/dsps.. */
+- apu_set_register(ess, channel, 2, 0x8);
+-
+- /* Load the buffer into the wave engine */
+- apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
+- /* XXX reg is little endian.. */
+- apu_set_register(ess, channel, 5, pa&0xFFFF);
+- apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF);
+- apu_set_register(ess, channel, 7, bsize);
+-
+- /* clear effects/env.. */
+- apu_set_register(ess, channel, 8, 0x00F0);
+-
+- /* amplitude now? sure. why not. */
+- apu_set_register(ess, channel, 9, 0x0000);
+-
+- /* set filter tune, radius, polar pan */
+- apu_set_register(ess, channel, 10, 0x8F08);
+-
+- /* route input */
+- apu_set_register(ess, channel, 11, route);
+- }
+-
+- /* clear WP interrupts */
+- outw(1, ess->card->iobase+0x04);
+- /* enable WP ints */
+- outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
+-
+- /* let 'er rip */
+- set_adc_rate(ess,rate);
+- start_adc(ess);
+-}
+-/* --------------------------------------------------------------------- */
+-
+-static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
+-{
+- M_printk("set_dmaa??\n");
+-}
+-
+-static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
+-{
+- M_printk("set_dmac??\n");
+-}
+-
+-/* Playback pointer */
+-static inline unsigned get_dmaa(struct ess_state *s)
+-{
+- int offset;
+-
+- offset = apu_get_register(s,0,5);
+-
+-/* M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */
+-
+- offset-=s->dma_dac.base;
+-
+- return (offset&0xFFFE)<<1; /* hardware is in words */
+-}
+-
+-/* Record pointer */
+-static inline unsigned get_dmac(struct ess_state *s)
+-{
+- int offset;
+-
+- offset = apu_get_register(s,2,5);
+-
+-/* M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */
+-
+- /* The offset is an address not a position relative to base */
+- offset-=s->dma_adc.base;
+-
+- return (offset&0xFFFE)<<1; /* hardware is in words */
+-}
+-
+-/*
+- * Meet Bob, the timer...
+- */
+-
+-static irqreturn_t ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+-
+-static void stop_bob(struct ess_state *s)
+-{
+- /* Mask IDR 11,17 */
+- maestro_write(s, 0x11, maestro_read(s, 0x11)&~1);
+- maestro_write(s, 0x17, maestro_read(s, 0x17)&~1);
+-}
+-
+-/* eventually we could be clever and limit bob ints
+- to the frequency at which our smallest duration
+- chunks may expire */
+-#define ESS_SYSCLK 50000000
+-static void start_bob(struct ess_state *s)
+-{
+- int prescale;
+- int divide;
+-
+- /* XXX make freq selector much smarter, see calc_bob_rate */
+- int freq = 200;
+-
+- /* compute ideal interrupt frequency for buffer size & play rate */
+- /* first, find best prescaler value to match freq */
+- for(prescale=5;prescale<12;prescale++)
+- if(freq > (ESS_SYSCLK>>(prescale+9)))
+- break;
+-
+- /* next, back off prescaler whilst getting divider into optimum range */
+- divide=1;
+- while((prescale > 5) && (divide<32))
+- {
+- prescale--;
+- divide <<=1;
+- }
+- divide>>=1;
+-
+- /* now fine-tune the divider for best match */
+- for(;divide<31;divide++)
+- if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))
+- break;
+-
+- /* divide = 0 is illegal, but don't let prescale = 4! */
+- if(divide == 0)
+- {
+- divide++;
+- if(prescale>5)
+- prescale--;
+- }
+-
+- maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */
+-
+- /* Now set IDR 11/17 */
+- maestro_write(s, 0x11, maestro_read(s, 0x11)|1);
+- maestro_write(s, 0x17, maestro_read(s, 0x17)|1);
+-}
+-/* --------------------------------------------------------------------- */
+-
+-/* this quickly calculates the frequency needed for bob
+- and sets it if its different than what bob is
+- currently running at. its called often so
+- needs to be fairly quick. */
+-#define BOB_MIN 50
+-#define BOB_MAX 400
+-static void calc_bob_rate(struct ess_state *s) {
+-#if 0 /* this thing tries to set the frequency of bob such that
+- there are 2 interrupts / buffer walked by the dac/adc. That
+- is probably very wrong for people who actually care about
+- mid buffer positioning. it should be calculated as bytes/interrupt
+- and that needs to be decided :) so for now just use the static 150
+- in start_bob.*/
+-
+- unsigned int dac_rate=2,adc_rate=1,newrate;
+- static int israte=-1;
+-
+- if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN;
+- else {
+- dac_rate = (2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
+- (s->dma_dac.fragsize) ;
+- }
+-
+- if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN;
+- else {
+- adc_rate = (2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
+- (s->dma_adc.fragsize) ;
+- }
+-
+- if(dac_rate > adc_rate) newrate = adc_rate;
+- else newrate=dac_rate;
+-
+- if(newrate > BOB_MAX) newrate = BOB_MAX;
+- else {
+- if(newrate < BOB_MIN)
+- newrate = BOB_MIN;
+- }
+-
+- if( israte != newrate) {
+- printk("dac: %d adc: %d rate: %d\n",dac_rate,adc_rate,israte);
+- israte=newrate;
+- }
+-#endif
+-
+-}
+-
+-static int
+-prog_dmabuf(struct ess_state *s, unsigned rec)
+-{
+- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+- unsigned rate = rec ? s->rateadc : s->ratedac;
+- unsigned bytepersec;
+- unsigned bufs;
+- unsigned char fmt;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- fmt = s->fmt;
+- if (rec) {
+- stop_adc(s);
+- fmt >>= ESS_ADC_SHIFT;
+- } else {
+- stop_dac(s);
+- fmt >>= ESS_DAC_SHIFT;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- fmt &= ESS_FMT_MASK;
+-
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+-
+- /* this algorithm is a little nuts.. where did /1000 come from? */
+- bytepersec = rate << sample_shift[fmt];
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytepersec)
+- db->fragshift = ld2(bytepersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- db->fragsamples = db->fragsize >> sample_shift[fmt];
+- db->dmasize = db->numfrag << db->fragshift;
+-
+- M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
+-
+- memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if (rec)
+- ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
+- else
+- ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+- db->ready = 1;
+-
+- return 0;
+-}
+-
+-static __inline__ void
+-clear_advance(struct ess_state *s)
+-{
+- unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+-
+- unsigned char *buf = s->dma_dac.rawbuf;
+- unsigned bsize = s->dma_dac.dmasize;
+- unsigned bptr = s->dma_dac.swptr;
+- unsigned len = s->dma_dac.fragsize;
+-
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(buf + bptr, c, x);
+- /* account for wrapping? */
+- bptr = 0;
+- len -= x;
+- }
+- memset(buf + bptr, c, len);
+-}
+-
+-/* call with spinlock held! */
+-static void
+-ess_update_ptr(struct ess_state *s)
+-{
+- unsigned hwptr;
+- int diff;
+-
+- /* update ADC pointer */
+- if (s->dma_adc.ready) {
+- /* oh boy should this all be re-written. everything in the current code paths think
+- that the various counters/pointers are expressed in bytes to the user but we have
+- two apus doing stereo stuff so we fix it up here.. it propagates to all the various
+- counters from here. */
+- if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
+- hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;
+- } else {
+- hwptr = get_dmac(s) % s->dma_adc.dmasize;
+- }
+- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- wake_up(&s->dma_adc.wait);
+- if (!s->dma_adc.mapped) {
+- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+- /* FILL ME
+- wrindir(s, SV_CIENABLE, s->enable); */
+- stop_adc(s);
+- /* brute force everyone back in sync, sigh */
+- s->dma_adc.count = 0;
+- s->dma_adc.swptr = 0;
+- s->dma_adc.hwptr = 0;
+- s->dma_adc.error++;
+- }
+- }
+- }
+- /* update DAC pointer */
+- if (s->dma_dac.ready) {
+- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
+- /* the apu only reports the length it has seen, not the
+- length of the memory that has been used (the WP
+- knows that) */
+- if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
+- hwptr<<=1;
+-
+- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+-/* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
+- s->dma_dac.hwptr = hwptr;
+- s->dma_dac.total_bytes += diff;
+- if (s->dma_dac.mapped) {
+- s->dma_dac.count += diff;
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
+- wake_up(&s->dma_dac.wait);
+- }
+- } else {
+- s->dma_dac.count -= diff;
+-/* M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
+- if (s->dma_dac.count <= 0) {
+- M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count,
+- hwptr, s->dma_dac.swptr);
+- /* FILL ME
+- wrindir(s, SV_CIENABLE, s->enable); */
+- /* XXX how on earth can calling this with the lock held work.. */
+- stop_dac(s);
+- /* brute force everyone back in sync, sigh */
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = hwptr;
+- s->dma_dac.error++;
+- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+- clear_advance(s);
+- s->dma_dac.endcleared = 1;
+- }
+- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
+- wake_up(&s->dma_dac.wait);
+-/* printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr,
+- hwptr);*/
+- }
+- }
+- }
+-}
+-
+-static irqreturn_t
+-ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct ess_state *s;
+- struct ess_card *c = (struct ess_card *)dev_id;
+- int i;
+- u32 event;
+-
+- if ( ! (event = inb(c->iobase+0x1A)) )
+- return IRQ_NONE;
+-
+- outw(inw(c->iobase+4)&1, c->iobase+4);
+-
+-/* M_printk("maestro int: %x\n",event);*/
+- if(event&(1<<6))
+- {
+- int x;
+- enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;
+- int volume;
+-
+- /* Figure out which volume control button was pushed,
+- based on differences from the default register
+- values. */
+- x = inb(c->iobase+0x1c);
+- if (x&1) vol_evt = MUTE_EVT;
+- else if (((x>>1)&7) > 4) vol_evt = UP_EVT;
+- else vol_evt = DOWN_EVT;
+-
+- /* Reset the volume control registers. */
+- outb(0x88, c->iobase+0x1c);
+- outb(0x88, c->iobase+0x1d);
+- outb(0x88, c->iobase+0x1e);
+- outb(0x88, c->iobase+0x1f);
+-
+- /* Deal with the button press in a hammer-handed
+- manner by adjusting the master mixer volume. */
+- volume = c->mix.mixer_state[0] & 0xff;
+- if (vol_evt == UP_EVT) {
+- volume += 5;
+- if (volume > 100)
+- volume = 100;
+- }
+- else if (vol_evt == DOWN_EVT) {
+- volume -= 5;
+- if (volume < 0)
+- volume = 0;
+- } else {
+- /* vol_evt == MUTE_EVT */
+- if (volume == 0)
+- volume = c->dock_mute_vol;
+- else {
+- c->dock_mute_vol = volume;
+- volume = 0;
+- }
+- }
+- set_mixer (c, 0, (volume << 8) | volume);
+- }
+-
+- /* Ack all the interrupts. */
+- outb(0xFF, c->iobase+0x1A);
+-
+- /*
+- * Update the pointers for all APU's we are running.
+- */
+- for(i=0;i<NR_DSPS;i++)
+- {
+- s=&c->channels[i];
+- if(s->dev_audio == -1)
+- break;
+- spin_lock(&s->lock);
+- ess_update_ptr(s);
+- spin_unlock(&s->lock);
+- }
+- return IRQ_HANDLED;
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n";
+-
+-#define VALIDATE_MAGIC(FOO,MAG) \
+-({ \
+- if (!(FOO) || (FOO)->magic != MAG) { \
+- printk(invalid_magic,__FUNCTION__); \
+- return -ENXIO; \
+- } \
+-})
+-
+-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC)
+-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC)
+-
+-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val )
+-{
+- unsigned int left,right;
+- /* cleanse input a little */
+- right = ((val >> 8) & 0xff) ;
+- left = (val & 0xff) ;
+-
+- if(right > 100) right = 100;
+- if(left > 100) left = 100;
+-
+- card->mix.mixer_state[mixer]=(right << 8) | left;
+- card->mix.write_mixer(card,mixer,left,right);
+-}
+-
+-static void
+-mixer_push_state(struct ess_card *card)
+-{
+- int i;
+- for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
+- if( ! supported_mixer(card,i)) continue;
+-
+- set_mixer(card,i,card->mix.mixer_state[i]);
+- }
+-}
+-
+-static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg)
+-{
+- int i, val=0;
+- unsigned long flags;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_CARD(card);
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
+- strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
+- info.modify_counter = card->mix.modcnt;
+- if (copy_to_user(argp, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == SOUND_OLD_MIXER_INFO) {
+- _old_mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
+- strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
+- if (copy_to_user(argp, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, p);
+-
+- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+- return -EINVAL;
+-
+- if (_IOC_DIR(cmd) == _IOC_READ) {
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* give them the current record source */
+-
+- if(!card->mix.recmask_io) {
+- val = 0;
+- } else {
+- spin_lock_irqsave(&card->lock, flags);
+- val = card->mix.recmask_io(card,1,0);
+- spin_unlock_irqrestore(&card->lock, flags);
+- }
+- break;
+-
+- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+- val = card->mix.supported_mixers;
+- break;
+-
+- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+- val = card->mix.record_sources;
+- break;
+-
+- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+- val = card->mix.stereo_mixers;
+- break;
+-
+- case SOUND_MIXER_CAPS:
+- val = SOUND_CAP_EXCL_INPUT;
+- break;
+-
+- default: /* read a specific mixer */
+- i = _IOC_NR(cmd);
+-
+- if ( ! supported_mixer(card,i))
+- return -EINVAL;
+-
+- /* do we ever want to touch the hardware? */
+-/* spin_lock_irqsave(&card->lock, flags);
+- val = card->mix.read_mixer(card,i);
+- spin_unlock_irqrestore(&card->lock, flags);*/
+-
+- val = card->mix.mixer_state[i];
+-/* M_printk("returned 0x%x for mixer %d\n",val,i);*/
+-
+- break;
+- }
+- return put_user(val, p);
+- }
+-
+- if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
+- return -EINVAL;
+-
+- card->mix.modcnt++;
+-
+- if (get_user(val, p))
+- return -EFAULT;
+-
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+-
+- if (!card->mix.recmask_io) return -EINVAL;
+- if(!val) return 0;
+- if(! (val &= card->mix.record_sources)) return -EINVAL;
+-
+- spin_lock_irqsave(&card->lock, flags);
+- card->mix.recmask_io(card,0,val);
+- spin_unlock_irqrestore(&card->lock, flags);
+- return 0;
+-
+- default:
+- i = _IOC_NR(cmd);
+-
+- if ( ! supported_mixer(card,i))
+- return -EINVAL;
+-
+- spin_lock_irqsave(&card->lock, flags);
+- set_mixer(card,i,val);
+- spin_unlock_irqrestore(&card->lock, flags);
+-
+- return 0;
+- }
+-}
+-
+-/* --------------------------------------------------------------------- */
+-static int ess_open_mixdev(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct ess_card *card = NULL;
+- struct pci_dev *pdev = NULL;
+- struct pci_driver *drvr;
+-
+- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+- drvr = pci_dev_driver (pdev);
+- if (drvr == &maestro_pci_driver) {
+- card = (struct ess_card*)pci_get_drvdata (pdev);
+- if (!card)
+- continue;
+- if (card->dev_mixer == minor)
+- break;
+- }
+- }
+- if (!card)
+- return -ENODEV;
+- file->private_data = card;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int ess_release_mixdev(struct inode *inode, struct file *file)
+-{
+- struct ess_card *card = (struct ess_card *)file->private_data;
+-
+- VALIDATE_CARD(card);
+-
+- return 0;
+-}
+-
+-static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct ess_card *card = (struct ess_card *)file->private_data;
+-
+- VALIDATE_CARD(card);
+-
+- return mixer_ioctl(card, cmd, arg);
+-}
+-
+-static /*const*/ struct file_operations ess_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = ess_ioctl_mixdev,
+- .open = ess_open_mixdev,
+- .release = ess_release_mixdev,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct ess_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait,current);
+- unsigned long flags;
+- int count;
+- signed long tmo;
+-
+- if (s->dma_dac.mapped || !s->dma_dac.ready)
+- return 0;
+- current->state = TASK_INTERRUPTIBLE;
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- for (;;) {
+- /* XXX uhm.. questionable locking*/
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- current->state = TASK_RUNNING;
+- return -EBUSY;
+- }
+- tmo = (count * HZ) / s->ratedac;
+- tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
+- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
+- or something. who cares. - zach */
+- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
+- M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies);
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- current->state = TASK_RUNNING;
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-/* Zach sez: "god this is gross.." */
+-static int
+-comb_stereo(unsigned char *real_buffer,unsigned char *tmp_buffer, int offset,
+- int count, int bufsize)
+-{
+- /* No such thing as stereo recording, so we
+- use dual input mixers. which means we have to
+- combine mono to stereo buffer. yuck.
+-
+- but we don't have to be able to work a byte at a time..*/
+-
+- unsigned char *so,*left,*right;
+- int i;
+-
+- so = tmp_buffer;
+- left = real_buffer + offset;
+- right = real_buffer + bufsize/2 + offset;
+-
+-/* M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/
+-
+- for(i=count/4; i ; i--) {
+- (*(so+2)) = *(right++);
+- (*(so+3)) = *(right++);
+- (*so) = *(left++);
+- (*(so+1)) = *(left++);
+- so+=4;
+- }
+-
+- return 0;
+-}
+-
+-/* in this loop, dma_adc.count signifies the amount of data thats waiting
+- to be copied to the user's buffer. it is filled by the interrupt
+- handler and drained by this loop. */
+-static ssize_t
+-ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct ess_state *s = (struct ess_state *)file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+- unsigned char *combbuf = NULL;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- if(!(combbuf = kmalloc(count,GFP_KERNEL)))
+- return -ENOMEM;
+- ret = 0;
+-
+- calc_bob_rate(s);
+-
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- /* remember, all these things are expressed in bytes to be
+- sent to the user.. hence the evil / 2 down below */
+- swptr = s->dma_adc.swptr;
+- cnt = s->dma_adc.dmasize-swptr;
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- if (cnt > count)
+- cnt = count;
+-
+- if ( cnt > 0 ) cnt &= ~3;
+-
+- if (cnt <= 0) {
+- start_adc(s);
+- if (file->f_flags & O_NONBLOCK)
+- {
+- ret = ret ? ret : -EAGAIN;
+- goto rec_return_free;
+- }
+- if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
+- if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+- s->dma_adc.hwptr, s->dma_adc.swptr);
+- stop_adc(s);
+- spin_lock_irqsave(&s->lock, flags);
+- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
+- /* program enhanced mode registers */
+- /* FILL ME */
+-/* wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
+- wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */
+- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (signal_pending(current))
+- {
+- ret = ret ? ret : -ERESTARTSYS;
+- goto rec_return_free;
+- }
+- continue;
+- }
+-
+- if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
+- /* swptr/2 so that we know the real offset in each apu's buffer */
+- comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize);
+- if (copy_to_user(buffer, combbuf, cnt)) {
+- ret = ret ? ret : -EFAULT;
+- goto rec_return_free;
+- }
+- } else {
+- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+- ret = ret ? ret : -EFAULT;
+- goto rec_return_free;
+- }
+- }
+-
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- start_adc(s);
+- }
+-
+-rec_return_free:
+- kfree(combbuf);
+- return ret;
+-}
+-
+-static ssize_t
+-ess_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct ess_state *s = (struct ess_state *)file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac.mapped)
+- return -ENXIO;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- calc_bob_rate(s);
+-
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+-
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = s->dma_dac.hwptr;
+- }
+- swptr = s->dma_dac.swptr;
+-
+- cnt = s->dma_dac.dmasize-swptr;
+-
+- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+-
+- spin_unlock_irqrestore(&s->lock, flags);
+-
+- if (cnt > count)
+- cnt = count;
+-
+- if (cnt <= 0) {
+- start_dac(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if(!ret) ret = -EAGAIN;
+- goto return_free;
+- }
+- if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
+- if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+- s->dma_dac.hwptr, s->dma_dac.swptr);
+- stop_dac(s);
+- spin_lock_irqsave(&s->lock, flags);
+- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
+- /* program enhanced mode registers */
+-/* wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
+- wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */
+- /* FILL ME */
+- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (signal_pending(current)) {
+- if (!ret) ret = -ERESTARTSYS;
+- goto return_free;
+- }
+- continue;
+- }
+- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+- if (!ret) ret = -EFAULT;
+- goto return_free;
+- }
+-/* printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/
+-
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac.swptr = swptr;
+- s->dma_dac.count += cnt;
+- s->dma_dac.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- start_dac(s);
+- }
+-return_free:
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct ess_state *s = (struct ess_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+-
+-/* In 0.14 prog_dmabuf always returns success anyway ... */
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
+- return 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
+- return 0;
+- }
+-
+- if (file->f_mode & FMODE_WRITE)
+- poll_wait(file, &s->dma_dac.wait, wait);
+- if (file->f_mode & FMODE_READ)
+- poll_wait(file, &s->dma_adc.wait, wait);
+- spin_lock_irqsave(&s->lock, flags);
+- ess_update_ptr(s);
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int ess_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct ess_state *s = (struct ess_state *)file->private_data;
+- struct dmabuf *db;
+- int ret = -EINVAL;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf(s, 1)) != 0)
+- goto out;
+- db = &s->dma_dac;
+- } else
+-#if 0
+- /* if we can have the wp/wc do the combining
+- we can turn this back on. */
+- if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf(s, 0)) != 0)
+- goto out;
+- db = &s->dma_adc;
+- } else
+-#endif
+- goto out;
+- ret = -EINVAL;
+- if (vma->vm_pgoff != 0)
+- goto out;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder))
+- goto out;
+- ret = -EAGAIN;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+- db->mapped = 1;
+- ret = 0;
+-out:
+- unlock_kernel();
+- return ret;
+-}
+-
+-static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct ess_state *s = (struct ess_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int val, mapped, ret;
+- unsigned char fmtm, fmtd;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+-/* printk("maestro: ess_ioctl: cmd %d\n", cmd);*/
+-
+- VALIDATE_STATE(s);
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, file->f_flags & O_NONBLOCK);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- /* XXX fix */
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->card->pcidev->irq);
+- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->card->pcidev->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- set_adc_rate(s, val);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- set_dac_rate(s, val);
+- }
+- }
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val)
+- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val)
+- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 0) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val >= 2)
+- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val >= 2)
+- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
+- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_U8|AFMT_S16_LE, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- /* fixed at 16bit for now */
+- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+-#if 0
+- if (val == AFMT_S16_LE)
+- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
+-#endif
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val == AFMT_S16_LE)
+- fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
+- (ESS_FMT_16BIT << ESS_ADC_SHIFT)
+- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
+- AFMT_S16_LE :
+- AFMT_U8,
+- p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
+- val |= PCM_ENABLE_INPUT;
+- if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- start_adc(s);
+- } else
+- stop_adc(s);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- start_dac(s);
+- } else
+- stop_dac(s);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- spin_lock_irqsave(&s->lock, flags);
+- ess_update_ptr(s);
+- abinfo.fragsize = s->dma_dac.fragsize;
+- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- spin_lock_irqsave(&s->lock, flags);
+- ess_update_ptr(s);
+- abinfo.fragsize = s->dma_adc.fragsize;
+- abinfo.bytes = s->dma_adc.count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- spin_lock_irqsave(&s->lock, flags);
+- ess_update_ptr(s);
+- val = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- spin_lock_irqsave(&s->lock, flags);
+- ess_update_ptr(s);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- spin_lock_irqsave(&s->lock, flags);
+- ess_update_ptr(s);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+- cinfo.ptr = s->dma_dac.hwptr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf(s, 0)))
+- return val;
+- return put_user(s->dma_dac.fragsize, p);
+- }
+- if ((val = prog_dmabuf(s, 1)))
+- return val;
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- M_printk("maestro: SETFRAGMENT: %0x\n",val);
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE)
+- s->dma_dac.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
+- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
+- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+- return -EINVAL;
+-}
+-
+-static void
+-set_base_registers(struct ess_state *s,void *vaddr)
+-{
+- unsigned long packed_phys = virt_to_bus(vaddr)>>12;
+- wave_set_register(s, 0x01FC , packed_phys);
+- wave_set_register(s, 0x01FD , packed_phys);
+- wave_set_register(s, 0x01FE , packed_phys);
+- wave_set_register(s, 0x01FF , packed_phys);
+-}
+-
+-/*
+- * this guy makes sure we're in the right power
+- * state for what we want to be doing
+- */
+-static void maestro_power(struct ess_card *card, int tostate)
+-{
+- u16 active_mask = acpi_state_mask[tostate];
+- u8 state;
+-
+- if(!use_pm) return;
+-
+- pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state);
+- state&=3;
+-
+- /* make sure we're in the right state */
+- if(state != tostate) {
+- M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n",
+- card->pcidev->bus->number,
+- PCI_SLOT(card->pcidev->devfn),
+- PCI_FUNC(card->pcidev->devfn),
+- state,tostate);
+- pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate);
+- }
+-
+- /* and make sure the units we care about are on
+- XXX we might want to do this before state flipping? */
+- pci_write_config_word(card->pcidev, 0x54, ~ active_mask);
+- pci_write_config_word(card->pcidev, 0x56, ~ active_mask);
+-}
+-
+-/* we allocate a large power of two for all our memory.
+- this is cut up into (not to scale :):
+- |silly fifo word | 512byte mixbuf per adc | dac/adc * channels |
+-*/
+-static int
+-allocate_buffers(struct ess_state *s)
+-{
+- void *rawbuf=NULL;
+- int order,i;
+- struct page *page, *pend;
+-
+- /* alloc as big a chunk as we can */
+- for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
+- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+- break;
+-
+- if (!rawbuf)
+- return 1;
+-
+- M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<<order,order, rawbuf);
+-
+- if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~((1<<28)-1)) {
+- printk(KERN_ERR "maestro: DMA buffer beyond 256MB! busaddr 0x%lx size %ld\n",
+- virt_to_bus(rawbuf), PAGE_SIZE << order);
+- kfree(rawbuf);
+- return 1;
+- }
+-
+- s->card->dmapages = rawbuf;
+- s->card->dmaorder = order;
+-
+- for(i=0;i<NR_DSPS;i++) {
+- struct ess_state *ess = &s->card->channels[i];
+-
+- if(ess->dev_audio == -1)
+- continue;
+-
+- ess->dma_dac.ready = s->dma_dac.mapped = 0;
+- ess->dma_adc.ready = s->dma_adc.mapped = 0;
+- ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1;
+-
+- /* offset dac and adc buffers starting half way through and then at each [da][ad]c's
+- order's intervals.. */
+- ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 )));
+- ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder);
+- /* offset mixbuf by a mixbuf so that the lame status fifo can
+- happily scribble away.. */
+- ess->mixbuf = rawbuf + (512 * (i+1));
+-
+- M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf,
+- ess->dma_adc.rawbuf, ess->mixbuf);
+-
+- }
+-
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
+- for (page = virt_to_page(rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+-
+- return 0;
+-}
+-static void
+-free_buffers(struct ess_state *s)
+-{
+- struct page *page, *pend;
+-
+- s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL;
+- s->dma_dac.mapped = s->dma_adc.mapped = 0;
+- s->dma_dac.ready = s->dma_adc.ready = 0;
+-
+- M_printk("maestro: freeing %p\n",s->card->dmapages);
+- /* undo marking the pages as reserved */
+-
+- pend = virt_to_page(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1);
+- for (page = virt_to_page(s->card->dmapages); page <= pend; page++)
+- ClearPageReserved(page);
+-
+- free_pages((unsigned long)s->card->dmapages,s->card->dmaorder);
+- s->card->dmapages = NULL;
+-}
+-
+-static int
+-ess_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct ess_state *s = NULL;
+- unsigned char fmtm = ~0, fmts = 0;
+- struct pci_dev *pdev = NULL;
+- /*
+- * Scan the cards and find the channel. We only
+- * do this at open time so it is ok
+- */
+-
+- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+- struct ess_card *c;
+- struct pci_driver *drvr;
+-
+- drvr = pci_dev_driver (pdev);
+- if (drvr == &maestro_pci_driver) {
+- int i;
+- struct ess_state *sp;
+-
+- c = (struct ess_card*)pci_get_drvdata (pdev);
+- if (!c)
+- continue;
+- for(i=0;i<NR_DSPS;i++)
+- {
+- sp=&c->channels[i];
+- if(sp->dev_audio < 0)
+- continue;
+- if((sp->dev_audio ^ minor) & ~0xf)
+- continue;
+- s=sp;
+- }
+- }
+- }
+- if (!s)
+- return -ENODEV;
+-
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EWOULDBLOCK;
+- }
+- mutex_unlock(&s->open_mutex);
+- interruptible_sleep_on(&s->open_wait);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+-
+- /* under semaphore.. */
+- if ((s->card->dmapages==NULL) && allocate_buffers(s)) {
+- mutex_unlock(&s->open_mutex);
+- return -ENOMEM;
+- }
+-
+- /* we're covered by the open_mutex */
+- if( ! s->card->dsps_open ) {
+- maestro_power(s->card,ACPI_D0);
+- start_bob(s);
+- }
+- s->card->dsps_open++;
+- M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
+-
+- /* ok, lets write WC base regs now that we've
+- powered up the chip */
+- M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages),
+- ((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12);
+- set_base_registers(s,s->card->dmapages);
+-
+- if (file->f_mode & FMODE_READ) {
+-/*
+- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */
+-
+- fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+- fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT;
+-
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+- set_adc_rate(s, 8000);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+-
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+- set_dac_rate(s, 8000);
+- }
+- set_fmt(s, fmtm, fmts);
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+-
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int
+-ess_release(struct inode *inode, struct file *file)
+-{
+- struct ess_state *s = (struct ess_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- }
+-
+- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+- /* we're covered by the open_mutex */
+- M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
+- if( --s->card->dsps_open <= 0) {
+- s->card->dsps_open = 0;
+- stop_bob(s);
+- free_buffers(s);
+- maestro_power(s->card,ACPI_D2);
+- }
+- mutex_unlock(&s->open_mutex);
+- wake_up(&s->open_wait);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static struct file_operations ess_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = ess_read,
+- .write = ess_write,
+- .poll = ess_poll,
+- .ioctl = ess_ioctl,
+- .mmap = ess_mmap,
+- .open = ess_open,
+- .release = ess_release,
+-};
+-
+-static int
+-maestro_config(struct ess_card *card)
+-{
+- struct pci_dev *pcidev = card->pcidev;
+- struct ess_state *ess = &card->channels[0];
+- int apu,iobase = card->iobase;
+- u16 w;
+- u32 n;
+-
+- /* We used to muck around with pci config space that
+- * we had no business messing with. We don't know enough
+- * about the machine to know which DMA mode is appropriate,
+- * etc. We were guessing wrong on some machines and making
+- * them unhappy. We now trust in the BIOS to do things right,
+- * which almost certainly means a new host of problems will
+- * arise with broken BIOS implementations. screw 'em.
+- * We're already intolerant of machines that don't assign
+- * IRQs.
+- */
+-
+- /* do config work at full power */
+- maestro_power(card,ACPI_D0);
+-
+- pci_read_config_word(pcidev, 0x50, &w);
+-
+- w&=~(1<<5); /* Don't swap left/right (undoc)*/
+-
+- pci_write_config_word(pcidev, 0x50, w);
+-
+- pci_read_config_word(pcidev, 0x52, &w);
+- w&=~(1<<15); /* Turn off internal clock multiplier */
+- /* XXX how do we know which to use? */
+- w&=~(1<<14); /* External clock */
+-
+- w|= (1<<7); /* Hardware volume control on */
+- w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */
+- w&=~(1<<5); /* GPIO 4:5 */
+- w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */
+- w&=~(1<<2); /* MIDI fix off (undoc) */
+- w&=~(1<<1); /* reserved, always write 0 */
+- pci_write_config_word(pcidev, 0x52, w);
+-
+- /*
+- * Legacy mode
+- */
+-
+- pci_read_config_word(pcidev, 0x40, &w);
+- w|=(1<<15); /* legacy decode off */
+- w&=~(1<<14); /* Disable SIRQ */
+- w&=~(0x1f); /* disable mpu irq/io, game port, fm, SB */
+-
+- pci_write_config_word(pcidev, 0x40, w);
+-
+- /* Set up 978 docking control chip. */
+- pci_read_config_word(pcidev, 0x58, &w);
+- w|=1<<2; /* Enable 978. */
+- w|=1<<3; /* Turn on 978 hardware volume control. */
+- w&=~(1<<11); /* Turn on 978 mixer volume control. */
+- pci_write_config_word(pcidev, 0x58, w);
+-
+- sound_reset(iobase);
+-
+- /*
+- * Ring Bus Setup
+- */
+-
+- /* setup usual 0x34 stuff.. 0x36 may be chip specific */
+- outw(0xC090, iobase+0x34); /* direct sound, stereo */
+- udelay(20);
+- outw(0x3000, iobase+0x36); /* direct sound, stereo */
+- udelay(20);
+-
+-
+- /*
+- * Reset the CODEC
+- */
+-
+- maestro_ac97_reset(iobase,pcidev);
+-
+- /*
+- * Ring Bus Setup
+- */
+-
+- n=inl(iobase+0x34);
+- n&=~0xF000;
+- n|=12<<12; /* Direct Sound, Stereo */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n&=~0x0F00; /* Modem off */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n&=~0x00F0;
+- n|=9<<4; /* DAC, Stereo */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n&=~0x000F; /* ASSP off */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n|=(1<<29); /* Enable ring bus */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n|=(1<<28); /* Enable serial bus */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n&=~0x00F00000; /* MIC off */
+- outl(n, iobase+0x34);
+-
+- n=inl(iobase+0x34);
+- n&=~0x000F0000; /* I2S off */
+- outl(n, iobase+0x34);
+-
+-
+- w=inw(iobase+0x18);
+- w&=~(1<<7); /* ClkRun off */
+- outw(w, iobase+0x18);
+-
+- w=inw(iobase+0x18);
+- w&=~(1<<6); /* Hardware volume control interrupt off... for now. */
+- outw(w, iobase+0x18);
+-
+- w=inw(iobase+0x18);
+- w&=~(1<<4); /* ASSP irq off */
+- outw(w, iobase+0x18);
+-
+- w=inw(iobase+0x18);
+- w&=~(1<<3); /* ISDN irq off */
+- outw(w, iobase+0x18);
+-
+- w=inw(iobase+0x18);
+- w|=(1<<2); /* Direct Sound IRQ on */
+- outw(w, iobase+0x18);
+-
+- w=inw(iobase+0x18);
+- w&=~(1<<1); /* MPU401 IRQ off */
+- outw(w, iobase+0x18);
+-
+- w=inw(iobase+0x18);
+- w|=(1<<0); /* SB IRQ on */
+- outw(w, iobase+0x18);
+-
+- /* Set hardware volume control registers to midpoints.
+- We can tell which button was pushed based on how they change. */
+- outb(0x88, iobase+0x1c);
+- outb(0x88, iobase+0x1d);
+- outb(0x88, iobase+0x1e);
+- outb(0x88, iobase+0x1f);
+-
+- /* it appears some maestros (dell 7500) only work if these are set,
+- regardless of whether we use the assp or not. */
+-
+- outb(0, iobase+0xA4);
+- outb(3, iobase+0xA2);
+- outb(0, iobase+0xA6);
+-
+- for(apu=0;apu<16;apu++)
+- {
+- /* Write 0 into the buffer area 0x1E0->1EF */
+- outw(0x01E0+apu, 0x10+iobase);
+- outw(0x0000, 0x12+iobase);
+-
+- /*
+- * The 1.10 test program seem to write 0 into the buffer area
+- * 0x1D0-0x1DF too.
+- */
+- outw(0x01D0+apu, 0x10+iobase);
+- outw(0x0000, 0x12+iobase);
+- }
+-
+-#if 1
+- wave_set_register(ess, IDR7_WAVE_ROMRAM,
+- (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00));
+- wave_set_register(ess, IDR7_WAVE_ROMRAM,
+- wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100);
+- wave_set_register(ess, IDR7_WAVE_ROMRAM,
+- wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200);
+- wave_set_register(ess, IDR7_WAVE_ROMRAM,
+- wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400);
+-#else
+- maestro_write(ess, IDR7_WAVE_ROMRAM,
+- (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00));
+- maestro_write(ess, IDR7_WAVE_ROMRAM,
+- maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100);
+- maestro_write(ess, IDR7_WAVE_ROMRAM,
+- maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200);
+- maestro_write(ess, IDR7_WAVE_ROMRAM,
+- maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400);
+-#endif
+-
+- maestro_write(ess, IDR2_CRAM_DATA, 0x0000);
+- maestro_write(ess, 0x08, 0xB004);
+- /* Now back to the DirectSound stuff */
+- maestro_write(ess, 0x09, 0x001B);
+- maestro_write(ess, 0x0A, 0x8000);
+- maestro_write(ess, 0x0B, 0x3F37);
+- maestro_write(ess, 0x0C, 0x0098);
+-
+- /* parallel out ?? */
+- maestro_write(ess, 0x0C,
+- (maestro_read(ess, 0x0C)&~0xF000)|0x8000);
+- /* parallel in, has something to do with recording :) */
+- maestro_write(ess, 0x0C,
+- (maestro_read(ess, 0x0C)&~0x0F00)|0x0500);
+-
+- maestro_write(ess, 0x0D, 0x7632);
+-
+- /* Wave cache control on - test off, sg off,
+- enable, enable extra chans 1Mb */
+-
+- outw(inw(0x14+iobase)|(1<<8),0x14+iobase);
+- outw(inw(0x14+iobase)&0xFE03,0x14+iobase);
+- outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase);
+- outw(inw(0x14+iobase)|(1<<7),0x14+iobase);
+-
+- outw(0xA1A0, 0x14+iobase); /* 0300 ? */
+-
+- /* Now clear the APU control ram */
+- for(apu=0;apu<NR_APUS;apu++)
+- {
+- for(w=0;w<NR_APU_REGS;w++)
+- apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0);
+-
+- }
+-
+- return 0;
+-
+-}
+-
+-/* this guy tries to find the pci power management
+- * register bank. this should really be in core
+- * code somewhere. 1 on success. */
+-static int
+-parse_power(struct ess_card *card, struct pci_dev *pcidev)
+-{
+- u32 n;
+- u16 w;
+- u8 next;
+- int max = 64; /* an a 8bit guy pointing to 32bit guys
+- can only express so much. */
+-
+- card->power_regs = 0;
+-
+- /* check to see if we have a capabilities list in
+- the config register */
+- pci_read_config_word(pcidev, PCI_STATUS, &w);
+- if(!(w & PCI_STATUS_CAP_LIST)) return 0;
+-
+- /* walk the list, starting at the head. */
+- pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
+-
+- while(next && max--) {
+- pci_read_config_dword(pcidev, next & ~3, &n);
+- if((n & 0xff) == PCI_CAP_ID_PM) {
+- card->power_regs = next;
+- break;
+- }
+- next = ((n>>8) & 0xff);
+- }
+-
+- return card->power_regs ? 1 : 0;
+-}
+-
+-static int __init
+-maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid)
+-{
+- int card_type = pdid->driver_data;
+- u32 n;
+- int iobase;
+- int i, ret;
+- struct ess_card *card;
+- struct ess_state *ess;
+- int num = 0;
+-
+-/* when built into the kernel, we only print version if device is found */
+-#ifndef MODULE
+- static int printed_version;
+- if (!printed_version++)
+- printk(version);
+-#endif
+-
+- /* don't pick up weird modem maestros */
+- if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
+- return -ENODEV;
+-
+-
+- if ((ret=pci_enable_device(pcidev)))
+- return ret;
+-
+- iobase = pci_resource_start(pcidev,0);
+- if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO))
+- return -ENODEV;
+-
+- if(pcidev->irq == 0)
+- return -ENODEV;
+-
+- /* stake our claim on the iospace */
+- if( request_region(iobase, 256, card_names[card_type]) == NULL )
+- {
+- printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
+- return -EBUSY;
+- }
+-
+- /* just to be sure */
+- pci_set_master(pcidev);
+-
+- card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
+- if(card == NULL)
+- {
+- printk(KERN_WARNING "maestro: out of memory\n");
+- release_region(iobase, 256);
+- return -ENOMEM;
+- }
+-
+- memset(card, 0, sizeof(*card));
+- card->pcidev = pcidev;
+-
+- card->iobase = iobase;
+- card->card_type = card_type;
+- card->irq = pcidev->irq;
+- card->magic = ESS_CARD_MAGIC;
+- spin_lock_init(&card->lock);
+- init_waitqueue_head(&card->suspend_queue);
+-
+- card->dock_mute_vol = 50;
+-
+- /* init our groups of 6 apus */
+- for(i=0;i<NR_DSPS;i++)
+- {
+- struct ess_state *s=&card->channels[i];
+-
+- s->index = i;
+-
+- s->card = card;
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- spin_lock_init(&s->lock);
+- mutex_init(&s->open_mutex);
+- s->magic = ESS_STATE_MAGIC;
+-
+- s->apu[0] = 6*i;
+- s->apu[1] = (6*i)+1;
+- s->apu[2] = (6*i)+2;
+- s->apu[3] = (6*i)+3;
+- s->apu[4] = (6*i)+4;
+- s->apu[5] = (6*i)+5;
+-
+- if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
+- printk("maestro: BOTCH!\n");
+- /* register devices */
+- if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
+- break;
+- }
+-
+- num = i;
+-
+- /* clear the rest if we ran out of slots to register */
+- for(;i<NR_DSPS;i++)
+- {
+- struct ess_state *s=&card->channels[i];
+- s->dev_audio = -1;
+- }
+-
+- ess = &card->channels[0];
+-
+- /*
+- * Ok card ready. Begin setup proper
+- */
+-
+- printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n",
+- card_names[card_type],iobase,card->irq);
+- pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
+- printk(KERN_INFO "maestro: subvendor id: 0x%08x\n",n);
+-
+- /* turn off power management unless:
+- * - the user explicitly asks for it
+- * or
+- * - we're not a 2e, lesser chipps seem to have problems.
+- * - we're not on our _very_ small whitelist. some implemenetations
+- * really don't like the pm code, others require it.
+- * feel free to expand this as required.
+- */
+-#define SUBSYSTEM_VENDOR(x) (x&0xffff)
+- if( (use_pm != 1) &&
+- ((card_type != TYPE_MAESTRO2E) || (SUBSYSTEM_VENDOR(n) != 0x1028)))
+- use_pm = 0;
+-
+- if(!use_pm)
+- printk(KERN_INFO "maestro: not attempting power management.\n");
+- else {
+- if(!parse_power(card,pcidev))
+- printk(KERN_INFO "maestro: no PCI power management interface found.\n");
+- else {
+- pci_read_config_dword(pcidev, card->power_regs, &n);
+- printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16);
+- }
+- }
+-
+- maestro_config(card);
+-
+- if(maestro_ac97_get(card, 0x00)==0x0080) {
+- printk(KERN_ERR "maestro: my goodness! you seem to have a pt101 codec, which is quite rare.\n"
+- "\tyou should tell someone about this.\n");
+- } else {
+- maestro_ac97_init(card);
+- }
+-
+- if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) {
+- printk("maestro: couldn't register mixer!\n");
+- } else {
+- memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state));
+- mixer_push_state(card);
+- }
+-
+- if((ret=request_irq(card->irq, ess_interrupt, IRQF_SHARED, card_names[card_type], card)))
+- {
+- printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
+- unregister_sound_mixer(card->dev_mixer);
+- for(i=0;i<NR_DSPS;i++)
+- {
+- struct ess_state *s = &card->channels[i];
+- if(s->dev_audio != -1)
+- unregister_sound_dsp(s->dev_audio);
+- }
+- release_region(card->iobase, 256);
+- unregister_reboot_notifier(&maestro_nb);
+- kfree(card);
+- return ret;
+- }
+-
+- /* Turn on hardware volume control interrupt.
+- This has to come after we grab the IRQ above,
+- or a crash will result on installation if a button has been pressed,
+- because in that case we'll get an immediate interrupt. */
+- n = inw(iobase+0x18);
+- n|=(1<<6);
+- outw(n, iobase+0x18);
+-
+- pci_set_drvdata(pcidev,card);
+- /* now go to sleep 'till something interesting happens */
+- maestro_power(card,ACPI_D2);
+-
+- printk(KERN_INFO "maestro: %d channels configured.\n", num);
+- return 0;
+-}
+-
+-static void maestro_remove(struct pci_dev *pcidev) {
+- struct ess_card *card = pci_get_drvdata(pcidev);
+- int i;
+- u32 n;
+-
+- /* XXX maybe should force stop bob, but should be all
+- stopped by _release by now */
+-
+- /* Turn off hardware volume control interrupt.
+- This has to come before we leave the IRQ below,
+- or a crash results if a button is pressed ! */
+- n = inw(card->iobase+0x18);
+- n&=~(1<<6);
+- outw(n, card->iobase+0x18);
+-
+- free_irq(card->irq, card);
+- unregister_sound_mixer(card->dev_mixer);
+- for(i=0;i<NR_DSPS;i++)
+- {
+- struct ess_state *ess = &card->channels[i];
+- if(ess->dev_audio != -1)
+- unregister_sound_dsp(ess->dev_audio);
+- }
+- /* Goodbye, Mr. Bond. */
+- maestro_power(card,ACPI_D3);
+- release_region(card->iobase, 256);
+- kfree(card);
+- pci_set_drvdata(pcidev,NULL);
+-}
+-
+-static struct pci_device_id maestro_pci_tbl[] = {
+- {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2},
+- {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E},
+- {PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO},
+- {0,}
+-};
+-MODULE_DEVICE_TABLE(pci, maestro_pci_tbl);
+-
+-static struct pci_driver maestro_pci_driver = {
+- .name = "maestro",
+- .id_table = maestro_pci_tbl,
+- .probe = maestro_probe,
+- .remove = maestro_remove,
+-};
+-
+-static int __init init_maestro(void)
+-{
+- int rc;
+-
+- rc = pci_register_driver(&maestro_pci_driver);
+- if (rc < 0)
+- return rc;
+-
+- if (register_reboot_notifier(&maestro_nb))
+- printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
+-#ifdef MODULE
+- printk(version);
+-#endif
+- if (dsps_order < 0) {
+- dsps_order = 1;
+- printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
+- }
+- else if (dsps_order > MAX_DSP_ORDER) {
+- dsps_order = MAX_DSP_ORDER;
+- printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
+- }
+- return 0;
+-}
+-
+-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+-{
+- /* this notifier is called when the kernel is really shut down. */
+- M_printk("maestro: shutting down\n");
+- /* this will remove all card instances too */
+- pci_unregister_driver(&maestro_pci_driver);
+- /* XXX dunno about power management */
+- return NOTIFY_OK;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-static void cleanup_maestro(void) {
+- M_printk("maestro: unloading\n");
+- pci_unregister_driver(&maestro_pci_driver);
+- unregister_reboot_notifier(&maestro_nb);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-void
+-check_suspend(struct ess_card *card)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+-
+- if(!card->in_suspend) return;
+-
+- card->in_suspend++;
+- add_wait_queue(&(card->suspend_queue), &wait);
+- current->state = TASK_UNINTERRUPTIBLE;
+- schedule();
+- remove_wait_queue(&(card->suspend_queue), &wait);
+- current->state = TASK_RUNNING;
+-}
+-
+-module_init(init_maestro);
+-module_exit(cleanup_maestro);
+diff --git a/sound/oss/maestro.h b/sound/oss/maestro.h
+deleted file mode 100644
+index 023ec7f..0000000
+--- a/sound/oss/maestro.h
++++ /dev/null
+@@ -1,60 +0,0 @@
+-/*
+- * Registers for the ESS PCI cards
+- */
+-
+-/*
+- * Memory access
+- */
+-
+-#define ESS_MEM_DATA 0x00
+-#define ESS_MEM_INDEX 0x02
+-
+-/*
+- * AC-97 Codec port. Delay 1uS after each write. This is used to
+- * talk AC-97 (see intel.com). Write data then register.
+- */
+-
+-#define ESS_AC97_INDEX 0x30 /* byte wide */
+-#define ESS_AC97_DATA 0x32
+-
+-/*
+- * Reading is a bit different. You write register|0x80 to ubdex
+- * delay 1uS poll the low bit of index, when it clears read the
+- * data value.
+- */
+-
+-/*
+- * Control port. Not yet fully understood
+- * The value 0xC090 gets loaded to it then 0x0000 and 0x2800
+- * to the data port. Then after 4uS the value 0x300 is written
+- */
+-
+-#define RING_BUS_CTRL_L 0x34
+-#define RING_BUS_CTRL_H 0x36
+-
+-/*
+- * This is also used during setup. The value 0x17 is written to it
+- */
+-
+-#define ESS_SETUP_18 0x18
+-
+-/*
+- * And this one gets 0x000b
+- */
+-
+-#define ESS_SETUP_A2 0xA2
+-
+-/*
+- * And this 0x0000
+- */
+-
+-#define ESS_SETUP_A4 0xA4
+-#define ESS_SETUP_A6 0xA6
+-
+-/*
+- * Stuff to do with Harpo - the wave stuff
+- */
+-
+-#define ESS_WAVETABLE_SIZE 0x14
+-#define ESS_WAVETABLE_2M 0xA180
+-
+diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c
+deleted file mode 100644
+index 5548e3c..0000000
+--- a/sound/oss/maestro3.c
++++ /dev/null
+@@ -1,2969 +0,0 @@
+-/*****************************************************************************
+- *
+- * ESS Maestro3/Allegro driver for Linux 2.4.x
+- *
+- * 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.
+- *
+- * (c) Copyright 2000 Zach Brown <zab at zabbo.net>
+- *
+- * I need to thank many people for helping make this driver happen.
+- * As always, Eric Brombaugh was a hacking machine and killed many bugs
+- * that I was too dumb to notice. Howard Kim at ESS provided reference boards
+- * and as much docs as he could. Todd and Mick at Dell tested snapshots on
+- * an army of laptops. msw and deviant at Red Hat also humoured me by hanging
+- * their laptops every few hours in the name of science.
+- *
+- * Shouts go out to Mike "DJ XPCom" Ang.
+- *
+- * History
+- * v1.23 - Jun 5 2002 - Michael Olson <olson at cs.odu.edu>
+- * added a module option to allow selection of GPIO pin number
+- * for external amp
+- * v1.22 - Feb 28 2001 - Zach Brown <zab at zabbo.net>
+- * allocate mem at insmod/setup, rather than open
+- * limit pci dma addresses to 28bit, thanks guys.
+- * v1.21 - Feb 04 2001 - Zach Brown <zab at zabbo.net>
+- * fix up really dumb notifier -> suspend oops
+- * v1.20 - Jan 30 2001 - Zach Brown <zab at zabbo.net>
+- * get rid of pm callback and use pci_dev suspend/resume instead
+- * m3_probe cleanups, including pm oops think-o
+- * v1.10 - Jan 6 2001 - Zach Brown <zab at zabbo.net>
+- * revert to lame remap_page_range mmap() just to make it work
+- * record mmap fixed.
+- * fix up incredibly broken open/release resource management
+- * duh. fix record format setting.
+- * add SMP locking and cleanup formatting here and there
+- * v1.00 - Dec 16 2000 - Zach Brown <zab at zabbo.net>
+- * port to sexy 2.4 interfaces
+- * properly align instance allocations so recording works
+- * clean up function namespace a little :/
+- * update PCI IDs based on mail from ESS
+- * arbitrarily bump version number to show its 2.4 now,
+- * 2.2 will stay 0., oss_audio port gets 2.
+- * v0.03 - Nov 05 2000 - Zach Brown <zab at zabbo.net>
+- * disable recording but allow dsp to be opened read
+- * pull out most silly compat defines
+- * v0.02 - Nov 04 2000 - Zach Brown <zab at zabbo.net>
+- * changed clocking setup for m3, slowdown fixed.
+- * codec reset is hopefully reliable now
+- * rudimentary apm/power management makes suspend/resume work
+- * v0.01 - Oct 31 2000 - Zach Brown <zab at zabbo.net>
+- * first release
+- * v0.00 - Sep 09 2000 - Zach Brown <zab at zabbo.net>
+- * first pass derivation from maestro.c
+- *
+- * TODO
+- * in/out allocated contiguously so fullduplex mmap will work?
+- * no beep on init (mute)
+- * resetup msrc data memory if freq changes?
+- *
+- * --
+- *
+- * Allow me to ramble a bit about the m3 architecture. The core of the
+- * chip is the 'assp', the custom ESS dsp that runs the show. It has
+- * a small amount of code and data ram. ESS drops binary dsp code images
+- * on our heads, but we don't get to see specs on the dsp.
+- *
+- * The constant piece of code on the dsp is the 'kernel'. It also has a
+- * chunk of the dsp memory that is statically set aside for its control
+- * info. This is the KDATA defines in maestro3.h. Part of its core
+- * data is a list of code addresses that point to the pieces of DSP code
+- * that it should walk through in its loop. These other pieces of code
+- * do the real work. The kernel presumably jumps into each of them in turn.
+- * These code images tend to have their own data area, and one can have
+- * multiple data areas representing different states for each of the 'client
+- * instance' code portions. There is generally a list in the kernel data
+- * that points to the data instances for a given piece of code.
+- *
+- * We've only been given the binary image for the 'minisrc', mini sample
+- * rate converter. This is rather annoying because it limits the work
+- * we can do on the dsp, but it also greatly simplifies the job of managing
+- * dsp data memory for the code and data for our playing streams :). We
+- * statically allocate the minisrc code into a region we 'know' to be free
+- * based on the map of the binary kernel image we're loading. We also
+- * statically allocate the data areas for the maximum number of pcm streams
+- * we can be dealing with. This max is set by the length of the static list
+- * in the kernel data that records the number of minisrc data regions we
+- * can have. Thats right, all software dsp mixing with static code list
+- * limits. Rock.
+- *
+- * How sound goes in and out is still a relative mystery. It appears
+- * that the dsp has the ability to get input and output through various
+- * 'connections'. To do IO from or to a connection, you put the address
+- * of the minisrc client area in the static kernel data lists for that
+- * input or output. so for pcm -> dsp -> mixer, we put the minisrc data
+- * instance in the DMA list and also in the list for the mixer. I guess
+- * it Just Knows which is in/out, and we give some dma control info that
+- * helps. There are all sorts of cool inputs/outputs that it seems we can't
+- * use without dsp code images that know how to use them.
+- *
+- * So at init time we preload all the memory allocation stuff and set some
+- * system wide parameters. When we really get a sound to play we build
+- * up its minisrc header (stream parameters, buffer addresses, input/output
+- * settings). Then we throw its header on the various lists. We also
+- * tickle some KDATA settings that ask the assp to raise clock interrupts
+- * and do some amount of software mixing before handing data to the ac97.
+- *
+- * Sorry for the vague details. Feel free to ask Eric or myself if you
+- * happen to be trying to use this driver elsewhere. Please accept my
+- * apologies for the quality of the OSS support code, its passed through
+- * too many hands now and desperately wants to be rethought.
+- */
+-
+-/*****************************************************************************/
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/ctype.h>
+-#include <linux/ioport.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/vmalloc.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/poll.h>
+-#include <linux/reboot.h>
+-#include <linux/spinlock.h>
+-#include <linux/ac97_codec.h>
+-#include <linux/wait.h>
+-#include <linux/mutex.h>
+-
+-
+-#include <asm/io.h>
+-#include <asm/dma.h>
+-#include <asm/uaccess.h>
+-
+-#include "maestro3.h"
+-
+-#define M_DEBUG 1
+-
+-#define DRIVER_VERSION "1.23"
+-#define M3_MODULE_NAME "maestro3"
+-#define PFX M3_MODULE_NAME ": "
+-
+-#define M3_STATE_MAGIC 0x734d724d
+-#define M3_CARD_MAGIC 0x646e6f50
+-
+-#define ESS_FMT_STEREO 0x01
+-#define ESS_FMT_16BIT 0x02
+-#define ESS_FMT_MASK 0x03
+-#define ESS_DAC_SHIFT 0
+-#define ESS_ADC_SHIFT 4
+-
+-#define DAC_RUNNING 1
+-#define ADC_RUNNING 2
+-
+-#define SND_DEV_DSP16 5
+-
+-#ifdef M_DEBUG
+-static int debug;
+-#define DPMOD 1 /* per module load */
+-#define DPSTR 2 /* per 'stream' */
+-#define DPSYS 3 /* per syscall */
+-#define DPCRAP 4 /* stuff the user shouldn't see unless they're really debuggin */
+-#define DPINT 5 /* per interrupt, LOTS */
+-#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}
+-#else
+-#define DPRINTK(x)
+-#endif
+-
+-struct m3_list {
+- int curlen;
+- u16 mem_addr;
+- int max;
+-};
+-
+-static int external_amp = 1;
+-static int gpio_pin = -1;
+-
+-struct m3_state {
+- unsigned int magic;
+- struct m3_card *card;
+- unsigned char fmt, enable;
+-
+- int index;
+-
+- /* this locks around the oss state in the driver */
+- /* no, this lock is removed - only use card->lock */
+- /* otherwise: against what are you protecting on SMP
+- when irqhandler uses s->lock
+- and m3_assp_read uses card->lock ?
+- */
+- struct mutex open_mutex;
+- wait_queue_head_t open_wait;
+- mode_t open_mode;
+-
+- int dev_audio;
+-
+- struct assp_instance {
+- u16 code, data;
+- } dac_inst, adc_inst;
+-
+- /* should be in dmabuf */
+- unsigned int rateadc, ratedac;
+-
+- struct dmabuf {
+- void *rawbuf;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- unsigned hwptr, swptr;
+- unsigned total_bytes;
+- int count;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize;
+- unsigned fragsamples;
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned endcleared:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- /* new in m3 */
+- int mixer_index, dma_index, msrc_index, adc1_index;
+- int in_lists;
+- /* 2.4.. */
+- dma_addr_t handle;
+-
+- } dma_dac, dma_adc;
+-};
+-
+-struct m3_card {
+- unsigned int magic;
+-
+- struct m3_card *next;
+-
+- struct ac97_codec *ac97;
+- spinlock_t ac97_lock;
+-
+- int card_type;
+-
+-#define NR_DSPS 1
+-#define MAX_DSPS NR_DSPS
+- struct m3_state channels[MAX_DSPS];
+-
+- /* this locks around the physical registers on the card */
+- spinlock_t lock;
+-
+- /* hardware resources */
+- struct pci_dev *pcidev;
+- u32 iobase;
+- u32 irq;
+-
+- int dacs_active;
+-
+- int timer_users;
+-
+- struct m3_list msrc_list,
+- mixer_list,
+- adc1_list,
+- dma_list;
+-
+- /* for storing reset state..*/
+- u8 reset_state;
+-
+- u16 *suspend_mem;
+- int in_suspend;
+- wait_queue_head_t suspend_queue;
+-};
+-
+-/*
+- * an arbitrary volume we set the internal
+- * volume settings to so that the ac97 volume
+- * range is a little less insane. 0x7fff is
+- * max.
+- */
+-#define ARB_VOLUME ( 0x6800 )
+-
+-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+-
+-enum {
+- ESS_ALLEGRO,
+- ESS_MAESTRO3,
+- /*
+- * a maestro3 with 'hardware strapping', only
+- * found inside ESS?
+- */
+- ESS_MAESTRO3HW,
+-};
+-
+-static char *card_names[] = {
+- [ESS_ALLEGRO] = "Allegro",
+- [ESS_MAESTRO3] = "Maestro3(i)",
+- [ESS_MAESTRO3HW] = "Maestro3(i)hw"
+-};
+-
+-#ifndef PCI_VENDOR_ESS
+-#define PCI_VENDOR_ESS 0x125D
+-#endif
+-
+-#define M3_DEVICE(DEV, TYPE) \
+-{ \
+-.vendor = PCI_VENDOR_ESS, \
+-.device = DEV, \
+-.subvendor = PCI_ANY_ID, \
+-.subdevice = PCI_ANY_ID, \
+-.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, \
+-.class_mask = 0xffff << 8, \
+-.driver_data = TYPE, \
+-}
+-
+-static struct pci_device_id m3_id_table[] = {
+- M3_DEVICE(0x1988, ESS_ALLEGRO),
+- M3_DEVICE(0x1998, ESS_MAESTRO3),
+- M3_DEVICE(0x199a, ESS_MAESTRO3HW),
+- {0,}
+-};
+-
+-MODULE_DEVICE_TABLE (pci, m3_id_table);
+-
+-/*
+- * reports seem to indicate that the m3 is limited
+- * to 28bit bus addresses. aaaargggh...
+- */
+-#define M3_PCI_DMA_MASK 0x0fffffff
+-
+-static unsigned
+-ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-static struct m3_card *devs;
+-
+-/*
+- * I'm not very good at laying out functions in a file :)
+- */
+-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
+-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state);
+-static void check_suspend(struct m3_card *card);
+-
+-static struct notifier_block m3_reboot_nb = {
+- .notifier_call = m3_notifier,
+-};
+-
+-static void m3_outw(struct m3_card *card,
+- u16 value, unsigned long reg)
+-{
+- check_suspend(card);
+- outw(value, card->iobase + reg);
+-}
+-
+-static u16 m3_inw(struct m3_card *card, unsigned long reg)
+-{
+- check_suspend(card);
+- return inw(card->iobase + reg);
+-}
+-static void m3_outb(struct m3_card *card,
+- u8 value, unsigned long reg)
+-{
+- check_suspend(card);
+- outb(value, card->iobase + reg);
+-}
+-static u8 m3_inb(struct m3_card *card, unsigned long reg)
+-{
+- check_suspend(card);
+- return inb(card->iobase + reg);
+-}
+-
+-/*
+- * access 16bit words to the code or data regions of the dsp's memory.
+- * index addresses 16bit words.
+- */
+-static u16 __m3_assp_read(struct m3_card *card, u16 region, u16 index)
+-{
+- m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
+- m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
+- return m3_inw(card, DSP_PORT_MEMORY_DATA);
+-}
+-static u16 m3_assp_read(struct m3_card *card, u16 region, u16 index)
+-{
+- unsigned long flags;
+- u16 ret;
+-
+- spin_lock_irqsave(&(card->lock), flags);
+- ret = __m3_assp_read(card, region, index);
+- spin_unlock_irqrestore(&(card->lock), flags);
+-
+- return ret;
+-}
+-
+-static void __m3_assp_write(struct m3_card *card,
+- u16 region, u16 index, u16 data)
+-{
+- m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
+- m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
+- m3_outw(card, data, DSP_PORT_MEMORY_DATA);
+-}
+-static void m3_assp_write(struct m3_card *card,
+- u16 region, u16 index, u16 data)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&(card->lock), flags);
+- __m3_assp_write(card, region, index, data);
+- spin_unlock_irqrestore(&(card->lock), flags);
+-}
+-
+-static void m3_assp_halt(struct m3_card *card)
+-{
+- card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
+- mdelay(10);
+- m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
+-}
+-
+-static void m3_assp_continue(struct m3_card *card)
+-{
+- m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
+-}
+-
+-/*
+- * This makes me sad. the maestro3 has lists
+- * internally that must be packed.. 0 terminates,
+- * apparently, or maybe all unused entries have
+- * to be 0, the lists have static lengths set
+- * by the binary code images.
+- */
+-
+-static int m3_add_list(struct m3_card *card,
+- struct m3_list *list, u16 val)
+-{
+- DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n",
+- val, list, list->curlen);
+-
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- list->mem_addr + list->curlen,
+- val);
+-
+- return list->curlen++;
+-
+-}
+-
+-static void m3_remove_list(struct m3_card *card,
+- struct m3_list *list, int index)
+-{
+- u16 val;
+- int lastindex = list->curlen - 1;
+-
+- DPRINTK(DPSTR, "removing ind %d from list 0x%p\n",
+- index, list);
+-
+- if(index != lastindex) {
+- val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+- list->mem_addr + lastindex);
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- list->mem_addr + index,
+- val);
+- }
+-
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- list->mem_addr + lastindex,
+- 0);
+-
+- list->curlen--;
+-}
+-
+-static void set_fmt(struct m3_state *s, unsigned char mask, unsigned char data)
+-{
+- int tmp;
+-
+- s->fmt = (s->fmt & mask) | data;
+-
+- tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
+-
+- /* write to 'mono' word */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1,
+- (tmp & ESS_FMT_STEREO) ? 0 : 1);
+- /* write to '8bit' word */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2,
+- (tmp & ESS_FMT_16BIT) ? 0 : 1);
+-
+- tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK;
+-
+- /* write to 'mono' word */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1,
+- (tmp & ESS_FMT_STEREO) ? 0 : 1);
+- /* write to '8bit' word */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2,
+- (tmp & ESS_FMT_16BIT) ? 0 : 1);
+-}
+-
+-static void set_dac_rate(struct m3_state *s, unsigned int rate)
+-{
+- u32 freq;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+-
+- s->ratedac = rate;
+-
+- freq = ((rate << 15) + 24000 ) / 48000;
+- if(freq)
+- freq--;
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_FREQUENCY,
+- freq);
+-}
+-
+-static void set_adc_rate(struct m3_state *s, unsigned int rate)
+-{
+- u32 freq;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 8000)
+- rate = 8000;
+-
+- s->rateadc = rate;
+-
+- freq = ((rate << 15) + 24000 ) / 48000;
+- if(freq)
+- freq--;
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_FREQUENCY,
+- freq);
+-}
+-
+-static void inc_timer_users(struct m3_card *card)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&card->lock, flags);
+-
+- card->timer_users++;
+- DPRINTK(DPSYS, "inc timer users now %d\n",
+- card->timer_users);
+- if(card->timer_users != 1)
+- goto out;
+-
+- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_TIMER_COUNT_RELOAD,
+- 240 ) ;
+-
+- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_TIMER_COUNT_CURRENT,
+- 240 ) ;
+-
+- m3_outw(card,
+- m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
+- HOST_INT_CTRL);
+-out:
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-static void dec_timer_users(struct m3_card *card)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&card->lock, flags);
+-
+- card->timer_users--;
+- DPRINTK(DPSYS, "dec timer users now %d\n",
+- card->timer_users);
+- if(card->timer_users > 0 )
+- goto out;
+-
+- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_TIMER_COUNT_RELOAD,
+- 0 ) ;
+-
+- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_TIMER_COUNT_CURRENT,
+- 0 ) ;
+-
+- m3_outw(card, m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
+- HOST_INT_CTRL);
+-out:
+- spin_unlock_irqrestore(&card->lock, flags);
+-}
+-
+-/*
+- * {start,stop}_{adc,dac} should be called
+- * while holding the 'state' lock and they
+- * will try to grab the 'card' lock..
+- */
+-static void stop_adc(struct m3_state *s)
+-{
+- if (! (s->enable & ADC_RUNNING))
+- return;
+-
+- s->enable &= ~ADC_RUNNING;
+- dec_timer_users(s->card);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_INSTANCE_READY, 0);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- KDATA_ADC1_REQUEST, 0);
+-}
+-
+-static void stop_dac(struct m3_state *s)
+-{
+- if (! (s->enable & DAC_RUNNING))
+- return;
+-
+- DPRINTK(DPSYS, "stop_dac()\n");
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_INSTANCE_READY, 0);
+-
+- s->enable &= ~DAC_RUNNING;
+- s->card->dacs_active--;
+- dec_timer_users(s->card);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- KDATA_MIXER_TASK_NUMBER,
+- s->card->dacs_active ) ;
+-}
+-
+-static void start_dac(struct m3_state *s)
+-{
+- if( (!s->dma_dac.mapped && s->dma_dac.count < 1) ||
+- !s->dma_dac.ready ||
+- (s->enable & DAC_RUNNING))
+- return;
+-
+- DPRINTK(DPSYS, "start_dac()\n");
+-
+- s->enable |= DAC_RUNNING;
+- s->card->dacs_active++;
+- inc_timer_users(s->card);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_INSTANCE_READY, 1);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- KDATA_MIXER_TASK_NUMBER,
+- s->card->dacs_active ) ;
+-}
+-
+-static void start_adc(struct m3_state *s)
+-{
+- if ((! s->dma_adc.mapped &&
+- s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+- || !s->dma_adc.ready
+- || (s->enable & ADC_RUNNING) )
+- return;
+-
+- DPRINTK(DPSYS, "start_adc()\n");
+-
+- s->enable |= ADC_RUNNING;
+- inc_timer_users(s->card);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- KDATA_ADC1_REQUEST, 1);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_INSTANCE_READY, 1);
+-}
+-
+-static struct play_vals {
+- u16 addr, val;
+-} pv[] = {
+- {CDATA_LEFT_VOLUME, ARB_VOLUME},
+- {CDATA_RIGHT_VOLUME, ARB_VOLUME},
+- {SRC3_DIRECTION_OFFSET, 0} ,
+- /* +1, +2 are stereo/16 bit */
+- {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
+- {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
+- {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
+- {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
+- {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
+- {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
+- {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
+- {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
+- {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
+- {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
+- {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
+- {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
+- {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
+- {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
+- {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
+- {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
+- {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
+-};
+-
+-
+-/* the mode passed should be already shifted and masked */
+-static void m3_play_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
+-{
+- int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
+- int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
+- int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
+- int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
+- struct dmabuf *db = &s->dma_dac;
+- int i;
+-
+- DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n",
+- mode, rate, buffer, size);
+-
+-#define LO(x) ((x) & 0xffff)
+-#define HI(x) LO((x) >> 16)
+-
+- /* host dma buffer pointers */
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_HOST_SRC_ADDRL,
+- LO(virt_to_bus(buffer)));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_HOST_SRC_ADDRH,
+- HI(virt_to_bus(buffer)));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
+- LO(virt_to_bus(buffer) + size));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
+- HI(virt_to_bus(buffer) + size));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_HOST_SRC_CURRENTL,
+- LO(virt_to_bus(buffer)));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_HOST_SRC_CURRENTH,
+- HI(virt_to_bus(buffer)));
+-#undef LO
+-#undef HI
+-
+- /* dsp buffers */
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_IN_BUF_BEGIN,
+- dsp_in_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1,
+- dsp_in_buffer + (dsp_in_size / 2));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_IN_BUF_HEAD,
+- dsp_in_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_IN_BUF_TAIL,
+- dsp_in_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_OUT_BUF_BEGIN,
+- dsp_out_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1,
+- dsp_out_buffer + (dsp_out_size / 2));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_OUT_BUF_HEAD,
+- dsp_out_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_OUT_BUF_TAIL,
+- dsp_out_buffer);
+-
+- /*
+- * some per client initializers
+- */
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12,
+- s->dac_inst.data + 40 + 8);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19,
+- s->dac_inst.code + MINISRC_COEF_LOC);
+-
+- /* enable or disable low pass filter? */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22,
+- s->ratedac > 45000 ? 0xff : 0 );
+-
+- /* tell it which way dma is going? */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + CDATA_DMA_CONTROL,
+- DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
+-
+- /*
+- * set an armload of static initializers
+- */
+- for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++)
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->dac_inst.data + pv[i].addr, pv[i].val);
+-
+- /*
+- * put us in the lists if we're not already there
+- */
+-
+- if(db->in_lists == 0) {
+-
+- db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
+- s->dac_inst.data >> DP_SHIFT_COUNT);
+-
+- db->dma_index = m3_add_list(s->card, &s->card->dma_list,
+- s->dac_inst.data >> DP_SHIFT_COUNT);
+-
+- db->mixer_index = m3_add_list(s->card, &s->card->mixer_list,
+- s->dac_inst.data >> DP_SHIFT_COUNT);
+-
+- db->in_lists = 1;
+- }
+-
+- set_dac_rate(s,rate);
+- start_dac(s);
+-}
+-
+-/*
+- * Native record driver
+- */
+-static struct rec_vals {
+- u16 addr, val;
+-} rv[] = {
+- {CDATA_LEFT_VOLUME, ARB_VOLUME},
+- {CDATA_RIGHT_VOLUME, ARB_VOLUME},
+- {SRC3_DIRECTION_OFFSET, 1} ,
+- /* +1, +2 are stereo/16 bit */
+- {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
+- {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
+- {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
+- {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
+- {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
+- {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
+- {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
+- {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
+- {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
+- {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
+- {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
+- {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
+- {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
+- {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
+- {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
+- {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
+- {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
+- {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
+- {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
+-};
+-
+-/* again, passed mode is alrady shifted/masked */
+-static void m3_rec_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
+-{
+- int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
+- int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
+- int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
+- int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
+- struct dmabuf *db = &s->dma_adc;
+- int i;
+-
+- DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n",
+- mode, rate, buffer, size);
+-
+-#define LO(x) ((x) & 0xffff)
+-#define HI(x) LO((x) >> 16)
+-
+- /* host dma buffer pointers */
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_HOST_SRC_ADDRL,
+- LO(virt_to_bus(buffer)));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_HOST_SRC_ADDRH,
+- HI(virt_to_bus(buffer)));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
+- LO(virt_to_bus(buffer) + size));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
+- HI(virt_to_bus(buffer) + size));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_HOST_SRC_CURRENTL,
+- LO(virt_to_bus(buffer)));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_HOST_SRC_CURRENTH,
+- HI(virt_to_bus(buffer)));
+-#undef LO
+-#undef HI
+-
+- /* dsp buffers */
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_IN_BUF_BEGIN,
+- dsp_in_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1,
+- dsp_in_buffer + (dsp_in_size / 2));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_IN_BUF_HEAD,
+- dsp_in_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_IN_BUF_TAIL,
+- dsp_in_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_OUT_BUF_BEGIN,
+- dsp_out_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1,
+- dsp_out_buffer + (dsp_out_size / 2));
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_OUT_BUF_HEAD,
+- dsp_out_buffer);
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_OUT_BUF_TAIL,
+- dsp_out_buffer);
+-
+- /*
+- * some per client initializers
+- */
+-
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12,
+- s->adc_inst.data + 40 + 8);
+-
+- /* tell it which way dma is going? */
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + CDATA_DMA_CONTROL,
+- DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT +
+- DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
+-
+- /*
+- * set an armload of static initializers
+- */
+- for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++)
+- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+- s->adc_inst.data + rv[i].addr, rv[i].val);
+-
+- /*
+- * put us in the lists if we're not already there
+- */
+-
+- if(db->in_lists == 0) {
+-
+- db->adc1_index = m3_add_list(s->card, &s->card->adc1_list,
+- s->adc_inst.data >> DP_SHIFT_COUNT);
+-
+- db->dma_index = m3_add_list(s->card, &s->card->dma_list,
+- s->adc_inst.data >> DP_SHIFT_COUNT);
+-
+- db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
+- s->adc_inst.data >> DP_SHIFT_COUNT);
+-
+- db->in_lists = 1;
+- }
+-
+- set_adc_rate(s,rate);
+- start_adc(s);
+-}
+-/* --------------------------------------------------------------------- */
+-
+-static void set_dmaa(struct m3_state *s, unsigned int addr, unsigned int count)
+-{
+- DPRINTK(DPINT,"set_dmaa??\n");
+-}
+-
+-static void set_dmac(struct m3_state *s, unsigned int addr, unsigned int count)
+-{
+- DPRINTK(DPINT,"set_dmac??\n");
+-}
+-
+-static u32 get_dma_pos(struct m3_card *card,
+- int instance_addr)
+-{
+- u16 hi = 0, lo = 0;
+- int retry = 10;
+-
+- /*
+- * try and get a valid answer
+- */
+- while(retry--) {
+- hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+- instance_addr + CDATA_HOST_SRC_CURRENTH);
+-
+- lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+- instance_addr + CDATA_HOST_SRC_CURRENTL);
+-
+- if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+- instance_addr + CDATA_HOST_SRC_CURRENTH))
+- break;
+- }
+- return lo | (hi<<16);
+-}
+-
+-static u32 get_dmaa(struct m3_state *s)
+-{
+- u32 offset;
+-
+- offset = get_dma_pos(s->card, s->dac_inst.data) -
+- virt_to_bus(s->dma_dac.rawbuf);
+-
+- DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset);
+-
+- return offset;
+-}
+-
+-static u32 get_dmac(struct m3_state *s)
+-{
+- u32 offset;
+-
+- offset = get_dma_pos(s->card, s->adc_inst.data) -
+- virt_to_bus(s->dma_adc.rawbuf);
+-
+- DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset);
+-
+- return offset;
+-
+-}
+-
+-static int
+-prog_dmabuf(struct m3_state *s, unsigned rec)
+-{
+- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+- unsigned rate = rec ? s->rateadc : s->ratedac;
+- unsigned bytepersec;
+- unsigned bufs;
+- unsigned char fmt;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->card->lock, flags);
+-
+- fmt = s->fmt;
+- if (rec) {
+- stop_adc(s);
+- fmt >>= ESS_ADC_SHIFT;
+- } else {
+- stop_dac(s);
+- fmt >>= ESS_DAC_SHIFT;
+- }
+- fmt &= ESS_FMT_MASK;
+-
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+-
+- bytepersec = rate << sample_shift[fmt];
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytepersec)
+- db->fragshift = ld2(bytepersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- db->fragsamples = db->fragsize >> sample_shift[fmt];
+- db->dmasize = db->numfrag << db->fragshift;
+-
+- DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
+-
+- memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+-
+- if (rec)
+- m3_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
+- else
+- m3_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
+-
+- db->ready = 1;
+-
+- spin_unlock_irqrestore(&s->card->lock, flags);
+-
+- return 0;
+-}
+-
+-static void clear_advance(struct m3_state *s)
+-{
+- unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+-
+- unsigned char *buf = s->dma_dac.rawbuf;
+- unsigned bsize = s->dma_dac.dmasize;
+- unsigned bptr = s->dma_dac.swptr;
+- unsigned len = s->dma_dac.fragsize;
+-
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(buf + bptr, c, x);
+- /* account for wrapping? */
+- bptr = 0;
+- len -= x;
+- }
+- memset(buf + bptr, c, len);
+-}
+-
+-/* call with spinlock held! */
+-static void m3_update_ptr(struct m3_state *s)
+-{
+- unsigned hwptr;
+- int diff;
+-
+- /* update ADC pointer */
+- if (s->dma_adc.ready) {
+- hwptr = get_dmac(s) % s->dma_adc.dmasize;
+- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- wake_up(&s->dma_adc.wait);
+- if (!s->dma_adc.mapped) {
+- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+- stop_adc(s);
+- /* brute force everyone back in sync, sigh */
+- s->dma_adc.count = 0;
+- s->dma_adc.swptr = 0;
+- s->dma_adc.hwptr = 0;
+- s->dma_adc.error++;
+- }
+- }
+- }
+- /* update DAC pointer */
+- if (s->dma_dac.ready) {
+- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
+- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+-
+- DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n",
+- hwptr,diff,s->dma_dac.count);
+-
+- s->dma_dac.hwptr = hwptr;
+- s->dma_dac.total_bytes += diff;
+-
+- if (s->dma_dac.mapped) {
+-
+- s->dma_dac.count += diff;
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
+- wake_up(&s->dma_dac.wait);
+- }
+- } else {
+-
+- s->dma_dac.count -= diff;
+-
+- if (s->dma_dac.count <= 0) {
+- DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n",
+- diff, diff,
+- s->dma_dac.count,
+- s->dma_dac.count,
+- hwptr, hwptr,
+- s->dma_dac.swptr,
+- s->dma_dac.swptr);
+- stop_dac(s);
+- /* brute force everyone back in sync, sigh */
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = hwptr;
+- s->dma_dac.error++;
+- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+- clear_advance(s);
+- s->dma_dac.endcleared = 1;
+- }
+- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
+- wake_up(&s->dma_dac.wait);
+- DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n",
+- s->dma_dac.count, s->dma_dac.swptr, hwptr);
+- }
+- }
+- }
+-}
+-
+-static irqreturn_t m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct m3_card *c = (struct m3_card *)dev_id;
+- struct m3_state *s = &c->channels[0];
+- u8 status;
+-
+- status = inb(c->iobase+0x1A);
+-
+- if(status == 0xff)
+- return IRQ_NONE;
+-
+- /* presumably acking the ints? */
+- outw(status, c->iobase+0x1A);
+-
+- if(c->in_suspend)
+- return IRQ_HANDLED;
+-
+- /*
+- * ack an assp int if its running
+- * and has an int pending
+- */
+- if( status & ASSP_INT_PENDING) {
+- u8 ctl = inb(c->iobase + ASSP_CONTROL_B);
+- if( !(ctl & STOP_ASSP_CLOCK)) {
+- ctl = inb(c->iobase + ASSP_HOST_INT_STATUS );
+- if(ctl & DSP2HOST_REQ_TIMER) {
+- outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS);
+- /* update adc/dac info if it was a timer int */
+- spin_lock(&c->lock);
+- m3_update_ptr(s);
+- spin_unlock(&c->lock);
+- }
+- }
+- }
+-
+- /* XXX is this needed? */
+- if(status & 0x40)
+- outb(0x40, c->iobase+0x1A);
+- return IRQ_HANDLED;
+-}
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";
+-
+-#define VALIDATE_MAGIC(FOO,MAG) \
+-({ \
+- if (!(FOO) || (FOO)->magic != MAG) { \
+- printk(invalid_magic,__FUNCTION__); \
+- return -ENXIO; \
+- } \
+-})
+-
+-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)
+-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct m3_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait,current);
+- unsigned long flags;
+- int count;
+- signed long tmo;
+-
+- if (s->dma_dac.mapped || !s->dma_dac.ready)
+- return 0;
+- set_current_state(TASK_INTERRUPTIBLE);
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- for (;;) {
+- spin_lock_irqsave(&s->card->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return -EBUSY;
+- }
+- tmo = (count * HZ) / s->ratedac;
+- tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
+- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
+- or something. who cares. - zach */
+- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
+- DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-static ssize_t m3_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct m3_state *s = (struct m3_state *)file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- spin_lock_irqsave(&s->card->lock, flags);
+-
+- while (count > 0) {
+- int timed_out;
+-
+- swptr = s->dma_adc.swptr;
+- cnt = s->dma_adc.dmasize-swptr;
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+-
+- if (cnt > count)
+- cnt = count;
+-
+- if (cnt <= 0) {
+- start_adc(s);
+- if (file->f_flags & O_NONBLOCK)
+- {
+- ret = ret ? ret : -EAGAIN;
+- goto out;
+- }
+-
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0;
+- spin_lock_irqsave(&s->card->lock, flags);
+-
+- if(timed_out) {
+- printk("read: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
+- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+- s->dma_adc.hwptr, s->dma_adc.swptr);
+- stop_adc(s);
+- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
+- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+- }
+- if (signal_pending(current))
+- {
+- ret = ret ? ret : -ERESTARTSYS;
+- goto out;
+- }
+- continue;
+- }
+-
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+- ret = ret ? ret : -EFAULT;
+- return ret;
+- }
+- spin_lock_irqsave(&s->card->lock, flags);
+-
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- start_adc(s);
+- }
+-
+-out:
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- return ret;
+-}
+-
+-static ssize_t m3_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct m3_state *s = (struct m3_state *)file->private_data;
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac.mapped)
+- return -ENXIO;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-
+- spin_lock_irqsave(&s->card->lock, flags);
+-
+- while (count > 0) {
+- int timed_out;
+-
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = s->dma_dac.hwptr;
+- }
+- swptr = s->dma_dac.swptr;
+-
+- cnt = s->dma_dac.dmasize-swptr;
+-
+- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+-
+-
+- if (cnt > count)
+- cnt = count;
+-
+- if (cnt <= 0) {
+- start_dac(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if(!ret) ret = -EAGAIN;
+- goto out;
+- }
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0;
+- spin_lock_irqsave(&s->card->lock, flags);
+- if(timed_out) {
+- DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
+- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+- s->dma_dac.hwptr, s->dma_dac.swptr);
+- stop_dac(s);
+- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
+- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+- }
+- if (signal_pending(current)) {
+- if (!ret) ret = -ERESTARTSYS;
+- goto out;
+- }
+- continue;
+- }
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+- if (!ret) ret = -EFAULT;
+- return ret;
+- }
+- spin_lock_irqsave(&s->card->lock, flags);
+-
+- DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n",
+- cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);
+-
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+-
+- s->dma_dac.swptr = swptr;
+- s->dma_dac.count += cnt;
+- s->dma_dac.endcleared = 0;
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- start_dac(s);
+- }
+-out:
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- return ret;
+-}
+-
+-static unsigned int m3_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct m3_state *s = (struct m3_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE)
+- poll_wait(file, &s->dma_dac.wait, wait);
+- if (file->f_mode & FMODE_READ)
+- poll_wait(file, &s->dma_adc.wait, wait);
+-
+- spin_lock_irqsave(&s->card->lock, flags);
+- m3_update_ptr(s);
+-
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+-
+- spin_unlock_irqrestore(&s->card->lock, flags);
+- return mask;
+-}
+-
+-static int m3_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct m3_state *s = (struct m3_state *)file->private_data;
+- unsigned long max_size, size, start, offset;
+- struct dmabuf *db;
+- int ret = -EINVAL;
+-
+- VALIDATE_STATE(s);
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf(s, 0)) != 0)
+- return ret;
+- db = &s->dma_dac;
+- } else
+- if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf(s, 1)) != 0)
+- return ret;
+- db = &s->dma_adc;
+- } else
+- return -EINVAL;
+-
+- max_size = db->dmasize;
+-
+- start = vma->vm_start;
+- offset = (vma->vm_pgoff << PAGE_SHIFT);
+- size = vma->vm_end - vma->vm_start;
+-
+- if(size > max_size)
+- goto out;
+- if(offset > max_size - size)
+- goto out;
+-
+- /*
+- * this will be ->nopage() once I can
+- * ask Jeff what the hell I'm doing wrong.
+- */
+- ret = -EAGAIN;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+-
+- db->mapped = 1;
+- ret = 0;
+-
+-out:
+- return ret;
+-}
+-
+-/*
+- * this function is a disaster..
+- */
+-#define get_user_ret(x, ptr, ret) ({ if(get_user(x, ptr)) return ret; })
+-static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct m3_state *s = (struct m3_state *)file->private_data;
+- struct m3_card *card=s->card;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int val, mapped, ret;
+- unsigned char fmtm, fmtd;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+-
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+-
+- DPRINTK(DPSYS,"m3_ioctl: cmd %d\n", cmd);
+-
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, file->f_flags & O_NONBLOCK);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- /* XXX fix */
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+- spin_lock_irqsave(&card->lock, flags);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->card->pcidev->irq);
+- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->card->pcidev->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- spin_unlock_irqrestore(&card->lock, flags);
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- get_user_ret(val, p, -EFAULT);
+- spin_lock_irqsave(&card->lock, flags);
+- if (val >= 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- set_adc_rate(s, val);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- set_dac_rate(s, val);
+- }
+- }
+- spin_unlock_irqrestore(&card->lock, flags);
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SNDCTL_DSP_STEREO:
+- get_user_ret(val, p, -EFAULT);
+- spin_lock_irqsave(&card->lock, flags);
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val)
+- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val)
+- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- spin_unlock_irqrestore(&card->lock, flags);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- get_user_ret(val, p, -EFAULT);
+- spin_lock_irqsave(&card->lock, flags);
+- if (val != 0) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val >= 2)
+- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val >= 2)
+- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- spin_unlock_irqrestore(&card->lock, flags);
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
+- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_U8|AFMT_S16_LE, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- get_user_ret(val, p, -EFAULT);
+- spin_lock_irqsave(&card->lock, flags);
+- if (val != AFMT_QUERY) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val == AFMT_S16_LE)
+- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val == AFMT_S16_LE)
+- fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+- else
+- fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- spin_unlock_irqrestore(&card->lock, flags);
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
+- (ESS_FMT_16BIT << ESS_ADC_SHIFT)
+- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
+- AFMT_S16_LE :
+- AFMT_U8,
+- p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
+- val |= PCM_ENABLE_INPUT;
+- if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- get_user_ret(val, p, -EFAULT);
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- start_adc(s);
+- } else
+- stop_adc(s);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- start_dac(s);
+- } else
+- stop_dac(s);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
+- return val;
+- spin_lock_irqsave(&card->lock, flags);
+- m3_update_ptr(s);
+- abinfo.fragsize = s->dma_dac.fragsize;
+- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- spin_unlock_irqrestore(&card->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
+- return val;
+- spin_lock_irqsave(&card->lock, flags);
+- m3_update_ptr(s);
+- abinfo.fragsize = s->dma_adc.fragsize;
+- abinfo.bytes = s->dma_adc.count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- spin_unlock_irqrestore(&card->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&card->lock, flags);
+- m3_update_ptr(s);
+- val = s->dma_dac.count;
+- spin_unlock_irqrestore(&card->lock, flags);
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- spin_lock_irqsave(&card->lock, flags);
+- m3_update_ptr(s);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&card->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- spin_lock_irqsave(&card->lock, flags);
+- m3_update_ptr(s);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+- cinfo.ptr = s->dma_dac.hwptr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize-1;
+- spin_unlock_irqrestore(&card->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf(s, 0)))
+- return val;
+- return put_user(s->dma_dac.fragsize, p);
+- }
+- if ((val = prog_dmabuf(s, 1)))
+- return val;
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- get_user_ret(val, p, -EFAULT);
+- spin_lock_irqsave(&card->lock, flags);
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- }
+- spin_unlock_irqrestore(&card->lock, flags);
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- get_user_ret(val, p, -EFAULT);
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE)
+- s->dma_dac.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
+- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
+- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+- return -EINVAL;
+-}
+-
+-static int
+-allocate_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
+-{
+- int order;
+-
+- DPRINTK(DPSTR,"allocating for dmabuf %p\n", db);
+-
+- /*
+- * alloc as big a chunk as we can, start with
+- * 64k 'cause we're insane. based on order cause
+- * the amazingly complicated prog_dmabuf wants it.
+- *
+- * pci_alloc_sonsistent guarantees that it won't cross a natural
+- * boundary; the m3 hardware can't have dma cross a 64k bus
+- * address boundary.
+- */
+- for (order = 16-PAGE_SHIFT; order >= 1; order--) {
+- db->rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
+- &(db->handle));
+- if(db->rawbuf)
+- break;
+- }
+-
+- if (!db->rawbuf)
+- return 1;
+-
+- DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n",
+- PAGE_SIZE<<order, order, db->rawbuf);
+-
+- {
+- struct page *page, *pend;
+-
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << order) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- }
+-
+-
+- db->buforder = order;
+- db->ready = 0;
+- db->mapped = 0;
+-
+- return 0;
+-}
+-
+-static void
+-nuke_lists(struct m3_card *card, struct dmabuf *db)
+-{
+- m3_remove_list(card, &(card->dma_list), db->dma_index);
+- m3_remove_list(card, &(card->msrc_list), db->msrc_index);
+- db->in_lists = 0;
+-}
+-
+-static void
+-free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
+-{
+- if(db->rawbuf == NULL)
+- return;
+-
+- DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
+-
+- {
+- struct page *page, *pend;
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- }
+-
+-
+- pci_free_consistent(pci_dev, PAGE_SIZE << db->buforder,
+- db->rawbuf, db->handle);
+-
+- db->rawbuf = NULL;
+- db->buforder = 0;
+- db->mapped = 0;
+- db->ready = 0;
+-}
+-
+-static int m3_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct m3_card *c;
+- struct m3_state *s = NULL;
+- int i;
+- unsigned char fmtm = ~0, fmts = 0;
+- unsigned long flags;
+-
+- /*
+- * Scan the cards and find the channel. We only
+- * do this at open time so it is ok
+- */
+- for(c = devs ; c != NULL ; c = c->next) {
+-
+- for(i=0;i<NR_DSPS;i++) {
+-
+- if(c->channels[i].dev_audio < 0)
+- continue;
+- if((c->channels[i].dev_audio ^ minor) & ~0xf)
+- continue;
+-
+- s = &c->channels[i];
+- break;
+- }
+- }
+-
+- if (!s)
+- return -ENODEV;
+-
+- VALIDATE_STATE(s);
+-
+- file->private_data = s;
+-
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EWOULDBLOCK;
+- }
+- mutex_unlock(&s->open_mutex);
+- interruptible_sleep_on(&s->open_wait);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+-
+- spin_lock_irqsave(&c->lock, flags);
+-
+- if (file->f_mode & FMODE_READ) {
+- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+-
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+- set_adc_rate(s, 8000);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+-
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+- set_dac_rate(s, 8000);
+- }
+- set_fmt(s, fmtm, fmts);
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+-
+- mutex_unlock(&s->open_mutex);
+- spin_unlock_irqrestore(&c->lock, flags);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int m3_release(struct inode *inode, struct file *file)
+-{
+- struct m3_state *s = (struct m3_state *)file->private_data;
+- struct m3_card *card=s->card;
+- unsigned long flags;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+-
+- mutex_lock(&s->open_mutex);
+- spin_lock_irqsave(&card->lock, flags);
+-
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- if(s->dma_dac.in_lists) {
+- m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
+- nuke_lists(s->card, &(s->dma_dac));
+- }
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- if(s->dma_adc.in_lists) {
+- m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
+- nuke_lists(s->card, &(s->dma_adc));
+- }
+- }
+-
+- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+-
+- spin_unlock_irqrestore(&card->lock, flags);
+- mutex_unlock(&s->open_mutex);
+- wake_up(&s->open_wait);
+-
+- return 0;
+-}
+-
+-/*
+- * Wait for the ac97 serial bus to be free.
+- * return nonzero if the bus is still busy.
+- */
+-static int m3_ac97_wait(struct m3_card *card)
+-{
+- int i = 10000;
+-
+- while( (m3_inb(card, 0x30) & 1) && i--) ;
+-
+- return i == 0;
+-}
+-
+-static u16 m3_ac97_read(struct ac97_codec *codec, u8 reg)
+-{
+- u16 ret = 0;
+- struct m3_card *card = codec->private_data;
+-
+- spin_lock(&card->ac97_lock);
+-
+- if(m3_ac97_wait(card)) {
+- printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg);
+- goto out;
+- }
+-
+- m3_outb(card, 0x80 | (reg & 0x7f), 0x30);
+-
+- if(m3_ac97_wait(card)) {
+- printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg);
+- goto out;
+- }
+-
+- ret = m3_inw(card, 0x32);
+- DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);
+-
+-out:
+- spin_unlock(&card->ac97_lock);
+- return ret;
+-}
+-
+-static void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
+-{
+- struct m3_card *card = codec->private_data;
+-
+- spin_lock(&card->ac97_lock);
+-
+- if(m3_ac97_wait(card)) {
+- printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg);
+- goto out;
+- }
+- DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg);
+-
+- m3_outw(card, val, 0x32);
+- m3_outb(card, reg & 0x7f, 0x30);
+-out:
+- spin_unlock(&card->ac97_lock);
+-}
+-/* OSS /dev/mixer file operation methods */
+-static int m3_open_mixdev(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct m3_card *card = devs;
+-
+- for (card = devs; card != NULL; card = card->next) {
+- if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor))
+- break;
+- }
+-
+- if (!card) {
+- return -ENODEV;
+- }
+-
+- file->private_data = card->ac97;
+-
+- return nonseekable_open(inode, file);
+-}
+-
+-static int m3_release_mixdev(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+- unsigned long arg)
+-{
+- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+-
+- return codec->mixer_ioctl(codec, cmd, arg);
+-}
+-
+-static struct file_operations m3_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = m3_ioctl_mixdev,
+- .open = m3_open_mixdev,
+- .release = m3_release_mixdev,
+-};
+-
+-static void remote_codec_config(int io, int isremote)
+-{
+- isremote = isremote ? 1 : 0;
+-
+- outw( (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
+- io + RING_BUS_CTRL_B);
+- outw( (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
+- io + SDO_OUT_DEST_CTRL);
+- outw( (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
+- io + SDO_IN_DEST_CTRL);
+-}
+-
+-/*
+- * hack, returns non zero on err
+- */
+-static int try_read_vendor(struct m3_card *card)
+-{
+- u16 ret;
+-
+- if(m3_ac97_wait(card))
+- return 1;
+-
+- m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
+-
+- if(m3_ac97_wait(card))
+- return 1;
+-
+- ret = m3_inw(card, 0x32);
+-
+- return (ret == 0) || (ret == 0xffff);
+-}
+-
+-static void m3_codec_reset(struct m3_card *card, int busywait)
+-{
+- u16 dir;
+- int delay1 = 0, delay2 = 0, i;
+- int io = card->iobase;
+-
+- switch (card->card_type) {
+- /*
+- * the onboard codec on the allegro seems
+- * to want to wait a very long time before
+- * coming back to life
+- */
+- case ESS_ALLEGRO:
+- delay1 = 50;
+- delay2 = 800;
+- break;
+- case ESS_MAESTRO3:
+- case ESS_MAESTRO3HW:
+- delay1 = 20;
+- delay2 = 500;
+- break;
+- }
+-
+- for(i = 0; i < 5; i ++) {
+- dir = inw(io + GPIO_DIRECTION);
+- dir |= 0x10; /* assuming pci bus master? */
+-
+- remote_codec_config(io, 0);
+-
+- outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
+- udelay(20);
+-
+- outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
+- outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
+- outw(0, io + GPIO_DATA);
+- outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
+-
+- if(busywait) {
+- mdelay(delay1);
+- } else {
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout((delay1 * HZ) / 1000);
+- }
+-
+- outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
+- udelay(5);
+- /* ok, bring back the ac-link */
+- outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
+- outw(~0, io + GPIO_MASK);
+-
+- if(busywait) {
+- mdelay(delay2);
+- } else {
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout((delay2 * HZ) / 1000);
+- }
+- if(! try_read_vendor(card))
+- break;
+-
+- delay1 += 10;
+- delay2 += 100;
+-
+- DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n",
+- delay1, delay2);
+- }
+-
+-#if 0
+- /* more gung-ho reset that doesn't
+- * seem to work anywhere :)
+- */
+- tmp = inw(io + RING_BUS_CTRL_A);
+- outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
+- mdelay(20);
+- outw(tmp, io + RING_BUS_CTRL_A);
+- mdelay(50);
+-#endif
+-}
+-
+-static int __devinit m3_codec_install(struct m3_card *card)
+-{
+- struct ac97_codec *codec;
+-
+- if ((codec = ac97_alloc_codec()) == NULL)
+- return -ENOMEM;
+-
+- codec->private_data = card;
+- codec->codec_read = m3_ac97_read;
+- codec->codec_write = m3_ac97_write;
+- /* someday we should support secondary codecs.. */
+- codec->id = 0;
+-
+- if (ac97_probe_codec(codec) == 0) {
+- printk(KERN_ERR PFX "codec probe failed\n");
+- ac97_release_codec(codec);
+- return -1;
+- }
+-
+- if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) {
+- printk(KERN_ERR PFX "couldn't register mixer!\n");
+- ac97_release_codec(codec);
+- return -1;
+- }
+-
+- card->ac97 = codec;
+-
+- return 0;
+-}
+-
+-
+-#define MINISRC_LPF_LEN 10
+-static u16 minisrc_lpf[MINISRC_LPF_LEN] = {
+- 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
+- 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
+-};
+-static void m3_assp_init(struct m3_card *card)
+-{
+- int i;
+-
+- /* zero kernel data */
+- for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_BASE_ADDR + i, 0);
+-
+- /* zero mixer data? */
+- for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_BASE_ADDR2 + i, 0);
+-
+- /* init dma pointer */
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_CURRENT_DMA,
+- KDATA_DMA_XFER0);
+-
+- /* write kernel into code memory.. */
+- for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
+- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+- REV_B_CODE_MEMORY_BEGIN + i,
+- assp_kernel_image[i]);
+- }
+-
+- /*
+- * We only have this one client and we know that 0x400
+- * is free in our kernel's mem map, so lets just
+- * drop it there. It seems that the minisrc doesn't
+- * need vectors, so we won't bother with them..
+- */
+- for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) {
+- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+- 0x400 + i,
+- assp_minisrc_image[i]);
+- }
+-
+- /*
+- * write the coefficients for the low pass filter?
+- */
+- for(i = 0; i < MINISRC_LPF_LEN ; i++) {
+- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+- 0x400 + MINISRC_COEF_LOC + i,
+- minisrc_lpf[i]);
+- }
+-
+- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+- 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
+- 0x8000);
+-
+- /*
+- * the minisrc is the only thing on
+- * our task list..
+- */
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_TASK0,
+- 0x400);
+-
+- /*
+- * init the mixer number..
+- */
+-
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_MIXER_TASK_NUMBER,0);
+-
+- /*
+- * EXTREME KERNEL MASTER VOLUME
+- */
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
+-
+- card->mixer_list.mem_addr = KDATA_MIXER_XFER0;
+- card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
+- card->adc1_list.mem_addr = KDATA_ADC1_XFER0;
+- card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
+- card->dma_list.mem_addr = KDATA_DMA_XFER0;
+- card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
+- card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
+- card->msrc_list.max = MAX_INSTANCE_MINISRC;
+-}
+-
+-static int setup_msrc(struct m3_card *card,
+- struct assp_instance *inst, int index)
+-{
+- int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 +
+- MINISRC_IN_BUFFER_SIZE / 2 +
+- 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
+- int address, i;
+-
+- /*
+- * the revb memory map has 0x1100 through 0x1c00
+- * free.
+- */
+-
+- /*
+- * align instance address to 256 bytes so that it's
+- * shifted list address is aligned.
+- * list address = (mem address >> 1) >> 7;
+- */
+- data_bytes = (data_bytes + 255) & ~255;
+- address = 0x1100 + ((data_bytes/2) * index);
+-
+- if((address + (data_bytes/2)) >= 0x1c00) {
+- printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n",
+- data_bytes, index, address);
+- return -1;
+- }
+-
+- for(i = 0; i < data_bytes/2 ; i++)
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- address + i, 0);
+-
+- inst->code = 0x400;
+- inst->data = address;
+-
+- return 0;
+-}
+-
+-static int m3_assp_client_init(struct m3_state *s)
+-{
+- setup_msrc(s->card, &(s->dac_inst), s->index * 2);
+- setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1);
+-
+- return 0;
+-}
+-
+-static void m3_amp_enable(struct m3_card *card, int enable)
+-{
+- /*
+- * this works for the reference board, have to find
+- * out about others
+- *
+- * this needs more magic for 4 speaker, but..
+- */
+- int io = card->iobase;
+- u16 gpo, polarity_port, polarity;
+-
+- if(!external_amp)
+- return;
+-
+- if (gpio_pin >= 0 && gpio_pin <= 15) {
+- polarity_port = 0x1000 + (0x100 * gpio_pin);
+- } else {
+- switch (card->card_type) {
+- case ESS_ALLEGRO:
+- polarity_port = 0x1800;
+- break;
+- default:
+- polarity_port = 0x1100;
+- /* Panasonic toughbook CF72 has to be different... */
+- if(card->pcidev->subsystem_vendor == 0x10F7 && card->pcidev->subsystem_device == 0x833D)
+- polarity_port = 0x1D00;
+- break;
+- }
+- }
+-
+- gpo = (polarity_port >> 8) & 0x0F;
+- polarity = polarity_port >> 12;
+- if ( enable )
+- polarity = !polarity;
+- polarity = polarity << gpo;
+- gpo = 1 << gpo;
+-
+- outw(~gpo , io + GPIO_MASK);
+-
+- outw( inw(io + GPIO_DIRECTION) | gpo ,
+- io + GPIO_DIRECTION);
+-
+- outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) ,
+- io + GPIO_DATA);
+-
+- outw(0xffff , io + GPIO_MASK);
+-}
+-
+-static int
+-maestro_config(struct m3_card *card)
+-{
+- struct pci_dev *pcidev = card->pcidev;
+- u32 n;
+- u8 t; /* makes as much sense as 'n', no? */
+-
+- pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
+- n &= REDUCED_DEBOUNCE;
+- n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
+- pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
+-
+- outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B);
+- pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
+- n &= ~INT_CLK_SELECT;
+- if(card->card_type >= ESS_MAESTRO3) {
+- n &= ~INT_CLK_MULT_ENABLE;
+- n |= INT_CLK_SRC_NOT_PCI;
+- }
+- n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
+- pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
+-
+- if(card->card_type <= ESS_ALLEGRO) {
+- pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
+- n |= IN_CLK_12MHZ_SELECT;
+- pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
+- }
+-
+- t = inb(card->iobase + ASSP_CONTROL_A);
+- t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT);
+- t |= ASSP_CLK_49MHZ_SELECT;
+- t |= ASSP_0_WS_ENABLE;
+- outb(t, card->iobase + ASSP_CONTROL_A);
+-
+- outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B);
+-
+- return 0;
+-}
+-
+-static void m3_enable_ints(struct m3_card *card)
+-{
+- unsigned long io = card->iobase;
+-
+- outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
+- outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
+- io + ASSP_CONTROL_C);
+-}
+-
+-static struct file_operations m3_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = m3_read,
+- .write = m3_write,
+- .poll = m3_poll,
+- .ioctl = m3_ioctl,
+- .mmap = m3_mmap,
+- .open = m3_open,
+- .release = m3_release,
+-};
+-
+-#ifdef CONFIG_PM
+-static int alloc_dsp_suspendmem(struct m3_card *card)
+-{
+- int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
+-
+- if( (card->suspend_mem = vmalloc(len)) == NULL)
+- return 1;
+-
+- return 0;
+-}
+-
+-#else
+-#define alloc_dsp_suspendmem(args...) 0
+-#endif
+-
+-/*
+- * great day! this function is ugly as hell.
+- */
+-static int __devinit m3_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+-{
+- u32 n;
+- int i;
+- struct m3_card *card = NULL;
+- int ret = 0;
+- int card_type = pci_id->driver_data;
+-
+- DPRINTK(DPMOD, "in maestro_install\n");
+-
+- if (pci_enable_device(pci_dev))
+- return -EIO;
+-
+- if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) {
+- printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n");
+- return -ENODEV;
+- }
+-
+- pci_set_master(pci_dev);
+-
+- if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) {
+- printk(KERN_WARNING PFX "out of memory\n");
+- return -ENOMEM;
+- }
+- memset(card, 0, sizeof(struct m3_card));
+- card->pcidev = pci_dev;
+- init_waitqueue_head(&card->suspend_queue);
+-
+- if ( ! request_region(pci_resource_start(pci_dev, 0),
+- pci_resource_len (pci_dev, 0), M3_MODULE_NAME)) {
+-
+- printk(KERN_WARNING PFX "unable to reserve I/O space.\n");
+- ret = -EBUSY;
+- goto out;
+- }
+-
+- card->iobase = pci_resource_start(pci_dev, 0);
+-
+- if(alloc_dsp_suspendmem(card)) {
+- printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n",
+- REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
+- ret = -ENOMEM;
+- goto out;
+- }
+-
+- card->card_type = card_type;
+- card->irq = pci_dev->irq;
+- card->next = devs;
+- card->magic = M3_CARD_MAGIC;
+- spin_lock_init(&card->lock);
+- spin_lock_init(&card->ac97_lock);
+- devs = card;
+- for(i = 0; i<NR_DSPS; i++) {
+- struct m3_state *s = &(card->channels[i]);
+- s->dev_audio = -1;
+- }
+-
+- printk(KERN_INFO PFX "Configuring ESS %s found at IO 0x%04X IRQ %d\n",
+- card_names[card->card_type], card->iobase, card->irq);
+-
+- pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &n);
+- printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n);
+-
+- maestro_config(card);
+- m3_assp_halt(card);
+-
+- m3_codec_reset(card, 0);
+-
+- if(m3_codec_install(card)) {
+- ret = -EIO;
+- goto out;
+- }
+-
+- m3_assp_init(card);
+- m3_amp_enable(card, 1);
+-
+- for(i=0;i<NR_DSPS;i++) {
+- struct m3_state *s=&card->channels[i];
+-
+- s->index = i;
+-
+- s->card = card;
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- mutex_init(&(s->open_mutex));
+- s->magic = M3_STATE_MAGIC;
+-
+- m3_assp_client_init(s);
+-
+- if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
+- printk(KERN_WARNING PFX "initing a dsp device that is already in use?\n");
+- /* register devices */
+- if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) {
+- break;
+- }
+-
+- if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) ||
+- allocate_dmabuf(card->pcidev, &(s->dma_dac))) {
+- ret = -ENOMEM;
+- goto out;
+- }
+- }
+-
+- if(request_irq(card->irq, m3_interrupt, IRQF_SHARED, card_names[card->card_type], card)) {
+-
+- printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq);
+-
+- ret = -EIO;
+- goto out;
+- }
+-
+- pci_set_drvdata(pci_dev, card);
+-
+- m3_enable_ints(card);
+- m3_assp_continue(card);
+-
+-out:
+- if(ret) {
+- if(card->iobase)
+- release_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
+- vfree(card->suspend_mem);
+- if(card->ac97) {
+- unregister_sound_mixer(card->ac97->dev_mixer);
+- kfree(card->ac97);
+- }
+- for(i=0;i<NR_DSPS;i++)
+- {
+- struct m3_state *s = &card->channels[i];
+- if(s->dev_audio != -1)
+- unregister_sound_dsp(s->dev_audio);
+- }
+- kfree(card);
+- }
+-
+- return ret;
+-}
+-
+-static void m3_remove(struct pci_dev *pci_dev)
+-{
+- struct m3_card *card;
+-
+- unregister_reboot_notifier(&m3_reboot_nb);
+-
+- while ((card = devs)) {
+- int i;
+- devs = devs->next;
+-
+- free_irq(card->irq, card);
+- unregister_sound_mixer(card->ac97->dev_mixer);
+- kfree(card->ac97);
+-
+- for(i=0;i<NR_DSPS;i++)
+- {
+- struct m3_state *s = &card->channels[i];
+- if(s->dev_audio < 0)
+- continue;
+-
+- unregister_sound_dsp(s->dev_audio);
+- free_dmabuf(card->pcidev, &s->dma_adc);
+- free_dmabuf(card->pcidev, &s->dma_dac);
+- }
+-
+- release_region(card->iobase, 256);
+- vfree(card->suspend_mem);
+- kfree(card);
+- }
+- devs = NULL;
+-}
+-
+-/*
+- * some bioses like the sound chip to be powered down
+- * at shutdown. We're just calling _suspend to
+- * achieve that..
+- */
+-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+-{
+- struct m3_card *card;
+-
+- DPRINTK(DPMOD, "notifier suspending all cards\n");
+-
+- for(card = devs; card != NULL; card = card->next) {
+- if(!card->in_suspend)
+- m3_suspend(card->pcidev, PMSG_SUSPEND); /* XXX legal? */
+- }
+- return 0;
+-}
+-
+-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state)
+-{
+- unsigned long flags;
+- int i;
+- struct m3_card *card = pci_get_drvdata(pci_dev);
+-
+- /* must be a better way.. */
+- spin_lock_irqsave(&card->lock, flags);
+-
+- DPRINTK(DPMOD, "pm in dev %p\n",card);
+-
+- for(i=0;i<NR_DSPS;i++) {
+- struct m3_state *s = &card->channels[i];
+-
+- if(s->dev_audio == -1)
+- continue;
+-
+- DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i);
+- stop_dac(s);
+- stop_adc(s);
+- }
+-
+- mdelay(10); /* give the assp a chance to idle.. */
+-
+- m3_assp_halt(card);
+-
+- if(card->suspend_mem) {
+- int index = 0;
+-
+- DPRINTK(DPMOD, "saving code\n");
+- for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
+- card->suspend_mem[index++] =
+- m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i);
+- DPRINTK(DPMOD, "saving data\n");
+- for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
+- card->suspend_mem[index++] =
+- m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i);
+- }
+-
+- DPRINTK(DPMOD, "powering down apci regs\n");
+- m3_outw(card, 0xffff, 0x54);
+- m3_outw(card, 0xffff, 0x56);
+-
+- card->in_suspend = 1;
+-
+- spin_unlock_irqrestore(&card->lock, flags);
+-
+- return 0;
+-}
+-
+-static int m3_resume(struct pci_dev *pci_dev)
+-{
+- unsigned long flags;
+- int index;
+- int i;
+- struct m3_card *card = pci_get_drvdata(pci_dev);
+-
+- spin_lock_irqsave(&card->lock, flags);
+- card->in_suspend = 0;
+-
+- DPRINTK(DPMOD, "resuming\n");
+-
+- /* first lets just bring everything back. .*/
+-
+- DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card);
+- m3_outw(card, 0, 0x54);
+- m3_outw(card, 0, 0x56);
+-
+- DPRINTK(DPMOD, "restoring pci configs and reseting codec\n");
+- maestro_config(card);
+- m3_assp_halt(card);
+- m3_codec_reset(card, 1);
+-
+- DPRINTK(DPMOD, "restoring dsp code card\n");
+- index = 0;
+- for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
+- m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i,
+- card->suspend_mem[index++]);
+- for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i,
+- card->suspend_mem[index++]);
+-
+- /* tell the dma engine to restart itself */
+- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+- KDATA_DMA_ACTIVE, 0);
+-
+- DPRINTK(DPMOD, "resuming dsp\n");
+- m3_assp_continue(card);
+-
+- DPRINTK(DPMOD, "enabling ints\n");
+- m3_enable_ints(card);
+-
+- /* bring back the old school flavor */
+- for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) {
+- int state = card->ac97->mixer_state[i];
+- if (!supported_mixer(card->ac97, i))
+- continue;
+-
+- card->ac97->write_mixer(card->ac97, i,
+- state & 0xff, (state >> 8) & 0xff);
+- }
+-
+- m3_amp_enable(card, 1);
+-
+- /*
+- * now we flip on the music
+- */
+- for(i=0;i<NR_DSPS;i++) {
+- struct m3_state *s = &card->channels[i];
+- if(s->dev_audio == -1)
+- continue;
+- /*
+- * db->ready makes it so these guys can be
+- * called unconditionally..
+- */
+- DPRINTK(DPMOD, "turning on dacs ind %d\n",i);
+- start_dac(s);
+- start_adc(s);
+- }
+-
+- spin_unlock_irqrestore(&card->lock, flags);
+-
+- /*
+- * all right, we think things are ready,
+- * wake up people who were using the device
+- * when we suspended
+- */
+- wake_up(&card->suspend_queue);
+-
+- return 0;
+-}
+-
+-MODULE_AUTHOR("Zach Brown <zab at zabbo.net>");
+-MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver");
+-MODULE_LICENSE("GPL");
+-
+-#ifdef M_DEBUG
+-module_param(debug, int, 0);
+-#endif
+-module_param(external_amp, int, 0);
+-module_param(gpio_pin, int, 0);
+-
+-static struct pci_driver m3_pci_driver = {
+- .name = "ess_m3_audio",
+- .id_table = m3_id_table,
+- .probe = m3_probe,
+- .remove = m3_remove,
+- .suspend = m3_suspend,
+- .resume = m3_resume,
+-};
+-
+-static int __init m3_init_module(void)
+-{
+- printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n");
+-
+- if (register_reboot_notifier(&m3_reboot_nb)) {
+- printk(KERN_WARNING PFX "reboot notifier registration failed\n");
+- return -ENODEV; /* ? */
+- }
+-
+- if (pci_register_driver(&m3_pci_driver)) {
+- unregister_reboot_notifier(&m3_reboot_nb);
+- return -ENODEV;
+- }
+- return 0;
+-}
+-
+-static void __exit m3_cleanup_module(void)
+-{
+- pci_unregister_driver(&m3_pci_driver);
+-}
+-
+-module_init(m3_init_module);
+-module_exit(m3_cleanup_module);
+-
+-void check_suspend(struct m3_card *card)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+-
+- if(!card->in_suspend)
+- return;
+-
+- card->in_suspend++;
+- add_wait_queue(&card->suspend_queue, &wait);
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule();
+- remove_wait_queue(&card->suspend_queue, &wait);
+- set_current_state(TASK_RUNNING);
+-}
+diff --git a/sound/oss/maestro3.h b/sound/oss/maestro3.h
+deleted file mode 100644
+index dde2986..0000000
+--- a/sound/oss/maestro3.h
++++ /dev/null
+@@ -1,821 +0,0 @@
+-/*
+- * ESS Technology allegro audio driver.
+- *
+- * Copyright (C) 1992-2000 Don Kim (don.kim at esstech.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- * Hacked for the maestro3 driver by zab
+- */
+-
+-// Allegro PCI configuration registers
+-#define PCI_LEGACY_AUDIO_CTRL 0x40
+-#define SOUND_BLASTER_ENABLE 0x00000001
+-#define FM_SYNTHESIS_ENABLE 0x00000002
+-#define GAME_PORT_ENABLE 0x00000004
+-#define MPU401_IO_ENABLE 0x00000008
+-#define MPU401_IRQ_ENABLE 0x00000010
+-#define ALIAS_10BIT_IO 0x00000020
+-#define SB_DMA_MASK 0x000000C0
+-#define SB_DMA_0 0x00000040
+-#define SB_DMA_1 0x00000040
+-#define SB_DMA_R 0x00000080
+-#define SB_DMA_3 0x000000C0
+-#define SB_IRQ_MASK 0x00000700
+-#define SB_IRQ_5 0x00000000
+-#define SB_IRQ_7 0x00000100
+-#define SB_IRQ_9 0x00000200
+-#define SB_IRQ_10 0x00000300
+-#define MIDI_IRQ_MASK 0x00003800
+-#define SERIAL_IRQ_ENABLE 0x00004000
+-#define DISABLE_LEGACY 0x00008000
+-
+-#define PCI_ALLEGRO_CONFIG 0x50
+-#define SB_ADDR_240 0x00000004
+-#define MPU_ADDR_MASK 0x00000018
+-#define MPU_ADDR_330 0x00000000
+-#define MPU_ADDR_300 0x00000008
+-#define MPU_ADDR_320 0x00000010
+-#define MPU_ADDR_340 0x00000018
+-#define USE_PCI_TIMING 0x00000040
+-#define POSTED_WRITE_ENABLE 0x00000080
+-#define DMA_POLICY_MASK 0x00000700
+-#define DMA_DDMA 0x00000000
+-#define DMA_TDMA 0x00000100
+-#define DMA_PCPCI 0x00000200
+-#define DMA_WBDMA16 0x00000400
+-#define DMA_WBDMA4 0x00000500
+-#define DMA_WBDMA2 0x00000600
+-#define DMA_WBDMA1 0x00000700
+-#define DMA_SAFE_GUARD 0x00000800
+-#define HI_PERF_GP_ENABLE 0x00001000
+-#define PIC_SNOOP_MODE_0 0x00002000
+-#define PIC_SNOOP_MODE_1 0x00004000
+-#define SOUNDBLASTER_IRQ_MASK 0x00008000
+-#define RING_IN_ENABLE 0x00010000
+-#define SPDIF_TEST_MODE 0x00020000
+-#define CLK_MULT_MODE_SELECT_2 0x00040000
+-#define EEPROM_WRITE_ENABLE 0x00080000
+-#define CODEC_DIR_IN 0x00100000
+-#define HV_BUTTON_FROM_GD 0x00200000
+-#define REDUCED_DEBOUNCE 0x00400000
+-#define HV_CTRL_ENABLE 0x00800000
+-#define SPDIF_ENABLE 0x01000000
+-#define CLK_DIV_SELECT 0x06000000
+-#define CLK_DIV_BY_48 0x00000000
+-#define CLK_DIV_BY_49 0x02000000
+-#define CLK_DIV_BY_50 0x04000000
+-#define CLK_DIV_RESERVED 0x06000000
+-#define PM_CTRL_ENABLE 0x08000000
+-#define CLK_MULT_MODE_SELECT 0x30000000
+-#define CLK_MULT_MODE_SHIFT 28
+-#define CLK_MULT_MODE_0 0x00000000
+-#define CLK_MULT_MODE_1 0x10000000
+-#define CLK_MULT_MODE_2 0x20000000
+-#define CLK_MULT_MODE_3 0x30000000
+-#define INT_CLK_SELECT 0x40000000
+-#define INT_CLK_MULT_RESET 0x80000000
+-
+-// M3
+-#define INT_CLK_SRC_NOT_PCI 0x00100000
+-#define INT_CLK_MULT_ENABLE 0x80000000
+-
+-#define PCI_ACPI_CONTROL 0x54
+-#define PCI_ACPI_D0 0x00000000
+-#define PCI_ACPI_D1 0xB4F70000
+-#define PCI_ACPI_D2 0xB4F7B4F7
+-
+-#define PCI_USER_CONFIG 0x58
+-#define EXT_PCI_MASTER_ENABLE 0x00000001
+-#define SPDIF_OUT_SELECT 0x00000002
+-#define TEST_PIN_DIR_CTRL 0x00000004
+-#define AC97_CODEC_TEST 0x00000020
+-#define TRI_STATE_BUFFER 0x00000080
+-#define IN_CLK_12MHZ_SELECT 0x00000100
+-#define MULTI_FUNC_DISABLE 0x00000200
+-#define EXT_MASTER_PAIR_SEL 0x00000400
+-#define PCI_MASTER_SUPPORT 0x00000800
+-#define STOP_CLOCK_ENABLE 0x00001000
+-#define EAPD_DRIVE_ENABLE 0x00002000
+-#define REQ_TRI_STATE_ENABLE 0x00004000
+-#define REQ_LOW_ENABLE 0x00008000
+-#define MIDI_1_ENABLE 0x00010000
+-#define MIDI_2_ENABLE 0x00020000
+-#define SB_AUDIO_SYNC 0x00040000
+-#define HV_CTRL_TEST 0x00100000
+-#define SOUNDBLASTER_TEST 0x00400000
+-
+-#define PCI_USER_CONFIG_C 0x5C
+-
+-#define PCI_DDMA_CTRL 0x60
+-#define DDMA_ENABLE 0x00000001
+-
+-
+-// Allegro registers
+-#define HOST_INT_CTRL 0x18
+-#define SB_INT_ENABLE 0x0001
+-#define MPU401_INT_ENABLE 0x0002
+-#define ASSP_INT_ENABLE 0x0010
+-#define RING_INT_ENABLE 0x0020
+-#define HV_INT_ENABLE 0x0040
+-#define CLKRUN_GEN_ENABLE 0x0100
+-#define HV_CTRL_TO_PME 0x0400
+-#define SOFTWARE_RESET_ENABLE 0x8000
+-
+-/*
+- * should be using the above defines, probably.
+- */
+-#define REGB_ENABLE_RESET 0x01
+-#define REGB_STOP_CLOCK 0x10
+-
+-#define HOST_INT_STATUS 0x1A
+-#define SB_INT_PENDING 0x01
+-#define MPU401_INT_PENDING 0x02
+-#define ASSP_INT_PENDING 0x10
+-#define RING_INT_PENDING 0x20
+-#define HV_INT_PENDING 0x40
+-
+-#define HARDWARE_VOL_CTRL 0x1B
+-#define SHADOW_MIX_REG_VOICE 0x1C
+-#define HW_VOL_COUNTER_VOICE 0x1D
+-#define SHADOW_MIX_REG_MASTER 0x1E
+-#define HW_VOL_COUNTER_MASTER 0x1F
+-
+-#define CODEC_COMMAND 0x30
+-#define CODEC_READ_B 0x80
+-
+-#define CODEC_STATUS 0x30
+-#define CODEC_BUSY_B 0x01
+-
+-#define CODEC_DATA 0x32
+-
+-#define RING_BUS_CTRL_A 0x36
+-#define RAC_PME_ENABLE 0x0100
+-#define RAC_SDFS_ENABLE 0x0200
+-#define LAC_PME_ENABLE 0x0400
+-#define LAC_SDFS_ENABLE 0x0800
+-#define SERIAL_AC_LINK_ENABLE 0x1000
+-#define IO_SRAM_ENABLE 0x2000
+-#define IIS_INPUT_ENABLE 0x8000
+-
+-#define RING_BUS_CTRL_B 0x38
+-#define SECOND_CODEC_ID_MASK 0x0003
+-#define SPDIF_FUNC_ENABLE 0x0010
+-#define SECOND_AC_ENABLE 0x0020
+-#define SB_MODULE_INTF_ENABLE 0x0040
+-#define SSPE_ENABLE 0x0040
+-#define M3I_DOCK_ENABLE 0x0080
+-
+-#define SDO_OUT_DEST_CTRL 0x3A
+-#define COMMAND_ADDR_OUT 0x0003
+-#define PCM_LR_OUT_LOCAL 0x0000
+-#define PCM_LR_OUT_REMOTE 0x0004
+-#define PCM_LR_OUT_MUTE 0x0008
+-#define PCM_LR_OUT_BOTH 0x000C
+-#define LINE1_DAC_OUT_LOCAL 0x0000
+-#define LINE1_DAC_OUT_REMOTE 0x0010
+-#define LINE1_DAC_OUT_MUTE 0x0020
+-#define LINE1_DAC_OUT_BOTH 0x0030
+-#define PCM_CLS_OUT_LOCAL 0x0000
+-#define PCM_CLS_OUT_REMOTE 0x0040
+-#define PCM_CLS_OUT_MUTE 0x0080
+-#define PCM_CLS_OUT_BOTH 0x00C0
+-#define PCM_RLF_OUT_LOCAL 0x0000
+-#define PCM_RLF_OUT_REMOTE 0x0100
+-#define PCM_RLF_OUT_MUTE 0x0200
+-#define PCM_RLF_OUT_BOTH 0x0300
+-#define LINE2_DAC_OUT_LOCAL 0x0000
+-#define LINE2_DAC_OUT_REMOTE 0x0400
+-#define LINE2_DAC_OUT_MUTE 0x0800
+-#define LINE2_DAC_OUT_BOTH 0x0C00
+-#define HANDSET_OUT_LOCAL 0x0000
+-#define HANDSET_OUT_REMOTE 0x1000
+-#define HANDSET_OUT_MUTE 0x2000
+-#define HANDSET_OUT_BOTH 0x3000
+-#define IO_CTRL_OUT_LOCAL 0x0000
+-#define IO_CTRL_OUT_REMOTE 0x4000
+-#define IO_CTRL_OUT_MUTE 0x8000
+-#define IO_CTRL_OUT_BOTH 0xC000
+-
+-#define SDO_IN_DEST_CTRL 0x3C
+-#define STATUS_ADDR_IN 0x0003
+-#define PCM_LR_IN_LOCAL 0x0000
+-#define PCM_LR_IN_REMOTE 0x0004
+-#define PCM_LR_RESERVED 0x0008
+-#define PCM_LR_IN_BOTH 0x000C
+-#define LINE1_ADC_IN_LOCAL 0x0000
+-#define LINE1_ADC_IN_REMOTE 0x0010
+-#define LINE1_ADC_IN_MUTE 0x0020
+-#define MIC_ADC_IN_LOCAL 0x0000
+-#define MIC_ADC_IN_REMOTE 0x0040
+-#define MIC_ADC_IN_MUTE 0x0080
+-#define LINE2_DAC_IN_LOCAL 0x0000
+-#define LINE2_DAC_IN_REMOTE 0x0400
+-#define LINE2_DAC_IN_MUTE 0x0800
+-#define HANDSET_IN_LOCAL 0x0000
+-#define HANDSET_IN_REMOTE 0x1000
+-#define HANDSET_IN_MUTE 0x2000
+-#define IO_STATUS_IN_LOCAL 0x0000
+-#define IO_STATUS_IN_REMOTE 0x4000
+-
+-#define SPDIF_IN_CTRL 0x3E
+-#define SPDIF_IN_ENABLE 0x0001
+-
+-#define GPIO_DATA 0x60
+-#define GPIO_DATA_MASK 0x0FFF
+-#define GPIO_HV_STATUS 0x3000
+-#define GPIO_PME_STATUS 0x4000
+-
+-#define GPIO_MASK 0x64
+-#define GPIO_DIRECTION 0x68
+-#define GPO_PRIMARY_AC97 0x0001
+-#define GPI_LINEOUT_SENSE 0x0004
+-#define GPO_SECONDARY_AC97 0x0008
+-#define GPI_VOL_DOWN 0x0010
+-#define GPI_VOL_UP 0x0020
+-#define GPI_IIS_CLK 0x0040
+-#define GPI_IIS_LRCLK 0x0080
+-#define GPI_IIS_DATA 0x0100
+-#define GPI_DOCKING_STATUS 0x0100
+-#define GPI_HEADPHONE_SENSE 0x0200
+-#define GPO_EXT_AMP_SHUTDOWN 0x1000
+-
+-// M3
+-#define GPO_M3_EXT_AMP_SHUTDN 0x0002
+-
+-#define ASSP_INDEX_PORT 0x80
+-#define ASSP_MEMORY_PORT 0x82
+-#define ASSP_DATA_PORT 0x84
+-
+-#define MPU401_DATA_PORT 0x98
+-#define MPU401_STATUS_PORT 0x99
+-
+-#define CLK_MULT_DATA_PORT 0x9C
+-
+-#define ASSP_CONTROL_A 0xA2
+-#define ASSP_0_WS_ENABLE 0x01
+-#define ASSP_CTRL_A_RESERVED1 0x02
+-#define ASSP_CTRL_A_RESERVED2 0x04
+-#define ASSP_CLK_49MHZ_SELECT 0x08
+-#define FAST_PLU_ENABLE 0x10
+-#define ASSP_CTRL_A_RESERVED3 0x20
+-#define DSP_CLK_36MHZ_SELECT 0x40
+-
+-#define ASSP_CONTROL_B 0xA4
+-#define RESET_ASSP 0x00
+-#define RUN_ASSP 0x01
+-#define ENABLE_ASSP_CLOCK 0x00
+-#define STOP_ASSP_CLOCK 0x10
+-#define RESET_TOGGLE 0x40
+-
+-#define ASSP_CONTROL_C 0xA6
+-#define ASSP_HOST_INT_ENABLE 0x01
+-#define FM_ADDR_REMAP_DISABLE 0x02
+-#define HOST_WRITE_PORT_ENABLE 0x08
+-
+-#define ASSP_HOST_INT_STATUS 0xAC
+-#define DSP2HOST_REQ_PIORECORD 0x01
+-#define DSP2HOST_REQ_I2SRATE 0x02
+-#define DSP2HOST_REQ_TIMER 0x04
+-
+-// AC97 registers
+-// XXX fix this crap up
+-/*#define AC97_RESET 0x00*/
+-
+-#define AC97_VOL_MUTE_B 0x8000
+-#define AC97_VOL_M 0x1F
+-#define AC97_LEFT_VOL_S 8
+-
+-#define AC97_MASTER_VOL 0x02
+-#define AC97_LINE_LEVEL_VOL 0x04
+-#define AC97_MASTER_MONO_VOL 0x06
+-#define AC97_PC_BEEP_VOL 0x0A
+-#define AC97_PC_BEEP_VOL_M 0x0F
+-#define AC97_SROUND_MASTER_VOL 0x38
+-#define AC97_PC_BEEP_VOL_S 1
+-
+-/*#define AC97_PHONE_VOL 0x0C
+-#define AC97_MIC_VOL 0x0E*/
+-#define AC97_MIC_20DB_ENABLE 0x40
+-
+-/*#define AC97_LINEIN_VOL 0x10
+-#define AC97_CD_VOL 0x12
+-#define AC97_VIDEO_VOL 0x14
+-#define AC97_AUX_VOL 0x16*/
+-#define AC97_PCM_OUT_VOL 0x18
+-/*#define AC97_RECORD_SELECT 0x1A*/
+-#define AC97_RECORD_MIC 0x00
+-#define AC97_RECORD_CD 0x01
+-#define AC97_RECORD_VIDEO 0x02
+-#define AC97_RECORD_AUX 0x03
+-#define AC97_RECORD_MONO_MUX 0x02
+-#define AC97_RECORD_DIGITAL 0x03
+-#define AC97_RECORD_LINE 0x04
+-#define AC97_RECORD_STEREO 0x05
+-#define AC97_RECORD_MONO 0x06
+-#define AC97_RECORD_PHONE 0x07
+-
+-/*#define AC97_RECORD_GAIN 0x1C*/
+-#define AC97_RECORD_VOL_M 0x0F
+-
+-/*#define AC97_GENERAL_PURPOSE 0x20*/
+-#define AC97_POWER_DOWN_CTRL 0x26
+-#define AC97_ADC_READY 0x0001
+-#define AC97_DAC_READY 0x0002
+-#define AC97_ANALOG_READY 0x0004
+-#define AC97_VREF_ON 0x0008
+-#define AC97_PR0 0x0100
+-#define AC97_PR1 0x0200
+-#define AC97_PR2 0x0400
+-#define AC97_PR3 0x0800
+-#define AC97_PR4 0x1000
+-
+-#define AC97_RESERVED1 0x28
+-
+-#define AC97_VENDOR_TEST 0x5A
+-
+-#define AC97_CLOCK_DELAY 0x5C
+-#define AC97_LINEOUT_MUX_SEL 0x0001
+-#define AC97_MONO_MUX_SEL 0x0002
+-#define AC97_CLOCK_DELAY_SEL 0x1F
+-#define AC97_DAC_CDS_SHIFT 6
+-#define AC97_ADC_CDS_SHIFT 11
+-
+-#define AC97_MULTI_CHANNEL_SEL 0x74
+-
+-/*#define AC97_VENDOR_ID1 0x7C
+-#define AC97_VENDOR_ID2 0x7E*/
+-
+-/*
+- * ASSP control regs
+- */
+-#define DSP_PORT_TIMER_COUNT 0x06
+-
+-#define DSP_PORT_MEMORY_INDEX 0x80
+-
+-#define DSP_PORT_MEMORY_TYPE 0x82
+-#define MEMTYPE_INTERNAL_CODE 0x0002
+-#define MEMTYPE_INTERNAL_DATA 0x0003
+-#define MEMTYPE_MASK 0x0003
+-
+-#define DSP_PORT_MEMORY_DATA 0x84
+-
+-#define DSP_PORT_CONTROL_REG_A 0xA2
+-#define DSP_PORT_CONTROL_REG_B 0xA4
+-#define DSP_PORT_CONTROL_REG_C 0xA6
+-
+-#define REV_A_CODE_MEMORY_BEGIN 0x0000
+-#define REV_A_CODE_MEMORY_END 0x0FFF
+-#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040
+-#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
+-
+-#define REV_B_CODE_MEMORY_BEGIN 0x0000
+-#define REV_B_CODE_MEMORY_END 0x0BFF
+-#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040
+-#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
+-
+-#define REV_A_DATA_MEMORY_BEGIN 0x1000
+-#define REV_A_DATA_MEMORY_END 0x2FFF
+-#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080
+-#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
+-
+-#define REV_B_DATA_MEMORY_BEGIN 0x1000
+-#define REV_B_DATA_MEMORY_END 0x2BFF
+-#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080
+-#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
+-
+-
+-#define NUM_UNITS_KERNEL_CODE 16
+-#define NUM_UNITS_KERNEL_DATA 2
+-
+-#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
+-#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5
+-
+-/*
+- * Kernel data layout
+- */
+-
+-#define DP_SHIFT_COUNT 7
+-
+-#define KDATA_BASE_ADDR 0x1000
+-#define KDATA_BASE_ADDR2 0x1080
+-
+-#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000)
+-#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001)
+-#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002)
+-#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003)
+-#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004)
+-#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005)
+-#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006)
+-#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007)
+-#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008)
+-
+-#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009)
+-#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A)
+-
+-#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B)
+-#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C)
+-#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D)
+-#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E)
+-#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F)
+-#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010)
+-#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011)
+-#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012)
+-#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013)
+-#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014)
+-
+-#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015)
+-#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016)
+-
+-#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017)
+-#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018)
+-
+-#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019)
+-#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A)
+-
+-#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B)
+-#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C)
+-#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D)
+-
+-#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E)
+-#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F)
+-#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020)
+-#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021)
+-#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022)
+-
+-#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023)
+-#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024)
+-#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025)
+-
+-#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026)
+-#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027)
+-#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028)
+-
+-#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029)
+-#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A)
+-#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B)
+-#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C)
+-#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D)
+-#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E)
+-#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F)
+-#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030)
+-#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031)
+-#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032)
+-
+-#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033)
+-#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034)
+-#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035)
+-
+-#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036)
+-#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037)
+-
+-#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038)
+-#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039)
+-#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A)
+-
+-#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B)
+-#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C)
+-#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D)
+-#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E)
+-#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F)
+-#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040)
+-
+-#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041)
+-#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042)
+-#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043)
+-#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044)
+-#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045)
+-#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046)
+-
+-#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047)
+-#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048)
+-#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049)
+-#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A)
+-#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B)
+-#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C)
+-
+-#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D)
+-#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E)
+-#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F)
+-#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050)
+-
+-#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051)
+-#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052)
+-
+-#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053)
+-#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054)
+-
+-#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055)
+-#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056)
+-#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057)
+-#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058)
+-#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059)
+-
+-#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A)
+-#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B)
+-
+-#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C)
+-#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D)
+-#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E)
+-
+-#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F)
+-#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060)
+-
+-#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061)
+-
+-#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062)
+-#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063)
+-#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064)
+-#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065)
+-#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066)
+-#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067)
+-#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068)
+-#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069)
+-#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A)
+-#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B)
+-#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C)
+-#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D)
+-
+-#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E)
+-#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F)
+-#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070)
+-#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071)
+-
+-#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072)
+-#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073)
+-
+-#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074)
+-#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075)
+-#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076)
+-#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077)
+-
+-#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078)
+-#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079)
+-#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A)
+-#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B)
+-#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C)
+-
+-/*
+- * second 'segment' (?) reserved for mixer
+- * buffers..
+- */
+-
+-#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000)
+-#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001)
+-#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002)
+-#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003)
+-#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004)
+-#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005)
+-#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006)
+-#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007)
+-#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008)
+-#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009)
+-#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A)
+-#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B)
+-#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C)
+-#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D)
+-#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E)
+-#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F)
+-
+-#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010)
+-#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011)
+-#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012)
+-#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013)
+-#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014)
+-#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015)
+-#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016)
+-#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017)
+-#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018)
+-#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019)
+-#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A)
+-
+-#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B)
+-#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C)
+-#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D)
+-#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E)
+-#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F)
+-#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020)
+-
+-#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
+-#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
+-#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
+-#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
+-
+-/*
+- * client data area offsets
+- */
+-#define CDATA_INSTANCE_READY 0x00
+-
+-#define CDATA_HOST_SRC_ADDRL 0x01
+-#define CDATA_HOST_SRC_ADDRH 0x02
+-#define CDATA_HOST_SRC_END_PLUS_1L 0x03
+-#define CDATA_HOST_SRC_END_PLUS_1H 0x04
+-#define CDATA_HOST_SRC_CURRENTL 0x05
+-#define CDATA_HOST_SRC_CURRENTH 0x06
+-
+-#define CDATA_IN_BUF_CONNECT 0x07
+-#define CDATA_OUT_BUF_CONNECT 0x08
+-
+-#define CDATA_IN_BUF_BEGIN 0x09
+-#define CDATA_IN_BUF_END_PLUS_1 0x0A
+-#define CDATA_IN_BUF_HEAD 0x0B
+-#define CDATA_IN_BUF_TAIL 0x0C
+-#define CDATA_OUT_BUF_BEGIN 0x0D
+-#define CDATA_OUT_BUF_END_PLUS_1 0x0E
+-#define CDATA_OUT_BUF_HEAD 0x0F
+-#define CDATA_OUT_BUF_TAIL 0x10
+-
+-#define CDATA_DMA_CONTROL 0x11
+-#define CDATA_RESERVED 0x12
+-
+-#define CDATA_FREQUENCY 0x13
+-#define CDATA_LEFT_VOLUME 0x14
+-#define CDATA_RIGHT_VOLUME 0x15
+-#define CDATA_LEFT_SUR_VOL 0x16
+-#define CDATA_RIGHT_SUR_VOL 0x17
+-
+-#define CDATA_HEADER_LEN 0x18
+-
+-#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN
+-#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1)
+-#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2)
+-#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3)
+-#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8)
+-#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10)
+-#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16)
+-#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17)
+-
+-#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 )
+-#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
+-#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
+-#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
+-#define MINISRC_BIQUAD_STAGE 2
+-#define MINISRC_COEF_LOC 0X175
+-
+-#define DMACONTROL_BLOCK_MASK 0x000F
+-#define DMAC_BLOCK0_SELECTOR 0x0000
+-#define DMAC_BLOCK1_SELECTOR 0x0001
+-#define DMAC_BLOCK2_SELECTOR 0x0002
+-#define DMAC_BLOCK3_SELECTOR 0x0003
+-#define DMAC_BLOCK4_SELECTOR 0x0004
+-#define DMAC_BLOCK5_SELECTOR 0x0005
+-#define DMAC_BLOCK6_SELECTOR 0x0006
+-#define DMAC_BLOCK7_SELECTOR 0x0007
+-#define DMAC_BLOCK8_SELECTOR 0x0008
+-#define DMAC_BLOCK9_SELECTOR 0x0009
+-#define DMAC_BLOCKA_SELECTOR 0x000A
+-#define DMAC_BLOCKB_SELECTOR 0x000B
+-#define DMAC_BLOCKC_SELECTOR 0x000C
+-#define DMAC_BLOCKD_SELECTOR 0x000D
+-#define DMAC_BLOCKE_SELECTOR 0x000E
+-#define DMAC_BLOCKF_SELECTOR 0x000F
+-#define DMACONTROL_PAGE_MASK 0x00F0
+-#define DMAC_PAGE0_SELECTOR 0x0030
+-#define DMAC_PAGE1_SELECTOR 0x0020
+-#define DMAC_PAGE2_SELECTOR 0x0010
+-#define DMAC_PAGE3_SELECTOR 0x0000
+-#define DMACONTROL_AUTOREPEAT 0x1000
+-#define DMACONTROL_STOPPED 0x2000
+-#define DMACONTROL_DIRECTION 0x0100
+-
+-
+-/*
+- * DSP Code images
+- */
+-
+-static u16 assp_kernel_image[] = {
+- 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4,
+- 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
+- 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
+- 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4,
+- 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08,
+- 0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909,
+- 0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41,
+- 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308,
+- 0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910,
+- 0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00,
+- 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026,
+- 0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0,
+- 0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012,
+- 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A,
+- 0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000,
+- 0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05,
+- 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26,
+- 0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300,
+- 0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88,
+- 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008,
+- 0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80,
+- 0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71,
+- 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A,
+- 0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100,
+- 0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900,
+- 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903,
+- 0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309,
+- 0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B,
+- 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540,
+- 0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C,
+- 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380,
+- 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340,
+- 0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041,
+- 0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18,
+- 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40,
+- 0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9,
+- 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8,
+- 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A,
+- 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80,
+- 0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40,
+- 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80,
+- 0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A,
+- 0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F,
+- 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1,
+- 0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034,
+- 0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E,
+- 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977,
+- 0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B,
+- 0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388,
+- 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80,
+- 0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473,
+- 0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473,
+- 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880,
+- 0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80,
+- 0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6,
+- 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909,
+- 0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED,
+- 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005,
+- 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388,
+- 0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4,
+- 0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100,
+- 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10,
+- 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070,
+- 0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71,
+- 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A,
+- 0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061,
+- 0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A,
+- 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6,
+- 0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A,
+- 0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6,
+- 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358,
+- 0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6,
+- 0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9,
+- 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379,
+- 0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6,
+- 0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C,
+- 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166,
+- 0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B,
+- 0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A,
+- 0xBE3A,
+-};
+-
+-/*
+- * Mini sample rate converter code image
+- * that is to be loaded at 0x400 on the DSP.
+- */
+-static u16 assp_minisrc_image[] = {
+-
+- 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412,
+- 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41,
+- 0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907,
+- 0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01,
+- 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904,
+- 0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D,
+- 0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD,
+- 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22,
+- 0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0,
+- 0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9,
+- 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89,
+- 0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0,
+- 0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484,
+- 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80,
+- 0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624,
+- 0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4,
+- 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027,
+- 0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903,
+- 0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809,
+- 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46,
+- 0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47,
+- 0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0,
+- 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516,
+- 0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E,
+- 0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C,
+- 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180,
+- 0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E,
+- 0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0,
+- 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0,
+- 0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0,
+- 0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F,
+- 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+-};
+-
+diff --git a/sound/oss/maui.c b/sound/oss/maui.c
+deleted file mode 100644
+index 05cf194..0000000
+--- a/sound/oss/maui.c
++++ /dev/null
+@@ -1,478 +0,0 @@
+-/*
+- * sound/maui.c
+- *
+- * The low level driver for Turtle Beach Maui and Tropez.
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- * Changes:
+- * Alan Cox General clean up, use kernel IRQ
+- * system
+- * Christoph Hellwig Adapted to module_init/module_exit
+- * Bartlomiej Zolnierkiewicz
+- * Added __init to download_code()
+- *
+- * Status:
+- * Andrew J. Kroll Tested 06/01/1999 with:
+- * * OSWF.MOT File Version: 1.15
+- * * OSWF.MOT File Dated: 09/12/94
+- * * Older versions will cause problems.
+- */
+-
+-#include <linux/interrupt.h>
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-
+-#define USE_SEQ_MACROS
+-#define USE_SIMPLE_MACROS
+-
+-#include "sound_config.h"
+-#include "sound_firmware.h"
+-
+-#include "mpu401.h"
+-
+-static int maui_base = 0x330;
+-
+-static volatile int irq_ok;
+-static int *maui_osp;
+-
+-#define HOST_DATA_PORT (maui_base + 2)
+-#define HOST_STAT_PORT (maui_base + 3)
+-#define HOST_CTRL_PORT (maui_base + 3)
+-
+-#define STAT_TX_INTR 0x40
+-#define STAT_TX_AVAIL 0x20
+-#define STAT_TX_IENA 0x10
+-#define STAT_RX_INTR 0x04
+-#define STAT_RX_AVAIL 0x02
+-#define STAT_RX_IENA 0x01
+-
+-static int (*orig_load_patch)(int dev, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag) = NULL;
+-
+-#include "maui_boot.h"
+-
+-static int maui_wait(int mask)
+-{
+- int i;
+-
+- /*
+- * Perform a short initial wait without sleeping
+- */
+-
+- for (i = 0; i < 100; i++)
+- if (inb(HOST_STAT_PORT) & mask)
+- return 1;
+-
+- /*
+- * Wait up to 15 seconds with sleeping
+- */
+-
+- for (i = 0; i < 150; i++) {
+- if (inb(HOST_STAT_PORT) & mask)
+- return 1;
+- current->state = TASK_INTERRUPTIBLE;
+- schedule_timeout(HZ / 10);
+- if (signal_pending(current))
+- return 0;
+- }
+- return 0;
+-}
+-
+-static int maui_read(void)
+-{
+- if (maui_wait(STAT_RX_AVAIL))
+- return inb(HOST_DATA_PORT);
+- return -1;
+-}
+-
+-static int maui_write(unsigned char data)
+-{
+- if (maui_wait(STAT_TX_AVAIL)) {
+- outb((data), HOST_DATA_PORT);
+- return 1;
+- }
+- printk(KERN_WARNING "Maui: Write timeout\n");
+- return 0;
+-}
+-
+-static irqreturn_t mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
+-{
+- irq_ok = 1;
+- return IRQ_HANDLED;
+-}
+-
+-static int __init download_code(void)
+-{
+- int i, lines = 0;
+- int eol_seen = 0, done = 0;
+- int skip = 1;
+-
+- printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
+-
+- for (i = 0; i < maui_osLen; i++) {
+- if (maui_os[i] != '\r') {
+- if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
+- skip = 0;
+-
+- if (maui_os[i] == '\n')
+- eol_seen = skip = 1;
+- else if (maui_os[i] == 'S') {
+- if (maui_os[i + 1] == '8')
+- done = 1;
+- if (!maui_write(0xF1))
+- goto failure;
+- if (!maui_write('S'))
+- goto failure;
+- } else {
+- if (!maui_write(maui_os[i]))
+- goto failure;
+- }
+-
+- if (eol_seen) {
+- int c = 0;
+- int n;
+-
+- eol_seen = 0;
+-
+- for (n = 0; n < 2; n++) {
+- if (maui_wait(STAT_RX_AVAIL)) {
+- c = inb(HOST_DATA_PORT);
+- break;
+- }
+- }
+- if (c != 0x80) {
+- printk("Download not acknowledged\n");
+- return 0;
+- }
+- else if (!(lines++ % 10))
+- printk(".");
+-
+- if (done) {
+- printk("\n");
+- printk(KERN_INFO "Download complete\n");
+- return 1;
+- }
+- }
+- }
+- }
+- }
+-
+-failure:
+- printk("\n");
+- printk(KERN_ERR "Download failed!!!\n");
+- return 0;
+-}
+-
+-static int __init maui_init(int irq)
+-{
+- unsigned char bits;
+-
+- switch (irq) {
+- case 9:
+- bits = 0x00;
+- break;
+- case 5:
+- bits = 0x08;
+- break;
+- case 12:
+- bits = 0x10;
+- break;
+- case 15:
+- bits = 0x18;
+- break;
+-
+- default:
+- printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq);
+- return 0;
+- }
+- outb((0x00), HOST_CTRL_PORT); /* Reset */
+- outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */
+- outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
+- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
+- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
+- outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
+-
+-#ifdef CONFIG_SMP
+- {
+- int i;
+- for (i = 0; i < 1000000 && !irq_ok; i++)
+- ;
+- if (!irq_ok)
+- return 0;
+- }
+-#endif
+- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
+-
+- printk(KERN_INFO "Turtle Beach Maui initialization\n");
+-
+- if (!download_code())
+- return 0;
+-
+- outb((0xE0), HOST_CTRL_PORT); /* Normal operation */
+-
+- /* Select mpu401 mode */
+-
+- maui_write(0xf0);
+- maui_write(1);
+- if (maui_read() != 0x80) {
+- maui_write(0xf0);
+- maui_write(1);
+- if (maui_read() != 0x80)
+- printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n");
+- }
+- printk(KERN_INFO "Maui initialized OK\n");
+- return 1;
+-}
+-
+-static int maui_short_wait(int mask) {
+- int i;
+-
+- for (i = 0; i < 1000; i++) {
+- if (inb(HOST_STAT_PORT) & mask) {
+- return 1;
+- }
+- }
+- return 0;
+-}
+-
+-static int maui_load_patch(int dev, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag)
+-{
+-
+- struct sysex_info header;
+- unsigned long left, src_offs;
+- int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
+- int i;
+-
+- if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
+- return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
+-
+- if (format != MAUI_PATCH)
+- {
+- printk(KERN_WARNING "Maui: Unknown patch format\n");
+- }
+- if (count < hdr_size) {
+-/* printk("Maui error: Patch header too short\n");*/
+- return -EINVAL;
+- }
+- count -= hdr_size;
+-
+- /*
+- * Copy the header from user space but ignore the first bytes which have
+- * been transferred already.
+- */
+-
+- if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
+- return -EFAULT;
+-
+- if (count < header.len) {
+- printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
+- header.len = count;
+- }
+- left = header.len;
+- src_offs = 0;
+-
+- for (i = 0; i < left; i++) {
+- unsigned char data;
+-
+- if(get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])))
+- return -EFAULT;
+- if (i == 0 && !(data & 0x80))
+- return -EINVAL;
+-
+- if (maui_write(data) == -1)
+- return -EIO;
+- }
+-
+- if ((i = maui_read()) != 0x80) {
+- if (i != -1)
+- printk("Maui: Error status %02x\n", i);
+- return -EIO;
+- }
+- return 0;
+-}
+-
+-static int __init probe_maui(struct address_info *hw_config)
+-{
+- struct resource *ports;
+- int this_dev;
+- int i;
+- int tmp1, tmp2, ret;
+-
+- ports = request_region(hw_config->io_base, 2, "mpu401");
+- if (!ports)
+- return 0;
+-
+- if (!request_region(hw_config->io_base + 2, 6, "Maui"))
+- goto out;
+-
+- maui_base = hw_config->io_base;
+- maui_osp = hw_config->osp;
+-
+- if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
+- goto out2;
+-
+- /*
+- * Initialize the processor if necessary
+- */
+-
+- if (maui_osLen > 0) {
+- if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
+- !maui_write(0x9F) || /* Report firmware version */
+- !maui_short_wait(STAT_RX_AVAIL) ||
+- maui_read() == -1 || maui_read() == -1)
+- if (!maui_init(hw_config->irq))
+- goto out3;
+- }
+- if (!maui_write(0xCF)) /* Report hardware version */ {
+- printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
+- goto out3;
+- }
+- if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
+- printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
+- goto out3;
+- }
+- if (tmp1 == 0xff || tmp2 == 0xff)
+- goto out3;
+- printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
+-
+- if (!maui_write(0x9F)) /* Report firmware version */
+- goto out3;
+- if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
+- goto out3;
+-
+- printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
+-
+- if (!maui_write(0x85)) /* Report free DRAM */
+- goto out3;
+- tmp1 = 0;
+- for (i = 0; i < 4; i++) {
+- tmp1 |= maui_read() << (7 * i);
+- }
+- printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
+-
+- for (i = 0; i < 1000; i++)
+- if (probe_mpu401(hw_config, ports))
+- break;
+-
+- ret = probe_mpu401(hw_config, ports);
+- if (!ret)
+- goto out3;
+-
+- conf_printf("Maui", hw_config);
+-
+- hw_config->irq *= -1;
+- hw_config->name = "Maui";
+- attach_mpu401(hw_config, THIS_MODULE);
+-
+- if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ {
+- struct synth_operations *synth;
+-
+- this_dev = hw_config->slots[1];
+-
+- /*
+- * Intercept patch loading calls so that they can be handled
+- * by the Maui driver.
+- */
+-
+- synth = midi_devs[this_dev]->converter;
+- if (synth != NULL) {
+- synth->id = "MAUI";
+- orig_load_patch = synth->load_patch;
+- synth->load_patch = &maui_load_patch;
+- } else
+- printk(KERN_ERR "Maui: Can't install patch loader\n");
+- }
+- return 1;
+-
+-out3:
+- free_irq(hw_config->irq, NULL);
+-out2:
+- release_region(hw_config->io_base + 2, 6);
+-out:
+- release_region(hw_config->io_base, 2);
+- return 0;
+-}
+-
+-static void __exit unload_maui(struct address_info *hw_config)
+-{
+- int irq = hw_config->irq;
+- release_region(hw_config->io_base + 2, 6);
+- unload_mpu401(hw_config);
+-
+- if (irq < 0)
+- irq = -irq;
+- if (irq > 0)
+- free_irq(irq, NULL);
+-}
+-
+-static int fw_load;
+-
+-static struct address_info cfg;
+-
+-static int __initdata io = -1;
+-static int __initdata irq = -1;
+-
+-module_param(io, int, 0);
+-module_param(irq, int, 0);
+-
+-/*
+- * Install a Maui card. Needs mpu401 loaded already.
+- */
+-
+-static int __init init_maui(void)
+-{
+- printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
+-
+- cfg.io_base = io;
+- cfg.irq = irq;
+-
+- if (cfg.io_base == -1 || cfg.irq == -1) {
+- printk(KERN_INFO "maui: irq and io must be set.\n");
+- return -EINVAL;
+- }
+-
+- if (maui_os == NULL) {
+- fw_load = 1;
+- maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
+- }
+- if (probe_maui(&cfg) == 0)
+- return -ENODEV;
+-
+- return 0;
+-}
+-
+-static void __exit cleanup_maui(void)
+-{
+- if (fw_load && maui_os)
+- vfree(maui_os);
+- unload_maui(&cfg);
+-}
+-
+-module_init(init_maui);
+-module_exit(cleanup_maui);
+-
+-#ifndef MODULE
+-static int __init setup_maui(char *str)
+-{
+- /* io, irq */
+- int ints[3];
+-
+- str = get_options(str, ARRAY_SIZE(ints), ints);
+-
+- io = ints[1];
+- irq = ints[2];
+-
+- return 1;
+-}
+-
+-__setup("maui=", setup_maui);
+-#endif
+-MODULE_LICENSE("GPL");
+diff --git a/sound/oss/midi_syms.c b/sound/oss/midi_syms.c
+deleted file mode 100644
+index 5b146dd..0000000
+--- a/sound/oss/midi_syms.c
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * Exported symbols for midi driver.
+- */
+-
+-#include <linux/module.h>
+-
+-char midi_syms_symbol;
+-
+-#include "sound_config.h"
+-#define _MIDI_SYNTH_C_
+-#include "midi_synth.h"
+-
+-EXPORT_SYMBOL(do_midi_msg);
+-EXPORT_SYMBOL(midi_synth_open);
+-EXPORT_SYMBOL(midi_synth_close);
+-EXPORT_SYMBOL(midi_synth_ioctl);
+-EXPORT_SYMBOL(midi_synth_kill_note);
+-EXPORT_SYMBOL(midi_synth_start_note);
+-EXPORT_SYMBOL(midi_synth_set_instr);
+-EXPORT_SYMBOL(midi_synth_reset);
+-EXPORT_SYMBOL(midi_synth_hw_control);
+-EXPORT_SYMBOL(midi_synth_aftertouch);
+-EXPORT_SYMBOL(midi_synth_controller);
+-EXPORT_SYMBOL(midi_synth_panning);
+-EXPORT_SYMBOL(midi_synth_setup_voice);
+-EXPORT_SYMBOL(midi_synth_send_sysex);
+-EXPORT_SYMBOL(midi_synth_bender);
+-EXPORT_SYMBOL(midi_synth_load_patch);
+-EXPORT_SYMBOL(MIDIbuf_avail);
+diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
+index 972edc6..9e45098 100644
+--- a/sound/oss/midi_synth.c
++++ b/sound/oss/midi_synth.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/midi_synth.c
++ * sound/oss/midi_synth.c
+ *
+ * High level midi sequencer manager for dumb MIDI interfaces.
+ */
+@@ -84,6 +84,7 @@ do_midi_msg(int synthno, unsigned char *
+ ;
+ }
+ }
++EXPORT_SYMBOL(do_midi_msg);
+
+ static void
+ midi_outc(int midi_dev, int data)
+@@ -276,6 +277,7 @@ int midi_synth_ioctl(int dev, unsigned i
+ return -EINVAL;
+ }
+ }
++EXPORT_SYMBOL(midi_synth_ioctl);
+
+ int
+ midi_synth_kill_note(int dev, int channel, int note, int velocity)
+@@ -342,6 +344,7 @@ midi_synth_kill_note(int dev, int channe
+
+ return 0;
+ }
++EXPORT_SYMBOL(midi_synth_kill_note);
+
+ int
+ midi_synth_set_instr(int dev, int channel, int instr_no)
+@@ -364,6 +367,7 @@ midi_synth_set_instr(int dev, int channe
+
+ return 0;
+ }
++EXPORT_SYMBOL(midi_synth_set_instr);
+
+ int
+ midi_synth_start_note(int dev, int channel, int note, int velocity)
+@@ -405,6 +409,7 @@ midi_synth_start_note(int dev, int chann
+ }
+ return 0;
+ }
++EXPORT_SYMBOL(midi_synth_start_note);
+
+ void
+ midi_synth_reset(int dev)
+@@ -412,6 +417,7 @@ midi_synth_reset(int dev)
+
+ leave_sysex(dev);
+ }
++EXPORT_SYMBOL(midi_synth_reset);
+
+ int
+ midi_synth_open(int dev, int mode)
+@@ -444,6 +450,7 @@ midi_synth_open(int dev, int mode)
+
+ return 1;
+ }
++EXPORT_SYMBOL(midi_synth_open);
+
+ void
+ midi_synth_close(int dev)
+@@ -459,11 +466,13 @@ midi_synth_close(int dev)
+
+ midi_devs[orig_dev]->close(orig_dev);
+ }
++EXPORT_SYMBOL(midi_synth_close);
+
+ void
+ midi_synth_hw_control(int dev, unsigned char *event)
+ {
+ }
++EXPORT_SYMBOL(midi_synth_hw_control);
+
+ int
+ midi_synth_load_patch(int dev, int format, const char __user *addr,
+@@ -542,11 +551,13 @@ midi_synth_load_patch(int dev, int forma
+ midi_outc(orig_dev, 0xf7);
+ return 0;
+ }
+-
++EXPORT_SYMBOL(midi_synth_load_patch);
++
+ void midi_synth_panning(int dev, int channel, int pressure)
+ {
+ }
+-
++EXPORT_SYMBOL(midi_synth_panning);
++
+ void midi_synth_aftertouch(int dev, int channel, int pressure)
+ {
+ int orig_dev = synth_devs[dev]->midi_dev;
+@@ -576,6 +587,7 @@ void midi_synth_aftertouch(int dev, int
+
+ midi_outc(orig_dev, pressure);
+ }
++EXPORT_SYMBOL(midi_synth_aftertouch);
+
+ void
+ midi_synth_controller(int dev, int channel, int ctrl_num, int value)
+@@ -604,6 +616,7 @@ midi_synth_controller(int dev, int chann
+ midi_outc(orig_dev, ctrl_num);
+ midi_outc(orig_dev, value & 0x7f);
+ }
++EXPORT_SYMBOL(midi_synth_controller);
+
+ void
+ midi_synth_bender(int dev, int channel, int value)
+@@ -635,11 +648,13 @@ midi_synth_bender(int dev, int channel,
+ midi_outc(orig_dev, value & 0x7f);
+ midi_outc(orig_dev, (value >> 7) & 0x7f);
+ }
++EXPORT_SYMBOL(midi_synth_bender);
+
+ void
+ midi_synth_setup_voice(int dev, int voice, int channel)
+ {
+ }
++EXPORT_SYMBOL(midi_synth_setup_voice);
+
+ int
+ midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
+@@ -695,3 +710,5 @@ midi_synth_send_sysex(int dev, unsigned
+
+ return 0;
+ }
++EXPORT_SYMBOL(midi_synth_send_sysex);
++
+diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
+index 6982556..a40be0c 100644
+--- a/sound/oss/midibuf.c
++++ b/sound/oss/midibuf.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/midibuf.c
++ * sound/oss/midibuf.c
+ *
+ * Device file manager for /dev/midi#
+ */
+@@ -414,18 +414,11 @@ unsigned int MIDIbuf_poll(int dev, struc
+ }
+
+
+-void MIDIbuf_init(void)
+-{
+- /* drag in midi_syms.o */
+- {
+- extern char midi_syms_symbol;
+- midi_syms_symbol = 0;
+- }
+-}
+-
+ int MIDIbuf_avail(int dev)
+ {
+ if (midi_in_buf[dev])
+ return DATA_AVAIL (midi_in_buf[dev]);
+ return 0;
+ }
++EXPORT_SYMBOL(MIDIbuf_avail);
++
+diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
+index 0aac54c..e962205 100644
+--- a/sound/oss/mpu401.c
++++ b/sound/oss/mpu401.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/mpu401.c
++ * sound/oss/mpu401.c
+ *
+ * The low level driver for Roland MPU-401 compatible Midi cards.
+ */
+@@ -432,19 +432,10 @@ static void mpu401_input_loop(struct mpu
+ devc->m_busy = 0;
+ }
+
+-int intchk_mpu401(void *dev_id)
++static irqreturn_t mpuintr(int irq, void *dev_id)
+ {
+ struct mpu_config *devc;
+- int dev = (int) dev_id;
+-
+- devc = &dev_conf[dev];
+- return input_avail(devc);
+-}
+-
+-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+-{
+- struct mpu_config *devc;
+- int dev = (int) dev_id;
++ int dev = (int)(unsigned long) dev_id;
+ int handled = 0;
+
+ devc = &dev_conf[dev];
+@@ -1761,8 +1752,6 @@ static int mpu_timer_init(int midi_dev)
+ EXPORT_SYMBOL(probe_mpu401);
+ EXPORT_SYMBOL(attach_mpu401);
+ EXPORT_SYMBOL(unload_mpu401);
+-EXPORT_SYMBOL(intchk_mpu401);
+-EXPORT_SYMBOL(mpuintr);
+
+ static struct address_info cfg;
+
+diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h
+index bdc5bde..0ad1e9e 100644
+--- a/sound/oss/mpu401.h
++++ b/sound/oss/mpu401.h
+@@ -3,12 +3,9 @@
+ int probe_uart401 (struct address_info *hw_config, struct module *owner);
+ void unload_uart401 (struct address_info *hw_config);
+
+-irqreturn_t uart401intr (int irq, void *dev_id, struct pt_regs * dummy);
++irqreturn_t uart401intr (int irq, void *dev_id);
+
+ /* From mpu401.c */
+ int probe_mpu401(struct address_info *hw_config, struct resource *ports);
+ int attach_mpu401(struct address_info * hw_config, struct module *owner);
+ void unload_mpu401(struct address_info *hw_info);
+-
+-int intchk_mpu401(void *dev_id);
+-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
+diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
+index 6d7763d..d514679 100644
+--- a/sound/oss/msnd_pinnacle.c
++++ b/sound/oss/msnd_pinnacle.c
+@@ -1087,7 +1087,7 @@ static __inline__ void eval_dsp_msg(regi
+ }
+ }
+
+-static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t intr(int irq, void *dev_id)
+ {
+ /* Send ack to DSP */
+ msnd_inb(dev.io + HP_RXL);
+diff --git a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c
+index 6f7f2f0..da9728e 100644
+--- a/sound/oss/nec_vrc5477.c
++++ b/sound/oss/nec_vrc5477.c
+@@ -848,7 +848,7 @@ static inline void vrc5477_ac97_dac_inte
+ wake_up_interruptible(&dac->wait);
+ }
+
+-static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id)
+ {
+ struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)dev_id;
+ u32 irqStatus;
+diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h
+index 21e07b5..1dade90 100644
+--- a/sound/oss/nm256.h
++++ b/sound/oss/nm256.h
+@@ -115,7 +115,7 @@ struct nm256_info
+ int has_irq;
+
+ /* The card interrupt service routine. */
+- irqreturn_t (*introutine) (int, void *, struct pt_regs *);
++ irq_handler_t introutine;
+
+ /* Current audio config, cached. */
+ struct sinfo {
+diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
+index 7760ddd..44cd155 100644
+--- a/sound/oss/nm256_audio.c
++++ b/sound/oss/nm256_audio.c
+@@ -45,8 +45,8 @@ static struct audio_driver nm256_audio_d
+
+ static int nm256_grabInterrupt (struct nm256_info *card);
+ static int nm256_releaseInterrupt (struct nm256_info *card);
+-static irqreturn_t nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy);
+-static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy);
++static irqreturn_t nm256_interrupt (int irq, void *dev_id);
++static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id);
+
+ /* These belong in linux/pci.h. */
+ #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
+@@ -526,7 +526,7 @@ nm256_initHw (struct nm256_info *card)
+ */
+
+ static irqreturn_t
+-nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
++nm256_interrupt (int irq, void *dev_id)
+ {
+ struct nm256_info *card = (struct nm256_info *)dev_id;
+ u16 status;
+@@ -629,7 +629,7 @@ nm256_interrupt (int irq, void *dev_id,
+ */
+
+ static irqreturn_t
+-nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
++nm256_interrupt_zx (int irq, void *dev_id)
+ {
+ struct nm256_info *card = (struct nm256_info *)dev_id;
+ u32 status;
+diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c
+index a31734b..4799bc7 100644
+--- a/sound/oss/opl3.c
++++ b/sound/oss/opl3.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/opl3.c
++ * sound/oss/opl3.c
+ *
+ * A low level driver for Yamaha YM3812 and OPL-3 -chips
+ *
+diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c
+deleted file mode 100644
+index fe4907c..0000000
+--- a/sound/oss/opl3sa.c
++++ /dev/null
+@@ -1,329 +0,0 @@
+-/*
+- * sound/opl3sa.c
+- *
+- * Low level driver for Yamaha YMF701B aka OPL3-SA chip
+- *
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- * Changes:
+- * Alan Cox Modularisation
+- * Christoph Hellwig Adapted to module_init/module_exit
+- * Arnaldo C. de Melo got rid of attach_uart401
+- *
+- * FIXME:
+- * Check for install of mpu etc is wrong, should check result of the mss stuff
+- */
+-
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/spinlock.h>
+-
+-#undef SB_OK
+-
+-#include "sound_config.h"
+-
+-#include "ad1848.h"
+-#include "mpu401.h"
+-
+-#ifdef SB_OK
+-#include "sb.h"
+-static int sb_initialized;
+-#endif
+-
+-static DEFINE_SPINLOCK(lock);
+-
+-static unsigned char opl3sa_read(int addr)
+-{
+- unsigned long flags;
+- unsigned char tmp;
+-
+- spin_lock_irqsave(&lock,flags);
+- outb((0x1d), 0xf86); /* password */
+- outb(((unsigned char) addr), 0xf86); /* address */
+- tmp = inb(0xf87); /* data */
+- spin_unlock_irqrestore(&lock,flags);
+-
+- return tmp;
+-}
+-
+-static void opl3sa_write(int addr, int data)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&lock,flags);
+- outb((0x1d), 0xf86); /* password */
+- outb(((unsigned char) addr), 0xf86); /* address */
+- outb(((unsigned char) data), 0xf87); /* data */
+- spin_unlock_irqrestore(&lock,flags);
+-}
+-
+-static int __init opl3sa_detect(void)
+-{
+- int tmp;
+-
+- if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
+- {
+- DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
+- /* return 0; */
+- }
+-
+- /*
+- * Check that the password feature has any effect
+- */
+-
+- if (inb(0xf87) == tmp)
+- {
+- DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
+- return 0;
+- }
+- tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
+-
+- if (tmp != 0 && tmp != 1)
+- {
+- DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
+- return 0;
+- }
+- DDB(printk("OPL3-SA mode %x detected\n", tmp));
+-
+- opl3sa_write(0x01, 0x00); /* Disable MSS */
+- opl3sa_write(0x02, 0x00); /* Disable SB */
+- opl3sa_write(0x03, 0x00); /* Disable MPU */
+-
+- return 1;
+-}
+-
+-/*
+- * Probe and attach routines for the Windows Sound System mode of
+- * OPL3-SA
+- */
+-
+-static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
+-{
+- unsigned char tmp = 0x24; /* WSS enable */
+-
+- /*
+- * Check if the IO port returns valid signature. The original MS Sound
+- * system returns 0x04 while some cards (OPL3-SA for example)
+- * return 0x00.
+- */
+-
+- if (!opl3sa_detect())
+- {
+- printk(KERN_ERR "OSS: OPL3-SA chip not found\n");
+- return 0;
+- }
+-
+- switch (hw_config->io_base)
+- {
+- case 0x530:
+- tmp |= 0x00;
+- break;
+- case 0xe80:
+- tmp |= 0x08;
+- break;
+- case 0xf40:
+- tmp |= 0x10;
+- break;
+- case 0x604:
+- tmp |= 0x18;
+- break;
+- default:
+- printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
+- return 0;
+- }
+-
+- opl3sa_write(0x01, tmp); /* WSS setup register */
+-
+- return probe_ms_sound(hw_config, ports);
+-}
+-
+-static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
+-{
+- int nm = num_mixers;
+-
+- /* FIXME */
+- attach_ms_sound(hw_config, ports, THIS_MODULE);
+- if (num_mixers > nm) /* A mixer was installed */
+- {
+- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
+- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
+- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+- }
+-}
+-
+-
+-static int __init probe_opl3sa_mpu(struct address_info *hw_config)
+-{
+- unsigned char conf;
+- static signed char irq_bits[] = {
+- -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
+- };
+-
+- if (hw_config->irq > 10)
+- {
+- printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
+- return 0;
+- }
+- if (irq_bits[hw_config->irq] == -1)
+- {
+- printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
+- return 0;
+- }
+- switch (hw_config->io_base)
+- {
+- case 0x330:
+- conf = 0x00;
+- break;
+- case 0x332:
+- conf = 0x20;
+- break;
+- case 0x334:
+- conf = 0x40;
+- break;
+- case 0x300:
+- conf = 0x60;
+- break;
+- default:
+- return 0; /* Invalid port */
+- }
+-
+- conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */
+- conf |= irq_bits[hw_config->irq] << 2;
+-
+- opl3sa_write(0x03, conf);
+-
+- hw_config->name = "OPL3-SA (MPU401)";
+-
+- return probe_uart401(hw_config, THIS_MODULE);
+-}
+-
+-static void __exit unload_opl3sa_wss(struct address_info *hw_config)
+-{
+- int dma2 = hw_config->dma2;
+-
+- if (dma2 == -1)
+- dma2 = hw_config->dma;
+-
+- release_region(0xf86, 2);
+- release_region(hw_config->io_base, 4);
+-
+- ad1848_unload(hw_config->io_base + 4,
+- hw_config->irq,
+- hw_config->dma,
+- dma2,
+- 0);
+- sound_unload_audiodev(hw_config->slots[0]);
+-}
+-
+-static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
+-{
+- unload_uart401(hw_config);
+-}
+-
+-#ifdef SB_OK
+-static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
+-{
+- sb_dsp_unload(hw_config);
+-}
+-#endif
+-
+-static int found_mpu;
+-
+-static struct address_info cfg;
+-static struct address_info cfg_mpu;
+-
+-static int __initdata io = -1;
+-static int __initdata irq = -1;
+-static int __initdata dma = -1;
+-static int __initdata dma2 = -1;
+-static int __initdata mpu_io = -1;
+-static int __initdata mpu_irq = -1;
+-
+-module_param(io, int, 0);
+-module_param(irq, int, 0);
+-module_param(dma, int, 0);
+-module_param(dma2, int, 0);
+-module_param(mpu_io, int, 0);
+-module_param(mpu_irq, int, 0);
+-
+-static int __init init_opl3sa(void)
+-{
+- struct resource *ports;
+- if (io == -1 || irq == -1 || dma == -1) {
+- printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
+- return -EINVAL;
+- }
+-
+- cfg.io_base = io;
+- cfg.irq = irq;
+- cfg.dma = dma;
+- cfg.dma2 = dma2;
+-
+- cfg_mpu.io_base = mpu_io;
+- cfg_mpu.irq = mpu_irq;
+-
+- ports = request_region(io + 4, 4, "ad1848");
+- if (!ports)
+- return -EBUSY;
+-
+- if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ {
+- release_region(io + 4, 4);
+- return 0;
+- }
+-
+- if (!request_region(io, 4, "WSS config")) {
+- release_region(0x86, 2);
+- release_region(io + 4, 4);
+- return 0;
+- }
+-
+- if (probe_opl3sa_wss(&cfg, ports) == 0) {
+- release_region(0xf86, 2);
+- release_region(io, 4);
+- release_region(io + 4, 4);
+- return -ENODEV;
+- }
+-
+- found_mpu=probe_opl3sa_mpu(&cfg_mpu);
+-
+- attach_opl3sa_wss(&cfg, ports);
+- return 0;
+-}
+-
+-static void __exit cleanup_opl3sa(void)
+-{
+- if(found_mpu)
+- unload_opl3sa_mpu(&cfg_mpu);
+- unload_opl3sa_wss(&cfg);
+-}
+-
+-module_init(init_opl3sa);
+-module_exit(cleanup_opl3sa);
+-
+-#ifndef MODULE
+-static int __init setup_opl3sa(char *str)
+-{
+- /* io, irq, dma, dma2, mpu_io, mpu_irq */
+- int ints[7];
+-
+- str = get_options(str, ARRAY_SIZE(ints), ints);
+-
+- io = ints[1];
+- irq = ints[2];
+- dma = ints[3];
+- dma2 = ints[4];
+- mpu_io = ints[5];
+- mpu_irq = ints[6];
+-
+- return 1;
+-}
+-
+-__setup("opl3sa=", setup_opl3sa);
+-#endif
+-MODULE_LICENSE("GPL");
+diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
+index aec05a2..e20051f 100644
+--- a/sound/oss/opl3sa2.c
++++ b/sound/oss/opl3sa2.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/opl3sa2.c
++ * sound/oss/opl3sa2.c
+ *
+ * A low level driver for Yamaha OPL3-SA2 and SA3 cards.
+ * NOTE: All traces of the name OPL3-SAx have now (December 2000) been
+diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c
+index 9766600..25f3a22 100644
+--- a/sound/oss/pas2_card.c
++++ b/sound/oss/pas2_card.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/pas2_card.c
++ * sound/oss/pas2_card.c
+ *
+ * Detection routine for the Pro Audio Spectrum cards.
+ */
+@@ -88,7 +88,7 @@ void pas_write(unsigned char data, int i
+
+ /******************* Begin of the Interrupt Handler ********************/
+
+-static irqreturn_t pasintr(int irq, void *dev_id, struct pt_regs *dummy)
++static irqreturn_t pasintr(int irq, void *dev_id)
+ {
+ int status;
+
+diff --git a/sound/oss/pas2_midi.c b/sound/oss/pas2_midi.c
+index 79d6a58..1122d10 100644
+--- a/sound/oss/pas2_midi.c
++++ b/sound/oss/pas2_midi.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/pas2_midi.c
++ * sound/oss/pas2_midi.c
+ *
+ * The low level driver for the PAS Midi Interface.
+ */
+diff --git a/sound/oss/pas2_mixer.c b/sound/oss/pas2_mixer.c
+index 4aade53..a0bcb85 100644
+--- a/sound/oss/pas2_mixer.c
++++ b/sound/oss/pas2_mixer.c
+@@ -1,6 +1,6 @@
+
+ /*
+- * sound/pas2_mixer.c
++ * sound/oss/pas2_mixer.c
+ *
+ * Mixer routines for the Pro Audio Spectrum cards.
+ */
+diff --git a/sound/oss/pss.c b/sound/oss/pss.c
+index 37ee234..ece428b 100644
+--- a/sound/oss/pss.c
++++ b/sound/oss/pss.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/pss.c
++ * sound/oss/pss.c
+ *
+ * The low level driver for the Personal Sound System (ECHO ESC614).
+ *
+diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
+deleted file mode 100644
+index f17d25b..0000000
+--- a/sound/oss/rme96xx.c
++++ /dev/null
+@@ -1,1857 +0,0 @@
+-/* (C) 2000 Guenter Geiger <geiger at debian.org>
+- with copy/pastes from the driver of Winfried Ritsch <ritsch at iem.kug.ac.at>
+- based on es1370.c
+-
+-
+-
+- * 10 Jan 2001: 0.1 initial version
+- * 19 Jan 2001: 0.2 fixed bug in select()
+- * 27 Apr 2001: 0.3 more than one card usable
+- * 11 May 2001: 0.4 fixed for SMP, included into kernel source tree
+- * 17 May 2001: 0.5 draining code didn't work on new cards
+- * 18 May 2001: 0.6 remove synchronize_irq() call
+- * 17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards
+- * 2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!)
+- Marcus Meissner <Marcus.Meissner at caldera.de>
+-
+- Modifications - Heiko Purnhagen <purnhage at tnt.uni-hannover.de>
+- HP20020108 fixed handling of "large" read()
+- HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
+- HP20020118 made mixer ioctl and handling of devices>1 more safe
+- HP20020201 fixed handling of "large" read() properly
+- added REV 1.5 S/P-DIF receiver support
+- SNDCTL_DSP_SPEED now returns the actual speed
+- * 10 Aug 2002: added synchronize_irq() again
+-
+-TODO:
+- - test more than one card --- done
+- - check for pci IOREGION (see es1370) in rme96xx_probe ??
+- - error detection
+- - mmap interface
+- - mixer mmap interface
+- - mixer ioctl
+- - get rid of noise upon first open (why ??)
+- - allow multiple open (at least for read)
+- - allow multiple open for non overlapping regions
+- - recheck the multiple devices part (offsets of different devices, etc)
+- - do decent draining in _release --- done
+- - SMP support
+- - what about using fragstotal>2 for small fragsize? (HP20020118)
+- - add support for AFMT_S32_LE
+-*/
+-
+-#ifndef RMEVERSION
+-#define RMEVERSION "0.8"
+-#endif
+-
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/sched.h>
+-#include <linux/sound.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/smp_lock.h>
+-#include <linux/delay.h>
+-#include <linux/slab.h>
+-#include <linux/interrupt.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/poll.h>
+-#include <linux/wait.h>
+-#include <linux/mutex.h>
+-
+-#include <asm/dma.h>
+-#include <asm/page.h>
+-
+-#include "rme96xx.h"
+-
+-#define NR_DEVICE 2
+-
+-static int devices = 1;
+-module_param(devices, int, 0);
+-MODULE_PARM_DESC(devices, "number of dsp devices allocated by the driver");
+-
+-
+-MODULE_AUTHOR("Guenter Geiger, geiger at debian.org");
+-MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver");
+-MODULE_LICENSE("GPL");
+-
+-
+-#ifdef DEBUG
+-#define DBG(x) printk("RME_DEBUG:");x
+-#define COMM(x) printk("RME_COMM: " x "\n");
+-#else
+-#define DBG(x) while (0) {}
+-#define COMM(x)
+-#endif
+-
+-/*--------------------------------------------------------------------------
+- Preporcessor Macros and Definitions
+- --------------------------------------------------------------------------*/
+-
+-#define RME96xx_MAGIC 0x6473
+-
+-/* Registers-Space in offsets from base address with 16MByte size */
+-
+-#define RME96xx_IO_EXTENT 16l*1024l*1024l
+-#define RME96xx_CHANNELS_PER_CARD 26
+-
+-/* Write - Register */
+-
+-/* 0,4,8,12,16,20,24,28 ... hardware init (erasing fifo-pointer intern) */
+-#define RME96xx_num_of_init_regs 8
+-
+-#define RME96xx_init_buffer (0/4)
+-#define RME96xx_play_buffer (32/4) /* pointer to 26x64kBit RAM from mainboard */
+-#define RME96xx_rec_buffer (36/4) /* pointer to 26x64kBit RAM from mainboard */
+-#define RME96xx_control_register (64/4) /* exact meaning see below */
+-#define RME96xx_irq_clear (96/4) /* irq acknowledge */
+-#define RME96xx_time_code (100/4) /* if used with alesis adat */
+-#define RME96xx_thru_base (128/4) /* 132...228 Thru for 26 channels */
+-#define RME96xx_thru_channels RME96xx_CHANNELS_PER_CARD
+-
+-/* Read Register */
+-
+-#define RME96xx_status_register 0 /* meaning see below */
+-
+-
+-
+-/* Status Register: */
+-/* ------------------------------------------------------------------------ */
+-#define RME96xx_IRQ 0x0000001 /* IRQ is High if not reset by RMExx_irq_clear */
+-#define RME96xx_lock_2 0x0000002 /* ADAT 3-PLL: 1=locked, 0=unlocked */
+-#define RME96xx_lock_1 0x0000004 /* ADAT 2-PLL: 1=locked, 0=unlocked */
+-#define RME96xx_lock_0 0x0000008 /* ADAT 1-PLL: 1=locked, 0=unlocked */
+-
+-#define RME96xx_fs48 0x0000010 /* sample rate 0 ...44.1/88.2, 1 ... 48/96 Khz */
+-#define RME96xx_wsel_rd 0x0000020 /* if Word-Clock is used and valid then 1 */
+-#define RME96xx_buf_pos1 0x0000040 /* Bit 6..15 : Position of buffer-pointer in 64Bytes-blocks */
+-#define RME96xx_buf_pos2 0x0000080 /* resolution +/- 1 64Byte/block (since 64Bytes bursts) */
+-
+-#define RME96xx_buf_pos3 0x0000100 /* 10 bits = 1024 values */
+-#define RME96xx_buf_pos4 0x0000200 /* if we mask off the first 6 bits, we can take the status */
+-#define RME96xx_buf_pos5 0x0000400 /* register as sample counter in the hardware buffer */
+-#define RME96xx_buf_pos6 0x0000800
+-
+-#define RME96xx_buf_pos7 0x0001000
+-#define RME96xx_buf_pos8 0x0002000
+-#define RME96xx_buf_pos9 0x0004000
+-#define RME96xx_buf_pos10 0x0008000
+-
+-#define RME96xx_sync_2 0x0010000 /* if ADAT-IN3 synced to system clock */
+-#define RME96xx_sync_1 0x0020000 /* if ADAT-IN2 synced to system clock */
+-#define RME96xx_sync_0 0x0040000 /* if ADAT-IN1 synced to system clock */
+-#define RME96xx_DS_rd 0x0080000 /* 1=Double Speed, 0=Normal Speed */
+-
+-#define RME96xx_tc_busy 0x0100000 /* 1=time-code copy in progress (960ms) */
+-#define RME96xx_tc_out 0x0200000 /* time-code out bit */
+-#define RME96xx_F_0 0x0400000 /* 000=64kHz, 100=88.2kHz, 011=96kHz */
+-#define RME96xx_F_1 0x0800000 /* 111=32kHz, 110=44.1kHz, 101=48kHz, */
+-
+-#define RME96xx_F_2 0x1000000 /* 001=Rev 1.5+ external Crystal Chip */
+-#define RME96xx_ERF 0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/
+-#define RME96xx_buffer_id 0x4000000 /* toggles by each interrupt on rec/play */
+-#define RME96xx_tc_valid 0x8000000 /* 1 = a signal is detected on time-code input */
+-#define RME96xx_SPDIF_READ 0x10000000 /* byte available from Rev 1.5+ SPDIF interface */
+-
+-/* Status Register Fields */
+-
+-#define RME96xx_lock (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2)
+-#define RME96xx_sync (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2)
+-#define RME96xx_F (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2)
+-#define rme96xx_decode_spdif_rate(x) ((x)>>22)
+-
+-/* Bit 6..15 : h/w buffer pointer */
+-#define RME96xx_buf_pos 0x000FFC0
+-/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
+- Rev G EEPROMS and Rev 1.5 cards or later.
+-*/
+-#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos))
+-
+-
+-/* Control-Register: */
+-/*--------------------------------------------------------------------------------*/
+-
+-#define RME96xx_start_bit 0x0001 /* start record/play */
+-#define RME96xx_latency0 0x0002 /* Buffer size / latency */
+-#define RME96xx_latency1 0x0004 /* buffersize = 512Bytes * 2^n */
+-#define RME96xx_latency2 0x0008 /* 0=64samples ... 7=8192samples */
+-
+-#define RME96xx_Master 0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */
+-#define RME96xx_IE 0x0020 /* Interupt Enable */
+-#define RME96xx_freq 0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/
+-#define RME96xx_freq1 0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */
+-#define RME96xx_DS 0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */
+-#define RME96xx_PRO 0x0200 /* SPDIF-OUT 0=consumer, 1=professional */
+-#define RME96xx_EMP 0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */
+-#define RME96xx_Dolby 0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */
+-
+-#define RME96xx_opt_out 0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */
+-#define RME96xx_wsel 0x2000 /* use Wordclock as sync (overwrites master) */
+-#define RME96xx_inp_0 0x4000 /* SPDIF-IN 00=optical (ADAT1), */
+-#define RME96xx_inp_1 0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */
+-
+-#define RME96xx_SyncRef0 0x10000 /* preferred sync-source in autosync */
+-#define RME96xx_SyncRef1 0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
+-
+-#define RME96xx_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w SPDIF receiver */
+-#define RME96xx_SPDIF_SELECT (1<<19)
+-#define RME96xx_SPDIF_CLOCK (1<<20)
+-#define RME96xx_SPDIF_WRITE (1<<21)
+-#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */
+-
+-
+-#define RME96xx_ctrl_init (RME96xx_latency0 |\
+- RME96xx_Master |\
+- RME96xx_inp_1)
+-
+-
+-
+-/* Control register fields and shortcuts */
+-
+-#define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2)
+-#define RME96xx_inp (RME96xx_inp_0|RME96xx_inp_1)
+-#define RME96xx_SyncRef (RME96xx_SyncRef0|RME96xx_SyncRef1)
+-#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL)
+-
+-/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1 (??? HP20020201) */
+-
+-#define RME96xx_SET_LATENCY(x) (((x)&0x7)<<1)
+-#define RME96xx_GET_LATENCY(x) (((x)>>1)&0x7)
+-#define RME96xx_SET_inp(x) (((x)&0x3)<<14)
+-#define RME96xx_GET_inp(x) (((x)>>14)&0x3)
+-#define RME96xx_SET_SyncRef(x) (((x)&0x3)<<17)
+-#define RME96xx_GET_SyncRef(x) (((x)>>17)&0x3)
+-
+-
+-/* buffer sizes */
+-#define RME96xx_BYTES_PER_SAMPLE 4 /* sizeof(u32) */
+-#define RME_16K 16*1024
+-
+-#define RME96xx_DMA_MAX_SAMPLES (RME_16K)
+-#define RME96xx_DMA_MAX_SIZE (RME_16K * RME96xx_BYTES_PER_SAMPLE)
+-#define RME96xx_DMA_MAX_SIZE_ALL (RME96xx_DMA_MAX_SIZE * RME96xx_CHANNELS_PER_CARD)
+-
+-#define RME96xx_NUM_OF_FRAGMENTS 2
+-#define RME96xx_FRAGMENT_MAX_SIZE (RME96xx_DMA_MAX_SIZE/2)
+-#define RME96xx_FRAGMENT_MAX_SAMPLES (RME96xx_DMA_MAX_SAMPLES/2)
+-#define RME96xx_MAX_LATENCY 7 /* 16k samples */
+-
+-
+-#define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */
+-#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */
+-
+-#define RME_MESS "rme96xx:"
+-/*------------------------------------------------------------------------
+- Types, struct and function declarations
+- ------------------------------------------------------------------------*/
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT RME_MESS" invalid magic value\n";
+-
+-#define VALIDATE_STATE(s) \
+-({ \
+- if (!(s) || (s)->magic != RME96xx_MAGIC) { \
+- printk(invalid_magic); \
+- return -ENXIO; \
+- } \
+-})
+-
+-/* --------------------------------------------------------------------- */
+-
+-
+-static struct file_operations rme96xx_audio_fops;
+-static struct file_operations rme96xx_mixer_fops;
+-static int numcards;
+-
+-typedef int32_t raw_sample_t;
+-
+-typedef struct _rme96xx_info {
+-
+- /* hardware settings */
+- int magic;
+- struct pci_dev * pcidev; /* pci_dev structure */
+- unsigned long __iomem *iobase;
+- unsigned int irq;
+-
+- /* list of rme96xx devices */
+- struct list_head devs;
+-
+- spinlock_t lock;
+-
+- u32 *recbuf; /* memory for rec buffer */
+- u32 *playbuf; /* memory for play buffer */
+-
+- u32 control_register;
+-
+- u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
+-
+- int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
+- char *card_name; /* hammerfall or hammerfall light names */
+-
+- int open_count; /* unused ??? HP20020201 */
+-
+- int rate;
+- int latency;
+- unsigned int fragsize;
+- int started;
+-
+- int hwptr; /* can be negativ because of pci burst offset */
+- unsigned int hwbufid; /* set by interrupt, buffer which is written/read now */
+-
+- struct dmabuf {
+-
+- unsigned int format;
+- int formatshift;
+- int inchannels; /* number of channels for device */
+- int outchannels; /* number of channels for device */
+- int mono; /* if true, we play mono on 2 channels */
+- int inoffset; /* which channel is considered the first one */
+- int outoffset;
+-
+- /* state */
+- int opened; /* open() made */
+- int started; /* first write/read */
+- int mmapped; /* mmap */
+- int open_mode;
+-
+- struct _rme96xx_info *s;
+-
+- /* pointer to read/write position in buffer */
+- unsigned readptr;
+- unsigned writeptr;
+-
+- unsigned error; /* over/underruns cleared on sync again */
+-
+- /* waiting and locking */
+- wait_queue_head_t wait;
+- struct mutex open_mutex;
+- wait_queue_head_t open_wait;
+-
+- } dma[RME96xx_MAX_DEVS];
+-
+- int dspnum[RME96xx_MAX_DEVS]; /* register with sound subsystem */
+- int mixer; /* register with sound subsystem */
+-} rme96xx_info;
+-
+-
+-/* fiddling with the card (first level hardware control) */
+-
+-static inline void rme96xx_set_ctrl(rme96xx_info* s,int mask)
+-{
+-
+- s->control_register|=mask;
+- writel(s->control_register,s->iobase + RME96xx_control_register);
+-
+-}
+-
+-static inline void rme96xx_unset_ctrl(rme96xx_info* s,int mask)
+-{
+-
+- s->control_register&=(~mask);
+- writel(s->control_register,s->iobase + RME96xx_control_register);
+-
+-}
+-
+-static inline int rme96xx_get_sample_rate_status(rme96xx_info* s)
+-{
+- int val;
+- u32 status;
+- status = readl(s->iobase + RME96xx_status_register);
+- val = (status & RME96xx_fs48) ? 48000 : 44100;
+- if (status & RME96xx_DS_rd)
+- val *= 2;
+- return val;
+-}
+-
+-static inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s)
+-{
+- int val;
+- val = (s->control_register & RME96xx_freq) ? 48000 : 44100;
+- if (s->control_register & RME96xx_DS)
+- val *= 2;
+- return val;
+-}
+-
+-
+-/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver HP 20020201 */
+-
+-static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff)
+-{
+- if (onoff)
+- s->control_register |= mask;
+- else
+- s->control_register &= ~mask;
+-
+- writel(s->control_register,s->iobase + RME96xx_control_register);
+-}
+-
+-static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val)
+-{
+- long mask;
+- long i;
+-
+- for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
+- if (val & mask)
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1);
+- else
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0);
+-
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
+- }
+-}
+-
+-static int rme96xx_spdif_read_byte (rme96xx_info* s)
+-{
+- long mask;
+- long val;
+- long i;
+-
+- val = 0;
+-
+- for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
+- if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ)
+- val |= mask;
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
+- }
+-
+- return val;
+-}
+-
+-static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data)
+-{
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
+- rme96xx_spdif_write_byte (s, 0x20);
+- rme96xx_spdif_write_byte (s, address);
+- rme96xx_spdif_write_byte (s, data);
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
+-}
+-
+-
+-static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address)
+-{
+- int ret;
+-
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
+- rme96xx_spdif_write_byte (s, 0x20);
+- rme96xx_spdif_write_byte (s, address);
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
+-
+- rme96xx_spdif_write_byte (s, 0x21);
+- ret = rme96xx_spdif_read_byte (s);
+- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
+-
+- return ret;
+-}
+-
+-static void rme96xx_initialize_spdif_receiver (rme96xx_info* s)
+-{
+- /* XXX what unsets this ? */
+- /* no idea ??? HP 20020201 */
+-
+- s->control_register |= RME96xx_SPDIF_RESET;
+-
+- rme96xx_write_spdif_codec (s, 4, 0x40);
+- rme96xx_write_spdif_codec (s, 17, 0x13);
+- rme96xx_write_spdif_codec (s, 6, 0x02);
+-}
+-
+-static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate)
+-{
+- unsigned int rate_bits;
+-
+- *spdifrate = 0x1;
+- if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) {
+- return -1; /* error condition */
+- }
+-
+- if (s->hw_rev == 15) {
+-
+- int x, y, ret;
+-
+- x = rme96xx_spdif_read_codec (s, 30);
+-
+- if (x != 0)
+- y = 48000 * 64 / x;
+- else
+- y = 0;
+-
+- if (y > 30400 && y < 33600) {ret = 32000; *spdifrate = 0x7;}
+- else if (y > 41900 && y < 46000) {ret = 44100; *spdifrate = 0x6;}
+- else if (y > 46000 && y < 50400) {ret = 48000; *spdifrate = 0x5;}
+- else if (y > 60800 && y < 67200) {ret = 64000; *spdifrate = 0x0;}
+- else if (y > 83700 && y < 92000) {ret = 88200; *spdifrate = 0x4;}
+- else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;}
+- else {ret = 0; *spdifrate = 0x1;}
+- return ret;
+- }
+-
+- rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F;
+-
+- switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) {
+- case 0x7:
+- return 32000;
+- break;
+-
+- case 0x6:
+- return 44100;
+- break;
+-
+- case 0x5:
+- return 48000;
+- break;
+-
+- case 0x4:
+- return 88200;
+- break;
+-
+- case 0x3:
+- return 96000;
+- break;
+-
+- case 0x0:
+- return 64000;
+- break;
+-
+- default:
+- /* was an ALSA warning ...
+- snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n",
+- s->card_name, rate_bits);
+- */
+- return 0;
+- break;
+- }
+-}
+-
+-/* end of code from ALSA card-rme9652.c */
+-
+-
+-
+-/* the hwbuf in the status register seems to have some jitter, to get rid of
+- it, we first only let the numbers grow, to be on the secure side we
+- subtract a certain amount RME96xx_BURSTBYTES from the resulting number */
+-
+-/* the function returns the hardware pointer in bytes */
+-#define RME96xx_BURSTBYTES -64 /* bytes by which hwptr could be off */
+-
+-static inline int rme96xx_gethwptr(rme96xx_info* s,int exact)
+-{
+- unsigned long flags;
+- if (exact) {
+- unsigned int hwp;
+-/* the hwptr seems to be rather unreliable :(, so we don't use it */
+- spin_lock_irqsave(&s->lock,flags);
+-
+- hwp = readl(s->iobase + RME96xx_status_register) & 0xffc0;
+- s->hwptr = (hwp < s->hwptr) ? s->hwptr : hwp;
+-// s->hwptr = hwp;
+-
+- spin_unlock_irqrestore(&s->lock,flags);
+- return (s->hwptr+RME96xx_BURSTBYTES) & ((s->fragsize<<1)-1);
+- }
+- return (s->hwbufid ? s->fragsize : 0);
+-}
+-
+-static inline void rme96xx_setlatency(rme96xx_info* s,int l)
+-{
+- s->latency = l;
+- s->fragsize = 1<<(8+l);
+- rme96xx_unset_ctrl(s,RME96xx_latency);
+- rme96xx_set_ctrl(s,RME96xx_SET_LATENCY(l));
+-}
+-
+-
+-static void rme96xx_clearbufs(struct dmabuf* dma)
+-{
+- int i,j;
+- unsigned long flags;
+-
+- /* clear dmabufs */
+- for(i=0;i<devices;i++) {
+- for (j=0;j<dma->outchannels + dma->mono;j++)
+- memset(&dma->s->playbuf[(dma->outoffset + j)*RME96xx_DMA_MAX_SAMPLES],
+- 0, RME96xx_DMA_MAX_SIZE);
+- }
+- spin_lock_irqsave(&dma->s->lock,flags);
+- dma->writeptr = 0;
+- dma->readptr = 0;
+- spin_unlock_irqrestore(&dma->s->lock,flags);
+-}
+-
+-static int rme96xx_startcard(rme96xx_info *s,int stop)
+-{
+- int i;
+- unsigned long flags;
+-
+- COMM ("startcard");
+- if(s->control_register & RME96xx_IE){
+- /* disable interrupt first */
+-
+- rme96xx_unset_ctrl( s,RME96xx_start_bit );
+- udelay(10);
+- rme96xx_unset_ctrl( s,RME96xx_IE);
+- spin_lock_irqsave(&s->lock,flags); /* timing is critical */
+- s->started = 0;
+- spin_unlock_irqrestore(&s->lock,flags);
+- if (stop) {
+- COMM("Sound card stopped");
+- return 1;
+- }
+- }
+- COMM ("interrupt disabled");
+- /* first initialize all pointers on card */
+- for(i=0;i<RME96xx_num_of_init_regs;i++){
+- writel(0,s->iobase + i);
+- udelay(10); /* ?? */
+- }
+- COMM ("regs cleaned");
+-
+- spin_lock_irqsave(&s->lock,flags); /* timing is critical */
+- udelay(10);
+- s->started = 1;
+- s->hwptr = 0;
+- spin_unlock_irqrestore(&s->lock,flags);
+-
+- rme96xx_set_ctrl( s, RME96xx_IE | RME96xx_start_bit);
+-
+-
+- COMM("Sound card started");
+-
+- return 1;
+-}
+-
+-
+-static inline int rme96xx_getospace(struct dmabuf * dma, unsigned int hwp)
+-{
+- int cnt;
+- int swptr;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&dma->s->lock,flags);
+- swptr = dma->writeptr;
+- cnt = (hwp - swptr);
+-
+- if (cnt < 0) {
+- cnt = ((dma->s->fragsize<<1) - swptr);
+- }
+- spin_unlock_irqrestore(&dma->s->lock,flags);
+- return cnt;
+-}
+-
+-static inline int rme96xx_getispace(struct dmabuf * dma, unsigned int hwp)
+-{
+- int cnt;
+- int swptr;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&dma->s->lock,flags);
+- swptr = dma->readptr;
+- cnt = (hwp - swptr);
+-
+- if (cnt < 0) {
+- cnt = ((dma->s->fragsize<<1) - swptr);
+- }
+- spin_unlock_irqrestore(&dma->s->lock,flags);
+- return cnt;
+-}
+-
+-
+-static inline int rme96xx_copyfromuser(struct dmabuf* dma,const char __user * buffer,int count,int hop)
+-{
+- int swptr = dma->writeptr;
+- switch (dma->format) {
+- case AFMT_S32_BLOCKED:
+- {
+- char __user * buf = (char __user *)buffer;
+- int cnt = count/dma->outchannels;
+- int i;
+- for (i=0;i < dma->outchannels;i++) {
+- char* hwbuf =(char*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
+- hwbuf+=swptr;
+-
+- if (copy_from_user(hwbuf,buf, cnt))
+- return -1;
+- buf+=hop;
+- }
+- swptr+=cnt;
+- break;
+- }
+- case AFMT_S16_LE:
+- {
+- int i,j;
+- int cnt = count/dma->outchannels;
+- for (i=0;i < dma->outchannels + dma->mono;i++) {
+- short __user * sbuf = (short __user *)buffer + i*(!dma->mono);
+- short* hwbuf =(short*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
+- hwbuf+=(swptr>>1);
+- for (j=0;j<(cnt>>1);j++) {
+- hwbuf++; /* skip the low 16 bits */
+- __get_user(*hwbuf++,sbuf++);
+- sbuf+=(dma->outchannels-1);
+- }
+- }
+- swptr += (cnt<<1);
+- break;
+- }
+- default:
+- printk(RME_MESS" unsupported format\n");
+- return -1;
+- } /* switch */
+-
+- swptr&=((dma->s->fragsize<<1) -1);
+- dma->writeptr = swptr;
+-
+- return 0;
+-}
+-
+-/* The count argument is the number of bytes */
+-static inline int rme96xx_copytouser(struct dmabuf* dma,const char __user* buffer,int count,int hop)
+-{
+- int swptr = dma->readptr;
+- switch (dma->format) {
+- case AFMT_S32_BLOCKED:
+- {
+- char __user * buf = (char __user *)buffer;
+- int cnt = count/dma->inchannels;
+- int i;
+-
+- for (i=0;i < dma->inchannels;i++) {
+- char* hwbuf =(char*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
+- hwbuf+=swptr;
+-
+- if (copy_to_user(buf,hwbuf,cnt))
+- return -1;
+- buf+=hop;
+- }
+- swptr+=cnt;
+- break;
+- }
+- case AFMT_S16_LE:
+- {
+- int i,j;
+- int cnt = count/dma->inchannels;
+- for (i=0;i < dma->inchannels;i++) {
+- short __user * sbuf = (short __user *)buffer + i;
+- short* hwbuf =(short*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
+- hwbuf+=(swptr>>1);
+- for (j=0;j<(cnt>>1);j++) {
+- hwbuf++;
+- __put_user(*hwbuf++,sbuf++);
+- sbuf+=(dma->inchannels-1);
+- }
+- }
+- swptr += (cnt<<1);
+- break;
+- }
+- default:
+- printk(RME_MESS" unsupported format\n");
+- return -1;
+- } /* switch */
+-
+- swptr&=((dma->s->fragsize<<1) -1);
+- dma->readptr = swptr;
+- return 0;
+-}
+-
+-
+-static irqreturn_t rme96xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- int i;
+- rme96xx_info *s = (rme96xx_info *)dev_id;
+- struct dmabuf *db;
+- u32 status;
+- unsigned long flags;
+-
+- status = readl(s->iobase + RME96xx_status_register);
+- if (!(status & RME96xx_IRQ)) {
+- return IRQ_NONE;
+- }
+-
+- spin_lock_irqsave(&s->lock,flags);
+- writel(0,s->iobase + RME96xx_irq_clear);
+-
+- s->hwbufid = (status & RME96xx_buffer_id)>>26;
+- if ((status & 0xffc0) <= 256) s->hwptr = 0;
+- for(i=0;i<devices;i++)
+- {
+- db = &(s->dma[i]);
+- if(db->started > 0)
+- wake_up(&(db->wait));
+- }
+- spin_unlock_irqrestore(&s->lock,flags);
+- return IRQ_HANDLED;
+-}
+-
+-
+-
+-/*----------------------------------------------------------------------------
+- PCI detection and module initialization stuff
+- ----------------------------------------------------------------------------*/
+-
+-static void* busmaster_malloc(int size) {
+- int pg; /* 2 s exponent of memory size */
+- char *buf;
+-
+- DBG(printk("kernel malloc pages ..\n"));
+-
+- for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+-
+- buf = (char *) __get_free_pages(GFP_KERNEL | GFP_DMA, pg);
+-
+- if (buf) {
+- struct page* page, *last_page;
+-
+- page = virt_to_page(buf);
+- last_page = page + (1 << pg);
+- DBG(printk("setting reserved bit\n"));
+- while (page < last_page) {
+- SetPageReserved(page);
+- page++;
+- }
+- return buf;
+- }
+- DBG(printk("allocated %ld",(long)buf));
+- return NULL;
+-}
+-
+-static void busmaster_free(void* ptr,int size) {
+- int pg;
+- struct page* page, *last_page;
+-
+- if (ptr == NULL)
+- return;
+-
+- for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+-
+- page = virt_to_page(ptr);
+- last_page = page + (1 << pg);
+- while (page < last_page) {
+- ClearPageReserved(page);
+- page++;
+- }
+- DBG(printk("freeing pages\n"));
+- free_pages((unsigned long) ptr, pg);
+- DBG(printk("done\n"));
+-}
+-
+-/* initialize those parts of the info structure which are not pci detectable resources */
+-
+-static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) {
+-
+- mutex_init(&dma->open_mutex);
+- init_waitqueue_head(&dma->open_wait);
+- init_waitqueue_head(&dma->wait);
+- dma->s = s;
+- dma->error = 0;
+-
+- dma->format = AFMT_S32_BLOCKED;
+- dma->formatshift = 0;
+- dma->inchannels = dma->outchannels = 1;
+- dma->inoffset = ioffset;
+- dma->outoffset = ooffset;
+-
+- dma->opened=0;
+- dma->started=0;
+- dma->mmapped=0;
+- dma->open_mode=0;
+- dma->mono=0;
+-
+- rme96xx_clearbufs(dma);
+- return 0;
+-}
+-
+-
+-static int rme96xx_init(rme96xx_info* s)
+-{
+- int i;
+- int status;
+- unsigned short rev;
+-
+- DBG(printk("%s\n", __FUNCTION__));
+- numcards++;
+-
+- s->magic = RME96xx_MAGIC;
+-
+- spin_lock_init(&s->lock);
+-
+- COMM ("setup busmaster memory")
+- s->recbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
+- s->playbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
+-
+- if (!s->recbuf || !s->playbuf) {
+- printk(KERN_ERR RME_MESS" Unable to allocate busmaster memory\n");
+- return -ENODEV;
+- }
+-
+- COMM ("setting rec and playbuffers")
+-
+- writel((u32) virt_to_bus(s->recbuf),s->iobase + RME96xx_rec_buffer);
+- writel((u32) virt_to_bus(s->playbuf),s->iobase + RME96xx_play_buffer);
+-
+- COMM ("initializing control register")
+- rme96xx_unset_ctrl(s,0xffffffff);
+- rme96xx_set_ctrl(s,RME96xx_ctrl_init);
+-
+-
+- COMM ("setup devices")
+- for (i=0;i < devices;i++) {
+- struct dmabuf * dma = &s->dma[i];
+- rme96xx_dmabuf_init(s,dma,2*i,2*i);
+- }
+-
+- /* code from ALSA card-rme9652.c HP 20020201 */
+- /* Determine the h/w rev level of the card. This seems like
+- a particularly kludgy way to encode it, but its what RME
+- chose to do, so we follow them ...
+- */
+-
+- status = readl(s->iobase + RME96xx_status_register);
+- if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) {
+- s->hw_rev = 15;
+- } else {
+- s->hw_rev = 11;
+- }
+-
+- /* Differentiate between the standard Hammerfall, and the
+- "Light", which does not have the expansion board. This
+- method comes from information received from Mathhias
+- Clausen at RME. Display the EEPROM and h/w revID where
+- relevant.
+- */
+-
+- pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev);
+- switch (rev & 0xff) {
+- case 8: /* original eprom */
+- if (s->hw_rev == 15) {
+- s->card_name = "RME Digi9636 (Rev 1.5)";
+- } else {
+- s->card_name = "RME Digi9636";
+- }
+- break;
+- case 9: /* W36_G EPROM */
+- s->card_name = "RME Digi9636 (Rev G)";
+- break;
+- case 4: /* W52_G EPROM */
+- s->card_name = "RME Digi9652 (Rev G)";
+- break;
+- default:
+- case 3: /* original eprom */
+- if (s->hw_rev == 15) {
+- s->card_name = "RME Digi9652 (Rev 1.5)";
+- } else {
+- s->card_name = "RME Digi9652";
+- }
+- break;
+- }
+-
+- printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev);
+-
+- if (s->hw_rev == 15)
+- rme96xx_initialize_spdif_receiver (s);
+-
+- s->started = 0;
+- rme96xx_setlatency(s,7);
+-
+- printk(KERN_INFO RME_MESS" card %d initialized\n",numcards);
+- return 0;
+-}
+-
+-
+-/* open uses this to figure out which device was opened .. this seems to be
+- unnecessary complex */
+-
+-static LIST_HEAD(devs);
+-
+-static int __devinit rme96xx_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+-{
+- int i;
+- rme96xx_info *s;
+-
+- DBG(printk("%s\n", __FUNCTION__));
+-
+- if (pcidev->irq == 0)
+- return -1;
+- if (!pci_dma_supported(pcidev, 0xffffffff)) {
+- printk(KERN_WARNING RME_MESS" architecture does not support 32bit PCI busmaster DMA\n");
+- return -1;
+- }
+- if (!(s = kmalloc(sizeof(rme96xx_info), GFP_KERNEL))) {
+- printk(KERN_WARNING RME_MESS" out of memory\n");
+- return -1;
+- }
+- memset(s, 0, sizeof(rme96xx_info));
+-
+- s->pcidev = pcidev;
+- s->iobase = ioremap(pci_resource_start(pcidev, 0),RME96xx_IO_EXTENT);
+- s->irq = pcidev->irq;
+-
+- DBG(printk("remapped iobase: %lx irq %d\n",(long)s->iobase,s->irq));
+-
+- if (pci_enable_device(pcidev))
+- goto err_irq;
+- if (request_irq(s->irq, rme96xx_interrupt, IRQF_SHARED, "rme96xx", s)) {
+- printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq);
+- goto err_irq;
+- }
+-
+- /* initialize the card */
+-
+- i = 0;
+- if (rme96xx_init(s) < 0) {
+- printk(KERN_ERR RME_MESS" initialization failed\n");
+- goto err_devices;
+- }
+- for (i=0;i<devices;i++) {
+- if ((s->dspnum[i] = register_sound_dsp(&rme96xx_audio_fops, -1)) < 0)
+- goto err_devices;
+- }
+-
+- if ((s->mixer = register_sound_mixer(&rme96xx_mixer_fops, -1)) < 0)
+- goto err_devices;
+-
+- pci_set_drvdata(pcidev, s);
+- pcidev->dma_mask = 0xffffffff; /* ????? */
+- /* put it into driver list */
+- list_add_tail(&s->devs, &devs);
+-
+- DBG(printk("initialization successful\n"));
+- return 0;
+-
+- /* error handler */
+- err_devices:
+- while (i--)
+- unregister_sound_dsp(s->dspnum[i]);
+- free_irq(s->irq,s);
+- err_irq:
+- kfree(s);
+- return -1;
+-}
+-
+-
+-static void __devexit rme96xx_remove(struct pci_dev *dev)
+-{
+- int i;
+- rme96xx_info *s = pci_get_drvdata(dev);
+-
+- if (!s) {
+- printk(KERN_ERR"device structure not valid\n");
+- return ;
+- }
+-
+- if (s->started) rme96xx_startcard(s,0);
+-
+- i = devices;
+- while (i) {
+- i--;
+- unregister_sound_dsp(s->dspnum[i]);
+- }
+-
+- unregister_sound_mixer(s->mixer);
+- synchronize_irq(s->irq);
+- free_irq(s->irq,s);
+- busmaster_free(s->recbuf,RME96xx_DMA_MAX_SIZE_ALL);
+- busmaster_free(s->playbuf,RME96xx_DMA_MAX_SIZE_ALL);
+- kfree(s);
+- pci_set_drvdata(dev, NULL);
+-}
+-
+-
+-#ifndef PCI_VENDOR_ID_RME
+-#define PCI_VENDOR_ID_RME 0x10ee
+-#endif
+-#ifndef PCI_DEVICE_ID_RME9652
+-#define PCI_DEVICE_ID_RME9652 0x3fc4
+-#endif
+-#ifndef PCI_ANY_ID
+-#define PCI_ANY_ID 0
+-#endif
+-
+-static struct pci_device_id id_table[] = {
+- {
+- .vendor = PCI_VENDOR_ID_RME,
+- .device = PCI_DEVICE_ID_RME9652,
+- .subvendor = PCI_ANY_ID,
+- .subdevice = PCI_ANY_ID,
+- },
+- { 0, },
+-};
+-
+-MODULE_DEVICE_TABLE(pci, id_table);
+-
+-static struct pci_driver rme96xx_driver = {
+- .name = "rme96xx",
+- .id_table = id_table,
+- .probe = rme96xx_probe,
+- .remove = __devexit_p(rme96xx_remove),
+-};
+-
+-static int __init init_rme96xx(void)
+-{
+- printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n");
+- devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
+- printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
+- numcards = 0;
+- return pci_register_driver(&rme96xx_driver);
+-}
+-
+-static void __exit cleanup_rme96xx(void)
+-{
+- printk(KERN_INFO RME_MESS" unloading\n");
+- pci_unregister_driver(&rme96xx_driver);
+-}
+-
+-module_init(init_rme96xx);
+-module_exit(cleanup_rme96xx);
+-
+-
+-
+-
+-
+-/*--------------------------------------------------------------------------
+- Implementation of file operations
+----------------------------------------------------------------------------*/
+-
+-#define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED)
+-/* AFTM_U8 is not (yet?) supported ... HP20020201 */
+-
+-static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct dmabuf * dma = (struct dmabuf *)file->private_data;
+- rme96xx_info *s = dma->s;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int count;
+- int val = 0;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+-
+- DBG(printk("ioctl %ud\n",cmd));
+-
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+-#if 0
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
+-#endif
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+-// rme96xx_clearbufs(dma);
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+-/* generally it's not a problem if we change the speed
+- if (dma->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
+- return -EINVAL;
+-*/
+- spin_lock_irqsave(&s->lock, flags);
+-
+- switch (val) {
+- case 44100:
+- case 88200:
+- rme96xx_unset_ctrl(s,RME96xx_freq);
+- break;
+- case 48000:
+- case 96000:
+- rme96xx_set_ctrl(s,RME96xx_freq);
+- break;
+- /* just report current rate as default
+- e.g. use 0 to "select" current digital input rate
+- default:
+- rme96xx_unset_ctrl(s,RME96xx_freq);
+- val = 44100;
+- */
+- }
+- if (val > 50000)
+- rme96xx_set_ctrl(s,RME96xx_DS);
+- else
+- rme96xx_unset_ctrl(s,RME96xx_DS);
+- /* set val to actual value HP 20020201 */
+- /* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */
+- if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel))
+- val = rme96xx_get_sample_rate_ctrl(s);
+- else
+- val = rme96xx_get_sample_rate_status(s);
+- s->rate = val;
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- DBG(printk("speed set to %d\n",val));
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_STEREO: /* this plays a mono file on two channels */
+- if (get_user(val, p))
+- return -EFAULT;
+-
+- if (!val) {
+- DBG(printk("setting to mono\n"));
+- dma->mono=1;
+- dma->inchannels = 1;
+- dma->outchannels = 1;
+- }
+- else {
+- DBG(printk("setting to stereo\n"));
+- dma->mono = 0;
+- dma->inchannels = 2;
+- dma->outchannels = 2;
+- }
+- return 0;
+- case SNDCTL_DSP_CHANNELS:
+- /* remember to check for resonable offset/channel pairs here */
+- if (get_user(val, p))
+- return -EFAULT;
+-
+- if (file->f_mode & FMODE_WRITE) {
+- if (val > 0 && (dma->outoffset + val) <= RME96xx_CHANNELS_PER_CARD)
+- dma->outchannels = val;
+- else
+- dma->outchannels = val = 2;
+- DBG(printk("setting to outchannels %d\n",val));
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (val > 0 && (dma->inoffset + val) <= RME96xx_CHANNELS_PER_CARD)
+- dma->inchannels = val;
+- else
+- dma->inchannels = val = 2;
+- DBG(printk("setting to inchannels %d\n",val));
+- }
+-
+- dma->mono=0;
+-
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(RME96xx_FMT, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- DBG(printk("setting to format %x\n",val));
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- if (val & RME96xx_FMT)
+- dma->format = val;
+- switch (dma->format) {
+- case AFMT_S16_LE:
+- dma->formatshift=1;
+- break;
+- case AFMT_S32_BLOCKED:
+- dma->formatshift=0;
+- break;
+- }
+- }
+- return put_user(dma->format, p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+-#if 0
+- if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN)
+- val |= PCM_ENABLE_OUTPUT;
+-#endif
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+-#if 0
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+- return ret;
+- start_adc(s);
+- } else
+- stop_adc(s);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+- return ret;
+- start_dac2(s);
+- } else
+- stop_dac2(s);
+- }
+-#endif
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+-
+- val = rme96xx_gethwptr(dma->s,0);
+-
+-
+- count = rme96xx_getospace(dma,val);
+- if (!s->started) count = s->fragsize*2;
+- abinfo.fragsize =(s->fragsize*dma->outchannels)>>dma->formatshift;
+- abinfo.bytes = (count*dma->outchannels)>>dma->formatshift;
+- abinfo.fragstotal = 2;
+- abinfo.fragments = (count > s->fragsize);
+-
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+-
+- val = rme96xx_gethwptr(dma->s,0);
+-
+- count = rme96xx_getispace(dma,val);
+-
+- abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift;
+- abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;
+- abinfo.fragstotal = 2;
+- abinfo.fragments = count > s->fragsize;
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY: /* What should this exactly do ? ,
+- ATM it is just abinfo.bytes */
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+-
+- val = rme96xx_gethwptr(dma->s,0);
+- count = val - dma->readptr;
+- if (count < 0)
+- count += s->fragsize<<1;
+-
+- return put_user(count, p);
+-
+-
+-/* check out how to use mmaped mode (can only be blocked !!!) */
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- val = rme96xx_gethwptr(dma->s,0);
+- spin_lock_irqsave(&s->lock,flags);
+- cinfo.bytes = s->fragsize<<1;
+- count = val - dma->readptr;
+- if (count < 0)
+- count += s->fragsize<<1;
+-
+- cinfo.blocks = (count > s->fragsize);
+- cinfo.ptr = val;
+- if (dma->mmapped)
+- dma->readptr &= s->fragsize<<1;
+- spin_unlock_irqrestore(&s->lock,flags);
+-
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- val = rme96xx_gethwptr(dma->s,0);
+- spin_lock_irqsave(&s->lock,flags);
+- cinfo.bytes = s->fragsize<<1;
+- count = val - dma->writeptr;
+- if (count < 0)
+- count += s->fragsize<<1;
+-
+- cinfo.blocks = (count > s->fragsize);
+- cinfo.ptr = val;
+- if (dma->mmapped)
+- dma->writeptr &= s->fragsize<<1;
+- spin_unlock_irqrestore(&s->lock,flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+- case SNDCTL_DSP_GETBLKSIZE:
+- return put_user(s->fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- val&=0xffff;
+- val -= 7;
+- if (val < 0) val = 0;
+- if (val > 7) val = 7;
+- rme96xx_setlatency(s,val);
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+-#if 0
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE)
+- s->dma_dac2.subdivision = val;
+-#endif
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- /* HP20020201 */
+- s->rate = rme96xx_get_sample_rate_status(s);
+- return put_user(s->rate, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user(dma->outchannels, p);
+-
+- case SOUND_PCM_READ_BITS:
+- switch (dma->format) {
+- case AFMT_S32_BLOCKED:
+- val = 32;
+- break;
+- case AFMT_S16_LE:
+- val = 16;
+- break;
+- }
+- return put_user(val, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+-
+-
+- return -ENODEV;
+-}
+-
+-
+-
+-static int rme96xx_open(struct inode *in, struct file *f)
+-{
+- int minor = iminor(in);
+- struct list_head *list;
+- int devnum;
+- rme96xx_info *s;
+- struct dmabuf* dma;
+- DECLARE_WAITQUEUE(wait, current);
+-
+- DBG(printk("device num %d open\n",devnum));
+-
+- nonseekable_open(in, f);
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, rme96xx_info, devs);
+- for (devnum=0; devnum<devices; devnum++)
+- if (!((s->dspnum[devnum] ^ minor) & ~0xf))
+- break;
+- if (devnum<devices)
+- break;
+- }
+- VALIDATE_STATE(s);
+-
+- dma = &s->dma[devnum];
+- f->private_data = dma;
+- /* wait for device to become free */
+- mutex_lock(&dma->open_mutex);
+- while (dma->open_mode & f->f_mode) {
+- if (f->f_flags & O_NONBLOCK) {
+- mutex_unlock(&dma->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&dma->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&dma->open_mutex);
+- schedule();
+- remove_wait_queue(&dma->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&dma->open_mutex);
+- }
+-
+- COMM ("hardware open")
+-
+- if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset);
+-
+- dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
+- dma->opened = 1;
+- mutex_unlock(&dma->open_mutex);
+-
+- DBG(printk("device num %d open finished\n",devnum));
+- return 0;
+-}
+-
+-static int rme96xx_release(struct inode *in, struct file *file)
+-{
+- struct dmabuf * dma = (struct dmabuf*) file->private_data;
+- /* int hwp; ... was unused HP20020201 */
+- DBG(printk("%s\n", __FUNCTION__));
+-
+- COMM ("draining")
+- if (dma->open_mode & FMODE_WRITE) {
+-#if 0 /* Why doesn't this work with some cards ?? */
+- hwp = rme96xx_gethwptr(dma->s,0);
+- while (rme96xx_getospace(dma,hwp)) {
+- interruptible_sleep_on(&(dma->wait));
+- hwp = rme96xx_gethwptr(dma->s,0);
+- }
+-#endif
+- rme96xx_clearbufs(dma);
+- }
+-
+- dma->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+-
+- if (!(dma->open_mode & (FMODE_READ|FMODE_WRITE))) {
+- dma->opened = 0;
+- if (dma->s->started) rme96xx_startcard(dma->s,1);
+- }
+-
+- wake_up(&dma->open_wait);
+- mutex_unlock(&dma->open_mutex);
+-
+- return 0;
+-}
+-
+-
+-static ssize_t rme96xx_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct dmabuf *dma = (struct dmabuf *)file->private_data;
+- ssize_t ret = 0;
+- int cnt; /* number of bytes from "buffer" that will/can be used */
+- int hop = count/dma->outchannels;
+- int hwp;
+- int exact = (file->f_flags & O_NONBLOCK);
+-
+-
+- if(dma == NULL || (dma->s) == NULL)
+- return -ENXIO;
+-
+- if (dma->mmapped || !dma->opened)
+- return -ENXIO;
+-
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+-
+- if (! (dma->open_mode & FMODE_WRITE))
+- return -ENXIO;
+-
+- if (!dma->s->started) rme96xx_startcard(dma->s,exact);
+- hwp = rme96xx_gethwptr(dma->s,0);
+-
+- if(!(dma->started)){
+- COMM ("first write")
+-
+- dma->readptr = hwp;
+- dma->writeptr = hwp;
+- dma->started = 1;
+- }
+-
+- while (count > 0) {
+- cnt = rme96xx_getospace(dma,hwp);
+- cnt>>=dma->formatshift;
+- cnt*=dma->outchannels;
+- if (cnt > count)
+- cnt = count;
+-
+- if (cnt != 0) {
+- if (rme96xx_copyfromuser(dma,buffer,cnt,hop))
+- return ret ? ret : -EFAULT;
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (count == 0) return ret;
+- }
+- if (file->f_flags & O_NONBLOCK)
+- return ret ? ret : -EAGAIN;
+-
+- if ((hwp - dma->writeptr) <= 0) {
+- interruptible_sleep_on(&(dma->wait));
+-
+- if (signal_pending(current))
+- return ret ? ret : -ERESTARTSYS;
+- }
+-
+- hwp = rme96xx_gethwptr(dma->s,exact);
+-
+- }; /* count > 0 */
+-
+- return ret;
+-}
+-
+-static ssize_t rme96xx_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct dmabuf *dma = (struct dmabuf *)file->private_data;
+- ssize_t ret = 0;
+- int cnt; /* number of bytes from "buffer" that will/can be used */
+- int hop = count/dma->inchannels;
+- int hwp;
+- int exact = (file->f_flags & O_NONBLOCK);
+-
+-
+- if(dma == NULL || (dma->s) == NULL)
+- return -ENXIO;
+-
+- if (dma->mmapped || !dma->opened)
+- return -ENXIO;
+-
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+-
+- if (! (dma->open_mode & FMODE_READ))
+- return -ENXIO;
+-
+- if (!dma->s->started) rme96xx_startcard(dma->s,exact);
+- hwp = rme96xx_gethwptr(dma->s,0);
+-
+- if(!(dma->started)){
+- COMM ("first read")
+-
+- dma->writeptr = hwp;
+- dma->readptr = hwp;
+- dma->started = 1;
+- }
+-
+- while (count > 0) {
+- cnt = rme96xx_getispace(dma,hwp);
+- cnt>>=dma->formatshift;
+- cnt*=dma->inchannels;
+-
+- if (cnt > count)
+- cnt = count;
+-
+- if (cnt != 0) {
+-
+- if (rme96xx_copytouser(dma,buffer,cnt,hop))
+- return ret ? ret : -EFAULT;
+-
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (count == 0) return ret;
+- }
+- if (file->f_flags & O_NONBLOCK)
+- return ret ? ret : -EAGAIN;
+-
+- if ((hwp - dma->readptr) <= 0) {
+- interruptible_sleep_on(&(dma->wait));
+-
+- if (signal_pending(current))
+- return ret ? ret : -ERESTARTSYS;
+- }
+- hwp = rme96xx_gethwptr(dma->s,exact);
+-
+- }; /* count > 0 */
+-
+- return ret;
+-}
+-
+-static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) {
+- struct dmabuf *dma = (struct dmabuf *)file->private_data;
+- rme96xx_info* s = dma->s;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+-
+- if (vma->vm_pgoff != 0) {
+- unlock_kernel();
+- return -EINVAL;
+- }
+- size = vma->vm_end - vma->vm_start;
+- if (size > RME96xx_DMA_MAX_SIZE) {
+- unlock_kernel();
+- return -EINVAL;
+- }
+-
+-
+- if (vma->vm_flags & VM_WRITE) {
+- if (!s->started) rme96xx_startcard(s,1);
+-
+- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
+- unlock_kernel();
+- return -EAGAIN;
+- }
+- }
+- else if (vma->vm_flags & VM_READ) {
+- if (!s->started) rme96xx_startcard(s,1);
+- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
+- unlock_kernel();
+- return -EAGAIN;
+- }
+- } else {
+- unlock_kernel();
+- return -EINVAL;
+- }
+-
+-
+-/* this is the mapping */
+- vma->vm_flags &= ~VM_IO;
+- dma->mmapped = 1;
+- unlock_kernel();
+- return 0;
+-}
+-
+-static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct dmabuf *dma = (struct dmabuf *)file->private_data;
+- rme96xx_info* s = dma->s;
+- unsigned int mask = 0;
+- unsigned int hwp,cnt;
+-
+- DBG(printk("rme96xx poll_wait ...\n"));
+- VALIDATE_STATE(s);
+-
+- if (!s->started) {
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- poll_wait(file, &dma->wait, wait);
+-
+- hwp = rme96xx_gethwptr(dma->s,0);
+-
+- DBG(printk("rme96xx poll: ..cnt %d > %d\n",cnt,s->fragsize));
+-
+- cnt = rme96xx_getispace(dma,hwp);
+-
+- if (file->f_mode & FMODE_READ)
+- if (cnt > 0)
+- mask |= POLLIN | POLLRDNORM;
+-
+-
+-
+- cnt = rme96xx_getospace(dma,hwp);
+-
+- if (file->f_mode & FMODE_WRITE)
+- if (cnt > 0)
+- mask |= POLLOUT | POLLWRNORM;
+-
+-
+-// printk("rme96xx poll_wait ...%d > %d\n",rme96xx_getospace(dma,hwp),rme96xx_getispace(dma,hwp));
+-
+- return mask;
+-}
+-
+-
+-static struct file_operations rme96xx_audio_fops = {
+- .owner = THIS_MODULE,
+- .read = rme96xx_read,
+- .write = rme96xx_write,
+- .poll = rme96xx_poll,
+- .ioctl = rme96xx_ioctl,
+- .mmap = rm96xx_mmap,
+- .open = rme96xx_open,
+- .release = rme96xx_release
+-};
+-
+-static int rme96xx_mixer_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- struct list_head *list;
+- rme96xx_info *s;
+-
+- COMM ("mixer open");
+-
+- nonseekable_open(inode, file);
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, rme96xx_info, devs);
+- if (s->mixer== minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+-
+- COMM ("mixer opened")
+- return 0;
+-}
+-
+-static int rme96xx_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- rme96xx_info *s = (rme96xx_info *)file->private_data;
+- u32 status;
+- int spdifrate;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- status = readl(s->iobase + RME96xx_status_register);
+- /* hack to convert rev 1.5 SPDIF rate to "crystalrate" format HP 20020201 */
+- rme96xx_spdif_sample_rate(s,&spdifrate);
+- status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F);
+-
+- VALIDATE_STATE(s);
+- if (cmd == SOUND_MIXER_PRIVATE1) {
+- rme_mixer mixer;
+- if (copy_from_user(&mixer,argp,sizeof(mixer)))
+- return -EFAULT;
+-
+- mixer.devnr &= RME96xx_MASK_DEVS;
+- if (mixer.devnr >= devices)
+- mixer.devnr = devices-1;
+- if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) {
+- /* modify only if device not open */
+- if (mixer.o_offset < 0)
+- mixer.o_offset = 0;
+- if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD)
+- mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1;
+- if (mixer.i_offset < 0)
+- mixer.i_offset = 0;
+- if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD)
+- mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1;
+- s->dma[mixer.devnr].outoffset = mixer.o_offset;
+- s->dma[mixer.devnr].inoffset = mixer.i_offset;
+- }
+-
+- mixer.o_offset = s->dma[mixer.devnr].outoffset;
+- mixer.i_offset = s->dma[mixer.devnr].inoffset;
+-
+- return copy_to_user(argp, &mixer, sizeof(mixer)) ? -EFAULT : 0;
+- }
+- if (cmd == SOUND_MIXER_PRIVATE2) {
+- return put_user(status, p);
+- }
+- if (cmd == SOUND_MIXER_PRIVATE3) {
+- u32 control;
+- if (copy_from_user(&control,argp,sizeof(control)))
+- return -EFAULT;
+- if (file->f_mode & FMODE_WRITE) {
+- s->control_register &= ~RME96xx_mixer_allowed;
+- s->control_register |= control & RME96xx_mixer_allowed;
+- writel(control,s->iobase + RME96xx_control_register);
+- }
+-
+- return put_user(s->control_register, p);
+- }
+- return -1;
+-}
+-
+-
+-
+-static int rme96xx_mixer_release(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations rme96xx_mixer_fops = {
+- .owner = THIS_MODULE,
+- .ioctl = rme96xx_mixer_ioctl,
+- .open = rme96xx_mixer_open,
+- .release = rme96xx_mixer_release,
+-};
+diff --git a/sound/oss/rme96xx.h b/sound/oss/rme96xx.h
+deleted file mode 100644
+index 7a3c188..0000000
+--- a/sound/oss/rme96xx.h
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/* (C) 2000 Guenter Geiger <geiger at debian.org>
+- with copy/pastes from the driver of Winfried Ritsch <ritsch at iem.kug.ac.at>
+-
+-Modifications - Heiko Purnhagen <purnhage at tnt.uni-hannover.de>
+- HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
+- HP20020201 completed?
+-
+-A text/graphic control panel (rmectrl/xrmectrl) is available from
+- http://gige.xdv.org/pages/soft/pages/rme
+-*/
+-
+-
+-#ifndef AFMT_S32_BLOCKED
+-#define AFMT_S32_BLOCKED 0x0000400
+-#endif
+-
+-/* AFMT_S16_BLOCKED not yet supported */
+-#ifndef AFMT_S16_BLOCKED
+-#define AFMT_S16_BLOCKED 0x0000800
+-#endif
+-
+-
+-typedef struct rme_status {
+- unsigned int irq:1;
+- unsigned int lockmask:3; /* ADAT input PLLs locked */
+- /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
+- unsigned int sr48:1; /* sample rate: 0=44.1/88.2 1=48/96 kHz */
+- unsigned int wclock:1; /* 1=wordclock used */
+- unsigned int bufpoint:10;
+- unsigned int syncmask:3; /* ADAT input in sync with system clock */
+- /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
+- unsigned int doublespeed:1; /* sample rate: 0=44.1/48 1=88.2/96 kHz */
+- unsigned int tc_busy:1;
+- unsigned int tc_out:1;
+- unsigned int crystalrate:3; /* spdif input sample rate: */
+- /* 000=64kHz, 100=88.2kHz, 011=96kHz */
+- /* 111=32kHz, 110=44.1kHz, 101=48kHz */
+- unsigned int spdif_error:1; /* 1=no spdif lock */
+- unsigned int bufid:1;
+- unsigned int tc_valid:1; /* 1=timecode input detected */
+- unsigned int spdif_read:1;
+-} rme_status_t;
+-
+-
+-/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */
+-typedef struct rme_control {
+- unsigned int start:1;
+- unsigned int latency:3; /* buffer size / latency [samples]: */
+- /* 0=64 ... 7=8192 */
+- unsigned int master:1; /* W: clock mode: 1=master 0=slave/auto */
+- unsigned int ie:1;
+- unsigned int sr48:1; /* samplerate 0=44.1/88.2, 1=48/96 kHz */
+- unsigned int spare:1;
+- unsigned int doublespeed:1; /* double speed 0=44.1/48, 1=88.2/96 Khz */
+- unsigned int pro:1; /* W: SPDIF-OUT 0=consumer, 1=professional */
+- unsigned int emphasis:1; /* W: SPDIF-OUT emphasis 0=off, 1=on */
+- unsigned int dolby:1; /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */
+- unsigned int opt_out:1; /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */
+- unsigned int wordclock:1; /* W: use Wordclock as sync (overwrites master) */
+- unsigned int spdif_in:2; /* W: SPDIF-IN: */
+- /* 00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */
+- unsigned int sync_ref:2; /* W: preferred sync-source in autosync */
+- /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
+- unsigned int spdif_reset:1;
+- unsigned int spdif_select:1;
+- unsigned int spdif_clock:1;
+- unsigned int spdif_write:1;
+- unsigned int adat1_cd:1; /* W: Rev 1.5+: if set, internal CD connector carries ADAT */
+-} rme_ctrl_t;
+-
+-
+-typedef struct _rme_mixer {
+- int i_offset;
+- int o_offset;
+- int devnr;
+- int spare[8];
+-} rme_mixer;
+-
+diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c
+index 75e54f6..733b014 100644
+--- a/sound/oss/sb_audio.c
++++ b/sound/oss/sb_audio.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sb_audio.c
++ * sound/oss/sb_audio.c
+ *
+ * Audio routines for Sound Blaster compatible cards.
+ *
+diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
+index 35bab6e..440537c 100644
+--- a/sound/oss/sb_common.c
++++ b/sound/oss/sb_common.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sb_common.c
++ * sound/oss/sb_common.c
+ *
+ * Common routines for Sound Blaster compatible cards.
+ *
+@@ -132,7 +132,7 @@ static void sb_intr (sb_devc *devc)
+
+ if (src & 4) /* MPU401 interrupt */
+ if(devc->midi_irq_cookie)
+- uart401intr(devc->irq, devc->midi_irq_cookie, NULL);
++ uart401intr(devc->irq, devc->midi_irq_cookie);
+
+ if (!(src & 3))
+ return; /* Not a DSP interrupt */
+@@ -200,7 +200,7 @@ static void pci_intr(sb_devc *devc)
+ sb_intr(devc);
+ }
+
+-static irqreturn_t sbintr(int irq, void *dev_id, struct pt_regs *dummy)
++static irqreturn_t sbintr(int irq, void *dev_id)
+ {
+ sb_devc *devc = dev_id;
+
+diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c
+index ed3bd06..2e3bc04 100644
+--- a/sound/oss/sb_midi.c
++++ b/sound/oss/sb_midi.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sb_dsp.c
++ * sound/oss/sb_midi.c
+ *
+ * The low level driver for the Sound Blaster DS chips.
+ *
+diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c
+index ccb21d4..238e2cf 100644
+--- a/sound/oss/sb_mixer.c
++++ b/sound/oss/sb_mixer.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sb_mixer.c
++ * sound/oss/sb_mixer.c
+ *
+ * The low level mixer driver for the Sound Blaster compatible cards.
+ */
+diff --git a/sound/oss/sb_mixer.h b/sound/oss/sb_mixer.h
+index ab74426..4b9425f 100644
+--- a/sound/oss/sb_mixer.h
++++ b/sound/oss/sb_mixer.h
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sb_mixer.h
++ * sound/oss/sb_mixer.h
+ *
+ * Definitions for the SB Pro and SB16 mixers
+ */
+diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
+index 6815c30..5c215f7 100644
+--- a/sound/oss/sequencer.c
++++ b/sound/oss/sequencer.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sequencer.c
++ * sound/oss/sequencer.c
+ *
+ * The sequencer personality manager.
+ */
+@@ -16,7 +16,6 @@
+ */
+ #include <linux/kmod.h>
+ #include <linux/spinlock.h>
+-#define SEQUENCER_C
+ #include "sound_config.h"
+
+ #include "midi_ctrl.h"
+@@ -157,6 +156,7 @@ void seq_copy_to_input(unsigned char *ev
+ wake_up(&midi_sleeper);
+ spin_unlock_irqrestore(&lock,flags);
+ }
++EXPORT_SYMBOL(seq_copy_to_input);
+
+ static void sequencer_midi_input(int dev, unsigned char data)
+ {
+@@ -206,6 +206,7 @@ void seq_input_event(unsigned char *even
+ }
+ seq_copy_to_input(event_rec, len);
+ }
++EXPORT_SYMBOL(seq_input_event);
+
+ int sequencer_write(int dev, struct file *file, const char __user *buf, int count)
+ {
+@@ -1554,6 +1555,7 @@ void sequencer_timer(unsigned long dummy
+ {
+ seq_startplay();
+ }
++EXPORT_SYMBOL(sequencer_timer);
+
+ int note_to_freq(int note_num)
+ {
+@@ -1587,6 +1589,7 @@ int note_to_freq(int note_num)
+
+ return note_freq;
+ }
++EXPORT_SYMBOL(note_to_freq);
+
+ unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
+ int vibrato_cents)
+@@ -1640,19 +1643,12 @@ unsigned long compute_finetune(unsigned
+ else
+ return (base_freq * amount) / 10000; /* Bend up */
+ }
+-
++EXPORT_SYMBOL(compute_finetune);
+
+ void sequencer_init(void)
+ {
+- /* drag in sequencer_syms.o */
+- {
+- extern char sequencer_syms_symbol;
+- sequencer_syms_symbol = 0;
+- }
+-
+ if (sequencer_ok)
+ return;
+- MIDIbuf_init();
+ queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
+ if (queue == NULL)
+ {
+@@ -1668,6 +1664,7 @@ void sequencer_init(void)
+ }
+ sequencer_ok = 1;
+ }
++EXPORT_SYMBOL(sequencer_init);
+
+ void sequencer_unload(void)
+ {
+diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c
+deleted file mode 100644
+index 5d00879..0000000
+--- a/sound/oss/sequencer_syms.c
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * Exported symbols for sequencer driver.
+- */
+-
+-#include <linux/module.h>
+-
+-char sequencer_syms_symbol;
+-
+-#include "sound_config.h"
+-#include "sound_calls.h"
+-
+-EXPORT_SYMBOL(note_to_freq);
+-EXPORT_SYMBOL(compute_finetune);
+-EXPORT_SYMBOL(seq_copy_to_input);
+-EXPORT_SYMBOL(seq_input_event);
+-EXPORT_SYMBOL(sequencer_init);
+-EXPORT_SYMBOL(sequencer_timer);
+-
+-EXPORT_SYMBOL(sound_timer_init);
+-EXPORT_SYMBOL(sound_timer_interrupt);
+-EXPORT_SYMBOL(sound_timer_syncinterval);
+-
+-/* Tuning */
+-
+-#define _SEQUENCER_C_
+-#include "tuning.h"
+-
+-EXPORT_SYMBOL(cent_tuning);
+-EXPORT_SYMBOL(semitone_tuning);
+diff --git a/sound/oss/sgalaxy.c b/sound/oss/sgalaxy.c
+deleted file mode 100644
+index 3f32d46..0000000
+--- a/sound/oss/sgalaxy.c
++++ /dev/null
+@@ -1,207 +0,0 @@
+-/*
+- * sound/sgalaxy.c
+- *
+- * Low level driver for Aztech Sound Galaxy cards.
+- * Copyright 1998 Artur Skawina <skawina at geocities.com>
+- *
+- * Supported cards:
+- * Aztech Sound Galaxy Waverider Pro 32 - 3D
+- * Aztech Sound Galaxy Washington 16
+- *
+- * Based on cs4232.c by Hannu Savolainen and Alan Cox.
+- *
+- *
+- * Copyright (C) by Hannu Savolainen 1993-1997
+- *
+- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- * Changes:
+- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz at linux-ide.org>
+- * Added __init to sb_rst() and sb_cmd()
+- */
+-
+-#include <linux/init.h>
+-#include <linux/module.h>
+-
+-#include "sound_config.h"
+-#include "ad1848.h"
+-
+-static void sleep( unsigned howlong )
+-{
+- current->state = TASK_INTERRUPTIBLE;
+- schedule_timeout(howlong);
+-}
+-
+-#define DPORT 0x80
+-
+-/* Sound Blaster regs */
+-
+-#define SBDSP_RESET 0x6
+-#define SBDSP_READ 0xA
+-#define SBDSP_COMMAND 0xC
+-#define SBDSP_STATUS SBDSP_COMMAND
+-#define SBDSP_DATA_AVAIL 0xE
+-
+-static int __init sb_rst(int base)
+-{
+- int i;
+-
+- outb( 1, base+SBDSP_RESET ); /* reset the DSP */
+- outb( 0, base+SBDSP_RESET );
+-
+- for ( i=0; i<500; i++ ) /* delay */
+- inb(DPORT);
+-
+- for ( i=0; i<100000; i++ )
+- {
+- if ( inb( base+SBDSP_DATA_AVAIL )&0x80 )
+- break;
+- }
+-
+- if ( inb( base+SBDSP_READ )!=0xAA )
+- return 0;
+-
+- return 1;
+-}
+-
+-static int __init sb_cmd( int base, unsigned char val )
+-{
+- int i;
+-
+- for ( i=100000; i; i-- )
+- {
+- if ( (inb( base+SBDSP_STATUS )&0x80)==0 )
+- {
+- outb( val, base+SBDSP_COMMAND );
+- break;
+- }
+- }
+- return i; /* i>0 == success */
+-}
+-
+-
+-#define ai_sgbase driver_use_1
+-
+-static int __init probe_sgalaxy( struct address_info *ai )
+-{
+- struct resource *ports;
+- int n;
+-
+- if (!request_region(ai->io_base, 4, "WSS config")) {
+- printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
+- return 0;
+- }
+-
+- ports = request_region(ai->io_base + 4, 4, "ad1848");
+- if (!ports) {
+- printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
+- release_region(ai->io_base, 4);
+- return 0;
+- }
+-
+- if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) {
+- printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
+- release_region(ai->io_base + 4, 4);
+- release_region(ai->io_base, 4);
+- return 0;
+- }
+-
+- if (ad1848_detect(ports, NULL, ai->osp))
+- goto out; /* The card is already active, check irq etc... */
+-
+- /* switch to MSS/WSS mode */
+-
+- sb_rst( ai->ai_sgbase );
+-
+- sb_cmd( ai->ai_sgbase, 9 );
+- sb_cmd( ai->ai_sgbase, 0 );
+-
+- sleep( HZ/10 );
+-
+-out:
+- if (!probe_ms_sound(ai, ports)) {
+- release_region(ai->io_base + 4, 4);
+- release_region(ai->io_base, 4);
+- release_region(ai->ai_sgbase, 0x10);
+- return 0;
+- }
+-
+- attach_ms_sound(ai, ports, THIS_MODULE);
+- n=ai->slots[0];
+-
+- if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
+- AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */
+- AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/
+- AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */
+- }
+- return 1;
+-}
+-
+-static void __exit unload_sgalaxy( struct address_info *ai )
+-{
+- unload_ms_sound( ai );
+- release_region( ai->ai_sgbase, 0x10 );
+-}
+-
+-static struct address_info cfg;
+-
+-static int __initdata io = -1;
+-static int __initdata irq = -1;
+-static int __initdata dma = -1;
+-static int __initdata dma2 = -1;
+-static int __initdata sgbase = -1;
+-
+-module_param(io, int, 0);
+-module_param(irq, int, 0);
+-module_param(dma, int, 0);
+-module_param(dma2, int, 0);
+-module_param(sgbase, int, 0);
+-
+-static int __init init_sgalaxy(void)
+-{
+- cfg.io_base = io;
+- cfg.irq = irq;
+- cfg.dma = dma;
+- cfg.dma2 = dma2;
+- cfg.ai_sgbase = sgbase;
+-
+- if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
+- printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
+- return -EINVAL;
+- }
+-
+- if ( probe_sgalaxy(&cfg) == 0 )
+- return -ENODEV;
+-
+- return 0;
+-}
+-
+-static void __exit cleanup_sgalaxy(void)
+-{
+- unload_sgalaxy(&cfg);
+-}
+-
+-module_init(init_sgalaxy);
+-module_exit(cleanup_sgalaxy);
+-
+-#ifndef MODULE
+-static int __init setup_sgalaxy(char *str)
+-{
+- /* io, irq, dma, dma2, sgbase */
+- int ints[6];
+-
+- str = get_options(str, ARRAY_SIZE(ints), ints);
+- io = ints[1];
+- irq = ints[2];
+- dma = ints[3];
+- dma2 = ints[4];
+- sgbase = ints[5];
+-
+- return 1;
+-}
+-
+-__setup("sgalaxy=", setup_sgalaxy);
+-#endif
+-MODULE_LICENSE("GPL");
+diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
+index 7b168d8..51f5541 100644
+--- a/sound/oss/sh_dac_audio.c
++++ b/sound/oss/sh_dac_audio.c
+@@ -1,3 +1,14 @@
++/*
++ * sound/oss/sh_dac_audio.c
++ *
++ * SH DAC based sound :(
++ *
++ * Copyright (C) 2004,2005 Andriy Skulysh
++ *
++ * 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/module.h>
+ #include <linux/init.h>
+ #include <linux/sched.h>
+@@ -6,18 +17,17 @@
+ #include <linux/fs.h>
+ #include <linux/sound.h>
+ #include <linux/soundcard.h>
++#include <linux/interrupt.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/irq.h>
+ #include <asm/delay.h>
+-#include <linux/interrupt.h>
+-
++#include <asm/clock.h>
+ #include <asm/cpu/dac.h>
+-
+-#ifdef MACH_HP600
+-#include <asm/hp6xx/hp6xx.h>
+-#include <asm/hd64461/hd64461.h>
+-#endif
++#include <asm/cpu/timer.h>
++#include <asm/machvec.h>
++#include <asm/hp6xx.h>
++#include <asm/hd64461.h>
+
+ #define MODNAME "sh_dac_audio"
+
+@@ -26,11 +36,6 @@
+ #define TMU1_TCR_INIT 0x0020 /* Clock/4, rising edge; interrupt on */
+ #define TMU1_TSTR_INIT 0x02 /* Bit to turn on TMU1 */
+
+-#define TMU_TSTR 0xfffffe92
+-#define TMU1_TCOR 0xfffffea0
+-#define TMU1_TCNT 0xfffffea4
+-#define TMU1_TCR 0xfffffea8
+-
+ #define BUFFER_SIZE 48000
+
+ static int rate;
+@@ -71,34 +76,37 @@ static void dac_audio_sync(void)
+
+ static void dac_audio_start(void)
+ {
+-#ifdef MACH_HP600
+- u16 v;
+- v = inw(HD64461_GPADR);
+- v &= ~HD64461_GPADR_SPEAKER;
+- outw(v, HD64461_GPADR);
+-#endif
++ if (mach_is_hp6xx()) {
++ u16 v = inw(HD64461_GPADR);
++ v &= ~HD64461_GPADR_SPEAKER;
++ outw(v, HD64461_GPADR);
++ }
++
+ sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+ ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
+ }
+ static void dac_audio_stop(void)
+ {
+-#ifdef MACH_HP600
+- u16 v;
+-#endif
+ dac_audio_stop_timer();
+-#ifdef MACH_HP600
+- v = inw(HD64461_GPADR);
+- v |= HD64461_GPADR_SPEAKER;
+- outw(v, HD64461_GPADR);
+-#endif
++
++ if (mach_is_hp6xx()) {
++ u16 v = inw(HD64461_GPADR);
++ v |= HD64461_GPADR_SPEAKER;
++ outw(v, HD64461_GPADR);
++ }
++
++ sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+ sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+ }
+
+ static void dac_audio_set_rate(void)
+ {
+ unsigned long interval;
++ struct clk *clk;
+
+- interval = (current_cpu_data.module_clock / 4) / rate;
++ clk = clk_get("module_clk");
++ interval = (clk_get_rate(clk) / 4) / rate;
++ clk_put(clk);
+ ctrl_outl(interval, TMU1_TCOR);
+ ctrl_outl(interval, TMU1_TCNT);
+ }
+@@ -255,7 +263,7 @@ struct file_operations dac_audio_fops =
+ .release = dac_audio_release,
+ };
+
+-static irqreturn_t timer1_interrupt(int irq, void *dev, struct pt_regs *regs)
++static irqreturn_t timer1_interrupt(int irq, void *dev)
+ {
+ unsigned long timer_status;
+
+diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
+deleted file mode 100644
+index 8ea532d..0000000
+--- a/sound/oss/sonicvibes.c
++++ /dev/null
+@@ -1,2792 +0,0 @@
+-/*****************************************************************************/
+-
+-/*
+- * sonicvibes.c -- S3 Sonic Vibes audio driver.
+- *
+- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer at alumni.ethz.ch)
+- *
+- * 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.
+- *
+- * Special thanks to David C. Niemi
+- *
+- *
+- * Module command line parameters:
+- * none so far
+- *
+- *
+- * Supported devices:
+- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+- * /dev/midi simple MIDI UART interface, no ioctl
+- *
+- * The card has both an FM and a Wavetable synth, but I have to figure
+- * out first how to drive them...
+- *
+- * Revision history
+- * 06.05.1998 0.1 Initial release
+- * 10.05.1998 0.2 Fixed many bugs, esp. ADC rate calculation
+- * First stab at a simple midi interface (no bells&whistles)
+- * 13.05.1998 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
+- * set_dac_rate in the FMODE_WRITE case in sv_open
+- * Fix hwptr out of bounds (now mpg123 works)
+- * 14.05.1998 0.4 Don't allow excessive interrupt rates
+- * 08.06.1998 0.5 First release using Alan Cox' soundcore instead of miscdevice
+- * 03.08.1998 0.6 Do not include modversions.h
+- * Now mixer behaviour can basically be selected between
+- * "OSS documented" and "OSS actual" behaviour
+- * 31.08.1998 0.7 Fix realplayer problems - dac.count issues
+- * 10.12.1998 0.8 Fix drain_dac trying to wait on not yet initialized DMA
+- * 16.12.1998 0.9 Fix a few f_file & FMODE_ bugs
+- * 06.01.1999 0.10 remove the silly SA_INTERRUPT flag.
+- * hopefully killed the egcs section type conflict
+- * 12.03.1999 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
+- * reported by Johan Maes <joma at telindus.be>
+- * 22.03.1999 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
+- * read/write cannot be executed
+- * 05.04.1999 0.13 added code to sv_read and sv_write which should detect
+- * lockups of the sound chip and revive it. This is basically
+- * an ugly hack, but at least applications using this driver
+- * won't hang forever. I don't know why these lockups happen,
+- * it might well be the motherboard chipset (an early 486 PCI
+- * board with ALI chipset), since every busmastering 100MB
+- * ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
+- * exhibit similar behaviour (they work for a couple of packets
+- * and then lock up and can be revived by ifconfig down/up).
+- * 07.04.1999 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+- * Alpha fixes reported by Peter Jones <pjones at redhat.com>
+- * Note: dmaio hack might still be wrong on archs other than i386
+- * 15.06.1999 0.15 Fix bad allocation bug.
+- * Thanks to Deti Fliegl <fliegl at in.tum.de>
+- * 28.06.1999 0.16 Add pci_set_master
+- * 03.08.1999 0.17 adapt to Linus' new __setup/__initcall
+- * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
+- * 12.08.1999 0.18 module_init/__setup fixes
+- * 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource
+- * 31.08.1999 0.20 add spin_lock_init
+- * use new resource allocation to allocate DDMA IO space
+- * replaced current->state = x with set_current_state(x)
+- * 03.09.1999 0.21 change read semantics for MIDI to match
+- * OSS more closely; remove possible wakeup race
+- * 28.10.1999 0.22 More waitqueue races fixed
+- * 01.12.1999 0.23 New argument to allocate_resource
+- * 07.12.1999 0.24 More allocate_resource semantics change
+- * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun;
+- * Tim Janik's BSE (Bedevilled Sound Engine) found this
+- * use Martin Mares' pci_assign_resource
+- * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver
+- * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+- * 12.12.2000 0.28 More dma buffer initializations, patch from
+- * Tjeerd Mulder <tjeerd.mulder at fujitsu-siemens.com>
+- * 31.01.2001 0.29 Register/Unregister gameport
+- * Fix SETTRIGGER non OSS API conformity
+- * 18.05.2001 0.30 PCI probing and error values cleaned up by Marcus
+- * Meissner <mm at caldera.de>
+- * 03.01.2003 0.31 open_mode fixes from Georg Acher <acher at in.tum.de>
+- *
+- */
+-
+-/*****************************************************************************/
+-
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/interrupt.h>
+-#include <linux/wait.h>
+-#include <linux/mm.h>
+-#include <linux/delay.h>
+-#include <linux/sound.h>
+-#include <linux/slab.h>
+-#include <linux/soundcard.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-#include <linux/poll.h>
+-#include <linux/spinlock.h>
+-#include <linux/smp_lock.h>
+-#include <linux/gameport.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/mutex.h>
+-
+-
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-
+-#include "dm.h"
+-
+-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+-#define SUPPORT_JOYSTICK 1
+-#endif
+-
+-/* --------------------------------------------------------------------- */
+-
+-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef PCI_VENDOR_ID_S3
+-#define PCI_VENDOR_ID_S3 0x5333
+-#endif
+-#ifndef PCI_DEVICE_ID_S3_SONICVIBES
+-#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
+-#endif
+-
+-#define SV_MAGIC ((PCI_VENDOR_ID_S3<<16)|PCI_DEVICE_ID_S3_SONICVIBES)
+-
+-#define SV_EXTENT_SB 0x10
+-#define SV_EXTENT_ENH 0x10
+-#define SV_EXTENT_SYNTH 0x4
+-#define SV_EXTENT_MIDI 0x4
+-#define SV_EXTENT_GAME 0x8
+-#define SV_EXTENT_DMA 0x10
+-
+-/*
+- * we are not a bridge and thus use a resource for DDMA that is used for bridges but
+- * left empty for normal devices
+- */
+-#define RESOURCE_SB 0
+-#define RESOURCE_ENH 1
+-#define RESOURCE_SYNTH 2
+-#define RESOURCE_MIDI 3
+-#define RESOURCE_GAME 4
+-#define RESOURCE_DDMA 7
+-
+-#define SV_MIDI_DATA 0
+-#define SV_MIDI_COMMAND 1
+-#define SV_MIDI_STATUS 1
+-
+-#define SV_DMA_ADDR0 0
+-#define SV_DMA_ADDR1 1
+-#define SV_DMA_ADDR2 2
+-#define SV_DMA_ADDR3 3
+-#define SV_DMA_COUNT0 4
+-#define SV_DMA_COUNT1 5
+-#define SV_DMA_COUNT2 6
+-#define SV_DMA_MODE 0xb
+-#define SV_DMA_RESET 0xd
+-#define SV_DMA_MASK 0xf
+-
+-/*
+- * DONT reset the DMA controllers unless you understand
+- * the reset semantics. Assuming reset semantics as in
+- * the 8237 does not work.
+- */
+-
+-#define DMA_MODE_AUTOINIT 0x10
+-#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
+-#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
+-
+-#define SV_CODEC_CONTROL 0
+-#define SV_CODEC_INTMASK 1
+-#define SV_CODEC_STATUS 2
+-#define SV_CODEC_IADDR 4
+-#define SV_CODEC_IDATA 5
+-
+-#define SV_CCTRL_RESET 0x80
+-#define SV_CCTRL_INTADRIVE 0x20
+-#define SV_CCTRL_WAVETABLE 0x08
+-#define SV_CCTRL_REVERB 0x04
+-#define SV_CCTRL_ENHANCED 0x01
+-
+-#define SV_CINTMASK_DMAA 0x01
+-#define SV_CINTMASK_DMAC 0x04
+-#define SV_CINTMASK_SPECIAL 0x08
+-#define SV_CINTMASK_UPDOWN 0x40
+-#define SV_CINTMASK_MIDI 0x80
+-
+-#define SV_CSTAT_DMAA 0x01
+-#define SV_CSTAT_DMAC 0x04
+-#define SV_CSTAT_SPECIAL 0x08
+-#define SV_CSTAT_UPDOWN 0x40
+-#define SV_CSTAT_MIDI 0x80
+-
+-#define SV_CIADDR_TRD 0x80
+-#define SV_CIADDR_MCE 0x40
+-
+-/* codec indirect registers */
+-#define SV_CIMIX_ADCINL 0x00
+-#define SV_CIMIX_ADCINR 0x01
+-#define SV_CIMIX_AUX1INL 0x02
+-#define SV_CIMIX_AUX1INR 0x03
+-#define SV_CIMIX_CDINL 0x04
+-#define SV_CIMIX_CDINR 0x05
+-#define SV_CIMIX_LINEINL 0x06
+-#define SV_CIMIX_LINEINR 0x07
+-#define SV_CIMIX_MICIN 0x08
+-#define SV_CIMIX_SYNTHINL 0x0A
+-#define SV_CIMIX_SYNTHINR 0x0B
+-#define SV_CIMIX_AUX2INL 0x0C
+-#define SV_CIMIX_AUX2INR 0x0D
+-#define SV_CIMIX_ANALOGINL 0x0E
+-#define SV_CIMIX_ANALOGINR 0x0F
+-#define SV_CIMIX_PCMINL 0x10
+-#define SV_CIMIX_PCMINR 0x11
+-
+-#define SV_CIGAMECONTROL 0x09
+-#define SV_CIDATAFMT 0x12
+-#define SV_CIENABLE 0x13
+-#define SV_CIUPDOWN 0x14
+-#define SV_CIREVISION 0x15
+-#define SV_CIADCOUTPUT 0x16
+-#define SV_CIDMAABASECOUNT1 0x18
+-#define SV_CIDMAABASECOUNT0 0x19
+-#define SV_CIDMACBASECOUNT1 0x1c
+-#define SV_CIDMACBASECOUNT0 0x1d
+-#define SV_CIPCMSR0 0x1e
+-#define SV_CIPCMSR1 0x1f
+-#define SV_CISYNTHSR0 0x20
+-#define SV_CISYNTHSR1 0x21
+-#define SV_CIADCCLKSOURCE 0x22
+-#define SV_CIADCALTSR 0x23
+-#define SV_CIADCPLLM 0x24
+-#define SV_CIADCPLLN 0x25
+-#define SV_CISYNTHPLLM 0x26
+-#define SV_CISYNTHPLLN 0x27
+-#define SV_CIUARTCONTROL 0x2a
+-#define SV_CIDRIVECONTROL 0x2b
+-#define SV_CISRSSPACE 0x2c
+-#define SV_CISRSCENTER 0x2d
+-#define SV_CIWAVETABLESRC 0x2e
+-#define SV_CIANALOGPWRDOWN 0x30
+-#define SV_CIDIGITALPWRDOWN 0x31
+-
+-
+-#define SV_CIMIX_ADCSRC_CD 0x20
+-#define SV_CIMIX_ADCSRC_DAC 0x40
+-#define SV_CIMIX_ADCSRC_AUX2 0x60
+-#define SV_CIMIX_ADCSRC_LINE 0x80
+-#define SV_CIMIX_ADCSRC_AUX1 0xa0
+-#define SV_CIMIX_ADCSRC_MIC 0xc0
+-#define SV_CIMIX_ADCSRC_MIXOUT 0xe0
+-#define SV_CIMIX_ADCSRC_MASK 0xe0
+-
+-#define SV_CFMT_STEREO 0x01
+-#define SV_CFMT_16BIT 0x02
+-#define SV_CFMT_MASK 0x03
+-#define SV_CFMT_ASHIFT 0
+-#define SV_CFMT_CSHIFT 4
+-
+-static const unsigned sample_size[] = { 1, 2, 2, 4 };
+-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+-
+-#define SV_CENABLE_PPE 0x4
+-#define SV_CENABLE_RE 0x2
+-#define SV_CENABLE_PE 0x1
+-
+-
+-/* MIDI buffer sizes */
+-
+-#define MIDIINBUF 256
+-#define MIDIOUTBUF 256
+-
+-#define FMODE_MIDI_SHIFT 2
+-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
+-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+-
+-#define FMODE_DMFM 0x10
+-
+-/* --------------------------------------------------------------------- */
+-
+-struct sv_state {
+- /* magic */
+- unsigned int magic;
+-
+- /* list of sonicvibes devices */
+- struct list_head devs;
+-
+- /* the corresponding pci_dev structure */
+- struct pci_dev *dev;
+-
+- /* soundcore stuff */
+- int dev_audio;
+- int dev_mixer;
+- int dev_midi;
+- int dev_dmfm;
+-
+- /* hardware resources */
+- unsigned long iosb, ioenh, iosynth, iomidi; /* long for SPARC */
+- unsigned int iodmaa, iodmac, irq;
+-
+- /* mixer stuff */
+- struct {
+- unsigned int modcnt;
+-#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS
+- unsigned short vol[13];
+-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+- } mix;
+-
+- /* wave stuff */
+- unsigned int rateadc, ratedac;
+- unsigned char fmt, enable;
+-
+- spinlock_t lock;
+- struct mutex open_mutex;
+- mode_t open_mode;
+- wait_queue_head_t open_wait;
+-
+- struct dmabuf {
+- void *rawbuf;
+- dma_addr_t dmaaddr;
+- unsigned buforder;
+- unsigned numfrag;
+- unsigned fragshift;
+- unsigned hwptr, swptr;
+- unsigned total_bytes;
+- int count;
+- unsigned error; /* over/underrun */
+- wait_queue_head_t wait;
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize;
+- unsigned fragsamples;
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned endcleared:1;
+- unsigned enabled:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+- } dma_dac, dma_adc;
+-
+- /* midi stuff */
+- struct {
+- unsigned ird, iwr, icnt;
+- unsigned ord, owr, ocnt;
+- wait_queue_head_t iwait;
+- wait_queue_head_t owait;
+- struct timer_list timer;
+- unsigned char ibuf[MIDIINBUF];
+- unsigned char obuf[MIDIOUTBUF];
+- } midi;
+-
+-#if SUPPORT_JOYSTICK
+- struct gameport *gameport;
+-#endif
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static LIST_HEAD(devs);
+-static unsigned long wavetable_mem;
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline unsigned ld2(unsigned int x)
+-{
+- unsigned r = 0;
+-
+- if (x >= 0x10000) {
+- x >>= 16;
+- r += 16;
+- }
+- if (x >= 0x100) {
+- x >>= 8;
+- r += 8;
+- }
+- if (x >= 0x10) {
+- x >>= 4;
+- r += 4;
+- }
+- if (x >= 4) {
+- x >>= 2;
+- r += 2;
+- }
+- if (x >= 2)
+- r++;
+- return r;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-/*
+- * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
+- */
+-
+-#undef DMABYTEIO
+-
+-static void set_dmaa(struct sv_state *s, unsigned int addr, unsigned int count)
+-{
+-#ifdef DMABYTEIO
+- unsigned io = s->iodmaa, u;
+-
+- count--;
+- for (u = 4; u > 0; u--, addr >>= 8, io++)
+- outb(addr & 0xff, io);
+- for (u = 3; u > 0; u--, count >>= 8, io++)
+- outb(count & 0xff, io);
+-#else /* DMABYTEIO */
+- count--;
+- outl(addr, s->iodmaa + SV_DMA_ADDR0);
+- outl(count, s->iodmaa + SV_DMA_COUNT0);
+-#endif /* DMABYTEIO */
+- outb(0x18, s->iodmaa + SV_DMA_MODE);
+-}
+-
+-static void set_dmac(struct sv_state *s, unsigned int addr, unsigned int count)
+-{
+-#ifdef DMABYTEIO
+- unsigned io = s->iodmac, u;
+-
+- count >>= 1;
+- count--;
+- for (u = 4; u > 0; u--, addr >>= 8, io++)
+- outb(addr & 0xff, io);
+- for (u = 3; u > 0; u--, count >>= 8, io++)
+- outb(count & 0xff, io);
+-#else /* DMABYTEIO */
+- count >>= 1;
+- count--;
+- outl(addr, s->iodmac + SV_DMA_ADDR0);
+- outl(count, s->iodmac + SV_DMA_COUNT0);
+-#endif /* DMABYTEIO */
+- outb(0x14, s->iodmac + SV_DMA_MODE);
+-}
+-
+-static inline unsigned get_dmaa(struct sv_state *s)
+-{
+-#ifdef DMABYTEIO
+- unsigned io = s->iodmaa+6, v = 0, u;
+-
+- for (u = 3; u > 0; u--, io--) {
+- v <<= 8;
+- v |= inb(io);
+- }
+- return v + 1;
+-#else /* DMABYTEIO */
+- return (inl(s->iodmaa + SV_DMA_COUNT0) & 0xffffff) + 1;
+-#endif /* DMABYTEIO */
+-}
+-
+-static inline unsigned get_dmac(struct sv_state *s)
+-{
+-#ifdef DMABYTEIO
+- unsigned io = s->iodmac+6, v = 0, u;
+-
+- for (u = 3; u > 0; u--, io--) {
+- v <<= 8;
+- v |= inb(io);
+- }
+- return (v + 1) << 1;
+-#else /* DMABYTEIO */
+- return ((inl(s->iodmac + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;
+-#endif /* DMABYTEIO */
+-}
+-
+-static void wrindir(struct sv_state *s, unsigned char idx, unsigned char data)
+-{
+- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- outb(data, s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+-}
+-
+-static unsigned char rdindir(struct sv_state *s, unsigned char idx)
+-{
+- unsigned char v;
+-
+- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- v = inb(s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+- return v;
+-}
+-
+-static void set_fmt(struct sv_state *s, unsigned char mask, unsigned char data)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- outb(SV_CIDATAFMT | SV_CIADDR_MCE, s->ioenh + SV_CODEC_IADDR);
+- if (mask) {
+- s->fmt = inb(s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+- }
+- s->fmt = (s->fmt & mask) | data;
+- outb(s->fmt, s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+- outb(0, s->ioenh + SV_CODEC_IADDR);
+- spin_unlock_irqrestore(&s->lock, flags);
+- udelay(10);
+-}
+-
+-static void frobindir(struct sv_state *s, unsigned char idx, unsigned char mask, unsigned char data)
+-{
+- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- outb((inb(s->ioenh + SV_CODEC_IDATA) & mask) ^ data, s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+-}
+-
+-#define REFFREQUENCY 24576000
+-#define ADCMULT 512
+-#define FULLRATE 48000
+-
+-static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
+-{
+- unsigned long flags;
+- unsigned char r, m=0, n=0;
+- unsigned xm, xn, xr, xd, metric = ~0U;
+- /* the warnings about m and n used uninitialized are bogus and may safely be ignored */
+-
+- if (rate < 625000/ADCMULT)
+- rate = 625000/ADCMULT;
+- if (rate > 150000000/ADCMULT)
+- rate = 150000000/ADCMULT;
+- /* slight violation of specs, needed for continuous sampling rates */
+- for (r = 0; rate < 75000000/ADCMULT; r += 0x20, rate <<= 1);
+- for (xn = 3; xn < 35; xn++)
+- for (xm = 3; xm < 130; xm++) {
+- xr = REFFREQUENCY/ADCMULT * xm / xn;
+- xd = abs((signed)(xr - rate));
+- if (xd < metric) {
+- metric = xd;
+- m = xm - 2;
+- n = xn - 2;
+- }
+- }
+- reg &= 0x3f;
+- spin_lock_irqsave(&s->lock, flags);
+- outb(reg, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- outb(m, s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+- outb(reg+1, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- outb(r | n, s->ioenh + SV_CODEC_IDATA);
+- spin_unlock_irqrestore(&s->lock, flags);
+- udelay(10);
+- return (REFFREQUENCY/ADCMULT * (m + 2) / (n + 2)) >> ((r >> 5) & 7);
+-}
+-
+-#if 0
+-
+-static unsigned getpll(struct sv_state *s, unsigned char reg)
+-{
+- unsigned long flags;
+- unsigned char m, n;
+-
+- reg &= 0x3f;
+- spin_lock_irqsave(&s->lock, flags);
+- outb(reg, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- m = inb(s->ioenh + SV_CODEC_IDATA);
+- udelay(10);
+- outb(reg+1, s->ioenh + SV_CODEC_IADDR);
+- udelay(10);
+- n = inb(s->ioenh + SV_CODEC_IDATA);
+- spin_unlock_irqrestore(&s->lock, flags);
+- udelay(10);
+- return (REFFREQUENCY/ADCMULT * (m + 2) / ((n & 0x1f) + 2)) >> ((n >> 5) & 7);
+-}
+-
+-#endif
+-
+-static void set_dac_rate(struct sv_state *s, unsigned rate)
+-{
+- unsigned div;
+- unsigned long flags;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 4000)
+- rate = 4000;
+- div = (rate * 65536 + FULLRATE/2) / FULLRATE;
+- if (div > 65535)
+- div = 65535;
+- spin_lock_irqsave(&s->lock, flags);
+- wrindir(s, SV_CIPCMSR1, div >> 8);
+- wrindir(s, SV_CIPCMSR0, div);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->ratedac = (div * FULLRATE + 32768) / 65536;
+-}
+-
+-static void set_adc_rate(struct sv_state *s, unsigned rate)
+-{
+- unsigned long flags;
+- unsigned rate1, rate2, div;
+-
+- if (rate > 48000)
+- rate = 48000;
+- if (rate < 4000)
+- rate = 4000;
+- rate1 = setpll(s, SV_CIADCPLLM, rate);
+- div = (48000 + rate/2) / rate;
+- if (div > 8)
+- div = 8;
+- rate2 = (48000 + div/2) / div;
+- spin_lock_irqsave(&s->lock, flags);
+- wrindir(s, SV_CIADCALTSR, (div-1) << 4);
+- if (abs((signed)(rate-rate2)) <= abs((signed)(rate-rate1))) {
+- wrindir(s, SV_CIADCCLKSOURCE, 0x10);
+- s->rateadc = rate2;
+- } else {
+- wrindir(s, SV_CIADCCLKSOURCE, 0x00);
+- s->rateadc = rate1;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static inline void stop_adc(struct sv_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->enable &= ~SV_CENABLE_RE;
+- wrindir(s, SV_CIENABLE, s->enable);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static inline void stop_dac(struct sv_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- s->enable &= ~(SV_CENABLE_PPE | SV_CENABLE_PE);
+- wrindir(s, SV_CIENABLE, s->enable);
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_dac(struct sv_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+- s->enable = (s->enable & ~SV_CENABLE_PPE) | SV_CENABLE_PE;
+- wrindir(s, SV_CIENABLE, s->enable);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-static void start_adc(struct sv_state *s)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+- && s->dma_adc.ready) {
+- s->enable |= SV_CENABLE_RE;
+- wrindir(s, SV_CIENABLE, s->enable);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-static void dealloc_dmabuf(struct sv_state *s, struct dmabuf *db)
+-{
+- struct page *page, *pend;
+-
+- if (db->rawbuf) {
+- /* undo marking the pages as reserved */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- ClearPageReserved(page);
+- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
+- }
+- db->rawbuf = NULL;
+- db->mapped = db->ready = 0;
+-}
+-
+-
+-/* DMAA is used for playback, DMAC is used for recording */
+-
+-static int prog_dmabuf(struct sv_state *s, unsigned rec)
+-{
+- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+- unsigned rate = rec ? s->rateadc : s->ratedac;
+- int order;
+- unsigned bytepersec;
+- unsigned bufs;
+- struct page *page, *pend;
+- unsigned char fmt;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- fmt = s->fmt;
+- if (rec) {
+- s->enable &= ~SV_CENABLE_RE;
+- fmt >>= SV_CFMT_CSHIFT;
+- } else {
+- s->enable &= ~SV_CENABLE_PE;
+- fmt >>= SV_CFMT_ASHIFT;
+- }
+- wrindir(s, SV_CIENABLE, s->enable);
+- spin_unlock_irqrestore(&s->lock, flags);
+- fmt &= SV_CFMT_MASK;
+- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+- if (!db->rawbuf) {
+- db->ready = db->mapped = 0;
+- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
+- break;
+- if (!db->rawbuf)
+- return -ENOMEM;
+- db->buforder = order;
+- if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
+- printk(KERN_DEBUG "sv: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
+- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
+- if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
+- printk(KERN_DEBUG "sv: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
+- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
+- SetPageReserved(page);
+- }
+- bytepersec = rate << sample_shift[fmt];
+- bufs = PAGE_SIZE << db->buforder;
+- if (db->ossfragshift) {
+- if ((1000 << db->ossfragshift) < bytepersec)
+- db->fragshift = ld2(bytepersec/1000);
+- else
+- db->fragshift = db->ossfragshift;
+- } else {
+- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+- if (db->fragshift < 3)
+- db->fragshift = 3;
+- }
+- db->numfrag = bufs >> db->fragshift;
+- while (db->numfrag < 4 && db->fragshift > 3) {
+- db->fragshift--;
+- db->numfrag = bufs >> db->fragshift;
+- }
+- db->fragsize = 1 << db->fragshift;
+- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+- db->numfrag = db->ossmaxfrags;
+- db->fragsamples = db->fragsize >> sample_shift[fmt];
+- db->dmasize = db->numfrag << db->fragshift;
+- memset(db->rawbuf, (fmt & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
+- spin_lock_irqsave(&s->lock, flags);
+- if (rec) {
+- set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift);
+- /* program enhanced mode registers */
+- wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8);
+- wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1);
+- } else {
+- set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift);
+- /* program enhanced mode registers */
+- wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8);
+- wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- db->enabled = 1;
+- db->ready = 1;
+- return 0;
+-}
+-
+-static inline void clear_advance(struct sv_state *s)
+-{
+- unsigned char c = (s->fmt & (SV_CFMT_16BIT << SV_CFMT_ASHIFT)) ? 0 : 0x80;
+- unsigned char *buf = s->dma_dac.rawbuf;
+- unsigned bsize = s->dma_dac.dmasize;
+- unsigned bptr = s->dma_dac.swptr;
+- unsigned len = s->dma_dac.fragsize;
+-
+- if (bptr + len > bsize) {
+- unsigned x = bsize - bptr;
+- memset(buf + bptr, c, x);
+- bptr = 0;
+- len -= x;
+- }
+- memset(buf + bptr, c, len);
+-}
+-
+-/* call with spinlock held! */
+-static void sv_update_ptr(struct sv_state *s)
+-{
+- unsigned hwptr;
+- int diff;
+-
+- /* update ADC pointer */
+- if (s->dma_adc.ready) {
+- hwptr = (s->dma_adc.dmasize - get_dmac(s)) % s->dma_adc.dmasize;
+- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+- s->dma_adc.hwptr = hwptr;
+- s->dma_adc.total_bytes += diff;
+- s->dma_adc.count += diff;
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- wake_up(&s->dma_adc.wait);
+- if (!s->dma_adc.mapped) {
+- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+- s->enable &= ~SV_CENABLE_RE;
+- wrindir(s, SV_CIENABLE, s->enable);
+- s->dma_adc.error++;
+- }
+- }
+- }
+- /* update DAC pointer */
+- if (s->dma_dac.ready) {
+- hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize;
+- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+- s->dma_dac.hwptr = hwptr;
+- s->dma_dac.total_bytes += diff;
+- if (s->dma_dac.mapped) {
+- s->dma_dac.count += diff;
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- wake_up(&s->dma_dac.wait);
+- } else {
+- s->dma_dac.count -= diff;
+- if (s->dma_dac.count <= 0) {
+- s->enable &= ~SV_CENABLE_PE;
+- wrindir(s, SV_CIENABLE, s->enable);
+- s->dma_dac.error++;
+- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+- clear_advance(s);
+- s->dma_dac.endcleared = 1;
+- }
+- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
+- wake_up(&s->dma_dac.wait);
+- }
+- }
+-}
+-
+-/* hold spinlock for the following! */
+-static void sv_handle_midi(struct sv_state *s)
+-{
+- unsigned char ch;
+- int wake;
+-
+- wake = 0;
+- while (!(inb(s->iomidi+1) & 0x80)) {
+- ch = inb(s->iomidi);
+- if (s->midi.icnt < MIDIINBUF) {
+- s->midi.ibuf[s->midi.iwr] = ch;
+- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+- s->midi.icnt++;
+- }
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.iwait);
+- wake = 0;
+- while (!(inb(s->iomidi+1) & 0x40) && s->midi.ocnt > 0) {
+- outb(s->midi.obuf[s->midi.ord], s->iomidi);
+- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+- s->midi.ocnt--;
+- if (s->midi.ocnt < MIDIOUTBUF-16)
+- wake = 1;
+- }
+- if (wake)
+- wake_up(&s->midi.owait);
+-}
+-
+-static irqreturn_t sv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct sv_state *s = (struct sv_state *)dev_id;
+- unsigned int intsrc;
+-
+- /* fastpath out, to ease interrupt sharing */
+- intsrc = inb(s->ioenh + SV_CODEC_STATUS);
+- if (!(intsrc & (SV_CSTAT_DMAA | SV_CSTAT_DMAC | SV_CSTAT_MIDI)))
+- return IRQ_NONE;
+- spin_lock(&s->lock);
+- sv_update_ptr(s);
+- sv_handle_midi(s);
+- spin_unlock(&s->lock);
+- return IRQ_HANDLED;
+-}
+-
+-static void sv_midi_timer(unsigned long data)
+-{
+- struct sv_state *s = (struct sv_state *)data;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- sv_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->midi.timer.expires = jiffies+1;
+- add_timer(&s->midi.timer);
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static const char invalid_magic[] = KERN_CRIT "sv: invalid magic value\n";
+-
+-#define VALIDATE_STATE(s) \
+-({ \
+- if (!(s) || (s)->magic != SV_MAGIC) { \
+- printk(invalid_magic); \
+- return -ENXIO; \
+- } \
+-})
+-
+-/* --------------------------------------------------------------------- */
+-
+-#define MT_4 1
+-#define MT_5MUTE 2
+-#define MT_4MUTEMONO 3
+-#define MT_6MUTE 4
+-
+-static const struct {
+- unsigned left:5;
+- unsigned right:5;
+- unsigned type:3;
+- unsigned rec:3;
+-} mixtable[SOUND_MIXER_NRDEVICES] = {
+- [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 },
+- [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 },
+- [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 },
+- [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 },
+- [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 },
+- [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 },
+- [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 },
+- [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 },
+- [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 }
+-};
+-
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+-
+-static int return_mixval(struct sv_state *s, unsigned i, int *arg)
+-{
+- unsigned long flags;
+- unsigned char l, r, rl, rr;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- l = rdindir(s, mixtable[i].left);
+- r = rdindir(s, mixtable[i].right);
+- spin_unlock_irqrestore(&s->lock, flags);
+- switch (mixtable[i].type) {
+- case MT_4:
+- r &= 0xf;
+- l &= 0xf;
+- rl = 10 + 6 * (l & 15);
+- rr = 10 + 6 * (r & 15);
+- break;
+-
+- case MT_4MUTEMONO:
+- rl = 55 - 3 * (l & 15);
+- if (r & 0x10)
+- rl += 45;
+- rr = rl;
+- r = l;
+- break;
+-
+- case MT_5MUTE:
+- default:
+- rl = 100 - 3 * (l & 31);
+- rr = 100 - 3 * (r & 31);
+- break;
+-
+- case MT_6MUTE:
+- rl = 100 - 3 * (l & 63) / 2;
+- rr = 100 - 3 * (r & 63) / 2;
+- break;
+- }
+- if (l & 0x80)
+- rl = 0;
+- if (r & 0x80)
+- rr = 0;
+- return put_user((rr << 8) | rl, arg);
+-}
+-
+-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+-
+-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
+-{
+- [SOUND_MIXER_RECLEV] = 1,
+- [SOUND_MIXER_LINE1] = 2,
+- [SOUND_MIXER_CD] = 3,
+- [SOUND_MIXER_LINE] = 4,
+- [SOUND_MIXER_MIC] = 5,
+- [SOUND_MIXER_SYNTH] = 6,
+- [SOUND_MIXER_LINE2] = 7,
+- [SOUND_MIXER_VOLUME] = 8,
+- [SOUND_MIXER_PCM] = 9
+-};
+-
+-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+-
+-static unsigned mixer_recmask(struct sv_state *s)
+-{
+- unsigned long flags;
+- int i, j;
+-
+- spin_lock_irqsave(&s->lock, flags);
+- j = rdindir(s, SV_CIMIX_ADCINL) >> 5;
+- spin_unlock_irqrestore(&s->lock, flags);
+- j &= 7;
+- for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++);
+- return 1 << i;
+-}
+-
+-static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
+-{
+- unsigned long flags;
+- int i, val;
+- unsigned char l, r, rl, rr;
+- int __user *p = (int __user *)arg;
+-
+- VALIDATE_STATE(s);
+- if (cmd == SOUND_MIXER_INFO) {
+- mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.id, "SonicVibes", sizeof(info.id));
+- strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
+- info.modify_counter = s->mix.modcnt;
+- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == SOUND_OLD_MIXER_INFO) {
+- _old_mixer_info info;
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.id, "SonicVibes", sizeof(info.id));
+- strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
+- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+- return -EFAULT;
+- return 0;
+- }
+- if (cmd == OSS_GETVERSION)
+- return put_user(SOUND_VERSION, p);
+- if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */
+- if (get_user(val, p))
+- return -EFAULT;
+- spin_lock_irqsave(&s->lock, flags);
+- if (val & 1) {
+- if (val & 2) {
+- l = 4 - ((val >> 2) & 7);
+- if (l & ~3)
+- l = 4;
+- r = 4 - ((val >> 5) & 7);
+- if (r & ~3)
+- r = 4;
+- wrindir(s, SV_CISRSSPACE, l);
+- wrindir(s, SV_CISRSCENTER, r);
+- } else
+- wrindir(s, SV_CISRSSPACE, 0x80);
+- }
+- l = rdindir(s, SV_CISRSSPACE);
+- r = rdindir(s, SV_CISRSCENTER);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (l & 0x80)
+- return put_user(0, p);
+- return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, p);
+- }
+- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+- return -EINVAL;
+- if (_SIOC_DIR(cmd) == _SIOC_READ) {
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- return put_user(mixer_recmask(s), p);
+-
+- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].type)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].rec)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
+- val |= 1 << i;
+- return put_user(val, p);
+-
+- case SOUND_MIXER_CAPS:
+- return put_user(SOUND_CAP_EXCL_INPUT, p);
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
+- return -EINVAL;
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- return return_mixval(s, i, p);
+-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+- if (!volidx[i])
+- return -EINVAL;
+- return put_user(s->mix.vol[volidx[i]-1], p);
+-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+- }
+- }
+- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
+- return -EINVAL;
+- s->mix.modcnt++;
+- switch (_IOC_NR(cmd)) {
+- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+- if (get_user(val, p))
+- return -EFAULT;
+- i = hweight32(val);
+- if (i == 0)
+- return 0; /*val = mixer_recmask(s);*/
+- else if (i > 1)
+- val &= ~mixer_recmask(s);
+- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+- if (!(val & (1 << i)))
+- continue;
+- if (mixtable[i].rec)
+- break;
+- }
+- if (i == SOUND_MIXER_NRDEVICES)
+- return 0;
+- spin_lock_irqsave(&s->lock, flags);
+- frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5);
+- frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5);
+- spin_unlock_irqrestore(&s->lock, flags);
+- return 0;
+-
+- default:
+- i = _IOC_NR(cmd);
+- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- l = val & 0xff;
+- r = (val >> 8) & 0xff;
+- if (mixtable[i].type == MT_4MUTEMONO)
+- l = (r + l) / 2;
+- if (l > 100)
+- l = 100;
+- if (r > 100)
+- r = 100;
+- spin_lock_irqsave(&s->lock, flags);
+- switch (mixtable[i].type) {
+- case MT_4:
+- if (l >= 10)
+- l -= 10;
+- if (r >= 10)
+- r -= 10;
+- frobindir(s, mixtable[i].left, 0xf0, l / 6);
+- frobindir(s, mixtable[i].right, 0xf0, l / 6);
+- break;
+-
+- case MT_4MUTEMONO:
+- rr = 0;
+- if (l < 10)
+- rl = 0x80;
+- else {
+- if (l >= 55) {
+- rr = 0x10;
+- l -= 45;
+- }
+- rl = (55 - l) / 3;
+- }
+- wrindir(s, mixtable[i].left, rl);
+- frobindir(s, mixtable[i].right, ~0x10, rr);
+- break;
+-
+- case MT_5MUTE:
+- if (l < 7)
+- rl = 0x80;
+- else
+- rl = (100 - l) / 3;
+- if (r < 7)
+- rr = 0x80;
+- else
+- rr = (100 - r) / 3;
+- wrindir(s, mixtable[i].left, rl);
+- wrindir(s, mixtable[i].right, rr);
+- break;
+-
+- case MT_6MUTE:
+- if (l < 6)
+- rl = 0x80;
+- else
+- rl = (100 - l) * 2 / 3;
+- if (r < 6)
+- rr = 0x80;
+- else
+- rr = (100 - r) * 2 / 3;
+- wrindir(s, mixtable[i].left, rl);
+- wrindir(s, mixtable[i].right, rr);
+- break;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+- return return_mixval(s, i, p);
+-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+- if (!volidx[i])
+- return -EINVAL;
+- s->mix.vol[volidx[i]-1] = val;
+- return put_user(s->mix.vol[volidx[i]-1], p);
+-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
+- }
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int sv_open_mixdev(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- struct list_head *list;
+- struct sv_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct sv_state, devs);
+- if (s->dev_mixer == minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- return nonseekable_open(inode, file);
+-}
+-
+-static int sv_release_mixdev(struct inode *inode, struct file *file)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- return 0;
+-}
+-
+-static int sv_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- return mixer_ioctl((struct sv_state *)file->private_data, cmd, arg);
+-}
+-
+-static /*const*/ struct file_operations sv_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = sv_ioctl_mixdev,
+- .open = sv_open_mixdev,
+- .release = sv_release_mixdev,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int drain_dac(struct sv_state *s, int nonblock)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- int count, tmo;
+-
+- if (s->dma_dac.mapped || !s->dma_dac.ready)
+- return 0;
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (nonblock) {
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return -EBUSY;
+- }
+- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
+- tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
+- if (!schedule_timeout(tmo + 1))
+- printk(KERN_DEBUG "sv: dma timed out??\n");
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- return 0;
+-}
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t sv_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_adc.mapped)
+- return -ENXIO;
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-#if 0
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-#endif
+- add_wait_queue(&s->dma_adc.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- swptr = s->dma_adc.swptr;
+- cnt = s->dma_adc.dmasize-swptr;
+- if (s->dma_adc.count < cnt)
+- cnt = s->dma_adc.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_adc.enabled)
+- start_adc(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- if (!schedule_timeout(HZ)) {
+- printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+- s->dma_adc.hwptr, s->dma_adc.swptr);
+- stop_adc(s);
+- spin_lock_irqsave(&s->lock, flags);
+- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
+- /* program enhanced mode registers */
+- wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
+- wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1);
+- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- swptr = (swptr + cnt) % s->dma_adc.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_adc.swptr = swptr;
+- s->dma_adc.count -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_adc.enabled)
+- start_adc(s);
+- }
+- remove_wait_queue(&s->dma_adc.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-static ssize_t sv_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned swptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (s->dma_dac.mapped)
+- return -ENXIO;
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- ret = 0;
+-#if 0
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+-#endif
+- add_wait_queue(&s->dma_dac.wait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- if (s->dma_dac.count < 0) {
+- s->dma_dac.count = 0;
+- s->dma_dac.swptr = s->dma_dac.hwptr;
+- }
+- swptr = s->dma_dac.swptr;
+- cnt = s->dma_dac.dmasize-swptr;
+- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (s->dma_dac.enabled)
+- start_dac(s);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- if (!schedule_timeout(HZ)) {
+- printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+- s->dma_dac.hwptr, s->dma_dac.swptr);
+- stop_dac(s);
+- spin_lock_irqsave(&s->lock, flags);
+- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
+- /* program enhanced mode registers */
+- wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
+- wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1);
+- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+- spin_lock_irqsave(&s->lock, flags);
+- s->dma_dac.swptr = swptr;
+- s->dma_dac.count += cnt;
+- s->dma_dac.endcleared = 0;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- if (s->dma_dac.enabled)
+- start_dac(s);
+- }
+- remove_wait_queue(&s->dma_dac.wait, &wait);
+- set_current_state(TASK_RUNNING);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE) {
+- if (!s->dma_dac.ready && prog_dmabuf(s, 1))
+- return 0;
+- poll_wait(file, &s->dma_dac.wait, wait);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!s->dma_adc.ready && prog_dmabuf(s, 0))
+- return 0;
+- poll_wait(file, &s->dma_adc.wait, wait);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- if (file->f_mode & FMODE_READ) {
+- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->dma_dac.mapped) {
+- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int sv_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- struct dmabuf *db;
+- int ret = -EINVAL;
+- unsigned long size;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf(s, 1)) != 0)
+- goto out;
+- db = &s->dma_dac;
+- } else if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf(s, 0)) != 0)
+- goto out;
+- db = &s->dma_adc;
+- } else
+- goto out;
+- ret = -EINVAL;
+- if (vma->vm_pgoff != 0)
+- goto out;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << db->buforder))
+- goto out;
+- ret = -EAGAIN;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- goto out;
+- db->mapped = 1;
+- ret = 0;
+-out:
+- unlock_kernel();
+- return ret;
+-}
+-
+-static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int count;
+- int val, mapped, ret;
+- unsigned char fmtm, fmtd;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- VALIDATE_STATE(s);
+- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+- switch (cmd) {
+- case OSS_GETVERSION:
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_SYNC:
+- if (file->f_mode & FMODE_WRITE)
+- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+- return 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
+-
+- case SNDCTL_DSP_RESET:
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- synchronize_irq(s->irq);
+- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- synchronize_irq(s->irq);
+- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SPEED:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val >= 0) {
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- set_adc_rate(s, val);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- set_dac_rate(s, val);
+- }
+- }
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SNDCTL_DSP_STEREO:
+- if (get_user(val, p))
+- return -EFAULT;
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val)
+- fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
+- else
+- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val)
+- fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
+- else
+- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- return 0;
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 0) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val >= 2)
+- fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
+- else
+- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val >= 2)
+- fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
+- else
+- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT)
+- : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+- return put_user(AFMT_S16_LE|AFMT_U8, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != AFMT_QUERY) {
+- fmtd = 0;
+- fmtm = ~0;
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- s->dma_adc.ready = 0;
+- if (val == AFMT_S16_LE)
+- fmtd |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
+- else
+- fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_CSHIFT);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- s->dma_dac.ready = 0;
+- if (val == AFMT_S16_LE)
+- fmtd |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
+- else
+- fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_ASHIFT);
+- }
+- set_fmt(s, fmtm, fmtd);
+- }
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT)
+- : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, p);
+-
+- case SNDCTL_DSP_POST:
+- return 0;
+-
+- case SNDCTL_DSP_GETTRIGGER:
+- val = 0;
+- if (file->f_mode & FMODE_READ && s->enable & SV_CENABLE_RE)
+- val |= PCM_ENABLE_INPUT;
+- if (file->f_mode & FMODE_WRITE && s->enable & SV_CENABLE_PE)
+- val |= PCM_ENABLE_OUTPUT;
+- return put_user(val, p);
+-
+- case SNDCTL_DSP_SETTRIGGER:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- if (val & PCM_ENABLE_INPUT) {
+- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+- return ret;
+- s->dma_adc.enabled = 1;
+- start_adc(s);
+- } else {
+- s->dma_adc.enabled = 0;
+- stop_adc(s);
+- }
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (val & PCM_ENABLE_OUTPUT) {
+- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+- return ret;
+- s->dma_dac.enabled = 1;
+- start_dac(s);
+- } else {
+- s->dma_dac.enabled = 0;
+- stop_dac(s);
+- }
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- abinfo.fragsize = s->dma_dac.fragsize;
+- count = s->dma_dac.count;
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = s->dma_dac.dmasize - count;
+- abinfo.fragstotal = s->dma_dac.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- abinfo.fragsize = s->dma_adc.fragsize;
+- count = s->dma_adc.count;
+- if (count < 0)
+- count = 0;
+- abinfo.bytes = count;
+- abinfo.fragstotal = s->dma_adc.numfrag;
+- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+- spin_unlock_irqrestore(&s->lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETODELAY:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- count = s->dma_dac.count;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count < 0)
+- count = 0;
+- return put_user(count, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- cinfo.bytes = s->dma_adc.total_bytes;
+- count = s->dma_adc.count;
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_adc.fragshift;
+- cinfo.ptr = s->dma_adc.hwptr;
+- if (s->dma_adc.mapped)
+- s->dma_adc.count &= s->dma_adc.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+- return val;
+- spin_lock_irqsave(&s->lock, flags);
+- sv_update_ptr(s);
+- cinfo.bytes = s->dma_dac.total_bytes;
+- count = s->dma_dac.count;
+- if (count < 0)
+- count = 0;
+- cinfo.blocks = count >> s->dma_dac.fragshift;
+- cinfo.ptr = s->dma_dac.hwptr;
+- if (s->dma_dac.mapped)
+- s->dma_dac.count &= s->dma_dac.fragsize-1;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf(s, 0)))
+- return val;
+- return put_user(s->dma_dac.fragsize, p);
+- }
+- if ((val = prog_dmabuf(s, 1)))
+- return val;
+- return put_user(s->dma_adc.fragsize, p);
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- if (file->f_mode & FMODE_READ) {
+- s->dma_adc.ossfragshift = val & 0xffff;
+- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_adc.ossfragshift < 4)
+- s->dma_adc.ossfragshift = 4;
+- if (s->dma_adc.ossfragshift > 15)
+- s->dma_adc.ossfragshift = 15;
+- if (s->dma_adc.ossmaxfrags < 4)
+- s->dma_adc.ossmaxfrags = 4;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->dma_dac.ossfragshift = val & 0xffff;
+- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+- if (s->dma_dac.ossfragshift < 4)
+- s->dma_dac.ossfragshift = 4;
+- if (s->dma_dac.ossfragshift > 15)
+- s->dma_dac.ossfragshift = 15;
+- if (s->dma_dac.ossmaxfrags < 4)
+- s->dma_dac.ossmaxfrags = 4;
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SUBDIVIDE:
+- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+- return -EINVAL;
+- if (get_user(val, p))
+- return -EFAULT;
+- if (val != 1 && val != 2 && val != 4)
+- return -EINVAL;
+- if (file->f_mode & FMODE_READ)
+- s->dma_adc.subdivision = val;
+- if (file->f_mode & FMODE_WRITE)
+- s->dma_dac.subdivision = val;
+- return 0;
+-
+- case SOUND_PCM_READ_RATE:
+- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT)
+- : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
+-
+- case SOUND_PCM_READ_BITS:
+- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT)
+- : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, p);
+-
+- case SOUND_PCM_WRITE_FILTER:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_READ_FILTER:
+- return -EINVAL;
+-
+- }
+- return mixer_ioctl(s, cmd, arg);
+-}
+-
+-static int sv_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned char fmtm = ~0, fmts = 0;
+- struct list_head *list;
+- struct sv_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct sv_state, devs);
+- if (!((s->dev_audio ^ minor) & ~0xf))
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & file->f_mode) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- if (file->f_mode & FMODE_READ) {
+- fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_CSHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
+- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+- s->dma_adc.enabled = 1;
+- set_adc_rate(s, 8000);
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_ASHIFT);
+- if ((minor & 0xf) == SND_DEV_DSP16)
+- fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
+- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+- s->dma_dac.enabled = 1;
+- set_dac_rate(s, 8000);
+- }
+- set_fmt(s, fmtm, fmts);
+- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int sv_release(struct inode *inode, struct file *file)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE)
+- drain_dac(s, file->f_flags & O_NONBLOCK);
+- mutex_lock(&s->open_mutex);
+- if (file->f_mode & FMODE_WRITE) {
+- stop_dac(s);
+- dealloc_dmabuf(s, &s->dma_dac);
+- }
+- if (file->f_mode & FMODE_READ) {
+- stop_adc(s);
+- dealloc_dmabuf(s, &s->dma_adc);
+- }
+- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations sv_audio_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = sv_read,
+- .write = sv_write,
+- .poll = sv_poll,
+- .ioctl = sv_ioctl,
+- .mmap = sv_mmap,
+- .open = sv_open,
+- .release = sv_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static ssize_t sv_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_WRITE, buffer, count))
+- return -EFAULT;
+- if (count == 0)
+- return 0;
+- ret = 0;
+- add_wait_queue(&s->midi.iwait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.ird;
+- cnt = MIDIINBUF - ptr;
+- if (s->midi.icnt < cnt)
+- cnt = s->midi.icnt;
+- if (cnt <= 0)
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- ptr = (ptr + cnt) % MIDIINBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.ird = ptr;
+- s->midi.icnt -= cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- break;
+- }
+- __set_current_state(TASK_RUNNING);
+- remove_wait_queue(&s->midi.iwait, &wait);
+- return ret;
+-}
+-
+-static ssize_t sv_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned ptr;
+- int cnt;
+-
+- VALIDATE_STATE(s);
+- if (!access_ok(VERIFY_READ, buffer, count))
+- return -EFAULT;
+- if (count == 0)
+- return 0;
+- ret = 0;
+- add_wait_queue(&s->midi.owait, &wait);
+- while (count > 0) {
+- spin_lock_irqsave(&s->lock, flags);
+- ptr = s->midi.owr;
+- cnt = MIDIOUTBUF - ptr;
+- if (s->midi.ocnt + cnt > MIDIOUTBUF)
+- cnt = MIDIOUTBUF - s->midi.ocnt;
+- if (cnt <= 0) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- sv_handle_midi(s);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret)
+- ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- if (signal_pending(current)) {
+- if (!ret)
+- ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+- if (!ret)
+- ret = -EFAULT;
+- break;
+- }
+- ptr = (ptr + cnt) % MIDIOUTBUF;
+- spin_lock_irqsave(&s->lock, flags);
+- s->midi.owr = ptr;
+- s->midi.ocnt += cnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- spin_lock_irqsave(&s->lock, flags);
+- sv_handle_midi(s);
+- spin_unlock_irqrestore(&s->lock, flags);
+- }
+- __set_current_state(TASK_RUNNING);
+- remove_wait_queue(&s->midi.owait, &wait);
+- return ret;
+-}
+-
+-/* No kernel lock - we have our own spinlock */
+-static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- VALIDATE_STATE(s);
+- if (file->f_mode & FMODE_WRITE)
+- poll_wait(file, &s->midi.owait, wait);
+- if (file->f_mode & FMODE_READ)
+- poll_wait(file, &s->midi.iwait, wait);
+- spin_lock_irqsave(&s->lock, flags);
+- if (file->f_mode & FMODE_READ) {
+- if (s->midi.icnt > 0)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- if (s->midi.ocnt < MIDIOUTBUF)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- return mask;
+-}
+-
+-static int sv_midi_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- struct list_head *list;
+- struct sv_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct sv_state, devs);
+- if (s->dev_midi == minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- //outb(inb(s->ioenh + SV_CODEC_CONTROL) | SV_CCTRL_WAVETABLE, s->ioenh + SV_CODEC_CONTROL);
+- outb(inb(s->ioenh + SV_CODEC_INTMASK) | SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
+- wrindir(s, SV_CIUARTCONTROL, 5); /* output MIDI data to external and internal synth */
+- wrindir(s, SV_CIWAVETABLESRC, 1); /* Wavetable in PC RAM */
+- outb(0xff, s->iomidi+1); /* reset command */
+- outb(0x3f, s->iomidi+1); /* uart command */
+- if (!(inb(s->iomidi+1) & 0x80))
+- inb(s->iomidi);
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- init_timer(&s->midi.timer);
+- s->midi.timer.expires = jiffies+1;
+- s->midi.timer.data = (unsigned long)s;
+- s->midi.timer.function = sv_midi_timer;
+- add_timer(&s->midi.timer);
+- }
+- if (file->f_mode & FMODE_READ) {
+- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int sv_midi_release(struct inode *inode, struct file *file)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
+- unsigned long flags;
+- unsigned count, tmo;
+-
+- VALIDATE_STATE(s);
+-
+- lock_kernel();
+- if (file->f_mode & FMODE_WRITE) {
+- add_wait_queue(&s->midi.owait, &wait);
+- for (;;) {
+- __set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irqsave(&s->lock, flags);
+- count = s->midi.ocnt;
+- spin_unlock_irqrestore(&s->lock, flags);
+- if (count <= 0)
+- break;
+- if (signal_pending(current))
+- break;
+- if (file->f_flags & O_NONBLOCK) {
+- remove_wait_queue(&s->midi.owait, &wait);
+- set_current_state(TASK_RUNNING);
+- unlock_kernel();
+- return -EBUSY;
+- }
+- tmo = (count * HZ) / 3100;
+- if (!schedule_timeout(tmo ? : 1) && tmo)
+- printk(KERN_DEBUG "sv: midi timed out??\n");
+- }
+- remove_wait_queue(&s->midi.owait, &wait);
+- set_current_state(TASK_RUNNING);
+- }
+- mutex_lock(&s->open_mutex);
+- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
+- spin_lock_irqsave(&s->lock, flags);
+- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+- outb(inb(s->ioenh + SV_CODEC_INTMASK) & ~SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
+- del_timer(&s->midi.timer);
+- }
+- spin_unlock_irqrestore(&s->lock, flags);
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations sv_midi_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = sv_midi_read,
+- .write = sv_midi_write,
+- .poll = sv_midi_poll,
+- .open = sv_midi_open,
+- .release = sv_midi_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-static int sv_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- static const unsigned char op_offset[18] = {
+- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
+- };
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- struct dm_fm_voice v;
+- struct dm_fm_note n;
+- struct dm_fm_params p;
+- unsigned int io;
+- unsigned int regb;
+-
+- switch (cmd) {
+- case FM_IOCTL_RESET:
+- for (regb = 0xb0; regb < 0xb9; regb++) {
+- outb(regb, s->iosynth);
+- outb(0, s->iosynth+1);
+- outb(regb, s->iosynth+2);
+- outb(0, s->iosynth+3);
+- }
+- return 0;
+-
+- case FM_IOCTL_PLAY_NOTE:
+- if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
+- return -EFAULT;
+- if (n.voice >= 18)
+- return -EINVAL;
+- if (n.voice >= 9) {
+- regb = n.voice - 9;
+- io = s->iosynth+2;
+- } else {
+- regb = n.voice;
+- io = s->iosynth;
+- }
+- outb(0xa0 + regb, io);
+- outb(n.fnum & 0xff, io+1);
+- outb(0xb0 + regb, io);
+- outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
+- return 0;
+-
+- case FM_IOCTL_SET_VOICE:
+- if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
+- return -EFAULT;
+- if (v.voice >= 18)
+- return -EINVAL;
+- regb = op_offset[v.voice];
+- io = s->iosynth + ((v.op & 1) << 1);
+- outb(0x20 + regb, io);
+- outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
+- ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
+- outb(0x40 + regb, io);
+- outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
+- outb(0x60 + regb, io);
+- outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
+- outb(0x80 + regb, io);
+- outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
+- outb(0xe0 + regb, io);
+- outb(v.waveform & 0x7, io+1);
+- if (n.voice >= 9) {
+- regb = n.voice - 9;
+- io = s->iosynth+2;
+- } else {
+- regb = n.voice;
+- io = s->iosynth;
+- }
+- outb(0xc0 + regb, io);
+- outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
+- (v.connection & 1), io+1);
+- return 0;
+-
+- case FM_IOCTL_SET_PARAMS:
+- if (copy_from_user(&p, (void *__user )arg, sizeof(p)))
+- return -EFAULT;
+- outb(0x08, s->iosynth);
+- outb((p.kbd_split & 1) << 6, s->iosynth+1);
+- outb(0xbd, s->iosynth);
+- outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
+- ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->iosynth+1);
+- return 0;
+-
+- case FM_IOCTL_SET_OPL:
+- outb(4, s->iosynth+2);
+- outb(arg, s->iosynth+3);
+- return 0;
+-
+- case FM_IOCTL_SET_MODE:
+- outb(5, s->iosynth+2);
+- outb(arg & 1, s->iosynth+3);
+- return 0;
+-
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static int sv_dmfm_open(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- DECLARE_WAITQUEUE(wait, current);
+- struct list_head *list;
+- struct sv_state *s;
+-
+- for (list = devs.next; ; list = list->next) {
+- if (list == &devs)
+- return -ENODEV;
+- s = list_entry(list, struct sv_state, devs);
+- if (s->dev_dmfm == minor)
+- break;
+- }
+- VALIDATE_STATE(s);
+- file->private_data = s;
+- /* wait for device to become free */
+- mutex_lock(&s->open_mutex);
+- while (s->open_mode & FMODE_DMFM) {
+- if (file->f_flags & O_NONBLOCK) {
+- mutex_unlock(&s->open_mutex);
+- return -EBUSY;
+- }
+- add_wait_queue(&s->open_wait, &wait);
+- __set_current_state(TASK_INTERRUPTIBLE);
+- mutex_unlock(&s->open_mutex);
+- schedule();
+- remove_wait_queue(&s->open_wait, &wait);
+- set_current_state(TASK_RUNNING);
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+- mutex_lock(&s->open_mutex);
+- }
+- /* init the stuff */
+- outb(1, s->iosynth);
+- outb(0x20, s->iosynth+1); /* enable waveforms */
+- outb(4, s->iosynth+2);
+- outb(0, s->iosynth+3); /* no 4op enabled */
+- outb(5, s->iosynth+2);
+- outb(1, s->iosynth+3); /* enable OPL3 */
+- s->open_mode |= FMODE_DMFM;
+- mutex_unlock(&s->open_mutex);
+- return nonseekable_open(inode, file);
+-}
+-
+-static int sv_dmfm_release(struct inode *inode, struct file *file)
+-{
+- struct sv_state *s = (struct sv_state *)file->private_data;
+- unsigned int regb;
+-
+- VALIDATE_STATE(s);
+- lock_kernel();
+- mutex_lock(&s->open_mutex);
+- s->open_mode &= ~FMODE_DMFM;
+- for (regb = 0xb0; regb < 0xb9; regb++) {
+- outb(regb, s->iosynth);
+- outb(0, s->iosynth+1);
+- outb(regb, s->iosynth+2);
+- outb(0, s->iosynth+3);
+- }
+- wake_up(&s->open_wait);
+- mutex_unlock(&s->open_mutex);
+- unlock_kernel();
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations sv_dmfm_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = sv_dmfm_ioctl,
+- .open = sv_dmfm_open,
+- .release = sv_dmfm_release,
+-};
+-
+-/* --------------------------------------------------------------------- */
+-
+-/* maximum number of devices; only used for command line params */
+-#define NR_DEVICE 5
+-
+-static int reverb[NR_DEVICE];
+-
+-#if 0
+-static int wavetable[NR_DEVICE];
+-#endif
+-
+-static unsigned int devindex;
+-
+-module_param_array(reverb, bool, NULL, 0);
+-MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
+-#if 0
+-MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i");
+-MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
+-#endif
+-
+-MODULE_AUTHOR("Thomas M. Sailer, sailer at ife.ee.ethz.ch, hb9jnx at hb9w.che.eu");
+-MODULE_DESCRIPTION("S3 SonicVibes Driver");
+-MODULE_LICENSE("GPL");
+-
+-
+-/* --------------------------------------------------------------------- */
+-
+-static struct initvol {
+- int mixch;
+- int vol;
+-} initvol[] __devinitdata = {
+- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
+- { SOUND_MIXER_WRITE_CD, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE, 0x4040 },
+- { SOUND_MIXER_WRITE_MIC, 0x4040 },
+- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
+- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
+- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
+- { SOUND_MIXER_WRITE_PCM, 0x4040 }
+-};
+-
+-#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;
+-
+- if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) {
+- printk(KERN_ERR "sv: gameport io ports are in use\n");
+- return -EBUSY;
+- }
+-
+- s->gameport = gp = gameport_allocate_port();
+- if (!gp) {
+- printk(KERN_ERR "sv: can not allocate memory for gameport\n");
+- release_region(io_port, SV_EXTENT_GAME);
+- return -ENOMEM;
+- }
+-
+- gameport_set_name(gp, "S3 SonicVibes Gameport");
+- gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+- gp->dev.parent = &s->dev->dev;
+- gp->io = io_port;
+-
+- gameport_register_port(gp);
+-
+- 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";
+- struct sv_state *s;
+- mm_segment_t fs;
+- int i, val, ret;
+- int gpio;
+- char *ddmaname;
+- unsigned ddmanamelen;
+-
+- if ((ret=pci_enable_device(pcidev)))
+- return ret;
+-
+- if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
+- !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
+- !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
+- !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
+- !RSRCISIOREGION(pcidev, RESOURCE_GAME))
+- return -ENODEV;
+- if (pcidev->irq == 0)
+- return -ENODEV;
+- if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK)) {
+- printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
+- return -ENODEV;
+- }
+- /* try to allocate a DDMA resource if not already available */
+- if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
+- pcidev->resource[RESOURCE_DDMA].start = 0;
+- pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
+- pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
+- ddmanamelen = strlen(sv_ddma_name)+1;
+- if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
+- return -1;
+- memcpy(ddmaname, sv_ddma_name, ddmanamelen);
+- pcidev->resource[RESOURCE_DDMA].name = ddmaname;
+- if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
+- pcidev->resource[RESOURCE_DDMA].name = NULL;
+- kfree(ddmaname);
+- printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
+- return -EBUSY;
+- }
+- }
+- if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
+- printk(KERN_WARNING "sv: out of memory\n");
+- return -ENOMEM;
+- }
+- memset(s, 0, sizeof(struct sv_state));
+- init_waitqueue_head(&s->dma_adc.wait);
+- init_waitqueue_head(&s->dma_dac.wait);
+- init_waitqueue_head(&s->open_wait);
+- init_waitqueue_head(&s->midi.iwait);
+- init_waitqueue_head(&s->midi.owait);
+- mutex_init(&s->open_mutex);
+- spin_lock_init(&s->lock);
+- s->magic = SV_MAGIC;
+- s->dev = pcidev;
+- s->iosb = pci_resource_start(pcidev, RESOURCE_SB);
+- s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH);
+- s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH);
+- s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
+- s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
+- s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
+- gpio = pci_resource_start(pcidev, RESOURCE_GAME);
+- pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */
+- pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */
+- printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
+- s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac);
+- s->irq = pcidev->irq;
+-
+- /* hack */
+- pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */
+-
+- ret = -EBUSY;
+- if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) {
+- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1);
+- goto err_region5;
+- }
+- if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) {
+- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1);
+- goto err_region4;
+- }
+- if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) {
+- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1);
+- goto err_region3;
+- }
+- if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) {
+- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1);
+- goto err_region2;
+- }
+- if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) {
+- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
+- goto err_region1;
+- }
+-
+- /* initialize codec registers */
+- outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
+- udelay(50);
+- outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */
+- udelay(50);
+- outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */
+- | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL);
+- inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */
+- wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */
+- wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */
+- outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
+- /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+- /* outb(0xff, s->iodmac + SV_DMA_RESET); */
+- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
+- wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
+- wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
+- wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */
+- setpll(s, SV_CIADCPLLM, 8000);
+- wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */
+- wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff);
+- wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff);
+- wrindir(s, SV_CIADCOUTPUT, 0);
+- /* request irq */
+- if ((ret=request_irq(s->irq,sv_interrupt,IRQF_SHARED,"S3 SonicVibes",s))) {
+- printk(KERN_ERR "sv: irq %u in use\n", s->irq);
+- goto err_irq;
+- }
+- printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n",
+- s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
+- /* register devices */
+- if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) {
+- ret = s->dev_audio;
+- goto err_dev1;
+- }
+- if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) {
+- ret = s->dev_mixer;
+- goto err_dev2;
+- }
+- if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) {
+- ret = s->dev_midi;
+- goto err_dev3;
+- }
+- if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) {
+- ret = s->dev_dmfm;
+- goto err_dev4;
+- }
+- pci_set_master(pcidev); /* enable bus mastering */
+- /* initialize the chips */
+- fs = get_fs();
+- set_fs(KERNEL_DS);
+- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH;
+- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+- val = initvol[i].vol;
+- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+- }
+- set_fs(fs);
+- /* register gameport */
+- sv_register_gameport(s, gpio);
+- /* store it in the driver field */
+- pci_set_drvdata(pcidev, s);
+- /* put it into driver list */
+- list_add_tail(&s->devs, &devs);
+- /* increment devindex */
+- if (devindex < NR_DEVICE-1)
+- devindex++;
+- return 0;
+-
+- err_dev4:
+- unregister_sound_midi(s->dev_midi);
+- err_dev3:
+- unregister_sound_mixer(s->dev_mixer);
+- err_dev2:
+- unregister_sound_dsp(s->dev_audio);
+- err_dev1:
+- printk(KERN_ERR "sv: cannot register misc device\n");
+- free_irq(s->irq, s);
+- err_irq:
+- release_region(s->iosynth, SV_EXTENT_SYNTH);
+- err_region1:
+- release_region(s->iomidi, SV_EXTENT_MIDI);
+- err_region2:
+- release_region(s->iodmac, SV_EXTENT_DMA);
+- err_region3:
+- release_region(s->iodmaa, SV_EXTENT_DMA);
+- err_region4:
+- release_region(s->ioenh, SV_EXTENT_ENH);
+- err_region5:
+- kfree(s);
+- return ret;
+-}
+-
+-static void __devexit sv_remove(struct pci_dev *dev)
+-{
+- struct sv_state *s = pci_get_drvdata(dev);
+-
+- if (!s)
+- return;
+- list_del(&s->devs);
+- outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */
+- synchronize_irq(s->irq);
+- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
+- wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */
+- /*outb(0, s->iodmaa + SV_DMA_RESET);*/
+- /*outb(0, s->iodmac + SV_DMA_RESET);*/
+- free_irq(s->irq, s);
+- 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);
+- release_region(s->iomidi, SV_EXTENT_MIDI);
+- release_region(s->iosynth, SV_EXTENT_SYNTH);
+- unregister_sound_dsp(s->dev_audio);
+- unregister_sound_mixer(s->dev_mixer);
+- unregister_sound_midi(s->dev_midi);
+- unregister_sound_special(s->dev_dmfm);
+- kfree(s);
+- pci_set_drvdata(dev, NULL);
+-}
+-
+-static struct pci_device_id id_table[] = {
+- { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, id_table);
+-
+-static struct pci_driver sv_driver = {
+- .name = "sonicvibes",
+- .id_table = id_table,
+- .probe = sv_probe,
+- .remove = __devexit_p(sv_remove),
+-};
+-
+-static int __init init_sonicvibes(void)
+-{
+- printk(KERN_INFO "sv: version v0.31 time " __TIME__ " " __DATE__ "\n");
+-#if 0
+- if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
+- printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
+-#endif
+- return pci_register_driver(&sv_driver);
+-}
+-
+-static void __exit cleanup_sonicvibes(void)
+-{
+- printk(KERN_INFO "sv: unloading\n");
+- pci_unregister_driver(&sv_driver);
+- if (wavetable_mem)
+- free_pages(wavetable_mem, 20-PAGE_SHIFT);
+-}
+-
+-module_init(init_sonicvibes);
+-module_exit(cleanup_sonicvibes);
+-
+-/* --------------------------------------------------------------------- */
+-
+-#ifndef MODULE
+-
+-/* format is: sonicvibes=[reverb] sonicvibesdmaio=dmaioaddr */
+-
+-static int __init sonicvibes_setup(char *str)
+-{
+- static unsigned __initdata nr_dev = 0;
+-
+- if (nr_dev >= NR_DEVICE)
+- return 0;
+-#if 0
+- if (get_option(&str, &reverb[nr_dev]) == 2)
+- (void)get_option(&str, &wavetable[nr_dev]);
+-#else
+- (void)get_option(&str, &reverb[nr_dev]);
+-#endif
+-
+- nr_dev++;
+- return 1;
+-}
+-
+-__setup("sonicvibes=", sonicvibes_setup);
+-
+-#endif /* MODULE */
+diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h
+index 1ae0750..87d8ad4 100644
+--- a/sound/oss/sound_calls.h
++++ b/sound/oss/sound_calls.h
+@@ -13,8 +13,6 @@ int DMAbuf_move_wrpointer(int dev, int l
+ void DMAbuf_init(int dev, int dma1, int dma2);
+ void DMAbuf_deinit(int dev);
+ int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
+-int DMAbuf_open_dma (int dev);
+-void DMAbuf_close_dma (int dev);
+ void DMAbuf_inputintr(int dev);
+ void DMAbuf_outputintr(int dev, int underflow_flag);
+ struct dma_buffparms;
+@@ -73,7 +71,6 @@ unsigned int MIDIbuf_poll(int dev, struc
+ int MIDIbuf_avail(int dev);
+
+ void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
+-void MIDIbuf_init(void);
+
+
+ /* From soundcard.c */
+diff --git a/sound/oss/sound_syms.c b/sound/oss/sound_syms.c
+deleted file mode 100644
+index cb7c33f..0000000
+--- a/sound/oss/sound_syms.c
++++ /dev/null
+@@ -1,50 +0,0 @@
+-/*
+- * The sound core exports the following symbols to the rest of
+- * modulespace.
+- *
+- * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL
+- *
+- * Thu May 27 1999 Andrew J. Kroll <ag784 at freenet..buffalo..edu>
+- * left out exported symbol... fixed
+- */
+-
+-#include <linux/module.h>
+-#include "sound_config.h"
+-#include "sound_calls.h"
+-
+-char sound_syms_symbol;
+-
+-EXPORT_SYMBOL(mixer_devs);
+-EXPORT_SYMBOL(audio_devs);
+-EXPORT_SYMBOL(num_mixers);
+-EXPORT_SYMBOL(num_audiodevs);
+-
+-EXPORT_SYMBOL(midi_devs);
+-EXPORT_SYMBOL(num_midis);
+-EXPORT_SYMBOL(synth_devs);
+-
+-EXPORT_SYMBOL(sound_timer_devs);
+-
+-EXPORT_SYMBOL(sound_install_audiodrv);
+-EXPORT_SYMBOL(sound_install_mixer);
+-EXPORT_SYMBOL(sound_alloc_dma);
+-EXPORT_SYMBOL(sound_free_dma);
+-EXPORT_SYMBOL(sound_open_dma);
+-EXPORT_SYMBOL(sound_close_dma);
+-EXPORT_SYMBOL(sound_alloc_mididev);
+-EXPORT_SYMBOL(sound_alloc_mixerdev);
+-EXPORT_SYMBOL(sound_alloc_timerdev);
+-EXPORT_SYMBOL(sound_alloc_synthdev);
+-EXPORT_SYMBOL(sound_unload_audiodev);
+-EXPORT_SYMBOL(sound_unload_mididev);
+-EXPORT_SYMBOL(sound_unload_mixerdev);
+-EXPORT_SYMBOL(sound_unload_timerdev);
+-EXPORT_SYMBOL(sound_unload_synthdev);
+-
+-EXPORT_SYMBOL(load_mixer_volumes);
+-
+-EXPORT_SYMBOL(conf_printf);
+-EXPORT_SYMBOL(conf_printf2);
+-
+-MODULE_DESCRIPTION("OSS Sound subsystem");
+-MODULE_AUTHOR("Hannu Savolainen, et al.");
+diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c
+index bc2777d..f0f0c19 100644
+--- a/sound/oss/sound_timer.c
++++ b/sound/oss/sound_timer.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sound_timer.c
++ * sound/oss/sound_timer.c
+ */
+ /*
+ * Copyright (C) by Hannu Savolainen 1993-1997
+@@ -76,6 +76,7 @@ void sound_timer_syncinterval(unsigned i
+ tmr_ctr = 0;
+ usecs_per_tmr = new_usecs;
+ }
++EXPORT_SYMBOL(sound_timer_syncinterval);
+
+ static void tmr_reset(void)
+ {
+@@ -300,6 +301,7 @@ void sound_timer_interrupt(void)
+ }
+ spin_unlock_irqrestore(&lock,flags);
+ }
++EXPORT_SYMBOL(sound_timer_interrupt);
+
+ void sound_timer_init(struct sound_lowlev_timer *t, char *name)
+ {
+@@ -321,3 +323,5 @@ void sound_timer_init(struct sound_lowl
+ strcpy(sound_timer.info.name, name);
+ sound_timer_devs[n] = &sound_timer;
+ }
++EXPORT_SYMBOL(sound_timer_init);
++
+diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
+index 0860d67..2344d09 100644
+--- a/sound/oss/soundcard.c
++++ b/sound/oss/soundcard.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/sound/soundcard.c
++ * linux/sound/oss/soundcard.c
+ *
+ * Sound card driver for Linux
+ *
+@@ -107,6 +107,7 @@ int *load_mixer_volumes(char *name, int
+ mixer_vols[n].levels[i] = levels[i];
+ return mixer_vols[n].levels;
+ }
++EXPORT_SYMBOL(load_mixer_volumes);
+
+ static int set_mixer_levels(void __user * arg)
+ {
+@@ -541,12 +542,6 @@ static int __init oss_init(void)
+ int err;
+ int i, j;
+
+- /* drag in sound_syms.o */
+- {
+- extern char sound_syms_symbol;
+- sound_syms_symbol = 0;
+- }
+-
+ #ifdef CONFIG_PCI
+ if(dmabug)
+ isa_dma_bridge_buggy = dmabug;
+@@ -614,6 +609,8 @@ static void __exit oss_cleanup(void)
+ module_init(oss_init);
+ module_exit(oss_cleanup);
+ MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("OSS Sound subsystem");
++MODULE_AUTHOR("Hannu Savolainen, et al.");
+
+
+ int sound_alloc_dma(int chn, char *deviceID)
+@@ -627,6 +624,7 @@ int sound_alloc_dma(int chn, char *devic
+
+ return 0;
+ }
++EXPORT_SYMBOL(sound_alloc_dma);
+
+ int sound_open_dma(int chn, char *deviceID)
+ {
+@@ -642,6 +640,7 @@ int sound_open_dma(int chn, char *device
+ dma_alloc_map[chn] = DMA_MAP_BUSY;
+ return 0;
+ }
++EXPORT_SYMBOL(sound_open_dma);
+
+ void sound_free_dma(int chn)
+ {
+@@ -652,6 +651,7 @@ void sound_free_dma(int chn)
+ free_dma(chn);
+ dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
+ }
++EXPORT_SYMBOL(sound_free_dma);
+
+ void sound_close_dma(int chn)
+ {
+@@ -661,6 +661,7 @@ void sound_close_dma(int chn)
+ }
+ dma_alloc_map[chn] = DMA_MAP_FREE;
+ }
++EXPORT_SYMBOL(sound_close_dma);
+
+ static void do_sequencer_timer(unsigned long dummy)
+ {
+@@ -714,6 +715,7 @@ void conf_printf(char *name, struct addr
+ printk("\n");
+ #endif
+ }
++EXPORT_SYMBOL(conf_printf);
+
+ void conf_printf2(char *name, int base, int irq, int dma, int dma2)
+ {
+@@ -734,3 +736,5 @@ void conf_printf2(char *name, int base,
+ printk("\n");
+ #endif
+ }
++EXPORT_SYMBOL(conf_printf2);
++
+diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c
+index 9ed5211..51f2fa6 100644
+--- a/sound/oss/sscape.c
++++ b/sound/oss/sscape.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sscape.c
++ * sound/oss/sscape.c
+ *
+ * Low level driver for Ensoniq SoundScape
+ *
+diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
+index eb5ea32..471c274 100644
+--- a/sound/oss/swarm_cs4297a.c
++++ b/sound/oss/swarm_cs4297a.c
+@@ -725,7 +725,7 @@ static int serdma_reg_access(struct cs42
+ serdma_t *d = &s->dma_dac;
+ u64 *data_p;
+ unsigned swptr;
+- int flags;
++ unsigned long flags;
+ serdma_descr_t *descr;
+
+ if (s->reg_request) {
+@@ -2505,7 +2505,7 @@ static /*const */ struct file_operations
+ .release = cs4297a_release,
+ };
+
+-static void cs4297a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void cs4297a_interrupt(int irq, void *dev_id)
+ {
+ struct cs4297a_state *s = (struct cs4297a_state *) dev_id;
+ u32 status;
+diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c
+index c9d0451..1075344 100644
+--- a/sound/oss/sys_timer.c
++++ b/sound/oss/sys_timer.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/sys_timer.c
++ * sound/oss/sys_timer.c
+ *
+ * The default timer for the Level 2 sequencer interface
+ * Uses the (1/HZ sec) timer of kernel.
+diff --git a/sound/oss/trident.c b/sound/oss/trident.c
+index 2813e4c..7a363a1 100644
+--- a/sound/oss/trident.c
++++ b/sound/oss/trident.c
+@@ -488,10 +488,6 @@ static void ali_set_spdif_out_rate(struc
+ static void ali_enable_special_channel(struct trident_state *stat);
+ static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card);
+ static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);
+-static void ali_restore_regs(struct trident_card *card);
+-static void ali_save_regs(struct trident_card *card);
+-static int trident_suspend(struct pci_dev *dev, pm_message_t unused);
+-static int trident_resume(struct pci_dev *dev);
+ static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);
+ static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);
+ static unsigned int ali_get_spdif_in_rate(struct trident_card *card);
+@@ -507,13 +503,6 @@ static int ali_allocate_other_states_res
+ int chan_nums);
+ static void ali_free_other_states_resources(struct trident_state *state);
+
+-/* save registers for ALi Power Management */
+-static struct ali_saved_registers {
+- unsigned long global_regs[ALI_GLOBAL_REGS];
+- unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];
+- unsigned mixer_regs[ALI_MIXER_REGS];
+-} ali_registers;
+-
+ #define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) do { \
+ (dma_ptr) += (offset); \
+ (buffer) += (offset); \
+@@ -1822,7 +1811,7 @@ cyber_address_interrupt(struct trident_c
+ }
+
+ static irqreturn_t
+-trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++trident_interrupt(int irq, void *dev_id)
+ {
+ struct trident_card *card = (struct trident_card *) dev_id;
+ u32 event;
+@@ -1873,7 +1862,7 @@ trident_read(struct file *file, char __u
+ unsigned swptr;
+ int cnt;
+
+- pr_debug("trident: trident_read called, count = %d\n", count);
++ pr_debug("trident: trident_read called, count = %zd\n", count);
+
+ VALIDATE_STATE(state);
+
+@@ -1989,7 +1978,7 @@ trident_write(struct file *file, const c
+ unsigned int copy_count;
+ int lret; /* for lock_set_fmt */
+
+- pr_debug("trident: trident_write called, count = %d\n", count);
++ pr_debug("trident: trident_write called, count = %zd\n", count);
+
+ VALIDATE_STATE(state);
+
+@@ -3280,8 +3269,8 @@ ali_setup_spdif_out(struct trident_card
+ char temp;
+ struct pci_dev *pci_dev = NULL;
+
+- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+- pci_dev);
++ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
++ pci_dev);
+ if (pci_dev == NULL)
+ return;
+ pci_read_config_byte(pci_dev, 0x61, &temp);
+@@ -3295,6 +3284,8 @@ ali_setup_spdif_out(struct trident_card
+ temp |= 0x10;
+ pci_write_config_byte(pci_dev, 0x7e, temp);
+
++ pci_dev_put(pci_dev);
++
+ ch = inb(TRID_REG(card, ALI_SCTRL));
+ outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL));
+ ch = inb(TRID_REG(card, ALI_SPDIF_CTRL));
+@@ -3501,16 +3492,19 @@ ali_close_multi_channels(void)
+ char temp = 0;
+ struct pci_dev *pci_dev = NULL;
+
+- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+- pci_dev);
++ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
++ pci_dev);
+ if (pci_dev == NULL)
+ return -1;
++
+ pci_read_config_byte(pci_dev, 0x59, &temp);
+ temp &= ~0x80;
+ pci_write_config_byte(pci_dev, 0x59, temp);
+
+- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+- pci_dev);
++ pci_dev_put(pci_dev);
++
++ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
++ NULL);
+ if (pci_dev == NULL)
+ return -1;
+
+@@ -3518,6 +3512,8 @@ ali_close_multi_channels(void)
+ temp &= ~0x20;
+ pci_write_config_byte(pci_dev, 0xB8, temp);
+
++ pci_dev_put(pci_dev);
++
+ return 0;
+ }
+
+@@ -3528,21 +3524,26 @@ ali_setup_multi_channels(struct trident_
+ char temp = 0;
+ struct pci_dev *pci_dev = NULL;
+
+- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+- pci_dev);
++ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
++ pci_dev);
+ if (pci_dev == NULL)
+ return -1;
+ pci_read_config_byte(pci_dev, 0x59, &temp);
+ temp |= 0x80;
+ pci_write_config_byte(pci_dev, 0x59, temp);
+
+- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+- pci_dev);
++ pci_dev_put(pci_dev);
++
++ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
++ NULL);
+ if (pci_dev == NULL)
+ return -1;
+ pci_read_config_byte(pci_dev, (int) 0xB8, &temp);
+ temp |= 0x20;
+ pci_write_config_byte(pci_dev, (int) 0xB8, (u8) temp);
++
++ pci_dev_put(pci_dev);
++
+ if (chan_nums == 6) {
+ dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000;
+ outl(dwValue, TRID_REG(card, ALI_SCTRL));
+@@ -3653,6 +3654,14 @@ ali_allocate_other_states_resources(stru
+ return 0;
+ }
+
++#ifdef CONFIG_PM
++/* save registers for ALi Power Management */
++static struct ali_saved_registers {
++ unsigned long global_regs[ALI_GLOBAL_REGS];
++ unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];
++ unsigned mixer_regs[ALI_MIXER_REGS];
++} ali_registers;
++
+ static void
+ ali_save_regs(struct trident_card *card)
+ {
+@@ -3746,6 +3755,7 @@ trident_resume(struct pci_dev *dev)
+ }
+ return 0;
+ }
++#endif
+
+ static struct trident_channel *
+ ali_alloc_pcm_channel(struct trident_card *card)
+@@ -4105,8 +4115,8 @@ ali_reset_5451(struct trident_card *card
+ unsigned int dwVal;
+ unsigned short wCount, wReg;
+
+- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+- pci_dev);
++ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
++ pci_dev);
+ if (pci_dev == NULL)
+ return -1;
+
+@@ -4116,6 +4126,7 @@ ali_reset_5451(struct trident_card *card
+ pci_read_config_dword(pci_dev, 0x7c, &dwVal);
+ pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);
+ udelay(5000);
++ pci_dev_put(pci_dev);
+
+ pci_dev = card->pci_dev;
+ if (pci_dev == NULL)
+@@ -4395,7 +4406,7 @@ trident_probe(struct pci_dev *pci_dev, c
+
+ init_timer(&card->timer);
+ card->iobase = iobase;
+- card->pci_dev = pci_dev;
++ card->pci_dev = pci_dev_get(pci_dev);
+ card->pci_id = pci_id->device;
+ card->revision = revision;
+ card->irq = pci_dev->irq;
+@@ -4549,6 +4560,7 @@ out_unregister_sound_dsp:
+ out_free_irq:
+ free_irq(card->irq, card);
+ out_proc_fs:
++ pci_dev_put(card->pci_dev);
+ if (res) {
+ remove_proc_entry("ALi5451", NULL);
+ res = NULL;
+@@ -4599,9 +4611,9 @@ trident_remove(struct pci_dev *pci_dev)
+ }
+ unregister_sound_dsp(card->dev_audio);
+
+- kfree(card);
+-
+ pci_set_drvdata(pci_dev, NULL);
++ pci_dev_put(card->pci_dev);
++ kfree(card);
+ }
+
+ MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee, Muli Ben-Yehuda");
+@@ -4616,8 +4628,10 @@ static struct pci_driver trident_pci_dri
+ .id_table = trident_pci_tbl,
+ .probe = trident_probe,
+ .remove = __devexit_p(trident_remove),
++#ifdef CONFIG_PM
+ .suspend = trident_suspend,
+ .resume = trident_resume
++#endif
+ };
+
+ static int __init
+diff --git a/sound/oss/trix.c b/sound/oss/trix.c
+index d1f1f15..e04169e 100644
+--- a/sound/oss/trix.c
++++ b/sound/oss/trix.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/trix.c
++ * sound/oss/trix.c
+ *
+ * Low level driver for the MediaTrix AudioTrix Pro
+ * (MT-0002-PC Control Chip)
+diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h
+index 858e1fe..a73e3dd 100644
+--- a/sound/oss/tuning.h
++++ b/sound/oss/tuning.h
+@@ -1,13 +1,11 @@
+-#ifdef SEQUENCER_C
+-
+-unsigned short semitone_tuning[24] =
++static unsigned short semitone_tuning[24] =
+ {
+ /* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
+ /* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
+ /* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
+ };
+
+-unsigned short cent_tuning[100] =
++static unsigned short cent_tuning[100] =
+ {
+ /* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
+ /* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
+@@ -23,7 +21,3 @@ unsigned short cent_tuning[100] =
+ /* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
+ /* 96 */ 10570, 10576, 10582, 10589
+ };
+-#else
+-extern unsigned short semitone_tuning[24];
+-extern unsigned short cent_tuning[100];
+-#endif
+diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c
+index a3d75ba..a446b82 100644
+--- a/sound/oss/uart401.c
++++ b/sound/oss/uart401.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/uart401.c
++ * sound/oss/uart401.c
+ *
+ * MPU-401 UART driver (formerly uart401_midi.c)
+ *
+@@ -96,7 +96,7 @@ static void uart401_input_loop(uart401_d
+ printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base);
+ }
+
+-irqreturn_t uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
++irqreturn_t uart401intr(int irq, void *dev_id)
+ {
+ uart401_devc *devc = dev_id;
+
+diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c
+index 74ae75f..f3f914a 100644
+--- a/sound/oss/uart6850.c
++++ b/sound/oss/uart6850.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/uart6850.c
++ * sound/oss/uart6850.c
+ *
+ *
+ * Copyright (C) by Hannu Savolainen 1993-1997
+@@ -104,7 +104,7 @@ static void uart6850_input_loop(void)
+ }
+ }
+
+-static irqreturn_t m6850intr(int irq, void *dev_id, struct pt_regs *dummy)
++static irqreturn_t m6850intr(int irq, void *dev_id)
+ {
+ if (input_avail())
+ uart6850_input_loop();
+diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c
+index a7ef04f..d952b22 100644
+--- a/sound/oss/v_midi.c
++++ b/sound/oss/v_midi.c
+@@ -1,5 +1,5 @@
+ /*
+- * sound/v_midi.c
++ * sound/oss/v_midi.c
+ *
+ * The low level driver for the Sound Blaster DS chips.
+ *
+diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
+index 08d8c94..17837d4 100644
+--- a/sound/oss/via82cxxx_audio.c
++++ b/sound/oss/via82cxxx_audio.c
+@@ -1547,7 +1547,7 @@ static int via_mixer_open (struct inode
+
+ DPRINTK ("ENTER\n");
+
+- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
++ while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+ drvr = pci_dev_driver (pdev);
+ if (drvr == &via_driver) {
+ assert (pci_get_drvdata (pdev) != NULL);
+@@ -1562,6 +1562,7 @@ static int via_mixer_open (struct inode
+ return -ENODEV;
+
+ match:
++ pci_dev_put(pdev);
+ file->private_data = card->ac97;
+
+ DPRINTK ("EXIT, returning 0\n");
+@@ -1911,7 +1912,7 @@ static void via_intr_channel (struct via
+ }
+
+
+-static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t via_interrupt(int irq, void *dev_id)
+ {
+ struct via_info *card = dev_id;
+ u32 status32;
+@@ -1926,7 +1927,7 @@ static irqreturn_t via_interrupt(int ir
+ {
+ #ifdef CONFIG_MIDI_VIA82CXXX
+ if (card->midi_devc)
+- uart401intr(irq, card->midi_devc, regs);
++ uart401intr(irq, card->midi_devc);
+ #endif
+ return IRQ_HANDLED;
+ }
+@@ -1949,7 +1950,7 @@ static irqreturn_t via_interrupt(int ir
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t via_new_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t via_new_interrupt(int irq, void *dev_id)
+ {
+ struct via_info *card = dev_id;
+ u32 status32;
+@@ -3245,7 +3246,7 @@ static int via_dsp_open (struct inode *i
+ }
+
+ card = NULL;
+- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
++ while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+ drvr = pci_dev_driver (pdev);
+ if (drvr == &via_driver) {
+ assert (pci_get_drvdata (pdev) != NULL);
+@@ -3264,6 +3265,7 @@ static int via_dsp_open (struct inode *i
+ return -ENODEV;
+
+ match:
++ pci_dev_put(pdev);
+ if (nonblock) {
+ if (!mutex_trylock(&card->open_mutex)) {
+ DPRINTK ("EXIT, returning -EAGAIN\n");
+diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c
+index 8932d89..bb4a096 100644
+--- a/sound/oss/vidc.c
++++ b/sound/oss/vidc.c
+@@ -372,7 +372,7 @@ static void vidc_audio_trigger(int dev,
+ adev->flags |= DMA_ACTIVE;
+
+ dma_interrupt = vidc_audio_dma_interrupt;
+- vidc_sound_dma_irq(0, NULL, NULL);
++ vidc_sound_dma_irq(0, NULL);
+ iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR);
+
+ local_irq_restore(flags);
+diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h
+index d5b8064..0d14247 100644
+--- a/sound/oss/vidc.h
++++ b/sound/oss/vidc.h
+@@ -33,7 +33,7 @@ extern unsigned long vidc_fill_2x16_s(un
+ * DMA Interrupt handler
+ */
+
+-extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref, struct pt_regs *regs);
++extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref);
+
+ /*
+ * Filler routine pointer
+diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
+index 5f140c7..6dfb9f4 100644
+--- a/sound/oss/vwsnd.c
++++ b/sound/oss/vwsnd.c
+@@ -2233,12 +2233,12 @@ static void vwsnd_audio_write_intr(vwsnd
+ pcm_output(devc, underflown, 0);
+ }
+
+-static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id)
+ {
+- vwsnd_dev_t *devc = (vwsnd_dev_t *) dev_id;
++ vwsnd_dev_t *devc = dev_id;
+ unsigned int status;
+
+- DBGEV("(irq=%d, dev_id=0x%p, regs=0x%p)\n", irq, dev_id, regs);
++ DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id);
+
+ status = li_get_clear_intr_status(&devc->lith);
+ vwsnd_audio_read_intr(devc, status);
+diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
+index 22d2662..c5bf363 100644
+--- a/sound/oss/waveartist.c
++++ b/sound/oss/waveartist.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/sound/waveartist.c
++ * linux/sound/oss/waveartist.c
+ *
+ * The low level driver for the RWA010 Rockwell Wave Artist
+ * codec chip used in the Rebel.com NetWinder.
+@@ -833,7 +833,7 @@ static struct audio_driver waveartist_au
+
+
+ static irqreturn_t
+-waveartist_intr(int irq, void *dev_id, struct pt_regs *regs)
++waveartist_intr(int irq, void *dev_id)
+ {
+ wavnc_info *devc = (wavnc_info *)dev_id;
+ int irqstatus, status;
+diff --git a/sound/oss/waveartist.h b/sound/oss/waveartist.h
+index 2033fb8..dac4ca9 100644
+--- a/sound/oss/waveartist.h
++++ b/sound/oss/waveartist.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/sound/waveartist.h
++ * linux/sound/oss/waveartist.h
+ *
+ * def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder
+ */
+diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c
+deleted file mode 100644
+index 1dec395..0000000
+--- a/sound/oss/wavfront.c
++++ /dev/null
+@@ -1,3554 +0,0 @@
+-/* -*- linux-c -*-
+- *
+- * sound/wavfront.c
+- *
+- * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus)
+- *
+- * This driver supports the onboard wavetable synthesizer (an ICS2115),
+- * including patch, sample and program loading and unloading, conversion
+- * of GUS patches during loading, and full user-level access to all
+- * WaveFront commands. It tries to provide semi-intelligent patch and
+- * sample management as well.
+- *
+- * It also provides support for the ICS emulation of an MPU-401. Full
+- * support for the ICS emulation's "virtual MIDI mode" is provided in
+- * wf_midi.c.
+- *
+- * Support is also provided for the Tropez Plus' onboard FX processor,
+- * a Yamaha YSS225. Currently, code exists to configure the YSS225,
+- * and there is an interface allowing tweaking of any of its memory
+- * addresses. However, I have been unable to decipher the logical
+- * positioning of the configuration info for various effects, so for
+- * now, you just get the YSS225 in the same state as Turtle Beach's
+- * "SETUPSND.EXE" utility leaves it.
+- *
+- * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co],
+- * This chip also controls the configuration of the card: the wavefront
+- * synth is logical unit 4.
+- *
+- *
+- * Supported devices:
+- *
+- * /dev/dsp - using cs4232+ad1848 modules, OSS compatible
+- * /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible
+- * /dev/synth00 - raw synth interface
+- *
+- **********************************************************************
+- *
+- * Copyright (C) by Paul Barton-Davis 1998
+- *
+- * Some portions of this file are taken from work that is
+- * copyright (C) by Hannu Savolainen 1993-1996
+- *
+- * Although the relevant code here is all new, the handling of
+- * sample/alias/multi- samples is entirely based on a driver by Matt
+- * Martin and Rutger Nijlunsing which demonstrated how to get things
+- * to work correctly. The GUS patch loading code has been almost
+- * unaltered by me, except to fit formatting and function names in the
+- * rest of the file. Many thanks to them.
+- *
+- * Appreciation and thanks to Hannu Savolainen for his early work on the Maui
+- * driver, and answering a few questions while this one was developed.
+- *
+- * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their
+- * complete lack of help in developing this driver, and in particular
+- * for their utter silence in response to questions about undocumented
+- * aspects of configuring a WaveFront soundcard, particularly the
+- * effects processor.
+- *
+- * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $
+- *
+- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- *
+- * Changes:
+- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz at linux-ide.org>
+- * Added some __init and __initdata to entries in yss225.c
+- */
+-
+-#include <linux/module.h>
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/sched.h>
+-#include <linux/smp_lock.h>
+-#include <linux/ptrace.h>
+-#include <linux/fcntl.h>
+-#include <linux/syscalls.h>
+-#include <linux/ioport.h>
+-#include <linux/spinlock.h>
+-#include <linux/interrupt.h>
+-#include <linux/config.h>
+-
+-#include <linux/delay.h>
+-
+-#include "sound_config.h"
+-
+-#include <linux/wavefront.h>
+-
+-#define _MIDI_SYNTH_C_
+-#define MIDI_SYNTH_NAME "WaveFront MIDI"
+-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
+-#include "midi_synth.h"
+-
+-/* Compile-time control of the extent to which OSS is supported.
+-
+- I consider /dev/sequencer to be an anachronism, but given its
+- widespread usage by various Linux MIDI software, it seems worth
+- offering support to it if it's not too painful. Instead of using
+- /dev/sequencer, I recommend:
+-
+- for synth programming and patch loading: /dev/synthNN
+- for kernel-synchronized MIDI sequencing: the ALSA sequencer
+- for direct MIDI control: /dev/midiNN
+-
+- I have never tried static compilation into the kernel. The #if's
+- for this are really just notes to myself about what the code is
+- for.
+-*/
+-
+-#define OSS_SUPPORT_SEQ 0x1 /* use of /dev/sequencer */
+-#define OSS_SUPPORT_STATIC_INSTALL 0x2 /* static compilation into kernel */
+-
+-#define OSS_SUPPORT_LEVEL 0x1 /* just /dev/sequencer for now */
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+-static int (*midi_load_patch) (int devno, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag) = NULL;
+-#endif /* OSS_SUPPORT_SEQ */
+-
+-/* if WF_DEBUG not defined, no run-time debugging messages will
+- be available via the debug flag setting. Given the current
+- beta state of the driver, this will remain set until a future
+- version.
+-*/
+-
+-#define WF_DEBUG 1
+-
+-#ifdef WF_DEBUG
+-
+-/* Thank goodness for gcc's preprocessor ... */
+-
+-#define DPRINT(cond, format, args...) \
+- if ((dev.debug & (cond)) == (cond)) { \
+- printk (KERN_DEBUG LOGNAME format, ## args); \
+- }
+-#else
+-#define DPRINT(cond, format, args...)
+-#endif
+-
+-#define LOGNAME "WaveFront: "
+-
+-/* bitmasks for WaveFront status port value */
+-
+-#define STAT_RINTR_ENABLED 0x01
+-#define STAT_CAN_READ 0x02
+-#define STAT_INTR_READ 0x04
+-#define STAT_WINTR_ENABLED 0x10
+-#define STAT_CAN_WRITE 0x20
+-#define STAT_INTR_WRITE 0x40
+-
+-/*** Module-accessible parameters ***************************************/
+-
+-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.
+- The default is to download the microprogram and
+- associated coefficients to set it up for "default"
+- operation, whatever that means.
+- */
+-
+-static int debug_default; /* you can set this to control debugging
+- during driver loading. it takes any combination
+- of the WF_DEBUG_* flags defined in
+- wavefront.h
+- */
+-
+-/* XXX this needs to be made firmware and hardware version dependent */
+-
+-static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
+- version of the WaveFront OS
+- */
+-
+-static int wait_polls = 2000; /* This is a number of tries we poll the
+- status register before resorting to sleeping.
+- WaveFront being an ISA card each poll takes
+- about 1.2us. So before going to
+- sleep we wait up to 2.4ms in a loop.
+- */
+-
+-static int sleep_length = HZ/100; /* This says how long we're going to
+- sleep between polls.
+- 10ms sounds reasonable for fast response.
+- */
+-
+-static int sleep_tries = 50; /* Wait for status 0.5 seconds total. */
+-
+-static int reset_time = 2; /* hundreths of a second we wait after a HW reset for
+- the expected interrupt.
+- */
+-
+-static int ramcheck_time = 20; /* time in seconds to wait while ROM code
+- checks on-board RAM.
+- */
+-
+-static int osrun_time = 10; /* time in seconds we wait for the OS to
+- start running.
+- */
+-
+-module_param(wf_raw, int, 0);
+-module_param(fx_raw, int, 0);
+-module_param(debug_default, int, 0);
+-module_param(wait_polls, int, 0);
+-module_param(sleep_length, int, 0);
+-module_param(sleep_tries, int, 0);
+-module_param(ospath, charp, 0);
+-module_param(reset_time, int, 0);
+-module_param(ramcheck_time, int, 0);
+-module_param(osrun_time, int, 0);
+-
+-/***************************************************************************/
+-
+-/* Note: because this module doesn't export any symbols, this really isn't
+- a global variable, even if it looks like one. I was quite confused by
+- this when I started writing this as a (newer) module -- pbd.
+-*/
+-
+-struct wf_config {
+- int devno; /* device number from kernel */
+- int irq; /* "you were one, one of the few ..." */
+- int base; /* low i/o port address */
+-
+-#define mpu_data_port base
+-#define mpu_command_port base + 1 /* write semantics */
+-#define mpu_status_port base + 1 /* read semantics */
+-#define data_port base + 2
+-#define status_port base + 3 /* read semantics */
+-#define control_port base + 3 /* write semantics */
+-#define block_port base + 4 /* 16 bit, writeonly */
+-#define last_block_port base + 6 /* 16 bit, writeonly */
+-
+- /* FX ports. These are mapped through the ICS2115 to the YS225.
+- The ICS2115 takes care of flipping the relevant pins on the
+- YS225 so that access to each of these ports does the right
+- thing. Note: these are NOT documented by Turtle Beach.
+- */
+-
+-#define fx_status base + 8
+-#define fx_op base + 8
+-#define fx_lcr base + 9
+-#define fx_dsp_addr base + 0xa
+-#define fx_dsp_page base + 0xb
+-#define fx_dsp_lsb base + 0xc
+-#define fx_dsp_msb base + 0xd
+-#define fx_mod_addr base + 0xe
+-#define fx_mod_data base + 0xf
+-
+- volatile int irq_ok; /* set by interrupt handler */
+- volatile int irq_cnt; /* ditto */
+- int opened; /* flag, holds open(2) mode */
+- char debug; /* debugging flags */
+- int freemem; /* installed RAM, in bytes */
+-
+- int synth_dev; /* devno for "raw" synth */
+- int mididev; /* devno for internal MIDI */
+- int ext_mididev; /* devno for external MIDI */
+- int fx_mididev; /* devno for FX MIDI interface */
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+- int oss_dev; /* devno for OSS sequencer synth */
+-#endif /* OSS_SUPPORT_SEQ */
+-
+- char fw_version[2]; /* major = [0], minor = [1] */
+- char hw_version[2]; /* major = [0], minor = [1] */
+- char israw; /* needs Motorola microcode */
+- char has_fx; /* has FX processor (Tropez+) */
+- char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */
+- char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */
+- char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
+- int samples_used; /* how many */
+- char interrupts_on; /* h/w MPU interrupts enabled ? */
+- char rom_samples_rdonly; /* can we write on ROM samples */
+- wait_queue_head_t interrupt_sleeper;
+-} dev;
+-
+-static DEFINE_SPINLOCK(lock);
+-static int detect_wffx(void);
+-static int wffx_ioctl (wavefront_fx_info *);
+-static int wffx_init (void);
+-
+-static int wavefront_delete_sample (int sampnum);
+-static int wavefront_find_free_sample (void);
+-
+-/* From wf_midi.c */
+-
+-extern int virtual_midi_enable (void);
+-extern int virtual_midi_disable (void);
+-extern int detect_wf_mpu (int, int);
+-extern int install_wf_mpu (void);
+-extern int uninstall_wf_mpu (void);
+-
+-typedef struct {
+- int cmd;
+- char *action;
+- unsigned int read_cnt;
+- unsigned int write_cnt;
+- int need_ack;
+-} wavefront_command;
+-
+-static struct {
+- int errno;
+- const char *errstr;
+-} wavefront_errors[] = {
+- { 0x01, "Bad sample number" },
+- { 0x02, "Out of sample memory" },
+- { 0x03, "Bad patch number" },
+- { 0x04, "Error in number of voices" },
+- { 0x06, "Sample load already in progress" },
+- { 0x0B, "No sample load request pending" },
+- { 0x0E, "Bad MIDI channel number" },
+- { 0x10, "Download Record Error" },
+- { 0x80, "Success" },
+- { 0 }
+-};
+-
+-#define NEEDS_ACK 1
+-
+-static wavefront_command wavefront_commands[] = {
+- { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK },
+- { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0},
+- { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK },
+- { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 },
+- { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK },
+- { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 },
+- { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK },
+- { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK },
+- { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 },
+- { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK },
+- { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK },
+- { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK },
+- { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK },
+- { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 },
+- { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 },
+- { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 },
+- { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 },
+- { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 },
+- { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 },
+- { WFC_DOWNLOAD_SAMPLE, "download sample",
+- 0, WF_SAMPLE_BYTES, NEEDS_ACK },
+- { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK},
+- { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header",
+- 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK },
+- { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 },
+-
+- /* This command requires a variable number of bytes to be written.
+- There is a hack in wavefront_cmd() to support this. The actual
+- count is passed in as the read buffer ptr, cast appropriately.
+- Ugh.
+- */
+-
+- { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK },
+-
+- /* This one is a hack as well. We just read the first byte of the
+- response, don't fetch an ACK, and leave the rest to the
+- calling function. Ugly, ugly, ugly.
+- */
+-
+- { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 },
+- { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias",
+- 0, WF_ALIAS_BYTES, NEEDS_ACK },
+- { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0},
+- { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK },
+- { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 },
+- { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" },
+- { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 },
+- { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK },
+- { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 },
+- { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK },
+- { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 },
+- { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9,
+- NEEDS_ACK},
+- { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0},
+- { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel",
+- 0, 1, NEEDS_ACK },
+- { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK },
+- { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers",
+- 32, 0, 0 },
+- { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK },
+- { 0x00 }
+-};
+-
+-static const char *
+-wavefront_errorstr (int errnum)
+-
+-{
+- int i;
+-
+- for (i = 0; wavefront_errors[i].errstr; i++) {
+- if (wavefront_errors[i].errno == errnum) {
+- return wavefront_errors[i].errstr;
+- }
+- }
+-
+- return "Unknown WaveFront error";
+-}
+-
+-static wavefront_command *
+-wavefront_get_command (int cmd)
+-
+-{
+- int i;
+-
+- for (i = 0; wavefront_commands[i].cmd != 0; i++) {
+- if (cmd == wavefront_commands[i].cmd) {
+- return &wavefront_commands[i];
+- }
+- }
+-
+- return (wavefront_command *) 0;
+-}
+-
+-static inline int
+-wavefront_status (void)
+-
+-{
+- return inb (dev.status_port);
+-}
+-
+-static int
+-wavefront_wait (int mask)
+-
+-{
+- int i;
+-
+- for (i = 0; i < wait_polls; i++)
+- if (wavefront_status() & mask)
+- return 1;
+-
+- for (i = 0; i < sleep_tries; i++) {
+-
+- if (wavefront_status() & mask) {
+- set_current_state(TASK_RUNNING);
+- return 1;
+- }
+-
+- set_current_state(TASK_INTERRUPTIBLE);
+- schedule_timeout(sleep_length);
+- if (signal_pending(current))
+- break;
+- }
+-
+- set_current_state(TASK_RUNNING);
+- return 0;
+-}
+-
+-static int
+-wavefront_read (void)
+-
+-{
+- if (wavefront_wait (STAT_CAN_READ))
+- return inb (dev.data_port);
+-
+- DPRINT (WF_DEBUG_DATA, "read timeout.\n");
+-
+- return -1;
+-}
+-
+-static int
+-wavefront_write (unsigned char data)
+-
+-{
+- if (wavefront_wait (STAT_CAN_WRITE)) {
+- outb (data, dev.data_port);
+- return 0;
+- }
+-
+- DPRINT (WF_DEBUG_DATA, "write timeout.\n");
+-
+- return -1;
+-}
+-
+-static int
+-wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf)
+-
+-{
+- int ack;
+- int i;
+- int c;
+- wavefront_command *wfcmd;
+-
+- if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) {
+- printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n",
+- cmd);
+- return 1;
+- }
+-
+- /* Hack to handle the one variable-size write command. See
+- wavefront_send_multisample() for the other half of this
+- gross and ugly strategy.
+- */
+-
+- if (cmd == WFC_DOWNLOAD_MULTISAMPLE) {
+- wfcmd->write_cnt = (unsigned int) rbuf;
+- rbuf = NULL;
+- }
+-
+- DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n",
+- cmd, wfcmd->action, wfcmd->read_cnt,
+- wfcmd->write_cnt, wfcmd->need_ack);
+-
+- if (wavefront_write (cmd)) {
+- DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request "
+- "0x%x [%s].\n",
+- cmd, wfcmd->action);
+- return 1;
+- }
+-
+- if (wfcmd->write_cnt > 0) {
+- DPRINT (WF_DEBUG_DATA, "writing %d bytes "
+- "for 0x%x\n",
+- wfcmd->write_cnt, cmd);
+-
+- for (i = 0; i < wfcmd->write_cnt; i++) {
+- if (wavefront_write (wbuf[i])) {
+- DPRINT (WF_DEBUG_IO, "bad write for byte "
+- "%d of 0x%x [%s].\n",
+- i, cmd, wfcmd->action);
+- return 1;
+- }
+-
+- DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n",
+- i, wbuf[i]);
+- }
+- }
+-
+- if (wfcmd->read_cnt > 0) {
+- DPRINT (WF_DEBUG_DATA, "reading %d ints "
+- "for 0x%x\n",
+- wfcmd->read_cnt, cmd);
+-
+- for (i = 0; i < wfcmd->read_cnt; i++) {
+-
+- if ((c = wavefront_read()) == -1) {
+- DPRINT (WF_DEBUG_IO, "bad read for byte "
+- "%d of 0x%x [%s].\n",
+- i, cmd, wfcmd->action);
+- return 1;
+- }
+-
+- /* Now handle errors. Lots of special cases here */
+-
+- if (c == 0xff) {
+- if ((c = wavefront_read ()) == -1) {
+- DPRINT (WF_DEBUG_IO, "bad read for "
+- "error byte at "
+- "read byte %d "
+- "of 0x%x [%s].\n",
+- i, cmd,
+- wfcmd->action);
+- return 1;
+- }
+-
+- /* Can you believe this madness ? */
+-
+- if (c == 1 &&
+- wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) {
+- rbuf[0] = WF_ST_EMPTY;
+- return (0);
+-
+- } else if (c == 3 &&
+- wfcmd->cmd == WFC_UPLOAD_PATCH) {
+-
+- return 3;
+-
+- } else if (c == 1 &&
+- wfcmd->cmd == WFC_UPLOAD_PROGRAM) {
+-
+- return 1;
+-
+- } else {
+-
+- DPRINT (WF_DEBUG_IO, "error %d (%s) "
+- "during "
+- "read for byte "
+- "%d of 0x%x "
+- "[%s].\n",
+- c,
+- wavefront_errorstr (c),
+- i, cmd,
+- wfcmd->action);
+- return 1;
+-
+- }
+-
+- } else {
+- rbuf[i] = c;
+- }
+-
+- DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]);
+- }
+- }
+-
+- if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) {
+-
+- DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd);
+-
+- /* Some commands need an ACK, but return zero instead
+- of the standard value.
+- */
+-
+- if ((ack = wavefront_read()) == 0) {
+- ack = WF_ACK;
+- }
+-
+- if (ack != WF_ACK) {
+- if (ack == -1) {
+- DPRINT (WF_DEBUG_IO, "cannot read ack for "
+- "0x%x [%s].\n",
+- cmd, wfcmd->action);
+- return 1;
+-
+- } else {
+- int err = -1; /* something unknown */
+-
+- if (ack == 0xff) { /* explicit error */
+-
+- if ((err = wavefront_read ()) == -1) {
+- DPRINT (WF_DEBUG_DATA,
+- "cannot read err "
+- "for 0x%x [%s].\n",
+- cmd, wfcmd->action);
+- }
+- }
+-
+- DPRINT (WF_DEBUG_IO, "0x%x [%s] "
+- "failed (0x%x, 0x%x, %s)\n",
+- cmd, wfcmd->action, ack, err,
+- wavefront_errorstr (err));
+-
+- return -err;
+- }
+- }
+-
+- DPRINT (WF_DEBUG_DATA, "ack received "
+- "for 0x%x [%s]\n",
+- cmd, wfcmd->action);
+- } else {
+-
+- DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need "
+- "ACK (%d,%d,%d)\n",
+- cmd, wfcmd->action, wfcmd->read_cnt,
+- wfcmd->write_cnt, wfcmd->need_ack);
+- }
+-
+- return 0;
+-
+-}
+-
+-/***********************************************************************
+-WaveFront: data munging
+-
+-Things here are weird. All data written to the board cannot
+-have its most significant bit set. Any data item with values
+-potentially > 0x7F (127) must be split across multiple bytes.
+-
+-Sometimes, we need to munge numeric values that are represented on
+-the x86 side as 8-32 bit values. Sometimes, we need to munge data
+-that is represented on the x86 side as an array of bytes. The most
+-efficient approach to handling both cases seems to be to use 2
+-different functions for munging and 2 for de-munging. This avoids
+-weird casting and worrying about bit-level offsets.
+-
+-**********************************************************************/
+-
+-static
+-unsigned char *
+-munge_int32 (unsigned int src,
+- unsigned char *dst,
+- unsigned int dst_size)
+-{
+- int i;
+-
+- for (i = 0;i < dst_size; i++) {
+- *dst = src & 0x7F; /* Mask high bit of LSB */
+- src = src >> 7; /* Rotate Right 7 bits */
+- /* Note: we leave the upper bits in place */
+-
+- dst++;
+- };
+- return dst;
+-};
+-
+-static int
+-demunge_int32 (unsigned char* src, int src_size)
+-
+-{
+- int i;
+- int outval = 0;
+-
+- for (i = src_size - 1; i >= 0; i--) {
+- outval=(outval<<7)+src[i];
+- }
+-
+- return outval;
+-};
+-
+-static
+-unsigned char *
+-munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size)
+-
+-{
+- int i;
+- unsigned int last = dst_size / 2;
+-
+- for (i = 0; i < last; i++) {
+- *dst++ = src[i] & 0x7f;
+- *dst++ = src[i] >> 7;
+- }
+- return dst;
+-}
+-
+-static
+-unsigned char *
+-demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes)
+-
+-{
+- int i;
+- unsigned char *end = src + src_bytes;
+-
+- end = src + src_bytes;
+-
+- /* NOTE: src and dst *CAN* point to the same address */
+-
+- for (i = 0; src != end; i++) {
+- dst[i] = *src++;
+- dst[i] |= (*src++)<<7;
+- }
+-
+- return dst;
+-}
+-
+-/***********************************************************************
+-WaveFront: sample, patch and program management.
+-***********************************************************************/
+-
+-static int
+-wavefront_delete_sample (int sample_num)
+-
+-{
+- unsigned char wbuf[2];
+- int x;
+-
+- wbuf[0] = sample_num & 0x7f;
+- wbuf[1] = sample_num >> 7;
+-
+- if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) {
+- dev.sample_status[sample_num] = WF_ST_EMPTY;
+- }
+-
+- return x;
+-}
+-
+-static int
+-wavefront_get_sample_status (int assume_rom)
+-
+-{
+- int i;
+- unsigned char rbuf[32], wbuf[32];
+- unsigned int sc_real, sc_alias, sc_multi;
+-
+- /* check sample status */
+-
+- if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) {
+- printk (KERN_WARNING LOGNAME "cannot request sample count.\n");
+- return -1;
+- }
+-
+- sc_real = sc_alias = sc_multi = dev.samples_used = 0;
+-
+- for (i = 0; i < WF_MAX_SAMPLE; i++) {
+-
+- wbuf[0] = i & 0x7f;
+- wbuf[1] = i >> 7;
+-
+- if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
+- printk (KERN_WARNING LOGNAME
+- "cannot identify sample "
+- "type of slot %d\n", i);
+- dev.sample_status[i] = WF_ST_EMPTY;
+- continue;
+- }
+-
+- dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]);
+-
+- if (assume_rom) {
+- dev.sample_status[i] |= WF_SLOT_ROM;
+- }
+-
+- switch (rbuf[0] & WF_ST_MASK) {
+- case WF_ST_SAMPLE:
+- sc_real++;
+- break;
+- case WF_ST_MULTISAMPLE:
+- sc_multi++;
+- break;
+- case WF_ST_ALIAS:
+- sc_alias++;
+- break;
+- case WF_ST_EMPTY:
+- break;
+-
+- default:
+- printk (KERN_WARNING LOGNAME "unknown sample type for "
+- "slot %d (0x%x)\n",
+- i, rbuf[0]);
+- }
+-
+- if (rbuf[0] != WF_ST_EMPTY) {
+- dev.samples_used++;
+- }
+- }
+-
+- printk (KERN_INFO LOGNAME
+- "%d samples used (%d real, %d aliases, %d multi), "
+- "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi,
+- WF_MAX_SAMPLE - dev.samples_used);
+-
+-
+- return (0);
+-
+-}
+-
+-static int
+-wavefront_get_patch_status (void)
+-
+-{
+- unsigned char patchbuf[WF_PATCH_BYTES];
+- unsigned char patchnum[2];
+- wavefront_patch *p;
+- int i, x, cnt, cnt2;
+-
+- for (i = 0; i < WF_MAX_PATCH; i++) {
+- patchnum[0] = i & 0x7f;
+- patchnum[1] = i >> 7;
+-
+- if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf,
+- patchnum)) == 0) {
+-
+- dev.patch_status[i] |= WF_SLOT_FILLED;
+- p = (wavefront_patch *) patchbuf;
+- dev.sample_status
+- [p->sample_number|(p->sample_msb<<7)] |=
+- WF_SLOT_USED;
+-
+- } else if (x == 3) { /* Bad patch number */
+- dev.patch_status[i] = 0;
+- } else {
+- printk (KERN_ERR LOGNAME "upload patch "
+- "error 0x%x\n", x);
+- dev.patch_status[i] = 0;
+- return 1;
+- }
+- }
+-
+- /* program status has already filled in slot_used bits */
+-
+- for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) {
+- if (dev.patch_status[i] & WF_SLOT_FILLED) {
+- cnt++;
+- }
+- if (dev.patch_status[i] & WF_SLOT_USED) {
+- cnt2++;
+- }
+-
+- }
+- printk (KERN_INFO LOGNAME
+- "%d patch slots filled, %d in use\n", cnt, cnt2);
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_get_program_status (void)
+-
+-{
+- unsigned char progbuf[WF_PROGRAM_BYTES];
+- wavefront_program prog;
+- unsigned char prognum;
+- int i, x, l, cnt;
+-
+- for (i = 0; i < WF_MAX_PROGRAM; i++) {
+- prognum = i;
+-
+- if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf,
+- &prognum)) == 0) {
+-
+- dev.prog_status[i] |= WF_SLOT_USED;
+-
+- demunge_buf (progbuf, (unsigned char *) &prog,
+- WF_PROGRAM_BYTES);
+-
+- for (l = 0; l < WF_NUM_LAYERS; l++) {
+- if (prog.layer[l].mute) {
+- dev.patch_status
+- [prog.layer[l].patch_number] |=
+- WF_SLOT_USED;
+- }
+- }
+- } else if (x == 1) { /* Bad program number */
+- dev.prog_status[i] = 0;
+- } else {
+- printk (KERN_ERR LOGNAME "upload program "
+- "error 0x%x\n", x);
+- dev.prog_status[i] = 0;
+- }
+- }
+-
+- for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) {
+- if (dev.prog_status[i]) {
+- cnt++;
+- }
+- }
+-
+- printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt);
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_send_patch (wavefront_patch_info *header)
+-
+-{
+- unsigned char buf[WF_PATCH_BYTES+2];
+- unsigned char *bptr;
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n",
+- header->number);
+-
+- dev.patch_status[header->number] |= WF_SLOT_FILLED;
+-
+- bptr = buf;
+- bptr = munge_int32 (header->number, buf, 2);
+- munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES);
+-
+- if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) {
+- printk (KERN_ERR LOGNAME "download patch failed\n");
+- return -(EIO);
+- }
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_send_program (wavefront_patch_info *header)
+-
+-{
+- unsigned char buf[WF_PROGRAM_BYTES+1];
+- int i;
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n",
+- header->number);
+-
+- dev.prog_status[header->number] = WF_SLOT_USED;
+-
+- /* XXX need to zero existing SLOT_USED bit for program_status[i]
+- where `i' is the program that's being (potentially) overwritten.
+- */
+-
+- for (i = 0; i < WF_NUM_LAYERS; i++) {
+- if (header->hdr.pr.layer[i].mute) {
+- dev.patch_status[header->hdr.pr.layer[i].patch_number] |=
+- WF_SLOT_USED;
+-
+- /* XXX need to mark SLOT_USED for sample used by
+- patch_number, but this means we have to load it. Ick.
+- */
+- }
+- }
+-
+- buf[0] = header->number;
+- munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES);
+-
+- if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
+- printk (KERN_WARNING LOGNAME "download patch failed\n");
+- return -(EIO);
+- }
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_freemem (void)
+-
+-{
+- char rbuf[8];
+-
+- if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) {
+- printk (KERN_WARNING LOGNAME "can't get memory stats.\n");
+- return -1;
+- } else {
+- return demunge_int32 (rbuf, 4);
+- }
+-}
+-
+-static int
+-wavefront_send_sample (wavefront_patch_info *header,
+- UINT16 __user *dataptr,
+- int data_is_unsigned)
+-
+-{
+- /* samples are downloaded via a 16-bit wide i/o port
+- (you could think of it as 2 adjacent 8-bit wide ports
+- but its less efficient that way). therefore, all
+- the blocksizes and so forth listed in the documentation,
+- and used conventionally to refer to sample sizes,
+- which are given in 8-bit units (bytes), need to be
+- divided by 2.
+- */
+-
+- UINT16 sample_short;
+- UINT32 length;
+- UINT16 __user *data_end = NULL;
+- unsigned int i;
+- const int max_blksize = 4096/2;
+- unsigned int written;
+- unsigned int blocksize;
+- int dma_ack;
+- int blocknum;
+- unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES];
+- unsigned char *shptr;
+- int skip = 0;
+- int initial_skip = 0;
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, "
+- "type %d, %d bytes from %p\n",
+- header->size ? "" : "header ",
+- header->number, header->subkey,
+- header->size,
+- header->dataptr);
+-
+- if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) {
+- int x;
+-
+- if ((x = wavefront_find_free_sample ()) < 0) {
+- return -ENOMEM;
+- }
+- printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x);
+- header->number = x;
+- }
+-
+- if (header->size) {
+-
+- /* XXX it's a debatable point whether or not RDONLY semantics
+- on the ROM samples should cover just the sample data or
+- the sample header. For now, it only covers the sample data,
+- so anyone is free at all times to rewrite sample headers.
+-
+- My reason for this is that we have the sample headers
+- available in the WFB file for General MIDI, and so these
+- can always be reset if needed. The sample data, however,
+- cannot be recovered without a complete reset and firmware
+- reload of the ICS2115, which is a very expensive operation.
+-
+- So, doing things this way allows us to honor the notion of
+- "RESETSAMPLES" reasonably cheaply. Note however, that this
+- is done purely at user level: there is no WFB parser in
+- this driver, and so a complete reset (back to General MIDI,
+- or theoretically some other configuration) is the
+- responsibility of the user level library.
+-
+- To try to do this in the kernel would be a little
+- crazy: we'd need 158K of kernel space just to hold
+- a copy of the patch/program/sample header data.
+- */
+-
+- if (dev.rom_samples_rdonly) {
+- if (dev.sample_status[header->number] & WF_SLOT_ROM) {
+- printk (KERN_ERR LOGNAME "sample slot %d "
+- "write protected\n",
+- header->number);
+- return -EACCES;
+- }
+- }
+-
+- wavefront_delete_sample (header->number);
+- }
+-
+- if (header->size) {
+- dev.freemem = wavefront_freemem ();
+-
+- if (dev.freemem < header->size) {
+- printk (KERN_ERR LOGNAME
+- "insufficient memory to "
+- "load %d byte sample.\n",
+- header->size);
+- return -ENOMEM;
+- }
+-
+- }
+-
+- skip = WF_GET_CHANNEL(&header->hdr.s);
+-
+- if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
+- printk (KERN_ERR LOGNAME "channel selection only "
+- "possible on 16-bit samples");
+- return -(EINVAL);
+- }
+-
+- switch (skip) {
+- case 0:
+- initial_skip = 0;
+- skip = 1;
+- break;
+- case 1:
+- initial_skip = 0;
+- skip = 2;
+- break;
+- case 2:
+- initial_skip = 1;
+- skip = 2;
+- break;
+- case 3:
+- initial_skip = 2;
+- skip = 3;
+- break;
+- case 4:
+- initial_skip = 3;
+- skip = 4;
+- break;
+- case 5:
+- initial_skip = 4;
+- skip = 5;
+- break;
+- case 6:
+- initial_skip = 5;
+- skip = 6;
+- break;
+- }
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => "
+- "initial skip = %d, skip = %d\n",
+- WF_GET_CHANNEL (&header->hdr.s),
+- initial_skip, skip);
+-
+- /* Be safe, and zero the "Unused" bits ... */
+-
+- WF_SET_CHANNEL(&header->hdr.s, 0);
+-
+- /* adjust size for 16 bit samples by dividing by two. We always
+- send 16 bits per write, even for 8 bit samples, so the length
+- is always half the size of the sample data in bytes.
+- */
+-
+- length = header->size / 2;
+-
+- /* the data we're sent has not been munged, and in fact, the
+- header we have to send isn't just a munged copy either.
+- so, build the sample header right here.
+- */
+-
+- shptr = &sample_hdr[0];
+-
+- shptr = munge_int32 (header->number, shptr, 2);
+-
+- if (header->size) {
+- shptr = munge_int32 (length, shptr, 4);
+- }
+-
+- /* Yes, a 4 byte result doesn't contain all of the offset bits,
+- but the offset only uses 24 bits.
+- */
+-
+- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset),
+- shptr, 4);
+- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset),
+- shptr, 4);
+- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset),
+- shptr, 4);
+- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
+- shptr, 4);
+-
+- /* This one is truly weird. What kind of weirdo decided that in
+- a system dominated by 16 and 32 bit integers, they would use
+- a just 12 bits ?
+- */
+-
+- shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3);
+-
+- /* Why is this nybblified, when the MSB is *always* zero ?
+- Anyway, we can't take address of bitfield, so make a
+- good-faith guess at where it starts.
+- */
+-
+- shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1),
+- shptr, 2);
+-
+- if (wavefront_cmd (header->size ?
+- WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER,
+- NULL, sample_hdr)) {
+- printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n",
+- header->size ? "" : "header ");
+- return -(EIO);
+- }
+-
+- if (header->size == 0) {
+- goto sent; /* Sorry. Just had to have one somewhere */
+- }
+-
+- data_end = dataptr + length;
+-
+- /* Do any initial skip over an unused channel's data */
+-
+- dataptr += initial_skip;
+-
+- for (written = 0, blocknum = 0;
+- written < length; written += max_blksize, blocknum++) {
+-
+- if ((length - written) > max_blksize) {
+- blocksize = max_blksize;
+- } else {
+- /* round to nearest 16-byte value */
+- blocksize = ((length-written+7)&~0x7);
+- }
+-
+- if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
+- printk (KERN_WARNING LOGNAME "download block "
+- "request refused.\n");
+- return -(EIO);
+- }
+-
+- for (i = 0; i < blocksize; i++) {
+-
+- if (dataptr < data_end) {
+-
+- __get_user (sample_short, dataptr);
+- dataptr += skip;
+-
+- if (data_is_unsigned) { /* GUS ? */
+-
+- if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) {
+-
+- /* 8 bit sample
+- resolution, sign
+- extend both bytes.
+- */
+-
+- ((unsigned char*)
+- &sample_short)[0] += 0x7f;
+- ((unsigned char*)
+- &sample_short)[1] += 0x7f;
+-
+- } else {
+-
+- /* 16 bit sample
+- resolution, sign
+- extend the MSB.
+- */
+-
+- sample_short += 0x7fff;
+- }
+- }
+-
+- } else {
+-
+- /* In padding section of final block:
+-
+- Don't fetch unsupplied data from
+- user space, just continue with
+- whatever the final value was.
+- */
+- }
+-
+- if (i < blocksize - 1) {
+- outw (sample_short, dev.block_port);
+- } else {
+- outw (sample_short, dev.last_block_port);
+- }
+- }
+-
+- /* Get "DMA page acknowledge", even though its really
+- nothing to do with DMA at all.
+- */
+-
+- if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) {
+- if (dma_ack == -1) {
+- printk (KERN_ERR LOGNAME "upload sample "
+- "DMA ack timeout\n");
+- return -(EIO);
+- } else {
+- printk (KERN_ERR LOGNAME "upload sample "
+- "DMA ack error 0x%x\n",
+- dma_ack);
+- return -(EIO);
+- }
+- }
+- }
+-
+- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE);
+-
+- /* Note, label is here because sending the sample header shouldn't
+- alter the sample_status info at all.
+- */
+-
+- sent:
+- return (0);
+-}
+-
+-static int
+-wavefront_send_alias (wavefront_patch_info *header)
+-
+-{
+- unsigned char alias_hdr[WF_ALIAS_BYTES];
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is "
+- "alias for %d\n",
+- header->number,
+- header->hdr.a.OriginalSample);
+-
+- munge_int32 (header->number, &alias_hdr[0], 2);
+- munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2);
+- munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset),
+- &alias_hdr[4], 4);
+- munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset),
+- &alias_hdr[8], 4);
+- munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset),
+- &alias_hdr[12], 4);
+- munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset),
+- &alias_hdr[16], 4);
+- munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3);
+- munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2);
+-
+- if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
+- printk (KERN_ERR LOGNAME "download alias failed.\n");
+- return -(EIO);
+- }
+-
+- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_send_multisample (wavefront_patch_info *header)
+-{
+- int i;
+- int num_samples;
+- unsigned char msample_hdr[WF_MSAMPLE_BYTES];
+-
+- munge_int32 (header->number, &msample_hdr[0], 2);
+-
+- /* You'll recall at this point that the "number of samples" value
+- in a wavefront_multisample struct is actually the log2 of the
+- real number of samples.
+- */
+-
+- num_samples = (1<<(header->hdr.ms.NumberOfSamples&7));
+- msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples;
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n",
+- header->number,
+- header->hdr.ms.NumberOfSamples,
+- num_samples);
+-
+- for (i = 0; i < num_samples; i++) {
+- DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n",
+- i, header->hdr.ms.SampleNumber[i]);
+- munge_int32 (header->hdr.ms.SampleNumber[i],
+- &msample_hdr[3+(i*2)], 2);
+- }
+-
+- /* Need a hack here to pass in the number of bytes
+- to be written to the synth. This is ugly, and perhaps
+- one day, I'll fix it.
+- */
+-
+- if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE,
+- (unsigned char *) ((num_samples*2)+3),
+- msample_hdr)) {
+- printk (KERN_ERR LOGNAME "download of multisample failed.\n");
+- return -(EIO);
+- }
+-
+- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_fetch_multisample (wavefront_patch_info *header)
+-{
+- int i;
+- unsigned char log_ns[1];
+- unsigned char number[2];
+- int num_samples;
+-
+- munge_int32 (header->number, number, 2);
+-
+- if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
+- printk (KERN_ERR LOGNAME "upload multisample failed.\n");
+- return -(EIO);
+- }
+-
+- DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
+- header->number, log_ns[0]);
+-
+- header->hdr.ms.NumberOfSamples = log_ns[0];
+-
+- /* get the number of samples ... */
+-
+- num_samples = (1 << log_ns[0]);
+-
+- for (i = 0; i < num_samples; i++) {
+- s8 d[2];
+-
+- if ((d[0] = wavefront_read ()) == -1) {
+- printk (KERN_ERR LOGNAME "upload multisample failed "
+- "during sample loop.\n");
+- return -(EIO);
+- }
+-
+- if ((d[1] = wavefront_read ()) == -1) {
+- printk (KERN_ERR LOGNAME "upload multisample failed "
+- "during sample loop.\n");
+- return -(EIO);
+- }
+-
+- header->hdr.ms.SampleNumber[i] =
+- demunge_int32 ((unsigned char *) d, 2);
+-
+- DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n",
+- i, header->hdr.ms.SampleNumber[i]);
+- }
+-
+- return (0);
+-}
+-
+-
+-static int
+-wavefront_send_drum (wavefront_patch_info *header)
+-
+-{
+- unsigned char drumbuf[WF_DRUM_BYTES];
+- wavefront_drum *drum = &header->hdr.d;
+- int i;
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI "
+- "note %d, patch = %d\n",
+- header->number, drum->PatchNumber);
+-
+- drumbuf[0] = header->number & 0x7f;
+-
+- for (i = 0; i < 4; i++) {
+- munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2);
+- }
+-
+- if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
+- printk (KERN_ERR LOGNAME "download drum failed.\n");
+- return -(EIO);
+- }
+-
+- return (0);
+-}
+-
+-static int
+-wavefront_find_free_sample (void)
+-
+-{
+- int i;
+-
+- for (i = 0; i < WF_MAX_SAMPLE; i++) {
+- if (!(dev.sample_status[i] & WF_SLOT_FILLED)) {
+- return i;
+- }
+- }
+- printk (KERN_WARNING LOGNAME "no free sample slots!\n");
+- return -1;
+-}
+-
+-static int
+-wavefront_find_free_patch (void)
+-
+-{
+- int i;
+-
+- for (i = 0; i < WF_MAX_PATCH; i++) {
+- if (!(dev.patch_status[i] & WF_SLOT_FILLED)) {
+- return i;
+- }
+- }
+- printk (KERN_WARNING LOGNAME "no free patch slots!\n");
+- return -1;
+-}
+-
+-static int
+-log2_2048(int n)
+-
+-{
+- int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143,
+- 6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192,
+- 8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390,
+- 9510, 9626, 9738, 9845, 9949, 10049, 10146};
+- int i;
+-
+- /* Returns 2048*log2(n) */
+-
+- /* FIXME: this is like doing integer math
+- on quantum particles (RuN) */
+-
+- i=0;
+- while(n>=32*256) {
+- n>>=8;
+- i+=2048*8;
+- }
+- while(n>=32) {
+- n>>=1;
+- i+=2048;
+- }
+- i+=tbl[n];
+- return(i);
+-}
+-
+-static int
+-wavefront_load_gus_patch (int devno, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag)
+-{
+- struct patch_info guspatch;
+- wavefront_patch_info *samp, *pat, *prog;
+- wavefront_patch *patp;
+- wavefront_sample *sampp;
+- wavefront_program *progp;
+-
+- int i,base_note;
+- long sizeof_patch;
+- int rc = -ENOMEM;
+-
+- samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL);
+- if (!samp)
+- goto free_fail;
+- pat = samp + 1;
+- prog = pat + 1;
+-
+- /* Copy in the header of the GUS patch */
+-
+- sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch;
+- if (copy_from_user(&((char *) &guspatch)[offs],
+- &(addr)[offs], sizeof_patch - offs)) {
+- rc = -EFAULT;
+- goto free_fail;
+- }
+-
+- if ((i = wavefront_find_free_patch ()) == -1) {
+- rc = -EBUSY;
+- goto free_fail;
+- }
+- pat->number = i;
+- pat->subkey = WF_ST_PATCH;
+- patp = &pat->hdr.p;
+-
+- if ((i = wavefront_find_free_sample ()) == -1) {
+- rc = -EBUSY;
+- goto free_fail;
+- }
+- samp->number = i;
+- samp->subkey = WF_ST_SAMPLE;
+- samp->size = guspatch.len;
+- sampp = &samp->hdr.s;
+-
+- prog->number = guspatch.instr_no;
+- progp = &prog->hdr.pr;
+-
+- /* Setup the patch structure */
+-
+- patp->amplitude_bias=guspatch.volume;
+- patp->portamento=0;
+- patp->sample_number= samp->number & 0xff;
+- patp->sample_msb= samp->number >> 8;
+- patp->pitch_bend= /*12*/ 0;
+- patp->mono=1;
+- patp->retrigger=1;
+- patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1;
+- patp->frequency_bias=0;
+- patp->restart=0;
+- patp->reuse=0;
+- patp->reset_lfo=1;
+- patp->fm_src2=0;
+- patp->fm_src1=WF_MOD_MOD_WHEEL;
+- patp->am_src=WF_MOD_PRESSURE;
+- patp->am_amount=127;
+- patp->fc1_mod_amount=0;
+- patp->fc2_mod_amount=0;
+- patp->fm_amount1=0;
+- patp->fm_amount2=0;
+- patp->envelope1.attack_level=127;
+- patp->envelope1.decay1_level=127;
+- patp->envelope1.decay2_level=127;
+- patp->envelope1.sustain_level=127;
+- patp->envelope1.release_level=0;
+- patp->envelope2.attack_velocity=127;
+- patp->envelope2.attack_level=127;
+- patp->envelope2.decay1_level=127;
+- patp->envelope2.decay2_level=127;
+- patp->envelope2.sustain_level=127;
+- patp->envelope2.release_level=0;
+- patp->envelope2.attack_velocity=127;
+- patp->randomizer=0;
+-
+- /* Program for this patch */
+-
+- progp->layer[0].patch_number= pat->number; /* XXX is this right ? */
+- progp->layer[0].mute=1;
+- progp->layer[0].pan_or_mod=1;
+- progp->layer[0].pan=7;
+- progp->layer[0].mix_level=127 /* guspatch.volume */;
+- progp->layer[0].split_type=0;
+- progp->layer[0].split_point=0;
+- progp->layer[0].play_below=0;
+-
+- for (i = 1; i < 4; i++) {
+- progp->layer[i].mute=0;
+- }
+-
+- /* Sample data */
+-
+- sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1);
+-
+- for (base_note=0;
+- note_to_freq (base_note) < guspatch.base_note;
+- base_note++);
+-
+- if ((guspatch.base_note-note_to_freq(base_note))
+- >(note_to_freq(base_note)-guspatch.base_note))
+- base_note++;
+-
+- printk(KERN_DEBUG "ref freq=%d,base note=%d\n",
+- guspatch.base_freq,
+- base_note);
+-
+- sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq)
+- + base_note*171);
+- printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias);
+- sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0;
+- sampp->sampleStartOffset.Fraction=0;
+- sampp->sampleStartOffset.Integer=0;
+- sampp->loopStartOffset.Fraction=0;
+- sampp->loopStartOffset.Integer=guspatch.loop_start
+- >>((guspatch.mode&WAVE_16_BITS) ? 1:0);
+- sampp->loopEndOffset.Fraction=0;
+- sampp->loopEndOffset.Integer=guspatch.loop_end
+- >>((guspatch.mode&WAVE_16_BITS) ? 1:0);
+- sampp->sampleEndOffset.Fraction=0;
+- sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1);
+- sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0;
+- sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0;
+-
+- /* Now ship it down */
+-
+- wavefront_send_sample (samp,
+- (unsigned short __user *) &(addr)[sizeof_patch],
+- (guspatch.mode & WAVE_UNSIGNED) ? 1:0);
+- wavefront_send_patch (pat);
+- wavefront_send_program (prog);
+-
+- /* Now pan as best we can ... use the slave/internal MIDI device
+- number if it exists (since it talks to the WaveFront), or the
+- master otherwise.
+- */
+-
+- if (dev.mididev > 0) {
+- midi_synth_controller (dev.mididev, guspatch.instr_no, 10,
+- ((guspatch.panning << 4) > 127) ?
+- 127 : (guspatch.panning << 4));
+- }
+- rc = 0;
+-
+-free_fail:
+- kfree(samp);
+- return rc;
+-}
+-
+-static int
+-wavefront_load_patch (const char __user *addr)
+-
+-
+-{
+- wavefront_patch_info header;
+-
+- if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) -
+- sizeof(wavefront_any))) {
+- printk (KERN_WARNING LOGNAME "bad address for load patch.\n");
+- return -EFAULT;
+- }
+-
+- DPRINT (WF_DEBUG_LOAD_PATCH, "download "
+- "Sample type: %d "
+- "Sample number: %d "
+- "Sample size: %d\n",
+- header.subkey,
+- header.number,
+- header.size);
+-
+- switch (header.subkey) {
+- case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */
+-
+- if (copy_from_user((unsigned char *) &header.hdr.s,
+- (unsigned char __user *) header.hdrptr,
+- sizeof (wavefront_sample)))
+- return -EFAULT;
+-
+- return wavefront_send_sample (&header, header.dataptr, 0);
+-
+- case WF_ST_MULTISAMPLE:
+-
+- if (copy_from_user(&header.hdr.s, header.hdrptr,
+- sizeof(wavefront_multisample)))
+- return -EFAULT;
+-
+- return wavefront_send_multisample (&header);
+-
+-
+- case WF_ST_ALIAS:
+-
+- if (copy_from_user(&header.hdr.a, header.hdrptr,
+- sizeof (wavefront_alias)))
+- return -EFAULT;
+-
+- return wavefront_send_alias (&header);
+-
+- case WF_ST_DRUM:
+- if (copy_from_user(&header.hdr.d, header.hdrptr,
+- sizeof (wavefront_drum)))
+- return -EFAULT;
+-
+- return wavefront_send_drum (&header);
+-
+- case WF_ST_PATCH:
+- if (copy_from_user(&header.hdr.p, header.hdrptr,
+- sizeof (wavefront_patch)))
+- return -EFAULT;
+-
+- return wavefront_send_patch (&header);
+-
+- case WF_ST_PROGRAM:
+- if (copy_from_user(&header.hdr.pr, header.hdrptr,
+- sizeof (wavefront_program)))
+- return -EFAULT;
+-
+- return wavefront_send_program (&header);
+-
+- default:
+- printk (KERN_ERR LOGNAME "unknown patch type %d.\n",
+- header.subkey);
+- return -(EINVAL);
+- }
+-
+- return 0;
+-}
+-
+-/***********************************************************************
+-WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces
+-***********************************************************************/
+-
+-static void
+-process_sample_hdr (UCHAR8 *buf)
+-
+-{
+- wavefront_sample s;
+- UCHAR8 *ptr;
+-
+- ptr = buf;
+-
+- /* The board doesn't send us an exact copy of a "wavefront_sample"
+- in response to an Upload Sample Header command. Instead, we
+- have to convert the data format back into our data structure,
+- just as in the Download Sample command, where we have to do
+- something very similar in the reverse direction.
+- */
+-
+- *((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
+- *((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
+- *((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
+- *((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
+- *((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3;
+-
+- s.SampleResolution = *ptr & 0x3;
+- s.Loop = *ptr & 0x8;
+- s.Bidirectional = *ptr & 0x10;
+- s.Reverse = *ptr & 0x40;
+-
+- /* Now copy it back to where it came from */
+-
+- memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample));
+-}
+-
+-static int
+-wavefront_synth_control (int cmd, wavefront_control *wc)
+-
+-{
+- unsigned char patchnumbuf[2];
+- int i;
+-
+- DPRINT (WF_DEBUG_CMD, "synth control with "
+- "cmd 0x%x\n", wc->cmd);
+-
+- /* Pre-handling of or for various commands */
+-
+- switch (wc->cmd) {
+- case WFC_DISABLE_INTERRUPTS:
+- printk (KERN_INFO LOGNAME "interrupts disabled.\n");
+- outb (0x80|0x20, dev.control_port);
+- dev.interrupts_on = 0;
+- return 0;
+-
+- case WFC_ENABLE_INTERRUPTS:
+- printk (KERN_INFO LOGNAME "interrupts enabled.\n");
+- outb (0x80|0x40|0x20, dev.control_port);
+- dev.interrupts_on = 1;
+- return 0;
+-
+- case WFC_INTERRUPT_STATUS:
+- wc->rbuf[0] = dev.interrupts_on;
+- return 0;
+-
+- case WFC_ROMSAMPLES_RDONLY:
+- dev.rom_samples_rdonly = wc->wbuf[0];
+- wc->status = 0;
+- return 0;
+-
+- case WFC_IDENTIFY_SLOT_TYPE:
+- i = wc->wbuf[0] | (wc->wbuf[1] << 7);
+- if (i <0 || i >= WF_MAX_SAMPLE) {
+- printk (KERN_WARNING LOGNAME "invalid slot ID %d\n",
+- i);
+- wc->status = EINVAL;
+- return 0;
+- }
+- wc->rbuf[0] = dev.sample_status[i];
+- wc->status = 0;
+- return 0;
+-
+- case WFC_DEBUG_DRIVER:
+- dev.debug = wc->wbuf[0];
+- printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug);
+- return 0;
+-
+- case WFC_FX_IOCTL:
+- wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]);
+- return 0;
+-
+- case WFC_UPLOAD_PATCH:
+- munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2);
+- memcpy (wc->wbuf, patchnumbuf, 2);
+- break;
+-
+- case WFC_UPLOAD_MULTISAMPLE:
+- /* multisamples have to be handled differently, and
+- cannot be dealt with properly by wavefront_cmd() alone.
+- */
+- wc->status = wavefront_fetch_multisample
+- ((wavefront_patch_info *) wc->rbuf);
+- return 0;
+-
+- case WFC_UPLOAD_SAMPLE_ALIAS:
+- printk (KERN_INFO LOGNAME "support for sample alias upload "
+- "being considered.\n");
+- wc->status = EINVAL;
+- return -EINVAL;
+- }
+-
+- wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf);
+-
+- /* Post-handling of certain commands.
+-
+- In particular, if the command was an upload, demunge the data
+- so that the user-level doesn't have to think about it.
+- */
+-
+- if (wc->status == 0) {
+- switch (wc->cmd) {
+- /* intercept any freemem requests so that we know
+- we are always current with the user-level view
+- of things.
+- */
+-
+- case WFC_REPORT_FREE_MEMORY:
+- dev.freemem = demunge_int32 (wc->rbuf, 4);
+- break;
+-
+- case WFC_UPLOAD_PATCH:
+- demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES);
+- break;
+-
+- case WFC_UPLOAD_PROGRAM:
+- demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES);
+- break;
+-
+- case WFC_UPLOAD_EDRUM_PROGRAM:
+- demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1);
+- break;
+-
+- case WFC_UPLOAD_SAMPLE_HEADER:
+- process_sample_hdr (wc->rbuf);
+- break;
+-
+- case WFC_UPLOAD_SAMPLE_ALIAS:
+- printk (KERN_INFO LOGNAME "support for "
+- "sample aliases still "
+- "being considered.\n");
+- break;
+-
+- case WFC_VMIDI_OFF:
+- if (virtual_midi_disable () < 0) {
+- return -(EIO);
+- }
+- break;
+-
+- case WFC_VMIDI_ON:
+- if (virtual_midi_enable () < 0) {
+- return -(EIO);
+- }
+- break;
+- }
+- }
+-
+- return 0;
+-}
+-
+-
+-/***********************************************************************/
+-/* WaveFront: Linux file system interface (for access via raw synth) */
+-/***********************************************************************/
+-
+-static int
+-wavefront_open (struct inode *inode, struct file *file)
+-{
+- /* XXX fix me */
+- dev.opened = file->f_flags;
+- return 0;
+-}
+-
+-static int
+-wavefront_release(struct inode *inode, struct file *file)
+-{
+- lock_kernel();
+- dev.opened = 0;
+- dev.debug = 0;
+- unlock_kernel();
+- return 0;
+-}
+-
+-static int
+-wavefront_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- wavefront_control wc;
+- int err;
+-
+- switch (cmd) {
+-
+- case WFCTL_WFCMD:
+- if (copy_from_user(&wc, (void __user *) arg, sizeof (wc)))
+- return -EFAULT;
+-
+- if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+- if (copy_to_user ((void __user *) arg, &wc, sizeof (wc)))
+- return -EFAULT;
+- }
+-
+- return err;
+-
+- case WFCTL_LOAD_SPP:
+- return wavefront_load_patch ((const char __user *) arg);
+-
+- default:
+- printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd);
+- return -(EINVAL);
+-
+- }
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations wavefront_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = wavefront_ioctl,
+- .open = wavefront_open,
+- .release = wavefront_release,
+-};
+-
+-
+-/***********************************************************************/
+-/* WaveFront: OSS installation and support interface */
+-/***********************************************************************/
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+-
+-static struct synth_info wavefront_info =
+-{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT,
+- 0, 32, 0, 0, SYNTH_CAP_INPUT};
+-
+-static int
+-wavefront_oss_open (int devno, int mode)
+-
+-{
+- dev.opened = mode;
+- return 0;
+-}
+-
+-static void
+-wavefront_oss_close (int devno)
+-
+-{
+- dev.opened = 0;
+- dev.debug = 0;
+- return;
+-}
+-
+-static int
+-wavefront_oss_ioctl (int devno, unsigned int cmd, void __user * arg)
+-
+-{
+- wavefront_control wc;
+- int err;
+-
+- switch (cmd) {
+- case SNDCTL_SYNTH_INFO:
+- if(copy_to_user(arg, &wavefront_info, sizeof (wavefront_info)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_SEQ_RESETSAMPLES:
+-// printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
+- return 0; /* don't force an error */
+-
+- case SNDCTL_SEQ_PERCMODE:
+- return 0; /* don't force an error */
+-
+- case SNDCTL_SYNTH_MEMAVL:
+- if ((dev.freemem = wavefront_freemem ()) < 0) {
+- printk (KERN_ERR LOGNAME "cannot get memory size\n");
+- return -EIO;
+- } else {
+- return dev.freemem;
+- }
+- break;
+-
+- case SNDCTL_SYNTH_CONTROL:
+- if(copy_from_user (&wc, arg, sizeof (wc)))
+- err = -EFAULT;
+- else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+- if(copy_to_user (arg, &wc, sizeof (wc)))
+- err = -EFAULT;
+- }
+-
+- return err;
+-
+- default:
+- return -(EINVAL);
+- }
+-}
+-
+-static int
+-wavefront_oss_load_patch (int devno, int format, const char __user *addr,
+- int offs, int count, int pmgr_flag)
+-{
+-
+- if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */
+- if (midi_load_patch == NULL) {
+- printk (KERN_ERR LOGNAME
+- "SYSEX not loadable: "
+- "no midi patch loader!\n");
+- return -(EINVAL);
+- }
+-
+- return midi_load_patch (devno, format, addr,
+- offs, count, pmgr_flag);
+-
+- } else if (format == GUS_PATCH) {
+- return wavefront_load_gus_patch (devno, format,
+- addr, offs, count, pmgr_flag);
+-
+- } else if (format != WAVEFRONT_PATCH) {
+- printk (KERN_ERR LOGNAME "unknown patch format %d\n", format);
+- return -(EINVAL);
+- }
+-
+- if (count < sizeof (wavefront_patch_info)) {
+- printk (KERN_ERR LOGNAME "sample header too short\n");
+- return -(EINVAL);
+- }
+-
+- /* "addr" points to a user-space wavefront_patch_info */
+-
+- return wavefront_load_patch (addr);
+-}
+-
+-static struct synth_operations wavefront_operations =
+-{
+- .owner = THIS_MODULE,
+- .id = "WaveFront",
+- .info = &wavefront_info,
+- .midi_dev = 0,
+- .synth_type = SYNTH_TYPE_SAMPLE,
+- .synth_subtype = SAMPLE_TYPE_WAVEFRONT,
+- .open = wavefront_oss_open,
+- .close = wavefront_oss_close,
+- .ioctl = wavefront_oss_ioctl,
+- .kill_note = midi_synth_kill_note,
+- .start_note = midi_synth_start_note,
+- .set_instr = midi_synth_set_instr,
+- .reset = midi_synth_reset,
+- .load_patch = midi_synth_load_patch,
+- .aftertouch = midi_synth_aftertouch,
+- .controller = midi_synth_controller,
+- .panning = midi_synth_panning,
+- .bender = midi_synth_bender,
+- .setup_voice = midi_synth_setup_voice
+-};
+-#endif /* OSS_SUPPORT_SEQ */
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL
+-
+-static void __init attach_wavefront (struct address_info *hw_config)
+-{
+- (void) install_wavefront ();
+-}
+-
+-static int __init probe_wavefront (struct address_info *hw_config)
+-{
+- return !detect_wavefront (hw_config->irq, hw_config->io_base);
+-}
+-
+-static void __exit unload_wavefront (struct address_info *hw_config)
+-{
+- (void) uninstall_wavefront ();
+-}
+-
+-#endif /* OSS_SUPPORT_STATIC_INSTALL */
+-
+-/***********************************************************************/
+-/* WaveFront: Linux modular sound kernel installation interface */
+-/***********************************************************************/
+-
+-static irqreturn_t
+-wavefrontintr(int irq, void *dev_id, struct pt_regs *dummy)
+-{
+- struct wf_config *hw = dev_id;
+-
+- /*
+- Some comments on interrupts. I attempted a version of this
+- driver that used interrupts throughout the code instead of
+- doing busy and/or sleep-waiting. Alas, it appears that once
+- the Motorola firmware is downloaded, the card *never*
+- generates an RX interrupt. These are successfully generated
+- during firmware loading, and after that wavefront_status()
+- reports that an interrupt is pending on the card from time
+- to time, but it never seems to be delivered to this
+- driver. Note also that wavefront_status() continues to
+- report that RX interrupts are enabled, suggesting that I
+- didn't goof up and disable them by mistake.
+-
+- Thus, I stepped back to a prior version of
+- wavefront_wait(), the only place where this really
+- matters. Its sad, but I've looked through the code to check
+- on things, and I really feel certain that the Motorola
+- firmware prevents RX-ready interrupts.
+- */
+-
+- if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) {
+- return IRQ_NONE;
+- }
+-
+- hw->irq_ok = 1;
+- hw->irq_cnt++;
+- wake_up_interruptible (&hw->interrupt_sleeper);
+- return IRQ_HANDLED;
+-}
+-
+-/* STATUS REGISTER
+-
+-0 Host Rx Interrupt Enable (1=Enabled)
+-1 Host Rx Register Full (1=Full)
+-2 Host Rx Interrupt Pending (1=Interrupt)
+-3 Unused
+-4 Host Tx Interrupt (1=Enabled)
+-5 Host Tx Register empty (1=Empty)
+-6 Host Tx Interrupt Pending (1=Interrupt)
+-7 Unused
+-*/
+-
+-static int
+-wavefront_interrupt_bits (int irq)
+-
+-{
+- int bits;
+-
+- switch (irq) {
+- case 9:
+- bits = 0x00;
+- break;
+- case 5:
+- bits = 0x08;
+- break;
+- case 12:
+- bits = 0x10;
+- break;
+- case 15:
+- bits = 0x18;
+- break;
+-
+- default:
+- printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq);
+- bits = -1;
+- }
+-
+- return bits;
+-}
+-
+-static void
+-wavefront_should_cause_interrupt (int val, int port, int timeout)
+-
+-{
+- unsigned long flags;
+-
+- /* this will not help on SMP - but at least it compiles */
+- spin_lock_irqsave(&lock, flags);
+- dev.irq_ok = 0;
+- outb (val,port);
+- interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout);
+- spin_unlock_irqrestore(&lock,flags);
+-}
+-
+-static int __init wavefront_hw_reset (void)
+-{
+- int bits;
+- int hwv[2];
+- unsigned long irq_mask;
+- short reported_irq;
+-
+- /* IRQ already checked in init_module() */
+-
+- bits = wavefront_interrupt_bits (dev.irq);
+-
+- printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n");
+-
+- irq_mask = probe_irq_on ();
+-
+- outb (0x0, dev.control_port);
+- outb (0x80 | 0x40 | bits, dev.data_port);
+- wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
+- dev.control_port,
+- (reset_time*HZ)/100);
+-
+- reported_irq = probe_irq_off (irq_mask);
+-
+- if (reported_irq != dev.irq) {
+- if (reported_irq == 0) {
+- printk (KERN_ERR LOGNAME
+- "No unassigned interrupts detected "
+- "after h/w reset\n");
+- } else if (reported_irq < 0) {
+- printk (KERN_ERR LOGNAME
+- "Multiple unassigned interrupts detected "
+- "after h/w reset\n");
+- } else {
+- printk (KERN_ERR LOGNAME "autodetected IRQ %d not the "
+- "value provided (%d)\n", reported_irq,
+- dev.irq);
+- }
+- dev.irq = -1;
+- return 1;
+- } else {
+- printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n",
+- reported_irq);
+- }
+-
+- if (request_irq (dev.irq, wavefrontintr,
+- IRQF_DISABLED|IRQF_SHARED,
+- "wavefront synth", &dev) < 0) {
+- printk (KERN_WARNING LOGNAME "IRQ %d not available!\n",
+- dev.irq);
+- return 1;
+- }
+-
+- /* try reset of port */
+-
+- outb (0x0, dev.control_port);
+-
+- /* At this point, the board is in reset, and the H/W initialization
+- register is accessed at the same address as the data port.
+-
+- Bit 7 - Enable IRQ Driver
+- 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs
+- 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus.
+-
+- Bit 6 - MIDI Interface Select
+-
+- 0 - Use the MIDI Input from the 26-pin WaveBlaster
+- compatible header as the serial MIDI source
+- 1 - Use the MIDI Input from the 9-pin D connector as the
+- serial MIDI source.
+-
+- Bits 5:3 - IRQ Selection
+- 0 0 0 - IRQ 2/9
+- 0 0 1 - IRQ 5
+- 0 1 0 - IRQ 12
+- 0 1 1 - IRQ 15
+- 1 0 0 - Reserved
+- 1 0 1 - Reserved
+- 1 1 0 - Reserved
+- 1 1 1 - Reserved
+-
+- Bits 2:1 - Reserved
+- Bit 0 - Disable Boot ROM
+- 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM
+- 1 - memory accesses to 03FC30-03FFFFH are directed to external
+- storage.
+-
+- */
+-
+- /* configure hardware: IRQ, enable interrupts,
+- plus external 9-pin MIDI interface selected
+- */
+-
+- outb (0x80 | 0x40 | bits, dev.data_port);
+-
+- /* CONTROL REGISTER
+-
+- 0 Host Rx Interrupt Enable (1=Enabled) 0x1
+- 1 Unused 0x2
+- 2 Unused 0x4
+- 3 Unused 0x8
+- 4 Host Tx Interrupt Enable 0x10
+- 5 Mute (0=Mute; 1=Play) 0x20
+- 6 Master Interrupt Enable (1=Enabled) 0x40
+- 7 Master Reset (0=Reset; 1=Run) 0x80
+-
+- Take us out of reset, mute output, master + TX + RX interrupts on.
+-
+- We'll get an interrupt presumably to tell us that the TX
+- register is clear.
+- */
+-
+- wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
+- dev.control_port,
+- (reset_time*HZ)/100);
+-
+- /* Note: data port is now the data port, not the h/w initialization
+- port.
+- */
+-
+- if (!dev.irq_ok) {
+- printk (KERN_WARNING LOGNAME
+- "intr not received after h/w un-reset.\n");
+- goto gone_bad;
+- }
+-
+- dev.interrupts_on = 1;
+-
+- /* Note: data port is now the data port, not the h/w initialization
+- port.
+-
+- At this point, only "HW VERSION" or "DOWNLOAD OS" commands
+- will work. So, issue one of them, and wait for TX
+- interrupt. This can take a *long* time after a cold boot,
+- while the ISC ROM does its RAM test. The SDK says up to 4
+- seconds - with 12MB of RAM on a Tropez+, it takes a lot
+- longer than that (~16secs). Note that the card understands
+- the difference between a warm and a cold boot, so
+- subsequent ISC2115 reboots (say, caused by module
+- reloading) will get through this much faster.
+-
+- XXX Interesting question: why is no RX interrupt received first ?
+- */
+-
+- wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION,
+- dev.data_port, ramcheck_time*HZ);
+-
+- if (!dev.irq_ok) {
+- printk (KERN_WARNING LOGNAME
+- "post-RAM-check interrupt not received.\n");
+- goto gone_bad;
+- }
+-
+- if (!wavefront_wait (STAT_CAN_READ)) {
+- printk (KERN_WARNING LOGNAME
+- "no response to HW version cmd.\n");
+- goto gone_bad;
+- }
+-
+- if ((hwv[0] = wavefront_read ()) == -1) {
+- printk (KERN_WARNING LOGNAME
+- "board not responding correctly.\n");
+- goto gone_bad;
+- }
+-
+- if (hwv[0] == 0xFF) { /* NAK */
+-
+- /* Board's RAM test failed. Try to read error code,
+- and tell us about it either way.
+- */
+-
+- if ((hwv[0] = wavefront_read ()) == -1) {
+- printk (KERN_WARNING LOGNAME "on-board RAM test failed "
+- "(bad error code).\n");
+- } else {
+- printk (KERN_WARNING LOGNAME "on-board RAM test failed "
+- "(error code: 0x%x).\n",
+- hwv[0]);
+- }
+- goto gone_bad;
+- }
+-
+- /* We're OK, just get the next byte of the HW version response */
+-
+- if ((hwv[1] = wavefront_read ()) == -1) {
+- printk (KERN_WARNING LOGNAME "incorrect h/w response.\n");
+- goto gone_bad;
+- }
+-
+- printk (KERN_INFO LOGNAME "hardware version %d.%d\n",
+- hwv[0], hwv[1]);
+-
+- return 0;
+-
+-
+- gone_bad:
+- if (dev.irq >= 0) {
+- free_irq (dev.irq, &dev);
+- dev.irq = -1;
+- }
+- return (1);
+-}
+-
+-static int __init detect_wavefront (int irq, int io_base)
+-{
+- unsigned char rbuf[4], wbuf[4];
+-
+- /* TB docs say the device takes up 8 ports, but we know that
+- if there is an FX device present (i.e. a Tropez+) it really
+- consumes 16.
+- */
+-
+- if (!request_region (io_base, 16, "wavfront")) {
+- printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x "
+- "already in use - ignored\n", dev.base,
+- dev.base+15);
+- return -1;
+- }
+-
+- dev.irq = irq;
+- dev.base = io_base;
+- dev.israw = 0;
+- dev.debug = debug_default;
+- dev.interrupts_on = 0;
+- dev.irq_cnt = 0;
+- dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */
+-
+- if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {
+-
+- dev.fw_version[0] = rbuf[0];
+- dev.fw_version[1] = rbuf[1];
+- printk (KERN_INFO LOGNAME
+- "firmware %d.%d already loaded.\n",
+- rbuf[0], rbuf[1]);
+-
+- /* check that a command actually works */
+-
+- if (wavefront_cmd (WFC_HARDWARE_VERSION,
+- rbuf, wbuf) == 0) {
+- dev.hw_version[0] = rbuf[0];
+- dev.hw_version[1] = rbuf[1];
+- } else {
+- printk (KERN_WARNING LOGNAME "not raw, but no "
+- "hardware version!\n");
+- release_region (io_base, 16);
+- return 0;
+- }
+-
+- if (!wf_raw) {
+- /* will re-acquire region in install_wavefront() */
+- release_region (io_base, 16);
+- return 1;
+- } else {
+- printk (KERN_INFO LOGNAME
+- "reloading firmware anyway.\n");
+- dev.israw = 1;
+- }
+-
+- } else {
+-
+- dev.israw = 1;
+- printk (KERN_INFO LOGNAME
+- "no response to firmware probe, assume raw.\n");
+-
+- }
+-
+- init_waitqueue_head (&dev.interrupt_sleeper);
+-
+- if (wavefront_hw_reset ()) {
+- printk (KERN_WARNING LOGNAME "hardware reset failed\n");
+- release_region (io_base, 16);
+- return 0;
+- }
+-
+- /* Check for FX device, present only on Tropez+ */
+-
+- dev.has_fx = (detect_wffx () == 0);
+-
+- /* will re-acquire region in install_wavefront() */
+- release_region (io_base, 16);
+- return 1;
+-}
+-
+-#include "os.h"
+-#include <linux/fs.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <asm/uaccess.h>
+-
+-
+-static int
+-wavefront_download_firmware (char *path)
+-
+-{
+- unsigned char section[WF_SECTION_MAX];
+- char section_length; /* yes, just a char; max value is WF_SECTION_MAX */
+- int section_cnt_downloaded = 0;
+- int fd;
+- int c;
+- int i;
+- mm_segment_t fs;
+-
+- /* This tries to be a bit cleverer than the stuff Alan Cox did for
+- the generic sound firmware, in that it actually knows
+- something about the structure of the Motorola firmware. In
+- particular, it uses a version that has been stripped of the
+- 20K of useless header information, and had section lengths
+- added, making it possible to load the entire OS without any
+- [kv]malloc() activity, since the longest entity we ever read is
+- 42 bytes (well, WF_SECTION_MAX) long.
+- */
+-
+- fs = get_fs();
+- set_fs (get_ds());
+-
+- if ((fd = sys_open (path, 0, 0)) < 0) {
+- printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",
+- path);
+- return 1;
+- }
+-
+- while (1) {
+- int x;
+-
+- if ((x = sys_read (fd, §ion_length, sizeof (section_length))) !=
+- sizeof (section_length)) {
+- printk (KERN_ERR LOGNAME "firmware read error.\n");
+- goto failure;
+- }
+-
+- if (section_length == 0) {
+- break;
+- }
+-
+- if (sys_read (fd, section, section_length) != section_length) {
+- printk (KERN_ERR LOGNAME "firmware section "
+- "read error.\n");
+- goto failure;
+- }
+-
+- /* Send command */
+-
+- if (wavefront_write (WFC_DOWNLOAD_OS)) {
+- goto failure;
+- }
+-
+- for (i = 0; i < section_length; i++) {
+- if (wavefront_write (section[i])) {
+- goto failure;
+- }
+- }
+-
+- /* get ACK */
+-
+- if (wavefront_wait (STAT_CAN_READ)) {
+-
+- if ((c = inb (dev.data_port)) != WF_ACK) {
+-
+- printk (KERN_ERR LOGNAME "download "
+- "of section #%d not "
+- "acknowledged, ack = 0x%x\n",
+- section_cnt_downloaded + 1, c);
+- goto failure;
+-
+- }
+-
+- } else {
+- printk (KERN_ERR LOGNAME "time out for firmware ACK.\n");
+- goto failure;
+- }
+-
+- }
+-
+- sys_close (fd);
+- set_fs (fs);
+- return 0;
+-
+- failure:
+- sys_close (fd);
+- set_fs (fs);
+- printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n");
+- return 1;
+-}
+-
+-static int __init wavefront_config_midi (void)
+-{
+- unsigned char rbuf[4], wbuf[4];
+-
+- if (detect_wf_mpu (dev.irq, dev.base) < 0) {
+- printk (KERN_WARNING LOGNAME
+- "could not find working MIDI device\n");
+- return -1;
+- }
+-
+- if ((dev.mididev = install_wf_mpu ()) < 0) {
+- printk (KERN_WARNING LOGNAME
+- "MIDI interfaces not configured\n");
+- return -1;
+- }
+-
+- /* Route external MIDI to WaveFront synth (by default) */
+-
+- if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) {
+- printk (KERN_WARNING LOGNAME
+- "cannot enable MIDI-IN to synth routing.\n");
+- /* XXX error ? */
+- }
+-
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+- /* Get the regular MIDI patch loading function, so we can
+- use it if we ever get handed a SYSEX patch. This is
+- unlikely, because its so damn slow, but we may as well
+- leave this functionality from maui.c behind, since it
+- could be useful for sequencer applications that can
+- only use MIDI to do patch loading.
+- */
+-
+- if (midi_devs[dev.mididev]->converter != NULL) {
+- midi_load_patch = midi_devs[dev.mididev]->converter->load_patch;
+- midi_devs[dev.mididev]->converter->load_patch =
+- &wavefront_oss_load_patch;
+- }
+-
+-#endif /* OSS_SUPPORT_SEQ */
+-
+- /* Turn on Virtual MIDI, but first *always* turn it off,
+- since otherwise consectutive reloads of the driver will
+- never cause the hardware to generate the initial "internal" or
+- "external" source bytes in the MIDI data stream. This
+- is pretty important, since the internal hardware generally will
+- be used to generate none or very little MIDI output, and
+- thus the only source of MIDI data is actually external. Without
+- the switch bytes, the driver will think it all comes from
+- the internal interface. Duh.
+- */
+-
+- if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) {
+- printk (KERN_WARNING LOGNAME
+- "virtual MIDI mode not disabled\n");
+- return 0; /* We're OK, but missing the external MIDI dev */
+- }
+-
+- if ((dev.ext_mididev = virtual_midi_enable ()) < 0) {
+- printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n");
+- } else {
+- if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) {
+- printk (KERN_WARNING LOGNAME
+- "cannot enable virtual MIDI mode.\n");
+- virtual_midi_disable ();
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int __init wavefront_do_reset (int atboot)
+-{
+- char voices[1];
+-
+- if (!atboot && wavefront_hw_reset ()) {
+- printk (KERN_WARNING LOGNAME "hw reset failed.\n");
+- goto gone_bad;
+- }
+-
+- if (dev.israw) {
+- if (wavefront_download_firmware (ospath)) {
+- goto gone_bad;
+- }
+-
+- dev.israw = 0;
+-
+- /* Wait for the OS to get running. The protocol for
+- this is non-obvious, and was determined by
+- using port-IO tracing in DOSemu and some
+- experimentation here.
+-
+- Rather than using timed waits, use interrupts creatively.
+- */
+-
+- wavefront_should_cause_interrupt (WFC_NOOP,
+- dev.data_port,
+- (osrun_time*HZ));
+-
+- if (!dev.irq_ok) {
+- printk (KERN_WARNING LOGNAME
+- "no post-OS interrupt.\n");
+- goto gone_bad;
+- }
+-
+- /* Now, do it again ! */
+-
+- wavefront_should_cause_interrupt (WFC_NOOP,
+- dev.data_port, (10*HZ));
+-
+- if (!dev.irq_ok) {
+- printk (KERN_WARNING LOGNAME
+- "no post-OS interrupt(2).\n");
+- goto gone_bad;
+- }
+-
+- /* OK, no (RX/TX) interrupts any more, but leave mute
+- in effect.
+- */
+-
+- outb (0x80|0x40, dev.control_port);
+-
+- /* No need for the IRQ anymore */
+-
+- free_irq (dev.irq, &dev);
+-
+- }
+-
+- if (dev.has_fx && fx_raw) {
+- wffx_init ();
+- }
+-
+- /* SETUPSND.EXE asks for sample memory config here, but since i
+- have no idea how to interpret the result, we'll forget
+- about it.
+- */
+-
+- if ((dev.freemem = wavefront_freemem ()) < 0) {
+- goto gone_bad;
+- }
+-
+- printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024);
+-
+- if (wavefront_write (0xf0) ||
+- wavefront_write (1) ||
+- (wavefront_read () < 0)) {
+- dev.debug = 0;
+- printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n");
+- goto gone_bad;
+- }
+-
+- voices[0] = 32;
+-
+- if (wavefront_cmd (WFC_SET_NVOICES, NULL, voices)) {
+- printk (KERN_WARNING LOGNAME
+- "cannot set number of voices to 32.\n");
+- goto gone_bad;
+- }
+-
+-
+- return 0;
+-
+- gone_bad:
+- /* reset that sucker so that it doesn't bother us. */
+-
+- outb (0x0, dev.control_port);
+- dev.interrupts_on = 0;
+- if (dev.irq >= 0) {
+- free_irq (dev.irq, &dev);
+- }
+- return 1;
+-}
+-
+-static int __init wavefront_init (int atboot)
+-{
+- int samples_are_from_rom;
+-
+- if (dev.israw) {
+- samples_are_from_rom = 1;
+- } else {
+- /* XXX is this always true ? */
+- samples_are_from_rom = 0;
+- }
+-
+- if (dev.israw || fx_raw) {
+- if (wavefront_do_reset (atboot)) {
+- return -1;
+- }
+- }
+-
+- wavefront_get_sample_status (samples_are_from_rom);
+- wavefront_get_program_status ();
+- wavefront_get_patch_status ();
+-
+- /* Start normal operation: unreset, master interrupt enabled, no mute
+- */
+-
+- outb (0x80|0x40|0x20, dev.control_port);
+-
+- return (0);
+-}
+-
+-static int __init install_wavefront (void)
+-{
+- if (!request_region (dev.base+2, 6, "wavefront synth"))
+- return -1;
+-
+- if (dev.has_fx) {
+- if (!request_region (dev.base+8, 8, "wavefront fx")) {
+- release_region (dev.base+2, 6);
+- return -1;
+- }
+- }
+-
+- if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
+- printk (KERN_ERR LOGNAME "cannot register raw synth\n");
+- goto err_out;
+- }
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+- if ((dev.oss_dev = sound_alloc_synthdev()) == -1) {
+- printk (KERN_ERR LOGNAME "Too many sequencers\n");
+- /* FIXME: leak: should unregister sound synth */
+- goto err_out;
+- } else {
+- synth_devs[dev.oss_dev] = &wavefront_operations;
+- }
+-#endif /* OSS_SUPPORT_SEQ */
+-
+- if (wavefront_init (1) < 0) {
+- printk (KERN_WARNING LOGNAME "initialization failed.\n");
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+- sound_unload_synthdev (dev.oss_dev);
+-#endif /* OSS_SUPPORT_SEQ */
+-
+- goto err_out;
+- }
+-
+- if (wavefront_config_midi ()) {
+- printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n");
+- }
+-
+- return dev.oss_dev;
+-
+-err_out:
+- release_region (dev.base+2, 6);
+- if (dev.has_fx)
+- release_region (dev.base+8, 8);
+- return -1;
+-}
+-
+-static void __exit uninstall_wavefront (void)
+-{
+- /* the first two i/o addresses are freed by the wf_mpu code */
+- release_region (dev.base+2, 6);
+-
+- if (dev.has_fx) {
+- release_region (dev.base+8, 8);
+- }
+-
+- unregister_sound_synth (dev.synth_dev);
+-
+-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+- sound_unload_synthdev (dev.oss_dev);
+-#endif /* OSS_SUPPORT_SEQ */
+- uninstall_wf_mpu ();
+-}
+-
+-/***********************************************************************/
+-/* WaveFront FX control */
+-/***********************************************************************/
+-
+-#include "yss225.h"
+-
+-/* Control bits for the Load Control Register
+- */
+-
+-#define FX_LSB_TRANSFER 0x01 /* transfer after DSP LSB byte written */
+-#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
+-#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
+-
+-static int
+-wffx_idle (void)
+-
+-{
+- int i;
+- unsigned int x = 0x80;
+-
+- for (i = 0; i < 1000; i++) {
+- x = inb (dev.fx_status);
+- if ((x & 0x80) == 0) {
+- break;
+- }
+- }
+-
+- if (x & 0x80) {
+- printk (KERN_ERR LOGNAME "FX device never idle.\n");
+- return 0;
+- }
+-
+- return (1);
+-}
+-
+-int __init detect_wffx (void)
+-{
+- /* This is a crude check, but its the best one I have for now.
+- Certainly on the Maui and the Tropez, wffx_idle() will
+- report "never idle", which suggests that this test should
+- work OK.
+- */
+-
+- if (inb (dev.fx_status) & 0x80) {
+- printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n");
+- return -1;
+- }
+-
+- return 0;
+-}
+-
+-static void
+-wffx_mute (int onoff)
+-
+-{
+- if (!wffx_idle()) {
+- return;
+- }
+-
+- outb (onoff ? 0x02 : 0x00, dev.fx_op);
+-}
+-
+-static int
+-wffx_memset (int page,
+- int addr, int cnt, unsigned short *data)
+-{
+- if (page < 0 || page > 7) {
+- printk (KERN_ERR LOGNAME "FX memset: "
+- "page must be >= 0 and <= 7\n");
+- return -(EINVAL);
+- }
+-
+- if (addr < 0 || addr > 0x7f) {
+- printk (KERN_ERR LOGNAME "FX memset: "
+- "addr must be >= 0 and <= 7f\n");
+- return -(EINVAL);
+- }
+-
+- if (cnt == 1) {
+-
+- outb (FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (page, dev.fx_dsp_page);
+- outb (addr, dev.fx_dsp_addr);
+- outb ((data[0] >> 8), dev.fx_dsp_msb);
+- outb ((data[0] & 0xff), dev.fx_dsp_lsb);
+-
+- printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n",
+- page, addr, data[0]);
+-
+- } else {
+- int i;
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (page, dev.fx_dsp_page);
+- outb (addr, dev.fx_dsp_addr);
+-
+- for (i = 0; i < cnt; i++) {
+- outb ((data[i] >> 8), dev.fx_dsp_msb);
+- outb ((data[i] & 0xff), dev.fx_dsp_lsb);
+- if (!wffx_idle ()) {
+- break;
+- }
+- }
+-
+- if (i != cnt) {
+- printk (KERN_WARNING LOGNAME
+- "FX memset "
+- "(0x%x, 0x%x, %p, %d) incomplete\n",
+- page, addr, data, cnt);
+- return -(EIO);
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int
+-wffx_ioctl (wavefront_fx_info *r)
+-
+-{
+- unsigned short page_data[256];
+- unsigned short *pd;
+-
+- switch (r->request) {
+- case WFFX_MUTE:
+- wffx_mute (r->data[0]);
+- return 0;
+-
+- case WFFX_MEMSET:
+-
+- if (r->data[2] <= 0) {
+- printk (KERN_ERR LOGNAME "cannot write "
+- "<= 0 bytes to FX\n");
+- return -(EINVAL);
+- } else if (r->data[2] == 1) {
+- pd = (unsigned short *) &r->data[3];
+- } else {
+- if (r->data[2] > sizeof (page_data)) {
+- printk (KERN_ERR LOGNAME "cannot write "
+- "> 255 bytes to FX\n");
+- return -(EINVAL);
+- }
+- if (copy_from_user(page_data,
+- (unsigned char __user *)r->data[3],
+- r->data[2]))
+- return -EFAULT;
+- pd = page_data;
+- }
+-
+- return wffx_memset (r->data[0], /* page */
+- r->data[1], /* addr */
+- r->data[2], /* cnt */
+- pd);
+-
+- default:
+- printk (KERN_WARNING LOGNAME
+- "FX: ioctl %d not yet supported\n",
+- r->request);
+- return -(EINVAL);
+- }
+-}
+-
+-/* YSS225 initialization.
+-
+- This code was developed using DOSEMU. The Turtle Beach SETUPSND
+- utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
+- of the port I/O done, using the Yamaha faxback document as a guide
+- to add more logic to the code. Its really pretty weird.
+-
+- There was an alternative approach of just dumping the whole I/O
+- sequence as a series of port/value pairs and a simple loop
+- that output it. However, I hope that eventually I'll get more
+- control over what this code does, and so I tried to stick with
+- a somewhat "algorithmic" approach.
+-*/
+-
+-static int __init wffx_init (void)
+-{
+- int i;
+- int j;
+-
+- /* Set all bits for all channels on the MOD unit to zero */
+- /* XXX But why do this twice ? */
+-
+- for (j = 0; j < 2; j++) {
+- for (i = 0x10; i <= 0xff; i++) {
+-
+- if (!wffx_idle ()) {
+- return (-1);
+- }
+-
+- outb (i, dev.fx_mod_addr);
+- outb (0x0, dev.fx_mod_data);
+- }
+- }
+-
+- if (!wffx_idle()) return (-1);
+- outb (0x02, dev.fx_op); /* mute on */
+-
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x44, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x42, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x43, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x7c, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x7e, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x46, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x49, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x47, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x4a, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+-
+- /* either because of stupidity by TB's programmers, or because it
+- actually does something, rezero the MOD page.
+- */
+- for (i = 0x10; i <= 0xff; i++) {
+-
+- if (!wffx_idle ()) {
+- return (-1);
+- }
+-
+- outb (i, dev.fx_mod_addr);
+- outb (0x0, dev.fx_mod_data);
+- }
+- /* load page zero */
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x00, dev.fx_dsp_page);
+- outb (0x00, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_zero); i += 2) {
+- outb (page_zero[i], dev.fx_dsp_msb);
+- outb (page_zero[i+1], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- /* Now load page one */
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x01, dev.fx_dsp_page);
+- outb (0x00, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_one); i += 2) {
+- outb (page_one[i], dev.fx_dsp_msb);
+- outb (page_one[i+1], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x02, dev.fx_dsp_page);
+- outb (0x00, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_two); i++) {
+- outb (page_two[i], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x03, dev.fx_dsp_page);
+- outb (0x00, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_three); i++) {
+- outb (page_three[i], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x04, dev.fx_dsp_page);
+- outb (0x00, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_four); i++) {
+- outb (page_four[i], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- /* Load memory area (page six) */
+-
+- outb (FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x06, dev.fx_dsp_page);
+-
+- for (i = 0; i < sizeof (page_six); i += 3) {
+- outb (page_six[i], dev.fx_dsp_addr);
+- outb (page_six[i+1], dev.fx_dsp_msb);
+- outb (page_six[i+2], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x00, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_seven); i += 2) {
+- outb (page_seven[i], dev.fx_dsp_msb);
+- outb (page_seven[i+1], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- /* Now setup the MOD area. We do this algorithmically in order to
+- save a little data space. It could be done in the same fashion
+- as the "pages".
+- */
+-
+- for (i = 0x00; i <= 0x0f; i++) {
+- outb (0x01, dev.fx_mod_addr);
+- outb (i, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- outb (0x02, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0xb0; i <= 0xbf; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x20, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0xf0; i <= 0xff; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x20, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0x10; i <= 0x1d; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0xff, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0x1e, dev.fx_mod_addr);
+- outb (0x40, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- for (i = 0x1f; i <= 0x2d; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0xff, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0x2e, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- for (i = 0x2f; i <= 0x3e; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0x3f, dev.fx_mod_addr);
+- outb (0x20, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- for (i = 0x40; i <= 0x4d; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0x4e, dev.fx_mod_addr);
+- outb (0x0e, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- outb (0x4f, dev.fx_mod_addr);
+- outb (0x0e, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+-
+- for (i = 0x50; i <= 0x6b; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0x6c, dev.fx_mod_addr);
+- outb (0x40, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- outb (0x6d, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- outb (0x6e, dev.fx_mod_addr);
+- outb (0x40, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- outb (0x6f, dev.fx_mod_addr);
+- outb (0x40, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- for (i = 0x70; i <= 0x7f; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0xc0, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0x80; i <= 0xaf; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0xc0; i <= 0xdd; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0xde, dev.fx_mod_addr);
+- outb (0x10, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- outb (0xdf, dev.fx_mod_addr);
+- outb (0x10, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+-
+- for (i = 0xe0; i <= 0xef; i++) {
+- outb (i, dev.fx_mod_addr);
+- outb (0x00, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0x00; i <= 0x0f; i++) {
+- outb (0x01, dev.fx_mod_addr);
+- outb (i, dev.fx_mod_data);
+- outb (0x02, dev.fx_mod_addr);
+- outb (0x01, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (0x02, dev.fx_op); /* mute on */
+-
+- /* Now set the coefficients and so forth for the programs above */
+-
+- for (i = 0; i < sizeof (coefficients); i += 4) {
+- outb (coefficients[i], dev.fx_dsp_page);
+- outb (coefficients[i+1], dev.fx_dsp_addr);
+- outb (coefficients[i+2], dev.fx_dsp_msb);
+- outb (coefficients[i+3], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- /* Some settings (?) that are too small to bundle into loops */
+-
+- if (!wffx_idle()) return (-1);
+- outb (0x1e, dev.fx_mod_addr);
+- outb (0x14, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- outb (0xde, dev.fx_mod_addr);
+- outb (0x20, dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- outb (0xdf, dev.fx_mod_addr);
+- outb (0x20, dev.fx_mod_data);
+-
+- /* some more coefficients */
+-
+- if (!wffx_idle()) return (-1);
+- outb (0x06, dev.fx_dsp_page);
+- outb (0x78, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x40, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x03, dev.fx_dsp_addr);
+- outb (0x0f, dev.fx_dsp_msb);
+- outb (0xff, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x0b, dev.fx_dsp_addr);
+- outb (0x0f, dev.fx_dsp_msb);
+- outb (0xff, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x02, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x0a, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x46, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x49, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+-
+- /* Now, for some strange reason, lets reload every page
+- and all the coefficients over again. I have *NO* idea
+- why this is done. I do know that no sound is produced
+- is this phase is omitted.
+- */
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x00, dev.fx_dsp_page);
+- outb (0x10, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_zero_v2); i += 2) {
+- outb (page_zero_v2[i], dev.fx_dsp_msb);
+- outb (page_zero_v2[i+1], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x01, dev.fx_dsp_page);
+- outb (0x10, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_one_v2); i += 2) {
+- outb (page_one_v2[i], dev.fx_dsp_msb);
+- outb (page_one_v2[i+1], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- if (!wffx_idle()) return (-1);
+- if (!wffx_idle()) return (-1);
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x02, dev.fx_dsp_page);
+- outb (0x10, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_two_v2); i++) {
+- outb (page_two_v2[i], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x03, dev.fx_dsp_page);
+- outb (0x10, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_three_v2); i++) {
+- outb (page_three_v2[i], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x04, dev.fx_dsp_page);
+- outb (0x10, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_four_v2); i++) {
+- outb (page_four_v2[i], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x06, dev.fx_dsp_page);
+-
+- /* Page six v.2 is algorithmic */
+-
+- for (i = 0x10; i <= 0x3e; i += 2) {
+- outb (i, dev.fx_dsp_addr);
+- outb (0x00, dev.fx_dsp_msb);
+- outb (0x00, dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+- outb (0x07, dev.fx_dsp_page);
+- outb (0x10, dev.fx_dsp_addr);
+-
+- for (i = 0; i < sizeof (page_seven_v2); i += 2) {
+- outb (page_seven_v2[i], dev.fx_dsp_msb);
+- outb (page_seven_v2[i+1], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0x00; i < sizeof(mod_v2); i += 2) {
+- outb (mod_v2[i], dev.fx_mod_addr);
+- outb (mod_v2[i+1], dev.fx_mod_data);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0; i < sizeof (coefficients2); i += 4) {
+- outb (coefficients2[i], dev.fx_dsp_page);
+- outb (coefficients2[i+1], dev.fx_dsp_addr);
+- outb (coefficients2[i+2], dev.fx_dsp_msb);
+- outb (coefficients2[i+3], dev.fx_dsp_lsb);
+- if (!wffx_idle()) return (-1);
+- }
+-
+- for (i = 0; i < sizeof (coefficients3); i += 2) {
+- int x;
+-
+- outb (0x07, dev.fx_dsp_page);
+- x = (i % 4) ? 0x4e : 0x4c;
+- outb (x, dev.fx_dsp_addr);
+- outb (coefficients3[i], dev.fx_dsp_msb);
+- outb (coefficients3[i+1], dev.fx_dsp_lsb);
+- }
+-
+- outb (0x00, dev.fx_op); /* mute off */
+- if (!wffx_idle()) return (-1);
+-
+- return (0);
+-}
+-
+-static int io = -1;
+-static int irq = -1;
+-
+-MODULE_AUTHOR ("Paul Barton-Davis <pbd at op.net>");
+-MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver");
+-MODULE_LICENSE("GPL");
+-module_param (io, int, 0);
+-module_param (irq, int, 0);
+-
+-static int __init init_wavfront (void)
+-{
+- printk ("Turtle Beach WaveFront Driver\n"
+- "Copyright (C) by Hannu Solvainen, "
+- "Paul Barton-Davis 1993-1998.\n");
+-
+- /* XXX t'would be lovely to ask the CS4232 for these values, eh ? */
+-
+- if (io == -1 || irq == -1) {
+- printk (KERN_INFO LOGNAME "irq and io options must be set.\n");
+- return -EINVAL;
+- }
+-
+- if (wavefront_interrupt_bits (irq) < 0) {
+- printk (KERN_INFO LOGNAME
+- "IRQ must be 9, 5, 12 or 15 (not %d)\n", irq);
+- return -ENODEV;
+- }
+-
+- if (detect_wavefront (irq, io) < 0) {
+- return -ENODEV;
+- }
+-
+- if (install_wavefront () < 0) {
+- return -EIO;
+- }
+-
+- return 0;
+-}
+-
+-static void __exit cleanup_wavfront (void)
+-{
+- uninstall_wavefront ();
+-}
+-
+-module_init(init_wavfront);
+-module_exit(cleanup_wavfront);
+diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c
+deleted file mode 100644
+index 3f3a390..0000000
+--- a/sound/oss/wf_midi.c
++++ /dev/null
+@@ -1,880 +0,0 @@
+-/*
+- * sound/wf_midi.c
+- *
+- * The low level driver for the WaveFront ICS2115 MIDI interface(s)
+- * Note that there is also an MPU-401 emulation (actually, a UART-401
+- * emulation) on the CS4232 on the Tropez Plus. This code has nothing
+- * to do with that interface at all.
+- *
+- * The interface is essentially just a UART-401, but is has the
+- * interesting property of supporting what Turtle Beach called
+- * "Virtual MIDI" mode. In this mode, there are effectively *two*
+- * MIDI buses accessible via the interface, one that is routed
+- * solely to/from the external WaveFront synthesizer and the other
+- * corresponding to the pin/socket connector used to link external
+- * MIDI devices to the board.
+- *
+- * This driver fully supports this mode, allowing two distinct
+- * midi devices (/dev/midiNN and /dev/midiNN+1) to be used
+- * completely independently, giving 32 channels of MIDI routing,
+- * 16 to the WaveFront synth and 16 to the external MIDI bus.
+- *
+- * Switching between the two is accomplished externally by the driver
+- * using the two otherwise unused MIDI bytes. See the code for more details.
+- *
+- * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c)
+- *
+- * The main reason to turn off Virtual MIDI mode is when you want to
+- * tightly couple the WaveFront synth with an external MIDI
+- * device. You won't be able to distinguish the source of any MIDI
+- * data except via SysEx ID, but thats probably OK, since for the most
+- * part, the WaveFront won't be sending any MIDI data at all.
+- *
+- * The main reason to turn on Virtual MIDI Mode is to provide two
+- * completely independent 16-channel MIDI buses, one to the
+- * WaveFront and one to any external MIDI devices. Given the 32
+- * voice nature of the WaveFront, its pretty easy to find a use
+- * for all 16 channels driving just that synth.
+- *
+- */
+-
+-/*
+- * Copyright (C) by Paul Barton-Davis 1998
+- * Some portions of this file are derived from work that is:
+- *
+- * CopyriGht (C) by Hannu Savolainen 1993-1996
+- *
+- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+- * Version 2 (June 1991). See the "COPYING" file distributed with this software
+- * for more info.
+- */
+-
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/spinlock.h>
+-#include "sound_config.h"
+-
+-#include <linux/wavefront.h>
+-
+-#ifdef MODULE
+-
+-struct wf_mpu_config {
+- int base;
+-#define DATAPORT(d) (d)->base
+-#define COMDPORT(d) (d)->base+1
+-#define STATPORT(d) (d)->base+1
+-
+- int irq;
+- int opened;
+- int devno;
+- int synthno;
+- int mode;
+-#define MODE_MIDI 1
+-#define MODE_SYNTH 2
+-
+- void (*inputintr) (int dev, unsigned char data);
+- char isvirtual; /* do virtual I/O stuff */
+-};
+-
+-static struct wf_mpu_config devs[2];
+-static struct wf_mpu_config *phys_dev = &devs[0];
+-static struct wf_mpu_config *virt_dev = &devs[1];
+-
+-static void start_uart_mode (void);
+-static DEFINE_SPINLOCK(lock);
+-
+-#define OUTPUT_READY 0x40
+-#define INPUT_AVAIL 0x80
+-#define MPU_ACK 0xFE
+-#define UART_MODE_ON 0x3F
+-
+-static inline int wf_mpu_status (void)
+-{
+- return inb (STATPORT (phys_dev));
+-}
+-
+-static inline int input_avail (void)
+-{
+- return !(wf_mpu_status() & INPUT_AVAIL);
+-}
+-
+-static inline int output_ready (void)
+-{
+- return !(wf_mpu_status() & OUTPUT_READY);
+-}
+-
+-static inline int read_data (void)
+-{
+- return inb (DATAPORT (phys_dev));
+-}
+-
+-static inline void write_data (unsigned char byte)
+-{
+- outb (byte, DATAPORT (phys_dev));
+-}
+-
+-/*
+- * States for the input scanner (should be in dev_table.h)
+- */
+-
+-#define MST_SYSMSG 100 /* System message (sysx etc). */
+-#define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */
+-#define MST_SONGSEL 103 /* Song select */
+-#define MST_SONGPOS 104 /* Song position pointer */
+-#define MST_TIMED 105 /* Leading timing byte rcvd */
+-
+-/* buffer space check for input scanner */
+-
+-#define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
+-{printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \
+- mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;}
+-
+-static unsigned char len_tab[] = /* # of data bytes following a status
+- */
+-{
+- 2, /* 8x */
+- 2, /* 9x */
+- 2, /* Ax */
+- 2, /* Bx */
+- 1, /* Cx */
+- 1, /* Dx */
+- 2, /* Ex */
+- 0 /* Fx */
+-};
+-
+-static int
+-wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
+-
+-{
+- struct midi_input_info *mi = &midi_devs[devno]->in_info;
+-
+- switch (mi->m_state) {
+- case MST_INIT:
+- switch (midic) {
+- case 0xf8:
+- /* Timer overflow */
+- break;
+-
+- case 0xfc:
+- break;
+-
+- case 0xfd:
+- /* XXX do something useful with this. If there is
+- an external MIDI timer (e.g. a hardware sequencer,
+- a useful timer can be derived ...
+-
+- For now, no timer support.
+- */
+- break;
+-
+- case 0xfe:
+- return MPU_ACK;
+- break;
+-
+- case 0xf0:
+- case 0xf1:
+- case 0xf2:
+- case 0xf3:
+- case 0xf4:
+- case 0xf5:
+- case 0xf6:
+- case 0xf7:
+- break;
+-
+- case 0xf9:
+- break;
+-
+- case 0xff:
+- mi->m_state = MST_SYSMSG;
+- break;
+-
+- default:
+- if (midic <= 0xef) {
+- mi->m_state = MST_TIMED;
+- }
+- else
+- printk (KERN_ERR "<MPU: Unknown event %02x> ",
+- midic);
+- }
+- break;
+-
+- case MST_TIMED:
+- {
+- int msg = ((int) (midic & 0xf0) >> 4);
+-
+- mi->m_state = MST_DATA;
+-
+- if (msg < 8) { /* Data byte */
+-
+- msg = ((int) (mi->m_prev_status & 0xf0) >> 4);
+- msg -= 8;
+- mi->m_left = len_tab[msg] - 1;
+-
+- mi->m_ptr = 2;
+- mi->m_buf[0] = mi->m_prev_status;
+- mi->m_buf[1] = midic;
+-
+- if (mi->m_left <= 0) {
+- mi->m_state = MST_INIT;
+- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
+- mi->m_ptr = 0;
+- }
+- } else if (msg == 0xf) { /* MPU MARK */
+-
+- mi->m_state = MST_INIT;
+-
+- switch (midic) {
+- case 0xf8:
+- break;
+-
+- case 0xf9:
+- break;
+-
+- case 0xfc:
+- break;
+-
+- default:
+- break;
+- }
+- } else {
+- mi->m_prev_status = midic;
+- msg -= 8;
+- mi->m_left = len_tab[msg];
+-
+- mi->m_ptr = 1;
+- mi->m_buf[0] = midic;
+-
+- if (mi->m_left <= 0) {
+- mi->m_state = MST_INIT;
+- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
+- mi->m_ptr = 0;
+- }
+- }
+- }
+- break;
+-
+- case MST_SYSMSG:
+- switch (midic) {
+- case 0xf0:
+- mi->m_state = MST_SYSEX;
+- break;
+-
+- case 0xf1:
+- mi->m_state = MST_MTC;
+- break;
+-
+- case 0xf2:
+- mi->m_state = MST_SONGPOS;
+- mi->m_ptr = 0;
+- break;
+-
+- case 0xf3:
+- mi->m_state = MST_SONGSEL;
+- break;
+-
+- case 0xf6:
+- mi->m_state = MST_INIT;
+-
+- /*
+- * Real time messages
+- */
+- case 0xf8:
+- /* midi clock */
+- mi->m_state = MST_INIT;
+- /* XXX need ext MIDI timer support */
+- break;
+-
+- case 0xfA:
+- mi->m_state = MST_INIT;
+- /* XXX need ext MIDI timer support */
+- break;
+-
+- case 0xFB:
+- mi->m_state = MST_INIT;
+- /* XXX need ext MIDI timer support */
+- break;
+-
+- case 0xFC:
+- mi->m_state = MST_INIT;
+- /* XXX need ext MIDI timer support */
+- break;
+-
+- case 0xFE:
+- /* active sensing */
+- mi->m_state = MST_INIT;
+- break;
+-
+- case 0xff:
+- mi->m_state = MST_INIT;
+- break;
+-
+- default:
+- printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
+- mi->m_state = MST_INIT;
+- }
+- break;
+-
+- case MST_MTC:
+- mi->m_state = MST_INIT;
+- break;
+-
+- case MST_SYSEX:
+- if (midic == 0xf7) {
+- mi->m_state = MST_INIT;
+- } else {
+- /* XXX fix me */
+- }
+- break;
+-
+- case MST_SONGPOS:
+- BUFTEST (mi);
+- mi->m_buf[mi->m_ptr++] = midic;
+- if (mi->m_ptr == 2) {
+- mi->m_state = MST_INIT;
+- mi->m_ptr = 0;
+- /* XXX need ext MIDI timer support */
+- }
+- break;
+-
+- case MST_DATA:
+- BUFTEST (mi);
+- mi->m_buf[mi->m_ptr++] = midic;
+- if ((--mi->m_left) <= 0) {
+- mi->m_state = MST_INIT;
+- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
+- mi->m_ptr = 0;
+- }
+- break;
+-
+- default:
+- printk (KERN_ERR "Bad state %d ", mi->m_state);
+- mi->m_state = MST_INIT;
+- }
+-
+- return 1;
+-}
+-
+-static irqreturn_t
+-wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+-
+-{
+- struct wf_mpu_config *physical_dev = dev_id;
+- static struct wf_mpu_config *input_dev;
+- struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
+- int n;
+-
+- if (!input_avail()) { /* not for us */
+- return IRQ_NONE;
+- }
+-
+- if (mi->m_busy)
+- return IRQ_HANDLED;
+- spin_lock(&lock);
+- mi->m_busy = 1;
+-
+- if (!input_dev) {
+- input_dev = physical_dev;
+- }
+-
+- n = 50; /* XXX why ? */
+-
+- do {
+- unsigned char c = read_data ();
+-
+- if (phys_dev->isvirtual) {
+-
+- if (c == WF_EXTERNAL_SWITCH) {
+- input_dev = virt_dev;
+- continue;
+- } else if (c == WF_INTERNAL_SWITCH) {
+- input_dev = phys_dev;
+- continue;
+- } /* else just leave it as it is */
+-
+- } else {
+- input_dev = phys_dev;
+- }
+-
+- if (input_dev->mode == MODE_SYNTH) {
+-
+- wf_mpu_input_scanner (input_dev->devno,
+- input_dev->synthno, c);
+-
+- } else if (input_dev->opened & OPEN_READ) {
+-
+- if (input_dev->inputintr) {
+- input_dev->inputintr (input_dev->devno, c);
+- }
+- }
+-
+- } while (input_avail() && n-- > 0);
+-
+- mi->m_busy = 0;
+- spin_unlock(&lock);
+- return IRQ_HANDLED;
+-}
+-
+-static int
+-wf_mpu_open (int dev, int mode,
+- void (*input) (int dev, unsigned char data),
+- void (*output) (int dev)
+- )
+-{
+- struct wf_mpu_config *devc;
+-
+- if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
+- return -(ENXIO);
+-
+- if (phys_dev->devno == dev) {
+- devc = phys_dev;
+- } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
+- devc = virt_dev;
+- } else {
+- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+- return -(EINVAL);
+- }
+-
+- if (devc->opened) {
+- return -(EBUSY);
+- }
+-
+- devc->mode = MODE_MIDI;
+- devc->opened = mode;
+- devc->synthno = 0;
+-
+- devc->inputintr = input;
+- return 0;
+-}
+-
+-static void
+-wf_mpu_close (int dev)
+-{
+- struct wf_mpu_config *devc;
+-
+- if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
+- return;
+-
+- if (phys_dev->devno == dev) {
+- devc = phys_dev;
+- } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
+- devc = virt_dev;
+- } else {
+- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+- return;
+- }
+-
+- devc->mode = 0;
+- devc->inputintr = NULL;
+- devc->opened = 0;
+-}
+-
+-static int
+-wf_mpu_out (int dev, unsigned char midi_byte)
+-{
+- int timeout;
+- unsigned long flags;
+- static int lastoutdev = -1;
+- unsigned char switchch;
+-
+- if (phys_dev->isvirtual && lastoutdev != dev) {
+-
+- if (dev == phys_dev->devno) {
+- switchch = WF_INTERNAL_SWITCH;
+- } else if (dev == virt_dev->devno) {
+- switchch = WF_EXTERNAL_SWITCH;
+- } else {
+- printk (KERN_ERR "WF-MPU: bad device number %d", dev);
+- return (0);
+- }
+-
+- /* XXX fix me */
+-
+- for (timeout = 30000; timeout > 0 && !output_ready ();
+- timeout--);
+-
+- spin_lock_irqsave(&lock,flags);
+-
+- if (!output_ready ()) {
+- printk (KERN_WARNING "WF-MPU: Send switch "
+- "byte timeout\n");
+- spin_unlock_irqrestore(&lock,flags);
+- return 0;
+- }
+-
+- write_data (switchch);
+- spin_unlock_irqrestore(&lock,flags);
+- }
+-
+- lastoutdev = dev;
+-
+- /*
+- * Sometimes it takes about 30000 loops before the output becomes ready
+- * (After reset). Normally it takes just about 10 loops.
+- */
+-
+- /* XXX fix me */
+-
+- for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
+-
+- spin_lock_irqsave(&lock,flags);
+- if (!output_ready ()) {
+- spin_unlock_irqrestore(&lock,flags);
+- printk (KERN_WARNING "WF-MPU: Send data timeout\n");
+- return 0;
+- }
+-
+- write_data (midi_byte);
+- spin_unlock_irqrestore(&lock,flags);
+-
+- return 1;
+-}
+-
+-static inline int wf_mpu_start_read (int dev) {
+- return 0;
+-}
+-
+-static inline int wf_mpu_end_read (int dev) {
+- return 0;
+-}
+-
+-static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg)
+-{
+- printk (KERN_WARNING
+- "WF-MPU: Intelligent mode not supported by hardware.\n");
+- return -(EINVAL);
+-}
+-
+-static int wf_mpu_buffer_status (int dev)
+-{
+- return 0;
+-}
+-
+-static struct synth_operations wf_mpu_synth_operations[2];
+-static struct midi_operations wf_mpu_midi_operations[2];
+-
+-static struct midi_operations wf_mpu_midi_proto =
+-{
+- .owner = THIS_MODULE,
+- .info = {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+- .in_info = {0}, /* in_info */
+- .open = wf_mpu_open,
+- .close = wf_mpu_close,
+- .ioctl = wf_mpu_ioctl,
+- .outputc = wf_mpu_out,
+- .start_read = wf_mpu_start_read,
+- .end_read = wf_mpu_end_read,
+- .buffer_status = wf_mpu_buffer_status,
+-};
+-
+-static struct synth_info wf_mpu_synth_info_proto =
+-{"WaveFront MPU-401 interface", 0,
+- SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+-
+-static struct synth_info wf_mpu_synth_info[2];
+-
+-static int
+-wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg)
+-{
+- int midi_dev;
+- int index;
+-
+- midi_dev = synth_devs[dev]->midi_dev;
+-
+- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
+- return -(ENXIO);
+-
+- if (midi_dev == phys_dev->devno) {
+- index = 0;
+- } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
+- index = 1;
+- } else {
+- return -(EINVAL);
+- }
+-
+- switch (cmd) {
+-
+- case SNDCTL_SYNTH_INFO:
+- if (copy_to_user(arg,
+- &wf_mpu_synth_info[index],
+- sizeof (struct synth_info)))
+- return -EFAULT;
+- return 0;
+-
+- case SNDCTL_SYNTH_MEMAVL:
+- return 0x7fffffff;
+-
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static int
+-wf_mpu_synth_open (int dev, int mode)
+-{
+- int midi_dev;
+- struct wf_mpu_config *devc;
+-
+- midi_dev = synth_devs[dev]->midi_dev;
+-
+- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
+- return -(ENXIO);
+- }
+-
+- if (phys_dev->devno == midi_dev) {
+- devc = phys_dev;
+- } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
+- devc = virt_dev;
+- } else {
+- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+- return -(EINVAL);
+- }
+-
+- if (devc->opened) {
+- return -(EBUSY);
+- }
+-
+- devc->mode = MODE_SYNTH;
+- devc->synthno = dev;
+- devc->opened = mode;
+- devc->inputintr = NULL;
+- return 0;
+-}
+-
+-static void
+-wf_mpu_synth_close (int dev)
+-{
+- int midi_dev;
+- struct wf_mpu_config *devc;
+-
+- midi_dev = synth_devs[dev]->midi_dev;
+-
+- if (phys_dev->devno == midi_dev) {
+- devc = phys_dev;
+- } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
+- devc = virt_dev;
+- } else {
+- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+- return;
+- }
+-
+- devc->inputintr = NULL;
+- devc->opened = 0;
+- devc->mode = 0;
+-}
+-
+-#define _MIDI_SYNTH_C_
+-#define MIDI_SYNTH_NAME "WaveFront (MIDI)"
+-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
+-#include "midi_synth.h"
+-
+-static struct synth_operations wf_mpu_synth_proto =
+-{
+- .owner = THIS_MODULE,
+- .id = "WaveFront (ICS2115)",
+- .info = NULL, /* info field, filled in during configuration */
+- .midi_dev = 0, /* MIDI dev XXX should this be -1 ? */
+- .synth_type = SYNTH_TYPE_MIDI,
+- .synth_subtype = SAMPLE_TYPE_WAVEFRONT,
+- .open = wf_mpu_synth_open,
+- .close = wf_mpu_synth_close,
+- .ioctl = wf_mpu_synth_ioctl,
+- .kill_note = midi_synth_kill_note,
+- .start_note = midi_synth_start_note,
+- .set_instr = midi_synth_set_instr,
+- .reset = midi_synth_reset,
+- .hw_control = midi_synth_hw_control,
+- .load_patch = midi_synth_load_patch,
+- .aftertouch = midi_synth_aftertouch,
+- .controller = midi_synth_controller,
+- .panning = midi_synth_panning,
+- .bender = midi_synth_bender,
+- .setup_voice = midi_synth_setup_voice,
+- .send_sysex = midi_synth_send_sysex
+-};
+-
+-static int
+-config_wf_mpu (struct wf_mpu_config *dev)
+-
+-{
+- int is_external;
+- char *name;
+- int index;
+-
+- if (dev == phys_dev) {
+- name = "WaveFront internal MIDI";
+- is_external = 0;
+- index = 0;
+- memcpy ((char *) &wf_mpu_synth_operations[index],
+- (char *) &wf_mpu_synth_proto,
+- sizeof (struct synth_operations));
+- } else {
+- name = "WaveFront external MIDI";
+- is_external = 1;
+- index = 1;
+- /* no synth operations for an external MIDI interface */
+- }
+-
+- memcpy ((char *) &wf_mpu_synth_info[dev->devno],
+- (char *) &wf_mpu_synth_info_proto,
+- sizeof (struct synth_info));
+-
+- strcpy (wf_mpu_synth_info[index].name, name);
+-
+- wf_mpu_synth_operations[index].midi_dev = dev->devno;
+- wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
+-
+- memcpy ((char *) &wf_mpu_midi_operations[index],
+- (char *) &wf_mpu_midi_proto,
+- sizeof (struct midi_operations));
+-
+- if (is_external) {
+- wf_mpu_midi_operations[index].converter = NULL;
+- } else {
+- wf_mpu_midi_operations[index].converter =
+- &wf_mpu_synth_operations[index];
+- }
+-
+- strcpy (wf_mpu_midi_operations[index].info.name, name);
+-
+- midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
+- midi_devs[dev->devno]->in_info.m_busy = 0;
+- midi_devs[dev->devno]->in_info.m_state = MST_INIT;
+- midi_devs[dev->devno]->in_info.m_ptr = 0;
+- midi_devs[dev->devno]->in_info.m_left = 0;
+- midi_devs[dev->devno]->in_info.m_prev_status = 0;
+-
+- devs[index].opened = 0;
+- devs[index].mode = 0;
+-
+- return (0);
+-}
+-
+-int virtual_midi_enable (void)
+-
+-{
+- if ((virt_dev->devno < 0) &&
+- (virt_dev->devno = sound_alloc_mididev()) == -1) {
+- printk (KERN_ERR
+- "WF-MPU: too many midi devices detected\n");
+- return -1;
+- }
+-
+- config_wf_mpu (virt_dev);
+-
+- phys_dev->isvirtual = 1;
+- return virt_dev->devno;
+-}
+-
+-int
+-virtual_midi_disable (void)
+-
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&lock,flags);
+-
+- wf_mpu_close (virt_dev->devno);
+- /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
+- phys_dev->isvirtual = 0;
+-
+- spin_unlock_irqrestore(&lock,flags);
+-
+- return 0;
+-}
+-
+-int __init detect_wf_mpu (int irq, int io_base)
+-{
+- if (!request_region(io_base, 2, "wavefront midi")) {
+- printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
+- io_base);
+- return -1;
+- }
+-
+- phys_dev->base = io_base;
+- phys_dev->irq = irq;
+- phys_dev->devno = -1;
+- virt_dev->devno = -1;
+-
+- return 0;
+-}
+-
+-int __init install_wf_mpu (void)
+-{
+- if ((phys_dev->devno = sound_alloc_mididev()) < 0){
+-
+- printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
+- release_region(phys_dev->base, 2);
+- return -1;
+- }
+-
+- phys_dev->isvirtual = 0;
+-
+- if (config_wf_mpu (phys_dev)) {
+-
+- printk (KERN_WARNING
+- "WF-MPU: configuration for MIDI device %d failed\n",
+- phys_dev->devno);
+- sound_unload_mididev (phys_dev->devno);
+-
+- }
+-
+- /* OK, now we're configured to handle an interrupt ... */
+-
+- if (request_irq (phys_dev->irq, wf_mpuintr, IRQF_DISABLED|IRQF_SHARED,
+- "wavefront midi", phys_dev) < 0) {
+-
+- printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
+- phys_dev->irq);
+- return -1;
+-
+- }
+-
+- /* This being a WaveFront (ICS-2115) emulated MPU-401, we have
+- to switch it into UART (dumb) mode, because otherwise, it
+- won't do anything at all.
+- */
+-
+- start_uart_mode ();
+-
+- return phys_dev->devno;
+-}
+-
+-void
+-uninstall_wf_mpu (void)
+-
+-{
+- release_region (phys_dev->base, 2);
+- free_irq (phys_dev->irq, phys_dev);
+- sound_unload_mididev (phys_dev->devno);
+-
+- if (virt_dev->devno >= 0) {
+- sound_unload_mididev (virt_dev->devno);
+- }
+-}
+-
+-static void
+-start_uart_mode (void)
+-
+-{
+- int ok, i;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&lock,flags);
+-
+- /* XXX fix me */
+-
+- for (i = 0; i < 30000 && !output_ready (); i++);
+-
+- outb (UART_MODE_ON, COMDPORT(phys_dev));
+-
+- for (ok = 0, i = 50000; i > 0 && !ok; i--) {
+- if (input_avail ()) {
+- if (read_data () == MPU_ACK) {
+- ok = 1;
+- }
+- }
+- }
+-
+- spin_unlock_irqrestore(&lock,flags);
+-}
+-#endif
+diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c
+deleted file mode 100644
+index 6e22472..0000000
+--- a/sound/oss/ymfpci.c
++++ /dev/null
+@@ -1,2692 +0,0 @@
+-/*
+- * Copyright 1999 Jaroslav Kysela <perex at suse.cz>
+- * Copyright 2000 Alan Cox <alan at redhat.com>
+- * Copyright 2001 Kai Germaschewski <kai at tp1.ruhr-uni-bochum.de>
+- * Copyright 2002 Pete Zaitcev <zaitcev at yahoo.com>
+- *
+- * Yamaha YMF7xx driver.
+- *
+- * This code is a result of high-speed collision
+- * between ymfpci.c of ALSA and cs46xx.c of Linux.
+- * -- Pete Zaitcev <zaitcev at yahoo.com>; 2000/09/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
+- * (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.
+- *
+- * TODO:
+- * - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot).
+- * - 96KHz playback for DVD - use pitch of 2.0.
+- * - Retain DMA buffer on close, do not wait the end of frame.
+- * - Resolve XXX tagged questions.
+- * - Cannot play 5133Hz.
+- * - 2001/01/07 Consider if we can remove voice_lock, like so:
+- * : Allocate/deallocate voices in open/close under semafore.
+- * : We access voices in interrupt, that only for pcms that open.
+- * voice_lock around playback_prepare closes interrupts for insane duration.
+- * - Revisit the way voice_alloc is done - too confusing, overcomplicated.
+- * Should support various channel types, however.
+- * - Remove prog_dmabuf from read/write, leave it in open.
+- * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
+- * native synthesizer through a playback slot.
+- * - 2001/11/29 ac97_save_state
+- * Talk to Kai to remove ac97_save_state before it's too late!
+- * - Second AC97
+- * - Restore S/PDIF - Toshibas have it.
+- *
+- * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
+- * unconventional. However, given how small our fragments can be,
+- * a little uncached access is perhaps better than endless flushing.
+- * On i386 and other I/O-coherent architectures pci_alloc_consistent
+- * is entirely harmless.
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/ioport.h>
+-#include <linux/delay.h>
+-#include <linux/pci.h>
+-#include <linux/slab.h>
+-#include <linux/poll.h>
+-#include <linux/soundcard.h>
+-#include <linux/ac97_codec.h>
+-#include <linux/sound.h>
+-
+-#include <asm/io.h>
+-#include <asm/dma.h>
+-#include <asm/uaccess.h>
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+-# include "sound_config.h"
+-# include "mpu401.h"
+-#endif
+-#include "ymfpci.h"
+-
+-/*
+- * I do not believe in debug levels as I never can guess what
+- * part of the code is going to be problematic in the future.
+- * Don't forget to run your klogd with -c 8.
+- *
+- * Example (do not remove):
+- * #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0)
+- */
+-#define YMFDBGW(fmt, arg...) /* */ /* write counts */
+-#define YMFDBGI(fmt, arg...) /* */ /* interrupts */
+-#define YMFDBGX(fmt, arg...) /* */ /* ioctl */
+-
+-static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
+-static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
+-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice);
+-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank);
+-static int ymf_playback_prepare(struct ymf_state *state);
+-static int ymf_capture_prepare(struct ymf_state *state);
+-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit);
+-
+-static void ymfpci_aclink_reset(struct pci_dev * pci);
+-static void ymfpci_disable_dsp(ymfpci_t *unit);
+-static void ymfpci_download_image(ymfpci_t *codec);
+-static void ymf_memload(ymfpci_t *unit);
+-
+-static DEFINE_SPINLOCK(ymf_devs_lock);
+-static LIST_HEAD(ymf_devs);
+-
+-/*
+- * constants
+- */
+-
+-static struct pci_device_id ymf_id_tbl[] = {
+-#define DEV(dev, data) \
+- { PCI_VENDOR_ID_YAMAHA, dev, PCI_ANY_ID, PCI_ANY_ID, 0, 0, \
+- (unsigned long)data }
+- DEV (PCI_DEVICE_ID_YAMAHA_724, "YMF724"),
+- DEV (PCI_DEVICE_ID_YAMAHA_724F, "YMF724F"),
+- DEV (PCI_DEVICE_ID_YAMAHA_740, "YMF740"),
+- DEV (PCI_DEVICE_ID_YAMAHA_740C, "YMF740C"),
+- DEV (PCI_DEVICE_ID_YAMAHA_744, "YMF744"),
+- DEV (PCI_DEVICE_ID_YAMAHA_754, "YMF754"),
+-#undef DEV
+- { }
+-};
+-MODULE_DEVICE_TABLE(pci, ymf_id_tbl);
+-
+-/*
+- * common I/O routines
+- */
+-
+-static inline void ymfpci_writeb(ymfpci_t *codec, u32 offset, u8 val)
+-{
+- writeb(val, codec->reg_area_virt + offset);
+-}
+-
+-static inline u16 ymfpci_readw(ymfpci_t *codec, u32 offset)
+-{
+- return readw(codec->reg_area_virt + offset);
+-}
+-
+-static inline void ymfpci_writew(ymfpci_t *codec, u32 offset, u16 val)
+-{
+- writew(val, codec->reg_area_virt + offset);
+-}
+-
+-static inline u32 ymfpci_readl(ymfpci_t *codec, u32 offset)
+-{
+- return readl(codec->reg_area_virt + offset);
+-}
+-
+-static inline void ymfpci_writel(ymfpci_t *codec, u32 offset, u32 val)
+-{
+- writel(val, codec->reg_area_virt + offset);
+-}
+-
+-static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched)
+-{
+- signed long end_time;
+- u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
+-
+- end_time = jiffies + 3 * (HZ / 4);
+- do {
+- if ((ymfpci_readw(codec, reg) & 0x8000) == 0)
+- return 0;
+- if (sched) {
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout(1);
+- }
+- } while (end_time - (signed long)jiffies >= 0);
+- printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
+- secondary, ymfpci_readw(codec, reg));
+- return -EBUSY;
+-}
+-
+-static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val)
+-{
+- ymfpci_t *codec = dev->private_data;
+- u32 cmd;
+-
+- spin_lock(&codec->ac97_lock);
+- /* XXX Do make use of dev->id */
+- ymfpci_codec_ready(codec, 0, 0);
+- cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
+- ymfpci_writel(codec, YDSXGR_AC97CMDDATA, cmd);
+- spin_unlock(&codec->ac97_lock);
+-}
+-
+-static u16 _ymfpci_codec_read(ymfpci_t *unit, u8 reg)
+-{
+- int i;
+-
+- if (ymfpci_codec_ready(unit, 0, 0))
+- return ~0;
+- ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
+- if (ymfpci_codec_ready(unit, 0, 0))
+- return ~0;
+- if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
+- for (i = 0; i < 600; i++)
+- ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
+- }
+- return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
+-}
+-
+-static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
+-{
+- ymfpci_t *unit = dev->private_data;
+- u16 ret;
+-
+- spin_lock(&unit->ac97_lock);
+- ret = _ymfpci_codec_read(unit, reg);
+- spin_unlock(&unit->ac97_lock);
+-
+- return ret;
+-}
+-
+-/*
+- * Misc routines
+- */
+-
+-/*
+- * Calculate the actual sampling rate relatetively to the base clock (48kHz).
+- */
+-static u32 ymfpci_calc_delta(u32 rate)
+-{
+- switch (rate) {
+- case 8000: return 0x02aaab00;
+- case 11025: return 0x03accd00;
+- case 16000: return 0x05555500;
+- case 22050: return 0x07599a00;
+- case 32000: return 0x0aaaab00;
+- case 44100: return 0x0eb33300;
+- default: return ((rate << 16) / 48000) << 12;
+- }
+-}
+-
+-static u32 def_rate[8] = {
+- 100, 2000, 8000, 11025, 16000, 22050, 32000, 48000
+-};
+-
+-static u32 ymfpci_calc_lpfK(u32 rate)
+-{
+- u32 i;
+- static u32 val[8] = {
+- 0x00570000, 0x06AA0000, 0x18B20000, 0x20930000,
+- 0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000
+- };
+-
+- if (rate == 44100)
+- return 0x40000000; /* FIXME: What's the right value? */
+- for (i = 0; i < 8; i++)
+- if (rate <= def_rate[i])
+- return val[i];
+- return val[0];
+-}
+-
+-static u32 ymfpci_calc_lpfQ(u32 rate)
+-{
+- u32 i;
+- static u32 val[8] = {
+- 0x35280000, 0x34A70000, 0x32020000, 0x31770000,
+- 0x31390000, 0x31C90000, 0x33D00000, 0x40000000
+- };
+-
+- if (rate == 44100)
+- return 0x370A0000;
+- for (i = 0; i < 8; i++)
+- if (rate <= def_rate[i])
+- return val[i];
+- return val[0];
+-}
+-
+-static u32 ymf_calc_lend(u32 rate)
+-{
+- return (rate * YMF_SAMPF) / 48000;
+-}
+-
+-/*
+- * We ever allow only a few formats, but let's be generic, for smaller surprise.
+- */
+-static int ymf_pcm_format_width(int format)
+-{
+- static int mask16 = AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE;
+-
+- if ((format & (format-1)) != 0) {
+- printk(KERN_ERR "ymfpci: format 0x%x is not a power of 2\n", format);
+- return 8;
+- }
+-
+- if (format == AFMT_IMA_ADPCM) return 4;
+- if ((format & mask16) != 0) return 16;
+- return 8;
+-}
+-
+-static void ymf_pcm_update_shift(struct ymf_pcm_format *f)
+-{
+- f->shift = 0;
+- if (f->voices == 2)
+- f->shift++;
+- if (ymf_pcm_format_width(f->format) == 16)
+- f->shift++;
+-}
+-
+-/* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */
+-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+-#define DMABUF_MINORDER 1
+-
+-/*
+- * Allocate DMA buffer
+- */
+-static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
+-{
+- void *rawbuf = NULL;
+- dma_addr_t dma_addr;
+- int order;
+- struct page *map, *mapend;
+-
+- /* alloc as big a chunk as we can */
+- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+- rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
+- if (rawbuf)
+- break;
+- }
+- if (!rawbuf)
+- return -ENOMEM;
+-
+-#if 0
+- printk(KERN_DEBUG "ymfpci: allocated %ld (order = %d) bytes at %p\n",
+- PAGE_SIZE << order, order, rawbuf);
+-#endif
+-
+- dmabuf->ready = dmabuf->mapped = 0;
+- dmabuf->rawbuf = rawbuf;
+- dmabuf->dma_addr = dma_addr;
+- dmabuf->buforder = order;
+-
+- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
+- mapend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
+- for (map = virt_to_page(rawbuf); map <= mapend; map++)
+- set_bit(PG_reserved, &map->flags);
+-
+- return 0;
+-}
+-
+-/*
+- * Free DMA buffer
+- */
+-static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
+-{
+- struct page *map, *mapend;
+-
+- if (dmabuf->rawbuf) {
+- /* undo marking the pages as reserved */
+- mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+- for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
+- clear_bit(PG_reserved, &map->flags);
+-
+- pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
+- dmabuf->rawbuf, dmabuf->dma_addr);
+- }
+- dmabuf->rawbuf = NULL;
+- dmabuf->mapped = dmabuf->ready = 0;
+-}
+-
+-static int prog_dmabuf(struct ymf_state *state, int rec)
+-{
+- struct ymf_dmabuf *dmabuf;
+- int w_16;
+- unsigned bufsize;
+- unsigned long flags;
+- int redzone, redfrags;
+- int ret;
+-
+- w_16 = ymf_pcm_format_width(state->format.format) == 16;
+- dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf;
+-
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->hwptr = dmabuf->swptr = 0;
+- dmabuf->total_bytes = 0;
+- dmabuf->count = 0;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+-
+- /* allocate DMA buffer if not allocated yet */
+- if (!dmabuf->rawbuf)
+- if ((ret = alloc_dmabuf(state->unit, dmabuf)))
+- return ret;
+-
+- /*
+- * Create fake fragment sizes and numbers for OSS ioctls.
+- * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
+- */
+- bufsize = PAGE_SIZE << dmabuf->buforder;
+- /* By default we give 4 big buffers. */
+- dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
+- if (dmabuf->ossfragshift > 3 &&
+- dmabuf->ossfragshift < dmabuf->fragshift) {
+- /* If OSS set smaller fragments, give more smaller buffers. */
+- dmabuf->fragshift = dmabuf->ossfragshift;
+- }
+- dmabuf->fragsize = 1 << dmabuf->fragshift;
+-
+- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+-
+- if (dmabuf->ossmaxfrags >= 2) {
+- redzone = ymf_calc_lend(state->format.rate);
+- redzone <<= state->format.shift;
+- redzone *= 3;
+- redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift;
+-
+- if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) {
+- dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags;
+- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+- }
+- }
+-
+- memset(dmabuf->rawbuf, w_16 ? 0 : 0x80, dmabuf->dmasize);
+-
+- /*
+- * Now set up the ring
+- */
+-
+- /* XXX ret = rec? cap_pre(): pbk_pre(); */
+- spin_lock_irqsave(&state->unit->voice_lock, flags);
+- if (rec) {
+- if ((ret = ymf_capture_prepare(state)) != 0) {
+- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
+- return ret;
+- }
+- } else {
+- if ((ret = ymf_playback_prepare(state)) != 0) {
+- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
+- return ret;
+- }
+- }
+- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
+-
+- /* set the ready flag for the dma buffer (this comment is not stupid) */
+- dmabuf->ready = 1;
+-
+-#if 0
+- printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
+- " numfrag %d fragsize %d dmasize %d\n",
+- state->format.rate, state->format.format, dmabuf->numfrag,
+- dmabuf->fragsize, dmabuf->dmasize);
+-#endif
+-
+- return 0;
+-}
+-
+-static void ymf_start_dac(struct ymf_state *state)
+-{
+- ymf_playback_trigger(state->unit, &state->wpcm, 1);
+-}
+-
+-// static void ymf_start_adc(struct ymf_state *state)
+-// {
+-// ymf_capture_trigger(state->unit, &state->rpcm, 1);
+-// }
+-
+-/*
+- * Wait until output is drained.
+- * This does not kill the hardware for the sake of ioctls.
+- */
+-static void ymf_wait_dac(struct ymf_state *state)
+-{
+- struct ymf_unit *unit = state->unit;
+- struct ymf_pcm *ypcm = &state->wpcm;
+- DECLARE_WAITQUEUE(waita, current);
+- unsigned long flags;
+-
+- add_wait_queue(&ypcm->dmabuf.wait, &waita);
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (ypcm->dmabuf.count != 0 && !ypcm->running) {
+- ymf_playback_trigger(unit, ypcm, 1);
+- }
+-
+-#if 0
+- if (file->f_flags & O_NONBLOCK) {
+- /*
+- * XXX Our mistake is to attach DMA buffer to state
+- * rather than to some per-device structure.
+- * Cannot skip waiting, can only make it shorter.
+- */
+- }
+-#endif
+-
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- while (ypcm->running) {
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- schedule();
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- }
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&ypcm->dmabuf.wait, &waita);
+-
+- /*
+- * This function may take up to 4 seconds to reach this point
+- * (32K circular buffer, 8000 Hz). User notices.
+- */
+-}
+-
+-/* Can just stop, without wait. Or can we? */
+-static void ymf_stop_adc(struct ymf_state *state)
+-{
+- struct ymf_unit *unit = state->unit;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- ymf_capture_trigger(unit, &state->rpcm, 0);
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-}
+-
+-/*
+- * Hardware start management
+- */
+-
+-static void ymfpci_hw_start(ymfpci_t *unit)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (unit->start_count++ == 0) {
+- ymfpci_writel(unit, YDSXGR_MODE,
+- ymfpci_readl(unit, YDSXGR_MODE) | 3);
+- unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
+- }
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-}
+-
+-static void ymfpci_hw_stop(ymfpci_t *unit)
+-{
+- unsigned long flags;
+- long timeout = 1000;
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (--unit->start_count == 0) {
+- ymfpci_writel(unit, YDSXGR_MODE,
+- ymfpci_readl(unit, YDSXGR_MODE) & ~3);
+- while (timeout-- > 0) {
+- if ((ymfpci_readl(unit, YDSXGR_STATUS) & 2) == 0)
+- break;
+- }
+- }
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-}
+-
+-/*
+- * Playback voice management
+- */
+-
+-static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[])
+-{
+- ymfpci_voice_t *voice, *voice2;
+- int idx;
+-
+- for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {
+- voice = &codec->voices[idx];
+- voice2 = pair ? &codec->voices[idx+1] : NULL;
+- if (voice->use || (voice2 && voice2->use))
+- continue;
+- voice->use = 1;
+- if (voice2)
+- voice2->use = 1;
+- switch (type) {
+- case YMFPCI_PCM:
+- voice->pcm = 1;
+- if (voice2)
+- voice2->pcm = 1;
+- break;
+- case YMFPCI_SYNTH:
+- voice->synth = 1;
+- break;
+- case YMFPCI_MIDI:
+- voice->midi = 1;
+- break;
+- }
+- ymfpci_hw_start(codec);
+- rvoice[0] = voice;
+- if (voice2) {
+- ymfpci_hw_start(codec);
+- rvoice[1] = voice2;
+- }
+- return 0;
+- }
+- return -EBUSY; /* Your audio channel is open by someone else. */
+-}
+-
+-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice)
+-{
+- ymfpci_hw_stop(unit);
+- pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
+- pvoice->ypcm = NULL;
+-}
+-
+-/*
+- */
+-
+-static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
+-{
+- struct ymf_pcm *ypcm;
+- int redzone;
+- int pos, delta, swptr;
+- int played, distance;
+- struct ymf_state *state;
+- struct ymf_dmabuf *dmabuf;
+- char silence;
+-
+- if ((ypcm = voice->ypcm) == NULL) {
+- return;
+- }
+- if ((state = ypcm->state) == NULL) {
+- ypcm->running = 0; // lock it
+- return;
+- }
+- dmabuf = &ypcm->dmabuf;
+- spin_lock(&codec->reg_lock);
+- if (ypcm->running) {
+- YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
+- voice->number, codec->active_bank, dmabuf->count,
+- le32_to_cpu(voice->bank[0].start),
+- le32_to_cpu(voice->bank[1].start));
+- silence = (ymf_pcm_format_width(state->format.format) == 16) ?
+- 0 : 0x80;
+- /* We need actual left-hand-side redzone size here. */
+- redzone = ymf_calc_lend(state->format.rate);
+- redzone <<= (state->format.shift + 1);
+- swptr = dmabuf->swptr;
+-
+- pos = le32_to_cpu(voice->bank[codec->active_bank].start);
+- pos <<= state->format.shift;
+- if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
+- printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
+- codec->dev_audio, voice->number,
+- dmabuf->hwptr, pos, dmabuf->dmasize);
+- pos = 0;
+- }
+- if (pos < dmabuf->hwptr) {
+- delta = dmabuf->dmasize - dmabuf->hwptr;
+- memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
+- delta += pos;
+- memset(dmabuf->rawbuf, silence, pos);
+- } else {
+- delta = pos - dmabuf->hwptr;
+- memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
+- }
+- dmabuf->hwptr = pos;
+-
+- if (dmabuf->count == 0) {
+- printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
+- codec->dev_audio, voice->number, dmabuf->hwptr);
+- ymf_playback_trigger(codec, ypcm, 0);
+- }
+-
+- if (swptr <= pos) {
+- distance = pos - swptr;
+- } else {
+- distance = dmabuf->dmasize - (swptr - pos);
+- }
+- if (distance < redzone) {
+- /*
+- * hwptr inside redzone => DMA ran out of samples.
+- */
+- if (delta < dmabuf->count) {
+- /*
+- * Lost interrupt or other screwage.
+- */
+- printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
+- " hwptr %d swptr %d distance %d count %d\n",
+- codec->dev_audio, voice->number, delta,
+- dmabuf->hwptr, swptr, distance, dmabuf->count);
+- } else {
+- /*
+- * Normal end of DMA.
+- */
+- YMFDBGI("ymfpci%d: %d: done: delta %d"
+- " hwptr %d swptr %d distance %d count %d\n",
+- codec->dev_audio, voice->number, delta,
+- dmabuf->hwptr, swptr, distance, dmabuf->count);
+- }
+- played = dmabuf->count;
+- if (ypcm->running) {
+- ymf_playback_trigger(codec, ypcm, 0);
+- }
+- } else {
+- /*
+- * hwptr is chipping away towards a remote swptr.
+- * Calculate other distance and apply it to count.
+- */
+- if (swptr >= pos) {
+- distance = swptr - pos;
+- } else {
+- distance = dmabuf->dmasize - (pos - swptr);
+- }
+- if (distance < dmabuf->count) {
+- played = dmabuf->count - distance;
+- } else {
+- played = 0;
+- }
+- }
+-
+- dmabuf->total_bytes += played;
+- dmabuf->count -= played;
+- if (dmabuf->count < dmabuf->dmasize / 2) {
+- wake_up(&dmabuf->wait);
+- }
+- }
+- spin_unlock(&codec->reg_lock);
+-}
+-
+-static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap)
+-{
+- struct ymf_pcm *ypcm;
+- int redzone;
+- struct ymf_state *state;
+- struct ymf_dmabuf *dmabuf;
+- int pos, delta;
+- int cnt;
+-
+- if ((ypcm = cap->ypcm) == NULL) {
+- return;
+- }
+- if ((state = ypcm->state) == NULL) {
+- ypcm->running = 0; // lock it
+- return;
+- }
+- dmabuf = &ypcm->dmabuf;
+- spin_lock(&unit->reg_lock);
+- if (ypcm->running) {
+- redzone = ymf_calc_lend(state->format.rate);
+- redzone <<= (state->format.shift + 1);
+-
+- pos = le32_to_cpu(cap->bank[unit->active_bank].start);
+- // pos <<= state->format.shift;
+- if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
+- printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
+- unit->dev_audio, ypcm->capture_bank_number,
+- dmabuf->hwptr, pos, dmabuf->dmasize);
+- pos = 0;
+- }
+- if (pos < dmabuf->hwptr) {
+- delta = dmabuf->dmasize - dmabuf->hwptr;
+- delta += pos;
+- } else {
+- delta = pos - dmabuf->hwptr;
+- }
+- dmabuf->hwptr = pos;
+-
+- cnt = dmabuf->count;
+- cnt += delta;
+- if (cnt + redzone > dmabuf->dmasize) {
+- /* Overflow - bump swptr */
+- dmabuf->count = dmabuf->dmasize - redzone;
+- dmabuf->swptr = dmabuf->hwptr + redzone;
+- if (dmabuf->swptr >= dmabuf->dmasize) {
+- dmabuf->swptr -= dmabuf->dmasize;
+- }
+- } else {
+- dmabuf->count = cnt;
+- }
+-
+- dmabuf->total_bytes += delta;
+- if (dmabuf->count) { /* && is_sleeping XXX */
+- wake_up(&dmabuf->wait);
+- }
+- }
+- spin_unlock(&unit->reg_lock);
+-}
+-
+-static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
+-{
+-
+- if (ypcm->voices[0] == NULL) {
+- return -EINVAL;
+- }
+- if (cmd != 0) {
+- codec->ctrl_playback[ypcm->voices[0]->number + 1] =
+- cpu_to_le32(ypcm->voices[0]->bank_ba);
+- if (ypcm->voices[1] != NULL)
+- codec->ctrl_playback[ypcm->voices[1]->number + 1] =
+- cpu_to_le32(ypcm->voices[1]->bank_ba);
+- ypcm->running = 1;
+- } else {
+- codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
+- if (ypcm->voices[1] != NULL)
+- codec->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
+- ypcm->running = 0;
+- }
+- return 0;
+-}
+-
+-static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
+-{
+- u32 tmp;
+-
+- if (cmd != 0) {
+- tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
+- ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
+- ypcm->running = 1;
+- } else {
+- tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
+- ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
+- ypcm->running = 0;
+- }
+-}
+-
+-static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices)
+-{
+- struct ymf_unit *unit;
+- int err;
+-
+- unit = ypcm->state->unit;
+- if (ypcm->voices[1] != NULL && voices < 2) {
+- ymfpci_voice_free(unit, ypcm->voices[1]);
+- ypcm->voices[1] = NULL;
+- }
+- if (voices == 1 && ypcm->voices[0] != NULL)
+- return 0; /* already allocated */
+- if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)
+- return 0; /* already allocated */
+- if (voices > 1) {
+- if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
+- ymfpci_voice_free(unit, ypcm->voices[0]);
+- ypcm->voices[0] = NULL;
+- }
+- if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0)
+- return err;
+- ypcm->voices[0]->ypcm = ypcm;
+- ypcm->voices[1]->ypcm = ypcm;
+- } else {
+- if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0)
+- return err;
+- ypcm->voices[0]->ypcm = ypcm;
+- }
+- return 0;
+-}
+-
+-static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
+- int rate, int w_16, unsigned long addr, unsigned int end, int spdif)
+-{
+- u32 format;
+- u32 delta = ymfpci_calc_delta(rate);
+- u32 lpfQ = ymfpci_calc_lpfQ(rate);
+- u32 lpfK = ymfpci_calc_lpfK(rate);
+- ymfpci_playback_bank_t *bank;
+- int nbank;
+-
+- /*
+- * The gain is a floating point number. According to the manual,
+- * bit 31 indicates a sign bit, bit 30 indicates an integer part,
+- * and bits [29:15] indicate a decimal fraction part. Thus,
+- * for a gain of 1.0 the constant of 0x40000000 is loaded.
+- */
+- unsigned default_gain = cpu_to_le32(0x40000000);
+-
+- format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
+- if (stereo)
+- end >>= 1;
+- if (w_16)
+- end >>= 1;
+- for (nbank = 0; nbank < 2; nbank++) {
+- bank = &voice->bank[nbank];
+- bank->format = cpu_to_le32(format);
+- bank->loop_default = 0; /* 0-loops forever, otherwise count */
+- bank->base = cpu_to_le32(addr);
+- bank->loop_start = 0;
+- bank->loop_end = cpu_to_le32(end);
+- bank->loop_frac = 0;
+- bank->eg_gain_end = default_gain;
+- bank->lpfQ = cpu_to_le32(lpfQ);
+- bank->status = 0;
+- bank->num_of_frames = 0;
+- bank->loop_count = 0;
+- bank->start = 0;
+- bank->start_frac = 0;
+- bank->delta =
+- bank->delta_end = cpu_to_le32(delta);
+- bank->lpfK =
+- bank->lpfK_end = cpu_to_le32(lpfK);
+- bank->eg_gain = default_gain;
+- bank->lpfD1 =
+- bank->lpfD2 = 0;
+-
+- bank->left_gain =
+- bank->right_gain =
+- bank->left_gain_end =
+- bank->right_gain_end =
+- bank->eff1_gain =
+- bank->eff2_gain =
+- bank->eff3_gain =
+- bank->eff1_gain_end =
+- bank->eff2_gain_end =
+- bank->eff3_gain_end = 0;
+-
+- if (!stereo) {
+- if (!spdif) {
+- bank->left_gain =
+- bank->right_gain =
+- bank->left_gain_end =
+- bank->right_gain_end = default_gain;
+- } else {
+- bank->eff2_gain =
+- bank->eff2_gain_end =
+- bank->eff3_gain =
+- bank->eff3_gain_end = default_gain;
+- }
+- } else {
+- if (!spdif) {
+- if ((voice->number & 1) == 0) {
+- bank->left_gain =
+- bank->left_gain_end = default_gain;
+- } else {
+- bank->format |= cpu_to_le32(1);
+- bank->right_gain =
+- bank->right_gain_end = default_gain;
+- }
+- } else {
+- if ((voice->number & 1) == 0) {
+- bank->eff2_gain =
+- bank->eff2_gain_end = default_gain;
+- } else {
+- bank->format |= cpu_to_le32(1);
+- bank->eff3_gain =
+- bank->eff3_gain_end = default_gain;
+- }
+- }
+- }
+- }
+-}
+-
+-/*
+- * XXX Capture channel allocation is entirely fake at the moment.
+- * We use only one channel and mark it busy as required.
+- */
+-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank)
+-{
+- struct ymf_capture *cap;
+- int cbank;
+-
+- cbank = 1; /* Only ADC slot is used for now. */
+- cap = &unit->capture[cbank];
+- if (cap->use)
+- return -EBUSY;
+- cap->use = 1;
+- *pbank = cbank;
+- return 0;
+-}
+-
+-static int ymf_playback_prepare(struct ymf_state *state)
+-{
+- struct ymf_pcm *ypcm = &state->wpcm;
+- int err, nvoice;
+-
+- if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
+- /* Somebody started 32 mpg123's in parallel? */
+- printk(KERN_INFO "ymfpci%d: cannot allocate voice\n",
+- state->unit->dev_audio);
+- return err;
+- }
+-
+- for (nvoice = 0; nvoice < state->format.voices; nvoice++) {
+- ymf_pcm_init_voice(ypcm->voices[nvoice],
+- state->format.voices == 2, state->format.rate,
+- ymf_pcm_format_width(state->format.format) == 16,
+- ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
+- ypcm->spdif);
+- }
+- return 0;
+-}
+-
+-static int ymf_capture_prepare(struct ymf_state *state)
+-{
+- ymfpci_t *unit = state->unit;
+- struct ymf_pcm *ypcm = &state->rpcm;
+- ymfpci_capture_bank_t * bank;
+- /* XXX This is confusing, gotta rename one of them banks... */
+- int nbank; /* flip-flop bank */
+- int cbank; /* input [super-]bank */
+- struct ymf_capture *cap;
+- u32 rate, format;
+-
+- if (ypcm->capture_bank_number == -1) {
+- if (ymf_capture_alloc(unit, &cbank) != 0)
+- return -EBUSY;
+-
+- ypcm->capture_bank_number = cbank;
+-
+- cap = &unit->capture[cbank];
+- cap->bank = unit->bank_capture[cbank][0];
+- cap->ypcm = ypcm;
+- ymfpci_hw_start(unit);
+- }
+-
+- // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream);
+- // frag_size is replaced with nonfragged byte-aligned rolling buffer
+- rate = ((48000 * 4096) / state->format.rate) - 1;
+- format = 0;
+- if (state->format.voices == 2)
+- format |= 2;
+- if (ymf_pcm_format_width(state->format.format) == 8)
+- format |= 1;
+- switch (ypcm->capture_bank_number) {
+- case 0:
+- ymfpci_writel(unit, YDSXGR_RECFORMAT, format);
+- ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate);
+- break;
+- case 1:
+- ymfpci_writel(unit, YDSXGR_ADCFORMAT, format);
+- ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate);
+- break;
+- }
+- for (nbank = 0; nbank < 2; nbank++) {
+- bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
+- bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
+- // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
+- bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
+- bank->start = 0;
+- bank->num_of_loops = 0;
+- }
+-#if 0 /* s/pdif */
+- if (state->digital.dig_valid)
+- /*state->digital.type == SND_PCM_DIG_AES_IEC958*/
+- ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,
+- state->digital.dig_status[0] | (state->digital.dig_status[1] << 8));
+-#endif
+- return 0;
+-}
+-
+-static irqreturn_t ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- ymfpci_t *codec = dev_id;
+- u32 status, nvoice, mode;
+- struct ymf_voice *voice;
+- struct ymf_capture *cap;
+-
+- status = ymfpci_readl(codec, YDSXGR_STATUS);
+- if (status & 0x80000000) {
+- codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1;
+- spin_lock(&codec->voice_lock);
+- for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
+- voice = &codec->voices[nvoice];
+- if (voice->use)
+- ymf_pcm_interrupt(codec, voice);
+- }
+- for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
+- cap = &codec->capture[nvoice];
+- if (cap->use)
+- ymf_cap_interrupt(codec, cap);
+- }
+- spin_unlock(&codec->voice_lock);
+- spin_lock(&codec->reg_lock);
+- ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000);
+- mode = ymfpci_readl(codec, YDSXGR_MODE) | 2;
+- ymfpci_writel(codec, YDSXGR_MODE, mode);
+- spin_unlock(&codec->reg_lock);
+- }
+-
+- status = ymfpci_readl(codec, YDSXGR_INTFLAG);
+- if (status & 1) {
+- /* timer handler */
+- ymfpci_writel(codec, YDSXGR_INTFLAG, ~0);
+- }
+- return IRQ_HANDLED;
+-}
+-
+-static void ymf_pcm_free_substream(struct ymf_pcm *ypcm)
+-{
+- unsigned long flags;
+- struct ymf_unit *unit;
+-
+- unit = ypcm->state->unit;
+-
+- if (ypcm->type == PLAYBACK_VOICE) {
+- spin_lock_irqsave(&unit->voice_lock, flags);
+- if (ypcm->voices[1])
+- ymfpci_voice_free(unit, ypcm->voices[1]);
+- if (ypcm->voices[0])
+- ymfpci_voice_free(unit, ypcm->voices[0]);
+- spin_unlock_irqrestore(&unit->voice_lock, flags);
+- } else {
+- if (ypcm->capture_bank_number != -1) {
+- unit->capture[ypcm->capture_bank_number].use = 0;
+- ypcm->capture_bank_number = -1;
+- ymfpci_hw_stop(unit);
+- }
+- }
+-}
+-
+-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit)
+-{
+- struct ymf_pcm *ypcm;
+- struct ymf_state *state;
+-
+- if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) {
+- goto out0;
+- }
+- memset(state, 0, sizeof(struct ymf_state));
+-
+- ypcm = &state->wpcm;
+- ypcm->state = state;
+- ypcm->type = PLAYBACK_VOICE;
+- ypcm->capture_bank_number = -1;
+- init_waitqueue_head(&ypcm->dmabuf.wait);
+-
+- ypcm = &state->rpcm;
+- ypcm->state = state;
+- ypcm->type = CAPTURE_AC97;
+- ypcm->capture_bank_number = -1;
+- init_waitqueue_head(&ypcm->dmabuf.wait);
+-
+- state->unit = unit;
+-
+- state->format.format = AFMT_U8;
+- state->format.rate = 8000;
+- state->format.voices = 1;
+- ymf_pcm_update_shift(&state->format);
+-
+- return state;
+-
+-out0:
+- return NULL;
+-}
+-
+-/* AES/IEC958 channel status bits */
+-#define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
+-#define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */
+-#define SND_PCM_AES0_PRO_EMPHASIS (7<<2) /* mask - emphasis */
+-#define SND_PCM_AES0_PRO_EMPHASIS_NOTID (0<<2) /* emphasis not indicated */
+-#define SND_PCM_AES0_PRO_EMPHASIS_NONE (1<<2) /* none emphasis */
+-#define SND_PCM_AES0_PRO_EMPHASIS_5015 (3<<2) /* 50/15us emphasis */
+-#define SND_PCM_AES0_PRO_EMPHASIS_CCITT (7<<2) /* CCITT J.17 emphasis */
+-#define SND_PCM_AES0_PRO_FREQ_UNLOCKED (1<<5) /* source sample frequency: 0 = locked, 1 = unlocked */
+-#define SND_PCM_AES0_PRO_FS (3<<6) /* mask - sample frequency */
+-#define SND_PCM_AES0_PRO_FS_NOTID (0<<6) /* fs not indicated */
+-#define SND_PCM_AES0_PRO_FS_44100 (1<<6) /* 44.1kHz */
+-#define SND_PCM_AES0_PRO_FS_48000 (2<<6) /* 48kHz */
+-#define SND_PCM_AES0_PRO_FS_32000 (3<<6) /* 32kHz */
+-#define SND_PCM_AES0_CON_NOT_COPYRIGHT (1<<2) /* 0 = copyright, 1 = not copyright */
+-#define SND_PCM_AES0_CON_EMPHASIS (7<<3) /* mask - emphasis */
+-#define SND_PCM_AES0_CON_EMPHASIS_NONE (0<<3) /* none emphasis */
+-#define SND_PCM_AES0_CON_EMPHASIS_5015 (1<<3) /* 50/15us emphasis */
+-#define SND_PCM_AES0_CON_MODE (3<<6) /* mask - mode */
+-#define SND_PCM_AES1_PRO_MODE (15<<0) /* mask - channel mode */
+-#define SND_PCM_AES1_PRO_MODE_NOTID (0<<0) /* not indicated */
+-#define SND_PCM_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */
+-#define SND_PCM_AES1_PRO_MODE_SINGLE (4<<0) /* single channel */
+-#define SND_PCM_AES1_PRO_MODE_TWO (8<<0) /* two channels */
+-#define SND_PCM_AES1_PRO_MODE_PRIMARY (12<<0) /* primary/secondary */
+-#define SND_PCM_AES1_PRO_MODE_BYTE3 (15<<0) /* vector to byte 3 */
+-#define SND_PCM_AES1_PRO_USERBITS (15<<4) /* mask - user bits */
+-#define SND_PCM_AES1_PRO_USERBITS_NOTID (0<<4) /* not indicated */
+-#define SND_PCM_AES1_PRO_USERBITS_192 (8<<4) /* 192-bit structure */
+-#define SND_PCM_AES1_PRO_USERBITS_UDEF (12<<4) /* user defined application */
+-#define SND_PCM_AES1_CON_CATEGORY 0x7f
+-#define SND_PCM_AES1_CON_GENERAL 0x00
+-#define SND_PCM_AES1_CON_EXPERIMENTAL 0x40
+-#define SND_PCM_AES1_CON_SOLIDMEM_MASK 0x0f
+-#define SND_PCM_AES1_CON_SOLIDMEM_ID 0x08
+-#define SND_PCM_AES1_CON_BROADCAST1_MASK 0x07
+-#define SND_PCM_AES1_CON_BROADCAST1_ID 0x04
+-#define SND_PCM_AES1_CON_DIGDIGCONV_MASK 0x07
+-#define SND_PCM_AES1_CON_DIGDIGCONV_ID 0x02
+-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
+-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_ID 0x06
+-#define SND_PCM_AES1_CON_ADC_MASK 0x1f
+-#define SND_PCM_AES1_CON_ADC_ID 0x16
+-#define SND_PCM_AES1_CON_BROADCAST2_MASK 0x0f
+-#define SND_PCM_AES1_CON_BROADCAST2_ID 0x0e
+-#define SND_PCM_AES1_CON_LASEROPT_MASK 0x07
+-#define SND_PCM_AES1_CON_LASEROPT_ID 0x01
+-#define SND_PCM_AES1_CON_MUSICAL_MASK 0x07
+-#define SND_PCM_AES1_CON_MUSICAL_ID 0x05
+-#define SND_PCM_AES1_CON_MAGNETIC_MASK 0x07
+-#define SND_PCM_AES1_CON_MAGNETIC_ID 0x03
+-#define SND_PCM_AES1_CON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x00)
+-#define SND_PCM_AES1_CON_NON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x08)
+-#define SND_PCM_AES1_CON_PCM_CODER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x00)
+-#define SND_PCM_AES1_CON_SAMPLER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x20)
+-#define SND_PCM_AES1_CON_MIXER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x10)
+-#define SND_PCM_AES1_CON_RATE_CONVERTER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x18)
+-#define SND_PCM_AES1_CON_SYNTHESIZER (SND_PCM_AES1_CON_MUSICAL_ID|0x00)
+-#define SND_PCM_AES1_CON_MICROPHONE (SND_PCM_AES1_CON_MUSICAL_ID|0x08)
+-#define SND_PCM_AES1_CON_DAT (SND_PCM_AES1_CON_MAGNETIC_ID|0x00)
+-#define SND_PCM_AES1_CON_VCR (SND_PCM_AES1_CON_MAGNETIC_ID|0x08)
+-#define SND_PCM_AES1_CON_ORIGINAL (1<<7) /* this bits depends on the category code */
+-#define SND_PCM_AES2_PRO_SBITS (7<<0) /* mask - sample bits */
+-#define SND_PCM_AES2_PRO_SBITS_20 (2<<0) /* 20-bit - coordination */
+-#define SND_PCM_AES2_PRO_SBITS_24 (4<<0) /* 24-bit - main audio */
+-#define SND_PCM_AES2_PRO_SBITS_UDEF (6<<0) /* user defined application */
+-#define SND_PCM_AES2_PRO_WORDLEN (7<<3) /* mask - source word length */
+-#define SND_PCM_AES2_PRO_WORDLEN_NOTID (0<<3) /* not indicated */
+-#define SND_PCM_AES2_PRO_WORDLEN_22_18 (2<<3) /* 22-bit or 18-bit */
+-#define SND_PCM_AES2_PRO_WORDLEN_23_19 (4<<3) /* 23-bit or 19-bit */
+-#define SND_PCM_AES2_PRO_WORDLEN_24_20 (5<<3) /* 24-bit or 20-bit */
+-#define SND_PCM_AES2_PRO_WORDLEN_20_16 (6<<3) /* 20-bit or 16-bit */
+-#define SND_PCM_AES2_CON_SOURCE (15<<0) /* mask - source number */
+-#define SND_PCM_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */
+-#define SND_PCM_AES2_CON_CHANNEL (15<<4) /* mask - channel number */
+-#define SND_PCM_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */
+-#define SND_PCM_AES3_CON_FS (15<<0) /* mask - sample frequency */
+-#define SND_PCM_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */
+-#define SND_PCM_AES3_CON_FS_48000 (2<<0) /* 48kHz */
+-#define SND_PCM_AES3_CON_FS_32000 (3<<0) /* 32kHz */
+-#define SND_PCM_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */
+-#define SND_PCM_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */
+-#define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */
+-#define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */
+-
+-/*
+- * User interface
+- */
+-
+-/*
+- * in this loop, dmabuf.count signifies the amount of data that is
+- * waiting to be copied to the user's buffer. it is filled by the dma
+- * machine and drained by this loop.
+- */
+-static ssize_t
+-ymf_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct ymf_state *state = (struct ymf_state *)file->private_data;
+- struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf;
+- struct ymf_unit *unit = state->unit;
+- DECLARE_WAITQUEUE(waita, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned int swptr;
+- int cnt; /* This many to go in this revolution */
+-
+- if (dmabuf->mapped)
+- return -ENXIO;
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+- return ret;
+- ret = 0;
+-
+- add_wait_queue(&dmabuf->wait, &waita);
+- set_current_state(TASK_INTERRUPTIBLE);
+- while (count > 0) {
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (unit->suspended) {
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- schedule();
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (signal_pending(current)) {
+- if (!ret) ret = -EAGAIN;
+- break;
+- }
+- continue;
+- }
+- swptr = dmabuf->swptr;
+- cnt = dmabuf->dmasize - swptr;
+- if (dmabuf->count < cnt)
+- cnt = dmabuf->count;
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- unsigned long tmo;
+- /* buffer is empty, start the dma machine and wait for data to be
+- recorded */
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- if (!state->rpcm.running) {
+- ymf_capture_trigger(state->unit, &state->rpcm, 1);
+- }
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret) ret = -EAGAIN;
+- break;
+- }
+- /* This isnt strictly right for the 810 but it'll do */
+- tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2);
+- tmo >>= state->format.shift;
+- /* There are two situations when sleep_on_timeout returns, one is when
+- the interrupt is serviced correctly and the process is waked up by
+- ISR ON TIME. Another is when timeout is expired, which means that
+- either interrupt is NOT serviced correctly (pending interrupt) or it
+- is TOO LATE for the process to be scheduled to run (scheduler latency)
+- which results in a (potential) buffer overrun. And worse, there is
+- NOTHING we can do to prevent it. */
+- tmo = schedule_timeout(tmo);
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (tmo == 0 && dmabuf->count == 0) {
+- printk(KERN_ERR "ymfpci%d: recording schedule timeout, "
+- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+- state->unit->dev_audio,
+- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+- dmabuf->hwptr, dmabuf->swptr);
+- }
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- if (signal_pending(current)) {
+- if (!ret) ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+-
+- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
+- if (!ret) ret = -EFAULT;
+- break;
+- }
+-
+- swptr = (swptr + cnt) % dmabuf->dmasize;
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (unit->suspended) {
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- continue;
+- }
+-
+- dmabuf->swptr = swptr;
+- dmabuf->count -= cnt;
+- // spin_unlock_irqrestore(&unit->reg_lock, flags);
+-
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- // spin_lock_irqsave(&unit->reg_lock, flags);
+- if (!state->rpcm.running) {
+- ymf_capture_trigger(unit, &state->rpcm, 1);
+- }
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- }
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&dmabuf->wait, &waita);
+-
+- return ret;
+-}
+-
+-static ssize_t
+-ymf_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+-{
+- struct ymf_state *state = (struct ymf_state *)file->private_data;
+- struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
+- struct ymf_unit *unit = state->unit;
+- DECLARE_WAITQUEUE(waita, current);
+- ssize_t ret;
+- unsigned long flags;
+- unsigned int swptr;
+- int cnt; /* This many to go in this revolution */
+- int redzone;
+- int delay;
+-
+- YMFDBGW("ymf_write: count %d\n", count);
+-
+- if (dmabuf->mapped)
+- return -ENXIO;
+- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+- return ret;
+- ret = 0;
+-
+- /*
+- * Alan's cs46xx works without a red zone - marvel of ingenuity.
+- * We are not so brilliant... Red zone does two things:
+- * 1. allows for safe start after a pause as we have no way
+- * to know what the actual, relentlessly advancing, hwptr is.
+- * 2. makes computations in ymf_pcm_interrupt simpler.
+- */
+- redzone = ymf_calc_lend(state->format.rate) << state->format.shift;
+- redzone *= 3; /* 2 redzone + 1 possible uncertainty reserve. */
+-
+- add_wait_queue(&dmabuf->wait, &waita);
+- set_current_state(TASK_INTERRUPTIBLE);
+- while (count > 0) {
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (unit->suspended) {
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- schedule();
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (signal_pending(current)) {
+- if (!ret) ret = -EAGAIN;
+- break;
+- }
+- continue;
+- }
+- if (dmabuf->count < 0) {
+- printk(KERN_ERR
+- "ymf_write: count %d, was legal in cs46xx\n",
+- dmabuf->count);
+- dmabuf->count = 0;
+- }
+- if (dmabuf->count == 0) {
+- swptr = dmabuf->hwptr;
+- if (state->wpcm.running) {
+- /*
+- * Add uncertainty reserve.
+- */
+- cnt = ymf_calc_lend(state->format.rate);
+- cnt <<= state->format.shift;
+- if ((swptr += cnt) >= dmabuf->dmasize) {
+- swptr -= dmabuf->dmasize;
+- }
+- }
+- dmabuf->swptr = swptr;
+- } else {
+- /*
+- * XXX This is not right if dmabuf->count is small -
+- * about 2*x frame size or less. We cannot count on
+- * on appending and not causing an artefact.
+- * Should use a variation of the count==0 case above.
+- */
+- swptr = dmabuf->swptr;
+- }
+- cnt = dmabuf->dmasize - swptr;
+- if (dmabuf->count + cnt > dmabuf->dmasize - redzone)
+- cnt = (dmabuf->dmasize - redzone) - dmabuf->count;
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-
+- if (cnt > count)
+- cnt = count;
+- if (cnt <= 0) {
+- YMFDBGW("ymf_write: full, count %d swptr %d\n",
+- dmabuf->count, dmabuf->swptr);
+- /*
+- * buffer is full, start the dma machine and
+- * wait for data to be played
+- */
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (!state->wpcm.running) {
+- ymf_playback_trigger(unit, &state->wpcm, 1);
+- }
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- if (file->f_flags & O_NONBLOCK) {
+- if (!ret) ret = -EAGAIN;
+- break;
+- }
+- schedule();
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (signal_pending(current)) {
+- if (!ret) ret = -ERESTARTSYS;
+- break;
+- }
+- continue;
+- }
+- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+- if (!ret) ret = -EFAULT;
+- break;
+- }
+-
+- if ((swptr += cnt) >= dmabuf->dmasize) {
+- swptr -= dmabuf->dmasize;
+- }
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+- if (unit->suspended) {
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- continue;
+- }
+- dmabuf->swptr = swptr;
+- dmabuf->count += cnt;
+-
+- /*
+- * Start here is a bad idea - may cause startup click
+- * in /bin/play when dmabuf is not full yet.
+- * However, some broken applications do not make
+- * any use of SNDCTL_DSP_SYNC (Doom is the worst).
+- * One frame is about 5.3ms, Doom write size is 46ms.
+- */
+- delay = state->format.rate / 20; /* 50ms */
+- delay <<= state->format.shift;
+- if (dmabuf->count >= delay && !state->wpcm.running) {
+- ymf_playback_trigger(unit, &state->wpcm, 1);
+- }
+-
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-
+- count -= cnt;
+- buffer += cnt;
+- ret += cnt;
+- }
+-
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&dmabuf->wait, &waita);
+-
+- YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);
+- return ret;
+-}
+-
+-static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
+-{
+- struct ymf_state *state = (struct ymf_state *)file->private_data;
+- struct ymf_dmabuf *dmabuf;
+- int redzone;
+- unsigned long flags;
+- unsigned int mask = 0;
+-
+- if (file->f_mode & FMODE_WRITE)
+- poll_wait(file, &state->wpcm.dmabuf.wait, wait);
+- if (file->f_mode & FMODE_READ)
+- poll_wait(file, &state->rpcm.dmabuf.wait, wait);
+-
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- if (file->f_mode & FMODE_READ) {
+- dmabuf = &state->rpcm.dmabuf;
+- if (dmabuf->count >= (signed)dmabuf->fragsize)
+- mask |= POLLIN | POLLRDNORM;
+- }
+- if (file->f_mode & FMODE_WRITE) {
+- redzone = ymf_calc_lend(state->format.rate);
+- redzone <<= state->format.shift;
+- redzone *= 3;
+-
+- dmabuf = &state->wpcm.dmabuf;
+- if (dmabuf->mapped) {
+- if (dmabuf->count >= (signed)dmabuf->fragsize)
+- mask |= POLLOUT | POLLWRNORM;
+- } else {
+- /*
+- * Don't select unless a full fragment is available.
+- * Otherwise artsd does GETOSPACE, sees 0, and loops.
+- */
+- if (dmabuf->count + redzone + dmabuf->fragsize
+- <= dmabuf->dmasize)
+- mask |= POLLOUT | POLLWRNORM;
+- }
+- }
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+-
+- return mask;
+-}
+-
+-static int ymf_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct ymf_state *state = (struct ymf_state *)file->private_data;
+- struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
+- int ret;
+- unsigned long size;
+-
+- if (vma->vm_flags & VM_WRITE) {
+- if ((ret = prog_dmabuf(state, 0)) != 0)
+- return ret;
+- } else if (vma->vm_flags & VM_READ) {
+- if ((ret = prog_dmabuf(state, 1)) != 0)
+- return ret;
+- } else
+- return -EINVAL;
+-
+- if (vma->vm_pgoff != 0)
+- return -EINVAL;
+- size = vma->vm_end - vma->vm_start;
+- if (size > (PAGE_SIZE << dmabuf->buforder))
+- return -EINVAL;
+- if (remap_pfn_range(vma, vma->vm_start,
+- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
+- size, vma->vm_page_prot))
+- return -EAGAIN;
+- dmabuf->mapped = 1;
+-
+-/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
+- return 0;
+-}
+-
+-static int ymf_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct ymf_state *state = (struct ymf_state *)file->private_data;
+- struct ymf_dmabuf *dmabuf;
+- unsigned long flags;
+- audio_buf_info abinfo;
+- count_info cinfo;
+- int redzone;
+- int val;
+- void __user *argp = (void __user *)arg;
+- int __user *p = argp;
+-
+- switch (cmd) {
+- case OSS_GETVERSION:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
+- return put_user(SOUND_VERSION, p);
+-
+- case SNDCTL_DSP_RESET:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
+- if (file->f_mode & FMODE_WRITE) {
+- ymf_wait_dac(state);
+- dmabuf = &state->wpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- dmabuf->swptr = dmabuf->hwptr;
+- dmabuf->count = dmabuf->total_bytes = 0;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- if (file->f_mode & FMODE_READ) {
+- ymf_stop_adc(state);
+- dmabuf = &state->rpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- dmabuf->swptr = dmabuf->hwptr;
+- dmabuf->count = dmabuf->total_bytes = 0;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_SYNC:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
+- if (file->f_mode & FMODE_WRITE) {
+- dmabuf = &state->wpcm.dmabuf;
+- if (file->f_flags & O_NONBLOCK) {
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- if (dmabuf->count != 0 && !state->wpcm.running) {
+- ymf_start_dac(state);
+- }
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- } else {
+- ymf_wait_dac(state);
+- }
+- }
+- /* XXX What does this do for reading? dmabuf->count=0; ? */
+- return 0;
+-
+- case SNDCTL_DSP_SPEED: /* set smaple rate */
+- if (get_user(val, p))
+- return -EFAULT;
+- YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
+- if (val >= 8000 && val <= 48000) {
+- if (file->f_mode & FMODE_WRITE) {
+- ymf_wait_dac(state);
+- dmabuf = &state->wpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- state->format.rate = val;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- if (file->f_mode & FMODE_READ) {
+- ymf_stop_adc(state);
+- dmabuf = &state->rpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- state->format.rate = val;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- }
+- return put_user(state->format.rate, p);
+-
+- /*
+- * OSS manual does not mention SNDCTL_DSP_STEREO at all.
+- * All channels are mono and if you want stereo, you
+- * play into two channels with SNDCTL_DSP_CHANNELS.
+- * However, mpg123 calls it. I wonder, why Michael Hipp used it.
+- */
+- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
+- if (get_user(val, p))
+- return -EFAULT;
+- YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
+- if (file->f_mode & FMODE_WRITE) {
+- ymf_wait_dac(state);
+- dmabuf = &state->wpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- state->format.voices = val ? 2 : 1;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- if (file->f_mode & FMODE_READ) {
+- ymf_stop_adc(state);
+- dmabuf = &state->rpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- state->format.voices = val ? 2 : 1;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- return 0;
+-
+- case SNDCTL_DSP_GETBLKSIZE:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
+- if (file->f_mode & FMODE_WRITE) {
+- if ((val = prog_dmabuf(state, 0)))
+- return val;
+- val = state->wpcm.dmabuf.fragsize;
+- YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
+- return put_user(val, p);
+- }
+- if (file->f_mode & FMODE_READ) {
+- if ((val = prog_dmabuf(state, 1)))
+- return val;
+- val = state->rpcm.dmabuf.fragsize;
+- YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
+- return put_user(val, p);
+- }
+- return -EINVAL;
+-
+- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
+- return put_user(AFMT_S16_LE|AFMT_U8, p);
+-
+- case SNDCTL_DSP_SETFMT: /* Select sample format */
+- if (get_user(val, p))
+- return -EFAULT;
+- YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
+- if (val == AFMT_S16_LE || val == AFMT_U8) {
+- if (file->f_mode & FMODE_WRITE) {
+- ymf_wait_dac(state);
+- dmabuf = &state->wpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- state->format.format = val;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- if (file->f_mode & FMODE_READ) {
+- ymf_stop_adc(state);
+- dmabuf = &state->rpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf->ready = 0;
+- state->format.format = val;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- }
+- return put_user(state->format.format, p);
+-
+- case SNDCTL_DSP_CHANNELS:
+- if (get_user(val, p))
+- return -EFAULT;
+- YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
+- if (val != 0) {
+- if (file->f_mode & FMODE_WRITE) {
+- ymf_wait_dac(state);
+- if (val == 1 || val == 2) {
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf = &state->wpcm.dmabuf;
+- dmabuf->ready = 0;
+- state->format.voices = val;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- }
+- if (file->f_mode & FMODE_READ) {
+- ymf_stop_adc(state);
+- if (val == 1 || val == 2) {
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- dmabuf = &state->rpcm.dmabuf;
+- dmabuf->ready = 0;
+- state->format.voices = val;
+- ymf_pcm_update_shift(&state->format);
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- }
+- }
+- }
+- return put_user(state->format.voices, p);
+-
+- case SNDCTL_DSP_POST:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
+- /*
+- * Quoting OSS PG:
+- * The ioctl SNDCTL_DSP_POST is a lightweight version of
+- * SNDCTL_DSP_SYNC. It just tells to the driver that there
+- * is likely to be a pause in the output. This makes it
+- * possible for the device to handle the pause more
+- * intelligently. This ioctl doesn't block the application.
+- *
+- * The paragraph above is a clumsy way to say "flush ioctl".
+- * This ioctl is used by mpg123.
+- */
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {
+- ymf_start_dac(state);
+- }
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- return 0;
+-
+- case SNDCTL_DSP_SETFRAGMENT:
+- if (get_user(val, p))
+- return -EFAULT;
+- YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
+- cmd,
+- (val >> 16) & 0xFFFF, val & 0xFFFF,
+- (val >> 16) & 0xFFFF, val & 0xFFFF);
+- dmabuf = &state->wpcm.dmabuf;
+- dmabuf->ossfragshift = val & 0xffff;
+- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+- if (dmabuf->ossfragshift < 4)
+- dmabuf->ossfragshift = 4;
+- if (dmabuf->ossfragshift > 15)
+- dmabuf->ossfragshift = 15;
+- return 0;
+-
+- case SNDCTL_DSP_GETOSPACE:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- dmabuf = &state->wpcm.dmabuf;
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+- return val;
+- redzone = ymf_calc_lend(state->format.rate);
+- redzone <<= state->format.shift;
+- redzone *= 3;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- abinfo.fragsize = dmabuf->fragsize;
+- abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
+- abinfo.fragstotal = dmabuf->numfrag;
+- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETISPACE:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- dmabuf = &state->rpcm.dmabuf;
+- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
+- return val;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- abinfo.fragsize = dmabuf->fragsize;
+- abinfo.bytes = dmabuf->count;
+- abinfo.fragstotal = dmabuf->numfrag;
+- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_NONBLOCK:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
+- file->f_flags |= O_NONBLOCK;
+- return 0;
+-
+- case SNDCTL_DSP_GETCAPS:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
+- /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
+- p); */
+- return put_user(0, p);
+-
+- case SNDCTL_DSP_GETIPTR:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
+- if (!(file->f_mode & FMODE_READ))
+- return -EINVAL;
+- dmabuf = &state->rpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- cinfo.bytes = dmabuf->total_bytes;
+- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+- cinfo.ptr = dmabuf->hwptr;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
+- cinfo.ptr, cinfo.bytes);
+- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_GETOPTR:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
+- if (!(file->f_mode & FMODE_WRITE))
+- return -EINVAL;
+- dmabuf = &state->wpcm.dmabuf;
+- spin_lock_irqsave(&state->unit->reg_lock, flags);
+- cinfo.bytes = dmabuf->total_bytes;
+- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+- cinfo.ptr = dmabuf->hwptr;
+- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+- YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
+- cinfo.ptr, cinfo.bytes);
+- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
+-
+- case SNDCTL_DSP_SETDUPLEX:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
+- return 0; /* Always duplex */
+-
+- case SOUND_PCM_READ_RATE:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
+- return put_user(state->format.rate, p);
+-
+- case SOUND_PCM_READ_CHANNELS:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
+- return put_user(state->format.voices, p);
+-
+- case SOUND_PCM_READ_BITS:
+- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
+- return put_user(AFMT_S16_LE, p);
+-
+- case SNDCTL_DSP_MAPINBUF:
+- case SNDCTL_DSP_MAPOUTBUF:
+- case SNDCTL_DSP_SETSYNCRO:
+- case SOUND_PCM_WRITE_FILTER:
+- case SOUND_PCM_READ_FILTER:
+- YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);
+- return -ENOTTY;
+-
+- default:
+- /*
+- * Some programs mix up audio devices and ioctls
+- * or perhaps they expect "universal" ioctls,
+- * for instance we get SNDCTL_TMR_CONTINUE here.
+- * (mpg123 -g 100 ends here too - to be fixed.)
+- */
+- YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
+- break;
+- }
+- return -ENOTTY;
+-}
+-
+-/*
+- * open(2)
+- * We use upper part of the minor to distinguish between soundcards.
+- * Channels are opened with a clone open.
+- */
+-static int ymf_open(struct inode *inode, struct file *file)
+-{
+- struct list_head *list;
+- ymfpci_t *unit = NULL;
+- int minor;
+- struct ymf_state *state;
+- int err;
+-
+- minor = iminor(inode);
+- if ((minor & 0x0F) == 3) { /* /dev/dspN */
+- ;
+- } else {
+- return -ENXIO;
+- }
+-
+- unit = NULL; /* gcc warns */
+- spin_lock(&ymf_devs_lock);
+- list_for_each(list, &ymf_devs) {
+- unit = list_entry(list, ymfpci_t, ymf_devs);
+- if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
+- break;
+- }
+- spin_unlock(&ymf_devs_lock);
+- if (unit == NULL)
+- return -ENODEV;
+-
+- mutex_lock(&unit->open_mutex);
+-
+- if ((state = ymf_state_alloc(unit)) == NULL) {
+- mutex_unlock(&unit->open_mutex);
+- return -ENOMEM;
+- }
+- list_add_tail(&state->chain, &unit->states);
+-
+- file->private_data = state;
+-
+- /*
+- * ymf_read and ymf_write that we borrowed from cs46xx
+- * allocate buffers with prog_dmabuf(). We call prog_dmabuf
+- * here so that in case of DMA memory exhaustion open
+- * fails rather than write.
+- *
+- * XXX prog_dmabuf allocates voice. Should allocate explicitly, above.
+- */
+- if (file->f_mode & FMODE_WRITE) {
+- if (!state->wpcm.dmabuf.ready) {
+- if ((err = prog_dmabuf(state, 0)) != 0) {
+- goto out_nodma;
+- }
+- }
+- }
+- if (file->f_mode & FMODE_READ) {
+- if (!state->rpcm.dmabuf.ready) {
+- if ((err = prog_dmabuf(state, 1)) != 0) {
+- goto out_nodma;
+- }
+- }
+- }
+-
+-#if 0 /* test if interrupts work */
+- ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
+- ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
+- (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
+-#endif
+- mutex_unlock(&unit->open_mutex);
+-
+- return nonseekable_open(inode, file);
+-
+-out_nodma:
+- /*
+- * XXX Broken custom: "goto out_xxx" in other place is
+- * a nestable exception, but here it is not nestable due to semaphore.
+- * XXX Doubtful technique of self-describing objects....
+- */
+- dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+- dealloc_dmabuf(unit, &state->rpcm.dmabuf);
+- ymf_pcm_free_substream(&state->wpcm);
+- ymf_pcm_free_substream(&state->rpcm);
+-
+- list_del(&state->chain);
+- kfree(state);
+-
+- mutex_unlock(&unit->open_mutex);
+- return err;
+-}
+-
+-static int ymf_release(struct inode *inode, struct file *file)
+-{
+- struct ymf_state *state = (struct ymf_state *)file->private_data;
+- ymfpci_t *unit = state->unit;
+-
+-#if 0 /* test if interrupts work */
+- ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
+-#endif
+-
+- mutex_lock(&unit->open_mutex);
+-
+- /*
+- * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
+- * Deallocate when unloading the driver and we can wait.
+- */
+- ymf_wait_dac(state);
+- ymf_stop_adc(state); /* fortunately, it's immediate */
+- dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+- dealloc_dmabuf(unit, &state->rpcm.dmabuf);
+- ymf_pcm_free_substream(&state->wpcm);
+- ymf_pcm_free_substream(&state->rpcm);
+-
+- list_del(&state->chain);
+- file->private_data = NULL; /* Can you tell I programmed Solaris */
+- kfree(state);
+-
+- mutex_unlock(&unit->open_mutex);
+-
+- return 0;
+-}
+-
+-/*
+- * Mixer operations are based on cs46xx.
+- */
+-static int ymf_open_mixdev(struct inode *inode, struct file *file)
+-{
+- int minor = iminor(inode);
+- struct list_head *list;
+- ymfpci_t *unit;
+- int i;
+-
+- spin_lock(&ymf_devs_lock);
+- list_for_each(list, &ymf_devs) {
+- unit = list_entry(list, ymfpci_t, ymf_devs);
+- for (i = 0; i < NR_AC97; i++) {
+- if (unit->ac97_codec[i] != NULL &&
+- unit->ac97_codec[i]->dev_mixer == minor) {
+- spin_unlock(&ymf_devs_lock);
+- goto match;
+- }
+- }
+- }
+- spin_unlock(&ymf_devs_lock);
+- return -ENODEV;
+-
+- match:
+- file->private_data = unit->ac97_codec[i];
+-
+- return nonseekable_open(inode, file);
+-}
+-
+-static int ymf_ioctl_mixdev(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+-
+- return codec->mixer_ioctl(codec, cmd, arg);
+-}
+-
+-static int ymf_release_mixdev(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-static /*const*/ struct file_operations ymf_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .read = ymf_read,
+- .write = ymf_write,
+- .poll = ymf_poll,
+- .ioctl = ymf_ioctl,
+- .mmap = ymf_mmap,
+- .open = ymf_open,
+- .release = ymf_release,
+-};
+-
+-static /*const*/ struct file_operations ymf_mixer_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .ioctl = ymf_ioctl_mixdev,
+- .open = ymf_open_mixdev,
+- .release = ymf_release_mixdev,
+-};
+-
+-/*
+- */
+-
+-static int ymf_suspend(struct pci_dev *pcidev, pm_message_t unused)
+-{
+- struct ymf_unit *unit = pci_get_drvdata(pcidev);
+- unsigned long flags;
+- struct ymf_dmabuf *dmabuf;
+- struct list_head *p;
+- struct ymf_state *state;
+- struct ac97_codec *codec;
+- int i;
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+-
+- unit->suspended = 1;
+-
+- for (i = 0; i < NR_AC97; i++) {
+- if ((codec = unit->ac97_codec[i]) != NULL)
+- ac97_save_state(codec);
+- }
+-
+- list_for_each(p, &unit->states) {
+- state = list_entry(p, struct ymf_state, chain);
+-
+- dmabuf = &state->wpcm.dmabuf;
+- dmabuf->hwptr = dmabuf->swptr = 0;
+- dmabuf->total_bytes = 0;
+- dmabuf->count = 0;
+-
+- dmabuf = &state->rpcm.dmabuf;
+- dmabuf->hwptr = dmabuf->swptr = 0;
+- dmabuf->total_bytes = 0;
+- dmabuf->count = 0;
+- }
+-
+- ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0);
+- ymfpci_disable_dsp(unit);
+-
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+-
+- return 0;
+-}
+-
+-static int ymf_resume(struct pci_dev *pcidev)
+-{
+- struct ymf_unit *unit = pci_get_drvdata(pcidev);
+- unsigned long flags;
+- struct list_head *p;
+- struct ymf_state *state;
+- struct ac97_codec *codec;
+- int i;
+-
+- ymfpci_aclink_reset(unit->pci);
+- ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+- /* XXX At this time the legacy registers are probably deprogrammed. */
+-#endif
+-
+- ymfpci_download_image(unit);
+-
+- ymf_memload(unit);
+-
+- spin_lock_irqsave(&unit->reg_lock, flags);
+-
+- if (unit->start_count) {
+- ymfpci_writel(unit, YDSXGR_MODE, 3);
+- unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
+- }
+-
+- for (i = 0; i < NR_AC97; i++) {
+- if ((codec = unit->ac97_codec[i]) != NULL)
+- ac97_restore_state(codec);
+- }
+-
+- unit->suspended = 0;
+- list_for_each(p, &unit->states) {
+- state = list_entry(p, struct ymf_state, chain);
+- wake_up(&state->wpcm.dmabuf.wait);
+- wake_up(&state->rpcm.dmabuf.wait);
+- }
+-
+- spin_unlock_irqrestore(&unit->reg_lock, flags);
+- return 0;
+-}
+-
+-/*
+- * initialization routines
+- */
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+-
+-static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev)
+-{
+- int v;
+- int mpuio = -1, oplio = -1;
+-
+- switch (unit->iomidi) {
+- case 0x330:
+- mpuio = 0;
+- break;
+- case 0x300:
+- mpuio = 1;
+- break;
+- case 0x332:
+- mpuio = 2;
+- break;
+- case 0x334:
+- mpuio = 3;
+- break;
+- default: ;
+- }
+-
+- switch (unit->iosynth) {
+- case 0x388:
+- oplio = 0;
+- break;
+- case 0x398:
+- oplio = 1;
+- break;
+- case 0x3a0:
+- oplio = 2;
+- break;
+- case 0x3a8:
+- oplio = 3;
+- break;
+- default: ;
+- }
+-
+- if (mpuio >= 0 || oplio >= 0) {
+- /* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */
+- v = 0x001e;
+- pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
+-
+- switch (pcidev->device) {
+- case PCI_DEVICE_ID_YAMAHA_724:
+- case PCI_DEVICE_ID_YAMAHA_740:
+- case PCI_DEVICE_ID_YAMAHA_724F:
+- case PCI_DEVICE_ID_YAMAHA_740C:
+- v = 0x8800;
+- if (mpuio >= 0) { v |= mpuio<<4; }
+- if (oplio >= 0) { v |= oplio; }
+- pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+- break;
+-
+- case PCI_DEVICE_ID_YAMAHA_744:
+- case PCI_DEVICE_ID_YAMAHA_754:
+- v = 0x8800;
+- pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+- if (oplio >= 0) {
+- pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth);
+- }
+- if (mpuio >= 0) {
+- pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi);
+- }
+- break;
+-
+- default:
+- printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n",
+- pcidev->device);
+- return -EINVAL;
+- }
+- }
+-
+- return 0;
+-}
+-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+-
+-static void ymfpci_aclink_reset(struct pci_dev * pci)
+-{
+- u8 cmd;
+-
+- /*
+- * In the 744, 754 only 0x01 exists, 0x02 is undefined.
+- * It does not seem to hurt to trip both regardless of revision.
+- */
+- pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
+- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
+- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+-
+- pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
+- pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
+-}
+-
+-static void ymfpci_enable_dsp(ymfpci_t *codec)
+-{
+- ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000001);
+-}
+-
+-static void ymfpci_disable_dsp(ymfpci_t *codec)
+-{
+- u32 val;
+- int timeout = 1000;
+-
+- val = ymfpci_readl(codec, YDSXGR_CONFIG);
+- if (val)
+- ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000);
+- while (timeout-- > 0) {
+- val = ymfpci_readl(codec, YDSXGR_STATUS);
+- if ((val & 0x00000002) == 0)
+- break;
+- }
+-}
+-
+-#include "ymfpci_image.h"
+-
+-static void ymfpci_download_image(ymfpci_t *codec)
+-{
+- int i, ver_1e;
+- u16 ctrl;
+-
+- ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
+- ymfpci_disable_dsp(codec);
+- ymfpci_writel(codec, YDSXGR_MODE, 0x00010000);
+- ymfpci_writel(codec, YDSXGR_MODE, 0x00000000);
+- ymfpci_writel(codec, YDSXGR_MAPOFREC, 0x00000000);
+- ymfpci_writel(codec, YDSXGR_MAPOFEFFECT, 0x00000000);
+- ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0x00000000);
+- ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0x00000000);
+- ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0x00000000);
+- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
+- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
+-
+- /* setup DSP instruction code */
+- for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
+- ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
+-
+- switch (codec->pci->device) {
+- case PCI_DEVICE_ID_YAMAHA_724F:
+- case PCI_DEVICE_ID_YAMAHA_740C:
+- case PCI_DEVICE_ID_YAMAHA_744:
+- case PCI_DEVICE_ID_YAMAHA_754:
+- ver_1e = 1;
+- break;
+- default:
+- ver_1e = 0;
+- }
+-
+- if (ver_1e) {
+- /* setup control instruction code */
+- for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
+- ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]);
+- } else {
+- for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
+- ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]);
+- }
+-
+- ymfpci_enable_dsp(codec);
+-
+- /* 0.02s sounds not too bad, we may do schedule_timeout() later. */
+- mdelay(20); /* seems we need some delay after downloading image.. */
+-}
+-
+-static int ymfpci_memalloc(ymfpci_t *codec)
+-{
+- unsigned int playback_ctrl_size;
+- unsigned int bank_size_playback;
+- unsigned int bank_size_capture;
+- unsigned int bank_size_effect;
+- unsigned int size;
+- unsigned int off;
+- char *ptr;
+- dma_addr_t pba;
+- int voice, bank;
+-
+- playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
+- bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
+- bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
+- bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
+- codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
+-
+- size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
+- ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
+- ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
+- ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
+- codec->work_size;
+-
+- ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
+- if (ptr == NULL)
+- return -ENOMEM;
+- codec->dma_area_va = ptr;
+- codec->dma_area_ba = pba;
+- codec->dma_area_size = size + 0xff;
+-
+- off = (unsigned long)ptr & 0xff;
+- if (off) {
+- ptr += 0x100 - off;
+- pba += 0x100 - off;
+- }
+-
+- /*
+- * Hardware requires only ptr[playback_ctrl_size] zeroed,
+- * but in our judgement it is a wrong kind of savings, so clear it all.
+- */
+- memset(ptr, 0, size);
+-
+- codec->ctrl_playback = (u32 *)ptr;
+- codec->ctrl_playback_ba = pba;
+- codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
+- ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+- pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+-
+- off = 0;
+- for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
+- codec->voices[voice].number = voice;
+- codec->voices[voice].bank =
+- (ymfpci_playback_bank_t *) (ptr + off);
+- codec->voices[voice].bank_ba = pba + off;
+- off += 2 * bank_size_playback; /* 2 banks */
+- }
+- off = (off + 0xff) & ~0xff;
+- ptr += off;
+- pba += off;
+-
+- off = 0;
+- codec->bank_base_capture = pba;
+- for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
+- for (bank = 0; bank < 2; bank++) {
+- codec->bank_capture[voice][bank] =
+- (ymfpci_capture_bank_t *) (ptr + off);
+- off += bank_size_capture;
+- }
+- off = (off + 0xff) & ~0xff;
+- ptr += off;
+- pba += off;
+-
+- off = 0;
+- codec->bank_base_effect = pba;
+- for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
+- for (bank = 0; bank < 2; bank++) {
+- codec->bank_effect[voice][bank] =
+- (ymfpci_effect_bank_t *) (ptr + off);
+- off += bank_size_effect;
+- }
+- off = (off + 0xff) & ~0xff;
+- ptr += off;
+- pba += off;
+-
+- codec->work_base = pba;
+-
+- return 0;
+-}
+-
+-static void ymfpci_memfree(ymfpci_t *codec)
+-{
+- ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0);
+- ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0);
+- ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
+- ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
+- ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
+- pci_free_consistent(codec->pci,
+- codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
+-}
+-
+-static void ymf_memload(ymfpci_t *unit)
+-{
+-
+- ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
+- ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
+- ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
+- ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
+- ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
+-
+- /* S/PDIF output initialization */
+- ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0);
+- ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS,
+- SND_PCM_AES0_CON_EMPHASIS_NONE |
+- (SND_PCM_AES1_CON_ORIGINAL << 8) |
+- (SND_PCM_AES1_CON_PCM_CODER << 8));
+-
+- /* S/PDIF input initialization */
+- ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0);
+-
+- /* move this volume setup to mixer */
+- ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
+- ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0);
+- ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
+- ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
+-}
+-
+-static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
+-{
+- struct ac97_codec *codec;
+- u16 eid;
+-
+- if ((codec = ac97_alloc_codec()) == NULL)
+- return -ENOMEM;
+-
+- /* initialize some basic codec information, other fields will be filled
+- in ac97_probe_codec */
+- codec->private_data = unit;
+- codec->id = num_ac97;
+-
+- codec->codec_read = ymfpci_codec_read;
+- codec->codec_write = ymfpci_codec_write;
+-
+- if (ac97_probe_codec(codec) == 0) {
+- printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
+- goto out_kfree;
+- }
+-
+- eid = ymfpci_codec_read(codec, AC97_EXTENDED_ID);
+- if (eid==0xFFFF) {
+- printk(KERN_WARNING "ymfpci: no codec attached ?\n");
+- goto out_kfree;
+- }
+-
+- unit->ac97_features = eid;
+-
+- if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) {
+- printk(KERN_ERR "ymfpci: couldn't register mixer!\n");
+- goto out_kfree;
+- }
+-
+- unit->ac97_codec[num_ac97] = codec;
+-
+- return 0;
+- out_kfree:
+- ac97_release_codec(codec);
+- return -ENODEV;
+-}
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+-# ifdef MODULE
+-static int mpu_io;
+-static int synth_io;
+-module_param(mpu_io, int, 0);
+-module_param(synth_io, int, 0);
+-# else
+-static int mpu_io = 0x330;
+-static int synth_io = 0x388;
+-# endif
+-static int assigned;
+-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+-
+-static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
+-{
+- u16 ctrl;
+- unsigned long base;
+- ymfpci_t *codec;
+-
+- int err;
+-
+- if ((err = pci_enable_device(pcidev)) != 0) {
+- printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
+- return err;
+- }
+- base = pci_resource_start(pcidev, 0);
+-
+- if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
+- printk(KERN_ERR "ymfpci: no core\n");
+- return -ENOMEM;
+- }
+- memset(codec, 0, sizeof(*codec));
+-
+- spin_lock_init(&codec->reg_lock);
+- spin_lock_init(&codec->voice_lock);
+- spin_lock_init(&codec->ac97_lock);
+- mutex_init(&codec->open_mutex);
+- INIT_LIST_HEAD(&codec->states);
+- codec->pci = pcidev;
+-
+- pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
+-
+- if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
+- printk(KERN_ERR "ymfpci: unable to request mem region\n");
+- goto out_free;
+- }
+-
+- if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
+- printk(KERN_ERR "ymfpci: unable to map registers\n");
+- goto out_release_region;
+- }
+-
+- pci_set_master(pcidev);
+-
+- printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
+- (char *)ent->driver_data, base, pcidev->irq);
+-
+- ymfpci_aclink_reset(pcidev);
+- if (ymfpci_codec_ready(codec, 0, 1) < 0)
+- goto out_unmap;
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+- if (assigned == 0) {
+- codec->iomidi = mpu_io;
+- codec->iosynth = synth_io;
+- if (ymfpci_setup_legacy(codec, pcidev) < 0)
+- goto out_unmap;
+- assigned = 1;
+- }
+-#endif
+-
+- ymfpci_download_image(codec);
+-
+- if (ymfpci_memalloc(codec) < 0)
+- goto out_disable_dsp;
+- ymf_memload(codec);
+-
+- if (request_irq(pcidev->irq, ymf_interrupt, IRQF_SHARED, "ymfpci", codec) != 0) {
+- printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
+- pcidev->irq);
+- goto out_memfree;
+- }
+-
+- /* register /dev/dsp */
+- if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
+- printk(KERN_ERR "ymfpci: unable to register dsp\n");
+- goto out_free_irq;
+- }
+-
+- /*
+- * Poke just the primary for the moment.
+- */
+- if ((err = ymf_ac97_init(codec, 0)) != 0)
+- goto out_unregister_sound_dsp;
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+- codec->opl3_data.name = "ymfpci";
+- codec->mpu_data.name = "ymfpci";
+-
+- codec->opl3_data.io_base = codec->iosynth;
+- codec->opl3_data.irq = -1;
+-
+- codec->mpu_data.io_base = codec->iomidi;
+- codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */
+-
+- if (codec->iomidi) {
+- if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
+- codec->iomidi = 0; /* XXX kludge */
+- }
+- }
+-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+-
+- /* put it into driver list */
+- spin_lock(&ymf_devs_lock);
+- list_add_tail(&codec->ymf_devs, &ymf_devs);
+- spin_unlock(&ymf_devs_lock);
+- pci_set_drvdata(pcidev, codec);
+-
+- return 0;
+-
+- out_unregister_sound_dsp:
+- unregister_sound_dsp(codec->dev_audio);
+- out_free_irq:
+- free_irq(pcidev->irq, codec);
+- out_memfree:
+- ymfpci_memfree(codec);
+- out_disable_dsp:
+- ymfpci_disable_dsp(codec);
+- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
+- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
+- ymfpci_writel(codec, YDSXGR_STATUS, ~0);
+- out_unmap:
+- iounmap(codec->reg_area_virt);
+- out_release_region:
+- release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
+- out_free:
+- if (codec->ac97_codec[0])
+- ac97_release_codec(codec->ac97_codec[0]);
+- return -ENODEV;
+-}
+-
+-static void __devexit ymf_remove_one(struct pci_dev *pcidev)
+-{
+- __u16 ctrl;
+- ymfpci_t *codec = pci_get_drvdata(pcidev);
+-
+- /* remove from list of devices */
+- spin_lock(&ymf_devs_lock);
+- list_del(&codec->ymf_devs);
+- spin_unlock(&ymf_devs_lock);
+-
+- unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer);
+- ac97_release_codec(codec->ac97_codec[0]);
+- unregister_sound_dsp(codec->dev_audio);
+- free_irq(pcidev->irq, codec);
+- ymfpci_memfree(codec);
+- ymfpci_writel(codec, YDSXGR_STATUS, ~0);
+- ymfpci_disable_dsp(codec);
+- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
+- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
+- iounmap(codec->reg_area_virt);
+- release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+- if (codec->iomidi) {
+- unload_uart401(&codec->mpu_data);
+- }
+-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+-}
+-
+-MODULE_AUTHOR("Jaroslav Kysela");
+-MODULE_DESCRIPTION("Yamaha YMF7xx PCI Audio");
+-MODULE_LICENSE("GPL");
+-
+-static struct pci_driver ymfpci_driver = {
+- .name = "ymfpci",
+- .id_table = ymf_id_tbl,
+- .probe = ymf_probe_one,
+- .remove = __devexit_p(ymf_remove_one),
+- .suspend = ymf_suspend,
+- .resume = ymf_resume
+-};
+-
+-static int __init ymf_init_module(void)
+-{
+- return pci_register_driver(&ymfpci_driver);
+-}
+-
+-static void __exit ymf_cleanup_module (void)
+-{
+- pci_unregister_driver(&ymfpci_driver);
+-}
+-
+-module_init(ymf_init_module);
+-module_exit(ymf_cleanup_module);
+diff --git a/sound/oss/ymfpci.h b/sound/oss/ymfpci.h
+deleted file mode 100644
+index ac1785f..0000000
+--- a/sound/oss/ymfpci.h
++++ /dev/null
+@@ -1,361 +0,0 @@
+-#ifndef __YMFPCI_H
+-#define __YMFPCI_H
+-
+-/*
+- * Copyright (c) by Jaroslav Kysela <perex at suse.cz>
+- * Definitions for Yahama YMF724/740/744/754 chips
+- *
+- *
+- * 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/config.h>
+-#include <linux/mutex.h>
+-
+-/*
+- * Direct registers
+- */
+-
+-/* #define YMFREG(codec, reg) (codec->port + YDSXGR_##reg) */
+-
+-#define YDSXGR_INTFLAG 0x0004
+-#define YDSXGR_ACTIVITY 0x0006
+-#define YDSXGR_GLOBALCTRL 0x0008
+-#define YDSXGR_ZVCTRL 0x000A
+-#define YDSXGR_TIMERCTRL 0x0010
+-#define YDSXGR_TIMERCTRL_TEN 0x0001
+-#define YDSXGR_TIMERCTRL_TIEN 0x0002
+-#define YDSXGR_TIMERCOUNT 0x0012
+-#define YDSXGR_SPDIFOUTCTRL 0x0018
+-#define YDSXGR_SPDIFOUTSTATUS 0x001C
+-#define YDSXGR_EEPROMCTRL 0x0020
+-#define YDSXGR_SPDIFINCTRL 0x0034
+-#define YDSXGR_SPDIFINSTATUS 0x0038
+-#define YDSXGR_DSPPROGRAMDL 0x0048
+-#define YDSXGR_DLCNTRL 0x004C
+-#define YDSXGR_GPIOININTFLAG 0x0050
+-#define YDSXGR_GPIOININTENABLE 0x0052
+-#define YDSXGR_GPIOINSTATUS 0x0054
+-#define YDSXGR_GPIOOUTCTRL 0x0056
+-#define YDSXGR_GPIOFUNCENABLE 0x0058
+-#define YDSXGR_GPIOTYPECONFIG 0x005A
+-#define YDSXGR_AC97CMDDATA 0x0060
+-#define YDSXGR_AC97CMDADR 0x0062
+-#define YDSXGR_PRISTATUSDATA 0x0064
+-#define YDSXGR_PRISTATUSADR 0x0066
+-#define YDSXGR_SECSTATUSDATA 0x0068
+-#define YDSXGR_SECSTATUSADR 0x006A
+-#define YDSXGR_SECCONFIG 0x0070
+-#define YDSXGR_LEGACYOUTVOL 0x0080
+-#define YDSXGR_LEGACYOUTVOLL 0x0080
+-#define YDSXGR_LEGACYOUTVOLR 0x0082
+-#define YDSXGR_NATIVEDACOUTVOL 0x0084
+-#define YDSXGR_NATIVEDACOUTVOLL 0x0084
+-#define YDSXGR_NATIVEDACOUTVOLR 0x0086
+-#define YDSXGR_SPDIFOUTVOL 0x0088
+-#define YDSXGR_SPDIFOUTVOLL 0x0088
+-#define YDSXGR_SPDIFOUTVOLR 0x008A
+-#define YDSXGR_AC3OUTVOL 0x008C
+-#define YDSXGR_AC3OUTVOLL 0x008C
+-#define YDSXGR_AC3OUTVOLR 0x008E
+-#define YDSXGR_PRIADCOUTVOL 0x0090
+-#define YDSXGR_PRIADCOUTVOLL 0x0090
+-#define YDSXGR_PRIADCOUTVOLR 0x0092
+-#define YDSXGR_LEGACYLOOPVOL 0x0094
+-#define YDSXGR_LEGACYLOOPVOLL 0x0094
+-#define YDSXGR_LEGACYLOOPVOLR 0x0096
+-#define YDSXGR_NATIVEDACLOOPVOL 0x0098
+-#define YDSXGR_NATIVEDACLOOPVOLL 0x0098
+-#define YDSXGR_NATIVEDACLOOPVOLR 0x009A
+-#define YDSXGR_SPDIFLOOPVOL 0x009C
+-#define YDSXGR_SPDIFLOOPVOLL 0x009E
+-#define YDSXGR_SPDIFLOOPVOLR 0x009E
+-#define YDSXGR_AC3LOOPVOL 0x00A0
+-#define YDSXGR_AC3LOOPVOLL 0x00A0
+-#define YDSXGR_AC3LOOPVOLR 0x00A2
+-#define YDSXGR_PRIADCLOOPVOL 0x00A4
+-#define YDSXGR_PRIADCLOOPVOLL 0x00A4
+-#define YDSXGR_PRIADCLOOPVOLR 0x00A6
+-#define YDSXGR_NATIVEADCINVOL 0x00A8
+-#define YDSXGR_NATIVEADCINVOLL 0x00A8
+-#define YDSXGR_NATIVEADCINVOLR 0x00AA
+-#define YDSXGR_NATIVEDACINVOL 0x00AC
+-#define YDSXGR_NATIVEDACINVOLL 0x00AC
+-#define YDSXGR_NATIVEDACINVOLR 0x00AE
+-#define YDSXGR_BUF441OUTVOL 0x00B0
+-#define YDSXGR_BUF441OUTVOLL 0x00B0
+-#define YDSXGR_BUF441OUTVOLR 0x00B2
+-#define YDSXGR_BUF441LOOPVOL 0x00B4
+-#define YDSXGR_BUF441LOOPVOLL 0x00B4
+-#define YDSXGR_BUF441LOOPVOLR 0x00B6
+-#define YDSXGR_SPDIFOUTVOL2 0x00B8
+-#define YDSXGR_SPDIFOUTVOL2L 0x00B8
+-#define YDSXGR_SPDIFOUTVOL2R 0x00BA
+-#define YDSXGR_SPDIFLOOPVOL2 0x00BC
+-#define YDSXGR_SPDIFLOOPVOL2L 0x00BC
+-#define YDSXGR_SPDIFLOOPVOL2R 0x00BE
+-#define YDSXGR_ADCSLOTSR 0x00C0
+-#define YDSXGR_RECSLOTSR 0x00C4
+-#define YDSXGR_ADCFORMAT 0x00C8
+-#define YDSXGR_RECFORMAT 0x00CC
+-#define YDSXGR_P44SLOTSR 0x00D0
+-#define YDSXGR_STATUS 0x0100
+-#define YDSXGR_CTRLSELECT 0x0104
+-#define YDSXGR_MODE 0x0108
+-#define YDSXGR_SAMPLECOUNT 0x010C
+-#define YDSXGR_NUMOFSAMPLES 0x0110
+-#define YDSXGR_CONFIG 0x0114
+-#define YDSXGR_PLAYCTRLSIZE 0x0140
+-#define YDSXGR_RECCTRLSIZE 0x0144
+-#define YDSXGR_EFFCTRLSIZE 0x0148
+-#define YDSXGR_WORKSIZE 0x014C
+-#define YDSXGR_MAPOFREC 0x0150
+-#define YDSXGR_MAPOFEFFECT 0x0154
+-#define YDSXGR_PLAYCTRLBASE 0x0158
+-#define YDSXGR_RECCTRLBASE 0x015C
+-#define YDSXGR_EFFCTRLBASE 0x0160
+-#define YDSXGR_WORKBASE 0x0164
+-#define YDSXGR_DSPINSTRAM 0x1000
+-#define YDSXGR_CTRLINSTRAM 0x4000
+-
+-#define YDSXG_AC97READCMD 0x8000
+-#define YDSXG_AC97WRITECMD 0x0000
+-
+-#define PCIR_LEGCTRL 0x40
+-#define PCIR_ELEGCTRL 0x42
+-#define PCIR_DSXGCTRL 0x48
+-#define PCIR_DSXPWRCTRL1 0x4a
+-#define PCIR_DSXPWRCTRL2 0x4e
+-#define PCIR_OPLADR 0x60
+-#define PCIR_SBADR 0x62
+-#define PCIR_MPUADR 0x64
+-
+-#define YDSXG_DSPLENGTH 0x0080
+-#define YDSXG_CTRLLENGTH 0x3000
+-
+-#define YDSXG_DEFAULT_WORK_SIZE 0x0400
+-
+-#define YDSXG_PLAYBACK_VOICES 64
+-#define YDSXG_CAPTURE_VOICES 2
+-#define YDSXG_EFFECT_VOICES 5
+-
+-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+-#define NR_AC97 2
+-
+-#define YMF_SAMPF 256 /* Samples per frame @48000 */
+-
+-/*
+- * The slot/voice control bank (2 of these per voice)
+- */
+-
+-typedef struct stru_ymfpci_playback_bank {
+- u32 format;
+- u32 loop_default;
+- u32 base; /* 32-bit address */
+- u32 loop_start; /* 32-bit offset */
+- u32 loop_end; /* 32-bit offset */
+- u32 loop_frac; /* 8-bit fraction - loop_start */
+- u32 delta_end; /* pitch delta end */
+- u32 lpfK_end;
+- u32 eg_gain_end;
+- u32 left_gain_end;
+- u32 right_gain_end;
+- u32 eff1_gain_end;
+- u32 eff2_gain_end;
+- u32 eff3_gain_end;
+- u32 lpfQ;
+- u32 status; /* P3: Always 0 for some reason. */
+- u32 num_of_frames;
+- u32 loop_count;
+- u32 start; /* P3: J. reads this to know where chip is. */
+- u32 start_frac;
+- u32 delta;
+- u32 lpfK;
+- u32 eg_gain;
+- u32 left_gain;
+- u32 right_gain;
+- u32 eff1_gain;
+- u32 eff2_gain;
+- u32 eff3_gain;
+- u32 lpfD1;
+- u32 lpfD2;
+-} ymfpci_playback_bank_t;
+-
+-typedef struct stru_ymfpci_capture_bank {
+- u32 base; /* 32-bit address (aligned at 4) */
+- u32 loop_end; /* size in BYTES (aligned at 4) */
+- u32 start; /* 32-bit offset */
+- u32 num_of_loops; /* counter */
+-} ymfpci_capture_bank_t;
+-
+-typedef struct stru_ymfpci_effect_bank {
+- u32 base; /* 32-bit address */
+- u32 loop_end; /* 32-bit offset */
+- u32 start; /* 32-bit offset */
+- u32 temp;
+-} ymfpci_effect_bank_t;
+-
+-typedef struct ymf_voice ymfpci_voice_t;
+-/*
+- * Throughout the code Yaroslav names YMF unit pointer "codec"
+- * even though it does not correspond to any codec. Must be historic.
+- * We replace it with "unit" over time.
+- * AC97 parts use "codec" to denote a codec, naturally.
+- */
+-typedef struct ymf_unit ymfpci_t;
+-
+-typedef enum {
+- YMFPCI_PCM,
+- YMFPCI_SYNTH,
+- YMFPCI_MIDI
+-} ymfpci_voice_type_t;
+-
+-struct ymf_voice {
+- // ymfpci_t *codec;
+- int number;
+- char use, pcm, synth, midi; // bool
+- ymfpci_playback_bank_t *bank;
+- struct ymf_pcm *ypcm;
+- dma_addr_t bank_ba;
+-};
+-
+-struct ymf_capture {
+- // struct ymf_unit *unit;
+- int use;
+- ymfpci_capture_bank_t *bank;
+- struct ymf_pcm *ypcm;
+-};
+-
+-struct ymf_unit {
+- u8 rev; /* PCI revision */
+- void __iomem *reg_area_virt;
+- void *dma_area_va;
+- dma_addr_t dma_area_ba;
+- unsigned int dma_area_size;
+-
+- dma_addr_t bank_base_capture;
+- dma_addr_t bank_base_effect;
+- dma_addr_t work_base;
+- unsigned int work_size;
+-
+- u32 *ctrl_playback;
+- dma_addr_t ctrl_playback_ba;
+- ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
+- ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
+- ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
+-
+- int start_count;
+- int suspended;
+-
+- u32 active_bank;
+- struct ymf_voice voices[YDSXG_PLAYBACK_VOICES];
+- struct ymf_capture capture[YDSXG_CAPTURE_VOICES];
+-
+- struct ac97_codec *ac97_codec[NR_AC97];
+- u16 ac97_features;
+-
+- struct pci_dev *pci;
+-
+-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+- /* legacy hardware resources */
+- unsigned int iosynth, iomidi;
+- struct address_info opl3_data, mpu_data;
+-#endif
+-
+- spinlock_t reg_lock;
+- spinlock_t voice_lock;
+- spinlock_t ac97_lock;
+-
+- /* soundcore stuff */
+- int dev_audio;
+- struct mutex open_mutex;
+-
+- struct list_head ymf_devs;
+- struct list_head states; /* List of states for this unit */
+-};
+-
+-struct ymf_dmabuf {
+- dma_addr_t dma_addr;
+- void *rawbuf;
+- unsigned buforder;
+-
+- /* OSS buffer management stuff */
+- unsigned numfrag;
+- unsigned fragshift;
+-
+- /* our buffer acts like a circular ring */
+- unsigned hwptr; /* where dma last started */
+- unsigned swptr; /* where driver last clear/filled */
+- int count; /* fill count */
+- unsigned total_bytes; /* total bytes dmaed by hardware */
+-
+- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
+-
+- /* redundant, but makes calculations easier */
+- unsigned fragsize;
+- unsigned dmasize; /* Total rawbuf[] size */
+-
+- /* OSS stuff */
+- unsigned mapped:1;
+- unsigned ready:1;
+- unsigned ossfragshift;
+- int ossmaxfrags;
+- unsigned subdivision;
+-};
+-
+-struct ymf_pcm_format {
+- int format; /* OSS format */
+- int rate; /* rate in Hz */
+- int voices; /* number of voices */
+- int shift; /* redundant, computed from the above */
+-};
+-
+-typedef enum {
+- PLAYBACK_VOICE,
+- CAPTURE_REC,
+- CAPTURE_AC97,
+- EFFECT_DRY_LEFT,
+- EFFECT_DRY_RIGHT,
+- EFFECT_EFF1,
+- EFFECT_EFF2,
+- EFFECT_EFF3
+-} ymfpci_pcm_type_t;
+-
+-/* This is variant record, but we hate unions. Little waste on pointers []. */
+-struct ymf_pcm {
+- ymfpci_pcm_type_t type;
+- struct ymf_state *state;
+-
+- ymfpci_voice_t *voices[2];
+- int capture_bank_number;
+-
+- struct ymf_dmabuf dmabuf;
+- int running;
+- int spdif;
+-};
+-
+-/*
+- * "Software" or virtual channel, an instance of opened /dev/dsp.
+- * It may have two physical channels (pcms) for duplex operations.
+- */
+-
+-struct ymf_state {
+- struct list_head chain;
+- struct ymf_unit *unit; /* backpointer */
+- struct ymf_pcm rpcm, wpcm;
+- struct ymf_pcm_format format;
+-};
+-
+-#endif /* __YMFPCI_H */
+diff --git a/sound/oss/ymfpci_image.h b/sound/oss/ymfpci_image.h
+deleted file mode 100644
+index 112f2ff..0000000
+--- a/sound/oss/ymfpci_image.h
++++ /dev/null
+@@ -1,1565 +0,0 @@
+-#ifndef _HWMCODE_
+-#define _HWMCODE_
+-
+-static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
+- 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
+- 0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
+- 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
+- 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
+- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+- 0x00000000, 0x00000000, 0x00000000, 0x00000000
+-};
+-
+-static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
+- 0x000007, 0x240007, 0x0C0007, 0x1C0007,
+- 0x060007, 0x700002, 0x000020, 0x030040,
+- 0x007104, 0x004286, 0x030040, 0x000F0D,
+- 0x000810, 0x20043A, 0x000282, 0x00020D,
+- 0x000810, 0x20043A, 0x001282, 0x200E82,
+- 0x001A82, 0x032D0D, 0x000810, 0x10043A,
+- 0x02D38D, 0x000810, 0x18043A, 0x00010D,
+- 0x020015, 0x0000FD, 0x000020, 0x038860,
+- 0x039060, 0x038060, 0x038040, 0x038040,
+- 0x038040, 0x018040, 0x000A7D, 0x038040,
+- 0x038040, 0x018040, 0x200402, 0x000882,
+- 0x08001A, 0x000904, 0x015986, 0x000007,
+- 0x260007, 0x000007, 0x000007, 0x018A06,
+- 0x000007, 0x030C8D, 0x000810, 0x18043A,
+- 0x260007, 0x00087D, 0x018042, 0x00160A,
+- 0x04A206, 0x000007, 0x00218D, 0x000810,
+- 0x08043A, 0x21C206, 0x000007, 0x0007FD,
+- 0x018042, 0x08000A, 0x000904, 0x029386,
+- 0x000195, 0x090D04, 0x000007, 0x000820,
+- 0x0000F5, 0x000B7D, 0x01F060, 0x0000FD,
+- 0x032206, 0x018040, 0x000A7D, 0x038042,
+- 0x13804A, 0x18000A, 0x001820, 0x059060,
+- 0x058860, 0x018040, 0x0000FD, 0x018042,
+- 0x70000A, 0x000115, 0x071144, 0x032386,
+- 0x030000, 0x007020, 0x034A06, 0x018040,
+- 0x00348D, 0x000810, 0x08043A, 0x21EA06,
+- 0x000007, 0x02D38D, 0x000810, 0x18043A,
+- 0x018206, 0x000007, 0x240007, 0x000F8D,
+- 0x000810, 0x00163A, 0x002402, 0x005C02,
+- 0x0028FD, 0x000020, 0x018040, 0x08000D,
+- 0x000815, 0x510984, 0x000007, 0x00004D,
+- 0x000E5D, 0x000E02, 0x00418D, 0x000810,
+- 0x08043A, 0x2C8A06, 0x000007, 0x00008D,
+- 0x000924, 0x000F02, 0x00458D, 0x000810,
+- 0x08043A, 0x2C8A06, 0x000007, 0x00387D,
+- 0x018042, 0x08000A, 0x001015, 0x010984,
+- 0x018386, 0x000007, 0x01AA06, 0x000007,
+- 0x0008FD, 0x018042, 0x18000A, 0x001904,
+- 0x218086, 0x280007, 0x001810, 0x28043A,
+- 0x280C02, 0x00000D, 0x000810, 0x28143A,
+- 0x08808D, 0x000820, 0x0002FD, 0x018040,
+- 0x200007, 0x00020D, 0x189904, 0x000007,
+- 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x055A86, 0x000007,
+- 0x000100, 0x000A20, 0x00047D, 0x018040,
+- 0x018042, 0x20000A, 0x003015, 0x012144,
+- 0x034986, 0x000007, 0x002104, 0x034986,
+- 0x000007, 0x000F8D, 0x000810, 0x280C3A,
+- 0x023944, 0x06C986, 0x000007, 0x001810,
+- 0x28043A, 0x08810D, 0x000820, 0x0002FD,
+- 0x018040, 0x200007, 0x002810, 0x78003A,
+- 0x00688D, 0x000810, 0x08043A, 0x288A06,
+- 0x000007, 0x00400D, 0x001015, 0x189904,
+- 0x292904, 0x393904, 0x000007, 0x060206,
+- 0x000007, 0x0004F5, 0x00007D, 0x000020,
+- 0x00008D, 0x010860, 0x018040, 0x00047D,
+- 0x038042, 0x21804A, 0x18000A, 0x021944,
+- 0x215886, 0x000007, 0x004075, 0x71F104,
+- 0x000007, 0x010042, 0x28000A, 0x002904,
+- 0x212086, 0x000007, 0x003C0D, 0x30A904,
+- 0x000007, 0x00077D, 0x018042, 0x08000A,
+- 0x000904, 0x07DA86, 0x00057D, 0x002820,
+- 0x03B060, 0x07F206, 0x018040, 0x003020,
+- 0x03A860, 0x018040, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x07FA86, 0x000007,
+- 0x00057D, 0x018042, 0x28040A, 0x000E8D,
+- 0x000810, 0x280C3A, 0x00000D, 0x000810,
+- 0x28143A, 0x09000D, 0x000820, 0x0002FD,
+- 0x018040, 0x200007, 0x003DFD, 0x000020,
+- 0x018040, 0x00107D, 0x008D8D, 0x000810,
+- 0x08043A, 0x288A06, 0x000007, 0x000815,
+- 0x08001A, 0x010984, 0x095186, 0x00137D,
+- 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
+- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
+- 0x038A60, 0x018040, 0x007FBD, 0x383DC4,
+- 0x000007, 0x001A7D, 0x001375, 0x018042,
+- 0x09004A, 0x10000A, 0x0B8D04, 0x139504,
+- 0x000007, 0x000820, 0x019060, 0x001104,
+- 0x212086, 0x010040, 0x0017FD, 0x018042,
+- 0x08000A, 0x000904, 0x212286, 0x000007,
+- 0x00197D, 0x038042, 0x09804A, 0x10000A,
+- 0x000924, 0x001664, 0x0011FD, 0x038042,
+- 0x2B804A, 0x19804A, 0x00008D, 0x218944,
+- 0x000007, 0x002244, 0x0AE186, 0x000007,
+- 0x001A64, 0x002A24, 0x00197D, 0x080102,
+- 0x100122, 0x000820, 0x039060, 0x018040,
+- 0x003DFD, 0x00008D, 0x000820, 0x018040,
+- 0x001375, 0x001A7D, 0x010042, 0x09804A,
+- 0x10000A, 0x00021D, 0x0189E4, 0x2992E4,
+- 0x309144, 0x000007, 0x00060D, 0x000A15,
+- 0x000C1D, 0x001025, 0x00A9E4, 0x012BE4,
+- 0x000464, 0x01B3E4, 0x0232E4, 0x000464,
+- 0x000464, 0x000464, 0x000464, 0x00040D,
+- 0x08B1C4, 0x000007, 0x000820, 0x000BF5,
+- 0x030040, 0x00197D, 0x038042, 0x09804A,
+- 0x000A24, 0x08000A, 0x080E64, 0x000007,
+- 0x100122, 0x000820, 0x031060, 0x010040,
+- 0x0064AC, 0x00027D, 0x000020, 0x018040,
+- 0x00107D, 0x018042, 0x0011FD, 0x3B804A,
+- 0x09804A, 0x20000A, 0x000095, 0x1A1144,
+- 0x00A144, 0x0D2086, 0x00040D, 0x00B984,
+- 0x0D2186, 0x0018FD, 0x018042, 0x0010FD,
+- 0x09804A, 0x28000A, 0x000095, 0x010924,
+- 0x002A64, 0x0D1186, 0x000007, 0x002904,
+- 0x0D2286, 0x000007, 0x0D2A06, 0x080002,
+- 0x00008D, 0x00387D, 0x000820, 0x018040,
+- 0x00127D, 0x018042, 0x10000A, 0x003904,
+- 0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984,
+- 0x0DA186, 0x000025, 0x0E7A06, 0x00002D,
+- 0x000015, 0x00082D, 0x02C78D, 0x000820,
+- 0x0EC206, 0x00000D, 0x7F8035, 0x00B984,
+- 0x0E7186, 0x400025, 0x00008D, 0x110944,
+- 0x000007, 0x00018D, 0x109504, 0x000007,
+- 0x009164, 0x000424, 0x000424, 0x000424,
+- 0x100102, 0x280002, 0x02C68D, 0x000820,
+- 0x0EC206, 0x00018D, 0x00042D, 0x00008D,
+- 0x109504, 0x000007, 0x00020D, 0x109184,
+- 0x000007, 0x02C70D, 0x000820, 0x00008D,
+- 0x0038FD, 0x018040, 0x003BFD, 0x001020,
+- 0x03A860, 0x000815, 0x313184, 0x212184,
+- 0x000007, 0x03B060, 0x03A060, 0x018040,
+- 0x0022FD, 0x000095, 0x010924, 0x000424,
+- 0x000424, 0x001264, 0x100102, 0x000820,
+- 0x039060, 0x018040, 0x001924, 0x00FB8D,
+- 0x00397D, 0x000820, 0x058040, 0x038042,
+- 0x09844A, 0x000606, 0x08040A, 0x000424,
+- 0x000424, 0x00117D, 0x018042, 0x08000A,
+- 0x000A24, 0x280502, 0x280C02, 0x09800D,
+- 0x000820, 0x0002FD, 0x018040, 0x200007,
+- 0x0022FD, 0x018042, 0x08000A, 0x000095,
+- 0x280DC4, 0x011924, 0x00197D, 0x018042,
+- 0x0011FD, 0x09804A, 0x10000A, 0x0000B5,
+- 0x113144, 0x0A8D04, 0x000007, 0x080A44,
+- 0x129504, 0x000007, 0x0023FD, 0x001020,
+- 0x038040, 0x101244, 0x000007, 0x000820,
+- 0x039060, 0x018040, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x10FA86, 0x000007,
+- 0x003BFD, 0x000100, 0x000A10, 0x0B807A,
+- 0x13804A, 0x090984, 0x000007, 0x000095,
+- 0x013D04, 0x118086, 0x10000A, 0x100002,
+- 0x090984, 0x000007, 0x038042, 0x11804A,
+- 0x090D04, 0x000007, 0x10000A, 0x090D84,
+- 0x000007, 0x00257D, 0x000820, 0x018040,
+- 0x00010D, 0x000810, 0x28143A, 0x00127D,
+- 0x018042, 0x20000A, 0x00197D, 0x018042,
+- 0x00117D, 0x31804A, 0x10000A, 0x003124,
+- 0x01280D, 0x00397D, 0x000820, 0x058040,
+- 0x038042, 0x09844A, 0x000606, 0x08040A,
+- 0x300102, 0x003124, 0x000424, 0x000424,
+- 0x001224, 0x280502, 0x001A4C, 0x130186,
+- 0x700002, 0x00002D, 0x030000, 0x00387D,
+- 0x018042, 0x10000A, 0x132A06, 0x002124,
+- 0x0000AD, 0x100002, 0x00010D, 0x000924,
+- 0x006B24, 0x01368D, 0x00397D, 0x000820,
+- 0x058040, 0x038042, 0x09844A, 0x000606,
+- 0x08040A, 0x003264, 0x00008D, 0x000A24,
+- 0x001020, 0x00227D, 0x018040, 0x013C0D,
+- 0x000810, 0x08043A, 0x29D206, 0x000007,
+- 0x002820, 0x00207D, 0x018040, 0x00117D,
+- 0x038042, 0x13804A, 0x33800A, 0x00387D,
+- 0x018042, 0x08000A, 0x000904, 0x163A86,
+- 0x000007, 0x00008D, 0x030964, 0x01478D,
+- 0x00397D, 0x000820, 0x058040, 0x038042,
+- 0x09844A, 0x000606, 0x08040A, 0x380102,
+- 0x000424, 0x000424, 0x001224, 0x0002FD,
+- 0x018042, 0x08000A, 0x000904, 0x14A286,
+- 0x000007, 0x280502, 0x001A4C, 0x163986,
+- 0x000007, 0x032164, 0x00632C, 0x003DFD,
+- 0x018042, 0x08000A, 0x000095, 0x090904,
+- 0x000007, 0x000820, 0x001A4C, 0x156186,
+- 0x018040, 0x030000, 0x157A06, 0x002124,
+- 0x00010D, 0x000924, 0x006B24, 0x015B8D,
+- 0x00397D, 0x000820, 0x058040, 0x038042,
+- 0x09844A, 0x000606, 0x08040A, 0x003A64,
+- 0x000095, 0x001224, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x15DA86, 0x000007,
+- 0x01628D, 0x000810, 0x08043A, 0x29D206,
+- 0x000007, 0x14D206, 0x000007, 0x007020,
+- 0x08010A, 0x10012A, 0x0020FD, 0x038860,
+- 0x039060, 0x018040, 0x00227D, 0x018042,
+- 0x003DFD, 0x08000A, 0x31844A, 0x000904,
+- 0x16D886, 0x18008B, 0x00008D, 0x189904,
+- 0x00312C, 0x17AA06, 0x000007, 0x00324C,
+- 0x173386, 0x000007, 0x001904, 0x173086,
+- 0x000007, 0x000095, 0x199144, 0x00222C,
+- 0x003124, 0x00636C, 0x000E3D, 0x001375,
+- 0x000BFD, 0x010042, 0x09804A, 0x10000A,
+- 0x038AEC, 0x0393EC, 0x00224C, 0x17A986,
+- 0x000007, 0x00008D, 0x189904, 0x00226C,
+- 0x00322C, 0x30050A, 0x301DAB, 0x002083,
+- 0x0018FD, 0x018042, 0x08000A, 0x018924,
+- 0x300502, 0x001083, 0x001875, 0x010042,
+- 0x10000A, 0x00008D, 0x010924, 0x001375,
+- 0x330542, 0x330CCB, 0x332CCB, 0x3334CB,
+- 0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB,
+- 0x305C8B, 0x006083, 0x0002F5, 0x010042,
+- 0x08000A, 0x000904, 0x187A86, 0x000007,
+- 0x001E2D, 0x0005FD, 0x018042, 0x08000A,
+- 0x028924, 0x280502, 0x00060D, 0x000810,
+- 0x280C3A, 0x00008D, 0x000810, 0x28143A,
+- 0x0A808D, 0x000820, 0x0002F5, 0x010040,
+- 0x220007, 0x001275, 0x030042, 0x21004A,
+- 0x00008D, 0x1A0944, 0x000007, 0x01980D,
+- 0x000810, 0x08043A, 0x2B2206, 0x000007,
+- 0x0001F5, 0x030042, 0x0D004A, 0x10000A,
+- 0x089144, 0x000007, 0x000820, 0x010040,
+- 0x0025F5, 0x0A3144, 0x000007, 0x000820,
+- 0x032860, 0x030040, 0x00217D, 0x038042,
+- 0x0B804A, 0x10000A, 0x000820, 0x031060,
+- 0x030040, 0x00008D, 0x000124, 0x00012C,
+- 0x000E64, 0x001A64, 0x00636C, 0x08010A,
+- 0x10012A, 0x000820, 0x031060, 0x030040,
+- 0x0020FD, 0x018042, 0x08000A, 0x00227D,
+- 0x018042, 0x10000A, 0x000820, 0x031060,
+- 0x030040, 0x00197D, 0x018042, 0x08000A,
+- 0x0022FD, 0x038042, 0x10000A, 0x000820,
+- 0x031060, 0x030040, 0x090D04, 0x000007,
+- 0x000820, 0x030040, 0x038042, 0x0B804A,
+- 0x10000A, 0x000820, 0x031060, 0x030040,
+- 0x038042, 0x13804A, 0x19804A, 0x110D04,
+- 0x198D04, 0x000007, 0x08000A, 0x001020,
+- 0x031860, 0x030860, 0x030040, 0x00008D,
+- 0x0B0944, 0x000007, 0x000820, 0x010040,
+- 0x0005F5, 0x030042, 0x08000A, 0x000820,
+- 0x010040, 0x0000F5, 0x010042, 0x08000A,
+- 0x000904, 0x1C6086, 0x001E75, 0x030042,
+- 0x01044A, 0x000C0A, 0x1C7206, 0x000007,
+- 0x000402, 0x000C02, 0x00177D, 0x001AF5,
+- 0x018042, 0x03144A, 0x031C4A, 0x03244A,
+- 0x032C4A, 0x03344A, 0x033C4A, 0x03444A,
+- 0x004C0A, 0x00043D, 0x0013F5, 0x001AFD,
+- 0x030042, 0x0B004A, 0x1B804A, 0x13804A,
+- 0x20000A, 0x089144, 0x19A144, 0x0389E4,
+- 0x0399EC, 0x005502, 0x005D0A, 0x030042,
+- 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
+- 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
+- 0x006502, 0x006D0A, 0x030042, 0x0B004A,
+- 0x19004A, 0x2B804A, 0x13804A, 0x21804A,
+- 0x30000A, 0x089144, 0x19A144, 0x2AB144,
+- 0x0389E4, 0x0399EC, 0x007502, 0x007D0A,
+- 0x03A9E4, 0x000702, 0x00107D, 0x000415,
+- 0x018042, 0x08000A, 0x0109E4, 0x000F02,
+- 0x002AF5, 0x0019FD, 0x010042, 0x09804A,
+- 0x10000A, 0x000934, 0x001674, 0x0029F5,
+- 0x010042, 0x10000A, 0x00917C, 0x002075,
+- 0x010042, 0x08000A, 0x000904, 0x1ED286,
+- 0x0026F5, 0x0027F5, 0x030042, 0x09004A,
+- 0x10000A, 0x000A3C, 0x00167C, 0x001A75,
+- 0x000BFD, 0x010042, 0x51804A, 0x48000A,
+- 0x160007, 0x001075, 0x010042, 0x282C0A,
+- 0x281D12, 0x282512, 0x001F32, 0x1E0007,
+- 0x0E0007, 0x001975, 0x010042, 0x002DF5,
+- 0x0D004A, 0x10000A, 0x009144, 0x1FB286,
+- 0x010042, 0x28340A, 0x000E5D, 0x00008D,
+- 0x000375, 0x000820, 0x010040, 0x05D2F4,
+- 0x54D104, 0x00735C, 0x205386, 0x000007,
+- 0x0C0007, 0x080007, 0x0A0007, 0x02040D,
+- 0x000810, 0x08043A, 0x332206, 0x000007,
+- 0x205A06, 0x000007, 0x080007, 0x002275,
+- 0x010042, 0x20000A, 0x002104, 0x212086,
+- 0x001E2D, 0x0002F5, 0x010042, 0x08000A,
+- 0x000904, 0x209286, 0x000007, 0x002010,
+- 0x30043A, 0x00057D, 0x0180C3, 0x08000A,
+- 0x028924, 0x280502, 0x280C02, 0x0A810D,
+- 0x000820, 0x0002F5, 0x010040, 0x220007,
+- 0x0004FD, 0x018042, 0x70000A, 0x030000,
+- 0x007020, 0x06FA06, 0x018040, 0x02180D,
+- 0x000810, 0x08043A, 0x2B2206, 0x000007,
+- 0x0002FD, 0x018042, 0x08000A, 0x000904,
+- 0x218A86, 0x000007, 0x01F206, 0x000007,
+- 0x000875, 0x0009FD, 0x00010D, 0x220A06,
+- 0x000295, 0x000B75, 0x00097D, 0x00000D,
+- 0x000515, 0x010042, 0x18000A, 0x001904,
+- 0x287886, 0x0006F5, 0x001020, 0x010040,
+- 0x0004F5, 0x000820, 0x010040, 0x000775,
+- 0x010042, 0x09804A, 0x10000A, 0x001124,
+- 0x000904, 0x22BA86, 0x000815, 0x080102,
+- 0x101204, 0x22DA06, 0x000575, 0x081204,
+- 0x000007, 0x100102, 0x000575, 0x000425,
+- 0x021124, 0x100102, 0x000820, 0x031060,
+- 0x010040, 0x001924, 0x287886, 0x00008D,
+- 0x000464, 0x009D04, 0x278886, 0x180102,
+- 0x000575, 0x010042, 0x28040A, 0x00018D,
+- 0x000924, 0x280D02, 0x00000D, 0x000924,
+- 0x281502, 0x10000D, 0x000820, 0x0002F5,
+- 0x010040, 0x200007, 0x001175, 0x0002FD,
+- 0x018042, 0x08000A, 0x000904, 0x23C286,
+- 0x000007, 0x000100, 0x080B20, 0x130B60,
+- 0x1B0B60, 0x030A60, 0x010040, 0x050042,
+- 0x3D004A, 0x35004A, 0x2D004A, 0x20000A,
+- 0x0006F5, 0x010042, 0x28140A, 0x0004F5,
+- 0x010042, 0x08000A, 0x000315, 0x010D04,
+- 0x24CA86, 0x004015, 0x000095, 0x010D04,
+- 0x24B886, 0x100022, 0x10002A, 0x24E206,
+- 0x000007, 0x333104, 0x2AA904, 0x000007,
+- 0x032124, 0x280502, 0x001124, 0x000424,
+- 0x000424, 0x003224, 0x00292C, 0x00636C,
+- 0x25F386, 0x000007, 0x02B164, 0x000464,
+- 0x000464, 0x00008D, 0x000A64, 0x280D02,
+- 0x10008D, 0x000820, 0x0002F5, 0x010040,
+- 0x220007, 0x00008D, 0x38B904, 0x000007,
+- 0x03296C, 0x30010A, 0x0002F5, 0x010042,
+- 0x08000A, 0x000904, 0x25BA86, 0x000007,
+- 0x02312C, 0x28050A, 0x00008D, 0x01096C,
+- 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
+- 0x010040, 0x220007, 0x001124, 0x000424,
+- 0x000424, 0x003224, 0x300102, 0x032944,
+- 0x267A86, 0x000007, 0x300002, 0x0004F5,
+- 0x010042, 0x08000A, 0x000315, 0x010D04,
+- 0x26C086, 0x003124, 0x000464, 0x300102,
+- 0x0002F5, 0x010042, 0x08000A, 0x000904,
+- 0x26CA86, 0x000007, 0x003124, 0x300502,
+- 0x003924, 0x300583, 0x000883, 0x0005F5,
+- 0x010042, 0x28040A, 0x00008D, 0x008124,
+- 0x280D02, 0x00008D, 0x008124, 0x281502,
+- 0x10018D, 0x000820, 0x0002F5, 0x010040,
+- 0x220007, 0x001025, 0x000575, 0x030042,
+- 0x09004A, 0x10000A, 0x0A0904, 0x121104,
+- 0x000007, 0x001020, 0x050860, 0x050040,
+- 0x0006FD, 0x018042, 0x09004A, 0x10000A,
+- 0x0000A5, 0x0A0904, 0x121104, 0x000007,
+- 0x000820, 0x019060, 0x010040, 0x0002F5,
+- 0x010042, 0x08000A, 0x000904, 0x284286,
+- 0x000007, 0x230A06, 0x000007, 0x000606,
+- 0x000007, 0x0002F5, 0x010042, 0x08000A,
+- 0x000904, 0x289286, 0x000007, 0x000100,
+- 0x080B20, 0x138B60, 0x1B8B60, 0x238B60,
+- 0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60,
+- 0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60,
+- 0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60,
+- 0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60,
+- 0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60,
+- 0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60,
+- 0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60,
+- 0x000606, 0x018040, 0x00008D, 0x000A64,
+- 0x280D02, 0x000A24, 0x00027D, 0x018042,
+- 0x10000A, 0x001224, 0x0003FD, 0x018042,
+- 0x08000A, 0x000904, 0x2A8286, 0x000007,
+- 0x00018D, 0x000A24, 0x000464, 0x000464,
+- 0x080102, 0x000924, 0x000424, 0x000424,
+- 0x100102, 0x02000D, 0x009144, 0x2AD986,
+- 0x000007, 0x0001FD, 0x018042, 0x08000A,
+- 0x000A44, 0x2ABB86, 0x018042, 0x0A000D,
+- 0x000820, 0x0002FD, 0x018040, 0x200007,
+- 0x00027D, 0x001020, 0x000606, 0x018040,
+- 0x0002F5, 0x010042, 0x08000A, 0x000904,
+- 0x2B2A86, 0x000007, 0x00037D, 0x018042,
+- 0x08000A, 0x000904, 0x2B5A86, 0x000007,
+- 0x000075, 0x002E7D, 0x010042, 0x0B804A,
+- 0x000020, 0x000904, 0x000686, 0x010040,
+- 0x31844A, 0x30048B, 0x000883, 0x00008D,
+- 0x000810, 0x28143A, 0x00008D, 0x000810,
+- 0x280C3A, 0x000675, 0x010042, 0x08000A,
+- 0x003815, 0x010924, 0x280502, 0x0B000D,
+- 0x000820, 0x0002F5, 0x010040, 0x000606,
+- 0x220007, 0x000464, 0x000464, 0x000606,
+- 0x000007, 0x000134, 0x007F8D, 0x00093C,
+- 0x281D12, 0x282512, 0x001F32, 0x0E0007,
+- 0x00010D, 0x00037D, 0x000820, 0x018040,
+- 0x05D2F4, 0x000007, 0x080007, 0x00037D,
+- 0x018042, 0x08000A, 0x000904, 0x2D0286,
+- 0x000007, 0x000606, 0x000007, 0x000007,
+- 0x000012, 0x100007, 0x320007, 0x600007,
+- 0x100080, 0x48001A, 0x004904, 0x2D6186,
+- 0x000007, 0x001210, 0x58003A, 0x000145,
+- 0x5C5D04, 0x000007, 0x000080, 0x48001A,
+- 0x004904, 0x2DB186, 0x000007, 0x001210,
+- 0x50003A, 0x005904, 0x2E0886, 0x000045,
+- 0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524,
+- 0x004224, 0x500102, 0x200502, 0x000082,
+- 0x40001A, 0x004104, 0x2E3986, 0x000007,
+- 0x003865, 0x40001A, 0x004020, 0x00104D,
+- 0x04C184, 0x301B86, 0x000040, 0x040007,
+- 0x000165, 0x000145, 0x004020, 0x000040,
+- 0x000765, 0x080080, 0x40001A, 0x004104,
+- 0x2EC986, 0x000007, 0x001210, 0x40003A,
+- 0x004104, 0x2F2286, 0x00004D, 0x0000CD,
+- 0x004810, 0x20043A, 0x000882, 0x40001A,
+- 0x004104, 0x2F3186, 0x000007, 0x004820,
+- 0x005904, 0x300886, 0x000040, 0x0007E5,
+- 0x200480, 0x2816A0, 0x3216E0, 0x3A16E0,
+- 0x4216E0, 0x021260, 0x000040, 0x000032,
+- 0x400075, 0x00007D, 0x07D574, 0x200512,
+- 0x000082, 0x40001A, 0x004104, 0x2FE186,
+- 0x000007, 0x037206, 0x640007, 0x060007,
+- 0x0000E5, 0x000020, 0x000040, 0x000A65,
+- 0x000020, 0x020040, 0x020040, 0x000040,
+- 0x000165, 0x000042, 0x70000A, 0x007104,
+- 0x30A286, 0x000007, 0x018206, 0x640007,
+- 0x050000, 0x007020, 0x000040, 0x037206,
+- 0x640007, 0x000007, 0x00306D, 0x028860,
+- 0x029060, 0x08000A, 0x028860, 0x008040,
+- 0x100012, 0x00100D, 0x009184, 0x314186,
+- 0x000E0D, 0x009184, 0x325186, 0x000007,
+- 0x300007, 0x001020, 0x003B6D, 0x008040,
+- 0x000080, 0x08001A, 0x000904, 0x316186,
+- 0x000007, 0x001220, 0x000DED, 0x008040,
+- 0x008042, 0x10000A, 0x40000D, 0x109544,
+- 0x000007, 0x001020, 0x000DED, 0x008040,
+- 0x008042, 0x20040A, 0x000082, 0x08001A,
+- 0x000904, 0x31F186, 0x000007, 0x003B6D,
+- 0x008042, 0x08000A, 0x000E15, 0x010984,
+- 0x329B86, 0x600007, 0x08001A, 0x000C15,
+- 0x010984, 0x328386, 0x000020, 0x1A0007,
+- 0x0002ED, 0x008040, 0x620007, 0x00306D,
+- 0x028042, 0x0A804A, 0x000820, 0x0A804A,
+- 0x000606, 0x10804A, 0x000007, 0x282512,
+- 0x001F32, 0x05D2F4, 0x54D104, 0x00735C,
+- 0x000786, 0x000007, 0x0C0007, 0x0A0007,
+- 0x1C0007, 0x003465, 0x020040, 0x004820,
+- 0x025060, 0x40000A, 0x024060, 0x000040,
+- 0x454944, 0x000007, 0x004020, 0x003AE5,
+- 0x000040, 0x0028E5, 0x000042, 0x48000A,
+- 0x004904, 0x386886, 0x002C65, 0x000042,
+- 0x40000A, 0x0000D5, 0x454104, 0x000007,
+- 0x000655, 0x054504, 0x34F286, 0x0001D5,
+- 0x054504, 0x34F086, 0x002B65, 0x000042,
+- 0x003AE5, 0x50004A, 0x40000A, 0x45C3D4,
+- 0x000007, 0x454504, 0x000007, 0x0000CD,
+- 0x444944, 0x000007, 0x454504, 0x000007,
+- 0x00014D, 0x554944, 0x000007, 0x045144,
+- 0x34E986, 0x002C65, 0x000042, 0x48000A,
+- 0x4CD104, 0x000007, 0x04C144, 0x34F386,
+- 0x000007, 0x160007, 0x002CE5, 0x040042,
+- 0x40000A, 0x004020, 0x000040, 0x002965,
+- 0x000042, 0x40000A, 0x004104, 0x356086,
+- 0x000007, 0x002402, 0x36A206, 0x005C02,
+- 0x0025E5, 0x000042, 0x40000A, 0x004274,
+- 0x002AE5, 0x000042, 0x40000A, 0x004274,
+- 0x500112, 0x0029E5, 0x000042, 0x40000A,
+- 0x004234, 0x454104, 0x000007, 0x004020,
+- 0x000040, 0x003EE5, 0x000020, 0x000040,
+- 0x002DE5, 0x400152, 0x50000A, 0x045144,
+- 0x364A86, 0x0000C5, 0x003EE5, 0x004020,
+- 0x000040, 0x002BE5, 0x000042, 0x40000A,
+- 0x404254, 0x000007, 0x002AE5, 0x004020,
+- 0x000040, 0x500132, 0x040134, 0x005674,
+- 0x0029E5, 0x020042, 0x42000A, 0x000042,
+- 0x50000A, 0x05417C, 0x0028E5, 0x000042,
+- 0x48000A, 0x0000C5, 0x4CC144, 0x371086,
+- 0x0026E5, 0x0027E5, 0x020042, 0x40004A,
+- 0x50000A, 0x00423C, 0x00567C, 0x0028E5,
+- 0x004820, 0x000040, 0x281D12, 0x282512,
+- 0x001F72, 0x002965, 0x000042, 0x40000A,
+- 0x004104, 0x37AA86, 0x0E0007, 0x160007,
+- 0x1E0007, 0x003EE5, 0x000042, 0x40000A,
+- 0x004104, 0x37E886, 0x002D65, 0x000042,
+- 0x28340A, 0x003465, 0x020042, 0x42004A,
+- 0x004020, 0x4A004A, 0x50004A, 0x05D2F4,
+- 0x54D104, 0x00735C, 0x385186, 0x000007,
+- 0x000606, 0x080007, 0x0C0007, 0x080007,
+- 0x0A0007, 0x0001E5, 0x020045, 0x004020,
+- 0x000060, 0x000365, 0x000040, 0x002E65,
+- 0x001A20, 0x0A1A60, 0x000040, 0x003465,
+- 0x020042, 0x42004A, 0x004020, 0x4A004A,
+- 0x000606, 0x50004A, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000
+-};
+-
+-// --------------------------------------------
+-// DS-1E Controller InstructionRAM Code
+-// 1999/06/21
+-// Buf441 slot is Enabled.
+-// --------------------------------------------
+-// 04/09 creat
+-// 04/12 stop nise fix
+-// 06/21 WorkingOff timming
+-static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
+- 0x000007, 0x240007, 0x0C0007, 0x1C0007,
+- 0x060007, 0x700002, 0x000020, 0x030040,
+- 0x007104, 0x004286, 0x030040, 0x000F0D,
+- 0x000810, 0x20043A, 0x000282, 0x00020D,
+- 0x000810, 0x20043A, 0x001282, 0x200E82,
+- 0x00800D, 0x000810, 0x20043A, 0x001A82,
+- 0x03460D, 0x000810, 0x10043A, 0x02EC0D,
+- 0x000810, 0x18043A, 0x00010D, 0x020015,
+- 0x0000FD, 0x000020, 0x038860, 0x039060,
+- 0x038060, 0x038040, 0x038040, 0x038040,
+- 0x018040, 0x000A7D, 0x038040, 0x038040,
+- 0x018040, 0x200402, 0x000882, 0x08001A,
+- 0x000904, 0x017186, 0x000007, 0x260007,
+- 0x400007, 0x000007, 0x03258D, 0x000810,
+- 0x18043A, 0x260007, 0x284402, 0x00087D,
+- 0x018042, 0x00160A, 0x05A206, 0x000007,
+- 0x440007, 0x00230D, 0x000810, 0x08043A,
+- 0x22FA06, 0x000007, 0x0007FD, 0x018042,
+- 0x08000A, 0x000904, 0x02AB86, 0x000195,
+- 0x090D04, 0x000007, 0x000820, 0x0000F5,
+- 0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
+- 0x018040, 0x000A7D, 0x038042, 0x13804A,
+- 0x18000A, 0x001820, 0x059060, 0x058860,
+- 0x018040, 0x0000FD, 0x018042, 0x70000A,
+- 0x000115, 0x071144, 0x033B86, 0x030000,
+- 0x007020, 0x036206, 0x018040, 0x00360D,
+- 0x000810, 0x08043A, 0x232206, 0x000007,
+- 0x02EC0D, 0x000810, 0x18043A, 0x019A06,
+- 0x000007, 0x240007, 0x000F8D, 0x000810,
+- 0x00163A, 0x002402, 0x005C02, 0x0028FD,
+- 0x000020, 0x018040, 0x08000D, 0x000815,
+- 0x510984, 0x000007, 0x00004D, 0x000E5D,
+- 0x000E02, 0x00430D, 0x000810, 0x08043A,
+- 0x2E1206, 0x000007, 0x00008D, 0x000924,
+- 0x000F02, 0x00470D, 0x000810, 0x08043A,
+- 0x2E1206, 0x000007, 0x480480, 0x001210,
+- 0x28043A, 0x00778D, 0x000810, 0x280C3A,
+- 0x00068D, 0x000810, 0x28143A, 0x284402,
+- 0x03258D, 0x000810, 0x18043A, 0x07FF8D,
+- 0x000820, 0x0002FD, 0x018040, 0x260007,
+- 0x200007, 0x0002FD, 0x018042, 0x08000A,
+- 0x000904, 0x051286, 0x000007, 0x240007,
+- 0x02EC0D, 0x000810, 0x18043A, 0x00387D,
+- 0x018042, 0x08000A, 0x001015, 0x010984,
+- 0x019B86, 0x000007, 0x01B206, 0x000007,
+- 0x0008FD, 0x018042, 0x18000A, 0x001904,
+- 0x22B886, 0x280007, 0x001810, 0x28043A,
+- 0x280C02, 0x00000D, 0x000810, 0x28143A,
+- 0x08808D, 0x000820, 0x0002FD, 0x018040,
+- 0x200007, 0x00020D, 0x189904, 0x000007,
+- 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x065A86, 0x000007,
+- 0x000100, 0x000A20, 0x00047D, 0x018040,
+- 0x018042, 0x20000A, 0x003015, 0x012144,
+- 0x036186, 0x000007, 0x002104, 0x036186,
+- 0x000007, 0x000F8D, 0x000810, 0x280C3A,
+- 0x023944, 0x07C986, 0x000007, 0x001810,
+- 0x28043A, 0x08810D, 0x000820, 0x0002FD,
+- 0x018040, 0x200007, 0x002810, 0x78003A,
+- 0x00788D, 0x000810, 0x08043A, 0x2A1206,
+- 0x000007, 0x00400D, 0x001015, 0x189904,
+- 0x292904, 0x393904, 0x000007, 0x070206,
+- 0x000007, 0x0004F5, 0x00007D, 0x000020,
+- 0x00008D, 0x010860, 0x018040, 0x00047D,
+- 0x038042, 0x21804A, 0x18000A, 0x021944,
+- 0x229086, 0x000007, 0x004075, 0x71F104,
+- 0x000007, 0x010042, 0x28000A, 0x002904,
+- 0x225886, 0x000007, 0x003C0D, 0x30A904,
+- 0x000007, 0x00077D, 0x018042, 0x08000A,
+- 0x000904, 0x08DA86, 0x00057D, 0x002820,
+- 0x03B060, 0x08F206, 0x018040, 0x003020,
+- 0x03A860, 0x018040, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x08FA86, 0x000007,
+- 0x00057D, 0x018042, 0x28040A, 0x000E8D,
+- 0x000810, 0x280C3A, 0x00000D, 0x000810,
+- 0x28143A, 0x09000D, 0x000820, 0x0002FD,
+- 0x018040, 0x200007, 0x003DFD, 0x000020,
+- 0x018040, 0x00107D, 0x009D8D, 0x000810,
+- 0x08043A, 0x2A1206, 0x000007, 0x000815,
+- 0x08001A, 0x010984, 0x0A5186, 0x00137D,
+- 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
+- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
+- 0x038A60, 0x018040, 0x00107D, 0x018042,
+- 0x08000A, 0x000215, 0x010984, 0x3A8186,
+- 0x000007, 0x007FBD, 0x383DC4, 0x000007,
+- 0x001A7D, 0x001375, 0x018042, 0x09004A,
+- 0x10000A, 0x0B8D04, 0x139504, 0x000007,
+- 0x000820, 0x019060, 0x001104, 0x225886,
+- 0x010040, 0x0017FD, 0x018042, 0x08000A,
+- 0x000904, 0x225A86, 0x000007, 0x00197D,
+- 0x038042, 0x09804A, 0x10000A, 0x000924,
+- 0x001664, 0x0011FD, 0x038042, 0x2B804A,
+- 0x19804A, 0x00008D, 0x218944, 0x000007,
+- 0x002244, 0x0C1986, 0x000007, 0x001A64,
+- 0x002A24, 0x00197D, 0x080102, 0x100122,
+- 0x000820, 0x039060, 0x018040, 0x003DFD,
+- 0x00008D, 0x000820, 0x018040, 0x001375,
+- 0x001A7D, 0x010042, 0x09804A, 0x10000A,
+- 0x00021D, 0x0189E4, 0x2992E4, 0x309144,
+- 0x000007, 0x00060D, 0x000A15, 0x000C1D,
+- 0x001025, 0x00A9E4, 0x012BE4, 0x000464,
+- 0x01B3E4, 0x0232E4, 0x000464, 0x000464,
+- 0x000464, 0x000464, 0x00040D, 0x08B1C4,
+- 0x000007, 0x000820, 0x000BF5, 0x030040,
+- 0x00197D, 0x038042, 0x09804A, 0x000A24,
+- 0x08000A, 0x080E64, 0x000007, 0x100122,
+- 0x000820, 0x031060, 0x010040, 0x0064AC,
+- 0x00027D, 0x000020, 0x018040, 0x00107D,
+- 0x018042, 0x0011FD, 0x3B804A, 0x09804A,
+- 0x20000A, 0x000095, 0x1A1144, 0x00A144,
+- 0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
+- 0x0018FD, 0x018042, 0x0010FD, 0x09804A,
+- 0x28000A, 0x000095, 0x010924, 0x002A64,
+- 0x0E4986, 0x000007, 0x002904, 0x0E5A86,
+- 0x000007, 0x0E6206, 0x080002, 0x00008D,
+- 0x00387D, 0x000820, 0x018040, 0x00127D,
+- 0x018042, 0x10000A, 0x003904, 0x0F0986,
+- 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
+- 0x000025, 0x0FB206, 0x00002D, 0x000015,
+- 0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
+- 0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
+- 0x400025, 0x00008D, 0x110944, 0x000007,
+- 0x00018D, 0x109504, 0x000007, 0x009164,
+- 0x000424, 0x000424, 0x000424, 0x100102,
+- 0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
+- 0x00018D, 0x00042D, 0x00008D, 0x109504,
+- 0x000007, 0x00020D, 0x109184, 0x000007,
+- 0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
+- 0x018040, 0x003BFD, 0x001020, 0x03A860,
+- 0x000815, 0x313184, 0x212184, 0x000007,
+- 0x03B060, 0x03A060, 0x018040, 0x0022FD,
+- 0x000095, 0x010924, 0x000424, 0x000424,
+- 0x001264, 0x100102, 0x000820, 0x039060,
+- 0x018040, 0x001924, 0x010F0D, 0x00397D,
+- 0x000820, 0x058040, 0x038042, 0x09844A,
+- 0x000606, 0x08040A, 0x000424, 0x000424,
+- 0x00117D, 0x018042, 0x08000A, 0x000A24,
+- 0x280502, 0x280C02, 0x09800D, 0x000820,
+- 0x0002FD, 0x018040, 0x200007, 0x0022FD,
+- 0x018042, 0x08000A, 0x000095, 0x280DC4,
+- 0x011924, 0x00197D, 0x018042, 0x0011FD,
+- 0x09804A, 0x10000A, 0x0000B5, 0x113144,
+- 0x0A8D04, 0x000007, 0x080A44, 0x129504,
+- 0x000007, 0x0023FD, 0x001020, 0x038040,
+- 0x101244, 0x000007, 0x000820, 0x039060,
+- 0x018040, 0x0002FD, 0x018042, 0x08000A,
+- 0x000904, 0x123286, 0x000007, 0x003BFD,
+- 0x000100, 0x000A10, 0x0B807A, 0x13804A,
+- 0x090984, 0x000007, 0x000095, 0x013D04,
+- 0x12B886, 0x10000A, 0x100002, 0x090984,
+- 0x000007, 0x038042, 0x11804A, 0x090D04,
+- 0x000007, 0x10000A, 0x090D84, 0x000007,
+- 0x00257D, 0x000820, 0x018040, 0x00010D,
+- 0x000810, 0x28143A, 0x00127D, 0x018042,
+- 0x20000A, 0x00197D, 0x018042, 0x00117D,
+- 0x31804A, 0x10000A, 0x003124, 0x013B8D,
+- 0x00397D, 0x000820, 0x058040, 0x038042,
+- 0x09844A, 0x000606, 0x08040A, 0x300102,
+- 0x003124, 0x000424, 0x000424, 0x001224,
+- 0x280502, 0x001A4C, 0x143986, 0x700002,
+- 0x00002D, 0x030000, 0x00387D, 0x018042,
+- 0x10000A, 0x146206, 0x002124, 0x0000AD,
+- 0x100002, 0x00010D, 0x000924, 0x006B24,
+- 0x014A0D, 0x00397D, 0x000820, 0x058040,
+- 0x038042, 0x09844A, 0x000606, 0x08040A,
+- 0x003264, 0x00008D, 0x000A24, 0x001020,
+- 0x00227D, 0x018040, 0x014F8D, 0x000810,
+- 0x08043A, 0x2B5A06, 0x000007, 0x002820,
+- 0x00207D, 0x018040, 0x00117D, 0x038042,
+- 0x13804A, 0x33800A, 0x00387D, 0x018042,
+- 0x08000A, 0x000904, 0x177286, 0x000007,
+- 0x00008D, 0x030964, 0x015B0D, 0x00397D,
+- 0x000820, 0x058040, 0x038042, 0x09844A,
+- 0x000606, 0x08040A, 0x380102, 0x000424,
+- 0x000424, 0x001224, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x15DA86, 0x000007,
+- 0x280502, 0x001A4C, 0x177186, 0x000007,
+- 0x032164, 0x00632C, 0x003DFD, 0x018042,
+- 0x08000A, 0x000095, 0x090904, 0x000007,
+- 0x000820, 0x001A4C, 0x169986, 0x018040,
+- 0x030000, 0x16B206, 0x002124, 0x00010D,
+- 0x000924, 0x006B24, 0x016F0D, 0x00397D,
+- 0x000820, 0x058040, 0x038042, 0x09844A,
+- 0x000606, 0x08040A, 0x003A64, 0x000095,
+- 0x001224, 0x0002FD, 0x018042, 0x08000A,
+- 0x000904, 0x171286, 0x000007, 0x01760D,
+- 0x000810, 0x08043A, 0x2B5A06, 0x000007,
+- 0x160A06, 0x000007, 0x007020, 0x08010A,
+- 0x10012A, 0x0020FD, 0x038860, 0x039060,
+- 0x018040, 0x00227D, 0x018042, 0x003DFD,
+- 0x08000A, 0x31844A, 0x000904, 0x181086,
+- 0x18008B, 0x00008D, 0x189904, 0x00312C,
+- 0x18E206, 0x000007, 0x00324C, 0x186B86,
+- 0x000007, 0x001904, 0x186886, 0x000007,
+- 0x000095, 0x199144, 0x00222C, 0x003124,
+- 0x00636C, 0x000E3D, 0x001375, 0x000BFD,
+- 0x010042, 0x09804A, 0x10000A, 0x038AEC,
+- 0x0393EC, 0x00224C, 0x18E186, 0x000007,
+- 0x00008D, 0x189904, 0x00226C, 0x00322C,
+- 0x30050A, 0x301DAB, 0x002083, 0x0018FD,
+- 0x018042, 0x08000A, 0x018924, 0x300502,
+- 0x001083, 0x001875, 0x010042, 0x10000A,
+- 0x00008D, 0x010924, 0x001375, 0x330542,
+- 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
+- 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
+- 0x006083, 0x0002F5, 0x010042, 0x08000A,
+- 0x000904, 0x19B286, 0x000007, 0x001E2D,
+- 0x0005FD, 0x018042, 0x08000A, 0x028924,
+- 0x280502, 0x00060D, 0x000810, 0x280C3A,
+- 0x00008D, 0x000810, 0x28143A, 0x0A808D,
+- 0x000820, 0x0002F5, 0x010040, 0x220007,
+- 0x001275, 0x030042, 0x21004A, 0x00008D,
+- 0x1A0944, 0x000007, 0x01AB8D, 0x000810,
+- 0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
+- 0x030042, 0x0D004A, 0x10000A, 0x089144,
+- 0x000007, 0x000820, 0x010040, 0x0025F5,
+- 0x0A3144, 0x000007, 0x000820, 0x032860,
+- 0x030040, 0x00217D, 0x038042, 0x0B804A,
+- 0x10000A, 0x000820, 0x031060, 0x030040,
+- 0x00008D, 0x000124, 0x00012C, 0x000E64,
+- 0x001A64, 0x00636C, 0x08010A, 0x10012A,
+- 0x000820, 0x031060, 0x030040, 0x0020FD,
+- 0x018042, 0x08000A, 0x00227D, 0x018042,
+- 0x10000A, 0x000820, 0x031060, 0x030040,
+- 0x00197D, 0x018042, 0x08000A, 0x0022FD,
+- 0x038042, 0x10000A, 0x000820, 0x031060,
+- 0x030040, 0x090D04, 0x000007, 0x000820,
+- 0x030040, 0x038042, 0x0B804A, 0x10000A,
+- 0x000820, 0x031060, 0x030040, 0x038042,
+- 0x13804A, 0x19804A, 0x110D04, 0x198D04,
+- 0x000007, 0x08000A, 0x001020, 0x031860,
+- 0x030860, 0x030040, 0x00008D, 0x0B0944,
+- 0x000007, 0x000820, 0x010040, 0x0005F5,
+- 0x030042, 0x08000A, 0x000820, 0x010040,
+- 0x0000F5, 0x010042, 0x08000A, 0x000904,
+- 0x1D9886, 0x001E75, 0x030042, 0x01044A,
+- 0x000C0A, 0x1DAA06, 0x000007, 0x000402,
+- 0x000C02, 0x00177D, 0x001AF5, 0x018042,
+- 0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
+- 0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
+- 0x00043D, 0x0013F5, 0x001AFD, 0x030042,
+- 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
+- 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
+- 0x005502, 0x005D0A, 0x030042, 0x0B004A,
+- 0x1B804A, 0x13804A, 0x20000A, 0x089144,
+- 0x19A144, 0x0389E4, 0x0399EC, 0x006502,
+- 0x006D0A, 0x030042, 0x0B004A, 0x19004A,
+- 0x2B804A, 0x13804A, 0x21804A, 0x30000A,
+- 0x089144, 0x19A144, 0x2AB144, 0x0389E4,
+- 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
+- 0x000702, 0x00107D, 0x000415, 0x018042,
+- 0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
+- 0x0019FD, 0x010042, 0x09804A, 0x10000A,
+- 0x000934, 0x001674, 0x0029F5, 0x010042,
+- 0x10000A, 0x00917C, 0x002075, 0x010042,
+- 0x08000A, 0x000904, 0x200A86, 0x0026F5,
+- 0x0027F5, 0x030042, 0x09004A, 0x10000A,
+- 0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
+- 0x010042, 0x51804A, 0x48000A, 0x160007,
+- 0x001075, 0x010042, 0x282C0A, 0x281D12,
+- 0x282512, 0x001F32, 0x1E0007, 0x0E0007,
+- 0x001975, 0x010042, 0x002DF5, 0x0D004A,
+- 0x10000A, 0x009144, 0x20EA86, 0x010042,
+- 0x28340A, 0x000E5D, 0x00008D, 0x000375,
+- 0x000820, 0x010040, 0x05D2F4, 0x54D104,
+- 0x00735C, 0x218B86, 0x000007, 0x0C0007,
+- 0x080007, 0x0A0007, 0x02178D, 0x000810,
+- 0x08043A, 0x34B206, 0x000007, 0x219206,
+- 0x000007, 0x080007, 0x002275, 0x010042,
+- 0x20000A, 0x002104, 0x225886, 0x001E2D,
+- 0x0002F5, 0x010042, 0x08000A, 0x000904,
+- 0x21CA86, 0x000007, 0x002010, 0x30043A,
+- 0x00057D, 0x0180C3, 0x08000A, 0x028924,
+- 0x280502, 0x280C02, 0x0A810D, 0x000820,
+- 0x0002F5, 0x010040, 0x220007, 0x0004FD,
+- 0x018042, 0x70000A, 0x030000, 0x007020,
+- 0x07FA06, 0x018040, 0x022B8D, 0x000810,
+- 0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
+- 0x018042, 0x08000A, 0x000904, 0x22C286,
+- 0x000007, 0x020206, 0x000007, 0x000875,
+- 0x0009FD, 0x00010D, 0x234206, 0x000295,
+- 0x000B75, 0x00097D, 0x00000D, 0x000515,
+- 0x010042, 0x18000A, 0x001904, 0x2A0086,
+- 0x0006F5, 0x001020, 0x010040, 0x0004F5,
+- 0x000820, 0x010040, 0x000775, 0x010042,
+- 0x09804A, 0x10000A, 0x001124, 0x000904,
+- 0x23F286, 0x000815, 0x080102, 0x101204,
+- 0x241206, 0x000575, 0x081204, 0x000007,
+- 0x100102, 0x000575, 0x000425, 0x021124,
+- 0x100102, 0x000820, 0x031060, 0x010040,
+- 0x001924, 0x2A0086, 0x00008D, 0x000464,
+- 0x009D04, 0x291086, 0x180102, 0x000575,
+- 0x010042, 0x28040A, 0x00018D, 0x000924,
+- 0x280D02, 0x00000D, 0x000924, 0x281502,
+- 0x10000D, 0x000820, 0x0002F5, 0x010040,
+- 0x200007, 0x001175, 0x0002FD, 0x018042,
+- 0x08000A, 0x000904, 0x24FA86, 0x000007,
+- 0x000100, 0x080B20, 0x130B60, 0x1B0B60,
+- 0x030A60, 0x010040, 0x050042, 0x3D004A,
+- 0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
+- 0x010042, 0x28140A, 0x0004F5, 0x010042,
+- 0x08000A, 0x000315, 0x010D04, 0x260286,
+- 0x004015, 0x000095, 0x010D04, 0x25F086,
+- 0x100022, 0x10002A, 0x261A06, 0x000007,
+- 0x333104, 0x2AA904, 0x000007, 0x032124,
+- 0x280502, 0x284402, 0x001124, 0x400102,
+- 0x000424, 0x000424, 0x003224, 0x00292C,
+- 0x00636C, 0x277386, 0x000007, 0x02B164,
+- 0x000464, 0x000464, 0x00008D, 0x000A64,
+- 0x280D02, 0x10008D, 0x000820, 0x0002F5,
+- 0x010040, 0x220007, 0x00008D, 0x38B904,
+- 0x000007, 0x03296C, 0x30010A, 0x0002F5,
+- 0x010042, 0x08000A, 0x000904, 0x270286,
+- 0x000007, 0x00212C, 0x28050A, 0x00316C,
+- 0x00046C, 0x00046C, 0x28450A, 0x001124,
+- 0x006B64, 0x100102, 0x00008D, 0x01096C,
+- 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
+- 0x010040, 0x220007, 0x004124, 0x000424,
+- 0x000424, 0x003224, 0x300102, 0x032944,
+- 0x27FA86, 0x000007, 0x300002, 0x0004F5,
+- 0x010042, 0x08000A, 0x000315, 0x010D04,
+- 0x284086, 0x003124, 0x000464, 0x300102,
+- 0x0002F5, 0x010042, 0x08000A, 0x000904,
+- 0x284A86, 0x000007, 0x284402, 0x003124,
+- 0x300502, 0x003924, 0x300583, 0x000883,
+- 0x0005F5, 0x010042, 0x28040A, 0x00008D,
+- 0x008124, 0x280D02, 0x00008D, 0x008124,
+- 0x281502, 0x10018D, 0x000820, 0x0002F5,
+- 0x010040, 0x220007, 0x001025, 0x000575,
+- 0x030042, 0x09004A, 0x10000A, 0x0A0904,
+- 0x121104, 0x000007, 0x001020, 0x050860,
+- 0x050040, 0x0006FD, 0x018042, 0x09004A,
+- 0x10000A, 0x0000A5, 0x0A0904, 0x121104,
+- 0x000007, 0x000820, 0x019060, 0x010040,
+- 0x0002F5, 0x010042, 0x08000A, 0x000904,
+- 0x29CA86, 0x000007, 0x244206, 0x000007,
+- 0x000606, 0x000007, 0x0002F5, 0x010042,
+- 0x08000A, 0x000904, 0x2A1A86, 0x000007,
+- 0x000100, 0x080B20, 0x138B60, 0x1B8B60,
+- 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
+- 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
+- 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
+- 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
+- 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
+- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
+- 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
+- 0x038A60, 0x000606, 0x018040, 0x00008D,
+- 0x000A64, 0x280D02, 0x000A24, 0x00027D,
+- 0x018042, 0x10000A, 0x001224, 0x0003FD,
+- 0x018042, 0x08000A, 0x000904, 0x2C0A86,
+- 0x000007, 0x00018D, 0x000A24, 0x000464,
+- 0x000464, 0x080102, 0x000924, 0x000424,
+- 0x000424, 0x100102, 0x02000D, 0x009144,
+- 0x2C6186, 0x000007, 0x0001FD, 0x018042,
+- 0x08000A, 0x000A44, 0x2C4386, 0x018042,
+- 0x0A000D, 0x000820, 0x0002FD, 0x018040,
+- 0x200007, 0x00027D, 0x001020, 0x000606,
+- 0x018040, 0x0002F5, 0x010042, 0x08000A,
+- 0x000904, 0x2CB286, 0x000007, 0x00037D,
+- 0x018042, 0x08000A, 0x000904, 0x2CE286,
+- 0x000007, 0x000075, 0x002E7D, 0x010042,
+- 0x0B804A, 0x000020, 0x000904, 0x000686,
+- 0x010040, 0x31844A, 0x30048B, 0x000883,
+- 0x00008D, 0x000810, 0x28143A, 0x00008D,
+- 0x000810, 0x280C3A, 0x000675, 0x010042,
+- 0x08000A, 0x003815, 0x010924, 0x280502,
+- 0x0B000D, 0x000820, 0x0002F5, 0x010040,
+- 0x000606, 0x220007, 0x000464, 0x000464,
+- 0x000606, 0x000007, 0x000134, 0x007F8D,
+- 0x00093C, 0x281D12, 0x282512, 0x001F32,
+- 0x0E0007, 0x00010D, 0x00037D, 0x000820,
+- 0x018040, 0x05D2F4, 0x000007, 0x080007,
+- 0x00037D, 0x018042, 0x08000A, 0x000904,
+- 0x2E8A86, 0x000007, 0x000606, 0x000007,
+- 0x000007, 0x000012, 0x100007, 0x320007,
+- 0x600007, 0x460007, 0x100080, 0x48001A,
+- 0x004904, 0x2EF186, 0x000007, 0x001210,
+- 0x58003A, 0x000145, 0x5C5D04, 0x000007,
+- 0x000080, 0x48001A, 0x004904, 0x2F4186,
+- 0x000007, 0x001210, 0x50003A, 0x005904,
+- 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
+- 0x7FFF7D, 0x07D524, 0x004224, 0x500102,
+- 0x200502, 0x000082, 0x40001A, 0x004104,
+- 0x2FC986, 0x000007, 0x003865, 0x40001A,
+- 0x004020, 0x00104D, 0x04C184, 0x31AB86,
+- 0x000040, 0x040007, 0x000165, 0x000145,
+- 0x004020, 0x000040, 0x000765, 0x080080,
+- 0x40001A, 0x004104, 0x305986, 0x000007,
+- 0x001210, 0x40003A, 0x004104, 0x30B286,
+- 0x00004D, 0x0000CD, 0x004810, 0x20043A,
+- 0x000882, 0x40001A, 0x004104, 0x30C186,
+- 0x000007, 0x004820, 0x005904, 0x319886,
+- 0x000040, 0x0007E5, 0x200480, 0x2816A0,
+- 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
+- 0x000040, 0x000032, 0x400075, 0x00007D,
+- 0x07D574, 0x200512, 0x000082, 0x40001A,
+- 0x004104, 0x317186, 0x000007, 0x038A06,
+- 0x640007, 0x0000E5, 0x000020, 0x000040,
+- 0x000A65, 0x000020, 0x020040, 0x020040,
+- 0x000040, 0x000165, 0x000042, 0x70000A,
+- 0x007104, 0x323286, 0x000007, 0x060007,
+- 0x019A06, 0x640007, 0x050000, 0x007020,
+- 0x000040, 0x038A06, 0x640007, 0x000007,
+- 0x00306D, 0x028860, 0x029060, 0x08000A,
+- 0x028860, 0x008040, 0x100012, 0x00100D,
+- 0x009184, 0x32D186, 0x000E0D, 0x009184,
+- 0x33E186, 0x000007, 0x300007, 0x001020,
+- 0x003B6D, 0x008040, 0x000080, 0x08001A,
+- 0x000904, 0x32F186, 0x000007, 0x001220,
+- 0x000DED, 0x008040, 0x008042, 0x10000A,
+- 0x40000D, 0x109544, 0x000007, 0x001020,
+- 0x000DED, 0x008040, 0x008042, 0x20040A,
+- 0x000082, 0x08001A, 0x000904, 0x338186,
+- 0x000007, 0x003B6D, 0x008042, 0x08000A,
+- 0x000E15, 0x010984, 0x342B86, 0x600007,
+- 0x08001A, 0x000C15, 0x010984, 0x341386,
+- 0x000020, 0x1A0007, 0x0002ED, 0x008040,
+- 0x620007, 0x00306D, 0x028042, 0x0A804A,
+- 0x000820, 0x0A804A, 0x000606, 0x10804A,
+- 0x000007, 0x282512, 0x001F32, 0x05D2F4,
+- 0x54D104, 0x00735C, 0x000786, 0x000007,
+- 0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
+- 0x020040, 0x004820, 0x025060, 0x40000A,
+- 0x024060, 0x000040, 0x454944, 0x000007,
+- 0x004020, 0x003AE5, 0x000040, 0x0028E5,
+- 0x000042, 0x48000A, 0x004904, 0x39F886,
+- 0x002C65, 0x000042, 0x40000A, 0x0000D5,
+- 0x454104, 0x000007, 0x000655, 0x054504,
+- 0x368286, 0x0001D5, 0x054504, 0x368086,
+- 0x002B65, 0x000042, 0x003AE5, 0x50004A,
+- 0x40000A, 0x45C3D4, 0x000007, 0x454504,
+- 0x000007, 0x0000CD, 0x444944, 0x000007,
+- 0x454504, 0x000007, 0x00014D, 0x554944,
+- 0x000007, 0x045144, 0x367986, 0x002C65,
+- 0x000042, 0x48000A, 0x4CD104, 0x000007,
+- 0x04C144, 0x368386, 0x000007, 0x160007,
+- 0x002CE5, 0x040042, 0x40000A, 0x004020,
+- 0x000040, 0x002965, 0x000042, 0x40000A,
+- 0x004104, 0x36F086, 0x000007, 0x002402,
+- 0x383206, 0x005C02, 0x0025E5, 0x000042,
+- 0x40000A, 0x004274, 0x002AE5, 0x000042,
+- 0x40000A, 0x004274, 0x500112, 0x0029E5,
+- 0x000042, 0x40000A, 0x004234, 0x454104,
+- 0x000007, 0x004020, 0x000040, 0x003EE5,
+- 0x000020, 0x000040, 0x002DE5, 0x400152,
+- 0x50000A, 0x045144, 0x37DA86, 0x0000C5,
+- 0x003EE5, 0x004020, 0x000040, 0x002BE5,
+- 0x000042, 0x40000A, 0x404254, 0x000007,
+- 0x002AE5, 0x004020, 0x000040, 0x500132,
+- 0x040134, 0x005674, 0x0029E5, 0x020042,
+- 0x42000A, 0x000042, 0x50000A, 0x05417C,
+- 0x0028E5, 0x000042, 0x48000A, 0x0000C5,
+- 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
+- 0x020042, 0x40004A, 0x50000A, 0x00423C,
+- 0x00567C, 0x0028E5, 0x004820, 0x000040,
+- 0x281D12, 0x282512, 0x001F72, 0x002965,
+- 0x000042, 0x40000A, 0x004104, 0x393A86,
+- 0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
+- 0x000042, 0x40000A, 0x004104, 0x397886,
+- 0x002D65, 0x000042, 0x28340A, 0x003465,
+- 0x020042, 0x42004A, 0x004020, 0x4A004A,
+- 0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
+- 0x39E186, 0x000007, 0x000606, 0x080007,
+- 0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
+- 0x020045, 0x004020, 0x000060, 0x000365,
+- 0x000040, 0x002E65, 0x001A20, 0x0A1A60,
+- 0x000040, 0x003465, 0x020042, 0x42004A,
+- 0x004020, 0x4A004A, 0x000606, 0x50004A,
+- 0x0017FD, 0x018042, 0x08000A, 0x000904,
+- 0x225A86, 0x000007, 0x00107D, 0x018042,
+- 0x0011FD, 0x33804A, 0x19804A, 0x20000A,
+- 0x000095, 0x2A1144, 0x01A144, 0x3B9086,
+- 0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
+- 0x018042, 0x0010FD, 0x09804A, 0x38000A,
+- 0x000095, 0x010924, 0x003A64, 0x3B8186,
+- 0x000007, 0x003904, 0x3B9286, 0x000007,
+- 0x3B9A06, 0x00000D, 0x00008D, 0x000820,
+- 0x00387D, 0x018040, 0x700002, 0x00117D,
+- 0x018042, 0x00197D, 0x29804A, 0x30000A,
+- 0x380002, 0x003124, 0x000424, 0x000424,
+- 0x002A24, 0x280502, 0x00068D, 0x000810,
+- 0x28143A, 0x00750D, 0x00B124, 0x002264,
+- 0x3D0386, 0x284402, 0x000810, 0x280C3A,
+- 0x0B800D, 0x000820, 0x0002FD, 0x018040,
+- 0x200007, 0x00758D, 0x00B124, 0x100102,
+- 0x012144, 0x3E4986, 0x001810, 0x10003A,
+- 0x00387D, 0x018042, 0x08000A, 0x000904,
+- 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
+- 0x00008D, 0x023164, 0x000A64, 0x280D02,
+- 0x0B808D, 0x000820, 0x0002FD, 0x018040,
+- 0x200007, 0x00387D, 0x018042, 0x08000A,
+- 0x000904, 0x3E3286, 0x030000, 0x0002FD,
+- 0x018042, 0x08000A, 0x000904, 0x3D8286,
+- 0x000007, 0x002810, 0x28043A, 0x00750D,
+- 0x030924, 0x002264, 0x280D02, 0x02316C,
+- 0x28450A, 0x0B810D, 0x000820, 0x0002FD,
+- 0x018040, 0x200007, 0x00008D, 0x000A24,
+- 0x3E4A06, 0x100102, 0x001810, 0x10003A,
+- 0x0000BD, 0x003810, 0x30043A, 0x00187D,
+- 0x018042, 0x0018FD, 0x09804A, 0x20000A,
+- 0x0000AD, 0x028924, 0x07212C, 0x001010,
+- 0x300583, 0x300D8B, 0x3014BB, 0x301C83,
+- 0x002083, 0x00137D, 0x038042, 0x33844A,
+- 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
+- 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
+- 0x001E0D, 0x0005FD, 0x018042, 0x20000A,
+- 0x020924, 0x00068D, 0x00A96C, 0x00009D,
+- 0x0002FD, 0x018042, 0x08000A, 0x000904,
+- 0x3F6A86, 0x000007, 0x280502, 0x280D0A,
+- 0x284402, 0x001810, 0x28143A, 0x0C008D,
+- 0x000820, 0x0002FD, 0x018040, 0x220007,
+- 0x003904, 0x225886, 0x001E0D, 0x00057D,
+- 0x018042, 0x20000A, 0x020924, 0x0000A5,
+- 0x0002FD, 0x018042, 0x08000A, 0x000904,
+- 0x402A86, 0x000007, 0x280502, 0x280C02,
+- 0x002010, 0x28143A, 0x0C010D, 0x000820,
+- 0x0002FD, 0x018040, 0x225A06, 0x220007,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000,
+- 0x000000, 0x000000, 0x000000, 0x000000
+-};
+-
+-#endif //_HWMCODE_
+diff --git a/sound/oss/yss225.c b/sound/oss/yss225.c
+deleted file mode 100644
+index e700400..0000000
+--- a/sound/oss/yss225.c
++++ /dev/null
+@@ -1,319 +0,0 @@
+-#include <linux/init.h>
+-
+-unsigned char page_zero[] __initdata = {
+-0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
+-0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
+-0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
+-0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
+-0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
+-0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
+-0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
+-0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
+-0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
+-0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
+-0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
+-0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
+-0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+-0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
+-0x1d, 0x02, 0xdf
+-};
+-
+-unsigned char page_one[] __initdata = {
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
+-0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
+-0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
+-0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
+-0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
+-0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
+-0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
+-0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
+-0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
+-0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
+-0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+-0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
+-0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
+-0x60, 0x00, 0x1b
+-};
+-
+-unsigned char page_two[] __initdata = {
+-0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
+-0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
+-0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
+-0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
+-0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
+-0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
+-0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
+-0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
+-};
+-
+-unsigned char page_three[] __initdata = {
+-0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
+-0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
+-0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
+-0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
+-0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+-0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+-0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
+-0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
+-};
+-
+-unsigned char page_four[] __initdata = {
+-0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
+-0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
+-0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
+-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
+-0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
+-0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
+-0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
+-};
+-
+-unsigned char page_six[] __initdata = {
+-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
+-0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
+-0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
+-0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
+-0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
+-0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
+-0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
+-0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
+-0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
+-0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
+-0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
+-0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
+-0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
+-0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
+-0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
+-0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
+-0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
+-0x80, 0x00, 0x7e, 0x80, 0x80
+-};
+-
+-unsigned char page_seven[] __initdata = {
+-0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+-0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
+-0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
+-0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
+-0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
+-0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
+-0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
+-0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
+-0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
+-0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
+-0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
+-0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x02, 0x00
+-};
+-
+-unsigned char page_zero_v2[] __initdata = {
+-0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
+-
+-unsigned char page_one_v2[] __initdata = {
+-0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
+-
+-unsigned char page_two_v2[] __initdata = {
+-0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00
+-};
+-unsigned char page_three_v2[] __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
+-};
+-unsigned char page_four_v2[] __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
+-};
+-
+-unsigned char page_seven_v2[] __initdata = {
+-0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
+-unsigned char mod_v2[] __initdata = {
+-0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
+-0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
+-0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
+-0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
+-0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
+-0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
+-0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
+-0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
+-0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
+-0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
+-0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
+-0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
+-0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
+-0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
+-0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
+-0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
+-0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
+-0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
+-0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
+-0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
+-0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
+-0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
+-0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
+-0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
+-0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
+-0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
+-0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
+-0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
+-};
+-unsigned char coefficients[] __initdata = {
+-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
+-0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
+-0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
+-0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
+-0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
+-0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
+-0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
+-0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
+-0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
+-0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
+-0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
+-0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
+-0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
+-0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
+-0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
+-0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
+-0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
+-0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
+-0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
+-0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
+-0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
+-0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
+-0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
+-0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
+-0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
+-0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
+-0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
+-0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
+-0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
+-0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
+-0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
+-0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
+-0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
+-0xba
+-};
+-unsigned char coefficients2[] __initdata = {
+-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
+-0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
+-0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
+-0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
+-0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
+-};
+-unsigned char coefficients3[] __initdata = {
+-0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
+-0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
+-0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
+-0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
+-0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
+-0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
+-0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
+-0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
+-0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
+-0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
+-0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
+-0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
+-0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
+-0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
+-0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
+-0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
+-0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
+-0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
+-0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
+-0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
+-0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
+-0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
+-0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
+-0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
+-0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
+-0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
+-0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
+-0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
+-0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
+-0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
+-0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
+-0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
+-0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
+-0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
+-0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
+-0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
+-0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
+-};
+-
+diff --git a/sound/oss/yss225.h b/sound/oss/yss225.h
+deleted file mode 100644
+index 56d8b6b..0000000
+--- a/sound/oss/yss225.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-#ifndef __yss255_h__
+-#define __yss255_h__
+-
+-extern unsigned char page_zero[256];
+-extern unsigned char page_one[256];
+-extern unsigned char page_two[128];
+-extern unsigned char page_three[128];
+-extern unsigned char page_four[128];
+-extern unsigned char page_six[192];
+-extern unsigned char page_seven[256];
+-extern unsigned char page_zero_v2[96];
+-extern unsigned char page_one_v2[96];
+-extern unsigned char page_two_v2[48];
+-extern unsigned char page_three_v2[48];
+-extern unsigned char page_four_v2[48];
+-extern unsigned char page_seven_v2[96];
+-extern unsigned char mod_v2[304];
+-extern unsigned char coefficients[364];
+-extern unsigned char coefficients2[56];
+-extern unsigned char coefficients3[404];
+-
+-
+-#endif /* __ys225_h__ */
+-
+diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
+index ce73f3e..cf60333 100644
+--- a/sound/parisc/harmony.c
++++ b/sound/parisc/harmony.c
+@@ -193,7 +193,7 @@ harmony_set_control(struct snd_harmony *
+ }
+
+ static irqreturn_t
+-snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
++snd_harmony_interrupt(int irq, void *dev)
+ {
+ u32 dstatus;
+ struct snd_harmony *h = dev;
+diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
+index e49c0fe..8a6b180 100644
+--- a/sound/pci/Kconfig
++++ b/sound/pci/Kconfig
+@@ -475,6 +475,7 @@ config SND_FM801_TEA575X
+ depends on SND_FM801_TEA575X_BOOL
+ default SND_FM801
+ select VIDEO_V4L1
++ select VIDEO_DEV
+
+ config SND_HDA_INTEL
+ tristate "Intel HD Audio"
+@@ -743,4 +744,17 @@ config SND_YMFPCI
+ To compile this driver as a module, choose M here: the module
+ will be called snd-ymfpci.
+
++config SND_AC97_POWER_SAVE
++ bool "AC97 Power-Saving Mode"
++ depends on SND_AC97_CODEC && EXPERIMENTAL
++ default n
++ help
++ Say Y here to enable the aggressive power-saving support of
++ AC97 codecs. In this mode, the power-mode is dynamically
++ controlled at each open/close.
++
++ The mode is activated by passing power_save=1 option to
++ snd-ac97-codec driver. You can toggle it dynamically over
++ sysfs, too.
++
+ endmenu
+diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
+index 51e83d7..6577b23 100644
+--- a/sound/pci/ac97/ac97_codec.c
++++ b/sound/pci/ac97/ac97_codec.c
+@@ -31,6 +31,7 @@
+ #include <linux/mutex.h>
+ #include <sound/core.h>
+ #include <sound/pcm.h>
++#include <sound/tlv.h>
+ #include <sound/ac97_codec.h>
+ #include <sound/asoundef.h>
+ #include <sound/initval.h>
+@@ -47,6 +48,11 @@ static int enable_loopback;
+ module_param(enable_loopback, bool, 0444);
+ MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
+
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++static int power_save;
++module_param(power_save, bool, 0644);
++MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
++#endif
+ /*
+
+ */
+@@ -151,7 +157,7 @@ static const struct ac97_codec_id snd_ac
+ { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk
+ { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
+ { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix
+-{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
++{ 0x50534304, 0xffffffff, "UCB1400", patch_ucb1400, NULL },
+ { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH },
+ { 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
+ { 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
+@@ -187,6 +193,8 @@ static const struct ac97_codec_id snd_ac
+ };
+
+
++static void update_power_regs(struct snd_ac97 *ac97);
++
+ /*
+ * I/O routines
+ */
+@@ -554,6 +562,17 @@ int snd_ac97_put_volsw(struct snd_kcontr
+ }
+ err = snd_ac97_update_bits(ac97, reg, val_mask, val);
+ snd_ac97_page_restore(ac97, page_save);
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ /* check analog mixer power-down */
++ if ((val_mask & 0x8000) &&
++ (kcontrol->private_value & (1<<30))) {
++ if (val & 0x8000)
++ ac97->power_up &= ~(1 << (reg>>1));
++ else
++ ac97->power_up |= 1 << (reg>>1);
++ update_power_regs(ac97);
++ }
++#endif
+ return err;
+ }
+
+@@ -962,6 +981,10 @@ static int snd_ac97_bus_dev_free(struct
+ static int snd_ac97_free(struct snd_ac97 *ac97)
+ {
+ if (ac97) {
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ if (ac97->power_workq)
++ destroy_workqueue(ac97->power_workq);
++#endif
+ snd_ac97_proc_done(ac97);
+ if (ac97->bus)
+ ac97->bus->codec[ac97->num] = NULL;
+@@ -1117,7 +1140,9 @@ struct snd_kcontrol *snd_ac97_cnew(const
+ /*
+ * create mute switch(es) for normal stereo controls
+ */
+-static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97)
++static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
++ int check_stereo, int check_amix,
++ struct snd_ac97 *ac97)
+ {
+ struct snd_kcontrol *kctl;
+ int err;
+@@ -1137,10 +1162,14 @@ static int snd_ac97_cmute_new_stereo(str
+ }
+ if (mute_mask == 0x8080) {
+ struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
++ if (check_amix)
++ tmp.private_value |= (1 << 30);
+ tmp.index = ac97->num;
+ kctl = snd_ctl_new1(&tmp, ac97);
+ } else {
+ struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1);
++ if (check_amix)
++ tmp.private_value |= (1 << 30);
+ tmp.index = ac97->num;
+ kctl = snd_ctl_new1(&tmp, ac97);
+ }
+@@ -1153,6 +1182,32 @@ static int snd_ac97_cmute_new_stereo(str
+ }
+
+ /*
++ * set dB information
++ */
++static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
++
++static unsigned int *find_db_scale(unsigned int maxval)
++{
++ switch (maxval) {
++ case 0x0f: return db_scale_4bit;
++ case 0x1f: return db_scale_5bit;
++ case 0x3f: return db_scale_6bit;
++ }
++ return NULL;
++}
++
++static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
++{
++ kctl->tlv.p = tlv;
++ if (tlv)
++ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
++}
++
++/*
+ * create a volume for normal stereo/mono controls
+ */
+ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max,
+@@ -1174,6 +1229,10 @@ static int snd_ac97_cvol_new(struct snd_
+ tmp.index = ac97->num;
+ kctl = snd_ctl_new1(&tmp, ac97);
+ }
++ if (reg >= AC97_PHONE && reg <= AC97_PCM)
++ set_tlv_db_scale(kctl, db_scale_5bit_12db_max);
++ else
++ set_tlv_db_scale(kctl, find_db_scale(lo_max));
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
+@@ -1186,7 +1245,9 @@ static int snd_ac97_cvol_new(struct snd_
+ /*
+ * create a mute-switch and a volume for normal stereo/mono controls
+ */
+-static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97)
++static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
++ int reg, int check_stereo, int check_amix,
++ struct snd_ac97 *ac97)
+ {
+ int err;
+ char name[44];
+@@ -1197,7 +1258,9 @@ static int snd_ac97_cmix_new_stereo(stru
+
+ if (snd_ac97_try_bit(ac97, reg, 15)) {
+ sprintf(name, "%s Switch", pfx);
+- if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0)
++ if ((err = snd_ac97_cmute_new_stereo(card, name, reg,
++ check_stereo, check_amix,
++ ac97)) < 0)
+ return err;
+ }
+ check_volume_resolution(ac97, reg, &lo_max, &hi_max);
+@@ -1209,8 +1272,10 @@ static int snd_ac97_cmix_new_stereo(stru
+ return 0;
+ }
+
+-#define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97)
+-#define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97)
++#define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \
++ snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97)
++#define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \
++ snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97)
+
+ static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
+
+@@ -1226,9 +1291,11 @@ static int snd_ac97_mixer_build(struct s
+ /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
+ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
+ if (ac97->flags & AC97_HAS_NO_MASTER_VOL)
+- err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97);
++ err = snd_ac97_cmute_new(card, "Master Playback Switch",
++ AC97_MASTER, 0, ac97);
+ else
+- err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97);
++ err = snd_ac97_cmix_new(card, "Master Playback",
++ AC97_MASTER, 0, ac97);
+ if (err < 0)
+ return err;
+ }
+@@ -1245,6 +1312,7 @@ static int snd_ac97_mixer_build(struct s
+ snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max);
+ kctl->private_value &= ~(0xff << 16);
+ kctl->private_value |= (int)max << 16;
++ set_tlv_db_scale(kctl, find_db_scale(max));
+ snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max);
+ }
+
+@@ -1258,6 +1326,7 @@ static int snd_ac97_mixer_build(struct s
+ snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max);
+ kctl->private_value &= ~(0xff << 16);
+ kctl->private_value |= (int)max << 16;
++ set_tlv_db_scale(kctl, find_db_scale(max));
+ snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8);
+ }
+
+@@ -1265,19 +1334,23 @@ static int snd_ac97_mixer_build(struct s
+ if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
+ && !(ac97->flags & AC97_AD_MULTI)) {
+ /* Surround Master (0x38) is with stereo mutes */
+- if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback",
++ AC97_SURROUND_MASTER, 1, 0,
++ ac97)) < 0)
+ return err;
+ }
+
+ /* build headphone controls */
+ if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
+- if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Headphone Playback",
++ AC97_HEADPHONE, 0, ac97)) < 0)
+ return err;
+ }
+
+ /* build master mono controls */
+ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
+- if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Master Mono Playback",
++ AC97_MASTER_MONO, 0, ac97)) < 0)
+ return err;
+ }
+
+@@ -1301,8 +1374,9 @@ static int snd_ac97_mixer_build(struct s
+ ((ac97->flags & AC97_HAS_PC_BEEP) ||
+ snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) {
+ for (idx = 0; idx < 2; idx++)
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_4bit);
+ snd_ac97_write_cache(ac97, AC97_PC_BEEP,
+ snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e);
+ }
+@@ -1310,7 +1384,8 @@ static int snd_ac97_mixer_build(struct s
+ /* build Phone controls */
+ if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
+- if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Phone Playback",
++ AC97_PHONE, 1, ac97)) < 0)
+ return err;
+ }
+ }
+@@ -1318,7 +1393,8 @@ static int snd_ac97_mixer_build(struct s
+ /* build MIC controls */
+ if (!(ac97->flags & AC97_HAS_NO_MIC)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+- if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Mic Playback",
++ AC97_MIC, 1, ac97)) < 0)
+ return err;
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
+ return err;
+@@ -1327,14 +1403,16 @@ static int snd_ac97_mixer_build(struct s
+
+ /* build Line controls */
+ if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
+- if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Line Playback",
++ AC97_LINE, 1, ac97)) < 0)
+ return err;
+ }
+
+ /* build CD controls */
+ if (!(ac97->flags & AC97_HAS_NO_CD)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
+- if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "CD Playback",
++ AC97_CD, 1, ac97)) < 0)
+ return err;
+ }
+ }
+@@ -1342,7 +1420,8 @@ static int snd_ac97_mixer_build(struct s
+ /* build Video controls */
+ if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
+- if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Video Playback",
++ AC97_VIDEO, 1, ac97)) < 0)
+ return err;
+ }
+ }
+@@ -1350,7 +1429,8 @@ static int snd_ac97_mixer_build(struct s
+ /* build Aux controls */
+ if (!(ac97->flags & AC97_HAS_NO_AUX)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
+- if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
++ if ((err = snd_ac97_cmix_new(card, "Aux Playback",
++ AC97_AUX, 1, ac97)) < 0)
+ return err;
+ }
+ }
+@@ -1363,31 +1443,38 @@ static int snd_ac97_mixer_build(struct s
+ else
+ init_val = 0x9f1f;
+ for (idx = 0; idx < 2; idx++)
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_5bit);
+ ac97->spec.ad18xx.pcmreg[0] = init_val;
+ if (ac97->scaps & AC97_SCAP_SURROUND_DAC) {
+ for (idx = 0; idx < 2; idx++)
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_5bit);
+ ac97->spec.ad18xx.pcmreg[1] = init_val;
+ }
+ if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) {
+ for (idx = 0; idx < 2; idx++)
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_5bit);
+ for (idx = 0; idx < 2; idx++)
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_5bit);
+ ac97->spec.ad18xx.pcmreg[2] = init_val;
+ }
+ snd_ac97_write_cache(ac97, AC97_PCM, init_val);
+ } else {
+ if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
+ if (ac97->flags & AC97_HAS_NO_PCM_VOL)
+- err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
++ err = snd_ac97_cmute_new(card,
++ "PCM Playback Switch",
++ AC97_PCM, 0, ac97);
+ else
+- err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
++ err = snd_ac97_cmix_new(card, "PCM Playback",
++ AC97_PCM, 0, ac97);
+ if (err < 0)
+ return err;
+ }
+@@ -1398,19 +1485,23 @@ static int snd_ac97_mixer_build(struct s
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
+ return err;
+ if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
+- if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0)
++ err = snd_ac97_cmute_new(card, "Capture Switch",
++ AC97_REC_GAIN, 0, ac97);
++ if (err < 0)
+ return err;
+ }
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_rec_gain);
+ snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);
+ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);
+ }
+ /* build MIC Capture controls */
+ if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) {
+ for (idx = 0; idx < 2; idx++)
+- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0)
++ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0)
+ return err;
++ set_tlv_db_scale(kctl, db_scale_rec_gain);
+ snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000);
+ }
+
+@@ -1481,6 +1572,12 @@ static int snd_ac97_mixer_build(struct s
+ }
+
+ /* build S/PDIF controls */
++
++ /* Hack for ASUS P5P800-VM, which does not indicate S/PDIF capability */
++ if (ac97->subsystem_vendor == 0x1043 &&
++ ac97->subsystem_device == 0x810f)
++ ac97->ext_id |= AC97_EI_SPDIF;
++
+ if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) {
+ if (ac97->build_ops->build_spdif) {
+ if ((err = ac97->build_ops->build_spdif(ac97)) < 0)
+@@ -1817,18 +1914,25 @@ static int snd_ac97_dev_register(struct
+ return 0;
+ }
+
+-/* unregister ac97 codec */
+-static int snd_ac97_dev_unregister(struct snd_device *device)
++/* disconnect ac97 codec */
++static int snd_ac97_dev_disconnect(struct snd_device *device)
+ {
+ struct snd_ac97 *ac97 = device->device_data;
+ if (ac97->dev.bus)
+ device_unregister(&ac97->dev);
+- return snd_ac97_free(ac97);
++ return 0;
+ }
+
+ /* build_ops to do nothing */
+ static struct snd_ac97_build_ops null_build_ops;
+
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++static void do_update_power(void *data)
++{
++ update_power_regs(data);
++}
++#endif
++
+ /**
+ * snd_ac97_mixer - create an Codec97 component
+ * @bus: the AC97 bus which codec is attached to
+@@ -1860,7 +1964,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *
+ static struct snd_device_ops ops = {
+ .dev_free = snd_ac97_dev_free,
+ .dev_register = snd_ac97_dev_register,
+- .dev_unregister = snd_ac97_dev_unregister,
++ .dev_disconnect = snd_ac97_dev_disconnect,
+ };
+
+ snd_assert(rac97 != NULL, return -EINVAL);
+@@ -1883,6 +1987,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *
+ bus->codec[ac97->num] = ac97;
+ mutex_init(&ac97->reg_mutex);
+ mutex_init(&ac97->page_mutex);
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ ac97->power_workq = create_workqueue("ac97");
++ INIT_WORK(&ac97->power_work, do_update_power, ac97);
++#endif
+
+ #ifdef CONFIG_PCI
+ if (ac97->pci) {
+@@ -2117,15 +2225,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *
+ return -ENOMEM;
+ }
+ }
+- /* make sure the proper powerdown bits are cleared */
+- if (ac97->scaps && ac97_is_audio(ac97)) {
+- reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
+- if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
+- reg &= ~AC97_EA_PRJ;
+- if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
+- reg &= ~(AC97_EA_PRI | AC97_EA_PRK);
+- snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg);
+- }
++ if (ac97_is_audio(ac97))
++ update_power_regs(ac97);
+ snd_ac97_proc_init(ac97);
+ if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {
+ snd_ac97_free(ac97);
+@@ -2153,19 +2254,149 @@ static void snd_ac97_powerdown(struct sn
+ snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
+ }
+
+- power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */
+- power |= 0x4000; /* Headphone amplifier powerdown */
+- power |= 0x0300; /* ADC & DAC powerdown */
++ /* surround, CLFE, mic powerdown */
++ power = ac97->regs[AC97_EXTENDED_STATUS];
++ if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
++ power |= AC97_EA_PRJ;
++ if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
++ power |= AC97_EA_PRI | AC97_EA_PRK;
++ power |= AC97_EA_PRL;
++ snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power);
++
++ /* powerdown external amplifier */
++ if (ac97->scaps & AC97_SCAP_INV_EAPD)
++ power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD;
++ else if (! (ac97->scaps & AC97_SCAP_EAPD_LED))
++ power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD;
++ power |= AC97_PD_PR6; /* Headphone amplifier powerdown */
++ power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */
+ snd_ac97_write(ac97, AC97_POWERDOWN, power);
+ udelay(100);
+- power |= 0x0400; /* Analog Mixer powerdown (Vref on) */
+- snd_ac97_write(ac97, AC97_POWERDOWN, power);
+- udelay(100);
+-#if 0
+- /* FIXME: this causes click noises on some boards at resume */
+- power |= 0x3800; /* AC-link powerdown, internal Clk disable */
++ power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
+ snd_ac97_write(ac97, AC97_POWERDOWN, power);
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ if (power_save) {
++ udelay(100);
++ /* AC-link powerdown, internal Clk disable */
++ /* FIXME: this may cause click noises on some boards */
++ power |= AC97_PD_PR4 | AC97_PD_PR5;
++ snd_ac97_write(ac97, AC97_POWERDOWN, power);
++ }
++#endif
++}
++
++
++struct ac97_power_reg {
++ unsigned short reg;
++ unsigned short power_reg;
++ unsigned short mask;
++};
++
++enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE };
++
++static struct ac97_power_reg power_regs[PWIDX_SIZE] = {
++ [PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0},
++ [PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1},
++ [PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS,
++ AC97_EA_PRI | AC97_EA_PRK},
++ [PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS,
++ AC97_EA_PRJ},
++ [PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS,
++ AC97_EA_PRL},
++};
++
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++/**
++ * snd_ac97_update_power - update the powerdown register
++ * @ac97: the codec instance
++ * @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE
++ * @powerup: non-zero when power up the part
++ *
++ * Update the AC97 powerdown register bits of the given part.
++ */
++int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
++{
++ int i;
++
++ if (! ac97)
++ return 0;
++
++ if (reg) {
++ /* SPDIF requires DAC power, too */
++ if (reg == AC97_SPDIF)
++ reg = AC97_PCM_FRONT_DAC_RATE;
++ for (i = 0; i < PWIDX_SIZE; i++) {
++ if (power_regs[i].reg == reg) {
++ if (powerup)
++ ac97->power_up |= (1 << i);
++ else
++ ac97->power_up &= ~(1 << i);
++ break;
++ }
++ }
++ }
++
++ if (power_save && !powerup && ac97->power_workq)
++ /* adjust power-down bits after two seconds delay
++ * (for avoiding loud click noises for many (OSS) apps
++ * that open/close frequently)
++ */
++ queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
++ else
++ update_power_regs(ac97);
++
++ return 0;
++}
++
++EXPORT_SYMBOL(snd_ac97_update_power);
++#endif /* CONFIG_SND_AC97_POWER_SAVE */
++
++static void update_power_regs(struct snd_ac97 *ac97)
++{
++ unsigned int power_up, bits;
++ int i;
++
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ if (power_save)
++ power_up = ac97->power_up;
++ else {
+ #endif
++ power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
++ power_up |= (1 << PWIDX_MIC);
++ if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
++ power_up |= (1 << PWIDX_SURR);
++ if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
++ power_up |= (1 << PWIDX_CLFE);
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ }
++#endif
++ if (power_up) {
++ if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
++ /* needs power-up analog mix and vref */
++ snd_ac97_update_bits(ac97, AC97_POWERDOWN,
++ AC97_PD_PR3, 0);
++ msleep(1);
++ snd_ac97_update_bits(ac97, AC97_POWERDOWN,
++ AC97_PD_PR2, 0);
++ }
++ }
++ for (i = 0; i < PWIDX_SIZE; i++) {
++ if (power_up & (1 << i))
++ bits = 0;
++ else
++ bits = power_regs[i].mask;
++ snd_ac97_update_bits(ac97, power_regs[i].power_reg,
++ power_regs[i].mask, bits);
++ }
++ if (! power_up) {
++ if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) {
++ /* power down analog mix and vref */
++ snd_ac97_update_bits(ac97, AC97_POWERDOWN,
++ AC97_PD_PR2, AC97_PD_PR2);
++ snd_ac97_update_bits(ac97, AC97_POWERDOWN,
++ AC97_PD_PR3, AC97_PD_PR3);
++ }
++ }
+ }
+
+
+@@ -2484,6 +2715,7 @@ static int tune_mute_led(struct snd_ac97
+ msw->put = master_mute_sw_put;
+ snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
+ snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
++ ac97->scaps |= AC97_SCAP_EAPD_LED;
+ return 0;
+ }
+
+diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
+index 094cfc1..15be6ba 100644
+--- a/sound/pci/ac97/ac97_patch.c
++++ b/sound/pci/ac97/ac97_patch.c
+@@ -32,6 +32,7 @@
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/ac97_codec.h>
+ #include "ac97_patch.h"
+ #include "ac97_id.h"
+@@ -51,6 +52,20 @@ static int patch_build_controls(struct s
+ return 0;
+ }
+
++/* replace with a new TLV */
++static void reset_tlv(struct snd_ac97 *ac97, const char *name,
++ unsigned int *tlv)
++{
++ struct snd_ctl_elem_id sid;
++ struct snd_kcontrol *kctl;
++ memset(&sid, 0, sizeof(sid));
++ strcpy(sid.name, name);
++ sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
++ kctl = snd_ctl_find_id(ac97->bus->card, &sid);
++ if (kctl && kctl->tlv.p)
++ kctl->tlv.p = tlv;
++}
++
+ /* set to the page, update bits and restore the page */
+ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page)
+ {
+@@ -466,7 +481,7 @@ int patch_wolfson05(struct snd_ac97 * ac
+ ac97->build_ops = &patch_wolfson_wm9705_ops;
+ #ifdef CONFIG_TOUCHSCREEN_WM9705
+ /* WM9705 touchscreen uses AUX and VIDEO for touch */
+- ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
++ ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
+ #endif
+ return 0;
+ }
+@@ -515,7 +530,7 @@ AC97_ENUM("ALC Headphone Mux", wm9711_en
+ AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+ AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+-AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
++AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 0),
+ AC97_ENUM("Out3 Mux", wm9711_enum[2]),
+ AC97_ENUM("Out3 LR Mux", wm9711_enum[3]),
+ AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+@@ -560,13 +575,14 @@ AC97_SINGLE("Playback Attenuate (-6dB) S
+
+ AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+ AC97_ENUM("Capture Volume Steps", wm9711_enum[6]),
+-AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1),
++AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
+ AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+ AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1),
+ AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1),
+ AC97_ENUM("Mic Select Source", wm9711_enum[7]),
+-AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1),
++AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
++AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+ AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+
+ AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
+@@ -1380,6 +1396,17 @@ static void ad1888_resume(struct snd_ac9
+
+ #endif
+
++static const struct snd_ac97_res_table ad1819_restbl[] = {
++ { AC97_PHONE, 0x9f1f },
++ { AC97_MIC, 0x9f1f },
++ { AC97_LINE, 0x9f1f },
++ { AC97_CD, 0x9f1f },
++ { AC97_VIDEO, 0x9f1f },
++ { AC97_AUX, 0x9f1f },
++ { AC97_PCM, 0x9f1f },
++ { } /* terminator */
++};
++
+ int patch_ad1819(struct snd_ac97 * ac97)
+ {
+ unsigned short scfg;
+@@ -1387,6 +1414,7 @@ int patch_ad1819(struct snd_ac97 * ac97)
+ // patch for Analog Devices
+ scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
+ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */
++ ac97->res_table = ad1819_restbl;
+ return 0;
+ }
+
+@@ -1522,12 +1550,16 @@ static const struct snd_kcontrol_new snd
+ AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
+ };
+
++static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
++
+ static int patch_ad1885_specific(struct snd_ac97 * ac97)
+ {
+ int err;
+
+ if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)
+ return err;
++ reset_tlv(ac97, "Headphone Playback Volume",
++ db_scale_6bit_6db_max);
+ return 0;
+ }
+
+@@ -1551,12 +1583,27 @@ int patch_ad1885(struct snd_ac97 * ac97)
+ return 0;
+ }
+
++static int patch_ad1886_specific(struct snd_ac97 * ac97)
++{
++ reset_tlv(ac97, "Headphone Playback Volume",
++ db_scale_6bit_6db_max);
++ return 0;
++}
++
++static struct snd_ac97_build_ops patch_ad1886_build_ops = {
++ .build_specific = &patch_ad1886_specific,
++#ifdef CONFIG_PM
++ .resume = ad18xx_resume
++#endif
++};
++
+ int patch_ad1886(struct snd_ac97 * ac97)
+ {
+ patch_ad1881(ac97);
+ /* Presario700 workaround */
+ /* for Jack Sense/SPDIF Register misetting causing */
+ snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
++ ac97->build_ops = &patch_ad1886_build_ops;
+ return 0;
+ }
+
+@@ -2015,6 +2062,8 @@ static const struct snd_kcontrol_new snd
+ /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
+ };
+
++static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
++
+ static int patch_alc650_specific(struct snd_ac97 * ac97)
+ {
+ int err;
+@@ -2025,6 +2074,9 @@ static int patch_alc650_specific(struct
+ if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0)
+ return err;
+ }
++ if (ac97->id != AC97_ID_ALC650F)
++ reset_tlv(ac97, "Master Playback Volume",
++ db_scale_5bit_3db_max);
+ return 0;
+ }
+
+@@ -2208,7 +2260,8 @@ int patch_alc655(struct snd_ac97 * ac97)
+ val &= ~(1 << 1); /* Pin 47 is spdif input pin */
+ else { /* ALC655 */
+ if (ac97->subsystem_vendor == 0x1462 &&
+- ac97->subsystem_device == 0x0131) /* MSI S270 laptop */
++ (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
++ ac97->subsystem_device == 0x0161)) /* LG K1 Express */
+ val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
+ else
+ val |= (1 << 1); /* Pin 47 is spdif input pin */
+@@ -2759,6 +2812,10 @@ int patch_vt1616(struct snd_ac97 * ac97)
+ */
+ int patch_vt1617a(struct snd_ac97 * ac97)
+ {
++ /* bring analog power consumption to normal, like WinXP driver
++ * for EPIA SP
++ */
++ snd_ac97_write_cache(ac97, 0x5c, 0x20);
+ ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+ return 0;
+@@ -2872,3 +2929,41 @@ int patch_lm4550(struct snd_ac97 *ac97)
+ ac97->res_table = lm4550_restbl;
+ return 0;
+ }
++
++/*
++ * UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf)
++ */
++static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = {
++/* enable/disable headphone driver which allows direct connection to
++ stereo headphone without the use of external DC blocking
++ capacitors */
++AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0),
++/* Filter used to compensate the DC offset is added in the ADC to remove idle
++ tones from the audio band. */
++AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0),
++/* Control smart-low-power mode feature. Allows automatic power down
++ of unused blocks in the ADC analog front end and the PLL. */
++AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0),
++};
++
++static int patch_ucb1400_specific(struct snd_ac97 * ac97)
++{
++ int idx, err;
++ for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++)
++ if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0)
++ return err;
++ return 0;
++}
++
++static struct snd_ac97_build_ops patch_ucb1400_ops = {
++ .build_specific = patch_ucb1400_specific,
++};
++
++int patch_ucb1400(struct snd_ac97 * ac97)
++{
++ ac97->build_ops = &patch_ucb1400_ops;
++ /* enable headphone driver and smart low power mode by default */
++ snd_ac97_write(ac97, 0x6a, 0x0050);
++ snd_ac97_write(ac97, 0x6c, 0x0030);
++ return 0;
++}
+diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
+index adcaa04..7419792 100644
+--- a/sound/pci/ac97/ac97_patch.h
++++ b/sound/pci/ac97/ac97_patch.h
+@@ -58,5 +58,6 @@ int patch_cm9780(struct snd_ac97 * ac97)
+ int patch_vt1616(struct snd_ac97 * ac97);
+ int patch_vt1617a(struct snd_ac97 * ac97);
+ int patch_it2646(struct snd_ac97 * ac97);
++int patch_ucb1400(struct snd_ac97 * ac97);
+ int mpatch_si3036(struct snd_ac97 * ac97);
+ int patch_lm4550(struct snd_ac97 * ac97);
+diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
+index f684aa2..3758d07 100644
+--- a/sound/pci/ac97/ac97_pcm.c
++++ b/sound/pci/ac97/ac97_pcm.c
+@@ -269,6 +269,7 @@ int snd_ac97_set_rate(struct snd_ac97 *a
+ return -EINVAL;
+ }
+
++ snd_ac97_update_power(ac97, reg, 1);
+ switch (reg) {
+ case AC97_PCM_MIC_ADC_RATE:
+ if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */
+@@ -606,6 +607,7 @@ int snd_ac97_pcm_open(struct ac97_pcm *p
+ goto error;
+ }
+ }
++ pcm->cur_dbl = r;
+ spin_unlock_irq(&pcm->bus->bus_lock);
+ for (i = 3; i < 12; i++) {
+ if (!(slots & (1 << i)))
+@@ -651,6 +653,21 @@ int snd_ac97_pcm_close(struct ac97_pcm *
+ unsigned short slots = pcm->aslots;
+ int i, cidx;
+
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ int r = pcm->cur_dbl;
++ for (i = 3; i < 12; i++) {
++ if (!(slots & (1 << i)))
++ continue;
++ for (cidx = 0; cidx < 4; cidx++) {
++ if (pcm->r[r].rslots[cidx] & (1 << i)) {
++ int reg = get_slot_reg(pcm, cidx, i, r);
++ snd_ac97_update_power(pcm->r[r].codec[cidx],
++ reg, 0);
++ }
++ }
++ }
++#endif
++
+ bus = pcm->bus;
+ spin_lock_irq(&pcm->bus->bus_lock);
+ for (i = 3; i < 12; i++) {
+@@ -660,6 +677,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *
+ bus->used_slots[pcm->stream][cidx] &= ~(1 << i);
+ }
+ pcm->aslots = 0;
++ pcm->cur_dbl = 0;
+ spin_unlock_irq(&pcm->bus->bus_lock);
+ return 0;
+ }
+diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
+index 2118df5..a3fdd7d 100644
+--- a/sound/pci/ac97/ac97_proc.c
++++ b/sound/pci/ac97/ac97_proc.c
+@@ -457,14 +457,10 @@ void snd_ac97_proc_init(struct snd_ac97
+
+ void snd_ac97_proc_done(struct snd_ac97 * ac97)
+ {
+- if (ac97->proc_regs) {
+- snd_info_unregister(ac97->proc_regs);
+- ac97->proc_regs = NULL;
+- }
+- if (ac97->proc) {
+- snd_info_unregister(ac97->proc);
+- ac97->proc = NULL;
+- }
++ snd_info_free_entry(ac97->proc_regs);
++ ac97->proc_regs = NULL;
++ snd_info_free_entry(ac97->proc);
++ ac97->proc = NULL;
+ }
+
+ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus)
+@@ -485,8 +481,6 @@ void snd_ac97_bus_proc_init(struct snd_a
+
+ void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus)
+ {
+- if (bus->proc) {
+- snd_info_unregister(bus->proc);
+- bus->proc = NULL;
+- }
++ snd_info_free_entry(bus->proc);
++ bus->proc = NULL;
+ }
+diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
+index 94c26ec..c153cb7 100644
+--- a/sound/pci/ac97/ak4531_codec.c
++++ b/sound/pci/ac97/ak4531_codec.c
+@@ -27,6 +27,7 @@
+
+ #include <sound/core.h>
+ #include <sound/ak4531_codec.h>
++#include <sound/tlv.h>
+
+ MODULE_AUTHOR("Jaroslav Kysela <perex at suse.cz>");
+ MODULE_DESCRIPTION("Universal routines for AK4531 codec");
+@@ -63,6 +64,14 @@ static void snd_ak4531_dump(struct snd_a
+ .info = snd_ak4531_info_single, \
+ .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \
+ .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) }
++#define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .index = xindex, \
++ .info = snd_ak4531_info_single, \
++ .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \
++ .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22), \
++ .tlv = { .p = (xtlv) } }
+
+ static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+@@ -122,6 +131,14 @@ static int snd_ak4531_put_single(struct
+ .info = snd_ak4531_info_double, \
+ .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) }
++#define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .index = xindex, \
++ .info = snd_ak4531_info_double, \
++ .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \
++ .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22), \
++ .tlv = { .p = (xtlv) } }
+
+ static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+@@ -250,50 +267,62 @@ static int snd_ak4531_put_input_sw(struc
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
++
+ static struct snd_kcontrol_new snd_ak4531_controls[] = {
+
+-AK4531_DOUBLE("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1),
++AK4531_DOUBLE_TLV("Master Playback Switch", 0,
++ AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1,
++ db_scale_master),
+ AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1),
+
+-AK4531_SINGLE("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1),
++AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1,
++ db_scale_mono),
+ AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1),
+
+ AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1),
+-AK4531_DOUBLE("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1),
++AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1,
++ db_scale_input),
+ AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0),
+ AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0),
+
+ AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1),
+-AK4531_DOUBLE("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1),
++AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1,
++ db_scale_input),
+ AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0),
+ AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5),
+
+ AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1),
+-AK4531_DOUBLE("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1),
++AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1,
++ db_scale_input),
+ AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0),
+ AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1),
+
+ AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1),
+-AK4531_DOUBLE("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1),
++AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1,
++ db_scale_input),
+ AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0),
+ AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3),
+
+ AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1),
+-AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1),
++AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1,
++ db_scale_input),
+ AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0),
+ AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3),
+
+ AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1),
+-AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1),
++AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input),
+ AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0),
+ AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0),
+
+ AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1),
+-AK4531_SINGLE("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1),
++AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input),
+ AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0),
+ AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0),
+
+-AK4531_SINGLE("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1),
++AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input),
+ AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1),
+ AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0),
+ AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0),
+diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
+index 0786d0e..cbf8331 100644
+--- a/sound/pci/ad1889.c
++++ b/sound/pci/ad1889.c
+@@ -596,9 +596,7 @@ static struct snd_pcm_ops snd_ad1889_cap
+ };
+
+ static irqreturn_t
+-snd_ad1889_interrupt(int irq,
+- void *dev_id,
+- struct pt_regs *regs)
++snd_ad1889_interrupt(int irq, void *dev_id)
+ {
+ unsigned long st;
+ struct snd_ad1889 *chip = dev_id;
+diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
+index 7466839..a7edd56 100644
+--- a/sound/pci/ali5451/ali5451.c
++++ b/sound/pci/ali5451/ali5451.c
+@@ -1047,9 +1047,7 @@ static void snd_ali_interrupt(struct snd
+ }
+
+
+-static irqreturn_t snd_ali_card_interrupt(int irq,
+- void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_ali_card_interrupt(int irq, void *dev_id)
+ {
+ struct snd_ali *codec = dev_id;
+
+@@ -2034,8 +2032,10 @@ static int ali_suspend(struct pci_dev *p
+ outl(0xffffffff, ALI_REG(chip, ALI_STOP));
+
+ spin_unlock_irq(&chip->reg_lock);
++
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2050,8 +2050,15 @@ static int ali_resume(struct pci_dev *pc
+ if (! im)
+ return 0;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "ali5451: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
++ pci_set_master(pci);
+
+ spin_lock_irq(&chip->reg_lock);
+
+diff --git a/sound/pci/als300.c b/sound/pci/als300.c
+index 96cfb8a..95f70f3 100644
+--- a/sound/pci/als300.c
++++ b/sound/pci/als300.c
+@@ -204,8 +204,7 @@ static int snd_als300_dev_free(struct sn
+ return snd_als300_free(chip);
+ }
+
+-static irqreturn_t snd_als300_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_als300_interrupt(int irq, void *dev_id)
+ {
+ u8 status;
+ struct snd_als300 *chip = dev_id;
+@@ -236,8 +235,7 @@ static irqreturn_t snd_als300_interrupt(
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id)
+ {
+ u8 general, mpu, dram;
+ struct snd_als300 *chip = dev_id;
+@@ -770,9 +768,9 @@ static int snd_als300_suspend(struct pci
+ snd_pcm_suspend_all(chip->pcm);
+ snd_ac97_suspend(chip->ac97);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -781,9 +779,14 @@ static int snd_als300_resume(struct pci_
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_als300 *chip = card->private_data;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "als300: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_als300_init(chip);
+diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
+index 9e596f7..8fb55d3 100644
+--- a/sound/pci/als4000.c
++++ b/sound/pci/als4000.c
+@@ -385,7 +385,7 @@ static snd_pcm_uframes_t snd_als4000_pla
+ * SB IRQ status.
+ * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS??
+ * */
+-static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
+ {
+ struct snd_sb *chip = dev_id;
+ unsigned gcr_status;
+@@ -399,7 +399,7 @@ static irqreturn_t snd_als4000_interrupt
+ if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */
+ snd_pcm_period_elapsed(chip->capture_substream);
+ if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+ /* release the gcr */
+ outb(gcr_status, chip->alt_port + 0xe);
+
+@@ -804,9 +804,9 @@ static int snd_als4000_suspend(struct pc
+ snd_pcm_suspend_all(chip->pcm);
+ snd_sbmixer_suspend(chip);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -816,9 +816,14 @@ static int snd_als4000_resume(struct pci
+ struct snd_card_als4000 *acard = card->private_data;
+ struct snd_sb *chip = acard->chip;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "als4000: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_als4000_configure(chip);
+diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
+index 347e25f..e3e99f3 100644
+--- a/sound/pci/atiixp.c
++++ b/sound/pci/atiixp.c
+@@ -1300,7 +1300,7 @@ static int __devinit snd_atiixp_pcm_new(
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
+ {
+ struct atiixp *chip = dev_id;
+ unsigned int status;
+@@ -1442,9 +1442,9 @@ static int snd_atiixp_suspend(struct pci
+ snd_atiixp_aclink_down(chip);
+ snd_atiixp_chip_stop(chip);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1454,9 +1454,14 @@ static int snd_atiixp_resume(struct pci_
+ struct atiixp *chip = card->private_data;
+ int i;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "atiixp: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_atiixp_aclink_reset(chip);
+diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
+index a89d67c..dc54f2c 100644
+--- a/sound/pci/atiixp_modem.c
++++ b/sound/pci/atiixp_modem.c
+@@ -1017,7 +1017,7 @@ static int __devinit snd_atiixp_pcm_new(
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
+ {
+ struct atiixp_modem *chip = dev_id;
+ unsigned int status;
+@@ -1128,9 +1128,9 @@ static int snd_atiixp_suspend(struct pci
+ snd_atiixp_aclink_down(chip);
+ snd_atiixp_chip_stop(chip);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1140,9 +1140,14 @@ static int snd_atiixp_resume(struct pci_
+ struct atiixp_modem *chip = card->private_data;
+ int i;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "atiixp-modem: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_atiixp_aclink_reset(chip);
+diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
+index ef189d7..6ed5ad5 100644
+--- a/sound/pci/au88x0/au88x0.c
++++ b/sound/pci/au88x0/au88x0.c
+@@ -128,6 +128,7 @@ static int snd_vortex_dev_free(struct sn
+ // Take down PCI interface.
+ synchronize_irq(vortex->irq);
+ free_irq(vortex->irq, vortex);
++ iounmap(vortex->mmio);
+ pci_release_regions(vortex->pci_dev);
+ pci_disable_device(vortex->pci_dev);
+ kfree(vortex);
+diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
+index b1cfc3c..5ccf0b1 100644
+--- a/sound/pci/au88x0/au88x0.h
++++ b/sound/pci/au88x0/au88x0.h
+@@ -236,8 +236,7 @@ static void vortex_spdif_init(vortex_t *
+ static int vortex_core_init(vortex_t * card);
+ static int vortex_core_shutdown(vortex_t * card);
+ static void vortex_enable_int(vortex_t * card);
+-static irqreturn_t vortex_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t vortex_interrupt(int irq, void *dev_id);
+ static int vortex_alsafmt_aspfmt(int alsafmt);
+
+ /* Connection stuff. */
+diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
+index 5299cce..4a336ea 100644
+--- a/sound/pci/au88x0/au88x0_core.c
++++ b/sound/pci/au88x0/au88x0_core.c
+@@ -2385,7 +2385,7 @@ static void vortex_disable_int(vortex_t
+ hwread(card->mmio, VORTEX_CTRL) & ~CTRL_IRQ_ENABLE);
+ }
+
+-static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t vortex_interrupt(int irq, void *dev_id)
+ {
+ vortex_t *vortex = dev_id;
+ int i, handled;
+@@ -2462,7 +2462,7 @@ static irqreturn_t vortex_interrupt(int
+ }
+ if (source & IRQ_MIDI) {
+ snd_mpu401_uart_interrupt(vortex->irq,
+- vortex->rmidi->private_data, regs);
++ vortex->rmidi->private_data);
+ handled = 1;
+ }
+
+diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
+index bac8e9c..2414ee6 100644
+--- a/sound/pci/azt3328.c
++++ b/sound/pci/azt3328.c
+@@ -1191,7 +1191,7 @@ snd_azf3328_capture_pointer(struct snd_p
+ }
+
+ static irqreturn_t
+-snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++snd_azf3328_interrupt(int irq, void *dev_id)
+ {
+ struct snd_azf3328 *chip = dev_id;
+ u8 status, which;
+@@ -1256,7 +1256,7 @@ snd_azf3328_interrupt(int irq, void *dev
+ /* MPU401 has less critical IRQ requirements
+ * than timer and playback/recording, right? */
+ if (status & IRQ_MPU401) {
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+
+ /* hmm, do we have to ack the IRQ here somehow?
+ * If so, then I don't know how... */
+@@ -1903,9 +1903,9 @@ snd_azf3328_suspend(struct pci_dev *pci,
+ for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
+ chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1916,9 +1916,14 @@ snd_azf3328_resume(struct pci_dev *pci)
+ struct snd_azf3328 *chip = card->private_data;
+ int reg;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "azt3328: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
+diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
+index 97a280a..d33a370 100644
+--- a/sound/pci/bt87x.c
++++ b/sound/pci/bt87x.c
+@@ -269,7 +269,7 @@ static void snd_bt87x_pci_error(struct s
+ }
+ }
+
+-static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id)
+ {
+ struct snd_bt87x *chip = dev_id;
+ unsigned int status, irq_status;
+diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
+index 12bbbb6..6fa4a30 100644
+--- a/sound/pci/ca0106/ca0106_main.c
++++ b/sound/pci/ca0106/ca0106_main.c
+@@ -1058,8 +1058,7 @@ static int snd_ca0106_dev_free(struct sn
+ return snd_ca0106_free(chip);
+ }
+
+-static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
+ {
+ unsigned int status;
+
+diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
+index 146eed7..9855f52 100644
+--- a/sound/pci/ca0106/ca0106_mixer.c
++++ b/sound/pci/ca0106/ca0106_mixer.c
+@@ -70,9 +70,13 @@
+ #include <sound/pcm.h>
+ #include <sound/ac97_codec.h>
+ #include <sound/info.h>
++#include <sound/tlv.h>
+
+ #include "ca0106.h"
+
++static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
++static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
++
+ static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+ {
+@@ -469,18 +473,24 @@ static int snd_ca0106_i2c_volume_put(str
+ #define CA_VOLUME(xname,chid,reg) \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_ca0106_volume_info, \
+ .get = snd_ca0106_volume_get, \
+ .put = snd_ca0106_volume_put, \
++ .tlv = { .p = snd_ca0106_db_scale1 }, \
+ .private_value = ((chid) << 8) | (reg) \
+ }
+
+ #define I2C_VOLUME(xname,chid) \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_ca0106_i2c_volume_info, \
+ .get = snd_ca0106_i2c_volume_get, \
+ .put = snd_ca0106_i2c_volume_put, \
++ .tlv = { .p = snd_ca0106_db_scale2 }, \
+ .private_value = chid \
+ }
+
+diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
+index 876b644..0093cd1 100644
+--- a/sound/pci/cmipci.c
++++ b/sound/pci/cmipci.c
+@@ -1294,7 +1294,7 @@ static int snd_cmipci_capture_spdif_hw_f
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id)
+ {
+ struct cmipci *cm = dev_id;
+ unsigned int status, mask = 0;
+@@ -1315,7 +1315,7 @@ static irqreturn_t snd_cmipci_interrupt(
+ spin_unlock(&cm->reg_lock);
+
+ if (cm->rmidi && (status & CM_UARTINT))
+- snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data);
+
+ if (cm->pcm) {
+ if ((status & CM_CHINT0) && cm->channel[0].running)
+@@ -3122,9 +3122,9 @@ static int snd_cmipci_suspend(struct pci
+ /* disable ints */
+ snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -3134,9 +3134,14 @@ static int snd_cmipci_resume(struct pci_
+ struct cmipci *cm = card->private_data;
+ int i;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "cmipci: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ /* reset / initialize to a sane state */
+diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
+index 9631456..0905fa8 100644
+--- a/sound/pci/cs4281.c
++++ b/sound/pci/cs4281.c
+@@ -33,6 +33,7 @@
+ #include <sound/pcm.h>
+ #include <sound/rawmidi.h>
+ #include <sound/ac97_codec.h>
++#include <sound/tlv.h>
+ #include <sound/opl3.h>
+ #include <sound/initval.h>
+
+@@ -492,7 +493,7 @@ struct cs4281 {
+
+ };
+
+-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
+
+ static struct pci_device_id snd_cs4281_ids[] = {
+ { 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4281 */
+@@ -1054,6 +1055,8 @@ static int snd_cs4281_put_volume(struct
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
++
+ static struct snd_kcontrol_new snd_cs4281_fm_vol =
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1062,6 +1065,7 @@ static struct snd_kcontrol_new snd_cs428
+ .get = snd_cs4281_get_volume,
+ .put = snd_cs4281_put_volume,
+ .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC),
++ .tlv = { .p = db_scale_dsp },
+ };
+
+ static struct snd_kcontrol_new snd_cs4281_pcm_vol =
+@@ -1072,6 +1076,7 @@ static struct snd_kcontrol_new snd_cs428
+ .get = snd_cs4281_get_volume,
+ .put = snd_cs4281_put_volume,
+ .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC),
++ .tlv = { .p = db_scale_dsp },
+ };
+
+ static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
+@@ -1809,7 +1814,7 @@ static int __devinit snd_cs4281_midi(str
+ * Interrupt handler
+ */
+
+-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
+ {
+ struct cs4281 *chip = dev_id;
+ unsigned int status, dma, val;
+@@ -2045,6 +2050,7 @@ static int cs4281_suspend(struct pci_dev
+
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2055,8 +2061,14 @@ static int cs4281_resume(struct pci_dev
+ unsigned int i;
+ u32 ulCLK;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "cs4281: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
+diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
+index 4851847..2807b97 100644
+--- a/sound/pci/cs46xx/cs46xx_lib.c
++++ b/sound/pci/cs46xx/cs46xx_lib.c
+@@ -1149,7 +1149,7 @@ static int snd_cs46xx_capture_prepare(st
+ return 0;
+ }
+
+-static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id)
+ {
+ struct snd_cs46xx *chip = dev_id;
+ u32 status1;
+@@ -3687,8 +3687,10 @@ int snd_cs46xx_suspend(struct pci_dev *p
+ /* disable CLKRUN */
+ chip->active_ctrl(chip, -chip->amplifier);
+ chip->amplifier = amp_saved; /* restore the status */
++
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -3698,9 +3700,16 @@ int snd_cs46xx_resume(struct pci_dev *pc
+ struct snd_cs46xx *chip = card->private_data;
+ int amp_saved;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "cs46xx: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
++
+ amp_saved = chip->amplifier;
+ chip->amplifier = 0;
+ chip->active_ctrl(chip, 1); /* force to on */
+diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
+index 5c9711c..89c4027 100644
+--- a/sound/pci/cs46xx/dsp_spos.c
++++ b/sound/pci/cs46xx/dsp_spos.c
+@@ -868,35 +868,23 @@ int cs46xx_dsp_proc_done (struct snd_cs4
+ struct dsp_spos_instance * ins = chip->dsp_spos_instance;
+ int i;
+
+- if (ins->proc_sym_info_entry) {
+- snd_info_unregister(ins->proc_sym_info_entry);
+- ins->proc_sym_info_entry = NULL;
+- }
+-
+- if (ins->proc_modules_info_entry) {
+- snd_info_unregister(ins->proc_modules_info_entry);
+- ins->proc_modules_info_entry = NULL;
+- }
+-
+- if (ins->proc_parameter_dump_info_entry) {
+- snd_info_unregister(ins->proc_parameter_dump_info_entry);
+- ins->proc_parameter_dump_info_entry = NULL;
+- }
+-
+- if (ins->proc_sample_dump_info_entry) {
+- snd_info_unregister(ins->proc_sample_dump_info_entry);
+- ins->proc_sample_dump_info_entry = NULL;
+- }
+-
+- if (ins->proc_scb_info_entry) {
+- snd_info_unregister(ins->proc_scb_info_entry);
+- ins->proc_scb_info_entry = NULL;
+- }
+-
+- if (ins->proc_task_info_entry) {
+- snd_info_unregister(ins->proc_task_info_entry);
+- ins->proc_task_info_entry = NULL;
+- }
++ snd_info_free_entry(ins->proc_sym_info_entry);
++ ins->proc_sym_info_entry = NULL;
++
++ snd_info_free_entry(ins->proc_modules_info_entry);
++ ins->proc_modules_info_entry = NULL;
++
++ snd_info_free_entry(ins->proc_parameter_dump_info_entry);
++ ins->proc_parameter_dump_info_entry = NULL;
++
++ snd_info_free_entry(ins->proc_sample_dump_info_entry);
++ ins->proc_sample_dump_info_entry = NULL;
++
++ snd_info_free_entry(ins->proc_scb_info_entry);
++ ins->proc_scb_info_entry = NULL;
++
++ snd_info_free_entry(ins->proc_task_info_entry);
++ ins->proc_task_info_entry = NULL;
+
+ mutex_lock(&chip->spos_mutex);
+ for (i = 0; i < ins->nscb; ++i) {
+@@ -905,10 +893,8 @@ int cs46xx_dsp_proc_done (struct snd_cs4
+ }
+ mutex_unlock(&chip->spos_mutex);
+
+- if (ins->proc_dsp_dir) {
+- snd_info_unregister (ins->proc_dsp_dir);
+- ins->proc_dsp_dir = NULL;
+- }
++ snd_info_free_entry(ins->proc_dsp_dir);
++ ins->proc_dsp_dir = NULL;
+
+ return 0;
+ }
+diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
+index 232b337..343f51d 100644
+--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
++++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
+@@ -233,7 +233,7 @@ void cs46xx_dsp_proc_free_scb_desc (stru
+
+ snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
+
+- snd_info_unregister(scb->proc_info);
++ snd_info_free_entry(scb->proc_info);
+ scb->proc_info = NULL;
+
+ snd_assert (scb_info != NULL, return);
+diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
+index 2911a8a..ad947b4 100644
+--- a/sound/pci/cs5535audio/Makefile
++++ b/sound/pci/cs5535audio/Makefile
+@@ -4,7 +4,7 @@
+
+ snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o
+
+-ifdef CONFIG_PM
++ifeq ($(CONFIG_PM),y)
+ snd-cs5535audio-objs += cs5535audio_pm.o
+ endif
+
+diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
+index 64c7826..2441238 100644
+--- a/sound/pci/cs5535audio/cs5535audio.c
++++ b/sound/pci/cs5535audio/cs5535audio.c
+@@ -203,8 +203,7 @@ static void process_bm1_irq(struct cs553
+ }
+ }
+
+-static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
+ {
+ u16 acc_irq_stat;
+ u8 bm_stat;
+diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
+index aad0e69..3e4d198 100644
+--- a/sound/pci/cs5535audio/cs5535audio_pm.c
++++ b/sound/pci/cs5535audio/cs5535audio_pm.c
+@@ -73,9 +73,10 @@ int snd_cs5535audio_suspend(struct pci_d
+ snd_ac97_suspend(cs5535au->ac97);
+ /* save important regs, then disable aclink in hw */
+ snd_cs5535audio_stop_hardware(cs5535au);
++
+ pci_disable_device(pci);
+ pci_save_state(pci);
+-
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -87,8 +88,14 @@ int snd_cs5535audio_resume(struct pci_de
+ int timeout;
+ int i;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ /* set LNK_WRM_RST to reset AC link */
+diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
+index c3dafa2..e5e88fe 100644
+--- a/sound/pci/echoaudio/echoaudio.c
++++ b/sound/pci/echoaudio/echoaudio.c
+@@ -1818,8 +1818,7 @@ static struct snd_kcontrol_new snd_echo_
+ IRQ Handler
+ ******************************************************************************/
+
+-static irqreturn_t snd_echo_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
+ {
+ struct echoaudio *chip = dev_id;
+ struct snd_pcm_substream *substream;
+diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
+index 7ec5b63..97e42e1 100644
+--- a/sound/pci/echoaudio/layla24_dsp.c
++++ b/sound/pci/echoaudio/layla24_dsp.c
+@@ -302,11 +302,11 @@ static int switch_asic(struct echoaudio
+
+ /* Check to see if this is already loaded */
+ if (asic != chip->asic_code) {
+- monitors = kmalloc(MONITOR_ARRAY_SIZE, GFP_KERNEL);
++ monitors = kmemdup(chip->comm_page->monitors,
++ MONITOR_ARRAY_SIZE, GFP_KERNEL);
+ if (! monitors)
+ return -ENOMEM;
+
+- memcpy(monitors, chip->comm_page->monitors, MONITOR_ARRAY_SIZE);
+ memset(chip->comm_page->monitors, ECHOGAIN_MUTED,
+ MONITOR_ARRAY_SIZE);
+
+diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
+index 289bcd9..55caf34 100644
+--- a/sound/pci/emu10k1/emu10k1.c
++++ b/sound/pci/emu10k1/emu10k1.c
+@@ -226,22 +226,27 @@ static int snd_emu10k1_suspend(struct pc
+
+ snd_emu10k1_done(emu);
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+-int snd_emu10k1_resume(struct pci_dev *pci)
++static int snd_emu10k1_resume(struct pci_dev *pci)
+ {
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_emu10k1 *emu = card->private_data;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "emu10k1: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+-
++
+ snd_emu10k1_resume_init(emu);
+ snd_emu10k1_efx_resume(emu);
+ snd_ac97_resume(emu->ac97);
+diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
+index 79f24cd..8058059 100644
+--- a/sound/pci/emu10k1/emu10k1_main.c
++++ b/sound/pci/emu10k1/emu10k1_main.c
+@@ -927,6 +927,7 @@ static struct snd_emu_chip_details emu_c
+ .ca0151_chip = 1,
+ .spk71 = 1,
+ .spdif_bug = 1,
++ .adc_1361t = 1, /* 24 bit capture instead of 16bit */
+ .ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
+ .driver = "Audigy2", .name = "Audigy 2 EX [1005]",
+@@ -1460,8 +1461,8 @@ void snd_emu10k1_resume_regs(struct snd_
+
+ /* resore for spdif */
+ if (emu->audigy)
+- outl(emu->port + A_IOCFG, emu->saved_a_iocfg);
+- outl(emu->port + HCFG, emu->saved_hcfg);
++ outl(emu->saved_a_iocfg, emu->port + A_IOCFG);
++ outl(emu->saved_hcfg, emu->port + HCFG);
+
+ val = emu->saved_ptr;
+ for (reg = saved_regs; *reg != 0xff; reg++)
+diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
+index bda8bdf..c46905a 100644
+--- a/sound/pci/emu10k1/emu10k1x.c
++++ b/sound/pci/emu10k1/emu10k1x.c
+@@ -780,8 +780,7 @@ static int snd_emu10k1x_dev_free(struct
+ return snd_emu10k1x_free(chip);
+ }
+
+-static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
+ {
+ unsigned int status;
+
+@@ -1626,12 +1625,7 @@ static struct pci_driver driver = {
+ // initialization of the module
+ static int __init alsa_card_emu10k1x_init(void)
+ {
+- int err;
+-
+- if ((err = pci_register_driver(&driver)) > 0)
+- return err;
+-
+- return 0;
++ return pci_register_driver(&driver);
+ }
+
+ // clean up the module
+diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
+index dfba002..13cd6ce 100644
+--- a/sound/pci/emu10k1/emufx.c
++++ b/sound/pci/emu10k1/emufx.c
+@@ -35,6 +35,7 @@
+ #include <linux/mutex.h>
+
+ #include <sound/core.h>
++#include <sound/tlv.h>
+ #include <sound/emu10k1.h>
+
+ #if 0 /* for testing purposes - digital out -> capture */
+@@ -266,6 +267,7 @@ static const u32 treble_table[41][5] = {
+ { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
+ };
+
++/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
+ static const u32 db_table[101] = {
+ 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
+ 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
+@@ -290,6 +292,9 @@ static const u32 db_table[101] = {
+ 0x7fffffff,
+ };
+
++/* EMU10k1/EMU10k2 DSP control db gain */
++static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
++
+ static const u32 onoff_table[2] = {
+ 0x00000000, 0x00000001
+ };
+@@ -755,6 +760,11 @@ static int snd_emu10k1_add_controls(stru
+ knew.device = gctl->id.device;
+ knew.subdevice = gctl->id.subdevice;
+ knew.info = snd_emu10k1_gpr_ctl_info;
++ if (gctl->tlv.p) {
++ knew.tlv.p = gctl->tlv.p;
++ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ;
++ }
+ knew.get = snd_emu10k1_gpr_ctl_get;
+ knew.put = snd_emu10k1_gpr_ctl_put;
+ memset(nctl, 0, sizeof(*nctl));
+@@ -1013,6 +1023,7 @@ snd_emu10k1_init_mono_control(struct snd
+ ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
+ ctl->min = 0;
+ ctl->max = 100;
++ ctl->tlv.p = snd_emu10k1_db_scale1;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ }
+
+@@ -1027,6 +1038,7 @@ snd_emu10k1_init_stereo_control(struct s
+ ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
+ ctl->min = 0;
+ ctl->max = 100;
++ ctl->tlv.p = snd_emu10k1_db_scale1;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ }
+
+diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c
+index 1076af4..4f18f7e 100644
+--- a/sound/pci/emu10k1/irq.c
++++ b/sound/pci/emu10k1/irq.c
+@@ -30,7 +30,7 @@
+ #include <sound/core.h>
+ #include <sound/emu10k1.h>
+
+-irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
+ {
+ struct snd_emu10k1 *emu = dev_id;
+ unsigned int status, status2, orig_status, orig_status2;
+diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
+index 9905651..4e0f954 100644
+--- a/sound/pci/emu10k1/p16v.c
++++ b/sound/pci/emu10k1/p16v.c
+@@ -100,6 +100,7 @@
+ #include <sound/pcm.h>
+ #include <sound/ac97_codec.h>
+ #include <sound/info.h>
++#include <sound/tlv.h>
+ #include <sound/emu10k1.h>
+ #include "p16v.h"
+
+@@ -784,12 +785,16 @@ static int snd_p16v_capture_channel_put(
+ }
+ return change;
+ }
++static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
+
+ #define P16V_VOL(xname,xreg,xhl) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_p16v_volume_info, \
+ .get = snd_p16v_volume_get, \
+ .put = snd_p16v_volume_put, \
++ .tlv = { .p = snd_p16v_db_scale1 }, \
+ .private_value = ((xreg) | ((xhl) << 8)) \
+ }
+
+diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
+index a8a601f..d2a811f 100644
+--- a/sound/pci/ens1370.c
++++ b/sound/pci/ens1370.c
+@@ -444,7 +444,7 @@ struct ensoniq {
+ #endif
+ };
+
+-static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id);
+
+ static struct pci_device_id snd_audiopci_ids[] = {
+ #ifdef CHIP1370
+@@ -2072,9 +2072,10 @@ static int snd_ensoniq_suspend(struct pc
+ udelay(100);
+ snd_ak4531_suspend(ensoniq->u.es1370.ak4531);
+ #endif
+- pci_set_power_state(pci, PCI_D3hot);
++
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2083,9 +2084,14 @@ static int snd_ensoniq_resume(struct pci
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct ensoniq *ensoniq = card->private_data;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR DRIVER_NAME ": pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_ensoniq_chip_init(ensoniq);
+@@ -2404,7 +2410,7 @@ static int __devinit snd_ensoniq_midi(st
+ * Interrupt handler
+ */
+
+-static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id)
+ {
+ struct ensoniq *ensoniq = dev_id;
+ unsigned int status, sctrl;
+diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
+index cc0f34f..1a8d36d 100644
+--- a/sound/pci/es1938.c
++++ b/sound/pci/es1938.c
+@@ -62,6 +62,7 @@
+ #include <sound/opl3.h>
+ #include <sound/mpu401.h>
+ #include <sound/initval.h>
++#include <sound/tlv.h>
+
+ #include <asm/io.h>
+
+@@ -240,7 +241,7 @@ struct es1938 {
+ #endif
+ };
+
+-static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
+
+ static struct pci_device_id snd_es1938_ids[] = {
+ { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Solo-1 */
+@@ -1164,6 +1165,14 @@ static int snd_es1938_reg_read(struct es
+ return snd_es1938_read(chip, reg);
+ }
+
++#define ES1938_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\
++ .name = xname, .index = xindex, \
++ .info = snd_es1938_info_single, \
++ .get = snd_es1938_get_single, .put = snd_es1938_put_single, \
++ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
++ .tlv = { .p = xtlv } }
+ #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_es1938_info_single, \
+@@ -1217,6 +1226,14 @@ static int snd_es1938_put_single(struct
+ return snd_es1938_reg_bits(chip, reg, mask, val) != val;
+ }
+
++#define ES1938_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\
++ .name = xname, .index = xindex, \
++ .info = snd_es1938_info_double, \
++ .get = snd_es1938_get_double, .put = snd_es1938_put_double, \
++ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
++ .tlv = { .p = xtlv } }
+ #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_es1938_info_double, \
+@@ -1297,8 +1314,41 @@ static int snd_es1938_put_double(struct
+ return change;
+ }
+
++static unsigned int db_scale_master[] = {
++ TLV_DB_RANGE_HEAD(2),
++ 0, 54, TLV_DB_SCALE_ITEM(-3600, 50, 1),
++ 54, 63, TLV_DB_SCALE_ITEM(-900, 100, 0),
++};
++
++static unsigned int db_scale_audio1[] = {
++ TLV_DB_RANGE_HEAD(2),
++ 0, 8, TLV_DB_SCALE_ITEM(-3300, 300, 1),
++ 8, 15, TLV_DB_SCALE_ITEM(-900, 150, 0),
++};
++
++static unsigned int db_scale_audio2[] = {
++ TLV_DB_RANGE_HEAD(2),
++ 0, 8, TLV_DB_SCALE_ITEM(-3450, 300, 1),
++ 8, 15, TLV_DB_SCALE_ITEM(-1050, 150, 0),
++};
++
++static unsigned int db_scale_mic[] = {
++ TLV_DB_RANGE_HEAD(2),
++ 0, 8, TLV_DB_SCALE_ITEM(-2400, 300, 1),
++ 8, 15, TLV_DB_SCALE_ITEM(0, 150, 0),
++};
++
++static unsigned int db_scale_line[] = {
++ TLV_DB_RANGE_HEAD(2),
++ 0, 8, TLV_DB_SCALE_ITEM(-3150, 300, 1),
++ 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0),
++};
++
++static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
++
+ static struct snd_kcontrol_new snd_es1938_controls[] = {
+-ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),
++ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0,
++ db_scale_master),
+ ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1309,19 +1359,27 @@ ES1938_DOUBLE("Master Playback Switch",
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READ |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Hardware Master Playback Switch",
+- .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = snd_es1938_info_hw_switch,
+ .get = snd_es1938_get_hw_switch,
++ .tlv = { .p = db_scale_master },
+ },
+ ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0),
+-ES1938_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),
++ES1938_DOUBLE_TLV("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0,
++ db_scale_line),
+ ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
+-ES1938_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),
+-ES1938_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+-ES1938_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),
+-ES1938_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),
+-ES1938_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),
++ES1938_DOUBLE_TLV("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0,
++ db_scale_mic),
++ES1938_DOUBLE_TLV("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0,
++ db_scale_mic),
++ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0,
++ db_scale_capture),
+ ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0),
+ ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
+ ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+@@ -1332,16 +1390,26 @@ ES1938_SINGLE("Capture Switch", 0, 0x1c,
+ .get = snd_es1938_get_mux,
+ .put = snd_es1938_put_mux,
+ },
+-ES1938_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+-ES1938_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),
+-ES1938_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),
+-ES1938_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),
+-ES1938_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),
+-ES1938_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0),
+-ES1938_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),
+-ES1938_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0),
+-ES1938_DOUBLE("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0),
+-ES1938_DOUBLE("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0),
++ES1938_DOUBLE_TLV("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0,
++ db_scale_audio2),
++ES1938_DOUBLE_TLV("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0,
++ db_scale_mic),
++ES1938_DOUBLE_TLV("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0,
++ db_scale_mic),
++ES1938_DOUBLE_TLV("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0,
++ db_scale_line),
++ES1938_DOUBLE_TLV("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0,
++ db_scale_audio2),
++ES1938_DOUBLE_TLV("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0,
++ db_scale_audio1),
+ ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1413,10 +1481,14 @@ static int es1938_suspend(struct pci_dev
+ *d = snd_es1938_reg_read(chip, *s);
+
+ outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */
+- if (chip->irq >= 0)
++ if (chip->irq >= 0) {
++ synchronize_irq(chip->irq);
+ free_irq(chip->irq, chip);
++ chip->irq = -1;
++ }
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1426,10 +1498,22 @@ static int es1938_resume(struct pci_dev
+ struct es1938 *chip = card->private_data;
+ unsigned char *s, *d;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
+- request_irq(pci->irq, snd_es1938_interrupt,
+- IRQF_DISABLED|IRQF_SHARED, "ES1938", chip);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "es1938: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
++
++ if (request_irq(pci->irq, snd_es1938_interrupt,
++ IRQF_DISABLED|IRQF_SHARED, "ES1938", chip)) {
++ printk(KERN_ERR "es1938: unable to grab IRQ %d, "
++ "disabling device\n", pci->irq);
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ chip->irq = pci->irq;
+ snd_es1938_chip_init(chip);
+
+@@ -1488,8 +1572,10 @@ static int snd_es1938_free(struct es1938
+
+ snd_es1938_free_gameport(chip);
+
+- if (chip->irq >= 0)
++ if (chip->irq >= 0) {
++ synchronize_irq(chip->irq);
+ free_irq(chip->irq, chip);
++ }
+ pci_release_regions(chip->pci);
+ pci_disable_device(chip->pci);
+ kfree(chip);
+@@ -1534,6 +1620,7 @@ static int __devinit snd_es1938_create(s
+ spin_lock_init(&chip->mixer_lock);
+ chip->card = card;
+ chip->pci = pci;
++ chip->irq = -1;
+ if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) {
+ kfree(chip);
+ pci_disable_device(pci);
+@@ -1574,7 +1661,7 @@ static int __devinit snd_es1938_create(s
+ /* --------------------------------------------------------------------
+ * Interrupt handler
+ * -------------------------------------------------------------------- */
+-static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
+ {
+ struct es1938 *chip = dev_id;
+ unsigned char status, audiostatus;
+@@ -1646,7 +1733,7 @@ static irqreturn_t snd_es1938_interrupt(
+ // snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0); /* ack? */
+ if (chip->rmidi) {
+ handled = 1;
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+ }
+ }
+ return IRQ_RETVAL(handled);
+diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
+index 3c5ab7c..092da53 100644
+--- a/sound/pci/es1968.c
++++ b/sound/pci/es1968.c
+@@ -432,46 +432,6 @@ MODULE_PARM_DESC(joystick, "Enable joyst
+ #define ESM_MODE_PLAY 0
+ #define ESM_MODE_CAPTURE 1
+
+-/* acpi states */
+-enum {
+- ACPI_D0=0,
+- ACPI_D1,
+- ACPI_D2,
+- ACPI_D3
+-};
+-
+-/* bits in the acpi masks */
+-#define ACPI_12MHZ ( 1 << 15)
+-#define ACPI_24MHZ ( 1 << 14)
+-#define ACPI_978 ( 1 << 13)
+-#define ACPI_SPDIF ( 1 << 12)
+-#define ACPI_GLUE ( 1 << 11)
+-#define ACPI__10 ( 1 << 10) /* reserved */
+-#define ACPI_PCIINT ( 1 << 9)
+-#define ACPI_HV ( 1 << 8) /* hardware volume */
+-#define ACPI_GPIO ( 1 << 7)
+-#define ACPI_ASSP ( 1 << 6)
+-#define ACPI_SB ( 1 << 5) /* sb emul */
+-#define ACPI_FM ( 1 << 4) /* fm emul */
+-#define ACPI_RB ( 1 << 3) /* ringbus / aclink */
+-#define ACPI_MIDI ( 1 << 2)
+-#define ACPI_GP ( 1 << 1) /* game port */
+-#define ACPI_WP ( 1 << 0) /* wave processor */
+-
+-#define ACPI_ALL (0xffff)
+-#define ACPI_SLEEP (~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
+- ACPI_MIDI|ACPI_GP|ACPI_WP))
+-#define ACPI_NONE (ACPI__10)
+-
+-/* these masks indicate which units we care about at
+- which states */
+-static u16 acpi_state_mask[] = {
+- [ACPI_D0] = ACPI_ALL,
+- [ACPI_D1] = ACPI_SLEEP,
+- [ACPI_D2] = ACPI_SLEEP,
+- [ACPI_D3] = ACPI_NONE
+-};
+-
+
+ /* APU use in the driver */
+ enum snd_enum_apu_type {
+@@ -590,7 +550,7 @@ struct es1968 {
+ #endif
+ };
+
+-static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
+
+ static struct pci_device_id snd_es1968_ids[] = {
+ /* Maestro 1 */
+@@ -1905,7 +1865,7 @@ static void es1968_update_hw_volume(unsi
+ /* Figure out which volume control button was pushed,
+ based on differences from the default register
+ values. */
+- x = inb(chip->io_port + 0x1c);
++ x = inb(chip->io_port + 0x1c) & 0xee;
+ /* Reset the volume control registers. */
+ outb(0x88, chip->io_port + 0x1c);
+ outb(0x88, chip->io_port + 0x1d);
+@@ -1921,7 +1881,8 @@ static void es1968_update_hw_volume(unsi
+ /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
+ spin_lock_irqsave(&chip->ac97_lock, flags);
+ val = chip->ac97->regs[AC97_MASTER];
+- if (x & 1) {
++ switch (x) {
++ case 0x88:
+ /* mute */
+ val ^= 0x8000;
+ chip->ac97->regs[AC97_MASTER] = val;
+@@ -1929,26 +1890,31 @@ static void es1968_update_hw_volume(unsi
+ outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_switch->id);
+- } else {
+- val &= 0x7fff;
+- if (((x>>1) & 7) > 4) {
+- /* volume up */
+- if ((val & 0xff) > 0)
+- val--;
+- if ((val & 0xff00) > 0)
+- val -= 0x0100;
+- } else {
+- /* volume down */
+- if ((val & 0xff) < 0x1f)
+- val++;
+- if ((val & 0xff00) < 0x1f00)
+- val += 0x0100;
+- }
++ break;
++ case 0xaa:
++ /* volume up */
++ if ((val & 0x7f) > 0)
++ val--;
++ if ((val & 0x7f00) > 0)
++ val -= 0x0100;
++ chip->ac97->regs[AC97_MASTER] = val;
++ outw(val, chip->io_port + ESM_AC97_DATA);
++ outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
++ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
++ &chip->master_volume->id);
++ break;
++ case 0x66:
++ /* volume down */
++ if ((val & 0x7f) < 0x1f)
++ val++;
++ if ((val & 0x7f00) < 0x1f00)
++ val += 0x0100;
+ chip->ac97->regs[AC97_MASTER] = val;
+ outw(val, chip->io_port + ESM_AC97_DATA);
+ outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_volume->id);
++ break;
+ }
+ spin_unlock_irqrestore(&chip->ac97_lock, flags);
+ }
+@@ -1956,7 +1922,7 @@ static void es1968_update_hw_volume(unsi
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
+ {
+ struct es1968 *chip = dev_id;
+ u32 event;
+@@ -1973,7 +1939,7 @@ static irqreturn_t snd_es1968_interrupt(
+ outb(0xFF, chip->io_port + 0x1A);
+
+ if ((event & ESM_MPU401_IRQ) && chip->rmidi) {
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+ }
+
+ if (event & ESM_SOUND_IRQ) {
+@@ -2154,21 +2120,6 @@ static void snd_es1968_reset(struct es19
+ }
+
+ /*
+- * power management
+- */
+-static void snd_es1968_set_acpi(struct es1968 *chip, int state)
+-{
+- u16 active_mask = acpi_state_mask[state];
+-
+- pci_set_power_state(chip->pci, state);
+- /* make sure the units we care about are on
+- XXX we might want to do this before state flipping? */
+- pci_write_config_word(chip->pci, 0x54, ~ active_mask);
+- pci_write_config_word(chip->pci, 0x56, ~ active_mask);
+-}
+-
+-
+-/*
+ * initialize maestro chip
+ */
+ static void snd_es1968_chip_init(struct es1968 *chip)
+@@ -2190,9 +2141,6 @@ static void snd_es1968_chip_init(struct
+ * IRQs.
+ */
+
+- /* do config work at full power */
+- snd_es1968_set_acpi(chip, ACPI_D0);
+-
+ /* Config Reg A */
+ pci_read_config_word(pci, ESM_CONFIG_A, &w);
+
+@@ -2391,9 +2339,10 @@ static int es1968_suspend(struct pci_dev
+ snd_pcm_suspend_all(chip->pcm);
+ snd_ac97_suspend(chip->ac97);
+ snd_es1968_bob_stop(chip);
+- snd_es1968_set_acpi(chip, ACPI_D3);
++
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2407,9 +2356,16 @@ static int es1968_resume(struct pci_dev
+ return 0;
+
+ /* restore all our config */
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "es1968: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
++
+ snd_es1968_chip_init(chip);
+
+ /* need to restore the base pointers.. */
+@@ -2508,7 +2464,6 @@ static int snd_es1968_free(struct es1968
+ if (chip->irq >= 0)
+ free_irq(chip->irq, (void *)chip);
+ snd_es1968_free_gameport(chip);
+- snd_es1968_set_acpi(chip, ACPI_D3);
+ chip->master_switch = NULL;
+ chip->master_volume = NULL;
+ pci_release_regions(chip->pci);
+diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
+index 13868c9..77e3d5c 100644
+--- a/sound/pci/fm801.c
++++ b/sound/pci/fm801.c
+@@ -2,6 +2,7 @@
+ * The driver for the ForteMedia FM801 based soundcards
+ * Copyright (c) by Jaroslav Kysela <perex at suse.cz>
+ *
++ * Support FM only card by Andy Shevchenko <andy at smile.org.ua>
+ *
+ * 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
+@@ -28,6 +29,7 @@
+ #include <linux/moduleparam.h>
+ #include <sound/core.h>
+ #include <sound/pcm.h>
++#include <sound/tlv.h>
+ #include <sound/ac97_codec.h>
+ #include <sound/mpu401.h>
+ #include <sound/opl3.h>
+@@ -54,6 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_D
+ * 1 = MediaForte 256-PCS
+ * 2 = MediaForte 256-PCPR
+ * 3 = MediaForte 64-PCR
++ * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card
+ * High 16-bits are video (radio) device number + 1
+ */
+ static int tea575x_tuner[SNDRV_CARDS];
+@@ -158,6 +161,7 @@ struct fm801 {
+ unsigned int multichannel: 1, /* multichannel support */
+ secondary: 1; /* secondary codec */
+ unsigned char secondary_addr; /* address of the secondary codec */
++ unsigned int tea575x_tuner; /* tuner flags */
+
+ unsigned short ply_ctrl; /* playback control */
+ unsigned short cap_ctrl; /* capture control */
+@@ -318,10 +322,8 @@ static unsigned int channels[] = {
+ 2, 4, 6
+ };
+
+-#define CHANNELS sizeof(channels) / sizeof(channels[0])
+-
+ static struct snd_pcm_hw_constraint_list hw_constraints_channels = {
+- .count = CHANNELS,
++ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+ };
+@@ -518,7 +520,7 @@ static snd_pcm_uframes_t snd_fm801_captu
+ return bytes_to_frames(substream->runtime, ptr);
+ }
+
+-static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
+ {
+ struct fm801 *chip = dev_id;
+ unsigned short status;
+@@ -559,7 +561,7 @@ static irqreturn_t snd_fm801_interrupt(i
+ snd_pcm_period_elapsed(chip->capture_substream);
+ }
+ if (chip->rmidi && (status & FM801_IRQ_MPU))
+- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+ if (status & FM801_IRQ_VOLUME)
+ ;/* TODO */
+
+@@ -1052,6 +1054,13 @@ static int snd_fm801_put_single(struct s
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \
+ .get = snd_fm801_get_double, .put = snd_fm801_put_double, \
+ .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) }
++#define FM801_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
++ .name = xname, .info = snd_fm801_info_double, \
++ .get = snd_fm801_get_double, .put = snd_fm801_put_double, \
++ .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \
++ .tlv = { .p = (xtlv) } }
+
+ static int snd_fm801_info_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+@@ -1148,14 +1157,19 @@ static int snd_fm801_put_mux(struct snd_
+ return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
++
+ #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)
+
+ static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = {
+-FM801_DOUBLE("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1),
++FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1,
++ db_scale_dsp),
+ FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1),
+-FM801_DOUBLE("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1),
++FM801_DOUBLE_TLV("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1,
++ db_scale_dsp),
+ FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1),
+-FM801_DOUBLE("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1),
++FM801_DOUBLE_TLV("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1,
++ db_scale_dsp),
+ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1253,6 +1267,9 @@ static int snd_fm801_chip_init(struct fm
+ int id;
+ unsigned short cmdw;
+
++ if (chip->tea575x_tuner & 0x0010)
++ goto __ac97_ok;
++
+ /* codec cold reset + AC'97 warm reset */
+ outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL));
+ inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
+@@ -1290,6 +1307,8 @@ static int snd_fm801_chip_init(struct fm
+ wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750));
+ }
+
++ __ac97_ok:
++
+ /* init volume */
+ outw(0x0808, FM801_REG(chip, PCM_VOL));
+ outw(0x9f1f, FM801_REG(chip, FM_VOL));
+@@ -1298,9 +1317,12 @@ static int snd_fm801_chip_init(struct fm
+ /* I2S control - I2S mode */
+ outw(0x0003, FM801_REG(chip, I2S_MODE));
+
+- /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */
++ /* interrupt setup */
+ cmdw = inw(FM801_REG(chip, IRQ_MASK));
+- cmdw &= ~0x0083;
++ if (chip->irq < 0)
++ cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */
++ else
++ cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */
+ outw(cmdw, FM801_REG(chip, IRQ_MASK));
+
+ /* interrupt clear */
+@@ -1365,20 +1387,23 @@ static int __devinit snd_fm801_create(st
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
++ chip->tea575x_tuner = tea575x_tuner;
+ if ((err = pci_request_regions(pci, "FM801")) < 0) {
+ kfree(chip);
+ pci_disable_device(pci);
+ return err;
+ }
+ chip->port = pci_resource_start(pci, 0);
+- if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED,
+- "FM801", chip)) {
+- snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
+- snd_fm801_free(chip);
+- return -EBUSY;
++ if ((tea575x_tuner & 0x0010) == 0) {
++ if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED,
++ "FM801", chip)) {
++ snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
++ snd_fm801_free(chip);
++ return -EBUSY;
++ }
++ chip->irq = pci->irq;
++ pci_set_master(pci);
+ }
+- chip->irq = pci->irq;
+- pci_set_master(pci);
+
+ pci_read_config_byte(pci, PCI_REVISION_ID, &rev);
+ if (rev >= 0xb1) /* FM801-AU */
+@@ -1394,12 +1419,12 @@ static int __devinit snd_fm801_create(st
+ snd_card_set_dev(card, &pci->dev);
+
+ #ifdef TEA575X_RADIO
+- if (tea575x_tuner > 0 && (tea575x_tuner & 0xffff) < 4) {
++ if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
+ chip->tea.dev_nr = tea575x_tuner >> 16;
+ chip->tea.card = card;
+ chip->tea.freq_fixup = 10700;
+ chip->tea.private_data = chip;
+- chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0xffff) - 1];
++ chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1];
+ snd_tea575x_init(&chip->tea);
+ }
+ #endif
+@@ -1439,6 +1464,9 @@ static int __devinit snd_card_fm801_prob
+ sprintf(card->longname, "%s at 0x%lx, irq %i",
+ card->shortname, chip->port, chip->irq);
+
++ if (tea575x_tuner[dev] & 0x0010)
++ goto __fm801_tuner_only;
++
+ if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
+ snd_card_free(card);
+ return err;
+@@ -1465,6 +1493,7 @@ static int __devinit snd_card_fm801_prob
+ return err;
+ }
+
++ __fm801_tuner_only:
+ if ((err = snd_card_register(card)) < 0) {
+ snd_card_free(card);
+ return err;
+@@ -1502,9 +1531,9 @@ static int snd_fm801_suspend(struct pci_
+ chip->saved_regs[i] = inw(chip->port + saved_regs[i]);
+ /* FIXME: tea575x suspend */
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1514,9 +1543,14 @@ static int snd_fm801_resume(struct pci_d
+ struct fm801 *chip = card->private_data;
+ int i;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "fm801: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_fm801_chip_init(chip, 1);
+diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
+index 23201f3..9c3d7ac 100644
+--- a/sound/pci/hda/hda_codec.c
++++ b/sound/pci/hda/hda_codec.c
+@@ -29,6 +29,7 @@
+ #include <sound/core.h>
+ #include "hda_codec.h"
+ #include <sound/asoundef.h>
++#include <sound/tlv.h>
+ #include <sound/initval.h>
+ #include "hda_local.h"
+
+@@ -50,8 +51,10 @@ struct hda_vendor_id {
+ /* codec vendor labels */
+ static struct hda_vendor_id hda_vendor_ids[] = {
+ { 0x10ec, "Realtek" },
++ { 0x1057, "Motorola" },
+ { 0x11d4, "Analog Devices" },
+ { 0x13f6, "C-Media" },
++ { 0x14f1, "Conexant" },
+ { 0x434d, "C-Media" },
+ { 0x8384, "SigmaTel" },
+ {} /* terminator */
+@@ -841,6 +844,31 @@ int snd_hda_mixer_amp_volume_put(struct
+ return change;
+ }
+
++int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
++ unsigned int size, unsigned int __user *_tlv)
++{
++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
++ hda_nid_t nid = get_amp_nid(kcontrol);
++ int dir = get_amp_direction(kcontrol);
++ u32 caps, val1, val2;
++
++ if (size < 4 * sizeof(unsigned int))
++ return -ENOMEM;
++ caps = query_amp_caps(codec, nid, dir);
++ val2 = (((caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT) + 1) * 25;
++ val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
++ val1 = ((int)val1) * ((int)val2);
++ if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
++ return -EFAULT;
++ if (put_user(2 * sizeof(unsigned int), _tlv + 1))
++ return -EFAULT;
++ if (put_user(val1, _tlv + 2))
++ return -EFAULT;
++ if (put_user(val2, _tlv + 3))
++ return -EFAULT;
++ return 0;
++}
++
+ /* switch */
+ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+@@ -1477,10 +1505,10 @@ int snd_hda_query_supported_pcm(struct h
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ if (val & AC_SUPPCM_BITS_32)
+ bps = 32;
+- else if (val & AC_SUPPCM_BITS_20)
+- bps = 20;
+ else if (val & AC_SUPPCM_BITS_24)
+ bps = 24;
++ else if (val & AC_SUPPCM_BITS_20)
++ bps = 20;
+ }
+ }
+ else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */
+@@ -1916,7 +1944,7 @@ int snd_hda_multi_out_analog_prepare(str
+
+ /* front */
+ snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
+- if (mout->hp_nid)
++ if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT])
+ /* headphone out will just decode front left/right (stereo) */
+ snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
+ /* extra outputs copied from front */
+@@ -1984,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid,
+ * in the order of front, rear, CLFE, side, ...
+ *
+ * If more extra outputs (speaker and headphone) are found, the pins are
+- * assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack
++ * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
+ * is detected, one of speaker of HP pins is assigned as the primary
+ * output, i.e. to line_out_pins[0]. So, line_outs is always positive
+ * if any analog output exists.
+@@ -2046,14 +2074,26 @@ int snd_hda_parse_pin_def_config(struct
+ cfg->speaker_outs++;
+ break;
+ case AC_JACK_HP_OUT:
+- cfg->hp_pin = nid;
++ if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
++ continue;
++ cfg->hp_pins[cfg->hp_outs] = nid;
++ cfg->hp_outs++;
+ break;
+- case AC_JACK_MIC_IN:
+- if (loc == AC_JACK_LOC_FRONT)
+- cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid;
+- else
+- cfg->input_pins[AUTO_PIN_MIC] = nid;
++ case AC_JACK_MIC_IN: {
++ int preferred, alt;
++ if (loc == AC_JACK_LOC_FRONT) {
++ preferred = AUTO_PIN_FRONT_MIC;
++ alt = AUTO_PIN_MIC;
++ } else {
++ preferred = AUTO_PIN_MIC;
++ alt = AUTO_PIN_FRONT_MIC;
++ }
++ if (!cfg->input_pins[preferred])
++ cfg->input_pins[preferred] = nid;
++ else if (!cfg->input_pins[alt])
++ cfg->input_pins[alt] = nid;
+ break;
++ }
+ case AC_JACK_LINE_IN:
+ if (loc == AC_JACK_LOC_FRONT)
+ cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
+@@ -2119,8 +2159,10 @@ int snd_hda_parse_pin_def_config(struct
+ cfg->speaker_outs, cfg->speaker_pins[0],
+ cfg->speaker_pins[1], cfg->speaker_pins[2],
+ cfg->speaker_pins[3], cfg->speaker_pins[4]);
+- snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n",
+- cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin);
++ snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
++ cfg->hp_outs, cfg->hp_pins[0],
++ cfg->hp_pins[1], cfg->hp_pins[2],
++ cfg->hp_pins[3], cfg->hp_pins[4]);
+ snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
+ " cd=0x%x, aux=0x%x\n",
+ cfg->input_pins[AUTO_PIN_MIC],
+@@ -2141,10 +2183,12 @@ int snd_hda_parse_pin_def_config(struct
+ sizeof(cfg->speaker_pins));
+ cfg->speaker_outs = 0;
+ memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+- } else if (cfg->hp_pin) {
+- cfg->line_outs = 1;
+- cfg->line_out_pins[0] = cfg->hp_pin;
+- cfg->hp_pin = 0;
++ } else if (cfg->hp_outs) {
++ cfg->line_outs = cfg->hp_outs;
++ memcpy(cfg->line_out_pins, cfg->hp_pins,
++ sizeof(cfg->hp_pins));
++ cfg->hp_outs = 0;
++ memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+ }
+ }
+
+diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
+index 40520e9..c12bc4e 100644
+--- a/sound/pci/hda/hda_codec.h
++++ b/sound/pci/hda/hda_codec.h
+@@ -479,7 +479,7 @@ struct hda_codec_ops {
+ struct hda_amp_info {
+ u32 key; /* hash key */
+ u32 amp_caps; /* amp capabilities */
+- u16 vol[2]; /* current volume & mute*/
++ u16 vol[2]; /* current volume & mute */
+ u16 status; /* update flag */
+ u16 next; /* next link */
+ };
+diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
+index 85ad164..97e9af1 100644
+--- a/sound/pci/hda/hda_generic.c
++++ b/sound/pci/hda/hda_generic.c
+@@ -46,11 +46,18 @@ struct hda_gnode {
+ };
+
+ /* patch-specific record */
++
++#define MAX_PCM_VOLS 2
++struct pcm_vol {
++ struct hda_gnode *node; /* Node for PCM volume */
++ unsigned int index; /* connection of PCM volume */
++};
++
+ struct hda_gspec {
+ struct hda_gnode *dac_node[2]; /* DAC node */
+ struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */
+- struct hda_gnode *pcm_vol_node[2]; /* Node for PCM volume */
+- unsigned int pcm_vol_index[2]; /* connection of PCM volume */
++ struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */
++ unsigned int pcm_vol_nodes; /* number of PCM volumes */
+
+ struct hda_gnode *adc_node; /* ADC node */
+ struct hda_gnode *cap_vol_node; /* Node for capture volume */
+@@ -285,9 +292,11 @@ static int parse_output_path(struct hda_
+ return node == spec->dac_node[dac_idx];
+ }
+ spec->dac_node[dac_idx] = node;
+- if (node->wid_caps & AC_WCAP_OUT_AMP) {
+- spec->pcm_vol_node[dac_idx] = node;
+- spec->pcm_vol_index[dac_idx] = 0;
++ if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
++ spec->pcm_vol_nodes < MAX_PCM_VOLS) {
++ spec->pcm_vol[spec->pcm_vol_nodes].node = node;
++ spec->pcm_vol[spec->pcm_vol_nodes].index = 0;
++ spec->pcm_vol_nodes++;
+ }
+ return 1; /* found */
+ }
+@@ -307,13 +316,16 @@ static int parse_output_path(struct hda_
+ select_input_connection(codec, node, i);
+ unmute_input(codec, node, i);
+ unmute_output(codec, node);
+- if (! spec->pcm_vol_node[dac_idx]) {
+- if (node->wid_caps & AC_WCAP_IN_AMP) {
+- spec->pcm_vol_node[dac_idx] = node;
+- spec->pcm_vol_index[dac_idx] = i;
+- } else if (node->wid_caps & AC_WCAP_OUT_AMP) {
+- spec->pcm_vol_node[dac_idx] = node;
+- spec->pcm_vol_index[dac_idx] = 0;
++ if (spec->dac_node[dac_idx] &&
++ spec->pcm_vol_nodes < MAX_PCM_VOLS &&
++ !(spec->dac_node[dac_idx]->wid_caps &
++ AC_WCAP_OUT_AMP)) {
++ if ((node->wid_caps & AC_WCAP_IN_AMP) ||
++ (node->wid_caps & AC_WCAP_OUT_AMP)) {
++ int n = spec->pcm_vol_nodes;
++ spec->pcm_vol[n].node = node;
++ spec->pcm_vol[n].index = i;
++ spec->pcm_vol_nodes++;
+ }
+ }
+ return 1;
+@@ -370,7 +382,9 @@ static struct hda_gnode *parse_output_ja
+ /* set PIN-Out enable */
+ snd_hda_codec_write(codec, node->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+- AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
++ AC_PINCTL_OUT_EN |
++ ((node->pin_caps & AC_PINCAP_HP_DRV) ?
++ AC_PINCTL_HP_EN : 0));
+ return node;
+ }
+ }
+@@ -461,14 +475,19 @@ static const char *get_input_type(struct
+ return "Front Line";
+ return "Line";
+ case AC_JACK_CD:
++#if 0
+ if (pinctl)
+ *pinctl |= AC_PINCTL_VREF_GRD;
++#endif
+ return "CD";
+ case AC_JACK_AUX:
+ if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+ return "Front Aux";
+ return "Aux";
+ case AC_JACK_MIC_IN:
++ if (node->pin_caps &
++ (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))
++ *pinctl |= AC_PINCTL_VREF_80;
+ if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+ return "Front Mic";
+ return "Mic";
+@@ -556,6 +575,29 @@ static int parse_adc_sub_nodes(struct hd
+ return 1; /* found */
+ }
+
++/* add a capture source element */
++static void add_cap_src(struct hda_gspec *spec, int idx)
++{
++ struct hda_input_mux_item *csrc;
++ char *buf;
++ int num, ocap;
++
++ num = spec->input_mux.num_items;
++ csrc = &spec->input_mux.items[num];
++ buf = spec->cap_labels[num];
++ for (ocap = 0; ocap < num; ocap++) {
++ if (! strcmp(buf, spec->cap_labels[ocap])) {
++ /* same label already exists,
++ * put the index number to be unique
++ */
++ sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
++ break;
++ }
++ }
++ csrc->index = idx;
++ spec->input_mux.num_items++;
++}
++
+ /*
+ * parse input
+ */
+@@ -576,28 +618,26 @@ static int parse_input_path(struct hda_c
+ * if it reaches to a proper input PIN, add the path as the
+ * input path.
+ */
++ /* first, check the direct connections to PIN widgets */
+ for (i = 0; i < adc_node->nconns; i++) {
+ node = hda_get_node(spec, adc_node->conn_list[i]);
+- if (! node)
+- continue;
+- err = parse_adc_sub_nodes(codec, spec, node);
+- if (err < 0)
+- return err;
+- else if (err > 0) {
+- struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items];
+- char *buf = spec->cap_labels[spec->input_mux.num_items];
+- int ocap;
+- for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) {
+- if (! strcmp(buf, spec->cap_labels[ocap])) {
+- /* same label already exists,
+- * put the index number to be unique
+- */
+- sprintf(buf, "%s %d", spec->cap_labels[ocap],
+- spec->input_mux.num_items);
+- }
+- }
+- csrc->index = i;
+- spec->input_mux.num_items++;
++ if (node && node->type == AC_WID_PIN) {
++ err = parse_adc_sub_nodes(codec, spec, node);
++ if (err < 0)
++ return err;
++ else if (err > 0)
++ add_cap_src(spec, i);
++ }
++ }
++ /* ... then check the rests, more complicated connections */
++ for (i = 0; i < adc_node->nconns; i++) {
++ node = hda_get_node(spec, adc_node->conn_list[i]);
++ if (node && node->type != AC_WID_PIN) {
++ err = parse_adc_sub_nodes(codec, spec, node);
++ if (err < 0)
++ return err;
++ else if (err > 0)
++ add_cap_src(spec, i);
+ }
+ }
+
+@@ -647,9 +687,6 @@ static int parse_input(struct hda_codec
+ /*
+ * create mixer controls if possible
+ */
+-#define DIR_OUT 0x1
+-#define DIR_IN 0x2
+-
+ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
+ unsigned int index, const char *type, const char *dir_sfx)
+ {
+@@ -722,49 +759,97 @@ static int check_existing_control(struct
+ /*
+ * build output mixer controls
+ */
+-static int build_output_controls(struct hda_codec *codec)
++static int create_output_mixers(struct hda_codec *codec, const char **names)
+ {
+ struct hda_gspec *spec = codec->spec;
+- static const char *types[2] = { "Master", "Headphone" };
+ int i, err;
+
+- for (i = 0; i < 2 && spec->pcm_vol_node[i]; i++) {
+- err = create_mixer(codec, spec->pcm_vol_node[i],
+- spec->pcm_vol_index[i],
+- types[i], "Playback");
++ for (i = 0; i < spec->pcm_vol_nodes; i++) {
++ err = create_mixer(codec, spec->pcm_vol[i].node,
++ spec->pcm_vol[i].index,
++ names[i], "Playback");
+ if (err < 0)
+ return err;
+ }
+ return 0;
+ }
+
++static int build_output_controls(struct hda_codec *codec)
++{
++ struct hda_gspec *spec = codec->spec;
++ static const char *types_speaker[] = { "Speaker", "Headphone" };
++ static const char *types_line[] = { "Front", "Headphone" };
++
++ switch (spec->pcm_vol_nodes) {
++ case 1:
++ return create_mixer(codec, spec->pcm_vol[0].node,
++ spec->pcm_vol[0].index,
++ "Master", "Playback");
++ case 2:
++ if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER)
++ return create_output_mixers(codec, types_speaker);
++ else
++ return create_output_mixers(codec, types_line);
++ }
++ return 0;
++}
++
+ /* create capture volume/switch */
+ static int build_input_controls(struct hda_codec *codec)
+ {
+ struct hda_gspec *spec = codec->spec;
+ struct hda_gnode *adc_node = spec->adc_node;
+- int err;
+-
+- if (! adc_node)
++ int i, err;
++ static struct snd_kcontrol_new cap_sel = {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Capture Source",
++ .info = capture_source_info,
++ .get = capture_source_get,
++ .put = capture_source_put,
++ };
++
++ if (! adc_node || ! spec->input_mux.num_items)
+ return 0; /* not found */
+
++ spec->cur_cap_src = 0;
++ select_input_connection(codec, adc_node,
++ spec->input_mux.items[0].index);
++
+ /* create capture volume and switch controls if the ADC has an amp */
+- err = create_mixer(codec, adc_node, 0, NULL, "Capture");
++ /* do we have only a single item? */
++ if (spec->input_mux.num_items == 1) {
++ err = create_mixer(codec, adc_node,
++ spec->input_mux.items[0].index,
++ NULL, "Capture");
++ if (err < 0)
++ return err;
++ return 0;
++ }
+
+ /* create input MUX if multiple sources are available */
+- if (spec->input_mux.num_items > 1) {
+- static struct snd_kcontrol_new cap_sel = {
+- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+- .name = "Capture Source",
+- .info = capture_source_info,
+- .get = capture_source_get,
+- .put = capture_source_put,
+- };
+- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0)
++ if ((err = snd_ctl_add(codec->bus->card,
++ snd_ctl_new1(&cap_sel, codec))) < 0)
++ return err;
++
++ /* no volume control? */
++ if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) ||
++ ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS))
++ return 0;
++
++ for (i = 0; i < spec->input_mux.num_items; i++) {
++ struct snd_kcontrol_new knew;
++ char name[32];
++ sprintf(name, "%s Capture Volume",
++ spec->input_mux.items[i].label);
++ knew = (struct snd_kcontrol_new)
++ HDA_CODEC_VOLUME(name, adc_node->nid,
++ spec->input_mux.items[i].index,
++ HDA_INPUT);
++ if ((err = snd_ctl_add(codec->bus->card,
++ snd_ctl_new1(&knew, codec))) < 0)
+ return err;
+- spec->cur_cap_src = 0;
+- select_input_connection(codec, adc_node, spec->input_mux.items[0].index);
+ }
++
+ return 0;
+ }
+
+diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
+index 79d63c9..0e292dc 100644
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -55,6 +55,7 @@ static char *model;
+ static int position_fix;
+ static int probe_mask = -1;
+ static int single_cmd;
++static int disable_msi;
+
+ module_param(index, int, 0444);
+ MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
+@@ -68,6 +69,8 @@ module_param(probe_mask, int, 0444);
+ MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+ module_param(single_cmd, bool, 0444);
+ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
++module_param(disable_msi, int, 0);
++MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
+
+
+ /* just for backward compatibility */
+@@ -83,6 +86,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},
+ "{ATI, SB450},"
+ "{ATI, SB600},"
+ "{ATI, RS600},"
++ "{ATI, RS690},"
+ "{VIA, VT8251},"
+ "{VIA, VT8237A},"
+ "{SiS, SIS966},"
+@@ -252,7 +256,7 @@ enum {
+ struct azx_dev {
+ u32 *bdl; /* virtual address of the BDL */
+ dma_addr_t bdl_addr; /* physical address of the BDL */
+- volatile u32 *posbuf; /* position buffer pointer */
++ u32 *posbuf; /* position buffer pointer */
+
+ unsigned int bufsize; /* size of the play buffer in bytes */
+ unsigned int fragsize; /* size of each period in bytes */
+@@ -271,8 +275,8 @@ struct azx_dev {
+ /* for sanity check of position buffer */
+ unsigned int period_intr;
+
+- unsigned int opened: 1;
+- unsigned int running: 1;
++ unsigned int opened :1;
++ unsigned int running :1;
+ };
+
+ /* CORB/RIRB */
+@@ -330,8 +334,10 @@ struct azx {
+
+ /* flags */
+ int position_fix;
+- unsigned int initialized: 1;
+- unsigned int single_cmd: 1;
++ unsigned int initialized :1;
++ unsigned int single_cmd :1;
++ unsigned int polling_mode :1;
++ unsigned int msi :1;
+ };
+
+ /* driver types */
+@@ -392,6 +398,7 @@ static char *driver_short_names[] __devi
+ */
+ #define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)
+
++static int azx_acquire_irq(struct azx *chip, int do_disconnect);
+
+ /*
+ * Interface for HD codec
+@@ -516,23 +523,48 @@ static void azx_update_rirb(struct azx *
+ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
+ {
+ struct azx *chip = codec->bus->private_data;
+- int timeout = 50;
++ unsigned long timeout;
+
+- while (chip->rirb.cmds) {
+- if (! --timeout) {
+- snd_printk(KERN_ERR
+- "hda_intel: azx_get_response timeout, "
+- "switching to single_cmd mode...\n");
+- chip->rirb.rp = azx_readb(chip, RIRBWP);
+- chip->rirb.cmds = 0;
+- /* switch to single_cmd mode */
+- chip->single_cmd = 1;
+- azx_free_cmd_io(chip);
+- return -1;
++ again:
++ timeout = jiffies + msecs_to_jiffies(1000);
++ do {
++ if (chip->polling_mode) {
++ spin_lock_irq(&chip->reg_lock);
++ azx_update_rirb(chip);
++ spin_unlock_irq(&chip->reg_lock);
+ }
+- msleep(1);
++ if (! chip->rirb.cmds)
++ return chip->rirb.res; /* the last value */
++ schedule_timeout_interruptible(1);
++ } while (time_after_eq(timeout, jiffies));
++
++ if (chip->msi) {
++ snd_printk(KERN_WARNING "hda_intel: No response from codec, "
++ "disabling MSI...\n");
++ free_irq(chip->irq, chip);
++ chip->irq = -1;
++ pci_disable_msi(chip->pci);
++ chip->msi = 0;
++ if (azx_acquire_irq(chip, 1) < 0)
++ return -1;
++ goto again;
++ }
++
++ if (!chip->polling_mode) {
++ snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
++ "switching to polling mode...\n");
++ chip->polling_mode = 1;
++ goto again;
+ }
+- return chip->rirb.res; /* the last value */
++
++ snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
++ "switching to single_cmd mode...\n");
++ chip->rirb.rp = azx_readb(chip, RIRBWP);
++ chip->rirb.cmds = 0;
++ /* switch to single_cmd mode */
++ chip->single_cmd = 1;
++ azx_free_cmd_io(chip);
++ return -1;
+ }
+
+ /*
+@@ -642,14 +674,14 @@ static int azx_reset(struct azx *chip)
+ azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
+
+ count = 50;
+- while (! azx_readb(chip, GCTL) && --count)
++ while (!azx_readb(chip, GCTL) && --count)
+ msleep(1);
+
+- /* Brent Chartrand said to wait >= 540us for codecs to intialize */
++ /* Brent Chartrand said to wait >= 540us for codecs to initialize */
+ msleep(1);
+
+ /* check to see if controller is ready */
+- if (! azx_readb(chip, GCTL)) {
++ if (!azx_readb(chip, GCTL)) {
+ snd_printd("azx_reset: controller not ready!\n");
+ return -EBUSY;
+ }
+@@ -658,7 +690,7 @@ static int azx_reset(struct azx *chip)
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);
+
+ /* detect codecs */
+- if (! chip->codec_mask) {
++ if (!chip->codec_mask) {
+ chip->codec_mask = azx_readw(chip, STATESTS);
+ snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);
+ }
+@@ -766,7 +798,7 @@ static void azx_init_chip(struct azx *ch
+ azx_int_enable(chip);
+
+ /* initialize the codec command I/O */
+- if (! chip->single_cmd)
++ if (!chip->single_cmd)
+ azx_init_cmd_io(chip);
+
+ /* program the position buffer */
+@@ -794,7 +826,7 @@ static void azx_init_chip(struct azx *ch
+ /*
+ * interrupt handler
+ */
+-static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
++static irqreturn_t azx_interrupt(int irq, void *dev_id)
+ {
+ struct azx *chip = dev_id;
+ struct azx_dev *azx_dev;
+@@ -999,8 +1031,9 @@ static struct snd_pcm_hardware azx_pcm_h
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+- SNDRV_PCM_INFO_PAUSE /*|*/
+- /*SNDRV_PCM_INFO_RESUME*/),
++ /* No full-resume yet implemented */
++ /* SNDRV_PCM_INFO_RESUME |*/
++ SNDRV_PCM_INFO_PAUSE),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+@@ -1178,7 +1211,7 @@ static snd_pcm_uframes_t azx_pcm_pointer
+ if (chip->position_fix == POS_FIX_POSBUF ||
+ chip->position_fix == POS_FIX_AUTO) {
+ /* use the position buffer */
+- pos = *azx_dev->posbuf;
++ pos = le32_to_cpu(*azx_dev->posbuf);
+ if (chip->position_fix == POS_FIX_AUTO &&
+ azx_dev->period_intr == 1 && ! pos) {
+ printk(KERN_WARNING
+@@ -1222,7 +1255,12 @@ static int __devinit create_codec_pcm(st
+ struct snd_pcm *pcm;
+ struct azx_pcm *apcm;
+
+- snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL);
++ /* if no substreams are defined for both playback and capture,
++ * it's just a placeholder. ignore it.
++ */
++ if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
++ return 0;
++
+ snd_assert(cpcm->name, return -EINVAL);
+
+ err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+@@ -1248,7 +1286,8 @@ static int __devinit create_codec_pcm(st
+ snd_dma_pci_data(chip->pci),
+ 1024 * 64, 1024 * 128);
+ chip->pcm[pcm_dev] = pcm;
+- chip->pcm_devs = pcm_dev + 1;
++ if (chip->pcm_devs < pcm_dev + 1)
++ chip->pcm_devs = pcm_dev + 1;
+
+ return 0;
+ }
+@@ -1326,7 +1365,7 @@ static int __devinit azx_init_stream(str
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
+ azx_dev->bdl = (u32 *)(chip->bdl.area + off);
+ azx_dev->bdl_addr = chip->bdl.addr + off;
+- azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
++ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
+ /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+ /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+@@ -1339,6 +1378,20 @@ static int __devinit azx_init_stream(str
+ return 0;
+ }
+
++static int azx_acquire_irq(struct azx *chip, int do_disconnect)
++{
++ if (request_irq(chip->pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
++ "HDA Intel", chip)) {
++ printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
++ "disabling device\n", chip->pci->irq);
++ if (do_disconnect)
++ snd_card_disconnect(chip->card);
++ return -1;
++ }
++ chip->irq = chip->pci->irq;
++ return 0;
++}
++
+
+ #ifdef CONFIG_PM
+ /*
+@@ -1355,8 +1408,16 @@ static int azx_suspend(struct pci_dev *p
+ snd_pcm_suspend_all(chip->pcm[i]);
+ snd_hda_suspend(chip->bus, state);
+ azx_free_cmd_io(chip);
++ if (chip->irq >= 0) {
++ synchronize_irq(chip->irq);
++ free_irq(chip->irq, chip);
++ chip->irq = -1;
++ }
++ if (chip->msi)
++ pci_disable_msi(chip->pci);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1365,9 +1426,20 @@ static int azx_resume(struct pci_dev *pc
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct azx *chip = card->private_data;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "hda-intel: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
++ if (chip->msi)
++ if (pci_enable_msi(pci) < 0)
++ chip->msi = 0;
++ if (azx_acquire_irq(chip, 1) < 0)
++ return -EIO;
+ azx_init_chip(chip);
+ snd_hda_resume(chip->bus);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+@@ -1397,13 +1469,14 @@ static int azx_free(struct azx *chip)
+ /* disable position buffer */
+ azx_writel(chip, DPLBASE, 0);
+ azx_writel(chip, DPUBASE, 0);
+-
+- /* wait a little for interrupts to finish */
+- msleep(1);
+ }
+
+- if (chip->irq >= 0)
++ if (chip->irq >= 0) {
++ synchronize_irq(chip->irq);
+ free_irq(chip->irq, (void*)chip);
++ }
++ if (chip->msi)
++ pci_disable_msi(chip->pci);
+ if (chip->remap_addr)
+ iounmap(chip->remap_addr);
+
+@@ -1434,19 +1507,19 @@ static int __devinit azx_create(struct s
+ struct azx **rchip)
+ {
+ struct azx *chip;
+- int err = 0;
++ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = azx_dev_free,
+ };
+
+ *rchip = NULL;
+
+- if ((err = pci_enable_device(pci)) < 0)
++ err = pci_enable_device(pci);
++ if (err < 0)
+ return err;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+-
+- if (NULL == chip) {
++ if (!chip) {
+ snd_printk(KERN_ERR SFX "cannot allocate chip\n");
+ pci_disable_device(pci);
+ return -ENOMEM;
+@@ -1458,6 +1531,7 @@ static int __devinit azx_create(struct s
+ chip->pci = pci;
+ chip->irq = -1;
+ chip->driver_type = driver_type;
++ chip->msi = !disable_msi;
+
+ chip->position_fix = position_fix;
+ chip->single_cmd = single_cmd;
+@@ -1472,13 +1546,14 @@ static int __devinit azx_create(struct s
+ }
+ #endif
+
+- if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
++ err = pci_request_regions(pci, "ICH HD audio");
++ if (err < 0) {
+ kfree(chip);
+ pci_disable_device(pci);
+ return err;
+ }
+
+- chip->addr = pci_resource_start(pci,0);
++ chip->addr = pci_resource_start(pci, 0);
+ chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0));
+ if (chip->remap_addr == NULL) {
+ snd_printk(KERN_ERR SFX "ioremap error\n");
+@@ -1486,13 +1561,14 @@ static int __devinit azx_create(struct s
+ goto errout;
+ }
+
+- if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
+- "HDA Intel", (void*)chip)) {
+- snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
++ if (chip->msi)
++ if (pci_enable_msi(pci) < 0)
++ chip->msi = 0;
++
++ if (azx_acquire_irq(chip, 0) < 0) {
+ err = -EBUSY;
+ goto errout;
+ }
+- chip->irq = pci->irq;
+
+ pci_set_master(pci);
+ synchronize_irq(chip->irq);
+@@ -1519,7 +1595,7 @@ static int __devinit azx_create(struct s
+ }
+ chip->num_streams = chip->playback_streams + chip->capture_streams;
+ chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
+- if (! chip->azx_dev) {
++ if (!chip->azx_dev) {
+ snd_printk(KERN_ERR "cannot malloc azx_dev\n");
+ goto errout;
+ }
+@@ -1550,7 +1626,7 @@ static int __devinit azx_create(struct s
+ chip->initialized = 1;
+
+ /* codec detection */
+- if (! chip->codec_mask) {
++ if (!chip->codec_mask) {
+ snd_printk(KERN_ERR SFX "no codecs found!\n");
+ err = -ENODEV;
+ goto errout;
+@@ -1577,16 +1653,16 @@ static int __devinit azx_probe(struct pc
+ {
+ struct snd_card *card;
+ struct azx *chip;
+- int err = 0;
++ int err;
+
+ card = snd_card_new(index, id, THIS_MODULE, 0);
+- if (NULL == card) {
++ if (!card) {
+ snd_printk(KERN_ERR SFX "Error creating card!\n");
+ return -ENOMEM;
+ }
+
+- if ((err = azx_create(card, pci, pci_id->driver_data,
+- &chip)) < 0) {
++ err = azx_create(card, pci, pci_id->driver_data, &chip);
++ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+@@ -1637,11 +1713,13 @@ static struct pci_device_id azx_ids[] =
+ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+ { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
+ { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
++ { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
+ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
+ { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
+ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
+ { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */
+ { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */
++ { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 03f0 */
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, azx_ids);
+diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
+index 14e8aa2..f9416c3 100644
+--- a/sound/pci/hda/hda_local.h
++++ b/sound/pci/hda/hda_local.h
+@@ -30,9 +30,13 @@
+ /* mono volume with index (index=0,1,...) (channel=1,2) */
+ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
+ .info = snd_hda_mixer_amp_volume_info, \
+ .get = snd_hda_mixer_amp_volume_get, \
+ .put = snd_hda_mixer_amp_volume_put, \
++ .tlv = { .c = snd_hda_mixer_amp_tlv }, \
+ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+ /* stereo volume with index */
+ #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
+@@ -63,6 +67,7 @@
+ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
+ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
++int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv);
+ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
+ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+@@ -224,7 +229,8 @@ struct auto_pin_cfg {
+ hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
+ int speaker_outs;
+ hda_nid_t speaker_pins[5];
+- hda_nid_t hp_pin;
++ int hp_outs;
++ hda_nid_t hp_pins[5];
+ hda_nid_t input_pins[AUTO_PIN_LAST];
+ hda_nid_t dig_out_pin;
+ hda_nid_t dig_in_pin;
+diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
+index c2f0fe8..d737f17 100644
+--- a/sound/pci/hda/hda_proc.c
++++ b/sound/pci/hda/hda_proc.c
+@@ -52,10 +52,9 @@ static void print_amp_caps(struct snd_in
+ struct hda_codec *codec, hda_nid_t nid, int dir)
+ {
+ unsigned int caps;
+- if (dir == HDA_OUTPUT)
+- caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP);
+- else
+- caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP);
++ caps = snd_hda_param_read(codec, nid,
++ dir == HDA_OUTPUT ?
++ AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+ if (caps == -1 || caps == 0) {
+ snd_iprintf(buffer, "N/A\n");
+ return;
+@@ -74,10 +73,7 @@ static void print_amp_vals(struct snd_in
+ unsigned int val;
+ int i;
+
+- if (dir == HDA_OUTPUT)
+- dir = AC_AMP_GET_OUTPUT;
+- else
+- dir = AC_AMP_GET_INPUT;
++ dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
+ for (i = 0; i < indices; i++) {
+ snd_iprintf(buffer, " [");
+ if (stereo) {
+diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
+index 6823f2b..edd22de 100644
+--- a/sound/pci/hda/patch_analog.c
++++ b/sound/pci/hda/patch_analog.c
+@@ -488,9 +488,13 @@ static struct snd_kcontrol_new ad1986a_m
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = ad1986a_pcm_amp_vol_info,
+ .get = ad1986a_pcm_amp_vol_get,
+ .put = ad1986a_pcm_amp_vol_put,
++ .tlv = { .c = snd_hda_mixer_amp_tlv },
+ .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
+ },
+ {
+@@ -637,6 +641,7 @@ static struct snd_kcontrol_new ad1986a_l
+ .info = snd_hda_mixer_amp_volume_info,
+ .get = snd_hda_mixer_amp_volume_get,
+ .put = ad1986a_laptop_master_vol_put,
++ .tlv = { .c = snd_hda_mixer_amp_tlv },
+ .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
+ },
+ {
+@@ -791,6 +796,8 @@ static struct hda_board_config ad1986a_c
+ .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
+ .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
++ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb,
++ .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */
+ { .modelname = "laptop", .config = AD1986A_LAPTOP },
+ { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
+ .config = AD1986A_LAPTOP }, /* FSC V2060 */
+@@ -803,12 +810,16 @@ static struct hda_board_config ad1986a_c
+ .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
+ { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
+ .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
++ { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026,
++ .config = AD1986A_LAPTOP_EAPD }, /* Samsung X10-T2300 Culesa */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
+ .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
+ .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7,
+ .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */
++ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1263,
++ .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1297,
+ .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af,
+@@ -1626,10 +1637,12 @@ static int ad198x_ch_mode_put(struct snd
+ {
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+- if (spec->need_dac_fix)
++ int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
++ spec->num_channel_mode,
++ &spec->multiout.max_channels);
++ if (! err && spec->need_dac_fix)
+ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+- return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
+- spec->num_channel_mode, &spec->multiout.max_channels);
++ return err;
+ }
+
+ /* 6-stack mode */
+@@ -2460,7 +2473,7 @@ static void ad1988_auto_init_extra_out(s
+ pin = spec->autocfg.speaker_pins[0];
+ if (pin) /* connect to front */
+ ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+- pin = spec->autocfg.hp_pin;
++ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ }
+@@ -2512,7 +2525,7 @@ static int ad1988_parse_auto_config(stru
+ (err = ad1988_auto_create_extra_out(codec,
+ spec->autocfg.speaker_pins[0],
+ "Speaker")) < 0 ||
+- (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin,
++ (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
+ "Headphone")) < 0 ||
+ (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+ return err;
+diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
+index a27440f..7333f27 100644
+--- a/sound/pci/hda/patch_atihdmi.c
++++ b/sound/pci/hda/patch_atihdmi.c
+@@ -161,5 +161,6 @@ static int patch_atihdmi(struct hda_code
+ */
+ struct hda_codec_preset snd_hda_preset_atihdmi[] = {
+ { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
++ { .id = 0x1002791a, .name = "ATI RS690 HDMI", .patch = patch_atihdmi },
+ {} /* terminator */
+ };
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 18d1052..0d728c6 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -79,6 +79,7 @@ enum {
+ ALC262_BASIC,
+ ALC262_FUJITSU,
+ ALC262_HP_BPC,
++ ALC262_BENQ_ED8,
+ ALC262_AUTO,
+ ALC262_MODEL_LAST /* last tag */
+ };
+@@ -89,6 +90,7 @@ enum {
+ ALC660_3ST,
+ ALC861_3ST_DIG,
+ ALC861_6ST_DIG,
++ ALC861_UNIWILL_M31,
+ ALC861_AUTO,
+ ALC861_MODEL_LAST,
+ };
+@@ -97,6 +99,7 @@ enum {
+ enum {
+ ALC882_3ST_DIG,
+ ALC882_6ST_DIG,
++ ALC882_ARIMA,
+ ALC882_AUTO,
+ ALC882_MODEL_LAST,
+ };
+@@ -108,6 +111,7 @@ enum {
+ ALC883_3ST_6ch,
+ ALC883_6ST_DIG,
+ ALC888_DEMO_BOARD,
++ ALC883_ACER,
+ ALC883_AUTO,
+ ALC883_MODEL_LAST,
+ };
+@@ -153,6 +157,7 @@ struct alc_spec {
+ /* channel model */
+ const struct hda_channel_mode *channel_mode;
+ int num_channel_mode;
++ int need_dac_fix;
+
+ /* PCM information */
+ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
+@@ -190,6 +195,7 @@ struct alc_config_preset {
+ hda_nid_t dig_in_nid;
+ unsigned int num_channel_mode;
+ const struct hda_channel_mode *channel_mode;
++ int need_dac_fix;
+ unsigned int num_mux_defs;
+ const struct hda_input_mux *input_mux;
+ void (*unsol_event)(struct hda_codec *, unsigned int);
+@@ -262,9 +268,12 @@ static int alc_ch_mode_put(struct snd_kc
+ {
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+- return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
+- spec->num_channel_mode,
+- &spec->multiout.max_channels);
++ int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
++ spec->num_channel_mode,
++ &spec->multiout.max_channels);
++ if (! err && spec->need_dac_fix)
++ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
++ return err;
+ }
+
+ /*
+@@ -544,6 +553,7 @@ static void setup_preset(struct alc_spec
+
+ spec->channel_mode = preset->channel_mode;
+ spec->num_channel_mode = preset->num_channel_mode;
++ spec->need_dac_fix = preset->need_dac_fix;
+
+ spec->multiout.max_channels = spec->channel_mode[0].channels;
+
+@@ -1348,6 +1358,10 @@ static struct hda_verb alc880_pin_clevo_
+ };
+
+ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
++ /* change to EAPD mode */
++ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
++ {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
++
+ /* Headphone output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ /* Front output*/
+@@ -1782,26 +1796,10 @@ static int alc_build_pcms(struct hda_cod
+ }
+ }
+
+- /* If the use of more than one ADC is requested for the current
+- * model, configure a second analog capture-only PCM.
+- */
+- if (spec->num_adc_nids > 1) {
+- codec->num_pcms++;
+- info++;
+- info->name = spec->stream_name_analog;
+- /* No playback stream for second PCM */
+- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
+- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
+- if (spec->stream_analog_capture) {
+- snd_assert(spec->adc_nids, return -EINVAL);
+- info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+- info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
+- }
+- }
+-
++ /* SPDIF for stream index #1 */
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+- codec->num_pcms++;
+- info++;
++ codec->num_pcms = 2;
++ info = spec->pcm_rec + 1;
+ info->name = spec->stream_name_digital;
+ if (spec->multiout.dig_out_nid &&
+ spec->stream_digital_playback) {
+@@ -1815,6 +1813,24 @@ static int alc_build_pcms(struct hda_cod
+ }
+ }
+
++ /* If the use of more than one ADC is requested for the current
++ * model, configure a second analog capture-only PCM.
++ */
++ /* Additional Analaog capture for index #2 */
++ if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
++ spec->adc_nids) {
++ codec->num_pcms = 3;
++ info = spec->pcm_rec + 2;
++ info->name = spec->stream_name_analog;
++ /* No playback stream for second PCM */
++ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
++ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
++ if (spec->stream_analog_capture) {
++ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
++ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
++ }
++ }
++
+ return 0;
+ }
+
+@@ -2130,7 +2146,10 @@ static struct hda_board_config alc880_cf
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
++ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST },
++ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
++ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
+@@ -2145,6 +2164,7 @@ static struct hda_board_config alc880_cf
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
+ /* TCL S700 */
++ { .modelname = "tcl", .config = ALC880_TCL_S700 },
+ { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
+
+ /* Back 3 jack, front 2 jack (Internal add Aux-In) */
+@@ -2156,8 +2176,13 @@ static struct hda_board_config alc880_cf
+ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
+ { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
+- /* Clevo m520G NB */
+- { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO },
++
++ /* Clevo laptops */
++ { .modelname = "clevo", .config = ALC880_CLEVO },
++ { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520,
++ .config = ALC880_CLEVO }, /* Clevo m520G NB */
++ { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660,
++ .config = ALC880_CLEVO }, /* Clevo m665n */
+
+ /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
+@@ -2222,12 +2247,16 @@ static struct hda_board_config alc880_cf
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
++ { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
++ { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
++ { .modelname = "asus-dig", .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
++ { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 },
+ { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
+
+ { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
+@@ -2243,6 +2272,7 @@ static struct hda_board_config alc880_cf
+
+ { .modelname = "lg-lw", .config = ALC880_LG_LW },
+ { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
++ { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW },
+
+ #ifdef CONFIG_SND_DEBUG
+ { .modelname = "test", .config = ALC880_TEST },
+@@ -2263,6 +2293,7 @@ static struct alc_config_preset alc880_p
+ .dac_nids = alc880_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_3ST_DIG] = {
+@@ -2273,6 +2304,7 @@ static struct alc_config_preset alc880_p
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_TCL_S700] = {
+@@ -2365,6 +2397,7 @@ static struct alc_config_preset alc880_p
+ .dac_nids = alc880_asus_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_ASUS_DIG] = {
+@@ -2376,6 +2409,7 @@ static struct alc_config_preset alc880_p
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_ASUS_DIG2] = {
+@@ -2387,6 +2421,7 @@ static struct alc_config_preset alc880_p
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_ASUS_W1V] = {
+@@ -2398,6 +2433,7 @@ static struct alc_config_preset alc880_p
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_UNIWILL_DIG] = {
+@@ -2408,6 +2444,7 @@ static struct alc_config_preset alc880_p
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_CLEVO] = {
+@@ -2419,6 +2456,7 @@ static struct alc_config_preset alc880_p
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_LG] = {
+@@ -2430,6 +2468,7 @@ static struct alc_config_preset alc880_p
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
+ .channel_mode = alc880_lg_ch_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc880_lg_capture_source,
+ .unsol_event = alc880_lg_unsol_event,
+ .init_hook = alc880_lg_automute,
+@@ -2714,7 +2753,7 @@ static void alc880_auto_init_extra_out(s
+ pin = spec->autocfg.speaker_pins[0];
+ if (pin) /* connect to front */
+ alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+- pin = spec->autocfg.hp_pin;
++ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ }
+@@ -2755,7 +2794,7 @@ static int alc880_parse_auto_config(stru
+ (err = alc880_auto_create_extra_out(spec,
+ spec->autocfg.speaker_pins[0],
+ "Speaker")) < 0 ||
+- (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin,
++ (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
+ "Headphone")) < 0 ||
+ (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+ return err;
+@@ -3697,7 +3736,7 @@ static int alc260_auto_create_multi_out_
+ return err;
+ }
+
+- nid = cfg->hp_pin;
++ nid = cfg->hp_pins[0];
+ if (nid) {
+ err = alc260_add_playback_controls(spec, nid, "Headphone");
+ if (err < 0)
+@@ -3767,7 +3806,7 @@ static void alc260_auto_init_multi_out(s
+ if (nid)
+ alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
+
+- nid = spec->autocfg.hp_pin;
++ nid = spec->autocfg.hp_pins[0];
+ if (nid)
+ alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
+ }
+@@ -3900,7 +3939,8 @@ static struct hda_board_config alc260_cf
+ { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
+ .config = ALC260_BASIC }, /* CTL Travel Master U553W */
+ { .modelname = "hp", .config = ALC260_HP },
+- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
++ { .modelname = "hp-3013", .config = ALC260_HP_3013 },
++ { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 },
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
+@@ -4266,6 +4306,13 @@ static struct hda_verb alc882_init_verbs
+ { }
+ };
+
++static struct hda_verb alc882_eapd_verbs[] = {
++ /* change to EAPD mode */
++ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
++ {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
++ { }
++};
++
+ /*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+@@ -4397,6 +4444,9 @@ static struct hda_board_config alc882_cf
+ .config = ALC882_6ST_DIG }, /* Foxconn */
+ { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
+ .config = ALC882_6ST_DIG }, /* ECS to Intel*/
++ { .modelname = "arima", .config = ALC882_ARIMA },
++ { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054,
++ .config = ALC882_ARIMA }, /* Arima W820Di1 */
+ { .modelname = "auto", .config = ALC882_AUTO },
+ {}
+ };
+@@ -4411,6 +4461,7 @@ static struct alc_config_preset alc882_p
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc882_capture_source,
+ },
+ [ALC882_6ST_DIG] = {
+@@ -4424,6 +4475,15 @@ static struct alc_config_preset alc882_p
+ .channel_mode = alc882_sixstack_modes,
+ .input_mux = &alc882_capture_source,
+ },
++ [ALC882_ARIMA] = {
++ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
++ .channel_mode = alc882_sixstack_modes,
++ .input_mux = &alc882_capture_source,
++ },
+ };
+
+
+@@ -4466,7 +4526,7 @@ static void alc882_auto_init_hp_out(stru
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+- pin = spec->autocfg.hp_pin;
++ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */
+ }
+@@ -4999,16 +5059,27 @@ static struct snd_kcontrol_new alc883_ca
+ */
+ static struct hda_board_config alc883_cfg_tbl[] = {
+ { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
++ { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG },
++ { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
++ .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
++ { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch },
++ { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
++ .config = ALC883_3ST_6ch },
++ { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601,
++ .config = ALC883_3ST_6ch }, /* D102GGC */
+ { .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
+- { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
+ { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
+ .config = ALC883_6ST_DIG }, /* MSI */
+ { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
+ .config = ALC883_6ST_DIG }, /* Foxconn */
+- { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
+- .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
+- { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
+- .config = ALC883_3ST_6ch },
++ { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
++ { .modelname = "acer", .config = ALC883_ACER },
++ { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/,
++ .config = ALC883_ACER },
++ { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102,
++ .config = ALC883_ACER },
++ { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f,
++ .config = ALC883_ACER },
+ { .modelname = "auto", .config = ALC883_AUTO },
+ {}
+ };
+@@ -5038,6 +5109,7 @@ static struct alc_config_preset alc883_p
+ .dig_in_nid = ALC883_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+ .channel_mode = alc883_3ST_6ch_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc883_capture_source,
+ },
+ [ALC883_3ST_6ch] = {
+@@ -5049,6 +5121,7 @@ static struct alc_config_preset alc883_p
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+ .channel_mode = alc883_3ST_6ch_modes,
++ .need_dac_fix = 1,
+ .input_mux = &alc883_capture_source,
+ },
+ [ALC883_6ST_DIG] = {
+@@ -5077,6 +5150,23 @@ static struct alc_config_preset alc883_p
+ .channel_mode = alc883_sixstack_modes,
+ .input_mux = &alc883_capture_source,
+ },
++ [ALC883_ACER] = {
++ .mixers = { alc883_base_mixer,
++ alc883_chmode_mixer },
++ /* On TravelMate laptops, GPIO 0 enables the internal speaker
++ * and the headphone jack. Turn this on and rely on the
++ * standard mute methods whenever the user wants to turn
++ * these outputs off.
++ */
++ .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
++ .dac_nids = alc883_dac_nids,
++ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
++ .adc_nids = alc883_adc_nids,
++ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
++ .channel_mode = alc883_3ST_2ch_modes,
++ .input_mux = &alc883_capture_source,
++ },
+ };
+
+
+@@ -5121,7 +5211,7 @@ static void alc883_auto_init_hp_out(stru
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+- pin = spec->autocfg.hp_pin;
++ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ /* use dac 0 */
+ alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+@@ -5217,8 +5307,10 @@ static int patch_alc883(struct hda_codec
+ spec->stream_digital_playback = &alc883_pcm_digital_playback;
+ spec->stream_digital_capture = &alc883_pcm_digital_capture;
+
+- spec->adc_nids = alc883_adc_nids;
+- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
++ if (! spec->adc_nids && spec->input_mux) {
++ spec->adc_nids = alc883_adc_nids;
++ spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
++ }
+
+ codec->patch_ops = alc_patch_ops;
+ if (board_config == ALC883_AUTO)
+@@ -5481,6 +5573,7 @@ static struct snd_kcontrol_new alc262_fu
+ .info = snd_hda_mixer_amp_volume_info,
+ .get = snd_hda_mixer_amp_volume_get,
+ .put = alc262_fujitsu_master_vol_put,
++ .tlv = { .c = snd_hda_mixer_amp_tlv },
+ .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
+ },
+ {
+@@ -5499,6 +5592,13 @@ static struct snd_kcontrol_new alc262_fu
+ { } /* end */
+ };
+
++/* additional init verbs for Benq laptops */
++static struct hda_verb alc262_EAPD_verbs[] = {
++ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
++ {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
++ {}
++};
++
+ /* add playback controls from the parsed DAC table */
+ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
+ {
+@@ -5534,7 +5634,7 @@ static int alc262_auto_create_multi_out_
+ return err;
+ }
+ }
+- nid = cfg->hp_pin;
++ nid = cfg->hp_pins[0];
+ if (nid) {
+ /* spec->multiout.hp_nid = 2; */
+ if (nid == 0x16) {
+@@ -5769,6 +5869,7 @@ static struct hda_board_config alc262_cf
+ { .modelname = "fujitsu", .config = ALC262_FUJITSU },
+ { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
+ .config = ALC262_FUJITSU },
++ { .modelname = "hp-bpc", .config = ALC262_HP_BPC },
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x208c,
+ .config = ALC262_HP_BPC }, /* xw4400 */
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
+@@ -5777,6 +5878,9 @@ static struct hda_board_config alc262_cf
+ .config = ALC262_HP_BPC }, /* xw8400 */
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
+ .config = ALC262_HP_BPC }, /* xw9400 */
++ { .modelname = "benq", .config = ALC262_BENQ_ED8 },
++ { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560,
++ .config = ALC262_BENQ_ED8 },
+ { .modelname = "auto", .config = ALC262_AUTO },
+ {}
+ };
+@@ -5814,6 +5918,16 @@ static struct alc_config_preset alc262_p
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_HP_capture_source,
+ },
++ [ALC262_BENQ_ED8] = {
++ .mixers = { alc262_base_mixer },
++ .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
++ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
++ .dac_nids = alc262_dac_nids,
++ .hp_nid = 0x03,
++ .num_channel_mode = ARRAY_SIZE(alc262_modes),
++ .channel_mode = alc262_modes,
++ .input_mux = &alc262_capture_source,
++ },
+ };
+
+ static int patch_alc262(struct hda_codec *codec)
+@@ -5942,6 +6056,23 @@ static struct hda_channel_mode alc861_th
+ { 2, alc861_threestack_ch2_init },
+ { 6, alc861_threestack_ch6_init },
+ };
++/* Set mic1 as input and unmute the mixer */
++static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
++ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
++ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
++ { } /* end */
++};
++/* Set mic1 as output and mute mixer */
++static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
++ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
++ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
++ { } /* end */
++};
++
++static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
++ { 2, alc861_uniwill_m31_ch2_init },
++ { 4, alc861_uniwill_m31_ch4_init },
++};
+
+ /* patch-ALC861 */
+
+@@ -6020,6 +6151,47 @@ static struct snd_kcontrol_new alc861_3S
+ },
+ { } /* end */
+ };
++static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
++ /* output mixer control */
++ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
++ HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
++ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
++ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
++ /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
++
++ /* Input mixer control */
++ /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
++ HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
++ HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
++ HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
++ HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
++ HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
++ HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
++ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
++
++ /* Capture mixer control */
++ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
++ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Capture Source",
++ .count = 1,
++ .info = alc_mux_enum_info,
++ .get = alc_mux_enum_get,
++ .put = alc_mux_enum_put,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Channel Mode",
++ .info = alc_ch_mode_info,
++ .get = alc_ch_mode_get,
++ .put = alc_ch_mode_put,
++ .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
++ },
++ { } /* end */
++};
+
+ /*
+ * generic initialization of ADC, input mixers and output mixers
+@@ -6148,6 +6320,67 @@ static struct hda_verb alc861_threestack
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ { }
+ };
++
++static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
++ /*
++ * Unmute ADC0 and set the default input to mic-in
++ */
++ /* port-A for surround (rear panel) */
++ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
++ /* port-B for mic-in (rear panel) with vref */
++ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
++ /* port-C for line-in (rear panel) */
++ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
++ /* port-D for Front */
++ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
++ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
++ /* port-E for HP out (front panel) */
++ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80
++ /* route front PCM to HP */
++ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ /* port-F for mic-in (front panel) with vref */
++ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
++ /* port-G for CLFE (rear panel) */
++ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
++ /* port-H for side (rear panel) */
++ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
++ /* CD-in */
++ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
++ /* route front mic to ADC1*/
++ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
++ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ /* Unmute DAC0~3 & spdif out*/
++ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
++ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
++ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
++ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
++
++ /* Unmute Mixer 14 (mic) 1c (Line in)*/
++ {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++
++ /* Unmute Stereo Mixer 15 */
++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step
++
++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front)
++ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
++ { }
++};
++
+ /*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+@@ -6401,7 +6634,7 @@ static void alc861_auto_init_hp_out(stru
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+- pin = spec->autocfg.hp_pin;
++ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]);
+ }
+@@ -6436,7 +6669,7 @@ static int alc861_parse_auto_config(stru
+
+ if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
+ (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
+- (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 ||
++ (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0])) < 0 ||
+ (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+ return err;
+
+@@ -6477,10 +6710,14 @@ static struct hda_board_config alc861_cf
+ { .modelname = "3stack", .config = ALC861_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
+ .config = ALC861_3ST },
++ { .modelname = "3stack-660", .config = ALC660_3ST },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
+ .config = ALC660_3ST },
+ { .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
+ { .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
++ { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31},
++ { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072,
++ .config = ALC861_UNIWILL_M31 },
+ { .modelname = "auto", .config = ALC861_AUTO },
+ {}
+ };
+@@ -6493,6 +6730,7 @@ static struct alc_config_preset alc861_p
+ .dac_nids = alc861_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+ .channel_mode = alc861_threestack_modes,
++ .need_dac_fix = 1,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+@@ -6505,6 +6743,7 @@ static struct alc_config_preset alc861_p
+ .dig_out_nid = ALC861_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+ .channel_mode = alc861_threestack_modes,
++ .need_dac_fix = 1,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+@@ -6528,10 +6767,25 @@ static struct alc_config_preset alc861_p
+ .dac_nids = alc660_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+ .channel_mode = alc861_threestack_modes,
++ .need_dac_fix = 1,
++ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
++ .adc_nids = alc861_adc_nids,
++ .input_mux = &alc861_capture_source,
++ },
++ [ALC861_UNIWILL_M31] = {
++ .mixers = { alc861_uniwill_m31_mixer },
++ .init_verbs = { alc861_uniwill_m31_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
++ .dac_nids = alc861_dac_nids,
++ .dig_out_nid = ALC861_DIGOUT_NID,
++ .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
++ .channel_mode = alc861_uniwill_m31_modes,
++ .need_dac_fix = 1,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ },
++
+ };
+
+
+diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
+index 250242c..cc87dff 100644
+--- a/sound/pci/hda/patch_si3054.c
++++ b/sound/pci/hda/patch_si3054.c
+@@ -297,7 +297,13 @@ static int patch_si3054(struct hda_codec
+ struct hda_codec_preset snd_hda_preset_si3054[] = {
+ { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
++ { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
++ { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 },
++ { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 },
++ { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
++ { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
++ { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
+ {}
+ };
+
+diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
+index ea99083..731b7b9 100644
+--- a/sound/pci/hda/patch_sigmatel.c
++++ b/sound/pci/hda/patch_sigmatel.c
+@@ -36,15 +36,15 @@
+
+ #define NUM_CONTROL_ALLOC 32
+ #define STAC_HP_EVENT 0x37
+-#define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT)
+
+ #define STAC_REF 0
+ #define STAC_D945GTP3 1
+ #define STAC_D945GTP5 2
+ #define STAC_MACMINI 3
+-#define STAC_D965_2112 4
+-#define STAC_D965_284B 5
+-#define STAC_922X_MODELS 6 /* number of 922x models */
++#define STAC_922X_MODELS 4 /* number of 922x models */
++#define STAC_D965_3ST 4
++#define STAC_D965_5ST 5
++#define STAC_927X_MODELS 6 /* number of 922x models */
+
+ struct sigmatel_spec {
+ struct snd_kcontrol_new *mixers[4];
+@@ -73,6 +73,7 @@ struct sigmatel_spec {
+ hda_nid_t *pin_nids;
+ unsigned int num_pins;
+ unsigned int *pin_configs;
++ unsigned int *bios_pin_configs;
+
+ /* codec specific stuff */
+ struct hda_verb *init;
+@@ -110,24 +111,10 @@ static hda_nid_t stac922x_adc_nids[2] =
+ 0x06, 0x07,
+ };
+
+-static hda_nid_t stac9227_adc_nids[2] = {
+- 0x07, 0x08,
+-};
+-
+-#if 0
+-static hda_nid_t d965_2112_dac_nids[3] = {
+- 0x02, 0x03, 0x05,
+-};
+-#endif
+-
+ static hda_nid_t stac922x_mux_nids[2] = {
+ 0x12, 0x13,
+ };
+
+-static hda_nid_t stac9227_mux_nids[2] = {
+- 0x15, 0x16,
+-};
+-
+ static hda_nid_t stac927x_adc_nids[3] = {
+ 0x07, 0x08, 0x09
+ };
+@@ -136,8 +123,17 @@ static hda_nid_t stac927x_mux_nids[3] =
+ 0x15, 0x16, 0x17
+ };
+
++static hda_nid_t stac9205_adc_nids[2] = {
++ 0x12, 0x13
++};
++
++static hda_nid_t stac9205_mux_nids[2] = {
++ 0x19, 0x1a
++};
++
+ static hda_nid_t stac9200_pin_nids[8] = {
+- 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
++ 0x08, 0x09, 0x0d, 0x0e,
++ 0x0f, 0x10, 0x11, 0x12,
+ };
+
+ static hda_nid_t stac922x_pin_nids[10] = {
+@@ -151,6 +147,13 @@ static hda_nid_t stac927x_pin_nids[14] =
+ 0x14, 0x21, 0x22, 0x23,
+ };
+
++static hda_nid_t stac9205_pin_nids[12] = {
++ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
++ 0x0f, 0x14, 0x16, 0x17, 0x18,
++ 0x21, 0x22,
++
++};
++
+ static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+@@ -190,25 +193,23 @@ static struct hda_verb stac922x_core_ini
+ {}
+ };
+
+-static struct hda_verb stac9227_core_init[] = {
++static struct hda_verb d965_core_init[] = {
+ /* set master volume and direct control */
+- { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
++ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ /* unmute node 0x1b */
+ { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
++ /* select node 0x03 as DAC */
++ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {}
+ };
+
+-static struct hda_verb d965_2112_core_init[] = {
++static struct hda_verb stac927x_core_init[] = {
+ /* set master volume and direct control */
+- { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+- /* unmute node 0x1b */
+- { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+- /* select node 0x03 as DAC */
+- { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
++ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ {}
+ };
+
+-static struct hda_verb stac927x_core_init[] = {
++static struct hda_verb stac9205_core_init[] = {
+ /* set master volume and direct control */
+ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ {}
+@@ -277,6 +278,21 @@ static snd_kcontrol_new_t stac927x_mixer
+ { } /* end */
+ };
+
++static snd_kcontrol_new_t stac9205_mixer[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input Source",
++ .count = 1,
++ .info = stac92xx_mux_enum_info,
++ .get = stac92xx_mux_enum_get,
++ .put = stac92xx_mux_enum_put,
++ },
++ HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT),
++ HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT),
++ HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT),
++ { } /* end */
++};
++
+ static int stac92xx_build_controls(struct hda_codec *codec)
+ {
+ struct sigmatel_spec *spec = codec->spec;
+@@ -341,38 +357,67 @@ static unsigned int d945gtp5_pin_configs
+ 0x02a19320, 0x40000100,
+ };
+
+-static unsigned int d965_2112_pin_configs[10] = {
+- 0x0221401f, 0x40000100, 0x40000100, 0x01014011,
+- 0x01a19021, 0x01813024, 0x01452130, 0x40000100,
+- 0x02a19320, 0x40000100,
+-};
+-
+ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
+ [STAC_REF] = ref922x_pin_configs,
+ [STAC_D945GTP3] = d945gtp3_pin_configs,
+ [STAC_D945GTP5] = d945gtp5_pin_configs,
+ [STAC_MACMINI] = d945gtp5_pin_configs,
+- [STAC_D965_2112] = d965_2112_pin_configs,
+ };
+
+ static struct hda_board_config stac922x_cfg_tbl[] = {
++ { .modelname = "5stack", .config = STAC_D945GTP5 },
++ { .modelname = "3stack", .config = STAC_D945GTP3 },
+ { .modelname = "ref",
+ .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x2668, /* DFI LanParty */
+ .config = STAC_REF }, /* SigmaTel reference board */
++ /* Intel 945G based systems */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x0101,
+ .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x0202,
+- .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack, 9221 A1 */
++ .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+- .pci_subdevice = 0x0b0b,
+- .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack, 9221 A1 */
++ .pci_subdevice = 0x0606,
++ .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0601,
++ .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0111,
++ .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x1115,
++ .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x1116,
++ .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x1117,
++ .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x1118,
++ .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x1119,
++ .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x8826,
++ .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x5049,
++ .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x5055,
++ .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x5048,
++ .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0110,
++ .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+- .pci_subdevice = 0x0707,
+- .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */
+- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x0404,
+ .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+@@ -384,44 +429,214 @@ static struct hda_board_config stac922x_
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x0417,
+ .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */
++ /* Intel 945P based systems */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0b0b,
++ .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0112,
++ .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0d0d,
++ .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0909,
++ .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0505,
++ .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x0707,
++ .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */
++ /* other systems */
+ { .pci_subvendor = 0x8384,
+ .pci_subdevice = 0x7680,
+ .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */
++ {} /* terminator */
++};
++
++static unsigned int ref927x_pin_configs[14] = {
++ 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
++ 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
++ 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
++ 0x01c42190, 0x40000100,
++};
++
++static unsigned int d965_3st_pin_configs[14] = {
++ 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
++ 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
++ 0x40000100, 0x40000100, 0x40000100, 0x40000100,
++ 0x40000100, 0x40000100
++};
++
++static unsigned int d965_5st_pin_configs[14] = {
++ 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
++ 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
++ 0x40000100, 0x40000100, 0x40000100, 0x01442070,
++ 0x40000100, 0x40000100
++};
++
++static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
++ [STAC_REF] = ref927x_pin_configs,
++ [STAC_D965_3ST] = d965_3st_pin_configs,
++ [STAC_D965_5ST] = d965_5st_pin_configs,
++};
++
++static struct hda_board_config stac927x_cfg_tbl[] = {
++ { .modelname = "5stack", .config = STAC_D965_5ST },
++ { .modelname = "3stack", .config = STAC_D965_3ST },
++ { .modelname = "ref",
++ .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2668, /* DFI LanParty */
++ .config = STAC_REF }, /* SigmaTel reference board */
++ /* Intel 946 based systems */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x3d01,
++ .config = STAC_D965_3ST }, /* D946 configuration */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0xa301,
++ .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */
++ /* 965 based 3 stack systems */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2116,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2115,
++ .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2114,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2113,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x2112,
+- .config = STAC_D965_2112 },
++ .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2111,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2110,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2009,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2008,
++ .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2007,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2006,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2005,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2004,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2003,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2002,
++ .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2001,
++ .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
++ /* 965 based 5 stack systems */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2301,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2302,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2303,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
+ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+- .pci_subdevice = 0x284b,
+- .config = STAC_D965_284B },
++ .pci_subdevice = 0x2304,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2305,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2501,
++ .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2502,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2503,
++ .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
++ { .pci_subvendor = PCI_VENDOR_ID_INTEL,
++ .pci_subdevice = 0x2504,
++ .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */
+ {} /* terminator */
+ };
+
+-static unsigned int ref927x_pin_configs[14] = {
+- 0x01813122, 0x01a19021, 0x01014010, 0x01016011,
+- 0x01012012, 0x01011014, 0x40000100, 0x40000100,
+- 0x40000100, 0x40000100, 0x40000100, 0x01441030,
+- 0x01c41030, 0x40000100,
++static unsigned int ref9205_pin_configs[12] = {
++ 0x40000100, 0x40000100, 0x01016011, 0x01014010,
++ 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
++ 0x40000100, 0x40000100, 0x01441030, 0x01c41030
+ };
+
+-static unsigned int *stac927x_brd_tbl[] = {
+- ref927x_pin_configs,
++static unsigned int *stac9205_brd_tbl[] = {
++ ref9205_pin_configs,
+ };
+
+-static struct hda_board_config stac927x_cfg_tbl[] = {
++static struct hda_board_config stac9205_cfg_tbl[] = {
+ { .modelname = "ref",
+ .pci_subvendor = PCI_VENDOR_ID_INTEL,
+ .pci_subdevice = 0x2668, /* DFI LanParty */
+ .config = STAC_REF }, /* SigmaTel reference board */
++ /* Dell laptops have BIOS problem */
++ { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5,
++ .config = STAC_REF }, /* Dell Inspiron 630m */
++ { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2,
++ .config = STAC_REF }, /* Dell Latitude D620 */
++ { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb,
++ .config = STAC_REF }, /* Dell Latitude 120L */
+ {} /* terminator */
+ };
+
++static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
++{
++ int i;
++ struct sigmatel_spec *spec = codec->spec;
++
++ if (! spec->bios_pin_configs) {
++ spec->bios_pin_configs = kcalloc(spec->num_pins,
++ sizeof(*spec->bios_pin_configs), GFP_KERNEL);
++ if (! spec->bios_pin_configs)
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < spec->num_pins; i++) {
++ hda_nid_t nid = spec->pin_nids[i];
++ unsigned int pin_cfg;
++
++ pin_cfg = snd_hda_codec_read(codec, nid, 0,
++ AC_VERB_GET_CONFIG_DEFAULT, 0x00);
++ snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
++ nid, pin_cfg);
++ spec->bios_pin_configs[i] = pin_cfg;
++ }
++
++ return 0;
++}
++
+ static void stac92xx_set_config_regs(struct hda_codec *codec)
+ {
+ int i;
+ struct sigmatel_spec *spec = codec->spec;
+ unsigned int pin_cfg;
+
+- for (i=0; i < spec->num_pins; i++) {
++ if (! spec->pin_nids || ! spec->pin_configs)
++ return;
++
++ for (i = 0; i < spec->num_pins; i++) {
+ snd_hda_codec_write(codec, spec->pin_nids[i], 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+ spec->pin_configs[i] & 0x000000ff);
+@@ -795,11 +1010,29 @@ static int stac92xx_auto_fill_dac_nids(s
+ return 0;
+ }
+
++/* create volume control/switch for the given prefx type */
++static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
++{
++ char name[32];
++ int err;
++
++ sprintf(name, "%s Playback Volume", pfx);
++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
++ HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
++ if (err < 0)
++ return err;
++ sprintf(name, "%s Playback Switch", pfx);
++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
++ HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
++ if (err < 0)
++ return err;
++ return 0;
++}
++
+ /* add playback controls from the parsed DAC table */
+ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec,
+ const struct auto_pin_cfg *cfg)
+ {
+- char name[32];
+ static const char *chname[4] = {
+ "Front", "Surround", NULL /*CLFE*/, "Side"
+ };
+@@ -814,26 +1047,15 @@ static int stac92xx_auto_create_multi_ou
+
+ if (i == 2) {
+ /* Center/LFE */
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume",
+- HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
+- return err;
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume",
+- HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
+- return err;
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch",
+- HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
++ err = create_controls(spec, "Center", nid, 1);
++ if (err < 0)
+ return err;
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch",
+- HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
++ err = create_controls(spec, "LFE", nid, 2);
++ if (err < 0)
+ return err;
+ } else {
+- sprintf(name, "%s Playback Volume", chname[i]);
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+- return err;
+- sprintf(name, "%s Playback Switch", chname[i]);
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
++ err = create_controls(spec, chname[i], nid, 3);
++ if (err < 0)
+ return err;
+ }
+ }
+@@ -849,39 +1071,85 @@ static int stac92xx_auto_create_multi_ou
+ return 0;
+ }
+
+-/* add playback controls for HP output */
+-static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg)
++static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+ {
+- struct sigmatel_spec *spec = codec->spec;
+- hda_nid_t pin = cfg->hp_pin;
+- hda_nid_t nid;
+- int i, err;
+- unsigned int wid_caps;
++ int i;
+
+- if (! pin)
+- return 0;
++ for (i = 0; i < spec->multiout.num_dacs; i++) {
++ if (spec->multiout.dac_nids[i] == nid)
++ return 1;
++ }
++ if (spec->multiout.hp_nid == nid)
++ return 1;
++ return 0;
++}
+
+- wid_caps = get_wcaps(codec, pin);
+- if (wid_caps & AC_WCAP_UNSOL_CAP)
+- spec->hp_detect = 1;
++static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
++{
++ if (!spec->multiout.hp_nid)
++ spec->multiout.hp_nid = nid;
++ else if (spec->multiout.num_dacs > 4) {
++ printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
++ return 1;
++ } else {
++ spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
++ spec->multiout.num_dacs++;
++ }
++ return 0;
++}
+
+- nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+- for (i = 0; i < cfg->line_outs; i++) {
+- if (! spec->multiout.dac_nids[i])
++/* add playback controls for Speaker and HP outputs */
++static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
++ struct auto_pin_cfg *cfg)
++{
++ struct sigmatel_spec *spec = codec->spec;
++ hda_nid_t nid;
++ int i, old_num_dacs, err;
++
++ old_num_dacs = spec->multiout.num_dacs;
++ for (i = 0; i < cfg->hp_outs; i++) {
++ unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
++ if (wid_caps & AC_WCAP_UNSOL_CAP)
++ spec->hp_detect = 1;
++ nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
++ AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
++ if (check_in_dac_nids(spec, nid))
++ nid = 0;
++ if (! nid)
+ continue;
+- if (spec->multiout.dac_nids[i] == nid)
+- return 0;
++ add_spec_dacs(spec, nid);
++ }
++ for (i = 0; i < cfg->speaker_outs; i++) {
++ nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0,
++ AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
++ if (check_in_dac_nids(spec, nid))
++ nid = 0;
++ if (check_in_dac_nids(spec, nid))
++ nid = 0;
++ if (! nid)
++ continue;
++ add_spec_dacs(spec, nid);
+ }
+
+- spec->multiout.hp_nid = nid;
+-
+- /* control HP volume/switch on the output mixer amp */
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume",
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+- return err;
+- if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+- return err;
++ for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
++ static const char *pfxs[] = {
++ "Speaker", "External Speaker", "Speaker2",
++ };
++ err = create_controls(spec, pfxs[i - old_num_dacs],
++ spec->multiout.dac_nids[i], 3);
++ if (err < 0)
++ return err;
++ }
++ if (spec->multiout.hp_nid) {
++ const char *pfx;
++ if (old_num_dacs == spec->multiout.num_dacs)
++ pfx = "Master";
++ else
++ pfx = "Headphone";
++ err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
++ if (err < 0)
++ return err;
++ }
+
+ return 0;
+ }
+@@ -895,23 +1163,28 @@ static int stac92xx_auto_create_analog_i
+ int i, j, k;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+- int index = -1;
+- if (cfg->input_pins[i]) {
+- imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
+-
+- for (j=0; j<spec->num_muxes; j++) {
+- int num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS);
+- for (k=0; k<num_cons; k++)
+- if (con_lst[k] == cfg->input_pins[i]) {
+- index = k;
+- break;
+- }
+- if (index >= 0)
+- break;
+- }
+- imux->items[imux->num_items].index = index;
+- imux->num_items++;
++ int index;
++
++ if (!cfg->input_pins[i])
++ continue;
++ index = -1;
++ for (j = 0; j < spec->num_muxes; j++) {
++ int num_cons;
++ num_cons = snd_hda_get_connections(codec,
++ spec->mux_nids[j],
++ con_lst,
++ HDA_MAX_NUM_INPUTS);
++ for (k = 0; k < num_cons; k++)
++ if (con_lst[k] == cfg->input_pins[i]) {
++ index = k;
++ goto found;
++ }
+ }
++ continue;
++ found:
++ imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
++ imux->items[imux->num_items].index = index;
++ imux->num_items++;
+ }
+
+ if (imux->num_items == 1) {
+@@ -944,11 +1217,20 @@ static void stac92xx_auto_init_multi_out
+ static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
+ {
+ struct sigmatel_spec *spec = codec->spec;
+- hda_nid_t pin;
++ int i;
+
+- pin = spec->autocfg.hp_pin;
+- if (pin) /* connect to front */
+- stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
++ for (i = 0; i < spec->autocfg.hp_outs; i++) {
++ hda_nid_t pin;
++ pin = spec->autocfg.hp_pins[i];
++ if (pin) /* connect to front */
++ stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
++ }
++ for (i = 0; i < spec->autocfg.speaker_outs; i++) {
++ hda_nid_t pin;
++ pin = spec->autocfg.speaker_pins[i];
++ if (pin) /* connect to front */
++ stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
++ }
+ }
+
+ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
+@@ -994,7 +1276,7 @@ static int stac9200_auto_create_hp_ctls(
+ struct auto_pin_cfg *cfg)
+ {
+ struct sigmatel_spec *spec = codec->spec;
+- hda_nid_t pin = cfg->hp_pin;
++ hda_nid_t pin = cfg->hp_pins[0];
+ unsigned int wid_caps;
+
+ if (! pin)
+@@ -1007,6 +1289,57 @@ static int stac9200_auto_create_hp_ctls(
+ return 0;
+ }
+
++/* add playback controls for LFE output */
++static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
++ struct auto_pin_cfg *cfg)
++{
++ struct sigmatel_spec *spec = codec->spec;
++ int err;
++ hda_nid_t lfe_pin = 0x0;
++ int i;
++
++ /*
++ * search speaker outs and line outs for a mono speaker pin
++ * with an amp. If one is found, add LFE controls
++ * for it.
++ */
++ for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
++ hda_nid_t pin = spec->autocfg.speaker_pins[i];
++ unsigned long wcaps = get_wcaps(codec, pin);
++ wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
++ if (wcaps == AC_WCAP_OUT_AMP)
++ /* found a mono speaker with an amp, must be lfe */
++ lfe_pin = pin;
++ }
++
++ /* if speaker_outs is 0, then speakers may be in line_outs */
++ if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
++ for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
++ hda_nid_t pin = spec->autocfg.line_out_pins[i];
++ unsigned long cfg;
++ cfg = snd_hda_codec_read(codec, pin, 0,
++ AC_VERB_GET_CONFIG_DEFAULT,
++ 0x00);
++ if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
++ unsigned long wcaps = get_wcaps(codec, pin);
++ wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
++ if (wcaps == AC_WCAP_OUT_AMP)
++ /* found a mono speaker with an amp,
++ must be lfe */
++ lfe_pin = pin;
++ }
++ }
++ }
++
++ if (lfe_pin) {
++ err = create_controls(spec, "LFE", lfe_pin, 1);
++ if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
+ static int stac9200_parse_auto_config(struct hda_codec *codec)
+ {
+ struct sigmatel_spec *spec = codec->spec;
+@@ -1021,6 +1354,9 @@ static int stac9200_parse_auto_config(st
+ if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
+ return err;
+
++ if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
++ return err;
++
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = 0x05;
+ if (spec->autocfg.dig_in_pin)
+@@ -1073,6 +1409,15 @@ static void stac922x_gpio_mute(struct hd
+ AC_VERB_SET_GPIO_DATA, gpiostate);
+ }
+
++static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
++ unsigned int event)
++{
++ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
++ snd_hda_codec_write(codec, nid, 0,
++ AC_VERB_SET_UNSOLICITED_ENABLE,
++ (AC_USRSP_EN | event));
++}
++
+ static int stac92xx_init(struct hda_codec *codec)
+ {
+ struct sigmatel_spec *spec = codec->spec;
+@@ -1084,9 +1429,10 @@ static int stac92xx_init(struct hda_code
+ /* set up pins */
+ if (spec->hp_detect) {
+ /* Enable unsolicited responses on the HP widget */
+- snd_hda_codec_write(codec, cfg->hp_pin, 0,
+- AC_VERB_SET_UNSOLICITED_ENABLE,
+- STAC_UNSOL_ENABLE);
++ for (i = 0; i < cfg->hp_outs; i++)
++ enable_pin_detect(codec, cfg->hp_pins[i],
++ STAC_HP_EVENT);
++ stac92xx_auto_init_hp_out(codec);
+ /* fake event to set up pins */
+ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ } else {
+@@ -1131,6 +1477,9 @@ static void stac92xx_free(struct hda_cod
+ kfree(spec->kctl_alloc);
+ }
+
++ if (spec->bios_pin_configs)
++ kfree(spec->bios_pin_configs);
++
+ kfree(spec);
+ }
+
+@@ -1139,6 +1488,8 @@ static void stac92xx_set_pinctl(struct h
+ {
+ unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
++ if (flag == AC_PINCTL_OUT_EN && (pin_ctl & AC_PINCTL_IN_EN))
++ return;
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_ctl | flag);
+@@ -1154,33 +1505,57 @@ static void stac92xx_reset_pinctl(struct
+ pin_ctl & ~flag);
+ }
+
+-static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
++static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
++{
++ if (!nid)
++ return 0;
++ if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
++ & (1 << 31))
++ return 1;
++ return 0;
++}
++
++static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
+ {
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, presence;
+
+- if ((res >> 26) != STAC_HP_EVENT)
+- return;
+-
+- presence = snd_hda_codec_read(codec, cfg->hp_pin, 0,
+- AC_VERB_GET_PIN_SENSE, 0x00) >> 31;
++ presence = 0;
++ for (i = 0; i < cfg->hp_outs; i++) {
++ presence = get_pin_presence(codec, cfg->hp_pins[i]);
++ if (presence)
++ break;
++ }
+
+ if (presence) {
+ /* disable lineouts, enable hp */
+ for (i = 0; i < cfg->line_outs; i++)
+ stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
+ AC_PINCTL_OUT_EN);
+- stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
++ for (i = 0; i < cfg->speaker_outs; i++)
++ stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
++ AC_PINCTL_OUT_EN);
+ } else {
+ /* enable lineouts, disable hp */
+ for (i = 0; i < cfg->line_outs; i++)
+ stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
+ AC_PINCTL_OUT_EN);
+- stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
++ for (i = 0; i < cfg->speaker_outs; i++)
++ stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
++ AC_PINCTL_OUT_EN);
+ }
+ }
+
++static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
++{
++ switch (res >> 26) {
++ case STAC_HP_EVENT:
++ stac92xx_hp_detect(codec, res);
++ break;
++ }
++}
++
+ #ifdef CONFIG_PM
+ static int stac92xx_resume(struct hda_codec *codec)
+ {
+@@ -1188,6 +1563,7 @@ static int stac92xx_resume(struct hda_co
+ int i;
+
+ stac92xx_init(codec);
++ stac92xx_set_config_regs(codec);
+ for (i = 0; i < spec->num_mixers; i++)
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ if (spec->multiout.dig_out_nid)
+@@ -1220,12 +1596,18 @@ static int patch_stac9200(struct hda_cod
+ return -ENOMEM;
+
+ codec->spec = spec;
++ spec->num_pins = 8;
++ spec->pin_nids = stac9200_pin_nids;
+ spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl);
+- if (spec->board_config < 0)
+- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
+- else {
+- spec->num_pins = 8;
+- spec->pin_nids = stac9200_pin_nids;
++ if (spec->board_config < 0) {
++ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
++ err = stac92xx_save_bios_config_regs(codec);
++ if (err < 0) {
++ stac92xx_free(codec);
++ return err;
++ }
++ spec->pin_configs = spec->bios_pin_configs;
++ } else {
+ spec->pin_configs = stac9200_brd_tbl[spec->board_config];
+ stac92xx_set_config_regs(codec);
+ }
+@@ -1261,13 +1643,19 @@ static int patch_stac922x(struct hda_cod
+ return -ENOMEM;
+
+ codec->spec = spec;
++ spec->num_pins = 10;
++ spec->pin_nids = stac922x_pin_nids;
+ spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
+- if (spec->board_config < 0)
+- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
+- "using BIOS defaults\n");
+- else if (stac922x_brd_tbl[spec->board_config] != NULL) {
+- spec->num_pins = 10;
+- spec->pin_nids = stac922x_pin_nids;
++ if (spec->board_config < 0) {
++ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
++ "using BIOS defaults\n");
++ err = stac92xx_save_bios_config_regs(codec);
++ if (err < 0) {
++ stac92xx_free(codec);
++ return err;
++ }
++ spec->pin_configs = spec->bios_pin_configs;
++ } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
+ spec->pin_configs = stac922x_brd_tbl[spec->board_config];
+ stac92xx_set_config_regs(codec);
+ }
+@@ -1281,25 +1669,6 @@ static int patch_stac922x(struct hda_cod
+
+ spec->multiout.dac_nids = spec->dac_nids;
+
+- switch (spec->board_config) {
+- case STAC_D965_2112:
+- spec->adc_nids = stac9227_adc_nids;
+- spec->mux_nids = stac9227_mux_nids;
+-#if 0
+- spec->multiout.dac_nids = d965_2112_dac_nids;
+- spec->multiout.num_dacs = ARRAY_SIZE(d965_2112_dac_nids);
+-#endif
+- spec->init = d965_2112_core_init;
+- spec->mixer = stac9227_mixer;
+- break;
+- case STAC_D965_284B:
+- spec->adc_nids = stac9227_adc_nids;
+- spec->mux_nids = stac9227_mux_nids;
+- spec->init = stac9227_core_init;
+- spec->mixer = stac9227_mixer;
+- break;
+- }
+-
+ err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
+ if (err < 0) {
+ stac92xx_free(codec);
+@@ -1324,26 +1693,94 @@ static int patch_stac927x(struct hda_cod
+ return -ENOMEM;
+
+ codec->spec = spec;
++ spec->num_pins = 14;
++ spec->pin_nids = stac927x_pin_nids;
+ spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl);
+- if (spec->board_config < 0)
++ if (spec->board_config < 0) {
+ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
+- else {
+- spec->num_pins = 14;
+- spec->pin_nids = stac927x_pin_nids;
++ err = stac92xx_save_bios_config_regs(codec);
++ if (err < 0) {
++ stac92xx_free(codec);
++ return err;
++ }
++ spec->pin_configs = spec->bios_pin_configs;
++ } else if (stac927x_brd_tbl[spec->board_config] != NULL) {
+ spec->pin_configs = stac927x_brd_tbl[spec->board_config];
+ stac92xx_set_config_regs(codec);
+ }
+
+- spec->adc_nids = stac927x_adc_nids;
+- spec->mux_nids = stac927x_mux_nids;
++ switch (spec->board_config) {
++ case STAC_D965_3ST:
++ spec->adc_nids = stac927x_adc_nids;
++ spec->mux_nids = stac927x_mux_nids;
++ spec->num_muxes = 3;
++ spec->init = d965_core_init;
++ spec->mixer = stac9227_mixer;
++ break;
++ case STAC_D965_5ST:
++ spec->adc_nids = stac927x_adc_nids;
++ spec->mux_nids = stac927x_mux_nids;
++ spec->num_muxes = 3;
++ spec->init = d965_core_init;
++ spec->mixer = stac9227_mixer;
++ break;
++ default:
++ spec->adc_nids = stac927x_adc_nids;
++ spec->mux_nids = stac927x_mux_nids;
++ spec->num_muxes = 3;
++ spec->init = stac927x_core_init;
++ spec->mixer = stac927x_mixer;
++ }
++
++ spec->multiout.dac_nids = spec->dac_nids;
++
++ err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
++ if (err < 0) {
++ stac92xx_free(codec);
++ return err;
++ }
++
++ codec->patch_ops = stac92xx_patch_ops;
++
++ return 0;
++}
++
++static int patch_stac9205(struct hda_codec *codec)
++{
++ struct sigmatel_spec *spec;
++ int err;
++
++ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
++ if (spec == NULL)
++ return -ENOMEM;
++
++ codec->spec = spec;
++ spec->num_pins = 14;
++ spec->pin_nids = stac9205_pin_nids;
++ spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl);
++ if (spec->board_config < 0) {
++ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
++ err = stac92xx_save_bios_config_regs(codec);
++ if (err < 0) {
++ stac92xx_free(codec);
++ return err;
++ }
++ spec->pin_configs = spec->bios_pin_configs;
++ } else {
++ spec->pin_configs = stac9205_brd_tbl[spec->board_config];
++ stac92xx_set_config_regs(codec);
++ }
++
++ spec->adc_nids = stac9205_adc_nids;
++ spec->mux_nids = stac9205_mux_nids;
+ spec->num_muxes = 3;
+
+- spec->init = stac927x_core_init;
+- spec->mixer = stac927x_mixer;
++ spec->init = stac9205_core_init;
++ spec->mixer = stac9205_mixer;
+
+ spec->multiout.dac_nids = spec->dac_nids;
+
+- err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
++ err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+@@ -1355,10 +1792,10 @@ static int patch_stac927x(struct hda_cod
+ }
+
+ /*
+- * STAC 7661(?) hack
++ * STAC9872 hack
+ */
+
+-/* static config for Sony VAIO FE550G */
++/* static config for Sony VAIO FE550G and Sony VAIO AR */
+ static hda_nid_t vaio_dacs[] = { 0x2 };
+ #define VAIO_HP_DAC 0x5
+ static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
+@@ -1389,6 +1826,23 @@ static struct hda_verb vaio_init[] = {
+ {}
+ };
+
++static struct hda_verb vaio_ar_init[] = {
++ {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
++ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
++ {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
++ {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
++/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
++ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
++ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
++ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
++/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
++ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
++ {}
++};
++
+ /* bind volumes of both NID 0x02 and 0x05 */
+ static int vaio_master_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+@@ -1434,6 +1888,38 @@ static struct snd_kcontrol_new vaio_mixe
+ .info = snd_hda_mixer_amp_volume_info,
+ .get = snd_hda_mixer_amp_volume_get,
+ .put = vaio_master_vol_put,
++ .tlv = { .c = snd_hda_mixer_amp_tlv },
++ .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Master Playback Switch",
++ .info = snd_hda_mixer_amp_switch_info,
++ .get = snd_hda_mixer_amp_switch_get,
++ .put = vaio_master_sw_put,
++ .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
++ },
++ /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Capture Source",
++ .count = 1,
++ .info = stac92xx_mux_enum_info,
++ .get = stac92xx_mux_enum_get,
++ .put = stac92xx_mux_enum_put,
++ },
++ {}
++};
++
++static struct snd_kcontrol_new vaio_ar_mixer[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Master Playback Volume",
++ .info = snd_hda_mixer_amp_volume_info,
++ .get = snd_hda_mixer_amp_volume_get,
++ .put = vaio_master_vol_put,
+ .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+ },
+ {
+@@ -1447,6 +1933,8 @@ static struct snd_kcontrol_new vaio_mixe
+ /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
++ /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
++ HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+@@ -1458,7 +1946,7 @@ static struct snd_kcontrol_new vaio_mixe
+ {}
+ };
+
+-static struct hda_codec_ops stac7661_patch_ops = {
++static struct hda_codec_ops stac9872_patch_ops = {
+ .build_controls = stac92xx_build_controls,
+ .build_pcms = stac92xx_build_pcms,
+ .init = stac92xx_init,
+@@ -1468,23 +1956,34 @@ static struct hda_codec_ops stac7661_pat
+ #endif
+ };
+
+-enum { STAC7661_VAIO };
+-
+-static struct hda_board_config stac7661_cfg_tbl[] = {
+- { .modelname = "vaio", .config = STAC7661_VAIO },
++enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
++ CXD9872RD_VAIO,
++ /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
++ STAC9872AK_VAIO,
++ /* Unknown. id=0x83847661 and subsys=0x104D1200. */
++ STAC9872K_VAIO,
++ /* AR Series. id=0x83847664 and subsys=104D1300 */
++ CXD9872AKD_VAIO
++ };
++
++static struct hda_board_config stac9872_cfg_tbl[] = {
++ { .modelname = "vaio", .config = CXD9872RD_VAIO },
++ { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO },
+ { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6,
+- .config = STAC7661_VAIO },
++ .config = CXD9872RD_VAIO },
+ { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef,
+- .config = STAC7661_VAIO },
++ .config = CXD9872RD_VAIO },
++ { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd,
++ .config = CXD9872AKD_VAIO },
+ {}
+ };
+
+-static int patch_stac7661(struct hda_codec *codec)
++static int patch_stac9872(struct hda_codec *codec)
+ {
+ struct sigmatel_spec *spec;
+ int board_config;
+
+- board_config = snd_hda_check_board_config(codec, stac7661_cfg_tbl);
++ board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl);
+ if (board_config < 0)
+ /* unknown config, let generic-parser do its job... */
+ return snd_hda_parse_generic_codec(codec);
+@@ -1495,7 +1994,9 @@ static int patch_stac7661(struct hda_cod
+
+ codec->spec = spec;
+ switch (board_config) {
+- case STAC7661_VAIO:
++ case CXD9872RD_VAIO:
++ case STAC9872AK_VAIO:
++ case STAC9872K_VAIO:
+ spec->mixer = vaio_mixer;
+ spec->init = vaio_init;
+ spec->multiout.max_channels = 2;
+@@ -1507,9 +2008,22 @@ static int patch_stac7661(struct hda_cod
+ spec->input_mux = &vaio_mux;
+ spec->mux_nids = vaio_mux_nids;
+ break;
++
++ case CXD9872AKD_VAIO:
++ spec->mixer = vaio_ar_mixer;
++ spec->init = vaio_ar_init;
++ spec->multiout.max_channels = 2;
++ spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
++ spec->multiout.dac_nids = vaio_dacs;
++ spec->multiout.hp_nid = VAIO_HP_DAC;
++ spec->num_adcs = ARRAY_SIZE(vaio_adcs);
++ spec->adc_nids = vaio_adcs;
++ spec->input_mux = &vaio_mux;
++ spec->mux_nids = vaio_mux_nids;
++ break;
+ }
+
+- codec->patch_ops = stac7661_patch_ops;
++ codec->patch_ops = stac9872_patch_ops;
+ return 0;
+ }
+
+@@ -1525,12 +2039,12 @@ struct hda_codec_preset snd_hda_preset_s
+ { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
+ { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
+ { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
+- { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac922x },
+- { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac922x },
+- { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac922x },
+- { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac922x },
+- { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac922x },
+- { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac922x },
++ { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
++ { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
++ { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
++ { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
++ { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
++ { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
+ { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
+ { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
+ { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
+@@ -1541,6 +2055,20 @@ struct hda_codec_preset snd_hda_preset_s
+ { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
+ { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
+ { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
+- { .id = 0x83847661, .name = "STAC7661", .patch = patch_stac7661 },
++ /* The following does not take into account .id=0x83847661 when subsys =
++ * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
++ * currently not fully supported.
++ */
++ { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
++ { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
++ { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
++ { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
++ { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
++ { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
++ { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
++ { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
++ { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
++ { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
++ { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
+ {} /* terminator */
+ };
+diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
+index 9492f3d..9e76ceb 100644
+--- a/sound/pci/ice1712/aureon.c
++++ b/sound/pci/ice1712/aureon.c
+@@ -60,6 +60,7 @@
+ #include "ice1712.h"
+ #include "envy24ht.h"
+ #include "aureon.h"
++#include <sound/tlv.h>
+
+ /* WM8770 registers */
+ #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
+@@ -660,6 +661,12 @@ static int aureon_ac97_mmute_put(struct
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
++static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
++static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
++
+ /*
+ * Logarithmic volume values for WM8770
+ * Computed as 20 * Log10(255 / x)
+@@ -1409,10 +1416,13 @@ static struct snd_kcontrol_new aureon_da
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Master Playback Volume",
+ .info = wm_master_vol_info,
+ .get = wm_master_vol_get,
+- .put = wm_master_vol_put
++ .put = wm_master_vol_put,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1424,11 +1434,14 @@ static struct snd_kcontrol_new aureon_da
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Front Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (2 << 8) | 0
++ .private_value = (2 << 8) | 0,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1440,11 +1453,14 @@ static struct snd_kcontrol_new aureon_da
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Rear Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (2 << 8) | 2
++ .private_value = (2 << 8) | 2,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1456,11 +1472,14 @@ static struct snd_kcontrol_new aureon_da
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Center Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (1 << 8) | 4
++ .private_value = (1 << 8) | 4,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1472,11 +1491,14 @@ static struct snd_kcontrol_new aureon_da
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "LFE Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (1 << 8) | 5
++ .private_value = (1 << 8) | 5,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1488,11 +1510,14 @@ static struct snd_kcontrol_new aureon_da
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Side Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (2 << 8) | 6
++ .private_value = (2 << 8) | 6,
++ .tlv = { .p = db_scale_wm_dac }
+ }
+ };
+
+@@ -1506,10 +1531,13 @@ static struct snd_kcontrol_new wm_contro
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "PCM Playback Volume",
+ .info = wm_pcm_vol_info,
+ .get = wm_pcm_vol_get,
+- .put = wm_pcm_vol_put
++ .put = wm_pcm_vol_put,
++ .tlv = { .p = db_scale_wm_pcm }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1520,10 +1548,13 @@ static struct snd_kcontrol_new wm_contro
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Capture Volume",
+ .info = wm_adc_vol_info,
+ .get = wm_adc_vol_get,
+- .put = wm_adc_vol_put
++ .put = wm_adc_vol_put,
++ .tlv = { .p = db_scale_wm_adc }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1567,11 +1598,14 @@ static struct snd_kcontrol_new ac97_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "AC97 Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_MASTER|AUREON_AC97_STEREO
++ .private_value = AC97_MASTER|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_master }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1583,11 +1617,14 @@ static struct snd_kcontrol_new ac97_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "CD Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_CD|AUREON_AC97_STEREO
++ .private_value = AC97_CD|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1599,11 +1636,14 @@ static struct snd_kcontrol_new ac97_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Aux Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_AUX|AUREON_AC97_STEREO
++ .private_value = AC97_AUX|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1615,11 +1655,14 @@ static struct snd_kcontrol_new ac97_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Line Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_LINE|AUREON_AC97_STEREO
++ .private_value = AC97_LINE|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1631,11 +1674,14 @@ static struct snd_kcontrol_new ac97_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Mic Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_MIC
++ .private_value = AC97_MIC,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1657,11 +1703,14 @@ static struct snd_kcontrol_new universe_
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "AC97 Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_MASTER|AUREON_AC97_STEREO
++ .private_value = AC97_MASTER|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_master }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1673,11 +1722,14 @@ static struct snd_kcontrol_new universe_
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "CD Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_AUX|AUREON_AC97_STEREO
++ .private_value = AC97_AUX|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1685,15 +1737,18 @@ static struct snd_kcontrol_new universe_
+ .info = aureon_ac97_mute_info,
+ .get = aureon_ac97_mute_get,
+ .put = aureon_ac97_mute_put,
+- .private_value = AC97_CD,
++ .private_value = AC97_CD
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Phono Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_CD|AUREON_AC97_STEREO
++ .private_value = AC97_CD|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1705,11 +1760,14 @@ static struct snd_kcontrol_new universe_
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Line Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_LINE|AUREON_AC97_STEREO
++ .private_value = AC97_LINE|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1721,11 +1779,14 @@ static struct snd_kcontrol_new universe_
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Mic Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_MIC
++ .private_value = AC97_MIC,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -1744,11 +1805,14 @@ static struct snd_kcontrol_new universe_
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Aux Playback Volume",
+ .info = aureon_ac97_vol_info,
+ .get = aureon_ac97_vol_get,
+ .put = aureon_ac97_vol_put,
+- .private_value = AC97_VIDEO|AUREON_AC97_STEREO
++ .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
++ .tlv = { .p = db_scale_ac97_gain }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
+index bf20858..8a576b7 100644
+--- a/sound/pci/ice1712/ice1712.c
++++ b/sound/pci/ice1712/ice1712.c
+@@ -62,6 +62,7 @@
+ #include <sound/cs8427.h>
+ #include <sound/info.h>
+ #include <sound/initval.h>
++#include <sound/tlv.h>
+
+ #include <sound/asoundef.h>
+
+@@ -419,7 +420,7 @@ static void snd_ice1712_set_input_clock_
+ * Interrupt handler
+ */
+
+-static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
+ {
+ struct snd_ice1712 *ice = dev_id;
+ unsigned char status;
+@@ -432,7 +433,7 @@ static irqreturn_t snd_ice1712_interrupt
+ handled = 1;
+ if (status & ICE1712_IRQ_MPU1) {
+ if (ice->rmidi[0])
+- snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
+ outb(ICE1712_IRQ_MPU1, ICEREG(ice, IRQSTAT));
+ status &= ~ICE1712_IRQ_MPU1;
+ }
+@@ -440,7 +441,7 @@ static irqreturn_t snd_ice1712_interrupt
+ outb(ICE1712_IRQ_TIMER, ICEREG(ice, IRQSTAT));
+ if (status & ICE1712_IRQ_MPU2) {
+ if (ice->rmidi[1])
+- snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data);
+ outb(ICE1712_IRQ_MPU2, ICEREG(ice, IRQSTAT));
+ status &= ~ICE1712_IRQ_MPU2;
+ }
+@@ -1377,6 +1378,7 @@ static int snd_ice1712_pro_mixer_volume_
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
+
+ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
+ {
+@@ -1390,12 +1392,15 @@ static struct snd_kcontrol_new snd_ice17
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Multi Playback Volume",
+ .info = snd_ice1712_pro_mixer_volume_info,
+ .get = snd_ice1712_pro_mixer_volume_get,
+ .put = snd_ice1712_pro_mixer_volume_put,
+ .private_value = 0,
+ .count = 10,
++ .tlv = { .p = db_scale_playback }
+ },
+ };
+
+@@ -1420,11 +1425,14 @@ static struct snd_kcontrol_new snd_ice17
+
+ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "H/W Multi Capture Volume",
+ .info = snd_ice1712_pro_mixer_volume_info,
+ .get = snd_ice1712_pro_mixer_volume_get,
+ .put = snd_ice1712_pro_mixer_volume_put,
+ .private_value = 10,
++ .tlv = { .p = db_scale_playback }
+ };
+
+ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
+@@ -1857,7 +1865,7 @@ static int snd_ice1712_pro_internal_cloc
+ {
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ static unsigned int xrate[13] = {
+- 8000, 9600, 11025, 12000, 1600, 22050, 24000,
++ 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000
+ };
+ unsigned char oval;
+@@ -1924,7 +1932,7 @@ static int snd_ice1712_pro_internal_cloc
+ {
+ int val;
+ static unsigned int xrate[13] = {
+- 8000, 9600, 11025, 12000, 1600, 22050, 24000,
++ 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000
+ };
+
+@@ -1941,7 +1949,7 @@ static int snd_ice1712_pro_internal_cloc
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ static unsigned int xrate[13] = {
+- 8000, 9600, 11025, 12000, 1600, 22050, 24000,
++ 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000
+ };
+ unsigned char oval;
+diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
+index 71d6aed..e9cbfdf 100644
+--- a/sound/pci/ice1712/ice1724.c
++++ b/sound/pci/ice1712/ice1724.c
+@@ -218,7 +218,7 @@ static unsigned int snd_vt1724_get_gpio_
+ * Interrupt handler
+ */
+
+-static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
+ {
+ struct snd_ice1712 *ice = dev_id;
+ unsigned char status;
+@@ -236,7 +236,7 @@ static irqreturn_t snd_vt1724_interrupt(
+ */
+ if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) {
+ if (ice->rmidi[0])
+- snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
+ outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT));
+ status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
+ }
+diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
+index 502da1c..e08d73f 100644
+--- a/sound/pci/ice1712/phase.c
++++ b/sound/pci/ice1712/phase.c
+@@ -46,6 +46,7 @@
+ #include "ice1712.h"
+ #include "envy24ht.h"
+ #include "phase.h"
++#include <sound/tlv.h>
+
+ /* WM8770 registers */
+ #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
+@@ -696,6 +697,9 @@ static int phase28_oversampling_put(stru
+ return 0;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
++static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
++
+ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -706,10 +710,13 @@ static struct snd_kcontrol_new phase28_d
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Master Playback Volume",
+ .info = wm_master_vol_info,
+ .get = wm_master_vol_get,
+- .put = wm_master_vol_put
++ .put = wm_master_vol_put,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -721,11 +728,14 @@ static struct snd_kcontrol_new phase28_d
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Front Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (2 << 8) | 0
++ .private_value = (2 << 8) | 0,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -737,11 +747,14 @@ static struct snd_kcontrol_new phase28_d
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Rear Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (2 << 8) | 2
++ .private_value = (2 << 8) | 2,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -753,11 +766,14 @@ static struct snd_kcontrol_new phase28_d
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Center Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (1 << 8) | 4
++ .private_value = (1 << 8) | 4,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -769,11 +785,14 @@ static struct snd_kcontrol_new phase28_d
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "LFE Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (1 << 8) | 5
++ .private_value = (1 << 8) | 5,
++ .tlv = { .p = db_scale_wm_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -785,11 +804,14 @@ static struct snd_kcontrol_new phase28_d
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Side Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+- .private_value = (2 << 8) | 6
++ .private_value = (2 << 8) | 6,
++ .tlv = { .p = db_scale_wm_dac }
+ }
+ };
+
+@@ -803,10 +825,13 @@ static struct snd_kcontrol_new wm_contro
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "PCM Playback Volume",
+ .info = wm_pcm_vol_info,
+ .get = wm_pcm_vol_get,
+- .put = wm_pcm_vol_put
++ .put = wm_pcm_vol_put,
++ .tlv = { .p = db_scale_wm_pcm }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
+index 0efcad9..6c74c2d 100644
+--- a/sound/pci/ice1712/pontis.c
++++ b/sound/pci/ice1712/pontis.c
+@@ -31,6 +31,7 @@
+
+ #include <sound/core.h>
+ #include <sound/info.h>
++#include <sound/tlv.h>
+
+ #include "ice1712.h"
+ #include "envy24ht.h"
+@@ -564,6 +565,8 @@ static int pontis_gpio_data_put(struct s
+ return changed;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
++
+ /*
+ * mixers
+ */
+@@ -571,17 +574,23 @@ static int pontis_gpio_data_put(struct s
+ static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "PCM Playback Volume",
+ .info = wm_dac_vol_info,
+ .get = wm_dac_vol_get,
+ .put = wm_dac_vol_put,
++ .tlv = { .p = db_scale_volume },
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Capture Volume",
+ .info = wm_adc_vol_info,
+ .get = wm_adc_vol_get,
+ .put = wm_adc_vol_put,
++ .tlv = { .p = db_scale_volume },
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
+index fdb5cb8..41b2605 100644
+--- a/sound/pci/ice1712/prodigy192.c
++++ b/sound/pci/ice1712/prodigy192.c
+@@ -35,6 +35,7 @@
+ #include "envy24ht.h"
+ #include "prodigy192.h"
+ #include "stac946x.h"
++#include <sound/tlv.h>
+
+ static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val)
+ {
+@@ -356,6 +357,9 @@ static int aureon_oversampling_put(struc
+ }
+ #endif
+
++static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
++
+ /*
+ * mixers
+ */
+@@ -368,14 +372,18 @@ static struct snd_kcontrol_new stac_cont
+ .get = stac9460_dac_mute_get,
+ .put = stac9460_dac_mute_put,
+ .private_value = 1,
++ .tlv = { .p = db_scale_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Master Playback Volume",
+ .info = stac9460_dac_vol_info,
+ .get = stac9460_dac_vol_get,
+ .put = stac9460_dac_vol_put,
+ .private_value = 1,
++ .tlv = { .p = db_scale_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -387,11 +395,14 @@ static struct snd_kcontrol_new stac_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "DAC Volume",
+ .count = 6,
+ .info = stac9460_dac_vol_info,
+ .get = stac9460_dac_vol_get,
+ .put = stac9460_dac_vol_put,
++ .tlv = { .p = db_scale_dac }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -404,11 +415,14 @@ static struct snd_kcontrol_new stac_cont
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "ADC Volume",
+ .count = 1,
+ .info = stac9460_adc_vol_info,
+ .get = stac9460_adc_vol_get,
+ .put = stac9460_adc_vol_put,
++ .tlv = { .p = db_scale_adc }
+ },
+ #if 0
+ {
+diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
+index fec9440..bf98ea3 100644
+--- a/sound/pci/ice1712/revo.c
++++ b/sound/pci/ice1712/revo.c
+@@ -87,16 +87,33 @@ static void revo_set_rate_val(struct snd
+ * initialize the chips on M-Audio Revolution cards
+ */
+
+-static unsigned int revo71_num_stereo_front[] = {2};
+-static char *revo71_channel_names_front[] = {"PCM Playback Volume"};
++#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
+
+-static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2};
+-static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume",
+- "PCM Side Playback Volume", "PCM Rear Playback Volume"};
++static struct snd_akm4xxx_dac_channel revo71_front[] = {
++ AK_DAC("PCM Playback Volume", 2)
++};
++
++static struct snd_akm4xxx_dac_channel revo71_surround[] = {
++ AK_DAC("PCM Center Playback Volume", 1),
++ AK_DAC("PCM LFE Playback Volume", 1),
++ AK_DAC("PCM Side Playback Volume", 2),
++ AK_DAC("PCM Rear Playback Volume", 2),
++};
+
+-static unsigned int revo51_num_stereo[] = {2, 1, 1, 2};
+-static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume",
+- "PCM LFE Playback Volume", "PCM Rear Playback Volume"};
++static struct snd_akm4xxx_dac_channel revo51_dac[] = {
++ AK_DAC("PCM Playback Volume", 2),
++ AK_DAC("PCM Center Playback Volume", 1),
++ AK_DAC("PCM LFE Playback Volume", 1),
++ AK_DAC("PCM Rear Playback Volume", 2),
++};
++
++static struct snd_akm4xxx_adc_channel revo51_adc[] = {
++ {
++ .name = "PCM Capture Volume",
++ .switch_name = "PCM Capture Switch",
++ .num_channels = 2
++ },
++};
+
+ static struct snd_akm4xxx akm_revo_front __devinitdata = {
+ .type = SND_AK4381,
+@@ -104,8 +121,7 @@ static struct snd_akm4xxx akm_revo_front
+ .ops = {
+ .set_rate_val = revo_set_rate_val
+ },
+- .num_stereo = revo71_num_stereo_front,
+- .channel_names = revo71_channel_names_front
++ .dac_info = revo71_front,
+ };
+
+ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
+@@ -127,8 +143,7 @@ static struct snd_akm4xxx akm_revo_surro
+ .ops = {
+ .set_rate_val = revo_set_rate_val
+ },
+- .num_stereo = revo71_num_stereo_surround,
+- .channel_names = revo71_channel_names_surround
++ .dac_info = revo71_surround,
+ };
+
+ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
+@@ -149,8 +164,7 @@ static struct snd_akm4xxx akm_revo51 __d
+ .ops = {
+ .set_rate_val = revo_set_rate_val
+ },
+- .num_stereo = revo51_num_stereo,
+- .channel_names = revo51_channel_names
++ .dac_info = revo51_dac,
+ };
+
+ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
+@@ -159,7 +173,25 @@ static struct snd_ak4xxx_private akm_rev
+ .data_mask = VT1724_REVO_CDOUT,
+ .clk_mask = VT1724_REVO_CCLK,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+- .cs_addr = 0,
++ .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2,
++ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
++ .add_flags = VT1724_REVO_CCLK, /* high at init */
++ .mask_flags = 0,
++};
++
++static struct snd_akm4xxx akm_revo51_adc __devinitdata = {
++ .type = SND_AK5365,
++ .num_adcs = 2,
++ .adc_info = revo51_adc,
++};
++
++static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
++ .caddr = 2,
++ .cif = 0,
++ .data_mask = VT1724_REVO_CDOUT,
++ .clk_mask = VT1724_REVO_CCLK,
++ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
++ .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .add_flags = VT1724_REVO_CCLK, /* high at init */
+ .mask_flags = 0,
+@@ -202,9 +234,13 @@ static int __devinit revo_init(struct sn
+ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+ break;
+ case VT1724_SUBDEVICE_REVOLUTION51:
+- ice->akm_codecs = 1;
++ ice->akm_codecs = 2;
+ if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
+ return err;
++ err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc,
++ &akm_revo51_adc_priv, ice);
++ if (err < 0)
++ return err;
+ /* unmute all codecs - needed! */
+ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+ break;
+diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h
+index dea52ea..efbb86e 100644
+--- a/sound/pci/ice1712/revo.h
++++ b/sound/pci/ice1712/revo.h
+@@ -42,7 +42,7 @@ extern struct snd_ice1712_card_info snd_
+ #define VT1724_REVO_CCLK 0x02
+ #define VT1724_REVO_CDIN 0x04 /* not used */
+ #define VT1724_REVO_CDOUT 0x08
+-#define VT1724_REVO_CS0 0x10 /* not used */
++#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */
+ #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */
+ #define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */
+ #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */
+diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
+index 6874263..9c1bce7 100644
+--- a/sound/pci/intel8x0.c
++++ b/sound/pci/intel8x0.c
+@@ -801,7 +801,7 @@ static inline void snd_intel8x0_update(s
+ status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI));
+ }
+
+-static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
+ {
+ struct intel8x0 *chip = dev_id;
+ struct ichdev *ichdev;
+@@ -1962,6 +1962,12 @@ static struct ac97_quirk ac97_quirks[] _
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
++ .subvendor = 0x10f7,
++ .subdevice = 0x834c,
++ .name = "Panasonic CF-R4",
++ .type = AC97_TUNE_HP_ONLY,
++ },
++ {
+ .subvendor = 0x110a,
+ .subdevice = 0x0056,
+ .name = "Fujitsu-Siemens Scenic", /* AD1981? */
+@@ -2251,6 +2257,16 @@ static int snd_intel8x0_ich_chip_init(st
+ /* ACLink on, 2 channels */
+ cnt = igetdword(chip, ICHREG(GLOB_CNT));
+ cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
++#ifdef CONFIG_SND_AC97_POWER_SAVE
++ /* do cold reset - the full ac97 powerdown may leave the controller
++ * in a warm state but actually it cannot communicate with the codec.
++ */
++ iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD);
++ cnt = igetdword(chip, ICHREG(GLOB_CNT));
++ udelay(10);
++ iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
++ msleep(1);
++#else
+ /* finish cold or do warm reset */
+ cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
+ iputdword(chip, ICHREG(GLOB_CNT), cnt);
+@@ -2265,6 +2281,7 @@ static int snd_intel8x0_ich_chip_init(st
+ return -EIO;
+
+ __ok:
++#endif
+ if (probing) {
+ /* wait for any codec ready status.
+ * Once it becomes ready it should remain ready
+@@ -2465,10 +2482,14 @@ static int intel8x0_suspend(struct pci_d
+ if (chip->device_type == DEVICE_INTEL_ICH4)
+ chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
+
+- if (chip->irq >= 0)
++ if (chip->irq >= 0) {
++ synchronize_irq(chip->irq);
+ free_irq(chip->irq, chip);
++ chip->irq = -1;
++ }
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2478,14 +2499,25 @@ static int intel8x0_resume(struct pci_de
+ struct intel8x0 *chip = card->private_data;
+ int i;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "intel8x0: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+- request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_DISABLED|IRQF_SHARED,
+- card->shortname, chip);
++ if (request_irq(pci->irq, snd_intel8x0_interrupt,
++ IRQF_DISABLED|IRQF_SHARED, card->shortname, chip)) {
++ printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
++ "disabling device\n", pci->irq);
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ chip->irq = pci->irq;
+ synchronize_irq(chip->irq);
+- snd_intel8x0_chip_init(chip, 1);
++ snd_intel8x0_chip_init(chip, 0);
+
+ /* re-initialize mixer stuff */
+ if (chip->device_type == DEVICE_INTEL_ICH4) {
+@@ -2615,6 +2647,7 @@ static void __devinit intel8x0_measure_a
+ /* not 48000Hz, tuning the clock.. */
+ chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
+ printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
++ snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
+ }
+
+ #ifdef CONFIG_PROC_FS
+diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
+index 9185028..bd467c5 100644
+--- a/sound/pci/intel8x0m.c
++++ b/sound/pci/intel8x0m.c
+@@ -511,7 +511,7 @@ static inline void snd_intel8x0_update(s
+ iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+ }
+
+-static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
+ {
+ struct intel8x0m *chip = dev_id;
+ struct ichdev *ichdev;
+@@ -1045,8 +1045,14 @@ static int intel8x0m_suspend(struct pci_
+ for (i = 0; i < chip->pcm_devs; i++)
+ snd_pcm_suspend_all(chip->pcm[i]);
+ snd_ac97_suspend(chip->ac97);
++ if (chip->irq >= 0) {
++ synchronize_irq(chip->irq);
++ free_irq(chip->irq, chip);
++ chip->irq = -1;
++ }
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1055,9 +1061,23 @@ static int intel8x0m_resume(struct pci_d
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct intel8x0m *chip = card->private_data;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "intel8x0m: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
++ if (request_irq(pci->irq, snd_intel8x0_interrupt,
++ IRQF_DISABLED|IRQF_SHARED, card->shortname, chip)) {
++ printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
++ "disabling device\n", pci->irq);
++ snd_card_disconnect(card);
++ return -EIO;
++ }
++ chip->irq = pci->irq;
+ snd_intel8x0_chip_init(chip, 0);
+ snd_ac97_resume(chip->ac97);
+
+diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
+index cfea51f..fa8cd8c 100644
+--- a/sound/pci/korg1212/korg1212.c
++++ b/sound/pci/korg1212/korg1212.c
+@@ -1119,14 +1119,11 @@ static void snd_korg1212_OnDSPDownloadCo
+ snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_COMPLETE);
+ }
+
+-static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id)
+ {
+ u32 doorbellValue;
+ struct snd_korg1212 *korg1212 = dev_id;
+
+- if(irq != korg1212->irq)
+- return IRQ_NONE;
+-
+ doorbellValue = readl(korg1212->inDoorbellPtr);
+
+ if (!doorbellValue)
+@@ -1140,7 +1137,6 @@ static irqreturn_t snd_korg1212_interrup
+
+ korg1212->inIRQ++;
+
+-
+ switch (doorbellValue) {
+ case K1212_DB_DSPDownloadDone:
+ K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DNLD count - %ld, %x, [%s].\n",
+diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
+index 45214b3..8cab342 100644
+--- a/sound/pci/maestro3.c
++++ b/sound/pci/maestro3.c
+@@ -1685,8 +1685,7 @@ static void snd_m3_update_hw_volume(unsi
+ spin_unlock_irqrestore(&chip->ac97_lock, flags);
+ }
+
+-static irqreturn_t
+-snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
+ {
+ struct snd_m3 *chip = dev_id;
+ u8 status;
+@@ -2590,12 +2589,9 @@ static int m3_suspend(struct pci_dev *pc
+ chip->suspend_mem[index++] =
+ snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i);
+
+- /* power down apci registers */
+- snd_m3_outw(chip, 0xffff, 0x54);
+- snd_m3_outw(chip, 0xffff, 0x56);
+-
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2608,8 +2604,14 @@ static int m3_resume(struct pci_dev *pci
+ if (chip->suspend_mem == NULL)
+ return 0;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "maestor3: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ /* first lets just bring everything back. .*/
+diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
+index cc43ecd..216aee5 100644
+--- a/sound/pci/mixart/mixart.c
++++ b/sound/pci/mixart/mixart.c
+@@ -1109,13 +1109,13 @@ static long long snd_mixart_BA0_llseek(s
+ offset = offset & ~3; /* 4 bytes aligned */
+
+ switch(orig) {
+- case 0: /* SEEK_SET */
++ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+- case 1: /* SEEK_CUR */
++ case SEEK_CUR:
+ file->f_pos += offset;
+ break;
+- case 2: /* SEEK_END, offset is negative */
++ case SEEK_END: /* offset is negative */
+ file->f_pos = MIXART_BA0_SIZE + offset;
+ break;
+ default:
+@@ -1135,13 +1135,13 @@ static long long snd_mixart_BA1_llseek(s
+ offset = offset & ~3; /* 4 bytes aligned */
+
+ switch(orig) {
+- case 0: /* SEEK_SET */
++ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+- case 1: /* SEEK_CUR */
++ case SEEK_CUR:
+ file->f_pos += offset;
+ break;
+- case 2: /* SEEK_END, offset is negative */
++ case SEEK_END: /* offset is negative */
+ file->f_pos = MIXART_BA1_SIZE + offset;
+ break;
+ default:
+diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
+index 406ac3a..d544573 100644
+--- a/sound/pci/mixart/mixart_core.c
++++ b/sound/pci/mixart/mixart_core.c
+@@ -408,7 +408,7 @@ void snd_mixart_msg_tasklet(unsigned lon
+ }
+
+
+-irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
+ {
+ struct mixart_mgr *mgr = dev_id;
+ int err;
+diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
+index 1fe2bcf..c919b73 100644
+--- a/sound/pci/mixart/mixart_core.h
++++ b/sound/pci/mixart/mixart_core.h
+@@ -563,7 +563,7 @@ int snd_mixart_send_msg(struct mixart_m
+ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *request, u32 notif_event);
+ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request);
+
+-irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t snd_mixart_interrupt(int irq, void *dev_id);
+ void snd_mixart_msg_tasklet(unsigned long arg);
+
+ void snd_mixart_reset_board(struct mixart_mgr *mgr);
+diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
+index ed47b73..13de0f7 100644
+--- a/sound/pci/mixart/mixart_mixer.c
++++ b/sound/pci/mixart/mixart_mixer.c
+@@ -31,6 +31,7 @@
+ #include "mixart_core.h"
+ #include "mixart_hwdep.h"
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include "mixart_mixer.h"
+
+ static u32 mixart_analog_level[256] = {
+@@ -388,12 +389,17 @@ static int mixart_analog_vol_put(struct
+ return changed;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
++
+ static struct snd_kcontrol_new mixart_control_analog_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ /* name will be filled later */
+ .info = mixart_analog_vol_info,
+ .get = mixart_analog_vol_get,
+ .put = mixart_analog_vol_put,
++ .tlv = { .p = db_scale_analog },
+ };
+
+ /* shared */
+@@ -866,14 +872,19 @@ static int mixart_pcm_vol_put(struct snd
+ return changed;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
++
+ static struct snd_kcontrol_new snd_mixart_pcm_vol =
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ /* name will be filled later */
+ /* count will be filled later */
+ .info = mixart_digital_vol_info, /* shared */
+ .get = mixart_pcm_vol_get,
+ .put = mixart_pcm_vol_put,
++ .tlv = { .p = db_scale_digital },
+ };
+
+
+@@ -984,10 +995,13 @@ static int mixart_monitor_vol_put(struct
+
+ static struct snd_kcontrol_new mixart_control_monitor_vol = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Monitoring Volume",
+ .info = mixart_digital_vol_info, /* shared */
+ .get = mixart_monitor_vol_get,
+ .put = mixart_monitor_vol_put,
++ .tlv = { .p = db_scale_digital },
+ };
+
+ /*
+diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
+index 101eee0..945d21b 100644
+--- a/sound/pci/nm256/nm256.c
++++ b/sound/pci/nm256/nm256.c
+@@ -236,7 +236,7 @@ struct nm256 {
+
+ int irq;
+ int irq_acks;
+- irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
++ irq_handler_t interrupt;
+ int badintrcount; /* counter to check bogus interrupts */
+ struct mutex irq_mutex;
+
+@@ -1004,7 +1004,7 @@ snd_nm256_intr_check(struct nm256 *chip)
+ */
+
+ static irqreturn_t
+-snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
++snd_nm256_interrupt(int irq, void *dev_id)
+ {
+ struct nm256 *chip = dev_id;
+ u16 status;
+@@ -1069,7 +1069,7 @@ snd_nm256_interrupt(int irq, void *dev_i
+ */
+
+ static irqreturn_t
+-snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
++snd_nm256_interrupt_zx(int irq, void *dev_id)
+ {
+ struct nm256 *chip = dev_id;
+ u32 status;
+@@ -1390,6 +1390,7 @@ static int nm256_suspend(struct pci_dev
+ chip->coeffs_current = 0;
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1401,8 +1402,17 @@ static int nm256_resume(struct pci_dev *
+
+ /* Perform a full reset on the hardware */
+ chip->in_resume = 1;
++
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "nm256: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
++ pci_set_master(pci);
++
+ snd_nm256_init_chip(chip);
+
+ /* restore ac97 */
+diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
+index c40f590..0ff8dc3 100644
+--- a/sound/pci/pcxhr/pcxhr_core.c
++++ b/sound/pci/pcxhr/pcxhr_core.c
+@@ -1131,7 +1131,7 @@ static void pcxhr_update_timer_pos(struc
+ }
+
+
+-irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
+ {
+ struct pcxhr_mgr *mgr = dev_id;
+ unsigned int reg;
+diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
+index e7415d6..d9a4ab6 100644
+--- a/sound/pci/pcxhr/pcxhr_core.h
++++ b/sound/pci/pcxhr/pcxhr_core.h
+@@ -194,7 +194,7 @@ int pcxhr_write_io_num_reg_cont(struct p
+
+
+ /* interrupt handling */
+-irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t pcxhr_interrupt(int irq, void *dev_id);
+ void pcxhr_msg_tasklet(unsigned long arg);
+
+ #endif /* __SOUND_PCXHR_CORE_H */
+diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
+index 94e63a1..b133ad9 100644
+--- a/sound/pci/pcxhr/pcxhr_mixer.c
++++ b/sound/pci/pcxhr/pcxhr_mixer.c
+@@ -31,6 +31,7 @@
+ #include "pcxhr_hwdep.h"
+ #include "pcxhr_core.h"
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/asoundef.h>
+ #include "pcxhr_mixer.h"
+
+@@ -43,6 +44,9 @@
+ #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */
+ #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
+
++static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
++
+ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
+ {
+ int err, vol;
+@@ -130,10 +134,13 @@ static int pcxhr_analog_vol_put(struct s
+
+ static struct snd_kcontrol_new pcxhr_control_analog_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ /* name will be filled later */
+ .info = pcxhr_analog_vol_info,
+ .get = pcxhr_analog_vol_get,
+ .put = pcxhr_analog_vol_put,
++ /* tlv will be filled later */
+ };
+
+ /* shared */
+@@ -188,6 +195,7 @@ static struct snd_kcontrol_new pcxhr_con
+ #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */
+ #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */
+
++static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+
+ #define MORE_THAN_ONE_STREAM_LEVEL 0x000001
+ #define VALID_STREAM_PAN_LEVEL_MASK 0x800000
+@@ -343,11 +351,14 @@ static int pcxhr_pcm_vol_put(struct snd_
+ static struct snd_kcontrol_new snd_pcxhr_pcm_vol =
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ /* name will be filled later */
+ /* count will be filled later */
+ .info = pcxhr_digital_vol_info, /* shared */
+ .get = pcxhr_pcm_vol_get,
+ .put = pcxhr_pcm_vol_put,
++ .tlv = { .p = db_scale_digital },
+ };
+
+
+@@ -433,10 +444,13 @@ static int pcxhr_monitor_vol_put(struct
+
+ static struct snd_kcontrol_new pcxhr_control_monitor_vol = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Monitoring Volume",
+ .info = pcxhr_digital_vol_info, /* shared */
+ .get = pcxhr_monitor_vol_get,
+ .put = pcxhr_monitor_vol_put,
++ .tlv = { .p = db_scale_digital },
+ };
+
+ /*
+@@ -928,6 +942,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr
+ temp = pcxhr_control_analog_level;
+ temp.name = "Master Playback Volume";
+ temp.private_value = 0; /* playback */
++ temp.tlv.p = db_scale_analog_playback;
+ if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+ return err;
+ /* output mute controls */
+@@ -963,6 +978,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr
+ temp = pcxhr_control_analog_level;
+ temp.name = "Master Capture Volume";
+ temp.private_value = 1; /* capture */
++ temp.tlv.p = db_scale_analog_capture;
+ if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+ return err;
+
+diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
+index f435fcd..56e0c01 100644
+--- a/sound/pci/riptide/riptide.c
++++ b/sound/pci/riptide/riptide.c
+@@ -673,9 +673,13 @@ static struct lbuspath lbus_rec_path = {
+ #define FIRMWARE_VERSIONS 1
+ static union firmware_version firmware_versions[] = {
+ {
+- .firmware.ASIC = 3,.firmware.CODEC = 2,
+- .firmware.AUXDSP = 3,.firmware.PROG = 773,
+- },
++ .firmware = {
++ .ASIC = 3,
++ .CODEC = 2,
++ .AUXDSP = 3,
++ .PROG = 773,
++ },
++ },
+ };
+
+ static u32 atoh(unsigned char *in, unsigned int len)
+@@ -1174,9 +1178,9 @@ static int riptide_suspend(struct pci_de
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ snd_ac97_suspend(chip->ac97);
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1185,9 +1189,14 @@ static int riptide_resume(struct pci_dev
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_riptide *chip = card->private_data;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "riptide: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+ snd_riptide_initialize(chip);
+ snd_ac97_resume(chip->ac97);
+@@ -1732,7 +1741,7 @@ snd_riptide_pcm(struct snd_riptide *chip
+ }
+
+ static irqreturn_t
+-snd_riptide_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++snd_riptide_interrupt(int irq, void *dev_id)
+ {
+ struct snd_riptide *chip = dev_id;
+ struct cmdif *cif = chip->cif;
+@@ -1747,8 +1756,7 @@ snd_riptide_interrupt(int irq, void *dev
+ if (chip->rmidi && IS_MPUIRQ(cif->hwport)) {
+ chip->handled_irqs++;
+ snd_mpu401_uart_interrupt(irq,
+- chip->rmidi->private_data,
+- regs);
++ chip->rmidi->private_data);
+ }
+ SET_AIACK(cif->hwport);
+ }
+diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
+index 2a71499..dc8d130 100644
+--- a/sound/pci/rme32.c
++++ b/sound/pci/rme32.c
+@@ -818,8 +818,7 @@ static void snd_rme32_pcm_stop(struct rm
+ writel(0, rme32->iobase + RME32_IO_RESET_POS);
+ }
+
+-static irqreturn_t
+-snd_rme32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_rme32_interrupt(int irq, void *dev_id)
+ {
+ struct rme32 *rme32 = (struct rme32 *) dev_id;
+
+diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
+index f8de7c9..106110a 100644
+--- a/sound/pci/rme96.c
++++ b/sound/pci/rme96.c
+@@ -1117,8 +1117,7 @@ snd_rme96_capture_stop(struct rme96 *rme
+
+ static irqreturn_t
+ snd_rme96_interrupt(int irq,
+- void *dev_id,
+- struct pt_regs *regs)
++ void *dev_id)
+ {
+ struct rme96 *rme96 = (struct rme96 *)dev_id;
+
+diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
+index e5a52da..694aa05 100644
+--- a/sound/pci/rme9652/hdsp.c
++++ b/sound/pci/rme9652/hdsp.c
+@@ -726,22 +726,36 @@ static int hdsp_get_iobox_version (struc
+ }
+
+
+-static int hdsp_check_for_firmware (struct hdsp *hdsp, int show_err)
++#ifdef HDSP_FW_LOADER
++static int __devinit hdsp_request_fw_loader(struct hdsp *hdsp);
++#endif
++
++static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
+ {
+- if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
++ if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
++ return 0;
+ if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
+- snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
+ hdsp->state &= ~HDSP_FirmwareLoaded;
+- if (! show_err)
++ if (! load_on_demand)
+ return -EIO;
++ snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
+ /* try to load firmware */
+- if (hdsp->state & HDSP_FirmwareCached) {
+- if (snd_hdsp_load_firmware_from_cache(hdsp) != 0)
+- snd_printk(KERN_ERR "Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
+- } else {
+- snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
++ if (! (hdsp->state & HDSP_FirmwareCached)) {
++#ifdef HDSP_FW_LOADER
++ if (! hdsp_request_fw_loader(hdsp))
++ return 0;
++#endif
++ snd_printk(KERN_ERR
++ "Hammerfall-DSP: No firmware loaded nor "
++ "cached, please upload firmware.\n");
++ return -EIO;
++ }
++ if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
++ snd_printk(KERN_ERR
++ "Hammerfall-DSP: Firmware loading from "
++ "cache failed, please upload manually.\n");
++ return -EIO;
+ }
+- return -EIO;
+ }
+ return 0;
+ }
+@@ -3181,8 +3195,16 @@ snd_hdsp_proc_read(struct snd_info_entry
+ return;
+ }
+ } else {
+- snd_iprintf(buffer, "No firmware loaded nor cached, please upload firmware.\n");
+- return;
++ int err = -EINVAL;
++#ifdef HDSP_FW_LOADER
++ err = hdsp_request_fw_loader(hdsp);
++#endif
++ if (err < 0) {
++ snd_iprintf(buffer,
++ "No firmware loaded nor cached, "
++ "please upload firmware.\n");
++ return;
++ }
+ }
+ }
+
+@@ -3581,7 +3603,7 @@ static void hdsp_midi_tasklet(unsigned l
+ snd_hdsp_midi_input_read (&hdsp->midi[1]);
+ }
+
+-static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
+ {
+ struct hdsp *hdsp = (struct hdsp *) dev_id;
+ unsigned int status;
+@@ -3851,7 +3873,7 @@ static int snd_hdsp_trigger(struct snd_p
+ if (hdsp_check_for_iobox (hdsp))
+ return -EIO;
+
+- if (hdsp_check_for_firmware(hdsp, 1))
++ if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */
+ return -EIO;
+
+ spin_lock(&hdsp->lock);
+diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
+index 7d03ae0..7055d89 100644
+--- a/sound/pci/rme9652/hdspm.c
++++ b/sound/pci/rme9652/hdspm.c
+@@ -2556,8 +2556,7 @@ static int snd_hdspm_set_defaults(struct
+ interupt
+ ------------------------------------------------------------*/
+
+-static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
+ {
+ struct hdspm *hdspm = (struct hdspm *) dev_id;
+ unsigned int status;
+diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
+index fc15f61..cf0427b 100644
+--- a/sound/pci/rme9652/rme9652.c
++++ b/sound/pci/rme9652/rme9652.c
+@@ -1882,7 +1882,7 @@ static void snd_rme9652_set_defaults(str
+ rme9652_set_rate(rme9652, 48000);
+ }
+
+-static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id)
+ {
+ struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) dev_id;
+
+diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
+index e5d4def..f9b8afa 100644
+--- a/sound/pci/sonicvibes.c
++++ b/sound/pci/sonicvibes.c
+@@ -580,7 +580,7 @@ static int snd_sonicvibes_trigger(struct
+ return result;
+ }
+
+-static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
+ {
+ struct sonicvibes *sonic = dev_id;
+ unsigned char status;
+@@ -601,7 +601,7 @@ static irqreturn_t snd_sonicvibes_interr
+ }
+ if (sonic->rmidi) {
+ if (status & SV_MIDI_IRQ)
+- snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data);
+ }
+ if (status & SV_UD_IRQ) {
+ unsigned char udreg;
+diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
+index 4930cc6..1fbc432 100644
+--- a/sound/pci/trident/trident_main.c
++++ b/sound/pci/trident/trident_main.c
+@@ -40,6 +40,7 @@
+ #include <sound/core.h>
+ #include <sound/info.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <sound/trident.h>
+ #include <sound/asoundef.h>
+
+@@ -51,8 +52,7 @@ static int snd_trident_pcm_mixer_build(s
+ static int snd_trident_pcm_mixer_free(struct snd_trident *trident,
+ struct snd_trident_voice * voice,
+ struct snd_pcm_substream *substream);
+-static irqreturn_t snd_trident_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs);
++static irqreturn_t snd_trident_interrupt(int irq, void *dev_id);
+ static int snd_trident_sis_reset(struct snd_trident *trident);
+
+ static void snd_trident_clear_voices(struct snd_trident * trident,
+@@ -2627,6 +2627,8 @@ static int snd_trident_vol_control_get(s
+ return 0;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
++
+ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -2653,6 +2655,7 @@ static struct snd_kcontrol_new snd_tride
+ .get = snd_trident_vol_control_get,
+ .put = snd_trident_vol_control_put,
+ .private_value = 16,
++ .tlv = { .p = db_scale_gvol },
+ };
+
+ static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata =
+@@ -2663,6 +2666,7 @@ static struct snd_kcontrol_new snd_tride
+ .get = snd_trident_vol_control_get,
+ .put = snd_trident_vol_control_put,
+ .private_value = 0,
++ .tlv = { .p = db_scale_gvol },
+ };
+
+ /*---------------------------------------------------------------------------
+@@ -2730,6 +2734,7 @@ static struct snd_kcontrol_new snd_tride
+ .info = snd_trident_pcm_vol_control_info,
+ .get = snd_trident_pcm_vol_control_get,
+ .put = snd_trident_pcm_vol_control_put,
++ /* FIXME: no tlv yet */
+ };
+
+ /*---------------------------------------------------------------------------
+@@ -2839,6 +2844,8 @@ static int snd_trident_pcm_rvol_control_
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
++
+ static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+@@ -2848,6 +2855,7 @@ static struct snd_kcontrol_new snd_tride
+ .info = snd_trident_pcm_rvol_control_info,
+ .get = snd_trident_pcm_rvol_control_get,
+ .put = snd_trident_pcm_rvol_control_put,
++ .tlv = { .p = db_scale_crvol },
+ };
+
+ /*---------------------------------------------------------------------------
+@@ -2903,6 +2911,7 @@ static struct snd_kcontrol_new snd_tride
+ .info = snd_trident_pcm_cvol_control_info,
+ .get = snd_trident_pcm_cvol_control_get,
+ .put = snd_trident_pcm_cvol_control_put,
++ .tlv = { .p = db_scale_crvol },
+ };
+
+ static void snd_trident_notify_pcm_change1(struct snd_card *card,
+@@ -3727,7 +3736,7 @@ static int snd_trident_free(struct snd_t
+
+ ---------------------------------------------------------------------------*/
+
+-static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_trident_interrupt(int irq, void *dev_id)
+ {
+ struct snd_trident *trident = dev_id;
+ unsigned int audio_int, chn_int, stimer, channel, mask, tmp;
+@@ -3815,7 +3824,7 @@ static irqreturn_t snd_trident_interrupt
+ }
+ if (audio_int & MPU401_IRQ) {
+ if (trident->rmidi) {
+- snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data);
+ } else {
+ inb(TRID_REG(trident, T4D_MPUR0));
+ }
+@@ -3957,15 +3966,9 @@ int snd_trident_suspend(struct pci_dev *
+ snd_ac97_suspend(trident->ac97);
+ snd_ac97_suspend(trident->ac97_sec);
+
+- switch (trident->device) {
+- case TRIDENT_DEVICE_ID_DX:
+- case TRIDENT_DEVICE_ID_NX:
+- break; /* TODO */
+- case TRIDENT_DEVICE_ID_SI7018:
+- break;
+- }
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -3974,9 +3977,15 @@ int snd_trident_resume(struct pci_dev *p
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_trident *trident = card->private_data;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
+- pci_set_master(pci); /* to be sure */
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "trident: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
++ pci_set_master(pci);
+
+ switch (trident->device) {
+ case TRIDENT_DEVICE_ID_DX:
+diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
+index 08da923..92b0736 100644
+--- a/sound/pci/via82xx.c
++++ b/sound/pci/via82xx.c
+@@ -59,6 +59,7 @@
+ #include <sound/pcm.h>
+ #include <sound/pcm_params.h>
+ #include <sound/info.h>
++#include <sound/tlv.h>
+ #include <sound/ac97_codec.h>
+ #include <sound/mpu401.h>
+ #include <sound/initval.h>
+@@ -612,7 +613,7 @@ static void snd_via82xx_channel_reset(st
+ * Interrupt handler
+ * Used for 686 and 8233A
+ */
+-static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_via686_interrupt(int irq, void *dev_id)
+ {
+ struct via82xx *chip = dev_id;
+ unsigned int status;
+@@ -622,7 +623,7 @@ static irqreturn_t snd_via686_interrupt(
+ if (! (status & chip->intr_mask)) {
+ if (chip->rmidi)
+ /* check mpu401 interrupt */
+- return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
++ return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
+ return IRQ_NONE;
+ }
+
+@@ -658,7 +659,7 @@ static irqreturn_t snd_via686_interrupt(
+ /*
+ * Interrupt handler
+ */
+-static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id)
+ {
+ struct via82xx *chip = dev_id;
+ unsigned int status;
+@@ -1277,7 +1278,18 @@ static int snd_via82xx_pcm_close(struct
+ if (! ratep->used)
+ ratep->rate = 0;
+ spin_unlock_irq(&ratep->lock);
+-
++ if (! ratep->rate) {
++ if (! viadev->direction) {
++ snd_ac97_update_power(chip->ac97,
++ AC97_PCM_FRONT_DAC_RATE, 0);
++ snd_ac97_update_power(chip->ac97,
++ AC97_PCM_SURR_DAC_RATE, 0);
++ snd_ac97_update_power(chip->ac97,
++ AC97_PCM_LFE_DAC_RATE, 0);
++ } else
++ snd_ac97_update_power(chip->ac97,
++ AC97_PCM_LR_ADC_RATE, 0);
++ }
+ viadev->substream = NULL;
+ return 0;
+ }
+@@ -1687,21 +1699,29 @@ static int snd_via8233_pcmdxs_volume_put
+ return change;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
++
+ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = {
+ .name = "PCM Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .info = snd_via8233_dxs_volume_info,
+ .get = snd_via8233_pcmdxs_volume_get,
+ .put = snd_via8233_pcmdxs_volume_put,
++ .tlv = { .p = db_scale_dxs }
+ };
+
+ static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = {
+ .name = "VIA DXS Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .count = 4,
+ .info = snd_via8233_dxs_volume_info,
+ .get = snd_via8233_dxs_volume_get,
+ .put = snd_via8233_dxs_volume_put,
++ .tlv = { .p = db_scale_dxs }
+ };
+
+ /*
+@@ -2165,9 +2185,9 @@ static int snd_via82xx_suspend(struct pc
+ chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
+ }
+
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2177,9 +2197,15 @@ static int snd_via82xx_resume(struct pci
+ struct via82xx *chip = card->private_data;
+ int i;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "via82xx: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
++ pci_set_master(pci);
+
+ snd_via82xx_chip_init(chip);
+
+@@ -2393,6 +2419,7 @@ static int __devinit check_dxs_list(stru
+ { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
+ { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
+ { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
++ { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */
+ { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
+ { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
+ { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
+diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
+index 016f9da..feb27c9 100644
+--- a/sound/pci/via82xx_modem.c
++++ b/sound/pci/via82xx_modem.c
+@@ -475,7 +475,7 @@ static void snd_via82xx_channel_reset(st
+ * Interrupt handler
+ */
+
+-static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id)
+ {
+ struct via82xx_modem *chip = dev_id;
+ unsigned int status;
+@@ -1032,9 +1032,10 @@ static int snd_via82xx_suspend(struct pc
+ snd_via82xx_channel_reset(chip, &chip->devs[i]);
+ synchronize_irq(chip->irq);
+ snd_ac97_suspend(chip->ac97);
+- pci_set_power_state(pci, PCI_D3hot);
++
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -1044,9 +1045,14 @@ static int snd_via82xx_resume(struct pci
+ struct via82xx_modem *chip = card->private_data;
+ int i;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "via82xx-modem: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+
+ snd_via82xx_chip_init(chip);
+diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
+index 9c03c6b..af49e8a 100644
+--- a/sound/pci/vx222/vx222.c
++++ b/sound/pci/vx222/vx222.c
+@@ -26,6 +26,7 @@
+ #include <linux/moduleparam.h>
+ #include <sound/core.h>
+ #include <sound/initval.h>
++#include <sound/tlv.h>
+ #include "vx222.h"
+
+ #define CARD_NAME "VX222"
+@@ -72,6 +73,9 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids);
+ /*
+ */
+
++static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
++static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
++
+ static struct snd_vx_hardware vx222_old_hw = {
+
+ .name = "VX222/Old",
+@@ -81,6 +85,7 @@ static struct snd_vx_hardware vx222_old_
+ .num_ins = 1,
+ .num_outs = 1,
+ .output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
++ .output_level_db_scale = db_scale_old_vol,
+ };
+
+ static struct snd_vx_hardware vx222_v2_hw = {
+@@ -92,6 +97,7 @@ static struct snd_vx_hardware vx222_v2_h
+ .num_ins = 1,
+ .num_outs = 1,
+ .output_level_max = VX2_AKM_LEVEL_MAX,
++ .output_level_db_scale = db_scale_akm,
+ };
+
+ static struct snd_vx_hardware vx222_mic_hw = {
+@@ -103,6 +109,7 @@ static struct snd_vx_hardware vx222_mic_
+ .num_ins = 1,
+ .num_outs = 1,
+ .output_level_max = VX2_AKM_LEVEL_MAX,
++ .output_level_db_scale = db_scale_akm,
+ };
+
+
+@@ -259,9 +266,9 @@ static int snd_vx222_suspend(struct pci_
+ int err;
+
+ err = snd_vx_suspend(&vx->core, state);
+- pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return err;
+ }
+
+@@ -270,9 +277,14 @@ static int snd_vx222_resume(struct pci_d
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_vx222 *vx = card->private_data;
+
+- pci_restore_state(pci);
+- pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "vx222: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+ return snd_vx_resume(&vx->core);
+ }
+diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
+index 9b6d345..5e51950 100644
+--- a/sound/pci/vx222/vx222_ops.c
++++ b/sound/pci/vx222/vx222_ops.c
+@@ -28,6 +28,7 @@
+
+ #include <sound/core.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include <asm/io.h>
+ #include "vx222.h"
+
+@@ -845,6 +846,8 @@ static void vx2_set_input_level(struct s
+
+ #define MIC_LEVEL_MAX 0xff
+
++static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
++
+ /*
+ * controls API for input levels
+ */
+@@ -922,18 +925,24 @@ static int vx_mic_level_put(struct snd_k
+
+ static struct snd_kcontrol_new vx_control_input_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Capture Volume",
+ .info = vx_input_level_info,
+ .get = vx_input_level_get,
+ .put = vx_input_level_put,
++ .tlv = { .p = db_scale_mic },
+ };
+
+ static struct snd_kcontrol_new vx_control_mic_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Mic Capture Volume",
+ .info = vx_mic_level_info,
+ .get = vx_mic_level_get,
+ .put = vx_mic_level_put,
++ .tlv = { .p = db_scale_mic },
+ };
+
+ /*
+diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
+index a55b5fd..a40c108 100644
+--- a/sound/pci/ymfpci/ymfpci_main.c
++++ b/sound/pci/ymfpci/ymfpci_main.c
+@@ -36,6 +36,7 @@
+ #include <sound/core.h>
+ #include <sound/control.h>
+ #include <sound/info.h>
++#include <sound/tlv.h>
+ #include <sound/ymfpci.h>
+ #include <sound/asoundef.h>
+ #include <sound/mpu401.h>
+@@ -752,7 +753,7 @@ static void snd_ymfpci_irq_wait(struct s
+ }
+ }
+
+-static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id)
+ {
+ struct snd_ymfpci *chip = dev_id;
+ u32 status, nvoice, mode;
+@@ -798,7 +799,7 @@ static irqreturn_t snd_ymfpci_interrupt(
+ snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status);
+
+ if (chip->rawmidi)
+- snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs);
++ snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data);
+ return IRQ_HANDLED;
+ }
+
+@@ -1477,11 +1478,15 @@ static int snd_ymfpci_put_single(struct
+ return change;
+ }
+
++static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
++
+ #define YMFPCI_DOUBLE(xname, xindex, reg) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_ymfpci_info_double, \
+ .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \
+- .private_value = reg }
++ .private_value = reg, \
++ .tlv = { .p = db_scale_native } }
+
+ static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+ {
+@@ -2213,6 +2218,7 @@ int snd_ymfpci_suspend(struct pci_dev *p
+ snd_ymfpci_disable_dsp(chip);
+ pci_disable_device(pci);
+ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+ }
+
+@@ -2222,8 +2228,14 @@ int snd_ymfpci_resume(struct pci_dev *pc
+ struct snd_ymfpci *chip = card->private_data;
+ unsigned int i;
+
++ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+- pci_enable_device(pci);
++ if (pci_enable_device(pci) < 0) {
++ printk(KERN_ERR "ymfpci: pci_enable_device failed, "
++ "disabling device\n");
++ snd_card_disconnect(card);
++ return -EIO;
++ }
+ pci_set_master(pci);
+ snd_ymfpci_aclink_reset(pci);
+ snd_ymfpci_codec_ready(chip, 0);
+diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
+index 1c09e5f..fd3590f 100644
+--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
++++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
+@@ -206,7 +206,7 @@ static void snd_pdacf_detach(struct pcmc
+ snd_pdacf_powerdown(chip);
+ chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
+ snd_card_disconnect(chip->card);
+- snd_card_free_in_thread(chip->card);
++ snd_card_free_when_closed(chip->card);
+ }
+
+ /*
+diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
+index 9a14a4f..206e2f5 100644
+--- a/sound/pcmcia/pdaudiocf/pdaudiocf.h
++++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h
+@@ -138,7 +138,7 @@ int snd_pdacf_suspend(struct snd_pdacf *
+ int snd_pdacf_resume(struct snd_pdacf *chip);
+ #endif
+ int snd_pdacf_pcm_new(struct snd_pdacf *chip);
+-irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs);
++irqreturn_t pdacf_interrupt(int irq, void *dev);
+ void pdacf_tasklet(unsigned long private_data);
+ void pdacf_reinit(struct snd_pdacf *chip, int resume);
+
+diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+index 7c5f21e..5bd6920 100644
+--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
++++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+@@ -22,11 +22,12 @@
+ #include <sound/core.h>
+ #include "pdaudiocf.h"
+ #include <sound/initval.h>
++#include <asm/irq_regs.h>
+
+ /*
+ *
+ */
+-irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
++irqreturn_t pdacf_interrupt(int irq, void *dev)
+ {
+ struct snd_pdacf *chip = dev;
+ unsigned short stat;
+@@ -45,7 +46,7 @@ irqreturn_t pdacf_interrupt(int irq, voi
+ if (!(stat & PDAUDIOCF_IRQAKM))
+ stat |= PDAUDIOCF_IRQAKM; /* check rate */
+ }
+- if (regs != NULL)
++ if (get_irq_regs() != NULL)
+ snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
+ return IRQ_HANDLED;
+ }
+diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c
+index e237f6c..bced7b6 100644
+--- a/sound/pcmcia/vx/vxp_mixer.c
++++ b/sound/pcmcia/vx/vxp_mixer.c
+@@ -23,6 +23,7 @@
+ #include <sound/driver.h>
+ #include <sound/core.h>
+ #include <sound/control.h>
++#include <sound/tlv.h>
+ #include "vxpocket.h"
+
+ #define MIC_LEVEL_MIN 0
+@@ -63,12 +64,17 @@ static int vx_mic_level_put(struct snd_k
+ return 0;
+ }
+
++static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0);
++
+ static struct snd_kcontrol_new vx_control_mic_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Mic Capture Volume",
+ .info = vx_mic_level_info,
+ .get = vx_mic_level_get,
+ .put = vx_mic_level_put,
++ .tlv = { .p = db_scale_mic },
+ };
+
+ /*
+diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
+index cafe664..3089fcc 100644
+--- a/sound/pcmcia/vx/vxpocket.c
++++ b/sound/pcmcia/vx/vxpocket.c
+@@ -27,6 +27,7 @@
+ #include <pcmcia/ciscode.h>
+ #include <pcmcia/cisreg.h>
+ #include <sound/initval.h>
++#include <sound/tlv.h>
+
+ /*
+ */
+@@ -65,7 +66,7 @@ static void vxpocket_release(struct pcmc
+ }
+
+ /*
+- * destructor, called from snd_card_free_in_thread()
++ * destructor, called from snd_card_free_when_closed()
+ */
+ static int snd_vxpocket_dev_free(struct snd_device *device)
+ {
+@@ -90,6 +91,8 @@ static int snd_vxpocket_dev_free(struct
+ * Only output levels can be modified
+ */
+
++static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
++
+ static struct snd_vx_hardware vxpocket_hw = {
+ .name = "VXPocket",
+ .type = VX_TYPE_VXPOCKET,
+@@ -99,6 +102,7 @@ static struct snd_vx_hardware vxpocket_h
+ .num_ins = 1,
+ .num_outs = 1,
+ .output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
++ .output_level_db_scale = db_scale_old_vol,
+ };
+
+ /* VX-pocket 440
+@@ -120,6 +124,7 @@ static struct snd_vx_hardware vxp440_hw
+ .num_ins = 2,
+ .num_outs = 2,
+ .output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
++ .output_level_db_scale = db_scale_old_vol,
+ };
+
+
+@@ -363,7 +368,7 @@ static void vxpocket_detach(struct pcmci
+ chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
+ snd_card_disconnect(chip->card);
+ vxpocket_release(link);
+- snd_card_free_in_thread(chip->card);
++ snd_card_free_when_closed(chip->card);
+ }
+
+ /*
+diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
+index 5fec1e5..5f38f67 100644
+--- a/sound/ppc/beep.c
++++ b/sound/ppc/beep.c
+@@ -215,15 +215,18 @@ int __init snd_pmac_attach_beep(struct s
+ {
+ struct pmac_beep *beep;
+ struct input_dev *input_dev;
++ struct snd_kcontrol *beep_ctl;
+ void *dmabuf;
+ int err = -ENOMEM;
+
+ beep = kzalloc(sizeof(*beep), GFP_KERNEL);
++ if (! beep)
++ return -ENOMEM;
+ dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
+ &beep->addr, GFP_KERNEL);
+ input_dev = input_allocate_device();
+- if (!beep || !dmabuf || !input_dev)
+- goto fail;
++ if (! dmabuf || ! input_dev)
++ goto fail1;
+
+ /* FIXME: set more better values */
+ input_dev->name = "PowerMac Beep";
+@@ -244,17 +247,24 @@ int __init snd_pmac_attach_beep(struct s
+ beep->volume = BEEP_VOLUME;
+ beep->running = 0;
+
+- err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip));
++ beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
++ err = snd_ctl_add(chip->card, beep_ctl);
+ if (err < 0)
+- goto fail;
++ goto fail1;
++
++ chip->beep = beep;
+
+- chip->beep = beep;
+- input_register_device(beep->dev);
+-
+- return 0;
+-
+- fail: input_free_device(input_dev);
+- kfree(dmabuf);
++ err = input_register_device(beep->dev);
++ if (err)
++ goto fail2;
++
++ return 0;
++
++ fail2: snd_ctl_remove(chip->card, beep_ctl);
++ fail1: input_free_device(input_dev);
++ if (dmabuf)
++ dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
++ dmabuf, beep->addr);
+ kfree(beep);
+ return err;
+ }
+diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
+index 59482a4..272ae38 100644
+--- a/sound/ppc/keywest.c
++++ b/sound/ppc/keywest.c
+@@ -117,6 +117,9 @@ int __init snd_pmac_tumbler_post_init(vo
+ {
+ int err;
+
++ if (!keywest_ctx || !keywest_ctx->client)
++ return -ENXIO;
++
+ if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
+ snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err);
+ return err;
+diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
+index 6414306..c64af55 100644
+--- a/sound/ppc/pmac.c
++++ b/sound/ppc/pmac.c
+@@ -713,7 +713,7 @@ void snd_pmac_beep_dma_stop(struct snd_p
+ * interrupt handlers
+ */
+ static irqreturn_t
+-snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs)
++snd_pmac_tx_intr(int irq, void *devid)
+ {
+ struct snd_pmac *chip = devid;
+ snd_pmac_pcm_update(chip, &chip->playback);
+@@ -722,7 +722,7 @@ snd_pmac_tx_intr(int irq, void *devid, s
+
+
+ static irqreturn_t
+-snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs)
++snd_pmac_rx_intr(int irq, void *devid)
+ {
+ struct snd_pmac *chip = devid;
+ snd_pmac_pcm_update(chip, &chip->capture);
+@@ -731,7 +731,7 @@ snd_pmac_rx_intr(int irq, void *devid, s
+
+
+ static irqreturn_t
+-snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs)
++snd_pmac_ctrl_intr(int irq, void *devid)
+ {
+ struct snd_pmac *chip = devid;
+ int ctrl = in_le32(&chip->awacs->control);
+diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
+index 84f6b19..2fbe1d1 100644
+--- a/sound/ppc/tumbler.c
++++ b/sound/ppc/tumbler.c
+@@ -190,7 +190,7 @@ static int check_audio_gpio(struct pmac_
+
+ ret = do_gpio_read(gp);
+
+- return (ret & 0xd) == (gp->active_val & 0xd);
++ return (ret & 0x1) == (gp->active_val & 0x1);
+ }
+
+ static int read_audio_gpio(struct pmac_gpio *gp)
+@@ -198,7 +198,8 @@ static int read_audio_gpio(struct pmac_g
+ int ret;
+ if (! gp->addr)
+ return 0;
+- ret = ((do_gpio_read(gp) & 0x02) !=0);
++ ret = do_gpio_read(gp);
++ ret = (ret & 0x02) !=0;
+ return ret == gp->active_state;
+ }
+
+@@ -1016,7 +1017,7 @@ static void tumbler_update_automute(stru
+
+
+ /* interrupt - headphone plug changed */
+-static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs)
++static irqreturn_t headphone_intr(int irq, void *devid)
+ {
+ struct snd_pmac *chip = devid;
+ if (chip->update_automute && chip->initialized) {
+@@ -1035,7 +1036,7 @@ static struct device_node *find_audio_de
+ return NULL;
+
+ for (np = np->child; np; np = np->sibling) {
+- char *property = get_property(np, "audio-gpio", NULL);
++ const char *property = get_property(np, "audio-gpio", NULL);
+ if (property && strcmp(property, name) == 0)
+ return np;
+ }
+@@ -1062,7 +1063,8 @@ static long tumbler_find_device(const ch
+ struct pmac_gpio *gp, int is_compatible)
+ {
+ struct device_node *node;
+- u32 *base, addr;
++ const u32 *base;
++ u32 addr;
+
+ if (is_compatible)
+ node = find_compatible_audio_device(device);
+@@ -1074,9 +1076,9 @@ static long tumbler_find_device(const ch
+ return -ENODEV;
+ }
+
+- base = (u32 *)get_property(node, "AAPL,address", NULL);
++ base = get_property(node, "AAPL,address", NULL);
+ if (! base) {
+- base = (u32 *)get_property(node, "reg", NULL);
++ base = get_property(node, "reg", NULL);
+ if (!base) {
+ DBG("(E) cannot find address for device %s !\n", device);
+ snd_printd("cannot find address for device %s\n", device);
+@@ -1090,13 +1092,13 @@ static long tumbler_find_device(const ch
+
+ gp->addr = addr & 0x0000ffff;
+ /* Try to find the active state, default to 0 ! */
+- base = (u32 *)get_property(node, "audio-gpio-active-state", NULL);
++ base = get_property(node, "audio-gpio-active-state", NULL);
+ if (base) {
+ gp->active_state = *base;
+ gp->active_val = (*base) ? 0x5 : 0x4;
+ gp->inactive_val = (*base) ? 0x4 : 0x5;
+ } else {
+- u32 *prop = NULL;
++ const u32 *prop = NULL;
+ gp->active_state = 0;
+ gp->active_val = 0x4;
+ gp->inactive_val = 0x5;
+@@ -1105,7 +1107,7 @@ static long tumbler_find_device(const ch
+ * as we don't yet have an interpreter for these things
+ */
+ if (platform)
+- prop = (u32 *)get_property(node, platform, NULL);
++ prop = get_property(node, platform, NULL);
+ if (prop) {
+ if (prop[3] == 0x9 && prop[4] == 0x9) {
+ gp->active_val = 0xd;
+diff --git a/sound/sound_core.c b/sound/sound_core.c
+index 62d4d0c..5322c50 100644
+--- a/sound/sound_core.c
++++ b/sound/sound_core.c
+@@ -366,25 +366,6 @@ int register_sound_dsp(const struct file
+ EXPORT_SYMBOL(register_sound_dsp);
+
+ /**
+- * register_sound_synth - register a synth device
+- * @fops: File operations for the driver
+- * @dev: Unit number to allocate
+- *
+- * Allocate a synth device. Unit is the number of the synth device requested.
+- * Pass -1 to request the next free synth unit. On success the allocated
+- * number is returned, on failure a negative error code is returned.
+- */
+-
+-
+-int register_sound_synth(const struct file_operations *fops, int dev)
+-{
+- return sound_insert_unit(&chains[9], fops, dev, 9, 137,
+- "synth", S_IRUSR | S_IWUSR, NULL);
+-}
+-
+-EXPORT_SYMBOL(register_sound_synth);
+-
+-/**
+ * unregister_sound_special - unregister a special sound device
+ * @unit: unit number to allocate
+ *
+@@ -449,21 +430,6 @@ void unregister_sound_dsp(int unit)
+
+ EXPORT_SYMBOL(unregister_sound_dsp);
+
+-/**
+- * unregister_sound_synth - unregister a synth device
+- * @unit: unit number to allocate
+- *
+- * Release a sound device that was allocated with register_sound_synth().
+- * The unit passed is the return value from the register function.
+- */
+-
+-void unregister_sound_synth(int unit)
+-{
+- return sound_remove_unit(&chains[9], unit);
+-}
+-
+-EXPORT_SYMBOL(unregister_sound_synth);
+-
+ /*
+ * Now our file operations
+ */
+@@ -551,10 +517,6 @@ int soundcore_open(struct inode *inode,
+ return -ENODEV;
+ }
+
+-extern int mod_firmware_load(const char *, char **);
+-EXPORT_SYMBOL(mod_firmware_load);
+-
+-
+ MODULE_DESCRIPTION("Core sound module");
+ MODULE_AUTHOR("Alan Cox");
+ MODULE_LICENSE("GPL");
+diff --git a/sound/sound_firmware.c b/sound/sound_firmware.c
+index 6ddadfa..3a181d4 100644
+--- a/sound/sound_firmware.c
++++ b/sound/sound_firmware.c
+@@ -4,6 +4,7 @@
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+ #include <asm/uaccess.h>
++#include "oss/sound_firmware.h"
+
+ static int do_mod_firmware_load(const char *fn, char **fp)
+ {
+@@ -59,8 +60,7 @@ static int do_mod_firmware_load(const ch
+ * value zero on a failure.
+ *
+ * Caution: This API is not recommended. Firmware should be loaded via
+- * an ioctl call and a setup application. This function may disappear
+- * in future.
++ * request_firmware.
+ */
+
+ int mod_firmware_load(const char *fn, char **fp)
+@@ -73,4 +73,6 @@ int mod_firmware_load(const char *fn, ch
+ set_fs(fs);
+ return r;
+ }
++EXPORT_SYMBOL(mod_firmware_load);
+
++MODULE_LICENSE("GPL");
+diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
+index 2bd8e40..c899786 100644
+--- a/sound/sparc/amd7930.c
++++ b/sound/sparc/amd7930.c
+@@ -491,7 +491,7 @@ static void __amd7930_update_map(struct
+ __amd7930_write_map(amd);
+ }
+
+-static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id)
+ {
+ struct snd_amd7930 *amd = dev_id;
+ unsigned int elapsed;
+@@ -755,7 +755,7 @@ static struct snd_pcm_ops snd_amd7930_ca
+ .pointer = snd_amd7930_capture_pointer,
+ };
+
+-static int __init snd_amd7930_pcm(struct snd_amd7930 *amd)
++static int __devinit snd_amd7930_pcm(struct snd_amd7930 *amd)
+ {
+ struct snd_pcm *pcm;
+ int err;
+@@ -870,7 +870,7 @@ static int snd_amd7930_put_volume(struct
+ return change;
+ }
+
+-static struct snd_kcontrol_new amd7930_controls[] __initdata = {
++static struct snd_kcontrol_new amd7930_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Monitor Volume",
+@@ -900,7 +900,7 @@ static struct snd_kcontrol_new amd7930_c
+ },
+ };
+
+-static int __init snd_amd7930_mixer(struct snd_amd7930 *amd)
++static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd)
+ {
+ struct snd_card *card;
+ int idx, err;
+@@ -945,11 +945,11 @@ static struct snd_device_ops snd_amd7930
+ .dev_free = snd_amd7930_dev_free,
+ };
+
+-static int __init snd_amd7930_create(struct snd_card *card,
+- struct resource *rp,
+- unsigned int reg_size,
+- int irq, int dev,
+- struct snd_amd7930 **ramd)
++static int __devinit snd_amd7930_create(struct snd_card *card,
++ struct resource *rp,
++ unsigned int reg_size,
++ int irq, int dev,
++ struct snd_amd7930 **ramd)
+ {
+ unsigned long flags;
+ struct snd_amd7930 *amd;
+@@ -1013,7 +1013,7 @@ static int __init snd_amd7930_create(str
+ return 0;
+ }
+
+-static int __init amd7930_attach_common(struct resource *rp, int irq)
++static int __devinit amd7930_attach_common(struct resource *rp, int irq)
+ {
+ static int dev_num;
+ struct snd_card *card;
+@@ -1065,7 +1065,7 @@ out_err:
+ return err;
+ }
+
+-static int __init amd7930_obio_attach(struct device_node *dp)
++static int __devinit amd7930_obio_attach(struct device_node *dp)
+ {
+ struct linux_prom_registers *regs;
+ struct linux_prom_irqs *irqp;
+diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
+index 9a06c3b..edeb3d3 100644
+--- a/sound/sparc/cs4231.c
++++ b/sound/sparc/cs4231.c
+@@ -1753,7 +1753,7 @@ out_err:
+
+ #ifdef SBUS_SUPPORT
+
+-static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id)
+ {
+ unsigned long flags;
+ unsigned char status;
+diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
+index f3ae6e2..4ceb09d 100644
+--- a/sound/sparc/dbri.c
++++ b/sound/sparc/dbri.c
+@@ -2,6 +2,8 @@
+ * Driver for DBRI sound chip found on Sparcs.
+ * Copyright (C) 2004, 2005 Martin Habets (mhabets at users.sourceforge.net)
+ *
++ * Converted to ring buffered version by Krzysztof Helt (krzysztof.h1 at wp.pl)
++ *
+ * Based entirely upon drivers/sbus/audio/dbri.c which is:
+ * Copyright (C) 1997 Rudolf Koenig (rfkoenig at immd4.informatik.uni-erlangen.de)
+ * Copyright (C) 1998, 1999 Brent Baccala (baccala at freesoft.org)
+@@ -34,7 +36,7 @@
+ * (the second one is a monitor/tee pipe, valid only for serial input).
+ *
+ * The mmcodec is connected via the CHI bus and needs the data & some
+- * parameters (volume, balance, output selection) timemultiplexed in 8 byte
++ * parameters (volume, output selection) timemultiplexed in 8 byte
+ * chunks. It also has a control mode, which serves for audio format setting.
+ *
+ * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on
+@@ -83,7 +85,7 @@ MODULE_PARM_DESC(id, "ID string for Sun
+ module_param_array(enable, bool, NULL, 0444);
+ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
+
+-#define DBRI_DEBUG
++#undef DBRI_DEBUG
+
+ #define D_INT (1<<0)
+ #define D_GEN (1<<1)
+@@ -104,17 +106,15 @@ static char *cmds[] = {
+
+ #define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x)
+
+-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \
+- (1 << 27) | \
+- value)
+ #else
+-#define dprintk(a, x...)
++#define dprintk(a, x...) do { } while (0)
+
+-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \
+- (intr << 27) | \
+- value)
+ #endif /* DBRI_DEBUG */
+
++#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \
++ (intr << 27) | \
++ value)
++
+ /***************************************************************************
+ CS4215 specific definitions and structures
+ ****************************************************************************/
+@@ -160,7 +160,7 @@ static struct {
+ /* { NA, (1 << 4), (5 << 3) }, */
+ { 48000, (1 << 4), (6 << 3) },
+ { 9600, (1 << 4), (7 << 3) },
+- { 5513, (2 << 4), (0 << 3) }, /* Actually 5512.5 */
++ { 5512, (2 << 4), (0 << 3) }, /* Actually 5512.5 */
+ { 11025, (2 << 4), (1 << 3) },
+ { 18900, (2 << 4), (2 << 3) },
+ { 22050, (2 << 4), (3 << 3) },
+@@ -240,28 +240,21 @@ static struct {
+ #define REG9 0x24UL /* Interrupt Queue Pointer */
+
+ #define DBRI_NO_CMDS 64
+-#define DBRI_NO_INTS 1 /* Note: the value of this define was
+- * originally 2. The ringbuffer to store
+- * interrupts in dma is currently broken.
+- * This is a temporary fix until the ringbuffer
+- * is fixed.
+- */
+ #define DBRI_INT_BLK 64
+ #define DBRI_NO_DESCS 64
+ #define DBRI_NO_PIPES 32
+-
+-#define DBRI_MM_ONB 1
+-#define DBRI_MM_SB 2
++#define DBRI_MAX_PIPE (DBRI_NO_PIPES - 1)
+
+ #define DBRI_REC 0
+ #define DBRI_PLAY 1
+ #define DBRI_NO_STREAMS 2
+
+ /* One transmit/receive descriptor */
++/* When ba != 0 descriptor is used */
+ struct dbri_mem {
+ volatile __u32 word1;
+- volatile __u32 ba; /* Transmit/Receive Buffer Address */
+- volatile __u32 nda; /* Next Descriptor Address */
++ __u32 ba; /* Transmit/Receive Buffer Address */
++ __u32 nda; /* Next Descriptor Address */
+ volatile __u32 word4;
+ };
+
+@@ -269,8 +262,8 @@ struct dbri_mem {
+ * the CPU and the DBRI
+ */
+ struct dbri_dma {
+- volatile s32 cmd[DBRI_NO_CMDS]; /* Place for commands */
+- volatile s32 intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */
++ s32 cmd[DBRI_NO_CMDS]; /* Place for commands */
++ volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */
+ struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */
+ };
+
+@@ -282,58 +275,43 @@ enum in_or_out { PIPEinput, PIPEoutput }
+
+ struct dbri_pipe {
+ u32 sdp; /* SDP command word */
+- enum in_or_out direction;
+ int nextpipe; /* Next pipe in linked list */
+- int prevpipe;
+- int cycle; /* Offset of timeslot (bits) */
+ int length; /* Length of timeslot (bits) */
+ int first_desc; /* Index of first descriptor */
+ int desc; /* Index of active descriptor */
+ volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */
+ };
+
+-struct dbri_desc {
+- int inuse; /* Boolean flag */
+- int next; /* Index of next desc, or -1 */
+- unsigned int len;
+-};
+-
+ /* Per stream (playback or record) information */
+ struct dbri_streaminfo {
+ struct snd_pcm_substream *substream;
+ u32 dvma_buffer; /* Device view of Alsa DMA buffer */
+- int left; /* # of bytes left in DMA buffer */
+ int size; /* Size of DMA buffer */
+ size_t offset; /* offset in user buffer */
+ int pipe; /* Data pipe used */
+ int left_gain; /* mixer elements */
+ int right_gain;
+- int balance;
+ };
+
+ /* This structure holds the information for both chips (DBRI & CS4215) */
+ struct snd_dbri {
+ struct snd_card *card; /* ALSA card */
+- struct snd_pcm *pcm;
+
+ int regs_size, irq; /* Needed for unload */
+ struct sbus_dev *sdev; /* SBUS device info */
+ spinlock_t lock;
+
+- volatile struct dbri_dma *dma; /* Pointer to our DMA block */
++ struct dbri_dma *dma; /* Pointer to our DMA block */
+ u32 dma_dvma; /* DBRI visible DMA address */
+
+ void __iomem *regs; /* dbri HW regs */
+- int dbri_version; /* 'e' and up is OK */
+ int dbri_irqp; /* intr queue pointer */
+- int wait_send; /* sequence of command buffers send */
+- int wait_ackd; /* sequence of command buffers acknowledged */
+
+ struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */
+- struct dbri_desc descs[DBRI_NO_DESCS];
++ int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */
++ spinlock_t cmdlock; /* Protects cmd queue accesses */
++ s32 *cmdptr; /* Pointer to the last queued cmd */
+
+- int chi_in_pipe;
+- int chi_out_pipe;
+ int chi_bpf;
+
+ struct cs4215 mm; /* mmcodec special info */
+@@ -345,8 +323,6 @@ struct snd_dbri {
+
+ #define DBRI_MAX_VOLUME 63 /* Output volume */
+ #define DBRI_MAX_GAIN 15 /* Input gain */
+-#define DBRI_RIGHT_BALANCE 255
+-#define DBRI_MID_BALANCE (DBRI_RIGHT_BALANCE >> 1)
+
+ /* DBRI Reg0 - Status Control Register - defines. (Page 17) */
+ #define D_P (1<<15) /* Program command & queue pointer valid */
+@@ -569,7 +545,7 @@ struct snd_dbri {
+ #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */
+ #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */
+ /* Maximum buffer size per TD: almost 8Kb */
+-#define DBRI_TD_MAXCNT ((1 << 13) - 1)
++#define DBRI_TD_MAXCNT ((1 << 13) - 4)
+
+ /* Receive descriptor defines */
+ #define DBRI_RD_F (1<<31) /* End of Frame */
+@@ -633,93 +609,124 @@ The list is terminated with a WAIT comma
+ CPU interrupt to signal completion.
+
+ Since the DBRI can run in parallel with the CPU, several means of
+-synchronization present themselves. The method implemented here is close
+-to the original scheme (Rudolf's), and uses 2 counters (wait_send and
+-wait_ackd) to synchronize the command buffer between the CPU and the DBRI.
++synchronization present themselves. The method implemented here is only
++use of the dbri_cmdwait() to wait for execution of batch of sent commands.
+
+-A more sophisticated scheme might involve a circular command buffer
+-or an array of command buffers. A routine could fill one with
+-commands and link it onto a list. When a interrupt signaled
+-completion of the current command buffer, look on the list for
+-the next one.
++A circular command buffer is used here. A new command is being added
++while another can be executed. The scheme works by adding two WAIT commands
++after each sent batch of commands. When the next batch is prepared it is
++added after the WAIT commands then the WAITs are replaced with single JUMP
++command to the new batch. The the DBRI is forced to reread the last WAIT
++command (replaced by the JUMP by then). If the DBRI is still executing
++previous commands the request to reread the WAIT command is ignored.
+
+ Every time a routine wants to write commands to the DBRI, it must
+-first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
+-in return. dbri_cmdlock() will block if the previous commands have not
+-been completed yet. After this the commands can be written to the buffer,
+-and dbri_cmdsend() is called with the final pointer value to send them
+-to the DBRI.
++first call dbri_cmdlock() and get pointer to a free space in
++dbri->dma->cmd buffer. After this, the commands can be written to
++the buffer, and dbri_cmdsend() is called with the final pointer value
++to send them to the DBRI.
+
+ */
+
+-static void dbri_process_interrupt_buffer(struct snd_dbri * dbri);
+-
+-enum dbri_lock { NoGetLock, GetLock };
+-#define MAXLOOPS 10
+-
+-static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get)
++#define MAXLOOPS 20
++/*
++ * Wait for the current command string to execute
++ */
++static void dbri_cmdwait(struct snd_dbri *dbri)
+ {
+ int maxloops = MAXLOOPS;
+-
+-#ifndef SMP
+- if ((get == GetLock) && spin_is_locked(&dbri->lock)) {
+- printk(KERN_ERR "DBRI: cmdlock called while in spinlock.");
+- }
+-#endif
++ unsigned long flags;
+
+ /* Delay if previous commands are still being processed */
+- while ((--maxloops) > 0 && (dbri->wait_send != dbri->wait_ackd)) {
++ spin_lock_irqsave(&dbri->lock, flags);
++ while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) {
++ spin_unlock_irqrestore(&dbri->lock, flags);
+ msleep_interruptible(1);
+- /* If dbri_cmdlock() got called from inside the
+- * interrupt handler, this will do the processing.
+- */
+- dbri_process_interrupt_buffer(dbri);
++ spin_lock_irqsave(&dbri->lock, flags);
+ }
++ spin_unlock_irqrestore(&dbri->lock, flags);
++
+ if (maxloops == 0) {
+- printk(KERN_ERR "DBRI: Chip never completed command buffer %d\n",
+- dbri->wait_send);
++ printk(KERN_ERR "DBRI: Chip never completed command buffer\n");
+ } else {
+ dprintk(D_CMD, "Chip completed command buffer (%d)\n",
+ MAXLOOPS - maxloops - 1);
+ }
++}
++/*
++ * Lock the command queue and returns pointer to a space for len cmd words
++ * It locks the cmdlock spinlock.
++ */
++static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len)
++{
++ /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */
++ len += 2;
++ spin_lock(&dbri->cmdlock);
++ if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2)
++ return dbri->cmdptr + 2;
++ else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma)
++ return dbri->dma->cmd;
++ else
++ printk(KERN_ERR "DBRI: no space for commands.");
+
+- /*if (get == GetLock) spin_lock(&dbri->lock); */
+- return &dbri->dma->cmd[0];
++ return NULL;
+ }
+
+-static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd)
++/*
++ * Send prepared cmd string. It works by writting a JUMP cmd into
++ * the last WAIT cmd and force DBRI to reread the cmd.
++ * The JUMP cmd points to the new cmd string.
++ * It also releases the cmdlock spinlock.
++ *
++ * Lock must not be held before calling this.
++ */
++static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len)
+ {
+- volatile s32 *ptr;
+- u32 reg;
++ s32 tmp, addr;
++ static int wait_id = 0;
+
+- for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) {
+- dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
+- }
++ wait_id++;
++ wait_id &= 0xffff; /* restrict it to a 16 bit counter. */
++ *(cmd) = DBRI_CMD(D_WAIT, 1, wait_id);
++ *(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id);
+
+- if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) {
+- printk(KERN_ERR "DBRI: Command buffer overflow! (bug in driver)\n");
+- /* Ignore the last part. */
+- cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3];
+- }
++ /* Replace the last command with JUMP */
++ addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32);
++ *(dbri->cmdptr+1) = addr;
++ *(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0);
+
+- dbri->wait_send++;
+- dbri->wait_send &= 0xffff; /* restrict it to a 16 bit counter. */
+- *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+- *(cmd++) = DBRI_CMD(D_WAIT, 1, dbri->wait_send);
++#ifdef DBRI_DEBUG
++ if (cmd > dbri->cmdptr) {
++ s32 *ptr;
++
++ for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++)
++ dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
++ } else {
++ s32 *ptr = dbri->cmdptr;
+
+- /* Set command pointer and signal it is valid. */
+- sbus_writel(dbri->dma_dvma, dbri->regs + REG8);
+- reg = sbus_readl(dbri->regs + REG0);
+- reg |= D_P;
+- sbus_writel(reg, dbri->regs + REG0);
++ dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
++ ptr++;
++ dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
++ for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) {
++ dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
++ }
++ }
++#endif
++
++ /* Reread the last command */
++ tmp = sbus_readl(dbri->regs + REG0);
++ tmp |= D_P;
++ sbus_writel(tmp, dbri->regs + REG0);
+
+- /*spin_unlock(&dbri->lock); */
++ dbri->cmdptr = cmd;
++ spin_unlock(&dbri->cmdlock);
+ }
+
+ /* Lock must be held when calling this */
+ static void dbri_reset(struct snd_dbri * dbri)
+ {
+ int i;
++ u32 tmp;
+
+ dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n",
+ sbus_readl(dbri->regs + REG0),
+@@ -729,13 +736,20 @@ static void dbri_reset(struct snd_dbri *
+ sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */
+ for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)
+ udelay(10);
++
++ /* A brute approach - DBRI falls back to working burst size by itself
++ * On SS20 D_S does not work, so do not try so high. */
++ tmp = sbus_readl(dbri->regs + REG0);
++ tmp |= D_G | D_E;
++ tmp &= ~D_S;
++ sbus_writel(tmp, dbri->regs + REG0);
+ }
+
+ /* Lock must not be held before calling this */
+ static void dbri_initialize(struct snd_dbri * dbri)
+ {
+- volatile s32 *cmd;
+- u32 dma_addr, tmp;
++ s32 *cmd;
++ u32 dma_addr;
+ unsigned long flags;
+ int n;
+
+@@ -743,42 +757,34 @@ static void dbri_initialize(struct snd_d
+
+ dbri_reset(dbri);
+
+- cmd = dbri_cmdlock(dbri, NoGetLock);
+- dprintk(D_GEN, "init: cmd: %p, int: %p\n",
+- &dbri->dma->cmd[0], &dbri->dma->intr[0]);
++ /* Initialize pipes */
++ for (n = 0; n < DBRI_NO_PIPES; n++)
++ dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
+
++ spin_lock_init(&dbri->cmdlock);
+ /*
+ * Initialize the interrupt ringbuffer.
+ */
+- for (n = 0; n < DBRI_NO_INTS - 1; n++) {
+- dma_addr = dbri->dma_dvma;
+- dma_addr += dbri_dma_off(intr, ((n + 1) & DBRI_INT_BLK));
+- dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
+- }
+ dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
+- dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
++ dbri->dma->intr[0] = dma_addr;
+ dbri->dbri_irqp = 1;
+-
+- /* Initialize pipes */
+- for (n = 0; n < DBRI_NO_PIPES; n++)
+- dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
+-
+- /* A brute approach - DBRI falls back to working burst size by itself
+- * On SS20 D_S does not work, so do not try so high. */
+- tmp = sbus_readl(dbri->regs + REG0);
+- tmp |= D_G | D_E;
+- tmp &= ~D_S;
+- sbus_writel(tmp, dbri->regs + REG0);
+-
+ /*
+ * Set up the interrupt queue
+ */
+- dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
++ spin_lock(&dbri->cmdlock);
++ cmd = dbri->cmdptr = dbri->dma->cmd;
+ *(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
+ *(cmd++) = dma_addr;
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
++ dbri->cmdptr = cmd;
++ *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
++ *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
++ dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0);
++ sbus_writel(dma_addr, dbri->regs + REG8);
++ spin_unlock(&dbri->cmdlock);
+
+- dbri_cmdsend(dbri, cmd);
+ spin_unlock_irqrestore(&dbri->lock, flags);
++ dbri_cmdwait(dbri);
+ }
+
+ /*
+@@ -809,9 +815,9 @@ static void reset_pipe(struct snd_dbri *
+ {
+ int sdp;
+ int desc;
+- volatile int *cmd;
++ s32 *cmd;
+
+- if (pipe < 0 || pipe > 31) {
++ if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
+ printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n");
+ return;
+ }
+@@ -822,25 +828,29 @@ static void reset_pipe(struct snd_dbri *
+ return;
+ }
+
+- cmd = dbri_cmdlock(dbri, NoGetLock);
++ cmd = dbri_cmdlock(dbri, 3);
+ *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
+ *(cmd++) = 0;
+- dbri_cmdsend(dbri, cmd);
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
++ dbri_cmdsend(dbri, cmd, 3);
+
+ desc = dbri->pipes[pipe].first_desc;
+- while (desc != -1) {
+- dbri->descs[desc].inuse = 0;
+- desc = dbri->descs[desc].next;
+- }
++ if ( desc >= 0)
++ do {
++ dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0;
++ desc = dbri->next_desc[desc];
++ } while (desc != -1 && desc != dbri->pipes[pipe].first_desc);
+
+ dbri->pipes[pipe].desc = -1;
+ dbri->pipes[pipe].first_desc = -1;
+ }
+
+-/* FIXME: direction as an argument? */
++/*
++ * Lock must be held before calling this.
++ */
+ static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp)
+ {
+- if (pipe < 0 || pipe > 31) {
++ if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
+ printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n");
+ return;
+ }
+@@ -860,119 +870,87 @@ static void setup_pipe(struct snd_dbri *
+ dbri->pipes[pipe].sdp = sdp;
+ dbri->pipes[pipe].desc = -1;
+ dbri->pipes[pipe].first_desc = -1;
+- if (sdp & D_SDP_TO_SER)
+- dbri->pipes[pipe].direction = PIPEoutput;
+- else
+- dbri->pipes[pipe].direction = PIPEinput;
+
+ reset_pipe(dbri, pipe);
+ }
+
+-/* FIXME: direction not needed */
++/*
++ * Lock must be held before calling this.
++ */
+ static void link_time_slot(struct snd_dbri * dbri, int pipe,
+- enum in_or_out direction, int basepipe,
++ int prevpipe, int nextpipe,
+ int length, int cycle)
+ {
+- volatile s32 *cmd;
++ s32 *cmd;
+ int val;
+- int prevpipe;
+- int nextpipe;
+
+- if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) {
++ if (pipe < 0 || pipe > DBRI_MAX_PIPE
++ || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
++ || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
+ printk(KERN_ERR
+ "DBRI: link_time_slot called with illegal pipe number\n");
+ return;
+ }
+
+- if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) {
++ if (dbri->pipes[pipe].sdp == 0
++ || dbri->pipes[prevpipe].sdp == 0
++ || dbri->pipes[nextpipe].sdp == 0) {
+ printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n");
+ return;
+ }
+
+- /* Deal with CHI special case:
+- * "If transmission on edges 0 or 1 is desired, then cycle n
+- * (where n = # of bit times per frame...) must be used."
+- * - DBRI data sheet, page 11
+- */
+- if (basepipe == 16 && direction == PIPEoutput && cycle == 0)
+- cycle = dbri->chi_bpf;
+-
+- if (basepipe == pipe) {
+- prevpipe = pipe;
+- nextpipe = pipe;
+- } else {
+- /* We're not initializing a new linked list (basepipe != pipe),
+- * so run through the linked list and find where this pipe
+- * should be sloted in, based on its cycle. CHI confuses
+- * things a bit, since it has a single anchor for both its
+- * transmit and receive lists.
+- */
+- if (basepipe == 16) {
+- if (direction == PIPEinput) {
+- prevpipe = dbri->chi_in_pipe;
+- } else {
+- prevpipe = dbri->chi_out_pipe;
+- }
+- } else {
+- prevpipe = basepipe;
+- }
+-
+- nextpipe = dbri->pipes[prevpipe].nextpipe;
+-
+- while (dbri->pipes[nextpipe].cycle < cycle
+- && dbri->pipes[nextpipe].nextpipe != basepipe) {
+- prevpipe = nextpipe;
+- nextpipe = dbri->pipes[nextpipe].nextpipe;
+- }
+- }
+-
+- if (prevpipe == 16) {
+- if (direction == PIPEinput) {
+- dbri->chi_in_pipe = pipe;
+- } else {
+- dbri->chi_out_pipe = pipe;
+- }
+- } else {
+- dbri->pipes[prevpipe].nextpipe = pipe;
+- }
+-
++ dbri->pipes[prevpipe].nextpipe = pipe;
+ dbri->pipes[pipe].nextpipe = nextpipe;
+- dbri->pipes[pipe].cycle = cycle;
+ dbri->pipes[pipe].length = length;
+
+- cmd = dbri_cmdlock(dbri, NoGetLock);
++ cmd = dbri_cmdlock(dbri, 4);
+
+- if (direction == PIPEinput) {
+- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
++ if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
++ /* Deal with CHI special case:
++ * "If transmission on edges 0 or 1 is desired, then cycle n
++ * (where n = # of bit times per frame...) must be used."
++ * - DBRI data sheet, page 11
++ */
++ if (prevpipe == 16 && cycle == 0)
++ cycle = dbri->chi_bpf;
++
++ val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
++ *(cmd++) = 0;
+ *(cmd++) =
+ D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+- *(cmd++) = 0;
+ } else {
+- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
++ val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+- *(cmd++) = 0;
+ *(cmd++) =
+ D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
++ *(cmd++) = 0;
+ }
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+
+- dbri_cmdsend(dbri, cmd);
++ dbri_cmdsend(dbri, cmd, 4);
+ }
+
++#if 0
++/*
++ * Lock must be held before calling this.
++ */
+ static void unlink_time_slot(struct snd_dbri * dbri, int pipe,
+ enum in_or_out direction, int prevpipe,
+ int nextpipe)
+ {
+- volatile s32 *cmd;
++ s32 *cmd;
+ int val;
+
+- if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
++ if (pipe < 0 || pipe > DBRI_MAX_PIPE
++ || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
++ || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
+ printk(KERN_ERR
+ "DBRI: unlink_time_slot called with illegal pipe number\n");
+ return;
+ }
+
+- cmd = dbri_cmdlock(dbri, NoGetLock);
++ cmd = dbri_cmdlock(dbri, 4);
+
+ if (direction == PIPEinput) {
+ val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
+@@ -985,9 +963,11 @@ static void unlink_time_slot(struct snd_
+ *(cmd++) = 0;
+ *(cmd++) = D_TS_NEXT(nextpipe);
+ }
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+
+- dbri_cmdsend(dbri, cmd);
++ dbri_cmdsend(dbri, cmd, 4);
+ }
++#endif
+
+ /* xmit_fixed() / recv_fixed()
+ *
+@@ -1001,13 +981,16 @@ static void unlink_time_slot(struct snd_
+ * the actual time slot is. The interrupt handler takes care of bit
+ * ordering and alignment. An 8-bit time slot will always end up
+ * in the low-order 8 bits, filled either MSB-first or LSB-first,
+- * depending on the settings passed to setup_pipe()
++ * depending on the settings passed to setup_pipe().
++ *
++ * Lock must not be held before calling it.
+ */
+ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data)
+ {
+- volatile s32 *cmd;
++ s32 *cmd;
++ unsigned long flags;
+
+- if (pipe < 16 || pipe > 31) {
++ if (pipe < 16 || pipe > DBRI_MAX_PIPE) {
+ printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n");
+ return;
+ }
+@@ -1032,17 +1015,22 @@ static void xmit_fixed(struct snd_dbri *
+ if (dbri->pipes[pipe].sdp & D_SDP_MSB)
+ data = reverse_bytes(data, dbri->pipes[pipe].length);
+
+- cmd = dbri_cmdlock(dbri, GetLock);
++ cmd = dbri_cmdlock(dbri, 3);
+
+ *(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
+ *(cmd++) = data;
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
++
++ spin_lock_irqsave(&dbri->lock, flags);
++ dbri_cmdsend(dbri, cmd, 3);
++ spin_unlock_irqrestore(&dbri->lock, flags);
++ dbri_cmdwait(dbri);
+
+- dbri_cmdsend(dbri, cmd);
+ }
+
+ static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr)
+ {
+- if (pipe < 16 || pipe > 31) {
++ if (pipe < 16 || pipe > DBRI_MAX_PIPE) {
+ printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n");
+ return;
+ }
+@@ -1071,12 +1059,16 @@ static void recv_fixed(struct snd_dbri *
+ * and work by building chains of descriptors which identify the
+ * data buffers. Buffers too large for a single descriptor will
+ * be spread across multiple descriptors.
++ *
++ * All descriptors create a ring buffer.
++ *
++ * Lock must be held before calling this.
+ */
+ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period)
+ {
+ struct dbri_streaminfo *info = &dbri->stream_info[streamno];
+ __u32 dvma_buffer;
+- int desc = 0;
++ int desc;
+ int len;
+ int first_desc = -1;
+ int last_desc = -1;
+@@ -1119,11 +1111,23 @@ static int setup_descs(struct snd_dbri *
+ len &= ~3;
+ }
+
++ /* Free descriptors if pipe has any */
++ desc = dbri->pipes[info->pipe].first_desc;
++ if ( desc >= 0)
++ do {
++ dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0;
++ desc = dbri->next_desc[desc];
++ } while (desc != -1 && desc != dbri->pipes[info->pipe].first_desc);
++
++ dbri->pipes[info->pipe].desc = -1;
++ dbri->pipes[info->pipe].first_desc = -1;
++
++ desc = 0;
+ while (len > 0) {
+ int mylen;
+
+ for (; desc < DBRI_NO_DESCS; desc++) {
+- if (!dbri->descs[desc].inuse)
++ if (!dbri->dma->desc[desc].ba)
+ break;
+ }
+ if (desc == DBRI_NO_DESCS) {
+@@ -1131,37 +1135,33 @@ static int setup_descs(struct snd_dbri *
+ return -1;
+ }
+
+- if (len > DBRI_TD_MAXCNT) {
+- mylen = DBRI_TD_MAXCNT; /* 8KB - 1 */
+- } else {
++ if (len > DBRI_TD_MAXCNT)
++ mylen = DBRI_TD_MAXCNT; /* 8KB - 4 */
++ else
+ mylen = len;
+- }
+- if (mylen > period) {
++
++ if (mylen > period)
+ mylen = period;
+- }
+
+- dbri->descs[desc].inuse = 1;
+- dbri->descs[desc].next = -1;
++ dbri->next_desc[desc] = -1;
+ dbri->dma->desc[desc].ba = dvma_buffer;
+ dbri->dma->desc[desc].nda = 0;
+
+ if (streamno == DBRI_PLAY) {
+- dbri->descs[desc].len = mylen;
+ dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen);
+ dbri->dma->desc[desc].word4 = 0;
+- if (first_desc != -1)
+- dbri->dma->desc[desc].word1 |= DBRI_TD_M;
++ dbri->dma->desc[desc].word1 |=
++ DBRI_TD_F | DBRI_TD_B;
+ } else {
+- dbri->descs[desc].len = 0;
+ dbri->dma->desc[desc].word1 = 0;
+ dbri->dma->desc[desc].word4 =
+ DBRI_RD_B | DBRI_RD_BCNT(mylen);
+ }
+
+- if (first_desc == -1) {
++ if (first_desc == -1)
+ first_desc = desc;
+- } else {
+- dbri->descs[last_desc].next = desc;
++ else {
++ dbri->next_desc[last_desc] = desc;
+ dbri->dma->desc[last_desc].nda =
+ dbri->dma_dvma + dbri_dma_off(desc, desc);
+ }
+@@ -1176,21 +1176,24 @@ static int setup_descs(struct snd_dbri *
+ return -1;
+ }
+
+- dbri->dma->desc[last_desc].word1 &= ~DBRI_TD_M;
+- if (streamno == DBRI_PLAY) {
+- dbri->dma->desc[last_desc].word1 |=
+- DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
+- }
++ dbri->dma->desc[last_desc].nda =
++ dbri->dma_dvma + dbri_dma_off(desc, first_desc);
++ dbri->next_desc[last_desc] = first_desc;
+ dbri->pipes[info->pipe].first_desc = first_desc;
+ dbri->pipes[info->pipe].desc = first_desc;
+
+- for (desc = first_desc; desc != -1; desc = dbri->descs[desc].next) {
++#ifdef DBRI_DEBUG
++ for (desc = first_desc; desc != -1; ) {
+ dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n",
+ desc,
+ dbri->dma->desc[desc].word1,
+ dbri->dma->desc[desc].ba,
+ dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4);
++ desc = dbri->next_desc[desc];
++ if ( desc == first_desc )
++ break;
+ }
++#endif
+ return 0;
+ }
+
+@@ -1207,56 +1210,30 @@ multiplexed serial interface which the D
+
+ enum master_or_slave { CHImaster, CHIslave };
+
++/*
++ * Lock must not be held before calling it.
++ */
+ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave,
+ int bits_per_frame)
+ {
+- volatile s32 *cmd;
++ s32 *cmd;
+ int val;
+- static int chi_initialized = 0; /* FIXME: mutex? */
+-
+- if (!chi_initialized) {
+-
+- cmd = dbri_cmdlock(dbri, GetLock);
+-
+- /* Set CHI Anchor: Pipe 16 */
+-
+- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);
+- *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+- *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+- *(cmd++) = 0;
+-
+- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);
+- *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+- *(cmd++) = 0;
+- *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+
+- dbri->pipes[16].sdp = 1;
+- dbri->pipes[16].nextpipe = 16;
+- dbri->chi_in_pipe = 16;
+- dbri->chi_out_pipe = 16;
++ /* Set CHI Anchor: Pipe 16 */
+
+-#if 0
+- chi_initialized++;
+-#endif
+- } else {
+- int pipe;
++ cmd = dbri_cmdlock(dbri, 4);
++ val = D_DTS_VO | D_DTS_VI | D_DTS_INS
++ | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16);
++ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
++ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
++ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
++ dbri_cmdsend(dbri, cmd, 4);
+
+- for (pipe = dbri->chi_in_pipe;
+- pipe != 16; pipe = dbri->pipes[pipe].nextpipe) {
+- unlink_time_slot(dbri, pipe, PIPEinput,
+- 16, dbri->pipes[pipe].nextpipe);
+- }
+- for (pipe = dbri->chi_out_pipe;
+- pipe != 16; pipe = dbri->pipes[pipe].nextpipe) {
+- unlink_time_slot(dbri, pipe, PIPEoutput,
+- 16, dbri->pipes[pipe].nextpipe);
+- }
++ dbri->pipes[16].sdp = 1;
++ dbri->pipes[16].nextpipe = 16;
+
+- dbri->chi_in_pipe = 16;
+- dbri->chi_out_pipe = 16;
+-
+- cmd = dbri_cmdlock(dbri, GetLock);
+- }
++ cmd = dbri_cmdlock(dbri, 4);
+
+ if (master_or_slave == CHIslave) {
+ /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
+@@ -1295,8 +1272,9 @@ static void reset_chi(struct snd_dbri *
+
+ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+ *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN);
++ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+
+- dbri_cmdsend(dbri, cmd);
++ dbri_cmdsend(dbri, cmd, 4);
+ }
+
+ /*
+@@ -1307,9 +1285,14 @@ static void reset_chi(struct snd_dbri *
+ In the standard SPARC audio configuration, the CS4215 codec is attached
+ to the DBRI via the CHI interface and few of the DBRI's PIO pins.
+
++ * Lock must not be held before calling it.
++
+ */
+ static void cs4215_setup_pipes(struct snd_dbri * dbri)
+ {
++ unsigned long flags;
++
++ spin_lock_irqsave(&dbri->lock, flags);
+ /*
+ * Data mode:
+ * Pipe 4: Send timeslots 1-4 (audio data)
+@@ -1333,6 +1316,9 @@ static void cs4215_setup_pipes(struct sn
+ setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+ setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
++ spin_unlock_irqrestore(&dbri->lock, flags);
++
++ dbri_cmdwait(dbri);
+ }
+
+ static int cs4215_init_data(struct cs4215 *mm)
+@@ -1364,7 +1350,7 @@ static int cs4215_init_data(struct cs421
+ mm->status = 0;
+ mm->version = 0xff;
+ mm->precision = 8; /* For ULAW */
+- mm->channels = 2;
++ mm->channels = 1;
+
+ return 0;
+ }
+@@ -1379,16 +1365,8 @@ static void cs4215_setdata(struct snd_db
+ } else {
+ /* Start by setting the playback attenuation. */
+ struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];
+- int left_gain = info->left_gain % 64;
+- int right_gain = info->right_gain % 64;
+-
+- if (info->balance < DBRI_MID_BALANCE) {
+- right_gain *= info->balance;
+- right_gain /= DBRI_MID_BALANCE;
+- } else {
+- left_gain *= DBRI_RIGHT_BALANCE - info->balance;
+- left_gain /= DBRI_MID_BALANCE;
+- }
++ int left_gain = info->left_gain & 0x3f;
++ int right_gain = info->right_gain & 0x3f;
+
+ dbri->mm.data[0] &= ~0x3f; /* Reset the volume bits */
+ dbri->mm.data[1] &= ~0x3f;
+@@ -1397,8 +1375,8 @@ static void cs4215_setdata(struct snd_db
+
+ /* Now set the recording gain. */
+ info = &dbri->stream_info[DBRI_REC];
+- left_gain = info->left_gain % 16;
+- right_gain = info->right_gain % 16;
++ left_gain = info->left_gain & 0xf;
++ right_gain = info->right_gain & 0xf;
+ dbri->mm.data[2] |= CS4215_LG(left_gain);
+ dbri->mm.data[3] |= CS4215_RG(right_gain);
+ }
+@@ -1413,6 +1391,7 @@ static void cs4215_open(struct snd_dbri
+ {
+ int data_width;
+ u32 tmp;
++ unsigned long flags;
+
+ dprintk(D_MM, "cs4215_open: %d channels, %d bits\n",
+ dbri->mm.channels, dbri->mm.precision);
+@@ -1437,6 +1416,7 @@ static void cs4215_open(struct snd_dbri
+ * bits. The CS4215, it seems, observes TSIN (the delayed signal)
+ * even if it's the CHI master. Don't ask me...
+ */
++ spin_lock_irqsave(&dbri->lock, flags);
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp &= ~(D_C); /* Disable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
+@@ -1455,15 +1435,16 @@ static void cs4215_open(struct snd_dbri
+ */
+ data_width = dbri->mm.channels * dbri->mm.precision;
+
+- link_time_slot(dbri, 20, PIPEoutput, 16, 32, dbri->mm.offset + 32);
+- link_time_slot(dbri, 4, PIPEoutput, 16, data_width, dbri->mm.offset);
+- link_time_slot(dbri, 6, PIPEinput, 16, data_width, dbri->mm.offset);
+- link_time_slot(dbri, 21, PIPEinput, 16, 16, dbri->mm.offset + 40);
++ link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset);
++ link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32);
++ link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset);
++ link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40);
+
+ /* FIXME: enable CHI after _setdata? */
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp |= D_C; /* Enable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
++ spin_unlock_irqrestore(&dbri->lock, flags);
+
+ cs4215_setdata(dbri, 0);
+ }
+@@ -1475,6 +1456,7 @@ static int cs4215_setctrl(struct snd_dbr
+ {
+ int i, val;
+ u32 tmp;
++ unsigned long flags;
+
+ /* FIXME - let the CPU do something useful during these delays */
+
+@@ -1511,6 +1493,7 @@ static int cs4215_setctrl(struct snd_dbr
+ * done in hardware by a TI 248 that delays the DBRI->4215
+ * frame sync signal by eight clock cycles. Anybody know why?
+ */
++ spin_lock_irqsave(&dbri->lock, flags);
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp &= ~D_C; /* Disable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
+@@ -1524,17 +1507,20 @@ static int cs4215_setctrl(struct snd_dbr
+ * Pipe 19: Receive timeslot 7 (version).
+ */
+
+- link_time_slot(dbri, 17, PIPEoutput, 16, 32, dbri->mm.offset);
+- link_time_slot(dbri, 18, PIPEinput, 16, 8, dbri->mm.offset);
+- link_time_slot(dbri, 19, PIPEinput, 16, 8, dbri->mm.offset + 48);
++ link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset);
++ link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset);
++ link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48);
++ spin_unlock_irqrestore(&dbri->lock, flags);
+
+ /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
+ dbri->mm.ctrl[0] &= ~CS4215_CLB;
+ xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
+
++ spin_lock_irqsave(&dbri->lock, flags);
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp |= D_C; /* Enable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
++ spin_unlock_irqrestore(&dbri->lock, flags);
+
+ for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) {
+ msleep_interruptible(1);
+@@ -1614,8 +1600,7 @@ static int cs4215_prepare(struct snd_dbr
+ CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal;
+
+ dbri->mm.channels = channels;
+- /* Stereo bit: 8 bit stereo not working yet. */
+- if ((channels > 1) && (dbri->mm.precision == 16))
++ if (channels == 2)
+ dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
+
+ ret = cs4215_setctrl(dbri);
+@@ -1655,7 +1640,6 @@ static int cs4215_init(struct snd_dbri *
+ }
+
+ cs4215_setup_pipes(dbri);
+-
+ cs4215_init_data(&dbri->mm);
+
+ /* Enable capture of the status & version timeslots. */
+@@ -1684,88 +1668,71 @@ buffer and calls dbri_process_one_interr
+ Complicated interrupts are handled by dedicated functions (which
+ appear first in this file). Any pending interrupts can be serviced by
+ calling dbri_process_interrupt_buffer(), which works even if the CPU's
+-interrupts are disabled. This function is used by dbri_cmdlock()
+-to make sure we're synced up with the chip before each command sequence,
+-even if we're running cli'ed.
++interrupts are disabled.
+
+ */
+
+ /* xmit_descs()
+ *
+- * Transmit the current TD's for recording/playing, if needed.
++ * Starts transmiting the current TD's for recording/playing.
+ * For playback, ALSA has filled the DMA memory with new data (we hope).
+ */
+-static void xmit_descs(unsigned long data)
++static void xmit_descs(struct snd_dbri *dbri)
+ {
+- struct snd_dbri *dbri = (struct snd_dbri *) data;
+ struct dbri_streaminfo *info;
+- volatile s32 *cmd;
++ s32 *cmd;
+ unsigned long flags;
+ int first_td;
+
+ if (dbri == NULL)
+ return; /* Disabled */
+
+- /* First check the recording stream for buffer overflow */
+ info = &dbri->stream_info[DBRI_REC];
+ spin_lock_irqsave(&dbri->lock, flags);
+
+- if ((info->left >= info->size) && (info->pipe >= 0)) {
++ if (info->pipe >= 0) {
+ first_td = dbri->pipes[info->pipe].first_desc;
+
+ dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td);
+
+ /* Stream could be closed by the time we run. */
+- if (first_td < 0) {
+- goto play;
+- }
+-
+- cmd = dbri_cmdlock(dbri, NoGetLock);
+- *(cmd++) = DBRI_CMD(D_SDP, 0,
+- dbri->pipes[info->pipe].sdp
+- | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+- *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
+- dbri_cmdsend(dbri, cmd);
++ if (first_td >= 0) {
++ cmd = dbri_cmdlock(dbri, 2);
++ *(cmd++) = DBRI_CMD(D_SDP, 0,
++ dbri->pipes[info->pipe].sdp
++ | D_SDP_P | D_SDP_EVERY | D_SDP_C);
++ *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
++ dbri_cmdsend(dbri, cmd, 2);
+
+- /* Reset our admin of the pipe & bytes read. */
+- dbri->pipes[info->pipe].desc = first_td;
+- info->left = 0;
++ /* Reset our admin of the pipe. */
++ dbri->pipes[info->pipe].desc = first_td;
++ }
+ }
+
+-play:
+- spin_unlock_irqrestore(&dbri->lock, flags);
+-
+- /* Now check the playback stream for buffer underflow */
+ info = &dbri->stream_info[DBRI_PLAY];
+- spin_lock_irqsave(&dbri->lock, flags);
+
+- if ((info->left <= 0) && (info->pipe >= 0)) {
++ if (info->pipe >= 0) {
+ first_td = dbri->pipes[info->pipe].first_desc;
+
+ dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td);
+
+ /* Stream could be closed by the time we run. */
+- if (first_td < 0) {
+- spin_unlock_irqrestore(&dbri->lock, flags);
+- return;
+- }
+-
+- cmd = dbri_cmdlock(dbri, NoGetLock);
+- *(cmd++) = DBRI_CMD(D_SDP, 0,
+- dbri->pipes[info->pipe].sdp
+- | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+- *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
+- dbri_cmdsend(dbri, cmd);
++ if (first_td >= 0) {
++ cmd = dbri_cmdlock(dbri, 2);
++ *(cmd++) = DBRI_CMD(D_SDP, 0,
++ dbri->pipes[info->pipe].sdp
++ | D_SDP_P | D_SDP_EVERY | D_SDP_C);
++ *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
++ dbri_cmdsend(dbri, cmd, 2);
+
+- /* Reset our admin of the pipe & bytes written. */
+- dbri->pipes[info->pipe].desc = first_td;
+- info->left = info->size;
++ /* Reset our admin of the pipe. */
++ dbri->pipes[info->pipe].desc = first_td;
++ }
+ }
++
+ spin_unlock_irqrestore(&dbri->lock, flags);
+ }
+
+-static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0);
+-
+ /* transmission_complete_intr()
+ *
+ * Called by main interrupt handler when DBRI signals transmission complete
+@@ -1775,9 +1742,9 @@ static DECLARE_TASKLET(xmit_descs_task,
+ * them as available. Stops when the first descriptor is found without
+ * TBC (Transmit Buffer Complete) set, or we've run through them all.
+ *
+- * The DMA buffers are not released, but re-used. Since the transmit buffer
+- * descriptors are not clobbered, they can be re-submitted as is. This is
+- * done by the xmit_descs() tasklet above since that could take longer.
++ * The DMA buffers are not released. They form a ring buffer and
++ * they are filled by ALSA while others are transmitted by DMA.
++ *
+ */
+
+ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe)
+@@ -1803,21 +1770,9 @@ static void transmission_complete_intr(s
+ dprintk(D_INT, "TD %d, status 0x%02x\n", td, status);
+
+ dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */
+- info->offset += dbri->descs[td].len;
+- info->left -= dbri->descs[td].len;
+-
+- /* On the last TD, transmit them all again. */
+- if (dbri->descs[td].next == -1) {
+- if (info->left > 0) {
+- printk(KERN_WARNING
+- "%d bytes left after last transfer.\n",
+- info->left);
+- info->left = 0;
+- }
+- tasklet_schedule(&xmit_descs_task);
+- }
++ info->offset += DBRI_RD_CNT(dbri->dma->desc[td].word1);
+
+- td = dbri->descs[td].next;
++ td = dbri->next_desc[td];
+ dbri->pipes[pipe].desc = td;
+ }
+
+@@ -1841,30 +1796,18 @@ static void reception_complete_intr(stru
+ return;
+ }
+
+- dbri->descs[rd].inuse = 0;
+- dbri->pipes[pipe].desc = dbri->descs[rd].next;
++ dbri->pipes[pipe].desc = dbri->next_desc[rd];
+ status = dbri->dma->desc[rd].word1;
+ dbri->dma->desc[rd].word1 = 0; /* Reset it for next time. */
+
+ info = &dbri->stream_info[DBRI_REC];
+ info->offset += DBRI_RD_CNT(status);
+- info->left += DBRI_RD_CNT(status);
+
+ /* FIXME: Check status */
+
+ dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n",
+ rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));
+
+- /* On the last TD, transmit them all again. */
+- if (dbri->descs[rd].next == -1) {
+- if (info->left > info->size) {
+- printk(KERN_WARNING
+- "%d bytes recorded in %d size buffer.\n",
+- info->left, info->size);
+- }
+- tasklet_schedule(&xmit_descs_task);
+- }
+-
+ /* Notify ALSA */
+ if (spin_is_locked(&dbri->lock)) {
+ spin_unlock(&dbri->lock);
+@@ -1892,16 +1835,11 @@ static void dbri_process_one_interrupt(s
+ channel, code, rval);
+ }
+
+- if (channel == D_INTR_CMD && command == D_WAIT) {
+- dbri->wait_ackd = val;
+- if (dbri->wait_send != val) {
+- printk(KERN_ERR "Processing wait command %d when %d was send.\n",
+- val, dbri->wait_send);
+- }
+- return;
+- }
+-
+ switch (code) {
++ case D_INTR_CMDI:
++ if (command != D_WAIT)
++ printk(KERN_ERR "DBRI: Command read interrupt\n");
++ break;
+ case D_INTR_BRDY:
+ reception_complete_intr(dbri, channel);
+ break;
+@@ -1914,8 +1852,10 @@ static void dbri_process_one_interrupt(s
+ * resend SDP command with clear pipe bit (C) set
+ */
+ {
+- volatile s32 *cmd;
+-
++ /* FIXME: do something useful in case of underrun */
++ printk(KERN_ERR "DBRI: Underrun error\n");
++#if 0
++ s32 *cmd;
+ int pipe = channel;
+ int td = dbri->pipes[pipe].desc;
+
+@@ -1926,6 +1866,7 @@ static void dbri_process_one_interrupt(s
+ | D_SDP_P | D_SDP_C | D_SDP_2SAME);
+ *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td);
+ dbri_cmdsend(dbri, cmd);
++#endif
+ }
+ break;
+ case D_INTR_FXDT:
+@@ -1946,9 +1887,7 @@ static void dbri_process_one_interrupt(s
+ /* dbri_process_interrupt_buffer advances through the DBRI's interrupt
+ * buffer until it finds a zero word (indicating nothing more to do
+ * right now). Non-zero words require processing and are handed off
+- * to dbri_process_one_interrupt AFTER advancing the pointer. This
+- * order is important since we might recurse back into this function
+- * and need to make sure the pointer has been advanced first.
++ * to dbri_process_one_interrupt AFTER advancing the pointer.
+ */
+ static void dbri_process_interrupt_buffer(struct snd_dbri * dbri)
+ {
+@@ -1957,17 +1896,14 @@ static void dbri_process_interrupt_buffe
+ while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
+ dbri->dma->intr[dbri->dbri_irqp] = 0;
+ dbri->dbri_irqp++;
+- if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
++ if (dbri->dbri_irqp == DBRI_INT_BLK)
+ dbri->dbri_irqp = 1;
+- else if ((dbri->dbri_irqp & (DBRI_INT_BLK - 1)) == 0)
+- dbri->dbri_irqp++;
+
+ dbri_process_one_interrupt(dbri, x);
+ }
+ }
+
+-static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id,
+- struct pt_regs *regs)
++static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id)
+ {
+ struct snd_dbri *dbri = dev_id;
+ static int errcnt = 0;
+@@ -2020,8 +1956,6 @@ static irqreturn_t snd_dbri_interrupt(in
+
+ dbri_process_interrupt_buffer(dbri);
+
+- /* FIXME: Write 0 into regs to ACK interrupt */
+-
+ spin_unlock(&dbri->lock);
+
+ return IRQ_HANDLED;
+@@ -2039,8 +1973,8 @@ static struct snd_pcm_hardware snd_dbri_
+ SNDRV_PCM_FMTBIT_A_LAW |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_BE,
+- .rates = SNDRV_PCM_RATE_8000_48000,
+- .rate_min = 8000,
++ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512,
++ .rate_min = 5512,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+@@ -2051,6 +1985,39 @@ static struct snd_pcm_hardware snd_dbri_
+ .periods_max = 1024,
+ };
+
++static int snd_hw_rule_format(struct snd_pcm_hw_params *params,
++ struct snd_pcm_hw_rule *rule)
++{
++ struct snd_interval *c = hw_param_interval(params,
++ SNDRV_PCM_HW_PARAM_CHANNELS);
++ struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
++ struct snd_mask fmt;
++
++ snd_mask_any(&fmt);
++ if (c->min > 1) {
++ fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_BE;
++ return snd_mask_refine(f, &fmt);
++ }
++ return 0;
++}
++
++static int snd_hw_rule_channels(struct snd_pcm_hw_params *params,
++ struct snd_pcm_hw_rule *rule)
++{
++ struct snd_interval *c = hw_param_interval(params,
++ SNDRV_PCM_HW_PARAM_CHANNELS);
++ struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
++ struct snd_interval ch;
++
++ snd_interval_any(&ch);
++ if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) {
++ ch.min = ch.max = 1;
++ ch.integer = 1;
++ return snd_interval_refine(c, &ch);
++ }
++ return 0;
++}
++
+ static int snd_dbri_open(struct snd_pcm_substream *substream)
+ {
+ struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
+@@ -2063,12 +2030,19 @@ static int snd_dbri_open(struct snd_pcm_
+
+ spin_lock_irqsave(&dbri->lock, flags);
+ info->substream = substream;
+- info->left = 0;
+ info->offset = 0;
+ info->dvma_buffer = 0;
+ info->pipe = -1;
+ spin_unlock_irqrestore(&dbri->lock, flags);
+
++ snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_CHANNELS,
++ snd_hw_rule_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT,
++ -1);
++ snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_FORMAT,
++ snd_hw_rule_channels, NULL,
++ SNDRV_PCM_HW_PARAM_CHANNELS,
++ -1);
++
+ cs4215_open(dbri);
+
+ return 0;
+@@ -2081,7 +2055,6 @@ static int snd_dbri_close(struct snd_pcm
+
+ dprintk(D_USR, "close audio output.\n");
+ info->substream = NULL;
+- info->left = 0;
+ info->offset = 0;
+
+ return 0;
+@@ -2134,6 +2107,7 @@ static int snd_dbri_hw_free(struct snd_p
+ struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
+ struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
+ int direction;
++
+ dprintk(D_USR, "hw_free.\n");
+
+ /* hw_free can get called multiple times. Only unmap the DMA once.
+@@ -2148,7 +2122,10 @@ static int snd_dbri_hw_free(struct snd_p
+ substream->runtime->buffer_size, direction);
+ info->dvma_buffer = 0;
+ }
+- info->pipe = -1;
++ if (info->pipe != -1) {
++ reset_pipe(dbri, info->pipe);
++ info->pipe = -1;
++ }
+
+ return snd_pcm_lib_free_pages(substream);
+ }
+@@ -2157,18 +2134,16 @@ static int snd_dbri_prepare(struct snd_p
+ {
+ struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
+ struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
+- struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+
+ info->size = snd_pcm_lib_buffer_bytes(substream);
+ if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+ info->pipe = 4; /* Send pipe */
+- else {
++ else
+ info->pipe = 6; /* Receive pipe */
+- info->left = info->size; /* To trigger submittal */
+- }
+
+ spin_lock_irq(&dbri->lock);
++ info->offset = 0;
+
+ /* Setup the all the transmit/receive desciptors to cover the
+ * whole DMA buffer.
+@@ -2176,8 +2151,6 @@ static int snd_dbri_prepare(struct snd_p
+ ret = setup_descs(dbri, DBRI_STREAMNO(substream),
+ snd_pcm_lib_period_bytes(substream));
+
+- runtime->stop_threshold = DBRI_TD_MAXCNT / runtime->channels;
+-
+ spin_unlock_irq(&dbri->lock);
+
+ dprintk(D_USR, "prepare audio output. %d bytes\n", info->size);
+@@ -2194,14 +2167,11 @@ static int snd_dbri_trigger(struct snd_p
+ case SNDRV_PCM_TRIGGER_START:
+ dprintk(D_USR, "start audio, period is %d bytes\n",
+ (int)snd_pcm_lib_period_bytes(substream));
+- /* Enable & schedule the tasklet that re-submits the TDs. */
+- xmit_descs_task.data = (unsigned long)dbri;
+- tasklet_schedule(&xmit_descs_task);
++ /* Re-submit the TDs. */
++ xmit_descs(dbri);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ dprintk(D_USR, "stop audio.\n");
+- /* Make the tasklet bail out immediately. */
+- xmit_descs_task.data = 0;
+ reset_pipe(dbri, info->pipe);
+ break;
+ default:
+@@ -2219,8 +2189,8 @@ static snd_pcm_uframes_t snd_dbri_pointe
+
+ ret = bytes_to_frames(substream->runtime, info->offset)
+ % substream->runtime->buffer_size;
+- dprintk(D_USR, "I/O pointer: %ld frames, %d bytes left.\n",
+- ret, info->left);
++ dprintk(D_USR, "I/O pointer: %ld frames of %ld.\n",
++ ret, substream->runtime->buffer_size);
+ return ret;
+ }
+
+@@ -2254,7 +2224,6 @@ static int __devinit snd_dbri_pcm(struct
+ pcm->private_data = dbri;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, dbri->card->shortname);
+- dbri->pcm = pcm;
+
+ if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+@@ -2303,7 +2272,6 @@ static int snd_cs4215_put_volume(struct
+ {
+ struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
+ struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value];
+- unsigned long flags;
+ int changed = 0;
+
+ if (info->left_gain != ucontrol->value.integer.value[0]) {
+@@ -2318,13 +2286,9 @@ static int snd_cs4215_put_volume(struct
+ /* First mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+- spin_lock_irqsave(&dbri->lock, flags);
+-
+ cs4215_setdata(dbri, 1);
+ udelay(125);
+ cs4215_setdata(dbri, 0);
+-
+- spin_unlock_irqrestore(&dbri->lock, flags);
+ }
+ return changed;
+ }
+@@ -2371,7 +2335,6 @@ static int snd_cs4215_put_single(struct
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
+- unsigned long flags;
+ int elem = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0xff;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+@@ -2404,13 +2367,9 @@ static int snd_cs4215_put_single(struct
+ /* First mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+- spin_lock_irqsave(&dbri->lock, flags);
+-
+ cs4215_setdata(dbri, 1);
+ udelay(125);
+ cs4215_setdata(dbri, 0);
+-
+- spin_unlock_irqrestore(&dbri->lock, flags);
+ }
+ return changed;
+ }
+@@ -2452,8 +2411,6 @@ static struct snd_kcontrol_new dbri_cont
+ CS4215_SINGLE("Mic boost", 4, 4, 1, 1)
+ };
+
+-#define NUM_CS4215_CONTROLS (sizeof(dbri_controls)/sizeof(struct snd_kcontrol_new))
+-
+ static int __init snd_dbri_mixer(struct snd_dbri * dbri)
+ {
+ struct snd_card *card;
+@@ -2464,7 +2421,7 @@ static int __init snd_dbri_mixer(struct
+ card = dbri->card;
+ strcpy(card->mixername, card->shortname);
+
+- for (idx = 0; idx < NUM_CS4215_CONTROLS; idx++) {
++ for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) {
+ if ((err = snd_ctl_add(card,
+ snd_ctl_new1(&dbri_controls[idx], dbri))) < 0)
+ return err;
+@@ -2473,7 +2430,6 @@ static int __init snd_dbri_mixer(struct
+ for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) {
+ dbri->stream_info[idx].left_gain = 0;
+ dbri->stream_info[idx].right_gain = 0;
+- dbri->stream_info[idx].balance = DBRI_MID_BALANCE;
+ }
+
+ return 0;
+@@ -2505,12 +2461,11 @@ static void dbri_debug_read(struct snd_i
+ struct dbri_pipe *pptr = &dbri->pipes[pipe];
+ snd_iprintf(buffer,
+ "Pipe %d: %s SDP=0x%x desc=%d, "
+- "len=%d @ %d prev: %d next %d\n",
++ "len=%d next %d\n",
+ pipe,
+- (pptr->direction ==
+- PIPEinput ? "input" : "output"), pptr->sdp,
+- pptr->desc, pptr->length, pptr->cycle,
+- pptr->prevpipe, pptr->nextpipe);
++ ((pptr->sdp & D_SDP_TO_SER) ? "output" : "input"),
++ pptr->sdp, pptr->desc,
++ pptr->length, pptr->nextpipe);
+ }
+ }
+ }
+@@ -2549,7 +2504,6 @@ static int __init snd_dbri_create(struct
+ dbri->card = card;
+ dbri->sdev = sdev;
+ dbri->irq = irq->pri;
+- dbri->dbri_version = sdev->prom_name[9];
+
+ dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
+ &dbri->dma_dvma);
+@@ -2669,7 +2623,7 @@ static int __init dbri_attach(int prom_n
+
+ printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
+ dev, dbri->regs,
+- dbri->irq, dbri->dbri_version, dbri->mm.version);
++ dbri->irq, sdev->prom_name[9], dbri->mm.version);
+ dev++;
+
+ return 0;
+diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c
+index 58b9601..59144ec 100644
+--- a/sound/synth/emux/emux_proc.c
++++ b/sound/synth/emux/emux_proc.c
+@@ -128,10 +128,8 @@ void snd_emux_proc_init(struct snd_emux
+
+ void snd_emux_proc_free(struct snd_emux *emu)
+ {
+- if (emu->proc) {
+- snd_info_unregister(emu->proc);
+- emu->proc = NULL;
+- }
++ snd_info_free_entry(emu->proc);
++ emu->proc = NULL;
+ }
+
+ #endif /* CONFIG_PROC_FS */
+diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
+index 1b7f499..c82b01c 100644
+--- a/sound/usb/usbaudio.c
++++ b/sound/usb/usbaudio.c
+@@ -68,7 +68,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEF
+ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
+ static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
+ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
+-static int nrpacks = 4; /* max. number of packets per urb */
++static int nrpacks = 8; /* max. number of packets per urb */
+ static int async_unlink = 1;
+ static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
+
+@@ -100,7 +100,7 @@ MODULE_PARM_DESC(device_setup, "Specific
+ *
+ */
+
+-#define MAX_PACKS 10
++#define MAX_PACKS 20
+ #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
+ #define MAX_URBS 8
+ #define SYNC_URBS 4 /* always four urbs for sync */
+@@ -123,6 +123,7 @@ struct audioformat {
+ unsigned int rate_min, rate_max; /* min/max rates */
+ unsigned int nr_rates; /* number of rate table entries */
+ unsigned int *rate_table; /* rate table */
++ unsigned int needs_knot; /* any unusual rates? */
+ };
+
+ struct snd_usb_substream;
+@@ -652,7 +653,7 @@ static struct snd_urb_ops audio_urb_ops_
+ /*
+ * complete callback from data urb
+ */
+-static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
++static void snd_complete_urb(struct urb *urb)
+ {
+ struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_usb_substream *subs = ctx->subs;
+@@ -675,7 +676,7 @@ static void snd_complete_urb(struct urb
+ /*
+ * complete callback from sync urb
+ */
+-static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
++static void snd_complete_sync_urb(struct urb *urb)
+ {
+ struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_usb_substream *subs = ctx->subs;
+@@ -1759,6 +1760,9 @@ static int check_hw_params_convention(st
+ }
+ channels[f->format] |= (1 << f->channels);
+ rates[f->format] |= f->rates;
++ /* needs knot? */
++ if (f->needs_knot)
++ goto __out;
+ }
+ /* check whether channels and rates match for all formats */
+ cmaster = rmaster = 0;
+@@ -1799,6 +1803,38 @@ static int check_hw_params_convention(st
+ return err;
+ }
+
++/*
++ * If the device supports unusual bit rates, does the request meet these?
++ */
++static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
++ struct snd_usb_substream *subs)
++{
++ struct list_head *p;
++ struct snd_pcm_hw_constraint_list constraints_rates;
++ int err;
++
++ list_for_each(p, &subs->fmt_list) {
++ struct audioformat *fp;
++ fp = list_entry(p, struct audioformat, list);
++
++ if (!fp->needs_knot)
++ continue;
++
++ constraints_rates.count = fp->nr_rates;
++ constraints_rates.list = fp->rate_table;
++ constraints_rates.mask = 0;
++
++ err = snd_pcm_hw_constraint_list(runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &constraints_rates);
++
++ if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
+
+ /*
+ * set up the runtime hardware information.
+@@ -1861,6 +1897,8 @@ static int setup_hw_info(struct snd_pcm_
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ -1)) < 0)
+ return err;
++ if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
++ return err;
+ }
+ return 0;
+ }
+@@ -2008,10 +2046,9 @@ int snd_usb_ctl_msg(struct usb_device *d
+ void *buf = NULL;
+
+ if (size > 0) {
+- buf = kmalloc(size, GFP_KERNEL);
++ buf = kmemdup(data, size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+- memcpy(buf, data, size);
+ }
+ err = usb_control_msg(dev, pipe, request, requesttype,
+ value, index, buf, size, timeout);
+@@ -2049,7 +2086,7 @@ static struct usb_driver usb_audio_drive
+ };
+
+
+-#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS)
++#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
+ /*
+ * proc interface for list the supported pcm formats
+@@ -2406,6 +2443,7 @@ static int parse_audio_format_rates(stru
+ unsigned char *fmt, int offset)
+ {
+ int nr_rates = fmt[offset];
++ int found;
+ if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
+ snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
+ chip->dev->devnum, fp->iface, fp->altsetting);
+@@ -2428,6 +2466,7 @@ static int parse_audio_format_rates(stru
+ return -1;
+ }
+
++ fp->needs_knot = 0;
+ fp->nr_rates = nr_rates;
+ fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
+ for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
+@@ -2436,13 +2475,19 @@ static int parse_audio_format_rates(stru
+ fp->rate_min = rate;
+ else if (rate > fp->rate_max)
+ fp->rate_max = rate;
++ found = 0;
+ for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
+ if (rate == conv_rates[c]) {
++ found = 1;
+ fp->rates |= (1 << c);
+ break;
+ }
+ }
++ if (!found)
++ fp->needs_knot = 1;
+ }
++ if (fp->needs_knot)
++ fp->rates |= SNDRV_PCM_RATE_KNOT;
+ } else {
+ /* continuous rates */
+ fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
+@@ -2800,12 +2845,11 @@ static int create_fixed_stream_quirk(str
+ int stream, err;
+ int *rate_table = NULL;
+
+- fp = kmalloc(sizeof(*fp), GFP_KERNEL);
++ fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
+ if (! fp) {
+- snd_printk(KERN_ERR "cannot malloc\n");
++ snd_printk(KERN_ERR "cannot memdup\n");
+ return -ENOMEM;
+ }
+- memcpy(fp, quirk->data, sizeof(*fp));
+ if (fp->nr_rates > 0) {
+ rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
+ if (!rate_table) {
+@@ -2983,10 +3027,9 @@ static int create_ua1000_quirk(struct sn
+ altsd->bNumEndpoints != 1)
+ return -ENXIO;
+
+- fp = kmalloc(sizeof(*fp), GFP_KERNEL);
++ fp = kmemdup(&ua1000_format, sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
+- memcpy(fp, &ua1000_format, sizeof(*fp));
+
+ fp->channels = alts->extra[4];
+ fp->iface = altsd->bInterfaceNumber;
+@@ -3499,7 +3542,7 @@ static void snd_usb_audio_disconnect(str
+ }
+ usb_chip[chip->index] = NULL;
+ mutex_unlock(®ister_mutex);
+- snd_card_free(card);
++ snd_card_free_when_closed(card);
+ } else {
+ mutex_unlock(®ister_mutex);
+ }
+diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
+index 5105b6b..b7c5e59 100644
+--- a/sound/usb/usbmidi.c
++++ b/sound/usb/usbmidi.c
+@@ -181,9 +181,9 @@ static int snd_usbmidi_urb_error(int sta
+ case -ENODEV:
+ return -ENODEV;
+ /* errors that might occur during unplugging */
+- case -EPROTO: /* EHCI */
+- case -ETIMEDOUT: /* OHCI */
+- case -EILSEQ: /* UHCI */
++ case -EPROTO:
++ case -ETIME:
++ case -EILSEQ:
+ return -EIO;
+ default:
+ snd_printk(KERN_ERR "urb status %d\n", status);
+@@ -223,7 +223,7 @@ static void dump_urb(const char *type, c
+ /*
+ * Processes the data read from the device.
+ */
+-static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
++static void snd_usbmidi_in_urb_complete(struct urb* urb)
+ {
+ struct snd_usb_midi_in_endpoint* ep = urb->context;
+
+@@ -247,7 +247,7 @@ static void snd_usbmidi_in_urb_complete(
+ snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
+ }
+
+-static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
++static void snd_usbmidi_out_urb_complete(struct urb* urb)
+ {
+ struct snd_usb_midi_out_endpoint* ep = urb->context;
+
+@@ -323,10 +323,9 @@ static int send_bulk_static_data(struct
+ const void *data, int len)
+ {
+ int err;
+- void *buf = kmalloc(len, GFP_KERNEL);
++ void *buf = kmemdup(data, len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+- memcpy(buf, data, len);
+ dump_urb("sending", buf, len);
+ err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len,
+ NULL, 250);
+diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
+index 491e975..1024c17 100644
+--- a/sound/usb/usbmixer.c
++++ b/sound/usb/usbmixer.c
+@@ -37,6 +37,7 @@
+ #include <sound/control.h>
+ #include <sound/hwdep.h>
+ #include <sound/info.h>
++#include <sound/tlv.h>
+
+ #include "usbaudio.h"
+
+@@ -416,6 +417,26 @@ static inline int set_cur_mix_value(stru
+ return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
+ }
+
++/*
++ * TLV callback for mixer volume controls
++ */
++static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
++ unsigned int size, unsigned int __user *_tlv)
++{
++ struct usb_mixer_elem_info *cval = kcontrol->private_data;
++ DECLARE_TLV_DB_SCALE(scale, 0, 0, 0);
++
++ if (size < sizeof(scale))
++ return -ENOMEM;
++ /* USB descriptions contain the dB scale in 1/256 dB unit
++ * while ALSA TLV contains in 1/100 dB unit
++ */
++ scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
++ scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256;
++ if (copy_to_user(_tlv, scale, sizeof(scale)))
++ return -EFAULT;
++ return 0;
++}
+
+ /*
+ * parser routines begin here...
+@@ -933,6 +954,12 @@ static void build_feature_ctl(struct mix
+ }
+ strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume",
+ sizeof(kctl->id.name));
++ if (control == USB_FEATURE_VOLUME) {
++ kctl->tlv.c = mixer_vol_tlv;
++ kctl->vd[0].access |=
++ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
++ }
+ break;
+
+ default:
+@@ -1683,7 +1710,7 @@ static void snd_usb_mixer_memory_change(
+ }
+ }
+
+-static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs)
++static void snd_usb_mixer_status_complete(struct urb *urb)
+ {
+ struct usb_mixer_interface *mixer = urb->context;
+
+@@ -1745,8 +1772,7 @@ static int snd_usb_mixer_status_create(s
+ return 0;
+ }
+
+-static void snd_usb_soundblaster_remote_complete(struct urb *urb,
+- struct pt_regs *regs)
++static void snd_usb_soundblaster_remote_complete(struct urb *urb)
+ {
+ struct usb_mixer_interface *mixer = urb->context;
+ const struct rc_config *rc = mixer->rc_cfg;
+diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c
+index 37accb6..7c4dcb3 100644
+--- a/sound/usb/usbmixer_maps.c
++++ b/sound/usb/usbmixer_maps.c
+@@ -234,6 +234,26 @@ static struct usbmix_name_map justlink_m
+ { 0 } /* terminator */
+ };
+
++/* TerraTec Aureon 5.1 MkII USB */
++static struct usbmix_name_map aureon_51_2_map[] = {
++ /* 1: IT USB */
++ /* 2: IT Mic */
++ /* 3: IT Line */
++ /* 4: IT SPDIF */
++ /* 5: OT SPDIF */
++ /* 6: OT Speaker */
++ /* 7: OT USB */
++ { 8, "Capture Source" }, /* SU */
++ { 9, "Master Playback" }, /* FU */
++ { 10, "Mic Capture" }, /* FU */
++ { 11, "Line Capture" }, /* FU */
++ { 12, "IEC958 In Capture" }, /* FU */
++ { 13, "Mic Playback" }, /* FU */
++ { 14, "Line Playback" }, /* FU */
++ /* 15: MU */
++ {} /* terminator */
++};
++
+ /*
+ * Control map entries
+ */
+@@ -276,6 +296,10 @@ static struct usbmix_ctl_map usbmix_ctl_
+ .id = USB_ID(0x0c45, 0x1158),
+ .map = justlink_map,
+ },
++ {
++ .id = USB_ID(0x0ccd, 0x0028),
++ .map = aureon_51_2_map,
++ },
+ { 0 } /* terminator */
+ };
+
+diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
+index 9351846..a7e9563 100644
+--- a/sound/usb/usbquirks.h
++++ b/sound/usb/usbquirks.h
+@@ -123,6 +123,10 @@ YAMAHA_DEVICE(0x103e, NULL),
+ YAMAHA_DEVICE(0x103f, NULL),
+ YAMAHA_DEVICE(0x1040, NULL),
+ YAMAHA_DEVICE(0x1041, NULL),
++YAMAHA_DEVICE(0x1042, NULL),
++YAMAHA_DEVICE(0x1043, NULL),
++YAMAHA_DEVICE(0x1044, NULL),
++YAMAHA_DEVICE(0x1045, NULL),
+ YAMAHA_DEVICE(0x2000, "DGP-7"),
+ YAMAHA_DEVICE(0x2001, "DGP-5"),
+ YAMAHA_DEVICE(0x2002, NULL),
+@@ -141,6 +145,7 @@ YAMAHA_DEVICE(0x500b, "DME64N"),
+ YAMAHA_DEVICE(0x500c, "DME24N"),
+ YAMAHA_DEVICE(0x500d, NULL),
+ YAMAHA_DEVICE(0x500e, NULL),
++YAMAHA_DEVICE(0x500f, NULL),
+ YAMAHA_DEVICE(0x7000, "DTX"),
+ YAMAHA_DEVICE(0x7010, "UB99"),
+ #undef YAMAHA_DEVICE
+diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
+index cfec38d..e011fca 100644
+--- a/sound/usb/usx2y/usbusx2y.c
++++ b/sound/usb/usx2y/usbusx2y.c
+@@ -172,7 +172,7 @@ static void snd_usX2Y_card_private_free(
+ /*
+ * pipe 4 is used for switching the lamps, setting samplerate, volumes ....
+ */
+-static void i_usX2Y_Out04Int(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_Out04Int(struct urb *urb)
+ {
+ #ifdef CONFIG_SND_DEBUG
+ if (urb->status) {
+@@ -184,7 +184,7 @@ static void i_usX2Y_Out04Int(struct urb
+ #endif
+ }
+
+-static void i_usX2Y_In04Int(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_In04Int(struct urb *urb)
+ {
+ int err = 0;
+ struct usX2Ydev *usX2Y = urb->context;
+diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
+index f6bd0de..367f8a3 100644
+--- a/sound/usb/usx2y/usbusx2yaudio.c
++++ b/sound/usb/usx2y/usbusx2yaudio.c
+@@ -306,7 +306,7 @@ static void usX2Y_error_sequence(struct
+ usX2Y_clients_stop(usX2Y);
+ }
+
+-static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_urb_complete(struct urb *urb)
+ {
+ struct snd_usX2Y_substream *subs = urb->context;
+ struct usX2Ydev *usX2Y = subs->usX2Y;
+@@ -322,7 +322,7 @@ static void i_usX2Y_urb_complete(struct
+ usX2Y_error_urb_status(usX2Y, subs, urb);
+ return;
+ }
+- if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
++ if (likely(urb->start_frame == usX2Y->wait_iso_frame))
+ subs->completed_urb = urb;
+ else {
+ usX2Y_error_sequence(usX2Y, subs, urb);
+@@ -335,13 +335,9 @@ static void i_usX2Y_urb_complete(struct
+ atomic_read(&capsubs->state) >= state_PREPARED &&
+ (playbacksubs->completed_urb ||
+ atomic_read(&playbacksubs->state) < state_PREPARED)) {
+- if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) {
+- if (nr_of_packs() <= urb->start_frame &&
+- urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
+- usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
+- else
+- usX2Y->wait_iso_frame += nr_of_packs();
+- } else {
++ if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame))
++ usX2Y->wait_iso_frame += nr_of_packs();
++ else {
+ snd_printdd("\n");
+ usX2Y_clients_stop(usX2Y);
+ }
+@@ -350,7 +346,7 @@ static void i_usX2Y_urb_complete(struct
+ }
+
+ static void usX2Y_urbs_set_complete(struct usX2Ydev * usX2Y,
+- void (*complete)(struct urb *, struct pt_regs *))
++ void (*complete)(struct urb *))
+ {
+ int s, u;
+ for (s = 0; s < 4; s++) {
+@@ -370,7 +366,7 @@ static void usX2Y_subs_startup_finish(st
+ usX2Y->prepare_subs = NULL;
+ }
+
+-static void i_usX2Y_subs_startup(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_subs_startup(struct urb *urb)
+ {
+ struct snd_usX2Y_substream *subs = urb->context;
+ struct usX2Ydev *usX2Y = subs->usX2Y;
+@@ -382,7 +378,7 @@ static void i_usX2Y_subs_startup(struct
+ wake_up(&usX2Y->prepare_wait_queue);
+ }
+
+- i_usX2Y_urb_complete(urb, regs);
++ i_usX2Y_urb_complete(urb);
+ }
+
+ static void usX2Y_subs_prepare(struct snd_usX2Y_substream *subs)
+@@ -495,7 +491,6 @@ static int usX2Y_urbs_start(struct snd_u
+ if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
+ goto start;
+ }
+- usX2Y->wait_iso_frame = -1;
+
+ start:
+ usX2Y_subs_startup(subs);
+@@ -516,10 +511,9 @@ static int usX2Y_urbs_start(struct snd_u
+ snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+ err = -EPIPE;
+ goto cleanup;
+- } else {
+- if (0 > usX2Y->wait_iso_frame)
++ } else
++ if (i == 0)
+ usX2Y->wait_iso_frame = urb->start_frame;
+- }
+ urb->transfer_flags = 0;
+ } else {
+ atomic_set(&subs->state, state_STARTING1);
+@@ -663,7 +657,7 @@ static struct s_c2 SetRate48000[] =
+ };
+ #define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000)
+
+-static void i_usX2Y_04Int(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_04Int(struct urb *urb)
+ {
+ struct usX2Ydev *usX2Y = urb->context;
+
+diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
+index 88b72b5..8f3e35e 100644
+--- a/sound/usb/usx2y/usx2yhwdeppcm.c
++++ b/sound/usb/usx2y/usx2yhwdeppcm.c
+@@ -226,7 +226,7 @@ static inline int usX2Y_usbpcm_usbframe_
+ }
+
+
+-static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
+ {
+ struct snd_usX2Y_substream *subs = urb->context;
+ struct usX2Ydev *usX2Y = subs->usX2Y;
+@@ -243,7 +243,7 @@ static void i_usX2Y_usbpcm_urb_complete(
+ usX2Y_error_urb_status(usX2Y, subs, urb);
+ return;
+ }
+- if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
++ if (likely(urb->start_frame == usX2Y->wait_iso_frame))
+ subs->completed_urb = urb;
+ else {
+ usX2Y_error_sequence(usX2Y, subs, urb);
+@@ -256,13 +256,9 @@ static void i_usX2Y_usbpcm_urb_complete(
+ if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
+ (NULL == capsubs2 || capsubs2->completed_urb) &&
+ (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
+- if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
+- if (nr_of_packs() <= urb->start_frame &&
+- urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
+- usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
+- else
+- usX2Y->wait_iso_frame += nr_of_packs();
+- } else {
++ if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
++ usX2Y->wait_iso_frame += nr_of_packs();
++ else {
+ snd_printdd("\n");
+ usX2Y_clients_stop(usX2Y);
+ }
+@@ -294,7 +290,7 @@ static void usX2Y_usbpcm_subs_startup_fi
+ usX2Y->prepare_subs = NULL;
+ }
+
+-static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
++static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
+ {
+ struct snd_usX2Y_substream *subs = urb->context;
+ struct usX2Ydev *usX2Y = subs->usX2Y;
+@@ -311,7 +307,7 @@ static void i_usX2Y_usbpcm_subs_startup(
+ wake_up(&usX2Y->prepare_wait_queue);
+ }
+
+- i_usX2Y_usbpcm_urb_complete(urb, regs);
++ i_usX2Y_usbpcm_urb_complete(urb);
+ }
+
+ /*
+@@ -433,7 +429,6 @@ static int usX2Y_usbpcm_urbs_start(struc
+ if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
+ goto start;
+ }
+- usX2Y->wait_iso_frame = -1;
+
+ start:
+ usX2Y_usbpcm_subs_startup(subs);
+@@ -459,7 +454,7 @@ static int usX2Y_usbpcm_urbs_start(struc
+ goto cleanup;
+ } else {
+ snd_printdd("%i\n", urb->start_frame);
+- if (0 > usX2Y->wait_iso_frame)
++ if (u == 0)
+ usX2Y->wait_iso_frame = urb->start_frame;
+ }
+ urb->transfer_flags = 0;
+@@ -632,7 +627,7 @@ static int usX2Y_pcms_lock_check(struct
+ for (s = 0; s < 2; ++s) {
+ struct snd_pcm_substream *substream;
+ substream = pcm->streams[s].substream;
+- if (SUBSTREAM_BUSY(substream))
++ if (substream && SUBSTREAM_BUSY(substream))
+ err = -EBUSY;
+ }
+ }
+diff --git a/usr/Makefile b/usr/Makefile
+index 5b31c0b..e338e7b 100644
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -3,6 +3,8 @@
+ #
+
+ klibcdirs:;
++PHONY += klibcdirs
++
+
+ # Generate builtin.o based on initramfs_data.o
+ obj-y := initramfs_data.o
Added: people/maks-guest/linux-2.6/debian/patches/alpha-prctl.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/alpha-prctl.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,32 @@
+diff --git a/include/asm-alpha/thread_info.h b/include/asm-alpha/thread_info.h
+index 69ffd93..011daaf 100644
+--- a/include/asm-alpha/thread_info.h
++++ b/include/asm-alpha/thread_info.h
+@@ -92,5 +92,27 @@ register struct thread_info *__current_t
+ #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
+ | _TIF_SYSCALL_TRACE)
+
++#define ALPHA_UAC_SHIFT 6
++#define ALPHA_UAC_MASK (1 << TIF_UAC_NOPRINT | 1 << TIF_UAC_NOFIX | \
++ 1 << TIF_UAC_SIGBUS)
++
++#define SET_UNALIGN_CTL(task,value) ({ \
++ (task)->thread_info->flags = (((task)->thread_info->flags & \
++ ~ALPHA_UAC_MASK) \
++ | (((value) << ALPHA_UAC_SHIFT) & (1 << TIF_UAC_NOPRINT)) \
++ | (((value) << ALPHA_UAC_SHIFT + 1) & (1 << TIF_UAC_SIGBUS)) \
++ | (((value) << ALPHA_UAC_SHIFT - 1) & (1 << TIF_UAC_NOFIX)));\
++ 0; })
++
++#define GET_UNALIGN_CTL(task,value) ({ \
++ put_user(((task)->thread_info->flags & (1 << TIF_UAC_NOPRINT)) \
++ >> ALPHA_UAC_SHIFT \
++ | ((task)->thread_info->flags & (1 << TIF_UAC_SIGBUS)) \
++ >> ALPHA_UAC_SHIFT + 1 \
++ | ((task)->thread_info->flags & (1 << TIF_UAC_NOFIX)) \
++ >> ALPHA_UAC_SHIFT - 1, \
++ (int __user *)(value)); \
++ })
++
+ #endif /* __KERNEL__ */
+ #endif /* _ALPHA_THREAD_INFO_H */
Added: people/maks-guest/linux-2.6/debian/patches/arm-get_unaligned-gcc41-const.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/arm-get_unaligned-gcc41-const.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,128 @@
+# Make get_unaligned() work with const pointers and GCC 4.1
+
+# See
+# http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2006-September/035862.html
+
+
+From: Lennert Buytenhek <buytenh at wantstofly.org>
+
+On Wed, Sep 06, 2006 at 09:32:58AM +0100, Russell King - ARM Linux wrote:
+> > CC [M] drivers/net/wireless/zd1211rw/zd_usb.o
+> > drivers/net/wireless/zd1211rw/zd_usb.c: In function 'handle_rx_packet':
+> > drivers/net/wireless/zd1211rw/zd_usb.c:547: error: assignment of read-only variable '__v'
+> > This comes from
+> > if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG))
+> > which gets expanded to arm's __get_unaligned_le(). The code ends up
+> > being something like:
+
+The attached patch makes get_unaligned() work with const pointers,
+and doesn't seem to noticably affect code generation.
+
+Original code (2.6.18-rc5), format is instructions/registers:
+
+ 2.95.3 3.2.3 3.3.3 3.4.2 4.0.2 4.1.0
+original, u8 1/1 1/1 1/1 1/1 1/1 1/1
+original, u16 3/2 3/3 3/3 3/2 3/2 3/2
+original, u32 7/4 8/5 9/5 7/5 7/4 8/5
+original, u64 19/8 19/8 21/8 19/7 20/9 22/11
+
+
+After patch (* denotes change):
+
+ 2.95.3 3.2.3 3.3.3 3.4.2 4.0.2 4.1.0
+fixed, u8 1/1 1/1 1/1 1/1 1/1 1/1
+fixed, u16 3/2 3/3 3/3 3/2 3/2 3/2
+fixed, u32 7/4 9/6 * 9/6 * 7/5 7/4 8/5
+fixed, u64 19/8 19/8 20/8 * 19/7 20/9 22/11
+
+
+So, for gcc 3.2.3 in the u32 case we need 1 insn and 1 register more,
+on gcc 3.3.3 we need 1 reg more in the u32 case and save one insn in
+the u64 case, and all the other compiler versions don't seem to care
+at all.
+
+
+--- a/include/asm-arm/unaligned.h.orig 2006-09-07 00:36:56.937552584 +0200
++++ b/include/asm-arm/unaligned.h 2006-09-07 02:03:40.522487432 +0200
+@@ -3,7 +3,7 @@
+
+ #include <asm/types.h>
+
+-extern int __bug_unaligned_x(void *ptr);
++extern int __bug_unaligned_x(const void *ptr);
+
+ /*
+ * What is the most efficient way of loading/storing an unaligned value?
+@@ -51,47 +51,34 @@
+ #define __get_unaligned_4_be(__p) \
+ (__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3])
+
+-#define __get_unaligned_le(ptr) \
+- ({ \
+- __typeof__(*(ptr)) __v; \
+- __u8 *__p = (__u8 *)(ptr); \
+- switch (sizeof(*(ptr))) { \
+- case 1: __v = *(ptr); break; \
+- case 2: __v = __get_unaligned_2_le(__p); break; \
+- case 4: __v = __get_unaligned_4_le(__p); break; \
+- case 8: { \
+- unsigned int __v1, __v2; \
+- __v2 = __get_unaligned_4_le((__p+4)); \
+- __v1 = __get_unaligned_4_le(__p); \
+- __v = ((unsigned long long)__v2 << 32 | __v1); \
+- } \
+- break; \
+- default: __v = __bug_unaligned_x(__p); break; \
+- } \
+- __v; \
++#define __get_unaligned_8_le(__p) \
++ ((unsigned long long)__get_unaligned_4_le((__p+4)) << 32 | \
++ __get_unaligned_4_le(__p))
++
++#define __get_unaligned_8_be(__p) \
++ ((unsigned long long)__get_unaligned_4_le(__p) << 32 | \
++ __get_unaligned_4_le((__p+4)))
++
++#define __get_unaligned_le(ptr) \
++ ({ \
++ const __u8 *__p = (const __u8 *)(ptr); \
++ sizeof(*(ptr)) == 1 ? *__p : \
++ sizeof(*(ptr)) == 2 ? __get_unaligned_2_le(__p) : \
++ sizeof(*(ptr)) == 4 ? __get_unaligned_4_le(__p) : \
++ sizeof(*(ptr)) == 8 ? __get_unaligned_8_le(__p) : \
++ __bug_unaligned_x(__p); \
+ })
+
+-#define __get_unaligned_be(ptr) \
+- ({ \
+- __typeof__(*(ptr)) __v; \
+- __u8 *__p = (__u8 *)(ptr); \
+- switch (sizeof(*(ptr))) { \
+- case 1: __v = *(ptr); break; \
+- case 2: __v = __get_unaligned_2_be(__p); break; \
+- case 4: __v = __get_unaligned_4_be(__p); break; \
+- case 8: { \
+- unsigned int __v1, __v2; \
+- __v2 = __get_unaligned_4_be(__p); \
+- __v1 = __get_unaligned_4_be((__p+4)); \
+- __v = ((unsigned long long)__v2 << 32 | __v1); \
+- } \
+- break; \
+- default: __v = __bug_unaligned_x(__p); break; \
+- } \
+- __v; \
++#define __get_unaligned_be(ptr) \
++ ({ \
++ const __u8 *__p = (const __u8 *)(ptr); \
++ sizeof(*(ptr)) == 1 ? *__p : \
++ sizeof(*(ptr)) == 2 ? __get_unaligned_2_be(__p) : \
++ sizeof(*(ptr)) == 4 ? __get_unaligned_4_be(__p) : \
++ sizeof(*(ptr)) == 8 ? __get_unaligned_8_be(__p) : \
++ __bug_unaligned_x(__p); \
+ })
+
+-
+ static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p)
+ {
+ *__p++ = __v;
+
Added: people/maks-guest/linux-2.6/debian/patches/arm-iop-generic-backport.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/arm-iop-generic-backport.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,222 @@
+# Backport of a number of generic functions which subsequent patches use
+# Upstream status: will go into 2.6.19
+
+diff -urN a/arch/arm/mach-iop3xx/Makefile b/arch/arm/mach-iop3xx/Makefile
+--- a/arch/arm/mach-iop3xx/Makefile 2006-08-03 11:39:01.664742750 +0000
++++ b/arch/arm/mach-iop3xx/Makefile 2006-08-07 17:33:38.237095500 +0000
+@@ -10,7 +10,7 @@
+ obj-n :=
+ obj- :=
+
+-obj-$(CONFIG_ARCH_IOP321) += iop321-setup.o iop321-irq.o iop321-pci.o iop321-time.o
++obj-$(CONFIG_ARCH_IOP321) += iop321-setup.o iop321-irq.o iop321-pci.o iop321-time.o iop321-gpio.o
+
+ obj-$(CONFIG_ARCH_IOP331) += iop331-setup.o iop331-irq.o iop331-pci.o iop331-time.o
+
+diff -urN a/arch/arm/mach-iop3xx/iop321-gpio.c b/arch/arm/mach-iop3xx/iop321-gpio.c
+--- a/arch/arm/mach-iop3xx/iop321-gpio.c 1970-01-01 00:00:00.000000000 +0000
++++ b/arch/arm/mach-iop3xx/iop321-gpio.c 2006-08-07 17:33:38.237095500 +0000
+@@ -0,0 +1,44 @@
++/*
++ * arch/arm/plat-iop/gpio.c
++ * GPIO handling for Intel IOP3xx processors.
++ *
++ * Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.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
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/device.h>
++#include <asm/arch/iop321.h>
++
++void gpio_line_config(int line, int direction)
++{
++ unsigned long flags;
++
++ if (direction == GPIO_IN) {
++ *IOP321_GPOE |= 1 << line;
++ } else if (direction == GPIO_OUT) {
++ *IOP321_GPOE &= ~(1 << line);
++ }
++}
++EXPORT_SYMBOL(gpio_line_config);
++
++int gpio_line_get(int line)
++{
++ return !!(*IOP321_GPID & (1 << line));
++}
++EXPORT_SYMBOL(gpio_line_get);
++
++void gpio_line_set(int line, int value)
++{
++ unsigned long flags;
++
++ if (value == GPIO_LOW) {
++ *IOP321_GPOD &= ~(1 << line);
++ } else if (value == GPIO_HIGH) {
++ *IOP321_GPOD |= 1 << line;
++ }
++}
++EXPORT_SYMBOL(gpio_line_set);
+diff -urN a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
+--- a/arch/arm/mach-iop3xx/iop321-setup.c 2006-08-03 11:39:01.664742750 +0000
++++ b/arch/arm/mach-iop3xx/iop321-setup.c 2006-08-07 17:33:38.237095500 +0000
+@@ -75,7 +75,7 @@
+ }
+ };
+
+-static struct resource iop32x_i2c_0_resources[] = {
++struct resource iop32x_i2c_0_resources[] = {
+ [0] = {
+ .start = 0xfffff680,
+ .end = 0xfffff698,
+@@ -88,7 +88,7 @@
+ }
+ };
+
+-static struct resource iop32x_i2c_1_resources[] = {
++struct resource iop32x_i2c_1_resources[] = {
+ [0] = {
+ .start = 0xfffff6a0,
+ .end = 0xfffff6b8,
+@@ -101,14 +101,14 @@
+ }
+ };
+
+-static struct platform_device iop32x_i2c_0_controller = {
++struct platform_device iop32x_i2c_0_controller = {
+ .name = "IOP3xx-I2C",
+ .id = 0,
+ .num_resources = 2,
+ .resource = iop32x_i2c_0_resources
+ };
+
+-static struct platform_device iop32x_i2c_1_controller = {
++struct platform_device iop32x_i2c_1_controller = {
+ .name = "IOP3xx-I2C",
+ .id = 1,
+ .num_resources = 2,
+diff -urN a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c
+--- a/arch/arm/mach-iop3xx/iop321-time.c 2006-08-03 11:39:01.664742750 +0000
++++ b/arch/arm/mach-iop3xx/iop321-time.c 2006-08-07 17:33:50.349852500 +0000
+@@ -28,6 +28,19 @@
+
+ #define IOP321_TIME_SYNC 0
+
++static unsigned long ticks_per_jiffy;
++static unsigned long ticks_per_usec;
++static unsigned long next_jiffy_time;
++
++unsigned long iop3xx_gettimeoffset(void)
++{
++ unsigned long offset;
++
++ offset = next_jiffy_time - *IOP321_TU_TCR1;
++
++ return offset / ticks_per_usec;
++}
++
+ static inline unsigned long get_elapsed(void)
+ {
+ return LATCH - *IOP321_TU_TCR0;
+@@ -65,6 +78,24 @@
+ }
+
+ static irqreturn_t
++iop3xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ write_seqlock(&xtime_lock);
++
++ asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (1));
++
++ while ((signed long)(next_jiffy_time - *IOP321_TU_TCR1)
++ >= ticks_per_jiffy) {
++ timer_tick(regs);
++ next_jiffy_time -= ticks_per_jiffy;
++ }
++
++ write_sequnlock(&xtime_lock);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t
+ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ u32 tisr;
+@@ -82,12 +113,41 @@
+ return IRQ_HANDLED;
+ }
+
++static struct irqaction iop3xx_timer_irq = {
++ .name = "IOP3XX Timer Tick",
++ .handler = iop3xx_timer_interrupt,
++ .flags = IRQF_DISABLED | IRQF_TIMER,
++};
++
+ static struct irqaction iop321_timer_irq = {
+ .name = "IOP321 Timer Tick",
+ .handler = iop321_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ };
+
++void __init iop3xx_init_time(unsigned long tick_rate)
++{
++ u32 timer_ctl;
++
++ ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
++ ticks_per_usec = tick_rate / 1000000;
++ next_jiffy_time = 0xffffffff;
++
++ timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD |
++ IOP321_TMR_RATIO_1_1;
++
++ /*
++ * We use timer 0 for our timer interrupt, and timer 1 as
++ * monotonic counter for tracking missed jiffies.
++ */
++ asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (ticks_per_jiffy - 1));
++ asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
++ asm volatile("mcr p6, 0, %0, c5, c1, 0" : : "r" (0xffffffff));
++ asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl));
++
++ setup_irq(IRQ_IOP321_TIMER0, &iop3xx_timer_irq);
++}
++
+ static void __init iop321_timer_init(void)
+ {
+ u32 timer_ctl;
+diff -urN a/include/asm-arm/arch-iop3xx/iop321.h b/include/asm-arm/arch-iop3xx/iop321.h
+--- a/include/asm-arm/arch-iop3xx/iop321.h 2006-08-03 11:39:08.109145500 +0000
++++ b/include/asm-arm/arch-iop3xx/iop321.h 2006-08-07 17:33:38.241095750 +0000
+@@ -232,6 +232,12 @@
+ #define IOP321_GPID (volatile u32 *)IOP321_REG_ADDR(0x000007C8)
+ #define IOP321_GPOD (volatile u32 *)IOP321_REG_ADDR(0x000007CC)
+
++#define GPIO_IN 0
++#define GPIO_OUT 1
++#define GPIO_LOW 0
++#define GPIO_HIGH 1
++#define IOP3XX_GPIO_LINE(x) (x)
++
+ /* Interrupt Controller */
+ #define IOP321_INTCTL (volatile u32 *)IOP321_REG_ADDR(0x000007D0)
+ #define IOP321_INTSTR (volatile u32 *)IOP321_REG_ADDR(0x000007D4)
+@@ -340,6 +346,13 @@
+ extern void iop321_map_io(void);
+ extern void iop321_init_irq(void);
+ extern void iop321_time_init(void);
++extern unsigned long iop3xx_gettimeoffset(void);
++extern void iop3xx_init_time(unsigned long);
++extern struct platform_device iop32x_i2c_0_controller;
++extern struct platform_device iop32x_i2c_1_controller;
++extern void gpio_line_config(int line, int direction);
++extern int gpio_line_get(int line);
++extern void gpio_line_set(int line, int value);
+ #endif
+
+ #endif // _IOP321_HW_H_
+
Added: people/maks-guest/linux-2.6/debian/patches/arm-iop-mtd-maps.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/arm-iop-mtd-maps.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,188 @@
+# Add an MTD maps for IOP3xx boards
+# Upstream status: can be solved in a better way as of 2.6.18
+
+diff -urN a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
+--- a/drivers/mtd/maps/Kconfig 2006-08-03 11:39:05.885006500 +0000
++++ b/drivers/mtd/maps/Kconfig 2006-08-07 17:19:06.190596000 +0000
+@@ -447,6 +447,14 @@
+ 21285 bridge used with Intel's StrongARM processors. More info at
+ <http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
+
++config MTD_IOP3XX
++ tristate "CFI Flash device mapped on the XScale IOP3XX board"
++ depends on ARM && MTD_CFI && ARCH_IOP3XX
++ help
++ This enables access routines for the flash chips on the Intel XScale
++ IOP3XX based evaluation board. If you have one of these boards and
++ would like to use the flash chips on it, say 'Y'.
++
+ config MTD_IQ80310
+ tristate "CFI Flash device mapped on the XScale IQ80310 board"
+ depends on MTD_CFI && ARCH_IQ80310
+diff -urN a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
+--- a/drivers/mtd/maps/Makefile 2006-08-03 11:39:05.885006500 +0000
++++ b/drivers/mtd/maps/Makefile 2006-08-07 17:18:53.981833000 +0000
+@@ -15,7 +15,7 @@
+ 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_IQ80310) += iq80310.o
++obj-$(CONFIG_MTD_IOP3XX) += iop3xx.o
+ obj-$(CONFIG_MTD_L440GX) += l440gx.o
+ obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
+ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
+diff -urN a/drivers/mtd/maps/iop3xx.c b/drivers/mtd/maps/iop3xx.c
+--- a/drivers/mtd/maps/iop3xx.c 1970-01-01 00:00:00.000000000 +0000
++++ b/drivers/mtd/maps/iop3xx.c 2006-08-07 17:18:53.981833000 +0000
+@@ -0,0 +1,150 @@
++/*
++ * $Id: iop3xx.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $
++ *
++ * Mapping for Intel XScale IOP3xx based platforms
++ *
++ * Author: Nicolas Pitre
++ * Copyright: (C) 2001-2003 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.
++ *
++ * 09/03: Cleaned up to be generic to all IOP3xx systems - ds
++ *
++ * If you add a new machine type with a different WINDOW_SIZE or
++ * physmap addr, just wrap the init in if(machine_is_X()) { }
++ * and make sure your board header gets included in
++ * include/asm-arm/arch-iop3xx/hardware.h to pick up the definitions.
++ *
++ * DO NOT fill this file with #ifdef CONFIG_ARCH_XXXX crap.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <asm/io.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++static struct mtd_info *mymtd;
++
++static struct map_info iop3xx_map = {
++ .name = "IOP3xx Flash",
++};
++
++static struct mtd_partition iop3xx_partitions[6] = {
++ {
++ .name = "RedBoot",
++ .size = 0x00040000,
++ .offset = 0,
++ },{
++ .name = "ramdisk",
++ .size = 0x00d00000,
++ .offset = 0x00040000,
++ },{
++ .name = "kernel",
++ .size = 0x00160000,
++ .offset = 0x00d40000
++ },{
++ .name = "user",
++ .size = 0x00120000,
++ .offset = 0x00ea0000
++ },{
++ .name = "RedBoot config",
++ .size = 0x00020000,
++ .offset = 0x00fc0000,
++ // .mask_flags = MTD_WRITEABLE
++ },{
++ .name = "FIS directory",
++ .size = 0x00020000,
++ .offset = 0x00fe0000
++ }
++};
++
++static struct mtd_info *mymtd;
++static struct mtd_partition *parsed_parts;
++static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
++
++static int __init init_iop3xx(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ int parsed_nr_parts = 0;
++ int ret;
++
++ if(machine_is_iq80321()) {
++ iop3xx_map.phys = IQ80321_FLASHBASE;
++ iop3xx_map.size = IQ80321_FLASHSIZE;
++ iop3xx_map.bankwidth = IQ80321_FLASHWIDTH;
++ } else if(machine_is_iq31244()) {
++ iop3xx_map.phys = IQ31244_FLASHBASE;
++ iop3xx_map.size = IQ31244_FLASHSIZE;
++ iop3xx_map.bankwidth = IQ31244_FLASHWIDTH;
++ } else if(machine_is_iq80331()) {
++ iop3xx_map.phys = IQ80331_FLASHBASE;
++ iop3xx_map.size = IQ80331_FLASHSIZE;
++ iop3xx_map.bankwidth = IQ80331_FLASHWIDTH;
++ } else if(machine_is_n2100()) {
++ iop3xx_map.phys = N2100_FLASHBASE;
++ iop3xx_map.size = N2100_FLASHSIZE;
++ iop3xx_map.bankwidth = N2100_FLASHWIDTH;
++ } else {
++ printk("Unknown IOP3xx platform - flash access disabled\n");
++ return -ENODEV;
++ }
++
++ iop3xx_map.virt =
++ (unsigned long)ioremap(iop3xx_map.phys, iop3xx_map.size );
++ if (!iop3xx_map.virt) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++ simple_map_init(&iop3xx_map);
++
++ mymtd = do_map_probe("cfi_probe", &iop3xx_map);
++ if (!mymtd) {
++ iounmap((void *)iop3xx_map.virt);
++ return -ENXIO;
++ }
++ mymtd->owner = THIS_MODULE;
++
++ ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
++ ret=-1;
++ if (ret > 0)
++ parsed_nr_parts = ret;
++ if (parsed_nr_parts > 0) {
++ parts = parsed_parts;
++ nb_parts = parsed_nr_parts;
++ } else {
++ parts = iop3xx_partitions;
++ nb_parts = ARRAY_SIZE(iop3xx_partitions);
++ }
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit cleanup_iop3xx(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++ if (iop3xx_map.virt)
++ iounmap((void *)iop3xx_map.virt);
++}
++
++module_init(init_iop3xx);
++module_exit(cleanup_iop3xx);
++
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Nicolas Pitre <nico at cam.org>");
++MODULE_DESCRIPTION("MTD map driver for Intel XScale IOP3xx Platforms");
+
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/alpha/asm-subarchs.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/alpha/asm-subarchs.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,40 @@
+--- source/include/asm-alpha/compiler.h.orig 2006-09-19 20:42:06.000000000 -0700
++++ source/include/asm-alpha/compiler.h 2006-11-06 17:10:00.000000000 -0800
+@@ -78,16 +78,20 @@
+ #else
+ #define __kernel_ldbu(mem) \
+ ({ unsigned char __kir; \
+- __asm__("ldbu %0,%1" : "=r"(__kir) : "m"(mem)); \
++ __asm__(".arch ev56; \
++ ldbu %0,%1" : "=r"(__kir) : "m"(mem)); \
+ __kir; })
+ #define __kernel_ldwu(mem) \
+ ({ unsigned short __kir; \
+- __asm__("ldwu %0,%1" : "=r"(__kir) : "m"(mem)); \
++ __asm__(".arch ev56; \
++ ldwu %0,%1" : "=r"(__kir) : "m"(mem)); \
+ __kir; })
+-#define __kernel_stb(val,mem) \
+- __asm__("stb %1,%0" : "=m"(mem) : "r"(val))
+-#define __kernel_stw(val,mem) \
+- __asm__("stw %1,%0" : "=m"(mem) : "r"(val))
++#define __kernel_stb(val,mem) \
++ __asm__(".arch ev56; \
++ stb %1,%0" : "=m"(mem) : "r"(val))
++#define __kernel_stw(val,mem) \
++ __asm__(".arch ev56; \
++ stw %1,%0" : "=m"(mem) : "r"(val))
+ #endif
+
+ #ifdef __KERNEL__
+--- source/arch/alpha/kernel/sys_titan.c.orig 2006-11-06 23:17:50.000000000 -0800
++++ source/arch/alpha/kernel/sys_titan.c 2006-11-06 23:17:04.000000000 -0800
+@@ -257,7 +257,7 @@
+ */
+ while (mask) {
+ /* convert to SRM vector... priority is <63> -> <0> */
+- __asm__("ctlz %1, %0" : "=r"(vector) : "r"(mask));
++ __asm__(".arch ev6; ctlz %1, %0" : "=r"(vector) : "r"(mask));
+ vector = 63 - vector;
+ mask &= ~(1UL << vector); /* clear it out */
+ vector = 0x900 + (vector << 4); /* convert to SRM vector */
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/arm/.n2100-serial-irq.patch.swp
==============================================================================
Binary file. No diff available.
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/arm/arm-generic-time.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/arm/arm-generic-time.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,75 @@
+Backported from 2.6.19-rc3, needed for ixp4xx-clocksource.patch
+
+Index: linux-2.6.18/arch/arm/Kconfig
+===================================================================
+--- linux-2.6.18.orig/arch/arm/Kconfig 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/arch/arm/Kconfig 2006-10-29 01:59:14.000000000 -0700
+@@ -17,6 +17,10 @@
+ Europe. There is an ARM Linux project with a web page at
+ <http://www.arm.linux.org.uk/>.
+
++config GENERIC_TIME
++ bool
++ default n
++
+ config MMU
+ bool
+ default y
+Index: linux-2.6.18/arch/arm/kernel/time.c
+===================================================================
+--- linux-2.6.18.orig/arch/arm/kernel/time.c 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/arch/arm/kernel/time.c 2006-10-29 01:59:14.000000000 -0700
+@@ -69,10 +69,12 @@
+ */
+ int (*set_rtc)(void);
+
++#ifndef CONFIG_GENERIC_TIME
+ static unsigned long dummy_gettimeoffset(void)
+ {
+ return 0;
+ }
++#endif
+
+ /*
+ * Scheduler clock - returns current time in nanosec units.
+@@ -230,6 +232,7 @@
+ #define do_leds()
+ #endif
+
++#ifndef CONFIG_GENERIC_TIME
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+@@ -291,6 +294,7 @@
+ }
+
+ EXPORT_SYMBOL(do_settimeofday);
++#endif /* !CONFIG_GENERIC_TIME */
+
+ /**
+ * save_time_delta - Save the offset between system time and RTC time
+@@ -500,8 +504,10 @@
+
+ void __init time_init(void)
+ {
++#ifndef CONFIG_GENERIC_TIME
+ if (system_timer->offset == NULL)
+ system_timer->offset = dummy_gettimeoffset;
++#endif
+ system_timer->init();
+
+ #ifdef CONFIG_NO_IDLE_HZ
+Index: linux-2.6.18/include/asm-arm/mach/time.h
+===================================================================
+--- linux-2.6.18.orig/include/asm-arm/mach/time.h 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/include/asm-arm/mach/time.h 2006-10-29 01:59:14.000000000 -0700
+@@ -38,7 +38,9 @@
+ void (*init)(void);
+ void (*suspend)(void);
+ void (*resume)(void);
++#ifndef CONFIG_GENERIC_TIME
+ unsigned long (*offset)(void);
++#endif
+
+ #ifdef CONFIG_NO_IDLE_HZ
+ struct dyn_tick_timer *dyn_tick;
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/arm/iop3xx-mtd-map-fix.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/arm/iop3xx-mtd-map-fix.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/maps/iop3xx.c 2006-11-03 12:04:58.503631320 +0100
++++ b/drivers/mtd/maps/iop3xx.c 2006-11-03 12:05:21.880967575 +0100
+@@ -57,7 +57,7 @@
+ .offset = 0x00ea0000
+ },{
+ .name = "RedBoot config",
+- .size = 0x00020000,
++ .size = 0x00001000,
+ .offset = 0x00fc0000,
+ // .mask_flags = MTD_WRITEABLE
+ },{
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/arm/n2100-eth1-irq.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/arm/n2100-eth1-irq.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,13 @@
+Fix the interrupt of the 2nd Ethernet slot.
+
+--- a/arch/arm/mach-iop3xx/n2100.c~ 2006-10-26 22:23:24.053694788 +0000
++++ b/arch/arm/mach-iop3xx/n2100.c 2006-10-26 22:23:41.955186517 +0000
+@@ -85,7 +85,7 @@
+ irq = IRQ_IOP321_XINT0;
+ } else if (PCI_SLOT(dev->devfn) == 2) {
+ /* RTL8110SB #2 */
+- irq = IRQ_IOP321_XINT1;
++ irq = IRQ_IOP321_XINT3;
+ } else if (PCI_SLOT(dev->devfn) == 3) {
+ /* Sil3512 */
+ irq = IRQ_IOP321_XINT2;
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/arm/n2100-serial-irq.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/arm/n2100-serial-irq.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,65 @@
+Allow USB and serial to co-exist on N2100 by using a platform device for
+serial and IRQ 0 for serial.
+
+--- a/arch/arm/mach-iop3xx/iop321-setup.c~ 2006-10-26 22:06:04.000000000 +0000
++++ b/arch/arm/mach-iop3xx/iop321-setup.c 2006-10-27 07:33:24.663719957 +0000
+@@ -131,7 +131,7 @@
+ void __init iop321_map_io(void)
+ {
+ iotable_init(iop321_std_desc, ARRAY_SIZE(iop321_std_desc));
+- if (!machine_is_glantank())
++ if (!machine_is_glantank() && !machine_is_n2100())
+ early_serial_setup(&iop321_serial_ports[0]);
+ }
+
+--- a/arch/arm/mach-iop3xx/n2100.c~ 2006-10-26 22:23:24.000000000 +0000
++++ b/arch/arm/mach-iop3xx/n2100.c 2006-10-27 07:32:15.130694184 +0000
+@@ -170,6 +170,40 @@
+
+
+ /*
++ * N2100 machine initialisation.
++ */
++
++static struct plat_serial8250_port n2100_serial_port[] = {
++ {
++ .mapbase = N2100_UART,
++ .membase = (char *)N2100_UART,
++ .irq = 0,
++ .flags = UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 1843200,
++ },
++ { },
++};
++
++static struct resource n2100_uart_resource = {
++ .start = N2100_UART,
++ .end = N2100_UART + 7,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device n2100_serial_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = n2100_serial_port,
++ },
++ .num_resources = 1,
++ .resource = &n2100_uart_resource,
++};
++
++
++/*
+ * Pull PCA9532 GPIO #8 low to power off the machine.
+ */
+ static void n2100_power_off(void)
+@@ -212,6 +246,7 @@
+ static void __init n2100_init_machine(void)
+ {
+ platform_device_register(&iop32x_i2c_0_controller);
++ platform_device_register(&n2100_serial_device);
+
+ pm_power_off = n2100_power_off;
+
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/copy-user-highpage-2.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/copy-user-highpage-2.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,33 @@
+Adjust copy_user_highpage callers to match new signature
+
+Signed-off-by: Thiemo Seufer <ths at networkno.de>
+
+
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -44,14 +44,14 @@ static void clear_huge_page(struct page
+ }
+
+ static void copy_huge_page(struct page *dst, struct page *src,
+- unsigned long addr)
++ unsigned long addr, struct vm_area_struct *vma)
+ {
+ int i;
+
+ might_sleep();
+ for (i = 0; i < HPAGE_SIZE/PAGE_SIZE; i++) {
+ cond_resched();
+- copy_user_highpage(dst + i, src + i, addr + i*PAGE_SIZE);
++ copy_user_highpage(dst + i, src + i, addr + i*PAGE_SIZE, vma);
+ }
+ }
+
+@@ -417,7 +417,7 @@ static int hugetlb_cow(struct mm_struct
+ }
+
+ spin_unlock(&mm->page_table_lock);
+- copy_huge_page(new_page, old_page, address);
++ copy_huge_page(new_page, old_page, address, vma);
+ spin_lock(&mm->page_table_lock);
+
+ ptep = huge_pte_offset(mm, address & HPAGE_MASK);
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/copy-user-highpage.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/copy-user-highpage.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,70 @@
+# Arch-specific copy_user_highpage, from linux-mips.org 2.6.18-stable,
+# also in kernel.org mainline, needed for cache alias fix.
+
+
+--- a/include/linux/highmem.h
++++ b/include/linux/highmem.h
+@@ -89,7 +89,10 @@ static inline void memclear_highpage_flu
+ kunmap_atomic(kaddr, KM_USER0);
+ }
+
+-static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr)
++#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
++
++static inline void copy_user_highpage(struct page *to, struct page *from,
++ unsigned long vaddr, struct vm_area_struct *vma)
+ {
+ char *vfrom, *vto;
+
+@@ -102,6 +105,8 @@ static inline void copy_user_highpage(st
+ smp_wmb();
+ }
+
++#endif
++
+ static inline void copy_highpage(struct page *to, struct page *from)
+ {
+ char *vfrom, *vto;
+diff --git a/mm/memory.c b/mm/memory.c
+index 109e986..2e4ee87 100644
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -1407,7 +1407,7 @@ static inline pte_t maybe_mkwrite(pte_t
+ return pte;
+ }
+
+-static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va)
++static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va, struct vm_area_struct *vma)
+ {
+ /*
+ * If the source page was a PFN mapping, we don't have
+@@ -1429,9 +1429,9 @@ static inline void cow_user_page(struct
+ memset(kaddr, 0, PAGE_SIZE);
+ kunmap_atomic(kaddr, KM_USER0);
+ return;
+-
++
+ }
+- copy_user_highpage(dst, src, va);
++ copy_user_highpage(dst, src, va, vma);
+ }
+
+ /*
+@@ -1531,7 +1531,7 @@ gotten:
+ new_page = alloc_page_vma(GFP_HIGHUSER, vma, address);
+ if (!new_page)
+ goto oom;
+- cow_user_page(new_page, old_page, address);
++ cow_user_page(new_page, old_page, address, vma);
+ }
+
+ /*
+@@ -2135,7 +2135,7 @@ retry:
+ page = alloc_page_vma(GFP_HIGHUSER, vma, address);
+ if (!page)
+ goto oom;
+- copy_user_highpage(page, new_page, address);
++ copy_user_highpage(page, new_page, address, vma);
+ page_cache_release(new_page);
+ new_page = page;
+ anon = 1;
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/fdomain-pci-id-table.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/fdomain-pci-id-table.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,31 @@
+From: Ben Collins <bcollins at ubuntu.com>
+Date: Fri, 11 Nov 2005 20:01:26 +0000 (-0500)
+Subject: [UBUNTU:scsi] Add basic hotplug support to fdomain
+X-Git-Tag: v2.6.15-rc1
+X-Git-Url: http://kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-2.6.git;a=commitdiff;h=e82633eb19c4b390846a6eecd72204b696448954
+
+[UBUNTU:scsi] Add basic hotplug support to some drivers
+
+UpstreamStatus: Unsubmitted
+
+Signed-off-by: Ben Collins <bcollins at ubuntu.com>
+---
+
+--- a/drivers/scsi/fdomain.c
++++ b/drivers/scsi/fdomain.c
+@@ -1720,6 +1720,15 @@ static int fdomain_16x0_release(struct S
+ return 0;
+ }
+
++#ifndef PCMCIA
++static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
++ { }
++};
++MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
++#endif
++
+ struct scsi_host_template fdomain_driver_template = {
+ .module = THIS_MODULE,
+ .name = "fdomain",
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/dec-scsi.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/dec-scsi.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,32 @@
+# Upstream status: in linux-mips tree; someone needs to figure out how to
+# integrate this into the Linux tree...
+
+From: Maciej W. Rozycki <macro at linux-mips.org>
+
+--- a/drivers/scsi/NCR53C9x.h 2006-03-05 20:35:04.000000000 +0100
++++ b/drivers/scsi/NCR53C9x.h 2006-03-05 19:51:16.000000000 +0100
+@@ -145,12 +145,7 @@
+
+ #ifndef MULTIPLE_PAD_SIZES
+
+-#ifdef CONFIG_CPU_HAS_WB
+-#include <asm/wbflush.h>
+-#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
+-#else
+-#define esp_write(__reg, __val) ((__reg) = (__val))
+-#endif
++#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0)
+ #define esp_read(__reg) (__reg)
+
+ struct ESP_regs {
+--- a/drivers/scsi/dec_esp.c
++++ b/drivers/scsi/dec_esp.c
+@@ -230,7 +230,7 @@ static int dec_esp_detect(struct scsi_ho
+ mem_start = get_tc_base_addr(slot);
+
+ /* Store base addr into esp struct */
+- esp->slot = CPHYSADDR(mem_start);
++ esp->slot = mem_start;
+
+ esp->dregs = 0;
+ esp->eregs = (void *)CKSEG1ADDR(mem_start +
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/dec-serial.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/dec-serial.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,197 @@
+# Upstream status: won't go into Linus' tree like this but is in the
+# linux-mips tree. The drivers/char serial drivers need to be converted to
+# real serial drivers in drivers/serial
+
+# Author: Martin Michlmayr <tbm at cyrius.com>, mostly taken from the
+# linux-mips tree, with some updates by Maciej W. Rozycki.
+
+
+--- b/drivers/char/Kconfig~ 2006-05-25 12:51:58.000000000 +0200
++++ b/drivers/char/Kconfig 2006-05-25 12:53:03.000000000 +0200
+@@ -362,6 +362,41 @@
+ bool "Console on BCM1xxx DUART"
+ depends on SIBYTE_SB1250_DUART
+
++config SERIAL_DEC
++ bool "DECstation serial support"
++ depends on MACH_DECSTATION
++ default y
++ help
++ This selects whether you want to be asked about drivers for
++ DECstation serial ports.
++
++ Note that the answer to this question won't directly affect the
++ kernel: saying N will just cause the configurator to skip all
++ the questions about DECstation serial ports.
++
++ If unsure, say Y.
++
++config SERIAL_DEC_CONSOLE
++ bool "Support for console on a DECstation serial port"
++ depends on SERIAL_DEC
++ default y
++ help
++ If you say Y here, it will be possible to use a serial port as the
++ system console (the system console is the device which receives all
++ kernel messages and warnings and which allows logins in single user
++ mode). Note that the firmware uses ttyS0 as the serial console on
++ the Maxine and ttyS2 on the others.
++
++ If unsure, say Y.
++
++config ZS
++ bool "Z85C30 Serial Support"
++ depends on SERIAL_DEC
++ default y
++ help
++ Documentation on the Zilog 85C350 serial communications controller
++ is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>.
++
+ config QTRONIX_KEYBOARD
+ bool "Enable Qtronix 990P Keyboard Support"
+ depends on IT8712
+--- b/drivers/char/Makefile~ 2006-05-25 12:51:52.000000000 +0200
++++ b/drivers/char/Makefile 2006-05-25 12:52:27.000000000 +0200
+@@ -50,6 +50,7 @@
+ obj-$(CONFIG_VIOTAPE) += viotape.o
+ obj-$(CONFIG_HVCS) += hvcs.o
+ obj-$(CONFIG_SGI_MBCS) += mbcs.o
++obj-$(CONFIG_SERIAL_DEC) += decserial.o
+
+ obj-$(CONFIG_PRINTER) += lp.o
+ obj-$(CONFIG_TIPAR) += tipar.o
+--- a/drivers/char/decserial.c
++++ b/drivers/char/decserial.c
+@@ -14,86 +14,84 @@
+ * device. Added support for PROM console in drivers/char/tty_io.c
+ * instead. Although it may work to enable more than one
+ * console device I strongly recommend to use only one.
++ *
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
+
++#include <linux/errno.h>
+ #include <linux/init.h>
+-#include <asm/dec/machtype.h>
+-
+-#ifdef CONFIG_ZS
+-extern int zs_init(void);
+-#endif
+
+-#ifdef CONFIG_DZ
+-extern int dz_init(void);
+-#endif
++#include <asm/dec/machtype.h>
++#include <asm/dec/serial.h>
+
+-#ifdef CONFIG_SERIAL_CONSOLE
++extern int register_zs_hook(unsigned int channel,
++ struct dec_serial_hook *hook);
++extern int unregister_zs_hook(unsigned int channel);
+
++int register_dec_serial_hook(unsigned int channel,
++ struct dec_serial_hook *hook)
++{
+ #ifdef CONFIG_ZS
+-extern void zs_serial_console_init(void);
+-#endif
+-
+-#ifdef CONFIG_DZ
+-extern void dz_serial_console_init(void);
++ if (IOASIC)
++ return register_zs_hook(channel, hook);
+ #endif
++ return 0;
++}
+
++int unregister_dec_serial_hook(unsigned int channel)
++{
++#ifdef CONFIG_ZS
++ if (IOASIC)
++ return unregister_zs_hook(channel);
+ #endif
++ return 0;
++}
+
+-/* rs_init - starts up the serial interface -
+- handle normal case of starting up the serial interface */
+
+-#ifdef CONFIG_SERIAL
++extern int zs_init(void);
++extern int dz_init(void);
+
++/*
++ * rs_init - starts up the serial interface -
++ * handle normal case of starting up the serial interface
++ */
+ int __init rs_init(void)
+ {
+-
+-#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+- if (IOASIC)
+- return zs_init();
+- else
+- return dz_init();
+-#else
+-
+ #ifdef CONFIG_ZS
+- return zs_init();
++ if (IOASIC)
++ return zs_init();
+ #endif
+-
+ #ifdef CONFIG_DZ
+- return dz_init();
+-#endif
+-
++ if (!IOASIC)
++ return dz_init();
+ #endif
++ return -ENXIO;
+ }
+
+ __initcall(rs_init);
+
+-#endif
+
+-#ifdef CONFIG_SERIAL_CONSOLE
++#ifdef CONFIG_SERIAL_DEC_CONSOLE
+
+-/* serial_console_init handles the special case of starting
+- * up the console on the serial port
++extern void zs_serial_console_init(void);
++extern void dz_serial_console_init(void);
++
++/*
++ * dec_serial_console_init handles the special case of starting
++ * up the console on the serial port
+ */
+-static int __init decserial_console_init(void)
++static int __init dec_serial_console_init(void)
+ {
+-#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+- if (IOASIC)
+- zs_serial_console_init();
+- else
+- dz_serial_console_init();
+-#else
+-
+ #ifdef CONFIG_ZS
+- zs_serial_console_init();
++ if (IOASIC)
++ zs_serial_console_init();
+ #endif
+-
+ #ifdef CONFIG_DZ
+- dz_serial_console_init();
+-#endif
+-
++ if (!IOASIC)
++ dz_serial_console_init();
+ #endif
+ return 0;
+ }
+-console_initcall(decserial_console_init);
++console_initcall(dec_serial_console_init);
+
+ #endif
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/header-exports.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/header-exports.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,73 @@
+# Cleanups for kernel header exports, from linux-mips.org 2.6.18-stable,
+# scheduled for mainline.
+
+
+diff --git a/include/asm-mips/Kbuild b/include/asm-mips/Kbuild
+index c68e168..7897f05 100644
+--- a/include/asm-mips/Kbuild
++++ b/include/asm-mips/Kbuild
+@@ -1 +1,3 @@
+ include include/asm-generic/Kbuild.asm
++
++header-y += cachectl.h sgidefs.h sysmips.h
+diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
+index 4113316..4fb0fc4 100644
+--- a/include/asm-mips/ptrace.h
++++ b/include/asm-mips/ptrace.h
+@@ -10,8 +10,6 @@ #ifndef _ASM_PTRACE_H
+ #define _ASM_PTRACE_H
+
+
+-#include <asm/isadep.h>
+-
+ /* 0 - 31 are integer registers, 32 - 63 are fp registers. */
+ #define FPR_BASE 32
+ #define PC 64
+@@ -73,6 +71,7 @@ #define PTRACE_GET_THREAD_AREA_3264 0xc4
+ #ifdef __KERNEL__
+
+ #include <linux/linkage.h>
++#include <asm/isadep.h>
+
+ /*
+ * Does the process account for user or for system time?
+diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h
+index 98aa737..b80de8e 100644
+--- a/include/asm-mips/timex.h
++++ b/include/asm-mips/timex.h
+@@ -8,6 +8,8 @@
+ #ifndef _ASM_TIMEX_H
+ #define _ASM_TIMEX_H
+
++#ifdef __KERNEL__
++
+ #include <asm/mipsregs.h>
+
+ /*
+@@ -51,4 +53,6 @@ static inline cycles_t get_cycles (void)
+ return read_c0_count();
+ }
+
++#endif /* __KERNEL__ */
++
+ #endif /* _ASM_TIMEX_H */
+diff --git a/include/asm-mips/user.h b/include/asm-mips/user.h
+index 89bf8b4..61f2a09 100644
+--- a/include/asm-mips/user.h
++++ b/include/asm-mips/user.h
+@@ -8,6 +8,8 @@
+ #ifndef _ASM_USER_H
+ #define _ASM_USER_H
+
++#ifdef __KERNEL__
++
+ #include <asm/page.h>
+ #include <asm/reg.h>
+
+@@ -55,4 +57,6 @@ #define HOST_TEXT_START_ADDR (u.start_co
+ #define HOST_DATA_START_ADDR (u.start_data)
+ #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
++#endif /* __KERNEL__ */
++
+ #endif /* _ASM_USER_H */
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/ip22-zilog-console.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/ip22-zilog-console.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,22 @@
+# Upstream status: in linux-mips tree; someone needs to figure out how to
+# integrate this into the Linux tree...
+
+--- a/drivers/serial/ip22zilog.c
++++ b/drivers/serial/ip22zilog.c
+@@ -865,6 +865,7 @@ ip22zilog_set_termios(struct uart_port *
+ up->cflag = termios->c_cflag;
+
+ ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
++ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ }
+@@ -1026,6 +1027,8 @@ ip22serial_console_termios(struct consol
+ }
+
+ con->cflag = cflag | CS8; /* 8N1 */
++
++ uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud);
+ }
+
+ static int __init ip22zilog_console_setup(struct console *con, char *options)
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-duart-tts.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-duart-tts.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,24 @@
+Patch: change the name of the sb1250 DUART from duart to ttyS
+Needed for debian-installer
+Status: the sb1250_duart.c driver needs a completely re-write...
+
+--- a/drivers/char/sb1250_duart.c~ 2006-09-05 15:04:15.015419723 +0200
++++ b/drivers/char/sb1250_duart.c 2006-09-05 15:04:24.442152073 +0200
+@@ -762,7 +762,7 @@
+ return -ENOMEM;
+
+ sb1250_duart_driver->owner = THIS_MODULE;
+- sb1250_duart_driver->name = "duart";
++ sb1250_duart_driver->name = "ttyS";
+ sb1250_duart_driver->major = TTY_MAJOR;
+ sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
+ sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL;
+@@ -891,7 +891,7 @@ #endif
+ }
+
+ static struct console sb1250_ser_cons = {
+- .name = "duart",
++ .name = "ttyS",
+ .write = ser_console_write,
+ .device = ser_console_device,
+ .setup = ser_console_setup,
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,67 @@
+# Add missing cache flush, fixes hang on boot from PIO-driven devices,
+# proposed patch at linux-mips.org.
+#
+# Signed-off-by: Thiemo Seufer <ths at networkno.de>
+
+diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
+index 16bad7c..acae51c 100644
+--- a/arch/mips/mm/c-sb1.c
++++ b/arch/mips/mm/c-sb1.c
+@@ -19,6 +19,7 @@
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ #include <linux/init.h>
++#include <linux/hardirq.h>
+
+ #include <asm/asm.h>
+ #include <asm/bootinfo.h>
+@@ -233,6 +234,25 @@ void sb1_flush_cache_page(struct vm_area
+ __attribute__((alias("local_sb1_flush_cache_page")));
+ #endif
+
++#ifdef CONFIG_SMP
++static void sb1_flush_cache_data_page_ipi(void *info)
++{
++ unsigned long start = (unsigned long)info;
++
++ __sb1_writeback_inv_dcache_range(start, start + PAGE_SIZE);
++}
++
++static void sb1_flush_cache_data_page(unsigned long addr)
++{
++ if (in_atomic())
++ __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE);
++ else
++ on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1);
++}
++#else
++void sb1_flush_cache_data_page(unsigned long)
++ __attribute__((alias("local_sb1_flush_cache_data_page")));
++#endif
+
+ /*
+ * Invalidate all caches on this CPU
+@@ -504,7 +524,6 @@ static __init void probe_cache_sizes(voi
+ void sb1_cache_init(void)
+ {
+ extern char except_vec2_sb1;
+- extern char handle_vec2_sb1;
+
+ /* Special cache error handler for SB1 */
+ set_uncached_handler (0x100, &except_vec2_sb1, 0x80);
+@@ -534,7 +553,7 @@ #endif
+
+ flush_cache_sigtramp = sb1_flush_cache_sigtramp;
+ local_flush_data_cache_page = (void *) sb1_nop;
+- flush_data_cache_page = (void *) sb1_nop;
++ flush_data_cache_page = sb1_flush_cache_data_page;
+
+ /* Full flush */
+ __flush_cache_all = sb1___flush_cache_all;
+@@ -558,5 +577,5 @@ #endif
+ :
+ : "memory");
+
+- flush_cache_all();
++ local_sb1___flush_cache_all();
+ }
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-interrupt-handler.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sb1-interrupt-handler.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,76 @@
+# Fix broken interrupt routing for sb1, from linux-mips.org
+# 2.6.18-stable, also in kernel.org mainline.
+
+
+diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
+index ed325f0..a0222fa 100644
+--- a/arch/mips/sibyte/bcm1480/irq.c
++++ b/arch/mips/sibyte/bcm1480/irq.c
+@@ -469,21 +469,6 @@ void bcm1480_kgdb_interrupt(struct pt_re
+
+ #endif /* CONFIG_KGDB */
+
+-static inline int dclz(unsigned long long x)
+-{
+- int lz;
+-
+- __asm__ (
+- " .set push \n"
+- " .set mips64 \n"
+- " dclz %0, %1 \n"
+- " .set pop \n"
+- : "=r" (lz)
+- : "r" (x));
+-
+- return lz;
+-}
+-
+ extern void bcm1480_timer_interrupt(struct pt_regs *regs);
+ extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
+ extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
+@@ -536,9 +521,9 @@ #endif
+
+ if (mask_h) {
+ if (mask_h ^ 1)
+- do_IRQ(63 - dclz(mask_h), regs);
++ do_IRQ(fls64(mask_h) - 1, regs);
+ else
+- do_IRQ(127 - dclz(mask_l), regs);
++ do_IRQ(63 + fls64(mask_l), regs);
+ }
+ }
+ }
+diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
+index 1de71ad..a451b4c 100644
+--- a/arch/mips/sibyte/sb1250/irq.c
++++ b/arch/mips/sibyte/sb1250/irq.c
+@@ -419,21 +419,6 @@ static void sb1250_kgdb_interrupt(struct
+
+ #endif /* CONFIG_KGDB */
+
+-static inline int dclz(unsigned long long x)
+-{
+- int lz;
+-
+- __asm__ (
+- " .set push \n"
+- " .set mips64 \n"
+- " dclz %0, %1 \n"
+- " .set pop \n"
+- : "=r" (lz)
+- : "r" (x));
+-
+- return lz;
+-}
+-
+ extern void sb1250_timer_interrupt(struct pt_regs *regs);
+ extern void sb1250_mailbox_interrupt(struct pt_regs *regs);
+ extern void sb1250_kgdb_interrupt(struct pt_regs *regs);
+@@ -490,6 +475,6 @@ #endif
+ mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
+ R_IMR_INTERRUPT_STATUS_BASE)));
+ if (mask)
+- do_IRQ(63 - dclz(mask), regs);
++ do_IRQ(fls64(mask) - 1, regs);
+ }
+ }
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sgi-ioc3.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/sgi-ioc3.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,164 @@
+# ioc3 driver checksumming fix, from linux-mips.org 2.6.18-stable,
+# scheduled for kernel.org mainline.
+
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index a2bd811..778fbae 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -467,25 +471,6 @@ config SGI_IOC3_ETH
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+-config SGI_IOC3_ETH_HW_RX_CSUM
+- bool "Receive hardware checksums"
+- depends on SGI_IOC3_ETH && INET
+- default y
+- help
+- The SGI IOC3 network adapter supports TCP and UDP checksums in
+- hardware to offload processing of these checksums from the CPU. At
+- the moment only acceleration of IPv4 is supported. This option
+- enables offloading for checksums on receive. If unsure, say Y.
+-
+-config SGI_IOC3_ETH_HW_TX_CSUM
+- bool "Transmit hardware checksums"
+- depends on SGI_IOC3_ETH && INET
+- default y
+- help
+- The SGI IOC3 network adapter supports TCP and UDP checksums in
+- hardware to offload processing of these checksums from the CPU. At
+- the moment only acceleration of IPv4 is supported. This option
+- enables offloading for checksums on transmit. If unsure, say Y.
+
+ config MIPS_SIM_NET
+ tristate "MIPS simulator Network device (EXPERIMENTAL)"
+diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
+index 68d8af7..9837213 100644
+--- a/drivers/net/ioc3-eth.c
++++ b/drivers/net/ioc3-eth.c
+@@ -5,7 +5,7 @@
+ *
+ * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
+ *
+- * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle
++ * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle
+ * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
+ *
+ * References:
+@@ -62,12 +62,7 @@ #include <asm/io.h>
+ #include <asm/pgtable.h>
+ #include <asm/uaccess.h>
+ #include <asm/sn/types.h>
+-#include <asm/sn/sn0/addrs.h>
+-#include <asm/sn/sn0/hubni.h>
+-#include <asm/sn/sn0/hubio.h>
+-#include <asm/sn/klconfig.h>
+ #include <asm/sn/ioc3.h>
+-#include <asm/sn/sn0/ip27.h>
+ #include <asm/pci/bridge.h>
+
+ /*
+@@ -95,6 +90,9 @@ struct ioc3_private {
+ u32 emcr, ehar_h, ehar_l;
+ spinlock_t ioc3_lock;
+ struct mii_if_info mii;
++ unsigned long flags;
++#define IOC3_FLAG_RX_CHECKSUMS 1
++
+ struct pci_dev *pdev;
+
+ /* Members used by autonegotiation */
+@@ -522,8 +520,6 @@ static struct net_device_stats *ioc3_get
+ return &ip->stats;
+ }
+
+-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
+-
+ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
+ {
+ struct ethhdr *eh = eth_hdr(skb);
+@@ -591,7 +587,6 @@ static void ioc3_tcpudp_checksum(struct
+ if (csum == 0xffff)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+-#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */
+
+ static inline void ioc3_rx(struct ioc3_private *ip)
+ {
+@@ -626,9 +621,9 @@ static inline void ioc3_rx(struct ioc3_p
+ goto next;
+ }
+
+-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
+- ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len);
+-#endif
++ if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS))
++ ioc3_tcpudp_checksum(skb,
++ w0 & ERXBUF_IPCKSUM_MASK, len);
+
+ netif_rx(skb);
+
+@@ -1289,9 +1284,7 @@ #endif
+ dev->set_multicast_list = ioc3_set_multicast_list;
+ dev->set_mac_address = ioc3_set_mac_address;
+ dev->ethtool_ops = &ioc3_ethtool_ops;
+-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
+ dev->features = NETIF_F_IP_CSUM;
+-#endif
+
+ sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
+ sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
+@@ -1378,7 +1371,6 @@ static int ioc3_start_xmit(struct sk_buf
+ uint32_t w0 = 0;
+ int produce;
+
+-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
+ /*
+ * IOC3 has a fairly simple minded checksumming hardware which simply
+ * adds up the 1's complement checksum for the entire packet and
+@@ -1426,7 +1418,6 @@ #ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
+
+ w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
+ }
+-#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */
+
+ spin_lock_irq(&ip->ioc3_lock);
+
+@@ -1580,12 +1571,37 @@ static u32 ioc3_get_link(struct net_devi
+ return rc;
+ }
+
++static u32 ioc3_get_rx_csum(struct net_device *dev)
++{
++ struct ioc3_private *ip = netdev_priv(dev);
++
++ return ip->flags & IOC3_FLAG_RX_CHECKSUMS;
++}
++
++static int ioc3_set_rx_csum(struct net_device *dev, u32 data)
++{
++ struct ioc3_private *ip = netdev_priv(dev);
++
++ spin_lock_bh(&ip->ioc3_lock);
++ if (data)
++ ip->flags |= IOC3_FLAG_RX_CHECKSUMS;
++ else
++ ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS;
++ spin_unlock_bh(&ip->ioc3_lock);
++
++ return 0;
++}
++
+ static struct ethtool_ops ioc3_ethtool_ops = {
+ .get_drvinfo = ioc3_get_drvinfo,
+ .get_settings = ioc3_get_settings,
+ .set_settings = ioc3_set_settings,
+ .nway_reset = ioc3_nway_reset,
+ .get_link = ioc3_get_link,
++ .get_rx_csum = ioc3_get_rx_csum,
++ .set_rx_csum = ioc3_set_rx_csum,
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = ethtool_op_set_tx_csum
+ };
+
+ static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/signal-handling.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/signal-handling.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,78 @@
+# Fix signal handling, from linux-mips.org 2.6.18-stable, scheduled for
+# kernel.org mainline.
+
+
+diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
+index 6b4d9be..b9d358e 100644
+--- a/arch/mips/kernel/signal.c
++++ b/arch/mips/kernel/signal.c
+@@ -424,15 +424,11 @@ void do_signal(struct pt_regs *regs)
+ if (!user_mode(regs))
+ return;
+
+- if (try_to_freeze())
+- goto no_signal;
+-
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
+ oldset = ¤t->blocked;
+
+-
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+@@ -446,9 +442,10 @@ void do_signal(struct pt_regs *regs)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
++
++ return;
+ }
+
+-no_signal:
+ /*
+ * Who's code doesn't conform to the restartable syscall convention
+ * dies here!!! The li instruction, a single machine instruction,
+@@ -466,6 +463,7 @@ no_signal:
+ regs->regs[7] = regs->regs[26];
+ regs->cp0_epc -= 4;
+ }
++ regs->regs[0] = 0; /* Don't deal with this again. */
+ }
+
+ /*
+diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
+index f32a229..c86a5dd 100644
+--- a/arch/mips/kernel/signal32.c
++++ b/arch/mips/kernel/signal32.c
+@@ -815,9 +815,6 @@ void do_signal32(struct pt_regs *regs)
+ if (!user_mode(regs))
+ return;
+
+- if (try_to_freeze())
+- goto no_signal;
+-
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
+@@ -836,9 +833,10 @@ void do_signal32(struct pt_regs *regs)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
++
++ return;
+ }
+
+-no_signal:
+ /*
+ * Who's code doesn't conform to the restartable syscall convention
+ * dies here!!! The li instruction, a single machine instruction,
+@@ -856,6 +854,7 @@ no_signal:
+ regs->regs[7] = regs->regs[26];
+ regs->cp0_epc -= 4;
+ }
++ regs->regs[0] = 0; /* Don't deal with this again. */
+ }
+
+ /*
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/smp-cpu-bringup.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/smp-cpu-bringup.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,85 @@
+# Fix bringup of non-contiguous CPU topology, from linux-mips.org
+# 2.6.18-stable, scheduled for kernel.org mainline.
+
+
+diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h
+index 896550b..d35c617 100644
+--- a/include/asm-mips/irq.h
++++ b/include/asm-mips/irq.h
+@@ -76,8 +76,4 @@ extern int setup_irq_smtc(unsigned int i
+ unsigned long hwmask);
+ #endif /* CONFIG_MIPS_MT_SMTC */
+
+-#ifdef CONFIG_SMP
+-#define ARCH_HAS_IRQ_PER_CPU
+-#endif
+-
+ #endif /* _ASM_IRQ_H */
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index 330f6ab..96165d7 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -614,6 +610,7 @@ config SGI_IP27
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_NUMA
++ select SYS_SUPPORTS_SMP
+ help
+ This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
+ workstations. To compile a Linux kernel that runs on these, say Y
+@@ -1649,9 +1648,7 @@ config GENERIC_IRQ_PROBE
+ default y
+
+ config IRQ_PER_CPU
+- depends on SMP
+ bool
+- default y
+
+ #
+ # - Highmem only makes sense for the 32-bit kernel.
+@@ -1691,9 +1688,6 @@ config ARCH_DISCONTIGMEM_ENABLE
+
+ config ARCH_SPARSEMEM_ENABLE
+ bool
+-
+-config ARCH_SPARSEMEM_ENABLE
+- bool
+ select SPARSEMEM_STATIC
+
+ config NUMA
+@@ -1719,6 +1713,7 @@ source "mm/Kconfig"
+ config SMP
+ bool "Multi-Processing support"
+ depends on SYS_SUPPORTS_SMP
++ select IRQ_PER_CPU
+ help
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, like most personal computers, say N. If
+diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
+index 2218958..1af3612 100644
+--- a/arch/mips/kernel/smp.c
++++ b/arch/mips/kernel/smp.c
+@@ -467,14 +467,18 @@ static DEFINE_PER_CPU(struct cpu, cpu_de
+
+ static int __init topology_init(void)
+ {
+- int cpu;
+- int ret;
++ int i, ret;
+
+- for_each_present_cpu(cpu) {
+- ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
++#ifdef CONFIG_NUMA
++ for_each_online_node(i)
++ register_one_node(i);
++#endif /* CONFIG_NUMA */
++
++ for_each_present_cpu(i) {
++ ret = register_cpu(&per_cpu(cpu_devices, i), i);
+ if (ret)
+ printk(KERN_WARNING "topology_init: register_cpu %d "
+- "failed (%d)\n", cpu, ret);
++ "failed (%d)\n", i, ret);
+ }
+
+ return 0;
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/syscall-wiring.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/syscall-wiring.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,54 @@
+# Fix syscall wiring for n32 rt_sigqueueinfo, fix implementation of
+# sys_set_thread_area. Patch from linux-mips.org 2.6.18-stable,
+# scheduled for kernel.org mainline.
+
+
+diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
+index 450ac59..dc500e2 100644
+--- a/arch/mips/kernel/linux32.c
++++ b/arch/mips/kernel/linux32.c
+@@ -1296,9 +1296,3 @@ _sys32_clone(nabi_no_regargs struct pt_r
+ return do_fork(clone_flags, newsp, ®s, 0,
+ parent_tidptr, child_tidptr);
+ }
+-
+-extern asmlinkage void sys_set_thread_area(u32 addr);
+-asmlinkage void sys32_set_thread_area(u32 addr)
+-{
+- sys_set_thread_area(AA(addr));
+-}
+diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
+index 0721314..9951240 100644
+--- a/arch/mips/kernel/syscall.c
++++ b/arch/mips/kernel/syscall.c
+@@ -263,7 +263,7 @@ asmlinkage int sys_olduname(struct oldol
+ return error;
+ }
+
+-void sys_set_thread_area(unsigned long addr)
++asmlinkage int sys_set_thread_area(unsigned long addr)
+ {
+ struct thread_info *ti = task_thread_info(current);
+
+@@ -271,6 +271,8 @@ void sys_set_thread_area(unsigned long a
+
+ /* If some future MIPS implementation has this register in hardware,
+ * we will need to update it here (and in context switches). */
++
++ return 0;
+ }
+
+ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
+diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
+index 98abbc5..f25c2a2 100644
+--- a/arch/mips/kernel/scall64-n32.S
++++ b/arch/mips/kernel/scall64-n32.S
+@@ -247,7 +247,7 @@ EXPORT(sysn32_call_table)
+ PTR sys_capset
+ PTR sys32_rt_sigpending /* 6125 */
+ PTR compat_sys_rt_sigtimedwait
+- PTR sys_rt_sigqueueinfo
++ PTR sys32_rt_sigqueueinfo
+ PTR sysn32_rt_sigsuspend
+ PTR sys32_sigaltstack
+ PTR compat_sys_utime /* 6130 */
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/mips/wait-race.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/mips/wait-race.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,118 @@
+# Fix race condition of wait with enabled interrupts, from linux-mips.org
+# 2.6.18-stable, also in kernel.org mainline.
+
+
+diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
+index aa2caa6..8485af3 100644
+--- a/arch/mips/kernel/cpu-probe.c
++++ b/arch/mips/kernel/cpu-probe.c
+@@ -38,15 +38,40 @@ static void r3081_wait(void)
+
+ static void r39xx_wait(void)
+ {
+- unsigned long cfg = read_c0_conf();
+- write_c0_conf(cfg | TX39_CONF_HALT);
++ local_irq_disable();
++ if (!need_resched())
++ write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
++ local_irq_enable();
+ }
+
++/*
++ * There is a race when WAIT instruction executed with interrupt
++ * enabled.
++ * But it is implementation-dependent wheter the pipelie restarts when
++ * a non-enabled interrupt is requested.
++ */
+ static void r4k_wait(void)
+ {
+- __asm__(".set\tmips3\n\t"
+- "wait\n\t"
+- ".set\tmips0");
++ __asm__(" .set mips3 \n"
++ " wait \n"
++ " .set mips0 \n");
++}
++
++/*
++ * This variant is preferable as it allows testing need_resched and going to
++ * sleep depending on the outcome atomically. Unfortunately the "It is
++ * implementation-dependent whether the pipeline restarts when a non-enabled
++ * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
++ * using this version a gamble.
++ */
++static void r4k_wait_irqoff(void)
++{
++ local_irq_disable();
++ if (!need_resched())
++ __asm__(" .set mips3 \n"
++ " wait \n"
++ " .set mips0 \n");
++ local_irq_enable();
+ }
+
+ /* The Au1xxx wait is available only if using 32khz counter or
+@@ -56,17 +81,17 @@ int allow_au1k_wait;
+ static void au1k_wait(void)
+ {
+ /* using the wait instruction makes CP0 counter unusable */
+- __asm__(".set mips3\n\t"
+- "cache 0x14, 0(%0)\n\t"
+- "cache 0x14, 32(%0)\n\t"
+- "sync\n\t"
+- "nop\n\t"
+- "wait\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- "nop\n\t"
+- ".set mips0\n\t"
++ __asm__(" .set mips3 \n"
++ " cache 0x14, 0(%0) \n"
++ " cache 0x14, 32(%0) \n"
++ " sync \n"
++ " nop \n"
++ " wait \n"
++ " nop \n"
++ " nop \n"
++ " nop \n"
++ " nop \n"
++ " .set mips0 \n"
+ : : "r" (au1k_wait));
+ }
+
+@@ -110,8 +135,6 @@ static inline void check_wait(void)
+ case CPU_R5000:
+ case CPU_NEVADA:
+ case CPU_RM7000:
+- case CPU_RM9000:
+- case CPU_TX49XX:
+ case CPU_4KC:
+ case CPU_4KEC:
+ case CPU_4KSC:
+@@ -125,6 +148,10 @@ static inline void check_wait(void)
+ cpu_wait = r4k_wait;
+ printk(" available.\n");
+ break;
++ case CPU_TX49XX:
++ cpu_wait = r4k_wait_irqoff;
++ printk(" available.\n");
++ break;
+ case CPU_AU1000:
+ case CPU_AU1100:
+ case CPU_AU1500:
+@@ -136,6 +163,14 @@ static inline void check_wait(void)
+ } else
+ printk(" unavailable.\n");
+ break;
++ case CPU_RM9000:
++ if ((c->processor_id & 0x00ff) >= 0x40) {
++ cpu_wait = r4k_wait;
++ printk(" available.\n");
++ } else {
++ printk(" unavailable.\n");
++ }
++ break;
+ default:
+ printk(" unavailable.\n");
+ break;
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/net-netpoll.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/net-netpoll.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,42 @@
+From netdev-owner at vger.kernel.org Wed Oct 18 23:31:05 2006
+From: Stephen Hemminger <shemminger at osdl.org>
+
+If netpoll uses up it's retries, it should drop the skb
+not leak memory.
+
+Signed-off-by: Stephen Hemminger <shemminger at osdl.org>
+---
+ net/core/netpoll.c | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/net/core/netpoll.c b/net/core/netpoll.c
+index ead5920..c375fde 100644
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -273,10 +273,8 @@ static void netpoll_send_skb(struct netp
+ int status;
+ struct netpoll_info *npinfo;
+
+- if (!np || !np->dev || !netif_running(np->dev)) {
+- __kfree_skb(skb);
+- return;
+- }
++ if (!np || !np->dev || !netif_running(np->dev))
++ goto free_skb;
+
+ npinfo = np->dev->npinfo;
+
+@@ -314,6 +312,8 @@ static void netpoll_send_skb(struct netp
+ netpoll_poll(np);
+ udelay(50);
+ } while (npinfo->tries > 0);
++free_skb:
++ __kfree_skb(skb);
+ }
+
+ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
+--
+1.4.2.3
+
+
+
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/build-links.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/build-links.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,26 @@
+diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
+index 01667d1..4d650e1 100644
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -177,7 +177,7 @@ # Temporary hack until we have migrated
+ include/asm: arch/$(ARCH)/include/asm
+ arch/$(ARCH)/include/asm: FORCE
+ $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi
+- $(Q)ln -fsn $(srctree)/include/asm-$(OLDARCH) arch/$(ARCH)/include/asm
++ $(Q)ln -fsn $(if $(KBUILD_SRC),$(KBUILD_SRC),../../..)/include/asm-$(OLDARCH) arch/$(ARCH)/include/asm
+ endif
+
+ # Use the file '.tmp_gas_check' for binutils tests, as gas won't output
+diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
+index 0db66dc..8523a15 100644
+--- a/arch/ppc/Makefile
++++ b/arch/ppc/Makefile
+@@ -116,7 +116,7 @@ # Temporary hack until we have migrated
+ include/asm: arch/$(ARCH)/include/asm
+ arch/$(ARCH)/include/asm:
+ $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi
+- $(Q)ln -fsn $(srctree)/include/asm-powerpc arch/$(ARCH)/include/asm
++ $(Q)ln -fsn $(if $(KBUILD_SRC),$(KBUILD_SRC),../../..)/include/asm-powerpc arch/$(ARCH)/include/asm
+
+ # Use the file '.tmp_gas_check' for binutils tests, as gas won't output
+ # to stdout and these checks are run even on install targets.
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/mv643xx-hotplug-support.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/mv643xx-hotplug-support.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,35 @@
+#
+# Hotplug support patch for mv643xx_eth driver used on pegasos machines.
+# Author: Nicolas Det <nicolas.det at bplan-gmbh.de>
+# Upstream status: In the process of being submitted, may need a bit of
+# cleanup in order to not break embedded arches using this controller, but
+# should not be a worry for debian.
+#
+--- linux/drivers/net/mv643xx_eth.c.orig 2006-01-01 17:22:07.000000000 +0000
++++ linux/drivers/net/mv643xx_eth.c 2006-01-01 17:23:56.000000000 +0000
+@@ -41,6 +41,8 @@
+ #include <linux/ethtool.h>
+ #include <linux/platform_device.h>
+
++#include <linux/pci.h>
++
+ #include <asm/io.h>
+ #include <asm/types.h>
+ #include <asm/pgtable.h>
+@@ -1635,6 +1637,15 @@
+ " and Dale Farnsworth");
+ MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX");
+
++static struct pci_device_id pci_marvell_mv64360[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) },
++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64460) },
++ { }
++};
++
++MODULE_DEVICE_TABLE(pci, pci_marvell_mv64360);
++
++
+ /*
+ * The second part is the low level driver of the gigE ethernet ports.
+ */
+
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/oldworld-boot-fix.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/oldworld-boot-fix.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,54 @@
+# Patch author: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+# Description: Fix oldworld initrd loading problems.
+# It looks like older OF "setprop" is bogus and isn't actually copying the
+# data but just taking a pointer. The LongTrail workaround also has that
+# problem as "property" will not copy the data. This fixes the workaround
+# and applies it to Apple OF 1.0.5.
+# Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+# Closes:
+# 375035: Kernel 2.6.16 attempts to access root device before running initramfs init
+# 366620: initramfs-tools: 2.6.16-1-powerpc fails to mount rootfs, 2.6.15-1-powerpc works
+#
+
+Index: linux-tika/arch/powerpc/kernel/prom_init.c
+===================================================================
+--- linux-tika.orig/arch/powerpc/kernel/prom_init.c 2006-09-02 09:53:00.000000000 +1000
++++ linux-tika/arch/powerpc/kernel/prom_init.c 2006-09-18 20:55:26.000000000 +1000
+@@ -102,7 +102,7 @@
+ #endif
+
+ #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */
+-#define OF_WA_LONGTRAIL 2 /* work around longtrail bugs */
++#define OF_WA_SETPROP 2 /* work around setprop bugs */
+
+ #define PROM_BUG() do { \
+ prom_printf("kernel BUG at %s line 0x%x!\n", \
+@@ -472,7 +472,7 @@
+ {
+ char cmd[256], *p;
+
+- if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL))
++ if (!(OF_WORKAROUNDS & OF_WA_SETPROP))
+ return call_prom("setprop", 4, 1, node, ADDR(pname),
+ (u32)(unsigned long) value, (u32) valuelen);
+
+@@ -482,6 +482,7 @@
+ add_string(&p, nodename);
+ add_string(&p, tohex((u32)(unsigned long) value));
+ add_string(&p, tohex(valuelen));
++ add_string(&p, "encode-bytes");
+ add_string(&p, tohex(ADDR(pname)));
+ add_string(&p, tohex(strlen(RELOC(pname))));
+ add_string(&p, "property");
+@@ -1466,9 +1467,9 @@
+ version[sizeof(version) - 1] = 0;
+ /* XXX might need to add other versions here */
+ if (strcmp(version, "Open Firmware, 1.0.5") == 0)
+- of_workarounds = OF_WA_CLAIM;
++ of_workarounds = OF_WA_CLAIM | OF_WA_SETPROP;
+ else if (strncmp(version, "FirmWorks,3.", 12) == 0) {
+- of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
++ of_workarounds = OF_WA_CLAIM | OF_WA_SETPROP;
+ call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
+ } else
+ return;
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/prep-utah-ide-interrupt.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/prep-utah-ide-interrupt.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,16 @@
+#
+# Description: Reenables IDE interrupt on Motorola Powerstack II (Utah)
+# Patch author: Sven Luther <luther at debian.org>
+# Closes: #345424: linux-source-2.6.14: Missing IDE IRQ for PReP Utah (PowerstackII Pro4000)
+#
+--- linux-2.6-2.6.14+2.6.15-rc7/arch/ppc/platforms/prep_pci.c.orig 2005-12-31 14:51:16.000000000 +0000
++++ linux-2.6-2.6.14+2.6.15-rc7/arch/ppc/platforms/prep_pci.c 2005-12-31 14:58:23.000000000 +0000
+@@ -46,7 +46,7 @@
+ static char Utah_pci_IRQ_map[23] =
+ {
+ 0, /* Slot 0 - unused */
+- 0, /* Slot 1 - unused */
++ 4, /* Slot 1 - IDE - SL82C105 */
+ 5, /* Slot 2 - SCSI - NCR825A */
+ 0, /* Slot 3 - unused */
+ 3, /* Slot 4 - Ethernet - DEC2114x */
Added: people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/serial.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/bugfix/powerpc/serial.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,50 @@
+#! /bin/sh -e
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Disables legacy serial driver on powermacs.
+## DP: Patch author: Sven Luther <luther at debian.org>
+## DP: Patch author: adapted from the SuSE kernel tree.
+## DP: Forward ported to 2.6.17 by Mark Hymers <mark at hymers.org.uk>
+## DP: Upstream status: workaround hack waiting for a clean legacy device solution.
+
+diff -aurN a/drivers/serial/8250.c b/drivers/serial/8250.c
+--- a/drivers/serial/8250.c 2005-06-17 15:48:29.000000000 -0400
++++ b/drivers/serial/8250.c 2005-06-18 12:05:39.000000000 -0400
+@@ -45,6 +45,10 @@
+ #include <asm/io.h>
+ #include <asm/irq.h>
+
++#ifdef CONFIG_PPC_PMAC
++#include <asm/machdep.h>
++#endif
++
+ #include "8250.h"
+
+ /*
+@@ -2307,6 +2312,12 @@
+
+ static int __init serial8250_console_init(void)
+ {
++#ifdef CONFIG_PPC_PMAC
++ if(machine_is(powermac)) {
++ printk("%s: nothing to do on PowerMac\n",__FUNCTION__);
++ return -ENODEV;
++ }
++#endif
+ serial8250_isa_init_ports();
+ register_console(&serial8250_console);
+ return 0;
+@@ -2617,6 +2628,13 @@
+ {
+ int ret, i;
+
++#ifdef CONFIG_PPC_PMAC
++ if(machine_is(powermac)) {
++ printk("%s: nothing to do on PowerMac\n",__FUNCTION__);
++ return -ENODEV;
++ }
++#endif
++
+ if (nr_uarts > UART_NR)
+ nr_uarts = UART_NR;
+
Added: people/maks-guest/linux-2.6/debian/patches/debian/doc-build-parallel.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/doc-build-parallel.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,13 @@
+diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
+index 5a2882d..71c7077 100644
+--- a/Documentation/DocBook/Makefile
++++ b/Documentation/DocBook/Makefile
+@@ -146,7 +146,7 @@ quiet_cmd_db2html = HTML $@
+ cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi
+
+ quiet_cmd_db2man = MAN $@
+- cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; gzip -f $(obj)/man/*.9; fi
++ cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; fi
+ %.9 : %.xml
+ @(which xmlto > /dev/null 2>&1) || \
+ (echo "*** You need to install xmlto ***"; \
Added: people/maks-guest/linux-2.6/debian/patches/debian/kernelvariables.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/kernelvariables.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,26 @@
+diff --git a/Makefile b/Makefile
+index edfc2fd..2fb76d7 100644
+--- a/Makefile
++++ b/Makefile
+@@ -176,9 +176,6 @@ # Note: Some architectures assign CROSS_
+ ARCH ?= $(SUBARCH)
+ CROSS_COMPILE ?=
+
+-# Architecture as present in compile.h
+-UTS_MACHINE := $(ARCH)
+-
+ KCONFIG_CONFIG ?= .config
+
+ # SHELL used by kbuild
+@@ -298,6 +295,11 @@ LDFLAGS_MODULE = -r
+ CFLAGS_KERNEL =
+ AFLAGS_KERNEL =
+
++-include .kernelvariables
++
++# Architecture as present in compile.h
++UTS_MACHINE := $(ARCH)
++
+
+ # Use LINUXINCLUDE when you must reference the include/ directory.
+ # Needed to be compatible with the O= option
Added: people/maks-guest/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,57 @@
+#
+# Mkvmlinuz support patch, called by debian's kernel-package to generate
+# the files needed by mkvmlinuz to generate the bootable images from vmlinux.
+# Author: Sven Luther <luther at debian.org>
+# Based on work from: Jens Schmalzing <jensen at debian.org>
+# Original comment from Jens :
+# This shell script is intended to be put into the debian subdirectory
+# of a Linux kernel tree, where make-kpkg will find and execute it
+# while building a kernel-image package. The purpose of this script
+# is to add glue (object code, libraries, utilities and so on) from
+# the kernel tree to the kernel-image package. Later, the mkvmlinuz
+# utility, which is available as a separate Debian package, can use
+# this glue to create a bootable compressed kernel from the
+# uncompressed kernel in the kernel-image package and optionally a
+# ramdisk. This is especially important on PowerPC subarchitectures
+# that don't have a boot loader, but also comes handy for rescue
+# systems and the like.
+# Upstream status: This patch stays a debian specific patch for now,
+# but it is not in a form where it could go upstream.
+#
+--- linux-2.6.17/arch/powerpc/Makefile.orig 2006-04-12 16:57:16.000000000 +0000
++++ linux-2.6.17/arch/powerpc/Makefile 2006-04-12 16:58:53.000000000 +0000
+@@ -147,7 +147,7 @@
+
+ CPPFLAGS_vmlinux.lds := -Upowerpc
+
+-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin
++BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin mkvmlinuz_support_install
+
+ PHONY += $(BOOT_TARGETS)
+
+--- linux-2.6.16/arch/powerpc/boot/Makefile.orig 2006-04-12 16:40:11.000000000 +0000
++++ linux-2.6.16/arch/powerpc/boot/Makefile 2006-04-12 19:23:06.000000000 +0000
+@@ -213,3 +213,23 @@
+ sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
+
+ clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
++
++#-----------------------------------------------------------
++# install mkvmlinuz support files
++#-----------------------------------------------------------
++quiet_cmd_mkvmlinuz = INSTALL mkvmlinuz support files
++ cmd_mkvmlinuz = cp -f $? $(INSTALL_MKVMLINUZ)
++
++mkvmlinuz-obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/mkvmlinuz-kernel-%.o, $(section)))
++mkvmlinuz-src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/mkvmlinuz-kernel-%.c, $(section)))
++
++$(call mkvmlinuz-src-sec, $(required) $(initrd)): $(obj)/mkvmlinuz-kernel-%.c:
++ @touch $@
++$(call mkvmlinuz-obj-sec, $(required) $(initrd)): $(obj)/mkvmlinuz-kernel-%.o: $(obj)/mkvmlinuz-kernel-%.c
++ $(call if_changed_dep,bootcc)
++
++$(obj)/mkvmlinuz_support_install: $(obj)/addRamDisk $(obj)/addnote $(obj-boot) $(call mkvmlinuz-obj-sec, $(required) $(initrd)) $(srctree)/$(src)/zImage.lds
++ mkdir -p $(INSTALL_MKVMLINUZ)
++ $(call cmd,mkvmlinuz)
++targets += mkvmlinuz_support_install
++
Added: people/maks-guest/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-ppc.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-ppc.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,48 @@
+#
+# Mkvmlinuz support patch, called by debian's kernel-package to generate
+# the files needed by mkvmlinuz to generate the bootable images from vmlinux.
+# Author: Sven Luther <luther at debian.org>
+# Based on work from: Jens Schmalzing <jensen at debian.org>
+# Original comment from Jens :
+# This shell script is intended to be put into the debian subdirectory
+# of a Linux kernel tree, where make-kpkg will find and execute it
+# while building a kernel-image package. The purpose of this script
+# is to add glue (object code, libraries, utilities and so on) from
+# the kernel tree to the kernel-image package. Later, the mkvmlinuz
+# utility, which is available as a separate Debian package, can use
+# this glue to create a bootable compressed kernel from the
+# uncompressed kernel in the kernel-image package and optionally a
+# ramdisk. This is especially important on PowerPC subarchitectures
+# that don't have a boot loader, but also comes handy for rescue
+# systems and the like.
+# Upstream status: well, this is a debian specific hack, it would be nice
+# if it was going upstream, but probably not in this form.
+#
+--- linux-kernel-2.6.12-2.6.12/arch/ppc/boot/Makefile.orig 2005-07-15 12:46:28.000000000 +0000
++++ linux-kernel-2.6.12-2.6.12/arch/ppc/boot/Makefile 2005-07-15 12:55:56.000000000 +0000
+@@ -32,3 +32,25 @@
+ $(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
+ $(addprefix $(obj)/,$(hostprogs-y))
+ $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
++
++mkvmlinuz_support_install:
++ # mkvmlinuz support, based on work done originally by Jens Schmalzing <jensen at debian.org>
++ mkdir -p $(INSTALL_MKVMLINUZ)/boot
++ install -m 644 ld.script $(INSTALL_MKVMLINUZ)/boot
++
++ mkdir -p $(INSTALL_MKVMLINUZ)/lib
++ install -m 644 ../../../lib/lib.a $(INSTALL_MKVMLINUZ)/lib
++ install -m 644 lib/lib.a $(INSTALL_MKVMLINUZ)/lib/ppc.a
++ install -m 644 common/lib.a $(INSTALL_MKVMLINUZ)/lib/common.a
++ if [ -e of1275/lib.a ]; then \
++ install -m 644 of1275/lib.a $(INSTALL_MKVMLINUZ)/lib/of.a; \
++ fi
++
++ mkdir -p $(INSTALL_MKVMLINUZ)/obj/simple
++ install -m 644 simple/*.o $(INSTALL_MKVMLINUZ)/obj/simple
++ rm -f $(INSTALL_MKVMLINUZ)/obj/simple/image*.o
++
++ mkdir -p $(INSTALL_MKVMLINUZ)/utils
++ install -m 755 utils/mkbugboot $(INSTALL_MKVMLINUZ)/utils
++ install -m 755 utils/mkprep $(INSTALL_MKVMLINUZ)/utils
++ install -m 755 utils/mktree $(INSTALL_MKVMLINUZ)/utils
Added: people/maks-guest/linux-2.6/debian/patches/debian/scripts-kconfig-reportoldconfig.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/scripts-kconfig-reportoldconfig.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,321 @@
+diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
+index e6499db..c16974c 100644
+--- a/scripts/kconfig/Makefile
++++ b/scripts/kconfig/Makefile
+@@ -2,7 +2,7 @@ # ======================================
+ # Kernel configuration targets
+ # These targets are used from top-level makefile
+
+-PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
++PHONY += oldconfig xconfig gconfig menuconfig config reportoldconfig silentoldconfig updateoldconfig update-po-config
+
+ xconfig: $(obj)/qconf
+ $< arch/$(ARCH)/Kconfig
+@@ -20,9 +20,15 @@ config: $(obj)/conf
+ oldconfig: $(obj)/conf
+ $< -o arch/$(ARCH)/Kconfig
+
++reportoldconfig: $(obj)/conf
++ $< -R arch/$(ARCH)/Kconfig
++
+ silentoldconfig: $(obj)/conf
+ $< -s arch/$(ARCH)/Kconfig
+
++updateoldconfig: $(obj)/conf
++ $< -U arch/$(ARCH)/Kconfig
++
+ update-po-config: $(obj)/kxgettext
+ xgettext --default-domain=linux \
+ --add-comments --keyword=_ --keyword=N_ \
+diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
+index 4dcb886..b5e1b25 100644
+--- a/scripts/kconfig/conf.c
++++ b/scripts/kconfig/conf.c
+@@ -4,6 +4,7 @@
+ */
+
+ #include <ctype.h>
++#include <stdbool.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+@@ -490,11 +491,100 @@ static void check_conf(struct menu *menu
+ check_conf(child);
+ }
+
++void report_changes(void)
++{
++ struct symbol *sym;
++ struct menu *menu;
++ int type, l;
++ const char *str;
++
++ fprintf(stdout, "\n#\n"
++ "# Changes:\n"
++ "#\n");
++ menu = rootmenu.list;
++ while (menu) {
++ sym = menu->sym;
++ if (!sym) {
++ if (!menu_is_visible(menu))
++ goto next;
++ } else if (!(sym->flags & SYMBOL_CHOICE)) {
++ sym_calc_value(sym);
++ if ((sym->flags & (SYMBOL_WRITE | SYMBOL_CHANGED_REAL | SYMBOL_DEF_USER)) !=
++ (SYMBOL_WRITE | SYMBOL_CHANGED_REAL | SYMBOL_DEF_USER))
++ goto next;
++ if (sym->visible == no)
++ goto next;
++ type = sym->type;
++ if (type == S_TRISTATE) {
++ sym_calc_value(modules_sym);
++ if (modules_sym->curr.tri == no)
++ type = S_BOOLEAN;
++ }
++ switch (type) {
++ case S_BOOLEAN:
++ case S_TRISTATE:
++ switch (sym_get_tristate_value(sym)) {
++ case no:
++ fprintf(stdout, "# CONFIG_%s is not set\n", sym->name);
++ break;
++ case mod:
++ fprintf(stdout, "CONFIG_%s=m\n", sym->name);
++ break;
++ case yes:
++ fprintf(stdout, "CONFIG_%s=y\n", sym->name);
++ break;
++ }
++ break;
++ case S_STRING:
++ str = sym_get_string_value(sym);
++ fprintf(stdout, "CONFIG_%s=\"", sym->name);
++ while (1) {
++ l = strcspn(str, "\"\\");
++ if (l) {
++ fwrite(str, l, 1, stdout);
++ str += l;
++ }
++ if (!*str)
++ break;
++ fprintf(stdout, "\\%c", *str++);
++ }
++ fputs("\"\n", stdout);
++ break;
++ case S_HEX:
++ str = sym_get_string_value(sym);
++ if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
++ fprintf(stdout, "CONFIG_%s=%s\n", sym->name, str);
++ break;
++ }
++ case S_INT:
++ str = sym_get_string_value(sym);
++ fprintf(stdout, "CONFIG_%s=%s\n", sym->name, str);
++ break;
++ }
++ }
++
++ next:
++ if (menu->list) {
++ menu = menu->list;
++ continue;
++ }
++ if (menu->next)
++ menu = menu->next;
++ else while ((menu = menu->parent)) {
++ if (menu->next) {
++ menu = menu->next;
++ break;
++ }
++ }
++ }
++}
++
+ int main(int ac, char **av)
+ {
+ int i = 1;
+ const char *name;
+ struct stat tmpstat;
++ bool report = false, update = false;
+
+ if (ac > i && av[i][0] == '-') {
+ switch (av[i++][1]) {
+@@ -530,6 +620,14 @@ int main(int ac, char **av)
+ input_mode = set_random;
+ srandom(time(NULL));
+ break;
++ case 'R':
++ input_mode = set_default;
++ report = update = true;
++ break;
++ case 'U':
++ input_mode = set_default;
++ update = true;
++ break;
+ case 'h':
+ case '?':
+ fprintf(stderr, "See README for usage info\n");
+@@ -545,13 +643,17 @@ int main(int ac, char **av)
+ //zconfdump(stdout);
+ switch (input_mode) {
+ case set_default:
+- if (!defconfig_file)
+- defconfig_file = conf_get_default_confname();
+- if (conf_read(defconfig_file)) {
+- printf("***\n"
+- "*** Can't find default configuration \"%s\"!\n"
+- "***\n", defconfig_file);
+- exit(1);
++ if (update)
++ conf_read(NULL);
++ else {
++ if (!defconfig_file)
++ defconfig_file = conf_get_default_confname();
++ if (conf_read(defconfig_file)) {
++ printf("***\n"
++ "*** Can't find default configuration \"%s\"!\n"
++ "***\n", defconfig_file);
++ exit(1);
++ }
+ }
+ break;
+ case ask_silent:
+@@ -613,6 +715,10 @@ int main(int ac, char **av)
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
++
++ if (report)
++ report_changes();
++
+ if (conf_write(NULL)) {
+ fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+ return 1;
+diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
+index a69d8ac..0acd498 100644
+--- a/scripts/kconfig/confdata.c
++++ b/scripts/kconfig/confdata.c
+@@ -338,8 +338,6 @@ int conf_read(const char *name)
+ /* maybe print value in verbose mode... */
+ sym_ok:
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+- if (sym->visible == no)
+- sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
+index 6084525..9be2d56 100644
+--- a/scripts/kconfig/expr.h
++++ b/scripts/kconfig/expr.h
+@@ -101,6 +101,7 @@ #define SYMBOL_DEF_USER 0x10000
+ #define SYMBOL_DEF_AUTO 0x20000
+ #define SYMBOL_DEF3 0x40000
+ #define SYMBOL_DEF4 0x80000
++#define SYMBOL_CHANGED_REAL 0x100000
+
+ #define SYMBOL_MAXLENGTH 256
+ #define SYMBOL_HASHSIZE 257
+diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
+index 2628023..c7ecae9 100644
+--- a/scripts/kconfig/lkc.h
++++ b/scripts/kconfig/lkc.h
+@@ -103,7 +103,7 @@ const char *str_get(struct gstr *gs);
+ void sym_init(void);
+ void sym_clear_all_valid(void);
+ void sym_set_all_changed(void);
+-void sym_set_changed(struct symbol *sym);
++void sym_set_changed(struct symbol *sym, bool real);
+ struct symbol *sym_check_deps(struct symbol *sym);
+ struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+ struct symbol *prop_get_symbol(struct property *prop);
+diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
+index ee225ce..f8a31ee 100644
+--- a/scripts/kconfig/symbol.c
++++ b/scripts/kconfig/symbol.c
+@@ -4,6 +4,7 @@
+ */
+
+ #include <ctype.h>
++#include <stdbool.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <regex.h>
+@@ -206,7 +207,7 @@ static void sym_calc_visibility(struct s
+ tri = yes;
+ if (sym->visible != tri) {
+ sym->visible = tri;
+- sym_set_changed(sym);
++ sym_set_changed(sym, false);
+ }
+ if (sym_is_choice_value(sym))
+ return;
+@@ -217,7 +218,7 @@ static void sym_calc_visibility(struct s
+ tri = yes;
+ if (sym->rev_dep.tri != tri) {
+ sym->rev_dep.tri = tri;
+- sym_set_changed(sym);
++ sym_set_changed(sym, false);
+ }
+ }
+
+@@ -354,7 +355,7 @@ void sym_calc_value(struct symbol *sym)
+ sym_validate_range(sym);
+
+ if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+- sym_set_changed(sym);
++ sym_set_changed(sym, false);
+ if (modules_sym == sym) {
+ sym_set_all_changed();
+ modules_val = modules_sym->curr.tri;
+@@ -367,7 +368,7 @@ void sym_calc_value(struct symbol *sym)
+ for (e = prop->expr; e; e = e->left.expr) {
+ e->right.sym->flags |= flags;
+ if (flags & SYMBOL_CHANGED)
+- sym_set_changed(e->right.sym);
++ sym_set_changed(e->right.sym, false);
+ }
+ }
+ }
+@@ -384,11 +385,13 @@ void sym_clear_all_valid(void)
+ sym_calc_value(modules_sym);
+ }
+
+-void sym_set_changed(struct symbol *sym)
++void sym_set_changed(struct symbol *sym, bool real)
+ {
+ struct property *prop;
+
+ sym->flags |= SYMBOL_CHANGED;
++ if (real)
++ sym->flags |= SYMBOL_CHANGED_REAL;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu)
+ prop->menu->flags |= MENU_CHANGED;
+@@ -401,7 +404,7 @@ void sym_set_all_changed(void)
+ int i;
+
+ for_all_symbols(i, sym)
+- sym_set_changed(sym);
++ sym_set_changed(sym, false);
+ }
+
+ bool sym_tristate_within_range(struct symbol *sym, tristate val)
+@@ -432,7 +435,7 @@ bool sym_set_tristate_value(struct symbo
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+- sym_set_changed(sym);
++ sym_set_changed(sym, true);
+ }
+ /*
+ * setting a choice value also resets the new flag of the choice
+@@ -594,7 +597,7 @@ bool sym_set_string_value(struct symbol
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+- sym_set_changed(sym);
++ sym_set_changed(sym, true);
+ }
+
+ oldval = sym->def[S_DEF_USER].val;
Added: people/maks-guest/linux-2.6/debian/patches/debian/version.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/version.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,68 @@
+diff --git a/init/version.c b/init/version.c
+index 3ddc3ce..c2111a7 100644
+--- a/init/version.c
++++ b/init/version.c
+@@ -29,5 +29,15 @@ struct new_utsname system_utsname = {
+ EXPORT_SYMBOL(system_utsname);
+
+ const char linux_banner[] =
+- "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
+- LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
++ "Linux version " UTS_RELEASE " "
++#ifdef LINUX_COMPILE_SYSTEM_OFFICIAL
++ "(" LINUX_COMPILE_SYSTEM_DISTRIBUTION " "
++ LINUX_COMPILE_SYSTEM_VERSION ") "
++ "(" LINUX_COMPILE_SYSTEM_MAINTAINER ") "
++#else
++# ifdef LINUX_COMPILE_SYSTEM_VERSION
++ "(" LINUX_COMPILE_SYSTEM_VERSION ") "
++# endif
++ "(" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
++#endif
++ "(" LINUX_COMPILER ") " UTS_VERSION "\n";
+diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
+index d7b8a38..87035a0 100755
+--- a/scripts/mkcompile_h
++++ b/scripts/mkcompile_h
+@@ -46,16 +46,34 @@ ( echo /\* This file is auto generated,
+
+ echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
+
++ if [ -e debian/changelog ]; then
++ DISTRIBUTION=$(lsb_release -is 2>/dev/null)
++ DISTRIBUTION=${DISTRIBUTION:-Debian}
++ MAINTAINER=$(dpkg-parsechangelog | sed -ne 's,^Maintainer: .[^<]*<\([^>]*\)>,\1,p')
++ VERSION=$(dpkg-parsechangelog | awk '/^Version:/ {print $$2}')
++ echo \#define LINUX_COMPILE_SYSTEM_DISTRIBUTION \"$DISTRIBUTION\"
++ echo \#define LINUX_COMPILE_SYSTEM_MAINTAINER \"$MAINTAINER\"
++ echo \#define LINUX_COMPILE_SYSTEM_VERSION \"$VERSION\"
++ fi
++
+ echo \#define LINUX_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\"
+- echo \#define LINUX_COMPILE_BY \"`whoami`\"
+- echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
+
+- if [ -x /bin/dnsdomainname ]; then
+- echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
+- elif [ -x /bin/domainname ]; then
+- echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
+- else
++ if [ -e debian/official ]; then
++ echo \#define LINUX_COMPILE_SYSTEM_OFFICIAL
++ echo \#define LINUX_COMPILE_BY \"unknown\"
++ echo \#define LINUX_COMPILE_HOST \"$DISTRIBUTION\"
+ echo \#define LINUX_COMPILE_DOMAIN
++ else
++ echo \#define LINUX_COMPILE_BY \"`whoami`\"
++ echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
++
++ if [ -x /bin/dnsdomainname ]; then
++ echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
++ elif [ -x /bin/domainname ]; then
++ echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
++ else
++ echo \#define LINUX_COMPILE_DOMAIN
++ fi
+ fi
+
+ echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
Added: people/maks-guest/linux-2.6/debian/patches/debian/vserver-version.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/debian/vserver-version.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,21 @@
+--- linux-2.6.15/init/version.c 2005-03-02 12:39:08 +0100
++++ linux-2.6.15/init/version.c 2006-01-04 19:50:18 +0100
+@@ -31,3 +31,18 @@
+ "(" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
+ #endif
+ "(" LINUX_COMPILER ") " UTS_VERSION "\n";
++
++const char vx_linux_banner[] =
++ "Linux version %s "
++#ifdef LINUX_COMPILE_SYSTEM_OFFICIAL
++ "(" LINUX_COMPILE_SYSTEM_DISTRIBUTION " "
++ LINUX_COMPILE_SYSTEM_VERSION ") "
++ "(" LINUX_COMPILE_SYSTEM_MAINTAINER ") "
++#else
++# ifdef LINUX_COMPILE_SYSTEM_VERSION
++ "(" LINUX_COMPILE_SYSTEM_VERSION ") "
++# endif
++ "(" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
++#endif
++ "(" LINUX_COMPILER ") %s\n";
++
Added: people/maks-guest/linux-2.6/debian/patches/fbdev-radeon-noaccel.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/fbdev-radeon-noaccel.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,23 @@
+ Patch to enhance the FBIOGET_FSCREENINFO ioctl,
+ used by lcd_hack tool by BenH. (Sven Luther)
+ added for kernel-source-2.6.10 (2.6.10-5)
+
+ Status: Not submitted
+
+diff -aurN a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
+--- a/drivers/video/aty/radeon_base.c 2005-06-06 11:22:29.000000000 -0400
++++ b/drivers/video/aty/radeon_base.c 2005-06-15 21:55:56.000000000 -0400
+@@ -1907,8 +1907,12 @@
+
+ fb_alloc_cmap(&info->cmap, 256, 0);
+
+- if (noaccel)
++ if (noaccel) {
+ info->flags |= FBINFO_HWACCEL_DISABLED;
++ info->fix.accel = FB_ACCEL_NONE;
++ } else {
++ info->fix.accel = FB_ACCEL_ATI_RADEON;
++ }
+
+ return 0;
+ }
Added: people/maks-guest/linux-2.6/debian/patches/features/all/fs-asfs.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/fs-asfs.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,5276 @@
+## fs-asfs.dpatch by Sven Luther <luther at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: add support for the Amiga SmartFilesystem (asfs), 1.0beta11
+## DP: Patch author: Marek Szyprowski <marek at amiga.pl>
+## DP: Upstream status: submitted but no reply. Submitted again on 2005.03.22.
+## DP: Reference: http://home.elka.pw.edu.pl/~mszyprow/programy/asfs/
+
+diff -urN linux-2.6.18/Documentation/filesystems/00-INDEX linux-2.6.18-asfs-1.0b11/Documentation/filesystems/00-INDEX
+--- linux-2.6.18/Documentation/filesystems/00-INDEX 2006-09-22 22:47:41.000000000 +0200
++++ linux-2.6.18-asfs-1.0b11/Documentation/filesystems/00-INDEX 2006-09-22 22:53:21.000000000 +0200
+@@ -10,6 +10,8 @@
+ - info and examples for the distributed AFS (Andrew File System) fs.
+ affs.txt
+ - info and mount options for the Amiga Fast File System.
++asfs.txt
++ - info and mount options for the Amiga Smart File System.
+ automount-support.txt
+ - information about filesystem automount support.
+ befs.txt
+diff -urN linux-2.6.18/Documentation/filesystems/asfs.txt linux-2.6.18-asfs-1.0b11/Documentation/filesystems/asfs.txt
+--- linux-2.6.18/Documentation/filesystems/asfs.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/Documentation/filesystems/asfs.txt 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,161 @@
++
++Amiga SmartFileSystem, Linux implementation
++===========================================
++
++ASFS is a Amiga Smart FileSystem driver for Linux. It supports reading
++files and directories. From version 1.0 there is also an experimental
++(almost full) write support. Experimental means that it hasn't been
++tested enough yet, so use it with care. Symbolic links (in AmigaOS
++called soft links) are also supported read/write. Read notes below
++about symlinks support.
++
++
++Unsupported features of Amiga SFS
++================================
++
++ASFS currently does not support safe-delete feature of Amiga SFS
++filesystem. It simply deletes files instead of moving them to
++".recycled" directory. It also doesn't remove files from ".recycled"
++directory, when there is no space left on drive.
++
++If there is no space left, you need to manually remove files from
++".recycled" directory. Also if you want to delete a file in a safe
++way, you need to move it to ".recycled" directory by hand.
++
++Because of all of above, the amount of free space on disk does not
++include space used by all files from ".recycled" directory.
++
++
++Limitations
++===========
++
++There is no Amiga protection bits into Linux permission bits tranlation
++and vice versa. If you need this feature, mail me.
++
++ASFS will always keep some amount of blocks free. This means that you
++cannot fill the drive completely. It is because Amiga SFS uses some
++special methods of writing data (called safe write), which needs some
++additional free space.
++
++File systems with unfinished transactions (this happens when system crashed
++during writing data to disk on AmigaOS/MorphOS) will be mounted read-only
++to protect data. The only way to fix such filesystem is to mount it under
++AmigaOS or MorphOS.
++
++Do not try to mount and write to filesystem with errors. Bad things will
++happen.
++
++
++Mount options for the ASFS
++==========================
++
++setuid=uid
++ This sets the owner of all files and directories in the file
++ system to uid.
++
++setgid=gid
++ Same as above, but for gid.
++
++mode=mode
++ Sets the mode flags to the given (octal) value. Directories
++ will get an x permission if the corresponding r bit is set.
++ The default mode is 0644, which means that everybody are allowed
++ to read files, but only root can write to them.
++ (for directories this means also that search bits are set).
++
++prefix=path
++ Path will be prefixed to every absolute path name of symbolic
++ links on an ASFS/AFFS partition. Default = "/". (See below.)
++
++volume=name
++ When symbolic links with an absolute path are created
++ on an ASFS/AFFS partition, name will be prepended as the
++ volume name. Default = "" (empty string). (See below.)
++
++lowercasevol
++ Translate all volume names in symlinks to lower case.
++ Disabled by default. (See below.)
++
++iocharset=name
++ Character set to use for converting file names. Specifies
++ character set used by your Linux system.
++codepage=name
++ Set the codepage number for converting file names. Specifies
++ character set used by your Amiga. Use full name (for example
++ 'cp1251' instead of '1251') here, this allows to specify any
++ character set, not only numbered one (like 'iso8859-2').
++ Use special name 'none' to disable the NLS file name
++ translation.
++
++Symbolic links
++==============
++
++Although the Amiga and Linux file systems resemble each other, there
++are some, not always subtle, differences. One of them becomes apparent
++with symbolic links. While Linux has a file system with exactly one
++root directory, the Amiga has a separate root directory for each
++file system (for example, partition, floppy disk, ...). With the Amiga,
++these entities are called "volumes". They have symbolic names which
++can be used to access them. Thus, symbolic links can point to a
++different volume. ASFS turns the volume name into a directory name
++and prepends the prefix path (see prefix option) to it. When option
++"lowercasevol" is set, it also translates volume names to lower case.
++If the volume name is the same as a name given in "volume" option,
++it will be ignored and an absolute path will be created.
++
++Example:
++You mount all your Amiga partitions under /amiga/<volume> (where
++<volume> is the name of the volume), and you give options
++`prefix="/amiga/",volume="Linux",lowercasevol' when mounting all your
++ASFS partitions. (They might be "User", "WB" and "Graphics", the mount
++points /amiga/user, /amiga/wb and /amiga/graphics).
++
++A symbolic link referring to "USER:sc/include/dos/dos.h" will be
++translated to "/amiga/user/sc/include/dos/dos.h".
++A symbolic link referring to "Linux:etc/fstab" will be translated to
++"/etc/fstab".
++If you create a symlink referring to "/amiga/graphics/data/pict.jpg",
++it will be saved as "graphics:data/pict.jpg".
++If you create a symlink referring to "/boot/System.map", it will be
++saved as "Linux:boot/System.map".
++
++
++Other information
++=================
++
++Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
++speed up almost everything at the expense of wasted disk space. The speed
++gain above 4K seems not really worth the price, so you don't lose too
++much here, either.
++
++This file system has been tested on Motorola PPC and 68k, as well as
++Intel x86 systems. I don't know, if it works on other Linux systems.
++
++This filesystem is in BETA STAGE. This means that driver MIGHT corrupt
++or damage data on your disk. Remember! YOU USE IT ON YOUR OWN RISK!
++
++I made almost all I could to minimalize this risk. On my systems several
++gigabytes has been succesfully copied from and to SFS disks. I would also
++appreciate any infomation if this filesystem works on your system or not.
++See next paragraph for my email.
++
++Some parts of this documentation has been adapted from AFFS driver docs.
++
++
++Author, contact and copyright infos
++===================================
++
++ASFS has been written by Marek 'March' Szyprowski <marek at amiga.pl>.
++Mail me if you have any suggestions or found a bug.
++
++Copyright (C) 2003,2004,2005 Marek 'March' Szyprowski <marek at amiga.pl>
++
++Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts
++of original amiga version of SmartFilesystem source code.
++
++SmartFilesystem is copyrighted (C) 2003,2004 by: John Hendrikx,
++Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
++
++The ASFS driver is realased under the terms of of the GNU General
++Public License. See source code for more details.
++
+diff -urN linux-2.6.18/fs/asfs/adminspace.c linux-2.6.18-asfs-1.0b11/fs/asfs/adminspace.c
+--- linux-2.6.18/fs/asfs/adminspace.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/adminspace.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,446 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta7
++ *
++ * This file contains some parts of the original amiga version of
++ * SmartFilesystem source code.
++ *
++ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
++ * Ralph Schmidt, Emmanuel Lesueur, David Gerber, and Marcin Kurek
++ *
++ * Adapted and modified by Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include "asfs_fs.h"
++#include "bitfuncs.h"
++
++#include <asm/byteorder.h>
++
++#ifdef CONFIG_ASFS_RW
++
++static int setfreeblocks(struct super_block *sb, u32 freeblocks)
++{
++ struct buffer_head *bh;
++ if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
++ struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
++ ASFS_SB(sb)->freeblocks = freeblocks;
++ ri->freeblocks = cpu_to_be32(freeblocks);
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ return 0;
++ }
++ return -EIO;
++}
++
++static inline int enoughspace(struct super_block *sb, u32 blocks)
++{
++ if (ASFS_SB(sb)->freeblocks - ASFS_ALWAYSFREE < blocks)
++ return FALSE;
++
++ return TRUE;
++}
++
++ /* Determines the amount of free blocks starting from block /block/.
++ If there are no blocks found or if there was an error -1 is returned,
++ otherwise this function will count the number of free blocks until
++ an allocated block is encountered or until maxneeded has been
++ exceeded. */
++
++static int availablespace(struct super_block *sb, u32 block, u32 maxneeded)
++{
++ struct buffer_head *bh = NULL;
++ struct fsBitmap *b;
++ u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5;
++ u32 maxbitmapblock = ASFS_SB(sb)->bitmapbase + ASFS_SB(sb)->blocks_bitmap;
++ int blocksfound = 0;
++ u32 bitstart;
++ int bitend;
++ u32 nextblock = ASFS_SB(sb)->bitmapbase + block / ASFS_SB(sb)->blocks_inbitmap;
++
++ bitstart = block % ASFS_SB(sb)->blocks_inbitmap;
++
++ while (nextblock < maxbitmapblock && (bh = asfs_breadcheck(sb, nextblock++, ASFS_BITMAP_ID))) {
++ b = (void *) bh->b_data;
++
++ if ((bitend = bmffz(b->bitmap, longs, bitstart)) >= 0) {
++ blocksfound += bitend - bitstart;
++ asfs_brelse(bh);
++ return blocksfound;
++ }
++ blocksfound += ASFS_SB(sb)->blocks_inbitmap - bitstart;
++ if (blocksfound >= maxneeded) {
++ asfs_brelse(bh);
++ return blocksfound;
++ }
++ bitstart = 0;
++ asfs_brelse(bh);
++ }
++
++ if (bh == NULL)
++ return (-1);
++
++ return (blocksfound);
++}
++
++int asfs_findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end, u32 * returned_block, u32 * returned_blocks)
++{
++ struct buffer_head *bh;
++ u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5;
++ u32 space = 0;
++ u32 block;
++ u32 bitmapblock = ASFS_SB(sb)->bitmapbase + start / ASFS_SB(sb)->blocks_inbitmap;
++ u32 breakpoint;
++ int bitstart, bitend;
++ int reads;
++
++ if (enoughspace(sb, maxneeded) == FALSE) {
++ *returned_block = 0;
++ *returned_blocks = 0;
++ return -ENOSPC;
++ }
++
++ if (start >= ASFS_SB(sb)->totalblocks)
++ start -= ASFS_SB(sb)->totalblocks;
++
++ if (end == 0)
++ end = ASFS_SB(sb)->totalblocks;
++
++ reads = ((end - 1) / ASFS_SB(sb)->blocks_inbitmap) + 1 - start / ASFS_SB(sb)->blocks_inbitmap;
++
++ if (start >= end)
++ reads += (ASFS_SB(sb)->totalblocks - 1) / ASFS_SB(sb)->blocks_inbitmap + 1;
++
++ breakpoint = (start < end ? end : ASFS_SB(sb)->totalblocks);
++
++ *returned_block = 0;
++ *returned_blocks = 0;
++
++ bitend = start % ASFS_SB(sb)->blocks_inbitmap;
++ block = start - bitend;
++
++ while ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
++ struct fsBitmap *b = (void *) bh->b_data;
++ u32 localbreakpoint = breakpoint - block;
++
++ if (localbreakpoint > ASFS_SB(sb)->blocks_inbitmap)
++ localbreakpoint = ASFS_SB(sb)->blocks_inbitmap;
++
++ /* At this point space contains the amount of free blocks at
++ the end of the previous bitmap block. If there are no
++ free blocks at the start of this bitmap block, space will
++ be set to zero, since in that case the space isn't adjacent. */
++
++ while ((bitstart = bmffo(b->bitmap, longs, bitend)) < ASFS_SB(sb)->blocks_inbitmap) {
++ /* found the start of an empty space, now find out how large it is */
++
++ if (bitstart >= localbreakpoint)
++ break;
++
++ if (bitstart != 0)
++ space = 0;
++
++ bitend = bmffz(b->bitmap, longs, bitstart);
++
++ if (bitend > localbreakpoint)
++ bitend = localbreakpoint;
++
++ space += bitend - bitstart;
++
++ if (*returned_blocks < space) {
++ *returned_block = block + bitend - space;
++ if (space >= maxneeded) {
++ *returned_blocks = maxneeded;
++ asfs_brelse(bh);
++ return 0;
++ }
++ *returned_blocks = space;
++ }
++
++ if (bitend >= localbreakpoint)
++ break;
++ }
++
++ if (--reads == 0)
++ break;
++
++ /* no (more) empty spaces found in this block */
++
++ if (bitend != ASFS_SB(sb)->blocks_inbitmap)
++ space = 0;
++
++ bitend = 0;
++ block += ASFS_SB(sb)->blocks_inbitmap;
++
++ if (block >= ASFS_SB(sb)->totalblocks) {
++ block = 0;
++ space = 0;
++ breakpoint = end;
++ bitmapblock = ASFS_SB(sb)->bitmapbase;
++ }
++ asfs_brelse(bh);
++ }
++
++ if (bh == NULL)
++ return -EIO;
++
++ asfs_brelse(bh);
++
++ if (*returned_blocks == 0)
++ return -ENOSPC;
++ else
++ return 0;
++}
++
++int asfs_markspace(struct super_block *sb, u32 block, u32 blocks)
++{
++ int errorcode;
++
++ asfs_debug("markspace: Marking %d blocks from block %d\n", blocks, block);
++
++ if ((availablespace(sb, block, blocks)) < blocks) {
++ printk("ASFS: Attempted to mark %d blocks from block %d, but some of them were already full!\n", blocks, block);
++ return -EIO;
++ }
++
++ if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks - blocks)) == 0) {
++ struct buffer_head *bh;
++ u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap;
++ u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2;
++ u32 bitmapblock;
++
++ block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap;
++ bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks;
++
++ while (blocks > 0) {
++ if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
++ struct fsBitmap *b = (void *) bh->b_data;
++
++ blocks -= bmclr(b->bitmap, longs, block, blocks);
++ block = 0;
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ } else
++ return -EIO;
++ }
++ }
++
++ return (errorcode);
++}
++
++ /* This function checks the bitmap and tries to locate at least /blocksneeded/
++ adjacent unused blocks. If found it sets returned_block to the start block
++ and returns no error. If not found, ERROR_DISK_IS_FULL is returned and
++ returned_block is set to zero. Any other errors are returned as well. */
++
++static inline int internalfindspace(struct super_block *sb, u32 blocksneeded, u32 startblock, u32 endblock, u32 * returned_block)
++{
++ u32 blocks;
++ int errorcode;
++
++ if ((errorcode = asfs_findspace(sb, blocksneeded, startblock, endblock, returned_block, &blocks)) == 0)
++ if (blocks != blocksneeded)
++ return -ENOSPC;
++
++ return errorcode;
++}
++
++static int findandmarkspace(struct super_block *sb, u32 blocksneeded, u32 * returned_block)
++{
++ int errorcode;
++
++ if (enoughspace(sb, blocksneeded) != FALSE) {
++ if ((errorcode = internalfindspace(sb, blocksneeded, 0, ASFS_SB(sb)->totalblocks, returned_block)) == 0)
++ errorcode = asfs_markspace(sb, *returned_block, blocksneeded);
++ } else
++ errorcode = -ENOSPC;
++
++ return (errorcode);
++}
++
++/* ************************** */
++
++int asfs_freespace(struct super_block *sb, u32 block, u32 blocks)
++{
++ int errorcode;
++
++ asfs_debug("freespace: Freeing %d blocks from block %d\n", blocks, block);
++
++ if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks + blocks)) == 0) {
++ struct buffer_head *bh;
++ u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap;
++ u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2;
++ u32 bitmapblock;
++
++ block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap;
++ bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks;
++
++ while (blocks > 0) {
++ if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
++ struct fsBitmap *b = (void *) bh->b_data;
++
++ blocks -= bmset(b->bitmap, longs, block, blocks);
++ block = 0;
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ } else
++ return -EIO;
++ }
++ }
++
++ return (errorcode);
++}
++
++/*************** admin space containers ****************/
++
++int asfs_allocadminspace(struct super_block *sb, u32 *returned_block)
++{
++ struct buffer_head *bh;
++ u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
++ int errorcode = -EIO;
++
++ asfs_debug("allocadminspace: allocating new block\n");
++
++ while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
++ struct fsAdminSpaceContainer *asc1 = (void *) bh->b_data;
++ struct fsAdminSpace *as1 = asc1->adminspace;
++ int adminspaces1 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
++
++ while (adminspaces1-- > 0) {
++ s16 bitoffset;
++
++ if (as1->space != 0 && (bitoffset = bfffz(be32_to_cpu(as1->bits), 0)) >= 0) {
++ u32 emptyadminblock = be32_to_cpu(as1->space) + bitoffset;
++ as1->bits |= cpu_to_be32(1 << (31 - bitoffset));
++ asfs_bstore(sb, bh);
++ *returned_block = emptyadminblock;
++ asfs_brelse(bh);
++ asfs_debug("allocadminspace: found block %d\n", *returned_block);
++ return 0;
++ }
++ as1++;
++ }
++
++ adminspaceblock = be32_to_cpu(asc1->next);
++ asfs_brelse(bh);
++
++ if (adminspaceblock == 0) {
++ u32 startblock;
++
++ asfs_debug("allocadminspace: allocating new adminspace area\n");
++
++ /* If we get here it means current adminspace areas are all filled.
++ We would now need to find a new area and create a fsAdminSpace
++ structure in one of the AdminSpaceContainer blocks. If these
++ don't have any room left for new adminspace areas a new
++ AdminSpaceContainer would have to be created first which is
++ placed as the first block in the newly found admin area. */
++
++ adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
++
++ if ((errorcode = findandmarkspace(sb, 32, &startblock)))
++ return errorcode;
++
++ while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
++ struct fsAdminSpaceContainer *asc2 = (void *) bh->b_data;
++ struct fsAdminSpace *as2 = asc2->adminspace;
++ int adminspaces2 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
++
++ while (adminspaces2-- > 0 && as2->space != 0)
++ as2++;
++
++ if (adminspaces2 >= 0) { /* Found a unused AdminSpace in this AdminSpaceContainer! */
++ as2->space = cpu_to_be32(startblock);
++ as2->bits = 0;
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ break;
++ }
++
++ if (asc2->next == 0) {
++ /* Oh-oh... we marked our new adminspace area in use, but we couldn't
++ find space to store a fsAdminSpace structure in the existing
++ fsAdminSpaceContainer blocks. This means we need to create and
++ link a new fsAdminSpaceContainer as the first block in our newly
++ marked adminspace. */
++
++ asc2->next = cpu_to_be32(startblock);
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ /* Now preparing new AdminSpaceContainer */
++
++ if ((bh = asfs_getzeroblk(sb, startblock)) == NULL)
++ return -EIO;
++
++ asc2 = (void *) bh->b_data;
++ asc2->bheader.id = cpu_to_be32(ASFS_ADMINSPACECONTAINER_ID);
++ asc2->bheader.ownblock = cpu_to_be32(startblock);
++ asc2->previous = cpu_to_be32(adminspaceblock);
++ asc2->adminspace[0].space = cpu_to_be32(startblock);
++ asc2->adminspace[0].bits = cpu_to_be32(0x80000000);
++ asc2->bits = 32;
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ adminspaceblock = startblock;
++ break; /* Breaks through to outer loop! */
++ }
++ adminspaceblock = be32_to_cpu(asc2->next);
++ asfs_brelse(bh);
++ }
++ }
++ }
++ return errorcode;
++}
++
++int asfs_freeadminspace(struct super_block *sb, u32 block)
++{
++ struct buffer_head *bh;
++ u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
++
++ asfs_debug("freeadminspace: Entry -- freeing block %d\n", block);
++
++ while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
++ struct fsAdminSpaceContainer *asc = (void *) bh->b_data;
++ struct fsAdminSpace *as = asc->adminspace;
++ int adminspaces = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
++
++ while (adminspaces-- > 0) {
++ if (block >= be32_to_cpu(as->space) && block < be32_to_cpu(as->space) + 32) {
++ s16 bitoffset = block - be32_to_cpu(as->space);
++ asfs_debug("freeadminspace: Block to be freed is located in AdminSpaceContainer block at %d\n", adminspaceblock);
++ as->bits &= cpu_to_be32(~(1 << (31 - bitoffset)));
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ return 0;
++ }
++ as++;
++ }
++
++ if ((adminspaceblock = be32_to_cpu(asc->next)) == 0)
++ break;
++
++ asfs_brelse(bh);
++ }
++
++ if (bh != NULL) {
++ asfs_brelse(bh);
++ printk("ASFS: Unable to free an administration block. The block cannot be found.");
++ return -ENOENT;
++ }
++
++ return -EIO;
++}
++
++#endif
+diff -urN linux-2.6.18/fs/asfs/asfs_fs.h linux-2.6.18-asfs-1.0b11/fs/asfs/asfs_fs.h
+--- linux-2.6.18/fs/asfs/asfs_fs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/asfs_fs.h 2006-09-22 23:18:03.000000000 +0200
+@@ -0,0 +1,217 @@
++#ifndef __LINUX_ASFS_FS_H
++#define __LINUX_ASFS_FS_H
++
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <asm/byteorder.h>
++#include <linux/amigasfs.h>
++
++#define asfs_debug(fmt,arg...) /* no debug at all */
++//#define asfs_debug(fmt,arg...) printk(fmt,##arg) /* general debug infos */
++
++#if !defined (__BIG_ENDIAN) && !defined (__LITTLE_ENDIAN)
++#error Endianes must be known for ASFS to work. Sorry.
++#endif
++
++#define ASFS_MAXFN_BUF (ASFS_MAXFN + 4)
++#define ASFS_DEFAULT_UID 0
++#define ASFS_DEFAULT_GID 0
++#define ASFS_DEFAULT_MODE 0644 /* default permission bits for files, dirs have same permission, but with "x" set */
++
++/* Extent structure located in RAM (e.g. inside inode structure),
++ currently used to store last used extent */
++
++struct inramExtent {
++ u32 startblock; /* Block from begginig of the file */
++ u32 key;
++ u32 next;
++ u16 blocks;
++};
++
++/* inode in-kernel data */
++
++struct asfs_inode_info {
++ u32 firstblock;
++ u32 hashtable;
++ int modified;
++ loff_t mmu_private;
++ struct inramExtent ext_cache;
++ struct inode vfs_inode;
++};
++
++/* short cut to get to the asfs specific inode data */
++static inline struct asfs_inode_info *ASFS_I(struct inode *inode)
++{
++ return list_entry(inode, struct asfs_inode_info, vfs_inode);
++}
++
++/* Amiga SFS superblock in-core data */
++
++struct asfs_sb_info {
++ u32 totalblocks;
++ u32 rootobjectcontainer;
++ u32 extentbnoderoot;
++ u32 objectnoderoot;
++
++ u32 adminspacecontainer;
++ u32 bitmapbase;
++ u32 freeblocks;
++ u32 blocks_inbitmap;
++ u32 blocks_bitmap;
++ u32 block_rovingblockptr;
++
++ uid_t uid;
++ gid_t gid;
++ umode_t mode;
++ u16 flags;
++ char *prefix;
++ char *root_volume; /* Volume prefix for absolute symlinks. */
++ char *iocharset;
++ char *codepage;
++ struct nls_table *nls_io;
++ struct nls_table *nls_disk;
++};
++
++/* short cut to get to the asfs specific sb data */
++static inline struct asfs_sb_info *ASFS_SB(struct super_block *sb)
++{
++ return sb->s_fs_info;
++}
++
++/* io inline code */
++
++u32 asfs_calcchecksum(void *block, u32 blocksize);
++
++static inline int
++asfs_check_block(struct fsBlockHeader *block, u32 blocksize, u32 n, u32 id)
++{
++ if (asfs_calcchecksum(block, blocksize) ==
++ be32_to_cpu(((struct fsBlockHeader *) block)->checksum) &&
++ n == be32_to_cpu(((struct fsBlockHeader *) block)->ownblock) &&
++ id == be32_to_cpu(((struct fsBlockHeader *) block)->id))
++ return TRUE;
++ return FALSE;
++}
++
++/* get fs structure from block and do some checks... */
++static inline struct buffer_head *
++asfs_breadcheck(struct super_block *sb, u32 n, u32 type)
++{
++ struct buffer_head *bh;
++ if ((bh = sb_bread(sb, n))) {
++ if (asfs_check_block ((void *)bh->b_data, sb->s_blocksize, n, type)) {
++ return bh; /* all okay */
++ }
++ brelse(bh);
++ }
++ return NULL; /* error */
++}
++
++static inline struct buffer_head *
++asfs_getzeroblk(struct super_block *sb, int block)
++{
++ struct buffer_head *bh;
++ bh = sb_getblk(sb, block);
++ lock_buffer(bh);
++ memset(bh->b_data, 0, sb->s_blocksize);
++ set_buffer_uptodate(bh);
++ unlock_buffer(bh);
++ return bh;
++}
++
++static inline void
++asfs_bstore(struct super_block *sb, struct buffer_head *bh)
++{
++ ((struct fsBlockHeader *) (bh->b_data))->checksum =
++ cpu_to_be32(asfs_calcchecksum(bh->b_data, sb->s_blocksize));
++ mark_buffer_dirty(bh);
++}
++
++static inline void asfs_brelse(struct buffer_head *bh)
++{
++ brelse(bh);
++}
++
++static inline void dec_count(struct inode *inode)
++{
++ inode->i_nlink--;
++ mark_inode_dirty(inode);
++}
++
++/* all prototypes */
++
++/* adminspace.c */
++int asfs_allocadminspace(struct super_block *sb, u32 * block);
++int asfs_freeadminspace(struct super_block *sb, u32 block);
++int asfs_markspace(struct super_block *sb, u32 block, u32 blocks);
++int asfs_freespace(struct super_block *sb, u32 block, u32 blocks);
++int asfs_findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end,
++ u32 * returned_block, u32 * returned_blocks);
++
++/* dir.c */
++int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
++struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
++
++/* extents.c */
++int asfs_getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh,
++ struct fsExtentBNode **ret_ebn);
++int asfs_deletebnode(struct super_block *sb, struct buffer_head *cb, u32 key);
++int asfs_deleteextents(struct super_block *sb, u32 key);
++int asfs_addblocks(struct super_block *sb, u16 blocks, u32 newspace,
++ u32 objectnode, u32 * io_lastextentbnode);
++
++/* file.c */
++int asfs_readpage(struct file *file, struct page *page);
++sector_t asfs_bmap(struct address_space *mapping, sector_t block);
++int asfs_writepage(struct page *page, struct writeback_control *wbc);
++int asfs_prepare_write(struct file *file, struct page *page, unsigned from,
++ unsigned to);
++void asfs_truncate(struct inode *inode);
++int asfs_file_open(struct inode *inode, struct file *filp);
++int asfs_file_release(struct inode *inode, struct file *filp);
++
++/* inode.c */
++struct inode *asfs_get_root_inode(struct super_block *sb);
++void asfs_read_locked_inode(struct inode *inode, void *arg);
++
++/* namei */
++u8 asfs_lowerchar(u8 c);
++int asfs_check_name(const u8 *name, int len);
++int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t);
++u16 asfs_hash(u8 *name, int casesensitive);
++void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit);
++
++/* nodes */
++int asfs_getnode(struct super_block *sb, u32 nodeno,
++ struct buffer_head **ret_bh, struct fsObjectNode **ret_node);
++int asfs_createnode(struct super_block *sb, struct buffer_head **returned_cb,
++ struct fsNode **returned_node, u32 * returned_nodeno);
++int asfs_deletenode(struct super_block *sb, u32 objectnode);
++
++/* objects */
++struct fsObject *asfs_nextobject(struct fsObject *obj);
++struct fsObject *asfs_find_obj_by_name(struct super_block *sb,
++ struct fsObjectContainer *objcont, u8 * name);
++int asfs_readobject(struct super_block *sb, u32 objectnode,
++ struct buffer_head **cb, struct fsObject **returned_object);
++int asfs_createobject(struct super_block *sb, struct buffer_head **io_cb,
++ struct fsObject **io_o, struct fsObject *src_o,
++ u8 * objname, int force);
++int asfs_deleteobject(struct super_block *sb, struct buffer_head *cb,
++ struct fsObject *o);
++int asfs_renameobject(struct super_block *sb, struct buffer_head *cb1,
++ struct fsObject *o1, struct buffer_head *cbparent,
++ struct fsObject *oparent, u8 * newname);
++
++int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objcb,
++ struct fsObject *o, u32 blocks, u32 * newspace,
++ u32 * addedblocks);
++int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh,
++ struct fsObject *o, u32 newsize);
++
++/* symlink.c */
++int asfs_symlink_readpage(struct file *file, struct page *page);
++int asfs_write_symlink(struct inode *symfile, const char *symname);
++
++#endif
+Pliki binarne linux-2.6.18/fs/asfs/asfs.ko i linux-2.6.18-asfs-1.0b11/fs/asfs/asfs.ko siê ró¿ni±
+diff -urN linux-2.6.18/fs/asfs/bitfuncs.c linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.c
+--- linux-2.6.18/fs/asfs/bitfuncs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,171 @@
++/*
++ *
++ * 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/types.h>
++#include <asm/byteorder.h>
++#include "bitfuncs.h"
++
++/* Bitmap (bm) functions:
++ These functions perform bit-operations on regions of memory which
++ are a multiple of 4 bytes in length. Bitmap is in bigendian byte order.
++*/
++
++/* This function finds the first set bit in a region of memory starting
++ with /bitoffset/. The region of memory is /longs/ longs long. It
++ returns the bitoffset of the first set bit it finds. */
++
++int bmffo(u32 *bitmap, int longs, int bitoffset)
++{
++ u32 *scan = bitmap;
++ int longoffset, bit;
++
++ longoffset = bitoffset >> 5;
++ longs -= longoffset;
++ scan += longoffset;
++
++ bitoffset = bitoffset & 0x1F;
++
++ if (bitoffset != 0) {
++ if ((bit = bfffo(be32_to_cpu(*scan), bitoffset)) >= 0) {
++ return (bit + ((scan - bitmap) << 5));
++ }
++ scan++;
++ longs--;
++ }
++
++ while (longs-- > 0) {
++ if (*scan++ != 0) {
++ return (bfffo(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5));
++ }
++ }
++
++ return (-1);
++}
++
++/* This function finds the first unset bit in a region of memory starting
++ with /bitoffset/. The region of memory is /longs/ longs long. It
++ returns the bitoffset of the first unset bit it finds. */
++
++int bmffz(u32 *bitmap, int longs, int bitoffset)
++{
++ u32 *scan = bitmap;
++ int longoffset, bit;
++
++ longoffset = bitoffset >> 5;
++ longs -= longoffset;
++ scan += longoffset;
++
++ bitoffset = bitoffset & 0x1F;
++
++ if (bitoffset != 0) {
++ if ((bit = bfffz(be32_to_cpu(*scan), bitoffset)) >= 0) {
++ return (bit + ((scan - bitmap) << 5));
++ }
++ scan++;
++ longs--;
++ }
++
++ while (longs-- > 0) {
++ if (*scan++ != 0xFFFFFFFF) {
++ return (bfffz(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5));
++ }
++ }
++
++ return (-1);
++}
++
++/* This function clears /bits/ bits in a region of memory starting
++ with /bitoffset/. The region of memory is /longs/ longs long. If
++ the region of memory is too small to clear /bits/ bits then this
++ function exits after having cleared all bits till the end of the
++ memory region. In any case it returns the number of bits which
++ were actually cleared. */
++
++int bmclr(u32 *bitmap, int longs, int bitoffset, int bits)
++{
++ u32 *scan = bitmap;
++ int longoffset;
++ int orgbits = bits;
++
++ longoffset = bitoffset >> 5;
++ longs -= longoffset;
++ scan += longoffset;
++
++ bitoffset = bitoffset & 0x1F;
++
++ if (bitoffset != 0) {
++ if (bits < 32) {
++ *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, bits));
++ } else {
++ *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, 32));
++ }
++ scan++;
++ longs--;
++ bits -= 32 - bitoffset;
++ }
++
++ while (bits > 0 && longs-- > 0) {
++ if (bits > 31) {
++ *scan++ = 0;
++ } else {
++ *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), 0, bits));
++ }
++ bits -= 32;
++ }
++
++ if (bits <= 0) {
++ return (orgbits);
++ }
++ return (orgbits - bits);
++}
++
++/* This function sets /bits/ bits in a region of memory starting
++ with /bitoffset/. The region of memory is /longs/ longs long. If
++ the region of memory is too small to set /bits/ bits then this
++ function exits after having set all bits till the end of the
++ memory region. In any case it returns the number of bits which
++ were actually set. */
++
++int bmset(u32 *bitmap, int longs, int bitoffset, int bits)
++{
++ u32 *scan = bitmap;
++ int longoffset;
++ int orgbits = bits;
++
++ longoffset = bitoffset >> 5;
++ longs -= longoffset;
++ scan += longoffset;
++
++ bitoffset = bitoffset & 0x1F;
++
++ if (bitoffset != 0) {
++ if (bits < 32) {
++ *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, bits));
++ } else {
++ *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, 32));
++ }
++ scan++;
++ longs--;
++ bits -= 32 - bitoffset;
++ }
++
++ while (bits > 0 && longs-- > 0) {
++ if (bits > 31) {
++ *scan++ = 0xFFFFFFFF;
++ } else {
++ *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), 0, bits));
++ }
++ bits -= 32;
++ }
++
++ if (bits <= 0) {
++ return (orgbits);
++ }
++ return (orgbits - bits);
++}
+diff -urN linux-2.6.18/fs/asfs/bitfuncs.h linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.h
+--- linux-2.6.18/fs/asfs/bitfuncs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.h 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ *
++ * 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.
++ *
++ */
++
++#ifndef __BITFUNCS_H
++#define __BITFUNCS_H
++
++#include <linux/types.h>
++#include <asm/byteorder.h>
++
++#include <asm/bitops.h>
++#include <linux/bitops.h>
++
++/* Finds first set bit in /data/ starting at /bitoffset/. This function
++ considers the MSB to be the first bit. */
++static inline int bfffo(u32 data, int bitoffset)
++{
++ u32 mask = 0xffffffff >> bitoffset;
++ data &= mask;
++ return data == 0 ? -1 : 32-fls(data);
++}
++
++/* Finds first zero bit in /data/ starting at /bitoffset/. This function
++ considers the MSB to be the first bit. */
++static inline int bfffz(u32 data, int bitoffset)
++{
++ return bfffo(~data, bitoffset);
++}
++
++/* Sets /bits/ bits starting from /bitoffset/ in /data/.
++ /bits/ must be between 1 and 32. */
++static inline u32 bfset(u32 data, int bitoffset, int bits)
++{
++ u32 mask = ~((1 << (32 - bits)) - 1);
++ mask >>= bitoffset;
++ return data | mask;
++}
++
++/* Clears /bits/ bits starting from /bitoffset/ in /data/.
++ /bits/ must be between 1 and 32. */
++static inline u32 bfclr(u32 data, int bitoffset, int bits)
++{
++ u32 mask = ~((1 << (32 - bits)) - 1);
++ mask >>= bitoffset;
++ return data & ~mask;
++}
++
++/* bm??? functions assumes that in-memory bitmap is in bigendian byte order */
++int bmffo(u32 *, int, int);
++int bmffz(u32 *, int, int);
++int bmclr(u32 *, int, int, int);
++int bmset(u32 *, int, int, int);
++
++#endif
+diff -urN linux-2.6.18/fs/asfs/Changes linux-2.6.18-asfs-1.0b11/fs/asfs/Changes
+--- linux-2.6.18/fs/asfs/Changes 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/Changes 2006-09-22 23:24:31.000000000 +0200
+@@ -0,0 +1,116 @@
++
++Amiga Smart File System, Linux implementation
++
++Please direct bug reports to: marek at amiga.pl
++
++History:
++
++v1.0beta11 (22.09.2006)
++- adapted to 2.6.18 kernel VFS changes
++- made some functions static to reduce overhead in kernel namespace
++
++v1.0beta10 (13.06.2005)
++- fixed ugly bug introduced in beta9 that caused kernel crash on x86
++ (thanks to Emiliano for reporting it!)
++
++v1.0beta9 (17.03.2005)
++- added NLS support (thanks to Pavel Fedin!)
++
++v1.0beta8 (07.01.2005)
++- adapted to 2.6.10 kernel VFS changes
++- added workaround for buggy Mandrake kernel headers
++
++v1.0beta7 (25.06.2004)
++- small changes in documentation
++- code clean up: bitfuncs.c, super.c, inode.c, *.h, Makefile, added
++ asfs_ prefix to function names, made some functions static
++ (big thanks to Christoph Hellwig for advice!)
++- fixed minor bugs (inode leak in super.c, not-realesed buffer during
++ object renaming in inode.c)
++- now files/dirs are created with global ownership/permission bits
++
++v1.0beta6 (04.06.2004)
++- fixed: ASFS_SB(sb)->flags was always zero in 2.6.x code
++
++v1.0beta5 (07.05.2004)
++- finally fixed a problem with file size attrib. not being written
++ to disk
++- fixed some problems with GCC 3.x and debug enabled
++
++v1.0beta4 (12.04.2004)
++- removed dummy asfs_notify_change (this fixes major bug introduced
++ in 1.0beta3 - file size wasn't written to disk) until it will
++ be implemented completely
++
++v1.0beta3 (22.03.2004) - still beta
++- updated for 2.6.x kernels VFS changes
++- code clean-up
++- added dummy asfs_notify_change (chmod now returns no errors)
++- added symlinks write support
++- fixed: ASFS_SB(sb)->flags was always zero
++
++v1.0beta2 (11.01.2004) - special version for Pegasos][ kernel
++- separated read and write functions, can be compiled also
++ as read-only fs
++
++v1.0beta1 (02.12.2003) - first public beta with write support
++- added dentry hashing/comparing routines
++- code clean-up
++
++v1.0aplha4 (30.11.2003) - preparing for first public beta
++- fixed some problems with renaming/moving files
++- fixed two major bugs, which didn't occur when fs was mounted
++ on loopback device (newly allocated blocks were not written to
++ disk and state bits were not set correctly on newly mapped file
++ blocks)
++- fixed many small bugs in io code (some buffers were not freed)
++- added/modified sb locks in asfs_lookup and asfs_getblock
++- fixed serious bug in file block allocation routines
++
++v1.0aplha3 (23.11.2003)
++- added (hopefully) all byteswap code, should now work again on
++ little-endian systems (also with write support!)
++- updated documentation
++
++v1.0alpha2 (13.11.2003)
++- now alocates file blocks in chunks during one request
++- fixed some dead-locks, other fixes
++
++v1.0alpha (02.11.2003) - first working version with full write support
++- too much to list it here ;)
++
++... (working on write support)
++
++v0.7 (12.10.2003) - internal realase
++- added asfs_breadcheck, modified asfs_get_node, asfs_search_BTree,
++ no more from_be32/16 macros, other...
++- code splitted into several files
++
++v0.6 (04.09.2003) - final read-only version
++- added support for HashTables, directory scaning should be
++ MUCH faster now
++- added checking of block IDs before reading any data from block
++
++v0.5 (19.07.2003)
++- added simple but effective extent cache - real speed-up
++ in reading large files
++- added read support for symlinks - based on AFFS symlinks
++
++v0.4 (10.07.2003)
++- third code clean-up (thanks to Roman Zippel for advice)
++- now uses generic readpage and readinode routines
++
++v0.3beta (17.06.2003)
++- second code clean-up
++
++v0.2beta2 (15.06.2003)
++- fixed yet another stupid bug - driver can't read root block on little-endian systems
++v0.2beta (15.06.2003)
++- fixed stupid bug - now files have 'file' flag (S_IFREG) set...
++- added mount options to set uid, gid and mode of files and dirs
++- made hidden files & dirs really hidden (= not listed in directories)
++- code clean-up
++
++v0.1beta (11.06.2003)
++- after many kernel crashes, finally got it!
++- first working read-only filesystem driver
+diff -urN linux-2.6.18/fs/asfs/dir.c linux-2.6.18-asfs-1.0b11/fs/asfs/dir.c
+--- linux-2.6.18/fs/asfs/dir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/dir.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,240 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta7
++ *
++ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ *
++ * 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/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++
++extern struct dentry_operations asfs_dentry_operations;
++
++int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
++{
++ struct inode *dir = filp->f_dentry->d_inode;
++ struct super_block *sb = dir->i_sb;
++ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
++ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
++ u8 buf[512];
++ unsigned long f_pos;
++ int stored = 0;
++
++ struct buffer_head *bh;
++ struct fsObjectContainer *objcont;
++ struct fsObject *obj;
++ u32 block;
++ int startnode;
++ int add;
++
++ asfs_debug("asfs_readdir:\n");
++
++ if (filp->f_pos == ASFS_SB(sb)->totalblocks)
++ return stored;
++
++ f_pos = filp->f_pos;
++
++ if (f_pos == 0) {
++ filp->private_data = (void *)0;
++ if (filldir(dirent, ".", 1, f_pos, dir->i_ino, DT_DIR) < 0)
++ return 0;
++ filp->f_pos = f_pos = 1;
++ stored++;
++ }
++ if (f_pos == 1) {
++ if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0)
++ return stored;
++ filp->f_pos = f_pos = 2;
++ stored++;
++ }
++
++ if (ASFS_I(dir)->firstblock == 0) { /* empty directory */
++ filp->f_pos = ASFS_SB(sb)->totalblocks;
++ ASFS_I(dir)->modified = 0;
++ return stored;
++ }
++
++ if (f_pos == 2) { /* reading directory from its beginning */
++ block = ASFS_I(dir)->firstblock;
++ add = 1;
++ startnode = 0;
++ } else {
++ startnode = (int)filp->private_data;
++ add = 0;
++ if (ASFS_I(dir)->modified == 0)
++ block = f_pos;
++ else
++ block = ASFS_I(dir)->firstblock;
++ }
++
++ do {
++ if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID)))
++ return stored;
++ objcont = (struct fsObjectContainer *) bh->b_data;
++ obj = &(objcont->object[0]);
++
++ while (be32_to_cpu(obj->objectnode) > 0 &&
++ ((char *)obj - (char *)objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
++
++ if (!add && be32_to_cpu(obj->objectnode) == startnode)
++ add++;
++
++ if (add && !(obj->bits & OTYPE_HIDDEN)) {
++ unsigned int type;
++ asfs_translate(buf, obj->name, nls_io, nls_disk, 512);
++ asfs_debug("ASFS: DirFilling: entry #%d \"%s\" (node %u offset %u), type %x\n", \
++ stored, buf, be32_to_cpu(obj->objectnode), block, obj->bits);
++ filp->f_pos = block;
++
++ if (obj->bits & OTYPE_DIR)
++ type = DT_DIR;
++ else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK))
++ type = DT_LNK;
++ else
++ type = DT_REG;
++
++ if (filldir(dirent, buf, strlen(buf), block, be32_to_cpu(obj->objectnode), type) < 0) {
++ filp->private_data = (void *)be32_to_cpu(obj->objectnode);
++ ASFS_I(dir)->modified = 0;
++ asfs_debug("ASFS: DirFilling: to be continued...\n");
++ asfs_brelse(bh);
++ return stored;
++ }
++ stored++;
++ }
++ obj = asfs_nextobject(obj);
++ }
++ block = be32_to_cpu(objcont->next);
++ asfs_brelse(bh);
++
++ } while (block != 0);
++
++ filp->f_pos = ASFS_SB(sb)->totalblocks;
++ ASFS_I(dir)->modified = 0;
++
++ return stored;
++}
++
++static struct fsObject *asfs_find_obj_by_name_nls(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
++{
++ struct fsObject *obj;
++ u8 buf[512];
++
++ obj = &(objcont->object[0]);
++ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
++ asfs_translate(buf, obj->name, ASFS_SB(sb)->nls_io, ASFS_SB(sb)->nls_disk, 512);
++ if (asfs_namecmp(buf, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, ASFS_SB(sb)->nls_io) == 0) {
++ asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
++ return obj;
++ }
++ obj = asfs_nextobject(obj);
++ }
++ return NULL;
++}
++
++struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
++{
++ int res = -EACCES; /* placeholder for "no data here" */
++ struct inode *inode;
++ struct super_block *sb = dir->i_sb;
++ u8 *name = (u8 *) dentry->d_name.name;
++ struct buffer_head *bh;
++ struct fsObject *obj;
++ u8 bufname[ASFS_MAXFN_BUF];
++
++ asfs_translate(bufname, name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
++
++ asfs_debug("asfs_lookup: (searching \"%s\"...) ", name);
++
++ lock_super(sb);
++
++ if ((!strchr(name, '?')) && (ASFS_I(dir)->hashtable != 0)) { /* hashtable block is available and name can be reverse translated, quick search */
++ struct fsObjectNode *node_p;
++ struct buffer_head *node_bh;
++ u32 node;
++ u16 hash16;
++
++ asfs_debug("(quick search) ");
++
++ if (!(bh = asfs_breadcheck(sb, ASFS_I(dir)->hashtable, ASFS_HASHTABLE_ID))) {
++ unlock_super(sb);
++ return ERR_PTR(res);
++ }
++ hash16 = asfs_hash(bufname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE);
++ node = be32_to_cpu(((struct fsHashTable *) bh->b_data)->hashentry[HASHCHAIN(hash16)]);
++ asfs_brelse(bh);
++
++ while (node != 0) {
++ if (asfs_getnode(sb, node, &node_bh, &node_p) != 0)
++ goto not_found;
++ if (be16_to_cpu(node_p->hash16) == hash16) {
++ if (!(bh = asfs_breadcheck(sb, be32_to_cpu(node_p->node.data), ASFS_OBJECTCONTAINER_ID))) {
++ asfs_brelse(node_bh);
++ unlock_super(sb);
++ return ERR_PTR(res);
++ }
++ if ((obj = asfs_find_obj_by_name(sb, (struct fsObjectContainer *) bh->b_data, bufname)) != NULL) {
++ asfs_brelse(node_bh);
++ goto found_inode;
++ }
++ asfs_brelse(bh);
++ }
++ node = be32_to_cpu(node_p->next);
++ asfs_brelse(node_bh);
++ }
++ } else { /* hashtable not available or name can't be reverse-translated, long search */
++ struct fsObjectContainer *objcont;
++ u32 block;
++
++ asfs_debug("(long search) ");
++ block = ASFS_I(dir)->firstblock;
++ while (block != 0) {
++ if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID))) {
++ unlock_super(sb);
++ return ERR_PTR(res);
++ }
++ objcont = (struct fsObjectContainer *) bh->b_data;
++ if ((obj = asfs_find_obj_by_name_nls(sb, objcont, name)) != NULL)
++ goto found_inode;
++ block = be32_to_cpu(objcont->next);
++ asfs_brelse(bh);
++ }
++ }
++
++not_found:
++ unlock_super(sb);
++ inode = NULL;
++ asfs_debug("object not found.\n");
++ if (0) {
++found_inode:
++ unlock_super(sb);
++ if (!(inode = iget_locked(sb, be32_to_cpu(obj->objectnode)))) {
++ asfs_debug("ASFS: Strange - no inode allocated.\n");
++ return ERR_PTR(res);
++ }
++ if (inode->i_state & I_NEW) {
++ asfs_read_locked_inode(inode, obj);
++ unlock_new_inode(inode);
++ }
++ asfs_brelse(bh);
++ }
++ res = 0;
++ dentry->d_op = &asfs_dentry_operations;
++ d_add(dentry, inode);
++ return ERR_PTR(res);
++}
+diff -urN linux-2.6.18/fs/asfs/extents.c linux-2.6.18-asfs-1.0b11/fs/asfs/extents.c
+--- linux-2.6.18/fs/asfs/extents.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/extents.c 2006-09-22 23:22:48.000000000 +0200
+@@ -0,0 +1,586 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta11
++ *
++ * This file contains some parts of the original amiga version of
++ * SmartFilesystem source code.
++ *
++ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
++ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
++ *
++ * Adapted and modified by Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++
++ /* This function looks for the BNode equal to the key. If no
++ exact match is available then the BNode which is slightly
++ lower than key will be returned. If no such BNode exists
++ either, then the first BNode in this block is returned.
++
++ This function will return the first BNode even if there
++ are no BNode's at all in this block (this can only happen
++ for the Root of the tree). Be sure to check if the Root
++ is not empty before calling this function. */
++
++static struct BNode *searchforbnode(u32 key, struct BTreeContainer *tc)
++{
++ struct BNode *tn;
++ s16 n = be16_to_cpu(tc->nodecount) - 1;
++
++ tn = (struct BNode *) ((u8 *) tc->bnode + n * tc->nodesize);
++ for (;;) {
++ if (n <= 0 || key >= be32_to_cpu(tn->key))
++ return tn;
++
++ tn = (struct BNode *) ((u8 *) tn - tc->nodesize);
++ n--;
++ }
++}
++
++/* This function finds the BNode with the given key. If no exact match can be
++ found then this function will return either the next or previous closest
++ match (don't rely on this).
++
++ If there were no BNode's at all, then *returned_bh will be NULL. */
++
++static int findbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode)
++{
++ u32 rootblock = ASFS_SB(sb)->extentbnoderoot;
++
++ asfs_debug("findbnode: Looking for BNode with key %d\n", key);
++
++ while ((*returned_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) {
++ struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data;
++ struct BTreeContainer *btc = &bnc->btc;
++
++ if (btc->nodecount == 0) {
++ *returned_bnode = NULL;
++ break;
++ }
++
++ *returned_bnode = searchforbnode(key, btc);
++ if (btc->isleaf == TRUE)
++ break;
++
++ rootblock = be32_to_cpu((*returned_bnode)->data);
++ asfs_brelse(*returned_bh);
++ }
++
++ if (*returned_bh == NULL)
++ return -EIO;
++
++ return 0;
++}
++
++int asfs_getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh, struct fsExtentBNode **ret_ebn)
++{
++ int result;
++ if ((result = findbnode(sb, key, ret_bh, (struct BNode **)ret_ebn)) == 0)
++ if (be32_to_cpu((*ret_ebn)->key) != key) {
++ brelse(*ret_bh);
++ *ret_bh = NULL;
++ return -ENOENT;
++ }
++
++ return result;
++}
++
++#ifdef CONFIG_ASFS_RW
++
++ /* This routine inserts a node sorted into a BTreeContainer. It does
++ this by starting at the end, and moving the nodes one by one to
++ a higher slot until the empty slot has the correct position for
++ this key. Donot use this function on completely filled
++ BTreeContainers! */
++
++static struct BNode *insertbnode(u32 key, struct BTreeContainer *btc)
++{
++ struct BNode *bn;
++ bn = (struct BNode *) ((u8 *) btc->bnode + btc->nodesize * (be16_to_cpu(btc->nodecount) - 1));
++
++ for (;;) {
++ if (bn < btc->bnode || key > be32_to_cpu(bn->key)) {
++ bn = (struct BNode *) ((u8 *) bn + btc->nodesize);
++ bn->key = cpu_to_be32(key);
++ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + 1);
++ break;
++ } else
++ memmove((u8 *)bn + btc->nodesize, bn, btc->nodesize);
++
++ bn = (struct BNode *) ((u8 *) bn - btc->nodesize);
++ }
++
++ return bn;
++}
++
++static int getparentbtreecontainer(struct super_block *sb, struct buffer_head *bh, struct buffer_head **parent_bh)
++{
++ u32 rootblock = ASFS_SB(sb)->extentbnoderoot;
++ u32 childkey = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->btc.bnode[0].key);
++ u32 childblock = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->bheader.ownblock);
++
++ asfs_debug("getparentbtreecontainer: Getting parent of block %d\n", childblock);
++
++ /* This function gets the BTreeContainer parent of the passed in buffer_head. If
++ there is no parent this function sets dest_cont io_bh to NULL */
++
++ if (rootblock != childblock) {
++ while ((*parent_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) {
++ struct fsBNodeContainer *bnc = (void *) (*parent_bh)->b_data;
++ struct BTreeContainer *btc = &bnc->btc;
++ struct BNode *bn;
++ s16 n = be16_to_cpu(btc->nodecount);
++
++ if (btc->isleaf == TRUE) {
++ asfs_brelse(*parent_bh);
++ break;
++ }
++
++ while (n-- > 0)
++ if (be32_to_cpu(btc->bnode[n].data) == childblock)
++ return 0; /* Found parent!! */
++
++ bn = searchforbnode(childkey, btc); /* This searchforbnode() doesn't have to get EXACT key matches. */
++ rootblock = be32_to_cpu(bn->data);
++ asfs_brelse(*parent_bh);
++ }
++ if (*parent_bh == NULL)
++ return -EIO;
++ }
++
++ *parent_bh = NULL;
++ return 0;
++}
++
++/* Spits a btreecontainer. It realses passed in bh! */
++
++static int splitbtreecontainer(struct super_block *sb, struct buffer_head *bh)
++{
++ struct buffer_head *bhparent;
++ struct BNode *bn;
++ int errorcode;
++
++ asfs_debug("splitbtreecontainer: splitting block %u\n", be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock));
++
++ if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
++ if (bhparent == NULL) {
++ u32 newbcontblock;
++ u32 bcontblock;
++ /* We need to create Root tree-container - adding new level to extent tree */
++
++ asfs_debug("splitbtreecontainer: creating root tree-container.\n");
++
++ bhparent = bh;
++ if ((errorcode = asfs_allocadminspace(sb, &newbcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newbcontblock))) {
++ struct fsBNodeContainer *bnc = (void *) bh->b_data;
++ struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
++ struct BTreeContainer *btcparent = &bncparent->btc;
++
++ bcontblock = be32_to_cpu(bncparent->bheader.ownblock);
++ memcpy(bh->b_data, bhparent->b_data, sb->s_blocksize);
++ bnc->bheader.ownblock = cpu_to_be32(newbcontblock);
++ asfs_bstore(sb, bh);
++
++ memset(bhparent->b_data, '\0', sb->s_blocksize); /* Not strictly needed, but makes things more clear. */
++ bncparent->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID);
++ bncparent->bheader.ownblock = cpu_to_be32(bcontblock);
++ btcparent->isleaf = FALSE;
++ btcparent->nodesize = sizeof(struct BNode);
++ btcparent->nodecount = 0;
++
++ bn = insertbnode(0, btcparent);
++ bn->data = cpu_to_be32(newbcontblock);
++
++ asfs_bstore(sb, bhparent);
++ }
++ if (bh == NULL)
++ errorcode = -EIO;
++ }
++
++ if (errorcode == 0) {
++ struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
++ struct BTreeContainer *btcparent = &bncparent->btc;
++ int branches1 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btcparent->nodesize;
++
++ if (be16_to_cpu(btcparent->nodecount) == branches1) {
++ /* We need to split the parent tree-container first! */
++ if ((errorcode = splitbtreecontainer(sb, bhparent)) == 0) {
++ /* bhparent might have changed after the split and has been released */
++ if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
++ bncparent = (void *) bhparent->b_data;
++ btcparent = &bncparent->btc;
++ }
++ }
++ }
++
++ if (errorcode == 0) {
++ u32 newbcontblock;
++ struct buffer_head *bhnew;
++
++ /* We can split this container and add it to the parent
++ because the parent has enough room. */
++
++ if ((errorcode = asfs_allocadminspace(sb, &newbcontblock)) == 0 && (bhnew = asfs_getzeroblk(sb, newbcontblock))) {
++ struct fsBNodeContainer *bncnew = (void *) bhnew->b_data;
++ struct BTreeContainer *btcnew = &bncnew->btc;
++ struct fsBNodeContainer *bnc = (void *) bh->b_data;
++ struct BTreeContainer *btc = &bnc->btc;
++ int branches2 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
++ u32 newkey;
++
++ bncnew->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID);
++ bncnew->bheader.ownblock = cpu_to_be32(newbcontblock);
++
++ btcnew->isleaf = btc->isleaf;
++ btcnew->nodesize = btc->nodesize;
++
++ btcnew->nodecount = cpu_to_be16(branches2 - branches2 / 2);
++
++ memcpy(btcnew->bnode, (u8 *) btc->bnode + branches2 / 2 * btc->nodesize, (branches2 - branches2 / 2) * btc->nodesize);
++ newkey = be32_to_cpu(btcnew->bnode[0].key);
++
++ asfs_bstore(sb, bhnew);
++ asfs_brelse(bhnew);
++
++ btc->nodecount = cpu_to_be16(branches2 / 2);
++ asfs_bstore(sb, bh);
++
++ bn = insertbnode(newkey, btcparent);
++ bn->data = cpu_to_be32(newbcontblock);
++ asfs_bstore(sb, bhparent);
++ }
++ }
++ }
++ asfs_brelse(bhparent);
++ }
++ asfs_brelse(bh);
++
++ return errorcode;
++}
++
++/* Returns created extentbnode - returned_bh need to saved and realesed in caller funkction! */
++
++static int createextentbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode)
++{
++ int errorcode;
++
++ asfs_debug("createbnode: Creating BNode with key %d\n", key);
++
++ while ((errorcode = findbnode(sb, key, returned_bh, returned_bnode)) == 0) {
++ struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data;
++ struct BTreeContainer *btc = &bnc->btc;
++ int extbranches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
++
++ asfs_debug("createbnode: findbnode found block %d\n", be32_to_cpu(((struct fsBlockHeader *) (*returned_bh)->b_data)->ownblock));
++
++ if (be16_to_cpu(btc->nodecount) < extbranches) {
++ /* Simply insert new node in this BTreeContainer */
++ asfs_debug("createbnode: Simple insert\n");
++ *returned_bnode = insertbnode(key, btc);
++ break;
++ } else if ((errorcode = splitbtreecontainer(sb, *returned_bh)) != 0)
++ break;
++
++ /* Loop and try insert it the normal way again :-) */
++ }
++
++ return (errorcode);
++}
++
++
++/* This routine removes a node from a BTreeContainer indentified
++ by its key. If no such key exists this routine does nothing.
++ It correctly handles empty BTreeContainers. */
++
++static void removebnode(u32 key, struct BTreeContainer *btc)
++{
++ struct BNode *bn = btc->bnode;
++ int n = 0;
++
++ asfs_debug("removebnode: key %d\n", key);
++
++ while (n < be16_to_cpu(btc->nodecount)) {
++ if (be32_to_cpu(bn->key) == key) {
++ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) - 1);
++ memmove(bn, (u8 *) bn + btc->nodesize, (be16_to_cpu(btc->nodecount) - n) * btc->nodesize);
++ break;
++ }
++ bn = (struct BNode *) ((u8 *) bn + btc->nodesize);
++ n++;
++ }
++}
++
++int asfs_deletebnode(struct super_block *sb, struct buffer_head *bh, u32 key)
++{
++ struct fsBNodeContainer *bnc1 = (void *) bh->b_data;
++ struct BTreeContainer *btc = &bnc1->btc;
++ u16 branches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
++ int errorcode = 0;
++
++ /* Deletes specified internal node. */
++
++ removebnode(key, btc);
++ asfs_bstore(sb, bh);
++
++ /* Now checks if the container still contains enough nodes,
++ and takes action accordingly. */
++
++ asfs_debug("deletebnode: branches = %d, btc->nodecount = %d\n", branches, be16_to_cpu(btc->nodecount));
++
++ if (be16_to_cpu(btc->nodecount) < (branches + 1) / 2) {
++ struct buffer_head *bhparent;
++ struct buffer_head *bhsec;
++
++ /* nodecount has become to low. We need to merge this Container
++ with a neighbouring Container, or we need to steal a few nodes
++ from a neighbouring Container. */
++
++ /* We get the parent of the container here, so we can find out what
++ containers neighbour the container which currently hasn't got enough nodes. */
++
++ if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
++ if (bhparent != NULL) {
++ struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
++ struct BTreeContainer *btcparent = &bncparent->btc;
++ s16 n;
++
++ asfs_debug("deletebnode: get parent returned block %d.\n", be32_to_cpu(((struct fsBlockHeader *) bhparent->b_data)->ownblock));
++
++ for (n = 0; n < be16_to_cpu(btcparent->nodecount); n++)
++ if (btcparent->bnode[n].data == bnc1->bheader.ownblock)
++ break;
++ /* n is now the offset of our own bnode. */
++
++ if (n < be16_to_cpu(btcparent->nodecount) - 1) { /* Check if we have a next neighbour. */
++ asfs_debug("deletebnode: using next container - merging blocks %d and %d\n", be32_to_cpu(bnc1->bheader.ownblock), be32_to_cpu(btcparent->bnode[n+1].data));
++
++ if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n + 1].data), ASFS_BNODECONTAINER_ID))) {
++ struct fsBNodeContainer *bnc_next = (void *) bhsec->b_data;
++ struct BTreeContainer *btc_next = &bnc_next->btc;
++
++ if (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount) > branches) { /* Check if we need to steal nodes. */
++ s16 nodestosteal = (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount);
++
++ /* Merging them is not possible. Steal a few nodes then. */
++ memcpy((u8 *) btc->bnode + be16_to_cpu(btc->nodecount) * btc->nodesize, btc_next->bnode, nodestosteal * btc->nodesize);
++ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal);
++ asfs_bstore(sb, bh);
++
++ memcpy(btc_next->bnode, (u8 *) btc_next->bnode + btc_next->nodesize * nodestosteal,
++ btc->nodesize * (be16_to_cpu(btc_next->nodecount) - nodestosteal));
++ btc_next->nodecount = cpu_to_be16(be16_to_cpu(btc_next->nodecount) - nodestosteal);
++ asfs_bstore(sb, bhsec);
++
++ btcparent->bnode[n + 1].key = btc_next->bnode[0].key;
++ asfs_bstore(sb, bhparent);
++ } else { /* Merging is possible. */
++ memcpy((u8 *) btc->bnode + btc->nodesize * be16_to_cpu(btc->nodecount), btc_next->bnode, btc->nodesize * be16_to_cpu(btc_next->nodecount));
++ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + be16_to_cpu(btc_next->nodecount));
++ asfs_bstore(sb, bh);
++
++ if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0)
++ errorcode = asfs_deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n + 1].key));
++ }
++ asfs_brelse(bhsec);
++ }
++ } else if (n > 0) { /* Check if we have a previous neighbour. */
++ asfs_debug("deletebnode: using prev container.\n");
++
++ if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n - 1].data), ASFS_BNODECONTAINER_ID)) == 0) {
++ struct fsBNodeContainer *bnc2 = (void *) bhsec->b_data;
++ struct BTreeContainer *btc2 = &bnc2->btc;
++
++ if (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount) > branches) {
++ /* Merging them is not possible. Steal a few nodes then. */
++ s16 nodestosteal = (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount);
++
++ memmove((u8 *) btc->bnode + nodestosteal * btc->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize);
++ btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal);
++ memcpy(btc->bnode, (u8 *) btc2->bnode + (be16_to_cpu(btc2->nodecount) - nodestosteal) * btc2->nodesize, nodestosteal * btc->nodesize);
++
++ asfs_bstore(sb, bh);
++
++ btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) - nodestosteal);
++ asfs_bstore(sb, bhsec);
++
++ btcparent->bnode[n].key = btc->bnode[0].key;
++ asfs_bstore(sb, bhparent);
++ } else { /* Merging is possible. */
++ memcpy((u8 *) btc2->bnode + be16_to_cpu(btc2->nodecount) * btc2->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize);
++ btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount));
++ asfs_bstore(sb, bhsec);
++
++ if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0)
++ errorcode = asfs_deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n].key));
++ }
++ asfs_brelse(bhsec);
++ }
++ }
++ /* else
++ {
++ // Never happens, except for root and then we don't care.
++ } */
++ } else if (btc->nodecount == 1) {
++ /* No parent, so must be root. */
++
++ asfs_debug("deletebnode: no parent so must be root\n");
++
++ if (btc->isleaf == FALSE) {
++ struct fsBNodeContainer *bnc3 = (void *) bh->b_data;
++
++ /* The current root has only 1 node. We now copy the data of this node into the
++ root and promote that data to be the new root. The rootblock number stays the
++ same that way. */
++
++ if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btc->bnode[0].data), ASFS_BNODECONTAINER_ID))) {
++ u32 blockno = be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock);
++ memcpy(bh->b_data, bhsec->b_data, sb->s_blocksize);
++ bnc3->bheader.ownblock = cpu_to_be32(blockno);
++
++ asfs_bstore(sb, bh);
++ errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock));
++ asfs_brelse(bhsec);
++ } else
++ errorcode = -EIO;
++ }
++ /* If not, then root contains leafs. */
++ }
++
++ asfs_debug("deletebnode: almost done\n");
++ /* otherwise, it must be the root, and the root is allowed
++ to contain less than the minimum amount of nodes. */
++
++ }
++ if (bhparent != NULL)
++ asfs_brelse(bhparent);
++ }
++
++ return errorcode;
++}
++
++ /* Deletes an fsExtentBNode structure by key and any fsExtentBNodes linked to it.
++ This function DOES NOT fix the next pointer in a possible fsExtentBNode which
++ might have been pointing to the first BNode we are deleting. Make sure you check
++ this yourself, if needed.
++
++ If key is zero, than this function does nothing. */
++
++int asfs_deleteextents(struct super_block *sb, u32 key)
++{
++ struct buffer_head *bh;
++ struct fsExtentBNode *ebn;
++ int errorcode = 0;
++
++ asfs_debug("deleteextents: Entry -- deleting extents from key %d\n", key);
++
++ while (key != 0 && (errorcode = findbnode(sb, key, &bh, (struct BNode **) &ebn)) == 0) {
++ /* node to be deleted located. */
++ key = be32_to_cpu(ebn->next);
++ if ((errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key), be16_to_cpu(ebn->blocks))) != 0)
++ break;
++
++ if ((errorcode = asfs_deletebnode(sb, bh, be32_to_cpu(ebn->key))) != 0)
++ break;
++
++ asfs_brelse(bh);
++ }
++
++ return (errorcode);
++}
++
++ /* This function adds /blocks/ blocks starting at block /newspace/ to a file
++ identified by /objectnode/ and /lastextentbnode/. /io_lastextentbnode/ can
++ be zero if there is no ExtentBNode chain attached to this file yet.
++ /blocks/ ranges from 1 to 8192. To be able to extend Extents which are
++ almost full, it is wise to make this value no higher than 8192 blocks.
++ /io_lastextentbnode/ will contain the new lastextentbnode value when this
++ function completes.
++ If there was no chain yet, then this function will create a new one. */
++
++int asfs_addblocks(struct super_block *sb, u16 blocks, u32 newspace, u32 objectnode, u32 *io_lastextentbnode)
++{
++ struct buffer_head *bh;
++ struct fsExtentBNode *ebn;
++ int errorcode = 0;
++
++ if (*io_lastextentbnode != 0) {
++ /* There was already a ExtentBNode chain for this file. Extending it. */
++
++ asfs_debug(" addblocks: Extending existing ExtentBNode chain.\n");
++
++ if ((errorcode = asfs_getextent(sb, *io_lastextentbnode, &bh, &ebn)) == 0) {
++ if (be32_to_cpu(ebn->key) + be16_to_cpu(ebn->blocks) == newspace && be16_to_cpu(ebn->blocks) + blocks < 65536) {
++ /* It is possible to extent the last ExtentBNode! */
++ asfs_debug(" addblocks: Extending last ExtentBNode.\n");
++
++ ebn->blocks = cpu_to_be16(be16_to_cpu(ebn->blocks) + blocks);
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ } else {
++ /* It isn't possible to extent the last ExtentBNode so we create
++ a new one and link it to the last ExtentBNode. */
++
++ ebn->next = cpu_to_be32(newspace);
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) {
++ asfs_debug(" addblocks: Created new ExtentBNode.\n");
++
++ ebn->key = cpu_to_be32(newspace);
++ ebn->prev = cpu_to_be32(*io_lastextentbnode);
++ ebn->next = 0;
++ ebn->blocks = cpu_to_be16(blocks);
++
++ *io_lastextentbnode = newspace;
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ ASFS_SB(sb)->block_rovingblockptr = newspace + blocks;
++
++ /* to be changed in the future */
++/* if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks)
++ ASFS_SB(sb)->block_rovingblockptr = 0;*/
++ }
++ }
++ }
++ } else {
++ /* There is no ExtentBNode chain yet for this file. Attaching one! */
++ if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) {
++ asfs_debug(" addblocks: Created new ExtentBNode chain.\n");
++
++ ebn->key = cpu_to_be32(newspace);
++ ebn->prev = cpu_to_be32(objectnode + 0x80000000);
++ ebn->next = 0;
++ ebn->blocks = cpu_to_be16(blocks);
++
++ *io_lastextentbnode = newspace;
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ ASFS_SB(sb)->block_rovingblockptr = newspace + blocks;
++
++/* if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks)
++ ASFS_SB(sb)->block_rovingblockptr = 0;*/
++ }
++ }
++
++ asfs_debug(" addblocks: done.\n");
++
++ return errorcode;
++}
++#endif
+diff -urN linux-2.6.18/fs/asfs/file.c linux-2.6.18-asfs-1.0b11/fs/asfs/file.c
+--- linux-2.6.18/fs/asfs/file.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/file.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,251 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta7
++ *
++ * Copyright (C) 2003,2004 Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ *
++ * 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/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/pagemap.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++
++static int
++asfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
++{
++ struct buffer_head *ebn_bh;
++ struct fsExtentBNode extent, *ebn_p;
++ u32 filedata;
++ unsigned long pos;
++ struct super_block *sb = inode->i_sb;
++#ifdef CONFIG_ASFS_RW
++ int error;
++ struct buffer_head *bh;
++ struct fsObject *obj;
++#endif
++
++ asfs_debug("ASFS: get_block(%lu, %ld, %d)\n", inode->i_ino, block, create);
++
++ if (block < 0) {
++ printk(KERN_ERR "ASFS: asfsget_block: requested block (%ld) < 0!\n", block);
++ return -EIO;
++ } else if (block >= inode->i_blocks && !create) {
++ printk(KERN_ERR "ASFS: asfsget_block: strange block request %ld!\n", block);
++ return -EIO;
++ }
++
++ if (create)
++#ifdef CONFIG_ASFS_RW
++ ASFS_I(inode)->modified = TRUE;
++#else
++ return -EROFS;
++#endif
++
++ if (block < inode->i_blocks)
++ create = 0;
++
++ lock_super(sb);
++
++#ifdef CONFIG_ASFS_RW
++ if (create) {
++ int blockstoadd;
++ u32 newspace, addedblocks;
++
++ blockstoadd = block - inode->i_blocks + 1;
++
++ if (blockstoadd < ASFS_BLOCKCHUNKS)
++ blockstoadd = ASFS_BLOCKCHUNKS;
++
++ asfs_debug("ASFS get_block: Trying to add %d blocks to file\n", blockstoadd);
++
++ if ((error = asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
++ unlock_super(sb);
++ return error;
++ }
++
++ if ((error = asfs_addblockstofile(sb, bh, obj, blockstoadd, &newspace, &addedblocks)) != 0) {
++ asfs_brelse(bh);
++ unlock_super(sb);
++ return error;
++ }
++ ASFS_I(inode)->mmu_private += addedblocks * sb->s_blocksize;
++ inode->i_blocks += addedblocks;
++ ASFS_I(inode)->ext_cache.key = 0;
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
++ asfs_brelse(bh);
++ }
++#endif
++
++ if (ASFS_I(inode)->ext_cache.key > 0 && ASFS_I(inode)->ext_cache.startblock <= block) {
++ extent.key = ASFS_I(inode)->ext_cache.key;
++ extent.next = ASFS_I(inode)->ext_cache.next;
++ extent.blocks = ASFS_I(inode)->ext_cache.blocks;
++ pos = ASFS_I(inode)->ext_cache.startblock;
++ } else {
++ if (asfs_getextent(inode->i_sb, ASFS_I(inode)->firstblock, &ebn_bh, &ebn_p) != 0) {
++ unlock_super(sb);
++ return -EIO;
++ }
++ extent.key = be32_to_cpu(ebn_p->key);
++ extent.next = be32_to_cpu(ebn_p->next);
++ extent.blocks = be16_to_cpu(ebn_p->blocks);
++ pos = 0;
++ asfs_brelse(ebn_bh);
++ }
++ ebn_p = &extent;
++ filedata = ebn_p->next;
++
++ while (pos + ebn_p->blocks <= block && ebn_p->next != 0 && pos < inode->i_blocks) {
++ pos += ebn_p->blocks;
++ if (asfs_getextent(inode->i_sb, filedata, &ebn_bh, &ebn_p) != 0) {
++ unlock_super(sb);
++ return -EIO;
++ }
++ extent.key = be32_to_cpu(ebn_p->key);
++ extent.next = be32_to_cpu(ebn_p->next);
++ extent.blocks = be16_to_cpu(ebn_p->blocks);
++ ebn_p = &extent;
++ filedata = ebn_p->next;
++ asfs_brelse(ebn_bh);
++ }
++
++ unlock_super(sb);
++
++ map_bh(bh_result, inode->i_sb, (sector_t) (ebn_p->key + block - pos));
++
++ if (create)
++ set_buffer_new(bh_result);
++
++ asfs_debug("ASFS: get_block - mapped block %lu\n", ebn_p->key + block - pos);
++
++ ASFS_I(inode)->ext_cache.startblock = pos;
++ ASFS_I(inode)->ext_cache.key = ebn_p->key;
++ ASFS_I(inode)->ext_cache.next = ebn_p->next;
++ ASFS_I(inode)->ext_cache.blocks = ebn_p->blocks;
++
++ return 0;
++}
++
++int asfs_readpage(struct file *file, struct page *page)
++{
++ asfs_debug("ASFS: %s\n", __FUNCTION__);
++ return block_read_full_page(page, asfs_get_block);
++}
++
++sector_t asfs_bmap(struct address_space *mapping, sector_t block)
++{
++ asfs_debug("ASFS: %s\n", __FUNCTION__);
++ return generic_block_bmap(mapping,block,asfs_get_block);
++}
++
++#ifdef CONFIG_ASFS_RW
++
++int asfs_writepage(struct page *page, struct writeback_control *wbc)
++{
++ asfs_debug("ASFS: %s\n", __FUNCTION__);
++ return block_write_full_page(page, asfs_get_block, wbc);
++}
++
++int asfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
++{
++ asfs_debug("ASFS: %s\n", __FUNCTION__);
++ return cont_prepare_write(page, from, to, asfs_get_block, &ASFS_I(page->mapping->host)->mmu_private);
++}
++
++void asfs_truncate(struct inode *inode)
++{
++ struct super_block *sb = inode->i_sb;
++ struct buffer_head *bh;
++ struct fsObject *obj;
++
++ asfs_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
++ (u32)inode->i_ino, (u32)ASFS_I(inode)->mmu_private, (u32)inode->i_size);
++
++ if (inode->i_size > ASFS_I(inode)->mmu_private) {
++ printk("ASFS: enlarging file is not supported yet\n");
++ return;
++ }
++
++ lock_super(sb);
++
++ if ((asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
++ unlock_super(sb);
++ return;
++ }
++
++ if (asfs_truncateblocksinfile(sb, bh, obj, inode->i_size) != 0) {
++ asfs_brelse(bh);
++ unlock_super(sb);
++ return;
++ }
++
++ obj->object.file.size = cpu_to_be32(inode->i_size);
++ ASFS_I(inode)->mmu_private = inode->i_size;
++ ASFS_I(inode)->modified = TRUE;
++ inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ unlock_super(sb);
++}
++
++int asfs_file_open(struct inode *inode, struct file *filp)
++{
++ if (atomic_read(&filp->f_count) != 1)
++ return 0;
++ asfs_debug("ASFS: file open (node %d)\n", (int)inode->i_ino);
++ return 0;
++}
++
++int asfs_file_release(struct inode *inode, struct file *filp)
++{
++ int error = 0;
++
++ asfs_debug("ASFS: file release (node %d oc %d)\n", (int)inode->i_ino, atomic_read(&filp->f_count));
++
++ if (atomic_read(&filp->f_count) != 0)
++ return 0;
++
++ if (ASFS_I(inode)->modified == TRUE) {
++ struct buffer_head *bh;
++ struct fsObject *obj;
++ lock_super(inode->i_sb);
++
++ if ((error = asfs_readobject(inode->i_sb, inode->i_ino, &bh, &obj)) != 0) {
++ unlock_super(inode->i_sb);
++ return error;
++ }
++
++ obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60);
++ if (inode->i_mode & S_IFREG) {
++ error = asfs_truncateblocksinfile(inode->i_sb, bh, obj, (u32)inode->i_size);
++ obj->object.file.size = cpu_to_be32(inode->i_size);
++ ASFS_I(inode)->mmu_private = inode->i_size;
++ inode->i_blocks = (be32_to_cpu(obj->object.file.size) + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
++ }
++ asfs_bstore(inode->i_sb, bh);
++
++ unlock_super(inode->i_sb);
++
++ asfs_brelse(bh);
++ }
++ ASFS_I(inode)->modified = FALSE;
++
++ return error;
++}
++
++#endif
+diff -urN linux-2.6.18/fs/asfs/inode.c linux-2.6.18-asfs-1.0b11/fs/asfs/inode.c
+--- linux-2.6.18/fs/asfs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/inode.c 2006-09-22 23:22:35.000000000 +0200
+@@ -0,0 +1,436 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta11
++ *
++ * Copyright (C) 2003,2004,2005 Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ *
++ * 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/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/time.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/dirent.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++
++static int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd);
++static int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++static int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
++static int asfs_rmdir(struct inode *dir, struct dentry *dentry);
++static int asfs_unlink(struct inode *dir, struct dentry *dentry);
++static int asfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry);
++/*static int asfs_notify_change(struct dentry *dentry, struct iattr *attr);*/
++
++
++/* Mapping from our types to the kernel */
++
++static struct address_space_operations asfs_aops = {
++ .readpage = asfs_readpage,
++ .sync_page = block_sync_page,
++ .bmap = asfs_bmap,
++#ifdef CONFIG_ASFS_RW
++ .writepage = asfs_writepage,
++ .prepare_write = asfs_prepare_write,
++ .commit_write = generic_commit_write,
++#endif
++};
++
++static struct file_operations asfs_file_operations = {
++ .llseek = generic_file_llseek,
++ .read = generic_file_read,
++ .mmap = generic_file_mmap,
++#ifdef CONFIG_ASFS_RW
++ .write = generic_file_write,
++ .open = asfs_file_open,
++ .release = asfs_file_release,
++ .fsync = file_fsync,
++#endif
++};
++
++static struct file_operations asfs_dir_operations = {
++ .read = generic_read_dir,
++ .readdir = asfs_readdir,
++};
++
++static struct inode_operations asfs_dir_inode_operations = {
++ .lookup = asfs_lookup,
++#ifdef CONFIG_ASFS_RW
++ .create = asfs_create,
++ .unlink = asfs_unlink,
++ .symlink = asfs_symlink,
++ .mkdir = asfs_mkdir,
++ .rmdir = asfs_rmdir,
++ .rename = asfs_rename,
++/* .setattr = asfs_notify_change,*/
++#endif
++};
++
++static struct inode_operations asfs_file_inode_operations = {
++#ifdef CONFIG_ASFS_RW
++ .truncate = asfs_truncate,
++/* .setattr = asfs_notify_change,*/
++#endif
++};
++
++static struct address_space_operations asfs_symlink_aops = {
++ .readpage = asfs_symlink_readpage,
++};
++
++static struct inode_operations asfs_symlink_inode_operations = {
++ .readlink = page_readlink,
++ .follow_link = page_follow_link_light,
++ .put_link = page_put_link,
++#ifdef CONFIG_ASFS_RW
++/* .setattr = asfs_notify_change,*/
++#endif
++};
++
++void asfs_read_locked_inode(struct inode *inode, void *arg)
++{
++ struct super_block *sb = inode->i_sb;
++ struct fsObject *obj = arg;
++
++ inode->i_mode = ASFS_SB(sb)->mode;
++ inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = be32_to_cpu(obj->datemodified) + (365*8+2)*24*60*60;
++ /* Linux: seconds since 01-01-1970, AmigaSFS: seconds since 01-01-1978 */
++ inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
++ inode->i_uid = ASFS_SB(sb)->uid;
++ inode->i_gid = ASFS_SB(sb)->gid;
++
++ asfs_debug("asfs_read_inode2: Setting-up node %lu... ", inode->i_ino);
++
++ if (obj->bits & OTYPE_DIR) {
++ asfs_debug("dir (FirstdirBlock: %u, HashTable %u)\n", \
++ be32_to_cpu(obj->object.dir.firstdirblock), be32_to_cpu(obj->object.dir.hashtable));
++
++ inode->i_size = 0;
++ inode->i_op = &asfs_dir_inode_operations;
++ inode->i_fop = &asfs_dir_operations;
++ inode->i_mode |= S_IFDIR | ((inode->i_mode & 0400) ? 0100 : 0) |
++ ((inode->i_mode & 0040) ? 0010 : 0) | ((inode->i_mode & 0004) ? 0001 : 0);
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
++ ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable);
++ ASFS_I(inode)->modified = 0;
++ } else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK)) {
++ asfs_debug("symlink\n");
++ inode->i_size = 0;
++ inode->i_op = &asfs_symlink_inode_operations;
++ inode->i_mapping->a_ops = &asfs_symlink_aops;
++ inode->i_mode |= S_IFLNK | S_IRWXUGO;
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
++ } else {
++ asfs_debug("file (Size: %u, FirstBlock: %u)\n", be32_to_cpu(obj->object.file.size), be32_to_cpu(obj->object.file.data));
++ inode->i_size = be32_to_cpu(obj->object.file.size);
++ inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
++ inode->i_op = &asfs_file_inode_operations;
++ inode->i_fop = &asfs_file_operations;
++ inode->i_mapping->a_ops = &asfs_aops;
++ inode->i_mode |= S_IFREG;
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
++ ASFS_I(inode)->ext_cache.startblock = 0;
++ ASFS_I(inode)->ext_cache.key = 0;
++ ASFS_I(inode)->mmu_private = inode->i_size;
++ }
++ return;
++}
++
++struct inode *asfs_get_root_inode(struct super_block *sb)
++{
++ struct inode *result = NULL;
++ struct fsObject *obj;
++ struct buffer_head *bh;
++
++ asfs_debug("asfs_get_root_inode\n");
++
++ if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
++ obj = &(((struct fsObjectContainer *)bh->b_data)->object[0]);
++ if (be32_to_cpu(obj->objectnode) > 0)
++ result = iget_locked(sb, be32_to_cpu(obj->objectnode));
++
++ if (result != NULL && result->i_state & I_NEW) {
++ asfs_read_locked_inode(result, obj);
++ unlock_new_inode(result);
++ }
++ asfs_brelse(bh);
++ }
++ return result;
++}
++
++#ifdef CONFIG_ASFS_RW
++
++static void asfs_sync_dir_inode(struct inode *dir, struct fsObject *obj)
++{
++ ASFS_I(dir)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
++ ASFS_I(dir)->modified = 1;
++ dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME;
++ obj->datemodified = cpu_to_be32(dir->i_mtime.tv_sec - (365*8+2)*24*60*60);
++}
++
++enum { it_file, it_dir, it_link };
++
++static int asfs_create_object(struct inode *dir, struct dentry *dentry, int mode, int type, const char *symname)
++{
++ int error;
++ struct super_block *sb = dir->i_sb;
++ struct inode *inode;
++ struct buffer_head *bh, *dir_bh;
++ struct fsObject obj_data, *dir_obj, *obj;
++ u8 *name = (u8 *) dentry->d_name.name;
++ u8 bufname[ASFS_MAXFN_BUF];
++
++ asfs_debug("asfs_create_obj %s in dir node %d\n", name, (int)dir->i_ino);
++
++ asfs_translate(bufname, name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
++ if ((error = asfs_check_name(bufname, strlen(bufname))) != 0)
++ return error;
++
++ sb = dir->i_sb;
++ inode = new_inode(sb);
++ if (!inode)
++ return -ENOMEM;
++
++ memset(&obj_data, 0, sizeof(struct fsObject));
++
++ obj_data.protection = cpu_to_be32(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
++ obj_data.datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60);
++ switch (type) {
++ case it_dir:
++ obj_data.bits = OTYPE_DIR;
++ break;
++ case it_link:
++ obj_data.bits = OTYPE_LINK;
++ break;
++ default:
++ break;
++ }
++
++ lock_super(sb);
++
++ if ((error = asfs_readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) {
++ dec_count(inode);
++ unlock_super(sb);
++ return error;
++ }
++
++ bh = dir_bh;
++ obj = dir_obj;
++
++ if ((error = asfs_createobject(sb, &bh, &obj, &obj_data, bufname, FALSE)) != 0) {
++ asfs_brelse(dir_bh);
++ dec_count(inode);
++ unlock_super(sb);
++ return error;
++ }
++
++ inode->i_ino = be32_to_cpu(obj->objectnode);
++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
++ inode->i_size = inode->i_blocks = inode->i_blksize = 0;
++ inode->i_uid = dir->i_uid;
++ inode->i_gid = dir->i_gid;
++ inode->i_mode = mode | ASFS_SB(sb)->mode;
++
++ switch (type) {
++ case it_dir:
++ inode->i_mode |= S_IFDIR;
++ inode->i_op = &asfs_dir_inode_operations;
++ inode->i_fop = &asfs_dir_operations;
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
++ ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable);
++ ASFS_I(inode)->modified = 0;
++ break;
++ case it_file:
++ inode->i_mode |= S_IFREG;
++ inode->i_op = &asfs_file_inode_operations;
++ inode->i_fop = &asfs_file_operations;
++ inode->i_mapping->a_ops = &asfs_aops;
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
++ ASFS_I(inode)->ext_cache.startblock = 0;
++ ASFS_I(inode)->ext_cache.key = 0;
++ ASFS_I(inode)->mmu_private = inode->i_size;
++ break;
++ case it_link:
++ inode->i_mode = S_IFLNK | S_IRWXUGO;
++ inode->i_op = &page_symlink_inode_operations;
++ inode->i_mapping->a_ops = &asfs_symlink_aops;
++ ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
++ error = asfs_write_symlink(inode, symname);
++ break;
++ default:
++ break;
++ }
++
++ asfs_bstore(sb, bh);
++ insert_inode_hash(inode);
++ mark_inode_dirty(inode);
++ d_instantiate(dentry, inode);
++ asfs_sync_dir_inode(dir, dir_obj);
++ asfs_bstore(sb, dir_bh);
++
++ unlock_super(sb);
++ asfs_brelse(bh);
++ asfs_brelse(dir_bh);
++
++ return error;
++}
++
++static int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
++{
++ return asfs_create_object(dir, dentry, mode, it_file, NULL);
++}
++
++static int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ return asfs_create_object(dir, dentry, mode, it_dir, NULL);
++}
++
++static int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
++{
++ return asfs_create_object(dir, dentry, 0, it_link, symname);
++}
++
++static int asfs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ asfs_debug("ASFS: %s\n", __FUNCTION__);
++
++ if (ASFS_I(dentry->d_inode)->firstblock != 0)
++ return -ENOTEMPTY;
++
++ return asfs_unlink(dir, dentry);
++}
++
++static int asfs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ struct inode *inode = dentry->d_inode;
++ int error;
++ struct super_block *sb = dir->i_sb;
++ struct buffer_head *bh, *dir_bh;
++ struct fsObject *dir_obj, *obj;
++
++ asfs_debug("ASFS: %s\n", __FUNCTION__);
++
++ lock_super(sb);
++
++ if ((error = asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
++ unlock_super(sb);
++ return error;
++ }
++ if ((error = asfs_deleteobject(sb, bh, obj)) != 0) {
++ asfs_brelse(bh);
++ unlock_super(sb);
++ return error;
++ }
++ asfs_brelse(bh);
++
++ /* directory data could change after removing the object */
++ if ((error = asfs_readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) {
++ unlock_super(sb);
++ return error;
++ }
++
++ asfs_sync_dir_inode(dir, dir_obj);
++ asfs_bstore(sb, dir_bh);
++
++ dec_count(inode);
++ unlock_super(sb);
++ asfs_brelse(dir_bh);
++
++ return 0;
++}
++
++static int asfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
++{
++ struct super_block *sb = old_dir->i_sb;
++ struct buffer_head *src_bh, *old_bh, *new_bh;
++ int error;
++ struct fsObject *src_obj, *old_obj, *new_obj;
++ u8 bufname[ASFS_MAXFN_BUF];
++
++ asfs_debug("ASFS: rename (old=%u,\"%*s\" to new=%u,\"%*s\")\n",
++ (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
++ (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
++
++ asfs_translate(bufname, (u8 *) new_dentry->d_name.name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
++ if ((error = asfs_check_name(bufname, strlen(bufname))) != 0)
++ return error;
++
++
++ /* Unlink destination if it already exists */
++ if (new_dentry->d_inode)
++ if ((error = asfs_unlink(new_dir, new_dentry)) != 0)
++ return error;
++
++ lock_super(sb);
++
++ if ((error = asfs_readobject(sb, old_dentry->d_inode->i_ino, &src_bh, &src_obj)) != 0) {
++ unlock_super(sb);
++ return error;
++ }
++ if ((error = asfs_readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) {
++ asfs_brelse(src_bh);
++ unlock_super(sb);
++ return error;
++ }
++
++ if ((error = asfs_renameobject(sb, src_bh, src_obj, new_bh, new_obj, bufname)) != 0) {
++ asfs_brelse(src_bh);
++ asfs_brelse(new_bh);
++ unlock_super(sb);
++ return error;
++ }
++ asfs_brelse(src_bh);
++ asfs_brelse(new_bh);
++
++ if ((error = asfs_readobject(sb, old_dir->i_ino, &old_bh, &old_obj)) != 0) {
++ unlock_super(sb);
++ return error;
++ }
++ if ((error = asfs_readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) {
++ asfs_brelse(old_bh);
++ unlock_super(sb);
++ return error;
++ }
++
++ asfs_sync_dir_inode(old_dir, old_obj);
++ asfs_sync_dir_inode(new_dir, new_obj);
++
++ asfs_bstore(sb, new_bh);
++ asfs_bstore(sb, old_bh);
++
++ unlock_super(sb);
++ asfs_brelse(old_bh);
++ asfs_brelse(new_bh);
++
++ mark_inode_dirty(old_dir);
++ mark_inode_dirty(new_dir);
++
++ return 0;
++}
++
++/*
++int asfs_notify_change(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++
++ asfs_debug("ASFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
++
++ error = inode_change_ok(inode,attr);
++
++ return error;
++}
++*/
++#endif
+diff -urN linux-2.6.18/fs/asfs/Makefile linux-2.6.18-asfs-1.0b11/fs/asfs/Makefile
+--- linux-2.6.18/fs/asfs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/Makefile 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,8 @@
++#
++# Makefile for the linux asfs filesystem routines.
++#
++
++obj-$(CONFIG_ASFS_FS) += asfs.o
++
++asfs-y += dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o
++asfs-$(CONFIG_ASFS_RW) += adminspace.o bitfuncs.o
+diff -urN linux-2.6.18/fs/asfs/namei.c linux-2.6.18-asfs-1.0b11/fs/asfs/namei.c
+--- linux-2.6.18/fs/asfs/namei.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/namei.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta10
++ *
++ * Copyright (C) 2003,2004,2005 Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ *
++ * 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/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/string.h>
++#include <linux/nls.h>
++#include "asfs_fs.h"
++
++static inline u8 asfs_upperchar(u8 c)
++{
++ if ((c >= 224 && c <= 254 && c != 247) || (c >= 'a' && c <= 'z'))
++ c -= 32;
++ return (c);
++}
++
++u8 asfs_lowerchar(u8 c)
++{
++ if ((c >= 192 && c <= 222 && c != 215) || (c >= 'A' && c <= 'Z'))
++ c += 32;
++ return (c);
++}
++
++static inline u8 asfs_nls_upperchar(u8 c, struct nls_table *t)
++{
++ if (t) {
++ u8 nc = t->charset2upper[c];
++ return nc ? nc : c;
++ } else
++ return asfs_upperchar(c);
++}
++
++/* Check if the name is valid for a asfs object. */
++
++inline int asfs_check_name(const u8 *name, int len)
++{
++ int i;
++
++ if (len > ASFS_MAXFN)
++ return -ENAMETOOLONG;
++
++ for (i = 0; i < len; i++)
++ if (name[i] < ' ' || name[i] == ':' || (name[i] > 0x7e && name[i] < 0xa0))
++ return -EINVAL;
++
++ return 0;
++}
++
++/* Note: the dentry argument is the parent dentry. */
++
++static int asfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
++{
++ struct super_block *sb = dentry->d_inode->i_sb;
++ const u8 *name = qstr->name;
++ unsigned long hash;
++ int i;
++ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
++
++ i = asfs_check_name(qstr->name,qstr->len);
++ if (i)
++ return i;
++
++ hash = init_name_hash();
++
++ if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE)
++ for (i=qstr->len; i > 0; name++, i--)
++ hash = partial_name_hash(*name, hash);
++ else
++ for (i=qstr->len; i > 0; name++, i--)
++ hash = partial_name_hash(asfs_nls_upperchar(*name, nls_io), hash);
++
++ qstr->hash = end_name_hash(hash);
++
++ return 0;
++}
++
++static int asfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
++{
++ struct super_block *sb = dentry->d_inode->i_sb;
++ const u8 *aname = a->name;
++ const u8 *bname = b->name;
++ int len;
++ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
++
++ /* 'a' is the qstr of an already existing dentry, so the name
++ * must be valid. 'b' must be validated first.
++ */
++
++ if (asfs_check_name(b->name,b->len))
++ return 1;
++
++ if (a->len != b->len)
++ return 1;
++
++ if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) {
++ for (len=a->len; len > 0; len--)
++ if (*aname++ != *bname++)
++ return 1;
++ } else {
++ for (len=a->len; len > 0; len--)
++ if (asfs_nls_upperchar(*aname++, nls_io) != asfs_nls_upperchar(*bname++, nls_io))
++ return 1;
++ }
++
++ return 0;
++}
++
++struct dentry_operations asfs_dentry_operations = {
++ d_hash: asfs_hash_dentry,
++ d_compare: asfs_compare_dentry,
++};
++
++int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t)
++{
++ if (casesensitive) {
++ while (*s == *ct && *ct != '\0' && *ct != '/') {
++ s++;
++ ct++;
++ }
++ } else {
++ while (asfs_nls_upperchar(*s, t) == asfs_nls_upperchar(*ct, t) && *ct != '\0'
++ && *ct != '/') {
++ s++;
++ ct++;
++ }
++ }
++ return (*s == '\0' && (*ct == '\0' || *ct == '/')) ? 0 : *ct - *s;
++}
++
++u16 asfs_hash(u8 *name, int casesensitive)
++{
++ u16 hashval = 0;
++ while (name[hashval] != 0 && name[hashval] != '/')
++ hashval++;
++ if (casesensitive) {
++ u8 c = *name;
++ while (c != 0 && c != '/') {
++ hashval = hashval * 13 + c;
++ c = *++name;
++ }
++ } else {
++ u8 c = *name;
++ while (c != 0 && c != '/') {
++ hashval = hashval * 13 + asfs_upperchar(c);
++ c = *++name;
++ }
++ }
++ return hashval;
++}
++
++void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit)
++{
++ wchar_t uni;
++ int i, len;
++ int from_len, to_len = limit;
++
++ if (nls_to) {
++ from_len = strlen(from);
++ for (i=0; i < from_len && to_len > 1; ) {
++ len = nls_from->char2uni(&from[i], from_len-i, &uni);
++ if (len > 0) {
++ i += len;
++ len = nls_to->uni2char(uni, to, to_len);
++ if (len > 0) {
++ to += len;
++ to_len -= len;
++ }
++ } else
++ i++;
++ if (len < 0) {
++ *to++ = '?';
++ to_len--;
++ }
++ }
++ *to = '\0';
++ } else {
++ strncpy (to, from, limit);
++ to[limit-1] = '\0';
++ }
++}
+diff -urN linux-2.6.18/fs/asfs/nodes.c linux-2.6.18-asfs-1.0b11/fs/asfs/nodes.c
+--- linux-2.6.18/fs/asfs/nodes.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/nodes.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,455 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta7
++ *
++ * This file contains some parts of the original amiga version of
++ * SmartFilesystem source code.
++ *
++ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
++ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
++ *
++ * Adapted and modified by Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++
++/* Finds a specific node by number. */
++int asfs_getnode(struct super_block *sb, u32 nodeno, struct buffer_head **ret_bh, struct fsObjectNode **ret_node)
++{
++ struct buffer_head *bh;
++ struct fsNodeContainer *nodecont;
++ u32 nodeindex = ASFS_SB(sb)->objectnoderoot;
++
++ while ((bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) {
++ nodecont = (struct fsNodeContainer *) bh->b_data;
++
++ if (be32_to_cpu(nodecont->nodes) == 1) {
++ *ret_node = (struct fsObjectNode *) ((u8 *) nodecont->node + NODE_STRUCT_SIZE * (nodeno - be32_to_cpu(nodecont->nodenumber)));
++ *ret_bh = bh;
++ return 0;
++ } else {
++ u16 containerentry = (nodeno - be32_to_cpu(nodecont->nodenumber)) / be32_to_cpu(nodecont->nodes);
++ nodeindex = be32_to_cpu(nodecont->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
++ }
++ asfs_brelse(bh);
++ }
++ if (bh == NULL)
++ return -EIO;
++ return -ENOENT;
++}
++
++#ifdef CONFIG_ASFS_RW
++
++ /* Looks for the parent of the passed-in buffer_head (fsNodeContainer)
++ starting from the root. It returns an error if any error occured.
++ If error is 0 and io_bh is NULL as well, then there was no parent (ie,
++ you asked parent of the root). Otherwise io_bh should contain the
++ parent of the passed-in NodeContainer. */
++
++static int parentnodecontainer(struct super_block *sb, struct buffer_head **io_bh)
++{
++ u32 noderoot = ASFS_SB(sb)->objectnoderoot;
++ u32 childblock = be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock);
++ u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (*io_bh)->b_data)->nodenumber);
++ int errorcode = 0;
++
++ if (noderoot == childblock) {
++ *io_bh = NULL;
++ return 0;
++ }
++
++ while ((*io_bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) {
++ struct fsNodeContainer *nc = (void *) (*io_bh)->b_data;
++
++ if (be32_to_cpu(nc->nodes) == 1) {
++ /* We've descended the tree to a leaf NodeContainer, something
++ which should never happen if the passed-in io_bh had
++ contained a valid fsNodeContainer. */
++ printk("ASFS: Failed to locate the parent NodeContainer - node tree is corrupted!\n");
++ *io_bh = NULL;
++ return -EIO;
++ } else {
++ u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
++ noderoot = be32_to_cpu(nc->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
++ }
++
++ if (noderoot == childblock)
++ break;
++
++ asfs_brelse(*io_bh);
++ }
++
++ if (*io_bh == NULL)
++ return -EIO;
++
++ return errorcode;
++}
++
++
++static int isfull(struct super_block *sb, struct fsNodeContainer *nc)
++{
++ u32 *p = nc->node;
++ s16 n = NODECONT_BLOCK_COUNT;
++
++ while (--n >= 0) {
++ if (*p == 0 || (be32_to_cpu(*p) & 0x00000001) == 0) {
++ break;
++ }
++ p++;
++ }
++
++ return n < 0;
++}
++
++static int markparentfull(struct super_block *sb, struct buffer_head *bh)
++{
++ u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (bh->b_data))->nodenumber);
++ int errorcode;
++
++ if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) {
++ struct fsNodeContainer *nc = (void *) bh->b_data;
++ u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
++
++ nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) | 0x00000001);
++
++ asfs_bstore(sb, bh);
++
++ if (isfull(sb, nc)) { /* This container now is full as well! Mark the next higher up container too then! */
++ return markparentfull(sb, bh);
++ }
++ asfs_brelse(bh);
++ }
++
++ return errorcode;
++}
++
++static int addnewnodelevel(struct super_block *sb, u16 nodesize)
++{
++ struct buffer_head *bh;
++ u32 noderoot = ASFS_SB(sb)->objectnoderoot;
++ int errorcode;
++
++ /* Adds a new level to the Node tree. */
++
++ asfs_debug("addnewnodelevel: Entry\n");
++
++ if ((bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) {
++ struct buffer_head *newbh;
++ u32 newblock;
++
++ if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (newbh = asfs_getzeroblk(sb, newblock))) {
++ struct fsNodeContainer *nc = (void *) bh->b_data;
++ struct fsNodeContainer *newnc = (void *) newbh->b_data;
++
++ /* The newly allocated block will become a copy of the current root. */
++
++ newnc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID);
++ newnc->bheader.ownblock = cpu_to_be32(newblock);
++ newnc->nodenumber = nc->nodenumber;
++ newnc->nodes = nc->nodes;
++ memcpy(newnc->node, nc->node, sb->s_blocksize - sizeof(struct fsNodeContainer));
++
++ asfs_bstore(sb, newbh);
++ asfs_brelse(newbh);
++
++ /* The current root will now be transformed into a new root. */
++
++ if (be32_to_cpu(nc->nodes) == 1)
++ nc->nodes = cpu_to_be32((sb->s_blocksize - sizeof(struct fsNodeContainer)) / nodesize);
++ else
++ nc->nodes = cpu_to_be32(be32_to_cpu(nc->nodes) * NODECONT_BLOCK_COUNT);
++
++ nc->node[0] = cpu_to_be32((newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY)) + 1); /* Tree is full from that point! */
++ memset(&nc->node[1], 0, sb->s_blocksize - sizeof(struct fsNodeContainer) - 4);
++
++ asfs_bstore(sb, bh);
++ }
++ asfs_brelse(bh);
++ } else
++ errorcode = -EIO;
++
++ return errorcode;
++}
++
++static int createnodecontainer(struct super_block *sb, u32 nodenumber, u32 nodes, u32 * returned_block)
++{
++ struct buffer_head *bh;
++ int errorcode;
++ u32 newblock;
++
++ asfs_debug("createnodecontainer: nodenumber = %u, nodes = %u\n", nodenumber, nodes);
++
++ if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (bh = asfs_getzeroblk(sb, newblock))) {
++ struct fsNodeContainer *nc = (void *) bh->b_data;
++
++ nc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID);
++ nc->bheader.ownblock = cpu_to_be32(newblock);
++
++ nc->nodenumber = cpu_to_be32(nodenumber);
++ nc->nodes = cpu_to_be32(nodes);
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ *returned_block = newblock;
++ }
++
++ return errorcode;
++}
++
++ /* This function creates a new fsNode structure in a fsNodeContainer. If needed
++ it will create a new fsNodeContainers and a new fsNodeIndexContainer. */
++
++int asfs_createnode(struct super_block *sb, struct buffer_head **returned_bh, struct fsNode **returned_node, u32 * returned_nodeno)
++{
++ u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE;
++ u32 noderoot = ASFS_SB(sb)->objectnoderoot;
++ u32 nodeindex = noderoot;
++ int errorcode = 0;
++
++ while ((*returned_bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) {
++ struct fsNodeContainer *nc = (void *) (*returned_bh)->b_data;
++
++ if (be32_to_cpu(nc->nodes) == 1) { /* Is it a leaf-container? */
++ struct fsNode *n;
++ s16 i = nodecount;
++
++ n = (struct fsNode *) nc->node;
++
++ while (i-- > 0) {
++ if (n->data == 0)
++ break;
++
++ n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
++ }
++
++ if (i >= 0) {
++ /* Found an empty fsNode structure! */
++ *returned_node = n;
++ *returned_nodeno = be32_to_cpu(nc->nodenumber) + ((u8 *) n - (u8 *) nc->node) / NODE_STRUCT_SIZE;
++
++ asfs_debug("createnode: Created Node %d\n", *returned_nodeno);
++
++ /* Below we continue to look through the NodeContainer block. We skip the entry
++ we found to be unused, and see if there are any more unused entries. If we
++ do not find any more unused entries then this container is now full. */
++
++ n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
++
++ while (i-- > 0) {
++ if (n->data == 0)
++ break;
++
++ n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
++ }
++
++ if (i < 0) {
++ /* No more empty fsNode structures in this block. Mark parent full. */
++ errorcode = markparentfull(sb, *returned_bh);
++ }
++
++ return errorcode;
++ } else {
++ /* What happened now is that we found a leaf-container which was
++ completely filled. In practice this should only happen when there
++ is only a single NodeContainer (only this container), or when there
++ was an error in one of the full-bits in a higher level container. */
++
++ if (noderoot != nodeindex) {
++ /*** Hmmm... it looks like there was a damaged full-bit or something.
++ In this case we'd probably better call markcontainerfull. */
++
++ printk("ASFS: Couldn't find empty Node in NodeContainer while NodeIndexContainer indicated there should be one!\n");
++
++ errorcode = -ENOSPC;
++ break;
++ } else {
++ /* Container is completely filled. */
++
++ if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0)
++ return errorcode;
++
++ nodeindex = noderoot;
++ }
++ }
++ } else { /* This isn't a leaf container */
++ u32 *p = nc->node;
++ s16 i = NODECONT_BLOCK_COUNT;
++
++ /* We've read a normal container */
++
++ while (i-- > 0) {
++ if (*p != 0 && (be32_to_cpu(*p) & 0x00000001) == 0)
++ break;
++
++ p++;
++ }
++
++ if (i >= 0) {
++ /* Found a not completely filled Container */
++
++ nodeindex = be32_to_cpu(*p) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
++ } else {
++ /* Everything in the NodeIndexContainer was completely filled. There possibly
++ are some unused pointers in this block however. */
++
++ asfs_debug("createnode: NodeContainer at block has no empty Nodes.\n");
++
++ p = nc->node;
++ i = NODECONT_BLOCK_COUNT;
++
++ while (i-- > 0) {
++ if (*p == 0)
++ break;
++
++ p++;
++ }
++
++ if (i >= 0) {
++ u32 newblock;
++ u32 nodes;
++
++ /* Found an unused Container pointer */
++
++ if (be32_to_cpu(nc->nodes) == (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE) {
++ nodes = 1;
++ } else {
++ nodes = be32_to_cpu(nc->nodes) / NODECONT_BLOCK_COUNT;
++ }
++
++ if ((errorcode = createnodecontainer(sb, be32_to_cpu(nc->nodenumber) + (p - nc->node) * be32_to_cpu(nc->nodes), nodes, &newblock)) != 0) {
++ break;
++ }
++
++ *p = cpu_to_be32(newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY));
++
++ asfs_bstore(sb, *returned_bh);
++ } else {
++ /* Container is completely filled. This must be the top-level NodeIndex container
++ as otherwise the full-bit would have been wrong! */
++
++ if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0)
++ break;
++
++ nodeindex = noderoot;
++ }
++ }
++ }
++ asfs_brelse(*returned_bh);
++ }
++
++ if (*returned_bh == NULL)
++ return -EIO;
++
++ return (errorcode);
++}
++
++static int markparentempty(struct super_block *sb, struct buffer_head *bh)
++{
++ u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber);
++ int errorcode;
++
++ if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) {
++ struct fsNodeContainer *nc = (void *) bh->b_data;
++ int wasfull;
++ u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
++
++ wasfull = isfull(sb, nc);
++
++ nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) & ~0x00000001);
++
++ asfs_bstore(sb, bh);
++
++ if (wasfull) {
++ /* This container was completely full before! Mark the next higher up container too then! */
++ return markparentempty(sb, bh);
++ }
++ asfs_brelse(bh);
++ }
++
++ return errorcode;
++}
++
++static int freecontainer(struct super_block *sb, struct buffer_head *bh)
++{
++ u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber);
++ int errorcode;
++
++ if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != NULL) { /* This line also prevents the freeing of the noderoot. */
++ struct fsNodeContainer *nc = (void *) bh->b_data;
++ u16 containerindex = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
++
++ if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(nc->node[containerindex]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY))) == 0) {
++ u32 *p = nc->node;
++ s16 n = NODECONT_BLOCK_COUNT;
++
++ nc->node[containerindex] = 0;
++ asfs_bstore(sb, bh);
++
++ while (n-- > 0)
++ if (*p++ != 0)
++ break;
++
++ if (n < 0) { /* This container is now completely empty! Free this NodeIndexContainer too then! */
++ return freecontainer(sb, bh);
++ }
++ }
++ asfs_brelse(bh);
++ }
++
++ return errorcode;
++}
++
++static int internaldeletenode(struct super_block *sb, struct buffer_head *bh, struct fsNode *n)
++{
++ struct fsNodeContainer *nc = (void *) bh->b_data;
++ u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE;
++ s16 i = nodecount;
++ s16 empty = 0;
++ int errorcode = 0;
++
++ n->data = 0;
++ n = (struct fsNode *) nc->node;
++
++ while (i-- > 0) {
++ if (n->data == 0)
++ empty++;
++
++ n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
++ }
++
++ asfs_bstore(sb, bh);
++
++ if (empty == 1) /* NodeContainer was completely full before, so we need to mark it empty now. */
++ errorcode = markparentempty(sb, bh);
++ else if (empty == nodecount) /* NodeContainer is now completely empty! Free it! */
++ errorcode = freecontainer(sb, bh);
++
++ return (errorcode);
++}
++
++int asfs_deletenode(struct super_block *sb, u32 objectnode)
++{
++ struct buffer_head *bh;
++ struct fsObjectNode *on;
++ int errorcode;
++
++ asfs_debug("deletenode: Deleting Node %d\n", objectnode);
++
++ if ((errorcode = asfs_getnode(sb, objectnode, &bh, &on)) == 0)
++ errorcode = internaldeletenode(sb, bh, (struct fsNode *) on);
++
++ asfs_brelse(bh);
++ return (errorcode);
++}
++
++#endif
+diff -urN linux-2.6.18/fs/asfs/objects.c linux-2.6.18-asfs-1.0b11/fs/asfs/objects.c
+--- linux-2.6.18/fs/asfs/objects.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/objects.c 2006-09-22 23:22:42.000000000 +0200
+@@ -0,0 +1,765 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta11
++ *
++ * This file contains some parts of the original amiga version of
++ * SmartFilesystem source code.
++ *
++ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
++ * Ralph Schmidt, Emmanuel Lesueur, David Gerber, and Marcin Kurek
++ *
++ * Adapted and modified by Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++
++struct fsObject *asfs_nextobject(struct fsObject *obj)
++{
++ int i;
++ u8 *p = obj->name;
++
++ for (i = 2; i > 0; p++)
++ if (*p == '\0')
++ i--;
++ if ((p - (u8 *) obj) & 0x01)
++ p++;
++
++ return ((struct fsObject *) p);
++}
++
++struct fsObject *asfs_find_obj_by_name(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
++{
++ struct fsObject *obj;
++
++ obj = &(objcont->object[0]);
++ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
++ if (asfs_namecmp(obj->name, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, NULL) == 0) {
++ asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
++ return obj;
++ }
++ obj = asfs_nextobject(obj);
++ }
++ return NULL;
++}
++
++#ifdef CONFIG_ASFS_RW
++
++static struct fsObject *find_obj_by_node(struct super_block *sb, struct fsObjectContainer *objcont, u32 objnode)
++{
++ struct fsObject *obj;
++
++ obj = &(objcont->object[0]);
++ while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
++ if (be32_to_cpu(obj->objectnode) == objnode) {
++ return obj;
++ }
++ obj = asfs_nextobject(obj);
++ }
++ return NULL;
++}
++
++int asfs_readobject(struct super_block *sb, u32 objectnode, struct buffer_head **bh, struct fsObject **returned_object)
++{
++ struct fsObjectNode *on;
++ int errorcode;
++ u32 contblock;
++
++ asfs_debug("Seaching object - node %d\n", objectnode);
++
++ if ((errorcode = asfs_getnode(sb, objectnode, bh, &on)) != 0)
++ return errorcode;
++ contblock = be32_to_cpu(on->node.data);
++ asfs_brelse(*bh);
++
++ if (contblock > 0 && (*bh = asfs_breadcheck(sb, contblock, ASFS_OBJECTCONTAINER_ID))) {
++ *returned_object = find_obj_by_node(sb, (void *) (*bh)->b_data, objectnode);
++ if (*returned_object == NULL) {
++ brelse(*bh);
++ *bh = NULL;
++ return -ENOENT;
++ }
++ return 0;
++ } else
++ return -EIO;
++}
++
++static int removeobjectcontainer(struct super_block *sb, struct buffer_head *bh)
++{
++ struct fsObjectContainer *oc = (void *) bh->b_data;
++ int errorcode;
++ struct buffer_head *block;
++
++ asfs_debug("removeobjectcontainer: block %u\n", be32_to_cpu(oc->bheader.ownblock));
++
++ if (oc->next != 0 && oc->next != oc->bheader.ownblock) {
++ struct fsObjectContainer *next_oc;
++
++ if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID)) == NULL)
++ return -EIO;
++
++ next_oc = (void *) block->b_data;
++ next_oc->previous = oc->previous;
++
++ asfs_bstore(sb, block);
++ asfs_brelse(block);
++ }
++
++ if (oc->previous != 0 && oc->previous != oc->bheader.ownblock) {
++ struct fsObjectContainer *previous_oc;
++
++ if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->previous), ASFS_OBJECTCONTAINER_ID)) == NULL)
++ return -EIO;
++
++ previous_oc = (void *) block->b_data;
++ previous_oc->next = oc->next;
++
++ asfs_bstore(sb, block);
++ asfs_brelse(block);
++ } else {
++ struct fsObject *parent_o;
++
++ if ((errorcode = asfs_readobject(sb, be32_to_cpu(oc->parent), &block, &parent_o)) != 0)
++ return (errorcode);
++
++ parent_o->object.dir.firstdirblock = oc->next;
++
++ asfs_bstore(sb, block);
++ asfs_brelse(block);
++ }
++
++ if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(oc->bheader.ownblock))) != 0)
++ return (errorcode);
++
++ return (0);
++}
++
++static int setrecycledinfodiff(struct super_block *sb, s32 deletedfiles, s32 deletedblocks)
++{
++ struct buffer_head *bh;
++
++ if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
++ struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
++
++ ri->deletedfiles = cpu_to_be32(be32_to_cpu(ri->deletedfiles) + deletedfiles);
++ ri->deletedblocks = cpu_to_be32(be32_to_cpu(ri->deletedblocks) + deletedblocks);
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++ } else
++ return -EIO;
++ return 0;
++}
++
++ /* This function removes the fsObject structure passed in from the passed
++ buffer_head. If the ObjectContainer becomes completely empty it will be
++ delinked from the ObjectContainer chain and marked free for reuse.
++ This function doesn't delink the object from the hashchain! */
++
++static int simpleremoveobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
++{
++ struct fsObjectContainer *oc = (void *) bh->b_data;
++ int errorcode = 0;
++
++ asfs_debug("simpleremoveobject:\n");
++
++ if (be32_to_cpu(oc->parent) == ASFS_RECYCLEDNODE) {
++ /* This object is removed from the Recycled directory. */
++ if ((errorcode = setrecycledinfodiff(sb, -1, -((be32_to_cpu(o->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits))) != 0)
++ return errorcode;
++ }
++
++ if ((asfs_nextobject(oc->object))->name[0] == '\0')
++ errorcode = removeobjectcontainer(sb, bh);
++ else {
++ struct fsObject *nexto;
++ int objlen;
++
++ nexto = asfs_nextobject(o);
++ objlen = (u8 *) nexto - (u8 *) o;
++
++ memmove(o, nexto, sb->s_blocksize - ((u8 *) nexto - (u8 *) oc));
++ memset((u8 *) oc + sb->s_blocksize - objlen, 0, objlen);
++
++ asfs_bstore(sb, bh);
++ }
++ return errorcode;
++}
++
++/* This function delinks the passed in ObjectNode from its hash-chain. Handy when deleting
++ the object, or when renaming/moving it. */
++
++static int dehashobjectquick(struct super_block *sb, u32 objectnode, u8 *name, u32 parentobjectnode)
++{
++ struct fsObject *o;
++ int errorcode = 0;
++ struct buffer_head *block;
++
++ asfs_debug("dehashobject: Delinking object %d (=ObjectNode) from hashchain. Parentnode = %d\n", objectnode, parentobjectnode);
++
++ if ((errorcode = asfs_readobject(sb, parentobjectnode, &block, &o)) == 0 && o->object.dir.hashtable != 0) {
++ u32 hashtable = be32_to_cpu(o->object.dir.hashtable);
++ asfs_brelse(block);
++
++ if ((block = asfs_breadcheck(sb, hashtable, ASFS_HASHTABLE_ID))) {
++ struct buffer_head *node_bh;
++ struct fsObjectNode *onptr, on;
++ struct fsHashTable *ht = (void *) block->b_data;
++ u32 nexthash;
++
++ if ((errorcode = asfs_getnode(sb, objectnode, &node_bh, &onptr)) == 0) {
++ u16 hashchain;
++
++ asfs_debug("dehashobject: Read HashTable block of parent object of object to be delinked\n");
++
++ hashchain = HASHCHAIN(asfs_hash(name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
++ nexthash = be32_to_cpu(ht->hashentry[hashchain]);
++
++ if (nexthash == objectnode) {
++ /* The hashtable directly points to the fsObject to be delinked. We simply
++ modify the Hashtable to point to the new nexthash entry. */
++
++ asfs_debug("dehashobject: The hashtable points directly to the to be delinked object\n");
++
++ ht->hashentry[hashchain] = onptr->next;
++ asfs_bstore(sb, block);
++ } else {
++ struct fsObjectNode *onsearch = 0;
++
++ on = *onptr;
++
++ asfs_debug("dehashobject: Walking through hashchain\n");
++
++ while (nexthash != 0 && nexthash != objectnode) {
++ asfs_brelse(node_bh);
++ if ((errorcode = asfs_getnode(sb, nexthash, &node_bh, &onsearch)) != 0)
++ break;
++ nexthash = be32_to_cpu(onsearch->next);
++ }
++
++ if (errorcode == 0) {
++ if (nexthash != 0) {
++ /* Previous fsObjectNode found in hash chain. Modify the fsObjectNode to 'skip' the
++ ObjectNode which is being delinked from the hash chain. */
++
++ onsearch->next = on.next;
++ asfs_bstore(sb, node_bh);
++ } else {
++ printk("ASFS: Hashchain of object %d is corrupt or incorrectly linked.", objectnode);
++
++ /*** This is strange. We have been looking for the fsObjectNode which is located before the
++ passed in fsObjectNode in the hash-chain. However, we never found the
++ fsObjectNode reffered to in the hash-chain! Has to be somekind
++ of internal error... */
++
++ errorcode = -ENOENT;
++ }
++ }
++ }
++ asfs_brelse(node_bh);
++ }
++ asfs_brelse(block);
++ }
++ }
++ return errorcode;
++}
++
++
++ /* This function removes an object from any directory. It takes care
++ of delinking the object from the hashchain and also frees the
++ objectnode number. */
++
++static int removeobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
++{
++ struct fsObjectContainer *oc = (void *) bh->b_data;
++ int errorcode;
++
++ asfs_debug("removeobject\n");
++
++ if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o->objectnode), o->name, be32_to_cpu(oc->parent))) == 0) {
++ u32 objectnode = be32_to_cpu(o->objectnode);
++
++ if ((errorcode = simpleremoveobject(sb, bh, o)) == 0)
++ errorcode = asfs_deletenode(sb, objectnode);
++ }
++
++ return (errorcode);
++}
++
++ /* This function deletes the specified object. */
++int asfs_deleteobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
++{
++ int errorcode = 0;
++
++ asfs_debug("deleteobject: Entry -- deleting object %d (%s)\n", be32_to_cpu(o->objectnode), o->name);
++
++ if ((o->bits & OTYPE_DIR) == 0 || o->object.dir.firstdirblock == 0) {
++ u8 bits = o->bits;
++ u32 hashblckno = be32_to_cpu(o->object.dir.hashtable);
++ u32 extentbnode = be32_to_cpu(o->object.file.data);
++
++ if ((errorcode = removeobject(sb, bh, o)) == 0) {
++ if ((bits & OTYPE_LINK) != 0) {
++ asfs_debug("deleteobject: Object is soft link!\n");
++ errorcode = asfs_freeadminspace(sb, extentbnode);
++ } else if ((bits & OTYPE_DIR) != 0) {
++ asfs_debug("deleteobject: Object is a directory!\n");
++ errorcode = asfs_freeadminspace(sb, hashblckno);
++ } else {
++ asfs_debug("deleteobject: Object is a file\n");
++ if (extentbnode != 0)
++ errorcode = asfs_deleteextents(sb, extentbnode);
++ }
++ }
++ }
++
++ return (errorcode);
++}
++
++ /* This function takes a HashBlock pointer, an ObjectNode and an ObjectName.
++ If there is a hashblock, then this function will correctly link the object
++ into the hashchain. If there isn't a hashblock (=0) then this function
++ does nothing. */
++
++static int hashobject(struct super_block *sb, u32 hashblock, struct fsObjectNode *on, u32 nodeno, u8 *objectname)
++{
++ struct buffer_head *hash_bh;
++
++ asfs_debug("hashobject, using hashblock %d\n", hashblock);
++ if (hashblock == 0)
++ return 0;
++
++ if ((hash_bh = asfs_breadcheck(sb, hashblock, ASFS_HASHTABLE_ID))) {
++ struct fsHashTable *ht = (void *) hash_bh->b_data;
++ u32 nexthash;
++ u16 hashvalue, hashchain;
++
++ hashvalue = asfs_hash(objectname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE);
++ hashchain = HASHCHAIN(hashvalue);
++ nexthash = be32_to_cpu(ht->hashentry[hashchain]);
++
++ ht->hashentry[hashchain] = cpu_to_be32(nodeno);
++
++ asfs_bstore(sb, hash_bh);
++ asfs_brelse(hash_bh);
++
++ on->next = cpu_to_be32(nexthash);
++ on->hash16 = cpu_to_be16(hashvalue);
++ } else
++ return -EIO;
++
++ return 0;
++}
++
++ /* This function returns a pointer to the first unused byte in
++ an ObjectContainer. */
++
++static u8 *emptyspaceinobjectcontainer(struct super_block *sb, struct fsObjectContainer *oc)
++{
++ struct fsObject *o = oc->object;
++ u8 *endadr;
++
++ endadr = (u8 *) oc + sb->s_blocksize - sizeof(struct fsObject) - 2;
++
++ while ((u8 *) o < endadr && o->name[0] != 0)
++ o = asfs_nextobject(o);
++
++ return (u8 *) o;
++}
++
++ /* This function will look in the directory indicated by io_o
++ for an ObjectContainer block which contains bytesneeded free
++ bytes. If none is found then this function simply creates a
++ new ObjectContainer and adds that to the indicated directory. */
++
++static int findobjectspace(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, u32 bytesneeded)
++{
++ struct buffer_head *bhparent = *io_bh;
++ struct fsObject *oparent = *io_o;
++ struct buffer_head *bh;
++ u32 nextblock = be32_to_cpu(oparent->object.dir.firstdirblock);
++ int errorcode = 0;
++
++ asfs_debug("findobjectspace: Looking for %u bytes in directory with ObjectNode number %d (in block %d)\n", bytesneeded, be32_to_cpu((*io_o)->objectnode),
++ be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
++
++ while (nextblock != 0 && (bh = asfs_breadcheck(sb, nextblock, ASFS_OBJECTCONTAINER_ID))) {
++ struct fsObjectContainer *oc = (void *) bh->b_data;
++ u8 *emptyspace;
++
++ /* We need to find out how much free space this ObjectContainer has */
++
++ emptyspace = emptyspaceinobjectcontainer(sb, oc);
++
++ if ((u8 *) oc + sb->s_blocksize - emptyspace >= bytesneeded) {
++ /* We found enough space in one of the ObjectContainer blocks!!
++ We return a struct fsObject *. */
++ *io_bh = bh;
++ *io_o = (struct fsObject *) emptyspace;
++ break;
++ }
++ nextblock = be32_to_cpu(oc->next);
++ asfs_brelse(bh);
++ }
++
++ if (nextblock == 0) {
++ u32 newcontblock;
++ /* If we get here, we traversed the *entire* directory (ough!) and found no empty
++ space large enough for our entry. We allocate new space and add it to this
++ directory. */
++
++ if ((errorcode = asfs_allocadminspace(sb, &newcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newcontblock))) {
++ struct fsObjectContainer *oc = (void *) bh->b_data;
++ struct buffer_head *bhnext;
++
++ asfs_debug("findobjectspace: No room was found, allocated new block at %u\n", newcontblock);
++
++ /* Allocated new block. We will now link it to the START of the directory chain
++ so the new free space can be found quickly when more entries need to be added. */
++
++ oc->bheader.id = cpu_to_be32(ASFS_OBJECTCONTAINER_ID);
++ oc->bheader.ownblock = cpu_to_be32(newcontblock);
++ oc->parent = oparent->objectnode;
++ oc->next = oparent->object.dir.firstdirblock;
++ oc->previous = 0;
++
++ oparent->object.dir.firstdirblock = cpu_to_be32(newcontblock);
++
++ asfs_bstore(sb, bhparent);
++
++ if (oc->next != 0 && (bhnext = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID))) {
++ struct fsObjectContainer *ocnext = (void *) bhnext->b_data;
++ ocnext->previous = cpu_to_be32(newcontblock);
++ asfs_bstore(sb, bhnext);
++ asfs_brelse(bhnext);
++ }
++
++ *io_bh = bh;
++ *io_o = oc->object;
++ }
++ }
++
++ asfs_debug("findobjectspace: new object will be in container block %u\n", be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
++
++ return (errorcode);
++}
++
++/* io_bh & io_o refer to the direct parent of the new object. Objectname is the
++ name of the new object (name only). Does not realese io_bh !!! */
++
++int asfs_createobject(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, struct fsObject *src_o, u8 *objectname, int force)
++{
++ int errorcode;
++ u32 object_size;
++ u32 hashblock = be32_to_cpu((*io_o)->object.dir.hashtable);
++
++ asfs_debug("createobject: Creating object '%s' in dir '%s'.\n", objectname, (*io_o)->name);
++
++ if (!force && ASFS_SB(sb)->freeblocks < ASFS_ALWAYSFREE)
++ return -ENOSPC;
++
++ if (!force && be32_to_cpu((*io_o)->objectnode) == ASFS_RECYCLEDNODE)
++ return -EINVAL;
++
++ object_size = sizeof(struct fsObject) + strlen(objectname) + 2;
++
++ if ((errorcode = findobjectspace(sb, io_bh, io_o, object_size)) == 0) {
++ struct fsObject *o2 = *io_o;
++ u8 *name = o2->name;
++ u8 *objname = objectname;
++ struct buffer_head *node_bh;
++ struct fsObjectNode *on;
++ u32 nodeno;
++
++ **io_o = *src_o; /* Copying whole object data... */
++
++ while (*objname != 0) /* Copying name */
++ *name++ = *objname++;
++
++ *name++ = 0;
++ *name = 0; /* zero byte for comment */
++
++ if (o2->objectnode != 0) /* ObjectNode reuse or creation */
++ errorcode = asfs_getnode(sb, o2->objectnode, &node_bh, &on);
++ else {
++ if ((errorcode = asfs_createnode(sb, &node_bh, (struct fsNode **) &on, &nodeno)) == 0) {
++ on->hash16 = cpu_to_be16(asfs_hash(o2->name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
++ o2->objectnode = cpu_to_be32(nodeno);
++ }
++ asfs_debug("createnode returned with errorcode: %d\n", errorcode);
++ }
++
++ if (errorcode == 0) { /* in io_bh there is a container with created object */
++ on->node.data = ((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock;
++ if ((errorcode = hashobject(sb, hashblock, on, be32_to_cpu(o2->objectnode), objectname)) == 0) {
++ asfs_bstore(sb, node_bh);
++ asfs_brelse(node_bh);
++ } else
++ errorcode = -EIO;
++ }
++
++ if (errorcode == 0) { /* HashBlock reuse or creation:*/
++
++ if ((o2->bits & OTYPE_DIR) != 0 && o2->object.dir.hashtable == 0) {
++ struct buffer_head *hashbh;
++ u32 hashblock;
++
++ asfs_debug("creating Hashblock\n");
++
++ if ((errorcode = asfs_allocadminspace(sb, &hashblock)) == 0 && (hashbh = asfs_getzeroblk(sb, hashblock))) {
++ struct fsHashTable *ht = (void *) hashbh->b_data;
++
++ o2->object.dir.hashtable = cpu_to_be32(hashblock);
++
++ ht->bheader.id = cpu_to_be32(ASFS_HASHTABLE_ID);
++ ht->bheader.ownblock = cpu_to_be32(hashblock);
++ ht->parent = o2->objectnode;
++
++ asfs_bstore(sb, hashbh);
++ asfs_brelse(hashbh);
++ }
++ }
++ }
++
++ if (errorcode == 0) { /* SoftLink creation: */
++ if ((o2->bits & (OTYPE_LINK | OTYPE_HARDLINK)) == OTYPE_LINK && o2->object.file.data == 0) {
++ struct buffer_head *bh2;
++ u32 slinkblock;
++
++ if ((errorcode = asfs_allocadminspace(sb, &slinkblock)) == 0 && (bh2 = asfs_getzeroblk(sb, slinkblock))) {
++ struct fsSoftLink *sl = (void *) bh2->b_data;
++ o2->object.file.data = cpu_to_be32(slinkblock);
++ sl->bheader.id = cpu_to_be32(ASFS_SOFTLINK_ID);
++ sl->bheader.ownblock = cpu_to_be32(slinkblock);
++ sl->parent = o2->objectnode;
++ sl->next = 0;
++ sl->previous = 0;
++ asfs_bstore(sb, bh2);
++ asfs_brelse(bh2);
++ }
++ }
++ }
++ }
++ asfs_debug("createobject: done.\n");
++
++ return (errorcode);
++}
++
++ /* This function extends the file object 'o' with a number of blocks
++ (hopefully, if any blocks has been found!). Only new Extents will
++ be created -- the size of the file will not be altered, and changing
++ it is left up to the caller. If the file did not have any blocks
++ yet, then the o->object.file.data will be set to the first (new)
++ ExtentBNode. It returns the number of added blocks through
++ addedblocks pointer */
++
++int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objbh, struct fsObject *o, u32 blocks, u32 * newspace, u32 * addedblocks)
++{
++ u32 lastextentbnode;
++ int errorcode = 0;
++ struct fsExtentBNode *ebnp;
++ struct buffer_head *block = NULL;
++
++
++ asfs_debug("extendblocksinfile: Trying to increasing number of blocks by %d.\n", blocks);
++
++ lastextentbnode = be32_to_cpu(o->object.file.data);
++
++ if (lastextentbnode != 0) {
++ while (lastextentbnode != 0 && errorcode == 0) {
++ if (block != NULL)
++ asfs_brelse(block);
++ errorcode = asfs_getextent(sb, lastextentbnode, &block, &ebnp);
++ lastextentbnode = be32_to_cpu(ebnp->next);
++ }
++ lastextentbnode = be32_to_cpu(ebnp->key);
++ }
++
++ if (errorcode == 0) {
++ u32 searchstart;
++
++ u32 found_block;
++ u32 found_blocks;
++
++ *addedblocks = 0;
++ *newspace = 0;
++
++ if (lastextentbnode != 0)
++ searchstart = be32_to_cpu(ebnp->key) + be16_to_cpu(ebnp->blocks);
++ else
++ searchstart = 0; //ASFS_SB(sb)->block_rovingblockptr;
++
++ if ((errorcode = asfs_findspace(sb, blocks, searchstart, searchstart, &found_block, &found_blocks)) != 0) {
++ asfs_brelse(block);
++ asfs_debug("extendblocksinfile: findspace returned %s\n", errorcode == -ENOSPC ? "ENOSPC" : "error");
++ return errorcode;
++ }
++
++ blocks = found_blocks;
++ errorcode = asfs_markspace(sb, found_block, found_blocks);
++ *addedblocks = found_blocks;
++ *newspace = found_block;
++
++ asfs_debug("extendblocksinfile: block = %u, lastextentbnode = %u, extentblocks = %d\n", found_block, lastextentbnode, blocks);
++
++ if ((errorcode = asfs_addblocks(sb, blocks, found_block, be32_to_cpu(o->objectnode), &lastextentbnode)) != 0) {
++ asfs_debug("extendblocksinfile: addblocks returned errorcode %d\n", errorcode);
++ return errorcode;
++ }
++
++ if (o->object.file.data == 0)
++ o->object.file.data = cpu_to_be32(lastextentbnode);
++ }
++
++ if (block)
++ asfs_brelse(block);
++ asfs_bstore(sb, objbh);
++
++ asfs_debug("addblockstofile: done. added %d blocks\n", *addedblocks);
++
++ return errorcode;
++}
++
++ /* The Object indicated by bh1 & o1, gets renamed to newname and placed
++ in the directory indicated by bhparent & oparent. */
++
++int asfs_renameobject(struct super_block *sb, struct buffer_head *bh1, struct fsObject *o1, struct buffer_head *bhparent, struct fsObject *oparent, u8 * newname)
++{
++ struct fsObject object;
++ u32 oldparentnode = be32_to_cpu(((struct fsObjectContainer *) bh1->b_data)->parent);
++ u8 oldname[107];
++ int errorcode;
++
++ asfs_debug("renameobject: Renaming '%s' to '%s' in dir '%s'\n", o1->name, newname, oparent->name);
++
++ object = *o1;
++ strcpy(oldname, o1->name);
++
++ if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o1->objectnode), o1->name, oldparentnode)) == 0) {
++ u32 parentobjectnode = be32_to_cpu(oparent->objectnode);
++
++ if ((errorcode = simpleremoveobject(sb, bh1, o1)) == 0) {
++ struct buffer_head *bh2 = bhparent;
++ struct fsObject *o2;
++
++ /* oparent might changed after simpleremoveobject */
++ oparent = o2 = find_obj_by_node(sb, (struct fsObjectContainer *) bhparent->b_data, parentobjectnode);
++
++ /* In goes the Parent bh & o, out comes the New object's bh & o :-) */
++ if ((errorcode = asfs_createobject(sb, &bh2, &o2, &object, newname, TRUE)) == 0) {
++ asfs_bstore(sb, bh2);
++ if (be32_to_cpu(oparent->objectnode) == ASFS_RECYCLEDNODE) {
++ asfs_debug("renameobject: Updating recycled dir info\n");
++ if ((errorcode = setrecycledinfodiff(sb, 1, (be32_to_cpu(o2->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits)) != 0) {
++ brelse(bh2);
++ return errorcode;
++ }
++ }
++ brelse(bh2);
++ asfs_debug("renameobject: Succesfully created & stored new object.\n");
++ } else { /* recreate object in old place, maybe this will not fail, but who knows... */
++ asfs_debug("renameobject: Creating new object failed. Trying to recreate it in source directory.\n");
++ if (asfs_readobject(sb, oldparentnode, &bh1, &o1) == 0) {
++ struct buffer_head *bh2 = bh1;
++ if (asfs_createobject(sb, &bh2, &o1, &object, oldname, TRUE) == 0) {
++ asfs_bstore(sb, bh2);
++ if (oldparentnode == ASFS_RECYCLEDNODE) {
++ asfs_debug("renameobject: Updating recycled dir info\n");
++ setrecycledinfodiff(sb, 1, (be32_to_cpu(o1->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits);
++ }
++ brelse(bh2);
++ }
++ brelse(bh1);
++ }
++ }
++ }
++ }
++ return errorcode;
++}
++
++ /* Truncates the specified file to /newsize/ bytes */
++
++int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh, struct fsObject *o, u32 newsize)
++{
++ struct buffer_head *ebh;
++ struct fsExtentBNode *ebn;
++ int errorcode;
++ u32 pos = 0;
++ u32 newblocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
++ u32 filedata = be32_to_cpu(o->object.file.data);
++ u32 eprev, ekey;
++ u16 eblocks;
++
++ asfs_debug("trucateblocksinfile: newsize %u\n", newsize);
++
++ if (filedata == 0)
++ return 0;
++
++ for (;;) {
++ if ((errorcode = asfs_getextent(sb, filedata, &ebh, &ebn)) != 0)
++ return errorcode;
++ if (pos + be16_to_cpu(ebn->blocks) >= newblocks)
++ break;
++ pos += be16_to_cpu(ebn->blocks);
++ if ((filedata = be32_to_cpu(ebn->next)) == 0)
++ break;
++ asfs_brelse(ebh);
++ };
++
++ eblocks = newblocks - pos;
++ ekey = be32_to_cpu(ebn->key);
++ eprev = be32_to_cpu(ebn->prev);
++
++ if (be16_to_cpu(ebn->blocks) < eblocks) {
++ printk("ASFS: Extent chain is too short or damaged!\n");
++ asfs_brelse(ebh);
++ return -ENOENT;
++ }
++ if (be16_to_cpu(ebn->blocks) - eblocks > 0 && (errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key) + eblocks, be16_to_cpu(ebn->blocks) - eblocks)) != 0) {
++ asfs_brelse(ebh);
++ return errorcode;
++ }
++ if (be32_to_cpu(ebn->next) > 0 && (errorcode = asfs_deleteextents(sb, be32_to_cpu(ebn->next))) != 0) {
++ asfs_brelse(ebh);
++ return errorcode;
++ }
++ ebn->blocks = cpu_to_be16(eblocks);
++ ebn->next = 0;
++ asfs_bstore(sb, ebh);
++
++ if (eblocks == 0) {
++ if (eprev & MSB_MASK) {
++ o->object.file.data = 0;
++ asfs_bstore(sb, bh);
++ } else {
++ struct buffer_head *ebhp;
++ struct fsExtentBNode *ebnp;
++
++ if ((errorcode = asfs_getextent(sb, eprev & !MSB_MASK, &ebhp, &ebnp)) != 0) {
++ asfs_brelse(ebh);
++ return errorcode;
++ }
++
++ ebnp->next = 0;
++ asfs_bstore(sb, ebhp);
++ asfs_brelse(ebhp);
++ }
++ if ((errorcode = asfs_deletebnode(sb, ebh, ekey)) != 0) {
++ asfs_brelse(ebh);
++ return errorcode;
++ }
++ }
++ asfs_brelse(ebh);
++
++ return 0;
++}
++#endif
+diff -urN linux-2.6.18/fs/asfs/super.c linux-2.6.18-asfs-1.0b11/fs/asfs/super.c
+--- linux-2.6.18/fs/asfs/super.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/super.c 2006-09-22 23:22:22.000000000 +0200
+@@ -0,0 +1,497 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ *
++ * version: 1.0beta11 for 2.6.xx kernel
++ *
++ * Copyright (C) 2003,2004,2005,2006 Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ * NLS support by Pavel Fedin (C) 2005
++ *
++ *
++ * Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts
++ * of original amiga version of SmartFilesystem source code.
++ *
++ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
++ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
++ *
++ *
++ * ASFS is based on the Amiga FFS filesystem for Linux
++ * Copyright (C) 1993 Ray Burr
++ * Copyright (C) 1996 Hans-Joachim Widmaier
++ *
++ * Earlier versions were based on the Linux implementation of
++ * the ROMFS file system
++ * Copyright (C) 1997-1999 Janos Farkas <chexum at shadow.banki.hu>
++ *
++ * ASFS used some parts of the smbfs filesystem:
++ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
++ * Copyright (C) 1997 by Volker Lendecke
++ *
++ * and parts of the Minix filesystem additionally
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ * Copyright (C) 1996 Gertjan van Wingerde
++ *
++ *
++ * 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.
++ *
++ */
++
++/* todo:
++ * - remove bugs
++ * - add missing features (maybe safe-delete, other...)
++ * - create other fs tools like mkfs.asfs and fsck.asfs, some data-recovery tools
++ */
++
++#define ASFS_VERSION "1.0beta11 (22.09.2006)"
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/smp_lock.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/parser.h>
++#include <linux/nls.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++#include <asm/uaccess.h>
++
++static void asfs_put_super(struct super_block *sb);
++static int asfs_statfs(struct dentry *dentry, struct kstatfs *buf);
++static int asfs_remount(struct super_block *sb, int *flags, char *data);
++static struct inode *asfs_alloc_inode(struct super_block *sb);
++static void asfs_destroy_inode(struct inode *inode);
++
++static char asfs_default_codepage[] = CONFIG_ASFS_DEFAULT_CODEPAGE;
++static char asfs_default_iocharset[] = CONFIG_NLS_DEFAULT;
++
++u32 asfs_calcchecksum(void *block, u32 blocksize)
++{
++ u32 *data = block, checksum = 1;
++ while (blocksize > 0) {
++ checksum += be32_to_cpu(*data++);
++ blocksize -= 4;
++ }
++ checksum -= be32_to_cpu(((struct fsBlockHeader *)block)->checksum);
++ return -checksum;
++}
++
++static struct super_operations asfs_ops = {
++ .alloc_inode = asfs_alloc_inode,
++ .destroy_inode = asfs_destroy_inode,
++ .put_super = asfs_put_super,
++ .statfs = asfs_statfs,
++#ifdef CONFIG_ASFS_RW
++ .remount_fs = asfs_remount,
++#endif
++};
++
++extern struct dentry_operations asfs_dentry_operations;
++
++enum {
++ Opt_mode, Opt_setgid, Opt_setuid, Opt_prefix, Opt_volume,
++ Opt_lcvol, Opt_iocharset, Opt_codepage, Opt_ignore, Opt_err
++};
++
++static match_table_t tokens = {
++ {Opt_mode, "mode=%o"},
++ {Opt_setgid, "setgid=%u"},
++ {Opt_setuid, "setuid=%u"},
++ {Opt_prefix, "prefix=%s"},
++ {Opt_volume, "volume=%s"},
++ {Opt_lcvol, "lowercasevol"},
++ {Opt_iocharset, "iocharset=%s"},
++ {Opt_codepage, "codepage=%s"},
++ {Opt_ignore, "grpquota"},
++ {Opt_ignore, "noquota"},
++ {Opt_ignore, "quota"},
++ {Opt_ignore, "usrquota"},
++ {Opt_err, NULL},
++};
++
++static int asfs_parse_options(char *options, struct super_block *sb)
++{
++ char *p;
++ substring_t args[MAX_OPT_ARGS];
++
++ if (!options)
++ return 1;
++ while ((p = strsep(&options, ",")) != NULL) {
++ int token, option;
++ if (!*p)
++ continue;
++ token = match_token(p, tokens, args);
++
++ switch (token) {
++ case Opt_mode:
++ if (match_octal(&args[0], &option))
++ goto no_arg;
++ ASFS_SB(sb)->mode = option & 0777;
++ break;
++ case Opt_setgid:
++ if (match_int(&args[0], &option))
++ goto no_arg;
++ ASFS_SB(sb)->gid = option;
++ break;
++ case Opt_setuid:
++ if (match_int(&args[0], &option))
++ goto no_arg;
++ ASFS_SB(sb)->uid = option;
++ break;
++ case Opt_prefix:
++ if (ASFS_SB(sb)->prefix) {
++ kfree(ASFS_SB(sb)->prefix);
++ ASFS_SB(sb)->prefix = NULL;
++ }
++ ASFS_SB(sb)->prefix = match_strdup(&args[0]);
++ if (! ASFS_SB(sb)->prefix)
++ return 0;
++ break;
++ case Opt_volume:
++ if (ASFS_SB(sb)->root_volume) {
++ kfree(ASFS_SB(sb)->root_volume);
++ ASFS_SB(sb)->root_volume = NULL;
++ }
++ ASFS_SB(sb)->root_volume = match_strdup(&args[0]);
++ if (! ASFS_SB(sb)->root_volume)
++ return 0;
++ break;
++ case Opt_lcvol:
++ ASFS_SB(sb)->flags |= ASFS_VOL_LOWERCASE;
++ break;
++ case Opt_iocharset:
++ if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
++ kfree(ASFS_SB(sb)->iocharset);
++ ASFS_SB(sb)->iocharset = match_strdup(&args[0]);
++ if (!ASFS_SB(sb)->iocharset)
++ return 0;
++ break;
++ case Opt_codepage:
++ if (ASFS_SB(sb)->codepage != asfs_default_codepage)
++ kfree(ASFS_SB(sb)->codepage);
++ ASFS_SB(sb)->codepage = match_strdup(&args[0]);
++ if (!ASFS_SB(sb)->codepage)
++ return 0;
++ case Opt_ignore:
++ /* Silently ignore the quota options */
++ break;
++ default:
++no_arg:
++ printk("ASFS: Unrecognized mount option \"%s\" "
++ "or missing value\n", p);
++ return 0;
++ }
++ }
++ return 1;
++}
++
++static int asfs_fill_super(struct super_block *sb, void *data, int silent)
++{
++ struct asfs_sb_info *sbi;
++ struct buffer_head *bh;
++ struct fsRootBlock *rootblock;
++ struct inode *rootinode;
++
++ sbi = kmalloc(sizeof(struct asfs_sb_info), GFP_KERNEL);
++ if (!sbi)
++ return -ENOMEM;
++ sb->s_fs_info = sbi;
++
++ /* Fill in defaults */
++ ASFS_SB(sb)->uid = ASFS_DEFAULT_UID;
++ ASFS_SB(sb)->gid = ASFS_DEFAULT_GID;
++ ASFS_SB(sb)->mode = ASFS_DEFAULT_MODE;
++ ASFS_SB(sb)->prefix = NULL;
++ ASFS_SB(sb)->root_volume = NULL;
++ ASFS_SB(sb)->flags = 0;
++ ASFS_SB(sb)->iocharset = asfs_default_iocharset;
++ ASFS_SB(sb)->codepage = asfs_default_codepage;
++
++ if (!asfs_parse_options(data, sb)) {
++ printk(KERN_ERR "ASFS: Error parsing options\n");
++ return -EINVAL;
++ }
++
++ if (!sb_set_blocksize(sb, 512))
++ return -EINVAL;
++ sb->s_maxbytes = ASFS_MAXFILESIZE;
++
++ bh = sb_bread(sb, 0);
++ if (!bh) {
++ printk(KERN_ERR "ASFS: unable to read superblock\n");
++ return -EINVAL;
++ }
++
++ rootblock = (struct fsRootBlock *)bh->b_data;
++
++ if (be32_to_cpu(rootblock->bheader.id) == ASFS_ROOTID &&
++ be16_to_cpu(rootblock->version) == ASFS_STRUCTURE_VERISON) {
++
++ sb->s_blocksize = be32_to_cpu(rootblock->blocksize);
++ ASFS_SB(sb)->totalblocks = be32_to_cpu(rootblock->totalblocks);
++ ASFS_SB(sb)->rootobjectcontainer = be32_to_cpu(rootblock->rootobjectcontainer);
++ ASFS_SB(sb)->extentbnoderoot = be32_to_cpu(rootblock->extentbnoderoot);
++ ASFS_SB(sb)->objectnoderoot = be32_to_cpu(rootblock->objectnoderoot);
++ ASFS_SB(sb)->flags |= 0xff & rootblock->bits;
++ ASFS_SB(sb)->adminspacecontainer = be32_to_cpu(rootblock->adminspacecontainer);
++ ASFS_SB(sb)->bitmapbase = be32_to_cpu(rootblock->bitmapbase);
++ ASFS_SB(sb)->blocks_inbitmap = (sb->s_blocksize - sizeof(struct fsBitmap))<<3; /* must be a multiple of 32 !! */
++ ASFS_SB(sb)->blocks_bitmap = (ASFS_SB(sb)->totalblocks + ASFS_SB(sb)->blocks_inbitmap - 1) / ASFS_SB(sb)->blocks_inbitmap;
++ ASFS_SB(sb)->block_rovingblockptr = 0;
++ asfs_brelse(bh);
++
++ if (!sb_set_blocksize(sb, sb->s_blocksize)) {
++ printk(KERN_ERR "ASFS: Found Amiga SFS RootBlock on dev %s, but blocksize %ld is not supported!\n", \
++ sb->s_id, sb->s_blocksize);
++ return -EINVAL;
++ }
++
++ bh = sb_bread(sb, 0);
++ if (!bh) {
++ printk(KERN_ERR "ASFS: unable to read superblock\n");
++ goto out;
++ }
++ rootblock = (struct fsRootBlock *)bh->b_data;
++
++ if (asfs_check_block((void *)rootblock, sb->s_blocksize, 0, ASFS_ROOTID)) {
++#ifdef CONFIG_ASFS_RW
++ struct buffer_head *tmpbh;
++ if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
++ struct fsRootInfo *ri = (struct fsRootInfo *)((u8 *)tmpbh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
++ ASFS_SB(sb)->freeblocks = be32_to_cpu(ri->freeblocks);
++ asfs_brelse(tmpbh);
++ } else
++ ASFS_SB(sb)->freeblocks = 0;
++
++ if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer+2, ASFS_TRANSACTIONFAILURE_ID))) {
++ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but it has unfinished transaction. Mounting read-only.\n", sb->s_id);
++ ASFS_SB(sb)->flags |= ASFS_READONLY;
++ asfs_brelse(tmpbh);
++ }
++
++ if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->totalblocks-1, ASFS_ROOTID)) == NULL) {
++ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but there is no second RootBlock! Mounting read-only.\n", sb->s_id);
++ ASFS_SB(sb)->flags |= ASFS_READONLY;
++ asfs_brelse(tmpbh);
++ }
++ if (!(ASFS_SB(sb)->flags & ASFS_READONLY))
++ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id);
++#else
++ ASFS_SB(sb)->freeblocks = 0;
++ ASFS_SB(sb)->flags |= ASFS_READONLY;
++ printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id);
++#endif
++ } else {
++ if (!silent)
++ printk(KERN_ERR "VFS: Found Amiga SFS RootBlock on dev %s, but it has checksum error!\n", \
++ sb->s_id);
++ goto out;
++ }
++ } else {
++ if (!silent)
++ printk(KERN_ERR "VFS: Can't find a valid Amiga SFS filesystem on dev %s.\n", \
++ sb->s_id);
++ goto out;
++ }
++
++ asfs_brelse(bh);
++
++ sb->s_magic = ASFS_MAGIC;
++ sb->s_flags |= MS_NODEV | MS_NOSUID;
++ if (ASFS_SB(sb)->flags & ASFS_READONLY)
++ sb->s_flags |= MS_RDONLY;
++ sb->s_op = &asfs_ops;
++ asfs_debug("Case sensitive: %s\n", (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) ? "yes" : "no");
++
++ if (ASFS_SB(sb)->codepage[0] != '\0' && strcmp(ASFS_SB(sb)->codepage, "none") != 0) {
++ ASFS_SB(sb)->nls_disk = load_nls(ASFS_SB(sb)->codepage);
++ if (!ASFS_SB(sb)->nls_disk) {
++ printk(KERN_ERR "ASFS: codepage %s not found\n", ASFS_SB(sb)->codepage);
++ return -EINVAL;
++ }
++ ASFS_SB(sb)->nls_io = load_nls(ASFS_SB(sb)->iocharset);
++ if (!ASFS_SB(sb)->nls_io) {
++ printk(KERN_ERR "ASFS: IO charset %s not found\n", ASFS_SB(sb)->iocharset);
++ goto out2;
++ }
++ } else {
++ ASFS_SB(sb)->nls_io = NULL;
++ ASFS_SB(sb)->nls_disk = NULL;
++ }
++
++ if ((rootinode = asfs_get_root_inode(sb))) {
++ if ((sb->s_root = d_alloc_root(rootinode))) {
++ sb->s_root->d_op = &asfs_dentry_operations;
++ return 0;
++ }
++ iput(rootinode);
++ }
++ unload_nls(ASFS_SB(sb)->nls_io);
++out2:
++ unload_nls(ASFS_SB(sb)->nls_disk);
++ return -EINVAL;
++
++out:
++ asfs_brelse(bh);
++ return -EINVAL;
++
++}
++
++#ifdef CONFIG_ASFS_RW
++static int asfs_remount(struct super_block *sb, int *flags, char *data)
++{
++ asfs_debug("ASFS: remount (flags=0x%x, opts=\"%s\")\n",*flags,data);
++
++ if (!asfs_parse_options(data,sb))
++ return -EINVAL;
++
++ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
++ return 0;
++
++ if (*flags & MS_RDONLY) {
++ sb->s_flags |= MS_RDONLY;
++ } else if (!(ASFS_SB(sb)->flags & ASFS_READONLY)) {
++ sb->s_flags &= ~MS_RDONLY;
++ } else {
++ printk("VFS: Can't remount Amiga SFS on dev %s read/write because of errors.", sb->s_id);
++ return -EINVAL;
++ }
++ return 0;
++}
++#endif
++
++static void asfs_put_super(struct super_block *sb)
++{
++ struct asfs_sb_info *sbi = ASFS_SB(sb);
++
++ if (ASFS_SB(sb)->prefix)
++ kfree(ASFS_SB(sb)->prefix);
++ if (ASFS_SB(sb)->root_volume)
++ kfree(ASFS_SB(sb)->root_volume);
++ if (ASFS_SB(sb)->nls_disk)
++ unload_nls(ASFS_SB(sb)->nls_disk);
++ if (ASFS_SB(sb)->nls_io)
++ unload_nls(ASFS_SB(sb)->nls_io);
++ if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
++ kfree(ASFS_SB(sb)->iocharset);
++ if (ASFS_SB(sb)->codepage != asfs_default_codepage)
++ kfree(ASFS_SB(sb)->codepage);
++
++ kfree(sbi);
++ sb->s_fs_info = NULL;
++ return;
++}
++
++/* That's simple too. */
++static int asfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct super_block *sb = dentry->d_sb;
++
++ buf->f_type = ASFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_bfree = buf->f_bavail = ASFS_SB(sb)->freeblocks;
++ buf->f_blocks = ASFS_SB(sb)->totalblocks;
++ buf->f_namelen = ASFS_MAXFN;
++ return 0;
++}
++
++/* --- new in 2.6.x --- */
++static kmem_cache_t * asfs_inode_cachep;
++
++static struct inode *asfs_alloc_inode(struct super_block *sb)
++{
++ struct asfs_inode_info *ei;
++ ei = (struct asfs_inode_info *)kmem_cache_alloc(asfs_inode_cachep, SLAB_KERNEL);
++ if (!ei)
++ return NULL;
++ return &ei->vfs_inode;
++}
++
++static void asfs_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(asfs_inode_cachep, ASFS_I(inode));
++}
++
++static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
++{
++ struct asfs_inode_info *ei = (struct asfs_inode_info *) foo;
++
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR) {
++ inode_init_once(&ei->vfs_inode);
++ }
++}
++
++static int init_inodecache(void)
++{
++ asfs_inode_cachep = kmem_cache_create("asfs_inode_cache",
++ sizeof(struct asfs_inode_info),
++ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
++ init_once, NULL);
++ if (asfs_inode_cachep == NULL)
++ return -ENOMEM;
++ return 0;
++}
++
++static void destroy_inodecache(void)
++{
++ if (kmem_cache_destroy(asfs_inode_cachep))
++ printk(KERN_INFO "asfs_inode_cache: not all structures were freed\n");
++}
++
++static int asfs_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
++{
++ return get_sb_bdev(fs_type, flags, dev_name, data, asfs_fill_super,
++ mnt);
++}
++
++static struct file_system_type asfs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "asfs",
++ .get_sb = asfs_get_sb,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++
++static int __init init_asfs_fs(void)
++{
++ int err = init_inodecache();
++ if (err)
++ goto out1;
++ err = register_filesystem(&asfs_fs_type);
++ if (err)
++ goto out;
++ return 0;
++out:
++ destroy_inodecache();
++out1:
++ return err;
++}
++
++static void __exit exit_asfs_fs(void)
++{
++ unregister_filesystem(&asfs_fs_type);
++ destroy_inodecache();
++}
++
++/* Yes, works even as a module... :) */
++
++#ifdef CONFIG_ASFS_RW
++MODULE_DESCRIPTION("Amiga Smart File System (read/write) support for Linux kernel 2.6.x v" ASFS_VERSION);
++#else
++MODULE_DESCRIPTION("Amiga Smart File System (read-only) support for Linux kernel 2.6.x v" ASFS_VERSION);
++#endif
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Marek Szyprowski <marek at amiga.pl>");
++
++module_init(init_asfs_fs)
++module_exit(exit_asfs_fs)
+diff -urN linux-2.6.18/fs/asfs/symlink.c linux-2.6.18-asfs-1.0b11/fs/asfs/symlink.c
+--- linux-2.6.18/fs/asfs/symlink.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/fs/asfs/symlink.c 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,235 @@
++/*
++ *
++ * Amiga Smart File System, Linux implementation
++ * version: 1.0beta9
++ *
++ * Copyright (C) 2003,2004,2005 Marek 'March' Szyprowski <marek at amiga.pl>
++ *
++ *
++ * 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/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/pagemap.h>
++#include <linux/nls.h>
++#include "asfs_fs.h"
++
++#include <asm/byteorder.h>
++#include <asm/uaccess.h>
++
++int asfs_symlink_readpage(struct file *file, struct page *page)
++{
++ struct buffer_head *bh;
++ struct fsSoftLink *slinkcont;
++ struct inode *inode = page->mapping->host;
++ struct super_block *sb = inode->i_sb;
++ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
++ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
++ char *link = kmap(page);
++ int i = 0, j = 0;
++ char c, lc = 0, *prefix, *lf, *p;
++ wchar_t uni;
++ int clen;
++
++ if (!(bh = asfs_breadcheck(sb, ASFS_I(inode)->firstblock, ASFS_SOFTLINK_ID))) {
++ SetPageError(page);
++ kunmap(page);
++ unlock_page(page);
++ return -EIO;
++ }
++ slinkcont = (struct fsSoftLink *) bh->b_data;
++
++ lf = slinkcont->string;
++ prefix = ASFS_SB(sb)->prefix ? ASFS_SB(sb)->prefix : "/";
++
++ if ((p = strchr(lf,':'))) { /* Handle assign or volume name */
++ if (ASFS_SB(sb)->root_volume &&
++ strncmp(lf, ASFS_SB(sb)->root_volume, strlen(ASFS_SB(sb)->root_volume)) == 0) {
++ /* global root volume name found */
++ link[i++] = '/';
++ lf = p+1;
++ } else {
++ /* adding volume prefix */
++ while (i < 1023 && (c = prefix[i]))
++ link[i++] = c;
++ while (i < 1023 && lf[j] != ':')
++ {
++ c = lf[j++];
++ if (ASFS_SB(sb)->flags & ASFS_VOL_LOWERCASE)
++ c = asfs_lowerchar(c);
++ if (nls_io)
++ {
++ clen = nls_disk->char2uni(&c, 1, &uni);
++ if (clen>0) {
++ clen = nls_io->uni2char(uni, &link[i], NLS_MAX_CHARSET_SIZE);
++ if (clen>0)
++ i += clen;
++ }
++ if (clen<0)
++ link[i++] = '?';
++ } else
++ link[i++] = c;
++ }
++ if (i < 1023)
++ link[i++] = '/';
++ j++;
++ }
++ lc = '/';
++ }
++
++ while (i < 1023 && (c = lf[j])) {
++ if (c == '/' && lc == '/' && i < 1020) { /* parent dir */
++ link[i++] = '.';
++ link[i++] = '.';
++ }
++ lc = c;
++ if (nls_io)
++ {
++ clen = nls_disk->char2uni(&c, 1, &uni);
++ if (clen>0) {
++ clen = nls_io->uni2char(uni, &link[i], NLS_MAX_CHARSET_SIZE);
++ if (clen>0)
++ i += clen;
++ }
++ if (clen<0)
++ link[i++] = '?';
++ } else
++ link[i++] = c;
++ j++;
++ }
++ link[i] = '\0';
++ SetPageUptodate(page);
++ kunmap(page);
++ unlock_page(page);
++ asfs_brelse(bh);
++ return 0;
++}
++
++#ifdef CONFIG_ASFS_RW
++
++int asfs_write_symlink(struct inode *symfile, const char *symname)
++{
++ struct super_block *sb = symfile->i_sb;
++ struct buffer_head *bh;
++ struct fsSoftLink *slinkcont;
++ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
++ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
++ char *p, c, lc;
++ int i, maxlen, pflen;
++ wchar_t uni;
++ int clen, blen;
++
++ asfs_debug("asfs_write_symlink %s to node %d\n", symname, (int)symfile->i_ino);
++
++ if (!(bh = asfs_breadcheck(sb, ASFS_I(symfile)->firstblock, ASFS_SOFTLINK_ID))) {
++ unlock_super(sb);
++ return -EIO;
++ }
++ slinkcont = (struct fsSoftLink *) bh->b_data;
++
++ /* translating symlink target path */
++
++ maxlen = sb->s_blocksize - sizeof(struct fsSoftLink) - 2;
++ i = 0;
++ p = slinkcont->string;
++ lc = '/';
++
++ if (*symname == '/') {
++ while (*symname == '/')
++ symname++;
++ if (ASFS_SB(sb)->prefix &&
++ strncmp(symname-1, ASFS_SB(sb)->prefix, (pflen = strlen(ASFS_SB(sb)->prefix))) == 0) {
++ /* found volume prefix, ommiting it */
++ symname += pflen;
++ blen = strlen(symname);
++ while (*symname != '/' && *symname != '\0') {
++ clen = nls_io->char2uni(symname, blen, &uni);
++ if (clen>0) {
++ symname += clen;
++ blen -= clen;
++ clen = nls_disk->uni2char(uni, p, NLS_MAX_CHARSET_SIZE);
++ if (clen>0)
++ p += clen;
++ }
++ else
++ {
++ symname++;
++ blen--;
++ }
++ if (clen<0)
++ *p++ = '?';
++ i++;
++ }
++ symname++;
++ *p++ = ':';
++ } else if (ASFS_SB(sb)->root_volume) { /* adding root volume name */
++ while (ASFS_SB(sb)->root_volume[i])
++ *p++ = ASFS_SB(sb)->root_volume[i++];
++ *p++ = ':';
++ } else { /* do nothing */
++ *p++ = '/';
++ }
++ i++;
++ }
++
++ blen = strlen(symname);
++ while (i < maxlen && (c = *symname)) {
++ if (c == '.' && lc == '/' && symname[1] == '.' && symname[2] == '/') {
++ *p++ = '/';
++ i++;
++ symname += 3;
++ blen -= 3;
++ lc = '/';
++ } else if (c == '.' && lc == '/' && symname[1] == '/') {
++ symname += 2;
++ blen -= 2;
++ lc = '/';
++ } else {
++ clen = nls_io->char2uni(symname, blen, &uni);
++ if (clen>0) {
++ symname += clen;
++ blen -= clen;
++ clen = nls_disk->uni2char(uni, p, NLS_MAX_CHARSET_SIZE);
++ if (clen>0)
++ lc = *p;
++ p += clen;
++ }
++ else
++ {
++ symname++;
++ blen--;
++ }
++ if (clen<0)
++ {
++ *p++ = '?';
++ lc = '?';
++ }
++ i++;
++ }
++ if (lc == '/')
++ while (*symname == '/')
++ {
++ symname++;
++ blen--;
++ }
++ }
++ *p = 0;
++
++ asfs_bstore(sb, bh);
++ asfs_brelse(bh);
++
++ unlock_super(sb);
++
++ return 0;
++}
++
++#endif
+diff -urN linux-2.6.18/fs/Kconfig linux-2.6.18-asfs-1.0b11/fs/Kconfig
+--- linux-2.6.18/fs/Kconfig 2006-09-22 22:48:22.000000000 +0200
++++ linux-2.6.18-asfs-1.0b11/fs/Kconfig 2006-09-22 22:52:37.000000000 +0200
+@@ -955,6 +955,53 @@
+ To compile this file system support as a module, choose M here: the
+ module will be called affs. If unsure, say N.
+
++config ASFS_FS
++ tristate "Amiga SFS file system support (EXPERIMENTAL)"
++ select NLS
++ depends on EXPERIMENTAL
++ help
++
++ The Amiga Smart FileSystem (SFS) is the file system used on hard
++ disks by Amiga(tm) and MorphOS(tm) systems. Say Y if you want
++ to be able to read files from an Amiga SFS partition on your hard
++ drive.
++
++ For more information read <file:Documentation/filesystems/asfs.txt>
++
++ To compile this file system support as a module, choose M here: the
++ module will be called asfs.
++
++ If unsure, say N.
++
++config ASFS_DEFAULT_CODEPAGE
++ string "Default codepage for SFS"
++ depends on ASFS_FS
++ default ""
++ help
++ This option should be set to the codepage of your SFS filesystems.
++ It can be overridden with the 'codepage' mount option. Leave it blank
++ or enter 'none' to disable filename converting.
++
++ Use full codepage name (for example 'cp1251' instead of '1251') here,
++ this allows to specify any character set, not only numbered one (like
++ 'iso8859-2').
++
++ If unsure, leave it blank.
++
++config ASFS_RW
++ bool "Amiga SFS write support (DANGEROUS)"
++ depends on ASFS_FS
++ help
++
++ If you say Y here, you will be able to write to ASFS file
++ systems as well as read from them. The read-write support in ASFS
++ is in beta stage. This means that useing it to write files to SFS
++ partitions is DANGEROUS and COULD corrupt the filesystem.
++
++ For more information read <file:Documentation/filesystems/asfs.txt>
++
++ If unsure, say N.
++
+ config HFS_FS
+ tristate "Apple Macintosh file system support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+diff -urN linux-2.6.18/fs/Makefile linux-2.6.18-asfs-1.0b11/fs/Makefile
+--- linux-2.6.18/fs/Makefile 2006-09-22 22:48:22.000000000 +0200
++++ linux-2.6.18-asfs-1.0b11/fs/Makefile 2006-09-22 22:52:37.000000000 +0200
+@@ -85,6 +85,7 @@
+ obj-$(CONFIG_JFFS_FS) += jffs/
+ obj-$(CONFIG_JFFS2_FS) += jffs2/
+ obj-$(CONFIG_AFFS_FS) += affs/
++obj-$(CONFIG_ASFS_FS) += asfs/
+ obj-$(CONFIG_ROMFS_FS) += romfs/
+ obj-$(CONFIG_QNX4FS_FS) += qnx4/
+ obj-$(CONFIG_AUTOFS_FS) += autofs/
+diff -urN linux-2.6.18/include/linux/amigasfs.h linux-2.6.18-asfs-1.0b11/include/linux/amigasfs.h
+--- linux-2.6.18/include/linux/amigasfs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-asfs-1.0b11/include/linux/amigasfs.h 2006-09-22 22:52:37.000000000 +0200
+@@ -0,0 +1,276 @@
++#ifndef __LINUX_AMIGASFS_H
++#define __LINUX_AMIGASFS_H
++
++#include <linux/types.h>
++
++/* some helper macros... */
++#define ASFS_MAKE_ID(a,b,c,d) (((a)&0xff)<<24|((b)&0xff)<<16|((c)&0xff)<<8|((d)&0xff))
++
++/* Amiga SFS block IDs */
++#define ASFS_ROOTID ASFS_MAKE_ID('S','F','S','\0')
++#define ASFS_OBJECTCONTAINER_ID ASFS_MAKE_ID('O','B','J','C')
++#define ASFS_BNODECONTAINER_ID ASFS_MAKE_ID('B','N','D','C')
++#define ASFS_NODECONTAINER_ID ASFS_MAKE_ID('N','D','C',' ')
++#define ASFS_HASHTABLE_ID ASFS_MAKE_ID('H','T','A','B')
++#define ASFS_SOFTLINK_ID ASFS_MAKE_ID('S','L','N','K')
++#define ASFS_ADMINSPACECONTAINER_ID ASFS_MAKE_ID('A','D','M','C')
++#define ASFS_BITMAP_ID ASFS_MAKE_ID('B','T','M','P')
++#define ASFS_TRANSACTIONFAILURE_ID ASFS_MAKE_ID('T','R','F','A')
++
++/* Amiga SFS defines and magic values */
++
++#define ASFS_MAGIC 0xa0ff
++#define ASFS_MAXFN (105u)
++#define ASFS_MAXFILESIZE 0x8FFFFFFE
++
++#define ASFS_STRUCTURE_VERISON (3)
++#define ASFS_BLCKFACCURACY (5)
++
++#define ASFS_ROOTBITS_CASESENSITIVE (128)
++#define ASFS_READONLY (512)
++#define ASFS_VOL_LOWERCASE (1024)
++
++#define ASFS_ROOTNODE (1)
++#define ASFS_RECYCLEDNODE (2)
++
++#define OTYPE_HIDDEN (1)
++#define OTYPE_HARDLINK (32)
++#define OTYPE_LINK (64)
++#define OTYPE_DIR (128)
++
++#define MSB_MASK (1ul << 31)
++
++#define NODE_STRUCT_SIZE (10) /* (sizeof(struct fsObjectNode)) */
++#define NODECONT_BLOCK_COUNT ((sb->s_blocksize - sizeof(struct fsNodeContainer)) / sizeof(u32))
++
++#define ASFS_ALWAYSFREE (16) /* keep this amount of blocks free */
++
++#define ASFS_BLOCKCHUNKS (16) /* try to allocate this number of blocks in one request */
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++/* amigados protection bits */
++
++#define FIBB_SCRIPT 6 /* program is a script (execute) file */
++#define FIBB_PURE 5 /* program is reentrant and rexecutable */
++#define FIBB_ARCHIVE 4 /* cleared whenever file is changed */
++#define FIBB_READ 3 /* ignored by old filesystem */
++#define FIBB_WRITE 2 /* ignored by old filesystem */
++#define FIBB_EXECUTE 1 /* ignored by system, used by Shell */
++#define FIBB_DELETE 0 /* prevent file from being deleted */
++
++#define FIBF_SCRIPT (1<<FIBB_SCRIPT)
++#define FIBF_PURE (1<<FIBB_PURE)
++#define FIBF_ARCHIVE (1<<FIBB_ARCHIVE)
++#define FIBF_READ (1<<FIBB_READ)
++#define FIBF_WRITE (1<<FIBB_WRITE)
++#define FIBF_EXECUTE (1<<FIBB_EXECUTE)
++#define FIBF_DELETE (1<<FIBB_DELETE)
++
++/* name hashing macro */
++
++#define HASHCHAIN(x) (u16)(x % (u16)(((sb->s_blocksize) - sizeof(struct fsHashTable))>>2))
++
++/* Each block has its own header with checksum and id, its called fsBlockHeader */
++
++struct fsBlockHeader {
++ u32 id; /* 4 character id string of this block */
++ u32 checksum; /* The checksum */
++ u32 ownblock; /* The blocknumber of the block this block is stored at */
++};
++
++/* On-disk "super block", called fsRootBlock */
++
++struct fsRootBlock {
++ struct fsBlockHeader bheader;
++
++ u16 version; /* Version number of the filesystem block structure */
++ u16 sequencenumber; /* The Root with the highest sequencenumber is valid */
++
++ u32 datecreated; /* Creation date (when first formatted). Cannot be changed. */
++ u8 bits; /* various settings, see defines below. */
++ u8 pad1;
++ u16 pad2;
++
++ u32 reserved1[2];
++
++ u32 firstbyteh; /* The first byte of our partition from the start of the */
++ u32 firstbyte; /* disk. firstbyteh = upper 32 bits, firstbyte = lower 32 bits. */
++
++ u32 lastbyteh; /* The last byte of our partition, excluding this one. */
++ u32 lastbyte;
++
++ u32 totalblocks; /* size of this partition in blocks */
++ u32 blocksize; /* blocksize used */
++
++ u32 reserved2[2];
++ u32 reserved3[8];
++
++ u32 bitmapbase; /* location of the bitmap */
++ u32 adminspacecontainer; /* location of first adminspace container */
++ u32 rootobjectcontainer; /* location of the root objectcontainer */
++ u32 extentbnoderoot; /* location of the root of the extentbnode B-tree */
++ u32 objectnoderoot; /* location of the root of the objectnode tree */
++
++ u32 reserved4[3];
++};
++
++/* On disk inode, called fsObject */
++
++struct fsObject {
++ u16 owneruid;
++ u16 ownergid;
++ u32 objectnode;
++ u32 protection;
++
++ union {
++ struct {
++ u32 data;
++ u32 size;
++ } file;
++
++ struct {
++ u32 hashtable; /* for directories & root, 0 means no hashblock */
++ u32 firstdirblock;
++ } dir;
++ } object;
++
++ u32 datemodified;
++ u8 bits;
++
++ u8 name[0];
++ u8 comment[0];
++};
++
++/* On disk block containging a number of fsObjects */
++
++struct fsObjectContainer {
++ struct fsBlockHeader bheader;
++
++ u32 parent;
++ u32 next;
++ u32 previous; /* 0 for the first block in the directory chain */
++
++ struct fsObject object[0];
++};
++
++/* BTree structures, used to collect file data position on disk */
++
++struct fsExtentBNode {
++ u32 key; /* data! */
++ u32 next;
++ u32 prev;
++ u16 blocks; /* The size in blocks of the region this Extent controls */
++};
++
++struct BNode {
++ u32 key;
++ u32 data;
++};
++
++struct BTreeContainer {
++ u16 nodecount;
++ u8 isleaf;
++ u8 nodesize; /* Must be a multiple of 2 */
++
++ struct BNode bnode[0];
++};
++
++/* On disk block with BTreeContainer */
++
++struct fsBNodeContainer {
++ struct fsBlockHeader bheader;
++ struct BTreeContainer btc;
++};
++
++/* On disk block with soft link data */
++
++struct fsSoftLink {
++ struct fsBlockHeader bheader;
++ u32 parent;
++ u32 next;
++ u32 previous;
++ u8 string[0];
++};
++
++/* On disk block with hashtable data */
++
++struct fsHashTable {
++ struct fsBlockHeader bheader;
++ u32 parent;
++ u32 hashentry[0];
++};
++
++/* On disk block with node index and some helper structures */
++
++struct fsNodeContainer {
++ struct fsBlockHeader bheader;
++ u32 nodenumber;
++ u32 nodes;
++ u32 node[0];
++};
++
++struct fsNode {
++ u32 data;
++};
++
++struct fsObjectNode {
++ struct fsNode node;
++ u32 next;
++ u16 hash16;
++} __attribute__ ((packed));
++
++/* Some adminspace and bitmap block structures */
++
++struct fsAdminSpace {
++ u32 space;
++ u32 bits;
++/* Set bits are used blocks, bit 31 is the first block in the AdminSpace. */
++};
++
++struct fsAdminSpaceContainer {
++ struct fsBlockHeader bheader;
++
++ u32 next;
++ u32 previous;
++
++ u8 bits;
++ u8 pad1;
++ u16 pad2;
++
++ struct fsAdminSpace adminspace[0];
++};
++
++struct fsBitmap {
++ struct fsBlockHeader bheader;
++
++ u32 bitmap[0];
++
++/* Bits are 1 if the block is free, and 0 if full.
++ Bitmap must consist of an integral number of longwords. */
++};
++
++/* The fsRootInfo structure has all kinds of information about the format
++ of the disk. */
++
++struct fsRootInfo {
++ u32 deletedblocks; /* Amount in blocks which deleted files consume. */
++ u32 deletedfiles; /* Number of deleted files in recycled. */
++ u32 freeblocks; /* Cached number of free blocks on disk. */
++
++ u32 datecreated;
++
++ u32 lastallocatedblock; /* Block which was most recently allocated */
++ u32 lastallocatedadminspace; /* AdminSpaceContainer which most recently was used to allocate a block */
++ u32 lastallocatedextentnode; /* ExtentNode which was most recently created */
++ u32 lastallocatedobjectnode; /* ObjectNode which was most recently created */
++
++ u32 rovingpointer;
++};
++
++#endif
+
+
+
Added: people/maks-guest/linux-2.6/debian/patches/features/all/vserver/bindmount-dev.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/vserver/bindmount-dev.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,42 @@
+diff -ur source-s390-vserver.orig/fs/namespace.c source-s390-vserver/fs/namespace.c
+--- source-s390-vserver.orig/fs/namespace.c 2006-08-12 16:51:51.000000000 +0200
++++ source-s390-vserver/fs/namespace.c 2006-08-12 16:53:26.000000000 +0200
+@@ -986,6 +986,9 @@
+ if (!mnt)
+ goto out;
+
++ if (!capable(CAP_SYS_ADMIN) && (old_nd.mnt->mnt_flags & MNT_NODEV))
++ mnt_flags |= MNT_NODEV;
++
+ mnt->mnt_flags = mnt_flags;
+ if (flags & MS_XID) {
+ mnt->mnt_xid = xid;
+@@ -1028,6 +1031,9 @@
+ if (nd->dentry != nd->mnt->mnt_root)
+ return -EINVAL;
+
++ if (!capable(CAP_SYS_ADMIN))
++ mnt_flags |= MNT_NODEV;
++
+ down_write(&sb->s_umount);
+ err = do_remount_sb(sb, flags, data, 0);
+ if (!err)
+@@ -1136,6 +1142,9 @@
+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT))
+ return -EPERM;
+
++ if (!capable(CAP_SYS_ADMIN))
++ mnt_flags |= MNT_NODEV;
++
+ mnt = do_kern_mount(type, flags, name, data);
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+@@ -1409,8 +1418,6 @@
+ if (flags & MS_NODIRATIME)
+ mnt_flags |= MNT_NODIRATIME;
+
+- if (!capable(CAP_SYS_ADMIN))
+- mnt_flags |= MNT_NODEV;
+ flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
+ MS_NOATIME | MS_NODIRATIME);
+
Added: people/maks-guest/linux-2.6/debian/patches/features/all/vserver/gen-patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/vserver/gen-patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,14 @@
+#!/bin/sh
+patch="$1"
+
+error() {
+ echo "$@";
+ exit 1
+}
+
+version=$(filterdiff -p 1 -i Makefile "$patch" | grep "+EXTRAVERSION" | sed -e 's,.*-vs,vs,')
+[ "$version" ] || error "can't find version!"
+
+file="$(dirname $0)/$version.patch"
+
+filterdiff -p 1 -x Makefile -x init/version.c "$patch" > "$file"
Added: people/maks-guest/linux-2.6/debian/patches/features/all/xen/fedora-36252.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/xen/fedora-36252.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,94391 @@
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/boot-xen/Makefile linux-2.6.18-xen/arch/i386/boot-xen/Makefile
+--- linux-2.6.18.1/arch/i386/boot-xen/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/boot-xen/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,21 @@
++
++OBJCOPYFLAGS := -g --strip-unneeded
++
++vmlinuz: vmlinux-stripped FORCE
++ $(call if_changed,gzip)
++
++vmlinux-stripped: vmlinux FORCE
++ $(call if_changed,objcopy)
++
++INSTALL_ROOT := $(patsubst %/boot,%,$(INSTALL_PATH))
++
++XINSTALL_NAME ?= $(KERNELRELEASE)
++install:
++ mkdir -p $(INSTALL_ROOT)/boot
++ ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(XENGUEST)$(INSTALL_SUFFIX)
++ rm -f $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX)
++ install -m0644 vmlinuz $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX)
++ install -m0644 vmlinux $(INSTALL_ROOT)/boot/vmlinux-syms-$(XINSTALL_NAME)$(INSTALL_SUFFIX)
++ install -m0664 .config $(INSTALL_ROOT)/boot/config-$(XINSTALL_NAME)$(INSTALL_SUFFIX)
++ install -m0664 System.map $(INSTALL_ROOT)/boot/System.map-$(XINSTALL_NAME)$(INSTALL_SUFFIX)
++ ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL)$(XENGUEST)$(INSTALL_SUFFIX)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/Kconfig linux-2.6.18-xen/arch/i386/Kconfig
+--- linux-2.6.18.1/arch/i386/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/Kconfig 2006-09-22 16:38:35.000000000 +0200
+@@ -16,6 +16,7 @@
+
+ config GENERIC_TIME
+ bool
++ depends on !X86_XEN
+ default y
+
+ config LOCKDEP_SUPPORT
+@@ -103,6 +104,15 @@
+ help
+ Choose this option if your computer is a standard PC or compatible.
+
++config X86_XEN
++ bool "Xen-compatible"
++ select X86_UP_APIC if !SMP && XEN_PRIVILEGED_GUEST
++ select X86_UP_IOAPIC if !SMP && XEN_PRIVILEGED_GUEST
++ select SWIOTLB
++ help
++ Choose this option if you plan to run this kernel on top of the
++ Xen Hypervisor.
++
+ config X86_ELAN
+ bool "AMD Elan"
+ help
+@@ -213,6 +223,7 @@
+
+ config HPET_TIMER
+ bool "HPET Timer Support"
++ depends on !X86_XEN
+ help
+ This enables the use of the HPET for the kernel's internal timer.
+ HPET is the next generation timer replacing legacy 8254s.
+@@ -263,7 +274,7 @@
+
+ config X86_UP_APIC
+ bool "Local APIC support on uniprocessors"
+- depends on !SMP && !(X86_VISWS || X86_VOYAGER)
++ depends on !SMP && !(X86_VISWS || X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)
+ help
+ A local APIC (Advanced Programmable Interrupt Controller) is an
+ integrated interrupt controller in the CPU. If you have a single-CPU
+@@ -288,12 +299,12 @@
+
+ config X86_LOCAL_APIC
+ bool
+- depends on X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER)
++ depends on X86_UP_APIC || ((X86_VISWS || SMP) && !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST))
+ default y
+
+ config X86_IO_APIC
+ bool
+- depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER))
++ depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER || XEN_UNPRIVILEGED_GUEST))
+ default y
+
+ config X86_VISWS_APIC
+@@ -303,7 +314,7 @@
+
+ config X86_MCE
+ bool "Machine Check Exception"
+- depends on !X86_VOYAGER
++ depends on !(X86_VOYAGER || X86_XEN)
+ ---help---
+ Machine Check Exception support allows the processor to notify the
+ kernel if it detects a problem (e.g. overheating, component failure).
+@@ -402,6 +413,7 @@
+
+ config MICROCODE
+ tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
++ depends on !XEN_UNPRIVILEGED_GUEST
+ ---help---
+ If you say Y here and also to "/dev file system support" in the
+ 'File systems' section, you will be able to update the microcode on
+@@ -419,6 +431,7 @@
+
+ config X86_MSR
+ tristate "/dev/cpu/*/msr - Model-specific register support"
++ depends on !X86_XEN
+ help
+ This device gives privileged processes access to the x86
+ Model-Specific Registers (MSRs). It is a character device with
+@@ -434,6 +447,10 @@
+ with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
+ /dev/cpu/31/cpuid.
+
++config SWIOTLB
++ bool
++ default n
++
+ source "drivers/firmware/Kconfig"
+
+ choice
+@@ -607,7 +624,7 @@
+
+ config HIGHPTE
+ bool "Allocate 3rd-level pagetables from highmem"
+- depends on HIGHMEM4G || HIGHMEM64G
++ depends on (HIGHMEM4G || HIGHMEM64G) && !X86_XEN
+ help
+ The VM uses one page table entry for each page of physical memory.
+ For systems with a lot of RAM, this can be wasteful of precious
+@@ -616,6 +633,7 @@
+
+ config MATH_EMULATION
+ bool "Math emulation"
++ depends on !X86_XEN
+ ---help---
+ Linux can emulate a math coprocessor (used for floating point
+ operations) if you don't have one. 486DX and Pentium processors have
+@@ -641,6 +659,8 @@
+
+ config MTRR
+ bool "MTRR (Memory Type Range Register) support"
++ depends on !XEN_UNPRIVILEGED_GUEST
++ default y if X86_XEN
+ ---help---
+ On Intel P6 family processors (Pentium Pro, Pentium II and later)
+ the Memory Type Range Registers (MTRRs) may be used to control
+@@ -675,7 +695,7 @@
+
+ config EFI
+ bool "Boot from EFI support"
+- depends on ACPI
++ depends on ACPI && !X86_XEN
+ default n
+ ---help---
+ This enables the the kernel to boot on EFI platforms using
+@@ -693,7 +713,7 @@
+
+ config IRQBALANCE
+ bool "Enable kernel irq balancing"
+- depends on SMP && X86_IO_APIC
++ depends on SMP && X86_IO_APIC && !X86_XEN
+ default y
+ help
+ The default yes will allow the kernel to do irq load balancing.
+@@ -741,7 +761,7 @@
+
+ config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on EXPERIMENTAL && !X86_XEN
+ 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
+@@ -794,6 +814,7 @@
+ config COMPAT_VDSO
+ bool "Compat VDSO support"
+ default y
++ depends on !X86_XEN
+ help
+ Map the VDSO to the predictable old-style address too.
+ ---help---
+@@ -810,18 +831,20 @@
+ depends on HIGHMEM
+
+ menu "Power management options (ACPI, APM)"
+- depends on !X86_VOYAGER
++ depends on !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)
+
++if !X86_XEN
+ source kernel/power/Kconfig
++endif
+
+ source "drivers/acpi/Kconfig"
+
+ menu "APM (Advanced Power Management) BIOS Support"
+-depends on PM && !X86_VISWS
++depends on PM && !(X86_VISWS || X86_XEN)
+
+ config APM
+ tristate "APM (Advanced Power Management) BIOS support"
+- depends on PM
++ depends on PM && PM_LEGACY
+ ---help---
+ APM is a BIOS specification for saving power using several different
+ techniques. This is mostly useful for battery powered laptops with
+@@ -1006,6 +1029,7 @@
+
+ config PCI_GOBIOS
+ bool "BIOS"
++ depends on !X86_XEN
+
+ config PCI_GOMMCONFIG
+ bool "MMConfig"
+@@ -1013,6 +1037,13 @@
+ config PCI_GODIRECT
+ bool "Direct"
+
++config PCI_GOXEN_FE
++ bool "Xen PCI Frontend"
++ depends on X86_XEN
++ help
++ The PCI device frontend driver allows the kernel to import arbitrary
++ PCI devices from a PCI backend to support PCI driver domains.
++
+ config PCI_GOANY
+ bool "Any"
+
+@@ -1020,7 +1051,7 @@
+
+ config PCI_BIOS
+ bool
+- depends on !X86_VISWS && PCI && (PCI_GOBIOS || PCI_GOANY)
++ depends on !(X86_VISWS || X86_XEN) && PCI && (PCI_GOBIOS || PCI_GOANY)
+ default y
+
+ config PCI_DIRECT
+@@ -1033,6 +1064,18 @@
+ depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
+ default y
+
++config XEN_PCIDEV_FRONTEND
++ bool
++ depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)
++ default y
++
++config XEN_PCIDEV_FE_DEBUG
++ bool "Xen PCI Frontend Debugging"
++ depends on XEN_PCIDEV_FRONTEND
++ default n
++ help
++ Enables some debug statements within the PCI Frontend.
++
+ source "drivers/pci/pcie/Kconfig"
+
+ source "drivers/pci/Kconfig"
+@@ -1043,7 +1086,7 @@
+
+ config ISA
+ bool "ISA support"
+- depends on !(X86_VOYAGER || X86_VISWS)
++ depends on !(X86_VOYAGER || X86_VISWS || X86_XEN)
+ help
+ Find out whether you have ISA slots on your motherboard. ISA is the
+ name of a bus system, i.e. the way the CPU talks to the other stuff
+@@ -1070,7 +1113,7 @@
+ source "drivers/eisa/Kconfig"
+
+ config MCA
+- bool "MCA support" if !(X86_VISWS || X86_VOYAGER)
++ bool "MCA support" if !(X86_VISWS || X86_VOYAGER || X86_XEN)
+ default y if X86_VOYAGER
+ help
+ MicroChannel Architecture is found in some IBM PS/2 machines and
+@@ -1146,6 +1189,8 @@
+
+ source "crypto/Kconfig"
+
++source "drivers/xen/Kconfig"
++
+ source "lib/Kconfig"
+
+ #
+@@ -1171,7 +1216,7 @@
+
+ config X86_HT
+ bool
+- depends on SMP && !(X86_VISWS || X86_VOYAGER)
++ depends on SMP && !(X86_VISWS || X86_VOYAGER || X86_XEN)
+ default y
+
+ config X86_BIOS_REBOOT
+@@ -1184,6 +1229,16 @@
+ depends on X86_SMP || (X86_VOYAGER && SMP)
+ default y
+
++config X86_NO_TSS
++ bool
++ depends on X86_XEN
++ default y
++
++config X86_NO_IDT
++ bool
++ depends on X86_XEN
++ default y
++
+ config KTIME_SCALAR
+ bool
+ default y
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/Kconfig.cpu linux-2.6.18-xen/arch/i386/Kconfig.cpu
+--- linux-2.6.18.1/arch/i386/Kconfig.cpu 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/Kconfig.cpu 2006-09-04 16:31:00.000000000 +0200
+@@ -251,7 +251,7 @@
+
+ config X86_F00F_BUG
+ bool
+- depends on M586MMX || M586TSC || M586 || M486 || M386
++ depends on (M586MMX || M586TSC || M586 || M486 || M386) && !X86_NO_IDT
+ default y
+
+ config X86_WP_WORKS_OK
+@@ -311,5 +311,5 @@
+
+ config X86_TSC
+ bool
+- depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX) && !X86_NUMAQ
++ depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX) && !X86_NUMAQ && !X86_XEN
+ default y
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/Kconfig.debug linux-2.6.18-xen/arch/i386/Kconfig.debug
+--- linux-2.6.18.1/arch/i386/Kconfig.debug 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/Kconfig.debug 2006-09-04 16:31:00.000000000 +0200
+@@ -79,6 +79,7 @@
+ config DOUBLEFAULT
+ default y
+ bool "Enable doublefault exception handler" if EMBEDDED
++ depends on !X86_NO_TSS
+ help
+ This option allows trapping of rare doublefault exceptions that
+ would otherwise cause a system to silently reboot. Disabling this
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/acpi/boot-xen.c linux-2.6.18-xen/arch/i386/kernel/acpi/boot-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/acpi/boot-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/acpi/boot-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,1168 @@
++/*
++ * boot.c - Architecture-Specific Low-Level ACPI Boot Support
++ *
++ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh at intel.com>
++ * Copyright (C) 2001 Jun Nakajima <jun.nakajima at 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/init.h>
++#include <linux/acpi.h>
++#include <linux/efi.h>
++#include <linux/module.h>
++#include <linux/dmi.h>
++#include <linux/irq.h>
++
++#include <asm/pgtable.h>
++#include <asm/io_apic.h>
++#include <asm/apic.h>
++#include <asm/io.h>
++#include <asm/mpspec.h>
++
++#ifdef CONFIG_X86_64
++
++extern void __init clustered_apic_check(void);
++
++extern int gsi_irq_sharing(int gsi);
++#include <asm/proto.h>
++
++static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return 0; }
++
++
++#else /* X86 */
++
++#ifdef CONFIG_X86_LOCAL_APIC
++#include <mach_apic.h>
++#include <mach_mpparse.h>
++#endif /* CONFIG_X86_LOCAL_APIC */
++
++static inline int gsi_irq_sharing(int gsi) { return gsi; }
++
++#endif /* X86 */
++
++#define BAD_MADT_ENTRY(entry, end) ( \
++ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
++ ((acpi_table_entry_header *)entry)->length < sizeof(*entry))
++
++#define PREFIX "ACPI: "
++
++int acpi_noirq __initdata; /* skip ACPI IRQ initialization */
++int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */
++int acpi_ht __initdata = 1; /* enable HT */
++
++int acpi_lapic;
++int acpi_ioapic;
++int acpi_strict;
++EXPORT_SYMBOL(acpi_strict);
++
++acpi_interrupt_flags acpi_sci_flags __initdata;
++int acpi_sci_override_gsi __initdata;
++int acpi_skip_timer_override __initdata;
++
++#ifdef CONFIG_X86_LOCAL_APIC
++static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
++#endif
++
++#ifndef __HAVE_ARCH_CMPXCHG
++#warning ACPI uses CMPXCHG, i486 and later hardware
++#endif
++
++#define MAX_MADT_ENTRIES 256
++u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
++ {[0 ... MAX_MADT_ENTRIES - 1] = 0xff };
++EXPORT_SYMBOL(x86_acpiid_to_apicid);
++
++/* --------------------------------------------------------------------------
++ Boot-time Configuration
++ -------------------------------------------------------------------------- */
++
++/*
++ * The default interrupt routing model is PIC (8259). This gets
++ * overriden if IOAPICs are enumerated (below).
++ */
++enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
++
++#if defined(CONFIG_X86_64) && !defined(CONFIG_XEN)
++
++/* rely on all ACPI tables being in the direct mapping */
++char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
++{
++ if (!phys_addr || !size)
++ return NULL;
++
++ if (phys_addr+size <= (end_pfn_map << PAGE_SHIFT) + PAGE_SIZE)
++ return __va(phys_addr);
++
++ return NULL;
++}
++
++#else
++
++/*
++ * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
++ * to map the target physical address. The problem is that set_fixmap()
++ * provides a single page, and it is possible that the page is not
++ * sufficient.
++ * By using this area, we can map up to MAX_IO_APICS pages temporarily,
++ * i.e. until the next __va_range() call.
++ *
++ * Important Safety Note: The fixed I/O APIC page numbers are *subtracted*
++ * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and
++ * count idx down while incrementing the phys address.
++ */
++char *__acpi_map_table(unsigned long phys, unsigned long size)
++{
++ unsigned long base, offset, mapped_size;
++ int idx;
++
++#ifndef CONFIG_XEN
++ if (phys + size < 8 * 1024 * 1024)
++ return __va(phys);
++#endif
++
++ offset = phys & (PAGE_SIZE - 1);
++ mapped_size = PAGE_SIZE - offset;
++ set_fixmap(FIX_ACPI_END, phys);
++ base = fix_to_virt(FIX_ACPI_END);
++
++ /*
++ * Most cases can be covered by the below.
++ */
++ idx = FIX_ACPI_END;
++ while (mapped_size < size) {
++ if (--idx < FIX_ACPI_BEGIN)
++ return NULL; /* cannot handle this */
++ phys += PAGE_SIZE;
++ set_fixmap(idx, phys);
++ mapped_size += PAGE_SIZE;
++ }
++
++ return ((unsigned char *)base + offset);
++}
++#endif
++
++#ifdef CONFIG_PCI_MMCONFIG
++/* 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;
++
++ mcfg = (struct acpi_table_mcfg *)__acpi_map_table(phys_addr, size);
++ if (!mcfg) {
++ printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
++ return -ENODEV;
++ }
++
++ /* 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;
++ }
++
++ 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");
++ kfree(pci_mmcfg_config);
++ pci_mmcfg_config_num = 0;
++ return -ENODEV;
++ }
++ }
++
++ return 0;
++}
++#endif /* CONFIG_PCI_MMCONFIG */
++
++#ifdef CONFIG_X86_LOCAL_APIC
++static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
++{
++ struct acpi_table_madt *madt = NULL;
++
++ if (!phys_addr || !size || !cpu_has_apic)
++ return -EINVAL;
++
++ madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size);
++ if (!madt) {
++ printk(KERN_WARNING PREFIX "Unable to map MADT\n");
++ return -ENODEV;
++ }
++
++ if (madt->lapic_address) {
++ acpi_lapic_addr = (u64) madt->lapic_address;
++
++ printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
++ madt->lapic_address);
++ }
++
++ acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
++
++ return 0;
++}
++
++static int __init
++acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
++{
++ struct acpi_table_lapic *processor = NULL;
++
++ processor = (struct acpi_table_lapic *)header;
++
++ if (BAD_MADT_ENTRY(processor, end))
++ return -EINVAL;
++
++ acpi_table_print_madt_entry(header);
++
++ /* Record local apic id only when enabled */
++ if (processor->flags.enabled)
++ x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
++
++ /*
++ * We need to register disabled CPU as well to permit
++ * counting disabled CPUs. This allows us to size
++ * cpus_possible_map more accurately, to permit
++ * to not preallocating memory for all NR_CPUS
++ * when we use CPU hotplug.
++ */
++ mp_register_lapic(processor->id, /* APIC ID */
++ processor->flags.enabled); /* Enabled? */
++
++ return 0;
++}
++
++static int __init
++acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
++ const unsigned long end)
++{
++ struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL;
++
++ lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header;
++
++ if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
++ return -EINVAL;
++
++ acpi_lapic_addr = lapic_addr_ovr->address;
++
++ return 0;
++}
++
++static int __init
++acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
++{
++ struct acpi_table_lapic_nmi *lapic_nmi = NULL;
++
++ lapic_nmi = (struct acpi_table_lapic_nmi *)header;
++
++ if (BAD_MADT_ENTRY(lapic_nmi, end))
++ return -EINVAL;
++
++ acpi_table_print_madt_entry(header);
++
++ if (lapic_nmi->lint != 1)
++ printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
++
++ return 0;
++}
++
++#endif /*CONFIG_X86_LOCAL_APIC */
++
++#ifdef CONFIG_X86_IO_APIC
++
++static int __init
++acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
++{
++ struct acpi_table_ioapic *ioapic = NULL;
++
++ ioapic = (struct acpi_table_ioapic *)header;
++
++ if (BAD_MADT_ENTRY(ioapic, end))
++ return -EINVAL;
++
++ acpi_table_print_madt_entry(header);
++
++ mp_register_ioapic(ioapic->id,
++ ioapic->address, ioapic->global_irq_base);
++
++ return 0;
++}
++
++/*
++ * Parse Interrupt Source Override for the ACPI SCI
++ */
++static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
++{
++ if (trigger == 0) /* compatible SCI trigger is level */
++ trigger = 3;
++
++ if (polarity == 0) /* compatible SCI polarity is low */
++ polarity = 3;
++
++ /* Command-line over-ride via acpi_sci= */
++ if (acpi_sci_flags.trigger)
++ trigger = acpi_sci_flags.trigger;
++
++ if (acpi_sci_flags.polarity)
++ polarity = acpi_sci_flags.polarity;
++
++ /*
++ * mp_config_acpi_legacy_irqs() already setup IRQs < 16
++ * If GSI is < 16, this will update its flags,
++ * else it will create a new mp_irqs[] entry.
++ */
++ mp_override_legacy_irq(gsi, polarity, trigger, gsi);
++
++ /*
++ * stash over-ride to indicate we've been here
++ * and for later update of acpi_fadt
++ */
++ acpi_sci_override_gsi = gsi;
++ return;
++}
++
++static int __init
++acpi_parse_int_src_ovr(acpi_table_entry_header * header,
++ const unsigned long end)
++{
++ struct acpi_table_int_src_ovr *intsrc = NULL;
++
++ intsrc = (struct acpi_table_int_src_ovr *)header;
++
++ if (BAD_MADT_ENTRY(intsrc, end))
++ return -EINVAL;
++
++ acpi_table_print_madt_entry(header);
++
++ if (intsrc->bus_irq == acpi_fadt.sci_int) {
++ acpi_sci_ioapic_setup(intsrc->global_irq,
++ intsrc->flags.polarity,
++ intsrc->flags.trigger);
++ return 0;
++ }
++
++ if (acpi_skip_timer_override &&
++ intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
++ printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
++ return 0;
++ }
++
++ mp_override_legacy_irq(intsrc->bus_irq,
++ intsrc->flags.polarity,
++ intsrc->flags.trigger, intsrc->global_irq);
++
++ return 0;
++}
++
++static int __init
++acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
++{
++ struct acpi_table_nmi_src *nmi_src = NULL;
++
++ nmi_src = (struct acpi_table_nmi_src *)header;
++
++ if (BAD_MADT_ENTRY(nmi_src, end))
++ return -EINVAL;
++
++ acpi_table_print_madt_entry(header);
++
++ /* TBD: Support nimsrc entries? */
++
++ return 0;
++}
++
++#endif /* CONFIG_X86_IO_APIC */
++
++/*
++ * acpi_pic_sci_set_trigger()
++ *
++ * use ELCR to set PIC-mode trigger type for SCI
++ *
++ * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
++ * it may require Edge Trigger -- use "acpi_sci=edge"
++ *
++ * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
++ * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
++ * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0)
++ * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
++ */
++
++void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
++{
++ unsigned int mask = 1 << irq;
++ unsigned int old, new;
++
++ /* Real old ELCR mask */
++ old = inb(0x4d0) | (inb(0x4d1) << 8);
++
++ /*
++ * If we use ACPI to set PCI irq's, then we should clear ELCR
++ * since we will set it correctly as we enable the PCI irq
++ * routing.
++ */
++ new = acpi_noirq ? old : 0;
++
++ /*
++ * Update SCI information in the ELCR, it isn't in the PCI
++ * routing tables..
++ */
++ switch (trigger) {
++ case 1: /* Edge - clear */
++ new &= ~mask;
++ break;
++ case 3: /* Level - set */
++ new |= mask;
++ break;
++ }
++
++ if (old == new)
++ return;
++
++ printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
++ outb(new, 0x4d0);
++ outb(new >> 8, 0x4d1);
++}
++
++int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
++{
++#ifdef CONFIG_X86_IO_APIC
++ if (use_pci_vector() && !platform_legacy_irq(gsi))
++ *irq = IO_APIC_VECTOR(gsi);
++ else
++#endif
++ *irq = gsi_irq_sharing(gsi);
++ return 0;
++}
++
++/*
++ * success: return IRQ number (>=0)
++ * failure: return < 0
++ */
++int acpi_register_gsi(u32 gsi, int triggering, int polarity)
++{
++ unsigned int irq;
++ unsigned int plat_gsi = gsi;
++
++#ifdef CONFIG_PCI
++ /*
++ * Make sure all (legacy) PCI IRQs are set as level-triggered.
++ */
++ if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
++ extern void eisa_set_level_irq(unsigned int irq);
++
++ if (triggering == ACPI_LEVEL_SENSITIVE)
++ eisa_set_level_irq(gsi);
++ }
++#endif
++
++#ifdef CONFIG_X86_IO_APIC
++ if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
++ plat_gsi = mp_register_gsi(gsi, triggering, polarity);
++ }
++#endif
++ acpi_gsi_to_irq(plat_gsi, &irq);
++ return irq;
++}
++
++EXPORT_SYMBOL(acpi_register_gsi);
++
++/*
++ * ACPI based hotplug support for CPU
++ */
++#ifdef CONFIG_ACPI_HOTPLUG_CPU
++int acpi_map_lsapic(acpi_handle handle, int *pcpu)
++{
++ /* TBD */
++ return -EINVAL;
++}
++
++EXPORT_SYMBOL(acpi_map_lsapic);
++
++int acpi_unmap_lsapic(int cpu)
++{
++ /* TBD */
++ return -EINVAL;
++}
++
++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, unsigned long length)
++{
++ unsigned long offset = 0;
++ unsigned long sig_len = sizeof("RSD PTR ") - 1;
++ unsigned long vstart = (unsigned long)isa_bus_to_virt(start);
++
++ /*
++ * Scan all 16-byte boundaries of the physical memory region for the
++ * RSDP signature.
++ */
++ for (offset = 0; offset < length; offset += 16) {
++ if (strncmp((char *)(vstart + offset), "RSD PTR ", sig_len))
++ continue;
++ return (start + offset);
++ }
++
++ return 0;
++}
++
++static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
++{
++ struct acpi_table_sbf *sb;
++
++ if (!phys_addr || !size)
++ return -EINVAL;
++
++ sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size);
++ if (!sb) {
++ printk(KERN_WARNING PREFIX "Unable to map SBF\n");
++ return -ENODEV;
++ }
++
++ sbf_port = sb->sbf_cmos; /* Save CMOS port */
++
++ return 0;
++}
++
++#ifdef CONFIG_HPET_TIMER
++
++static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
++{
++ struct acpi_table_hpet *hpet_tbl;
++
++ if (!phys || !size)
++ return -EINVAL;
++
++ hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size);
++ if (!hpet_tbl) {
++ printk(KERN_WARNING PREFIX "Unable to map HPET\n");
++ return -ENODEV;
++ }
++
++ if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
++ printk(KERN_WARNING PREFIX "HPET timers must be located in "
++ "memory.\n");
++ return -1;
++ }
++#ifdef CONFIG_X86_64
++ vxtime.hpet_address = hpet_tbl->addr.addrl |
++ ((long)hpet_tbl->addr.addrh << 32);
++
++ printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
++ hpet_tbl->id, vxtime.hpet_address);
++#else /* X86 */
++ {
++ extern unsigned long hpet_address;
++
++ hpet_address = hpet_tbl->addr.addrl;
++ printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
++ hpet_tbl->id, hpet_address);
++ }
++#endif /* X86 */
++
++ return 0;
++}
++#else
++#define acpi_parse_hpet NULL
++#endif
++
++#ifdef CONFIG_X86_PM_TIMER
++extern u32 pmtmr_ioport;
++#endif
++
++static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
++{
++ struct fadt_descriptor *fadt = NULL;
++
++ fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size);
++ if (!fadt) {
++ printk(KERN_WARNING PREFIX "Unable to map FADT\n");
++ return 0;
++ }
++ /* initialize sci_int early for INT_SRC_OVR MADT parsing */
++ acpi_fadt.sci_int = fadt->sci_int;
++
++ /* initialize rev and apic_phys_dest_mode for x86_64 genapic */
++ acpi_fadt.revision = fadt->revision;
++ acpi_fadt.force_apic_physical_destination_mode =
++ fadt->force_apic_physical_destination_mode;
++
++#if defined(CONFIG_X86_PM_TIMER) && !defined(CONFIG_XEN)
++ /* detect the location of the ACPI PM Timer */
++ if (fadt->revision >= FADT2_REVISION_ID) {
++ /* FADT rev. 2 */
++ if (fadt->xpm_tmr_blk.address_space_id !=
++ ACPI_ADR_SPACE_SYSTEM_IO)
++ return 0;
++
++ pmtmr_ioport = fadt->xpm_tmr_blk.address;
++ /*
++ * "X" fields are optional extensions to the original V1.0
++ * fields, so we must selectively expand V1.0 fields if the
++ * corresponding X field is zero.
++ */
++ if (!pmtmr_ioport)
++ pmtmr_ioport = fadt->V1_pm_tmr_blk;
++ } else {
++ /* FADT rev. 1 */
++ pmtmr_ioport = fadt->V1_pm_tmr_blk;
++ }
++ if (pmtmr_ioport)
++ printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
++ pmtmr_ioport);
++#endif
++ return 0;
++}
++
++unsigned long __init acpi_find_rsdp(void)
++{
++ unsigned long rsdp_phys = 0;
++
++ if (efi_enabled) {
++ if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
++ return efi.acpi20;
++ else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
++ return efi.acpi;
++ }
++ /*
++ * Scan memory looking for the RSDP signature. First search EBDA (low
++ * memory) paragraphs and then search upper memory (E0000-FFFFF).
++ */
++ rsdp_phys = acpi_scan_rsdp(0, 0x400);
++ if (!rsdp_phys)
++ rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
++
++ return rsdp_phys;
++}
++
++#ifdef CONFIG_X86_LOCAL_APIC
++/*
++ * Parse LAPIC entries in MADT
++ * returns 0 on success, < 0 on error
++ */
++static int __init acpi_parse_madt_lapic_entries(void)
++{
++ int count;
++
++ if (!cpu_has_apic)
++ return -ENODEV;
++
++ /*
++ * Note that the LAPIC address is obtained from the MADT (32-bit value)
++ * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
++ */
++
++ count =
++ acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR,
++ acpi_parse_lapic_addr_ovr, 0);
++ if (count < 0) {
++ printk(KERN_ERR PREFIX
++ "Error parsing LAPIC address override entry\n");
++ return count;
++ }
++
++ mp_register_lapic_address(acpi_lapic_addr);
++
++ count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
++ MAX_APICS);
++ if (!count) {
++ printk(KERN_ERR PREFIX "No LAPIC entries present\n");
++ /* TBD: Cleanup to allow fallback to MPS */
++ return -ENODEV;
++ } else if (count < 0) {
++ printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
++ /* TBD: Cleanup to allow fallback to MPS */
++ return count;
++ }
++
++ count =
++ acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
++ if (count < 0) {
++ printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
++ /* TBD: Cleanup to allow fallback to MPS */
++ return count;
++ }
++ return 0;
++}
++#endif /* CONFIG_X86_LOCAL_APIC */
++
++#ifdef CONFIG_X86_IO_APIC
++/*
++ * Parse IOAPIC related entries in MADT
++ * returns 0 on success, < 0 on error
++ */
++static int __init acpi_parse_madt_ioapic_entries(void)
++{
++ int count;
++
++ /*
++ * ACPI interpreter is required to complete interrupt setup,
++ * so if it is off, don't enumerate the io-apics with ACPI.
++ * If MPS is present, it will handle them,
++ * otherwise the system will stay in PIC mode
++ */
++ if (acpi_disabled || acpi_noirq) {
++ return -ENODEV;
++ }
++
++ if (!cpu_has_apic)
++ return -ENODEV;
++
++ /*
++ * if "noapic" boot option, don't look for IO-APICs
++ */
++ if (skip_ioapic_setup) {
++ printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
++ "due to 'noapic' option.\n");
++ return -ENODEV;
++ }
++
++ count =
++ acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic,
++ MAX_IO_APICS);
++ if (!count) {
++ printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
++ return -ENODEV;
++ } else if (count < 0) {
++ printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
++ return count;
++ }
++
++ count =
++ acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr,
++ NR_IRQ_VECTORS);
++ if (count < 0) {
++ printk(KERN_ERR PREFIX
++ "Error parsing interrupt source overrides entry\n");
++ /* TBD: Cleanup to allow fallback to MPS */
++ return count;
++ }
++
++ /*
++ * If BIOS did not supply an INT_SRC_OVR for the SCI
++ * pretend we got one so we can set the SCI flags.
++ */
++ if (!acpi_sci_override_gsi)
++ acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
++
++ /* Fill in identity legacy mapings where no override */
++ mp_config_acpi_legacy_irqs();
++
++ count =
++ acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src,
++ NR_IRQ_VECTORS);
++ if (count < 0) {
++ printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
++ /* TBD: Cleanup to allow fallback to MPS */
++ return count;
++ }
++
++ return 0;
++}
++#else
++static inline int acpi_parse_madt_ioapic_entries(void)
++{
++ return -1;
++}
++#endif /* !CONFIG_X86_IO_APIC */
++
++static void __init acpi_process_madt(void)
++{
++#ifdef CONFIG_X86_LOCAL_APIC
++ int count, error;
++
++ count = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
++ if (count >= 1) {
++
++ /*
++ * Parse MADT LAPIC entries
++ */
++ error = acpi_parse_madt_lapic_entries();
++ if (!error) {
++ acpi_lapic = 1;
++
++#ifdef CONFIG_X86_GENERICARCH
++ generic_bigsmp_probe();
++#endif
++ /*
++ * Parse MADT IO-APIC entries
++ */
++ error = acpi_parse_madt_ioapic_entries();
++ if (!error) {
++ acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
++ acpi_irq_balance_set(NULL);
++ acpi_ioapic = 1;
++
++ smp_found_config = 1;
++ clustered_apic_check();
++ }
++ }
++ if (error == -EINVAL) {
++ /*
++ * Dell Precision Workstation 410, 610 come here.
++ */
++ printk(KERN_ERR PREFIX
++ "Invalid BIOS MADT, disabling ACPI\n");
++ disable_acpi();
++ }
++ }
++#endif
++ return;
++}
++
++extern int acpi_force;
++
++#ifdef __i386__
++
++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;
++}
++
++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 at 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"),
++ },
++ },
++
++ /*
++ * 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 /* __i386__ */
++
++/*
++ * acpi_boot_table_init() and acpi_boot_init()
++ * called from setup_arch(), always.
++ * 1. checksums all tables
++ * 2. enumerates lapics
++ * 3. enumerates io-apics
++ *
++ * acpi_table_init() is separate to allow reading SRAT without
++ * other side effects.
++ *
++ * side effects of acpi_boot_init:
++ * acpi_lapic = 1 if LAPIC found
++ * acpi_ioapic = 1 if IOAPIC found
++ * if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
++ * if acpi_blacklisted() acpi_disabled = 1;
++ * acpi_irq_model=...
++ * ...
++ *
++ * return value: (currently ignored)
++ * 0: success
++ * !0: failure
++ */
++
++int __init 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
++ */
++ if (acpi_disabled && !acpi_ht)
++ return 1;
++
++ /*
++ * Initialize the ACPI boot-time table parser.
++ */
++ error = acpi_table_init();
++ if (error) {
++ disable_acpi();
++ return error;
++ }
++
++ acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
++
++ /*
++ * blacklist may disable ACPI entirely
++ */
++ error = acpi_blacklisted();
++ if (error) {
++ if (acpi_force) {
++ printk(KERN_WARNING PREFIX "acpi=force override\n");
++ } else {
++ printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
++ disable_acpi();
++ return error;
++ }
++ }
++
++ return 0;
++}
++
++int __init acpi_boot_init(void)
++{
++ /*
++ * If acpi_disabled, bail out
++ * One exception: acpi=ht continues far enough to enumerate LAPICs
++ */
++ if (acpi_disabled && !acpi_ht)
++ return 1;
++
++ acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
++
++ /*
++ * set sci_int and PM timer address
++ */
++ acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
++
++ /*
++ * Process the Multiple APIC Description Table (MADT), if present
++ */
++ acpi_process_madt();
++
++ acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/acpi/Makefile linux-2.6.18-xen/arch/i386/kernel/acpi/Makefile
+--- linux-2.6.18.1/arch/i386/kernel/acpi/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/acpi/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -6,3 +6,7 @@
+ obj-y += cstate.o processor.o
+ endif
+
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++obj-y := $(call cherrypickxen, $(obj-y), $(src))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/alternative.c linux-2.6.18-xen/arch/i386/kernel/alternative.c
+--- linux-2.6.18.1/arch/i386/kernel/alternative.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/alternative.c 2006-09-04 16:31:00.000000000 +0200
+@@ -4,7 +4,11 @@
+ #include <asm/alternative.h>
+ #include <asm/sections.h>
+
++#ifdef CONFIG_X86_64_XEN
++static int no_replacement = 1;
++#else
+ static int no_replacement = 0;
++#endif
+ static int smp_alt_once = 0;
+ static int debug_alternative = 0;
+
+@@ -151,7 +155,11 @@
+ #ifdef CONFIG_X86_64
+ /* vsyscall code is not mapped yet. resolve it manually. */
+ if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END) {
++#ifdef CONFIG_XEN
++ instr = __va(instr - (u8*)VSYSCALL_START + (u8*)phys_to_machine(__pa_symbol(&__vsyscall_0)));
++#else
+ instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0));
++#endif
+ DPRINTK("%s: vsyscall fixup: %p => %p\n",
+ __FUNCTION__, a->instr, instr);
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/apic-xen.c linux-2.6.18-xen/arch/i386/kernel/apic-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/apic-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/apic-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,160 @@
++/*
++ * Local APIC handling, local APIC timers
++ *
++ * (c) 1999, 2000 Ingo Molnar <mingo at redhat.com>
++ *
++ * Fixes
++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
++ * thanks to Eric Gilmore
++ * and Rolf G. Tews
++ * for testing these extensively.
++ * Maciej W. Rozycki : Various updates and fixes.
++ * Mikael Pettersson : Power Management for UP-APIC.
++ * Pavel Machek and
++ * Mikael Pettersson : PM converted to driver model.
++ */
++
++#include <linux/init.h>
++
++#include <linux/mm.h>
++#include <linux/delay.h>
++#include <linux/bootmem.h>
++#include <linux/smp_lock.h>
++#include <linux/interrupt.h>
++#include <linux/mc146818rtc.h>
++#include <linux/kernel_stat.h>
++#include <linux/sysdev.h>
++#include <linux/cpu.h>
++#include <linux/module.h>
++
++#include <asm/atomic.h>
++#include <asm/smp.h>
++#include <asm/mtrr.h>
++#include <asm/mpspec.h>
++#include <asm/desc.h>
++#include <asm/arch_hooks.h>
++#include <asm/hpet.h>
++#include <asm/i8253.h>
++#include <asm/nmi.h>
++
++#include <mach_apic.h>
++#include <mach_apicdef.h>
++#include <mach_ipi.h>
++
++#include "io_ports.h"
++
++#ifndef CONFIG_XEN
++/*
++ * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
++ * IPIs in place of local APIC timers
++ */
++static cpumask_t timer_bcast_ipi;
++#endif
++
++/*
++ * 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;
++
++static int modern_apic(void)
++{
++#ifndef CONFIG_XEN
++ unsigned int lvr, version;
++ /* AMD systems use old APIC versions, so check the CPU */
++ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
++ boot_cpu_data.x86 >= 0xf)
++ return 1;
++ lvr = apic_read(APIC_LVR);
++ version = GET_APIC_VERSION(lvr);
++ return version >= 0x14;
++#else
++ return 1;
++#endif
++}
++
++/*
++ * '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);
++ /*
++ * Currently unexpected vectors happen only on SMP and APIC.
++ * We _must_ ack these because every local APIC has only N
++ * irq slots per priority level, and a 'hanging, unacked' IRQ
++ * holds up an irq slot - in excessive cases (when multiple
++ * unexpected vectors occur) that might lock up the APIC
++ * completely.
++ * But only ack when the APIC is enabled -AK
++ */
++ if (cpu_has_apic)
++ ack_APIC_irq();
++}
++
++int get_physical_broadcast(void)
++{
++ if (modern_apic())
++ return 0xff;
++ else
++ return 0xf;
++}
++
++#ifndef CONFIG_XEN
++#ifndef CONFIG_SMP
++static void up_apic_timer_interrupt_call(struct pt_regs *regs)
++{
++ int cpu = smp_processor_id();
++
++ /*
++ * the NMI deadlock-detector uses this.
++ */
++ per_cpu(irq_stat, cpu).apic_timer_irqs++;
++
++ smp_local_timer_interrupt(regs);
++}
++#endif
++
++void smp_send_timer_broadcast_ipi(struct pt_regs *regs)
++{
++ cpumask_t mask;
++
++ cpus_and(mask, cpu_online_map, timer_bcast_ipi);
++ if (!cpus_empty(mask)) {
++#ifdef CONFIG_SMP
++ send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
++#else
++ /*
++ * We can directly call the apic timer interrupt handler
++ * in UP case. Minus all irq related functions
++ */
++ up_apic_timer_interrupt_call(regs);
++#endif
++ }
++}
++#endif
++
++int setup_profiling_timer(unsigned int multiplier)
++{
++ return -EINVAL;
++}
++
++/*
++ * This initializes the IO-APIC and APIC hardware if this is
++ * a UP kernel.
++ */
++int __init APIC_init_uniprocessor (void)
++{
++#ifdef CONFIG_X86_IO_APIC
++ if (smp_found_config)
++ if (!skip_ioapic_setup && nr_ioapics)
++ setup_IO_APIC();
++#endif
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/asm-offsets.c linux-2.6.18-xen/arch/i386/kernel/asm-offsets.c
+--- linux-2.6.18.1/arch/i386/kernel/asm-offsets.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/asm-offsets.c 2006-09-04 16:31:00.000000000 +0200
+@@ -66,9 +66,14 @@
+ OFFSET(pbe_orig_address, pbe, orig_address);
+ OFFSET(pbe_next, pbe, next);
+
++#ifndef CONFIG_X86_NO_TSS
+ /* Offset from the sysenter stack to tss.esp0 */
+- DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) -
++ DEFINE(SYSENTER_stack_esp0, offsetof(struct tss_struct, esp0) -
+ sizeof(struct tss_struct));
++#else
++ /* sysenter stack points directly to esp0 */
++ DEFINE(SYSENTER_stack_esp0, 0);
++#endif
+
+ DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
+ DEFINE(VDSO_PRELINK, VDSO_PRELINK);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/cpu/common-xen.c linux-2.6.18-xen/arch/i386/kernel/cpu/common-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/cpu/common-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/cpu/common-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,739 @@
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/delay.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/percpu.h>
++#include <linux/bootmem.h>
++#include <asm/semaphore.h>
++#include <asm/processor.h>
++#include <asm/i387.h>
++#include <asm/msr.h>
++#include <asm/io.h>
++#include <asm/mmu_context.h>
++#include <asm/mtrr.h>
++#include <asm/mce.h>
++#ifdef CONFIG_X86_LOCAL_APIC
++#include <asm/mpspec.h>
++#include <asm/apic.h>
++#include <mach_apic.h>
++#endif
++#include <asm/hypervisor.h>
++
++#include "cpu.h"
++
++DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
++EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
++
++#ifndef CONFIG_XEN
++DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
++EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
++#endif
++
++static int cachesize_override __cpuinitdata = -1;
++static int disable_x86_fxsr __cpuinitdata;
++static int disable_x86_serial_nr __cpuinitdata = 1;
++static int disable_x86_sep __cpuinitdata;
++
++struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
++
++extern int disable_pse;
++
++static void default_init(struct cpuinfo_x86 * c)
++{
++ /* Not much we can do here... */
++ /* Check if at least it has cpuid */
++ if (c->cpuid_level == -1) {
++ /* No cpuid. It must be an ancient CPU */
++ if (c->x86 == 4)
++ strcpy(c->x86_model_id, "486");
++ else if (c->x86 == 3)
++ strcpy(c->x86_model_id, "386");
++ }
++}
++
++static struct cpu_dev default_cpu = {
++ .c_init = default_init,
++ .c_vendor = "Unknown",
++};
++static struct cpu_dev * this_cpu = &default_cpu;
++
++static int __init cachesize_setup(char *str)
++{
++ get_option (&str, &cachesize_override);
++ return 1;
++}
++__setup("cachesize=", cachesize_setup);
++
++int __cpuinit get_model_name(struct cpuinfo_x86 *c)
++{
++ unsigned int *v;
++ char *p, *q;
++
++ if (cpuid_eax(0x80000000) < 0x80000004)
++ return 0;
++
++ v = (unsigned int *) c->x86_model_id;
++ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
++ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
++ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
++ c->x86_model_id[48] = 0;
++
++ /* Intel chips right-justify this string for some dumb reason;
++ undo that brain damage */
++ p = q = &c->x86_model_id[0];
++ while ( *p == ' ' )
++ p++;
++ if ( p != q ) {
++ while ( *p )
++ *q++ = *p++;
++ while ( q <= &c->x86_model_id[48] )
++ *q++ = '\0'; /* Zero-pad the rest */
++ }
++
++ return 1;
++}
++
++
++void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
++{
++ unsigned int n, dummy, ecx, edx, l2size;
++
++ n = cpuid_eax(0x80000000);
++
++ if (n >= 0x80000005) {
++ cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
++ printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
++ edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
++ c->x86_cache_size=(ecx>>24)+(edx>>24);
++ }
++
++ if (n < 0x80000006) /* Some chips just has a large L1. */
++ return;
++
++ ecx = cpuid_ecx(0x80000006);
++ l2size = ecx >> 16;
++
++ /* do processor-specific cache resizing */
++ if (this_cpu->c_size_cache)
++ l2size = this_cpu->c_size_cache(c,l2size);
++
++ /* Allow user to override all this if necessary. */
++ if (cachesize_override != -1)
++ l2size = cachesize_override;
++
++ if ( l2size == 0 )
++ return; /* Again, no L2 cache is possible */
++
++ c->x86_cache_size = l2size;
++
++ printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
++ l2size, ecx & 0xFF);
++}
++
++/* Naming convention should be: <Name> [(<Codename>)] */
++/* This table only is used unless init_<vendor>() below doesn't set it; */
++/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
++
++/* Look up CPU names by table lookup. */
++static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)
++{
++ struct cpu_model_info *info;
++
++ if ( c->x86_model >= 16 )
++ return NULL; /* Range check */
++
++ if (!this_cpu)
++ return NULL;
++
++ info = this_cpu->c_models;
++
++ while (info && info->family) {
++ if (info->family == c->x86)
++ return info->model_names[c->x86_model];
++ info++;
++ }
++ return NULL; /* Not found */
++}
++
++
++static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
++{
++ char *v = c->x86_vendor_id;
++ int i;
++ static int printed;
++
++ for (i = 0; i < X86_VENDOR_NUM; i++) {
++ if (cpu_devs[i]) {
++ if (!strcmp(v,cpu_devs[i]->c_ident[0]) ||
++ (cpu_devs[i]->c_ident[1] &&
++ !strcmp(v,cpu_devs[i]->c_ident[1]))) {
++ c->x86_vendor = i;
++ if (!early)
++ this_cpu = cpu_devs[i];
++ return;
++ }
++ }
++ }
++ if (!printed) {
++ printed++;
++ printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
++ printk(KERN_ERR "CPU: Your system may be unstable.\n");
++ }
++ c->x86_vendor = X86_VENDOR_UNKNOWN;
++ this_cpu = &default_cpu;
++}
++
++
++static int __init x86_fxsr_setup(char * s)
++{
++ disable_x86_fxsr = 1;
++ return 1;
++}
++__setup("nofxsr", x86_fxsr_setup);
++
++
++static int __init x86_sep_setup(char * s)
++{
++ disable_x86_sep = 1;
++ return 1;
++}
++__setup("nosep", x86_sep_setup);
++
++
++/* Standard macro to see if a specific flag is changeable */
++static inline int flag_is_changeable_p(u32 flag)
++{
++ u32 f1, f2;
++
++ asm("pushfl\n\t"
++ "pushfl\n\t"
++ "popl %0\n\t"
++ "movl %0,%1\n\t"
++ "xorl %2,%0\n\t"
++ "pushl %0\n\t"
++ "popfl\n\t"
++ "pushfl\n\t"
++ "popl %0\n\t"
++ "popfl\n\t"
++ : "=&r" (f1), "=&r" (f2)
++ : "ir" (flag));
++
++ return ((f1^f2) & flag) != 0;
++}
++
++
++/* Probe for the CPUID instruction */
++static int __cpuinit have_cpuid_p(void)
++{
++ return flag_is_changeable_p(X86_EFLAGS_ID);
++}
++
++/* Do minimum CPU detection early.
++ Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
++ The others are not touched to avoid unwanted side effects.
++
++ WARNING: this function is only called on the BP. Don't add code here
++ that is supposed to run on all CPUs. */
++static void __init early_cpu_detect(void)
++{
++ struct cpuinfo_x86 *c = &boot_cpu_data;
++
++ c->x86_cache_alignment = 32;
++
++ if (!have_cpuid_p())
++ return;
++
++ /* Get vendor name */
++ cpuid(0x00000000, &c->cpuid_level,
++ (int *)&c->x86_vendor_id[0],
++ (int *)&c->x86_vendor_id[8],
++ (int *)&c->x86_vendor_id[4]);
++
++ get_cpu_vendor(c, 1);
++
++ c->x86 = 4;
++ if (c->cpuid_level >= 0x00000001) {
++ u32 junk, tfms, cap0, misc;
++ cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
++ c->x86 = (tfms >> 8) & 15;
++ c->x86_model = (tfms >> 4) & 15;
++ if (c->x86 == 0xf)
++ c->x86 += (tfms >> 20) & 0xff;
++ if (c->x86 >= 0x6)
++ c->x86_model += ((tfms >> 16) & 0xF) << 4;
++ c->x86_mask = tfms & 15;
++ if (cap0 & (1<<19))
++ c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
++ }
++}
++
++void __cpuinit generic_identify(struct cpuinfo_x86 * c)
++{
++ u32 tfms, xlvl;
++ int ebx;
++
++ if (have_cpuid_p()) {
++ /* Get vendor name */
++ cpuid(0x00000000, &c->cpuid_level,
++ (int *)&c->x86_vendor_id[0],
++ (int *)&c->x86_vendor_id[8],
++ (int *)&c->x86_vendor_id[4]);
++
++ get_cpu_vendor(c, 0);
++ /* Initialize the standard set of capabilities */
++ /* Note that the vendor-specific code below might override */
++
++ /* Intel-defined flags: level 0x00000001 */
++ if ( c->cpuid_level >= 0x00000001 ) {
++ u32 capability, excap;
++ cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
++ c->x86_capability[0] = capability;
++ c->x86_capability[4] = excap;
++ c->x86 = (tfms >> 8) & 15;
++ c->x86_model = (tfms >> 4) & 15;
++ if (c->x86 == 0xf)
++ c->x86 += (tfms >> 20) & 0xff;
++ if (c->x86 >= 0x6)
++ c->x86_model += ((tfms >> 16) & 0xF) << 4;
++ c->x86_mask = tfms & 15;
++#ifdef CONFIG_X86_HT
++ c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
++#else
++ c->apicid = (ebx >> 24) & 0xFF;
++#endif
++ } else {
++ /* Have CPUID level 0 only - unheard of */
++ c->x86 = 4;
++ }
++
++ /* AMD-defined flags: level 0x80000001 */
++ xlvl = cpuid_eax(0x80000000);
++ if ( (xlvl & 0xffff0000) == 0x80000000 ) {
++ if ( xlvl >= 0x80000001 ) {
++ c->x86_capability[1] = cpuid_edx(0x80000001);
++ c->x86_capability[6] = cpuid_ecx(0x80000001);
++ }
++ if ( xlvl >= 0x80000004 )
++ get_model_name(c); /* Default name */
++ }
++ }
++
++ early_intel_workaround(c);
++
++#ifdef CONFIG_X86_HT
++ c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
++#endif
++}
++
++static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
++{
++ if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
++ /* Disable processor serial number */
++ unsigned long lo,hi;
++ rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
++ lo |= 0x200000;
++ wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
++ printk(KERN_NOTICE "CPU serial number disabled.\n");
++ clear_bit(X86_FEATURE_PN, c->x86_capability);
++
++ /* Disabling the serial number may affect the cpuid level */
++ c->cpuid_level = cpuid_eax(0);
++ }
++}
++
++static int __init x86_serial_nr_setup(char *s)
++{
++ disable_x86_serial_nr = 0;
++ return 1;
++}
++__setup("serialnumber", x86_serial_nr_setup);
++
++
++
++/*
++ * This does the hard work of actually picking apart the CPU stuff...
++ */
++void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
++{
++ int i;
++
++ c->loops_per_jiffy = loops_per_jiffy;
++ c->x86_cache_size = -1;
++ c->x86_vendor = X86_VENDOR_UNKNOWN;
++ c->cpuid_level = -1; /* CPUID not detected */
++ c->x86_model = c->x86_mask = 0; /* So far unknown... */
++ c->x86_vendor_id[0] = '\0'; /* Unset */
++ c->x86_model_id[0] = '\0'; /* Unset */
++ c->x86_max_cores = 1;
++ memset(&c->x86_capability, 0, sizeof c->x86_capability);
++
++ if (!have_cpuid_p()) {
++ /* First of all, decide if this is a 486 or higher */
++ /* It's a 486 if we can modify the AC flag */
++ if ( flag_is_changeable_p(X86_EFLAGS_AC) )
++ c->x86 = 4;
++ else
++ c->x86 = 3;
++ }
++
++ generic_identify(c);
++
++ printk(KERN_DEBUG "CPU: After generic identify, caps:");
++ for (i = 0; i < NCAPINTS; i++)
++ printk(" %08lx", c->x86_capability[i]);
++ printk("\n");
++
++ if (this_cpu->c_identify) {
++ this_cpu->c_identify(c);
++
++ printk(KERN_DEBUG "CPU: After vendor identify, caps:");
++ for (i = 0; i < NCAPINTS; i++)
++ printk(" %08lx", c->x86_capability[i]);
++ printk("\n");
++ }
++
++ /*
++ * Vendor-specific initialization. In this section we
++ * canonicalize the feature flags, meaning if there are
++ * features a certain CPU supports which CPUID doesn't
++ * tell us, CPUID claiming incorrect flags, or other bugs,
++ * we handle them here.
++ *
++ * At the end of this section, c->x86_capability better
++ * indicate the features this CPU genuinely supports!
++ */
++ if (this_cpu->c_init)
++ this_cpu->c_init(c);
++
++ /* Disable the PN if appropriate */
++ squash_the_stupid_serial_number(c);
++
++ /*
++ * The vendor-specific functions might have changed features. Now
++ * we do "generic changes."
++ */
++
++ /* TSC disabled? */
++ if ( tsc_disable )
++ clear_bit(X86_FEATURE_TSC, c->x86_capability);
++
++ /* FXSR disabled? */
++ if (disable_x86_fxsr) {
++ clear_bit(X86_FEATURE_FXSR, c->x86_capability);
++ clear_bit(X86_FEATURE_XMM, c->x86_capability);
++ }
++
++ /* SEP disabled? */
++ if (disable_x86_sep)
++ clear_bit(X86_FEATURE_SEP, c->x86_capability);
++
++ if (disable_pse)
++ clear_bit(X86_FEATURE_PSE, c->x86_capability);
++
++ /* If the model name is still unset, do table lookup. */
++ if ( !c->x86_model_id[0] ) {
++ char *p;
++ p = table_lookup_model(c);
++ if ( p )
++ strcpy(c->x86_model_id, p);
++ else
++ /* Last resort... */
++ sprintf(c->x86_model_id, "%02x/%02x",
++ c->x86, c->x86_model);
++ }
++
++ /* Now the feature flags better reflect actual CPU features! */
++
++ printk(KERN_DEBUG "CPU: After all inits, caps:");
++ for (i = 0; i < NCAPINTS; i++)
++ printk(" %08lx", c->x86_capability[i]);
++ printk("\n");
++
++ /*
++ * On SMP, boot_cpu_data holds the common feature set between
++ * all CPUs; so make sure that we indicate which features are
++ * common between the CPUs. The first time this routine gets
++ * executed, c == &boot_cpu_data.
++ */
++ if ( c != &boot_cpu_data ) {
++ /* AND the already accumulated flags with these */
++ for ( i = 0 ; i < NCAPINTS ; i++ )
++ boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
++ }
++
++ /* Init Machine Check Exception if available. */
++ mcheck_init(c);
++
++ 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 __cpuinit detect_ht(struct cpuinfo_x86 *c)
++{
++ u32 eax, ebx, ecx, edx;
++ int index_msb, core_bits;
++
++ cpuid(1, &eax, &ebx, &ecx, &edx);
++
++ if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
++ return;
++
++ smp_num_siblings = (ebx & 0xff0000) >> 16;
++
++ if (smp_num_siblings == 1) {
++ printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
++ } else if (smp_num_siblings > 1 ) {
++
++ if (smp_num_siblings > NR_CPUS) {
++ printk(KERN_WARNING "CPU: Unsupported number of the "
++ "siblings %d", smp_num_siblings);
++ smp_num_siblings = 1;
++ return;
++ }
++
++ index_msb = get_count_order(smp_num_siblings);
++ c->phys_proc_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
++
++ printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
++ c->phys_proc_id);
++
++ smp_num_siblings = smp_num_siblings / c->x86_max_cores;
++
++ index_msb = get_count_order(smp_num_siblings) ;
++
++ core_bits = get_count_order(c->x86_max_cores);
++
++ c->cpu_core_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
++ ((1 << core_bits) - 1);
++
++ if (c->x86_max_cores > 1)
++ printk(KERN_INFO "CPU: Processor Core ID: %d\n",
++ c->cpu_core_id);
++ }
++}
++#endif
++
++void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
++{
++ char *vendor = NULL;
++
++ if (c->x86_vendor < X86_VENDOR_NUM)
++ vendor = this_cpu->c_vendor;
++ else if (c->cpuid_level >= 0)
++ vendor = c->x86_vendor_id;
++
++ if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
++ printk("%s ", vendor);
++
++ if (!c->x86_model_id[0])
++ printk("%d86", c->x86);
++ else
++ printk("%s", c->x86_model_id);
++
++ if (c->x86_mask || c->cpuid_level >= 0)
++ printk(" stepping %02x\n", c->x86_mask);
++ else
++ printk("\n");
++}
++
++cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
++
++/* This is hacky. :)
++ * We're emulating future behavior.
++ * In the future, the cpu-specific init functions will be called implicitly
++ * via the magic of initcalls.
++ * They will insert themselves into the cpu_devs structure.
++ * Then, when cpu_init() is called, we can just iterate over that array.
++ */
++
++extern int intel_cpu_init(void);
++extern int cyrix_init_cpu(void);
++extern int nsc_init_cpu(void);
++extern int amd_init_cpu(void);
++extern int centaur_init_cpu(void);
++extern int transmeta_init_cpu(void);
++extern int rise_init_cpu(void);
++extern int nexgen_init_cpu(void);
++extern int umc_init_cpu(void);
++
++void __init early_cpu_init(void)
++{
++ intel_cpu_init();
++ cyrix_init_cpu();
++ nsc_init_cpu();
++ amd_init_cpu();
++ centaur_init_cpu();
++ transmeta_init_cpu();
++ rise_init_cpu();
++ nexgen_init_cpu();
++ umc_init_cpu();
++ early_cpu_detect();
++
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ /* pse is not compatible with on-the-fly unmapping,
++ * disable it even if the cpus claim to support it.
++ */
++ clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
++ disable_pse = 1;
++#endif
++}
++
++void __cpuinit cpu_gdt_init(struct Xgt_desc_struct *gdt_descr)
++{
++ unsigned long frames[16];
++ unsigned long va;
++ int f;
++
++ for (va = gdt_descr->address, f = 0;
++ va < gdt_descr->address + gdt_descr->size;
++ va += PAGE_SIZE, f++) {
++ frames[f] = virt_to_mfn(va);
++ make_lowmem_page_readonly(
++ (void *)va, XENFEAT_writable_descriptor_tables);
++ }
++ if (HYPERVISOR_set_gdt(frames, gdt_descr->size / 8))
++ BUG();
++}
++
++/*
++ * cpu_init() initializes state that is per-CPU. Some data is already
++ * initialized (naturally) in the bootstrap process, such as the GDT
++ * and IDT. We reload them nevertheless, this function acts as a
++ * 'CPU state barrier', nothing should get across.
++ */
++void __cpuinit cpu_init(void)
++{
++ int cpu = smp_processor_id();
++#ifndef CONFIG_X86_NO_TSS
++ struct tss_struct * t = &per_cpu(init_tss, cpu);
++#endif
++ struct thread_struct *thread = ¤t->thread;
++ struct desc_struct *gdt;
++ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
++
++ if (cpu_test_and_set(cpu, cpu_initialized)) {
++ printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
++ for (;;) local_irq_enable();
++ }
++ printk(KERN_INFO "Initializing CPU#%d\n", cpu);
++
++ if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
++ clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
++ if (tsc_disable && cpu_has_tsc) {
++ printk(KERN_NOTICE "Disabling TSC...\n");
++ /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
++ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
++ set_in_cr4(X86_CR4_TSD);
++ }
++
++#ifndef CONFIG_XEN
++ /* The CPU hotplug case */
++ if (cpu_gdt_descr->address) {
++ gdt = (struct desc_struct *)cpu_gdt_descr->address;
++ memset(gdt, 0, PAGE_SIZE);
++ goto old_gdt;
++ }
++ /*
++ * This is a horrible hack to allocate the GDT. The problem
++ * is that cpu_init() is called really early for the boot CPU
++ * (and hence needs bootmem) but much later for the secondary
++ * CPUs, when bootmem will have gone away
++ */
++ if (NODE_DATA(0)->bdata->node_bootmem_map) {
++ gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
++ /* alloc_bootmem_pages panics on failure, so no check */
++ memset(gdt, 0, PAGE_SIZE);
++ } else {
++ gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
++ if (unlikely(!gdt)) {
++ printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
++ for (;;)
++ local_irq_enable();
++ }
++ }
++old_gdt:
++ /*
++ * Initialize the per-CPU GDT with the boot GDT,
++ * and set up the GDT descriptor:
++ */
++ memcpy(gdt, cpu_gdt_table, GDT_SIZE);
++
++ /* Set up GDT entry for 16bit stack */
++ *(__u64 *)(&gdt[GDT_ENTRY_ESPFIX_SS]) |=
++ ((((__u64)stk16_off) << 16) & 0x000000ffffff0000ULL) |
++ ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
++ (CPU_16BIT_STACK_SIZE - 1);
++
++ cpu_gdt_descr->size = GDT_SIZE - 1;
++ cpu_gdt_descr->address = (unsigned long)gdt;
++#else
++ if (cpu == 0 && cpu_gdt_descr->address == 0) {
++ gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
++ /* alloc_bootmem_pages panics on failure, so no check */
++ memset(gdt, 0, PAGE_SIZE);
++
++ memcpy(gdt, cpu_gdt_table, GDT_SIZE);
++
++ cpu_gdt_descr->size = GDT_SIZE;
++ cpu_gdt_descr->address = (unsigned long)gdt;
++ }
++#endif
++
++ cpu_gdt_init(cpu_gdt_descr);
++
++ /*
++ * Set up and load the per-CPU TSS and LDT
++ */
++ atomic_inc(&init_mm.mm_count);
++ current->active_mm = &init_mm;
++ if (current->mm)
++ BUG();
++ enter_lazy_tlb(&init_mm, current);
++
++ load_esp0(t, thread);
++
++ load_LDT(&init_mm.context);
++
++#ifdef CONFIG_DOUBLEFAULT
++ /* Set up doublefault TSS pointer in the GDT */
++ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
++#endif
++
++ /* Clear %fs and %gs. */
++ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
++
++ /* Clear all 6 debug registers: */
++ set_debugreg(0, 0);
++ set_debugreg(0, 1);
++ set_debugreg(0, 2);
++ set_debugreg(0, 3);
++ set_debugreg(0, 6);
++ set_debugreg(0, 7);
++
++ /*
++ * Force FPU initialization:
++ */
++ current_thread_info()->status = 0;
++ clear_used_math();
++ mxcsr_feature_mask_init();
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++void __cpuinit 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 -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/cpu/Makefile linux-2.6.18-xen/arch/i386/kernel/cpu/Makefile
+--- linux-2.6.18.1/arch/i386/kernel/cpu/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/cpu/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -17,3 +17,8 @@
+
+ obj-$(CONFIG_MTRR) += mtrr/
+ obj-$(CONFIG_CPU_FREQ) += cpufreq/
++
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++obj-y := $(call cherrypickxen, $(obj-y), $(src))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/cpu/mtrr/main-xen.c linux-2.6.18-xen/arch/i386/kernel/cpu/mtrr/main-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/cpu/mtrr/main-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/cpu/mtrr/main-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,197 @@
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/mutex.h>
++#include <asm/uaccess.h>
++
++#include <asm/mtrr.h>
++#include "mtrr.h"
++
++static DEFINE_MUTEX(mtrr_mutex);
++
++void generic_get_mtrr(unsigned int reg, unsigned long *base,
++ unsigned int *size, mtrr_type * type)
++{
++ dom0_op_t op;
++
++ op.cmd = DOM0_READ_MEMTYPE;
++ op.u.read_memtype.reg = reg;
++ (void)HYPERVISOR_dom0_op(&op);
++
++ *size = op.u.read_memtype.nr_mfns;
++ *base = op.u.read_memtype.mfn;
++ *type = op.u.read_memtype.type;
++}
++
++struct mtrr_ops generic_mtrr_ops = {
++ .use_intel_if = 1,
++ .get = generic_get_mtrr,
++};
++
++struct mtrr_ops *mtrr_if = &generic_mtrr_ops;
++unsigned int num_var_ranges;
++unsigned int *usage_table;
++
++static void __init set_num_var_ranges(void)
++{
++ dom0_op_t op;
++
++ for (num_var_ranges = 0; ; num_var_ranges++) {
++ op.cmd = DOM0_READ_MEMTYPE;
++ op.u.read_memtype.reg = num_var_ranges;
++ if (HYPERVISOR_dom0_op(&op) != 0)
++ break;
++ }
++}
++
++static void __init init_table(void)
++{
++ int i, max;
++
++ max = num_var_ranges;
++ if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
++ == NULL) {
++ printk(KERN_ERR "mtrr: could not allocate\n");
++ return;
++ }
++ for (i = 0; i < max; i++)
++ usage_table[i] = 0;
++}
++
++int mtrr_add_page(unsigned long base, unsigned long size,
++ unsigned int type, char increment)
++{
++ int error;
++ dom0_op_t op;
++
++ mutex_lock(&mtrr_mutex);
++
++ op.cmd = DOM0_ADD_MEMTYPE;
++ op.u.add_memtype.mfn = base;
++ op.u.add_memtype.nr_mfns = size;
++ op.u.add_memtype.type = type;
++ error = HYPERVISOR_dom0_op(&op);
++ if (error) {
++ mutex_unlock(&mtrr_mutex);
++ BUG_ON(error > 0);
++ return error;
++ }
++
++ if (increment)
++ ++usage_table[op.u.add_memtype.reg];
++
++ mutex_unlock(&mtrr_mutex);
++
++ return op.u.add_memtype.reg;
++}
++
++static int mtrr_check(unsigned long base, unsigned long size)
++{
++ if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
++ printk(KERN_WARNING
++ "mtrr: size and base must be multiples of 4 kiB\n");
++ printk(KERN_DEBUG
++ "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
++ dump_stack();
++ return -1;
++ }
++ return 0;
++}
++
++int
++mtrr_add(unsigned long base, unsigned long size, unsigned int type,
++ char increment)
++{
++ if (mtrr_check(base, size))
++ return -EINVAL;
++ return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
++ increment);
++}
++
++int mtrr_del_page(int reg, unsigned long base, unsigned long size)
++{
++ unsigned i;
++ mtrr_type ltype;
++ unsigned long lbase;
++ unsigned int lsize;
++ int error = -EINVAL;
++ dom0_op_t op;
++
++ mutex_lock(&mtrr_mutex);
++
++ if (reg < 0) {
++ /* Search for existing MTRR */
++ for (i = 0; i < num_var_ranges; ++i) {
++ mtrr_if->get(i, &lbase, &lsize, <ype);
++ if (lbase == base && lsize == size) {
++ reg = i;
++ break;
++ }
++ }
++ if (reg < 0) {
++ printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
++ size);
++ goto out;
++ }
++ }
++ if (usage_table[reg] < 1) {
++ printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
++ goto out;
++ }
++ if (--usage_table[reg] < 1) {
++ op.cmd = DOM0_DEL_MEMTYPE;
++ op.u.del_memtype.handle = 0;
++ op.u.del_memtype.reg = reg;
++ error = HYPERVISOR_dom0_op(&op);
++ if (error) {
++ BUG_ON(error > 0);
++ goto out;
++ }
++ }
++ error = reg;
++ out:
++ mutex_unlock(&mtrr_mutex);
++ return error;
++}
++
++int
++mtrr_del(int reg, unsigned long base, unsigned long size)
++{
++ if (mtrr_check(base, size))
++ return -EINVAL;
++ return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
++}
++
++EXPORT_SYMBOL(mtrr_add);
++EXPORT_SYMBOL(mtrr_del);
++
++void __init mtrr_bp_init(void)
++{
++}
++
++void mtrr_ap_init(void)
++{
++}
++
++static int __init mtrr_init(void)
++{
++ struct cpuinfo_x86 *c = &boot_cpu_data;
++
++ if (!is_initial_xendomain())
++ return -ENODEV;
++
++ if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
++ (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
++ (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
++ (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
++ return -ENODEV;
++
++ set_num_var_ranges();
++ init_table();
++
++ return 0;
++}
++
++subsys_initcall(mtrr_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/cpu/mtrr/Makefile linux-2.6.18-xen/arch/i386/kernel/cpu/mtrr/Makefile
+--- linux-2.6.18.1/arch/i386/kernel/cpu/mtrr/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/cpu/mtrr/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -3,3 +3,10 @@
+ obj-y += cyrix.o
+ obj-y += centaur.o
+
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++n-obj-xen := generic.o state.o amd.o cyrix.o centaur.o
++
++obj-y := $(call filterxen, $(obj-y), $(n-obj-xen))
++obj-y := $(call cherrypickxen, $(obj-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/early_printk-xen.c linux-2.6.18-xen/arch/i386/kernel/early_printk-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/early_printk-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/early_printk-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,2 @@
++
++#include "../../x86_64/kernel/early_printk-xen.c"
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/entry.S linux-2.6.18-xen/arch/i386/kernel/entry.S
+--- linux-2.6.18.1/arch/i386/kernel/entry.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/entry.S 2006-09-21 01:33:31.000000000 +0200
+@@ -269,7 +269,7 @@
+ CFI_STARTPROC simple
+ CFI_DEF_CFA esp, 0
+ CFI_REGISTER esp, ebp
+- movl TSS_sysenter_esp0(%esp),%esp
++ movl SYSENTER_stack_esp0(%esp),%esp
+ sysenter_past_esp:
+ /*
+ * No need to follow this irqs on/off section: the syscall
+@@ -689,7 +689,7 @@
+ * that sets up the real kernel stack. Check here, since we can't
+ * allow the wrong stack to be used.
+ *
+- * "TSS_sysenter_esp0+12" is because the NMI/debug handler will have
++ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have
+ * already pushed 3 words if it hits on the sysenter instruction:
+ * eflags, cs and eip.
+ *
+@@ -701,7 +701,7 @@
+ cmpw $__KERNEL_CS,4(%esp); \
+ jne ok; \
+ label: \
+- movl TSS_sysenter_esp0+offset(%esp),%esp; \
++ movl SYSENTER_stack_esp0+offset(%esp),%esp; \
+ pushfl; \
+ pushl $__KERNEL_CS; \
+ pushl $sysenter_past_esp
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/entry-xen.S linux-2.6.18-xen/arch/i386/kernel/entry-xen.S
+--- linux-2.6.18.1/arch/i386/kernel/entry-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/entry-xen.S 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,1213 @@
++/*
++ * linux/arch/i386/entry.S
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ */
++
++/*
++ * entry.S contains the system-call and fault low-level handling routines.
++ * This also contains the timer-interrupt handler, as well as all interrupts
++ * and faults that can result in a task-switch.
++ *
++ * NOTE: This code handles signal-recognition, which happens every time
++ * after a timer-interrupt and after each system call.
++ *
++ * I changed all the .align's to 4 (16 byte alignment), as that's faster
++ * on a 486.
++ *
++ * Stack layout in 'ret_from_system_call':
++ * ptrace needs to have all regs on the stack.
++ * if the order here is changed, it needs to be
++ * updated in fork.c:copy_process, signal.c:do_signal,
++ * ptrace.c and ptrace.h
++ *
++ * 0(%esp) - %ebx
++ * 4(%esp) - %ecx
++ * 8(%esp) - %edx
++ * C(%esp) - %esi
++ * 10(%esp) - %edi
++ * 14(%esp) - %ebp
++ * 18(%esp) - %eax
++ * 1C(%esp) - %ds
++ * 20(%esp) - %es
++ * 24(%esp) - orig_eax
++ * 28(%esp) - %eip
++ * 2C(%esp) - %cs
++ * 30(%esp) - %eflags
++ * 34(%esp) - %oldesp
++ * 38(%esp) - %oldss
++ *
++ * "current" is in register %ebx during any slow entries.
++ */
++
++#include <linux/linkage.h>
++#include <asm/thread_info.h>
++#include <asm/irqflags.h>
++#include <asm/errno.h>
++#include <asm/segment.h>
++#include <asm/smp.h>
++#include <asm/page.h>
++#include <asm/desc.h>
++#include <asm/dwarf2.h>
++#include "irq_vectors.h"
++#include <xen/interface/xen.h>
++
++#define nr_syscalls ((syscall_table_size)/4)
++
++EBX = 0x00
++ECX = 0x04
++EDX = 0x08
++ESI = 0x0C
++EDI = 0x10
++EBP = 0x14
++EAX = 0x18
++DS = 0x1C
++ES = 0x20
++ORIG_EAX = 0x24
++EIP = 0x28
++CS = 0x2C
++EFLAGS = 0x30
++OLDESP = 0x34
++OLDSS = 0x38
++
++CF_MASK = 0x00000001
++TF_MASK = 0x00000100
++IF_MASK = 0x00000200
++DF_MASK = 0x00000400
++NT_MASK = 0x00004000
++VM_MASK = 0x00020000
++/* Pseudo-eflags. */
++NMI_MASK = 0x80000000
++
++#ifndef CONFIG_XEN
++#define DISABLE_INTERRUPTS cli
++#define ENABLE_INTERRUPTS sti
++#else
++/* Offsets into shared_info_t. */
++#define evtchn_upcall_pending /* 0 */
++#define evtchn_upcall_mask 1
++
++#define sizeof_vcpu_shift 6
++
++#ifdef CONFIG_SMP
++#define GET_VCPU_INFO movl TI_cpu(%ebp),%esi ; \
++ shl $sizeof_vcpu_shift,%esi ; \
++ addl HYPERVISOR_shared_info,%esi
++#else
++#define GET_VCPU_INFO movl HYPERVISOR_shared_info,%esi
++#endif
++
++#define __DISABLE_INTERRUPTS movb $1,evtchn_upcall_mask(%esi)
++#define __ENABLE_INTERRUPTS movb $0,evtchn_upcall_mask(%esi)
++#define DISABLE_INTERRUPTS GET_VCPU_INFO ; \
++ __DISABLE_INTERRUPTS
++#define ENABLE_INTERRUPTS GET_VCPU_INFO ; \
++ __ENABLE_INTERRUPTS
++#define __TEST_PENDING testb $0xFF,evtchn_upcall_pending(%esi)
++#endif
++
++#ifdef CONFIG_PREEMPT
++#define preempt_stop cli; TRACE_IRQS_OFF
++#else
++#define preempt_stop
++#define resume_kernel restore_nocheck
++#endif
++
++.macro TRACE_IRQS_IRET
++#ifdef CONFIG_TRACE_IRQFLAGS
++ testl $IF_MASK,EFLAGS(%esp) # interrupts off?
++ jz 1f
++ TRACE_IRQS_ON
++1:
++#endif
++.endm
++
++#ifdef CONFIG_VM86
++#define resume_userspace_sig check_userspace
++#else
++#define resume_userspace_sig resume_userspace
++#endif
++
++#define SAVE_ALL \
++ cld; \
++ pushl %es; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ /*CFI_REL_OFFSET es, 0;*/\
++ pushl %ds; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ /*CFI_REL_OFFSET ds, 0;*/\
++ pushl %eax; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET eax, 0;\
++ pushl %ebp; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET ebp, 0;\
++ pushl %edi; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET edi, 0;\
++ pushl %esi; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET esi, 0;\
++ pushl %edx; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET edx, 0;\
++ pushl %ecx; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET ecx, 0;\
++ pushl %ebx; \
++ CFI_ADJUST_CFA_OFFSET 4;\
++ CFI_REL_OFFSET ebx, 0;\
++ movl $(__USER_DS), %edx; \
++ movl %edx, %ds; \
++ movl %edx, %es;
++
++#define RESTORE_INT_REGS \
++ popl %ebx; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE ebx;\
++ popl %ecx; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE ecx;\
++ popl %edx; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE edx;\
++ popl %esi; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE esi;\
++ popl %edi; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE edi;\
++ popl %ebp; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE ebp;\
++ popl %eax; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ CFI_RESTORE eax
++
++#define RESTORE_REGS \
++ RESTORE_INT_REGS; \
++1: popl %ds; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ /*CFI_RESTORE ds;*/\
++2: popl %es; \
++ CFI_ADJUST_CFA_OFFSET -4;\
++ /*CFI_RESTORE es;*/\
++.section .fixup,"ax"; \
++3: movl $0,(%esp); \
++ jmp 1b; \
++4: movl $0,(%esp); \
++ jmp 2b; \
++.previous; \
++.section __ex_table,"a";\
++ .align 4; \
++ .long 1b,3b; \
++ .long 2b,4b; \
++.previous
++
++#define RING0_INT_FRAME \
++ CFI_STARTPROC simple;\
++ CFI_DEF_CFA esp, 3*4;\
++ /*CFI_OFFSET cs, -2*4;*/\
++ CFI_OFFSET eip, -3*4
++
++#define RING0_EC_FRAME \
++ CFI_STARTPROC simple;\
++ CFI_DEF_CFA esp, 4*4;\
++ /*CFI_OFFSET cs, -2*4;*/\
++ CFI_OFFSET eip, -3*4
++
++#define RING0_PTREGS_FRAME \
++ CFI_STARTPROC simple;\
++ CFI_DEF_CFA esp, OLDESP-EBX;\
++ /*CFI_OFFSET cs, CS-OLDESP;*/\
++ CFI_OFFSET eip, EIP-OLDESP;\
++ /*CFI_OFFSET es, ES-OLDESP;*/\
++ /*CFI_OFFSET ds, DS-OLDESP;*/\
++ CFI_OFFSET eax, EAX-OLDESP;\
++ CFI_OFFSET ebp, EBP-OLDESP;\
++ CFI_OFFSET edi, EDI-OLDESP;\
++ CFI_OFFSET esi, ESI-OLDESP;\
++ CFI_OFFSET edx, EDX-OLDESP;\
++ CFI_OFFSET ecx, ECX-OLDESP;\
++ CFI_OFFSET ebx, EBX-OLDESP
++
++ENTRY(ret_from_fork)
++ CFI_STARTPROC
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ call schedule_tail
++ GET_THREAD_INFO(%ebp)
++ popl %eax
++ CFI_ADJUST_CFA_OFFSET -4
++ pushl $0x0202 # Reset kernel eflags
++ CFI_ADJUST_CFA_OFFSET 4
++ popfl
++ CFI_ADJUST_CFA_OFFSET -4
++ jmp syscall_exit
++ CFI_ENDPROC
++
++/*
++ * Return to user mode is not as complex as all this looks,
++ * but we want the default path for a system call return to
++ * go as quickly as possible which is why some of this is
++ * less clear than it otherwise should be.
++ */
++
++ # userspace resumption stub bypassing syscall exit tracing
++ ALIGN
++ RING0_PTREGS_FRAME
++ret_from_exception:
++ preempt_stop
++ret_from_intr:
++ GET_THREAD_INFO(%ebp)
++check_userspace:
++ movl EFLAGS(%esp), %eax # mix EFLAGS and CS
++ movb CS(%esp), %al
++ testl $(VM_MASK | 2), %eax
++ jz resume_kernel
++ENTRY(resume_userspace)
++ DISABLE_INTERRUPTS # make sure we don't miss an interrupt
++ # setting need_resched or sigpending
++ # between sampling and the iret
++ movl TI_flags(%ebp), %ecx
++ andl $_TIF_WORK_MASK, %ecx # is there any work to be done on
++ # int/exception return?
++ jne work_pending
++ jmp restore_all
++
++#ifdef CONFIG_PREEMPT
++ENTRY(resume_kernel)
++ cli
++ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
++ jnz restore_nocheck
++need_resched:
++ movl TI_flags(%ebp), %ecx # need_resched set ?
++ testb $_TIF_NEED_RESCHED, %cl
++ jz restore_all
++ testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ?
++ jz restore_all
++ call preempt_schedule_irq
++ jmp need_resched
++#endif
++ CFI_ENDPROC
++
++/* SYSENTER_RETURN points to after the "sysenter" instruction in
++ the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */
++
++ # sysenter call handler stub
++ENTRY(sysenter_entry)
++ CFI_STARTPROC simple
++ CFI_DEF_CFA esp, 0
++ CFI_REGISTER esp, ebp
++ movl SYSENTER_stack_esp0(%esp),%esp
++sysenter_past_esp:
++ /*
++ * No need to follow this irqs on/off section: the syscall
++ * disabled irqs and here we enable it straight after entry:
++ */
++ sti
++ pushl $(__USER_DS)
++ CFI_ADJUST_CFA_OFFSET 4
++ /*CFI_REL_OFFSET ss, 0*/
++ pushl %ebp
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET esp, 0
++ pushfl
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $(__USER_CS)
++ CFI_ADJUST_CFA_OFFSET 4
++ /*CFI_REL_OFFSET cs, 0*/
++ /*
++ * Push current_thread_info()->sysenter_return to the stack.
++ * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
++ * pushed above; +8 corresponds to copy_thread's esp0 setting.
++ */
++ pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET eip, 0
++
++/*
++ * Load the potential sixth argument from user stack.
++ * Careful about security.
++ */
++ cmpl $__PAGE_OFFSET-3,%ebp
++ jae syscall_fault
++1: movl (%ebp),%ebp
++.section __ex_table,"a"
++ .align 4
++ .long 1b,syscall_fault
++.previous
++
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ GET_THREAD_INFO(%ebp)
++
++ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ jnz syscall_trace_entry
++ cmpl $(nr_syscalls), %eax
++ jae syscall_badsys
++ call *sys_call_table(,%eax,4)
++ movl %eax,EAX(%esp)
++ DISABLE_INTERRUPTS
++ TRACE_IRQS_OFF
++ movl TI_flags(%ebp), %ecx
++ testw $_TIF_ALLWORK_MASK, %cx
++ jne syscall_exit_work
++/* if something modifies registers it must also disable sysexit */
++ movl EIP(%esp), %edx
++ movl OLDESP(%esp), %ecx
++ xorl %ebp,%ebp
++ TRACE_IRQS_ON
++#ifdef CONFIG_XEN
++ __ENABLE_INTERRUPTS
++sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/
++ __TEST_PENDING
++ jnz 14f # process more events if necessary...
++ movl ESI(%esp), %esi
++ sysexit
++14: __DISABLE_INTERRUPTS
++sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/
++ push %esp
++ CFI_ADJUST_CFA_OFFSET 4
++ call evtchn_do_upcall
++ add $4,%esp
++ CFI_ADJUST_CFA_OFFSET -4
++ jmp ret_from_intr
++#else
++ sti
++ sysexit
++#endif /* !CONFIG_XEN */
++ CFI_ENDPROC
++
++
++ # system call handler stub
++ENTRY(system_call)
++ RING0_INT_FRAME # can't unwind into user space anyway
++ pushl %eax # save orig_eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ GET_THREAD_INFO(%ebp)
++ testl $TF_MASK,EFLAGS(%esp)
++ jz no_singlestep
++ orl $_TIF_SINGLESTEP,TI_flags(%ebp)
++no_singlestep:
++ # system call tracing in operation / emulation
++ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ jnz syscall_trace_entry
++ cmpl $(nr_syscalls), %eax
++ jae syscall_badsys
++syscall_call:
++ call *sys_call_table(,%eax,4)
++ movl %eax,EAX(%esp) # store the return value
++syscall_exit:
++ DISABLE_INTERRUPTS # make sure we don't miss an interrupt
++ # setting need_resched or sigpending
++ # between sampling and the iret
++ TRACE_IRQS_OFF
++ movl TI_flags(%ebp), %ecx
++ testw $_TIF_ALLWORK_MASK, %cx # current->work
++ jne syscall_exit_work
++
++restore_all:
++#ifndef CONFIG_XEN
++ movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
++ # Warning: OLDSS(%esp) contains the wrong/random values if we
++ # are returning to the kernel.
++ # See comments in process.c:copy_thread() for details.
++ movb OLDSS(%esp), %ah
++ movb CS(%esp), %al
++ andl $(VM_MASK | (4 << 8) | 3), %eax
++ cmpl $((4 << 8) | 3), %eax
++ je ldt_ss # returning to user-space with LDT SS
++restore_nocheck:
++#else
++restore_nocheck:
++ movl EFLAGS(%esp), %eax
++ testl $(VM_MASK|NMI_MASK), %eax
++ jnz hypervisor_iret
++ shr $9, %eax # EAX[0] == IRET_EFLAGS.IF
++ GET_VCPU_INFO
++ andb evtchn_upcall_mask(%esi),%al
++ andb $1,%al # EAX[0] == IRET_EFLAGS.IF & event_mask
++ jnz restore_all_enable_events # != 0 => enable event delivery
++#endif
++ TRACE_IRQS_IRET
++ CFI_REMEMBER_STATE
++restore_nocheck_notrace:
++ RESTORE_REGS
++ addl $4, %esp
++ CFI_ADJUST_CFA_OFFSET -4
++1: iret
++.section .fixup,"ax"
++iret_exc:
++#ifndef CONFIG_XEN
++ TRACE_IRQS_ON
++ sti
++#endif
++ pushl $0 # no error code
++ pushl $do_iret_error
++ jmp error_code
++.previous
++.section __ex_table,"a"
++ .align 4
++ .long 1b,iret_exc
++.previous
++
++ CFI_RESTORE_STATE
++#ifndef CONFIG_XEN
++ldt_ss:
++ larl OLDSS(%esp), %eax
++ jnz restore_nocheck
++ testl $0x00400000, %eax # returning to 32bit stack?
++ jnz restore_nocheck # allright, normal return
++ /* If returning to userspace with 16bit stack,
++ * try to fix the higher word of ESP, as the CPU
++ * won't restore it.
++ * This is an "official" bug of all the x86-compatible
++ * CPUs, which we can try to work around to make
++ * dosemu and wine happy. */
++ subl $8, %esp # reserve space for switch16 pointer
++ CFI_ADJUST_CFA_OFFSET 8
++ cli
++ TRACE_IRQS_OFF
++ movl %esp, %eax
++ /* Set up the 16bit stack frame with switch32 pointer on top,
++ * and a switch16 pointer on top of the current frame. */
++ call setup_x86_bogus_stack
++ CFI_ADJUST_CFA_OFFSET -8 # frame has moved
++ TRACE_IRQS_IRET
++ RESTORE_REGS
++ lss 20+4(%esp), %esp # switch to 16bit stack
++1: iret
++.section __ex_table,"a"
++ .align 4
++ .long 1b,iret_exc
++.previous
++#else
++hypervisor_iret:
++ andl $~NMI_MASK, EFLAGS(%esp)
++ RESTORE_REGS
++ addl $4, %esp
++ jmp hypercall_page + (__HYPERVISOR_iret * 32)
++#endif
++ CFI_ENDPROC
++
++ # perform work that needs to be done immediately before resumption
++ ALIGN
++ RING0_PTREGS_FRAME # can't unwind into user space anyway
++work_pending:
++ testb $_TIF_NEED_RESCHED, %cl
++ jz work_notifysig
++work_resched:
++ call schedule
++ DISABLE_INTERRUPTS # make sure we don't miss an interrupt
++ # setting need_resched or sigpending
++ # between sampling and the iret
++ TRACE_IRQS_OFF
++ movl TI_flags(%ebp), %ecx
++ andl $_TIF_WORK_MASK, %ecx # is there any work to be done other
++ # than syscall tracing?
++ jz restore_all
++ testb $_TIF_NEED_RESCHED, %cl
++ jnz work_resched
++
++work_notifysig: # deal with pending signals and
++ # notify-resume requests
++ testl $VM_MASK, EFLAGS(%esp)
++ movl %esp, %eax
++ jne work_notifysig_v86 # returning to kernel-space or
++ # vm86-space
++ xorl %edx, %edx
++ call do_notify_resume
++ jmp resume_userspace_sig
++
++ ALIGN
++work_notifysig_v86:
++#ifdef CONFIG_VM86
++ pushl %ecx # save ti_flags for do_notify_resume
++ CFI_ADJUST_CFA_OFFSET 4
++ call save_v86_state # %eax contains pt_regs pointer
++ popl %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ movl %eax, %esp
++ xorl %edx, %edx
++ call do_notify_resume
++ jmp resume_userspace_sig
++#endif
++
++ # perform syscall exit tracing
++ ALIGN
++syscall_trace_entry:
++ movl $-ENOSYS,EAX(%esp)
++ movl %esp, %eax
++ xorl %edx,%edx
++ call do_syscall_trace
++ cmpl $0, %eax
++ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
++ movl ORIG_EAX(%esp), %eax
++ cmpl $(nr_syscalls), %eax
++ jnae syscall_call
++ jmp syscall_exit
++
++ # perform syscall exit tracing
++ ALIGN
++syscall_exit_work:
++ testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
++ jz work_pending
++ TRACE_IRQS_ON
++ ENABLE_INTERRUPTS # could let do_syscall_trace() call
++ # schedule() instead
++ movl %esp, %eax
++ movl $1, %edx
++ call do_syscall_trace
++ jmp resume_userspace
++ CFI_ENDPROC
++
++ RING0_INT_FRAME # can't unwind into user space anyway
++syscall_fault:
++ pushl %eax # save orig_eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ GET_THREAD_INFO(%ebp)
++ movl $-EFAULT,EAX(%esp)
++ jmp resume_userspace
++
++syscall_badsys:
++ movl $-ENOSYS,EAX(%esp)
++ jmp resume_userspace
++ CFI_ENDPROC
++
++#ifndef CONFIG_XEN
++#define FIXUP_ESPFIX_STACK \
++ movl %esp, %eax; \
++ /* switch to 32bit stack using the pointer on top of 16bit stack */ \
++ lss %ss:CPU_16BIT_STACK_SIZE-8, %esp; \
++ /* copy data from 16bit stack to 32bit stack */ \
++ call fixup_x86_bogus_stack; \
++ /* put ESP to the proper location */ \
++ movl %eax, %esp;
++#define UNWIND_ESPFIX_STACK \
++ pushl %eax; \
++ CFI_ADJUST_CFA_OFFSET 4; \
++ movl %ss, %eax; \
++ /* see if on 16bit stack */ \
++ cmpw $__ESPFIX_SS, %ax; \
++ je 28f; \
++27: popl %eax; \
++ CFI_ADJUST_CFA_OFFSET -4; \
++.section .fixup,"ax"; \
++28: movl $__KERNEL_DS, %eax; \
++ movl %eax, %ds; \
++ movl %eax, %es; \
++ /* switch to 32bit stack */ \
++ FIXUP_ESPFIX_STACK; \
++ jmp 27b; \
++.previous
++
++/*
++ * Build the entry stubs and pointer table with
++ * some assembler magic.
++ */
++.data
++ENTRY(interrupt)
++.text
++
++vector=0
++ENTRY(irq_entries_start)
++ RING0_INT_FRAME
++.rept NR_IRQS
++ ALIGN
++ .if vector
++ CFI_ADJUST_CFA_OFFSET -4
++ .endif
++1: pushl $~(vector)
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp common_interrupt
++.data
++ .long 1b
++.text
++vector=vector+1
++.endr
++
++/*
++ * the CPU automatically disables interrupts when executing an IRQ vector,
++ * so IRQ-flags tracing has to follow that:
++ */
++ ALIGN
++common_interrupt:
++ SAVE_ALL
++ TRACE_IRQS_OFF
++ movl %esp,%eax
++ call do_IRQ
++ jmp ret_from_intr
++ CFI_ENDPROC
++
++#define BUILD_INTERRUPT(name, nr) \
++ENTRY(name) \
++ SAVE_ALL \
++ RING0_INT_FRAME; \
++ pushl $~(nr); \
++ CFI_ADJUST_CFA_OFFSET 4; \
++ SAVE_ALL; \
++ TRACE_IRQS_OFF \
++ movl %esp,%eax; \
++ call smp_/**/name; \
++ jmp ret_from_intr; \
++ CFI_ENDPROC
++
++/* The include is where all of the SMP etc. interrupts come from */
++#include "entry_arch.h"
++#else
++#define UNWIND_ESPFIX_STACK
++#endif
++
++ENTRY(divide_error)
++ RING0_INT_FRAME
++ pushl $0 # no error code
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_divide_error
++ CFI_ADJUST_CFA_OFFSET 4
++ ALIGN
++error_code:
++ pushl %ds
++ CFI_ADJUST_CFA_OFFSET 4
++ /*CFI_REL_OFFSET ds, 0*/
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET eax, 0
++ xorl %eax, %eax
++ pushl %ebp
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ebp, 0
++ pushl %edi
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edi, 0
++ pushl %esi
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET esi, 0
++ pushl %edx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET edx, 0
++ decl %eax # eax = -1
++ pushl %ecx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ecx, 0
++ pushl %ebx
++ CFI_ADJUST_CFA_OFFSET 4
++ CFI_REL_OFFSET ebx, 0
++ cld
++ pushl %es
++ CFI_ADJUST_CFA_OFFSET 4
++ /*CFI_REL_OFFSET es, 0*/
++ UNWIND_ESPFIX_STACK
++ popl %ecx
++ CFI_ADJUST_CFA_OFFSET -4
++ /*CFI_REGISTER es, ecx*/
++ movl ES(%esp), %edi # get the function address
++ movl ORIG_EAX(%esp), %edx # get the error code
++ movl %eax, ORIG_EAX(%esp)
++ movl %ecx, ES(%esp)
++ /*CFI_REL_OFFSET es, ES*/
++ movl $(__USER_DS), %ecx
++ movl %ecx, %ds
++ movl %ecx, %es
++ movl %esp,%eax # pt_regs pointer
++ call *%edi
++ jmp ret_from_exception
++ CFI_ENDPROC
++
++#ifdef CONFIG_XEN
++# A note on the "critical region" in our callback handler.
++# We want to avoid stacking callback handlers due to events occurring
++# during handling of the last event. To do this, we keep events disabled
++# until we've done all processing. HOWEVER, we must enable events before
++# popping the stack frame (can't be done atomically) and so it would still
++# be possible to get enough handler activations to overflow the stack.
++# Although unlikely, bugs of that kind are hard to track down, so we'd
++# like to avoid the possibility.
++# So, on entry to the handler we detect whether we interrupted an
++# existing activation in its critical region -- if so, we pop the current
++# activation and restart the handler using the previous one.
++#
++# The sysexit critical region is slightly different. sysexit
++# atomically removes the entire stack frame. If we interrupt in the
++# critical region we know that the entire frame is present and correct
++# so we can simply throw away the new one.
++ENTRY(hypervisor_callback)
++ RING0_INT_FRAME
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ movl EIP(%esp),%eax
++ cmpl $scrit,%eax
++ jb 11f
++ cmpl $ecrit,%eax
++ jb critical_region_fixup
++ cmpl $sysexit_scrit,%eax
++ jb 11f
++ cmpl $sysexit_ecrit,%eax
++ ja 11f
++ # interrupted in sysexit critical
++ addl $0x34,%esp # Remove cs...ebx from stack frame.
++ # this popped off new frame to reuse the old one, therefore no
++ # CFI_ADJUST_CFA_OFFSET here
++11: push %esp
++ CFI_ADJUST_CFA_OFFSET 4
++ call evtchn_do_upcall
++ add $4,%esp
++ CFI_ADJUST_CFA_OFFSET -4
++ jmp ret_from_intr
++
++ ALIGN
++restore_all_enable_events:
++ __ENABLE_INTERRUPTS
++scrit: /**** START OF CRITICAL REGION ****/
++ __TEST_PENDING
++ jnz 14f # process more events if necessary...
++ RESTORE_REGS
++ addl $4, %esp
++ CFI_ADJUST_CFA_OFFSET -4
++1: iret
++.section __ex_table,"a"
++ .align 4
++ .long 1b,iret_exc
++.previous
++14: __DISABLE_INTERRUPTS
++ jmp 11b
++ecrit: /**** END OF CRITICAL REGION ****/
++# [How we do the fixup]. We want to merge the current stack frame with the
++# just-interrupted frame. How we do this depends on where in the critical
++# region the interrupted handler was executing, and so how many saved
++# registers are in each frame. We do this quickly using the lookup table
++# 'critical_fixup_table'. For each byte offset in the critical region, it
++# provides the number of bytes which have already been popped from the
++# interrupted stack frame.
++critical_region_fixup:
++ addl $critical_fixup_table-scrit,%eax
++ movzbl (%eax),%eax # %eax contains num bytes popped
++ cmpb $0xff,%al # 0xff => vcpu_info critical region
++ jne 15f
++ GET_THREAD_INFO(%ebp)
++ xorl %eax,%eax
++15: mov %esp,%esi
++ add %eax,%esi # %esi points at end of src region
++ mov %esp,%edi
++ add $0x34,%edi # %edi points at end of dst region
++ mov %eax,%ecx
++ shr $2,%ecx # convert words to bytes
++ je 17f # skip loop if nothing to copy
++16: subl $4,%esi # pre-decrementing copy loop
++ subl $4,%edi
++ movl (%esi),%eax
++ movl %eax,(%edi)
++ loop 16b
++17: movl %edi,%esp # final %edi is top of merged stack
++ # this popped off new frame to reuse the old one, therefore no
++ # CFI_DEF_CFA_OFFSET here
++ jmp 11b
++ CFI_ENDPROC
++
++critical_fixup_table:
++ .byte 0xff,0xff,0xff # testb $0xff,(%esi) = __TEST_PENDING
++ .byte 0xff,0xff # jnz 14f
++ .byte 0x00 # pop %ebx
++ .byte 0x04 # pop %ecx
++ .byte 0x08 # pop %edx
++ .byte 0x0c # pop %esi
++ .byte 0x10 # pop %edi
++ .byte 0x14 # pop %ebp
++ .byte 0x18 # pop %eax
++ .byte 0x1c # pop %ds
++ .byte 0x20 # pop %es
++ .byte 0x24,0x24,0x24 # add $4,%esp
++ .byte 0x28 # iret
++ .byte 0xff,0xff,0xff,0xff # movb $1,1(%esi)
++ .byte 0x00,0x00 # jmp 11b
++
++# Hypervisor uses this for application faults while it executes.
++# We get here for two reasons:
++# 1. Fault while reloading DS, ES, FS or GS
++# 2. Fault while executing IRET
++# Category 1 we fix up by reattempting the load, and zeroing the segment
++# register if the load fails.
++# Category 2 we fix up by jumping to do_iret_error. We cannot use the
++# normal Linux return path in this case because if we use the IRET hypercall
++# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
++# We distinguish between categories by maintaining a status value in EAX.
++ENTRY(failsafe_callback)
++ RING0_INT_FRAME
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ movl $1,%eax
++1: mov 4(%esp),%ds
++2: mov 8(%esp),%es
++3: mov 12(%esp),%fs
++4: mov 16(%esp),%gs
++ testl %eax,%eax
++ popl %eax
++ CFI_ADJUST_CFA_OFFSET -4
++ jz 5f
++ addl $16,%esp # EAX != 0 => Category 2 (Bad IRET)
++ CFI_ADJUST_CFA_OFFSET -16
++ jmp iret_exc
++ CFI_ADJUST_CFA_OFFSET 16
++5: addl $16,%esp # EAX == 0 => Category 1 (Bad segment)
++ CFI_ADJUST_CFA_OFFSET -16
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ jmp ret_from_exception
++.section .fixup,"ax"; \
++6: xorl %eax,%eax; \
++ movl %eax,4(%esp); \
++ jmp 1b; \
++7: xorl %eax,%eax; \
++ movl %eax,8(%esp); \
++ jmp 2b; \
++8: xorl %eax,%eax; \
++ movl %eax,12(%esp); \
++ jmp 3b; \
++9: xorl %eax,%eax; \
++ movl %eax,16(%esp); \
++ jmp 4b; \
++.previous; \
++.section __ex_table,"a"; \
++ .align 4; \
++ .long 1b,6b; \
++ .long 2b,7b; \
++ .long 3b,8b; \
++ .long 4b,9b; \
++.previous
++ CFI_ENDPROC
++#endif
++
++ENTRY(coprocessor_error)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_coprocessor_error
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(simd_coprocessor_error)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_simd_coprocessor_error
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(device_not_available)
++ RING0_INT_FRAME
++ pushl $-1 # mark this as an int
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++#ifndef CONFIG_XEN
++ movl %cr0, %eax
++ testl $0x4, %eax # EM (math emulation bit)
++ je device_available_emulate
++ pushl $0 # temporary storage for ORIG_EIP
++ CFI_ADJUST_CFA_OFFSET 4
++ call math_emulate
++ addl $4, %esp
++ CFI_ADJUST_CFA_OFFSET -4
++ jmp ret_from_exception
++device_available_emulate:
++#endif
++ preempt_stop
++ call math_state_restore
++ jmp ret_from_exception
++ CFI_ENDPROC
++
++#ifndef CONFIG_XEN
++/*
++ * Debug traps and NMI can happen at the one SYSENTER instruction
++ * that sets up the real kernel stack. Check here, since we can't
++ * allow the wrong stack to be used.
++ *
++ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have
++ * already pushed 3 words if it hits on the sysenter instruction:
++ * eflags, cs and eip.
++ *
++ * We just load the right stack, and push the three (known) values
++ * by hand onto the new stack - while updating the return eip past
++ * the instruction that would have done it for sysenter.
++ */
++#define FIX_STACK(offset, ok, label) \
++ cmpw $__KERNEL_CS,4(%esp); \
++ jne ok; \
++label: \
++ movl SYSENTER_stack_esp0+offset(%esp),%esp; \
++ pushfl; \
++ pushl $__KERNEL_CS; \
++ pushl $sysenter_past_esp
++#endif /* CONFIG_XEN */
++
++KPROBE_ENTRY(debug)
++ RING0_INT_FRAME
++#ifndef CONFIG_XEN
++ cmpl $sysenter_entry,(%esp)
++ jne debug_stack_correct
++ FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
++debug_stack_correct:
++#endif /* !CONFIG_XEN */
++ pushl $-1 # mark this as an int
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ xorl %edx,%edx # error code 0
++ movl %esp,%eax # pt_regs pointer
++ call do_debug
++ jmp ret_from_exception
++ CFI_ENDPROC
++ .previous .text
++
++#ifndef CONFIG_XEN
++/*
++ * NMI is doubly nasty. It can happen _while_ we're handling
++ * a debug fault, and the debug fault hasn't yet been able to
++ * clear up the stack. So we first check whether we got an
++ * NMI on the sysenter entry path, but after that we need to
++ * check whether we got an NMI on the debug path where the debug
++ * fault happened on the sysenter path.
++ */
++ENTRY(nmi)
++ RING0_INT_FRAME
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ movl %ss, %eax
++ cmpw $__ESPFIX_SS, %ax
++ popl %eax
++ CFI_ADJUST_CFA_OFFSET -4
++ je nmi_16bit_stack
++ cmpl $sysenter_entry,(%esp)
++ je nmi_stack_fixup
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ movl %esp,%eax
++ /* Do not access memory above the end of our stack page,
++ * it might not exist.
++ */
++ andl $(THREAD_SIZE-1),%eax
++ cmpl $(THREAD_SIZE-20),%eax
++ popl %eax
++ CFI_ADJUST_CFA_OFFSET -4
++ jae nmi_stack_correct
++ cmpl $sysenter_entry,12(%esp)
++ je nmi_debug_stack_check
++nmi_stack_correct:
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ xorl %edx,%edx # zero error code
++ movl %esp,%eax # pt_regs pointer
++ call do_nmi
++ jmp restore_nocheck_notrace
++ CFI_ENDPROC
++
++nmi_stack_fixup:
++ FIX_STACK(12,nmi_stack_correct, 1)
++ jmp nmi_stack_correct
++nmi_debug_stack_check:
++ cmpw $__KERNEL_CS,16(%esp)
++ jne nmi_stack_correct
++ cmpl $debug,(%esp)
++ jb nmi_stack_correct
++ cmpl $debug_esp_fix_insn,(%esp)
++ ja nmi_stack_correct
++ FIX_STACK(24,nmi_stack_correct, 1)
++ jmp nmi_stack_correct
++
++nmi_16bit_stack:
++ RING0_INT_FRAME
++ /* create the pointer to lss back */
++ pushl %ss
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl %esp
++ CFI_ADJUST_CFA_OFFSET 4
++ movzwl %sp, %esp
++ addw $4, (%esp)
++ /* copy the iret frame of 12 bytes */
++ .rept 3
++ pushl 16(%esp)
++ CFI_ADJUST_CFA_OFFSET 4
++ .endr
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ FIXUP_ESPFIX_STACK # %eax == %esp
++ CFI_ADJUST_CFA_OFFSET -20 # the frame has now moved
++ xorl %edx,%edx # zero error code
++ call do_nmi
++ RESTORE_REGS
++ lss 12+4(%esp), %esp # back to 16bit stack
++1: iret
++ CFI_ENDPROC
++.section __ex_table,"a"
++ .align 4
++ .long 1b,iret_exc
++.previous
++#else
++ENTRY(nmi)
++ RING0_INT_FRAME
++ pushl %eax
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ xorl %edx,%edx # zero error code
++ movl %esp,%eax # pt_regs pointer
++ call do_nmi
++ orl $NMI_MASK, EFLAGS(%esp)
++ jmp restore_all
++ CFI_ENDPROC
++#endif
++
++KPROBE_ENTRY(int3)
++ RING0_INT_FRAME
++ pushl $-1 # mark this as an int
++ CFI_ADJUST_CFA_OFFSET 4
++ SAVE_ALL
++ xorl %edx,%edx # zero error code
++ movl %esp,%eax # pt_regs pointer
++ call do_int3
++ jmp ret_from_exception
++ CFI_ENDPROC
++ .previous .text
++
++ENTRY(overflow)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_overflow
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(bounds)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_bounds
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(invalid_op)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_invalid_op
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(coprocessor_segment_overrun)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl $do_coprocessor_segment_overrun
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(invalid_TSS)
++ RING0_EC_FRAME
++ pushl $do_invalid_TSS
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(segment_not_present)
++ RING0_EC_FRAME
++ pushl $do_segment_not_present
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++ENTRY(stack_segment)
++ RING0_EC_FRAME
++ pushl $do_stack_segment
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++KPROBE_ENTRY(general_protection)
++ RING0_EC_FRAME
++ pushl $do_general_protection
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++ .previous .text
++
++ENTRY(alignment_check)
++ RING0_EC_FRAME
++ pushl $do_alignment_check
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++KPROBE_ENTRY(page_fault)
++ RING0_EC_FRAME
++ pushl $do_page_fault
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++ .previous .text
++
++#ifdef CONFIG_X86_MCE
++ENTRY(machine_check)
++ RING0_INT_FRAME
++ pushl $0
++ CFI_ADJUST_CFA_OFFSET 4
++ pushl machine_check_vector
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++#endif
++
++ENTRY(fixup_4gb_segment)
++ RING0_INT_FRAME
++ pushl $do_fixup_4gb_segment
++ CFI_ADJUST_CFA_OFFSET 4
++ jmp error_code
++ CFI_ENDPROC
++
++#ifdef CONFIG_STACK_UNWIND
++ENTRY(arch_unwind_init_running)
++ CFI_STARTPROC
++ movl 4(%esp), %edx
++ movl (%esp), %ecx
++ leal 4(%esp), %eax
++ movl %ebx, EBX(%edx)
++ xorl %ebx, %ebx
++ movl %ebx, ECX(%edx)
++ movl %ebx, EDX(%edx)
++ movl %esi, ESI(%edx)
++ movl %edi, EDI(%edx)
++ movl %ebp, EBP(%edx)
++ movl %ebx, EAX(%edx)
++ movl $__USER_DS, DS(%edx)
++ movl $__USER_DS, ES(%edx)
++ movl %ebx, ORIG_EAX(%edx)
++ movl %ecx, EIP(%edx)
++ movl 12(%esp), %ecx
++ movl $__KERNEL_CS, CS(%edx)
++ movl %ebx, EFLAGS(%edx)
++ movl %eax, OLDESP(%edx)
++ movl 8(%esp), %eax
++ movl %ecx, 8(%esp)
++ movl EBX(%edx), %ebx
++ movl $__KERNEL_DS, OLDSS(%edx)
++ jmpl *%eax
++ CFI_ENDPROC
++ENDPROC(arch_unwind_init_running)
++#endif
++
++.section .rodata,"a"
++#include "syscall_table.S"
++
++syscall_table_size=(.-sys_call_table)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/fixup.c linux-2.6.18-xen/arch/i386/kernel/fixup.c
+--- linux-2.6.18.1/arch/i386/kernel/fixup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/fixup.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,92 @@
++/******************************************************************************
++ * fixup.c
++ *
++ * Binary-rewriting of certain IA32 instructions, on notification by Xen.
++ * Used to avoid repeated slow emulation of common instructions used by the
++ * user-space TLS (Thread-Local Storage) libraries.
++ *
++ * **** NOTE ****
++ * Issues with the binary rewriting have caused it to be removed. Instead
++ * we rely on Xen's emulator to boot the kernel, and then print a banner
++ * message recommending that the user disables /lib/tls.
++ *
++ * Copyright (c) 2004, K A Fraser
++ *
++ * 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/init.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/version.h>
++
++#define DP(_f, _args...) printk(KERN_ALERT " " _f "\n" , ## _args )
++
++fastcall void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
++{
++#if 0
++ static unsigned long printed = 0;
++ char info[100];
++ int i;
++
++ if (test_and_set_bit(0, &printed))
++ return;
++
++ HYPERVISOR_vm_assist(
++ VMASST_CMD_disable, VMASST_TYPE_4gb_segments_notify);
++
++ sprintf(info, "%s (pid=%d)", current->comm, current->tgid);
++
++
++ DP("");
++ DP("***************************************************************");
++ DP("***************************************************************");
++ DP("** WARNING: Currently emulating unsupported memory accesses **");
++ DP("** in /lib/tls glibc libraries. The emulation is **");
++ DP("** slow. To ensure full performance you should **");
++ DP("** install a 'xen-friendly' (nosegneg) version of **");
++ DP("** the library, or disable tls support by executing **");
++ DP("** the following as root: **");
++ DP("** mv /lib/tls /lib/tls.disabled **");
++ DP("** Offending process: %-38.38s **", info);
++ DP("***************************************************************");
++ DP("***************************************************************");
++ DP("");
++
++ for (i = 5; i > 0; i--) {
++ touch_softlockup_watchdog();
++ printk("Pausing... %d", i);
++ mdelay(1000);
++ printk("\b\b\b\b\b\b\b\b\b\b\b\b");
++ }
++
++ printk("Continuing...\n\n");
++#else
++ if (printk_ratelimit())
++ printk(KERN_WARNING
++ "4gb seg fixup, process %s (pid %d), cs:ip %02x:%08lx\n",
++ current->comm, current->tgid, regs->xcs, regs->eip);
++#endif
++}
++
++static int __init fixup_init(void)
++{
++ HYPERVISOR_vm_assist(
++ VMASST_CMD_enable, VMASST_TYPE_4gb_segments_notify);
++ return 0;
++}
++__initcall(fixup_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/head-xen.S linux-2.6.18-xen/arch/i386/kernel/head-xen.S
+--- linux-2.6.18.1/arch/i386/kernel/head-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/head-xen.S 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,200 @@
++
++
++.text
++#include <linux/elfnote.h>
++#include <linux/threads.h>
++#include <linux/linkage.h>
++#include <asm/segment.h>
++#include <asm/page.h>
++#include <asm/thread_info.h>
++#include <asm/asm-offsets.h>
++#include <xen/interface/arch-x86_32.h>
++#include <xen/interface/elfnote.h>
++
++/*
++ * References to members of the new_cpu_data structure.
++ */
++
++#define X86 new_cpu_data+CPUINFO_x86
++#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor
++#define X86_MODEL new_cpu_data+CPUINFO_x86_model
++#define X86_MASK new_cpu_data+CPUINFO_x86_mask
++#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math
++#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level
++#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability
++#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id
++
++#define VIRT_ENTRY_OFFSET 0x0
++.org VIRT_ENTRY_OFFSET
++ENTRY(startup_32)
++ movl %esi,xen_start_info
++ cld
++
++ /* Set up the stack pointer */
++ movl $(init_thread_union+THREAD_SIZE),%esp
++
++ /* get vendor info */
++ xorl %eax,%eax # call CPUID with 0 -> return vendor ID
++ XEN_CPUID
++ movl %eax,X86_CPUID # save CPUID level
++ movl %ebx,X86_VENDOR_ID # lo 4 chars
++ movl %edx,X86_VENDOR_ID+4 # next 4 chars
++ movl %ecx,X86_VENDOR_ID+8 # last 4 chars
++
++ movl $1,%eax # Use the CPUID instruction to get CPU type
++ XEN_CPUID
++ movb %al,%cl # save reg for future use
++ andb $0x0f,%ah # mask processor family
++ movb %ah,X86
++ andb $0xf0,%al # mask model
++ shrb $4,%al
++ movb %al,X86_MODEL
++ andb $0x0f,%cl # mask mask revision
++ movb %cl,X86_MASK
++ movl %edx,X86_CAPABILITY
++
++ movb $1,X86_HARD_MATH
++
++ xorl %eax,%eax # Clear FS/GS and LDT
++ movl %eax,%fs
++ movl %eax,%gs
++ cld # gcc2 wants the direction flag cleared at all times
++
++ call start_kernel
++L6:
++ jmp L6 # main should never return here, but
++ # just in case, we know what happens.
++
++#define HYPERCALL_PAGE_OFFSET 0x1000
++.org HYPERCALL_PAGE_OFFSET
++ENTRY(hypercall_page)
++.skip 0x1000
++
++/*
++ * Real beginning of normal "text" segment
++ */
++ENTRY(stext)
++ENTRY(_stext)
++
++/*
++ * BSS section
++ */
++.section ".bss.page_aligned","w"
++ENTRY(empty_zero_page)
++ .fill 4096,1,0
++
++/*
++ * This starts the data section.
++ */
++.data
++
++/*
++ * The Global Descriptor Table contains 28 quadwords, per-CPU.
++ */
++ENTRY(cpu_gdt_table)
++ .quad 0x0000000000000000 /* NULL descriptor */
++ .quad 0x0000000000000000 /* 0x0b reserved */
++ .quad 0x0000000000000000 /* 0x13 reserved */
++ .quad 0x0000000000000000 /* 0x1b reserved */
++ .quad 0x0000000000000000 /* 0x20 unused */
++ .quad 0x0000000000000000 /* 0x28 unused */
++ .quad 0x0000000000000000 /* 0x33 TLS entry 1 */
++ .quad 0x0000000000000000 /* 0x3b TLS entry 2 */
++ .quad 0x0000000000000000 /* 0x43 TLS entry 3 */
++ .quad 0x0000000000000000 /* 0x4b reserved */
++ .quad 0x0000000000000000 /* 0x53 reserved */
++ .quad 0x0000000000000000 /* 0x5b reserved */
++
++ .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */
++ .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */
++ .quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */
++ .quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */
++
++ .quad 0x0000000000000000 /* 0x80 TSS descriptor */
++ .quad 0x0000000000000000 /* 0x88 LDT descriptor */
++
++ /*
++ * Segments used for calling PnP BIOS have byte granularity.
++ * They code segments and data segments have fixed 64k limits,
++ * the transfer segment sizes are set at run time.
++ */
++ .quad 0x0000000000000000 /* 0x90 32-bit code */
++ .quad 0x0000000000000000 /* 0x98 16-bit code */
++ .quad 0x0000000000000000 /* 0xa0 16-bit data */
++ .quad 0x0000000000000000 /* 0xa8 16-bit data */
++ .quad 0x0000000000000000 /* 0xb0 16-bit data */
++
++ /*
++ * The APM segments have byte granularity and their bases
++ * are set at run time. All have 64k limits.
++ */
++ .quad 0x0000000000000000 /* 0xb8 APM CS code */
++ .quad 0x0000000000000000 /* 0xc0 APM CS 16 code (16 bit) */
++ .quad 0x0000000000000000 /* 0xc8 APM DS data */
++
++ .quad 0x0000000000000000 /* 0xd0 - ESPFIX 16-bit SS */
++ .quad 0x0000000000000000 /* 0xd8 - unused */
++ .quad 0x0000000000000000 /* 0xe0 - unused */
++ .quad 0x0000000000000000 /* 0xe8 - unused */
++ .quad 0x0000000000000000 /* 0xf0 - unused */
++ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
++
++#ifdef CONFIG_XEN_COMPAT_030002
++/*
++ * __xen_guest information
++ */
++.macro utoa value
++ .if (\value) < 0 || (\value) >= 0x10
++ utoa (((\value)>>4)&0x0fffffff)
++ .endif
++ .if ((\value) & 0xf) < 10
++ .byte '0' + ((\value) & 0xf)
++ .else
++ .byte 'A' + ((\value) & 0xf) - 10
++ .endif
++.endm
++
++.section __xen_guest
++ .ascii "GUEST_OS=linux,GUEST_VER=2.6"
++ .ascii ",XEN_VER=xen-3.0"
++ .ascii ",VIRT_BASE=0x"
++ utoa __PAGE_OFFSET
++ .ascii ",ELF_PADDR_OFFSET=0x"
++ utoa __PAGE_OFFSET
++ .ascii ",VIRT_ENTRY=0x"
++ utoa (__PAGE_OFFSET + __PHYSICAL_START + VIRT_ENTRY_OFFSET)
++ .ascii ",HYPERCALL_PAGE=0x"
++ utoa ((__PHYSICAL_START+HYPERCALL_PAGE_OFFSET)>>PAGE_SHIFT)
++ .ascii ",FEATURES=writable_page_tables"
++ .ascii "|writable_descriptor_tables"
++ .ascii "|auto_translated_physmap"
++ .ascii "|pae_pgdir_above_4gb"
++ .ascii "|supervisor_mode_kernel"
++#ifdef CONFIG_X86_PAE
++ .ascii ",PAE=yes[extended-cr3]"
++#else
++ .ascii ",PAE=no"
++#endif
++ .ascii ",LOADER=generic"
++ .byte 0
++#endif /* CONFIG_XEN_COMPAT_030002 */
++
++
++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "linux")
++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "2.6")
++ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0")
++ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long, __PAGE_OFFSET)
++#ifdef CONFIG_XEN_COMPAT_030002
++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, __PAGE_OFFSET)
++#else
++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, 0)
++#endif /* !CONFIG_XEN_COMPAT_030002 */
++ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long, startup_32)
++ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long, hypercall_page)
++ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel")
++#ifdef CONFIG_X86_PAE
++ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "yes")
++#else
++ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "no")
++#endif
++ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic")
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/init_task-xen.c linux-2.6.18-xen/arch/i386/kernel/init_task-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/init_task-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/init_task-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/init_task.h>
++#include <linux/fs.h>
++#include <linux/mqueue.h>
++
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/desc.h>
++
++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);
++
++#define swapper_pg_dir ((pgd_t *)NULL)
++struct mm_struct init_mm = INIT_MM(init_mm);
++#undef swapper_pg_dir
++
++EXPORT_SYMBOL(init_mm);
++
++/*
++ * Initial thread structure.
++ *
++ * We need to make sure that this is THREAD_SIZE aligned due to the
++ * way process stacks are handled. This is done by having a special
++ * "init_task" linker map entry..
++ */
++union thread_union init_thread_union
++ __attribute__((__section__(".data.init_task"))) =
++ { INIT_THREAD_INFO(init_task) };
++
++/*
++ * Initial task structure.
++ *
++ * All other task structs will be allocated on slabs in fork.c
++ */
++struct task_struct init_task = INIT_TASK(init_task);
++
++EXPORT_SYMBOL(init_task);
++
++#ifndef CONFIG_X86_NO_TSS
++/*
++ * per-CPU TSS segments. Threads are completely 'soft' on Linux,
++ * no more per-task TSS's.
++ */
++DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
++#endif
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/io_apic-xen.c linux-2.6.18-xen/arch/i386/kernel/io_apic-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/io_apic-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/io_apic-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,2771 @@
++/*
++ * Intel IO-APIC support for multi-Pentium hosts.
++ *
++ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo
++ *
++ * Many thanks to Stig Venaas for trying out countless experimental
++ * patches and reporting/debugging problems patiently!
++ *
++ * (c) 1999, Multiple IO-APIC support, developed by
++ * Ken-ichi Yaku <yaku at css1.kbnes.nec.co.jp> and
++ * Hidemi Kishimoto <kisimoto at css1.kbnes.nec.co.jp>,
++ * further tested and cleaned up by Zach Brown <zab at redhat.com>
++ * and Ingo Molnar <mingo at redhat.com>
++ *
++ * Fixes
++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
++ * thanks to Eric Gilmore
++ * and Rolf G. Tews
++ * for testing these extensively
++ * Paul Diefenbaugh : Added full ACPI support
++ */
++
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/smp_lock.h>
++#include <linux/mc146818rtc.h>
++#include <linux/compiler.h>
++#include <linux/acpi.h>
++#include <linux/module.h>
++#include <linux/sysdev.h>
++
++#include <asm/io.h>
++#include <asm/smp.h>
++#include <asm/desc.h>
++#include <asm/timer.h>
++#include <asm/i8259.h>
++#include <asm/nmi.h>
++
++#include <mach_apic.h>
++
++#include "io_ports.h"
++
++#ifdef CONFIG_XEN
++
++#include <xen/interface/xen.h>
++#include <xen/interface/physdev.h>
++
++/* Fake i8259 */
++#define make_8259A_irq(_irq) (io_apic_irqs &= ~(1UL<<(_irq)))
++#define disable_8259A_irq(_irq) ((void)0)
++#define i8259A_irq_pending(_irq) (0)
++
++unsigned long io_apic_irqs;
++
++static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg)
++{
++ struct physdev_apic apic_op;
++ int ret;
++
++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr;
++ apic_op.reg = reg;
++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
++ if (ret)
++ return ret;
++ return apic_op.value;
++}
++
++static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
++{
++ struct physdev_apic apic_op;
++
++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr;
++ apic_op.reg = reg;
++ apic_op.value = value;
++ HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
++}
++
++#define io_apic_read(a,r) xen_io_apic_read(a,r)
++#define io_apic_write(a,r,v) xen_io_apic_write(a,r,v)
++
++#endif /* CONFIG_XEN */
++
++int (*ioapic_renumber_irq)(int ioapic, int irq);
++atomic_t irq_mis_count;
++
++/* Where if anywhere is the i8259 connect in external int mode */
++static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
++
++static DEFINE_SPINLOCK(ioapic_lock);
++static DEFINE_SPINLOCK(vector_lock);
++
++int timer_over_8254 __initdata = 1;
++
++/*
++ * Is the SiS APIC rmw bug present ?
++ * -1 = don't know, 0 = no, 1 = yes
++ */
++int sis_apic_bug = -1;
++
++/*
++ * # of IRQ routing registers
++ */
++int nr_ioapic_registers[MAX_IO_APICS];
++
++int disable_timer_pin_1 __initdata;
++
++/*
++ * Rough estimation of how many shared IRQs there are, can
++ * be changed anytime.
++ */
++#define MAX_PLUS_SHARED_IRQS NR_IRQS
++#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
++
++/*
++ * This is performance-critical, we want to do it O(1)
++ *
++ * the indexing order of this array favors 1:1 mappings
++ * between pins and IRQs.
++ */
++
++static struct irq_pin_list {
++ int apic, pin, next;
++} irq_2_pin[PIN_MAP_SIZE];
++
++int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
++#ifdef CONFIG_PCI_MSI
++#define vector_to_irq(vector) \
++ (platform_legacy_irq(vector) ? vector : vector_irq[vector])
++#else
++#define vector_to_irq(vector) (vector)
++#endif
++
++/*
++ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
++ * shared ISA-space IRQs, so we have to support them. We are super
++ * fast in the common case, and fast for shared ISA-space IRQs.
++ */
++static void add_pin_to_irq(unsigned int irq, int apic, int pin)
++{
++ static int first_free_entry = NR_IRQS;
++ struct irq_pin_list *entry = irq_2_pin + irq;
++
++ while (entry->next)
++ entry = irq_2_pin + entry->next;
++
++ if (entry->pin != -1) {
++ entry->next = first_free_entry;
++ entry = irq_2_pin + entry->next;
++ if (++first_free_entry >= PIN_MAP_SIZE)
++ panic("io_apic.c: whoops");
++ }
++ entry->apic = apic;
++ entry->pin = pin;
++}
++
++#ifdef CONFIG_XEN
++#define clear_IO_APIC() ((void)0)
++#else
++/*
++ * Reroute an IRQ to a different pin.
++ */
++static void __init replace_pin_at_irq(unsigned int irq,
++ int oldapic, int oldpin,
++ int newapic, int newpin)
++{
++ struct irq_pin_list *entry = irq_2_pin + irq;
++
++ while (1) {
++ if (entry->apic == oldapic && entry->pin == oldpin) {
++ entry->apic = newapic;
++ entry->pin = newpin;
++ }
++ if (!entry->next)
++ break;
++ entry = irq_2_pin + entry->next;
++ }
++}
++
++static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable)
++{
++ struct irq_pin_list *entry = irq_2_pin + irq;
++ unsigned int pin, reg;
++
++ for (;;) {
++ pin = entry->pin;
++ if (pin == -1)
++ break;
++ reg = io_apic_read(entry->apic, 0x10 + pin*2);
++ reg &= ~disable;
++ reg |= enable;
++ io_apic_modify(entry->apic, 0x10 + pin*2, reg);
++ if (!entry->next)
++ break;
++ entry = irq_2_pin + entry->next;
++ }
++}
++
++/* mask = 1 */
++static void __mask_IO_APIC_irq (unsigned int irq)
++{
++ __modify_IO_APIC_irq(irq, 0x00010000, 0);
++}
++
++/* mask = 0 */
++static void __unmask_IO_APIC_irq (unsigned int irq)
++{
++ __modify_IO_APIC_irq(irq, 0, 0x00010000);
++}
++
++/* mask = 1, trigger = 0 */
++static void __mask_and_edge_IO_APIC_irq (unsigned int irq)
++{
++ __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000);
++}
++
++/* mask = 0, trigger = 1 */
++static void __unmask_and_level_IO_APIC_irq (unsigned int irq)
++{
++ __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000);
++}
++
++static void mask_IO_APIC_irq (unsigned int irq)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ __mask_IO_APIC_irq(irq);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++static void unmask_IO_APIC_irq (unsigned int irq)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ __unmask_IO_APIC_irq(irq);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
++{
++ struct IO_APIC_route_entry entry;
++ unsigned long flags;
++
++ /* Check delivery_mode to be sure we're not clearing an SMI pin */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
++ *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ if (entry.delivery_mode == dest_SMI)
++ return;
++
++ /*
++ * Disable it in the IO-APIC irq-routing table:
++ */
++ memset(&entry, 0, sizeof(entry));
++ entry.mask = 1;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++static void clear_IO_APIC (void)
++{
++ int apic, pin;
++
++ for (apic = 0; apic < nr_ioapics; apic++)
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
++ clear_IO_APIC_pin(apic, pin);
++}
++
++#ifdef CONFIG_SMP
++static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
++{
++ unsigned long flags;
++ int pin;
++ struct irq_pin_list *entry = irq_2_pin + irq;
++ unsigned int apicid_value;
++ cpumask_t tmp;
++
++ cpus_and(tmp, cpumask, cpu_online_map);
++ if (cpus_empty(tmp))
++ tmp = TARGET_CPUS;
++
++ cpus_and(cpumask, tmp, CPU_MASK_ALL);
++
++ apicid_value = cpu_mask_to_apicid(cpumask);
++ /* Prepare to do the io_apic_write */
++ apicid_value = apicid_value << 24;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ for (;;) {
++ pin = entry->pin;
++ if (pin == -1)
++ break;
++ io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value);
++ if (!entry->next)
++ break;
++ entry = irq_2_pin + entry->next;
++ }
++ set_irq_info(irq, cpumask);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++#if defined(CONFIG_IRQBALANCE)
++# include <asm/processor.h> /* kernel_thread() */
++# include <linux/kernel_stat.h> /* kstat */
++# include <linux/slab.h> /* kmalloc() */
++# include <linux/timer.h> /* time_after() */
++
++#ifdef CONFIG_BALANCED_IRQ_DEBUG
++# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0)
++# define Dprintk(x...) do { TDprintk(x); } while (0)
++# else
++# define TDprintk(x...)
++# define Dprintk(x...)
++# endif
++
++#define IRQBALANCE_CHECK_ARCH -999
++#define MAX_BALANCED_IRQ_INTERVAL (5*HZ)
++#define MIN_BALANCED_IRQ_INTERVAL (HZ/2)
++#define BALANCED_IRQ_MORE_DELTA (HZ/10)
++#define BALANCED_IRQ_LESS_DELTA (HZ)
++
++static int irqbalance_disabled __read_mostly = IRQBALANCE_CHECK_ARCH;
++static int physical_balance __read_mostly;
++static long balanced_irq_interval __read_mostly = MAX_BALANCED_IRQ_INTERVAL;
++
++static struct irq_cpu_info {
++ unsigned long * last_irq;
++ unsigned long * irq_delta;
++ unsigned long irq;
++} irq_cpu_data[NR_CPUS];
++
++#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq)
++#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq])
++#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq])
++
++#define IDLE_ENOUGH(cpu,now) \
++ (idle_cpu(cpu) && ((now) - per_cpu(irq_stat, (cpu)).idle_timestamp > 1))
++
++#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask)
++
++#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i]))
++
++static cpumask_t balance_irq_affinity[NR_IRQS] = {
++ [0 ... NR_IRQS-1] = CPU_MASK_ALL
++};
++
++void set_balance_irq_affinity(unsigned int irq, cpumask_t mask)
++{
++ balance_irq_affinity[irq] = mask;
++}
++
++static unsigned long move(int curr_cpu, cpumask_t allowed_mask,
++ unsigned long now, int direction)
++{
++ int search_idle = 1;
++ int cpu = curr_cpu;
++
++ goto inside;
++
++ do {
++ if (unlikely(cpu == curr_cpu))
++ search_idle = 0;
++inside:
++ if (direction == 1) {
++ cpu++;
++ if (cpu >= NR_CPUS)
++ cpu = 0;
++ } else {
++ cpu--;
++ if (cpu == -1)
++ cpu = NR_CPUS-1;
++ }
++ } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) ||
++ (search_idle && !IDLE_ENOUGH(cpu,now)));
++
++ return cpu;
++}
++
++static inline void balance_irq(int cpu, int irq)
++{
++ unsigned long now = jiffies;
++ cpumask_t allowed_mask;
++ unsigned int new_cpu;
++
++ if (irqbalance_disabled)
++ return;
++
++ cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[irq]);
++ new_cpu = move(cpu, allowed_mask, now, 1);
++ if (cpu != new_cpu) {
++ set_pending_irq(irq, cpumask_of_cpu(new_cpu));
++ }
++}
++
++static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
++{
++ int i, j;
++ Dprintk("Rotating IRQs among CPUs.\n");
++ for_each_online_cpu(i) {
++ for (j = 0; j < NR_IRQS; j++) {
++ if (!irq_desc[j].action)
++ continue;
++ /* Is it a significant load ? */
++ if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) <
++ useful_load_threshold)
++ continue;
++ balance_irq(i, j);
++ }
++ }
++ balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
++ balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
++ return;
++}
++
++static void do_irq_balance(void)
++{
++ int i, j;
++ unsigned long max_cpu_irq = 0, min_cpu_irq = (~0);
++ unsigned long move_this_load = 0;
++ int max_loaded = 0, min_loaded = 0;
++ int load;
++ unsigned long useful_load_threshold = balanced_irq_interval + 10;
++ int selected_irq;
++ int tmp_loaded, first_attempt = 1;
++ unsigned long tmp_cpu_irq;
++ unsigned long imbalance = 0;
++ cpumask_t allowed_mask, target_cpu_mask, tmp;
++
++ for_each_possible_cpu(i) {
++ int package_index;
++ CPU_IRQ(i) = 0;
++ if (!cpu_online(i))
++ continue;
++ package_index = CPU_TO_PACKAGEINDEX(i);
++ for (j = 0; j < NR_IRQS; j++) {
++ unsigned long value_now, delta;
++ /* Is this an active IRQ? */
++ if (!irq_desc[j].action)
++ continue;
++ if ( package_index == i )
++ IRQ_DELTA(package_index,j) = 0;
++ /* Determine the total count per processor per IRQ */
++ value_now = (unsigned long) kstat_cpu(i).irqs[j];
++
++ /* Determine the activity per processor per IRQ */
++ delta = value_now - LAST_CPU_IRQ(i,j);
++
++ /* Update last_cpu_irq[][] for the next time */
++ LAST_CPU_IRQ(i,j) = value_now;
++
++ /* Ignore IRQs whose rate is less than the clock */
++ if (delta < useful_load_threshold)
++ continue;
++ /* update the load for the processor or package total */
++ IRQ_DELTA(package_index,j) += delta;
++
++ /* Keep track of the higher numbered sibling as well */
++ if (i != package_index)
++ CPU_IRQ(i) += delta;
++ /*
++ * We have sibling A and sibling B in the package
++ *
++ * cpu_irq[A] = load for cpu A + load for cpu B
++ * cpu_irq[B] = load for cpu B
++ */
++ CPU_IRQ(package_index) += delta;
++ }
++ }
++ /* Find the least loaded processor package */
++ for_each_online_cpu(i) {
++ if (i != CPU_TO_PACKAGEINDEX(i))
++ continue;
++ if (min_cpu_irq > CPU_IRQ(i)) {
++ min_cpu_irq = CPU_IRQ(i);
++ min_loaded = i;
++ }
++ }
++ max_cpu_irq = ULONG_MAX;
++
++tryanothercpu:
++ /* Look for heaviest loaded processor.
++ * We may come back to get the next heaviest loaded processor.
++ * Skip processors with trivial loads.
++ */
++ tmp_cpu_irq = 0;
++ tmp_loaded = -1;
++ for_each_online_cpu(i) {
++ if (i != CPU_TO_PACKAGEINDEX(i))
++ continue;
++ if (max_cpu_irq <= CPU_IRQ(i))
++ continue;
++ if (tmp_cpu_irq < CPU_IRQ(i)) {
++ tmp_cpu_irq = CPU_IRQ(i);
++ tmp_loaded = i;
++ }
++ }
++
++ if (tmp_loaded == -1) {
++ /* In the case of small number of heavy interrupt sources,
++ * loading some of the cpus too much. We use Ingo's original
++ * approach to rotate them around.
++ */
++ if (!first_attempt && imbalance >= useful_load_threshold) {
++ rotate_irqs_among_cpus(useful_load_threshold);
++ return;
++ }
++ goto not_worth_the_effort;
++ }
++
++ first_attempt = 0; /* heaviest search */
++ max_cpu_irq = tmp_cpu_irq; /* load */
++ max_loaded = tmp_loaded; /* processor */
++ imbalance = (max_cpu_irq - min_cpu_irq) / 2;
++
++ Dprintk("max_loaded cpu = %d\n", max_loaded);
++ Dprintk("min_loaded cpu = %d\n", min_loaded);
++ Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq);
++ Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq);
++ Dprintk("load imbalance = %lu\n", imbalance);
++
++ /* if imbalance is less than approx 10% of max load, then
++ * observe diminishing returns action. - quit
++ */
++ if (imbalance < (max_cpu_irq >> 3)) {
++ Dprintk("Imbalance too trivial\n");
++ goto not_worth_the_effort;
++ }
++
++tryanotherirq:
++ /* if we select an IRQ to move that can't go where we want, then
++ * see if there is another one to try.
++ */
++ move_this_load = 0;
++ selected_irq = -1;
++ for (j = 0; j < NR_IRQS; j++) {
++ /* Is this an active IRQ? */
++ if (!irq_desc[j].action)
++ continue;
++ if (imbalance <= IRQ_DELTA(max_loaded,j))
++ continue;
++ /* Try to find the IRQ that is closest to the imbalance
++ * without going over.
++ */
++ if (move_this_load < IRQ_DELTA(max_loaded,j)) {
++ move_this_load = IRQ_DELTA(max_loaded,j);
++ selected_irq = j;
++ }
++ }
++ if (selected_irq == -1) {
++ goto tryanothercpu;
++ }
++
++ imbalance = move_this_load;
++
++ /* For physical_balance case, we accumlated both load
++ * values in the one of the siblings cpu_irq[],
++ * to use the same code for physical and logical processors
++ * as much as possible.
++ *
++ * NOTE: the cpu_irq[] array holds the sum of the load for
++ * sibling A and sibling B in the slot for the lowest numbered
++ * sibling (A), _AND_ the load for sibling B in the slot for
++ * the higher numbered sibling.
++ *
++ * We seek the least loaded sibling by making the comparison
++ * (A+B)/2 vs B
++ */
++ load = CPU_IRQ(min_loaded) >> 1;
++ for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) {
++ if (load > CPU_IRQ(j)) {
++ /* This won't change cpu_sibling_map[min_loaded] */
++ load = CPU_IRQ(j);
++ min_loaded = j;
++ }
++ }
++
++ cpus_and(allowed_mask,
++ cpu_online_map,
++ balance_irq_affinity[selected_irq]);
++ target_cpu_mask = cpumask_of_cpu(min_loaded);
++ cpus_and(tmp, target_cpu_mask, allowed_mask);
++
++ if (!cpus_empty(tmp)) {
++
++ Dprintk("irq = %d moved to cpu = %d\n",
++ selected_irq, min_loaded);
++ /* mark for change destination */
++ set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
++
++ /* Since we made a change, come back sooner to
++ * check for more variation.
++ */
++ balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
++ balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
++ return;
++ }
++ goto tryanotherirq;
++
++not_worth_the_effort:
++ /*
++ * if we did not find an IRQ to move, then adjust the time interval
++ * upward
++ */
++ balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
++ balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);
++ Dprintk("IRQ worth rotating not found\n");
++ return;
++}
++
++static int balanced_irq(void *unused)
++{
++ int i;
++ unsigned long prev_balance_time = jiffies;
++ long time_remaining = balanced_irq_interval;
++
++ daemonize("kirqd");
++
++ /* push everything to CPU 0 to give us a starting point. */
++ for (i = 0 ; i < NR_IRQS ; i++) {
++ irq_desc[i].pending_mask[i] = cpumask_of_cpu(0);
++ set_pending_irq(i, cpumask_of_cpu(0));
++ }
++
++ for ( ; ; ) {
++ time_remaining = schedule_timeout_interruptible(time_remaining);
++ 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;
++}
++
++static int __init balanced_irq_init(void)
++{
++ int i;
++ struct cpuinfo_x86 *c;
++ cpumask_t tmp;
++
++ cpus_shift_right(tmp, cpu_online_map, 2);
++ c = &boot_cpu_data;
++ /* When not overwritten by the command line ask subarchitecture. */
++ if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
++ irqbalance_disabled = NO_BALANCE_IRQ;
++ if (irqbalance_disabled)
++ return 0;
++
++ /* disable irqbalance completely if there is only one processor online */
++ if (num_online_cpus() < 2) {
++ irqbalance_disabled = 1;
++ return 0;
++ }
++ /*
++ * Enable physical balance only if more than 1 physical processor
++ * is present
++ */
++ if (smp_num_siblings > 1 && !cpus_empty(tmp))
++ physical_balance = 1;
++
++ for_each_online_cpu(i) {
++ irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
++ irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
++ if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) {
++ printk(KERN_ERR "balanced_irq_init: out of memory");
++ goto failed;
++ }
++ memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS);
++ memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS);
++ }
++
++ printk(KERN_INFO "Starting balanced_irq\n");
++ if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0)
++ return 0;
++ else
++ printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
++failed:
++ for_each_possible_cpu(i) {
++ kfree(irq_cpu_data[i].irq_delta);
++ irq_cpu_data[i].irq_delta = NULL;
++ kfree(irq_cpu_data[i].last_irq);
++ irq_cpu_data[i].last_irq = NULL;
++ }
++ return 0;
++}
++
++int __init irqbalance_disable(char *str)
++{
++ irqbalance_disabled = 1;
++ return 1;
++}
++
++__setup("noirqbalance", irqbalance_disable);
++
++late_initcall(balanced_irq_init);
++#endif /* CONFIG_IRQBALANCE */
++#endif /* CONFIG_SMP */
++#endif
++
++#ifndef CONFIG_SMP
++void fastcall send_IPI_self(int vector)
++{
++#ifndef CONFIG_XEN
++ unsigned int cfg;
++
++ /*
++ * Wait for idle.
++ */
++ apic_wait_icr_idle();
++ cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL;
++ /*
++ * Send the IPI. The write to APIC_ICR fires this off.
++ */
++ apic_write_around(APIC_ICR, cfg);
++#endif
++}
++#endif /* !CONFIG_SMP */
++
++
++/*
++ * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
++ * specific CPU-side IRQs.
++ */
++
++#define MAX_PIRQS 8
++static int pirq_entries [MAX_PIRQS];
++static int pirqs_enabled;
++int skip_ioapic_setup;
++
++static int __init ioapic_setup(char *str)
++{
++ skip_ioapic_setup = 1;
++ return 1;
++}
++
++__setup("noapic", ioapic_setup);
++
++static int __init ioapic_pirq_setup(char *str)
++{
++ int i, max;
++ int ints[MAX_PIRQS+1];
++
++ get_options(str, ARRAY_SIZE(ints), ints);
++
++ for (i = 0; i < MAX_PIRQS; i++)
++ pirq_entries[i] = -1;
++
++ pirqs_enabled = 1;
++ apic_printk(APIC_VERBOSE, KERN_INFO
++ "PIRQ redirection, working around broken MP-BIOS.\n");
++ max = MAX_PIRQS;
++ if (ints[0] < MAX_PIRQS)
++ max = ints[0];
++
++ for (i = 0; i < max; i++) {
++ apic_printk(APIC_VERBOSE, KERN_DEBUG
++ "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
++ /*
++ * PIRQs are mapped upside down, usually.
++ */
++ pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
++ }
++ return 1;
++}
++
++__setup("pirq=", ioapic_pirq_setup);
++
++/*
++ * Find the IRQ entry number of a certain pin.
++ */
++static int find_irq_entry(int apic, int pin, int type)
++{
++ int i;
++
++ for (i = 0; i < mp_irq_entries; i++)
++ if (mp_irqs[i].mpc_irqtype == type &&
++ (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
++ mp_irqs[i].mpc_dstirq == pin)
++ return i;
++
++ return -1;
++}
++
++/*
++ * Find the pin to which IRQ[irq] (ISA) is connected
++ */
++static int __init find_isa_irq_pin(int irq, int type)
++{
++ int i;
++
++ for (i = 0; i < mp_irq_entries; i++) {
++ int lbus = mp_irqs[i].mpc_srcbus;
++
++ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_NEC98
++ ) &&
++ (mp_irqs[i].mpc_irqtype == type) &&
++ (mp_irqs[i].mpc_srcbusirq == irq))
++
++ return mp_irqs[i].mpc_dstirq;
++ }
++ return -1;
++}
++
++static int __init find_isa_irq_apic(int irq, int type)
++{
++ int i;
++
++ for (i = 0; i < mp_irq_entries; i++) {
++ int lbus = mp_irqs[i].mpc_srcbus;
++
++ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_NEC98
++ ) &&
++ (mp_irqs[i].mpc_irqtype == type) &&
++ (mp_irqs[i].mpc_srcbusirq == irq))
++ break;
++ }
++ if (i < mp_irq_entries) {
++ int apic;
++ for(apic = 0; apic < nr_ioapics; apic++) {
++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
++ return apic;
++ }
++ }
++
++ return -1;
++}
++
++/*
++ * Find a specific PCI IRQ entry.
++ * Not an __init, possibly needed by modules
++ */
++static int pin_2_irq(int idx, int apic, int pin);
++
++int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
++{
++ int apic, i, best_guess = -1;
++
++ apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, "
++ "slot:%d, pin:%d.\n", bus, slot, pin);
++ if (mp_bus_id_to_pci_bus[bus] == -1) {
++ printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
++ return -1;
++ }
++ for (i = 0; i < mp_irq_entries; i++) {
++ int lbus = mp_irqs[i].mpc_srcbus;
++
++ for (apic = 0; apic < nr_ioapics; apic++)
++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||
++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
++ break;
++
++ if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
++ !mp_irqs[i].mpc_irqtype &&
++ (bus == lbus) &&
++ (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
++ int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
++
++ if (!(apic || IO_APIC_IRQ(irq)))
++ continue;
++
++ if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
++ return irq;
++ /*
++ * Use the first all-but-pin matching entry as a
++ * best-guess fuzzy result for broken mptables.
++ */
++ if (best_guess < 0)
++ best_guess = irq;
++ }
++ }
++ return best_guess;
++}
++EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
++
++/*
++ * This function currently is only a helper for the i386 smp boot process where
++ * we need to reprogram the ioredtbls to cater for the cpus which have come online
++ * so mask in all cases should simply be TARGET_CPUS
++ */
++#ifdef CONFIG_SMP
++#ifndef CONFIG_XEN
++void __init setup_ioapic_dest(void)
++{
++ int pin, ioapic, irq, irq_entry;
++
++ if (skip_ioapic_setup == 1)
++ return;
++
++ for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
++ for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
++ irq_entry = find_irq_entry(ioapic, pin, mp_INT);
++ if (irq_entry == -1)
++ continue;
++ irq = pin_2_irq(irq_entry, ioapic, pin);
++ set_ioapic_affinity_irq(irq, TARGET_CPUS);
++ }
++
++ }
++}
++#endif /* !CONFIG_XEN */
++#endif
++
++/*
++ * EISA Edge/Level control register, ELCR
++ */
++static int EISA_ELCR(unsigned int irq)
++{
++ if (irq < 16) {
++ unsigned int port = 0x4d0 + (irq >> 3);
++ return (inb(port) >> (irq & 7)) & 1;
++ }
++ apic_printk(APIC_VERBOSE, KERN_INFO
++ "Broken MPtable reports ISA irq %d\n", irq);
++ return 0;
++}
++
++/* EISA interrupts are always polarity zero and can be edge or level
++ * trigger depending on the ELCR value. If an interrupt is listed as
++ * EISA conforming in the MP table, that means its trigger type must
++ * be read in from the ELCR */
++
++#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
++#define default_EISA_polarity(idx) (0)
++
++/* ISA interrupts are always polarity zero edge triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_ISA_trigger(idx) (0)
++#define default_ISA_polarity(idx) (0)
++
++/* PCI interrupts are always polarity one level triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_PCI_trigger(idx) (1)
++#define default_PCI_polarity(idx) (1)
++
++/* MCA interrupts are always polarity zero level triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_MCA_trigger(idx) (1)
++#define default_MCA_polarity(idx) (0)
++
++/* NEC98 interrupts are always polarity zero edge triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_NEC98_trigger(idx) (0)
++#define default_NEC98_polarity(idx) (0)
++
++static int __init MPBIOS_polarity(int idx)
++{
++ int bus = mp_irqs[idx].mpc_srcbus;
++ int polarity;
++
++ /*
++ * Determine IRQ line polarity (high active or low active):
++ */
++ switch (mp_irqs[idx].mpc_irqflag & 3)
++ {
++ case 0: /* conforms, ie. bus-type dependent polarity */
++ {
++ switch (mp_bus_id_to_type[bus])
++ {
++ case MP_BUS_ISA: /* ISA pin */
++ {
++ polarity = default_ISA_polarity(idx);
++ break;
++ }
++ case MP_BUS_EISA: /* EISA pin */
++ {
++ polarity = default_EISA_polarity(idx);
++ break;
++ }
++ case MP_BUS_PCI: /* PCI pin */
++ {
++ polarity = default_PCI_polarity(idx);
++ break;
++ }
++ case MP_BUS_MCA: /* MCA pin */
++ {
++ polarity = default_MCA_polarity(idx);
++ break;
++ }
++ case MP_BUS_NEC98: /* NEC 98 pin */
++ {
++ polarity = default_NEC98_polarity(idx);
++ break;
++ }
++ default:
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ polarity = 1;
++ break;
++ }
++ }
++ break;
++ }
++ case 1: /* high active */
++ {
++ polarity = 0;
++ break;
++ }
++ case 2: /* reserved */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ polarity = 1;
++ break;
++ }
++ case 3: /* low active */
++ {
++ polarity = 1;
++ break;
++ }
++ default: /* invalid */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ polarity = 1;
++ break;
++ }
++ }
++ return polarity;
++}
++
++static int MPBIOS_trigger(int idx)
++{
++ int bus = mp_irqs[idx].mpc_srcbus;
++ int trigger;
++
++ /*
++ * Determine IRQ trigger mode (edge or level sensitive):
++ */
++ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
++ {
++ case 0: /* conforms, ie. bus-type dependent */
++ {
++ switch (mp_bus_id_to_type[bus])
++ {
++ case MP_BUS_ISA: /* ISA pin */
++ {
++ trigger = default_ISA_trigger(idx);
++ break;
++ }
++ case MP_BUS_EISA: /* EISA pin */
++ {
++ trigger = default_EISA_trigger(idx);
++ break;
++ }
++ case MP_BUS_PCI: /* PCI pin */
++ {
++ trigger = default_PCI_trigger(idx);
++ break;
++ }
++ case MP_BUS_MCA: /* MCA pin */
++ {
++ trigger = default_MCA_trigger(idx);
++ break;
++ }
++ case MP_BUS_NEC98: /* NEC 98 pin */
++ {
++ trigger = default_NEC98_trigger(idx);
++ break;
++ }
++ default:
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ trigger = 1;
++ break;
++ }
++ }
++ break;
++ }
++ case 1: /* edge */
++ {
++ trigger = 0;
++ break;
++ }
++ case 2: /* reserved */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ trigger = 1;
++ break;
++ }
++ case 3: /* level */
++ {
++ trigger = 1;
++ break;
++ }
++ default: /* invalid */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ trigger = 0;
++ break;
++ }
++ }
++ return trigger;
++}
++
++static inline int irq_polarity(int idx)
++{
++ return MPBIOS_polarity(idx);
++}
++
++static inline int irq_trigger(int idx)
++{
++ return MPBIOS_trigger(idx);
++}
++
++static int pin_2_irq(int idx, int apic, int pin)
++{
++ int irq, i;
++ int bus = mp_irqs[idx].mpc_srcbus;
++
++ /*
++ * Debugging check, we are in big trouble if this message pops up!
++ */
++ if (mp_irqs[idx].mpc_dstirq != pin)
++ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
++
++ switch (mp_bus_id_to_type[bus])
++ {
++ case MP_BUS_ISA: /* ISA pin */
++ case MP_BUS_EISA:
++ case MP_BUS_MCA:
++ case MP_BUS_NEC98:
++ {
++ irq = mp_irqs[idx].mpc_srcbusirq;
++ break;
++ }
++ case MP_BUS_PCI: /* PCI pin */
++ {
++ /*
++ * PCI IRQs are mapped in order
++ */
++ i = irq = 0;
++ while (i < apic)
++ irq += nr_ioapic_registers[i++];
++ irq += pin;
++
++ /*
++ * For MPS mode, so far only needed by ES7000 platform
++ */
++ if (ioapic_renumber_irq)
++ irq = ioapic_renumber_irq(apic, irq);
++
++ break;
++ }
++ default:
++ {
++ printk(KERN_ERR "unknown bus type %d.\n",bus);
++ irq = 0;
++ break;
++ }
++ }
++
++ /*
++ * PCI IRQ command line redirection. Yes, limits are hardcoded.
++ */
++ if ((pin >= 16) && (pin <= 23)) {
++ if (pirq_entries[pin-16] != -1) {
++ if (!pirq_entries[pin-16]) {
++ apic_printk(APIC_VERBOSE, KERN_DEBUG
++ "disabling PIRQ%d\n", pin-16);
++ } else {
++ irq = pirq_entries[pin-16];
++ apic_printk(APIC_VERBOSE, KERN_DEBUG
++ "using PIRQ%d -> IRQ %d\n",
++ pin-16, irq);
++ }
++ }
++ }
++ return irq;
++}
++
++static inline int IO_APIC_irq_trigger(int irq)
++{
++ int apic, idx, pin;
++
++ for (apic = 0; apic < nr_ioapics; apic++) {
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
++ idx = find_irq_entry(apic,pin,mp_INT);
++ if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
++ return irq_trigger(idx);
++ }
++ }
++ /*
++ * nonexistent IRQs are edge default
++ */
++ return 0;
++}
++
++/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
++u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; /* = { FIRST_DEVICE_VECTOR , 0 }; */
++
++int assign_irq_vector(int irq)
++{
++ struct physdev_irq irq_op;
++ unsigned long flags;
++
++ BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
++
++ spin_lock_irqsave(&vector_lock, flags);
++
++ if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
++ spin_unlock_irqrestore(&vector_lock, flags);
++ return IO_APIC_VECTOR(irq);
++ }
++ irq_op.irq = irq;
++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op))
++ return -ENOSPC;
++
++ vector_irq[irq_op.vector] = irq;
++ if (irq != AUTO_ASSIGN)
++ IO_APIC_VECTOR(irq) = irq_op.vector;
++
++ spin_unlock_irqrestore(&vector_lock, flags);
++
++ return irq_op.vector;
++}
++
++#ifndef CONFIG_XEN
++static struct hw_interrupt_type ioapic_level_type;
++static struct hw_interrupt_type ioapic_edge_type;
++
++#define IOAPIC_AUTO -1
++#define IOAPIC_EDGE 0
++#define IOAPIC_LEVEL 1
++
++static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
++{
++ unsigned idx;
++
++ idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
++
++ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
++ trigger == IOAPIC_LEVEL)
++ irq_desc[idx].chip = &ioapic_level_type;
++ else
++ irq_desc[idx].chip = &ioapic_edge_type;
++ set_intr_gate(vector, interrupt[idx]);
++}
++#else
++#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0)
++#endif
++
++static void __init setup_IO_APIC_irqs(void)
++{
++ struct IO_APIC_route_entry entry;
++ int apic, pin, idx, irq, first_notcon = 1, vector;
++ unsigned long flags;
++
++ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
++
++ for (apic = 0; apic < nr_ioapics; apic++) {
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
++
++ /*
++ * add it to the IO-APIC irq-routing table:
++ */
++ memset(&entry,0,sizeof(entry));
++
++ entry.delivery_mode = INT_DELIVERY_MODE;
++ entry.dest_mode = INT_DEST_MODE;
++ entry.mask = 0; /* enable IRQ */
++ entry.dest.logical.logical_dest =
++ cpu_mask_to_apicid(TARGET_CPUS);
++
++ idx = find_irq_entry(apic,pin,mp_INT);
++ if (idx == -1) {
++ if (first_notcon) {
++ apic_printk(APIC_VERBOSE, KERN_DEBUG
++ " IO-APIC (apicid-pin) %d-%d",
++ mp_ioapics[apic].mpc_apicid,
++ pin);
++ first_notcon = 0;
++ } else
++ apic_printk(APIC_VERBOSE, ", %d-%d",
++ mp_ioapics[apic].mpc_apicid, pin);
++ continue;
++ }
++
++ entry.trigger = irq_trigger(idx);
++ entry.polarity = irq_polarity(idx);
++
++ if (irq_trigger(idx)) {
++ entry.trigger = 1;
++ entry.mask = 1;
++ }
++
++ irq = pin_2_irq(idx, apic, pin);
++ /*
++ * skip adding the timer int on secondary nodes, which causes
++ * a small but painful rift in the time-space continuum
++ */
++ if (multi_timer_check(apic, irq))
++ continue;
++ else
++ add_pin_to_irq(irq, apic, pin);
++
++ if (/*!apic &&*/ !IO_APIC_IRQ(irq))
++ continue;
++
++ if (IO_APIC_IRQ(irq)) {
++ vector = assign_irq_vector(irq);
++ entry.vector = vector;
++ ioapic_register_intr(irq, vector, IOAPIC_AUTO);
++
++ if (!apic && (irq < 16))
++ disable_8259A_irq(irq);
++ }
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
++ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
++ set_native_irq_info(irq, TARGET_CPUS);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ }
++ }
++
++ if (!first_notcon)
++ apic_printk(APIC_VERBOSE, " not connected.\n");
++}
++
++/*
++ * Set up the 8259A-master output pin:
++ */
++#ifndef CONFIG_XEN
++static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
++{
++ struct IO_APIC_route_entry entry;
++ unsigned long flags;
++
++ memset(&entry,0,sizeof(entry));
++
++ disable_8259A_irq(0);
++
++ /* mask LVT0 */
++ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
++
++ /*
++ * We use logical delivery to get the timer IRQ
++ * to the first CPU.
++ */
++ entry.dest_mode = INT_DEST_MODE;
++ entry.mask = 0; /* unmask IRQ now */
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++ entry.delivery_mode = INT_DELIVERY_MODE;
++ entry.polarity = 0;
++ entry.trigger = 0;
++ entry.vector = vector;
++
++ /*
++ * The timer IRQ doesn't have to know that behind the
++ * scene we have a 8259A-master in AEOI mode ...
++ */
++ irq_desc[0].chip = &ioapic_edge_type;
++
++ /*
++ * Add it to the IO-APIC irq-routing table:
++ */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
++ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ enable_8259A_irq(0);
++}
++
++static inline void UNEXPECTED_IO_APIC(void)
++{
++}
++
++void __init print_IO_APIC(void)
++{
++ int apic, i;
++ union IO_APIC_reg_00 reg_00;
++ union IO_APIC_reg_01 reg_01;
++ union IO_APIC_reg_02 reg_02;
++ union IO_APIC_reg_03 reg_03;
++ unsigned long flags;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
++ for (i = 0; i < nr_ioapics; i++)
++ printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
++ mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
++
++ /*
++ * We are a bit conservative about what we expect. We have to
++ * know about every hardware change ASAP.
++ */
++ printk(KERN_INFO "testing the IO APIC.......................\n");
++
++ for (apic = 0; apic < nr_ioapics; apic++) {
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(apic, 0);
++ reg_01.raw = io_apic_read(apic, 1);
++ if (reg_01.bits.version >= 0x10)
++ reg_02.raw = io_apic_read(apic, 2);
++ if (reg_01.bits.version >= 0x20)
++ reg_03.raw = io_apic_read(apic, 3);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
++ printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
++ printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
++ printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
++ printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
++ if (reg_00.bits.ID >= get_physical_broadcast())
++ UNEXPECTED_IO_APIC();
++ if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
++ UNEXPECTED_IO_APIC();
++
++ printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw);
++ printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
++ if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */
++ (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */
++ (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */
++ (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */
++ (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
++ (reg_01.bits.entries != 0x2E) &&
++ (reg_01.bits.entries != 0x3F)
++ )
++ UNEXPECTED_IO_APIC();
++
++ printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
++ printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
++ if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */
++ (reg_01.bits.version != 0x10) && /* oldest IO-APICs */
++ (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
++ (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
++ (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */
++ )
++ UNEXPECTED_IO_APIC();
++ if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
++ UNEXPECTED_IO_APIC();
++
++ /*
++ * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
++ * but the value of reg_02 is read as the previous read register
++ * value, so ignore it if reg_02 == reg_01.
++ */
++ if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
++ printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
++ printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
++ if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
++ UNEXPECTED_IO_APIC();
++ }
++
++ /*
++ * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02
++ * or reg_03, but the value of reg_0[23] is read as the previous read
++ * register value, so ignore it if reg_03 == reg_0[12].
++ */
++ if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&
++ reg_03.raw != reg_01.raw) {
++ printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);
++ printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT);
++ if (reg_03.bits.__reserved_1)
++ UNEXPECTED_IO_APIC();
++ }
++
++ printk(KERN_DEBUG ".... IRQ redirection table:\n");
++
++ printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
++ " Stat Dest Deli Vect: \n");
++
++ for (i = 0; i <= reg_01.bits.entries; i++) {
++ struct IO_APIC_route_entry entry;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
++ *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ printk(KERN_DEBUG " %02x %03X %02X ",
++ i,
++ entry.dest.logical.logical_dest,
++ entry.dest.physical.physical_dest
++ );
++
++ printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
++ entry.mask,
++ entry.trigger,
++ entry.irr,
++ entry.polarity,
++ entry.delivery_status,
++ entry.dest_mode,
++ entry.delivery_mode,
++ entry.vector
++ );
++ }
++ }
++ if (use_pci_vector())
++ printk(KERN_INFO "Using vector-based indexing\n");
++ printk(KERN_DEBUG "IRQ to pin mappings:\n");
++ for (i = 0; i < NR_IRQS; i++) {
++ struct irq_pin_list *entry = irq_2_pin + i;
++ if (entry->pin < 0)
++ continue;
++ if (use_pci_vector() && !platform_legacy_irq(i))
++ printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
++ else
++ printk(KERN_DEBUG "IRQ%d ", i);
++ for (;;) {
++ printk("-> %d:%d", entry->apic, entry->pin);
++ if (!entry->next)
++ break;
++ entry = irq_2_pin + entry->next;
++ }
++ printk("\n");
++ }
++
++ printk(KERN_INFO ".................................... done.\n");
++
++ return;
++}
++
++#if 0
++
++static void print_APIC_bitfield (int base)
++{
++ unsigned int v;
++ int i, j;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);
++ for (i = 0; i < 8; i++) {
++ v = apic_read(base + i*0x10);
++ for (j = 0; j < 32; j++) {
++ if (v & (1<<j))
++ printk("1");
++ else
++ printk("0");
++ }
++ printk("\n");
++ }
++}
++
++void /*__init*/ print_local_APIC(void * dummy)
++{
++ unsigned int v, ver, maxlvt;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
++ smp_processor_id(), hard_smp_processor_id());
++ v = apic_read(APIC_ID);
++ printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v));
++ v = apic_read(APIC_LVR);
++ printk(KERN_INFO "... APIC VERSION: %08x\n", v);
++ ver = GET_APIC_VERSION(v);
++ maxlvt = get_maxlvt();
++
++ v = apic_read(APIC_TASKPRI);
++ printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
++
++ if (APIC_INTEGRATED(ver)) { /* !82489DX */
++ v = apic_read(APIC_ARBPRI);
++ printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
++ v & APIC_ARBPRI_MASK);
++ v = apic_read(APIC_PROCPRI);
++ printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
++ }
++
++ v = apic_read(APIC_EOI);
++ printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
++ v = apic_read(APIC_RRR);
++ printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
++ v = apic_read(APIC_LDR);
++ printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
++ v = apic_read(APIC_DFR);
++ printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
++ v = apic_read(APIC_SPIV);
++ printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
++
++ printk(KERN_DEBUG "... APIC ISR field:\n");
++ print_APIC_bitfield(APIC_ISR);
++ printk(KERN_DEBUG "... APIC TMR field:\n");
++ print_APIC_bitfield(APIC_TMR);
++ printk(KERN_DEBUG "... APIC IRR field:\n");
++ print_APIC_bitfield(APIC_IRR);
++
++ if (APIC_INTEGRATED(ver)) { /* !82489DX */
++ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
++ apic_write(APIC_ESR, 0);
++ v = apic_read(APIC_ESR);
++ printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
++ }
++
++ v = apic_read(APIC_ICR);
++ printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
++ v = apic_read(APIC_ICR2);
++ printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
++
++ v = apic_read(APIC_LVTT);
++ printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
++
++ if (maxlvt > 3) { /* PC is LVT#4. */
++ v = apic_read(APIC_LVTPC);
++ printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
++ }
++ v = apic_read(APIC_LVT0);
++ printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
++ v = apic_read(APIC_LVT1);
++ printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
++
++ if (maxlvt > 2) { /* ERR is LVT#3. */
++ v = apic_read(APIC_LVTERR);
++ printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
++ }
++
++ v = apic_read(APIC_TMICT);
++ printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
++ v = apic_read(APIC_TMCCT);
++ printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
++ v = apic_read(APIC_TDCR);
++ printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
++ printk("\n");
++}
++
++void print_all_local_APICs (void)
++{
++ on_each_cpu(print_local_APIC, NULL, 1, 1);
++}
++
++void /*__init*/ print_PIC(void)
++{
++ unsigned int v;
++ unsigned long flags;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk(KERN_DEBUG "\nprinting PIC contents\n");
++
++ spin_lock_irqsave(&i8259A_lock, flags);
++
++ v = inb(0xa1) << 8 | inb(0x21);
++ printk(KERN_DEBUG "... PIC IMR: %04x\n", v);
++
++ v = inb(0xa0) << 8 | inb(0x20);
++ printk(KERN_DEBUG "... PIC IRR: %04x\n", v);
++
++ outb(0x0b,0xa0);
++ outb(0x0b,0x20);
++ v = inb(0xa0) << 8 | inb(0x20);
++ outb(0x0a,0xa0);
++ outb(0x0a,0x20);
++
++ spin_unlock_irqrestore(&i8259A_lock, flags);
++
++ printk(KERN_DEBUG "... PIC ISR: %04x\n", v);
++
++ v = inb(0x4d1) << 8 | inb(0x4d0);
++ printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
++}
++
++#endif /* 0 */
++
++#else
++void __init print_IO_APIC(void) { }
++#endif /* !CONFIG_XEN */
++
++static void __init enable_IO_APIC(void)
++{
++ union IO_APIC_reg_01 reg_01;
++ int i8259_apic, i8259_pin;
++ int i, apic;
++ unsigned long flags;
++
++ for (i = 0; i < PIN_MAP_SIZE; i++) {
++ irq_2_pin[i].pin = -1;
++ irq_2_pin[i].next = 0;
++ }
++ if (!pirqs_enabled)
++ for (i = 0; i < MAX_PIRQS; i++)
++ pirq_entries[i] = -1;
++
++ /*
++ * The number of IO-APIC IRQ registers (== #pins):
++ */
++ for (apic = 0; apic < nr_ioapics; apic++) {
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_01.raw = io_apic_read(apic, 1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ nr_ioapic_registers[apic] = reg_01.bits.entries+1;
++ }
++ for(apic = 0; apic < nr_ioapics; apic++) {
++ int pin;
++ /* See if any of the pins is in ExtINT mode */
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
++ struct IO_APIC_route_entry entry;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
++ *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++
++ /* If the interrupt line is enabled and in ExtInt mode
++ * I have found the pin where the i8259 is connected.
++ */
++ if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {
++ ioapic_i8259.apic = apic;
++ ioapic_i8259.pin = pin;
++ goto found_i8259;
++ }
++ }
++ }
++ found_i8259:
++ /* Look to see what if the MP table has reported the ExtINT */
++ /* If we could not find the appropriate pin by looking at the ioapic
++ * the i8259 probably is not connected the ioapic but give the
++ * mptable a chance anyway.
++ */
++ i8259_pin = find_isa_irq_pin(0, mp_ExtINT);
++ i8259_apic = find_isa_irq_apic(0, mp_ExtINT);
++ /* Trust the MP table if nothing is setup in the hardware */
++ if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {
++ printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");
++ ioapic_i8259.pin = i8259_pin;
++ ioapic_i8259.apic = i8259_apic;
++ }
++ /* Complain if the MP table and the hardware disagree */
++ if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&
++ (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))
++ {
++ printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");
++ }
++
++ /*
++ * Do not trust the IO-APIC being empty at bootup
++ */
++ clear_IO_APIC();
++}
++
++/*
++ * Not an __init, needed by the reboot code
++ */
++void disable_IO_APIC(void)
++{
++ /*
++ * Clear the IO-APIC before rebooting:
++ */
++ clear_IO_APIC();
++
++#ifndef CONFIG_XEN
++ /*
++ * If the i8259 is routed through an IOAPIC
++ * Put that IOAPIC in virtual wire mode
++ * so legacy interrupts can be delivered.
++ */
++ if (ioapic_i8259.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 = dest_ExtINT; /* ExtInt */
++ entry.vector = 0;
++ entry.dest.physical.physical_dest =
++ GET_APIC_ID(apic_read(APIC_ID));
++
++ /*
++ * Add it to the IO-APIC irq-routing table:
++ */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin,
++ *(((int *)&entry)+1));
++ io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin,
++ *(((int *)&entry)+0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ }
++ disconnect_bsp_APIC(ioapic_i8259.pin != -1);
++#endif
++}
++
++/*
++ * function to set the IO-APIC physical IDs based on the
++ * values stored in the MPC table.
++ *
++ * by Matt Domsch <Matt_Domsch at dell.com> Tue Dec 21 12:25:05 CST 1999
++ */
++
++#if !defined(CONFIG_XEN) && !defined(CONFIG_X86_NUMAQ)
++static void __init setup_ioapic_ids_from_mpc(void)
++{
++ union IO_APIC_reg_00 reg_00;
++ physid_mask_t phys_id_present_map;
++ int apic;
++ int i;
++ unsigned char old_id;
++ unsigned long flags;
++
++ /*
++ * Don't check I/O APIC IDs for xAPIC systems. They have
++ * no meaning without the serial APIC bus.
++ */
++ if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
++ || APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
++ return;
++ /*
++ * This is broken; anything with a real cpu count has to
++ * circumvent this idiocy regardless.
++ */
++ phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map);
++
++ /*
++ * Set the IOAPIC ID to the value stored in the MPC table.
++ */
++ for (apic = 0; apic < nr_ioapics; apic++) {
++
++ /* Read the register 0 value */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(apic, 0);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ old_id = mp_ioapics[apic].mpc_apicid;
++
++ if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {
++ printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
++ apic, mp_ioapics[apic].mpc_apicid);
++ printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
++ reg_00.bits.ID);
++ mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;
++ }
++
++ /*
++ * Sanity check, is the ID really free? Every APIC in a
++ * system must have a unique ID or we get lots of nice
++ * 'stuck on smp_invalidate_needed IPI wait' messages.
++ */
++ if (check_apicid_used(phys_id_present_map,
++ mp_ioapics[apic].mpc_apicid)) {
++ printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
++ apic, mp_ioapics[apic].mpc_apicid);
++ for (i = 0; i < get_physical_broadcast(); i++)
++ if (!physid_isset(i, phys_id_present_map))
++ break;
++ if (i >= get_physical_broadcast())
++ panic("Max APIC ID exceeded!\n");
++ printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
++ i);
++ physid_set(i, phys_id_present_map);
++ mp_ioapics[apic].mpc_apicid = i;
++ } else {
++ physid_mask_t tmp;
++ tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid);
++ apic_printk(APIC_VERBOSE, "Setting %d in the "
++ "phys_id_present_map\n",
++ mp_ioapics[apic].mpc_apicid);
++ physids_or(phys_id_present_map, phys_id_present_map, tmp);
++ }
++
++
++ /*
++ * We need to adjust the IRQ routing table
++ * if the ID changed.
++ */
++ if (old_id != mp_ioapics[apic].mpc_apicid)
++ for (i = 0; i < mp_irq_entries; i++)
++ if (mp_irqs[i].mpc_dstapic == old_id)
++ mp_irqs[i].mpc_dstapic
++ = mp_ioapics[apic].mpc_apicid;
++
++ /*
++ * Read the right value from the MPC table and
++ * write it into the ID register.
++ */
++ apic_printk(APIC_VERBOSE, KERN_INFO
++ "...changing IO-APIC physical APIC ID to %d ...",
++ mp_ioapics[apic].mpc_apicid);
++
++ reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0, reg_00.raw);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ /*
++ * Sanity check
++ */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(apic, 0);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
++ printk("could not set ID!\n");
++ else
++ apic_printk(APIC_VERBOSE, " ok.\n");
++ }
++}
++#else
++static void __init setup_ioapic_ids_from_mpc(void) { }
++#endif
++
++#ifndef CONFIG_XEN
++/*
++ * There is a nasty bug in some older SMP boards, their mptable lies
++ * about the timer IRQ. We do the following to work around the situation:
++ *
++ * - timer IRQ defaults to IO-APIC IRQ
++ * - if this function detects that timer IRQs are defunct, then we fall
++ * back to ISA timer IRQs
++ */
++static int __init timer_irq_works(void)
++{
++ unsigned long t1 = jiffies;
++
++ local_irq_enable();
++ /* Let ten ticks pass... */
++ mdelay((10 * 1000) / HZ);
++
++ /*
++ * Expect a few ticks at least, to be sure some possible
++ * glue logic does not lock up after one or two first
++ * ticks in a non-ExtINT mode. Also the local APIC
++ * might have cached one ExtINT interrupt. Finally, at
++ * least one tick may be lost due to delays.
++ */
++ if (jiffies - t1 > 4)
++ return 1;
++
++ return 0;
++}
++
++/*
++ * In the SMP+IOAPIC case it might happen that there are an unspecified
++ * number of pending IRQ events unhandled. These cases are very rare,
++ * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
++ * better to do it this way as thus we do not have to be aware of
++ * 'pending' interrupts in the IRQ path, except at this point.
++ */
++/*
++ * Edge triggered needs to resend any interrupt
++ * that was delayed but this is now handled in the device
++ * independent code.
++ */
++
++/*
++ * Starting up a edge-triggered IO-APIC interrupt is
++ * nasty - we need to make sure that we get the edge.
++ * If it is already asserted for some reason, we need
++ * return 1 to indicate that is was pending.
++ *
++ * This is not complete - we should be able to fake
++ * an edge even if it isn't on the 8259A...
++ */
++static unsigned int startup_edge_ioapic_irq(unsigned int irq)
++{
++ int was_pending = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ if (irq < 16) {
++ disable_8259A_irq(irq);
++ if (i8259A_irq_pending(irq))
++ was_pending = 1;
++ }
++ __unmask_IO_APIC_irq(irq);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return was_pending;
++}
++
++/*
++ * Once we have recorded IRQ_PENDING already, we can mask the
++ * interrupt for real. This prevents IRQ storms from unhandled
++ * devices.
++ */
++static void ack_edge_ioapic_irq(unsigned int irq)
++{
++ move_irq(irq);
++ if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
++ == (IRQ_PENDING | IRQ_DISABLED))
++ mask_IO_APIC_irq(irq);
++ ack_APIC_irq();
++}
++
++/*
++ * Level triggered interrupts can just be masked,
++ * and shutting down and starting up the interrupt
++ * is the same as enabling and disabling them -- except
++ * with a startup need to return a "was pending" value.
++ *
++ * Level triggered interrupts are special because we
++ * do not touch any IO-APIC register while handling
++ * them. We ack the APIC in the end-IRQ handler, not
++ * in the start-IRQ-handler. Protection against reentrance
++ * from the same interrupt is still provided, both by the
++ * generic IRQ layer and by the fact that an unacked local
++ * APIC does not accept IRQs.
++ */
++static unsigned int startup_level_ioapic_irq (unsigned int irq)
++{
++ unmask_IO_APIC_irq(irq);
++
++ return 0; /* don't check for pending */
++}
++
++static void end_level_ioapic_irq (unsigned int irq)
++{
++ unsigned long v;
++ int i;
++
++ move_irq(irq);
++/*
++ * It appears there is an erratum which affects at least version 0x11
++ * of I/O APIC (that's the 82093AA and cores integrated into various
++ * chipsets). Under certain conditions a level-triggered interrupt is
++ * erroneously delivered as edge-triggered one but the respective IRR
++ * bit gets set nevertheless. As a result the I/O unit expects an EOI
++ * message but it will never arrive and further interrupts are blocked
++ * from the source. The exact reason is so far unknown, but the
++ * phenomenon was observed when two consecutive interrupt requests
++ * from a given source get delivered to the same CPU and the source is
++ * temporarily disabled in between.
++ *
++ * A workaround is to simulate an EOI message manually. We achieve it
++ * by setting the trigger mode to edge and then to level when the edge
++ * trigger mode gets detected in the TMR of a local APIC for a
++ * level-triggered interrupt. We mask the source for the time of the
++ * operation to prevent an edge-triggered interrupt escaping meanwhile.
++ * The idea is from Manfred Spraul. --macro
++ */
++ i = IO_APIC_VECTOR(irq);
++
++ v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
++
++ ack_APIC_irq();
++
++ if (!(v & (1 << (i & 0x1f)))) {
++ atomic_inc(&irq_mis_count);
++ spin_lock(&ioapic_lock);
++ __mask_and_edge_IO_APIC_irq(irq);
++ __unmask_and_level_IO_APIC_irq(irq);
++ spin_unlock(&ioapic_lock);
++ }
++}
++
++#ifdef CONFIG_PCI_MSI
++static unsigned int startup_edge_ioapic_vector(unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ return startup_edge_ioapic_irq(irq);
++}
++
++static void ack_edge_ioapic_vector(unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ move_native_irq(vector);
++ ack_edge_ioapic_irq(irq);
++}
++
++static unsigned int startup_level_ioapic_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ return startup_level_ioapic_irq (irq);
++}
++
++static void end_level_ioapic_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ move_native_irq(vector);
++ end_level_ioapic_irq(irq);
++}
++
++static void mask_IO_APIC_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ mask_IO_APIC_irq(irq);
++}
++
++static void unmask_IO_APIC_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ unmask_IO_APIC_irq(irq);
++}
++
++#ifdef CONFIG_SMP
++static void set_ioapic_affinity_vector (unsigned int vector,
++ cpumask_t cpu_mask)
++{
++ int irq = vector_to_irq(vector);
++
++ set_native_irq_info(vector, cpu_mask);
++ set_ioapic_affinity_irq(irq, cpu_mask);
++}
++#endif
++#endif
++
++static int ioapic_retrigger(unsigned int irq)
++{
++ send_IPI_self(IO_APIC_VECTOR(irq));
++
++ return 1;
++}
++
++/*
++ * Level and edge triggered IO-APIC interrupts need different handling,
++ * so we use two separate IRQ descriptors. Edge triggered IRQs can be
++ * handled with the level-triggered descriptor, but that one has slightly
++ * more overhead. Level-triggered interrupts cannot be handled with the
++ * edge-triggered handler, without risking IRQ storms and other ugly
++ * races.
++ */
++static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
++ .typename = "IO-APIC-edge",
++ .startup = startup_edge_ioapic,
++ .shutdown = shutdown_edge_ioapic,
++ .enable = enable_edge_ioapic,
++ .disable = disable_edge_ioapic,
++ .ack = ack_edge_ioapic,
++ .end = end_edge_ioapic,
++#ifdef CONFIG_SMP
++ .set_affinity = set_ioapic_affinity,
++#endif
++ .retrigger = ioapic_retrigger,
++};
++
++static struct hw_interrupt_type ioapic_level_type __read_mostly = {
++ .typename = "IO-APIC-level",
++ .startup = startup_level_ioapic,
++ .shutdown = shutdown_level_ioapic,
++ .enable = enable_level_ioapic,
++ .disable = disable_level_ioapic,
++ .ack = mask_and_ack_level_ioapic,
++ .end = end_level_ioapic,
++#ifdef CONFIG_SMP
++ .set_affinity = set_ioapic_affinity,
++#endif
++ .retrigger = ioapic_retrigger,
++};
++#endif /* !CONFIG_XEN */
++
++static inline void init_IO_APIC_traps(void)
++{
++ int irq;
++
++ /*
++ * NOTE! The local APIC isn't very good at handling
++ * multiple interrupts at the same interrupt level.
++ * As the interrupt level is determined by taking the
++ * vector number and shifting that right by 4, we
++ * want to spread these out a bit so that they don't
++ * all fall in the same interrupt level.
++ *
++ * Also, we've got to be careful not to trash gate
++ * 0x80, because int 0x80 is hm, kind of importantish. ;)
++ */
++ for (irq = 0; irq < NR_IRQS ; irq++) {
++ int tmp = irq;
++ if (use_pci_vector()) {
++ if (!platform_legacy_irq(tmp))
++ if ((tmp = vector_to_irq(tmp)) == -1)
++ continue;
++ }
++ if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
++ /*
++ * Hmm.. We don't have an entry for this,
++ * so default to an old-fashioned 8259
++ * interrupt if we can..
++ */
++ if (irq < 16)
++ make_8259A_irq(irq);
++#ifndef CONFIG_XEN
++ else
++ /* Strange. Oh, well.. */
++ irq_desc[irq].chip = &no_irq_type;
++#endif
++ }
++ }
++}
++
++#ifndef CONFIG_XEN
++static void enable_lapic_irq (unsigned int irq)
++{
++ unsigned long v;
++
++ v = apic_read(APIC_LVT0);
++ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
++}
++
++static void disable_lapic_irq (unsigned int irq)
++{
++ unsigned long v;
++
++ v = apic_read(APIC_LVT0);
++ apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
++}
++
++static void ack_lapic_irq (unsigned int irq)
++{
++ ack_APIC_irq();
++}
++
++static void end_lapic_irq (unsigned int i) { /* nothing */ }
++
++static struct hw_interrupt_type lapic_irq_type __read_mostly = {
++ .typename = "local-APIC-edge",
++ .startup = NULL, /* startup_irq() not used for IRQ0 */
++ .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
++ .enable = enable_lapic_irq,
++ .disable = disable_lapic_irq,
++ .ack = ack_lapic_irq,
++ .end = end_lapic_irq
++};
++
++static void setup_nmi (void)
++{
++ /*
++ * Dirty trick to enable the NMI watchdog ...
++ * We put the 8259A master into AEOI mode and
++ * unmask on all local APICs LVT0 as NMI.
++ *
++ * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
++ * is from Maciej W. Rozycki - so we do not have to EOI from
++ * the NMI handler or the timer interrupt.
++ */
++ apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ...");
++
++ on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1);
++
++ apic_printk(APIC_VERBOSE, " done.\n");
++}
++
++/*
++ * This looks a bit hackish but it's about the only one way of sending
++ * a few INTA cycles to 8259As and any associated glue logic. ICR does
++ * not support the ExtINT mode, unfortunately. We need to send these
++ * cycles as some i82489DX-based boards have glue logic that keeps the
++ * 8259A interrupt line asserted until INTA. --macro
++ */
++static inline void unlock_ExtINT_logic(void)
++{
++ int apic, pin, i;
++ struct IO_APIC_route_entry entry0, entry1;
++ unsigned char save_control, save_freq_select;
++ unsigned long flags;
++
++ pin = find_isa_irq_pin(8, mp_INT);
++ apic = find_isa_irq_apic(8, mp_INT);
++ if (pin == -1)
++ return;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
++ *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ clear_IO_APIC_pin(apic, pin);
++
++ memset(&entry1, 0, sizeof(entry1));
++
++ entry1.dest_mode = 0; /* physical delivery */
++ entry1.mask = 0; /* unmask IRQ now */
++ entry1.dest.physical.physical_dest = hard_smp_processor_id();
++ entry1.delivery_mode = dest_ExtINT;
++ entry1.polarity = entry0.polarity;
++ entry1.trigger = 0;
++ entry1.vector = 0;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ save_control = CMOS_READ(RTC_CONTROL);
++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
++ CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
++ RTC_FREQ_SELECT);
++ CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
++
++ i = 100;
++ while (i-- > 0) {
++ mdelay(10);
++ if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
++ i -= 10;
++ }
++
++ CMOS_WRITE(save_control, RTC_CONTROL);
++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
++ clear_IO_APIC_pin(apic, pin);
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++#endif /* CONFIG_XEN */
++int timer_uses_ioapic_pin_0;
++#ifdef CONFI_XEN
++/*
++ * This code may look a bit paranoid, but it's supposed to cooperate with
++ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
++ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
++ * fanatically on his truly buggy board.
++ */
++static inline void check_timer(void)
++{
++ int apic1, pin1, apic2, pin2;
++ int vector;
++
++ /*
++ * get/set the timer IRQ vector:
++ */
++ disable_8259A_irq(0);
++ vector = assign_irq_vector(0);
++ set_intr_gate(vector, interrupt[0]);
++
++ /*
++ * Subtle, code in do_timer_interrupt() expects an AEOI
++ * mode for the 8259A whenever interrupts are routed
++ * through I/O APICs. Also IRQ0 has to be enabled in
++ * the 8259A which implies the virtual wire has to be
++ * disabled in the local APIC.
++ */
++ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
++ init_8259A(1);
++ timer_ack = 1;
++ if (timer_over_8254 > 0)
++ enable_8259A_irq(0);
++
++ pin1 = find_isa_irq_pin(0, mp_INT);
++ apic1 = find_isa_irq_apic(0, mp_INT);
++ pin2 = ioapic_i8259.pin;
++ apic2 = ioapic_i8259.apic;
++
++ if (pin1 == 0)
++ timer_uses_ioapic_pin_0 = 1;
++
++ printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
++ vector, apic1, pin1, apic2, pin2);
++
++ if (pin1 != -1) {
++ /*
++ * Ok, does IRQ0 through the IOAPIC work?
++ */
++ unmask_IO_APIC_irq(0);
++ if (timer_irq_works()) {
++ if (nmi_watchdog == NMI_IO_APIC) {
++ disable_8259A_irq(0);
++ setup_nmi();
++ enable_8259A_irq(0);
++ }
++ if (disable_timer_pin_1 > 0)
++ clear_IO_APIC_pin(0, pin1);
++ return;
++ }
++ clear_IO_APIC_pin(apic1, pin1);
++ printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to "
++ "IO-APIC\n");
++ }
++
++ printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
++ if (pin2 != -1) {
++ printk("\n..... (found pin %d) ...", pin2);
++ /*
++ * legacy devices should be connected to IO APIC #0
++ */
++ setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
++ if (timer_irq_works()) {
++ printk("works.\n");
++ if (pin1 != -1)
++ replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
++ else
++ add_pin_to_irq(0, apic2, pin2);
++ if (nmi_watchdog == NMI_IO_APIC) {
++ setup_nmi();
++ }
++ return;
++ }
++ /*
++ * Cleanup, just in case ...
++ */
++ clear_IO_APIC_pin(apic2, pin2);
++ }
++ printk(" failed.\n");
++
++ if (nmi_watchdog == NMI_IO_APIC) {
++ printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
++ nmi_watchdog = 0;
++ }
++
++ printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
++
++ disable_8259A_irq(0);
++ irq_desc[0].chip = &lapic_irq_type;
++ apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
++ enable_8259A_irq(0);
++
++ if (timer_irq_works()) {
++ printk(" works.\n");
++ return;
++ }
++ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
++ printk(" failed.\n");
++
++ printk(KERN_INFO "...trying to set up timer as ExtINT IRQ...");
++
++ timer_ack = 0;
++ init_8259A(0);
++ make_8259A_irq(0);
++ apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
++
++ unlock_ExtINT_logic();
++
++ if (timer_irq_works()) {
++ printk(" works.\n");
++ return;
++ }
++ printk(" failed :(.\n");
++ panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
++ "report. Then try booting with the 'noapic' option");
++}
++#else
++#define check_timer() ((void)0)
++#endif
++
++/*
++ *
++ * IRQ's that are handled by the PIC in the MPS IOAPIC case.
++ * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
++ * Linux doesn't really care, as it's not actually used
++ * for any interrupt handling anyway.
++ */
++#define PIC_IRQS (1 << PIC_CASCADE_IR)
++
++void __init setup_IO_APIC(void)
++{
++ enable_IO_APIC();
++
++ if (acpi_ioapic)
++ io_apic_irqs = ~0; /* all IRQs go through IOAPIC */
++ else
++ io_apic_irqs = ~PIC_IRQS;
++
++ printk("ENABLING IO-APIC IRQs\n");
++
++ /*
++ * Set up IO-APIC IRQ routing.
++ */
++ if (!acpi_ioapic)
++ setup_ioapic_ids_from_mpc();
++#ifndef CONFIG_XEN
++ sync_Arb_IDs();
++#endif
++ setup_IO_APIC_irqs();
++ init_IO_APIC_traps();
++ check_timer();
++ if (!acpi_ioapic)
++ print_IO_APIC();
++}
++
++static int __init setup_disable_8254_timer(char *s)
++{
++ timer_over_8254 = -1;
++ return 1;
++}
++static int __init setup_enable_8254_timer(char *s)
++{
++ timer_over_8254 = 2;
++ return 1;
++}
++
++__setup("disable_8254_timer", setup_disable_8254_timer);
++__setup("enable_8254_timer", setup_enable_8254_timer);
++
++/*
++ * Called after all the initialization is done. If we didnt find any
++ * APIC bugs then we can allow the modify fast path
++ */
++
++static int __init io_apic_bug_finalize(void)
++{
++ if(sis_apic_bug == -1)
++ sis_apic_bug = 0;
++ if (is_initial_xendomain()) {
++ dom0_op_t op = { .cmd = DOM0_PLATFORM_QUIRK };
++ op.u.platform_quirk.quirk_id = sis_apic_bug ?
++ QUIRK_IOAPIC_BAD_REGSEL : QUIRK_IOAPIC_GOOD_REGSEL;
++ HYPERVISOR_dom0_op(&op);
++ }
++ return 0;
++}
++
++late_initcall(io_apic_bug_finalize);
++
++struct sysfs_ioapic_data {
++ struct sys_device dev;
++ struct IO_APIC_route_entry entry[0];
++};
++static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
++
++static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
++{
++ struct IO_APIC_route_entry *entry;
++ struct sysfs_ioapic_data *data;
++ unsigned long flags;
++ int i;
++
++ data = container_of(dev, struct sysfs_ioapic_data, dev);
++ entry = data->entry;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
++ *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
++ *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
++ }
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return 0;
++}
++
++static int ioapic_resume(struct sys_device *dev)
++{
++ struct IO_APIC_route_entry *entry;
++ struct sysfs_ioapic_data *data;
++ unsigned long flags;
++ union IO_APIC_reg_00 reg_00;
++ int i;
++
++ data = container_of(dev, struct sysfs_ioapic_data, dev);
++ entry = data->entry;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(dev->id, 0);
++ if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) {
++ reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
++ io_apic_write(dev->id, 0, reg_00.raw);
++ }
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
++ io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
++ io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
++ }
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return 0;
++}
++
++static struct sysdev_class ioapic_sysdev_class = {
++ set_kset_name("ioapic"),
++ .suspend = ioapic_suspend,
++ .resume = ioapic_resume,
++};
++
++static int __init ioapic_init_sysfs(void)
++{
++ struct sys_device * dev;
++ int i, size, error = 0;
++
++ error = sysdev_class_register(&ioapic_sysdev_class);
++ if (error)
++ return error;
++
++ for (i = 0; i < nr_ioapics; i++ ) {
++ size = sizeof(struct sys_device) + nr_ioapic_registers[i]
++ * sizeof(struct IO_APIC_route_entry);
++ mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL);
++ if (!mp_ioapic_data[i]) {
++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
++ continue;
++ }
++ memset(mp_ioapic_data[i], 0, size);
++ dev = &mp_ioapic_data[i]->dev;
++ dev->id = i;
++ dev->cls = &ioapic_sysdev_class;
++ error = sysdev_register(dev);
++ if (error) {
++ kfree(mp_ioapic_data[i]);
++ mp_ioapic_data[i] = NULL;
++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++device_initcall(ioapic_init_sysfs);
++
++/* --------------------------------------------------------------------------
++ ACPI-based IOAPIC Configuration
++ -------------------------------------------------------------------------- */
++
++#ifdef CONFIG_ACPI
++
++int __init io_apic_get_unique_id (int ioapic, int apic_id)
++{
++#ifndef CONFIG_XEN
++ union IO_APIC_reg_00 reg_00;
++ static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
++ physid_mask_t tmp;
++ unsigned long flags;
++ int i = 0;
++
++ /*
++ * The P4 platform supports up to 256 APIC IDs on two separate APIC
++ * buses (one for LAPICs, one for IOAPICs), where predecessors only
++ * supports up to 16 on one shared APIC bus.
++ *
++ * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
++ * advantage of new APIC bus architecture.
++ */
++
++ if (physids_empty(apic_id_map))
++ apic_id_map = ioapic_phys_id_map(phys_cpu_present_map);
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(ioapic, 0);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ if (apic_id >= get_physical_broadcast()) {
++ printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
++ "%d\n", ioapic, apic_id, reg_00.bits.ID);
++ apic_id = reg_00.bits.ID;
++ }
++
++ /*
++ * Every APIC in a system must have a unique ID or we get lots of nice
++ * 'stuck on smp_invalidate_needed IPI wait' messages.
++ */
++ if (check_apicid_used(apic_id_map, apic_id)) {
++
++ for (i = 0; i < get_physical_broadcast(); i++) {
++ if (!check_apicid_used(apic_id_map, i))
++ break;
++ }
++
++ if (i == get_physical_broadcast())
++ panic("Max apic_id exceeded!\n");
++
++ printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
++ "trying %d\n", ioapic, apic_id, i);
++
++ apic_id = i;
++ }
++
++ tmp = apicid_to_cpu_present(apic_id);
++ physids_or(apic_id_map, apic_id_map, tmp);
++
++ if (reg_00.bits.ID != apic_id) {
++ reg_00.bits.ID = apic_id;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(ioapic, 0, reg_00.raw);
++ reg_00.raw = io_apic_read(ioapic, 0);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ /* Sanity check */
++ if (reg_00.bits.ID != apic_id) {
++ printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
++ return -1;
++ }
++ }
++
++ apic_printk(APIC_VERBOSE, KERN_INFO
++ "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
++#endif /* !CONFIG_XEN */
++
++ return apic_id;
++}
++
++
++int __init io_apic_get_version (int ioapic)
++{
++ union IO_APIC_reg_01 reg_01;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_01.raw = io_apic_read(ioapic, 1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return reg_01.bits.version;
++}
++
++
++int __init io_apic_get_redir_entries (int ioapic)
++{
++ union IO_APIC_reg_01 reg_01;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_01.raw = io_apic_read(ioapic, 1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return reg_01.bits.entries;
++}
++
++
++int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low)
++{
++ struct IO_APIC_route_entry entry;
++ unsigned long flags;
++
++ if (!IO_APIC_IRQ(irq)) {
++ printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
++ ioapic);
++ return -EINVAL;
++ }
++
++ /*
++ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
++ * Note that we mask (disable) IRQs now -- these get enabled when the
++ * corresponding device driver registers for this IRQ.
++ */
++
++ memset(&entry,0,sizeof(entry));
++
++ entry.delivery_mode = INT_DELIVERY_MODE;
++ entry.dest_mode = INT_DEST_MODE;
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++ entry.trigger = edge_level;
++ entry.polarity = active_high_low;
++ entry.mask = 1;
++
++ /*
++ * IRQs < 16 are already in the irq_2_pin[] map
++ */
++ if (irq >= 16)
++ add_pin_to_irq(irq, ioapic, pin);
++
++ entry.vector = assign_irq_vector(irq);
++
++ apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry "
++ "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic,
++ mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq,
++ edge_level, active_high_low);
++
++ ioapic_register_intr(irq, entry.vector, edge_level);
++
++ if (!ioapic && (irq < 16))
++ disable_8259A_irq(irq);
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
++ io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
++ set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return 0;
++}
++
++#endif /* CONFIG_ACPI */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/ioport-xen.c linux-2.6.18-xen/arch/i386/kernel/ioport-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/ioport-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/ioport-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,121 @@
++/*
++ * linux/arch/i386/kernel/ioport.c
++ *
++ * This contains the io-permission bitmap code - written by obz, with changes
++ * by Linus.
++ */
++
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/capability.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/ioport.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/stddef.h>
++#include <linux/slab.h>
++#include <linux/thread_info.h>
++#include <xen/interface/physdev.h>
++
++/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
++static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value)
++{
++ unsigned long mask;
++ unsigned long *bitmap_base = bitmap + (base / BITS_PER_LONG);
++ unsigned int low_index = base & (BITS_PER_LONG-1);
++ int length = low_index + extent;
++
++ if (low_index != 0) {
++ mask = (~0UL << low_index);
++ if (length < BITS_PER_LONG)
++ mask &= ~(~0UL << length);
++ if (new_value)
++ *bitmap_base++ |= mask;
++ else
++ *bitmap_base++ &= ~mask;
++ length -= BITS_PER_LONG;
++ }
++
++ mask = (new_value ? ~0UL : 0UL);
++ while (length >= BITS_PER_LONG) {
++ *bitmap_base++ = mask;
++ length -= BITS_PER_LONG;
++ }
++
++ if (length > 0) {
++ mask = ~(~0UL << length);
++ if (new_value)
++ *bitmap_base++ |= mask;
++ else
++ *bitmap_base++ &= ~mask;
++ }
++}
++
++
++/*
++ * this changes the io permissions bitmap in the current task.
++ */
++asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
++{
++ struct thread_struct * t = ¤t->thread;
++ unsigned long *bitmap;
++ struct physdev_set_iobitmap set_iobitmap;
++
++ if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
++ return -EINVAL;
++ if (turn_on && !capable(CAP_SYS_RAWIO))
++ return -EPERM;
++
++ /*
++ * If it's the first ioperm() call in this thread's lifetime, set the
++ * IO bitmap up. ioperm() is much less timing critical than clone(),
++ * this is why we delay this operation until now:
++ */
++ if (!t->io_bitmap_ptr) {
++ bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
++ if (!bitmap)
++ return -ENOMEM;
++
++ memset(bitmap, 0xff, IO_BITMAP_BYTES);
++ t->io_bitmap_ptr = bitmap;
++
++ set_iobitmap.bitmap = (char *)bitmap;
++ set_iobitmap.nr_ports = IO_BITMAP_BITS;
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap);
++ }
++
++ set_bitmap(t->io_bitmap_ptr, from, num, !turn_on);
++
++ return 0;
++}
++
++/*
++ * sys_iopl has to be used when you want to access the IO ports
++ * beyond the 0x3ff range: to get the full 65536 ports bitmapped
++ * you'd need 8kB of bitmaps/process, which is a bit excessive.
++ *
++ * Here we just change the eflags value on the stack: we allow
++ * only the super-user to do it. This depends on the stack-layout
++ * on system-call entry - see also fork() and the signal handling
++ * code.
++ */
++
++asmlinkage long sys_iopl(unsigned long unused)
++{
++ volatile struct pt_regs * regs = (struct pt_regs *) &unused;
++ unsigned int level = regs->ebx;
++ struct thread_struct *t = ¤t->thread;
++ unsigned int old = (t->iopl >> 12) & 3;
++
++ if (level > 3)
++ return -EINVAL;
++ /* Trying to gain more privileges? */
++ if (level > old) {
++ if (!capable(CAP_SYS_RAWIO))
++ return -EPERM;
++ }
++ t->iopl = level << 12;
++ set_iopl_mask(t->iopl);
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/irq-xen.c linux-2.6.18-xen/arch/i386/kernel/irq-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/irq-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/irq-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,324 @@
++/*
++ * linux/arch/i386/kernel/irq.c
++ *
++ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
++ *
++ * This file contains the lowest level x86-specific interrupt
++ * entry, irq-stacks and irq statistics code. All the remaining
++ * irq logic is done by the generic kernel/irq/ code and
++ * by the x86-specific irq controller code. (e.g. i8259.c and
++ * io_apic.c.)
++ */
++
++#include <asm/uaccess.h>
++#include <linux/module.h>
++#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_internodealigned_in_smp;
++EXPORT_PER_CPU_SYMBOL(irq_stat);
++
++#ifndef CONFIG_X86_LOCAL_APIC
++/*
++ * '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);
++}
++#endif
++
++#ifdef CONFIG_4KSTACKS
++/*
++ * per-CPU IRQ handling contexts (thread information and stack)
++ */
++union irq_ctx {
++ struct thread_info tinfo;
++ u32 stack[THREAD_SIZE/sizeof(u32)];
++};
++
++static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
++static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
++#endif
++
++/*
++ * do_IRQ handles all normal device IRQ's (the special
++ * SMP cross-CPU interrupts have their own specific
++ * handlers).
++ */
++fastcall unsigned int do_IRQ(struct pt_regs *regs)
++{
++ /* high bit used in ret_from_ code */
++ int irq = ~regs->orig_eax;
++#ifdef CONFIG_4KSTACKS
++ union irq_ctx *curctx, *irqctx;
++ u32 *isp;
++#endif
++
++ if (unlikely((unsigned)irq >= NR_IRQS)) {
++ printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
++ __FUNCTION__, irq);
++ BUG();
++ }
++
++ irq_enter();
++#ifdef CONFIG_DEBUG_STACKOVERFLOW
++ /* Debugging check for stack overflow: is there less than 1KB free? */
++ {
++ long esp;
++
++ __asm__ __volatile__("andl %%esp,%0" :
++ "=r" (esp) : "0" (THREAD_SIZE - 1));
++ if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
++ printk("do_IRQ: stack overflow: %ld\n",
++ esp - sizeof(struct thread_info));
++ dump_stack();
++ }
++ }
++#endif
++
++#ifdef CONFIG_4KSTACKS
++
++ curctx = (union irq_ctx *) current_thread_info();
++ irqctx = hardirq_ctx[smp_processor_id()];
++
++ /*
++ * this is where we switch to the IRQ stack. However, if we are
++ * already using the IRQ stack (because we interrupted a hardirq
++ * handler) we can't do that and just have to keep using the
++ * current stack (which is the irq stack already after all)
++ */
++ if (curctx != irqctx) {
++ int arg1, arg2, ebx;
++
++ /* build the stack frame on the IRQ stack */
++ isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
++ irqctx->tinfo.task = curctx->tinfo.task;
++ irqctx->tinfo.previous_esp = current_stack_pointer;
++
++ /*
++ * Copy the softirq bits in preempt_count so that the
++ * softirq checks work in the hardirq context.
++ */
++ irqctx->tinfo.preempt_count =
++ (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
++ (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
++
++ asm volatile(
++ " xchgl %%ebx,%%esp \n"
++ " call __do_IRQ \n"
++ " movl %%ebx,%%esp \n"
++ : "=a" (arg1), "=d" (arg2), "=b" (ebx)
++ : "0" (irq), "1" (regs), "2" (isp)
++ : "memory", "cc", "ecx"
++ );
++ } else
++#endif
++ __do_IRQ(irq, regs);
++
++ irq_exit();
++
++ return 1;
++}
++
++#ifdef CONFIG_4KSTACKS
++
++/*
++ * These should really be __section__(".bss.page_aligned") as well, but
++ * gcc's 3.0 and earlier don't handle that correctly.
++ */
++static char softirq_stack[NR_CPUS * THREAD_SIZE]
++ __attribute__((__aligned__(THREAD_SIZE)));
++
++static char hardirq_stack[NR_CPUS * THREAD_SIZE]
++ __attribute__((__aligned__(THREAD_SIZE)));
++
++/*
++ * allocate per-cpu stacks for hardirq and for softirq processing
++ */
++void irq_ctx_init(int cpu)
++{
++ union irq_ctx *irqctx;
++
++ if (hardirq_ctx[cpu])
++ return;
++
++ irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
++ irqctx->tinfo.task = NULL;
++ irqctx->tinfo.exec_domain = NULL;
++ irqctx->tinfo.cpu = cpu;
++ irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
++ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
++
++ hardirq_ctx[cpu] = irqctx;
++
++ irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
++ irqctx->tinfo.task = NULL;
++ irqctx->tinfo.exec_domain = NULL;
++ irqctx->tinfo.cpu = cpu;
++ irqctx->tinfo.preempt_count = 0;
++ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
++
++ softirq_ctx[cpu] = irqctx;
++
++ printk("CPU %u irqstacks, hard=%p soft=%p\n",
++ 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)
++{
++ unsigned long flags;
++ struct thread_info *curctx;
++ union irq_ctx *irqctx;
++ u32 *isp;
++
++ if (in_interrupt())
++ return;
++
++ local_irq_save(flags);
++
++ if (local_softirq_pending()) {
++ curctx = current_thread_info();
++ irqctx = softirq_ctx[smp_processor_id()];
++ irqctx->tinfo.task = curctx->task;
++ irqctx->tinfo.previous_esp = current_stack_pointer;
++
++ /* build the stack frame on the softirq stack */
++ isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
++
++ asm volatile(
++ " xchgl %%ebx,%%esp \n"
++ " call __do_softirq \n"
++ " movl %%ebx,%%esp \n"
++ : "=b"(isp)
++ : "0"(isp)
++ : "memory", "cc", "edx", "ecx", "eax"
++ );
++ /*
++ * Shouldnt happen, we returned above if in_interrupt():
++ */
++ WARN_ON_ONCE(softirq_count());
++ }
++
++ local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(do_softirq);
++#endif
++
++/*
++ * Interrupt statistics:
++ */
++
++atomic_t irq_err_count;
++
++/*
++ * /proc/interrupts printing:
++ */
++
++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_each_online_cpu(j)
++ seq_printf(p, "CPU%-8d ",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_each_online_cpu(j)
++ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
++#endif
++ seq_printf(p, " %14s", irq_desc[i].chip->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_each_online_cpu(j)
++ seq_printf(p, "%10u ", nmi_count(j));
++ seq_putc(p, '\n');
++#ifdef CONFIG_X86_LOCAL_APIC
++ seq_printf(p, "LOC: ");
++ for_each_online_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));
++#if defined(CONFIG_X86_IO_APIC)
++ seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
++#endif
++ }
++ return 0;
++}
++
++#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_desc[irq].affinity, map);
++ if (any_online_cpu(mask) == NR_CPUS) {
++ /*printk("Breaking affinity for irq %i\n", irq);*/
++ mask = map;
++ }
++ if (irq_desc[irq].chip->set_affinity)
++ irq_desc[irq].chip->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 -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/ldt-xen.c linux-2.6.18-xen/arch/i386/kernel/ldt-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/ldt-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/ldt-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,270 @@
++/*
++ * linux/kernel/ldt.c
++ *
++ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
++ * Copyright (C) 1999 Ingo Molnar <mingo at redhat.com>
++ */
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
++
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/ldt.h>
++#include <asm/desc.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
++static void flush_ldt(void *null)
++{
++ if (current->active_mm)
++ load_LDT(¤t->active_mm->context);
++}
++#endif
++
++static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++{
++ void *oldldt;
++ void *newldt;
++ int oldsize;
++
++ if (mincount <= pc->size)
++ return 0;
++ oldsize = pc->size;
++ mincount = (mincount+511)&(~511);
++ if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
++ newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
++ else
++ newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
++
++ if (!newldt)
++ return -ENOMEM;
++
++ if (oldsize)
++ memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
++ oldldt = pc->ldt;
++ memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
++ pc->ldt = newldt;
++ wmb();
++ pc->size = mincount;
++ wmb();
++
++ if (reload) {
++#ifdef CONFIG_SMP
++ cpumask_t mask;
++ preempt_disable();
++#endif
++ make_pages_readonly(
++ pc->ldt,
++ (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ load_LDT(pc);
++#ifdef CONFIG_SMP
++ mask = cpumask_of_cpu(smp_processor_id());
++ if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++ smp_call_function(flush_ldt, NULL, 1, 1);
++ preempt_enable();
++#endif
++ }
++ if (oldsize) {
++ make_pages_writable(
++ oldldt,
++ (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
++ vfree(oldldt);
++ else
++ kfree(oldldt);
++ }
++ return 0;
++}
++
++static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++{
++ int err = alloc_ldt(new, old->size, 0);
++ if (err < 0)
++ return err;
++ memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++ make_pages_readonly(
++ new->ldt,
++ (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ return 0;
++}
++
++/*
++ * we do not have to muck with descriptors here, that is
++ * done in switch_mm() as needed.
++ */
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++ struct mm_struct * old_mm;
++ int retval = 0;
++
++ init_MUTEX(&mm->context.sem);
++ mm->context.size = 0;
++ mm->context.has_foreign_mappings = 0;
++ old_mm = current->mm;
++ if (old_mm && old_mm->context.size > 0) {
++ down(&old_mm->context.sem);
++ retval = copy_ldt(&mm->context, &old_mm->context);
++ up(&old_mm->context.sem);
++ }
++ return retval;
++}
++
++/*
++ * No need to lock the MM as we are the last user
++ */
++void destroy_context(struct mm_struct *mm)
++{
++ if (mm->context.size) {
++ if (mm == current->active_mm)
++ clear_LDT();
++ make_pages_writable(
++ mm->context.ldt,
++ (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
++ vfree(mm->context.ldt);
++ else
++ kfree(mm->context.ldt);
++ mm->context.size = 0;
++ }
++}
++
++static int read_ldt(void __user * ptr, unsigned long bytecount)
++{
++ int err;
++ unsigned long size;
++ struct mm_struct * mm = current->mm;
++
++ if (!mm->context.size)
++ return 0;
++ if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
++ bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
++
++ down(&mm->context.sem);
++ size = mm->context.size*LDT_ENTRY_SIZE;
++ if (size > bytecount)
++ size = bytecount;
++
++ err = 0;
++ if (copy_to_user(ptr, mm->context.ldt, size))
++ err = -EFAULT;
++ up(&mm->context.sem);
++ if (err < 0)
++ goto error_return;
++ if (size != bytecount) {
++ /* zero-fill the rest */
++ if (clear_user(ptr+size, bytecount-size) != 0) {
++ err = -EFAULT;
++ goto error_return;
++ }
++ }
++ return bytecount;
++error_return:
++ return err;
++}
++
++static int read_default_ldt(void __user * ptr, unsigned long bytecount)
++{
++ int err;
++ unsigned long size;
++ void *address;
++
++ err = 0;
++ address = &default_ldt[0];
++ size = 5*sizeof(struct desc_struct);
++ if (size > bytecount)
++ size = bytecount;
++
++ err = size;
++ if (copy_to_user(ptr, address, size))
++ err = -EFAULT;
++
++ return err;
++}
++
++static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++{
++ struct mm_struct * mm = current->mm;
++ __u32 entry_1, entry_2;
++ int error;
++ struct user_desc ldt_info;
++
++ error = -EINVAL;
++ if (bytecount != sizeof(ldt_info))
++ goto out;
++ error = -EFAULT;
++ if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
++ goto out;
++
++ error = -EINVAL;
++ if (ldt_info.entry_number >= LDT_ENTRIES)
++ goto out;
++ if (ldt_info.contents == 3) {
++ if (oldmode)
++ goto out;
++ if (ldt_info.seg_not_present == 0)
++ goto out;
++ }
++
++ down(&mm->context.sem);
++ if (ldt_info.entry_number >= mm->context.size) {
++ error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1);
++ if (error < 0)
++ goto out_unlock;
++ }
++
++ /* Allow LDTs to be cleared by the user. */
++ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
++ if (oldmode || LDT_empty(&ldt_info)) {
++ entry_1 = 0;
++ entry_2 = 0;
++ goto install;
++ }
++ }
++
++ entry_1 = LDT_entry_a(&ldt_info);
++ entry_2 = LDT_entry_b(&ldt_info);
++ if (oldmode)
++ entry_2 &= ~(1 << 20);
++
++ /* Install the new entry ... */
++install:
++ error = write_ldt_entry(mm->context.ldt, ldt_info.entry_number,
++ entry_1, entry_2);
++
++out_unlock:
++ up(&mm->context.sem);
++out:
++ return error;
++}
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++ int ret = -ENOSYS;
++
++ switch (func) {
++ case 0:
++ ret = read_ldt(ptr, bytecount);
++ break;
++ case 1:
++ ret = write_ldt(ptr, bytecount, 1);
++ break;
++ case 2:
++ ret = read_default_ldt(ptr, bytecount);
++ break;
++ case 0x11:
++ ret = write_ldt(ptr, bytecount, 0);
++ break;
++ }
++ return ret;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/Makefile linux-2.6.18-xen/arch/i386/kernel/Makefile
+--- linux-2.6.18.1/arch/i386/kernel/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/Makefile 2006-09-21 01:33:31.000000000 +0200
+@@ -44,6 +44,12 @@
+
+ obj-$(CONFIG_SCx200) += scx200.o
+
++ifdef CONFIG_XEN
++vsyscall_note := vsyscall-note-xen.o
++else
++vsyscall_note := vsyscall-note.o
++endif
++
+ # vsyscall.o contains the vsyscall DSO images as __initdata.
+ # We must build both images before we can assemble it.
+ # Note: kbuild does not track this dependency due to usage of .incbin
+@@ -65,7 +71,7 @@
+
+ $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
+ $(obj)/vsyscall-%.so: $(src)/vsyscall.lds \
+- $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE
++ $(obj)/vsyscall-%.o $(obj)/$(vsyscall_note) FORCE
+ $(call if_changed,syscall)
+
+ # We also create a special relocatable object that should mirror the symbol
+@@ -77,8 +83,19 @@
+
+ SYSCFLAGS_vsyscall-syms.o = -r
+ $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
+- $(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE
++ $(obj)/vsyscall-sysenter.o $(obj)/$(vsyscall_note) FORCE
+ $(call if_changed,syscall)
+
+ k8-y += ../../x86_64/kernel/k8.o
+
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++
++obj-y += fixup.o
++microcode-$(subst m,y,$(CONFIG_MICROCODE)) := microcode-xen.o
++n-obj-xen := i8259.o timers/ reboot.o smpboot.o trampoline.o
++
++obj-y := $(call filterxen, $(obj-y), $(n-obj-xen))
++obj-y := $(call cherrypickxen, $(obj-y))
++extra-y := $(call cherrypickxen, $(extra-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/microcode-xen.c linux-2.6.18-xen/arch/i386/kernel/microcode-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/microcode-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/microcode-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,147 @@
++/*
++ * Intel CPU Microcode Update Driver for Linux
++ *
++ * Copyright (C) 2000-2004 Tigran Aivazian
++ *
++ * This driver allows to upgrade microcode on Intel processors
++ * belonging to IA-32 family - PentiumPro, Pentium II,
++ * Pentium III, Xeon, Pentium 4, etc.
++ *
++ * Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual,
++ * Order Number 245472 or free download from:
++ *
++ * http://developer.intel.com/design/pentium4/manuals/245472.htm
++ *
++ * For more information, go to http://www.urbanmyth.org/microcode
++ *
++ * 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.
++ */
++
++//#define DEBUG /* pr_debug */
++#include <linux/capability.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/cpumask.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/miscdevice.h>
++#include <linux/spinlock.h>
++#include <linux/mm.h>
++#include <linux/mutex.h>
++#include <linux/syscalls.h>
++
++#include <asm/msr.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++
++MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
++MODULE_AUTHOR("Tigran Aivazian <tigran at veritas.com>");
++MODULE_LICENSE("GPL");
++
++#define MICROCODE_VERSION "1.14-xen"
++
++#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
++#define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */
++#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
++
++/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
++static DEFINE_MUTEX(microcode_mutex);
++
++static void __user *user_buffer; /* user area microcode data buffer */
++static unsigned int user_buffer_size; /* it's size */
++
++static int microcode_open (struct inode *unused1, struct file *unused2)
++{
++ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
++}
++
++
++static int do_microcode_update (void)
++{
++ int err;
++ dom0_op_t op;
++
++ err = sys_mlock((unsigned long)user_buffer, user_buffer_size);
++ if (err != 0)
++ return err;
++
++ op.cmd = DOM0_MICROCODE;
++ set_xen_guest_handle(op.u.microcode.data, user_buffer);
++ op.u.microcode.length = user_buffer_size;
++ err = HYPERVISOR_dom0_op(&op);
++
++ (void)sys_munlock((unsigned long)user_buffer, user_buffer_size);
++
++ return err;
++}
++
++static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
++{
++ ssize_t ret;
++
++ if (len < DEFAULT_UCODE_TOTALSIZE) {
++ printk(KERN_ERR "microcode: not enough data\n");
++ return -EINVAL;
++ }
++
++ if ((len >> PAGE_SHIFT) > num_physpages) {
++ printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
++ return -EINVAL;
++ }
++
++ mutex_lock(µcode_mutex);
++
++ user_buffer = (void __user *) buf;
++ user_buffer_size = (int) len;
++
++ ret = do_microcode_update();
++ if (!ret)
++ ret = (ssize_t)len;
++
++ mutex_unlock(µcode_mutex);
++
++ return ret;
++}
++
++static struct file_operations microcode_fops = {
++ .owner = THIS_MODULE,
++ .write = microcode_write,
++ .open = microcode_open,
++};
++
++static struct miscdevice microcode_dev = {
++ .minor = MICROCODE_MINOR,
++ .name = "microcode",
++ .fops = µcode_fops,
++};
++
++static int __init microcode_init (void)
++{
++ int error;
++
++ error = misc_register(µcode_dev);
++ if (error) {
++ printk(KERN_ERR
++ "microcode: can't misc_register on minor=%d\n",
++ MICROCODE_MINOR);
++ return error;
++ }
++
++ printk(KERN_INFO
++ "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran at veritas.com>\n");
++ return 0;
++}
++
++static void __exit microcode_exit (void)
++{
++ misc_deregister(µcode_dev);
++}
++
++module_init(microcode_init)
++module_exit(microcode_exit)
++MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/mpparse-xen.c linux-2.6.18-xen/arch/i386/kernel/mpparse-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/mpparse-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/mpparse-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,1185 @@
++/*
++ * Intel Multiprocessor Specification 1.1 and 1.4
++ * compliant MP-table parsing routines.
++ *
++ * (c) 1995 Alan Cox, Building #3 <alan at redhat.com>
++ * (c) 1998, 1999, 2000 Ingo Molnar <mingo at redhat.com>
++ *
++ * Fixes
++ * Erich Boleyn : MP v1.4 and additional changes.
++ * Alan Cox : Added EBDA scanning
++ * Ingo Molnar : various cleanups and rewrites
++ * Maciej W. Rozycki: Bits for default MP configurations
++ * Paul Diefenbaugh: Added full ACPI support
++ */
++
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/acpi.h>
++#include <linux/delay.h>
++#include <linux/bootmem.h>
++#include <linux/smp_lock.h>
++#include <linux/kernel_stat.h>
++#include <linux/mc146818rtc.h>
++#include <linux/bitops.h>
++
++#include <asm/smp.h>
++#include <asm/acpi.h>
++#include <asm/mtrr.h>
++#include <asm/mpspec.h>
++#include <asm/io_apic.h>
++
++#include <mach_apic.h>
++#include <mach_mpparse.h>
++#include <bios_ebda.h>
++
++/* Have we found an MP table */
++int smp_found_config;
++unsigned int __initdata maxcpus = NR_CPUS;
++
++/*
++ * Various Linux-internal data structures created from the
++ * MP-table.
++ */
++int apic_version [MAX_APICS];
++int mp_bus_id_to_type [MAX_MP_BUSSES];
++int mp_bus_id_to_node [MAX_MP_BUSSES];
++int mp_bus_id_to_local [MAX_MP_BUSSES];
++int quad_local_to_mp_bus_id [NR_CPUS/4][4];
++int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
++static int mp_current_pci_id;
++
++/* I/O APIC entries */
++struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
++
++/* # of MP IRQ source entries */
++struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
++
++/* MP IRQ source entries */
++int mp_irq_entries;
++
++int nr_ioapics;
++
++int pic_mode;
++unsigned long mp_lapic_addr;
++
++unsigned int def_to_bigsmp = 0;
++
++/* Processor that is doing the boot up */
++unsigned int boot_cpu_physical_apicid = -1U;
++/* Internal processor count */
++static unsigned int __devinitdata num_processors;
++
++/* Bitmask of physically existing CPUs */
++physid_mask_t phys_cpu_present_map;
++
++u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
++
++/*
++ * Intel MP BIOS table parsing routines:
++ */
++
++
++/*
++ * Checksum an MP configuration block.
++ */
++
++static int __init mpf_checksum(unsigned char *mp, int len)
++{
++ int sum = 0;
++
++ while (len--)
++ sum += *mp++;
++
++ return sum & 0xFF;
++}
++
++/*
++ * Have to match translation table entries to main table entries by counter
++ * hence the mpc_record variable .... can't see a less disgusting way of
++ * doing this ....
++ */
++
++static int mpc_record;
++static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata;
++
++#ifndef CONFIG_XEN
++static void __devinit MP_processor_info (struct mpc_config_processor *m)
++{
++ int ver, apicid;
++ physid_mask_t phys_cpu;
++
++ if (!(m->mpc_cpuflag & CPU_ENABLED))
++ return;
++
++ apicid = mpc_apic_id(m, translation_table[mpc_record]);
++
++ if (m->mpc_featureflag&(1<<0))
++ Dprintk(" Floating point unit present.\n");
++ if (m->mpc_featureflag&(1<<7))
++ Dprintk(" Machine Exception supported.\n");
++ if (m->mpc_featureflag&(1<<8))
++ Dprintk(" 64 bit compare & exchange supported.\n");
++ if (m->mpc_featureflag&(1<<9))
++ Dprintk(" Internal APIC present.\n");
++ if (m->mpc_featureflag&(1<<11))
++ Dprintk(" SEP present.\n");
++ if (m->mpc_featureflag&(1<<12))
++ Dprintk(" MTRR present.\n");
++ if (m->mpc_featureflag&(1<<13))
++ Dprintk(" PGE present.\n");
++ if (m->mpc_featureflag&(1<<14))
++ Dprintk(" MCA present.\n");
++ if (m->mpc_featureflag&(1<<15))
++ Dprintk(" CMOV present.\n");
++ if (m->mpc_featureflag&(1<<16))
++ Dprintk(" PAT present.\n");
++ if (m->mpc_featureflag&(1<<17))
++ Dprintk(" PSE present.\n");
++ if (m->mpc_featureflag&(1<<18))
++ Dprintk(" PSN present.\n");
++ if (m->mpc_featureflag&(1<<19))
++ Dprintk(" Cache Line Flush Instruction present.\n");
++ /* 20 Reserved */
++ if (m->mpc_featureflag&(1<<21))
++ Dprintk(" Debug Trace and EMON Store present.\n");
++ if (m->mpc_featureflag&(1<<22))
++ Dprintk(" ACPI Thermal Throttle Registers present.\n");
++ if (m->mpc_featureflag&(1<<23))
++ Dprintk(" MMX present.\n");
++ if (m->mpc_featureflag&(1<<24))
++ Dprintk(" FXSR present.\n");
++ if (m->mpc_featureflag&(1<<25))
++ Dprintk(" XMM present.\n");
++ if (m->mpc_featureflag&(1<<26))
++ Dprintk(" Willamette New Instructions present.\n");
++ if (m->mpc_featureflag&(1<<27))
++ Dprintk(" Self Snoop present.\n");
++ if (m->mpc_featureflag&(1<<28))
++ Dprintk(" HT present.\n");
++ if (m->mpc_featureflag&(1<<29))
++ Dprintk(" Thermal Monitor present.\n");
++ /* 30, 31 Reserved */
++
++
++ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
++ Dprintk(" Bootup CPU\n");
++ boot_cpu_physical_apicid = m->mpc_apicid;
++ }
++
++ ver = m->mpc_apicver;
++
++ /*
++ * Validate version
++ */
++ if (ver == 0x0) {
++ printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! "
++ "fixing up to 0x10. (tell your hw vendor)\n",
++ m->mpc_apicid);
++ ver = 0x10;
++ }
++ apic_version[m->mpc_apicid] = ver;
++
++ phys_cpu = apicid_to_cpu_present(apicid);
++ physids_or(phys_cpu_present_map, phys_cpu_present_map, phys_cpu);
++
++ if (num_processors >= NR_CPUS) {
++ printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
++ " Processor ignored.\n", NR_CPUS);
++ return;
++ }
++
++ if (num_processors >= maxcpus) {
++ printk(KERN_WARNING "WARNING: maxcpus limit of %i reached."
++ " Processor ignored.\n", maxcpus);
++ return;
++ }
++
++ cpu_set(num_processors, cpu_possible_map);
++ num_processors++;
++
++ /*
++ * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
++ * but we need to work other dependencies like SMP_SUSPEND etc
++ * before this can be done without some confusion.
++ * if (CPU_HOTPLUG_ENABLED || num_processors > 8)
++ * - Ashok Raj <ashok.raj at intel.com>
++ */
++ if (num_processors > 8) {
++ switch (boot_cpu_data.x86_vendor) {
++ case X86_VENDOR_INTEL:
++ if (!APIC_XAPIC(ver)) {
++ def_to_bigsmp = 0;
++ break;
++ }
++ /* If P4 and above fall through */
++ case X86_VENDOR_AMD:
++ def_to_bigsmp = 1;
++ }
++ }
++ bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
++}
++#else
++void __init MP_processor_info (struct mpc_config_processor *m)
++{
++ num_processors++;
++}
++#endif /* CONFIG_XEN */
++
++static void __init MP_bus_info (struct mpc_config_bus *m)
++{
++ char str[7];
++
++ memcpy(str, m->mpc_bustype, 6);
++ str[6] = 0;
++
++ mpc_oem_bus_info(m, str, translation_table[mpc_record]);
++
++ if (m->mpc_busid >= MAX_MP_BUSSES) {
++ printk(KERN_WARNING "MP table busid value (%d) for bustype %s "
++ " is too large, max. supported is %d\n",
++ m->mpc_busid, str, MAX_MP_BUSSES - 1);
++ return;
++ }
++
++ if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
++ } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
++ } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {
++ mpc_oem_pci_bus(m, translation_table[mpc_record]);
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
++ mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
++ mp_current_pci_id++;
++ } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
++ } else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98;
++ } else {
++ printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
++ }
++}
++
++static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
++{
++ if (!(m->mpc_flags & MPC_APIC_USABLE))
++ return;
++
++ printk(KERN_INFO "I/O APIC #%d Version %d at 0x%lX.\n",
++ m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
++ if (nr_ioapics >= MAX_IO_APICS) {
++ printk(KERN_CRIT "Max # of I/O APICs (%d) exceeded (found %d).\n",
++ MAX_IO_APICS, nr_ioapics);
++ panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
++ }
++ if (!m->mpc_apicaddr) {
++ printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
++ " found in MP table, skipping!\n");
++ return;
++ }
++ mp_ioapics[nr_ioapics] = *m;
++ nr_ioapics++;
++}
++
++static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
++{
++ mp_irqs [mp_irq_entries] = *m;
++ Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
++ " IRQ %02x, APIC ID %x, APIC INT %02x\n",
++ m->mpc_irqtype, m->mpc_irqflag & 3,
++ (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
++ m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
++ if (++mp_irq_entries == MAX_IRQ_SOURCES)
++ panic("Max # of irq sources exceeded!!\n");
++}
++
++static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
++{
++ Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
++ " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
++ m->mpc_irqtype, m->mpc_irqflag & 3,
++ (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
++ m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
++ /*
++ * Well it seems all SMP boards in existence
++ * use ExtINT/LVT1 == LINT0 and
++ * NMI/LVT2 == LINT1 - the following check
++ * will show us if this assumptions is false.
++ * Until then we do not have to add baggage.
++ */
++ if ((m->mpc_irqtype == mp_ExtINT) &&
++ (m->mpc_destapiclint != 0))
++ BUG();
++ if ((m->mpc_irqtype == mp_NMI) &&
++ (m->mpc_destapiclint != 1))
++ BUG();
++}
++
++#ifdef CONFIG_X86_NUMAQ
++static void __init MP_translation_info (struct mpc_config_translation *m)
++{
++ printk(KERN_INFO "Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);
++
++ if (mpc_record >= MAX_MPC_ENTRY)
++ printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n");
++ else
++ translation_table[mpc_record] = m; /* stash this for later */
++ if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad))
++ node_set_online(m->trans_quad);
++}
++
++/*
++ * Read/parse the MPC oem tables
++ */
++
++static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \
++ unsigned short oemsize)
++{
++ int count = sizeof (*oemtable); /* the header size */
++ unsigned char *oemptr = ((unsigned char *)oemtable)+count;
++
++ mpc_record = 0;
++ printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", oemtable);
++ if (memcmp(oemtable->oem_signature,MPC_OEM_SIGNATURE,4))
++ {
++ printk(KERN_WARNING "SMP mpc oemtable: bad signature [%c%c%c%c]!\n",
++ oemtable->oem_signature[0],
++ oemtable->oem_signature[1],
++ oemtable->oem_signature[2],
++ oemtable->oem_signature[3]);
++ return;
++ }
++ if (mpf_checksum((unsigned char *)oemtable,oemtable->oem_length))
++ {
++ printk(KERN_WARNING "SMP oem mptable: checksum error!\n");
++ return;
++ }
++ while (count < oemtable->oem_length) {
++ switch (*oemptr) {
++ case MP_TRANSLATION:
++ {
++ struct mpc_config_translation *m=
++ (struct mpc_config_translation *)oemptr;
++ MP_translation_info(m);
++ oemptr += sizeof(*m);
++ count += sizeof(*m);
++ ++mpc_record;
++ break;
++ }
++ default:
++ {
++ printk(KERN_WARNING "Unrecognised OEM table entry type! - %d\n", (int) *oemptr);
++ return;
++ }
++ }
++ }
++}
++
++static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,
++ char *productid)
++{
++ if (strncmp(oem, "IBM NUMA", 8))
++ printk("Warning! May not be a NUMA-Q system!\n");
++ if (mpc->mpc_oemptr)
++ smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr,
++ mpc->mpc_oemsize);
++}
++#endif /* CONFIG_X86_NUMAQ */
++
++/*
++ * Read/parse the MPC
++ */
++
++static int __init smp_read_mpc(struct mp_config_table *mpc)
++{
++ char str[16];
++ char oem[10];
++ int count=sizeof(*mpc);
++ unsigned char *mpt=((unsigned char *)mpc)+count;
++
++ if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
++ printk(KERN_ERR "SMP mptable: bad signature [0x%x]!\n",
++ *(u32 *)mpc->mpc_signature);
++ return 0;
++ }
++ if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {
++ printk(KERN_ERR "SMP mptable: checksum error!\n");
++ return 0;
++ }
++ if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
++ printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",
++ mpc->mpc_spec);
++ return 0;
++ }
++ if (!mpc->mpc_lapic) {
++ printk(KERN_ERR "SMP mptable: null local APIC address!\n");
++ return 0;
++ }
++ memcpy(oem,mpc->mpc_oem,8);
++ oem[8]=0;
++ printk(KERN_INFO "OEM ID: %s ",oem);
++
++ memcpy(str,mpc->mpc_productid,12);
++ str[12]=0;
++ printk("Product ID: %s ",str);
++
++ mps_oem_check(mpc, oem, str);
++
++ printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
++
++ /*
++ * Save the local APIC address (it might be non-default) -- but only
++ * if we're not using ACPI.
++ */
++ if (!acpi_lapic)
++ mp_lapic_addr = mpc->mpc_lapic;
++
++ /*
++ * Now process the configuration blocks.
++ */
++ mpc_record = 0;
++ while (count < mpc->mpc_length) {
++ switch(*mpt) {
++ case MP_PROCESSOR:
++ {
++ struct mpc_config_processor *m=
++ (struct mpc_config_processor *)mpt;
++ /* ACPI may have already provided this data */
++ if (!acpi_lapic)
++ MP_processor_info(m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
++ break;
++ }
++ case MP_BUS:
++ {
++ struct mpc_config_bus *m=
++ (struct mpc_config_bus *)mpt;
++ MP_bus_info(m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
++ break;
++ }
++ case MP_IOAPIC:
++ {
++ struct mpc_config_ioapic *m=
++ (struct mpc_config_ioapic *)mpt;
++ MP_ioapic_info(m);
++ mpt+=sizeof(*m);
++ count+=sizeof(*m);
++ break;
++ }
++ case MP_INTSRC:
++ {
++ struct mpc_config_intsrc *m=
++ (struct mpc_config_intsrc *)mpt;
++
++ MP_intsrc_info(m);
++ mpt+=sizeof(*m);
++ count+=sizeof(*m);
++ break;
++ }
++ case MP_LINTSRC:
++ {
++ struct mpc_config_lintsrc *m=
++ (struct mpc_config_lintsrc *)mpt;
++ MP_lintsrc_info(m);
++ mpt+=sizeof(*m);
++ count+=sizeof(*m);
++ break;
++ }
++ default:
++ {
++ count = mpc->mpc_length;
++ break;
++ }
++ }
++ ++mpc_record;
++ }
++ clustered_apic_check();
++ if (!num_processors)
++ printk(KERN_ERR "SMP mptable: no processors registered!\n");
++ return num_processors;
++}
++
++static int __init ELCR_trigger(unsigned int irq)
++{
++ unsigned int port;
++
++ port = 0x4d0 + (irq >> 3);
++ return (inb(port) >> (irq & 7)) & 1;
++}
++
++static void __init construct_default_ioirq_mptable(int mpc_default_type)
++{
++ struct mpc_config_intsrc intsrc;
++ int i;
++ int ELCR_fallback = 0;
++
++ intsrc.mpc_type = MP_INTSRC;
++ intsrc.mpc_irqflag = 0; /* conforming */
++ intsrc.mpc_srcbus = 0;
++ intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
++
++ intsrc.mpc_irqtype = mp_INT;
++
++ /*
++ * If true, we have an ISA/PCI system with no IRQ entries
++ * in the MP table. To prevent the PCI interrupts from being set up
++ * incorrectly, we try to use the ELCR. The sanity check to see if
++ * there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can
++ * never be level sensitive, so we simply see if the ELCR agrees.
++ * If it does, we assume it's valid.
++ */
++ if (mpc_default_type == 5) {
++ printk(KERN_INFO "ISA/PCI bus type with no IRQ information... falling back to ELCR\n");
++
++ if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13))
++ printk(KERN_WARNING "ELCR contains invalid data... not using ELCR\n");
++ else {
++ printk(KERN_INFO "Using ELCR to identify PCI interrupts\n");
++ ELCR_fallback = 1;
++ }
++ }
++
++ for (i = 0; i < 16; i++) {
++ switch (mpc_default_type) {
++ case 2:
++ if (i == 0 || i == 13)
++ continue; /* IRQ0 & IRQ13 not connected */
++ /* fall through */
++ default:
++ if (i == 2)
++ continue; /* IRQ2 is never connected */
++ }
++
++ if (ELCR_fallback) {
++ /*
++ * If the ELCR indicates a level-sensitive interrupt, we
++ * copy that information over to the MP table in the
++ * irqflag field (level sensitive, active high polarity).
++ */
++ if (ELCR_trigger(i))
++ intsrc.mpc_irqflag = 13;
++ else
++ intsrc.mpc_irqflag = 0;
++ }
++
++ intsrc.mpc_srcbusirq = i;
++ intsrc.mpc_dstirq = i ? i : 2; /* IRQ0 to INTIN2 */
++ MP_intsrc_info(&intsrc);
++ }
++
++ intsrc.mpc_irqtype = mp_ExtINT;
++ intsrc.mpc_srcbusirq = 0;
++ intsrc.mpc_dstirq = 0; /* 8259A to INTIN0 */
++ MP_intsrc_info(&intsrc);
++}
++
++static inline void __init construct_default_ISA_mptable(int mpc_default_type)
++{
++ struct mpc_config_processor processor;
++ struct mpc_config_bus bus;
++ struct mpc_config_ioapic ioapic;
++ struct mpc_config_lintsrc lintsrc;
++ int linttypes[2] = { mp_ExtINT, mp_NMI };
++ int i;
++
++ /*
++ * local APIC has default address
++ */
++ mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
++
++ /*
++ * 2 CPUs, numbered 0 & 1.
++ */
++ processor.mpc_type = MP_PROCESSOR;
++ /* Either an integrated APIC or a discrete 82489DX. */
++ processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
++ processor.mpc_cpuflag = CPU_ENABLED;
++ processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
++ (boot_cpu_data.x86_model << 4) |
++ boot_cpu_data.x86_mask;
++ processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
++ processor.mpc_reserved[0] = 0;
++ processor.mpc_reserved[1] = 0;
++ for (i = 0; i < 2; i++) {
++ processor.mpc_apicid = i;
++ MP_processor_info(&processor);
++ }
++
++ bus.mpc_type = MP_BUS;
++ bus.mpc_busid = 0;
++ switch (mpc_default_type) {
++ default:
++ printk("???\n");
++ printk(KERN_ERR "Unknown standard configuration %d\n",
++ mpc_default_type);
++ /* fall through */
++ case 1:
++ case 5:
++ memcpy(bus.mpc_bustype, "ISA ", 6);
++ break;
++ case 2:
++ case 6:
++ case 3:
++ memcpy(bus.mpc_bustype, "EISA ", 6);
++ break;
++ case 4:
++ case 7:
++ memcpy(bus.mpc_bustype, "MCA ", 6);
++ }
++ MP_bus_info(&bus);
++ if (mpc_default_type > 4) {
++ bus.mpc_busid = 1;
++ memcpy(bus.mpc_bustype, "PCI ", 6);
++ MP_bus_info(&bus);
++ }
++
++ ioapic.mpc_type = MP_IOAPIC;
++ ioapic.mpc_apicid = 2;
++ ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
++ ioapic.mpc_flags = MPC_APIC_USABLE;
++ ioapic.mpc_apicaddr = 0xFEC00000;
++ MP_ioapic_info(&ioapic);
++
++ /*
++ * We set up most of the low 16 IO-APIC pins according to MPS rules.
++ */
++ construct_default_ioirq_mptable(mpc_default_type);
++
++ lintsrc.mpc_type = MP_LINTSRC;
++ lintsrc.mpc_irqflag = 0; /* conforming */
++ lintsrc.mpc_srcbusid = 0;
++ lintsrc.mpc_srcbusirq = 0;
++ lintsrc.mpc_destapic = MP_APIC_ALL;
++ for (i = 0; i < 2; i++) {
++ lintsrc.mpc_irqtype = linttypes[i];
++ lintsrc.mpc_destapiclint = i;
++ MP_lintsrc_info(&lintsrc);
++ }
++}
++
++static struct intel_mp_floating *mpf_found;
++
++/*
++ * Scan the memory blocks for an SMP configuration block.
++ */
++void __init get_smp_config (void)
++{
++ struct intel_mp_floating *mpf = mpf_found;
++
++ /*
++ * ACPI supports both logical (e.g. Hyper-Threading) and physical
++ * processors, where MPS only supports physical.
++ */
++ if (acpi_lapic && acpi_ioapic) {
++ printk(KERN_INFO "Using ACPI (MADT) for SMP configuration information\n");
++ return;
++ }
++ else if (acpi_lapic)
++ printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n");
++
++ printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
++ if (mpf->mpf_feature2 & (1<<7)) {
++ printk(KERN_INFO " IMCR and PIC compatibility mode.\n");
++ pic_mode = 1;
++ } else {
++ printk(KERN_INFO " Virtual Wire compatibility mode.\n");
++ pic_mode = 0;
++ }
++
++ /*
++ * Now see if we need to read further.
++ */
++ if (mpf->mpf_feature1 != 0) {
++
++ printk(KERN_INFO "Default MP configuration #%d\n", mpf->mpf_feature1);
++ construct_default_ISA_mptable(mpf->mpf_feature1);
++
++ } else if (mpf->mpf_physptr) {
++
++ /*
++ * Read the physical hardware table. Anything here will
++ * override the defaults.
++ */
++ if (!smp_read_mpc(isa_bus_to_virt(mpf->mpf_physptr))) {
++ smp_found_config = 0;
++ printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
++ printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
++ return;
++ }
++ /*
++ * If there are no explicit MP IRQ entries, then we are
++ * broken. We set up most of the low 16 IO-APIC pins to
++ * ISA defaults and hope it will work.
++ */
++ if (!mp_irq_entries) {
++ struct mpc_config_bus bus;
++
++ printk(KERN_ERR "BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n");
++
++ bus.mpc_type = MP_BUS;
++ bus.mpc_busid = 0;
++ memcpy(bus.mpc_bustype, "ISA ", 6);
++ MP_bus_info(&bus);
++
++ construct_default_ioirq_mptable(0);
++ }
++
++ } else
++ BUG();
++
++ printk(KERN_INFO "Processors: %d\n", num_processors);
++ /*
++ * Only use the first configuration found.
++ */
++}
++
++static int __init smp_scan_config (unsigned long base, unsigned long length)
++{
++ unsigned long *bp = isa_bus_to_virt(base);
++ struct intel_mp_floating *mpf;
++
++ Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length);
++ if (sizeof(*mpf) != 16)
++ printk("Error: MPF size\n");
++
++ while (length > 0) {
++ mpf = (struct intel_mp_floating *)bp;
++ if ((*bp == SMP_MAGIC_IDENT) &&
++ (mpf->mpf_length == 1) &&
++ !mpf_checksum((unsigned char *)bp, 16) &&
++ ((mpf->mpf_specification == 1)
++ || (mpf->mpf_specification == 4)) ) {
++
++ smp_found_config = 1;
++#ifndef CONFIG_XEN
++ printk(KERN_INFO "found SMP MP-table at %08lx\n",
++ virt_to_phys(mpf));
++ reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
++ if (mpf->mpf_physptr) {
++ /*
++ * We cannot access to MPC table to compute
++ * table size yet, as only few megabytes from
++ * the bottom is mapped now.
++ * PC-9800's MPC table places on the very last
++ * of physical memory; so that simply reserving
++ * PAGE_SIZE from mpg->mpf_physptr yields BUG()
++ * in reserve_bootmem.
++ */
++ unsigned long size = PAGE_SIZE;
++ unsigned long end = max_low_pfn * PAGE_SIZE;
++ if (mpf->mpf_physptr + size > end)
++ size = end - mpf->mpf_physptr;
++ reserve_bootmem(mpf->mpf_physptr, size);
++ }
++#else
++ printk(KERN_INFO "found SMP MP-table at %08lx\n",
++ ((unsigned long)bp - (unsigned long)isa_bus_to_virt(base)) + base);
++#endif
++
++ mpf_found = mpf;
++ return 1;
++ }
++ bp += 4;
++ length -= 16;
++ }
++ return 0;
++}
++
++void __init find_smp_config (void)
++{
++#ifndef CONFIG_XEN
++ unsigned int address;
++#endif
++
++ /*
++ * FIXME: Linux assumes you have 640K of base ram..
++ * this continues the error...
++ *
++ * 1) Scan the bottom 1K for a signature
++ * 2) Scan the top 1K of base RAM
++ * 3) Scan the 64K of bios
++ */
++ if (smp_scan_config(0x0,0x400) ||
++ smp_scan_config(639*0x400,0x400) ||
++ smp_scan_config(0xF0000,0x10000))
++ return;
++ /*
++ * If it is an SMP machine we should know now, unless the
++ * configuration is in an EISA/MCA bus machine with an
++ * extended bios data area.
++ *
++ * there is a real-mode segmented pointer pointing to the
++ * 4K EBDA area at 0x40E, calculate and scan it here.
++ *
++ * NOTE! There are Linux loaders that will corrupt the EBDA
++ * area, and as such this kind of SMP config may be less
++ * trustworthy, simply because the SMP table may have been
++ * stomped on during early boot. These loaders are buggy and
++ * should be fixed.
++ *
++ * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
++ */
++
++#ifndef CONFIG_XEN
++ address = get_bios_ebda();
++ if (address)
++ smp_scan_config(address, 0x400);
++#endif
++}
++
++int es7000_plat;
++
++/* --------------------------------------------------------------------------
++ ACPI-based MP Configuration
++ -------------------------------------------------------------------------- */
++
++#ifdef CONFIG_ACPI
++
++void __init mp_register_lapic_address (
++ u64 address)
++{
++#ifndef CONFIG_XEN
++ mp_lapic_addr = (unsigned long) address;
++
++ set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
++
++ if (boot_cpu_physical_apicid == -1U)
++ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
++
++ Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid);
++#endif
++}
++
++
++void __devinit mp_register_lapic (
++ u8 id,
++ u8 enabled)
++{
++ struct mpc_config_processor processor;
++ int boot_cpu = 0;
++
++ if (MAX_APICS - id <= 0) {
++ printk(KERN_WARNING "Processor #%d invalid (max %d)\n",
++ id, MAX_APICS);
++ return;
++ }
++
++ if (id == boot_cpu_physical_apicid)
++ boot_cpu = 1;
++
++#ifndef CONFIG_XEN
++ processor.mpc_type = MP_PROCESSOR;
++ processor.mpc_apicid = id;
++ processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR));
++ processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0);
++ processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0);
++ processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
++ (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
++ processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
++ processor.mpc_reserved[0] = 0;
++ processor.mpc_reserved[1] = 0;
++#endif
++
++ MP_processor_info(&processor);
++}
++
++#ifdef CONFIG_X86_IO_APIC
++
++#define MP_ISA_BUS 0
++#define MP_MAX_IOAPIC_PIN 127
++
++static struct mp_ioapic_routing {
++ int apic_id;
++ int gsi_base;
++ int gsi_end;
++ u32 pin_programmed[4];
++} mp_ioapic_routing[MAX_IO_APICS];
++
++
++static int mp_find_ioapic (
++ int gsi)
++{
++ int i = 0;
++
++ /* Find the IOAPIC that manages this GSI. */
++ for (i = 0; i < nr_ioapics; i++) {
++ if ((gsi >= mp_ioapic_routing[i].gsi_base)
++ && (gsi <= mp_ioapic_routing[i].gsi_end))
++ return i;
++ }
++
++ printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
++
++ return -1;
++}
++
++
++void __init mp_register_ioapic (
++ u8 id,
++ u32 address,
++ u32 gsi_base)
++{
++ int idx = 0;
++ int tmpid;
++
++ if (nr_ioapics >= MAX_IO_APICS) {
++ printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
++ "(found %d)\n", MAX_IO_APICS, nr_ioapics);
++ panic("Recompile kernel with bigger MAX_IO_APICS!\n");
++ }
++ if (!address) {
++ printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
++ " found in MADT table, skipping!\n");
++ return;
++ }
++
++ idx = nr_ioapics++;
++
++ mp_ioapics[idx].mpc_type = MP_IOAPIC;
++ mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
++ mp_ioapics[idx].mpc_apicaddr = address;
++
++#ifndef CONFIG_XEN
++ set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
++#endif
++ if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
++ && !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
++ tmpid = io_apic_get_unique_id(idx, id);
++ else
++ tmpid = id;
++ if (tmpid == -1) {
++ nr_ioapics--;
++ return;
++ }
++ mp_ioapics[idx].mpc_apicid = tmpid;
++ mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
++
++ /*
++ * Build basic GSI lookup table to facilitate gsi->io_apic lookups
++ * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
++ */
++ mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
++ mp_ioapic_routing[idx].gsi_base = gsi_base;
++ mp_ioapic_routing[idx].gsi_end = gsi_base +
++ io_apic_get_redir_entries(idx);
++
++ printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, "
++ "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
++ mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
++ mp_ioapic_routing[idx].gsi_base,
++ mp_ioapic_routing[idx].gsi_end);
++
++ return;
++}
++
++
++void __init mp_override_legacy_irq (
++ u8 bus_irq,
++ u8 polarity,
++ u8 trigger,
++ u32 gsi)
++{
++ struct mpc_config_intsrc intsrc;
++ int ioapic = -1;
++ int pin = -1;
++
++ /*
++ * Convert 'gsi' to 'ioapic.pin'.
++ */
++ ioapic = mp_find_ioapic(gsi);
++ if (ioapic < 0)
++ return;
++ pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
++
++ /*
++ * TBD: This check is for faulty timer entries, where the override
++ * erroneously sets the trigger to level, resulting in a HUGE
++ * increase of timer interrupts!
++ */
++ if ((bus_irq == 0) && (trigger == 3))
++ trigger = 1;
++
++ intsrc.mpc_type = MP_INTSRC;
++ intsrc.mpc_irqtype = mp_INT;
++ intsrc.mpc_irqflag = (trigger << 2) | polarity;
++ intsrc.mpc_srcbus = MP_ISA_BUS;
++ intsrc.mpc_srcbusirq = bus_irq; /* IRQ */
++ intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* APIC ID */
++ intsrc.mpc_dstirq = pin; /* INTIN# */
++
++ Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n",
++ intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
++ (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
++ intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
++
++ mp_irqs[mp_irq_entries] = intsrc;
++ if (++mp_irq_entries == MAX_IRQ_SOURCES)
++ panic("Max # of irq sources exceeded!\n");
++
++ return;
++}
++
++void __init mp_config_acpi_legacy_irqs (void)
++{
++ struct mpc_config_intsrc intsrc;
++ int i = 0;
++ int ioapic = -1;
++
++ /*
++ * Fabricate the legacy ISA bus (bus #31).
++ */
++ mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
++ Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
++
++ /*
++ * Older generations of ES7000 have no legacy identity mappings
++ */
++ if (es7000_plat == 1)
++ return;
++
++ /*
++ * Locate the IOAPIC that manages the ISA IRQs (0-15).
++ */
++ ioapic = mp_find_ioapic(0);
++ if (ioapic < 0)
++ return;
++
++ intsrc.mpc_type = MP_INTSRC;
++ intsrc.mpc_irqflag = 0; /* Conforming */
++ intsrc.mpc_srcbus = MP_ISA_BUS;
++ intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
++
++ /*
++ * Use the default configuration for the IRQs 0-15. Unless
++ * overriden by (MADT) interrupt source override entries.
++ */
++ for (i = 0; i < 16; i++) {
++ int idx;
++
++ for (idx = 0; idx < mp_irq_entries; idx++) {
++ struct mpc_config_intsrc *irq = mp_irqs + idx;
++
++ /* Do we already have a mapping for this ISA IRQ? */
++ if (irq->mpc_srcbus == MP_ISA_BUS && irq->mpc_srcbusirq == i)
++ break;
++
++ /* Do we already have a mapping for this IOAPIC pin */
++ if ((irq->mpc_dstapic == intsrc.mpc_dstapic) &&
++ (irq->mpc_dstirq == i))
++ break;
++ }
++
++ if (idx != mp_irq_entries) {
++ printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
++ continue; /* IRQ already used */
++ }
++
++ intsrc.mpc_irqtype = mp_INT;
++ intsrc.mpc_srcbusirq = i; /* Identity mapped */
++ intsrc.mpc_dstirq = i;
++
++ Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, "
++ "%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
++ (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
++ intsrc.mpc_srcbusirq, intsrc.mpc_dstapic,
++ intsrc.mpc_dstirq);
++
++ mp_irqs[mp_irq_entries] = intsrc;
++ if (++mp_irq_entries == MAX_IRQ_SOURCES)
++ panic("Max # of irq sources exceeded!\n");
++ }
++}
++
++#define MAX_GSI_NUM 4096
++
++int mp_register_gsi (u32 gsi, int triggering, int polarity)
++{
++ int ioapic = -1;
++ int ioapic_pin = 0;
++ int idx, bit = 0;
++ static int pci_irq = 16;
++ /*
++ * Mapping between Global System Interrups, which
++ * represent all possible interrupts, and IRQs
++ * assigned to actual devices.
++ */
++ static int gsi_to_irq[MAX_GSI_NUM];
++
++ /* Don't set up the ACPI SCI because it's already set up */
++ if (acpi_fadt.sci_int == gsi)
++ return gsi;
++
++ ioapic = mp_find_ioapic(gsi);
++ if (ioapic < 0) {
++ printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
++ return gsi;
++ }
++
++ ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
++
++ if (ioapic_renumber_irq)
++ gsi = ioapic_renumber_irq(ioapic, gsi);
++
++ /*
++ * Avoid pin reprogramming. PRTs typically include entries
++ * with redundant pin->gsi mappings (but unique PCI devices);
++ * we only program the IOAPIC on the first.
++ */
++ bit = ioapic_pin % 32;
++ idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
++ if (idx > 3) {
++ printk(KERN_ERR "Invalid reference to IOAPIC pin "
++ "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
++ ioapic_pin);
++ return gsi;
++ }
++ if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
++ Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
++ mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
++ return gsi_to_irq[gsi];
++ }
++
++ mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
++
++ if (triggering == ACPI_LEVEL_SENSITIVE) {
++ /*
++ * For PCI devices assign IRQs in order, avoiding gaps
++ * due to unused I/O APIC pins.
++ */
++ int irq = gsi;
++ if (gsi < MAX_GSI_NUM) {
++ /*
++ * Retain the VIA chipset work-around (gsi > 15), but
++ * avoid a problem where the 8254 timer (IRQ0) is setup
++ * via an override (so it's not on pin 0 of the ioapic),
++ * and at the same time, the pin 0 interrupt is a PCI
++ * type. The gsi > 15 test could cause these two pins
++ * to be shared as IRQ0, and they are not shareable.
++ * So test for this condition, and if necessary, avoid
++ * the pin collision.
++ */
++ if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
++ gsi = pci_irq++;
++ /*
++ * Don't assign IRQ used by ACPI SCI
++ */
++ if (gsi == acpi_fadt.sci_int)
++ gsi = pci_irq++;
++ gsi_to_irq[irq] = gsi;
++ } else {
++ printk(KERN_ERR "GSI %u is too high\n", gsi);
++ return gsi;
++ }
++ }
++
++ io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
++ triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
++ polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
++ return gsi;
++}
++
++#endif /* CONFIG_X86_IO_APIC */
++#endif /* CONFIG_ACPI */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/pci-dma-xen.c linux-2.6.18-xen/arch/i386/kernel/pci-dma-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/pci-dma-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/pci-dma-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,379 @@
++/*
++ * Dynamic DMA mapping support.
++ *
++ * On i386 there is no hardware dynamic DMA address translation,
++ * so consistent alloc/free are merely page allocation/freeing.
++ * The rest of the dynamic DMA mapping interface is implemented
++ * in asm/pci.h.
++ */
++
++#include <linux/types.h>
++#include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/pci.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <asm/io.h>
++#include <xen/balloon.h>
++#include <asm/tlbflush.h>
++#include <asm-i386/mach-xen/asm/swiotlb.h>
++#include <asm/bug.h>
++
++#ifdef __x86_64__
++int iommu_merge __read_mostly = 0;
++EXPORT_SYMBOL(iommu_merge);
++
++dma_addr_t bad_dma_address __read_mostly;
++EXPORT_SYMBOL(bad_dma_address);
++
++/* This tells the BIO block layer to assume merging. Default to off
++ because we cannot guarantee merging later. */
++int iommu_bio_merge __read_mostly = 0;
++EXPORT_SYMBOL(iommu_bio_merge);
++
++int iommu_sac_force __read_mostly = 0;
++EXPORT_SYMBOL(iommu_sac_force);
++
++int no_iommu __read_mostly;
++#ifdef CONFIG_IOMMU_DEBUG
++int panic_on_overflow __read_mostly = 1;
++int force_iommu __read_mostly = 1;
++#else
++int panic_on_overflow __read_mostly = 0;
++int force_iommu __read_mostly= 0;
++#endif
++
++/* Set this to 1 if there is a HW IOMMU in the system */
++int iommu_detected __read_mostly = 0;
++
++void __init pci_iommu_alloc(void)
++{
++ /*
++ * The order of these functions is important for
++ * fall-back/fail-over reasons
++ */
++#ifdef CONFIG_IOMMU
++ iommu_hole_init();
++#endif
++
++#ifdef CONFIG_CALGARY_IOMMU
++#include <asm/calgary.h>
++ detect_calgary();
++#endif
++
++#ifdef CONFIG_SWIOTLB
++ pci_swiotlb_init();
++#endif
++}
++
++__init int iommu_setup(char *p)
++{
++ return 1;
++}
++#endif
++
++struct dma_coherent_mem {
++ void *virt_base;
++ u32 device_base;
++ int size;
++ int flags;
++ unsigned long *bitmap;
++};
++
++#define IOMMU_BUG_ON(test) \
++do { \
++ if (unlikely(test)) { \
++ printk(KERN_ALERT "Fatal DMA error! " \
++ "Please use 'swiotlb=force'\n"); \
++ BUG(); \
++ } \
++} while (0)
++
++int
++dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
++ enum dma_data_direction direction)
++{
++ int i, rc;
++
++ if (direction == DMA_NONE)
++ BUG();
++ WARN_ON(nents == 0 || sg[0].length == 0);
++
++ if (swiotlb) {
++ rc = swiotlb_map_sg(hwdev, sg, nents, direction);
++ } else {
++ for (i = 0; i < nents; i++ ) {
++ sg[i].dma_address =
++ page_to_bus(sg[i].page) + sg[i].offset;
++ sg[i].dma_length = sg[i].length;
++ BUG_ON(!sg[i].page);
++ IOMMU_BUG_ON(address_needs_mapping(
++ hwdev, sg[i].dma_address));
++ }
++ rc = nents;
++ }
++
++ flush_write_buffers();
++ return rc;
++}
++EXPORT_SYMBOL(dma_map_sg);
++
++void
++dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
++ enum dma_data_direction direction)
++{
++ BUG_ON(direction == DMA_NONE);
++ if (swiotlb)
++ swiotlb_unmap_sg(hwdev, sg, nents, direction);
++}
++EXPORT_SYMBOL(dma_unmap_sg);
++
++/*
++ * XXX This file is also used by xenLinux/ia64.
++ * "defined(__i386__) || defined (__x86_64__)" means "!defined(__ia64__)".
++ * This #if work around should be removed once this file is merbed back into
++ * i386' pci-dma or is moved to drivers/xen/core.
++ */
++#if defined(__i386__) || defined(__x86_64__)
++dma_addr_t
++dma_map_page(struct device *dev, struct page *page, unsigned long offset,
++ size_t size, enum dma_data_direction direction)
++{
++ dma_addr_t dma_addr;
++
++ BUG_ON(direction == DMA_NONE);
++
++ if (swiotlb) {
++ dma_addr = swiotlb_map_page(
++ dev, page, offset, size, direction);
++ } else {
++ dma_addr = page_to_bus(page) + offset;
++ IOMMU_BUG_ON(address_needs_mapping(dev, dma_addr));
++ }
++
++ return dma_addr;
++}
++EXPORT_SYMBOL(dma_map_page);
++
++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);
++ if (swiotlb)
++ swiotlb_unmap_page(dev, dma_address, size, direction);
++}
++EXPORT_SYMBOL(dma_unmap_page);
++#endif /* defined(__i386__) || defined(__x86_64__) */
++
++int
++dma_mapping_error(dma_addr_t dma_addr)
++{
++ if (swiotlb)
++ return swiotlb_dma_mapping_error(dma_addr);
++ return 0;
++}
++EXPORT_SYMBOL(dma_mapping_error);
++
++int
++dma_supported(struct device *dev, u64 mask)
++{
++ if (swiotlb)
++ return swiotlb_dma_supported(dev, mask);
++ /*
++ * By default we'll BUG when an infeasible DMA is requested, and
++ * request swiotlb=force (see IOMMU_BUG_ON).
++ */
++ return 1;
++}
++EXPORT_SYMBOL(dma_supported);
++
++void *dma_alloc_coherent(struct device *dev, size_t size,
++ dma_addr_t *dma_handle, gfp_t gfp)
++{
++ void *ret;
++ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
++ unsigned int order = get_order(size);
++ unsigned long vstart;
++ /* ignore region specifiers */
++ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
++
++ if (mem) {
++ int page = bitmap_find_free_region(mem->bitmap, mem->size,
++ order);
++ if (page >= 0) {
++ *dma_handle = mem->device_base + (page << PAGE_SHIFT);
++ ret = mem->virt_base + (page << PAGE_SHIFT);
++ memset(ret, 0, size);
++ return ret;
++ }
++ if (mem->flags & DMA_MEMORY_EXCLUSIVE)
++ return NULL;
++ }
++
++ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
++ gfp |= GFP_DMA;
++
++ vstart = __get_free_pages(gfp, order);
++ ret = (void *)vstart;
++
++ if (ret != NULL) {
++ /* NB. Hardcode 31 address bits for now: aacraid limitation. */
++ if (xen_create_contiguous_region(vstart, order, 31) != 0) {
++ free_pages(vstart, order);
++ return NULL;
++ }
++ memset(ret, 0, size);
++ *dma_handle = virt_to_bus(ret);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(dma_alloc_coherent);
++
++void dma_free_coherent(struct device *dev, size_t size,
++ void *vaddr, dma_addr_t dma_handle)
++{
++ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
++ int order = get_order(size);
++
++ if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
++ int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
++
++ bitmap_release_region(mem->bitmap, page, order);
++ } else {
++ xen_destroy_contiguous_region((unsigned long)vaddr, order);
++ free_pages((unsigned long)vaddr, order);
++ }
++}
++EXPORT_SYMBOL(dma_free_coherent);
++
++#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
++int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
++ dma_addr_t device_addr, size_t size, int flags)
++{
++ void __iomem *mem_base;
++ int pages = size >> PAGE_SHIFT;
++ int bitmap_size = (pages + 31)/32;
++
++ if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
++ goto out;
++ if (!size)
++ goto out;
++ if (dev->dma_mem)
++ goto out;
++
++ /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
++
++ mem_base = ioremap(bus_addr, size);
++ if (!mem_base)
++ goto out;
++
++ dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
++ if (!dev->dma_mem)
++ goto out;
++ memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
++ dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL);
++ if (!dev->dma_mem->bitmap)
++ goto free1_out;
++ memset(dev->dma_mem->bitmap, 0, bitmap_size);
++
++ dev->dma_mem->virt_base = mem_base;
++ dev->dma_mem->device_base = device_addr;
++ dev->dma_mem->size = pages;
++ dev->dma_mem->flags = flags;
++
++ if (flags & DMA_MEMORY_MAP)
++ return DMA_MEMORY_MAP;
++
++ return DMA_MEMORY_IO;
++
++ free1_out:
++ kfree(dev->dma_mem->bitmap);
++ out:
++ return 0;
++}
++EXPORT_SYMBOL(dma_declare_coherent_memory);
++
++void dma_release_declared_memory(struct device *dev)
++{
++ struct dma_coherent_mem *mem = dev->dma_mem;
++
++ if(!mem)
++ return;
++ dev->dma_mem = NULL;
++ iounmap(mem->virt_base);
++ kfree(mem->bitmap);
++ kfree(mem);
++}
++EXPORT_SYMBOL(dma_release_declared_memory);
++
++void *dma_mark_declared_memory_occupied(struct device *dev,
++ dma_addr_t device_addr, size_t size)
++{
++ struct dma_coherent_mem *mem = dev->dma_mem;
++ int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
++ int pos, err;
++
++ if (!mem)
++ return ERR_PTR(-EINVAL);
++
++ pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
++ err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
++ if (err != 0)
++ return ERR_PTR(err);
++ return mem->virt_base + (pos << PAGE_SHIFT);
++}
++EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
++#endif /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */
++
++dma_addr_t
++dma_map_single(struct device *dev, void *ptr, size_t size,
++ enum dma_data_direction direction)
++{
++ dma_addr_t dma;
++
++ if (direction == DMA_NONE)
++ BUG();
++ WARN_ON(size == 0);
++
++ if (swiotlb) {
++ dma = swiotlb_map_single(dev, ptr, size, direction);
++ } else {
++ dma = virt_to_bus(ptr);
++ IOMMU_BUG_ON(range_straddles_page_boundary(ptr, size));
++ IOMMU_BUG_ON(address_needs_mapping(dev, dma));
++ }
++
++ flush_write_buffers();
++ return dma;
++}
++EXPORT_SYMBOL(dma_map_single);
++
++void
++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction direction)
++{
++ if (direction == DMA_NONE)
++ BUG();
++ if (swiotlb)
++ swiotlb_unmap_single(dev, dma_addr, size, direction);
++}
++EXPORT_SYMBOL(dma_unmap_single);
++
++void
++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction direction)
++{
++ if (swiotlb)
++ swiotlb_sync_single_for_cpu(dev, dma_handle, size, direction);
++}
++EXPORT_SYMBOL(dma_sync_single_for_cpu);
++
++void
++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction direction)
++{
++ if (swiotlb)
++ swiotlb_sync_single_for_device(dev, dma_handle, size, direction);
++}
++EXPORT_SYMBOL(dma_sync_single_for_device);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/process-xen.c linux-2.6.18-xen/arch/i386/kernel/process-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/process-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/process-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,812 @@
++/*
++ * linux/arch/i386/kernel/process.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ *
++ * Pentium III FXSR, SSE support
++ * Gareth Hughes <gareth at valinux.com>, May 2000
++ */
++
++/*
++ * This file handles the architecture-dependent parts of process handling..
++ */
++
++#include <stdarg.h>
++
++#include <linux/cpu.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/elfcore.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/stddef.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/user.h>
++#include <linux/a.out.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/mc146818rtc.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++#include <linux/ptrace.h>
++#include <linux/random.h>
++
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/ldt.h>
++#include <asm/processor.h>
++#include <asm/i387.h>
++#include <asm/desc.h>
++#include <asm/vm86.h>
++#ifdef CONFIG_MATH_EMULATION
++#include <asm/math_emu.h>
++#endif
++
++#include <xen/interface/physdev.h>
++#include <xen/interface/vcpu.h>
++#include <xen/cpu_hotplug.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;
++
++unsigned long boot_option_idle_override = 0;
++EXPORT_SYMBOL(boot_option_idle_override);
++
++/*
++ * Return saved PC of a blocked thread.
++ */
++unsigned long thread_saved_pc(struct task_struct *tsk)
++{
++ return ((unsigned long *)tsk->thread.esp)[3];
++}
++
++/*
++ * Powermanagement idle function, if any..
++ */
++void (*pm_idle)(void);
++EXPORT_SYMBOL(pm_idle);
++static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
++
++void disable_hlt(void)
++{
++ hlt_counter++;
++}
++
++EXPORT_SYMBOL(disable_hlt);
++
++void enable_hlt(void)
++{
++ hlt_counter--;
++}
++
++EXPORT_SYMBOL(enable_hlt);
++
++/* XXX XEN doesn't use default_idle(), poll_idle(). Use xen_idle() instead. */
++void xen_idle(void)
++{
++ local_irq_disable();
++
++ if (need_resched())
++ local_irq_enable();
++ else {
++ current_thread_info()->status &= ~TS_POLLING;
++ smp_mb__after_clear_bit();
++ safe_halt();
++ current_thread_info()->status |= TS_POLLING;
++ }
++}
++#ifdef CONFIG_APM_MODULE
++EXPORT_SYMBOL(default_idle);
++#endif
++
++#ifdef CONFIG_HOTPLUG_CPU
++extern cpumask_t cpu_initialized;
++static inline void play_dead(void)
++{
++ idle_task_exit();
++ local_irq_disable();
++ cpu_clear(smp_processor_id(), cpu_initialized);
++ preempt_enable_no_resched();
++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
++ cpu_bringup();
++}
++#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)
++{
++ int cpu = smp_processor_id();
++
++ current_thread_info()->status |= TS_POLLING;
++
++
++ /* endless idle loop with no priority at all */
++ while (1) {
++ while (!need_resched()) {
++
++ if (__get_cpu_var(cpu_idle_state))
++ __get_cpu_var(cpu_idle_state) = 0;
++
++ rmb();
++
++ if (cpu_is_offline(cpu))
++ play_dead();
++
++ __get_cpu_var(irq_stat).idle_timestamp = jiffies;
++ xen_idle();
++ }
++ preempt_enable_no_resched();
++ schedule();
++ preempt_disable();
++ }
++}
++
++void cpu_idle_wait(void)
++{
++ unsigned int cpu, this_cpu = get_cpu();
++ cpumask_t map;
++
++ set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
++ put_cpu();
++
++ cpus_clear(map);
++ for_each_online_cpu(cpu) {
++ per_cpu(cpu_idle_state, cpu) = 1;
++ cpu_set(cpu, map);
++ }
++
++ __get_cpu_var(cpu_idle_state) = 0;
++
++ wmb();
++ do {
++ ssleep(1);
++ for_each_online_cpu(cpu) {
++ if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
++ cpu_clear(cpu, map);
++ }
++ cpus_and(map, map, cpu_online_map);
++ } while (!cpus_empty(map));
++}
++EXPORT_SYMBOL_GPL(cpu_idle_wait);
++
++/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */
++/* Always use xen_idle() instead. */
++void __devinit select_idle_routine(const struct cpuinfo_x86 *c) {}
++
++void show_regs(struct pt_regs * regs)
++{
++ unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
++
++ printk("\n");
++ printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
++ printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id());
++ print_symbol("EIP is at %s\n", regs->eip);
++
++ if (user_mode_vm(regs))
++ printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
++ printk(" EFLAGS: %08lx %s (%s %.*s)\n",
++ regs->eflags, print_tainted(), system_utsname.release,
++ (int)strcspn(system_utsname.version, " "),
++ system_utsname.version);
++ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
++ regs->eax,regs->ebx,regs->ecx,regs->edx);
++ printk("ESI: %08lx EDI: %08lx EBP: %08lx",
++ regs->esi, regs->edi, regs->ebp);
++ printk(" DS: %04x ES: %04x\n",
++ 0xffff & regs->xds,0xffff & regs->xes);
++
++ cr0 = read_cr0();
++ cr2 = read_cr2();
++ cr3 = read_cr3();
++ cr4 = read_cr4_safe();
++ printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
++ show_trace(NULL, regs, ®s->esp);
++}
++
++/*
++ * This gets run with %ebx containing the
++ * function to call, and %edx containing
++ * the "args".
++ */
++extern void kernel_thread_helper(void);
++__asm__(".section .text\n"
++ ".align 4\n"
++ "kernel_thread_helper:\n\t"
++ "movl %edx,%eax\n\t"
++ "pushl %edx\n\t"
++ "call *%ebx\n\t"
++ "pushl %eax\n\t"
++ "call do_exit\n"
++ ".previous");
++
++/*
++ * Create a kernel thread
++ */
++int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++{
++ struct pt_regs regs;
++
++ memset(®s, 0, sizeof(regs));
++
++ regs.ebx = (unsigned long) fn;
++ regs.edx = (unsigned long) arg;
++
++ regs.xds = __USER_DS;
++ regs.xes = __USER_DS;
++ regs.orig_eax = -1;
++ regs.eip = (unsigned long) kernel_thread_helper;
++ regs.xcs = GET_KERNEL_CS();
++ regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
++
++ /* Ok, create the new process.. */
++ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);
++}
++EXPORT_SYMBOL(kernel_thread);
++
++/*
++ * Free current thread data structures etc..
++ */
++void exit_thread(void)
++{
++ /* The process may have allocated an io port bitmap... nuke it. */
++ if (unlikely(test_thread_flag(TIF_IO_BITMAP))) {
++ struct task_struct *tsk = current;
++ struct thread_struct *t = &tsk->thread;
++
++ struct physdev_set_iobitmap set_iobitmap = { 0 };
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap);
++ kfree(t->io_bitmap_ptr);
++ t->io_bitmap_ptr = NULL;
++ clear_thread_flag(TIF_IO_BITMAP);
++ }
++}
++
++void flush_thread(void)
++{
++ struct task_struct *tsk = current;
++
++ memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
++ memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
++ clear_tsk_thread_flag(tsk, TIF_DEBUG);
++ /*
++ * Forget coprocessor state..
++ */
++ clear_fpu(tsk);
++ clear_used_math();
++}
++
++void release_thread(struct task_struct *dead_task)
++{
++ BUG_ON(dead_task->mm);
++ release_vm86_irqs(dead_task);
++}
++
++/*
++ * This gets called before we allocate a new thread and copy
++ * the current task into it.
++ */
++void prepare_to_copy(struct task_struct *tsk)
++{
++ unlazy_fpu(tsk);
++}
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
++ unsigned long unused,
++ struct task_struct * p, struct pt_regs * regs)
++{
++ struct pt_regs * childregs;
++ struct task_struct *tsk;
++ int err;
++
++ childregs = task_pt_regs(p);
++ *childregs = *regs;
++ childregs->eax = 0;
++ childregs->esp = esp;
++
++ p->thread.esp = (unsigned long) childregs;
++ p->thread.esp0 = (unsigned long) (childregs+1);
++
++ p->thread.eip = (unsigned long) ret_from_fork;
++
++ savesegment(fs,p->thread.fs);
++ savesegment(gs,p->thread.gs);
++
++ tsk = current;
++ if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
++ p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
++ if (!p->thread.io_bitmap_ptr) {
++ p->thread.io_bitmap_max = 0;
++ return -ENOMEM;
++ }
++ memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr,
++ IO_BITMAP_BYTES);
++ set_tsk_thread_flag(p, TIF_IO_BITMAP);
++ }
++
++ /*
++ * Set a new TLS for the child thread?
++ */
++ if (clone_flags & CLONE_SETTLS) {
++ struct desc_struct *desc;
++ struct user_desc info;
++ int idx;
++
++ err = -EFAULT;
++ if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info)))
++ goto out;
++ err = -EINVAL;
++ if (LDT_empty(&info))
++ goto out;
++
++ idx = info.entry_number;
++ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
++ goto out;
++
++ desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
++ desc->a = LDT_entry_a(&info);
++ desc->b = LDT_entry_b(&info);
++ }
++
++ p->thread.iopl = current->thread.iopl;
++
++ err = 0;
++ out:
++ if (err && p->thread.io_bitmap_ptr) {
++ kfree(p->thread.io_bitmap_ptr);
++ p->thread.io_bitmap_max = 0;
++ }
++ return err;
++}
++
++/*
++ * fill in the user structure for a core dump..
++ */
++void dump_thread(struct pt_regs * regs, struct user * dump)
++{
++ int i;
++
++/* changed the size calculations - should hopefully work better. lbt */
++ dump->magic = CMAGIC;
++ dump->start_code = 0;
++ dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
++ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
++ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
++ dump->u_dsize -= dump->u_tsize;
++ dump->u_ssize = 0;
++ for (i = 0; i < 8; i++)
++ dump->u_debugreg[i] = current->thread.debugreg[i];
++
++ if (dump->start_stack < TASK_SIZE)
++ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
++
++ dump->regs.ebx = regs->ebx;
++ dump->regs.ecx = regs->ecx;
++ dump->regs.edx = regs->edx;
++ dump->regs.esi = regs->esi;
++ dump->regs.edi = regs->edi;
++ dump->regs.ebp = regs->ebp;
++ dump->regs.eax = regs->eax;
++ dump->regs.ds = regs->xds;
++ dump->regs.es = regs->xes;
++ savesegment(fs,dump->regs.fs);
++ savesegment(gs,dump->regs.gs);
++ dump->regs.orig_eax = regs->orig_eax;
++ dump->regs.eip = regs->eip;
++ dump->regs.cs = regs->xcs;
++ dump->regs.eflags = regs->eflags;
++ dump->regs.esp = regs->esp;
++ dump->regs.ss = regs->xss;
++
++ dump->u_fpvalid = dump_fpu (regs, &dump->i387);
++}
++EXPORT_SYMBOL(dump_thread);
++
++/*
++ * Capture the user space registers if the task is not running (in user space)
++ */
++int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
++{
++ struct pt_regs ptregs = *task_pt_regs(tsk);
++ ptregs.xcs &= 0xffff;
++ ptregs.xds &= 0xffff;
++ ptregs.xes &= 0xffff;
++ ptregs.xss &= 0xffff;
++
++ elf_core_copy_regs(regs, &ptregs);
++
++ return 1;
++}
++
++/*
++ * 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 = task_thread_info(prev_p);
++ next = task_thread_info(next_p);
++
++ 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
++ * (as a call from the fsave or fwait in effect) rather than to
++ * the wrong process. Lazy FP saving no longer makes any sense
++ * with modern CPU's, and this simplifies a lot of things (SMP
++ * and UP become the same).
++ *
++ * NOTE! We used to use the x86 hardware context switching. The
++ * reason for not using it any more becomes apparent when you
++ * try to recover gracefully from saved state that is no longer
++ * valid (stale segment register values in particular). With the
++ * hardware task-switch, there is no way to fix up bad state in
++ * a reasonable manner.
++ *
++ * The fact that Intel documents the hardware task-switching to
++ * be slow is a fairly red herring - this code is not noticeably
++ * faster. However, there _is_ some room for improvement here,
++ * so the performance issues may eventually be a valid point.
++ * More important, however, is the fact that this allows us much
++ * more flexibility.
++ *
++ * The return value (in %eax) will be the "prev" task after
++ * the task-switch, and shows up in ret_from_fork in entry.S,
++ * for example.
++ */
++struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
++{
++ struct thread_struct *prev = &prev_p->thread,
++ *next = &next_p->thread;
++ int cpu = smp_processor_id();
++#ifndef CONFIG_X86_NO_TSS
++ struct tss_struct *tss = &per_cpu(init_tss, cpu);
++#endif
++ struct physdev_set_iopl iopl_op;
++ struct physdev_set_iobitmap iobmp_op;
++ multicall_entry_t _mcl[8], *mcl = _mcl;
++
++ /* XEN NOTE: FS/GS saved in switch_mm(), not here. */
++
++ /*
++ * This is basically '__unlazy_fpu', except that we queue a
++ * multicall to indicate FPU task switch, rather than
++ * synchronously trapping to Xen.
++ */
++ if (prev_p->thread_info->status & TS_USEDFPU) {
++ __save_init_fpu(prev_p); /* _not_ save_init_fpu() */
++ mcl->op = __HYPERVISOR_fpu_taskswitch;
++ mcl->args[0] = 1;
++ mcl++;
++ }
++#if 0 /* lazy fpu sanity check */
++ else BUG_ON(!(read_cr0() & 8));
++#endif
++
++ /*
++ * Reload esp0.
++ * This is load_esp0(tss, next) with a multicall.
++ */
++ mcl->op = __HYPERVISOR_stack_switch;
++ mcl->args[0] = __KERNEL_DS;
++ mcl->args[1] = next->esp0;
++ mcl++;
++
++ /*
++ * Load the per-thread Thread-Local Storage descriptor.
++ * This is load_TLS(next, cpu) with multicalls.
++ */
++#define C(i) do { \
++ if (unlikely(next->tls_array[i].a != prev->tls_array[i].a || \
++ next->tls_array[i].b != prev->tls_array[i].b)) { \
++ mcl->op = __HYPERVISOR_update_descriptor; \
++ *(u64 *)&mcl->args[0] = virt_to_machine( \
++ &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]);\
++ *(u64 *)&mcl->args[2] = *(u64 *)&next->tls_array[i]; \
++ mcl++; \
++ } \
++} while (0)
++ C(0); C(1); C(2);
++#undef C
++
++ if (unlikely(prev->iopl != next->iopl)) {
++ iopl_op.iopl = (next->iopl == 0) ? 1 : (next->iopl >> 12) & 3;
++ mcl->op = __HYPERVISOR_physdev_op;
++ mcl->args[0] = PHYSDEVOP_set_iopl;
++ mcl->args[1] = (unsigned long)&iopl_op;
++ mcl++;
++ }
++
++ if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
++ iobmp_op.bitmap = (char *)next->io_bitmap_ptr;
++ iobmp_op.nr_ports = next->io_bitmap_ptr ? IO_BITMAP_BITS : 0;
++ mcl->op = __HYPERVISOR_physdev_op;
++ mcl->args[0] = PHYSDEVOP_set_iobitmap;
++ mcl->args[1] = (unsigned long)&iobmp_op;
++ mcl++;
++ }
++
++ (void)HYPERVISOR_multicall(_mcl, mcl - _mcl);
++
++ /*
++ * Restore %fs and %gs if needed.
++ *
++ * Glibc normally makes %fs be zero, and %gs is one of
++ * the TLS segments.
++ */
++ if (unlikely(next->fs))
++ loadsegment(fs, next->fs);
++
++ if (next->gs)
++ loadsegment(gs, next->gs);
++
++ /*
++ * Now maybe reload the debug registers
++ */
++ if (unlikely(next->debugreg[7])) {
++ set_debugreg(next->debugreg[0], 0);
++ set_debugreg(next->debugreg[1], 1);
++ set_debugreg(next->debugreg[2], 2);
++ set_debugreg(next->debugreg[3], 3);
++ /* no 4 and 5 */
++ set_debugreg(next->debugreg[6], 6);
++ set_debugreg(next->debugreg[7], 7);
++ }
++
++ disable_tsc(prev_p, next_p);
++
++ return prev_p;
++}
++
++asmlinkage int sys_fork(struct pt_regs regs)
++{
++ return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL);
++}
++
++asmlinkage int sys_clone(struct pt_regs regs)
++{
++ unsigned long clone_flags;
++ unsigned long newsp;
++ int __user *parent_tidptr, *child_tidptr;
++
++ clone_flags = regs.ebx;
++ newsp = regs.ecx;
++ parent_tidptr = (int __user *)regs.edx;
++ child_tidptr = (int __user *)regs.edi;
++ if (!newsp)
++ newsp = regs.esp;
++ return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr);
++}
++
++/*
++ * This is trivial, and on the face of it looks like it
++ * could equally well be done in user mode.
++ *
++ * Not so, for quite unobvious reasons - register pressure.
++ * In user mode vfork() cannot have a stack frame, and if
++ * done by calling the "clone()" system call directly, you
++ * do not have enough call-clobbered registers to hold all
++ * the information you need.
++ */
++asmlinkage int sys_vfork(struct pt_regs regs)
++{
++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL);
++}
++
++/*
++ * sys_execve() executes a new program.
++ */
++asmlinkage int sys_execve(struct pt_regs regs)
++{
++ int error;
++ char * filename;
++
++ filename = getname((char __user *) regs.ebx);
++ error = PTR_ERR(filename);
++ if (IS_ERR(filename))
++ goto out;
++ error = do_execve(filename,
++ (char __user * __user *) regs.ecx,
++ (char __user * __user *) regs.edx,
++ ®s);
++ if (error == 0) {
++ task_lock(current);
++ current->ptrace &= ~PT_DTRACE;
++ task_unlock(current);
++ /* Make sure we don't return using sysenter.. */
++ set_thread_flag(TIF_IRET);
++ }
++ putname(filename);
++out:
++ return error;
++}
++
++#define top_esp (THREAD_SIZE - sizeof(unsigned long))
++#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long))
++
++unsigned long get_wchan(struct task_struct *p)
++{
++ unsigned long ebp, esp, eip;
++ unsigned long stack_page;
++ int count = 0;
++ if (!p || p == current || p->state == TASK_RUNNING)
++ return 0;
++ stack_page = (unsigned long)task_stack_page(p);
++ esp = p->thread.esp;
++ if (!stack_page || esp < stack_page || esp > top_esp+stack_page)
++ return 0;
++ /* include/asm-i386/system.h:switch_to() pushes ebp last. */
++ ebp = *(unsigned long *) esp;
++ do {
++ if (ebp < stack_page || ebp > top_ebp+stack_page)
++ return 0;
++ eip = *(unsigned long *) (ebp+4);
++ if (!in_sched_functions(eip))
++ return eip;
++ ebp = *(unsigned long *) ebp;
++ } while (count++ < 16);
++ return 0;
++}
++
++/*
++ * sys_alloc_thread_area: get a yet unused TLS descriptor index.
++ */
++static int get_free_idx(void)
++{
++ struct thread_struct *t = ¤t->thread;
++ int idx;
++
++ for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
++ if (desc_empty(t->tls_array + idx))
++ return idx + GDT_ENTRY_TLS_MIN;
++ return -ESRCH;
++}
++
++/*
++ * Set a given TLS descriptor:
++ */
++asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
++{
++ struct thread_struct *t = ¤t->thread;
++ struct user_desc info;
++ struct desc_struct *desc;
++ int cpu, idx;
++
++ if (copy_from_user(&info, u_info, sizeof(info)))
++ return -EFAULT;
++ idx = info.entry_number;
++
++ /*
++ * index -1 means the kernel should try to find and
++ * allocate an empty descriptor:
++ */
++ if (idx == -1) {
++ idx = get_free_idx();
++ if (idx < 0)
++ return idx;
++ if (put_user(idx, &u_info->entry_number))
++ return -EFAULT;
++ }
++
++ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
++ return -EINVAL;
++
++ desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;
++
++ /*
++ * We must not get preempted while modifying the TLS.
++ */
++ cpu = get_cpu();
++
++ if (LDT_empty(&info)) {
++ desc->a = 0;
++ desc->b = 0;
++ } else {
++ desc->a = LDT_entry_a(&info);
++ desc->b = LDT_entry_b(&info);
++ }
++ load_TLS(t, cpu);
++
++ put_cpu();
++
++ return 0;
++}
++
++/*
++ * Get the current Thread-Local Storage area:
++ */
++
++#define GET_BASE(desc) ( \
++ (((desc)->a >> 16) & 0x0000ffff) | \
++ (((desc)->b << 16) & 0x00ff0000) | \
++ ( (desc)->b & 0xff000000) )
++
++#define GET_LIMIT(desc) ( \
++ ((desc)->a & 0x0ffff) | \
++ ((desc)->b & 0xf0000) )
++
++#define GET_32BIT(desc) (((desc)->b >> 22) & 1)
++#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3)
++#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1)
++#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1)
++#define GET_PRESENT(desc) (((desc)->b >> 15) & 1)
++#define GET_USEABLE(desc) (((desc)->b >> 20) & 1)
++
++asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
++{
++ struct user_desc info;
++ struct desc_struct *desc;
++ int idx;
++
++ if (get_user(idx, &u_info->entry_number))
++ return -EFAULT;
++ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
++ return -EINVAL;
++
++ memset(&info, 0, sizeof(info));
++
++ desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
++
++ info.entry_number = idx;
++ info.base_addr = GET_BASE(desc);
++ info.limit = GET_LIMIT(desc);
++ info.seg_32bit = GET_32BIT(desc);
++ info.contents = GET_CONTENTS(desc);
++ info.read_exec_only = !GET_WRITABLE(desc);
++ info.limit_in_pages = GET_LIMIT_PAGES(desc);
++ info.seg_not_present = !GET_PRESENT(desc);
++ info.useable = GET_USEABLE(desc);
++
++ if (copy_to_user(u_info, &info, sizeof(info)))
++ return -EFAULT;
++ return 0;
++}
++
++unsigned long arch_align_stack(unsigned long sp)
++{
++ if (randomize_va_space)
++ sp -= get_random_int() % 8192;
++ return sp & ~0xf;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/quirks-xen.c linux-2.6.18-xen/arch/i386/kernel/quirks-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/quirks-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/quirks-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * This file contains work-arounds for x86 and x86_64 platform bugs.
++ */
++#include <linux/pci.h>
++#include <linux/irq.h>
++
++#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_XEN)) && defined(CONFIG_PCI)
++
++static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
++{
++ u8 config, rev;
++ u32 word;
++
++ /* BIOS may enable hardware IRQ balancing for
++ * E7520/E7320/E7525(revision ID 0x9 and below)
++ * based platforms.
++ * Disable SW irqbalance/affinity on those platforms.
++ */
++ pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
++ if (rev > 0x9)
++ return;
++
++ printk(KERN_INFO "Intel E7520/7320/7525 detected.");
++
++ /* enable access to config space*/
++ pci_read_config_byte(dev, 0xf4, &config);
++ pci_write_config_byte(dev, 0xf4, config|0x2);
++
++ /* read xTPR register */
++ raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
++
++ if (!(word & (1 << 13))) {
++ dom0_op_t op;
++ printk(KERN_INFO "Disabling irq balancing and affinity\n");
++ op.cmd = DOM0_PLATFORM_QUIRK;
++ op.u.platform_quirk.quirk_id = QUIRK_NOIRQBALANCING;
++ (void)HYPERVISOR_dom0_op(&op);
++ }
++
++ /* put back the original value for config space*/
++ if (!(config & 0x2))
++ pci_write_config_byte(dev, 0xf4, config);
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/setup-xen.c linux-2.6.18-xen/arch/i386/kernel/setup-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/setup-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/setup-xen.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,1832 @@
++/*
++ * linux/arch/i386/kernel/setup.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ *
++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
++ *
++ * Memory region support
++ * David Parsons <orc at pell.chi.il.us>, July-August 1999
++ *
++ * Added E820 sanitization routine (removes overlapping memory regions);
++ * Brian Moyle <bmoyle at mvista.com>, February 2001
++ *
++ * Moved CPU detection code to cpu/${cpu}.c
++ * Patrick Mochel <mochel at osdl.org>, March 2002
++ *
++ * Provisions for empty E820 memory regions (reported by certain BIOSes).
++ * Alex Achenbach <xela at slit.de>, December 2002.
++ *
++ */
++
++/*
++ * This file handles the architecture-dependent parts of initialization
++ */
++
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/mmzone.h>
++#include <linux/screen_info.h>
++#include <linux/ioport.h>
++#include <linux/acpi.h>
++#include <linux/apm_bios.h>
++#include <linux/initrd.h>
++#include <linux/bootmem.h>
++#include <linux/seq_file.h>
++#include <linux/platform_device.h>
++#include <linux/console.h>
++#include <linux/mca.h>
++#include <linux/root_dev.h>
++#include <linux/highmem.h>
++#include <linux/module.h>
++#include <linux/efi.h>
++#include <linux/init.h>
++#include <linux/edd.h>
++#include <linux/nodemask.h>
++#include <linux/kexec.h>
++#include <linux/crash_dump.h>
++#include <linux/dmi.h>
++#include <linux/pfn.h>
++
++#include <video/edid.h>
++
++#include <asm/apic.h>
++#include <asm/e820.h>
++#include <asm/mpspec.h>
++#include <asm/setup.h>
++#include <asm/arch_hooks.h>
++#include <asm/sections.h>
++#include <asm/io_apic.h>
++#include <asm/ist.h>
++#include <asm/io.h>
++#include <asm/hypervisor.h>
++#include <xen/interface/physdev.h>
++#include <xen/interface/memory.h>
++#include <xen/features.h>
++#include <xen/xencons.h>
++#include "setup_arch.h"
++#include <bios_ebda.h>
++
++/* Forward Declaration. */
++void __init find_max_pfn(void);
++
++static int xen_panic_event(struct notifier_block *, unsigned long, void *);
++static struct notifier_block xen_panic_block = {
++ xen_panic_event, NULL, 0 /* try to go last */
++};
++
++extern char hypercall_page[PAGE_SIZE];
++EXPORT_SYMBOL(hypercall_page);
++
++int disable_pse __devinitdata = 0;
++
++/*
++ * Machine setup..
++ */
++
++#ifdef CONFIG_EFI
++int efi_enabled = 0;
++EXPORT_SYMBOL(efi_enabled);
++#endif
++
++/* cpu data as detected by the assembly code in head.S */
++struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
++/* common cpu data for all cpus */
++struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
++EXPORT_SYMBOL(boot_cpu_data);
++
++unsigned long mmu_cr4_features;
++
++#ifdef CONFIG_ACPI
++ int acpi_disabled = 0;
++#else
++ int acpi_disabled = 1;
++#endif
++EXPORT_SYMBOL(acpi_disabled);
++
++#ifdef CONFIG_ACPI
++int __initdata acpi_force = 0;
++extern acpi_interrupt_flags acpi_sci_flags;
++#endif
++
++/* for MCA, but anyone else can use it if they want */
++unsigned int machine_id;
++#ifdef CONFIG_MCA
++EXPORT_SYMBOL(machine_id);
++#endif
++unsigned int machine_submodel_id;
++unsigned int BIOS_revision;
++unsigned int mca_pentium_flag;
++
++/* For PCI or other memory-mapped resources */
++unsigned long pci_mem_start = 0x10000000;
++#ifdef CONFIG_PCI
++EXPORT_SYMBOL(pci_mem_start);
++#endif
++
++/* Boot loader ID as an integer, for the benefit of proc_dointvec */
++int bootloader_type;
++
++/* user-defined highmem size */
++static unsigned int highmem_pages = -1;
++
++/*
++ * Setup options
++ */
++struct drive_info_struct { char dummy[32]; } drive_info;
++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \
++ defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
++EXPORT_SYMBOL(drive_info);
++#endif
++struct screen_info screen_info;
++EXPORT_SYMBOL(screen_info);
++struct apm_info apm_info;
++EXPORT_SYMBOL(apm_info);
++struct sys_desc_table_struct {
++ unsigned short length;
++ unsigned char table[0];
++};
++struct edid_info edid_info;
++EXPORT_SYMBOL_GPL(edid_info);
++struct ist_info ist_info;
++#if defined(CONFIG_X86_SPEEDSTEP_SMI) || \
++ defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
++EXPORT_SYMBOL(ist_info);
++#endif
++struct e820map e820;
++static void __init e820_setup_gap(struct e820entry *e820, int nr_map);
++#ifdef CONFIG_XEN
++struct e820map machine_e820;
++#endif
++
++extern void early_cpu_init(void);
++extern void generic_apic_probe(char *);
++extern int root_mountflags;
++
++unsigned long saved_videomode;
++
++#define RAMDISK_IMAGE_START_MASK 0x07FF
++#define RAMDISK_PROMPT_FLAG 0x8000
++#define RAMDISK_LOAD_FLAG 0x4000
++
++static char command_line[COMMAND_LINE_SIZE];
++
++unsigned char __initdata boot_params[PARAM_SIZE];
++
++static struct resource data_resource = {
++ .name = "Kernel data",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
++};
++
++static struct resource code_resource = {
++ .name = "Kernel code",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
++};
++
++static struct resource system_rom_resource = {
++ .name = "System ROM",
++ .start = 0xf0000,
++ .end = 0xfffff,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++};
++
++static struct resource extension_rom_resource = {
++ .name = "Extension ROM",
++ .start = 0xe0000,
++ .end = 0xeffff,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++};
++
++static struct resource adapter_rom_resources[] = { {
++ .name = "Adapter ROM",
++ .start = 0xc8000,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++}, {
++ .name = "Adapter ROM",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++}, {
++ .name = "Adapter ROM",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++}, {
++ .name = "Adapter ROM",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++}, {
++ .name = "Adapter ROM",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++}, {
++ .name = "Adapter ROM",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++} };
++
++#define ADAPTER_ROM_RESOURCES \
++ (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
++
++static struct resource video_rom_resource = {
++ .name = "Video ROM",
++ .start = 0xc0000,
++ .end = 0xc7fff,
++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
++};
++
++static struct resource video_ram_resource = {
++ .name = "Video RAM area",
++ .start = 0xa0000,
++ .end = 0xbffff,
++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
++};
++
++static struct resource standard_io_resources[] = { {
++ .name = "dma1",
++ .start = 0x0000,
++ .end = 0x001f,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "pic1",
++ .start = 0x0020,
++ .end = 0x0021,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "timer0",
++ .start = 0x0040,
++ .end = 0x0043,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "timer1",
++ .start = 0x0050,
++ .end = 0x0053,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "keyboard",
++ .start = 0x0060,
++ .end = 0x006f,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "dma page reg",
++ .start = 0x0080,
++ .end = 0x008f,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "pic2",
++ .start = 0x00a0,
++ .end = 0x00a1,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "dma2",
++ .start = 0x00c0,
++ .end = 0x00df,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++}, {
++ .name = "fpu",
++ .start = 0x00f0,
++ .end = 0x00ff,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO
++} };
++
++#define STANDARD_IO_RESOURCES \
++ (sizeof standard_io_resources / sizeof standard_io_resources[0])
++
++#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
++
++static int __init romchecksum(unsigned char *rom, unsigned long length)
++{
++ unsigned char *p, sum = 0;
++
++ for (p = rom; p < rom + length; p++)
++ sum += *p;
++ return sum == 0;
++}
++
++static void __init probe_roms(void)
++{
++ unsigned long start, length, upper;
++ unsigned char *rom;
++ int i;
++
++#ifdef CONFIG_XEN
++ /* Nothing to do if not running in dom0. */
++ if (!is_initial_xendomain())
++ return;
++#endif
++
++ /* video rom */
++ upper = adapter_rom_resources[0].start;
++ for (start = video_rom_resource.start; start < upper; start += 2048) {
++ rom = isa_bus_to_virt(start);
++ if (!romsignature(rom))
++ continue;
++
++ video_rom_resource.start = start;
++
++ /* 0 < length <= 0x7f * 512, historically */
++ length = rom[2] * 512;
++
++ /* if checksum okay, trust length byte */
++ if (length && romchecksum(rom, length))
++ video_rom_resource.end = start + length - 1;
++ break;
++ }
++
++ start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
++ if (start < upper)
++ start = upper;
++
++ /* system rom */
++ request_resource(&iomem_resource, &system_rom_resource);
++ upper = system_rom_resource.start;
++
++ /* check for extension rom (ignore length byte!) */
++ rom = isa_bus_to_virt(extension_rom_resource.start);
++ if (romsignature(rom)) {
++ length = extension_rom_resource.end - extension_rom_resource.start + 1;
++ if (romchecksum(rom, length)) {
++ request_resource(&iomem_resource, &extension_rom_resource);
++ upper = extension_rom_resource.start;
++ }
++ }
++
++ /* check for adapter roms on 2k boundaries */
++ for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
++ rom = isa_bus_to_virt(start);
++ if (!romsignature(rom))
++ continue;
++
++ /* 0 < length <= 0x7f * 512, historically */
++ length = rom[2] * 512;
++
++ /* but accept any length that fits if checksum okay */
++ if (!length || start + length > upper || !romchecksum(rom, length))
++ continue;
++
++ adapter_rom_resources[i].start = start;
++ adapter_rom_resources[i].end = start + length - 1;
++ request_resource(&iomem_resource, &adapter_rom_resources[i]);
++
++ start = adapter_rom_resources[i++].end & ~2047UL;
++ }
++}
++
++/*
++ * Point at the empty zero page to start with. We map the real shared_info
++ * page as soon as fixmap is up and running.
++ */
++shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
++EXPORT_SYMBOL(HYPERVISOR_shared_info);
++
++unsigned long *phys_to_machine_mapping;
++unsigned long *pfn_to_mfn_frame_list_list, *pfn_to_mfn_frame_list[16];
++EXPORT_SYMBOL(phys_to_machine_mapping);
++
++/* Raw start-of-day parameters from the hypervisor. */
++start_info_t *xen_start_info;
++EXPORT_SYMBOL(xen_start_info);
++
++void __init add_memory_region(unsigned long long start,
++ unsigned long long size, int type)
++{
++ int x;
++
++ if (!efi_enabled) {
++ x = e820.nr_map;
++
++ if (x == E820MAX) {
++ printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
++ return;
++ }
++
++ e820.map[x].addr = start;
++ e820.map[x].size = size;
++ e820.map[x].type = type;
++ e820.nr_map++;
++ }
++} /* add_memory_region */
++
++static void __init limit_regions(unsigned long long size)
++{
++ unsigned long long current_addr = 0;
++ int i;
++
++ if (efi_enabled) {
++ efi_memory_desc_t *md;
++ void *p;
++
++ for (p = memmap.map, i = 0; p < memmap.map_end;
++ p += memmap.desc_size, i++) {
++ md = p;
++ current_addr = md->phys_addr + (md->num_pages << 12);
++ if (md->type == EFI_CONVENTIONAL_MEMORY) {
++ if (current_addr >= size) {
++ md->num_pages -=
++ (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT);
++ memmap.nr_map = i + 1;
++ return;
++ }
++ }
++ }
++ }
++ for (i = 0; i < e820.nr_map; i++) {
++ current_addr = e820.map[i].addr + e820.map[i].size;
++ if (current_addr < size)
++ continue;
++
++ if (e820.map[i].type != E820_RAM)
++ continue;
++
++ if (e820.map[i].addr >= size) {
++ /*
++ * This region starts past the end of the
++ * requested size, skip it completely.
++ */
++ e820.nr_map = i;
++ } else {
++ e820.nr_map = i + 1;
++ e820.map[i].size -= current_addr - size;
++ }
++ return;
++ }
++#ifdef CONFIG_XEN
++ if (i==e820.nr_map && current_addr < size) {
++ /*
++ * The e820 map finished before our requested size so
++ * extend the final entry to the requested address.
++ */
++ --i;
++ if (e820.map[i].type == E820_RAM)
++ e820.map[i].size -= current_addr - size;
++ else
++ add_memory_region(current_addr, size - current_addr, E820_RAM);
++ }
++#endif
++}
++
++#define E820_DEBUG 1
++
++static void __init print_memory_map(char *who)
++{
++ int i;
++
++ for (i = 0; i < e820.nr_map; i++) {
++ printk(" %s: %016Lx - %016Lx ", who,
++ e820.map[i].addr,
++ e820.map[i].addr + e820.map[i].size);
++ switch (e820.map[i].type) {
++ case E820_RAM: printk("(usable)\n");
++ break;
++ case E820_RESERVED:
++ printk("(reserved)\n");
++ break;
++ case E820_ACPI:
++ printk("(ACPI data)\n");
++ break;
++ case E820_NVS:
++ printk("(ACPI NVS)\n");
++ break;
++ default: printk("type %lu\n", e820.map[i].type);
++ break;
++ }
++ }
++}
++
++/*
++ * Sanitize the BIOS e820 map.
++ *
++ * Some e820 responses include overlapping entries. The following
++ * replaces the original e820 map with a new one, removing overlaps.
++ *
++ */
++struct change_member {
++ struct e820entry *pbios; /* pointer to original bios entry */
++ unsigned long long addr; /* address for this change point */
++};
++static struct change_member change_point_list[2*E820MAX] __initdata;
++static struct change_member *change_point[2*E820MAX] __initdata;
++static struct e820entry *overlap_list[E820MAX] __initdata;
++static struct e820entry new_bios[E820MAX] __initdata;
++
++int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
++{
++ struct change_member *change_tmp;
++ unsigned long current_type, last_type;
++ unsigned long long last_addr;
++ int chgidx, still_changing;
++ int overlap_entries;
++ int new_bios_entry;
++ int old_nr, new_nr, chg_nr;
++ int i;
++
++ /*
++ Visually we're performing the following (1,2,3,4 = memory types)...
++
++ Sample memory map (w/overlaps):
++ ____22__________________
++ ______________________4_
++ ____1111________________
++ _44_____________________
++ 11111111________________
++ ____________________33__
++ ___________44___________
++ __________33333_________
++ ______________22________
++ ___________________2222_
++ _________111111111______
++ _____________________11_
++ _________________4______
++
++ Sanitized equivalent (no overlap):
++ 1_______________________
++ _44_____________________
++ ___1____________________
++ ____22__________________
++ ______11________________
++ _________1______________
++ __________3_____________
++ ___________44___________
++ _____________33_________
++ _______________2________
++ ________________1_______
++ _________________4______
++ ___________________2____
++ ____________________33__
++ ______________________4_
++ */
++
++ /* if there's only one memory region, don't bother */
++ if (*pnr_map < 2)
++ return -1;
++
++ old_nr = *pnr_map;
++
++ /* bail out if we find any unreasonable addresses in bios map */
++ for (i=0; i<old_nr; i++)
++ if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
++ return -1;
++
++ /* create pointers for initial change-point information (for sorting) */
++ for (i=0; i < 2*old_nr; i++)
++ change_point[i] = &change_point_list[i];
++
++ /* record all known change-points (starting and ending addresses),
++ omitting those that are for empty memory regions */
++ chgidx = 0;
++ for (i=0; i < old_nr; i++) {
++ if (biosmap[i].size != 0) {
++ change_point[chgidx]->addr = biosmap[i].addr;
++ change_point[chgidx++]->pbios = &biosmap[i];
++ change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
++ change_point[chgidx++]->pbios = &biosmap[i];
++ }
++ }
++ chg_nr = chgidx; /* true number of change-points */
++
++ /* sort change-point list by memory addresses (low -> high) */
++ still_changing = 1;
++ while (still_changing) {
++ still_changing = 0;
++ for (i=1; i < chg_nr; i++) {
++ /* if <current_addr> > <last_addr>, swap */
++ /* or, if current=<start_addr> & last=<end_addr>, swap */
++ if ((change_point[i]->addr < change_point[i-1]->addr) ||
++ ((change_point[i]->addr == change_point[i-1]->addr) &&
++ (change_point[i]->addr == change_point[i]->pbios->addr) &&
++ (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
++ )
++ {
++ change_tmp = change_point[i];
++ change_point[i] = change_point[i-1];
++ change_point[i-1] = change_tmp;
++ still_changing=1;
++ }
++ }
++ }
++
++ /* create a new bios memory map, removing overlaps */
++ overlap_entries=0; /* number of entries in the overlap table */
++ new_bios_entry=0; /* index for creating new bios map entries */
++ last_type = 0; /* start with undefined memory type */
++ last_addr = 0; /* start with 0 as last starting address */
++ /* loop through change-points, determining affect on the new bios map */
++ for (chgidx=0; chgidx < chg_nr; chgidx++)
++ {
++ /* keep track of all overlapping bios entries */
++ if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
++ {
++ /* add map entry to overlap list (> 1 entry implies an overlap) */
++ overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
++ }
++ else
++ {
++ /* remove entry from list (order independent, so swap with last) */
++ for (i=0; i<overlap_entries; i++)
++ {
++ if (overlap_list[i] == change_point[chgidx]->pbios)
++ overlap_list[i] = overlap_list[overlap_entries-1];
++ }
++ overlap_entries--;
++ }
++ /* if there are overlapping entries, decide which "type" to use */
++ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
++ current_type = 0;
++ for (i=0; i<overlap_entries; i++)
++ if (overlap_list[i]->type > current_type)
++ current_type = overlap_list[i]->type;
++ /* continue building up new bios map based on this information */
++ if (current_type != last_type) {
++ if (last_type != 0) {
++ new_bios[new_bios_entry].size =
++ change_point[chgidx]->addr - last_addr;
++ /* move forward only if the new size was non-zero */
++ if (new_bios[new_bios_entry].size != 0)
++ if (++new_bios_entry >= E820MAX)
++ break; /* no more space left for new bios entries */
++ }
++ if (current_type != 0) {
++ new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
++ new_bios[new_bios_entry].type = current_type;
++ last_addr=change_point[chgidx]->addr;
++ }
++ last_type = current_type;
++ }
++ }
++ new_nr = new_bios_entry; /* retain count for new bios entries */
++
++ /* copy new bios mapping into original location */
++ memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
++ *pnr_map = new_nr;
++
++ return 0;
++}
++
++/*
++ * Copy the BIOS e820 map into a safe place.
++ *
++ * Sanity-check it while we're at it..
++ *
++ * If we're lucky and live on a modern system, the setup code
++ * will have given us a memory map that we can use to properly
++ * set up memory. If we aren't, we'll fake a memory map.
++ *
++ * We check to see that the memory map contains at least 2 elements
++ * before we'll use it, because the detection code in setup.S may
++ * not be perfect and most every PC known to man has two memory
++ * regions: one from 0 to 640k, and one from 1mb up. (The IBM
++ * thinkpad 560x, for example, does not cooperate with the memory
++ * detection code.)
++ */
++int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
++{
++#ifndef CONFIG_XEN
++ /* Only one memory region (or negative)? Ignore it */
++ if (nr_map < 2)
++ return -1;
++#else
++ BUG_ON(nr_map < 1);
++#endif
++
++ do {
++ unsigned long long start = biosmap->addr;
++ unsigned long long size = biosmap->size;
++ unsigned long long end = start + size;
++ unsigned long type = biosmap->type;
++
++ /* Overflow in 64 bits? Ignore the memory map. */
++ if (start > end)
++ return -1;
++
++#ifndef CONFIG_XEN
++ /*
++ * Some BIOSes claim RAM in the 640k - 1M region.
++ * Not right. Fix it up.
++ */
++ if (type == E820_RAM) {
++ if (start < 0x100000ULL && end > 0xA0000ULL) {
++ if (start < 0xA0000ULL)
++ add_memory_region(start, 0xA0000ULL-start, type);
++ if (end <= 0x100000ULL)
++ continue;
++ start = 0x100000ULL;
++ size = end - start;
++ }
++ }
++#endif
++ add_memory_region(start, size, type);
++ } while (biosmap++,--nr_map);
++ return 0;
++}
++
++#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
++struct edd edd;
++#ifdef CONFIG_EDD_MODULE
++EXPORT_SYMBOL(edd);
++#endif
++/**
++ * copy_edd() - Copy the BIOS EDD information
++ * from boot_params into a safe place.
++ *
++ */
++static inline void copy_edd(void)
++{
++ memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature));
++ memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info));
++ edd.mbr_signature_nr = EDD_MBR_SIG_NR;
++ edd.edd_info_nr = EDD_NR;
++}
++#else
++static inline void copy_edd(void)
++{
++}
++#endif
++
++static void __init parse_cmdline_early (char ** cmdline_p)
++{
++ char c = ' ', *to = command_line, *from = saved_command_line;
++ int len = 0, max_cmdline;
++ int userdef = 0;
++
++ if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE)
++ max_cmdline = COMMAND_LINE_SIZE;
++ memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline);
++ /* Save unparsed command line copy for /proc/cmdline */
++ saved_command_line[max_cmdline-1] = '\0';
++
++ for (;;) {
++ if (c != ' ')
++ goto next_char;
++ /*
++ * "mem=nopentium" disables the 4MB page tables.
++ * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
++ * to <mem>, overriding the bios size.
++ * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from
++ * <start> to <start>+<mem>, overriding the bios size.
++ *
++ * HPA tells me bootloaders need to parse mem=, so no new
++ * option should be mem= [also see Documentation/i386/boot.txt]
++ */
++ if (!memcmp(from, "mem=", 4)) {
++ if (to != command_line)
++ to--;
++ if (!memcmp(from+4, "nopentium", 9)) {
++ from += 9+4;
++ clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
++ disable_pse = 1;
++ } else {
++ /* If the user specifies memory size, we
++ * limit the BIOS-provided memory map to
++ * that size. exactmap can be used to specify
++ * the exact map. mem=number can be used to
++ * trim the existing memory map.
++ */
++ unsigned long long mem_size;
++
++ mem_size = memparse(from+4, &from);
++ limit_regions(mem_size);
++ userdef=1;
++ }
++ }
++
++ else if (!memcmp(from, "memmap=", 7)) {
++ 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;
++ } else {
++ /* If the user specifies memory size, we
++ * limit the BIOS-provided memory map to
++ * that size. exactmap can be used to specify
++ * the exact map. mem=number can be used to
++ * trim the existing memory map.
++ */
++ unsigned long long start_at, mem_size;
++
++ mem_size = memparse(from+7, &from);
++ if (*from == '@') {
++ start_at = memparse(from+1, &from);
++ add_memory_region(start_at, mem_size, E820_RAM);
++ } else if (*from == '#') {
++ start_at = memparse(from+1, &from);
++ add_memory_region(start_at, mem_size, E820_ACPI);
++ } else if (*from == '$') {
++ start_at = memparse(from+1, &from);
++ add_memory_region(start_at, mem_size, E820_RESERVED);
++ } else {
++ limit_regions(mem_size);
++ userdef=1;
++ }
++ }
++ }
++
++ else if (!memcmp(from, "noexec=", 7))
++ noexec_setup(from + 7);
++
++
++#ifdef CONFIG_X86_MPPARSE
++ /*
++ * If the BIOS enumerates physical processors before logical,
++ * maxcpus=N at enumeration-time can be used to disable HT.
++ */
++ else if (!memcmp(from, "maxcpus=", 8)) {
++ extern unsigned int maxcpus;
++
++ maxcpus = simple_strtoul(from + 8, NULL, 0);
++ }
++#endif
++
++#ifdef CONFIG_ACPI
++ /* "acpi=off" disables both ACPI table parsing and interpreter */
++ else if (!memcmp(from, "acpi=off", 8)) {
++ disable_acpi();
++ }
++
++ /* acpi=force to over-ride black-list */
++ else if (!memcmp(from, "acpi=force", 10)) {
++ acpi_force = 1;
++ acpi_ht = 1;
++ acpi_disabled = 0;
++ }
++
++ /* acpi=strict disables out-of-spec workarounds */
++ else if (!memcmp(from, "acpi=strict", 11)) {
++ acpi_strict = 1;
++ }
++
++ /* Limit ACPI just to boot-time to enable HT */
++ else if (!memcmp(from, "acpi=ht", 7)) {
++ if (!acpi_force)
++ disable_acpi();
++ acpi_ht = 1;
++ }
++
++ /* "pci=noacpi" disable ACPI IRQ routing and PCI scan */
++ else if (!memcmp(from, "pci=noacpi", 10)) {
++ acpi_disable_pci();
++ }
++ /* "acpi=noirq" disables ACPI interrupt routing */
++ else if (!memcmp(from, "acpi=noirq", 10)) {
++ acpi_noirq_set();
++ }
++
++ else if (!memcmp(from, "acpi_sci=edge", 13))
++ acpi_sci_flags.trigger = 1;
++
++ else if (!memcmp(from, "acpi_sci=level", 14))
++ acpi_sci_flags.trigger = 3;
++
++ else if (!memcmp(from, "acpi_sci=high", 13))
++ acpi_sci_flags.polarity = 1;
++
++ else if (!memcmp(from, "acpi_sci=low", 12))
++ acpi_sci_flags.polarity = 3;
++
++#ifdef CONFIG_X86_IO_APIC
++ else if (!memcmp(from, "acpi_skip_timer_override", 24))
++ acpi_skip_timer_override = 1;
++
++ if (!memcmp(from, "disable_timer_pin_1", 19))
++ disable_timer_pin_1 = 1;
++ if (!memcmp(from, "enable_timer_pin_1", 18))
++ disable_timer_pin_1 = -1;
++
++ /* disable IO-APIC */
++ else if (!memcmp(from, "noapic", 6))
++ disable_ioapic_setup();
++#endif /* CONFIG_X86_IO_APIC */
++#endif /* CONFIG_ACPI */
++
++#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 at 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_PROC_VMCORE
++ /* 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.
++ * This also works to reduce highmem size on bigger boxes.
++ */
++ else if (!memcmp(from, "highmem=", 8))
++ highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
++
++ /*
++ * vmalloc=size forces the vmalloc area to be exactly 'size'
++ * bytes. This can be used to increase (or decrease) the
++ * vmalloc area - the default is 128m.
++ */
++ else if (!memcmp(from, "vmalloc=", 8))
++ __VMALLOC_RESERVE = memparse(from+8, &from);
++
++ next_char:
++ c = *(from++);
++ if (!c)
++ break;
++ if (COMMAND_LINE_SIZE <= ++len)
++ break;
++ *(to++) = c;
++ }
++ *to = '\0';
++ *cmdline_p = command_line;
++ if (userdef) {
++ printk(KERN_INFO "user-defined physical RAM map:\n");
++ print_memory_map("user");
++ }
++}
++
++/*
++ * Callback for efi_memory_walk.
++ */
++static int __init
++efi_find_max_pfn(unsigned long start, unsigned long end, void *arg)
++{
++ unsigned long *max_pfn = arg, pfn;
++
++ if (start < end) {
++ pfn = PFN_UP(end -1);
++ if (pfn > *max_pfn)
++ *max_pfn = pfn;
++ }
++ return 0;
++}
++
++static int __init
++efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg)
++{
++ memory_present(0, start, end);
++ return 0;
++}
++
++ /*
++ * This function checks if the entire range <start,end> is mapped with type.
++ *
++ * Note: this function only works correct if the e820 table is sorted and
++ * not-overlapping, which is the case
++ */
++int __init
++e820_all_mapped(unsigned long s, unsigned long e, unsigned type)
++{
++ u64 start = s;
++ u64 end = e;
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ if (type && ei->type != type)
++ continue;
++ /* is the region (part) in overlap with the current region ?*/
++ if (ei->addr >= end || ei->addr + ei->size <= start)
++ continue;
++ /* if the region is at the beginning of <start,end> we move
++ * start to the end of the region since it's ok until there
++ */
++ if (ei->addr <= start)
++ start = ei->addr + ei->size;
++ /* if start is now at or beyond end, we're done, full
++ * coverage */
++ if (start >= end)
++ return 1; /* we're done */
++ }
++ return 0;
++}
++
++/*
++ * Find the highest page frame number we have available
++ */
++void __init find_max_pfn(void)
++{
++ int i;
++
++ max_pfn = 0;
++ if (efi_enabled) {
++ efi_memmap_walk(efi_find_max_pfn, &max_pfn);
++ efi_memmap_walk(efi_memory_present_wrapper, NULL);
++ return;
++ }
++
++ for (i = 0; i < e820.nr_map; i++) {
++ unsigned long start, end;
++ /* RAM? */
++ if (e820.map[i].type != E820_RAM)
++ continue;
++ start = PFN_UP(e820.map[i].addr);
++ end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
++ if (start >= end)
++ continue;
++ if (end > max_pfn)
++ max_pfn = end;
++ memory_present(0, start, end);
++ }
++}
++
++/*
++ * Determine low and high memory ranges:
++ */
++unsigned long __init find_max_low_pfn(void)
++{
++ unsigned long max_low_pfn;
++
++ max_low_pfn = max_pfn;
++ if (max_low_pfn > MAXMEM_PFN) {
++ if (highmem_pages == -1)
++ highmem_pages = max_pfn - MAXMEM_PFN;
++ if (highmem_pages + MAXMEM_PFN < max_pfn)
++ max_pfn = MAXMEM_PFN + highmem_pages;
++ if (highmem_pages + MAXMEM_PFN > max_pfn) {
++ printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages));
++ highmem_pages = 0;
++ }
++ max_low_pfn = MAXMEM_PFN;
++#ifndef CONFIG_HIGHMEM
++ /* Maximum memory usable is what is directly addressable */
++ printk(KERN_WARNING "Warning only %ldMB will be used.\n",
++ MAXMEM>>20);
++ if (max_pfn > MAX_NONPAE_PFN)
++ printk(KERN_WARNING "Use a PAE enabled kernel.\n");
++ else
++ printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
++ max_pfn = MAXMEM_PFN;
++#else /* !CONFIG_HIGHMEM */
++#ifndef CONFIG_X86_PAE
++ if (max_pfn > MAX_NONPAE_PFN) {
++ max_pfn = MAX_NONPAE_PFN;
++ printk(KERN_WARNING "Warning only 4GB will be used.\n");
++ printk(KERN_WARNING "Use a PAE enabled kernel.\n");
++ }
++#endif /* !CONFIG_X86_PAE */
++#endif /* !CONFIG_HIGHMEM */
++ } else {
++ if (highmem_pages == -1)
++ highmem_pages = 0;
++#ifdef CONFIG_HIGHMEM
++ if (highmem_pages >= max_pfn) {
++ printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
++ highmem_pages = 0;
++ }
++ if (highmem_pages) {
++ if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){
++ printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages));
++ highmem_pages = 0;
++ }
++ max_low_pfn -= highmem_pages;
++ }
++#else
++ if (highmem_pages)
++ printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n");
++#endif
++ }
++ return max_low_pfn;
++}
++
++/*
++ * Free all available memory for boot time allocation. Used
++ * as a callback function by efi_memory_walk()
++ */
++
++static int __init
++free_available_memory(unsigned long start, unsigned long end, void *arg)
++{
++ /* check max_low_pfn */
++ if (start >= (max_low_pfn << PAGE_SHIFT))
++ return 0;
++ if (end >= (max_low_pfn << PAGE_SHIFT))
++ end = max_low_pfn << PAGE_SHIFT;
++ if (start < end)
++ free_bootmem(start, end - start);
++
++ return 0;
++}
++/*
++ * Register fully available low RAM pages with the bootmem allocator.
++ */
++static void __init register_bootmem_low_pages(unsigned long max_low_pfn)
++{
++ int i;
++
++ if (efi_enabled) {
++ efi_memmap_walk(free_available_memory, NULL);
++ return;
++ }
++ for (i = 0; i < e820.nr_map; i++) {
++ unsigned long curr_pfn, last_pfn, size;
++ /*
++ * Reserve usable low memory
++ */
++ if (e820.map[i].type != E820_RAM)
++ continue;
++ /*
++ * We are rounding up the start address of usable memory:
++ */
++ curr_pfn = PFN_UP(e820.map[i].addr);
++ if (curr_pfn >= max_low_pfn)
++ continue;
++ /*
++ * ... and at the end of the usable range downwards:
++ */
++ last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
++
++#ifdef CONFIG_XEN
++ /*
++ * Truncate to the number of actual pages currently
++ * present.
++ */
++ if (last_pfn > xen_start_info->nr_pages)
++ last_pfn = xen_start_info->nr_pages;
++#endif
++
++ if (last_pfn > max_low_pfn)
++ last_pfn = max_low_pfn;
++
++ /*
++ * .. finally, did all the rounding and playing
++ * around just make the area go away?
++ */
++ if (last_pfn <= curr_pfn)
++ continue;
++
++ size = last_pfn - curr_pfn;
++ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
++ }
++}
++
++#ifndef CONFIG_XEN
++/*
++ * workaround for Dell systems that neglect to reserve EBDA
++ */
++static void __init reserve_ebda_region(void)
++{
++ unsigned int addr;
++ addr = get_bios_ebda();
++ if (addr)
++ reserve_bootmem(addr, PAGE_SIZE);
++}
++#endif
++
++#ifndef CONFIG_NEED_MULTIPLE_NODES
++void __init setup_bootmem_allocator(void);
++static unsigned long __init setup_memory(void)
++{
++ /*
++ * partially used pages are not usable - thus
++ * we are rounding upwards:
++ */
++ min_low_pfn = PFN_UP(__pa(xen_start_info->pt_base)) +
++ xen_start_info->nr_pt_frames;
++
++ find_max_pfn();
++
++ max_low_pfn = find_max_low_pfn();
++
++#ifdef CONFIG_HIGHMEM
++ highstart_pfn = highend_pfn = max_pfn;
++ if (max_pfn > max_low_pfn) {
++ highstart_pfn = max_low_pfn;
++ }
++ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
++ pages_to_mb(highend_pfn - highstart_pfn));
++#endif
++ printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
++ pages_to_mb(max_low_pfn));
++
++ setup_bootmem_allocator();
++
++ return max_low_pfn;
++}
++
++void __init zone_sizes_init(void)
++{
++ unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
++ unsigned int max_dma, low;
++
++ /*
++ * XEN: Our notion of "DMA memory" is fake when running over Xen.
++ * We simply put all RAM in the DMA zone so that those drivers which
++ * needlessly specify GFP_DMA do not get starved of RAM unnecessarily.
++ * Those drivers that *do* require lowmem are screwed anyway when
++ * running over Xen!
++ */
++ max_dma = max_low_pfn;
++ low = max_low_pfn;
++
++ if (low < max_dma)
++ zones_size[ZONE_DMA] = low;
++ else {
++ zones_size[ZONE_DMA] = max_dma;
++ zones_size[ZONE_NORMAL] = low - max_dma;
++#ifdef CONFIG_HIGHMEM
++ zones_size[ZONE_HIGHMEM] = highend_pfn - low;
++#endif
++ }
++ free_area_init(zones_size);
++}
++#else
++extern unsigned long __init setup_memory(void);
++extern void zone_sizes_init(void);
++#endif /* !CONFIG_NEED_MULTIPLE_NODES */
++
++void __init setup_bootmem_allocator(void)
++{
++ unsigned long bootmap_size;
++ /*
++ * Initialize the boot-time allocator (with low memory only):
++ */
++ bootmap_size = init_bootmem(min_low_pfn, max_low_pfn);
++
++ register_bootmem_low_pages(max_low_pfn);
++
++ /*
++ * Reserve the bootmem bitmap itself as well. We do this in two
++ * steps (first step was init_bootmem()) because this catches
++ * the (very unlikely) case of us accidentally initializing the
++ * bootmem allocator with an invalid RAM area.
++ */
++ reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) +
++ bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START));
++
++#ifndef CONFIG_XEN
++ /*
++ * reserve physical page 0 - it's a special BIOS page on many boxes,
++ * enabling clean reboots, SMP operation, laptop functions.
++ */
++ reserve_bootmem(0, PAGE_SIZE);
++
++ /* reserve EBDA region, it's a 4K region */
++ reserve_ebda_region();
++
++ /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent
++ PCI prefetch into it (errata #56). Usually the page is reserved anyways,
++ unless you have no PS/2 mouse plugged in. */
++ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
++ boot_cpu_data.x86 == 6)
++ reserve_bootmem(0xa0000 - 4096, 4096);
++
++#ifdef CONFIG_SMP
++ /*
++ * But first pinch a few for the stack/trampoline stuff
++ * FIXME: Don't need the extra page at 4K, but need to fix
++ * trampoline before removing it. (see the GDT stuff)
++ */
++ reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
++#endif
++#ifdef CONFIG_ACPI_SLEEP
++ /*
++ * Reserve low memory region for sleep support.
++ */
++ acpi_reserve_bootmem();
++#endif
++#endif /* !CONFIG_XEN */
++
++#ifdef CONFIG_BLK_DEV_INITRD
++ if (xen_start_info->mod_start) {
++ if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
++ /*reserve_bootmem(INITRD_START, INITRD_SIZE);*/
++ initrd_start = INITRD_START + PAGE_OFFSET;
++ initrd_end = initrd_start+INITRD_SIZE;
++ initrd_below_start_ok = 1;
++ }
++ else {
++ printk(KERN_ERR "initrd extends beyond end of memory "
++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
++ INITRD_START + INITRD_SIZE,
++ max_low_pfn << PAGE_SHIFT);
++ initrd_start = 0;
++ }
++ }
++#endif
++#ifdef CONFIG_KEXEC
++ if (crashk_res.start != crashk_res.end)
++ reserve_bootmem(crashk_res.start,
++ crashk_res.end - crashk_res.start + 1);
++#endif
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap))
++ phys_to_machine_mapping =
++ (unsigned long *)xen_start_info->mfn_list;
++}
++
++/*
++ * The node 0 pgdat is initialized before all of these because
++ * it's needed for bootmem. node>0 pgdats have their virtual
++ * space allocated before the pagetables are in place to access
++ * them, so they can't be cleared then.
++ *
++ * This should all compile down to nothing when NUMA is off.
++ */
++void __init remapped_pgdat_init(void)
++{
++ int nid;
++
++ for_each_online_node(nid) {
++ if (nid != 0)
++ memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
++ }
++}
++
++/*
++ * Request address space for all standard RAM and ROM resources
++ * and also for regions reported as reserved by the e820.
++ */
++static void __init
++legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource)
++{
++ int i;
++ struct e820entry *map = e820.map;
++ int nr_map = e820.nr_map;
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++ struct xen_memory_map memmap;
++
++ map = machine_e820.map;
++ memmap.nr_entries = E820MAX;
++
++ set_xen_guest_handle(memmap.buffer, map);
++
++ if(HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
++ BUG();
++ machine_e820.nr_map = memmap.nr_entries;
++ nr_map = memmap.nr_entries;
++ e820_setup_gap(map, memmap.nr_entries);
++#endif
++
++ probe_roms();
++
++ for (i = 0; i < nr_map; i++) {
++ struct resource *res;
++ if (map[i].addr + map[i].size > 0x100000000ULL)
++ continue;
++ res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
++ switch (map[i].type) {
++ case E820_RAM: res->name = "System RAM"; break;
++ case E820_ACPI: res->name = "ACPI Tables"; break;
++ case E820_NVS: res->name = "ACPI Non-volatile Storage"; break;
++ default: res->name = "reserved";
++ }
++ res->start = map[i].addr;
++ res->end = res->start + map[i].size - 1;
++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++ if (request_resource(&iomem_resource, res)) {
++ kfree(res);
++ continue;
++ }
++ if (map[i].type == E820_RAM) {
++ /*
++ * We don't know which RAM region contains kernel data,
++ * so we try it repeatedly and let the resource manager
++ * test it.
++ */
++#ifndef CONFIG_XEN
++ request_resource(res, code_resource);
++ request_resource(res, data_resource);
++#endif
++#ifdef CONFIG_KEXEC
++ request_resource(res, &crashk_res);
++#endif
++ }
++ }
++}
++
++/*
++ * Request address space for all standard resources
++ *
++ * This is called just before pcibios_init(), which is also a
++ * subsys_initcall, but is linked in later (in arch/i386/pci/common.c).
++ */
++static int __init request_standard_resources(void)
++{
++ int i;
++
++ /* Nothing to do if not running in dom0. */
++ if (!is_initial_xendomain())
++ return 0;
++
++ printk("Setting up standard PCI resources\n");
++ if (efi_enabled)
++ efi_initialize_iomem_resources(&code_resource, &data_resource);
++ else
++ legacy_init_iomem_resources(&code_resource, &data_resource);
++
++ /* EFI systems may still have VGA */
++ request_resource(&iomem_resource, &video_ram_resource);
++
++ /* request I/O space for devices used on all i[345]86 PCs */
++ for (i = 0; i < STANDARD_IO_RESOURCES; i++)
++ request_resource(&ioport_resource, &standard_io_resources[i]);
++ return 0;
++}
++
++subsys_initcall(request_standard_resources);
++
++/*
++ * Locate a unused range of the physical address space below 4G which
++ * can be used for PCI mappings.
++ */
++static void __init
++e820_setup_gap(struct e820entry *e820, int nr_map)
++{
++ unsigned long gapstart, gapsize, round;
++ unsigned long long last;
++ int i;
++
++ /*
++ * Search for the bigest gap in the low 32 bits of the e820
++ * memory space.
++ */
++ last = 0x100000000ull;
++ gapstart = 0x10000000;
++ gapsize = 0x400000;
++ i = nr_map;
++ while (--i >= 0) {
++ unsigned long long start = e820[i].addr;
++ unsigned long long end = start + e820[i].size;
++
++ /*
++ * Since "last" is at most 4GB, we know we'll
++ * fit in 32 bits if this condition is true
++ */
++ if (last > end) {
++ unsigned long gap = last - end;
++
++ if (gap > gapsize) {
++ gapsize = gap;
++ gapstart = end;
++ }
++ }
++ if (start < last)
++ last = start;
++ }
++
++ /*
++ * See how much we want to round up: start off with
++ * rounding to the next 1MB area.
++ */
++ round = 0x100000;
++ while ((gapsize >> 4) > round)
++ round += round;
++ /* Fun with two's complement */
++ pci_mem_start = (gapstart + round) & -round;
++
++ printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n",
++ pci_mem_start, gapstart, gapsize);
++}
++
++static void __init register_memory(void)
++{
++#ifndef CONFIG_XEN
++ e820_setup_gap(e820.map, e820.nr_map);
++#endif
++}
++
++#ifdef CONFIG_MCA
++static void set_mca_bus(int x)
++{
++ MCA_bus = x;
++}
++#else
++static void set_mca_bus(int x) { }
++#endif
++
++/*
++ * Determine if we were loaded by an EFI loader. If so, then we have also been
++ * passed the efi memmap, systab, etc., so we should use these data structures
++ * for initialization. Note, the efi init code path is determined by the
++ * global efi_enabled. This allows the same kernel image to be used on existing
++ * systems (with a traditional BIOS) as well as on EFI systems.
++ */
++void __init setup_arch(char **cmdline_p)
++{
++ int i, j, k, fpp;
++ struct physdev_set_iopl set_iopl;
++ unsigned long max_low_pfn;
++
++ /* Force a quick death if the kernel panics (not domain 0). */
++ extern int panic_timeout;
++ if (!panic_timeout && !is_initial_xendomain())
++ panic_timeout = 1;
++
++ /* Register a call for panic conditions. */
++ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
++
++ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
++ HYPERVISOR_vm_assist(VMASST_CMD_enable,
++ VMASST_TYPE_writable_pagetables);
++
++ memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
++ pre_setup_arch_hook();
++ early_cpu_init();
++
++ /*
++ * FIXME: This isn't an official loader_type right
++ * now but does currently work with elilo.
++ * If we were configured as an EFI kernel, check to make
++ * sure that we were loaded correctly from elilo and that
++ * the system table is valid. If not, then initialize normally.
++ */
++#ifdef CONFIG_EFI
++ if ((LOADER_TYPE == 0x50) && EFI_SYSTAB)
++ efi_enabled = 1;
++#endif
++
++ /* This must be initialized to UNNAMED_MAJOR for ipconfig to work
++ properly. Setting ROOT_DEV to default to /dev/ram0 breaks initrd.
++ */
++ ROOT_DEV = MKDEV(UNNAMED_MAJOR,0);
++ drive_info = DRIVE_INFO;
++ screen_info = SCREEN_INFO;
++ edid_info = EDID_INFO;
++ apm_info.bios = APM_BIOS_INFO;
++ ist_info = IST_INFO;
++ saved_videomode = VIDEO_MODE;
++ if( SYS_DESC_TABLE.length != 0 ) {
++ set_mca_bus(SYS_DESC_TABLE.table[3] & 0x2);
++ machine_id = SYS_DESC_TABLE.table[0];
++ machine_submodel_id = SYS_DESC_TABLE.table[1];
++ BIOS_revision = SYS_DESC_TABLE.table[2];
++ }
++ bootloader_type = LOADER_TYPE;
++
++ if (is_initial_xendomain()) {
++ /* This is drawn from a dump from vgacon:startup in
++ * standard Linux. */
++ screen_info.orig_video_mode = 3;
++ screen_info.orig_video_isVGA = 1;
++ screen_info.orig_video_lines = 25;
++ screen_info.orig_video_cols = 80;
++ screen_info.orig_video_ega_bx = 3;
++ screen_info.orig_video_points = 16;
++ screen_info.orig_y = screen_info.orig_video_lines - 1;
++ if (xen_start_info->console.dom0.info_size >=
++ sizeof(struct dom0_vga_console_info)) {
++ const struct dom0_vga_console_info *info =
++ (struct dom0_vga_console_info *)(
++ (char *)xen_start_info +
++ xen_start_info->console.dom0.info_off);
++ dom0_init_screen_info(info);
++ }
++ xen_start_info->console.domU.mfn = 0;
++ xen_start_info->console.domU.evtchn = 0;
++ } else
++ screen_info.orig_video_isVGA = 0;
++
++#ifdef CONFIG_BLK_DEV_RAM
++ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
++ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
++ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
++#endif
++
++ setup_xen_features();
++
++ ARCH_SETUP
++ if (efi_enabled)
++ efi_init();
++ else {
++ printk(KERN_INFO "BIOS-provided physical RAM map:\n");
++ print_memory_map(machine_specific_memory_setup());
++ }
++
++ copy_edd();
++
++ if (!MOUNT_ROOT_RDONLY)
++ root_mountflags &= ~MS_RDONLY;
++ init_mm.start_code = (unsigned long) _text;
++ init_mm.end_code = (unsigned long) _etext;
++ init_mm.end_data = (unsigned long) _edata;
++ init_mm.brk = (PFN_UP(__pa(xen_start_info->pt_base)) +
++ xen_start_info->nr_pt_frames) << PAGE_SHIFT;
++
++ code_resource.start = virt_to_phys(_text);
++ code_resource.end = virt_to_phys(_etext)-1;
++ data_resource.start = virt_to_phys(_etext);
++ data_resource.end = virt_to_phys(_edata)-1;
++
++ parse_cmdline_early(cmdline_p);
++
++#ifdef CONFIG_EARLY_PRINTK
++ {
++ char *s = strstr(*cmdline_p, "earlyprintk=");
++ if (s) {
++ setup_early_printk(strchr(s, '=') + 1);
++ printk("early console enabled\n");
++ }
++ }
++#endif
++
++ max_low_pfn = setup_memory();
++
++ /*
++ * NOTE: before this point _nobody_ is allowed to allocate
++ * any memory using the bootmem allocator. Although the
++ * alloctor is now initialised only the first 8Mb of the kernel
++ * virtual address space has been mapped. All allocations before
++ * paging_init() has completed must use the alloc_bootmem_low_pages()
++ * variant (which allocates DMA'able memory) and care must be taken
++ * not to exceed the 8Mb limit.
++ */
++
++#ifdef CONFIG_SMP
++ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
++#endif
++ paging_init();
++ remapped_pgdat_init();
++ sparse_init();
++ zone_sizes_init();
++
++#ifdef CONFIG_X86_FIND_SMP_CONFIG
++ /*
++ * Find and reserve possible boot-time SMP configuration:
++ */
++ find_smp_config();
++#endif
++
++ /* Make sure we have a correctly sized P->M table. */
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ phys_to_machine_mapping = alloc_bootmem_low_pages(
++ max_pfn * sizeof(unsigned long));
++ memset(phys_to_machine_mapping, ~0,
++ max_pfn * sizeof(unsigned long));
++ memcpy(phys_to_machine_mapping,
++ (unsigned long *)xen_start_info->mfn_list,
++ xen_start_info->nr_pages * sizeof(unsigned long));
++ free_bootmem(
++ __pa(xen_start_info->mfn_list),
++ PFN_PHYS(PFN_UP(xen_start_info->nr_pages *
++ sizeof(unsigned long))));
++
++ /*
++ * Initialise the list of the frames that specify the list of
++ * frames that make up the p2m table. Used by save/restore
++ */
++ pfn_to_mfn_frame_list_list = alloc_bootmem_low_pages(PAGE_SIZE);
++ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
++ virt_to_mfn(pfn_to_mfn_frame_list_list);
++
++ fpp = PAGE_SIZE/sizeof(unsigned long);
++ for (i=0, j=0, k=-1; i< max_pfn; i+=fpp, j++) {
++ if ((j % fpp) == 0) {
++ k++;
++ BUG_ON(k>=16);
++ pfn_to_mfn_frame_list[k] =
++ alloc_bootmem_low_pages(PAGE_SIZE);
++ pfn_to_mfn_frame_list_list[k] =
++ virt_to_mfn(pfn_to_mfn_frame_list[k]);
++ j=0;
++ }
++ pfn_to_mfn_frame_list[k][j] =
++ virt_to_mfn(&phys_to_machine_mapping[i]);
++ }
++ HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
++ }
++
++ /*
++ * NOTE: at this point the bootmem allocator is fully available.
++ */
++
++ if (is_initial_xendomain())
++ dmi_scan_machine();
++
++#ifdef CONFIG_X86_GENERICARCH
++ generic_apic_probe(*cmdline_p);
++#endif
++ if (efi_enabled)
++ efi_map_memmap();
++
++ set_iopl.iopl = 1;
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++
++#ifdef CONFIG_ACPI
++ if (!is_initial_xendomain()) {
++ printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
++ acpi_disabled = 1;
++ acpi_ht = 0;
++ }
++
++ /*
++ * Parse the ACPI tables for possible boot-time SMP configuration.
++ */
++ acpi_boot_table_init();
++#endif
++
++#ifdef CONFIG_X86_IO_APIC
++ check_acpi_pci(); /* Checks more than just ACPI actually */
++#endif
++
++#ifdef CONFIG_ACPI
++ acpi_boot_init();
++
++#if defined(CONFIG_SMP) && defined(CONFIG_X86_PC)
++ if (def_to_bigsmp)
++ printk(KERN_WARNING "More than 8 CPUs detected and "
++ "CONFIG_X86_PC cannot handle it.\nUse "
++ "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n");
++#endif
++#endif
++#ifdef CONFIG_X86_LOCAL_APIC
++ if (smp_found_config)
++ get_smp_config();
++#endif
++#if defined(CONFIG_XEN) && defined(CONFIG_SMP)
++ prefill_possible_map();
++#endif
++
++ register_memory();
++
++ if (is_initial_xendomain()) {
++#ifdef CONFIG_VT
++#if defined(CONFIG_VGA_CONSOLE)
++ if (!efi_enabled ||
++ (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
++ conswitchp = &vga_con;
++#elif defined(CONFIG_DUMMY_CONSOLE)
++ conswitchp = &dummy_con;
++#endif
++#endif
++ } else {
++ extern int console_use_vt;
++ console_use_vt = 0;
++ }
++#ifdef CONFIG_X86_TSC
++ tsc_init();
++#endif
++}
++
++static int
++xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
++{
++ HYPERVISOR_shutdown(SHUTDOWN_crash);
++ /* we're never actually going to get here... */
++ return NOTIFY_DONE;
++}
++
++static __init int add_pcspkr(void)
++{
++ struct platform_device *pd;
++ int ret;
++
++ pd = platform_device_alloc("pcspkr", -1);
++ if (!pd)
++ return -ENOMEM;
++
++ ret = platform_device_add(pd);
++ if (ret)
++ platform_device_put(pd);
++
++ return ret;
++}
++device_initcall(add_pcspkr);
++
++/*
++ * Local Variables:
++ * mode:c
++ * c-file-style:"k&r"
++ * c-basic-offset:8
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/smp-xen.c linux-2.6.18-xen/arch/i386/kernel/smp-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/smp-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/smp-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,624 @@
++/*
++ * Intel SMP support routines.
++ *
++ * (c) 1995 Alan Cox, Building #3 <alan at redhat.com>
++ * (c) 1998-99, 2000 Ingo Molnar <mingo at redhat.com>
++ *
++ * This code is released under the GNU General Public License version 2 or
++ * later.
++ */
++
++#include <linux/init.h>
++
++#include <linux/mm.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/smp_lock.h>
++#include <linux/kernel_stat.h>
++#include <linux/mc146818rtc.h>
++#include <linux/cache.h>
++#include <linux/interrupt.h>
++#include <linux/cpu.h>
++#include <linux/module.h>
++
++#include <asm/mtrr.h>
++#include <asm/tlbflush.h>
++#if 0
++#include <mach_apic.h>
++#endif
++#include <xen/evtchn.h>
++
++/*
++ * Some notes on x86 processor bugs affecting SMP operation:
++ *
++ * Pentium, Pentium Pro, II, III (and all CPUs) have bugs.
++ * The Linux implications for SMP are handled as follows:
++ *
++ * Pentium III / [Xeon]
++ * None of the E1AP-E3AP errata are visible to the user.
++ *
++ * E1AP. see PII A1AP
++ * E2AP. see PII A2AP
++ * E3AP. see PII A3AP
++ *
++ * Pentium II / [Xeon]
++ * None of the A1AP-A3AP errata are visible to the user.
++ *
++ * A1AP. see PPro 1AP
++ * A2AP. see PPro 2AP
++ * A3AP. see PPro 7AP
++ *
++ * Pentium Pro
++ * None of 1AP-9AP errata are visible to the normal user,
++ * except occasional delivery of 'spurious interrupt' as trap #15.
++ * This is very rare and a non-problem.
++ *
++ * 1AP. Linux maps APIC as non-cacheable
++ * 2AP. worked around in hardware
++ * 3AP. fixed in C0 and above steppings microcode update.
++ * Linux does not use excessive STARTUP_IPIs.
++ * 4AP. worked around in hardware
++ * 5AP. symmetric IO mode (normal Linux operation) not affected.
++ * 'noapic' mode has vector 0xf filled out properly.
++ * 6AP. 'noapic' mode might be affected - fixed in later steppings
++ * 7AP. We do not assume writes to the LVT deassering IRQs
++ * 8AP. We do not enable low power mode (deep sleep) during MP bootup
++ * 9AP. We do not use mixed mode
++ *
++ * Pentium
++ * There is a marginal case where REP MOVS on 100MHz SMP
++ * machines with B stepping processors can fail. XXX should provide
++ * an L1cache=Writethrough or L1cache=off option.
++ *
++ * B stepping CPUs may hang. There are hardware work arounds
++ * for this. We warn about it in case your board doesn't have the work
++ * arounds. Basically thats so I can tell anyone with a B stepping
++ * CPU and SMP problems "tough".
++ *
++ * Specific items [From Pentium Processor Specification Update]
++ *
++ * 1AP. Linux doesn't use remote read
++ * 2AP. Linux doesn't trust APIC errors
++ * 3AP. We work around this
++ * 4AP. Linux never generated 3 interrupts of the same priority
++ * to cause a lost local interrupt.
++ * 5AP. Remote read is never used
++ * 6AP. not affected - worked around in hardware
++ * 7AP. not affected - worked around in hardware
++ * 8AP. worked around in hardware - we get explicit CS errors if not
++ * 9AP. only 'noapic' mode affected. Might generate spurious
++ * interrupts, we log only the first one and count the
++ * rest silently.
++ * 10AP. not affected - worked around in hardware
++ * 11AP. Linux reads the APIC between writes to avoid this, as per
++ * the documentation. Make sure you preserve this as it affects
++ * the C stepping chips too.
++ * 12AP. not affected - worked around in hardware
++ * 13AP. not affected - worked around in hardware
++ * 14AP. we always deassert INIT during bootup
++ * 15AP. not affected - worked around in hardware
++ * 16AP. not affected - worked around in hardware
++ * 17AP. not affected - worked around in hardware
++ * 18AP. not affected - worked around in hardware
++ * 19AP. not affected - worked around in BIOS
++ *
++ * If this sounds worrying believe me these bugs are either ___RARE___,
++ * or are signal timing bugs worked around in hardware and there's
++ * about nothing of note with C stepping upwards.
++ */
++
++DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, };
++
++/*
++ * the following functions deal with sending IPIs between CPUs.
++ *
++ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
++ */
++
++static inline int __prepare_ICR (unsigned int shortcut, int vector)
++{
++ unsigned int icr = shortcut | APIC_DEST_LOGICAL;
++
++ switch (vector) {
++ default:
++ icr |= APIC_DM_FIXED | vector;
++ break;
++ case NMI_VECTOR:
++ icr |= APIC_DM_NMI;
++ break;
++ }
++ return icr;
++}
++
++static inline int __prepare_ICR2 (unsigned int mask)
++{
++ return SET_APIC_DEST_FIELD(mask);
++}
++
++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
++
++static inline void __send_IPI_one(unsigned int cpu, int vector)
++{
++ int irq = per_cpu(ipi_to_irq, cpu)[vector];
++ BUG_ON(irq < 0);
++ notify_remote_via_irq(irq);
++}
++
++void __send_IPI_shortcut(unsigned int shortcut, int vector)
++{
++ int cpu;
++
++ switch (shortcut) {
++ case APIC_DEST_SELF:
++ __send_IPI_one(smp_processor_id(), vector);
++ break;
++ case APIC_DEST_ALLBUT:
++ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++ if (cpu == smp_processor_id())
++ continue;
++ if (cpu_isset(cpu, cpu_online_map)) {
++ __send_IPI_one(cpu, vector);
++ }
++ }
++ break;
++ default:
++ printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
++ vector);
++ break;
++ }
++}
++
++void fastcall send_IPI_self(int vector)
++{
++ __send_IPI_shortcut(APIC_DEST_SELF, vector);
++}
++
++/*
++ * This is only used on smaller machines.
++ */
++void send_IPI_mask_bitmask(cpumask_t mask, int vector)
++{
++ unsigned long flags;
++ unsigned int cpu;
++
++ local_irq_save(flags);
++ WARN_ON(cpus_addr(mask)[0] & ~cpus_addr(cpu_online_map)[0]);
++
++ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++ if (cpu_isset(cpu, mask)) {
++ __send_IPI_one(cpu, vector);
++ }
++ }
++
++ local_irq_restore(flags);
++}
++
++void send_IPI_mask_sequence(cpumask_t mask, int vector)
++{
++
++ send_IPI_mask_bitmask(mask, vector);
++}
++
++#include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
++
++#if 0 /* XEN */
++/*
++ * Smarter SMP flushing macros.
++ * c/o Linus Torvalds.
++ *
++ * These mean you can really definitely utterly forget about
++ * writing to user space from interrupts. (Its not allowed anyway).
++ *
++ * Optimizations Manfred Spraul <manfred at colorfullife.com>
++ */
++
++static cpumask_t flush_cpumask;
++static struct mm_struct * flush_mm;
++static unsigned long flush_va;
++static DEFINE_SPINLOCK(tlbstate_lock);
++#define FLUSH_ALL 0xffffffff
++
++/*
++ * We cannot call mmdrop() because we are in interrupt context,
++ * instead update mm->cpu_vm_mask.
++ *
++ * We need to reload %cr3 since the page tables may be going
++ * away from under us..
++ */
++static inline void leave_mm (unsigned long cpu)
++{
++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
++ BUG();
++ cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask);
++ load_cr3(swapper_pg_dir);
++}
++
++/*
++ *
++ * The flush IPI assumes that a thread switch happens in this order:
++ * [cpu0: the cpu that switches]
++ * 1) switch_mm() either 1a) or 1b)
++ * 1a) thread switch to a different mm
++ * 1a1) cpu_clear(cpu, old_mm->cpu_vm_mask);
++ * Stop ipi delivery for the old mm. This is not synchronized with
++ * the other cpus, but smp_invalidate_interrupt ignore flush ipis
++ * for the wrong mm, and in the worst case we perform a superflous
++ * tlb flush.
++ * 1a2) set cpu_tlbstate to TLBSTATE_OK
++ * Now the smp_invalidate_interrupt won't call leave_mm if cpu0
++ * was in lazy tlb mode.
++ * 1a3) update cpu_tlbstate[].active_mm
++ * Now cpu0 accepts tlb flushes for the new mm.
++ * 1a4) cpu_set(cpu, new_mm->cpu_vm_mask);
++ * Now the other cpus will send tlb flush ipis.
++ * 1a4) change cr3.
++ * 1b) thread switch without mm change
++ * cpu_tlbstate[].active_mm is correct, cpu0 already handles
++ * flush ipis.
++ * 1b1) set cpu_tlbstate to TLBSTATE_OK
++ * 1b2) test_and_set the cpu bit in cpu_vm_mask.
++ * Atomically set the bit [other cpus will start sending flush ipis],
++ * and test the bit.
++ * 1b3) if the bit was 0: leave_mm was called, flush the tlb.
++ * 2) switch %%esp, ie current
++ *
++ * The interrupt must handle 2 special cases:
++ * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm.
++ * - the cpu performs speculative tlb reads, i.e. even if the cpu only
++ * runs in kernel space, the cpu could load tlb entries for user space
++ * pages.
++ *
++ * The good news is that cpu_tlbstate is local to each cpu, no
++ * write/read ordering problems.
++ */
++
++/*
++ * TLB flush IPI:
++ *
++ * 1) Flush the tlb entries if the cpu uses the mm that's being flushed.
++ * 2) Leave the mm if we are in the lazy tlb mode.
++ */
++
++irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++ unsigned long cpu;
++
++ cpu = get_cpu();
++
++ if (!cpu_isset(cpu, flush_cpumask))
++ goto out;
++ /*
++ * This was a BUG() but until someone can quote me the
++ * line from the intel manual that guarantees an IPI to
++ * multiple CPUs is retried _only_ on the erroring CPUs
++ * its staying as a return
++ *
++ * BUG();
++ */
++
++ if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
++ if (flush_va == FLUSH_ALL)
++ local_flush_tlb();
++ else
++ __flush_tlb_one(flush_va);
++ } else
++ leave_mm(cpu);
++ }
++ smp_mb__before_clear_bit();
++ cpu_clear(cpu, flush_cpumask);
++ smp_mb__after_clear_bit();
++out:
++ put_cpu_no_resched();
++
++ return IRQ_HANDLED;
++}
++
++static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
++ unsigned long va)
++{
++ /*
++ * A couple of (to be removed) sanity checks:
++ *
++ * - current CPU must not be in mask
++ * - mask must exist :)
++ */
++ BUG_ON(cpus_empty(cpumask));
++ BUG_ON(cpu_isset(smp_processor_id(), cpumask));
++ BUG_ON(!mm);
++
++ /* If a CPU which we ran on has gone down, OK. */
++ cpus_and(cpumask, cpumask, cpu_online_map);
++ if (cpus_empty(cpumask))
++ return;
++
++ /*
++ * i'm not happy about this global shared spinlock in the
++ * MM hot path, but we'll see how contended it is.
++ * Temporarily this turns IRQs off, so that lockups are
++ * detected by the NMI watchdog.
++ */
++ spin_lock(&tlbstate_lock);
++
++ flush_mm = mm;
++ flush_va = va;
++#if NR_CPUS <= BITS_PER_LONG
++ atomic_set_mask(cpumask, &flush_cpumask);
++#else
++ {
++ int k;
++ unsigned long *flush_mask = (unsigned long *)&flush_cpumask;
++ unsigned long *cpu_mask = (unsigned long *)&cpumask;
++ for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k)
++ atomic_set_mask(cpu_mask[k], &flush_mask[k]);
++ }
++#endif
++ /*
++ * We have to send the IPI only to
++ * CPUs affected.
++ */
++ send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
++
++ while (!cpus_empty(flush_cpumask))
++ /* nothing. lockup detection does not belong here */
++ mb();
++
++ flush_mm = NULL;
++ flush_va = 0;
++ spin_unlock(&tlbstate_lock);
++}
++
++void flush_tlb_current_task(void)
++{
++ struct mm_struct *mm = current->mm;
++ cpumask_t cpu_mask;
++
++ preempt_disable();
++ cpu_mask = mm->cpu_vm_mask;
++ cpu_clear(smp_processor_id(), cpu_mask);
++
++ local_flush_tlb();
++ if (!cpus_empty(cpu_mask))
++ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
++ preempt_enable();
++}
++
++void flush_tlb_mm (struct mm_struct * mm)
++{
++ cpumask_t cpu_mask;
++
++ preempt_disable();
++ cpu_mask = mm->cpu_vm_mask;
++ cpu_clear(smp_processor_id(), cpu_mask);
++
++ if (current->active_mm == mm) {
++ if (current->mm)
++ local_flush_tlb();
++ else
++ leave_mm(smp_processor_id());
++ }
++ if (!cpus_empty(cpu_mask))
++ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
++
++ preempt_enable();
++}
++
++void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
++{
++ struct mm_struct *mm = vma->vm_mm;
++ cpumask_t cpu_mask;
++
++ preempt_disable();
++ cpu_mask = mm->cpu_vm_mask;
++ cpu_clear(smp_processor_id(), cpu_mask);
++
++ if (current->active_mm == mm) {
++ if(current->mm)
++ __flush_tlb_one(va);
++ else
++ leave_mm(smp_processor_id());
++ }
++
++ if (!cpus_empty(cpu_mask))
++ flush_tlb_others(cpu_mask, mm, va);
++
++ preempt_enable();
++}
++EXPORT_SYMBOL(flush_tlb_page);
++
++static void do_flush_tlb_all(void* info)
++{
++ unsigned long cpu = smp_processor_id();
++
++ __flush_tlb_all();
++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY)
++ leave_mm(cpu);
++}
++
++void flush_tlb_all(void)
++{
++ on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
++}
++
++#else
++
++irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{ return 0; }
++void flush_tlb_current_task(void)
++{ xen_tlb_flush_mask(¤t->mm->cpu_vm_mask); }
++void flush_tlb_mm(struct mm_struct * mm)
++{ xen_tlb_flush_mask(&mm->cpu_vm_mask); }
++void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
++{ xen_invlpg_mask(&vma->vm_mm->cpu_vm_mask, va); }
++EXPORT_SYMBOL(flush_tlb_page);
++void flush_tlb_all(void)
++{ xen_tlb_flush_all(); }
++
++#endif /* XEN */
++
++/*
++ * this function sends a 'reschedule' IPI to another CPU.
++ * it goes straight through and wastes no time serializing
++ * anything. Worst case is that we lose a reschedule ...
++ */
++void smp_send_reschedule(int cpu)
++{
++ WARN_ON(cpu_is_offline(cpu));
++ send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
++}
++
++/*
++ * Structure and data for smp_call_function(). This is designed to minimise
++ * static memory requirements. It also looks cleaner.
++ */
++static DEFINE_SPINLOCK(call_lock);
++
++struct call_data_struct {
++ void (*func) (void *info);
++ void *info;
++ atomic_t started;
++ atomic_t finished;
++ 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;
++
++/**
++ * smp_call_function(): Run a function on all other CPUs.
++ * @func: The function to run. This must be fast and non-blocking.
++ * @info: An arbitrary pointer to pass to the function.
++ * @nonatomic: currently unused.
++ * @wait: If true, wait (atomically) until function has completed on other CPUs.
++ *
++ * Returns 0 on success, else a negative status code. Does not return until
++ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
++ *
++ * You must not call this function with disabled interrupts or from a
++ * hardware interrupt handler or from a bottom half handler.
++ */
++int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
++ int wait)
++{
++ struct call_data_struct data;
++ int 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());
++
++ data.func = func;
++ data.info = info;
++ atomic_set(&data.started, 0);
++ data.wait = wait;
++ if (wait)
++ atomic_set(&data.finished, 0);
++
++ call_data = &data;
++ mb();
++
++ /* Send a message to all other CPUs and wait for them to respond */
++ send_IPI_allbutself(CALL_FUNCTION_VECTOR);
++
++ /* Wait for response */
++ while (atomic_read(&data.started) != cpus)
++ barrier();
++
++ if (wait)
++ while (atomic_read(&data.finished) != cpus)
++ barrier();
++ spin_unlock(&call_lock);
++
++ return 0;
++}
++EXPORT_SYMBOL(smp_call_function);
++
++static void stop_this_cpu (void * dummy)
++{
++ /*
++ * Remove this CPU:
++ */
++ cpu_clear(smp_processor_id(), cpu_online_map);
++ local_irq_disable();
++#if 0
++ disable_local_APIC();
++#endif
++ if (cpu_data[smp_processor_id()].hlt_works_ok)
++ for(;;) halt();
++ for (;;);
++}
++
++/*
++ * this function calls the 'stop' function on all other CPUs in the system.
++ */
++
++void smp_send_stop(void)
++{
++ smp_call_function(stop_this_cpu, NULL, 1, 0);
++
++ local_irq_disable();
++#if 0
++ disable_local_APIC();
++#endif
++ local_irq_enable();
++}
++
++/*
++ * Reschedule call back. Nothing to do,
++ * all the work is done automatically when
++ * we return from the interrupt.
++ */
++irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++
++ return IRQ_HANDLED;
++}
++
++#include <linux/kallsyms.h>
++irqreturn_t smp_call_function_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++ void (*func) (void *info) = call_data->func;
++ void *info = call_data->info;
++ int wait = call_data->wait;
++
++ /*
++ * Notify initiating CPU that I've grabbed the data and am
++ * about to execute the function
++ */
++ mb();
++ atomic_inc(&call_data->started);
++ /*
++ * At this point the info structure may be out of scope unless wait==1
++ */
++ irq_enter();
++ (*func)(info);
++ irq_exit();
++
++ if (wait) {
++ mb();
++ atomic_inc(&call_data->finished);
++ }
++
++ return IRQ_HANDLED;
++}
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/swiotlb.c linux-2.6.18-xen/arch/i386/kernel/swiotlb.c
+--- linux-2.6.18.1/arch/i386/kernel/swiotlb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/swiotlb.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,672 @@
++/*
++ * Dynamic DMA mapping support.
++ *
++ * This implementation is a fallback for platforms that do not support
++ * I/O TLBs (aka DMA address translation hardware).
++ * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick at intel.com>
++ * Copyright (C) 2000 Goutham Rao <goutham.rao at intel.com>
++ * Copyright (C) 2000, 2003 Hewlett-Packard Co
++ * David Mosberger-Tang <davidm at hpl.hp.com>
++ * Copyright (C) 2005 Keir Fraser <keir at xensource.com>
++ */
++
++#include <linux/cache.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/ctype.h>
++#include <linux/init.h>
++#include <linux/bootmem.h>
++#include <linux/highmem.h>
++#include <asm/io.h>
++#include <asm/pci.h>
++#include <asm/dma.h>
++#include <asm/uaccess.h>
++#include <xen/interface/memory.h>
++
++int swiotlb;
++EXPORT_SYMBOL(swiotlb);
++
++#define OFFSET(val,align) ((unsigned long)((val) & ( (align) - 1)))
++
++#define SG_ENT_PHYS_ADDRESS(sg) (page_to_bus((sg)->page) + (sg)->offset)
++
++/*
++ * Maximum allowable number of contiguous slabs to map,
++ * must be a power of 2. What is the appropriate value ?
++ * The complexity of {map,unmap}_single is linearly dependent on this value.
++ */
++#define IO_TLB_SEGSIZE 128
++
++/*
++ * log of the size of each IO TLB slab. The number of slabs is command line
++ * controllable.
++ */
++#define IO_TLB_SHIFT 11
++
++/* Width of DMA addresses in the IO TLB. 31 bits is an aacraid limitation. */
++#define IO_TLB_DMA_BITS 31
++
++int swiotlb_force;
++static char *iotlb_virt_start;
++static unsigned long iotlb_nslabs;
++
++/*
++ * Used to do a quick range check in swiotlb_unmap_single and
++ * swiotlb_sync_single_*, to see if the memory was in fact allocated by this
++ * API.
++ */
++static unsigned long iotlb_pfn_start, iotlb_pfn_end;
++
++/* Does the given dma address reside within the swiotlb aperture? */
++static inline int in_swiotlb_aperture(dma_addr_t dev_addr)
++{
++ unsigned long pfn = mfn_to_local_pfn(dev_addr >> PAGE_SHIFT);
++ return (pfn_valid(pfn)
++ && (pfn >= iotlb_pfn_start)
++ && (pfn < iotlb_pfn_end));
++}
++
++/*
++ * When the IOMMU overflows we return a fallback buffer. This sets the size.
++ */
++static unsigned long io_tlb_overflow = 32*1024;
++
++void *io_tlb_overflow_buffer;
++
++/*
++ * This is a free list describing the number of free entries available from
++ * each index
++ */
++static unsigned int *io_tlb_list;
++static unsigned int io_tlb_index;
++
++/*
++ * We need to save away the original address corresponding to a mapped entry
++ * for the sync operations.
++ */
++static struct phys_addr {
++ struct page *page;
++ unsigned int offset;
++} *io_tlb_orig_addr;
++
++/*
++ * Protect the above data structures in the map and unmap calls
++ */
++static DEFINE_SPINLOCK(io_tlb_lock);
++
++static int __init
++setup_io_tlb_npages(char *str)
++{
++ /* Unlike ia64, the size is aperture in megabytes, not 'slabs'! */
++ if (isdigit(*str)) {
++ iotlb_nslabs = simple_strtoul(str, &str, 0) <<
++ (20 - IO_TLB_SHIFT);
++ iotlb_nslabs = ALIGN(iotlb_nslabs, IO_TLB_SEGSIZE);
++ /* Round up to power of two (xen_create_contiguous_region). */
++ while (iotlb_nslabs & (iotlb_nslabs-1))
++ iotlb_nslabs += iotlb_nslabs & ~(iotlb_nslabs-1);
++ }
++ if (*str == ',')
++ ++str;
++ /*
++ * NB. 'force' enables the swiotlb, but doesn't force its use for
++ * every DMA like it does on native Linux. 'off' forcibly disables
++ * use of the swiotlb.
++ */
++ if (!strcmp(str, "force"))
++ swiotlb_force = 1;
++ else if (!strcmp(str, "off"))
++ swiotlb_force = -1;
++ return 1;
++}
++__setup("swiotlb=", setup_io_tlb_npages);
++/* make io_tlb_overflow tunable too? */
++
++/*
++ * Statically reserve bounce buffer space and initialize bounce buffer data
++ * structures for the software IO TLB used to implement the PCI DMA API.
++ */
++void
++swiotlb_init_with_default_size (size_t default_size)
++{
++ unsigned long i, bytes;
++
++ if (!iotlb_nslabs) {
++ iotlb_nslabs = (default_size >> IO_TLB_SHIFT);
++ iotlb_nslabs = ALIGN(iotlb_nslabs, IO_TLB_SEGSIZE);
++ /* Round up to power of two (xen_create_contiguous_region). */
++ while (iotlb_nslabs & (iotlb_nslabs-1))
++ iotlb_nslabs += iotlb_nslabs & ~(iotlb_nslabs-1);
++ }
++
++ bytes = iotlb_nslabs * (1UL << IO_TLB_SHIFT);
++
++ /*
++ * Get IO TLB memory from the low pages
++ */
++ iotlb_virt_start = alloc_bootmem_low_pages(bytes);
++ if (!iotlb_virt_start)
++ panic("Cannot allocate SWIOTLB buffer!\n"
++ "Use dom0_mem Xen boot parameter to reserve\n"
++ "some DMA memory (e.g., dom0_mem=-128M).\n");
++
++ for (i = 0; i < iotlb_nslabs; i += IO_TLB_SEGSIZE) {
++ int rc = xen_create_contiguous_region(
++ (unsigned long)iotlb_virt_start + (i << IO_TLB_SHIFT),
++ get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT),
++ IO_TLB_DMA_BITS);
++ BUG_ON(rc);
++ }
++
++ /*
++ * Allocate and initialize the free list array. This array is used
++ * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE.
++ */
++ io_tlb_list = alloc_bootmem(iotlb_nslabs * sizeof(int));
++ for (i = 0; i < iotlb_nslabs; i++)
++ io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
++ io_tlb_index = 0;
++ io_tlb_orig_addr = alloc_bootmem(
++ iotlb_nslabs * sizeof(*io_tlb_orig_addr));
++
++ /*
++ * Get the overflow emergency buffer
++ */
++ io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
++
++ iotlb_pfn_start = __pa(iotlb_virt_start) >> PAGE_SHIFT;
++ iotlb_pfn_end = iotlb_pfn_start + (bytes >> PAGE_SHIFT);
++
++ printk(KERN_INFO "Software IO TLB enabled: \n"
++ " Aperture: %lu megabytes\n"
++ " Kernel range: 0x%016lx - 0x%016lx\n",
++ bytes >> 20,
++ (unsigned long)iotlb_virt_start,
++ (unsigned long)iotlb_virt_start + bytes);
++}
++
++void
++swiotlb_init(void)
++{
++ long ram_end;
++ size_t defsz = 64 * (1 << 20); /* 64MB default size */
++
++ if (swiotlb_force == 1) {
++ swiotlb = 1;
++ } else if ((swiotlb_force != -1) &&
++ is_running_on_xen() &&
++ is_initial_xendomain()) {
++ /* Domain 0 always has a swiotlb. */
++ ram_end = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
++ if (ram_end <= 0x7ffff)
++ defsz = 2 * (1 << 20); /* 2MB on <2GB on systems. */
++ swiotlb = 1;
++ }
++
++ if (swiotlb)
++ swiotlb_init_with_default_size(defsz);
++ else
++ printk(KERN_INFO "Software IO TLB disabled\n");
++}
++
++/*
++ * We use __copy_to_user_inatomic to transfer to the host buffer because the
++ * buffer may be mapped read-only (e.g, in blkback driver) but lower-level
++ * drivers map the buffer for DMA_BIDIRECTIONAL access. This causes an
++ * unnecessary copy from the aperture to the host buffer, and a page fault.
++ */
++static void
++__sync_single(struct phys_addr buffer, char *dma_addr, size_t size, int dir)
++{
++ if (PageHighMem(buffer.page)) {
++ size_t len, bytes;
++ char *dev, *host, *kmp;
++ len = size;
++ while (len != 0) {
++ if (((bytes = len) + buffer.offset) > PAGE_SIZE)
++ bytes = PAGE_SIZE - buffer.offset;
++ kmp = kmap_atomic(buffer.page, KM_SWIOTLB);
++ dev = dma_addr + size - len;
++ host = kmp + buffer.offset;
++ if (dir == DMA_FROM_DEVICE) {
++ if (__copy_to_user_inatomic(host, dev, bytes))
++ /* inaccessible */;
++ } else
++ memcpy(dev, host, bytes);
++ kunmap_atomic(kmp, KM_SWIOTLB);
++ len -= bytes;
++ buffer.page++;
++ buffer.offset = 0;
++ }
++ } else {
++ char *host = (char *)phys_to_virt(
++ page_to_pseudophys(buffer.page)) + buffer.offset;
++ if (dir == DMA_FROM_DEVICE) {
++ if (__copy_to_user_inatomic(host, dma_addr, size))
++ /* inaccessible */;
++ } else if (dir == DMA_TO_DEVICE)
++ memcpy(dma_addr, host, size);
++ }
++}
++
++/*
++ * Allocates bounce buffer and returns its kernel virtual address.
++ */
++static void *
++map_single(struct device *hwdev, struct phys_addr buffer, size_t size, int dir)
++{
++ unsigned long flags;
++ char *dma_addr;
++ unsigned int nslots, stride, index, wrap;
++ int i;
++
++ /*
++ * For mappings greater than a page, we limit the stride (and
++ * hence alignment) to a page size.
++ */
++ nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
++ if (size > PAGE_SIZE)
++ stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
++ else
++ stride = 1;
++
++ BUG_ON(!nslots);
++
++ /*
++ * Find suitable number of IO TLB entries size that will fit this
++ * request and allocate a buffer from that IO TLB pool.
++ */
++ spin_lock_irqsave(&io_tlb_lock, flags);
++ {
++ wrap = index = ALIGN(io_tlb_index, stride);
++
++ if (index >= iotlb_nslabs)
++ wrap = index = 0;
++
++ do {
++ /*
++ * If we find a slot that indicates we have 'nslots'
++ * number of contiguous buffers, we allocate the
++ * buffers from that slot and mark the entries as '0'
++ * indicating unavailable.
++ */
++ if (io_tlb_list[index] >= nslots) {
++ int count = 0;
++
++ for (i = index; i < (int)(index + nslots); i++)
++ io_tlb_list[i] = 0;
++ for (i = index - 1;
++ (OFFSET(i, IO_TLB_SEGSIZE) !=
++ IO_TLB_SEGSIZE -1) && io_tlb_list[i];
++ i--)
++ io_tlb_list[i] = ++count;
++ dma_addr = iotlb_virt_start +
++ (index << IO_TLB_SHIFT);
++
++ /*
++ * Update the indices to avoid searching in
++ * the next round.
++ */
++ io_tlb_index =
++ ((index + nslots) < iotlb_nslabs
++ ? (index + nslots) : 0);
++
++ goto found;
++ }
++ index += stride;
++ if (index >= iotlb_nslabs)
++ index = 0;
++ } while (index != wrap);
++
++ spin_unlock_irqrestore(&io_tlb_lock, flags);
++ return NULL;
++ }
++ found:
++ spin_unlock_irqrestore(&io_tlb_lock, flags);
++
++ /*
++ * Save away the mapping from the original address to the DMA address.
++ * This is needed when we sync the memory. Then we sync the buffer if
++ * needed.
++ */
++ io_tlb_orig_addr[index] = buffer;
++ if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL))
++ __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
++
++ return dma_addr;
++}
++
++/*
++ * dma_addr is the kernel virtual address of the bounce buffer to unmap.
++ */
++static void
++unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
++{
++ unsigned long flags;
++ int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
++ int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT;
++ struct phys_addr buffer = io_tlb_orig_addr[index];
++
++ /*
++ * First, sync the memory before unmapping the entry
++ */
++ if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))
++ __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
++
++ /*
++ * Return the buffer to the free list by setting the corresponding
++ * entries to indicate the number of contigous entries available.
++ * While returning the entries to the free list, we merge the entries
++ * with slots below and above the pool being returned.
++ */
++ spin_lock_irqsave(&io_tlb_lock, flags);
++ {
++ count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ?
++ io_tlb_list[index + nslots] : 0);
++ /*
++ * Step 1: return the slots to the free list, merging the
++ * slots with superceeding slots
++ */
++ for (i = index + nslots - 1; i >= index; i--)
++ io_tlb_list[i] = ++count;
++ /*
++ * Step 2: merge the returned slots with the preceding slots,
++ * if available (non zero)
++ */
++ for (i = index - 1;
++ (OFFSET(i, IO_TLB_SEGSIZE) !=
++ IO_TLB_SEGSIZE -1) && io_tlb_list[i];
++ i--)
++ io_tlb_list[i] = ++count;
++ }
++ spin_unlock_irqrestore(&io_tlb_lock, flags);
++}
++
++static void
++sync_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
++{
++ int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT;
++ struct phys_addr buffer = io_tlb_orig_addr[index];
++ BUG_ON((dir != DMA_FROM_DEVICE) && (dir != DMA_TO_DEVICE));
++ __sync_single(buffer, dma_addr, size, dir);
++}
++
++static void
++swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
++{
++ /*
++ * Ran out of IOMMU space for this operation. This is very bad.
++ * Unfortunately the drivers cannot handle this operation properly.
++ * unless they check for pci_dma_mapping_error (most don't)
++ * When the mapping is small enough return a static buffer to limit
++ * the damage, or panic when the transfer is too big.
++ */
++ printk(KERN_ERR "PCI-DMA: Out of SW-IOMMU space for %lu bytes at "
++ "device %s\n", (unsigned long)size, dev ? dev->bus_id : "?");
++
++ if (size > io_tlb_overflow && do_panic) {
++ if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
++ panic("PCI-DMA: Memory would be corrupted\n");
++ if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL)
++ panic("PCI-DMA: Random memory would be DMAed\n");
++ }
++}
++
++/*
++ * Map a single buffer of the indicated size for DMA in streaming mode. The
++ * PCI address to use is returned.
++ *
++ * Once the device is given the dma address, the device owns this memory until
++ * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
++ */
++dma_addr_t
++swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
++{
++ dma_addr_t dev_addr = virt_to_bus(ptr);
++ void *map;
++ struct phys_addr buffer;
++
++ BUG_ON(dir == DMA_NONE);
++
++ /*
++ * If the pointer passed in happens to be in the device's DMA window,
++ * we can safely return the device addr and not worry about bounce
++ * buffering it.
++ */
++ if (!range_straddles_page_boundary(ptr, size) &&
++ !address_needs_mapping(hwdev, dev_addr))
++ return dev_addr;
++
++ /*
++ * Oh well, have to allocate and map a bounce buffer.
++ */
++ buffer.page = virt_to_page(ptr);
++ buffer.offset = (unsigned long)ptr & ~PAGE_MASK;
++ map = map_single(hwdev, buffer, size, dir);
++ if (!map) {
++ swiotlb_full(hwdev, size, dir, 1);
++ map = io_tlb_overflow_buffer;
++ }
++
++ dev_addr = virt_to_bus(map);
++ return dev_addr;
++}
++
++/*
++ * Unmap a single streaming mode DMA translation. The dma_addr and size must
++ * match what was provided for in a previous swiotlb_map_single call. All
++ * other usages are undefined.
++ *
++ * After this call, reads by the cpu to the buffer are guaranteed to see
++ * whatever the device wrote there.
++ */
++void
++swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
++ int dir)
++{
++ BUG_ON(dir == DMA_NONE);
++ if (in_swiotlb_aperture(dev_addr))
++ unmap_single(hwdev, bus_to_virt(dev_addr), size, dir);
++}
++
++/*
++ * Make physical memory consistent for a single streaming mode DMA translation
++ * after a transfer.
++ *
++ * If you perform a swiotlb_map_single() but wish to interrogate the buffer
++ * using the cpu, yet do not wish to teardown the PCI dma mapping, you must
++ * call this function before doing so. At the next point you give the PCI dma
++ * address back to the card, you must first perform a
++ * swiotlb_dma_sync_for_device, and then the device again owns the buffer
++ */
++void
++swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
++ size_t size, int dir)
++{
++ BUG_ON(dir == DMA_NONE);
++ if (in_swiotlb_aperture(dev_addr))
++ sync_single(hwdev, bus_to_virt(dev_addr), size, dir);
++}
++
++void
++swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
++ size_t size, int dir)
++{
++ BUG_ON(dir == DMA_NONE);
++ if (in_swiotlb_aperture(dev_addr))
++ sync_single(hwdev, bus_to_virt(dev_addr), size, dir);
++}
++
++/*
++ * Map a set of buffers described by scatterlist in streaming mode for DMA.
++ * This is the scatter-gather version of the above swiotlb_map_single
++ * interface. Here the scatter gather list elements are each tagged with the
++ * appropriate dma address and length. They are obtained via
++ * sg_dma_{address,length}(SG).
++ *
++ * NOTE: An implementation may be able to use a smaller number of
++ * DMA address/length pairs than there are SG table elements.
++ * (for example via virtual mapping capabilities)
++ * The routine returns the number of addr/length pairs actually
++ * used, at most nents.
++ *
++ * Device ownership issues as mentioned above for swiotlb_map_single are the
++ * same here.
++ */
++int
++swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
++ int dir)
++{
++ struct phys_addr buffer;
++ dma_addr_t dev_addr;
++ char *map;
++ int i;
++
++ BUG_ON(dir == DMA_NONE);
++
++ for (i = 0; i < nelems; i++, sg++) {
++ dev_addr = SG_ENT_PHYS_ADDRESS(sg);
++ if (address_needs_mapping(hwdev, dev_addr)) {
++ buffer.page = sg->page;
++ buffer.offset = sg->offset;
++ map = map_single(hwdev, buffer, sg->length, dir);
++ if (!map) {
++ /* Don't panic here, we expect map_sg users
++ to do proper error handling. */
++ swiotlb_full(hwdev, sg->length, dir, 0);
++ swiotlb_unmap_sg(hwdev, sg - i, i, dir);
++ sg[0].dma_length = 0;
++ return 0;
++ }
++ sg->dma_address = (dma_addr_t)virt_to_bus(map);
++ } else
++ sg->dma_address = dev_addr;
++ sg->dma_length = sg->length;
++ }
++ return nelems;
++}
++
++/*
++ * Unmap a set of streaming mode DMA translations. Again, cpu read rules
++ * concerning calls here are the same as for swiotlb_unmap_single() above.
++ */
++void
++swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
++ int dir)
++{
++ int i;
++
++ BUG_ON(dir == DMA_NONE);
++
++ for (i = 0; i < nelems; i++, sg++)
++ if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
++ unmap_single(hwdev,
++ (void *)bus_to_virt(sg->dma_address),
++ sg->dma_length, dir);
++}
++
++/*
++ * Make physical memory consistent for a set of streaming mode DMA translations
++ * after a transfer.
++ *
++ * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules
++ * and usage.
++ */
++void
++swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
++ int nelems, int dir)
++{
++ int i;
++
++ BUG_ON(dir == DMA_NONE);
++
++ for (i = 0; i < nelems; i++, sg++)
++ if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
++ sync_single(hwdev,
++ (void *)bus_to_virt(sg->dma_address),
++ sg->dma_length, dir);
++}
++
++void
++swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
++ int nelems, int dir)
++{
++ int i;
++
++ BUG_ON(dir == DMA_NONE);
++
++ for (i = 0; i < nelems; i++, sg++)
++ if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
++ sync_single(hwdev,
++ (void *)bus_to_virt(sg->dma_address),
++ sg->dma_length, dir);
++}
++
++dma_addr_t
++swiotlb_map_page(struct device *hwdev, struct page *page,
++ unsigned long offset, size_t size,
++ enum dma_data_direction direction)
++{
++ struct phys_addr buffer;
++ dma_addr_t dev_addr;
++ char *map;
++
++ dev_addr = page_to_bus(page) + offset;
++ if (address_needs_mapping(hwdev, dev_addr)) {
++ buffer.page = page;
++ buffer.offset = offset;
++ map = map_single(hwdev, buffer, size, direction);
++ if (!map) {
++ swiotlb_full(hwdev, size, direction, 1);
++ map = io_tlb_overflow_buffer;
++ }
++ dev_addr = (dma_addr_t)virt_to_bus(map);
++ }
++
++ return dev_addr;
++}
++
++void
++swiotlb_unmap_page(struct device *hwdev, dma_addr_t dma_address,
++ size_t size, enum dma_data_direction direction)
++{
++ BUG_ON(direction == DMA_NONE);
++ if (in_swiotlb_aperture(dma_address))
++ unmap_single(hwdev, bus_to_virt(dma_address), size, direction);
++}
++
++int
++swiotlb_dma_mapping_error(dma_addr_t dma_addr)
++{
++ return (dma_addr == virt_to_bus(io_tlb_overflow_buffer));
++}
++
++/*
++ * Return whether the given PCI device DMA address mask can be supported
++ * properly. For example, if your device can only drive the low 24-bits
++ * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
++ * this function.
++ */
++int
++swiotlb_dma_supported (struct device *hwdev, u64 mask)
++{
++ return (mask >= ((1UL << IO_TLB_DMA_BITS) - 1));
++}
++
++EXPORT_SYMBOL(swiotlb_init);
++EXPORT_SYMBOL(swiotlb_map_single);
++EXPORT_SYMBOL(swiotlb_unmap_single);
++EXPORT_SYMBOL(swiotlb_map_sg);
++EXPORT_SYMBOL(swiotlb_unmap_sg);
++EXPORT_SYMBOL(swiotlb_sync_single_for_cpu);
++EXPORT_SYMBOL(swiotlb_sync_single_for_device);
++EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
++EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
++EXPORT_SYMBOL(swiotlb_map_page);
++EXPORT_SYMBOL(swiotlb_unmap_page);
++EXPORT_SYMBOL(swiotlb_dma_mapping_error);
++EXPORT_SYMBOL(swiotlb_dma_supported);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/sysenter.c linux-2.6.18-xen/arch/i386/kernel/sysenter.c
+--- linux-2.6.18.1/arch/i386/kernel/sysenter.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/sysenter.c 2006-09-04 16:31:00.000000000 +0200
+@@ -23,6 +23,10 @@
+ #include <asm/pgtable.h>
+ #include <asm/unistd.h>
+
++#ifdef CONFIG_XEN
++#include <xen/interface/callback.h>
++#endif
++
+ /*
+ * Should the kernel map a VDSO page into processes and pass its
+ * address down to glibc upon exec()?
+@@ -44,6 +48,7 @@
+
+ void enable_sep_cpu(void)
+ {
++#ifndef CONFIG_X86_NO_TSS
+ int cpu = get_cpu();
+ struct tss_struct *tss = &per_cpu(init_tss, cpu);
+
+@@ -58,6 +63,7 @@
+ wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
+ wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
+ put_cpu();
++#endif
+ }
+
+ /*
+@@ -72,6 +78,18 @@
+ {
+ syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+
++#ifdef CONFIG_XEN
++ if (boot_cpu_has(X86_FEATURE_SEP)) {
++ struct callback_register sysenter = {
++ .type = CALLBACKTYPE_sysenter,
++ .address = { __KERNEL_CS, (unsigned long)sysenter_entry },
++ };
++
++ if (HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) < 0)
++ clear_bit(X86_FEATURE_SEP, boot_cpu_data.x86_capability);
++ }
++#endif
++
+ #ifdef CONFIG_COMPAT_VDSO
+ __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
+ printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
+@@ -79,8 +97,12 @@
+ /*
+ * In the non-compat case the ELF coredumping code needs the fixmap:
+ */
++#ifdef CONFIG_XEN
++ __set_fixmap(FIX_VDSO, virt_to_machine(syscall_page), PAGE_KERNEL_RO);
++#else
+ __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO);
+ #endif
++#endif
+
+ if (!boot_cpu_has(X86_FEATURE_SEP)) {
+ memcpy(syscall_page,
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/time-xen.c linux-2.6.18-xen/arch/i386/kernel/time-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/time-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/time-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,1101 @@
++/*
++ * linux/arch/i386/kernel/time.c
++ *
++ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
++ *
++ * This file contains the PC-specific time handling details:
++ * reading the RTC at bootup, etc..
++ * 1994-07-02 Alan Modra
++ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
++ * 1995-03-26 Markus Kuhn
++ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
++ * precision CMOS clock update
++ * 1996-05-03 Ingo Molnar
++ * fixed time warps in do_[slow|fast]_gettimeoffset()
++ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
++ * "A Kernel Model for Precision Timekeeping" by Dave Mills
++ * 1998-09-05 (Various)
++ * More robust do_fast_gettimeoffset() algorithm implemented
++ * (works with APM, Cyrix 6x86MX and Centaur C6),
++ * monotonic gettimeofday() with fast_get_timeoffset(),
++ * drift-proof precision TSC calibration on boot
++ * (C. Scott Ananian <cananian at alumni.princeton.edu>, Andrew D.
++ * Balsa <andrebalsa at altern.org>, Philip Gladstone <philip at raptor.com>;
++ * ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause at tu-harburg.de>).
++ * 1998-12-16 Andrea Arcangeli
++ * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
++ * because was not accounting lost_ticks.
++ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli
++ * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
++ * serialize accesses to xtime/lost_ticks).
++ */
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/param.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/sysdev.h>
++#include <linux/bcd.h>
++#include <linux/efi.h>
++#include <linux/mca.h>
++#include <linux/sysctl.h>
++#include <linux/percpu.h>
++#include <linux/kernel_stat.h>
++#include <linux/posix-timers.h>
++
++#include <asm/io.h>
++#include <asm/smp.h>
++#include <asm/irq.h>
++#include <asm/msr.h>
++#include <asm/delay.h>
++#include <asm/mpspec.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++#include <asm/timer.h>
++#include <asm/sections.h>
++
++#include "mach_time.h"
++
++#include <linux/timex.h>
++
++#include <asm/hpet.h>
++
++#include <asm/arch_hooks.h>
++
++#include <xen/evtchn.h>
++#include <xen/interface/vcpu.h>
++
++#if defined (__i386__)
++#include <asm/i8259.h>
++#endif
++
++int pit_latch_buggy; /* extern */
++
++#if defined(__x86_64__)
++unsigned long vxtime_hz = PIT_TICK_RATE;
++struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */
++volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
++unsigned long __wall_jiffies __section_wall_jiffies = INITIAL_JIFFIES;
++struct timespec __xtime __section_xtime;
++struct timezone __sys_tz __section_sys_tz;
++#endif
++
++#define USEC_PER_TICK (USEC_PER_SEC / HZ)
++#define NSEC_PER_TICK (NSEC_PER_SEC / HZ)
++#define FSEC_PER_TICK (FSEC_PER_SEC / HZ)
++
++#define NS_SCALE 10 /* 2^10, carefully chosen */
++#define US_SCALE 32 /* 2^32, arbitralrily chosen */
++
++unsigned int cpu_khz; /* Detected as we calibrate the TSC */
++EXPORT_SYMBOL(cpu_khz);
++
++extern unsigned long wall_jiffies;
++
++DEFINE_SPINLOCK(rtc_lock);
++EXPORT_SYMBOL(rtc_lock);
++
++extern struct init_timer_opts timer_tsc_init;
++extern struct timer_opts timer_tsc;
++#define timer_none timer_tsc
++
++/* These are peridically updated in shared_info, and then copied here. */
++struct shadow_time_info {
++ u64 tsc_timestamp; /* TSC at last update of time vals. */
++ u64 system_timestamp; /* Time, in nanosecs, since boot. */
++ u32 tsc_to_nsec_mul;
++ u32 tsc_to_usec_mul;
++ int tsc_shift;
++ u32 version;
++};
++static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
++static struct timespec shadow_tv;
++static u32 shadow_tv_version;
++
++/* Keep track of last time we did processing/updating of jiffies and xtime. */
++static u64 processed_system_time; /* System time (ns) at last processing. */
++static DEFINE_PER_CPU(u64, processed_system_time);
++
++/* How much CPU time was spent blocked and how much was 'stolen'? */
++static DEFINE_PER_CPU(u64, processed_stolen_time);
++static DEFINE_PER_CPU(u64, processed_blocked_time);
++
++/* Current runstate of each CPU (updated automatically by the hypervisor). */
++static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
++
++/* Must be signed, as it's compared with s64 quantities which can be -ve. */
++#define NS_PER_TICK (1000000000LL/HZ)
++
++static inline void __normalize_time(time_t *sec, s64 *nsec)
++{
++ while (*nsec >= NSEC_PER_SEC) {
++ (*nsec) -= NSEC_PER_SEC;
++ (*sec)++;
++ }
++ while (*nsec < 0) {
++ (*nsec) += NSEC_PER_SEC;
++ (*sec)--;
++ }
++}
++
++/* Does this guest OS track Xen time, or set its wall clock independently? */
++static int independent_wallclock = 0;
++static int __init __independent_wallclock(char *str)
++{
++ independent_wallclock = 1;
++ return 1;
++}
++__setup("independent_wallclock", __independent_wallclock);
++
++/* Permitted clock jitter, in nsecs, beyond which a warning will be printed. */
++static unsigned long permitted_clock_jitter = 10000000UL; /* 10ms */
++static int __init __permitted_clock_jitter(char *str)
++{
++ permitted_clock_jitter = simple_strtoul(str, NULL, 0);
++ return 1;
++}
++__setup("permitted_clock_jitter=", __permitted_clock_jitter);
++
++#ifndef CONFIG_X86
++int tsc_disable __devinitdata = 0;
++#endif
++
++static void delay_tsc(unsigned long loops)
++{
++ unsigned long bclock, now;
++
++ rdtscl(bclock);
++ do {
++ rep_nop();
++ rdtscl(now);
++ } while ((now - bclock) < loops);
++}
++
++struct timer_opts timer_tsc = {
++ .name = "tsc",
++ .delay = delay_tsc,
++};
++
++/*
++ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
++ * yielding a 64-bit result.
++ */
++static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
++{
++ u64 product;
++#ifdef __i386__
++ u32 tmp1, tmp2;
++#endif
++
++ if (shift < 0)
++ delta >>= -shift;
++ else
++ delta <<= shift;
++
++#ifdef __i386__
++ __asm__ (
++ "mul %5 ; "
++ "mov %4,%%eax ; "
++ "mov %%edx,%4 ; "
++ "mul %5 ; "
++ "xor %5,%5 ; "
++ "add %4,%%eax ; "
++ "adc %5,%%edx ; "
++ : "=A" (product), "=r" (tmp1), "=r" (tmp2)
++ : "a" ((u32)delta), "1" ((u32)(delta >> US_SCALE)), "2" (mul_frac) );
++#else
++ __asm__ (
++ "mul %%rdx ; shrd $32,%%rdx,%%rax"
++ : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
++#endif
++
++ return product;
++}
++
++#if defined (__i386__)
++int read_current_timer(unsigned long *timer_val)
++{
++ rdtscl(*timer_val);
++ return 0;
++}
++#endif
++
++void init_cpu_khz(void)
++{
++ u64 __cpu_khz = 1000000ULL << US_SCALE;
++ struct vcpu_time_info *info;
++ info = &HYPERVISOR_shared_info->vcpu_info[0].time;
++ do_div(__cpu_khz, info->tsc_to_system_mul);
++ if (info->tsc_shift < 0)
++ cpu_khz = __cpu_khz << -info->tsc_shift;
++ else
++ cpu_khz = __cpu_khz >> info->tsc_shift;
++}
++
++static u64 get_nsec_offset(struct shadow_time_info *shadow)
++{
++ u64 now, delta;
++ rdtscll(now);
++ delta = now - shadow->tsc_timestamp;
++ return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
++}
++
++static unsigned long get_usec_offset(struct shadow_time_info *shadow)
++{
++ u64 now, delta;
++ rdtscll(now);
++ delta = now - shadow->tsc_timestamp;
++ return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift);
++}
++
++static void __update_wallclock(time_t sec, long nsec)
++{
++ long wtm_nsec, xtime_nsec;
++ time_t wtm_sec, xtime_sec;
++ u64 tmp, wc_nsec;
++
++ /* Adjust wall-clock time base based on wall_jiffies ticks. */
++ wc_nsec = processed_system_time;
++ wc_nsec += sec * (u64)NSEC_PER_SEC;
++ wc_nsec += nsec;
++ wc_nsec -= (jiffies - wall_jiffies) * (u64)NS_PER_TICK;
++
++ /* Split wallclock base into seconds and nanoseconds. */
++ tmp = wc_nsec;
++ xtime_nsec = do_div(tmp, 1000000000);
++ xtime_sec = (time_t)tmp;
++
++ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
++ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
++
++ set_normalized_timespec(&xtime, xtime_sec, xtime_nsec);
++ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
++
++ ntp_clear();
++}
++
++static void update_wallclock(void)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++
++ do {
++ shadow_tv_version = s->wc_version;
++ rmb();
++ shadow_tv.tv_sec = s->wc_sec;
++ shadow_tv.tv_nsec = s->wc_nsec;
++ rmb();
++ } while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
++
++ if (!independent_wallclock)
++ __update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec);
++}
++
++/*
++ * Reads a consistent set of time-base values from Xen, into a shadow data
++ * area.
++ */
++static void get_time_values_from_xen(void)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++ struct vcpu_time_info *src;
++ struct shadow_time_info *dst;
++
++ src = &s->vcpu_info[smp_processor_id()].time;
++ dst = &per_cpu(shadow_time, smp_processor_id());
++
++ do {
++ dst->version = src->version;
++ rmb();
++ dst->tsc_timestamp = src->tsc_timestamp;
++ dst->system_timestamp = src->system_time;
++ dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
++ dst->tsc_shift = src->tsc_shift;
++ rmb();
++ } while ((src->version & 1) | (dst->version ^ src->version));
++
++ dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
++}
++
++static inline int time_values_up_to_date(int cpu)
++{
++ struct vcpu_time_info *src;
++ struct shadow_time_info *dst;
++
++ src = &HYPERVISOR_shared_info->vcpu_info[cpu].time;
++ dst = &per_cpu(shadow_time, cpu);
++
++ rmb();
++ return (dst->version == src->version);
++}
++
++/*
++ * This is a special lock that is owned by the CPU and holds the index
++ * register we are working with. It is required for NMI access to the
++ * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details.
++ */
++volatile unsigned long cmos_lock = 0;
++EXPORT_SYMBOL(cmos_lock);
++
++/* Routines for accessing the CMOS RAM/RTC. */
++unsigned char rtc_cmos_read(unsigned char addr)
++{
++ unsigned char val;
++ lock_cmos_prefix(addr);
++ outb_p(addr, RTC_PORT(0));
++ val = inb_p(RTC_PORT(1));
++ lock_cmos_suffix(addr);
++ return val;
++}
++EXPORT_SYMBOL(rtc_cmos_read);
++
++void rtc_cmos_write(unsigned char val, unsigned char addr)
++{
++ lock_cmos_prefix(addr);
++ outb_p(addr, RTC_PORT(0));
++ outb_p(val, RTC_PORT(1));
++ lock_cmos_suffix(addr);
++}
++EXPORT_SYMBOL(rtc_cmos_write);
++
++/*
++ * This version of gettimeofday has microsecond resolution
++ * and better than microsecond precision on fast x86 machines with TSC.
++ */
++void do_gettimeofday(struct timeval *tv)
++{
++ unsigned long seq;
++ unsigned long usec, sec;
++ unsigned long max_ntp_tick;
++ s64 nsec;
++ unsigned int cpu;
++ struct shadow_time_info *shadow;
++ u32 local_time_version;
++
++ cpu = get_cpu();
++ shadow = &per_cpu(shadow_time, cpu);
++
++ do {
++ unsigned long lost;
++
++ local_time_version = shadow->version;
++ seq = read_seqbegin(&xtime_lock);
++
++ usec = get_usec_offset(shadow);
++ lost = jiffies - wall_jiffies;
++
++ /*
++ * If time_adjust is negative then NTP is slowing the clock
++ * so make sure not to go into next possible interval.
++ * Better to lose some accuracy than have time go backwards..
++ */
++ if (unlikely(time_adjust < 0)) {
++ max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;
++ usec = min(usec, max_ntp_tick);
++
++ if (lost)
++ usec += lost * max_ntp_tick;
++ }
++ else if (unlikely(lost))
++ usec += lost * (USEC_PER_SEC / HZ);
++
++ sec = xtime.tv_sec;
++ usec += (xtime.tv_nsec / NSEC_PER_USEC);
++
++ nsec = shadow->system_timestamp - processed_system_time;
++ __normalize_time(&sec, &nsec);
++ usec += (long)nsec / NSEC_PER_USEC;
++
++ if (unlikely(!time_values_up_to_date(cpu))) {
++ /*
++ * We may have blocked for a long time,
++ * rendering our calculations invalid
++ * (e.g. the time delta may have
++ * overflowed). Detect that and recalculate
++ * with fresh values.
++ */
++ get_time_values_from_xen();
++ continue;
++ }
++ } while (read_seqretry(&xtime_lock, seq) ||
++ (local_time_version != shadow->version));
++
++ put_cpu();
++
++ while (usec >= USEC_PER_SEC) {
++ usec -= USEC_PER_SEC;
++ sec++;
++ }
++
++ tv->tv_sec = sec;
++ tv->tv_usec = usec;
++}
++
++EXPORT_SYMBOL(do_gettimeofday);
++
++int do_settimeofday(struct timespec *tv)
++{
++ time_t sec;
++ s64 nsec;
++ unsigned int cpu;
++ struct shadow_time_info *shadow;
++ dom0_op_t op;
++
++ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
++ return -EINVAL;
++
++ cpu = get_cpu();
++ shadow = &per_cpu(shadow_time, cpu);
++
++ write_seqlock_irq(&xtime_lock);
++
++ /*
++ * Ensure we don't get blocked for a long time so that our time delta
++ * overflows. If that were to happen then our shadow time values would
++ * be stale, so we can retry with fresh ones.
++ */
++ for (;;) {
++ nsec = tv->tv_nsec - get_nsec_offset(shadow);
++ if (time_values_up_to_date(cpu))
++ break;
++ get_time_values_from_xen();
++ }
++ sec = tv->tv_sec;
++ __normalize_time(&sec, &nsec);
++
++ if (is_initial_xendomain() && !independent_wallclock) {
++ op.cmd = DOM0_SETTIME;
++ op.u.settime.secs = sec;
++ op.u.settime.nsecs = nsec;
++ op.u.settime.system_time = shadow->system_timestamp;
++ HYPERVISOR_dom0_op(&op);
++ update_wallclock();
++ } else if (independent_wallclock) {
++ nsec -= shadow->system_timestamp;
++ __normalize_time(&sec, &nsec);
++ __update_wallclock(sec, nsec);
++ }
++
++ write_sequnlock_irq(&xtime_lock);
++
++ put_cpu();
++
++ clock_was_set();
++ return 0;
++}
++
++EXPORT_SYMBOL(do_settimeofday);
++
++static void sync_xen_wallclock(unsigned long dummy);
++static DEFINE_TIMER(sync_xen_wallclock_timer, sync_xen_wallclock, 0, 0);
++static void sync_xen_wallclock(unsigned long dummy)
++{
++ time_t sec;
++ s64 nsec;
++ dom0_op_t op;
++
++ if (!ntp_synced() || independent_wallclock || !is_initial_xendomain())
++ return;
++
++ write_seqlock_irq(&xtime_lock);
++
++ sec = xtime.tv_sec;
++ nsec = xtime.tv_nsec + ((jiffies - wall_jiffies) * (u64)NS_PER_TICK);
++ __normalize_time(&sec, &nsec);
++
++ op.cmd = DOM0_SETTIME;
++ op.u.settime.secs = sec;
++ op.u.settime.nsecs = nsec;
++ op.u.settime.system_time = processed_system_time;
++ HYPERVISOR_dom0_op(&op);
++
++ update_wallclock();
++
++ write_sequnlock_irq(&xtime_lock);
++
++ /* Once per minute. */
++ mod_timer(&sync_xen_wallclock_timer, jiffies + 60*HZ);
++}
++
++static int set_rtc_mmss(unsigned long nowtime)
++{
++ int retval;
++ unsigned long flags;
++
++ if (independent_wallclock || !is_initial_xendomain())
++ return 0;
++
++ /* gets recalled with irq locally disabled */
++ spin_lock_irqsave(&rtc_lock, flags);
++ if (efi_enabled)
++ retval = efi_set_rtc_mmss(nowtime);
++ else
++ retval = mach_set_rtc_mmss(nowtime);
++ spin_unlock_irqrestore(&rtc_lock, flags);
++
++ return retval;
++}
++
++/* monotonic_clock(): returns # of nanoseconds passed since time_init()
++ * Note: This function is required to return accurate
++ * time even in the absence of multiple timer ticks.
++ */
++unsigned long long monotonic_clock(void)
++{
++ int cpu = get_cpu();
++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
++ u64 time;
++ u32 local_time_version;
++
++ do {
++ local_time_version = shadow->version;
++ barrier();
++ time = shadow->system_timestamp + get_nsec_offset(shadow);
++ if (!time_values_up_to_date(cpu))
++ get_time_values_from_xen();
++ barrier();
++ } while (local_time_version != shadow->version);
++
++ put_cpu();
++
++ return time;
++}
++EXPORT_SYMBOL(monotonic_clock);
++
++unsigned long long sched_clock(void)
++{
++ return monotonic_clock();
++}
++
++#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
++unsigned long profile_pc(struct pt_regs *regs)
++{
++ unsigned long pc = instruction_pointer(regs);
++
++#ifdef __x86_64__
++ /* Assume the lock function has either no stack frame or only a single word.
++ This checks if the address on the stack looks like a kernel text address.
++ There is a small window for false hits, but in that case the tick
++ is just accounted to the spinlock function.
++ Better would be to write these functions in assembler again
++ and check exactly. */
++ if (!user_mode_vm(regs) && in_lock_functions(pc)) {
++ char *v = *(char **)regs->rsp;
++ if ((v >= _stext && v <= _etext) ||
++ (v >= _sinittext && v <= _einittext) ||
++ (v >= (char *)MODULES_VADDR && v <= (char *)MODULES_END))
++ return (unsigned long)v;
++ return ((unsigned long *)regs->rsp)[1];
++ }
++#else
++ if (!user_mode_vm(regs) && in_lock_functions(pc))
++ return *(unsigned long *)(regs->ebp + 4);
++#endif
++
++ return pc;
++}
++EXPORT_SYMBOL(profile_pc);
++#endif
++
++irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ s64 delta, delta_cpu, stolen, blocked;
++ u64 sched_time;
++ int i, cpu = smp_processor_id();
++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
++
++ write_seqlock(&xtime_lock);
++
++ do {
++ get_time_values_from_xen();
++
++ /* Obtain a consistent snapshot of elapsed wallclock cycles. */
++ delta = delta_cpu =
++ shadow->system_timestamp + get_nsec_offset(shadow);
++ delta -= processed_system_time;
++ delta_cpu -= per_cpu(processed_system_time, cpu);
++
++ /*
++ * Obtain a consistent snapshot of stolen/blocked cycles. We
++ * can use state_entry_time to detect if we get preempted here.
++ */
++ do {
++ sched_time = runstate->state_entry_time;
++ barrier();
++ stolen = runstate->time[RUNSTATE_runnable] +
++ runstate->time[RUNSTATE_offline] -
++ per_cpu(processed_stolen_time, cpu);
++ blocked = runstate->time[RUNSTATE_blocked] -
++ per_cpu(processed_blocked_time, cpu);
++ barrier();
++ } while (sched_time != runstate->state_entry_time);
++ } while (!time_values_up_to_date(cpu));
++
++ if ((unlikely(delta < -(s64)permitted_clock_jitter) ||
++ unlikely(delta_cpu < -(s64)permitted_clock_jitter))
++ && printk_ratelimit()) {
++ printk("Timer ISR/%d: Time went backwards: "
++ "delta=%lld delta_cpu=%lld shadow=%lld "
++ "off=%lld processed=%lld cpu_processed=%lld\n",
++ cpu, delta, delta_cpu, shadow->system_timestamp,
++ (s64)get_nsec_offset(shadow),
++ processed_system_time,
++ per_cpu(processed_system_time, cpu));
++ for (i = 0; i < num_online_cpus(); i++)
++ printk(" %d: %lld\n", i,
++ per_cpu(processed_system_time, i));
++ }
++
++ /* System-wide jiffy work. */
++ while (delta >= NS_PER_TICK) {
++ delta -= NS_PER_TICK;
++ processed_system_time += NS_PER_TICK;
++ do_timer(regs);
++ }
++
++ if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
++ update_wallclock();
++ clock_was_set();
++ }
++
++ write_sequnlock(&xtime_lock);
++
++ /*
++ * Account stolen ticks.
++ * HACK: Passing NULL to account_steal_time()
++ * ensures that the ticks are accounted as stolen.
++ */
++ if ((stolen > 0) && (delta_cpu > 0)) {
++ delta_cpu -= stolen;
++ if (unlikely(delta_cpu < 0))
++ stolen += delta_cpu; /* clamp local-time progress */
++ do_div(stolen, NS_PER_TICK);
++ per_cpu(processed_stolen_time, cpu) += stolen * NS_PER_TICK;
++ per_cpu(processed_system_time, cpu) += stolen * NS_PER_TICK;
++ account_steal_time(NULL, (cputime_t)stolen);
++ }
++
++ /*
++ * Account blocked ticks.
++ * HACK: Passing idle_task to account_steal_time()
++ * ensures that the ticks are accounted as idle/wait.
++ */
++ if ((blocked > 0) && (delta_cpu > 0)) {
++ delta_cpu -= blocked;
++ if (unlikely(delta_cpu < 0))
++ blocked += delta_cpu; /* clamp local-time progress */
++ do_div(blocked, NS_PER_TICK);
++ per_cpu(processed_blocked_time, cpu) += blocked * NS_PER_TICK;
++ per_cpu(processed_system_time, cpu) += blocked * NS_PER_TICK;
++ account_steal_time(idle_task(cpu), (cputime_t)blocked);
++ }
++
++ /* Account user/system ticks. */
++ if (delta_cpu > 0) {
++ do_div(delta_cpu, NS_PER_TICK);
++ per_cpu(processed_system_time, cpu) += delta_cpu * NS_PER_TICK;
++ if (user_mode(regs))
++ account_user_time(current, (cputime_t)delta_cpu);
++ else
++ account_system_time(current, HARDIRQ_OFFSET,
++ (cputime_t)delta_cpu);
++ }
++
++ /* Local timer processing (see update_process_times()). */
++ run_local_timers();
++ if (rcu_pending(cpu))
++ rcu_check_callbacks(cpu, user_mode(regs));
++ scheduler_tick();
++ run_posix_cpu_timers(current);
++
++ return IRQ_HANDLED;
++}
++
++static void init_missing_ticks_accounting(int cpu)
++{
++ struct vcpu_register_runstate_memory_area area;
++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
++
++ memset(runstate, 0, sizeof(*runstate));
++
++ area.addr.v = runstate;
++ HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area);
++
++ per_cpu(processed_blocked_time, cpu) =
++ runstate->time[RUNSTATE_blocked];
++ per_cpu(processed_stolen_time, cpu) =
++ runstate->time[RUNSTATE_runnable] +
++ runstate->time[RUNSTATE_offline];
++}
++
++/* not static: needed by APM */
++unsigned long get_cmos_time(void)
++{
++ unsigned long retval;
++ unsigned long flags;
++
++ spin_lock_irqsave(&rtc_lock, flags);
++
++ if (efi_enabled)
++ retval = efi_get_time();
++ else
++ retval = mach_get_cmos_time();
++
++ spin_unlock_irqrestore(&rtc_lock, flags);
++
++ return retval;
++}
++EXPORT_SYMBOL(get_cmos_time);
++
++static void sync_cmos_clock(unsigned long dummy);
++
++static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
++
++static void sync_cmos_clock(unsigned long dummy)
++{
++ struct timeval now, next;
++ int fail = 1;
++
++ /*
++ * If we have an externally synchronized Linux clock, then update
++ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
++ * called as close as possible to 500 ms before the new second starts.
++ * This code is run on a timer. If the clock is set, that timer
++ * may not expire at the correct time. Thus, we adjust...
++ */
++ if (!ntp_synced())
++ /*
++ * Not synced, exit, do not restart a timer (if one is
++ * running, let it run out).
++ */
++ return;
++
++ do_gettimeofday(&now);
++ if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
++ now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
++ fail = set_rtc_mmss(now.tv_sec);
++
++ next.tv_usec = USEC_AFTER - now.tv_usec;
++ if (next.tv_usec <= 0)
++ next.tv_usec += USEC_PER_SEC;
++
++ if (!fail)
++ next.tv_sec = 659;
++ else
++ next.tv_sec = 0;
++
++ if (next.tv_usec >= USEC_PER_SEC) {
++ next.tv_sec++;
++ next.tv_usec -= USEC_PER_SEC;
++ }
++ mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
++}
++
++void notify_arch_cmos_timer(void)
++{
++ mod_timer(&sync_cmos_timer, jiffies + 1);
++ mod_timer(&sync_xen_wallclock_timer, jiffies + 1);
++}
++
++static long clock_cmos_diff, sleep_start;
++
++static int timer_suspend(struct sys_device *dev, pm_message_t state)
++{
++ /*
++ * Estimate time zone so that set_time can update the clock
++ */
++ clock_cmos_diff = -get_cmos_time();
++ clock_cmos_diff += get_seconds();
++ sleep_start = get_cmos_time();
++ return 0;
++}
++
++static int timer_resume(struct sys_device *dev)
++{
++ unsigned long flags;
++ unsigned long sec;
++ unsigned long sleep_length;
++
++#ifdef CONFIG_HPET_TIMER
++ if (is_hpet_enabled())
++ hpet_reenable();
++#endif
++ sec = get_cmos_time() + clock_cmos_diff;
++ sleep_length = (get_cmos_time() - sleep_start) * HZ;
++ write_seqlock_irqsave(&xtime_lock, flags);
++ xtime.tv_sec = sec;
++ xtime.tv_nsec = 0;
++ jiffies_64 += sleep_length;
++ wall_jiffies += sleep_length;
++ write_sequnlock_irqrestore(&xtime_lock, flags);
++ touch_softlockup_watchdog();
++ return 0;
++}
++
++static struct sysdev_class timer_sysclass = {
++ .resume = timer_resume,
++ .suspend = timer_suspend,
++ set_kset_name("timer"),
++};
++
++
++/* XXX this driverfs stuff should probably go elsewhere later -john */
++static struct sys_device device_timer = {
++ .id = 0,
++ .cls = &timer_sysclass,
++};
++
++static int time_init_device(void)
++{
++ int error = sysdev_class_register(&timer_sysclass);
++ if (!error)
++ error = sysdev_register(&device_timer);
++ return error;
++}
++
++device_initcall(time_init_device);
++
++#ifdef CONFIG_HPET_TIMER
++extern void (*late_time_init)(void);
++/* Duplicate of time_init() below, with hpet_enable part added */
++static void __init hpet_time_init(void)
++{
++ xtime.tv_sec = get_cmos_time();
++ xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
++ set_normalized_timespec(&wall_to_monotonic,
++ -xtime.tv_sec, -xtime.tv_nsec);
++
++ if ((hpet_enable() >= 0) && hpet_use_timer) {
++ printk("Using HPET for base-timer\n");
++ }
++ time_init_hook();
++}
++#endif
++
++/* Dynamically-mapped IRQ. */
++DEFINE_PER_CPU(int, timer_irq);
++
++extern void (*late_time_init)(void);
++static void setup_cpu0_timer_irq(void)
++{
++ per_cpu(timer_irq, 0) =
++ bind_virq_to_irqhandler(
++ VIRQ_TIMER,
++ 0,
++ timer_interrupt,
++ SA_INTERRUPT,
++ "timer0",
++ NULL);
++ BUG_ON(per_cpu(timer_irq, 0) < 0);
++}
++
++void __init time_init(void)
++{
++#ifdef CONFIG_HPET_TIMER
++ if (is_hpet_capable()) {
++ /*
++ * HPET initialization needs to do memory-mapped io. So, let
++ * us do a late initialization after mem_init().
++ */
++ late_time_init = hpet_time_init;
++ return;
++ }
++#endif
++ get_time_values_from_xen();
++
++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
++ per_cpu(processed_system_time, 0) = processed_system_time;
++ init_missing_ticks_accounting(0);
++
++ update_wallclock();
++
++ init_cpu_khz();
++ printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n",
++ cpu_khz / 1000, cpu_khz % 1000);
++
++#if defined(__x86_64__)
++ vxtime.mode = VXTIME_TSC;
++ vxtime.quot = (1000000L << US_SCALE) / vxtime_hz;
++ vxtime.tsc_quot = (1000L << US_SCALE) / cpu_khz;
++ sync_core();
++ rdtscll(vxtime.last_tsc);
++#endif
++
++ /* Cannot request_irq() until kmem is initialised. */
++ late_time_init = setup_cpu0_timer_irq;
++}
++
++/* Convert jiffies to system time. */
++u64 jiffies_to_st(unsigned long j)
++{
++ unsigned long seq;
++ long delta;
++ u64 st;
++
++ do {
++ seq = read_seqbegin(&xtime_lock);
++ delta = j - jiffies;
++ if (delta < 1) {
++ /* Triggers in some wrap-around cases, but that's okay:
++ * we just end up with a shorter timeout. */
++ st = processed_system_time + NS_PER_TICK;
++ } else if (((unsigned long)delta >> (BITS_PER_LONG-3)) != 0) {
++ /* Very long timeout means there is no pending timer.
++ * We indicate this to Xen by passing zero timeout. */
++ st = 0;
++ } else {
++ st = processed_system_time + delta * (u64)NS_PER_TICK;
++ }
++ } while (read_seqretry(&xtime_lock, seq));
++
++ return st;
++}
++EXPORT_SYMBOL(jiffies_to_st);
++
++/*
++ * stop_hz_timer / start_hz_timer - enter/exit 'tickless mode' on an idle cpu
++ * These functions are based on implementations from arch/s390/kernel/time.c
++ */
++static void stop_hz_timer(void)
++{
++ unsigned int cpu = smp_processor_id();
++ unsigned long j;
++
++ cpu_set(cpu, nohz_cpu_mask);
++
++ /* See matching smp_mb in rcu_start_batch in rcupdate.c. These mbs */
++ /* ensure that if __rcu_pending (nested in rcu_needs_cpu) fetches a */
++ /* value of rcp->cur that matches rdp->quiescbatch and allows us to */
++ /* stop the hz timer then the cpumasks created for subsequent values */
++ /* of cur in rcu_start_batch are guaranteed to pick up the updated */
++ /* nohz_cpu_mask and so will not depend on this cpu. */
++
++ smp_mb();
++
++ /* Leave ourselves in tick mode if rcu or softirq or timer pending. */
++ if (rcu_needs_cpu(cpu) || local_softirq_pending() ||
++ (j = next_timer_interrupt(), time_before_eq(j, jiffies))) {
++ cpu_clear(cpu, nohz_cpu_mask);
++ j = jiffies + 1;
++ }
++
++ if (HYPERVISOR_set_timer_op(jiffies_to_st(j)) != 0)
++ BUG();
++}
++
++static void start_hz_timer(void)
++{
++ cpu_clear(smp_processor_id(), nohz_cpu_mask);
++}
++
++void raw_safe_halt(void)
++{
++ stop_hz_timer();
++ /* Blocking includes an implicit local_irq_enable(). */
++ HYPERVISOR_block();
++ start_hz_timer();
++}
++EXPORT_SYMBOL(raw_safe_halt);
++
++void halt(void)
++{
++ if (irqs_disabled())
++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
++}
++EXPORT_SYMBOL(halt);
++
++/* No locking required. We are only CPU running, and interrupts are off. */
++void time_resume(void)
++{
++ init_cpu_khz();
++
++ get_time_values_from_xen();
++
++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
++ per_cpu(processed_system_time, 0) = processed_system_time;
++ init_missing_ticks_accounting(0);
++
++ update_wallclock();
++}
++
++#ifdef CONFIG_SMP
++static char timer_name[NR_CPUS][15];
++
++void local_setup_timer(unsigned int cpu)
++{
++ int seq;
++
++ BUG_ON(cpu == 0);
++
++ do {
++ seq = read_seqbegin(&xtime_lock);
++ /* Use cpu0 timestamp: cpu's shadow is not initialised yet. */
++ per_cpu(processed_system_time, cpu) =
++ per_cpu(shadow_time, 0).system_timestamp;
++ init_missing_ticks_accounting(cpu);
++ } while (read_seqretry(&xtime_lock, seq));
++
++ sprintf(timer_name[cpu], "timer%d", cpu);
++ per_cpu(timer_irq, cpu) =
++ bind_virq_to_irqhandler(
++ VIRQ_TIMER,
++ cpu,
++ timer_interrupt,
++ SA_INTERRUPT,
++ timer_name[cpu],
++ NULL);
++ BUG_ON(per_cpu(timer_irq, cpu) < 0);
++}
++
++void local_teardown_timer(unsigned int cpu)
++{
++ BUG_ON(cpu == 0);
++ unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL);
++}
++#endif
++
++/*
++ * /proc/sys/xen: This really belongs in another file. It can stay here for
++ * now however.
++ */
++static ctl_table xen_subtable[] = {
++ {
++ .ctl_name = 1,
++ .procname = "independent_wallclock",
++ .data = &independent_wallclock,
++ .maxlen = sizeof(independent_wallclock),
++ .mode = 0644,
++ .proc_handler = proc_dointvec
++ },
++ {
++ .ctl_name = 2,
++ .procname = "permitted_clock_jitter",
++ .data = &permitted_clock_jitter,
++ .maxlen = sizeof(permitted_clock_jitter),
++ .mode = 0644,
++ .proc_handler = proc_doulongvec_minmax
++ },
++ { 0 }
++};
++static ctl_table xen_table[] = {
++ {
++ .ctl_name = 123,
++ .procname = "xen",
++ .mode = 0555,
++ .child = xen_subtable},
++ { 0 }
++};
++static int __init xen_sysctl_init(void)
++{
++ (void)register_sysctl_table(xen_table, 0);
++ return 0;
++}
++__initcall(xen_sysctl_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/traps.c linux-2.6.18-xen/arch/i386/kernel/traps.c
+--- linux-2.6.18.1/arch/i386/kernel/traps.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/traps.c 2006-09-04 16:31:00.000000000 +0200
+@@ -642,18 +642,11 @@
+
+ static void io_check_error(unsigned char reason, struct pt_regs * regs)
+ {
+- unsigned long i;
+-
+ printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
+ show_registers(regs);
+
+ /* Re-enable the IOCK line, wait for a few seconds */
+- reason = (reason & 0xf) | 8;
+- outb(reason, 0x61);
+- i = 2000;
+- while (--i) udelay(1000);
+- reason &= ~8;
+- outb(reason, 0x61);
++ clear_io_check_error(reason);
+ }
+
+ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/traps-xen.c linux-2.6.18-xen/arch/i386/kernel/traps-xen.c
+--- linux-2.6.18.1/arch/i386/kernel/traps-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/traps-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,1184 @@
++/*
++ * linux/arch/i386/traps.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Pentium III FXSR, SSE support
++ * Gareth Hughes <gareth at valinux.com>, May 2000
++ */
++
++/*
++ * 'Traps.c' handles hardware traps and faults after we have saved some
++ * state in 'asm.s'.
++ */
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/highmem.h>
++#include <linux/kallsyms.h>
++#include <linux/ptrace.h>
++#include <linux/utsname.h>
++#include <linux/kprobes.h>
++#include <linux/kexec.h>
++#include <linux/unwind.h>
++
++#ifdef CONFIG_EISA
++#include <linux/ioport.h>
++#include <linux/eisa.h>
++#endif
++
++#ifdef CONFIG_MCA
++#include <linux/mca.h>
++#endif
++
++#include <asm/processor.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/debugreg.h>
++#include <asm/desc.h>
++#include <asm/i387.h>
++#include <asm/nmi.h>
++#include <asm/unwind.h>
++#include <asm/smp.h>
++#include <asm/arch_hooks.h>
++#include <asm/kdebug.h>
++
++#include <linux/module.h>
++
++#include "mach_traps.h"
++
++asmlinkage int system_call(void);
++
++struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
++ { 0, 0 }, { 0, 0 } };
++
++/* Do we ignore FPU interrupts ? */
++char ignore_fpu_irq = 0;
++
++#ifndef CONFIG_X86_NO_IDT
++/*
++ * The IDT has to be page-aligned to simplify the Pentium
++ * F0 0F bug workaround.. We have a special link segment
++ * for this.
++ */
++struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
++#endif
++
++asmlinkage void divide_error(void);
++asmlinkage void debug(void);
++asmlinkage void nmi(void);
++asmlinkage void int3(void);
++asmlinkage void overflow(void);
++asmlinkage void bounds(void);
++asmlinkage void invalid_op(void);
++asmlinkage void device_not_available(void);
++asmlinkage void coprocessor_segment_overrun(void);
++asmlinkage void invalid_TSS(void);
++asmlinkage void segment_not_present(void);
++asmlinkage void stack_segment(void);
++asmlinkage void general_protection(void);
++asmlinkage void page_fault(void);
++asmlinkage void coprocessor_error(void);
++asmlinkage void simd_coprocessor_error(void);
++asmlinkage void alignment_check(void);
++#ifndef CONFIG_XEN
++asmlinkage void spurious_interrupt_bug(void);
++#else
++asmlinkage void fixup_4gb_segment(void);
++#endif
++asmlinkage void machine_check(void);
++
++static int kstack_depth_to_print = 24;
++#ifdef CONFIG_STACK_UNWIND
++static int call_trace = 1;
++#else
++#define call_trace (-1)
++#endif
++ATOMIC_NOTIFIER_HEAD(i386die_chain);
++
++int register_die_notifier(struct notifier_block *nb)
++{
++ vmalloc_sync_all();
++ return atomic_notifier_chain_register(&i386die_chain, nb);
++}
++EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */
++
++int unregister_die_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(&i386die_chain, nb);
++}
++EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */
++
++static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
++{
++ return p > (void *)tinfo &&
++ p < (void *)tinfo + THREAD_SIZE - 3;
++}
++
++/*
++ * Print one address/symbol entries per line.
++ */
++static inline void print_addr_and_symbol(unsigned long addr, char *log_lvl)
++{
++ printk(" [<%08lx>] ", addr);
++
++ print_symbol("%s\n", addr);
++}
++
++static inline unsigned long print_context_stack(struct thread_info *tinfo,
++ unsigned long *stack, unsigned long ebp,
++ char *log_lvl)
++{
++ unsigned long addr;
++
++#ifdef CONFIG_FRAME_POINTER
++ while (valid_stack_ptr(tinfo, (void *)ebp)) {
++ addr = *(unsigned long *)(ebp + 4);
++ print_addr_and_symbol(addr, log_lvl);
++ /*
++ * break out of recursive entries (such as
++ * end_of_stack_stop_unwind_function):
++ */
++ if (ebp == *(unsigned long *)ebp)
++ break;
++ ebp = *(unsigned long *)ebp;
++ }
++#else
++ while (valid_stack_ptr(tinfo, stack)) {
++ addr = *stack++;
++ if (__kernel_text_address(addr))
++ print_addr_and_symbol(addr, log_lvl);
++ }
++#endif
++ return ebp;
++}
++
++static asmlinkage int
++show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
++{
++ int n = 0;
++
++ while (unwind(info) == 0 && UNW_PC(info)) {
++ n++;
++ print_addr_and_symbol(UNW_PC(info), log_lvl);
++ if (arch_unw_user_mode(info))
++ break;
++ }
++ return n;
++}
++
++static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
++ unsigned long *stack, char *log_lvl)
++{
++ unsigned long ebp;
++
++ if (!task)
++ task = current;
++
++ if (call_trace >= 0) {
++ int unw_ret = 0;
++ struct unwind_frame_info info;
++
++ if (regs) {
++ if (unwind_init_frame_info(&info, task, regs) == 0)
++ unw_ret = show_trace_unwind(&info, log_lvl);
++ } else if (task == current)
++ unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl);
++ else {
++ if (unwind_init_blocked(&info, task) == 0)
++ unw_ret = show_trace_unwind(&info, log_lvl);
++ }
++ if (unw_ret > 0) {
++ if (call_trace == 1 && !arch_unw_user_mode(&info)) {
++ print_symbol("DWARF2 unwinder stuck at %s\n",
++ UNW_PC(&info));
++ if (UNW_SP(&info) >= PAGE_OFFSET) {
++ printk("Leftover inexact backtrace:\n");
++ stack = (void *)UNW_SP(&info);
++ } else
++ printk("Full inexact backtrace again:\n");
++ } else if (call_trace >= 1)
++ return;
++ } else
++ printk("Full inexact backtrace again:\n");
++ printk("Inexact backtrace:\n");
++ }
++
++ if (task == current) {
++ /* Grab ebp right from our regs */
++ asm ("movl %%ebp, %0" : "=r" (ebp) : );
++ } else {
++ /* ebp is the last reg pushed by switch_to */
++ ebp = *(unsigned long *) task->thread.esp;
++ }
++
++ while (1) {
++ struct thread_info *context;
++ context = (struct thread_info *)
++ ((unsigned long)stack & (~(THREAD_SIZE - 1)));
++ ebp = print_context_stack(context, stack, ebp, log_lvl);
++ stack = (unsigned long*)context->previous_esp;
++ if (!stack)
++ break;
++ printk("%s =======================\n", log_lvl);
++ }
++}
++
++void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long * stack)
++{
++ show_trace_log_lvl(task, regs, stack, "");
++}
++
++static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
++ unsigned long *esp, char *log_lvl)
++{
++ unsigned long *stack;
++ int i;
++
++ if (esp == NULL) {
++ if (task)
++ esp = (unsigned long*)task->thread.esp;
++ else
++ esp = (unsigned long *)&esp;
++ }
++
++ stack = esp;
++ for(i = 0; i < kstack_depth_to_print; i++) {
++ if (kstack_end(stack))
++ break;
++ if (i && ((i % 8) == 0))
++ printk("\n%s ", log_lvl);
++ printk("%08lx ", *stack++);
++ }
++ printk("\n%sCall Trace:\n", log_lvl);
++ show_trace_log_lvl(task, regs, esp, log_lvl);
++}
++
++void show_stack(struct task_struct *task, unsigned long *esp)
++{
++ printk(" ");
++ show_stack_log_lvl(task, NULL, esp, "");
++}
++
++/*
++ * The architecture-independent dump_stack generator
++ */
++void dump_stack(void)
++{
++ unsigned long stack;
++
++ show_trace(current, NULL, &stack);
++}
++
++EXPORT_SYMBOL(dump_stack);
++
++void show_registers(struct pt_regs *regs)
++{
++ int i;
++ int in_kernel = 1;
++ unsigned long esp;
++ unsigned short ss;
++
++ esp = (unsigned long) (®s->esp);
++ savesegment(ss, ss);
++ if (user_mode_vm(regs)) {
++ in_kernel = 0;
++ esp = regs->esp;
++ ss = regs->xss & 0xffff;
++ }
++ print_modules();
++ printk(KERN_EMERG "CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\n"
++ "EFLAGS: %08lx (%s %.*s) \n",
++ smp_processor_id(), 0xffff & regs->xcs, regs->eip,
++ print_tainted(), regs->eflags, system_utsname.release,
++ (int)strcspn(system_utsname.version, " "),
++ system_utsname.version);
++ print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip);
++ printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
++ regs->eax, regs->ebx, regs->ecx, regs->edx);
++ printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
++ regs->esi, regs->edi, regs->ebp, esp);
++ printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n",
++ regs->xds & 0xffff, regs->xes & 0xffff, ss);
++ printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
++ TASK_COMM_LEN, current->comm, current->pid,
++ current_thread_info(), current, current->thread_info);
++ /*
++ * When in-kernel, we also print out the stack and code at the
++ * time of the fault..
++ */
++ if (in_kernel) {
++ u8 __user *eip;
++
++ printk("\n" KERN_EMERG "Stack: ");
++ show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG);
++
++ printk(KERN_EMERG "Code: ");
++
++ eip = (u8 __user *)regs->eip - 43;
++ for (i = 0; i < 64; i++, eip++) {
++ unsigned char c;
++
++ if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
++ printk(" Bad EIP value.");
++ break;
++ }
++ if (eip == (u8 __user *)regs->eip)
++ printk("<%02x> ", c);
++ else
++ printk("%02x ", c);
++ }
++ }
++ printk("\n");
++}
++
++static void handle_BUG(struct pt_regs *regs)
++{
++ unsigned long eip = regs->eip;
++ unsigned short ud2;
++
++ if (eip < PAGE_OFFSET)
++ return;
++ if (__get_user(ud2, (unsigned short __user *)eip))
++ return;
++ if (ud2 != 0x0b0f)
++ return;
++
++ printk(KERN_EMERG "------------[ cut here ]------------\n");
++#ifdef CONFIG_DEBUG_BUGVERBOSE
++ do {
++ unsigned short line;
++ char *file;
++ char c;
++
++ if (__get_user(line, (unsigned short __user *)(eip + 2)))
++ break;
++ if (__get_user(file, (char * __user *)(eip + 4)) ||
++ (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
++ file = "<bad filename>";
++
++ printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
++ return;
++ } while (0);
++#endif
++ printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\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 {
++ spinlock_t lock;
++ u32 lock_owner;
++ int lock_owner_depth;
++ } die = {
++ .lock = SPIN_LOCK_UNLOCKED,
++ .lock_owner = -1,
++ .lock_owner_depth = 0
++ };
++ static int die_counter;
++ unsigned long flags;
++
++ oops_enter();
++
++ if (die.lock_owner != raw_smp_processor_id()) {
++ console_verbose();
++ spin_lock_irqsave(&die.lock, flags);
++ die.lock_owner = smp_processor_id();
++ die.lock_owner_depth = 0;
++ bust_spinlocks(1);
++ }
++ else
++ local_save_flags(flags);
++
++ if (++die.lock_owner_depth < 3) {
++ int nl = 0;
++ unsigned long esp;
++ unsigned short ss;
++
++ handle_BUG(regs);
++ printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
++#ifdef CONFIG_PREEMPT
++ printk(KERN_EMERG "PREEMPT ");
++ nl = 1;
++#endif
++#ifdef CONFIG_SMP
++ if (!nl)
++ printk(KERN_EMERG);
++ printk("SMP ");
++ nl = 1;
++#endif
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ if (!nl)
++ printk(KERN_EMERG);
++ printk("DEBUG_PAGEALLOC");
++ nl = 1;
++#endif
++ if (nl)
++ printk("\n");
++ if (notify_die(DIE_OOPS, str, regs, err,
++ current->thread.trap_no, SIGSEGV) !=
++ NOTIFY_STOP) {
++ show_registers(regs);
++ /* Executive summary in case the oops scrolled away */
++ esp = (unsigned long) (®s->esp);
++ savesegment(ss, ss);
++ if (user_mode(regs)) {
++ esp = regs->esp;
++ ss = regs->xss & 0xffff;
++ }
++ printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip);
++ print_symbol("%s", regs->eip);
++ printk(" SS:ESP %04x:%08lx\n", ss, esp);
++ }
++ else
++ regs = NULL;
++ } else
++ printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
++
++ bust_spinlocks(0);
++ die.lock_owner = -1;
++ spin_unlock_irqrestore(&die.lock, flags);
++
++ if (!regs)
++ return;
++
++ if (kexec_should_crash(current))
++ crash_kexec(regs);
++
++ if (in_interrupt())
++ panic("Fatal exception in interrupt");
++
++ if (panic_on_oops)
++ panic("Fatal exception");
++
++ oops_exit();
++ do_exit(SIGSEGV);
++}
++
++static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
++{
++ if (!user_mode_vm(regs))
++ die(str, regs, err);
++}
++
++static void __kprobes 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;
++ goto trap_signal;
++ }
++
++ if (!user_mode(regs))
++ goto kernel_trap;
++
++ trap_signal: {
++ if (info)
++ force_sig_info(signr, info, tsk);
++ else
++ force_sig(signr, tsk);
++ return;
++ }
++
++ kernel_trap: {
++ if (!fixup_exception(regs))
++ die(str, regs, error_code);
++ return;
++ }
++
++ vm86_trap: {
++ int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
++ if (ret) goto trap_signal;
++ return;
++ }
++}
++
++#define DO_ERROR(trapnr, signr, str, name) \
++fastcall void do_##name(struct pt_regs * regs, long error_code) \
++{ \
++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
++ == NOTIFY_STOP) \
++ return; \
++ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
++}
++
++#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
++fastcall void do_##name(struct pt_regs * regs, long error_code) \
++{ \
++ siginfo_t info; \
++ info.si_signo = signr; \
++ info.si_errno = 0; \
++ info.si_code = sicode; \
++ info.si_addr = (void __user *)siaddr; \
++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
++ == NOTIFY_STOP) \
++ return; \
++ do_trap(trapnr, signr, str, 0, regs, error_code, &info); \
++}
++
++#define DO_VM86_ERROR(trapnr, signr, str, name) \
++fastcall void do_##name(struct pt_regs * regs, long error_code) \
++{ \
++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
++ == NOTIFY_STOP) \
++ return; \
++ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
++}
++
++#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
++fastcall void do_##name(struct pt_regs * regs, long error_code) \
++{ \
++ siginfo_t info; \
++ info.si_signo = signr; \
++ info.si_errno = 0; \
++ info.si_code = sicode; \
++ info.si_addr = (void __user *)siaddr; \
++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
++ == NOTIFY_STOP) \
++ return; \
++ do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
++}
++
++DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip)
++#ifndef CONFIG_KPROBES
++DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
++#endif
++DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
++DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
++DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip)
++DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
++DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
++DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
++DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
++DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
++DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
++
++fastcall void __kprobes do_general_protection(struct pt_regs * regs,
++ long error_code)
++{
++ current->thread.error_code = error_code;
++ current->thread.trap_no = 13;
++
++ if (regs->eflags & VM_MASK)
++ goto gp_in_vm86;
++
++ if (!user_mode(regs))
++ goto gp_in_kernel;
++
++ current->thread.error_code = error_code;
++ current->thread.trap_no = 13;
++ force_sig(SIGSEGV, current);
++ return;
++
++gp_in_vm86:
++ local_irq_enable();
++ handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
++ return;
++
++gp_in_kernel:
++ if (!fixup_exception(regs)) {
++ if (notify_die(DIE_GPF, "general protection fault", regs,
++ error_code, 13, SIGSEGV) == NOTIFY_STOP)
++ return;
++ die("general protection fault", regs, error_code);
++ }
++}
++
++static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
++{
++ printk(KERN_EMERG "Uhhuh. NMI received. Dazed and confused, but trying "
++ "to continue\n");
++ printk(KERN_EMERG "You probably have a hardware problem with your RAM "
++ "chips\n");
++
++ /* Clear and disable the memory parity error line. */
++ clear_mem_error(reason);
++}
++
++static void io_check_error(unsigned char reason, struct pt_regs * regs)
++{
++ printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
++ show_registers(regs);
++
++ /* Re-enable the IOCK line, wait for a few seconds */
++ clear_io_check_error(reason);
++}
++
++static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
++{
++#ifdef CONFIG_MCA
++ /* Might actually be able to figure out what the guilty party
++ * is. */
++ if( MCA_bus ) {
++ mca_handle_nmi();
++ return;
++ }
++#endif
++ printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
++ reason, smp_processor_id());
++ printk("Dazed and confused, but trying to continue\n");
++ printk("Do you have a strange power saving mode enabled?\n");
++}
++
++static DEFINE_SPINLOCK(nmi_print_lock);
++
++void die_nmi (struct pt_regs *regs, const char *msg)
++{
++ if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) ==
++ NOTIFY_STOP)
++ return;
++
++ spin_lock(&nmi_print_lock);
++ /*
++ * We are in trouble anyway, lets at least try
++ * to get a message out.
++ */
++ bust_spinlocks(1);
++ printk(KERN_EMERG "%s", msg);
++ printk(" on CPU%d, eip %08lx, registers:\n",
++ smp_processor_id(), regs->eip);
++ show_registers(regs);
++ printk(KERN_EMERG "console shuts up ...\n");
++ 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_vm(regs)) {
++ current->thread.trap_no = 2;
++ crash_kexec(regs);
++ }
++
++ do_exit(SIGSEGV);
++}
++
++static void default_do_nmi(struct pt_regs * regs)
++{
++ unsigned char reason = 0;
++
++ /* Only the BSP gets external NMIs from the system. */
++ if (!smp_processor_id())
++ reason = get_nmi_reason();
++
++ if (!(reason & 0xc0)) {
++ if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
++ == NOTIFY_STOP)
++ return;
++#ifdef CONFIG_X86_LOCAL_APIC
++ /*
++ * Ok, so this is none of the documented NMI sources,
++ * so it must be the NMI watchdog.
++ */
++ if (nmi_watchdog) {
++ nmi_watchdog_tick(regs);
++ return;
++ }
++#endif
++ unknown_nmi_error(reason, regs);
++ return;
++ }
++ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
++ return;
++ if (reason & 0x80)
++ mem_parity_error(reason, regs);
++ if (reason & 0x40)
++ io_check_error(reason, regs);
++ /*
++ * Reassert NMI in case it became active meanwhile
++ * as it's edge-triggered.
++ */
++ reassert_nmi();
++}
++
++static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
++{
++ return 0;
++}
++
++static nmi_callback_t nmi_callback = dummy_nmi_callback;
++
++fastcall void do_nmi(struct pt_regs * regs, long error_code)
++{
++ int cpu;
++
++ nmi_enter();
++
++ cpu = smp_processor_id();
++
++ ++nmi_count(cpu);
++
++ if (!rcu_dereference(nmi_callback)(regs, cpu))
++ default_do_nmi(regs);
++
++ nmi_exit();
++}
++
++void set_nmi_callback(nmi_callback_t callback)
++{
++ vmalloc_sync_all();
++ rcu_assign_pointer(nmi_callback, callback);
++}
++EXPORT_SYMBOL_GPL(set_nmi_callback);
++
++void unset_nmi_callback(void)
++{
++ nmi_callback = dummy_nmi_callback;
++}
++EXPORT_SYMBOL_GPL(unset_nmi_callback);
++
++#ifdef CONFIG_KPROBES
++fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
++{
++ if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
++ == NOTIFY_STOP)
++ return;
++ /* This is an interrupt gate, because kprobes wants interrupts
++ disabled. Normal trap handlers don't. */
++ restore_interrupts(regs);
++ do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
++}
++#endif
++
++/*
++ * Our handling of the processor debug registers is non-trivial.
++ * We do not clear them on entry and exit from the kernel. Therefore
++ * it is possible to get a watchpoint trap here from inside the kernel.
++ * However, the code in ./ptrace.c has ensured that the user can
++ * only set watchpoints on userspace addresses. Therefore the in-kernel
++ * watchpoint trap can only occur in code which is reading/writing
++ * from user space. Such code must not hold kernel locks (since it
++ * can equally take a page fault), therefore it is safe to call
++ * force_sig_info even though that claims and releases locks.
++ *
++ * Code in ./signal.c ensures that the debug control register
++ * is restored before we deliver any signal, and therefore that
++ * user code runs with the correct debug control register even though
++ * we clear it here.
++ *
++ * Being careful here means that we don't have to be as careful in a
++ * lot of more complicated places (task switching can be a bit lazy
++ * about restoring all the debug state, and ptrace doesn't have to
++ * find every occurrence of the TF bit that could be saved away even
++ * by user code)
++ */
++fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
++{
++ unsigned int condition;
++ struct task_struct *tsk = current;
++
++ get_debugreg(condition, 6);
++
++ if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
++ SIGTRAP) == NOTIFY_STOP)
++ return;
++ /* It's safe to allow irq's after DR6 has been saved */
++ if (regs->eflags & X86_EFLAGS_IF)
++ local_irq_enable();
++
++ /* Mask out spurious debug traps due to lazy DR7 setting */
++ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
++ if (!tsk->thread.debugreg[7])
++ goto clear_dr7;
++ }
++
++ if (regs->eflags & VM_MASK)
++ goto debug_vm86;
++
++ /* Save debug status register where ptrace can see it */
++ tsk->thread.debugreg[6] = condition;
++
++ /*
++ * Single-stepping through TF: make sure we ignore any events in
++ * kernel space (but re-enable TF when returning to user mode).
++ */
++ if (condition & DR_STEP) {
++ /*
++ * We already checked v86 mode above, so we can
++ * check for kernel mode by just checking the CPL
++ * of CS.
++ */
++ if (!user_mode(regs))
++ goto clear_TF_reenable;
++ }
++
++ /* Ok, finally something we can handle */
++ send_sigtrap(tsk, regs, error_code);
++
++ /* Disable additional traps. They'll be re-enabled when
++ * the signal is delivered.
++ */
++clear_dr7:
++ set_debugreg(0, 7);
++ return;
++
++debug_vm86:
++ handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
++ return;
++
++clear_TF_reenable:
++ set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++ regs->eflags &= ~TF_MASK;
++ return;
++}
++
++/*
++ * Note that we play around with the 'TS' bit in an attempt to get
++ * the correct behaviour even in the presence of the asynchronous
++ * IRQ13 behaviour
++ */
++void math_error(void __user *eip)
++{
++ struct task_struct * task;
++ siginfo_t info;
++ unsigned short cwd, swd;
++
++ /*
++ * Save the info for the exception handler and clear the error.
++ */
++ task = current;
++ save_init_fpu(task);
++ task->thread.trap_no = 16;
++ task->thread.error_code = 0;
++ info.si_signo = SIGFPE;
++ info.si_errno = 0;
++ info.si_code = __SI_FAULT;
++ info.si_addr = eip;
++ /*
++ * (~cwd & swd) will mask out exceptions that are not set to unmasked
++ * status. 0x3f is the exception bits in these regs, 0x200 is the
++ * C1 reg you need in case of a stack fault, 0x040 is the stack
++ * fault bit. We should only be taking one exception at a time,
++ * so if this combination doesn't produce any single exception,
++ * then we have a bad program that isn't syncronizing its FPU usage
++ * and it will suffer the consequences since we won't be able to
++ * fully reproduce the context of the exception
++ */
++ cwd = get_fpu_cwd(task);
++ swd = get_fpu_swd(task);
++ switch (swd & ~cwd & 0x3f) {
++ case 0x000: /* No unmasked exception */
++ return;
++ default: /* Multiple exceptions */
++ break;
++ case 0x001: /* Invalid Op */
++ /*
++ * swd & 0x240 == 0x040: Stack Underflow
++ * swd & 0x240 == 0x240: Stack Overflow
++ * User must clear the SF bit (0x40) if set
++ */
++ info.si_code = FPE_FLTINV;
++ break;
++ case 0x002: /* Denormalize */
++ case 0x010: /* Underflow */
++ info.si_code = FPE_FLTUND;
++ break;
++ case 0x004: /* Zero Divide */
++ info.si_code = FPE_FLTDIV;
++ break;
++ case 0x008: /* Overflow */
++ info.si_code = FPE_FLTOVF;
++ break;
++ case 0x020: /* Precision */
++ info.si_code = FPE_FLTRES;
++ break;
++ }
++ force_sig_info(SIGFPE, &info, task);
++}
++
++fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code)
++{
++ ignore_fpu_irq = 1;
++ math_error((void __user *)regs->eip);
++}
++
++static void simd_math_error(void __user *eip)
++{
++ struct task_struct * task;
++ siginfo_t info;
++ unsigned short mxcsr;
++
++ /*
++ * Save the info for the exception handler and clear the error.
++ */
++ task = current;
++ save_init_fpu(task);
++ task->thread.trap_no = 19;
++ task->thread.error_code = 0;
++ info.si_signo = SIGFPE;
++ info.si_errno = 0;
++ info.si_code = __SI_FAULT;
++ info.si_addr = eip;
++ /*
++ * The SIMD FPU exceptions are handled a little differently, as there
++ * is only a single status/control register. Thus, to determine which
++ * unmasked exception was caught we must mask the exception mask bits
++ * at 0x1f80, and then use these to mask the exception bits at 0x3f.
++ */
++ mxcsr = get_fpu_mxcsr(task);
++ switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
++ case 0x000:
++ default:
++ break;
++ case 0x001: /* Invalid Op */
++ info.si_code = FPE_FLTINV;
++ break;
++ case 0x002: /* Denormalize */
++ case 0x010: /* Underflow */
++ info.si_code = FPE_FLTUND;
++ break;
++ case 0x004: /* Zero Divide */
++ info.si_code = FPE_FLTDIV;
++ break;
++ case 0x008: /* Overflow */
++ info.si_code = FPE_FLTOVF;
++ break;
++ case 0x020: /* Precision */
++ info.si_code = FPE_FLTRES;
++ break;
++ }
++ force_sig_info(SIGFPE, &info, task);
++}
++
++fastcall void do_simd_coprocessor_error(struct pt_regs * regs,
++ long error_code)
++{
++ if (cpu_has_xmm) {
++ /* Handle SIMD FPU exceptions on PIII+ processors. */
++ ignore_fpu_irq = 1;
++ simd_math_error((void __user *)regs->eip);
++ } else {
++ /*
++ * Handle strange cache flush from user space exception
++ * in all other cases. This is undocumented behaviour.
++ */
++ if (regs->eflags & VM_MASK) {
++ handle_vm86_fault((struct kernel_vm86_regs *)regs,
++ error_code);
++ return;
++ }
++ current->thread.trap_no = 19;
++ current->thread.error_code = error_code;
++ die_if_kernel("cache flush denied", regs, error_code);
++ force_sig(SIGSEGV, current);
++ }
++}
++
++#ifndef CONFIG_XEN
++fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
++ long error_code)
++{
++#if 0
++ /* No need to warn about this any longer. */
++ printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
++#endif
++}
++
++fastcall void setup_x86_bogus_stack(unsigned char * stk)
++{
++ unsigned long *switch16_ptr, *switch32_ptr;
++ struct pt_regs *regs;
++ unsigned long stack_top, stack_bot;
++ unsigned short iret_frame16_off;
++ int cpu = smp_processor_id();
++ /* reserve the space on 32bit stack for the magic switch16 pointer */
++ memmove(stk, stk + 8, sizeof(struct pt_regs));
++ switch16_ptr = (unsigned long *)(stk + sizeof(struct pt_regs));
++ regs = (struct pt_regs *)stk;
++ /* now the switch32 on 16bit stack */
++ stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu);
++ stack_top = stack_bot + CPU_16BIT_STACK_SIZE;
++ switch32_ptr = (unsigned long *)(stack_top - 8);
++ iret_frame16_off = CPU_16BIT_STACK_SIZE - 8 - 20;
++ /* copy iret frame on 16bit stack */
++ memcpy((void *)(stack_bot + iret_frame16_off), ®s->eip, 20);
++ /* fill in the switch pointers */
++ switch16_ptr[0] = (regs->esp & 0xffff0000) | iret_frame16_off;
++ switch16_ptr[1] = __ESPFIX_SS;
++ switch32_ptr[0] = (unsigned long)stk + sizeof(struct pt_regs) +
++ 8 - CPU_16BIT_STACK_SIZE;
++ switch32_ptr[1] = __KERNEL_DS;
++}
++
++fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp)
++{
++ unsigned long *switch32_ptr;
++ unsigned char *stack16, *stack32;
++ unsigned long stack_top, stack_bot;
++ int len;
++ int cpu = smp_processor_id();
++ stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu);
++ stack_top = stack_bot + CPU_16BIT_STACK_SIZE;
++ switch32_ptr = (unsigned long *)(stack_top - 8);
++ /* copy the data from 16bit stack to 32bit stack */
++ len = CPU_16BIT_STACK_SIZE - 8 - sp;
++ stack16 = (unsigned char *)(stack_bot + sp);
++ stack32 = (unsigned char *)
++ (switch32_ptr[0] + CPU_16BIT_STACK_SIZE - 8 - len);
++ memcpy(stack32, stack16, len);
++ return stack32;
++}
++#endif
++
++/*
++ * 'math_state_restore()' saves the current math information in the
++ * old math state array, and gets the new ones from the current task
++ *
++ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
++ * Don't touch unless you *really* know how it works.
++ *
++ * Must be called with kernel preemption disabled (in this case,
++ * local interrupts are disabled at the call-site in entry.S).
++ */
++asmlinkage void math_state_restore(struct pt_regs regs)
++{
++ struct thread_info *thread = current_thread_info();
++ struct task_struct *tsk = thread->task;
++
++ /* NB. 'clts' is done for us by Xen during virtual trap. */
++ if (!tsk_used_math(tsk))
++ init_fpu(tsk);
++ restore_fpu(tsk);
++ thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
++}
++
++#ifndef CONFIG_MATH_EMULATION
++
++asmlinkage void math_emulate(long arg)
++{
++ printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n");
++ printk(KERN_EMERG "killing %s.\n",current->comm);
++ force_sig(SIGFPE,current);
++ schedule();
++}
++
++#endif /* CONFIG_MATH_EMULATION */
++
++#ifdef CONFIG_X86_F00F_BUG
++void __init trap_init_f00f_bug(void)
++{
++ __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
++
++ /*
++ * Update the IDT descriptor and reload the IDT so that
++ * it uses the read-only mapped virtual address.
++ */
++ idt_descr.address = fix_to_virt(FIX_F00F_IDT);
++ load_idt(&idt_descr);
++}
++#endif
++
++
++/*
++ * NB. All these are "trap gates" (i.e. events_mask isn't set) except
++ * for those that specify <dpl>|4 in the second field.
++ */
++static trap_info_t trap_table[] = {
++ { 0, 0, __KERNEL_CS, (unsigned long)divide_error },
++ { 1, 0|4, __KERNEL_CS, (unsigned long)debug },
++ { 3, 3|4, __KERNEL_CS, (unsigned long)int3 },
++ { 4, 3, __KERNEL_CS, (unsigned long)overflow },
++ { 5, 0, __KERNEL_CS, (unsigned long)bounds },
++ { 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
++ { 7, 0|4, __KERNEL_CS, (unsigned long)device_not_available },
++ { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
++ { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
++ { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
++ { 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
++ { 13, 0, __KERNEL_CS, (unsigned long)general_protection },
++ { 14, 0|4, __KERNEL_CS, (unsigned long)page_fault },
++ { 15, 0, __KERNEL_CS, (unsigned long)fixup_4gb_segment },
++ { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
++ { 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
++#ifdef CONFIG_X86_MCE
++ { 18, 0, __KERNEL_CS, (unsigned long)machine_check },
++#endif
++ { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
++ { SYSCALL_VECTOR, 3, __KERNEL_CS, (unsigned long)system_call },
++ { 0, 0, 0, 0 }
++};
++
++void __init trap_init(void)
++{
++ HYPERVISOR_set_trap_table(trap_table);
++
++ if (cpu_has_fxsr) {
++ /*
++ * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
++ * Generates a compile-time "error: zero width for bit-field" if
++ * the alignment is wrong.
++ */
++ struct fxsrAlignAssert {
++ int _:!(offsetof(struct task_struct,
++ thread.i387.fxsave) & 15);
++ };
++
++ printk(KERN_INFO "Enabling fast FPU save and restore... ");
++ set_in_cr4(X86_CR4_OSFXSR);
++ printk("done.\n");
++ }
++ if (cpu_has_xmm) {
++ printk(KERN_INFO "Enabling unmasked SIMD FPU exception "
++ "support... ");
++ set_in_cr4(X86_CR4_OSXMMEXCPT);
++ printk("done.\n");
++ }
++
++ /*
++ * Should be a barrier for any external CPU state.
++ */
++ cpu_init();
++}
++
++void smp_trap_init(trap_info_t *trap_ctxt)
++{
++ trap_info_t *t = trap_table;
++
++ for (t = trap_table; t->address; t++) {
++ trap_ctxt[t->vector].flags = t->flags;
++ trap_ctxt[t->vector].cs = t->cs;
++ trap_ctxt[t->vector].address = t->address;
++ }
++}
++
++static int __init kstack_setup(char *s)
++{
++ kstack_depth_to_print = simple_strtoul(s, NULL, 0);
++ return 1;
++}
++__setup("kstack=", kstack_setup);
++
++#ifdef CONFIG_STACK_UNWIND
++static int __init call_trace_setup(char *s)
++{
++ if (strcmp(s, "old") == 0)
++ call_trace = -1;
++ else if (strcmp(s, "both") == 0)
++ call_trace = 0;
++ else if (strcmp(s, "newfallback") == 0)
++ call_trace = 1;
++ else if (strcmp(s, "new") == 2)
++ call_trace = 2;
++ return 1;
++}
++__setup("call_trace=", call_trace_setup);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/tsc.c linux-2.6.18-xen/arch/i386/kernel/tsc.c
+--- linux-2.6.18.1/arch/i386/kernel/tsc.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/tsc.c 2006-09-04 16:31:00.000000000 +0200
+@@ -101,6 +101,7 @@
+ return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+ }
+
++#ifndef CONFIG_XEN
+ /*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+@@ -124,6 +125,7 @@
+ /* return the value in ns */
+ return cycles_2_ns(this_offset);
+ }
++#endif
+
+ static unsigned long calculate_cpu_khz(void)
+ {
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/vm86.c linux-2.6.18-xen/arch/i386/kernel/vm86.c
+--- linux-2.6.18.1/arch/i386/kernel/vm86.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/vm86.c 2006-09-04 16:31:00.000000000 +0200
+@@ -97,7 +97,9 @@
+ struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
+ struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs)
+ {
++#ifndef CONFIG_X86_NO_TSS
+ struct tss_struct *tss;
++#endif
+ struct pt_regs *ret;
+ unsigned long tmp;
+
+@@ -122,12 +124,16 @@
+ do_exit(SIGSEGV);
+ }
+
++#ifndef CONFIG_X86_NO_TSS
+ tss = &per_cpu(init_tss, get_cpu());
++#endif
+ current->thread.esp0 = current->thread.saved_esp0;
+ current->thread.sysenter_cs = __KERNEL_CS;
+ load_esp0(tss, ¤t->thread);
+ current->thread.saved_esp0 = 0;
++#ifndef CONFIG_X86_NO_TSS
+ put_cpu();
++#endif
+
+ loadsegment(fs, current->thread.saved_fs);
+ loadsegment(gs, current->thread.saved_gs);
+@@ -251,7 +257,9 @@
+
+ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
+ {
++#ifndef CONFIG_X86_NO_TSS
+ struct tss_struct *tss;
++#endif
+ long eax;
+ /*
+ * make sure the vm86() system call doesn't try to do anything silly
+@@ -296,12 +304,16 @@
+ savesegment(fs, tsk->thread.saved_fs);
+ savesegment(gs, tsk->thread.saved_gs);
+
++#ifndef CONFIG_X86_NO_TSS
+ tss = &per_cpu(init_tss, get_cpu());
++#endif
+ tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
+ if (cpu_has_sep)
+ tsk->thread.sysenter_cs = 0;
+ load_esp0(tss, &tsk->thread);
++#ifndef CONFIG_X86_NO_TSS
+ put_cpu();
++#endif
+
+ tsk->thread.screen_bitmap = info->screen_bitmap;
+ if (info->flags & VM86_SCREEN_BITMAP)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/vmlinux.lds.S linux-2.6.18-xen/arch/i386/kernel/vmlinux.lds.S
+--- linux-2.6.18.1/arch/i386/kernel/vmlinux.lds.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/kernel/vmlinux.lds.S 2006-09-04 16:31:00.000000000 +0200
+@@ -13,6 +13,12 @@
+ OUTPUT_ARCH(i386)
+ ENTRY(phys_startup_32)
+ jiffies = jiffies_64;
++
++PHDRS {
++ text PT_LOAD FLAGS(5); /* R_E */
++ data PT_LOAD FLAGS(7); /* RWE */
++ note PT_NOTE FLAGS(4); /* R__ */
++}
+ SECTIONS
+ {
+ . = __KERNEL_START;
+@@ -26,7 +32,7 @@
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+- } = 0x9090
++ } :text = 0x9090
+
+ _etext = .; /* End of text section */
+
+@@ -48,7 +54,7 @@
+ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
+ *(.data)
+ CONSTRUCTORS
+- }
++ } :data
+
+ . = ALIGN(4096);
+ __nosave_begin = .;
+@@ -184,4 +190,6 @@
+ STABS_DEBUG
+
+ DWARF_DEBUG
++
++ NOTES
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/kernel/vsyscall-note-xen.S linux-2.6.18-xen/arch/i386/kernel/vsyscall-note-xen.S
+--- linux-2.6.18.1/arch/i386/kernel/vsyscall-note-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/kernel/vsyscall-note-xen.S 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
++ * Here we can supply some information useful to userland.
++ * First we get the vanilla i386 note that supplies the kernel version info.
++ */
++
++#include "vsyscall-note.S"
++
++/*
++ * Now we add a special note telling glibc's dynamic linker a fake hardware
++ * flavor that it will use to choose the search path for libraries in the
++ * same way it uses real hardware capabilities like "mmx".
++ * We supply "nosegneg" as the fake capability, to indicate that we
++ * do not like negative offsets in instructions using segment overrides,
++ * since we implement those inefficiently. This makes it possible to
++ * install libraries optimized to avoid those access patterns in someplace
++ * like /lib/i686/tls/nosegneg. Note that an /etc/ld.so.conf.d/file
++ * corresponding to the bits here is needed to make ldconfig work right.
++ * It should contain:
++ * hwcap 0 nosegneg
++ * to match the mapping of bit to name that we give here.
++ */
++#define NOTE_KERNELCAP_BEGIN(ncaps, mask) \
++ ASM_ELF_NOTE_BEGIN(".note.kernelcap", "a", "GNU", 2) \
++ .long ncaps, mask
++#define NOTE_KERNELCAP(bit, name) \
++ .byte bit; .asciz name
++#define NOTE_KERNELCAP_END ASM_ELF_NOTE_END
++
++NOTE_KERNELCAP_BEGIN(1, 1)
++NOTE_KERNELCAP(1, "nosegneg") /* Change 1 back to 0 when glibc is fixed! */
++NOTE_KERNELCAP_END
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/lib/delay.c linux-2.6.18-xen/arch/i386/lib/delay.c
+--- linux-2.6.18.1/arch/i386/lib/delay.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/lib/delay.c 2006-09-04 16:31:00.000000000 +0200
+@@ -61,6 +61,7 @@
+ delay_fn = delay_tsc;
+ }
+
++#ifndef CONFIG_X86_XEN
+ int read_current_timer(unsigned long *timer_val)
+ {
+ if (delay_fn == delay_tsc) {
+@@ -69,7 +70,7 @@
+ }
+ return -1;
+ }
+-
++#endif
+ void __delay(unsigned long loops)
+ {
+ delay_fn(loops);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mach-xen/irqflags.c linux-2.6.18-xen/arch/i386/mach-xen/irqflags.c
+--- linux-2.6.18.1/arch/i386/mach-xen/irqflags.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mach-xen/irqflags.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,99 @@
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <asm/irqflags.h>
++#include <asm/hypervisor.h>
++
++/* interrupt control.. */
++
++/*
++ * The use of 'barrier' in the following reflects their use as local-lock
++ * operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
++ * critical operations are executed. All critical operations must complete
++ * /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
++ * includes these barriers, for example.
++ */
++
++unsigned long __raw_local_save_flags(void)
++{
++ struct vcpu_info *_vcpu;
++ unsigned long flags;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ flags = _vcpu->evtchn_upcall_mask;
++ preempt_enable();
++
++ return flags;
++}
++EXPORT_SYMBOL(__raw_local_save_flags);
++
++void raw_local_irq_restore(unsigned long flags)
++{
++ struct vcpu_info *_vcpu;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ if ((_vcpu->evtchn_upcall_mask = flags) == 0) {
++ barrier(); /* unmask then check (avoid races) */
++ if (unlikely(_vcpu->evtchn_upcall_pending))
++ force_evtchn_callback();
++ preempt_enable();
++ } else
++ preempt_enable_no_resched();
++
++}
++EXPORT_SYMBOL(raw_local_irq_restore);
++
++void raw_local_irq_disable(void)
++{
++ struct vcpu_info *_vcpu;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ _vcpu->evtchn_upcall_mask = 1;
++ preempt_enable_no_resched();
++}
++EXPORT_SYMBOL(raw_local_irq_disable);
++
++void raw_local_irq_enable(void)
++{
++ struct vcpu_info *_vcpu;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ _vcpu->evtchn_upcall_mask = 0;
++ barrier(); /* unmask then check (avoid races) */
++ if (unlikely(_vcpu->evtchn_upcall_pending))
++ force_evtchn_callback();
++ preempt_enable();
++}
++EXPORT_SYMBOL(raw_local_irq_enable);
++
++/* Cannot use preempt_enable() here as we would recurse in preempt_sched(). */
++int raw_irqs_disabled(void)
++{
++ struct vcpu_info *_vcpu;
++ int disabled;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ disabled = (_vcpu->evtchn_upcall_mask != 0);
++ preempt_enable_no_resched();
++ return disabled;
++}
++EXPORT_SYMBOL(raw_irqs_disabled);
++
++unsigned long __raw_local_irq_save(void)
++{
++ struct vcpu_info *_vcpu;
++ unsigned long flags;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ flags = _vcpu->evtchn_upcall_mask;
++ _vcpu->evtchn_upcall_mask = 1;
++ preempt_enable_no_resched();
++
++ return flags;
++}
++EXPORT_SYMBOL(__raw_local_irq_save);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mach-xen/Makefile linux-2.6.18-xen/arch/i386/mach-xen/Makefile
+--- linux-2.6.18.1/arch/i386/mach-xen/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mach-xen/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,5 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y := setup.o irqflags.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mach-xen/setup.c linux-2.6.18-xen/arch/i386/mach-xen/setup.c
+--- linux-2.6.18.1/arch/i386/mach-xen/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mach-xen/setup.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,154 @@
++/*
++ * Machine specific setup for generic
++ */
++
++#include <linux/smp.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <asm/acpi.h>
++#include <asm/arch_hooks.h>
++#include <asm/e820.h>
++#include <asm/setup.h>
++#include <asm/fixmap.h>
++
++#include <xen/interface/callback.h>
++#include <xen/interface/memory.h>
++
++#ifdef CONFIG_HOTPLUG_CPU
++#define DEFAULT_SEND_IPI (1)
++#else
++#define DEFAULT_SEND_IPI (0)
++#endif
++
++int no_broadcast=DEFAULT_SEND_IPI;
++
++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);
++
++/**
++ * machine_specific_memory_setup - Hook for machine specific memory setup.
++ *
++ * Description:
++ * This is included late in kernel/setup.c so that it can make
++ * use of all of the static functions.
++ **/
++
++char * __init machine_specific_memory_setup(void)
++{
++ int rc;
++ struct xen_memory_map memmap;
++ /*
++ * This is rather large for a stack variable but this early in
++ * the boot process we know we have plenty slack space.
++ */
++ struct e820entry map[E820MAX];
++
++ memmap.nr_entries = E820MAX;
++ set_xen_guest_handle(memmap.buffer, map);
++
++ rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
++ if ( rc == -ENOSYS ) {
++ memmap.nr_entries = 1;
++ map[0].addr = 0ULL;
++ map[0].size = PFN_PHYS(xen_start_info->nr_pages);
++ /* 8MB slack (to balance backend allocations). */
++ map[0].size += 8ULL << 20;
++ map[0].type = E820_RAM;
++ rc = 0;
++ }
++ BUG_ON(rc);
++
++ sanitize_e820_map(map, (char *)&memmap.nr_entries);
++
++ BUG_ON(copy_e820_map(map, (char)memmap.nr_entries) < 0);
++
++ return "Xen";
++}
++
++extern void hypervisor_callback(void);
++extern void failsafe_callback(void);
++extern void nmi(void);
++
++unsigned long *machine_to_phys_mapping;
++EXPORT_SYMBOL(machine_to_phys_mapping);
++unsigned int machine_to_phys_order;
++EXPORT_SYMBOL(machine_to_phys_order);
++
++void __init machine_specific_arch_setup(void)
++{
++ int ret;
++ struct xen_machphys_mapping mapping;
++ unsigned long machine_to_phys_nr_ents;
++ struct xen_platform_parameters pp;
++ struct callback_register event = {
++ .type = CALLBACKTYPE_event,
++ .address = { __KERNEL_CS, (unsigned long)hypervisor_callback },
++ };
++ struct callback_register failsafe = {
++ .type = CALLBACKTYPE_failsafe,
++ .address = { __KERNEL_CS, (unsigned long)failsafe_callback },
++ };
++ struct callback_register nmi_cb = {
++ .type = CALLBACKTYPE_nmi,
++ .address = { __KERNEL_CS, (unsigned long)nmi },
++ };
++
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
++ if (ret == 0)
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
++ if (ret == -ENOSYS)
++ ret = HYPERVISOR_set_callbacks(
++ event.address.cs, event.address.eip,
++ failsafe.address.cs, failsafe.address.eip);
++ BUG_ON(ret);
++
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
++ if (ret == -ENOSYS) {
++ struct xennmi_callback cb;
++
++ cb.handler_address = nmi_cb.address.eip;
++ HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
++ }
++
++ if (HYPERVISOR_xen_version(XENVER_platform_parameters,
++ &pp) == 0)
++ set_fixaddr_top(pp.virt_start - PAGE_SIZE);
++
++ machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START;
++ machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
++ if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
++ machine_to_phys_mapping = (unsigned long *)mapping.v_start;
++ machine_to_phys_nr_ents = mapping.max_mfn + 1;
++ }
++ while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents )
++ machine_to_phys_order++;
++}
++
++/**
++ * pre_setup_arch_hook - hook called prior to any setup_arch() execution
++ *
++ * Description:
++ * generally used to activate any machine specific identification
++ * routines that may be needed before setup_arch() runs. On VISWS
++ * this is used to get the board revision and type.
++ **/
++void __init pre_setup_arch_hook(void)
++{
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/Makefile linux-2.6.18-xen/arch/i386/Makefile
+--- linux-2.6.18.1/arch/i386/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -48,6 +48,11 @@
+
+ CFLAGS += $(cflags-y)
+
++cppflags-$(CONFIG_XEN) += \
++ -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION)
++
++CPPFLAGS += $(cppflags-y)
++
+ # Default subarch .c files
+ mcore-y := mach-default
+
+@@ -71,6 +76,10 @@
+ mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit
+ mcore-$(CONFIG_X86_SUMMIT) := mach-default
+
++# Xen subarch support
++mflags-$(CONFIG_X86_XEN) := -Iinclude/asm-i386/mach-xen
++mcore-$(CONFIG_X86_XEN) := mach-xen
++
+ # generic subarchitecture
+ mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic
+ mcore-$(CONFIG_X86_GENERICARCH) := mach-default
+@@ -105,6 +114,19 @@
+ PHONY += zImage bzImage compressed zlilo bzlilo \
+ zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install
+
++ifdef CONFIG_XEN
++CPPFLAGS := -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
++head-y := arch/i386/kernel/head-xen.o arch/i386/kernel/init_task-xen.o
++boot := arch/i386/boot-xen
++.PHONY: vmlinuz
++all: vmlinuz
++
++vmlinuz: vmlinux
++ $(Q)$(MAKE) $(build)=$(boot) $@
++
++install:
++ $(Q)$(MAKE) $(build)=$(boot) XENGUEST=$(XENGUEST) $@
++else
+ all: bzImage
+
+ # KBUILD_IMAGE specify target image being built
+@@ -127,6 +149,7 @@
+
+ install:
+ $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
++endif
+
+ archclean:
+ $(Q)$(MAKE) $(clean)=arch/i386/boot
+@@ -145,3 +168,4 @@
+ CLEAN_FILES += arch/$(ARCH)/boot/fdimage \
+ arch/$(ARCH)/boot/image.iso \
+ arch/$(ARCH)/boot/mtools.conf
++CLEAN_FILES += vmlinuz vmlinux-stripped
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/fault-xen.c linux-2.6.18-xen/arch/i386/mm/fault-xen.c
+--- linux-2.6.18.1/arch/i386/mm/fault-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mm/fault-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,770 @@
++/*
++ * linux/arch/i386/mm/fault.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ */
++
++#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/mman.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/tty.h>
++#include <linux/vt_kern.h> /* For unblank_screen() */
++#include <linux/highmem.h>
++#include <linux/module.h>
++#include <linux/kprobes.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/desc.h>
++#include <asm/kdebug.h>
++
++extern void die(const char *,struct pt_regs *,long);
++
++#ifdef CONFIG_KPROBES
++ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++int register_page_fault_notifier(struct notifier_block *nb)
++{
++ vmalloc_sync_all();
++ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
++}
++
++int unregister_page_fault_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
++}
++
++static inline int notify_page_fault(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ struct die_args args = {
++ .regs = regs,
++ .str = str,
++ .err = err,
++ .trapnr = trap,
++ .signr = sig
++ };
++ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
++}
++#else
++static inline int notify_page_fault(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ return NOTIFY_DONE;
++}
++#endif
++
++/*
++ * Unlock any spinlocks which will prevent us from getting the
++ * message out
++ */
++void bust_spinlocks(int yes)
++{
++ int loglevel_save = console_loglevel;
++
++ if (yes) {
++ oops_in_progress = 1;
++ return;
++ }
++#ifdef CONFIG_VT
++ unblank_screen();
++#endif
++ oops_in_progress = 0;
++ /*
++ * OK, the message is on the console. Now we call printk()
++ * without oops_in_progress set so that printk will give klogd
++ * a poke. Hold onto your hats...
++ */
++ console_loglevel = 15; /* NMI oopser may have shut the console up */
++ printk(" ");
++ console_loglevel = loglevel_save;
++}
++
++/*
++ * Return EIP plus the CS segment base. The segment limit is also
++ * adjusted, clamped to the kernel/user address space (whichever is
++ * appropriate), and returned in *eip_limit.
++ *
++ * The segment is checked, because it might have been changed by another
++ * task between the original faulting instruction and here.
++ *
++ * If CS is no longer a valid code segment, or if EIP is beyond the
++ * limit, or if it is a kernel address when CS is not a kernel segment,
++ * then the returned value will be greater than *eip_limit.
++ *
++ * This is slow, but is very rarely executed.
++ */
++static inline unsigned long get_segment_eip(struct pt_regs *regs,
++ unsigned long *eip_limit)
++{
++ unsigned long eip = regs->eip;
++ unsigned seg = regs->xcs & 0xffff;
++ u32 seg_ar, seg_limit, base, *desc;
++
++ /* Unlikely, but must come before segment checks. */
++ if (unlikely(regs->eflags & VM_MASK)) {
++ base = seg << 4;
++ *eip_limit = base + 0xffff;
++ return base + (eip & 0xffff);
++ }
++
++ /* The standard kernel/user address space limit. */
++ *eip_limit = (seg & 2) ? USER_DS.seg : KERNEL_DS.seg;
++
++ /* By far the most common cases. */
++ if (likely(seg == __USER_CS || seg == GET_KERNEL_CS()))
++ return eip;
++
++ /* Check the segment exists, is within the current LDT/GDT size,
++ that kernel/user (ring 0..3) has the appropriate privilege,
++ that it's a code segment, and get the limit. */
++ __asm__ ("larl %3,%0; lsll %3,%1"
++ : "=&r" (seg_ar), "=r" (seg_limit) : "0" (0), "rm" (seg));
++ if ((~seg_ar & 0x9800) || eip > seg_limit) {
++ *eip_limit = 0;
++ return 1; /* So that returned eip > *eip_limit. */
++ }
++
++ /* Get the GDT/LDT descriptor base.
++ When you look for races in this code remember that
++ LDT and other horrors are only used in user space. */
++ if (seg & (1<<2)) {
++ /* Must lock the LDT while reading it. */
++ down(¤t->mm->context.sem);
++ desc = current->mm->context.ldt;
++ desc = (void *)desc + (seg & ~7);
++ } else {
++ /* Must disable preemption while reading the GDT. */
++ desc = (u32 *)get_cpu_gdt_table(get_cpu());
++ desc = (void *)desc + (seg & ~7);
++ }
++
++ /* Decode the code segment base from the descriptor */
++ base = get_desc_base((unsigned long *)desc);
++
++ if (seg & (1<<2)) {
++ up(¤t->mm->context.sem);
++ } else
++ put_cpu();
++
++ /* Adjust EIP and segment limit, and clamp at the kernel limit.
++ It's legitimate for segments to wrap at 0xffffffff. */
++ seg_limit += base;
++ if (seg_limit < *eip_limit && seg_limit >= base)
++ *eip_limit = seg_limit;
++ return eip + base;
++}
++
++/*
++ * Sometimes AMD Athlon/Opteron CPUs report invalid exceptions on prefetch.
++ * Check that here and ignore it.
++ */
++static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
++{
++ unsigned long limit;
++ unsigned long instr = get_segment_eip (regs, &limit);
++ int scan_more = 1;
++ int prefetch = 0;
++ int i;
++
++ for (i = 0; scan_more && i < 15; i++) {
++ unsigned char opcode;
++ unsigned char instr_hi;
++ unsigned char instr_lo;
++
++ if (instr > limit)
++ break;
++ if (__get_user(opcode, (unsigned char __user *) instr))
++ break;
++
++ instr_hi = opcode & 0xf0;
++ instr_lo = opcode & 0x0f;
++ instr++;
++
++ switch (instr_hi) {
++ case 0x20:
++ case 0x30:
++ /* Values 0x26,0x2E,0x36,0x3E are valid x86 prefixes. */
++ scan_more = ((instr_lo & 7) == 0x6);
++ break;
++
++ case 0x60:
++ /* 0x64 thru 0x67 are valid prefixes in all modes. */
++ scan_more = (instr_lo & 0xC) == 0x4;
++ break;
++ case 0xF0:
++ /* 0xF0, 0xF2, and 0xF3 are valid prefixes */
++ scan_more = !instr_lo || (instr_lo>>1) == 1;
++ break;
++ case 0x00:
++ /* Prefetch instruction is 0x0F0D or 0x0F18 */
++ scan_more = 0;
++ if (instr > limit)
++ break;
++ if (__get_user(opcode, (unsigned char __user *) instr))
++ break;
++ prefetch = (instr_lo == 0xF) &&
++ (opcode == 0x0D || opcode == 0x18);
++ break;
++ default:
++ scan_more = 0;
++ break;
++ }
++ }
++ return prefetch;
++}
++
++static inline int is_prefetch(struct pt_regs *regs, unsigned long addr,
++ unsigned long error_code)
++{
++ if (unlikely(boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
++ boot_cpu_data.x86 >= 6)) {
++ /* Catch an obscure case of prefetch inside an NX page. */
++ if (nx_enabled && (error_code & 16))
++ return 0;
++ return __is_prefetch(regs, addr);
++ }
++ return 0;
++}
++
++static noinline void force_sig_info_fault(int si_signo, int si_code,
++ unsigned long address, struct task_struct *tsk)
++{
++ siginfo_t info;
++
++ info.si_signo = si_signo;
++ info.si_errno = 0;
++ info.si_code = si_code;
++ info.si_addr = (void __user *)address;
++ force_sig_info(si_signo, &info, tsk);
++}
++
++fastcall void do_invalid_op(struct pt_regs *, unsigned long);
++
++#ifdef CONFIG_X86_PAE
++static void dump_fault_path(unsigned long address)
++{
++ unsigned long *p, page;
++ unsigned long mfn;
++
++ page = read_cr3();
++ p = (unsigned long *)__va(page);
++ p += (address >> 30) * 2;
++ printk(KERN_ALERT "%08lx -> *pde = %08lx:%08lx\n", page, p[1], p[0]);
++ if (p[0] & 1) {
++ mfn = (p[0] >> PAGE_SHIFT) | ((p[1] & 0x7) << 20);
++ page = mfn_to_pfn(mfn) << PAGE_SHIFT;
++ p = (unsigned long *)__va(page);
++ address &= 0x3fffffff;
++ p += (address >> 21) * 2;
++ printk(KERN_ALERT "%08lx -> *pme = %08lx:%08lx\n",
++ page, p[1], p[0]);
++#ifndef CONFIG_HIGHPTE
++ if (p[0] & 1) {
++ mfn = (p[0] >> PAGE_SHIFT) | ((p[1] & 0x7) << 20);
++ page = mfn_to_pfn(mfn) << PAGE_SHIFT;
++ p = (unsigned long *) __va(page);
++ address &= 0x001fffff;
++ p += (address >> 12) * 2;
++ printk(KERN_ALERT "%08lx -> *pte = %08lx:%08lx\n",
++ page, p[1], p[0]);
++ }
++#endif
++ }
++}
++#else
++static void dump_fault_path(unsigned long address)
++{
++ unsigned long page;
++
++ page = read_cr3();
++ page = ((unsigned long *) __va(page))[address >> 22];
++ if (oops_may_print())
++ printk(KERN_ALERT "*pde = ma %08lx pa %08lx\n", page,
++ machine_to_phys(page));
++ /*
++ * We must not directly access the pte in the highpte
++ * case, the page table might be allocated in highmem.
++ * And lets rather not kmap-atomic the pte, just in case
++ * it's allocated already.
++ */
++#ifndef CONFIG_HIGHPTE
++ if ((page & 1) && oops_may_print()) {
++ page &= PAGE_MASK;
++ address &= 0x003ff000;
++ page = machine_to_phys(page);
++ page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
++ printk(KERN_ALERT "*pte = ma %08lx pa %08lx\n", page,
++ machine_to_phys(page));
++ }
++#endif
++}
++#endif
++
++static int spurious_fault(struct pt_regs *regs,
++ unsigned long address,
++ unsigned long error_code)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++
++#ifdef CONFIG_XEN
++ /* Faults in hypervisor area are never spurious. */
++ if (address >= HYPERVISOR_VIRT_START)
++ return 0;
++#endif
++
++ /* Reserved-bit violation or user access to kernel space? */
++ if (error_code & 0x0c)
++ return 0;
++
++ pgd = init_mm.pgd + pgd_index(address);
++ if (!pgd_present(*pgd))
++ return 0;
++
++ pud = pud_offset(pgd, address);
++ if (!pud_present(*pud))
++ return 0;
++
++ pmd = pmd_offset(pud, address);
++ if (!pmd_present(*pmd))
++ return 0;
++
++ pte = pte_offset_kernel(pmd, address);
++ if (!pte_present(*pte))
++ return 0;
++ if ((error_code & 0x02) && !pte_write(*pte))
++ return 0;
++#ifdef CONFIG_X86_PAE
++ if ((error_code & 0x10) && (pte_val(*pte) & _PAGE_NX))
++ return 0;
++#endif
++
++ return 1;
++}
++
++static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
++{
++ unsigned index = pgd_index(address);
++ pgd_t *pgd_k;
++ pud_t *pud, *pud_k;
++ pmd_t *pmd, *pmd_k;
++
++ pgd += index;
++ pgd_k = init_mm.pgd + index;
++
++ if (!pgd_present(*pgd_k))
++ return NULL;
++
++ /*
++ * set_pgd(pgd, *pgd_k); here would be useless on PAE
++ * and redundant with the set_pmd() on non-PAE. As would
++ * set_pud.
++ */
++
++ pud = pud_offset(pgd, address);
++ pud_k = pud_offset(pgd_k, address);
++ if (!pud_present(*pud_k))
++ return NULL;
++
++ pmd = pmd_offset(pud, address);
++ pmd_k = pmd_offset(pud_k, address);
++ if (!pmd_present(*pmd_k))
++ return NULL;
++ if (!pmd_present(*pmd))
++#ifndef CONFIG_XEN
++ set_pmd(pmd, *pmd_k);
++#else
++ /*
++ * When running on Xen we must launder *pmd_k through
++ * pmd_val() to ensure that _PAGE_PRESENT is correctly set.
++ */
++ set_pmd(pmd, __pmd(pmd_val(*pmd_k)));
++#endif
++ else
++ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
++ return pmd_k;
++}
++
++/*
++ * Handle a fault on the vmalloc or module mapping area
++ *
++ * This assumes no large pages in there.
++ */
++static inline int vmalloc_fault(unsigned long address)
++{
++ unsigned long pgd_paddr;
++ pmd_t *pmd_k;
++ pte_t *pte_k;
++ /*
++ * Synchronize this task's top level page-table
++ * with the 'reference' page table.
++ *
++ * Do _not_ use "current" here. We might be inside
++ * an interrupt in the middle of a task switch..
++ */
++ pgd_paddr = read_cr3();
++ pmd_k = vmalloc_sync_one(__va(pgd_paddr), address);
++ if (!pmd_k)
++ return -1;
++ pte_k = pte_offset_kernel(pmd_k, address);
++ if (!pte_present(*pte_k))
++ return -1;
++ return 0;
++}
++
++/*
++ * This routine handles page faults. It determines the address,
++ * and the problem, and then passes it off to one of the appropriate
++ * routines.
++ *
++ * error_code:
++ * bit 0 == 0 means no page found, 1 means protection fault
++ * bit 1 == 0 means read, 1 means write
++ * bit 2 == 0 means kernel, 1 means user-mode
++ * bit 3 == 1 means use of reserved bit detected
++ * bit 4 == 1 means fault was an instruction fetch
++ */
++fastcall void __kprobes do_page_fault(struct pt_regs *regs,
++ unsigned long error_code)
++{
++ struct task_struct *tsk;
++ struct mm_struct *mm;
++ struct vm_area_struct * vma;
++ unsigned long address;
++ int write, si_code;
++
++ /* get the address */
++ address = read_cr2();
++
++ /* Set the "privileged fault" bit to something sane. */
++ error_code &= ~4;
++ error_code |= (regs->xcs & 2) << 1;
++ if (regs->eflags & X86_EFLAGS_VM)
++ error_code |= 4;
++
++ tsk = current;
++
++ si_code = SEGV_MAPERR;
++
++ /*
++ * We fault-in kernel-space virtual memory on-demand. The
++ * 'reference' page table is init_mm.pgd.
++ *
++ * NOTE! We MUST NOT take any locks for this case. We may
++ * be in an interrupt or a critical region, and should
++ * only copy the information from the master page table,
++ * nothing more.
++ *
++ * This verifies that the fault happens in kernel space
++ * (error_code & 4) == 0, and that the fault was not a
++ * protection error (error_code & 9) == 0.
++ */
++ if (unlikely(address >= TASK_SIZE)) {
++#ifdef CONFIG_XEN
++ /* Faults in hypervisor area can never be patched up. */
++ if (address >= HYPERVISOR_VIRT_START)
++ goto bad_area_nosemaphore;
++#endif
++ if (!(error_code & 0x0000000d) && vmalloc_fault(address) >= 0)
++ return;
++ /* Can take a spurious fault if mapping changes R/O -> R/W. */
++ if (spurious_fault(regs, address, error_code))
++ return;
++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
++ SIGSEGV) == NOTIFY_STOP)
++ return;
++ /*
++ * Don't take the mm semaphore here. If we fixup a prefetch
++ * fault we could otherwise deadlock.
++ */
++ goto bad_area_nosemaphore;
++ }
++
++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
++ SIGSEGV) == NOTIFY_STOP)
++ return;
++
++ /* It's safe to allow irq's after cr2 has been saved and the vmalloc
++ fault has been handled. */
++ if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
++ local_irq_enable();
++
++ mm = tsk->mm;
++
++ /*
++ * If we're in an interrupt, have no user context or are running in an
++ * atomic region then we must not take the fault..
++ */
++ if (in_atomic() || !mm)
++ goto bad_area_nosemaphore;
++
++ /* When running in the kernel we expect faults to occur only to
++ * addresses in user space. All other faults represent errors in the
++ * kernel and should generate an OOPS. Unfortunatly, in the case of an
++ * erroneous fault occurring in a code path which already holds mmap_sem
++ * we will deadlock attempting to validate the fault against the
++ * address space. Luckily the kernel only validly references user
++ * space from well defined areas of code, which are listed in the
++ * exceptions table.
++ *
++ * As the vast majority of faults will be valid we will only perform
++ * the source reference check when there is a possibilty of a deadlock.
++ * Attempt to lock the address space, if we cannot we then validate the
++ * source. If this is invalid we can skip the address space check,
++ * thus avoiding the deadlock.
++ */
++ if (!down_read_trylock(&mm->mmap_sem)) {
++ if ((error_code & 4) == 0 &&
++ !search_exception_tables(regs->eip))
++ goto bad_area_nosemaphore;
++ down_read(&mm->mmap_sem);
++ }
++
++ vma = find_vma(mm, address);
++ if (!vma)
++ goto bad_area;
++ if (vma->vm_start <= address)
++ goto good_area;
++ if (!(vma->vm_flags & VM_GROWSDOWN))
++ goto bad_area;
++ if (error_code & 4) {
++ /*
++ * Accessing the stack below %esp is always a bug.
++ * The large cushion allows instructions like enter
++ * and pusha to work. ("enter $65535,$31" pushes
++ * 32 pointers and then decrements %esp by 65535.)
++ */
++ if (address + 65536 + 32 * sizeof(unsigned long) < regs->esp)
++ 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:
++ si_code = SEGV_ACCERR;
++ write = 0;
++ switch (error_code & 3) {
++ default: /* 3: write, present */
++#ifdef TEST_VERIFY_AREA
++ if (regs->cs == GET_KERNEL_CS())
++ printk("WP fault at %08lx\n", regs->eip);
++#endif
++ /* fall through */
++ case 2: /* write, not present */
++ if (!(vma->vm_flags & VM_WRITE))
++ goto bad_area;
++ write++;
++ break;
++ case 1: /* read, present */
++ goto bad_area;
++ case 0: /* read, not present */
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ goto bad_area;
++ }
++
++ survive:
++ /*
++ * If for any reason at all we couldn't handle the fault,
++ * make sure we exit gracefully rather than endlessly redo
++ * the fault.
++ */
++ switch (handle_mm_fault(mm, vma, address, write)) {
++ case VM_FAULT_MINOR:
++ tsk->min_flt++;
++ break;
++ case VM_FAULT_MAJOR:
++ tsk->maj_flt++;
++ break;
++ case VM_FAULT_SIGBUS:
++ goto do_sigbus;
++ case VM_FAULT_OOM:
++ goto out_of_memory;
++ default:
++ BUG();
++ }
++
++ /*
++ * Did it hit the DOS screen memory VA from vm86 mode?
++ */
++ if (regs->eflags & VM_MASK) {
++ unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
++ if (bit < 32)
++ tsk->thread.screen_bitmap |= 1 << bit;
++ }
++ up_read(&mm->mmap_sem);
++ return;
++
++/*
++ * Something tried to access memory that isn't in our memory map..
++ * Fix it, but check if it's kernel or user first..
++ */
++bad_area:
++ up_read(&mm->mmap_sem);
++
++bad_area_nosemaphore:
++ /* User mode accesses just cause a SIGSEGV */
++ if (error_code & 4) {
++ /*
++ * Valid to do another page fault here because this one came
++ * from user space.
++ */
++ if (is_prefetch(regs, address, error_code))
++ return;
++
++ tsk->thread.cr2 = address;
++ /* Kernel addresses are always protection faults */
++ tsk->thread.error_code = error_code | (address >= TASK_SIZE);
++ tsk->thread.trap_no = 14;
++ force_sig_info_fault(SIGSEGV, si_code, address, tsk);
++ return;
++ }
++
++#ifdef CONFIG_X86_F00F_BUG
++ /*
++ * Pentium F0 0F C7 C8 bug workaround.
++ */
++ if (boot_cpu_data.f00f_bug) {
++ unsigned long nr;
++
++ nr = (address - idt_descr.address) >> 3;
++
++ if (nr == 6) {
++ do_invalid_op(regs, 0);
++ return;
++ }
++ }
++#endif
++
++no_context:
++ /* Are we prepared to handle this kernel fault? */
++ if (fixup_exception(regs))
++ return;
++
++ /*
++ * Valid to do another page fault here, because if this fault
++ * had been triggered by is_prefetch fixup_exception would have
++ * handled it.
++ */
++ if (is_prefetch(regs, address, error_code))
++ return;
++
++/*
++ * Oops. The kernel tried to access some bad page. We'll have to
++ * terminate things with extreme prejudice.
++ */
++
++ bust_spinlocks(1);
++
++ if (oops_may_print()) {
++ #ifdef CONFIG_X86_PAE
++ if (error_code & 16) {
++ pte_t *pte = lookup_address(address);
++
++ if (pte && pte_present(*pte) && !pte_exec_kernel(*pte))
++ printk(KERN_CRIT "kernel tried to execute "
++ "NX-protected page - exploit attempt? "
++ "(uid: %d)\n", current->uid);
++ }
++ #endif
++ if (address < PAGE_SIZE)
++ printk(KERN_ALERT "BUG: unable to handle kernel NULL "
++ "pointer dereference");
++ else
++ printk(KERN_ALERT "BUG: unable to handle kernel paging"
++ " request");
++ printk(" at virtual address %08lx\n",address);
++ printk(KERN_ALERT " printing eip:\n");
++ printk("%08lx\n", regs->eip);
++ dump_fault_path(address);
++ }
++ 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);
++
++/*
++ * We ran out of memory, or some other thing happened to us that made
++ * us unable to handle the page fault gracefully.
++ */
++out_of_memory:
++ up_read(&mm->mmap_sem);
++ if (tsk->pid == 1) {
++ yield();
++ down_read(&mm->mmap_sem);
++ goto survive;
++ }
++ printk("VM: killing process %s\n", tsk->comm);
++ if (error_code & 4)
++ do_exit(SIGKILL);
++ goto no_context;
++
++do_sigbus:
++ up_read(&mm->mmap_sem);
++
++ /* Kernel mode? Handle exceptions or die */
++ if (!(error_code & 4))
++ goto no_context;
++
++ /* User space => ok to do another page fault */
++ if (is_prefetch(regs, address, error_code))
++ return;
++
++ tsk->thread.cr2 = address;
++ tsk->thread.error_code = error_code;
++ tsk->thread.trap_no = 14;
++ force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
++}
++
++#ifndef CONFIG_X86_PAE
++void vmalloc_sync_all(void)
++{
++ /*
++ * Note that races in the updates of insync and start aren't
++ * problematic: insync can only get set bits added, and updates to
++ * start are only improving performance (without affecting correctness
++ * if undone).
++ */
++ static DECLARE_BITMAP(insync, PTRS_PER_PGD);
++ static unsigned long start = TASK_SIZE;
++ unsigned long address;
++
++ BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
++ for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
++ if (!test_bit(pgd_index(address), insync)) {
++ unsigned long flags;
++ struct page *page;
++
++ spin_lock_irqsave(&pgd_lock, flags);
++ for (page = pgd_list; page; page =
++ (struct page *)page->index)
++ if (!vmalloc_sync_one(page_address(page),
++ address)) {
++ BUG_ON(page != pgd_list);
++ break;
++ }
++ spin_unlock_irqrestore(&pgd_lock, flags);
++ if (!page)
++ set_bit(pgd_index(address), insync);
++ }
++ if (address == start && test_bit(pgd_index(address), insync))
++ start = address + PGDIR_SIZE;
++ }
++}
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/highmem-xen.c linux-2.6.18-xen/arch/i386/mm/highmem-xen.c
+--- linux-2.6.18.1/arch/i386/mm/highmem-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mm/highmem-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,133 @@
++#include <linux/highmem.h>
++#include <linux/module.h>
++
++void *kmap(struct page *page)
++{
++ might_sleep();
++ if (!PageHighMem(page))
++ return page_address(page);
++ return kmap_high(page);
++}
++
++void kunmap(struct page *page)
++{
++ if (in_interrupt())
++ BUG();
++ if (!PageHighMem(page))
++ return;
++ kunmap_high(page);
++}
++
++/*
++ * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
++ * no global lock is needed and because the kmap code must perform a global TLB
++ * invalidation when the kmap pool wraps.
++ *
++ * However when holding an atomic kmap is is not legal to sleep, so atomic
++ * kmaps are appropriate for short, tight code paths only.
++ */
++static void *__kmap_atomic(struct page *page, enum km_type type, pgprot_t prot)
++{
++ enum fixed_addresses idx;
++ unsigned long vaddr;
++
++ /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
++ inc_preempt_count();
++ if (!PageHighMem(page))
++ return page_address(page);
++
++ idx = type + KM_TYPE_NR*smp_processor_id();
++ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
++#ifdef CONFIG_DEBUG_HIGHMEM
++ if (!pte_none(*(kmap_pte-idx)))
++ BUG();
++#endif
++ set_pte_at_sync(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
++
++ return (void*) vaddr;
++}
++
++void *kmap_atomic(struct page *page, enum km_type type)
++{
++ return __kmap_atomic(page, type, kmap_prot);
++}
++
++/* Same as kmap_atomic but with PAGE_KERNEL_RO page protection. */
++void *kmap_atomic_pte(struct page *page, enum km_type type)
++{
++ return __kmap_atomic(page, type, PAGE_KERNEL_RO);
++}
++
++void kunmap_atomic(void *kvaddr, enum km_type type)
++{
++#if defined(CONFIG_DEBUG_HIGHMEM) || defined(CONFIG_XEN)
++ unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
++ enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
++
++ if (vaddr < FIXADDR_START) { // FIXME
++ dec_preempt_count();
++ preempt_check_resched();
++ return;
++ }
++#endif
++
++#if defined(CONFIG_DEBUG_HIGHMEM)
++ if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
++ BUG();
++
++ /*
++ * force other mappings to Oops if they'll try to access
++ * this pte without first remap it
++ */
++ pte_clear(&init_mm, vaddr, kmap_pte-idx);
++ __flush_tlb_one(vaddr);
++#elif defined(CONFIG_XEN)
++ /*
++ * We must ensure there are no dangling pagetable references when
++ * returning memory to Xen (decrease_reservation).
++ * XXX TODO: We could make this faster by only zapping when
++ * kmap_flush_unused is called but that is trickier and more invasive.
++ */
++ pte_clear(&init_mm, vaddr, kmap_pte-idx);
++#endif
++
++ dec_preempt_count();
++ 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;
++ pte_t *pte;
++
++ if (vaddr < FIXADDR_START)
++ return virt_to_page(ptr);
++
++ idx = virt_to_fix(vaddr);
++ pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
++ return pte_page(*pte);
++}
++
++EXPORT_SYMBOL(kmap);
++EXPORT_SYMBOL(kunmap);
++EXPORT_SYMBOL(kmap_atomic);
++EXPORT_SYMBOL(kunmap_atomic);
++EXPORT_SYMBOL(kmap_atomic_to_page);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/hypervisor.c linux-2.6.18-xen/arch/i386/mm/hypervisor.c
+--- linux-2.6.18.1/arch/i386/mm/hypervisor.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mm/hypervisor.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,457 @@
++/******************************************************************************
++ * mm/hypervisor.c
++ *
++ * Update page tables via the hypervisor.
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/vmalloc.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/hypervisor.h>
++#include <xen/balloon.h>
++#include <xen/features.h>
++#include <xen/interface/memory.h>
++#include <linux/module.h>
++#include <linux/percpu.h>
++#include <asm/tlbflush.h>
++
++#ifdef CONFIG_X86_64
++#define pmd_val_ma(v) (v).pmd
++#else
++#ifdef CONFIG_X86_PAE
++# define pmd_val_ma(v) ((v).pmd)
++# define pud_val_ma(v) ((v).pgd.pgd)
++#else
++# define pmd_val_ma(v) ((v).pud.pgd.pgd)
++#endif
++#endif
++
++void xen_l1_entry_update(pte_t *ptr, pte_t val)
++{
++ mmu_update_t u;
++ u.ptr = virt_to_machine(ptr);
++ u.val = pte_val_ma(val);
++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_l2_entry_update(pmd_t *ptr, pmd_t val)
++{
++ mmu_update_t u;
++ u.ptr = virt_to_machine(ptr);
++ u.val = pmd_val_ma(val);
++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
++}
++
++#ifdef CONFIG_X86_PAE
++void xen_l3_entry_update(pud_t *ptr, pud_t val)
++{
++ mmu_update_t u;
++ u.ptr = virt_to_machine(ptr);
++ u.val = pud_val_ma(val);
++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
++}
++#endif
++
++#ifdef CONFIG_X86_64
++void xen_l3_entry_update(pud_t *ptr, pud_t val)
++{
++ mmu_update_t u;
++ u.ptr = virt_to_machine(ptr);
++ u.val = val.pud;
++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_l4_entry_update(pgd_t *ptr, pgd_t val)
++{
++ mmu_update_t u;
++ u.ptr = virt_to_machine(ptr);
++ u.val = val.pgd;
++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
++}
++#endif /* CONFIG_X86_64 */
++
++void xen_machphys_update(unsigned long mfn, unsigned long pfn)
++{
++ mmu_update_t u;
++ if (xen_feature(XENFEAT_auto_translated_physmap)) {
++ BUG_ON(pfn != mfn);
++ return;
++ }
++ u.ptr = ((unsigned long long)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
++ u.val = pfn;
++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_pt_switch(unsigned long ptr)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_NEW_BASEPTR;
++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_new_user_pt(unsigned long ptr)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_NEW_USER_BASEPTR;
++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_tlb_flush(void)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++EXPORT_SYMBOL(xen_tlb_flush);
++
++void xen_invlpg(unsigned long ptr)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_INVLPG_LOCAL;
++ op.arg1.linear_addr = ptr & PAGE_MASK;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++EXPORT_SYMBOL(xen_invlpg);
++
++#ifdef CONFIG_SMP
++
++void xen_tlb_flush_all(void)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_TLB_FLUSH_ALL;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_tlb_flush_mask(cpumask_t *mask)
++{
++ struct mmuext_op op;
++ if ( cpus_empty(*mask) )
++ return;
++ op.cmd = MMUEXT_TLB_FLUSH_MULTI;
++ op.arg2.vcpumask = mask->bits;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_invlpg_all(unsigned long ptr)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_INVLPG_ALL;
++ op.arg1.linear_addr = ptr & PAGE_MASK;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr)
++{
++ struct mmuext_op op;
++ if ( cpus_empty(*mask) )
++ return;
++ op.cmd = MMUEXT_INVLPG_MULTI;
++ op.arg1.linear_addr = ptr & PAGE_MASK;
++ op.arg2.vcpumask = mask->bits;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++#endif /* CONFIG_SMP */
++
++void xen_pgd_pin(unsigned long ptr)
++{
++ struct mmuext_op op;
++#ifdef CONFIG_X86_64
++ op.cmd = MMUEXT_PIN_L4_TABLE;
++#elif defined(CONFIG_X86_PAE)
++ op.cmd = MMUEXT_PIN_L3_TABLE;
++#else
++ op.cmd = MMUEXT_PIN_L2_TABLE;
++#endif
++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_pgd_unpin(unsigned long ptr)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_UNPIN_TABLE;
++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++void xen_set_ldt(unsigned long ptr, unsigned long len)
++{
++ struct mmuext_op op;
++ op.cmd = MMUEXT_SET_LDT;
++ op.arg1.linear_addr = ptr;
++ op.arg2.nr_ents = len;
++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
++}
++
++/*
++ * Bitmap is indexed by page number. If bit is set, the page is part of a
++ * xen_create_contiguous_region() area of memory.
++ */
++unsigned long *contiguous_bitmap;
++
++static void contiguous_bitmap_set(
++ unsigned long first_page, unsigned long nr_pages)
++{
++ unsigned long start_off, end_off, curr_idx, end_idx;
++
++ curr_idx = first_page / BITS_PER_LONG;
++ start_off = first_page & (BITS_PER_LONG-1);
++ end_idx = (first_page + nr_pages) / BITS_PER_LONG;
++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
++
++ if (curr_idx == end_idx) {
++ contiguous_bitmap[curr_idx] |=
++ ((1UL<<end_off)-1) & -(1UL<<start_off);
++ } else {
++ contiguous_bitmap[curr_idx] |= -(1UL<<start_off);
++ while ( ++curr_idx < end_idx )
++ contiguous_bitmap[curr_idx] = ~0UL;
++ contiguous_bitmap[curr_idx] |= (1UL<<end_off)-1;
++ }
++}
++
++static void contiguous_bitmap_clear(
++ unsigned long first_page, unsigned long nr_pages)
++{
++ unsigned long start_off, end_off, curr_idx, end_idx;
++
++ curr_idx = first_page / BITS_PER_LONG;
++ start_off = first_page & (BITS_PER_LONG-1);
++ end_idx = (first_page + nr_pages) / BITS_PER_LONG;
++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
++
++ if (curr_idx == end_idx) {
++ contiguous_bitmap[curr_idx] &=
++ -(1UL<<end_off) | ((1UL<<start_off)-1);
++ } else {
++ contiguous_bitmap[curr_idx] &= (1UL<<start_off)-1;
++ while ( ++curr_idx != end_idx )
++ contiguous_bitmap[curr_idx] = 0;
++ contiguous_bitmap[curr_idx] &= -(1UL<<end_off);
++ }
++}
++
++/* Protected by balloon_lock. */
++#define MAX_CONTIG_ORDER 9 /* 2MB */
++static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER];
++static multicall_entry_t cr_mcl[1<<MAX_CONTIG_ORDER];
++
++/* Ensure multi-page extents are contiguous in machine memory. */
++int xen_create_contiguous_region(
++ unsigned long vstart, unsigned int order, unsigned int address_bits)
++{
++ unsigned long *in_frames = discontig_frames, out_frame;
++ unsigned long frame, i, flags;
++ long rc;
++ int success;
++ struct xen_memory_exchange exchange = {
++ .in = {
++ .nr_extents = 1UL << order,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ },
++ .out = {
++ .nr_extents = 1,
++ .extent_order = order,
++ .address_bits = address_bits,
++ .domid = DOMID_SELF
++ }
++ };
++
++ /*
++ * Currently an auto-translated guest will not perform I/O, nor will
++ * it require PAE page directories below 4GB. Therefore any calls to
++ * this function are redundant and can be ignored.
++ */
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return 0;
++
++ if (unlikely(order > MAX_CONTIG_ORDER))
++ return -ENOMEM;
++
++ set_xen_guest_handle(exchange.in.extent_start, in_frames);
++ set_xen_guest_handle(exchange.out.extent_start, &out_frame);
++
++ scrub_pages(vstart, 1 << order);
++
++ balloon_lock(flags);
++
++ /* 1. Zap current PTEs, remembering MFNs. */
++ for (i = 0; i < (1UL<<order); i++) {
++ in_frames[i] = pfn_to_mfn((__pa(vstart) >> PAGE_SHIFT) + i);
++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
++ __pte_ma(0), 0);
++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
++ INVALID_P2M_ENTRY);
++ }
++ if (HYPERVISOR_multicall(cr_mcl, i))
++ BUG();
++
++ /* 2. Get a new contiguous memory extent. */
++ out_frame = __pa(vstart) >> PAGE_SHIFT;
++ rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
++ success = (exchange.nr_exchanged == (1UL << order));
++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
++ BUG_ON(success && (rc != 0));
++ if (unlikely(rc == -ENOSYS)) {
++ /* Compatibility when XENMEM_exchange is unsupported. */
++ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &exchange.in) != (1UL << order))
++ BUG();
++ success = (HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &exchange.out) == 1);
++ if (!success) {
++ /* Couldn't get special memory: fall back to normal. */
++ for (i = 0; i < (1UL<<order); i++)
++ in_frames[i] = (__pa(vstart)>>PAGE_SHIFT) + i;
++ if (HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &exchange.in) != (1UL<<order))
++ BUG();
++ }
++ }
++
++ /* 3. Map the new extent in place of old pages. */
++ for (i = 0; i < (1UL<<order); i++) {
++ frame = success ? (out_frame + i) : in_frames[i];
++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
++ pfn_pte_ma(frame, PAGE_KERNEL), 0);
++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame);
++ }
++
++ cr_mcl[i - 1].args[MULTI_UVMFLAGS_INDEX] = order
++ ? UVMF_TLB_FLUSH|UVMF_ALL
++ : UVMF_INVLPG|UVMF_ALL;
++ if (HYPERVISOR_multicall(cr_mcl, i))
++ BUG();
++
++ if (success)
++ contiguous_bitmap_set(__pa(vstart) >> PAGE_SHIFT,
++ 1UL << order);
++
++ balloon_unlock(flags);
++
++ return success ? 0 : -ENOMEM;
++}
++
++void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
++{
++ unsigned long *out_frames = discontig_frames, in_frame;
++ unsigned long frame, i, flags;
++ long rc;
++ int success;
++ struct xen_memory_exchange exchange = {
++ .in = {
++ .nr_extents = 1,
++ .extent_order = order,
++ .domid = DOMID_SELF
++ },
++ .out = {
++ .nr_extents = 1UL << order,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ }
++ };
++
++ if (xen_feature(XENFEAT_auto_translated_physmap) ||
++ !test_bit(__pa(vstart) >> PAGE_SHIFT, contiguous_bitmap))
++ return;
++
++ if (unlikely(order > MAX_CONTIG_ORDER))
++ return;
++
++ set_xen_guest_handle(exchange.in.extent_start, &in_frame);
++ set_xen_guest_handle(exchange.out.extent_start, out_frames);
++
++ scrub_pages(vstart, 1 << order);
++
++ balloon_lock(flags);
++
++ contiguous_bitmap_clear(__pa(vstart) >> PAGE_SHIFT, 1UL << order);
++
++ /* 1. Find start MFN of contiguous extent. */
++ in_frame = pfn_to_mfn(__pa(vstart) >> PAGE_SHIFT);
++
++ /* 2. Zap current PTEs. */
++ for (i = 0; i < (1UL<<order); i++) {
++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
++ __pte_ma(0), 0);
++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
++ INVALID_P2M_ENTRY);
++ out_frames[i] = (__pa(vstart) >> PAGE_SHIFT) + i;
++ }
++ if (HYPERVISOR_multicall(cr_mcl, i))
++ BUG();
++
++ /* 3. Do the exchange for non-contiguous MFNs. */
++ rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
++ success = (exchange.nr_exchanged == 1);
++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
++ BUG_ON(success && (rc != 0));
++ if (unlikely(rc == -ENOSYS)) {
++ /* Compatibility when XENMEM_exchange is unsupported. */
++ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &exchange.in) != 1)
++ BUG();
++ if (HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &exchange.out) != (1UL << order))
++ BUG();
++ success = 1;
++ }
++
++ /* 4. Map new pages in place of old pages. */
++ for (i = 0; i < (1UL<<order); i++) {
++ frame = success ? out_frames[i] : (in_frame + i);
++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
++ pfn_pte_ma(frame, PAGE_KERNEL), 0);
++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame);
++ }
++
++ cr_mcl[i - 1].args[MULTI_UVMFLAGS_INDEX] = order
++ ? UVMF_TLB_FLUSH|UVMF_ALL
++ : UVMF_INVLPG|UVMF_ALL;
++ if (HYPERVISOR_multicall(cr_mcl, i))
++ BUG();
++
++ balloon_unlock(flags);
++}
++
++#ifdef __i386__
++int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b)
++{
++ __u32 *lp = (__u32 *)((char *)ldt + entry * 8);
++ maddr_t mach_lp = arbitrary_virt_to_machine(lp);
++ return HYPERVISOR_update_descriptor(
++ mach_lp, (u64)entry_a | ((u64)entry_b<<32));
++}
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/init-xen.c linux-2.6.18-xen/arch/i386/mm/init-xen.c
+--- linux-2.6.18.1/arch/i386/mm/init-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mm/init-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,851 @@
++/*
++ * linux/arch/i386/mm/init.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ *
++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
++ */
++
++#include <linux/module.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/mman.h>
++#include <linux/mm.h>
++#include <linux/hugetlb.h>
++#include <linux/swap.h>
++#include <linux/smp.h>
++#include <linux/init.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <linux/poison.h>
++#include <linux/bootmem.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/efi.h>
++#include <linux/memory_hotplug.h>
++#include <linux/initrd.h>
++#include <linux/cpumask.h>
++#include <linux/dma-mapping.h>
++#include <linux/scatterlist.h>
++
++#include <asm/processor.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/dma.h>
++#include <asm/fixmap.h>
++#include <asm/e820.h>
++#include <asm/apic.h>
++#include <asm/tlb.h>
++#include <asm/tlbflush.h>
++#include <asm/sections.h>
++#include <asm/hypervisor.h>
++#include <asm/swiotlb.h>
++
++extern unsigned long *contiguous_bitmap;
++
++unsigned int __VMALLOC_RESERVE = 128 << 20;
++
++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
++unsigned long highstart_pfn, highend_pfn;
++
++static int noinline do_test_wp_bit(void);
++
++/*
++ * Creates a middle page table and puts a pointer to it in the
++ * given global directory entry. This only returns the gd entry
++ * in non-PAE compilation mode, since the middle layer is folded.
++ */
++static pmd_t * __init one_md_table_init(pgd_t *pgd)
++{
++ pud_t *pud;
++ pmd_t *pmd_table;
++
++#ifdef CONFIG_X86_PAE
++ pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++ make_lowmem_page_readonly(pmd_table, XENFEAT_writable_page_tables);
++ set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
++ pud = pud_offset(pgd, 0);
++ if (pmd_table != pmd_offset(pud, 0))
++ BUG();
++#else
++ pud = pud_offset(pgd, 0);
++ pmd_table = pmd_offset(pud, 0);
++#endif
++
++ return pmd_table;
++}
++
++/*
++ * Create a page table and place a pointer to it in a middle page
++ * directory entry.
++ */
++static pte_t * __init one_page_table_init(pmd_t *pmd)
++{
++ if (pmd_none(*pmd)) {
++ pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++ make_lowmem_page_readonly(page_table,
++ XENFEAT_writable_page_tables);
++ set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
++ if (page_table != pte_offset_kernel(pmd, 0))
++ BUG();
++
++ return page_table;
++ }
++
++ return pte_offset_kernel(pmd, 0);
++}
++
++/*
++ * This function initializes a certain range of kernel virtual memory
++ * with new bootmem page tables, everywhere page tables are missing in
++ * the given range.
++ */
++
++/*
++ * NOTE: The pagetables are allocated contiguous on the physical space
++ * so we can cache the place of the first one and move around without
++ * checking the pgd every time.
++ */
++static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ int pgd_idx, pmd_idx;
++ unsigned long vaddr;
++
++ vaddr = start;
++ pgd_idx = pgd_index(vaddr);
++ pmd_idx = pmd_index(vaddr);
++ pgd = pgd_base + pgd_idx;
++
++ for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
++ if (pgd_none(*pgd))
++ one_md_table_init(pgd);
++ pud = pud_offset(pgd, vaddr);
++ pmd = pmd_offset(pud, vaddr);
++ for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
++ if (vaddr < HYPERVISOR_VIRT_START && pmd_none(*pmd))
++ one_page_table_init(pmd);
++
++ vaddr += PMD_SIZE;
++ }
++ pmd_idx = 0;
++ }
++}
++
++static inline int is_kernel_text(unsigned long addr)
++{
++ if (addr >= PAGE_OFFSET && addr <= (unsigned long)__init_end)
++ return 1;
++ return 0;
++}
++
++/*
++ * This maps the physical memory to kernel virtual address space, a total
++ * of max_low_pfn pages, by creating page tables starting from address
++ * PAGE_OFFSET.
++ */
++static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
++{
++ unsigned long pfn;
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++ int pgd_idx, pmd_idx, pte_ofs;
++
++ unsigned long max_ram_pfn = xen_start_info->nr_pages;
++ if (max_ram_pfn > max_low_pfn)
++ max_ram_pfn = max_low_pfn;
++
++ pgd_idx = pgd_index(PAGE_OFFSET);
++ pgd = pgd_base + pgd_idx;
++ pfn = 0;
++ pmd_idx = pmd_index(PAGE_OFFSET);
++ pte_ofs = pte_index(PAGE_OFFSET);
++
++ for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
++#ifdef CONFIG_XEN
++ /*
++ * Native linux hasn't PAE-paging enabled yet at this
++ * point. When running as xen domain we are in PAE
++ * mode already, thus we can't simply hook a empty
++ * pmd. That would kill the mappings we are currently
++ * using ...
++ */
++ pmd = pmd_offset(pud_offset(pgd, PAGE_OFFSET), PAGE_OFFSET);
++#else
++ pmd = one_md_table_init(pgd);
++#endif
++ if (pfn >= max_low_pfn)
++ continue;
++ pmd += pmd_idx;
++ for (; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
++ unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET;
++ if (address >= HYPERVISOR_VIRT_START)
++ continue;
++
++ /* Map with big pages if possible, otherwise create normal page tables. */
++ if (cpu_has_pse) {
++ unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1;
++
++ if (is_kernel_text(address) || is_kernel_text(address2))
++ set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC));
++ else
++ set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
++ pfn += PTRS_PER_PTE;
++ } else {
++ pte = one_page_table_init(pmd);
++
++ pte += pte_ofs;
++ for (; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {
++ /* XEN: Only map initial RAM allocation. */
++ if ((pfn >= max_ram_pfn) || pte_present(*pte))
++ continue;
++ if (is_kernel_text(address))
++ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
++ else
++ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
++ }
++ pte_ofs = 0;
++ }
++ }
++ pmd_idx = 0;
++ }
++}
++
++#ifndef CONFIG_XEN
++
++static inline int page_kills_ppro(unsigned long pagenr)
++{
++ if (pagenr >= 0x70000 && pagenr <= 0x7003F)
++ return 1;
++ return 0;
++}
++
++#else
++
++#define page_kills_ppro(p) 0
++
++#endif
++
++extern int is_available_memory(efi_memory_desc_t *);
++
++int page_is_ram(unsigned long pagenr)
++{
++ int i;
++ unsigned long addr, end;
++
++ if (efi_enabled) {
++ efi_memory_desc_t *md;
++ void *p;
++
++ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
++ md = p;
++ if (!is_available_memory(md))
++ continue;
++ addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
++ end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
++
++ if ((pagenr >= addr) && (pagenr < end))
++ return 1;
++ }
++ return 0;
++ }
++
++ for (i = 0; i < e820.nr_map; i++) {
++
++ if (e820.map[i].type != E820_RAM) /* not usable memory */
++ continue;
++ /*
++ * !!!FIXME!!! Some BIOSen report areas as RAM that
++ * are not. Notably the 640->1Mb area. We need a sanity
++ * check here.
++ */
++ addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
++ end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
++ if ((pagenr >= addr) && (pagenr < end))
++ return 1;
++ }
++ return 0;
++}
++
++#ifdef CONFIG_HIGHMEM
++pte_t *kmap_pte;
++pgprot_t kmap_prot;
++
++#define kmap_get_fixmap_pte(vaddr) \
++ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr))
++
++static void __init kmap_init(void)
++{
++ unsigned long kmap_vstart;
++
++ /* cache the first kmap pte */
++ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
++ kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
++
++ kmap_prot = PAGE_KERNEL;
++}
++
++static void __init permanent_kmaps_init(pgd_t *pgd_base)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ unsigned long vaddr;
++
++ vaddr = PKMAP_BASE;
++ page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
++
++ pgd = swapper_pg_dir + pgd_index(vaddr);
++ pud = pud_offset(pgd, vaddr);
++ pmd = pmd_offset(pud, vaddr);
++ pte = pte_offset_kernel(pmd, vaddr);
++ pkmap_page_table = pte;
++}
++
++static void __meminit free_new_highpage(struct page *page, int pfn)
++{
++ init_page_count(page);
++ if (pfn < xen_start_info->nr_pages)
++ __free_page(page);
++ totalhigh_pages++;
++}
++
++void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro)
++{
++ if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) {
++ ClearPageReserved(page);
++ free_new_highpage(page, pfn);
++ } else
++ SetPageReserved(page);
++}
++
++static int add_one_highpage_hotplug(struct page *page, unsigned long pfn)
++{
++ free_new_highpage(page, pfn);
++ totalram_pages++;
++#ifdef CONFIG_FLATMEM
++ max_mapnr = max(pfn, max_mapnr);
++#endif
++ num_physpages++;
++ return 0;
++}
++
++/*
++ * Not currently handling the NUMA case.
++ * Assuming single node and all memory that
++ * has been added dynamically that would be
++ * onlined here is in HIGHMEM
++ */
++void online_page(struct page *page)
++{
++ ClearPageReserved(page);
++ add_one_highpage_hotplug(page, page_to_pfn(page));
++}
++
++
++#ifdef CONFIG_NUMA
++extern void set_highmem_pages_init(int);
++#else
++static void __init set_highmem_pages_init(int bad_ppro)
++{
++ int pfn;
++ for (pfn = highstart_pfn; pfn < highend_pfn; pfn++)
++ add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
++ totalram_pages += totalhigh_pages;
++}
++#endif /* CONFIG_FLATMEM */
++
++#else
++#define kmap_init() do { } while (0)
++#define permanent_kmaps_init(pgd_base) do { } while (0)
++#define set_highmem_pages_init(bad_ppro) do { } while (0)
++#endif /* CONFIG_HIGHMEM */
++
++unsigned long long __PAGE_KERNEL = _PAGE_KERNEL;
++EXPORT_SYMBOL(__PAGE_KERNEL);
++unsigned long long __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC;
++
++#ifdef CONFIG_NUMA
++extern void __init remap_numa_kva(void);
++#else
++#define remap_numa_kva() do {} while (0)
++#endif
++
++pgd_t *swapper_pg_dir;
++
++static void __init pagetable_init (void)
++{
++ unsigned long vaddr;
++ pgd_t *pgd_base = (pgd_t *)xen_start_info->pt_base;
++
++ swapper_pg_dir = pgd_base;
++ init_mm.pgd = pgd_base;
++
++ /* Enable PSE if available */
++ if (cpu_has_pse) {
++ set_in_cr4(X86_CR4_PSE);
++ }
++
++ /* Enable PGE if available */
++ if (cpu_has_pge) {
++ set_in_cr4(X86_CR4_PGE);
++ __PAGE_KERNEL |= _PAGE_GLOBAL;
++ __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
++ }
++
++ kernel_physical_mapping_init(pgd_base);
++ remap_numa_kva();
++
++ /*
++ * Fixed mappings, only the page table structure has to be
++ * created - mappings will be set by set_fixmap():
++ */
++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
++ page_table_range_init(vaddr, 0, pgd_base);
++
++ permanent_kmaps_init(pgd_base);
++}
++
++#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
++/*
++ * Swap suspend & friends need this for resume because things like the intel-agp
++ * driver might have split up a kernel 4MB mapping.
++ */
++char __nosavedata swsusp_pg_dir[PAGE_SIZE]
++ __attribute__ ((aligned (PAGE_SIZE)));
++
++static inline void save_pg_dir(void)
++{
++ memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
++}
++#else
++static inline void save_pg_dir(void)
++{
++}
++#endif
++
++void zap_low_mappings (void)
++{
++ int i;
++
++ save_pg_dir();
++
++ /*
++ * Zap initial low-memory mappings.
++ *
++ * Note that "pgd_clear()" doesn't do it for
++ * us, because pgd_clear() is a no-op on i386.
++ */
++ for (i = 0; i < USER_PTRS_PER_PGD; i++)
++#if defined(CONFIG_X86_PAE) && !defined(CONFIG_XEN)
++ set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
++#else
++ set_pgd(swapper_pg_dir+i, __pgd(0));
++#endif
++ flush_tlb_all();
++}
++
++static int disable_nx __initdata = 0;
++u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
++EXPORT_SYMBOL(__supported_pte_mask);
++
++/*
++ * noexec = on|off
++ *
++ * Control non executable mappings.
++ *
++ * on Enable
++ * off Disable
++ */
++void __init noexec_setup(const char *str)
++{
++ if (!strncmp(str, "on",2) && cpu_has_nx) {
++ __supported_pte_mask |= _PAGE_NX;
++ disable_nx = 0;
++ } else if (!strncmp(str,"off",3)) {
++ disable_nx = 1;
++ __supported_pte_mask &= ~_PAGE_NX;
++ }
++}
++
++int nx_enabled = 0;
++#ifdef CONFIG_X86_PAE
++
++static void __init set_nx(void)
++{
++ unsigned int v[4], l, h;
++
++ if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) {
++ cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]);
++ if ((v[3] & (1 << 20)) && !disable_nx) {
++ rdmsr(MSR_EFER, l, h);
++ l |= EFER_NX;
++ wrmsr(MSR_EFER, l, h);
++ nx_enabled = 1;
++ __supported_pte_mask |= _PAGE_NX;
++ }
++ }
++}
++
++/*
++ * Enables/disables executability of a given kernel page and
++ * returns the previous setting.
++ */
++int __init set_kernel_exec(unsigned long vaddr, int enable)
++{
++ pte_t *pte;
++ int ret = 1;
++
++ if (!nx_enabled)
++ goto out;
++
++ pte = lookup_address(vaddr);
++ BUG_ON(!pte);
++
++ if (!pte_exec_kernel(*pte))
++ ret = 0;
++
++ if (enable)
++ pte->pte_high &= ~(1 << (_PAGE_BIT_NX - 32));
++ else
++ pte->pte_high |= 1 << (_PAGE_BIT_NX - 32);
++ __flush_tlb_all();
++out:
++ return ret;
++}
++
++#endif
++
++/*
++ * paging_init() sets up the page tables - note that the first 8MB are
++ * already mapped by head.S.
++ *
++ * This routines also unmaps the page at virtual kernel address 0, so
++ * that we can trap those pesky NULL-reference errors in the kernel.
++ */
++void __init paging_init(void)
++{
++ int i;
++
++#ifdef CONFIG_X86_PAE
++ set_nx();
++ if (nx_enabled)
++ printk("NX (Execute Disable) protection: active\n");
++#endif
++
++ pagetable_init();
++
++#if defined(CONFIG_X86_PAE) && !defined(CONFIG_XEN)
++ /*
++ * We will bail out later - printk doesn't work right now so
++ * the user would just see a hanging kernel.
++ * when running as xen domain we are already in PAE mode at
++ * this point.
++ */
++ if (cpu_has_pae)
++ set_in_cr4(X86_CR4_PAE);
++#endif
++ __flush_tlb_all();
++
++ kmap_init();
++
++ /* Switch to the real shared_info page, and clear the
++ * dummy page. */
++ set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
++ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
++ memset(empty_zero_page, 0, sizeof(empty_zero_page));
++
++ /* Setup mapping of lower 1st MB */
++ for (i = 0; i < NR_FIX_ISAMAPS; i++)
++ if (is_initial_xendomain())
++ set_fixmap(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE);
++ else
++ __set_fixmap(FIX_ISAMAP_BEGIN - i,
++ virt_to_machine(empty_zero_page),
++ PAGE_KERNEL_RO);
++}
++
++/*
++ * Test if the WP bit works in supervisor mode. It isn't supported on 386's
++ * and also on some strange 486's (NexGen etc.). All 586+'s are OK. This
++ * used to involve black magic jumps to work around some nasty CPU bugs,
++ * but fortunately the switch to using exceptions got rid of all that.
++ */
++
++static void __init test_wp_bit(void)
++{
++ printk("Checking if this processor honours the WP bit even in supervisor mode... ");
++
++ /* Any page-aligned address will do, the test is non-destructive */
++ __set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY);
++ boot_cpu_data.wp_works_ok = do_test_wp_bit();
++ clear_fixmap(FIX_WP_TEST);
++
++ if (!boot_cpu_data.wp_works_ok) {
++ printk("No.\n");
++#ifdef CONFIG_X86_WP_WORKS_OK
++ panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
++#endif
++ } else {
++ printk("Ok.\n");
++ }
++}
++
++static void __init set_max_mapnr_init(void)
++{
++#ifdef CONFIG_HIGHMEM
++ num_physpages = highend_pfn;
++#else
++ num_physpages = max_low_pfn;
++#endif
++#ifdef CONFIG_FLATMEM
++ max_mapnr = num_physpages;
++#endif
++}
++
++static struct kcore_list kcore_mem, kcore_vmalloc;
++
++void __init mem_init(void)
++{
++ extern int ppro_with_ram_bug(void);
++ int codesize, reservedpages, datasize, initsize;
++ int tmp;
++ int bad_ppro;
++ unsigned long pfn;
++
++ contiguous_bitmap = alloc_bootmem_low_pages(
++ (max_low_pfn + 2*BITS_PER_LONG) >> 3);
++ BUG_ON(!contiguous_bitmap);
++ memset(contiguous_bitmap, 0, (max_low_pfn + 2*BITS_PER_LONG) >> 3);
++
++#if defined(CONFIG_SWIOTLB)
++ swiotlb_init();
++#endif
++
++#ifdef CONFIG_FLATMEM
++ if (!mem_map)
++ BUG();
++#endif
++
++ bad_ppro = ppro_with_ram_bug();
++
++#ifdef CONFIG_HIGHMEM
++ /* check that fixmap and pkmap do not overlap */
++ if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
++ printk(KERN_ERR "fixmap and kmap areas overlap - this will crash\n");
++ printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n",
++ PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, FIXADDR_START);
++ BUG();
++ }
++#endif
++
++ set_max_mapnr_init();
++
++#ifdef CONFIG_HIGHMEM
++ high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
++#else
++ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
++#endif
++ printk("vmalloc area: %lx-%lx, maxmem %lx\n",
++ VMALLOC_START,VMALLOC_END,MAXMEM);
++ BUG_ON(VMALLOC_START > VMALLOC_END);
++
++ /* this will put all low memory onto the freelists */
++ totalram_pages += free_all_bootmem();
++ /* XEN: init and count low-mem pages outside initial allocation. */
++ for (pfn = xen_start_info->nr_pages; pfn < max_low_pfn; pfn++) {
++ ClearPageReserved(&mem_map[pfn]);
++ init_page_count(&mem_map[pfn]);
++ totalram_pages++;
++ }
++
++ reservedpages = 0;
++ for (tmp = 0; tmp < max_low_pfn; tmp++)
++ /*
++ * Only count reserved RAM pages
++ */
++ if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
++ reservedpages++;
++
++ set_highmem_pages_init(bad_ppro);
++
++ codesize = (unsigned long) &_etext - (unsigned long) &_text;
++ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
++ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
++
++ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
++ kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
++ VMALLOC_END-VMALLOC_START);
++
++ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
++ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
++ num_physpages << (PAGE_SHIFT-10),
++ codesize >> 10,
++ reservedpages << (PAGE_SHIFT-10),
++ datasize >> 10,
++ initsize >> 10,
++ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
++ );
++
++#ifdef CONFIG_X86_PAE
++ if (!cpu_has_pae)
++ panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!");
++#endif
++ if (boot_cpu_data.wp_works_ok < 0)
++ test_wp_bit();
++
++ /*
++ * Subtle. SMP is doing it's boot stuff late (because it has to
++ * fork idle threads) - but it also needs low mappings for the
++ * protected-mode entry to work. We zap these entries only after
++ * the WP-bit has been tested.
++ */
++#ifndef CONFIG_SMP
++ zap_low_mappings();
++#endif
++
++ set_bit(PG_pinned, &virt_to_page(init_mm.pgd)->flags);
++}
++
++/*
++ * this is for the non-NUMA, single node SMP system case.
++ * Specifically, in the case of x86, we will always add
++ * memory to the highmem for now.
++ */
++#ifdef CONFIG_MEMORY_HOTPLUG
++#ifndef CONFIG_NEED_MULTIPLE_NODES
++int arch_add_memory(u64 start, u64 size)
++{
++ struct pglist_data *pgdata = &contig_page_data;
++ struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
++ unsigned long start_pfn = start >> PAGE_SHIFT;
++ unsigned long nr_pages = size >> PAGE_SHIFT;
++
++ return __add_pages(zone, start_pfn, nr_pages);
++}
++
++int remove_memory(u64 start, u64 size)
++{
++ return -EINVAL;
++}
++#endif
++#endif
++
++kmem_cache_t *pgd_cache;
++kmem_cache_t *pmd_cache;
++
++void __init pgtable_cache_init(void)
++{
++ if (PTRS_PER_PMD > 1) {
++ pmd_cache = kmem_cache_create("pmd",
++ PTRS_PER_PMD*sizeof(pmd_t),
++ PTRS_PER_PMD*sizeof(pmd_t),
++ 0,
++ pmd_ctor,
++ NULL);
++ if (!pmd_cache)
++ panic("pgtable_cache_init(): cannot create pmd cache");
++ }
++ pgd_cache = kmem_cache_create("pgd",
++#ifndef CONFIG_XEN
++ PTRS_PER_PGD*sizeof(pgd_t),
++ PTRS_PER_PGD*sizeof(pgd_t),
++#else
++ PAGE_SIZE,
++ PAGE_SIZE,
++#endif
++ 0,
++ pgd_ctor,
++ PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
++ if (!pgd_cache)
++ panic("pgtable_cache_init(): Cannot create pgd cache");
++}
++
++/*
++ * This function cannot be __init, since exceptions don't work in that
++ * section. Put this after the callers, so that it cannot be inlined.
++ */
++static int noinline do_test_wp_bit(void)
++{
++ char tmp_reg;
++ int flag;
++
++ __asm__ __volatile__(
++ " movb %0,%1 \n"
++ "1: movb %1,%0 \n"
++ " xorl %2,%2 \n"
++ "2: \n"
++ ".section __ex_table,\"a\"\n"
++ " .align 4 \n"
++ " .long 1b,2b \n"
++ ".previous \n"
++ :"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
++ "=q" (tmp_reg),
++ "=r" (flag)
++ :"2" (1)
++ :"memory");
++
++ return flag;
++}
++
++#ifdef CONFIG_DEBUG_RODATA
++
++void mark_rodata_ro(void)
++{
++ unsigned long addr = (unsigned long)__start_rodata;
++
++ for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE)
++ change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO);
++
++ printk("Write protecting the kernel read-only data: %uk\n",
++ (__end_rodata - __start_rodata) >> 10);
++
++
++ /*
++ * change_page_attr() requires a global_flush_tlb() call after it.
++ * We do this after the printk so that if something went wrong in the
++ * change, the printk gets out at least to give a better debug hint
++ * of who is the culprit.
++ */
++ global_flush_tlb();
++}
++#endif
++
++void free_init_pages(char *what, unsigned long begin, unsigned long end)
++{
++ unsigned long addr;
++
++ for (addr = begin; addr < end; addr += PAGE_SIZE) {
++ ClearPageReserved(virt_to_page(addr));
++ init_page_count(virt_to_page(addr));
++ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
++ free_page(addr);
++ totalram_pages++;
++ }
++ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
++}
++
++void free_initmem(void)
++{
++ free_init_pages("unused kernel memory",
++ (unsigned long)(&__init_begin),
++ (unsigned long)(&__init_end));
++}
++
++#ifdef CONFIG_BLK_DEV_INITRD
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++ free_init_pages("initrd memory", start, end);
++}
++#endif
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/ioremap-xen.c linux-2.6.18-xen/arch/i386/mm/ioremap-xen.c
+--- linux-2.6.18.1/arch/i386/mm/ioremap-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mm/ioremap-xen.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,443 @@
++/*
++ * arch/i386/mm/ioremap.c
++ *
++ * Re-map IO memory to kernel address space so that we can access it.
++ * This is needed for high PCI addresses that aren't mapped in the
++ * 640k-1MB IO memory area on PC's
++ *
++ * (C) Copyright 1995 1996 Linus Torvalds
++ */
++
++#include <linux/vmalloc.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <asm/fixmap.h>
++#include <asm/cacheflush.h>
++#include <asm/tlbflush.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++
++#define ISA_START_ADDRESS 0x0
++#define ISA_END_ADDRESS 0x100000
++
++static int direct_remap_area_pte_fn(pte_t *pte,
++ struct page *pmd_page,
++ unsigned long address,
++ void *data)
++{
++ mmu_update_t **v = (mmu_update_t **)data;
++
++ BUG_ON(!pte_none(*pte));
++
++ (*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pmd_page)) <<
++ PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
++ (*v)++;
++
++ return 0;
++}
++
++static int __direct_remap_pfn_range(struct mm_struct *mm,
++ unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid)
++{
++ int rc;
++ unsigned long i, start_address;
++ mmu_update_t *u, *v, *w;
++
++ u = v = w = (mmu_update_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
++ if (u == NULL)
++ return -ENOMEM;
++
++ start_address = address;
++
++ flush_cache_all();
++
++ for (i = 0; i < size; i += PAGE_SIZE) {
++ if ((v - u) == (PAGE_SIZE / sizeof(mmu_update_t))) {
++ /* Flush a full batch after filling in the PTE ptrs. */
++ rc = apply_to_page_range(mm, start_address,
++ address - start_address,
++ direct_remap_area_pte_fn, &w);
++ if (rc)
++ goto out;
++ rc = -EFAULT;
++ if (HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0)
++ goto out;
++ v = w = u;
++ start_address = address;
++ }
++
++ /*
++ * Fill in the machine address: PTE ptr is done later by
++ * __direct_remap_area_pages().
++ */
++ v->val = pte_val_ma(pfn_pte_ma(mfn, prot));
++
++ mfn++;
++ address += PAGE_SIZE;
++ v++;
++ }
++
++ if (v != u) {
++ /* Final batch. */
++ rc = apply_to_page_range(mm, start_address,
++ address - start_address,
++ direct_remap_area_pte_fn, &w);
++ if (rc)
++ goto out;
++ rc = -EFAULT;
++ if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0))
++ goto out;
++ }
++
++ rc = 0;
++
++ out:
++ flush_tlb_all();
++
++ free_page((unsigned long)u);
++
++ return rc;
++}
++
++int direct_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return remap_pfn_range(vma, address, mfn, size, prot);
++
++ if (domid == DOMID_SELF)
++ return -EINVAL;
++
++ vma->vm_flags |= VM_IO | VM_RESERVED;
++
++ vma->vm_mm->context.has_foreign_mappings = 1;
++
++ return __direct_remap_pfn_range(
++ vma->vm_mm, address, mfn, size, prot, domid);
++}
++EXPORT_SYMBOL(direct_remap_pfn_range);
++
++int direct_kernel_remap_pfn_range(unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid)
++{
++ return __direct_remap_pfn_range(
++ &init_mm, address, mfn, size, prot, domid);
++}
++EXPORT_SYMBOL(direct_kernel_remap_pfn_range);
++
++static int lookup_pte_fn(
++ pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
++{
++ uint64_t *ptep = (uint64_t *)data;
++ if (ptep)
++ *ptep = ((uint64_t)pfn_to_mfn(page_to_pfn(pmd_page)) <<
++ PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
++ return 0;
++}
++
++int create_lookup_pte_addr(struct mm_struct *mm,
++ unsigned long address,
++ uint64_t *ptep)
++{
++ return apply_to_page_range(mm, address, PAGE_SIZE,
++ lookup_pte_fn, ptep);
++}
++
++EXPORT_SYMBOL(create_lookup_pte_addr);
++
++static int noop_fn(
++ pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
++{
++ return 0;
++}
++
++int touch_pte_range(struct mm_struct *mm,
++ unsigned long address,
++ unsigned long size)
++{
++ return apply_to_page_range(mm, address, size, noop_fn, NULL);
++}
++
++EXPORT_SYMBOL(touch_pte_range);
++
++/*
++ * Does @address reside within a non-highmem page that is local to this virtual
++ * machine (i.e., not an I/O page, nor a memory page belonging to another VM).
++ * See the comment that accompanies mfn_to_local_pfn() in page.h to understand
++ * why this works.
++ */
++static inline int is_local_lowmem(unsigned long address)
++{
++ extern unsigned long max_low_pfn;
++ return (mfn_to_local_pfn(address >> PAGE_SHIFT) < max_low_pfn);
++}
++
++/*
++ * Generic mapping function (not visible outside):
++ */
++
++/*
++ * Remap an arbitrary physical address space into the kernel virtual
++ * address space. Needed when the kernel wants to access high addresses
++ * directly.
++ *
++ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
++ * have to convert them into an offset in a page-aligned mapping, but the
++ * caller shouldn't need to know that small detail.
++ */
++void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
++{
++ void __iomem * addr;
++ struct vm_struct * area;
++ unsigned long offset, last_addr;
++ domid_t domid = DOMID_IO;
++
++ /* Don't allow wraparound or zero size */
++ last_addr = phys_addr + size - 1;
++ if (!size || last_addr < phys_addr)
++ return NULL;
++
++ /*
++ * Don't remap the low PCI/ISA area, it's always mapped..
++ */
++ if (is_initial_xendomain() &&
++ phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
++ return (void __iomem *) isa_bus_to_virt(phys_addr);
++
++ /*
++ * Don't allow anybody to remap normal RAM that we're using..
++ */
++ if (is_local_lowmem(phys_addr)) {
++ char *t_addr, *t_end;
++ struct page *page;
++
++ t_addr = bus_to_virt(phys_addr);
++ t_end = t_addr + (size - 1);
++
++ for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
++ if(!PageReserved(page))
++ return NULL;
++
++ domid = DOMID_SELF;
++ }
++
++ /*
++ * Mappings have to be page-aligned
++ */
++ offset = phys_addr & ~PAGE_MASK;
++ phys_addr &= PAGE_MASK;
++ size = PAGE_ALIGN(last_addr+1) - phys_addr;
++
++ /*
++ * Ok, go for it..
++ */
++ area = get_vm_area(size, VM_IOREMAP | (flags << 20));
++ if (!area)
++ return NULL;
++ area->phys_addr = phys_addr;
++ addr = (void __iomem *) area->addr;
++ flags |= _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED;
++ if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr,
++ phys_addr>>PAGE_SHIFT,
++ size, __pgprot(flags), domid)) {
++ vunmap((void __force *) addr);
++ return NULL;
++ }
++ return (void __iomem *) (offset + (char __iomem *)addr);
++}
++EXPORT_SYMBOL(__ioremap);
++
++/**
++ * ioremap_nocache - map bus memory into CPU space
++ * @offset: bus address of the memory
++ * @size: size of the resource to map
++ *
++ * ioremap_nocache performs a platform specific sequence of operations to
++ * make bus memory CPU accessible via the readb/readw/readl/writeb/
++ * writew/writel functions and the other mmio helpers. The returned
++ * address is not guaranteed to be usable directly as a virtual
++ * address.
++ *
++ * This version of ioremap ensures that the memory is marked uncachable
++ * on the CPU as well as honouring existing caching rules from things like
++ * the PCI bus. Note that there are other caches and buffers on many
++ * busses. In particular driver authors should read up on PCI writes
++ *
++ * It's useful if some control registers are in such an area and
++ * write combining or read caching is not desirable:
++ *
++ * Must be freed with iounmap.
++ */
++
++void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
++{
++ unsigned long last_addr;
++ void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
++ if (!p)
++ return p;
++
++ /* Guaranteed to be > phys_addr, as per __ioremap() */
++ last_addr = phys_addr + size - 1;
++
++ if (is_local_lowmem(last_addr)) {
++ struct page *ppage = virt_to_page(bus_to_virt(phys_addr));
++ unsigned long npages;
++
++ phys_addr &= PAGE_MASK;
++
++ /* This might overflow and become zero.. */
++ last_addr = PAGE_ALIGN(last_addr);
++
++ /* .. but that's ok, because modulo-2**n arithmetic will make
++ * the page-aligned "last - first" come out right.
++ */
++ npages = (last_addr - phys_addr) >> PAGE_SHIFT;
++
++ if (change_page_attr(ppage, npages, PAGE_KERNEL_NOCACHE) < 0) {
++ iounmap(p);
++ p = NULL;
++ }
++ global_flush_tlb();
++ }
++
++ return p;
++}
++EXPORT_SYMBOL(ioremap_nocache);
++
++/**
++ * iounmap - Free a IO remapping
++ * @addr: virtual address from ioremap_*
++ *
++ * Caller must ensure there is only one unmapping for the same pointer.
++ */
++void iounmap(volatile void __iomem *addr)
++{
++ struct vm_struct *p, *o;
++
++ if ((void __force *)addr <= high_memory)
++ return;
++
++ /*
++ * __ioremap special-cases the PCI/ISA range by not instantiating a
++ * vm_area and by simply returning an address into the kernel mapping
++ * of ISA space. So handle that here.
++ */
++ if ((unsigned long) addr >= fix_to_virt(FIX_ISAMAP_BEGIN))
++ return;
++
++ addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long __force)addr);
++
++ /* Use the vm area unlocked, assuming the caller
++ ensures there isn't another iounmap for the same address
++ in parallel. Reuse of the virtual address is prevented by
++ leaving it in the global lists until we're done with it.
++ cpa takes care of the direct mappings. */
++ read_lock(&vmlist_lock);
++ for (p = vmlist; p; p = p->next) {
++ if (p->addr == addr)
++ break;
++ }
++ read_unlock(&vmlist_lock);
++
++ if (!p) {
++ printk("iounmap: bad address %p\n", addr);
++ dump_stack();
++ return;
++ }
++
++ /* Reset the direct mapping. Can block */
++ if ((p->flags >> 20) && is_local_lowmem(p->phys_addr)) {
++ /* p->size includes the guard page, but cpa doesn't like that */
++ change_page_attr(virt_to_page(bus_to_virt(p->phys_addr)),
++ (p->size - PAGE_SIZE) >> PAGE_SHIFT,
++ PAGE_KERNEL);
++ global_flush_tlb();
++ }
++
++ /* Finally remove it */
++ o = remove_vm_area((void *)addr);
++ BUG_ON(p != o || o == NULL);
++ kfree(p);
++}
++EXPORT_SYMBOL(iounmap);
++
++void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
++{
++ unsigned long offset, last_addr;
++ unsigned int nrpages;
++ enum fixed_addresses idx;
++
++ /* Don't allow wraparound or zero size */
++ last_addr = phys_addr + size - 1;
++ if (!size || last_addr < phys_addr)
++ return NULL;
++
++ /*
++ * Don't remap the low PCI/ISA area, it's always mapped..
++ */
++ if (is_initial_xendomain() &&
++ phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
++ return isa_bus_to_virt(phys_addr);
++
++ /*
++ * Mappings have to be page-aligned
++ */
++ offset = phys_addr & ~PAGE_MASK;
++ phys_addr &= PAGE_MASK;
++ size = PAGE_ALIGN(last_addr) - phys_addr;
++
++ /*
++ * Mappings have to fit in the FIX_BTMAP area.
++ */
++ nrpages = size >> PAGE_SHIFT;
++ if (nrpages > NR_FIX_BTMAPS)
++ return NULL;
++
++ /*
++ * Ok, go for it..
++ */
++ idx = FIX_BTMAP_BEGIN;
++ while (nrpages > 0) {
++ set_fixmap(idx, phys_addr);
++ phys_addr += PAGE_SIZE;
++ --idx;
++ --nrpages;
++ }
++ return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN));
++}
++
++void __init bt_iounmap(void *addr, unsigned long size)
++{
++ unsigned long virt_addr;
++ unsigned long offset;
++ unsigned int nrpages;
++ enum fixed_addresses idx;
++
++ virt_addr = (unsigned long)addr;
++ if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN))
++ return;
++ if (virt_addr >= fix_to_virt(FIX_ISAMAP_BEGIN))
++ return;
++ offset = virt_addr & ~PAGE_MASK;
++ nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
++
++ idx = FIX_BTMAP_BEGIN;
++ while (nrpages > 0) {
++ clear_fixmap(idx);
++ --idx;
++ --nrpages;
++ }
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/Makefile linux-2.6.18-xen/arch/i386/mm/Makefile
+--- linux-2.6.18.1/arch/i386/mm/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/mm/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -8,3 +8,11 @@
+ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+ obj-$(CONFIG_HIGHMEM) += highmem.o
+ obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap.o
++
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++
++obj-y += hypervisor.o
++
++obj-y := $(call cherrypickxen, $(obj-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/pageattr.c linux-2.6.18-xen/arch/i386/mm/pageattr.c
+--- linux-2.6.18.1/arch/i386/mm/pageattr.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/mm/pageattr.c 2006-09-04 16:31:00.000000000 +0200
+@@ -84,7 +84,7 @@
+ unsigned long flags;
+
+ set_pte_atomic(kpte, pte); /* change init_mm */
+- if (PTRS_PER_PMD > 1)
++ if (HAVE_SHARED_KERNEL_PMD)
+ return;
+
+ spin_lock_irqsave(&pgd_lock, flags);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/mm/pgtable-xen.c linux-2.6.18-xen/arch/i386/mm/pgtable-xen.c
+--- linux-2.6.18.1/arch/i386/mm/pgtable-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/mm/pgtable-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,699 @@
++/*
++ * linux/arch/i386/mm/pgtable.c
++ */
++
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/swap.h>
++#include <linux/smp.h>
++#include <linux/highmem.h>
++#include <linux/slab.h>
++#include <linux/pagemap.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/fixmap.h>
++#include <asm/e820.h>
++#include <asm/tlb.h>
++#include <asm/tlbflush.h>
++#include <asm/io.h>
++#include <asm/mmu_context.h>
++
++#include <xen/features.h>
++#include <xen/foreign_page.h>
++#include <asm/hypervisor.h>
++
++static void pgd_test_and_unpin(pgd_t *pgd);
++
++void show_mem(void)
++{
++ int total = 0, reserved = 0;
++ int shared = 0, cached = 0;
++ int highmem = 0;
++ struct page *page;
++ pg_data_t *pgdat;
++ unsigned long i;
++ unsigned long flags;
++
++ printk(KERN_INFO "Mem-info:\n");
++ show_free_areas();
++ printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
++ for_each_online_pgdat(pgdat) {
++ pgdat_resize_lock(pgdat, &flags);
++ for (i = 0; i < pgdat->node_spanned_pages; ++i) {
++ page = pgdat_page_nr(pgdat, i);
++ total++;
++ if (PageHighMem(page))
++ highmem++;
++ if (PageReserved(page))
++ reserved++;
++ else if (PageSwapCache(page))
++ cached++;
++ else if (page_count(page))
++ shared += page_count(page) - 1;
++ }
++ pgdat_resize_unlock(pgdat, &flags);
++ }
++ 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);
++
++ printk(KERN_INFO "%lu pages dirty\n", global_page_state(NR_FILE_DIRTY));
++ printk(KERN_INFO "%lu pages writeback\n",
++ global_page_state(NR_WRITEBACK));
++ printk(KERN_INFO "%lu pages mapped\n", global_page_state(NR_FILE_MAPPED));
++ printk(KERN_INFO "%lu pages slab\n", global_page_state(NR_SLAB));
++ printk(KERN_INFO "%lu pages pagetables\n",
++ global_page_state(NR_PAGETABLE));
++}
++
++/*
++ * Associate a virtual page frame with a given physical page frame
++ * and protection flags for that frame.
++ */
++static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++
++ pgd = swapper_pg_dir + pgd_index(vaddr);
++ if (pgd_none(*pgd)) {
++ BUG();
++ return;
++ }
++ pud = pud_offset(pgd, vaddr);
++ if (pud_none(*pud)) {
++ BUG();
++ return;
++ }
++ pmd = pmd_offset(pud, vaddr);
++ if (pmd_none(*pmd)) {
++ BUG();
++ return;
++ }
++ pte = pte_offset_kernel(pmd, vaddr);
++ /* <pfn,flags> stored as-is, to permit clearing entries */
++ set_pte(pte, pfn_pte(pfn, flags));
++
++ /*
++ * It's enough to flush this one mapping.
++ * (PGE mappings get flushed as well)
++ */
++ __flush_tlb_one(vaddr);
++}
++
++/*
++ * Associate a virtual page frame with a given physical page frame
++ * and protection flags for that frame.
++ */
++static void set_pte_pfn_ma(unsigned long vaddr, unsigned long pfn,
++ pgprot_t flags)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++
++ pgd = swapper_pg_dir + pgd_index(vaddr);
++ if (pgd_none(*pgd)) {
++ BUG();
++ return;
++ }
++ pud = pud_offset(pgd, vaddr);
++ if (pud_none(*pud)) {
++ BUG();
++ return;
++ }
++ pmd = pmd_offset(pud, vaddr);
++ if (pmd_none(*pmd)) {
++ BUG();
++ return;
++ }
++ pte = pte_offset_kernel(pmd, vaddr);
++ /* <pfn,flags> stored as-is, to permit clearing entries */
++ set_pte(pte, pfn_pte_ma(pfn, flags));
++
++ /*
++ * It's enough to flush this one mapping.
++ * (PGE mappings get flushed as well)
++ */
++ __flush_tlb_one(vaddr);
++}
++
++/*
++ * Associate a large virtual page frame with a given physical page frame
++ * and protection flags for that frame. pfn is for the base of the page,
++ * vaddr is what the page gets mapped to - both must be properly aligned.
++ * The pmd must already be instantiated. Assumes PAE mode.
++ */
++void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++
++ if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */
++ printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
++ return; /* BUG(); */
++ }
++ if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */
++ printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
++ return; /* BUG(); */
++ }
++ pgd = swapper_pg_dir + pgd_index(vaddr);
++ if (pgd_none(*pgd)) {
++ printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
++ return; /* BUG(); */
++ }
++ pud = pud_offset(pgd, vaddr);
++ pmd = pmd_offset(pud, vaddr);
++ set_pmd(pmd, pfn_pmd(pfn, flags));
++ /*
++ * It's enough to flush this one mapping.
++ * (PGE mappings get flushed as well)
++ */
++ __flush_tlb_one(vaddr);
++}
++
++static int nr_fixmaps = 0;
++unsigned long __FIXADDR_TOP = (HYPERVISOR_VIRT_START - 2 * PAGE_SIZE);
++EXPORT_SYMBOL(__FIXADDR_TOP);
++
++void __set_fixmap (enum fixed_addresses idx, maddr_t phys, pgprot_t flags)
++{
++ unsigned long address = __fix_to_virt(idx);
++
++ if (idx >= __end_of_fixed_addresses) {
++ BUG();
++ return;
++ }
++ switch (idx) {
++ case FIX_WP_TEST:
++#ifdef CONFIG_X86_F00F_BUG
++ case FIX_F00F_IDT:
++#endif
++ set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
++ break;
++ default:
++ set_pte_pfn_ma(address, phys >> PAGE_SHIFT, flags);
++ break;
++ }
++ nr_fixmaps++;
++}
++
++void set_fixaddr_top(unsigned long top)
++{
++ BUG_ON(nr_fixmaps > 0);
++ __FIXADDR_TOP = top - PAGE_SIZE;
++}
++
++pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
++{
++ pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
++ if (pte)
++ make_lowmem_page_readonly(pte, XENFEAT_writable_page_tables);
++ return pte;
++}
++
++struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
++{
++ struct page *pte;
++
++#ifdef CONFIG_HIGHPTE
++ pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0);
++#else
++ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
++ if (pte) {
++ SetPageForeign(pte, pte_free);
++ init_page_count(pte);
++ }
++#endif
++ return pte;
++}
++
++void pte_free(struct page *pte)
++{
++ unsigned long va = (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT);
++
++ if (!pte_write(*virt_to_ptep(va)))
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ va, pfn_pte(page_to_pfn(pte), PAGE_KERNEL), 0));
++
++ ClearPageForeign(pte);
++ init_page_count(pte);
++
++ __free_page(pte);
++}
++
++void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags)
++{
++ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
++}
++
++/*
++ * List of all pgd's needed for non-PAE so it can invalidate entries
++ * in both cached and uncached pgd's; not needed for PAE since the
++ * kernel pmd is shared. If PAE were not to share the pmd a similar
++ * tactic would be needed. This is essentially codepath-based locking
++ * against pageattr.c; it is the unique case in which a valid change
++ * of kernel pagetables can't be lazily synchronized by vmalloc faults.
++ * vmalloc faults work because attached pagetables are never freed.
++ * The locking scheme was chosen on the basis of manfred's
++ * recommendations and having no core impact whatsoever.
++ * -- wli
++ */
++DEFINE_SPINLOCK(pgd_lock);
++struct page *pgd_list;
++
++static inline void pgd_list_add(pgd_t *pgd)
++{
++ struct page *page = virt_to_page(pgd);
++ page->index = (unsigned long)pgd_list;
++ if (pgd_list)
++ set_page_private(pgd_list, (unsigned long)&page->index);
++ pgd_list = page;
++ set_page_private(page, (unsigned long)&pgd_list);
++}
++
++static inline void pgd_list_del(pgd_t *pgd)
++{
++ struct page *next, **pprev, *page = virt_to_page(pgd);
++ next = (struct page *)page->index;
++ pprev = (struct page **)page_private(page);
++ *pprev = next;
++ if (next)
++ set_page_private(next, (unsigned long)pprev);
++}
++
++void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
++{
++ unsigned long flags;
++
++ if (PTRS_PER_PMD > 1) {
++ if (HAVE_SHARED_KERNEL_PMD)
++ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
++ swapper_pg_dir + USER_PTRS_PER_PGD,
++ KERNEL_PGD_PTRS);
++ } else {
++ spin_lock_irqsave(&pgd_lock, flags);
++ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
++ swapper_pg_dir + USER_PTRS_PER_PGD,
++ KERNEL_PGD_PTRS);
++ memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
++ pgd_list_add(pgd);
++ spin_unlock_irqrestore(&pgd_lock, flags);
++ }
++}
++
++/* never called when PTRS_PER_PMD > 1 */
++void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
++{
++ unsigned long flags; /* can be called from interrupt context */
++
++ spin_lock_irqsave(&pgd_lock, flags);
++ pgd_list_del(pgd);
++ spin_unlock_irqrestore(&pgd_lock, flags);
++
++ pgd_test_and_unpin(pgd);
++}
++
++pgd_t *pgd_alloc(struct mm_struct *mm)
++{
++ int i;
++ pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
++ pmd_t **pmd;
++ unsigned long flags;
++
++ pgd_test_and_unpin(pgd);
++
++ if (PTRS_PER_PMD == 1 || !pgd)
++ return pgd;
++
++ if (HAVE_SHARED_KERNEL_PMD) {
++ for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
++ pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
++ if (!pmd)
++ goto out_oom;
++ set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
++ }
++ return pgd;
++ }
++
++ /*
++ * We can race save/restore (if we sleep during a GFP_KERNEL memory
++ * allocation). We therefore store virtual addresses of pmds as they
++ * do not change across save/restore, and poke the machine addresses
++ * into the pgdir under the pgd_lock.
++ */
++ pmd = kmalloc(PTRS_PER_PGD * sizeof(pmd_t *), GFP_KERNEL);
++ if (!pmd) {
++ kmem_cache_free(pgd_cache, pgd);
++ return NULL;
++ }
++
++ /* Allocate pmds, remember virtual addresses. */
++ for (i = 0; i < PTRS_PER_PGD; ++i) {
++ pmd[i] = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
++ if (!pmd[i])
++ goto out_oom;
++ }
++
++ spin_lock_irqsave(&pgd_lock, flags);
++
++ /* Protect against save/restore: move below 4GB under pgd_lock. */
++ if (!xen_feature(XENFEAT_pae_pgdir_above_4gb)) {
++ int rc = xen_create_contiguous_region(
++ (unsigned long)pgd, 0, 32);
++ if (rc) {
++ spin_unlock_irqrestore(&pgd_lock, flags);
++ goto out_oom;
++ }
++ }
++
++ /* Copy kernel pmd contents and write-protect the new pmds. */
++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++ unsigned long v = (unsigned long)i << PGDIR_SHIFT;
++ pgd_t *kpgd = pgd_offset_k(v);
++ pud_t *kpud = pud_offset(kpgd, v);
++ pmd_t *kpmd = pmd_offset(kpud, v);
++ memcpy(pmd[i], kpmd, PAGE_SIZE);
++ make_lowmem_page_readonly(
++ pmd[i], XENFEAT_writable_page_tables);
++ }
++
++ /* It is safe to poke machine addresses of pmds under the pmd_lock. */
++ for (i = 0; i < PTRS_PER_PGD; i++)
++ set_pgd(&pgd[i], __pgd(1 + __pa(pmd[i])));
++
++ /* Ensure this pgd gets picked up and pinned on save/restore. */
++ pgd_list_add(pgd);
++
++ spin_unlock_irqrestore(&pgd_lock, flags);
++
++ kfree(pmd);
++
++ return pgd;
++
++out_oom:
++ if (HAVE_SHARED_KERNEL_PMD) {
++ for (i--; i >= 0; i--)
++ kmem_cache_free(pmd_cache,
++ (void *)__va(pgd_val(pgd[i])-1));
++ } else {
++ for (i--; i >= 0; i--)
++ kmem_cache_free(pmd_cache, pmd[i]);
++ kfree(pmd);
++ }
++ kmem_cache_free(pgd_cache, pgd);
++ return NULL;
++}
++
++void pgd_free(pgd_t *pgd)
++{
++ int i;
++
++ /*
++ * After this the pgd should not be pinned for the duration of this
++ * function's execution. We should never sleep and thus never race:
++ * 1. User pmds will not become write-protected under our feet due
++ * to a concurrent mm_pin_all().
++ * 2. The machine addresses in PGD entries will not become invalid
++ * due to a concurrent save/restore.
++ */
++ pgd_test_and_unpin(pgd);
++
++ /* in the PAE case user pgd entries are overwritten before usage */
++ if (PTRS_PER_PMD > 1) {
++ for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++ kmem_cache_free(pmd_cache, pmd);
++ }
++
++ if (!HAVE_SHARED_KERNEL_PMD) {
++ unsigned long flags;
++ spin_lock_irqsave(&pgd_lock, flags);
++ pgd_list_del(pgd);
++ spin_unlock_irqrestore(&pgd_lock, flags);
++
++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++ make_lowmem_page_writable(
++ pmd, XENFEAT_writable_page_tables);
++ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
++ kmem_cache_free(pmd_cache, pmd);
++ }
++
++ if (!xen_feature(XENFEAT_pae_pgdir_above_4gb))
++ xen_destroy_contiguous_region(
++ (unsigned long)pgd, 0);
++ }
++ }
++
++ /* in the non-PAE case, free_pgtables() clears user pgd entries */
++ kmem_cache_free(pgd_cache, pgd);
++}
++
++void make_lowmem_page_readonly(void *va, unsigned int feature)
++{
++ pte_t *pte;
++ int rc;
++
++ if (xen_feature(feature))
++ return;
++
++ pte = virt_to_ptep(va);
++ rc = HYPERVISOR_update_va_mapping(
++ (unsigned long)va, pte_wrprotect(*pte), 0);
++ BUG_ON(rc);
++}
++
++void make_lowmem_page_writable(void *va, unsigned int feature)
++{
++ pte_t *pte;
++ int rc;
++
++ if (xen_feature(feature))
++ return;
++
++ pte = virt_to_ptep(va);
++ rc = HYPERVISOR_update_va_mapping(
++ (unsigned long)va, pte_mkwrite(*pte), 0);
++ BUG_ON(rc);
++}
++
++void make_page_readonly(void *va, unsigned int feature)
++{
++ pte_t *pte;
++ int rc;
++
++ if (xen_feature(feature))
++ return;
++
++ pte = virt_to_ptep(va);
++ rc = HYPERVISOR_update_va_mapping(
++ (unsigned long)va, pte_wrprotect(*pte), 0);
++ if (rc) /* fallback? */
++ xen_l1_entry_update(pte, pte_wrprotect(*pte));
++ if ((unsigned long)va >= (unsigned long)high_memory) {
++ unsigned long pfn = pte_pfn(*pte);
++#ifdef CONFIG_HIGHMEM
++ if (pfn >= highstart_pfn)
++ kmap_flush_unused(); /* flush stale writable kmaps */
++ else
++#endif
++ make_lowmem_page_readonly(
++ phys_to_virt(pfn << PAGE_SHIFT), feature);
++ }
++}
++
++void make_page_writable(void *va, unsigned int feature)
++{
++ pte_t *pte;
++ int rc;
++
++ if (xen_feature(feature))
++ return;
++
++ pte = virt_to_ptep(va);
++ rc = HYPERVISOR_update_va_mapping(
++ (unsigned long)va, pte_mkwrite(*pte), 0);
++ if (rc) /* fallback? */
++ xen_l1_entry_update(pte, pte_mkwrite(*pte));
++ if ((unsigned long)va >= (unsigned long)high_memory) {
++ unsigned long pfn = pte_pfn(*pte);
++#ifdef CONFIG_HIGHMEM
++ if (pfn < highstart_pfn)
++#endif
++ make_lowmem_page_writable(
++ phys_to_virt(pfn << PAGE_SHIFT), feature);
++ }
++}
++
++void make_pages_readonly(void *va, unsigned int nr, unsigned int feature)
++{
++ if (xen_feature(feature))
++ return;
++
++ while (nr-- != 0) {
++ make_page_readonly(va, feature);
++ va = (void *)((unsigned long)va + PAGE_SIZE);
++ }
++}
++
++void make_pages_writable(void *va, unsigned int nr, unsigned int feature)
++{
++ if (xen_feature(feature))
++ return;
++
++ while (nr-- != 0) {
++ make_page_writable(va, feature);
++ va = (void *)((unsigned long)va + PAGE_SIZE);
++ }
++}
++
++static inline void pgd_walk_set_prot(void *pt, pgprot_t flags)
++{
++ struct page *page = virt_to_page(pt);
++ unsigned long pfn = page_to_pfn(page);
++
++ if (PageHighMem(page))
++ return;
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)__va(pfn << PAGE_SHIFT),
++ pfn_pte(pfn, flags), 0));
++}
++
++static void pgd_walk(pgd_t *pgd_base, pgprot_t flags)
++{
++ pgd_t *pgd = pgd_base;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ int g, u, m;
++
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return;
++
++ for (g = 0; g < USER_PTRS_PER_PGD; g++, pgd++) {
++ if (pgd_none(*pgd))
++ continue;
++ pud = pud_offset(pgd, 0);
++ if (PTRS_PER_PUD > 1) /* not folded */
++ pgd_walk_set_prot(pud,flags);
++ for (u = 0; u < PTRS_PER_PUD; u++, pud++) {
++ if (pud_none(*pud))
++ continue;
++ pmd = pmd_offset(pud, 0);
++ if (PTRS_PER_PMD > 1) /* not folded */
++ pgd_walk_set_prot(pmd,flags);
++ for (m = 0; m < PTRS_PER_PMD; m++, pmd++) {
++ if (pmd_none(*pmd))
++ continue;
++ pte = pte_offset_kernel(pmd,0);
++ pgd_walk_set_prot(pte,flags);
++ }
++ }
++ }
++
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)pgd_base,
++ pfn_pte(virt_to_phys(pgd_base)>>PAGE_SHIFT, flags),
++ UVMF_TLB_FLUSH));
++}
++
++static void __pgd_pin(pgd_t *pgd)
++{
++ pgd_walk(pgd, PAGE_KERNEL_RO);
++ xen_pgd_pin(__pa(pgd));
++ set_bit(PG_pinned, &virt_to_page(pgd)->flags);
++}
++
++static void __pgd_unpin(pgd_t *pgd)
++{
++ xen_pgd_unpin(__pa(pgd));
++ pgd_walk(pgd, PAGE_KERNEL);
++ clear_bit(PG_pinned, &virt_to_page(pgd)->flags);
++}
++
++static void pgd_test_and_unpin(pgd_t *pgd)
++{
++ if (test_bit(PG_pinned, &virt_to_page(pgd)->flags))
++ __pgd_unpin(pgd);
++}
++
++void mm_pin(struct mm_struct *mm)
++{
++ if (xen_feature(XENFEAT_writable_page_tables))
++ return;
++ spin_lock(&mm->page_table_lock);
++ __pgd_pin(mm->pgd);
++ spin_unlock(&mm->page_table_lock);
++}
++
++void mm_unpin(struct mm_struct *mm)
++{
++ if (xen_feature(XENFEAT_writable_page_tables))
++ return;
++ spin_lock(&mm->page_table_lock);
++ __pgd_unpin(mm->pgd);
++ spin_unlock(&mm->page_table_lock);
++}
++
++void mm_pin_all(void)
++{
++ struct page *page;
++
++ /* Only pgds on the pgd_list please: none hidden in the slab cache. */
++ kmem_cache_shrink(pgd_cache);
++
++ if (xen_feature(XENFEAT_writable_page_tables))
++ return;
++
++ for (page = pgd_list; page; page = (struct page *)page->index) {
++ if (!test_bit(PG_pinned, &page->flags))
++ __pgd_pin((pgd_t *)page_address(page));
++ }
++}
++
++void _arch_dup_mmap(struct mm_struct *mm)
++{
++ if (!test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags))
++ mm_pin(mm);
++}
++
++void _arch_exit_mmap(struct mm_struct *mm)
++{
++ struct task_struct *tsk = current;
++
++ task_lock(tsk);
++
++ /*
++ * We aggressively remove defunct pgd from cr3. We execute unmap_vmas()
++ * *much* faster this way, as no tlb flushes means bigger wrpt batches.
++ */
++ if (tsk->active_mm == mm) {
++ tsk->active_mm = &init_mm;
++ atomic_inc(&init_mm.mm_count);
++
++ switch_mm(mm, &init_mm, tsk);
++
++ atomic_dec(&mm->mm_count);
++ BUG_ON(atomic_read(&mm->mm_count) == 0);
++ }
++
++ task_unlock(tsk);
++
++ if (test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags) &&
++ (atomic_read(&mm->mm_count) == 1) &&
++ !mm->context.has_foreign_mappings)
++ mm_unpin(mm);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/oprofile/Makefile linux-2.6.18-xen/arch/i386/oprofile/Makefile
+--- linux-2.6.18.1/arch/i386/oprofile/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/oprofile/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -6,7 +6,11 @@
+ oprofilefs.o oprofile_stats.o \
+ timer_int.o )
+
++ifdef CONFIG_XEN
++oprofile-y := $(DRIVER_OBJS) xenoprof.o
++else
+ oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
+ oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \
+ op_model_ppro.o op_model_p4.o
+ oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/oprofile/xenoprof.c linux-2.6.18-xen/arch/i386/oprofile/xenoprof.c
+--- linux-2.6.18.1/arch/i386/oprofile/xenoprof.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/oprofile/xenoprof.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,584 @@
++/**
++ * @file xenoprof.c
++ *
++ * @remark Copyright 2002 OProfile authors
++ * @remark Read the file COPYING
++ *
++ * @author John Levon <levon at movementarian.org>
++ *
++ * Modified by Aravind Menon and Jose Renato Santos for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ */
++
++#include <linux/init.h>
++#include <linux/notifier.h>
++#include <linux/smp.h>
++#include <linux/oprofile.h>
++#include <linux/sysdev.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/vmalloc.h>
++#include <asm/nmi.h>
++#include <asm/msr.h>
++#include <asm/apic.h>
++#include <asm/pgtable.h>
++#include <xen/evtchn.h>
++#include "op_counter.h"
++
++#include <xen/driver_util.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/xenoprof.h>
++#include <../../../drivers/oprofile/cpu_buffer.h>
++#include <../../../drivers/oprofile/event_buffer.h>
++
++#define MAX_XENOPROF_SAMPLES 16
++
++static int xenoprof_start(void);
++static void xenoprof_stop(void);
++
++static int xenoprof_enabled = 0;
++static unsigned int num_events = 0;
++static int is_primary = 0;
++static int active_defined;
++
++/* sample buffers shared with Xen */
++xenoprof_buf_t * xenoprof_buf[MAX_VIRT_CPUS];
++/* Shared buffer area */
++char * shared_buffer = NULL;
++/* Number of buffers in shared area (one per VCPU) */
++int nbuf;
++/* Mappings of VIRQ_XENOPROF to irq number (per cpu) */
++int ovf_irq[NR_CPUS];
++/* cpu model type string - copied from Xen memory space on XENOPROF_init command */
++char cpu_type[XENOPROF_CPU_TYPE_SIZE];
++
++/* Passive sample buffers shared with Xen */
++xenoprof_buf_t *p_xenoprof_buf[MAX_OPROF_DOMAINS][MAX_VIRT_CPUS];
++/* Passive shared buffer area */
++char *p_shared_buffer[MAX_OPROF_DOMAINS];
++
++#ifdef CONFIG_PM
++
++static int xenoprof_suspend(struct sys_device * dev, pm_message_t state)
++{
++ if (xenoprof_enabled == 1)
++ xenoprof_stop();
++ return 0;
++}
++
++
++static int xenoprof_resume(struct sys_device * dev)
++{
++ if (xenoprof_enabled == 1)
++ xenoprof_start();
++ return 0;
++}
++
++
++static struct sysdev_class oprofile_sysclass = {
++ set_kset_name("oprofile"),
++ .resume = xenoprof_resume,
++ .suspend = xenoprof_suspend
++};
++
++
++static struct sys_device device_oprofile = {
++ .id = 0,
++ .cls = &oprofile_sysclass,
++};
++
++
++static int __init init_driverfs(void)
++{
++ int error;
++ if (!(error = sysdev_class_register(&oprofile_sysclass)))
++ error = sysdev_register(&device_oprofile);
++ return error;
++}
++
++
++static void __exit exit_driverfs(void)
++{
++ sysdev_unregister(&device_oprofile);
++ sysdev_class_unregister(&oprofile_sysclass);
++}
++
++#else
++#define init_driverfs() do { } while (0)
++#define exit_driverfs() do { } while (0)
++#endif /* CONFIG_PM */
++
++unsigned long long oprofile_samples = 0;
++unsigned long long p_oprofile_samples = 0;
++
++unsigned int pdomains;
++struct xenoprof_passive passive_domains[MAX_OPROF_DOMAINS];
++
++static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive)
++{
++ int head, tail, size;
++
++ head = buf->event_head;
++ tail = buf->event_tail;
++ size = buf->event_size;
++
++ if (tail > head) {
++ while (tail < size) {
++ oprofile_add_pc(buf->event_log[tail].eip,
++ buf->event_log[tail].mode,
++ buf->event_log[tail].event);
++ if (!is_passive)
++ oprofile_samples++;
++ else
++ p_oprofile_samples++;
++ tail++;
++ }
++ tail = 0;
++ }
++ while (tail < head) {
++ oprofile_add_pc(buf->event_log[tail].eip,
++ buf->event_log[tail].mode,
++ buf->event_log[tail].event);
++ if (!is_passive)
++ oprofile_samples++;
++ else
++ p_oprofile_samples++;
++ tail++;
++ }
++
++ buf->event_tail = tail;
++}
++
++static void xenoprof_handle_passive(void)
++{
++ int i, j;
++ int flag_domain, flag_switch = 0;
++
++ for (i = 0; i < pdomains; i++) {
++ flag_domain = 0;
++ for (j = 0; j < passive_domains[i].nbuf; j++) {
++ xenoprof_buf_t *buf = p_xenoprof_buf[i][j];
++ if (buf->event_head == buf->event_tail)
++ continue;
++ if (!flag_domain) {
++ if (!oprofile_add_domain_switch(passive_domains[i].
++ domain_id))
++ goto done;
++ flag_domain = 1;
++ }
++ xenoprof_add_pc(buf, 1);
++ flag_switch = 1;
++ }
++ }
++done:
++ if (flag_switch)
++ oprofile_add_domain_switch(COORDINATOR_DOMAIN);
++}
++
++static irqreturn_t
++xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs)
++{
++ struct xenoprof_buf * buf;
++ int cpu;
++ static unsigned long flag;
++
++ cpu = smp_processor_id();
++ buf = xenoprof_buf[cpu];
++
++ xenoprof_add_pc(buf, 0);
++
++ if (is_primary && !test_and_set_bit(0, &flag)) {
++ xenoprof_handle_passive();
++ smp_mb__before_clear_bit();
++ clear_bit(0, &flag);
++ }
++
++ return IRQ_HANDLED;
++}
++
++
++static void unbind_virq(void)
++{
++ int i;
++
++ for_each_possible_cpu(i) {
++ if (ovf_irq[i] >= 0) {
++ unbind_from_irqhandler(ovf_irq[i], NULL);
++ ovf_irq[i] = -1;
++ }
++ }
++}
++
++
++static int bind_virq(void)
++{
++ int i, result;
++
++ for_each_possible_cpu(i) {
++ result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
++ i,
++ xenoprof_ovf_interrupt,
++ SA_INTERRUPT,
++ "xenoprof",
++ NULL);
++
++ if (result < 0) {
++ unbind_virq();
++ return result;
++ }
++
++ ovf_irq[i] = result;
++ }
++
++ return 0;
++}
++
++
++static int map_xenoprof_buffer(int max_samples)
++{
++ struct xenoprof_get_buffer get_buffer;
++ struct xenoprof_buf *buf;
++ int npages, ret, i;
++ struct vm_struct *area;
++
++ if ( shared_buffer )
++ return 0;
++
++ get_buffer.max_samples = max_samples;
++
++ if ( (ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, &get_buffer)) )
++ return ret;
++
++ nbuf = get_buffer.nbuf;
++ npages = (get_buffer.bufsize * nbuf - 1) / PAGE_SIZE + 1;
++
++ area = alloc_vm_area(npages * PAGE_SIZE);
++ if (area == NULL)
++ return -ENOMEM;
++
++ if ( (ret = direct_kernel_remap_pfn_range(
++ (unsigned long)area->addr,
++ get_buffer.buf_maddr >> PAGE_SHIFT,
++ npages * PAGE_SIZE, __pgprot(_KERNPG_TABLE), DOMID_SELF)) ) {
++ vunmap(area->addr);
++ return ret;
++ }
++
++ shared_buffer = area->addr;
++ for (i=0; i< nbuf; i++) {
++ buf = (struct xenoprof_buf*)
++ &shared_buffer[i * get_buffer.bufsize];
++ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
++ xenoprof_buf[buf->vcpu_id] = buf;
++ }
++
++ return 0;
++}
++
++
++static int xenoprof_setup(void)
++{
++ int ret;
++ int i;
++
++ if ( (ret = map_xenoprof_buffer(MAX_XENOPROF_SAMPLES)) )
++ return ret;
++
++ if ( (ret = bind_virq()) )
++ return ret;
++
++ if (is_primary) {
++ struct xenoprof_counter counter;
++
++ /* Define dom0 as an active domain if not done yet */
++ if (!active_defined) {
++ domid_t domid;
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
++ if (ret)
++ goto err;
++ domid = 0;
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
++ if (ret)
++ goto err;
++ active_defined = 1;
++ }
++
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reserve_counters, NULL);
++ if (ret)
++ goto err;
++ for (i=0; i<num_events; i++) {
++ counter.ind = i;
++ counter.count = (uint64_t)counter_config[i].count;
++ counter.enabled = (uint32_t)counter_config[i].enabled;
++ counter.event = (uint32_t)counter_config[i].event;
++ counter.kernel = (uint32_t)counter_config[i].kernel;
++ counter.user = (uint32_t)counter_config[i].user;
++ counter.unit_mask = (uint64_t)counter_config[i].unit_mask;
++ HYPERVISOR_xenoprof_op(XENOPROF_counter,
++ &counter);
++ }
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_setup_events, NULL);
++
++ if (ret)
++ goto err;
++ }
++
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_enable_virq, NULL);
++ if (ret)
++ goto err;
++
++ xenoprof_enabled = 1;
++ return 0;
++ err:
++ unbind_virq();
++ return ret;
++}
++
++
++static void xenoprof_shutdown(void)
++{
++ xenoprof_enabled = 0;
++
++ HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL);
++
++ if (is_primary) {
++ HYPERVISOR_xenoprof_op(XENOPROF_release_counters, NULL);
++ active_defined = 0;
++ }
++
++ unbind_virq();
++
++}
++
++
++static int xenoprof_start(void)
++{
++ int ret = 0;
++
++ if (is_primary)
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_start, NULL);
++
++ return ret;
++}
++
++
++static void xenoprof_stop(void)
++{
++ if (is_primary)
++ HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL);
++}
++
++
++static int xenoprof_set_active(int * active_domains,
++ unsigned int adomains)
++{
++ int ret = 0;
++ int i;
++ int set_dom0 = 0;
++ domid_t domid;
++
++ if (!is_primary)
++ return 0;
++
++ if (adomains > MAX_OPROF_DOMAINS)
++ return -E2BIG;
++
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
++ if (ret)
++ return ret;
++
++ for (i=0; i<adomains; i++) {
++ domid = active_domains[i];
++ if (domid != active_domains[i]) {
++ ret = -EINVAL;
++ goto out;
++ }
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
++ if (ret)
++ goto out;
++ if (active_domains[i] == 0)
++ set_dom0 = 1;
++ }
++ /* dom0 must always be active but may not be in the list */
++ if (!set_dom0) {
++ domid = 0;
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
++ }
++
++out:
++ if (ret)
++ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
++ active_defined = !ret;
++ return ret;
++}
++
++static int xenoprof_set_passive(int * p_domains,
++ unsigned int pdoms)
++{
++ int ret;
++ int i, j;
++ int npages;
++ struct xenoprof_buf *buf;
++ struct vm_struct *area;
++ pgprot_t prot = __pgprot(_KERNPG_TABLE);
++
++ if (!is_primary)
++ return 0;
++
++ if (pdoms > MAX_OPROF_DOMAINS)
++ return -E2BIG;
++
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_passive_list, NULL);
++ if (ret)
++ return ret;
++
++ for (i = 0; i < pdoms; i++) {
++ passive_domains[i].domain_id = p_domains[i];
++ passive_domains[i].max_samples = 2048;
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive,
++ &passive_domains[i]);
++ if (ret)
++ goto out;
++
++ npages = (passive_domains[i].bufsize * passive_domains[i].nbuf - 1) / PAGE_SIZE + 1;
++
++ area = alloc_vm_area(npages * PAGE_SIZE);
++ if (area == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ret = direct_kernel_remap_pfn_range(
++ (unsigned long)area->addr,
++ passive_domains[i].buf_maddr >> PAGE_SHIFT,
++ npages * PAGE_SIZE, prot, DOMID_SELF);
++ if (ret) {
++ vunmap(area->addr);
++ goto out;
++ }
++
++ p_shared_buffer[i] = area->addr;
++
++ for (j = 0; j < passive_domains[i].nbuf; j++) {
++ buf = (struct xenoprof_buf *)
++ &p_shared_buffer[i][j * passive_domains[i].bufsize];
++ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
++ p_xenoprof_buf[i][buf->vcpu_id] = buf;
++ }
++
++ }
++
++ pdomains = pdoms;
++ return 0;
++
++out:
++ for (j = 0; j < i; j++) {
++ vunmap(p_shared_buffer[j]);
++ p_shared_buffer[j] = NULL;
++ }
++
++ return ret;
++}
++
++struct op_counter_config counter_config[OP_MAX_COUNTER];
++
++static int xenoprof_create_files(struct super_block * sb, struct dentry * root)
++{
++ unsigned int i;
++
++ for (i = 0; i < num_events; ++i) {
++ struct dentry * dir;
++ char buf[2];
++
++ snprintf(buf, 2, "%d", i);
++ dir = oprofilefs_mkdir(sb, root, buf);
++ oprofilefs_create_ulong(sb, dir, "enabled",
++ &counter_config[i].enabled);
++ oprofilefs_create_ulong(sb, dir, "event",
++ &counter_config[i].event);
++ oprofilefs_create_ulong(sb, dir, "count",
++ &counter_config[i].count);
++ oprofilefs_create_ulong(sb, dir, "unit_mask",
++ &counter_config[i].unit_mask);
++ oprofilefs_create_ulong(sb, dir, "kernel",
++ &counter_config[i].kernel);
++ oprofilefs_create_ulong(sb, dir, "user",
++ &counter_config[i].user);
++ }
++
++ return 0;
++}
++
++
++struct oprofile_operations xenoprof_ops = {
++ .create_files = xenoprof_create_files,
++ .set_active = xenoprof_set_active,
++ .set_passive = xenoprof_set_passive,
++ .setup = xenoprof_setup,
++ .shutdown = xenoprof_shutdown,
++ .start = xenoprof_start,
++ .stop = xenoprof_stop
++};
++
++
++/* in order to get driverfs right */
++static int using_xenoprof;
++
++int __init oprofile_arch_init(struct oprofile_operations * ops)
++{
++ struct xenoprof_init init;
++ int ret, i;
++
++ ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init);
++
++ if (!ret) {
++ num_events = init.num_events;
++ is_primary = init.is_primary;
++
++ /* just in case - make sure we do not overflow event list
++ (i.e. counter_config list) */
++ if (num_events > OP_MAX_COUNTER)
++ num_events = OP_MAX_COUNTER;
++
++ /* cpu_type is detected by Xen */
++ cpu_type[XENOPROF_CPU_TYPE_SIZE-1] = 0;
++ strncpy(cpu_type, init.cpu_type, XENOPROF_CPU_TYPE_SIZE - 1);
++ xenoprof_ops.cpu_type = cpu_type;
++
++ init_driverfs();
++ using_xenoprof = 1;
++ *ops = xenoprof_ops;
++
++ for (i=0; i<NR_CPUS; i++)
++ ovf_irq[i] = -1;
++
++ active_defined = 0;
++ }
++ printk(KERN_INFO "oprofile_arch_init: ret %d, events %d, "
++ "is_primary %d\n", ret, num_events, is_primary);
++ return ret;
++}
++
++
++void __exit oprofile_arch_exit(void)
++{
++ int i;
++
++ if (using_xenoprof)
++ exit_driverfs();
++
++ if (shared_buffer) {
++ vunmap(shared_buffer);
++ shared_buffer = NULL;
++ }
++ if (is_primary) {
++ for (i = 0; i < pdomains; i++)
++ if (p_shared_buffer[i]) {
++ vunmap(p_shared_buffer[i]);
++ p_shared_buffer[i] = NULL;
++ }
++ HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL);
++ }
++
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/pci/irq-xen.c linux-2.6.18-xen/arch/i386/pci/irq-xen.c
+--- linux-2.6.18.1/arch/i386/pci/irq-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/pci/irq-xen.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,1206 @@
++/*
++ * Low-Level PCI Support for PC -- Routing of Interrupts
++ *
++ * (c) 1999--2000 Martin Mares <mj at ucw.cz>
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/dmi.h>
++#include <asm/io.h>
++#include <asm/smp.h>
++#include <asm/io_apic.h>
++#include <linux/irq.h>
++#include <linux/acpi.h>
++
++#include "pci.h"
++
++#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
++#define PIRQ_VERSION 0x0100
++
++static int broken_hp_bios_irq9;
++static int acer_tm360_irqrouting;
++
++static struct irq_routing_table *pirq_table;
++
++static int pirq_enable_irq(struct pci_dev *dev);
++
++/*
++ * Never use: 0, 1, 2 (timer, keyboard, and cascade)
++ * Avoid using: 13, 14 and 15 (FP error and IDE).
++ * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
++ */
++unsigned int pcibios_irq_mask = 0xfff8;
++
++static int pirq_penalty[16] = {
++ 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
++ 0, 0, 0, 0, 1000, 100000, 100000, 100000
++};
++
++struct irq_router {
++ char *name;
++ u16 vendor, device;
++ int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
++ int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
++};
++
++struct irq_router_handler {
++ u16 vendor;
++ int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device);
++};
++
++int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
++void (*pcibios_disable_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(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt);
++ return rt;
++ }
++ return NULL;
++}
++
++
++
++/*
++ * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
++ */
++
++static struct irq_routing_table * __init pirq_find_routing_table(void)
++{
++ u8 *addr;
++ struct irq_routing_table *rt;
++
++#ifdef CONFIG_XEN
++ if (!is_initial_xendomain())
++ return NULL;
++#endif
++ if (pirq_table_addr) {
++ rt = pirq_check_routing_table((u8 *) isa_bus_to_virt(pirq_table_addr));
++ if (rt)
++ return rt;
++ printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
++ }
++ for(addr = (u8 *) isa_bus_to_virt(0xf0000); addr < (u8 *) isa_bus_to_virt(0x100000); addr += 16) {
++ rt = pirq_check_routing_table(addr);
++ if (rt)
++ return rt;
++ }
++
++ return NULL;
++}
++
++/*
++ * If we have a IRQ routing table, use it to search for peer host
++ * bridges. It's a gross hack, but since there are no other known
++ * ways how to get a list of buses, we have to go this way.
++ */
++
++static void __init pirq_peer_trick(void)
++{
++ struct irq_routing_table *rt = pirq_table;
++ u8 busmap[256];
++ int i;
++ struct irq_info *e;
++
++ memset(busmap, 0, sizeof(busmap));
++ for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
++ e = &rt->slots[i];
++#ifdef DEBUG
++ {
++ int j;
++ DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
++ for(j=0; j<4; j++)
++ DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
++ DBG("\n");
++ }
++#endif
++ busmap[e->bus] = 1;
++ }
++ for(i = 1; i < 256; i++) {
++ if (!busmap[i] || pci_find_bus(0, i))
++ continue;
++ if (pci_scan_bus(i, &pci_root_ops, NULL))
++ printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
++ }
++ pcibios_last_bus = -1;
++}
++
++/*
++ * Code for querying and setting of IRQ routes on various interrupt routers.
++ */
++
++void eisa_set_level_irq(unsigned int irq)
++{
++ unsigned char mask = 1 << (irq & 7);
++ unsigned int port = 0x4d0 + (irq >> 3);
++ unsigned char val;
++ static u16 eisa_irq_mask;
++
++ if (irq >= 16 || (1 << irq) & eisa_irq_mask)
++ return;
++
++ eisa_irq_mask |= (1 << irq);
++ printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq);
++ val = inb(port);
++ if (!(val & mask)) {
++ DBG(KERN_DEBUG " -> edge");
++ outb(val | mask, port);
++ }
++}
++
++/*
++ * Common IRQ routing practice: nybbles in config space,
++ * offset by some magic constant.
++ */
++static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
++{
++ u8 x;
++ unsigned reg = offset + (nr >> 1);
++
++ pci_read_config_byte(router, reg, &x);
++ return (nr & 1) ? (x >> 4) : (x & 0xf);
++}
++
++static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
++{
++ u8 x;
++ unsigned reg = offset + (nr >> 1);
++
++ pci_read_config_byte(router, reg, &x);
++ x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
++ pci_write_config_byte(router, reg, x);
++}
++
++/*
++ * ALI pirq entries are damn ugly, and completely undocumented.
++ * This has been figured out from pirq tables, and it's not a pretty
++ * picture.
++ */
++static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ static const unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
++
++ return irqmap[read_config_nybble(router, 0x48, pirq-1)];
++}
++
++static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ static const unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
++ unsigned int val = irqmap[irq];
++
++ if (val) {
++ write_config_nybble(router, 0x48, pirq-1, val);
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
++ * just a pointer to the config space.
++ */
++static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ u8 x;
++
++ pci_read_config_byte(router, pirq, &x);
++ return (x < 16) ? x : 0;
++}
++
++static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ pci_write_config_byte(router, pirq, irq);
++ return 1;
++}
++
++/*
++ * The VIA pirq rules are nibble-based, like ALI,
++ * but without the ugly irq number munging.
++ * However, PIRQD is in the upper instead of lower 4 bits.
++ */
++static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq);
++}
++
++static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq);
++ return 1;
++}
++
++/*
++ * The VIA pirq rules are nibble-based, like ALI,
++ * but without the ugly irq number munging.
++ * However, for 82C586, nibble map is different .
++ */
++static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ static const unsigned int pirqmap[4] = { 3, 2, 5, 1 };
++ return read_config_nybble(router, 0x55, pirqmap[pirq-1]);
++}
++
++static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ static const unsigned int pirqmap[4] = { 3, 2, 5, 1 };
++ write_config_nybble(router, 0x55, pirqmap[pirq-1], irq);
++ return 1;
++}
++
++/*
++ * ITE 8330G pirq rules are nibble-based
++ * FIXME: pirqmap may be { 1, 0, 3, 2 },
++ * 2+3 are both mapped to irq 9 on my system
++ */
++static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ static const unsigned char pirqmap[4] = { 1, 0, 2, 3 };
++ return read_config_nybble(router,0x43, pirqmap[pirq-1]);
++}
++
++static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ static const unsigned char pirqmap[4] = { 1, 0, 2, 3 };
++ write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
++ return 1;
++}
++
++/*
++ * OPTI: high four bits are nibble pointer..
++ * I wonder what the low bits do?
++ */
++static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ return read_config_nybble(router, 0xb8, pirq >> 4);
++}
++
++static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ write_config_nybble(router, 0xb8, pirq >> 4, irq);
++ return 1;
++}
++
++/*
++ * Cyrix: nibble offset 0x5C
++ * 0x5C bits 7:4 is INTB bits 3:0 is INTA
++ * 0x5D bits 7:4 is INTD bits 3:0 is INTC
++ */
++static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ return read_config_nybble(router, 0x5C, (pirq-1)^1);
++}
++
++static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
++ return 1;
++}
++
++/*
++ * PIRQ routing for SiS 85C503 router used in several SiS chipsets.
++ * We have to deal with the following issues here:
++ * - vendors have different ideas about the meaning of link values
++ * - some onboard devices (integrated in the chipset) have special
++ * links and are thus routed differently (i.e. not via PCI INTA-INTD)
++ * - different revision of the router have a different layout for
++ * the routing registers, particularly for the onchip devices
++ *
++ * For all routing registers the common thing is we have one byte
++ * per routeable link which is defined as:
++ * bit 7 IRQ mapping enabled (0) or disabled (1)
++ * bits [6:4] reserved (sometimes used for onchip devices)
++ * bits [3:0] IRQ to map to
++ * allowed: 3-7, 9-12, 14-15
++ * reserved: 0, 1, 2, 8, 13
++ *
++ * The config-space registers located at 0x41/0x42/0x43/0x44 are
++ * always used to route the normal PCI INT A/B/C/D respectively.
++ * Apparently there are systems implementing PCI routing table using
++ * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D.
++ * We try our best to handle both link mappings.
++ *
++ * Currently (2003-05-21) it appears most SiS chipsets follow the
++ * definition of routing registers from the SiS-5595 southbridge.
++ * According to the SiS 5595 datasheets the revision id's of the
++ * router (ISA-bridge) should be 0x01 or 0xb0.
++ *
++ * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1.
++ * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets.
++ * They seem to work with the current routing code. However there is
++ * some concern because of the two USB-OHCI HCs (original SiS 5595
++ * had only one). YMMV.
++ *
++ * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1:
++ *
++ * 0x61: IDEIRQ:
++ * bits [6:5] must be written 01
++ * bit 4 channel-select primary (0), secondary (1)
++ *
++ * 0x62: USBIRQ:
++ * bit 6 OHCI function disabled (0), enabled (1)
++ *
++ * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved
++ *
++ * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved
++ *
++ * We support USBIRQ (in addition to INTA-INTD) and keep the
++ * IDE, ACPI and DAQ routing untouched as set by the BIOS.
++ *
++ * Currently the only reported exception is the new SiS 65x chipset
++ * which includes the SiS 69x southbridge. Here we have the 85C503
++ * router revision 0x04 and there are changes in the register layout
++ * mostly related to the different USB HCs with USB 2.0 support.
++ *
++ * Onchip routing for router rev-id 0x04 (try-and-error observation)
++ *
++ * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs
++ * bit 6-4 are probably unused, not like 5595
++ */
++
++#define PIRQ_SIS_IRQ_MASK 0x0f
++#define PIRQ_SIS_IRQ_DISABLE 0x80
++#define PIRQ_SIS_USB_ENABLE 0x40
++
++static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ u8 x;
++ int reg;
++
++ reg = pirq;
++ if (reg >= 0x01 && reg <= 0x04)
++ reg += 0x40;
++ pci_read_config_byte(router, reg, &x);
++ return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
++}
++
++static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ u8 x;
++ int reg;
++
++ reg = pirq;
++ if (reg >= 0x01 && reg <= 0x04)
++ reg += 0x40;
++ pci_read_config_byte(router, reg, &x);
++ x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE);
++ x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE;
++ pci_write_config_byte(router, reg, x);
++ return 1;
++}
++
++
++/*
++ * VLSI: nibble offset 0x74 - educated guess due to routing table and
++ * config space of VLSI 82C534 PCI-bridge/router (1004:0102)
++ * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
++ * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
++ * for the busbridge to the docking station.
++ */
++
++static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ if (pirq > 8) {
++ printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
++ return 0;
++ }
++ return read_config_nybble(router, 0x74, pirq-1);
++}
++
++static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ if (pirq > 8) {
++ printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
++ return 0;
++ }
++ write_config_nybble(router, 0x74, pirq-1, irq);
++ return 1;
++}
++
++/*
++ * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
++ * and Redirect I/O registers (0x0c00 and 0x0c01). The Index register
++ * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect
++ * register is a straight binary coding of desired PIC IRQ (low nibble).
++ *
++ * The 'link' value in the PIRQ table is already in the correct format
++ * for the Index register. There are some special index values:
++ * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
++ * and 0x03 for SMBus.
++ */
++static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ outb_p(pirq, 0xc00);
++ return inb(0xc01) & 0xf;
++}
++
++static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ outb_p(pirq, 0xc00);
++ outb_p(irq, 0xc01);
++ return 1;
++}
++
++/* Support for AMD756 PCI IRQ Routing
++ * Jhon H. Caicedo <jhcaiced at osso.org.co>
++ * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
++ * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
++ * The AMD756 pirq rules are nibble-based
++ * offset 0x56 0-3 PIRQA 4-7 PIRQB
++ * offset 0x57 0-3 PIRQC 4-7 PIRQD
++ */
++static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
++{
++ u8 irq;
++ irq = 0;
++ if (pirq <= 4)
++ {
++ irq = read_config_nybble(router, 0x56, pirq - 1);
++ }
++ printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
++ dev->vendor, dev->device, pirq, irq);
++ return irq;
++}
++
++static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n",
++ dev->vendor, dev->device, pirq, irq);
++ if (pirq <= 4)
++ {
++ write_config_nybble(router, 0x56, pirq - 1, irq);
++ }
++ return 1;
++}
++
++#ifdef CONFIG_PCI_BIOS
++
++static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
++{
++ struct pci_dev *bridge;
++ int pin = pci_get_interrupt_pin(dev, &bridge);
++ return pcibios_set_irq_routing(bridge, pin, irq);
++}
++
++#endif
++
++static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ static struct pci_device_id __initdata pirq_440gx[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) },
++ { },
++ };
++
++ /* 440GX has a proprietary PIRQ router -- don't use it */
++ if (pci_dev_present(pirq_440gx))
++ return 0;
++
++ switch(device)
++ {
++ case PCI_DEVICE_ID_INTEL_82371FB_0:
++ case PCI_DEVICE_ID_INTEL_82371SB_0:
++ case PCI_DEVICE_ID_INTEL_82371AB_0:
++ case PCI_DEVICE_ID_INTEL_82371MX:
++ case PCI_DEVICE_ID_INTEL_82443MX_0:
++ case PCI_DEVICE_ID_INTEL_82801AA_0:
++ case PCI_DEVICE_ID_INTEL_82801AB_0:
++ case PCI_DEVICE_ID_INTEL_82801BA_0:
++ case PCI_DEVICE_ID_INTEL_82801BA_10:
++ case PCI_DEVICE_ID_INTEL_82801CA_0:
++ case PCI_DEVICE_ID_INTEL_82801CA_12:
++ case PCI_DEVICE_ID_INTEL_82801DB_0:
++ case PCI_DEVICE_ID_INTEL_82801E_0:
++ case PCI_DEVICE_ID_INTEL_82801EB_0:
++ case PCI_DEVICE_ID_INTEL_ESB_1:
++ case PCI_DEVICE_ID_INTEL_ICH6_0:
++ case PCI_DEVICE_ID_INTEL_ICH6_1:
++ case PCI_DEVICE_ID_INTEL_ICH7_0:
++ case PCI_DEVICE_ID_INTEL_ICH7_1:
++ case PCI_DEVICE_ID_INTEL_ICH7_30:
++ case PCI_DEVICE_ID_INTEL_ICH7_31:
++ case PCI_DEVICE_ID_INTEL_ESB2_0:
++ case PCI_DEVICE_ID_INTEL_ICH8_0:
++ case PCI_DEVICE_ID_INTEL_ICH8_1:
++ case PCI_DEVICE_ID_INTEL_ICH8_2:
++ case PCI_DEVICE_ID_INTEL_ICH8_3:
++ case PCI_DEVICE_ID_INTEL_ICH8_4:
++ r->name = "PIIX/ICH";
++ r->get = pirq_piix_get;
++ r->set = pirq_piix_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int via_router_probe(struct irq_router *r,
++ struct pci_dev *router, u16 device)
++{
++ /* FIXME: We should move some of the quirk fixup stuff here */
++
++ /*
++ * work arounds for some buggy BIOSes
++ */
++ if (device == PCI_DEVICE_ID_VIA_82C586_0) {
++ switch(router->device) {
++ case PCI_DEVICE_ID_VIA_82C686:
++ /*
++ * Asus k7m bios wrongly reports 82C686A
++ * as 586-compatible
++ */
++ device = PCI_DEVICE_ID_VIA_82C686;
++ break;
++ case PCI_DEVICE_ID_VIA_8235:
++ /**
++ * Asus a7v-x bios wrongly reports 8235
++ * as 586-compatible
++ */
++ device = PCI_DEVICE_ID_VIA_8235;
++ break;
++ }
++ }
++
++ switch(device) {
++ case PCI_DEVICE_ID_VIA_82C586_0:
++ r->name = "VIA";
++ r->get = pirq_via586_get;
++ r->set = pirq_via586_set;
++ return 1;
++ case PCI_DEVICE_ID_VIA_82C596:
++ case PCI_DEVICE_ID_VIA_82C686:
++ case PCI_DEVICE_ID_VIA_8231:
++ case PCI_DEVICE_ID_VIA_8233A:
++ case PCI_DEVICE_ID_VIA_8235:
++ case PCI_DEVICE_ID_VIA_8237:
++ /* FIXME: add new ones for 8233/5 */
++ r->name = "VIA";
++ r->get = pirq_via_get;
++ r->set = pirq_via_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_VLSI_82C534:
++ r->name = "VLSI 82C534";
++ r->get = pirq_vlsi_get;
++ r->set = pirq_vlsi_set;
++ return 1;
++ }
++ return 0;
++}
++
++
++static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_SERVERWORKS_OSB4:
++ case PCI_DEVICE_ID_SERVERWORKS_CSB5:
++ r->name = "ServerWorks";
++ r->get = pirq_serverworks_get;
++ r->set = pirq_serverworks_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ if (device != PCI_DEVICE_ID_SI_503)
++ return 0;
++
++ r->name = "SIS";
++ r->get = pirq_sis_get;
++ r->set = pirq_sis_set;
++ return 1;
++}
++
++static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_CYRIX_5520:
++ r->name = "NatSemi";
++ r->get = pirq_cyrix_get;
++ r->set = pirq_cyrix_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_OPTI_82C700:
++ r->name = "OPTI";
++ r->get = pirq_opti_get;
++ r->set = pirq_opti_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_ITE_IT8330G_0:
++ r->name = "ITE";
++ r->get = pirq_ite_get;
++ r->set = pirq_ite_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_AL_M1533:
++ case PCI_DEVICE_ID_AL_M1563:
++ printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n");
++ r->name = "ALI";
++ r->get = pirq_ali_get;
++ r->set = pirq_ali_set;
++ return 1;
++ }
++ return 0;
++}
++
++static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
++{
++ switch(device)
++ {
++ case PCI_DEVICE_ID_AMD_VIPER_740B:
++ r->name = "AMD756";
++ break;
++ case PCI_DEVICE_ID_AMD_VIPER_7413:
++ r->name = "AMD766";
++ break;
++ case PCI_DEVICE_ID_AMD_VIPER_7443:
++ r->name = "AMD768";
++ break;
++ default:
++ return 0;
++ }
++ r->get = pirq_amd756_get;
++ r->set = pirq_amd756_set;
++ return 1;
++}
++
++static __initdata struct irq_router_handler pirq_routers[] = {
++ { PCI_VENDOR_ID_INTEL, intel_router_probe },
++ { PCI_VENDOR_ID_AL, ali_router_probe },
++ { PCI_VENDOR_ID_ITE, ite_router_probe },
++ { PCI_VENDOR_ID_VIA, via_router_probe },
++ { PCI_VENDOR_ID_OPTI, opti_router_probe },
++ { PCI_VENDOR_ID_SI, sis_router_probe },
++ { PCI_VENDOR_ID_CYRIX, cyrix_router_probe },
++ { PCI_VENDOR_ID_VLSI, vlsi_router_probe },
++ { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
++ { PCI_VENDOR_ID_AMD, amd_router_probe },
++ /* Someone with docs needs to add the ATI Radeon IGP */
++ { 0, NULL }
++};
++static struct irq_router pirq_router;
++static struct pci_dev *pirq_router_dev;
++
++
++/*
++ * FIXME: should we have an option to say "generic for
++ * chipset" ?
++ */
++
++static void __init pirq_find_router(struct irq_router *r)
++{
++ struct irq_routing_table *rt = pirq_table;
++ struct irq_router_handler *h;
++
++#ifdef CONFIG_PCI_BIOS
++ if (!rt->signature) {
++ printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
++ r->set = pirq_bios_set;
++ r->name = "BIOS";
++ return;
++ }
++#endif
++
++ /* Default unless a driver reloads it */
++ r->name = "default";
++ r->get = NULL;
++ r->set = NULL;
++
++ DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n",
++ rt->rtr_vendor, rt->rtr_device);
++
++ pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
++ if (!pirq_router_dev) {
++ DBG(KERN_DEBUG "PCI: Interrupt router not found at "
++ "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
++ return;
++ }
++
++ for( h = pirq_routers; h->vendor; h++) {
++ /* First look for a router match */
++ if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device))
++ break;
++ /* Fall back to a device match */
++ if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device))
++ break;
++ }
++ printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
++ pirq_router.name,
++ pirq_router_dev->vendor,
++ pirq_router_dev->device,
++ pci_name(pirq_router_dev));
++}
++
++static struct irq_info *pirq_get_info(struct pci_dev *dev)
++{
++ struct irq_routing_table *rt = pirq_table;
++ int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
++ struct irq_info *info;
++
++ for (info = rt->slots; entries--; info++)
++ if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
++ return info;
++ return NULL;
++}
++
++static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
++{
++ u8 pin;
++ struct irq_info *info;
++ int i, pirq, newirq;
++ int irq = 0;
++ u32 mask;
++ struct irq_router *r = &pirq_router;
++ struct pci_dev *dev2 = NULL;
++ char *msg = NULL;
++
++ /* Find IRQ pin */
++ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
++ if (!pin) {
++ DBG(KERN_DEBUG " -> no interrupt pin\n");
++ return 0;
++ }
++ pin = pin - 1;
++
++ /* Find IRQ routing entry */
++
++ if (!pirq_table)
++ return 0;
++
++ DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin);
++ info = pirq_get_info(dev);
++ if (!info) {
++ DBG(" -> not found in routing table\n" KERN_DEBUG);
++ return 0;
++ }
++ pirq = info->irq[pin].link;
++ mask = info->irq[pin].bitmap;
++ if (!pirq) {
++ DBG(" -> not routed\n" KERN_DEBUG);
++ return 0;
++ }
++ DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
++ mask &= pcibios_irq_mask;
++
++ /* Work around broken HP Pavilion Notebooks which assign USB to
++ IRQ 9 even though it is actually wired to IRQ 11 */
++
++ if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
++ dev->irq = 11;
++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
++ r->set(pirq_router_dev, dev, pirq, 11);
++ }
++
++ /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */
++ if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) {
++ pirq = 0x68;
++ mask = 0x400;
++ dev->irq = r->get(pirq_router_dev, dev, pirq);
++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
++ }
++
++ /*
++ * Find the best IRQ to assign: use the one
++ * reported by the device if possible.
++ */
++ newirq = dev->irq;
++ if (newirq && !((1 << newirq) & mask)) {
++ if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
++ else printk("\n" KERN_WARNING
++ "PCI: IRQ %i for device %s doesn't match PIRQ mask "
++ "- try pci=usepirqmask\n" KERN_DEBUG, newirq,
++ pci_name(dev));
++ }
++ if (!newirq && assign) {
++ for (i = 0; i < 16; i++) {
++ if (!(mask & (1 << i)))
++ continue;
++ if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, IRQF_SHARED))
++ newirq = i;
++ }
++ }
++ DBG(" -> newirq=%d", newirq);
++
++ /* Check if it is hardcoded */
++ if ((pirq & 0xf0) == 0xf0) {
++ irq = pirq & 0xf;
++ DBG(" -> hardcoded IRQ %d\n", irq);
++ msg = "Hardcoded";
++ } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
++ ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
++ DBG(" -> got IRQ %d\n", irq);
++ msg = "Found";
++ eisa_set_level_irq(irq);
++ } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
++ DBG(" -> assigning IRQ %d", newirq);
++ if (r->set(pirq_router_dev, dev, pirq, newirq)) {
++ eisa_set_level_irq(newirq);
++ DBG(" ... OK\n");
++ msg = "Assigned";
++ irq = newirq;
++ }
++ }
++
++ if (!irq) {
++ DBG(" ... failed\n");
++ if (newirq && mask == (1 << newirq)) {
++ msg = "Guessed";
++ irq = newirq;
++ } else
++ return 0;
++ }
++ printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, pci_name(dev));
++
++ /* Update IRQ for all devices with the same pirq value */
++ while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
++ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
++ if (!pin)
++ continue;
++ pin--;
++ info = pirq_get_info(dev2);
++ if (!info)
++ continue;
++ if (info->irq[pin].link == pirq) {
++ /* We refuse to override the dev->irq information. Give a warning! */
++ if ( dev2->irq && dev2->irq != irq && \
++ (!(pci_probe & PCI_USE_PIRQ_MASK) || \
++ ((1 << dev2->irq) & mask)) ) {
++#ifndef CONFIG_PCI_MSI
++ printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
++ pci_name(dev2), dev2->irq, irq);
++#endif
++ continue;
++ }
++ dev2->irq = irq;
++ pirq_penalty[irq]++;
++ if (dev != dev2)
++ printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2));
++ }
++ }
++ return 1;
++}
++
++static void __init pcibios_fixup_irqs(void)
++{
++ struct pci_dev *dev = NULL;
++ u8 pin;
++
++ DBG(KERN_DEBUG "PCI: IRQ fixup\n");
++ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
++ /*
++ * If the BIOS has set an out of range IRQ number, just ignore it.
++ * Also keep track of which IRQ's are already in use.
++ */
++ if (dev->irq >= 16) {
++ DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq);
++ dev->irq = 0;
++ }
++ /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
++ if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
++ pirq_penalty[dev->irq] = 0;
++ pirq_penalty[dev->irq]++;
++ }
++
++ dev = NULL;
++ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
++ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
++#ifdef CONFIG_X86_IO_APIC
++ /*
++ * Recalculate IRQ numbers if we use the I/O APIC.
++ */
++ if (io_apic_assign_pci_irqs)
++ {
++ int irq;
++
++ if (pin) {
++ pin--; /* interrupt pins are numbered starting from 1 */
++ irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
++ /*
++ * Busses behind bridges are typically not listed in the MP-table.
++ * In this case we have to look up the IRQ based on the parent bus,
++ * parent slot, and pin number. The SMP code detects such bridged
++ * busses itself so we should get into this branch reliably.
++ */
++ if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
++ struct pci_dev * bridge = dev->bus->self;
++
++ pin = (pin + PCI_SLOT(dev->devfn)) % 4;
++ irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
++ PCI_SLOT(bridge->devfn), pin);
++ if (irq >= 0)
++ printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n",
++ pci_name(bridge), 'A' + pin, irq);
++ }
++ if (irq >= 0) {
++ if (use_pci_vector() &&
++ !platform_legacy_irq(irq))
++ irq = IO_APIC_VECTOR(irq);
++
++ printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
++ pci_name(dev), 'A' + pin, irq);
++ dev->irq = irq;
++ }
++ }
++ }
++#endif
++ /*
++ * Still no IRQ? Try to lookup one...
++ */
++ if (pin && !dev->irq)
++ pcibios_lookup_irq(dev, 0);
++ }
++}
++
++/*
++ * Work around broken HP Pavilion Notebooks which assign USB to
++ * IRQ 9 even though it is actually wired to IRQ 11
++ */
++static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d)
++{
++ if (!broken_hp_bios_irq9) {
++ broken_hp_bios_irq9 = 1;
++ printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
++ }
++ return 0;
++}
++
++/*
++ * Work around broken Acer TravelMate 360 Notebooks which assign
++ * Cardbus to IRQ 11 even though it is actually wired to IRQ 10
++ */
++static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d)
++{
++ if (!acer_tm360_irqrouting) {
++ acer_tm360_irqrouting = 1;
++ printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
++ }
++ return 0;
++}
++
++static struct dmi_system_id __initdata pciirq_dmi_table[] = {
++ {
++ .callback = fix_broken_hp_bios_irq9,
++ .ident = "HP Pavilion N5400 Series Laptop",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
++ DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
++ DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
++ DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
++ },
++ },
++ {
++ .callback = fix_acer_tm360_irqrouting,
++ .ident = "Acer TravelMate 36x Laptop",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
++ },
++ },
++ { }
++};
++
++static int __init pcibios_irq_init(void)
++{
++ DBG(KERN_DEBUG "PCI: IRQ init\n");
++
++ if (pcibios_enable_irq || raw_pci_ops == NULL)
++ return 0;
++
++ dmi_check_system(pciirq_dmi_table);
++
++ pirq_table = pirq_find_routing_table();
++
++#ifdef CONFIG_PCI_BIOS
++ if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
++ pirq_table = pcibios_get_irq_routing_table();
++#endif
++ if (pirq_table) {
++ pirq_peer_trick();
++ pirq_find_router(&pirq_router);
++ if (pirq_table->exclusive_irqs) {
++ int i;
++ for (i=0; i<16; i++)
++ if (!(pirq_table->exclusive_irqs & (1 << i)))
++ pirq_penalty[i] += 100;
++ }
++ /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
++ if (io_apic_assign_pci_irqs)
++ pirq_table = NULL;
++ }
++
++ pcibios_enable_irq = pirq_enable_irq;
++
++ pcibios_fixup_irqs();
++ return 0;
++}
++
++subsys_initcall(pcibios_irq_init);
++
++
++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) {
++ if (active)
++ pirq_penalty[irq] += 1000;
++ else
++ pirq_penalty[irq] += 100;
++ }
++}
++
++void pcibios_penalize_isa_irq(int irq, int active)
++{
++#ifdef CONFIG_ACPI
++ if (!acpi_noirq)
++ acpi_penalize_isa_irq(irq, active);
++ else
++#endif
++ pirq_penalize_isa_irq(irq, active);
++}
++
++static int pirq_enable_irq(struct pci_dev *dev)
++{
++ u8 pin;
++ struct pci_dev *temp_dev;
++
++ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
++ if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
++ char *msg = "";
++
++ pin--; /* interrupt pins are numbered starting from 1 */
++
++ if (io_apic_assign_pci_irqs) {
++ int irq;
++
++ irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
++ /*
++ * Busses behind bridges are typically not listed in the MP-table.
++ * In this case we have to look up the IRQ based on the parent bus,
++ * parent slot, and pin number. The SMP code detects such bridged
++ * busses itself so we should get into this branch reliably.
++ */
++ temp_dev = dev;
++ while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
++ struct pci_dev * bridge = dev->bus->self;
++
++ pin = (pin + PCI_SLOT(dev->devfn)) % 4;
++ irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
++ PCI_SLOT(bridge->devfn), pin);
++ if (irq >= 0)
++ printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n",
++ pci_name(bridge), 'A' + pin, irq);
++ dev = bridge;
++ }
++ dev = temp_dev;
++ if (irq >= 0) {
++#ifdef CONFIG_PCI_MSI
++ if (!platform_legacy_irq(irq))
++ irq = IO_APIC_VECTOR(irq);
++#endif
++ printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
++ pci_name(dev), 'A' + pin, irq);
++ dev->irq = irq;
++ return 0;
++ } else
++ msg = " Probably buggy MP table.";
++ } else if (pci_probe & PCI_BIOS_IRQ_SCAN)
++ msg = "";
++ else
++ msg = " Please try using pci=biosirq.";
++
++ /* With IDE legacy devices the IRQ lookup failure is not a problem.. */
++ if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
++ return 0;
++
++ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
++ 'A' + pin, pci_name(dev), msg);
++ }
++ return 0;
++}
++
++int pci_vector_resources(int last, int nr_released)
++{
++ int count = nr_released;
++
++ int next = last;
++ int offset = (last % 8);
++
++ while (next < FIRST_SYSTEM_VECTOR) {
++ next += 8;
++#ifdef CONFIG_X86_64
++ if (next == IA32_SYSCALL_VECTOR)
++ continue;
++#else
++ if (next == SYSCALL_VECTOR)
++ continue;
++#endif
++ count++;
++ if (next >= FIRST_SYSTEM_VECTOR) {
++ if (offset%8) {
++ next = FIRST_DEVICE_VECTOR + offset;
++ offset++;
++ continue;
++ }
++ count--;
++ }
++ }
++
++ return count;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/pci/Makefile linux-2.6.18-xen/arch/i386/pci/Makefile
+--- linux-2.6.18.1/arch/i386/pci/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/pci/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -4,6 +4,10 @@
+ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o
+ obj-$(CONFIG_PCI_DIRECT) += direct.o
+
++# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
++# take over if direct access to the PCI bus is unavailable
++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o
++
+ pci-y := fixup.o
+ pci-$(CONFIG_ACPI) += acpi.o
+ pci-y += legacy.o irq.o
+@@ -12,3 +16,8 @@
+ pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o
+
+ obj-y += $(pci-y) common.o
++
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++obj-y := $(call cherrypickxen, $(obj-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/pci/pcifront.c linux-2.6.18-xen/arch/i386/pci/pcifront.c
+--- linux-2.6.18.1/arch/i386/pci/pcifront.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/i386/pci/pcifront.c 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,55 @@
++/*
++ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
++ * to support the Xen PCI Frontend's operation
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <asm/acpi.h>
++#include "pci.h"
++
++static int pcifront_enable_irq(struct pci_dev *dev)
++{
++ u8 irq;
++ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
++ dev->irq = irq;
++
++ return 0;
++}
++
++extern u8 pci_cache_line_size;
++
++static int __init pcifront_x86_stub_init(void)
++{
++ struct cpuinfo_x86 *c = &boot_cpu_data;
++
++ /* Only install our method if we haven't found real hardware already */
++ if (raw_pci_ops)
++ return 0;
++
++ printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
++
++ /* Copied from arch/i386/pci/common.c */
++ pci_cache_line_size = 32 >> 2;
++ if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
++ pci_cache_line_size = 64 >> 2; /* K7 & K8 */
++ else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
++ pci_cache_line_size = 128 >> 2; /* P4 */
++
++ /* On x86, we need to disable the normal IRQ routing table and
++ * just ask the backend
++ */
++ pcibios_enable_irq = pcifront_enable_irq;
++ pcibios_disable_irq = NULL;
++
++#ifdef CONFIG_ACPI
++ /* Keep ACPI out of the picture */
++ acpi_noirq = 1;
++#endif
++
++ return 0;
++}
++
++arch_initcall(pcifront_x86_stub_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/i386/power/Makefile linux-2.6.18-xen/arch/i386/power/Makefile
+--- linux-2.6.18.1/arch/i386/power/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/i386/power/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -1,2 +1,4 @@
+-obj-$(CONFIG_PM) += cpu.o
++obj-$(CONFIG_PM_LEGACY) += cpu.o
++obj-$(CONFIG_SOFTWARE_SUSPEND) += cpu.o
++obj-$(CONFIG_ACPI_SLEEP) += cpu.o
+ obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/dig/setup.c linux-2.6.18-xen/arch/ia64/dig/setup.c
+--- linux-2.6.18.1/arch/ia64/dig/setup.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/dig/setup.c 2006-09-21 01:33:31.000000000 +0200
+@@ -24,6 +24,8 @@
+ #include <asm/machvec.h>
+ #include <asm/system.h>
+
++#include <xen/xencons.h>
++
+ void __init
+ dig_setup (char **cmdline_p)
+ {
+@@ -67,4 +69,19 @@
+ screen_info.orig_video_mode = 3; /* XXX fake */
+ screen_info.orig_video_isVGA = 1; /* XXX fake */
+ screen_info.orig_video_ega_bx = 3; /* XXX fake */
++#ifdef CONFIG_XEN
++ if (!is_running_on_xen() || !is_initial_xendomain())
++ return;
++
++ if (xen_start_info->console.dom0.info_size >=
++ sizeof(struct dom0_vga_console_info)) {
++ const struct dom0_vga_console_info *info =
++ (struct dom0_vga_console_info *)(
++ (char *)xen_start_info +
++ xen_start_info->console.dom0.info_off);
++ dom0_init_screen_info(info);
++ }
++ xen_start_info->console.domU.mfn = 0;
++ xen_start_info->console.domU.evtchn = 0;
++#endif
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/hp/sim/Makefile linux-2.6.18-xen/arch/ia64/hp/sim/Makefile
+--- linux-2.6.18.1/arch/ia64/hp/sim/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/hp/sim/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -14,3 +14,5 @@
+ obj-$(CONFIG_HP_SIMSERIAL) += simserial.o
+ obj-$(CONFIG_HP_SIMSERIAL_CONSOLE) += hpsim_console.o
+ obj-$(CONFIG_HP_SIMSCSI) += simscsi.o
++obj-$(CONFIG_XEN) += simserial.o
++obj-$(CONFIG_XEN) += hpsim_console.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/Kconfig linux-2.6.18-xen/arch/ia64/Kconfig
+--- linux-2.6.18.1/arch/ia64/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/Kconfig 2006-10-17 15:01:58.000000000 +0200
+@@ -58,6 +58,34 @@
+ bool
+ default y
+
++config XEN
++ bool "Xen hypervisor support"
++ default y
++ help
++ Enable Xen hypervisor support. Resulting kernel runs
++ both as a guest OS on Xen and natively on hardware.
++
++config XEN_IA64_VDSO_PARAVIRT
++ bool
++ depends on XEN && !ITANIUM
++ default y
++ help
++ vDSO paravirtualization
++
++config XEN_IA64_EXPOSE_P2M
++ bool "Xen/IA64 exposure p2m table"
++ depends on XEN
++ default y
++ help
++ expose p2m from xen
++
++config XEN_IA64_EXPOSE_P2M_USE_DTR
++ bool "Xen/IA64 map p2m table with dtr"
++ depends on XEN_IA64_EXPOSE_P2M
++ default y
++ help
++ use dtr to map the exposed p2m table
++
+ config SCHED_NO_NO_OMIT_FRAME_POINTER
+ bool
+ default y
+@@ -465,6 +493,21 @@
+ bool
+ default PCI
+
++config XEN_PCIDEV_FRONTEND
++ bool "Xen PCI Frontend"
++ depends on PCI && XEN
++ default y
++ help
++ The PCI device frontend driver allows the kernel to import arbitrary
++ PCI devices from a PCI backend to support PCI driver domains.
++
++config XEN_PCIDEV_FE_DEBUG
++ bool "Xen PCI Frontend Debugging"
++ depends on XEN_PCIDEV_FRONTEND
++ default n
++ help
++ Enables some debug statements within the PCI Frontend.
++
+ source "drivers/pci/pcie/Kconfig"
+
+ source "drivers/pci/Kconfig"
+@@ -528,3 +571,34 @@
+ source "security/Kconfig"
+
+ source "crypto/Kconfig"
++
++#
++# override default values of drivers/xen/Kconfig
++#
++if XEN
++config XEN_UTIL
++ default n
++
++config HAVE_ARCH_ALLOC_SKB
++ default y
++
++config HAVE_ARCH_DEV_ALLOC_SKB
++ default y
++
++config XEN_BALLOON
++ default y
++
++config XEN_SKBUFF
++ default y
++
++config XEN_DEVMEM
++ default n
++
++config XEN_REBOOT
++ default y
++
++config XEN_SMPBOOT
++ default n
++endif
++
++source "drivers/xen/Kconfig"
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/asm-offsets.c linux-2.6.18-xen/arch/ia64/kernel/asm-offsets.c
+--- linux-2.6.18.1/arch/ia64/kernel/asm-offsets.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/asm-offsets.c 2006-09-04 16:31:00.000000000 +0200
+@@ -268,4 +268,29 @@
+ DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64);
+ DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32);
+ DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec));
++
++#ifdef CONFIG_XEN
++ BLANK();
++
++#define DEFINE_MAPPED_REG_OFS(sym, field) \
++ DEFINE(sym, (XMAPPEDREGS_OFS + offsetof(mapped_regs_t, field)))
++
++ DEFINE_MAPPED_REG_OFS(XSI_PSR_I_ADDR_OFS, interrupt_mask_addr);
++ DEFINE_MAPPED_REG_OFS(XSI_IPSR_OFS, ipsr);
++ DEFINE_MAPPED_REG_OFS(XSI_IIP_OFS, iip);
++ DEFINE_MAPPED_REG_OFS(XSI_IFS_OFS, ifs);
++ DEFINE_MAPPED_REG_OFS(XSI_PRECOVER_IFS_OFS, precover_ifs);
++ DEFINE_MAPPED_REG_OFS(XSI_ISR_OFS, isr);
++ DEFINE_MAPPED_REG_OFS(XSI_IFA_OFS, ifa);
++ DEFINE_MAPPED_REG_OFS(XSI_IIPA_OFS, iipa);
++ DEFINE_MAPPED_REG_OFS(XSI_IIM_OFS, iim);
++ DEFINE_MAPPED_REG_OFS(XSI_IHA_OFS, iha);
++ DEFINE_MAPPED_REG_OFS(XSI_ITIR_OFS, itir);
++ DEFINE_MAPPED_REG_OFS(XSI_PSR_IC_OFS, interrupt_collection_enabled);
++ DEFINE_MAPPED_REG_OFS(XSI_PEND_OFS, pending_interruption);
++ DEFINE_MAPPED_REG_OFS(XSI_INCOMPL_REGFR_OFS, incomplete_regframe);
++ DEFINE_MAPPED_REG_OFS(XSI_BANKNUM_OFS, banknum);
++ DEFINE_MAPPED_REG_OFS(XSI_BANK0_R16_OFS, bank0_regs[0]);
++ DEFINE_MAPPED_REG_OFS(XSI_BANK1_R16_OFS, bank1_regs[0]);
++#endif /* CONFIG_XEN */
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/entry.S linux-2.6.18-xen/arch/ia64/kernel/entry.S
+--- linux-2.6.18.1/arch/ia64/kernel/entry.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/entry.S 2006-09-21 01:33:31.000000000 +0200
+@@ -180,7 +180,7 @@
+ * called. The code starting at .map relies on this. The rest of the code
+ * doesn't care about the interrupt masking status.
+ */
+-GLOBAL_ENTRY(ia64_switch_to)
++GLOBAL_ENTRY(__ia64_switch_to)
+ .prologue
+ alloc r16=ar.pfs,1,0,0,0
+ DO_SAVE_SWITCH_STACK
+@@ -234,7 +234,7 @@
+ ;;
+ srlz.d
+ br.cond.sptk .done
+-END(ia64_switch_to)
++END(__ia64_switch_to)
+
+ /*
+ * Note that interrupts are enabled during save_switch_stack and load_switch_stack. This
+@@ -375,7 +375,7 @@
+ * - b7 holds address to return to
+ * - must not touch r8-r11
+ */
+-ENTRY(load_switch_stack)
++GLOBAL_ENTRY(load_switch_stack)
+ .prologue
+ .altrp b7
+
+@@ -510,7 +510,7 @@
+ * because some system calls (such as ia64_execve) directly
+ * manipulate ar.pfs.
+ */
+-GLOBAL_ENTRY(ia64_trace_syscall)
++GLOBAL_ENTRY(__ia64_trace_syscall)
+ PT_REGS_UNWIND_INFO(0)
+ /*
+ * We need to preserve the scratch registers f6-f11 in case the system
+@@ -582,7 +582,7 @@
+ (p6) mov r10=-1
+ (p6) mov r8=r9
+ br.cond.sptk .strace_save_retval
+-END(ia64_trace_syscall)
++END(__ia64_trace_syscall)
+
+ /*
+ * When traced and returning from sigreturn, we invoke syscall_trace but then
+@@ -635,8 +635,11 @@
+ adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8
+ mov r10=r0 // clear error indication in r10
+ (p7) br.cond.spnt handle_syscall_error // handle potential syscall failure
++ ;;
++ // don't fall through, ia64_leave_syscall may be #define'd
++ br.cond.sptk.few ia64_leave_syscall
++ ;;
+ END(ia64_ret_from_syscall)
+- // fall through
+ /*
+ * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't
+ * need to switch to bank 0 and doesn't restore the scratch registers.
+@@ -681,7 +684,7 @@
+ * ar.csd: cleared
+ * ar.ssd: cleared
+ */
+-ENTRY(ia64_leave_syscall)
++GLOBAL_ENTRY(__ia64_leave_syscall)
+ PT_REGS_UNWIND_INFO(0)
+ /*
+ * work.need_resched etc. mustn't get changed by this CPU before it returns to
+@@ -789,7 +792,7 @@
+ 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)
++END(__ia64_leave_syscall)
+
+ #ifdef CONFIG_IA32_SUPPORT
+ GLOBAL_ENTRY(ia64_ret_from_ia32_execve)
+@@ -801,10 +804,13 @@
+ st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit
+ .mem.offset 8,0
+ st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit
++ ;;
++ // don't fall through, ia64_leave_kernel may be #define'd
++ br.cond.sptk.few ia64_leave_kernel
++ ;;
+ END(ia64_ret_from_ia32_execve)
+- // fall through
+ #endif /* CONFIG_IA32_SUPPORT */
+-GLOBAL_ENTRY(ia64_leave_kernel)
++GLOBAL_ENTRY(__ia64_leave_kernel)
+ PT_REGS_UNWIND_INFO(0)
+ /*
+ * work.need_resched etc. mustn't get changed by this CPU before it returns to
+@@ -1135,7 +1141,7 @@
+ ld8 r10=[r3]
+ br.cond.sptk.many .work_processed_syscall // re-check
+
+-END(ia64_leave_kernel)
++END(__ia64_leave_kernel)
+
+ ENTRY(handle_syscall_error)
+ /*
+@@ -1175,7 +1181,7 @@
+ * be set up by the caller. We declare 8 input registers so the system call
+ * args get preserved, in case we need to restart a system call.
+ */
+-ENTRY(notify_resume_user)
++GLOBAL_ENTRY(notify_resume_user)
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+ alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
+ mov r9=ar.unat
+@@ -1263,7 +1269,7 @@
+ adds sp=16,sp
+ ;;
+ ld8 r9=[sp] // load new ar.unat
+- mov.sptk b7=r8,ia64_leave_kernel
++ mov.sptk b7=r8,__ia64_leave_kernel
+ ;;
+ mov ar.unat=r9
+ br.many b7
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/gate.lds.S linux-2.6.18-xen/arch/ia64/kernel/gate.lds.S
+--- linux-2.6.18.1/arch/ia64/kernel/gate.lds.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/gate.lds.S 2006-09-04 16:31:00.000000000 +0200
+@@ -43,6 +43,28 @@
+ __start_gate_brl_fsys_bubble_down_patchlist = .;
+ *(.data.patch.brl_fsys_bubble_down)
+ __end_gate_brl_fsys_bubble_down_patchlist = .;
++
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++ __start_gate_running_on_xen_patchlist = .;
++ *(.data.patch.running_on_xen)
++ __end_gate_running_on_xen_patchlist = .;
++
++ __start_gate_brl_xen_rsm_be_i_patchlist = .;
++ *(.data.patch.brl_xen_rsm_be_i)
++ __end_gate_brl_xen_rsm_be_i_patchlist = .;
++
++ __start_gate_brl_xen_get_psr_patchlist = .;
++ *(.data.patch.brl_xen_get_psr)
++ __end_gate_brl_xen_get_psr_patchlist = .;
++
++ __start_gate_brl_xen_ssm_i_0_patchlist = .;
++ *(.data.patch.brl_xen_ssm_i_0)
++ __end_gate_brl_xen_ssm_i_0_patchlist = .;
++
++ __start_gate_brl_xen_ssm_i_1_patchlist = .;
++ *(.data.patch.brl_xen_ssm_i_1)
++ __end_gate_brl_xen_ssm_i_1_patchlist = .;
++#endif
+ } :readable
+ .IA_64.unwind_info : { *(.IA_64.unwind_info*) }
+ .IA_64.unwind : { *(.IA_64.unwind*) } :readable :unwind
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/gate.S linux-2.6.18-xen/arch/ia64/kernel/gate.S
+--- linux-2.6.18.1/arch/ia64/kernel/gate.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/gate.S 2006-09-04 16:31:00.000000000 +0200
+@@ -6,13 +6,15 @@
+ * David Mosberger-Tang <davidm at hpl.hp.com>
+ */
+
+-
+ #include <asm/asmmacro.h>
+ #include <asm/errno.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/sigcontext.h>
+ #include <asm/system.h>
+ #include <asm/unistd.h>
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++# include <asm/privop.h>
++#endif
+
+ /*
+ * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation,
+@@ -32,6 +34,52 @@
+ [1:](pr)brl.cond.sptk 0; \
+ .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-.
+
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++ // The page in which hyperprivop lives must be pinned by ITR.
++ // However vDSO area isn't pinned. So issuing hyperprivop
++ // from vDSO page causes trouble that Kevin pointed out.
++ // After clearing vpsr.ic, the vcpu is pre-empted and the itlb
++ // is flushed. Then vcpu get cpu again, tlb miss fault occures.
++ // However it results in nested dtlb fault because vpsr.ic is off.
++ // To avoid such a situation, we jump into the kernel text area
++ // which is pinned, and then issue hyperprivop and return back
++ // to vDSO page.
++ // This is Dan Magenheimer's idea.
++
++ // Currently is_running_on_xen() is defined as running_on_xen.
++ // If is_running_on_xen() is a real function, we must update
++ // according to it.
++ .section ".data.patch.running_on_xen", "a"
++ .previous
++#define LOAD_RUNNING_ON_XEN(reg) \
++[1:] movl reg=0; \
++ .xdata4 ".data.patch.running_on_xen", 1b-.
++
++ .section ".data.patch.brl_xen_rsm_be_i", "a"
++ .previous
++#define BRL_COND_XEN_RSM_BE_I(pr) \
++[1:](pr)brl.cond.sptk 0; \
++ .xdata4 ".data.patch.brl_xen_rsm_be_i", 1b-.
++
++ .section ".data.patch.brl_xen_get_psr", "a"
++ .previous
++#define BRL_COND_XEN_GET_PSR(pr) \
++[1:](pr)brl.cond.sptk 0; \
++ .xdata4 ".data.patch.brl_xen_get_psr", 1b-.
++
++ .section ".data.patch.brl_xen_ssm_i_0", "a"
++ .previous
++#define BRL_COND_XEN_SSM_I_0(pr) \
++[1:](pr)brl.cond.sptk 0; \
++ .xdata4 ".data.patch.brl_xen_ssm_i_0", 1b-.
++
++ .section ".data.patch.brl_xen_ssm_i_1", "a"
++ .previous
++#define BRL_COND_XEN_SSM_I_1(pr) \
++[1:](pr)brl.cond.sptk 0; \
++ .xdata4 ".data.patch.brl_xen_ssm_i_1", 1b-.
++#endif
++
+ GLOBAL_ENTRY(__kernel_syscall_via_break)
+ .prologue
+ .altrp b6
+@@ -76,7 +124,39 @@
+ epc // B causes split-issue
+ }
+ ;;
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++ // r20 = 1
++ // r22 = &vcpu->evtchn_mask
++ // r23 = &vpsr.ic
++ // r24 = &vcpu->pending_interruption
++ // r25 = tmp
++ // r28 = &running_on_xen
++ // r30 = running_on_xen
++ // r31 = tmp
++ // p11 = tmp
++ // p12 = running_on_xen
++ // p13 = !running_on_xen
++ // p14 = tmp
++ // p15 = tmp
++#define isXen p12
++#define isRaw p13
++ LOAD_RUNNING_ON_XEN(r28)
++ movl r22=XSI_PSR_I_ADDR
++ movl r23=XSI_PSR_IC
++ movl r24=XSI_PSR_I_ADDR+(XSI_PEND_OFS-XSI_PSR_I_ADDR_OFS)
++ mov r20=1
++ ;;
++ ld4 r30=[r28]
++ ;;
++ cmp.ne isXen,isRaw=r0,r30
++ ;;
++(isRaw) rsm psr.be | psr.i
++ BRL_COND_XEN_RSM_BE_I(isXen)
++ .global .vdso_rsm_be_i_ret
++.vdso_rsm_be_i_ret:
++#else
+ rsm psr.be | psr.i // M2 (5 cyc to srlz.d)
++#endif
+ LOAD_FSYSCALL_TABLE(r14) // X
+ ;;
+ mov r16=IA64_KR(CURRENT) // M2 (12 cyc)
+@@ -84,7 +164,14 @@
+ mov r19=NR_syscalls-1 // A
+ ;;
+ lfetch [r18] // M0|1
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++(isRaw) mov r29=psr
++ BRL_COND_XEN_GET_PSR(isXen)
++ .global .vdso_get_psr_ret
++.vdso_get_psr_ret:
++#else
+ mov r29=psr // M2 (12 cyc)
++#endif
+ // If r17 is a NaT, p6 will be zero
+ cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)?
+ ;;
+@@ -98,9 +185,21 @@
+ ;;
+ nop.m 0
+ (p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!)
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++ ;;
++ // p14 = running_on_xen && p8
++ // p15 = !running_on_xen && p8
++(p8) cmp.ne.unc p14,p15=r0,r30
++ ;;
++(p15) ssm psr.i
++ BRL_COND_XEN_SSM_I_0(p14)
++ .global .vdso_ssm_i_0_ret
++.vdso_ssm_i_0_ret:
++#else
+ nop.i 0
+ ;;
+ (p8) ssm psr.i
++#endif
+ (p6) mov b7=r18 // I0
+ (p8) br.dptk.many b7 // B
+
+@@ -121,9 +220,21 @@
+ #else
+ BRL_COND_FSYS_BUBBLE_DOWN(p6)
+ #endif
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++(isRaw) ssm psr.i
++ BRL_COND_XEN_SSM_I_1(isXen)
++ .global .vdso_ssm_i_1_ret
++.vdso_ssm_i_1_ret:
++#else
+ ssm psr.i
++#endif
+ mov r10=-1
+ (p10) mov r8=EINVAL
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++ dv_serialize_data // shut up gas warning.
++ // we know xen_hyper_ssm_i_0 or xen_hyper_ssm_i_1
++ // doesn't change p9 and p10
++#endif
+ (p9) mov r8=ENOSYS
+ FSYS_RETURN
+ END(__kernel_syscall_via_epc)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/head.S linux-2.6.18-xen/arch/ia64/kernel/head.S
+--- linux-2.6.18.1/arch/ia64/kernel/head.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/head.S 2006-09-21 01:33:31.000000000 +0200
+@@ -367,6 +367,12 @@
+ ;;
+ (isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader
+
++#ifdef CONFIG_XEN
++ // Note: isBP is used by the subprogram.
++ br.call.sptk.many rp=early_xen_setup
++ ;;
++#endif
++
+ #ifdef CONFIG_SMP
+ (isAP) br.call.sptk.many rp=start_secondary
+ .ret0:
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/iosapic.c linux-2.6.18-xen/arch/ia64/kernel/iosapic.c
+--- linux-2.6.18.1/arch/ia64/kernel/iosapic.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/iosapic.c 2006-09-04 16:31:00.000000000 +0200
+@@ -159,6 +159,65 @@
+ static int iosapic_kmalloc_ok;
+ static LIST_HEAD(free_rte_list);
+
++#ifdef CONFIG_XEN
++#include <xen/interface/xen.h>
++#include <xen/interface/physdev.h>
++#include <asm/hypervisor.h>
++static inline unsigned int xen_iosapic_read(char __iomem *iosapic, unsigned int reg)
++{
++ struct physdev_apic apic_op;
++ int ret;
++
++ apic_op.apic_physbase = (unsigned long)iosapic -
++ __IA64_UNCACHED_OFFSET;
++ apic_op.reg = reg;
++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
++ if (ret)
++ return ret;
++ return apic_op.value;
++}
++
++static inline void xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
++{
++ struct physdev_apic apic_op;
++
++ apic_op.apic_physbase = (unsigned long)iosapic -
++ __IA64_UNCACHED_OFFSET;
++ apic_op.reg = reg;
++ apic_op.value = val;
++ HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
++}
++
++static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
++{
++ if (!is_running_on_xen()) {
++ writel(reg, iosapic + IOSAPIC_REG_SELECT);
++ return readl(iosapic + IOSAPIC_WINDOW);
++ } else
++ return xen_iosapic_read(iosapic, reg);
++}
++
++static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
++{
++ if (!is_running_on_xen()) {
++ writel(reg, iosapic + IOSAPIC_REG_SELECT);
++ writel(val, iosapic + IOSAPIC_WINDOW);
++ } else
++ xen_iosapic_write(iosapic, reg, val);
++}
++
++int xen_assign_irq_vector(int irq)
++{
++ struct physdev_irq irq_op;
++
++ irq_op.irq = irq;
++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op))
++ return -ENOSPC;
++
++ return irq_op.vector;
++}
++#endif /* XEN */
++
+ /*
+ * Find an IOSAPIC associated with a GSI
+ */
+@@ -653,6 +712,9 @@
+ iosapic_intr_info[vector].dmode = delivery;
+ iosapic_intr_info[vector].trigger = trigger;
+
++ if (is_running_on_xen())
++ return 0;
++
+ if (trigger == IOSAPIC_EDGE)
+ irq_type = &irq_type_iosapic_edge;
+ else
+@@ -1015,6 +1077,9 @@
+ }
+
+ pcat_compat = system_pcat_compat;
++ if (is_running_on_xen())
++ return;
++
+ if (pcat_compat) {
+ /*
+ * Disable the compatibility mode interrupts (8259 style),
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/irq_ia64.c linux-2.6.18-xen/arch/ia64/kernel/irq_ia64.c
+--- linux-2.6.18.1/arch/ia64/kernel/irq_ia64.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/irq_ia64.c 2006-09-04 16:31:00.000000000 +0200
+@@ -30,6 +30,9 @@
+ #include <linux/smp_lock.h>
+ #include <linux/threads.h>
+ #include <linux/bitops.h>
++#ifdef CONFIG_XEN
++#include <linux/cpu.h>
++#endif
+
+ #include <asm/delay.h>
+ #include <asm/intrinsics.h>
+@@ -69,6 +72,13 @@
+ assign_irq_vector (int irq)
+ {
+ int pos, vector;
++
++#ifdef CONFIG_XEN
++ if (is_running_on_xen()) {
++ extern int xen_assign_irq_vector(int);
++ return xen_assign_irq_vector(irq);
++ }
++#endif
+ again:
+ pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
+ vector = IA64_FIRST_DEVICE_VECTOR + pos;
+@@ -240,14 +250,215 @@
+ };
+ #endif
+
++#ifdef CONFIG_XEN
++#include <xen/evtchn.h>
++#include <xen/interface/callback.h>
++
++static DEFINE_PER_CPU(int, timer_irq) = -1;
++static DEFINE_PER_CPU(int, ipi_irq) = -1;
++static DEFINE_PER_CPU(int, resched_irq) = -1;
++static char timer_name[NR_CPUS][15];
++static char ipi_name[NR_CPUS][15];
++static char resched_name[NR_CPUS][15];
++
++struct saved_irq {
++ unsigned int irq;
++ struct irqaction *action;
++};
++/* 16 should be far optimistic value, since only several percpu irqs
++ * are registered early.
++ */
++#define MAX_LATE_IRQ 16
++static struct saved_irq saved_percpu_irqs[MAX_LATE_IRQ];
++static unsigned short late_irq_cnt = 0;
++static unsigned short saved_irq_cnt = 0;
++static int xen_slab_ready = 0;
++
++#ifdef CONFIG_SMP
++/* Dummy stub. Though we may check RESCHEDULE_VECTOR before __do_IRQ,
++ * it ends up to issue several memory accesses upon percpu data and
++ * thus adds unnecessary traffic to other paths.
++ */
++static irqreturn_t
++handle_reschedule(int irq, void *dev_id, struct pt_regs *regs)
++{
++
++ return IRQ_HANDLED;
++}
++
++static struct irqaction resched_irqaction = {
++ .handler = handle_reschedule,
++ .flags = SA_INTERRUPT,
++ .name = "RESCHED"
++};
++#endif
++
++/*
++ * This is xen version percpu irq registration, which needs bind
++ * to xen specific evtchn sub-system. One trick here is that xen
++ * evtchn binding interface depends on kmalloc because related
++ * port needs to be freed at device/cpu down. So we cache the
++ * registration on BSP before slab is ready and then deal them
++ * at later point. For rest instances happening after slab ready,
++ * we hook them to xen evtchn immediately.
++ *
++ * FIXME: MCA is not supported by far, and thus "nomca" boot param is
++ * required.
++ */
++static void
++xen_register_percpu_irq (unsigned int irq, struct irqaction *action, int save)
++{
++ unsigned int cpu = smp_processor_id();
++ int ret = 0;
++
++ if (xen_slab_ready) {
++ switch (irq) {
++ case IA64_TIMER_VECTOR:
++ sprintf(timer_name[cpu], "%s%d", action->name, cpu);
++ ret = bind_virq_to_irqhandler(VIRQ_ITC, cpu,
++ action->handler, action->flags,
++ timer_name[cpu], action->dev_id);
++ per_cpu(timer_irq,cpu) = ret;
++ printk(KERN_INFO "register VIRQ_ITC (%s) to xen irq (%d)\n", timer_name[cpu], ret);
++ break;
++ case IA64_IPI_RESCHEDULE:
++ sprintf(resched_name[cpu], "%s%d", action->name, cpu);
++ ret = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, cpu,
++ action->handler, action->flags,
++ resched_name[cpu], action->dev_id);
++ per_cpu(resched_irq,cpu) = ret;
++ printk(KERN_INFO "register RESCHEDULE_VECTOR (%s) to xen irq (%d)\n", resched_name[cpu], ret);
++ break;
++ case IA64_IPI_VECTOR:
++ sprintf(ipi_name[cpu], "%s%d", action->name, cpu);
++ ret = bind_ipi_to_irqhandler(IPI_VECTOR, cpu,
++ action->handler, action->flags,
++ ipi_name[cpu], action->dev_id);
++ per_cpu(ipi_irq,cpu) = ret;
++ printk(KERN_INFO "register IPI_VECTOR (%s) to xen irq (%d)\n", ipi_name[cpu], ret);
++ break;
++ case IA64_SPURIOUS_INT_VECTOR:
++ break;
++ default:
++ printk(KERN_WARNING "Percpu irq %d is unsupported by xen!\n", irq);
++ break;
++ }
++ BUG_ON(ret < 0);
++ }
++
++ /* For BSP, we cache registered percpu irqs, and then re-walk
++ * them when initializing APs
++ */
++ if (!cpu && save) {
++ BUG_ON(saved_irq_cnt == MAX_LATE_IRQ);
++ saved_percpu_irqs[saved_irq_cnt].irq = irq;
++ saved_percpu_irqs[saved_irq_cnt].action = action;
++ saved_irq_cnt++;
++ if (!xen_slab_ready)
++ late_irq_cnt++;
++ }
++}
++
++static void
++xen_bind_early_percpu_irq (void)
++{
++ int i;
++
++ xen_slab_ready = 1;
++ /* There's no race when accessing this cached array, since only
++ * BSP will face with such step shortly
++ */
++ for (i = 0; i < late_irq_cnt; i++)
++ xen_register_percpu_irq(saved_percpu_irqs[i].irq,
++ saved_percpu_irqs[i].action, 0);
++}
++
++/* FIXME: There's no obvious point to check whether slab is ready. So
++ * a hack is used here by utilizing a late time hook.
++ */
++extern void (*late_time_init)(void);
++extern char xen_event_callback;
++extern void xen_init_IRQ(void);
++
++#ifdef CONFIG_HOTPLUG_CPU
++static int __devinit
++unbind_evtchn_callback(struct notifier_block *nfb,
++ unsigned long action, void *hcpu)
++{
++ unsigned int cpu = (unsigned long)hcpu;
++
++ if (action == CPU_DEAD) {
++ /* Unregister evtchn. */
++ if (per_cpu(ipi_irq,cpu) >= 0) {
++ unbind_from_irqhandler (per_cpu(ipi_irq, cpu), NULL);
++ per_cpu(ipi_irq, cpu) = -1;
++ }
++ if (per_cpu(resched_irq,cpu) >= 0) {
++ unbind_from_irqhandler (per_cpu(resched_irq, cpu),
++ NULL);
++ per_cpu(resched_irq, cpu) = -1;
++ }
++ if (per_cpu(timer_irq,cpu) >= 0) {
++ unbind_from_irqhandler (per_cpu(timer_irq, cpu), NULL);
++ per_cpu(timer_irq, cpu) = -1;
++ }
++ }
++ return NOTIFY_OK;
++}
++
++static struct notifier_block unbind_evtchn_notifier = {
++ .notifier_call = unbind_evtchn_callback,
++ .priority = 0
++};
++#endif
++
++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
++void xen_smp_intr_init(void)
++{
++#ifdef CONFIG_SMP
++ unsigned int cpu = smp_processor_id();
++ unsigned int i = 0;
++ struct callback_register event = {
++ .type = CALLBACKTYPE_event,
++ .address = (unsigned long)&xen_event_callback,
++ };
++
++ if (cpu == 0) {
++ /* Initialization was already done for boot cpu. */
++#ifdef CONFIG_HOTPLUG_CPU
++ /* Register the notifier only once. */
++ register_cpu_notifier(&unbind_evtchn_notifier);
++#endif
++ return;
++ }
++
++ /* This should be piggyback when setup vcpu guest context */
++ BUG_ON(HYPERVISOR_callback_op(CALLBACKOP_register, &event));
++
++ for (i = 0; i < saved_irq_cnt; i++)
++ xen_register_percpu_irq(saved_percpu_irqs[i].irq,
++ saved_percpu_irqs[i].action, 0);
++#endif /* CONFIG_SMP */
++}
++#endif /* CONFIG_XEN */
++
+ void
+ register_percpu_irq (ia64_vector vec, struct irqaction *action)
+ {
+ irq_desc_t *desc;
+ unsigned int irq;
+
++#ifdef CONFIG_XEN
++ if (is_running_on_xen())
++ return xen_register_percpu_irq(vec, action, 1);
++#endif
++
+ for (irq = 0; irq < NR_IRQS; ++irq)
+ if (irq_to_vector(irq) == vec) {
++#ifdef CONFIG_XEN
++ if (is_running_on_xen())
++ return xen_register_percpu_irq(vec, action, 1);
++#endif
+ desc = irq_desc + irq;
+ desc->status |= IRQ_PER_CPU;
+ desc->chip = &irq_type_ia64_lsapic;
+@@ -259,6 +470,21 @@
+ void __init
+ init_IRQ (void)
+ {
++#ifdef CONFIG_XEN
++ /* Maybe put into platform_irq_init later */
++ if (is_running_on_xen()) {
++ struct callback_register event = {
++ .type = CALLBACKTYPE_event,
++ .address = (unsigned long)&xen_event_callback,
++ };
++ xen_init_IRQ();
++ BUG_ON(HYPERVISOR_callback_op(CALLBACKOP_register, &event));
++ late_time_init = xen_bind_early_percpu_irq;
++#ifdef CONFIG_SMP
++ register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction);
++#endif /* CONFIG_SMP */
++ }
++#endif /* CONFIG_XEN */
+ register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
+ #ifdef CONFIG_SMP
+ register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
+@@ -276,6 +502,39 @@
+ unsigned long ipi_data;
+ unsigned long phys_cpu_id;
+
++#ifdef CONFIG_XEN
++ if (is_running_on_xen()) {
++ int irq = -1;
++
++#ifdef CONFIG_SMP
++ /* TODO: we need to call vcpu_up here */
++ if (unlikely(vector == ap_wakeup_vector)) {
++ extern void xen_send_ipi (int cpu, int vec);
++ xen_send_ipi (cpu, vector);
++ //vcpu_prepare_and_up(cpu);
++ return;
++ }
++#endif
++
++ switch(vector) {
++ case IA64_IPI_VECTOR:
++ irq = per_cpu(ipi_to_irq, cpu)[IPI_VECTOR];
++ break;
++ case IA64_IPI_RESCHEDULE:
++ irq = per_cpu(ipi_to_irq, cpu)[RESCHEDULE_VECTOR];
++ break;
++ default:
++ printk(KERN_WARNING"Unsupported IPI type 0x%x\n", vector);
++ irq = 0;
++ break;
++ }
++
++ BUG_ON(irq < 0);
++ notify_remote_via_irq(irq);
++ return;
++ }
++#endif /* CONFIG_XEN */
++
+ #ifdef CONFIG_SMP
+ phys_cpu_id = cpu_physical_id(cpu);
+ #else
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/pal.S linux-2.6.18-xen/arch/ia64/kernel/pal.S
+--- linux-2.6.18.1/arch/ia64/kernel/pal.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/pal.S 2006-09-04 16:31:00.000000000 +0200
+@@ -16,6 +16,7 @@
+ #include <asm/processor.h>
+
+ .data
++ .globl pal_entry_point
+ pal_entry_point:
+ data8 ia64_pal_default_handler
+ .text
+@@ -53,7 +54,7 @@
+ * in4 1 ==> clear psr.ic, 0 ==> don't clear psr.ic
+ *
+ */
+-GLOBAL_ENTRY(ia64_pal_call_static)
++GLOBAL_ENTRY(__ia64_pal_call_static)
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
+ alloc loc1 = ar.pfs,5,5,0,0
+ movl loc2 = pal_entry_point
+@@ -90,7 +91,7 @@
+ ;;
+ srlz.d // seralize restoration of psr.l
+ br.ret.sptk.many b0
+-END(ia64_pal_call_static)
++END(__ia64_pal_call_static)
+
+ /*
+ * Make a PAL call using the stacked registers calling convention.
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/patch.c linux-2.6.18-xen/arch/ia64/kernel/patch.c
+--- linux-2.6.18.1/arch/ia64/kernel/patch.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/patch.c 2006-09-04 16:31:00.000000000 +0200
+@@ -184,6 +184,73 @@
+ ia64_srlz_i();
+ }
+
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++extern char __start_gate_running_on_xen_patchlist[];
++extern char __end_gate_running_on_xen_patchlist[];
++
++void __init
++patch_running_on_xen(unsigned long start, unsigned long end)
++{
++ extern int running_on_xen;
++ s32 *offp = (s32 *)start;
++ u64 ip;
++
++ while (offp < (s32 *)end) {
++ ip = (u64)ia64_imva((char *)offp + *offp);
++ ia64_patch_imm64(ip, (u64)&running_on_xen);
++ ia64_fc((void *)ip);
++ ++offp;
++ }
++ ia64_sync_i();
++ ia64_srlz_i();
++}
++
++static void __init
++patch_brl_symaddr(unsigned long start, unsigned long end,
++ unsigned long symaddr)
++{
++ s32 *offp = (s32 *)start;
++ u64 ip;
++
++ while (offp < (s32 *)end) {
++ ip = (u64)offp + *offp;
++ ia64_patch_imm60((u64)ia64_imva((void *)ip),
++ (u64)(symaddr - (ip & -16)) / 16);
++ ia64_fc((void *)ip);
++ ++offp;
++ }
++ ia64_sync_i();
++ ia64_srlz_i();
++}
++
++#define EXTERN_PATCHLIST(name) \
++ extern char __start_gate_brl_##name##_patchlist[]; \
++ extern char __end_gate_brl_##name##_patchlist[]; \
++ extern char name[]
++
++#define PATCH_BRL_SYMADDR(name) \
++ patch_brl_symaddr((unsigned long)__start_gate_brl_##name##_patchlist, \
++ (unsigned long)__end_gate_brl_##name##_patchlist, \
++ (unsigned long)name)
++
++static void __init
++patch_brl_in_vdso(void)
++{
++ EXTERN_PATCHLIST(xen_rsm_be_i);
++ EXTERN_PATCHLIST(xen_get_psr);
++ EXTERN_PATCHLIST(xen_ssm_i_0);
++ EXTERN_PATCHLIST(xen_ssm_i_1);
++
++ PATCH_BRL_SYMADDR(xen_rsm_be_i);
++ PATCH_BRL_SYMADDR(xen_get_psr);
++ PATCH_BRL_SYMADDR(xen_ssm_i_0);
++ PATCH_BRL_SYMADDR(xen_ssm_i_1);
++}
++#else
++#define patch_running_on_xen(start, end) do { } while (0)
++#define patch_brl_in_vdso() do { } while (0)
++#endif
++
+ void __init
+ ia64_patch_gate (void)
+ {
+@@ -192,6 +259,10 @@
+
+ patch_fsyscall_table(START(fsyscall), END(fsyscall));
+ patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down));
++#ifdef CONFIG_XEN
++ patch_running_on_xen(START(running_on_xen), END(running_on_xen));
++ patch_brl_in_vdso();
++#endif
+ ia64_patch_vtop(START(vtop), END(vtop));
+ ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/kernel/setup.c linux-2.6.18-xen/arch/ia64/kernel/setup.c
+--- linux-2.6.18.1/arch/ia64/kernel/setup.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/kernel/setup.c 2006-10-17 15:01:58.000000000 +0200
+@@ -60,6 +60,10 @@
+ #include <asm/system.h>
+ #include <asm/unistd.h>
+ #include <asm/system.h>
++#ifdef CONFIG_XEN
++#include <asm/hypervisor.h>
++#endif
++#include <linux/dma-mapping.h>
+
+ #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
+ # error "struct cpuinfo_ia64 too big!"
+@@ -70,6 +74,24 @@
+ EXPORT_SYMBOL(__per_cpu_offset);
+ #endif
+
++#ifdef CONFIG_XEN
++unsigned long kernel_start_pa;
++
++static int
++xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
++{
++ HYPERVISOR_shutdown(SHUTDOWN_crash);
++ /* we're never actually going to get here... */
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block xen_panic_block = {
++ .notifier_call = xen_panic_event,
++ .next = NULL,
++ .priority = 0 /* try to go last */
++};
++#endif
++
+ extern void ia64_setup_printk_clock(void);
+
+ DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
+@@ -176,15 +198,33 @@
+ return 0;
+ }
+
++static int __init
++rsvd_region_cmp(struct rsvd_region *lhs, struct rsvd_region *rhs)
++{
++ if (lhs->start > rhs->start)
++ return 1;
++ if (lhs->start < rhs->start)
++ return -1;
++
++ if (lhs->end > rhs->end)
++ return 1;
++ if (lhs->end < rhs->end)
++ return -1;
++
++ return 0;
++}
++
+ static void __init
+ sort_regions (struct rsvd_region *rsvd_region, int max)
+ {
++ int num = max;
+ int j;
+
+ /* simple bubble sorting */
+ while (max--) {
+ for (j = 0; j < max; ++j) {
+- if (rsvd_region[j].start > rsvd_region[j+1].start) {
++ if (rsvd_region_cmp(&rsvd_region[j],
++ &rsvd_region[j + 1]) > 0) {
+ struct rsvd_region tmp;
+ tmp = rsvd_region[j];
+ rsvd_region[j] = rsvd_region[j + 1];
+@@ -192,6 +232,36 @@
+ }
+ }
+ }
++
++ for (j = 0; j < num - 1; j++) {
++ int k;
++ unsigned long start = rsvd_region[j].start;
++ unsigned long end = rsvd_region[j].end;
++ int collapsed;
++
++ for (k = j + 1; k < num; k++) {
++ BUG_ON(start > rsvd_region[k].start);
++ if (end < rsvd_region[k].start) {
++ k--;
++ break;
++ }
++ end = max(end, rsvd_region[k].end);
++ }
++ if (k == num)
++ k--;
++ rsvd_region[j].end = end;
++ collapsed = k - j;
++ num -= collapsed;
++ for (k = j + 1; k < num; k++) {
++ rsvd_region[k] = rsvd_region[k + collapsed];
++ }
++ }
++
++ num_rsvd_regions = num;
++ for (j = 0; j < num; j++) {
++ printk("rsvd_region[%d]: [0x%016lx, 0x%06lx)\n",
++ j, rsvd_region[j].start, rsvd_region[j].end);
++ }
+ }
+
+ /*
+@@ -242,6 +312,14 @@
+ rsvd_region[n].end = (unsigned long) ia64_imva(_end);
+ n++;
+
++#ifdef CONFIG_XEN
++ if (is_running_on_xen()) {
++ rsvd_region[n].start = (unsigned long)__va((HYPERVISOR_shared_info->arch.start_info_pfn << PAGE_SHIFT));
++ rsvd_region[n].end = rsvd_region[n].start + PAGE_SIZE;
++ n++;
++ }
++#endif
++
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (ia64_boot_param->initrd_start) {
+ rsvd_region[n].start = (unsigned long)__va(ia64_boot_param->initrd_start);
+@@ -333,6 +411,16 @@
+ {
+ int earlycons = 0;
+
++#ifdef CONFIG_XEN
++#ifndef CONFIG_IA64_HP_SIM
++ if (is_running_on_xen()) {
++ extern struct console hpsim_cons;
++ hpsim_cons.flags |= CON_BOOT;
++ register_console(&hpsim_cons);
++ earlycons++;
++ }
++#endif
++#endif
+ #ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
+ {
+ extern int sn_serial_console_early_setup(void);
+@@ -402,6 +490,15 @@
+ {
+ unw_init();
+
++#ifdef CONFIG_XEN
++ if (is_running_on_xen()) {
++ kernel_start_pa = KERNEL_START - ia64_tpa(KERNEL_START);
++ setup_xen_features();
++ /* Register a call for panic conditions. */
++ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
++ }
++#endif
++
+ ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
+
+ *cmdline_p = __va(ia64_boot_param->command_line);
+@@ -478,6 +575,23 @@
+ conswitchp = &vga_con;
+ # endif
+ }
++#ifdef CONFIG_XEN
++ if (is_running_on_xen()) {
++ shared_info_t *s = HYPERVISOR_shared_info;
++
++ xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT);
++
++ printk("Running on Xen! start_info_pfn=0x%lx nr_pages=%ld "
++ "flags=0x%x\n", s->arch.start_info_pfn,
++ xen_start_info->nr_pages, xen_start_info->flags);
++
++ if (!is_initial_xendomain()) {
++ extern int console_use_vt;
++ conswitchp = NULL;
++ console_use_vt = 0;
++ }
++ }
++#endif
+ #endif
+
+ /* enable IA-64 Machine Check Abort Handling unless disabled */
+@@ -486,6 +600,9 @@
+
+ platform_setup(cmdline_p);
+ paging_init();
++#ifdef CONFIG_XEN
++ contiguous_bitmap_init(max_pfn);
++#endif
+ }
+
+ /*
+@@ -870,6 +987,15 @@
+ /* 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();
++
++#ifdef CONFIG_XEN
++ /* Need to be moved into platform_cpu_init later */
++ if (is_running_on_xen()) {
++ extern void xen_smp_intr_init(void);
++ xen_smp_intr_init();
++ }
++#endif
++
+ pm_idle = default_idle;
+ }
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/Makefile linux-2.6.18-xen/arch/ia64/Makefile
+--- linux-2.6.18.1/arch/ia64/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/Makefile 2006-09-04 16:31:00.000000000 +0200
+@@ -45,6 +45,12 @@
+ endif
+
+ CFLAGS += $(cflags-y)
++
++cppflags-$(CONFIG_XEN) += \
++ -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION)
++
++CPPFLAGS += $(cppflags-y)
++
+ head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o
+
+ libs-y += arch/ia64/lib/
+@@ -55,9 +61,15 @@
+ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
+ core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
+ core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/
++core-$(CONFIG_XEN) += arch/ia64/xen/
+
+ drivers-$(CONFIG_PCI) += arch/ia64/pci/
++ifneq ($(CONFIG_XEN),y)
+ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
++endif
++ifneq ($(CONFIG_IA64_GENERIC),y)
++drivers-$(CONFIG_XEN) += arch/ia64/hp/sim/
++endif
+ drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
+ drivers-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
+ drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/
+@@ -87,8 +99,8 @@
+ boot: lib/lib.a vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $@
+
+-install: vmlinux.gz
+- sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
++install:
++ -yes | sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
+
+ define archhelp
+ echo '* compressed - Build compressed kernel image'
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/mm/ioremap.c linux-2.6.18-xen/arch/ia64/mm/ioremap.c
+--- linux-2.6.18.1/arch/ia64/mm/ioremap.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/ia64/mm/ioremap.c 2006-09-04 16:31:00.000000000 +0200
+@@ -16,6 +16,9 @@
+ static inline void __iomem *
+ __ioremap (unsigned long offset, unsigned long size)
+ {
++#ifdef CONFIG_XEN
++ offset = HYPERVISOR_ioremap(offset, size);
++#endif
+ return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset);
+ }
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/drivers/README linux-2.6.18-xen/arch/ia64/xen/drivers/README
+--- linux-2.6.18.1/arch/ia64/xen/drivers/README 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/drivers/README 2006-09-04 16:31:00.000000000 +0200
+@@ -0,0 +1,2 @@
++This is a temporary location for source/Makefiles that need to be
++patched/reworked in drivers/xen to work with xenlinux/ia64.
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/hypercall.S linux-2.6.18-xen/arch/ia64/xen/hypercall.S
+--- linux-2.6.18.1/arch/ia64/xen/hypercall.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/hypercall.S 2006-09-04 16:31:01.000000000 +0200
+@@ -0,0 +1,413 @@
++/*
++ * Support routines for Xen hypercalls
++ *
++ * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer at hp.com>
++ */
++
++#include <asm/processor.h>
++#include <asm/asmmacro.h>
++
++/* To clear vpsr.ic, vpsr.i needs to be cleared first */
++#define XEN_CLEAR_PSR_IC \
++ mov r14=1; \
++ movl r15=XSI_PSR_I_ADDR; \
++ movl r2=XSI_PSR_IC; \
++ ;; \
++ ld8 r15=[r15]; \
++ ld4 r3=[r2]; \
++ ;; \
++ ld1 r16=[r15]; \
++ ;; \
++ st1 [r15]=r14; \
++ st4 [r2]=r0; \
++ ;;
++
++/* First restore vpsr.ic, and then vpsr.i */
++#define XEN_RESTORE_PSR_IC \
++ st4 [r2]=r3; \
++ st1 [r15]=r16; \
++ ;;
++
++GLOBAL_ENTRY(xen_get_ivr)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov r8=cr.ivr;;
++(p7) br.ret.sptk.many rp
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_GET_IVR
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_get_ivr)
++
++GLOBAL_ENTRY(xen_get_tpr)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov r8=cr.tpr;;
++(p7) br.ret.sptk.many rp
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_GET_TPR
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_get_tpr)
++
++GLOBAL_ENTRY(xen_set_tpr)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov cr.tpr=r32;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_SET_TPR
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_set_tpr)
++
++GLOBAL_ENTRY(xen_eoi)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov cr.eoi=r0;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_EOI
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_eoi)
++
++GLOBAL_ENTRY(xen_thash)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) thash r8=r32;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_THASH
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_thash)
++
++GLOBAL_ENTRY(xen_set_itm)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov cr.itm=r32;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_SET_ITM
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_set_itm)
++
++GLOBAL_ENTRY(xen_ptcga)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) ptc.ga r32,r33;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ mov r9=r33
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_PTC_GA
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_ptcga)
++
++GLOBAL_ENTRY(xen_get_rr)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov r8=rr[r32];;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_GET_RR
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_get_rr)
++
++GLOBAL_ENTRY(xen_set_rr)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov rr[r32]=r33;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ mov r9=r33
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_SET_RR
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_set_rr)
++
++GLOBAL_ENTRY(xen_set_kr)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.ne p7,p0=r8,r0;;
++(p7) br.cond.spnt.few 1f;
++ ;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar0=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar1=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar2=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar3=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar4=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar5=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar6=r9
++(p7) br.ret.sptk.many rp;;
++ cmp.eq p7,p0=r8,r0
++ adds r8=-1,r8;;
++(p7) mov ar7=r9
++(p7) br.ret.sptk.many rp;;
++
++1: mov r8=r32
++ mov r9=r33
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_SET_KR
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++END(xen_set_kr)
++
++GLOBAL_ENTRY(xen_fc)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) fc r32;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_FC
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++END(xen_fc)
++
++GLOBAL_ENTRY(xen_get_cpuid)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov r8=cpuid[r32];;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_GET_CPUID
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++END(xen_get_cpuid)
++
++GLOBAL_ENTRY(xen_get_pmd)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov r8=pmd[r32];;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_GET_PMD
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++END(xen_get_pmd)
++
++#ifdef CONFIG_IA32_SUPPORT
++GLOBAL_ENTRY(xen_get_eflag)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov r8=ar24;;
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_GET_EFLAG
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++END(xen_get_eflag)
++
++// some bits aren't set if pl!=0, see SDM vol1 3.1.8
++GLOBAL_ENTRY(xen_set_eflag)
++ movl r8=running_on_xen;;
++ ld4 r8=[r8];;
++ cmp.eq p7,p0=r8,r0;;
++(p7) mov ar24=r32
++(p7) br.ret.sptk.many rp
++ ;;
++ mov r8=r32
++ ;;
++ XEN_CLEAR_PSR_IC
++ ;;
++ XEN_HYPER_SET_EFLAG
++ ;;
++ XEN_RESTORE_PSR_IC
++ ;;
++ br.ret.sptk.many rp
++END(xen_set_eflag)
++#endif
++
++GLOBAL_ENTRY(xen_send_ipi)
++ mov r14=r32
++ mov r15=r33
++ mov r2=0x400
++ break 0x1000
++ ;;
++ br.ret.sptk.many rp
++ ;;
++END(xen_send_ipi)
++
++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
++// Those are vdso specialized.
++// In fsys mode, call, ret can't be used.
++GLOBAL_ENTRY(xen_rsm_be_i)
++ ld8 r22=[r22]
++ ;;
++ st1 [r22]=r20
++ st4 [r23]=r0
++ XEN_HYPER_RSM_BE
++ st4 [r23]=r20
++ brl.cond.sptk .vdso_rsm_be_i_ret
++ ;;
++END(xen_rsm_be_i)
++
++GLOBAL_ENTRY(xen_get_psr)
++ mov r31=r8
++ mov r25=IA64_PSR_IC
++ st4 [r23]=r0
++ XEN_HYPER_GET_PSR
++ ;;
++ st4 [r23]=r20
++ or r29=r8,r25 // vpsr.ic was cleared for hyperprivop
++ mov r8=r31
++ brl.cond.sptk .vdso_get_psr_ret
++ ;;
++END(xen_get_psr)
++
++ // see xen_ssm_i() in privop.h
++ // r22 = &vcpu->evtchn_mask
++ // r23 = &vpsr.ic
++ // r24 = &vcpu->pending_interruption
++ // r25 = tmp
++ // r31 = tmp
++ // p11 = tmp
++ // p14 = tmp
++#define XEN_SET_PSR_I \
++ ld4 r31=[r22]; \
++ ld4 r25=[r24]; \
++ ;; \
++ st4 [r22]=r0; \
++ cmp.ne.unc p14,p0=r0,r31; \
++ ;; \
++(p14) cmp.ne.unc p11,p0=r0,r25; \
++ ;; \
++(p11) st4 [r22]=r20; \
++(p11) st4 [r23]=r0; \
++(p11) XEN_HYPER_SSM_I;
++
++GLOBAL_ENTRY(xen_ssm_i_0)
++ XEN_SET_PSR_I
++ brl.cond.sptk .vdso_ssm_i_0_ret
++ ;;
++END(xen_ssm_i_0)
++
++GLOBAL_ENTRY(xen_ssm_i_1)
++ XEN_SET_PSR_I
++ brl.cond.sptk .vdso_ssm_i_1_ret
++ ;;
++END(xen_ssm_i_1)
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/hypervisor.c linux-2.6.18-xen/arch/ia64/xen/hypervisor.c
+--- linux-2.6.18.1/arch/ia64/xen/hypervisor.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/hypervisor.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,1052 @@
++/******************************************************************************
++ * include/asm-ia64/shadow.h
++ *
++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
++ * VA Linux Systems Japan K.K.
++ *
++ * 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/spinlock.h>
++#include <linux/bootmem.h>
++#include <linux/module.h>
++#include <linux/vmalloc.h>
++#include <asm/page.h>
++#include <asm/hypervisor.h>
++#include <asm/hypercall.h>
++#include <xen/interface/memory.h>
++#include <xen/balloon.h>
++
++shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)XSI_BASE;
++EXPORT_SYMBOL(HYPERVISOR_shared_info);
++
++start_info_t *xen_start_info;
++EXPORT_SYMBOL(xen_start_info);
++
++int running_on_xen;
++EXPORT_SYMBOL(running_on_xen);
++
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
++static int p2m_expose_init(void);
++#else
++#define p2m_expose_init() (-ENOSYS)
++#endif
++
++//XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear()
++// move those to lib/contiguous_bitmap?
++//XXX discontigmem/sparsemem
++
++/*
++ * Bitmap is indexed by page number. If bit is set, the page is part of a
++ * xen_create_contiguous_region() area of memory.
++ */
++unsigned long *contiguous_bitmap;
++
++void
++contiguous_bitmap_init(unsigned long end_pfn)
++{
++ unsigned long size = (end_pfn + 2 * BITS_PER_LONG) >> 3;
++ contiguous_bitmap = alloc_bootmem_low_pages(size);
++ BUG_ON(!contiguous_bitmap);
++ memset(contiguous_bitmap, 0, size);
++}
++
++#if 0
++int
++contiguous_bitmap_test(void* p)
++{
++ return test_bit(__pa(p) >> PAGE_SHIFT, contiguous_bitmap);
++}
++#endif
++
++static void contiguous_bitmap_set(
++ unsigned long first_page, unsigned long nr_pages)
++{
++ unsigned long start_off, end_off, curr_idx, end_idx;
++
++ curr_idx = first_page / BITS_PER_LONG;
++ start_off = first_page & (BITS_PER_LONG-1);
++ end_idx = (first_page + nr_pages) / BITS_PER_LONG;
++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
++
++ if (curr_idx == end_idx) {
++ contiguous_bitmap[curr_idx] |=
++ ((1UL<<end_off)-1) & -(1UL<<start_off);
++ } else {
++ contiguous_bitmap[curr_idx] |= -(1UL<<start_off);
++ while ( ++curr_idx < end_idx )
++ contiguous_bitmap[curr_idx] = ~0UL;
++ contiguous_bitmap[curr_idx] |= (1UL<<end_off)-1;
++ }
++}
++
++static void contiguous_bitmap_clear(
++ unsigned long first_page, unsigned long nr_pages)
++{
++ unsigned long start_off, end_off, curr_idx, end_idx;
++
++ curr_idx = first_page / BITS_PER_LONG;
++ start_off = first_page & (BITS_PER_LONG-1);
++ end_idx = (first_page + nr_pages) / BITS_PER_LONG;
++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
++
++ if (curr_idx == end_idx) {
++ contiguous_bitmap[curr_idx] &=
++ -(1UL<<end_off) | ((1UL<<start_off)-1);
++ } else {
++ contiguous_bitmap[curr_idx] &= (1UL<<start_off)-1;
++ while ( ++curr_idx != end_idx )
++ contiguous_bitmap[curr_idx] = 0;
++ contiguous_bitmap[curr_idx] &= -(1UL<<end_off);
++ }
++}
++
++// __xen_create_contiguous_region(), __xen_destroy_contiguous_region()
++// are based on i386 xen_create_contiguous_region(),
++// xen_destroy_contiguous_region()
++
++/* Protected by balloon_lock. */
++#define MAX_CONTIG_ORDER 7
++static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER];
++
++/* Ensure multi-page extents are contiguous in machine memory. */
++int
++__xen_create_contiguous_region(unsigned long vstart,
++ unsigned int order, unsigned int address_bits)
++{
++ unsigned long error = 0;
++ unsigned long gphys = __pa(vstart);
++ unsigned long start_gpfn = gphys >> PAGE_SHIFT;
++ unsigned long num_gpfn = 1 << order;
++ unsigned long i;
++ unsigned long flags;
++
++ unsigned long *in_frames = discontig_frames, out_frame;
++ int success;
++ struct xen_memory_exchange exchange = {
++ .in = {
++ .nr_extents = num_gpfn,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ },
++ .out = {
++ .nr_extents = 1,
++ .extent_order = order,
++ .address_bits = address_bits,
++ .domid = DOMID_SELF
++ },
++ .nr_exchanged = 0
++ };
++
++ if (unlikely(order > MAX_CONTIG_ORDER))
++ return -ENOMEM;
++
++ set_xen_guest_handle(exchange.in.extent_start, in_frames);
++ set_xen_guest_handle(exchange.out.extent_start, &out_frame);
++
++ scrub_pages(vstart, num_gpfn);
++
++ balloon_lock(flags);
++
++ /* Get a new contiguous memory extent. */
++ for (i = 0; i < num_gpfn; i++) {
++ in_frames[i] = start_gpfn + i;
++ }
++ out_frame = start_gpfn;
++ error = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
++ success = (exchange.nr_exchanged == num_gpfn);
++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (error == 0)));
++ BUG_ON(success && (error != 0));
++ if (unlikely(error == -ENOSYS)) {
++ /* Compatibility when XENMEM_exchange is unsupported. */
++ error = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &exchange.in);
++ BUG_ON(error != num_gpfn);
++ error = HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &exchange.out);
++ if (error != 1) {
++ /* Couldn't get special memory: fall back to normal. */
++ for (i = 0; i < num_gpfn; i++) {
++ in_frames[i] = start_gpfn + i;
++ }
++ error = HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &exchange.in);
++ BUG_ON(error != num_gpfn);
++ success = 0;
++ } else
++ success = 1;
++ }
++ if (success)
++ contiguous_bitmap_set(start_gpfn, num_gpfn);
++#if 0
++ if (success) {
++ unsigned long mfn;
++ unsigned long mfn_prev = ~0UL;
++ for (i = 0; i < num_gpfn; i++) {
++ mfn = pfn_to_mfn_for_dma(start_gpfn + i);
++ if (mfn_prev != ~0UL && mfn != mfn_prev + 1) {
++ xprintk("\n");
++ xprintk("%s:%d order %d "
++ "start 0x%lx bus 0x%lx "
++ "machine 0x%lx\n",
++ __func__, __LINE__, order,
++ vstart, virt_to_bus((void*)vstart),
++ phys_to_machine_for_dma(gphys));
++ xprintk("mfn: ");
++ for (i = 0; i < num_gpfn; i++) {
++ mfn = pfn_to_mfn_for_dma(
++ start_gpfn + i);
++ xprintk("0x%lx ", mfn);
++ }
++ xprintk("\n");
++ break;
++ }
++ mfn_prev = mfn;
++ }
++ }
++#endif
++ balloon_unlock(flags);
++ return success? 0: -ENOMEM;
++}
++
++void
++__xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
++{
++ unsigned long flags;
++ unsigned long error = 0;
++ unsigned long start_gpfn = __pa(vstart) >> PAGE_SHIFT;
++ unsigned long num_gpfn = 1UL << order;
++ unsigned long i;
++
++ unsigned long *out_frames = discontig_frames, in_frame;
++ int success;
++ struct xen_memory_exchange exchange = {
++ .in = {
++ .nr_extents = 1,
++ .extent_order = order,
++ .domid = DOMID_SELF
++ },
++ .out = {
++ .nr_extents = num_gpfn,
++ .extent_order = 0,
++ .address_bits = 0,
++ .domid = DOMID_SELF
++ },
++ .nr_exchanged = 0
++ };
++
++
++ if (!test_bit(start_gpfn, contiguous_bitmap))
++ return;
++
++ if (unlikely(order > MAX_CONTIG_ORDER))
++ return;
++
++ set_xen_guest_handle(exchange.in.extent_start, &in_frame);
++ set_xen_guest_handle(exchange.out.extent_start, out_frames);
++
++ scrub_pages(vstart, num_gpfn);
++
++ balloon_lock(flags);
++
++ contiguous_bitmap_clear(start_gpfn, num_gpfn);
++
++ /* Do the exchange for non-contiguous MFNs. */
++ in_frame = start_gpfn;
++ for (i = 0; i < num_gpfn; i++) {
++ out_frames[i] = start_gpfn + i;
++ }
++ error = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
++ success = (exchange.nr_exchanged == 1);
++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (error == 0)));
++ BUG_ON(success && (error != 0));
++ if (unlikely(error == -ENOSYS)) {
++ /* Compatibility when XENMEM_exchange is unsupported. */
++ error = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &exchange.in);
++ BUG_ON(error != 1);
++
++ error = HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &exchange.out);
++ BUG_ON(error != num_gpfn);
++ }
++ balloon_unlock(flags);
++}
++
++
++///////////////////////////////////////////////////////////////////////////
++// grant table hack
++// cmd: GNTTABOP_xxx
++
++#include <linux/mm.h>
++#include <xen/interface/xen.h>
++#include <xen/gnttab.h>
++
++static void
++gnttab_map_grant_ref_pre(struct gnttab_map_grant_ref *uop)
++{
++ uint32_t flags;
++
++ flags = uop->flags;
++
++ if (flags & GNTMAP_host_map) {
++ if (flags & GNTMAP_application_map) {
++ xprintd("GNTMAP_application_map is not supported yet: flags 0x%x\n", flags);
++ BUG();
++ }
++ if (flags & GNTMAP_contains_pte) {
++ xprintd("GNTMAP_contains_pte is not supported yet flags 0x%x\n", flags);
++ BUG();
++ }
++ } else if (flags & GNTMAP_device_map) {
++ xprintd("GNTMAP_device_map is not supported yet 0x%x\n", flags);
++ BUG();//XXX not yet. actually this flag is not used.
++ } else {
++ BUG();
++ }
++}
++
++int
++HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
++{
++ if (cmd == GNTTABOP_map_grant_ref) {
++ unsigned int i;
++ for (i = 0; i < count; i++) {
++ gnttab_map_grant_ref_pre(
++ (struct gnttab_map_grant_ref*)uop + i);
++ }
++ }
++ return xencomm_mini_hypercall_grant_table_op(cmd, uop, count);
++}
++EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
++
++///////////////////////////////////////////////////////////////////////////
++// PageForeign(), SetPageForeign(), ClearPageForeign()
++
++struct address_space xen_ia64_foreign_dummy_mapping;
++EXPORT_SYMBOL(xen_ia64_foreign_dummy_mapping);
++
++///////////////////////////////////////////////////////////////////////////
++// foreign mapping
++#include <linux/efi.h>
++#include <asm/meminit.h> // for IA64_GRANULE_SIZE, GRANULEROUND{UP,DOWN}()
++
++static unsigned long privcmd_resource_min = 0;
++// Xen/ia64 currently can handle pseudo physical address bits up to
++// (PAGE_SHIFT * 3)
++static unsigned long privcmd_resource_max = GRANULEROUNDDOWN((1UL << (PAGE_SHIFT * 3)) - 1);
++static unsigned long privcmd_resource_align = IA64_GRANULE_SIZE;
++
++static unsigned long
++md_end_addr(const efi_memory_desc_t *md)
++{
++ return md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
++}
++
++#define XEN_IA64_PRIVCMD_LEAST_GAP_SIZE (1024 * 1024 * 1024UL)
++static int
++xen_ia64_privcmd_check_size(unsigned long start, unsigned long end)
++{
++ return (start < end &&
++ (end - start) > XEN_IA64_PRIVCMD_LEAST_GAP_SIZE);
++}
++
++static int __init
++xen_ia64_privcmd_init(void)
++{
++ void *efi_map_start, *efi_map_end, *p;
++ u64 efi_desc_size;
++ efi_memory_desc_t *md;
++ unsigned long tmp_min;
++ unsigned long tmp_max;
++ unsigned long gap_size;
++ unsigned long prev_end;
++
++ if (!is_running_on_xen())
++ return -1;
++
++ efi_map_start = __va(ia64_boot_param->efi_memmap);
++ efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
++ efi_desc_size = ia64_boot_param->efi_memdesc_size;
++
++ // at first check the used highest address
++ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
++ // nothing
++ }
++ md = p - efi_desc_size;
++ privcmd_resource_min = GRANULEROUNDUP(md_end_addr(md));
++ if (xen_ia64_privcmd_check_size(privcmd_resource_min,
++ privcmd_resource_max)) {
++ goto out;
++ }
++
++ // the used highest address is too large. try to find the largest gap.
++ tmp_min = privcmd_resource_max;
++ tmp_max = 0;
++ gap_size = 0;
++ prev_end = 0;
++ for (p = efi_map_start;
++ p < efi_map_end - efi_desc_size;
++ p += efi_desc_size) {
++ unsigned long end;
++ efi_memory_desc_t* next;
++ unsigned long next_start;
++
++ md = p;
++ end = md_end_addr(md);
++ if (end > privcmd_resource_max) {
++ break;
++ }
++ if (end < prev_end) {
++ // work around.
++ // Xen may pass incompletely sorted memory
++ // descriptors like
++ // [x, x + length]
++ // [x, x]
++ // this order should be reversed.
++ continue;
++ }
++ next = p + efi_desc_size;
++ next_start = next->phys_addr;
++ if (next_start > privcmd_resource_max) {
++ next_start = privcmd_resource_max;
++ }
++ if (end < next_start && gap_size < (next_start - end)) {
++ tmp_min = end;
++ tmp_max = next_start;
++ gap_size = tmp_max - tmp_min;
++ }
++ prev_end = end;
++ }
++
++ privcmd_resource_min = GRANULEROUNDUP(tmp_min);
++ if (xen_ia64_privcmd_check_size(privcmd_resource_min, tmp_max)) {
++ privcmd_resource_max = tmp_max;
++ goto out;
++ }
++
++ privcmd_resource_min = tmp_min;
++ privcmd_resource_max = tmp_max;
++ if (!xen_ia64_privcmd_check_size(privcmd_resource_min,
++ privcmd_resource_max)) {
++ // Any large enough gap isn't found.
++ // go ahead anyway with the warning hoping that large region
++ // won't be requested.
++ printk(KERN_WARNING "xen privcmd: large enough region for privcmd mmap is not found.\n");
++ }
++
++out:
++ printk(KERN_INFO "xen privcmd uses pseudo physical addr range [0x%lx, 0x%lx] (%ldMB)\n",
++ privcmd_resource_min, privcmd_resource_max,
++ (privcmd_resource_max - privcmd_resource_min) >> 20);
++ BUG_ON(privcmd_resource_min >= privcmd_resource_max);
++
++ // XXX this should be somewhere appropriate
++ (void)p2m_expose_init();
++
++ return 0;
++}
++late_initcall(xen_ia64_privcmd_init);
++
++struct xen_ia64_privcmd_entry {
++ atomic_t map_count;
++#define INVALID_GPFN (~0UL)
++ unsigned long gpfn;
++};
++
++struct xen_ia64_privcmd_range {
++ atomic_t ref_count;
++ unsigned long pgoff; // in PAGE_SIZE
++ struct resource* res;
++
++ unsigned long num_entries;
++ struct xen_ia64_privcmd_entry entries[0];
++};
++
++struct xen_ia64_privcmd_vma {
++ int is_privcmd_mmapped;
++ struct xen_ia64_privcmd_range* range;
++
++ unsigned long num_entries;
++ struct xen_ia64_privcmd_entry* entries;
++};
++
++static void
++xen_ia64_privcmd_init_entry(struct xen_ia64_privcmd_entry* entry)
++{
++ atomic_set(&entry->map_count, 0);
++ entry->gpfn = INVALID_GPFN;
++}
++
++static int
++xen_ia64_privcmd_entry_mmap(struct vm_area_struct* vma,
++ unsigned long addr,
++ struct xen_ia64_privcmd_range* privcmd_range,
++ int i,
++ unsigned long mfn,
++ pgprot_t prot,
++ domid_t domid)
++{
++ int error = 0;
++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i];
++ unsigned long gpfn;
++ unsigned long flags;
++
++ if ((addr & ~PAGE_MASK) != 0 || mfn == INVALID_MFN) {
++ error = -EINVAL;
++ goto out;
++ }
++
++ if (entry->gpfn != INVALID_GPFN) {
++ error = -EBUSY;
++ goto out;
++ }
++ gpfn = (privcmd_range->res->start >> PAGE_SHIFT) + i;
++
++ flags = ASSIGN_writable;
++ if (pgprot_val(prot) == PROT_READ) {
++ flags = ASSIGN_readonly;
++ }
++ error = HYPERVISOR_add_physmap(gpfn, mfn, flags, domid);
++ if (error != 0) {
++ goto out;
++ }
++
++ prot = vma->vm_page_prot;
++ error = remap_pfn_range(vma, addr, gpfn, 1 << PAGE_SHIFT, prot);
++ if (error != 0) {
++ error = HYPERVISOR_zap_physmap(gpfn, 0);
++ if (error) {
++ BUG();//XXX
++ }
++ } else {
++ atomic_inc(&entry->map_count);
++ entry->gpfn = gpfn;
++ }
++
++out:
++ return error;
++}
++
++static void
++xen_ia64_privcmd_entry_munmap(struct xen_ia64_privcmd_range* privcmd_range,
++ int i)
++{
++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i];
++ unsigned long gpfn = entry->gpfn;
++ //gpfn = (privcmd_range->res->start >> PAGE_SHIFT) +
++ // (vma->vm_pgoff - privcmd_range->pgoff);
++ int error;
++
++ error = HYPERVISOR_zap_physmap(gpfn, 0);
++ if (error) {
++ BUG();//XXX
++ }
++ entry->gpfn = INVALID_GPFN;
++}
++
++static void
++xen_ia64_privcmd_entry_open(struct xen_ia64_privcmd_range* privcmd_range,
++ int i)
++{
++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i];
++ if (entry->gpfn != INVALID_GPFN) {
++ atomic_inc(&entry->map_count);
++ } else {
++ BUG_ON(atomic_read(&entry->map_count) != 0);
++ }
++}
++
++static void
++xen_ia64_privcmd_entry_close(struct xen_ia64_privcmd_range* privcmd_range,
++ int i)
++{
++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i];
++ if (entry->gpfn != INVALID_GPFN &&
++ atomic_dec_and_test(&entry->map_count)) {
++ xen_ia64_privcmd_entry_munmap(privcmd_range, i);
++ }
++}
++
++static void xen_ia64_privcmd_vma_open(struct vm_area_struct* vma);
++static void xen_ia64_privcmd_vma_close(struct vm_area_struct* vma);
++
++struct vm_operations_struct xen_ia64_privcmd_vm_ops = {
++ .open = &xen_ia64_privcmd_vma_open,
++ .close = &xen_ia64_privcmd_vma_close,
++};
++
++static void
++__xen_ia64_privcmd_vma_open(struct vm_area_struct* vma,
++ struct xen_ia64_privcmd_vma* privcmd_vma,
++ struct xen_ia64_privcmd_range* privcmd_range)
++{
++ unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff;
++ unsigned long num_entries = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++ unsigned long i;
++
++ BUG_ON(entry_offset < 0);
++ BUG_ON(entry_offset + num_entries > privcmd_range->num_entries);
++
++ privcmd_vma->range = privcmd_range;
++ privcmd_vma->num_entries = num_entries;
++ privcmd_vma->entries = &privcmd_range->entries[entry_offset];
++ vma->vm_private_data = privcmd_vma;
++ for (i = 0; i < privcmd_vma->num_entries; i++) {
++ xen_ia64_privcmd_entry_open(privcmd_range, entry_offset + i);
++ }
++
++ vma->vm_private_data = privcmd_vma;
++ vma->vm_ops = &xen_ia64_privcmd_vm_ops;
++}
++
++static void
++xen_ia64_privcmd_vma_open(struct vm_area_struct* vma)
++{
++ struct xen_ia64_privcmd_vma* old_privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
++ struct xen_ia64_privcmd_vma* privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
++ struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range;
++
++ atomic_inc(&privcmd_range->ref_count);
++ // vm_op->open() can't fail.
++ privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL | __GFP_NOFAIL);
++ // copy original value if necessary
++ privcmd_vma->is_privcmd_mmapped = old_privcmd_vma->is_privcmd_mmapped;
++
++ __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range);
++}
++
++static void
++xen_ia64_privcmd_vma_close(struct vm_area_struct* vma)
++{
++ struct xen_ia64_privcmd_vma* privcmd_vma =
++ (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
++ struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range;
++ unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff;
++ unsigned long i;
++
++ for (i = 0; i < privcmd_vma->num_entries; i++) {
++ xen_ia64_privcmd_entry_close(privcmd_range, entry_offset + i);
++ }
++ vma->vm_private_data = NULL;
++ kfree(privcmd_vma);
++
++ if (atomic_dec_and_test(&privcmd_range->ref_count)) {
++#if 1
++ for (i = 0; i < privcmd_range->num_entries; i++) {
++ struct xen_ia64_privcmd_entry* entry =
++ &privcmd_range->entries[i];
++ BUG_ON(atomic_read(&entry->map_count) != 0);
++ BUG_ON(entry->gpfn != INVALID_GPFN);
++ }
++#endif
++ release_resource(privcmd_range->res);
++ kfree(privcmd_range->res);
++ vfree(privcmd_range);
++ }
++}
++
++int
++privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
++{
++ struct xen_ia64_privcmd_vma* privcmd_vma =
++ (struct xen_ia64_privcmd_vma *)vma->vm_private_data;
++ return (xchg(&privcmd_vma->is_privcmd_mmapped, 1) == 0);
++}
++
++int
++privcmd_mmap(struct file * file, struct vm_area_struct * vma)
++{
++ int error;
++ unsigned long size = vma->vm_end - vma->vm_start;
++ unsigned long num_entries = size >> PAGE_SHIFT;
++ struct xen_ia64_privcmd_range* privcmd_range = NULL;
++ struct xen_ia64_privcmd_vma* privcmd_vma = NULL;
++ struct resource* res = NULL;
++ unsigned long i;
++ BUG_ON(!is_running_on_xen());
++
++ BUG_ON(file->private_data != NULL);
++
++ error = -ENOMEM;
++ privcmd_range =
++ vmalloc(sizeof(*privcmd_range) +
++ sizeof(privcmd_range->entries[0]) * num_entries);
++ if (privcmd_range == NULL) {
++ goto out_enomem0;
++ }
++ privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL);
++ if (privcmd_vma == NULL) {
++ goto out_enomem1;
++ }
++ privcmd_vma->is_privcmd_mmapped = 0;
++
++ res = kzalloc(sizeof(*res), GFP_KERNEL);
++ if (res == NULL) {
++ goto out_enomem1;
++ }
++ res->name = "Xen privcmd mmap";
++ error = allocate_resource(&iomem_resource, res, size,
++ privcmd_resource_min, privcmd_resource_max,
++ privcmd_resource_align, NULL, NULL);
++ if (error) {
++ goto out_enomem1;
++ }
++ privcmd_range->res = res;
++
++ /* DONTCOPY is essential for Xen as copy_page_range is broken. */
++ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
++
++ atomic_set(&privcmd_range->ref_count, 1);
++ privcmd_range->pgoff = vma->vm_pgoff;
++ privcmd_range->num_entries = num_entries;
++ for (i = 0; i < privcmd_range->num_entries; i++) {
++ xen_ia64_privcmd_init_entry(&privcmd_range->entries[i]);
++ }
++
++ __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range);
++ return 0;
++
++out_enomem1:
++ kfree(res);
++ kfree(privcmd_vma);
++out_enomem0:
++ vfree(privcmd_range);
++ return error;
++}
++
++int
++direct_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long address, // process virtual address
++ unsigned long mfn, // mfn, mfn + 1, ... mfn + size/PAGE_SIZE
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid) // target domain
++{
++ struct xen_ia64_privcmd_vma* privcmd_vma =
++ (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
++ struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range;
++ unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff;
++
++ unsigned long i;
++ unsigned long offset;
++ int error = 0;
++ BUG_ON(!is_running_on_xen());
++
++#if 0
++ if (prot != vm->vm_page_prot) {
++ return -EINVAL;
++ }
++#endif
++
++ i = (address - vma->vm_start) >> PAGE_SHIFT;
++ for (offset = 0; offset < size; offset += PAGE_SIZE) {
++ error = xen_ia64_privcmd_entry_mmap(vma, (address + offset) & PAGE_MASK, privcmd_range, entry_offset + i, mfn, prot, domid);
++ if (error != 0) {
++ break;
++ }
++
++ i++;
++ mfn++;
++ }
++
++ return error;
++}
++
++
++/* Called after suspend, to resume time. */
++void
++time_resume(void)
++{
++ extern void ia64_cpu_local_tick(void);
++
++ /* Just trigger a tick. */
++ ia64_cpu_local_tick();
++}
++
++///////////////////////////////////////////////////////////////////////////
++// expose p2m table
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
++#include <linux/cpu.h>
++#include <asm/uaccess.h>
++
++int p2m_initialized __read_mostly = 0;
++
++unsigned long p2m_min_low_pfn __read_mostly;
++unsigned long p2m_max_low_pfn __read_mostly;
++unsigned long p2m_convert_min_pfn __read_mostly;
++unsigned long p2m_convert_max_pfn __read_mostly;
++
++static struct resource p2m_resource = {
++ .name = "Xen p2m table",
++ .flags = IORESOURCE_MEM,
++};
++static unsigned long p2m_assign_start_pfn __read_mostly;
++static unsigned long p2m_assign_end_pfn __read_mostly;
++volatile const pte_t* p2m_pte __read_mostly;
++
++#define GRNULE_PFN PTRS_PER_PTE
++static unsigned long p2m_granule_pfn __read_mostly = GRNULE_PFN;
++
++#define ROUNDDOWN(x, y) ((x) & ~((y) - 1))
++#define ROUNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1))
++
++#define P2M_PREFIX "Xen p2m: "
++
++static int xen_ia64_p2m_expose __read_mostly = 1;
++module_param(xen_ia64_p2m_expose, int, 0);
++MODULE_PARM_DESC(xen_ia64_p2m_expose,
++ "enable/disable xen/ia64 p2m exposure optimization\n");
++
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
++static int xen_ia64_p2m_expose_use_dtr __read_mostly = 1;
++module_param(xen_ia64_p2m_expose_use_dtr, int, 0);
++MODULE_PARM_DESC(xen_ia64_p2m_expose_use_dtr,
++ "use/unuse dtr to map exposed p2m table\n");
++
++static const int p2m_page_shifts[] = {
++ _PAGE_SIZE_4K,
++ _PAGE_SIZE_8K,
++ _PAGE_SIZE_16K,
++ _PAGE_SIZE_64K,
++ _PAGE_SIZE_256K,
++ _PAGE_SIZE_1M,
++ _PAGE_SIZE_4M,
++ _PAGE_SIZE_16M,
++ _PAGE_SIZE_64M,
++ _PAGE_SIZE_256M,
++};
++
++struct p2m_itr_arg {
++ unsigned long vaddr;
++ unsigned long pteval;
++ unsigned long log_page_size;
++};
++static struct p2m_itr_arg p2m_itr_arg __read_mostly;
++
++// This should be in asm-ia64/kregs.h
++#define IA64_TR_P2M_TABLE 3
++
++static void
++p2m_itr(void* info)
++{
++ struct p2m_itr_arg* arg = (struct p2m_itr_arg*)info;
++ ia64_itr(0x2, IA64_TR_P2M_TABLE,
++ arg->vaddr, arg->pteval, arg->log_page_size);
++ ia64_srlz_d();
++}
++
++static int
++p2m_expose_dtr_call(struct notifier_block *self,
++ unsigned long event, void* ptr)
++{
++ unsigned int cpu = (unsigned int)(long)ptr;
++ if (event != CPU_ONLINE)
++ return 0;
++ if (!(p2m_initialized && xen_ia64_p2m_expose_use_dtr))
++ smp_call_function_single(cpu, &p2m_itr, &p2m_itr_arg, 1, 1);
++ return 0;
++}
++
++static struct notifier_block p2m_expose_dtr_hotplug_notifier = {
++ .notifier_call = p2m_expose_dtr_call,
++ .next = NULL,
++ .priority = 0
++};
++#endif
++
++static int
++p2m_expose_init(void)
++{
++ unsigned long num_pfn;
++ unsigned long size = 0;
++ unsigned long p2m_size = 0;
++ unsigned long align = ~0UL;
++ int error = 0;
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
++ int i;
++ unsigned long page_size;
++ unsigned long log_page_size = 0;
++#endif
++
++ if (!xen_ia64_p2m_expose)
++ return -ENOSYS;
++ if (p2m_initialized)
++ return 0;
++
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
++ error = register_cpu_notifier(&p2m_expose_dtr_hotplug_notifier);
++ if (error < 0)
++ return error;
++#endif
++
++ lock_cpu_hotplug();
++ if (p2m_initialized)
++ goto out;
++
++#ifdef CONFIG_DISCONTIGMEM
++ p2m_min_low_pfn = min_low_pfn;
++ p2m_max_low_pfn = max_low_pfn;
++#else
++ p2m_min_low_pfn = 0;
++ p2m_max_low_pfn = max_pfn;
++#endif
++
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
++ if (xen_ia64_p2m_expose_use_dtr) {
++ unsigned long granule_pfn = 0;
++ p2m_size = p2m_max_low_pfn - p2m_min_low_pfn;
++ for (i = 0;
++ i < sizeof(p2m_page_shifts)/sizeof(p2m_page_shifts[0]);
++ i++) {
++ log_page_size = p2m_page_shifts[i];
++ page_size = 1UL << log_page_size;
++ if (page_size < p2m_size)
++ continue;
++
++ granule_pfn = max(page_size >> PAGE_SHIFT,
++ p2m_granule_pfn);
++ p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn,
++ granule_pfn);
++ p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn,
++ granule_pfn);
++ num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
++ size = num_pfn << PAGE_SHIFT;
++ p2m_size = num_pfn / PTRS_PER_PTE;
++ p2m_size = ROUNDUP(p2m_size, granule_pfn << PAGE_SHIFT);
++ if (p2m_size == page_size)
++ break;
++ }
++ if (p2m_size != page_size) {
++ printk(KERN_ERR "p2m_size != page_size\n");
++ error = -EINVAL;
++ goto out;
++ }
++ align = max(privcmd_resource_align, granule_pfn << PAGE_SHIFT);
++ } else
++#endif
++ {
++ BUG_ON(p2m_granule_pfn & (p2m_granule_pfn - 1));
++ p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn,
++ p2m_granule_pfn);
++ p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, p2m_granule_pfn);
++ num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
++ size = num_pfn << PAGE_SHIFT;
++ p2m_size = num_pfn / PTRS_PER_PTE;
++ p2m_size = ROUNDUP(p2m_size, p2m_granule_pfn << PAGE_SHIFT);
++ align = max(privcmd_resource_align,
++ p2m_granule_pfn << PAGE_SHIFT);
++ }
++
++ // use privcmd region
++ error = allocate_resource(&iomem_resource, &p2m_resource, p2m_size,
++ privcmd_resource_min, privcmd_resource_max,
++ align, NULL, NULL);
++ if (error) {
++ printk(KERN_ERR P2M_PREFIX
++ "can't allocate region for p2m exposure "
++ "[0x%016lx, 0x%016lx) 0x%016lx\n",
++ p2m_convert_min_pfn, p2m_convert_max_pfn, p2m_size);
++ goto out;
++ }
++
++ p2m_assign_start_pfn = p2m_resource.start >> PAGE_SHIFT;
++ p2m_assign_end_pfn = p2m_resource.end >> PAGE_SHIFT;
++
++ error = HYPERVISOR_expose_p2m(p2m_convert_min_pfn,
++ p2m_assign_start_pfn,
++ size, p2m_granule_pfn);
++ if (error) {
++ printk(KERN_ERR P2M_PREFIX "failed expose p2m hypercall %d\n",
++ error);
++ printk(KERN_ERR P2M_PREFIX "conv 0x%016lx assign 0x%016lx "
++ "size 0x%016lx granule 0x%016lx\n",
++ p2m_convert_min_pfn, p2m_assign_start_pfn,
++ size, p2m_granule_pfn);;
++ release_resource(&p2m_resource);
++ goto out;
++ }
++ p2m_pte = (volatile const pte_t*)pfn_to_kaddr(p2m_assign_start_pfn);
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
++ if (xen_ia64_p2m_expose_use_dtr) {
++ p2m_itr_arg.vaddr = (unsigned long)__va(p2m_assign_start_pfn
++ << PAGE_SHIFT);
++ p2m_itr_arg.pteval = pte_val(pfn_pte(p2m_assign_start_pfn,
++ PAGE_KERNEL));
++ p2m_itr_arg.log_page_size = log_page_size;
++ smp_mb();
++ smp_call_function(&p2m_itr, &p2m_itr_arg, 1, 1);
++ p2m_itr(&p2m_itr_arg);
++ }
++#endif
++ smp_mb();
++ p2m_initialized = 1;
++ printk(P2M_PREFIX "assign p2m table of [0x%016lx, 0x%016lx)\n",
++ p2m_convert_min_pfn << PAGE_SHIFT,
++ p2m_convert_max_pfn << PAGE_SHIFT);
++ printk(P2M_PREFIX "to [0x%016lx, 0x%016lx) (%ld KBytes)\n",
++ p2m_assign_start_pfn << PAGE_SHIFT,
++ p2m_assign_end_pfn << PAGE_SHIFT,
++ p2m_size / 1024);
++out:
++ unlock_cpu_hotplug();
++ return error;
++}
++
++#ifdef notyet
++void
++p2m_expose_cleanup(void)
++{
++ BUG_ON(!p2m_initialized);
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
++ unregister_cpu_notifier(&p2m_expose_dtr_hotplug_notifier);
++#endif
++ release_resource(&p2m_resource);
++}
++#endif
++
++//XXX inlinize?
++unsigned long
++p2m_phystomach(unsigned long gpfn)
++{
++ volatile const pte_t* pte;
++ unsigned long mfn;
++ unsigned long pteval;
++
++ if (!p2m_initialized ||
++ gpfn < p2m_min_low_pfn || gpfn > p2m_max_low_pfn
++ /* || !pfn_valid(gpfn) */)
++ return INVALID_MFN;
++ pte = p2m_pte + (gpfn - p2m_convert_min_pfn);
++
++ mfn = INVALID_MFN;
++ if (likely(__get_user(pteval, (unsigned long __user *)pte) == 0 &&
++ pte_present(__pte(pteval)) &&
++ pte_pfn(__pte(pteval)) != (INVALID_MFN >> PAGE_SHIFT)))
++ mfn = (pteval & _PFN_MASK) >> PAGE_SHIFT;
++
++ return mfn;
++}
++
++EXPORT_SYMBOL_GPL(p2m_initialized);
++EXPORT_SYMBOL_GPL(p2m_min_low_pfn);
++EXPORT_SYMBOL_GPL(p2m_max_low_pfn);
++EXPORT_SYMBOL_GPL(p2m_convert_min_pfn);
++EXPORT_SYMBOL_GPL(p2m_convert_max_pfn);
++EXPORT_SYMBOL_GPL(p2m_pte);
++EXPORT_SYMBOL_GPL(p2m_phystomach);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/Makefile linux-2.6.18-xen/arch/ia64/xen/Makefile
+--- linux-2.6.18.1/arch/ia64/xen/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/Makefile 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,9 @@
++#
++# Makefile for Xen components
++#
++
++obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \
++ hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \
++ xcom_privcmd.o
++
++pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/util.c linux-2.6.18-xen/arch/ia64/xen/util.c
+--- linux-2.6.18.1/arch/ia64/xen/util.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/util.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,117 @@
++/******************************************************************************
++ * arch/ia64/xen/util.c
++ * This file is the ia64 counterpart of drivers/xen/util.c
++ *
++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
++ * VA Linux Systems Japan K.K.
++ *
++ * 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/mm.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <xen/driver_util.h>
++#include <xen/interface/memory.h>
++#include <asm/hypercall.h>
++
++struct vm_struct *alloc_vm_area(unsigned long size)
++{
++ int order;
++ unsigned long virt;
++ unsigned long nr_pages;
++ struct vm_struct* area;
++
++ order = get_order(size);
++ virt = __get_free_pages(GFP_KERNEL, order);
++ if (virt == 0) {
++ goto err0;
++ }
++ nr_pages = 1 << order;
++ scrub_pages(virt, nr_pages);
++
++ area = kmalloc(sizeof(*area), GFP_KERNEL);
++ if (area == NULL) {
++ goto err1;
++ }
++
++ area->flags = VM_IOREMAP;//XXX
++ area->addr = (void*)virt;
++ area->size = size;
++ area->pages = NULL; //XXX
++ area->nr_pages = nr_pages;
++ area->phys_addr = 0; /* xenbus_map_ring_valloc uses this field! */
++
++ return area;
++
++err1:
++ free_pages(virt, order);
++err0:
++ return NULL;
++
++}
++EXPORT_SYMBOL_GPL(alloc_vm_area);
++
++void free_vm_area(struct vm_struct *area)
++{
++ unsigned int order = get_order(area->size);
++ unsigned long i;
++ unsigned long phys_addr = __pa(area->addr);
++
++ // This area is used for foreign page mappping.
++ // So underlying machine page may not be assigned.
++ for (i = 0; i < (1 << order); i++) {
++ unsigned long ret;
++ unsigned long gpfn = (phys_addr >> PAGE_SHIFT) + i;
++ struct xen_memory_reservation reservation = {
++ .nr_extents = 1,
++ .address_bits = 0,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++ set_xen_guest_handle(reservation.extent_start, &gpfn);
++ ret = HYPERVISOR_memory_op(XENMEM_populate_physmap,
++ &reservation);
++ BUG_ON(ret != 1);
++ }
++ free_pages((unsigned long)area->addr, order);
++ kfree(area);
++}
++EXPORT_SYMBOL_GPL(free_vm_area);
++
++void lock_vm_area(struct vm_struct *area)
++{
++ // nothing
++}
++EXPORT_SYMBOL_GPL(lock_vm_area);
++
++void unlock_vm_area(struct vm_struct *area)
++{
++ // nothing
++}
++EXPORT_SYMBOL_GPL(unlock_vm_area);
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * indent-tabs-mode: t
++ * c-indent-level: 8
++ * c-basic-offset: 8
++ * tab-width: 8
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xcom_hcall.c linux-2.6.18-xen/arch/ia64/xen/xcom_hcall.c
+--- linux-2.6.18.1/arch/ia64/xen/xcom_hcall.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xcom_hcall.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,469 @@
++/*
++ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++ *
++ * Tristan Gingold <tristan.gingold at bull.net>
++ */
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/gfp.h>
++#include <linux/module.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/dom0_ops.h>
++#include <xen/interface/memory.h>
++#include <xen/interface/xencomm.h>
++#include <xen/interface/version.h>
++#include <xen/interface/sched.h>
++#include <xen/interface/event_channel.h>
++#include <xen/interface/physdev.h>
++#include <xen/interface/grant_table.h>
++#include <xen/interface/callback.h>
++#include <xen/interface/acm_ops.h>
++#include <xen/interface/hvm/params.h>
++#include <xen/public/privcmd.h>
++#include <asm/hypercall.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/xen/xencomm.h>
++
++/* Xencomm notes:
++ * This file defines hypercalls to be used by xencomm. The hypercalls simply
++ * create inlines descriptors for pointers and then call the raw arch hypercall
++ * xencomm_arch_hypercall_XXX
++ *
++ * If the arch wants to directly use these hypercalls, simply define macros
++ * in asm/hypercall.h, eg:
++ * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
++ *
++ * The arch may also define HYPERVISOR_xxx as a function and do more operations
++ * before/after doing the hypercall.
++ *
++ * Note: because only inline descriptors are created these functions must only
++ * be called with in kernel memory parameters.
++ */
++
++int
++xencomm_hypercall_console_io(int cmd, int count, char *str)
++{
++ return xencomm_arch_hypercall_console_io
++ (cmd, count, xencomm_create_inline(str));
++}
++
++int
++xencomm_hypercall_event_channel_op(int cmd, void *op)
++{
++ return xencomm_arch_hypercall_event_channel_op
++ (cmd, xencomm_create_inline(op));
++}
++
++int
++xencomm_hypercall_xen_version(int cmd, void *arg)
++{
++ switch (cmd) {
++ case XENVER_version:
++ case XENVER_extraversion:
++ case XENVER_compile_info:
++ case XENVER_capabilities:
++ case XENVER_changeset:
++ case XENVER_platform_parameters:
++ case XENVER_pagesize:
++ case XENVER_get_features:
++ break;
++ default:
++ printk("%s: unknown version cmd %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ return xencomm_arch_hypercall_xen_version
++ (cmd, xencomm_create_inline(arg));
++}
++
++int
++xencomm_hypercall_physdev_op(int cmd, void *op)
++{
++ return xencomm_arch_hypercall_physdev_op
++ (cmd, xencomm_create_inline(op));
++}
++
++static void *
++xencommize_grant_table_op(unsigned int cmd, void *op, unsigned int count)
++{
++ switch (cmd) {
++ case GNTTABOP_map_grant_ref:
++ case GNTTABOP_unmap_grant_ref:
++ break;
++ case GNTTABOP_setup_table:
++ {
++ struct gnttab_setup_table *setup = op;
++ struct xencomm_handle *frame_list;
++
++ frame_list = xencomm_create_inline
++ (xen_guest_handle(setup->frame_list));
++
++ set_xen_guest_handle(setup->frame_list, (void *)frame_list);
++ break;
++ }
++ case GNTTABOP_dump_table:
++ case GNTTABOP_transfer:
++ case GNTTABOP_copy:
++ break;
++ default:
++ printk("%s: unknown grant table op %d\n", __func__, cmd);
++ BUG();
++ }
++
++ return xencomm_create_inline(op);
++}
++
++int
++xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, unsigned int count)
++{
++ void *desc = xencommize_grant_table_op (cmd, op, count);
++
++ return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
++}
++
++int
++xencomm_hypercall_sched_op(int cmd, void *arg)
++{
++ switch (cmd) {
++ case SCHEDOP_yield:
++ case SCHEDOP_block:
++ case SCHEDOP_shutdown:
++ case SCHEDOP_poll:
++ case SCHEDOP_remote_shutdown:
++ break;
++ default:
++ printk("%s: unknown sched op %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ return xencomm_arch_hypercall_sched_op(cmd, xencomm_create_inline(arg));
++}
++
++int
++xencomm_hypercall_multicall(void *call_list, int nr_calls)
++{
++ int i;
++ multicall_entry_t *mce;
++
++ for (i = 0; i < nr_calls; i++) {
++ mce = (multicall_entry_t *)call_list + i;
++
++ switch (mce->op) {
++ case __HYPERVISOR_update_va_mapping:
++ case __HYPERVISOR_mmu_update:
++ /* No-op on ia64. */
++ break;
++ case __HYPERVISOR_grant_table_op:
++ mce->args[1] = (unsigned long)xencommize_grant_table_op
++ (mce->args[0], (void *)mce->args[1],
++ mce->args[2]);
++ break;
++ case __HYPERVISOR_memory_op:
++ default:
++ printk("%s: unhandled multicall op entry op %lu\n",
++ __func__, mce->op);
++ return -ENOSYS;
++ }
++ }
++
++ return xencomm_arch_hypercall_multicall
++ (xencomm_create_inline(call_list), nr_calls);
++}
++
++int
++xencomm_hypercall_callback_op(int cmd, void *arg)
++{
++ switch (cmd)
++ {
++ case CALLBACKOP_register:
++ case CALLBACKOP_unregister:
++ break;
++ default:
++ printk("%s: unknown callback op %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ return xencomm_arch_hypercall_callback_op
++ (cmd, xencomm_create_inline(arg));
++}
++
++static void
++xencommize_memory_reservation (xen_memory_reservation_t *mop)
++{
++ struct xencomm_handle *desc;
++
++ desc = xencomm_create_inline(xen_guest_handle(mop->extent_start));
++ set_xen_guest_handle(mop->extent_start, (void *)desc);
++}
++
++int
++xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
++{
++ switch (cmd) {
++ case XENMEM_increase_reservation:
++ case XENMEM_decrease_reservation:
++ case XENMEM_populate_physmap:
++ xencommize_memory_reservation((xen_memory_reservation_t *)arg);
++ break;
++
++ case XENMEM_maximum_ram_page:
++ break;
++
++ case XENMEM_exchange:
++ xencommize_memory_reservation
++ (&((xen_memory_exchange_t *)arg)->in);
++ xencommize_memory_reservation
++ (&((xen_memory_exchange_t *)arg)->out);
++ break;
++
++ default:
++ printk("%s: unknown memory op %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ return xencomm_arch_hypercall_memory_op
++ (cmd, xencomm_create_inline(arg));
++}
++
++unsigned long
++xencomm_hypercall_hvm_op(int cmd, void *arg)
++{
++ switch (cmd) {
++ case HVMOP_set_param:
++ case HVMOP_get_param:
++ break;
++ default:
++ printk("%s: unknown hvm op %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ return xencomm_arch_hypercall_hvm_op(cmd, xencomm_create_inline(arg));
++}
++
++int
++xencomm_hypercall_suspend(unsigned long srec)
++{
++ struct sched_shutdown arg;
++
++ arg.reason = SHUTDOWN_suspend;
++
++ return xencomm_arch_hypercall_suspend(xencomm_create_inline(&arg));
++}
++
++int
++xencomm_mini_hypercall_event_channel_op(int cmd, void *op)
++{
++ struct xencomm_mini xc_area[2];
++ int nbr_area = 2;
++ struct xencomm_handle *desc;
++ int rc;
++
++ rc = xencomm_create_mini(xc_area, &nbr_area,
++ op, sizeof(evtchn_op_t), &desc);
++ if (rc)
++ return rc;
++
++ return xencomm_arch_hypercall_event_channel_op(cmd, desc);
++}
++EXPORT_SYMBOL(xencomm_mini_hypercall_event_channel_op);
++
++static int
++xencommize_mini_grant_table_op(struct xencomm_mini *xc_area, int *nbr_area,
++ unsigned int cmd, void *op, unsigned int count,
++ struct xencomm_handle **desc)
++{
++ struct xencomm_handle *desc1;
++ unsigned int argsize;
++ int rc;
++
++ switch (cmd) {
++ case GNTTABOP_map_grant_ref:
++ argsize = sizeof(struct gnttab_map_grant_ref);
++ break;
++ case GNTTABOP_unmap_grant_ref:
++ argsize = sizeof(struct gnttab_unmap_grant_ref);
++ break;
++ case GNTTABOP_setup_table:
++ {
++ struct gnttab_setup_table *setup = op;
++
++ argsize = sizeof(*setup);
++
++ if (count != 1)
++ return -EINVAL;
++ rc = xencomm_create_mini
++ (xc_area, nbr_area,
++ xen_guest_handle(setup->frame_list),
++ setup->nr_frames
++ * sizeof(*xen_guest_handle(setup->frame_list)),
++ &desc1);
++ if (rc)
++ return rc;
++ set_xen_guest_handle(setup->frame_list, (void *)desc1);
++ break;
++ }
++ case GNTTABOP_dump_table:
++ argsize = sizeof(struct gnttab_dump_table);
++ break;
++ case GNTTABOP_transfer:
++ argsize = sizeof(struct gnttab_transfer);
++ break;
++ default:
++ printk("%s: unknown mini grant table op %d\n", __func__, cmd);
++ BUG();
++ }
++
++ rc = xencomm_create_mini(xc_area, nbr_area, op, count * argsize, desc);
++ if (rc)
++ return rc;
++
++ return 0;
++}
++
++int
++xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op,
++ unsigned int count)
++{
++ int rc;
++ struct xencomm_handle *desc;
++ int nbr_area = 2;
++ struct xencomm_mini xc_area[2];
++
++ rc = xencommize_mini_grant_table_op(xc_area, &nbr_area,
++ cmd, op, count, &desc);
++ if (rc)
++ return rc;
++
++ return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
++}
++EXPORT_SYMBOL(xencomm_mini_hypercall_grant_table_op);
++
++int
++xencomm_mini_hypercall_multicall(void *call_list, int nr_calls)
++{
++ int i;
++ multicall_entry_t *mce;
++ int nbr_area = 2 + nr_calls * 3;
++ struct xencomm_mini xc_area[nbr_area];
++ struct xencomm_handle *desc;
++ int rc;
++
++ for (i = 0; i < nr_calls; i++) {
++ mce = (multicall_entry_t *)call_list + i;
++
++ switch (mce->op) {
++ case __HYPERVISOR_update_va_mapping:
++ case __HYPERVISOR_mmu_update:
++ /* No-op on ia64. */
++ break;
++ case __HYPERVISOR_grant_table_op:
++ rc = xencommize_mini_grant_table_op
++ (xc_area, &nbr_area,
++ mce->args[0], (void *)mce->args[1],
++ mce->args[2], &desc);
++ if (rc)
++ return rc;
++ mce->args[1] = (unsigned long)desc;
++ break;
++ case __HYPERVISOR_memory_op:
++ default:
++ printk("%s: unhandled multicall op entry op %lu\n",
++ __func__, mce->op);
++ return -ENOSYS;
++ }
++ }
++
++ rc = xencomm_create_mini(xc_area, &nbr_area, call_list,
++ nr_calls * sizeof(multicall_entry_t), &desc);
++ if (rc)
++ return rc;
++
++ return xencomm_arch_hypercall_multicall(desc, nr_calls);
++}
++EXPORT_SYMBOL(xencomm_mini_hypercall_multicall);
++
++static int
++xencommize_mini_memory_reservation(struct xencomm_mini *area, int *nbr_area,
++ xen_memory_reservation_t *mop)
++{
++ struct xencomm_handle *desc;
++ int rc;
++
++ rc = xencomm_create_mini
++ (area, nbr_area,
++ xen_guest_handle(mop->extent_start),
++ mop->nr_extents
++ * sizeof(*xen_guest_handle(mop->extent_start)),
++ &desc);
++ if (rc)
++ return rc;
++
++ set_xen_guest_handle(mop->extent_start, (void *)desc);
++
++ return 0;
++}
++
++int
++xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg)
++{
++ int nbr_area = 4;
++ struct xencomm_mini xc_area[4];
++ struct xencomm_handle *desc;
++ int rc;
++ unsigned int argsize;
++
++ switch (cmd) {
++ case XENMEM_increase_reservation:
++ case XENMEM_decrease_reservation:
++ case XENMEM_populate_physmap:
++ argsize = sizeof(xen_memory_reservation_t);
++ rc = xencommize_mini_memory_reservation
++ (xc_area, &nbr_area, (xen_memory_reservation_t *)arg);
++ if (rc)
++ return rc;
++ break;
++
++ case XENMEM_maximum_ram_page:
++ argsize = 0;
++ break;
++
++ case XENMEM_exchange:
++ argsize = sizeof(xen_memory_exchange_t);
++ rc = xencommize_mini_memory_reservation
++ (xc_area, &nbr_area,
++ &((xen_memory_exchange_t *)arg)->in);
++ if (rc)
++ return rc;
++ rc = xencommize_mini_memory_reservation
++ (xc_area, &nbr_area,
++ &((xen_memory_exchange_t *)arg)->out);
++ if (rc)
++ return rc;
++ break;
++
++ default:
++ printk("%s: unknown mini memory op %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc);
++ if (rc)
++ return rc;
++
++ return xencomm_arch_hypercall_memory_op(cmd, desc);
++}
++EXPORT_SYMBOL(xencomm_mini_hypercall_memory_op);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xcom_privcmd.c linux-2.6.18-xen/arch/ia64/xen/xcom_privcmd.c
+--- linux-2.6.18.1/arch/ia64/xen/xcom_privcmd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xcom_privcmd.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,600 @@
++/*
++ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++ *
++ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
++ * Tristan Gingold <tristan.gingold at bull.net>
++ */
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/gfp.h>
++#include <linux/module.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/dom0_ops.h>
++#define __XEN__
++#include <xen/interface/domctl.h>
++#include <xen/interface/sysctl.h>
++#include <xen/interface/memory.h>
++#include <xen/interface/version.h>
++#include <xen/interface/event_channel.h>
++#include <xen/interface/acm_ops.h>
++#include <xen/interface/hvm/params.h>
++#include <xen/public/privcmd.h>
++#include <asm/hypercall.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/xen/xencomm.h>
++
++#define ROUND_DIV(v,s) (((v) + (s) - 1) / (s))
++
++static int
++xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall)
++{
++ dom0_op_t kern_op;
++ dom0_op_t __user *user_op = (dom0_op_t __user *)hypercall->arg[0];
++ struct xencomm_handle *op_desc;
++ struct xencomm_handle *desc = NULL;
++ int ret = 0;
++
++ if (copy_from_user(&kern_op, user_op, sizeof(dom0_op_t)))
++ return -EFAULT;
++
++ if (kern_op.interface_version != DOM0_INTERFACE_VERSION)
++ return -EACCES;
++
++ op_desc = xencomm_create_inline(&kern_op);
++
++ switch (kern_op.cmd) {
++ default:
++ printk("%s: unknown dom0 cmd %d\n", __func__, kern_op.cmd);
++ return -ENOSYS;
++ }
++
++ if (ret) {
++ /* error mapping the nested pointer */
++ return ret;
++ }
++
++ ret = xencomm_arch_hypercall_dom0_op(op_desc);
++
++ /* FIXME: should we restore the handle? */
++ if (copy_to_user(user_op, &kern_op, sizeof(dom0_op_t)))
++ ret = -EFAULT;
++
++ if (desc)
++ xencomm_free(desc);
++ return ret;
++}
++
++static int
++xencomm_privcmd_sysctl(privcmd_hypercall_t *hypercall)
++{
++ xen_sysctl_t kern_op;
++ xen_sysctl_t __user *user_op;
++ struct xencomm_handle *op_desc;
++ struct xencomm_handle *desc = NULL;
++ struct xencomm_handle *desc1 = NULL;
++ int ret = 0;
++
++ user_op = (xen_sysctl_t __user *)hypercall->arg[0];
++
++ if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t)))
++ return -EFAULT;
++
++ if (kern_op.interface_version != XEN_SYSCTL_INTERFACE_VERSION)
++ return -EACCES;
++
++ op_desc = xencomm_create_inline(&kern_op);
++
++ switch (kern_op.cmd) {
++ case XEN_SYSCTL_readconsole:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.readconsole.buffer),
++ kern_op.u.readconsole.count,
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.readconsole.buffer,
++ (void *)desc);
++ break;
++ case XEN_SYSCTL_tbuf_op:
++ case XEN_SYSCTL_physinfo:
++ case XEN_SYSCTL_sched_id:
++ break;
++ case XEN_SYSCTL_perfc_op:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.perfc_op.desc),
++ kern_op.u.perfc_op.nr_counters *
++ sizeof(xen_sysctl_perfc_desc_t),
++ &desc, GFP_KERNEL);
++ if (ret)
++ return ret;
++ set_xen_guest_handle(kern_op.u.perfc_op.val,
++ (void *)desc);
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.perfc_op.val),
++ kern_op.u.perfc_op.nr_vals *
++ sizeof(xen_sysctl_perfc_desc_t),
++ &desc1, GFP_KERNEL);
++ if (ret)
++ xencomm_free(desc);
++ set_xen_guest_handle(kern_op.u.perfc_op.val,
++ (void *)desc1);
++ break;
++ case XEN_SYSCTL_getdomaininfolist:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.getdomaininfolist.buffer),
++ kern_op.u.getdomaininfolist.max_domains *
++ sizeof(xen_domctl_getdomaininfo_t),
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer,
++ (void *)desc);
++ break;
++ default:
++ printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd);
++ return -ENOSYS;
++ }
++
++ if (ret) {
++ /* error mapping the nested pointer */
++ return ret;
++ }
++
++ ret = xencomm_arch_hypercall_sysctl(op_desc);
++
++ /* FIXME: should we restore the handle? */
++ if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t)))
++ ret = -EFAULT;
++
++ if (desc)
++ xencomm_free(desc);
++ if (desc1)
++ xencomm_free(desc1);
++ return ret;
++}
++
++static int
++xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall)
++{
++ xen_domctl_t kern_op;
++ xen_domctl_t __user *user_op;
++ struct xencomm_handle *op_desc;
++ struct xencomm_handle *desc = NULL;
++ int ret = 0;
++
++ user_op = (xen_domctl_t __user *)hypercall->arg[0];
++
++ if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t)))
++ return -EFAULT;
++
++ if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION)
++ return -EACCES;
++
++ op_desc = xencomm_create_inline(&kern_op);
++
++ switch (kern_op.cmd) {
++ case XEN_DOMCTL_createdomain:
++ case XEN_DOMCTL_destroydomain:
++ case XEN_DOMCTL_pausedomain:
++ case XEN_DOMCTL_unpausedomain:
++ case XEN_DOMCTL_getdomaininfo:
++ break;
++ case XEN_DOMCTL_getmemlist:
++ {
++ unsigned long nr_pages = kern_op.u.getmemlist.max_pfns;
++
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.getmemlist.buffer),
++ nr_pages * sizeof(unsigned long),
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.getmemlist.buffer,
++ (void *)desc);
++ break;
++ }
++ case XEN_DOMCTL_getpageframeinfo:
++ break;
++ case XEN_DOMCTL_getpageframeinfo2:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.getpageframeinfo2.array),
++ kern_op.u.getpageframeinfo2.num,
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.getpageframeinfo2.array,
++ (void *)desc);
++ break;
++ case XEN_DOMCTL_shadow_op:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap),
++ ROUND_DIV(kern_op.u.shadow_op.pages, 8),
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap,
++ (void *)desc);
++ break;
++ case XEN_DOMCTL_max_mem:
++ break;
++ case XEN_DOMCTL_setvcpucontext:
++ case XEN_DOMCTL_getvcpucontext:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.vcpucontext.ctxt),
++ sizeof(vcpu_guest_context_t),
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc);
++ break;
++ case XEN_DOMCTL_getvcpuinfo:
++ break;
++ case XEN_DOMCTL_setvcpuaffinity:
++ case XEN_DOMCTL_getvcpuaffinity:
++ ret = xencomm_create(
++ xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap),
++ ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8),
++ &desc, GFP_KERNEL);
++ set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap,
++ (void *)desc);
++ break;
++ case XEN_DOMCTL_max_vcpus:
++ case XEN_DOMCTL_scheduler_op:
++ case XEN_DOMCTL_setdomainhandle:
++ case XEN_DOMCTL_setdebugging:
++ case XEN_DOMCTL_irq_permission:
++ case XEN_DOMCTL_iomem_permission:
++ case XEN_DOMCTL_ioport_permission:
++ case XEN_DOMCTL_hypercall_init:
++ case XEN_DOMCTL_arch_setup:
++ case XEN_DOMCTL_settimeoffset:
++ break;
++ default:
++ printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd);
++ return -ENOSYS;
++ }
++
++ if (ret) {
++ /* error mapping the nested pointer */
++ return ret;
++ }
++
++ ret = xencomm_arch_hypercall_domctl (op_desc);
++
++ /* FIXME: should we restore the handle? */
++ if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t)))
++ ret = -EFAULT;
++
++ if (desc)
++ xencomm_free(desc);
++ return ret;
++}
++
++static int
++xencomm_privcmd_acm_op(privcmd_hypercall_t *hypercall)
++{
++ int cmd = hypercall->arg[0];
++ void __user *arg = (void __user *)hypercall->arg[1];
++ struct xencomm_handle *op_desc;
++ struct xencomm_handle *desc = NULL;
++ int ret;
++
++ switch (cmd) {
++ case ACMOP_getssid:
++ {
++ struct acm_getssid kern_arg;
++
++ if (copy_from_user(&kern_arg, arg, sizeof (kern_arg)))
++ return -EFAULT;
++
++ op_desc = xencomm_create_inline(&kern_arg);
++
++ ret = xencomm_create(xen_guest_handle(kern_arg.ssidbuf),
++ kern_arg.ssidbuf_size, &desc, GFP_KERNEL);
++ if (ret)
++ return ret;
++
++ set_xen_guest_handle(kern_arg.ssidbuf, (void *)desc);
++
++ ret = xencomm_arch_hypercall_acm_op(cmd, op_desc);
++
++ xencomm_free(desc);
++
++ if (copy_to_user(arg, &kern_arg, sizeof (kern_arg)))
++ return -EFAULT;
++
++ return ret;
++ }
++ default:
++ printk("%s: unknown acm_op cmd %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ return ret;
++}
++
++static int
++xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall)
++{
++ const unsigned long cmd = hypercall->arg[0];
++ int ret = 0;
++
++ switch (cmd) {
++ case XENMEM_increase_reservation:
++ case XENMEM_decrease_reservation:
++ case XENMEM_populate_physmap:
++ {
++ xen_memory_reservation_t kern_op;
++ xen_memory_reservation_t __user *user_op;
++ struct xencomm_handle *desc = NULL;
++ struct xencomm_handle *desc_op;
++
++ user_op = (xen_memory_reservation_t __user *)hypercall->arg[1];
++ if (copy_from_user(&kern_op, user_op,
++ sizeof(xen_memory_reservation_t)))
++ return -EFAULT;
++ desc_op = xencomm_create_inline(&kern_op);
++
++ if (xen_guest_handle(kern_op.extent_start)) {
++ void * addr;
++
++ addr = xen_guest_handle(kern_op.extent_start);
++ ret = xencomm_create
++ (addr,
++ kern_op.nr_extents *
++ sizeof(*xen_guest_handle
++ (kern_op.extent_start)),
++ &desc, GFP_KERNEL);
++ if (ret)
++ return ret;
++ set_xen_guest_handle(kern_op.extent_start,
++ (void *)desc);
++ }
++
++ ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
++
++ if (desc)
++ xencomm_free(desc);
++
++ if (ret != 0)
++ return ret;
++
++ if (copy_to_user(user_op, &kern_op,
++ sizeof(xen_memory_reservation_t)))
++ return -EFAULT;
++
++ return ret;
++ }
++ case XENMEM_translate_gpfn_list:
++ {
++ xen_translate_gpfn_list_t kern_op;
++ xen_translate_gpfn_list_t __user *user_op;
++ struct xencomm_handle *desc_gpfn = NULL;
++ struct xencomm_handle *desc_mfn = NULL;
++ struct xencomm_handle *desc_op;
++ void *addr;
++
++ user_op = (xen_translate_gpfn_list_t __user *)
++ hypercall->arg[1];
++ if (copy_from_user(&kern_op, user_op,
++ sizeof(xen_translate_gpfn_list_t)))
++ return -EFAULT;
++ desc_op = xencomm_create_inline(&kern_op);
++
++ if (kern_op.nr_gpfns) {
++ /* gpfn_list. */
++ addr = xen_guest_handle(kern_op.gpfn_list);
++
++ ret = xencomm_create(addr, kern_op.nr_gpfns *
++ sizeof(*xen_guest_handle
++ (kern_op.gpfn_list)),
++ &desc_gpfn, GFP_KERNEL);
++ if (ret)
++ return ret;
++ set_xen_guest_handle(kern_op.gpfn_list,
++ (void *)desc_gpfn);
++
++ /* mfn_list. */
++ addr = xen_guest_handle(kern_op.mfn_list);
++
++ ret = xencomm_create(addr, kern_op.nr_gpfns *
++ sizeof(*xen_guest_handle
++ (kern_op.mfn_list)),
++ &desc_mfn, GFP_KERNEL);
++ if (ret)
++ return ret;
++ set_xen_guest_handle(kern_op.mfn_list,
++ (void *)desc_mfn);
++ }
++
++ ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
++
++ if (desc_gpfn)
++ xencomm_free(desc_gpfn);
++
++ if (desc_mfn)
++ xencomm_free(desc_mfn);
++
++ if (ret != 0)
++ return ret;
++
++ return ret;
++ }
++ default:
++ printk("%s: unknown memory op %lu\n", __func__, cmd);
++ ret = -ENOSYS;
++ }
++ return ret;
++}
++
++static int
++xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall)
++{
++ int cmd = hypercall->arg[0];
++ void __user *arg = (void __user *)hypercall->arg[1];
++ struct xencomm_handle *desc;
++ size_t argsize;
++ int rc;
++
++ switch (cmd) {
++ case XENVER_version:
++ /* do not actually pass an argument */
++ return xencomm_arch_hypercall_xen_version(cmd, 0);
++ case XENVER_extraversion:
++ argsize = sizeof(xen_extraversion_t);
++ break;
++ case XENVER_compile_info:
++ argsize = sizeof(xen_compile_info_t);
++ break;
++ case XENVER_capabilities:
++ argsize = sizeof(xen_capabilities_info_t);
++ break;
++ case XENVER_changeset:
++ argsize = sizeof(xen_changeset_info_t);
++ break;
++ case XENVER_platform_parameters:
++ argsize = sizeof(xen_platform_parameters_t);
++ break;
++ case XENVER_pagesize:
++ argsize = (arg == NULL) ? 0 : sizeof(void *);
++ break;
++ case XENVER_get_features:
++ argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t);
++ break;
++
++ default:
++ printk("%s: unknown version op %d\n", __func__, cmd);
++ return -ENOSYS;
++ }
++
++ rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL);
++ if (rc)
++ return rc;
++
++ rc = xencomm_arch_hypercall_xen_version(cmd, desc);
++
++ xencomm_free(desc);
++
++ return rc;
++}
++
++static int
++xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall)
++{
++ int cmd = hypercall->arg[0];
++ struct xencomm_handle *desc;
++ unsigned int argsize;
++ int ret;
++
++ switch (cmd) {
++ case EVTCHNOP_alloc_unbound:
++ argsize = sizeof(evtchn_alloc_unbound_t);
++ break;
++
++ case EVTCHNOP_status:
++ argsize = sizeof(evtchn_status_t);
++ break;
++
++ default:
++ printk("%s: unknown EVTCHNOP %d\n", __func__, cmd);
++ return -EINVAL;
++ }
++
++ ret = xencomm_create((void *)hypercall->arg[1], argsize,
++ &desc, GFP_KERNEL);
++ if (ret)
++ return ret;
++
++ ret = xencomm_arch_hypercall_event_channel_op(cmd, desc);
++
++ xencomm_free(desc);
++ return ret;
++}
++
++static int
++xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall)
++{
++ int cmd = hypercall->arg[0];
++ struct xencomm_handle *desc;
++ unsigned int argsize;
++ int ret;
++
++ switch (cmd) {
++ case HVMOP_get_param:
++ case HVMOP_set_param:
++ argsize = sizeof(xen_hvm_param_t);
++ break;
++ default:
++ printk("%s: unknown HVMOP %d\n", __func__, cmd);
++ return -EINVAL;
++ }
++
++ ret = xencomm_create((void *)hypercall->arg[1], argsize,
++ &desc, GFP_KERNEL);
++ if (ret)
++ return ret;
++
++ ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
++
++ xencomm_free(desc);
++ return ret;
++}
++
++static int
++xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall)
++{
++ int cmd = hypercall->arg[0];
++ struct xencomm_handle *desc;
++ unsigned int argsize;
++ int ret;
++
++ switch (cmd) {
++ case SCHEDOP_remote_shutdown:
++ argsize = sizeof(sched_remote_shutdown_t);
++ break;
++ default:
++ printk("%s: unknown SCHEDOP %d\n", __func__, cmd);
++ return -EINVAL;
++ }
++
++ ret = xencomm_create((void *)hypercall->arg[1], argsize,
++ &desc, GFP_KERNEL);
++ if (ret)
++ return ret;
++
++ ret = xencomm_arch_hypercall_sched_op(cmd, desc);
++
++ xencomm_free(desc);
++ return ret;
++}
++
++int
++privcmd_hypercall(privcmd_hypercall_t *hypercall)
++{
++ switch (hypercall->op) {
++ case __HYPERVISOR_dom0_op:
++ return xencomm_privcmd_dom0_op(hypercall);
++ case __HYPERVISOR_domctl:
++ return xencomm_privcmd_domctl(hypercall);
++ case __HYPERVISOR_sysctl:
++ return xencomm_privcmd_sysctl(hypercall);
++ case __HYPERVISOR_acm_op:
++ return xencomm_privcmd_acm_op(hypercall);
++ case __HYPERVISOR_xen_version:
++ return xencomm_privcmd_xen_version(hypercall);
++ case __HYPERVISOR_memory_op:
++ return xencomm_privcmd_memory_op(hypercall);
++ case __HYPERVISOR_event_channel_op:
++ return xencomm_privcmd_event_channel_op(hypercall);
++ case __HYPERVISOR_hvm_op:
++ return xencomm_privcmd_hvm_op(hypercall);
++ case __HYPERVISOR_sched_op:
++ return xencomm_privcmd_sched_op(hypercall);
++ default:
++ printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op);
++ return -ENOSYS;
++ }
++}
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xencomm.c linux-2.6.18-xen/arch/ia64/xen/xencomm.c
+--- linux-2.6.18.1/arch/ia64/xen/xencomm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xencomm.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,244 @@
++/*
++ * Copyright (C) 2006 Hollis Blanchard <hollisb at us.ibm.com>, IBM Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/gfp.h>
++#include <linux/mm.h>
++#include <asm/page.h>
++#include <asm/xen/xencomm.h>
++#include <xen/interface/xen.h>
++
++static int xencomm_debug = 0;
++
++/* Translate virtual address to physical address. */
++unsigned long
++xencomm_vaddr_to_paddr(unsigned long vaddr)
++{
++ struct page *page;
++ struct vm_area_struct *vma;
++
++ if (vaddr == 0)
++ return 0;
++
++#ifdef __ia64__
++ if (REGION_NUMBER(vaddr) == 5) {
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *ptep;
++
++ /* On ia64, TASK_SIZE refers to current. It is not initialized
++ during boot.
++ Furthermore the kernel is relocatable and __pa() doesn't
++ work on addresses. */
++ if (vaddr >= KERNEL_START
++ && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) {
++ extern unsigned long kernel_start_pa;
++
++ return vaddr - kernel_start_pa;
++ }
++
++ /* In kernel area -- virtually mapped. */
++ pgd = pgd_offset_k(vaddr);
++ if (pgd_none(*pgd) || pgd_bad(*pgd))
++ return ~0UL;
++
++ pud = pud_offset(pgd, vaddr);
++ if (pud_none(*pud) || pud_bad(*pud))
++ return ~0UL;
++
++ pmd = pmd_offset(pud, vaddr);
++ if (pmd_none(*pmd) || pmd_bad(*pmd))
++ return ~0UL;
++
++ ptep = pte_offset_kernel(pmd, vaddr);
++ if (!ptep)
++ return ~0UL;
++
++ return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK);
++ }
++#endif
++
++ if (vaddr > TASK_SIZE) {
++ /* kernel address */
++ return __pa(vaddr);
++ }
++
++ /* XXX double-check (lack of) locking */
++ vma = find_extend_vma(current->mm, vaddr);
++ if (!vma)
++ return ~0UL;
++
++ /* We assume the page is modified. */
++ page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH);
++ if (!page)
++ return ~0UL;
++
++ return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
++}
++
++static int
++xencomm_init(struct xencomm_desc *desc, void *buffer, unsigned long bytes)
++{
++ unsigned long recorded = 0;
++ int i = 0;
++
++ BUG_ON((buffer == NULL) && (bytes > 0));
++
++ /* record the physical pages used */
++ if (buffer == NULL)
++ desc->nr_addrs = 0;
++
++ while ((recorded < bytes) && (i < desc->nr_addrs)) {
++ unsigned long vaddr = (unsigned long)buffer + recorded;
++ unsigned long paddr;
++ int offset;
++ int chunksz;
++
++ offset = vaddr % PAGE_SIZE; /* handle partial pages */
++ chunksz = min(PAGE_SIZE - offset, bytes - recorded);
++
++ paddr = xencomm_vaddr_to_paddr(vaddr);
++ if (paddr == ~0UL) {
++ printk("%s: couldn't translate vaddr %lx\n",
++ __func__, vaddr);
++ return -EINVAL;
++ }
++
++ desc->address[i++] = paddr;
++ recorded += chunksz;
++ }
++
++ if (recorded < bytes) {
++ printk("%s: could only translate %ld of %ld bytes\n",
++ __func__, recorded, bytes);
++ return -ENOSPC;
++ }
++
++ /* mark remaining addresses invalid (just for safety) */
++ while (i < desc->nr_addrs)
++ desc->address[i++] = XENCOMM_INVALID;
++
++ desc->magic = XENCOMM_MAGIC;
++
++ return 0;
++}
++
++static struct xencomm_desc *
++xencomm_alloc(gfp_t gfp_mask)
++{
++ struct xencomm_desc *desc;
++
++ desc = (struct xencomm_desc *)__get_free_page(gfp_mask);
++ if (desc == NULL)
++ panic("%s: page allocation failed\n", __func__);
++
++ desc->nr_addrs = (PAGE_SIZE - sizeof(struct xencomm_desc)) /
++ sizeof(*desc->address);
++
++ return desc;
++}
++
++void
++xencomm_free(struct xencomm_handle *desc)
++{
++ if (desc)
++ free_page((unsigned long)__va(desc));
++}
++
++int
++xencomm_create(void *buffer, unsigned long bytes,
++ struct xencomm_handle **ret, gfp_t gfp_mask)
++{
++ struct xencomm_desc *desc;
++ struct xencomm_handle *handle;
++ int rc;
++
++ if (xencomm_debug)
++ printk("%s: %p[%ld]\n", __func__, buffer, bytes);
++
++ if (buffer == NULL || bytes == 0) {
++ *ret = (struct xencomm_handle *)NULL;
++ return 0;
++ }
++
++ desc = xencomm_alloc(gfp_mask);
++ if (!desc) {
++ printk("%s failure\n", "xencomm_alloc");
++ return -ENOMEM;
++ }
++ handle = (struct xencomm_handle *)__pa(desc);
++
++ rc = xencomm_init(desc, buffer, bytes);
++ if (rc) {
++ printk("%s failure: %d\n", "xencomm_init", rc);
++ xencomm_free(handle);
++ return rc;
++ }
++
++ *ret = handle;
++ return 0;
++}
++
++/* "mini" routines, for stack-based communications: */
++
++static void *
++xencomm_alloc_mini(struct xencomm_mini *area, int *nbr_area)
++{
++ unsigned long base;
++ unsigned int pageoffset;
++
++ while (*nbr_area >= 0) {
++ /* Allocate an area. */
++ (*nbr_area)--;
++
++ base = (unsigned long)(area + *nbr_area);
++ pageoffset = base % PAGE_SIZE;
++
++ /* If the area does not cross a page, use it. */
++ if ((PAGE_SIZE - pageoffset) >= sizeof(struct xencomm_mini))
++ return &area[*nbr_area];
++ }
++ /* No more area. */
++ return NULL;
++}
++
++int
++xencomm_create_mini(struct xencomm_mini *area, int *nbr_area,
++ void *buffer, unsigned long bytes,
++ struct xencomm_handle **ret)
++{
++ struct xencomm_desc *desc;
++ int rc;
++ unsigned long res;
++
++ desc = xencomm_alloc_mini(area, nbr_area);
++ if (!desc)
++ return -ENOMEM;
++ desc->nr_addrs = XENCOMM_MINI_ADDRS;
++
++ rc = xencomm_init(desc, buffer, bytes);
++ if (rc)
++ return rc;
++
++ res = xencomm_vaddr_to_paddr((unsigned long)desc);
++ if (res == ~0UL)
++ return -EINVAL;
++
++ *ret = (struct xencomm_handle*)res;
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xenentry.S linux-2.6.18-xen/arch/ia64/xen/xenentry.S
+--- linux-2.6.18.1/arch/ia64/xen/xenentry.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xenentry.S 2006-09-04 16:31:01.000000000 +0200
+@@ -0,0 +1,867 @@
++/*
++ * ia64/xen/entry.S
++ *
++ * Alternate kernel routines for Xen. Heavily leveraged from
++ * ia64/kernel/entry.S
++ *
++ * Copyright (C) 2005 Hewlett-Packard Co
++ * Dan Magenheimer <dan.magenheimer at .hp.com>
++ */
++
++#include <asm/asmmacro.h>
++#include <asm/cache.h>
++#include <asm/errno.h>
++#include <asm/kregs.h>
++#include <asm/asm-offsets.h>
++#include <asm/pgtable.h>
++#include <asm/percpu.h>
++#include <asm/processor.h>
++#include <asm/thread_info.h>
++#include <asm/unistd.h>
++
++#ifdef CONFIG_XEN
++#include "xenminstate.h"
++#else
++#include "minstate.h"
++#endif
++
++/*
++ * prev_task <- ia64_switch_to(struct task_struct *next)
++ * With Ingo's new scheduler, interrupts are disabled when this routine gets
++ * called. The code starting at .map relies on this. The rest of the code
++ * doesn't care about the interrupt masking status.
++ */
++#ifdef CONFIG_XEN
++GLOBAL_ENTRY(xen_switch_to)
++ .prologue
++ alloc r16=ar.pfs,1,0,0,0
++ movl r22=running_on_xen;;
++ ld4 r22=[r22];;
++ cmp.eq p7,p0=r22,r0
++(p7) br.cond.sptk.many __ia64_switch_to;;
++#else
++GLOBAL_ENTRY(ia64_switch_to)
++ .prologue
++ alloc r16=ar.pfs,1,0,0,0
++#endif
++ DO_SAVE_SWITCH_STACK
++ .body
++
++ adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13
++ movl r25=init_task
++ mov r27=IA64_KR(CURRENT_STACK)
++ adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
++ dep r20=0,in0,61,3 // physical address of "next"
++ ;;
++ st8 [r22]=sp // save kernel stack pointer of old task
++ shr.u r26=r20,IA64_GRANULE_SHIFT
++ cmp.eq p7,p6=r25,in0
++ ;;
++#ifdef CONFIG_XEN
++ movl r8=XSI_PSR_IC
++ ;;
++ st4 [r8]=r0 // force psr.ic off for hyperprivop(s)
++ ;;
++#endif
++ /*
++ * If we've already mapped this task's page, we can skip doing it again.
++ */
++(p6) cmp.eq p7,p6=r26,r27
++(p6) br.cond.dpnt .map
++ ;;
++.done:
++#ifdef CONFIG_XEN
++ // psr.ic already off
++ // update "current" application register
++ mov r8=IA64_KR_CURRENT
++ mov r9=in0;;
++ XEN_HYPER_SET_KR
++ ld8 sp=[r21] // load kernel stack pointer of new task
++ movl r27=XSI_PSR_IC
++ mov r8=1
++ ;;
++ st4 [r27]=r8 // psr.ic back on
++#else
++ ld8 sp=[r21] // load kernel stack pointer of new task
++ mov IA64_KR(CURRENT)=in0 // update "current" application register
++#endif
++ mov r8=r13 // return pointer to previously running task
++ mov r13=in0 // set "current" pointer
++ ;;
++ DO_LOAD_SWITCH_STACK
++
++#ifdef CONFIG_SMP
++ sync.i // ensure "fc"s done by this CPU are visible on other CPUs
++#endif
++ br.ret.sptk.many rp // boogie on out in new context
++
++.map:
++#ifdef CONFIG_XEN
++ // psr.ic already off
++#else
++ rsm psr.ic // interrupts (psr.i) are already disabled here
++#endif
++ movl r25=PAGE_KERNEL
++ ;;
++ srlz.d
++ or r23=r25,r20 // construct PA | page properties
++ mov r25=IA64_GRANULE_SHIFT<<2
++ ;;
++#ifdef CONFIG_XEN
++ movl r8=XSI_ITIR
++ ;;
++ st8 [r8]=r25
++ ;;
++ movl r8=XSI_IFA
++ ;;
++ st8 [r8]=in0 // VA of next task...
++ ;;
++ mov r25=IA64_TR_CURRENT_STACK
++ // remember last page we mapped...
++ mov r8=IA64_KR_CURRENT_STACK
++ mov r9=r26;;
++ XEN_HYPER_SET_KR;;
++#else
++ mov cr.itir=r25
++ mov cr.ifa=in0 // VA of next task...
++ ;;
++ mov r25=IA64_TR_CURRENT_STACK
++ mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped...
++#endif
++ ;;
++ itr.d dtr[r25]=r23 // wire in new mapping...
++#ifndef CONFIG_XEN
++ ssm psr.ic // reenable the psr.ic bit
++ ;;
++ srlz.d
++#endif
++ br.cond.sptk .done
++#ifdef CONFIG_XEN
++END(xen_switch_to)
++#else
++END(ia64_switch_to)
++#endif
++
++ /*
++ * Invoke a system call, but do some tracing before and after the call.
++ * We MUST preserve the current register frame throughout this routine
++ * because some system calls (such as ia64_execve) directly
++ * manipulate ar.pfs.
++ */
++#ifdef CONFIG_XEN
++GLOBAL_ENTRY(xen_trace_syscall)
++ PT_REGS_UNWIND_INFO(0)
++ movl r16=running_on_xen;;
++ ld4 r16=[r16];;
++ cmp.eq p7,p0=r16,r0
++(p7) br.cond.sptk.many __ia64_trace_syscall;;
++#else
++GLOBAL_ENTRY(ia64_trace_syscall)
++ PT_REGS_UNWIND_INFO(0)
++#endif
++ /*
++ * We need to preserve the scratch registers f6-f11 in case the system
++ * call is sigreturn.
++ */
++ adds r16=PT(F6)+16,sp
++ adds r17=PT(F7)+16,sp
++ ;;
++ stf.spill [r16]=f6,32
++ stf.spill [r17]=f7,32
++ ;;
++ stf.spill [r16]=f8,32
++ stf.spill [r17]=f9,32
++ ;;
++ stf.spill [r16]=f10
++ stf.spill [r17]=f11
++ br.call.sptk.many rp=syscall_trace_enter // give parent a chance to catch syscall args
++ adds r16=PT(F6)+16,sp
++ adds r17=PT(F7)+16,sp
++ ;;
++ ldf.fill f6=[r16],32
++ ldf.fill f7=[r17],32
++ ;;
++ ldf.fill f8=[r16],32
++ ldf.fill f9=[r17],32
++ ;;
++ ldf.fill f10=[r16]
++ ldf.fill f11=[r17]
++ // the syscall number may have changed, so re-load it and re-calculate the
++ // syscall entry-point:
++ adds r15=PT(R15)+16,sp // r15 = &pt_regs.r15 (syscall #)
++ ;;
++ ld8 r15=[r15]
++ mov r3=NR_syscalls - 1
++ ;;
++ adds r15=-1024,r15
++ movl r16=sys_call_table
++ ;;
++ shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024)
++ cmp.leu p6,p7=r15,r3
++ ;;
++(p6) ld8 r20=[r20] // load address of syscall entry point
++(p7) movl r20=sys_ni_syscall
++ ;;
++ mov b6=r20
++ br.call.sptk.many rp=b6 // do the syscall
++.strace_check_retval:
++ cmp.lt p6,p0=r8,r0 // syscall failed?
++ adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8
++ adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10
++ mov r10=0
++(p6) br.cond.sptk strace_error // syscall failed ->
++ ;; // avoid RAW on r10
++.strace_save_retval:
++.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8
++.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10
++ br.call.sptk.many rp=syscall_trace_leave // give parent a chance to catch return value
++.ret3:
++(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
++ br.cond.sptk .work_pending_syscall_end
++
++strace_error:
++ ld8 r3=[r2] // load pt_regs.r8
++ sub r9=0,r8 // negate return value to get errno value
++ ;;
++ cmp.ne p6,p0=r3,r0 // is pt_regs.r8!=0?
++ adds r3=16,r2 // r3=&pt_regs.r10
++ ;;
++(p6) mov r10=-1
++(p6) mov r8=r9
++ br.cond.sptk .strace_save_retval
++#ifdef CONFIG_XEN
++END(xen_trace_syscall)
++#else
++END(ia64_trace_syscall)
++#endif
++
++/*
++ * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't
++ * need to switch to bank 0 and doesn't restore the scratch registers.
++ * To avoid leaking kernel bits, the scratch registers are set to
++ * the following known-to-be-safe values:
++ *
++ * r1: restored (global pointer)
++ * r2: cleared
++ * r3: 1 (when returning to user-level)
++ * r8-r11: restored (syscall return value(s))
++ * r12: restored (user-level stack pointer)
++ * r13: restored (user-level thread pointer)
++ * r14: set to __kernel_syscall_via_epc
++ * r15: restored (syscall #)
++ * r16-r17: cleared
++ * r18: user-level b6
++ * r19: cleared
++ * r20: user-level ar.fpsr
++ * r21: user-level b0
++ * r22: cleared
++ * r23: user-level ar.bspstore
++ * r24: user-level ar.rnat
++ * r25: user-level ar.unat
++ * r26: user-level ar.pfs
++ * r27: user-level ar.rsc
++ * r28: user-level ip
++ * r29: user-level psr
++ * r30: user-level cfm
++ * r31: user-level pr
++ * f6-f11: cleared
++ * pr: restored (user-level pr)
++ * b0: restored (user-level rp)
++ * b6: restored
++ * 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)
++ * ar.rnat: restored (user-level ar.rnat)
++ * ar.bspstore: restored (user-level ar.bspstore)
++ * ar.fpsr: restored (user-level ar.fpsr)
++ * ar.ccv: cleared
++ * ar.csd: cleared
++ * ar.ssd: cleared
++ */
++#ifdef CONFIG_XEN
++GLOBAL_ENTRY(xen_leave_syscall)
++ PT_REGS_UNWIND_INFO(0)
++ movl r22=running_on_xen;;
++ ld4 r22=[r22];;
++ cmp.eq p7,p0=r22,r0
++(p7) br.cond.sptk.many __ia64_leave_syscall;;
++#else
++ENTRY(ia64_leave_syscall)
++ PT_REGS_UNWIND_INFO(0)
++#endif
++ /*
++ * work.need_resched etc. mustn't get changed by this CPU before it returns to
++ * user- or fsys-mode, hence we disable interrupts early on.
++ *
++ * p6 controls whether current_thread_info()->flags needs to be check for
++ * extra work. We always check for extra work when returning to user-level.
++ * With CONFIG_PREEMPT, we also check for extra work when the preempt_count
++ * is 0. After extra work processing has been completed, execution
++ * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check
++ * needs to be redone.
++ */
++#ifdef CONFIG_PREEMPT
++ rsm psr.i // disable interrupts
++ cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall
++(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
++ ;;
++ .pred.rel.mutex pUStk,pKStk
++(pKStk) ld4 r21=[r20] // r21 <- preempt_count
++(pUStk) mov r21=0 // r21 <- 0
++ ;;
++ cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0)
++#else /* !CONFIG_PREEMPT */
++#ifdef CONFIG_XEN
++ movl r2=XSI_PSR_I_ADDR
++ mov r18=1
++ ;;
++ ld8 r2=[r2]
++ ;;
++(pUStk) st1 [r2]=r18
++#else
++(pUStk) rsm psr.i
++#endif
++ cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall
++(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
++#endif
++.work_processed_syscall:
++ adds r2=PT(LOADRS)+16,r12
++ adds r3=PT(AR_BSPSTORE)+16,r12
++ adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
++ ;;
++(p6) ld4 r31=[r18] // load current_thread_info()->flags
++ ld8 r19=[r2],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs"
++ nop.i 0
++ ;;
++ 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?
++ ;;
++ 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)
++(pNonSys) break 0 // bug check: we shouldn't be here if pNonSys is TRUE!
++ ;;
++ invala // M0|1 invalidate ALAT
++#ifdef CONFIG_XEN
++ movl r28=XSI_PSR_I_ADDR
++ movl r29=XSI_PSR_IC
++ ;;
++ ld8 r28=[r28]
++ mov r30=1
++ ;;
++ st1 [r28]=r30
++ st4 [r29]=r0 // note: clears both vpsr.i and vpsr.ic!
++ ;;
++#else
++ rsm psr.i | psr.ic // M2 turn off interrupts and interruption collection
++#endif
++ cmp.eq p9,p0=r0,r0 // A set p9 to indicate that we should restore cr.ifs
++
++ 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
++(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
++ nop 0
++ ;;
++ 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) // 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) // M0|1 load ar.fpsr
++ ld8.fill r1=[r3],16 // M0|1 load r1
++(pUStk) mov r17=1 // A
++ ;;
++(pUStk) st1 [r14]=r17 // M2|3
++ ld8.fill r13=[r3],16 // M0|1
++ mov f8=f0 // F clear f8
++ ;;
++ ld8.fill r12=[r2] // M0|1 restore r12 (sp)
++ ld8.fill r15=[r3] // M0|1 restore r15
++ mov b6=r18 // I0 restore b6
++
++ 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
++#ifdef CONFIG_XEN
++ XEN_HYPER_COVER;
++#else
++ cover // B add current frame into dirty partition & set cr.ifs
++#endif
++ ;;
++(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.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.ssd=r0 // M2 clear ar.ssd
++ mov f11=f0 // F clear f11
++ br.cond.sptk.many rbs_switch // B
++#ifdef CONFIG_XEN
++END(xen_leave_syscall)
++#else
++END(ia64_leave_syscall)
++#endif
++
++#ifdef CONFIG_XEN
++GLOBAL_ENTRY(xen_leave_kernel)
++ PT_REGS_UNWIND_INFO(0)
++ movl r22=running_on_xen;;
++ ld4 r22=[r22];;
++ cmp.eq p7,p0=r22,r0
++(p7) br.cond.sptk.many __ia64_leave_kernel;;
++#else
++GLOBAL_ENTRY(ia64_leave_kernel)
++ PT_REGS_UNWIND_INFO(0)
++#endif
++ /*
++ * work.need_resched etc. mustn't get changed by this CPU before it returns to
++ * user- or fsys-mode, hence we disable interrupts early on.
++ *
++ * p6 controls whether current_thread_info()->flags needs to be check for
++ * extra work. We always check for extra work when returning to user-level.
++ * With CONFIG_PREEMPT, we also check for extra work when the preempt_count
++ * is 0. After extra work processing has been completed, execution
++ * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check
++ * needs to be redone.
++ */
++#ifdef CONFIG_PREEMPT
++ rsm psr.i // disable interrupts
++ cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel
++(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
++ ;;
++ .pred.rel.mutex pUStk,pKStk
++(pKStk) ld4 r21=[r20] // r21 <- preempt_count
++(pUStk) mov r21=0 // r21 <- 0
++ ;;
++ cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0)
++#else
++#ifdef CONFIG_XEN
++(pUStk) movl r17=XSI_PSR_I_ADDR
++(pUStk) mov r31=1
++ ;;
++(pUStk) ld8 r17=[r17]
++ ;;
++(pUStk) st1 [r17]=r31
++ ;;
++#else
++(pUStk) rsm psr.i
++#endif
++ cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel
++(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
++#endif
++.work_processed_kernel:
++ adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
++ ;;
++(p6) ld4 r31=[r17] // load current_thread_info()->flags
++ adds r21=PT(PR)+16,r12
++ ;;
++
++ lfetch [r21],PT(CR_IPSR)-PT(PR)
++ adds r2=PT(B6)+16,r12
++ adds r3=PT(R16)+16,r12
++ ;;
++ lfetch [r21]
++ ld8 r28=[r2],8 // load b6
++ adds r29=PT(R24)+16,r12
++
++ ld8.fill r16=[r3],PT(AR_CSD)-PT(R16)
++ adds r30=PT(AR_CCV)+16,r12
++(p6) and r19=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE?
++ ;;
++ ld8.fill r24=[r29]
++ ld8 r15=[r30] // load ar.ccv
++(p6) cmp4.ne.unc p6,p0=r19, r0 // any special work pending?
++ ;;
++ ld8 r29=[r2],16 // load b7
++ ld8 r30=[r3],16 // load ar.csd
++(p6) br.cond.spnt .work_pending
++ ;;
++ ld8 r31=[r2],16 // load ar.ssd
++ ld8.fill r8=[r3],16
++ ;;
++ ld8.fill r9=[r2],16
++ ld8.fill r10=[r3],PT(R17)-PT(R10)
++ ;;
++ ld8.fill r11=[r2],PT(R18)-PT(R11)
++ ld8.fill r17=[r3],16
++ ;;
++ ld8.fill r18=[r2],16
++ ld8.fill r19=[r3],16
++ ;;
++ ld8.fill r20=[r2],16
++ ld8.fill r21=[r3],16
++ mov ar.csd=r30
++ mov ar.ssd=r31
++ ;;
++#ifdef CONFIG_XEN
++ movl r23=XSI_PSR_I_ADDR
++ movl r22=XSI_PSR_IC
++ ;;
++ ld8 r23=[r23]
++ mov r25=1
++ ;;
++ st1 [r23]=r25
++ st4 [r22]=r0 // note: clears both vpsr.i and vpsr.ic!
++ ;;
++#else
++ rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection
++#endif
++ invala // invalidate ALAT
++ ;;
++ ld8.fill r22=[r2],24
++ ld8.fill r23=[r3],24
++ mov b6=r28
++ ;;
++ ld8.fill r25=[r2],16
++ ld8.fill r26=[r3],16
++ mov b7=r29
++ ;;
++ ld8.fill r27=[r2],16
++ ld8.fill r28=[r3],16
++ ;;
++ ld8.fill r29=[r2],16
++ ld8.fill r30=[r3],24
++ ;;
++ ld8.fill r31=[r2],PT(F9)-PT(R31)
++ adds r3=PT(F10)-PT(F6),r3
++ ;;
++ ldf.fill f9=[r2],PT(F6)-PT(F9)
++ ldf.fill f10=[r3],PT(F8)-PT(F10)
++ ;;
++ ldf.fill f6=[r2],PT(F7)-PT(F6)
++ ;;
++ ldf.fill f7=[r2],PT(F11)-PT(F7)
++ ldf.fill f8=[r3],32
++ ;;
++ 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]
++#ifdef CONFIG_XEN
++ ;;
++ // r16-r31 all now hold bank1 values
++ movl r2=XSI_BANK1_R16
++ movl r3=XSI_BANK1_R16+8
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r16,16
++.mem.offset 8,0; st8.spill [r3]=r17,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r18,16
++.mem.offset 8,0; st8.spill [r3]=r19,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r20,16
++.mem.offset 8,0; st8.spill [r3]=r21,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r22,16
++.mem.offset 8,0; st8.spill [r3]=r23,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r24,16
++.mem.offset 8,0; st8.spill [r3]=r25,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r26,16
++.mem.offset 8,0; st8.spill [r3]=r27,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r28,16
++.mem.offset 8,0; st8.spill [r3]=r29,16
++ ;;
++.mem.offset 0,0; st8.spill [r2]=r30,16
++.mem.offset 8,0; st8.spill [r3]=r31,16
++ ;;
++ movl r2=XSI_BANKNUM;;
++ st4 [r2]=r0;
++#else
++ bsw.0 // switch back to bank 0 (no stop bit required beforehand...)
++#endif
++ ;;
++(pUStk) mov r18=IA64_KR(CURRENT)// M2 (12 cycle read latency)
++ adds r16=PT(CR_IPSR)+16,r12
++ adds r17=PT(CR_IIP)+16,r12
++
++(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
++ nop.i 0
++ nop.i 0
++ ;;
++ ld8 r29=[r16],16 // load cr.ipsr
++ ld8 r28=[r17],16 // load cr.iip
++ ;;
++ ld8 r30=[r16],16 // load cr.ifs
++ ld8 r25=[r17],16 // load ar.unat
++ ;;
++ ld8 r26=[r16],16 // load ar.pfs
++ ld8 r27=[r17],16 // load ar.rsc
++ cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs
++ ;;
++ ld8 r24=[r16],16 // load ar.rnat (may be garbage)
++ ld8 r23=[r17],16 // load ar.bspstore (may be garbage)
++ ;;
++ ld8 r31=[r16],16 // load predicates
++ ld8 r21=[r17],16 // load b0
++ ;;
++ ld8 r19=[r16],16 // load ar.rsc value for "loadrs"
++ ld8.fill r1=[r17],16 // load r1
++ ;;
++ ld8.fill r12=[r16],16
++ ld8.fill r13=[r17],16
++(pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18
++ ;;
++ ld8 r20=[r16],16 // ar.fpsr
++ ld8.fill r15=[r17],16
++ ;;
++ ld8.fill r14=[r16],16
++ ld8.fill r2=[r17]
++(pUStk) mov r17=1
++ ;;
++ ld8.fill r3=[r16]
++(pUStk) st1 [r18]=r17 // restore current->thread.on_ustack
++ shr.u r18=r19,16 // get byte size of existing "dirty" partition
++ ;;
++ mov r16=ar.bsp // get existing backing store pointer
++ addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0
++ ;;
++ ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8
++(pKStk) br.cond.dpnt skip_rbs_switch
++
++ /*
++ * Restore user backing store.
++ *
++ * NOTE: alloc, loadrs, and cover can't be predicated.
++ */
++(pNonSys) br.cond.dpnt dont_preserve_current_frame
++
++#ifdef CONFIG_XEN
++ XEN_HYPER_COVER;
++#else
++ cover // add current frame into dirty partition and set cr.ifs
++#endif
++ ;;
++ 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
++ ;;
++ sub r19=r19,r16 // calculate total byte size of dirty partition
++ add r18=64,r18 // don't force in0-in7 into memory...
++ ;;
++ shl r19=r19,16 // shift size of dirty partition into loadrs position
++ ;;
++dont_preserve_current_frame:
++ /*
++ * To prevent leaking bits between the kernel and user-space,
++ * we must clear the stacked registers in the "invalid" partition here.
++ * Not pretty, but at least it's fast (3.34 registers/cycle on Itanium,
++ * 5 registers/cycle on McKinley).
++ */
++# define pRecurse p6
++# define pReturn p7
++#ifdef CONFIG_ITANIUM
++# define Nregs 10
++#else
++# define Nregs 14
++#endif
++ alloc loc0=ar.pfs,2,Nregs-2,2,0
++ shr.u loc1=r18,9 // RNaTslots <= floor(dirtySize / (64*8))
++ sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize
++ ;;
++ mov ar.rsc=r19 // load ar.rsc to be used for "loadrs"
++ shladd in0=loc1,3,r17
++ mov in1=0
++ ;;
++ TEXT_ALIGN(32)
++rse_clear_invalid:
++#ifdef CONFIG_ITANIUM
++ // cycle 0
++ { .mii
++ alloc loc0=ar.pfs,2,Nregs-2,2,0
++ cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse
++ add out0=-Nregs*8,in0
++}{ .mfb
++ add out1=1,in1 // increment recursion count
++ nop.f 0
++ nop.b 0 // can't do br.call here because of alloc (WAW on CFM)
++ ;;
++}{ .mfi // cycle 1
++ mov loc1=0
++ nop.f 0
++ mov loc2=0
++}{ .mib
++ mov loc3=0
++ mov loc4=0
++(pRecurse) br.call.sptk.many b0=rse_clear_invalid
++
++}{ .mfi // cycle 2
++ mov loc5=0
++ nop.f 0
++ cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret
++}{ .mib
++ mov loc6=0
++ mov loc7=0
++(pReturn) br.ret.sptk.many b0
++}
++#else /* !CONFIG_ITANIUM */
++ alloc loc0=ar.pfs,2,Nregs-2,2,0
++ cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse
++ add out0=-Nregs*8,in0
++ add out1=1,in1 // increment recursion count
++ mov loc1=0
++ mov loc2=0
++ ;;
++ mov loc3=0
++ mov loc4=0
++ mov loc5=0
++ mov loc6=0
++ mov loc7=0
++(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.dptk.many b0
++#endif /* !CONFIG_ITANIUM */
++# undef pRecurse
++# undef pReturn
++ ;;
++ alloc r17=ar.pfs,0,0,0,0 // drop current register frame
++ ;;
++ loadrs
++ ;;
++skip_rbs_switch:
++ mov ar.unat=r25 // M2
++(pKStk) extr.u r22=r22,21,1 // I0 extract current value of psr.pp from r22
++(pLvSys)mov r19=r0 // A clear r19 for leave_syscall, no-op otherwise
++ ;;
++(pUStk) mov ar.bspstore=r23 // M2
++(pKStk) dep r29=r22,r29,21,1 // I0 update ipsr.pp with psr.pp
++(pLvSys)mov r16=r0 // A clear r16 for leave_syscall, no-op otherwise
++ ;;
++#ifdef CONFIG_XEN
++ movl r25=XSI_IPSR
++ ;;
++ st8[r25]=r29,XSI_IFS_OFS-XSI_IPSR_OFS
++ ;;
++#else
++ mov cr.ipsr=r29 // M2
++#endif
++ mov ar.pfs=r26 // I0
++(pLvSys)mov r17=r0 // A clear r17 for leave_syscall, no-op otherwise
++
++#ifdef CONFIG_XEN
++(p9) st8 [r25]=r30
++ ;;
++ adds r25=XSI_IIP_OFS-XSI_IFS_OFS,r25
++ ;;
++#else
++(p9) mov cr.ifs=r30 // M2
++#endif
++ mov b0=r21 // I0
++(pLvSys)mov r18=r0 // A clear r18 for leave_syscall, no-op otherwise
++
++ mov ar.fpsr=r20 // M2
++#ifdef CONFIG_XEN
++ st8 [r25]=r28
++#else
++ mov cr.iip=r28 // M2
++#endif
++ nop 0
++ ;;
++(pUStk) mov ar.rnat=r24 // M2 must happen with RSE in lazy mode
++ nop 0
++(pLvSys)mov r2=r0
++
++ mov ar.rsc=r27 // M2
++ mov pr=r31,-1 // I0
++#ifdef CONFIG_XEN
++ ;;
++ XEN_HYPER_RFI;
++#else
++ rfi // B
++#endif
++
++ /*
++ * On entry:
++ * r20 = ¤t->thread_info->pre_count (if CONFIG_PREEMPT)
++ * r31 = current->thread_info->flags
++ * On exit:
++ * p6 = TRUE if work-pending-check needs to be redone
++ */
++.work_pending_syscall:
++ add r2=-8,r2
++ add r3=-8,r3
++ ;;
++ st8 [r2]=r8
++ st8 [r3]=r10
++.work_pending:
++ tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0?
++(p6) br.cond.sptk.few .notify
++#ifdef CONFIG_PREEMPT
++(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1
++ ;;
++(pKStk) st4 [r20]=r21
++ ssm psr.i // enable interrupts
++#endif
++ br.call.spnt.many rp=schedule
++.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1
++#ifdef CONFIG_XEN
++ movl r2=XSI_PSR_I_ADDR
++ mov r20=1
++ ;;
++ ld8 r2=[r2]
++ ;;
++ st1 [r2]=r20
++#else
++ rsm psr.i // disable interrupts
++#endif
++ ;;
++#ifdef CONFIG_PREEMPT
++(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
++ ;;
++(pKStk) st4 [r20]=r0 // preempt_count() <- 0
++#endif
++(pLvSys)br.cond.sptk.few .work_pending_syscall_end
++ br.cond.sptk.many .work_processed_kernel // re-check
++
++.notify:
++(pUStk) br.call.spnt.many rp=notify_resume_user
++.ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0
++(pLvSys)br.cond.sptk.few .work_pending_syscall_end
++ br.cond.sptk.many .work_processed_kernel // don't re-check
++
++.work_pending_syscall_end:
++ adds r2=PT(R8)+16,r12
++ adds r3=PT(R10)+16,r12
++ ;;
++ ld8 r8=[r2]
++ ld8 r10=[r3]
++ br.cond.sptk.many .work_processed_syscall // re-check
++
++#ifdef CONFIG_XEN
++END(xen_leave_kernel)
++#else
++END(ia64_leave_kernel)
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xenhpski.c linux-2.6.18-xen/arch/ia64/xen/xenhpski.c
+--- linux-2.6.18.1/arch/ia64/xen/xenhpski.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xenhpski.c 2006-09-04 16:31:01.000000000 +0200
+@@ -0,0 +1,19 @@
++
++extern unsigned long xen_get_cpuid(int);
++
++int
++running_on_sim(void)
++{
++ int i;
++ long cpuid[6];
++
++ for (i = 0; i < 5; ++i)
++ cpuid[i] = xen_get_cpuid(i);
++ if ((cpuid[0] & 0xff) != 'H') return 0;
++ if ((cpuid[3] & 0xff) != 0x4) return 0;
++ if (((cpuid[3] >> 8) & 0xff) != 0x0) return 0;
++ if (((cpuid[3] >> 16) & 0xff) != 0x0) return 0;
++ if (((cpuid[3] >> 24) & 0x7) != 0x7) return 0;
++ return 1;
++}
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xenivt.S linux-2.6.18-xen/arch/ia64/xen/xenivt.S
+--- linux-2.6.18.1/arch/ia64/xen/xenivt.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xenivt.S 2006-09-04 16:31:01.000000000 +0200
+@@ -0,0 +1,2169 @@
++/*
++ * arch/ia64/xen/ivt.S
++ *
++ * Copyright (C) 2005 Hewlett-Packard Co
++ * Dan Magenheimer <dan.magenheimer at hp.com>
++ */
++/*
++ * This file defines the interruption vector table used by the CPU.
++ * It does not include one entry per possible cause of interruption.
++ *
++ * The first 20 entries of the table contain 64 bundles each while the
++ * remaining 48 entries contain only 16 bundles each.
++ *
++ * The 64 bundles are used to allow inlining the whole handler for critical
++ * interruptions like TLB misses.
++ *
++ * For each entry, the comment is as follows:
++ *
++ * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51)
++ * entry offset ----/ / / / /
++ * entry number ---------/ / / /
++ * size of the entry -------------/ / /
++ * vector name -------------------------------------/ /
++ * interruptions triggering this vector ----------------------/
++ *
++ * The table is 32KB in size and must be aligned on 32KB boundary.
++ * (The CPU ignores the 15 lower bits of the address)
++ *
++ * Table is based upon EAS2.6 (Oct 1999)
++ */
++
++#include <asm/asmmacro.h>
++#include <asm/break.h>
++#include <asm/ia32.h>
++#include <asm/kregs.h>
++#include <asm/asm-offsets.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/ptrace.h>
++#include <asm/system.h>
++#include <asm/thread_info.h>
++#include <asm/unistd.h>
++#include <asm/errno.h>
++
++#ifdef CONFIG_XEN
++#define ia64_ivt xen_ivt
++#endif
++
++#if 1
++# define PSR_DEFAULT_BITS psr.ac
++#else
++# define PSR_DEFAULT_BITS 0
++#endif
++
++#if 0
++ /*
++ * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't
++ * needed for something else before enabling this...
++ */
++# define DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16
++#else
++# define DBG_FAULT(i)
++#endif
++
++#define MINSTATE_VIRT /* needed by minstate.h */
++#include "xenminstate.h"
++
++#define FAULT(n) \
++ mov r31=pr; \
++ mov r19=n;; /* prepare to save predicates */ \
++ br.sptk.many dispatch_to_fault_handler
++
++ .section .text.ivt,"ax"
++
++ .align 32768 // align on 32KB boundary
++ .global ia64_ivt
++ia64_ivt:
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47)
++ENTRY(vhpt_miss)
++ DBG_FAULT(0)
++ /*
++ * The VHPT vector is invoked when the TLB entry for the virtual page table
++ * is missing. This happens only as a result of a previous
++ * (the "original") TLB miss, which may either be caused by an instruction
++ * fetch or a data access (or non-access).
++ *
++ * What we do here is normal TLB miss handing for the _original_ miss,
++ * followed by inserting the TLB entry for the virtual page table page
++ * that the VHPT walker was attempting to access. The latter gets
++ * inserted as long as page table entry above pte level have valid
++ * mappings for the faulting address. The TLB entry for the original
++ * miss gets inserted only if the pte entry indicates that the page is
++ * present.
++ *
++ * do_page_fault gets invoked in the following cases:
++ * - the faulting virtual address uses unimplemented address bits
++ * - the faulting virtual address has no valid page table mapping
++ */
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++#ifdef CONFIG_HUGETLB_PAGE
++ movl r18=PAGE_SHIFT
++ movl r25=XSI_ITIR
++ ;;
++ ld8 r25=[r25]
++#endif
++ ;;
++#else
++ mov r16=cr.ifa // get address that caused the TLB miss
++#ifdef CONFIG_HUGETLB_PAGE
++ movl r18=PAGE_SHIFT
++ mov r25=cr.itir
++#endif
++#endif
++ ;;
++#ifdef CONFIG_XEN
++ XEN_HYPER_RSM_PSR_DT;
++#else
++ rsm psr.dt // use physical addressing for data
++#endif
++ mov r31=pr // save the predicate registers
++ mov r19=IA64_KR(PT_BASE) // get page table base address
++ shl r21=r16,3 // shift bit 60 into sign bit
++ shr.u r17=r16,61 // get the region number into r17
++ ;;
++ shr.u r22=r21,3
++#ifdef CONFIG_HUGETLB_PAGE
++ extr.u r26=r25,2,6
++ ;;
++ cmp.ne p8,p0=r18,r26
++ sub r27=r26,r18
++ ;;
++(p8) dep r25=r18,r25,2,6
++(p8) shr r22=r22,r27
++#endif
++ ;;
++ cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5?
++ shr.u r18=r22,PGDIR_SHIFT // get bottom portion of pgd index bit
++ ;;
++(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place
++
++ srlz.d
++ LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir
++
++ .pred.rel "mutex", p6, p7
++(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT
++(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3
++ ;;
++(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=pgd_offset for region 5
++(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=pgd_offset for region[0-4]
++ cmp.eq p7,p6=0,r21 // unused address bits all zeroes?
++#ifdef CONFIG_PGTABLE_4
++ shr.u r28=r22,PUD_SHIFT // shift pud index into position
++#else
++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position
++#endif
++ ;;
++ ld8 r17=[r17] // get *pgd (may be 0)
++ ;;
++(p7) cmp.eq p6,p7=r17,r0 // was pgd_present(*pgd) == NULL?
++#ifdef CONFIG_PGTABLE_4
++ dep r28=r28,r17,3,(PAGE_SHIFT-3) // r28=pud_offset(pgd,addr)
++ ;;
++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position
++(p7) ld8 r29=[r28] // get *pud (may be 0)
++ ;;
++(p7) cmp.eq.or.andcm p6,p7=r29,r0 // was pud_present(*pud) == NULL?
++ dep r17=r18,r29,3,(PAGE_SHIFT-3) // r17=pmd_offset(pud,addr)
++#else
++ dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=pmd_offset(pgd,addr)
++#endif
++ ;;
++(p7) ld8 r20=[r17] // get *pmd (may be 0)
++ shr.u r19=r22,PAGE_SHIFT // shift pte index into position
++ ;;
++(p7) cmp.eq.or.andcm p6,p7=r20,r0 // was pmd_present(*pmd) == NULL?
++ dep r21=r19,r20,3,(PAGE_SHIFT-3) // r21=pte_offset(pmd,addr)
++ ;;
++(p7) ld8 r18=[r21] // read *pte
++#ifdef CONFIG_XEN
++ movl r19=XSI_ISR
++ ;;
++ ld8 r19=[r19]
++#else
++ mov r19=cr.isr // cr.isr bit 32 tells us if this is an insn miss
++#endif
++ ;;
++(p7) tbit.z p6,p7=r18,_PAGE_P_BIT // page present bit cleared?
++#ifdef CONFIG_XEN
++ movl r22=XSI_IHA
++ ;;
++ ld8 r22=[r22]
++#else
++ mov r22=cr.iha // get the VHPT address that caused the TLB miss
++#endif
++ ;; // avoid RAW on p7
++(p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss?
++ dep r23=0,r20,0,PAGE_SHIFT // clear low bits to get page address
++ ;;
++#ifdef CONFIG_XEN
++ mov r24=r8
++ mov r8=r18
++ ;;
++(p10) XEN_HYPER_ITC_I
++ ;;
++(p11) XEN_HYPER_ITC_D
++ ;;
++ mov r8=r24
++ ;;
++#else
++(p10) itc.i r18 // insert the instruction TLB entry
++(p11) itc.d r18 // insert the data TLB entry
++#endif
++(p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault)
++#ifdef CONFIG_XEN
++ movl r24=XSI_IFA
++ ;;
++ st8 [r24]=r22
++ ;;
++#else
++ mov cr.ifa=r22
++#endif
++
++#ifdef CONFIG_HUGETLB_PAGE
++(p8) mov cr.itir=r25 // change to default page-size for VHPT
++#endif
++
++ /*
++ * Now compute and insert the TLB entry for the virtual page table. We never
++ * execute in a page table page so there is no need to set the exception deferral
++ * bit.
++ */
++ adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23
++ ;;
++#ifdef CONFIG_XEN
++(p7) mov r25=r8
++(p7) mov r8=r24
++ ;;
++(p7) XEN_HYPER_ITC_D
++ ;;
++(p7) mov r8=r25
++ ;;
++#else
++(p7) itc.d r24
++#endif
++ ;;
++#ifdef CONFIG_SMP
++ /*
++ * Tell the assemblers dependency-violation checker that the above "itc" instructions
++ * cannot possibly affect the following loads:
++ */
++ dv_serialize_data
++
++ /*
++ * Re-check pagetable entry. If they changed, we may have received a ptc.g
++ * between reading the pagetable and the "itc". If so, flush the entry we
++ * inserted and retry. At this point, we have:
++ *
++ * r28 = equivalent of pud_offset(pgd, ifa)
++ * r17 = equivalent of pmd_offset(pud, ifa)
++ * r21 = equivalent of pte_offset(pmd, ifa)
++ *
++ * r29 = *pud
++ * r20 = *pmd
++ * r18 = *pte
++ */
++ ld8 r25=[r21] // read *pte again
++ ld8 r26=[r17] // read *pmd again
++#ifdef CONFIG_PGTABLE_4
++ ld8 r19=[r28] // read *pud again
++#endif
++ cmp.ne p6,p7=r0,r0
++ ;;
++ cmp.ne.or.andcm p6,p7=r26,r20 // did *pmd change
++#ifdef CONFIG_PGTABLE_4
++ cmp.ne.or.andcm p6,p7=r19,r29 // did *pud change
++#endif
++ mov r27=PAGE_SHIFT<<2
++ ;;
++(p6) ptc.l r22,r27 // purge PTE page translation
++(p7) cmp.ne.or.andcm p6,p7=r25,r18 // did *pte change
++ ;;
++(p6) ptc.l r16,r27 // purge translation
++#endif
++
++ mov pr=r31,-1 // restore predicate registers
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI
++ dv_serialize_data
++#else
++ rfi
++#endif
++END(vhpt_miss)
++
++ .org ia64_ivt+0x400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x0400 Entry 1 (size 64 bundles) ITLB (21)
++ENTRY(itlb_miss)
++ DBG_FAULT(1)
++ /*
++ * The ITLB handler accesses the PTE via the virtually mapped linear
++ * page table. If a nested TLB miss occurs, we switch into physical
++ * mode, walk the page table, and then re-execute the PTE read and
++ * go on normally after that.
++ */
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++#else
++ mov r16=cr.ifa // get virtual address
++#endif
++ mov r29=b0 // save b0
++ mov r31=pr // save predicates
++.itlb_fault:
++#ifdef CONFIG_XEN
++ movl r17=XSI_IHA
++ ;;
++ ld8 r17=[r17] // get virtual address of L3 PTE
++#else
++ mov r17=cr.iha // get virtual address of PTE
++#endif
++ movl r30=1f // load nested fault continuation point
++ ;;
++1: ld8 r18=[r17] // read *pte
++ ;;
++ mov b0=r29
++ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared?
++(p6) br.cond.spnt page_fault
++ ;;
++#ifdef CONFIG_XEN
++ mov r19=r8
++ mov r8=r18
++ ;;
++ XEN_HYPER_ITC_I
++ ;;
++ mov r8=r19
++#else
++ itc.i r18
++#endif
++ ;;
++#ifdef CONFIG_SMP
++ /*
++ * Tell the assemblers dependency-violation checker that the above "itc" instructions
++ * cannot possibly affect the following loads:
++ */
++ dv_serialize_data
++
++ ld8 r19=[r17] // read *pte again and see if same
++ mov r20=PAGE_SHIFT<<2 // setup page size for purge
++ ;;
++ cmp.ne p7,p0=r18,r19
++ ;;
++(p7) ptc.l r16,r20
++#endif
++ mov pr=r31,-1
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI
++ dv_serialize_data
++#else
++ rfi
++#endif
++END(itlb_miss)
++
++ .org ia64_ivt+0x0800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48)
++ENTRY(dtlb_miss)
++ DBG_FAULT(2)
++ /*
++ * The DTLB handler accesses the PTE via the virtually mapped linear
++ * page table. If a nested TLB miss occurs, we switch into physical
++ * mode, walk the page table, and then re-execute the PTE read and
++ * go on normally after that.
++ */
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++#else
++ mov r16=cr.ifa // get virtual address
++#endif
++ mov r29=b0 // save b0
++ mov r31=pr // save predicates
++dtlb_fault:
++#ifdef CONFIG_XEN
++ movl r17=XSI_IHA
++ ;;
++ ld8 r17=[r17] // get virtual address of L3 PTE
++#else
++ mov r17=cr.iha // get virtual address of PTE
++#endif
++ movl r30=1f // load nested fault continuation point
++ ;;
++1: ld8 r18=[r17] // read *pte
++ ;;
++ mov b0=r29
++ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared?
++(p6) br.cond.spnt page_fault
++ ;;
++#ifdef CONFIG_XEN
++ mov r19=r8
++ mov r8=r18
++ ;;
++ XEN_HYPER_ITC_D
++ ;;
++ mov r8=r19
++ ;;
++#else
++ itc.d r18
++#endif
++ ;;
++#ifdef CONFIG_SMP
++ /*
++ * Tell the assemblers dependency-violation checker that the above "itc" instructions
++ * cannot possibly affect the following loads:
++ */
++ dv_serialize_data
++
++ ld8 r19=[r17] // read *pte again and see if same
++ mov r20=PAGE_SHIFT<<2 // setup page size for purge
++ ;;
++ cmp.ne p7,p0=r18,r19
++ ;;
++(p7) ptc.l r16,r20
++#endif
++ mov pr=r31,-1
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI
++ dv_serialize_data
++#else
++ rfi
++#endif
++END(dtlb_miss)
++
++ .org ia64_ivt+0x0c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19)
++ENTRY(alt_itlb_miss)
++ DBG_FAULT(3)
++#ifdef CONFIG_XEN
++ movl r31=XSI_IPSR
++ ;;
++ ld8 r21=[r31],XSI_IFA_OFS-XSI_IPSR_OFS // get ipsr, point to ifa
++ movl r17=PAGE_KERNEL
++ ;;
++ ld8 r16=[r31] // get ifa
++#else
++ mov r16=cr.ifa // get address that caused the TLB miss
++ movl r17=PAGE_KERNEL
++ mov r21=cr.ipsr
++#endif
++ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
++ mov r31=pr
++ ;;
++#ifdef CONFIG_DISABLE_VHPT
++ shr.u r22=r16,61 // get the region number into r21
++ ;;
++ cmp.gt p8,p0=6,r22 // user mode
++ ;;
++#ifndef CONFIG_XEN
++(p8) thash r17=r16
++ ;;
++(p8) mov cr.iha=r17
++#endif
++(p8) mov r29=b0 // save b0
++(p8) br.cond.dptk .itlb_fault
++#endif
++ extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
++ and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
++ shr.u r18=r16,57 // move address bit 61 to bit 4
++ ;;
++ andcm r18=0x10,r18 // bit 4=~address-bit(61)
++ cmp.ne p8,p0=r0,r23 // psr.cpl != 0?
++ or r19=r17,r19 // insert PTE control bits into r19
++ ;;
++ or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6
++(p8) br.cond.spnt page_fault
++ ;;
++#ifdef CONFIG_XEN
++ mov r18=r8
++ mov r8=r19
++ ;;
++ XEN_HYPER_ITC_I
++ ;;
++ mov r8=r18
++ ;;
++ mov pr=r31,-1
++ ;;
++ XEN_HYPER_RFI;
++#else
++ itc.i r19 // insert the TLB entry
++ mov pr=r31,-1
++ rfi
++#endif
++END(alt_itlb_miss)
++
++ .org ia64_ivt+0x1000
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46)
++ENTRY(alt_dtlb_miss)
++ DBG_FAULT(4)
++#ifdef CONFIG_XEN
++ movl r31=XSI_IPSR
++ ;;
++ ld8 r21=[r31],XSI_ISR_OFS-XSI_IPSR_OFS // get ipsr, point to isr
++ movl r17=PAGE_KERNEL
++ ;;
++ ld8 r20=[r31],XSI_IFA_OFS-XSI_ISR_OFS // get isr, point to ifa
++ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
++ ;;
++ ld8 r16=[r31] // get ifa
++#else
++ mov r16=cr.ifa // get address that caused the TLB miss
++ movl r17=PAGE_KERNEL
++ mov r20=cr.isr
++ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
++ mov r21=cr.ipsr
++#endif
++ mov r31=pr
++ ;;
++#ifdef CONFIG_DISABLE_VHPT
++ shr.u r22=r16,61 // get the region number into r21
++ ;;
++ cmp.gt p8,p0=6,r22 // access to region 0-5
++ ;;
++#ifndef CONFIG_XEN
++(p8) thash r17=r16
++ ;;
++(p8) mov cr.iha=r17
++#endif
++(p8) mov r29=b0 // save b0
++(p8) br.cond.dptk dtlb_fault
++#endif
++ extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
++ and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field
++ tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on?
++ shr.u r18=r16,57 // move address bit 61 to bit 4
++ and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
++ tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on?
++ ;;
++ andcm r18=0x10,r18 // bit 4=~address-bit(61)
++ cmp.ne p8,p0=r0,r23
++(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field
++(p8) br.cond.spnt page_fault
++
++ dep r21=-1,r21,IA64_PSR_ED_BIT,1
++ or r19=r19,r17 // insert PTE control bits into r19
++ ;;
++ or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6
++(p6) mov cr.ipsr=r21
++ ;;
++#ifdef CONFIG_XEN
++(p7) mov r18=r8
++(p7) mov r8=r19
++ ;;
++(p7) XEN_HYPER_ITC_D
++ ;;
++(p7) mov r8=r18
++ ;;
++ mov pr=r31,-1
++ ;;
++ XEN_HYPER_RFI;
++#else
++(p7) itc.d r19 // insert the TLB entry
++ mov pr=r31,-1
++ rfi
++#endif
++END(alt_dtlb_miss)
++
++ .org ia64_ivt+0x1400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45)
++ENTRY(nested_dtlb_miss)
++ /*
++ * In the absence of kernel bugs, we get here when the virtually mapped linear
++ * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction
++ * Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page
++ * table is missing, a nested TLB miss fault is triggered and control is
++ * transferred to this point. When this happens, we lookup the pte for the
++ * faulting address by walking the page table in physical mode and return to the
++ * continuation point passed in register r30 (or call page_fault if the address is
++ * not mapped).
++ *
++ * Input: r16: faulting address
++ * r29: saved b0
++ * r30: continuation address
++ * r31: saved pr
++ *
++ * Output: r17: physical address of PTE of faulting address
++ * r29: saved b0
++ * r30: continuation address
++ * r31: saved pr
++ *
++ * Clobbered: b0, r18, r19, r21, r22, psr.dt (cleared)
++ */
++#ifdef CONFIG_XEN
++ XEN_HYPER_RSM_PSR_DT;
++#else
++ rsm psr.dt // switch to using physical data addressing
++#endif
++ mov r19=IA64_KR(PT_BASE) // get the page table base address
++ shl r21=r16,3 // shift bit 60 into sign bit
++#ifdef CONFIG_XEN
++ movl r18=XSI_ITIR
++ ;;
++ ld8 r18=[r18]
++#else
++ mov r18=cr.itir
++#endif
++ ;;
++ shr.u r17=r16,61 // get the region number into r17
++ extr.u r18=r18,2,6 // get the faulting page size
++ ;;
++ cmp.eq p6,p7=5,r17 // is faulting address in region 5?
++ add r22=-PAGE_SHIFT,r18 // adjustment for hugetlb address
++ add r18=PGDIR_SHIFT-PAGE_SHIFT,r18
++ ;;
++ shr.u r22=r16,r22
++ shr.u r18=r16,r18
++(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place
++
++ srlz.d
++ LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir
++
++ .pred.rel "mutex", p6, p7
++(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT
++(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3
++ ;;
++(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=pgd_offset for region 5
++(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=pgd_offset for region[0-4]
++ cmp.eq p7,p6=0,r21 // unused address bits all zeroes?
++#ifdef CONFIG_PGTABLE_4
++ shr.u r18=r22,PUD_SHIFT // shift pud index into position
++#else
++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position
++#endif
++ ;;
++ ld8 r17=[r17] // get *pgd (may be 0)
++ ;;
++(p7) cmp.eq p6,p7=r17,r0 // was pgd_present(*pgd) == NULL?
++ dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=p[u|m]d_offset(pgd,addr)
++ ;;
++#ifdef CONFIG_PGTABLE_4
++(p7) ld8 r17=[r17] // get *pud (may be 0)
++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position
++ ;;
++(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was pud_present(*pud) == NULL?
++ dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=pmd_offset(pud,addr)
++ ;;
++#endif
++(p7) ld8 r17=[r17] // get *pmd (may be 0)
++ shr.u r19=r22,PAGE_SHIFT // shift pte index into position
++ ;;
++(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was pmd_present(*pmd) == NULL?
++ dep r17=r19,r17,3,(PAGE_SHIFT-3) // r17=pte_offset(pmd,addr);
++(p6) br.cond.spnt page_fault
++ mov b0=r30
++ br.sptk.many b0 // return to continuation point
++END(nested_dtlb_miss)
++
++ .org ia64_ivt+0x1800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24)
++ENTRY(ikey_miss)
++ DBG_FAULT(6)
++ FAULT(6)
++END(ikey_miss)
++
++ //-----------------------------------------------------------------------------------
++ // call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address)
++ENTRY(page_fault)
++#ifdef CONFIG_XEN
++ XEN_HYPER_SSM_PSR_DT
++#else
++ ssm psr.dt
++ ;;
++ srlz.i
++#endif
++ ;;
++ SAVE_MIN_WITH_COVER
++ alloc r15=ar.pfs,0,0,3,0
++#ifdef CONFIG_XEN
++ movl r3=XSI_ISR
++ ;;
++ ld8 out1=[r3],XSI_IFA_OFS-XSI_ISR_OFS // get vcr.isr, point to ifa
++ ;;
++ ld8 out0=[r3] // get vcr.ifa
++ mov r14=1
++ ;;
++ add r3=XSI_PSR_IC_OFS-XSI_IFA_OFS, r3 // point to vpsr.ic
++ ;;
++ st4 [r3]=r14 // vpsr.ic = 1
++ adds r3=8,r2 // set up second base pointer
++ ;;
++#else
++ mov out0=cr.ifa
++ mov out1=cr.isr
++ adds r3=8,r2 // set up second base pointer
++ ;;
++ ssm psr.ic | PSR_DEFAULT_BITS
++ ;;
++ srlz.i // guarantee that interruption collectin is on
++ ;;
++#endif
++#ifdef CONFIG_XEN
++ br.cond.sptk.many xen_page_fault
++ ;;
++done_xen_page_fault:
++#endif
++(p15) ssm psr.i // restore psr.i
++ movl r14=ia64_leave_kernel
++ ;;
++ SAVE_REST
++ mov rp=r14
++ ;;
++ adds out2=16,r12 // out2 = pointer to pt_regs
++ br.call.sptk.many b6=ia64_do_page_fault // ignore return address
++END(page_fault)
++
++ .org ia64_ivt+0x1c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51)
++ENTRY(dkey_miss)
++ DBG_FAULT(7)
++ FAULT(7)
++#ifdef CONFIG_XEN
++ // Leaving this code inline above results in an IVT section overflow
++ // There is no particular reason for this code to be here...
++xen_page_fault:
++(p15) movl r3=XSI_PSR_I_ADDR
++ ;;
++(p15) ld8 r3=[r3]
++ ;;
++(p15) st1 [r3]=r0,XSI_PEND_OFS-XSI_PSR_I_ADDR_OFS // if (p15) vpsr.i = 1
++ mov r14=r0
++ ;;
++(p15) ld4 r14=[r3] // if (pending_interrupts)
++ adds r3=8,r2 // re-set up second base pointer
++ ;;
++(p15) cmp.ne p15,p0=r14,r0
++ ;;
++ br.cond.sptk.many done_xen_page_fault
++ ;;
++#endif
++END(dkey_miss)
++
++ .org ia64_ivt+0x2000
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54)
++ENTRY(dirty_bit)
++ DBG_FAULT(8)
++ /*
++ * What we do here is to simply turn on the dirty bit in the PTE. We need to
++ * update both the page-table and the TLB entry. To efficiently access the PTE,
++ * we address it through the virtual page table. Most likely, the TLB entry for
++ * the relevant virtual page table page is still present in the TLB so we can
++ * normally do this without additional TLB misses. In case the necessary virtual
++ * page table TLB entry isn't present, we take a nested TLB miss hit where we look
++ * up the physical address of the L3 PTE and then continue at label 1 below.
++ */
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++ ;;
++#else
++ mov r16=cr.ifa // get the address that caused the fault
++#endif
++ movl r30=1f // load continuation point in case of nested fault
++ ;;
++#ifdef CONFIG_XEN
++ mov r18=r8;
++ mov r8=r16;
++ XEN_HYPER_THASH;;
++ mov r17=r8;
++ mov r8=r18;;
++#else
++ thash r17=r16 // compute virtual address of L3 PTE
++#endif
++ mov r29=b0 // save b0 in case of nested fault
++ mov r31=pr // save pr
++#ifdef CONFIG_SMP
++ mov r28=ar.ccv // save ar.ccv
++ ;;
++1: ld8 r18=[r17]
++ ;; // avoid RAW on r18
++ mov ar.ccv=r18 // set compare value for cmpxchg
++ or r25=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits
++ tbit.z p7,p6 = r18,_PAGE_P_BIT // Check present bit
++ ;;
++(p6) cmpxchg8.acq r26=[r17],r25,ar.ccv // Only update if page is present
++ mov r24=PAGE_SHIFT<<2
++ ;;
++(p6) cmp.eq p6,p7=r26,r18 // Only compare if page is present
++ ;;
++#ifdef CONFIG_XEN
++(p6) mov r18=r8
++(p6) mov r8=r25
++ ;;
++(p6) XEN_HYPER_ITC_D
++ ;;
++(p6) mov r8=r18
++#else
++(p6) itc.d r25 // install updated PTE
++#endif
++ ;;
++ /*
++ * Tell the assemblers dependency-violation checker that the above "itc" instructions
++ * cannot possibly affect the following loads:
++ */
++ dv_serialize_data
++
++ ld8 r18=[r17] // read PTE again
++ ;;
++ cmp.eq p6,p7=r18,r25 // is it same as the newly installed
++ ;;
++(p7) ptc.l r16,r24
++ mov b0=r29 // restore b0
++ mov ar.ccv=r28
++#else
++ ;;
++1: ld8 r18=[r17]
++ ;; // avoid RAW on r18
++ or r18=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits
++ mov b0=r29 // restore b0
++ ;;
++ st8 [r17]=r18 // store back updated PTE
++ itc.d r18 // install updated PTE
++#endif
++ mov pr=r31,-1 // restore pr
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI
++ dv_serialize_data
++#else
++ rfi
++#endif
++END(dirty_bit)
++
++ .org ia64_ivt+0x2400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27)
++ENTRY(iaccess_bit)
++ DBG_FAULT(9)
++ // Like Entry 8, except for instruction access
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++ ;;
++#else
++ mov r16=cr.ifa // get the address that caused the fault
++#endif
++ movl r30=1f // load continuation point in case of nested fault
++ mov r31=pr // save predicates
++#ifdef CONFIG_ITANIUM
++ /*
++ * Erratum 10 (IFA may contain incorrect address) has "NoFix" status.
++ */
++ mov r17=cr.ipsr
++ ;;
++ mov r18=cr.iip
++ tbit.z p6,p0=r17,IA64_PSR_IS_BIT // IA64 instruction set?
++ ;;
++(p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa
++#endif /* CONFIG_ITANIUM */
++ ;;
++#ifdef CONFIG_XEN
++ mov r18=r8;
++ mov r8=r16;
++ XEN_HYPER_THASH;;
++ mov r17=r8;
++ mov r8=r18;;
++#else
++ thash r17=r16 // compute virtual address of L3 PTE
++#endif
++ mov r29=b0 // save b0 in case of nested fault)
++#ifdef CONFIG_SMP
++ mov r28=ar.ccv // save ar.ccv
++ ;;
++1: ld8 r18=[r17]
++ ;;
++ mov ar.ccv=r18 // set compare value for cmpxchg
++ or r25=_PAGE_A,r18 // set the accessed bit
++ tbit.z p7,p6 = r18,_PAGE_P_BIT // Check present bit
++ ;;
++(p6) cmpxchg8.acq r26=[r17],r25,ar.ccv // Only if page present
++ mov r24=PAGE_SHIFT<<2
++ ;;
++(p6) cmp.eq p6,p7=r26,r18 // Only if page present
++ ;;
++#ifdef CONFIG_XEN
++ mov r26=r8
++ mov r8=r25
++ ;;
++(p6) XEN_HYPER_ITC_I
++ ;;
++ mov r8=r26
++ ;;
++#else
++(p6) itc.i r25 // install updated PTE
++#endif
++ ;;
++ /*
++ * Tell the assemblers dependency-violation checker that the above "itc" instructions
++ * cannot possibly affect the following loads:
++ */
++ dv_serialize_data
++
++ ld8 r18=[r17] // read PTE again
++ ;;
++ cmp.eq p6,p7=r18,r25 // is it same as the newly installed
++ ;;
++(p7) ptc.l r16,r24
++ mov b0=r29 // restore b0
++ mov ar.ccv=r28
++#else /* !CONFIG_SMP */
++ ;;
++1: ld8 r18=[r17]
++ ;;
++ or r18=_PAGE_A,r18 // set the accessed bit
++ mov b0=r29 // restore b0
++ ;;
++ st8 [r17]=r18 // store back updated PTE
++ itc.i r18 // install updated PTE
++#endif /* !CONFIG_SMP */
++ mov pr=r31,-1
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI
++ dv_serialize_data
++#else
++ rfi
++#endif
++END(iaccess_bit)
++
++ .org ia64_ivt+0x2800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55)
++ENTRY(daccess_bit)
++ DBG_FAULT(10)
++ // Like Entry 8, except for data access
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++ ;;
++#else
++ mov r16=cr.ifa // get the address that caused the fault
++#endif
++ movl r30=1f // load continuation point in case of nested fault
++ ;;
++#ifdef CONFIG_XEN
++ mov r18=r8
++ mov r8=r16
++ XEN_HYPER_THASH
++ ;;
++ mov r17=r8
++ mov r8=r18
++ ;;
++#else
++ thash r17=r16 // compute virtual address of L3 PTE
++#endif
++ mov r31=pr
++ mov r29=b0 // save b0 in case of nested fault)
++#ifdef CONFIG_SMP
++ mov r28=ar.ccv // save ar.ccv
++ ;;
++1: ld8 r18=[r17]
++ ;; // avoid RAW on r18
++ mov ar.ccv=r18 // set compare value for cmpxchg
++ or r25=_PAGE_A,r18 // set the dirty bit
++ tbit.z p7,p6 = r18,_PAGE_P_BIT // Check present bit
++ ;;
++(p6) cmpxchg8.acq r26=[r17],r25,ar.ccv // Only if page is present
++ mov r24=PAGE_SHIFT<<2
++ ;;
++(p6) cmp.eq p6,p7=r26,r18 // Only if page is present
++ ;;
++#ifdef CONFIG_XEN
++ mov r26=r8
++ mov r8=r25
++ ;;
++(p6) XEN_HYPER_ITC_D
++ ;;
++ mov r8=r26
++ ;;
++#else
++(p6) itc.d r25 // install updated PTE
++#endif
++ /*
++ * Tell the assemblers dependency-violation checker that the above "itc" instructions
++ * cannot possibly affect the following loads:
++ */
++ dv_serialize_data
++ ;;
++ ld8 r18=[r17] // read PTE again
++ ;;
++ cmp.eq p6,p7=r18,r25 // is it same as the newly installed
++ ;;
++(p7) ptc.l r16,r24
++ mov ar.ccv=r28
++#else
++ ;;
++1: ld8 r18=[r17]
++ ;; // avoid RAW on r18
++ or r18=_PAGE_A,r18 // set the accessed bit
++ ;;
++ st8 [r17]=r18 // store back updated PTE
++ itc.d r18 // install updated PTE
++#endif
++ mov b0=r29 // restore b0
++ mov pr=r31,-1
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI
++ dv_serialize_data
++#else
++ rfi
++#endif
++END(daccess_bit)
++
++ .org ia64_ivt+0x2c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33)
++ENTRY(break_fault)
++ /*
++ * The streamlined system call entry/exit paths only save/restore the initial part
++ * of pt_regs. This implies that the callers of system-calls must adhere to the
++ * normal procedure calling conventions.
++ *
++ * Registers to be saved & restored:
++ * CR registers: cr.ipsr, cr.iip, cr.ifs
++ * AR registers: ar.unat, ar.pfs, ar.rsc, ar.rnat, ar.bspstore, ar.fpsr
++ * others: pr, b0, b6, loadrs, r1, r11, r12, r13, r15
++ * Registers to be restored only:
++ * r8-r11: output value from the system call.
++ *
++ * During system call exit, scratch registers (including r15) are modified/cleared
++ * to prevent leaking bits from kernel to user level.
++ */
++ DBG_FAULT(11)
++ mov.m r16=IA64_KR(CURRENT) // M2 r16 <- current task (12 cyc)
++#ifdef CONFIG_XEN
++ movl r22=XSI_IPSR
++ ;;
++ ld8 r29=[r22],XSI_IIM_OFS-XSI_IPSR_OFS // get ipsr, point to iip
++#else
++ mov r29=cr.ipsr // M2 (12 cyc)
++#endif
++ mov r31=pr // I0 (2 cyc)
++
++#ifdef CONFIG_XEN
++ ;;
++ ld8 r17=[r22],XSI_IIP_OFS-XSI_IIM_OFS
++#else
++ mov r17=cr.iim // M2 (2 cyc)
++#endif
++ 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
++
++#ifdef CONFIG_XEN
++ ld8 r28=[r22]
++#else
++ mov r28=cr.iip // M2 (2 cyc)
++#endif
++ 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 = ¤t_thread_info()->flags
++
++ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16
++ adds r15=-1024,r15 // A subtract 1024 from syscall number
++ mov r3=NR_syscalls - 1
++ ;;
++ 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?
++ ;;
++
++ 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?
++
++ mov.m ar.bspstore=r22 // M2 switch to kernel RBS
++ cmp.eq p8,p9=2,r8 // A isr.ei==2?
++ ;;
++
++(p8) mov r8=0 // A clear ei to 0
++(p7) movl r30=sys_ni_syscall // X
++
++(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
++ ;;
++
++ 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
++#ifdef CONFIG_XEN
++ mov r2=b0; br.call.sptk b0=xen_bsw1;; mov b0=r2;;
++#else
++ bsw.1 // B (6 cyc) regs are saved, switch to bank 1
++#endif
++ ;;
++
++#ifdef CONFIG_XEN
++ movl r16=XSI_PSR_IC
++ mov r3=1
++ ;;
++ st4 [r16]=r3,XSI_PSR_I_ADDR_OFS-XSI_PSR_IC_OFS // vpsr.ic = 1
++#else
++ ssm psr.ic | PSR_DEFAULT_BITS // M2 now it's safe to re-enable intr.-collection
++#endif
++ movl r3=ia64_ret_from_syscall // X
++ ;;
++
++ 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
++
++#ifdef CONFIG_XEN
++(p15) ld8 r16=[r16] // vpsr.i
++ ;;
++(p15) st1 [r16]=r0,XSI_PEND_OFS-XSI_PSR_I_ADDR_OFS // if (p15) vpsr.i = 1
++ mov r2=r0
++ ;;
++(p15) ld4 r2=[r16] // if (pending_interrupts)
++ ;;
++ cmp.ne p6,p0=r2,r0
++ ;;
++(p6) ssm psr.i // do a real ssm psr.i
++#else
++(p15) ssm psr.i // M2 restore psr.i
++#endif
++(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
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4)
++ENTRY(interrupt)
++ DBG_FAULT(12)
++ mov r31=pr // prepare to save predicates
++ ;;
++ SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3
++#ifdef CONFIG_XEN
++ movl r3=XSI_PSR_IC
++ mov r14=1
++ ;;
++ st4 [r3]=r14
++#else
++ ssm psr.ic | PSR_DEFAULT_BITS
++#endif
++ ;;
++ adds r3=8,r2 // set up second base pointer for SAVE_REST
++ srlz.i // ensure everybody knows psr.ic is back on
++ ;;
++ SAVE_REST
++ ;;
++ alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group
++#ifdef CONFIG_XEN
++ ;;
++ br.call.sptk.many rp=xen_get_ivr
++ ;;
++ mov out0=r8 // pass cr.ivr as first arg
++#else
++ mov out0=cr.ivr // pass cr.ivr as first arg
++#endif
++ add out1=16,sp // pass pointer to pt_regs as second arg
++ ;;
++ srlz.d // make sure we see the effect of cr.ivr
++ movl r14=ia64_leave_kernel
++ ;;
++ mov rp=r14
++ br.call.sptk.many b6=ia64_handle_irq
++END(interrupt)
++
++ .org ia64_ivt+0x3400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x3400 Entry 13 (size 64 bundles) Reserved
++ DBG_FAULT(13)
++ FAULT(13)
++
++ .org ia64_ivt+0x3800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x3800 Entry 14 (size 64 bundles) Reserved
++ DBG_FAULT(14)
++ FAULT(14)
++
++ /*
++ * There is no particular reason for this code to be here, other than that
++ * there happens to be space here that would go unused otherwise. If this
++ * fault ever gets "unreserved", simply moved the following code to a more
++ * suitable spot...
++ *
++ * ia64_syscall_setup() is a separate subroutine so that it can
++ * allocate stacked registers so it can safely demine any
++ * potential NaT values from the input registers.
++ *
++ * On entry:
++ * - executing on bank 0 or bank 1 register set (doesn't matter)
++ * - r1: stack pointer
++ * - r2: current task pointer
++ * - r3: preserved
++ * - r11: original contents (saved ar.pfs to be saved)
++ * - r12: original contents (sp to be saved)
++ * - r13: original contents (tp to be saved)
++ * - r15: original contents (syscall # to be saved)
++ * - r18: saved bsp (after switching to kernel stack)
++ * - r19: saved b6
++ * - r20: saved r1 (gp)
++ * - r21: saved ar.fpsr
++ * - r22: kernel's register backing store base (krbs_base)
++ * - r23: saved ar.bspstore
++ * - r24: saved ar.rnat
++ * - r25: saved ar.unat
++ * - r26: saved ar.pfs
++ * - r27: saved ar.rsc
++ * - r28: saved cr.iip
++ * - r29: saved cr.ipsr
++ * - r31: saved pr
++ * - b0: original contents (to be saved)
++ * On exit:
++ * - p10: TRUE if syscall is invoked with more than 8 out
++ * registers or r15's Nat is true
++ * - r1: kernel's gp
++ * - r3: preserved (same as on entry)
++ * - 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)
++ */
++#ifndef CONFIG_XEN
++GLOBAL_ENTRY(ia64_syscall_setup)
++#if PT(B6) != 0
++# error This code assumes that b6 is the first field in pt_regs.
++#endif
++ st8 [r1]=r19 // save b6
++ add r16=PT(CR_IPSR),r1 // initialize first base pointer
++ add r17=PT(R11),r1 // initialize second base pointer
++ ;;
++ alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable
++ st8 [r16]=r29,PT(AR_PFS)-PT(CR_IPSR) // save cr.ipsr
++ tnat.nz p8,p0=in0
++
++ st8.spill [r17]=r11,PT(CR_IIP)-PT(R11) // save r11
++ tnat.nz p9,p0=in1
++(pKStk) mov r18=r0 // make sure r18 isn't NaT
++ ;;
++
++ st8 [r16]=r26,PT(CR_IFS)-PT(AR_PFS) // save ar.pfs
++ st8 [r17]=r28,PT(AR_UNAT)-PT(CR_IIP) // save cr.iip
++ mov r28=b0 // save b0 (2 cyc)
++ ;;
++
++ st8 [r17]=r25,PT(AR_RSC)-PT(AR_UNAT) // save ar.unat
++ dep r19=0,r19,38,26 // clear all bits but 0..37 [I0]
++(p8) mov in0=-1
++ ;;
++
++ st8 [r16]=r19,PT(AR_RNAT)-PT(CR_IFS) // store ar.pfs.pfm in cr.ifs
++ extr.u r11=r19,7,7 // I0 // get sol of ar.pfs
++ and r8=0x7f,r19 // A // get sof of ar.pfs
++
++ st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc
++ tbit.nz p15,p0=r29,IA64_PSR_I_BIT // I0
++(p9) mov in1=-1
++ ;;
++
++(pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8
++ tnat.nz p10,p0=in2
++ add r11=8,r11
++ ;;
++(pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field
++(pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field
++ tnat.nz p11,p0=in3
++ ;;
++(p10) mov in2=-1
++ tnat.nz p12,p0=in4 // [I0]
++(p11) mov in3=-1
++ ;;
++(pUStk) st8 [r16]=r24,PT(PR)-PT(AR_RNAT) // save ar.rnat
++(pUStk) st8 [r17]=r23,PT(B0)-PT(AR_BSPSTORE) // save ar.bspstore
++ shl r18=r18,16 // compute ar.rsc to be used for "loadrs"
++ ;;
++ st8 [r16]=r31,PT(LOADRS)-PT(PR) // save predicates
++ st8 [r17]=r28,PT(R1)-PT(B0) // save b0
++ tnat.nz p13,p0=in5 // [I0]
++ ;;
++ st8 [r16]=r18,PT(R12)-PT(LOADRS) // save ar.rsc value for "loadrs"
++ st8.spill [r17]=r20,PT(R13)-PT(R1) // save original r1
++(p12) mov in4=-1
++ ;;
++
++.mem.offset 0,0; st8.spill [r16]=r12,PT(AR_FPSR)-PT(R12) // save r12
++.mem.offset 8,0; st8.spill [r17]=r13,PT(R15)-PT(R13) // save r13
++(p13) mov in5=-1
++ ;;
++ st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr
++ tnat.nz p13,p0=in6
++ cmp.lt p10,p9=r11,r8 // frame size can't be more than local+8
++ ;;
++ mov r8=1
++(p9) tnat.nz p10,p0=r15
++ adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch)
++
++ st8.spill [r17]=r15 // save r15
++ tnat.nz p8,p0=in7
++ nop.i 0
++
++ mov r13=r2 // establish `current'
++ movl r1=__gp // establish kernel global pointer
++ ;;
++ st8 [r16]=r8 // ensure pt_regs.r8 != 0 (see handle_syscall_error)
++(p13) mov in6=-1
++(p8) mov in7=-1
++
++ cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0
++ movl r17=FPSR_DEFAULT
++ ;;
++ mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value
++(p10) mov r8=-EINVAL
++ br.ret.sptk.many b7
++END(ia64_syscall_setup)
++#endif
++
++ .org ia64_ivt+0x3c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x3c00 Entry 15 (size 64 bundles) Reserved
++ DBG_FAULT(15)
++ FAULT(15)
++
++ /*
++ * Squatting in this space ...
++ *
++ * This special case dispatcher for illegal operation faults allows preserved
++ * registers to be modified through a callback function (asm only) that is handed
++ * back from the fault handler in r8. Up to three arguments can be passed to the
++ * callback function by returning an aggregate with the callback as its first
++ * element, followed by the arguments.
++ */
++ENTRY(dispatch_illegal_op_fault)
++ .prologue
++ .body
++ SAVE_MIN_WITH_COVER
++ ssm psr.ic | PSR_DEFAULT_BITS
++ ;;
++ srlz.i // guarantee that interruption collection is on
++ ;;
++(p15) ssm psr.i // restore psr.i
++ adds r3=8,r2 // set up second base pointer for SAVE_REST
++ ;;
++ alloc r14=ar.pfs,0,0,1,0 // must be first in insn group
++ mov out0=ar.ec
++ ;;
++ SAVE_REST
++ PT_REGS_UNWIND_INFO(0)
++ ;;
++ br.call.sptk.many rp=ia64_illegal_op_fault
++.ret0: ;;
++ alloc r14=ar.pfs,0,0,3,0 // must be first in insn group
++ mov out0=r9
++ mov out1=r10
++ mov out2=r11
++ movl r15=ia64_leave_kernel
++ ;;
++ mov rp=r15
++ mov b6=r8
++ ;;
++ cmp.ne p6,p0=0,r8
++(p6) br.call.dpnt.many b6=b6 // call returns to ia64_leave_kernel
++ br.sptk.many ia64_leave_kernel
++END(dispatch_illegal_op_fault)
++
++ .org ia64_ivt+0x4000
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x4000 Entry 16 (size 64 bundles) Reserved
++ DBG_FAULT(16)
++ FAULT(16)
++
++ .org ia64_ivt+0x4400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x4400 Entry 17 (size 64 bundles) Reserved
++ DBG_FAULT(17)
++ 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
++ // there happens to be space here that would go unused otherwise. If this
++ // fault ever gets "unreserved", simply moved the following code to a more
++ // suitable spot...
++
++ alloc r14=ar.pfs,0,0,2,0
++ mov out0=cr.iim
++ add out1=16,sp
++ adds r3=8,r2 // set up second base pointer for SAVE_REST
++
++ ssm psr.ic | PSR_DEFAULT_BITS
++ ;;
++ srlz.i // guarantee that interruption collection is on
++ ;;
++(p15) ssm psr.i // restore psr.i
++ movl r15=ia64_leave_kernel
++ ;;
++ SAVE_REST
++ mov rp=r15
++ ;;
++ br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr
++END(non_syscall)
++
++ .org ia64_ivt+0x4800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x4800 Entry 18 (size 64 bundles) Reserved
++ DBG_FAULT(18)
++ FAULT(18)
++
++ /*
++ * There is no particular reason for this code to be here, other than that
++ * there happens to be space here that would go unused otherwise. If this
++ * fault ever gets "unreserved", simply moved the following code to a more
++ * suitable spot...
++ */
++
++ENTRY(dispatch_unaligned_handler)
++ SAVE_MIN_WITH_COVER
++ ;;
++ alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!)
++ mov out0=cr.ifa
++ adds out1=16,sp
++
++ ssm psr.ic | PSR_DEFAULT_BITS
++ ;;
++ srlz.i // guarantee that interruption collection is on
++ ;;
++(p15) ssm psr.i // restore psr.i
++ adds r3=8,r2 // set up second base pointer
++ ;;
++ SAVE_REST
++ movl r14=ia64_leave_kernel
++ ;;
++ mov rp=r14
++ br.sptk.many ia64_prepare_handle_unaligned
++END(dispatch_unaligned_handler)
++
++ .org ia64_ivt+0x4c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x4c00 Entry 19 (size 64 bundles) Reserved
++ DBG_FAULT(19)
++ FAULT(19)
++
++ /*
++ * There is no particular reason for this code to be here, other than that
++ * there happens to be space here that would go unused otherwise. If this
++ * fault ever gets "unreserved", simply moved the following code to a more
++ * suitable spot...
++ */
++
++ENTRY(dispatch_to_fault_handler)
++ /*
++ * Input:
++ * psr.ic: off
++ * r19: fault vector number (e.g., 24 for General Exception)
++ * r31: contains saved predicates (pr)
++ */
++ SAVE_MIN_WITH_COVER_R19
++ alloc r14=ar.pfs,0,0,5,0
++ mov out0=r15
++#ifdef CONFIG_XEN
++ movl out1=XSI_ISR
++ ;;
++ adds out2=XSI_IFA-XSI_ISR,out1
++ adds out3=XSI_IIM-XSI_ISR,out1
++ adds out4=XSI_ITIR-XSI_ISR,out1
++ ;;
++ ld8 out1=[out1]
++ ld8 out2=[out2]
++ ld8 out3=[out4]
++ ld8 out4=[out4]
++ ;;
++#else
++ mov out1=cr.isr
++ mov out2=cr.ifa
++ mov out3=cr.iim
++ mov out4=cr.itir
++ ;;
++#endif
++ ssm psr.ic | PSR_DEFAULT_BITS
++ ;;
++ srlz.i // guarantee that interruption collection is on
++ ;;
++(p15) ssm psr.i // restore psr.i
++ adds r3=8,r2 // set up second base pointer for SAVE_REST
++ ;;
++ SAVE_REST
++ movl r14=ia64_leave_kernel
++ ;;
++ mov rp=r14
++ br.call.sptk.many b6=ia64_fault
++END(dispatch_to_fault_handler)
++
++//
++// --- End of long entries, Beginning of short entries
++//
++
++ .org ia64_ivt+0x5000
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49)
++ENTRY(page_not_present)
++ DBG_FAULT(20)
++ mov r16=cr.ifa
++ rsm psr.dt
++ /*
++ * The Linux page fault handler doesn't expect non-present pages to be in
++ * the TLB. Flush the existing entry now, so we meet that expectation.
++ */
++ mov r17=PAGE_SHIFT<<2
++ ;;
++ ptc.l r16,r17
++ ;;
++ mov r31=pr
++ srlz.d
++ br.sptk.many page_fault
++END(page_not_present)
++
++ .org ia64_ivt+0x5100
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52)
++ENTRY(key_permission)
++ DBG_FAULT(21)
++ mov r16=cr.ifa
++ rsm psr.dt
++ mov r31=pr
++ ;;
++ srlz.d
++ br.sptk.many page_fault
++END(key_permission)
++
++ .org ia64_ivt+0x5200
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26)
++ENTRY(iaccess_rights)
++ DBG_FAULT(22)
++ mov r16=cr.ifa
++ rsm psr.dt
++ mov r31=pr
++ ;;
++ srlz.d
++ br.sptk.many page_fault
++END(iaccess_rights)
++
++ .org ia64_ivt+0x5300
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53)
++ENTRY(daccess_rights)
++ DBG_FAULT(23)
++#ifdef CONFIG_XEN
++ movl r16=XSI_IFA
++ ;;
++ ld8 r16=[r16]
++ ;;
++ XEN_HYPER_RSM_PSR_DT
++#else
++ mov r16=cr.ifa
++ rsm psr.dt
++#endif
++ mov r31=pr
++ ;;
++ srlz.d
++ br.sptk.many page_fault
++END(daccess_rights)
++
++ .org ia64_ivt+0x5400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39)
++ENTRY(general_exception)
++ DBG_FAULT(24)
++ mov r16=cr.isr
++ mov r31=pr
++ ;;
++ cmp4.eq p6,p0=0,r16
++(p6) br.sptk.many dispatch_illegal_op_fault
++ ;;
++ mov r19=24 // fault number
++ br.sptk.many dispatch_to_fault_handler
++END(general_exception)
++
++ .org ia64_ivt+0x5500
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35)
++ENTRY(disabled_fp_reg)
++ DBG_FAULT(25)
++ rsm psr.dfh // ensure we can access fph
++ ;;
++ srlz.d
++ mov r31=pr
++ mov r19=25
++ br.sptk.many dispatch_to_fault_handler
++END(disabled_fp_reg)
++
++ .org ia64_ivt+0x5600
++/////////////////////////////////////////////////////////////////////////////////////////
++// 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)
++
++ .org ia64_ivt+0x5700
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5700 Entry 27 (size 16 bundles) Speculation (40)
++ENTRY(speculation_vector)
++ DBG_FAULT(27)
++ /*
++ * A [f]chk.[as] instruction needs to take the branch to the recovery code but
++ * this part of the architecture is not implemented in hardware on some CPUs, such
++ * as Itanium. Thus, in general we need to emulate the behavior. IIM contains
++ * the relative target (not yet sign extended). So after sign extending it we
++ * simply add it to IIP. We also need to reset the EI field of the IPSR to zero,
++ * i.e., the slot to restart into.
++ *
++ * cr.imm contains zero_ext(imm21)
++ */
++ mov r18=cr.iim
++ ;;
++ mov r17=cr.iip
++ shl r18=r18,43 // put sign bit in position (43=64-21)
++ ;;
++
++ mov r16=cr.ipsr
++ shr r18=r18,39 // sign extend (39=43-4)
++ ;;
++
++ add r17=r17,r18 // now add the offset
++ ;;
++ mov cr.iip=r17
++ dep r16=0,r16,41,2 // clear EI
++ ;;
++
++ mov cr.ipsr=r16
++ ;;
++
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI;
++#else
++ rfi // and go back
++#endif
++END(speculation_vector)
++
++ .org ia64_ivt+0x5800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5800 Entry 28 (size 16 bundles) Reserved
++ DBG_FAULT(28)
++ FAULT(28)
++
++ .org ia64_ivt+0x5900
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56)
++ENTRY(debug_vector)
++ DBG_FAULT(29)
++ FAULT(29)
++END(debug_vector)
++
++ .org ia64_ivt+0x5a00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57)
++ENTRY(unaligned_access)
++ DBG_FAULT(30)
++ mov r31=pr // prepare to save predicates
++ ;;
++ br.sptk.many dispatch_unaligned_handler
++END(unaligned_access)
++
++ .org ia64_ivt+0x5b00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57)
++ENTRY(unsupported_data_reference)
++ DBG_FAULT(31)
++ FAULT(31)
++END(unsupported_data_reference)
++
++ .org ia64_ivt+0x5c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64)
++ENTRY(floating_point_fault)
++ DBG_FAULT(32)
++ FAULT(32)
++END(floating_point_fault)
++
++ .org ia64_ivt+0x5d00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66)
++ENTRY(floating_point_trap)
++ DBG_FAULT(33)
++ FAULT(33)
++END(floating_point_trap)
++
++ .org ia64_ivt+0x5e00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66)
++ENTRY(lower_privilege_trap)
++ DBG_FAULT(34)
++ FAULT(34)
++END(lower_privilege_trap)
++
++ .org ia64_ivt+0x5f00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68)
++ENTRY(taken_branch_trap)
++ DBG_FAULT(35)
++ FAULT(35)
++END(taken_branch_trap)
++
++ .org ia64_ivt+0x6000
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69)
++ENTRY(single_step_trap)
++ DBG_FAULT(36)
++ FAULT(36)
++END(single_step_trap)
++
++ .org ia64_ivt+0x6100
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6100 Entry 37 (size 16 bundles) Reserved
++ DBG_FAULT(37)
++ FAULT(37)
++
++ .org ia64_ivt+0x6200
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6200 Entry 38 (size 16 bundles) Reserved
++ DBG_FAULT(38)
++ FAULT(38)
++
++ .org ia64_ivt+0x6300
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6300 Entry 39 (size 16 bundles) Reserved
++ DBG_FAULT(39)
++ FAULT(39)
++
++ .org ia64_ivt+0x6400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6400 Entry 40 (size 16 bundles) Reserved
++ DBG_FAULT(40)
++ FAULT(40)
++
++ .org ia64_ivt+0x6500
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6500 Entry 41 (size 16 bundles) Reserved
++ DBG_FAULT(41)
++ FAULT(41)
++
++ .org ia64_ivt+0x6600
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6600 Entry 42 (size 16 bundles) Reserved
++ DBG_FAULT(42)
++ FAULT(42)
++
++ .org ia64_ivt+0x6700
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6700 Entry 43 (size 16 bundles) Reserved
++ DBG_FAULT(43)
++ FAULT(43)
++
++ .org ia64_ivt+0x6800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6800 Entry 44 (size 16 bundles) Reserved
++ DBG_FAULT(44)
++ FAULT(44)
++
++ .org ia64_ivt+0x6900
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77)
++ENTRY(ia32_exception)
++ DBG_FAULT(45)
++ FAULT(45)
++END(ia32_exception)
++
++ .org ia64_ivt+0x6a00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71)
++ENTRY(ia32_intercept)
++ DBG_FAULT(46)
++#ifdef CONFIG_IA32_SUPPORT
++ mov r31=pr
++ mov r16=cr.isr
++ ;;
++ extr.u r17=r16,16,8 // get ISR.code
++ mov r18=ar.eflag
++ mov r19=cr.iim // old eflag value
++ ;;
++ cmp.ne p6,p0=2,r17
++(p6) br.cond.spnt 1f // not a system flag fault
++ xor r16=r18,r19
++ ;;
++ extr.u r17=r16,18,1 // get the eflags.ac bit
++ ;;
++ cmp.eq p6,p0=0,r17
++(p6) br.cond.spnt 1f // eflags.ac bit didn't change
++ ;;
++ mov pr=r31,-1 // restore predicate registers
++#ifdef CONFIG_XEN
++ XEN_HYPER_RFI;
++#else
++ rfi
++#endif
++
++1:
++#endif // CONFIG_IA32_SUPPORT
++ FAULT(46)
++END(ia32_intercept)
++
++ .org ia64_ivt+0x6b00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74)
++ENTRY(ia32_interrupt)
++ DBG_FAULT(47)
++#ifdef CONFIG_IA32_SUPPORT
++ mov r31=pr
++ br.sptk.many dispatch_to_ia32_handler
++#else
++ FAULT(47)
++#endif
++END(ia32_interrupt)
++
++ .org ia64_ivt+0x6c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6c00 Entry 48 (size 16 bundles) Reserved
++ DBG_FAULT(48)
++ FAULT(48)
++
++ .org ia64_ivt+0x6d00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6d00 Entry 49 (size 16 bundles) Reserved
++ DBG_FAULT(49)
++ FAULT(49)
++
++ .org ia64_ivt+0x6e00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6e00 Entry 50 (size 16 bundles) Reserved
++ DBG_FAULT(50)
++ FAULT(50)
++
++ .org ia64_ivt+0x6f00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x6f00 Entry 51 (size 16 bundles) Reserved
++ DBG_FAULT(51)
++ FAULT(51)
++
++ .org ia64_ivt+0x7000
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7000 Entry 52 (size 16 bundles) Reserved
++ DBG_FAULT(52)
++ FAULT(52)
++
++ .org ia64_ivt+0x7100
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7100 Entry 53 (size 16 bundles) Reserved
++ DBG_FAULT(53)
++ FAULT(53)
++
++ .org ia64_ivt+0x7200
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7200 Entry 54 (size 16 bundles) Reserved
++ DBG_FAULT(54)
++ FAULT(54)
++
++ .org ia64_ivt+0x7300
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7300 Entry 55 (size 16 bundles) Reserved
++ DBG_FAULT(55)
++ FAULT(55)
++
++ .org ia64_ivt+0x7400
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7400 Entry 56 (size 16 bundles) Reserved
++ DBG_FAULT(56)
++ FAULT(56)
++
++ .org ia64_ivt+0x7500
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7500 Entry 57 (size 16 bundles) Reserved
++ DBG_FAULT(57)
++ FAULT(57)
++
++ .org ia64_ivt+0x7600
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7600 Entry 58 (size 16 bundles) Reserved
++ DBG_FAULT(58)
++ FAULT(58)
++
++ .org ia64_ivt+0x7700
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7700 Entry 59 (size 16 bundles) Reserved
++ DBG_FAULT(59)
++ FAULT(59)
++
++ .org ia64_ivt+0x7800
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7800 Entry 60 (size 16 bundles) Reserved
++ DBG_FAULT(60)
++ FAULT(60)
++
++ .org ia64_ivt+0x7900
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7900 Entry 61 (size 16 bundles) Reserved
++ DBG_FAULT(61)
++ FAULT(61)
++
++ .org ia64_ivt+0x7a00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7a00 Entry 62 (size 16 bundles) Reserved
++ DBG_FAULT(62)
++ FAULT(62)
++
++ .org ia64_ivt+0x7b00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7b00 Entry 63 (size 16 bundles) Reserved
++ DBG_FAULT(63)
++ FAULT(63)
++
++ .org ia64_ivt+0x7c00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7c00 Entry 64 (size 16 bundles) Reserved
++ DBG_FAULT(64)
++ FAULT(64)
++
++ .org ia64_ivt+0x7d00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7d00 Entry 65 (size 16 bundles) Reserved
++ DBG_FAULT(65)
++ FAULT(65)
++
++ .org ia64_ivt+0x7e00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7e00 Entry 66 (size 16 bundles) Reserved
++ DBG_FAULT(66)
++ FAULT(66)
++
++#ifdef CONFIG_XEN
++ /*
++ * There is no particular reason for this code to be here, other than that
++ * there happens to be space here that would go unused otherwise. If this
++ * fault ever gets "unreserved", simply moved the following code to a more
++ * suitable spot...
++ */
++
++GLOBAL_ENTRY(xen_bsw1)
++ /* FIXME: THIS CODE IS NOT NaT SAFE! */
++ movl r30=XSI_BANKNUM;
++ mov r31=1;;
++ st4 [r30]=r31;
++ movl r30=XSI_BANK1_R16;
++ movl r31=XSI_BANK1_R16+8;;
++ ld8 r16=[r30],16; ld8 r17=[r31],16;;
++ ld8 r18=[r30],16; ld8 r19=[r31],16;;
++ ld8 r20=[r30],16; ld8 r21=[r31],16;;
++ ld8 r22=[r30],16; ld8 r23=[r31],16;;
++ ld8 r24=[r30],16; ld8 r25=[r31],16;;
++ ld8 r26=[r30],16; ld8 r27=[r31],16;;
++ ld8 r28=[r30],16; ld8 r29=[r31],16;;
++ ld8 r30=[r30]; ld8 r31=[r31];;
++ br.ret.sptk.many b0
++END(xen_bsw1)
++#endif
++
++ .org ia64_ivt+0x7f00
++/////////////////////////////////////////////////////////////////////////////////////////
++// 0x7f00 Entry 67 (size 16 bundles) Reserved
++ DBG_FAULT(67)
++ FAULT(67)
++
++#ifdef CONFIG_IA32_SUPPORT
++
++ /*
++ * There is no particular reason for this code to be here, other than that
++ * there happens to be space here that would go unused otherwise. If this
++ * fault ever gets "unreserved", simply moved the following code to a more
++ * suitable spot...
++ */
++
++ // IA32 interrupt entry point
++
++ENTRY(dispatch_to_ia32_handler)
++ SAVE_MIN
++ ;;
++ mov r14=cr.isr
++ ssm psr.ic | PSR_DEFAULT_BITS
++ ;;
++ srlz.i // guarantee that interruption collection is on
++ ;;
++(p15) ssm psr.i
++ adds r3=8,r2 // Base pointer for SAVE_REST
++ ;;
++ SAVE_REST
++ ;;
++ mov r15=0x80
++ shr r14=r14,16 // Get interrupt number
++ ;;
++ cmp.ne p6,p0=r14,r15
++(p6) br.call.dpnt.many b6=non_ia32_syscall
++
++ adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions
++ adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp
++ ;;
++ cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0
++ ld8 r8=[r14] // get r8
++ ;;
++ st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP)
++ ;;
++ alloc r15=ar.pfs,0,0,6,0 // must first in an insn group
++ ;;
++ ld4 r8=[r14],8 // r8 == eax (syscall number)
++ mov r15=IA32_NR_syscalls
++ ;;
++ cmp.ltu.unc p6,p7=r8,r15
++ ld4 out1=[r14],8 // r9 == ecx
++ ;;
++ ld4 out2=[r14],8 // r10 == edx
++ ;;
++ ld4 out0=[r14] // r11 == ebx
++ adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp
++ ;;
++ ld4 out5=[r14],PT(R14)-PT(R13) // r13 == ebp
++ ;;
++ ld4 out3=[r14],PT(R15)-PT(R14) // r14 == esi
++ adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
++ ;;
++ ld4 out4=[r14] // r15 == edi
++ movl r16=ia32_syscall_table
++ ;;
++(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number
++ ld4 r2=[r2] // r2 = current_thread_info()->flags
++ ;;
++ ld8 r16=[r16]
++ and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit
++ ;;
++ mov b6=r16
++ movl r15=ia32_ret_from_syscall
++ cmp.eq p8,p0=r2,r0
++ ;;
++ mov rp=r15
++(p8) br.call.sptk.many b6=b6
++ br.cond.sptk ia32_trace_syscall
++
++non_ia32_syscall:
++ alloc r15=ar.pfs,0,0,2,0
++ mov out0=r14 // interrupt #
++ add out1=16,sp // pointer to pt_regs
++ ;; // avoid WAW on CFM
++ br.call.sptk.many rp=ia32_bad_interrupt
++.ret1: movl r15=ia64_leave_kernel
++ ;;
++ mov rp=r15
++ br.ret.sptk.many rp
++END(dispatch_to_ia32_handler)
++#endif /* CONFIG_IA32_SUPPORT */
++
++#ifdef CONFIG_XEN
++ .section .text,"ax"
++GLOBAL_ENTRY(xen_event_callback)
++ mov r31=pr // prepare to save predicates
++ ;;
++ SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3
++ ;;
++ movl r3=XSI_PSR_IC
++ mov r14=1
++ ;;
++ st4 [r3]=r14
++ ;;
++ adds r3=8,r2 // set up second base pointer for SAVE_REST
++ srlz.i // ensure everybody knows psr.ic is back on
++ ;;
++ SAVE_REST
++ ;;
++ alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group
++ add out0=16,sp // pass pointer to pt_regs as first arg
++ ;;
++ srlz.d // make sure we see the effect of cr.ivr
++ movl r14=ia64_leave_kernel
++ ;;
++ mov rp=r14
++ br.call.sptk.many b6=evtchn_do_upcall
++END(xen_event_callback)
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xenminstate.h linux-2.6.18-xen/arch/ia64/xen/xenminstate.h
+--- linux-2.6.18.1/arch/ia64/xen/xenminstate.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xenminstate.h 2006-09-04 16:31:01.000000000 +0200
+@@ -0,0 +1,368 @@
++
++#include <asm/cache.h>
++
++#ifdef CONFIG_XEN
++#include "../kernel/entry.h"
++#else
++#include "entry.h"
++#endif
++
++/*
++ * For ivt.s we want to access the stack virtually so we don't have to disable translation
++ * on interrupts.
++ *
++ * On entry:
++ * r1: pointer to current task (ar.k6)
++ */
++#define MINSTATE_START_SAVE_MIN_VIRT \
++(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \
++ ;; \
++(pUStk) mov.m r24=ar.rnat; \
++(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \
++(pKStk) mov r1=sp; /* get sp */ \
++ ;; \
++(pUStk) lfetch.fault.excl.nt1 [r22]; \
++(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \
++(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \
++ ;; \
++(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \
++(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \
++ ;; \
++(pUStk) mov r18=ar.bsp; \
++(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \
++
++#define MINSTATE_END_SAVE_MIN_VIRT \
++ bsw.1; /* switch back to bank 1 (must be last in insn group) */ \
++ ;;
++
++/*
++ * For mca_asm.S we want to access the stack physically since the state is saved before we
++ * go virtual and don't want to destroy the iip or ipsr.
++ */
++#define MINSTATE_START_SAVE_MIN_PHYS \
++(pKStk) mov r3=IA64_KR(PER_CPU_DATA);; \
++(pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;; \
++(pKStk) ld8 r3 = [r3];; \
++(pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;; \
++(pKStk) addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \
++(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \
++(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \
++ ;; \
++(pUStk) mov r24=ar.rnat; \
++(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \
++(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \
++(pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \
++ ;; \
++(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \
++(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \
++ ;; \
++(pUStk) mov r18=ar.bsp; \
++(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \
++
++#define MINSTATE_END_SAVE_MIN_PHYS \
++ dep r12=-1,r12,61,3; /* make sp a kernel virtual address */ \
++ ;;
++
++#ifdef MINSTATE_VIRT
++# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT)
++# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_VIRT
++# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_VIRT
++#endif
++
++#ifdef MINSTATE_PHYS
++# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; tpa reg=reg
++# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS
++# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS
++#endif
++
++/*
++ * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
++ * the minimum state necessary that allows us to turn psr.ic back
++ * on.
++ *
++ * Assumed state upon entry:
++ * psr.ic: off
++ * r31: contains saved predicates (pr)
++ *
++ * Upon exit, the state is as follows:
++ * psr.ic: off
++ * r2 = points to &pt_regs.r16
++ * r8 = contents of ar.ccv
++ * r9 = contents of ar.csd
++ * r10 = contents of ar.ssd
++ * r11 = FPSR_DEFAULT
++ * r12 = kernel sp (kernel virtual address)
++ * r13 = points to current task_struct (kernel virtual address)
++ * p15 = TRUE if psr.i is set in cr.ipsr
++ * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15:
++ * preserved
++ * CONFIG_XEN note: p6/p7 are not preserved
++ *
++ * Note that psr.ic is NOT turned on by this macro. This is so that
++ * we can pass interruption state as arguments to a handler.
++ */
++#ifdef CONFIG_XEN
++#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \
++ MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \
++ mov r27=ar.rsc; /* M */ \
++ mov r20=r1; /* A */ \
++ mov r25=ar.unat; /* M */ \
++ /* mov r29=cr.ipsr; /* M */ \
++ movl r29=XSI_IPSR;; \
++ ld8 r29=[r29];; \
++ mov r26=ar.pfs; /* I */ \
++ /* mov r28=cr.iip; /* M */ \
++ movl r28=XSI_IIP;; \
++ ld8 r28=[r28];; \
++ mov r21=ar.fpsr; /* M */ \
++ COVER; /* B;; (or nothing) */ \
++ ;; \
++ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16; \
++ ;; \
++ ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \
++ st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \
++ adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 \
++ /* switch from user to kernel RBS: */ \
++ ;; \
++ invala; /* M */ \
++ /* SAVE_IFS; /* see xen special handling below */ \
++ cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \
++ ;; \
++ MINSTATE_START_SAVE_MIN \
++ adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \
++ adds r16=PT(CR_IPSR),r1; \
++ ;; \
++ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \
++ st8 [r16]=r29; /* save cr.ipsr */ \
++ ;; \
++ lfetch.fault.excl.nt1 [r17]; \
++ tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \
++ mov r29=b0 \
++ ;; \
++ adds r16=PT(R8),r1; /* initialize first base pointer */ \
++ adds r17=PT(R9),r1; /* initialize second base pointer */ \
++(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r8,16; \
++.mem.offset 8,0; st8.spill [r17]=r9,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r10,24; \
++.mem.offset 8,0; st8.spill [r17]=r11,24; \
++ ;; \
++ /* xen special handling for possibly lazy cover */ \
++ movl r8=XSI_INCOMPL_REGFR; \
++ ;; \
++ ld4 r30=[r8]; \
++ ;; \
++ /* set XSI_INCOMPL_REGFR 0 */ \
++ st4 [r8]=r0; \
++ cmp.eq p6,p7=r30,r0; \
++ ;; /* not sure if this stop bit is necessary */ \
++(p6) adds r8=XSI_PRECOVER_IFS-XSI_INCOMPL_REGFR,r8; \
++(p7) adds r8=XSI_IFS-XSI_INCOMPL_REGFR,r8; \
++ ;; \
++ ld8 r30=[r8]; \
++ ;; \
++ st8 [r16]=r28,16; /* save cr.iip */ \
++ st8 [r17]=r30,16; /* save cr.ifs */ \
++(pUStk) sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \
++ mov r8=ar.ccv; \
++ mov r9=ar.csd; \
++ mov r10=ar.ssd; \
++ movl r11=FPSR_DEFAULT; /* L-unit */ \
++ ;; \
++ st8 [r16]=r25,16; /* save ar.unat */ \
++ st8 [r17]=r26,16; /* save ar.pfs */ \
++ shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \
++ ;; \
++ st8 [r16]=r27,16; /* save ar.rsc */ \
++(pUStk) st8 [r17]=r24,16; /* save ar.rnat */ \
++(pKStk) adds r17=16,r17; /* skip over ar_rnat field */ \
++ ;; /* avoid RAW on r16 & r17 */ \
++(pUStk) st8 [r16]=r23,16; /* save ar.bspstore */ \
++ st8 [r17]=r31,16; /* save predicates */ \
++(pKStk) adds r16=16,r16; /* skip over ar_bspstore field */ \
++ ;; \
++ st8 [r16]=r29,16; /* save b0 */ \
++ st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \
++ cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \
++.mem.offset 8,0; st8.spill [r17]=r12,16; \
++ adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r13,16; \
++.mem.offset 8,0; st8.spill [r17]=r21,16; /* save ar.fpsr */ \
++ mov r13=IA64_KR(CURRENT); /* establish `current' */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r15,16; \
++.mem.offset 8,0; st8.spill [r17]=r14,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r2,16; \
++.mem.offset 8,0; st8.spill [r17]=r3,16; \
++ ;; \
++ EXTRA; \
++ mov r2=b0; br.call.sptk b0=xen_bsw1;; mov b0=r2; \
++ adds r2=IA64_PT_REGS_R16_OFFSET,r1; \
++ ;; \
++ movl r1=__gp; /* establish kernel global pointer */ \
++ ;; \
++ /* MINSTATE_END_SAVE_MIN */
++#else
++#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \
++ MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \
++ mov r27=ar.rsc; /* M */ \
++ mov r20=r1; /* A */ \
++ mov r25=ar.unat; /* M */ \
++ mov r29=cr.ipsr; /* M */ \
++ mov r26=ar.pfs; /* I */ \
++ mov r28=cr.iip; /* M */ \
++ mov r21=ar.fpsr; /* M */ \
++ COVER; /* B;; (or nothing) */ \
++ ;; \
++ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16; \
++ ;; \
++ ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \
++ st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \
++ adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 \
++ /* switch from user to kernel RBS: */ \
++ ;; \
++ invala; /* M */ \
++ SAVE_IFS; \
++ cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \
++ ;; \
++ MINSTATE_START_SAVE_MIN \
++ adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \
++ adds r16=PT(CR_IPSR),r1; \
++ ;; \
++ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \
++ st8 [r16]=r29; /* save cr.ipsr */ \
++ ;; \
++ lfetch.fault.excl.nt1 [r17]; \
++ tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \
++ mov r29=b0 \
++ ;; \
++ adds r16=PT(R8),r1; /* initialize first base pointer */ \
++ adds r17=PT(R9),r1; /* initialize second base pointer */ \
++(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r8,16; \
++.mem.offset 8,0; st8.spill [r17]=r9,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r10,24; \
++.mem.offset 8,0; st8.spill [r17]=r11,24; \
++ ;; \
++ st8 [r16]=r28,16; /* save cr.iip */ \
++ st8 [r17]=r30,16; /* save cr.ifs */ \
++(pUStk) sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \
++ mov r8=ar.ccv; \
++ mov r9=ar.csd; \
++ mov r10=ar.ssd; \
++ movl r11=FPSR_DEFAULT; /* L-unit */ \
++ ;; \
++ st8 [r16]=r25,16; /* save ar.unat */ \
++ st8 [r17]=r26,16; /* save ar.pfs */ \
++ shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \
++ ;; \
++ st8 [r16]=r27,16; /* save ar.rsc */ \
++(pUStk) st8 [r17]=r24,16; /* save ar.rnat */ \
++(pKStk) adds r17=16,r17; /* skip over ar_rnat field */ \
++ ;; /* avoid RAW on r16 & r17 */ \
++(pUStk) st8 [r16]=r23,16; /* save ar.bspstore */ \
++ st8 [r17]=r31,16; /* save predicates */ \
++(pKStk) adds r16=16,r16; /* skip over ar_bspstore field */ \
++ ;; \
++ st8 [r16]=r29,16; /* save b0 */ \
++ st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \
++ cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \
++.mem.offset 8,0; st8.spill [r17]=r12,16; \
++ adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r13,16; \
++.mem.offset 8,0; st8.spill [r17]=r21,16; /* save ar.fpsr */ \
++ mov r13=IA64_KR(CURRENT); /* establish `current' */ \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r15,16; \
++.mem.offset 8,0; st8.spill [r17]=r14,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r16]=r2,16; \
++.mem.offset 8,0; st8.spill [r17]=r3,16; \
++ adds r2=IA64_PT_REGS_R16_OFFSET,r1; \
++ ;; \
++ EXTRA; \
++ movl r1=__gp; /* establish kernel global pointer */ \
++ ;; \
++ MINSTATE_END_SAVE_MIN
++#endif
++
++/*
++ * SAVE_REST saves the remainder of pt_regs (with psr.ic on).
++ *
++ * Assumed state upon entry:
++ * psr.ic: on
++ * r2: points to &pt_regs.r16
++ * r3: points to &pt_regs.r17
++ * r8: contents of ar.ccv
++ * r9: contents of ar.csd
++ * r10: contents of ar.ssd
++ * r11: FPSR_DEFAULT
++ *
++ * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST.
++ */
++#define SAVE_REST \
++.mem.offset 0,0; st8.spill [r2]=r16,16; \
++.mem.offset 8,0; st8.spill [r3]=r17,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r18,16; \
++.mem.offset 8,0; st8.spill [r3]=r19,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r20,16; \
++.mem.offset 8,0; st8.spill [r3]=r21,16; \
++ mov r18=b6; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r22,16; \
++.mem.offset 8,0; st8.spill [r3]=r23,16; \
++ mov r19=b7; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r24,16; \
++.mem.offset 8,0; st8.spill [r3]=r25,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r26,16; \
++.mem.offset 8,0; st8.spill [r3]=r27,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r28,16; \
++.mem.offset 8,0; st8.spill [r3]=r29,16; \
++ ;; \
++.mem.offset 0,0; st8.spill [r2]=r30,16; \
++.mem.offset 8,0; st8.spill [r3]=r31,32; \
++ ;; \
++ mov ar.fpsr=r11; /* M-unit */ \
++ st8 [r2]=r8,8; /* ar.ccv */ \
++ adds r24=PT(B6)-PT(F7),r3; \
++ ;; \
++ stf.spill [r2]=f6,32; \
++ stf.spill [r3]=f7,32; \
++ ;; \
++ stf.spill [r2]=f8,32; \
++ stf.spill [r3]=f9,32; \
++ ;; \
++ stf.spill [r2]=f10; \
++ stf.spill [r3]=f11; \
++ adds r25=PT(B7)-PT(F11),r3; \
++ ;; \
++ st8 [r24]=r18,16; /* b6 */ \
++ st8 [r25]=r19,16; /* b7 */ \
++ ;; \
++ st8 [r24]=r9; /* ar.csd */ \
++ st8 [r25]=r10; /* ar.ssd */ \
++ ;;
++
++#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov r30=cr.ifs,)
++#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19)
++#ifdef CONFIG_XEN
++#define SAVE_MIN break 0;; /* FIXME: non-cover version only for ia32 support? */
++#else
++#define SAVE_MIN DO_SAVE_MIN( , mov r30=r0, )
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xenpal.S linux-2.6.18-xen/arch/ia64/xen/xenpal.S
+--- linux-2.6.18.1/arch/ia64/xen/xenpal.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xenpal.S 2006-09-04 16:31:01.000000000 +0200
+@@ -0,0 +1,76 @@
++/*
++ * ia64/xen/xenpal.S
++ *
++ * Alternate PAL routines for Xen. Heavily leveraged from
++ * ia64/kernel/pal.S
++ *
++ * Copyright (C) 2005 Hewlett-Packard Co
++ * Dan Magenheimer <dan.magenheimer at .hp.com>
++ */
++
++#include <asm/asmmacro.h>
++#include <asm/processor.h>
++
++GLOBAL_ENTRY(xen_pal_call_static)
++ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
++ alloc loc1 = ar.pfs,5,5,0,0
++#ifdef CONFIG_XEN
++ movl r22=running_on_xen;;
++ ld4 r22=[r22];;
++ cmp.eq p7,p0=r22,r0
++(p7) br.cond.spnt.many __ia64_pal_call_static;;
++#endif
++ movl loc2 = pal_entry_point
++1: {
++ mov r28 = in0
++ mov r29 = in1
++ mov r8 = ip
++ }
++ ;;
++ ld8 loc2 = [loc2] // loc2 <- entry point
++ tbit.nz p6,p7 = in4, 0
++ adds r8 = 1f-1b,r8
++ mov loc4=ar.rsc // save RSE configuration
++ ;;
++ mov ar.rsc=0 // put RSE in enforced lazy, LE mode
++ mov loc3 = psr
++ mov loc0 = rp
++ .body
++ mov r30 = in2
++
++#ifdef CONFIG_XEN
++ // this is low priority for paravirtualization, but is called
++ // from the idle loop so confuses privop counting
++ movl r31=XSI_PSR_IC
++ ;;
++(p6) st4 [r31]=r0
++ ;;
++(p7) adds r31=XSI_PSR_I_ADDR_OFS-XSI_PSR_IC_OFS,r31
++(p7) mov r22=1
++ ;;
++(p7) ld8 r31=[r31]
++ ;;
++(p7) st1 [r31]=r22
++ ;;
++ mov r31 = in3
++ mov b7 = loc2
++ ;;
++#else
++(p6) rsm psr.i | psr.ic
++ mov r31 = in3
++ mov b7 = loc2
++
++(p7) rsm psr.i
++ ;;
++(p6) srlz.i
++#endif
++ mov rp = r8
++ br.cond.sptk.many b7
++1: mov psr.l = loc3
++ mov ar.rsc = loc4 // restore RSE configuration
++ mov ar.pfs = loc1
++ mov rp = loc0
++ ;;
++ srlz.d // seralize restoration of psr.l
++ br.ret.sptk.many b0
++END(xen_pal_call_static)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/ia64/xen/xensetup.S linux-2.6.18-xen/arch/ia64/xen/xensetup.S
+--- linux-2.6.18.1/arch/ia64/xen/xensetup.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/ia64/xen/xensetup.S 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,53 @@
++/*
++ * Support routines for Xen
++ *
++ * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer at hp.com>
++ */
++
++#include <asm/processor.h>
++#include <asm/asmmacro.h>
++
++#define isBP p3 // are we the Bootstrap Processor?
++
++ .text
++GLOBAL_ENTRY(early_xen_setup)
++ mov r8=ar.rsc // Initialized in head.S
++(isBP) movl r9=running_on_xen;;
++ extr.u r8=r8,2,2;; // Extract pl fields
++ cmp.eq p7,p0=r8,r0 // p7: !running on xen
++ mov r8=1 // booleanize.
++(p7) br.ret.sptk.many rp;;
++(isBP) st4 [r9]=r8
++ movl r10=xen_ivt;;
++
++ mov cr.iva=r10
++
++ /* Set xsi base. */
++#define FW_HYPERCALL_SET_SHARED_INFO_VA 0x600
++(isBP) mov r2=FW_HYPERCALL_SET_SHARED_INFO_VA
++(isBP) movl r28=XSI_BASE;;
++(isBP) break 0x1000;;
++
++ br.ret.sptk.many rp
++ ;;
++END(early_xen_setup)
++
++#include <xen/interface/xen.h>
++
++/* Stub for suspend.
++ Just force the stacked registers to be written in memory. */
++GLOBAL_ENTRY(xencomm_arch_hypercall_suspend)
++ mov r15=r32
++ ;;
++ alloc r20=ar.pfs,0,0,0,0
++ mov r2=__HYPERVISOR_sched_op
++ ;;
++ /* We don't want to deal with RSE. */
++ flushrs
++ mov r14=2 // SCHEDOP_shutdown
++ ;;
++ break 0x1000
++ ;;
++ mov ar.pfs=r20
++ br.ret.sptk.many b0
++END(xencomm_arch_hypercall_suspend)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/um/kernel/physmem.c linux-2.6.18-xen/arch/um/kernel/physmem.c
+--- linux-2.6.18.1/arch/um/kernel/physmem.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/um/kernel/physmem.c 2006-09-04 16:31:02.000000000 +0200
+@@ -226,7 +226,7 @@
+ EXPORT_SYMBOL(physmem_remove_mapping);
+ EXPORT_SYMBOL(physmem_subst_mapping);
+
+-void arch_free_page(struct page *page, int order)
++int arch_free_page(struct page *page, int order)
+ {
+ void *virt;
+ int i;
+@@ -235,6 +235,8 @@
+ virt = __va(page_to_phys(page + i));
+ physmem_remove_mapping(virt);
+ }
++
++ return 0;
+ }
+
+ int is_remapped(void *virt)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/ia32/ia32entry-xen.S linux-2.6.18-xen/arch/x86_64/ia32/ia32entry-xen.S
+--- linux-2.6.18.1/arch/x86_64/ia32/ia32entry-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/ia32/ia32entry-xen.S 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,743 @@
++/*
++ * Compatibility mode system call entry point for x86-64.
++ *
++ * Copyright 2000-2002 Andi Kleen, SuSE Labs.
++ */
++
++#include <asm/dwarf2.h>
++#include <asm/calling.h>
++#include <asm/asm-offsets.h>
++#include <asm/current.h>
++#include <asm/errno.h>
++#include <asm/ia32_unistd.h>
++#include <asm/thread_info.h>
++#include <asm/segment.h>
++#include <asm/vsyscall32.h>
++#include <asm/irqflags.h>
++#include <linux/linkage.h>
++
++#define __XEN_X86_64 1
++
++#define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8)
++
++ .macro IA32_ARG_FIXUP noebp=0
++ movl %edi,%r8d
++ .if \noebp
++ .else
++ movl %ebp,%r9d
++ .endif
++ xchg %ecx,%esi
++ movl %ebx,%edi
++ movl %edx,%edx /* zero extension */
++ .endm
++
++ /* clobbers %eax */
++ .macro CLEAR_RREGS
++ xorl %eax,%eax
++ movq %rax,R11(%rsp)
++ movq %rax,R10(%rsp)
++ movq %rax,R9(%rsp)
++ movq %rax,R8(%rsp)
++ .endm
++
++#if defined (__XEN_X86_64)
++#include "../kernel/xen_entry.S"
++
++#define __swapgs
++#define __cli
++#define __sti
++#else
++/*
++ * Use the native instructions
++ */
++#define __swapgs swapgs
++#define __cli cli
++#define __sti sti
++#endif
++
++ .macro CFI_STARTPROC32 simple
++ CFI_STARTPROC \simple
++ CFI_UNDEFINED r8
++ CFI_UNDEFINED r9
++ CFI_UNDEFINED r10
++ CFI_UNDEFINED r11
++ CFI_UNDEFINED r12
++ CFI_UNDEFINED r13
++ CFI_UNDEFINED r14
++ CFI_UNDEFINED r15
++ .endm
++
++/*
++ * 32bit SYSENTER instruction entry.
++ *
++ * Arguments:
++ * %eax System call number.
++ * %ebx Arg1
++ * %ecx Arg2
++ * %edx Arg3
++ * %esi Arg4
++ * %edi Arg5
++ * %ebp user stack
++ * 0(%ebp) Arg6
++ *
++ * Interrupts off.
++ *
++ * This is purely a fast path. For anything complicated we use the int 0x80
++ * path below. Set up a complete hardware stack frame to share code
++ * with the int 0x80 path.
++ */
++ENTRY(ia32_sysenter_target)
++ CFI_STARTPROC32 simple
++ CFI_DEF_CFA rsp,0
++ CFI_REGISTER rsp,rbp
++ __swapgs
++ movq %gs:pda_kernelstack, %rsp
++ addq $(PDA_STACKOFFSET),%rsp
++ /*
++ * No need to follow this irqs on/off section: the syscall
++ * disabled irqs, here we enable it straight after entry:
++ */
++ XEN_UNBLOCK_EVENTS(%r11)
++ __sti
++ movl %ebp,%ebp /* zero extension */
++ pushq $__USER32_DS
++ CFI_ADJUST_CFA_OFFSET 8
++ /*CFI_REL_OFFSET ss,0*/
++ pushq %rbp
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rsp,0
++ pushfq
++ CFI_ADJUST_CFA_OFFSET 8
++ /*CFI_REL_OFFSET rflags,0*/
++ movl $VSYSCALL32_SYSEXIT, %r10d
++ CFI_REGISTER rip,r10
++ pushq $__USER32_CS
++ CFI_ADJUST_CFA_OFFSET 8
++ /*CFI_REL_OFFSET cs,0*/
++ movl %eax, %eax
++ pushq %r10
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rip,0
++ pushq %rax
++ CFI_ADJUST_CFA_OFFSET 8
++ cld
++ SAVE_ARGS 0,0,0
++ /* no need to do an access_ok check here because rbp has been
++ 32bit zero extended */
++1: movl (%rbp),%r9d
++ .section __ex_table,"a"
++ .quad 1b,ia32_badarg
++ .previous
++ GET_THREAD_INFO(%r10)
++ orl $TS_COMPAT,threadinfo_status(%r10)
++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
++ CFI_REMEMBER_STATE
++ jnz sysenter_tracesys
++sysenter_do_call:
++ cmpl $(IA32_NR_syscalls-1),%eax
++ ja ia32_badsys
++ IA32_ARG_FIXUP 1
++ call *ia32_sys_call_table(,%rax,8)
++ movq %rax,RAX-ARGOFFSET(%rsp)
++ GET_THREAD_INFO(%r10)
++ XEN_BLOCK_EVENTS(%r11)
++ __cli
++ TRACE_IRQS_OFF
++ testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
++ jnz int_ret_from_sys_call
++ andl $~TS_COMPAT,threadinfo_status(%r10)
++ /* clear IF, that popfq doesn't enable interrupts early */
++ andl $~0x200,EFLAGS-R11(%rsp)
++ RESTORE_ARGS 1,24,1,1,1,1
++ popfq
++ CFI_ADJUST_CFA_OFFSET -8
++ /*CFI_RESTORE rflags*/
++ popq %rcx /* User %esp */
++ CFI_ADJUST_CFA_OFFSET -8
++ CFI_REGISTER rsp,rcx
++ movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */
++ CFI_REGISTER rip,rdx
++ TRACE_IRQS_ON
++ __swapgs
++ XEN_UNBLOCK_EVENTS(%r11)
++ __sti /* sti only takes effect after the next instruction */
++ /* sysexit */
++ .byte 0xf, 0x35 /* TBD */
++
++sysenter_tracesys:
++ CFI_RESTORE_STATE
++ SAVE_REST
++ CLEAR_RREGS
++ movq $-ENOSYS,RAX(%rsp) /* really needed? */
++ movq %rsp,%rdi /* &pt_regs -> arg1 */
++ call syscall_trace_enter
++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
++ RESTORE_REST
++ movl %ebp, %ebp
++ /* no need to do an access_ok check here because rbp has been
++ 32bit zero extended */
++1: movl (%rbp),%r9d
++ .section __ex_table,"a"
++ .quad 1b,ia32_badarg
++ .previous
++ jmp sysenter_do_call
++ CFI_ENDPROC
++ENDPROC(ia32_sysenter_target)
++
++/*
++ * 32bit SYSCALL instruction entry.
++ *
++ * Arguments:
++ * %eax System call number.
++ * %ebx Arg1
++ * %ecx return EIP
++ * %edx Arg3
++ * %esi Arg4
++ * %edi Arg5
++ * %ebp Arg2 [note: not saved in the stack frame, should not be touched]
++ * %esp user stack
++ * 0(%esp) Arg6
++ *
++ * Interrupts off.
++ *
++ * This is purely a fast path. For anything complicated we use the int 0x80
++ * path below. Set up a complete hardware stack frame to share code
++ * with the int 0x80 path.
++ */
++ENTRY(ia32_cstar_target)
++ CFI_STARTPROC32 simple
++ CFI_DEF_CFA rsp,PDA_STACKOFFSET
++ CFI_REGISTER rip,rcx
++ /*CFI_REGISTER rflags,r11*/
++ __swapgs
++ movl %esp,%r8d
++ CFI_REGISTER rsp,r8
++ movq %gs:pda_kernelstack,%rsp
++ /*
++ * No need to follow this irqs on/off section: the syscall
++ * disabled irqs and here we enable it straight after entry:
++ */
++ XEN_UNBLOCK_EVENTS(%r11)
++ __sti
++ SAVE_ARGS 8,1,1
++ movl %eax,%eax /* zero extension */
++ movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
++ movq %rcx,RIP-ARGOFFSET(%rsp)
++ CFI_REL_OFFSET rip,RIP-ARGOFFSET
++ movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */
++ movl %ebp,%ecx
++ movq $__USER32_CS,CS-ARGOFFSET(%rsp)
++ movq $__USER32_DS,SS-ARGOFFSET(%rsp)
++ movq %r11,EFLAGS-ARGOFFSET(%rsp)
++ /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
++ movq %r8,RSP-ARGOFFSET(%rsp)
++ CFI_REL_OFFSET rsp,RSP-ARGOFFSET
++ /* no need to do an access_ok check here because r8 has been
++ 32bit zero extended */
++ /* hardware stack frame is complete now */
++1: movl (%r8),%r9d
++ .section __ex_table,"a"
++ .quad 1b,ia32_badarg
++ .previous
++ GET_THREAD_INFO(%r10)
++ orl $TS_COMPAT,threadinfo_status(%r10)
++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
++ CFI_REMEMBER_STATE
++ jnz cstar_tracesys
++cstar_do_call:
++ cmpl $IA32_NR_syscalls-1,%eax
++ ja ia32_badsys
++ IA32_ARG_FIXUP 1
++ call *ia32_sys_call_table(,%rax,8)
++ movq %rax,RAX-ARGOFFSET(%rsp)
++ GET_THREAD_INFO(%r10)
++ XEN_BLOCK_EVENTS(%r11)
++ __cli
++ TRACE_IRQS_OFF
++ testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
++ jnz int_ret_from_sys_call
++ andl $~TS_COMPAT,threadinfo_status(%r10)
++ RESTORE_ARGS 1,-ARG_SKIP,1,1,1
++ movl RIP-ARGOFFSET(%rsp),%ecx
++ CFI_REGISTER rip,rcx
++ movl EFLAGS-ARGOFFSET(%rsp),%r11d
++ /*CFI_REGISTER rflags,r11*/
++ TRACE_IRQS_ON
++ movl RSP-ARGOFFSET(%rsp),%esp
++ CFI_RESTORE rsp
++ __swapgs
++ sysretl /* TBD */
++
++cstar_tracesys:
++ CFI_RESTORE_STATE
++ SAVE_REST
++ CLEAR_RREGS
++ movq $-ENOSYS,RAX(%rsp) /* really needed? */
++ movq %rsp,%rdi /* &pt_regs -> arg1 */
++ call syscall_trace_enter
++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
++ RESTORE_REST
++ movl RSP-ARGOFFSET(%rsp), %r8d
++ /* no need to do an access_ok check here because r8 has been
++ 32bit zero extended */
++1: movl (%r8),%r9d
++ .section __ex_table,"a"
++ .quad 1b,ia32_badarg
++ .previous
++ jmp cstar_do_call
++END(ia32_cstar_target)
++
++ia32_badarg:
++ movq $-EFAULT,%rax
++ jmp ia32_sysret
++ CFI_ENDPROC
++
++/*
++ * Emulated IA32 system calls via int 0x80.
++ *
++ * Arguments:
++ * %eax System call number.
++ * %ebx Arg1
++ * %ecx Arg2
++ * %edx Arg3
++ * %esi Arg4
++ * %edi Arg5
++ * %ebp Arg6 [note: not saved in the stack frame, should not be touched]
++ *
++ * Notes:
++ * Uses the same stack frame as the x86-64 version.
++ * All registers except %eax must be saved (but ptrace may violate that)
++ * Arguments are zero extended. For system calls that want sign extension and
++ * take long arguments a wrapper is needed. Most calls can just be called
++ * directly.
++ * Assumes it is only called from user space and entered with interrupts off.
++ */
++
++ENTRY(ia32_syscall)
++ CFI_STARTPROC simple
++ CFI_DEF_CFA rsp,SS+8-RIP
++ /*CFI_REL_OFFSET ss,SS-RIP*/
++ CFI_REL_OFFSET rsp,RSP-RIP
++ /*CFI_REL_OFFSET rflags,EFLAGS-RIP*/
++ /*CFI_REL_OFFSET cs,CS-RIP*/
++ CFI_REL_OFFSET rip,RIP-RIP
++ __swapgs
++ /*
++ * No need to follow this irqs on/off section: the syscall
++ * disabled irqs and here we enable it straight after entry:
++ */
++ XEN_UNBLOCK_EVENTS(%r11)
++ __sti
++ movq (%rsp),%rcx
++ movq 8(%rsp),%r11
++ addq $0x10,%rsp /* skip rcx and r11 */
++ movl %eax,%eax
++ pushq %rax
++ CFI_ADJUST_CFA_OFFSET 8
++ cld
++/* 1: jmp 1b */
++ /* note the registers are not zero extended to the sf.
++ this could be a problem. */
++ SAVE_ARGS 0,0,1
++ GET_THREAD_INFO(%r10)
++ orl $TS_COMPAT,threadinfo_status(%r10)
++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
++ jnz ia32_tracesys
++ia32_do_syscall:
++ cmpl $(IA32_NR_syscalls-1),%eax
++ ja ia32_badsys
++ IA32_ARG_FIXUP
++ call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
++ia32_sysret:
++ movq %rax,RAX-ARGOFFSET(%rsp)
++ jmp int_ret_from_sys_call
++
++ia32_tracesys:
++ SAVE_REST
++ movq $-ENOSYS,RAX(%rsp) /* really needed? */
++ movq %rsp,%rdi /* &pt_regs -> arg1 */
++ call syscall_trace_enter
++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
++ RESTORE_REST
++ jmp ia32_do_syscall
++END(ia32_syscall)
++
++ia32_badsys:
++ movq $0,ORIG_RAX-ARGOFFSET(%rsp)
++ movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
++ jmp int_ret_from_sys_call
++
++quiet_ni_syscall:
++ movq $-ENOSYS,%rax
++ ret
++ CFI_ENDPROC
++
++ .macro PTREGSCALL label, func, arg
++ .globl \label
++\label:
++ leaq \func(%rip),%rax
++ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
++ jmp ia32_ptregs_common
++ .endm
++
++ CFI_STARTPROC32
++
++ PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
++ PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
++ PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
++ PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx
++ PTREGSCALL stub32_execve, sys32_execve, %rcx
++ PTREGSCALL stub32_fork, sys_fork, %rdi
++ PTREGSCALL stub32_clone, sys32_clone, %rdx
++ PTREGSCALL stub32_vfork, sys_vfork, %rdi
++ PTREGSCALL stub32_iopl, sys_iopl, %rsi
++ PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx
++
++ENTRY(ia32_ptregs_common)
++ popq %r11
++ CFI_ENDPROC
++ CFI_STARTPROC32 simple
++ CFI_DEF_CFA rsp,SS+8-ARGOFFSET
++ CFI_REL_OFFSET rax,RAX-ARGOFFSET
++ CFI_REL_OFFSET rcx,RCX-ARGOFFSET
++ CFI_REL_OFFSET rdx,RDX-ARGOFFSET
++ CFI_REL_OFFSET rsi,RSI-ARGOFFSET
++ CFI_REL_OFFSET rdi,RDI-ARGOFFSET
++ CFI_REL_OFFSET rip,RIP-ARGOFFSET
++/* CFI_REL_OFFSET cs,CS-ARGOFFSET*/
++/* CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
++ CFI_REL_OFFSET rsp,RSP-ARGOFFSET
++/* CFI_REL_OFFSET ss,SS-ARGOFFSET*/
++ SAVE_REST
++ call *%rax
++ RESTORE_REST
++ jmp ia32_sysret /* misbalances the return cache */
++ CFI_ENDPROC
++END(ia32_ptregs_common)
++
++ .section .rodata,"a"
++ .align 8
++ia32_sys_call_table:
++ .quad sys_restart_syscall
++ .quad sys_exit
++ .quad stub32_fork
++ .quad sys_read
++ .quad sys_write
++ .quad compat_sys_open /* 5 */
++ .quad sys_close
++ .quad sys32_waitpid
++ .quad sys_creat
++ .quad sys_link
++ .quad sys_unlink /* 10 */
++ .quad stub32_execve
++ .quad sys_chdir
++ .quad compat_sys_time
++ .quad sys_mknod
++ .quad sys_chmod /* 15 */
++ .quad sys_lchown16
++ .quad quiet_ni_syscall /* old break syscall holder */
++ .quad sys_stat
++ .quad sys32_lseek
++ .quad sys_getpid /* 20 */
++ .quad compat_sys_mount /* mount */
++ .quad sys_oldumount /* old_umount */
++ .quad sys_setuid16
++ .quad sys_getuid16
++ .quad compat_sys_stime /* stime */ /* 25 */
++ .quad sys32_ptrace /* ptrace */
++ .quad sys_alarm
++ .quad sys_fstat /* (old)fstat */
++ .quad sys_pause
++ .quad compat_sys_utime /* 30 */
++ .quad quiet_ni_syscall /* old stty syscall holder */
++ .quad quiet_ni_syscall /* old gtty syscall holder */
++ .quad sys_access
++ .quad sys_nice
++ .quad quiet_ni_syscall /* 35 */ /* old ftime syscall holder */
++ .quad sys_sync
++ .quad sys32_kill
++ .quad sys_rename
++ .quad sys_mkdir
++ .quad sys_rmdir /* 40 */
++ .quad sys_dup
++ .quad sys32_pipe
++ .quad compat_sys_times
++ .quad quiet_ni_syscall /* old prof syscall holder */
++ .quad sys_brk /* 45 */
++ .quad sys_setgid16
++ .quad sys_getgid16
++ .quad sys_signal
++ .quad sys_geteuid16
++ .quad sys_getegid16 /* 50 */
++ .quad sys_acct
++ .quad sys_umount /* new_umount */
++ .quad quiet_ni_syscall /* old lock syscall holder */
++ .quad compat_sys_ioctl
++ .quad compat_sys_fcntl64 /* 55 */
++ .quad quiet_ni_syscall /* old mpx syscall holder */
++ .quad sys_setpgid
++ .quad quiet_ni_syscall /* old ulimit syscall holder */
++ .quad sys32_olduname
++ .quad sys_umask /* 60 */
++ .quad sys_chroot
++ .quad sys32_ustat
++ .quad sys_dup2
++ .quad sys_getppid
++ .quad sys_getpgrp /* 65 */
++ .quad sys_setsid
++ .quad sys32_sigaction
++ .quad sys_sgetmask
++ .quad sys_ssetmask
++ .quad sys_setreuid16 /* 70 */
++ .quad sys_setregid16
++ .quad stub32_sigsuspend
++ .quad compat_sys_sigpending
++ .quad sys_sethostname
++ .quad compat_sys_setrlimit /* 75 */
++ .quad compat_sys_old_getrlimit /* old_getrlimit */
++ .quad compat_sys_getrusage
++ .quad sys32_gettimeofday
++ .quad sys32_settimeofday
++ .quad sys_getgroups16 /* 80 */
++ .quad sys_setgroups16
++ .quad sys32_old_select
++ .quad sys_symlink
++ .quad sys_lstat
++ .quad sys_readlink /* 85 */
++#ifdef CONFIG_IA32_AOUT
++ .quad sys_uselib
++#else
++ .quad quiet_ni_syscall
++#endif
++ .quad sys_swapon
++ .quad sys_reboot
++ .quad compat_sys_old_readdir
++ .quad sys32_mmap /* 90 */
++ .quad sys_munmap
++ .quad sys_truncate
++ .quad sys_ftruncate
++ .quad sys_fchmod
++ .quad sys_fchown16 /* 95 */
++ .quad sys_getpriority
++ .quad sys_setpriority
++ .quad quiet_ni_syscall /* old profil syscall holder */
++ .quad compat_sys_statfs
++ .quad compat_sys_fstatfs /* 100 */
++ .quad sys_ioperm
++ .quad compat_sys_socketcall
++ .quad sys_syslog
++ .quad compat_sys_setitimer
++ .quad compat_sys_getitimer /* 105 */
++ .quad compat_sys_newstat
++ .quad compat_sys_newlstat
++ .quad compat_sys_newfstat
++ .quad sys32_uname
++ .quad stub32_iopl /* 110 */
++ .quad sys_vhangup
++ .quad quiet_ni_syscall /* old "idle" system call */
++ .quad sys32_vm86_warning /* vm86old */
++ .quad compat_sys_wait4
++ .quad sys_swapoff /* 115 */
++ .quad sys32_sysinfo
++ .quad sys32_ipc
++ .quad sys_fsync
++ .quad stub32_sigreturn
++ .quad stub32_clone /* 120 */
++ .quad sys_setdomainname
++ .quad sys_uname
++ .quad sys_modify_ldt
++ .quad compat_sys_adjtimex
++ .quad sys32_mprotect /* 125 */
++ .quad compat_sys_sigprocmask
++ .quad quiet_ni_syscall /* create_module */
++ .quad sys_init_module
++ .quad sys_delete_module
++ .quad quiet_ni_syscall /* 130 get_kernel_syms */
++ .quad sys_quotactl
++ .quad sys_getpgid
++ .quad sys_fchdir
++ .quad quiet_ni_syscall /* bdflush */
++ .quad sys_sysfs /* 135 */
++ .quad sys_personality
++ .quad quiet_ni_syscall /* for afs_syscall */
++ .quad sys_setfsuid16
++ .quad sys_setfsgid16
++ .quad sys_llseek /* 140 */
++ .quad compat_sys_getdents
++ .quad compat_sys_select
++ .quad sys_flock
++ .quad sys_msync
++ .quad compat_sys_readv /* 145 */
++ .quad compat_sys_writev
++ .quad sys_getsid
++ .quad sys_fdatasync
++ .quad sys32_sysctl /* sysctl */
++ .quad sys_mlock /* 150 */
++ .quad sys_munlock
++ .quad sys_mlockall
++ .quad sys_munlockall
++ .quad sys_sched_setparam
++ .quad sys_sched_getparam /* 155 */
++ .quad sys_sched_setscheduler
++ .quad sys_sched_getscheduler
++ .quad sys_sched_yield
++ .quad sys_sched_get_priority_max
++ .quad sys_sched_get_priority_min /* 160 */
++ .quad sys_sched_rr_get_interval
++ .quad compat_sys_nanosleep
++ .quad sys_mremap
++ .quad sys_setresuid16
++ .quad sys_getresuid16 /* 165 */
++ .quad sys32_vm86_warning /* vm86 */
++ .quad quiet_ni_syscall /* query_module */
++ .quad sys_poll
++ .quad compat_sys_nfsservctl
++ .quad sys_setresgid16 /* 170 */
++ .quad sys_getresgid16
++ .quad sys_prctl
++ .quad stub32_rt_sigreturn
++ .quad sys32_rt_sigaction
++ .quad sys32_rt_sigprocmask /* 175 */
++ .quad sys32_rt_sigpending
++ .quad compat_sys_rt_sigtimedwait
++ .quad sys32_rt_sigqueueinfo
++ .quad stub32_rt_sigsuspend
++ .quad sys32_pread /* 180 */
++ .quad sys32_pwrite
++ .quad sys_chown16
++ .quad sys_getcwd
++ .quad sys_capget
++ .quad sys_capset
++ .quad stub32_sigaltstack
++ .quad sys32_sendfile
++ .quad quiet_ni_syscall /* streams1 */
++ .quad quiet_ni_syscall /* streams2 */
++ .quad stub32_vfork /* 190 */
++ .quad compat_sys_getrlimit
++ .quad sys32_mmap2
++ .quad sys32_truncate64
++ .quad sys32_ftruncate64
++ .quad sys32_stat64 /* 195 */
++ .quad sys32_lstat64
++ .quad sys32_fstat64
++ .quad sys_lchown
++ .quad sys_getuid
++ .quad sys_getgid /* 200 */
++ .quad sys_geteuid
++ .quad sys_getegid
++ .quad sys_setreuid
++ .quad sys_setregid
++ .quad sys_getgroups /* 205 */
++ .quad sys_setgroups
++ .quad sys_fchown
++ .quad sys_setresuid
++ .quad sys_getresuid
++ .quad sys_setresgid /* 210 */
++ .quad sys_getresgid
++ .quad sys_chown
++ .quad sys_setuid
++ .quad sys_setgid
++ .quad sys_setfsuid /* 215 */
++ .quad sys_setfsgid
++ .quad sys_pivot_root
++ .quad sys_mincore
++ .quad sys_madvise
++ .quad compat_sys_getdents64 /* 220 getdents64 */
++ .quad compat_sys_fcntl64
++ .quad quiet_ni_syscall /* tux */
++ .quad quiet_ni_syscall /* security */
++ .quad sys_gettid
++ .quad sys_readahead /* 225 */
++ .quad sys_setxattr
++ .quad sys_lsetxattr
++ .quad sys_fsetxattr
++ .quad sys_getxattr
++ .quad sys_lgetxattr /* 230 */
++ .quad sys_fgetxattr
++ .quad sys_listxattr
++ .quad sys_llistxattr
++ .quad sys_flistxattr
++ .quad sys_removexattr /* 235 */
++ .quad sys_lremovexattr
++ .quad sys_fremovexattr
++ .quad sys_tkill
++ .quad sys_sendfile64
++ .quad compat_sys_futex /* 240 */
++ .quad compat_sys_sched_setaffinity
++ .quad compat_sys_sched_getaffinity
++ .quad sys32_set_thread_area
++ .quad sys32_get_thread_area
++ .quad compat_sys_io_setup /* 245 */
++ .quad sys_io_destroy
++ .quad compat_sys_io_getevents
++ .quad compat_sys_io_submit
++ .quad sys_io_cancel
++ .quad sys_fadvise64 /* 250 */
++ .quad quiet_ni_syscall /* free_huge_pages */
++ .quad sys_exit_group
++ .quad sys32_lookup_dcookie
++ .quad sys_epoll_create
++ .quad sys_epoll_ctl /* 255 */
++ .quad sys_epoll_wait
++ .quad sys_remap_file_pages
++ .quad sys_set_tid_address
++ .quad compat_sys_timer_create
++ .quad compat_sys_timer_settime /* 260 */
++ .quad compat_sys_timer_gettime
++ .quad sys_timer_getoverrun
++ .quad sys_timer_delete
++ .quad compat_sys_clock_settime
++ .quad compat_sys_clock_gettime /* 265 */
++ .quad compat_sys_clock_getres
++ .quad compat_sys_clock_nanosleep
++ .quad compat_sys_statfs64
++ .quad compat_sys_fstatfs64
++ .quad sys_tgkill /* 270 */
++ .quad compat_sys_utimes
++ .quad sys32_fadvise64_64
++ .quad quiet_ni_syscall /* sys_vserver */
++ .quad sys_mbind
++ .quad compat_sys_get_mempolicy /* 275 */
++ .quad sys_set_mempolicy
++ .quad compat_sys_mq_open
++ .quad sys_mq_unlink
++ .quad compat_sys_mq_timedsend
++ .quad compat_sys_mq_timedreceive /* 280 */
++ .quad compat_sys_mq_notify
++ .quad compat_sys_mq_getsetattr
++ .quad compat_sys_kexec_load /* reserved for kexec */
++ .quad compat_sys_waitid
++ .quad quiet_ni_syscall /* 285: sys_altroot */
++ .quad sys_add_key
++ .quad sys_request_key
++ .quad sys_keyctl
++ .quad sys_ioprio_set
++ .quad sys_ioprio_get /* 290 */
++ .quad sys_inotify_init
++ .quad sys_inotify_add_watch
++ .quad sys_inotify_rm_watch
++ .quad sys_migrate_pages
++ .quad compat_sys_openat /* 295 */
++ .quad sys_mkdirat
++ .quad sys_mknodat
++ .quad sys_fchownat
++ .quad compat_sys_futimesat
++ .quad sys32_fstatat /* 300 */
++ .quad sys_unlinkat
++ .quad sys_renameat
++ .quad sys_linkat
++ .quad sys_symlinkat
++ .quad sys_readlinkat /* 305 */
++ .quad sys_fchmodat
++ .quad sys_faccessat
++ .quad quiet_ni_syscall /* pselect6 for now */
++ .quad quiet_ni_syscall /* ppoll for now */
++ .quad sys_unshare /* 310 */
++ .quad compat_sys_set_robust_list
++ .quad compat_sys_get_robust_list
++ .quad sys_splice
++ .quad sys_sync_file_range
++ .quad sys_tee
++ .quad compat_sys_vmsplice
++ .quad compat_sys_move_pages
++ia32_syscall_end:
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/ia32/Makefile linux-2.6.18-xen/arch/x86_64/ia32/Makefile
+--- linux-2.6.18.1/arch/x86_64/ia32/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/ia32/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -27,9 +27,25 @@
+ -Wl,-soname=linux-gate.so.1 -o $@ \
+ -Wl,-T,$(filter-out FORCE,$^)
+
++$(obj)/vsyscall-int80.so \
+ $(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \
+ $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+ $(call if_changed,syscall)
+
+-AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32
+-AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32
++AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32 -Iarch/i386/kernel
++AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32 -Iarch/i386/kernel
++
++ifdef CONFIG_XEN
++AFLAGS_vsyscall-int80.o = -m32 -Wa,-32 -Iarch/i386/kernel
++CFLAGS_syscall32-xen.o += -DUSE_INT80
++AFLAGS_syscall32_syscall-xen.o += -DUSE_INT80
++
++$(obj)/syscall32_syscall-xen.o: \
++ $(foreach F,int80 sysenter syscall,$(obj)/vsyscall-$F.so)
++
++targets := $(foreach F,int80 sysenter syscall,vsyscall-$F.o vsyscall-$F.so)
++
++include $(srctree)/scripts/Makefile.xen
++
++obj-y := $(call cherrypickxen, $(obj-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/ia32/syscall32_syscall-xen.S linux-2.6.18-xen/arch/x86_64/ia32/syscall32_syscall-xen.S
+--- linux-2.6.18.1/arch/x86_64/ia32/syscall32_syscall-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/ia32/syscall32_syscall-xen.S 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,28 @@
++/* 32bit VDSOs mapped into user space. */
++
++ .section ".init.data","aw"
++
++#ifdef USE_INT80
++
++ .globl syscall32_int80
++ .globl syscall32_int80_end
++
++syscall32_int80:
++ .incbin "arch/x86_64/ia32/vsyscall-int80.so"
++syscall32_int80_end:
++
++#endif
++
++ .globl syscall32_syscall
++ .globl syscall32_syscall_end
++
++syscall32_syscall:
++ .incbin "arch/x86_64/ia32/vsyscall-syscall.so"
++syscall32_syscall_end:
++
++ .globl syscall32_sysenter
++ .globl syscall32_sysenter_end
++
++syscall32_sysenter:
++ .incbin "arch/x86_64/ia32/vsyscall-sysenter.so"
++syscall32_sysenter_end:
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/ia32/syscall32-xen.c linux-2.6.18-xen/arch/x86_64/ia32/syscall32-xen.c
+--- linux-2.6.18.1/arch/x86_64/ia32/syscall32-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/ia32/syscall32-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,128 @@
++/* Copyright 2002,2003 Andi Kleen, SuSE Labs */
++
++/* vsyscall handling for 32bit processes. Map a stub page into it
++ on demand because 32bit cannot reach the kernel's fixmaps */
++
++#include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/gfp.h>
++#include <linux/init.h>
++#include <linux/stringify.h>
++#include <linux/security.h>
++#include <asm/proto.h>
++#include <asm/tlbflush.h>
++#include <asm/ia32_unistd.h>
++
++#ifdef USE_INT80
++extern unsigned char syscall32_int80[], syscall32_int80_end[];
++#endif
++extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
++extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
++extern int sysctl_vsyscall32;
++
++char *syscall32_page;
++#ifndef USE_INT80
++static int use_sysenter = -1;
++#endif
++
++static struct page *
++syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type)
++{
++ struct page *p = virt_to_page(adr - vma->vm_start + syscall32_page);
++ get_page(p);
++ return p;
++}
++
++/* Prevent VMA merging */
++static void syscall32_vma_close(struct vm_area_struct *vma)
++{
++}
++
++static struct vm_operations_struct syscall32_vm_ops = {
++ .close = syscall32_vma_close,
++ .nopage = syscall32_nopage,
++};
++
++struct linux_binprm;
++
++/* Setup a VMA at program startup for the vsyscall page */
++int syscall32_setup_pages(struct linux_binprm *bprm, int exstack)
++{
++ int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT;
++ struct vm_area_struct *vma;
++ struct mm_struct *mm = current->mm;
++ int ret;
++
++ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
++ if (!vma)
++ return -ENOMEM;
++
++ memset(vma, 0, sizeof(struct vm_area_struct));
++ /* Could randomize here */
++ vma->vm_start = VSYSCALL32_BASE;
++ vma->vm_end = VSYSCALL32_END;
++ /* MAYWRITE to allow gdb to COW and set breakpoints */
++ vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
++ vma->vm_flags |= mm->def_flags;
++ vma->vm_page_prot = protection_map[vma->vm_flags & 7];
++ vma->vm_ops = &syscall32_vm_ops;
++ vma->vm_mm = mm;
++
++ down_write(&mm->mmap_sem);
++ if ((ret = insert_vm_struct(mm, vma))) {
++ up_write(&mm->mmap_sem);
++ kmem_cache_free(vm_area_cachep, vma);
++ return ret;
++ }
++ mm->total_vm += npages;
++ up_write(&mm->mmap_sem);
++ return 0;
++}
++
++static int __init init_syscall32(void)
++{
++ syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
++ if (!syscall32_page)
++ panic("Cannot allocate syscall32 page");
++
++#ifdef USE_INT80
++ /*
++ * At this point we use int 0x80.
++ */
++ memcpy(syscall32_page, syscall32_int80,
++ syscall32_int80_end - syscall32_int80);
++#else
++ if (use_sysenter > 0) {
++ memcpy(syscall32_page, syscall32_sysenter,
++ syscall32_sysenter_end - syscall32_sysenter);
++ } else {
++ memcpy(syscall32_page, syscall32_syscall,
++ syscall32_syscall_end - syscall32_syscall);
++ }
++#endif
++ return 0;
++}
++
++/*
++ * This must be done early in case we have an initrd containing 32-bit
++ * binaries (e.g., hotplug). This could be pushed upstream to arch/x86_64.
++ */
++core_initcall(init_syscall32);
++
++/* May not be __init: called during resume */
++void syscall32_cpu_init(void)
++{
++#ifndef USE_INT80
++ if (use_sysenter < 0)
++ use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
++
++ /* Load these always in case some future AMD CPU supports
++ SYSENTER from compat mode too. */
++ checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
++ checking_wrmsrl(MSR_IA32_SYSENTER_ESP, 0ULL);
++ checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
++
++ wrmsrl(MSR_CSTAR, ia32_cstar_target);
++#endif
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/ia32/vsyscall-int80.S linux-2.6.18-xen/arch/x86_64/ia32/vsyscall-int80.S
+--- linux-2.6.18.1/arch/x86_64/ia32/vsyscall-int80.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/ia32/vsyscall-int80.S 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,58 @@
++/*
++ * Code for the vsyscall page. This version uses the old int $0x80 method.
++ *
++ * NOTE:
++ * 1) __kernel_vsyscall _must_ be first in this page.
++ * 2) there are alignment constraints on this stub, see vsyscall-sigreturn.S
++ * for details.
++ */
++#include <asm/ia32_unistd.h>
++#include <asm/asm-offsets.h>
++
++ .code32
++ .text
++ .section .text.vsyscall,"ax"
++ .globl __kernel_vsyscall
++ .type __kernel_vsyscall, at function
++__kernel_vsyscall:
++.LSTART_vsyscall:
++ int $0x80
++ ret
++.LEND_vsyscall:
++ .size __kernel_vsyscall,.-.LSTART_vsyscall
++ .previous
++
++ .section .eh_frame,"a", at progbits
++.LSTARTFRAME:
++ .long .LENDCIE-.LSTARTCIE
++.LSTARTCIE:
++ .long 0 /* CIE ID */
++ .byte 1 /* Version number */
++ .string "zR" /* NUL-terminated augmentation string */
++ .uleb128 1 /* Code alignment factor */
++ .sleb128 -4 /* Data alignment factor */
++ .byte 8 /* Return address register column */
++ .uleb128 1 /* Augmentation value length */
++ .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
++ .byte 0x0c /* DW_CFA_def_cfa */
++ .uleb128 4
++ .uleb128 4
++ .byte 0x88 /* DW_CFA_offset, column 0x8 */
++ .uleb128 1
++ .align 4
++.LENDCIE:
++
++ .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */
++.LSTARTFDE1:
++ .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */
++ .long .LSTART_vsyscall-. /* PC-relative start address */
++ .long .LEND_vsyscall-.LSTART_vsyscall
++ .uleb128 0 /* Augmentation length */
++ .align 4
++.LENDFDE1:
++
++/*
++ * Get the common code for the sigreturn entry points.
++ */
++#define SYSCALL_ENTER_KERNEL int $0x80
++#include "vsyscall-sigreturn.S"
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/ia32/vsyscall-sigreturn.S linux-2.6.18-xen/arch/x86_64/ia32/vsyscall-sigreturn.S
+--- linux-2.6.18.1/arch/x86_64/ia32/vsyscall-sigreturn.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/ia32/vsyscall-sigreturn.S 2006-09-04 16:31:03.000000000 +0200
+@@ -139,5 +139,5 @@
+ .align 4
+ .LENDFDE3:
+
+-#include "../../i386/kernel/vsyscall-note.S"
++#include <vsyscall-note.S>
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/Kconfig linux-2.6.18-xen/arch/x86_64/Kconfig
+--- linux-2.6.18.1/arch/x86_64/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/Kconfig 2006-09-22 16:38:35.000000000 +0200
+@@ -30,6 +30,7 @@
+
+ config STACKTRACE_SUPPORT
+ bool
++ depends on !X86_64_XEN
+ default y
+
+ config SEMAPHORE_SLEEPERS
+@@ -135,6 +136,22 @@
+
+ endchoice
+
++config X86_64_XEN
++ bool "Enable Xen compatible kernel"
++ select SWIOTLB
++ help
++ This option will compile a kernel compatible with Xen hypervisor
++
++config X86_NO_TSS
++ bool
++ depends on X86_64_XEN
++ default y
++
++config X86_NO_IDT
++ bool
++ depends on X86_64_XEN
++ default y
++
+ #
+ # Define implied options from the CPU selection here
+ #
+@@ -155,6 +172,7 @@
+
+ config X86_TSC
+ bool
++ depends on !X86_64_XEN
+ default y
+
+ config X86_GOOD_APIC
+@@ -197,7 +215,7 @@
+
+ config X86_HT
+ bool
+- depends on SMP && !MK8
++ depends on SMP && !MK8 && !X86_64_XEN
+ default y
+
+ config MATH_EMULATION
+@@ -211,14 +229,22 @@
+
+ config X86_IO_APIC
+ bool
++ depends !XEN_UNPRIVILEGED_GUEST
+ default y
+
++config X86_XEN_GENAPIC
++ bool
++ depends X86_64_XEN
++ default XEN_PRIVILEGED_GUEST || SMP
++
+ config X86_LOCAL_APIC
+ bool
++ depends !XEN_UNPRIVILEGED_GUEST
+ default y
+
+ config MTRR
+ bool "MTRR (Memory Type Range Register) support"
++ depends on !XEN_UNPRIVILEGED_GUEST
+ ---help---
+ On Intel P6 family processors (Pentium Pro, Pentium II and later)
+ the Memory Type Range Registers (MTRRs) may be used to control
+@@ -259,7 +285,7 @@
+
+ config SCHED_SMT
+ bool "SMT (Hyperthreading) scheduler support"
+- depends on SMP
++ depends on SMP && !X86_64_XEN
+ default n
+ help
+ SMT scheduler support improves the CPU scheduler's decision making
+@@ -269,7 +295,7 @@
+
+ config SCHED_MC
+ bool "Multi-core scheduler support"
+- depends on SMP
++ depends on SMP && !X86_64_XEN
+ default y
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+@@ -280,7 +306,7 @@
+
+ config NUMA
+ bool "Non Uniform Memory Access (NUMA) Support"
+- depends on SMP
++ depends on SMP && !X86_64_XEN
+ help
+ Enable NUMA (Non Uniform Memory Access) support. The kernel
+ will try to allocate memory used by a CPU on the local memory
+@@ -341,7 +367,7 @@
+
+ config ARCH_SPARSEMEM_ENABLE
+ def_bool y
+- depends on (NUMA || EXPERIMENTAL)
++ depends on (NUMA || EXPERIMENTAL) && !X86_64_XEN
+
+ config ARCH_MEMORY_PROBE
+ def_bool y
+@@ -365,6 +391,7 @@
+ int "Maximum number of CPUs (2-256)"
+ range 2 255
+ depends on SMP
++ default "16" if X86_64_XEN
+ default "8"
+ help
+ This allows you to specify the maximum number of CPUs which this
+@@ -387,6 +414,7 @@
+
+ config HPET_TIMER
+ bool
++ depends on !X86_64_XEN
+ default y
+ help
+ Use the IA-PC HPET (High Precision Event Timer) to manage
+@@ -407,7 +435,7 @@
+ default y
+ select SWIOTLB
+ select AGP
+- depends on PCI
++ depends on PCI && !X86_64_XEN
+ help
+ Support for full DMA access of devices with 32bit memory access only
+ on systems with more than 3GB. This is usually needed for USB,
+@@ -444,6 +472,7 @@
+
+ config X86_MCE
+ bool "Machine check support" if EMBEDDED
++ depends on !X86_64_XEN
+ default y
+ help
+ Include a machine check error handler to report hardware errors.
+@@ -469,7 +498,7 @@
+
+ config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+- depends on EXPERIMENTAL
++ depends on EXPERIMENTAL && !X86_64_XEN
+ 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
+@@ -564,8 +593,11 @@
+ default y
+
+ menu "Power management options"
++ depends on !XEN_UNPRIVILEGED_GUEST
+
++if !X86_64_XEN
+ source kernel/power/Kconfig
++endif
+
+ source "drivers/acpi/Kconfig"
+
+@@ -588,6 +620,21 @@
+ bool "Support mmconfig PCI config space access"
+ depends on PCI && ACPI
+
++config XEN_PCIDEV_FRONTEND
++ bool "Xen PCI Frontend"
++ depends on PCI && X86_64_XEN
++ default y
++ help
++ The PCI device frontend driver allows the kernel to import arbitrary
++ PCI devices from a PCI backend to support PCI driver domains.
++
++config XEN_PCIDEV_FE_DEBUG
++ bool "Xen PCI Frontend Debugging"
++ depends on XEN_PCIDEV_FRONTEND
++ default n
++ help
++ Enables some debug statements within the PCI Frontend.
++
+ source "drivers/pci/pcie/Kconfig"
+
+ source "drivers/pci/Kconfig"
+@@ -658,4 +705,6 @@
+
+ source "crypto/Kconfig"
+
++source "drivers/xen/Kconfig"
++
+ source "lib/Kconfig"
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/acpi/Makefile linux-2.6.18-xen/arch/x86_64/kernel/acpi/Makefile
+--- linux-2.6.18.1/arch/x86_64/kernel/acpi/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/kernel/acpi/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -7,3 +7,4 @@
+ processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o
+ endif
+
++boot-$(CONFIG_XEN) := ../../../i386/kernel/acpi/boot-xen.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/apic-xen.c linux-2.6.18-xen/arch/x86_64/kernel/apic-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/apic-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/apic-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ * Local APIC handling, local APIC timers
++ *
++ * (c) 1999, 2000 Ingo Molnar <mingo at redhat.com>
++ *
++ * Fixes
++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
++ * thanks to Eric Gilmore
++ * and Rolf G. Tews
++ * for testing these extensively.
++ * Maciej W. Rozycki : Various updates and fixes.
++ * Mikael Pettersson : Power Management for UP-APIC.
++ * Pavel Machek and
++ * Mikael Pettersson : PM converted to driver model.
++ */
++
++#include <linux/init.h>
++
++#include <linux/mm.h>
++#include <linux/delay.h>
++#include <linux/bootmem.h>
++#include <linux/smp_lock.h>
++#include <linux/interrupt.h>
++#include <linux/mc146818rtc.h>
++#include <linux/kernel_stat.h>
++#include <linux/sysdev.h>
++#include <linux/module.h>
++
++#include <asm/atomic.h>
++#include <asm/smp.h>
++#include <asm/mtrr.h>
++#include <asm/mpspec.h>
++#include <asm/desc.h>
++#include <asm/arch_hooks.h>
++#include <asm/hpet.h>
++#include <asm/idle.h>
++
++int apic_verbosity;
++
++/*
++ * '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);
++ /*
++ * Currently unexpected vectors happen only on SMP and APIC.
++ * We _must_ ack these because every local APIC has only N
++ * irq slots per priority level, and a 'hanging, unacked' IRQ
++ * holds up an irq slot - in excessive cases (when multiple
++ * unexpected vectors occur) that might lock up the APIC
++ * completely.
++ * But don't ack when the APIC is disabled. -AK
++ */
++ if (!disable_apic)
++ ack_APIC_irq();
++}
++
++int setup_profiling_timer(unsigned int multiplier)
++{
++ return -EINVAL;
++}
++
++void smp_local_timer_interrupt(struct pt_regs *regs)
++{
++ profile_tick(CPU_PROFILING, regs);
++#ifndef CONFIG_XEN
++#ifdef CONFIG_SMP
++ update_process_times(user_mode(regs));
++#endif
++#endif
++ /*
++ * We take the 'long' return path, and there every subsystem
++ * grabs the appropriate locks (kernel lock/ irq lock).
++ *
++ * we might want to decouple profiling from the 'long path',
++ * and do the profiling totally in assembly.
++ *
++ * Currently this isn't too much of an issue (performance wise),
++ * we can take more than 100K local irqs per second on a 100 MHz P5.
++ */
++}
++
++/*
++ * Local APIC timer interrupt. This is the most natural way for doing
++ * local interrupts, but local timer interrupts can be emulated by
++ * broadcast interrupts too. [in case the hw doesn't support APIC timers]
++ *
++ * [ if a single-CPU system runs an SMP kernel then we call the local
++ * interrupt as well. Thus we cannot inline the local irq ... ]
++ */
++void smp_apic_timer_interrupt(struct pt_regs *regs)
++{
++ /*
++ * the NMI deadlock-detector uses this.
++ */
++ add_pda(apic_timer_irqs, 1);
++
++ /*
++ * NOTE! We'd better ACK the irq immediately,
++ * because timer handling can be slow.
++ */
++ ack_APIC_irq();
++ /*
++ * update_process_times() expects us to have done irq_enter().
++ * Besides, if we don't timer interrupts ignore the global
++ * interrupt lock, which is the WrongThing (tm) to do.
++ */
++ exit_idle();
++ irq_enter();
++ smp_local_timer_interrupt(regs);
++ irq_exit();
++}
++
++/*
++ * This interrupt should _never_ happen with our APIC/SMP architecture
++ */
++asmlinkage void smp_spurious_interrupt(void)
++{
++ unsigned int v;
++ exit_idle();
++ irq_enter();
++ /*
++ * Check if this really is a spurious interrupt and ACK it
++ * if it is a vectored one. Just in case...
++ * Spurious interrupts should not be ACKed.
++ */
++ v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
++ if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
++ ack_APIC_irq();
++
++#if 0
++ static unsigned long last_warning;
++ static unsigned long skipped;
++
++ /* see sw-dev-man vol 3, chapter 7.4.13.5 */
++ if (time_before(last_warning+30*HZ,jiffies)) {
++ printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
++ smp_processor_id(), skipped);
++ last_warning = jiffies;
++ skipped = 0;
++ } else {
++ skipped++;
++ }
++#endif
++ irq_exit();
++}
++
++/*
++ * This interrupt should never happen with our APIC/SMP architecture
++ */
++
++asmlinkage void smp_error_interrupt(void)
++{
++ unsigned int v, v1;
++
++ exit_idle();
++ irq_enter();
++ /* First tickle the hardware, only then report what went on. -- REW */
++ v = apic_read(APIC_ESR);
++ apic_write(APIC_ESR, 0);
++ v1 = apic_read(APIC_ESR);
++ ack_APIC_irq();
++ atomic_inc(&irq_err_count);
++
++ /* Here is what the APIC error bits mean:
++ 0: Send CS error
++ 1: Receive CS error
++ 2: Send accept error
++ 3: Receive accept error
++ 4: Reserved
++ 5: Send illegal vector
++ 6: Received illegal vector
++ 7: Illegal register address
++ */
++ printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
++ smp_processor_id(), v , v1);
++ irq_exit();
++}
++
++int disable_apic;
++
++/*
++ * This initializes the IO-APIC and APIC hardware if this is
++ * a UP kernel.
++ */
++int __init APIC_init_uniprocessor (void)
++{
++#ifdef CONFIG_X86_IO_APIC
++ if (smp_found_config)
++ if (!skip_ioapic_setup && nr_ioapics)
++ setup_IO_APIC();
++#endif
++
++ return 1;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/asm-offsets.c linux-2.6.18-xen/arch/x86_64/kernel/asm-offsets.c
+--- linux-2.6.18.1/arch/x86_64/kernel/asm-offsets.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/kernel/asm-offsets.c 2006-09-04 16:31:03.000000000 +0200
+@@ -67,8 +67,10 @@
+ DEFINE(pbe_address, offsetof(struct pbe, address));
+ DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
+ DEFINE(pbe_next, offsetof(struct pbe, next));
++#ifndef CONFIG_X86_NO_TSS
+ BLANK();
+ DEFINE(TSS_ist, offsetof(struct tss_struct, ist));
++#endif
+ BLANK();
+ DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+ return 0;
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/e820-xen.c linux-2.6.18-xen/arch/x86_64/kernel/e820-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/e820-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/e820-xen.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,757 @@
++/*
++ * Handle the memory map.
++ * The functions here do the job until bootmem takes over.
++ *
++ * Getting sanitize_e820_map() in sync with i386 version by applying change:
++ * - Provisions for empty E820 memory regions (reported by certain BIOSes).
++ * Alex Achenbach <xela at slit.de>, December 2002.
++ * Venkatesh Pallipadi <venkatesh.pallipadi at intel.com>
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/bootmem.h>
++#include <linux/ioport.h>
++#include <linux/string.h>
++#include <linux/kexec.h>
++#include <linux/module.h>
++
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/e820.h>
++#include <asm/proto.h>
++#include <asm/bootsetup.h>
++#include <asm/sections.h>
++#include <xen/interface/memory.h>
++
++/*
++ * PFN of last memory page.
++ */
++unsigned long end_pfn;
++EXPORT_SYMBOL(end_pfn);
++
++/*
++ * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
++ * The direct mapping extends to end_pfn_map, so that we can directly access
++ * apertures, ACPI and other tables without having to play with fixmaps.
++ */
++unsigned long end_pfn_map;
++
++/*
++ * Last pfn which the user wants to use.
++ */
++unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;
++
++extern struct resource code_resource, data_resource;
++
++/* Check for some hardcoded bad areas that early boot is not allowed to touch */
++static inline int bad_addr(unsigned long *addrp, unsigned long size)
++{
++ unsigned long addr = *addrp, last = addr + size;
++
++#ifndef CONFIG_XEN
++ /* various gunk below that needed for SMP startup */
++ if (addr < 0x8000) {
++ *addrp = 0x8000;
++ return 1;
++ }
++
++ /* direct mapping tables of the kernel */
++ if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) {
++ *addrp = table_end << PAGE_SHIFT;
++ return 1;
++ }
++
++ /* initrd */
++#ifdef CONFIG_BLK_DEV_INITRD
++ if (LOADER_TYPE && INITRD_START && last >= INITRD_START &&
++ addr < INITRD_START+INITRD_SIZE) {
++ *addrp = INITRD_START + INITRD_SIZE;
++ return 1;
++ }
++#endif
++ /* kernel code + 640k memory hole (later should not be needed, but
++ be paranoid for now) */
++ if (last >= 640*1024 && addr < 1024*1024) {
++ *addrp = 1024*1024;
++ return 1;
++ }
++ if (last >= __pa_symbol(&_text) && last < __pa_symbol(&_end)) {
++ *addrp = __pa_symbol(&_end);
++ return 1;
++ }
++
++ if (last >= ebda_addr && addr < ebda_addr + ebda_size) {
++ *addrp = ebda_addr + ebda_size;
++ return 1;
++ }
++
++ /* XXX ramdisk image here? */
++#else
++ if (last < (table_end<<PAGE_SHIFT)) {
++ *addrp = table_end << PAGE_SHIFT;
++ return 1;
++ }
++#endif
++ return 0;
++}
++
++/*
++ * This function checks if any part of the range <start,end> is mapped
++ * with type.
++ */
++int __meminit
++e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
++{
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ if (type && ei->type != type)
++ continue;
++ if (ei->addr >= end || ei->addr + ei->size <= start)
++ continue;
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * This function checks if the entire range <start,end> is mapped with type.
++ *
++ * Note: this function only works correct if the e820 table is sorted and
++ * not-overlapping, which is the case
++ */
++int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type)
++{
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ if (type && ei->type != type)
++ continue;
++ /* is the region (part) in overlap with the current region ?*/
++ if (ei->addr >= end || ei->addr + ei->size <= start)
++ continue;
++
++ /* if the region is at the beginning of <start,end> we move
++ * start to the end of the region since it's ok until there
++ */
++ if (ei->addr <= start)
++ start = ei->addr + ei->size;
++ /* if start is now at or beyond end, we're done, full coverage */
++ if (start >= end)
++ return 1; /* we're done */
++ }
++ return 0;
++}
++
++/*
++ * Find a free area in a specific range.
++ */
++unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size)
++{
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ unsigned long addr = ei->addr, last;
++ if (ei->type != E820_RAM)
++ continue;
++ if (addr < start)
++ addr = start;
++ if (addr > ei->addr + ei->size)
++ continue;
++ while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
++ ;
++ last = addr + size;
++ if (last > ei->addr + ei->size)
++ continue;
++ if (last > end)
++ continue;
++ return addr;
++ }
++ return -1UL;
++}
++
++/*
++ * Free bootmem based on the e820 table for a node.
++ */
++void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
++{
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ unsigned long last, addr;
++
++ if (ei->type != E820_RAM ||
++ ei->addr+ei->size <= start ||
++ ei->addr >= end)
++ continue;
++
++ addr = round_up(ei->addr, PAGE_SIZE);
++ if (addr < start)
++ addr = start;
++
++ last = round_down(ei->addr + ei->size, PAGE_SIZE);
++ if (last >= end)
++ last = end;
++
++ if (last > addr && last-addr >= PAGE_SIZE)
++ free_bootmem_node(pgdat, addr, last-addr);
++ }
++}
++
++/*
++ * Find the highest page frame number we have available
++ */
++unsigned long __init e820_end_of_ram(void)
++{
++ int i;
++ unsigned long end_pfn = 0;
++
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ unsigned long start, end;
++
++ start = round_up(ei->addr, PAGE_SIZE);
++ end = round_down(ei->addr + ei->size, PAGE_SIZE);
++ if (start >= end)
++ continue;
++ if (ei->type == E820_RAM) {
++ if (end > end_pfn<<PAGE_SHIFT)
++ end_pfn = end>>PAGE_SHIFT;
++ } else {
++ if (end > end_pfn_map<<PAGE_SHIFT)
++ end_pfn_map = end>>PAGE_SHIFT;
++ }
++ }
++
++ if (end_pfn > end_pfn_map)
++ end_pfn_map = end_pfn;
++ if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
++ end_pfn_map = MAXMEM>>PAGE_SHIFT;
++ if (end_pfn > end_user_pfn)
++ end_pfn = end_user_pfn;
++ if (end_pfn > end_pfn_map)
++ end_pfn = end_pfn_map;
++
++ return end_pfn;
++}
++
++/*
++ * Compute how much memory is missing in a range.
++ * Unlike the other functions in this file the arguments are in page numbers.
++ */
++unsigned long __init
++e820_hole_size(unsigned long start_pfn, unsigned long end_pfn)
++{
++ unsigned long ram = 0;
++ unsigned long start = start_pfn << PAGE_SHIFT;
++ unsigned long end = end_pfn << PAGE_SHIFT;
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ unsigned long last, addr;
++
++ if (ei->type != E820_RAM ||
++ ei->addr+ei->size <= start ||
++ ei->addr >= end)
++ continue;
++
++ addr = round_up(ei->addr, PAGE_SIZE);
++ if (addr < start)
++ addr = start;
++
++ last = round_down(ei->addr + ei->size, PAGE_SIZE);
++ if (last >= end)
++ last = end;
++
++ if (last > addr)
++ ram += last - addr;
++ }
++ return ((end - start) - ram) >> PAGE_SHIFT;
++}
++
++/*
++ * Mark e820 reserved areas as busy for the resource manager.
++ */
++void __init e820_reserve_resources(struct e820entry *e820, int nr_map)
++{
++ int i;
++ for (i = 0; i < nr_map; i++) {
++ struct resource *res;
++ res = alloc_bootmem_low(sizeof(struct resource));
++ switch (e820[i].type) {
++ case E820_RAM: res->name = "System RAM"; break;
++ case E820_ACPI: res->name = "ACPI Tables"; break;
++ case E820_NVS: res->name = "ACPI Non-volatile Storage"; break;
++ default: res->name = "reserved";
++ }
++ res->start = e820[i].addr;
++ res->end = res->start + e820[i].size - 1;
++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++ request_resource(&iomem_resource, res);
++ if (e820[i].type == E820_RAM) {
++ /*
++ * We don't know which RAM region contains kernel data,
++ * so we try it repeatedly and let the resource manager
++ * test it.
++ */
++#ifndef CONFIG_XEN
++ request_resource(res, &code_resource);
++ request_resource(res, &data_resource);
++#endif
++#ifdef CONFIG_KEXEC
++ request_resource(res, &crashk_res);
++#endif
++ }
++ }
++}
++
++/*
++ * Add a memory region to the kernel e820 map.
++ */
++void __init add_memory_region(unsigned long start, unsigned long size, int type)
++{
++ int x = e820.nr_map;
++
++ if (x == E820MAX) {
++ printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
++ return;
++ }
++
++ e820.map[x].addr = start;
++ e820.map[x].size = size;
++ e820.map[x].type = type;
++ e820.nr_map++;
++}
++
++void __init e820_print_map(char *who)
++{
++ int i;
++
++ for (i = 0; i < e820.nr_map; i++) {
++ printk(" %s: %016Lx - %016Lx ", who,
++ (unsigned long long) e820.map[i].addr,
++ (unsigned long long) (e820.map[i].addr + e820.map[i].size));
++ switch (e820.map[i].type) {
++ case E820_RAM: printk("(usable)\n");
++ break;
++ case E820_RESERVED:
++ printk("(reserved)\n");
++ break;
++ case E820_ACPI:
++ printk("(ACPI data)\n");
++ break;
++ case E820_NVS:
++ printk("(ACPI NVS)\n");
++ break;
++ default: printk("type %u\n", e820.map[i].type);
++ break;
++ }
++ }
++}
++
++/*
++ * Sanitize the BIOS e820 map.
++ *
++ * Some e820 responses include overlapping entries. The following
++ * replaces the original e820 map with a new one, removing overlaps.
++ *
++ */
++static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
++{
++ struct change_member {
++ struct e820entry *pbios; /* pointer to original bios entry */
++ unsigned long long addr; /* address for this change point */
++ };
++ static struct change_member change_point_list[2*E820MAX] __initdata;
++ static struct change_member *change_point[2*E820MAX] __initdata;
++ static struct e820entry *overlap_list[E820MAX] __initdata;
++ static struct e820entry new_bios[E820MAX] __initdata;
++ struct change_member *change_tmp;
++ unsigned long current_type, last_type;
++ unsigned long long last_addr;
++ int chgidx, still_changing;
++ int overlap_entries;
++ int new_bios_entry;
++ int old_nr, new_nr, chg_nr;
++ int i;
++
++ /*
++ Visually we're performing the following (1,2,3,4 = memory types)...
++
++ Sample memory map (w/overlaps):
++ ____22__________________
++ ______________________4_
++ ____1111________________
++ _44_____________________
++ 11111111________________
++ ____________________33__
++ ___________44___________
++ __________33333_________
++ ______________22________
++ ___________________2222_
++ _________111111111______
++ _____________________11_
++ _________________4______
++
++ Sanitized equivalent (no overlap):
++ 1_______________________
++ _44_____________________
++ ___1____________________
++ ____22__________________
++ ______11________________
++ _________1______________
++ __________3_____________
++ ___________44___________
++ _____________33_________
++ _______________2________
++ ________________1_______
++ _________________4______
++ ___________________2____
++ ____________________33__
++ ______________________4_
++ */
++
++ /* if there's only one memory region, don't bother */
++ if (*pnr_map < 2)
++ return -1;
++
++ old_nr = *pnr_map;
++
++ /* bail out if we find any unreasonable addresses in bios map */
++ for (i=0; i<old_nr; i++)
++ if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
++ return -1;
++
++ /* create pointers for initial change-point information (for sorting) */
++ for (i=0; i < 2*old_nr; i++)
++ change_point[i] = &change_point_list[i];
++
++ /* record all known change-points (starting and ending addresses),
++ omitting those that are for empty memory regions */
++ chgidx = 0;
++ for (i=0; i < old_nr; i++) {
++ if (biosmap[i].size != 0) {
++ change_point[chgidx]->addr = biosmap[i].addr;
++ change_point[chgidx++]->pbios = &biosmap[i];
++ change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
++ change_point[chgidx++]->pbios = &biosmap[i];
++ }
++ }
++ chg_nr = chgidx;
++
++ /* sort change-point list by memory addresses (low -> high) */
++ still_changing = 1;
++ while (still_changing) {
++ still_changing = 0;
++ for (i=1; i < chg_nr; i++) {
++ /* if <current_addr> > <last_addr>, swap */
++ /* or, if current=<start_addr> & last=<end_addr>, swap */
++ if ((change_point[i]->addr < change_point[i-1]->addr) ||
++ ((change_point[i]->addr == change_point[i-1]->addr) &&
++ (change_point[i]->addr == change_point[i]->pbios->addr) &&
++ (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
++ )
++ {
++ change_tmp = change_point[i];
++ change_point[i] = change_point[i-1];
++ change_point[i-1] = change_tmp;
++ still_changing=1;
++ }
++ }
++ }
++
++ /* create a new bios memory map, removing overlaps */
++ overlap_entries=0; /* number of entries in the overlap table */
++ new_bios_entry=0; /* index for creating new bios map entries */
++ last_type = 0; /* start with undefined memory type */
++ last_addr = 0; /* start with 0 as last starting address */
++ /* loop through change-points, determining affect on the new bios map */
++ for (chgidx=0; chgidx < chg_nr; chgidx++)
++ {
++ /* keep track of all overlapping bios entries */
++ if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
++ {
++ /* add map entry to overlap list (> 1 entry implies an overlap) */
++ overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
++ }
++ else
++ {
++ /* remove entry from list (order independent, so swap with last) */
++ for (i=0; i<overlap_entries; i++)
++ {
++ if (overlap_list[i] == change_point[chgidx]->pbios)
++ overlap_list[i] = overlap_list[overlap_entries-1];
++ }
++ overlap_entries--;
++ }
++ /* if there are overlapping entries, decide which "type" to use */
++ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
++ current_type = 0;
++ for (i=0; i<overlap_entries; i++)
++ if (overlap_list[i]->type > current_type)
++ current_type = overlap_list[i]->type;
++ /* continue building up new bios map based on this information */
++ if (current_type != last_type) {
++ if (last_type != 0) {
++ new_bios[new_bios_entry].size =
++ change_point[chgidx]->addr - last_addr;
++ /* move forward only if the new size was non-zero */
++ if (new_bios[new_bios_entry].size != 0)
++ if (++new_bios_entry >= E820MAX)
++ break; /* no more space left for new bios entries */
++ }
++ if (current_type != 0) {
++ new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
++ new_bios[new_bios_entry].type = current_type;
++ last_addr=change_point[chgidx]->addr;
++ }
++ last_type = current_type;
++ }
++ }
++ new_nr = new_bios_entry; /* retain count for new bios entries */
++
++ /* copy new bios mapping into original location */
++ memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
++ *pnr_map = new_nr;
++
++ return 0;
++}
++
++/*
++ * Copy the BIOS e820 map into a safe place.
++ *
++ * Sanity-check it while we're at it..
++ *
++ * If we're lucky and live on a modern system, the setup code
++ * will have given us a memory map that we can use to properly
++ * set up memory. If we aren't, we'll fake a memory map.
++ *
++ * We check to see that the memory map contains at least 2 elements
++ * before we'll use it, because the detection code in setup.S may
++ * not be perfect and most every PC known to man has two memory
++ * regions: one from 0 to 640k, and one from 1mb up. (The IBM
++ * thinkpad 560x, for example, does not cooperate with the memory
++ * detection code.)
++ */
++static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
++{
++#ifndef CONFIG_XEN
++ /* Only one memory region (or negative)? Ignore it */
++ if (nr_map < 2)
++ return -1;
++#else
++ BUG_ON(nr_map < 1);
++#endif
++
++ do {
++ unsigned long start = biosmap->addr;
++ unsigned long size = biosmap->size;
++ unsigned long end = start + size;
++ unsigned long type = biosmap->type;
++
++ /* Overflow in 64 bits? Ignore the memory map. */
++ if (start > end)
++ return -1;
++
++#ifndef CONFIG_XEN
++ /*
++ * Some BIOSes claim RAM in the 640k - 1M region.
++ * Not right. Fix it up.
++ *
++ * This should be removed on Hammer which is supposed to not
++ * have non e820 covered ISA mappings there, but I had some strange
++ * problems so it stays for now. -AK
++ */
++ if (type == E820_RAM) {
++ if (start < 0x100000ULL && end > 0xA0000ULL) {
++ if (start < 0xA0000ULL)
++ add_memory_region(start, 0xA0000ULL-start, type);
++ if (end <= 0x100000ULL)
++ continue;
++ start = 0x100000ULL;
++ size = end - start;
++ }
++ }
++#endif
++
++ add_memory_region(start, size, type);
++ } while (biosmap++,--nr_map);
++ return 0;
++}
++
++#ifndef CONFIG_XEN
++void __init setup_memory_region(void)
++{
++ char *who = "BIOS-e820";
++
++ /*
++ * Try to copy the BIOS-supplied E820-map.
++ *
++ * Otherwise fake a memory map; one section from 0k->640k,
++ * the next section from 1mb->appropriate_mem_k
++ */
++ sanitize_e820_map(E820_MAP, &E820_MAP_NR);
++ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
++ unsigned long mem_size;
++
++ /* compare results from other methods and take the greater */
++ if (ALT_MEM_K < EXT_MEM_K) {
++ mem_size = EXT_MEM_K;
++ who = "BIOS-88";
++ } else {
++ mem_size = ALT_MEM_K;
++ who = "BIOS-e801";
++ }
++
++ e820.nr_map = 0;
++ add_memory_region(0, LOWMEMSIZE(), E820_RAM);
++ add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
++ }
++ printk(KERN_INFO "BIOS-provided physical RAM map:\n");
++ e820_print_map(who);
++}
++
++#else /* CONFIG_XEN */
++
++void __init setup_memory_region(void)
++{
++ int rc;
++ struct xen_memory_map memmap;
++ /*
++ * This is rather large for a stack variable but this early in
++ * the boot process we know we have plenty slack space.
++ */
++ struct e820entry map[E820MAX];
++
++ memmap.nr_entries = E820MAX;
++ set_xen_guest_handle(memmap.buffer, map);
++
++ rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
++ if ( rc == -ENOSYS ) {
++ memmap.nr_entries = 1;
++ map[0].addr = 0ULL;
++ map[0].size = xen_start_info->nr_pages << PAGE_SHIFT;
++ /* 8MB slack (to balance backend allocations). */
++ map[0].size += 8 << 20;
++ map[0].type = E820_RAM;
++ rc = 0;
++ }
++ BUG_ON(rc);
++
++ sanitize_e820_map(map, (char *)&memmap.nr_entries);
++
++ BUG_ON(copy_e820_map(map, (char)memmap.nr_entries) < 0);
++
++ printk(KERN_INFO "BIOS-provided physical RAM map:\n");
++ e820_print_map("Xen");
++}
++#endif
++
++void __init parse_memopt(char *p, char **from)
++{
++ int i;
++ unsigned long current_end;
++ unsigned long end;
++
++ end_user_pfn = memparse(p, from);
++ end_user_pfn >>= PAGE_SHIFT;
++
++ end = end_user_pfn<<PAGE_SHIFT;
++ i = e820.nr_map-1;
++ current_end = e820.map[i].addr + e820.map[i].size;
++
++ if (current_end < end) {
++ /*
++ * The e820 map ends before our requested size so
++ * extend the final entry to the requested address.
++ */
++ if (e820.map[i].type == E820_RAM)
++ e820.map[i].size = end - e820.map[i].addr;
++ else
++ add_memory_region(current_end, end - current_end, E820_RAM);
++ }
++}
++
++void __init parse_memmapopt(char *p, char **from)
++{
++ unsigned long long start_at, mem_size;
++
++ mem_size = memparse(p, from);
++ p = *from;
++ if (*p == '@') {
++ start_at = memparse(p+1, from);
++ add_memory_region(start_at, mem_size, E820_RAM);
++ } else if (*p == '#') {
++ start_at = memparse(p+1, from);
++ add_memory_region(start_at, mem_size, E820_ACPI);
++ } else if (*p == '$') {
++ start_at = memparse(p+1, from);
++ add_memory_region(start_at, mem_size, E820_RESERVED);
++ } else {
++ end_user_pfn = (mem_size >> PAGE_SHIFT);
++ }
++ p = *from;
++}
++
++unsigned long pci_mem_start = 0xaeedbabe;
++EXPORT_SYMBOL(pci_mem_start);
++
++/*
++ * Search for the biggest gap in the low 32 bits of the e820
++ * memory space. We pass this space to PCI to assign MMIO resources
++ * for hotplug or unconfigured devices in.
++ * Hopefully the BIOS let enough space left.
++ */
++__init void e820_setup_gap(struct e820entry *e820, int nr_map)
++{
++ unsigned long gapstart, gapsize, round;
++ unsigned long last;
++ int i;
++ int found = 0;
++
++ last = 0x100000000ull;
++ gapstart = 0x10000000;
++ gapsize = 0x400000;
++ i = nr_map;
++ while (--i >= 0) {
++ unsigned long long start = e820[i].addr;
++ unsigned long long end = start + e820[i].size;
++
++ /*
++ * Since "last" is at most 4GB, we know we'll
++ * fit in 32 bits if this condition is true
++ */
++ if (last > end) {
++ unsigned long gap = last - end;
++
++ if (gap > gapsize) {
++ gapsize = gap;
++ gapstart = end;
++ found = 1;
++ }
++ }
++ if (start < last)
++ last = start;
++ }
++
++ if (!found) {
++ gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
++ printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n"
++ KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n");
++ }
++
++ /*
++ * See how much we want to round up: start off with
++ * rounding to the next 1MB area.
++ */
++ round = 0x100000;
++ while ((gapsize >> 4) > round)
++ round += round;
++ /* Fun with two's complement */
++ pci_mem_start = (gapstart + round) & -round;
++
++ printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
++ pci_mem_start, gapstart, gapsize);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/early_printk-xen.c linux-2.6.18-xen/arch/x86_64/kernel/early_printk-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/early_printk-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/early_printk-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,304 @@
++
++#include <linux/console.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/screen_info.h>
++#include <asm/io.h>
++#include <asm/processor.h>
++#include <asm/fcntl.h>
++
++/* Simple VGA output */
++
++#ifdef __i386__
++#include <asm/setup.h>
++#define VGABASE (__ISA_IO_base + 0xb8000)
++#else
++#include <asm/bootsetup.h>
++#define VGABASE ((void __iomem *)0xffffffff800b8000UL)
++#endif
++
++static int max_ypos = 25, max_xpos = 80;
++static int current_ypos = 25, current_xpos = 0;
++
++#ifndef CONFIG_XEN
++static void early_vga_write(struct console *con, const char *str, unsigned n)
++{
++ char c;
++ int i, k, j;
++
++ while ((c = *str++) != '\0' && n-- > 0) {
++ if (current_ypos >= max_ypos) {
++ /* scroll 1 line up */
++ for (k = 1, j = 0; k < max_ypos; k++, j++) {
++ for (i = 0; i < max_xpos; i++) {
++ writew(readw(VGABASE+2*(max_xpos*k+i)),
++ VGABASE + 2*(max_xpos*j + i));
++ }
++ }
++ for (i = 0; i < max_xpos; i++)
++ writew(0x720, VGABASE + 2*(max_xpos*j + i));
++ current_ypos = max_ypos-1;
++ }
++ if (c == '\n') {
++ current_xpos = 0;
++ current_ypos++;
++ } else if (c != '\r') {
++ writew(((0x7 << 8) | (unsigned short) c),
++ VGABASE + 2*(max_xpos*current_ypos +
++ current_xpos++));
++ if (current_xpos >= max_xpos) {
++ current_xpos = 0;
++ current_ypos++;
++ }
++ }
++ }
++}
++
++static struct console early_vga_console = {
++ .name = "earlyvga",
++ .write = early_vga_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++/* Serial functions loosely based on a similar package from Klaus P. Gerlicher */
++
++static int early_serial_base = 0x3f8; /* ttyS0 */
++
++#define XMTRDY 0x20
++
++#define DLAB 0x80
++
++#define TXR 0 /* Transmit register (WRITE) */
++#define RXR 0 /* Receive register (READ) */
++#define IER 1 /* Interrupt Enable */
++#define IIR 2 /* Interrupt ID */
++#define FCR 2 /* FIFO control */
++#define LCR 3 /* Line control */
++#define MCR 4 /* Modem control */
++#define LSR 5 /* Line Status */
++#define MSR 6 /* Modem Status */
++#define DLL 0 /* Divisor Latch Low */
++#define DLH 1 /* Divisor latch High */
++
++static int early_serial_putc(unsigned char ch)
++{
++ unsigned timeout = 0xffff;
++ while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
++ cpu_relax();
++ outb(ch, early_serial_base + TXR);
++ return timeout ? 0 : -1;
++}
++
++static void early_serial_write(struct console *con, const char *s, unsigned n)
++{
++ while (*s && n-- > 0) {
++ early_serial_putc(*s);
++ if (*s == '\n')
++ early_serial_putc('\r');
++ s++;
++ }
++}
++
++#define DEFAULT_BAUD 9600
++
++static __init void early_serial_init(char *s)
++{
++ unsigned char c;
++ unsigned divisor;
++ unsigned baud = DEFAULT_BAUD;
++ char *e;
++
++ if (*s == ',')
++ ++s;
++
++ if (*s) {
++ unsigned port;
++ if (!strncmp(s,"0x",2)) {
++ early_serial_base = simple_strtoul(s, &e, 16);
++ } else {
++ static int bases[] = { 0x3f8, 0x2f8 };
++
++ if (!strncmp(s,"ttyS",4))
++ s += 4;
++ port = simple_strtoul(s, &e, 10);
++ if (port > 1 || s == e)
++ port = 0;
++ early_serial_base = bases[port];
++ }
++ s += strcspn(s, ",");
++ if (*s == ',')
++ s++;
++ }
++
++ outb(0x3, early_serial_base + LCR); /* 8n1 */
++ outb(0, early_serial_base + IER); /* no interrupt */
++ outb(0, early_serial_base + FCR); /* no fifo */
++ outb(0x3, early_serial_base + MCR); /* DTR + RTS */
++
++ if (*s) {
++ baud = simple_strtoul(s, &e, 0);
++ if (baud == 0 || s == e)
++ baud = DEFAULT_BAUD;
++ }
++
++ divisor = 115200 / baud;
++ c = inb(early_serial_base + LCR);
++ outb(c | DLAB, early_serial_base + LCR);
++ outb(divisor & 0xff, early_serial_base + DLL);
++ outb((divisor >> 8) & 0xff, early_serial_base + DLH);
++ outb(c & ~DLAB, early_serial_base + LCR);
++}
++
++#else /* CONFIG_XEN */
++
++#undef SCREEN_INFO
++#define SCREEN_INFO screen_info
++extern struct screen_info screen_info;
++
++static void
++early_serial_write(struct console *con, const char *s, unsigned count)
++{
++ int n;
++
++ while (count > 0) {
++ n = HYPERVISOR_console_io(CONSOLEIO_write, count, (char *)s);
++ if (n <= 0)
++ break;
++ count -= n;
++ s += n;
++ }
++}
++
++static __init void early_serial_init(char *s)
++{
++ current_xpos = 0;
++}
++
++/*
++ * No early VGA console on Xen, as we do not have convenient ISA-space
++ * mappings. Someone should fix this for domain 0. For now, use fake serial.
++ */
++#define early_vga_console early_serial_console
++
++#endif
++
++static struct console early_serial_console = {
++ .name = "earlyser",
++ .write = early_serial_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++/* Console interface to a host file on AMD's SimNow! */
++
++static int simnow_fd;
++
++enum {
++ MAGIC1 = 0xBACCD00A,
++ MAGIC2 = 0xCA110000,
++ XOPEN = 5,
++ XWRITE = 4,
++};
++
++static noinline long simnow(long cmd, long a, long b, long c)
++{
++ long ret;
++ asm volatile("cpuid" :
++ "=a" (ret) :
++ "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
++ return ret;
++}
++
++void __init simnow_init(char *str)
++{
++ char *fn = "klog";
++ if (*str == '=')
++ fn = ++str;
++ /* error ignored */
++ simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644);
++}
++
++static void simnow_write(struct console *con, const char *s, unsigned n)
++{
++ simnow(XWRITE, simnow_fd, (unsigned long)s, n);
++}
++
++static struct console simnow_console = {
++ .name = "simnow",
++ .write = simnow_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++/* Direct interface for emergencies */
++struct console *early_console = &early_vga_console;
++static int early_console_initialized = 0;
++
++void early_printk(const char *fmt, ...)
++{
++ char buf[512];
++ int n;
++ va_list ap;
++
++ va_start(ap,fmt);
++ n = vscnprintf(buf,512,fmt,ap);
++ early_console->write(early_console,buf,n);
++ va_end(ap);
++}
++
++static int __initdata keep_early;
++
++int __init setup_early_printk(char *opt)
++{
++ char *space;
++ char buf[256];
++
++ if (early_console_initialized)
++ return 1;
++
++ strlcpy(buf,opt,sizeof(buf));
++ space = strchr(buf, ' ');
++ if (space)
++ *space = 0;
++
++ if (strstr(buf,"keep"))
++ keep_early = 1;
++
++ if (!strncmp(buf, "serial", 6)) {
++ early_serial_init(buf + 6);
++ early_console = &early_serial_console;
++ } else if (!strncmp(buf, "ttyS", 4)) {
++ early_serial_init(buf);
++ early_console = &early_serial_console;
++ } else if (!strncmp(buf, "vga", 3)
++ && SCREEN_INFO.orig_video_isVGA == 1) {
++ max_xpos = SCREEN_INFO.orig_video_cols;
++ max_ypos = SCREEN_INFO.orig_video_lines;
++ current_ypos = SCREEN_INFO.orig_y;
++ early_console = &early_vga_console;
++ } else if (!strncmp(buf, "simnow", 6)) {
++ simnow_init(buf + 6);
++ early_console = &simnow_console;
++ keep_early = 1;
++ }
++ early_console_initialized = 1;
++ register_console(early_console);
++ return 0;
++}
++
++void __init disable_early_printk(void)
++{
++ if (!early_console_initialized || !early_console)
++ return;
++ if (!keep_early) {
++ printk("disabling early console\n");
++ unregister_console(early_console);
++ early_console_initialized = 0;
++ } else {
++ printk("keeping early console\n");
++ }
++}
++
++__setup("earlyprintk=", setup_early_printk);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/entry-xen.S linux-2.6.18-xen/arch/x86_64/kernel/entry-xen.S
+--- linux-2.6.18.1/arch/x86_64/kernel/entry-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/entry-xen.S 2006-09-22 16:38:35.000000000 +0200
+@@ -0,0 +1,1213 @@
++/*
++ * linux/arch/x86_64/entry.S
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
++ * Copyright (C) 2000 Pavel Machek <pavel at suse.cz>
++ *
++ * $Id$
++ *
++ * Jun Nakajima <jun.nakajima at intel.com>
++ * Asit Mallick <asit.k.mallick at intel.com>
++ * Modified for Xen
++ */
++
++/*
++ * entry.S contains the system-call and fault low-level handling routines.
++ *
++ * NOTE: This code handles signal-recognition, which happens every time
++ * after an interrupt and after each system call.
++ *
++ * Normal syscalls and interrupts don't save a full stack frame, this is
++ * only done for syscall tracing, signals or fork/exec et.al.
++ *
++ * A note on terminology:
++ * - top of stack: Architecture defined interrupt frame from SS to RIP
++ * at the top of the kernel process stack.
++ * - partial stack frame: partially saved registers upto R11.
++ * - full stack frame: Like partial stack frame, but all register saved.
++ *
++ * TODO:
++ * - schedule it carefully for the final hardware.
++ */
++
++#define ASSEMBLY 1
++#ifdef CONFIG_DEBUG_INFO
++#undef CONFIG_DEBUG_INFO
++#endif
++#include <linux/linkage.h>
++#include <asm/segment.h>
++#include <asm/smp.h>
++#include <asm/cache.h>
++#include <asm/errno.h>
++#include <asm/dwarf2.h>
++#include <asm/calling.h>
++#include <asm/asm-offsets.h>
++#include <asm/msr.h>
++#include <asm/unistd.h>
++#include <asm/thread_info.h>
++#include <asm/hw_irq.h>
++#include <asm/page.h>
++#include <asm/irqflags.h>
++#include <asm/errno.h>
++#include <xen/interface/arch-x86_64.h>
++#include <xen/interface/features.h>
++
++#include "irq_vectors.h"
++
++#include "xen_entry.S"
++
++ .code64
++
++#ifndef CONFIG_PREEMPT
++#define retint_kernel retint_restore_args
++#endif
++
++
++.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
++#ifdef CONFIG_TRACE_IRQFLAGS
++ bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
++ jnc 1f
++ TRACE_IRQS_ON
++1:
++#endif
++.endm
++
++NMI_MASK = 0x80000000
++
++/*
++ * C code is not supposed to know about undefined top of stack. Every time
++ * a C function with an pt_regs argument is called from the SYSCALL based
++ * fast path FIXUP_TOP_OF_STACK is needed.
++ * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
++ * manipulation.
++ */
++
++ /* %rsp:at FRAMEEND */
++ .macro FIXUP_TOP_OF_STACK tmp
++ movq $__USER_CS,CS(%rsp)
++ movq $-1,RCX(%rsp)
++ .endm
++
++ .macro RESTORE_TOP_OF_STACK tmp,offset=0
++ .endm
++
++ .macro FAKE_STACK_FRAME child_rip
++ /* push in order ss, rsp, eflags, cs, rip */
++ xorl %eax, %eax
++ pushq %rax /* ss */
++ CFI_ADJUST_CFA_OFFSET 8
++ /*CFI_REL_OFFSET ss,0*/
++ pushq %rax /* rsp */
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rsp,0
++ pushq $(1<<9) /* eflags - interrupts on */
++ CFI_ADJUST_CFA_OFFSET 8
++ /*CFI_REL_OFFSET rflags,0*/
++ pushq $__KERNEL_CS /* cs */
++ CFI_ADJUST_CFA_OFFSET 8
++ /*CFI_REL_OFFSET cs,0*/
++ pushq \child_rip /* rip */
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rip,0
++ pushq %rax /* orig rax */
++ CFI_ADJUST_CFA_OFFSET 8
++ .endm
++
++ .macro UNFAKE_STACK_FRAME
++ addq $8*6, %rsp
++ CFI_ADJUST_CFA_OFFSET -(6*8)
++ .endm
++
++ .macro CFI_DEFAULT_STACK start=1
++ .if \start
++ CFI_STARTPROC simple
++ CFI_DEF_CFA rsp,SS+8
++ .else
++ CFI_DEF_CFA_OFFSET SS+8
++ .endif
++ CFI_REL_OFFSET r15,R15
++ CFI_REL_OFFSET r14,R14
++ CFI_REL_OFFSET r13,R13
++ CFI_REL_OFFSET r12,R12
++ CFI_REL_OFFSET rbp,RBP
++ CFI_REL_OFFSET rbx,RBX
++ CFI_REL_OFFSET r11,R11
++ CFI_REL_OFFSET r10,R10
++ CFI_REL_OFFSET r9,R9
++ CFI_REL_OFFSET r8,R8
++ CFI_REL_OFFSET rax,RAX
++ CFI_REL_OFFSET rcx,RCX
++ CFI_REL_OFFSET rdx,RDX
++ CFI_REL_OFFSET rsi,RSI
++ CFI_REL_OFFSET rdi,RDI
++ CFI_REL_OFFSET rip,RIP
++ /*CFI_REL_OFFSET cs,CS*/
++ /*CFI_REL_OFFSET rflags,EFLAGS*/
++ CFI_REL_OFFSET rsp,RSP
++ /*CFI_REL_OFFSET ss,SS*/
++ .endm
++
++ /*
++ * Must be consistent with the definition in arch-x86_64.h:
++ * struct iret_context {
++ * u64 rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
++ * };
++ * #define VGCF_IN_SYSCALL (1<<8)
++ */
++ .macro HYPERVISOR_IRET flag
++ testb $3,1*8(%rsp)
++ jnz 2f
++ testl $NMI_MASK,2*8(%rsp)
++ jnz 2f
++
++ testb $1,(xen_features+XENFEAT_supervisor_mode_kernel)
++ jnz 1f
++
++ /* Direct iret to kernel space. Correct CS and SS. */
++ orb $3,1*8(%rsp)
++ orb $3,4*8(%rsp)
++1: iretq
++
++2: /* Slow iret via hypervisor. */
++ andl $~NMI_MASK, 16(%rsp)
++ pushq $\flag
++ jmp hypercall_page + (__HYPERVISOR_iret * 32)
++ .endm
++
++ .macro SWITCH_TO_KERNEL ssoff,adjust=0
++ jc 1f
++ orb $1,\ssoff-\adjust+4(%rsp)
++1:
++ .endm
++
++/*
++ * A newly forked process directly context switches into this.
++ */
++/* rdi: prev */
++ENTRY(ret_from_fork)
++ CFI_DEFAULT_STACK
++ call schedule_tail
++ GET_THREAD_INFO(%rcx)
++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
++ jnz rff_trace
++rff_action:
++ RESTORE_REST
++ testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
++ je int_ret_from_sys_call
++ testl $_TIF_IA32,threadinfo_flags(%rcx)
++ jnz int_ret_from_sys_call
++ RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
++ jmp ret_from_sys_call
++rff_trace:
++ movq %rsp,%rdi
++ call syscall_trace_leave
++ GET_THREAD_INFO(%rcx)
++ jmp rff_action
++ CFI_ENDPROC
++END(ret_from_fork)
++
++/*
++ * System call entry. Upto 6 arguments in registers are supported.
++ *
++ * SYSCALL does not save anything on the stack and does not change the
++ * stack pointer.
++ */
++
++/*
++ * Register setup:
++ * rax system call number
++ * rdi arg0
++ * rcx return address for syscall/sysret, C arg3
++ * rsi arg1
++ * rdx arg2
++ * r10 arg3 (--> moved to rcx for C)
++ * r8 arg4
++ * r9 arg5
++ * r11 eflags for syscall/sysret, temporary for C
++ * r12-r15,rbp,rbx saved by C code, not touched.
++ *
++ * Interrupts are off on entry.
++ * Only called from user space.
++ *
++ * XXX if we had a free scratch register we could save the RSP into the stack frame
++ * and report it properly in ps. Unfortunately we haven't.
++ *
++ * When user can change the frames always force IRET. That is because
++ * it deals with uncanonical addresses better. SYSRET has trouble
++ * with them due to bugs in both AMD and Intel CPUs.
++ */
++
++ENTRY(system_call)
++ CFI_STARTPROC simple
++ CFI_DEF_CFA rsp,PDA_STACKOFFSET
++ CFI_REGISTER rip,rcx
++ /*CFI_REGISTER rflags,r11*/
++ SAVE_ARGS -8,0
++ movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
++ /*
++ * No need to follow this irqs off/on section - it's straight
++ * and short:
++ */
++ XEN_UNBLOCK_EVENTS(%r11)
++ GET_THREAD_INFO(%rcx)
++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
++ CFI_REMEMBER_STATE
++ jnz tracesys
++ cmpq $__NR_syscall_max,%rax
++ ja badsys
++ movq %r10,%rcx
++ call *sys_call_table(,%rax,8) # XXX: rip relative
++ movq %rax,RAX-ARGOFFSET(%rsp)
++/*
++ * Syscall return path ending with SYSRET (fast path)
++ * Has incomplete stack frame and undefined top of stack.
++ */
++ .globl ret_from_sys_call
++ret_from_sys_call:
++ movl $_TIF_ALLWORK_MASK,%edi
++ /* edi: flagmask */
++sysret_check:
++ GET_THREAD_INFO(%rcx)
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ movl threadinfo_flags(%rcx),%edx
++ andl %edi,%edx
++ CFI_REMEMBER_STATE
++ jnz sysret_careful
++ /*
++ * sysretq will re-enable interrupts:
++ */
++ TRACE_IRQS_ON
++ XEN_UNBLOCK_EVENTS(%rsi)
++ CFI_REGISTER rip,rcx
++ RESTORE_ARGS 0,8,0
++ /*CFI_REGISTER rflags,r11*/
++ HYPERVISOR_IRET VGCF_IN_SYSCALL
++
++ /* Handle reschedules */
++ /* edx: work, edi: workmask */
++sysret_careful:
++ CFI_RESTORE_STATE
++ bt $TIF_NEED_RESCHED,%edx
++ jnc sysret_signal
++ TRACE_IRQS_ON
++ XEN_UNBLOCK_EVENTS(%rsi)
++ pushq %rdi
++ CFI_ADJUST_CFA_OFFSET 8
++ call schedule
++ popq %rdi
++ CFI_ADJUST_CFA_OFFSET -8
++ jmp sysret_check
++
++ /* Handle a signal */
++sysret_signal:
++ TRACE_IRQS_ON
++/* sti */
++ XEN_UNBLOCK_EVENTS(%rsi)
++ testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
++ jz 1f
++
++ /* Really a signal */
++ /* edx: work flags (arg3) */
++ leaq do_notify_resume(%rip),%rax
++ leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
++ xorl %esi,%esi # oldset -> arg2
++ call ptregscall_common
++1: movl $_TIF_NEED_RESCHED,%edi
++ /* Use IRET because user could have changed frame. This
++ works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
++ cli
++ TRACE_IRQS_OFF
++ jmp int_with_check
++
++badsys:
++ movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
++ jmp ret_from_sys_call
++
++ /* Do syscall tracing */
++tracesys:
++ CFI_RESTORE_STATE
++ SAVE_REST
++ movq $-ENOSYS,RAX(%rsp)
++ FIXUP_TOP_OF_STACK %rdi
++ movq %rsp,%rdi
++ call syscall_trace_enter
++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
++ RESTORE_REST
++ cmpq $__NR_syscall_max,%rax
++ ja 1f
++ movq %r10,%rcx /* fixup for C */
++ call *sys_call_table(,%rax,8)
++1: movq %rax,RAX-ARGOFFSET(%rsp)
++ /* Use IRET because user could have changed frame */
++ jmp int_ret_from_sys_call
++ CFI_ENDPROC
++END(system_call)
++
++/*
++ * Syscall return path ending with IRET.
++ * Has correct top of stack, but partial stack frame.
++ */
++ENTRY(int_ret_from_sys_call)
++ CFI_STARTPROC simple
++ CFI_DEF_CFA rsp,SS+8-ARGOFFSET
++ /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
++ CFI_REL_OFFSET rsp,RSP-ARGOFFSET
++ /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
++ /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
++ CFI_REL_OFFSET rip,RIP-ARGOFFSET
++ CFI_REL_OFFSET rdx,RDX-ARGOFFSET
++ CFI_REL_OFFSET rcx,RCX-ARGOFFSET
++ CFI_REL_OFFSET rax,RAX-ARGOFFSET
++ CFI_REL_OFFSET rdi,RDI-ARGOFFSET
++ CFI_REL_OFFSET rsi,RSI-ARGOFFSET
++ CFI_REL_OFFSET r8,R8-ARGOFFSET
++ CFI_REL_OFFSET r9,R9-ARGOFFSET
++ CFI_REL_OFFSET r10,R10-ARGOFFSET
++ CFI_REL_OFFSET r11,R11-ARGOFFSET
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ testb $3,CS-ARGOFFSET(%rsp)
++ jnz 1f
++ /* Need to set the proper %ss (not NULL) for ring 3 iretq */
++ movl $__KERNEL_DS,SS-ARGOFFSET(%rsp)
++ jmp retint_restore_args # retrun from ring3 kernel
++1:
++ movl $_TIF_ALLWORK_MASK,%edi
++ /* edi: mask to check */
++int_with_check:
++ GET_THREAD_INFO(%rcx)
++ movl threadinfo_flags(%rcx),%edx
++ andl %edi,%edx
++ jnz int_careful
++ andl $~TS_COMPAT,threadinfo_status(%rcx)
++ jmp retint_restore_args
++
++ /* Either reschedule or signal or syscall exit tracking needed. */
++ /* First do a reschedule test. */
++ /* edx: work, edi: workmask */
++int_careful:
++ bt $TIF_NEED_RESCHED,%edx
++ jnc int_very_careful
++ TRACE_IRQS_ON
++/* sti */
++ XEN_UNBLOCK_EVENTS(%rsi)
++ pushq %rdi
++ CFI_ADJUST_CFA_OFFSET 8
++ call schedule
++ popq %rdi
++ CFI_ADJUST_CFA_OFFSET -8
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ jmp int_with_check
++
++ /* handle signals and tracing -- both require a full stack frame */
++int_very_careful:
++ TRACE_IRQS_ON
++/* sti */
++ XEN_UNBLOCK_EVENTS(%rsi)
++ SAVE_REST
++ /* Check for syscall exit trace */
++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
++ jz int_signal
++ pushq %rdi
++ CFI_ADJUST_CFA_OFFSET 8
++ leaq 8(%rsp),%rdi # &ptregs -> arg1
++ call syscall_trace_leave
++ popq %rdi
++ CFI_ADJUST_CFA_OFFSET -8
++ andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ jmp int_restore_rest
++
++int_signal:
++ testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
++ jz 1f
++ movq %rsp,%rdi # &ptregs -> arg1
++ xorl %esi,%esi # oldset -> arg2
++ call do_notify_resume
++1: movl $_TIF_NEED_RESCHED,%edi
++int_restore_rest:
++ RESTORE_REST
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ jmp int_with_check
++ CFI_ENDPROC
++END(int_ret_from_sys_call)
++
++/*
++ * Certain special system calls that need to save a complete full stack frame.
++ */
++
++ .macro PTREGSCALL label,func,arg
++ .globl \label
++\label:
++ leaq \func(%rip),%rax
++ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
++ jmp ptregscall_common
++END(\label)
++ .endm
++
++ CFI_STARTPROC
++
++ PTREGSCALL stub_clone, sys_clone, %r8
++ PTREGSCALL stub_fork, sys_fork, %rdi
++ PTREGSCALL stub_vfork, sys_vfork, %rdi
++ PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
++ PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
++ PTREGSCALL stub_iopl, sys_iopl, %rsi
++
++ENTRY(ptregscall_common)
++ popq %r11
++ CFI_ADJUST_CFA_OFFSET -8
++ CFI_REGISTER rip, r11
++ SAVE_REST
++ movq %r11, %r15
++ CFI_REGISTER rip, r15
++ FIXUP_TOP_OF_STACK %r11
++ call *%rax
++ RESTORE_TOP_OF_STACK %r11
++ movq %r15, %r11
++ CFI_REGISTER rip, r11
++ RESTORE_REST
++ pushq %r11
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rip, 0
++ ret
++ CFI_ENDPROC
++END(ptregscall_common)
++
++ENTRY(stub_execve)
++ CFI_STARTPROC
++ popq %r11
++ CFI_ADJUST_CFA_OFFSET -8
++ CFI_REGISTER rip, r11
++ SAVE_REST
++ FIXUP_TOP_OF_STACK %r11
++ call sys_execve
++ RESTORE_TOP_OF_STACK %r11
++ movq %rax,RAX(%rsp)
++ RESTORE_REST
++ jmp int_ret_from_sys_call
++ CFI_ENDPROC
++END(stub_execve)
++
++/*
++ * sigreturn is special because it needs to restore all registers on return.
++ * This cannot be done with SYSRET, so use the IRET return path instead.
++ */
++ENTRY(stub_rt_sigreturn)
++ CFI_STARTPROC
++ addq $8, %rsp
++ CFI_ADJUST_CFA_OFFSET -8
++ SAVE_REST
++ movq %rsp,%rdi
++ FIXUP_TOP_OF_STACK %r11
++ call sys_rt_sigreturn
++ movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
++ RESTORE_REST
++ jmp int_ret_from_sys_call
++ CFI_ENDPROC
++END(stub_rt_sigreturn)
++
++/*
++ * initial frame state for interrupts and exceptions
++ */
++ .macro _frame ref
++ CFI_STARTPROC simple
++ CFI_DEF_CFA rsp,SS+8-\ref
++ /*CFI_REL_OFFSET ss,SS-\ref*/
++ CFI_REL_OFFSET rsp,RSP-\ref
++ /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
++ /*CFI_REL_OFFSET cs,CS-\ref*/
++ CFI_REL_OFFSET rip,RIP-\ref
++ .endm
++
++/* initial frame state for interrupts (and exceptions without error code) */
++#define INTR_FRAME _frame RIP
++/* initial frame state for exceptions with error code (and interrupts with
++ vector already pushed) */
++#define XCPT_FRAME _frame ORIG_RAX
++
++/*
++ * Interrupt exit.
++ *
++ */
++
++retint_check:
++ movl threadinfo_flags(%rcx),%edx
++ andl %edi,%edx
++ CFI_REMEMBER_STATE
++ jnz retint_careful
++retint_restore_args:
++ movl EFLAGS-REST_SKIP(%rsp), %eax
++ shr $9, %eax # EAX[0] == IRET_EFLAGS.IF
++ XEN_GET_VCPU_INFO(%rsi)
++ andb evtchn_upcall_mask(%rsi),%al
++ andb $1,%al # EAX[0] == IRET_EFLAGS.IF & event_mask
++ jnz restore_all_enable_events # != 0 => enable event delivery
++ XEN_PUT_VCPU_INFO(%rsi)
++ TRACE_IRQS_IRETQ
++ RESTORE_ARGS 0,8,0
++ HYPERVISOR_IRET 0
++
++ /* edi: workmask, edx: work */
++retint_careful:
++ CFI_RESTORE_STATE
++ bt $TIF_NEED_RESCHED,%edx
++ jnc retint_signal
++ TRACE_IRQS_ON
++ XEN_UNBLOCK_EVENTS(%rsi)
++/* sti */
++ pushq %rdi
++ CFI_ADJUST_CFA_OFFSET 8
++ call schedule
++ popq %rdi
++ CFI_ADJUST_CFA_OFFSET -8
++ GET_THREAD_INFO(%rcx)
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++/* cli */
++ jmp retint_check
++
++retint_signal:
++ testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
++ jz retint_restore_args
++ TRACE_IRQS_ON
++ XEN_UNBLOCK_EVENTS(%rsi)
++ SAVE_REST
++ movq $-1,ORIG_RAX(%rsp)
++ xorl %esi,%esi # oldset
++ movq %rsp,%rdi # &pt_regs
++ call do_notify_resume
++ RESTORE_REST
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ movl $_TIF_NEED_RESCHED,%edi
++ GET_THREAD_INFO(%rcx)
++ jmp retint_check
++
++#ifdef CONFIG_PREEMPT
++ /* Returning to kernel space. Check if we need preemption */
++ /* rcx: threadinfo. interrupts off. */
++ .p2align
++retint_kernel:
++ cmpl $0,threadinfo_preempt_count(%rcx)
++ jnz retint_restore_args
++ bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
++ jnc retint_restore_args
++ bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
++ jnc retint_restore_args
++ call preempt_schedule_irq
++ jmp retint_kernel /* check again */
++#endif
++
++ CFI_ENDPROC
++END(common_interrupt)
++
++/*
++ * APIC interrupts.
++ */
++ .macro apicinterrupt num,func
++ INTR_FRAME
++ pushq $~(\num)
++ CFI_ADJUST_CFA_OFFSET 8
++ interrupt \func
++ jmp error_entry
++ CFI_ENDPROC
++ .endm
++
++#ifndef CONFIG_XEN
++ENTRY(thermal_interrupt)
++ apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
++END(thermal_interrupt)
++
++ENTRY(threshold_interrupt)
++ apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
++END(threshold_interrupt)
++
++#ifdef CONFIG_SMP
++ENTRY(reschedule_interrupt)
++ apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
++END(reschedule_interrupt)
++
++ .macro INVALIDATE_ENTRY num
++ENTRY(invalidate_interrupt\num)
++ apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
++END(invalidate_interrupt\num)
++ .endm
++
++ INVALIDATE_ENTRY 0
++ INVALIDATE_ENTRY 1
++ INVALIDATE_ENTRY 2
++ INVALIDATE_ENTRY 3
++ INVALIDATE_ENTRY 4
++ INVALIDATE_ENTRY 5
++ INVALIDATE_ENTRY 6
++ INVALIDATE_ENTRY 7
++
++ENTRY(call_function_interrupt)
++ apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
++END(call_function_interrupt)
++#endif
++
++#ifdef CONFIG_X86_LOCAL_APIC
++ENTRY(apic_timer_interrupt)
++ apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
++END(apic_timer_interrupt)
++
++ENTRY(error_interrupt)
++ apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
++END(error_interrupt)
++
++ENTRY(spurious_interrupt)
++ apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
++END(spurious_interrupt)
++#endif
++#endif /* !CONFIG_XEN */
++
++/*
++ * Exception entry points.
++ */
++ .macro zeroentry sym
++ INTR_FRAME
++ movq (%rsp),%rcx
++ movq 8(%rsp),%r11
++ addq $0x10,%rsp /* skip rcx and r11 */
++ pushq $0 /* push error code/oldrax */
++ CFI_ADJUST_CFA_OFFSET 8
++ pushq %rax /* push real oldrax to the rdi slot */
++ CFI_ADJUST_CFA_OFFSET 8
++ leaq \sym(%rip),%rax
++ jmp error_entry
++ CFI_ENDPROC
++ .endm
++
++ .macro errorentry sym
++ XCPT_FRAME
++ movq (%rsp),%rcx
++ movq 8(%rsp),%r11
++ addq $0x10,%rsp /* rsp points to the error code */
++ pushq %rax
++ CFI_ADJUST_CFA_OFFSET 8
++ leaq \sym(%rip),%rax
++ jmp error_entry
++ CFI_ENDPROC
++ .endm
++
++#if 0 /* not XEN */
++ /* error code is on the stack already */
++ /* handle NMI like exceptions that can happen everywhere */
++ .macro paranoidentry sym, ist=0
++ movq (%rsp),%rcx
++ movq 8(%rsp),%r11
++ addq $0x10,%rsp /* skip rcx and r11 */
++ SAVE_ALL
++ cld
++#if 0 /* not XEN */
++ movl $1,%ebx
++ movl $MSR_GS_BASE,%ecx
++ rdmsr
++ testl %edx,%edx
++ js 1f
++ swapgs
++ xorl %ebx,%ebx
++1:
++#endif
++ .if \ist
++ movq %gs:pda_data_offset, %rbp
++ .endif
++ movq %rsp,%rdi
++ movq ORIG_RAX(%rsp),%rsi
++ movq $-1,ORIG_RAX(%rsp)
++ .if \ist
++ subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
++ .endif
++ call \sym
++ .if \ist
++ addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
++ .endif
++/* cli */
++ TRACE_IRQS_OFF
++ XEN_BLOCK_EVENTS(%rsi)
++ .endm
++#endif
++
++/*
++ * Exception entry point. This expects an error code/orig_rax on the stack
++ * and the exception handler in %rax.
++ */
++ENTRY(error_entry)
++ _frame RDI
++ /* rdi slot contains rax, oldrax contains error code */
++ cld
++ subq $14*8,%rsp
++ CFI_ADJUST_CFA_OFFSET (14*8)
++ movq %rsi,13*8(%rsp)
++ CFI_REL_OFFSET rsi,RSI
++ movq 14*8(%rsp),%rsi /* load rax from rdi slot */
++ movq %rdx,12*8(%rsp)
++ CFI_REL_OFFSET rdx,RDX
++ movq %rcx,11*8(%rsp)
++ CFI_REL_OFFSET rcx,RCX
++ movq %rsi,10*8(%rsp) /* store rax */
++ CFI_REL_OFFSET rax,RAX
++ movq %r8, 9*8(%rsp)
++ CFI_REL_OFFSET r8,R8
++ movq %r9, 8*8(%rsp)
++ CFI_REL_OFFSET r9,R9
++ movq %r10,7*8(%rsp)
++ CFI_REL_OFFSET r10,R10
++ movq %r11,6*8(%rsp)
++ CFI_REL_OFFSET r11,R11
++ movq %rbx,5*8(%rsp)
++ CFI_REL_OFFSET rbx,RBX
++ movq %rbp,4*8(%rsp)
++ CFI_REL_OFFSET rbp,RBP
++ movq %r12,3*8(%rsp)
++ CFI_REL_OFFSET r12,R12
++ movq %r13,2*8(%rsp)
++ CFI_REL_OFFSET r13,R13
++ movq %r14,1*8(%rsp)
++ CFI_REL_OFFSET r14,R14
++ movq %r15,(%rsp)
++ CFI_REL_OFFSET r15,R15
++#if 0
++ cmpl $__KERNEL_CS,CS(%rsp)
++ je error_kernelspace
++#endif
++error_call_handler:
++ movq %rdi, RDI(%rsp)
++ movq %rsp,%rdi
++ movq ORIG_RAX(%rsp),%rsi # get error code
++ movq $-1,ORIG_RAX(%rsp)
++ call *%rax
++error_exit:
++ RESTORE_REST
++/* cli */
++ XEN_BLOCK_EVENTS(%rsi)
++ TRACE_IRQS_OFF
++ GET_THREAD_INFO(%rcx)
++ testb $3,CS-ARGOFFSET(%rsp)
++ jz retint_kernel
++ movl threadinfo_flags(%rcx),%edx
++ movl $_TIF_WORK_MASK,%edi
++ andl %edi,%edx
++ jnz retint_careful
++ jmp retint_restore_args
++
++error_kernelspace:
++ /*
++ * We need to re-write the logic here because we don't do iretq to
++ * to return to user mode. It's still possible that we get trap/fault
++ * in the kernel (when accessing buffers pointed to by system calls,
++ * for example).
++ *
++ */
++#if 0
++ incl %ebx
++ /* There are two places in the kernel that can potentially fault with
++ usergs. Handle them here. The exception handlers after
++ iret run with kernel gs again, so don't set the user space flag.
++ B stepping K8s sometimes report an truncated RIP for IRET
++ exceptions returning to compat mode. Check for these here too. */
++ leaq iret_label(%rip),%rbp
++ cmpq %rbp,RIP(%rsp)
++ je error_swapgs
++ movl %ebp,%ebp /* zero extend */
++ cmpq %rbp,RIP(%rsp)
++ je error_swapgs
++ cmpq $gs_change,RIP(%rsp)
++ je error_swapgs
++ jmp error_sti
++#endif
++END(error_entry)
++
++ENTRY(hypervisor_callback)
++ zeroentry do_hypervisor_callback
++
++/*
++ * Copied from arch/xen/i386/kernel/entry.S
++ */
++# A note on the "critical region" in our callback handler.
++# We want to avoid stacking callback handlers due to events occurring
++# during handling of the last event. To do this, we keep events disabled
++# until we've done all processing. HOWEVER, we must enable events before
++# popping the stack frame (can't be done atomically) and so it would still
++# be possible to get enough handler activations to overflow the stack.
++# Although unlikely, bugs of that kind are hard to track down, so we'd
++# like to avoid the possibility.
++# So, on entry to the handler we detect whether we interrupted an
++# existing activation in its critical region -- if so, we pop the current
++# activation and restart the handler using the previous one.
++ENTRY(do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs)
++# Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
++# see the correct pointer to the pt_regs
++ movq %rdi, %rsp # we don't return, adjust the stack frame
++11: movq %gs:pda_irqstackptr,%rax
++ incl %gs:pda_irqcount
++ cmovzq %rax,%rsp
++ pushq %rdi
++ call evtchn_do_upcall
++ popq %rsp
++ decl %gs:pda_irqcount
++ jmp error_exit
++
++#ifdef CONFIG_X86_LOCAL_APIC
++KPROBE_ENTRY(nmi)
++ zeroentry do_nmi_callback
++ENTRY(do_nmi_callback)
++ addq $8, %rsp
++ call do_nmi
++ orl $NMI_MASK,EFLAGS(%rsp)
++ RESTORE_REST
++ XEN_BLOCK_EVENTS(%rsi)
++ GET_THREAD_INFO(%rcx)
++ jmp retint_restore_args
++ .previous .text
++#endif
++
++ ALIGN
++restore_all_enable_events:
++ XEN_UNBLOCK_EVENTS(%rsi) # %rsi is already set up...
++
++scrit: /**** START OF CRITICAL REGION ****/
++ XEN_TEST_PENDING(%rsi)
++ jnz 14f # process more events if necessary...
++ XEN_PUT_VCPU_INFO(%rsi)
++ RESTORE_ARGS 0,8,0
++ HYPERVISOR_IRET 0
++
++14: XEN_LOCKED_BLOCK_EVENTS(%rsi)
++ XEN_PUT_VCPU_INFO(%rsi)
++ SAVE_REST
++ movq %rsp,%rdi # set the argument again
++ jmp 11b
++ecrit: /**** END OF CRITICAL REGION ****/
++# At this point, unlike on x86-32, we don't do the fixup to simplify the
++# code and the stack frame is more complex on x86-64.
++# When the kernel is interrupted in the critical section, the kernel
++# will do IRET in that case, and everything will be restored at that point,
++# i.e. it just resumes from the next instruction interrupted with the same context.
++
++# Hypervisor uses this for application faults while it executes.
++# We get here for two reasons:
++# 1. Fault while reloading DS, ES, FS or GS
++# 2. Fault while executing IRET
++# Category 1 we do not need to fix up as Xen has already reloaded all segment
++# registers that could be reloaded and zeroed the others.
++# Category 2 we fix up by killing the current process. We cannot use the
++# normal Linux return path in this case because if we use the IRET hypercall
++# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
++# We distinguish between categories by comparing each saved segment register
++# with its current contents: any discrepancy means we in category 1.
++ENTRY(failsafe_callback)
++ movw %ds,%cx
++ cmpw %cx,0x10(%rsp)
++ jne 1f
++ movw %es,%cx
++ cmpw %cx,0x18(%rsp)
++ jne 1f
++ movw %fs,%cx
++ cmpw %cx,0x20(%rsp)
++ jne 1f
++ movw %gs,%cx
++ cmpw %cx,0x28(%rsp)
++ jne 1f
++ /* All segments match their saved values => Category 2 (Bad IRET). */
++ movq (%rsp),%rcx
++ movq 8(%rsp),%r11
++ addq $0x30,%rsp
++ movq $-9999,%rdi /* better code? */
++ jmp do_exit
++1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */
++ movq (%rsp),%rcx
++ movq 8(%rsp),%r11
++ addq $0x30,%rsp
++ pushq $0
++ SAVE_ALL
++ jmp error_exit
++#if 0
++ .section __ex_table,"a"
++ .align 8
++ .quad gs_change,bad_gs
++ .previous
++ .section .fixup,"ax"
++ /* running with kernelgs */
++bad_gs:
++/* swapgs */ /* switch back to user gs */
++ xorl %eax,%eax
++ movl %eax,%gs
++ jmp 2b
++ .previous
++#endif
++
++/*
++ * Create a kernel thread.
++ *
++ * C extern interface:
++ * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++ *
++ * asm input arguments:
++ * rdi: fn, rsi: arg, rdx: flags
++ */
++ENTRY(kernel_thread)
++ CFI_STARTPROC
++ FAKE_STACK_FRAME $child_rip
++ SAVE_ALL
++
++ # rdi: flags, rsi: usp, rdx: will be &pt_regs
++ movq %rdx,%rdi
++ orq kernel_thread_flags(%rip),%rdi
++ movq $-1, %rsi
++ movq %rsp, %rdx
++
++ xorl %r8d,%r8d
++ xorl %r9d,%r9d
++
++ # clone now
++ call do_fork
++ movq %rax,RAX(%rsp)
++ xorl %edi,%edi
++
++ /*
++ * It isn't worth to check for reschedule here,
++ * so internally to the x86_64 port you can rely on kernel_thread()
++ * not to reschedule the child before returning, this avoids the need
++ * of hacks for example to fork off the per-CPU idle tasks.
++ * [Hopefully no generic code relies on the reschedule -AK]
++ */
++ RESTORE_ALL
++ UNFAKE_STACK_FRAME
++ ret
++ CFI_ENDPROC
++ENDPROC(kernel_thread)
++
++child_rip:
++ pushq $0 # fake return address
++ CFI_STARTPROC
++ /*
++ * Here we are in the child and the registers are set as they were
++ * at kernel_thread() invocation in the parent.
++ */
++ movq %rdi, %rax
++ movq %rsi, %rdi
++ call *%rax
++ # exit
++ xorl %edi, %edi
++ call do_exit
++ CFI_ENDPROC
++ENDPROC(child_rip)
++
++/*
++ * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
++ *
++ * C extern interface:
++ * extern long execve(char *name, char **argv, char **envp)
++ *
++ * asm input arguments:
++ * rdi: name, rsi: argv, rdx: envp
++ *
++ * We want to fallback into:
++ * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
++ *
++ * do_sys_execve asm fallback arguments:
++ * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
++ */
++ENTRY(execve)
++ CFI_STARTPROC
++ FAKE_STACK_FRAME $0
++ SAVE_ALL
++ call sys_execve
++ movq %rax, RAX(%rsp)
++ RESTORE_REST
++ testq %rax,%rax
++ jne 1f
++ jmp int_ret_from_sys_call
++1: RESTORE_ARGS
++ UNFAKE_STACK_FRAME
++ ret
++ CFI_ENDPROC
++ENDPROC(execve)
++
++KPROBE_ENTRY(page_fault)
++ errorentry do_page_fault
++END(page_fault)
++ .previous .text
++
++ENTRY(coprocessor_error)
++ zeroentry do_coprocessor_error
++END(coprocessor_error)
++
++ENTRY(simd_coprocessor_error)
++ zeroentry do_simd_coprocessor_error
++END(simd_coprocessor_error)
++
++ENTRY(device_not_available)
++ zeroentry math_state_restore
++END(device_not_available)
++
++ /* runs on exception stack */
++KPROBE_ENTRY(debug)
++ INTR_FRAME
++/* pushq $0
++ CFI_ADJUST_CFA_OFFSET 8 */
++ zeroentry do_debug
++/* jmp paranoid_exit */
++ CFI_ENDPROC
++END(debug)
++ .previous .text
++
++#if 0
++ /* runs on exception stack */
++KPROBE_ENTRY(nmi)
++ INTR_FRAME
++ pushq $-1
++ CFI_ADJUST_CFA_OFFSET 8
++ paranoidentry do_nmi, 0, 0
++#ifdef CONFIG_TRACE_IRQFLAGS
++ paranoidexit 0
++#else
++ jmp paranoid_exit1
++ CFI_ENDPROC
++#endif
++END(nmi)
++ .previous .text
++#endif
++
++KPROBE_ENTRY(int3)
++ INTR_FRAME
++/* pushq $0
++ CFI_ADJUST_CFA_OFFSET 8 */
++ zeroentry do_int3
++/* jmp paranoid_exit */
++ CFI_ENDPROC
++END(int3)
++ .previous .text
++
++ENTRY(overflow)
++ zeroentry do_overflow
++END(overflow)
++
++ENTRY(bounds)
++ zeroentry do_bounds
++END(bounds)
++
++ENTRY(invalid_op)
++ zeroentry do_invalid_op
++END(invalid_op)
++
++ENTRY(coprocessor_segment_overrun)
++ zeroentry do_coprocessor_segment_overrun
++END(coprocessor_segment_overrun)
++
++ENTRY(reserved)
++ zeroentry do_reserved
++END(reserved)
++
++#if 0
++ /* runs on exception stack */
++ENTRY(double_fault)
++ XCPT_FRAME
++ paranoidentry do_double_fault
++ jmp paranoid_exit1
++ CFI_ENDPROC
++END(double_fault)
++#endif
++
++ENTRY(invalid_TSS)
++ errorentry do_invalid_TSS
++END(invalid_TSS)
++
++ENTRY(segment_not_present)
++ errorentry do_segment_not_present
++END(segment_not_present)
++ /* runs on exception stack */
++ENTRY(stack_segment)
++ XCPT_FRAME
++ errorentry do_stack_segment
++ CFI_ENDPROC
++END(stack_segment)
++
++KPROBE_ENTRY(general_protection)
++ errorentry do_general_protection
++END(general_protection)
++ .previous .text
++
++ENTRY(alignment_check)
++ errorentry do_alignment_check
++END(alignment_check)
++
++ENTRY(divide_error)
++ zeroentry do_divide_error
++END(divide_error)
++
++ENTRY(spurious_interrupt_bug)
++ zeroentry do_spurious_interrupt_bug
++END(spurious_interrupt_bug)
++
++#ifdef CONFIG_X86_MCE
++ /* runs on exception stack */
++ENTRY(machine_check)
++ INTR_FRAME
++ pushq $0
++ CFI_ADJUST_CFA_OFFSET 8
++ paranoidentry do_machine_check
++ jmp paranoid_exit1
++ CFI_ENDPROC
++END(machine_check)
++#endif
++
++ENTRY(call_softirq)
++ CFI_STARTPROC
++ push %rbp
++ CFI_ADJUST_CFA_OFFSET 8
++ CFI_REL_OFFSET rbp,0
++ mov %rsp,%rbp
++ CFI_DEF_CFA_REGISTER rbp
++ incl %gs:pda_irqcount
++ cmove %gs:pda_irqstackptr,%rsp
++ push %rbp # backlink for old unwinder
++ call __do_softirq
++ leaveq
++ CFI_DEF_CFA_REGISTER rsp
++ CFI_ADJUST_CFA_OFFSET -8
++ decl %gs:pda_irqcount
++ ret
++ CFI_ENDPROC
++ENDPROC(call_softirq)
++
++#ifdef CONFIG_STACK_UNWIND
++ENTRY(arch_unwind_init_running)
++ CFI_STARTPROC
++ movq %r15, R15(%rdi)
++ movq %r14, R14(%rdi)
++ xchgq %rsi, %rdx
++ movq %r13, R13(%rdi)
++ movq %r12, R12(%rdi)
++ xorl %eax, %eax
++ movq %rbp, RBP(%rdi)
++ movq %rbx, RBX(%rdi)
++ movq (%rsp), %rcx
++ movq %rax, R11(%rdi)
++ movq %rax, R10(%rdi)
++ movq %rax, R9(%rdi)
++ movq %rax, R8(%rdi)
++ movq %rax, RAX(%rdi)
++ movq %rax, RCX(%rdi)
++ movq %rax, RDX(%rdi)
++ movq %rax, RSI(%rdi)
++ movq %rax, RDI(%rdi)
++ movq %rax, ORIG_RAX(%rdi)
++ movq %rcx, RIP(%rdi)
++ leaq 8(%rsp), %rcx
++ movq $__KERNEL_CS, CS(%rdi)
++ movq %rax, EFLAGS(%rdi)
++ movq %rcx, RSP(%rdi)
++ movq $__KERNEL_DS, SS(%rdi)
++ jmpq *%rdx
++ CFI_ENDPROC
++ENDPROC(arch_unwind_init_running)
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/genapic_xen.c linux-2.6.18-xen/arch/x86_64/kernel/genapic_xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/genapic_xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/genapic_xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,176 @@
++/*
++ * Copyright 2004 James Cleverdon, IBM.
++ * Subject to the GNU Public License, v.2
++ *
++ * Xen APIC subarch code. Maximum 8 CPUs, logical delivery.
++ *
++ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
++ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
++ * James Cleverdon.
++ *
++ * Hacked to pieces for Xen by Chris Wright.
++ */
++#include <linux/threads.h>
++#include <linux/cpumask.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/init.h>
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++#include <asm/smp.h>
++#include <asm/ipi.h>
++#else
++#include <asm/apic.h>
++#include <asm/apicdef.h>
++#include <asm/genapic.h>
++#endif
++#include <xen/evtchn.h>
++
++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
++
++static inline void __send_IPI_one(unsigned int cpu, int vector)
++{
++ int irq = per_cpu(ipi_to_irq, cpu)[vector];
++ BUG_ON(irq < 0);
++ notify_remote_via_irq(irq);
++}
++
++void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
++{
++ int cpu;
++
++ switch (shortcut) {
++ case APIC_DEST_SELF:
++ __send_IPI_one(smp_processor_id(), vector);
++ break;
++ case APIC_DEST_ALLBUT:
++ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++ if (cpu == smp_processor_id())
++ continue;
++ if (cpu_isset(cpu, cpu_online_map)) {
++ __send_IPI_one(cpu, vector);
++ }
++ }
++ break;
++ case APIC_DEST_ALLINC:
++ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++ if (cpu_isset(cpu, cpu_online_map)) {
++ __send_IPI_one(cpu, vector);
++ }
++ }
++ break;
++ default:
++ printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
++ vector);
++ break;
++ }
++}
++
++static cpumask_t xen_target_cpus(void)
++{
++ return cpu_online_map;
++}
++
++/*
++ * Set up the logical destination ID.
++ * Do nothing, not called now.
++ */
++static void xen_init_apic_ldr(void)
++{
++ Dprintk("%s\n", __FUNCTION__);
++ return;
++}
++
++static void xen_send_IPI_mask(cpumask_t cpumask, int vector)
++{
++ unsigned long mask = cpus_addr(cpumask)[0];
++ unsigned int cpu;
++ unsigned long flags;
++
++ Dprintk("%s\n", __FUNCTION__);
++ local_irq_save(flags);
++ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
++
++ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++ if (cpu_isset(cpu, cpumask)) {
++ __send_IPI_one(cpu, vector);
++ }
++ }
++ local_irq_restore(flags);
++}
++
++static void xen_send_IPI_allbutself(int vector)
++{
++#ifdef CONFIG_HOTPLUG_CPU
++ int hotplug = 1;
++#else
++ int hotplug = 0;
++#endif
++ /*
++ * 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.
++ */
++ Dprintk("%s\n", __FUNCTION__);
++ if (hotplug || vector == NMI_VECTOR) {
++ cpumask_t allbutme = cpu_online_map;
++
++ cpu_clear(smp_processor_id(), allbutme);
++
++ if (!cpus_empty(allbutme))
++ xen_send_IPI_mask(allbutme, vector);
++ } else if (num_online_cpus() > 1) {
++ xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
++ }
++}
++
++static void xen_send_IPI_all(int vector)
++{
++ Dprintk("%s\n", __FUNCTION__);
++ if (vector == NMI_VECTOR)
++ xen_send_IPI_mask(cpu_online_map, vector);
++ else
++ xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
++}
++
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++static int xen_apic_id_registered(void)
++{
++ /* better be set */
++ Dprintk("%s\n", __FUNCTION__);
++ return physid_isset(smp_processor_id(), phys_cpu_present_map);
++}
++#endif
++
++static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask)
++{
++ Dprintk("%s\n", __FUNCTION__);
++ return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
++}
++
++static unsigned int phys_pkg_id(int index_msb)
++{
++ int ebx;
++ Dprintk("%s\n", __FUNCTION__);
++ ebx = cpuid_ebx(1);
++ return ((ebx >> 24) & 0xFF) >> index_msb;
++}
++
++struct genapic apic_xen = {
++ .name = "xen",
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++ .int_delivery_mode = dest_LowestPrio,
++#endif
++ .int_dest_mode = (APIC_DEST_LOGICAL != 0),
++ .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
++ .target_cpus = xen_target_cpus,
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++ .apic_id_registered = xen_apic_id_registered,
++#endif
++ .init_apic_ldr = xen_init_apic_ldr,
++ .send_IPI_all = xen_send_IPI_all,
++ .send_IPI_allbutself = xen_send_IPI_allbutself,
++ .send_IPI_mask = xen_send_IPI_mask,
++ .cpu_mask_to_apicid = xen_cpu_mask_to_apicid,
++ .phys_pkg_id = phys_pkg_id,
++};
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/genapic-xen.c linux-2.6.18-xen/arch/x86_64/kernel/genapic-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/genapic-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/genapic-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,143 @@
++/*
++ * Copyright 2004 James Cleverdon, IBM.
++ * Subject to the GNU Public License, v.2
++ *
++ * Generic APIC sub-arch probe layer.
++ *
++ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
++ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
++ * James Cleverdon.
++ */
++#include <linux/threads.h>
++#include <linux/cpumask.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include <asm/smp.h>
++#include <asm/ipi.h>
++
++#if defined(CONFIG_ACPI)
++#include <acpi/acpi_bus.h>
++#endif
++
++/* which logical CPU number maps to which CPU (physical APIC ID) */
++u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
++EXPORT_SYMBOL(x86_cpu_to_apicid);
++u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
++
++extern struct genapic apic_cluster;
++extern struct genapic apic_flat;
++extern struct genapic apic_physflat;
++
++#ifndef CONFIG_XEN
++struct genapic *genapic = &apic_flat;
++#else
++extern struct genapic apic_xen;
++struct genapic *genapic = &apic_xen;
++#endif
++
++
++/*
++ * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
++ */
++void __init clustered_apic_check(void)
++{
++#ifndef CONFIG_XEN
++ long i;
++ u8 clusters, max_cluster;
++ u8 id;
++ u8 cluster_cnt[NUM_APIC_CLUSTERS];
++ int max_apic = 0;
++
++#if defined(CONFIG_ACPI)
++ /*
++ * Some x86_64 machines use physical APIC mode regardless of how many
++ * procs/clusters are present (x86_64 ES7000 is an example).
++ */
++ if (acpi_fadt.revision > FADT2_REVISION_ID)
++ if (acpi_fadt.force_apic_physical_destination_mode) {
++ genapic = &apic_cluster;
++ goto print;
++ }
++#endif
++
++ memset(cluster_cnt, 0, sizeof(cluster_cnt));
++ for (i = 0; i < NR_CPUS; i++) {
++ id = bios_cpu_apicid[i];
++ if (id == BAD_APICID)
++ continue;
++ if (id > max_apic)
++ max_apic = id;
++ cluster_cnt[APIC_CLUSTERID(id)]++;
++ }
++
++ /* Don't use clustered mode on AMD platforms. */
++ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
++ genapic = &apic_physflat;
++#ifndef CONFIG_HOTPLUG_CPU
++ /* In the CPU hotplug case we cannot use broadcast mode
++ because that opens a race when a CPU is removed.
++ Stay at physflat mode in this case.
++ It is bad to do this unconditionally though. Once
++ we have ACPI platform support for CPU hotplug
++ we should detect hotplug capablity from ACPI tables and
++ only do this when really needed. -AK */
++ if (max_apic <= 8)
++ genapic = &apic_flat;
++#endif
++ goto print;
++ }
++
++ clusters = 0;
++ max_cluster = 0;
++
++ for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
++ if (cluster_cnt[i] > 0) {
++ ++clusters;
++ if (cluster_cnt[i] > max_cluster)
++ max_cluster = cluster_cnt[i];
++ }
++ }
++
++ /*
++ * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode,
++ * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical
++ * else physical mode.
++ * (We don't use lowest priority delivery + HW APIC IRQ steering, so
++ * can ignore the clustered logical case and go straight to physical.)
++ */
++ if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) {
++#ifdef CONFIG_HOTPLUG_CPU
++ /* Don't use APIC shortcuts in CPU hotplug to avoid races */
++ genapic = &apic_physflat;
++#else
++ genapic = &apic_flat;
++#endif
++ } else
++ genapic = &apic_cluster;
++
++print:
++#else
++ /* hardcode to xen apic functions */
++ genapic = &apic_xen;
++#endif
++ printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
++}
++
++/* Same for both flat and clustered. */
++
++#ifdef CONFIG_XEN
++extern void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest);
++#endif
++
++void send_IPI_self(int vector)
++{
++#ifndef CONFIG_XEN
++ __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
++#else
++ xen_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
++#endif
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/head64-xen.c linux-2.6.18-xen/arch/x86_64/kernel/head64-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/head64-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/head64-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,161 @@
++/*
++ * linux/arch/x86_64/kernel/head64.c -- prepare to run common code
++ *
++ * Copyright (C) 2000 Andrea Arcangeli <andrea at suse.de> SuSE
++ *
++ * Jun Nakajima <jun.nakajima at intel.com>
++ * Modified for Xen.
++ */
++
++#include <linux/init.h>
++#include <linux/linkage.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/percpu.h>
++#include <linux/module.h>
++
++#include <asm/processor.h>
++#include <asm/proto.h>
++#include <asm/smp.h>
++#include <asm/bootsetup.h>
++#include <asm/setup.h>
++#include <asm/desc.h>
++#include <asm/pgtable.h>
++#include <asm/sections.h>
++
++unsigned long start_pfn;
++
++/* Don't add a printk in there. printk relies on the PDA which is not initialized
++ yet. */
++#if 0
++static void __init clear_bss(void)
++{
++ memset(__bss_start, 0,
++ (unsigned long) __bss_stop - (unsigned long) __bss_start);
++}
++#endif
++
++#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
++#define OLD_CL_MAGIC_ADDR 0x90020
++#define OLD_CL_MAGIC 0xA33F
++#define OLD_CL_BASE_ADDR 0x90000
++#define OLD_CL_OFFSET 0x90022
++
++extern char saved_command_line[];
++
++static void __init copy_bootdata(char *real_mode_data)
++{
++#ifndef CONFIG_XEN
++ int new_data;
++ char * command_line;
++
++ memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE);
++ new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
++ if (!new_data) {
++ if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
++ printk("so old bootloader that it does not support commandline?!\n");
++ return;
++ }
++ new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
++ printk("old bootloader convention, maybe loadlin?\n");
++ }
++ command_line = (char *) ((u64)(new_data));
++ memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
++#else
++ int max_cmdline;
++
++ if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE)
++ max_cmdline = COMMAND_LINE_SIZE;
++ memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline);
++ saved_command_line[max_cmdline-1] = '\0';
++#endif
++ printk("Bootdata ok (command line is %s)\n", saved_command_line);
++}
++
++static void __init setup_boot_cpu_data(void)
++{
++ unsigned int dummy, eax;
++
++ /* get vendor info */
++ cpuid(0, (unsigned int *)&boot_cpu_data.cpuid_level,
++ (unsigned int *)&boot_cpu_data.x86_vendor_id[0],
++ (unsigned int *)&boot_cpu_data.x86_vendor_id[8],
++ (unsigned int *)&boot_cpu_data.x86_vendor_id[4]);
++
++ /* get cpu type */
++ cpuid(1, &eax, &dummy, &dummy,
++ (unsigned int *) &boot_cpu_data.x86_capability);
++ boot_cpu_data.x86 = (eax >> 8) & 0xf;
++ boot_cpu_data.x86_model = (eax >> 4) & 0xf;
++ boot_cpu_data.x86_mask = eax & 0xf;
++}
++
++#include <xen/interface/memory.h>
++unsigned long *machine_to_phys_mapping;
++EXPORT_SYMBOL(machine_to_phys_mapping);
++unsigned int machine_to_phys_order;
++EXPORT_SYMBOL(machine_to_phys_order);
++
++void __init x86_64_start_kernel(char * real_mode_data)
++{
++ struct xen_machphys_mapping mapping;
++ unsigned long machine_to_phys_nr_ents;
++ char *s;
++ int i;
++
++ xen_start_info = (struct start_info *)real_mode_data;
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ phys_to_machine_mapping =
++ (unsigned long *)xen_start_info->mfn_list;
++ start_pfn = (__pa(xen_start_info->pt_base) >> PAGE_SHIFT) +
++ xen_start_info->nr_pt_frames;
++ }
++
++ machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START;
++ machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
++ if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
++ machine_to_phys_mapping = (unsigned long *)mapping.v_start;
++ machine_to_phys_nr_ents = mapping.max_mfn + 1;
++ }
++ while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents )
++ machine_to_phys_order++;
++
++#if 0
++ for (i = 0; i < 256; i++)
++ set_intr_gate(i, early_idt_handler);
++ asm volatile("lidt %0" :: "m" (idt_descr));
++#endif
++
++ /*
++ * This must be called really, really early:
++ */
++ lockdep_init();
++
++ for (i = 0; i < NR_CPUS; i++)
++ cpu_pda(i) = &boot_cpu_pda[i];
++
++ pda_init(0);
++ copy_bootdata(real_mode_data);
++#ifdef CONFIG_SMP
++ cpu_set(0, cpu_online_map);
++#endif
++ s = strstr(saved_command_line, "earlyprintk=");
++ if (s != NULL)
++ setup_early_printk(strchr(s, '=') + 1);
++#ifdef CONFIG_NUMA
++ s = strstr(saved_command_line, "numa=");
++ if (s != NULL)
++ numa_setup(s+5);
++#endif
++#ifdef CONFIG_X86_IO_APIC
++ if (strstr(saved_command_line, "disableapic"))
++ disable_apic = 1;
++#endif
++ /* You need early console to see that */
++ if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE)
++ panic("Kernel too big for kernel mapping\n");
++
++ setup_boot_cpu_data();
++ start_kernel();
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/head-xen.S linux-2.6.18-xen/arch/x86_64/kernel/head-xen.S
+--- linux-2.6.18.1/arch/x86_64/kernel/head-xen.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/head-xen.S 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,191 @@
++/*
++ * linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
++ *
++ * Copyright (C) 2000 Andrea Arcangeli <andrea at suse.de> SuSE
++ * Copyright (C) 2000 Pavel Machek <pavel at suse.cz>
++ * Copyright (C) 2000 Karsten Keil <kkeil at suse.de>
++ * Copyright (C) 2001,2002 Andi Kleen <ak at suse.de>
++ *
++ * $Id: head.S,v 1.49 2002/03/19 17:39:25 ak Exp $
++ *
++ * Jun Nakajima <jun.nakajima at intel.com>
++ * Modified for Xen
++ */
++
++
++#include <linux/linkage.h>
++#include <linux/threads.h>
++#include <linux/init.h>
++#include <linux/elfnote.h>
++#include <asm/desc.h>
++#include <asm/segment.h>
++#include <asm/page.h>
++#include <asm/msr.h>
++#include <asm/cache.h>
++
++#include <xen/interface/elfnote.h>
++
++ .text
++ .section .bootstrap.text
++ .code64
++#define VIRT_ENTRY_OFFSET 0x0
++.org VIRT_ENTRY_OFFSET
++ .globl startup_64
++startup_64:
++ENTRY(_start)
++ movq $(init_thread_union+THREAD_SIZE-8),%rsp
++ /* zero EFLAGS after setting rsp */
++ pushq $0
++ popfq
++
++ /* rsi is pointer to startup info structure.
++ pass it to C */
++ movq %rsi,%rdi
++ jmp x86_64_start_kernel
++
++ENTRY(stext)
++ENTRY(_stext)
++
++ $page = 0
++#define NEXT_PAGE(name) \
++ $page = $page + 1; \
++ .org $page * 0x1000; \
++ phys_/**/name = $page * 0x1000 + __PHYSICAL_START; \
++ENTRY(name)
++
++NEXT_PAGE(init_level4_pgt)
++ /* This gets initialized in x86_64_start_kernel */
++ .fill 512,8,0
++
++ /*
++ * We update two pgd entries to make kernel and user pgd consistent
++ * at pgd_populate(). It can be used for kernel modules. So we place
++ * this page here for those cases to avoid memory corruption.
++ * We also use this page to establish the initiali mapping for
++ * vsyscall area.
++ */
++NEXT_PAGE(init_level4_user_pgt)
++ .fill 512,8,0
++
++NEXT_PAGE(level3_kernel_pgt)
++ .fill 512,8,0
++
++ /*
++ * This is used for vsyscall area mapping as we have a different
++ * level4 page table for user.
++ */
++NEXT_PAGE(level3_user_pgt)
++ .fill 512,8,0
++
++NEXT_PAGE(level2_kernel_pgt)
++ .fill 512,8,0
++
++NEXT_PAGE(hypercall_page)
++ .fill 512,8,0
++
++#undef NEXT_PAGE
++
++ .data
++
++ .align 16
++ .globl cpu_gdt_descr
++cpu_gdt_descr:
++ .word gdt_end-cpu_gdt_table-1
++gdt:
++ .quad cpu_gdt_table
++#ifdef CONFIG_SMP
++ .rept NR_CPUS-1
++ .word 0
++ .quad 0
++ .endr
++#endif
++
++/* We need valid kernel segments for data and code in long mode too
++ * IRET will check the segment types kkeil 2000/10/28
++ * Also sysret mandates a special GDT layout
++ */
++
++ .section .data.page_aligned, "aw"
++ .align PAGE_SIZE
++
++/* The TLS descriptors are currently at a different place compared to i386.
++ Hopefully nobody expects them at a fixed place (Wine?) */
++
++ENTRY(cpu_gdt_table)
++ .quad 0x0000000000000000 /* NULL descriptor */
++ .quad 0x0 /* unused */
++ .quad 0x00af9a000000ffff /* __KERNEL_CS */
++ .quad 0x00cf92000000ffff /* __KERNEL_DS */
++ .quad 0x00cffa000000ffff /* __USER32_CS */
++ .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */
++ .quad 0x00affa000000ffff /* __USER_CS */
++ .quad 0x00cf9a000000ffff /* __KERNEL32_CS */
++ .quad 0,0 /* TSS */
++ .quad 0,0 /* LDT */
++ .quad 0,0,0 /* three TLS descriptors */
++ .quad 0 /* unused */
++gdt_end:
++ /* asm/segment.h:GDT_ENTRIES must match this */
++ /* This should be a multiple of the cache line size */
++ /* GDTs of other CPUs are now dynamically allocated */
++
++ /* zero the remaining page */
++ .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0
++
++ .section .bss, "aw", @nobits
++ .align L1_CACHE_BYTES
++ENTRY(idt_table)
++ .skip 256 * 16
++
++ .section .bss.page_aligned, "aw", @nobits
++ .align PAGE_SIZE
++ENTRY(empty_zero_page)
++ .skip PAGE_SIZE
++
++#ifdef CONFIG_XEN_COMPAT_030002
++/*
++ * __xen_guest information
++ */
++.macro utoh value
++ .if (\value) < 0 || (\value) >= 0x10
++ utoh (((\value)>>4)&0x0fffffffffffffff)
++ .endif
++ .if ((\value) & 0xf) < 10
++ .byte '0' + ((\value) & 0xf)
++ .else
++ .byte 'A' + ((\value) & 0xf) - 10
++ .endif
++.endm
++
++.section __xen_guest
++ .ascii "GUEST_OS=linux,GUEST_VER=2.6"
++ .ascii ",XEN_VER=xen-3.0"
++ .ascii ",VIRT_BASE=0x"
++ utoh __START_KERNEL_map
++ .ascii ",ELF_PADDR_OFFSET=0x"
++ utoh __START_KERNEL_map
++ .ascii ",VIRT_ENTRY=0x"
++ utoh (__START_KERNEL_map + __PHYSICAL_START + VIRT_ENTRY_OFFSET)
++ .ascii ",HYPERCALL_PAGE=0x"
++ utoh (phys_hypercall_page >> PAGE_SHIFT)
++ .ascii ",FEATURES=writable_page_tables"
++ .ascii "|writable_descriptor_tables"
++ .ascii "|auto_translated_physmap"
++ .ascii "|supervisor_mode_kernel"
++ .ascii ",LOADER=generic"
++ .byte 0
++#endif /* CONFIG_XEN_COMPAT_030002 */
++
++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "linux")
++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "2.6")
++ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0")
++ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .quad, __START_KERNEL_map)
++#ifdef CONFIG_XEN_COMPAT_030002
++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, __START_KERNEL_map)
++#else
++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, 0)
++#endif /* !CONFIG_XEN_COMPAT_030002 */
++ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .quad, startup_64)
++ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .quad, hypercall_page)
++ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel")
++ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic")
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/init_task.c linux-2.6.18-xen/arch/x86_64/kernel/init_task.c
+--- linux-2.6.18.1/arch/x86_64/kernel/init_task.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/kernel/init_task.c 2006-09-04 16:31:03.000000000 +0200
+@@ -37,6 +37,8 @@
+ struct task_struct init_task = INIT_TASK(init_task);
+
+ EXPORT_SYMBOL(init_task);
++
++#ifndef CONFIG_X86_NO_TSS
+ /*
+ * per-CPU TSS segments. Threads are completely 'soft' on Linux,
+ * no more per-task TSS's. The TSS size is kept cacheline-aligned
+@@ -45,6 +47,7 @@
+ * on exact cacheline boundaries, to eliminate cacheline ping-pong.
+ */
+ DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
++#endif
+
+ /* Copies of the original ist values from the tss are only accessed during
+ * debugging, no special alignment required.
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/io_apic-xen.c linux-2.6.18-xen/arch/x86_64/kernel/io_apic-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/io_apic-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/io_apic-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,2263 @@
++/*
++ * Intel IO-APIC support for multi-Pentium hosts.
++ *
++ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo
++ *
++ * Many thanks to Stig Venaas for trying out countless experimental
++ * patches and reporting/debugging problems patiently!
++ *
++ * (c) 1999, Multiple IO-APIC support, developed by
++ * Ken-ichi Yaku <yaku at css1.kbnes.nec.co.jp> and
++ * Hidemi Kishimoto <kisimoto at css1.kbnes.nec.co.jp>,
++ * further tested and cleaned up by Zach Brown <zab at redhat.com>
++ * and Ingo Molnar <mingo at redhat.com>
++ *
++ * Fixes
++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
++ * thanks to Eric Gilmore
++ * and Rolf G. Tews
++ * for testing these extensively
++ * Paul Diefenbaugh : Added full ACPI support
++ */
++
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/smp_lock.h>
++#include <linux/mc146818rtc.h>
++#include <linux/acpi.h>
++#include <linux/sysdev.h>
++#ifdef CONFIG_ACPI
++#include <acpi/acpi_bus.h>
++#endif
++
++#include <asm/io.h>
++#include <asm/smp.h>
++#include <asm/desc.h>
++#include <asm/proto.h>
++#include <asm/mach_apic.h>
++#include <asm/acpi.h>
++#include <asm/dma.h>
++#include <asm/nmi.h>
++
++#define __apicdebuginit __init
++
++int sis_apic_bug; /* not actually supported, dummy for compile */
++
++static int no_timer_check;
++
++int disable_timer_pin_1 __initdata;
++
++#ifndef CONFIG_XEN
++int timer_over_8254 __initdata = 0;
++
++/* Where if anywhere is the i8259 connect in external int mode */
++static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
++#endif
++
++static DEFINE_SPINLOCK(ioapic_lock);
++static DEFINE_SPINLOCK(vector_lock);
++
++/*
++ * # of IRQ routing registers
++ */
++int nr_ioapic_registers[MAX_IO_APICS];
++
++/*
++ * Rough estimation of how many shared IRQs there are, can
++ * be changed anytime.
++ */
++#define MAX_PLUS_SHARED_IRQS NR_IRQ_VECTORS
++#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
++
++/*
++ * This is performance-critical, we want to do it O(1)
++ *
++ * the indexing order of this array favors 1:1 mappings
++ * between pins and IRQs.
++ */
++
++static struct irq_pin_list {
++ short apic, pin, next;
++} irq_2_pin[PIN_MAP_SIZE];
++
++int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
++#ifdef CONFIG_PCI_MSI
++#define vector_to_irq(vector) \
++ (platform_legacy_irq(vector) ? vector : vector_irq[vector])
++#else
++#define vector_to_irq(vector) (vector)
++#endif
++
++#ifdef CONFIG_XEN
++
++#include <xen/interface/xen.h>
++#include <xen/interface/physdev.h>
++
++/* Fake i8259 */
++#define make_8259A_irq(_irq) (io_apic_irqs &= ~(1UL<<(_irq)))
++#define disable_8259A_irq(_irq) ((void)0)
++#define i8259A_irq_pending(_irq) (0)
++
++unsigned long io_apic_irqs;
++
++static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg)
++{
++ struct physdev_apic apic_op;
++ int ret;
++
++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr;
++ apic_op.reg = reg;
++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
++ if (ret)
++ return ret;
++ return apic_op.value;
++}
++
++static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
++{
++ struct physdev_apic apic_op;
++
++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr;
++ apic_op.reg = reg;
++ apic_op.value = value;
++ HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
++}
++
++#define io_apic_read(a,r) xen_io_apic_read(a,r)
++#define io_apic_write(a,r,v) xen_io_apic_write(a,r,v)
++
++#define clear_IO_APIC() ((void)0)
++
++#else
++
++#ifdef CONFIG_SMP
++static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
++{
++ unsigned long flags;
++ unsigned int dest;
++ cpumask_t tmp;
++
++ cpus_and(tmp, mask, cpu_online_map);
++ if (cpus_empty(tmp))
++ tmp = TARGET_CPUS;
++
++ cpus_and(mask, tmp, CPU_MASK_ALL);
++
++ dest = cpu_mask_to_apicid(mask);
++
++ /*
++ * Only the high 8 bits are valid.
++ */
++ dest = SET_APIC_LOGICAL_ID(dest);
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ __DO_ACTION(1, = dest, )
++ set_irq_info(irq, mask);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++#endif
++
++#endif /* !CONFIG_XEN */
++
++/*
++ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
++ * shared ISA-space IRQs, so we have to support them. We are super
++ * fast in the common case, and fast for shared ISA-space IRQs.
++ */
++static void add_pin_to_irq(unsigned int irq, int apic, int pin)
++{
++ static int first_free_entry = NR_IRQS;
++ struct irq_pin_list *entry = irq_2_pin + irq;
++
++ BUG_ON(irq >= NR_IRQS);
++ while (entry->next)
++ entry = irq_2_pin + entry->next;
++
++ if (entry->pin != -1) {
++ entry->next = first_free_entry;
++ entry = irq_2_pin + entry->next;
++ if (++first_free_entry >= PIN_MAP_SIZE)
++ panic("io_apic.c: ran out of irq_2_pin entries!");
++ }
++ entry->apic = apic;
++ entry->pin = pin;
++}
++
++#ifndef CONFIG_XEN
++#define __DO_ACTION(R, ACTION, FINAL) \
++ \
++{ \
++ int pin; \
++ struct irq_pin_list *entry = irq_2_pin + irq; \
++ \
++ BUG_ON(irq >= NR_IRQS); \
++ for (;;) { \
++ unsigned int reg; \
++ pin = entry->pin; \
++ if (pin == -1) \
++ break; \
++ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
++ reg ACTION; \
++ io_apic_modify(entry->apic, reg); \
++ if (!entry->next) \
++ break; \
++ entry = irq_2_pin + entry->next; \
++ } \
++ FINAL; \
++}
++
++#define DO_ACTION(name,R,ACTION, FINAL) \
++ \
++ static void name##_IO_APIC_irq (unsigned int irq) \
++ __DO_ACTION(R, ACTION, FINAL)
++
++DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) )
++ /* mask = 1 */
++DO_ACTION( __unmask, 0, &= 0xfffeffff, )
++ /* mask = 0 */
++
++static void mask_IO_APIC_irq (unsigned int irq)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ __mask_IO_APIC_irq(irq);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++static void unmask_IO_APIC_irq (unsigned int irq)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ __unmask_IO_APIC_irq(irq);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
++{
++ struct IO_APIC_route_entry entry;
++ unsigned long flags;
++
++ /* Check delivery_mode to be sure we're not clearing an SMI pin */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
++ *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ if (entry.delivery_mode == dest_SMI)
++ return;
++ /*
++ * Disable it in the IO-APIC irq-routing table:
++ */
++ memset(&entry, 0, sizeof(entry));
++ entry.mask = 1;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++static void clear_IO_APIC (void)
++{
++ int apic, pin;
++
++ for (apic = 0; apic < nr_ioapics; apic++)
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
++ clear_IO_APIC_pin(apic, pin);
++}
++
++#endif /* !CONFIG_XEN */
++
++static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
++
++/*
++ * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
++ * specific CPU-side IRQs.
++ */
++
++#define MAX_PIRQS 8
++static int pirq_entries [MAX_PIRQS];
++static int pirqs_enabled;
++int skip_ioapic_setup;
++int ioapic_force;
++
++/* dummy parsing: see setup.c */
++
++static int __init disable_ioapic_setup(char *str)
++{
++ skip_ioapic_setup = 1;
++ return 1;
++}
++
++static int __init enable_ioapic_setup(char *str)
++{
++ ioapic_force = 1;
++ skip_ioapic_setup = 0;
++ return 1;
++}
++
++__setup("noapic", disable_ioapic_setup);
++__setup("apic", enable_ioapic_setup);
++
++#ifndef CONFIG_XEN
++static int __init setup_disable_8254_timer(char *s)
++{
++ timer_over_8254 = -1;
++ return 1;
++}
++static int __init setup_enable_8254_timer(char *s)
++{
++ timer_over_8254 = 2;
++ return 1;
++}
++
++__setup("disable_8254_timer", setup_disable_8254_timer);
++__setup("enable_8254_timer", setup_enable_8254_timer);
++#endif /* !CONFIG_XEN */
++
++#include <asm/pci-direct.h>
++#include <linux/pci_ids.h>
++#include <linux/pci.h>
++
++
++#ifdef CONFIG_ACPI
++
++static int nvidia_hpet_detected __initdata;
++
++static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
++{
++ nvidia_hpet_detected = 1;
++ return 0;
++}
++#endif
++
++/* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC
++ off. Check for an Nvidia or VIA PCI bridge and turn it off.
++ Use pci direct infrastructure because this runs before the PCI subsystem.
++
++ Can be overwritten with "apic"
++
++ And another hack to disable the IOMMU on VIA chipsets.
++
++ ... and others. Really should move this somewhere else.
++
++ Kludge-O-Rama. */
++void __init check_ioapic(void)
++{
++ int num,slot,func;
++ /* Poor man's PCI discovery */
++ for (num = 0; num < 32; num++) {
++ for (slot = 0; slot < 32; slot++) {
++ for (func = 0; func < 8; func++) {
++ u32 class;
++ u32 vendor;
++ u8 type;
++ class = read_pci_config(num,slot,func,
++ PCI_CLASS_REVISION);
++ if (class == 0xffffffff)
++ break;
++
++ if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
++ continue;
++
++ vendor = read_pci_config(num, slot, func,
++ PCI_VENDOR_ID);
++ vendor &= 0xffff;
++ switch (vendor) {
++ case PCI_VENDOR_ID_VIA:
++#ifdef CONFIG_IOMMU
++ if ((end_pfn > MAX_DMA32_PFN ||
++ force_iommu) &&
++ !iommu_aperture_allowed) {
++ printk(KERN_INFO
++ "Looks like a VIA chipset. Disabling IOMMU. Override with \"iommu=allowed\"\n");
++ iommu_aperture_disabled = 1;
++ }
++#endif
++ return;
++ case PCI_VENDOR_ID_NVIDIA:
++#ifdef CONFIG_ACPI
++ /*
++ * All timer overrides on Nvidia are
++ * wrong unless HPET is enabled.
++ */
++ nvidia_hpet_detected = 0;
++ acpi_table_parse(ACPI_HPET,
++ nvidia_hpet_check);
++ if (nvidia_hpet_detected == 0) {
++ acpi_skip_timer_override = 1;
++ printk(KERN_INFO "Nvidia board "
++ "detected. Ignoring ACPI "
++ "timer override.\n");
++ }
++#endif
++ /* RED-PEN skip them on mptables too? */
++ return;
++ case PCI_VENDOR_ID_ATI:
++
++ /* This should be actually default, but
++ for 2.6.16 let's do it for ATI only where
++ it's really needed. */
++#ifndef CONFIG_XEN
++ if (timer_over_8254 == 1) {
++ timer_over_8254 = 0;
++ printk(KERN_INFO
++ "ATI board detected. Disabling timer routing over 8254.\n");
++ }
++#endif
++ return;
++ }
++
++
++ /* No multi-function device? */
++ type = read_pci_config_byte(num,slot,func,
++ PCI_HEADER_TYPE);
++ if (!(type & 0x80))
++ break;
++ }
++ }
++ }
++}
++
++static int __init ioapic_pirq_setup(char *str)
++{
++ int i, max;
++ int ints[MAX_PIRQS+1];
++
++ get_options(str, ARRAY_SIZE(ints), ints);
++
++ for (i = 0; i < MAX_PIRQS; i++)
++ pirq_entries[i] = -1;
++
++ pirqs_enabled = 1;
++ apic_printk(APIC_VERBOSE, "PIRQ redirection, working around broken MP-BIOS.\n");
++ max = MAX_PIRQS;
++ if (ints[0] < MAX_PIRQS)
++ max = ints[0];
++
++ for (i = 0; i < max; i++) {
++ apic_printk(APIC_VERBOSE, "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
++ /*
++ * PIRQs are mapped upside down, usually.
++ */
++ pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
++ }
++ return 1;
++}
++
++__setup("pirq=", ioapic_pirq_setup);
++
++/*
++ * Find the IRQ entry number of a certain pin.
++ */
++static int find_irq_entry(int apic, int pin, int type)
++{
++ int i;
++
++ for (i = 0; i < mp_irq_entries; i++)
++ if (mp_irqs[i].mpc_irqtype == type &&
++ (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
++ mp_irqs[i].mpc_dstirq == pin)
++ return i;
++
++ return -1;
++}
++
++#ifndef CONFIG_XEN
++/*
++ * Find the pin to which IRQ[irq] (ISA) is connected
++ */
++static int __init find_isa_irq_pin(int irq, int type)
++{
++ int i;
++
++ for (i = 0; i < mp_irq_entries; i++) {
++ int lbus = mp_irqs[i].mpc_srcbus;
++
++ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
++ (mp_irqs[i].mpc_irqtype == type) &&
++ (mp_irqs[i].mpc_srcbusirq == irq))
++
++ return mp_irqs[i].mpc_dstirq;
++ }
++ return -1;
++}
++
++static int __init find_isa_irq_apic(int irq, int type)
++{
++ int i;
++
++ for (i = 0; i < mp_irq_entries; i++) {
++ int lbus = mp_irqs[i].mpc_srcbus;
++
++ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
++ mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
++ (mp_irqs[i].mpc_irqtype == type) &&
++ (mp_irqs[i].mpc_srcbusirq == irq))
++ break;
++ }
++ if (i < mp_irq_entries) {
++ int apic;
++ for(apic = 0; apic < nr_ioapics; apic++) {
++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
++ return apic;
++ }
++ }
++
++ return -1;
++}
++#endif
++
++/*
++ * Find a specific PCI IRQ entry.
++ * Not an __init, possibly needed by modules
++ */
++static int pin_2_irq(int idx, int apic, int pin);
++
++int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
++{
++ int apic, i, best_guess = -1;
++
++ apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
++ bus, slot, pin);
++ if (mp_bus_id_to_pci_bus[bus] == -1) {
++ apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
++ return -1;
++ }
++ for (i = 0; i < mp_irq_entries; i++) {
++ int lbus = mp_irqs[i].mpc_srcbus;
++
++ for (apic = 0; apic < nr_ioapics; apic++)
++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||
++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
++ break;
++
++ if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
++ !mp_irqs[i].mpc_irqtype &&
++ (bus == lbus) &&
++ (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
++ int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
++
++ if (!(apic || IO_APIC_IRQ(irq)))
++ continue;
++
++ if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
++ return irq;
++ /*
++ * Use the first all-but-pin matching entry as a
++ * best-guess fuzzy result for broken mptables.
++ */
++ if (best_guess < 0)
++ best_guess = irq;
++ }
++ }
++ BUG_ON(best_guess >= NR_IRQS);
++ return best_guess;
++}
++
++/*
++ * EISA Edge/Level control register, ELCR
++ */
++static int EISA_ELCR(unsigned int irq)
++{
++ if (irq < 16) {
++ unsigned int port = 0x4d0 + (irq >> 3);
++ return (inb(port) >> (irq & 7)) & 1;
++ }
++ apic_printk(APIC_VERBOSE, "Broken MPtable reports ISA irq %d\n", irq);
++ return 0;
++}
++
++/* EISA interrupts are always polarity zero and can be edge or level
++ * trigger depending on the ELCR value. If an interrupt is listed as
++ * EISA conforming in the MP table, that means its trigger type must
++ * be read in from the ELCR */
++
++#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
++#define default_EISA_polarity(idx) (0)
++
++/* ISA interrupts are always polarity zero edge triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_ISA_trigger(idx) (0)
++#define default_ISA_polarity(idx) (0)
++
++/* PCI interrupts are always polarity one level triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_PCI_trigger(idx) (1)
++#define default_PCI_polarity(idx) (1)
++
++/* MCA interrupts are always polarity zero level triggered,
++ * when listed as conforming in the MP table. */
++
++#define default_MCA_trigger(idx) (1)
++#define default_MCA_polarity(idx) (0)
++
++static int __init MPBIOS_polarity(int idx)
++{
++ int bus = mp_irqs[idx].mpc_srcbus;
++ int polarity;
++
++ /*
++ * Determine IRQ line polarity (high active or low active):
++ */
++ switch (mp_irqs[idx].mpc_irqflag & 3)
++ {
++ case 0: /* conforms, ie. bus-type dependent polarity */
++ {
++ switch (mp_bus_id_to_type[bus])
++ {
++ case MP_BUS_ISA: /* ISA pin */
++ {
++ polarity = default_ISA_polarity(idx);
++ break;
++ }
++ case MP_BUS_EISA: /* EISA pin */
++ {
++ polarity = default_EISA_polarity(idx);
++ break;
++ }
++ case MP_BUS_PCI: /* PCI pin */
++ {
++ polarity = default_PCI_polarity(idx);
++ break;
++ }
++ case MP_BUS_MCA: /* MCA pin */
++ {
++ polarity = default_MCA_polarity(idx);
++ break;
++ }
++ default:
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ polarity = 1;
++ break;
++ }
++ }
++ break;
++ }
++ case 1: /* high active */
++ {
++ polarity = 0;
++ break;
++ }
++ case 2: /* reserved */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ polarity = 1;
++ break;
++ }
++ case 3: /* low active */
++ {
++ polarity = 1;
++ break;
++ }
++ default: /* invalid */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ polarity = 1;
++ break;
++ }
++ }
++ return polarity;
++}
++
++static int MPBIOS_trigger(int idx)
++{
++ int bus = mp_irqs[idx].mpc_srcbus;
++ int trigger;
++
++ /*
++ * Determine IRQ trigger mode (edge or level sensitive):
++ */
++ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
++ {
++ case 0: /* conforms, ie. bus-type dependent */
++ {
++ switch (mp_bus_id_to_type[bus])
++ {
++ case MP_BUS_ISA: /* ISA pin */
++ {
++ trigger = default_ISA_trigger(idx);
++ break;
++ }
++ case MP_BUS_EISA: /* EISA pin */
++ {
++ trigger = default_EISA_trigger(idx);
++ break;
++ }
++ case MP_BUS_PCI: /* PCI pin */
++ {
++ trigger = default_PCI_trigger(idx);
++ break;
++ }
++ case MP_BUS_MCA: /* MCA pin */
++ {
++ trigger = default_MCA_trigger(idx);
++ break;
++ }
++ default:
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ trigger = 1;
++ break;
++ }
++ }
++ break;
++ }
++ case 1: /* edge */
++ {
++ trigger = 0;
++ break;
++ }
++ case 2: /* reserved */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ trigger = 1;
++ break;
++ }
++ case 3: /* level */
++ {
++ trigger = 1;
++ break;
++ }
++ default: /* invalid */
++ {
++ printk(KERN_WARNING "broken BIOS!!\n");
++ trigger = 0;
++ break;
++ }
++ }
++ return trigger;
++}
++
++static inline int irq_polarity(int idx)
++{
++ return MPBIOS_polarity(idx);
++}
++
++static inline int irq_trigger(int idx)
++{
++ return MPBIOS_trigger(idx);
++}
++
++static int next_irq = 16;
++
++/*
++ * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ
++ * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
++ * from ACPI, which can reach 800 in large boxen.
++ *
++ * Compact the sparse GSI space into a sequential IRQ series and reuse
++ * vectors if possible.
++ */
++int gsi_irq_sharing(int gsi)
++{
++ int i, tries, vector;
++
++ BUG_ON(gsi >= NR_IRQ_VECTORS);
++
++ if (platform_legacy_irq(gsi))
++ return gsi;
++
++ if (gsi_2_irq[gsi] != 0xFF)
++ return (int)gsi_2_irq[gsi];
++
++ tries = NR_IRQS;
++ try_again:
++ vector = assign_irq_vector(gsi);
++
++ /*
++ * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
++ * use of vector and if found, return that IRQ. However, we never want
++ * to share legacy IRQs, which usually have a different trigger mode
++ * than PCI.
++ */
++ for (i = 0; i < NR_IRQS; i++)
++ if (IO_APIC_VECTOR(i) == vector)
++ break;
++ if (platform_legacy_irq(i)) {
++ if (--tries >= 0) {
++ IO_APIC_VECTOR(i) = 0;
++ goto try_again;
++ }
++ panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
++ }
++ if (i < NR_IRQS) {
++ gsi_2_irq[gsi] = i;
++ printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
++ gsi, vector, i);
++ return i;
++ }
++
++ i = next_irq++;
++ BUG_ON(i >= NR_IRQS);
++ gsi_2_irq[gsi] = i;
++ IO_APIC_VECTOR(i) = vector;
++ printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
++ gsi, vector, i);
++ return i;
++}
++
++static int pin_2_irq(int idx, int apic, int pin)
++{
++ int irq, i;
++ int bus = mp_irqs[idx].mpc_srcbus;
++
++ /*
++ * Debugging check, we are in big trouble if this message pops up!
++ */
++ if (mp_irqs[idx].mpc_dstirq != pin)
++ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
++
++ switch (mp_bus_id_to_type[bus])
++ {
++ case MP_BUS_ISA: /* ISA pin */
++ case MP_BUS_EISA:
++ case MP_BUS_MCA:
++ {
++ irq = mp_irqs[idx].mpc_srcbusirq;
++ break;
++ }
++ case MP_BUS_PCI: /* PCI pin */
++ {
++ /*
++ * PCI IRQs are mapped in order
++ */
++ i = irq = 0;
++ while (i < apic)
++ irq += nr_ioapic_registers[i++];
++ irq += pin;
++ irq = gsi_irq_sharing(irq);
++ break;
++ }
++ default:
++ {
++ printk(KERN_ERR "unknown bus type %d.\n",bus);
++ irq = 0;
++ break;
++ }
++ }
++ BUG_ON(irq >= NR_IRQS);
++
++ /*
++ * PCI IRQ command line redirection. Yes, limits are hardcoded.
++ */
++ if ((pin >= 16) && (pin <= 23)) {
++ if (pirq_entries[pin-16] != -1) {
++ if (!pirq_entries[pin-16]) {
++ apic_printk(APIC_VERBOSE, "disabling PIRQ%d\n", pin-16);
++ } else {
++ irq = pirq_entries[pin-16];
++ apic_printk(APIC_VERBOSE, "using PIRQ%d -> IRQ %d\n",
++ pin-16, irq);
++ }
++ }
++ }
++ BUG_ON(irq >= NR_IRQS);
++ return irq;
++}
++
++static inline int IO_APIC_irq_trigger(int irq)
++{
++ int apic, idx, pin;
++
++ for (apic = 0; apic < nr_ioapics; apic++) {
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
++ idx = find_irq_entry(apic,pin,mp_INT);
++ if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
++ return irq_trigger(idx);
++ }
++ }
++ /*
++ * nonexistent IRQs are edge default
++ */
++ return 0;
++}
++
++/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
++u8 irq_vector[NR_IRQ_VECTORS] __read_mostly;
++
++int assign_irq_vector(int irq)
++{
++ struct physdev_irq irq_op;
++ unsigned long flags;
++
++ BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
++
++ spin_lock_irqsave(&vector_lock, flags);
++
++ if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
++ spin_unlock_irqrestore(&vector_lock, flags);
++ return IO_APIC_VECTOR(irq);
++ }
++ irq_op.irq = irq;
++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op))
++ return -ENOSPC;
++
++ vector_irq[irq_op.vector] = irq;
++ if (irq != AUTO_ASSIGN)
++ IO_APIC_VECTOR(irq) = irq_op.vector;
++
++ spin_unlock_irqrestore(&vector_lock, flags);
++ return irq_op.vector;
++}
++
++extern void (*interrupt[NR_IRQS])(void);
++#ifndef CONFIG_XEN
++static struct hw_interrupt_type ioapic_level_type;
++static struct hw_interrupt_type ioapic_edge_type;
++
++#define IOAPIC_AUTO -1
++#define IOAPIC_EDGE 0
++#define IOAPIC_LEVEL 1
++
++static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
++{
++ unsigned idx;
++
++ idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
++
++ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
++ trigger == IOAPIC_LEVEL)
++ irq_desc[idx].chip = &ioapic_level_type;
++ else
++ irq_desc[idx].chip = &ioapic_edge_type;
++ set_intr_gate(vector, interrupt[idx]);
++}
++#else
++#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0)
++#endif /* !CONFIG_XEN */
++
++static void __init setup_IO_APIC_irqs(void)
++{
++ struct IO_APIC_route_entry entry;
++ int apic, pin, idx, irq, first_notcon = 1, vector;
++ unsigned long flags;
++
++ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
++
++ for (apic = 0; apic < nr_ioapics; apic++) {
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
++
++ /*
++ * add it to the IO-APIC irq-routing table:
++ */
++ memset(&entry,0,sizeof(entry));
++
++ entry.delivery_mode = INT_DELIVERY_MODE;
++ entry.dest_mode = INT_DEST_MODE;
++ entry.mask = 0; /* enable IRQ */
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++
++ idx = find_irq_entry(apic,pin,mp_INT);
++ if (idx == -1) {
++ if (first_notcon) {
++ apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
++ first_notcon = 0;
++ } else
++ apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin);
++ continue;
++ }
++
++ entry.trigger = irq_trigger(idx);
++ entry.polarity = irq_polarity(idx);
++
++ if (irq_trigger(idx)) {
++ entry.trigger = 1;
++ entry.mask = 1;
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++ }
++
++ irq = pin_2_irq(idx, apic, pin);
++ add_pin_to_irq(irq, apic, pin);
++
++ if (/* !apic && */ !IO_APIC_IRQ(irq))
++ continue;
++
++ if (IO_APIC_IRQ(irq)) {
++ vector = assign_irq_vector(irq);
++ entry.vector = vector;
++
++ ioapic_register_intr(irq, vector, IOAPIC_AUTO);
++ if (!apic && (irq < 16))
++ disable_8259A_irq(irq);
++ }
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
++ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
++ set_native_irq_info(irq, TARGET_CPUS);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ }
++ }
++
++ if (!first_notcon)
++ apic_printk(APIC_VERBOSE," not connected.\n");
++}
++
++#ifndef CONFIG_XEN
++/*
++ * Set up the 8259A-master output pin as broadcast to all
++ * CPUs.
++ */
++static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
++{
++ struct IO_APIC_route_entry entry;
++ unsigned long flags;
++
++ memset(&entry,0,sizeof(entry));
++
++ disable_8259A_irq(0);
++
++ /* mask LVT0 */
++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
++
++ /*
++ * We use logical delivery to get the timer IRQ
++ * to the first CPU.
++ */
++ entry.dest_mode = INT_DEST_MODE;
++ entry.mask = 0; /* unmask IRQ now */
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++ entry.delivery_mode = INT_DELIVERY_MODE;
++ entry.polarity = 0;
++ entry.trigger = 0;
++ entry.vector = vector;
++
++ /*
++ * The timer IRQ doesn't have to know that behind the
++ * scene we have a 8259A-master in AEOI mode ...
++ */
++ irq_desc[0].chip = &ioapic_edge_type;
++
++ /*
++ * Add it to the IO-APIC irq-routing table:
++ */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
++ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ enable_8259A_irq(0);
++}
++
++void __init UNEXPECTED_IO_APIC(void)
++{
++}
++
++void __apicdebuginit print_IO_APIC(void)
++{
++ int apic, i;
++ union IO_APIC_reg_00 reg_00;
++ union IO_APIC_reg_01 reg_01;
++ union IO_APIC_reg_02 reg_02;
++ unsigned long flags;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
++ for (i = 0; i < nr_ioapics; i++)
++ printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
++ mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
++
++ /*
++ * We are a bit conservative about what we expect. We have to
++ * know about every hardware change ASAP.
++ */
++ printk(KERN_INFO "testing the IO APIC.......................\n");
++
++ for (apic = 0; apic < nr_ioapics; apic++) {
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(apic, 0);
++ reg_01.raw = io_apic_read(apic, 1);
++ if (reg_01.bits.version >= 0x10)
++ reg_02.raw = io_apic_read(apic, 2);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ printk("\n");
++ printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
++ printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
++ printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
++ if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
++ UNEXPECTED_IO_APIC();
++
++ printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01);
++ printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
++ if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */
++ (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */
++ (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */
++ (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */
++ (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
++ (reg_01.bits.entries != 0x2E) &&
++ (reg_01.bits.entries != 0x3F) &&
++ (reg_01.bits.entries != 0x03)
++ )
++ UNEXPECTED_IO_APIC();
++
++ printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
++ printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
++ if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */
++ (reg_01.bits.version != 0x02) && /* 82801BA IO-APICs (ICH2) */
++ (reg_01.bits.version != 0x10) && /* oldest IO-APICs */
++ (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
++ (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
++ (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */
++ )
++ UNEXPECTED_IO_APIC();
++ if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
++ UNEXPECTED_IO_APIC();
++
++ if (reg_01.bits.version >= 0x10) {
++ printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
++ printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
++ if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
++ UNEXPECTED_IO_APIC();
++ }
++
++ printk(KERN_DEBUG ".... IRQ redirection table:\n");
++
++ printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
++ " Stat Dest Deli Vect: \n");
++
++ for (i = 0; i <= reg_01.bits.entries; i++) {
++ struct IO_APIC_route_entry entry;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
++ *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ printk(KERN_DEBUG " %02x %03X %02X ",
++ i,
++ entry.dest.logical.logical_dest,
++ entry.dest.physical.physical_dest
++ );
++
++ printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
++ entry.mask,
++ entry.trigger,
++ entry.irr,
++ entry.polarity,
++ entry.delivery_status,
++ entry.dest_mode,
++ entry.delivery_mode,
++ entry.vector
++ );
++ }
++ }
++ if (use_pci_vector())
++ printk(KERN_INFO "Using vector-based indexing\n");
++ printk(KERN_DEBUG "IRQ to pin mappings:\n");
++ for (i = 0; i < NR_IRQS; i++) {
++ struct irq_pin_list *entry = irq_2_pin + i;
++ if (entry->pin < 0)
++ continue;
++ if (use_pci_vector() && !platform_legacy_irq(i))
++ printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
++ else
++ printk(KERN_DEBUG "IRQ%d ", i);
++ for (;;) {
++ printk("-> %d:%d", entry->apic, entry->pin);
++ if (!entry->next)
++ break;
++ entry = irq_2_pin + entry->next;
++ }
++ printk("\n");
++ }
++
++ printk(KERN_INFO ".................................... done.\n");
++
++ return;
++}
++
++#if 0
++
++static __apicdebuginit void print_APIC_bitfield (int base)
++{
++ unsigned int v;
++ int i, j;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);
++ for (i = 0; i < 8; i++) {
++ v = apic_read(base + i*0x10);
++ for (j = 0; j < 32; j++) {
++ if (v & (1<<j))
++ printk("1");
++ else
++ printk("0");
++ }
++ printk("\n");
++ }
++}
++
++void __apicdebuginit print_local_APIC(void * dummy)
++{
++ unsigned int v, ver, maxlvt;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
++ smp_processor_id(), hard_smp_processor_id());
++ v = apic_read(APIC_ID);
++ printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v));
++ v = apic_read(APIC_LVR);
++ printk(KERN_INFO "... APIC VERSION: %08x\n", v);
++ ver = GET_APIC_VERSION(v);
++ maxlvt = get_maxlvt();
++
++ v = apic_read(APIC_TASKPRI);
++ printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
++
++ v = apic_read(APIC_ARBPRI);
++ printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
++ v & APIC_ARBPRI_MASK);
++ v = apic_read(APIC_PROCPRI);
++ printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
++
++ v = apic_read(APIC_EOI);
++ printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
++ v = apic_read(APIC_RRR);
++ printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
++ v = apic_read(APIC_LDR);
++ printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
++ v = apic_read(APIC_DFR);
++ printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
++ v = apic_read(APIC_SPIV);
++ printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
++
++ printk(KERN_DEBUG "... APIC ISR field:\n");
++ print_APIC_bitfield(APIC_ISR);
++ printk(KERN_DEBUG "... APIC TMR field:\n");
++ print_APIC_bitfield(APIC_TMR);
++ printk(KERN_DEBUG "... APIC IRR field:\n");
++ print_APIC_bitfield(APIC_IRR);
++
++ v = apic_read(APIC_ESR);
++ printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
++
++ v = apic_read(APIC_ICR);
++ printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
++ v = apic_read(APIC_ICR2);
++ printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
++
++ v = apic_read(APIC_LVTT);
++ printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
++
++ if (maxlvt > 3) { /* PC is LVT#4. */
++ v = apic_read(APIC_LVTPC);
++ printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
++ }
++ v = apic_read(APIC_LVT0);
++ printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
++ v = apic_read(APIC_LVT1);
++ printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
++
++ if (maxlvt > 2) { /* ERR is LVT#3. */
++ v = apic_read(APIC_LVTERR);
++ printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
++ }
++
++ v = apic_read(APIC_TMICT);
++ printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
++ v = apic_read(APIC_TMCCT);
++ printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
++ v = apic_read(APIC_TDCR);
++ printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
++ printk("\n");
++}
++
++void print_all_local_APICs (void)
++{
++ on_each_cpu(print_local_APIC, NULL, 1, 1);
++}
++
++void __apicdebuginit print_PIC(void)
++{
++ unsigned int v;
++ unsigned long flags;
++
++ if (apic_verbosity == APIC_QUIET)
++ return;
++
++ printk(KERN_DEBUG "\nprinting PIC contents\n");
++
++ spin_lock_irqsave(&i8259A_lock, flags);
++
++ v = inb(0xa1) << 8 | inb(0x21);
++ printk(KERN_DEBUG "... PIC IMR: %04x\n", v);
++
++ v = inb(0xa0) << 8 | inb(0x20);
++ printk(KERN_DEBUG "... PIC IRR: %04x\n", v);
++
++ outb(0x0b,0xa0);
++ outb(0x0b,0x20);
++ v = inb(0xa0) << 8 | inb(0x20);
++ outb(0x0a,0xa0);
++ outb(0x0a,0x20);
++
++ spin_unlock_irqrestore(&i8259A_lock, flags);
++
++ printk(KERN_DEBUG "... PIC ISR: %04x\n", v);
++
++ v = inb(0x4d1) << 8 | inb(0x4d0);
++ printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
++}
++
++#endif /* 0 */
++
++#else
++void __init print_IO_APIC(void) { }
++#endif /* !CONFIG_XEN */
++
++static void __init enable_IO_APIC(void)
++{
++ union IO_APIC_reg_01 reg_01;
++#ifndef CONFIG_XEN
++ int i8259_apic, i8259_pin;
++#endif
++ int i, apic;
++ unsigned long flags;
++
++ for (i = 0; i < PIN_MAP_SIZE; i++) {
++ irq_2_pin[i].pin = -1;
++ irq_2_pin[i].next = 0;
++ }
++ if (!pirqs_enabled)
++ for (i = 0; i < MAX_PIRQS; i++)
++ pirq_entries[i] = -1;
++
++ /*
++ * The number of IO-APIC IRQ registers (== #pins):
++ */
++ for (apic = 0; apic < nr_ioapics; apic++) {
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_01.raw = io_apic_read(apic, 1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ nr_ioapic_registers[apic] = reg_01.bits.entries+1;
++ }
++#ifndef CONFIG_XEN
++ for(apic = 0; apic < nr_ioapics; apic++) {
++ int pin;
++ /* See if any of the pins is in ExtINT mode */
++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
++ struct IO_APIC_route_entry entry;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
++ *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++
++ /* If the interrupt line is enabled and in ExtInt mode
++ * I have found the pin where the i8259 is connected.
++ */
++ if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {
++ ioapic_i8259.apic = apic;
++ ioapic_i8259.pin = pin;
++ goto found_i8259;
++ }
++ }
++ }
++ found_i8259:
++ /* Look to see what if the MP table has reported the ExtINT */
++ i8259_pin = find_isa_irq_pin(0, mp_ExtINT);
++ i8259_apic = find_isa_irq_apic(0, mp_ExtINT);
++ /* Trust the MP table if nothing is setup in the hardware */
++ if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {
++ printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");
++ ioapic_i8259.pin = i8259_pin;
++ ioapic_i8259.apic = i8259_apic;
++ }
++ /* Complain if the MP table and the hardware disagree */
++ if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&
++ (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))
++ {
++ printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");
++ }
++#endif
++
++ /*
++ * Do not trust the IO-APIC being empty at bootup
++ */
++ clear_IO_APIC();
++}
++
++/*
++ * Not an __init, needed by the reboot code
++ */
++void disable_IO_APIC(void)
++{
++ /*
++ * Clear the IO-APIC before rebooting:
++ */
++ clear_IO_APIC();
++
++#ifndef CONFIG_XEN
++ /*
++ * If the i8259 is routed through an IOAPIC
++ * Put that IOAPIC in virtual wire mode
++ * so legacy interrupts can be delivered.
++ */
++ if (ioapic_i8259.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 = dest_ExtINT; /* ExtInt */
++ entry.vector = 0;
++ entry.dest.physical.physical_dest =
++ GET_APIC_ID(apic_read(APIC_ID));
++
++ /*
++ * Add it to the IO-APIC irq-routing table:
++ */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin,
++ *(((int *)&entry)+1));
++ io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin,
++ *(((int *)&entry)+0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ }
++
++ disconnect_bsp_APIC(ioapic_i8259.pin != -1);
++#endif
++}
++
++/*
++ * function to set the IO-APIC physical IDs based on the
++ * values stored in the MPC table.
++ *
++ * by Matt Domsch <Matt_Domsch at dell.com> Tue Dec 21 12:25:05 CST 1999
++ */
++
++#ifndef CONFIG_XEN
++static void __init setup_ioapic_ids_from_mpc (void)
++{
++ union IO_APIC_reg_00 reg_00;
++ int apic;
++ int i;
++ unsigned char old_id;
++ unsigned long flags;
++
++ /*
++ * Set the IOAPIC ID to the value stored in the MPC table.
++ */
++ for (apic = 0; apic < nr_ioapics; apic++) {
++
++ /* Read the register 0 value */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(apic, 0);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ old_id = mp_ioapics[apic].mpc_apicid;
++
++
++ printk(KERN_INFO "Using IO-APIC %d\n", mp_ioapics[apic].mpc_apicid);
++
++
++ /*
++ * We need to adjust the IRQ routing table
++ * if the ID changed.
++ */
++ if (old_id != mp_ioapics[apic].mpc_apicid)
++ for (i = 0; i < mp_irq_entries; i++)
++ if (mp_irqs[i].mpc_dstapic == old_id)
++ mp_irqs[i].mpc_dstapic
++ = mp_ioapics[apic].mpc_apicid;
++
++ /*
++ * Read the right value from the MPC table and
++ * write it into the ID register.
++ */
++ apic_printk(APIC_VERBOSE,KERN_INFO "...changing IO-APIC physical APIC ID to %d ...",
++ mp_ioapics[apic].mpc_apicid);
++
++ reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0, reg_00.raw);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ /*
++ * Sanity check
++ */
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(apic, 0);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
++ printk("could not set ID!\n");
++ else
++ apic_printk(APIC_VERBOSE," ok.\n");
++ }
++}
++#else
++static void __init setup_ioapic_ids_from_mpc(void) { }
++#endif
++
++/*
++ * There is a nasty bug in some older SMP boards, their mptable lies
++ * about the timer IRQ. We do the following to work around the situation:
++ *
++ * - timer IRQ defaults to IO-APIC IRQ
++ * - if this function detects that timer IRQs are defunct, then we fall
++ * back to ISA timer IRQs
++ */
++#ifndef CONFIG_XEN
++static int __init timer_irq_works(void)
++{
++ unsigned long t1 = jiffies;
++
++ local_irq_enable();
++ /* Let ten ticks pass... */
++ mdelay((10 * 1000) / HZ);
++
++ /*
++ * Expect a few ticks at least, to be sure some possible
++ * glue logic does not lock up after one or two first
++ * ticks in a non-ExtINT mode. Also the local APIC
++ * might have cached one ExtINT interrupt. Finally, at
++ * least one tick may be lost due to delays.
++ */
++
++ /* jiffies wrap? */
++ if (jiffies - t1 > 4)
++ return 1;
++ return 0;
++}
++
++/*
++ * In the SMP+IOAPIC case it might happen that there are an unspecified
++ * number of pending IRQ events unhandled. These cases are very rare,
++ * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
++ * better to do it this way as thus we do not have to be aware of
++ * 'pending' interrupts in the IRQ path, except at this point.
++ */
++/*
++ * Edge triggered needs to resend any interrupt
++ * that was delayed but this is now handled in the device
++ * independent code.
++ */
++
++/*
++ * Starting up a edge-triggered IO-APIC interrupt is
++ * nasty - we need to make sure that we get the edge.
++ * If it is already asserted for some reason, we need
++ * return 1 to indicate that is was pending.
++ *
++ * This is not complete - we should be able to fake
++ * an edge even if it isn't on the 8259A...
++ */
++
++static unsigned int startup_edge_ioapic_irq(unsigned int irq)
++{
++ int was_pending = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ if (irq < 16) {
++ disable_8259A_irq(irq);
++ if (i8259A_irq_pending(irq))
++ was_pending = 1;
++ }
++ __unmask_IO_APIC_irq(irq);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return was_pending;
++}
++
++/*
++ * Once we have recorded IRQ_PENDING already, we can mask the
++ * interrupt for real. This prevents IRQ storms from unhandled
++ * devices.
++ */
++static void ack_edge_ioapic_irq(unsigned int irq)
++{
++ move_irq(irq);
++ if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
++ == (IRQ_PENDING | IRQ_DISABLED))
++ mask_IO_APIC_irq(irq);
++ ack_APIC_irq();
++}
++
++/*
++ * Level triggered interrupts can just be masked,
++ * and shutting down and starting up the interrupt
++ * is the same as enabling and disabling them -- except
++ * with a startup need to return a "was pending" value.
++ *
++ * Level triggered interrupts are special because we
++ * do not touch any IO-APIC register while handling
++ * them. We ack the APIC in the end-IRQ handler, not
++ * in the start-IRQ-handler. Protection against reentrance
++ * from the same interrupt is still provided, both by the
++ * generic IRQ layer and by the fact that an unacked local
++ * APIC does not accept IRQs.
++ */
++static unsigned int startup_level_ioapic_irq (unsigned int irq)
++{
++ unmask_IO_APIC_irq(irq);
++
++ return 0; /* don't check for pending */
++}
++
++static void end_level_ioapic_irq (unsigned int irq)
++{
++ move_irq(irq);
++ ack_APIC_irq();
++}
++
++#ifdef CONFIG_PCI_MSI
++static unsigned int startup_edge_ioapic_vector(unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ return startup_edge_ioapic_irq(irq);
++}
++
++static void ack_edge_ioapic_vector(unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ move_native_irq(vector);
++ ack_edge_ioapic_irq(irq);
++}
++
++static unsigned int startup_level_ioapic_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ return startup_level_ioapic_irq (irq);
++}
++
++static void end_level_ioapic_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ move_native_irq(vector);
++ end_level_ioapic_irq(irq);
++}
++
++static void mask_IO_APIC_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ mask_IO_APIC_irq(irq);
++}
++
++static void unmask_IO_APIC_vector (unsigned int vector)
++{
++ int irq = vector_to_irq(vector);
++
++ unmask_IO_APIC_irq(irq);
++}
++
++#ifdef CONFIG_SMP
++static void set_ioapic_affinity_vector (unsigned int vector,
++ cpumask_t cpu_mask)
++{
++ int irq = vector_to_irq(vector);
++
++ set_native_irq_info(vector, cpu_mask);
++ set_ioapic_affinity_irq(irq, cpu_mask);
++}
++#endif // CONFIG_SMP
++#endif // CONFIG_PCI_MSI
++
++static int ioapic_retrigger(unsigned int irq)
++{
++ send_IPI_self(IO_APIC_VECTOR(irq));
++
++ return 1;
++}
++
++/*
++ * Level and edge triggered IO-APIC interrupts need different handling,
++ * so we use two separate IRQ descriptors. Edge triggered IRQs can be
++ * handled with the level-triggered descriptor, but that one has slightly
++ * more overhead. Level-triggered interrupts cannot be handled with the
++ * edge-triggered handler, without risking IRQ storms and other ugly
++ * races.
++ */
++
++static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
++ .typename = "IO-APIC-edge",
++ .startup = startup_edge_ioapic,
++ .shutdown = shutdown_edge_ioapic,
++ .enable = enable_edge_ioapic,
++ .disable = disable_edge_ioapic,
++ .ack = ack_edge_ioapic,
++ .end = end_edge_ioapic,
++#ifdef CONFIG_SMP
++ .set_affinity = set_ioapic_affinity,
++#endif
++ .retrigger = ioapic_retrigger,
++};
++
++static struct hw_interrupt_type ioapic_level_type __read_mostly = {
++ .typename = "IO-APIC-level",
++ .startup = startup_level_ioapic,
++ .shutdown = shutdown_level_ioapic,
++ .enable = enable_level_ioapic,
++ .disable = disable_level_ioapic,
++ .ack = mask_and_ack_level_ioapic,
++ .end = end_level_ioapic,
++#ifdef CONFIG_SMP
++ .set_affinity = set_ioapic_affinity,
++#endif
++ .retrigger = ioapic_retrigger,
++};
++#endif /* !CONFIG_XEN */
++
++static inline void init_IO_APIC_traps(void)
++{
++ int irq;
++
++ /*
++ * NOTE! The local APIC isn't very good at handling
++ * multiple interrupts at the same interrupt level.
++ * As the interrupt level is determined by taking the
++ * vector number and shifting that right by 4, we
++ * want to spread these out a bit so that they don't
++ * all fall in the same interrupt level.
++ *
++ * Also, we've got to be careful not to trash gate
++ * 0x80, because int 0x80 is hm, kind of importantish. ;)
++ */
++ for (irq = 0; irq < NR_IRQS ; irq++) {
++ int tmp = irq;
++ if (use_pci_vector()) {
++ if (!platform_legacy_irq(tmp))
++ if ((tmp = vector_to_irq(tmp)) == -1)
++ continue;
++ }
++ if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
++ /*
++ * Hmm.. We don't have an entry for this,
++ * so default to an old-fashioned 8259
++ * interrupt if we can..
++ */
++ if (irq < 16)
++ make_8259A_irq(irq);
++#ifndef CONFIG_XEN
++ else
++ /* Strange. Oh, well.. */
++ irq_desc[irq].chip = &no_irq_type;
++#endif
++ }
++ }
++}
++
++#ifndef CONFIG_XEN
++static void enable_lapic_irq (unsigned int irq)
++{
++ unsigned long v;
++
++ v = apic_read(APIC_LVT0);
++ apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
++}
++
++static void disable_lapic_irq (unsigned int irq)
++{
++ unsigned long v;
++
++ v = apic_read(APIC_LVT0);
++ apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
++}
++
++static void ack_lapic_irq (unsigned int irq)
++{
++ ack_APIC_irq();
++}
++
++static void end_lapic_irq (unsigned int i) { /* nothing */ }
++
++static struct hw_interrupt_type lapic_irq_type __read_mostly = {
++ .typename = "local-APIC-edge",
++ .startup = NULL, /* startup_irq() not used for IRQ0 */
++ .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
++ .enable = enable_lapic_irq,
++ .disable = disable_lapic_irq,
++ .ack = ack_lapic_irq,
++ .end = end_lapic_irq,
++};
++
++static void setup_nmi (void)
++{
++ /*
++ * Dirty trick to enable the NMI watchdog ...
++ * We put the 8259A master into AEOI mode and
++ * unmask on all local APICs LVT0 as NMI.
++ *
++ * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
++ * is from Maciej W. Rozycki - so we do not have to EOI from
++ * the NMI handler or the timer interrupt.
++ */
++ printk(KERN_INFO "activating NMI Watchdog ...");
++
++ enable_NMI_through_LVT0(NULL);
++
++ printk(" done.\n");
++}
++
++/*
++ * This looks a bit hackish but it's about the only one way of sending
++ * a few INTA cycles to 8259As and any associated glue logic. ICR does
++ * not support the ExtINT mode, unfortunately. We need to send these
++ * cycles as some i82489DX-based boards have glue logic that keeps the
++ * 8259A interrupt line asserted until INTA. --macro
++ */
++static inline void unlock_ExtINT_logic(void)
++{
++ int apic, pin, i;
++ struct IO_APIC_route_entry entry0, entry1;
++ unsigned char save_control, save_freq_select;
++ unsigned long flags;
++
++ pin = find_isa_irq_pin(8, mp_INT);
++ apic = find_isa_irq_apic(8, mp_INT);
++ if (pin == -1)
++ return;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
++ *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++ clear_IO_APIC_pin(apic, pin);
++
++ memset(&entry1, 0, sizeof(entry1));
++
++ entry1.dest_mode = 0; /* physical delivery */
++ entry1.mask = 0; /* unmask IRQ now */
++ entry1.dest.physical.physical_dest = hard_smp_processor_id();
++ entry1.delivery_mode = dest_ExtINT;
++ entry1.polarity = entry0.polarity;
++ entry1.trigger = 0;
++ entry1.vector = 0;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ save_control = CMOS_READ(RTC_CONTROL);
++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
++ CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
++ RTC_FREQ_SELECT);
++ CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
++
++ i = 100;
++ while (i-- > 0) {
++ mdelay(10);
++ if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
++ i -= 10;
++ }
++
++ CMOS_WRITE(save_control, RTC_CONTROL);
++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
++ clear_IO_APIC_pin(apic, pin);
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++
++int timer_uses_ioapic_pin_0;
++
++/*
++ * This code may look a bit paranoid, but it's supposed to cooperate with
++ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
++ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
++ * fanatically on his truly buggy board.
++ *
++ * FIXME: really need to revamp this for modern platforms only.
++ */
++static inline void check_timer(void)
++{
++ int apic1, pin1, apic2, pin2;
++ int vector;
++
++ /*
++ * get/set the timer IRQ vector:
++ */
++ disable_8259A_irq(0);
++ vector = assign_irq_vector(0);
++ set_intr_gate(vector, interrupt[0]);
++
++ /*
++ * Subtle, code in do_timer_interrupt() expects an AEOI
++ * mode for the 8259A whenever interrupts are routed
++ * through I/O APICs. Also IRQ0 has to be enabled in
++ * the 8259A which implies the virtual wire has to be
++ * disabled in the local APIC.
++ */
++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
++ init_8259A(1);
++ if (timer_over_8254 > 0)
++ enable_8259A_irq(0);
++
++ pin1 = find_isa_irq_pin(0, mp_INT);
++ apic1 = find_isa_irq_apic(0, mp_INT);
++ pin2 = ioapic_i8259.pin;
++ apic2 = ioapic_i8259.apic;
++
++ if (pin1 == 0)
++ timer_uses_ioapic_pin_0 = 1;
++
++ apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
++ vector, apic1, pin1, apic2, pin2);
++
++ if (pin1 != -1) {
++ /*
++ * Ok, does IRQ0 through the IOAPIC work?
++ */
++ unmask_IO_APIC_irq(0);
++ if (!no_timer_check && timer_irq_works()) {
++ nmi_watchdog_default();
++ if (nmi_watchdog == NMI_IO_APIC) {
++ disable_8259A_irq(0);
++ setup_nmi();
++ enable_8259A_irq(0);
++ }
++ if (disable_timer_pin_1 > 0)
++ clear_IO_APIC_pin(0, pin1);
++ return;
++ }
++ clear_IO_APIC_pin(apic1, pin1);
++ apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not "
++ "connected to IO-APIC\n");
++ }
++
++ apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) "
++ "through the 8259A ... ");
++ if (pin2 != -1) {
++ apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
++ apic2, pin2);
++ /*
++ * legacy devices should be connected to IO APIC #0
++ */
++ setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
++ if (timer_irq_works()) {
++ apic_printk(APIC_VERBOSE," works.\n");
++ nmi_watchdog_default();
++ if (nmi_watchdog == NMI_IO_APIC) {
++ setup_nmi();
++ }
++ return;
++ }
++ /*
++ * Cleanup, just in case ...
++ */
++ clear_IO_APIC_pin(apic2, pin2);
++ }
++ apic_printk(APIC_VERBOSE," failed.\n");
++
++ if (nmi_watchdog == NMI_IO_APIC) {
++ printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
++ nmi_watchdog = 0;
++ }
++
++ apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
++
++ disable_8259A_irq(0);
++ irq_desc[0].chip = &lapic_irq_type;
++ apic_write(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
++ enable_8259A_irq(0);
++
++ if (timer_irq_works()) {
++ apic_printk(APIC_VERBOSE," works.\n");
++ return;
++ }
++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
++ apic_printk(APIC_VERBOSE," failed.\n");
++
++ apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ...");
++
++ init_8259A(0);
++ make_8259A_irq(0);
++ apic_write(APIC_LVT0, APIC_DM_EXTINT);
++
++ unlock_ExtINT_logic();
++
++ if (timer_irq_works()) {
++ apic_printk(APIC_VERBOSE," works.\n");
++ return;
++ }
++ apic_printk(APIC_VERBOSE," failed :(.\n");
++ panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n");
++}
++#else
++int timer_uses_ioapic_pin_0;
++#define check_timer() ((void)0)
++#endif /* !CONFIG_XEN */
++
++static int __init notimercheck(char *s)
++{
++ no_timer_check = 1;
++ return 1;
++}
++__setup("no_timer_check", notimercheck);
++
++/*
++ *
++ * IRQ's that are handled by the PIC in the MPS IOAPIC case.
++ * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
++ * Linux doesn't really care, as it's not actually used
++ * for any interrupt handling anyway.
++ */
++#define PIC_IRQS (1<<2)
++
++void __init setup_IO_APIC(void)
++{
++ enable_IO_APIC();
++
++ if (acpi_ioapic)
++ io_apic_irqs = ~0; /* all IRQs go through IOAPIC */
++ else
++ io_apic_irqs = ~PIC_IRQS;
++
++ apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
++
++ /*
++ * Set up the IO-APIC IRQ routing table.
++ */
++ if (!acpi_ioapic)
++ setup_ioapic_ids_from_mpc();
++#ifndef CONFIG_XEN
++ sync_Arb_IDs();
++#endif /* !CONFIG_XEN */
++ setup_IO_APIC_irqs();
++ init_IO_APIC_traps();
++ check_timer();
++ if (!acpi_ioapic)
++ print_IO_APIC();
++}
++
++struct sysfs_ioapic_data {
++ struct sys_device dev;
++ struct IO_APIC_route_entry entry[0];
++};
++static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
++
++static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
++{
++ struct IO_APIC_route_entry *entry;
++ struct sysfs_ioapic_data *data;
++ unsigned long flags;
++ int i;
++
++ data = container_of(dev, struct sysfs_ioapic_data, dev);
++ entry = data->entry;
++ spin_lock_irqsave(&ioapic_lock, flags);
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
++ *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
++ *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
++ }
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return 0;
++}
++
++static int ioapic_resume(struct sys_device *dev)
++{
++ struct IO_APIC_route_entry *entry;
++ struct sysfs_ioapic_data *data;
++ unsigned long flags;
++ union IO_APIC_reg_00 reg_00;
++ int i;
++
++ data = container_of(dev, struct sysfs_ioapic_data, dev);
++ entry = data->entry;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_00.raw = io_apic_read(dev->id, 0);
++ if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) {
++ reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
++ io_apic_write(dev->id, 0, reg_00.raw);
++ }
++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
++ io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
++ io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
++ }
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return 0;
++}
++
++static struct sysdev_class ioapic_sysdev_class = {
++ set_kset_name("ioapic"),
++ .suspend = ioapic_suspend,
++ .resume = ioapic_resume,
++};
++
++static int __init ioapic_init_sysfs(void)
++{
++ struct sys_device * dev;
++ int i, size, error = 0;
++
++ error = sysdev_class_register(&ioapic_sysdev_class);
++ if (error)
++ return error;
++
++ for (i = 0; i < nr_ioapics; i++ ) {
++ size = sizeof(struct sys_device) + nr_ioapic_registers[i]
++ * sizeof(struct IO_APIC_route_entry);
++ mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL);
++ if (!mp_ioapic_data[i]) {
++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
++ continue;
++ }
++ memset(mp_ioapic_data[i], 0, size);
++ dev = &mp_ioapic_data[i]->dev;
++ dev->id = i;
++ dev->cls = &ioapic_sysdev_class;
++ error = sysdev_register(dev);
++ if (error) {
++ kfree(mp_ioapic_data[i]);
++ mp_ioapic_data[i] = NULL;
++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++device_initcall(ioapic_init_sysfs);
++
++/* --------------------------------------------------------------------------
++ ACPI-based IOAPIC Configuration
++ -------------------------------------------------------------------------- */
++
++#ifdef CONFIG_ACPI
++
++#define IO_APIC_MAX_ID 0xFE
++
++int __init io_apic_get_version (int ioapic)
++{
++ union IO_APIC_reg_01 reg_01;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_01.raw = io_apic_read(ioapic, 1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return reg_01.bits.version;
++}
++
++
++int __init io_apic_get_redir_entries (int ioapic)
++{
++ union IO_APIC_reg_01 reg_01;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ reg_01.raw = io_apic_read(ioapic, 1);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return reg_01.bits.entries;
++}
++
++
++int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low)
++{
++ struct IO_APIC_route_entry entry;
++ unsigned long flags;
++
++ if (!IO_APIC_IRQ(irq)) {
++ apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
++ ioapic);
++ return -EINVAL;
++ }
++
++ /*
++ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
++ * Note that we mask (disable) IRQs now -- these get enabled when the
++ * corresponding device driver registers for this IRQ.
++ */
++
++ memset(&entry,0,sizeof(entry));
++
++ entry.delivery_mode = INT_DELIVERY_MODE;
++ entry.dest_mode = INT_DEST_MODE;
++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
++ entry.trigger = edge_level;
++ entry.polarity = active_high_low;
++ entry.mask = 1; /* Disabled (masked) */
++
++ irq = gsi_irq_sharing(irq);
++ /*
++ * IRQs < 16 are already in the irq_2_pin[] map
++ */
++ if (irq >= 16)
++ add_pin_to_irq(irq, ioapic, pin);
++
++ entry.vector = assign_irq_vector(irq);
++
++ apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
++ "IRQ %d Mode:%i Active:%i)\n", ioapic,
++ mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq,
++ edge_level, active_high_low);
++
++ ioapic_register_intr(irq, entry.vector, edge_level);
++
++ if (!ioapic && (irq < 16))
++ disable_8259A_irq(irq);
++
++ spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
++ io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
++ set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
++ spin_unlock_irqrestore(&ioapic_lock, flags);
++
++ return 0;
++}
++
++#endif /* CONFIG_ACPI */
++
++
++#ifndef CONFIG_XEN
++/*
++ * This function currently is only a helper for the i386 smp boot process where
++ * we need to reprogram the ioredtbls to cater for the cpus which have come online
++ * so mask in all cases should simply be TARGET_CPUS
++ */
++#ifdef CONFIG_SMP
++void __init setup_ioapic_dest(void)
++{
++ int pin, ioapic, irq, irq_entry;
++
++ if (skip_ioapic_setup == 1)
++ return;
++
++ for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
++ for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
++ irq_entry = find_irq_entry(ioapic, pin, mp_INT);
++ if (irq_entry == -1)
++ continue;
++ irq = pin_2_irq(irq_entry, ioapic, pin);
++ set_ioapic_affinity_irq(irq, TARGET_CPUS);
++ }
++
++ }
++}
++#endif
++#endif /* !CONFIG_XEN */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/ioport-xen.c linux-2.6.18-xen/arch/x86_64/kernel/ioport-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/ioport-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/ioport-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,99 @@
++/*
++ * linux/arch/x86_64/kernel/ioport.c
++ *
++ * This contains the io-permission bitmap code - written by obz, with changes
++ * by Linus.
++ */
++
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/capability.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/stddef.h>
++#include <linux/slab.h>
++#include <linux/thread_info.h>
++#include <xen/interface/physdev.h>
++
++/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
++static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value)
++{
++ int i;
++
++ if (new_value)
++ for (i = base; i < base + extent; i++)
++ __set_bit(i, bitmap);
++ else
++ for (i = base; i < base + extent; i++)
++ clear_bit(i, bitmap);
++}
++
++/*
++ * this changes the io permissions bitmap in the current task.
++ */
++asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
++{
++ struct thread_struct * t = ¤t->thread;
++ unsigned long *bitmap;
++ struct physdev_set_iobitmap set_iobitmap;
++
++ if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
++ return -EINVAL;
++ if (turn_on && !capable(CAP_SYS_RAWIO))
++ return -EPERM;
++
++ /*
++ * If it's the first ioperm() call in this thread's lifetime, set the
++ * IO bitmap up. ioperm() is much less timing critical than clone(),
++ * this is why we delay this operation until now:
++ */
++ if (!t->io_bitmap_ptr) {
++ bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
++ if (!bitmap)
++ return -ENOMEM;
++
++ memset(bitmap, 0xff, IO_BITMAP_BYTES);
++ t->io_bitmap_ptr = bitmap;
++
++ set_iobitmap.bitmap = (char *)bitmap;
++ set_iobitmap.nr_ports = IO_BITMAP_BITS;
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap);
++ }
++
++ set_bitmap(t->io_bitmap_ptr, from, num, !turn_on);
++
++ return 0;
++}
++
++/*
++ * sys_iopl has to be used when you want to access the IO ports
++ * beyond the 0x3ff range: to get the full 65536 ports bitmapped
++ * you'd need 8kB of bitmaps/process, which is a bit excessive.
++ *
++ */
++
++asmlinkage long sys_iopl(unsigned int new_iopl, struct pt_regs *regs)
++{
++ unsigned int old_iopl = current->thread.iopl;
++ struct physdev_set_iopl set_iopl;
++
++ if (new_iopl > 3)
++ return -EINVAL;
++
++ /* Need "raw I/O" privileges for direct port access. */
++ if ((new_iopl > old_iopl) && !capable(CAP_SYS_RAWIO))
++ return -EPERM;
++
++ /* Change our version of the privilege levels. */
++ current->thread.iopl = new_iopl;
++
++ /* Force the change at ring 0. */
++ set_iopl.iopl = (new_iopl == 0) ? 1 : new_iopl;
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/irqflags-xen.c linux-2.6.18-xen/arch/x86_64/kernel/irqflags-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/irqflags-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/irqflags-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,100 @@
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <asm/irqflags.h>
++#include <asm/hypervisor.h>
++
++/*
++ * The use of 'barrier' in the following reflects their use as local-lock
++ * operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
++ * critical operations are executed. All critical operations must complete
++ * /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
++ * includes these barriers, for example.
++ */
++
++unsigned long __raw_local_save_flags(void)
++{
++ struct vcpu_info *_vcpu;
++ unsigned long flags;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ flags = _vcpu->evtchn_upcall_mask;
++ preempt_enable();
++
++ return flags;
++}
++EXPORT_SYMBOL(__raw_local_save_flags);
++
++void raw_local_irq_restore(unsigned long flags)
++{
++ struct vcpu_info *_vcpu;
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ if ((_vcpu->evtchn_upcall_mask = flags) == 0) {
++ barrier(); /* unmask then check (avoid races) */
++ if ( unlikely(_vcpu->evtchn_upcall_pending) )
++ force_evtchn_callback();
++ preempt_enable();
++ } else
++ preempt_enable_no_resched();
++}
++EXPORT_SYMBOL(raw_local_irq_restore);
++
++void raw_local_irq_disable(void)
++{
++ struct vcpu_info *_vcpu;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ _vcpu->evtchn_upcall_mask = 1;
++ preempt_enable_no_resched();
++}
++EXPORT_SYMBOL(raw_local_irq_disable);
++
++void raw_local_irq_enable(void)
++{
++ struct vcpu_info *_vcpu;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ _vcpu->evtchn_upcall_mask = 0;
++ barrier(); /* unmask then check (avoid races) */
++ if ( unlikely(_vcpu->evtchn_upcall_pending) )
++ force_evtchn_callback();
++ preempt_enable();
++}
++EXPORT_SYMBOL(raw_local_irq_enable);
++
++/*
++ * For spinlocks, etc.:
++ */
++
++unsigned long __raw_local_irq_save(void)
++{
++ struct vcpu_info *_vcpu;
++ unsigned long flags;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ flags = _vcpu->evtchn_upcall_mask;
++ _vcpu->evtchn_upcall_mask = 1;
++ preempt_enable_no_resched();
++
++ return flags;
++}
++EXPORT_SYMBOL(__raw_local_irq_save);
++
++/* Cannot use preempt_enable() here as we would recurse in preempt_sched(). */
++int raw_irqs_disabled(void)
++{
++ struct vcpu_info *_vcpu;
++ int disabled;
++
++ preempt_disable();
++ _vcpu = &HYPERVISOR_shared_info->vcpu_info[__vcpu_id];
++ disabled = (_vcpu->evtchn_upcall_mask != 0);
++ preempt_enable_no_resched();
++
++ return disabled;
++}
++EXPORT_SYMBOL(raw_irqs_disabled);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/irq-xen.c linux-2.6.18-xen/arch/x86_64/kernel/irq-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/irq-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/irq-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,198 @@
++/*
++ * linux/arch/x86_64/kernel/irq.c
++ *
++ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
++ *
++ * This file contains the lowest level x86_64-specific interrupt
++ * entry and irq statistics code. All the remaining irq logic is
++ * done by the generic kernel/irq/ code and in the
++ * x86_64-specific irq controller code. (e.g. i8259.c and
++ * io_apic.c.)
++ */
++
++#include <linux/kernel_stat.h>
++#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>
++#include <asm/idle.h>
++
++atomic_t irq_err_count;
++#ifdef CONFIG_X86_IO_APIC
++#ifdef APIC_MISMATCH_DEBUG
++atomic_t irq_mis_count;
++#endif
++#endif
++
++#ifdef CONFIG_DEBUG_STACKOVERFLOW
++/*
++ * Probabilistic stack overflow check:
++ *
++ * Only check the stack in process context, because everything else
++ * runs on the big interrupt stacks. Checking reliably is too expensive,
++ * so we just check from interrupts.
++ */
++static inline void stack_overflow_check(struct pt_regs *regs)
++{
++ u64 curbase = (u64) current->thread_info;
++ static unsigned long warned = -60*HZ;
++
++ if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE &&
++ regs->rsp < curbase + sizeof(struct thread_info) + 128 &&
++ time_after(jiffies, warned + 60*HZ)) {
++ printk("do_IRQ: %s near stack overflow (cur:%Lx,rsp:%lx)\n",
++ current->comm, curbase, regs->rsp);
++ show_stack(NULL,NULL);
++ warned = jiffies;
++ }
++}
++#endif
++
++/*
++ * 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_each_online_cpu(j)
++ seq_printf(p, "CPU%-8d ",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_each_online_cpu(j)
++ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
++#endif
++ seq_printf(p, " %14s", irq_desc[i].chip->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_each_online_cpu(j)
++ seq_printf(p, "%10u ", cpu_pda(j)->__nmi_count);
++ seq_putc(p, '\n');
++#ifdef CONFIG_X86_LOCAL_APIC
++ seq_printf(p, "LOC: ");
++ for_each_online_cpu(j)
++ seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs);
++ seq_putc(p, '\n');
++#endif
++ seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
++#ifdef CONFIG_X86_IO_APIC
++#ifdef APIC_MISMATCH_DEBUG
++ seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
++#endif
++#endif
++ }
++ return 0;
++}
++
++/*
++ * do_IRQ handles all normal device IRQ's (the special
++ * SMP cross-CPU interrupts have their own specific
++ * handlers).
++ */
++asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
++{
++ /* high bit used in ret_from_ code */
++ unsigned irq = ~regs->orig_rax;
++
++ if (unlikely(irq >= NR_IRQS)) {
++ printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
++ __FUNCTION__, irq);
++ BUG();
++ }
++
++ exit_idle();
++ irq_enter();
++
++#ifdef CONFIG_DEBUG_STACKOVERFLOW
++ stack_overflow_check(regs);
++#endif
++ __do_IRQ(irq, regs);
++ irq_exit();
++
++ 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_desc[irq].affinity, map);
++ if (any_online_cpu(mask) == NR_CPUS) {
++ printk("Breaking affinity for irq %i\n", irq);
++ mask = map;
++ }
++ if (irq_desc[irq].chip->set_affinity)
++ irq_desc[irq].chip->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
++
++extern void call_softirq(void);
++
++asmlinkage void do_softirq(void)
++{
++ __u32 pending;
++ unsigned long flags;
++
++ if (in_interrupt())
++ return;
++
++ local_irq_save(flags);
++ pending = local_softirq_pending();
++ /* Switch to interrupt stack */
++ if (pending) {
++ call_softirq();
++ WARN_ON_ONCE(softirq_count());
++ }
++ local_irq_restore(flags);
++}
++EXPORT_SYMBOL(do_softirq);
++
++#ifndef CONFIG_X86_LOCAL_APIC
++/*
++ * '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);
++}
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/ldt-xen.c linux-2.6.18-xen/arch/x86_64/kernel/ldt-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/ldt-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/ldt-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,282 @@
++/*
++ * linux/arch/x86_64/kernel/ldt.c
++ *
++ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
++ * Copyright (C) 1999 Ingo Molnar <mingo at redhat.com>
++ * Copyright (C) 2002 Andi Kleen
++ *
++ * This handles calls from both 32bit and 64bit mode.
++ */
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
++
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/ldt.h>
++#include <asm/desc.h>
++#include <asm/proto.h>
++#include <asm/pgalloc.h>
++
++#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
++static void flush_ldt(void *null)
++{
++ if (current->active_mm)
++ load_LDT(¤t->active_mm->context);
++}
++#endif
++
++static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++{
++ void *oldldt;
++ void *newldt;
++ unsigned oldsize;
++
++ if (mincount <= (unsigned)pc->size)
++ return 0;
++ oldsize = pc->size;
++ mincount = (mincount+511)&(~511);
++ if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
++ newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
++ else
++ newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
++
++ if (!newldt)
++ return -ENOMEM;
++
++ if (oldsize)
++ memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
++ oldldt = pc->ldt;
++ memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
++ wmb();
++ pc->ldt = newldt;
++ wmb();
++ pc->size = mincount;
++ wmb();
++ if (reload) {
++#ifdef CONFIG_SMP
++ cpumask_t mask;
++
++ preempt_disable();
++#endif
++ make_pages_readonly(
++ pc->ldt,
++ (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ load_LDT(pc);
++#ifdef CONFIG_SMP
++ mask = cpumask_of_cpu(smp_processor_id());
++ if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++ smp_call_function(flush_ldt, NULL, 1, 1);
++ preempt_enable();
++#endif
++ }
++ if (oldsize) {
++ make_pages_writable(
++ oldldt,
++ (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
++ vfree(oldldt);
++ else
++ kfree(oldldt);
++ }
++ return 0;
++}
++
++static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++{
++ int err = alloc_ldt(new, old->size, 0);
++ if (err < 0)
++ return err;
++ memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++ make_pages_readonly(
++ new->ldt,
++ (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ return 0;
++}
++
++/*
++ * we do not have to muck with descriptors here, that is
++ * done in switch_mm() as needed.
++ */
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++ struct mm_struct * old_mm;
++ int retval = 0;
++
++ memset(&mm->context, 0, sizeof(mm->context));
++ init_MUTEX(&mm->context.sem);
++ old_mm = current->mm;
++ if (old_mm && old_mm->context.size > 0) {
++ down(&old_mm->context.sem);
++ retval = copy_ldt(&mm->context, &old_mm->context);
++ up(&old_mm->context.sem);
++ }
++ if (retval == 0) {
++ spin_lock(&mm_unpinned_lock);
++ list_add(&mm->context.unpinned, &mm_unpinned);
++ spin_unlock(&mm_unpinned_lock);
++ }
++ return retval;
++}
++
++/*
++ *
++ * Don't touch the LDT register - we're already in the next thread.
++ */
++void destroy_context(struct mm_struct *mm)
++{
++ if (mm->context.size) {
++ if (mm == current->active_mm)
++ clear_LDT();
++ make_pages_writable(
++ mm->context.ldt,
++ (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE,
++ XENFEAT_writable_descriptor_tables);
++ if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
++ vfree(mm->context.ldt);
++ else
++ kfree(mm->context.ldt);
++ mm->context.size = 0;
++ }
++ if (!mm->context.pinned) {
++ spin_lock(&mm_unpinned_lock);
++ list_del(&mm->context.unpinned);
++ spin_unlock(&mm_unpinned_lock);
++ }
++}
++
++static int read_ldt(void __user * ptr, unsigned long bytecount)
++{
++ int err;
++ unsigned long size;
++ struct mm_struct * mm = current->mm;
++
++ if (!mm->context.size)
++ return 0;
++ if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
++ bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
++
++ down(&mm->context.sem);
++ size = mm->context.size*LDT_ENTRY_SIZE;
++ if (size > bytecount)
++ size = bytecount;
++
++ err = 0;
++ if (copy_to_user(ptr, mm->context.ldt, size))
++ err = -EFAULT;
++ up(&mm->context.sem);
++ if (err < 0)
++ goto error_return;
++ if (size != bytecount) {
++ /* zero-fill the rest */
++ if (clear_user(ptr+size, bytecount-size) != 0) {
++ err = -EFAULT;
++ goto error_return;
++ }
++ }
++ return bytecount;
++error_return:
++ return err;
++}
++
++static int read_default_ldt(void __user * ptr, unsigned long bytecount)
++{
++ /* Arbitrary number */
++ /* x86-64 default LDT is all zeros */
++ if (bytecount > 128)
++ bytecount = 128;
++ if (clear_user(ptr, bytecount))
++ return -EFAULT;
++ return bytecount;
++}
++
++static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++{
++ struct task_struct *me = current;
++ struct mm_struct * mm = me->mm;
++ __u32 entry_1, entry_2, *lp;
++ unsigned long mach_lp;
++ int error;
++ struct user_desc ldt_info;
++
++ error = -EINVAL;
++
++ if (bytecount != sizeof(ldt_info))
++ goto out;
++ error = -EFAULT;
++ if (copy_from_user(&ldt_info, ptr, bytecount))
++ goto out;
++
++ error = -EINVAL;
++ if (ldt_info.entry_number >= LDT_ENTRIES)
++ goto out;
++ if (ldt_info.contents == 3) {
++ if (oldmode)
++ goto out;
++ if (ldt_info.seg_not_present == 0)
++ goto out;
++ }
++
++ down(&mm->context.sem);
++ if (ldt_info.entry_number >= (unsigned)mm->context.size) {
++ error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1);
++ if (error < 0)
++ goto out_unlock;
++ }
++
++ lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
++ mach_lp = arbitrary_virt_to_machine(lp);
++
++ /* Allow LDTs to be cleared by the user. */
++ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
++ if (oldmode || LDT_empty(&ldt_info)) {
++ entry_1 = 0;
++ entry_2 = 0;
++ goto install;
++ }
++ }
++
++ entry_1 = LDT_entry_a(&ldt_info);
++ entry_2 = LDT_entry_b(&ldt_info);
++ if (oldmode)
++ entry_2 &= ~(1 << 20);
++
++ /* Install the new entry ... */
++install:
++ error = HYPERVISOR_update_descriptor(mach_lp, (unsigned long)((entry_1 | (unsigned long) entry_2 << 32)));
++
++out_unlock:
++ up(&mm->context.sem);
++out:
++ return error;
++}
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++ int ret = -ENOSYS;
++
++ switch (func) {
++ case 0:
++ ret = read_ldt(ptr, bytecount);
++ break;
++ case 1:
++ ret = write_ldt(ptr, bytecount, 1);
++ break;
++ case 2:
++ ret = read_default_ldt(ptr, bytecount);
++ break;
++ case 0x11:
++ ret = write_ldt(ptr, bytecount, 0);
++ break;
++ }
++ return ret;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/Makefile linux-2.6.18-xen/arch/x86_64/kernel/Makefile
+--- linux-2.6.18.1/arch/x86_64/kernel/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/kernel/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -21,11 +21,13 @@
+ obj-$(CONFIG_X86_CPUID) += cpuid.o
+ obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o
+ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
++obj-$(CONFIG_X86_XEN_GENAPIC) += genapic.o genapic_xen.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_CRASH_DUMP) += crash_dump.o
+-obj-$(CONFIG_PM) += suspend.o
++obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
++obj-$(CONFIG_ACPI_SLEEP) += suspend.o
+ obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
+ obj-$(CONFIG_CPU_FREQ) += cpufreq/
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+@@ -55,3 +57,18 @@
+ msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o
+ alternative-y += ../../i386/kernel/alternative.o
+
++ifdef CONFIG_XEN
++obj-y += irqflags.o
++time-y += ../../i386/kernel/time-xen.o
++pci-dma-y += ../../i386/kernel/pci-dma-xen.o
++microcode-$(subst m,y,$(CONFIG_MICROCODE)) := ../../i386/kernel/microcode-xen.o
++quirks-y := ../../i386/kernel/quirks-xen.o
++
++n-obj-xen := i8259.o reboot.o i8237.o smpboot.o trampoline.o
++
++include $(srctree)/scripts/Makefile.xen
++
++obj-y := $(call filterxen, $(obj-y), $(n-obj-xen))
++obj-y := $(call cherrypickxen, $(obj-y))
++extra-y := $(call cherrypickxen, $(extra-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/mpparse-xen.c linux-2.6.18-xen/arch/x86_64/kernel/mpparse-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/mpparse-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/mpparse-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,1011 @@
++/*
++ * Intel Multiprocessor Specification 1.1 and 1.4
++ * compliant MP-table parsing routines.
++ *
++ * (c) 1995 Alan Cox, Building #3 <alan at redhat.com>
++ * (c) 1998, 1999, 2000 Ingo Molnar <mingo at redhat.com>
++ *
++ * Fixes
++ * Erich Boleyn : MP v1.4 and additional changes.
++ * Alan Cox : Added EBDA scanning
++ * Ingo Molnar : various cleanups and rewrites
++ * Maciej W. Rozycki: Bits for default MP configurations
++ * Paul Diefenbaugh: Added full ACPI support
++ */
++
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/bootmem.h>
++#include <linux/smp_lock.h>
++#include <linux/kernel_stat.h>
++#include <linux/mc146818rtc.h>
++#include <linux/acpi.h>
++#include <linux/module.h>
++
++#include <asm/smp.h>
++#include <asm/mtrr.h>
++#include <asm/mpspec.h>
++#include <asm/pgalloc.h>
++#include <asm/io_apic.h>
++#include <asm/proto.h>
++#include <asm/acpi.h>
++
++/* Have we found an MP table */
++int smp_found_config;
++unsigned int __initdata maxcpus = NR_CPUS;
++
++int acpi_found_madt;
++
++/*
++ * Various Linux-internal data structures created from the
++ * MP-table.
++ */
++unsigned char apic_version [MAX_APICS];
++unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
++int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
++
++static int mp_current_pci_id = 0;
++/* I/O APIC entries */
++struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
++
++/* # of MP IRQ source entries */
++struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
++
++/* MP IRQ source entries */
++int mp_irq_entries;
++
++int nr_ioapics;
++int pic_mode;
++unsigned long mp_lapic_addr = 0;
++
++
++
++/* Processor that is doing the boot up */
++unsigned int boot_cpu_id = -1U;
++/* Internal processor count */
++unsigned int num_processors __initdata = 0;
++
++unsigned disabled_cpus __initdata;
++
++/* Bitmask of physically existing CPUs */
++physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE;
++
++/* ACPI MADT entry parsing functions */
++#ifdef CONFIG_ACPI
++extern struct acpi_boot_flags acpi_boot;
++#ifdef CONFIG_X86_LOCAL_APIC
++extern int acpi_parse_lapic (acpi_table_entry_header *header);
++extern int acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header);
++extern int acpi_parse_lapic_nmi (acpi_table_entry_header *header);
++#endif /*CONFIG_X86_LOCAL_APIC*/
++#ifdef CONFIG_X86_IO_APIC
++extern int acpi_parse_ioapic (acpi_table_entry_header *header);
++#endif /*CONFIG_X86_IO_APIC*/
++#endif /*CONFIG_ACPI*/
++
++u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
++
++
++/*
++ * Intel MP BIOS table parsing routines:
++ */
++
++/*
++ * Checksum an MP configuration block.
++ */
++
++static int __init mpf_checksum(unsigned char *mp, int len)
++{
++ int sum = 0;
++
++ while (len--)
++ sum += *mp++;
++
++ return sum & 0xFF;
++}
++
++#ifndef CONFIG_XEN
++static void __cpuinit MP_processor_info (struct mpc_config_processor *m)
++{
++ int cpu;
++ unsigned char ver;
++ cpumask_t tmp_map;
++
++ if (!(m->mpc_cpuflag & CPU_ENABLED)) {
++ disabled_cpus++;
++ return;
++ }
++
++ printk(KERN_INFO "Processor #%d %d:%d APIC version %d\n",
++ m->mpc_apicid,
++ (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8,
++ (m->mpc_cpufeature & CPU_MODEL_MASK)>>4,
++ m->mpc_apicver);
++
++ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
++ Dprintk(" Bootup CPU\n");
++ boot_cpu_id = m->mpc_apicid;
++ }
++ if (num_processors >= NR_CPUS) {
++ printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
++ " Processor ignored.\n", NR_CPUS);
++ return;
++ }
++
++ num_processors++;
++ cpus_complement(tmp_map, cpu_present_map);
++ cpu = first_cpu(tmp_map);
++
++#if MAX_APICS < 255
++ if ((int)m->mpc_apicid > MAX_APICS) {
++ printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
++ m->mpc_apicid, MAX_APICS);
++ return;
++ }
++#endif
++ ver = m->mpc_apicver;
++
++ physid_set(m->mpc_apicid, phys_cpu_present_map);
++ /*
++ * Validate version
++ */
++ if (ver == 0x0) {
++ printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
++ ver = 0x10;
++ }
++ apic_version[m->mpc_apicid] = ver;
++ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
++ /*
++ * bios_cpu_apicid is required to have processors listed
++ * in same order as logical cpu numbers. Hence the first
++ * entry is BSP, and so on.
++ */
++ cpu = 0;
++ }
++ bios_cpu_apicid[cpu] = m->mpc_apicid;
++ x86_cpu_to_apicid[cpu] = m->mpc_apicid;
++
++ cpu_set(cpu, cpu_possible_map);
++ cpu_set(cpu, cpu_present_map);
++}
++#else
++void __init MP_processor_info (struct mpc_config_processor *m)
++{
++ num_processors++;
++}
++#endif /* CONFIG_XEN */
++
++static void __init MP_bus_info (struct mpc_config_bus *m)
++{
++ char str[7];
++
++ memcpy(str, m->mpc_bustype, 6);
++ str[6] = 0;
++ Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
++
++ if (strncmp(str, "ISA", 3) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
++ } else if (strncmp(str, "EISA", 4) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
++ } else if (strncmp(str, "PCI", 3) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
++ mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
++ mp_current_pci_id++;
++ } else if (strncmp(str, "MCA", 3) == 0) {
++ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
++ } else {
++ printk(KERN_ERR "Unknown bustype %s\n", str);
++ }
++}
++
++static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
++{
++ if (!(m->mpc_flags & MPC_APIC_USABLE))
++ return;
++
++ printk("I/O APIC #%d Version %d at 0x%X.\n",
++ m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
++ if (nr_ioapics >= MAX_IO_APICS) {
++ printk(KERN_ERR "Max # of I/O APICs (%d) exceeded (found %d).\n",
++ MAX_IO_APICS, nr_ioapics);
++ panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
++ }
++ if (!m->mpc_apicaddr) {
++ printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
++ " found in MP table, skipping!\n");
++ return;
++ }
++ mp_ioapics[nr_ioapics] = *m;
++ nr_ioapics++;
++}
++
++static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
++{
++ mp_irqs [mp_irq_entries] = *m;
++ Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
++ " IRQ %02x, APIC ID %x, APIC INT %02x\n",
++ m->mpc_irqtype, m->mpc_irqflag & 3,
++ (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
++ m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
++ if (++mp_irq_entries >= MAX_IRQ_SOURCES)
++ panic("Max # of irq sources exceeded!!\n");
++}
++
++static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
++{
++ Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
++ " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
++ m->mpc_irqtype, m->mpc_irqflag & 3,
++ (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
++ m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
++ /*
++ * Well it seems all SMP boards in existence
++ * use ExtINT/LVT1 == LINT0 and
++ * NMI/LVT2 == LINT1 - the following check
++ * will show us if this assumptions is false.
++ * Until then we do not have to add baggage.
++ */
++ if ((m->mpc_irqtype == mp_ExtINT) &&
++ (m->mpc_destapiclint != 0))
++ BUG();
++ if ((m->mpc_irqtype == mp_NMI) &&
++ (m->mpc_destapiclint != 1))
++ BUG();
++}
++
++/*
++ * Read/parse the MPC
++ */
++
++static int __init smp_read_mpc(struct mp_config_table *mpc)
++{
++ char str[16];
++ int count=sizeof(*mpc);
++ unsigned char *mpt=((unsigned char *)mpc)+count;
++
++ if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
++ printk("SMP mptable: bad signature [%c%c%c%c]!\n",
++ mpc->mpc_signature[0],
++ mpc->mpc_signature[1],
++ mpc->mpc_signature[2],
++ mpc->mpc_signature[3]);
++ return 0;
++ }
++ if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {
++ printk("SMP mptable: checksum error!\n");
++ return 0;
++ }
++ if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
++ printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",
++ mpc->mpc_spec);
++ return 0;
++ }
++ if (!mpc->mpc_lapic) {
++ printk(KERN_ERR "SMP mptable: null local APIC address!\n");
++ return 0;
++ }
++ memcpy(str,mpc->mpc_oem,8);
++ str[8]=0;
++ printk(KERN_INFO "OEM ID: %s ",str);
++
++ memcpy(str,mpc->mpc_productid,12);
++ str[12]=0;
++ printk("Product ID: %s ",str);
++
++ printk("APIC at: 0x%X\n",mpc->mpc_lapic);
++
++ /* save the local APIC address, it might be non-default */
++ if (!acpi_lapic)
++ mp_lapic_addr = mpc->mpc_lapic;
++
++ /*
++ * Now process the configuration blocks.
++ */
++ while (count < mpc->mpc_length) {
++ switch(*mpt) {
++ case MP_PROCESSOR:
++ {
++ struct mpc_config_processor *m=
++ (struct mpc_config_processor *)mpt;
++ if (!acpi_lapic)
++ MP_processor_info(m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
++ break;
++ }
++ case MP_BUS:
++ {
++ struct mpc_config_bus *m=
++ (struct mpc_config_bus *)mpt;
++ MP_bus_info(m);
++ mpt += sizeof(*m);
++ count += sizeof(*m);
++ break;
++ }
++ case MP_IOAPIC:
++ {
++ struct mpc_config_ioapic *m=
++ (struct mpc_config_ioapic *)mpt;
++ MP_ioapic_info(m);
++ mpt+=sizeof(*m);
++ count+=sizeof(*m);
++ break;
++ }
++ case MP_INTSRC:
++ {
++ struct mpc_config_intsrc *m=
++ (struct mpc_config_intsrc *)mpt;
++
++ MP_intsrc_info(m);
++ mpt+=sizeof(*m);
++ count+=sizeof(*m);
++ break;
++ }
++ case MP_LINTSRC:
++ {
++ struct mpc_config_lintsrc *m=
++ (struct mpc_config_lintsrc *)mpt;
++ MP_lintsrc_info(m);
++ mpt+=sizeof(*m);
++ count+=sizeof(*m);
++ break;
++ }
++ }
++ }
++ clustered_apic_check();
++ if (!num_processors)
++ printk(KERN_ERR "SMP mptable: no processors registered!\n");
++ return num_processors;
++}
++
++static int __init ELCR_trigger(unsigned int irq)
++{
++ unsigned int port;
++
++ port = 0x4d0 + (irq >> 3);
++ return (inb(port) >> (irq & 7)) & 1;
++}
++
++static void __init construct_default_ioirq_mptable(int mpc_default_type)
++{
++ struct mpc_config_intsrc intsrc;
++ int i;
++ int ELCR_fallback = 0;
++
++ intsrc.mpc_type = MP_INTSRC;
++ intsrc.mpc_irqflag = 0; /* conforming */
++ intsrc.mpc_srcbus = 0;
++ intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
++
++ intsrc.mpc_irqtype = mp_INT;
++
++ /*
++ * If true, we have an ISA/PCI system with no IRQ entries
++ * in the MP table. To prevent the PCI interrupts from being set up
++ * incorrectly, we try to use the ELCR. The sanity check to see if
++ * there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can
++ * never be level sensitive, so we simply see if the ELCR agrees.
++ * If it does, we assume it's valid.
++ */
++ if (mpc_default_type == 5) {
++ printk(KERN_INFO "ISA/PCI bus type with no IRQ information... falling back to ELCR\n");
++
++ if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13))
++ printk(KERN_ERR "ELCR contains invalid data... not using ELCR\n");
++ else {
++ printk(KERN_INFO "Using ELCR to identify PCI interrupts\n");
++ ELCR_fallback = 1;
++ }
++ }
++
++ for (i = 0; i < 16; i++) {
++ switch (mpc_default_type) {
++ case 2:
++ if (i == 0 || i == 13)
++ continue; /* IRQ0 & IRQ13 not connected */
++ /* fall through */
++ default:
++ if (i == 2)
++ continue; /* IRQ2 is never connected */
++ }
++
++ if (ELCR_fallback) {
++ /*
++ * If the ELCR indicates a level-sensitive interrupt, we
++ * copy that information over to the MP table in the
++ * irqflag field (level sensitive, active high polarity).
++ */
++ if (ELCR_trigger(i))
++ intsrc.mpc_irqflag = 13;
++ else
++ intsrc.mpc_irqflag = 0;
++ }
++
++ intsrc.mpc_srcbusirq = i;
++ intsrc.mpc_dstirq = i ? i : 2; /* IRQ0 to INTIN2 */
++ MP_intsrc_info(&intsrc);
++ }
++
++ intsrc.mpc_irqtype = mp_ExtINT;
++ intsrc.mpc_srcbusirq = 0;
++ intsrc.mpc_dstirq = 0; /* 8259A to INTIN0 */
++ MP_intsrc_info(&intsrc);
++}
++
++static inline void __init construct_default_ISA_mptable(int mpc_default_type)
++{
++ struct mpc_config_processor processor;
++ struct mpc_config_bus bus;
++ struct mpc_config_ioapic ioapic;
++ struct mpc_config_lintsrc lintsrc;
++ int linttypes[2] = { mp_ExtINT, mp_NMI };
++ int i;
++
++ /*
++ * local APIC has default address
++ */
++ mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
++
++ /*
++ * 2 CPUs, numbered 0 & 1.
++ */
++ processor.mpc_type = MP_PROCESSOR;
++ /* Either an integrated APIC or a discrete 82489DX. */
++ processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
++ processor.mpc_cpuflag = CPU_ENABLED;
++ processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
++ (boot_cpu_data.x86_model << 4) |
++ boot_cpu_data.x86_mask;
++ processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
++ processor.mpc_reserved[0] = 0;
++ processor.mpc_reserved[1] = 0;
++ for (i = 0; i < 2; i++) {
++ processor.mpc_apicid = i;
++ MP_processor_info(&processor);
++ }
++
++ bus.mpc_type = MP_BUS;
++ bus.mpc_busid = 0;
++ switch (mpc_default_type) {
++ default:
++ printk(KERN_ERR "???\nUnknown standard configuration %d\n",
++ mpc_default_type);
++ /* fall through */
++ case 1:
++ case 5:
++ memcpy(bus.mpc_bustype, "ISA ", 6);
++ break;
++ case 2:
++ case 6:
++ case 3:
++ memcpy(bus.mpc_bustype, "EISA ", 6);
++ break;
++ case 4:
++ case 7:
++ memcpy(bus.mpc_bustype, "MCA ", 6);
++ }
++ MP_bus_info(&bus);
++ if (mpc_default_type > 4) {
++ bus.mpc_busid = 1;
++ memcpy(bus.mpc_bustype, "PCI ", 6);
++ MP_bus_info(&bus);
++ }
++
++ ioapic.mpc_type = MP_IOAPIC;
++ ioapic.mpc_apicid = 2;
++ ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
++ ioapic.mpc_flags = MPC_APIC_USABLE;
++ ioapic.mpc_apicaddr = 0xFEC00000;
++ MP_ioapic_info(&ioapic);
++
++ /*
++ * We set up most of the low 16 IO-APIC pins according to MPS rules.
++ */
++ construct_default_ioirq_mptable(mpc_default_type);
++
++ lintsrc.mpc_type = MP_LINTSRC;
++ lintsrc.mpc_irqflag = 0; /* conforming */
++ lintsrc.mpc_srcbusid = 0;
++ lintsrc.mpc_srcbusirq = 0;
++ lintsrc.mpc_destapic = MP_APIC_ALL;
++ for (i = 0; i < 2; i++) {
++ lintsrc.mpc_irqtype = linttypes[i];
++ lintsrc.mpc_destapiclint = i;
++ MP_lintsrc_info(&lintsrc);
++ }
++}
++
++static struct intel_mp_floating *mpf_found;
++
++/*
++ * Scan the memory blocks for an SMP configuration block.
++ */
++void __init get_smp_config (void)
++{
++ struct intel_mp_floating *mpf = mpf_found;
++
++ /*
++ * ACPI supports both logical (e.g. Hyper-Threading) and physical
++ * processors, where MPS only supports physical.
++ */
++ if (acpi_lapic && acpi_ioapic) {
++ printk(KERN_INFO "Using ACPI (MADT) for SMP configuration information\n");
++ return;
++ }
++ else if (acpi_lapic)
++ printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n");
++
++ printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
++ if (mpf->mpf_feature2 & (1<<7)) {
++ printk(KERN_INFO " IMCR and PIC compatibility mode.\n");
++ pic_mode = 1;
++ } else {
++ printk(KERN_INFO " Virtual Wire compatibility mode.\n");
++ pic_mode = 0;
++ }
++
++ /*
++ * Now see if we need to read further.
++ */
++ if (mpf->mpf_feature1 != 0) {
++
++ printk(KERN_INFO "Default MP configuration #%d\n", mpf->mpf_feature1);
++ construct_default_ISA_mptable(mpf->mpf_feature1);
++
++ } else if (mpf->mpf_physptr) {
++
++ /*
++ * Read the physical hardware table. Anything here will
++ * override the defaults.
++ */
++ if (!smp_read_mpc(isa_bus_to_virt(mpf->mpf_physptr))) {
++ smp_found_config = 0;
++ printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
++ printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
++ return;
++ }
++ /*
++ * If there are no explicit MP IRQ entries, then we are
++ * broken. We set up most of the low 16 IO-APIC pins to
++ * ISA defaults and hope it will work.
++ */
++ if (!mp_irq_entries) {
++ struct mpc_config_bus bus;
++
++ printk(KERN_ERR "BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n");
++
++ bus.mpc_type = MP_BUS;
++ bus.mpc_busid = 0;
++ memcpy(bus.mpc_bustype, "ISA ", 6);
++ MP_bus_info(&bus);
++
++ construct_default_ioirq_mptable(0);
++ }
++
++ } else
++ BUG();
++
++ printk(KERN_INFO "Processors: %d\n", num_processors);
++ /*
++ * Only use the first configuration found.
++ */
++}
++
++static int __init smp_scan_config (unsigned long base, unsigned long length)
++{
++ extern void __bad_mpf_size(void);
++ unsigned int *bp = isa_bus_to_virt(base);
++ struct intel_mp_floating *mpf;
++
++ Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length);
++ if (sizeof(*mpf) != 16)
++ __bad_mpf_size();
++
++ while (length > 0) {
++ mpf = (struct intel_mp_floating *)bp;
++ if ((*bp == SMP_MAGIC_IDENT) &&
++ (mpf->mpf_length == 1) &&
++ !mpf_checksum((unsigned char *)bp, 16) &&
++ ((mpf->mpf_specification == 1)
++ || (mpf->mpf_specification == 4)) ) {
++
++ smp_found_config = 1;
++ mpf_found = mpf;
++ return 1;
++ }
++ bp += 4;
++ length -= 16;
++ }
++ return 0;
++}
++
++void __init find_intel_smp (void)
++{
++ unsigned int address;
++
++ /*
++ * FIXME: Linux assumes you have 640K of base ram..
++ * this continues the error...
++ *
++ * 1) Scan the bottom 1K for a signature
++ * 2) Scan the top 1K of base RAM
++ * 3) Scan the 64K of bios
++ */
++ if (smp_scan_config(0x0,0x400) ||
++ smp_scan_config(639*0x400,0x400) ||
++ smp_scan_config(0xF0000,0x10000))
++ return;
++ /*
++ * If it is an SMP machine we should know now, unless the
++ * configuration is in an EISA/MCA bus machine with an
++ * extended bios data area.
++ *
++ * there is a real-mode segmented pointer pointing to the
++ * 4K EBDA area at 0x40E, calculate and scan it here.
++ *
++ * NOTE! There are Linux loaders that will corrupt the EBDA
++ * area, and as such this kind of SMP config may be less
++ * trustworthy, simply because the SMP table may have been
++ * stomped on during early boot. These loaders are buggy and
++ * should be fixed.
++ */
++
++ address = *(unsigned short *)phys_to_virt(0x40E);
++ address <<= 4;
++ if (smp_scan_config(address, 0x1000))
++ return;
++
++ /* If we have come this far, we did not find an MP table */
++ printk(KERN_INFO "No mptable found.\n");
++}
++
++/*
++ * - Intel MP Configuration Table
++ */
++void __init find_smp_config (void)
++{
++#ifdef CONFIG_X86_LOCAL_APIC
++ find_intel_smp();
++#endif
++}
++
++
++/* --------------------------------------------------------------------------
++ ACPI-based MP Configuration
++ -------------------------------------------------------------------------- */
++
++#ifdef CONFIG_ACPI
++
++void __init mp_register_lapic_address (
++ u64 address)
++{
++#ifndef CONFIG_XEN
++ mp_lapic_addr = (unsigned long) address;
++
++ set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
++
++ if (boot_cpu_id == -1U)
++ boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
++
++ Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid);
++#endif
++}
++
++
++void __cpuinit mp_register_lapic (
++ u8 id,
++ u8 enabled)
++{
++ struct mpc_config_processor processor;
++ int boot_cpu = 0;
++
++ if (id >= MAX_APICS) {
++ printk(KERN_WARNING "Processor #%d invalid (max %d)\n",
++ id, MAX_APICS);
++ return;
++ }
++
++ if (id == boot_cpu_physical_apicid)
++ boot_cpu = 1;
++
++#ifndef CONFIG_XEN
++ processor.mpc_type = MP_PROCESSOR;
++ processor.mpc_apicid = id;
++ processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR));
++ processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0);
++ processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0);
++ processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
++ (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
++ processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
++ processor.mpc_reserved[0] = 0;
++ processor.mpc_reserved[1] = 0;
++#endif
++
++ MP_processor_info(&processor);
++}
++
++#ifdef CONFIG_X86_IO_APIC
++
++#define MP_ISA_BUS 0
++#define MP_MAX_IOAPIC_PIN 127
++
++static struct mp_ioapic_routing {
++ int apic_id;
++ int gsi_start;
++ int gsi_end;
++ u32 pin_programmed[4];
++} mp_ioapic_routing[MAX_IO_APICS];
++
++
++static int mp_find_ioapic (
++ int gsi)
++{
++ int i = 0;
++
++ /* Find the IOAPIC that manages this GSI. */
++ for (i = 0; i < nr_ioapics; i++) {
++ if ((gsi >= mp_ioapic_routing[i].gsi_start)
++ && (gsi <= mp_ioapic_routing[i].gsi_end))
++ return i;
++ }
++
++ printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
++
++ return -1;
++}
++
++
++void __init mp_register_ioapic (
++ u8 id,
++ u32 address,
++ u32 gsi_base)
++{
++ int idx = 0;
++
++ if (nr_ioapics >= MAX_IO_APICS) {
++ printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
++ "(found %d)\n", MAX_IO_APICS, nr_ioapics);
++ panic("Recompile kernel with bigger MAX_IO_APICS!\n");
++ }
++ if (!address) {
++ printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
++ " found in MADT table, skipping!\n");
++ return;
++ }
++
++ idx = nr_ioapics++;
++
++ mp_ioapics[idx].mpc_type = MP_IOAPIC;
++ mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
++ mp_ioapics[idx].mpc_apicaddr = address;
++
++#ifndef CONFIG_XEN
++ set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
++#endif
++ mp_ioapics[idx].mpc_apicid = id;
++ mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
++
++ /*
++ * Build basic IRQ lookup table to facilitate gsi->io_apic lookups
++ * and to prevent reprogramming of IOAPIC pins (PCI IRQs).
++ */
++ mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
++ mp_ioapic_routing[idx].gsi_start = gsi_base;
++ mp_ioapic_routing[idx].gsi_end = gsi_base +
++ io_apic_get_redir_entries(idx);
++
++ printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
++ "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
++ mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
++ mp_ioapic_routing[idx].gsi_start,
++ mp_ioapic_routing[idx].gsi_end);
++
++ return;
++}
++
++
++void __init mp_override_legacy_irq (
++ u8 bus_irq,
++ u8 polarity,
++ u8 trigger,
++ u32 gsi)
++{
++ struct mpc_config_intsrc intsrc;
++ int ioapic = -1;
++ int pin = -1;
++
++ /*
++ * Convert 'gsi' to 'ioapic.pin'.
++ */
++ ioapic = mp_find_ioapic(gsi);
++ if (ioapic < 0)
++ return;
++ pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
++
++ /*
++ * TBD: This check is for faulty timer entries, where the override
++ * erroneously sets the trigger to level, resulting in a HUGE
++ * increase of timer interrupts!
++ */
++ if ((bus_irq == 0) && (trigger == 3))
++ trigger = 1;
++
++ intsrc.mpc_type = MP_INTSRC;
++ intsrc.mpc_irqtype = mp_INT;
++ intsrc.mpc_irqflag = (trigger << 2) | polarity;
++ intsrc.mpc_srcbus = MP_ISA_BUS;
++ intsrc.mpc_srcbusirq = bus_irq; /* IRQ */
++ intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* APIC ID */
++ intsrc.mpc_dstirq = pin; /* INTIN# */
++
++ Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n",
++ intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
++ (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
++ intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
++
++ mp_irqs[mp_irq_entries] = intsrc;
++ if (++mp_irq_entries == MAX_IRQ_SOURCES)
++ panic("Max # of irq sources exceeded!\n");
++
++ return;
++}
++
++
++void __init mp_config_acpi_legacy_irqs (void)
++{
++ struct mpc_config_intsrc intsrc;
++ int i = 0;
++ int ioapic = -1;
++
++ /*
++ * Fabricate the legacy ISA bus (bus #31).
++ */
++ mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
++ Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
++
++ /*
++ * Locate the IOAPIC that manages the ISA IRQs (0-15).
++ */
++ ioapic = mp_find_ioapic(0);
++ if (ioapic < 0)
++ return;
++
++ intsrc.mpc_type = MP_INTSRC;
++ intsrc.mpc_irqflag = 0; /* Conforming */
++ intsrc.mpc_srcbus = MP_ISA_BUS;
++ intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
++
++ /*
++ * Use the default configuration for the IRQs 0-15. Unless
++ * overridden by (MADT) interrupt source override entries.
++ */
++ for (i = 0; i < 16; i++) {
++ int idx;
++
++ for (idx = 0; idx < mp_irq_entries; idx++) {
++ struct mpc_config_intsrc *irq = mp_irqs + idx;
++
++ /* Do we already have a mapping for this ISA IRQ? */
++ if (irq->mpc_srcbus == MP_ISA_BUS && irq->mpc_srcbusirq == i)
++ break;
++
++ /* Do we already have a mapping for this IOAPIC pin */
++ if ((irq->mpc_dstapic == intsrc.mpc_dstapic) &&
++ (irq->mpc_dstirq == i))
++ break;
++ }
++
++ if (idx != mp_irq_entries) {
++ printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
++ continue; /* IRQ already used */
++ }
++
++ intsrc.mpc_irqtype = mp_INT;
++ intsrc.mpc_srcbusirq = i; /* Identity mapped */
++ intsrc.mpc_dstirq = i;
++
++ Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, "
++ "%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
++ (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
++ intsrc.mpc_srcbusirq, intsrc.mpc_dstapic,
++ intsrc.mpc_dstirq);
++
++ mp_irqs[mp_irq_entries] = intsrc;
++ if (++mp_irq_entries == MAX_IRQ_SOURCES)
++ panic("Max # of irq sources exceeded!\n");
++ }
++
++ return;
++}
++
++#define MAX_GSI_NUM 4096
++
++int mp_register_gsi(u32 gsi, int triggering, int polarity)
++{
++ int ioapic = -1;
++ int ioapic_pin = 0;
++ int idx, bit = 0;
++ static int pci_irq = 16;
++ /*
++ * Mapping between Global System Interrupts, which
++ * represent all possible interrupts, to the IRQs
++ * assigned to actual devices.
++ */
++ static int gsi_to_irq[MAX_GSI_NUM];
++
++ if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
++ return gsi;
++
++ /* Don't set up the ACPI SCI because it's already set up */
++ if (acpi_fadt.sci_int == gsi)
++ return gsi;
++
++ ioapic = mp_find_ioapic(gsi);
++ if (ioapic < 0) {
++ printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
++ return gsi;
++ }
++
++ ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
++
++ /*
++ * Avoid pin reprogramming. PRTs typically include entries
++ * with redundant pin->gsi mappings (but unique PCI devices);
++ * we only program the IOAPIC on the first.
++ */
++ bit = ioapic_pin % 32;
++ idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
++ if (idx > 3) {
++ printk(KERN_ERR "Invalid reference to IOAPIC pin "
++ "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
++ ioapic_pin);
++ return gsi;
++ }
++ if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
++ Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
++ mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
++ return gsi_to_irq[gsi];
++ }
++
++ mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
++
++ if (triggering == ACPI_LEVEL_SENSITIVE) {
++ /*
++ * For PCI devices assign IRQs in order, avoiding gaps
++ * due to unused I/O APIC pins.
++ */
++ int irq = gsi;
++ if (gsi < MAX_GSI_NUM) {
++ /*
++ * Retain the VIA chipset work-around (gsi > 15), but
++ * avoid a problem where the 8254 timer (IRQ0) is setup
++ * via an override (so it's not on pin 0 of the ioapic),
++ * and at the same time, the pin 0 interrupt is a PCI
++ * type. The gsi > 15 test could cause these two pins
++ * to be shared as IRQ0, and they are not shareable.
++ * So test for this condition, and if necessary, avoid
++ * the pin collision.
++ */
++ if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
++ gsi = pci_irq++;
++ /*
++ * Don't assign IRQ used by ACPI SCI
++ */
++ if (gsi == acpi_fadt.sci_int)
++ gsi = pci_irq++;
++ gsi_to_irq[irq] = gsi;
++ } else {
++ printk(KERN_ERR "GSI %u is too high\n", gsi);
++ return gsi;
++ }
++ }
++
++ io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
++ triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
++ polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
++ return gsi;
++}
++
++#endif /*CONFIG_X86_IO_APIC*/
++#endif /*CONFIG_ACPI*/
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/pci-swiotlb-xen.c linux-2.6.18-xen/arch/x86_64/kernel/pci-swiotlb-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/pci-swiotlb-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/pci-swiotlb-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,54 @@
++/* Glue code to lib/swiotlb.c */
++
++#include <linux/pci.h>
++#include <linux/cache.h>
++#include <linux/module.h>
++#include <asm/dma-mapping.h>
++#include <asm/proto.h>
++#include <asm/swiotlb.h>
++#include <asm/dma.h>
++
++#if 0
++int swiotlb __read_mostly;
++EXPORT_SYMBOL(swiotlb);
++#endif
++
++struct dma_mapping_ops swiotlb_dma_ops = {
++#if 0
++ .mapping_error = swiotlb_dma_mapping_error,
++ .alloc_coherent = swiotlb_alloc_coherent,
++ .free_coherent = swiotlb_free_coherent,
++ .map_single = swiotlb_map_single,
++ .unmap_single = swiotlb_unmap_single,
++ .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
++ .sync_single_for_device = swiotlb_sync_single_for_device,
++ .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
++ .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
++ .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
++ .sync_sg_for_device = swiotlb_sync_sg_for_device,
++ .map_sg = swiotlb_map_sg,
++ .unmap_sg = swiotlb_unmap_sg,
++ .dma_supported = NULL,
++#endif
++};
++
++void pci_swiotlb_init(void)
++{
++#if 0
++ /* don't initialize swiotlb if iommu=off (no_iommu=1) */
++ if (!iommu_aperture && !no_iommu &&
++ (end_pfn > MAX_DMA32_PFN || force_iommu))
++ swiotlb = 1;
++ if (swiotlb) {
++ printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n");
++ swiotlb_init();
++ dma_ops = &swiotlb_dma_ops;
++ }
++#else
++ swiotlb_init();
++ if (swiotlb) {
++ printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n");
++ dma_ops = &swiotlb_dma_ops;
++ }
++#endif
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/process-xen.c linux-2.6.18-xen/arch/x86_64/kernel/process-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/process-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/process-xen.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,793 @@
++/*
++ * linux/arch/x86-64/kernel/process.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ *
++ * Pentium III FXSR, SSE support
++ * Gareth Hughes <gareth at valinux.com>, May 2000
++ *
++ * X86-64 port
++ * Andi Kleen.
++ *
++ * CPU hotplug support - ashok.raj at intel.com
++ *
++ * Jun Nakajima <jun.nakajima at intel.com>
++ * Modified for Xen
++ */
++
++/*
++ * This file handles the architecture-dependent parts of process handling..
++ */
++
++#include <stdarg.h>
++
++#include <linux/cpu.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/elfcore.h>
++#include <linux/smp.h>
++#include <linux/slab.h>
++#include <linux/user.h>
++#include <linux/module.h>
++#include <linux/a.out.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/ptrace.h>
++#include <linux/utsname.h>
++#include <linux/random.h>
++#include <linux/notifier.h>
++#include <linux/kprobes.h>
++
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/processor.h>
++#include <asm/i387.h>
++#include <asm/mmu_context.h>
++#include <asm/pda.h>
++#include <asm/prctl.h>
++#include <asm/kdebug.h>
++#include <xen/interface/dom0_ops.h>
++#include <xen/interface/physdev.h>
++#include <xen/interface/vcpu.h>
++#include <asm/desc.h>
++#include <asm/proto.h>
++#include <asm/hardirq.h>
++#include <asm/ia32.h>
++#include <asm/idle.h>
++
++#include <xen/cpu_hotplug.h>
++
++asmlinkage extern void ret_from_fork(void);
++
++unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
++
++unsigned long boot_option_idle_override = 0;
++EXPORT_SYMBOL(boot_option_idle_override);
++
++/*
++ * Powermanagement idle function, if any..
++ */
++void (*pm_idle)(void);
++static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
++
++static ATOMIC_NOTIFIER_HEAD(idle_notifier);
++
++void idle_notifier_register(struct notifier_block *n)
++{
++ atomic_notifier_chain_register(&idle_notifier, n);
++}
++EXPORT_SYMBOL_GPL(idle_notifier_register);
++
++void idle_notifier_unregister(struct notifier_block *n)
++{
++ atomic_notifier_chain_unregister(&idle_notifier, n);
++}
++EXPORT_SYMBOL(idle_notifier_unregister);
++
++enum idle_state { CPU_IDLE, CPU_NOT_IDLE };
++static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE;
++
++void enter_idle(void)
++{
++ __get_cpu_var(idle_state) = CPU_IDLE;
++ atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
++}
++
++static void __exit_idle(void)
++{
++ __get_cpu_var(idle_state) = CPU_NOT_IDLE;
++ atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
++}
++
++/* Called from interrupts to signify idle end */
++void exit_idle(void)
++{
++ if (current->pid | read_pda(irqcount))
++ return;
++ __exit_idle();
++}
++
++/* XXX XEN doesn't use default_idle(), poll_idle(). Use xen_idle() instead. */
++void xen_idle(void)
++{
++ local_irq_disable();
++
++ if (need_resched())
++ local_irq_enable();
++ else {
++ current_thread_info()->status &= ~TS_POLLING;
++ smp_mb__after_clear_bit();
++ safe_halt();
++ current_thread_info()->status |= TS_POLLING;
++ }
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static inline void play_dead(void)
++{
++ idle_task_exit();
++ local_irq_disable();
++ cpu_clear(smp_processor_id(), cpu_initialized);
++ preempt_enable_no_resched();
++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
++ cpu_bringup();
++}
++#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)
++{
++ current_thread_info()->status |= TS_POLLING;
++ /* endless idle loop with no priority at all */
++ while (1) {
++ while (!need_resched()) {
++ if (__get_cpu_var(cpu_idle_state))
++ __get_cpu_var(cpu_idle_state) = 0;
++ rmb();
++
++ if (cpu_is_offline(smp_processor_id()))
++ play_dead();
++ enter_idle();
++ xen_idle();
++ __exit_idle();
++ }
++
++ preempt_enable_no_resched();
++ schedule();
++ preempt_disable();
++ }
++}
++
++void cpu_idle_wait(void)
++{
++ unsigned int cpu, this_cpu = get_cpu();
++ cpumask_t map;
++
++ set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
++ put_cpu();
++
++ cpus_clear(map);
++ for_each_online_cpu(cpu) {
++ per_cpu(cpu_idle_state, cpu) = 1;
++ cpu_set(cpu, map);
++ }
++
++ __get_cpu_var(cpu_idle_state) = 0;
++
++ wmb();
++ do {
++ ssleep(1);
++ for_each_online_cpu(cpu) {
++ if (cpu_isset(cpu, map) &&
++ !per_cpu(cpu_idle_state, cpu))
++ cpu_clear(cpu, map);
++ }
++ cpus_and(map, map, cpu_online_map);
++ } while (!cpus_empty(map));
++}
++EXPORT_SYMBOL_GPL(cpu_idle_wait);
++
++/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */
++/* Always use xen_idle() instead. */
++void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) {}
++
++/* Prints also some state that isn't saved in the pt_regs */
++void __show_regs(struct pt_regs * regs)
++{
++ unsigned long fs, gs, shadowgs;
++ unsigned int fsindex,gsindex;
++ unsigned int ds,cs,es;
++
++ printk("\n");
++ print_modules();
++ printk("Pid: %d, comm: %.20s %s %s %.*s\n",
++ current->pid, current->comm, print_tainted(),
++ system_utsname.release,
++ (int)strcspn(system_utsname.version, " "),
++ system_utsname.version);
++ printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
++ printk_address(regs->rip);
++ printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp,
++ regs->eflags);
++ printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
++ regs->rax, regs->rbx, regs->rcx);
++ printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
++ regs->rdx, regs->rsi, regs->rdi);
++ printk("RBP: %016lx R08: %016lx R09: %016lx\n",
++ regs->rbp, regs->r8, regs->r9);
++ printk("R10: %016lx R11: %016lx R12: %016lx\n",
++ regs->r10, regs->r11, regs->r12);
++ printk("R13: %016lx R14: %016lx R15: %016lx\n",
++ regs->r13, regs->r14, regs->r15);
++
++ asm("mov %%ds,%0" : "=r" (ds));
++ asm("mov %%cs,%0" : "=r" (cs));
++ asm("mov %%es,%0" : "=r" (es));
++ asm("mov %%fs,%0" : "=r" (fsindex));
++ asm("mov %%gs,%0" : "=r" (gsindex));
++
++ rdmsrl(MSR_FS_BASE, fs);
++ rdmsrl(MSR_GS_BASE, gs);
++ rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
++
++ printk("FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
++ fs,fsindex,gs,gsindex,shadowgs);
++ printk("CS: %04x DS: %04x ES: %04x\n", cs, ds, es);
++
++}
++
++void show_regs(struct pt_regs *regs)
++{
++ printk("CPU %d:", smp_processor_id());
++ __show_regs(regs);
++ show_trace(NULL, regs, ®s->rsp);
++}
++
++/*
++ * Free current thread data structures etc..
++ */
++void exit_thread(void)
++{
++ struct task_struct *me = current;
++ struct thread_struct *t = &me->thread;
++
++ if (me->thread.io_bitmap_ptr) {
++#ifndef CONFIG_X86_NO_TSS
++ struct tss_struct *tss = &per_cpu(init_tss, get_cpu());
++#endif
++#ifdef CONFIG_XEN
++ struct physdev_set_iobitmap iobmp_op = { 0 };
++#endif
++
++ kfree(t->io_bitmap_ptr);
++ t->io_bitmap_ptr = NULL;
++ /*
++ * Careful, clear this in the TSS too:
++ */
++#ifndef CONFIG_X86_NO_TSS
++ memset(tss->io_bitmap, 0xff, t->io_bitmap_max);
++ put_cpu();
++#endif
++#ifdef CONFIG_XEN
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &iobmp_op);
++#endif
++ t->io_bitmap_max = 0;
++ }
++}
++
++void load_gs_index(unsigned gs)
++{
++ HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, gs);
++}
++
++void flush_thread(void)
++{
++ struct task_struct *tsk = current;
++ struct thread_info *t = current_thread_info();
++
++ if (t->flags & _TIF_ABI_PENDING) {
++ t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
++ if (t->flags & _TIF_IA32)
++ current_thread_info()->status |= TS_COMPAT;
++ }
++
++
++ tsk->thread.debugreg0 = 0;
++ tsk->thread.debugreg1 = 0;
++ tsk->thread.debugreg2 = 0;
++ tsk->thread.debugreg3 = 0;
++ tsk->thread.debugreg6 = 0;
++ tsk->thread.debugreg7 = 0;
++ memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
++ /*
++ * Forget coprocessor state..
++ */
++ clear_fpu(tsk);
++ clear_used_math();
++}
++
++void release_thread(struct task_struct *dead_task)
++{
++ if (dead_task->mm) {
++ if (dead_task->mm->context.size) {
++ printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
++ dead_task->comm,
++ dead_task->mm->context.ldt,
++ dead_task->mm->context.size);
++ BUG();
++ }
++ }
++}
++
++static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr)
++{
++ struct user_desc ud = {
++ .base_addr = addr,
++ .limit = 0xfffff,
++ .seg_32bit = 1,
++ .limit_in_pages = 1,
++ .useable = 1,
++ };
++ struct n_desc_struct *desc = (void *)t->thread.tls_array;
++ desc += tls;
++ desc->a = LDT_entry_a(&ud);
++ desc->b = LDT_entry_b(&ud);
++}
++
++static inline u32 read_32bit_tls(struct task_struct *t, int tls)
++{
++ struct desc_struct *desc = (void *)t->thread.tls_array;
++ desc += tls;
++ return desc->base0 |
++ (((u32)desc->base1) << 16) |
++ (((u32)desc->base2) << 24);
++}
++
++/*
++ * This gets called before we allocate a new thread and copy
++ * the current task into it.
++ */
++void prepare_to_copy(struct task_struct *tsk)
++{
++ unlazy_fpu(tsk);
++}
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp,
++ unsigned long unused,
++ struct task_struct * p, struct pt_regs * regs)
++{
++ int err;
++ struct pt_regs * childregs;
++ struct task_struct *me = current;
++
++ childregs = ((struct pt_regs *)
++ (THREAD_SIZE + task_stack_page(p))) - 1;
++ *childregs = *regs;
++
++ childregs->rax = 0;
++ childregs->rsp = rsp;
++ if (rsp == ~0UL)
++ childregs->rsp = (unsigned long)childregs;
++
++ p->thread.rsp = (unsigned long) childregs;
++ p->thread.rsp0 = (unsigned long) (childregs+1);
++ p->thread.userrsp = me->thread.userrsp;
++
++ set_tsk_thread_flag(p, TIF_FORK);
++
++ p->thread.fs = me->thread.fs;
++ p->thread.gs = me->thread.gs;
++
++ asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
++ asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
++ asm("mov %%es,%0" : "=m" (p->thread.es));
++ asm("mov %%ds,%0" : "=m" (p->thread.ds));
++
++ if (unlikely(me->thread.io_bitmap_ptr != NULL)) {
++ p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
++ if (!p->thread.io_bitmap_ptr) {
++ p->thread.io_bitmap_max = 0;
++ return -ENOMEM;
++ }
++ memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr,
++ IO_BITMAP_BYTES);
++ }
++
++ /*
++ * Set a new TLS for the child thread?
++ */
++ if (clone_flags & CLONE_SETTLS) {
++#ifdef CONFIG_IA32_EMULATION
++ if (test_thread_flag(TIF_IA32))
++ err = ia32_child_tls(p, childregs);
++ else
++#endif
++ err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8);
++ if (err)
++ goto out;
++ }
++ p->thread.iopl = current->thread.iopl;
++
++ err = 0;
++out:
++ if (err && p->thread.io_bitmap_ptr) {
++ kfree(p->thread.io_bitmap_ptr);
++ p->thread.io_bitmap_max = 0;
++ }
++ return err;
++}
++
++static inline void __save_init_fpu( struct task_struct *tsk )
++{
++ asm volatile( "rex64 ; fxsave %0 ; fnclex"
++ : "=m" (tsk->thread.i387.fxsave));
++ tsk->thread_info->status &= ~TS_USEDFPU;
++}
++
++/*
++ * switch_to(x,y) should switch tasks from x to y.
++ *
++ * This could still be optimized:
++ * - fold all the options into a flag word and test it with a single test.
++ * - could test fs/gs bitsliced
++ *
++ * Kprobes not supported here. Set the probe on schedule instead.
++ */
++__kprobes struct task_struct *
++__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
++{
++ struct thread_struct *prev = &prev_p->thread,
++ *next = &next_p->thread;
++ int cpu = smp_processor_id();
++#ifndef CONFIG_X86_NO_TSS
++ struct tss_struct *tss = &per_cpu(init_tss, cpu);
++#endif
++ struct physdev_set_iopl iopl_op;
++ struct physdev_set_iobitmap iobmp_op;
++ multicall_entry_t _mcl[8], *mcl = _mcl;
++
++ /*
++ * Reload esp0, LDT and the page table pointer:
++ */
++ mcl->op = __HYPERVISOR_stack_switch;
++ mcl->args[0] = __KERNEL_DS;
++ mcl->args[1] = next->rsp0;
++ mcl++;
++
++ /*
++ * Load the per-thread Thread-Local Storage descriptor.
++ * This is load_TLS(next, cpu) with multicalls.
++ */
++#define C(i) do { \
++ if (unlikely(next->tls_array[i] != prev->tls_array[i])) { \
++ mcl->op = __HYPERVISOR_update_descriptor; \
++ mcl->args[0] = virt_to_machine( \
++ &cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]); \
++ mcl->args[1] = next->tls_array[i]; \
++ mcl++; \
++ } \
++} while (0)
++ C(0); C(1); C(2);
++#undef C
++
++ if (unlikely(prev->iopl != next->iopl)) {
++ iopl_op.iopl = (next->iopl == 0) ? 1 : next->iopl;
++ mcl->op = __HYPERVISOR_physdev_op;
++ mcl->args[0] = PHYSDEVOP_set_iopl;
++ mcl->args[1] = (unsigned long)&iopl_op;
++ mcl++;
++ }
++
++ if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
++ iobmp_op.bitmap = (char *)next->io_bitmap_ptr;
++ iobmp_op.nr_ports = next->io_bitmap_ptr ? IO_BITMAP_BITS : 0;
++ mcl->op = __HYPERVISOR_physdev_op;
++ mcl->args[0] = PHYSDEVOP_set_iobitmap;
++ mcl->args[1] = (unsigned long)&iobmp_op;
++ mcl++;
++ }
++
++ (void)HYPERVISOR_multicall(_mcl, mcl - _mcl);
++ /*
++ * Switch DS and ES.
++ * This won't pick up thread selector changes, but I guess that is ok.
++ */
++ if (unlikely(next->es))
++ loadsegment(es, next->es);
++
++ if (unlikely(next->ds))
++ loadsegment(ds, next->ds);
++
++ /*
++ * Switch FS and GS.
++ */
++ if (unlikely(next->fsindex))
++ loadsegment(fs, next->fsindex);
++
++ if (next->fs)
++ HYPERVISOR_set_segment_base(SEGBASE_FS, next->fs);
++
++ if (unlikely(next->gsindex))
++ load_gs_index(next->gsindex);
++
++ if (next->gs)
++ HYPERVISOR_set_segment_base(SEGBASE_GS_USER, next->gs);
++
++ /*
++ * Switch the PDA and FPU context.
++ */
++ prev->userrsp = read_pda(oldrsp);
++ write_pda(oldrsp, next->userrsp);
++ write_pda(pcurrent, next_p);
++
++ /* This must be here to ensure both math_state_restore() and
++ kernel_fpu_begin() work consistently.
++ And the AMD workaround requires it to be after DS reload. */
++ /*
++ * This is basically '__unlazy_fpu', except that we queue a
++ * multicall to indicate FPU task switch, rather than
++ * synchronously trapping to Xen.
++ */
++ if (prev_p->thread_info->status & TS_USEDFPU) {
++ __save_init_fpu(prev_p); /* _not_ save_init_fpu() */
++ HYPERVISOR_fpu_taskswitch(1);
++ }
++ write_pda(kernelstack,
++ task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
++
++ /*
++ * Now maybe reload the debug registers
++ */
++ if (unlikely(next->debugreg7)) {
++ set_debugreg(next->debugreg0, 0);
++ set_debugreg(next->debugreg1, 1);
++ set_debugreg(next->debugreg2, 2);
++ set_debugreg(next->debugreg3, 3);
++ /* no 4 and 5 */
++ set_debugreg(next->debugreg6, 6);
++ set_debugreg(next->debugreg7, 7);
++ }
++
++ return prev_p;
++}
++
++/*
++ * sys_execve() executes a new program.
++ */
++asmlinkage
++long sys_execve(char __user *name, char __user * __user *argv,
++ char __user * __user *envp, struct pt_regs regs)
++{
++ long error;
++ char * filename;
++
++ filename = getname(name);
++ error = PTR_ERR(filename);
++ if (IS_ERR(filename))
++ return error;
++ error = do_execve(filename, argv, envp, ®s);
++ if (error == 0) {
++ task_lock(current);
++ current->ptrace &= ~PT_DTRACE;
++ task_unlock(current);
++ }
++ putname(filename);
++ return error;
++}
++
++void set_personality_64bit(void)
++{
++ /* inherit personality from parent */
++
++ /* Make sure to be in 64bit mode */
++ clear_thread_flag(TIF_IA32);
++
++ /* TBD: overwrites user setup. Should have two bits.
++ But 64bit processes have always behaved this way,
++ so it's not too bad. The main problem is just that
++ 32bit childs are affected again. */
++ current->personality &= ~READ_IMPLIES_EXEC;
++}
++
++asmlinkage long sys_fork(struct pt_regs *regs)
++{
++ return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL);
++}
++
++asmlinkage long
++sys_clone(unsigned long clone_flags, unsigned long newsp,
++ void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
++{
++ if (!newsp)
++ newsp = regs->rsp;
++ return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
++}
++
++/*
++ * This is trivial, and on the face of it looks like it
++ * could equally well be done in user mode.
++ *
++ * Not so, for quite unobvious reasons - register pressure.
++ * In user mode vfork() cannot have a stack frame, and if
++ * done by calling the "clone()" system call directly, you
++ * do not have enough call-clobbered registers to hold all
++ * the information you need.
++ */
++asmlinkage long sys_vfork(struct pt_regs *regs)
++{
++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0,
++ NULL, NULL);
++}
++
++unsigned long get_wchan(struct task_struct *p)
++{
++ unsigned long stack;
++ u64 fp,rip;
++ int count = 0;
++
++ if (!p || p == current || p->state==TASK_RUNNING)
++ return 0;
++ stack = (unsigned long)task_stack_page(p);
++ if (p->thread.rsp < stack || p->thread.rsp > stack+THREAD_SIZE)
++ return 0;
++ fp = *(u64 *)(p->thread.rsp);
++ do {
++ if (fp < (unsigned long)stack ||
++ fp > (unsigned long)stack+THREAD_SIZE)
++ return 0;
++ rip = *(u64 *)(fp+8);
++ if (!in_sched_functions(rip))
++ return rip;
++ fp = *(u64 *)fp;
++ } while (count++ < 16);
++ return 0;
++}
++
++long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
++{
++ int ret = 0;
++ int doit = task == current;
++ int cpu;
++
++ switch (code) {
++ case ARCH_SET_GS:
++ if (addr >= TASK_SIZE_OF(task))
++ return -EPERM;
++ cpu = get_cpu();
++ /* handle small bases via the GDT because that's faster to
++ switch. */
++ if (addr <= 0xffffffff) {
++ set_32bit_tls(task, GS_TLS, addr);
++ if (doit) {
++ load_TLS(&task->thread, cpu);
++ load_gs_index(GS_TLS_SEL);
++ }
++ task->thread.gsindex = GS_TLS_SEL;
++ task->thread.gs = 0;
++ } else {
++ task->thread.gsindex = 0;
++ task->thread.gs = addr;
++ if (doit) {
++ load_gs_index(0);
++ ret = HYPERVISOR_set_segment_base(
++ SEGBASE_GS_USER, addr);
++ }
++ }
++ put_cpu();
++ break;
++ case ARCH_SET_FS:
++ /* Not strictly needed for fs, but do it for symmetry
++ with gs */
++ if (addr >= TASK_SIZE_OF(task))
++ return -EPERM;
++ cpu = get_cpu();
++ /* handle small bases via the GDT because that's faster to
++ switch. */
++ if (addr <= 0xffffffff) {
++ set_32bit_tls(task, FS_TLS, addr);
++ if (doit) {
++ load_TLS(&task->thread, cpu);
++ asm volatile("movl %0,%%fs" :: "r"(FS_TLS_SEL));
++ }
++ task->thread.fsindex = FS_TLS_SEL;
++ task->thread.fs = 0;
++ } else {
++ task->thread.fsindex = 0;
++ task->thread.fs = addr;
++ if (doit) {
++ /* set the selector to 0 to not confuse
++ __switch_to */
++ asm volatile("movl %0,%%fs" :: "r" (0));
++ ret = HYPERVISOR_set_segment_base(SEGBASE_FS,
++ addr);
++ }
++ }
++ put_cpu();
++ break;
++ case ARCH_GET_FS: {
++ unsigned long base;
++ if (task->thread.fsindex == FS_TLS_SEL)
++ base = read_32bit_tls(task, FS_TLS);
++ else if (doit)
++ rdmsrl(MSR_FS_BASE, base);
++ else
++ base = task->thread.fs;
++ ret = put_user(base, (unsigned long __user *)addr);
++ break;
++ }
++ case ARCH_GET_GS: {
++ unsigned long base;
++ unsigned gsindex;
++ if (task->thread.gsindex == GS_TLS_SEL)
++ base = read_32bit_tls(task, GS_TLS);
++ else if (doit) {
++ asm("movl %%gs,%0" : "=r" (gsindex));
++ if (gsindex)
++ rdmsrl(MSR_KERNEL_GS_BASE, base);
++ else
++ base = task->thread.gs;
++ }
++ else
++ base = task->thread.gs;
++ ret = put_user(base, (unsigned long __user *)addr);
++ break;
++ }
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++long sys_arch_prctl(int code, unsigned long addr)
++{
++ return do_arch_prctl(current, code, addr);
++}
++
++/*
++ * Capture the user space registers if the task is not running (in user space)
++ */
++int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
++{
++ struct pt_regs *pp, ptregs;
++
++ pp = task_pt_regs(tsk);
++
++ ptregs = *pp;
++ ptregs.cs &= 0xffff;
++ ptregs.ss &= 0xffff;
++
++ elf_core_copy_regs(regs, &ptregs);
++
++ boot_option_idle_override = 1;
++ return 1;
++}
++
++unsigned long arch_align_stack(unsigned long sp)
++{
++ if (randomize_va_space)
++ sp -= get_random_int() % 8192;
++ return sp & ~0xf;
++}
++
++#ifndef CONFIG_SMP
++void _restore_vcpu(void)
++{
++}
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/setup64-xen.c linux-2.6.18-xen/arch/x86_64/kernel/setup64-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/setup64-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/setup64-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,361 @@
++/*
++ * X86-64 specific CPU setup.
++ * Copyright (C) 1995 Linus Torvalds
++ * Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen.
++ * See setup.c for older changelog.
++ *
++ * Jun Nakajima <jun.nakajima at intel.com>
++ * Modified for Xen
++ *
++ */
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/bootmem.h>
++#include <linux/bitops.h>
++#include <linux/module.h>
++#include <asm/bootsetup.h>
++#include <asm/pda.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/desc.h>
++#include <asm/atomic.h>
++#include <asm/mmu_context.h>
++#include <asm/smp.h>
++#include <asm/i387.h>
++#include <asm/percpu.h>
++#include <asm/proto.h>
++#include <asm/sections.h>
++#ifdef CONFIG_XEN
++#include <asm/hypervisor.h>
++#endif
++
++char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
++
++cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
++
++struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly;
++EXPORT_SYMBOL(_cpu_pda);
++struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned;
++
++#ifndef CONFIG_X86_NO_IDT
++struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
++#endif
++
++char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
++
++unsigned long __supported_pte_mask __read_mostly = ~0UL;
++EXPORT_SYMBOL(__supported_pte_mask);
++static int do_not_nx __cpuinitdata = 0;
++
++/* noexec=on|off
++Control non executable mappings for 64bit processes.
++
++on Enable(default)
++off Disable
++*/
++int __init nonx_setup(char *str)
++{
++ if (!strncmp(str, "on", 2)) {
++ __supported_pte_mask |= _PAGE_NX;
++ do_not_nx = 0;
++ } else if (!strncmp(str, "off", 3)) {
++ do_not_nx = 1;
++ __supported_pte_mask &= ~_PAGE_NX;
++ }
++ return 1;
++}
++__setup("noexec=", nonx_setup); /* parsed early actually */
++
++int force_personality32 = 0;
++
++/* noexec32=on|off
++Control non executable heap for 32bit processes.
++To control the stack too use noexec=off
++
++on PROT_READ does not imply PROT_EXEC for 32bit processes
++off PROT_READ implies PROT_EXEC (default)
++*/
++static int __init nonx32_setup(char *str)
++{
++ if (!strcmp(str, "on"))
++ force_personality32 &= ~READ_IMPLIES_EXEC;
++ else if (!strcmp(str, "off"))
++ force_personality32 |= READ_IMPLIES_EXEC;
++ return 1;
++}
++__setup("noexec32=", nonx32_setup);
++
++/*
++ * Great future plan:
++ * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
++ * Always point %gs to its beginning
++ */
++void __init setup_per_cpu_areas(void)
++{
++ int i;
++ unsigned long size;
++
++#ifdef CONFIG_HOTPLUG_CPU
++ prefill_possible_map();
++#endif
++
++ /* Copy section for each CPU (we discard the original) */
++ size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
++#ifdef CONFIG_MODULES
++ if (size < PERCPU_ENOUGH_ROOM)
++ size = PERCPU_ENOUGH_ROOM;
++#endif
++
++ for_each_cpu_mask (i, cpu_possible_map) {
++ char *ptr;
++
++ if (!NODE_DATA(cpu_to_node(i))) {
++ printk("cpu with no node %d, num_online_nodes %d\n",
++ i, num_online_nodes());
++ ptr = alloc_bootmem(size);
++ } else {
++ ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
++ }
++ if (!ptr)
++ panic("Cannot allocate cpu data for CPU %d\n", i);
++ cpu_pda(i)->data_offset = ptr - __per_cpu_start;
++ memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
++ }
++}
++
++#ifdef CONFIG_XEN
++static void switch_pt(void)
++{
++ xen_pt_switch(__pa(init_level4_pgt));
++ xen_new_user_pt(__pa(init_level4_user_pgt));
++}
++
++void __cpuinit cpu_gdt_init(struct desc_ptr *gdt_descr)
++{
++ unsigned long frames[16];
++ unsigned long va;
++ int f;
++
++ for (va = gdt_descr->address, f = 0;
++ va < gdt_descr->address + gdt_descr->size;
++ va += PAGE_SIZE, f++) {
++ frames[f] = virt_to_mfn(va);
++ make_page_readonly(
++ (void *)va, XENFEAT_writable_descriptor_tables);
++ }
++ if (HYPERVISOR_set_gdt(frames, gdt_descr->size /
++ sizeof (struct desc_struct)))
++ BUG();
++}
++#else
++static void switch_pt(void)
++{
++ asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
++}
++
++void __init cpu_gdt_init(struct desc_ptr *gdt_descr)
++{
++ asm volatile("lgdt %0" :: "m" (*gdt_descr));
++ asm volatile("lidt %0" :: "m" (idt_descr));
++}
++#endif
++
++void pda_init(int cpu)
++{
++ struct x8664_pda *pda = cpu_pda(cpu);
++
++ /* Setup up data that may be needed in __get_free_pages early */
++ asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
++#ifndef CONFIG_XEN
++ wrmsrl(MSR_GS_BASE, pda);
++#else
++ HYPERVISOR_set_segment_base(SEGBASE_GS_KERNEL, (unsigned long)pda);
++#endif
++ pda->cpunumber = cpu;
++ pda->irqcount = -1;
++ pda->kernelstack =
++ (unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE;
++ pda->active_mm = &init_mm;
++ pda->mmu_state = 0;
++
++ if (cpu == 0) {
++#ifdef CONFIG_XEN
++ xen_init_pt();
++#endif
++ /* others are initialized in smpboot.c */
++ pda->pcurrent = &init_task;
++ pda->irqstackptr = boot_cpu_stack;
++ } else {
++ pda->irqstackptr = (char *)
++ __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
++ if (!pda->irqstackptr)
++ panic("cannot allocate irqstack for cpu %d", cpu);
++ }
++
++ switch_pt();
++
++ pda->irqstackptr += IRQSTACKSIZE-64;
++}
++
++#ifndef CONFIG_X86_NO_TSS
++char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]
++__attribute__((section(".bss.page_aligned")));
++#endif
++
++/* May not be marked __init: used by software suspend */
++void syscall_init(void)
++{
++#ifndef CONFIG_XEN
++ /*
++ * LSTAR and STAR live in a bit strange symbiosis.
++ * They both write to the same internal register. STAR allows to set CS/DS
++ * but only a 32bit target. LSTAR sets the 64bit rip.
++ */
++ wrmsrl(MSR_STAR, ((u64)__USER32_CS)<<48 | ((u64)__KERNEL_CS)<<32);
++ wrmsrl(MSR_LSTAR, system_call);
++
++ /* Flags to clear on syscall */
++ wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000);
++#endif
++#ifdef CONFIG_IA32_EMULATION
++ syscall32_cpu_init ();
++#endif
++}
++
++void __cpuinit check_efer(void)
++{
++ unsigned long efer;
++
++ rdmsrl(MSR_EFER, efer);
++ if (!(efer & EFER_NX) || do_not_nx) {
++ __supported_pte_mask &= ~_PAGE_NX;
++ }
++}
++
++/*
++ * cpu_init() initializes state that is per-CPU. Some data is already
++ * initialized (naturally) in the bootstrap process, such as the GDT
++ * and IDT. We reload them nevertheless, this function acts as a
++ * 'CPU state barrier', nothing should get across.
++ * A lot of state is already set up in PDA init.
++ */
++void __cpuinit cpu_init (void)
++{
++ int cpu = stack_smp_processor_id();
++#ifndef CONFIG_X86_NO_TSS
++ struct tss_struct *t = &per_cpu(init_tss, cpu);
++ struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
++ unsigned long v;
++ char *estacks = NULL;
++ unsigned i;
++#endif
++ struct task_struct *me;
++
++ /* CPU 0 is initialised in head64.c */
++ if (cpu != 0) {
++ pda_init(cpu);
++ zap_low_mappings(cpu);
++ }
++#ifndef CONFIG_X86_NO_TSS
++ else
++ estacks = boot_exception_stacks;
++#endif
++
++ me = current;
++
++ if (cpu_test_and_set(cpu, cpu_initialized))
++ panic("CPU#%d already initialized!\n", cpu);
++
++ printk("Initializing CPU#%d\n", cpu);
++
++ clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
++
++ /*
++ * Initialize the per-CPU GDT with the boot GDT,
++ * and set up the GDT descriptor:
++ */
++#ifndef CONFIG_XEN
++ if (cpu)
++ memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE);
++#endif
++
++ cpu_gdt_descr[cpu].size = GDT_SIZE;
++ cpu_gdt_init(&cpu_gdt_descr[cpu]);
++
++ memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
++ syscall_init();
++
++ wrmsrl(MSR_FS_BASE, 0);
++ wrmsrl(MSR_KERNEL_GS_BASE, 0);
++ barrier();
++
++ check_efer();
++
++#ifndef CONFIG_X86_NO_TSS
++ /*
++ * set up and load the per-CPU TSS
++ */
++ for (v = 0; v < N_EXCEPTION_STACKS; v++) {
++ if (cpu) {
++ static const unsigned int order[N_EXCEPTION_STACKS] = {
++ [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
++ [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
++ };
++
++ estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
++ if (!estacks)
++ panic("Cannot allocate exception stack %ld %d\n",
++ v, cpu);
++ }
++ switch (v + 1) {
++#if DEBUG_STKSZ > EXCEPTION_STKSZ
++ case DEBUG_STACK:
++ cpu_pda(cpu)->debugstack = (unsigned long)estacks;
++ estacks += DEBUG_STKSZ;
++ break;
++#endif
++ default:
++ estacks += EXCEPTION_STKSZ;
++ break;
++ }
++ orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks;
++ }
++
++ t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
++ /*
++ * <= is required because the CPU will access up to
++ * 8 bits beyond the end of the IO permission bitmap.
++ */
++ for (i = 0; i <= IO_BITMAP_LONGS; i++)
++ t->io_bitmap[i] = ~0UL;
++#endif
++
++ atomic_inc(&init_mm.mm_count);
++ me->active_mm = &init_mm;
++ if (me->mm)
++ BUG();
++ enter_lazy_tlb(&init_mm, me);
++
++#ifndef CONFIG_X86_NO_TSS
++ set_tss_desc(cpu, t);
++#endif
++#ifndef CONFIG_XEN
++ load_TR_desc();
++#endif
++ load_LDT(&init_mm.context);
++
++ /*
++ * Clear all 6 debug registers:
++ */
++
++ set_debugreg(0UL, 0);
++ set_debugreg(0UL, 1);
++ set_debugreg(0UL, 2);
++ set_debugreg(0UL, 3);
++ set_debugreg(0UL, 6);
++ set_debugreg(0UL, 7);
++
++ fpu_init();
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/setup-xen.c linux-2.6.18-xen/arch/x86_64/kernel/setup-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/setup-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/setup-xen.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,1637 @@
++/*
++ * linux/arch/x86-64/kernel/setup.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ *
++ * Nov 2001 Dave Jones <davej at suse.de>
++ * Forked from i386 setup code.
++ */
++
++/*
++ * This file handles the architecture-dependent parts of initialization
++ */
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/stddef.h>
++#include <linux/unistd.h>
++#include <linux/ptrace.h>
++#include <linux/slab.h>
++#include <linux/user.h>
++#include <linux/a.out.h>
++#include <linux/screen_info.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/initrd.h>
++#include <linux/highmem.h>
++#include <linux/bootmem.h>
++#include <linux/module.h>
++#include <asm/processor.h>
++#include <linux/console.h>
++#include <linux/seq_file.h>
++#include <linux/crash_dump.h>
++#include <linux/root_dev.h>
++#include <linux/pci.h>
++#include <linux/acpi.h>
++#include <linux/kallsyms.h>
++#include <linux/edd.h>
++#include <linux/mmzone.h>
++#include <linux/kexec.h>
++#include <linux/cpufreq.h>
++#include <linux/dmi.h>
++#include <linux/dma-mapping.h>
++#include <linux/ctype.h>
++
++#include <asm/mtrr.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/smp.h>
++#include <asm/msr.h>
++#include <asm/desc.h>
++#include <video/edid.h>
++#include <asm/e820.h>
++#include <asm/dma.h>
++#include <asm/mpspec.h>
++#include <asm/mmu_context.h>
++#include <asm/bootsetup.h>
++#include <asm/proto.h>
++#include <asm/setup.h>
++#include <asm/mach_apic.h>
++#include <asm/numa.h>
++#include <asm/sections.h>
++#include <asm/dmi.h>
++#ifdef CONFIG_XEN
++#include <linux/percpu.h>
++#include <linux/pfn.h>
++#include <xen/interface/physdev.h>
++#include "setup_arch_pre.h"
++#include <asm/hypervisor.h>
++#include <xen/interface/nmi.h>
++#include <xen/features.h>
++#include <xen/xencons.h>
++#include <asm/mach-xen/setup_arch_post.h>
++#include <xen/interface/memory.h>
++
++extern unsigned long start_pfn;
++extern struct edid_info edid_info;
++EXPORT_SYMBOL_GPL(edid_info);
++
++shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
++EXPORT_SYMBOL(HYPERVISOR_shared_info);
++
++extern char hypercall_page[PAGE_SIZE];
++EXPORT_SYMBOL(hypercall_page);
++
++/* Allows setting of maximum possible memory size */
++unsigned long xen_override_max_pfn;
++
++static int xen_panic_event(struct notifier_block *, unsigned long, void *);
++static struct notifier_block xen_panic_block = {
++ xen_panic_event, NULL, 0 /* try to go last */
++};
++
++unsigned long *phys_to_machine_mapping;
++unsigned long *pfn_to_mfn_frame_list_list, *pfn_to_mfn_frame_list[512];
++
++EXPORT_SYMBOL(phys_to_machine_mapping);
++
++DEFINE_PER_CPU(multicall_entry_t, multicall_list[8]);
++DEFINE_PER_CPU(int, nr_multicall_ents);
++
++/* Raw start-of-day parameters from the hypervisor. */
++start_info_t *xen_start_info;
++EXPORT_SYMBOL(xen_start_info);
++#endif
++
++/*
++ * Machine setup..
++ */
++
++struct cpuinfo_x86 boot_cpu_data __read_mostly;
++EXPORT_SYMBOL(boot_cpu_data);
++
++unsigned long mmu_cr4_features;
++
++int acpi_disabled;
++EXPORT_SYMBOL(acpi_disabled);
++#ifdef CONFIG_ACPI
++extern int __initdata acpi_ht;
++extern acpi_interrupt_flags acpi_sci_flags;
++int __initdata acpi_force = 0;
++#endif
++
++int acpi_numa __initdata;
++
++/* Boot loader ID as an integer, for the benefit of proc_dointvec */
++int bootloader_type;
++
++unsigned long saved_video_mode;
++
++/*
++ * Early DMI memory
++ */
++int dmi_alloc_index;
++char dmi_alloc_data[DMI_MAX_DATA];
++
++/*
++ * Setup options
++ */
++struct screen_info screen_info;
++EXPORT_SYMBOL(screen_info);
++struct sys_desc_table_struct {
++ unsigned short length;
++ unsigned char table[0];
++};
++
++struct edid_info edid_info;
++struct e820map e820;
++#ifdef CONFIG_XEN
++struct e820map machine_e820;
++#endif
++
++extern int root_mountflags;
++
++char command_line[COMMAND_LINE_SIZE];
++
++struct resource standard_io_resources[] = {
++ { .name = "dma1", .start = 0x00, .end = 0x1f,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "pic1", .start = 0x20, .end = 0x21,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "timer0", .start = 0x40, .end = 0x43,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "timer1", .start = 0x50, .end = 0x53,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "keyboard", .start = 0x60, .end = 0x6f,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "dma page reg", .start = 0x80, .end = 0x8f,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "pic2", .start = 0xa0, .end = 0xa1,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "dma2", .start = 0xc0, .end = 0xdf,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO },
++ { .name = "fpu", .start = 0xf0, .end = 0xff,
++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }
++};
++
++#define STANDARD_IO_RESOURCES \
++ (sizeof standard_io_resources / sizeof standard_io_resources[0])
++
++#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
++
++struct resource data_resource = {
++ .name = "Kernel data",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_RAM,
++};
++struct resource code_resource = {
++ .name = "Kernel code",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_RAM,
++};
++
++#define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM)
++
++static struct resource system_rom_resource = {
++ .name = "System ROM",
++ .start = 0xf0000,
++ .end = 0xfffff,
++ .flags = IORESOURCE_ROM,
++};
++
++static struct resource extension_rom_resource = {
++ .name = "Extension ROM",
++ .start = 0xe0000,
++ .end = 0xeffff,
++ .flags = IORESOURCE_ROM,
++};
++
++static struct resource adapter_rom_resources[] = {
++ { .name = "Adapter ROM", .start = 0xc8000, .end = 0,
++ .flags = IORESOURCE_ROM },
++ { .name = "Adapter ROM", .start = 0, .end = 0,
++ .flags = IORESOURCE_ROM },
++ { .name = "Adapter ROM", .start = 0, .end = 0,
++ .flags = IORESOURCE_ROM },
++ { .name = "Adapter ROM", .start = 0, .end = 0,
++ .flags = IORESOURCE_ROM },
++ { .name = "Adapter ROM", .start = 0, .end = 0,
++ .flags = IORESOURCE_ROM },
++ { .name = "Adapter ROM", .start = 0, .end = 0,
++ .flags = IORESOURCE_ROM }
++};
++
++#define ADAPTER_ROM_RESOURCES \
++ (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
++
++static struct resource video_rom_resource = {
++ .name = "Video ROM",
++ .start = 0xc0000,
++ .end = 0xc7fff,
++ .flags = IORESOURCE_ROM,
++};
++
++static struct resource video_ram_resource = {
++ .name = "Video RAM area",
++ .start = 0xa0000,
++ .end = 0xbffff,
++ .flags = IORESOURCE_RAM,
++};
++
++#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
++
++static int __init romchecksum(unsigned char *rom, unsigned long length)
++{
++ unsigned char *p, sum = 0;
++
++ for (p = rom; p < rom + length; p++)
++ sum += *p;
++ return sum == 0;
++}
++
++static void __init probe_roms(void)
++{
++ unsigned long start, length, upper;
++ unsigned char *rom;
++ int i;
++
++#ifdef CONFIG_XEN
++ /* Nothing to do if not running in dom0. */
++ if (!is_initial_xendomain())
++ return;
++#endif
++
++ /* video rom */
++ upper = adapter_rom_resources[0].start;
++ for (start = video_rom_resource.start; start < upper; start += 2048) {
++ rom = isa_bus_to_virt(start);
++ if (!romsignature(rom))
++ continue;
++
++ video_rom_resource.start = start;
++
++ /* 0 < length <= 0x7f * 512, historically */
++ length = rom[2] * 512;
++
++ /* if checksum okay, trust length byte */
++ if (length && romchecksum(rom, length))
++ video_rom_resource.end = start + length - 1;
++
++ request_resource(&iomem_resource, &video_rom_resource);
++ break;
++ }
++
++ start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
++ if (start < upper)
++ start = upper;
++
++ /* system rom */
++ request_resource(&iomem_resource, &system_rom_resource);
++ upper = system_rom_resource.start;
++
++ /* check for extension rom (ignore length byte!) */
++ rom = isa_bus_to_virt(extension_rom_resource.start);
++ if (romsignature(rom)) {
++ length = extension_rom_resource.end - extension_rom_resource.start + 1;
++ if (romchecksum(rom, length)) {
++ request_resource(&iomem_resource, &extension_rom_resource);
++ upper = extension_rom_resource.start;
++ }
++ }
++
++ /* check for adapter roms on 2k boundaries */
++ for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
++ rom = isa_bus_to_virt(start);
++ if (!romsignature(rom))
++ continue;
++
++ /* 0 < length <= 0x7f * 512, historically */
++ length = rom[2] * 512;
++
++ /* but accept any length that fits if checksum okay */
++ if (!length || start + length > upper || !romchecksum(rom, length))
++ continue;
++
++ adapter_rom_resources[i].start = start;
++ adapter_rom_resources[i].end = start + length - 1;
++ request_resource(&iomem_resource, &adapter_rom_resources[i]);
++
++ start = adapter_rom_resources[i++].end & ~2047UL;
++ }
++}
++
++/* Check for full argument with no trailing characters */
++static int fullarg(char *p, char *arg)
++{
++ int l = strlen(arg);
++ return !memcmp(p, arg, l) && (p[l] == 0 || isspace(p[l]));
++}
++
++static __init void parse_cmdline_early (char ** cmdline_p)
++{
++ char c = ' ', *to = command_line, *from = COMMAND_LINE;
++ int len = 0;
++ int userdef = 0;
++
++ for (;;) {
++ if (c != ' ')
++ goto next_char;
++
++#ifdef CONFIG_SMP
++ /*
++ * If the BIOS enumerates physical processors before logical,
++ * maxcpus=N at enumeration-time can be used to disable HT.
++ */
++ else if (!memcmp(from, "maxcpus=", 8)) {
++ extern unsigned int maxcpus;
++
++ maxcpus = simple_strtoul(from + 8, NULL, 0);
++ }
++#endif
++#ifdef CONFIG_ACPI
++ /* "acpi=off" disables both ACPI table parsing and interpreter init */
++ if (fullarg(from,"acpi=off"))
++ disable_acpi();
++
++ if (fullarg(from, "acpi=force")) {
++ /* add later when we do DMI horrors: */
++ acpi_force = 1;
++ acpi_disabled = 0;
++ }
++
++ /* acpi=ht just means: do ACPI MADT parsing
++ at bootup, but don't enable the full ACPI interpreter */
++ if (fullarg(from, "acpi=ht")) {
++ if (!acpi_force)
++ disable_acpi();
++ acpi_ht = 1;
++ }
++ else if (fullarg(from, "pci=noacpi"))
++ acpi_disable_pci();
++ else if (fullarg(from, "acpi=noirq"))
++ acpi_noirq_set();
++
++ else if (fullarg(from, "acpi_sci=edge"))
++ acpi_sci_flags.trigger = 1;
++ else if (fullarg(from, "acpi_sci=level"))
++ acpi_sci_flags.trigger = 3;
++ else if (fullarg(from, "acpi_sci=high"))
++ acpi_sci_flags.polarity = 1;
++ else if (fullarg(from, "acpi_sci=low"))
++ acpi_sci_flags.polarity = 3;
++
++ /* acpi=strict disables out-of-spec workarounds */
++ else if (fullarg(from, "acpi=strict")) {
++ acpi_strict = 1;
++ }
++#ifdef CONFIG_X86_IO_APIC
++ else if (fullarg(from, "acpi_skip_timer_override"))
++ acpi_skip_timer_override = 1;
++#endif
++#endif
++
++#ifndef CONFIG_XEN
++ if (fullarg(from, "disable_timer_pin_1"))
++ disable_timer_pin_1 = 1;
++ if (fullarg(from, "enable_timer_pin_1"))
++ disable_timer_pin_1 = -1;
++
++ if (fullarg(from, "nolapic") || fullarg(from, "disableapic")) {
++ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
++ disable_apic = 1;
++ }
++
++ if (fullarg(from, "noapic"))
++ skip_ioapic_setup = 1;
++
++ if (fullarg(from,"apic")) {
++ skip_ioapic_setup = 0;
++ ioapic_force = 1;
++ }
++#endif
++
++ if (!memcmp(from, "mem=", 4))
++ parse_memopt(from+4, &from);
++
++ if (!memcmp(from, "memmap=", 7)) {
++ /* exactmap option is for used defined memory */
++ 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.
++ */
++ saved_max_pfn = e820_end_of_ram();
++#endif
++ from += 8+7;
++ end_pfn_map = 0;
++ e820.nr_map = 0;
++ userdef = 1;
++ }
++ else {
++ parse_memmapopt(from+7, &from);
++ userdef = 1;
++ }
++ }
++
++#ifdef CONFIG_NUMA
++ if (!memcmp(from, "numa=", 5))
++ numa_setup(from+5);
++#endif
++
++ if (!memcmp(from,"iommu=",6)) {
++ iommu_setup(from+6);
++ }
++
++ if (fullarg(from,"oops=panic"))
++ panic_on_oops = 1;
++
++ if (!memcmp(from, "noexec=", 7))
++ nonx_setup(from + 7);
++
++#ifdef CONFIG_KEXEC
++ /* crashkernel=size at 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_PROC_VMCORE
++ /* elfcorehdr= specifies the location of elf core header
++ * stored by the crashed kernel. This option will be passed
++ * by kexec loader to the capture kernel.
++ */
++ else if(!memcmp(from, "elfcorehdr=", 11))
++ elfcorehdr_addr = memparse(from+11, &from);
++#endif
++
++#if defined(CONFIG_HOTPLUG_CPU) && !defined(CONFIG_XEN)
++ else if (!memcmp(from, "additional_cpus=", 16))
++ setup_additional_cpus(from+16);
++#endif
++
++ next_char:
++ c = *(from++);
++ if (!c)
++ break;
++ if (COMMAND_LINE_SIZE <= ++len)
++ break;
++ *(to++) = c;
++ }
++ if (userdef) {
++ printk(KERN_INFO "user-defined physical RAM map:\n");
++ e820_print_map("user");
++ }
++ *to = '\0';
++ *cmdline_p = command_line;
++}
++
++#ifndef CONFIG_NUMA
++static void __init
++contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
++{
++ unsigned long bootmap_size, bootmap;
++
++ bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
++ bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
++ if (bootmap == -1L)
++ panic("Cannot find bootmem map of size %ld\n",bootmap_size);
++ bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
++#ifdef CONFIG_XEN
++ e820_bootmem_free(NODE_DATA(0), 0, xen_start_info->nr_pages<<PAGE_SHIFT);
++#else
++ e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT);
++#endif
++ reserve_bootmem(bootmap, bootmap_size);
++}
++#endif
++
++#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
++struct edd edd;
++#ifdef CONFIG_EDD_MODULE
++EXPORT_SYMBOL(edd);
++#endif
++/**
++ * copy_edd() - Copy the BIOS EDD information
++ * from boot_params into a safe place.
++ *
++ */
++static inline void copy_edd(void)
++{
++ memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature));
++ memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info));
++ edd.mbr_signature_nr = EDD_MBR_SIG_NR;
++ edd.edd_info_nr = EDD_NR;
++}
++#else
++static inline void copy_edd(void)
++{
++}
++#endif
++
++#ifndef CONFIG_XEN
++#define EBDA_ADDR_POINTER 0x40E
++
++unsigned __initdata ebda_addr;
++unsigned __initdata ebda_size;
++
++static void discover_ebda(void)
++{
++ /*
++ * there is a real-mode segmented pointer pointing to the
++ * 4K EBDA area at 0x40E
++ */
++ ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER;
++ ebda_addr <<= 4;
++
++ ebda_size = *(unsigned short *)(unsigned long)ebda_addr;
++
++ /* Round EBDA up to pages */
++ if (ebda_size == 0)
++ ebda_size = 1;
++ ebda_size <<= 10;
++ ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
++ if (ebda_size > 64*1024)
++ ebda_size = 64*1024;
++}
++#endif
++
++void __init setup_arch(char **cmdline_p)
++{
++ struct xen_memory_map memmap;
++
++#ifdef CONFIG_XEN
++ /* Register a call for panic conditions. */
++ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
++
++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++ screen_info = SCREEN_INFO;
++
++ if (is_initial_xendomain()) {
++ /* This is drawn from a dump from vgacon:startup in
++ * standard Linux. */
++ screen_info.orig_video_mode = 3;
++ screen_info.orig_video_isVGA = 1;
++ screen_info.orig_video_lines = 25;
++ screen_info.orig_video_cols = 80;
++ screen_info.orig_video_ega_bx = 3;
++ screen_info.orig_video_points = 16;
++ screen_info.orig_y = screen_info.orig_video_lines - 1;
++ if (xen_start_info->console.dom0.info_size >=
++ sizeof(struct dom0_vga_console_info)) {
++ const struct dom0_vga_console_info *info =
++ (struct dom0_vga_console_info *)(
++ (char *)xen_start_info +
++ xen_start_info->console.dom0.info_off);
++ dom0_init_screen_info(info);
++ }
++ xen_start_info->console.domU.mfn = 0;
++ xen_start_info->console.domU.evtchn = 0;
++ } else
++ screen_info.orig_video_isVGA = 0;
++
++ edid_info = EDID_INFO;
++ saved_video_mode = SAVED_VIDEO_MODE;
++ bootloader_type = LOADER_TYPE;
++
++#ifdef CONFIG_BLK_DEV_RAM
++ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
++ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
++ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
++
++
++#endif
++
++ setup_xen_features();
++
++ HYPERVISOR_vm_assist(VMASST_CMD_enable,
++ VMASST_TYPE_writable_pagetables);
++
++ ARCH_SETUP
++#else
++ ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
++ screen_info = SCREEN_INFO;
++ edid_info = EDID_INFO;
++ saved_video_mode = SAVED_VIDEO_MODE;
++ bootloader_type = LOADER_TYPE;
++
++#ifdef CONFIG_BLK_DEV_RAM
++ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
++ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
++ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
++#endif
++#endif /* !CONFIG_XEN */
++ setup_memory_region();
++ copy_edd();
++
++ if (!MOUNT_ROOT_RDONLY)
++ root_mountflags &= ~MS_RDONLY;
++ init_mm.start_code = (unsigned long) &_text;
++ init_mm.end_code = (unsigned long) &_etext;
++ init_mm.end_data = (unsigned long) &_edata;
++ init_mm.brk = (unsigned long) &_end;
++
++ code_resource.start = virt_to_phys(&_text);
++ code_resource.end = virt_to_phys(&_etext)-1;
++ data_resource.start = virt_to_phys(&_etext);
++ data_resource.end = virt_to_phys(&_edata)-1;
++
++ parse_cmdline_early(cmdline_p);
++
++ early_identify_cpu(&boot_cpu_data);
++
++ /*
++ * partially used pages are not usable - thus
++ * we are rounding upwards:
++ */
++ end_pfn = e820_end_of_ram();
++ num_physpages = end_pfn; /* for pfn_valid */
++
++ check_efer();
++
++#ifndef CONFIG_XEN
++ discover_ebda();
++#endif
++
++ init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
++
++#ifdef CONFIG_ACPI_NUMA
++ /*
++ * Parse SRAT to discover nodes.
++ */
++ acpi_numa_init();
++#endif
++
++#ifdef CONFIG_NUMA
++ numa_initmem_init(0, end_pfn);
++#else
++ contig_initmem_init(0, end_pfn);
++#endif
++
++ /* Reserve direct mapping */
++ reserve_bootmem_generic(table_start << PAGE_SHIFT,
++ (table_end - table_start) << PAGE_SHIFT);
++
++ /* reserve kernel */
++ reserve_bootmem_generic(__pa_symbol(&_text),
++ __pa_symbol(&_end) - __pa_symbol(&_text));
++
++#ifdef CONFIG_XEN
++ /* reserve physmap, start info and initial page tables */
++ reserve_bootmem(__pa_symbol(&_end), (table_start<<PAGE_SHIFT)-__pa_symbol(&_end));
++#else
++ /*
++ * reserve physical page 0 - it's a special BIOS page on many boxes,
++ * enabling clean reboots, SMP operation, laptop functions.
++ */
++ reserve_bootmem_generic(0, PAGE_SIZE);
++
++ /* reserve ebda region */
++ if (ebda_addr)
++ reserve_bootmem_generic(ebda_addr, ebda_size);
++#endif
++
++#ifdef CONFIG_SMP
++ /*
++ * But first pinch a few for the stack/trampoline stuff
++ * FIXME: Don't need the extra page at 4K, but need to fix
++ * trampoline before removing it. (see the GDT stuff)
++ */
++ reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE);
++
++ /* Reserve SMP trampoline */
++ reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, PAGE_SIZE);
++#endif
++
++#ifdef CONFIG_ACPI_SLEEP
++ /*
++ * Reserve low memory region for sleep support.
++ */
++ acpi_reserve_bootmem();
++#endif
++#ifdef CONFIG_XEN
++#ifdef CONFIG_BLK_DEV_INITRD
++ if (xen_start_info->mod_start) {
++ if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
++ /*reserve_bootmem_generic(INITRD_START, INITRD_SIZE);*/
++ initrd_start = INITRD_START + PAGE_OFFSET;
++ initrd_end = initrd_start+INITRD_SIZE;
++ initrd_below_start_ok = 1;
++ } else {
++ printk(KERN_ERR "initrd extends beyond end of memory "
++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
++ (unsigned long)(INITRD_START + INITRD_SIZE),
++ (unsigned long)(end_pfn << PAGE_SHIFT));
++ initrd_start = 0;
++ }
++ }
++#endif
++#else /* CONFIG_XEN */
++#ifdef CONFIG_BLK_DEV_INITRD
++ if (LOADER_TYPE && INITRD_START) {
++ if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
++ reserve_bootmem_generic(INITRD_START, INITRD_SIZE);
++ initrd_start =
++ INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
++ initrd_end = initrd_start+INITRD_SIZE;
++ }
++ else {
++ printk(KERN_ERR "initrd extends beyond end of memory "
++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
++ (unsigned long)(INITRD_START + INITRD_SIZE),
++ (unsigned long)(end_pfn << PAGE_SHIFT));
++ initrd_start = 0;
++ }
++ }
++#endif
++#endif /* !CONFIG_XEN */
++#ifdef CONFIG_KEXEC
++ if (crashk_res.start != crashk_res.end) {
++ reserve_bootmem_generic(crashk_res.start,
++ crashk_res.end - crashk_res.start + 1);
++ }
++#endif
++
++ paging_init();
++#ifdef CONFIG_X86_LOCAL_APIC
++ /*
++ * Find and reserve possible boot-time SMP configuration:
++ */
++ find_smp_config();
++#endif
++#ifdef CONFIG_XEN
++ {
++ int i, j, k, fpp;
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ /* Make sure we have a large enough P->M table. */
++ phys_to_machine_mapping = alloc_bootmem_pages(
++ end_pfn * sizeof(unsigned long));
++ memset(phys_to_machine_mapping, ~0,
++ end_pfn * sizeof(unsigned long));
++ memcpy(phys_to_machine_mapping,
++ (unsigned long *)xen_start_info->mfn_list,
++ xen_start_info->nr_pages * sizeof(unsigned long));
++ free_bootmem(
++ __pa(xen_start_info->mfn_list),
++ PFN_PHYS(PFN_UP(xen_start_info->nr_pages *
++ sizeof(unsigned long))));
++
++ /*
++ * Initialise the list of the frames that specify the
++ * list of frames that make up the p2m table. Used by
++ * save/restore.
++ */
++ pfn_to_mfn_frame_list_list = alloc_bootmem_pages(PAGE_SIZE);
++ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
++ virt_to_mfn(pfn_to_mfn_frame_list_list);
++
++ fpp = PAGE_SIZE/sizeof(unsigned long);
++ for (i=0, j=0, k=-1; i< end_pfn; i+=fpp, j++) {
++ if ((j % fpp) == 0) {
++ k++;
++ BUG_ON(k>=fpp);
++ pfn_to_mfn_frame_list[k] =
++ alloc_bootmem_pages(PAGE_SIZE);
++ pfn_to_mfn_frame_list_list[k] =
++ virt_to_mfn(pfn_to_mfn_frame_list[k]);
++ j=0;
++ }
++ pfn_to_mfn_frame_list[k][j] =
++ virt_to_mfn(&phys_to_machine_mapping[i]);
++ }
++ HYPERVISOR_shared_info->arch.max_pfn = end_pfn;
++ }
++
++ }
++
++ if (is_initial_xendomain())
++ dmi_scan_machine();
++
++ if (!is_initial_xendomain()) {
++ acpi_disabled = 1;
++#ifdef CONFIG_ACPI
++ acpi_ht = 0;
++#endif
++ }
++#endif
++
++#ifndef CONFIG_XEN
++ check_ioapic();
++#endif
++
++ zap_low_mappings(0);
++
++ /*
++ * set this early, so we dont allocate cpu0
++ * if MADT list doesnt list BSP first
++ * mpparse.c/MP_processor_info() allocates logical cpu numbers.
++ */
++ cpu_set(0, cpu_present_map);
++#ifdef CONFIG_ACPI
++ /*
++ * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
++ * Call this early for SRAT node setup.
++ */
++ acpi_boot_table_init();
++
++ /*
++ * Read APIC and some other early information from ACPI tables.
++ */
++ acpi_boot_init();
++#endif
++
++ init_cpu_to_node();
++
++#ifdef CONFIG_X86_LOCAL_APIC
++ /*
++ * get boot-time SMP configuration:
++ */
++ if (smp_found_config)
++ get_smp_config();
++#ifndef CONFIG_XEN
++ init_apic_mappings();
++#endif
++#endif
++#if defined(CONFIG_XEN) && defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
++ prefill_possible_map();
++#endif
++
++ /*
++ * Request address space for all standard RAM and ROM resources
++ * and also for regions reported as reserved by the e820.
++ */
++ probe_roms();
++#ifdef CONFIG_XEN
++ if (is_initial_xendomain()) {
++ memmap.nr_entries = E820MAX;
++ set_xen_guest_handle(memmap.buffer, machine_e820.map);
++
++ if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
++ BUG();
++ machine_e820.nr_map = memmap.nr_entries;
++
++ e820_reserve_resources(machine_e820.map, machine_e820.nr_map);
++ }
++#else
++ e820_reserve_resources(e820.map, e820.nr_map);
++#endif
++
++ request_resource(&iomem_resource, &video_ram_resource);
++
++ {
++ unsigned i;
++ /* request I/O space for devices used on all i[345]86 PCs */
++ for (i = 0; i < STANDARD_IO_RESOURCES; i++)
++ request_resource(&ioport_resource, &standard_io_resources[i]);
++ }
++
++#ifdef CONFIG_XEN
++ if (is_initial_xendomain())
++ e820_setup_gap(machine_e820.map, machine_e820.nr_map);
++#else
++ e820_setup_gap(e820.map, e820.nr_map);
++#endif
++
++#ifdef CONFIG_XEN
++ {
++ struct physdev_set_iopl set_iopl;
++
++ set_iopl.iopl = 1;
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++
++ if (is_initial_xendomain()) {
++#ifdef CONFIG_VT
++#if defined(CONFIG_VGA_CONSOLE)
++ conswitchp = &vga_con;
++#elif defined(CONFIG_DUMMY_CONSOLE)
++ conswitchp = &dummy_con;
++#endif
++#endif
++ } else {
++ extern int console_use_vt;
++ console_use_vt = 0;
++ }
++ }
++#else /* CONFIG_XEN */
++
++#ifdef CONFIG_VT
++#if defined(CONFIG_VGA_CONSOLE)
++ conswitchp = &vga_con;
++#elif defined(CONFIG_DUMMY_CONSOLE)
++ conswitchp = &dummy_con;
++#endif
++#endif
++
++#endif /* !CONFIG_XEN */
++}
++
++#ifdef CONFIG_XEN
++static int
++xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
++{
++ HYPERVISOR_shutdown(SHUTDOWN_crash);
++ /* we're never actually going to get here... */
++ return NOTIFY_DONE;
++}
++#endif /* !CONFIG_XEN */
++
++
++static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
++{
++ unsigned int *v;
++
++ if (c->extended_cpuid_level < 0x80000004)
++ return 0;
++
++ v = (unsigned int *) c->x86_model_id;
++ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
++ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
++ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
++ c->x86_model_id[48] = 0;
++ return 1;
++}
++
++
++static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
++{
++ unsigned int n, dummy, eax, ebx, ecx, edx;
++
++ n = c->extended_cpuid_level;
++
++ if (n >= 0x80000005) {
++ cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
++ printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
++ edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
++ c->x86_cache_size=(ecx>>24)+(edx>>24);
++ /* On K8 L1 TLB is inclusive, so don't count it */
++ c->x86_tlbsize = 0;
++ }
++
++ if (n >= 0x80000006) {
++ cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
++ ecx = cpuid_ecx(0x80000006);
++ c->x86_cache_size = ecx >> 16;
++ c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
++
++ printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
++ c->x86_cache_size, ecx & 0xFF);
++ }
++
++ if (n >= 0x80000007)
++ cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power);
++ if (n >= 0x80000008) {
++ cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
++ c->x86_virt_bits = (eax >> 8) & 0xff;
++ c->x86_phys_bits = eax & 0xff;
++ }
++}
++
++#ifdef CONFIG_NUMA
++static int nearby_node(int apicid)
++{
++ int i;
++ for (i = apicid - 1; i >= 0; i--) {
++ int node = apicid_to_node[i];
++ if (node != NUMA_NO_NODE && node_online(node))
++ return node;
++ }
++ for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
++ int node = apicid_to_node[i];
++ if (node != NUMA_NO_NODE && node_online(node))
++ return node;
++ }
++ return first_node(node_online_map); /* Shouldn't happen */
++}
++#endif
++
++/*
++ * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
++ * Assumes number of cores is a power of two.
++ */
++static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
++{
++#ifdef CONFIG_SMP
++ unsigned bits;
++#ifdef CONFIG_NUMA
++ int cpu = smp_processor_id();
++ int node = 0;
++ unsigned apicid = hard_smp_processor_id();
++#endif
++ unsigned ecx = cpuid_ecx(0x80000008);
++
++ c->x86_max_cores = (ecx & 0xff) + 1;
++
++ /* CPU telling us the core id bits shift? */
++ bits = (ecx >> 12) & 0xF;
++
++ /* Otherwise recompute */
++ if (bits == 0) {
++ while ((1 << bits) < c->x86_max_cores)
++ bits++;
++ }
++
++ /* Low order bits define the core id (index of core in socket) */
++ c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
++ /* Convert the APIC ID into the socket ID */
++ c->phys_proc_id = phys_pkg_id(bits);
++
++#ifdef CONFIG_NUMA
++ node = c->phys_proc_id;
++ if (apicid_to_node[apicid] != NUMA_NO_NODE)
++ node = apicid_to_node[apicid];
++ if (!node_online(node)) {
++ /* Two possibilities here:
++ - The CPU is missing memory and no node was created.
++ In that case try picking one from a nearby CPU
++ - The APIC IDs differ from the HyperTransport node IDs
++ which the K8 northbridge parsing fills in.
++ Assume they are all increased by a constant offset,
++ but in the same order as the HT nodeids.
++ If that doesn't result in a usable node fall back to the
++ path for the previous case. */
++ int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits);
++ if (ht_nodeid >= 0 &&
++ apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
++ node = apicid_to_node[ht_nodeid];
++ /* Pick a nearby node */
++ if (!node_online(node))
++ node = nearby_node(apicid);
++ }
++ numa_set_node(cpu, node);
++
++ printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
++#endif
++#endif
++}
++
++static void __init init_amd(struct cpuinfo_x86 *c)
++{
++ unsigned level;
++
++#ifdef CONFIG_SMP
++ unsigned long value;
++
++ /*
++ * Disable TLB flush filter by setting HWCR.FFDIS on K8
++ * bit 6 of msr C001_0015
++ *
++ * Errata 63 for SH-B3 steppings
++ * Errata 122 for all steppings (F+ have it disabled by default)
++ */
++ if (c->x86 == 15) {
++ rdmsrl(MSR_K8_HWCR, value);
++ value |= 1 << 6;
++ wrmsrl(MSR_K8_HWCR, value);
++ }
++#endif
++
++ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
++ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
++ clear_bit(0*32+31, &c->x86_capability);
++
++ /* On C+ stepping K8 rep microcode works well for copy/memset */
++ level = cpuid_eax(1);
++ if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
++ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
++
++ /* Enable workaround for FXSAVE leak */
++ if (c->x86 >= 6)
++ set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
++
++ level = get_model_name(c);
++ if (!level) {
++ switch (c->x86) {
++ case 15:
++ /* Should distinguish Models here, but this is only
++ a fallback anyways. */
++ strcpy(c->x86_model_id, "Hammer");
++ break;
++ }
++ }
++ display_cacheinfo(c);
++
++ /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
++ if (c->x86_power & (1<<8))
++ set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
++
++ /* Multi core CPU? */
++ if (c->extended_cpuid_level >= 0x80000008)
++ amd_detect_cmp(c);
++
++ /* Fix cpuid4 emulation for more */
++ num_cache_leaves = 3;
++}
++
++static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
++{
++#ifdef CONFIG_SMP
++ u32 eax, ebx, ecx, edx;
++ int index_msb, core_bits;
++ int cpu = smp_processor_id();
++
++ cpuid(1, &eax, &ebx, &ecx, &edx);
++
++
++ if (!cpu_has(c, X86_FEATURE_HT))
++ return;
++ if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
++ goto out;
++
++ smp_num_siblings = (ebx & 0xff0000) >> 16;
++
++ if (smp_num_siblings == 1) {
++ printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
++ } else if (smp_num_siblings > 1 ) {
++
++ if (smp_num_siblings > NR_CPUS) {
++ printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
++ smp_num_siblings = 1;
++ return;
++ }
++
++ index_msb = get_count_order(smp_num_siblings);
++ c->phys_proc_id = phys_pkg_id(index_msb);
++
++ smp_num_siblings = smp_num_siblings / c->x86_max_cores;
++
++ index_msb = get_count_order(smp_num_siblings) ;
++
++ core_bits = get_count_order(c->x86_max_cores);
++
++ c->cpu_core_id = phys_pkg_id(index_msb) &
++ ((1 << core_bits) - 1);
++ }
++out:
++ if ((c->x86_max_cores * smp_num_siblings) > 1) {
++ printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
++ printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id);
++ }
++#endif
++}
++
++/*
++ * find out the number of processor cores on the die
++ */
++static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
++{
++ unsigned int eax, t;
++
++ if (c->cpuid_level < 4)
++ return 1;
++
++ cpuid_count(4, 0, &eax, &t, &t, &t);
++
++ if (eax & 0x1f)
++ return ((eax >> 26) + 1);
++ else
++ return 1;
++}
++
++static void srat_detect_node(void)
++{
++#ifdef CONFIG_NUMA
++ unsigned node;
++ int cpu = smp_processor_id();
++ int apicid = hard_smp_processor_id();
++
++ /* Don't do the funky fallback heuristics the AMD version employs
++ for now. */
++ node = apicid_to_node[apicid];
++ if (node == NUMA_NO_NODE)
++ node = first_node(node_online_map);
++ numa_set_node(cpu, node);
++
++ if (acpi_numa > 0)
++ printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
++#endif
++}
++
++static void __cpuinit init_intel(struct cpuinfo_x86 *c)
++{
++ /* Cache sizes */
++ unsigned n;
++
++ init_intel_cacheinfo(c);
++ if (c->cpuid_level > 9 ) {
++ unsigned eax = cpuid_eax(10);
++ /* Check for version and the number of counters */
++ if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
++ set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
++ }
++
++ n = c->extended_cpuid_level;
++ if (n >= 0x80000008) {
++ unsigned eax = cpuid_eax(0x80000008);
++ c->x86_virt_bits = (eax >> 8) & 0xff;
++ c->x86_phys_bits = eax & 0xff;
++ /* CPUID workaround for Intel 0F34 CPU */
++ if (c->x86_vendor == X86_VENDOR_INTEL &&
++ c->x86 == 0xF && c->x86_model == 0x3 &&
++ c->x86_mask == 0x4)
++ c->x86_phys_bits = 36;
++ }
++
++ if (c->x86 == 15)
++ c->x86_cache_alignment = c->x86_clflush_size * 2;
++ if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
++ (c->x86 == 0x6 && c->x86_model >= 0x0e))
++ set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
++ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
++ c->x86_max_cores = intel_num_cpu_cores(c);
++
++ srat_detect_node();
++}
++
++static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
++{
++ char *v = c->x86_vendor_id;
++
++ if (!strcmp(v, "AuthenticAMD"))
++ c->x86_vendor = X86_VENDOR_AMD;
++ else if (!strcmp(v, "GenuineIntel"))
++ c->x86_vendor = X86_VENDOR_INTEL;
++ else
++ c->x86_vendor = X86_VENDOR_UNKNOWN;
++}
++
++struct cpu_model_info {
++ int vendor;
++ int family;
++ char *model_names[16];
++};
++
++/* 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 __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
++{
++ u32 tfms;
++
++ c->loops_per_jiffy = loops_per_jiffy;
++ c->x86_cache_size = -1;
++ c->x86_vendor = X86_VENDOR_UNKNOWN;
++ c->x86_model = c->x86_mask = 0; /* So far unknown... */
++ c->x86_vendor_id[0] = '\0'; /* Unset */
++ c->x86_model_id[0] = '\0'; /* Unset */
++ c->x86_clflush_size = 64;
++ c->x86_cache_alignment = c->x86_clflush_size;
++ c->x86_max_cores = 1;
++ c->extended_cpuid_level = 0;
++ memset(&c->x86_capability, 0, sizeof c->x86_capability);
++
++ /* Get vendor name */
++ cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
++ (unsigned int *)&c->x86_vendor_id[0],
++ (unsigned int *)&c->x86_vendor_id[8],
++ (unsigned int *)&c->x86_vendor_id[4]);
++
++ get_cpu_vendor(c);
++
++ /* Initialize the standard set of capabilities */
++ /* Note that the vendor-specific code below might override */
++
++ /* Intel-defined flags: level 0x00000001 */
++ if (c->cpuid_level >= 0x00000001) {
++ __u32 misc;
++ cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
++ &c->x86_capability[0]);
++ c->x86 = (tfms >> 8) & 0xf;
++ c->x86_model = (tfms >> 4) & 0xf;
++ c->x86_mask = tfms & 0xf;
++ if (c->x86 == 0xf)
++ c->x86 += (tfms >> 20) & 0xff;
++ if (c->x86 >= 0x6)
++ c->x86_model += ((tfms >> 16) & 0xF) << 4;
++ if (c->x86_capability[0] & (1<<19))
++ c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
++ } else {
++ /* Have CPUID level 0 only - unheard of */
++ c->x86 = 4;
++ }
++
++#ifdef CONFIG_SMP
++ c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
++#endif
++}
++
++/*
++ * This does the hard work of actually picking apart the CPU stuff...
++ */
++void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
++{
++ int i;
++ u32 xlvl;
++
++ early_identify_cpu(c);
++
++ /* AMD-defined flags: level 0x80000001 */
++ xlvl = cpuid_eax(0x80000000);
++ c->extended_cpuid_level = xlvl;
++ if ((xlvl & 0xffff0000) == 0x80000000) {
++ if (xlvl >= 0x80000001) {
++ c->x86_capability[1] = cpuid_edx(0x80000001);
++ c->x86_capability[6] = cpuid_ecx(0x80000001);
++ }
++ if (xlvl >= 0x80000004)
++ get_model_name(c); /* Default name */
++ }
++
++ /* Transmeta-defined flags: level 0x80860001 */
++ xlvl = cpuid_eax(0x80860000);
++ if ((xlvl & 0xffff0000) == 0x80860000) {
++ /* Don't set x86_cpuid_level here for now to not confuse. */
++ if (xlvl >= 0x80860001)
++ c->x86_capability[2] = cpuid_edx(0x80860001);
++ }
++
++ c->apicid = phys_pkg_id(0);
++
++ /*
++ * Vendor-specific initialization. In this section we
++ * canonicalize the feature flags, meaning if there are
++ * features a certain CPU supports which CPUID doesn't
++ * tell us, CPUID claiming incorrect flags, or other bugs,
++ * we handle them here.
++ *
++ * At the end of this section, c->x86_capability better
++ * indicate the features this CPU genuinely supports!
++ */
++ switch (c->x86_vendor) {
++ case X86_VENDOR_AMD:
++ init_amd(c);
++ break;
++
++ case X86_VENDOR_INTEL:
++ init_intel(c);
++ break;
++
++ case X86_VENDOR_UNKNOWN:
++ default:
++ display_cacheinfo(c);
++ break;
++ }
++
++ select_idle_routine(c);
++ detect_ht(c);
++
++ /*
++ * On SMP, boot_cpu_data holds the common feature set between
++ * all CPUs; so make sure that we indicate which features are
++ * common between the CPUs. The first time this routine gets
++ * executed, c == &boot_cpu_data.
++ */
++ if (c != &boot_cpu_data) {
++ /* AND the already accumulated flags with these */
++ for (i = 0 ; i < NCAPINTS ; i++)
++ boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
++ }
++
++#ifdef CONFIG_X86_MCE
++ mcheck_init(c);
++#endif
++ if (c == &boot_cpu_data)
++ mtrr_bp_init();
++ else
++ mtrr_ap_init();
++#ifdef CONFIG_NUMA
++ numa_add_cpu(smp_processor_id());
++#endif
++}
++
++
++void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
++{
++ if (c->x86_model_id[0])
++ printk("%s", c->x86_model_id);
++
++ if (c->x86_mask || c->cpuid_level >= 0)
++ printk(" stepping %02x\n", c->x86_mask);
++ else
++ printk("\n");
++}
++
++/*
++ * Get CPU information for use by the procfs.
++ */
++
++static int show_cpuinfo(struct seq_file *m, void *v)
++{
++ struct cpuinfo_x86 *c = v;
++
++ /*
++ * These flag bits must match the definitions in <asm/cpufeature.h>.
++ * NULL means this bit is undefined or reserved; either way it doesn't
++ * have meaning as far as Linux is concerned. Note that it's important
++ * to realize there is a difference between this table and CPUID -- if
++ * applications want to get the raw CPUID data, they should access
++ * /dev/cpu/<cpu_nr>/cpuid instead.
++ */
++ static char *x86_cap_flags[] = {
++ /* Intel-defined */
++ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
++ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
++ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
++ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
++
++ /* AMD-defined */
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
++ NULL, "fxsr_opt", NULL, "rdtscp", NULL, "lm", "3dnowext", "3dnow",
++
++ /* Transmeta-defined */
++ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++
++ /* Other (Linux-defined) */
++ "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
++ "constant_tsc", NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ "up", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++
++ /* Intel-defined (#2) */
++ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
++ "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++
++ /* VIA/Cyrix/Centaur-defined */
++ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++
++ /* AMD-defined (#2) */
++ "lahf_lm", "cmp_legacy", "svm", NULL, "cr8_legacy", NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
++ };
++ static char *x86_power_flags[] = {
++ "ts", /* temperature sensor */
++ "fid", /* frequency id control */
++ "vid", /* voltage id control */
++ "ttp", /* thermal trip */
++ "tm",
++ "stc",
++ NULL,
++ /* nothing */ /* constant_tsc - moved to flags */
++ };
++
++
++#ifdef CONFIG_SMP
++ if (!cpu_online(c-cpu_data))
++ return 0;
++#endif
++
++ seq_printf(m,"processor\t: %u\n"
++ "vendor_id\t: %s\n"
++ "cpu family\t: %d\n"
++ "model\t\t: %d\n"
++ "model name\t: %s\n",
++ (unsigned)(c-cpu_data),
++ c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
++ c->x86,
++ (int)c->x86_model,
++ c->x86_model_id[0] ? c->x86_model_id : "unknown");
++
++ if (c->x86_mask || c->cpuid_level >= 0)
++ seq_printf(m, "stepping\t: %d\n", c->x86_mask);
++ else
++ seq_printf(m, "stepping\t: unknown\n");
++
++ if (cpu_has(c,X86_FEATURE_TSC)) {
++ unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data));
++ if (!freq)
++ freq = cpu_khz;
++ seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
++ freq / 1000, (freq % 1000));
++ }
++
++ /* Cache size */
++ if (c->x86_cache_size >= 0)
++ seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
++
++#ifdef CONFIG_SMP
++ if (smp_num_siblings * c->x86_max_cores > 1) {
++ int cpu = c - cpu_data;
++ seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
++ seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu]));
++ seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
++ seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
++ }
++#endif
++
++ seq_printf(m,
++ "fpu\t\t: yes\n"
++ "fpu_exception\t: yes\n"
++ "cpuid level\t: %d\n"
++ "wp\t\t: yes\n"
++ "flags\t\t:",
++ c->cpuid_level);
++
++ {
++ int i;
++ for ( i = 0 ; i < 32*NCAPINTS ; i++ )
++ if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
++ seq_printf(m, " %s", x86_cap_flags[i]);
++ }
++
++ seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
++ c->loops_per_jiffy/(500000/HZ),
++ (c->loops_per_jiffy/(5000/HZ)) % 100);
++
++ if (c->x86_tlbsize > 0)
++ seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
++ seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
++ seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
++
++ seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
++ c->x86_phys_bits, c->x86_virt_bits);
++
++ seq_printf(m, "power management:");
++ {
++ unsigned i;
++ for (i = 0; i < 32; i++)
++ if (c->x86_power & (1 << i)) {
++ if (i < ARRAY_SIZE(x86_power_flags) &&
++ x86_power_flags[i])
++ seq_printf(m, "%s%s",
++ x86_power_flags[i][0]?" ":"",
++ x86_power_flags[i]);
++ else
++ seq_printf(m, " [%d]", i);
++ }
++ }
++
++ seq_printf(m, "\n\n");
++
++ return 0;
++}
++
++static void *c_start(struct seq_file *m, loff_t *pos)
++{
++ return *pos < NR_CPUS ? cpu_data + *pos : NULL;
++}
++
++static void *c_next(struct seq_file *m, void *v, loff_t *pos)
++{
++ ++*pos;
++ return c_start(m, pos);
++}
++
++static void c_stop(struct seq_file *m, void *v)
++{
++}
++
++struct seq_operations cpuinfo_op = {
++ .start =c_start,
++ .next = c_next,
++ .stop = c_stop,
++ .show = show_cpuinfo,
++};
++
++#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE)
++#include <linux/platform_device.h>
++static __init int add_pcspkr(void)
++{
++ struct platform_device *pd;
++ int ret;
++
++ pd = platform_device_alloc("pcspkr", -1);
++ if (!pd)
++ return -ENOMEM;
++
++ ret = platform_device_add(pd);
++ if (ret)
++ platform_device_put(pd);
++
++ return ret;
++}
++device_initcall(add_pcspkr);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/smp-xen.c linux-2.6.18-xen/arch/x86_64/kernel/smp-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/smp-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/smp-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,600 @@
++/*
++ * Intel SMP support routines.
++ *
++ * (c) 1995 Alan Cox, Building #3 <alan at redhat.com>
++ * (c) 1998-99, 2000 Ingo Molnar <mingo at redhat.com>
++ * (c) 2002,2003 Andi Kleen, SuSE Labs.
++ *
++ * This code is released under the GNU General Public License version 2 or
++ * later.
++ */
++
++#include <linux/init.h>
++
++#include <linux/mm.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/smp_lock.h>
++#include <linux/smp.h>
++#include <linux/kernel_stat.h>
++#include <linux/mc146818rtc.h>
++#include <linux/interrupt.h>
++
++#include <asm/mtrr.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++#include <asm/mach_apic.h>
++#include <asm/mmu_context.h>
++#include <asm/proto.h>
++#include <asm/apicdef.h>
++#include <asm/idle.h>
++#ifdef CONFIG_XEN
++#include <xen/evtchn.h>
++#endif
++
++#ifndef CONFIG_XEN
++/*
++ * Smarter SMP flushing macros.
++ * c/o Linus Torvalds.
++ *
++ * These mean you can really definitely utterly forget about
++ * writing to user space from interrupts. (Its not allowed anyway).
++ *
++ * Optimizations Manfred Spraul <manfred at colorfullife.com>
++ *
++ * More scalable flush, from Andi Kleen
++ *
++ * To avoid global state use 8 different call vectors.
++ * Each CPU uses a specific vector to trigger flushes on other
++ * CPUs. Depending on the received vector the target CPUs look into
++ * the right per cpu variable for the flush data.
++ *
++ * With more than 8 CPUs they are hashed to the 8 available
++ * vectors. The limited global vector space forces us to this right now.
++ * In future when interrupts are split into per CPU domains this could be
++ * fixed, at the cost of triggering multiple IPIs in some cases.
++ */
++
++union smp_flush_state {
++ struct {
++ cpumask_t flush_cpumask;
++ struct mm_struct *flush_mm;
++ unsigned long flush_va;
++#define FLUSH_ALL -1ULL
++ spinlock_t tlbstate_lock;
++ };
++ char pad[SMP_CACHE_BYTES];
++} ____cacheline_aligned;
++
++/* State is put into the per CPU data section, but padded
++ to a full cache line because other CPUs can access it and we don't
++ want false sharing in the per cpu data segment. */
++static DEFINE_PER_CPU(union smp_flush_state, flush_state);
++#endif
++
++/*
++ * We cannot call mmdrop() because we are in interrupt context,
++ * instead update mm->cpu_vm_mask.
++ */
++static inline void leave_mm(unsigned long cpu)
++{
++ if (read_pda(mmu_state) == TLBSTATE_OK)
++ BUG();
++ cpu_clear(cpu, read_pda(active_mm)->cpu_vm_mask);
++ load_cr3(swapper_pg_dir);
++}
++
++#ifndef CONFIG_XEN
++/*
++ *
++ * The flush IPI assumes that a thread switch happens in this order:
++ * [cpu0: the cpu that switches]
++ * 1) switch_mm() either 1a) or 1b)
++ * 1a) thread switch to a different mm
++ * 1a1) cpu_clear(cpu, old_mm->cpu_vm_mask);
++ * Stop ipi delivery for the old mm. This is not synchronized with
++ * the other cpus, but smp_invalidate_interrupt ignore flush ipis
++ * for the wrong mm, and in the worst case we perform a superfluous
++ * tlb flush.
++ * 1a2) set cpu mmu_state to TLBSTATE_OK
++ * Now the smp_invalidate_interrupt won't call leave_mm if cpu0
++ * was in lazy tlb mode.
++ * 1a3) update cpu active_mm
++ * Now cpu0 accepts tlb flushes for the new mm.
++ * 1a4) cpu_set(cpu, new_mm->cpu_vm_mask);
++ * Now the other cpus will send tlb flush ipis.
++ * 1a4) change cr3.
++ * 1b) thread switch without mm change
++ * cpu active_mm is correct, cpu0 already handles
++ * flush ipis.
++ * 1b1) set cpu mmu_state to TLBSTATE_OK
++ * 1b2) test_and_set the cpu bit in cpu_vm_mask.
++ * Atomically set the bit [other cpus will start sending flush ipis],
++ * and test the bit.
++ * 1b3) if the bit was 0: leave_mm was called, flush the tlb.
++ * 2) switch %%esp, ie current
++ *
++ * The interrupt must handle 2 special cases:
++ * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm.
++ * - the cpu performs speculative tlb reads, i.e. even if the cpu only
++ * runs in kernel space, the cpu could load tlb entries for user space
++ * pages.
++ *
++ * The good news is that cpu mmu_state is local to each cpu, no
++ * write/read ordering problems.
++ */
++
++/*
++ * TLB flush IPI:
++ *
++ * 1) Flush the tlb entries if the cpu uses the mm that's being flushed.
++ * 2) Leave the mm if we are in the lazy tlb mode.
++ *
++ * Interrupts are disabled.
++ */
++
++asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
++{
++ int cpu;
++ int sender;
++ union smp_flush_state *f;
++
++ cpu = smp_processor_id();
++ /*
++ * orig_rax contains the interrupt vector - 256.
++ * Use that to determine where the sender put the data.
++ */
++ sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START;
++ f = &per_cpu(flush_state, sender);
++
++ if (!cpu_isset(cpu, f->flush_cpumask))
++ goto out;
++ /*
++ * This was a BUG() but until someone can quote me the
++ * line from the intel manual that guarantees an IPI to
++ * multiple CPUs is retried _only_ on the erroring CPUs
++ * its staying as a return
++ *
++ * BUG();
++ */
++
++ if (f->flush_mm == read_pda(active_mm)) {
++ if (read_pda(mmu_state) == TLBSTATE_OK) {
++ if (f->flush_va == FLUSH_ALL)
++ local_flush_tlb();
++ else
++ __flush_tlb_one(f->flush_va);
++ } else
++ leave_mm(cpu);
++ }
++out:
++ ack_APIC_irq();
++ cpu_clear(cpu, f->flush_cpumask);
++}
++
++static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
++ unsigned long va)
++{
++ int sender;
++ union smp_flush_state *f;
++
++ /* Caller has disabled preemption */
++ sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS;
++ f = &per_cpu(flush_state, sender);
++
++ /* Could avoid this lock when
++ num_online_cpus() <= NUM_INVALIDATE_TLB_VECTORS, but it is
++ probably not worth checking this for a cache-hot lock. */
++ spin_lock(&f->tlbstate_lock);
++
++ f->flush_mm = mm;
++ f->flush_va = va;
++ cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask);
++
++ /*
++ * We have to send the IPI only to
++ * CPUs affected.
++ */
++ send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender);
++
++ while (!cpus_empty(f->flush_cpumask))
++ cpu_relax();
++
++ f->flush_mm = NULL;
++ f->flush_va = 0;
++ spin_unlock(&f->tlbstate_lock);
++}
++
++int __cpuinit init_smp_flush(void)
++{
++ int i;
++ for_each_cpu_mask(i, cpu_possible_map) {
++ spin_lock_init(&per_cpu(flush_state, i).tlbstate_lock);
++ }
++ return 0;
++}
++
++core_initcall(init_smp_flush);
++
++void flush_tlb_current_task(void)
++{
++ struct mm_struct *mm = current->mm;
++ cpumask_t cpu_mask;
++
++ preempt_disable();
++ cpu_mask = mm->cpu_vm_mask;
++ cpu_clear(smp_processor_id(), cpu_mask);
++
++ local_flush_tlb();
++ if (!cpus_empty(cpu_mask))
++ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
++ preempt_enable();
++}
++EXPORT_SYMBOL(flush_tlb_current_task);
++
++void flush_tlb_mm (struct mm_struct * mm)
++{
++ cpumask_t cpu_mask;
++
++ preempt_disable();
++ cpu_mask = mm->cpu_vm_mask;
++ cpu_clear(smp_processor_id(), cpu_mask);
++
++ if (current->active_mm == mm) {
++ if (current->mm)
++ local_flush_tlb();
++ else
++ leave_mm(smp_processor_id());
++ }
++ if (!cpus_empty(cpu_mask))
++ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
++
++ preempt_enable();
++}
++EXPORT_SYMBOL(flush_tlb_mm);
++
++void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
++{
++ struct mm_struct *mm = vma->vm_mm;
++ cpumask_t cpu_mask;
++
++ preempt_disable();
++ cpu_mask = mm->cpu_vm_mask;
++ cpu_clear(smp_processor_id(), cpu_mask);
++
++ if (current->active_mm == mm) {
++ if(current->mm)
++ __flush_tlb_one(va);
++ else
++ leave_mm(smp_processor_id());
++ }
++
++ if (!cpus_empty(cpu_mask))
++ flush_tlb_others(cpu_mask, mm, va);
++
++ preempt_enable();
++}
++EXPORT_SYMBOL(flush_tlb_page);
++
++static void do_flush_tlb_all(void* info)
++{
++ unsigned long cpu = smp_processor_id();
++
++ __flush_tlb_all();
++ if (read_pda(mmu_state) == TLBSTATE_LAZY)
++ leave_mm(cpu);
++}
++
++void flush_tlb_all(void)
++{
++ on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
++}
++#else
++asmlinkage void smp_invalidate_interrupt (void)
++{ return; }
++void flush_tlb_current_task(void)
++{ xen_tlb_flush_mask(¤t->mm->cpu_vm_mask); }
++void flush_tlb_mm (struct mm_struct * mm)
++{ xen_tlb_flush_mask(&mm->cpu_vm_mask); }
++void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
++{ xen_invlpg_mask(&vma->vm_mm->cpu_vm_mask, va); }
++void flush_tlb_all(void)
++{ xen_tlb_flush_all(); }
++#endif /* Xen */
++
++/*
++ * this function sends a 'reschedule' IPI to another CPU.
++ * it goes straight through and wastes no time serializing
++ * anything. Worst case is that we lose a reschedule ...
++ */
++
++void smp_send_reschedule(int cpu)
++{
++ send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
++}
++
++/*
++ * Structure and data for smp_call_function(). This is designed to minimise
++ * static memory requirements. It also looks cleaner.
++ */
++static DEFINE_SPINLOCK(call_lock);
++
++struct call_data_struct {
++ void (*func) (void *info);
++ void *info;
++ atomic_t started;
++ atomic_t finished;
++ int wait;
++};
++
++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 one other CPU
++ * in the system.
++ *
++ * cpu is a standard Linux logical CPU number.
++ */
++static void
++__smp_call_function_single(int cpu, void (*func) (void *info), void *info,
++ int nonatomic, int wait)
++{
++ struct call_data_struct data;
++ int cpus = 1;
++
++ data.func = func;
++ data.info = info;
++ atomic_set(&data.started, 0);
++ data.wait = wait;
++ if (wait)
++ atomic_set(&data.finished, 0);
++
++ call_data = &data;
++ wmb();
++ /* Send a message to all other CPUs and wait for them to respond */
++ send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR);
++
++ /* Wait for response */
++ while (atomic_read(&data.started) != cpus)
++ cpu_relax();
++
++ if (!wait)
++ return;
++
++ while (atomic_read(&data.finished) != cpus)
++ cpu_relax();
++}
++
++/*
++ * smp_call_function_single - Run a function on another CPU
++ * @func: The function to run. This must be fast and non-blocking.
++ * @info: An arbitrary pointer to pass to the function.
++ * @nonatomic: Currently unused.
++ * @wait: If true, wait until function has completed on other CPUs.
++ *
++ * Retrurns 0 on success, else a negative status code.
++ *
++ * Does not return until the remote CPU is nearly ready to execute <func>
++ * or is or has executed.
++ */
++
++int smp_call_function_single (int cpu, void (*func) (void *info), void *info,
++ int nonatomic, int wait)
++{
++ /* prevent preemption and reschedule on another processor */
++ int me = get_cpu();
++ if (cpu == me) {
++ WARN_ON(1);
++ put_cpu();
++ return -EBUSY;
++ }
++ spin_lock_bh(&call_lock);
++ __smp_call_function_single(cpu, func, info, nonatomic, wait);
++ spin_unlock_bh(&call_lock);
++ put_cpu();
++ return 0;
++}
++
++/*
++ * this function sends a 'generic call function' IPI to all other CPUs
++ * in the system.
++ */
++static void __smp_call_function (void (*func) (void *info), void *info,
++ int nonatomic, int wait)
++{
++ struct call_data_struct data;
++ int cpus = num_online_cpus()-1;
++
++ if (!cpus)
++ return;
++
++ data.func = func;
++ data.info = info;
++ atomic_set(&data.started, 0);
++ data.wait = wait;
++ if (wait)
++ atomic_set(&data.finished, 0);
++
++ call_data = &data;
++ wmb();
++ /* Send a message to all other CPUs and wait for them to respond */
++ send_IPI_allbutself(CALL_FUNCTION_VECTOR);
++
++ /* Wait for response */
++ while (atomic_read(&data.started) != cpus)
++#ifndef CONFIG_XEN
++ cpu_relax();
++#else
++ barrier();
++#endif
++
++ if (!wait)
++ return;
++
++ while (atomic_read(&data.finished) != cpus)
++#ifndef CONFIG_XEN
++ cpu_relax();
++#else
++ barrier();
++#endif
++}
++
++/*
++ * smp_call_function - run a function on all other CPUs.
++ * @func: The function to run. This must be fast and non-blocking.
++ * @info: An arbitrary pointer to pass to the function.
++ * @nonatomic: currently unused.
++ * @wait: If true, wait (atomically) until function has completed on other
++ * CPUs.
++ *
++ * Returns 0 on success, else a negative status code. Does not return until
++ * remote CPUs are nearly ready to execute func or are or have executed.
++ *
++ * You must not call this function with disabled interrupts or from a
++ * hardware interrupt handler or from a bottom half handler.
++ * Actually there are a few legal cases, like panic.
++ */
++int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
++ int wait)
++{
++ spin_lock(&call_lock);
++ __smp_call_function(func,info,nonatomic,wait);
++ spin_unlock(&call_lock);
++ return 0;
++}
++EXPORT_SYMBOL(smp_call_function);
++
++void smp_stop_cpu(void)
++{
++ unsigned long flags;
++ /*
++ * Remove this CPU:
++ */
++ cpu_clear(smp_processor_id(), cpu_online_map);
++ local_irq_save(flags);
++#ifndef CONFIG_XEN
++ disable_local_APIC();
++#endif
++ local_irq_restore(flags);
++}
++
++static void smp_really_stop_cpu(void *dummy)
++{
++ smp_stop_cpu();
++ for (;;)
++ halt();
++}
++
++void smp_send_stop(void)
++{
++ int nolock = 0;
++#ifndef CONFIG_XEN
++ if (reboot_force)
++ return;
++#endif
++ /* Don't deadlock on the call lock in panic */
++ if (!spin_trylock(&call_lock)) {
++ /* ignore locking because we have panicked anyways */
++ nolock = 1;
++ }
++ __smp_call_function(smp_really_stop_cpu, NULL, 0, 0);
++ if (!nolock)
++ spin_unlock(&call_lock);
++
++ local_irq_disable();
++#ifndef CONFIG_XEN
++ disable_local_APIC();
++#endif
++ local_irq_enable();
++}
++
++/*
++ * Reschedule call back. Nothing to do,
++ * all the work is done automatically when
++ * we return from the interrupt.
++ */
++#ifndef CONFIG_XEN
++asmlinkage void smp_reschedule_interrupt(void)
++#else
++asmlinkage irqreturn_t smp_reschedule_interrupt(void)
++#endif
++{
++#ifndef CONFIG_XEN
++ ack_APIC_irq();
++#else
++ return IRQ_HANDLED;
++#endif
++}
++
++#ifndef CONFIG_XEN
++asmlinkage void smp_call_function_interrupt(void)
++#else
++asmlinkage irqreturn_t smp_call_function_interrupt(void)
++#endif
++{
++ void (*func) (void *info) = call_data->func;
++ void *info = call_data->info;
++ int wait = call_data->wait;
++
++#ifndef CONFIG_XEN
++ ack_APIC_irq();
++#endif
++ /*
++ * Notify initiating CPU that I've grabbed the data and am
++ * about to execute the function
++ */
++ mb();
++ atomic_inc(&call_data->started);
++ /*
++ * At this point the info structure may be out of scope unless wait==1
++ */
++ exit_idle();
++ irq_enter();
++ (*func)(info);
++ irq_exit();
++ if (wait) {
++ mb();
++ atomic_inc(&call_data->finished);
++ }
++#ifdef CONFIG_XEN
++ return IRQ_HANDLED;
++#endif
++}
++
++int safe_smp_processor_id(void)
++{
++#ifdef CONFIG_XEN
++ return smp_processor_id();
++#else
++ unsigned apicid, i;
++
++ if (disable_apic)
++ return 0;
++
++ apicid = hard_smp_processor_id();
++ if (apicid < NR_CPUS && x86_cpu_to_apicid[apicid] == apicid)
++ return apicid;
++
++ for (i = 0; i < NR_CPUS; ++i) {
++ if (x86_cpu_to_apicid[i] == apicid)
++ return i;
++ }
++
++ /* No entries in x86_cpu_to_apicid? Either no MPS|ACPI,
++ * or called too early. Either way, we must be CPU 0. */
++ if (x86_cpu_to_apicid[0] == BAD_APICID)
++ return 0;
++
++ return 0; /* Should not happen */
++#endif
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/traps-xen.c linux-2.6.18-xen/arch/x86_64/kernel/traps-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/traps-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/traps-xen.c 2006-09-22 16:38:35.000000000 +0200
+@@ -0,0 +1,1173 @@
++/*
++ * linux/arch/x86-64/traps.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
++ *
++ * Pentium III FXSR, SSE support
++ * Gareth Hughes <gareth at valinux.com>, May 2000
++ */
++
++/*
++ * 'Traps.c' handles hardware traps and faults after we have saved some
++ * state in 'entry.S'.
++ */
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/nmi.h>
++#include <linux/kprobes.h>
++#include <linux/kexec.h>
++#include <linux/unwind.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/debugreg.h>
++#include <asm/desc.h>
++#include <asm/i387.h>
++#include <asm/kdebug.h>
++#include <asm/processor.h>
++#include <asm/unwind.h>
++#include <asm/smp.h>
++#include <asm/pgalloc.h>
++#include <asm/pda.h>
++#include <asm/proto.h>
++#include <asm/nmi.h>
++
++asmlinkage void divide_error(void);
++asmlinkage void debug(void);
++asmlinkage void nmi(void);
++asmlinkage void int3(void);
++asmlinkage void overflow(void);
++asmlinkage void bounds(void);
++asmlinkage void invalid_op(void);
++asmlinkage void device_not_available(void);
++asmlinkage void double_fault(void);
++asmlinkage void coprocessor_segment_overrun(void);
++asmlinkage void invalid_TSS(void);
++asmlinkage void segment_not_present(void);
++asmlinkage void stack_segment(void);
++asmlinkage void general_protection(void);
++asmlinkage void page_fault(void);
++asmlinkage void coprocessor_error(void);
++asmlinkage void simd_coprocessor_error(void);
++asmlinkage void reserved(void);
++asmlinkage void alignment_check(void);
++asmlinkage void machine_check(void);
++asmlinkage void spurious_interrupt_bug(void);
++
++ATOMIC_NOTIFIER_HEAD(die_chain);
++
++int register_die_notifier(struct notifier_block *nb)
++{
++ vmalloc_sync_all();
++ return atomic_notifier_chain_register(&die_chain, nb);
++}
++EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */
++
++int unregister_die_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(&die_chain, nb);
++}
++EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */
++
++static inline void conditional_sti(struct pt_regs *regs)
++{
++ if (regs->eflags & X86_EFLAGS_IF)
++ local_irq_enable();
++}
++
++static inline void preempt_conditional_sti(struct pt_regs *regs)
++{
++ preempt_disable();
++ if (regs->eflags & X86_EFLAGS_IF)
++ local_irq_enable();
++}
++
++static inline void preempt_conditional_cli(struct pt_regs *regs)
++{
++ if (regs->eflags & X86_EFLAGS_IF)
++ local_irq_disable();
++ /* Make sure to not schedule here because we could be running
++ on an exception stack. */
++ preempt_enable_no_resched();
++}
++
++static int kstack_depth_to_print = 10;
++#ifdef CONFIG_STACK_UNWIND
++static int call_trace = 1;
++#else
++#define call_trace (-1)
++#endif
++
++
++#ifdef CONFIG_KALLSYMS
++# include <linux/kallsyms.h>
++void printk_address(unsigned long address)
++{
++ unsigned long offset = 0, symsize;
++ const char *symname;
++ char *modname;
++ char *delim = ":";
++ char namebuf[128];
++
++ symname = kallsyms_lookup(address, &symsize, &offset,
++ &modname, namebuf);
++ if (!symname) {
++ printk(" [<%016lx>]\n", address);
++ return;
++ }
++ if (!modname)
++ modname = delim = "";
++ printk(" [<%016lx>] %s%s%s%s+0x%lx/0x%lx\n",
++ address, delim, modname, delim, symname, offset, symsize);
++}
++#else
++void printk_address(unsigned long address)
++{
++ printk(" [<%016lx>]\n", address);
++}
++#endif
++
++static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
++ unsigned *usedp, const char **idp)
++{
++#ifndef CONFIG_X86_NO_TSS
++ static char ids[][8] = {
++ [DEBUG_STACK - 1] = "#DB",
++ [NMI_STACK - 1] = "NMI",
++ [DOUBLEFAULT_STACK - 1] = "#DF",
++ [STACKFAULT_STACK - 1] = "#SS",
++ [MCE_STACK - 1] = "#MC",
++#if DEBUG_STKSZ > EXCEPTION_STKSZ
++ [N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
++#endif
++ };
++ unsigned k;
++
++ /*
++ * Iterate over all exception stacks, and figure out whether
++ * 'stack' is in one of them:
++ */
++ for (k = 0; k < N_EXCEPTION_STACKS; k++) {
++ unsigned long end;
++
++ /*
++ * set 'end' to the end of the exception stack.
++ */
++ switch (k + 1) {
++ /*
++ * TODO: this block is not needed i think, because
++ * setup64.c:cpu_init() sets up t->ist[DEBUG_STACK]
++ * properly too.
++ */
++#if DEBUG_STKSZ > EXCEPTION_STKSZ
++ case DEBUG_STACK:
++ end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ;
++ break;
++#endif
++ default:
++ end = per_cpu(orig_tss, cpu).ist[k];
++ break;
++ }
++ /*
++ * Is 'stack' above this exception frame's end?
++ * If yes then skip to the next frame.
++ */
++ if (stack >= end)
++ continue;
++ /*
++ * Is 'stack' above this exception frame's start address?
++ * If yes then we found the right frame.
++ */
++ if (stack >= end - EXCEPTION_STKSZ) {
++ /*
++ * Make sure we only iterate through an exception
++ * stack once. If it comes up for the second time
++ * then there's something wrong going on - just
++ * break out and return NULL:
++ */
++ if (*usedp & (1U << k))
++ break;
++ *usedp |= 1U << k;
++ *idp = ids[k];
++ return (unsigned long *)end;
++ }
++ /*
++ * If this is a debug stack, and if it has a larger size than
++ * the usual exception stacks, then 'stack' might still
++ * be within the lower portion of the debug stack:
++ */
++#if DEBUG_STKSZ > EXCEPTION_STKSZ
++ if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
++ unsigned j = N_EXCEPTION_STACKS - 1;
++
++ /*
++ * Black magic. A large debug stack is composed of
++ * multiple exception stack entries, which we
++ * iterate through now. Dont look:
++ */
++ do {
++ ++j;
++ end -= EXCEPTION_STKSZ;
++ ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
++ } while (stack < end - EXCEPTION_STKSZ);
++ if (*usedp & (1U << j))
++ break;
++ *usedp |= 1U << j;
++ *idp = ids[j];
++ return (unsigned long *)end;
++ }
++#endif
++ }
++#endif
++ return NULL;
++}
++
++static int show_trace_unwind(struct unwind_frame_info *info, void *context)
++{
++ int n = 0;
++
++ while (unwind(info) == 0 && UNW_PC(info)) {
++ if (arch_unw_user_mode(info))
++ break;
++ n++;
++ printk_address(UNW_PC(info));
++ }
++ return n;
++}
++
++/*
++ * x86-64 can have upto three kernel stacks:
++ * process stack
++ * interrupt stack
++ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
++ */
++
++void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack)
++{
++ const unsigned cpu = safe_smp_processor_id();
++ unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
++ unsigned used = 0;
++
++ printk("\nCall Trace:\n");
++
++ if (!tsk)
++ tsk = current;
++
++ if (call_trace >= 0) {
++ int unw_ret = 0;
++ struct unwind_frame_info info;
++
++ if (regs) {
++ if (unwind_init_frame_info(&info, tsk, regs) == 0)
++ unw_ret = show_trace_unwind(&info, NULL);
++ } else if (tsk == current)
++ unw_ret = unwind_init_running(&info, show_trace_unwind, NULL);
++ else {
++ if (unwind_init_blocked(&info, tsk) == 0)
++ unw_ret = show_trace_unwind(&info, NULL);
++ }
++ if (unw_ret > 0) {
++ if (call_trace == 1 && !arch_unw_user_mode(&info)) {
++ print_symbol("DWARF2 unwinder stuck at %s\n",
++ UNW_PC(&info));
++ if ((long)UNW_SP(&info) < 0) {
++ printk("Leftover inexact backtrace:\n");
++ stack = (unsigned long *)UNW_SP(&info);
++ } else
++ printk("Full inexact backtrace again:\n");
++ } else if (call_trace >= 1)
++ return;
++ else
++ printk("Full inexact backtrace again:\n");
++ } else
++ printk("Inexact backtrace:\n");
++ }
++ /*
++ * Print function call entries within a stack. 'cond' is the
++ * "end of stackframe" condition, that the 'stack++'
++ * iteration will eventually trigger.
++ */
++#define HANDLE_STACK(cond) \
++ do while (cond) { \
++ unsigned long addr = *stack++; \
++ if (kernel_text_address(addr)) { \
++ /* \
++ * If the address is either in the text segment of the \
++ * kernel, or in the region which contains vmalloc'ed \
++ * memory, it *may* be the address of a calling \
++ * routine; if so, print it so that someone tracing \
++ * down the cause of the crash will be able to figure \
++ * out the call path that was taken. \
++ */ \
++ printk_address(addr); \
++ } \
++ } while (0)
++
++ /*
++ * Print function call entries in all stacks, starting at the
++ * current stack address. If the stacks consist of nested
++ * exceptions
++ */
++ for ( ; ; ) {
++ const char *id;
++ unsigned long *estack_end;
++ estack_end = in_exception_stack(cpu, (unsigned long)stack,
++ &used, &id);
++
++ if (estack_end) {
++ printk(" <%s>", id);
++ HANDLE_STACK (stack < estack_end);
++ printk(" <EOE>");
++ /*
++ * We link to the next stack via the
++ * second-to-last pointer (index -2 to end) in the
++ * exception stack:
++ */
++ stack = (unsigned long *) estack_end[-2];
++ continue;
++ }
++ if (irqstack_end) {
++ unsigned long *irqstack;
++ irqstack = irqstack_end -
++ (IRQSTACKSIZE - 64) / sizeof(*irqstack);
++
++ if (stack >= irqstack && stack < irqstack_end) {
++ printk(" <IRQ>");
++ HANDLE_STACK (stack < irqstack_end);
++ /*
++ * We link to the next stack (which would be
++ * the process stack normally) the last
++ * pointer (index -1 to end) in the IRQ stack:
++ */
++ stack = (unsigned long *) (irqstack_end[-1]);
++ irqstack_end = NULL;
++ printk(" <EOI>");
++ continue;
++ }
++ }
++ break;
++ }
++
++ /*
++ * This prints the process stack:
++ */
++ HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0);
++#undef HANDLE_STACK
++
++ printk("\n");
++}
++
++static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp)
++{
++ unsigned long *stack;
++ int i;
++ const int cpu = safe_smp_processor_id();
++ unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr);
++ unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
++
++ // debugging aid: "show_stack(NULL, NULL);" prints the
++ // back trace for this cpu.
++
++ if (rsp == NULL) {
++ if (tsk)
++ rsp = (unsigned long *)tsk->thread.rsp;
++ else
++ rsp = (unsigned long *)&rsp;
++ }
++
++ stack = rsp;
++ for(i=0; i < kstack_depth_to_print; i++) {
++ if (stack >= irqstack && stack <= irqstack_end) {
++ if (stack == irqstack_end) {
++ stack = (unsigned long *) (irqstack_end[-1]);
++ printk(" <EOI> ");
++ }
++ } else {
++ if (((long) stack & (THREAD_SIZE-1)) == 0)
++ break;
++ }
++ if (i && ((i % 4) == 0))
++ printk("\n");
++ printk(" %016lx ", *stack++);
++ touch_nmi_watchdog();
++ }
++ show_trace(tsk, regs, rsp);
++}
++
++void show_stack(struct task_struct *tsk, unsigned long * rsp)
++{
++ _show_stack(tsk, NULL, rsp);
++}
++
++/*
++ * The architecture-independent dump_stack generator
++ */
++void dump_stack(void)
++{
++ unsigned long dummy;
++ show_trace(NULL, NULL, &dummy);
++}
++
++EXPORT_SYMBOL(dump_stack);
++
++void show_registers(struct pt_regs *regs)
++{
++ int i;
++ int in_kernel = !user_mode(regs);
++ unsigned long rsp;
++ const int cpu = safe_smp_processor_id();
++ struct task_struct *cur = cpu_pda(cpu)->pcurrent;
++
++ rsp = regs->rsp;
++
++ printk("CPU %d ", cpu);
++ __show_regs(regs);
++ printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
++ cur->comm, cur->pid, task_thread_info(cur), cur);
++
++ /*
++ * When in-kernel, we also print out the stack and code at the
++ * time of the fault..
++ */
++ if (in_kernel) {
++
++ printk("Stack: ");
++ _show_stack(NULL, regs, (unsigned long*)rsp);
++
++ printk("\nCode: ");
++ if (regs->rip < PAGE_OFFSET)
++ goto bad;
++
++ for (i=0; i<20; i++) {
++ unsigned char c;
++ if (__get_user(c, &((unsigned char*)regs->rip)[i])) {
++bad:
++ printk(" Bad RIP value.");
++ break;
++ }
++ printk("%02x ", c);
++ }
++ }
++ printk("\n");
++}
++
++void handle_BUG(struct pt_regs *regs)
++{
++ struct bug_frame f;
++ long len;
++ const char *prefix = "";
++
++ if (user_mode(regs))
++ return;
++ if (__copy_from_user(&f, (const void __user *) regs->rip,
++ sizeof(struct bug_frame)))
++ return;
++ if (f.filename >= 0 ||
++ f.ud2[0] != 0x0f || f.ud2[1] != 0x0b)
++ return;
++ len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1;
++ if (len < 0 || len >= PATH_MAX)
++ f.filename = (int)(long)"unmapped filename";
++ else if (len > 50) {
++ f.filename += len - 50;
++ prefix = "...";
++ }
++ printk("----------- [cut here ] --------- [please bite here ] ---------\n");
++ printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line);
++}
++
++#ifdef CONFIG_BUG
++void out_of_line_bug(void)
++{
++ BUG();
++}
++#endif
++
++static DEFINE_SPINLOCK(die_lock);
++static int die_owner = -1;
++static unsigned int die_nest_count;
++
++unsigned __kprobes long oops_begin(void)
++{
++ int cpu = safe_smp_processor_id();
++ unsigned long flags;
++
++ /* racy, but better than risking deadlock. */
++ local_irq_save(flags);
++ if (!spin_trylock(&die_lock)) {
++ if (cpu == die_owner)
++ /* nested oops. should stop eventually */;
++ else
++ spin_lock(&die_lock);
++ }
++ die_nest_count++;
++ die_owner = cpu;
++ console_verbose();
++ bust_spinlocks(1);
++ return flags;
++}
++
++void __kprobes oops_end(unsigned long flags)
++{
++ die_owner = -1;
++ bust_spinlocks(0);
++ die_nest_count--;
++ if (die_nest_count)
++ /* We still own the lock */
++ local_irq_restore(flags);
++ else
++ /* Nest count reaches zero, release the lock. */
++ spin_unlock_irqrestore(&die_lock, flags);
++ if (panic_on_oops)
++ panic("Fatal exception");
++}
++
++void __kprobes __die(const char * str, struct pt_regs * regs, long err)
++{
++ static int die_counter;
++ printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
++#ifdef CONFIG_PREEMPT
++ printk("PREEMPT ");
++#endif
++#ifdef CONFIG_SMP
++ printk("SMP ");
++#endif
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ printk("DEBUG_PAGEALLOC");
++#endif
++ printk("\n");
++ notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
++ show_registers(regs);
++ /* Executive summary in case the oops scrolled away */
++ printk(KERN_ALERT "RIP ");
++ printk_address(regs->rip);
++ printk(" RSP <%016lx>\n", regs->rsp);
++ if (kexec_should_crash(current))
++ crash_kexec(regs);
++}
++
++void die(const char * str, struct pt_regs * regs, long err)
++{
++ unsigned long flags = oops_begin();
++
++ handle_BUG(regs);
++ __die(str, regs, err);
++ oops_end(flags);
++ do_exit(SIGSEGV);
++}
++
++#ifdef CONFIG_X86_LOCAL_APIC
++void __kprobes die_nmi(char *str, struct pt_regs *regs)
++{
++ unsigned long flags = oops_begin();
++
++ /*
++ * We are in trouble anyway, lets at least try
++ * to get a message out.
++ */
++ printk(str, safe_smp_processor_id());
++ show_registers(regs);
++ if (kexec_should_crash(current))
++ crash_kexec(regs);
++ if (panic_on_timeout || panic_on_oops)
++ panic("nmi watchdog");
++ printk("console shuts up ...\n");
++ oops_end(flags);
++ nmi_exit();
++ local_irq_enable();
++ do_exit(SIGSEGV);
++}
++#endif
++
++static void __kprobes do_trap(int trapnr, int signr, char *str,
++ 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 (user_mode(regs)) {
++ if (exception_trace && unhandled_signal(tsk, signr))
++ printk(KERN_INFO
++ "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
++ tsk->comm, tsk->pid, str,
++ regs->rip, regs->rsp, error_code);
++
++ if (info)
++ force_sig_info(signr, info, tsk);
++ else
++ force_sig(signr, tsk);
++ return;
++ }
++
++
++ /* kernel trap */
++ {
++ const struct exception_table_entry *fixup;
++ fixup = search_exception_tables(regs->rip);
++ if (fixup)
++ regs->rip = fixup->fixup;
++ else
++ die(str, regs, error_code);
++ return;
++ }
++}
++
++#define DO_ERROR(trapnr, signr, str, name) \
++asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
++{ \
++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
++ == NOTIFY_STOP) \
++ return; \
++ conditional_sti(regs); \
++ do_trap(trapnr, signr, str, regs, error_code, NULL); \
++}
++
++#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
++asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
++{ \
++ siginfo_t info; \
++ info.si_signo = signr; \
++ info.si_errno = 0; \
++ info.si_code = sicode; \
++ info.si_addr = (void __user *)siaddr; \
++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
++ == NOTIFY_STOP) \
++ return; \
++ conditional_sti(regs); \
++ do_trap(trapnr, signr, str, regs, error_code, &info); \
++}
++
++DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->rip)
++DO_ERROR( 4, SIGSEGV, "overflow", overflow)
++DO_ERROR( 5, SIGSEGV, "bounds", bounds)
++DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->rip)
++DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
++DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
++DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
++DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
++DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
++DO_ERROR(18, SIGSEGV, "reserved", reserved)
++
++/* Runs on IST stack */
++asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
++{
++ if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
++ 12, SIGBUS) == NOTIFY_STOP)
++ return;
++ preempt_conditional_sti(regs);
++ do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
++ preempt_conditional_cli(regs);
++}
++
++asmlinkage void do_double_fault(struct pt_regs * regs, long error_code)
++{
++ static const char str[] = "double fault";
++ struct task_struct *tsk = current;
++
++ /* Return not checked because double check cannot be ignored */
++ notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
++
++ tsk->thread.error_code = error_code;
++ tsk->thread.trap_no = 8;
++
++ /* This is always a kernel trap and never fixable (and thus must
++ never return). */
++ for (;;)
++ die(str, regs, error_code);
++}
++
++asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
++ long error_code)
++{
++ struct task_struct *tsk = current;
++
++ conditional_sti(regs);
++
++ tsk->thread.error_code = error_code;
++ tsk->thread.trap_no = 13;
++
++ if (user_mode(regs)) {
++ if (exception_trace && unhandled_signal(tsk, SIGSEGV))
++ printk(KERN_INFO
++ "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
++ tsk->comm, tsk->pid,
++ regs->rip, regs->rsp, error_code);
++
++ force_sig(SIGSEGV, tsk);
++ return;
++ }
++
++ /* kernel gp */
++ {
++ const struct exception_table_entry *fixup;
++ fixup = search_exception_tables(regs->rip);
++ if (fixup) {
++ regs->rip = fixup->fixup;
++ return;
++ }
++ if (notify_die(DIE_GPF, "general protection fault", regs,
++ error_code, 13, SIGSEGV) == NOTIFY_STOP)
++ return;
++ die("general protection fault", regs, error_code);
++ }
++}
++
++static __kprobes void
++mem_parity_error(unsigned char reason, struct pt_regs * regs)
++{
++ printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
++ printk("You probably have a hardware problem with your RAM chips\n");
++
++#if 0 /* XEN */
++ /* Clear and disable the memory parity error line. */
++ reason = (reason & 0xf) | 4;
++ outb(reason, 0x61);
++#endif /* XEN */
++}
++
++static __kprobes void
++io_check_error(unsigned char reason, struct pt_regs * regs)
++{
++ printk("NMI: IOCK error (debug interrupt?)\n");
++ show_registers(regs);
++
++#if 0 /* XEN */
++ /* Re-enable the IOCK line, wait for a few seconds */
++ reason = (reason & 0xf) | 8;
++ outb(reason, 0x61);
++ mdelay(2000);
++ reason &= ~8;
++ outb(reason, 0x61);
++#endif /* XEN */
++}
++
++static __kprobes void
++unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
++{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
++ printk("Dazed and confused, but trying to continue\n");
++ printk("Do you have a strange power saving mode enabled?\n");
++}
++
++/* Runs on IST stack. This code must keep interrupts off all the time.
++ Nested NMIs are prevented by the CPU. */
++asmlinkage __kprobes 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 (!cpu)
++ reason = get_nmi_reason();
++
++ if (!(reason & 0xc0)) {
++ if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
++ == NOTIFY_STOP)
++ return;
++#ifdef CONFIG_X86_LOCAL_APIC
++ /*
++ * Ok, so this is none of the documented NMI sources,
++ * so it must be the NMI watchdog.
++ */
++ if (nmi_watchdog > 0) {
++ nmi_watchdog_tick(regs,reason);
++ return;
++ }
++#endif
++ unknown_nmi_error(reason, regs);
++ return;
++ }
++ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
++ return;
++
++ /* AK: following checks seem to be broken on modern chipsets. FIXME */
++
++ if (reason & 0x80)
++ mem_parity_error(reason, regs);
++ if (reason & 0x40)
++ io_check_error(reason, regs);
++}
++
++/* runs on IST stack. */
++asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
++{
++ if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
++ return;
++ }
++ preempt_conditional_sti(regs);
++ do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
++ preempt_conditional_cli(regs);
++}
++
++/* Help handler running on IST stack to switch back to user stack
++ for scheduling or signal handling. The actual stack switch is done in
++ entry.S */
++asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
++{
++ struct pt_regs *regs = eregs;
++ /* Did already sync */
++ if (eregs == (struct pt_regs *)eregs->rsp)
++ ;
++ /* Exception from user space */
++ else if (user_mode(eregs))
++ regs = task_pt_regs(current);
++ /* Exception from kernel and interrupts are enabled. Move to
++ kernel process stack. */
++ else if (eregs->eflags & X86_EFLAGS_IF)
++ regs = (struct pt_regs *)(eregs->rsp -= sizeof(struct pt_regs));
++ if (eregs != regs)
++ *regs = *eregs;
++ return regs;
++}
++
++/* runs on IST stack. */
++asmlinkage void __kprobes do_debug(struct pt_regs * regs,
++ unsigned long error_code)
++{
++ unsigned long condition;
++ struct task_struct *tsk = current;
++ siginfo_t info;
++
++ get_debugreg(condition, 6);
++
++ if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
++ SIGTRAP) == NOTIFY_STOP)
++ return;
++
++ preempt_conditional_sti(regs);
++
++ /* Mask out spurious debug traps due to lazy DR7 setting */
++ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
++ if (!tsk->thread.debugreg7) {
++ goto clear_dr7;
++ }
++ }
++
++ tsk->thread.debugreg6 = condition;
++
++ /* Mask out spurious TF errors due to lazy TF clearing */
++ if (condition & DR_STEP) {
++ /*
++ * The TF error should be masked out only if the current
++ * process is not traced and if the TRAP flag has been set
++ * previously by a tracing process (condition detected by
++ * the PT_DTRACE flag); remember that the i386 TRAP flag
++ * can be modified by the process itself in user mode,
++ * allowing programs to debug themselves without the ptrace()
++ * interface.
++ */
++ if (!user_mode(regs))
++ goto clear_TF_reenable;
++ /*
++ * Was the TF flag set by a debugger? If so, clear it now,
++ * so that register information is correct.
++ */
++ if (tsk->ptrace & PT_DTRACE) {
++ regs->eflags &= ~TF_MASK;
++ tsk->ptrace &= ~PT_DTRACE;
++ }
++ }
++
++ /* Ok, finally something we can handle */
++ tsk->thread.trap_no = 1;
++ tsk->thread.error_code = error_code;
++ info.si_signo = SIGTRAP;
++ info.si_errno = 0;
++ info.si_code = TRAP_BRKPT;
++ info.si_addr = user_mode(regs) ? (void __user *)regs->rip : NULL;
++ force_sig_info(SIGTRAP, &info, tsk);
++
++clear_dr7:
++ set_debugreg(0UL, 7);
++ preempt_conditional_cli(regs);
++ return;
++
++clear_TF_reenable:
++ set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++ regs->eflags &= ~TF_MASK;
++ preempt_conditional_cli(regs);
++}
++
++static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
++{
++ const struct exception_table_entry *fixup;
++ fixup = search_exception_tables(regs->rip);
++ if (fixup) {
++ regs->rip = fixup->fixup;
++ return 1;
++ }
++ notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
++ /* Illegal floating point operation in the kernel */
++ current->thread.trap_no = trapnr;
++ die(str, regs, 0);
++ return 0;
++}
++
++/*
++ * Note that we play around with the 'TS' bit in an attempt to get
++ * the correct behaviour even in the presence of the asynchronous
++ * IRQ13 behaviour
++ */
++asmlinkage void do_coprocessor_error(struct pt_regs *regs)
++{
++ void __user *rip = (void __user *)(regs->rip);
++ struct task_struct * task;
++ siginfo_t info;
++ unsigned short cwd, swd;
++
++ conditional_sti(regs);
++ if (!user_mode(regs) &&
++ kernel_math_error(regs, "kernel x87 math error", 16))
++ return;
++
++ /*
++ * Save the info for the exception handler and clear the error.
++ */
++ task = current;
++ save_init_fpu(task);
++ task->thread.trap_no = 16;
++ task->thread.error_code = 0;
++ info.si_signo = SIGFPE;
++ info.si_errno = 0;
++ info.si_code = __SI_FAULT;
++ info.si_addr = rip;
++ /*
++ * (~cwd & swd) will mask out exceptions that are not set to unmasked
++ * status. 0x3f is the exception bits in these regs, 0x200 is the
++ * C1 reg you need in case of a stack fault, 0x040 is the stack
++ * fault bit. We should only be taking one exception at a time,
++ * so if this combination doesn't produce any single exception,
++ * then we have a bad program that isn't synchronizing its FPU usage
++ * and it will suffer the consequences since we won't be able to
++ * fully reproduce the context of the exception
++ */
++ cwd = get_fpu_cwd(task);
++ swd = get_fpu_swd(task);
++ switch (swd & ~cwd & 0x3f) {
++ case 0x000:
++ default:
++ break;
++ case 0x001: /* Invalid Op */
++ /*
++ * swd & 0x240 == 0x040: Stack Underflow
++ * swd & 0x240 == 0x240: Stack Overflow
++ * User must clear the SF bit (0x40) if set
++ */
++ info.si_code = FPE_FLTINV;
++ break;
++ case 0x002: /* Denormalize */
++ case 0x010: /* Underflow */
++ info.si_code = FPE_FLTUND;
++ break;
++ case 0x004: /* Zero Divide */
++ info.si_code = FPE_FLTDIV;
++ break;
++ case 0x008: /* Overflow */
++ info.si_code = FPE_FLTOVF;
++ break;
++ case 0x020: /* Precision */
++ info.si_code = FPE_FLTRES;
++ break;
++ }
++ force_sig_info(SIGFPE, &info, task);
++}
++
++asmlinkage void bad_intr(void)
++{
++ printk("bad interrupt");
++}
++
++asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
++{
++ void __user *rip = (void __user *)(regs->rip);
++ struct task_struct * task;
++ siginfo_t info;
++ unsigned short mxcsr;
++
++ conditional_sti(regs);
++ if (!user_mode(regs) &&
++ kernel_math_error(regs, "kernel simd math error", 19))
++ return;
++
++ /*
++ * Save the info for the exception handler and clear the error.
++ */
++ task = current;
++ save_init_fpu(task);
++ task->thread.trap_no = 19;
++ task->thread.error_code = 0;
++ info.si_signo = SIGFPE;
++ info.si_errno = 0;
++ info.si_code = __SI_FAULT;
++ info.si_addr = rip;
++ /*
++ * The SIMD FPU exceptions are handled a little differently, as there
++ * is only a single status/control register. Thus, to determine which
++ * unmasked exception was caught we must mask the exception mask bits
++ * at 0x1f80, and then use these to mask the exception bits at 0x3f.
++ */
++ mxcsr = get_fpu_mxcsr(task);
++ switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
++ case 0x000:
++ default:
++ break;
++ case 0x001: /* Invalid Op */
++ info.si_code = FPE_FLTINV;
++ break;
++ case 0x002: /* Denormalize */
++ case 0x010: /* Underflow */
++ info.si_code = FPE_FLTUND;
++ break;
++ case 0x004: /* Zero Divide */
++ info.si_code = FPE_FLTDIV;
++ break;
++ case 0x008: /* Overflow */
++ info.si_code = FPE_FLTOVF;
++ break;
++ case 0x020: /* Precision */
++ info.si_code = FPE_FLTRES;
++ break;
++ }
++ force_sig_info(SIGFPE, &info, task);
++}
++
++asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
++{
++}
++
++#if 0
++asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
++{
++}
++#endif
++
++asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
++{
++}
++
++/*
++ * 'math_state_restore()' saves the current math information in the
++ * old math state array, and gets the new ones from the current task
++ *
++ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
++ * Don't touch unless you *really* know how it works.
++ */
++asmlinkage void math_state_restore(void)
++{
++ struct task_struct *me = current;
++ /* clts(); */ /* 'clts' is done for us by Xen during virtual trap. */
++
++ if (!used_math())
++ init_fpu(me);
++ restore_fpu_checking(&me->thread.i387.fxsave);
++ task_thread_info(me)->status |= TS_USEDFPU;
++}
++
++
++/*
++ * NB. All these are "interrupt gates" (i.e. events_mask is set) because we
++ * specify <dpl>|4 in the second field.
++ */
++static trap_info_t trap_table[] = {
++ { 0, 0|4, __KERNEL_CS, (unsigned long)divide_error },
++ { 1, 0|4, __KERNEL_CS, (unsigned long)debug },
++ { 3, 3|4, __KERNEL_CS, (unsigned long)int3 },
++ { 4, 3|4, __KERNEL_CS, (unsigned long)overflow },
++ { 5, 0|4, __KERNEL_CS, (unsigned long)bounds },
++ { 6, 0|4, __KERNEL_CS, (unsigned long)invalid_op },
++ { 7, 0|4, __KERNEL_CS, (unsigned long)device_not_available },
++ { 9, 0|4, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun},
++ { 10, 0|4, __KERNEL_CS, (unsigned long)invalid_TSS },
++ { 11, 0|4, __KERNEL_CS, (unsigned long)segment_not_present },
++ { 12, 0|4, __KERNEL_CS, (unsigned long)stack_segment },
++ { 13, 0|4, __KERNEL_CS, (unsigned long)general_protection },
++ { 14, 0|4, __KERNEL_CS, (unsigned long)page_fault },
++ { 15, 0|4, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
++ { 16, 0|4, __KERNEL_CS, (unsigned long)coprocessor_error },
++ { 17, 0|4, __KERNEL_CS, (unsigned long)alignment_check },
++#ifdef CONFIG_X86_MCE
++ { 18, 0|4, __KERNEL_CS, (unsigned long)machine_check },
++#endif
++ { 19, 0|4, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
++#ifdef CONFIG_IA32_EMULATION
++ { IA32_SYSCALL_VECTOR, 3|4, __KERNEL_CS, (unsigned long)ia32_syscall},
++#endif
++ { 0, 0, 0, 0 }
++};
++
++void __init trap_init(void)
++{
++ int ret;
++
++ ret = HYPERVISOR_set_trap_table(trap_table);
++
++ if (ret)
++ printk("HYPERVISOR_set_trap_table faild: error %d\n",
++ ret);
++
++ /*
++ * Should be a barrier for any external CPU state.
++ */
++ cpu_init();
++}
++
++void smp_trap_init(trap_info_t *trap_ctxt)
++{
++ trap_info_t *t = trap_table;
++
++ for (t = trap_table; t->address; t++) {
++ trap_ctxt[t->vector].flags = t->flags;
++ trap_ctxt[t->vector].cs = t->cs;
++ trap_ctxt[t->vector].address = t->address;
++ }
++}
++
++
++/* Actual parsing is done early in setup.c. */
++static int __init oops_dummy(char *s)
++{
++ panic_on_oops = 1;
++ return 1;
++}
++__setup("oops=", oops_dummy);
++
++static int __init kstack_setup(char *s)
++{
++ kstack_depth_to_print = simple_strtoul(s,NULL,0);
++ return 1;
++}
++__setup("kstack=", kstack_setup);
++
++#ifdef CONFIG_STACK_UNWIND
++static int __init call_trace_setup(char *s)
++{
++ if (strcmp(s, "old") == 0)
++ call_trace = -1;
++ else if (strcmp(s, "both") == 0)
++ call_trace = 0;
++ else if (strcmp(s, "newfallback") == 0)
++ call_trace = 1;
++ else if (strcmp(s, "new") == 0)
++ call_trace = 2;
++ return 1;
++}
++__setup("call_trace=", call_trace_setup);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/vmlinux.lds.S linux-2.6.18-xen/arch/x86_64/kernel/vmlinux.lds.S
+--- linux-2.6.18.1/arch/x86_64/kernel/vmlinux.lds.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/kernel/vmlinux.lds.S 2006-09-21 01:33:31.000000000 +0200
+@@ -13,6 +13,12 @@
+ OUTPUT_ARCH(i386:x86-64)
+ ENTRY(phys_startup_64)
+ jiffies_64 = jiffies;
++PHDRS {
++ text PT_LOAD FLAGS(5); /* R_E */
++ data PT_LOAD FLAGS(7); /* RWE */
++ user PT_LOAD FLAGS(7); /* RWE */
++ note PT_NOTE FLAGS(4); /* R__ */
++}
+ SECTIONS
+ {
+ . = __START_KERNEL;
+@@ -31,7 +37,7 @@
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+- } = 0x9090
++ } :text = 0x9090
+ /* out-of-line lock text */
+ .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
+
+@@ -57,17 +63,10 @@
+ .data : AT(ADDR(.data) - LOAD_OFFSET) {
+ *(.data)
+ CONSTRUCTORS
+- }
++ } :data
+
+ _edata = .; /* End of data section */
+
+- __bss_start = .; /* BSS */
+- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+- *(.bss.page_aligned)
+- *(.bss)
+- }
+- __bss_stop = .;
+-
+ . = ALIGN(PAGE_SIZE);
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+@@ -89,7 +88,7 @@
+ #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+
+ . = VSYSCALL_ADDR;
+- .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) }
++ .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user
+ __vsyscall_0 = VSYSCALL_VIRT_ADDR;
+
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+@@ -132,7 +131,7 @@
+ . = ALIGN(8192); /* init_task */
+ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+ *(.data.init_task)
+- }
++ } :data
+
+ . = ALIGN(4096);
+ .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+@@ -222,6 +221,14 @@
+ . = ALIGN(4096);
+ __nosave_end = .;
+
++ __bss_start = .; /* BSS */
++ . = ALIGN(4096);
++ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
++ *(.bss.page_aligned)
++ *(.bss)
++ }
++ __bss_stop = .;
++
+ _end = . ;
+
+ /* Sections to be discarded */
+@@ -235,4 +242,6 @@
+ STABS_DEBUG
+
+ DWARF_DEBUG
++
++ NOTES
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/vsyscall-xen.c linux-2.6.18-xen/arch/x86_64/kernel/vsyscall-xen.c
+--- linux-2.6.18.1/arch/x86_64/kernel/vsyscall-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/vsyscall-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,239 @@
++/*
++ * linux/arch/x86_64/kernel/vsyscall.c
++ *
++ * Copyright (C) 2001 Andrea Arcangeli <andrea at suse.de> SuSE
++ * Copyright 2003 Andi Kleen, SuSE Labs.
++ *
++ * Thanks to hpa at transmeta.com for some useful hint.
++ * Special thanks to Ingo Molnar for his early experience with
++ * a different vsyscall implementation for Linux/IA32 and for the name.
++ *
++ * vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
++ * at virtual address -10Mbyte+1024bytes etc... There are at max 4
++ * vsyscalls. One vsyscall can reserve more than 1 slot to avoid
++ * jumping out of line if necessary. We cannot add more with this
++ * mechanism because older kernels won't return -ENOSYS.
++ * If we want more than four we need a vDSO.
++ *
++ * Note: the concept clashes with user mode linux. If you use UML and
++ * want per guest time just set the kernel.vsyscall64 sysctl to 0.
++ */
++
++#include <linux/time.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/timer.h>
++#include <linux/seqlock.h>
++#include <linux/jiffies.h>
++#include <linux/sysctl.h>
++
++#include <asm/vsyscall.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/fixmap.h>
++#include <asm/errno.h>
++#include <asm/io.h>
++
++#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
++
++int __sysctl_vsyscall __section_sysctl_vsyscall = 1;
++seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED;
++
++#include <asm/unistd.h>
++
++static __always_inline void timeval_normalize(struct timeval * tv)
++{
++ time_t __sec;
++
++ __sec = tv->tv_usec / 1000000;
++ if (__sec) {
++ tv->tv_usec %= 1000000;
++ tv->tv_sec += __sec;
++ }
++}
++
++static __always_inline void do_vgettimeofday(struct timeval * tv)
++{
++ long sequence, t;
++ unsigned long sec, usec;
++
++ do {
++ sequence = read_seqbegin(&__xtime_lock);
++
++ sec = __xtime.tv_sec;
++ usec = (__xtime.tv_nsec / 1000) +
++ (__jiffies - __wall_jiffies) * (1000000 / HZ);
++
++ if (__vxtime.mode != VXTIME_HPET) {
++ t = get_cycles_sync();
++ if (t < __vxtime.last_tsc)
++ t = __vxtime.last_tsc;
++ usec += ((t - __vxtime.last_tsc) *
++ __vxtime.tsc_quot) >> 32;
++ /* See comment in x86_64 do_gettimeofday. */
++ } else {
++ usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) -
++ __vxtime.last) * __vxtime.quot) >> 32;
++ }
++ } while (read_seqretry(&__xtime_lock, sequence));
++
++ tv->tv_sec = sec + usec / 1000000;
++ tv->tv_usec = usec % 1000000;
++}
++
++/* RED-PEN may want to readd seq locking, but then the variable should be write-once. */
++static __always_inline void do_get_tz(struct timezone * tz)
++{
++ *tz = __sys_tz;
++}
++
++static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
++{
++ int ret;
++ asm volatile("vsysc2: syscall"
++ : "=a" (ret)
++ : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber );
++ return ret;
++}
++
++static __always_inline long time_syscall(long *t)
++{
++ long secs;
++ asm volatile("vsysc1: syscall"
++ : "=a" (secs)
++ : "0" (__NR_time),"D" (t) : __syscall_clobber);
++ return secs;
++}
++
++int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
++{
++ if (!__sysctl_vsyscall)
++ return gettimeofday(tv,tz);
++ if (tv)
++ do_vgettimeofday(tv);
++ if (tz)
++ do_get_tz(tz);
++ return 0;
++}
++
++/* This will break when the xtime seconds get inaccurate, but that is
++ * unlikely */
++time_t __vsyscall(1) vtime(time_t *t)
++{
++ if (!__sysctl_vsyscall)
++ return time_syscall(t);
++ else if (t)
++ *t = __xtime.tv_sec;
++ return __xtime.tv_sec;
++}
++
++long __vsyscall(2) venosys_0(void)
++{
++ return -ENOSYS;
++}
++
++long __vsyscall(3) venosys_1(void)
++{
++ return -ENOSYS;
++}
++
++#ifdef CONFIG_SYSCTL
++
++#define SYSCALL 0x050f
++#define NOP2 0x9090
++
++/*
++ * NOP out syscall in vsyscall page when not needed.
++ */
++static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ extern u16 vsysc1, vsysc2;
++ u16 *map1, *map2;
++ int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
++ if (!write)
++ return ret;
++ /* gcc has some trouble with __va(__pa()), so just do it this
++ way. */
++ map1 = ioremap(__pa_symbol(&vsysc1), 2);
++ if (!map1)
++ return -ENOMEM;
++ map2 = ioremap(__pa_symbol(&vsysc2), 2);
++ if (!map2) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ if (!sysctl_vsyscall) {
++ *map1 = SYSCALL;
++ *map2 = SYSCALL;
++ } else {
++ *map1 = NOP2;
++ *map2 = NOP2;
++ }
++ iounmap(map2);
++out:
++ iounmap(map1);
++ return ret;
++}
++
++static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen,
++ void __user *oldval, size_t __user *oldlenp,
++ void __user *newval, size_t newlen,
++ void **context)
++{
++ return -ENOSYS;
++}
++
++static ctl_table kernel_table2[] = {
++ { .ctl_name = 99, .procname = "vsyscall64",
++ .data = &sysctl_vsyscall, .maxlen = sizeof(int), .mode = 0644,
++ .strategy = vsyscall_sysctl_nostrat,
++ .proc_handler = vsyscall_sysctl_change },
++ { 0, }
++};
++
++static ctl_table kernel_root_table2[] = {
++ { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555,
++ .child = kernel_table2 },
++ { 0 },
++};
++
++#endif
++
++static void __init map_vsyscall(void)
++{
++ extern char __vsyscall_0;
++ unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
++
++ __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
++}
++
++#ifdef CONFIG_XEN
++static void __init map_vsyscall_user(void)
++{
++ extern void __set_fixmap_user(enum fixed_addresses, unsigned long, pgprot_t);
++ extern char __vsyscall_0;
++ unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
++
++ __set_fixmap_user(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
++}
++#endif
++
++static int __init vsyscall_init(void)
++{
++ BUG_ON(((unsigned long) &vgettimeofday !=
++ VSYSCALL_ADDR(__NR_vgettimeofday)));
++ BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
++ BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
++ map_vsyscall();
++#ifdef CONFIG_XEN
++ map_vsyscall_user();
++ sysctl_vsyscall = 0; /* disable vgettimeofay() */
++#endif
++#ifdef CONFIG_SYSCTL
++ register_sysctl_table(kernel_root_table2, 0);
++#endif
++ return 0;
++}
++
++__initcall(vsyscall_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/kernel/xen_entry.S linux-2.6.18-xen/arch/x86_64/kernel/xen_entry.S
+--- linux-2.6.18.1/arch/x86_64/kernel/xen_entry.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/kernel/xen_entry.S 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,40 @@
++/*
++ * Copied from arch/xen/i386/kernel/entry.S
++ */
++/* Offsets into shared_info_t. */
++#define evtchn_upcall_pending /* 0 */
++#define evtchn_upcall_mask 1
++
++#define sizeof_vcpu_shift 6
++
++#ifdef CONFIG_SMP
++//#define preempt_disable(reg) incl threadinfo_preempt_count(reg)
++//#define preempt_enable(reg) decl threadinfo_preempt_count(reg)
++#define preempt_disable(reg)
++#define preempt_enable(reg)
++#define XEN_GET_VCPU_INFO(reg) preempt_disable(%rbp) ; \
++ movq %gs:pda_cpunumber,reg ; \
++ shl $32, reg ; \
++ shr $32-sizeof_vcpu_shift,reg ; \
++ addq HYPERVISOR_shared_info,reg
++#define XEN_PUT_VCPU_INFO(reg) preempt_enable(%rbp) ; \
++#define XEN_PUT_VCPU_INFO_fixup .byte 0xff,0xff,0xff
++#else
++#define XEN_GET_VCPU_INFO(reg) movq HYPERVISOR_shared_info,reg
++#define XEN_PUT_VCPU_INFO(reg)
++#define XEN_PUT_VCPU_INFO_fixup
++#endif
++
++#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg)
++#define XEN_LOCKED_UNBLOCK_EVENTS(reg) movb $0,evtchn_upcall_mask(reg)
++#define XEN_BLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \
++ XEN_LOCKED_BLOCK_EVENTS(reg) ; \
++ XEN_PUT_VCPU_INFO(reg)
++#define XEN_UNBLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \
++ XEN_LOCKED_UNBLOCK_EVENTS(reg) ; \
++ XEN_PUT_VCPU_INFO(reg)
++#define XEN_TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg)
++
++VGCF_IN_SYSCALL = (1<<8)
++
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/Makefile linux-2.6.18-xen/arch/x86_64/Makefile
+--- linux-2.6.18.1/arch/x86_64/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/Makefile 2006-09-04 16:31:02.000000000 +0200
+@@ -32,6 +32,10 @@
+ cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
+ cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
+
++cppflags-$(CONFIG_XEN) += \
++ -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION)
++CPPFLAGS += $(cppflags-y)
++
+ cflags-y += -m64
+ cflags-y += -mno-red-zone
+ cflags-y += -mcmodel=kernel
+@@ -74,6 +78,21 @@
+ PHONY += bzImage bzlilo install archmrproper \
+ fdimage fdimage144 fdimage288 isoimage archclean
+
++ifdef CONFIG_XEN
++CPPFLAGS := -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
++head-y := arch/x86_64/kernel/head-xen.o arch/x86_64/kernel/head64-xen.o arch/x86_64/kernel/init_task.o
++LDFLAGS_vmlinux := -e _start
++boot := arch/i386/boot-xen
++.PHONY: vmlinuz
++#Default target when executing "make"
++all: vmlinuz
++
++vmlinuz: vmlinux
++ $(Q)$(MAKE) $(build)=$(boot) $@
++
++install:
++ $(Q)$(MAKE) $(build)=$(boot) XENGUEST=$(XENGUEST) $@
++else
+ #Default target when executing "make"
+ all: bzImage
+
+@@ -94,6 +113,7 @@
+
+ install:
+ $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
++endif
+
+ archclean:
+ $(Q)$(MAKE) $(clean)=$(boot)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/mm/fault-xen.c linux-2.6.18-xen/arch/x86_64/mm/fault-xen.c
+--- linux-2.6.18.1/arch/x86_64/mm/fault-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/mm/fault-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,723 @@
++/*
++ * linux/arch/x86-64/mm/fault.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs.
++ */
++
++#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/mman.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/tty.h>
++#include <linux/vt_kern.h> /* For unblank_screen() */
++#include <linux/compiler.h>
++#include <linux/module.h>
++#include <linux/kprobes.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/pgalloc.h>
++#include <asm/smp.h>
++#include <asm/tlbflush.h>
++#include <asm/proto.h>
++#include <asm/kdebug.h>
++#include <asm-generic/sections.h>
++
++/* Page fault error code bits */
++#define PF_PROT (1<<0) /* or no page found */
++#define PF_WRITE (1<<1)
++#define PF_USER (1<<2)
++#define PF_RSVD (1<<3)
++#define PF_INSTR (1<<4)
++
++#ifdef CONFIG_KPROBES
++ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
++
++/* Hook to register for page fault notifications */
++int register_page_fault_notifier(struct notifier_block *nb)
++{
++ vmalloc_sync_all();
++ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
++}
++
++int unregister_page_fault_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
++}
++
++static inline int notify_page_fault(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ struct die_args args = {
++ .regs = regs,
++ .str = str,
++ .err = err,
++ .trapnr = trap,
++ .signr = sig
++ };
++ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
++}
++#else
++static inline int notify_page_fault(enum die_val val, const char *str,
++ struct pt_regs *regs, long err, int trap, int sig)
++{
++ return NOTIFY_DONE;
++}
++#endif
++
++void bust_spinlocks(int yes)
++{
++ int loglevel_save = console_loglevel;
++ if (yes) {
++ oops_in_progress = 1;
++ } else {
++#ifdef CONFIG_VT
++ unblank_screen();
++#endif
++ oops_in_progress = 0;
++ /*
++ * OK, the message is on the console. Now we call printk()
++ * without oops_in_progress set so that printk will give klogd
++ * a poke. Hold onto your hats...
++ */
++ console_loglevel = 15; /* NMI oopser may have shut the console up */
++ printk(" ");
++ console_loglevel = loglevel_save;
++ }
++}
++
++/* Sometimes the CPU reports invalid exceptions on prefetch.
++ Check that here and ignore.
++ Opcode checker based on code by Richard Brunner */
++static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr,
++ unsigned long error_code)
++{
++ unsigned char *instr;
++ int scan_more = 1;
++ int prefetch = 0;
++ unsigned char *max_instr;
++
++ /* If it was a exec fault ignore */
++ if (error_code & PF_INSTR)
++ return 0;
++
++ instr = (unsigned char *)convert_rip_to_linear(current, regs);
++ max_instr = instr + 15;
++
++ if (user_mode(regs) && instr >= (unsigned char *)TASK_SIZE)
++ return 0;
++
++ while (scan_more && instr < max_instr) {
++ unsigned char opcode;
++ unsigned char instr_hi;
++ unsigned char instr_lo;
++
++ if (__get_user(opcode, instr))
++ break;
++
++ instr_hi = opcode & 0xf0;
++ instr_lo = opcode & 0x0f;
++ instr++;
++
++ switch (instr_hi) {
++ case 0x20:
++ case 0x30:
++ /* Values 0x26,0x2E,0x36,0x3E are valid x86
++ prefixes. In long mode, the CPU will signal
++ invalid opcode if some of these prefixes are
++ present so we will never get here anyway */
++ scan_more = ((instr_lo & 7) == 0x6);
++ break;
++
++ case 0x40:
++ /* In AMD64 long mode, 0x40 to 0x4F are valid REX prefixes
++ Need to figure out under what instruction mode the
++ instruction was issued ... */
++ /* Could check the LDT for lm, but for now it's good
++ enough to assume that long mode only uses well known
++ segments or kernel. */
++ scan_more = (!user_mode(regs)) || (regs->cs == __USER_CS);
++ break;
++
++ case 0x60:
++ /* 0x64 thru 0x67 are valid prefixes in all modes. */
++ scan_more = (instr_lo & 0xC) == 0x4;
++ break;
++ case 0xF0:
++ /* 0xF0, 0xF2, and 0xF3 are valid prefixes in all modes. */
++ scan_more = !instr_lo || (instr_lo>>1) == 1;
++ break;
++ case 0x00:
++ /* Prefetch instruction is 0x0F0D or 0x0F18 */
++ scan_more = 0;
++ if (__get_user(opcode, instr))
++ break;
++ prefetch = (instr_lo == 0xF) &&
++ (opcode == 0x0D || opcode == 0x18);
++ break;
++ default:
++ scan_more = 0;
++ break;
++ }
++ }
++ return prefetch;
++}
++
++static int bad_address(void *p)
++{
++ unsigned long dummy;
++ return __get_user(dummy, (unsigned long *)p);
++}
++
++void dump_pagetable(unsigned long address)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++
++ pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK);
++ pgd += pgd_index(address);
++ if (bad_address(pgd)) goto bad;
++ printk("PGD %lx ", pgd_val(*pgd));
++ if (!pgd_present(*pgd)) goto ret;
++
++ pud = pud_offset(pgd, address);
++ if (bad_address(pud)) goto bad;
++ printk("PUD %lx ", pud_val(*pud));
++ if (!pud_present(*pud)) goto ret;
++
++ pmd = pmd_offset(pud, address);
++ if (bad_address(pmd)) goto bad;
++ printk("PMD %lx ", pmd_val(*pmd));
++ if (!pmd_present(*pmd)) goto ret;
++
++ pte = pte_offset_kernel(pmd, address);
++ if (bad_address(pte)) goto bad;
++ printk("PTE %lx", pte_val(*pte));
++ret:
++ printk("\n");
++ return;
++bad:
++ printk("BAD\n");
++}
++
++static const char errata93_warning[] =
++KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n"
++KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n"
++KERN_ERR "******* Please consider a BIOS update.\n"
++KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n";
++
++/* Workaround for K8 erratum #93 & buggy BIOS.
++ BIOS SMM functions are required to use a specific workaround
++ to avoid corruption of the 64bit RIP register on C stepping K8.
++ A lot of BIOS that didn't get tested properly miss this.
++ The OS sees this as a page fault with the upper 32bits of RIP cleared.
++ Try to work around it here.
++ Note we only handle faults in kernel here. */
++
++static int is_errata93(struct pt_regs *regs, unsigned long address)
++{
++ static int warned;
++ if (address != regs->rip)
++ return 0;
++ if ((address >> 32) != 0)
++ return 0;
++ address |= 0xffffffffUL << 32;
++ if ((address >= (u64)_stext && address <= (u64)_etext) ||
++ (address >= MODULES_VADDR && address <= MODULES_END)) {
++ if (!warned) {
++ printk(errata93_warning);
++ warned = 1;
++ }
++ regs->rip = address;
++ return 1;
++ }
++ return 0;
++}
++
++int unhandled_signal(struct task_struct *tsk, int sig)
++{
++ if (tsk->pid == 1)
++ return 1;
++ if (tsk->ptrace & PT_PTRACED)
++ return 0;
++ return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
++ (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
++}
++
++static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
++ unsigned long error_code)
++{
++ unsigned long flags = oops_begin();
++ struct task_struct *tsk;
++
++ printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
++ current->comm, address);
++ dump_pagetable(address);
++ tsk = current;
++ tsk->thread.cr2 = address;
++ tsk->thread.trap_no = 14;
++ tsk->thread.error_code = error_code;
++ __die("Bad pagetable", regs, error_code);
++ oops_end(flags);
++ do_exit(SIGKILL);
++}
++
++/*
++ * Handle a fault on the vmalloc area
++ *
++ * This assumes no large pages in there.
++ */
++static int vmalloc_fault(unsigned long address)
++{
++ pgd_t *pgd, *pgd_ref;
++ pud_t *pud, *pud_ref;
++ pmd_t *pmd, *pmd_ref;
++ pte_t *pte, *pte_ref;
++
++ /* Copy kernel mappings over when needed. This can also
++ happen within a race in page table update. In the later
++ case just flush. */
++
++ /* On Xen the line below does not always work. Needs investigating! */
++ /*pgd = pgd_offset(current->mm ?: &init_mm, address);*/
++ pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK);
++ pgd += pgd_index(address);
++ pgd_ref = pgd_offset_k(address);
++ if (pgd_none(*pgd_ref))
++ return -1;
++ if (pgd_none(*pgd))
++ set_pgd(pgd, *pgd_ref);
++ else
++ BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref));
++
++ /* Below here mismatches are bugs because these lower tables
++ are shared */
++
++ pud = pud_offset(pgd, address);
++ pud_ref = pud_offset(pgd_ref, address);
++ if (pud_none(*pud_ref))
++ return -1;
++ if (pud_none(*pud) || pud_page(*pud) != pud_page(*pud_ref))
++ BUG();
++ pmd = pmd_offset(pud, address);
++ pmd_ref = pmd_offset(pud_ref, address);
++ if (pmd_none(*pmd_ref))
++ return -1;
++ if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref))
++ BUG();
++ pte_ref = pte_offset_kernel(pmd_ref, address);
++ if (!pte_present(*pte_ref))
++ return -1;
++ pte = pte_offset_kernel(pmd, address);
++ /* Don't use pte_page here, because the mappings can point
++ outside mem_map, and the NUMA hash lookup cannot handle
++ that. */
++ if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref))
++ BUG();
++ return 0;
++}
++
++int page_fault_trace = 0;
++int exception_trace = 1;
++
++
++#define MEM_VERBOSE 1
++
++#ifdef MEM_VERBOSE
++#define MEM_LOG(_f, _a...) \
++ printk("fault.c:[%d]-> " _f "\n", \
++ __LINE__ , ## _a )
++#else
++#define MEM_LOG(_f, _a...) ((void)0)
++#endif
++
++static int spurious_fault(struct pt_regs *regs,
++ unsigned long address,
++ unsigned long error_code)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++
++#ifdef CONFIG_XEN
++ /* Faults in hypervisor area are never spurious. */
++ if ((address >= HYPERVISOR_VIRT_START) &&
++ (address < HYPERVISOR_VIRT_END))
++ return 0;
++#endif
++
++ /* Reserved-bit violation or user access to kernel space? */
++ if (error_code & (PF_RSVD|PF_USER))
++ return 0;
++
++ pgd = init_mm.pgd + pgd_index(address);
++ if (!pgd_present(*pgd))
++ return 0;
++
++ pud = pud_offset(pgd, address);
++ if (!pud_present(*pud))
++ return 0;
++
++ pmd = pmd_offset(pud, address);
++ if (!pmd_present(*pmd))
++ return 0;
++
++ pte = pte_offset_kernel(pmd, address);
++ if (!pte_present(*pte))
++ return 0;
++ if ((error_code & PF_WRITE) && !pte_write(*pte))
++ return 0;
++ if ((error_code & PF_INSTR) && (pte_val(*pte) & _PAGE_NX))
++ return 0;
++
++ return 1;
++}
++
++/*
++ * This routine handles page faults. It determines the address,
++ * and the problem, and then passes it off to one of the appropriate
++ * routines.
++ */
++asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
++ unsigned long error_code)
++{
++ struct task_struct *tsk;
++ struct mm_struct *mm;
++ struct vm_area_struct * vma;
++ unsigned long address;
++ const struct exception_table_entry *fixup;
++ int write;
++ unsigned long flags;
++ siginfo_t info;
++
++ if (!user_mode(regs))
++ error_code &= ~PF_USER; /* means kernel */
++
++ tsk = current;
++ mm = tsk->mm;
++ prefetchw(&mm->mmap_sem);
++
++ /* get the address */
++ address = HYPERVISOR_shared_info->vcpu_info[
++ smp_processor_id()].arch.cr2;
++
++ info.si_code = SEGV_MAPERR;
++
++
++ /*
++ * We fault-in kernel-space virtual memory on-demand. The
++ * 'reference' page table is init_mm.pgd.
++ *
++ * NOTE! We MUST NOT take any locks for this case. We may
++ * be in an interrupt or a critical region, and should
++ * only copy the information from the master page table,
++ * nothing more.
++ *
++ * This verifies that the fault happens in kernel space
++ * (error_code & 4) == 0, and that the fault was not a
++ * protection error (error_code & 9) == 0.
++ */
++ if (unlikely(address >= TASK_SIZE64)) {
++ /*
++ * Don't check for the module range here: its PML4
++ * is always initialized because it's shared with the main
++ * kernel text. Only vmalloc may need PML4 syncups.
++ */
++ if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
++ ((address >= VMALLOC_START && address < VMALLOC_END))) {
++ if (vmalloc_fault(address) >= 0)
++ return;
++ }
++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
++ SIGSEGV) == NOTIFY_STOP)
++ return;
++ /* Can take a spurious fault if mapping changes R/O -> R/W. */
++ if (spurious_fault(regs, address, error_code))
++ return;
++ /*
++ * Don't take the mm semaphore here. If we fixup a prefetch
++ * fault we could otherwise deadlock.
++ */
++ goto bad_area_nosemaphore;
++ }
++
++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
++ SIGSEGV) == NOTIFY_STOP)
++ return;
++
++ if (likely(regs->eflags & X86_EFLAGS_IF))
++ local_irq_enable();
++
++ if (unlikely(page_fault_trace))
++ printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
++ regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code);
++
++ if (unlikely(error_code & PF_RSVD))
++ pgtable_bad(address, regs, error_code);
++
++ /*
++ * If we're in an interrupt or have no user
++ * context, we must not take the fault..
++ */
++ if (unlikely(in_atomic() || !mm))
++ goto bad_area_nosemaphore;
++
++ again:
++ /* When running in the kernel we expect faults to occur only to
++ * addresses in user space. All other faults represent errors in the
++ * kernel and should generate an OOPS. Unfortunatly, in the case of an
++ * erroneous fault occurring in a code path which already holds mmap_sem
++ * we will deadlock attempting to validate the fault against the
++ * address space. Luckily the kernel only validly references user
++ * space from well defined areas of code, which are listed in the
++ * exceptions table.
++ *
++ * As the vast majority of faults will be valid we will only perform
++ * the source reference check when there is a possibilty of a deadlock.
++ * Attempt to lock the address space, if we cannot we then validate the
++ * source. If this is invalid we can skip the address space check,
++ * thus avoiding the deadlock.
++ */
++ if (!down_read_trylock(&mm->mmap_sem)) {
++ if ((error_code & PF_USER) == 0 &&
++ !search_exception_tables(regs->rip))
++ goto bad_area_nosemaphore;
++ down_read(&mm->mmap_sem);
++ }
++
++ vma = find_vma(mm, address);
++ if (!vma)
++ goto bad_area;
++ if (likely(vma->vm_start <= address))
++ goto good_area;
++ if (!(vma->vm_flags & VM_GROWSDOWN))
++ goto bad_area;
++ if (error_code & 4) {
++ // XXX: align red zone size with ABI
++ if (address + 128 < regs->rsp)
++ 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;
++ write = 0;
++ switch (error_code & (PF_PROT|PF_WRITE)) {
++ default: /* 3: write, present */
++ /* fall through */
++ case PF_WRITE: /* write, not present */
++ if (!(vma->vm_flags & VM_WRITE))
++ goto bad_area;
++ write++;
++ break;
++ case PF_PROT: /* read, present */
++ goto bad_area;
++ case 0: /* read, not present */
++ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
++ 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.
++ */
++ switch (handle_mm_fault(mm, vma, address, write)) {
++ case VM_FAULT_MINOR:
++ tsk->min_flt++;
++ break;
++ case VM_FAULT_MAJOR:
++ tsk->maj_flt++;
++ break;
++ case VM_FAULT_SIGBUS:
++ goto do_sigbus;
++ default:
++ goto out_of_memory;
++ }
++
++ up_read(&mm->mmap_sem);
++ return;
++
++/*
++ * Something tried to access memory that isn't in our memory map..
++ * Fix it, but check if it's kernel or user first..
++ */
++bad_area:
++ up_read(&mm->mmap_sem);
++
++bad_area_nosemaphore:
++ /* User mode accesses just cause a SIGSEGV */
++ if (error_code & PF_USER) {
++ if (is_prefetch(regs, address, error_code))
++ return;
++
++ /* Work around K8 erratum #100 K8 in compat mode
++ occasionally jumps to illegal addresses >4GB. We
++ catch this here in the page fault handler because
++ these addresses are not reachable. Just detect this
++ case and return. Any code segment in LDT is
++ compatibility mode. */
++ if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) &&
++ (address >> 32))
++ return;
++
++ if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
++ printk(
++ "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
++ tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
++ tsk->comm, tsk->pid, address, regs->rip,
++ regs->rsp, error_code);
++ }
++
++ tsk->thread.cr2 = address;
++ /* Kernel addresses are always protection faults */
++ tsk->thread.error_code = error_code | (address >= TASK_SIZE);
++ tsk->thread.trap_no = 14;
++ info.si_signo = SIGSEGV;
++ info.si_errno = 0;
++ /* info.si_code has been set above */
++ info.si_addr = (void __user *)address;
++ force_sig_info(SIGSEGV, &info, tsk);
++ return;
++ }
++
++no_context:
++
++ /* Are we prepared to handle this kernel fault? */
++ fixup = search_exception_tables(regs->rip);
++ if (fixup) {
++ regs->rip = fixup->fixup;
++ return;
++ }
++
++ /*
++ * Hall of shame of CPU/BIOS bugs.
++ */
++
++ if (is_prefetch(regs, address, error_code))
++ return;
++
++ if (is_errata93(regs, address))
++ return;
++
++/*
++ * Oops. The kernel tried to access some bad page. We'll have to
++ * terminate things with extreme prejudice.
++ */
++
++ flags = oops_begin();
++
++ if (address < PAGE_SIZE)
++ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
++ else
++ printk(KERN_ALERT "Unable to handle kernel paging request");
++ printk(" at %016lx RIP: \n" KERN_ALERT,address);
++ printk_address(regs->rip);
++ dump_pagetable(address);
++ tsk->thread.cr2 = address;
++ tsk->thread.trap_no = 14;
++ tsk->thread.error_code = error_code;
++ __die("Oops", regs, error_code);
++ /* Executive summary in case the body of the oops scrolled away */
++ printk(KERN_EMERG "CR2: %016lx\n", address);
++ oops_end(flags);
++ do_exit(SIGKILL);
++
++/*
++ * We ran out of memory, or some other thing happened to us that made
++ * us unable to handle the page fault gracefully.
++ */
++out_of_memory:
++ up_read(&mm->mmap_sem);
++ if (current->pid == 1) {
++ yield();
++ goto again;
++ }
++ printk("VM: killing process %s\n", tsk->comm);
++ if (error_code & 4)
++ do_exit(SIGKILL);
++ goto no_context;
++
++do_sigbus:
++ up_read(&mm->mmap_sem);
++
++ /* Kernel mode? Handle exceptions or die */
++ if (!(error_code & PF_USER))
++ goto no_context;
++
++ tsk->thread.cr2 = address;
++ tsk->thread.error_code = error_code;
++ tsk->thread.trap_no = 14;
++ info.si_signo = SIGBUS;
++ info.si_errno = 0;
++ info.si_code = BUS_ADRERR;
++ info.si_addr = (void __user *)address;
++ force_sig_info(SIGBUS, &info, tsk);
++ return;
++}
++
++DEFINE_SPINLOCK(pgd_lock);
++struct page *pgd_list;
++
++void vmalloc_sync_all(void)
++{
++ /* Note that races in the updates of insync and start aren't
++ problematic:
++ insync can only get set bits added, and updates to start are only
++ improving performance (without affecting correctness if undone). */
++ static DECLARE_BITMAP(insync, PTRS_PER_PGD);
++ static unsigned long start = VMALLOC_START & PGDIR_MASK;
++ unsigned long address;
++
++ for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
++ if (!test_bit(pgd_index(address), insync)) {
++ const pgd_t *pgd_ref = pgd_offset_k(address);
++ struct page *page;
++
++ if (pgd_none(*pgd_ref))
++ continue;
++ spin_lock(&pgd_lock);
++ for (page = pgd_list; page;
++ page = (struct page *)page->index) {
++ pgd_t *pgd;
++ pgd = (pgd_t *)page_address(page) + pgd_index(address);
++ if (pgd_none(*pgd))
++ set_pgd(pgd, *pgd_ref);
++ else
++ BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref));
++ }
++ spin_unlock(&pgd_lock);
++ set_bit(pgd_index(address), insync);
++ }
++ if (address == start)
++ start = address + PGDIR_SIZE;
++ }
++ /* Check that there is no need to do the same for the modules area. */
++ BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL));
++ BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) ==
++ (__START_KERNEL & PGDIR_MASK)));
++}
++
++static int __init enable_pagefaulttrace(char *str)
++{
++ page_fault_trace = 1;
++ return 1;
++}
++__setup("pagefaulttrace", enable_pagefaulttrace);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/mm/init-xen.c linux-2.6.18-xen/arch/x86_64/mm/init-xen.c
+--- linux-2.6.18.1/arch/x86_64/mm/init-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/mm/init-xen.c 2006-09-04 16:31:03.000000000 +0200
+@@ -0,0 +1,1200 @@
++/*
++ * linux/arch/x86_64/mm/init.c
++ *
++ * Copyright (C) 1995 Linus Torvalds
++ * Copyright (C) 2000 Pavel Machek <pavel at suse.cz>
++ * Copyright (C) 2002,2003 Andi Kleen <ak at suse.de>
++ *
++ * Jun Nakajima <jun.nakajima at intel.com>
++ * Modified for Xen.
++ */
++
++#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/mman.h>
++#include <linux/mm.h>
++#include <linux/swap.h>
++#include <linux/smp.h>
++#include <linux/init.h>
++#include <linux/pagemap.h>
++#include <linux/bootmem.h>
++#include <linux/proc_fs.h>
++#include <linux/pci.h>
++#include <linux/poison.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/memory_hotplug.h>
++
++#include <asm/processor.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/dma.h>
++#include <asm/fixmap.h>
++#include <asm/e820.h>
++#include <asm/apic.h>
++#include <asm/tlb.h>
++#include <asm/mmu_context.h>
++#include <asm/proto.h>
++#include <asm/smp.h>
++#include <asm/sections.h>
++
++#include <xen/features.h>
++
++#ifndef Dprintk
++#define Dprintk(x...)
++#endif
++
++struct dma_mapping_ops* dma_ops;
++EXPORT_SYMBOL(dma_ops);
++
++extern unsigned long *contiguous_bitmap;
++
++static unsigned long dma_reserve __initdata;
++
++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
++extern unsigned long start_pfn;
++
++/*
++ * Use this until direct mapping is established, i.e. before __va() is
++ * available in init_memory_mapping().
++ */
++
++#define addr_to_page(addr, page) \
++ (addr) &= PHYSICAL_PAGE_MASK; \
++ (page) = ((unsigned long *) ((unsigned long) \
++ (((mfn_to_pfn((addr) >> PAGE_SHIFT)) << PAGE_SHIFT) + \
++ __START_KERNEL_map)))
++
++static void early_make_page_readonly(void *va, unsigned int feature)
++{
++ unsigned long addr, _va = (unsigned long)va;
++ pte_t pte, *ptep;
++ unsigned long *page = (unsigned long *) init_level4_pgt;
++
++ if (xen_feature(feature))
++ return;
++
++ addr = (unsigned long) page[pgd_index(_va)];
++ addr_to_page(addr, page);
++
++ addr = page[pud_index(_va)];
++ addr_to_page(addr, page);
++
++ addr = page[pmd_index(_va)];
++ addr_to_page(addr, page);
++
++ ptep = (pte_t *) &page[pte_index(_va)];
++
++ pte.pte = ptep->pte & ~_PAGE_RW;
++ if (HYPERVISOR_update_va_mapping(_va, pte, 0))
++ BUG();
++}
++
++void make_page_readonly(void *va, unsigned int feature)
++{
++ pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t pte, *ptep;
++ unsigned long addr = (unsigned long) va;
++
++ if (xen_feature(feature))
++ return;
++
++ pgd = pgd_offset_k(addr);
++ pud = pud_offset(pgd, addr);
++ pmd = pmd_offset(pud, addr);
++ ptep = pte_offset_kernel(pmd, addr);
++
++ pte.pte = ptep->pte & ~_PAGE_RW;
++ if (HYPERVISOR_update_va_mapping(addr, pte, 0))
++ xen_l1_entry_update(ptep, pte); /* fallback */
++
++ if ((addr >= VMALLOC_START) && (addr < VMALLOC_END))
++ make_page_readonly(__va(pte_pfn(pte) << PAGE_SHIFT), feature);
++}
++
++void make_page_writable(void *va, unsigned int feature)
++{
++ pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t pte, *ptep;
++ unsigned long addr = (unsigned long) va;
++
++ if (xen_feature(feature))
++ return;
++
++ pgd = pgd_offset_k(addr);
++ pud = pud_offset(pgd, addr);
++ pmd = pmd_offset(pud, addr);
++ ptep = pte_offset_kernel(pmd, addr);
++
++ pte.pte = ptep->pte | _PAGE_RW;
++ if (HYPERVISOR_update_va_mapping(addr, pte, 0))
++ xen_l1_entry_update(ptep, pte); /* fallback */
++
++ if ((addr >= VMALLOC_START) && (addr < VMALLOC_END))
++ make_page_writable(__va(pte_pfn(pte) << PAGE_SHIFT), feature);
++}
++
++void make_pages_readonly(void *va, unsigned nr, unsigned int feature)
++{
++ if (xen_feature(feature))
++ return;
++
++ while (nr-- != 0) {
++ make_page_readonly(va, feature);
++ va = (void*)((unsigned long)va + PAGE_SIZE);
++ }
++}
++
++void make_pages_writable(void *va, unsigned nr, unsigned int feature)
++{
++ if (xen_feature(feature))
++ return;
++
++ while (nr-- != 0) {
++ make_page_writable(va, feature);
++ va = (void*)((unsigned long)va + PAGE_SIZE);
++ }
++}
++
++/*
++ * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
++ * physical space so we can cache the place of the first one and move
++ * around without checking the pgd every time.
++ */
++
++void show_mem(void)
++{
++ long i, total = 0, reserved = 0;
++ long shared = 0, cached = 0;
++ pg_data_t *pgdat;
++ struct page *page;
++
++ printk(KERN_INFO "Mem-info:\n");
++ show_free_areas();
++ printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
++
++ for_each_online_pgdat(pgdat) {
++ for (i = 0; i < pgdat->node_spanned_pages; ++i) {
++ page = pfn_to_page(pgdat->node_start_pfn + i);
++ total++;
++ if (PageReserved(page))
++ reserved++;
++ else if (PageSwapCache(page))
++ cached++;
++ else if (page_count(page))
++ shared += page_count(page) - 1;
++ }
++ }
++ printk(KERN_INFO "%lu pages of RAM\n", total);
++ printk(KERN_INFO "%lu reserved pages\n",reserved);
++ printk(KERN_INFO "%lu pages shared\n",shared);
++ printk(KERN_INFO "%lu pages swap cached\n",cached);
++}
++
++int after_bootmem;
++
++static __init void *spp_getpage(void)
++{
++ void *ptr;
++ if (after_bootmem)
++ ptr = (void *) get_zeroed_page(GFP_ATOMIC);
++ else
++ ptr = alloc_bootmem_pages(PAGE_SIZE);
++ if (!ptr || ((unsigned long)ptr & ~PAGE_MASK))
++ panic("set_pte_phys: cannot allocate page data %s\n", after_bootmem?"after bootmem":"");
++
++ Dprintk("spp_getpage %p\n", ptr);
++ return ptr;
++}
++
++#define pgd_offset_u(address) (pgd_t *)(init_level4_user_pgt + pgd_index(address))
++
++static inline pud_t *pud_offset_u(unsigned long address)
++{
++ pud_t *pud = level3_user_pgt;
++
++ return pud + pud_index(address);
++}
++
++static __init void set_pte_phys(unsigned long vaddr,
++ unsigned long phys, pgprot_t prot, int user_mode)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte, new_pte;
++
++ Dprintk("set_pte_phys %lx to %lx\n", vaddr, phys);
++
++ pgd = (user_mode ? pgd_offset_u(vaddr) : pgd_offset_k(vaddr));
++ if (pgd_none(*pgd)) {
++ printk("PGD FIXMAP MISSING, it should be setup in head.S!\n");
++ return;
++ }
++ pud = (user_mode ? pud_offset_u(vaddr) : pud_offset(pgd, vaddr));
++ if (pud_none(*pud)) {
++ pmd = (pmd_t *) spp_getpage();
++ make_page_readonly(pmd, XENFEAT_writable_page_tables);
++ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
++ if (pmd != pmd_offset(pud, 0)) {
++ printk("PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud,0));
++ return;
++ }
++ }
++ pmd = pmd_offset(pud, vaddr);
++ if (pmd_none(*pmd)) {
++ pte = (pte_t *) spp_getpage();
++ make_page_readonly(pte, XENFEAT_writable_page_tables);
++ set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
++ if (pte != pte_offset_kernel(pmd, 0)) {
++ printk("PAGETABLE BUG #02!\n");
++ return;
++ }
++ }
++ new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
++
++ pte = pte_offset_kernel(pmd, vaddr);
++ if (!pte_none(*pte) &&
++ pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
++ pte_ERROR(*pte);
++ set_pte(pte, new_pte);
++
++ /*
++ * It's enough to flush this one mapping.
++ * (PGE mappings get flushed as well)
++ */
++ __flush_tlb_one(vaddr);
++}
++
++static void set_pte_phys_ma(unsigned long vaddr,
++ unsigned long phys, pgprot_t prot)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte, new_pte;
++
++ Dprintk("set_pte_phys %lx to %lx\n", vaddr, phys);
++
++ pgd = pgd_offset_k(vaddr);
++ if (pgd_none(*pgd)) {
++ printk("PGD FIXMAP MISSING, it should be setup in head.S!\n");
++ return;
++ }
++ pud = pud_offset(pgd, vaddr);
++ if (pud_none(*pud)) {
++
++ pmd = (pmd_t *) spp_getpage();
++ make_page_readonly(pmd, XENFEAT_writable_page_tables);
++
++ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
++
++ if (pmd != pmd_offset(pud, 0)) {
++ printk("PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud,0));
++ return;
++ }
++ }
++ pmd = pmd_offset(pud, vaddr);
++
++ if (pmd_none(*pmd)) {
++ pte = (pte_t *) spp_getpage();
++ make_page_readonly(pte, XENFEAT_writable_page_tables);
++
++ set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
++ if (pte != pte_offset_kernel(pmd, 0)) {
++ printk("PAGETABLE BUG #02!\n");
++ return;
++ }
++ }
++
++ new_pte = pfn_pte_ma(phys >> PAGE_SHIFT, prot);
++ pte = pte_offset_kernel(pmd, vaddr);
++
++ /*
++ * Note that the pte page is already RO, thus we want to use
++ * xen_l1_entry_update(), not set_pte().
++ */
++ xen_l1_entry_update(pte,
++ pfn_pte_ma(phys >> PAGE_SHIFT, prot));
++
++ /*
++ * It's enough to flush this one mapping.
++ * (PGE mappings get flushed as well)
++ */
++ __flush_tlb_one(vaddr);
++}
++
++#define SET_FIXMAP_KERNEL 0
++#define SET_FIXMAP_USER 1
++
++/* NOTE: this is meant to be run only at boot */
++void __init
++__set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
++{
++ unsigned long address = __fix_to_virt(idx);
++
++ if (idx >= __end_of_fixed_addresses) {
++ printk("Invalid __set_fixmap\n");
++ return;
++ }
++ switch (idx) {
++ case VSYSCALL_FIRST_PAGE:
++ set_pte_phys(address, phys, prot, SET_FIXMAP_KERNEL);
++ break;
++ default:
++ set_pte_phys_ma(address, phys, prot);
++ break;
++ }
++}
++
++/*
++ * At this point it only supports vsyscall area.
++ */
++void __set_fixmap_user (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
++{
++ unsigned long address = __fix_to_virt(idx);
++
++ if (idx >= __end_of_fixed_addresses) {
++ printk("Invalid __set_fixmap\n");
++ return;
++ }
++
++ set_pte_phys(address, phys, prot, SET_FIXMAP_USER);
++}
++
++unsigned long __initdata table_start, table_end;
++
++#ifndef CONFIG_XEN
++extern pmd_t temp_boot_pmds[];
++
++static struct temp_map {
++ pmd_t *pmd;
++ void *address;
++ int allocated;
++} temp_mappings[] __initdata = {
++ { &temp_boot_pmds[0], (void *)(40UL * 1024 * 1024) },
++ { &temp_boot_pmds[1], (void *)(42UL * 1024 * 1024) },
++ {}
++};
++#endif /* !CONFIG_XEN */
++
++unsigned long get_machine_pfn(unsigned long addr)
++{
++ pud_t* pud = pud_offset_k(NULL, addr);
++ pmd_t* pmd = pmd_offset(pud, addr);
++ pte_t *pte = pte_offset_kernel(pmd, addr);
++
++ return pte_mfn(*pte);
++}
++
++static __meminit void *alloc_static_page(unsigned long *phys)
++{
++ unsigned long va = (start_pfn << PAGE_SHIFT) + __START_KERNEL_map;
++
++ if (after_bootmem) {
++ void *adr = (void *)get_zeroed_page(GFP_ATOMIC);
++
++ *phys = __pa(adr);
++ return adr;
++ }
++
++ *phys = start_pfn << PAGE_SHIFT;
++ start_pfn++;
++ memset((void *)va, 0, PAGE_SIZE);
++ return (void *)va;
++}
++
++#define PTE_SIZE PAGE_SIZE
++
++static inline void __set_pte(pte_t *dst, pte_t val)
++{
++ *dst = val;
++}
++
++static inline int make_readonly(unsigned long paddr)
++{
++ int readonly = 0;
++
++ /* Make new page tables read-only. */
++ if (!xen_feature(XENFEAT_writable_page_tables)
++ && (paddr >= (table_start << PAGE_SHIFT))
++ && (paddr < (table_end << PAGE_SHIFT)))
++ readonly = 1;
++ /* Make old page tables read-only. */
++ if (!xen_feature(XENFEAT_writable_page_tables)
++ && (paddr >= (xen_start_info->pt_base - __START_KERNEL_map))
++ && (paddr < (start_pfn << PAGE_SHIFT)))
++ readonly = 1;
++
++ /*
++ * No need for writable mapping of kernel image. This also ensures that
++ * page and descriptor tables embedded inside don't have writable
++ * mappings.
++ */
++ if ((paddr >= __pa_symbol(&_text)) && (paddr < __pa_symbol(&_end)))
++ readonly = 1;
++
++ return readonly;
++}
++
++#ifndef CONFIG_XEN
++/* Must run before zap_low_mappings */
++__init void *early_ioremap(unsigned long addr, unsigned long size)
++{
++ unsigned long map = round_down(addr, LARGE_PAGE_SIZE);
++
++ /* actually usually some more */
++ if (size >= LARGE_PAGE_SIZE) {
++ printk("SMBIOS area too long %lu\n", size);
++ return NULL;
++ }
++ set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE));
++ map += LARGE_PAGE_SIZE;
++ set_pmd(temp_mappings[1].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE));
++ __flush_tlb();
++ return temp_mappings[0].address + (addr & (LARGE_PAGE_SIZE-1));
++}
++
++/* To avoid virtual aliases later */
++__init void early_iounmap(void *addr, unsigned long size)
++{
++ if ((void *)round_down((unsigned long)addr, LARGE_PAGE_SIZE) != temp_mappings[0].address)
++ printk("early_iounmap: bad address %p\n", addr);
++ set_pmd(temp_mappings[0].pmd, __pmd(0));
++ set_pmd(temp_mappings[1].pmd, __pmd(0));
++ __flush_tlb();
++}
++#endif /* !CONFIG_XEN */
++
++static void __meminit
++phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end)
++{
++ int i, k;
++
++ for (i = 0; i < PTRS_PER_PMD; pmd++, i++) {
++ unsigned long pte_phys;
++ pte_t *pte, *pte_save;
++
++ if (address >= end) {
++ if (!after_bootmem)
++ for (; i < PTRS_PER_PMD; i++, pmd++)
++ set_pmd(pmd, __pmd(0));
++ break;
++ }
++ pte = alloc_static_page(&pte_phys);
++ pte_save = pte;
++ for (k = 0; k < PTRS_PER_PTE; pte++, k++, address += PTE_SIZE) {
++ if ((address >= end) ||
++ ((address >> PAGE_SHIFT) >=
++ xen_start_info->nr_pages)) {
++ __set_pte(pte, __pte(0));
++ continue;
++ }
++ if (make_readonly(address)) {
++ __set_pte(pte,
++ __pte(address | (_KERNPG_TABLE & ~_PAGE_RW)));
++ continue;
++ }
++ __set_pte(pte, __pte(address | _KERNPG_TABLE));
++ }
++ pte = pte_save;
++ early_make_page_readonly(pte, XENFEAT_writable_page_tables);
++ set_pmd(pmd, __pmd(pte_phys | _KERNPG_TABLE));
++ }
++}
++
++static void __meminit
++phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end)
++{
++ pmd_t *pmd = pmd_offset(pud, (unsigned long)__va(address));
++
++ if (pmd_none(*pmd)) {
++ spin_lock(&init_mm.page_table_lock);
++ phys_pmd_init(pmd, address, end);
++ spin_unlock(&init_mm.page_table_lock);
++ __flush_tlb_all();
++ }
++}
++
++static void __meminit phys_pud_init(pud_t *pud, unsigned long address, unsigned long end)
++{
++ long i = pud_index(address);
++
++ pud = pud + i;
++
++ if (after_bootmem && pud_val(*pud)) {
++ phys_pmd_update(pud, address, end);
++ return;
++ }
++
++ for (; i < PTRS_PER_PUD; pud++, i++) {
++ unsigned long paddr, pmd_phys;
++ pmd_t *pmd;
++
++ paddr = (address & PGDIR_MASK) + i*PUD_SIZE;
++ if (paddr >= end)
++ break;
++
++ pmd = alloc_static_page(&pmd_phys);
++ early_make_page_readonly(pmd, XENFEAT_writable_page_tables);
++ spin_lock(&init_mm.page_table_lock);
++ set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
++ phys_pmd_init(pmd, paddr, end);
++ spin_unlock(&init_mm.page_table_lock);
++ }
++ __flush_tlb();
++}
++
++void __init xen_init_pt(void)
++{
++ unsigned long addr, *page;
++
++ memset((void *)init_level4_pgt, 0, PAGE_SIZE);
++ memset((void *)level3_kernel_pgt, 0, PAGE_SIZE);
++ memset((void *)level2_kernel_pgt, 0, PAGE_SIZE);
++
++ /* Find the initial pte page that was built for us. */
++ page = (unsigned long *)xen_start_info->pt_base;
++ addr = page[pgd_index(__START_KERNEL_map)];
++ addr_to_page(addr, page);
++ addr = page[pud_index(__START_KERNEL_map)];
++ addr_to_page(addr, page);
++
++ /* Construct mapping of initial pte page in our own directories. */
++ init_level4_pgt[pgd_index(__START_KERNEL_map)] =
++ mk_kernel_pgd(__pa_symbol(level3_kernel_pgt));
++ level3_kernel_pgt[pud_index(__START_KERNEL_map)] =
++ __pud(__pa_symbol(level2_kernel_pgt) |
++ _KERNPG_TABLE);
++ memcpy((void *)level2_kernel_pgt, page, PAGE_SIZE);
++
++ early_make_page_readonly(init_level4_pgt,
++ XENFEAT_writable_page_tables);
++ early_make_page_readonly(init_level4_user_pgt,
++ XENFEAT_writable_page_tables);
++ early_make_page_readonly(level3_kernel_pgt,
++ XENFEAT_writable_page_tables);
++ early_make_page_readonly(level3_user_pgt,
++ XENFEAT_writable_page_tables);
++ early_make_page_readonly(level2_kernel_pgt,
++ XENFEAT_writable_page_tables);
++
++ xen_pgd_pin(__pa_symbol(init_level4_pgt));
++ xen_pgd_pin(__pa_symbol(init_level4_user_pgt));
++
++ set_pgd((pgd_t *)(init_level4_user_pgt + 511),
++ mk_kernel_pgd(__pa_symbol(level3_user_pgt)));
++}
++
++void __init extend_init_mapping(unsigned long tables_space)
++{
++ unsigned long va = __START_KERNEL_map;
++ unsigned long phys, addr, *pte_page;
++ pmd_t *pmd;
++ pte_t *pte, new_pte;
++ unsigned long *page = (unsigned long *)init_level4_pgt;
++
++ addr = page[pgd_index(va)];
++ addr_to_page(addr, page);
++ addr = page[pud_index(va)];
++ addr_to_page(addr, page);
++
++ /* Kill mapping of low 1MB. */
++ while (va < (unsigned long)&_text) {
++ HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0);
++ va += PAGE_SIZE;
++ }
++
++ /* Ensure init mappings cover kernel text/data and initial tables. */
++ while (va < (__START_KERNEL_map
++ + (start_pfn << PAGE_SHIFT)
++ + tables_space)) {
++ pmd = (pmd_t *)&page[pmd_index(va)];
++ if (pmd_none(*pmd)) {
++ pte_page = alloc_static_page(&phys);
++ early_make_page_readonly(
++ pte_page, XENFEAT_writable_page_tables);
++ set_pmd(pmd, __pmd(phys | _KERNPG_TABLE));
++ } else {
++ addr = page[pmd_index(va)];
++ addr_to_page(addr, pte_page);
++ }
++ pte = (pte_t *)&pte_page[pte_index(va)];
++ if (pte_none(*pte)) {
++ new_pte = pfn_pte(
++ (va - __START_KERNEL_map) >> PAGE_SHIFT,
++ __pgprot(_KERNPG_TABLE));
++ xen_l1_entry_update(pte, new_pte);
++ }
++ va += PAGE_SIZE;
++ }
++
++ /* Finally, blow away any spurious initial mappings. */
++ while (1) {
++ pmd = (pmd_t *)&page[pmd_index(va)];
++ if (pmd_none(*pmd))
++ break;
++ HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0);
++ va += PAGE_SIZE;
++ }
++}
++
++static void __init find_early_table_space(unsigned long end)
++{
++ unsigned long puds, pmds, ptes, tables;
++
++ puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
++ pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
++ ptes = (end + PTE_SIZE - 1) >> PAGE_SHIFT;
++
++ tables = round_up(puds * 8, PAGE_SIZE) +
++ round_up(pmds * 8, PAGE_SIZE) +
++ round_up(ptes * 8, PAGE_SIZE);
++
++ extend_init_mapping(tables);
++
++ table_start = start_pfn;
++ table_end = table_start + (tables>>PAGE_SHIFT);
++
++ early_printk("kernel direct mapping tables up to %lx @ %lx-%lx\n",
++ end, table_start << PAGE_SHIFT,
++ (table_end << PAGE_SHIFT) + tables);
++}
++
++/* Setup the direct mapping of the physical memory at PAGE_OFFSET.
++ This runs before bootmem is initialized and gets pages directly from the
++ physical memory. To access them they are temporarily mapped. */
++void __meminit init_memory_mapping(unsigned long start, unsigned long end)
++{
++ unsigned long next;
++
++ Dprintk("init_memory_mapping\n");
++
++ /*
++ * Find space for the kernel direct mapping tables.
++ * Later we should allocate these tables in the local node of the memory
++ * mapped. Unfortunately this is done currently before the nodes are
++ * discovered.
++ */
++ if (!after_bootmem)
++ find_early_table_space(end);
++
++ start = (unsigned long)__va(start);
++ end = (unsigned long)__va(end);
++
++ for (; start < end; start = next) {
++ unsigned long pud_phys;
++ pgd_t *pgd = pgd_offset_k(start);
++ pud_t *pud;
++
++ if (after_bootmem) {
++ pud = pud_offset(pgd, start & PGDIR_MASK);
++ make_page_readonly(pud, XENFEAT_writable_page_tables);
++ pud_phys = __pa(pud);
++ } else {
++ pud = alloc_static_page(&pud_phys);
++ early_make_page_readonly(pud, XENFEAT_writable_page_tables);
++ }
++ next = start + PGDIR_SIZE;
++ if (next > end)
++ next = end;
++ phys_pud_init(pud, __pa(start), __pa(next));
++ if (!after_bootmem)
++ set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
++ }
++
++ if (!after_bootmem) {
++ BUG_ON(start_pfn != table_end);
++
++ /* Re-vector virtual addresses pointing into the initial
++ mapping to the just-established permanent ones. */
++ xen_start_info = __va(__pa(xen_start_info));
++ xen_start_info->pt_base = (unsigned long)
++ __va(__pa(xen_start_info->pt_base));
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ phys_to_machine_mapping =
++ __va(__pa(xen_start_info->mfn_list));
++ xen_start_info->mfn_list = (unsigned long)
++ phys_to_machine_mapping;
++ }
++ if (xen_start_info->mod_start)
++ xen_start_info->mod_start = (unsigned long)
++ __va(__pa(xen_start_info->mod_start));
++
++ /* Destroy the Xen-created mappings beyond the kernel image as
++ * well as the temporary mappings created above. Prevents
++ * overlap with modules area (if init mapping is very big).
++ */
++ start = PAGE_ALIGN((unsigned long)_end);
++ end = __START_KERNEL_map + (table_end << PAGE_SHIFT);
++ for (; start < end; start += PAGE_SIZE)
++ WARN_ON(HYPERVISOR_update_va_mapping(
++ start, __pte_ma(0), 0));
++ }
++
++ __flush_tlb_all();
++}
++
++void __cpuinit zap_low_mappings(int cpu)
++{
++ /* this is not required for Xen */
++#if 0
++ swap_low_mappings();
++#endif
++}
++
++/* Compute zone sizes for the DMA and DMA32 zones in a node. */
++__init void
++size_zones(unsigned long *z, unsigned long *h,
++ unsigned long start_pfn, unsigned long end_pfn)
++{
++ int i;
++#ifndef CONFIG_XEN
++ unsigned long w;
++#endif
++
++ for (i = 0; i < MAX_NR_ZONES; i++)
++ z[i] = 0;
++
++#ifndef CONFIG_XEN
++ if (start_pfn < MAX_DMA_PFN)
++ z[ZONE_DMA] = MAX_DMA_PFN - start_pfn;
++ if (start_pfn < MAX_DMA32_PFN) {
++ unsigned long dma32_pfn = MAX_DMA32_PFN;
++ if (dma32_pfn > end_pfn)
++ dma32_pfn = end_pfn;
++ z[ZONE_DMA32] = dma32_pfn - start_pfn;
++ }
++ z[ZONE_NORMAL] = end_pfn - start_pfn;
++
++ /* Remove lower zones from higher ones. */
++ w = 0;
++ for (i = 0; i < MAX_NR_ZONES; i++) {
++ if (z[i])
++ z[i] -= w;
++ w += z[i];
++ }
++
++ /* Compute holes */
++ w = start_pfn;
++ for (i = 0; i < MAX_NR_ZONES; i++) {
++ unsigned long s = w;
++ w += z[i];
++ h[i] = e820_hole_size(s, w);
++ }
++
++ /* Add the space pace needed for mem_map to the holes too. */
++ for (i = 0; i < MAX_NR_ZONES; i++)
++ h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE;
++
++ /* The 16MB DMA zone has the kernel and other misc mappings.
++ Account them too */
++ if (h[ZONE_DMA]) {
++ h[ZONE_DMA] += dma_reserve;
++ if (h[ZONE_DMA] >= z[ZONE_DMA]) {
++ printk(KERN_WARNING
++ "Kernel too large and filling up ZONE_DMA?\n");
++ h[ZONE_DMA] = z[ZONE_DMA];
++ }
++ }
++#else
++ z[ZONE_DMA] = end_pfn;
++ for (i = 0; i < MAX_NR_ZONES; i++)
++ h[i] = 0;
++#endif
++}
++
++#ifndef CONFIG_NUMA
++void __init paging_init(void)
++{
++ unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES];
++ int i;
++
++ memory_present(0, 0, end_pfn);
++ sparse_init();
++ size_zones(zones, holes, 0, end_pfn);
++ free_area_init_node(0, NODE_DATA(0), zones,
++ __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
++
++ /* Switch to the real shared_info page, and clear the
++ * dummy page. */
++ set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
++ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
++ memset(empty_zero_page, 0, sizeof(empty_zero_page));
++
++ init_mm.context.pinned = 1;
++
++ /* Setup mapping of lower 1st MB */
++ for (i = 0; i < NR_FIX_ISAMAPS; i++)
++ if (is_initial_xendomain())
++ set_fixmap(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE);
++ else
++ __set_fixmap(FIX_ISAMAP_BEGIN - i,
++ virt_to_mfn(empty_zero_page) << PAGE_SHIFT,
++ PAGE_KERNEL_RO);
++}
++#endif
++
++/* Unmap a kernel mapping if it exists. This is useful to avoid prefetches
++ from the CPU leading to inconsistent cache lines. address and size
++ must be aligned to 2MB boundaries.
++ Does nothing when the mapping doesn't exist. */
++void __init clear_kernel_mapping(unsigned long address, unsigned long size)
++{
++ unsigned long end = address + size;
++
++ BUG_ON(address & ~LARGE_PAGE_MASK);
++ BUG_ON(size & ~LARGE_PAGE_MASK);
++
++ for (; address < end; address += LARGE_PAGE_SIZE) {
++ pgd_t *pgd = pgd_offset_k(address);
++ pud_t *pud;
++ pmd_t *pmd;
++ if (pgd_none(*pgd))
++ continue;
++ pud = pud_offset(pgd, address);
++ if (pud_none(*pud))
++ continue;
++ pmd = pmd_offset(pud, address);
++ if (!pmd || pmd_none(*pmd))
++ continue;
++ if (0 == (pmd_val(*pmd) & _PAGE_PSE)) {
++ /* Could handle this, but it should not happen currently. */
++ printk(KERN_ERR
++ "clear_kernel_mapping: mapping has been split. will leak memory\n");
++ pmd_ERROR(*pmd);
++ }
++ set_pmd(pmd, __pmd(0));
++ }
++ __flush_tlb_all();
++}
++
++/*
++ * Memory hotplug specific functions
++ */
++
++void online_page(struct page *page)
++{
++ ClearPageReserved(page);
++ init_page_count(page);
++ __free_page(page);
++ totalram_pages++;
++ num_physpages++;
++}
++
++#ifdef CONFIG_MEMORY_HOTPLUG
++/*
++ * XXX: memory_add_physaddr_to_nid() is to find node id from physical address
++ * via probe interface of sysfs. If acpi notifies hot-add event, then it
++ * can tell node id by searching dsdt. But, probe interface doesn't have
++ * node id. So, return 0 as node id at this time.
++ */
++#ifdef CONFIG_NUMA
++int memory_add_physaddr_to_nid(u64 start)
++{
++ return 0;
++}
++#endif
++
++/*
++ * Memory is added always to NORMAL zone. This means you will never get
++ * additional DMA/DMA32 memory.
++ */
++int arch_add_memory(int nid, u64 start, u64 size)
++{
++ struct pglist_data *pgdat = NODE_DATA(nid);
++ struct zone *zone = pgdat->node_zones + MAX_NR_ZONES-2;
++ unsigned long start_pfn = start >> PAGE_SHIFT;
++ unsigned long nr_pages = size >> PAGE_SHIFT;
++ int ret;
++
++ ret = __add_pages(zone, start_pfn, nr_pages);
++ if (ret)
++ goto error;
++
++ init_memory_mapping(start, (start + size -1));
++
++ return ret;
++error:
++ printk("%s: Problem encountered in __add_pages!\n", __func__);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(arch_add_memory);
++
++int remove_memory(u64 start, u64 size)
++{
++ return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(remove_memory);
++
++#else /* CONFIG_MEMORY_HOTPLUG */
++/*
++ * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
++ * just online the pages.
++ */
++int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
++{
++ int err = -EIO;
++ unsigned long pfn;
++ unsigned long total = 0, mem = 0;
++ for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
++ if (pfn_valid(pfn)) {
++ online_page(pfn_to_page(pfn));
++ err = 0;
++ mem++;
++ }
++ total++;
++ }
++ if (!err) {
++ z->spanned_pages += total;
++ z->present_pages += mem;
++ z->zone_pgdat->node_spanned_pages += total;
++ z->zone_pgdat->node_present_pages += mem;
++ }
++ return err;
++}
++#endif /* CONFIG_MEMORY_HOTPLUG */
++
++static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
++ kcore_vsyscall;
++
++void __init mem_init(void)
++{
++ long codesize, reservedpages, datasize, initsize;
++ unsigned long pfn;
++
++ contiguous_bitmap = alloc_bootmem_low_pages(
++ (end_pfn + 2*BITS_PER_LONG) >> 3);
++ BUG_ON(!contiguous_bitmap);
++ memset(contiguous_bitmap, 0, (end_pfn + 2*BITS_PER_LONG) >> 3);
++
++ pci_iommu_alloc();
++
++ /* How many end-of-memory variables you have, grandma! */
++ max_low_pfn = end_pfn;
++ max_pfn = end_pfn;
++ num_physpages = end_pfn;
++ high_memory = (void *) __va(end_pfn * PAGE_SIZE);
++
++ /* clear the zero-page */
++ memset(empty_zero_page, 0, PAGE_SIZE);
++
++ reservedpages = 0;
++
++ /* this will put all low memory onto the freelists */
++#ifdef CONFIG_NUMA
++ totalram_pages = numa_free_all_bootmem();
++#else
++ totalram_pages = free_all_bootmem();
++#endif
++ /* XEN: init and count pages outside initial allocation. */
++ for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
++ ClearPageReserved(&mem_map[pfn]);
++ init_page_count(&mem_map[pfn]);
++ totalram_pages++;
++ }
++ reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
++
++ after_bootmem = 1;
++
++ codesize = (unsigned long) &_etext - (unsigned long) &_text;
++ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
++ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
++
++ /* Register memory areas for /proc/kcore */
++ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
++ kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
++ VMALLOC_END-VMALLOC_START);
++ kclist_add(&kcore_kernel, &_stext, _end - _stext);
++ kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN);
++ kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START,
++ VSYSCALL_END - VSYSCALL_START);
++
++ printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
++ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
++ end_pfn << (PAGE_SHIFT-10),
++ codesize >> 10,
++ reservedpages << (PAGE_SHIFT-10),
++ datasize >> 10,
++ initsize >> 10);
++
++#ifndef CONFIG_XEN
++#ifdef CONFIG_SMP
++ /*
++ * Sync boot_level4_pgt mappings with the init_level4_pgt
++ * except for the low identity mappings which are already zapped
++ * in init_level4_pgt. This sync-up is essential for AP's bringup
++ */
++ memcpy(boot_level4_pgt+1, init_level4_pgt+1, (PTRS_PER_PGD-1)*sizeof(pgd_t));
++#endif
++#endif
++}
++
++void free_init_pages(char *what, unsigned long begin, unsigned long end)
++{
++#ifdef __DO_LATER__
++ unsigned long addr;
++
++ if (begin >= end)
++ return;
++
++ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
++ for (addr = begin; addr < end; addr += PAGE_SIZE) {
++ ClearPageReserved(virt_to_page(addr));
++ init_page_count(virt_to_page(addr));
++ memset((void *)(addr & ~(PAGE_SIZE-1)),
++ POISON_FREE_INITMEM, PAGE_SIZE);
++ free_page(addr);
++ totalram_pages++;
++ }
++#endif
++}
++
++void free_initmem(void)
++{
++#ifdef __DO_LATER__
++ memset(__initdata_begin, POISON_FREE_INITDATA,
++ __initdata_end - __initdata_begin);
++ free_init_pages("unused kernel memory",
++ (unsigned long)(&__init_begin),
++ (unsigned long)(&__init_end));
++#endif
++}
++
++#ifdef CONFIG_DEBUG_RODATA
++
++void mark_rodata_ro(void)
++{
++ unsigned long addr = (unsigned long)__start_rodata;
++
++ for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE)
++ change_page_attr_addr(addr, 1, PAGE_KERNEL_RO);
++
++ printk ("Write protecting the kernel read-only data: %luk\n",
++ (__end_rodata - __start_rodata) >> 10);
++ /*
++ * change_page_attr_addr() requires a global_flush_tlb() call after it.
++ * We do this after the printk so that if something went wrong in the
++ * change, the printk gets out at least to give a better debug hint
++ * of who is the culprit.
++ */
++ global_flush_tlb();
++}
++#endif
++
++#ifdef CONFIG_BLK_DEV_INITRD
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++ free_init_pages("initrd memory", start, end);
++}
++#endif
++
++void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
++{
++ /* Should check here against the e820 map to avoid double free */
++#ifdef CONFIG_NUMA
++ int nid = phys_to_nid(phys);
++ reserve_bootmem_node(NODE_DATA(nid), phys, len);
++#else
++ reserve_bootmem(phys, len);
++#endif
++ if (phys+len <= MAX_DMA_PFN*PAGE_SIZE)
++ dma_reserve += len / PAGE_SIZE;
++}
++
++int kern_addr_valid(unsigned long addr)
++{
++ unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++
++ if (above != 0 && above != -1UL)
++ return 0;
++
++ pgd = pgd_offset_k(addr);
++ if (pgd_none(*pgd))
++ return 0;
++
++ pud = pud_offset_k(pgd, addr);
++ if (pud_none(*pud))
++ return 0;
++
++ pmd = pmd_offset(pud, addr);
++ if (pmd_none(*pmd))
++ return 0;
++ if (pmd_large(*pmd))
++ return pfn_valid(pmd_pfn(*pmd));
++
++ pte = pte_offset_kernel(pmd, addr);
++ if (pte_none(*pte))
++ return 0;
++ return pfn_valid(pte_pfn(*pte));
++}
++
++#ifdef CONFIG_SYSCTL
++#include <linux/sysctl.h>
++
++extern int exception_trace, page_fault_trace;
++
++static ctl_table debug_table2[] = {
++ { 99, "exception-trace", &exception_trace, sizeof(int), 0644, NULL,
++ proc_dointvec },
++ { 0, }
++};
++
++static ctl_table debug_root_table2[] = {
++ { .ctl_name = CTL_DEBUG, .procname = "debug", .mode = 0555,
++ .child = debug_table2 },
++ { 0 },
++};
++
++static __init int x8664_sysctl_init(void)
++{
++ register_sysctl_table(debug_root_table2, 1);
++ return 0;
++}
++__initcall(x8664_sysctl_init);
++#endif
++
++/* A pseudo VMAs to allow ptrace access for the vsyscall page. This only
++ covers the 64bit vsyscall page now. 32bit has a real VMA now and does
++ not need special handling anymore. */
++
++static struct vm_area_struct gate_vma = {
++ .vm_start = VSYSCALL_START,
++ .vm_end = VSYSCALL_END,
++ .vm_page_prot = PAGE_READONLY
++};
++
++struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
++{
++#ifdef CONFIG_IA32_EMULATION
++ if (test_tsk_thread_flag(tsk, TIF_IA32))
++ return NULL;
++#endif
++ return &gate_vma;
++}
++
++int in_gate_area(struct task_struct *task, unsigned long addr)
++{
++ struct vm_area_struct *vma = get_gate_vma(task);
++ if (!vma)
++ return 0;
++ return (addr >= vma->vm_start) && (addr < vma->vm_end);
++}
++
++/* Use this when you have no reliable task/vma, typically from interrupt
++ * context. It is less reliable than using the task's vma and may give
++ * false positives.
++ */
++int in_gate_area_no_task(unsigned long addr)
++{
++ return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/mm/Makefile linux-2.6.18-xen/arch/x86_64/mm/Makefile
+--- linux-2.6.18.1/arch/x86_64/mm/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/mm/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -9,3 +9,13 @@
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
+
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
++
++ifdef CONFIG_XEN
++include $(srctree)/scripts/Makefile.xen
++
++ioremap-y += ../../i386/mm/ioremap-xen.o
++hypervisor-y += ../../i386/mm/hypervisor.o
++obj-y += hypervisor.o
++
++obj-y := $(call cherrypickxen, $(obj-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/mm/pageattr-xen.c linux-2.6.18-xen/arch/x86_64/mm/pageattr-xen.c
+--- linux-2.6.18.1/arch/x86_64/mm/pageattr-xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/arch/x86_64/mm/pageattr-xen.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,398 @@
++/*
++ * Copyright 2002 Andi Kleen, SuSE Labs.
++ * Thanks to Ben LaHaise for precious feedback.
++ */
++
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/highmem.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++#include <asm/tlbflush.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_XEN
++#include <asm/pgalloc.h>
++#include <asm/mmu_context.h>
++
++LIST_HEAD(mm_unpinned);
++DEFINE_SPINLOCK(mm_unpinned_lock);
++
++static inline void mm_walk_set_prot(void *pt, pgprot_t flags)
++{
++ struct page *page = virt_to_page(pt);
++ unsigned long pfn = page_to_pfn(page);
++
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)__va(pfn << PAGE_SHIFT),
++ pfn_pte(pfn, flags), 0));
++}
++
++static void mm_walk(struct mm_struct *mm, pgprot_t flags)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ int g,u,m;
++
++ pgd = mm->pgd;
++ /*
++ * Cannot iterate up to USER_PTRS_PER_PGD as these pagetables may not
++ * be the 'current' task's pagetables (e.g., current may be 32-bit,
++ * but the pagetables may be for a 64-bit task).
++ * Subtracting 1 from TASK_SIZE64 means the loop limit is correct
++ * regardless of whether TASK_SIZE64 is a multiple of PGDIR_SIZE.
++ */
++ for (g = 0; g <= ((TASK_SIZE64-1) / PGDIR_SIZE); g++, pgd++) {
++ if (pgd_none(*pgd))
++ continue;
++ pud = pud_offset(pgd, 0);
++ if (PTRS_PER_PUD > 1) /* not folded */
++ mm_walk_set_prot(pud,flags);
++ for (u = 0; u < PTRS_PER_PUD; u++, pud++) {
++ if (pud_none(*pud))
++ continue;
++ pmd = pmd_offset(pud, 0);
++ if (PTRS_PER_PMD > 1) /* not folded */
++ mm_walk_set_prot(pmd,flags);
++ for (m = 0; m < PTRS_PER_PMD; m++, pmd++) {
++ if (pmd_none(*pmd))
++ continue;
++ pte = pte_offset_kernel(pmd,0);
++ mm_walk_set_prot(pte,flags);
++ }
++ }
++ }
++}
++
++void mm_pin(struct mm_struct *mm)
++{
++ if (xen_feature(XENFEAT_writable_page_tables))
++ return;
++
++ spin_lock(&mm->page_table_lock);
++
++ mm_walk(mm, PAGE_KERNEL_RO);
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)mm->pgd,
++ pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO),
++ UVMF_TLB_FLUSH));
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)__user_pgd(mm->pgd),
++ pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, PAGE_KERNEL_RO),
++ UVMF_TLB_FLUSH));
++ xen_pgd_pin(__pa(mm->pgd)); /* kernel */
++ xen_pgd_pin(__pa(__user_pgd(mm->pgd))); /* user */
++ mm->context.pinned = 1;
++ spin_lock(&mm_unpinned_lock);
++ list_del(&mm->context.unpinned);
++ spin_unlock(&mm_unpinned_lock);
++
++ spin_unlock(&mm->page_table_lock);
++}
++
++void mm_unpin(struct mm_struct *mm)
++{
++ if (xen_feature(XENFEAT_writable_page_tables))
++ return;
++
++ spin_lock(&mm->page_table_lock);
++
++ xen_pgd_unpin(__pa(mm->pgd));
++ xen_pgd_unpin(__pa(__user_pgd(mm->pgd)));
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)mm->pgd,
++ pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0));
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)__user_pgd(mm->pgd),
++ pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, PAGE_KERNEL), 0));
++ mm_walk(mm, PAGE_KERNEL);
++ xen_tlb_flush();
++ mm->context.pinned = 0;
++ spin_lock(&mm_unpinned_lock);
++ list_add(&mm->context.unpinned, &mm_unpinned);
++ spin_unlock(&mm_unpinned_lock);
++
++ spin_unlock(&mm->page_table_lock);
++}
++
++void mm_pin_all(void)
++{
++ if (xen_feature(XENFEAT_writable_page_tables))
++ return;
++
++ while (!list_empty(&mm_unpinned))
++ mm_pin(list_entry(mm_unpinned.next, struct mm_struct,
++ context.unpinned));
++}
++
++void _arch_dup_mmap(struct mm_struct *mm)
++{
++ if (!mm->context.pinned)
++ mm_pin(mm);
++}
++
++void _arch_exit_mmap(struct mm_struct *mm)
++{
++ struct task_struct *tsk = current;
++
++ task_lock(tsk);
++
++ /*
++ * We aggressively remove defunct pgd from cr3. We execute unmap_vmas()
++ * *much* faster this way, as no tlb flushes means bigger wrpt batches.
++ */
++ if ( tsk->active_mm == mm )
++ {
++ tsk->active_mm = &init_mm;
++ atomic_inc(&init_mm.mm_count);
++
++ switch_mm(mm, &init_mm, tsk);
++
++ atomic_dec(&mm->mm_count);
++ BUG_ON(atomic_read(&mm->mm_count) == 0);
++ }
++
++ task_unlock(tsk);
++
++ if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) &&
++ !mm->context.has_foreign_mappings )
++ mm_unpin(mm);
++}
++
++void pte_free(struct page *pte)
++{
++ unsigned long va = (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT);
++
++ if (!pte_write(*virt_to_ptep(va)))
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ va, pfn_pte(page_to_pfn(pte), PAGE_KERNEL), 0));
++ __free_page(pte);
++}
++#endif /* CONFIG_XEN */
++
++static inline pte_t *lookup_address(unsigned long address)
++{
++ pgd_t *pgd = pgd_offset_k(address);
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ if (pgd_none(*pgd))
++ return NULL;
++ pud = pud_offset(pgd, address);
++ if (!pud_present(*pud))
++ return NULL;
++ pmd = pmd_offset(pud, address);
++ if (!pmd_present(*pmd))
++ return NULL;
++ if (pmd_large(*pmd))
++ return (pte_t *)pmd;
++ pte = pte_offset_kernel(pmd, address);
++ if (pte && !pte_present(*pte))
++ pte = NULL;
++ return pte;
++}
++
++static struct page *split_large_page(unsigned long address, pgprot_t prot,
++ pgprot_t ref_prot)
++{
++ int i;
++ unsigned long addr;
++ struct page *base = alloc_pages(GFP_KERNEL, 0);
++ pte_t *pbase;
++ if (!base)
++ return NULL;
++ /*
++ * page_private is used to track the number of entries in
++ * the page table page have non standard attributes.
++ */
++ SetPagePrivate(base);
++ page_private(base) = 0;
++
++ address = __pa(address);
++ addr = address & LARGE_PAGE_MASK;
++ pbase = (pte_t *)page_address(base);
++ for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
++ pbase[i] = pfn_pte(addr >> PAGE_SHIFT,
++ addr == address ? prot : ref_prot);
++ }
++ return base;
++}
++
++
++static void flush_kernel_map(void *address)
++{
++ if (0 && address && cpu_has_clflush) {
++ /* is this worth it? */
++ int i;
++ for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
++ asm volatile("clflush (%0)" :: "r" (address + i));
++ } else
++ asm volatile("wbinvd":::"memory");
++ if (address)
++ __flush_tlb_one(address);
++ else
++ __flush_tlb_all();
++}
++
++
++static inline void flush_map(unsigned long address)
++{
++ on_each_cpu(flush_kernel_map, (void *)address, 1, 1);
++}
++
++static struct page *deferred_pages; /* protected by init_mm.mmap_sem */
++
++static inline void save_page(struct page *fpage)
++{
++ fpage->lru.next = (struct list_head *)deferred_pages;
++ deferred_pages = fpage;
++}
++
++/*
++ * No more special protections in this 2/4MB area - revert to a
++ * large page again.
++ */
++static void revert_page(unsigned long address, pgprot_t ref_prot)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t large_pte;
++
++ pgd = pgd_offset_k(address);
++ BUG_ON(pgd_none(*pgd));
++ pud = pud_offset(pgd,address);
++ BUG_ON(pud_none(*pud));
++ pmd = pmd_offset(pud, address);
++ BUG_ON(pmd_val(*pmd) & _PAGE_PSE);
++ pgprot_val(ref_prot) |= _PAGE_PSE;
++ large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot);
++ set_pte((pte_t *)pmd, large_pte);
++}
++
++static int
++__change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
++ pgprot_t ref_prot)
++{
++ pte_t *kpte;
++ struct page *kpte_page;
++ unsigned kpte_flags;
++ pgprot_t ref_prot2;
++ kpte = lookup_address(address);
++ if (!kpte) return 0;
++ kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
++ kpte_flags = pte_val(*kpte);
++ if (pgprot_val(prot) != pgprot_val(ref_prot)) {
++ if ((kpte_flags & _PAGE_PSE) == 0) {
++ set_pte(kpte, pfn_pte(pfn, prot));
++ } else {
++ /*
++ * split_large_page will take the reference for this
++ * change_page_attr on the split page.
++ */
++
++ struct page *split;
++ ref_prot2 = __pgprot(pgprot_val(pte_pgprot(*lookup_address(address))) & ~(1<<_PAGE_BIT_PSE));
++
++ split = split_large_page(address, prot, ref_prot2);
++ if (!split)
++ return -ENOMEM;
++ set_pte(kpte,mk_pte(split, ref_prot2));
++ kpte_page = split;
++ }
++ page_private(kpte_page)++;
++ } else if ((kpte_flags & _PAGE_PSE) == 0) {
++ set_pte(kpte, pfn_pte(pfn, ref_prot));
++ BUG_ON(page_private(kpte_page) == 0);
++ page_private(kpte_page)--;
++ } else
++ BUG();
++
++ /* on x86-64 the direct mapping set at boot is not using 4k pages */
++ /*
++ * ..., but the XEN guest kernels (currently) do:
++ * If the pte was reserved, it means it was created at boot
++ * time (not via split_large_page) and in turn we must not
++ * replace it with a large page.
++ */
++#ifndef CONFIG_XEN
++ BUG_ON(PageReserved(kpte_page));
++#else
++ if(!PageReserved(kpte_page))
++#endif
++ if (page_private(kpte_page) == 0) {
++ save_page(kpte_page);
++ revert_page(address, ref_prot);
++ }
++ return 0;
++}
++
++/*
++ * Change the page attributes of an page in the linear mapping.
++ *
++ * This should be used when a page is mapped with a different caching policy
++ * than write-back somewhere - some CPUs do not like it when mappings with
++ * different caching policies exist. This changes the page attributes of the
++ * in kernel linear mapping too.
++ *
++ * The caller needs to ensure that there are no conflicting mappings elsewhere.
++ * This function only deals with the kernel linear map.
++ *
++ * Caller must call global_flush_tlb() after this.
++ */
++int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot)
++{
++ int err = 0;
++ int i;
++
++ down_write(&init_mm.mmap_sem);
++ for (i = 0; i < numpages; i++, address += PAGE_SIZE) {
++ unsigned long pfn = __pa(address) >> PAGE_SHIFT;
++
++ err = __change_page_attr(address, pfn, prot, PAGE_KERNEL);
++ if (err)
++ break;
++ /* Handle kernel mapping too which aliases part of the
++ * lowmem */
++ if (__pa(address) < KERNEL_TEXT_SIZE) {
++ unsigned long addr2;
++ pgprot_t prot2 = prot;
++ addr2 = __START_KERNEL_map + __pa(address);
++ pgprot_val(prot2) &= ~_PAGE_NX;
++ err = __change_page_attr(addr2, pfn, prot2, PAGE_KERNEL_EXEC);
++ }
++ }
++ up_write(&init_mm.mmap_sem);
++ return err;
++}
++
++/* Don't call this for MMIO areas that may not have a mem_map entry */
++int change_page_attr(struct page *page, int numpages, pgprot_t prot)
++{
++ unsigned long addr = (unsigned long)page_address(page);
++ return change_page_attr_addr(addr, numpages, prot);
++}
++
++void global_flush_tlb(void)
++{
++ struct page *dpage;
++
++ down_read(&init_mm.mmap_sem);
++ dpage = xchg(&deferred_pages, NULL);
++ up_read(&init_mm.mmap_sem);
++
++ flush_map((dpage && !dpage->lru.next) ? (unsigned long)page_address(dpage) : 0);
++ while (dpage) {
++ struct page *tmp = dpage;
++ dpage = (struct page *)dpage->lru.next;
++ ClearPagePrivate(tmp);
++ __free_page(tmp);
++ }
++}
++
++EXPORT_SYMBOL(change_page_attr);
++EXPORT_SYMBOL(global_flush_tlb);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/oprofile/Makefile linux-2.6.18-xen/arch/x86_64/oprofile/Makefile
+--- linux-2.6.18.1/arch/x86_64/oprofile/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/oprofile/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -11,9 +11,12 @@
+ oprofilefs.o oprofile_stats.o \
+ timer_int.o )
+
++ifdef CONFIG_XEN
++OPROFILE-y := xenoprof.o
++else
+ OPROFILE-y := init.o backtrace.o
+ OPROFILE-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_p4.o \
+ op_model_ppro.o
+ OPROFILE-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
+-
++endif
+ oprofile-y = $(DRIVER_OBJS) $(addprefix ../../i386/oprofile/, $(OPROFILE-y))
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/arch/x86_64/pci/Makefile linux-2.6.18-xen/arch/x86_64/pci/Makefile
+--- linux-2.6.18.1/arch/x86_64/pci/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/arch/x86_64/pci/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -15,11 +15,23 @@
+
+ obj-$(CONFIG_NUMA) += k8-bus.o
+
++# pcifront should be after mmconfig.o and direct.o as it should only
++# take over if direct access to the PCI bus is unavailable
++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o
++
+ direct-y += ../../i386/pci/direct.o
+ acpi-y += ../../i386/pci/acpi.o
++pcifront-y += ../../i386/pci/pcifront.o
+ legacy-y += ../../i386/pci/legacy.o
+ irq-y += ../../i386/pci/irq.o
+ common-y += ../../i386/pci/common.o
+ fixup-y += ../../i386/pci/fixup.o
+ i386-y += ../../i386/pci/i386.o
+ init-y += ../../i386/pci/init.o
++
++ifdef CONFIG_XEN
++irq-y := ../../i386/pci/irq-xen.o
++include $(srctree)/scripts/Makefile.xen
++
++obj-y := $(call cherrypickxen, $(obj-y))
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/acpi/Kconfig linux-2.6.18-xen/drivers/acpi/Kconfig
+--- linux-2.6.18.1/drivers/acpi/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/acpi/Kconfig 2006-09-04 16:31:03.000000000 +0200
+@@ -45,7 +45,7 @@
+
+ config ACPI_SLEEP
+ bool "Sleep States"
+- depends on X86 && (!SMP || SUSPEND_SMP)
++ depends on X86 && (!SMP || SUSPEND_SMP) && !XEN
+ depends on PM
+ default y
+ ---help---
+@@ -305,6 +305,7 @@
+ config X86_PM_TIMER
+ bool "Power Management Timer Support" if EMBEDDED
+ depends on X86
++ depends on !XEN
+ default y
+ help
+ The Power Management Timer is available on all ACPI-capable,
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/hangcheck-timer.c linux-2.6.18-xen/drivers/char/hangcheck-timer.c
+--- linux-2.6.18.1/drivers/char/hangcheck-timer.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/hangcheck-timer.c 2006-09-04 16:31:04.000000000 +0200
+@@ -117,7 +117,7 @@
+ __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
+ #endif /* not MODULE */
+
+-#if defined(CONFIG_X86_64) || defined(CONFIG_S390)
++#if defined(CONFIG_X86_64) || defined(CONFIG_S390) || defined(CONFIG_X86_XEN)
+ # define HAVE_MONOTONIC
+ # define TIMER_FREQ 1000000000ULL
+ #elif defined(CONFIG_IA64)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/mem.c linux-2.6.18-xen/drivers/char/mem.c
+--- linux-2.6.18.1/drivers/char/mem.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/mem.c 2006-09-04 16:31:04.000000000 +0200
+@@ -101,6 +101,7 @@
+ }
+ #endif
+
++#ifndef ARCH_HAS_DEV_MEM
+ /*
+ * This funcion reads the *physical* memory. The f_pos points directly to the
+ * memory location.
+@@ -223,6 +224,7 @@
+ *ppos += written;
+ return written;
+ }
++#endif
+
+ #ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+@@ -776,6 +778,7 @@
+ #define open_kmem open_mem
+ #define open_oldmem open_mem
+
++#ifndef ARCH_HAS_DEV_MEM
+ static const struct file_operations mem_fops = {
+ .llseek = memory_lseek,
+ .read = read_mem,
+@@ -783,6 +786,9 @@
+ .mmap = mmap_mem,
+ .open = open_mem,
+ };
++#else
++extern struct file_operations mem_fops;
++#endif
+
+ static const struct file_operations kmem_fops = {
+ .llseek = memory_lseek,
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/Kconfig linux-2.6.18-xen/drivers/char/tpm/Kconfig
+--- linux-2.6.18.1/drivers/char/tpm/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/tpm/Kconfig 2006-09-04 16:31:04.000000000 +0200
+@@ -31,7 +31,7 @@
+
+ config TCG_NSC
+ tristate "National Semiconductor TPM Interface"
+- depends on TCG_TPM && PNPACPI
++ depends on TCG_TPM && PNPACPI && !XEN_UNPRIVILEGED_GUEST
+ ---help---
+ If you have a TPM security chip from National Semicondutor
+ say Yes and it will be accessible from within Linux. To
+@@ -58,5 +58,13 @@
+ Further information on this driver and the supported hardware
+ can be found at http://www.prosec.rub.de/tpm
+
+-endmenu
++config TCG_XEN
++ tristate "XEN TPM Interface"
++ depends on TCG_TPM && XEN
++ ---help---
++ If you want to make TPM support available to a Xen user domain,
++ say Yes and it will be accessible from within Linux.
++ To compile this driver as a module, choose M here; the module
++ will be called tpm_xenu.
+
++endmenu
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/Makefile linux-2.6.18-xen/drivers/char/tpm/Makefile
+--- linux-2.6.18.1/drivers/char/tpm/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/tpm/Makefile 2006-09-04 16:31:04.000000000 +0200
+@@ -9,3 +9,5 @@
+ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
+ obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
+ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
++obj-$(CONFIG_TCG_XEN) += tpm_xenu.o
++tpm_xenu-y = tpm_xen.o tpm_vtpm.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/tpm.c linux-2.6.18-xen/drivers/char/tpm/tpm.c
+--- linux-2.6.18.1/drivers/char/tpm/tpm.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/tpm/tpm.c 2006-09-04 16:31:04.000000000 +0200
+@@ -30,7 +30,9 @@
+
+ enum tpm_const {
+ TPM_MINOR = 224, /* officially assigned */
++#ifndef CONFIG_XEN
+ TPM_BUFSIZE = 2048,
++#endif
+ TPM_NUM_DEVICES = 256,
+ };
+
+@@ -331,7 +333,11 @@
+
+ down(&chip->buffer_mutex);
+ atomic_set(&chip->data_pending, 0);
++#ifndef CONFIG_XEN
+ memset(chip->data_buffer, 0, TPM_BUFSIZE);
++#else
++ memset(chip->data_buffer, 0, get_chip_buffersize(chip));
++#endif
+ up(&chip->buffer_mutex);
+ }
+
+@@ -921,7 +927,12 @@
+
+ spin_unlock(&driver_lock);
+
++#ifndef CONFIG_XEN
+ chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
++#else
++ chip->data_buffer = kmalloc(get_chip_buffersize(chip) * sizeof(u8),
++ GFP_KERNEL);
++#endif
+ if (chip->data_buffer == NULL) {
+ chip->num_opens--;
+ put_device(chip->dev);
+@@ -969,8 +980,13 @@
+
+ down(&chip->buffer_mutex);
+
++#ifndef CONFIG_XEN
+ if (in_size > TPM_BUFSIZE)
+ in_size = TPM_BUFSIZE;
++#else
++ if (in_size > get_chip_buffersize(chip))
++ in_size = get_chip_buffersize(chip);
++#endif
+
+ if (copy_from_user
+ (chip->data_buffer, (void __user *) buf, in_size)) {
+@@ -979,9 +995,17 @@
+ }
+
+ /* atomic tpm command send and result receive */
++#ifndef CONFIG_XEN
+ out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
++#else
++ out_size = tpm_transmit(chip, chip->data_buffer,
++ get_chip_buffersize(chip));
++#endif
+
+ atomic_set(&chip->data_pending, out_size);
++#ifdef CONFIG_XEN
++ atomic_set(&chip->data_position, 0);
++#endif
+ up(&chip->buffer_mutex);
+
+ /* Set a timeout by which the reader must come claim the result */
+@@ -996,21 +1020,52 @@
+ {
+ struct tpm_chip *chip = file->private_data;
+ int ret_size;
++#ifdef CONFIG_XEN
++ int pos, pending = 0;
++#endif
+
++#ifndef CONFIG_XEN
+ del_singleshot_timer_sync(&chip->user_read_timer);
+ flush_scheduled_work();
++#endif
+ ret_size = atomic_read(&chip->data_pending);
++#ifndef CONFIG_XEN
+ atomic_set(&chip->data_pending, 0);
++#endif
+ if (ret_size > 0) { /* relay data */
+ if (size < ret_size)
+ ret_size = size;
+
++#ifdef CONFIG_XEN
++ pos = atomic_read(&chip->data_position);
++#endif
+ down(&chip->buffer_mutex);
++#ifndef CONFIG_XEN
+ if (copy_to_user(buf, chip->data_buffer, ret_size))
++#else
++ if (copy_to_user(buf, &chip->data_buffer[pos], ret_size)) {
++#endif
+ ret_size = -EFAULT;
++#ifdef CONFIG_XEN
++ } else {
++ pending = atomic_read(&chip->data_pending) - ret_size;
++ if ( pending ) {
++ atomic_set(&chip->data_pending, pending);
++ atomic_set(&chip->data_position,
++ pos+ret_size);
++ }
++ }
++#endif
+ up(&chip->buffer_mutex);
+ }
+
++#ifdef CONFIG_XEN
++ if ( ret_size <= 0 || pending == 0 ) {
++ atomic_set(&chip->data_pending, 0);
++ del_singleshot_timer_sync(&chip->user_read_timer);
++ flush_scheduled_work();
++ }
++#endif
+ return ret_size;
+ }
+ EXPORT_SYMBOL_GPL(tpm_read);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/tpm.h linux-2.6.18-xen/drivers/char/tpm/tpm.h
+--- linux-2.6.18.1/drivers/char/tpm/tpm.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/tpm/tpm.h 2006-09-21 01:33:31.000000000 +0200
+@@ -61,6 +61,7 @@
+ const u8 req_complete_mask;
+ const u8 req_complete_val;
+ const u8 req_canceled;
++ u32 buffersize;
+ void __iomem *iobase; /* ioremapped address */
+ unsigned long base; /* TPM base address */
+
+@@ -94,6 +95,7 @@
+ /* Data passed to and from the tpm via the read/write calls */
+ u8 *data_buffer;
+ atomic_t data_pending;
++ atomic_t data_position;
+ struct semaphore buffer_mutex;
+
+ struct timer_list user_read_timer; /* user needs to claim result */
+@@ -121,6 +123,11 @@
+ outb(value & 0xFF, base+1);
+ }
+
++static inline u32 get_chip_buffersize(struct tpm_chip *chip)
++{
++ return chip->vendor.buffersize;
++}
++
+ extern void tpm_get_timeouts(struct tpm_chip *);
+ extern void tpm_gen_interrupt(struct tpm_chip *);
+ extern void tpm_continue_selftest(struct tpm_chip *);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/tpm_vtpm.c linux-2.6.18-xen/drivers/char/tpm/tpm_vtpm.c
+--- linux-2.6.18.1/drivers/char/tpm/tpm_vtpm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/char/tpm/tpm_vtpm.c 2006-09-04 16:31:04.000000000 +0200
+@@ -0,0 +1,547 @@
++/*
++ * Copyright (C) 2006 IBM Corporation
++ *
++ * Authors:
++ * Stefan Berger <stefanb at us.ibm.com>
++ *
++ * Generic device driver part for device drivers in a virtualized
++ * environment.
++ *
++ * 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 of the
++ * License.
++ *
++ */
++
++#include <asm/uaccess.h>
++#include <linux/list.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include "tpm.h"
++#include "tpm_vtpm.h"
++
++/* read status bits */
++enum {
++ STATUS_BUSY = 0x01,
++ STATUS_DATA_AVAIL = 0x02,
++ STATUS_READY = 0x04
++};
++
++struct transmission {
++ struct list_head next;
++
++ unsigned char *request;
++ size_t request_len;
++ size_t request_buflen;
++
++ unsigned char *response;
++ size_t response_len;
++ size_t response_buflen;
++
++ unsigned int flags;
++};
++
++enum {
++ TRANSMISSION_FLAG_WAS_QUEUED = 0x1
++};
++
++
++enum {
++ DATAEX_FLAG_QUEUED_ONLY = 0x1
++};
++
++
++/* local variables */
++
++/* local function prototypes */
++static int _vtpm_send_queued(struct tpm_chip *chip);
++
++
++/* =============================================================
++ * Some utility functions
++ * =============================================================
++ */
++static void vtpm_state_init(struct vtpm_state *vtpms)
++{
++ vtpms->current_request = NULL;
++ spin_lock_init(&vtpms->req_list_lock);
++ init_waitqueue_head(&vtpms->req_wait_queue);
++ INIT_LIST_HEAD(&vtpms->queued_requests);
++
++ vtpms->current_response = NULL;
++ spin_lock_init(&vtpms->resp_list_lock);
++ init_waitqueue_head(&vtpms->resp_wait_queue);
++
++ vtpms->disconnect_time = jiffies;
++}
++
++
++static inline struct transmission *transmission_alloc(void)
++{
++ return kzalloc(sizeof(struct transmission), GFP_ATOMIC);
++}
++
++static unsigned char *
++transmission_set_req_buffer(struct transmission *t,
++ unsigned char *buffer, size_t len)
++{
++ if (t->request_buflen < len) {
++ kfree(t->request);
++ t->request = kmalloc(len, GFP_KERNEL);
++ if (!t->request) {
++ t->request_buflen = 0;
++ return NULL;
++ }
++ t->request_buflen = len;
++ }
++
++ memcpy(t->request, buffer, len);
++ t->request_len = len;
++
++ return t->request;
++}
++
++static unsigned char *
++transmission_set_res_buffer(struct transmission *t,
++ const unsigned char *buffer, size_t len)
++{
++ if (t->response_buflen < len) {
++ kfree(t->response);
++ t->response = kmalloc(len, GFP_ATOMIC);
++ if (!t->response) {
++ t->response_buflen = 0;
++ return NULL;
++ }
++ t->response_buflen = len;
++ }
++
++ memcpy(t->response, buffer, len);
++ t->response_len = len;
++
++ return t->response;
++}
++
++static inline void transmission_free(struct transmission *t)
++{
++ kfree(t->request);
++ kfree(t->response);
++ kfree(t);
++}
++
++/* =============================================================
++ * Interface with the lower layer driver
++ * =============================================================
++ */
++/*
++ * Lower layer uses this function to make a response available.
++ */
++int vtpm_vd_recv(const struct tpm_chip *chip,
++ const unsigned char *buffer, size_t count,
++ void *ptr)
++{
++ unsigned long flags;
++ int ret_size = 0;
++ struct transmission *t;
++ struct vtpm_state *vtpms;
++
++ vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ /*
++ * The list with requests must contain one request
++ * only and the element there must be the one that
++ * was passed to me from the front-end.
++ */
++ spin_lock_irqsave(&vtpms->resp_list_lock, flags);
++ if (vtpms->current_request != ptr) {
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ return 0;
++ }
++
++ if ((t = vtpms->current_request)) {
++ transmission_free(t);
++ vtpms->current_request = NULL;
++ }
++
++ t = transmission_alloc();
++ if (t) {
++ if (!transmission_set_res_buffer(t, buffer, count)) {
++ transmission_free(t);
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ return -ENOMEM;
++ }
++ ret_size = count;
++ vtpms->current_response = t;
++ wake_up_interruptible(&vtpms->resp_wait_queue);
++ }
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++
++ return ret_size;
++}
++
++
++/*
++ * Lower layer indicates its status (connected/disconnected)
++ */
++void vtpm_vd_status(const struct tpm_chip *chip, u8 vd_status)
++{
++ struct vtpm_state *vtpms;
++
++ vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ vtpms->vd_status = vd_status;
++ if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) {
++ vtpms->disconnect_time = jiffies;
++ }
++}
++
++/* =============================================================
++ * Interface with the generic TPM driver
++ * =============================================================
++ */
++static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
++{
++ int rc = 0;
++ unsigned long flags;
++ struct vtpm_state *vtpms;
++
++ vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ /*
++ * Check if the previous operation only queued the command
++ * In this case there won't be a response, so I just
++ * return from here and reset that flag. In any other
++ * case I should receive a response from the back-end.
++ */
++ spin_lock_irqsave(&vtpms->resp_list_lock, flags);
++ if ((vtpms->flags & DATAEX_FLAG_QUEUED_ONLY) != 0) {
++ vtpms->flags &= ~DATAEX_FLAG_QUEUED_ONLY;
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ /*
++ * The first few commands (measurements) must be
++ * queued since it might not be possible to talk to the
++ * TPM, yet.
++ * Return a response of up to 30 '0's.
++ */
++
++ count = min_t(size_t, count, 30);
++ memset(buf, 0x0, count);
++ return count;
++ }
++ /*
++ * Check whether something is in the responselist and if
++ * there's nothing in the list wait for something to appear.
++ */
++
++ if (!vtpms->current_response) {
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ interruptible_sleep_on_timeout(&vtpms->resp_wait_queue,
++ 1000);
++ spin_lock_irqsave(&vtpms->resp_list_lock ,flags);
++ }
++
++ if (vtpms->current_response) {
++ struct transmission *t = vtpms->current_response;
++ vtpms->current_response = NULL;
++ rc = min(count, t->response_len);
++ memcpy(buf, t->response, rc);
++ transmission_free(t);
++ }
++
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ return rc;
++}
++
++static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
++{
++ int rc = 0;
++ unsigned long flags;
++ struct transmission *t = transmission_alloc();
++ struct vtpm_state *vtpms;
++
++ vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ if (!t)
++ return -ENOMEM;
++ /*
++ * If there's a current request, it must be the
++ * previous request that has timed out.
++ */
++ spin_lock_irqsave(&vtpms->req_list_lock, flags);
++ if (vtpms->current_request != NULL) {
++ printk("WARNING: Sending although there is a request outstanding.\n"
++ " Previous request must have timed out.\n");
++ transmission_free(vtpms->current_request);
++ vtpms->current_request = NULL;
++ }
++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags);
++
++ /*
++ * Queue the packet if the driver below is not
++ * ready, yet, or there is any packet already
++ * in the queue.
++ * If the driver below is ready, unqueue all
++ * packets first before sending our current
++ * packet.
++ * For each unqueued packet, except for the
++ * last (=current) packet, call the function
++ * tpm_xen_recv to wait for the response to come
++ * back.
++ */
++ if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) {
++ if (time_after(jiffies,
++ vtpms->disconnect_time + HZ * 10)) {
++ rc = -ENOENT;
++ } else {
++ goto queue_it;
++ }
++ } else {
++ /*
++ * Send all queued packets.
++ */
++ if (_vtpm_send_queued(chip) == 0) {
++
++ vtpms->current_request = t;
++
++ rc = vtpm_vd_send(vtpms->tpm_private,
++ buf,
++ count,
++ t);
++ /*
++ * The generic TPM driver will call
++ * the function to receive the response.
++ */
++ if (rc < 0) {
++ vtpms->current_request = NULL;
++ goto queue_it;
++ }
++ } else {
++queue_it:
++ if (!transmission_set_req_buffer(t, buf, count)) {
++ transmission_free(t);
++ rc = -ENOMEM;
++ goto exit;
++ }
++ /*
++ * An error occurred. Don't event try
++ * to send the current request. Just
++ * queue it.
++ */
++ spin_lock_irqsave(&vtpms->req_list_lock, flags);
++ vtpms->flags |= DATAEX_FLAG_QUEUED_ONLY;
++ list_add_tail(&t->next, &vtpms->queued_requests);
++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags);
++ }
++ }
++
++exit:
++ return rc;
++}
++
++
++/*
++ * Send all queued requests.
++ */
++static int _vtpm_send_queued(struct tpm_chip *chip)
++{
++ int rc;
++ int error = 0;
++ long flags;
++ unsigned char buffer[1];
++ struct vtpm_state *vtpms;
++ vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ spin_lock_irqsave(&vtpms->req_list_lock, flags);
++
++ while (!list_empty(&vtpms->queued_requests)) {
++ /*
++ * Need to dequeue them.
++ * Read the result into a dummy buffer.
++ */
++ struct transmission *qt = (struct transmission *)
++ vtpms->queued_requests.next;
++ list_del(&qt->next);
++ vtpms->current_request = qt;
++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags);
++
++ rc = vtpm_vd_send(vtpms->tpm_private,
++ qt->request,
++ qt->request_len,
++ qt);
++
++ if (rc < 0) {
++ spin_lock_irqsave(&vtpms->req_list_lock, flags);
++ if ((qt = vtpms->current_request) != NULL) {
++ /*
++ * requeue it at the beginning
++ * of the list
++ */
++ list_add(&qt->next,
++ &vtpms->queued_requests);
++ }
++ vtpms->current_request = NULL;
++ error = 1;
++ break;
++ }
++ /*
++ * After this point qt is not valid anymore!
++ * It is freed when the front-end is delivering
++ * the data by calling tpm_recv
++ */
++ /*
++ * Receive response into provided dummy buffer
++ */
++ rc = vtpm_recv(chip, buffer, sizeof(buffer));
++ spin_lock_irqsave(&vtpms->req_list_lock, flags);
++ }
++
++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags);
++
++ return error;
++}
++
++static void vtpm_cancel(struct tpm_chip *chip)
++{
++ unsigned long flags;
++ struct vtpm_state *vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ spin_lock_irqsave(&vtpms->resp_list_lock,flags);
++
++ if (!vtpms->current_response && vtpms->current_request) {
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ interruptible_sleep_on(&vtpms->resp_wait_queue);
++ spin_lock_irqsave(&vtpms->resp_list_lock,flags);
++ }
++
++ if (vtpms->current_response) {
++ struct transmission *t = vtpms->current_response;
++ vtpms->current_response = NULL;
++ transmission_free(t);
++ }
++
++ spin_unlock_irqrestore(&vtpms->resp_list_lock,flags);
++}
++
++static u8 vtpm_status(struct tpm_chip *chip)
++{
++ u8 rc = 0;
++ unsigned long flags;
++ struct vtpm_state *vtpms;
++
++ vtpms = (struct vtpm_state *)chip_get_private(chip);
++
++ spin_lock_irqsave(&vtpms->resp_list_lock, flags);
++ /*
++ * Data are available if:
++ * - there's a current response
++ * - the last packet was queued only (this is fake, but necessary to
++ * get the generic TPM layer to call the receive function.)
++ */
++ if (vtpms->current_response ||
++ 0 != (vtpms->flags & DATAEX_FLAG_QUEUED_ONLY)) {
++ rc = STATUS_DATA_AVAIL;
++ } else if (!vtpms->current_response && !vtpms->current_request) {
++ rc = STATUS_READY;
++ }
++
++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
++ return rc;
++}
++
++static struct file_operations vtpm_ops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .open = tpm_open,
++ .read = tpm_read,
++ .write = tpm_write,
++ .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(enabled, S_IRUGO, tpm_show_enabled, NULL);
++static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
++static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
++static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
++ 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 *vtpm_attrs[] = {
++ &dev_attr_pubek.attr,
++ &dev_attr_pcrs.attr,
++ &dev_attr_enabled.attr,
++ &dev_attr_active.attr,
++ &dev_attr_owned.attr,
++ &dev_attr_temp_deactivated.attr,
++ &dev_attr_caps.attr,
++ &dev_attr_cancel.attr,
++ NULL,
++};
++
++static struct attribute_group vtpm_attr_grp = { .attrs = vtpm_attrs };
++
++#define TPM_LONG_TIMEOUT (10 * 60 * HZ)
++
++static struct tpm_vendor_specific tpm_vtpm = {
++ .recv = vtpm_recv,
++ .send = vtpm_send,
++ .cancel = vtpm_cancel,
++ .status = vtpm_status,
++ .req_complete_mask = STATUS_BUSY | STATUS_DATA_AVAIL,
++ .req_complete_val = STATUS_DATA_AVAIL,
++ .req_canceled = STATUS_READY,
++ .attr_group = &vtpm_attr_grp,
++ .miscdev = {
++ .fops = &vtpm_ops,
++ },
++ .duration = {
++ TPM_LONG_TIMEOUT,
++ TPM_LONG_TIMEOUT,
++ TPM_LONG_TIMEOUT,
++ },
++};
++
++struct tpm_chip *init_vtpm(struct device *dev,
++ struct tpm_virtual_device *tvd,
++ struct tpm_private *tp)
++{
++ long rc;
++ struct tpm_chip *chip;
++ struct vtpm_state *vtpms;
++
++ vtpms = kzalloc(sizeof(struct vtpm_state), GFP_KERNEL);
++ if (!vtpms)
++ return ERR_PTR(-ENOMEM);
++
++ vtpm_state_init(vtpms);
++ vtpms->tpmvd = tvd;
++ vtpms->tpm_private = tp;
++
++ if (tvd)
++ tpm_vtpm.buffersize = tvd->max_tx_size;
++
++ chip = tpm_register_hardware(dev, &tpm_vtpm);
++ if (!chip) {
++ rc = -ENODEV;
++ goto err_free_mem;
++ }
++
++ chip_set_private(chip, vtpms);
++
++ return chip;
++
++err_free_mem:
++ kfree(vtpms);
++
++ return ERR_PTR(rc);
++}
++
++void cleanup_vtpm(struct device *dev)
++{
++ struct tpm_chip *chip = dev_get_drvdata(dev);
++ struct vtpm_state *vtpms = (struct vtpm_state*)chip_get_private(chip);
++ tpm_remove_hardware(dev);
++ kfree(vtpms);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/tpm_vtpm.h linux-2.6.18-xen/drivers/char/tpm/tpm_vtpm.h
+--- linux-2.6.18.1/drivers/char/tpm/tpm_vtpm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/char/tpm/tpm_vtpm.h 2006-09-04 16:31:04.000000000 +0200
+@@ -0,0 +1,68 @@
++#ifndef TPM_VTPM_H
++#define TPM_VTPM_H
++
++struct tpm_chip;
++struct tpm_private;
++
++struct tpm_virtual_device {
++ /*
++ * This field indicates the maximum size the driver can
++ * transfer in one chunk. It is filled in by the front-end
++ * driver and should be propagated to the generic tpm driver
++ * for allocation of buffers.
++ */
++ unsigned int max_tx_size;
++};
++
++struct vtpm_state {
++ struct transmission *current_request;
++ spinlock_t req_list_lock;
++ wait_queue_head_t req_wait_queue;
++
++ struct list_head queued_requests;
++
++ struct transmission *current_response;
++ spinlock_t resp_list_lock;
++ wait_queue_head_t resp_wait_queue; // processes waiting for responses
++
++ u8 vd_status;
++ u8 flags;
++
++ unsigned long disconnect_time;
++
++ struct tpm_virtual_device *tpmvd;
++
++ /*
++ * The following is a private structure of the underlying
++ * driver. It is passed as parameter in the send function.
++ */
++ struct tpm_private *tpm_private;
++};
++
++
++enum vdev_status {
++ TPM_VD_STATUS_DISCONNECTED = 0x0,
++ TPM_VD_STATUS_CONNECTED = 0x1
++};
++
++/* this function is called from tpm_vtpm.c */
++int vtpm_vd_send(struct tpm_private * tp,
++ const u8 * buf, size_t count, void *ptr);
++
++/* these functions are offered by tpm_vtpm.c */
++struct tpm_chip *init_vtpm(struct device *,
++ struct tpm_virtual_device *,
++ struct tpm_private *);
++void cleanup_vtpm(struct device *);
++int vtpm_vd_recv(const struct tpm_chip* chip,
++ const unsigned char *buffer, size_t count, void *ptr);
++void vtpm_vd_status(const struct tpm_chip *, u8 status);
++
++static inline struct tpm_private *tpm_private_from_dev(struct device *dev)
++{
++ struct tpm_chip *chip = dev_get_drvdata(dev);
++ struct vtpm_state *vtpms = chip_get_private(chip);
++ return vtpms->tpm_private;
++}
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tpm/tpm_xen.c linux-2.6.18-xen/drivers/char/tpm/tpm_xen.c
+--- linux-2.6.18.1/drivers/char/tpm/tpm_xen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/char/tpm/tpm_xen.c 2006-09-04 16:31:04.000000000 +0200
+@@ -0,0 +1,756 @@
++/*
++ * Copyright (c) 2005, IBM Corporation
++ *
++ * Author: Stefan Berger, stefanb at us.ibm.com
++ * Grant table support: Mahadevan Gomathisankaran
++ *
++ * This code has been derived from drivers/xen/netfront/netfront.c
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/mutex.h>
++#include <asm/uaccess.h>
++#include <xen/evtchn.h>
++#include <xen/interface/grant_table.h>
++#include <xen/interface/io/tpmif.h>
++#include <xen/xenbus.h>
++#include "tpm.h"
++#include "tpm_vtpm.h"
++
++#undef DEBUG
++
++/* local structures */
++struct tpm_private {
++ struct tpm_chip *chip;
++
++ tpmif_tx_interface_t *tx;
++ atomic_t refcnt;
++ unsigned int evtchn;
++ unsigned int irq;
++ u8 is_connected;
++ u8 is_suspended;
++
++ spinlock_t tx_lock;
++
++ struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE];
++
++ atomic_t tx_busy;
++ void *tx_remember;
++
++ domid_t backend_id;
++ wait_queue_head_t wait_q;
++
++ struct xenbus_device *dev;
++ int ring_ref;
++};
++
++struct tx_buffer {
++ unsigned int size; // available space in data
++ unsigned int len; // used space in data
++ unsigned char *data; // pointer to a page
++};
++
++
++/* locally visible variables */
++static grant_ref_t gref_head;
++static struct tpm_private *my_priv;
++
++/* local function prototypes */
++static irqreturn_t tpmif_int(int irq,
++ void *tpm_priv,
++ struct pt_regs *ptregs);
++static void tpmif_rx_action(unsigned long unused);
++static int tpmif_connect(struct xenbus_device *dev,
++ struct tpm_private *tp,
++ domid_t domid);
++static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
++static int tpmif_allocate_tx_buffers(struct tpm_private *tp);
++static void tpmif_free_tx_buffers(struct tpm_private *tp);
++static void tpmif_set_connected_state(struct tpm_private *tp,
++ u8 newstate);
++static int tpm_xmit(struct tpm_private *tp,
++ const u8 * buf, size_t count, int userbuffer,
++ void *remember);
++static void destroy_tpmring(struct tpm_private *tp);
++void __exit tpmif_exit(void);
++
++#define DPRINTK(fmt, args...) \
++ pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "xen_tpm_fr: " fmt, ##args)
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args)
++
++#define GRANT_INVALID_REF 0
++
++
++static inline int
++tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len,
++ int isuserbuffer)
++{
++ int copied = len;
++
++ if (len > txb->size) {
++ copied = txb->size;
++ }
++ if (isuserbuffer) {
++ if (copy_from_user(txb->data, src, copied))
++ return -EFAULT;
++ } else {
++ memcpy(txb->data, src, copied);
++ }
++ txb->len = len;
++ return copied;
++}
++
++static inline struct tx_buffer *tx_buffer_alloc(void)
++{
++ struct tx_buffer *txb = kzalloc(sizeof (struct tx_buffer),
++ GFP_KERNEL);
++
++ if (txb) {
++ txb->len = 0;
++ txb->size = PAGE_SIZE;
++ txb->data = (unsigned char *)__get_free_page(GFP_KERNEL);
++ if (txb->data == NULL) {
++ kfree(txb);
++ txb = NULL;
++ }
++ }
++ return txb;
++}
++
++
++static inline void tx_buffer_free(struct tx_buffer *txb)
++{
++ if (txb) {
++ free_page((long)txb->data);
++ kfree(txb);
++ }
++}
++
++/**************************************************************
++ Utility function for the tpm_private structure
++**************************************************************/
++static inline void tpm_private_init(struct tpm_private *tp)
++{
++ spin_lock_init(&tp->tx_lock);
++ init_waitqueue_head(&tp->wait_q);
++ atomic_set(&tp->refcnt, 1);
++}
++
++static inline void tpm_private_put(void)
++{
++ if ( atomic_dec_and_test(&my_priv->refcnt)) {
++ tpmif_free_tx_buffers(my_priv);
++ kfree(my_priv);
++ my_priv = NULL;
++ }
++}
++
++static struct tpm_private *tpm_private_get(void)
++{
++ int err;
++ if (!my_priv) {
++ my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL);
++ if (my_priv) {
++ tpm_private_init(my_priv);
++ err = tpmif_allocate_tx_buffers(my_priv);
++ if (err < 0) {
++ tpm_private_put();
++ }
++ }
++ } else {
++ atomic_inc(&my_priv->refcnt);
++ }
++ return my_priv;
++}
++
++/**************************************************************
++
++ The interface to let the tpm plugin register its callback
++ function and send data to another partition using this module
++
++**************************************************************/
++
++static DEFINE_MUTEX(suspend_lock);
++/*
++ * Send data via this module by calling this function
++ */
++int vtpm_vd_send(struct tpm_private *tp,
++ const u8 * buf, size_t count, void *ptr)
++{
++ int sent;
++
++ mutex_lock(&suspend_lock);
++ sent = tpm_xmit(tp, buf, count, 0, ptr);
++ mutex_unlock(&suspend_lock);
++
++ return sent;
++}
++
++/**************************************************************
++ XENBUS support code
++**************************************************************/
++
++static int setup_tpmring(struct xenbus_device *dev,
++ struct tpm_private *tp)
++{
++ tpmif_tx_interface_t *sring;
++ int err;
++
++ tp->ring_ref = GRANT_INVALID_REF;
++
++ sring = (void *)__get_free_page(GFP_KERNEL);
++ if (!sring) {
++ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
++ return -ENOMEM;
++ }
++ tp->tx = sring;
++
++ err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
++ if (err < 0) {
++ free_page((unsigned long)sring);
++ tp->tx = NULL;
++ xenbus_dev_fatal(dev, err, "allocating grant reference");
++ goto fail;
++ }
++ tp->ring_ref = err;
++
++ err = tpmif_connect(dev, tp, dev->otherend_id);
++ if (err)
++ goto fail;
++
++ return 0;
++fail:
++ destroy_tpmring(tp);
++ return err;
++}
++
++
++static void destroy_tpmring(struct tpm_private *tp)
++{
++ tpmif_set_connected_state(tp, 0);
++
++ if (tp->ring_ref != GRANT_INVALID_REF) {
++ gnttab_end_foreign_access(tp->ring_ref, 0,
++ (unsigned long)tp->tx);
++ tp->ring_ref = GRANT_INVALID_REF;
++ tp->tx = NULL;
++ }
++
++ if (tp->irq)
++ unbind_from_irqhandler(tp->irq, tp);
++
++ tp->evtchn = tp->irq = 0;
++}
++
++
++static int talk_to_backend(struct xenbus_device *dev,
++ struct tpm_private *tp)
++{
++ const char *message = NULL;
++ int err;
++ struct xenbus_transaction xbt;
++
++ err = setup_tpmring(dev, tp);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "setting up ring");
++ goto out;
++ }
++
++again:
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ goto destroy_tpmring;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename,
++ "ring-ref","%u", tp->ring_ref);
++ if (err) {
++ message = "writing ring-ref";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename,
++ "event-channel", "%u", tp->evtchn);
++ if (err) {
++ message = "writing event-channel";
++ goto abort_transaction;
++ }
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err == -EAGAIN)
++ goto again;
++ if (err) {
++ xenbus_dev_fatal(dev, err, "completing transaction");
++ goto destroy_tpmring;
++ }
++
++ xenbus_switch_state(dev, XenbusStateConnected);
++
++ return 0;
++
++abort_transaction:
++ xenbus_transaction_end(xbt, 1);
++ if (message)
++ xenbus_dev_error(dev, err, "%s", message);
++destroy_tpmring:
++ destroy_tpmring(tp);
++out:
++ return err;
++}
++
++/**
++ * Callback received when the backend's state changes.
++ */
++static void backend_changed(struct xenbus_device *dev,
++ enum xenbus_state backend_state)
++{
++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
++ DPRINTK("\n");
++
++ switch (backend_state) {
++ case XenbusStateInitialising:
++ case XenbusStateInitWait:
++ case XenbusStateInitialised:
++ break;
++
++ case XenbusStateConnected:
++ tpmif_set_connected_state(tp, 1);
++ break;
++
++ case XenbusStateClosing:
++ tpmif_set_connected_state(tp, 0);
++ break;
++
++ case XenbusStateUnknown:
++ case XenbusStateClosed:
++ if (tp->is_suspended == 0)
++ device_unregister(&dev->dev);
++ xenbus_switch_state(dev, XenbusStateClosed);
++ break;
++ }
++}
++
++struct tpm_virtual_device tvd = {
++ .max_tx_size = PAGE_SIZE * TPMIF_TX_RING_SIZE,
++};
++
++static int tpmfront_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err;
++ int handle;
++ struct tpm_private *tp = tpm_private_get();
++
++ if (!tp)
++ return -ENOMEM;
++
++ tp->chip = init_vtpm(&dev->dev, &tvd, tp);
++
++ if (IS_ERR(tp->chip)) {
++ return PTR_ERR(tp->chip);
++ }
++
++ err = xenbus_scanf(XBT_NIL, dev->nodename,
++ "handle", "%i", &handle);
++ if (XENBUS_EXIST_ERR(err))
++ return err;
++
++ if (err < 0) {
++ xenbus_dev_fatal(dev,err,"reading virtual-device");
++ return err;
++ }
++
++ tp->dev = dev;
++
++ err = talk_to_backend(dev, tp);
++ if (err) {
++ tpm_private_put();
++ return err;
++ }
++ return 0;
++}
++
++
++static int tpmfront_remove(struct xenbus_device *dev)
++{
++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
++ destroy_tpmring(tp);
++ cleanup_vtpm(&dev->dev);
++ return 0;
++}
++
++static int tpmfront_suspend(struct xenbus_device *dev)
++{
++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
++ u32 ctr;
++ /* lock, so no app can send */
++ mutex_lock(&suspend_lock);
++ tp->is_suspended = 1;
++
++ for (ctr = 0; atomic_read(&tp->tx_busy) && ctr <= 25; ctr++) {
++ if ((ctr % 10) == 0)
++ printk("TPM-FE [INFO]: Waiting for outstanding request.\n");
++ /*
++ * Wait for a request to be responded to.
++ */
++ interruptible_sleep_on_timeout(&tp->wait_q, 100);
++ }
++ xenbus_switch_state(dev, XenbusStateClosing);
++
++ if (atomic_read(&tp->tx_busy)) {
++ /*
++ * A temporary work-around.
++ */
++ printk("TPM-FE [WARNING]: Resetting busy flag.");
++ atomic_set(&tp->tx_busy, 0);
++ }
++
++ return 0;
++}
++
++static int tpmfront_resume(struct xenbus_device *dev)
++{
++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
++ destroy_tpmring(tp);
++ return talk_to_backend(dev, tp);
++}
++
++static int tpmif_connect(struct xenbus_device *dev,
++ struct tpm_private *tp,
++ domid_t domid)
++{
++ int err;
++
++ tp->backend_id = domid;
++
++ err = xenbus_alloc_evtchn(dev, &tp->evtchn);
++ if (err)
++ return err;
++
++ err = bind_evtchn_to_irqhandler(tp->evtchn,
++ tpmif_int, SA_SAMPLE_RANDOM, "tpmif",
++ tp);
++ if (err <= 0) {
++ WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err);
++ return err;
++ }
++
++ tp->irq = err;
++ return 0;
++}
++
++static struct xenbus_device_id tpmfront_ids[] = {
++ { "vtpm" },
++ { "" }
++};
++
++static struct xenbus_driver tpmfront = {
++ .name = "vtpm",
++ .owner = THIS_MODULE,
++ .ids = tpmfront_ids,
++ .probe = tpmfront_probe,
++ .remove = tpmfront_remove,
++ .resume = tpmfront_resume,
++ .otherend_changed = backend_changed,
++ .suspend = tpmfront_suspend,
++};
++
++static void __init init_tpm_xenbus(void)
++{
++ xenbus_register_frontend(&tpmfront);
++}
++
++static void __exit exit_tpm_xenbus(void)
++{
++ xenbus_unregister_driver(&tpmfront);
++}
++
++static int tpmif_allocate_tx_buffers(struct tpm_private *tp)
++{
++ unsigned int i;
++
++ for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
++ tp->tx_buffers[i] = tx_buffer_alloc();
++ if (!tp->tx_buffers[i]) {
++ tpmif_free_tx_buffers(tp);
++ return -ENOMEM;
++ }
++ }
++ return 0;
++}
++
++static void tpmif_free_tx_buffers(struct tpm_private *tp)
++{
++ unsigned int i;
++
++ for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
++ tx_buffer_free(tp->tx_buffers[i]);
++ }
++}
++
++static void tpmif_rx_action(unsigned long priv)
++{
++ struct tpm_private *tp = (struct tpm_private *)priv;
++
++ int i = 0;
++ unsigned int received;
++ unsigned int offset = 0;
++ u8 *buffer;
++ tpmif_tx_request_t *tx;
++ tx = &tp->tx->ring[i].req;
++
++ atomic_set(&tp->tx_busy, 0);
++ wake_up_interruptible(&tp->wait_q);
++
++ received = tx->size;
++
++ buffer = kmalloc(received, GFP_ATOMIC);
++ if (NULL == buffer) {
++ goto exit;
++ }
++
++ for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) {
++ struct tx_buffer *txb = tp->tx_buffers[i];
++ tpmif_tx_request_t *tx;
++ unsigned int tocopy;
++
++ tx = &tp->tx->ring[i].req;
++ tocopy = tx->size;
++ if (tocopy > PAGE_SIZE) {
++ tocopy = PAGE_SIZE;
++ }
++
++ memcpy(&buffer[offset], txb->data, tocopy);
++
++ gnttab_release_grant_reference(&gref_head, tx->ref);
++
++ offset += tocopy;
++ }
++
++ vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember);
++ kfree(buffer);
++
++exit:
++
++ return;
++}
++
++
++static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs)
++{
++ struct tpm_private *tp = tpm_priv;
++ unsigned long flags;
++
++ spin_lock_irqsave(&tp->tx_lock, flags);
++ tpmif_rx_tasklet.data = (unsigned long)tp;
++ tasklet_schedule(&tpmif_rx_tasklet);
++ spin_unlock_irqrestore(&tp->tx_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++
++static int tpm_xmit(struct tpm_private *tp,
++ const u8 * buf, size_t count, int isuserbuffer,
++ void *remember)
++{
++ tpmif_tx_request_t *tx;
++ TPMIF_RING_IDX i;
++ unsigned int offset = 0;
++
++ spin_lock_irq(&tp->tx_lock);
++
++ if (unlikely(atomic_read(&tp->tx_busy))) {
++ printk("tpm_xmit: There's an outstanding request/response "
++ "on the way!\n");
++ spin_unlock_irq(&tp->tx_lock);
++ return -EBUSY;
++ }
++
++ if (tp->is_connected != 1) {
++ spin_unlock_irq(&tp->tx_lock);
++ return -EIO;
++ }
++
++ for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) {
++ struct tx_buffer *txb = tp->tx_buffers[i];
++ int copied;
++
++ if (NULL == txb) {
++ DPRINTK("txb (i=%d) is NULL. buffers initilized?\n"
++ "Not transmitting anything!\n", i);
++ spin_unlock_irq(&tp->tx_lock);
++ return -EFAULT;
++ }
++ copied = tx_buffer_copy(txb, &buf[offset], count,
++ isuserbuffer);
++ if (copied < 0) {
++ /* An error occurred */
++ spin_unlock_irq(&tp->tx_lock);
++ return copied;
++ }
++ count -= copied;
++ offset += copied;
++
++ tx = &tp->tx->ring[i].req;
++
++ tx->addr = virt_to_machine(txb->data);
++ tx->size = txb->len;
++
++ DPRINTK("First 4 characters sent by TPM-FE are 0x%02x 0x%02x 0x%02x 0x%02x\n",
++ txb->data[0],txb->data[1],txb->data[2],txb->data[3]);
++
++ /* get the granttable reference for this page */
++ tx->ref = gnttab_claim_grant_reference(&gref_head);
++
++ if (-ENOSPC == tx->ref) {
++ spin_unlock_irq(&tp->tx_lock);
++ DPRINTK(" Grant table claim reference failed in func:%s line:%d file:%s\n", __FUNCTION__, __LINE__, __FILE__);
++ return -ENOSPC;
++ }
++ gnttab_grant_foreign_access_ref( tx->ref,
++ tp->backend_id,
++ (tx->addr >> PAGE_SHIFT),
++ 0 /*RW*/);
++ wmb();
++ }
++
++ atomic_set(&tp->tx_busy, 1);
++ tp->tx_remember = remember;
++
++ mb();
++
++ DPRINTK("Notifying backend via event channel %d\n",
++ tp->evtchn);
++
++ notify_remote_via_irq(tp->irq);
++
++ spin_unlock_irq(&tp->tx_lock);
++ return offset;
++}
++
++
++static void tpmif_notify_upperlayer(struct tpm_private *tp)
++{
++ /*
++ * Notify upper layer about the state of the connection
++ * to the BE.
++ */
++ if (tp->is_connected) {
++ vtpm_vd_status(tp->chip, TPM_VD_STATUS_CONNECTED);
++ } else {
++ vtpm_vd_status(tp->chip, TPM_VD_STATUS_DISCONNECTED);
++ }
++}
++
++
++static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
++{
++ /*
++ * Don't notify upper layer if we are in suspend mode and
++ * should disconnect - assumption is that we will resume
++ * The mutex keeps apps from sending.
++ */
++ if (is_connected == 0 && tp->is_suspended == 1) {
++ return;
++ }
++
++ /*
++ * Unlock the mutex if we are connected again
++ * after being suspended - now resuming.
++ * This also removes the suspend state.
++ */
++ if (is_connected == 1 && tp->is_suspended == 1) {
++ tp->is_suspended = 0;
++ /* unlock, so apps can resume sending */
++ mutex_unlock(&suspend_lock);
++ }
++
++ if (is_connected != tp->is_connected) {
++ tp->is_connected = is_connected;
++ tpmif_notify_upperlayer(tp);
++ }
++}
++
++
++
++/* =================================================================
++ * Initialization function.
++ * =================================================================
++ */
++
++
++static int __init tpmif_init(void)
++{
++ long rc = 0;
++ struct tpm_private *tp;
++
++ if (is_initial_xendomain())
++ return -EPERM;
++
++ tp = tpm_private_get();
++ if (!tp) {
++ rc = -ENOMEM;
++ goto failexit;
++ }
++
++ IPRINTK("Initialising the vTPM driver.\n");
++ if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE,
++ &gref_head ) < 0) {
++ rc = -EFAULT;
++ goto gnttab_alloc_failed;
++ }
++
++ init_tpm_xenbus();
++ return 0;
++
++gnttab_alloc_failed:
++ tpm_private_put();
++failexit:
++
++ return (int)rc;
++}
++
++
++void __exit tpmif_exit(void)
++{
++ exit_tpm_xenbus();
++ tpm_private_put();
++ gnttab_free_grant_references(gref_head);
++}
++
++module_init(tpmif_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/char/tty_io.c linux-2.6.18-xen/drivers/char/tty_io.c
+--- linux-2.6.18.1/drivers/char/tty_io.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/char/tty_io.c 2006-09-22 16:38:35.000000000 +0200
+@@ -130,6 +130,8 @@
+ vt.c for deeply disgusting hack reasons */
+ DEFINE_MUTEX(tty_mutex);
+
++int console_use_vt = 1;
++
+ #ifdef CONFIG_UNIX98_PTYS
+ extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
+ extern int pty_limit; /* Config limit on Unix98 ptys */
+@@ -2483,7 +2485,7 @@
+ goto got_driver;
+ }
+ #ifdef CONFIG_VT
+- if (device == MKDEV(TTY_MAJOR,0)) {
++ if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) {
+ extern struct tty_driver *console_driver;
+ driver = console_driver;
+ index = fg_console;
+@@ -3909,6 +3911,8 @@
+ #endif
+
+ #ifdef CONFIG_VT
++ if (!console_use_vt)
++ goto out_vt;
+ cdev_init(&vc0_cdev, &console_fops);
+ if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+ register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+@@ -3916,6 +3920,7 @@
+ class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
+ vty_init();
++ out_vt:
+ #endif
+ return 0;
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/firmware/Kconfig linux-2.6.18-xen/drivers/firmware/Kconfig
+--- linux-2.6.18.1/drivers/firmware/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/firmware/Kconfig 2006-09-04 16:31:04.000000000 +0200
+@@ -7,7 +7,7 @@
+
+ config EDD
+ tristate "BIOS Enhanced Disk Drive calls determine boot disk"
+- depends on !IA64
++ depends on !IA64 && !XEN
+ help
+ Say Y or M here if you want to enable BIOS Enhanced Disk Drive
+ Services real mode BIOS calls to determine which disk
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/ide/ide-lib.c linux-2.6.18-xen/drivers/ide/ide-lib.c
+--- linux-2.6.18.1/drivers/ide/ide-lib.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/ide/ide-lib.c 2006-09-04 16:31:04.000000000 +0200
+@@ -408,10 +408,10 @@
+ {
+ u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */
+
+- if (!PCI_DMA_BUS_IS_PHYS) {
+- addr = BLK_BOUNCE_ANY;
+- } else if (on && drive->media == ide_disk) {
+- if (HWIF(drive)->pci_dev)
++ if (on && drive->media == ide_disk) {
++ if (!PCI_DMA_BUS_IS_PHYS)
++ addr = BLK_BOUNCE_ANY;
++ else if (HWIF(drive)->pci_dev)
+ addr = HWIF(drive)->pci_dev->dma_mask;
+ }
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/Makefile linux-2.6.18-xen/drivers/Makefile
+--- linux-2.6.18.1/drivers/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/Makefile 2006-09-04 16:31:03.000000000 +0200
+@@ -31,6 +31,7 @@
+ obj-$(CONFIG_NUBUS) += nubus/
+ obj-$(CONFIG_ATM) += atm/
+ obj-$(CONFIG_PPC_PMAC) += macintosh/
++obj-$(CONFIG_XEN) += xen/
+ obj-$(CONFIG_IDE) += ide/
+ obj-$(CONFIG_FC4) += fc4/
+ obj-$(CONFIG_SCSI) += scsi/
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/buffer_sync.c linux-2.6.18-xen/drivers/oprofile/buffer_sync.c
+--- linux-2.6.18.1/drivers/oprofile/buffer_sync.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/buffer_sync.c 2006-09-04 16:31:08.000000000 +0200
+@@ -6,6 +6,10 @@
+ *
+ * @author John Levon <levon at movementarian.org>
+ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ *
+ * This is the core of the buffer management. Each
+ * CPU buffer is processed and entered into the
+ * global event buffer. Such processing is necessary
+@@ -275,15 +279,31 @@
+ last_cookie = INVALID_COOKIE;
+ }
+
+-static void add_kernel_ctx_switch(unsigned int in_kernel)
++static void add_cpu_mode_switch(unsigned int cpu_mode)
+ {
+ add_event_entry(ESCAPE_CODE);
+- if (in_kernel)
+- add_event_entry(KERNEL_ENTER_SWITCH_CODE);
+- else
+- add_event_entry(KERNEL_EXIT_SWITCH_CODE);
++ switch (cpu_mode) {
++ case CPU_MODE_USER:
++ add_event_entry(USER_ENTER_SWITCH_CODE);
++ break;
++ case CPU_MODE_KERNEL:
++ add_event_entry(KERNEL_ENTER_SWITCH_CODE);
++ break;
++ case CPU_MODE_XEN:
++ add_event_entry(XEN_ENTER_SWITCH_CODE);
++ break;
++ default:
++ break;
++ }
+ }
+-
++
++static void add_domain_switch(unsigned long domain_id)
++{
++ add_event_entry(ESCAPE_CODE);
++ add_event_entry(DOMAIN_SWITCH_CODE);
++ add_event_entry(domain_id);
++}
++
+ static void
+ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
+ {
+@@ -348,9 +368,9 @@
+ * for later lookup from userspace.
+ */
+ static int
+-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
++add_sample(struct mm_struct * mm, struct op_sample * s, int cpu_mode)
+ {
+- if (in_kernel) {
++ if (cpu_mode >= CPU_MODE_KERNEL) {
+ add_sample_entry(s->eip, s->event);
+ return 1;
+ } else if (mm) {
+@@ -496,10 +516,11 @@
+ struct mm_struct *mm = NULL;
+ struct task_struct * new;
+ unsigned long cookie = 0;
+- int in_kernel = 1;
++ int cpu_mode = 1;
+ unsigned int i;
+ sync_buffer_state state = sb_buffer_start;
+ unsigned long available;
++ int domain_switch = 0;
+
+ mutex_lock(&buffer_mutex);
+
+@@ -512,16 +533,18 @@
+ for (i = 0; i < available; ++i) {
+ struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
+
+- if (is_code(s->eip)) {
+- if (s->event <= CPU_IS_KERNEL) {
+- /* kernel/userspace switch */
+- in_kernel = s->event;
++ if (is_code(s->eip) && !domain_switch) {
++ if (s->event <= CPU_MODE_XEN) {
++ /* xen/kernel/userspace switch */
++ cpu_mode = s->event;
+ if (state == sb_buffer_start)
+ state = sb_sample_start;
+- add_kernel_ctx_switch(s->event);
++ add_cpu_mode_switch(s->event);
+ } else if (s->event == CPU_TRACE_BEGIN) {
+ state = sb_bt_start;
+ add_trace_begin();
++ } else if (s->event == CPU_DOMAIN_SWITCH) {
++ domain_switch = 1;
+ } else {
+ struct mm_struct * oldmm = mm;
+
+@@ -535,11 +558,16 @@
+ add_user_ctx_switch(new, cookie);
+ }
+ } else {
+- if (state >= sb_bt_start &&
+- !add_sample(mm, s, in_kernel)) {
+- if (state == sb_bt_start) {
+- state = sb_bt_ignore;
+- atomic_inc(&oprofile_stats.bt_lost_no_mapping);
++ if (domain_switch) {
++ add_domain_switch(s->eip);
++ domain_switch = 0;
++ } else {
++ if (state >= sb_bt_start &&
++ !add_sample(mm, s, cpu_mode)) {
++ if (state == sb_bt_start) {
++ state = sb_bt_ignore;
++ atomic_inc(&oprofile_stats.bt_lost_no_mapping);
++ }
+ }
+ }
+ }
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/cpu_buffer.c linux-2.6.18-xen/drivers/oprofile/cpu_buffer.c
+--- linux-2.6.18.1/drivers/oprofile/cpu_buffer.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/cpu_buffer.c 2006-09-04 16:31:08.000000000 +0200
+@@ -6,6 +6,10 @@
+ *
+ * @author John Levon <levon at movementarian.org>
+ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ *
+ * Each CPU has a local buffer that stores PC value/event
+ * pairs. We also log context switches when we notice them.
+ * Eventually each CPU's buffer is processed into the global
+@@ -34,6 +38,8 @@
+ #define DEFAULT_TIMER_EXPIRE (HZ / 10)
+ static int work_enabled;
+
++static int32_t current_domain = COORDINATOR_DOMAIN;
++
+ void free_cpu_buffers(void)
+ {
+ int i;
+@@ -57,7 +63,7 @@
+ goto fail;
+
+ b->last_task = NULL;
+- b->last_is_kernel = -1;
++ b->last_cpu_mode = -1;
+ b->tracing = 0;
+ b->buffer_size = buffer_size;
+ b->tail_pos = 0;
+@@ -113,7 +119,7 @@
+ * collected will populate the buffer with proper
+ * values to initialize the buffer
+ */
+- cpu_buf->last_is_kernel = -1;
++ cpu_buf->last_cpu_mode = -1;
+ cpu_buf->last_task = NULL;
+ }
+
+@@ -163,13 +169,13 @@
+ * because of the head/tail separation of the writer and reader
+ * of the CPU buffer.
+ *
+- * is_kernel is needed because on some architectures you cannot
++ * cpu_mode is needed because on some architectures you cannot
+ * tell if you are in kernel or user space simply by looking at
+- * pc. We tag this in the buffer by generating kernel enter/exit
+- * events whenever is_kernel changes
++ * pc. We tag this in the buffer by generating kernel/user (and xen)
++ * enter events whenever cpu_mode changes
+ */
+ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
+- int is_kernel, unsigned long event)
++ int cpu_mode, unsigned long event)
+ {
+ struct task_struct * task;
+
+@@ -180,18 +186,20 @@
+ return 0;
+ }
+
+- is_kernel = !!is_kernel;
++ WARN_ON(cpu_mode > CPU_MODE_XEN);
+
+ task = current;
+
+ /* notice a switch from user->kernel or vice versa */
+- if (cpu_buf->last_is_kernel != is_kernel) {
+- cpu_buf->last_is_kernel = is_kernel;
+- add_code(cpu_buf, is_kernel);
++ if (cpu_buf->last_cpu_mode != cpu_mode) {
++ cpu_buf->last_cpu_mode = cpu_mode;
++ add_code(cpu_buf, cpu_mode);
+ }
+-
++
+ /* notice a task switch */
+- if (cpu_buf->last_task != task) {
++ /* if not processing other domain samples */
++ if ((cpu_buf->last_task != task) &&
++ (current_domain == COORDINATOR_DOMAIN)) {
+ cpu_buf->last_task = task;
+ add_code(cpu_buf, (unsigned long)task);
+ }
+@@ -275,6 +283,25 @@
+ add_sample(cpu_buf, pc, 0);
+ }
+
++int oprofile_add_domain_switch(int32_t domain_id)
++{
++ struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
++
++ /* should have space for switching into and out of domain
++ (2 slots each) plus one sample and one cpu mode switch */
++ if (((nr_available_slots(cpu_buf) < 6) &&
++ (domain_id != COORDINATOR_DOMAIN)) ||
++ (nr_available_slots(cpu_buf) < 2))
++ return 0;
++
++ add_code(cpu_buf, CPU_DOMAIN_SWITCH);
++ add_sample(cpu_buf, domain_id, 0);
++
++ current_domain = domain_id;
++
++ return 1;
++}
++
+ /*
+ * This serves to avoid cpu buffer overflow, and makes sure
+ * the task mortuary progresses
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/cpu_buffer.h linux-2.6.18-xen/drivers/oprofile/cpu_buffer.h
+--- linux-2.6.18.1/drivers/oprofile/cpu_buffer.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/cpu_buffer.h 2006-09-04 16:31:08.000000000 +0200
+@@ -36,7 +36,7 @@
+ volatile unsigned long tail_pos;
+ unsigned long buffer_size;
+ struct task_struct * last_task;
+- int last_is_kernel;
++ int last_cpu_mode;
+ int tracing;
+ struct op_sample * buffer;
+ unsigned long sample_received;
+@@ -51,7 +51,10 @@
+ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
+
+ /* transient events for the CPU buffer -> event buffer */
+-#define CPU_IS_KERNEL 1
+-#define CPU_TRACE_BEGIN 2
++#define CPU_MODE_USER 0
++#define CPU_MODE_KERNEL 1
++#define CPU_MODE_XEN 2
++#define CPU_TRACE_BEGIN 3
++#define CPU_DOMAIN_SWITCH 4
+
+ #endif /* OPROFILE_CPU_BUFFER_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/event_buffer.h linux-2.6.18-xen/drivers/oprofile/event_buffer.h
+--- linux-2.6.18.1/drivers/oprofile/event_buffer.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/event_buffer.h 2006-09-04 16:31:08.000000000 +0200
+@@ -29,15 +29,20 @@
+ #define CPU_SWITCH_CODE 2
+ #define COOKIE_SWITCH_CODE 3
+ #define KERNEL_ENTER_SWITCH_CODE 4
+-#define KERNEL_EXIT_SWITCH_CODE 5
++#define USER_ENTER_SWITCH_CODE 5
+ #define MODULE_LOADED_CODE 6
+ #define CTX_TGID_CODE 7
+ #define TRACE_BEGIN_CODE 8
+ #define TRACE_END_CODE 9
++#define XEN_ENTER_SWITCH_CODE 10
++#define DOMAIN_SWITCH_CODE 11
+
+ #define INVALID_COOKIE ~0UL
+ #define NO_COOKIE 0UL
+
++/* Constant used to refer to coordinator domain (Xen) */
++#define COORDINATOR_DOMAIN -1
++
+ /* add data to the event buffer */
+ void add_event_entry(unsigned long data);
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/oprof.c linux-2.6.18-xen/drivers/oprofile/oprof.c
+--- linux-2.6.18.1/drivers/oprofile/oprof.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/oprof.c 2006-09-04 16:31:08.000000000 +0200
+@@ -5,6 +5,10 @@
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon at movementarian.org>
++ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
+ */
+
+ #include <linux/kernel.h>
+@@ -19,7 +23,7 @@
+ #include "cpu_buffer.h"
+ #include "buffer_sync.h"
+ #include "oprofile_stats.h"
+-
++
+ struct oprofile_operations oprofile_ops;
+
+ unsigned long oprofile_started;
+@@ -33,6 +37,32 @@
+ */
+ static int timer = 0;
+
++int oprofile_set_active(int active_domains[], unsigned int adomains)
++{
++ int err;
++
++ if (!oprofile_ops.set_active)
++ return -EINVAL;
++
++ mutex_lock(&start_mutex);
++ err = oprofile_ops.set_active(active_domains, adomains);
++ mutex_unlock(&start_mutex);
++ return err;
++}
++
++int oprofile_set_passive(int passive_domains[], unsigned int pdomains)
++{
++ int err;
++
++ if (!oprofile_ops.set_passive)
++ return -EINVAL;
++
++ mutex_lock(&start_mutex);
++ err = oprofile_ops.set_passive(passive_domains, pdomains);
++ mutex_unlock(&start_mutex);
++ return err;
++}
++
+ int oprofile_setup(void)
+ {
+ int err;
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/oprof.h linux-2.6.18-xen/drivers/oprofile/oprof.h
+--- linux-2.6.18.1/drivers/oprofile/oprof.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/oprof.h 2006-09-04 16:31:08.000000000 +0200
+@@ -35,5 +35,8 @@
+ void oprofile_timer_init(struct oprofile_operations * ops);
+
+ int oprofile_set_backtrace(unsigned long depth);
++
++int oprofile_set_active(int active_domains[], unsigned int adomains);
++int oprofile_set_passive(int passive_domains[], unsigned int pdomains);
+
+ #endif /* OPROF_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/oprofile/oprofile_files.c linux-2.6.18-xen/drivers/oprofile/oprofile_files.c
+--- linux-2.6.18.1/drivers/oprofile/oprofile_files.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/oprofile/oprofile_files.c 2006-09-04 16:31:08.000000000 +0200
+@@ -5,15 +5,21 @@
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon at movementarian.org>
++ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
+ */
+
+ #include <linux/fs.h>
+ #include <linux/oprofile.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
+
+ #include "event_buffer.h"
+ #include "oprofile_stats.h"
+ #include "oprof.h"
+-
++
+ unsigned long fs_buffer_size = 131072;
+ unsigned long fs_cpu_buffer_size = 8192;
+ unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
+@@ -117,11 +123,208 @@
+ static struct file_operations dump_fops = {
+ .write = dump_write,
+ };
+-
++
++#ifdef CONFIG_XEN
++
++#define TMPBUFSIZE 512
++
++static unsigned int adomains = 0;
++static int active_domains[MAX_OPROF_DOMAINS + 1];
++static DEFINE_MUTEX(adom_mutex);
++
++static ssize_t adomain_write(struct file * file, char const __user * buf,
++ size_t count, loff_t * offset)
++{
++ char *tmpbuf;
++ char *startp, *endp;
++ int i;
++ unsigned long val;
++ ssize_t retval = count;
++
++ if (*offset)
++ return -EINVAL;
++ if (count > TMPBUFSIZE - 1)
++ return -EINVAL;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ if (copy_from_user(tmpbuf, buf, count)) {
++ kfree(tmpbuf);
++ return -EFAULT;
++ }
++ tmpbuf[count] = 0;
++
++ mutex_lock(&adom_mutex);
++
++ startp = tmpbuf;
++ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
++ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
++ val = simple_strtoul(startp, &endp, 0);
++ if (endp == startp)
++ break;
++ while (ispunct(*endp) || isspace(*endp))
++ endp++;
++ active_domains[i] = val;
++ if (active_domains[i] != val)
++ /* Overflow, force error below */
++ i = MAX_OPROF_DOMAINS + 1;
++ startp = endp;
++ }
++ /* Force error on trailing junk */
++ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++
++ kfree(tmpbuf);
++
++ if (adomains > MAX_OPROF_DOMAINS
++ || oprofile_set_active(active_domains, adomains)) {
++ adomains = 0;
++ retval = -EINVAL;
++ }
++
++ mutex_unlock(&adom_mutex);
++ return retval;
++}
++
++static ssize_t adomain_read(struct file * file, char __user * buf,
++ size_t count, loff_t * offset)
++{
++ char * tmpbuf;
++ size_t len;
++ int i;
++ ssize_t retval;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ mutex_lock(&adom_mutex);
++
++ len = 0;
++ for (i = 0; i < adomains; i++)
++ len += snprintf(tmpbuf + len,
++ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
++ "%u ", active_domains[i]);
++ WARN_ON(len > TMPBUFSIZE);
++ if (len != 0 && len <= TMPBUFSIZE)
++ tmpbuf[len-1] = '\n';
++
++ mutex_unlock(&adom_mutex);
++
++ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++
++ kfree(tmpbuf);
++ return retval;
++}
++
++
++static struct file_operations active_domain_ops = {
++ .read = adomain_read,
++ .write = adomain_write,
++};
++
++static unsigned int pdomains = 0;
++static int passive_domains[MAX_OPROF_DOMAINS];
++static DEFINE_MUTEX(pdom_mutex);
++
++static ssize_t pdomain_write(struct file * file, char const __user * buf,
++ size_t count, loff_t * offset)
++{
++ char *tmpbuf;
++ char *startp, *endp;
++ int i;
++ unsigned long val;
++ ssize_t retval = count;
++
++ if (*offset)
++ return -EINVAL;
++ if (count > TMPBUFSIZE - 1)
++ return -EINVAL;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ if (copy_from_user(tmpbuf, buf, count)) {
++ kfree(tmpbuf);
++ return -EFAULT;
++ }
++ tmpbuf[count] = 0;
++
++ mutex_lock(&pdom_mutex);
++
++ startp = tmpbuf;
++ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
++ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
++ val = simple_strtoul(startp, &endp, 0);
++ if (endp == startp)
++ break;
++ while (ispunct(*endp) || isspace(*endp))
++ endp++;
++ passive_domains[i] = val;
++ if (passive_domains[i] != val)
++ /* Overflow, force error below */
++ i = MAX_OPROF_DOMAINS + 1;
++ startp = endp;
++ }
++ /* Force error on trailing junk */
++ pdomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++
++ kfree(tmpbuf);
++
++ if (pdomains > MAX_OPROF_DOMAINS
++ || oprofile_set_passive(passive_domains, pdomains)) {
++ pdomains = 0;
++ retval = -EINVAL;
++ }
++
++ mutex_unlock(&pdom_mutex);
++ return retval;
++}
++
++static ssize_t pdomain_read(struct file * file, char __user * buf,
++ size_t count, loff_t * offset)
++{
++ char * tmpbuf;
++ size_t len;
++ int i;
++ ssize_t retval;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ mutex_lock(&pdom_mutex);
++
++ len = 0;
++ for (i = 0; i < pdomains; i++)
++ len += snprintf(tmpbuf + len,
++ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
++ "%u ", passive_domains[i]);
++ WARN_ON(len > TMPBUFSIZE);
++ if (len != 0 && len <= TMPBUFSIZE)
++ tmpbuf[len-1] = '\n';
++
++ mutex_unlock(&pdom_mutex);
++
++ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++
++ kfree(tmpbuf);
++ return retval;
++}
++
++static struct file_operations passive_domain_ops = {
++ .read = pdomain_read,
++ .write = pdomain_write,
++};
++
++#endif /* CONFIG_XEN */
++
+ void oprofile_create_files(struct super_block * sb, struct dentry * root)
+ {
+ oprofilefs_create_file(sb, root, "enable", &enable_fops);
+ oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
++#ifdef CONFIG_XEN
++ oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops);
++ oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops);
++#endif
+ oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
+ oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
+ oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/pci/Kconfig linux-2.6.18-xen/drivers/pci/Kconfig
+--- linux-2.6.18.1/drivers/pci/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/pci/Kconfig 2006-09-04 16:31:08.000000000 +0200
+@@ -5,6 +5,7 @@
+ bool "Message Signaled Interrupts (MSI and MSI-X)"
+ depends on PCI
+ depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
++ depends on !XEN
+ help
+ This allows device drivers to enable MSI (Message Signaled
+ Interrupts). Message Signaled Interrupts enable a device to
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/serial/Kconfig linux-2.6.18-xen/drivers/serial/Kconfig
+--- linux-2.6.18.1/drivers/serial/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/drivers/serial/Kconfig 2006-09-22 16:38:35.000000000 +0200
+@@ -11,6 +11,7 @@
+ config SERIAL_8250
+ tristate "8250/16550 and compatible serial support"
+ depends on (BROKEN || !SPARC)
++ depends on !XEN_DISABLE_SERIAL
+ select SERIAL_CORE
+ ---help---
+ This selects whether you want to include the driver for the standard
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/balloon/balloon.c linux-2.6.18-xen/drivers/xen/balloon/balloon.c
+--- linux-2.6.18.1/drivers/xen/balloon/balloon.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/balloon/balloon.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,637 @@
++/******************************************************************************
++ * balloon.c
++ *
++ * Xen balloon driver - enables returning/claiming memory to/from Xen.
++ *
++ * Copyright (c) 2003, B Dragovic
++ * Copyright (c) 2003-2004, M Williamson, K Fraser
++ * Copyright (c) 2005 Dan M. Smith, IBM 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <linux/smp_lock.h>
++#include <linux/pagemap.h>
++#include <linux/bootmem.h>
++#include <linux/highmem.h>
++#include <linux/vmalloc.h>
++#include <xen/xen_proc.h>
++#include <asm/hypervisor.h>
++#include <xen/balloon.h>
++#include <xen/interface/memory.h>
++#include <asm/pgalloc.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/tlb.h>
++#include <linux/list.h>
++
++#include <xen/xenbus.h>
++
++#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
++
++#ifdef CONFIG_PROC_FS
++static struct proc_dir_entry *balloon_pde;
++#endif
++
++static DECLARE_MUTEX(balloon_mutex);
++
++/*
++ * Protects atomic reservation decrease/increase against concurrent increases.
++ * Also protects non-atomic updates of current_pages and driver_pages, and
++ * balloon lists.
++ */
++DEFINE_SPINLOCK(balloon_lock);
++
++/* We aim for 'current allocation' == 'target allocation'. */
++static unsigned long current_pages;
++static unsigned long target_pages;
++
++/* We increase/decrease in batches which fit in a page */
++static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
++
++/* VM /proc information for memory */
++extern unsigned long totalram_pages;
++
++/* We may hit the hard limit in Xen. If we do then we remember it. */
++static unsigned long hard_limit;
++
++/*
++ * Drivers may alter the memory reservation independently, but they must
++ * inform the balloon driver so that we can avoid hitting the hard limit.
++ */
++static unsigned long driver_pages;
++
++/* List of ballooned pages, threaded through the mem_map array. */
++static LIST_HEAD(ballooned_pages);
++static unsigned long balloon_low, balloon_high;
++
++/* Main work function, always executed in process context. */
++static void balloon_process(void *unused);
++static DECLARE_WORK(balloon_worker, balloon_process, NULL);
++static struct timer_list balloon_timer;
++
++/* When ballooning out (allocating memory to return to Xen) we don't really
++ want the kernel to try too hard since that can trigger the oom killer. */
++#define GFP_BALLOON \
++ (GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC)
++
++#define PAGE_TO_LIST(p) (&(p)->lru)
++#define LIST_TO_PAGE(l) list_entry((l), struct page, lru)
++#define UNLIST_PAGE(p) \
++ do { \
++ list_del(PAGE_TO_LIST(p)); \
++ PAGE_TO_LIST(p)->next = NULL; \
++ PAGE_TO_LIST(p)->prev = NULL; \
++ } while(0)
++
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "xen_mem: " fmt, ##args)
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "xen_mem: " fmt, ##args)
++
++/* balloon_append: add the given page to the balloon. */
++static void balloon_append(struct page *page)
++{
++ /* Lowmem is re-populated first, so highmem pages go at list tail. */
++ if (PageHighMem(page)) {
++ list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
++ balloon_high++;
++ } else {
++ list_add(PAGE_TO_LIST(page), &ballooned_pages);
++ balloon_low++;
++ }
++}
++
++/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
++static struct page *balloon_retrieve(void)
++{
++ struct page *page;
++
++ if (list_empty(&ballooned_pages))
++ return NULL;
++
++ page = LIST_TO_PAGE(ballooned_pages.next);
++ UNLIST_PAGE(page);
++
++ if (PageHighMem(page))
++ balloon_high--;
++ else
++ balloon_low--;
++
++ return page;
++}
++
++static struct page *balloon_first_page(void)
++{
++ if (list_empty(&ballooned_pages))
++ return NULL;
++ return LIST_TO_PAGE(ballooned_pages.next);
++}
++
++static struct page *balloon_next_page(struct page *page)
++{
++ struct list_head *next = PAGE_TO_LIST(page)->next;
++ if (next == &ballooned_pages)
++ return NULL;
++ return LIST_TO_PAGE(next);
++}
++
++static void balloon_alarm(unsigned long unused)
++{
++ schedule_work(&balloon_worker);
++}
++
++static unsigned long current_target(void)
++{
++ unsigned long target = min(target_pages, hard_limit);
++ if (target > (current_pages + balloon_low + balloon_high))
++ target = current_pages + balloon_low + balloon_high;
++ return target;
++}
++
++static int increase_reservation(unsigned long nr_pages)
++{
++ unsigned long pfn, i, flags;
++ struct page *page;
++ long rc;
++ struct xen_memory_reservation reservation = {
++ .address_bits = 0,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++
++ if (nr_pages > ARRAY_SIZE(frame_list))
++ nr_pages = ARRAY_SIZE(frame_list);
++
++ balloon_lock(flags);
++
++ page = balloon_first_page();
++ for (i = 0; i < nr_pages; i++) {
++ BUG_ON(page == NULL);
++ frame_list[i] = page_to_pfn(page);;
++ page = balloon_next_page(page);
++ }
++
++ set_xen_guest_handle(reservation.extent_start, frame_list);
++ reservation.nr_extents = nr_pages;
++ rc = HYPERVISOR_memory_op(
++ XENMEM_populate_physmap, &reservation);
++ if (rc < nr_pages) {
++ if (rc > 0) {
++ int ret;
++
++ /* We hit the Xen hard limit: reprobe. */
++ reservation.nr_extents = rc;
++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &reservation);
++ BUG_ON(ret != rc);
++ }
++ if (rc >= 0)
++ hard_limit = current_pages + rc - driver_pages;
++ goto out;
++ }
++
++ for (i = 0; i < nr_pages; i++) {
++ page = balloon_retrieve();
++ BUG_ON(page == NULL);
++
++ pfn = page_to_pfn(page);
++ BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) &&
++ phys_to_machine_mapping_valid(pfn));
++
++ /* Update P->M and M->P tables. */
++ set_phys_to_machine(pfn, frame_list[i]);
++ xen_machphys_update(frame_list[i], pfn);
++
++ /* Link back into the page tables if not highmem. */
++ if (pfn < max_low_pfn) {
++ int ret;
++ ret = HYPERVISOR_update_va_mapping(
++ (unsigned long)__va(pfn << PAGE_SHIFT),
++ pfn_pte_ma(frame_list[i], PAGE_KERNEL),
++ 0);
++ BUG_ON(ret);
++ }
++
++ /* Relinquish the page back to the allocator. */
++ ClearPageReserved(page);
++ init_page_count(page);
++ __free_page(page);
++ }
++
++ current_pages += nr_pages;
++ totalram_pages = current_pages;
++
++ out:
++ balloon_unlock(flags);
++
++ return 0;
++}
++
++static int decrease_reservation(unsigned long nr_pages)
++{
++ unsigned long pfn, i, flags;
++ struct page *page;
++ void *v;
++ int need_sleep = 0;
++ int ret;
++ struct xen_memory_reservation reservation = {
++ .address_bits = 0,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++
++ if (nr_pages > ARRAY_SIZE(frame_list))
++ nr_pages = ARRAY_SIZE(frame_list);
++
++ for (i = 0; i < nr_pages; i++) {
++ if ((page = alloc_page(GFP_BALLOON)) == NULL) {
++ nr_pages = i;
++ need_sleep = 1;
++ break;
++ }
++
++ pfn = page_to_pfn(page);
++ frame_list[i] = pfn_to_mfn(pfn);
++
++ if (!PageHighMem(page)) {
++ v = phys_to_virt(pfn << PAGE_SHIFT);
++ scrub_pages(v, 1);
++ ret = HYPERVISOR_update_va_mapping(
++ (unsigned long)v, __pte_ma(0), 0);
++ BUG_ON(ret);
++ }
++#ifdef CONFIG_XEN_SCRUB_PAGES
++ else {
++ v = kmap(page);
++ scrub_pages(v, 1);
++ kunmap(page);
++ }
++#endif
++ }
++
++ /* Ensure that ballooned highmem pages don't have kmaps. */
++ kmap_flush_unused();
++ flush_tlb_all();
++
++ balloon_lock(flags);
++
++ /* No more mappings: invalidate P2M and add to balloon. */
++ for (i = 0; i < nr_pages; i++) {
++ pfn = mfn_to_pfn(frame_list[i]);
++ set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
++ balloon_append(pfn_to_page(pfn));
++ }
++
++ set_xen_guest_handle(reservation.extent_start, frame_list);
++ reservation.nr_extents = nr_pages;
++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
++ BUG_ON(ret != nr_pages);
++
++ current_pages -= nr_pages;
++ totalram_pages = current_pages;
++
++ balloon_unlock(flags);
++
++ return need_sleep;
++}
++
++/*
++ * We avoid multiple worker processes conflicting via the balloon mutex.
++ * We may of course race updates of the target counts (which are protected
++ * by the balloon lock), or with changes to the Xen hard limit, but we will
++ * recover from these in time.
++ */
++static void balloon_process(void *unused)
++{
++ int need_sleep = 0;
++ long credit;
++
++ down(&balloon_mutex);
++
++ do {
++ credit = current_target() - current_pages;
++ if (credit > 0)
++ need_sleep = (increase_reservation(credit) != 0);
++ if (credit < 0)
++ need_sleep = (decrease_reservation(-credit) != 0);
++
++#ifndef CONFIG_PREEMPT
++ if (need_resched())
++ schedule();
++#endif
++ } while ((credit != 0) && !need_sleep);
++
++ /* Schedule more work if there is some still to be done. */
++ if (current_target() != current_pages)
++ mod_timer(&balloon_timer, jiffies + HZ);
++
++ up(&balloon_mutex);
++}
++
++/* Resets the Xen limit, sets new target, and kicks off processing. */
++static void set_new_target(unsigned long target)
++{
++ /* No need for lock. Not read-modify-write updates. */
++ hard_limit = ~0UL;
++ target_pages = target;
++ schedule_work(&balloon_worker);
++}
++
++static struct xenbus_watch target_watch =
++{
++ .node = "memory/target"
++};
++
++/* React to a change in the target key */
++static void watch_target(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ unsigned long long new_target;
++ int err;
++
++ err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
++ if (err != 1) {
++ /* This is ok (for domain0 at least) - so just return */
++ return;
++ }
++
++ /* The given memory/target value is in KiB, so it needs converting to
++ * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
++ */
++ set_new_target(new_target >> (PAGE_SHIFT - 10));
++}
++
++static int balloon_init_watcher(struct notifier_block *notifier,
++ unsigned long event,
++ void *data)
++{
++ int err;
++
++ err = register_xenbus_watch(&target_watch);
++ if (err)
++ printk(KERN_ERR "Failed to set balloon watcher\n");
++
++ return NOTIFY_DONE;
++}
++
++#ifdef CONFIG_PROC_FS
++static int balloon_write(struct file *file, const char __user *buffer,
++ unsigned long count, void *data)
++{
++ char memstring[64], *endchar;
++ unsigned long long target_bytes;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ if (count <= 1)
++ return -EBADMSG; /* runt */
++ if (count > sizeof(memstring))
++ return -EFBIG; /* too long */
++
++ if (copy_from_user(memstring, buffer, count))
++ return -EFAULT;
++ memstring[sizeof(memstring)-1] = '\0';
++
++ target_bytes = memparse(memstring, &endchar);
++ set_new_target(target_bytes >> PAGE_SHIFT);
++
++ return count;
++}
++
++static int balloon_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(
++ page,
++ "Current allocation: %8lu kB\n"
++ "Requested target: %8lu kB\n"
++ "Low-mem balloon: %8lu kB\n"
++ "High-mem balloon: %8lu kB\n"
++ "Driver pages: %8lu kB\n"
++ "Xen hard limit: ",
++ PAGES2KB(current_pages), PAGES2KB(target_pages),
++ PAGES2KB(balloon_low), PAGES2KB(balloon_high),
++ PAGES2KB(driver_pages));
++
++ if (hard_limit != ~0UL)
++ len += sprintf(page + len, "%8lu kB\n", PAGES2KB(hard_limit));
++ else
++ len += sprintf(page + len, " ??? kB\n");
++
++ *eof = 1;
++ return len;
++}
++#endif
++
++static struct notifier_block xenstore_notifier;
++
++static int __init balloon_init(void)
++{
++ unsigned long pfn;
++ struct page *page;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ IPRINTK("Initialising balloon driver.\n");
++
++ current_pages = min(xen_start_info->nr_pages, max_pfn);
++ totalram_pages = current_pages;
++ target_pages = current_pages;
++ balloon_low = 0;
++ balloon_high = 0;
++ driver_pages = 0UL;
++ hard_limit = ~0UL;
++
++ init_timer(&balloon_timer);
++ balloon_timer.data = 0;
++ balloon_timer.function = balloon_alarm;
++
++#ifdef CONFIG_PROC_FS
++ if ((balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL) {
++ WPRINTK("Unable to create /proc/xen/balloon.\n");
++ return -1;
++ }
++
++ balloon_pde->read_proc = balloon_read;
++ balloon_pde->write_proc = balloon_write;
++#endif
++
++ /* Initialise the balloon with excess memory space. */
++ for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
++ page = pfn_to_page(pfn);
++ if (!PageReserved(page))
++ balloon_append(page);
++ }
++
++ target_watch.callback = watch_target;
++ xenstore_notifier.notifier_call = balloon_init_watcher;
++
++ register_xenstore_notifier(&xenstore_notifier);
++
++ return 0;
++}
++
++subsys_initcall(balloon_init);
++
++void balloon_update_driver_allowance(long delta)
++{
++ unsigned long flags;
++
++ balloon_lock(flags);
++ driver_pages += delta;
++ balloon_unlock(flags);
++}
++
++static int dealloc_pte_fn(
++ pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
++{
++ unsigned long mfn = pte_mfn(*pte);
++ int ret;
++ struct xen_memory_reservation reservation = {
++ .nr_extents = 1,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++ set_xen_guest_handle(reservation.extent_start, &mfn);
++ set_pte_at(&init_mm, addr, pte, __pte_ma(0));
++ set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
++ BUG_ON(ret != 1);
++ return 0;
++}
++
++struct page **alloc_empty_pages_and_pagevec(int nr_pages)
++{
++ unsigned long vaddr, flags;
++ struct page *page, **pagevec;
++ int i, ret;
++
++ pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
++ if (pagevec == NULL)
++ return NULL;
++
++ for (i = 0; i < nr_pages; i++) {
++ page = pagevec[i] = alloc_page(GFP_KERNEL);
++ if (page == NULL)
++ goto err;
++
++ vaddr = (unsigned long)page_address(page);
++
++ scrub_pages(vaddr, 1);
++
++ balloon_lock(flags);
++
++ if (xen_feature(XENFEAT_auto_translated_physmap)) {
++ unsigned long gmfn = page_to_pfn(page);
++ struct xen_memory_reservation reservation = {
++ .nr_extents = 1,
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++ set_xen_guest_handle(reservation.extent_start, &gmfn);
++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &reservation);
++ if (ret == 1)
++ ret = 0; /* success */
++ } else {
++ ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
++ dealloc_pte_fn, NULL);
++ }
++
++ if (ret != 0) {
++ balloon_unlock(flags);
++ __free_page(page);
++ goto err;
++ }
++
++ totalram_pages = --current_pages;
++
++ balloon_unlock(flags);
++ }
++
++ out:
++ schedule_work(&balloon_worker);
++ flush_tlb_all();
++ return pagevec;
++
++ err:
++ balloon_lock(flags);
++ while (--i >= 0)
++ balloon_append(pagevec[i]);
++ balloon_unlock(flags);
++ kfree(pagevec);
++ pagevec = NULL;
++ goto out;
++}
++
++void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
++{
++ unsigned long flags;
++ int i;
++
++ if (pagevec == NULL)
++ return;
++
++ balloon_lock(flags);
++ for (i = 0; i < nr_pages; i++) {
++ BUG_ON(page_count(pagevec[i]) != 1);
++ balloon_append(pagevec[i]);
++ }
++ balloon_unlock(flags);
++
++ kfree(pagevec);
++
++ schedule_work(&balloon_worker);
++}
++
++void balloon_release_driver_page(struct page *page)
++{
++ unsigned long flags;
++
++ balloon_lock(flags);
++ balloon_append(page);
++ driver_pages--;
++ balloon_unlock(flags);
++
++ schedule_work(&balloon_worker);
++}
++
++EXPORT_SYMBOL_GPL(balloon_update_driver_allowance);
++EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec);
++EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
++EXPORT_SYMBOL_GPL(balloon_release_driver_page);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/balloon/Makefile linux-2.6.18-xen/drivers/xen/balloon/Makefile
+--- linux-2.6.18.1/drivers/xen/balloon/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/balloon/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,2 @@
++
++obj-y += balloon.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkback/blkback.c linux-2.6.18-xen/drivers/xen/blkback/blkback.c
+--- linux-2.6.18.1/drivers/xen/blkback/blkback.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkback/blkback.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,549 @@
++/******************************************************************************
++ * arch/xen/drivers/blkif/backend/main.c
++ *
++ * Back-end of the driver for virtual block devices. This portion of the
++ * driver exports a 'unified' block-device interface that can be accessed
++ * by any operating system that implements a compatible front end. A
++ * reference front-end implementation can be found in:
++ * arch/xen/drivers/blkif/frontend
++ *
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Copyright (c) 2005, Christopher Clark
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/spinlock.h>
++#include <linux/kthread.h>
++#include <linux/list.h>
++#include <xen/balloon.h>
++#include <asm/hypervisor.h>
++#include <asm/hypercall.h>
++#include "common.h"
++
++/*
++ * These are rather arbitrary. They are fairly large because adjacent requests
++ * pulled from a communication ring are quite likely to end up being part of
++ * the same scatter/gather request at the disc.
++ *
++ * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
++ *
++ * This will increase the chances of being able to write whole tracks.
++ * 64 should be enough to keep us competitive with Linux.
++ */
++static int blkif_reqs = 64;
++module_param_named(reqs, blkif_reqs, int, 0);
++MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
++
++/* Run-time switchable: /sys/module/blkback/parameters/ */
++static unsigned int log_stats = 0;
++static unsigned int debug_lvl = 0;
++module_param(log_stats, int, 0644);
++module_param(debug_lvl, int, 0644);
++
++/*
++ * Each outstanding request that we've passed to the lower device layers has a
++ * 'pending_req' allocated to it. Each buffer_head that completes decrements
++ * the pendcnt towards zero. When it hits zero, the specified domain has a
++ * response queued for it, with the saved 'id' passed back.
++ */
++typedef struct {
++ blkif_t *blkif;
++ unsigned long id;
++ int nr_pages;
++ atomic_t pendcnt;
++ unsigned short operation;
++ int status;
++ struct list_head free_list;
++} pending_req_t;
++
++static pending_req_t *pending_reqs;
++static struct list_head pending_free;
++static DEFINE_SPINLOCK(pending_free_lock);
++static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
++
++#define BLKBACK_INVALID_HANDLE (~0)
++
++static struct page **pending_pages;
++static grant_handle_t *pending_grant_handles;
++
++static inline int vaddr_pagenr(pending_req_t *req, int seg)
++{
++ return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
++}
++
++static inline unsigned long vaddr(pending_req_t *req, int seg)
++{
++ unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
++ return (unsigned long)pfn_to_kaddr(pfn);
++}
++
++#define pending_handle(_req, _seg) \
++ (pending_grant_handles[vaddr_pagenr(_req, _seg)])
++
++
++static int do_block_io_op(blkif_t *blkif);
++static void dispatch_rw_block_io(blkif_t *blkif,
++ blkif_request_t *req,
++ pending_req_t *pending_req);
++static void make_response(blkif_t *blkif, unsigned long id,
++ unsigned short op, int st);
++
++/******************************************************************
++ * misc small helpers
++ */
++static pending_req_t* alloc_req(void)
++{
++ pending_req_t *req = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pending_free_lock, flags);
++ if (!list_empty(&pending_free)) {
++ req = list_entry(pending_free.next, pending_req_t, free_list);
++ list_del(&req->free_list);
++ }
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++ return req;
++}
++
++static void free_req(pending_req_t *req)
++{
++ unsigned long flags;
++ int was_empty;
++
++ spin_lock_irqsave(&pending_free_lock, flags);
++ was_empty = list_empty(&pending_free);
++ list_add(&req->free_list, &pending_free);
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++ if (was_empty)
++ wake_up(&pending_free_wq);
++}
++
++static void unplug_queue(blkif_t *blkif)
++{
++ if (blkif->plug == NULL)
++ return;
++ if (blkif->plug->unplug_fn)
++ blkif->plug->unplug_fn(blkif->plug);
++ blk_put_queue(blkif->plug);
++ blkif->plug = NULL;
++}
++
++static void plug_queue(blkif_t *blkif, struct bio *bio)
++{
++ request_queue_t *q = bdev_get_queue(bio->bi_bdev);
++
++ if (q == blkif->plug)
++ return;
++ unplug_queue(blkif);
++ blk_get_queue(q);
++ blkif->plug = q;
++}
++
++static void fast_flush_area(pending_req_t *req)
++{
++ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++ unsigned int i, invcount = 0;
++ grant_handle_t handle;
++ int ret;
++
++ for (i = 0; i < req->nr_pages; i++) {
++ handle = pending_handle(req, i);
++ if (handle == BLKBACK_INVALID_HANDLE)
++ continue;
++ gnttab_set_unmap_op(&unmap[i], vaddr(req, i), GNTMAP_host_map,
++ handle);
++ pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
++ invcount++;
++ }
++
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_unmap_grant_ref, unmap, invcount);
++ BUG_ON(ret);
++}
++
++/******************************************************************
++ * SCHEDULER FUNCTIONS
++ */
++
++static void print_stats(blkif_t *blkif)
++{
++ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d\n",
++ current->comm, blkif->st_oo_req,
++ blkif->st_rd_req, blkif->st_wr_req);
++ blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
++ blkif->st_rd_req = 0;
++ blkif->st_wr_req = 0;
++ blkif->st_oo_req = 0;
++}
++
++int blkif_schedule(void *arg)
++{
++ blkif_t *blkif = arg;
++
++ blkif_get(blkif);
++
++ if (debug_lvl)
++ printk(KERN_DEBUG "%s: started\n", current->comm);
++
++ while (!kthread_should_stop()) {
++ wait_event_interruptible(
++ blkif->wq,
++ blkif->waiting_reqs || kthread_should_stop());
++ wait_event_interruptible(
++ pending_free_wq,
++ !list_empty(&pending_free) || kthread_should_stop());
++
++ blkif->waiting_reqs = 0;
++ smp_mb(); /* clear flag *before* checking for work */
++
++ if (do_block_io_op(blkif))
++ blkif->waiting_reqs = 1;
++ unplug_queue(blkif);
++
++ if (log_stats && time_after(jiffies, blkif->st_print))
++ print_stats(blkif);
++ }
++
++ if (log_stats)
++ print_stats(blkif);
++ if (debug_lvl)
++ printk(KERN_DEBUG "%s: exiting\n", current->comm);
++
++ blkif->xenblkd = NULL;
++ blkif_put(blkif);
++
++ return 0;
++}
++
++/******************************************************************
++ * COMPLETION CALLBACK -- Called as bh->b_end_io()
++ */
++
++static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
++{
++ /* An error fails the entire request. */
++ if (!uptodate) {
++ DPRINTK("Buffer not up-to-date at end of operation\n");
++ pending_req->status = BLKIF_RSP_ERROR;
++ }
++
++ if (atomic_dec_and_test(&pending_req->pendcnt)) {
++ fast_flush_area(pending_req);
++ make_response(pending_req->blkif, pending_req->id,
++ pending_req->operation, pending_req->status);
++ blkif_put(pending_req->blkif);
++ free_req(pending_req);
++ }
++}
++
++static int end_block_io_op(struct bio *bio, unsigned int done, int error)
++{
++ if (bio->bi_size != 0)
++ return 1;
++ __end_block_io_op(bio->bi_private, !error);
++ bio_put(bio);
++ return error;
++}
++
++
++/******************************************************************************
++ * NOTIFICATION FROM GUEST OS.
++ */
++
++static void blkif_notify_work(blkif_t *blkif)
++{
++ blkif->waiting_reqs = 1;
++ wake_up(&blkif->wq);
++}
++
++irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ blkif_notify_work(dev_id);
++ return IRQ_HANDLED;
++}
++
++
++
++/******************************************************************
++ * DOWNWARD CALLS -- These interface with the block-device layer proper.
++ */
++
++static int do_block_io_op(blkif_t *blkif)
++{
++ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
++ blkif_request_t *req;
++ pending_req_t *pending_req;
++ RING_IDX rc, rp;
++ int more_to_do = 0;
++
++ rc = blk_ring->req_cons;
++ rp = blk_ring->sring->req_prod;
++ rmb(); /* Ensure we see queued requests up to 'rp'. */
++
++ while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) {
++
++ pending_req = alloc_req();
++ if (NULL == pending_req) {
++ blkif->st_oo_req++;
++ more_to_do = 1;
++ break;
++ }
++
++ req = RING_GET_REQUEST(blk_ring, rc);
++ blk_ring->req_cons = ++rc; /* before make_response() */
++
++ switch (req->operation) {
++ case BLKIF_OP_READ:
++ blkif->st_rd_req++;
++ dispatch_rw_block_io(blkif, req, pending_req);
++ break;
++ case BLKIF_OP_WRITE:
++ blkif->st_wr_req++;
++ dispatch_rw_block_io(blkif, req, pending_req);
++ break;
++ default:
++ DPRINTK("error: unknown block io operation [%d]\n",
++ req->operation);
++ make_response(blkif, req->id, req->operation,
++ BLKIF_RSP_ERROR);
++ free_req(pending_req);
++ break;
++ }
++ }
++ return more_to_do;
++}
++
++static void dispatch_rw_block_io(blkif_t *blkif,
++ blkif_request_t *req,
++ pending_req_t *pending_req)
++{
++ extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
++ int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
++ struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++ struct phys_req preq;
++ struct {
++ unsigned long buf; unsigned int nsec;
++ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++ unsigned int nseg;
++ struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++ int ret, i, nbio = 0;
++
++ /* Check that number of segments is sane. */
++ nseg = req->nr_segments;
++ if (unlikely(nseg == 0) ||
++ unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
++ DPRINTK("Bad number of segments in request (%d)\n", nseg);
++ goto fail_response;
++ }
++
++ preq.dev = req->handle;
++ preq.sector_number = req->sector_number;
++ preq.nr_sects = 0;
++
++ pending_req->blkif = blkif;
++ pending_req->id = req->id;
++ pending_req->operation = operation;
++ pending_req->status = BLKIF_RSP_OKAY;
++ pending_req->nr_pages = nseg;
++
++ for (i = 0; i < nseg; i++) {
++ uint32_t flags;
++
++ seg[i].nsec = req->seg[i].last_sect -
++ req->seg[i].first_sect + 1;
++
++ if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
++ (seg[i].nsec <= 0))
++ goto fail_response;
++ preq.nr_sects += seg[i].nsec;
++
++ flags = GNTMAP_host_map;
++ if ( operation == WRITE )
++ flags |= GNTMAP_readonly;
++ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
++ req->seg[i].gref, blkif->domid);
++ }
++
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
++ BUG_ON(ret);
++
++ for (i = 0; i < nseg; i++) {
++ if (unlikely(map[i].status != 0)) {
++ DPRINTK("invalid buffer -- could not remap it\n");
++ goto fail_flush;
++ }
++
++ pending_handle(pending_req, i) = map[i].handle;
++ set_phys_to_machine(__pa(vaddr(
++ pending_req, i)) >> PAGE_SHIFT,
++ FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
++ seg[i].buf = map[i].dev_bus_addr |
++ (req->seg[i].first_sect << 9);
++ }
++
++ if (vbd_translate(&preq, blkif, operation) != 0) {
++ DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n",
++ operation == READ ? "read" : "write",
++ preq.sector_number,
++ preq.sector_number + preq.nr_sects, preq.dev);
++ goto fail_flush;
++ }
++
++ for (i = 0; i < nseg; i++) {
++ if (((int)preq.sector_number|(int)seg[i].nsec) &
++ ((bdev_hardsect_size(preq.bdev) >> 9) - 1)) {
++ DPRINTK("Misaligned I/O request from domain %d",
++ blkif->domid);
++ goto fail_put_bio;
++ }
++
++ while ((bio == NULL) ||
++ (bio_add_page(bio,
++ virt_to_page(vaddr(pending_req, i)),
++ seg[i].nsec << 9,
++ seg[i].buf & ~PAGE_MASK) == 0)) {
++ bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
++ if (unlikely(bio == NULL))
++ goto fail_put_bio;
++
++ bio->bi_bdev = preq.bdev;
++ bio->bi_private = pending_req;
++ bio->bi_end_io = end_block_io_op;
++ bio->bi_sector = preq.sector_number;
++ }
++
++ preq.sector_number += seg[i].nsec;
++ }
++
++ plug_queue(blkif, bio);
++ atomic_set(&pending_req->pendcnt, nbio);
++ blkif_get(blkif);
++
++ for (i = 0; i < nbio; i++)
++ submit_bio(operation, biolist[i]);
++
++ return;
++
++ fail_put_bio:
++ for (i = 0; i < (nbio-1); i++)
++ bio_put(biolist[i]);
++ fail_flush:
++ fast_flush_area(pending_req);
++ fail_response:
++ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
++ free_req(pending_req);
++}
++
++
++
++/******************************************************************
++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
++ */
++
++
++static void make_response(blkif_t *blkif, unsigned long id,
++ unsigned short op, int st)
++{
++ blkif_response_t *resp;
++ unsigned long flags;
++ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
++ int more_to_do = 0;
++ int notify;
++
++ spin_lock_irqsave(&blkif->blk_ring_lock, flags);
++
++ /* Place on the response ring for the relevant domain. */
++ resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
++ resp->id = id;
++ resp->operation = op;
++ resp->status = st;
++ blk_ring->rsp_prod_pvt++;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(blk_ring, notify);
++
++ if (blk_ring->rsp_prod_pvt == blk_ring->req_cons) {
++ /*
++ * Tail check for pending requests. Allows frontend to avoid
++ * notifications if requests are already in flight (lower
++ * overheads and promotes batching).
++ */
++ RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do);
++
++ } else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
++ more_to_do = 1;
++
++ }
++ spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
++
++ if (more_to_do)
++ blkif_notify_work(blkif);
++ if (notify)
++ notify_remote_via_irq(blkif->irq);
++}
++
++static int __init blkif_init(void)
++{
++ int i, mmap_pages;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
++
++ pending_reqs = kmalloc(sizeof(pending_reqs[0]) *
++ blkif_reqs, GFP_KERNEL);
++ pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
++ mmap_pages, GFP_KERNEL);
++ pending_pages = alloc_empty_pages_and_pagevec(mmap_pages);
++
++ if (!pending_reqs || !pending_grant_handles || !pending_pages)
++ goto out_of_memory;
++
++ for (i = 0; i < mmap_pages; i++)
++ pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
++
++ blkif_interface_init();
++
++ memset(pending_reqs, 0, sizeof(pending_reqs));
++ INIT_LIST_HEAD(&pending_free);
++
++ for (i = 0; i < blkif_reqs; i++)
++ list_add_tail(&pending_reqs[i].free_list, &pending_free);
++
++ blkif_xenbus_init();
++
++ return 0;
++
++ out_of_memory:
++ kfree(pending_reqs);
++ kfree(pending_grant_handles);
++ free_empty_pages_and_pagevec(pending_pages, mmap_pages);
++ printk("%s: out of memory\n", __FUNCTION__);
++ return -ENOMEM;
++}
++
++module_init(blkif_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkback/common.h linux-2.6.18-xen/drivers/xen/blkback/common.h
+--- linux-2.6.18.1/drivers/xen/blkback/common.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkback/common.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,133 @@
++/*
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __BLKIF__BACKEND__COMMON_H__
++#define __BLKIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <linux/wait.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <asm/pgalloc.h>
++#include <xen/evtchn.h>
++#include <asm/hypervisor.h>
++#include <xen/interface/io/blkif.h>
++#include <xen/interface/io/ring.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++
++#define DPRINTK(_f, _a...) \
++ pr_debug("(file=%s, line=%d) " _f, \
++ __FILE__ , __LINE__ , ## _a )
++
++struct vbd {
++ blkif_vdev_t handle; /* what the domain refers to this vbd as */
++ unsigned char readonly; /* Non-zero -> read-only */
++ unsigned char type; /* VDISK_xxx */
++ u32 pdevice; /* phys device that this vbd maps to */
++ struct block_device *bdev;
++};
++
++struct backend_info;
++
++typedef struct blkif_st {
++ /* Unique identifier for this interface. */
++ domid_t domid;
++ unsigned int handle;
++ /* Physical parameters of the comms window. */
++ unsigned int evtchn;
++ unsigned int irq;
++ /* Comms information. */
++ blkif_back_ring_t blk_ring;
++ struct vm_struct *blk_ring_area;
++ /* The VBD attached to this interface. */
++ struct vbd vbd;
++ /* Back pointer to the backend_info. */
++ struct backend_info *be;
++ /* Private fields. */
++ spinlock_t blk_ring_lock;
++ atomic_t refcnt;
++
++ wait_queue_head_t wq;
++ struct task_struct *xenblkd;
++ unsigned int waiting_reqs;
++ request_queue_t *plug;
++
++ /* statistics */
++ unsigned long st_print;
++ int st_rd_req;
++ int st_wr_req;
++ int st_oo_req;
++
++ wait_queue_head_t waiting_to_free;
++
++ grant_handle_t shmem_handle;
++ grant_ref_t shmem_ref;
++} blkif_t;
++
++blkif_t *blkif_alloc(domid_t domid);
++void blkif_disconnect(blkif_t *blkif);
++void blkif_free(blkif_t *blkif);
++int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
++
++#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define blkif_put(_b) \
++ do { \
++ if (atomic_dec_and_test(&(_b)->refcnt)) \
++ wake_up(&(_b)->waiting_to_free);\
++ } while (0)
++
++/* Create a vbd. */
++int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, unsigned major,
++ unsigned minor, int readonly);
++void vbd_free(struct vbd *vbd);
++
++unsigned long vbd_size(struct vbd *vbd);
++unsigned int vbd_info(struct vbd *vbd);
++unsigned long vbd_secsize(struct vbd *vbd);
++
++struct phys_req {
++ unsigned short dev;
++ unsigned short nr_sects;
++ struct block_device *bdev;
++ blkif_sector_t sector_number;
++};
++
++int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
++
++void blkif_interface_init(void);
++
++void blkif_xenbus_init(void);
++
++irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++int blkif_schedule(void *arg);
++
++#endif /* __BLKIF__BACKEND__COMMON_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkback/interface.c linux-2.6.18-xen/drivers/xen/blkback/interface.c
+--- linux-2.6.18.1/drivers/xen/blkback/interface.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkback/interface.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,171 @@
++/******************************************************************************
++ * arch/xen/drivers/blkif/backend/interface.c
++ *
++ * Block-device interface management.
++ *
++ * Copyright (c) 2004, Keir Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include "common.h"
++#include <xen/evtchn.h>
++#include <linux/kthread.h>
++
++static kmem_cache_t *blkif_cachep;
++
++blkif_t *blkif_alloc(domid_t domid)
++{
++ blkif_t *blkif;
++
++ blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
++ if (!blkif)
++ return ERR_PTR(-ENOMEM);
++
++ memset(blkif, 0, sizeof(*blkif));
++ blkif->domid = domid;
++ spin_lock_init(&blkif->blk_ring_lock);
++ atomic_set(&blkif->refcnt, 1);
++ init_waitqueue_head(&blkif->wq);
++ blkif->st_print = jiffies;
++ init_waitqueue_head(&blkif->waiting_to_free);
++
++ return blkif;
++}
++
++static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
++{
++ struct gnttab_map_grant_ref op;
++ int ret;
++
++ gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++ GNTMAP_host_map, shared_page, blkif->domid);
++
++ lock_vm_area(blkif->blk_ring_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
++ unlock_vm_area(blkif->blk_ring_area);
++ BUG_ON(ret);
++
++ if (op.status) {
++ DPRINTK(" Grant table operation failure !\n");
++ return op.status;
++ }
++
++ blkif->shmem_ref = shared_page;
++ blkif->shmem_handle = op.handle;
++
++ return 0;
++}
++
++static void unmap_frontend_page(blkif_t *blkif)
++{
++ struct gnttab_unmap_grant_ref op;
++ int ret;
++
++ gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++ GNTMAP_host_map, blkif->shmem_handle);
++
++ lock_vm_area(blkif->blk_ring_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
++ unlock_vm_area(blkif->blk_ring_area);
++ BUG_ON(ret);
++}
++
++int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
++{
++ blkif_sring_t *sring;
++ int err;
++ struct evtchn_bind_interdomain bind_interdomain;
++
++ /* Already connected through? */
++ if (blkif->irq)
++ return 0;
++
++ if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
++ return -ENOMEM;
++
++ err = map_frontend_page(blkif, shared_page);
++ if (err) {
++ free_vm_area(blkif->blk_ring_area);
++ return err;
++ }
++
++ bind_interdomain.remote_dom = blkif->domid;
++ bind_interdomain.remote_port = evtchn;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++ if (err) {
++ unmap_frontend_page(blkif);
++ free_vm_area(blkif->blk_ring_area);
++ return err;
++ }
++
++ blkif->evtchn = bind_interdomain.local_port;
++
++ sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
++ BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
++
++ blkif->irq = bind_evtchn_to_irqhandler(
++ blkif->evtchn, blkif_be_int, 0, "blkif-backend", blkif);
++
++ return 0;
++}
++
++void blkif_disconnect(blkif_t *blkif)
++{
++ if (blkif->xenblkd) {
++ kthread_stop(blkif->xenblkd);
++ blkif->xenblkd = NULL;
++ }
++
++ atomic_dec(&blkif->refcnt);
++ wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
++ atomic_inc(&blkif->refcnt);
++
++ if (blkif->irq) {
++ unbind_from_irqhandler(blkif->irq, blkif);
++ blkif->irq = 0;
++ }
++
++ if (blkif->blk_ring.sring) {
++ unmap_frontend_page(blkif);
++ free_vm_area(blkif->blk_ring_area);
++ blkif->blk_ring.sring = NULL;
++ }
++}
++
++void blkif_free(blkif_t *blkif)
++{
++ if (!atomic_dec_and_test(&blkif->refcnt))
++ BUG();
++ kmem_cache_free(blkif_cachep, blkif);
++}
++
++void __init blkif_interface_init(void)
++{
++ blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
++ 0, 0, NULL, NULL);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkback/Makefile linux-2.6.18-xen/drivers/xen/blkback/Makefile
+--- linux-2.6.18.1/drivers/xen/blkback/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkback/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkbk.o
++
++blkbk-y := blkback.o xenbus.o interface.o vbd.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkback/vbd.c linux-2.6.18-xen/drivers/xen/blkback/vbd.c
+--- linux-2.6.18.1/drivers/xen/blkback/vbd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkback/vbd.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,119 @@
++/******************************************************************************
++ * blkback/vbd.c
++ *
++ * Routines for managing virtual block devices (VBDs).
++ *
++ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include "common.h"
++#include <xen/xenbus.h>
++
++#define vbd_sz(_v) ((_v)->bdev->bd_part ? \
++ (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
++
++unsigned long vbd_size(struct vbd *vbd)
++{
++ return vbd_sz(vbd);
++}
++
++unsigned int vbd_info(struct vbd *vbd)
++{
++ return vbd->type | (vbd->readonly?VDISK_READONLY:0);
++}
++
++unsigned long vbd_secsize(struct vbd *vbd)
++{
++ return bdev_hardsect_size(vbd->bdev);
++}
++
++int vbd_create(blkif_t *blkif, blkif_vdev_t handle, unsigned major,
++ unsigned minor, int readonly)
++{
++ struct vbd *vbd;
++ struct block_device *bdev;
++
++ vbd = &blkif->vbd;
++ vbd->handle = handle;
++ vbd->readonly = readonly;
++ vbd->type = 0;
++
++ vbd->pdevice = MKDEV(major, minor);
++
++ bdev = open_by_devnum(vbd->pdevice,
++ vbd->readonly ? FMODE_READ : FMODE_WRITE);
++
++ if (IS_ERR(bdev)) {
++ DPRINTK("vbd_creat: device %08x could not be opened.\n",
++ vbd->pdevice);
++ return -ENOENT;
++ }
++
++ vbd->bdev = bdev;
++
++ if (vbd->bdev->bd_disk == NULL) {
++ DPRINTK("vbd_creat: device %08x doesn't exist.\n",
++ vbd->pdevice);
++ vbd_free(vbd);
++ return -ENOENT;
++ }
++
++ if (vbd->bdev->bd_disk->flags & GENHD_FL_CD)
++ vbd->type |= VDISK_CDROM;
++ if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
++ vbd->type |= VDISK_REMOVABLE;
++
++ DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
++ handle, blkif->domid);
++ return 0;
++}
++
++void vbd_free(struct vbd *vbd)
++{
++ if (vbd->bdev)
++ blkdev_put(vbd->bdev);
++ vbd->bdev = NULL;
++}
++
++int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
++{
++ struct vbd *vbd = &blkif->vbd;
++ int rc = -EACCES;
++
++ if ((operation == WRITE) && vbd->readonly)
++ goto out;
++
++ if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
++ goto out;
++
++ req->dev = vbd->pdevice;
++ req->bdev = vbd->bdev;
++ rc = 0;
++
++ out:
++ return rc;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkback/xenbus.c linux-2.6.18-xen/drivers/xen/blkback/xenbus.c
+--- linux-2.6.18.1/drivers/xen/blkback/xenbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkback/xenbus.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,468 @@
++/* Xenbus code for blkif backend
++ Copyright (C) 2005 Rusty Russell <rusty at rustcorp.com.au>
++ Copyright (C) 2005 XenSource 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
++*/
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++#undef DPRINTK
++#define DPRINTK(fmt, args...) \
++ pr_debug("blkback/xenbus (%s:%d) " fmt ".\n", \
++ __FUNCTION__, __LINE__, ##args)
++
++struct backend_info
++{
++ struct xenbus_device *dev;
++ blkif_t *blkif;
++ struct xenbus_watch backend_watch;
++ unsigned major;
++ unsigned minor;
++ char *mode;
++};
++
++static void connect(struct backend_info *);
++static int connect_ring(struct backend_info *);
++static void backend_changed(struct xenbus_watch *, const char **,
++ unsigned int);
++
++static void update_blkif_status(blkif_t *blkif)
++{
++ int err;
++
++ /* Not ready to connect? */
++ if (!blkif->irq || !blkif->vbd.bdev)
++ return;
++
++ /* Already connected? */
++ if (blkif->be->dev->state == XenbusStateConnected)
++ return;
++
++ /* Attempt to connect: exit if we fail to. */
++ connect(blkif->be);
++ if (blkif->be->dev->state != XenbusStateConnected)
++ return;
++
++ blkif->xenblkd = kthread_run(blkif_schedule, blkif,
++ "xvd %d %02x:%02x",
++ blkif->domid,
++ blkif->be->major, blkif->be->minor);
++ if (IS_ERR(blkif->xenblkd)) {
++ err = PTR_ERR(blkif->xenblkd);
++ blkif->xenblkd = NULL;
++ xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
++ }
++}
++
++
++/****************************************************************
++ * sysfs interface for VBD I/O requests
++ */
++
++#define VBD_SHOW(name, format, args...) \
++ static ssize_t show_##name(struct device *_dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++ { \
++ struct xenbus_device *dev = to_xenbus_device(_dev); \
++ struct backend_info *be = dev->dev.driver_data; \
++ \
++ return sprintf(buf, format, ##args); \
++ } \
++ DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
++
++VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req);
++VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req);
++VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req);
++
++static struct attribute *vbdstat_attrs[] = {
++ &dev_attr_oo_req.attr,
++ &dev_attr_rd_req.attr,
++ &dev_attr_wr_req.attr,
++ NULL
++};
++
++static struct attribute_group vbdstat_group = {
++ .name = "statistics",
++ .attrs = vbdstat_attrs,
++};
++
++VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
++VBD_SHOW(mode, "%s\n", be->mode);
++
++int xenvbd_sysfs_addif(struct xenbus_device *dev)
++{
++ int error;
++
++ error = device_create_file(&dev->dev, &dev_attr_physical_device);
++ if (error)
++ goto fail1;
++
++ error = device_create_file(&dev->dev, &dev_attr_mode);
++ if (error)
++ goto fail2;
++
++ error = sysfs_create_group(&dev->dev.kobj, &vbdstat_group);
++ if (error)
++ goto fail3;
++
++ return 0;
++
++fail3: sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
++fail2: device_remove_file(&dev->dev, &dev_attr_mode);
++fail1: device_remove_file(&dev->dev, &dev_attr_physical_device);
++ return error;
++}
++
++void xenvbd_sysfs_delif(struct xenbus_device *dev)
++{
++ sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
++ device_remove_file(&dev->dev, &dev_attr_mode);
++ device_remove_file(&dev->dev, &dev_attr_physical_device);
++}
++
++static int blkback_remove(struct xenbus_device *dev)
++{
++ struct backend_info *be = dev->dev.driver_data;
++
++ DPRINTK("");
++
++ if (be->backend_watch.node) {
++ unregister_xenbus_watch(&be->backend_watch);
++ kfree(be->backend_watch.node);
++ be->backend_watch.node = NULL;
++ }
++
++ if (be->blkif) {
++ blkif_disconnect(be->blkif);
++ vbd_free(&be->blkif->vbd);
++ blkif_free(be->blkif);
++ be->blkif = NULL;
++ }
++
++ if (be->major || be->minor)
++ xenvbd_sysfs_delif(dev);
++
++ kfree(be);
++ dev->dev.driver_data = NULL;
++ return 0;
++}
++
++
++/**
++ * Entry point to this code when a new device is created. Allocate the basic
++ * structures, and watch the store waiting for the hotplug scripts to tell us
++ * the device's physical major and minor numbers. Switch to InitWait.
++ */
++static int blkback_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err;
++ struct backend_info *be = kzalloc(sizeof(struct backend_info),
++ GFP_KERNEL);
++ if (!be) {
++ xenbus_dev_fatal(dev, -ENOMEM,
++ "allocating backend structure");
++ return -ENOMEM;
++ }
++ be->dev = dev;
++ dev->dev.driver_data = be;
++
++ be->blkif = blkif_alloc(dev->otherend_id);
++ if (IS_ERR(be->blkif)) {
++ err = PTR_ERR(be->blkif);
++ be->blkif = NULL;
++ xenbus_dev_fatal(dev, err, "creating block interface");
++ goto fail;
++ }
++
++ /* setup back pointer */
++ be->blkif->be = be;
++
++ err = xenbus_watch_path2(dev, dev->nodename, "physical-device",
++ &be->backend_watch, backend_changed);
++ if (err)
++ goto fail;
++
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto fail;
++
++ return 0;
++
++fail:
++ DPRINTK("failed");
++ blkback_remove(dev);
++ return err;
++}
++
++
++/**
++ * Callback received when the hotplug scripts have placed the physical-device
++ * node. Read it and the mode node, and create a vbd. If the frontend is
++ * ready, connect.
++ */
++static void backend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ int err;
++ unsigned major;
++ unsigned minor;
++ struct backend_info *be
++ = container_of(watch, struct backend_info, backend_watch);
++ struct xenbus_device *dev = be->dev;
++
++ DPRINTK("");
++
++ err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
++ &major, &minor);
++ if (XENBUS_EXIST_ERR(err)) {
++ /* Since this watch will fire once immediately after it is
++ registered, we expect this. Ignore it, and wait for the
++ hotplug scripts. */
++ return;
++ }
++ if (err != 2) {
++ xenbus_dev_fatal(dev, err, "reading physical-device");
++ return;
++ }
++
++ if ((be->major || be->minor) &&
++ ((be->major != major) || (be->minor != minor))) {
++ printk(KERN_WARNING
++ "blkback: changing physical device (from %x:%x to "
++ "%x:%x) not supported.\n", be->major, be->minor,
++ major, minor);
++ return;
++ }
++
++ be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
++ if (IS_ERR(be->mode)) {
++ err = PTR_ERR(be->mode);
++ be->mode = NULL;
++ xenbus_dev_fatal(dev, err, "reading mode");
++ return;
++ }
++
++ if (be->major == 0 && be->minor == 0) {
++ /* Front end dir is a number, which is used as the handle. */
++
++ char *p = strrchr(dev->otherend, '/') + 1;
++ long handle = simple_strtoul(p, NULL, 0);
++
++ be->major = major;
++ be->minor = minor;
++
++ err = vbd_create(be->blkif, handle, major, minor,
++ (NULL == strchr(be->mode, 'w')));
++ if (err) {
++ be->major = be->minor = 0;
++ xenbus_dev_fatal(dev, err, "creating vbd structure");
++ return;
++ }
++
++ err = xenvbd_sysfs_addif(dev);
++ if (err) {
++ vbd_free(&be->blkif->vbd);
++ be->major = be->minor = 0;
++ xenbus_dev_fatal(dev, err, "creating sysfs entries");
++ return;
++ }
++
++ /* We're potentially connected now */
++ update_blkif_status(be->blkif);
++ }
++}
++
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state)
++{
++ struct backend_info *be = dev->dev.driver_data;
++ int err;
++
++ DPRINTK("%s", xenbus_strstate(frontend_state));
++
++ switch (frontend_state) {
++ case XenbusStateInitialising:
++ if (dev->state == XenbusStateClosed) {
++ printk("%s: %s: prepare for reconnect\n",
++ __FUNCTION__, dev->nodename);
++ xenbus_switch_state(dev, XenbusStateInitWait);
++ }
++ break;
++
++ case XenbusStateInitialised:
++ case XenbusStateConnected:
++ /* Ensure we connect even when two watches fire in
++ close successsion and we miss the intermediate value
++ of frontend_state. */
++ if (dev->state == XenbusStateConnected)
++ break;
++
++ err = connect_ring(be);
++ if (err)
++ break;
++ update_blkif_status(be->blkif);
++ break;
++
++ case XenbusStateClosing:
++ blkif_disconnect(be->blkif);
++ xenbus_switch_state(dev, XenbusStateClosing);
++ break;
++
++ case XenbusStateClosed:
++ xenbus_switch_state(dev, XenbusStateClosed);
++ if (xenbus_dev_is_online(dev))
++ break;
++ /* fall through if not online */
++ case XenbusStateUnknown:
++ device_unregister(&dev->dev);
++ break;
++
++ default:
++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++ frontend_state);
++ break;
++ }
++}
++
++
++/* ** Connection ** */
++
++
++/**
++ * Write the physical details regarding the block device to the store, and
++ * switch to Connected state.
++ */
++static void connect(struct backend_info *be)
++{
++ struct xenbus_transaction xbt;
++ int err;
++ struct xenbus_device *dev = be->dev;
++
++ DPRINTK("%s", dev->otherend);
++
++ /* Supply the information about the device the frontend needs */
++again:
++ err = xenbus_transaction_start(&xbt);
++
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ return;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "sectors", "%lu",
++ vbd_size(&be->blkif->vbd));
++ if (err) {
++ xenbus_dev_fatal(dev, err, "writing %s/sectors",
++ dev->nodename);
++ goto abort;
++ }
++
++ /* FIXME: use a typename instead */
++ err = xenbus_printf(xbt, dev->nodename, "info", "%u",
++ vbd_info(&be->blkif->vbd));
++ if (err) {
++ xenbus_dev_fatal(dev, err, "writing %s/info",
++ dev->nodename);
++ goto abort;
++ }
++ err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
++ vbd_secsize(&be->blkif->vbd));
++ if (err) {
++ xenbus_dev_fatal(dev, err, "writing %s/sector-size",
++ dev->nodename);
++ goto abort;
++ }
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err == -EAGAIN)
++ goto again;
++ if (err)
++ xenbus_dev_fatal(dev, err, "ending transaction");
++
++ err = xenbus_switch_state(dev, XenbusStateConnected);
++ if (err)
++ xenbus_dev_fatal(dev, err, "switching to Connected state",
++ dev->nodename);
++
++ return;
++ abort:
++ xenbus_transaction_end(xbt, 1);
++}
++
++
++static int connect_ring(struct backend_info *be)
++{
++ struct xenbus_device *dev = be->dev;
++ unsigned long ring_ref;
++ unsigned int evtchn;
++ int err;
++
++ DPRINTK("%s", dev->otherend);
++
++ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref,
++ "event-channel", "%u", &evtchn, NULL);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "reading %s/ring-ref and event-channel",
++ dev->otherend);
++ return err;
++ }
++
++ /* Map the shared frame, irq etc. */
++ err = blkif_map(be->blkif, ring_ref, evtchn);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
++ ring_ref, evtchn);
++ return err;
++ }
++
++ return 0;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static struct xenbus_device_id blkback_ids[] = {
++ { "vbd" },
++ { "" }
++};
++
++
++static struct xenbus_driver blkback = {
++ .name = "vbd",
++ .owner = THIS_MODULE,
++ .ids = blkback_ids,
++ .probe = blkback_probe,
++ .remove = blkback_remove,
++ .otherend_changed = frontend_changed
++};
++
++
++void blkif_xenbus_init(void)
++{
++ xenbus_register_backend(&blkback);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkfront/blkfront.c linux-2.6.18-xen/drivers/xen/blkfront/blkfront.c
+--- linux-2.6.18.1/drivers/xen/blkfront/blkfront.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkfront/blkfront.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,846 @@
++/******************************************************************************
++ * blkfront.c
++ *
++ * XenLinux virtual block-device driver.
++ *
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
++ * Copyright (c) 2004, Christian Limpach
++ * Copyright (c) 2004, Andrew Warfield
++ * Copyright (c) 2005, Christopher Clark
++ * Copyright (c) 2005, XenSource Ltd
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/version.h>
++#include "block.h"
++#include <linux/cdrom.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <scsi/scsi.h>
++#include <xen/evtchn.h>
++#include <xen/xenbus.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++#include <asm/hypervisor.h>
++#include <asm/maddr.h>
++
++#define BLKIF_STATE_DISCONNECTED 0
++#define BLKIF_STATE_CONNECTED 1
++#define BLKIF_STATE_SUSPENDED 2
++
++#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
++ (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
++#define GRANT_INVALID_REF 0
++
++static void connect(struct blkfront_info *);
++static void blkfront_closing(struct xenbus_device *);
++static int blkfront_remove(struct xenbus_device *);
++static int talk_to_backend(struct xenbus_device *, struct blkfront_info *);
++static int setup_blkring(struct xenbus_device *, struct blkfront_info *);
++
++static void kick_pending_request_queues(struct blkfront_info *);
++
++static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs);
++static void blkif_restart_queue(void *arg);
++static void blkif_recover(struct blkfront_info *);
++static void blkif_completion(struct blk_shadow *);
++static void blkif_free(struct blkfront_info *, int);
++
++
++/**
++ * Entry point to this code when a new device is created. Allocate the basic
++ * structures and the ring buffer for communication with the backend, and
++ * inform the backend of the appropriate details for those. Switch to
++ * Initialised state.
++ */
++static int blkfront_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err, vdevice, i;
++ struct blkfront_info *info;
++
++ /* FIXME: Use dynamic device id if this is not set. */
++ err = xenbus_scanf(XBT_NIL, dev->nodename,
++ "virtual-device", "%i", &vdevice);
++ if (err != 1) {
++ xenbus_dev_fatal(dev, err, "reading virtual-device");
++ return err;
++ }
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (!info) {
++ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
++ return -ENOMEM;
++ }
++
++ info->xbdev = dev;
++ info->vdevice = vdevice;
++ info->connected = BLKIF_STATE_DISCONNECTED;
++ INIT_WORK(&info->work, blkif_restart_queue, (void *)info);
++
++ for (i = 0; i < BLK_RING_SIZE; i++)
++ info->shadow[i].req.id = i+1;
++ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
++
++ /* Front end dir is a number, which is used as the id. */
++ info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0);
++ dev->dev.driver_data = info;
++
++ err = talk_to_backend(dev, info);
++ if (err) {
++ kfree(info);
++ dev->dev.driver_data = NULL;
++ return err;
++ }
++
++ return 0;
++}
++
++
++/**
++ * We are reconnecting to the backend, due to a suspend/resume, or a backend
++ * driver restart. We tear down our blkif structure and recreate it, but
++ * leave the device-layer structures intact so that this is transparent to the
++ * rest of the kernel.
++ */
++static int blkfront_resume(struct xenbus_device *dev)
++{
++ struct blkfront_info *info = dev->dev.driver_data;
++ int err;
++
++ DPRINTK("blkfront_resume: %s\n", dev->nodename);
++
++ blkif_free(info, 1);
++
++ err = talk_to_backend(dev, info);
++ if (!err)
++ blkif_recover(info);
++
++ return err;
++}
++
++
++/* Common code used when first setting up, and when resuming. */
++static int talk_to_backend(struct xenbus_device *dev,
++ struct blkfront_info *info)
++{
++ const char *message = NULL;
++ struct xenbus_transaction xbt;
++ int err;
++
++ /* Create shared ring, alloc event channel. */
++ err = setup_blkring(dev, info);
++ if (err)
++ goto out;
++
++again:
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ goto destroy_blkring;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename,
++ "ring-ref","%u", info->ring_ref);
++ if (err) {
++ message = "writing ring-ref";
++ goto abort_transaction;
++ }
++ err = xenbus_printf(xbt, dev->nodename,
++ "event-channel", "%u", info->evtchn);
++ if (err) {
++ message = "writing event-channel";
++ goto abort_transaction;
++ }
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err) {
++ if (err == -EAGAIN)
++ goto again;
++ xenbus_dev_fatal(dev, err, "completing transaction");
++ goto destroy_blkring;
++ }
++
++ xenbus_switch_state(dev, XenbusStateInitialised);
++
++ return 0;
++
++ abort_transaction:
++ xenbus_transaction_end(xbt, 1);
++ if (message)
++ xenbus_dev_fatal(dev, err, "%s", message);
++ destroy_blkring:
++ blkif_free(info, 0);
++ out:
++ return err;
++}
++
++
++static int setup_blkring(struct xenbus_device *dev,
++ struct blkfront_info *info)
++{
++ blkif_sring_t *sring;
++ int err;
++
++ info->ring_ref = GRANT_INVALID_REF;
++
++ sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
++ if (!sring) {
++ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
++ return -ENOMEM;
++ }
++ SHARED_RING_INIT(sring);
++ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
++
++ err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
++ if (err < 0) {
++ free_page((unsigned long)sring);
++ info->ring.sring = NULL;
++ goto fail;
++ }
++ info->ring_ref = err;
++
++ err = xenbus_alloc_evtchn(dev, &info->evtchn);
++ if (err)
++ goto fail;
++
++ err = bind_evtchn_to_irqhandler(
++ info->evtchn, blkif_int, SA_SAMPLE_RANDOM, "blkif", info);
++ if (err <= 0) {
++ xenbus_dev_fatal(dev, err,
++ "bind_evtchn_to_irqhandler failed");
++ goto fail;
++ }
++ info->irq = err;
++
++ return 0;
++fail:
++ blkif_free(info, 0);
++ return err;
++}
++
++
++/**
++ * Callback received when the backend's state changes.
++ */
++static void backend_changed(struct xenbus_device *dev,
++ enum xenbus_state backend_state)
++{
++ struct blkfront_info *info = dev->dev.driver_data;
++ struct block_device *bd;
++
++ DPRINTK("blkfront:backend_changed.\n");
++
++ switch (backend_state) {
++ case XenbusStateInitialising:
++ case XenbusStateInitWait:
++ case XenbusStateInitialised:
++ case XenbusStateUnknown:
++ case XenbusStateClosed:
++ break;
++
++ case XenbusStateConnected:
++ connect(info);
++ break;
++
++ case XenbusStateClosing:
++ bd = bdget(info->dev);
++ if (bd == NULL)
++ xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
++
++ mutex_lock(&bd->bd_mutex);
++ if (info->users > 0)
++ xenbus_dev_error(dev, -EBUSY,
++ "Device in use; refusing to close");
++ else
++ blkfront_closing(dev);
++ mutex_unlock(&bd->bd_mutex);
++ bdput(bd);
++ break;
++ }
++}
++
++
++/* ** Connection ** */
++
++
++/*
++ * Invoked when the backend is finally 'ready' (and has told produced
++ * the details about the physical device - #sectors, size, etc).
++ */
++static void connect(struct blkfront_info *info)
++{
++ unsigned long sectors, sector_size;
++ unsigned int binfo;
++ int err;
++
++ if ((info->connected == BLKIF_STATE_CONNECTED) ||
++ (info->connected == BLKIF_STATE_SUSPENDED) )
++ return;
++
++ DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend);
++
++ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
++ "sectors", "%lu", §ors,
++ "info", "%u", &binfo,
++ "sector-size", "%lu", §or_size,
++ NULL);
++ if (err) {
++ xenbus_dev_fatal(info->xbdev, err,
++ "reading backend fields at %s",
++ info->xbdev->otherend);
++ return;
++ }
++
++ err = xlvbd_add(sectors, info->vdevice, binfo, sector_size, info);
++ if (err) {
++ xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
++ info->xbdev->otherend);
++ return;
++ }
++
++ (void)xenbus_switch_state(info->xbdev, XenbusStateConnected);
++
++ /* Kick pending requests. */
++ spin_lock_irq(&blkif_io_lock);
++ info->connected = BLKIF_STATE_CONNECTED;
++ kick_pending_request_queues(info);
++ spin_unlock_irq(&blkif_io_lock);
++
++ add_disk(info->gd);
++}
++
++/**
++ * Handle the change of state of the backend to Closing. We must delete our
++ * device-layer structures now, to ensure that writes are flushed through to
++ * the backend. Once is this done, we can switch to Closed in
++ * acknowledgement.
++ */
++static void blkfront_closing(struct xenbus_device *dev)
++{
++ struct blkfront_info *info = dev->dev.driver_data;
++ unsigned long flags;
++
++ DPRINTK("blkfront_closing: %s removed\n", dev->nodename);
++
++ if (info->rq == NULL)
++ return;
++
++ spin_lock_irqsave(&blkif_io_lock, flags);
++ /* No more blkif_request(). */
++ blk_stop_queue(info->rq);
++ /* No more gnttab callback work. */
++ gnttab_cancel_free_callback(&info->callback);
++ spin_unlock_irqrestore(&blkif_io_lock, flags);
++
++ /* Flush gnttab callback work. Must be done with no locks held. */
++ flush_scheduled_work();
++
++ xlvbd_del(info);
++
++ xenbus_frontend_closed(dev);
++}
++
++
++static int blkfront_remove(struct xenbus_device *dev)
++{
++ struct blkfront_info *info = dev->dev.driver_data;
++
++ DPRINTK("blkfront_remove: %s removed\n", dev->nodename);
++
++ blkif_free(info, 0);
++
++ kfree(info);
++
++ return 0;
++}
++
++
++static inline int GET_ID_FROM_FREELIST(
++ struct blkfront_info *info)
++{
++ unsigned long free = info->shadow_free;
++ BUG_ON(free > BLK_RING_SIZE);
++ info->shadow_free = info->shadow[free].req.id;
++ info->shadow[free].req.id = 0x0fffffee; /* debug */
++ return free;
++}
++
++static inline void ADD_ID_TO_FREELIST(
++ struct blkfront_info *info, unsigned long id)
++{
++ info->shadow[id].req.id = info->shadow_free;
++ info->shadow[id].request = 0;
++ info->shadow_free = id;
++}
++
++static inline void flush_requests(struct blkfront_info *info)
++{
++ int notify;
++
++ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
++
++ if (notify)
++ notify_remote_via_irq(info->irq);
++}
++
++static void kick_pending_request_queues(struct blkfront_info *info)
++{
++ if (!RING_FULL(&info->ring)) {
++ /* Re-enable calldowns. */
++ blk_start_queue(info->rq);
++ /* Kick things off immediately. */
++ do_blkif_request(info->rq);
++ }
++}
++
++static void blkif_restart_queue(void *arg)
++{
++ struct blkfront_info *info = (struct blkfront_info *)arg;
++ spin_lock_irq(&blkif_io_lock);
++ if (info->connected == BLKIF_STATE_CONNECTED)
++ kick_pending_request_queues(info);
++ spin_unlock_irq(&blkif_io_lock);
++}
++
++static void blkif_restart_queue_callback(void *arg)
++{
++ struct blkfront_info *info = (struct blkfront_info *)arg;
++ schedule_work(&info->work);
++}
++
++int blkif_open(struct inode *inode, struct file *filep)
++{
++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++ info->users++;
++ return 0;
++}
++
++
++int blkif_release(struct inode *inode, struct file *filep)
++{
++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++ info->users--;
++ if (info->users == 0) {
++ /* Check whether we have been instructed to close. We will
++ have ignored this request initially, as the device was
++ still mounted. */
++ struct xenbus_device * dev = info->xbdev;
++ enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
++
++ if (state == XenbusStateClosing)
++ blkfront_closing(dev);
++ }
++ return 0;
++}
++
++
++int blkif_ioctl(struct inode *inode, struct file *filep,
++ unsigned command, unsigned long argument)
++{
++ int i;
++
++ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
++ command, (long)argument, inode->i_rdev);
++
++ switch (command) {
++ case CDROMMULTISESSION:
++ DPRINTK("FIXME: support multisession CDs later\n");
++ for (i = 0; i < sizeof(struct cdrom_multisession); i++)
++ if (put_user(0, (char __user *)(argument + i)))
++ return -EFAULT;
++ return 0;
++
++ default:
++ /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
++ command);*/
++ return -EINVAL; /* same return as native Linux */
++ }
++
++ return 0;
++}
++
++
++int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
++{
++ /* We don't have real geometry info, but let's at least return
++ values consistent with the size of the device */
++ sector_t nsect = get_capacity(bd->bd_disk);
++ sector_t cylinders = nsect;
++
++ hg->heads = 0xff;
++ hg->sectors = 0x3f;
++ sector_div(cylinders, hg->heads * hg->sectors);
++ hg->cylinders = cylinders;
++ if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
++ hg->cylinders = 0xffff;
++ return 0;
++}
++
++
++/*
++ * blkif_queue_request
++ *
++ * request block io
++ *
++ * id: for guest use only.
++ * operation: BLKIF_OP_{READ,WRITE,PROBE}
++ * buffer: buffer to read/write into. this should be a
++ * virtual address in the guest os.
++ */
++static int blkif_queue_request(struct request *req)
++{
++ struct blkfront_info *info = req->rq_disk->private_data;
++ unsigned long buffer_mfn;
++ blkif_request_t *ring_req;
++ struct bio *bio;
++ struct bio_vec *bvec;
++ int idx;
++ unsigned long id;
++ unsigned int fsect, lsect;
++ int ref;
++ grant_ref_t gref_head;
++
++ if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
++ return 1;
++
++ if (gnttab_alloc_grant_references(
++ BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
++ gnttab_request_free_callback(
++ &info->callback,
++ blkif_restart_queue_callback,
++ info,
++ BLKIF_MAX_SEGMENTS_PER_REQUEST);
++ return 1;
++ }
++
++ /* Fill out a communications ring structure. */
++ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
++ id = GET_ID_FROM_FREELIST(info);
++ info->shadow[id].request = (unsigned long)req;
++
++ ring_req->id = id;
++ ring_req->operation = rq_data_dir(req) ?
++ BLKIF_OP_WRITE : BLKIF_OP_READ;
++ ring_req->sector_number = (blkif_sector_t)req->sector;
++ ring_req->handle = info->handle;
++
++ ring_req->nr_segments = 0;
++ rq_for_each_bio (bio, req) {
++ bio_for_each_segment (bvec, bio, idx) {
++ BUG_ON(ring_req->nr_segments
++ == BLKIF_MAX_SEGMENTS_PER_REQUEST);
++ buffer_mfn = page_to_phys(bvec->bv_page) >> PAGE_SHIFT;
++ fsect = bvec->bv_offset >> 9;
++ lsect = fsect + (bvec->bv_len >> 9) - 1;
++ /* install a grant reference. */
++ ref = gnttab_claim_grant_reference(&gref_head);
++ BUG_ON(ref == -ENOSPC);
++
++ gnttab_grant_foreign_access_ref(
++ ref,
++ info->xbdev->otherend_id,
++ buffer_mfn,
++ rq_data_dir(req) );
++
++ info->shadow[id].frame[ring_req->nr_segments] =
++ mfn_to_pfn(buffer_mfn);
++
++ ring_req->seg[ring_req->nr_segments] =
++ (struct blkif_request_segment) {
++ .gref = ref,
++ .first_sect = fsect,
++ .last_sect = lsect };
++
++ ring_req->nr_segments++;
++ }
++ }
++
++ info->ring.req_prod_pvt++;
++
++ /* Keep a private copy so we can reissue requests when recovering. */
++ info->shadow[id].req = *ring_req;
++
++ gnttab_free_grant_references(gref_head);
++
++ return 0;
++}
++
++/*
++ * do_blkif_request
++ * read a block; request is in a request queue
++ */
++void do_blkif_request(request_queue_t *rq)
++{
++ struct blkfront_info *info = NULL;
++ struct request *req;
++ int queued;
++
++ DPRINTK("Entered do_blkif_request\n");
++
++ queued = 0;
++
++ while ((req = elv_next_request(rq)) != NULL) {
++ info = req->rq_disk->private_data;
++ if (!blk_fs_request(req)) {
++ end_request(req, 0);
++ continue;
++ }
++
++ if (RING_FULL(&info->ring))
++ goto wait;
++
++ DPRINTK("do_blk_req %p: cmd %p, sec %lx, "
++ "(%u/%li) buffer:%p [%s]\n",
++ req, req->cmd, req->sector, req->current_nr_sectors,
++ req->nr_sectors, req->buffer,
++ rq_data_dir(req) ? "write" : "read");
++
++
++ blkdev_dequeue_request(req);
++ if (blkif_queue_request(req)) {
++ blk_requeue_request(rq, req);
++ wait:
++ /* Avoid pointless unplugs. */
++ blk_stop_queue(rq);
++ break;
++ }
++
++ queued++;
++ }
++
++ if (queued != 0)
++ flush_requests(info);
++}
++
++
++static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
++{
++ struct request *req;
++ blkif_response_t *bret;
++ RING_IDX i, rp;
++ unsigned long flags;
++ struct blkfront_info *info = (struct blkfront_info *)dev_id;
++
++ spin_lock_irqsave(&blkif_io_lock, flags);
++
++ if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
++ spin_unlock_irqrestore(&blkif_io_lock, flags);
++ return IRQ_HANDLED;
++ }
++
++ again:
++ rp = info->ring.sring->rsp_prod;
++ rmb(); /* Ensure we see queued responses up to 'rp'. */
++
++ for (i = info->ring.rsp_cons; i != rp; i++) {
++ unsigned long id;
++ int ret;
++
++ bret = RING_GET_RESPONSE(&info->ring, i);
++ id = bret->id;
++ req = (struct request *)info->shadow[id].request;
++
++ blkif_completion(&info->shadow[id]);
++
++ ADD_ID_TO_FREELIST(info, id);
++
++ switch (bret->operation) {
++ case BLKIF_OP_READ:
++ case BLKIF_OP_WRITE:
++ if (unlikely(bret->status != BLKIF_RSP_OKAY))
++ DPRINTK("Bad return from blkdev data "
++ "request: %x\n", bret->status);
++
++ ret = end_that_request_first(
++ req, (bret->status == BLKIF_RSP_OKAY),
++ req->hard_nr_sectors);
++ BUG_ON(ret);
++ end_that_request_last(
++ req, (bret->status == BLKIF_RSP_OKAY));
++ break;
++ default:
++ BUG();
++ }
++ }
++
++ info->ring.rsp_cons = i;
++
++ if (i != info->ring.req_prod_pvt) {
++ int more_to_do;
++ RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
++ if (more_to_do)
++ goto again;
++ } else
++ info->ring.sring->rsp_event = i + 1;
++
++ kick_pending_request_queues(info);
++
++ spin_unlock_irqrestore(&blkif_io_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++static void blkif_free(struct blkfront_info *info, int suspend)
++{
++ /* Prevent new requests being issued until we fix things up. */
++ spin_lock_irq(&blkif_io_lock);
++ info->connected = suspend ?
++ BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
++ /* No more blkif_request(). */
++ if (info->rq)
++ blk_stop_queue(info->rq);
++ /* No more gnttab callback work. */
++ gnttab_cancel_free_callback(&info->callback);
++ spin_unlock_irq(&blkif_io_lock);
++
++ /* Flush gnttab callback work. Must be done with no locks held. */
++ flush_scheduled_work();
++
++ /* Free resources associated with old device channel. */
++ if (info->ring_ref != GRANT_INVALID_REF) {
++ gnttab_end_foreign_access(info->ring_ref, 0,
++ (unsigned long)info->ring.sring);
++ info->ring_ref = GRANT_INVALID_REF;
++ info->ring.sring = NULL;
++ }
++ if (info->irq)
++ unbind_from_irqhandler(info->irq, info);
++ info->evtchn = info->irq = 0;
++
++}
++
++static void blkif_completion(struct blk_shadow *s)
++{
++ int i;
++ for (i = 0; i < s->req.nr_segments; i++)
++ gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
++}
++
++static void blkif_recover(struct blkfront_info *info)
++{
++ int i;
++ blkif_request_t *req;
++ struct blk_shadow *copy;
++ int j;
++
++ /* Stage 1: Make a safe copy of the shadow state. */
++ copy = kmalloc(sizeof(info->shadow), GFP_KERNEL | __GFP_NOFAIL);
++ memcpy(copy, info->shadow, sizeof(info->shadow));
++
++ /* Stage 2: Set up free list. */
++ memset(&info->shadow, 0, sizeof(info->shadow));
++ for (i = 0; i < BLK_RING_SIZE; i++)
++ info->shadow[i].req.id = i+1;
++ info->shadow_free = info->ring.req_prod_pvt;
++ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
++
++ /* Stage 3: Find pending requests and requeue them. */
++ for (i = 0; i < BLK_RING_SIZE; i++) {
++ /* Not in use? */
++ if (copy[i].request == 0)
++ continue;
++
++ /* Grab a request slot and copy shadow state into it. */
++ req = RING_GET_REQUEST(
++ &info->ring, info->ring.req_prod_pvt);
++ *req = copy[i].req;
++
++ /* We get a new request id, and must reset the shadow state. */
++ req->id = GET_ID_FROM_FREELIST(info);
++ memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i]));
++
++ /* Rewrite any grant references invalidated by susp/resume. */
++ for (j = 0; j < req->nr_segments; j++)
++ gnttab_grant_foreign_access_ref(
++ req->seg[j].gref,
++ info->xbdev->otherend_id,
++ pfn_to_mfn(info->shadow[req->id].frame[j]),
++ rq_data_dir(
++ (struct request *)
++ info->shadow[req->id].request));
++ info->shadow[req->id].req = *req;
++
++ info->ring.req_prod_pvt++;
++ }
++
++ kfree(copy);
++
++ (void)xenbus_switch_state(info->xbdev, XenbusStateConnected);
++
++ spin_lock_irq(&blkif_io_lock);
++
++ /* Now safe for us to use the shared ring */
++ info->connected = BLKIF_STATE_CONNECTED;
++
++ /* Send off requeued requests */
++ flush_requests(info);
++
++ /* Kick any other new requests queued since we resumed */
++ kick_pending_request_queues(info);
++
++ spin_unlock_irq(&blkif_io_lock);
++}
++
++
++/* ** Driver Registration ** */
++
++
++static struct xenbus_device_id blkfront_ids[] = {
++ { "vbd" },
++ { "" }
++};
++
++
++static struct xenbus_driver blkfront = {
++ .name = "vbd",
++ .owner = THIS_MODULE,
++ .ids = blkfront_ids,
++ .probe = blkfront_probe,
++ .remove = blkfront_remove,
++ .resume = blkfront_resume,
++ .otherend_changed = backend_changed,
++};
++
++
++static int __init xlblk_init(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ return xenbus_register_frontend(&blkfront);
++}
++module_init(xlblk_init);
++
++
++static void xlblk_exit(void)
++{
++ return xenbus_unregister_driver(&blkfront);
++}
++module_exit(xlblk_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkfront/block.h linux-2.6.18-xen/drivers/xen/blkfront/block.h
+--- linux-2.6.18.1/drivers/xen/blkfront/block.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkfront/block.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,154 @@
++/******************************************************************************
++ * block.h
++ *
++ * Shared definitions between all levels of XenLinux Virtual block devices.
++ *
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
++ * Copyright (c) 2004-2005, Christian Limpach
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __XEN_DRIVERS_BLOCK_H__
++#define __XEN_DRIVERS_BLOCK_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/hdreg.h>
++#include <linux/blkdev.h>
++#include <linux/major.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++#include <xen/gnttab.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/io/blkif.h>
++#include <xen/interface/io/ring.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#if 1
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "xen_blk: " fmt, ##args)
++#else
++#define IPRINTK(fmt, args...) ((void)0)
++#endif
++
++#if 1
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "xen_blk: " fmt, ##args)
++#else
++#define WPRINTK(fmt, args...) ((void)0)
++#endif
++
++#define DPRINTK(_f, _a...) pr_debug(_f, ## _a)
++
++#if 0
++#define DPRINTK_IOCTL(_f, _a...) printk(KERN_ALERT _f, ## _a)
++#else
++#define DPRINTK_IOCTL(_f, _a...) ((void)0)
++#endif
++
++struct xlbd_type_info
++{
++ int partn_shift;
++ int disks_per_major;
++ char *devname;
++ char *diskname;
++};
++
++struct xlbd_major_info
++{
++ int major;
++ int index;
++ int usage;
++ struct xlbd_type_info *type;
++};
++
++struct blk_shadow {
++ blkif_request_t req;
++ unsigned long request;
++ unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++};
++
++#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
++
++/*
++ * We have one of these per vbd, whether ide, scsi or 'other'. They
++ * hang in private_data off the gendisk structure. We may end up
++ * putting all kinds of interesting stuff here :-)
++ */
++struct blkfront_info
++{
++ struct xenbus_device *xbdev;
++ dev_t dev;
++ struct gendisk *gd;
++ int vdevice;
++ blkif_vdev_t handle;
++ int connected;
++ int ring_ref;
++ blkif_front_ring_t ring;
++ unsigned int evtchn, irq;
++ struct xlbd_major_info *mi;
++ request_queue_t *rq;
++ struct work_struct work;
++ struct gnttab_free_callback callback;
++ struct blk_shadow shadow[BLK_RING_SIZE];
++ unsigned long shadow_free;
++
++ /**
++ * The number of people holding this device open. We won't allow a
++ * hot-unplug unless this is 0.
++ */
++ int users;
++};
++
++extern spinlock_t blkif_io_lock;
++
++extern int blkif_open(struct inode *inode, struct file *filep);
++extern int blkif_release(struct inode *inode, struct file *filep);
++extern int blkif_ioctl(struct inode *inode, struct file *filep,
++ unsigned command, unsigned long argument);
++extern int blkif_getgeo(struct block_device *, struct hd_geometry *);
++extern int blkif_check(dev_t dev);
++extern int blkif_revalidate(dev_t dev);
++extern void do_blkif_request (request_queue_t *rq);
++
++/* Virtual block-device subsystem. */
++/* Note that xlvbd_add doesn't call add_disk for you: you're expected
++ to call add_disk on info->gd once the disk is properly connected
++ up. */
++int xlvbd_add(blkif_sector_t capacity, int device,
++ u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
++void xlvbd_del(struct blkfront_info *info);
++
++#endif /* __XEN_DRIVERS_BLOCK_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkfront/Kconfig linux-2.6.18-xen/drivers/xen/blkfront/Kconfig
+--- linux-2.6.18.1/drivers/xen/blkfront/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkfront/Kconfig 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,6 @@
++
++config XENBLOCK
++ tristate "Block device driver"
++ depends on ARCH_XEN
++ help
++ Block device driver for Xen
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkfront/Makefile linux-2.6.18-xen/drivers/xen/blkfront/Makefile
+--- linux-2.6.18.1/drivers/xen/blkfront/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkfront/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,5 @@
++
++obj-$(CONFIG_XEN_BLKDEV_FRONTEND) := xenblk.o
++
++xenblk-objs := blkfront.o vbd.o
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blkfront/vbd.c linux-2.6.18-xen/drivers/xen/blkfront/vbd.c
+--- linux-2.6.18.1/drivers/xen/blkfront/vbd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blkfront/vbd.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,318 @@
++/******************************************************************************
++ * vbd.c
++ *
++ * XenLinux virtual block-device driver (xvd).
++ *
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
++ * Copyright (c) 2004-2005, Christian Limpach
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include "block.h"
++#include <linux/blkdev.h>
++#include <linux/list.h>
++
++#define BLKIF_MAJOR(dev) ((dev)>>8)
++#define BLKIF_MINOR(dev) ((dev) & 0xff)
++
++/*
++ * For convenience we distinguish between ide, scsi and 'other' (i.e.,
++ * potentially combinations of the two) in the naming scheme and in a few other
++ * places.
++ */
++
++#define NUM_IDE_MAJORS 10
++#define NUM_SCSI_MAJORS 9
++#define NUM_VBD_MAJORS 1
++
++static struct xlbd_type_info xlbd_ide_type = {
++ .partn_shift = 6,
++ .disks_per_major = 2,
++ .devname = "ide",
++ .diskname = "hd",
++};
++
++static struct xlbd_type_info xlbd_scsi_type = {
++ .partn_shift = 4,
++ .disks_per_major = 16,
++ .devname = "sd",
++ .diskname = "sd",
++};
++
++static struct xlbd_type_info xlbd_vbd_type = {
++ .partn_shift = 4,
++ .disks_per_major = 16,
++ .devname = "xvd",
++ .diskname = "xvd",
++};
++
++static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
++ NUM_VBD_MAJORS];
++
++#define XLBD_MAJOR_IDE_START 0
++#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
++#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
++
++#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
++#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
++#define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
++
++/* Information about our VBDs. */
++#define MAX_VBDS 64
++static LIST_HEAD(vbds_list);
++
++static struct block_device_operations xlvbd_block_fops =
++{
++ .owner = THIS_MODULE,
++ .open = blkif_open,
++ .release = blkif_release,
++ .ioctl = blkif_ioctl,
++ .getgeo = blkif_getgeo
++};
++
++DEFINE_SPINLOCK(blkif_io_lock);
++
++static struct xlbd_major_info *
++xlbd_alloc_major_info(int major, int minor, int index)
++{
++ struct xlbd_major_info *ptr;
++
++ ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
++ if (ptr == NULL)
++ return NULL;
++
++ ptr->major = major;
++
++ switch (index) {
++ case XLBD_MAJOR_IDE_RANGE:
++ ptr->type = &xlbd_ide_type;
++ ptr->index = index - XLBD_MAJOR_IDE_START;
++ break;
++ case XLBD_MAJOR_SCSI_RANGE:
++ ptr->type = &xlbd_scsi_type;
++ ptr->index = index - XLBD_MAJOR_SCSI_START;
++ break;
++ case XLBD_MAJOR_VBD_RANGE:
++ ptr->type = &xlbd_vbd_type;
++ ptr->index = index - XLBD_MAJOR_VBD_START;
++ break;
++ }
++
++ printk("Registering block device major %i\n", ptr->major);
++ if (register_blkdev(ptr->major, ptr->type->devname)) {
++ WPRINTK("can't get major %d with name %s\n",
++ ptr->major, ptr->type->devname);
++ kfree(ptr);
++ return NULL;
++ }
++
++/* devfs_mk_dir(ptr->type->devname);*/
++ major_info[index] = ptr;
++ return ptr;
++}
++
++static struct xlbd_major_info *
++xlbd_get_major_info(int vdevice)
++{
++ struct xlbd_major_info *mi;
++ int major, minor, index;
++
++ major = BLKIF_MAJOR(vdevice);
++ minor = BLKIF_MINOR(vdevice);
++
++ switch (major) {
++ case IDE0_MAJOR: index = 0; break;
++ case IDE1_MAJOR: index = 1; break;
++ case IDE2_MAJOR: index = 2; break;
++ case IDE3_MAJOR: index = 3; break;
++ case IDE4_MAJOR: index = 4; break;
++ case IDE5_MAJOR: index = 5; break;
++ case IDE6_MAJOR: index = 6; break;
++ case IDE7_MAJOR: index = 7; break;
++ case IDE8_MAJOR: index = 8; break;
++ case IDE9_MAJOR: index = 9; break;
++ case SCSI_DISK0_MAJOR: index = 10; break;
++ case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
++ index = 11 + major - SCSI_DISK1_MAJOR;
++ break;
++ case SCSI_CDROM_MAJOR: index = 18; break;
++ default: index = 19; break;
++ }
++
++ mi = ((major_info[index] != NULL) ? major_info[index] :
++ xlbd_alloc_major_info(major, minor, index));
++ if (mi)
++ mi->usage++;
++ return mi;
++}
++
++static void
++xlbd_put_major_info(struct xlbd_major_info *mi)
++{
++ mi->usage--;
++ /* XXX: release major if 0 */
++}
++
++static int
++xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
++{
++ request_queue_t *rq;
++
++ rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
++ if (rq == NULL)
++ return -1;
++
++ elevator_init(rq, "noop");
++
++ /* Hard sector size and max sectors impersonate the equiv. hardware. */
++ blk_queue_hardsect_size(rq, sector_size);
++ blk_queue_max_sectors(rq, 512);
++
++ /* Each segment in a request is up to an aligned page in size. */
++ blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
++ blk_queue_max_segment_size(rq, PAGE_SIZE);
++
++ /* Ensure a merged request will fit in a single I/O ring slot. */
++ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
++ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
++
++ /* Make sure buffer addresses are sector-aligned. */
++ blk_queue_dma_alignment(rq, 511);
++
++ gd->queue = rq;
++
++ return 0;
++}
++
++static int
++xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
++ u16 vdisk_info, u16 sector_size,
++ struct blkfront_info *info)
++{
++ struct gendisk *gd;
++ struct xlbd_major_info *mi;
++ int nr_minors = 1;
++ int err = -ENODEV;
++
++ BUG_ON(info->gd != NULL);
++ BUG_ON(info->mi != NULL);
++ BUG_ON(info->rq != NULL);
++
++ mi = xlbd_get_major_info(vdevice);
++ if (mi == NULL)
++ goto out;
++ info->mi = mi;
++
++ if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
++ nr_minors = 1 << mi->type->partn_shift;
++
++ gd = alloc_disk(nr_minors);
++ if (gd == NULL)
++ goto out;
++
++ if (nr_minors > 1)
++ sprintf(gd->disk_name, "%s%c", mi->type->diskname,
++ 'a' + mi->index * mi->type->disks_per_major +
++ (minor >> mi->type->partn_shift));
++ else
++ sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
++ 'a' + mi->index * mi->type->disks_per_major +
++ (minor >> mi->type->partn_shift),
++ minor & ((1 << mi->type->partn_shift) - 1));
++
++ gd->major = mi->major;
++ gd->first_minor = minor;
++ gd->fops = &xlvbd_block_fops;
++ gd->private_data = info;
++ gd->driverfs_dev = &(info->xbdev->dev);
++ set_capacity(gd, capacity);
++
++ if (xlvbd_init_blk_queue(gd, sector_size)) {
++ del_gendisk(gd);
++ goto out;
++ }
++
++ info->rq = gd->queue;
++
++ if (vdisk_info & VDISK_READONLY)
++ set_disk_ro(gd, 1);
++
++ if (vdisk_info & VDISK_REMOVABLE)
++ gd->flags |= GENHD_FL_REMOVABLE;
++
++ if (vdisk_info & VDISK_CDROM)
++ gd->flags |= GENHD_FL_CD;
++
++ info->gd = gd;
++
++ return 0;
++
++ out:
++ if (mi)
++ xlbd_put_major_info(mi);
++ info->mi = NULL;
++ return err;
++}
++
++int
++xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
++ u16 sector_size, struct blkfront_info *info)
++{
++ struct block_device *bd;
++ int err = 0;
++
++ info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice));
++
++ bd = bdget(info->dev);
++ if (bd == NULL)
++ return -ENODEV;
++
++ err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice,
++ vdisk_info, sector_size, info);
++
++ bdput(bd);
++ return err;
++}
++
++void
++xlvbd_del(struct blkfront_info *info)
++{
++ if (info->mi == NULL)
++ return;
++
++ BUG_ON(info->gd == NULL);
++ del_gendisk(info->gd);
++ put_disk(info->gd);
++ info->gd = NULL;
++
++ xlbd_put_major_info(info->mi);
++ info->mi = NULL;
++
++ BUG_ON(info->rq == NULL);
++ blk_cleanup_queue(info->rq);
++ info->rq = NULL;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blktap/blktapmain.c linux-2.6.18-xen/drivers/xen/blktap/blktapmain.c
+--- linux-2.6.18.1/drivers/xen/blktap/blktapmain.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blktap/blktapmain.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,1393 @@
++/******************************************************************************
++ * drivers/xen/blktap/blktap.c
++ *
++ * Back-end driver for user level virtual block devices. This portion of the
++ * driver exports a 'unified' block-device interface that can be accessed
++ * by any operating system that implements a compatible front end. Requests
++ * are remapped to a user-space memory region.
++ *
++ * Based on the blkback driver code.
++ *
++ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/spinlock.h>
++#include <linux/kthread.h>
++#include <linux/list.h>
++#include <asm/hypervisor.h>
++#include "common.h"
++#include <xen/balloon.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/errno.h>
++#include <linux/major.h>
++#include <linux/gfp.h>
++#include <linux/poll.h>
++#include <asm/tlbflush.h>
++
++#define MAX_TAP_DEV 100 /*the maximum number of tapdisk ring devices */
++#define MAX_DEV_NAME 100 /*the max tapdisk ring device name e.g. blktap0 */
++
++
++struct class *xen_class;
++EXPORT_SYMBOL_GPL(xen_class);
++
++/*
++ * Setup the xen class. This should probably go in another file, but
++ * since blktap is the only user of it so far, it gets to keep it.
++ */
++int setup_xen_class(void)
++{
++ int ret;
++
++ if (xen_class)
++ return 0;
++
++ xen_class = class_create(THIS_MODULE, "xen");
++ if ((ret = IS_ERR(xen_class))) {
++ xen_class = NULL;
++ return ret;
++ }
++
++ return 0;
++}
++
++/*
++ * The maximum number of requests that can be outstanding at any time
++ * is determined by
++ *
++ * [mmap_alloc * MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST]
++ *
++ * where mmap_alloc < MAX_DYNAMIC_MEM.
++ *
++ * TODO:
++ * mmap_alloc is initialised to 2 and should be adjustable on the fly via
++ * sysfs.
++ */
++#define MAX_DYNAMIC_MEM 64
++#define MAX_PENDING_REQS 64
++#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
++#define MMAP_VADDR(_start, _req,_seg) \
++ (_start + \
++ ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \
++ ((_seg) * PAGE_SIZE))
++static int blkif_reqs = MAX_PENDING_REQS;
++static int mmap_pages = MMAP_PAGES;
++
++#define RING_PAGES 1 /* BLKTAP - immediately before the mmap area, we
++ * have a bunch of pages reserved for shared
++ * memory rings.
++ */
++
++/*Data struct associated with each of the tapdisk devices*/
++typedef struct tap_blkif {
++ struct vm_area_struct *vma; /*Shared memory area */
++ unsigned long rings_vstart; /*Kernel memory mapping */
++ unsigned long user_vstart; /*User memory mapping */
++ unsigned long dev_inuse; /*One process opens device at a time. */
++ unsigned long dev_pending; /*In process of being opened */
++ unsigned long ring_ok; /*make this ring->state */
++ blkif_front_ring_t ufe_ring; /*Rings up to user space. */
++ wait_queue_head_t wait; /*for poll */
++ unsigned long mode; /*current switching mode */
++ int minor; /*Minor number for tapdisk device */
++ pid_t pid; /*tapdisk process id */
++ enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace
++ shutdown */
++ unsigned long *idx_map; /*Record the user ring id to kern
++ [req id, idx] tuple */
++ blkif_t *blkif; /*Associate blkif with tapdev */
++ int sysfs_set; /*Set if it has a class device. */
++} tap_blkif_t;
++
++/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
++typedef struct domid_translate {
++ unsigned short domid;
++ unsigned short busid;
++} domid_translate_t ;
++
++static domid_translate_t translate_domid[MAX_TAP_DEV];
++static tap_blkif_t *tapfds[MAX_TAP_DEV];
++
++static int __init set_blkif_reqs(char *str)
++{
++ get_option(&str, &blkif_reqs);
++ return 1;
++}
++__setup("blkif_reqs=", set_blkif_reqs);
++
++/* Run-time switchable: /sys/module/blktap/parameters/ */
++static unsigned int log_stats = 0;
++static unsigned int debug_lvl = 0;
++module_param(log_stats, int, 0644);
++module_param(debug_lvl, int, 0644);
++
++/*
++ * Each outstanding request that we've passed to the lower device layers has a
++ * 'pending_req' allocated to it. Each buffer_head that completes decrements
++ * the pendcnt towards zero. When it hits zero, the specified domain has a
++ * response queued for it, with the saved 'id' passed back.
++ */
++typedef struct {
++ blkif_t *blkif;
++ unsigned long id;
++ unsigned short mem_idx;
++ int nr_pages;
++ atomic_t pendcnt;
++ unsigned short operation;
++ int status;
++ struct list_head free_list;
++ int inuse;
++} pending_req_t;
++
++static pending_req_t *pending_reqs[MAX_PENDING_REQS];
++static struct list_head pending_free;
++static DEFINE_SPINLOCK(pending_free_lock);
++static DECLARE_WAIT_QUEUE_HEAD (pending_free_wq);
++static int alloc_pending_reqs;
++
++typedef unsigned int PEND_RING_IDX;
++
++static inline int MASK_PEND_IDX(int i) {
++ return (i & (MAX_PENDING_REQS-1));
++}
++
++static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) {
++ return (req - pending_reqs[idx]);
++}
++
++#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++
++#define BLKBACK_INVALID_HANDLE (~0)
++
++static struct page **foreign_pages[MAX_DYNAMIC_MEM];
++static inline unsigned long idx_to_kaddr(
++ unsigned int mmap_idx, unsigned int req_idx, unsigned int sg_idx)
++{
++ unsigned int arr_idx = req_idx*BLKIF_MAX_SEGMENTS_PER_REQUEST + sg_idx;
++ unsigned long pfn = page_to_pfn(foreign_pages[mmap_idx][arr_idx]);
++ return (unsigned long)pfn_to_kaddr(pfn);
++}
++
++static unsigned short mmap_alloc = 0;
++static unsigned short mmap_lock = 0;
++static unsigned short mmap_inuse = 0;
++
++/******************************************************************
++ * GRANT HANDLES
++ */
++
++/* When using grant tables to map a frame for device access then the
++ * handle returned must be used to unmap the frame. This is needed to
++ * drop the ref count on the frame.
++ */
++struct grant_handle_pair
++{
++ grant_handle_t kernel;
++ grant_handle_t user;
++};
++
++static struct grant_handle_pair
++ pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES];
++#define pending_handle(_id, _idx, _i) \
++ (pending_grant_handles[_id][((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) \
++ + (_i)])
++
++
++static int blktap_read_ufe_ring(tap_blkif_t *info); /*local prototypes*/
++
++#define BLKTAP_MINOR 0 /*/dev/xen/blktap has a dynamic major */
++#define BLKTAP_DEV_DIR "/dev/xen"
++
++static int blktap_major;
++
++/* blktap IOCTLs: */
++#define BLKTAP_IOCTL_KICK_FE 1
++#define BLKTAP_IOCTL_KICK_BE 2 /* currently unused */
++#define BLKTAP_IOCTL_SETMODE 3
++#define BLKTAP_IOCTL_SENDPID 4
++#define BLKTAP_IOCTL_NEWINTF 5
++#define BLKTAP_IOCTL_MINOR 6
++#define BLKTAP_IOCTL_MAJOR 7
++#define BLKTAP_QUERY_ALLOC_REQS 8
++#define BLKTAP_IOCTL_FREEINTF 9
++#define BLKTAP_IOCTL_PRINT_IDXS 100
++
++/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
++#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
++#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
++#define BLKTAP_MODE_INTERCEPT_BE 0x00000002 /* unimp. */
++
++#define BLKTAP_MODE_INTERPOSE \
++ (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
++
++
++static inline int BLKTAP_MODE_VALID(unsigned long arg)
++{
++ return ((arg == BLKTAP_MODE_PASSTHROUGH ) ||
++ (arg == BLKTAP_MODE_INTERCEPT_FE) ||
++ (arg == BLKTAP_MODE_INTERPOSE ));
++}
++
++/* Requests passing through the tap to userspace are re-assigned an ID.
++ * We must record a mapping between the BE [IDX,ID] tuple and the userspace
++ * ring ID.
++ */
++
++static inline unsigned long MAKE_ID(domid_t fe_dom, PEND_RING_IDX idx)
++{
++ return ((fe_dom << 16) | MASK_PEND_IDX(idx));
++}
++
++extern inline PEND_RING_IDX ID_TO_IDX(unsigned long id)
++{
++ return (PEND_RING_IDX)(id & 0x0000ffff);
++}
++
++extern inline int ID_TO_MIDX(unsigned long id)
++{
++ return (int)(id >> 16);
++}
++
++#define INVALID_REQ 0xdead0000
++
++/*TODO: Convert to a free list*/
++static inline int GET_NEXT_REQ(unsigned long *idx_map)
++{
++ int i;
++ for (i = 0; i < MAX_PENDING_REQS; i++)
++ if (idx_map[i] == INVALID_REQ)
++ return i;
++
++ return INVALID_REQ;
++}
++
++
++#define BLKTAP_INVALID_HANDLE(_g) \
++ (((_g->kernel) == 0xFFFF) && ((_g->user) == 0xFFFF))
++
++#define BLKTAP_INVALIDATE_HANDLE(_g) do { \
++ (_g)->kernel = 0xFFFF; (_g)->user = 0xFFFF; \
++ } while(0)
++
++
++/******************************************************************
++ * BLKTAP VM OPS
++ */
++
++static struct page *blktap_nopage(struct vm_area_struct *vma,
++ unsigned long address,
++ int *type)
++{
++ /*
++ * if the page has not been mapped in by the driver then return
++ * NOPAGE_SIGBUS to the domain.
++ */
++
++ return NOPAGE_SIGBUS;
++}
++
++struct vm_operations_struct blktap_vm_ops = {
++ nopage: blktap_nopage,
++};
++
++/******************************************************************
++ * BLKTAP FILE OPS
++ */
++
++/*Function Declarations*/
++static int get_next_free_dev(void);
++static int blktap_open(struct inode *inode, struct file *filp);
++static int blktap_release(struct inode *inode, struct file *filp);
++static int blktap_mmap(struct file *filp, struct vm_area_struct *vma);
++static int blktap_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg);
++static unsigned int blktap_poll(struct file *file, poll_table *wait);
++
++static struct file_operations blktap_fops = {
++ .owner = THIS_MODULE,
++ .poll = blktap_poll,
++ .ioctl = blktap_ioctl,
++ .open = blktap_open,
++ .release = blktap_release,
++ .mmap = blktap_mmap,
++};
++
++
++static int get_next_free_dev(void)
++{
++ tap_blkif_t *info;
++ int i = 0, ret = -1;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pending_free_lock, flags);
++
++ while (i < MAX_TAP_DEV) {
++ info = tapfds[i];
++ if ( (tapfds[i] != NULL) && (info->dev_inuse == 0)
++ && (info->dev_pending == 0) ) {
++ info->dev_pending = 1;
++ ret = i;
++ goto done;
++ }
++ i++;
++ }
++
++done:
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++
++ /*
++ * We are protected by having the dev_pending set.
++ */
++ if (!tapfds[i]->sysfs_set && xen_class) {
++ class_device_create(xen_class, NULL,
++ MKDEV(blktap_major, ret), NULL,
++ "blktap%d", ret);
++ tapfds[i]->sysfs_set = 1;
++ }
++ return ret;
++}
++
++int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif)
++{
++ int i;
++
++ for (i = 0; i < MAX_TAP_DEV; i++)
++ if ( (translate_domid[i].domid == domid)
++ && (translate_domid[i].busid == xenbus_id) ) {
++ tapfds[i]->blkif = blkif;
++ tapfds[i]->status = RUNNING;
++ return i;
++ }
++ return -1;
++}
++
++void signal_tapdisk(int idx)
++{
++ tap_blkif_t *info;
++ struct task_struct *ptask;
++
++ info = tapfds[idx];
++ if ( (idx > 0) && (idx < MAX_TAP_DEV) && (info->pid > 0) ) {
++ ptask = find_task_by_pid(info->pid);
++ if (ptask)
++ info->status = CLEANSHUTDOWN;
++ }
++ info->blkif = NULL;
++ return;
++}
++
++static int blktap_open(struct inode *inode, struct file *filp)
++{
++ blkif_sring_t *sring;
++ int idx = iminor(inode) - BLKTAP_MINOR;
++ tap_blkif_t *info;
++ int i;
++
++ if (tapfds[idx] == NULL) {
++ WPRINTK("Unable to open device /dev/xen/blktap%d\n",
++ idx);
++ return -ENOMEM;
++ }
++ DPRINTK("Opening device /dev/xen/blktap%d\n",idx);
++
++ info = tapfds[idx];
++
++ /*Only one process can access device at a time*/
++ if (test_and_set_bit(0, &info->dev_inuse))
++ return -EBUSY;
++
++ info->dev_pending = 0;
++
++ /* Allocate the fe ring. */
++ sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
++ if (sring == NULL)
++ goto fail_nomem;
++
++ SetPageReserved(virt_to_page(sring));
++
++ SHARED_RING_INIT(sring);
++ FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE);
++
++ filp->private_data = info;
++ info->vma = NULL;
++
++ info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS,
++ GFP_KERNEL);
++
++ if (idx > 0) {
++ init_waitqueue_head(&info->wait);
++ for (i = 0; i < MAX_PENDING_REQS; i++)
++ info->idx_map[i] = INVALID_REQ;
++ }
++
++ DPRINTK("Tap open: device /dev/xen/blktap%d\n",idx);
++ return 0;
++
++ fail_nomem:
++ return -ENOMEM;
++}
++
++static int blktap_release(struct inode *inode, struct file *filp)
++{
++ tap_blkif_t *info = filp->private_data;
++
++ /* can this ever happen? - sdr */
++ if (!info) {
++ WPRINTK("Trying to free device that doesn't exist "
++ "[/dev/xen/blktap%d]\n",iminor(inode) - BLKTAP_MINOR);
++ return -EBADF;
++ }
++ info->dev_inuse = 0;
++ DPRINTK("Freeing device [/dev/xen/blktap%d]\n",info->minor);
++
++ /* Free the ring page. */
++ ClearPageReserved(virt_to_page(info->ufe_ring.sring));
++ free_page((unsigned long) info->ufe_ring.sring);
++
++ /* Clear any active mappings and free foreign map table */
++ if (info->vma) {
++ zap_page_range(
++ info->vma, info->vma->vm_start,
++ info->vma->vm_end - info->vma->vm_start, NULL);
++ info->vma = NULL;
++ }
++
++ if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
++ kthread_stop(info->blkif->xenblkd);
++ info->blkif->xenblkd = NULL;
++ info->status = CLEANSHUTDOWN;
++ }
++ return 0;
++}
++
++
++/* Note on mmap:
++ * We need to map pages to user space in a way that will allow the block
++ * subsystem set up direct IO to them. This couldn't be done before, because
++ * there isn't really a sane way to translate a user virtual address down to a
++ * physical address when the page belongs to another domain.
++ *
++ * My first approach was to map the page in to kernel memory, add an entry
++ * for it in the physical frame list (using alloc_lomem_region as in blkback)
++ * and then attempt to map that page up to user space. This is disallowed
++ * by xen though, which realizes that we don't really own the machine frame
++ * underlying the physical page.
++ *
++ * The new approach is to provide explicit support for this in xen linux.
++ * The VMA now has a flag, VM_FOREIGN, to indicate that it contains pages
++ * mapped from other vms. vma->vm_private_data is set up as a mapping
++ * from pages to actual page structs. There is a new clause in get_user_pages
++ * that does the right thing for this sort of mapping.
++ */
++static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ int size;
++ struct page **map;
++ int i;
++ tap_blkif_t *info = filp->private_data;
++
++ if (info == NULL) {
++ WPRINTK("blktap: mmap, retrieving idx failed\n");
++ return -ENOMEM;
++ }
++
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_ops = &blktap_vm_ops;
++
++ size = vma->vm_end - vma->vm_start;
++ if (size != ((mmap_pages + RING_PAGES) << PAGE_SHIFT)) {
++ WPRINTK("you _must_ map exactly %d pages!\n",
++ mmap_pages + RING_PAGES);
++ return -EAGAIN;
++ }
++
++ size >>= PAGE_SHIFT;
++ info->rings_vstart = vma->vm_start;
++ info->user_vstart = info->rings_vstart + (RING_PAGES << PAGE_SHIFT);
++
++ /* Map the ring pages to the start of the region and reserve it. */
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++ if (remap_pfn_range(vma, vma->vm_start,
++ __pa(info->ufe_ring.sring) >> PAGE_SHIFT,
++ PAGE_SIZE, vma->vm_page_prot)) {
++ WPRINTK("Mapping user ring failed!\n");
++ goto fail;
++ }
++
++ /* Mark this VM as containing foreign pages, and set up mappings. */
++ map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT)
++ * sizeof(struct page_struct*),
++ GFP_KERNEL);
++ if (map == NULL) {
++ WPRINTK("Couldn't alloc VM_FOREIGN map.\n");
++ goto fail;
++ }
++
++ for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++)
++ map[i] = NULL;
++
++ vma->vm_private_data = map;
++ vma->vm_flags |= VM_FOREIGN;
++
++ info->vma = vma;
++ info->ring_ok = 1;
++ return 0;
++ fail:
++ /* Clear any active mappings. */
++ zap_page_range(vma, vma->vm_start,
++ vma->vm_end - vma->vm_start, NULL);
++
++ return -ENOMEM;
++}
++
++
++static int blktap_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ tap_blkif_t *info = filp->private_data;
++
++ switch(cmd) {
++ case BLKTAP_IOCTL_KICK_FE:
++ {
++ /* There are fe messages to process. */
++ return blktap_read_ufe_ring(info);
++ }
++ case BLKTAP_IOCTL_SETMODE:
++ {
++ if (info) {
++ if (BLKTAP_MODE_VALID(arg)) {
++ info->mode = arg;
++ /* XXX: may need to flush rings here. */
++ DPRINTK("blktap: set mode to %lx\n",
++ arg);
++ return 0;
++ }
++ }
++ return 0;
++ }
++ case BLKTAP_IOCTL_PRINT_IDXS:
++ {
++ if (info) {
++ printk("User Rings: \n-----------\n");
++ printk("UF: rsp_cons: %2d, req_prod_prv: %2d "
++ "| req_prod: %2d, rsp_prod: %2d\n",
++ info->ufe_ring.rsp_cons,
++ info->ufe_ring.req_prod_pvt,
++ info->ufe_ring.sring->req_prod,
++ info->ufe_ring.sring->rsp_prod);
++ }
++ return 0;
++ }
++ case BLKTAP_IOCTL_SENDPID:
++ {
++ if (info) {
++ info->pid = (pid_t)arg;
++ DPRINTK("blktap: pid received %d\n",
++ info->pid);
++ }
++ return 0;
++ }
++ case BLKTAP_IOCTL_NEWINTF:
++ {
++ uint64_t val = (uint64_t)arg;
++ domid_translate_t *tr = (domid_translate_t *)&val;
++ int newdev;
++
++ DPRINTK("NEWINTF Req for domid %d and bus id %d\n",
++ tr->domid, tr->busid);
++ newdev = get_next_free_dev();
++ if (newdev < 1) {
++ WPRINTK("Error initialising /dev/xen/blktap - "
++ "No more devices\n");
++ return -1;
++ }
++ translate_domid[newdev].domid = tr->domid;
++ translate_domid[newdev].busid = tr->busid;
++ return newdev;
++ }
++ case BLKTAP_IOCTL_FREEINTF:
++ {
++ unsigned long dev = arg;
++ unsigned long flags;
++
++ /* Looking at another device */
++ info = NULL;
++
++ if ( (dev > 0) && (dev < MAX_TAP_DEV) )
++ info = tapfds[dev];
++
++ spin_lock_irqsave(&pending_free_lock, flags);
++ if ( (info != NULL) && (info->dev_pending) )
++ info->dev_pending = 0;
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++
++ return 0;
++ }
++ case BLKTAP_IOCTL_MINOR:
++ {
++ unsigned long dev = arg;
++
++ /* Looking at another device */
++ info = NULL;
++
++ if ( (dev > 0) && (dev < MAX_TAP_DEV) )
++ info = tapfds[dev];
++
++ if (info != NULL)
++ return info->minor;
++ else
++ return -1;
++ }
++ case BLKTAP_IOCTL_MAJOR:
++ return blktap_major;
++
++ case BLKTAP_QUERY_ALLOC_REQS:
++ {
++ WPRINTK("BLKTAP_QUERY_ALLOC_REQS ioctl: %d/%d\n",
++ alloc_pending_reqs, blkif_reqs);
++ return (alloc_pending_reqs/blkif_reqs) * 100;
++ }
++ }
++ return -ENOIOCTLCMD;
++}
++
++static unsigned int blktap_poll(struct file *filp, poll_table *wait)
++{
++ tap_blkif_t *info = filp->private_data;
++
++ if (!info) {
++ WPRINTK(" poll, retrieving idx failed\n");
++ return 0;
++ }
++
++ /* do not work on the control device */
++ if (!info->minor)
++ return 0;
++
++ poll_wait(filp, &info->wait, wait);
++ if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) {
++ RING_PUSH_REQUESTS(&info->ufe_ring);
++ return POLLIN | POLLRDNORM;
++ }
++ return 0;
++}
++
++void blktap_kick_user(int idx)
++{
++ tap_blkif_t *info;
++
++ if (idx == 0)
++ return;
++
++ info = tapfds[idx];
++
++ if (info != NULL)
++ wake_up_interruptible(&info->wait);
++
++ return;
++}
++
++static int do_block_io_op(blkif_t *blkif);
++static void dispatch_rw_block_io(blkif_t *blkif,
++ blkif_request_t *req,
++ pending_req_t *pending_req);
++static void make_response(blkif_t *blkif, unsigned long id,
++ unsigned short op, int st);
++
++/******************************************************************
++ * misc small helpers
++ */
++static int req_increase(void)
++{
++ int i, j;
++
++ if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock)
++ return -EINVAL;
++
++ pending_reqs[mmap_alloc] = kzalloc(sizeof(pending_req_t)
++ * blkif_reqs, GFP_KERNEL);
++ foreign_pages[mmap_alloc] = alloc_empty_pages_and_pagevec(mmap_pages);
++
++ if (!pending_reqs[mmap_alloc] || !foreign_pages[mmap_alloc])
++ goto out_of_memory;
++
++ DPRINTK("%s: reqs=%d, pages=%d\n",
++ __FUNCTION__, blkif_reqs, mmap_pages);
++
++ for (i = 0; i < MAX_PENDING_REQS; i++) {
++ list_add_tail(&pending_reqs[mmap_alloc][i].free_list,
++ &pending_free);
++ pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc;
++ for (j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++)
++ BLKTAP_INVALIDATE_HANDLE(&pending_handle(mmap_alloc,
++ i, j));
++ }
++
++ mmap_alloc++;
++ DPRINTK("# MMAPs increased to %d\n",mmap_alloc);
++ return 0;
++
++ out_of_memory:
++ free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
++ kfree(pending_reqs[mmap_alloc]);
++ WPRINTK("%s: out of memory\n", __FUNCTION__);
++ return -ENOMEM;
++}
++
++static void mmap_req_del(int mmap)
++{
++ BUG_ON(!spin_is_locked(&pending_free_lock));
++
++ kfree(pending_reqs[mmap]);
++ pending_reqs[mmap] = NULL;
++
++ free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
++ foreign_pages[mmap] = NULL;
++
++ mmap_lock = 0;
++ DPRINTK("# MMAPs decreased to %d\n",mmap_alloc);
++ mmap_alloc--;
++}
++
++static pending_req_t* alloc_req(void)
++{
++ pending_req_t *req = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pending_free_lock, flags);
++
++ if (!list_empty(&pending_free)) {
++ req = list_entry(pending_free.next, pending_req_t, free_list);
++ list_del(&req->free_list);
++ }
++
++ if (req) {
++ req->inuse = 1;
++ alloc_pending_reqs++;
++ }
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++
++ return req;
++}
++
++static void free_req(pending_req_t *req)
++{
++ unsigned long flags;
++ int was_empty;
++
++ spin_lock_irqsave(&pending_free_lock, flags);
++
++ alloc_pending_reqs--;
++ req->inuse = 0;
++ if (mmap_lock && (req->mem_idx == mmap_alloc-1)) {
++ mmap_inuse--;
++ if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++ return;
++ }
++ was_empty = list_empty(&pending_free);
++ list_add(&req->free_list, &pending_free);
++
++ spin_unlock_irqrestore(&pending_free_lock, flags);
++
++ if (was_empty)
++ wake_up(&pending_free_wq);
++}
++
++static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, int
++ tapidx)
++{
++ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
++ unsigned int i, invcount = 0;
++ struct grant_handle_pair *khandle;
++ uint64_t ptep;
++ int ret, mmap_idx;
++ unsigned long kvaddr, uvaddr;
++
++ tap_blkif_t *info = tapfds[tapidx];
++
++ if (info == NULL) {
++ WPRINTK("fast_flush: Couldn't get info!\n");
++ return;
++ }
++ mmap_idx = req->mem_idx;
++
++ for (i = 0; i < req->nr_pages; i++) {
++ kvaddr = idx_to_kaddr(mmap_idx, k_idx, i);
++ uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
++
++ khandle = &pending_handle(mmap_idx, k_idx, i);
++ if (BLKTAP_INVALID_HANDLE(khandle)) {
++ WPRINTK("BLKTAP_INVALID_HANDLE\n");
++ continue;
++ }
++ gnttab_set_unmap_op(&unmap[invcount],
++ idx_to_kaddr(mmap_idx, k_idx, i),
++ GNTMAP_host_map, khandle->kernel);
++ invcount++;
++
++ if (create_lookup_pte_addr(
++ info->vma->vm_mm,
++ MMAP_VADDR(info->user_vstart, u_idx, i),
++ &ptep) !=0) {
++ WPRINTK("Couldn't get a pte addr!\n");
++ return;
++ }
++
++ gnttab_set_unmap_op(&unmap[invcount],
++ ptep, GNTMAP_host_map,
++ khandle->user);
++ invcount++;
++
++ BLKTAP_INVALIDATE_HANDLE(khandle);
++ }
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_unmap_grant_ref, unmap, invcount);
++ BUG_ON(ret);
++
++ if (info->vma != NULL)
++ zap_page_range(info->vma,
++ MMAP_VADDR(info->user_vstart, u_idx, 0),
++ req->nr_pages << PAGE_SHIFT, NULL);
++}
++
++/******************************************************************
++ * SCHEDULER FUNCTIONS
++ */
++
++static void print_stats(blkif_t *blkif)
++{
++ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d\n",
++ current->comm, blkif->st_oo_req,
++ blkif->st_rd_req, blkif->st_wr_req);
++ blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
++ blkif->st_rd_req = 0;
++ blkif->st_wr_req = 0;
++ blkif->st_oo_req = 0;
++}
++
++int tap_blkif_schedule(void *arg)
++{
++ blkif_t *blkif = arg;
++
++ blkif_get(blkif);
++
++ if (debug_lvl)
++ printk(KERN_DEBUG "%s: started\n", current->comm);
++
++ while (!kthread_should_stop()) {
++ wait_event_interruptible(
++ blkif->wq,
++ blkif->waiting_reqs || kthread_should_stop());
++ wait_event_interruptible(
++ pending_free_wq,
++ !list_empty(&pending_free) || kthread_should_stop());
++
++ blkif->waiting_reqs = 0;
++ smp_mb(); /* clear flag *before* checking for work */
++
++ if (do_block_io_op(blkif))
++ blkif->waiting_reqs = 1;
++
++ if (log_stats && time_after(jiffies, blkif->st_print))
++ print_stats(blkif);
++ }
++
++ if (log_stats)
++ print_stats(blkif);
++ if (debug_lvl)
++ printk(KERN_DEBUG "%s: exiting\n", current->comm);
++
++ blkif->xenblkd = NULL;
++ blkif_put(blkif);
++
++ return 0;
++}
++
++/******************************************************************
++ * COMPLETION CALLBACK -- Called by user level ioctl()
++ */
++
++static int blktap_read_ufe_ring(tap_blkif_t *info)
++{
++ /* This is called to read responses from the UFE ring. */
++ RING_IDX i, j, rp;
++ blkif_response_t *resp;
++ blkif_t *blkif=NULL;
++ int pending_idx, usr_idx, mmap_idx;
++ pending_req_t *pending_req;
++
++ if (!info)
++ return 0;
++
++ /* We currently only forward packets in INTERCEPT_FE mode. */
++ if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE))
++ return 0;
++
++ /* for each outstanding message on the UFEring */
++ rp = info->ufe_ring.sring->rsp_prod;
++ rmb();
++
++ for (i = info->ufe_ring.rsp_cons; i != rp; i++) {
++ resp = RING_GET_RESPONSE(&info->ufe_ring, i);
++ ++info->ufe_ring.rsp_cons;
++
++ /*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/
++ usr_idx = (int)resp->id;
++ pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
++ mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
++
++ if ( (mmap_idx >= mmap_alloc) ||
++ (ID_TO_IDX(info->idx_map[usr_idx]) >= MAX_PENDING_REQS) )
++ WPRINTK("Incorrect req map"
++ "[%d], internal map [%d,%d (%d)]\n",
++ usr_idx, mmap_idx,
++ ID_TO_IDX(info->idx_map[usr_idx]),
++ MASK_PEND_IDX(
++ ID_TO_IDX(info->idx_map[usr_idx])));
++
++ pending_req = &pending_reqs[mmap_idx][pending_idx];
++ blkif = pending_req->blkif;
++
++ for (j = 0; j < pending_req->nr_pages; j++) {
++
++ unsigned long kvaddr, uvaddr;
++ struct page **map = info->vma->vm_private_data;
++ struct page *pg;
++ int offset;
++
++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, j);
++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, j);
++
++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++ ClearPageReserved(pg);
++ offset = (uvaddr - info->vma->vm_start)
++ >> PAGE_SHIFT;
++ map[offset] = NULL;
++ }
++ fast_flush_area(pending_req, pending_idx, usr_idx, info->minor);
++ make_response(blkif, pending_req->id, resp->operation,
++ resp->status);
++ info->idx_map[usr_idx] = INVALID_REQ;
++ blkif_put(pending_req->blkif);
++ free_req(pending_req);
++ }
++
++ return 0;
++}
++
++
++/******************************************************************************
++ * NOTIFICATION FROM GUEST OS.
++ */
++
++static void blkif_notify_work(blkif_t *blkif)
++{
++ blkif->waiting_reqs = 1;
++ wake_up(&blkif->wq);
++}
++
++irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ blkif_notify_work(dev_id);
++ return IRQ_HANDLED;
++}
++
++
++
++/******************************************************************
++ * DOWNWARD CALLS -- These interface with the block-device layer proper.
++ */
++static int print_dbug = 1;
++static int do_block_io_op(blkif_t *blkif)
++{
++ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
++ blkif_request_t *req;
++ pending_req_t *pending_req;
++ RING_IDX rc, rp;
++ int more_to_do = 0;
++ tap_blkif_t *info;
++
++ rc = blk_ring->req_cons;
++ rp = blk_ring->sring->req_prod;
++ rmb(); /* Ensure we see queued requests up to 'rp'. */
++
++ /*Check blkif has corresponding UE ring*/
++ if (blkif->dev_num == -1) {
++ /*oops*/
++ if (print_dbug) {
++ WPRINTK("Corresponding UE "
++ "ring does not exist!\n");
++ print_dbug = 0; /*We only print this message once*/
++ }
++ return 0;
++ }
++
++ info = tapfds[blkif->dev_num];
++ if (info == NULL || !info->dev_inuse) {
++ if (print_dbug) {
++ WPRINTK("Can't get UE info!\n");
++ print_dbug = 0;
++ }
++ return 0;
++ }
++
++ while (rc != rp) {
++
++ if (RING_FULL(&info->ufe_ring)) {
++ WPRINTK("RING_FULL! More to do\n");
++ more_to_do = 1;
++ break;
++ }
++
++ if (RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) {
++ WPRINTK("RING_REQUEST_CONS_OVERFLOW!"
++ " More to do\n");
++ more_to_do = 1;
++ break;
++ }
++
++ pending_req = alloc_req();
++ if (NULL == pending_req) {
++ blkif->st_oo_req++;
++ more_to_do = 1;
++ break;
++ }
++
++ req = RING_GET_REQUEST(blk_ring, rc);
++ blk_ring->req_cons = ++rc; /* before make_response() */
++
++ switch (req->operation) {
++ case BLKIF_OP_READ:
++ blkif->st_rd_req++;
++ dispatch_rw_block_io(blkif, req, pending_req);
++ break;
++
++ case BLKIF_OP_WRITE:
++ blkif->st_wr_req++;
++ dispatch_rw_block_io(blkif, req, pending_req);
++ break;
++
++ default:
++ WPRINTK("unknown operation [%d]\n",
++ req->operation);
++ make_response(blkif, req->id, req->operation,
++ BLKIF_RSP_ERROR);
++ free_req(pending_req);
++ break;
++ }
++ }
++
++ blktap_kick_user(blkif->dev_num);
++
++ return more_to_do;
++}
++
++static void dispatch_rw_block_io(blkif_t *blkif,
++ blkif_request_t *req,
++ pending_req_t *pending_req)
++{
++ extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
++ int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
++ struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
++ unsigned int nseg;
++ int ret, i;
++ tap_blkif_t *info = tapfds[blkif->dev_num];
++ uint64_t sector;
++
++ blkif_request_t *target;
++ int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx);
++ int usr_idx = GET_NEXT_REQ(info->idx_map);
++ uint16_t mmap_idx = pending_req->mem_idx;
++
++ /*Check we have space on user ring - should never fail*/
++ if(usr_idx == INVALID_REQ) goto fail_flush;
++
++ /* Check that number of segments is sane. */
++ nseg = req->nr_segments;
++ if ( unlikely(nseg == 0) ||
++ unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) {
++ WPRINTK("Bad number of segments in request (%d)\n", nseg);
++ goto fail_response;
++ }
++
++ /* Make sure userspace is ready. */
++ if (!info->ring_ok) {
++ WPRINTK("blktap: ring not ready for requests!\n");
++ goto fail_response;
++ }
++
++ if (RING_FULL(&info->ufe_ring)) {
++ WPRINTK("blktap: fe_ring is full, can't add "
++ "IO Request will be dropped. %d %d\n",
++ RING_SIZE(&info->ufe_ring),
++ RING_SIZE(&blkif->blk_ring));
++ goto fail_response;
++ }
++
++ pending_req->blkif = blkif;
++ pending_req->id = req->id;
++ pending_req->operation = operation;
++ pending_req->status = BLKIF_RSP_OKAY;
++ pending_req->nr_pages = nseg;
++ op = 0;
++ for (i = 0; i < nseg; i++) {
++ unsigned long uvaddr;
++ unsigned long kvaddr;
++ uint64_t ptep;
++ struct page *page;
++ uint32_t flags;
++
++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++ page = virt_to_page(kvaddr);
++
++ sector = req->sector_number + (8*i);
++ if( (blkif->sectors > 0) && (sector >= blkif->sectors) ) {
++ WPRINTK("BLKTAP: Sector request greater"
++ "than size\n");
++ WPRINTK("BLKTAP: %s request sector"
++ "[%llu,%llu], Total [%llu]\n",
++ (req->operation ==
++ BLKIF_OP_WRITE ? "WRITE" : "READ"),
++ (long long unsigned) sector,
++ (long long unsigned) sector>>9,
++ blkif->sectors);
++ }
++
++ flags = GNTMAP_host_map;
++ if (operation == WRITE)
++ flags |= GNTMAP_readonly;
++ gnttab_set_map_op(&map[op], kvaddr, flags,
++ req->seg[i].gref, blkif->domid);
++ op++;
++
++ /* Now map it to user. */
++ ret = create_lookup_pte_addr(info->vma->vm_mm,
++ uvaddr, &ptep);
++ if (ret) {
++ WPRINTK("Couldn't get a pte addr!\n");
++ fast_flush_area(pending_req, pending_idx, usr_idx,
++ blkif->dev_num);
++ goto fail_flush;
++ }
++
++ flags = GNTMAP_host_map | GNTMAP_application_map
++ | GNTMAP_contains_pte;
++ if (operation == WRITE)
++ flags |= GNTMAP_readonly;
++ gnttab_set_map_op(&map[op], ptep, flags,
++ req->seg[i].gref, blkif->domid);
++ op++;
++ }
++
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
++ BUG_ON(ret);
++
++ for (i = 0; i < (nseg*2); i+=2) {
++ unsigned long uvaddr;
++ unsigned long kvaddr;
++ unsigned long offset;
++ struct page *pg;
++
++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i/2);
++
++ if (unlikely(map[i].status != 0)) {
++ WPRINTK("invalid kernel buffer -- "
++ "could not remap it\n");
++ goto fail_flush;
++ }
++
++ if (unlikely(map[i+1].status != 0)) {
++ WPRINTK("invalid user buffer -- "
++ "could not remap it\n");
++ goto fail_flush;
++ }
++
++ pending_handle(mmap_idx, pending_idx, i/2).kernel
++ = map[i].handle;
++ pending_handle(mmap_idx, pending_idx, i/2).user
++ = map[i+1].handle;
++ set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
++ FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
++ offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++ ((struct page **)info->vma->vm_private_data)[offset] =
++ pg;
++ }
++ /* Mark mapped pages as reserved: */
++ for (i = 0; i < req->nr_segments; i++) {
++ unsigned long kvaddr;
++ struct page *pg;
++
++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++ SetPageReserved(pg);
++ }
++
++ /*record [mmap_idx,pending_idx] to [usr_idx] mapping*/
++ info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx);
++
++ blkif_get(blkif);
++ /* Finally, write the request message to the user ring. */
++ target = RING_GET_REQUEST(&info->ufe_ring,
++ info->ufe_ring.req_prod_pvt);
++ memcpy(target, req, sizeof(*req));
++ target->id = usr_idx;
++ info->ufe_ring.req_prod_pvt++;
++ return;
++
++ fail_flush:
++ WPRINTK("Reached Fail_flush\n");
++ fast_flush_area(pending_req, pending_idx, usr_idx, blkif->dev_num);
++ fail_response:
++ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
++ free_req(pending_req);
++}
++
++
++
++/******************************************************************
++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
++ */
++
++
++static void make_response(blkif_t *blkif, unsigned long id,
++ unsigned short op, int st)
++{
++ blkif_response_t *resp;
++ unsigned long flags;
++ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
++ int more_to_do = 0;
++ int notify;
++
++ spin_lock_irqsave(&blkif->blk_ring_lock, flags);
++ /* Place on the response ring for the relevant domain. */
++ resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
++ resp->id = id;
++ resp->operation = op;
++ resp->status = st;
++ blk_ring->rsp_prod_pvt++;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(blk_ring, notify);
++
++ if (blk_ring->rsp_prod_pvt == blk_ring->req_cons) {
++ /*
++ * Tail check for pending requests. Allows frontend to avoid
++ * notifications if requests are already in flight (lower
++ * overheads and promotes batching).
++ */
++ RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do);
++ } else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
++ more_to_do = 1;
++
++ }
++ spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
++ if (more_to_do)
++ blkif_notify_work(blkif);
++ if (notify)
++ notify_remote_via_irq(blkif->irq);
++}
++
++static int __init blkif_init(void)
++{
++ int i, ret;
++ tap_blkif_t *info;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ INIT_LIST_HEAD(&pending_free);
++ for(i = 0; i < 2; i++) {
++ ret = req_increase();
++ if (ret)
++ break;
++ }
++ if (i == 0)
++ return ret;
++
++ tap_blkif_interface_init();
++
++ alloc_pending_reqs = 0;
++
++ tap_blkif_xenbus_init();
++
++ /*Create the blktap devices, but do not map memory or waitqueue*/
++ for(i = 0; i < MAX_TAP_DEV; i++) translate_domid[i].domid = 0xFFFF;
++
++ /* Dynamically allocate a major for this device */
++ ret = register_chrdev(0, "blktap", &blktap_fops);
++
++ if ( (ret < 0) ) {
++ WPRINTK("Couldn't register /dev/xen/blktap\n");
++ return -ENOMEM;
++ }
++
++ blktap_major = ret;
++
++ for(i = 0; i < MAX_TAP_DEV; i++ ) {
++ info = tapfds[i] = kzalloc(sizeof(tap_blkif_t),GFP_KERNEL);
++ if(tapfds[i] == NULL)
++ return -ENOMEM;
++ info->minor = i;
++ info->pid = 0;
++ info->blkif = NULL;
++
++ info->dev_pending = info->dev_inuse = 0;
++
++ DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
++ }
++
++ /* Make sure the xen class exists */
++ if (!setup_xen_class()) {
++ /*
++ * This will allow udev to create the blktap ctrl device.
++ * We only want to create blktap0 first. We don't want
++ * to flood the sysfs system with needless blktap devices.
++ * We only create the device when a request of a new device is
++ * made.
++ */
++ class_device_create(xen_class, NULL,
++ MKDEV(blktap_major, 0), NULL,
++ "blktap0");
++ tapfds[0]->sysfs_set = 1;
++ } else {
++ /* this is bad, but not fatal */
++ WPRINTK("blktap: sysfs xen_class not created\n");
++ }
++
++ DPRINTK("Blktap device successfully created\n");
++
++ return 0;
++}
++
++module_init(blkif_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blktap/common.h linux-2.6.18-xen/drivers/xen/blktap/common.h
+--- linux-2.6.18.1/drivers/xen/blktap/common.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blktap/common.h 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,120 @@
++/*
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __BLKIF__BACKEND__COMMON_H__
++#define __BLKIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <asm/pgalloc.h>
++#include <xen/evtchn.h>
++#include <asm/hypervisor.h>
++#include <xen/interface/io/blkif.h>
++#include <xen/interface/io/ring.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++
++#define DPRINTK(_f, _a...) pr_debug("(file=%s, line=%d) " _f, \
++ __FILE__ , __LINE__ , ## _a )
++
++#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
++
++struct backend_info;
++
++typedef struct blkif_st {
++ /* Unique identifier for this interface. */
++ domid_t domid;
++ unsigned int handle;
++ /* Physical parameters of the comms window. */
++ unsigned int evtchn;
++ unsigned int irq;
++ /* Comms information. */
++ blkif_back_ring_t blk_ring;
++ struct vm_struct *blk_ring_area;
++ /* Back pointer to the backend_info. */
++ struct backend_info *be;
++ /* Private fields. */
++ spinlock_t blk_ring_lock;
++ atomic_t refcnt;
++
++ wait_queue_head_t wq;
++ struct task_struct *xenblkd;
++ unsigned int waiting_reqs;
++ request_queue_t *plug;
++
++ /* statistics */
++ unsigned long st_print;
++ int st_rd_req;
++ int st_wr_req;
++ int st_oo_req;
++
++ wait_queue_head_t waiting_to_free;
++
++ grant_handle_t shmem_handle;
++ grant_ref_t shmem_ref;
++
++ int dev_num;
++ uint64_t sectors;
++} blkif_t;
++
++blkif_t *tap_alloc_blkif(domid_t domid);
++void tap_blkif_free(blkif_t *blkif);
++int tap_blkif_map(blkif_t *blkif, unsigned long shared_page,
++ unsigned int evtchn);
++void tap_blkif_unmap(blkif_t *blkif);
++
++#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define blkif_put(_b) \
++ do { \
++ if (atomic_dec_and_test(&(_b)->refcnt)) \
++ wake_up(&(_b)->waiting_to_free);\
++ } while (0)
++
++
++struct phys_req {
++ unsigned short dev;
++ unsigned short nr_sects;
++ struct block_device *bdev;
++ blkif_sector_t sector_number;
++};
++
++void tap_blkif_interface_init(void);
++
++void tap_blkif_xenbus_init(void);
++
++irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++int tap_blkif_schedule(void *arg);
++
++int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif);
++void signal_tapdisk(int idx);
++
++#endif /* __BLKIF__BACKEND__COMMON_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blktap/interface.c linux-2.6.18-xen/drivers/xen/blktap/interface.c
+--- linux-2.6.18.1/drivers/xen/blktap/interface.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blktap/interface.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,164 @@
++/******************************************************************************
++ * drivers/xen/blktap/interface.c
++ *
++ * Block-device interface management.
++ *
++ * Copyright (c) 2004, Keir Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++
++ */
++
++#include "common.h"
++#include <xen/evtchn.h>
++
++static kmem_cache_t *blkif_cachep;
++
++blkif_t *tap_alloc_blkif(domid_t domid)
++{
++ blkif_t *blkif;
++
++ blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
++ if (!blkif)
++ return ERR_PTR(-ENOMEM);
++
++ memset(blkif, 0, sizeof(*blkif));
++ blkif->domid = domid;
++ spin_lock_init(&blkif->blk_ring_lock);
++ atomic_set(&blkif->refcnt, 1);
++ init_waitqueue_head(&blkif->wq);
++ blkif->st_print = jiffies;
++ init_waitqueue_head(&blkif->waiting_to_free);
++
++ return blkif;
++}
++
++static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
++{
++ struct gnttab_map_grant_ref op;
++ int ret;
++
++ gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++ GNTMAP_host_map, shared_page, blkif->domid);
++
++ lock_vm_area(blkif->blk_ring_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
++ unlock_vm_area(blkif->blk_ring_area);
++ BUG_ON(ret);
++
++ if (op.status) {
++ DPRINTK(" Grant table operation failure !\n");
++ return op.status;
++ }
++
++ blkif->shmem_ref = shared_page;
++ blkif->shmem_handle = op.handle;
++
++ return 0;
++}
++
++static void unmap_frontend_page(blkif_t *blkif)
++{
++ struct gnttab_unmap_grant_ref op;
++ int ret;
++
++ gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++ GNTMAP_host_map, blkif->shmem_handle);
++
++ lock_vm_area(blkif->blk_ring_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
++ unlock_vm_area(blkif->blk_ring_area);
++ BUG_ON(ret);
++}
++
++int tap_blkif_map(blkif_t *blkif, unsigned long shared_page,
++ unsigned int evtchn)
++{
++ blkif_sring_t *sring;
++ int err;
++ struct evtchn_bind_interdomain bind_interdomain;
++
++ /* Already connected through? */
++ if (blkif->irq)
++ return 0;
++
++ if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
++ return -ENOMEM;
++
++ err = map_frontend_page(blkif, shared_page);
++ if (err) {
++ free_vm_area(blkif->blk_ring_area);
++ return err;
++ }
++
++ bind_interdomain.remote_dom = blkif->domid;
++ bind_interdomain.remote_port = evtchn;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++ if (err) {
++ unmap_frontend_page(blkif);
++ free_vm_area(blkif->blk_ring_area);
++ return err;
++ }
++
++ blkif->evtchn = bind_interdomain.local_port;
++
++ sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
++ BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
++
++ blkif->irq = bind_evtchn_to_irqhandler(
++ blkif->evtchn, tap_blkif_be_int, 0, "blkif-backend", blkif);
++
++ return 0;
++}
++
++void tap_blkif_unmap(blkif_t *blkif)
++{
++ if (blkif->irq) {
++ unbind_from_irqhandler(blkif->irq, blkif);
++ blkif->irq = 0;
++ }
++ if (blkif->blk_ring.sring) {
++ unmap_frontend_page(blkif);
++ free_vm_area(blkif->blk_ring_area);
++ blkif->blk_ring.sring = NULL;
++ }
++}
++
++void tap_blkif_free(blkif_t *blkif)
++{
++ atomic_dec(&blkif->refcnt);
++ wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
++
++ tap_blkif_unmap(blkif);
++ kmem_cache_free(blkif_cachep, blkif);
++}
++
++void __init tap_blkif_interface_init(void)
++{
++ blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t),
++ 0, 0, NULL, NULL);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blktap/Makefile linux-2.6.18-xen/drivers/xen/blktap/Makefile
+--- linux-2.6.18.1/drivers/xen/blktap/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blktap/Makefile 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,6 @@
++LINUXINCLUDE += -I../xen/include/public/io
++
++obj-$(CONFIG_XEN_BLKDEV_TAP) := blktap.o
++
++blktap-y := xenbus.o interface.o blktapmain.o
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/blktap/xenbus.c linux-2.6.18-xen/drivers/xen/blktap/xenbus.c
+--- linux-2.6.18.1/drivers/xen/blktap/xenbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/blktap/xenbus.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,366 @@
++/* drivers/xen/blktap/xenbus.c
++ *
++ * Xenbus code for blktap
++ *
++ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
++ *
++ * Based on the blkback xenbus code:
++ *
++ * Copyright (C) 2005 Rusty Russell <rusty at rustcorp.com.au>
++ * Copyright (C) 2005 XenSource Ltd
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++
++struct backend_info
++{
++ struct xenbus_device *dev;
++ blkif_t *blkif;
++ struct xenbus_watch backend_watch;
++ int xenbus_id;
++};
++
++
++static void connect(struct backend_info *);
++static int connect_ring(struct backend_info *);
++static int blktap_remove(struct xenbus_device *dev);
++static int blktap_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id);
++static void tap_backend_changed(struct xenbus_watch *, const char **,
++ unsigned int);
++static void tap_frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state);
++
++static int strsep_len(const char *str, char c, unsigned int len)
++{
++ unsigned int i;
++
++ for (i = 0; str[i]; i++)
++ if (str[i] == c) {
++ if (len == 0)
++ return i;
++ len--;
++ }
++ return (len == 0) ? i : -ERANGE;
++}
++
++static long get_id(const char *str)
++{
++ int len,end;
++ const char *ptr;
++ char *tptr, num[10];
++
++ len = strsep_len(str, '/', 2);
++ end = strlen(str);
++ if ( (len < 0) || (end < 0) ) return -1;
++
++ ptr = str + len + 1;
++ strncpy(num,ptr,end - len);
++ tptr = num + (end - (len + 1));
++ *tptr = '\0';
++ DPRINTK("Get_id called for %s (%s)\n",str,num);
++
++ return simple_strtol(num, NULL, 10);
++}
++
++static void tap_update_blkif_status(blkif_t *blkif)
++{
++ int err;
++
++ /* Not ready to connect? */
++ if(!blkif->irq || !blkif->sectors) {
++ return;
++ }
++
++ /* Already connected? */
++ if (blkif->be->dev->state == XenbusStateConnected)
++ return;
++
++ /* Attempt to connect: exit if we fail to. */
++ connect(blkif->be);
++ if (blkif->be->dev->state != XenbusStateConnected)
++ return;
++
++ blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif,
++ "xvd %d",
++ blkif->domid);
++
++ if (IS_ERR(blkif->xenblkd)) {
++ err = PTR_ERR(blkif->xenblkd);
++ blkif->xenblkd = NULL;
++ xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
++ WPRINTK("Error starting thread\n");
++ }
++}
++
++static int blktap_remove(struct xenbus_device *dev)
++{
++ struct backend_info *be = dev->dev.driver_data;
++
++ if (be->backend_watch.node) {
++ unregister_xenbus_watch(&be->backend_watch);
++ kfree(be->backend_watch.node);
++ be->backend_watch.node = NULL;
++ }
++ if (be->blkif) {
++ if (be->blkif->xenblkd)
++ kthread_stop(be->blkif->xenblkd);
++ signal_tapdisk(be->blkif->dev_num);
++ tap_blkif_free(be->blkif);
++ be->blkif = NULL;
++ }
++ kfree(be);
++ dev->dev.driver_data = NULL;
++ return 0;
++}
++
++/**
++ * Entry point to this code when a new device is created. Allocate
++ * the basic structures, and watch the store waiting for the
++ * user-space program to tell us the physical device info. Switch to
++ * InitWait.
++ */
++static int blktap_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err;
++ struct backend_info *be = kzalloc(sizeof(struct backend_info),
++ GFP_KERNEL);
++ if (!be) {
++ xenbus_dev_fatal(dev, -ENOMEM,
++ "allocating backend structure");
++ return -ENOMEM;
++ }
++
++ be->dev = dev;
++ dev->dev.driver_data = be;
++ be->xenbus_id = get_id(dev->nodename);
++
++ be->blkif = tap_alloc_blkif(dev->otherend_id);
++ if (IS_ERR(be->blkif)) {
++ err = PTR_ERR(be->blkif);
++ be->blkif = NULL;
++ xenbus_dev_fatal(dev, err, "creating block interface");
++ goto fail;
++ }
++
++ /* setup back pointer */
++ be->blkif->be = be;
++ be->blkif->sectors = 0;
++
++ /* set a watch on disk info, waiting for userspace to update details*/
++ err = xenbus_watch_path2(dev, dev->nodename, "info",
++ &be->backend_watch, tap_backend_changed);
++ if (err)
++ goto fail;
++
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto fail;
++ return 0;
++
++fail:
++ DPRINTK("blktap probe failed");
++ blktap_remove(dev);
++ return err;
++}
++
++
++/**
++ * Callback received when the user space code has placed the device
++ * information in xenstore.
++ */
++static void tap_backend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ int err;
++ unsigned long info;
++ struct backend_info *be
++ = container_of(watch, struct backend_info, backend_watch);
++ struct xenbus_device *dev = be->dev;
++
++ /**
++ * Check to see whether userspace code has opened the image
++ * and written sector
++ * and disk info to xenstore
++ */
++ err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info,
++ NULL);
++ if (err) {
++ xenbus_dev_error(dev, err, "getting info");
++ return;
++ }
++
++ DPRINTK("Userspace update on disk info, %lu\n",info);
++
++ err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu",
++ &be->blkif->sectors, NULL);
++
++ /* Associate tap dev with domid*/
++ be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id,
++ be->blkif);
++ DPRINTK("Thread started for domid [%d], connecting disk\n",
++ be->blkif->dev_num);
++
++ tap_update_blkif_status(be->blkif);
++}
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void tap_frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state)
++{
++ struct backend_info *be = dev->dev.driver_data;
++ int err;
++
++ DPRINTK("");
++
++ switch (frontend_state) {
++ case XenbusStateInitialising:
++ if (dev->state == XenbusStateClosed) {
++ printk("%s: %s: prepare for reconnect\n",
++ __FUNCTION__, dev->nodename);
++ xenbus_switch_state(dev, XenbusStateInitWait);
++ }
++ break;
++
++ case XenbusStateInitialised:
++ case XenbusStateConnected:
++ /* Ensure we connect even when two watches fire in
++ close successsion and we miss the intermediate value
++ of frontend_state. */
++ if (dev->state == XenbusStateConnected)
++ break;
++
++ err = connect_ring(be);
++ if (err)
++ break;
++ tap_update_blkif_status(be->blkif);
++ break;
++
++ case XenbusStateClosing:
++ if (be->blkif->xenblkd) {
++ kthread_stop(be->blkif->xenblkd);
++ be->blkif->xenblkd = NULL;
++ }
++ xenbus_switch_state(dev, XenbusStateClosing);
++ break;
++
++ case XenbusStateClosed:
++ xenbus_switch_state(dev, XenbusStateClosed);
++ if (xenbus_dev_is_online(dev))
++ break;
++ /* fall through if not online */
++ case XenbusStateUnknown:
++ device_unregister(&dev->dev);
++ break;
++
++ default:
++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++ frontend_state);
++ break;
++ }
++}
++
++
++/**
++ * Switch to Connected state.
++ */
++static void connect(struct backend_info *be)
++{
++ int err;
++
++ struct xenbus_device *dev = be->dev;
++
++ err = xenbus_switch_state(dev, XenbusStateConnected);
++ if (err)
++ xenbus_dev_fatal(dev, err, "switching to Connected state",
++ dev->nodename);
++
++ return;
++}
++
++
++static int connect_ring(struct backend_info *be)
++{
++ struct xenbus_device *dev = be->dev;
++ unsigned long ring_ref;
++ unsigned int evtchn;
++ int err;
++
++ DPRINTK("%s", dev->otherend);
++
++ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
++ &ring_ref, "event-channel", "%u", &evtchn, NULL);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "reading %s/ring-ref and event-channel",
++ dev->otherend);
++ return err;
++ }
++
++ /* Map the shared frame, irq etc. */
++ err = tap_blkif_map(be->blkif, ring_ref, evtchn);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
++ ring_ref, evtchn);
++ return err;
++ }
++
++ return 0;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static struct xenbus_device_id blktap_ids[] = {
++ { "tap" },
++ { "" }
++};
++
++
++static struct xenbus_driver blktap = {
++ .name = "tap",
++ .owner = THIS_MODULE,
++ .ids = blktap_ids,
++ .probe = blktap_probe,
++ .remove = blktap_remove,
++ .otherend_changed = tap_frontend_changed
++};
++
++
++void tap_blkif_xenbus_init(void)
++{
++ xenbus_register_backend(&blktap);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/char/Makefile linux-2.6.18-xen/drivers/xen/char/Makefile
+--- linux-2.6.18.1/drivers/xen/char/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/char/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,2 @@
++
++obj-y := mem.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/char/mem.c linux-2.6.18-xen/drivers/xen/char/mem.c
+--- linux-2.6.18.1/drivers/xen/char/mem.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/char/mem.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,180 @@
++/*
++ * Originally from linux/drivers/char/mem.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Added devfs support.
++ * Jan-11-1998, C. Scott Ananian <cananian at alumni.princeton.edu>
++ * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj at sgi.com>
++ */
++
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/mman.h>
++#include <linux/random.h>
++#include <linux/init.h>
++#include <linux/raw.h>
++#include <linux/tty.h>
++#include <linux/capability.h>
++#include <linux/smp_lock.h>
++#include <linux/ptrace.h>
++#include <linux/device.h>
++#include <asm/pgalloc.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/hypervisor.h>
++
++static inline int uncached_access(struct file *file)
++{
++ if (file->f_flags & O_SYNC)
++ return 1;
++ /* Xen sets correct MTRR type on non-RAM for us. */
++ return 0;
++}
++
++/*
++ * This funcion reads the *physical* memory. The f_pos points directly to the
++ * memory location.
++ */
++static ssize_t read_mem(struct file * file, char __user * buf,
++ size_t count, loff_t *ppos)
++{
++ unsigned long p = *ppos, ignored;
++ ssize_t read = 0, sz;
++ void __iomem *v;
++
++ while (count > 0) {
++ /*
++ * Handle first page in case it's not aligned
++ */
++ if (-p & (PAGE_SIZE - 1))
++ sz = -p & (PAGE_SIZE - 1);
++ else
++ sz = PAGE_SIZE;
++
++ sz = min_t(unsigned long, sz, count);
++
++ if ((v = ioremap(p, sz)) == NULL) {
++ /*
++ * Some programs (e.g., dmidecode) groove off into weird RAM
++ * areas where no tables can possibly exist (because Xen will
++ * have stomped on them!). These programs get rather upset if
++ * we let them know that Xen failed their access, so we fake
++ * out a read of all zeroes. :-)
++ */
++ if (clear_user(buf, count))
++ return -EFAULT;
++ read += count;
++ break;
++ }
++
++ ignored = copy_to_user(buf, v, sz);
++ iounmap(v);
++ if (ignored)
++ return -EFAULT;
++ buf += sz;
++ p += sz;
++ count -= sz;
++ read += sz;
++ }
++
++ *ppos += read;
++ return read;
++}
++
++static ssize_t write_mem(struct file * file, const char __user * buf,
++ size_t count, loff_t *ppos)
++{
++ unsigned long p = *ppos, ignored;
++ ssize_t written = 0, sz;
++ void __iomem *v;
++
++ while (count > 0) {
++ /*
++ * Handle first page in case it's not aligned
++ */
++ if (-p & (PAGE_SIZE - 1))
++ sz = -p & (PAGE_SIZE - 1);
++ else
++ sz = PAGE_SIZE;
++
++ sz = min_t(unsigned long, sz, count);
++
++ if ((v = ioremap(p, sz)) == NULL)
++ break;
++
++ ignored = copy_from_user(v, buf, sz);
++ iounmap(v);
++ if (ignored) {
++ written += sz - ignored;
++ if (written)
++ break;
++ return -EFAULT;
++ }
++ buf += sz;
++ p += sz;
++ count -= sz;
++ written += sz;
++ }
++
++ *ppos += written;
++ return written;
++}
++
++static int mmap_mem(struct file * file, struct vm_area_struct * vma)
++{
++ size_t size = vma->vm_end - vma->vm_start;
++
++ if (uncached_access(file))
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++ /* We want to return the real error code, not EAGAIN. */
++ return direct_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
++ size, vma->vm_page_prot, DOMID_IO);
++}
++
++/*
++ * The memory devices use the full 32/64 bits of the offset, and so we cannot
++ * check against negative addresses: they are ok. The return value is weird,
++ * though, in that case (0).
++ *
++ * also note that seeking relative to the "end of file" isn't supported:
++ * it has no meaning, so it returns -EINVAL.
++ */
++static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
++{
++ loff_t ret;
++
++ mutex_lock(&file->f_dentry->d_inode->i_mutex);
++ switch (orig) {
++ case 0:
++ file->f_pos = offset;
++ ret = file->f_pos;
++ force_successful_syscall_return();
++ break;
++ case 1:
++ file->f_pos += offset;
++ ret = file->f_pos;
++ force_successful_syscall_return();
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
++ return ret;
++}
++
++static int open_mem(struct inode * inode, struct file * filp)
++{
++ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
++}
++
++struct file_operations mem_fops = {
++ .llseek = memory_lseek,
++ .read = read_mem,
++ .write = write_mem,
++ .mmap = mmap_mem,
++ .open = open_mem,
++};
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/console/console.c linux-2.6.18-xen/drivers/xen/console/console.c
+--- linux-2.6.18.1/drivers/xen/console/console.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/console/console.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,688 @@
++/******************************************************************************
++ * console.c
++ *
++ * Virtual console driver.
++ *
++ * Copyright (c) 2002-2004, K A Fraser.
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/vt.h>
++#include <linux/serial.h>
++#include <linux/major.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/bootmem.h>
++#include <linux/sysrq.h>
++#include <linux/screen_info.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/event_channel.h>
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <xen/xencons.h>
++
++/*
++ * Modes:
++ * 'xencons=off' [XC_OFF]: Console is disabled.
++ * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
++ * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
++ * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
++ *
++ * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
++ * warnings from standard distro startup scripts.
++ */
++static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
++static int xc_num = -1;
++
++#ifdef CONFIG_MAGIC_SYSRQ
++static unsigned long sysrq_requested;
++extern int sysrq_enabled;
++#endif
++
++static int __init xencons_setup(char *str)
++{
++ char *q;
++ int n;
++
++ if (!strncmp(str, "ttyS", 4))
++ xc_mode = XC_SERIAL;
++ else if (!strncmp(str, "tty", 3))
++ xc_mode = XC_TTY;
++ else if (!strncmp(str, "off", 3))
++ xc_mode = XC_OFF;
++
++ switch (xc_mode) {
++ case XC_SERIAL:
++ n = simple_strtol(str+4, &q, 10);
++ if (q > (str + 4))
++ xc_num = n;
++ break;
++ case XC_TTY:
++ n = simple_strtol(str+3, &q, 10);
++ if (q > (str + 3))
++ xc_num = n;
++ break;
++ default:
++ break;
++ }
++
++ return 1;
++}
++__setup("xencons=", xencons_setup);
++
++/* The kernel and user-land drivers share a common transmit buffer. */
++static unsigned int wbuf_size = 4096;
++#define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
++static char *wbuf;
++static unsigned int wc, wp; /* write_cons, write_prod */
++
++static int __init xencons_bufsz_setup(char *str)
++{
++ unsigned int goal;
++ goal = simple_strtoul(str, NULL, 0);
++ if (goal) {
++ goal = roundup_pow_of_two(goal);
++ if (wbuf_size < goal)
++ wbuf_size = goal;
++ }
++ return 1;
++}
++__setup("xencons_bufsz=", xencons_bufsz_setup);
++
++/* This lock protects accesses to the common transmit buffer. */
++static DEFINE_SPINLOCK(xencons_lock);
++
++/* Common transmit-kick routine. */
++static void __xencons_tx_flush(void);
++
++static struct tty_driver *xencons_driver;
++
++/******************** Kernel console driver ********************************/
++
++static void kcons_write(struct console *c, const char *s, unsigned int count)
++{
++ int i = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++
++ while (i < count) {
++ for (; i < count; i++) {
++ if ((wp - wc) >= (wbuf_size - 1))
++ break;
++ if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
++ wbuf[WBUF_MASK(wp++)] = '\r';
++ }
++
++ __xencons_tx_flush();
++ }
++
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void kcons_write_dom0(struct console *c, const char *s, unsigned int count)
++{
++
++ while (count > 0) {
++ int rc;
++ rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s);
++ if (rc <= 0)
++ break;
++ count -= rc;
++ s += rc;
++ }
++}
++
++static struct tty_driver *kcons_device(struct console *c, int *index)
++{
++ *index = 0;
++ return xencons_driver;
++}
++
++static struct console kcons_info = {
++ .device = kcons_device,
++ .flags = CON_PRINTBUFFER | CON_ENABLED,
++ .index = -1,
++};
++
++static int __init xen_console_init(void)
++{
++ if (!is_running_on_xen())
++ goto out;
++
++ if (is_initial_xendomain()) {
++ if (xc_mode == XC_DEFAULT)
++ xc_mode = XC_SERIAL;
++ kcons_info.write = kcons_write_dom0;
++ } else {
++ if (!xen_start_info->console.domU.evtchn)
++ goto out;
++ if (xc_mode == XC_DEFAULT)
++ xc_mode = XC_TTY;
++ kcons_info.write = kcons_write;
++ }
++
++ switch (xc_mode) {
++ case XC_SERIAL:
++ strcpy(kcons_info.name, "ttyS");
++ if (xc_num == -1)
++ xc_num = 0;
++ break;
++
++ case XC_TTY:
++ strcpy(kcons_info.name, "tty");
++ if (xc_num == -1)
++ xc_num = 1;
++ break;
++
++ default:
++ goto out;
++ }
++
++ wbuf = alloc_bootmem(wbuf_size);
++
++ register_console(&kcons_info);
++
++ out:
++ return 0;
++}
++console_initcall(xen_console_init);
++
++/*** Useful function for console debugging -- goes straight to Xen. ***/
++asmlinkage int xprintk(const char *fmt, ...)
++{
++ va_list args;
++ int printk_len;
++ static char printk_buf[1024];
++
++ /* Emit the output into the temporary buffer */
++ va_start(args, fmt);
++ printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
++ va_end(args);
++
++ /* Send the processed output directly to Xen. */
++ kcons_write_dom0(NULL, printk_buf, printk_len);
++
++ return 0;
++}
++
++/*** Forcibly flush console data before dying. ***/
++void xencons_force_flush(void)
++{
++ int sz;
++
++ /* Emergency console is synchronous, so there's nothing to flush. */
++ if (!is_running_on_xen() ||
++ is_initial_xendomain() ||
++ !xen_start_info->console.domU.evtchn)
++ return;
++
++ /* Spin until console data is flushed through to the daemon. */
++ while (wc != wp) {
++ int sent = 0;
++ if ((sz = wp - wc) == 0)
++ continue;
++ sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
++ if (sent > 0)
++ wc += sent;
++ }
++}
++
++
++void dom0_init_screen_info(const struct dom0_vga_console_info *info)
++{
++ switch (info->video_type) {
++ case XEN_VGATYPE_TEXT_MODE_3:
++ screen_info.orig_video_mode = 3;
++ screen_info.orig_video_ega_bx = 3;
++ screen_info.orig_video_isVGA = 1;
++ screen_info.orig_video_lines = info->u.text_mode_3.rows;
++ screen_info.orig_video_cols = info->u.text_mode_3.columns;
++ screen_info.orig_x = info->u.text_mode_3.cursor_x;
++ screen_info.orig_y = info->u.text_mode_3.cursor_y;
++ screen_info.orig_video_points =
++ info->u.text_mode_3.font_height;
++ break;
++ case XEN_VGATYPE_VESA_LFB:
++ screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
++ screen_info.lfb_width = info->u.vesa_lfb.width;
++ screen_info.lfb_height = info->u.vesa_lfb.height;
++ screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
++ screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
++ screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
++ screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
++ screen_info.red_size = info->u.vesa_lfb.red_size;
++ screen_info.red_pos = info->u.vesa_lfb.red_pos;
++ screen_info.green_size = info->u.vesa_lfb.green_size;
++ screen_info.green_pos = info->u.vesa_lfb.green_pos;
++ screen_info.blue_size = info->u.vesa_lfb.blue_size;
++ screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
++ screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
++ screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
++ break;
++ }
++}
++
++
++/******************** User-space console driver (/dev/console) ************/
++
++#define DRV(_d) (_d)
++#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \
++ ((_tty)->index != (xc_num - 1)))
++
++static struct termios *xencons_termios[MAX_NR_CONSOLES];
++static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
++static struct tty_struct *xencons_tty;
++static int xencons_priv_irq;
++static char x_char;
++
++void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
++{
++ int i;
++ unsigned long flags;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ if (xencons_tty == NULL)
++ goto out;
++
++ for (i = 0; i < len; i++) {
++#ifdef CONFIG_MAGIC_SYSRQ
++ if (sysrq_enabled) {
++ if (buf[i] == '\x0f') { /* ^O */
++ sysrq_requested = jiffies;
++ continue; /* don't print the sysrq key */
++ } else if (sysrq_requested) {
++ unsigned long sysrq_timeout =
++ sysrq_requested + HZ*2;
++ sysrq_requested = 0;
++ if (time_before(jiffies, sysrq_timeout)) {
++ spin_unlock_irqrestore(
++ &xencons_lock, flags);
++ handle_sysrq(
++ buf[i], regs, xencons_tty);
++ spin_lock_irqsave(
++ &xencons_lock, flags);
++ continue;
++ }
++ }
++ }
++#endif
++ tty_insert_flip_char(xencons_tty, buf[i], 0);
++ }
++ tty_flip_buffer_push(xencons_tty);
++
++ out:
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void __xencons_tx_flush(void)
++{
++ int sent, sz, work_done = 0;
++
++ if (x_char) {
++ if (is_initial_xendomain())
++ kcons_write_dom0(NULL, &x_char, 1);
++ else
++ while (x_char)
++ if (xencons_ring_send(&x_char, 1) == 1)
++ break;
++ x_char = 0;
++ work_done = 1;
++ }
++
++ while (wc != wp) {
++ sz = wp - wc;
++ if (sz > (wbuf_size - WBUF_MASK(wc)))
++ sz = wbuf_size - WBUF_MASK(wc);
++ if (is_initial_xendomain()) {
++ kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
++ wc += sz;
++ } else {
++ sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
++ if (sent == 0)
++ break;
++ wc += sent;
++ }
++ work_done = 1;
++ }
++
++ if (work_done && (xencons_tty != NULL)) {
++ wake_up_interruptible(&xencons_tty->write_wait);
++ if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ (xencons_tty->ldisc.write_wakeup != NULL))
++ (xencons_tty->ldisc.write_wakeup)(xencons_tty);
++ }
++}
++
++void xencons_tx(void)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ __xencons_tx_flush();
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++/* Privileged receive callback and transmit kicker. */
++static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++ static char rbuf[16];
++ int l;
++
++ while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
++ xencons_rx(rbuf, l, regs);
++
++ xencons_tx();
++
++ return IRQ_HANDLED;
++}
++
++static int xencons_write_room(struct tty_struct *tty)
++{
++ return wbuf_size - (wp - wc);
++}
++
++static int xencons_chars_in_buffer(struct tty_struct *tty)
++{
++ return wp - wc;
++}
++
++static void xencons_send_xchar(struct tty_struct *tty, char ch)
++{
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ x_char = ch;
++ __xencons_tx_flush();
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void xencons_throttle(struct tty_struct *tty)
++{
++ if (DUMMY_TTY(tty))
++ return;
++
++ if (I_IXOFF(tty))
++ xencons_send_xchar(tty, STOP_CHAR(tty));
++}
++
++static void xencons_unthrottle(struct tty_struct *tty)
++{
++ if (DUMMY_TTY(tty))
++ return;
++
++ if (I_IXOFF(tty)) {
++ if (x_char != 0)
++ x_char = 0;
++ else
++ xencons_send_xchar(tty, START_CHAR(tty));
++ }
++}
++
++static void xencons_flush_buffer(struct tty_struct *tty)
++{
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ wc = wp = 0;
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static inline int __xencons_put_char(int ch)
++{
++ char _ch = (char)ch;
++ if ((wp - wc) == wbuf_size)
++ return 0;
++ wbuf[WBUF_MASK(wp++)] = _ch;
++ return 1;
++}
++
++static int xencons_write(
++ struct tty_struct *tty,
++ const unsigned char *buf,
++ int count)
++{
++ int i;
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return count;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++
++ for (i = 0; i < count; i++)
++ if (!__xencons_put_char(buf[i]))
++ break;
++
++ if (i != 0)
++ __xencons_tx_flush();
++
++ spin_unlock_irqrestore(&xencons_lock, flags);
++
++ return i;
++}
++
++static void xencons_put_char(struct tty_struct *tty, u_char ch)
++{
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ (void)__xencons_put_char(ch);
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void xencons_flush_chars(struct tty_struct *tty)
++{
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ __xencons_tx_flush();
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++ unsigned long orig_jiffies = jiffies;
++
++ if (DUMMY_TTY(tty))
++ return;
++
++ while (DRV(tty->driver)->chars_in_buffer(tty)) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1);
++ if (signal_pending(current))
++ break;
++ if (timeout && time_after(jiffies, orig_jiffies + timeout))
++ break;
++ }
++
++ set_current_state(TASK_RUNNING);
++}
++
++static int xencons_open(struct tty_struct *tty, struct file *filp)
++{
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return 0;
++
++ spin_lock_irqsave(&xencons_lock, flags);
++ tty->driver_data = NULL;
++ if (xencons_tty == NULL)
++ xencons_tty = tty;
++ __xencons_tx_flush();
++ spin_unlock_irqrestore(&xencons_lock, flags);
++
++ return 0;
++}
++
++static void xencons_close(struct tty_struct *tty, struct file *filp)
++{
++ unsigned long flags;
++
++ if (DUMMY_TTY(tty))
++ return;
++
++ mutex_lock(&tty_mutex);
++
++ if (tty->count != 1) {
++ mutex_unlock(&tty_mutex);
++ return;
++ }
++
++ /* Prevent other threads from re-opening this tty. */
++ set_bit(TTY_CLOSING, &tty->flags);
++ mutex_unlock(&tty_mutex);
++
++ tty->closing = 1;
++ tty_wait_until_sent(tty, 0);
++ if (DRV(tty->driver)->flush_buffer != NULL)
++ DRV(tty->driver)->flush_buffer(tty);
++ if (tty->ldisc.flush_buffer != NULL)
++ tty->ldisc.flush_buffer(tty);
++ tty->closing = 0;
++ spin_lock_irqsave(&xencons_lock, flags);
++ xencons_tty = NULL;
++ spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static struct tty_operations xencons_ops = {
++ .open = xencons_open,
++ .close = xencons_close,
++ .write = xencons_write,
++ .write_room = xencons_write_room,
++ .put_char = xencons_put_char,
++ .flush_chars = xencons_flush_chars,
++ .chars_in_buffer = xencons_chars_in_buffer,
++ .send_xchar = xencons_send_xchar,
++ .flush_buffer = xencons_flush_buffer,
++ .throttle = xencons_throttle,
++ .unthrottle = xencons_unthrottle,
++ .wait_until_sent = xencons_wait_until_sent,
++};
++
++static int __init xencons_init(void)
++{
++ int rc;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ if (xc_mode == XC_OFF)
++ return 0;
++
++ if (!is_initial_xendomain()) {
++ rc = xencons_ring_init();
++ if (rc)
++ return rc;
++ }
++
++ xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
++ 1 : MAX_NR_CONSOLES);
++ if (xencons_driver == NULL)
++ return -ENOMEM;
++
++ DRV(xencons_driver)->name = "xencons";
++ DRV(xencons_driver)->major = TTY_MAJOR;
++ DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
++ DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
++ DRV(xencons_driver)->init_termios = tty_std_termios;
++ DRV(xencons_driver)->flags =
++ TTY_DRIVER_REAL_RAW |
++ TTY_DRIVER_RESET_TERMIOS;
++ DRV(xencons_driver)->termios = xencons_termios;
++ DRV(xencons_driver)->termios_locked = xencons_termios_locked;
++
++ if (xc_mode == XC_SERIAL) {
++ DRV(xencons_driver)->name = "ttyS";
++ DRV(xencons_driver)->minor_start = 64 + xc_num;
++ DRV(xencons_driver)->name_base = 0 + xc_num;
++ } else {
++ DRV(xencons_driver)->name = "tty";
++ DRV(xencons_driver)->minor_start = 1;
++ DRV(xencons_driver)->name_base = 1;
++ }
++
++ tty_set_operations(xencons_driver, &xencons_ops);
++
++ if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
++ printk("WARNING: Failed to register Xen virtual "
++ "console driver as '%s%d'\n",
++ DRV(xencons_driver)->name,
++ DRV(xencons_driver)->name_base);
++ put_tty_driver(xencons_driver);
++ xencons_driver = NULL;
++ return rc;
++ }
++
++ if (is_initial_xendomain()) {
++ xencons_priv_irq = bind_virq_to_irqhandler(
++ VIRQ_CONSOLE,
++ 0,
++ xencons_priv_interrupt,
++ 0,
++ "console",
++ NULL);
++ BUG_ON(xencons_priv_irq < 0);
++ }
++
++ printk("Xen virtual console successfully installed as %s%d\n",
++ DRV(xencons_driver)->name, xc_num);
++
++ return 0;
++}
++
++module_init(xencons_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/console/Makefile linux-2.6.18-xen/drivers/xen/console/Makefile
+--- linux-2.6.18.1/drivers/xen/console/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/console/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,2 @@
++
++obj-y := console.o xencons_ring.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/console/xencons_ring.c linux-2.6.18-xen/drivers/xen/console/xencons_ring.c
+--- linux-2.6.18.1/drivers/xen/console/xencons_ring.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/console/xencons_ring.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,143 @@
++/*
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/major.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <xen/xencons.h>
++#include <linux/wait.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/err.h>
++#include <xen/interface/io/console.h>
++
++static int xencons_irq;
++
++static inline struct xencons_interface *xencons_interface(void)
++{
++ return mfn_to_virt(xen_start_info->console.domU.mfn);
++}
++
++static inline void notify_daemon(void)
++{
++ /* Use evtchn: this is called early, before irq is set up. */
++ notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
++}
++
++int xencons_ring_send(const char *data, unsigned len)
++{
++ int sent = 0;
++ struct xencons_interface *intf = xencons_interface();
++ XENCONS_RING_IDX cons, prod;
++
++ cons = intf->out_cons;
++ prod = intf->out_prod;
++ mb();
++ BUG_ON((prod - cons) > sizeof(intf->out));
++
++ while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
++ intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
++
++ wmb();
++ intf->out_prod = prod;
++
++ notify_daemon();
++
++ return sent;
++}
++
++static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs)
++{
++ struct xencons_interface *intf = xencons_interface();
++ XENCONS_RING_IDX cons, prod;
++
++ cons = intf->in_cons;
++ prod = intf->in_prod;
++ mb();
++ BUG_ON((prod - cons) > sizeof(intf->in));
++
++ while (cons != prod) {
++ xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1, regs);
++ cons++;
++ }
++
++ mb();
++ intf->in_cons = cons;
++
++ notify_daemon();
++
++ xencons_tx();
++
++ return IRQ_HANDLED;
++}
++
++int xencons_ring_init(void)
++{
++ int irq;
++
++ if (xencons_irq)
++ unbind_from_irqhandler(xencons_irq, NULL);
++ xencons_irq = 0;
++
++ if (!is_running_on_xen() ||
++ is_initial_xendomain() ||
++ !xen_start_info->console.domU.evtchn)
++ return -ENODEV;
++
++ irq = bind_evtchn_to_irqhandler(
++ xen_start_info->console.domU.evtchn,
++ handle_input, 0, "xencons", NULL);
++ if (irq < 0) {
++ printk(KERN_ERR "XEN console request irq failed %i\n", irq);
++ return irq;
++ }
++
++ xencons_irq = irq;
++
++ /* In case we have in-flight data after save/restore... */
++ notify_daemon();
++
++ return 0;
++}
++
++void xencons_resume(void)
++{
++ (void)xencons_ring_init();
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/cpu_hotplug.c linux-2.6.18-xen/drivers/xen/core/cpu_hotplug.c
+--- linux-2.6.18.1/drivers/xen/core/cpu_hotplug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/cpu_hotplug.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,188 @@
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
++#include <xen/cpu_hotplug.h>
++#include <xen/xenbus.h>
++
++/*
++ * Set of CPUs that remote admin software will allow us to bring online.
++ * Notified to us via xenbus.
++ */
++static cpumask_t xenbus_allowed_cpumask;
++
++/* Set of CPUs that local admin will allow us to bring online. */
++static cpumask_t local_allowed_cpumask = CPU_MASK_ALL;
++
++static int local_cpu_hotplug_request(void)
++{
++ /*
++ * We assume a CPU hotplug request comes from local admin if it is made
++ * via a userspace process (i.e., one with a real mm_struct).
++ */
++ return (current->mm != NULL);
++}
++
++static void vcpu_hotplug(unsigned int cpu)
++{
++ int err;
++ char dir[32], state[32];
++
++ if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
++ return;
++
++ sprintf(dir, "cpu/%d", cpu);
++ err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
++ if (err != 1) {
++ printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
++ return;
++ }
++
++ if (strcmp(state, "online") == 0) {
++ cpu_set(cpu, xenbus_allowed_cpumask);
++ (void)cpu_up(cpu);
++ } else if (strcmp(state, "offline") == 0) {
++ cpu_clear(cpu, xenbus_allowed_cpumask);
++ (void)cpu_down(cpu);
++ } else {
++ printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
++ state, cpu);
++ }
++}
++
++static void handle_vcpu_hotplug_event(
++ struct xenbus_watch *watch, const char **vec, unsigned int len)
++{
++ int cpu;
++ char *cpustr;
++ const char *node = vec[XS_WATCH_PATH];
++
++ if ((cpustr = strstr(node, "cpu/")) != NULL) {
++ sscanf(cpustr, "cpu/%d", &cpu);
++ vcpu_hotplug(cpu);
++ }
++}
++
++static int smpboot_cpu_notify(struct notifier_block *notifier,
++ unsigned long action, void *hcpu)
++{
++ int cpu = (long)hcpu;
++
++ /*
++ * We do this in a callback notifier rather than __cpu_disable()
++ * because local_cpu_hotplug_request() does not work in the latter
++ * as it's always executed from within a stopmachine kthread.
++ */
++ if ((action == CPU_DOWN_PREPARE) && local_cpu_hotplug_request())
++ cpu_clear(cpu, local_allowed_cpumask);
++
++ return NOTIFY_OK;
++}
++
++static int setup_cpu_watcher(struct notifier_block *notifier,
++ unsigned long event, void *data)
++{
++ int i;
++
++ static struct xenbus_watch cpu_watch = {
++ .node = "cpu",
++ .callback = handle_vcpu_hotplug_event,
++ .flags = XBWF_new_thread };
++ (void)register_xenbus_watch(&cpu_watch);
++
++ if (!is_initial_xendomain()) {
++ for_each_possible_cpu(i)
++ vcpu_hotplug(i);
++ printk(KERN_INFO "Brought up %ld CPUs\n",
++ (long)num_online_cpus());
++ }
++
++ return NOTIFY_DONE;
++}
++
++static int __init setup_vcpu_hotplug_event(void)
++{
++ static struct notifier_block hotplug_cpu = {
++ .notifier_call = smpboot_cpu_notify };
++ static struct notifier_block xsn_cpu = {
++ .notifier_call = setup_cpu_watcher };
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ register_cpu_notifier(&hotplug_cpu);
++ register_xenstore_notifier(&xsn_cpu);
++
++ return 0;
++}
++
++arch_initcall(setup_vcpu_hotplug_event);
++
++int smp_suspend(void)
++{
++ int i, err;
++
++ lock_cpu_hotplug();
++
++ /*
++ * Take all other CPUs offline. We hold the hotplug mutex to
++ * avoid other processes bringing up CPUs under our feet.
++ */
++ while (num_online_cpus() > 1) {
++ unlock_cpu_hotplug();
++ for_each_online_cpu(i) {
++ if (i == 0)
++ continue;
++ err = cpu_down(i);
++ if (err) {
++ printk(KERN_CRIT "Failed to take all CPUs "
++ "down: %d.\n", err);
++ for_each_possible_cpu(i)
++ vcpu_hotplug(i);
++ return err;
++ }
++ }
++ lock_cpu_hotplug();
++ }
++
++ return 0;
++}
++
++void smp_resume(void)
++{
++ int cpu;
++
++ for_each_possible_cpu(cpu)
++ cpu_initialize_context(cpu);
++
++ unlock_cpu_hotplug();
++
++ for_each_possible_cpu(cpu)
++ vcpu_hotplug(cpu);
++}
++
++int cpu_up_check(unsigned int cpu)
++{
++ int rc = 0;
++
++ if (local_cpu_hotplug_request()) {
++ cpu_set(cpu, local_allowed_cpumask);
++ if (!cpu_isset(cpu, xenbus_allowed_cpumask)) {
++ printk("%s: attempt to bring up CPU %u disallowed by "
++ "remote admin.\n", __FUNCTION__, cpu);
++ rc = -EBUSY;
++ }
++ } else if (!cpu_isset(cpu, local_allowed_cpumask) ||
++ !cpu_isset(cpu, xenbus_allowed_cpumask)) {
++ rc = -EBUSY;
++ }
++
++ return rc;
++}
++
++void init_xenbus_allowed_cpumask(void)
++{
++ xenbus_allowed_cpumask = cpu_present_map;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/evtchn.c linux-2.6.18-xen/drivers/xen/core/evtchn.c
+--- linux-2.6.18.1/drivers/xen/core/evtchn.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/evtchn.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,868 @@
++/******************************************************************************
++ * evtchn.c
++ *
++ * Communication via Xen event channels.
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/kernel_stat.h>
++#include <linux/version.h>
++#include <asm/atomic.h>
++#include <asm/system.h>
++#include <asm/ptrace.h>
++#include <asm/synch_bitops.h>
++#include <xen/evtchn.h>
++#include <xen/interface/event_channel.h>
++#include <xen/interface/physdev.h>
++#include <asm/hypervisor.h>
++#include <linux/mc146818rtc.h> /* RTC_IRQ */
++
++/*
++ * This lock protects updates to the following mapping and reference-count
++ * arrays. The lock does not need to be acquired to read the mapping tables.
++ */
++static DEFINE_SPINLOCK(irq_mapping_update_lock);
++
++/* IRQ <-> event-channel mappings. */
++static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
++ [0 ... NR_EVENT_CHANNELS-1] = -1 };
++
++/* Packed IRQ information: binding type, sub-type index, and event channel. */
++static u32 irq_info[NR_IRQS];
++
++/* Binding types. */
++enum { IRQT_UNBOUND, IRQT_PIRQ, IRQT_VIRQ, IRQT_IPI, IRQT_EVTCHN };
++
++/* Constructor for packed IRQ information. */
++static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn)
++{
++ return ((type << 24) | (index << 16) | evtchn);
++}
++
++/* Convenient shorthand for packed representation of an unbound IRQ. */
++#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
++
++/*
++ * Accessors for packed IRQ information.
++ */
++
++static inline unsigned int evtchn_from_irq(int irq)
++{
++ return (u16)(irq_info[irq]);
++}
++
++static inline unsigned int index_from_irq(int irq)
++{
++ return (u8)(irq_info[irq] >> 16);
++}
++
++static inline unsigned int type_from_irq(int irq)
++{
++ return (u8)(irq_info[irq] >> 24);
++}
++
++/* IRQ <-> VIRQ mapping. */
++DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
++
++/* IRQ <-> IPI mapping. */
++#ifndef NR_IPIS
++#define NR_IPIS 1
++#endif
++DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) = {[0 ... NR_IPIS-1] = -1};
++
++/* Reference counts for bindings to IRQs. */
++static int irq_bindcount[NR_IRQS];
++
++/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
++static unsigned long pirq_needs_eoi[NR_PIRQS/sizeof(unsigned long)];
++
++#ifdef CONFIG_SMP
++
++static u8 cpu_evtchn[NR_EVENT_CHANNELS];
++static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
++
++static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
++ unsigned int idx)
++{
++ return (sh->evtchn_pending[idx] &
++ cpu_evtchn_mask[cpu][idx] &
++ ~sh->evtchn_mask[idx]);
++}
++
++static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
++{
++ int irq = evtchn_to_irq[chn];
++
++ BUG_ON(irq == -1);
++ set_native_irq_info(irq, cpumask_of_cpu(cpu));
++
++ clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]);
++ set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]);
++ cpu_evtchn[chn] = cpu;
++}
++
++static void init_evtchn_cpu_bindings(void)
++{
++ int i;
++
++ /* By default all event channels notify CPU#0. */
++ for (i = 0; i < NR_IRQS; i++)
++ set_native_irq_info(i, cpumask_of_cpu(0));
++
++ memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
++ memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
++}
++
++static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
++{
++ return cpu_evtchn[evtchn];
++}
++
++#else
++
++static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
++ unsigned int idx)
++{
++ return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]);
++}
++
++static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
++{
++}
++
++static void init_evtchn_cpu_bindings(void)
++{
++}
++
++static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
++{
++ return 0;
++}
++
++#endif
++
++/* Upcall to generic IRQ layer. */
++#ifdef CONFIG_X86
++extern fastcall unsigned int do_IRQ(struct pt_regs *regs);
++void __init xen_init_IRQ(void);
++void __init init_IRQ(void)
++{
++ irq_ctx_init(0);
++ xen_init_IRQ();
++}
++#if defined (__i386__)
++static inline void exit_idle(void) {}
++#define IRQ_REG orig_eax
++#elif defined (__x86_64__)
++#include <asm/idle.h>
++#define IRQ_REG orig_rax
++#endif
++#define do_IRQ(irq, regs) do { \
++ (regs)->IRQ_REG = ~(irq); \
++ do_IRQ((regs)); \
++} while (0)
++#endif
++
++/* Xen will never allocate port zero for any purpose. */
++#define VALID_EVTCHN(chn) ((chn) != 0)
++
++/*
++ * Force a proper event-channel callback from Xen after clearing the
++ * callback mask. We do this in a very simple manner, by making a call
++ * down into Xen. The pending flag will be checked by Xen on return.
++ */
++void force_evtchn_callback(void)
++{
++ (void)HYPERVISOR_xen_version(0, NULL);
++}
++/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
++EXPORT_SYMBOL(force_evtchn_callback);
++
++/* NB. Interrupts are disabled on entry. */
++asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
++{
++ unsigned long l1, l2;
++ unsigned int l1i, l2i, port;
++ int irq, cpu = smp_processor_id();
++ shared_info_t *s = HYPERVISOR_shared_info;
++ vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
++
++ vcpu_info->evtchn_upcall_pending = 0;
++
++#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
++ /* Clear master pending flag /before/ clearing selector flag. */
++ rmb();
++#endif
++ l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
++ while (l1 != 0) {
++ l1i = __ffs(l1);
++ l1 &= ~(1UL << l1i);
++
++ while ((l2 = active_evtchns(cpu, s, l1i)) != 0) {
++ l2i = __ffs(l2);
++
++ port = (l1i * BITS_PER_LONG) + l2i;
++ if ((irq = evtchn_to_irq[port]) != -1)
++ do_IRQ(irq, regs);
++ else {
++ exit_idle();
++ evtchn_device_upcall(port);
++ }
++ }
++ }
++}
++
++static int find_unbound_irq(void)
++{
++ int irq;
++
++ /* Only allocate from dynirq range */
++ for (irq = DYNIRQ_BASE; irq < NR_IRQS; irq++)
++ if (irq_bindcount[irq] == 0)
++ break;
++
++ if (irq == NR_IRQS)
++ panic("No available IRQ to bind to: increase NR_IRQS!\n");
++
++ return irq;
++}
++
++static int bind_evtchn_to_irq(unsigned int evtchn)
++{
++ int irq;
++
++ spin_lock(&irq_mapping_update_lock);
++
++ if ((irq = evtchn_to_irq[evtchn]) == -1) {
++ irq = find_unbound_irq();
++ evtchn_to_irq[evtchn] = irq;
++ irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
++ }
++
++ irq_bindcount[irq]++;
++
++ spin_unlock(&irq_mapping_update_lock);
++
++ return irq;
++}
++
++static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
++{
++ struct evtchn_bind_virq bind_virq;
++ int evtchn, irq;
++
++ spin_lock(&irq_mapping_update_lock);
++
++ if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) {
++ bind_virq.virq = virq;
++ bind_virq.vcpu = cpu;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
++ &bind_virq) != 0)
++ BUG();
++ evtchn = bind_virq.port;
++
++ irq = find_unbound_irq();
++ evtchn_to_irq[evtchn] = irq;
++ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
++
++ per_cpu(virq_to_irq, cpu)[virq] = irq;
++
++ bind_evtchn_to_cpu(evtchn, cpu);
++ }
++
++ irq_bindcount[irq]++;
++
++ spin_unlock(&irq_mapping_update_lock);
++
++ return irq;
++}
++
++static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
++{
++ struct evtchn_bind_ipi bind_ipi;
++ int evtchn, irq;
++
++ spin_lock(&irq_mapping_update_lock);
++
++ if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) {
++ bind_ipi.vcpu = cpu;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
++ &bind_ipi) != 0)
++ BUG();
++ evtchn = bind_ipi.port;
++
++ irq = find_unbound_irq();
++ evtchn_to_irq[evtchn] = irq;
++ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
++
++ per_cpu(ipi_to_irq, cpu)[ipi] = irq;
++
++ bind_evtchn_to_cpu(evtchn, cpu);
++ }
++
++ irq_bindcount[irq]++;
++
++ spin_unlock(&irq_mapping_update_lock);
++
++ return irq;
++}
++
++static void unbind_from_irq(unsigned int irq)
++{
++ struct evtchn_close close;
++ int evtchn = evtchn_from_irq(irq);
++
++ spin_lock(&irq_mapping_update_lock);
++
++ if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) {
++ close.port = evtchn;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
++ BUG();
++
++ switch (type_from_irq(irq)) {
++ case IRQT_VIRQ:
++ per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
++ [index_from_irq(irq)] = -1;
++ break;
++ case IRQT_IPI:
++ per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
++ [index_from_irq(irq)] = -1;
++ break;
++ default:
++ break;
++ }
++
++ /* Closed ports are implicitly re-bound to VCPU0. */
++ bind_evtchn_to_cpu(evtchn, 0);
++
++ evtchn_to_irq[evtchn] = -1;
++ irq_info[irq] = IRQ_UNBOUND;
++ }
++
++ spin_unlock(&irq_mapping_update_lock);
++}
++
++int bind_evtchn_to_irqhandler(
++ unsigned int evtchn,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id)
++{
++ unsigned int irq;
++ int retval;
++
++ irq = bind_evtchn_to_irq(evtchn);
++ retval = request_irq(irq, handler, irqflags, devname, dev_id);
++ if (retval != 0) {
++ unbind_from_irq(irq);
++ return retval;
++ }
++
++ return irq;
++}
++EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
++
++int bind_virq_to_irqhandler(
++ unsigned int virq,
++ unsigned int cpu,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id)
++{
++ unsigned int irq;
++ int retval;
++
++ irq = bind_virq_to_irq(virq, cpu);
++ retval = request_irq(irq, handler, irqflags, devname, dev_id);
++ if (retval != 0) {
++ unbind_from_irq(irq);
++ return retval;
++ }
++
++ return irq;
++}
++EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
++
++int bind_ipi_to_irqhandler(
++ unsigned int ipi,
++ unsigned int cpu,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id)
++{
++ unsigned int irq;
++ int retval;
++
++ irq = bind_ipi_to_irq(ipi, cpu);
++ retval = request_irq(irq, handler, irqflags, devname, dev_id);
++ if (retval != 0) {
++ unbind_from_irq(irq);
++ return retval;
++ }
++
++ return irq;
++}
++EXPORT_SYMBOL_GPL(bind_ipi_to_irqhandler);
++
++void unbind_from_irqhandler(unsigned int irq, void *dev_id)
++{
++ free_irq(irq, dev_id);
++ unbind_from_irq(irq);
++}
++EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
++
++/* Rebind an evtchn so that it gets delivered to a specific cpu */
++static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
++{
++ struct evtchn_bind_vcpu bind_vcpu;
++ int evtchn = evtchn_from_irq(irq);
++
++ if (!VALID_EVTCHN(evtchn))
++ return;
++
++ /* Send future instances of this interrupt to other vcpu. */
++ bind_vcpu.port = evtchn;
++ bind_vcpu.vcpu = tcpu;
++
++ /*
++ * If this fails, it usually just indicates that we're dealing with a
++ * virq or IPI channel, which don't actually need to be rebound. Ignore
++ * it, but don't do the xenlinux-level rebind in that case.
++ */
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
++ bind_evtchn_to_cpu(evtchn, tcpu);
++}
++
++
++static void set_affinity_irq(unsigned irq, cpumask_t dest)
++{
++ unsigned tcpu = first_cpu(dest);
++ rebind_irq_to_cpu(irq, tcpu);
++}
++
++static int retrigger(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++ shared_info_t *s = HYPERVISOR_shared_info;
++ if (!VALID_EVTCHN(evtchn))
++ return 1;
++ BUG_ON(!synch_test_bit(evtchn, &s->evtchn_mask[0]));
++ synch_set_bit(evtchn, &s->evtchn_pending[0]);
++ return 1;
++}
++
++/*
++ * Interface to generic handling in irq.c
++ */
++
++static unsigned int startup_dynirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ unmask_evtchn(evtchn);
++ return 0;
++}
++
++static void shutdown_dynirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ mask_evtchn(evtchn);
++}
++
++static void enable_dynirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ unmask_evtchn(evtchn);
++}
++
++static void disable_dynirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ mask_evtchn(evtchn);
++}
++
++static void ack_dynirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ move_native_irq(irq);
++
++ if (VALID_EVTCHN(evtchn)) {
++ mask_evtchn(evtchn);
++ clear_evtchn(evtchn);
++ }
++}
++
++static void end_dynirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED))
++ unmask_evtchn(evtchn);
++}
++
++static struct hw_interrupt_type dynirq_type = {
++ .typename = "Dynamic-irq",
++ .startup = startup_dynirq,
++ .shutdown = shutdown_dynirq,
++ .enable = enable_dynirq,
++ .disable = disable_dynirq,
++ .ack = ack_dynirq,
++ .end = end_dynirq,
++#ifdef CONFIG_SMP
++ .set_affinity = set_affinity_irq,
++#endif
++ .retrigger = retrigger,
++};
++
++static inline void pirq_unmask_notify(int pirq)
++{
++ struct physdev_eoi eoi = { .irq = pirq };
++ if (unlikely(test_bit(pirq, &pirq_needs_eoi[0])))
++ (void)HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
++}
++
++static inline void pirq_query_unmask(int pirq)
++{
++ struct physdev_irq_status_query irq_status;
++ irq_status.irq = pirq;
++ (void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status);
++ clear_bit(pirq, &pirq_needs_eoi[0]);
++ if (irq_status.flags & XENIRQSTAT_needs_eoi)
++ set_bit(pirq, &pirq_needs_eoi[0]);
++}
++
++/*
++ * On startup, if there is no action associated with the IRQ then we are
++ * probing. In this case we should not share with others as it will confuse us.
++ */
++#define probing_irq(_irq) (irq_desc[(_irq)].action == NULL)
++
++static unsigned int startup_pirq(unsigned int irq)
++{
++ struct evtchn_bind_pirq bind_pirq;
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ goto out;
++
++ bind_pirq.pirq = irq;
++ /* NB. We are happy to share unless we are probing. */
++ bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) {
++ if (!probing_irq(irq))
++ printk(KERN_INFO "Failed to obtain physical IRQ %d\n",
++ irq);
++ return 0;
++ }
++ evtchn = bind_pirq.port;
++
++ pirq_query_unmask(irq_to_pirq(irq));
++
++ evtchn_to_irq[evtchn] = irq;
++ bind_evtchn_to_cpu(evtchn, 0);
++ irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn);
++
++ out:
++ unmask_evtchn(evtchn);
++ pirq_unmask_notify(irq_to_pirq(irq));
++
++ return 0;
++}
++
++static void shutdown_pirq(unsigned int irq)
++{
++ struct evtchn_close close;
++ int evtchn = evtchn_from_irq(irq);
++
++ if (!VALID_EVTCHN(evtchn))
++ return;
++
++ mask_evtchn(evtchn);
++
++ close.port = evtchn;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
++ BUG();
++
++ bind_evtchn_to_cpu(evtchn, 0);
++ evtchn_to_irq[evtchn] = -1;
++ irq_info[irq] = IRQ_UNBOUND;
++}
++
++static void enable_pirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn)) {
++ unmask_evtchn(evtchn);
++ pirq_unmask_notify(irq_to_pirq(irq));
++ }
++}
++
++static void disable_pirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ mask_evtchn(evtchn);
++}
++
++static void ack_pirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ move_native_irq(irq);
++
++ if (VALID_EVTCHN(evtchn)) {
++ mask_evtchn(evtchn);
++ clear_evtchn(evtchn);
++ }
++}
++
++static void end_pirq(unsigned int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED)) {
++ unmask_evtchn(evtchn);
++ pirq_unmask_notify(irq_to_pirq(irq));
++ }
++}
++
++static struct hw_interrupt_type pirq_type = {
++ .typename = "Phys-irq",
++ .startup = startup_pirq,
++ .shutdown = shutdown_pirq,
++ .enable = enable_pirq,
++ .disable = disable_pirq,
++ .ack = ack_pirq,
++ .end = end_pirq,
++#ifdef CONFIG_SMP
++ .set_affinity = set_affinity_irq,
++#endif
++ .retrigger = retrigger,
++};
++
++int irq_ignore_unhandled(unsigned int irq)
++{
++ struct physdev_irq_status_query irq_status = { .irq = irq };
++
++ if (!is_running_on_xen())
++ return 0;
++
++ (void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status);
++ return !!(irq_status.flags & XENIRQSTAT_shared);
++}
++
++void resend_irq_on_evtchn(unsigned int i)
++{
++ int evtchn = evtchn_from_irq(i);
++ shared_info_t *s = HYPERVISOR_shared_info;
++ if (!VALID_EVTCHN(evtchn))
++ return;
++ BUG_ON(!synch_test_bit(evtchn, &s->evtchn_mask[0]));
++ synch_set_bit(evtchn, &s->evtchn_pending[0]);
++}
++
++void notify_remote_via_irq(int irq)
++{
++ int evtchn = evtchn_from_irq(irq);
++
++ if (VALID_EVTCHN(evtchn))
++ notify_remote_via_evtchn(evtchn);
++}
++EXPORT_SYMBOL_GPL(notify_remote_via_irq);
++
++void mask_evtchn(int port)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++ synch_set_bit(port, &s->evtchn_mask[0]);
++}
++EXPORT_SYMBOL_GPL(mask_evtchn);
++
++void unmask_evtchn(int port)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++ unsigned int cpu = smp_processor_id();
++ vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
++
++ BUG_ON(!irqs_disabled());
++
++ /* Slow path (hypercall) if this is a non-local port. */
++ if (unlikely(cpu != cpu_from_evtchn(port))) {
++ struct evtchn_unmask unmask = { .port = port };
++ (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
++ return;
++ }
++
++ synch_clear_bit(port, &s->evtchn_mask[0]);
++
++ /*
++ * The following is basically the equivalent of 'hw_resend_irq'. Just
++ * like a real IO-APIC we 'lose the interrupt edge' if the channel is
++ * masked.
++ */
++ if (synch_test_bit(port, &s->evtchn_pending[0]) &&
++ !synch_test_and_set_bit(port / BITS_PER_LONG,
++ &vcpu_info->evtchn_pending_sel))
++ vcpu_info->evtchn_upcall_pending = 1;
++}
++EXPORT_SYMBOL_GPL(unmask_evtchn);
++
++void irq_resume(void)
++{
++ struct evtchn_bind_virq bind_virq;
++ struct evtchn_bind_ipi bind_ipi;
++ int cpu, pirq, virq, ipi, irq, evtchn;
++
++ init_evtchn_cpu_bindings();
++
++ /* New event-channel space is not 'live' yet. */
++ for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
++ mask_evtchn(evtchn);
++
++ /* Check that no PIRQs are still bound. */
++ for (pirq = 0; pirq < NR_PIRQS; pirq++)
++ BUG_ON(irq_info[pirq_to_irq(pirq)] != IRQ_UNBOUND);
++
++ /* Secondary CPUs must have no VIRQ or IPI bindings. */
++ for_each_possible_cpu(cpu) {
++ if (cpu == 0)
++ continue;
++ for (virq = 0; virq < NR_VIRQS; virq++)
++ BUG_ON(per_cpu(virq_to_irq, cpu)[virq] != -1);
++ for (ipi = 0; ipi < NR_IPIS; ipi++)
++ BUG_ON(per_cpu(ipi_to_irq, cpu)[ipi] != -1);
++ }
++
++ /* No IRQ <-> event-channel mappings. */
++ for (irq = 0; irq < NR_IRQS; irq++)
++ irq_info[irq] &= ~0xFFFF; /* zap event-channel binding */
++ for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
++ evtchn_to_irq[evtchn] = -1;
++
++ /* Primary CPU: rebind VIRQs automatically. */
++ for (virq = 0; virq < NR_VIRQS; virq++) {
++ if ((irq = per_cpu(virq_to_irq, 0)[virq]) == -1)
++ continue;
++
++ BUG_ON(irq_info[irq] != mk_irq_info(IRQT_VIRQ, virq, 0));
++
++ /* Get a new binding from Xen. */
++ bind_virq.virq = virq;
++ bind_virq.vcpu = 0;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
++ &bind_virq) != 0)
++ BUG();
++ evtchn = bind_virq.port;
++
++ /* Record the new mapping. */
++ evtchn_to_irq[evtchn] = irq;
++ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
++
++ /* Ready for use. */
++ unmask_evtchn(evtchn);
++ }
++
++ /* Primary CPU: rebind IPIs automatically. */
++ for (ipi = 0; ipi < NR_IPIS; ipi++) {
++ if ((irq = per_cpu(ipi_to_irq, 0)[ipi]) == -1)
++ continue;
++
++ BUG_ON(irq_info[irq] != mk_irq_info(IRQT_IPI, ipi, 0));
++
++ /* Get a new binding from Xen. */
++ bind_ipi.vcpu = 0;
++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
++ &bind_ipi) != 0)
++ BUG();
++ evtchn = bind_ipi.port;
++
++ /* Record the new mapping. */
++ evtchn_to_irq[evtchn] = irq;
++ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
++
++ /* Ready for use. */
++ unmask_evtchn(evtchn);
++ }
++}
++
++void __init xen_init_IRQ(void)
++{
++ int i;
++
++ init_evtchn_cpu_bindings();
++
++ /* No event channels are 'live' right now. */
++ for (i = 0; i < NR_EVENT_CHANNELS; i++)
++ mask_evtchn(i);
++
++ /* No IRQ -> event-channel mappings. */
++ for (i = 0; i < NR_IRQS; i++)
++ irq_info[i] = IRQ_UNBOUND;
++
++ /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
++ for (i = 0; i < NR_DYNIRQS; i++) {
++ irq_bindcount[dynirq_to_irq(i)] = 0;
++
++ irq_desc[dynirq_to_irq(i)].status = IRQ_DISABLED;
++ irq_desc[dynirq_to_irq(i)].action = NULL;
++ irq_desc[dynirq_to_irq(i)].depth = 1;
++ irq_desc[dynirq_to_irq(i)].chip = &dynirq_type;
++ }
++
++ /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */
++ for (i = 0; i < NR_PIRQS; i++) {
++ irq_bindcount[pirq_to_irq(i)] = 1;
++
++#ifdef RTC_IRQ
++ /* If not domain 0, force our RTC driver to fail its probe. */
++ if ((i == RTC_IRQ) && !is_initial_xendomain())
++ continue;
++#endif
++
++ irq_desc[pirq_to_irq(i)].status = IRQ_DISABLED;
++ irq_desc[pirq_to_irq(i)].action = NULL;
++ irq_desc[pirq_to_irq(i)].depth = 1;
++ irq_desc[pirq_to_irq(i)].chip = &pirq_type;
++ }
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/features.c linux-2.6.18-xen/drivers/xen/core/features.c
+--- linux-2.6.18.1/drivers/xen/core/features.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/features.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,30 @@
++/******************************************************************************
++ * features.c
++ *
++ * Xen feature flags.
++ *
++ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
++ */
++#include <linux/types.h>
++#include <linux/cache.h>
++#include <linux/module.h>
++#include <asm/hypervisor.h>
++#include <xen/features.h>
++
++u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
++/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
++EXPORT_SYMBOL(xen_features);
++
++void setup_xen_features(void)
++{
++ xen_feature_info_t fi;
++ int i, j;
++
++ for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
++ fi.submap_idx = i;
++ if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
++ break;
++ for (j=0; j<32; j++)
++ xen_features[i*32+j] = !!(fi.submap & 1<<j);
++ }
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/gnttab.c linux-2.6.18-xen/drivers/xen/core/gnttab.c
+--- linux-2.6.18.1/drivers/xen/core/gnttab.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/gnttab.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,483 @@
++/******************************************************************************
++ * gnttab.c
++ *
++ * Granting foreign access to our memory reservation.
++ *
++ * Copyright (c) 2005, Christopher Clark
++ * Copyright (c) 2004-2005, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/vmalloc.h>
++#include <xen/interface/xen.h>
++#include <xen/gnttab.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/synch_bitops.h>
++#include <asm/io.h>
++#include <xen/interface/memory.h>
++
++/* External tools reserve first few grant table entries. */
++#define NR_RESERVED_ENTRIES 8
++
++#define NR_GRANT_ENTRIES \
++ (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry))
++#define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
++
++static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
++static int gnttab_free_count;
++static grant_ref_t gnttab_free_head;
++static DEFINE_SPINLOCK(gnttab_list_lock);
++
++static struct grant_entry *shared;
++
++static struct gnttab_free_callback *gnttab_free_callback_list;
++
++static int get_free_entries(int count)
++{
++ unsigned long flags;
++ int ref;
++ grant_ref_t head;
++ spin_lock_irqsave(&gnttab_list_lock, flags);
++ if (gnttab_free_count < count) {
++ spin_unlock_irqrestore(&gnttab_list_lock, flags);
++ return -1;
++ }
++ ref = head = gnttab_free_head;
++ gnttab_free_count -= count;
++ while (count-- > 1)
++ head = gnttab_list[head];
++ gnttab_free_head = gnttab_list[head];
++ gnttab_list[head] = GNTTAB_LIST_END;
++ spin_unlock_irqrestore(&gnttab_list_lock, flags);
++ return ref;
++}
++
++#define get_free_entry() get_free_entries(1)
++
++static void do_free_callbacks(void)
++{
++ struct gnttab_free_callback *callback, *next;
++
++ callback = gnttab_free_callback_list;
++ gnttab_free_callback_list = NULL;
++
++ while (callback != NULL) {
++ next = callback->next;
++ if (gnttab_free_count >= callback->count) {
++ callback->next = NULL;
++ callback->fn(callback->arg);
++ } else {
++ callback->next = gnttab_free_callback_list;
++ gnttab_free_callback_list = callback;
++ }
++ callback = next;
++ }
++}
++
++static inline void check_free_callbacks(void)
++{
++ if (unlikely(gnttab_free_callback_list))
++ do_free_callbacks();
++}
++
++static void put_free_entry(grant_ref_t ref)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&gnttab_list_lock, flags);
++ gnttab_list[ref] = gnttab_free_head;
++ gnttab_free_head = ref;
++ gnttab_free_count++;
++ check_free_callbacks();
++ spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++
++/*
++ * Public grant-issuing interface functions
++ */
++
++int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
++ int readonly)
++{
++ int ref;
++
++ if (unlikely((ref = get_free_entry()) == -1))
++ return -ENOSPC;
++
++ shared[ref].frame = frame;
++ shared[ref].domid = domid;
++ wmb();
++ shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
++
++ return ref;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
++
++void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
++ unsigned long frame, int readonly)
++{
++ shared[ref].frame = frame;
++ shared[ref].domid = domid;
++ wmb();
++ shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
++
++
++int gnttab_query_foreign_access(grant_ref_t ref)
++{
++ u16 nflags;
++
++ nflags = shared[ref].flags;
++
++ return (nflags & (GTF_reading|GTF_writing));
++}
++EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
++
++int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
++{
++ u16 flags, nflags;
++
++ nflags = shared[ref].flags;
++ do {
++ if ((flags = nflags) & (GTF_reading|GTF_writing)) {
++ printk(KERN_ALERT "WARNING: g.e. still in use!\n");
++ return 0;
++ }
++ } while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) !=
++ flags);
++
++ return 1;
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
++
++void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
++ unsigned long page)
++{
++ if (gnttab_end_foreign_access_ref(ref, readonly)) {
++ put_free_entry(ref);
++ if (page != 0)
++ free_page(page);
++ } else {
++ /* XXX This needs to be fixed so that the ref and page are
++ placed on a list to be freed up later. */
++ printk(KERN_WARNING
++ "WARNING: leaking g.e. and page still in use!\n");
++ }
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
++
++int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
++{
++ int ref;
++
++ if (unlikely((ref = get_free_entry()) == -1))
++ return -ENOSPC;
++ gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
++
++ return ref;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
++
++void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
++ unsigned long pfn)
++{
++ shared[ref].frame = pfn;
++ shared[ref].domid = domid;
++ wmb();
++ shared[ref].flags = GTF_accept_transfer;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
++
++unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
++{
++ unsigned long frame;
++ u16 flags;
++
++ /*
++ * If a transfer is not even yet started, try to reclaim the grant
++ * reference and return failure (== 0).
++ */
++ while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
++ if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags)
++ return 0;
++ cpu_relax();
++ }
++
++ /* If a transfer is in progress then wait until it is completed. */
++ while (!(flags & GTF_transfer_completed)) {
++ flags = shared[ref].flags;
++ cpu_relax();
++ }
++
++ /* Read the frame number /after/ reading completion status. */
++ rmb();
++ frame = shared[ref].frame;
++ BUG_ON(frame == 0);
++
++ return frame;
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
++
++unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
++{
++ unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
++ put_free_entry(ref);
++ return frame;
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
++
++void gnttab_free_grant_reference(grant_ref_t ref)
++{
++ put_free_entry(ref);
++}
++EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
++
++void gnttab_free_grant_references(grant_ref_t head)
++{
++ grant_ref_t ref;
++ unsigned long flags;
++ int count = 1;
++ if (head == GNTTAB_LIST_END)
++ return;
++ spin_lock_irqsave(&gnttab_list_lock, flags);
++ ref = head;
++ while (gnttab_list[ref] != GNTTAB_LIST_END) {
++ ref = gnttab_list[ref];
++ count++;
++ }
++ gnttab_list[ref] = gnttab_free_head;
++ gnttab_free_head = head;
++ gnttab_free_count += count;
++ check_free_callbacks();
++ spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
++
++int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
++{
++ int h = get_free_entries(count);
++
++ if (h == -1)
++ return -ENOSPC;
++
++ *head = h;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
++
++int gnttab_empty_grant_references(const grant_ref_t *private_head)
++{
++ return (*private_head == GNTTAB_LIST_END);
++}
++EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
++
++int gnttab_claim_grant_reference(grant_ref_t *private_head)
++{
++ grant_ref_t g = *private_head;
++ if (unlikely(g == GNTTAB_LIST_END))
++ return -ENOSPC;
++ *private_head = gnttab_list[g];
++ return g;
++}
++EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
++
++void gnttab_release_grant_reference(grant_ref_t *private_head,
++ grant_ref_t release)
++{
++ gnttab_list[release] = *private_head;
++ *private_head = release;
++}
++EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
++
++void gnttab_request_free_callback(struct gnttab_free_callback *callback,
++ void (*fn)(void *), void *arg, u16 count)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&gnttab_list_lock, flags);
++ if (callback->next)
++ goto out;
++ callback->fn = fn;
++ callback->arg = arg;
++ callback->count = count;
++ callback->next = gnttab_free_callback_list;
++ gnttab_free_callback_list = callback;
++ check_free_callbacks();
++out:
++ spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
++
++void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
++{
++ struct gnttab_free_callback **pcb;
++ unsigned long flags;
++
++ spin_lock_irqsave(&gnttab_list_lock, flags);
++ for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
++ if (*pcb == callback) {
++ *pcb = callback->next;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
++
++#ifdef CONFIG_XEN
++
++#ifndef __ia64__
++static int map_pte_fn(pte_t *pte, struct page *pmd_page,
++ unsigned long addr, void *data)
++{
++ unsigned long **frames = (unsigned long **)data;
++
++ set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
++ (*frames)++;
++ return 0;
++}
++
++static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
++ unsigned long addr, void *data)
++{
++
++ set_pte_at(&init_mm, addr, pte, __pte(0));
++ return 0;
++}
++#endif
++
++int gnttab_resume(void)
++{
++ struct gnttab_setup_table setup;
++ unsigned long frames[NR_GRANT_FRAMES];
++ int rc;
++#ifndef __ia64__
++ void *pframes = frames;
++ struct vm_struct *area;
++#endif
++
++ setup.dom = DOMID_SELF;
++ setup.nr_frames = NR_GRANT_FRAMES;
++ set_xen_guest_handle(setup.frame_list, frames);
++
++ rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
++ if (rc == -ENOSYS)
++ return -ENOSYS;
++
++ BUG_ON(rc || setup.status);
++
++#ifndef __ia64__
++ if (shared == NULL) {
++ area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
++ BUG_ON(area == NULL);
++ shared = area->addr;
++ }
++ rc = apply_to_page_range(&init_mm, (unsigned long)shared,
++ PAGE_SIZE * NR_GRANT_FRAMES,
++ map_pte_fn, &pframes);
++ BUG_ON(rc);
++#else
++ shared = __va(frames[0] << PAGE_SHIFT);
++ printk("grant table at %p\n", shared);
++#endif
++
++ return 0;
++}
++
++int gnttab_suspend(void)
++{
++#ifndef __ia64__
++ apply_to_page_range(&init_mm, (unsigned long)shared,
++ PAGE_SIZE * NR_GRANT_FRAMES,
++ unmap_pte_fn, NULL);
++#endif
++ return 0;
++}
++
++#else /* !CONFIG_XEN */
++
++#include <platform-pci.h>
++
++int gnttab_resume(void)
++{
++ unsigned long frames;
++ struct xen_add_to_physmap xatp;
++ unsigned int i;
++
++ frames = alloc_xen_mmio(PAGE_SIZE * NR_GRANT_FRAMES);
++
++ for (i = 0; i < NR_GRANT_FRAMES; i++) {
++ xatp.domid = DOMID_SELF;
++ xatp.idx = i;
++ xatp.space = XENMAPSPACE_grant_table;
++ xatp.gpfn = (frames >> PAGE_SHIFT) + i;
++ if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
++ BUG();
++ }
++
++ shared = ioremap(frames, PAGE_SIZE * NR_GRANT_FRAMES);
++ if (shared == NULL) {
++ printk("error to ioremap gnttab share frames\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++int gnttab_suspend(void)
++{
++ iounmap(shared);
++ return 0;
++}
++
++#endif /* !CONFIG_XEN */
++
++int __init gnttab_init(void)
++{
++ int i;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ if (gnttab_resume() < 0)
++ return -ENODEV;
++
++ for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
++ gnttab_list[i] = i + 1;
++ gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
++ gnttab_free_head = NR_RESERVED_ENTRIES;
++
++ printk("Grant table initialized\n");
++ return 0;
++}
++
++#ifdef CONFIG_XEN
++core_initcall(gnttab_init);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/hypervisor_sysfs.c linux-2.6.18-xen/drivers/xen/core/hypervisor_sysfs.c
+--- linux-2.6.18.1/drivers/xen/core/hypervisor_sysfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/hypervisor_sysfs.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ * copyright (c) 2006 IBM Corporation
++ * Authored by: Mike D. Day <ncmike at 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/kobject.h>
++#include <xen/hypervisor_sysfs.h>
++
++decl_subsys(hypervisor, NULL, NULL);
++
++static ssize_t hyp_sysfs_show(struct kobject *kobj,
++ struct attribute *attr,
++ char *buffer)
++{
++ struct hyp_sysfs_attr *hyp_attr;
++ hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
++ if (hyp_attr->show)
++ return hyp_attr->show(hyp_attr, buffer);
++ return 0;
++}
++
++static ssize_t hyp_sysfs_store(struct kobject *kobj,
++ struct attribute *attr,
++ const char *buffer,
++ size_t len)
++{
++ struct hyp_sysfs_attr *hyp_attr;
++ hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
++ if (hyp_attr->store)
++ return hyp_attr->store(hyp_attr, buffer, len);
++ return 0;
++}
++
++struct sysfs_ops hyp_sysfs_ops = {
++ .show = hyp_sysfs_show,
++ .store = hyp_sysfs_store,
++};
++
++static struct kobj_type hyp_sysfs_kobj_type = {
++ .sysfs_ops = &hyp_sysfs_ops,
++};
++
++static int __init hypervisor_subsys_init(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ hypervisor_subsys.kset.kobj.ktype = &hyp_sysfs_kobj_type;
++ return subsystem_register(&hypervisor_subsys);
++}
++
++device_initcall(hypervisor_subsys_init);
++EXPORT_SYMBOL_GPL(hypervisor_subsys);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/Makefile linux-2.6.18-xen/drivers/xen/core/Makefile
+--- linux-2.6.18.1/drivers/xen/core/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,13 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y := evtchn.o gnttab.o features.o
++
++obj-$(CONFIG_PROC_FS) += xen_proc.o
++obj-$(CONFIG_SYSFS) += hypervisor_sysfs.o
++obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
++obj-$(CONFIG_XEN_SYSFS) += xen_sysfs.o
++obj-$(CONFIG_XEN_SKBUFF) += skbuff.o
++obj-$(CONFIG_XEN_REBOOT) += reboot.o
++obj-$(CONFIG_XEN_SMPBOOT) += smpboot.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/reboot.c linux-2.6.18-xen/drivers/xen/core/reboot.c
+--- linux-2.6.18.1/drivers/xen/core/reboot.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/reboot.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,384 @@
++#define __KERNEL_SYSCALLS__
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/unistd.h>
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/sysrq.h>
++#include <linux/stringify.h>
++#include <asm/irq.h>
++#include <asm/mmu_context.h>
++#include <xen/evtchn.h>
++#include <asm/hypervisor.h>
++#include <xen/interface/dom0_ops.h>
++#include <xen/xenbus.h>
++#include <linux/cpu.h>
++#include <linux/kthread.h>
++#include <xen/gnttab.h>
++#include <xen/xencons.h>
++#include <xen/cpu_hotplug.h>
++
++extern void ctrl_alt_del(void);
++
++#define SHUTDOWN_INVALID -1
++#define SHUTDOWN_POWEROFF 0
++#define SHUTDOWN_SUSPEND 2
++/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
++ * report a crash, not be instructed to crash!
++ * HALT is the same as POWEROFF, as far as we're concerned. The tools use
++ * the distinction when we return the reason code to them.
++ */
++#define SHUTDOWN_HALT 4
++
++#if defined(__i386__) || defined(__x86_64__)
++
++/*
++ * Power off function, if any
++ */
++void (*pm_power_off)(void);
++EXPORT_SYMBOL(pm_power_off);
++
++void machine_emergency_restart(void)
++{
++ /* We really want to get pending console data out before we die. */
++ xencons_force_flush();
++ HYPERVISOR_shutdown(SHUTDOWN_reboot);
++}
++
++void machine_restart(char * __unused)
++{
++ machine_emergency_restart();
++}
++
++void machine_halt(void)
++{
++ machine_power_off();
++}
++
++void machine_power_off(void)
++{
++ /* We really want to get pending console data out before we die. */
++ xencons_force_flush();
++ if (pm_power_off)
++ pm_power_off();
++ HYPERVISOR_shutdown(SHUTDOWN_poweroff);
++}
++
++int reboot_thru_bios = 0; /* for dmi_scan.c */
++EXPORT_SYMBOL(machine_restart);
++EXPORT_SYMBOL(machine_halt);
++EXPORT_SYMBOL(machine_power_off);
++
++#endif /* defined(__i386__) || defined(__x86_64__) */
++
++/******************************************************************************
++ * Stop/pickle callback handling.
++ */
++
++/* Ignore multiple shutdown requests. */
++static int shutting_down = SHUTDOWN_INVALID;
++static void __shutdown_handler(void *unused);
++static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
++
++#if defined(__i386__) || defined(__x86_64__)
++
++/* Ensure we run on the idle task page tables so that we will
++ switch page tables before running user space. This is needed
++ on architectures with separate kernel and user page tables
++ because the user page table pointer is not saved/restored. */
++static void switch_idle_mm(void)
++{
++ struct mm_struct *mm = current->active_mm;
++
++ if (mm == &init_mm)
++ return;
++
++ atomic_inc(&init_mm.mm_count);
++ switch_mm(mm, &init_mm, current);
++ current->active_mm = &init_mm;
++ mmdrop(mm);
++}
++
++static void pre_suspend(void)
++{
++ HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
++ clear_fixmap(FIX_SHARED_INFO);
++
++ xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
++ xen_start_info->console.domU.mfn =
++ mfn_to_pfn(xen_start_info->console.domU.mfn);
++}
++
++static void post_suspend(void)
++{
++ int i, j, k, fpp;
++ extern unsigned long max_pfn;
++ extern unsigned long *pfn_to_mfn_frame_list_list;
++ extern unsigned long *pfn_to_mfn_frame_list[];
++
++ set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
++
++ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
++
++ memset(empty_zero_page, 0, PAGE_SIZE);
++
++ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
++ virt_to_mfn(pfn_to_mfn_frame_list_list);
++
++ fpp = PAGE_SIZE/sizeof(unsigned long);
++ for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
++ if ((j % fpp) == 0) {
++ k++;
++ pfn_to_mfn_frame_list_list[k] =
++ virt_to_mfn(pfn_to_mfn_frame_list[k]);
++ j = 0;
++ }
++ pfn_to_mfn_frame_list[k][j] =
++ virt_to_mfn(&phys_to_machine_mapping[i]);
++ }
++ HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
++}
++
++#else /* !(defined(__i386__) || defined(__x86_64__)) */
++
++#define switch_idle_mm() ((void)0)
++#define mm_pin_all() ((void)0)
++#define pre_suspend() ((void)0)
++#define post_suspend() ((void)0)
++
++#endif
++
++static int __do_suspend(void *ignore)
++{
++ int err;
++
++ extern void time_resume(void);
++
++ BUG_ON(smp_processor_id() != 0);
++ BUG_ON(in_interrupt());
++
++#if defined(__i386__) || defined(__x86_64__)
++ if (xen_feature(XENFEAT_auto_translated_physmap)) {
++ printk(KERN_WARNING "Cannot suspend in "
++ "auto_translated_physmap mode.\n");
++ return -EOPNOTSUPP;
++ }
++#endif
++
++ err = smp_suspend();
++ if (err)
++ return err;
++
++ xenbus_suspend();
++
++ preempt_disable();
++
++ mm_pin_all();
++ local_irq_disable();
++ preempt_enable();
++
++ gnttab_suspend();
++
++ pre_suspend();
++
++ /*
++ * We'll stop somewhere inside this hypercall. When it returns,
++ * we'll start resuming after the restore.
++ */
++ HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
++
++ shutting_down = SHUTDOWN_INVALID;
++
++ post_suspend();
++
++ gnttab_resume();
++
++ irq_resume();
++
++ time_resume();
++
++ switch_idle_mm();
++
++ local_irq_enable();
++
++ xencons_resume();
++
++ xenbus_resume();
++
++ smp_resume();
++
++ return err;
++}
++
++static int shutdown_process(void *__unused)
++{
++ static char *envp[] = { "HOME=/", "TERM=linux",
++ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
++ static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
++
++ extern asmlinkage long sys_reboot(int magic1, int magic2,
++ unsigned int cmd, void *arg);
++
++ if ((shutting_down == SHUTDOWN_POWEROFF) ||
++ (shutting_down == SHUTDOWN_HALT)) {
++ if (execve("/sbin/poweroff", poweroff_argv, envp) < 0) {
++ sys_reboot(LINUX_REBOOT_MAGIC1,
++ LINUX_REBOOT_MAGIC2,
++ LINUX_REBOOT_CMD_POWER_OFF,
++ NULL);
++ }
++ }
++
++ shutting_down = SHUTDOWN_INVALID; /* could try again */
++
++ return 0;
++}
++
++static int kthread_create_on_cpu(int (*f)(void *arg),
++ void *arg,
++ const char *name,
++ int cpu)
++{
++ struct task_struct *p;
++ p = kthread_create(f, arg, name);
++ if (IS_ERR(p))
++ return PTR_ERR(p);
++ kthread_bind(p, cpu);
++ wake_up_process(p);
++ return 0;
++}
++
++static void __shutdown_handler(void *unused)
++{
++ int err;
++
++ if (shutting_down != SHUTDOWN_SUSPEND)
++ err = kernel_thread(shutdown_process, NULL,
++ CLONE_FS | CLONE_FILES);
++ else
++ err = kthread_create_on_cpu(__do_suspend, NULL, "suspend", 0);
++
++ if (err < 0) {
++ printk(KERN_WARNING "Error creating shutdown process (%d): "
++ "retrying...\n", -err);
++ schedule_delayed_work(&shutdown_work, HZ/2);
++ }
++}
++
++static void shutdown_handler(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ char *str;
++ struct xenbus_transaction xbt;
++ int err;
++
++ if (shutting_down != SHUTDOWN_INVALID)
++ return;
++
++ again:
++ err = xenbus_transaction_start(&xbt);
++ if (err)
++ return;
++ str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
++ /* Ignore read errors and empty reads. */
++ if (XENBUS_IS_ERR_READ(str)) {
++ xenbus_transaction_end(xbt, 1);
++ return;
++ }
++
++ xenbus_write(xbt, "control", "shutdown", "");
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err == -EAGAIN) {
++ kfree(str);
++ goto again;
++ }
++
++ if (strcmp(str, "poweroff") == 0)
++ shutting_down = SHUTDOWN_POWEROFF;
++ else if (strcmp(str, "reboot") == 0)
++ ctrl_alt_del();
++ else if (strcmp(str, "suspend") == 0)
++ shutting_down = SHUTDOWN_SUSPEND;
++ else if (strcmp(str, "halt") == 0)
++ shutting_down = SHUTDOWN_HALT;
++ else {
++ printk("Ignoring shutdown request: %s\n", str);
++ shutting_down = SHUTDOWN_INVALID;
++ }
++
++ if (shutting_down != SHUTDOWN_INVALID)
++ schedule_work(&shutdown_work);
++
++ kfree(str);
++}
++
++static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
++ unsigned int len)
++{
++ char sysrq_key = '\0';
++ struct xenbus_transaction xbt;
++ int err;
++
++ again:
++ err = xenbus_transaction_start(&xbt);
++ if (err)
++ return;
++ if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
++ printk(KERN_ERR "Unable to read sysrq code in "
++ "control/sysrq\n");
++ xenbus_transaction_end(xbt, 1);
++ return;
++ }
++
++ if (sysrq_key != '\0')
++ xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err == -EAGAIN)
++ goto again;
++
++#ifdef CONFIG_MAGIC_SYSRQ
++ if (sysrq_key != '\0')
++ handle_sysrq(sysrq_key, NULL, NULL);
++#endif
++}
++
++static struct xenbus_watch shutdown_watch = {
++ .node = "control/shutdown",
++ .callback = shutdown_handler
++};
++
++static struct xenbus_watch sysrq_watch = {
++ .node ="control/sysrq",
++ .callback = sysrq_handler
++};
++
++static int setup_shutdown_watcher(struct notifier_block *notifier,
++ unsigned long event,
++ void *data)
++{
++ int err;
++
++ err = register_xenbus_watch(&shutdown_watch);
++ if (err)
++ printk(KERN_ERR "Failed to set shutdown watcher\n");
++
++ err = register_xenbus_watch(&sysrq_watch);
++ if (err)
++ printk(KERN_ERR "Failed to set sysrq watcher\n");
++
++ return NOTIFY_DONE;
++}
++
++static int __init setup_shutdown_event(void)
++{
++ static struct notifier_block xenstore_notifier = {
++ .notifier_call = setup_shutdown_watcher
++ };
++ register_xenstore_notifier(&xenstore_notifier);
++ return 0;
++}
++
++subsys_initcall(setup_shutdown_event);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/skbuff.c linux-2.6.18-xen/drivers/xen/core/skbuff.c
+--- linux-2.6.18.1/drivers/xen/core/skbuff.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/skbuff.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,144 @@
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/netdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/hypervisor.h>
++
++/* Referenced in netback.c. */
++/*static*/ kmem_cache_t *skbuff_cachep;
++EXPORT_SYMBOL(skbuff_cachep);
++
++/* Allow up to 64kB or page-sized packets (whichever is greater). */
++#if PAGE_SHIFT < 16
++#define MAX_SKBUFF_ORDER (16 - PAGE_SHIFT)
++#else
++#define MAX_SKBUFF_ORDER 0
++#endif
++static kmem_cache_t *skbuff_order_cachep[MAX_SKBUFF_ORDER + 1];
++
++static struct {
++ int size;
++ kmem_cache_t *cachep;
++} skbuff_small[] = { { 512, NULL }, { 2048, NULL } };
++
++struct sk_buff *__alloc_skb(unsigned int length, gfp_t gfp_mask,
++ int fclone)
++{
++ int order, i;
++ kmem_cache_t *cachep;
++
++ length = SKB_DATA_ALIGN(length) + sizeof(struct skb_shared_info);
++
++ if (length <= skbuff_small[ARRAY_SIZE(skbuff_small)-1].size) {
++ for (i = 0; skbuff_small[i].size < length; i++)
++ continue;
++ cachep = skbuff_small[i].cachep;
++ } else {
++ order = get_order(length);
++ if (order > MAX_SKBUFF_ORDER) {
++ printk(KERN_ALERT "Attempt to allocate order %d "
++ "skbuff. Increase MAX_SKBUFF_ORDER.\n", order);
++ return NULL;
++ }
++ cachep = skbuff_order_cachep[order];
++ }
++
++ length -= sizeof(struct skb_shared_info);
++
++ return alloc_skb_from_cache(cachep, length, gfp_mask, fclone);
++}
++
++struct sk_buff *__dev_alloc_skb(unsigned int length, gfp_t gfp_mask)
++{
++ struct sk_buff *skb;
++ int order;
++
++ length = SKB_DATA_ALIGN(length + 16);
++ order = get_order(length + sizeof(struct skb_shared_info));
++ if (order > MAX_SKBUFF_ORDER) {
++ printk(KERN_ALERT "Attempt to allocate order %d skbuff. "
++ "Increase MAX_SKBUFF_ORDER.\n", order);
++ return NULL;
++ }
++
++ skb = alloc_skb_from_cache(
++ skbuff_order_cachep[order], length, gfp_mask, 0);
++ if (skb != NULL)
++ skb_reserve(skb, 16);
++
++ return skb;
++}
++
++static void skbuff_ctor(void *buf, kmem_cache_t *cachep, unsigned long unused)
++{
++ int order = 0;
++
++ while (skbuff_order_cachep[order] != cachep)
++ order++;
++
++ /* Do our best to allocate contiguous memory but fall back to IOMMU. */
++ if (order != 0)
++ (void)xen_create_contiguous_region(
++ (unsigned long)buf, order, 0);
++
++ scrub_pages(buf, 1 << order);
++}
++
++static void skbuff_dtor(void *buf, kmem_cache_t *cachep, unsigned long unused)
++{
++ int order = 0;
++
++ while (skbuff_order_cachep[order] != cachep)
++ order++;
++
++ if (order != 0)
++ xen_destroy_contiguous_region((unsigned long)buf, order);
++}
++
++static int __init skbuff_init(void)
++{
++ static char name[MAX_SKBUFF_ORDER + 1][20];
++ static char small_name[ARRAY_SIZE(skbuff_small)][20];
++ unsigned long size;
++ int i, order;
++
++ for (i = 0; i < ARRAY_SIZE(skbuff_small); i++) {
++ size = skbuff_small[i].size;
++ sprintf(small_name[i], "xen-skb-%lu", size);
++ /*
++ * No ctor/dtor: objects do not span page boundaries, and they
++ * are only used on transmit path so no need for scrubbing.
++ */
++ skbuff_small[i].cachep = kmem_cache_create(
++ small_name[i], size, size, 0, NULL, NULL);
++ }
++
++ for (order = 0; order <= MAX_SKBUFF_ORDER; order++) {
++ size = PAGE_SIZE << order;
++ sprintf(name[order], "xen-skb-%lu", size);
++ if (is_running_on_xen() && is_initial_xendomain())
++ skbuff_order_cachep[order] = kmem_cache_create(
++ name[order], size, size, 0,
++ skbuff_ctor, skbuff_dtor);
++ else
++ skbuff_order_cachep[order] = kmem_cache_create(
++ name[order], size, size, 0, NULL, NULL);
++
++ }
++
++ skbuff_cachep = skbuff_order_cachep[0];
++
++ return 0;
++}
++core_initcall(skbuff_init);
++
++EXPORT_SYMBOL(__dev_alloc_skb);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/smpboot.c linux-2.6.18-xen/drivers/xen/core/smpboot.c
+--- linux-2.6.18.1/drivers/xen/core/smpboot.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/smpboot.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,429 @@
++/*
++ * Xen SMP booting functions
++ *
++ * See arch/i386/kernel/smpboot.c for copyright and credits for derived
++ * portions of this file.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/kernel_stat.h>
++#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 <asm/desc.h>
++#include <asm/arch_hooks.h>
++#include <asm/pgalloc.h>
++#include <xen/evtchn.h>
++#include <xen/interface/vcpu.h>
++#include <xen/cpu_hotplug.h>
++#include <xen/xenbus.h>
++
++extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
++extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
++
++extern void local_setup_timer(unsigned int cpu);
++extern void local_teardown_timer(unsigned int cpu);
++
++extern void hypervisor_callback(void);
++extern void failsafe_callback(void);
++extern void system_call(void);
++extern void smp_trap_init(trap_info_t *);
++
++/* Number of siblings per CPU package */
++int smp_num_siblings = 1;
++EXPORT_SYMBOL(smp_num_siblings);
++#if defined(__i386__)
++int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
++#elif defined(__x86_64__)
++u8 cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
++#endif
++EXPORT_SYMBOL(cpu_llc_id);
++
++cpumask_t cpu_online_map;
++EXPORT_SYMBOL(cpu_online_map);
++cpumask_t cpu_possible_map;
++EXPORT_SYMBOL(cpu_possible_map);
++
++struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
++EXPORT_SYMBOL(cpu_data);
++
++#ifdef CONFIG_HOTPLUG_CPU
++DEFINE_PER_CPU(int, cpu_state) = { 0 };
++#endif
++
++static DEFINE_PER_CPU(int, resched_irq);
++static DEFINE_PER_CPU(int, callfunc_irq);
++static char resched_name[NR_CPUS][15];
++static char callfunc_name[NR_CPUS][15];
++
++u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
++
++void *xquad_portio;
++
++cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
++EXPORT_SYMBOL(cpu_sibling_map);
++cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
++EXPORT_SYMBOL(cpu_core_map);
++
++#if defined(__i386__)
++u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff };
++EXPORT_SYMBOL(x86_cpu_to_apicid);
++#elif !defined(CONFIG_X86_IO_APIC)
++unsigned int maxcpus = NR_CPUS;
++#endif
++
++void __init prefill_possible_map(void)
++{
++ int i, rc;
++
++ for (i = 0; i < NR_CPUS; i++) {
++ rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
++ if (rc >= 0)
++ cpu_set(i, cpu_possible_map);
++ }
++}
++
++void __init smp_alloc_memory(void)
++{
++}
++
++static inline void
++set_cpu_sibling_map(int cpu)
++{
++ cpu_data[cpu].phys_proc_id = cpu;
++ cpu_data[cpu].cpu_core_id = 0;
++
++ cpu_sibling_map[cpu] = cpumask_of_cpu(cpu);
++ cpu_core_map[cpu] = cpumask_of_cpu(cpu);
++
++ cpu_data[cpu].booted_cores = 1;
++}
++
++static void xen_smp_intr_init(unsigned int cpu)
++{
++ sprintf(resched_name[cpu], "resched%d", cpu);
++ per_cpu(resched_irq, cpu) =
++ bind_ipi_to_irqhandler(
++ RESCHEDULE_VECTOR,
++ cpu,
++ smp_reschedule_interrupt,
++ SA_INTERRUPT,
++ resched_name[cpu],
++ NULL);
++ BUG_ON(per_cpu(resched_irq, cpu) < 0);
++
++ sprintf(callfunc_name[cpu], "callfunc%d", cpu);
++ per_cpu(callfunc_irq, cpu) =
++ bind_ipi_to_irqhandler(
++ CALL_FUNCTION_VECTOR,
++ cpu,
++ smp_call_function_interrupt,
++ SA_INTERRUPT,
++ callfunc_name[cpu],
++ NULL);
++ BUG_ON(per_cpu(callfunc_irq, cpu) < 0);
++
++ if (cpu != 0)
++ local_setup_timer(cpu);
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static void xen_smp_intr_exit(unsigned int cpu)
++{
++ if (cpu != 0)
++ local_teardown_timer(cpu);
++
++ unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
++ unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
++}
++#endif
++
++void cpu_bringup(void)
++{
++ cpu_init();
++ touch_softlockup_watchdog();
++ preempt_disable();
++ local_irq_enable();
++}
++
++static void cpu_bringup_and_idle(void)
++{
++ cpu_bringup();
++ cpu_idle();
++}
++
++void cpu_initialize_context(unsigned int cpu)
++{
++ vcpu_guest_context_t ctxt;
++ struct task_struct *idle = idle_task(cpu);
++#ifdef __x86_64__
++ struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu];
++#else
++ struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
++#endif
++
++ if (cpu == 0)
++ return;
++
++ memset(&ctxt, 0, sizeof(ctxt));
++
++ ctxt.flags = VGCF_IN_KERNEL;
++ ctxt.user_regs.ds = __USER_DS;
++ ctxt.user_regs.es = __USER_DS;
++ ctxt.user_regs.fs = 0;
++ ctxt.user_regs.gs = 0;
++ ctxt.user_regs.ss = __KERNEL_DS;
++ ctxt.user_regs.eip = (unsigned long)cpu_bringup_and_idle;
++ ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */
++
++ memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
++
++ smp_trap_init(ctxt.trap_ctxt);
++
++ ctxt.ldt_ents = 0;
++
++ ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address);
++ ctxt.gdt_ents = gdt_descr->size / 8;
++
++#ifdef __i386__
++ ctxt.user_regs.cs = __KERNEL_CS;
++ ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
++
++ ctxt.kernel_ss = __KERNEL_DS;
++ ctxt.kernel_sp = idle->thread.esp0;
++
++ ctxt.event_callback_cs = __KERNEL_CS;
++ ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
++ ctxt.failsafe_callback_cs = __KERNEL_CS;
++ ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
++
++ ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
++#else /* __x86_64__ */
++ ctxt.user_regs.cs = __KERNEL_CS;
++ ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
++
++ ctxt.kernel_ss = __KERNEL_DS;
++ ctxt.kernel_sp = idle->thread.rsp0;
++
++ ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
++ ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
++ ctxt.syscall_callback_eip = (unsigned long)system_call;
++
++ ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
++
++ ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
++#endif
++
++ BUG_ON(HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt));
++}
++
++void __init smp_prepare_cpus(unsigned int max_cpus)
++{
++ int cpu;
++ struct task_struct *idle;
++#ifdef __x86_64__
++ struct desc_ptr *gdt_descr;
++#else
++ struct Xgt_desc_struct *gdt_descr;
++#endif
++
++ boot_cpu_data.apicid = 0;
++ cpu_data[0] = boot_cpu_data;
++
++ cpu_2_logical_apicid[0] = 0;
++ x86_cpu_to_apicid[0] = 0;
++
++ current_thread_info()->cpu = 0;
++
++ for (cpu = 0; cpu < NR_CPUS; cpu++) {
++ cpus_clear(cpu_sibling_map[cpu]);
++ cpus_clear(cpu_core_map[cpu]);
++ }
++
++ set_cpu_sibling_map(0);
++
++ xen_smp_intr_init(0);
++
++ /* Restrict the possible_map according to max_cpus. */
++ while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
++ for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
++ continue;
++ cpu_clear(cpu, cpu_possible_map);
++ }
++
++ for_each_possible_cpu (cpu) {
++ if (cpu == 0)
++ continue;
++
++#ifdef __x86_64__
++ gdt_descr = &cpu_gdt_descr[cpu];
++#else
++ gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
++#endif
++ gdt_descr->address = get_zeroed_page(GFP_KERNEL);
++ if (unlikely(!gdt_descr->address)) {
++ printk(KERN_CRIT "CPU%d failed to allocate GDT\n",
++ cpu);
++ continue;
++ }
++ gdt_descr->size = GDT_SIZE;
++ memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE);
++ make_page_readonly(
++ (void *)gdt_descr->address,
++ XENFEAT_writable_descriptor_tables);
++
++ cpu_data[cpu] = boot_cpu_data;
++ cpu_data[cpu].apicid = cpu;
++
++ cpu_2_logical_apicid[cpu] = cpu;
++ x86_cpu_to_apicid[cpu] = cpu;
++
++ idle = fork_idle(cpu);
++ if (IS_ERR(idle))
++ panic("failed fork for CPU %d", cpu);
++
++#ifdef __x86_64__
++ cpu_pda(cpu)->pcurrent = idle;
++ cpu_pda(cpu)->cpunumber = cpu;
++ clear_ti_thread_flag(idle->thread_info, TIF_FORK);
++#endif
++
++ irq_ctx_init(cpu);
++
++#ifdef CONFIG_HOTPLUG_CPU
++ if (is_initial_xendomain())
++ cpu_set(cpu, cpu_present_map);
++#else
++ cpu_set(cpu, cpu_present_map);
++#endif
++
++ cpu_initialize_context(cpu);
++ }
++
++ init_xenbus_allowed_cpumask();
++
++#ifdef CONFIG_X86_IO_APIC
++ /*
++ * Here we can be sure that there is an IO-APIC in the system. Let's
++ * go and set it up:
++ */
++ if (!skip_ioapic_setup && nr_ioapics)
++ setup_IO_APIC();
++#endif
++}
++
++void __devinit smp_prepare_boot_cpu(void)
++{
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++
++/*
++ * Initialize cpu_present_map late to skip SMP boot code in init/main.c.
++ * But do it early enough to catch critical for_each_present_cpu() loops
++ * in i386-specific code.
++ */
++static int __init initialize_cpu_present_map(void)
++{
++ cpu_present_map = cpu_possible_map;
++ return 0;
++}
++core_initcall(initialize_cpu_present_map);
++
++static void
++remove_siblinginfo(int cpu)
++{
++ cpu_data[cpu].phys_proc_id = BAD_APICID;
++ cpu_data[cpu].cpu_core_id = BAD_APICID;
++
++ cpus_clear(cpu_sibling_map[cpu]);
++ cpus_clear(cpu_core_map[cpu]);
++
++ cpu_data[cpu].booted_cores = 0;
++}
++
++int __cpu_disable(void)
++{
++ cpumask_t map = cpu_online_map;
++ int cpu = smp_processor_id();
++
++ if (cpu == 0)
++ return -EBUSY;
++
++ remove_siblinginfo(cpu);
++
++ cpu_clear(cpu, map);
++ fixup_irqs(map);
++ cpu_clear(cpu, cpu_online_map);
++
++ return 0;
++}
++
++void __cpu_die(unsigned int cpu)
++{
++ while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
++ current->state = TASK_UNINTERRUPTIBLE;
++ schedule_timeout(HZ/10);
++ }
++
++ xen_smp_intr_exit(cpu);
++
++ if (num_online_cpus() == 1)
++ alternatives_smp_switch(0);
++}
++
++#else /* !CONFIG_HOTPLUG_CPU */
++
++int __cpu_disable(void)
++{
++ return -ENOSYS;
++}
++
++void __cpu_die(unsigned int cpu)
++{
++ BUG();
++}
++
++#endif /* CONFIG_HOTPLUG_CPU */
++
++int __devinit __cpu_up(unsigned int cpu)
++{
++ int rc;
++
++ rc = cpu_up_check(cpu);
++ if (rc)
++ return rc;
++
++ if (num_online_cpus() == 1)
++ alternatives_smp_switch(1);
++
++ /* This must be done before setting cpu_online_map */
++ set_cpu_sibling_map(cpu);
++ wmb();
++
++ xen_smp_intr_init(cpu);
++ cpu_set(cpu, cpu_online_map);
++
++ rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
++ BUG_ON(rc);
++
++ return 0;
++}
++
++void __init smp_cpus_done(unsigned int max_cpus)
++{
++}
++
++#ifndef CONFIG_X86_LOCAL_APIC
++int setup_profiling_timer(unsigned int multiplier)
++{
++ return -EINVAL;
++}
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/xen_proc.c linux-2.6.18-xen/drivers/xen/core/xen_proc.c
+--- linux-2.6.18.1/drivers/xen/core/xen_proc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/xen_proc.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,18 @@
++
++#include <linux/proc_fs.h>
++#include <xen/xen_proc.h>
++
++static struct proc_dir_entry *xen_base;
++
++struct proc_dir_entry *create_xen_proc_entry(const char *name, mode_t mode)
++{
++ if ( xen_base == NULL )
++ if ( (xen_base = proc_mkdir("xen", &proc_root)) == NULL )
++ panic("Couldn't create /proc/xen");
++ return create_proc_entry(name, mode, xen_base);
++}
++
++void remove_xen_proc_entry(const char *name)
++{
++ remove_proc_entry(name, xen_base);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/core/xen_sysfs.c linux-2.6.18-xen/drivers/xen/core/xen_sysfs.c
+--- linux-2.6.18.1/drivers/xen/core/xen_sysfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/core/xen_sysfs.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,378 @@
++/*
++ * copyright (c) 2006 IBM Corporation
++ * Authored by: Mike D. Day <ncmike at 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <asm/hypervisor.h>
++#include <xen/features.h>
++#include <xen/hypervisor_sysfs.h>
++#include <xen/xenbus.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mike D. Day <ncmike at us.ibm.com>");
++
++static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ return sprintf(buffer, "xen\n");
++}
++
++HYPERVISOR_ATTR_RO(type);
++
++static int __init xen_sysfs_type_init(void)
++{
++ return sysfs_create_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
++}
++
++static void xen_sysfs_type_destroy(void)
++{
++ sysfs_remove_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
++}
++
++/* xen version attributes */
++static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int version = HYPERVISOR_xen_version(XENVER_version, NULL);
++ if (version)
++ return sprintf(buffer, "%d\n", version >> 16);
++ return -ENODEV;
++}
++
++HYPERVISOR_ATTR_RO(major);
++
++static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int version = HYPERVISOR_xen_version(XENVER_version, NULL);
++ if (version)
++ return sprintf(buffer, "%d\n", version & 0xff);
++ return -ENODEV;
++}
++
++HYPERVISOR_ATTR_RO(minor);
++
++static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ char *extra;
++
++ extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
++ if (extra) {
++ ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
++ if (!ret)
++ ret = sprintf(buffer, "%s\n", extra);
++ kfree(extra);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(extra);
++
++static struct attribute *version_attrs[] = {
++ &major_attr.attr,
++ &minor_attr.attr,
++ &extra_attr.attr,
++ NULL
++};
++
++static struct attribute_group version_group = {
++ .name = "version",
++ .attrs = version_attrs,
++};
++
++static int __init xen_sysfs_version_init(void)
++{
++ return sysfs_create_group(&hypervisor_subsys.kset.kobj,
++ &version_group);
++}
++
++static void xen_sysfs_version_destroy(void)
++{
++ sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group);
++}
++
++/* UUID */
++
++static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ char *vm, *val;
++ int ret;
++
++ vm = xenbus_read(XBT_NIL, "vm", "", NULL);
++ if (IS_ERR(vm))
++ return PTR_ERR(vm);
++ val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
++ kfree(vm);
++ if (IS_ERR(val))
++ return PTR_ERR(val);
++ ret = sprintf(buffer, "%s\n", val);
++ kfree(val);
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(uuid);
++
++static int __init xen_sysfs_uuid_init(void)
++{
++ return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
++}
++
++static void xen_sysfs_uuid_destroy(void)
++{
++ sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
++}
++
++/* xen compilation attributes */
++
++static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ struct xen_compile_info *info;
++
++ info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
++ if (info) {
++ ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
++ if (!ret)
++ ret = sprintf(buffer, "%s\n", info->compiler);
++ kfree(info);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(compiler);
++
++static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ struct xen_compile_info *info;
++
++ info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
++ if (info) {
++ ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
++ if (!ret)
++ ret = sprintf(buffer, "%s\n", info->compile_by);
++ kfree(info);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(compiled_by);
++
++static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ struct xen_compile_info *info;
++
++ info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
++ if (info) {
++ ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
++ if (!ret)
++ ret = sprintf(buffer, "%s\n", info->compile_date);
++ kfree(info);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(compile_date);
++
++static struct attribute *xen_compile_attrs[] = {
++ &compiler_attr.attr,
++ &compiled_by_attr.attr,
++ &compile_date_attr.attr,
++ NULL
++};
++
++static struct attribute_group xen_compilation_group = {
++ .name = "compilation",
++ .attrs = xen_compile_attrs,
++};
++
++int __init static xen_compilation_init(void)
++{
++ return sysfs_create_group(&hypervisor_subsys.kset.kobj,
++ &xen_compilation_group);
++}
++
++static void xen_compilation_destroy(void)
++{
++ sysfs_remove_group(&hypervisor_subsys.kset.kobj,
++ &xen_compilation_group);
++}
++
++/* xen properties info */
++
++static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ char *caps;
++
++ caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
++ if (caps) {
++ ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
++ if (!ret)
++ ret = sprintf(buffer, "%s\n", caps);
++ kfree(caps);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(capabilities);
++
++static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ char *cset;
++
++ cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
++ if (cset) {
++ ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
++ if (!ret)
++ ret = sprintf(buffer, "%s\n", cset);
++ kfree(cset);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(changeset);
++
++static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret = -ENOMEM;
++ struct xen_platform_parameters *parms;
++
++ parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
++ if (parms) {
++ ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
++ parms);
++ if (!ret)
++ ret = sprintf(buffer, "%lx\n", parms->virt_start);
++ kfree(parms);
++ }
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(virtual_start);
++
++static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ int ret;
++
++ ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
++ if (ret > 0)
++ ret = sprintf(buffer, "%x\n", ret);
++
++ return ret;
++}
++
++HYPERVISOR_ATTR_RO(pagesize);
++
++/* eventually there will be several more features to export */
++static ssize_t xen_feature_show(int index, char *buffer)
++{
++ int ret = -ENOMEM;
++ struct xen_feature_info *info;
++
++ info = kmalloc(sizeof(struct xen_feature_info), GFP_KERNEL);
++ if (info) {
++ info->submap_idx = index;
++ ret = HYPERVISOR_xen_version(XENVER_get_features, info);
++ if (!ret)
++ ret = sprintf(buffer, "%d\n", info->submap);
++ kfree(info);
++ }
++
++ return ret;
++}
++
++static ssize_t writable_pt_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++ return xen_feature_show(XENFEAT_writable_page_tables, buffer);
++}
++
++HYPERVISOR_ATTR_RO(writable_pt);
++
++static struct attribute *xen_properties_attrs[] = {
++ &capabilities_attr.attr,
++ &changeset_attr.attr,
++ &virtual_start_attr.attr,
++ &pagesize_attr.attr,
++ &writable_pt_attr.attr,
++ NULL
++};
++
++static struct attribute_group xen_properties_group = {
++ .name = "properties",
++ .attrs = xen_properties_attrs,
++};
++
++static int __init xen_properties_init(void)
++{
++ return sysfs_create_group(&hypervisor_subsys.kset.kobj,
++ &xen_properties_group);
++}
++
++static void xen_properties_destroy(void)
++{
++ sysfs_remove_group(&hypervisor_subsys.kset.kobj,
++ &xen_properties_group);
++}
++
++static int __init hyper_sysfs_init(void)
++{
++ int ret;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ ret = xen_sysfs_type_init();
++ if (ret)
++ goto out;
++ ret = xen_sysfs_version_init();
++ if (ret)
++ goto version_out;
++ ret = xen_compilation_init();
++ if (ret)
++ goto comp_out;
++ ret = xen_sysfs_uuid_init();
++ if (ret)
++ goto uuid_out;
++ ret = xen_properties_init();
++ if (!ret)
++ goto out;
++
++ xen_sysfs_uuid_destroy();
++uuid_out:
++ xen_compilation_destroy();
++comp_out:
++ xen_sysfs_version_destroy();
++version_out:
++ xen_sysfs_type_destroy();
++out:
++ return ret;
++}
++
++static void hyper_sysfs_exit(void)
++{
++ xen_properties_destroy();
++ xen_compilation_destroy();
++ xen_sysfs_uuid_destroy();
++ xen_sysfs_version_destroy();
++ xen_sysfs_type_destroy();
++
++}
++
++module_init(hyper_sysfs_init);
++module_exit(hyper_sysfs_exit);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/evtchn/evtchn.c linux-2.6.18-xen/drivers/xen/evtchn/evtchn.c
+--- linux-2.6.18.1/drivers/xen/evtchn/evtchn.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/evtchn/evtchn.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,456 @@
++/******************************************************************************
++ * evtchn.c
++ *
++ * Driver for receiving and demuxing event-channel signals.
++ *
++ * Copyright (c) 2004-2005, K A Fraser
++ * Multi-process extensions Copyright (c) 2004, Steven 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/miscdevice.h>
++#include <linux/major.h>
++#include <linux/proc_fs.h>
++#include <linux/stat.h>
++#include <linux/poll.h>
++#include <linux/irq.h>
++#include <linux/init.h>
++#include <linux/gfp.h>
++#include <xen/evtchn.h>
++#include <xen/public/evtchn.h>
++
++struct per_user_data {
++ /* Notification ring, accessed via /dev/xen/evtchn. */
++#define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t))
++#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
++ evtchn_port_t *ring;
++ unsigned int ring_cons, ring_prod, ring_overflow;
++
++ /* Processes wait on this queue when ring is empty. */
++ wait_queue_head_t evtchn_wait;
++ struct fasync_struct *evtchn_async_queue;
++};
++
++/* Who's bound to each port? */
++static struct per_user_data *port_user[NR_EVENT_CHANNELS];
++static spinlock_t port_user_lock;
++
++void evtchn_device_upcall(int port)
++{
++ struct per_user_data *u;
++
++ spin_lock(&port_user_lock);
++
++ mask_evtchn(port);
++ clear_evtchn(port);
++
++ if ((u = port_user[port]) != NULL) {
++ if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
++ u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
++ if (u->ring_cons == u->ring_prod++) {
++ wake_up_interruptible(&u->evtchn_wait);
++ kill_fasync(&u->evtchn_async_queue,
++ SIGIO, POLL_IN);
++ }
++ } else {
++ u->ring_overflow = 1;
++ }
++ }
++
++ spin_unlock(&port_user_lock);
++}
++
++static ssize_t evtchn_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ int rc;
++ unsigned int c, p, bytes1 = 0, bytes2 = 0;
++ struct per_user_data *u = file->private_data;
++
++ /* Whole number of ports. */
++ count &= ~(sizeof(evtchn_port_t)-1);
++
++ if (count == 0)
++ return 0;
++
++ if (count > PAGE_SIZE)
++ count = PAGE_SIZE;
++
++ for (;;) {
++ if (u->ring_overflow)
++ return -EFBIG;
++
++ if ((c = u->ring_cons) != (p = u->ring_prod))
++ break;
++
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++
++ rc = wait_event_interruptible(
++ u->evtchn_wait, u->ring_cons != u->ring_prod);
++ if (rc)
++ return rc;
++ }
++
++ /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
++ if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
++ bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
++ sizeof(evtchn_port_t);
++ bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
++ } else {
++ bytes1 = (p - c) * sizeof(evtchn_port_t);
++ bytes2 = 0;
++ }
++
++ /* Truncate chunks according to caller's maximum byte count. */
++ if (bytes1 > count) {
++ bytes1 = count;
++ bytes2 = 0;
++ } else if ((bytes1 + bytes2) > count) {
++ bytes2 = count - bytes1;
++ }
++
++ if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
++ ((bytes2 != 0) &&
++ copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
++ return -EFAULT;
++
++ u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
++
++ return bytes1 + bytes2;
++}
++
++static ssize_t evtchn_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ int rc, i;
++ evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
++ struct per_user_data *u = file->private_data;
++
++ if (kbuf == NULL)
++ return -ENOMEM;
++
++ /* Whole number of ports. */
++ count &= ~(sizeof(evtchn_port_t)-1);
++
++ if (count == 0) {
++ rc = 0;
++ goto out;
++ }
++
++ if (count > PAGE_SIZE)
++ count = PAGE_SIZE;
++
++ if (copy_from_user(kbuf, buf, count) != 0) {
++ rc = -EFAULT;
++ goto out;
++ }
++
++ spin_lock_irq(&port_user_lock);
++ for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
++ if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
++ unmask_evtchn(kbuf[i]);
++ spin_unlock_irq(&port_user_lock);
++
++ rc = count;
++
++ out:
++ free_page((unsigned long)kbuf);
++ return rc;
++}
++
++static void evtchn_bind_to_user(struct per_user_data *u, int port)
++{
++ spin_lock_irq(&port_user_lock);
++ BUG_ON(port_user[port] != NULL);
++ port_user[port] = u;
++ unmask_evtchn(port);
++ spin_unlock_irq(&port_user_lock);
++}
++
++static int evtchn_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int rc;
++ struct per_user_data *u = file->private_data;
++ void __user *uarg = (void __user *) arg;
++
++ switch (cmd) {
++ case IOCTL_EVTCHN_BIND_VIRQ: {
++ struct ioctl_evtchn_bind_virq bind;
++ struct evtchn_bind_virq bind_virq;
++
++ rc = -EFAULT;
++ if (copy_from_user(&bind, uarg, sizeof(bind)))
++ break;
++
++ bind_virq.virq = bind.virq;
++ bind_virq.vcpu = 0;
++ rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
++ &bind_virq);
++ if (rc != 0)
++ break;
++
++ rc = bind_virq.port;
++ evtchn_bind_to_user(u, rc);
++ break;
++ }
++
++ case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
++ struct ioctl_evtchn_bind_interdomain bind;
++ struct evtchn_bind_interdomain bind_interdomain;
++
++ rc = -EFAULT;
++ if (copy_from_user(&bind, uarg, sizeof(bind)))
++ break;
++
++ bind_interdomain.remote_dom = bind.remote_domain;
++ bind_interdomain.remote_port = bind.remote_port;
++ rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++ if (rc != 0)
++ break;
++
++ rc = bind_interdomain.local_port;
++ evtchn_bind_to_user(u, rc);
++ break;
++ }
++
++ case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
++ struct ioctl_evtchn_bind_unbound_port bind;
++ struct evtchn_alloc_unbound alloc_unbound;
++
++ rc = -EFAULT;
++ if (copy_from_user(&bind, uarg, sizeof(bind)))
++ break;
++
++ alloc_unbound.dom = DOMID_SELF;
++ alloc_unbound.remote_dom = bind.remote_domain;
++ rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
++ &alloc_unbound);
++ if (rc != 0)
++ break;
++
++ rc = alloc_unbound.port;
++ evtchn_bind_to_user(u, rc);
++ break;
++ }
++
++ case IOCTL_EVTCHN_UNBIND: {
++ struct ioctl_evtchn_unbind unbind;
++ struct evtchn_close close;
++ int ret;
++
++ rc = -EFAULT;
++ if (copy_from_user(&unbind, uarg, sizeof(unbind)))
++ break;
++
++ rc = -EINVAL;
++ if (unbind.port >= NR_EVENT_CHANNELS)
++ break;
++
++ spin_lock_irq(&port_user_lock);
++
++ rc = -ENOTCONN;
++ if (port_user[unbind.port] != u) {
++ spin_unlock_irq(&port_user_lock);
++ break;
++ }
++
++ port_user[unbind.port] = NULL;
++ mask_evtchn(unbind.port);
++
++ spin_unlock_irq(&port_user_lock);
++
++ close.port = unbind.port;
++ ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
++ BUG_ON(ret);
++
++ rc = 0;
++ break;
++ }
++
++ case IOCTL_EVTCHN_NOTIFY: {
++ struct ioctl_evtchn_notify notify;
++
++ rc = -EFAULT;
++ if (copy_from_user(¬ify, uarg, sizeof(notify)))
++ break;
++
++ if (notify.port >= NR_EVENT_CHANNELS) {
++ rc = -EINVAL;
++ } else if (port_user[notify.port] != u) {
++ rc = -ENOTCONN;
++ } else {
++ notify_remote_via_evtchn(notify.port);
++ rc = 0;
++ }
++ break;
++ }
++
++ case IOCTL_EVTCHN_RESET: {
++ /* Initialise the ring to empty. Clear errors. */
++ spin_lock_irq(&port_user_lock);
++ u->ring_cons = u->ring_prod = u->ring_overflow = 0;
++ spin_unlock_irq(&port_user_lock);
++ rc = 0;
++ break;
++ }
++
++ default:
++ rc = -ENOSYS;
++ break;
++ }
++
++ return rc;
++}
++
++static unsigned int evtchn_poll(struct file *file, poll_table *wait)
++{
++ unsigned int mask = POLLOUT | POLLWRNORM;
++ struct per_user_data *u = file->private_data;
++
++ poll_wait(file, &u->evtchn_wait, wait);
++ if (u->ring_cons != u->ring_prod)
++ mask |= POLLIN | POLLRDNORM;
++ if (u->ring_overflow)
++ mask = POLLERR;
++ return mask;
++}
++
++static int evtchn_fasync(int fd, struct file *filp, int on)
++{
++ struct per_user_data *u = filp->private_data;
++ return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
++}
++
++static int evtchn_open(struct inode *inode, struct file *filp)
++{
++ struct per_user_data *u;
++
++ if ((u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL)
++ return -ENOMEM;
++
++ memset(u, 0, sizeof(*u));
++ init_waitqueue_head(&u->evtchn_wait);
++
++ u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
++ if (u->ring == NULL) {
++ kfree(u);
++ return -ENOMEM;
++ }
++
++ filp->private_data = u;
++
++ return 0;
++}
++
++static int evtchn_release(struct inode *inode, struct file *filp)
++{
++ int i;
++ struct per_user_data *u = filp->private_data;
++ struct evtchn_close close;
++
++ spin_lock_irq(&port_user_lock);
++
++ free_page((unsigned long)u->ring);
++
++ for (i = 0; i < NR_EVENT_CHANNELS; i++) {
++ int ret;
++ if (port_user[i] != u)
++ continue;
++
++ port_user[i] = NULL;
++ mask_evtchn(i);
++
++ close.port = i;
++ ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
++ BUG_ON(ret);
++ }
++
++ spin_unlock_irq(&port_user_lock);
++
++ kfree(u);
++
++ return 0;
++}
++
++static struct file_operations evtchn_fops = {
++ .owner = THIS_MODULE,
++ .read = evtchn_read,
++ .write = evtchn_write,
++ .ioctl = evtchn_ioctl,
++ .poll = evtchn_poll,
++ .fasync = evtchn_fasync,
++ .open = evtchn_open,
++ .release = evtchn_release,
++};
++
++static struct miscdevice evtchn_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "evtchn",
++ .fops = &evtchn_fops,
++};
++
++static int __init evtchn_init(void)
++{
++ int err;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ spin_lock_init(&port_user_lock);
++ memset(port_user, 0, sizeof(port_user));
++
++ /* Create '/dev/misc/evtchn'. */
++ err = misc_register(&evtchn_miscdev);
++ if (err != 0) {
++ printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
++ return err;
++ }
++
++ printk("Event-channel device installed.\n");
++
++ return 0;
++}
++
++static void evtchn_cleanup(void)
++{
++ misc_deregister(&evtchn_miscdev);
++}
++
++module_init(evtchn_init);
++module_exit(evtchn_cleanup);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/evtchn/Makefile linux-2.6.18-xen/drivers/xen/evtchn/Makefile
+--- linux-2.6.18.1/drivers/xen/evtchn/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/evtchn/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,2 @@
++
++obj-y := evtchn.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/Kconfig linux-2.6.18-xen/drivers/xen/Kconfig
+--- linux-2.6.18.1/drivers/xen/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/Kconfig 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,260 @@
++#
++# This Kconfig describe xen options
++#
++
++mainmenu "Xen Configuration"
++
++config XEN
++ bool
++ default y if X86_XEN || X86_64_XEN
++ help
++ This is the Linux Xen port.
++
++if XEN
++config XEN_INTERFACE_VERSION
++ hex
++ default 0x00030203
++
++menu "XEN"
++
++config XEN_PRIVILEGED_GUEST
++ bool "Privileged Guest (domain 0)"
++ depends XEN
++ default n
++ help
++ Support for privileged operation (domain 0)
++
++config XEN_UNPRIVILEGED_GUEST
++ bool
++ default !XEN_PRIVILEGED_GUEST
++
++config XEN_PRIVCMD
++ bool
++ depends on PROC_FS
++ default y
++
++config XEN_XENBUS_DEV
++ bool
++ depends on PROC_FS
++ default y
++
++config XEN_BACKEND
++ tristate "Backend driver support"
++ default y
++ help
++ Support for backend device drivers that provide I/O services
++ to other virtual machines.
++
++config XEN_BLKDEV_BACKEND
++ tristate "Block-device backend driver"
++ depends on XEN_BACKEND
++ default y
++ help
++ The block-device backend driver allows the kernel to export its
++ block devices to other guests via a high-performance shared-memory
++ interface.
++
++config XEN_BLKDEV_TAP
++ tristate "Block-device tap backend driver"
++ depends on XEN_BACKEND
++ default XEN_PRIVILEGED_GUEST
++ help
++ The block tap driver is an alternative to the block back driver
++ and allows VM block requests to be redirected to userspace through
++ a device interface. The tap allows user-space development of
++ high-performance block backends, where disk images may be implemented
++ as files, in memory, or on other hosts across the network. This
++ driver can safely coexist with the existing blockback driver.
++
++config XEN_NETDEV_BACKEND
++ tristate "Network-device backend driver"
++ depends on XEN_BACKEND && NET
++ default y
++ help
++ The network-device backend driver allows the kernel to export its
++ network devices to other guests via a high-performance shared-memory
++ interface.
++
++config XEN_NETDEV_PIPELINED_TRANSMITTER
++ bool "Pipelined transmitter (DANGEROUS)"
++ depends on XEN_NETDEV_BACKEND
++ default n
++ help
++ If the net backend is a dumb domain, such as a transparent Ethernet
++ bridge with no local IP interface, it is safe to say Y here to get
++ slightly lower network overhead.
++ If the backend has a local IP interface; or may be doing smart things
++ like reassembling packets to perform firewall filtering; or if you
++ are unsure; or if you experience network hangs when this option is
++ enabled; then you must say N here.
++
++config XEN_NETDEV_LOOPBACK
++ tristate "Network-device loopback driver"
++ depends on XEN_NETDEV_BACKEND
++ default y
++ help
++ A two-interface loopback device to emulate a local netfront-netback
++ connection.
++
++config XEN_PCIDEV_BACKEND
++ tristate "PCI-device backend driver"
++ depends on PCI && XEN_BACKEND
++ default XEN_PRIVILEGED_GUEST
++ help
++ The PCI device backend driver allows the kernel to export arbitrary
++ PCI devices to other guests. If you select this to be a module, you
++ will need to make sure no other driver has bound to the device(s)
++ you want to make visible to other guests.
++
++choice
++ prompt "PCI Backend Mode"
++ depends on XEN_PCIDEV_BACKEND
++ default XEN_PCIDEV_BACKEND_VPCI
++
++config XEN_PCIDEV_BACKEND_VPCI
++ bool "Virtual PCI"
++ ---help---
++ This PCI Backend hides the true PCI topology and makes the frontend
++ think there is a single PCI bus with only the exported devices on it.
++ For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
++ second device at 02:1a.1 will be re-assigned to 00:01.1.
++
++config XEN_PCIDEV_BACKEND_PASS
++ bool "Passthrough"
++ ---help---
++ This PCI Backend provides a real view of the PCI topology to the
++ frontend (for example, a device at 06:01.b will still appear at
++ 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
++ PCI devices to its driver domains. This may be required for drivers
++ which depend on finding their hardward in certain bus/slot
++ locations.
++
++config XEN_PCIDEV_BACKEND_SLOT
++ bool "Slot"
++ ---help---
++ This PCI Backend hides the true PCI topology and makes the frontend
++ think there is a single PCI bus with only the exported devices on it.
++ Contrary to the virtual PCI backend, a function becomes a new slot.
++ For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
++ second device at 02:1a.1 will be re-assigned to 00:01.0.
++
++endchoice
++
++config XEN_PCIDEV_BE_DEBUG
++ bool "PCI Backend Debugging"
++ depends on XEN_PCIDEV_BACKEND
++ default n
++
++config XEN_TPMDEV_BACKEND
++ tristate "TPM-device backend driver"
++ depends on XEN_BACKEND
++ default n
++ help
++ The TPM-device backend driver
++
++config XEN_BLKDEV_FRONTEND
++ tristate "Block-device frontend driver"
++ depends on XEN
++ default y
++ help
++ The block-device frontend driver allows the kernel to access block
++ devices mounted within another guest OS. Unless you are building a
++ dedicated device-driver domain, or your master control domain
++ (domain 0), then you almost certainly want to say Y here.
++
++config XEN_NETDEV_FRONTEND
++ tristate "Network-device frontend driver"
++ depends on XEN && NET
++ default y
++ help
++ The network-device frontend driver allows the kernel to access
++ network interfaces within another guest OS. Unless you are building a
++ dedicated device-driver domain, or your master control domain
++ (domain 0), then you almost certainly want to say Y here.
++
++config XEN_SCRUB_PAGES
++ bool "Scrub memory before freeing it to Xen"
++ default y
++ help
++ Erase memory contents before freeing it back to Xen's global
++ pool. This ensures that any secrets contained within that
++ memory (e.g., private keys) cannot be found by other guests that
++ may be running on the machine. Most people will want to say Y here.
++ If security is not a concern then you may increase performance by
++ saying N.
++
++config XEN_DISABLE_SERIAL
++ bool "Disable serial port drivers"
++ default y
++ help
++ Disable serial port drivers, allowing the Xen console driver
++ to provide a serial console at ttyS0.
++
++config XEN_SYSFS
++ tristate "Export Xen attributes in sysfs"
++ depends on SYSFS
++ default y
++ help
++ Xen hypervisor attributes will show up under /sys/hypervisor/.
++
++choice
++ prompt "Xen version compatibility"
++ default XEN_COMPAT_030002_AND_LATER
++
++ config XEN_COMPAT_030002_AND_LATER
++ bool "3.0.2 and later"
++
++ config XEN_COMPAT_LATEST_ONLY
++ bool "no compatibility code"
++
++endchoice
++
++config XEN_COMPAT_030002
++ bool
++ default XEN_COMPAT_030002_AND_LATER
++
++endmenu
++
++config HAVE_ARCH_ALLOC_SKB
++ bool
++ default y
++
++config HAVE_ARCH_DEV_ALLOC_SKB
++ bool
++ default y
++
++config HAVE_IRQ_IGNORE_UNHANDLED
++ bool
++ default y
++
++config NO_IDLE_HZ
++ bool
++ default y
++
++config XEN_UTIL
++ bool
++ default y
++
++config XEN_BALLOON
++ bool
++ default y
++
++config XEN_DEVMEM
++ bool
++ default y
++
++config XEN_SKBUFF
++ bool
++ default y
++ depends on NET
++
++config XEN_REBOOT
++ bool
++ default y
++
++config XEN_SMPBOOT
++ bool
++ default y
++ depends on SMP
++
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/Makefile linux-2.6.18-xen/drivers/xen/Makefile
+--- linux-2.6.18.1/drivers/xen/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,17 @@
++obj-y += core/
++obj-y += console/
++obj-y += evtchn/
++obj-y += privcmd/
++obj-y += xenbus/
++
++obj-$(CONFIG_XEN_UTIL) += util.o
++obj-$(CONFIG_XEN_BALLOON) += balloon/
++obj-$(CONFIG_XEN_DEVMEM) += char/
++obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
++obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
++obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
++obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/
++obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
++obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/
++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netback/common.h linux-2.6.18-xen/drivers/xen/netback/common.h
+--- linux-2.6.18.1/drivers/xen/netback/common.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netback/common.h 2006-10-19 11:01:25.000000000 +0200
+@@ -0,0 +1,141 @@
++/******************************************************************************
++ * arch/xen/drivers/netif/backend/common.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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __NETIF__BACKEND__COMMON_H__
++#define __NETIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/wait.h>
++#include <xen/evtchn.h>
++#include <xen/interface/io/netif.h>
++#include <asm/io.h>
++#include <asm/pgalloc.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++#include <asm/hypercall.h>
++
++#define DPRINTK(_f, _a...) \
++ pr_debug("(file=%s, line=%d) " _f, \
++ __FILE__ , __LINE__ , ## _a )
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "xen_net: " fmt, ##args)
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "xen_net: " fmt, ##args)
++
++typedef struct netif_st {
++ /* Unique identifier for this interface. */
++ domid_t domid;
++ unsigned int handle;
++
++ u8 fe_dev_addr[6];
++
++ /* Physical parameters of the comms window. */
++ grant_handle_t tx_shmem_handle;
++ grant_ref_t tx_shmem_ref;
++ grant_handle_t rx_shmem_handle;
++ grant_ref_t rx_shmem_ref;
++ unsigned int evtchn;
++ unsigned int irq;
++
++ /* The shared rings and indexes. */
++ netif_tx_back_ring_t tx;
++ netif_rx_back_ring_t rx;
++ struct vm_struct *tx_comms_area;
++ struct vm_struct *rx_comms_area;
++
++ /* Set of features that can be turned on in dev->features. */
++ int features;
++
++ /* Internal feature information. */
++ int can_queue:1; /* can queue packets for receiver? */
++ int copying_receiver:1; /* copy packets to receiver? */
++
++ /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
++ RING_IDX rx_req_cons_peek;
++
++ /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
++ unsigned long credit_bytes;
++ unsigned long credit_usec;
++ unsigned long remaining_credit;
++ struct timer_list credit_timeout;
++
++ /* Miscellaneous private stuff. */
++ struct list_head list; /* scheduling list */
++ atomic_t refcnt;
++ struct net_device *dev;
++ struct net_device_stats stats;
++
++ wait_queue_head_t waiting_to_free;
++} netif_t;
++
++#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
++
++void netif_disconnect(netif_t *netif);
++
++netif_t *netif_alloc(domid_t domid, unsigned int handle);
++int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn);
++
++#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define netif_put(_b) \
++ do { \
++ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
++ wake_up(&(_b)->waiting_to_free); \
++ } while (0)
++
++void netif_xenbus_init(void);
++
++void netif_schedule_work(netif_t *netif);
++void netif_deschedule_work(netif_t *netif);
++
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
++struct net_device_stats *netif_be_get_stats(struct net_device *dev);
++irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++
++static inline int netbk_can_queue(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ return netif->can_queue;
++}
++
++static inline int netbk_can_sg(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ return netif->features & NETIF_F_SG;
++}
++
++#endif /* __NETIF__BACKEND__COMMON_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netback/interface.c linux-2.6.18-xen/drivers/xen/netback/interface.c
+--- linux-2.6.18.1/drivers/xen/netback/interface.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netback/interface.c 2006-10-19 11:01:25.000000000 +0200
+@@ -0,0 +1,352 @@
++/******************************************************************************
++ * arch/xen/drivers/netif/backend/interface.c
++ *
++ * Network-device interface management.
++ *
++ * Copyright (c) 2004-2005, Keir Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include "common.h"
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
++
++/*
++ * Module parameter 'queue_length':
++ *
++ * Enables queuing in the network stack when a client has run out of receive
++ * descriptors. Although this feature can improve receive bandwidth by avoiding
++ * packet loss, it can also result in packets sitting in the 'tx_queue' for
++ * unbounded time. This is bad if those packets hold onto foreign resources.
++ * For example, consider a packet that holds onto resources belonging to the
++ * guest for which it is queued (e.g., packet received on vif1.0, destined for
++ * vif1.1 which is not activated in the guest): in this situation the guest
++ * will never be destroyed, unless vif1.1 is taken down (which flushes the
++ * 'tx_queue').
++ *
++ * Only set this parameter to non-zero value if you know what you are doing!
++ */
++static unsigned long netbk_queue_length = 0;
++module_param_named(queue_length, netbk_queue_length, ulong, 0);
++
++static void __netif_up(netif_t *netif)
++{
++ enable_irq(netif->irq);
++ netif_schedule_work(netif);
++}
++
++static void __netif_down(netif_t *netif)
++{
++ disable_irq(netif->irq);
++ netif_deschedule_work(netif);
++ del_timer_sync(&netif->credit_timeout);
++}
++
++static int net_open(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ if (netif_carrier_ok(dev))
++ __netif_up(netif);
++ return 0;
++}
++
++static int net_close(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ if (netif_carrier_ok(dev))
++ __netif_down(netif);
++ return 0;
++}
++
++static int netbk_change_mtu(struct net_device *dev, int mtu)
++{
++ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++
++ if (mtu > max)
++ return -EINVAL;
++ dev->mtu = mtu;
++ return 0;
++}
++
++static int netbk_set_sg(struct net_device *dev, u32 data)
++{
++ if (data) {
++ netif_t *netif = netdev_priv(dev);
++
++ if (!(netif->features & NETIF_F_SG))
++ return -ENOSYS;
++ }
++
++ return ethtool_op_set_sg(dev, data);
++}
++
++static int netbk_set_tso(struct net_device *dev, u32 data)
++{
++ if (data) {
++ netif_t *netif = netdev_priv(dev);
++
++ if (!(netif->features & NETIF_F_TSO))
++ return -ENOSYS;
++ }
++
++ return ethtool_op_set_tso(dev, data);
++}
++
++static struct ethtool_ops network_ethtool_ops =
++{
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = ethtool_op_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = netbk_set_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = netbk_set_tso,
++ .get_link = ethtool_op_get_link,
++};
++
++netif_t *netif_alloc(domid_t domid, unsigned int handle)
++{
++ int err = 0, i;
++ struct net_device *dev;
++ netif_t *netif;
++ char name[IFNAMSIZ] = {};
++
++ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
++ dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
++ if (dev == NULL) {
++ DPRINTK("Could not create netif: out of memory\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ netif_carrier_off(dev);
++
++ netif = netdev_priv(dev);
++ memset(netif, 0, sizeof(*netif));
++ netif->domid = domid;
++ netif->handle = handle;
++ atomic_set(&netif->refcnt, 1);
++ init_waitqueue_head(&netif->waiting_to_free);
++ netif->dev = dev;
++
++ netif->credit_bytes = netif->remaining_credit = ~0UL;
++ netif->credit_usec = 0UL;
++ init_timer(&netif->credit_timeout);
++ netif->credit_timeout.expires = jiffies;
++
++ dev->hard_start_xmit = netif_be_start_xmit;
++ dev->get_stats = netif_be_get_stats;
++ dev->open = net_open;
++ dev->stop = net_close;
++ dev->change_mtu = netbk_change_mtu;
++ dev->features = NETIF_F_IP_CSUM;
++
++ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
++
++ dev->tx_queue_len = netbk_queue_length;
++ if (dev->tx_queue_len != 0)
++ printk(KERN_WARNING "netbk: WARNING: device '%s' has non-zero "
++ "queue length (%lu)!\n", dev->name, dev->tx_queue_len);
++
++ /*
++ * Initialise a dummy MAC address. We choose the numerically
++ * largest non-broadcast address to prevent the address getting
++ * stolen by an Ethernet bridge for STP purposes.
++ * (FE:FF:FF:FF:FF:FF)
++ */
++ memset(dev->dev_addr, 0xFF, ETH_ALEN);
++ dev->dev_addr[0] &= ~0x01;
++
++ rtnl_lock();
++ err = register_netdevice(dev);
++ rtnl_unlock();
++ if (err) {
++ DPRINTK("Could not register new net device %s: err=%d\n",
++ dev->name, err);
++ free_netdev(dev);
++ return ERR_PTR(err);
++ }
++
++ DPRINTK("Successfully created netif\n");
++ return netif;
++}
++
++static int map_frontend_pages(
++ netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
++{
++ struct gnttab_map_grant_ref op;
++ int ret;
++
++ gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, tx_ring_ref, netif->domid);
++
++ lock_vm_area(netif->tx_comms_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
++ unlock_vm_area(netif->tx_comms_area);
++ BUG_ON(ret);
++
++ if (op.status) {
++ DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
++ return op.status;
++ }
++
++ netif->tx_shmem_ref = tx_ring_ref;
++ netif->tx_shmem_handle = op.handle;
++
++ gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
++ GNTMAP_host_map, rx_ring_ref, netif->domid);
++
++ lock_vm_area(netif->rx_comms_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
++ unlock_vm_area(netif->rx_comms_area);
++ BUG_ON(ret);
++
++ if (op.status) {
++ DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
++ return op.status;
++ }
++
++ netif->rx_shmem_ref = rx_ring_ref;
++ netif->rx_shmem_handle = op.handle;
++
++ return 0;
++}
++
++static void unmap_frontend_pages(netif_t *netif)
++{
++ struct gnttab_unmap_grant_ref op;
++ int ret;
++
++ gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, netif->tx_shmem_handle);
++
++ lock_vm_area(netif->tx_comms_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
++ unlock_vm_area(netif->tx_comms_area);
++ BUG_ON(ret);
++
++ gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
++ GNTMAP_host_map, netif->rx_shmem_handle);
++
++ lock_vm_area(netif->rx_comms_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
++ unlock_vm_area(netif->rx_comms_area);
++ BUG_ON(ret);
++}
++
++int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn)
++{
++ int err = -ENOMEM;
++ netif_tx_sring_t *txs;
++ netif_rx_sring_t *rxs;
++ struct evtchn_bind_interdomain bind_interdomain;
++
++ /* Already connected through? */
++ if (netif->irq)
++ return 0;
++
++ netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (netif->tx_comms_area == NULL)
++ return -ENOMEM;
++ netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (netif->rx_comms_area == NULL)
++ goto err_rx;
++
++ err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
++ if (err)
++ goto err_map;
++
++ bind_interdomain.remote_dom = netif->domid;
++ bind_interdomain.remote_port = evtchn;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++ if (err)
++ goto err_hypervisor;
++
++ netif->evtchn = bind_interdomain.local_port;
++
++ netif->irq = bind_evtchn_to_irqhandler(
++ netif->evtchn, netif_be_int, 0, netif->dev->name, netif);
++ disable_irq(netif->irq);
++
++ txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
++ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
++
++ rxs = (netif_rx_sring_t *)
++ ((char *)netif->rx_comms_area->addr);
++ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
++
++ netif->rx_req_cons_peek = 0;
++
++ netif_get(netif);
++
++ rtnl_lock();
++ netif_carrier_on(netif->dev);
++ if (netif_running(netif->dev))
++ __netif_up(netif);
++ rtnl_unlock();
++
++ return 0;
++err_hypervisor:
++ unmap_frontend_pages(netif);
++err_map:
++ free_vm_area(netif->rx_comms_area);
++err_rx:
++ free_vm_area(netif->tx_comms_area);
++ return err;
++}
++
++static void netif_free(netif_t *netif)
++{
++ atomic_dec(&netif->refcnt);
++ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
++
++ if (netif->irq)
++ unbind_from_irqhandler(netif->irq, netif);
++
++ unregister_netdev(netif->dev);
++
++ if (netif->tx.sring) {
++ unmap_frontend_pages(netif);
++ free_vm_area(netif->tx_comms_area);
++ free_vm_area(netif->rx_comms_area);
++ }
++
++ free_netdev(netif->dev);
++}
++
++void netif_disconnect(netif_t *netif)
++{
++ if (netif_carrier_ok(netif->dev)) {
++ rtnl_lock();
++ netif_carrier_off(netif->dev);
++ if (netif_running(netif->dev))
++ __netif_down(netif);
++ rtnl_unlock();
++ netif_put(netif);
++ }
++ netif_free(netif);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netback/loopback.c linux-2.6.18-xen/drivers/xen/netback/loopback.c
+--- linux-2.6.18.1/drivers/xen/netback/loopback.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netback/loopback.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,320 @@
++/******************************************************************************
++ * netback/loopback.c
++ *
++ * A two-interface loopback device to emulate a local netfront-netback
++ * connection. This ensures that local packet delivery looks identical
++ * to inter-domain delivery. Most importantly, packets delivered locally
++ * originating from other domains will get *copied* when they traverse this
++ * driver. This prevents unbounded delays in socket-buffer queues from
++ * causing the netback driver to "seize up".
++ *
++ * This driver creates a symmetric pair of loopback interfaces with names
++ * vif0.0 and veth0. The intention is that 'vif0.0' is bound to an Ethernet
++ * bridge, just like a proper netback interface, while a local IP interface
++ * is configured on 'veth0'.
++ *
++ * As with a real netback interface, vif0.0 is configured with a suitable
++ * dummy MAC address. No default is provided for veth0: a reasonable strategy
++ * is to transfer eth0's MAC address to veth0, and give eth0 a dummy address
++ * (to avoid confusing the Etherbridge).
++ *
++ * Copyright (c) 2005 K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/ethtool.h>
++#include <net/dst.h>
++#include <net/xfrm.h> /* secpath_reset() */
++#include <asm/hypervisor.h> /* is_initial_xendomain() */
++
++static int nloopbacks = -1;
++module_param(nloopbacks, int, 0);
++MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create");
++
++struct net_private {
++ struct net_device *loopback_dev;
++ struct net_device_stats stats;
++};
++
++static int loopback_open(struct net_device *dev)
++{
++ struct net_private *np = netdev_priv(dev);
++ memset(&np->stats, 0, sizeof(np->stats));
++ netif_start_queue(dev);
++ return 0;
++}
++
++static int loopback_close(struct net_device *dev)
++{
++ netif_stop_queue(dev);
++ return 0;
++}
++
++#ifdef CONFIG_X86
++static int is_foreign(unsigned long pfn)
++{
++ /* NB. Play it safe for auto-translation mode. */
++ return (xen_feature(XENFEAT_auto_translated_physmap) ||
++ (phys_to_machine_mapping[pfn] & FOREIGN_FRAME_BIT));
++}
++#else
++/* How to detect a foreign mapping? Play it safe. */
++#define is_foreign(pfn) (1)
++#endif
++
++static int skb_remove_foreign_references(struct sk_buff *skb)
++{
++ struct page *page;
++ unsigned long pfn;
++ int i, off;
++ char *vaddr;
++
++ BUG_ON(skb_shinfo(skb)->frag_list);
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++ pfn = page_to_pfn(skb_shinfo(skb)->frags[i].page);
++ if (!is_foreign(pfn))
++ continue;
++
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(!page))
++ return 0;
++
++ vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
++ off = skb_shinfo(skb)->frags[i].page_offset;
++ memcpy(page_address(page) + off,
++ vaddr + off,
++ skb_shinfo(skb)->frags[i].size);
++ kunmap_skb_frag(vaddr);
++
++ put_page(skb_shinfo(skb)->frags[i].page);
++ skb_shinfo(skb)->frags[i].page = page;
++ }
++
++ return 1;
++}
++
++static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct net_private *np = netdev_priv(dev);
++
++ if (!skb_remove_foreign_references(skb)) {
++ np->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 0;
++ }
++
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ skb_orphan(skb);
++
++ np->stats.tx_bytes += skb->len;
++ np->stats.tx_packets++;
++
++ /* Switch to loopback context. */
++ dev = np->loopback_dev;
++ np = netdev_priv(dev);
++
++ np->stats.rx_bytes += skb->len;
++ np->stats.rx_packets++;
++
++ if (skb->ip_summed == CHECKSUM_HW) {
++ /* Defer checksum calculation. */
++ skb->proto_csum_blank = 1;
++ /* Must be a local packet: assert its integrity. */
++ skb->proto_data_valid = 1;
++ }
++
++ skb->ip_summed = skb->proto_data_valid ?
++ CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
++
++ skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
++ skb->protocol = eth_type_trans(skb, dev);
++ skb->dev = dev;
++ dev->last_rx = jiffies;
++
++ /* Flush netfilter context: rx'ed skbuffs not expected to have any. */
++ nf_reset(skb);
++ secpath_reset(skb);
++
++ netif_rx(skb);
++
++ return 0;
++}
++
++static struct net_device_stats *loopback_get_stats(struct net_device *dev)
++{
++ struct net_private *np = netdev_priv(dev);
++ return &np->stats;
++}
++
++static struct ethtool_ops network_ethtool_ops =
++{
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = ethtool_op_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = ethtool_op_set_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = ethtool_op_set_tso,
++ .get_link = ethtool_op_get_link,
++};
++
++/*
++ * Nothing to do here. Virtual interface is point-to-point and the
++ * physical interface is probably promiscuous anyway.
++ */
++static void loopback_set_multicast_list(struct net_device *dev)
++{
++}
++
++static void loopback_construct(struct net_device *dev, struct net_device *lo)
++{
++ struct net_private *np = netdev_priv(dev);
++
++ np->loopback_dev = lo;
++
++ dev->open = loopback_open;
++ dev->stop = loopback_close;
++ dev->hard_start_xmit = loopback_start_xmit;
++ dev->get_stats = loopback_get_stats;
++ dev->set_multicast_list = loopback_set_multicast_list;
++ dev->change_mtu = NULL; /* allow arbitrary mtu */
++
++ dev->tx_queue_len = 0;
++
++ dev->features = (NETIF_F_HIGHDMA |
++ NETIF_F_LLTX |
++ NETIF_F_TSO |
++ NETIF_F_SG |
++ NETIF_F_IP_CSUM);
++
++ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
++
++ /*
++ * We do not set a jumbo MTU on the interface. Otherwise the network
++ * stack will try to send large packets that will get dropped by the
++ * Ethernet bridge (unless the physical Ethernet interface is
++ * configured to transfer jumbo packets). If a larger MTU is desired
++ * then the system administrator can specify it using the 'ifconfig'
++ * command.
++ */
++ /*dev->mtu = 16*1024;*/
++}
++
++static int __init make_loopback(int i)
++{
++ struct net_device *dev1, *dev2;
++ char dev_name[IFNAMSIZ];
++ int err = -ENOMEM;
++
++ sprintf(dev_name, "vif0.%d", i);
++ dev1 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
++ if (!dev1)
++ return err;
++
++ sprintf(dev_name, "veth%d", i);
++ dev2 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
++ if (!dev2)
++ goto fail_netdev2;
++
++ loopback_construct(dev1, dev2);
++ loopback_construct(dev2, dev1);
++
++ /*
++ * Initialise a dummy MAC address for the 'dummy backend' interface. We
++ * choose the numerically largest non-broadcast address to prevent the
++ * address getting stolen by an Ethernet bridge for STP purposes.
++ */
++ memset(dev1->dev_addr, 0xFF, ETH_ALEN);
++ dev1->dev_addr[0] &= ~0x01;
++
++ if ((err = register_netdev(dev1)) != 0)
++ goto fail;
++
++ if ((err = register_netdev(dev2)) != 0) {
++ unregister_netdev(dev1);
++ goto fail;
++ }
++
++ return 0;
++
++ fail:
++ free_netdev(dev2);
++ fail_netdev2:
++ free_netdev(dev1);
++ return err;
++}
++
++static void __exit clean_loopback(int i)
++{
++ struct net_device *dev1, *dev2;
++ char dev_name[IFNAMSIZ];
++
++ sprintf(dev_name, "vif0.%d", i);
++ dev1 = dev_get_by_name(dev_name);
++ sprintf(dev_name, "veth%d", i);
++ dev2 = dev_get_by_name(dev_name);
++ if (dev1 && dev2) {
++ unregister_netdev(dev2);
++ unregister_netdev(dev1);
++ free_netdev(dev2);
++ free_netdev(dev1);
++ }
++}
++
++static int __init loopback_init(void)
++{
++ int i, err = 0;
++
++ if (nloopbacks == -1)
++ nloopbacks = is_initial_xendomain() ? 4 : 0;
++
++ for (i = 0; i < nloopbacks; i++)
++ if ((err = make_loopback(i)) != 0)
++ break;
++
++ return err;
++}
++
++module_init(loopback_init);
++
++static void __exit loopback_exit(void)
++{
++ int i;
++
++ for (i = nloopbacks; i-- > 0; )
++ clean_loopback(i);
++}
++
++module_exit(loopback_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netback/Makefile linux-2.6.18-xen/drivers/xen/netback/Makefile
+--- linux-2.6.18.1/drivers/xen/netback/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netback/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,5 @@
++obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
++obj-$(CONFIG_XEN_NETDEV_LOOPBACK) += netloop.o
++
++netbk-y := netback.o xenbus.o interface.o
++netloop-y := loopback.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netback/netback.c linux-2.6.18-xen/drivers/xen/netback/netback.c
+--- linux-2.6.18.1/drivers/xen/netback/netback.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netback/netback.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,1509 @@
++/******************************************************************************
++ * drivers/xen/netback/netback.c
++ *
++ * Back-end of the driver for virtual network devices. This portion of the
++ * driver exports a 'unified' network-device interface that can be accessed
++ * by any operating system that implements a compatible front end. A
++ * reference front-end implementation can be found in:
++ * drivers/xen/netfront/netfront.c
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include "common.h"
++#include <xen/balloon.h>
++#include <xen/interface/memory.h>
++#include <asm/page.h>
++
++/*#define NETBE_DEBUG_INTERRUPT*/
++
++struct netbk_rx_meta {
++ skb_frag_t frag;
++ int id;
++ int copy:1;
++};
++
++static void netif_idx_release(u16 pending_idx);
++static void netif_page_release(struct page *page);
++static void make_tx_response(netif_t *netif,
++ netif_tx_request_t *txp,
++ s8 st);
++static netif_rx_response_t *make_rx_response(netif_t *netif,
++ u16 id,
++ s8 st,
++ u16 offset,
++ u16 size,
++ u16 flags);
++
++static void net_tx_action(unsigned long unused);
++static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
++
++static void net_rx_action(unsigned long unused);
++static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
++
++static struct timer_list net_timer;
++
++#define MAX_PENDING_REQS 256
++
++static struct sk_buff_head rx_queue;
++
++static struct page **mmap_pages;
++static inline unsigned long idx_to_kaddr(unsigned int idx)
++{
++ return (unsigned long)pfn_to_kaddr(page_to_pfn(mmap_pages[idx]));
++}
++
++#define PKT_PROT_LEN 64
++
++static struct pending_tx_info {
++ netif_tx_request_t req;
++ netif_t *netif;
++} pending_tx_info[MAX_PENDING_REQS];
++static u16 pending_ring[MAX_PENDING_REQS];
++typedef unsigned int PEND_RING_IDX;
++#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
++static PEND_RING_IDX pending_prod, pending_cons;
++#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++
++/* Freed TX SKBs get batched on this ring before return to pending_ring. */
++static u16 dealloc_ring[MAX_PENDING_REQS];
++static PEND_RING_IDX dealloc_prod, dealloc_cons;
++
++static struct sk_buff_head tx_queue;
++
++static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
++static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS];
++static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS];
++
++static struct list_head net_schedule_list;
++static spinlock_t net_schedule_list_lock;
++
++#define MAX_MFN_ALLOC 64
++static unsigned long mfn_list[MAX_MFN_ALLOC];
++static unsigned int alloc_index = 0;
++
++static inline unsigned long alloc_mfn(void)
++{
++ return mfn_list[--alloc_index];
++}
++
++static int check_mfn(int nr)
++{
++ struct xen_memory_reservation reservation = {
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++
++ if (likely(alloc_index >= nr))
++ return 0;
++
++ set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
++ reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
++ alloc_index += HYPERVISOR_memory_op(XENMEM_increase_reservation,
++ &reservation);
++
++ return alloc_index >= nr ? 0 : -ENOMEM;
++}
++
++static inline void maybe_schedule_tx_action(void)
++{
++ smp_mb();
++ if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
++ !list_empty(&net_schedule_list))
++ tasklet_schedule(&net_tx_tasklet);
++}
++
++/*
++ * A gross way of confirming the origin of an skb data page. The slab
++ * allocator abuses a field in the page struct to cache the kmem_cache_t ptr.
++ */
++static inline int is_xen_skb(struct sk_buff *skb)
++{
++ extern kmem_cache_t *skbuff_cachep;
++ kmem_cache_t *cp = (kmem_cache_t *)virt_to_page(skb->head)->lru.next;
++ return (cp == skbuff_cachep);
++}
++
++/*
++ * We can flip without copying the packet unless:
++ * 1. The data is not allocated from our special cache; or
++ * 2. The main data area is shared; or
++ * 3. One or more fragments are shared; or
++ * 4. There are chained fragments.
++ */
++static inline int is_flippable_skb(struct sk_buff *skb)
++{
++ int frag;
++
++ if (!is_xen_skb(skb) || skb_cloned(skb))
++ return 0;
++
++ for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
++ if (page_count(skb_shinfo(skb)->frags[frag].page) > 1)
++ return 0;
++ }
++
++ if (skb_shinfo(skb)->frag_list != NULL)
++ return 0;
++
++ return 1;
++}
++
++static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
++{
++ struct skb_shared_info *ninfo;
++ struct sk_buff *nskb;
++ unsigned long offset;
++ int ret;
++ int len;
++ int headlen;
++
++ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++
++ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC);
++ if (unlikely(!nskb))
++ goto err;
++
++ skb_reserve(nskb, 16);
++ headlen = nskb->end - nskb->data;
++ if (headlen > skb_headlen(skb))
++ headlen = skb_headlen(skb);
++ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
++ BUG_ON(ret);
++
++ ninfo = skb_shinfo(nskb);
++ ninfo->gso_size = skb_shinfo(skb)->gso_size;
++ ninfo->gso_type = skb_shinfo(skb)->gso_type;
++
++ offset = headlen;
++ len = skb->len - headlen;
++
++ nskb->len = skb->len;
++ nskb->data_len = len;
++ nskb->truesize += len;
++
++ while (len) {
++ struct page *page;
++ int copy;
++ int zero;
++
++ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
++ dump_stack();
++ goto err_free;
++ }
++
++ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
++ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
++ if (unlikely(!page))
++ goto err_free;
++
++ ret = skb_copy_bits(skb, offset, page_address(page), copy);
++ BUG_ON(ret);
++
++ ninfo->frags[ninfo->nr_frags].page = page;
++ ninfo->frags[ninfo->nr_frags].page_offset = 0;
++ ninfo->frags[ninfo->nr_frags].size = copy;
++ ninfo->nr_frags++;
++
++ offset += copy;
++ len -= copy;
++ }
++
++ offset = nskb->data - skb->data;
++
++ nskb->h.raw = skb->h.raw + offset;
++ nskb->nh.raw = skb->nh.raw + offset;
++ nskb->mac.raw = skb->mac.raw + offset;
++
++ return nskb;
++
++ err_free:
++ kfree_skb(nskb);
++ err:
++ return NULL;
++}
++
++static inline int netbk_max_required_rx_slots(netif_t *netif)
++{
++ if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
++ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
++ return 1; /* all in one */
++}
++
++static inline int netbk_queue_full(netif_t *netif)
++{
++ RING_IDX peek = netif->rx_req_cons_peek;
++ RING_IDX needed = netbk_max_required_rx_slots(netif);
++
++ return ((netif->rx.sring->req_prod - peek) < needed) ||
++ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
++}
++
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++
++ BUG_ON(skb->dev != dev);
++
++ /* Drop the packet if the target domain has no receive buffers. */
++ if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)))
++ goto drop;
++
++ if (unlikely(netbk_queue_full(netif))) {
++ /* Not a BUG_ON() -- misbehaving netfront can trigger this. */
++ if (netbk_can_queue(dev))
++ DPRINTK("Queue full but not stopped!\n");
++ goto drop;
++ }
++
++ /* Copy the packet here if it's destined for a flipping
++ interface but isn't flippable (e.g. extra references to
++ data)
++ */
++ if (!netif->copying_receiver && !is_flippable_skb(skb)) {
++ struct sk_buff *nskb = netbk_copy_skb(skb);
++ if ( unlikely(nskb == NULL) )
++ goto drop;
++ /* Copy only the header fields we use in this driver. */
++ nskb->dev = skb->dev;
++ nskb->ip_summed = skb->ip_summed;
++ nskb->proto_data_valid = skb->proto_data_valid;
++ dev_kfree_skb(skb);
++ skb = nskb;
++ }
++
++ netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
++ !!skb_shinfo(skb)->gso_size;
++ netif_get(netif);
++
++ if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
++ netif->rx.sring->req_event = netif->rx_req_cons_peek +
++ netbk_max_required_rx_slots(netif);
++ mb(); /* request notification /then/ check & stop the queue */
++ if (netbk_queue_full(netif))
++ netif_stop_queue(dev);
++ }
++
++ skb_queue_tail(&rx_queue, skb);
++ tasklet_schedule(&net_rx_tasklet);
++
++ return 0;
++
++ drop:
++ netif->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 0;
++}
++
++#if 0
++static void xen_network_done_notify(void)
++{
++ static struct net_device *eth0_dev = NULL;
++ if (unlikely(eth0_dev == NULL))
++ eth0_dev = __dev_get_by_name("eth0");
++ netif_rx_schedule(eth0_dev);
++}
++/*
++ * Add following to poll() function in NAPI driver (Tigon3 is example):
++ * if ( xen_network_done() )
++ * tg3_enable_ints(tp);
++ */
++int xen_network_done(void)
++{
++ return skb_queue_empty(&rx_queue);
++}
++#endif
++
++struct netrx_pending_operations {
++ unsigned trans_prod, trans_cons;
++ unsigned mmu_prod, mmu_cons;
++ unsigned mcl_prod, mcl_cons;
++ unsigned copy_prod, copy_cons;
++ unsigned meta_prod, meta_cons;
++ mmu_update_t *mmu;
++ gnttab_transfer_t *trans;
++ gnttab_copy_t *copy;
++ multicall_entry_t *mcl;
++ struct netbk_rx_meta *meta;
++};
++
++/* Set up the grant operations for this fragment. If it's a flipping
++ interface, we also set up the unmap request from here. */
++static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
++ int i, struct netrx_pending_operations *npo,
++ struct page *page, unsigned long size,
++ unsigned long offset)
++{
++ mmu_update_t *mmu;
++ gnttab_transfer_t *gop;
++ gnttab_copy_t *copy_gop;
++ multicall_entry_t *mcl;
++ netif_rx_request_t *req;
++ unsigned long old_mfn, new_mfn;
++
++ old_mfn = virt_to_mfn(page_address(page));
++
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
++ if (netif->copying_receiver) {
++ /* The fragment needs to be copied rather than
++ flipped. */
++ meta->copy = 1;
++ copy_gop = npo->copy + npo->copy_prod++;
++ copy_gop->flags = GNTCOPY_dest_gref;
++ if (PageForeign(page)) {
++ struct pending_tx_info *src_pend =
++ &pending_tx_info[page->index];
++ copy_gop->source.domid = src_pend->netif->domid;
++ copy_gop->source.u.ref = src_pend->req.gref;
++ copy_gop->flags |= GNTCOPY_source_gref;
++ } else {
++ copy_gop->source.domid = DOMID_SELF;
++ copy_gop->source.u.gmfn = old_mfn;
++ }
++ copy_gop->source.offset = offset;
++ copy_gop->dest.domid = netif->domid;
++ copy_gop->dest.offset = 0;
++ copy_gop->dest.u.ref = req->gref;
++ copy_gop->len = size;
++ } else {
++ meta->copy = 0;
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ new_mfn = alloc_mfn();
++
++ /*
++ * Set the new P2M table entry before
++ * reassigning the old data page. Heed the
++ * comment in pgtable-2level.h:pte_page(). :-)
++ */
++ set_phys_to_machine(page_to_pfn(page), new_mfn);
++
++ mcl = npo->mcl + npo->mcl_prod++;
++ MULTI_update_va_mapping(mcl,
++ (unsigned long)page_address(page),
++ pfn_pte_ma(new_mfn, PAGE_KERNEL),
++ 0);
++
++ mmu = npo->mmu + npo->mmu_prod++;
++ mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
++ MMU_MACHPHYS_UPDATE;
++ mmu->val = page_to_pfn(page);
++ }
++
++ gop = npo->trans + npo->trans_prod++;
++ gop->mfn = old_mfn;
++ gop->domid = netif->domid;
++ gop->ref = req->gref;
++ }
++ return req->id;
++}
++
++static void netbk_gop_skb(struct sk_buff *skb,
++ struct netrx_pending_operations *npo)
++{
++ netif_t *netif = netdev_priv(skb->dev);
++ int nr_frags = skb_shinfo(skb)->nr_frags;
++ int i;
++ int extra;
++ struct netbk_rx_meta *head_meta, *meta;
++
++ head_meta = npo->meta + npo->meta_prod++;
++ head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
++ head_meta->frag.size = skb_shinfo(skb)->gso_size;
++ extra = !!head_meta->frag.size + 1;
++
++ for (i = 0; i < nr_frags; i++) {
++ meta = npo->meta + npo->meta_prod++;
++ meta->frag = skb_shinfo(skb)->frags[i];
++ meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
++ meta->frag.page,
++ meta->frag.size,
++ meta->frag.page_offset);
++ }
++
++ /*
++ * This must occur at the end to ensure that we don't trash
++ * skb_shinfo until we're done.
++ */
++ head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
++ virt_to_page(skb->data),
++ skb_headlen(skb),
++ offset_in_page(skb->data));
++
++ netif->rx.req_cons += nr_frags + extra;
++}
++
++static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
++{
++ int i;
++
++ for (i = 0; i < nr_frags; i++)
++ put_page(meta[i].frag.page);
++}
++
++/* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
++ used to set up the operations on the top of
++ netrx_pending_operations, which have since been done. Check that
++ they didn't give any errors and advance over them. */
++static int netbk_check_gop(int nr_frags, domid_t domid,
++ struct netrx_pending_operations *npo)
++{
++ multicall_entry_t *mcl;
++ gnttab_transfer_t *gop;
++ gnttab_copy_t *copy_op;
++ int status = NETIF_RSP_OKAY;
++ int i;
++
++ for (i = 0; i <= nr_frags; i++) {
++ if (npo->meta[npo->meta_cons + i].copy) {
++ copy_op = npo->copy + npo->copy_cons++;
++ if (copy_op->status != GNTST_okay) {
++ DPRINTK("Bad status %d from copy to DOM%d.\n",
++ gop->status, domid);
++ status = NETIF_RSP_ERROR;
++ }
++ } else {
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ mcl = npo->mcl + npo->mcl_cons++;
++ /* The update_va_mapping() must not fail. */
++ BUG_ON(mcl->result != 0);
++ }
++
++ gop = npo->trans + npo->trans_cons++;
++ /* Check the reassignment error code. */
++ if (gop->status != 0) {
++ DPRINTK("Bad status %d from grant transfer to DOM%u\n",
++ gop->status, domid);
++ /*
++ * Page no longer belongs to us unless
++ * GNTST_bad_page, but that should be
++ * a fatal error anyway.
++ */
++ BUG_ON(gop->status == GNTST_bad_page);
++ status = NETIF_RSP_ERROR;
++ }
++ }
++ }
++
++ return status;
++}
++
++static void netbk_add_frag_responses(netif_t *netif, int status,
++ struct netbk_rx_meta *meta, int nr_frags)
++{
++ int i;
++ unsigned long offset;
++
++ for (i = 0; i < nr_frags; i++) {
++ int id = meta[i].id;
++ int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
++
++ if (meta[i].copy)
++ offset = 0;
++ else
++ offset = meta[i].frag.page_offset;
++ make_rx_response(netif, id, status, offset,
++ meta[i].frag.size, flags);
++ }
++}
++
++static void net_rx_action(unsigned long unused)
++{
++ netif_t *netif = NULL;
++ s8 status;
++ u16 id, irq, flags;
++ netif_rx_response_t *resp;
++ multicall_entry_t *mcl;
++ struct sk_buff_head rxq;
++ struct sk_buff *skb;
++ int notify_nr = 0;
++ int ret;
++ int nr_frags;
++ int count;
++ unsigned long offset;
++
++ /*
++ * Putting hundreds of bytes on the stack is considered rude.
++ * Static works because a tasklet can only be on one CPU at any time.
++ */
++ static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+3];
++ static mmu_update_t rx_mmu[NET_RX_RING_SIZE];
++ static gnttab_transfer_t grant_trans_op[NET_RX_RING_SIZE];
++ static gnttab_copy_t grant_copy_op[NET_RX_RING_SIZE];
++ static unsigned char rx_notify[NR_IRQS];
++ static u16 notify_list[NET_RX_RING_SIZE];
++ static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
++
++ struct netrx_pending_operations npo = {
++ mmu: rx_mmu,
++ trans: grant_trans_op,
++ copy: grant_copy_op,
++ mcl: rx_mcl,
++ meta: meta};
++
++ skb_queue_head_init(&rxq);
++
++ count = 0;
++
++ while ((skb = skb_dequeue(&rx_queue)) != NULL) {
++ nr_frags = skb_shinfo(skb)->nr_frags;
++ *(int *)skb->cb = nr_frags;
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap) &&
++ check_mfn(nr_frags + 1)) {
++ /* Memory squeeze? Back off for an arbitrary while. */
++ if ( net_ratelimit() )
++ WPRINTK("Memory squeeze in netback "
++ "driver.\n");
++ mod_timer(&net_timer, jiffies + HZ);
++ skb_queue_head(&rx_queue, skb);
++ break;
++ }
++
++ netbk_gop_skb(skb, &npo);
++
++ count += nr_frags + 1;
++
++ __skb_queue_tail(&rxq, skb);
++
++ /* Filled the batch queue? */
++ if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
++ break;
++ }
++
++ if (npo.mcl_prod &&
++ !xen_feature(XENFEAT_auto_translated_physmap)) {
++ mcl = npo.mcl + npo.mcl_prod++;
++
++ BUG_ON(mcl[-1].op != __HYPERVISOR_update_va_mapping);
++ mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
++
++ mcl->op = __HYPERVISOR_mmu_update;
++ mcl->args[0] = (unsigned long)rx_mmu;
++ mcl->args[1] = npo.mmu_prod;
++ mcl->args[2] = 0;
++ mcl->args[3] = DOMID_SELF;
++ }
++
++ if (npo.trans_prod) {
++ mcl = npo.mcl + npo.mcl_prod++;
++ mcl->op = __HYPERVISOR_grant_table_op;
++ mcl->args[0] = GNTTABOP_transfer;
++ mcl->args[1] = (unsigned long)grant_trans_op;
++ mcl->args[2] = npo.trans_prod;
++ }
++
++ if (npo.copy_prod) {
++ mcl = npo.mcl + npo.mcl_prod++;
++ mcl->op = __HYPERVISOR_grant_table_op;
++ mcl->args[0] = GNTTABOP_copy;
++ mcl->args[1] = (unsigned long)grant_copy_op;
++ mcl->args[2] = npo.copy_prod;
++ }
++
++ /* Nothing to do? */
++ if (!npo.mcl_prod)
++ return;
++
++ BUG_ON(npo.copy_prod > NET_RX_RING_SIZE);
++ BUG_ON(npo.mmu_prod > NET_RX_RING_SIZE);
++ BUG_ON(npo.trans_prod > NET_RX_RING_SIZE);
++ BUG_ON(npo.mcl_prod > NET_RX_RING_SIZE+3);
++ BUG_ON(npo.meta_prod > NET_RX_RING_SIZE);
++
++ ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
++ BUG_ON(ret != 0);
++
++ while ((skb = __skb_dequeue(&rxq)) != NULL) {
++ nr_frags = *(int *)skb->cb;
++
++ netif = netdev_priv(skb->dev);
++ /* We can't rely on skb_release_data to release the
++ pages used by fragments for us, since it tries to
++ touch the pages in the fraglist. If we're in
++ flipping mode, that doesn't work. In copying mode,
++ we still have access to all of the pages, and so
++ it's safe to let release_data deal with it. */
++ /* (Freeing the fragments is safe since we copy
++ non-linear skbs destined for flipping interfaces) */
++ if (!netif->copying_receiver) {
++ atomic_set(&(skb_shinfo(skb)->dataref), 1);
++ skb_shinfo(skb)->frag_list = NULL;
++ skb_shinfo(skb)->nr_frags = 0;
++ netbk_free_pages(nr_frags, meta + npo.meta_cons + 1);
++ }
++
++ netif->stats.tx_bytes += skb->len;
++ netif->stats.tx_packets++;
++
++ status = netbk_check_gop(nr_frags, netif->domid, &npo);
++
++ id = meta[npo.meta_cons].id;
++ flags = nr_frags ? NETRXF_more_data : 0;
++
++ if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++ flags |= NETRXF_csum_blank | NETRXF_data_validated;
++ else if (skb->proto_data_valid) /* remote but checksummed? */
++ flags |= NETRXF_data_validated;
++
++ if (meta[npo.meta_cons].copy)
++ offset = 0;
++ else
++ offset = offset_in_page(skb->data);
++ resp = make_rx_response(netif, id, status, offset,
++ skb_headlen(skb), flags);
++
++ if (meta[npo.meta_cons].frag.size) {
++ struct netif_extra_info *gso =
++ (struct netif_extra_info *)
++ RING_GET_RESPONSE(&netif->rx,
++ netif->rx.rsp_prod_pvt++);
++
++ resp->flags |= NETRXF_extra_info;
++
++ gso->u.gso.size = meta[npo.meta_cons].frag.size;
++ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
++ gso->u.gso.pad = 0;
++ gso->u.gso.features = 0;
++
++ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
++ gso->flags = 0;
++ }
++
++ netbk_add_frag_responses(netif, status,
++ meta + npo.meta_cons + 1,
++ nr_frags);
++
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
++ irq = netif->irq;
++ if (ret && !rx_notify[irq]) {
++ rx_notify[irq] = 1;
++ notify_list[notify_nr++] = irq;
++ }
++
++ if (netif_queue_stopped(netif->dev) &&
++ !netbk_queue_full(netif))
++ netif_wake_queue(netif->dev);
++
++ netif_put(netif);
++ dev_kfree_skb(skb);
++ npo.meta_cons += nr_frags + 1;
++ }
++
++ while (notify_nr != 0) {
++ irq = notify_list[--notify_nr];
++ rx_notify[irq] = 0;
++ notify_remote_via_irq(irq);
++ }
++
++ /* More work to do? */
++ if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
++ tasklet_schedule(&net_rx_tasklet);
++#if 0
++ else
++ xen_network_done_notify();
++#endif
++}
++
++static void net_alarm(unsigned long unused)
++{
++ tasklet_schedule(&net_rx_tasklet);
++}
++
++struct net_device_stats *netif_be_get_stats(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ return &netif->stats;
++}
++
++static int __on_net_schedule_list(netif_t *netif)
++{
++ return netif->list.next != NULL;
++}
++
++static void remove_from_net_schedule_list(netif_t *netif)
++{
++ spin_lock_irq(&net_schedule_list_lock);
++ if (likely(__on_net_schedule_list(netif))) {
++ list_del(&netif->list);
++ netif->list.next = NULL;
++ netif_put(netif);
++ }
++ spin_unlock_irq(&net_schedule_list_lock);
++}
++
++static void add_to_net_schedule_list_tail(netif_t *netif)
++{
++ if (__on_net_schedule_list(netif))
++ return;
++
++ spin_lock_irq(&net_schedule_list_lock);
++ if (!__on_net_schedule_list(netif) &&
++ likely(netif_running(netif->dev) &&
++ netif_carrier_ok(netif->dev))) {
++ list_add_tail(&netif->list, &net_schedule_list);
++ netif_get(netif);
++ }
++ spin_unlock_irq(&net_schedule_list_lock);
++}
++
++/*
++ * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
++ * If this driver is pipelining transmit requests then we can be very
++ * aggressive in avoiding new-packet notifications -- frontend only needs to
++ * send a notification if there are no outstanding unreceived responses.
++ * If we may be buffer transmit buffers for any reason then we must be rather
++ * more conservative and treat this as the final check for pending work.
++ */
++void netif_schedule_work(netif_t *netif)
++{
++ int more_to_do;
++
++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
++ more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
++#else
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++#endif
++
++ if (more_to_do) {
++ add_to_net_schedule_list_tail(netif);
++ maybe_schedule_tx_action();
++ }
++}
++
++void netif_deschedule_work(netif_t *netif)
++{
++ remove_from_net_schedule_list(netif);
++}
++
++
++static void tx_add_credit(netif_t *netif)
++{
++ unsigned long max_burst;
++
++ /*
++ * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
++ * Otherwise the interface can seize up due to insufficient credit.
++ */
++ max_burst = RING_GET_REQUEST(&netif->tx, netif->tx.req_cons)->size;
++ max_burst = min(max_burst, 131072UL);
++ max_burst = max(max_burst, netif->credit_bytes);
++
++ netif->remaining_credit = min(netif->remaining_credit +
++ netif->credit_bytes,
++ max_burst);
++}
++
++static void tx_credit_callback(unsigned long data)
++{
++ netif_t *netif = (netif_t *)data;
++ tx_add_credit(netif);
++ netif_schedule_work(netif);
++}
++
++inline static void net_tx_action_dealloc(void)
++{
++ gnttab_unmap_grant_ref_t *gop;
++ u16 pending_idx;
++ PEND_RING_IDX dc, dp;
++ netif_t *netif;
++ int ret;
++
++ dc = dealloc_cons;
++ dp = dealloc_prod;
++
++ /* Ensure we see all indexes enqueued by netif_idx_release(). */
++ smp_rmb();
++
++ /*
++ * Free up any grants we have finished using
++ */
++ gop = tx_unmap_ops;
++ while (dc != dp) {
++ pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
++ gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
++ GNTMAP_host_map,
++ grant_tx_handle[pending_idx]);
++ gop++;
++ }
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
++ BUG_ON(ret);
++
++ while (dealloc_cons != dp) {
++ pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)];
++
++ netif = pending_tx_info[pending_idx].netif;
++
++ make_tx_response(netif, &pending_tx_info[pending_idx].req,
++ NETIF_RSP_OKAY);
++
++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++
++ netif_put(netif);
++ }
++}
++
++static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
++{
++ RING_IDX cons = netif->tx.req_cons;
++
++ do {
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ if (cons >= end)
++ break;
++ txp = RING_GET_REQUEST(&netif->tx, cons++);
++ } while (1);
++ netif->tx.req_cons = cons;
++ netif_schedule_work(netif);
++ netif_put(netif);
++}
++
++static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
++ netif_tx_request_t *txp, int work_to_do)
++{
++ RING_IDX cons = netif->tx.req_cons;
++ int frags = 0;
++
++ if (!(first->flags & NETTXF_more_data))
++ return 0;
++
++ do {
++ if (frags >= work_to_do) {
++ DPRINTK("Need more frags\n");
++ return -frags;
++ }
++
++ if (unlikely(frags >= MAX_SKB_FRAGS)) {
++ DPRINTK("Too many frags\n");
++ return -frags;
++ }
++
++ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
++ sizeof(*txp));
++ if (txp->size > first->size) {
++ DPRINTK("Frags galore\n");
++ return -frags;
++ }
++
++ first->size -= txp->size;
++ frags++;
++
++ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
++ DPRINTK("txp->offset: %x, size: %u\n",
++ txp->offset, txp->size);
++ return -frags;
++ }
++ } while ((txp++)->flags & NETTXF_more_data);
++
++ return frags;
++}
++
++static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
++ struct sk_buff *skb,
++ netif_tx_request_t *txp,
++ gnttab_map_grant_ref_t *mop)
++{
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ skb_frag_t *frags = shinfo->frags;
++ unsigned long pending_idx = *((u16 *)skb->data);
++ int i, start;
++
++ /* Skip first skb fragment if it is on same page as header fragment. */
++ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++
++ for (i = start; i < shinfo->nr_frags; i++, txp++) {
++ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)];
++
++ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
++ GNTMAP_host_map | GNTMAP_readonly,
++ txp->gref, netif->domid);
++
++ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
++ netif_get(netif);
++ pending_tx_info[pending_idx].netif = netif;
++ frags[i].page = (void *)pending_idx;
++ }
++
++ return mop;
++}
++
++static int netbk_tx_check_mop(struct sk_buff *skb,
++ gnttab_map_grant_ref_t **mopp)
++{
++ gnttab_map_grant_ref_t *mop = *mopp;
++ int pending_idx = *((u16 *)skb->data);
++ netif_t *netif = pending_tx_info[pending_idx].netif;
++ netif_tx_request_t *txp;
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ int nr_frags = shinfo->nr_frags;
++ int i, err, start;
++
++ /* Check status of header. */
++ err = mop->status;
++ if (unlikely(err)) {
++ txp = &pending_tx_info[pending_idx].req;
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++ netif_put(netif);
++ } else {
++ set_phys_to_machine(
++ __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
++ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
++ grant_tx_handle[pending_idx] = mop->handle;
++ }
++
++ /* Skip first skb fragment if it is on same page as header fragment. */
++ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++
++ for (i = start; i < nr_frags; i++) {
++ int j, newerr;
++
++ pending_idx = (unsigned long)shinfo->frags[i].page;
++
++ /* Check error status: if okay then remember grant handle. */
++ newerr = (++mop)->status;
++ if (likely(!newerr)) {
++ set_phys_to_machine(
++ __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
++ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
++ grant_tx_handle[pending_idx] = mop->handle;
++ /* Had a previous error? Invalidate this fragment. */
++ if (unlikely(err))
++ netif_idx_release(pending_idx);
++ continue;
++ }
++
++ /* Error on this fragment: respond to client with an error. */
++ txp = &pending_tx_info[pending_idx].req;
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++ netif_put(netif);
++
++ /* Not the first error? Preceding frags already invalidated. */
++ if (err)
++ continue;
++
++ /* First error: invalidate header and preceding fragments. */
++ pending_idx = *((u16 *)skb->data);
++ netif_idx_release(pending_idx);
++ for (j = start; j < i; j++) {
++ pending_idx = (unsigned long)shinfo->frags[i].page;
++ netif_idx_release(pending_idx);
++ }
++
++ /* Remember the error: invalidate all subsequent fragments. */
++ err = newerr;
++ }
++
++ *mopp = mop + 1;
++ return err;
++}
++
++static void netbk_fill_frags(struct sk_buff *skb)
++{
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ int nr_frags = shinfo->nr_frags;
++ int i;
++
++ for (i = 0; i < nr_frags; i++) {
++ skb_frag_t *frag = shinfo->frags + i;
++ netif_tx_request_t *txp;
++ unsigned long pending_idx;
++
++ pending_idx = (unsigned long)frag->page;
++ txp = &pending_tx_info[pending_idx].req;
++ frag->page = virt_to_page(idx_to_kaddr(pending_idx));
++ frag->size = txp->size;
++ frag->page_offset = txp->offset;
++
++ skb->len += txp->size;
++ skb->data_len += txp->size;
++ skb->truesize += txp->size;
++ }
++}
++
++int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
++ int work_to_do)
++{
++ struct netif_extra_info extra;
++ RING_IDX cons = netif->tx.req_cons;
++
++ do {
++ if (unlikely(work_to_do-- <= 0)) {
++ DPRINTK("Missing extra info\n");
++ return -EBADR;
++ }
++
++ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
++ sizeof(extra));
++ if (unlikely(!extra.type ||
++ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++ netif->tx.req_cons = ++cons;
++ DPRINTK("Invalid extra type: %d\n", extra.type);
++ return -EINVAL;
++ }
++
++ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
++ netif->tx.req_cons = ++cons;
++ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
++
++ return work_to_do;
++}
++
++static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
++{
++ if (!gso->u.gso.size) {
++ DPRINTK("GSO size must not be zero.\n");
++ return -EINVAL;
++ }
++
++ /* Currently only TCPv4 S.O. is supported. */
++ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
++ DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
++ return -EINVAL;
++ }
++
++ skb_shinfo(skb)->gso_size = gso->u.gso.size;
++ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++
++ /* Header must be checked, and gso_segs computed. */
++ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++ skb_shinfo(skb)->gso_segs = 0;
++
++ return 0;
++}
++
++/* Called after netfront has transmitted */
++static void net_tx_action(unsigned long unused)
++{
++ struct list_head *ent;
++ struct sk_buff *skb;
++ netif_t *netif;
++ netif_tx_request_t txreq;
++ netif_tx_request_t txfrags[MAX_SKB_FRAGS];
++ struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++ u16 pending_idx;
++ RING_IDX i;
++ gnttab_map_grant_ref_t *mop;
++ unsigned int data_len;
++ int ret, work_to_do;
++
++ if (dealloc_cons != dealloc_prod)
++ net_tx_action_dealloc();
++
++ mop = tx_map_ops;
++ while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ !list_empty(&net_schedule_list)) {
++ /* Get a netif from the list with work to do. */
++ ent = net_schedule_list.next;
++ netif = list_entry(ent, netif_t, list);
++ netif_get(netif);
++ remove_from_net_schedule_list(netif);
++
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
++ if (!work_to_do) {
++ netif_put(netif);
++ continue;
++ }
++
++ i = netif->tx.req_cons;
++ rmb(); /* Ensure that we see the request before we copy it. */
++ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
++
++ /* Credit-based scheduling. */
++ if (txreq.size > netif->remaining_credit) {
++ unsigned long now = jiffies;
++ unsigned long next_credit =
++ netif->credit_timeout.expires +
++ msecs_to_jiffies(netif->credit_usec / 1000);
++
++ /* Timer could already be pending in rare cases. */
++ if (timer_pending(&netif->credit_timeout)) {
++ netif_put(netif);
++ continue;
++ }
++
++ /* Passed the point where we can replenish credit? */
++ if (time_after_eq(now, next_credit)) {
++ netif->credit_timeout.expires = now;
++ tx_add_credit(netif);
++ }
++
++ /* Still too big to send right now? Set a callback. */
++ if (txreq.size > netif->remaining_credit) {
++ netif->credit_timeout.data =
++ (unsigned long)netif;
++ netif->credit_timeout.function =
++ tx_credit_callback;
++ __mod_timer(&netif->credit_timeout,
++ next_credit);
++ netif_put(netif);
++ continue;
++ }
++ }
++ netif->remaining_credit -= txreq.size;
++
++ work_to_do--;
++ netif->tx.req_cons = ++i;
++
++ memset(extras, 0, sizeof(extras));
++ if (txreq.flags & NETTXF_extra_info) {
++ work_to_do = netbk_get_extras(netif, extras,
++ work_to_do);
++ i = netif->tx.req_cons;
++ if (unlikely(work_to_do < 0)) {
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
++ }
++
++ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
++ if (unlikely(ret < 0)) {
++ netbk_tx_err(netif, &txreq, i - ret);
++ continue;
++ }
++ i += ret;
++
++ if (unlikely(txreq.size < ETH_HLEN)) {
++ DPRINTK("Bad packet size: %d\n", txreq.size);
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
++
++ /* No crossing a page as the payload mustn't fragment. */
++ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
++ DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
++ txreq.offset, txreq.size,
++ (txreq.offset &~PAGE_MASK) + txreq.size);
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
++
++ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
++
++ data_len = (txreq.size > PKT_PROT_LEN &&
++ ret < MAX_SKB_FRAGS) ?
++ PKT_PROT_LEN : txreq.size;
++
++ skb = alloc_skb(data_len+16, GFP_ATOMIC);
++ if (unlikely(skb == NULL)) {
++ DPRINTK("Can't allocate a skb in start_xmit.\n");
++ netbk_tx_err(netif, &txreq, i);
++ break;
++ }
++
++ /* Packets passed to netif_rx() must have some headroom. */
++ skb_reserve(skb, 16);
++
++ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
++ struct netif_extra_info *gso;
++ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++
++ if (netbk_set_skb_gso(skb, gso)) {
++ kfree_skb(skb);
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
++ }
++
++ gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
++ GNTMAP_host_map | GNTMAP_readonly,
++ txreq.gref, netif->domid);
++ mop++;
++
++ memcpy(&pending_tx_info[pending_idx].req,
++ &txreq, sizeof(txreq));
++ pending_tx_info[pending_idx].netif = netif;
++ *((u16 *)skb->data) = pending_idx;
++
++ __skb_put(skb, data_len);
++
++ skb_shinfo(skb)->nr_frags = ret;
++ if (data_len < txreq.size) {
++ skb_shinfo(skb)->nr_frags++;
++ skb_shinfo(skb)->frags[0].page =
++ (void *)(unsigned long)pending_idx;
++ } else {
++ /* Discriminate from any valid pending_idx value. */
++ skb_shinfo(skb)->frags[0].page = (void *)~0UL;
++ }
++
++ __skb_queue_tail(&tx_queue, skb);
++
++ pending_cons++;
++
++ mop = netbk_get_requests(netif, skb, txfrags, mop);
++
++ netif->tx.req_cons = i;
++ netif_schedule_work(netif);
++
++ if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
++ break;
++ }
++
++ if (mop == tx_map_ops)
++ return;
++
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
++ BUG_ON(ret);
++
++ mop = tx_map_ops;
++ while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
++ netif_tx_request_t *txp;
++
++ pending_idx = *((u16 *)skb->data);
++ netif = pending_tx_info[pending_idx].netif;
++ txp = &pending_tx_info[pending_idx].req;
++
++ /* Check the remap error code. */
++ if (unlikely(netbk_tx_check_mop(skb, &mop))) {
++ printk(KERN_ALERT "#### netback grant fails\n");
++ skb_shinfo(skb)->nr_frags = 0;
++ kfree_skb(skb);
++ continue;
++ }
++
++ data_len = skb->len;
++ memcpy(skb->data,
++ (void *)(idx_to_kaddr(pending_idx)|txp->offset),
++ data_len);
++ if (data_len < txp->size) {
++ /* Append the packet payload as a fragment. */
++ txp->offset += data_len;
++ txp->size -= data_len;
++ } else {
++ /* Schedule a response immediately. */
++ netif_idx_release(pending_idx);
++ }
++
++ /*
++ * Old frontends do not assert data_validated but we
++ * can infer it from csum_blank so test both flags.
++ */
++ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ skb->proto_data_valid = 1;
++ } else {
++ skb->ip_summed = CHECKSUM_NONE;
++ skb->proto_data_valid = 0;
++ }
++ skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
++
++ netbk_fill_frags(skb);
++
++ skb->dev = netif->dev;
++ skb->protocol = eth_type_trans(skb, skb->dev);
++
++ netif->stats.rx_bytes += skb->len;
++ netif->stats.rx_packets++;
++
++ netif_rx(skb);
++ netif->dev->last_rx = jiffies;
++ }
++}
++
++static void netif_idx_release(u16 pending_idx)
++{
++ static DEFINE_SPINLOCK(_lock);
++ unsigned long flags;
++
++ spin_lock_irqsave(&_lock, flags);
++ dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
++ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
++ smp_wmb();
++ dealloc_prod++;
++ spin_unlock_irqrestore(&_lock, flags);
++
++ tasklet_schedule(&net_tx_tasklet);
++}
++
++static void netif_page_release(struct page *page)
++{
++ /* Ready for next use. */
++ init_page_count(page);
++ netif_idx_release(page->index);
++}
++
++irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ netif_t *netif = dev_id;
++
++ add_to_net_schedule_list_tail(netif);
++ maybe_schedule_tx_action();
++
++ if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif))
++ netif_wake_queue(netif->dev);
++
++ return IRQ_HANDLED;
++}
++
++static void make_tx_response(netif_t *netif,
++ netif_tx_request_t *txp,
++ s8 st)
++{
++ RING_IDX i = netif->tx.rsp_prod_pvt;
++ netif_tx_response_t *resp;
++ int notify;
++
++ resp = RING_GET_RESPONSE(&netif->tx, i);
++ resp->id = txp->id;
++ resp->status = st;
++
++ if (txp->flags & NETTXF_extra_info)
++ RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
++
++ netif->tx.rsp_prod_pvt = ++i;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
++ if (notify)
++ notify_remote_via_irq(netif->irq);
++
++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
++ if (i == netif->tx.req_cons) {
++ int more_to_do;
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++ if (more_to_do)
++ add_to_net_schedule_list_tail(netif);
++ }
++#endif
++}
++
++static netif_rx_response_t *make_rx_response(netif_t *netif,
++ u16 id,
++ s8 st,
++ u16 offset,
++ u16 size,
++ u16 flags)
++{
++ RING_IDX i = netif->rx.rsp_prod_pvt;
++ netif_rx_response_t *resp;
++
++ resp = RING_GET_RESPONSE(&netif->rx, i);
++ resp->offset = offset;
++ resp->flags = flags;
++ resp->id = id;
++ resp->status = (s16)size;
++ if (st < 0)
++ resp->status = (s16)st;
++
++ netif->rx.rsp_prod_pvt = ++i;
++
++ return resp;
++}
++
++#ifdef NETBE_DEBUG_INTERRUPT
++static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct list_head *ent;
++ netif_t *netif;
++ int i = 0;
++
++ printk(KERN_ALERT "netif_schedule_list:\n");
++ spin_lock_irq(&net_schedule_list_lock);
++
++ list_for_each (ent, &net_schedule_list) {
++ netif = list_entry(ent, netif_t, list);
++ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
++ "rx_resp_prod=%08x\n",
++ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
++ printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n",
++ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
++ printk(KERN_ALERT " shared(rx_req_prod=%08x "
++ "rx_resp_prod=%08x\n",
++ netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
++ printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n",
++ netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
++ printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n",
++ netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
++ i++;
++ }
++
++ spin_unlock_irq(&net_schedule_list_lock);
++ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
++
++ return IRQ_HANDLED;
++}
++#endif
++
++static int __init netback_init(void)
++{
++ int i;
++ struct page *page;
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ /* We can increase reservation by this much in net_rx_action(). */
++ balloon_update_driver_allowance(NET_RX_RING_SIZE);
++
++ skb_queue_head_init(&rx_queue);
++ skb_queue_head_init(&tx_queue);
++
++ init_timer(&net_timer);
++ net_timer.data = 0;
++ net_timer.function = net_alarm;
++
++ mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
++ if (mmap_pages == NULL) {
++ printk("%s: out of memory\n", __FUNCTION__);
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < MAX_PENDING_REQS; i++) {
++ page = mmap_pages[i];
++ SetPageForeign(page, netif_page_release);
++ page->index = i;
++ }
++
++ pending_cons = 0;
++ pending_prod = MAX_PENDING_REQS;
++ for (i = 0; i < MAX_PENDING_REQS; i++)
++ pending_ring[i] = i;
++
++ spin_lock_init(&net_schedule_list_lock);
++ INIT_LIST_HEAD(&net_schedule_list);
++
++ netif_xenbus_init();
++
++#ifdef NETBE_DEBUG_INTERRUPT
++ (void)bind_virq_to_irqhandler(
++ VIRQ_DEBUG,
++ 0,
++ netif_be_dbg,
++ SA_SHIRQ,
++ "net-be-dbg",
++ &netif_be_dbg);
++#endif
++
++ return 0;
++}
++
++module_init(netback_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netback/xenbus.c linux-2.6.18-xen/drivers/xen/netback/xenbus.c
+--- linux-2.6.18.1/drivers/xen/netback/xenbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netback/xenbus.c 2006-10-19 11:01:25.000000000 +0200
+@@ -0,0 +1,438 @@
++/* Xenbus code for netif backend
++ Copyright (C) 2005 Rusty Russell <rusty at rustcorp.com.au>
++ Copyright (C) 2005 XenSource 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
++*/
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++#if 0
++#undef DPRINTK
++#define DPRINTK(fmt, args...) \
++ printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
++#endif
++
++struct backend_info {
++ struct xenbus_device *dev;
++ netif_t *netif;
++ enum xenbus_state frontend_state;
++};
++
++static int connect_rings(struct backend_info *);
++static void connect(struct backend_info *);
++static void backend_create_netif(struct backend_info *be);
++
++static int netback_remove(struct xenbus_device *dev)
++{
++ struct backend_info *be = dev->dev.driver_data;
++
++ if (be->netif) {
++ netif_disconnect(be->netif);
++ be->netif = NULL;
++ }
++ kfree(be);
++ dev->dev.driver_data = NULL;
++ return 0;
++}
++
++
++/**
++ * Entry point to this code when a new device is created. Allocate the basic
++ * structures and switch to InitWait.
++ */
++static int netback_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ const char *message;
++ struct xenbus_transaction xbt;
++ int err;
++ struct backend_info *be = kzalloc(sizeof(struct backend_info),
++ GFP_KERNEL);
++ if (!be) {
++ xenbus_dev_fatal(dev, -ENOMEM,
++ "allocating backend structure");
++ return -ENOMEM;
++ }
++
++ be->dev = dev;
++ dev->dev.driver_data = be;
++
++ do {
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ goto fail;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
++ if (err) {
++ message = "writing feature-sg";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
++ "%d", 1);
++ if (err) {
++ message = "writing feature-gso-tcpv4";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename,
++ "feature-rx-copy", "%d", 1);
++ if (err) {
++ message = "writing feature-copying";
++ goto abort_transaction;
++ }
++
++ err = xenbus_transaction_end(xbt, 0);
++ } while (err == -EAGAIN);
++
++ if (err) {
++ xenbus_dev_fatal(dev, err, "completing transaction");
++ goto fail;
++ }
++
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto fail;
++
++ /* This kicks hotplug scripts, so do it immediately. */
++ backend_create_netif(be);
++
++ return 0;
++
++abort_transaction:
++ xenbus_transaction_end(xbt, 1);
++ xenbus_dev_fatal(dev, err, "%s", message);
++fail:
++ DPRINTK("failed");
++ netback_remove(dev);
++ return err;
++}
++
++
++/**
++ * Handle the creation of the hotplug script environment. We add the script
++ * and vif variables to the environment, for the benefit of the vif-* hotplug
++ * scripts.
++ */
++static int netback_uevent(struct xenbus_device *xdev, char **envp,
++ int num_envp, char *buffer, int buffer_size)
++{
++ struct backend_info *be = xdev->dev.driver_data;
++ netif_t *netif = be->netif;
++ int i = 0, length = 0;
++ char *val;
++
++ DPRINTK("netback_uevent");
++
++ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
++ if (IS_ERR(val)) {
++ int err = PTR_ERR(val);
++ xenbus_dev_fatal(xdev, err, "reading script");
++ return err;
++ }
++ else {
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
++ &length, "script=%s", val);
++ kfree(val);
++ }
++
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "vif=%s", netif->dev->name);
++
++ envp[i] = NULL;
++
++ return 0;
++}
++
++
++static void backend_create_netif(struct backend_info *be)
++{
++ int err;
++ long handle;
++ struct xenbus_device *dev = be->dev;
++
++ if (be->netif != NULL)
++ return;
++
++ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
++ if (err != 1) {
++ xenbus_dev_fatal(dev, err, "reading handle");
++ return;
++ }
++
++ be->netif = netif_alloc(dev->otherend_id, handle);
++ if (IS_ERR(be->netif)) {
++ err = PTR_ERR(be->netif);
++ be->netif = NULL;
++ xenbus_dev_fatal(dev, err, "creating interface");
++ return;
++ }
++
++ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
++}
++
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state)
++{
++ struct backend_info *be = dev->dev.driver_data;
++
++ DPRINTK("%s", xenbus_strstate(frontend_state));
++
++ be->frontend_state = frontend_state;
++
++ switch (frontend_state) {
++ case XenbusStateInitialising:
++ if (dev->state == XenbusStateClosed) {
++ printk("%s: %s: prepare for reconnect\n",
++ __FUNCTION__, dev->nodename);
++ if (be->netif) {
++ netif_disconnect(be->netif);
++ be->netif = NULL;
++ }
++ xenbus_switch_state(dev, XenbusStateInitWait);
++ }
++ break;
++
++ case XenbusStateInitialised:
++ break;
++
++ case XenbusStateConnected:
++ backend_create_netif(be);
++ if (be->netif)
++ connect(be);
++ break;
++
++ case XenbusStateClosing:
++ xenbus_switch_state(dev, XenbusStateClosing);
++ break;
++
++ case XenbusStateClosed:
++ xenbus_switch_state(dev, XenbusStateClosed);
++ if (xenbus_dev_is_online(dev))
++ break;
++ /* fall through if not online */
++ case XenbusStateUnknown:
++ if (be->netif != NULL)
++ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++ device_unregister(&dev->dev);
++ break;
++
++ default:
++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++ frontend_state);
++ break;
++ }
++}
++
++
++static void xen_net_read_rate(struct xenbus_device *dev,
++ unsigned long *bytes, unsigned long *usec)
++{
++ char *s, *e;
++ unsigned long b, u;
++ char *ratestr;
++
++ /* Default to unlimited bandwidth. */
++ *bytes = ~0UL;
++ *usec = 0;
++
++ ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
++ if (IS_ERR(ratestr))
++ return;
++
++ s = ratestr;
++ b = simple_strtoul(s, &e, 10);
++ if ((s == e) || (*e != ','))
++ goto fail;
++
++ s = e + 1;
++ u = simple_strtoul(s, &e, 10);
++ if ((s == e) || (*e != '\0'))
++ goto fail;
++
++ *bytes = b;
++ *usec = u;
++
++ kfree(ratestr);
++ return;
++
++ fail:
++ WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
++ kfree(ratestr);
++}
++
++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
++{
++ char *s, *e, *macstr;
++ int i;
++
++ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++ if (IS_ERR(macstr))
++ return PTR_ERR(macstr);
++
++ for (i = 0; i < ETH_ALEN; i++) {
++ mac[i] = simple_strtoul(s, &e, 16);
++ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++ kfree(macstr);
++ return -ENOENT;
++ }
++ s = e+1;
++ }
++
++ kfree(macstr);
++ return 0;
++}
++
++static void connect(struct backend_info *be)
++{
++ int err;
++ struct xenbus_device *dev = be->dev;
++
++ err = connect_rings(be);
++ if (err)
++ return;
++
++ err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
++ return;
++ }
++
++ xen_net_read_rate(dev, &be->netif->credit_bytes,
++ &be->netif->credit_usec);
++ be->netif->remaining_credit = be->netif->credit_bytes;
++
++ xenbus_switch_state(dev, XenbusStateConnected);
++
++ /* May not get a kick from the frontend, so start the tx_queue now. */
++ if (!netbk_can_queue(be->netif->dev))
++ netif_start_queue(be->netif->dev);
++}
++
++
++static int connect_rings(struct backend_info *be)
++{
++ struct xenbus_device *dev = be->dev;
++ unsigned long tx_ring_ref, rx_ring_ref;
++ unsigned int evtchn, rx_copy;
++ int err;
++ int val;
++
++ DPRINTK("");
++
++ err = xenbus_gather(XBT_NIL, dev->otherend,
++ "tx-ring-ref", "%lu", &tx_ring_ref,
++ "rx-ring-ref", "%lu", &rx_ring_ref,
++ "event-channel", "%u", &evtchn, NULL);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "reading %s/ring-ref and event-channel",
++ dev->otherend);
++ return err;
++ }
++
++ err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
++ &rx_copy);
++ if (err == -ENOENT) {
++ err = 0;
++ rx_copy = 0;
++ }
++ if (err < 0) {
++ xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
++ dev->otherend);
++ return err;
++ }
++ be->netif->copying_receiver = !!rx_copy;
++
++ if (be->netif->dev->tx_queue_len != 0) {
++ if (xenbus_scanf(XBT_NIL, dev->otherend,
++ "feature-rx-notify", "%d", &val) < 0)
++ val = 0;
++ if (val)
++ be->netif->can_queue = 1;
++ else
++ /* Must be non-zero for pfifo_fast to work. */
++ be->netif->dev->tx_queue_len = 1;
++ }
++
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features |= NETIF_F_SG;
++ be->netif->dev->features |= NETIF_F_SG;
++ }
++
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d",
++ &val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features |= NETIF_F_TSO;
++ be->netif->dev->features |= NETIF_F_TSO;
++ }
++
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
++ "%d", &val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features &= ~NETIF_F_IP_CSUM;
++ be->netif->dev->features &= ~NETIF_F_IP_CSUM;
++ }
++
++ /* Map the shared frame, irq etc. */
++ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "mapping shared-frames %lu/%lu port %u",
++ tx_ring_ref, rx_ring_ref, evtchn);
++ return err;
++ }
++ return 0;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static struct xenbus_device_id netback_ids[] = {
++ { "vif" },
++ { "" }
++};
++
++
++static struct xenbus_driver netback = {
++ .name = "vif",
++ .owner = THIS_MODULE,
++ .ids = netback_ids,
++ .probe = netback_probe,
++ .remove = netback_remove,
++ .uevent = netback_uevent,
++ .otherend_changed = frontend_changed,
++};
++
++
++void netif_xenbus_init(void)
++{
++ xenbus_register_backend(&netback);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netfront/Kconfig linux-2.6.18-xen/drivers/xen/netfront/Kconfig
+--- linux-2.6.18.1/drivers/xen/netfront/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netfront/Kconfig 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,6 @@
++
++config XENNET
++ tristate "Xen network driver"
++ depends on NETDEVICES && ARCH_XEN
++ help
++ Network driver for Xen
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netfront/Makefile linux-2.6.18-xen/drivers/xen/netfront/Makefile
+--- linux-2.6.18.1/drivers/xen/netfront/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netfront/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,4 @@
++
++obj-$(CONFIG_XEN_NETDEV_FRONTEND) := xennet.o
++
++xennet-objs := netfront.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/netfront/netfront.c linux-2.6.18-xen/drivers/xen/netfront/netfront.c
+--- linux-2.6.18.1/drivers/xen/netfront/netfront.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/netfront/netfront.c 2006-10-19 11:01:25.000000000 +0200
+@@ -0,0 +1,2138 @@
++/******************************************************************************
++ * Virtual network driver for conversing with remote driver backends.
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ * Copyright (c) 2005, XenSource Ltd
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/netdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <linux/bitops.h>
++#include <linux/ethtool.h>
++#include <linux/in.h>
++#include <linux/if_ether.h>
++#include <linux/io.h>
++#include <linux/moduleparam.h>
++#include <net/sock.h>
++#include <net/pkt_sched.h>
++#include <net/arp.h>
++#include <net/route.h>
++#include <asm/hypercall.h>
++#include <asm/uaccess.h>
++#include <xen/evtchn.h>
++#include <xen/xenbus.h>
++#include <xen/interface/io/netif.h>
++#include <xen/interface/memory.h>
++#include <xen/balloon.h>
++#include <asm/page.h>
++#include <asm/maddr.h>
++#include <asm/uaccess.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++
++/*
++ * Mutually-exclusive module options to select receive data path:
++ * rx_copy : Packets are copied by network backend into local memory
++ * rx_flip : Page containing packet data is transferred to our ownership
++ * For fully-virtualised guests there is no option - copying must be used.
++ * For paravirtualised guests, flipping is the default.
++ */
++#ifdef CONFIG_XEN
++static int MODPARM_rx_copy = 0;
++module_param_named(rx_copy, MODPARM_rx_copy, bool, 0);
++MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)");
++static int MODPARM_rx_flip = 0;
++module_param_named(rx_flip, MODPARM_rx_flip, bool, 0);
++MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)");
++#else
++static const int MODPARM_rx_copy = 1;
++static const int MODPARM_rx_flip = 0;
++#endif
++
++#define RX_COPY_THRESHOLD 256
++
++/* If we don't have GSO, fake things up so that we never try to use it. */
++#if defined(NETIF_F_GSO)
++#define HAVE_GSO 1
++#define HAVE_TSO 1 /* TSO is a subset of GSO */
++static inline void dev_disable_gso_features(struct net_device *dev)
++{
++ /* Turn off all GSO bits except ROBUST. */
++ dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
++ dev->features |= NETIF_F_GSO_ROBUST;
++}
++#elif defined(NETIF_F_TSO)
++#define HAVE_TSO 1
++#define gso_size tso_size
++#define gso_segs tso_segs
++static inline void dev_disable_gso_features(struct net_device *dev)
++{
++ /* Turn off all TSO bits. */
++ dev->features &= ~NETIF_F_TSO;
++}
++static inline int skb_is_gso(const struct sk_buff *skb)
++{
++ return skb_shinfo(skb)->tso_size;
++}
++static inline int skb_gso_ok(struct sk_buff *skb, int features)
++{
++ return (features & NETIF_F_TSO);
++}
++
++static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
++{
++ return skb_is_gso(skb) &&
++ (!skb_gso_ok(skb, dev->features) ||
++ unlikely(skb->ip_summed != CHECKSUM_HW));
++}
++#else
++#define netif_needs_gso(dev, skb) 0
++#define dev_disable_gso_features(dev) ((void)0)
++#endif
++
++#define GRANT_INVALID_REF 0
++
++#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
++
++struct netfront_info {
++ struct list_head list;
++ struct net_device *netdev;
++
++ struct net_device_stats stats;
++
++ struct netif_tx_front_ring tx;
++ struct netif_rx_front_ring rx;
++
++ spinlock_t tx_lock;
++ spinlock_t rx_lock;
++
++ unsigned int evtchn, irq;
++ unsigned int copying_receiver;
++
++ /* Receive-ring batched refills. */
++#define RX_MIN_TARGET 8
++#define RX_DFL_MIN_TARGET 64
++#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
++ unsigned rx_min_target, rx_max_target, rx_target;
++ struct sk_buff_head rx_batch;
++
++ struct timer_list rx_refill_timer;
++
++ /*
++ * {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs
++ * is an index into a chain of free entries.
++ */
++ struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1];
++ struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
++
++#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
++ grant_ref_t gref_tx_head;
++ grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
++ grant_ref_t gref_rx_head;
++ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
++
++ struct xenbus_device *xbdev;
++ int tx_ring_ref;
++ int rx_ring_ref;
++ u8 mac[ETH_ALEN];
++
++ unsigned long rx_pfn_array[NET_RX_RING_SIZE];
++ struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
++ struct mmu_update rx_mmu[NET_RX_RING_SIZE];
++};
++
++struct netfront_rx_info {
++ struct netif_rx_response rx;
++ struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++};
++
++/*
++ * Access macros for acquiring freeing slots in tx_skbs[].
++ */
++
++static inline void add_id_to_freelist(struct sk_buff **list, unsigned short id)
++{
++ list[id] = list[0];
++ list[0] = (void *)(unsigned long)id;
++}
++
++static inline unsigned short get_id_from_freelist(struct sk_buff **list)
++{
++ unsigned int id = (unsigned int)(unsigned long)list[0];
++ list[0] = list[id];
++ return id;
++}
++
++static inline int xennet_rxidx(RING_IDX idx)
++{
++ return idx & (NET_RX_RING_SIZE - 1);
++}
++
++static inline struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
++ RING_IDX ri)
++{
++ int i = xennet_rxidx(ri);
++ struct sk_buff *skb = np->rx_skbs[i];
++ np->rx_skbs[i] = NULL;
++ return skb;
++}
++
++static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
++ RING_IDX ri)
++{
++ int i = xennet_rxidx(ri);
++ grant_ref_t ref = np->grant_rx_ref[i];
++ np->grant_rx_ref[i] = GRANT_INVALID_REF;
++ return ref;
++}
++
++#define DPRINTK(fmt, args...) \
++ pr_debug("netfront (%s:%d) " fmt, \
++ __FUNCTION__, __LINE__, ##args)
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "netfront: " fmt, ##args)
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "netfront: " fmt, ##args)
++
++static int setup_device(struct xenbus_device *, struct netfront_info *);
++static struct net_device *create_netdev(struct xenbus_device *);
++
++static void netfront_closing(struct xenbus_device *);
++
++static void end_access(int, void *);
++static void netif_disconnect_backend(struct netfront_info *);
++static int open_netdev(struct netfront_info *);
++static void close_netdev(struct netfront_info *);
++static void netif_free(struct netfront_info *);
++
++static int network_connect(struct net_device *);
++static void network_tx_buf_gc(struct net_device *);
++static void network_alloc_rx_buffers(struct net_device *);
++static int send_fake_arp(struct net_device *);
++
++static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs);
++
++#ifdef CONFIG_SYSFS
++static int xennet_sysfs_addif(struct net_device *netdev);
++static void xennet_sysfs_delif(struct net_device *netdev);
++#else /* !CONFIG_SYSFS */
++#define xennet_sysfs_addif(dev) (0)
++#define xennet_sysfs_delif(dev) do { } while(0)
++#endif
++
++static inline int xennet_can_sg(struct net_device *dev)
++{
++ return dev->features & NETIF_F_SG;
++}
++
++/**
++ * Entry point to this code when a new device is created. Allocate the basic
++ * structures and the ring buffers for communication with the backend, and
++ * inform the backend of the appropriate details for those.
++ */
++static int __devinit netfront_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err;
++ struct net_device *netdev;
++ struct netfront_info *info;
++
++ netdev = create_netdev(dev);
++ if (IS_ERR(netdev)) {
++ err = PTR_ERR(netdev);
++ xenbus_dev_fatal(dev, err, "creating netdev");
++ return err;
++ }
++
++ info = netdev_priv(netdev);
++ dev->dev.driver_data = info;
++
++ err = open_netdev(info);
++ if (err)
++ goto fail;
++
++ return 0;
++
++ fail:
++ free_netdev(netdev);
++ dev->dev.driver_data = NULL;
++ return err;
++}
++
++
++/**
++ * We are reconnecting to the backend, due to a suspend/resume, or a backend
++ * driver restart. We tear down our netif structure and recreate it, but
++ * leave the device-layer structures intact so that this is transparent to the
++ * rest of the kernel.
++ */
++static int netfront_resume(struct xenbus_device *dev)
++{
++ struct netfront_info *info = dev->dev.driver_data;
++
++ DPRINTK("%s\n", dev->nodename);
++
++ netif_disconnect_backend(info);
++ return 0;
++}
++
++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
++{
++ char *s, *e, *macstr;
++ int i;
++
++ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++ if (IS_ERR(macstr))
++ return PTR_ERR(macstr);
++
++ for (i = 0; i < ETH_ALEN; i++) {
++ mac[i] = simple_strtoul(s, &e, 16);
++ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++ kfree(macstr);
++ return -ENOENT;
++ }
++ s = e+1;
++ }
++
++ kfree(macstr);
++ return 0;
++}
++
++/* Common code used when first setting up, and when resuming. */
++static int talk_to_backend(struct xenbus_device *dev,
++ struct netfront_info *info)
++{
++ const char *message;
++ struct xenbus_transaction xbt;
++ int err;
++
++ err = xen_net_read_mac(dev, info->mac);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
++ goto out;
++ }
++
++ /* Create shared ring, alloc event channel. */
++ err = setup_device(dev, info);
++ if (err)
++ goto out;
++
++again:
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ goto destroy_ring;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u",
++ info->tx_ring_ref);
++ if (err) {
++ message = "writing tx ring-ref";
++ goto abort_transaction;
++ }
++ err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u",
++ info->rx_ring_ref);
++ if (err) {
++ message = "writing rx ring-ref";
++ goto abort_transaction;
++ }
++ err = xenbus_printf(xbt, dev->nodename,
++ "event-channel", "%u", info->evtchn);
++ if (err) {
++ message = "writing event-channel";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
++ info->copying_receiver);
++ if (err) {
++ message = "writing request-rx-copy";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
++ if (err) {
++ message = "writing feature-rx-notify";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
++ if (err) {
++ message = "writing feature-sg";
++ goto abort_transaction;
++ }
++
++#ifdef HAVE_TSO
++ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
++ if (err) {
++ message = "writing feature-gso-tcpv4";
++ goto abort_transaction;
++ }
++#endif
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err) {
++ if (err == -EAGAIN)
++ goto again;
++ xenbus_dev_fatal(dev, err, "completing transaction");
++ goto destroy_ring;
++ }
++
++ return 0;
++
++ abort_transaction:
++ xenbus_transaction_end(xbt, 1);
++ xenbus_dev_fatal(dev, err, "%s", message);
++ destroy_ring:
++ netif_disconnect_backend(info);
++ out:
++ return err;
++}
++
++
++static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
++{
++ struct netif_tx_sring *txs;
++ struct netif_rx_sring *rxs;
++ int err;
++ struct net_device *netdev = info->netdev;
++
++ info->tx_ring_ref = GRANT_INVALID_REF;
++ info->rx_ring_ref = GRANT_INVALID_REF;
++ info->rx.sring = NULL;
++ info->tx.sring = NULL;
++ info->irq = 0;
++
++ txs = (struct netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
++ if (!txs) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(dev, err, "allocating tx ring page");
++ goto fail;
++ }
++ SHARED_RING_INIT(txs);
++ FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
++
++ err = xenbus_grant_ring(dev, virt_to_mfn(txs));
++ if (err < 0) {
++ free_page((unsigned long)txs);
++ goto fail;
++ }
++ info->tx_ring_ref = err;
++
++ rxs = (struct netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
++ if (!rxs) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(dev, err, "allocating rx ring page");
++ goto fail;
++ }
++ SHARED_RING_INIT(rxs);
++ FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
++
++ err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
++ if (err < 0) {
++ free_page((unsigned long)rxs);
++ goto fail;
++ }
++ info->rx_ring_ref = err;
++
++ err = xenbus_alloc_evtchn(dev, &info->evtchn);
++ if (err)
++ goto fail;
++
++ memcpy(netdev->dev_addr, info->mac, ETH_ALEN);
++ err = bind_evtchn_to_irqhandler(info->evtchn, netif_int,
++ SA_SAMPLE_RANDOM, netdev->name,
++ netdev);
++ if (err < 0)
++ goto fail;
++ info->irq = err;
++ return 0;
++
++ fail:
++ netif_free(info);
++ return err;
++}
++
++
++/**
++ * Callback received when the backend's state changes.
++ */
++static void backend_changed(struct xenbus_device *dev,
++ enum xenbus_state backend_state)
++{
++ struct netfront_info *np = dev->dev.driver_data;
++ struct net_device *netdev = np->netdev;
++
++ DPRINTK("%s\n", xenbus_strstate(backend_state));
++
++ switch (backend_state) {
++ case XenbusStateInitialising:
++ case XenbusStateInitialised:
++ case XenbusStateConnected:
++ case XenbusStateUnknown:
++ case XenbusStateClosed:
++ break;
++
++ case XenbusStateInitWait:
++ if (network_connect(netdev) != 0) {
++ netif_free(np);
++ break;
++ }
++ xenbus_switch_state(dev, XenbusStateConnected);
++ (void)send_fake_arp(netdev);
++ break;
++
++ case XenbusStateClosing:
++ netfront_closing(dev);
++ break;
++ }
++}
++
++
++/** Send a packet on a net device to encourage switches to learn the
++ * MAC. We send a fake ARP request.
++ *
++ * @param dev device
++ * @return 0 on success, error code otherwise
++ */
++static int send_fake_arp(struct net_device *dev)
++{
++ struct sk_buff *skb;
++ u32 src_ip, dst_ip;
++
++ dst_ip = INADDR_BROADCAST;
++ src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK);
++
++ /* No IP? Then nothing to do. */
++ if (src_ip == 0)
++ return 0;
++
++ skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
++ dst_ip, dev, src_ip,
++ /*dst_hw*/ NULL, /*src_hw*/ NULL,
++ /*target_hw*/ dev->dev_addr);
++ if (skb == NULL)
++ return -ENOMEM;
++
++ return dev_queue_xmit(skb);
++}
++
++
++static int network_open(struct net_device *dev)
++{
++ struct netfront_info *np = netdev_priv(dev);
++
++ memset(&np->stats, 0, sizeof(np->stats));
++
++ spin_lock(&np->rx_lock);
++ if (netif_carrier_ok(dev)) {
++ network_alloc_rx_buffers(dev);
++ np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
++ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
++ netif_rx_schedule(dev);
++ }
++ spin_unlock(&np->rx_lock);
++
++ netif_start_queue(dev);
++
++ return 0;
++}
++
++static inline int netfront_tx_slot_available(struct netfront_info *np)
++{
++ return RING_FREE_REQUESTS(&np->tx) >= MAX_SKB_FRAGS + 2;
++}
++
++static inline void network_maybe_wake_tx(struct net_device *dev)
++{
++ struct netfront_info *np = netdev_priv(dev);
++
++ if (unlikely(netif_queue_stopped(dev)) &&
++ netfront_tx_slot_available(np) &&
++ likely(netif_running(dev)))
++ netif_wake_queue(dev);
++}
++
++static void network_tx_buf_gc(struct net_device *dev)
++{
++ RING_IDX cons, prod;
++ unsigned short id;
++ struct netfront_info *np = netdev_priv(dev);
++ struct sk_buff *skb;
++
++ BUG_ON(!netif_carrier_ok(dev));
++
++ do {
++ prod = np->tx.sring->rsp_prod;
++ rmb(); /* Ensure we see responses up to 'rp'. */
++
++ for (cons = np->tx.rsp_cons; cons != prod; cons++) {
++ struct netif_tx_response *txrsp;
++
++ txrsp = RING_GET_RESPONSE(&np->tx, cons);
++ if (txrsp->status == NETIF_RSP_NULL)
++ continue;
++
++ id = txrsp->id;
++ skb = np->tx_skbs[id];
++ if (unlikely(gnttab_query_foreign_access(
++ np->grant_tx_ref[id]) != 0)) {
++ printk(KERN_ALERT "network_tx_buf_gc: warning "
++ "-- grant still in use by backend "
++ "domain.\n");
++ BUG();
++ }
++ gnttab_end_foreign_access_ref(
++ np->grant_tx_ref[id], GNTMAP_readonly);
++ gnttab_release_grant_reference(
++ &np->gref_tx_head, np->grant_tx_ref[id]);
++ np->grant_tx_ref[id] = GRANT_INVALID_REF;
++ add_id_to_freelist(np->tx_skbs, id);
++ dev_kfree_skb_irq(skb);
++ }
++
++ np->tx.rsp_cons = prod;
++
++ /*
++ * Set a new event, then check for race with update of tx_cons.
++ * Note that it is essential to schedule a callback, no matter
++ * how few buffers are pending. Even if there is space in the
++ * transmit ring, higher layers may be blocked because too much
++ * data is outstanding: in such cases notification from Xen is
++ * likely to be the only kick that we'll get.
++ */
++ np->tx.sring->rsp_event =
++ prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
++ mb();
++ } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
++
++ network_maybe_wake_tx(dev);
++}
++
++
++static void rx_refill_timeout(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ netif_rx_schedule(dev);
++}
++
++
++static void network_alloc_rx_buffers(struct net_device *dev)
++{
++ unsigned short id;
++ struct netfront_info *np = netdev_priv(dev);
++ struct sk_buff *skb;
++ struct page *page;
++ int i, batch_target, notify;
++ RING_IDX req_prod = np->rx.req_prod_pvt;
++ struct xen_memory_reservation reservation;
++ grant_ref_t ref;
++ unsigned long pfn;
++ void *vaddr;
++ int nr_flips;
++ netif_rx_request_t *req;
++
++ if (unlikely(!netif_carrier_ok(dev)))
++ return;
++
++ /*
++ * Allocate skbuffs greedily, even though we batch updates to the
++ * receive ring. This creates a less bursty demand on the memory
++ * allocator, so should reduce the chance of failed allocation requests
++ * both for ourself and for other kernel subsystems.
++ */
++ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
++ for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
++ /*
++ * Allocate an skb and a page. Do not use __dev_alloc_skb as
++ * that will allocate page-sized buffers which is not
++ * necessary here.
++ * 16 bytes added as necessary headroom for netif_receive_skb.
++ */
++ skb = alloc_skb(RX_COPY_THRESHOLD + 16,
++ GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(!skb))
++ goto no_skb;
++
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
++ if (!page) {
++ kfree_skb(skb);
++no_skb:
++ /* Any skbuffs queued for refill? Force them out. */
++ if (i != 0)
++ goto refill;
++ /* Could not allocate any skbuffs. Try again later. */
++ mod_timer(&np->rx_refill_timer,
++ jiffies + (HZ/10));
++ break;
++ }
++
++ skb_reserve(skb, 16); /* mimic dev_alloc_skb() */
++ skb_shinfo(skb)->frags[0].page = page;
++ skb_shinfo(skb)->nr_frags = 1;
++ __skb_queue_tail(&np->rx_batch, skb);
++ }
++
++ /* Is the batch large enough to be worthwhile? */
++ if (i < (np->rx_target/2)) {
++ if (req_prod > np->rx.sring->req_prod)
++ goto push;
++ return;
++ }
++
++ /* Adjust our fill target if we risked running out of buffers. */
++ if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
++ ((np->rx_target *= 2) > np->rx_max_target))
++ np->rx_target = np->rx_max_target;
++
++ refill:
++ for (nr_flips = i = 0; ; i++) {
++ if ((skb = __skb_dequeue(&np->rx_batch)) == NULL)
++ break;
++
++ skb->dev = dev;
++
++ id = xennet_rxidx(req_prod + i);
++
++ BUG_ON(np->rx_skbs[id]);
++ np->rx_skbs[id] = skb;
++
++ ref = gnttab_claim_grant_reference(&np->gref_rx_head);
++ BUG_ON((signed short)ref < 0);
++ np->grant_rx_ref[id] = ref;
++
++ pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
++ vaddr = page_address(skb_shinfo(skb)->frags[0].page);
++
++ req = RING_GET_REQUEST(&np->rx, req_prod + i);
++ if (!np->copying_receiver) {
++ gnttab_grant_foreign_transfer_ref(ref,
++ np->xbdev->otherend_id,
++ pfn);
++ np->rx_pfn_array[nr_flips] = pfn_to_mfn(pfn);
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ /* Remove this page before passing
++ * back to Xen. */
++ set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
++ MULTI_update_va_mapping(np->rx_mcl+i,
++ (unsigned long)vaddr,
++ __pte(0), 0);
++ }
++ nr_flips++;
++ } else {
++ gnttab_grant_foreign_access_ref(ref,
++ np->xbdev->otherend_id,
++ pfn_to_mfn(pfn),
++ 0);
++ }
++
++ req->id = id;
++ req->gref = ref;
++ }
++
++ if ( nr_flips != 0 ) {
++ /* Tell the ballon driver what is going on. */
++ balloon_update_driver_allowance(i);
++
++ set_xen_guest_handle(reservation.extent_start,
++ np->rx_pfn_array);
++ reservation.nr_extents = nr_flips;
++ reservation.extent_order = 0;
++ reservation.address_bits = 0;
++ reservation.domid = DOMID_SELF;
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ /* After all PTEs have been zapped, flush the TLB. */
++ np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
++ UVMF_TLB_FLUSH|UVMF_ALL;
++
++ /* Give away a batch of pages. */
++ np->rx_mcl[i].op = __HYPERVISOR_memory_op;
++ np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
++ np->rx_mcl[i].args[1] = (unsigned long)&reservation;
++
++ /* Zap PTEs and give away pages in one big
++ * multicall. */
++ (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
++
++ /* Check return status of HYPERVISOR_memory_op(). */
++ if (unlikely(np->rx_mcl[i].result != i))
++ panic("Unable to reduce memory reservation\n");
++ } else {
++ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++ &reservation) != i)
++ panic("Unable to reduce memory reservation\n");
++ }
++ } else {
++ wmb();
++ }
++
++ /* Above is a suitable barrier to ensure backend will see requests. */
++ np->rx.req_prod_pvt = req_prod + i;
++ push:
++ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
++ if (notify)
++ notify_remote_via_irq(np->irq);
++}
++
++static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
++ struct netif_tx_request *tx)
++{
++ struct netfront_info *np = netdev_priv(dev);
++ char *data = skb->data;
++ unsigned long mfn;
++ RING_IDX prod = np->tx.req_prod_pvt;
++ int frags = skb_shinfo(skb)->nr_frags;
++ unsigned int offset = offset_in_page(data);
++ unsigned int len = skb_headlen(skb);
++ unsigned int id;
++ grant_ref_t ref;
++ int i;
++
++ while (len > PAGE_SIZE - offset) {
++ tx->size = PAGE_SIZE - offset;
++ tx->flags |= NETTXF_more_data;
++ len -= tx->size;
++ data += tx->size;
++ offset = 0;
++
++ id = get_id_from_freelist(np->tx_skbs);
++ np->tx_skbs[id] = skb_get(skb);
++ tx = RING_GET_REQUEST(&np->tx, prod++);
++ tx->id = id;
++ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
++ BUG_ON((signed short)ref < 0);
++
++ mfn = virt_to_mfn(data);
++ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
++ mfn, GNTMAP_readonly);
++
++ tx->gref = np->grant_tx_ref[id] = ref;
++ tx->offset = offset;
++ tx->size = len;
++ tx->flags = 0;
++ }
++
++ for (i = 0; i < frags; i++) {
++ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
++
++ tx->flags |= NETTXF_more_data;
++
++ id = get_id_from_freelist(np->tx_skbs);
++ np->tx_skbs[id] = skb_get(skb);
++ tx = RING_GET_REQUEST(&np->tx, prod++);
++ tx->id = id;
++ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
++ BUG_ON((signed short)ref < 0);
++
++ mfn = pfn_to_mfn(page_to_pfn(frag->page));
++ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
++ mfn, GNTMAP_readonly);
++
++ tx->gref = np->grant_tx_ref[id] = ref;
++ tx->offset = frag->page_offset;
++ tx->size = frag->size;
++ tx->flags = 0;
++ }
++
++ np->tx.req_prod_pvt = prod;
++}
++
++static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ unsigned short id;
++ struct netfront_info *np = netdev_priv(dev);
++ struct netif_tx_request *tx;
++ struct netif_extra_info *extra;
++ char *data = skb->data;
++ RING_IDX i;
++ grant_ref_t ref;
++ unsigned long mfn;
++ int notify;
++ int frags = skb_shinfo(skb)->nr_frags;
++ unsigned int offset = offset_in_page(data);
++ unsigned int len = skb_headlen(skb);
++
++ frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
++ if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
++ printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
++ frags);
++ dump_stack();
++ goto drop;
++ }
++
++ spin_lock_irq(&np->tx_lock);
++
++ if (unlikely(!netif_carrier_ok(dev) ||
++ (frags > 1 && !xennet_can_sg(dev)) ||
++ netif_needs_gso(dev, skb))) {
++ spin_unlock_irq(&np->tx_lock);
++ goto drop;
++ }
++
++ i = np->tx.req_prod_pvt;
++
++ id = get_id_from_freelist(np->tx_skbs);
++ np->tx_skbs[id] = skb;
++
++ tx = RING_GET_REQUEST(&np->tx, i);
++
++ tx->id = id;
++ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
++ BUG_ON((signed short)ref < 0);
++ mfn = virt_to_mfn(data);
++ gnttab_grant_foreign_access_ref(
++ ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
++ tx->gref = np->grant_tx_ref[id] = ref;
++ tx->offset = offset;
++ tx->size = len;
++
++ tx->flags = 0;
++ extra = NULL;
++
++ if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++ tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
++#ifdef CONFIG_XEN
++ if (skb->proto_data_valid) /* remote but checksummed? */
++ tx->flags |= NETTXF_data_validated;
++#endif
++
++#ifdef HAVE_TSO
++ if (skb_is_gso(skb)) {
++ struct netif_extra_info *gso = (struct netif_extra_info *)
++ RING_GET_REQUEST(&np->tx, ++i);
++
++ if (extra)
++ extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
++ else
++ tx->flags |= NETTXF_extra_info;
++
++ gso->u.gso.size = skb_shinfo(skb)->gso_size;
++ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
++ gso->u.gso.pad = 0;
++ gso->u.gso.features = 0;
++
++ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
++ gso->flags = 0;
++ extra = gso;
++ }
++#endif
++
++ np->tx.req_prod_pvt = i + 1;
++
++ xennet_make_frags(skb, dev, tx);
++ tx->size = skb->len;
++
++ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
++ if (notify)
++ notify_remote_via_irq(np->irq);
++
++ network_tx_buf_gc(dev);
++
++ if (!netfront_tx_slot_available(np))
++ netif_stop_queue(dev);
++
++ spin_unlock_irq(&np->tx_lock);
++
++ np->stats.tx_bytes += skb->len;
++ np->stats.tx_packets++;
++
++ return 0;
++
++ drop:
++ np->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 0;
++}
++
++static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
++{
++ struct net_device *dev = dev_id;
++ struct netfront_info *np = netdev_priv(dev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&np->tx_lock, flags);
++
++ if (likely(netif_carrier_ok(dev))) {
++ network_tx_buf_gc(dev);
++ /* Under tx_lock: protects access to rx shared-ring indexes. */
++ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
++ netif_rx_schedule(dev);
++ }
++
++ spin_unlock_irqrestore(&np->tx_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
++ grant_ref_t ref)
++{
++ int new = xennet_rxidx(np->rx.req_prod_pvt);
++
++ BUG_ON(np->rx_skbs[new]);
++ np->rx_skbs[new] = skb;
++ np->grant_rx_ref[new] = ref;
++ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
++ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
++ np->rx.req_prod_pvt++;
++}
++
++int xennet_get_extras(struct netfront_info *np,
++ struct netif_extra_info *extras, RING_IDX rp)
++
++{
++ struct netif_extra_info *extra;
++ RING_IDX cons = np->rx.rsp_cons;
++ int err = 0;
++
++ do {
++ struct sk_buff *skb;
++ grant_ref_t ref;
++
++ if (unlikely(cons + 1 == rp)) {
++ if (net_ratelimit())
++ WPRINTK("Missing extra info\n");
++ err = -EBADR;
++ break;
++ }
++
++ extra = (struct netif_extra_info *)
++ RING_GET_RESPONSE(&np->rx, ++cons);
++
++ if (unlikely(!extra->type ||
++ extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++ if (net_ratelimit())
++ WPRINTK("Invalid extra type: %d\n",
++ extra->type);
++ err = -EINVAL;
++ } else {
++ memcpy(&extras[extra->type - 1], extra,
++ sizeof(*extra));
++ }
++
++ skb = xennet_get_rx_skb(np, cons);
++ ref = xennet_get_rx_ref(np, cons);
++ xennet_move_rx_slot(np, skb, ref);
++ } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
++
++ np->rx.rsp_cons = cons;
++ return err;
++}
++
++static int xennet_get_responses(struct netfront_info *np,
++ struct netfront_rx_info *rinfo, RING_IDX rp,
++ struct sk_buff_head *list,
++ int *pages_flipped_p)
++{
++ int pages_flipped = *pages_flipped_p;
++ struct mmu_update *mmu;
++ struct multicall_entry *mcl;
++ struct netif_rx_response *rx = &rinfo->rx;
++ struct netif_extra_info *extras = rinfo->extras;
++ RING_IDX cons = np->rx.rsp_cons;
++ struct sk_buff *skb = xennet_get_rx_skb(np, cons);
++ grant_ref_t ref = xennet_get_rx_ref(np, cons);
++ int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
++ int frags = 1;
++ int err = 0;
++ unsigned long ret;
++
++ if (rx->flags & NETRXF_extra_info) {
++ err = xennet_get_extras(np, extras, rp);
++ cons = np->rx.rsp_cons;
++ }
++
++ for (;;) {
++ unsigned long mfn;
++
++ if (unlikely(rx->status < 0 ||
++ rx->offset + rx->status > PAGE_SIZE)) {
++ if (net_ratelimit())
++ WPRINTK("rx->offset: %x, size: %u\n",
++ rx->offset, rx->status);
++ xennet_move_rx_slot(np, skb, ref);
++ err = -EINVAL;
++ goto next;
++ }
++
++ /*
++ * This definitely indicates a bug, either in this driver or in
++ * the backend driver. In future this should flag the bad
++ * situation to the system controller to reboot the backed.
++ */
++ if (ref == GRANT_INVALID_REF) {
++ if (net_ratelimit())
++ WPRINTK("Bad rx response id %d.\n", rx->id);
++ err = -EINVAL;
++ goto next;
++ }
++
++ if (!np->copying_receiver) {
++ /* Memory pressure, insufficient buffer
++ * headroom, ... */
++ if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) {
++ if (net_ratelimit())
++ WPRINTK("Unfulfilled rx req "
++ "(id=%d, st=%d).\n",
++ rx->id, rx->status);
++ xennet_move_rx_slot(np, skb, ref);
++ err = -ENOMEM;
++ goto next;
++ }
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ /* Remap the page. */
++ struct page *page =
++ skb_shinfo(skb)->frags[0].page;
++ unsigned long pfn = page_to_pfn(page);
++ void *vaddr = page_address(page);
++
++ mcl = np->rx_mcl + pages_flipped;
++ mmu = np->rx_mmu + pages_flipped;
++
++ MULTI_update_va_mapping(mcl,
++ (unsigned long)vaddr,
++ pfn_pte_ma(mfn,
++ PAGE_KERNEL),
++ 0);
++ mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
++ | MMU_MACHPHYS_UPDATE;
++ mmu->val = pfn;
++
++ set_phys_to_machine(pfn, mfn);
++ }
++ pages_flipped++;
++ } else {
++ ret = gnttab_end_foreign_access_ref(ref, 0);
++ BUG_ON(!ret);
++ }
++
++ gnttab_release_grant_reference(&np->gref_rx_head, ref);
++
++ __skb_queue_tail(list, skb);
++
++next:
++ if (!(rx->flags & NETRXF_more_data))
++ break;
++
++ if (cons + frags == rp) {
++ if (net_ratelimit())
++ WPRINTK("Need more frags\n");
++ err = -ENOENT;
++ break;
++ }
++
++ rx = RING_GET_RESPONSE(&np->rx, cons + frags);
++ skb = xennet_get_rx_skb(np, cons + frags);
++ ref = xennet_get_rx_ref(np, cons + frags);
++ frags++;
++ }
++
++ if (unlikely(frags > max)) {
++ if (net_ratelimit())
++ WPRINTK("Too many frags\n");
++ err = -E2BIG;
++ }
++
++ if (unlikely(err))
++ np->rx.rsp_cons = cons + frags;
++
++ *pages_flipped_p = pages_flipped;
++
++ return err;
++}
++
++static RING_IDX xennet_fill_frags(struct netfront_info *np,
++ struct sk_buff *skb,
++ struct sk_buff_head *list)
++{
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ int nr_frags = shinfo->nr_frags;
++ RING_IDX cons = np->rx.rsp_cons;
++ skb_frag_t *frag = shinfo->frags + nr_frags;
++ struct sk_buff *nskb;
++
++ while ((nskb = __skb_dequeue(list))) {
++ struct netif_rx_response *rx =
++ RING_GET_RESPONSE(&np->rx, ++cons);
++
++ frag->page = skb_shinfo(nskb)->frags[0].page;
++ frag->page_offset = rx->offset;
++ frag->size = rx->status;
++
++ skb->data_len += rx->status;
++
++ skb_shinfo(nskb)->nr_frags = 0;
++ kfree_skb(nskb);
++
++ frag++;
++ nr_frags++;
++ }
++
++ shinfo->nr_frags = nr_frags;
++ return cons;
++}
++
++static int xennet_set_skb_gso(struct sk_buff *skb,
++ struct netif_extra_info *gso)
++{
++ if (!gso->u.gso.size) {
++ if (net_ratelimit())
++ WPRINTK("GSO size must not be zero.\n");
++ return -EINVAL;
++ }
++
++ /* Currently only TCPv4 S.O. is supported. */
++ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
++ if (net_ratelimit())
++ WPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
++ return -EINVAL;
++ }
++
++#ifdef HAVE_TSO
++ skb_shinfo(skb)->gso_size = gso->u.gso.size;
++#ifdef HAVE_GSO
++ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++
++ /* Header must be checked, and gso_segs computed. */
++ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++#endif
++ skb_shinfo(skb)->gso_segs = 0;
++
++ return 0;
++#else
++ if (net_ratelimit())
++ WPRINTK("GSO unsupported by this kernel.\n");
++ return -EINVAL;
++#endif
++}
++
++static int netif_poll(struct net_device *dev, int *pbudget)
++{
++ struct netfront_info *np = netdev_priv(dev);
++ struct sk_buff *skb;
++ struct netfront_rx_info rinfo;
++ struct netif_rx_response *rx = &rinfo.rx;
++ struct netif_extra_info *extras = rinfo.extras;
++ RING_IDX i, rp;
++ struct multicall_entry *mcl;
++ int work_done, budget, more_to_do = 1;
++ struct sk_buff_head rxq;
++ struct sk_buff_head errq;
++ struct sk_buff_head tmpq;
++ unsigned long flags;
++ unsigned int len;
++ int pages_flipped = 0;
++ int err;
++
++ spin_lock(&np->rx_lock);
++
++ if (unlikely(!netif_carrier_ok(dev))) {
++ spin_unlock(&np->rx_lock);
++ return 0;
++ }
++
++ skb_queue_head_init(&rxq);
++ skb_queue_head_init(&errq);
++ skb_queue_head_init(&tmpq);
++
++ if ((budget = *pbudget) > dev->quota)
++ budget = dev->quota;
++ rp = np->rx.sring->rsp_prod;
++ rmb(); /* Ensure we see queued responses up to 'rp'. */
++
++ i = np->rx.rsp_cons;
++ work_done = 0;
++ while ((i != rp) && (work_done < budget)) {
++ memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
++ memset(extras, 0, sizeof(extras));
++
++ err = xennet_get_responses(np, &rinfo, rp, &tmpq,
++ &pages_flipped);
++
++ if (unlikely(err)) {
++err:
++ while ((skb = __skb_dequeue(&tmpq)))
++ __skb_queue_tail(&errq, skb);
++ np->stats.rx_errors++;
++ i = np->rx.rsp_cons;
++ continue;
++ }
++
++ skb = __skb_dequeue(&tmpq);
++
++ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
++ struct netif_extra_info *gso;
++ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++
++ if (unlikely(xennet_set_skb_gso(skb, gso))) {
++ __skb_queue_head(&tmpq, skb);
++ np->rx.rsp_cons += skb_queue_len(&tmpq);
++ goto err;
++ }
++ }
++
++ skb->nh.raw = (void *)skb_shinfo(skb)->frags[0].page;
++ skb->h.raw = skb->nh.raw + rx->offset;
++
++ len = rx->status;
++ if (len > RX_COPY_THRESHOLD)
++ len = RX_COPY_THRESHOLD;
++ skb_put(skb, len);
++
++ if (rx->status > len) {
++ skb_shinfo(skb)->frags[0].page_offset =
++ rx->offset + len;
++ skb_shinfo(skb)->frags[0].size = rx->status - len;
++ skb->data_len = rx->status - len;
++ } else {
++ skb_shinfo(skb)->frags[0].page = NULL;
++ skb_shinfo(skb)->nr_frags = 0;
++ }
++
++ i = xennet_fill_frags(np, skb, &tmpq);
++
++ /*
++ * Truesize must approximates the size of true data plus
++ * any supervisor overheads. Adding hypervisor overheads
++ * has been shown to significantly reduce achievable
++ * bandwidth with the default receive buffer size. It is
++ * therefore not wise to account for it here.
++ *
++ * After alloc_skb(RX_COPY_THRESHOLD), truesize is set to
++ * RX_COPY_THRESHOLD + the supervisor overheads. Here, we
++ * add the size of the data pulled in xennet_fill_frags().
++ *
++ * We also adjust for any unused space in the main data
++ * area by subtracting (RX_COPY_THRESHOLD - len). This is
++ * especially important with drivers which split incoming
++ * packets into header and data, using only 66 bytes of
++ * the main data area (see the e1000 driver for example.)
++ * On such systems, without this last adjustement, our
++ * achievable receive throughout using the standard receive
++ * buffer size was cut by 25%(!!!).
++ */
++ skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
++ skb->len += skb->data_len;
++
++ /*
++ * Old backends do not assert data_validated but we
++ * can infer it from csum_blank so test both flags.
++ */
++ if (rx->flags & (NETRXF_data_validated|NETRXF_csum_blank))
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ else
++ skb->ip_summed = CHECKSUM_NONE;
++#ifdef CONFIG_XEN
++ skb->proto_data_valid = (skb->ip_summed != CHECKSUM_NONE);
++ skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank);
++#endif
++ np->stats.rx_packets++;
++ np->stats.rx_bytes += skb->len;
++
++ __skb_queue_tail(&rxq, skb);
++
++ np->rx.rsp_cons = ++i;
++ work_done++;
++ }
++
++ if (pages_flipped) {
++ /* Some pages are no longer absent... */
++ balloon_update_driver_allowance(-pages_flipped);
++
++ /* Do all the remapping work and M2P updates. */
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ mcl = np->rx_mcl + pages_flipped;
++ mcl->op = __HYPERVISOR_mmu_update;
++ mcl->args[0] = (unsigned long)np->rx_mmu;
++ mcl->args[1] = pages_flipped;
++ mcl->args[2] = 0;
++ mcl->args[3] = DOMID_SELF;
++ (void)HYPERVISOR_multicall(np->rx_mcl,
++ pages_flipped + 1);
++ }
++ }
++
++ while ((skb = __skb_dequeue(&errq)))
++ kfree_skb(skb);
++
++ while ((skb = __skb_dequeue(&rxq)) != NULL) {
++ struct page *page = (struct page *)skb->nh.raw;
++ void *vaddr = page_address(page);
++
++ memcpy(skb->data, vaddr + (skb->h.raw - skb->nh.raw),
++ skb_headlen(skb));
++
++ if (page != skb_shinfo(skb)->frags[0].page)
++ __free_page(page);
++
++ /* Ethernet work: Delayed to here as it peeks the header. */
++ skb->protocol = eth_type_trans(skb, dev);
++
++ /* Pass it up. */
++ netif_receive_skb(skb);
++ dev->last_rx = jiffies;
++ }
++
++ /* If we get a callback with very few responses, reduce fill target. */
++ /* NB. Note exponential increase, linear decrease. */
++ if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
++ ((3*np->rx_target) / 4)) &&
++ (--np->rx_target < np->rx_min_target))
++ np->rx_target = np->rx_min_target;
++
++ network_alloc_rx_buffers(dev);
++
++ *pbudget -= work_done;
++ dev->quota -= work_done;
++
++ if (work_done < budget) {
++ local_irq_save(flags);
++
++ RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
++ if (!more_to_do)
++ __netif_rx_complete(dev);
++
++ local_irq_restore(flags);
++ }
++
++ spin_unlock(&np->rx_lock);
++
++ return more_to_do;
++}
++
++static void netif_release_tx_bufs(struct netfront_info *np)
++{
++ struct sk_buff *skb;
++ int i;
++
++ for (i = 1; i <= NET_TX_RING_SIZE; i++) {
++ if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
++ continue;
++
++ skb = np->tx_skbs[i];
++ gnttab_end_foreign_access_ref(
++ np->grant_tx_ref[i], GNTMAP_readonly);
++ gnttab_release_grant_reference(
++ &np->gref_tx_head, np->grant_tx_ref[i]);
++ np->grant_tx_ref[i] = GRANT_INVALID_REF;
++ add_id_to_freelist(np->tx_skbs, i);
++ dev_kfree_skb_irq(skb);
++ }
++}
++
++static void netif_release_rx_bufs(struct netfront_info *np)
++{
++ struct mmu_update *mmu = np->rx_mmu;
++ struct multicall_entry *mcl = np->rx_mcl;
++ struct sk_buff_head free_list;
++ struct sk_buff *skb;
++ unsigned long mfn;
++ int xfer = 0, noxfer = 0, unused = 0;
++ int id, ref;
++
++ if (np->copying_receiver) {
++ printk("%s: fix me for copying receiver.\n", __FUNCTION__);
++ return;
++ }
++
++ skb_queue_head_init(&free_list);
++
++ spin_lock(&np->rx_lock);
++
++ for (id = 0; id < NET_RX_RING_SIZE; id++) {
++ if ((ref = np->grant_rx_ref[id]) == GRANT_INVALID_REF) {
++ unused++;
++ continue;
++ }
++
++ skb = np->rx_skbs[id];
++ mfn = gnttab_end_foreign_transfer_ref(ref);
++ gnttab_release_grant_reference(&np->gref_rx_head, ref);
++ np->grant_rx_ref[id] = GRANT_INVALID_REF;
++ add_id_to_freelist(np->rx_skbs, id);
++
++ if (0 == mfn) {
++ struct page *page = skb_shinfo(skb)->frags[0].page;
++ balloon_release_driver_page(page);
++ skb_shinfo(skb)->nr_frags = 0;
++ dev_kfree_skb(skb);
++ noxfer++;
++ continue;
++ }
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ /* Remap the page. */
++ struct page *page = skb_shinfo(skb)->frags[0].page;
++ unsigned long pfn = page_to_pfn(page);
++ void *vaddr = page_address(page);
++
++ MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
++ pfn_pte_ma(mfn, PAGE_KERNEL),
++ 0);
++ mcl++;
++ mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
++ | MMU_MACHPHYS_UPDATE;
++ mmu->val = pfn;
++ mmu++;
++
++ set_phys_to_machine(pfn, mfn);
++ }
++ __skb_queue_tail(&free_list, skb);
++ xfer++;
++ }
++
++ printk("%s: %d xfer, %d noxfer, %d unused\n",
++ __FUNCTION__, xfer, noxfer, unused);
++
++ if (xfer) {
++ /* Some pages are no longer absent... */
++ balloon_update_driver_allowance(-xfer);
++
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ /* Do all the remapping work and M2P updates. */
++ mcl->op = __HYPERVISOR_mmu_update;
++ mcl->args[0] = (unsigned long)np->rx_mmu;
++ mcl->args[1] = mmu - np->rx_mmu;
++ mcl->args[2] = 0;
++ mcl->args[3] = DOMID_SELF;
++ mcl++;
++ HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
++ }
++ }
++
++ while ((skb = __skb_dequeue(&free_list)) != NULL)
++ dev_kfree_skb(skb);
++
++ spin_unlock(&np->rx_lock);
++}
++
++static int network_close(struct net_device *dev)
++{
++ struct netfront_info *np = netdev_priv(dev);
++ netif_stop_queue(np->netdev);
++ return 0;
++}
++
++
++static struct net_device_stats *network_get_stats(struct net_device *dev)
++{
++ struct netfront_info *np = netdev_priv(dev);
++ return &np->stats;
++}
++
++static int xennet_change_mtu(struct net_device *dev, int mtu)
++{
++ int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++
++ if (mtu > max)
++ return -EINVAL;
++ dev->mtu = mtu;
++ return 0;
++}
++
++static int xennet_set_sg(struct net_device *dev, u32 data)
++{
++ if (data) {
++ struct netfront_info *np = netdev_priv(dev);
++ int val;
++
++ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
++ "%d", &val) < 0)
++ val = 0;
++ if (!val)
++ return -ENOSYS;
++ } else if (dev->mtu > ETH_DATA_LEN)
++ dev->mtu = ETH_DATA_LEN;
++
++ return ethtool_op_set_sg(dev, data);
++}
++
++static int xennet_set_tso(struct net_device *dev, u32 data)
++{
++#ifdef HAVE_TSO
++ if (data) {
++ struct netfront_info *np = netdev_priv(dev);
++ int val;
++
++ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
++ "feature-gso-tcpv4", "%d", &val) < 0)
++ val = 0;
++ if (!val)
++ return -ENOSYS;
++ }
++
++ return ethtool_op_set_tso(dev, data);
++#else
++ return -ENOSYS;
++#endif
++}
++
++static void xennet_set_features(struct net_device *dev)
++{
++ dev_disable_gso_features(dev);
++ xennet_set_sg(dev, 0);
++
++ /* We need checksum offload to enable scatter/gather and TSO. */
++ if (!(dev->features & NETIF_F_IP_CSUM))
++ return;
++
++ if (!xennet_set_sg(dev, 1))
++ xennet_set_tso(dev, 1);
++}
++
++static int network_connect(struct net_device *dev)
++{
++ struct netfront_info *np = netdev_priv(dev);
++ int i, requeue_idx, err;
++ struct sk_buff *skb;
++ grant_ref_t ref;
++ netif_rx_request_t *req;
++ unsigned int feature_rx_copy, feature_rx_flip;
++
++ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
++ "feature-rx-copy", "%u", &feature_rx_copy);
++ if (err != 1)
++ feature_rx_copy = 0;
++ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
++ "feature-rx-flip", "%u", &feature_rx_flip);
++ if (err != 1)
++ feature_rx_flip = 1;
++
++ /*
++ * Copy packets on receive path if:
++ * (a) This was requested by user, and the backend supports it; or
++ * (b) Flipping was requested, but this is unsupported by the backend.
++ */
++ np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
++ (MODPARM_rx_flip && !feature_rx_flip));
++
++ err = talk_to_backend(np->xbdev, np);
++ if (err)
++ return err;
++
++ xennet_set_features(dev);
++
++ IPRINTK("device %s has %sing receive path.\n",
++ dev->name, np->copying_receiver ? "copy" : "flipp");
++
++ spin_lock_irq(&np->tx_lock);
++ spin_lock(&np->rx_lock);
++
++ /*
++ * Recovery procedure:
++ * NB. Freelist index entries are always going to be less than
++ * PAGE_OFFSET, whereas pointers to skbs will always be equal or
++ * greater than PAGE_OFFSET: we use this property to distinguish
++ * them.
++ */
++
++ /* Step 1: Discard all pending TX packet fragments. */
++ netif_release_tx_bufs(np);
++
++ /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
++ for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
++ if (!np->rx_skbs[i])
++ continue;
++
++ skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
++ ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
++ req = RING_GET_REQUEST(&np->rx, requeue_idx);
++
++ if (!np->copying_receiver) {
++ gnttab_grant_foreign_transfer_ref(
++ ref, np->xbdev->otherend_id,
++ page_to_pfn(skb_shinfo(skb)->frags->page));
++ } else {
++ gnttab_grant_foreign_access_ref(
++ ref, np->xbdev->otherend_id,
++ pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
++ frags->page)),
++ 0);
++ }
++ req->gref = ref;
++ req->id = requeue_idx;
++
++ requeue_idx++;
++ }
++
++ np->rx.req_prod_pvt = requeue_idx;
++
++ /*
++ * Step 3: All public and private state should now be sane. Get
++ * ready to start sending and receiving packets and give the driver
++ * domain a kick because we've probably just requeued some
++ * packets.
++ */
++ netif_carrier_on(dev);
++ notify_remote_via_irq(np->irq);
++ network_tx_buf_gc(dev);
++ network_alloc_rx_buffers(dev);
++
++ spin_unlock(&np->rx_lock);
++ spin_unlock_irq(&np->tx_lock);
++
++ return 0;
++}
++
++static void netif_uninit(struct net_device *dev)
++{
++ struct netfront_info *np = netdev_priv(dev);
++ netif_release_tx_bufs(np);
++ netif_release_rx_bufs(np);
++ gnttab_free_grant_references(np->gref_tx_head);
++ gnttab_free_grant_references(np->gref_rx_head);
++}
++
++static struct ethtool_ops network_ethtool_ops =
++{
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = ethtool_op_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = xennet_set_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = xennet_set_tso,
++ .get_link = ethtool_op_get_link,
++};
++
++#ifdef CONFIG_SYSFS
++static ssize_t show_rxbuf_min(struct class_device *cd, char *buf)
++{
++ struct net_device *netdev = container_of(cd, struct net_device,
++ class_dev);
++ struct netfront_info *info = netdev_priv(netdev);
++
++ return sprintf(buf, "%u\n", info->rx_min_target);
++}
++
++static ssize_t store_rxbuf_min(struct class_device *cd,
++ const char *buf, size_t len)
++{
++ struct net_device *netdev = container_of(cd, struct net_device,
++ class_dev);
++ struct netfront_info *np = netdev_priv(netdev);
++ char *endp;
++ unsigned long target;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ target = simple_strtoul(buf, &endp, 0);
++ if (endp == buf)
++ return -EBADMSG;
++
++ if (target < RX_MIN_TARGET)
++ target = RX_MIN_TARGET;
++ if (target > RX_MAX_TARGET)
++ target = RX_MAX_TARGET;
++
++ spin_lock(&np->rx_lock);
++ if (target > np->rx_max_target)
++ np->rx_max_target = target;
++ np->rx_min_target = target;
++ if (target > np->rx_target)
++ np->rx_target = target;
++
++ network_alloc_rx_buffers(netdev);
++
++ spin_unlock(&np->rx_lock);
++ return len;
++}
++
++static ssize_t show_rxbuf_max(struct class_device *cd, char *buf)
++{
++ struct net_device *netdev = container_of(cd, struct net_device,
++ class_dev);
++ struct netfront_info *info = netdev_priv(netdev);
++
++ return sprintf(buf, "%u\n", info->rx_max_target);
++}
++
++static ssize_t store_rxbuf_max(struct class_device *cd,
++ const char *buf, size_t len)
++{
++ struct net_device *netdev = container_of(cd, struct net_device,
++ class_dev);
++ struct netfront_info *np = netdev_priv(netdev);
++ char *endp;
++ unsigned long target;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ target = simple_strtoul(buf, &endp, 0);
++ if (endp == buf)
++ return -EBADMSG;
++
++ if (target < RX_MIN_TARGET)
++ target = RX_MIN_TARGET;
++ if (target > RX_MAX_TARGET)
++ target = RX_MAX_TARGET;
++
++ spin_lock(&np->rx_lock);
++ if (target < np->rx_min_target)
++ np->rx_min_target = target;
++ np->rx_max_target = target;
++ if (target < np->rx_target)
++ np->rx_target = target;
++
++ network_alloc_rx_buffers(netdev);
++
++ spin_unlock(&np->rx_lock);
++ return len;
++}
++
++static ssize_t show_rxbuf_cur(struct class_device *cd, char *buf)
++{
++ struct net_device *netdev = container_of(cd, struct net_device,
++ class_dev);
++ struct netfront_info *info = netdev_priv(netdev);
++
++ return sprintf(buf, "%u\n", info->rx_target);
++}
++
++static const struct class_device_attribute xennet_attrs[] = {
++ __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
++ __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
++ __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
++};
++
++static int xennet_sysfs_addif(struct net_device *netdev)
++{
++ int i;
++ int error = 0;
++
++ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
++ error = class_device_create_file(&netdev->class_dev,
++ &xennet_attrs[i]);
++ if (error)
++ goto fail;
++ }
++ return 0;
++
++ fail:
++ while (--i >= 0)
++ class_device_remove_file(&netdev->class_dev,
++ &xennet_attrs[i]);
++ return error;
++}
++
++static void xennet_sysfs_delif(struct net_device *netdev)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
++ class_device_remove_file(&netdev->class_dev,
++ &xennet_attrs[i]);
++ }
++}
++
++#endif /* CONFIG_SYSFS */
++
++
++/*
++ * Nothing to do here. Virtual interface is point-to-point and the
++ * physical interface is probably promiscuous anyway.
++ */
++static void network_set_multicast_list(struct net_device *dev)
++{
++}
++
++static struct net_device * __devinit create_netdev(struct xenbus_device *dev)
++{
++ int i, err = 0;
++ struct net_device *netdev = NULL;
++ struct netfront_info *np = NULL;
++
++ netdev = alloc_etherdev(sizeof(struct netfront_info));
++ if (!netdev) {
++ printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
++ __FUNCTION__);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ np = netdev_priv(netdev);
++ np->xbdev = dev;
++
++ netif_carrier_off(netdev);
++
++ spin_lock_init(&np->tx_lock);
++ spin_lock_init(&np->rx_lock);
++
++ skb_queue_head_init(&np->rx_batch);
++ np->rx_target = RX_DFL_MIN_TARGET;
++ np->rx_min_target = RX_DFL_MIN_TARGET;
++ np->rx_max_target = RX_MAX_TARGET;
++
++ init_timer(&np->rx_refill_timer);
++ np->rx_refill_timer.data = (unsigned long)netdev;
++ np->rx_refill_timer.function = rx_refill_timeout;
++
++ /* Initialise {tx,rx}_skbs as a free chain containing every entry. */
++ for (i = 0; i <= NET_TX_RING_SIZE; i++) {
++ np->tx_skbs[i] = (void *)((unsigned long) i+1);
++ np->grant_tx_ref[i] = GRANT_INVALID_REF;
++ }
++
++ for (i = 0; i < NET_RX_RING_SIZE; i++) {
++ np->rx_skbs[i] = NULL;
++ np->grant_rx_ref[i] = GRANT_INVALID_REF;
++ }
++
++ /* A grant for every tx ring slot */
++ if (gnttab_alloc_grant_references(TX_MAX_TARGET,
++ &np->gref_tx_head) < 0) {
++ printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
++ err = -ENOMEM;
++ goto exit;
++ }
++ /* A grant for every rx ring slot */
++ if (gnttab_alloc_grant_references(RX_MAX_TARGET,
++ &np->gref_rx_head) < 0) {
++ printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
++ err = -ENOMEM;
++ goto exit_free_tx;
++ }
++
++ netdev->open = network_open;
++ netdev->hard_start_xmit = network_start_xmit;
++ netdev->stop = network_close;
++ netdev->get_stats = network_get_stats;
++ netdev->poll = netif_poll;
++ netdev->set_multicast_list = network_set_multicast_list;
++ netdev->uninit = netif_uninit;
++ netdev->change_mtu = xennet_change_mtu;
++ netdev->weight = 64;
++ netdev->features = NETIF_F_IP_CSUM;
++
++ SET_ETHTOOL_OPS(netdev, &network_ethtool_ops);
++ SET_MODULE_OWNER(netdev);
++ SET_NETDEV_DEV(netdev, &dev->dev);
++
++ np->netdev = netdev;
++ return netdev;
++
++ exit_free_tx:
++ gnttab_free_grant_references(np->gref_tx_head);
++ exit:
++ free_netdev(netdev);
++ return ERR_PTR(err);
++}
++
++/*
++ * We use this notifier to send out a fake ARP reply to reset switches and
++ * router ARP caches when an IP interface is brought up on a VIF.
++ */
++static int
++inetdev_notify(struct notifier_block *this, unsigned long event, void *ptr)
++{
++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
++ struct net_device *dev = ifa->ifa_dev->dev;
++
++ /* UP event and is it one of our devices? */
++ if (event == NETDEV_UP && dev->open == network_open)
++ (void)send_fake_arp(dev);
++
++ return NOTIFY_DONE;
++}
++
++
++/* ** Close down ** */
++
++
++/**
++ * Handle the change of state of the backend to Closing. We must delete our
++ * device-layer structures now, to ensure that writes are flushed through to
++ * the backend. Once is this done, we can switch to Closed in
++ * acknowledgement.
++ */
++static void netfront_closing(struct xenbus_device *dev)
++{
++ struct netfront_info *info = dev->dev.driver_data;
++
++ DPRINTK("%s\n", dev->nodename);
++
++ close_netdev(info);
++ xenbus_frontend_closed(dev);
++}
++
++
++static int __devexit netfront_remove(struct xenbus_device *dev)
++{
++ struct netfront_info *info = dev->dev.driver_data;
++
++ DPRINTK("%s\n", dev->nodename);
++
++ netif_disconnect_backend(info);
++ free_netdev(info->netdev);
++
++ return 0;
++}
++
++
++static int open_netdev(struct netfront_info *info)
++{
++ int err;
++
++ err = register_netdev(info->netdev);
++ if (err) {
++ printk(KERN_WARNING "%s: register_netdev err=%d\n",
++ __FUNCTION__, err);
++ return err;
++ }
++
++ err = xennet_sysfs_addif(info->netdev);
++ if (err) {
++ unregister_netdev(info->netdev);
++ printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
++ __FUNCTION__, err);
++ return err;
++ }
++
++ return 0;
++}
++
++static void close_netdev(struct netfront_info *info)
++{
++ del_timer_sync(&info->rx_refill_timer);
++
++ xennet_sysfs_delif(info->netdev);
++ unregister_netdev(info->netdev);
++}
++
++
++static void netif_disconnect_backend(struct netfront_info *info)
++{
++ /* Stop old i/f to prevent errors whilst we rebuild the state. */
++ spin_lock_irq(&info->tx_lock);
++ spin_lock(&info->rx_lock);
++ netif_carrier_off(info->netdev);
++ spin_unlock(&info->rx_lock);
++ spin_unlock_irq(&info->tx_lock);
++
++ if (info->irq)
++ unbind_from_irqhandler(info->irq, info->netdev);
++ info->evtchn = info->irq = 0;
++
++ end_access(info->tx_ring_ref, info->tx.sring);
++ end_access(info->rx_ring_ref, info->rx.sring);
++ info->tx_ring_ref = GRANT_INVALID_REF;
++ info->rx_ring_ref = GRANT_INVALID_REF;
++ info->tx.sring = NULL;
++ info->rx.sring = NULL;
++}
++
++
++static void netif_free(struct netfront_info *info)
++{
++ close_netdev(info);
++ netif_disconnect_backend(info);
++ free_netdev(info->netdev);
++}
++
++
++static void end_access(int ref, void *page)
++{
++ if (ref != GRANT_INVALID_REF)
++ gnttab_end_foreign_access(ref, 0, (unsigned long)page);
++}
++
++
++/* ** Driver registration ** */
++
++
++static struct xenbus_device_id netfront_ids[] = {
++ { "vif" },
++ { "" }
++};
++
++
++static struct xenbus_driver netfront = {
++ .name = "vif",
++ .owner = THIS_MODULE,
++ .ids = netfront_ids,
++ .probe = netfront_probe,
++ .remove = __devexit_p(netfront_remove),
++ .resume = netfront_resume,
++ .otherend_changed = backend_changed,
++};
++
++
++static struct notifier_block notifier_inetdev = {
++ .notifier_call = inetdev_notify,
++ .next = NULL,
++ .priority = 0
++};
++
++static int __init netif_init(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++#ifdef CONFIG_XEN
++ if (MODPARM_rx_flip && MODPARM_rx_copy) {
++ WPRINTK("Cannot specify both rx_copy and rx_flip.\n");
++ return -EINVAL;
++ }
++
++ if (!MODPARM_rx_flip && !MODPARM_rx_copy)
++ MODPARM_rx_flip = 1; /* Default is to flip. */
++#endif
++
++ if (is_initial_xendomain())
++ return 0;
++
++ IPRINTK("Initialising virtual ethernet driver.\n");
++
++ (void)register_inetaddr_notifier(¬ifier_inetdev);
++
++ return xenbus_register_frontend(&netfront);
++}
++module_init(netif_init);
++
++
++static void __exit netif_exit(void)
++{
++ unregister_inetaddr_notifier(¬ifier_inetdev);
++
++ return xenbus_unregister_driver(&netfront);
++}
++module_exit(netif_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space.c linux-2.6.18-xen/drivers/xen/pciback/conf_space.c
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,425 @@
++/*
++ * PCI Backend - Functions for creating a virtual configuration space for
++ * exported PCI Devices.
++ * It's dangerous to allow PCI Driver Domains to change their
++ * device's resources (memory, i/o ports, interrupts). We need to
++ * restrict changes to certain PCI Configuration registers:
++ * BARs, INTERRUPT_PIN, most registers in the header...
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++#define DEFINE_PCI_CONFIG(op,size,type) \
++int pciback_##op##_config_##size \
++(struct pci_dev *dev, int offset, type value, void *data) \
++{ \
++ return pci_##op##_config_##size (dev, offset, value); \
++}
++
++DEFINE_PCI_CONFIG(read, byte, u8 *)
++DEFINE_PCI_CONFIG(read, word, u16 *)
++DEFINE_PCI_CONFIG(read, dword, u32 *)
++
++DEFINE_PCI_CONFIG(write, byte, u8)
++DEFINE_PCI_CONFIG(write, word, u16)
++DEFINE_PCI_CONFIG(write, dword, u32)
++
++static int conf_space_read(struct pci_dev *dev,
++ struct config_field_entry *entry, int offset,
++ u32 * value)
++{
++ int ret = 0;
++ struct config_field *field = entry->field;
++
++ *value = 0;
++
++ switch (field->size) {
++ case 1:
++ if (field->u.b.read)
++ ret = field->u.b.read(dev, offset, (u8 *) value,
++ entry->data);
++ break;
++ case 2:
++ if (field->u.w.read)
++ ret = field->u.w.read(dev, offset, (u16 *) value,
++ entry->data);
++ break;
++ case 4:
++ if (field->u.dw.read)
++ ret = field->u.dw.read(dev, offset, value, entry->data);
++ break;
++ }
++ return ret;
++}
++
++static int conf_space_write(struct pci_dev *dev,
++ struct config_field_entry *entry, int offset,
++ u32 value)
++{
++ int ret = 0;
++ struct config_field *field = entry->field;
++
++ switch (field->size) {
++ case 1:
++ if (field->u.b.write)
++ ret = field->u.b.write(dev, offset, (u8) value,
++ entry->data);
++ break;
++ case 2:
++ if (field->u.w.write)
++ ret = field->u.w.write(dev, offset, (u16) value,
++ entry->data);
++ break;
++ case 4:
++ if (field->u.dw.write)
++ ret = field->u.dw.write(dev, offset, value,
++ entry->data);
++ break;
++ }
++ return ret;
++}
++
++static inline u32 get_mask(int size)
++{
++ if (size == 1)
++ return 0xff;
++ else if (size == 2)
++ return 0xffff;
++ else
++ return 0xffffffff;
++}
++
++static inline int valid_request(int offset, int size)
++{
++ /* Validate request (no un-aligned requests) */
++ if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
++ return 1;
++ return 0;
++}
++
++static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
++ int offset)
++{
++ if (offset >= 0) {
++ new_val_mask <<= (offset * 8);
++ new_val <<= (offset * 8);
++ } else {
++ new_val_mask >>= (offset * -8);
++ new_val >>= (offset * -8);
++ }
++ val = (val & ~new_val_mask) | (new_val & new_val_mask);
++
++ return val;
++}
++
++static int pcibios_err_to_errno(int err)
++{
++ switch (err) {
++ case PCIBIOS_SUCCESSFUL:
++ return XEN_PCI_ERR_success;
++ case PCIBIOS_DEVICE_NOT_FOUND:
++ return XEN_PCI_ERR_dev_not_found;
++ case PCIBIOS_BAD_REGISTER_NUMBER:
++ return XEN_PCI_ERR_invalid_offset;
++ case PCIBIOS_FUNC_NOT_SUPPORTED:
++ return XEN_PCI_ERR_not_implemented;
++ case PCIBIOS_SET_FAILED:
++ return XEN_PCI_ERR_access_denied;
++ }
++ return err;
++}
++
++int pciback_config_read(struct pci_dev *dev, int offset, int size,
++ u32 * ret_val)
++{
++ int err = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry;
++ struct config_field *field;
++ int req_start, req_end, field_start, field_end;
++ /* if read fails for any reason, return 0 (as if device didn't respond) */
++ u32 value = 0, tmp_val;
++
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
++ pci_name(dev), size, offset);
++
++ if (!valid_request(offset, size)) {
++ err = XEN_PCI_ERR_invalid_offset;
++ goto out;
++ }
++
++ /* Get the real value first, then modify as appropriate */
++ switch (size) {
++ case 1:
++ err = pci_read_config_byte(dev, offset, (u8 *) & value);
++ break;
++ case 2:
++ err = pci_read_config_word(dev, offset, (u16 *) & value);
++ break;
++ case 4:
++ err = pci_read_config_dword(dev, offset, &value);
++ break;
++ }
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ req_start = offset;
++ req_end = offset + size;
++ field_start = OFFSET(cfg_entry);
++ field_end = OFFSET(cfg_entry) + field->size;
++
++ if ((req_start >= field_start && req_start < field_end)
++ || (req_end > field_start && req_end <= field_end)) {
++ err = conf_space_read(dev, cfg_entry, field_start,
++ &tmp_val);
++ if (err)
++ goto out;
++
++ value = merge_value(value, tmp_val,
++ get_mask(field->size),
++ field_start - req_start);
++ }
++ }
++
++ out:
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
++ pci_name(dev), size, offset, value);
++
++ *ret_val = value;
++ return pcibios_err_to_errno(err);
++}
++
++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
++{
++ int err = 0, handled = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry;
++ struct config_field *field;
++ u32 tmp_val;
++ int req_start, req_end, field_start, field_end;
++
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG
++ "pciback: %s: write request %d bytes at 0x%x = %x\n",
++ pci_name(dev), size, offset, value);
++
++ if (!valid_request(offset, size))
++ return XEN_PCI_ERR_invalid_offset;
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ req_start = offset;
++ req_end = offset + size;
++ field_start = OFFSET(cfg_entry);
++ field_end = OFFSET(cfg_entry) + field->size;
++
++ if ((req_start >= field_start && req_start < field_end)
++ || (req_end > field_start && req_end <= field_end)) {
++ tmp_val = 0;
++
++ err = pciback_config_read(dev, field_start,
++ field->size, &tmp_val);
++ if (err)
++ break;
++
++ tmp_val = merge_value(tmp_val, value, get_mask(size),
++ req_start - field_start);
++
++ err = conf_space_write(dev, cfg_entry, field_start,
++ tmp_val);
++
++ /* handled is set true here, but not every byte
++ * may have been written! Properly detecting if
++ * every byte is handled is unnecessary as the
++ * flag is used to detect devices that need
++ * special helpers to work correctly.
++ */
++ handled = 1;
++ }
++ }
++
++ if (!handled && !err) {
++ /* By default, anything not specificially handled above is
++ * read-only. The permissive flag changes this behavior so
++ * that anything not specifically handled above is writable.
++ * This means that some fields may still be read-only because
++ * they have entries in the config_field list that intercept
++ * the write and do nothing. */
++ if (dev_data->permissive) {
++ switch (size) {
++ case 1:
++ err = pci_write_config_byte(dev, offset,
++ (u8) value);
++ break;
++ case 2:
++ err = pci_write_config_word(dev, offset,
++ (u16) value);
++ break;
++ case 4:
++ err = pci_write_config_dword(dev, offset,
++ (u32) value);
++ break;
++ }
++ } else if (!dev_data->warned_on_write) {
++ dev_data->warned_on_write = 1;
++ dev_warn(&dev->dev, "Driver tried to write to a "
++ "read-only configuration space field at offset "
++ "0x%x, size %d. This may be harmless, but if "
++ "you have problems with your device:\n"
++ "1) see permissive attribute in sysfs\n"
++ "2) report problems to the xen-devel "
++ "mailing list along with details of your "
++ "device obtained from lspci.\n", offset, size);
++ }
++ }
++
++ return pcibios_err_to_errno(err);
++}
++
++void pciback_config_free_dyn_fields(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry, *t;
++ struct config_field *field;
++
++ dev_dbg(&dev->dev,
++ "free-ing dynamically allocated virtual configuration space fields\n");
++
++ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ if (field->clean) {
++ field->clean(field);
++
++ if (cfg_entry->data)
++ kfree(cfg_entry->data);
++
++ list_del(&cfg_entry->list);
++ kfree(cfg_entry);
++ }
++
++ }
++}
++
++void pciback_config_reset_dev(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry;
++ struct config_field *field;
++
++ dev_dbg(&dev->dev, "resetting virtual configuration space\n");
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ if (field->reset)
++ field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
++ }
++}
++
++void pciback_config_free_dev(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry, *t;
++ struct config_field *field;
++
++ dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
++
++ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
++ list_del(&cfg_entry->list);
++
++ field = cfg_entry->field;
++
++ if (field->release)
++ field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
++
++ kfree(cfg_entry);
++ }
++}
++
++int pciback_config_add_field_offset(struct pci_dev *dev,
++ struct config_field *field,
++ unsigned int offset)
++{
++ int err = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry;
++ void *tmp;
++
++ /* silently ignore duplicate fields */
++ if (pciback_field_is_dup(dev, field->offset))
++ goto out;
++
++ cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
++ if (!cfg_entry) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ cfg_entry->data = NULL;
++ cfg_entry->field = field;
++ cfg_entry->base_offset = offset;
++
++ if (field->init) {
++ tmp = field->init(dev, OFFSET(cfg_entry));
++
++ if (IS_ERR(tmp)) {
++ err = PTR_ERR(tmp);
++ goto out;
++ }
++
++ cfg_entry->data = tmp;
++ }
++
++ dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
++ OFFSET(cfg_entry));
++ list_add_tail(&cfg_entry->list, &dev_data->config_fields);
++
++ out:
++ if (err)
++ kfree(cfg_entry);
++
++ return err;
++}
++
++/* This sets up the device's virtual configuration space to keep track of
++ * certain registers (like the base address registers (BARs) so that we can
++ * keep the client from manipulating them directly.
++ */
++int pciback_config_init_dev(struct pci_dev *dev)
++{
++ int err = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++
++ dev_dbg(&dev->dev, "initializing virtual configuration space\n");
++
++ INIT_LIST_HEAD(&dev_data->config_fields);
++
++ err = pciback_config_header_add_fields(dev);
++ if (err)
++ goto out;
++
++ err = pciback_config_capability_add_fields(dev);
++ if (err)
++ goto out;
++
++ err = pciback_config_quirks_init(dev);
++
++ out:
++ return err;
++}
++
++int pciback_config_init(void)
++{
++ return pciback_config_capability_init();
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_capability.c linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability.c
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_capability.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,71 @@
++/*
++ * PCI Backend - Handles the virtual fields found on the capability lists
++ * in the configuration space.
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static LIST_HEAD(capabilities);
++
++static struct config_field caplist_header[] = {
++ {
++ .offset = PCI_CAP_LIST_ID,
++ .size = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = NULL,
++ },
++ {
++ .size = 0,
++ },
++};
++
++static inline void register_capability(struct pciback_config_capability *cap)
++{
++ list_add_tail(&cap->cap_list, &capabilities);
++}
++
++int pciback_config_capability_add_fields(struct pci_dev *dev)
++{
++ int err = 0;
++ struct pciback_config_capability *cap;
++ int cap_offset;
++
++ list_for_each_entry(cap, &capabilities, cap_list) {
++ cap_offset = pci_find_capability(dev, cap->capability);
++ if (cap_offset) {
++ dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n",
++ cap->capability, cap_offset);
++
++ err = pciback_config_add_fields_offset(dev,
++ caplist_header,
++ cap_offset);
++ if (err)
++ goto out;
++ err = pciback_config_add_fields_offset(dev,
++ cap->fields,
++ cap_offset);
++ if (err)
++ goto out;
++ }
++ }
++
++ out:
++ return err;
++}
++
++extern struct pciback_config_capability pciback_config_capability_vpd;
++extern struct pciback_config_capability pciback_config_capability_pm;
++
++int pciback_config_capability_init(void)
++{
++ register_capability(&pciback_config_capability_vpd);
++ register_capability(&pciback_config_capability_pm);
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_capability.h linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability.h
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_capability.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,23 @@
++/*
++ * PCI Backend - Data structures for special overlays for structures on
++ * the capability list.
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#ifndef __PCIBACK_CONFIG_CAPABILITY_H__
++#define __PCIBACK_CONFIG_CAPABILITY_H__
++
++#include <linux/pci.h>
++#include <linux/list.h>
++
++struct pciback_config_capability {
++ struct list_head cap_list;
++
++ int capability;
++
++ /* If the device has the capability found above, add these fields */
++ struct config_field *fields;
++};
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_capability_pm.c linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability_pm.c
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_capability_pm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability_pm.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ * PCI Backend - Configuration space overlay for power management
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
++ void *data)
++{
++ int err;
++ u16 real_value;
++
++ err = pci_read_config_word(dev, offset, &real_value);
++ if (err)
++ goto out;
++
++ *value = real_value & ~PCI_PM_CAP_PME_MASK;
++
++ out:
++ return err;
++}
++
++/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
++ * Can't allow driver domain to enable PMEs - they're shared */
++#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
++
++static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
++ void *data)
++{
++ int err;
++ u16 cur_value;
++ pci_power_t new_state;
++
++ /* Handle setting power state separately */
++ new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
++
++ err = pci_read_config_word(dev, offset, &cur_value);
++ if (err)
++ goto out;
++
++ new_value &= PM_OK_BITS;
++ if ((cur_value & PM_OK_BITS) != new_value) {
++ new_value = (cur_value & ~PM_OK_BITS) | new_value;
++ err = pci_write_config_word(dev, offset, new_value);
++ if (err)
++ goto out;
++ }
++
++ /* Let pci core handle the power management change */
++ dev_dbg(&dev->dev, "set power state to %x\n", new_state);
++ err = pci_set_power_state(dev, new_state);
++ if (err)
++ err = PCIBIOS_SET_FAILED;
++
++ out:
++ return err;
++}
++
++/* Ensure PMEs are disabled */
++static void *pm_ctrl_init(struct pci_dev *dev, int offset)
++{
++ int err;
++ u16 value;
++
++ err = pci_read_config_word(dev, offset, &value);
++ if (err)
++ goto out;
++
++ if (value & PCI_PM_CTRL_PME_ENABLE) {
++ value &= ~PCI_PM_CTRL_PME_ENABLE;
++ err = pci_write_config_word(dev, offset, value);
++ }
++
++ out:
++ return ERR_PTR(err);
++}
++
++static struct config_field caplist_pm[] = {
++ {
++ .offset = PCI_PM_PMC,
++ .size = 2,
++ .u.w.read = pm_caps_read,
++ },
++ {
++ .offset = PCI_PM_CTRL,
++ .size = 2,
++ .init = pm_ctrl_init,
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = pm_ctrl_write,
++ },
++ {
++ .offset = PCI_PM_PPB_EXTENSIONS,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ .offset = PCI_PM_DATA_REGISTER,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ .size = 0,
++ },
++};
++
++struct pciback_config_capability pciback_config_capability_pm = {
++ .capability = PCI_CAP_ID_PM,
++ .fields = caplist_pm,
++};
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_capability_vpd.c linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability_vpd.c
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_capability_vpd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_capability_vpd.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,42 @@
++/*
++ * PCI Backend - Configuration space overlay for Vital Product Data
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static int vpd_address_write(struct pci_dev *dev, int offset, u16 value,
++ void *data)
++{
++ /* Disallow writes to the vital product data */
++ if (value & PCI_VPD_ADDR_F)
++ return PCIBIOS_SET_FAILED;
++ else
++ return pci_write_config_word(dev, offset, value);
++}
++
++static struct config_field caplist_vpd[] = {
++ {
++ .offset = PCI_VPD_ADDR,
++ .size = 2,
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = vpd_address_write,
++ },
++ {
++ .offset = PCI_VPD_DATA,
++ .size = 4,
++ .u.dw.read = pciback_read_config_dword,
++ .u.dw.write = NULL,
++ },
++ {
++ .size = 0,
++ },
++};
++
++struct pciback_config_capability pciback_config_capability_vpd = {
++ .capability = PCI_CAP_ID_VPD,
++ .fields = caplist_vpd,
++};
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space.h linux-2.6.18-xen/drivers/xen/pciback/conf_space.h
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,126 @@
++/*
++ * PCI Backend - Common data structures for overriding the configuration space
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#ifndef __XEN_PCIBACK_CONF_SPACE_H__
++#define __XEN_PCIBACK_CONF_SPACE_H__
++
++#include <linux/list.h>
++#include <linux/err.h>
++
++/* conf_field_init can return an errno in a ptr with ERR_PTR() */
++typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
++typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
++typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
++
++typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
++ void *data);
++typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
++ void *data);
++typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
++ void *data);
++typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
++ void *data);
++typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
++ void *data);
++typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
++ void *data);
++
++/* These are the fields within the configuration space which we
++ * are interested in intercepting reads/writes to and changing their
++ * values.
++ */
++struct config_field {
++ unsigned int offset;
++ unsigned int size;
++ unsigned int mask;
++ conf_field_init init;
++ conf_field_reset reset;
++ conf_field_free release;
++ void (*clean) (struct config_field * field);
++ union {
++ struct {
++ conf_dword_write write;
++ conf_dword_read read;
++ } dw;
++ struct {
++ conf_word_write write;
++ conf_word_read read;
++ } w;
++ struct {
++ conf_byte_write write;
++ conf_byte_read read;
++ } b;
++ } u;
++ struct list_head list;
++};
++
++struct config_field_entry {
++ struct list_head list;
++ struct config_field *field;
++ unsigned int base_offset;
++ void *data;
++};
++
++#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
++
++/* Add fields to a device - the add_fields macro expects to get a pointer to
++ * the first entry in an array (of which the ending is marked by size==0)
++ */
++int pciback_config_add_field_offset(struct pci_dev *dev,
++ struct config_field *field,
++ unsigned int offset);
++
++static inline int pciback_config_add_field(struct pci_dev *dev,
++ struct config_field *field)
++{
++ return pciback_config_add_field_offset(dev, field, 0);
++}
++
++static inline int pciback_config_add_fields(struct pci_dev *dev,
++ struct config_field *field)
++{
++ int i, err = 0;
++ for (i = 0; field[i].size != 0; i++) {
++ err = pciback_config_add_field(dev, &field[i]);
++ if (err)
++ break;
++ }
++ return err;
++}
++
++static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
++ struct config_field *field,
++ unsigned int offset)
++{
++ int i, err = 0;
++ for (i = 0; field[i].size != 0; i++) {
++ err = pciback_config_add_field_offset(dev, &field[i], offset);
++ if (err)
++ break;
++ }
++ return err;
++}
++
++/* Read/Write the real configuration space */
++int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
++ void *data);
++int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
++ void *data);
++int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
++ void *data);
++int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
++ void *data);
++int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
++ void *data);
++int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
++ void *data);
++
++int pciback_config_capability_init(void);
++
++int pciback_config_header_add_fields(struct pci_dev *dev);
++int pciback_config_capability_add_fields(struct pci_dev *dev);
++
++#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_header.c linux-2.6.18-xen/drivers/xen/pciback/conf_space_header.c
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_header.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_header.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,299 @@
++/*
++ * PCI Backend - Handles the virtual fields in the configuration space headers.
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++
++struct pci_bar_info {
++ u32 val;
++ u32 len_val;
++ int which;
++};
++
++#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
++#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
++
++static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
++{
++ if (!dev->is_enabled && is_enable_cmd(value)) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: enable\n",
++ pci_name(dev));
++ pci_enable_device(dev);
++ } else if (dev->is_enabled && !is_enable_cmd(value)) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: disable\n",
++ pci_name(dev));
++ pci_disable_device(dev);
++ }
++
++ if (!dev->is_busmaster && is_master_cmd(value)) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: set bus master\n",
++ pci_name(dev));
++ pci_set_master(dev);
++ }
++
++ if (value & PCI_COMMAND_INVALIDATE) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG
++ "pciback: %s: enable memory-write-invalidate\n",
++ pci_name(dev));
++ pci_set_mwi(dev);
++ }
++
++ return pci_write_config_word(dev, offset, value);
++}
++
++static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ if (unlikely(!bar)) {
++ printk(KERN_WARNING "pciback: driver data not found for %s\n",
++ pci_name(dev));
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ /* A write to obtain the length must happen as a 32-bit write.
++ * This does not (yet) support writing individual bytes
++ */
++ if (value == ~PCI_ROM_ADDRESS_ENABLE)
++ bar->which = 1;
++ else
++ bar->which = 0;
++
++ /* Do we need to support enabling/disabling the rom address here? */
++
++ return 0;
++}
++
++/* For the BARs, only allow writes which write ~0 or
++ * the correct resource information
++ * (Needed for when the driver probes the resource usage)
++ */
++static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ if (unlikely(!bar)) {
++ printk(KERN_WARNING "pciback: driver data not found for %s\n",
++ pci_name(dev));
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ /* A write to obtain the length must happen as a 32-bit write.
++ * This does not (yet) support writing individual bytes
++ */
++ if (value == ~0)
++ bar->which = 1;
++ else
++ bar->which = 0;
++
++ return 0;
++}
++
++static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ if (unlikely(!bar)) {
++ printk(KERN_WARNING "pciback: driver data not found for %s\n",
++ pci_name(dev));
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ *value = bar->which ? bar->len_val : bar->val;
++
++ return 0;
++}
++
++static inline void read_dev_bar(struct pci_dev *dev,
++ struct pci_bar_info *bar_info, int offset,
++ u32 len_mask)
++{
++ pci_read_config_dword(dev, offset, &bar_info->val);
++ pci_write_config_dword(dev, offset, len_mask);
++ pci_read_config_dword(dev, offset, &bar_info->len_val);
++ pci_write_config_dword(dev, offset, bar_info->val);
++}
++
++static void *bar_init(struct pci_dev *dev, int offset)
++{
++ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++
++ if (!bar)
++ return ERR_PTR(-ENOMEM);
++
++ read_dev_bar(dev, bar, offset, ~0);
++ bar->which = 0;
++
++ return bar;
++}
++
++static void *rom_init(struct pci_dev *dev, int offset)
++{
++ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++
++ if (!bar)
++ return ERR_PTR(-ENOMEM);
++
++ read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
++ bar->which = 0;
++
++ return bar;
++}
++
++static void bar_reset(struct pci_dev *dev, int offset, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ bar->which = 0;
++}
++
++static void bar_release(struct pci_dev *dev, int offset, void *data)
++{
++ kfree(data);
++}
++
++static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
++ void *data)
++{
++ *value = (u8) dev->irq;
++
++ return 0;
++}
++
++static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
++{
++ u8 cur_value;
++ int err;
++
++ err = pci_read_config_byte(dev, offset, &cur_value);
++ if (err)
++ goto out;
++
++ if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
++ || value == PCI_BIST_START)
++ err = pci_write_config_byte(dev, offset, value);
++
++ out:
++ return err;
++}
++
++static struct config_field header_common[] = {
++ {
++ .offset = PCI_COMMAND,
++ .size = 2,
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = command_write,
++ },
++ {
++ .offset = PCI_INTERRUPT_LINE,
++ .size = 1,
++ .u.b.read = interrupt_read,
++ },
++ {
++ .offset = PCI_INTERRUPT_PIN,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ /* Any side effects of letting driver domain control cache line? */
++ .offset = PCI_CACHE_LINE_SIZE,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ .u.b.write = pciback_write_config_byte,
++ },
++ {
++ .offset = PCI_LATENCY_TIMER,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ .offset = PCI_BIST,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ .u.b.write = bist_write,
++ },
++ {
++ .size = 0,
++ },
++};
++
++#define CFG_FIELD_BAR(reg_offset) \
++ { \
++ .offset = reg_offset, \
++ .size = 4, \
++ .init = bar_init, \
++ .reset = bar_reset, \
++ .release = bar_release, \
++ .u.dw.read = bar_read, \
++ .u.dw.write = bar_write, \
++ }
++
++#define CFG_FIELD_ROM(reg_offset) \
++ { \
++ .offset = reg_offset, \
++ .size = 4, \
++ .init = rom_init, \
++ .reset = bar_reset, \
++ .release = bar_release, \
++ .u.dw.read = bar_read, \
++ .u.dw.write = rom_write, \
++ }
++
++static struct config_field header_0[] = {
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
++ CFG_FIELD_ROM(PCI_ROM_ADDRESS),
++ {
++ .size = 0,
++ },
++};
++
++static struct config_field header_1[] = {
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
++ CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
++ {
++ .size = 0,
++ },
++};
++
++int pciback_config_header_add_fields(struct pci_dev *dev)
++{
++ int err;
++
++ err = pciback_config_add_fields(dev, header_common);
++ if (err)
++ goto out;
++
++ switch (dev->hdr_type) {
++ case PCI_HEADER_TYPE_NORMAL:
++ err = pciback_config_add_fields(dev, header_0);
++ break;
++
++ case PCI_HEADER_TYPE_BRIDGE:
++ err = pciback_config_add_fields(dev, header_1);
++ break;
++
++ default:
++ err = -EINVAL;
++ printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
++ pci_name(dev), dev->hdr_type);
++ break;
++ }
++
++ out:
++ return err;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_quirks.c linux-2.6.18-xen/drivers/xen/pciback/conf_space_quirks.c
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_quirks.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_quirks.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,128 @@
++/*
++ * PCI Backend - Handle special overlays for broken devices.
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ * Author: Chris Bookholt <hap10 at epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++LIST_HEAD(pciback_quirks);
++
++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
++{
++ struct pciback_config_quirk *tmp_quirk;
++
++ list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list)
++ if (pci_match_id(&tmp_quirk->devid, dev))
++ goto out;
++ tmp_quirk = NULL;
++ printk(KERN_DEBUG
++ "quirk didn't match any device pciback knows about\n");
++ out:
++ return tmp_quirk;
++}
++
++static inline void register_quirk(struct pciback_config_quirk *quirk)
++{
++ list_add_tail(&quirk->quirks_list, &pciback_quirks);
++}
++
++int pciback_field_is_dup(struct pci_dev *dev, int reg)
++{
++ int ret = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field *field;
++ struct config_field_entry *cfg_entry;
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++ if (field->offset == reg) {
++ ret = 1;
++ break;
++ }
++ }
++ return ret;
++}
++
++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
++ *field)
++{
++ int err = 0;
++
++ switch (field->size) {
++ case 1:
++ field->u.b.read = pciback_read_config_byte;
++ field->u.b.write = pciback_write_config_byte;
++ break;
++ case 2:
++ field->u.w.read = pciback_read_config_word;
++ field->u.w.write = pciback_write_config_word;
++ break;
++ case 4:
++ field->u.dw.read = pciback_read_config_dword;
++ field->u.dw.write = pciback_write_config_dword;
++ break;
++ default:
++ err = -EINVAL;
++ goto out;
++ }
++
++ pciback_config_add_field(dev, field);
++
++ out:
++ return err;
++}
++
++int pciback_config_quirks_init(struct pci_dev *dev)
++{
++ struct pciback_config_quirk *quirk;
++ int ret = 0;
++
++ quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC);
++ if (!quirk) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ quirk->devid.vendor = dev->vendor;
++ quirk->devid.device = dev->device;
++ quirk->devid.subvendor = dev->subsystem_vendor;
++ quirk->devid.subdevice = dev->subsystem_device;
++ quirk->devid.class = 0;
++ quirk->devid.class_mask = 0;
++ quirk->devid.driver_data = 0UL;
++
++ quirk->pdev = dev;
++
++ register_quirk(quirk);
++ out:
++ return ret;
++}
++
++void pciback_config_field_free(struct config_field *field)
++{
++ kfree(field);
++}
++
++int pciback_config_quirk_release(struct pci_dev *dev)
++{
++ struct pciback_config_quirk *quirk;
++ int ret = 0;
++
++ quirk = pciback_find_quirk(dev);
++ if (!quirk) {
++ ret = -ENXIO;
++ goto out;
++ }
++
++ list_del(&quirk->quirks_list);
++ kfree(quirk);
++
++ out:
++ return ret;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/conf_space_quirks.h linux-2.6.18-xen/drivers/xen/pciback/conf_space_quirks.h
+--- linux-2.6.18.1/drivers/xen/pciback/conf_space_quirks.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/conf_space_quirks.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * PCI Backend - Data structures for special overlays for broken devices.
++ *
++ * Ryan Wilson <hap9 at epoch.ncsc.mil>
++ * Chris Bookholt <hap10 at epoch.ncsc.mil>
++ */
++
++#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++
++#include <linux/pci.h>
++#include <linux/list.h>
++
++struct pciback_config_quirk {
++ struct list_head quirks_list;
++ struct pci_device_id devid;
++ struct pci_dev *pdev;
++};
++
++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev);
++
++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
++ *field);
++
++int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg);
++
++int pciback_config_quirks_init(struct pci_dev *dev);
++
++void pciback_config_field_free(struct config_field *field);
++
++int pciback_config_quirk_release(struct pci_dev *dev);
++
++int pciback_field_is_dup(struct pci_dev *dev, int reg);
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/Makefile linux-2.6.18-xen/drivers/xen/pciback/Makefile
+--- linux-2.6.18.1/drivers/xen/pciback/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,15 @@
++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
++
++pciback-y := pci_stub.o pciback_ops.o xenbus.o
++pciback-y += conf_space.o conf_space_header.o \
++ conf_space_capability.o \
++ conf_space_capability_vpd.o \
++ conf_space_capability_pm.o \
++ conf_space_quirks.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
++
++ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/passthrough.c linux-2.6.18-xen/drivers/xen/pciback/passthrough.c
+--- linux-2.6.18.1/drivers/xen/pciback/passthrough.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/passthrough.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,157 @@
++/*
++ * PCI Backend - Provides restricted access to the real PCI bus topology
++ * to the frontend
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++struct passthrough_dev_data {
++ /* Access to dev_list must be protected by lock */
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry;
++ struct pci_dev *dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
++ if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
++ && bus == (unsigned int)dev_entry->dev->bus->number
++ && devfn == dev_entry->dev->devfn) {
++ dev = dev_entry->dev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry;
++ unsigned long flags;
++
++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
++ if (!dev_entry)
++ return -ENOMEM;
++ dev_entry->dev = dev;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++ list_add_tail(&dev_entry->list, &dev_data->dev_list);
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ return 0;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry, *t;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
++ if (dev_entry->dev == dev) {
++ list_del(&dev_entry->list);
++ found_dev = dev_entry->dev;
++ kfree(dev_entry);
++ }
++ }
++
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ if (found_dev)
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ struct passthrough_dev_data *dev_data;
++
++ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
++ if (!dev_data)
++ return -ENOMEM;
++
++ spin_lock_init(&dev_data->lock);
++
++ INIT_LIST_HEAD(&dev_data->dev_list);
++
++ pdev->pci_dev_data = dev_data;
++
++ return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_root_cb)
++{
++ int err = 0;
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry, *e;
++ struct pci_dev *dev;
++ int found;
++ unsigned int domain, bus;
++
++ spin_lock(&dev_data->lock);
++
++ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
++ /* Only publish this device as a root if none of its
++ * parent bridges are exported
++ */
++ found = 0;
++ dev = dev_entry->dev->bus->self;
++ for (; !found && dev != NULL; dev = dev->bus->self) {
++ list_for_each_entry(e, &dev_data->dev_list, list) {
++ if (dev == e->dev) {
++ found = 1;
++ break;
++ }
++ }
++ }
++
++ domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
++ bus = (unsigned int)dev_entry->dev->bus->number;
++
++ if (!found) {
++ err = publish_root_cb(pdev, domain, bus);
++ if (err)
++ break;
++ }
++ }
++
++ spin_unlock(&dev_data->lock);
++
++ return err;
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry, *t;
++
++ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
++ list_del(&dev_entry->list);
++ pcistub_put_pci_dev(dev_entry->dev);
++ kfree(dev_entry);
++ }
++
++ kfree(dev_data);
++ pdev->pci_dev_data = NULL;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/pciback.h linux-2.6.18-xen/drivers/xen/pciback/pciback.h
+--- linux-2.6.18.1/drivers/xen/pciback/pciback.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/pciback.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,93 @@
++/*
++ * PCI Backend Common Data Structures & Function Declarations
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#ifndef __XEN_PCIBACK_H__
++#define __XEN_PCIBACK_H__
++
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <xen/xenbus.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <asm/atomic.h>
++#include <xen/interface/io/pciif.h>
++
++struct pci_dev_entry {
++ struct list_head list;
++ struct pci_dev *dev;
++};
++
++#define _PDEVF_op_active (0)
++#define PDEVF_op_active (1<<(_PDEVF_op_active))
++
++struct pciback_device {
++ void *pci_dev_data;
++ spinlock_t dev_lock;
++
++ struct xenbus_device *xdev;
++
++ struct xenbus_watch be_watch;
++ u8 be_watching;
++
++ int evtchn_irq;
++
++ struct vm_struct *sh_area;
++ struct xen_pci_sharedinfo *sh_info;
++
++ unsigned long flags;
++
++ struct work_struct op_work;
++};
++
++struct pciback_dev_data {
++ struct list_head config_fields;
++ int permissive;
++ int warned_on_write;
++};
++
++/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
++ int domain, int bus,
++ int slot, int func);
++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
++ struct pci_dev *dev);
++void pcistub_put_pci_dev(struct pci_dev *dev);
++
++/* Ensure a device is turned off or reset */
++void pciback_reset_device(struct pci_dev *pdev);
++
++/* Access a virtual configuration space for a PCI device */
++int pciback_config_init(void);
++int pciback_config_init_dev(struct pci_dev *dev);
++void pciback_config_free_dyn_fields(struct pci_dev *dev);
++void pciback_config_reset_dev(struct pci_dev *dev);
++void pciback_config_free_dev(struct pci_dev *dev);
++int pciback_config_read(struct pci_dev *dev, int offset, int size,
++ u32 * ret_val);
++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
++
++/* Handle requests for specific devices from the frontend */
++typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
++ unsigned int domain, unsigned int bus);
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn);
++int pciback_init_devices(struct pciback_device *pdev);
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb cb);
++void pciback_release_devices(struct pciback_device *pdev);
++
++/* Handles events from front-end */
++irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
++void pciback_do_op(void *data);
++
++int pciback_xenbus_register(void);
++void pciback_xenbus_unregister(void);
++
++extern int verbose_request;
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/pciback_ops.c linux-2.6.18-xen/drivers/xen/pciback/pciback_ops.c
+--- linux-2.6.18.1/drivers/xen/pciback/pciback_ops.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/pciback_ops.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,95 @@
++/*
++ * PCI Backend Operations - respond to PCI requests from Frontend
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <asm/bitops.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++
++int verbose_request = 0;
++module_param(verbose_request, int, 0644);
++
++/* Ensure a device is "turned off" and ready to be exported.
++ * (Also see pciback_config_reset to ensure virtual configuration space is
++ * ready to be re-exported)
++ */
++void pciback_reset_device(struct pci_dev *dev)
++{
++ u16 cmd;
++
++ /* Disable devices (but not bridges) */
++ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
++ pci_disable_device(dev);
++
++ pci_write_config_word(dev, PCI_COMMAND, 0);
++
++ dev->is_enabled = 0;
++ dev->is_busmaster = 0;
++ } else {
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ if (cmd & (PCI_COMMAND_INVALIDATE)) {
++ cmd &= ~(PCI_COMMAND_INVALIDATE);
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++ dev->is_busmaster = 0;
++ }
++ }
++}
++
++static inline void test_and_schedule_op(struct pciback_device *pdev)
++{
++ /* Check that frontend is requesting an operation and that we are not
++ * already processing a request */
++ if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
++ && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
++ schedule_work(&pdev->op_work);
++}
++
++/* Performing the configuration space reads/writes must not be done in atomic
++ * context because some of the pci_* functions can sleep (mostly due to ACPI
++ * use of semaphores). This function is intended to be called from a work
++ * queue in process context taking a struct pciback_device as a parameter */
++void pciback_do_op(void *data)
++{
++ struct pciback_device *pdev = data;
++ struct pci_dev *dev;
++ struct xen_pci_op *op = &pdev->sh_info->op;
++
++ dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
++
++ if (dev == NULL)
++ op->err = XEN_PCI_ERR_dev_not_found;
++ else if (op->cmd == XEN_PCI_OP_conf_read)
++ op->err = pciback_config_read(dev, op->offset, op->size,
++ &op->value);
++ else if (op->cmd == XEN_PCI_OP_conf_write)
++ op->err = pciback_config_write(dev, op->offset, op->size,
++ op->value);
++ else
++ op->err = XEN_PCI_ERR_not_implemented;
++
++ /* Tell the driver domain that we're done. */
++ wmb();
++ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
++ notify_remote_via_irq(pdev->evtchn_irq);
++
++ /* Mark that we're done. */
++ smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */
++ clear_bit(_PDEVF_op_active, &pdev->flags);
++ smp_mb__after_clear_bit(); /* /before/ final check for work */
++
++ /* Check to see if the driver domain tried to start another request in
++ * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active. */
++ test_and_schedule_op(pdev);
++}
++
++irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct pciback_device *pdev = dev_id;
++
++ test_and_schedule_op(pdev);
++
++ return IRQ_HANDLED;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/pci_stub.c linux-2.6.18-xen/drivers/xen/pciback/pci_stub.c
+--- linux-2.6.18.1/drivers/xen/pciback/pci_stub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/pci_stub.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,916 @@
++/*
++ * PCI Stub Driver - Grabs devices in backend to be exported later
++ *
++ * Ryan Wilson <hap9 at epoch.ncsc.mil>
++ * Chris Bookholt <hap10 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/kref.h>
++#include <asm/atomic.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++static char *pci_devs_to_hide = NULL;
++module_param_named(hide, pci_devs_to_hide, charp, 0444);
++
++struct pcistub_device_id {
++ struct list_head slot_list;
++ int domain;
++ unsigned char bus;
++ unsigned int devfn;
++};
++static LIST_HEAD(pcistub_device_ids);
++static DEFINE_SPINLOCK(device_ids_lock);
++
++struct pcistub_device {
++ struct kref kref;
++ struct list_head dev_list;
++ spinlock_t lock;
++
++ struct pci_dev *dev;
++ struct pciback_device *pdev; /* non-NULL if struct pci_dev is in use */
++};
++
++/* Access to pcistub_devices & seized_devices lists and the initialize_devices
++ * flag must be locked with pcistub_devices_lock
++ */
++static DEFINE_SPINLOCK(pcistub_devices_lock);
++static LIST_HEAD(pcistub_devices);
++
++/* wait for device_initcall before initializing our devices
++ * (see pcistub_init_devices_late)
++ */
++static int initialize_devices = 0;
++static LIST_HEAD(seized_devices);
++
++static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++
++ dev_dbg(&dev->dev, "pcistub_device_alloc\n");
++
++ psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC);
++ if (!psdev)
++ return NULL;
++
++ psdev->dev = pci_dev_get(dev);
++ if (!psdev->dev) {
++ kfree(psdev);
++ return NULL;
++ }
++
++ kref_init(&psdev->kref);
++ spin_lock_init(&psdev->lock);
++
++ return psdev;
++}
++
++/* Don't call this directly as it's called by pcistub_device_put */
++static void pcistub_device_release(struct kref *kref)
++{
++ struct pcistub_device *psdev;
++
++ psdev = container_of(kref, struct pcistub_device, kref);
++
++ dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
++
++ /* Clean-up the device */
++ pciback_reset_device(psdev->dev);
++ pciback_config_free_dyn_fields(psdev->dev);
++ pciback_config_free_dev(psdev->dev);
++ kfree(pci_get_drvdata(psdev->dev));
++ pci_set_drvdata(psdev->dev, NULL);
++
++ pci_dev_put(psdev->dev);
++
++ kfree(psdev);
++}
++
++static inline void pcistub_device_get(struct pcistub_device *psdev)
++{
++ kref_get(&psdev->kref);
++}
++
++static inline void pcistub_device_put(struct pcistub_device *psdev)
++{
++ kref_put(&psdev->kref, pcistub_device_release);
++}
++
++static struct pcistub_device *pcistub_device_find(int domain, int bus,
++ int slot, int func)
++{
++ struct pcistub_device *psdev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev != NULL
++ && domain == pci_domain_nr(psdev->dev->bus)
++ && bus == psdev->dev->bus->number
++ && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
++ pcistub_device_get(psdev);
++ goto out;
++ }
++ }
++
++ /* didn't find it */
++ psdev = NULL;
++
++ out:
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return psdev;
++}
++
++static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
++ struct pcistub_device *psdev)
++{
++ struct pci_dev *pci_dev = NULL;
++ unsigned long flags;
++
++ pcistub_device_get(psdev);
++
++ spin_lock_irqsave(&psdev->lock, flags);
++ if (!psdev->pdev) {
++ psdev->pdev = pdev;
++ pci_dev = psdev->dev;
++ }
++ spin_unlock_irqrestore(&psdev->lock, flags);
++
++ if (!pci_dev)
++ pcistub_device_put(psdev);
++
++ return pci_dev;
++}
++
++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
++ int domain, int bus,
++ int slot, int func)
++{
++ struct pcistub_device *psdev;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev != NULL
++ && domain == pci_domain_nr(psdev->dev->bus)
++ && bus == psdev->dev->bus->number
++ && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
++ found_dev = pcistub_device_get_pci_dev(pdev, psdev);
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return found_dev;
++}
++
++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
++ struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev == dev) {
++ found_dev = pcistub_device_get_pci_dev(pdev, psdev);
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return found_dev;
++}
++
++void pcistub_put_pci_dev(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev, *found_psdev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev == dev) {
++ found_psdev = psdev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ /* Cleanup our device
++ * (so it's ready for the next domain)
++ */
++ pciback_reset_device(found_psdev->dev);
++ pciback_config_free_dyn_fields(found_psdev->dev);
++ pciback_config_reset_dev(found_psdev->dev);
++
++ spin_lock_irqsave(&found_psdev->lock, flags);
++ found_psdev->pdev = NULL;
++ spin_unlock_irqrestore(&found_psdev->lock, flags);
++
++ pcistub_device_put(found_psdev);
++}
++
++static int __devinit pcistub_match_one(struct pci_dev *dev,
++ struct pcistub_device_id *pdev_id)
++{
++ /* Match the specified device by domain, bus, slot, func and also if
++ * any of the device's parent bridges match.
++ */
++ for (; dev != NULL; dev = dev->bus->self) {
++ if (pci_domain_nr(dev->bus) == pdev_id->domain
++ && dev->bus->number == pdev_id->bus
++ && dev->devfn == pdev_id->devfn)
++ return 1;
++
++ /* Sometimes topmost bridge links to itself. */
++ if (dev == dev->bus->self)
++ break;
++ }
++
++ return 0;
++}
++
++static int __devinit pcistub_match(struct pci_dev *dev)
++{
++ struct pcistub_device_id *pdev_id;
++ unsigned long flags;
++ int found = 0;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
++ if (pcistub_match_one(dev, pdev_id)) {
++ found = 1;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return found;
++}
++
++static int __devinit pcistub_init_device(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data;
++ int err = 0;
++
++ dev_dbg(&dev->dev, "initializing...\n");
++
++ /* The PCI backend is not intended to be a module (or to work with
++ * removable PCI devices (yet). If it were, pciback_config_free()
++ * would need to be called somewhere to free the memory allocated
++ * here and then to call kfree(pci_get_drvdata(psdev->dev)).
++ */
++ dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
++ if (!dev_data) {
++ err = -ENOMEM;
++ goto out;
++ }
++ pci_set_drvdata(dev, dev_data);
++
++ dev_dbg(&dev->dev, "initializing config\n");
++ err = pciback_config_init_dev(dev);
++ if (err)
++ goto out;
++
++ /* HACK: Force device (& ACPI) to determine what IRQ it's on - we
++ * must do this here because pcibios_enable_device may specify
++ * the pci device's true irq (and possibly its other resources)
++ * if they differ from what's in the configuration space.
++ * This makes the assumption that the device's resources won't
++ * change after this point (otherwise this code may break!)
++ */
++ dev_dbg(&dev->dev, "enabling device\n");
++ err = pci_enable_device(dev);
++ if (err)
++ goto config_release;
++
++ /* Now disable the device (this also ensures some private device
++ * data is setup before we export)
++ */
++ dev_dbg(&dev->dev, "reset device\n");
++ pciback_reset_device(dev);
++
++ return 0;
++
++ config_release:
++ pciback_config_free_dev(dev);
++
++ out:
++ pci_set_drvdata(dev, NULL);
++ kfree(dev_data);
++ return err;
++}
++
++/*
++ * Because some initialization still happens on
++ * devices during fs_initcall, we need to defer
++ * full initialization of our devices until
++ * device_initcall.
++ */
++static int __init pcistub_init_devices_late(void)
++{
++ struct pcistub_device *psdev;
++ unsigned long flags;
++ int err = 0;
++
++ pr_debug("pciback: pcistub_init_devices_late\n");
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ while (!list_empty(&seized_devices)) {
++ psdev = container_of(seized_devices.next,
++ struct pcistub_device, dev_list);
++ list_del(&psdev->dev_list);
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ err = pcistub_init_device(psdev->dev);
++ if (err) {
++ dev_err(&psdev->dev->dev,
++ "error %d initializing device\n", err);
++ kfree(psdev);
++ psdev = NULL;
++ }
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ if (psdev)
++ list_add_tail(&psdev->dev_list, &pcistub_devices);
++ }
++
++ initialize_devices = 1;
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ return 0;
++}
++
++static int __devinit pcistub_seize(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++ unsigned long flags;
++ int err = 0;
++
++ psdev = pcistub_device_alloc(dev);
++ if (!psdev)
++ return -ENOMEM;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ if (initialize_devices) {
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ /* don't want irqs disabled when calling pcistub_init_device */
++ err = pcistub_init_device(psdev->dev);
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ if (!err)
++ list_add(&psdev->dev_list, &pcistub_devices);
++ } else {
++ dev_dbg(&dev->dev, "deferring initialization\n");
++ list_add(&psdev->dev_list, &seized_devices);
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ if (err)
++ pcistub_device_put(psdev);
++
++ return err;
++}
++
++static int __devinit pcistub_probe(struct pci_dev *dev,
++ const struct pci_device_id *id)
++{
++ int err = 0;
++
++ dev_dbg(&dev->dev, "probing...\n");
++
++ if (pcistub_match(dev)) {
++
++ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
++ && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
++ dev_err(&dev->dev, "can't export pci devices that "
++ "don't have a normal (0) or bridge (1) "
++ "header type!\n");
++ err = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&dev->dev, "seizing device\n");
++ err = pcistub_seize(dev);
++ } else
++ /* Didn't find the device */
++ err = -ENODEV;
++
++ out:
++ return err;
++}
++
++static void pcistub_remove(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev, *found_psdev = NULL;
++ unsigned long flags;
++
++ dev_dbg(&dev->dev, "removing\n");
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ pciback_config_quirk_release(dev);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev == dev) {
++ found_psdev = psdev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ if (found_psdev) {
++ dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
++ found_psdev->pdev);
++
++ if (found_psdev->pdev) {
++ printk(KERN_WARNING "pciback: ****** removing device "
++ "%s while still in-use! ******\n",
++ pci_name(found_psdev->dev));
++ printk(KERN_WARNING "pciback: ****** driver domain may "
++ "still access this device's i/o resources!\n");
++ printk(KERN_WARNING "pciback: ****** shutdown driver "
++ "domain before binding device\n");
++ printk(KERN_WARNING "pciback: ****** to other drivers "
++ "or domains\n");
++
++ pciback_release_pci_dev(found_psdev->pdev,
++ found_psdev->dev);
++ }
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ list_del(&found_psdev->dev_list);
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ /* the final put for releasing from the list */
++ pcistub_device_put(found_psdev);
++ }
++}
++
++static struct pci_device_id pcistub_ids[] = {
++ {
++ .vendor = PCI_ANY_ID,
++ .device = PCI_ANY_ID,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ },
++ {0,},
++};
++
++/*
++ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
++ * for a normal device. I don't want it to be loaded automatically.
++ */
++
++static struct pci_driver pciback_pci_driver = {
++ .name = "pciback",
++ .id_table = pcistub_ids,
++ .probe = pcistub_probe,
++ .remove = pcistub_remove,
++};
++
++static inline int str_to_slot(const char *buf, int *domain, int *bus,
++ int *slot, int *func)
++{
++ int err;
++
++ err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
++ if (err == 4)
++ return 0;
++ else if (err < 0)
++ return -EINVAL;
++
++ /* try again without domain */
++ *domain = 0;
++ err = sscanf(buf, " %x:%x.%x", bus, slot, func);
++ if (err == 3)
++ return 0;
++
++ return -EINVAL;
++}
++
++static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
++ *slot, int *func, int *reg, int *size, int *mask)
++{
++ int err;
++
++ err =
++ sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot,
++ func, reg, size, mask);
++ if (err == 7)
++ return 0;
++ return -EINVAL;
++}
++
++static int pcistub_device_id_add(int domain, int bus, int slot, int func)
++{
++ struct pcistub_device_id *pci_dev_id;
++ unsigned long flags;
++
++ pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
++ if (!pci_dev_id)
++ return -ENOMEM;
++
++ pci_dev_id->domain = domain;
++ pci_dev_id->bus = bus;
++ pci_dev_id->devfn = PCI_DEVFN(slot, func);
++
++ pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
++ domain, bus, slot, func);
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return 0;
++}
++
++static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
++{
++ struct pcistub_device_id *pci_dev_id, *t;
++ int devfn = PCI_DEVFN(slot, func);
++ int err = -ENOENT;
++ unsigned long flags;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
++
++ if (pci_dev_id->domain == domain
++ && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
++ /* Don't break; here because it's possible the same
++ * slot could be in the list more than once
++ */
++ list_del(&pci_dev_id->slot_list);
++ kfree(pci_dev_id);
++
++ err = 0;
++
++ pr_debug("pciback: removed %04x:%02x:%02x.%01x from "
++ "seize list\n", domain, bus, slot, func);
++ }
++ }
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return err;
++}
++
++static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
++ int size, int mask)
++{
++ int err = 0;
++ struct pcistub_device *psdev;
++ struct pci_dev *dev;
++ struct config_field *field;
++
++ psdev = pcistub_device_find(domain, bus, slot, func);
++ if (!psdev || !psdev->dev) {
++ err = -ENODEV;
++ goto out;
++ }
++ dev = psdev->dev;
++
++ /* check for duplicate field */
++ if (pciback_field_is_dup(dev, reg))
++ goto out;
++
++ field = kzalloc(sizeof(*field), GFP_ATOMIC);
++ if (!field) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ field->offset = reg;
++ field->size = size;
++ field->mask = mask;
++ field->init = NULL;
++ field->reset = NULL;
++ field->release = NULL;
++ field->clean = pciback_config_field_free;
++
++ err = pciback_config_quirks_add_field(dev, field);
++ if (err)
++ kfree(field);
++ out:
++ return err;
++}
++
++static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func;
++ int err;
++
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++
++ err = pcistub_device_id_add(domain, bus, slot, func);
++
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
++
++static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func;
++ int err;
++
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++
++ err = pcistub_device_id_remove(domain, bus, slot, func);
++
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
++
++static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
++{
++ struct pcistub_device_id *pci_dev_id;
++ size_t count = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
++ if (count >= PAGE_SIZE)
++ break;
++
++ count += scnprintf(buf + count, PAGE_SIZE - count,
++ "%04x:%02x:%02x.%01x\n",
++ pci_dev_id->domain, pci_dev_id->bus,
++ PCI_SLOT(pci_dev_id->devfn),
++ PCI_FUNC(pci_dev_id->devfn));
++ }
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return count;
++}
++
++DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
++
++static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func, reg, size, mask;
++ int err;
++
++ err = str_to_quirk(buf, &domain, &bus, &slot, &func, ®, &size,
++ &mask);
++ if (err)
++ goto out;
++
++ err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
++
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
++{
++ int count = 0;
++ unsigned long flags;
++ extern struct list_head pciback_quirks;
++ struct pciback_config_quirk *quirk;
++ struct pciback_dev_data *dev_data;
++ struct config_field *field;
++ struct config_field_entry *cfg_entry;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry(quirk, &pciback_quirks, quirks_list) {
++ if (count >= PAGE_SIZE)
++ goto out;
++
++ count += scnprintf(buf + count, PAGE_SIZE - count,
++ "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n",
++ quirk->pdev->bus->number,
++ PCI_SLOT(quirk->pdev->devfn),
++ PCI_FUNC(quirk->pdev->devfn),
++ quirk->devid.vendor, quirk->devid.device,
++ quirk->devid.subvendor,
++ quirk->devid.subdevice);
++
++ dev_data = pci_get_drvdata(quirk->pdev);
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++ if (count >= PAGE_SIZE)
++ goto out;
++
++ count += scnprintf(buf + count, PAGE_SIZE -
++ count, "\t\t%08x:%01x:%08x\n",
++ field->offset, field->size,
++ field->mask);
++ }
++ }
++
++ out:
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return count;
++}
++
++DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
++
++static ssize_t permissive_add(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func;
++ int err;
++ struct pcistub_device *psdev;
++ struct pciback_dev_data *dev_data;
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++ psdev = pcistub_device_find(domain, bus, slot, func);
++ if (!psdev) {
++ err = -ENODEV;
++ goto out;
++ }
++ if (!psdev->dev) {
++ err = -ENODEV;
++ goto release;
++ }
++ dev_data = pci_get_drvdata(psdev->dev);
++ /* the driver data for a device should never be null at this point */
++ if (!dev_data) {
++ err = -ENXIO;
++ goto release;
++ }
++ if (!dev_data->permissive) {
++ dev_data->permissive = 1;
++ /* Let user know that what they're doing could be unsafe */
++ dev_warn(&psdev->dev->dev,
++ "enabling permissive mode configuration space accesses!\n");
++ dev_warn(&psdev->dev->dev,
++ "permissive mode is potentially unsafe!\n");
++ }
++ release:
++ pcistub_device_put(psdev);
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++static ssize_t permissive_show(struct device_driver *drv, char *buf)
++{
++ struct pcistub_device *psdev;
++ struct pciback_dev_data *dev_data;
++ size_t count = 0;
++ unsigned long flags;
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (count >= PAGE_SIZE)
++ break;
++ if (!psdev->dev)
++ continue;
++ dev_data = pci_get_drvdata(psdev->dev);
++ if (!dev_data || !dev_data->permissive)
++ continue;
++ count +=
++ scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
++ pci_name(psdev->dev));
++ }
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return count;
++}
++
++DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
++
++static int __init pcistub_init(void)
++{
++ int pos = 0;
++ int err = 0;
++ int domain, bus, slot, func;
++ int parsed;
++
++ if (pci_devs_to_hide && *pci_devs_to_hide) {
++ do {
++ parsed = 0;
++
++ err = sscanf(pci_devs_to_hide + pos,
++ " (%x:%x:%x.%x) %n",
++ &domain, &bus, &slot, &func, &parsed);
++ if (err != 4) {
++ domain = 0;
++ err = sscanf(pci_devs_to_hide + pos,
++ " (%x:%x.%x) %n",
++ &bus, &slot, &func, &parsed);
++ if (err != 3)
++ goto parse_error;
++ }
++
++ err = pcistub_device_id_add(domain, bus, slot, func);
++ if (err)
++ goto out;
++
++ /* if parsed<=0, we've reached the end of the string */
++ pos += parsed;
++ } while (parsed > 0 && pci_devs_to_hide[pos]);
++ }
++
++ /* If we're the first PCI Device Driver to register, we're the
++ * first one to get offered PCI devices as they become
++ * available (and thus we can be the first to grab them)
++ */
++ err = pci_register_driver(&pciback_pci_driver);
++ if (err < 0)
++ goto out;
++
++ driver_create_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
++ driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_remove_slot);
++ driver_create_file(&pciback_pci_driver.driver, &driver_attr_slots);
++ driver_create_file(&pciback_pci_driver.driver, &driver_attr_quirks);
++ driver_create_file(&pciback_pci_driver.driver, &driver_attr_permissive);
++
++ out:
++ return err;
++
++ parse_error:
++ printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
++ pci_devs_to_hide + pos);
++ return -EINVAL;
++}
++
++#ifndef MODULE
++/*
++ * fs_initcall happens before device_initcall
++ * so pciback *should* get called first (b/c we
++ * want to suck up any device before other drivers
++ * get a chance by being the first pci device
++ * driver to register)
++ */
++fs_initcall(pcistub_init);
++#endif
++
++static int __init pciback_init(void)
++{
++ int err;
++
++ err = pciback_config_init();
++ if (err)
++ return err;
++
++#ifdef MODULE
++ err = pcistub_init();
++ if (err < 0)
++ return err;
++#endif
++
++ pcistub_init_devices_late();
++ pciback_xenbus_register();
++
++ return 0;
++}
++
++static void __exit pciback_cleanup(void)
++{
++ pciback_xenbus_unregister();
++
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
++ driver_remove_file(&pciback_pci_driver.driver,
++ &driver_attr_remove_slot);
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
++
++ pci_unregister_driver(&pciback_pci_driver);
++}
++
++module_init(pciback_init);
++module_exit(pciback_cleanup);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/slot.c linux-2.6.18-xen/drivers/xen/pciback/slot.c
+--- linux-2.6.18.1/drivers/xen/pciback/slot.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/slot.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,151 @@
++/*
++ * PCI Backend - Provides a Virtual PCI bus (with real devices)
++ * to the frontend
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil> (vpci.c)
++ * Author: Tristan Gingold <tristan.gingold at bull.net>, from vpci.c
++ */
++
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++/* There are at most 32 slots in a pci bus. */
++#define PCI_SLOT_MAX 32
++
++#define PCI_BUS_NBR 2
++
++struct slot_dev_data {
++ /* Access to dev_list must be protected by lock */
++ struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
++ spinlock_t lock;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct pci_dev *dev = NULL;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if (domain != 0 || PCI_FUNC(devfn) != 0)
++ return NULL;
++
++ if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
++ return NULL;
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++ dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++ return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ int err = 0, slot, bus;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
++ err = -EFAULT;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Can't export bridges on the virtual PCI bus");
++ goto out;
++ }
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++
++ /* Assign to a new slot on the virtual PCI bus */
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (slot_dev->slots[bus][slot] == NULL) {
++ printk(KERN_INFO
++ "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
++ pci_name(dev), slot, bus);
++ slot_dev->slots[bus][slot] = dev;
++ goto unlock;
++ }
++ }
++
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "No more space on root virtual PCI bus");
++
++ unlock:
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++ out:
++ return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ int slot, bus;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (slot_dev->slots[bus][slot] == dev) {
++ slot_dev->slots[bus][slot] = NULL;
++ found_dev = dev;
++ goto out;
++ }
++ }
++
++ out:
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++ if (found_dev)
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ int slot, bus;
++ struct slot_dev_data *slot_dev;
++
++ slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
++ if (!slot_dev)
++ return -ENOMEM;
++
++ spin_lock_init(&slot_dev->lock);
++
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++)
++ slot_dev->slots[bus][slot] = NULL;
++
++ pdev->pci_dev_data = slot_dev;
++
++ return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_cb)
++{
++ /* The Virtual PCI bus has only one root */
++ return publish_cb(pdev, 0, 0);
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ int slot, bus;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ struct pci_dev *dev;
++
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ dev = slot_dev->slots[bus][slot];
++ if (dev != NULL)
++ pcistub_put_pci_dev(dev);
++ }
++
++ kfree(slot_dev);
++ pdev->pci_dev_data = NULL;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/vpci.c linux-2.6.18-xen/drivers/xen/pciback/vpci.c
+--- linux-2.6.18.1/drivers/xen/pciback/vpci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/vpci.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,204 @@
++/*
++ * PCI Backend - Provides a Virtual PCI bus (with real devices)
++ * to the frontend
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++#define PCI_SLOT_MAX 32
++
++struct vpci_dev_data {
++ /* Access to dev_list must be protected by lock */
++ struct list_head dev_list[PCI_SLOT_MAX];
++ spinlock_t lock;
++};
++
++static inline struct list_head *list_first(struct list_head *head)
++{
++ return head->next;
++}
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct pci_dev_entry *entry;
++ struct pci_dev *dev = NULL;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if (domain != 0 || bus != 0)
++ return NULL;
++
++ if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++
++ list_for_each_entry(entry,
++ &vpci_dev->dev_list[PCI_SLOT(devfn)],
++ list) {
++ if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
++ dev = entry->dev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++ }
++ return dev;
++}
++
++static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
++{
++ if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
++ && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
++ return 1;
++
++ return 0;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ int err = 0, slot;
++ struct pci_dev_entry *t, *dev_entry;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
++ err = -EFAULT;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Can't export bridges on the virtual PCI bus");
++ goto out;
++ }
++
++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
++ if (!dev_entry) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error adding entry to virtual PCI bus");
++ goto out;
++ }
++
++ dev_entry->dev = dev;
++
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++
++ /* Keep multi-function devices together on the virtual PCI bus */
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (!list_empty(&vpci_dev->dev_list[slot])) {
++ t = list_entry(list_first(&vpci_dev->dev_list[slot]),
++ struct pci_dev_entry, list);
++
++ if (match_slot(dev, t->dev)) {
++ pr_info("pciback: vpci: %s: "
++ "assign to virtual slot %d func %d\n",
++ pci_name(dev), slot,
++ PCI_FUNC(dev->devfn));
++ list_add_tail(&dev_entry->list,
++ &vpci_dev->dev_list[slot]);
++ goto unlock;
++ }
++ }
++ }
++
++ /* Assign to a new slot on the virtual PCI bus */
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (list_empty(&vpci_dev->dev_list[slot])) {
++ printk(KERN_INFO
++ "pciback: vpci: %s: assign to virtual slot %d\n",
++ pci_name(dev), slot);
++ list_add_tail(&dev_entry->list,
++ &vpci_dev->dev_list[slot]);
++ goto unlock;
++ }
++ }
++
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "No more space on root virtual PCI bus");
++
++ unlock:
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++ out:
++ return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ int slot;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ struct pci_dev_entry *e, *tmp;
++ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
++ list) {
++ if (e->dev == dev) {
++ list_del(&e->list);
++ found_dev = e->dev;
++ kfree(e);
++ goto out;
++ }
++ }
++ }
++
++ out:
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++
++ if (found_dev)
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ int slot;
++ struct vpci_dev_data *vpci_dev;
++
++ vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
++ if (!vpci_dev)
++ return -ENOMEM;
++
++ spin_lock_init(&vpci_dev->lock);
++
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
++ }
++
++ pdev->pci_dev_data = vpci_dev;
++
++ return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_cb)
++{
++ /* The Virtual PCI bus has only one root */
++ return publish_cb(pdev, 0, 0);
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ int slot;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ struct pci_dev_entry *e, *tmp;
++ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
++ list) {
++ list_del(&e->list);
++ pcistub_put_pci_dev(e->dev);
++ kfree(e);
++ }
++ }
++
++ kfree(vpci_dev);
++ pdev->pci_dev_data = NULL;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pciback/xenbus.c linux-2.6.18-xen/drivers/xen/pciback/xenbus.c
+--- linux-2.6.18.1/drivers/xen/pciback/xenbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pciback/xenbus.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,458 @@
++/*
++ * PCI Backend Xenbus Setup - handles setup with frontend and xend
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/vmalloc.h>
++#include <xen/xenbus.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++
++#define INVALID_EVTCHN_IRQ (-1)
++
++static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
++{
++ struct pciback_device *pdev;
++
++ pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL);
++ if (pdev == NULL)
++ goto out;
++ dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
++
++ pdev->xdev = xdev;
++ xdev->dev.driver_data = pdev;
++
++ spin_lock_init(&pdev->dev_lock);
++
++ pdev->sh_area = NULL;
++ pdev->sh_info = NULL;
++ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
++ pdev->be_watching = 0;
++
++ INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
++
++ if (pciback_init_devices(pdev)) {
++ kfree(pdev);
++ pdev = NULL;
++ }
++ out:
++ return pdev;
++}
++
++static void free_pdev(struct pciback_device *pdev)
++{
++ if (pdev->be_watching)
++ unregister_xenbus_watch(&pdev->be_watch);
++
++ /* Ensure the guest can't trigger our handler before removing devices */
++ if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
++ unbind_from_irqhandler(pdev->evtchn_irq, pdev);
++
++ /* If the driver domain started an op, make sure we complete it or
++ * delete it before releasing the shared memory */
++ cancel_delayed_work(&pdev->op_work);
++ flush_scheduled_work();
++
++ if (pdev->sh_info)
++ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
++
++ pciback_release_devices(pdev);
++
++ pdev->xdev->dev.driver_data = NULL;
++ pdev->xdev = NULL;
++
++ kfree(pdev);
++}
++
++static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
++ int remote_evtchn)
++{
++ int err = 0;
++ int evtchn;
++ struct vm_struct *area;
++
++ dev_dbg(&pdev->xdev->dev,
++ "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
++ gnt_ref, remote_evtchn);
++
++ area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
++ if (IS_ERR(area)) {
++ err = PTR_ERR(area);
++ goto out;
++ }
++ pdev->sh_area = area;
++ pdev->sh_info = area->addr;
++
++ err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
++ if (err)
++ goto out;
++
++ err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
++ SA_SAMPLE_RANDOM, "pciback", pdev);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error binding event channel to IRQ");
++ goto out;
++ }
++ pdev->evtchn_irq = err;
++ err = 0;
++
++ dev_dbg(&pdev->xdev->dev, "Attached!\n");
++ out:
++ return err;
++}
++
++static int pciback_attach(struct pciback_device *pdev)
++{
++ int err = 0;
++ int gnt_ref, remote_evtchn;
++ char *magic = NULL;
++
++ spin_lock(&pdev->dev_lock);
++
++ /* Make sure we only do this setup once */
++ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++ XenbusStateInitialised)
++ goto out;
++
++ /* Wait for frontend to state that it has published the configuration */
++ if (xenbus_read_driver_state(pdev->xdev->otherend) !=
++ XenbusStateInitialised)
++ goto out;
++
++ dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
++
++ err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
++ "pci-op-ref", "%u", &gnt_ref,
++ "event-channel", "%u", &remote_evtchn,
++ "magic", NULL, &magic, NULL);
++ if (err) {
++ /* If configuration didn't get read correctly, wait longer */
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading configuration from frontend");
++ goto out;
++ }
++
++ if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
++ xenbus_dev_fatal(pdev->xdev, -EFAULT,
++ "version mismatch (%s/%s) with pcifront - "
++ "halting pciback",
++ magic, XEN_PCI_MAGIC);
++ goto out;
++ }
++
++ err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
++ if (err)
++ goto out;
++
++ dev_dbg(&pdev->xdev->dev, "Connecting...\n");
++
++ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
++ if (err)
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error switching to connected state!");
++
++ dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
++ out:
++ spin_unlock(&pdev->dev_lock);
++
++ if (magic)
++ kfree(magic);
++
++ return err;
++}
++
++static void pciback_frontend_changed(struct xenbus_device *xdev,
++ enum xenbus_state fe_state)
++{
++ struct pciback_device *pdev = xdev->dev.driver_data;
++
++ dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
++
++ switch (fe_state) {
++ case XenbusStateInitialised:
++ pciback_attach(pdev);
++ break;
++
++ case XenbusStateClosing:
++ xenbus_switch_state(xdev, XenbusStateClosing);
++ break;
++
++ case XenbusStateUnknown:
++ case XenbusStateClosed:
++ dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
++ device_unregister(&xdev->dev);
++ break;
++
++ default:
++ break;
++ }
++}
++
++static int pciback_publish_pci_root(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus)
++{
++ unsigned int d, b;
++ int i, root_num, len, err;
++ char str[64];
++
++ dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ "root_num", "%d", &root_num);
++ if (err == 0 || err == -ENOENT)
++ root_num = 0;
++ else if (err < 0)
++ goto out;
++
++ /* Verify that we haven't already published this pci root */
++ for (i = 0; i < root_num; i++) {
++ len = snprintf(str, sizeof(str), "root-%d", i);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ str, "%x:%x", &d, &b);
++ if (err < 0)
++ goto out;
++ if (err != 2) {
++ err = -EINVAL;
++ goto out;
++ }
++
++ if (d == domain && b == bus) {
++ err = 0;
++ goto out;
++ }
++ }
++
++ len = snprintf(str, sizeof(str), "root-%d", root_num);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
++ root_num, domain, bus);
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++ "%04x:%02x", domain, bus);
++ if (err)
++ goto out;
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
++ "root_num", "%d", (root_num + 1));
++
++ out:
++ return err;
++}
++
++static int pciback_export_device(struct pciback_device *pdev,
++ int domain, int bus, int slot, int func)
++{
++ struct pci_dev *dev;
++ int err = 0;
++
++ dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
++ domain, bus, slot, func);
++
++ dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
++ if (!dev) {
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Couldn't locate PCI device "
++ "(%04x:%02x:%02x.%01x)! "
++ "perhaps already in-use?",
++ domain, bus, slot, func);
++ goto out;
++ }
++
++ err = pciback_add_pci_dev(pdev, dev);
++ if (err)
++ goto out;
++
++ /* TODO: It'd be nice to export a bridge and have all of its children
++ * get exported with it. This may be best done in xend (which will
++ * have to calculate resource usage anyway) but we probably want to
++ * put something in here to ensure that if a bridge gets given to a
++ * driver domain, that all devices under that bridge are not given
++ * to other driver domains (as he who controls the bridge can disable
++ * it and stop the other devices from working).
++ */
++ out:
++ return err;
++}
++
++static int pciback_setup_backend(struct pciback_device *pdev)
++{
++ /* Get configuration from xend (if available now) */
++ int domain, bus, slot, func;
++ int err = 0;
++ int i, num_devs;
++ char dev_str[64];
++
++ spin_lock(&pdev->dev_lock);
++
++ /* It's possible we could get the call to setup twice, so make sure
++ * we're not already connected.
++ */
++ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++ XenbusStateInitWait)
++ goto out;
++
++ dev_dbg(&pdev->xdev->dev, "getting be setup\n");
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
++ &num_devs);
++ if (err != 1) {
++ if (err >= 0)
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading number of devices");
++ goto out;
++ }
++
++ for (i = 0; i < num_devs; i++) {
++ int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
++ if (unlikely(l >= (sizeof(dev_str) - 1))) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "String overflow while reading "
++ "configuration");
++ goto out;
++ }
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
++ "%x:%x:%x.%x", &domain, &bus, &slot, &func);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading device configuration");
++ goto out;
++ }
++ if (err != 4) {
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error parsing pci device "
++ "configuration");
++ goto out;
++ }
++
++ err = pciback_export_device(pdev, domain, bus, slot, func);
++ if (err)
++ goto out;
++ }
++
++ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error while publish PCI root buses "
++ "for frontend");
++ goto out;
++ }
++
++ err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
++ if (err)
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error switching to initialised state!");
++
++ out:
++ spin_unlock(&pdev->dev_lock);
++
++ if (!err)
++ /* see if pcifront is already configured (if not, we'll wait) */
++ pciback_attach(pdev);
++
++ return err;
++}
++
++static void pciback_be_watch(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ struct pciback_device *pdev =
++ container_of(watch, struct pciback_device, be_watch);
++
++ switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
++ case XenbusStateInitWait:
++ pciback_setup_backend(pdev);
++ break;
++
++ default:
++ break;
++ }
++}
++
++static int pciback_xenbus_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err = 0;
++ struct pciback_device *pdev = alloc_pdev(dev);
++
++ if (pdev == NULL) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(dev, err,
++ "Error allocating pciback_device struct");
++ goto out;
++ }
++
++ /* wait for xend to configure us */
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto out;
++
++ /* watch the backend node for backend configuration information */
++ err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
++ pciback_be_watch);
++ if (err)
++ goto out;
++ pdev->be_watching = 1;
++
++ /* We need to force a call to our callback here in case
++ * xend already configured us!
++ */
++ pciback_be_watch(&pdev->be_watch, NULL, 0);
++
++ out:
++ return err;
++}
++
++static int pciback_xenbus_remove(struct xenbus_device *dev)
++{
++ struct pciback_device *pdev = dev->dev.driver_data;
++
++ if (pdev != NULL)
++ free_pdev(pdev);
++
++ return 0;
++}
++
++static struct xenbus_device_id xenpci_ids[] = {
++ {"pci"},
++ {{0}},
++};
++
++static struct xenbus_driver xenbus_pciback_driver = {
++ .name = "pciback",
++ .owner = THIS_MODULE,
++ .ids = xenpci_ids,
++ .probe = pciback_xenbus_probe,
++ .remove = pciback_xenbus_remove,
++ .otherend_changed = pciback_frontend_changed,
++};
++
++int __init pciback_xenbus_register(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ return xenbus_register_backend(&xenbus_pciback_driver);
++}
++
++void __exit pciback_xenbus_unregister(void)
++{
++ xenbus_unregister_driver(&xenbus_pciback_driver);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pcifront/Makefile linux-2.6.18-xen/drivers/xen/pcifront/Makefile
+--- linux-2.6.18.1/drivers/xen/pcifront/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pcifront/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,7 @@
++obj-y += pcifront.o
++
++pcifront-y := pci_op.o xenbus.o pci.o
++
++ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pcifront/pci.c linux-2.6.18-xen/drivers/xen/pcifront/pci.c
+--- linux-2.6.18.1/drivers/xen/pcifront/pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pcifront/pci.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,46 @@
++/*
++ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pcifront.h"
++
++DEFINE_SPINLOCK(pcifront_dev_lock);
++static struct pcifront_device *pcifront_dev = NULL;
++
++int pcifront_connect(struct pcifront_device *pdev)
++{
++ int err = 0;
++
++ spin_lock(&pcifront_dev_lock);
++
++ if (!pcifront_dev) {
++ dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
++ pcifront_dev = pdev;
++ }
++ else {
++ dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
++ err = -EEXIST;
++ }
++
++ spin_unlock(&pcifront_dev_lock);
++
++ return err;
++}
++
++void pcifront_disconnect(struct pcifront_device *pdev)
++{
++ spin_lock(&pcifront_dev_lock);
++
++ if (pdev == pcifront_dev) {
++ dev_info(&pdev->xdev->dev,
++ "Disconnecting PCI Frontend Buses\n");
++ pcifront_dev = NULL;
++ }
++
++ spin_unlock(&pcifront_dev_lock);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pcifront/pcifront.h linux-2.6.18-xen/drivers/xen/pcifront/pcifront.h
+--- linux-2.6.18.1/drivers/xen/pcifront/pcifront.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pcifront/pcifront.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,40 @@
++/*
++ * PCI Frontend - Common data structures & function declarations
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#ifndef __XEN_PCIFRONT_H__
++#define __XEN_PCIFRONT_H__
++
++#include <linux/spinlock.h>
++#include <linux/pci.h>
++#include <xen/xenbus.h>
++#include <xen/interface/io/pciif.h>
++#include <xen/pcifront.h>
++
++struct pci_bus_entry {
++ struct list_head list;
++ struct pci_bus *bus;
++};
++
++struct pcifront_device {
++ struct xenbus_device *xdev;
++ struct list_head root_buses;
++ spinlock_t dev_lock;
++
++ int evtchn;
++ int gnt_ref;
++
++ /* Lock this when doing any operations in sh_info */
++ spinlock_t sh_info_lock;
++ struct xen_pci_sharedinfo *sh_info;
++};
++
++int pcifront_connect(struct pcifront_device *pdev);
++void pcifront_disconnect(struct pcifront_device *pdev);
++
++int pcifront_scan_root(struct pcifront_device *pdev,
++ unsigned int domain, unsigned int bus);
++void pcifront_free_roots(struct pcifront_device *pdev);
++
++#endif /* __XEN_PCIFRONT_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pcifront/pci_op.c linux-2.6.18-xen/drivers/xen/pcifront/pci_op.c
+--- linux-2.6.18.1/drivers/xen/pcifront/pci_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pcifront/pci_op.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,273 @@
++/*
++ * PCI Frontend Operations - Communicates with frontend
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <linux/time.h>
++#include <xen/evtchn.h>
++#include "pcifront.h"
++
++static int verbose_request = 0;
++module_param(verbose_request, int, 0644);
++
++static int errno_to_pcibios_err(int errno)
++{
++ switch (errno) {
++ case XEN_PCI_ERR_success:
++ return PCIBIOS_SUCCESSFUL;
++
++ case XEN_PCI_ERR_dev_not_found:
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ case XEN_PCI_ERR_invalid_offset:
++ case XEN_PCI_ERR_op_failed:
++ return PCIBIOS_BAD_REGISTER_NUMBER;
++
++ case XEN_PCI_ERR_not_implemented:
++ return PCIBIOS_FUNC_NOT_SUPPORTED;
++
++ case XEN_PCI_ERR_access_denied:
++ return PCIBIOS_SET_FAILED;
++ }
++ return errno;
++}
++
++static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
++{
++ int err = 0;
++ struct xen_pci_op *active_op = &pdev->sh_info->op;
++ unsigned long irq_flags;
++ evtchn_port_t port = pdev->evtchn;
++ s64 ns, ns_timeout;
++ struct timeval tv;
++
++ spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
++
++ memcpy(active_op, op, sizeof(struct xen_pci_op));
++
++ /* Go */
++ wmb();
++ set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
++ notify_remote_via_evtchn(port);
++
++ /*
++ * We set a poll timeout of 3 seconds but give up on return after
++ * 2 seconds. It is better to time out too late rather than too early
++ * (in the latter case we end up continually re-executing poll() with a
++ * timeout in the past). 1s difference gives plenty of slack for error.
++ */
++ do_gettimeofday(&tv);
++ ns_timeout = timeval_to_ns(&tv) + 2 * NSEC_PER_SEC;
++
++ clear_evtchn(port);
++
++ while (test_bit(_XEN_PCIF_active,
++ (unsigned long *)&pdev->sh_info->flags)) {
++ if (HYPERVISOR_poll(&port, 1, jiffies + 3*HZ))
++ BUG();
++ clear_evtchn(port);
++ do_gettimeofday(&tv);
++ ns = timeval_to_ns(&tv);
++ if (ns > ns_timeout) {
++ dev_err(&pdev->xdev->dev,
++ "pciback not responding!!!\n");
++ clear_bit(_XEN_PCIF_active,
++ (unsigned long *)&pdev->sh_info->flags);
++ err = XEN_PCI_ERR_dev_not_found;
++ goto out;
++ }
++ }
++
++ memcpy(op, active_op, sizeof(struct xen_pci_op));
++
++ err = op->err;
++ out:
++ spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
++ return err;
++}
++
++/* Access to this function is spinlocked in drivers/pci/access.c */
++static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 * val)
++{
++ int err = 0;
++ struct xen_pci_op op = {
++ .cmd = XEN_PCI_OP_conf_read,
++ .domain = pci_domain_nr(bus),
++ .bus = bus->number,
++ .devfn = devfn,
++ .offset = where,
++ .size = size,
++ };
++ struct pcifront_sd *sd = bus->sysdata;
++ struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++ if (verbose_request)
++ dev_info(&pdev->xdev->dev,
++ "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
++ pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
++ PCI_FUNC(devfn), where, size);
++
++ err = do_pci_op(pdev, &op);
++
++ if (likely(!err)) {
++ if (verbose_request)
++ dev_info(&pdev->xdev->dev, "read got back value %x\n",
++ op.value);
++
++ *val = op.value;
++ } else if (err == -ENODEV) {
++ /* No device here, pretend that it just returned 0 */
++ err = 0;
++ *val = 0;
++ }
++
++ return errno_to_pcibios_err(err);
++}
++
++/* Access to this function is spinlocked in drivers/pci/access.c */
++static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 val)
++{
++ struct xen_pci_op op = {
++ .cmd = XEN_PCI_OP_conf_write,
++ .domain = pci_domain_nr(bus),
++ .bus = bus->number,
++ .devfn = devfn,
++ .offset = where,
++ .size = size,
++ .value = val,
++ };
++ struct pcifront_sd *sd = bus->sysdata;
++ struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++ if (verbose_request)
++ dev_info(&pdev->xdev->dev,
++ "write dev=%04x:%02x:%02x.%01x - "
++ "offset %x size %d val %x\n",
++ pci_domain_nr(bus), bus->number,
++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
++
++ return errno_to_pcibios_err(do_pci_op(pdev, &op));
++}
++
++struct pci_ops pcifront_bus_ops = {
++ .read = pcifront_bus_read,
++ .write = pcifront_bus_write,
++};
++
++/* Claim resources for the PCI frontend as-is, backend won't allow changes */
++static void pcifront_claim_resource(struct pci_dev *dev, void *data)
++{
++ struct pcifront_device *pdev = data;
++ int i;
++ struct resource *r;
++
++ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
++ r = &dev->resource[i];
++
++ if (!r->parent && r->start && r->flags) {
++ dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
++ pci_name(dev), i);
++ pci_claim_resource(dev, i);
++ }
++ }
++}
++
++int pcifront_scan_root(struct pcifront_device *pdev,
++ unsigned int domain, unsigned int bus)
++{
++ struct pci_bus *b;
++ struct pcifront_sd *sd = NULL;
++ struct pci_bus_entry *bus_entry = NULL;
++ int err = 0;
++
++#ifndef CONFIG_PCI_DOMAINS
++ if (domain != 0) {
++ dev_err(&pdev->xdev->dev,
++ "PCI Root in non-zero PCI Domain! domain=%d\n", domain);
++ dev_err(&pdev->xdev->dev,
++ "Please compile with CONFIG_PCI_DOMAINS\n");
++ err = -EINVAL;
++ goto err_out;
++ }
++#endif
++
++ dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
++ domain, bus);
++
++ bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
++ sd = kmalloc(sizeof(*sd), GFP_KERNEL);
++ if (!bus_entry || !sd) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++ pcifront_init_sd(sd, domain, pdev);
++
++ b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
++ &pcifront_bus_ops, sd);
++ if (!b) {
++ dev_err(&pdev->xdev->dev,
++ "Error creating PCI Frontend Bus!\n");
++ err = -ENOMEM;
++ goto err_out;
++ }
++ bus_entry->bus = b;
++
++ list_add(&bus_entry->list, &pdev->root_buses);
++
++ /* Claim resources before going "live" with our devices */
++ pci_walk_bus(b, pcifront_claim_resource, pdev);
++
++ pci_bus_add_devices(b);
++
++ return 0;
++
++ err_out:
++ kfree(bus_entry);
++ kfree(sd);
++
++ return err;
++}
++
++static void free_root_bus_devs(struct pci_bus *bus)
++{
++ struct pci_dev *dev;
++
++ down_write(&pci_bus_sem);
++ while (!list_empty(&bus->devices)) {
++ dev = container_of(bus->devices.next, struct pci_dev, bus_list);
++ up_write(&pci_bus_sem);
++
++ dev_dbg(&dev->dev, "removing device\n");
++ pci_remove_bus_device(dev);
++
++ down_write(&pci_bus_sem);
++ }
++ up_write(&pci_bus_sem);
++}
++
++void pcifront_free_roots(struct pcifront_device *pdev)
++{
++ struct pci_bus_entry *bus_entry, *t;
++
++ dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n");
++
++ list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
++ list_del(&bus_entry->list);
++
++ free_root_bus_devs(bus_entry->bus);
++
++ kfree(bus_entry->bus->sysdata);
++
++ device_unregister(bus_entry->bus->bridge);
++ pci_remove_bus(bus_entry->bus);
++
++ kfree(bus_entry);
++ }
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/pcifront/xenbus.c linux-2.6.18-xen/drivers/xen/pcifront/xenbus.c
+--- linux-2.6.18.1/drivers/xen/pcifront/xenbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/pcifront/xenbus.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,295 @@
++/*
++ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <xen/xenbus.h>
++#include <xen/gnttab.h>
++#include "pcifront.h"
++
++#define INVALID_GRANT_REF (0)
++#define INVALID_EVTCHN (-1)
++
++static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
++{
++ struct pcifront_device *pdev;
++
++ pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
++ if (pdev == NULL)
++ goto out;
++
++ pdev->sh_info =
++ (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
++ if (pdev->sh_info == NULL) {
++ kfree(pdev);
++ pdev = NULL;
++ goto out;
++ }
++ pdev->sh_info->flags = 0;
++
++ xdev->dev.driver_data = pdev;
++ pdev->xdev = xdev;
++
++ INIT_LIST_HEAD(&pdev->root_buses);
++
++ spin_lock_init(&pdev->dev_lock);
++ spin_lock_init(&pdev->sh_info_lock);
++
++ pdev->evtchn = INVALID_EVTCHN;
++ pdev->gnt_ref = INVALID_GRANT_REF;
++
++ dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
++ pdev, pdev->sh_info);
++ out:
++ return pdev;
++}
++
++static void free_pdev(struct pcifront_device *pdev)
++{
++ dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
++
++ pcifront_free_roots(pdev);
++
++ if (pdev->evtchn != INVALID_EVTCHN)
++ xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
++
++ if (pdev->gnt_ref != INVALID_GRANT_REF)
++ gnttab_end_foreign_access(pdev->gnt_ref, 0,
++ (unsigned long)pdev->sh_info);
++
++ pdev->xdev->dev.driver_data = NULL;
++
++ kfree(pdev);
++}
++
++static int pcifront_publish_info(struct pcifront_device *pdev)
++{
++ int err = 0;
++ struct xenbus_transaction trans;
++
++ err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
++ if (err < 0)
++ goto out;
++
++ pdev->gnt_ref = err;
++
++ err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
++ if (err)
++ goto out;
++
++ do_publish:
++ err = xenbus_transaction_start(&trans);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error writing configuration for backend "
++ "(start transaction)");
++ goto out;
++ }
++
++ err = xenbus_printf(trans, pdev->xdev->nodename,
++ "pci-op-ref", "%u", pdev->gnt_ref);
++ if (!err)
++ err = xenbus_printf(trans, pdev->xdev->nodename,
++ "event-channel", "%u", pdev->evtchn);
++ if (!err)
++ err = xenbus_printf(trans, pdev->xdev->nodename,
++ "magic", XEN_PCI_MAGIC);
++
++ if (err) {
++ xenbus_transaction_end(trans, 1);
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error writing configuration for backend");
++ goto out;
++ } else {
++ err = xenbus_transaction_end(trans, 0);
++ if (err == -EAGAIN)
++ goto do_publish;
++ else if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error completing transaction "
++ "for backend");
++ goto out;
++ }
++ }
++
++ xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
++
++ dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
++
++ out:
++ return err;
++}
++
++static int pcifront_try_connect(struct pcifront_device *pdev)
++{
++ int err = -EFAULT;
++ int i, num_roots, len;
++ char str[64];
++ unsigned int domain, bus;
++
++ spin_lock(&pdev->dev_lock);
++
++ /* Only connect once */
++ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++ XenbusStateInitialised)
++ goto out;
++
++ err = pcifront_connect(pdev);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error connecting PCI Frontend");
++ goto out;
++ }
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
++ "root_num", "%d", &num_roots);
++ if (err == -ENOENT) {
++ xenbus_dev_error(pdev->xdev, err,
++ "No PCI Roots found, trying 0000:00");
++ err = pcifront_scan_root(pdev, 0, 0);
++ num_roots = 0;
++ } else if (err != 1) {
++ if (err == 0)
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading number of PCI roots");
++ goto out;
++ }
++
++ for (i = 0; i < num_roots; i++) {
++ len = snprintf(str, sizeof(str), "root-%d", i);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
++ "%x:%x", &domain, &bus);
++ if (err != 2) {
++ if (err >= 0)
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading PCI root %d", i);
++ goto out;
++ }
++
++ err = pcifront_scan_root(pdev, domain, bus);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error scanning PCI root %04x:%02x",
++ domain, bus);
++ goto out;
++ }
++ }
++
++ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
++ if (err)
++ goto out;
++
++ out:
++ spin_unlock(&pdev->dev_lock);
++ return err;
++}
++
++static int pcifront_try_disconnect(struct pcifront_device *pdev)
++{
++ int err = 0;
++ enum xenbus_state prev_state;
++
++ spin_lock(&pdev->dev_lock);
++
++ prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
++
++ if (prev_state < XenbusStateClosing)
++ err = xenbus_switch_state(pdev->xdev, XenbusStateClosing);
++
++ if (!err && prev_state == XenbusStateConnected)
++ pcifront_disconnect(pdev);
++
++ spin_unlock(&pdev->dev_lock);
++
++ return err;
++}
++
++static void pcifront_backend_changed(struct xenbus_device *xdev,
++ enum xenbus_state be_state)
++{
++ struct pcifront_device *pdev = xdev->dev.driver_data;
++
++ switch (be_state) {
++ case XenbusStateClosing:
++ dev_warn(&xdev->dev, "backend going away!\n");
++ pcifront_try_disconnect(pdev);
++ break;
++
++ case XenbusStateUnknown:
++ case XenbusStateClosed:
++ dev_warn(&xdev->dev, "backend went away!\n");
++ pcifront_try_disconnect(pdev);
++
++ device_unregister(&pdev->xdev->dev);
++ break;
++
++ case XenbusStateConnected:
++ pcifront_try_connect(pdev);
++ break;
++
++ default:
++ break;
++ }
++}
++
++static int pcifront_xenbus_probe(struct xenbus_device *xdev,
++ const struct xenbus_device_id *id)
++{
++ int err = 0;
++ struct pcifront_device *pdev = alloc_pdev(xdev);
++
++ if (pdev == NULL) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(xdev, err,
++ "Error allocating pcifront_device struct");
++ goto out;
++ }
++
++ err = pcifront_publish_info(pdev);
++
++ out:
++ return err;
++}
++
++static int pcifront_xenbus_remove(struct xenbus_device *xdev)
++{
++ if (xdev->dev.driver_data)
++ free_pdev(xdev->dev.driver_data);
++
++ return 0;
++}
++
++static struct xenbus_device_id xenpci_ids[] = {
++ {"pci"},
++ {{0}},
++};
++
++static struct xenbus_driver xenbus_pcifront_driver = {
++ .name = "pcifront",
++ .owner = THIS_MODULE,
++ .ids = xenpci_ids,
++ .probe = pcifront_xenbus_probe,
++ .remove = pcifront_xenbus_remove,
++ .otherend_changed = pcifront_backend_changed,
++};
++
++static int __init pcifront_init(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ return xenbus_register_frontend(&xenbus_pcifront_driver);
++}
++
++/* Initialize after the Xen PCI Frontend Stub is initialized */
++subsys_initcall(pcifront_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/privcmd/Makefile linux-2.6.18-xen/drivers/xen/privcmd/Makefile
+--- linux-2.6.18.1/drivers/xen/privcmd/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/privcmd/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,2 @@
++
++obj-$(CONFIG_XEN_PRIVCMD) := privcmd.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/privcmd/privcmd.c linux-2.6.18-xen/drivers/xen/privcmd/privcmd.c
+--- linux-2.6.18.1/drivers/xen/privcmd/privcmd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/privcmd/privcmd.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,283 @@
++/******************************************************************************
++ * privcmd.c
++ *
++ * Interface to privileged domain-0 commands.
++ *
++ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <linux/swap.h>
++#include <linux/smp_lock.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <linux/seq_file.h>
++#include <linux/kthread.h>
++#include <asm/hypervisor.h>
++
++#include <asm/pgalloc.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/tlb.h>
++#include <asm/hypervisor.h>
++#include <xen/public/privcmd.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/dom0_ops.h>
++#include <xen/xen_proc.h>
++
++static struct proc_dir_entry *privcmd_intf;
++static struct proc_dir_entry *capabilities_intf;
++
++#ifndef HAVE_ARCH_PRIVCMD_MMAP
++static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
++#endif
++
++static int privcmd_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long data)
++{
++ int ret = -ENOSYS;
++ void __user *udata = (void __user *) data;
++
++ switch (cmd) {
++ case IOCTL_PRIVCMD_HYPERCALL: {
++ privcmd_hypercall_t hypercall;
++
++ if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
++ return -EFAULT;
++
++#if defined(__i386__)
++ __asm__ __volatile__ (
++ "pushl %%ebx; pushl %%ecx; pushl %%edx; "
++ "pushl %%esi; pushl %%edi; "
++ "movl 8(%%eax),%%ebx ;"
++ "movl 16(%%eax),%%ecx ;"
++ "movl 24(%%eax),%%edx ;"
++ "movl 32(%%eax),%%esi ;"
++ "movl 40(%%eax),%%edi ;"
++ "movl (%%eax),%%eax ;"
++ "shll $5,%%eax ;"
++ "addl $hypercall_page,%%eax ;"
++ "call *%%eax ;"
++ "popl %%edi; popl %%esi; popl %%edx; "
++ "popl %%ecx; popl %%ebx"
++ : "=a" (ret) : "0" (&hypercall) : "memory" );
++#elif defined (__x86_64__)
++ {
++ long ign1, ign2, ign3;
++ __asm__ __volatile__ (
++ "movq %8,%%r10; movq %9,%%r8;"
++ "shlq $5,%%rax ;"
++ "addq $hypercall_page,%%rax ;"
++ "call *%%rax"
++ : "=a" (ret), "=D" (ign1),
++ "=S" (ign2), "=d" (ign3)
++ : "0" ((unsigned long)hypercall.op),
++ "1" ((unsigned long)hypercall.arg[0]),
++ "2" ((unsigned long)hypercall.arg[1]),
++ "3" ((unsigned long)hypercall.arg[2]),
++ "g" ((unsigned long)hypercall.arg[3]),
++ "g" ((unsigned long)hypercall.arg[4])
++ : "r8", "r10", "memory" );
++ }
++#elif defined (__ia64__)
++ ret = privcmd_hypercall(&hypercall);
++#endif
++ }
++ break;
++
++ case IOCTL_PRIVCMD_MMAP: {
++ privcmd_mmap_t mmapcmd;
++ privcmd_mmap_entry_t msg;
++ privcmd_mmap_entry_t __user *p;
++ struct mm_struct *mm = current->mm;
++ struct vm_area_struct *vma;
++ unsigned long va;
++ int i, rc;
++
++ if (!is_initial_xendomain())
++ return -EPERM;
++
++ if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
++ return -EFAULT;
++
++ p = mmapcmd.entry;
++ if (copy_from_user(&msg, p, sizeof(msg)))
++ return -EFAULT;
++
++ down_read(&mm->mmap_sem);
++
++ vma = find_vma(mm, msg.va);
++ rc = -EINVAL;
++ if (!vma || (msg.va != vma->vm_start) ||
++ !privcmd_enforce_singleshot_mapping(vma))
++ goto mmap_out;
++
++ va = vma->vm_start;
++
++ for (i = 0; i < mmapcmd.num; i++) {
++ rc = -EFAULT;
++ if (copy_from_user(&msg, p, sizeof(msg)))
++ goto mmap_out;
++
++ /* Do not allow range to wrap the address space. */
++ rc = -EINVAL;
++ if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) ||
++ ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va))
++ goto mmap_out;
++
++ /* Range chunks must be contiguous in va space. */
++ if ((msg.va != va) ||
++ ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end))
++ goto mmap_out;
++
++ if ((rc = direct_remap_pfn_range(
++ vma,
++ msg.va & PAGE_MASK,
++ msg.mfn,
++ msg.npages << PAGE_SHIFT,
++ vma->vm_page_prot,
++ mmapcmd.dom)) < 0)
++ goto mmap_out;
++
++ p++;
++ va += msg.npages << PAGE_SHIFT;
++ }
++
++ rc = 0;
++
++ mmap_out:
++ up_read(&mm->mmap_sem);
++ ret = rc;
++ }
++ break;
++
++ case IOCTL_PRIVCMD_MMAPBATCH: {
++ privcmd_mmapbatch_t m;
++ struct mm_struct *mm = current->mm;
++ struct vm_area_struct *vma;
++ xen_pfn_t __user *p;
++ unsigned long addr, mfn;
++ int i;
++
++ if (!is_initial_xendomain())
++ return -EPERM;
++
++ if (copy_from_user(&m, udata, sizeof(m)))
++ return -EFAULT;
++
++ if ((m.num <= 0) || (m.num > (LONG_MAX >> PAGE_SHIFT)))
++ return -EINVAL;
++
++ down_read(&mm->mmap_sem);
++
++ vma = find_vma(mm, m.addr);
++ if (!vma ||
++ (m.addr != vma->vm_start) ||
++ ((m.addr + ((unsigned long)m.num<<PAGE_SHIFT)) !=
++ vma->vm_end) ||
++ !privcmd_enforce_singleshot_mapping(vma)) {
++ up_read(&mm->mmap_sem);
++ return -EINVAL;
++ }
++
++ p = m.arr;
++ addr = m.addr;
++ for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
++ if (get_user(mfn, p)) {
++ up_read(&mm->mmap_sem);
++ return -EFAULT;
++ }
++
++ ret = direct_remap_pfn_range(vma, addr & PAGE_MASK,
++ mfn, PAGE_SIZE,
++ vma->vm_page_prot, m.dom);
++ if (ret < 0)
++ put_user(0xF0000000 | mfn, p);
++ }
++
++ up_read(&mm->mmap_sem);
++ ret = 0;
++ }
++ break;
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++#ifndef HAVE_ARCH_PRIVCMD_MMAP
++static struct page *privcmd_nopage(struct vm_area_struct *vma,
++ unsigned long address,
++ int *type)
++{
++ return NOPAGE_SIGBUS;
++}
++
++static struct vm_operations_struct privcmd_vm_ops = {
++ .nopage = privcmd_nopage
++};
++
++static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
++{
++ /* Unsupported for auto-translate guests. */
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return -ENOSYS;
++
++ /* DONTCOPY is essential for Xen as copy_page_range is broken. */
++ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
++ vma->vm_ops = &privcmd_vm_ops;
++ vma->vm_private_data = NULL;
++
++ return 0;
++}
++
++static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
++{
++ return (xchg(&vma->vm_private_data, (void *)1) == NULL);
++}
++#endif
++
++static struct file_operations privcmd_file_ops = {
++ .ioctl = privcmd_ioctl,
++ .mmap = privcmd_mmap,
++};
++
++static int capabilities_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len = 0;
++ *page = 0;
++
++ if (is_initial_xendomain())
++ len = sprintf( page, "control_d\n" );
++
++ *eof = 1;
++ return len;
++}
++
++static int __init privcmd_init(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ privcmd_intf = create_xen_proc_entry("privcmd", 0400);
++ if (privcmd_intf != NULL)
++ privcmd_intf->proc_fops = &privcmd_file_ops;
++
++ capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
++ if (capabilities_intf != NULL)
++ capabilities_intf->read_proc = capabilities_read;
++
++ return 0;
++}
++
++__initcall(privcmd_init);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/tpmback/common.h linux-2.6.18-xen/drivers/xen/tpmback/common.h
+--- linux-2.6.18.1/drivers/xen/tpmback/common.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/tpmback/common.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,86 @@
++/******************************************************************************
++ * drivers/xen/tpmback/common.h
++ */
++
++#ifndef __NETIF__BACKEND__COMMON_H__
++#define __NETIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <xen/evtchn.h>
++#include <xen/driver_util.h>
++#include <xen/interface/grant_table.h>
++#include <xen/interface/io/tpmif.h>
++#include <asm/io.h>
++#include <asm/pgalloc.h>
++
++#define DPRINTK(_f, _a...) \
++ pr_debug("(file=%s, line=%d) " _f, \
++ __FILE__ , __LINE__ , ## _a )
++
++struct backend_info;
++
++typedef struct tpmif_st {
++ struct list_head tpmif_list;
++ /* Unique identifier for this interface. */
++ domid_t domid;
++ unsigned int handle;
++
++ /* Physical parameters of the comms window. */
++ unsigned int evtchn;
++ unsigned int irq;
++
++ /* The shared rings and indexes. */
++ tpmif_tx_interface_t *tx;
++ struct vm_struct *tx_area;
++
++ /* Miscellaneous private stuff. */
++ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
++ int active;
++
++ struct tpmif_st *hash_next;
++ struct list_head list; /* scheduling list */
++ atomic_t refcnt;
++
++ struct backend_info *bi;
++
++ grant_handle_t shmem_handle;
++ grant_ref_t shmem_ref;
++ struct page **mmap_pages;
++
++ char devname[20];
++} tpmif_t;
++
++void tpmif_disconnect_complete(tpmif_t * tpmif);
++tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi);
++void tpmif_interface_init(void);
++void tpmif_interface_exit(void);
++void tpmif_schedule_work(tpmif_t * tpmif);
++void tpmif_deschedule_work(tpmif_t * tpmif);
++void tpmif_xenbus_init(void);
++void tpmif_xenbus_exit(void);
++int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn);
++irqreturn_t tpmif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++
++long int tpmback_get_instance(struct backend_info *bi);
++
++int vtpm_release_packets(tpmif_t * tpmif, int send_msgs);
++
++
++#define tpmif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define tpmif_put(_b) \
++ do { \
++ if (atomic_dec_and_test(&(_b)->refcnt)) \
++ tpmif_disconnect_complete(_b); \
++ } while (0)
++
++extern int num_frontends;
++
++static inline unsigned long idx_to_kaddr(tpmif_t *t, unsigned int idx)
++{
++ return (unsigned long)pfn_to_kaddr(page_to_pfn(t->mmap_pages[idx]));
++}
++
++#endif /* __TPMIF__BACKEND__COMMON_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/tpmback/interface.c linux-2.6.18-xen/drivers/xen/tpmback/interface.c
+--- linux-2.6.18.1/drivers/xen/tpmback/interface.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/tpmback/interface.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,182 @@
++ /*****************************************************************************
++ * drivers/xen/tpmback/interface.c
++ *
++ * Vritual TPM interface management.
++ *
++ * Copyright (c) 2005, IBM Corporation
++ *
++ * Author: Stefan Berger, stefanb at us.ibm.com
++ *
++ * This code has been derived from drivers/xen/netback/interface.c
++ * Copyright (c) 2004, Keir Fraser
++ */
++
++#include "common.h"
++#include <xen/balloon.h>
++#include <xen/gnttab.h>
++
++static kmem_cache_t *tpmif_cachep;
++int num_frontends = 0;
++
++LIST_HEAD(tpmif_list);
++
++static tpmif_t *alloc_tpmif(domid_t domid, struct backend_info *bi)
++{
++ tpmif_t *tpmif;
++
++ tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL);
++ if (tpmif == NULL)
++ goto out_of_memory;
++
++ memset(tpmif, 0, sizeof (*tpmif));
++ tpmif->domid = domid;
++ tpmif->status = DISCONNECTED;
++ tpmif->bi = bi;
++ snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid);
++ atomic_set(&tpmif->refcnt, 1);
++
++ tpmif->mmap_pages = alloc_empty_pages_and_pagevec(TPMIF_TX_RING_SIZE);
++ if (tpmif->mmap_pages == NULL)
++ goto out_of_memory;
++
++ list_add(&tpmif->tpmif_list, &tpmif_list);
++ num_frontends++;
++
++ return tpmif;
++
++ out_of_memory:
++ if (tpmif != NULL)
++ kmem_cache_free(tpmif_cachep, tpmif);
++ printk("%s: out of memory\n", __FUNCTION__);
++ return ERR_PTR(-ENOMEM);
++}
++
++static void free_tpmif(tpmif_t * tpmif)
++{
++ num_frontends--;
++ list_del(&tpmif->tpmif_list);
++ free_empty_pages_and_pagevec(tpmif->mmap_pages, TPMIF_TX_RING_SIZE);
++ kmem_cache_free(tpmif_cachep, tpmif);
++}
++
++tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi)
++{
++ tpmif_t *tpmif;
++
++ list_for_each_entry(tpmif, &tpmif_list, tpmif_list) {
++ if (tpmif->bi == bi) {
++ if (tpmif->domid == domid) {
++ tpmif_get(tpmif);
++ return tpmif;
++ } else {
++ return ERR_PTR(-EEXIST);
++ }
++ }
++ }
++
++ return alloc_tpmif(domid, bi);
++}
++
++static int map_frontend_page(tpmif_t *tpmif, unsigned long shared_page)
++{
++ int ret;
++ struct gnttab_map_grant_ref op;
++
++ gnttab_set_map_op(&op, (unsigned long)tpmif->tx_area->addr,
++ GNTMAP_host_map, shared_page, tpmif->domid);
++
++ lock_vm_area(tpmif->tx_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
++ unlock_vm_area(tpmif->tx_area);
++ BUG_ON(ret);
++
++ if (op.status) {
++ DPRINTK(" Grant table operation failure !\n");
++ return op.status;
++ }
++
++ tpmif->shmem_ref = shared_page;
++ tpmif->shmem_handle = op.handle;
++
++ return 0;
++}
++
++static void unmap_frontend_page(tpmif_t *tpmif)
++{
++ struct gnttab_unmap_grant_ref op;
++ int ret;
++
++ gnttab_set_unmap_op(&op, (unsigned long)tpmif->tx_area->addr,
++ GNTMAP_host_map, tpmif->shmem_handle);
++
++ lock_vm_area(tpmif->tx_area);
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
++ unlock_vm_area(tpmif->tx_area);
++ BUG_ON(ret);
++}
++
++int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
++{
++ int err;
++ struct evtchn_bind_interdomain bind_interdomain;
++
++ if (tpmif->irq) {
++ return 0;
++ }
++
++ if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
++ return -ENOMEM;
++
++ err = map_frontend_page(tpmif, shared_page);
++ if (err) {
++ free_vm_area(tpmif->tx_area);
++ return err;
++ }
++
++
++ bind_interdomain.remote_dom = tpmif->domid;
++ bind_interdomain.remote_port = evtchn;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++ if (err) {
++ unmap_frontend_page(tpmif);
++ free_vm_area(tpmif->tx_area);
++ return err;
++ }
++
++ tpmif->evtchn = bind_interdomain.local_port;
++
++ tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
++
++ tpmif->irq = bind_evtchn_to_irqhandler(
++ tpmif->evtchn, tpmif_be_int, 0, tpmif->devname, tpmif);
++ tpmif->shmem_ref = shared_page;
++ tpmif->active = 1;
++
++ return 0;
++}
++
++void tpmif_disconnect_complete(tpmif_t *tpmif)
++{
++ if (tpmif->irq)
++ unbind_from_irqhandler(tpmif->irq, tpmif);
++
++ if (tpmif->tx) {
++ unmap_frontend_page(tpmif);
++ free_vm_area(tpmif->tx_area);
++ }
++
++ free_tpmif(tpmif);
++}
++
++void __init tpmif_interface_init(void)
++{
++ tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t),
++ 0, 0, NULL, NULL);
++}
++
++void __exit tpmif_interface_exit(void)
++{
++ kmem_cache_destroy(tpmif_cachep);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/tpmback/Makefile linux-2.6.18-xen/drivers/xen/tpmback/Makefile
+--- linux-2.6.18.1/drivers/xen/tpmback/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/tpmback/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,4 @@
++
++obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmbk.o
++
++tpmbk-y += tpmback.o interface.o xenbus.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/tpmback/tpmback.c linux-2.6.18-xen/drivers/xen/tpmback/tpmback.c
+--- linux-2.6.18.1/drivers/xen/tpmback/tpmback.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/tpmback/tpmback.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,944 @@
++/******************************************************************************
++ * drivers/xen/tpmback/tpmback.c
++ *
++ * Copyright (c) 2005, IBM Corporation
++ *
++ * Author: Stefan Berger, stefanb at us.ibm.com
++ * Grant table support: Mahadevan Gomathisankaran
++ *
++ * This code has been derived from drivers/xen/netback/netback.c
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ */
++
++#include "common.h"
++#include <xen/evtchn.h>
++
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/miscdevice.h>
++#include <linux/poll.h>
++#include <asm/uaccess.h>
++#include <xen/xenbus.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++
++/* local data structures */
++struct data_exchange {
++ struct list_head pending_pak;
++ struct list_head current_pak;
++ unsigned int copied_so_far;
++ u8 has_opener:1;
++ u8 aborted:1;
++ rwlock_t pak_lock; // protects all of the previous fields
++ wait_queue_head_t wait_queue;
++};
++
++struct vtpm_resp_hdr {
++ uint32_t instance_no;
++ uint16_t tag_no;
++ uint32_t len_no;
++ uint32_t ordinal_no;
++} __attribute__ ((packed));
++
++struct packet {
++ struct list_head next;
++ unsigned int data_len;
++ u8 *data_buffer;
++ tpmif_t *tpmif;
++ u32 tpm_instance;
++ u8 req_tag;
++ u32 last_read;
++ u8 flags;
++ struct timer_list processing_timer;
++};
++
++enum {
++ PACKET_FLAG_DISCARD_RESPONSE = 1,
++};
++
++/* local variables */
++static struct data_exchange dataex;
++
++/* local function prototypes */
++static int _packet_write(struct packet *pak,
++ const char *data, size_t size, int userbuffer);
++static void processing_timeout(unsigned long ptr);
++static int packet_read_shmem(struct packet *pak,
++ tpmif_t * tpmif,
++ u32 offset,
++ char *buffer, int isuserbuffer, u32 left);
++static int vtpm_queue_packet(struct packet *pak);
++
++/***************************************************************
++ Buffer copying fo user and kernel space buffes.
++***************************************************************/
++static inline int copy_from_buffer(void *to,
++ const void *from, unsigned long size,
++ int isuserbuffer)
++{
++ if (isuserbuffer) {
++ if (copy_from_user(to, (void __user *)from, size))
++ return -EFAULT;
++ } else {
++ memcpy(to, from, size);
++ }
++ return 0;
++}
++
++static inline int copy_to_buffer(void *to,
++ const void *from, unsigned long size,
++ int isuserbuffer)
++{
++ if (isuserbuffer) {
++ if (copy_to_user((void __user *)to, from, size))
++ return -EFAULT;
++ } else {
++ memcpy(to, from, size);
++ }
++ return 0;
++}
++
++
++static void dataex_init(struct data_exchange *dataex)
++{
++ INIT_LIST_HEAD(&dataex->pending_pak);
++ INIT_LIST_HEAD(&dataex->current_pak);
++ dataex->has_opener = 0;
++ rwlock_init(&dataex->pak_lock);
++ init_waitqueue_head(&dataex->wait_queue);
++}
++
++/***************************************************************
++ Packet-related functions
++***************************************************************/
++
++static struct packet *packet_find_instance(struct list_head *head,
++ u32 tpm_instance)
++{
++ struct packet *pak;
++ struct list_head *p;
++
++ /*
++ * traverse the list of packets and return the first
++ * one with the given instance number
++ */
++ list_for_each(p, head) {
++ pak = list_entry(p, struct packet, next);
++
++ if (pak->tpm_instance == tpm_instance) {
++ return pak;
++ }
++ }
++ return NULL;
++}
++
++static struct packet *packet_find_packet(struct list_head *head, void *packet)
++{
++ struct packet *pak;
++ struct list_head *p;
++
++ /*
++ * traverse the list of packets and return the first
++ * one with the given instance number
++ */
++ list_for_each(p, head) {
++ pak = list_entry(p, struct packet, next);
++
++ if (pak == packet) {
++ return pak;
++ }
++ }
++ return NULL;
++}
++
++static struct packet *packet_alloc(tpmif_t * tpmif,
++ u32 size, u8 req_tag, u8 flags)
++{
++ struct packet *pak = NULL;
++ pak = kzalloc(sizeof (struct packet), GFP_ATOMIC);
++ if (NULL != pak) {
++ if (tpmif) {
++ pak->tpmif = tpmif;
++ pak->tpm_instance = tpmback_get_instance(tpmif->bi);
++ tpmif_get(tpmif);
++ }
++ pak->data_len = size;
++ pak->req_tag = req_tag;
++ pak->last_read = 0;
++ pak->flags = flags;
++
++ /*
++ * cannot do tpmif_get(tpmif); bad things happen
++ * on the last tpmif_put()
++ */
++ init_timer(&pak->processing_timer);
++ pak->processing_timer.function = processing_timeout;
++ pak->processing_timer.data = (unsigned long)pak;
++ }
++ return pak;
++}
++
++static void inline packet_reset(struct packet *pak)
++{
++ pak->last_read = 0;
++}
++
++static void packet_free(struct packet *pak)
++{
++ if (timer_pending(&pak->processing_timer)) {
++ BUG();
++ }
++
++ if (pak->tpmif)
++ tpmif_put(pak->tpmif);
++ kfree(pak->data_buffer);
++ /*
++ * cannot do tpmif_put(pak->tpmif); bad things happen
++ * on the last tpmif_put()
++ */
++ kfree(pak);
++}
++
++
++/*
++ * Write data to the shared memory and send it to the FE.
++ */
++static int packet_write(struct packet *pak,
++ const char *data, size_t size, int isuserbuffer)
++{
++ int rc = 0;
++
++ if (0 != (pak->flags & PACKET_FLAG_DISCARD_RESPONSE)) {
++ /* Don't send a respone to this packet. Just acknowledge it. */
++ rc = size;
++ } else {
++ rc = _packet_write(pak, data, size, isuserbuffer);
++ }
++
++ return rc;
++}
++
++int _packet_write(struct packet *pak,
++ const char *data, size_t size, int isuserbuffer)
++{
++ /*
++ * Write into the shared memory pages directly
++ * and send it to the front end.
++ */
++ tpmif_t *tpmif = pak->tpmif;
++ grant_handle_t handle;
++ int rc = 0;
++ unsigned int i = 0;
++ unsigned int offset = 0;
++
++ if (tpmif == NULL) {
++ return -EFAULT;
++ }
++
++ if (tpmif->status == DISCONNECTED) {
++ return size;
++ }
++
++ while (offset < size && i < TPMIF_TX_RING_SIZE) {
++ unsigned int tocopy;
++ struct gnttab_map_grant_ref map_op;
++ struct gnttab_unmap_grant_ref unmap_op;
++ tpmif_tx_request_t *tx;
++
++ tx = &tpmif->tx->ring[i].req;
++
++ if (0 == tx->addr) {
++ DPRINTK("ERROR: Buffer for outgoing packet NULL?! i=%d\n", i);
++ return 0;
++ }
++
++ gnttab_set_map_op(&map_op, idx_to_kaddr(tpmif, i),
++ GNTMAP_host_map, tx->ref, tpmif->domid);
++
++ if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
++ &map_op, 1))) {
++ BUG();
++ }
++
++ handle = map_op.handle;
++
++ if (map_op.status) {
++ DPRINTK(" Grant table operation failure !\n");
++ return 0;
++ }
++
++ tocopy = min_t(size_t, size - offset, PAGE_SIZE);
++
++ if (copy_from_buffer((void *)(idx_to_kaddr(tpmif, i) |
++ (tx->addr & ~PAGE_MASK)),
++ &data[offset], tocopy, isuserbuffer)) {
++ tpmif_put(tpmif);
++ return -EFAULT;
++ }
++ tx->size = tocopy;
++
++ gnttab_set_unmap_op(&unmap_op, idx_to_kaddr(tpmif, i),
++ GNTMAP_host_map, handle);
++
++ if (unlikely
++ (HYPERVISOR_grant_table_op
++ (GNTTABOP_unmap_grant_ref, &unmap_op, 1))) {
++ BUG();
++ }
++
++ offset += tocopy;
++ i++;
++ }
++
++ rc = offset;
++ DPRINTK("Notifying frontend via irq %d\n", tpmif->irq);
++ notify_remote_via_irq(tpmif->irq);
++
++ return rc;
++}
++
++/*
++ * Read data from the shared memory and copy it directly into the
++ * provided buffer. Advance the read_last indicator which tells
++ * how many bytes have already been read.
++ */
++static int packet_read(struct packet *pak, size_t numbytes,
++ char *buffer, size_t buffersize, int isuserbuffer)
++{
++ tpmif_t *tpmif = pak->tpmif;
++
++ /*
++ * Read 'numbytes' of data from the buffer. The first 4
++ * bytes are the instance number in network byte order,
++ * after that come the data from the shared memory buffer.
++ */
++ u32 to_copy;
++ u32 offset = 0;
++ u32 room_left = buffersize;
++
++ if (pak->last_read < 4) {
++ /*
++ * copy the instance number into the buffer
++ */
++ u32 instance_no = htonl(pak->tpm_instance);
++ u32 last_read = pak->last_read;
++
++ to_copy = min_t(size_t, 4 - last_read, numbytes);
++
++ if (copy_to_buffer(&buffer[0],
++ &(((u8 *) & instance_no)[last_read]),
++ to_copy, isuserbuffer)) {
++ return -EFAULT;
++ }
++
++ pak->last_read += to_copy;
++ offset += to_copy;
++ room_left -= to_copy;
++ }
++
++ /*
++ * If the packet has a data buffer appended, read from it...
++ */
++
++ if (room_left > 0) {
++ if (pak->data_buffer) {
++ u32 to_copy = min_t(u32, pak->data_len - offset, room_left);
++ u32 last_read = pak->last_read - 4;
++
++ if (copy_to_buffer(&buffer[offset],
++ &pak->data_buffer[last_read],
++ to_copy, isuserbuffer)) {
++ return -EFAULT;
++ }
++ pak->last_read += to_copy;
++ offset += to_copy;
++ } else {
++ offset = packet_read_shmem(pak,
++ tpmif,
++ offset,
++ buffer,
++ isuserbuffer, room_left);
++ }
++ }
++ return offset;
++}
++
++static int packet_read_shmem(struct packet *pak,
++ tpmif_t * tpmif,
++ u32 offset, char *buffer, int isuserbuffer,
++ u32 room_left)
++{
++ u32 last_read = pak->last_read - 4;
++ u32 i = (last_read / PAGE_SIZE);
++ u32 pg_offset = last_read & (PAGE_SIZE - 1);
++ u32 to_copy;
++ grant_handle_t handle;
++
++ tpmif_tx_request_t *tx;
++
++ tx = &tpmif->tx->ring[0].req;
++ /*
++ * Start copying data at the page with index 'index'
++ * and within that page at offset 'offset'.
++ * Copy a maximum of 'room_left' bytes.
++ */
++ to_copy = min_t(u32, PAGE_SIZE - pg_offset, room_left);
++ while (to_copy > 0) {
++ void *src;
++ struct gnttab_map_grant_ref map_op;
++ struct gnttab_unmap_grant_ref unmap_op;
++
++ tx = &tpmif->tx->ring[i].req;
++
++ gnttab_set_map_op(&map_op, idx_to_kaddr(tpmif, i),
++ GNTMAP_host_map, tx->ref, tpmif->domid);
++
++ if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
++ &map_op, 1))) {
++ BUG();
++ }
++
++ if (map_op.status) {
++ DPRINTK(" Grant table operation failure !\n");
++ return -EFAULT;
++ }
++
++ handle = map_op.handle;
++
++ if (to_copy > tx->size) {
++ /*
++ * User requests more than what's available
++ */
++ to_copy = min_t(u32, tx->size, to_copy);
++ }
++
++ DPRINTK("Copying from mapped memory at %08lx\n",
++ (unsigned long)(idx_to_kaddr(tpmif, i) |
++ (tx->addr & ~PAGE_MASK)));
++
++ src = (void *)(idx_to_kaddr(tpmif, i) |
++ ((tx->addr & ~PAGE_MASK) + pg_offset));
++ if (copy_to_buffer(&buffer[offset],
++ src, to_copy, isuserbuffer)) {
++ return -EFAULT;
++ }
++
++ DPRINTK("Data from TPM-FE of domain %d are %d %d %d %d\n",
++ tpmif->domid, buffer[offset], buffer[offset + 1],
++ buffer[offset + 2], buffer[offset + 3]);
++
++ gnttab_set_unmap_op(&unmap_op, idx_to_kaddr(tpmif, i),
++ GNTMAP_host_map, handle);
++
++ if (unlikely
++ (HYPERVISOR_grant_table_op
++ (GNTTABOP_unmap_grant_ref, &unmap_op, 1))) {
++ BUG();
++ }
++
++ offset += to_copy;
++ pg_offset = 0;
++ last_read += to_copy;
++ room_left -= to_copy;
++
++ to_copy = min_t(u32, PAGE_SIZE, room_left);
++ i++;
++ } /* while (to_copy > 0) */
++ /*
++ * Adjust the last_read pointer
++ */
++ pak->last_read = last_read + 4;
++ return offset;
++}
++
++/* ============================================================
++ * The file layer for reading data from this device
++ * ============================================================
++ */
++static int vtpm_op_open(struct inode *inode, struct file *f)
++{
++ int rc = 0;
++ unsigned long flags;
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ if (dataex.has_opener == 0) {
++ dataex.has_opener = 1;
++ } else {
++ rc = -EPERM;
++ }
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++ return rc;
++}
++
++static ssize_t vtpm_op_read(struct file *file,
++ char __user * data, size_t size, loff_t * offset)
++{
++ int ret_size = -ENODATA;
++ struct packet *pak = NULL;
++ unsigned long flags;
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ if (dataex.aborted) {
++ dataex.aborted = 0;
++ dataex.copied_so_far = 0;
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++ return -EIO;
++ }
++
++ if (list_empty(&dataex.pending_pak)) {
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++ wait_event_interruptible(dataex.wait_queue,
++ !list_empty(&dataex.pending_pak));
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ dataex.copied_so_far = 0;
++ }
++
++ if (!list_empty(&dataex.pending_pak)) {
++ unsigned int left;
++
++ pak = list_entry(dataex.pending_pak.next, struct packet, next);
++ left = pak->data_len - dataex.copied_so_far;
++ list_del(&pak->next);
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++
++ DPRINTK("size given by app: %d, available: %d\n", size, left);
++
++ ret_size = min_t(size_t, size, left);
++
++ ret_size = packet_read(pak, ret_size, data, size, 1);
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++
++ if (ret_size < 0) {
++ del_singleshot_timer_sync(&pak->processing_timer);
++ packet_free(pak);
++ dataex.copied_so_far = 0;
++ } else {
++ DPRINTK("Copied %d bytes to user buffer\n", ret_size);
++
++ dataex.copied_so_far += ret_size;
++ if (dataex.copied_so_far >= pak->data_len + 4) {
++ DPRINTK("All data from this packet given to app.\n");
++ /* All data given to app */
++
++ del_singleshot_timer_sync(&pak->
++ processing_timer);
++ list_add_tail(&pak->next, &dataex.current_pak);
++ /*
++ * The more fontends that are handled at the same time,
++ * the more time we give the TPM to process the request.
++ */
++ mod_timer(&pak->processing_timer,
++ jiffies + (num_frontends * 60 * HZ));
++ dataex.copied_so_far = 0;
++ } else {
++ list_add(&pak->next, &dataex.pending_pak);
++ }
++ }
++ }
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++
++ DPRINTK("Returning result from read to app: %d\n", ret_size);
++
++ return ret_size;
++}
++
++/*
++ * Write operation - only works after a previous read operation!
++ */
++static ssize_t vtpm_op_write(struct file *file,
++ const char __user * data, size_t size,
++ loff_t * offset)
++{
++ struct packet *pak;
++ int rc = 0;
++ unsigned int off = 4;
++ unsigned long flags;
++ struct vtpm_resp_hdr vrh;
++
++ /*
++ * Minimum required packet size is:
++ * 4 bytes for instance number
++ * 2 bytes for tag
++ * 4 bytes for paramSize
++ * 4 bytes for the ordinal
++ * sum: 14 bytes
++ */
++ if (size < sizeof (vrh))
++ return -EFAULT;
++
++ if (copy_from_user(&vrh, data, sizeof (vrh)))
++ return -EFAULT;
++
++ /* malformed packet? */
++ if ((off + ntohl(vrh.len_no)) != size)
++ return -EFAULT;
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ pak = packet_find_instance(&dataex.current_pak,
++ ntohl(vrh.instance_no));
++
++ if (pak == NULL) {
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++ DPRINTK(KERN_ALERT "No associated packet! (inst=%d)\n",
++ ntohl(vrh.instance_no));
++ return -EFAULT;
++ }
++
++ del_singleshot_timer_sync(&pak->processing_timer);
++ list_del(&pak->next);
++
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++
++ /*
++ * The first 'offset' bytes must be the instance number - skip them.
++ */
++ size -= off;
++
++ rc = packet_write(pak, &data[off], size, 1);
++
++ if (rc > 0) {
++ /* I neglected the first 4 bytes */
++ rc += off;
++ }
++ packet_free(pak);
++ return rc;
++}
++
++static int vtpm_op_release(struct inode *inode, struct file *file)
++{
++ unsigned long flags;
++
++ vtpm_release_packets(NULL, 1);
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ dataex.has_opener = 0;
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++ return 0;
++}
++
++static unsigned int vtpm_op_poll(struct file *file,
++ struct poll_table_struct *pts)
++{
++ unsigned int flags = POLLOUT | POLLWRNORM;
++
++ poll_wait(file, &dataex.wait_queue, pts);
++ if (!list_empty(&dataex.pending_pak)) {
++ flags |= POLLIN | POLLRDNORM;
++ }
++ return flags;
++}
++
++static struct file_operations vtpm_ops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .open = vtpm_op_open,
++ .read = vtpm_op_read,
++ .write = vtpm_op_write,
++ .release = vtpm_op_release,
++ .poll = vtpm_op_poll,
++};
++
++static struct miscdevice vtpms_miscdevice = {
++ .minor = 225,
++ .name = "vtpm",
++ .fops = &vtpm_ops,
++};
++
++/***************************************************************
++ Utility functions
++***************************************************************/
++
++static int tpm_send_fail_message(struct packet *pak, u8 req_tag)
++{
++ int rc;
++ static const unsigned char tpm_error_message_fail[] = {
++ 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x0a,
++ 0x00, 0x00, 0x00, 0x09 /* TPM_FAIL */
++ };
++ unsigned char buffer[sizeof (tpm_error_message_fail)];
++
++ memcpy(buffer, tpm_error_message_fail,
++ sizeof (tpm_error_message_fail));
++ /*
++ * Insert the right response tag depending on the given tag
++ * All response tags are '+3' to the request tag.
++ */
++ buffer[1] = req_tag + 3;
++
++ /*
++ * Write the data to shared memory and notify the front-end
++ */
++ rc = packet_write(pak, buffer, sizeof (buffer), 0);
++
++ return rc;
++}
++
++static int _vtpm_release_packets(struct list_head *head,
++ tpmif_t * tpmif, int send_msgs)
++{
++ int aborted = 0;
++ int c = 0;
++ struct packet *pak;
++ struct list_head *pos, *tmp;
++
++ list_for_each_safe(pos, tmp, head) {
++ pak = list_entry(pos, struct packet, next);
++ c += 1;
++
++ if (tpmif == NULL || pak->tpmif == tpmif) {
++ int can_send = 0;
++
++ del_singleshot_timer_sync(&pak->processing_timer);
++ list_del(&pak->next);
++
++ if (pak->tpmif && pak->tpmif->status == CONNECTED) {
++ can_send = 1;
++ }
++
++ if (send_msgs && can_send) {
++ tpm_send_fail_message(pak, pak->req_tag);
++ }
++ packet_free(pak);
++ if (c == 1)
++ aborted = 1;
++ }
++ }
++ return aborted;
++}
++
++int vtpm_release_packets(tpmif_t * tpmif, int send_msgs)
++{
++ unsigned long flags;
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++
++ dataex.aborted = _vtpm_release_packets(&dataex.pending_pak,
++ tpmif,
++ send_msgs);
++ _vtpm_release_packets(&dataex.current_pak, tpmif, send_msgs);
++
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++ return 0;
++}
++
++static int vtpm_queue_packet(struct packet *pak)
++{
++ int rc = 0;
++
++ if (dataex.has_opener) {
++ unsigned long flags;
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ list_add_tail(&pak->next, &dataex.pending_pak);
++ /* give the TPM some time to pick up the request */
++ mod_timer(&pak->processing_timer, jiffies + (30 * HZ));
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++
++ wake_up_interruptible(&dataex.wait_queue);
++ } else {
++ rc = -EFAULT;
++ }
++ return rc;
++}
++
++static int vtpm_receive(tpmif_t * tpmif, u32 size)
++{
++ int rc = 0;
++ unsigned char buffer[10];
++ __be32 *native_size;
++ struct packet *pak = packet_alloc(tpmif, size, 0, 0);
++
++ if (!pak)
++ return -ENOMEM;
++ /*
++ * Read 10 bytes from the received buffer to test its
++ * content for validity.
++ */
++ if (sizeof (buffer) != packet_read(pak,
++ sizeof (buffer), buffer,
++ sizeof (buffer), 0)) {
++ goto failexit;
++ }
++ /*
++ * Reset the packet read pointer so we can read all its
++ * contents again.
++ */
++ packet_reset(pak);
++
++ native_size = (__force __be32 *) (&buffer[4 + 2]);
++ /*
++ * Verify that the size of the packet is correct
++ * as indicated and that there's actually someone reading packets.
++ * The minimum size of the packet is '10' for tag, size indicator
++ * and ordinal.
++ */
++ if (size < 10 ||
++ be32_to_cpu(*native_size) != size ||
++ 0 == dataex.has_opener || tpmif->status != CONNECTED) {
++ rc = -EINVAL;
++ goto failexit;
++ } else {
++ rc = vtpm_queue_packet(pak);
++ if (rc < 0)
++ goto failexit;
++ }
++ return 0;
++
++ failexit:
++ if (pak) {
++ tpm_send_fail_message(pak, buffer[4 + 1]);
++ packet_free(pak);
++ }
++ return rc;
++}
++
++/*
++ * Timeout function that gets invoked when a packet has not been processed
++ * during the timeout period.
++ * The packet must be on a list when this function is invoked. This
++ * also means that once its taken off a list, the timer must be
++ * destroyed as well.
++ */
++static void processing_timeout(unsigned long ptr)
++{
++ struct packet *pak = (struct packet *)ptr;
++ unsigned long flags;
++
++ write_lock_irqsave(&dataex.pak_lock, flags);
++ /*
++ * The packet needs to be searched whether it
++ * is still on the list.
++ */
++ if (pak == packet_find_packet(&dataex.pending_pak, pak) ||
++ pak == packet_find_packet(&dataex.current_pak, pak)) {
++ if ((pak->flags & PACKET_FLAG_DISCARD_RESPONSE) == 0) {
++ tpm_send_fail_message(pak, pak->req_tag);
++ }
++ /* discard future responses */
++ pak->flags |= PACKET_FLAG_DISCARD_RESPONSE;
++ }
++
++ write_unlock_irqrestore(&dataex.pak_lock, flags);
++}
++
++static void tpm_tx_action(unsigned long unused);
++static DECLARE_TASKLET(tpm_tx_tasklet, tpm_tx_action, 0);
++
++static struct list_head tpm_schedule_list;
++static spinlock_t tpm_schedule_list_lock;
++
++static inline void maybe_schedule_tx_action(void)
++{
++ smp_mb();
++ tasklet_schedule(&tpm_tx_tasklet);
++}
++
++static inline int __on_tpm_schedule_list(tpmif_t * tpmif)
++{
++ return tpmif->list.next != NULL;
++}
++
++static void remove_from_tpm_schedule_list(tpmif_t * tpmif)
++{
++ spin_lock_irq(&tpm_schedule_list_lock);
++ if (likely(__on_tpm_schedule_list(tpmif))) {
++ list_del(&tpmif->list);
++ tpmif->list.next = NULL;
++ tpmif_put(tpmif);
++ }
++ spin_unlock_irq(&tpm_schedule_list_lock);
++}
++
++static void add_to_tpm_schedule_list_tail(tpmif_t * tpmif)
++{
++ if (__on_tpm_schedule_list(tpmif))
++ return;
++
++ spin_lock_irq(&tpm_schedule_list_lock);
++ if (!__on_tpm_schedule_list(tpmif) && tpmif->active) {
++ list_add_tail(&tpmif->list, &tpm_schedule_list);
++ tpmif_get(tpmif);
++ }
++ spin_unlock_irq(&tpm_schedule_list_lock);
++}
++
++void tpmif_schedule_work(tpmif_t * tpmif)
++{
++ add_to_tpm_schedule_list_tail(tpmif);
++ maybe_schedule_tx_action();
++}
++
++void tpmif_deschedule_work(tpmif_t * tpmif)
++{
++ remove_from_tpm_schedule_list(tpmif);
++}
++
++static void tpm_tx_action(unsigned long unused)
++{
++ struct list_head *ent;
++ tpmif_t *tpmif;
++ tpmif_tx_request_t *tx;
++
++ DPRINTK("%s: Getting data from front-end(s)!\n", __FUNCTION__);
++
++ while (!list_empty(&tpm_schedule_list)) {
++ /* Get a tpmif from the list with work to do. */
++ ent = tpm_schedule_list.next;
++ tpmif = list_entry(ent, tpmif_t, list);
++ tpmif_get(tpmif);
++ remove_from_tpm_schedule_list(tpmif);
++
++ tx = &tpmif->tx->ring[0].req;
++
++ /* pass it up */
++ vtpm_receive(tpmif, tx->size);
++
++ tpmif_put(tpmif);
++ }
++}
++
++irqreturn_t tpmif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ tpmif_t *tpmif = (tpmif_t *) dev_id;
++
++ add_to_tpm_schedule_list_tail(tpmif);
++ maybe_schedule_tx_action();
++ return IRQ_HANDLED;
++}
++
++static int __init tpmback_init(void)
++{
++ int rc;
++
++ if ((rc = misc_register(&vtpms_miscdevice)) != 0) {
++ printk(KERN_ALERT
++ "Could not register misc device for TPM BE.\n");
++ return rc;
++ }
++
++ dataex_init(&dataex);
++
++ spin_lock_init(&tpm_schedule_list_lock);
++ INIT_LIST_HEAD(&tpm_schedule_list);
++
++ tpmif_interface_init();
++ tpmif_xenbus_init();
++
++ printk(KERN_ALERT "Successfully initialized TPM backend driver.\n");
++
++ return 0;
++}
++
++module_init(tpmback_init);
++
++void __exit tpmback_exit(void)
++{
++ vtpm_release_packets(NULL, 0);
++ tpmif_xenbus_exit();
++ tpmif_interface_exit();
++ misc_deregister(&vtpms_miscdevice);
++}
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/tpmback/xenbus.c linux-2.6.18-xen/drivers/xen/tpmback/xenbus.c
+--- linux-2.6.18.1/drivers/xen/tpmback/xenbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/tpmback/xenbus.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,287 @@
++/* Xenbus code for tpmif backend
++ Copyright (C) 2005 IBM Corporation
++ Copyright (C) 2005 Rusty Russell <rusty at rustcorp.com.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 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 <stdarg.h>
++#include <linux/module.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++struct backend_info
++{
++ struct xenbus_device *dev;
++
++ /* our communications channel */
++ tpmif_t *tpmif;
++
++ long int frontend_id;
++ long int instance; // instance of TPM
++ u8 is_instance_set;// whether instance number has been set
++
++ /* watch front end for changes */
++ struct xenbus_watch backend_watch;
++};
++
++static void maybe_connect(struct backend_info *be);
++static void connect(struct backend_info *be);
++static int connect_ring(struct backend_info *be);
++static void backend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len);
++static void frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state);
++
++long int tpmback_get_instance(struct backend_info *bi)
++{
++ long int res = -1;
++ if (bi && bi->is_instance_set)
++ res = bi->instance;
++ return res;
++}
++
++static int tpmback_remove(struct xenbus_device *dev)
++{
++ struct backend_info *be = dev->dev.driver_data;
++
++ if (!be) return 0;
++
++ if (be->backend_watch.node) {
++ unregister_xenbus_watch(&be->backend_watch);
++ kfree(be->backend_watch.node);
++ be->backend_watch.node = NULL;
++ }
++ if (be->tpmif) {
++ be->tpmif->bi = NULL;
++ vtpm_release_packets(be->tpmif, 0);
++ tpmif_put(be->tpmif);
++ be->tpmif = NULL;
++ }
++ kfree(be);
++ dev->dev.driver_data = NULL;
++ return 0;
++}
++
++static int tpmback_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err;
++ struct backend_info *be = kzalloc(sizeof(struct backend_info),
++ GFP_KERNEL);
++
++ if (!be) {
++ xenbus_dev_fatal(dev, -ENOMEM,
++ "allocating backend structure");
++ return -ENOMEM;
++ }
++
++ be->is_instance_set = 0;
++ be->dev = dev;
++ dev->dev.driver_data = be;
++
++ err = xenbus_watch_path2(dev, dev->nodename,
++ "instance", &be->backend_watch,
++ backend_changed);
++ if (err) {
++ goto fail;
++ }
++
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err) {
++ goto fail;
++ }
++ return 0;
++fail:
++ tpmback_remove(dev);
++ return err;
++}
++
++
++static void backend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ int err;
++ long instance;
++ struct backend_info *be
++ = container_of(watch, struct backend_info, backend_watch);
++ struct xenbus_device *dev = be->dev;
++
++ err = xenbus_scanf(XBT_NIL, dev->nodename,
++ "instance","%li", &instance);
++ if (XENBUS_EXIST_ERR(err)) {
++ return;
++ }
++
++ if (err != 1) {
++ xenbus_dev_fatal(dev, err, "reading instance");
++ return;
++ }
++
++ if (be->is_instance_set == 0) {
++ be->instance = instance;
++ be->is_instance_set = 1;
++ }
++}
++
++
++static void frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state)
++{
++ struct backend_info *be = dev->dev.driver_data;
++ int err;
++
++ switch (frontend_state) {
++ case XenbusStateInitialising:
++ case XenbusStateInitialised:
++ break;
++
++ case XenbusStateConnected:
++ err = connect_ring(be);
++ if (err) {
++ return;
++ }
++ maybe_connect(be);
++ break;
++
++ case XenbusStateClosing:
++ be->instance = -1;
++ break;
++
++ case XenbusStateUnknown:
++ case XenbusStateClosed:
++ device_unregister(&be->dev->dev);
++ tpmback_remove(dev);
++ break;
++
++ default:
++ xenbus_dev_fatal(dev, -EINVAL,
++ "saw state %d at frontend",
++ frontend_state);
++ break;
++ }
++}
++
++
++
++static void maybe_connect(struct backend_info *be)
++{
++ if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
++ return;
++
++ connect(be);
++}
++
++
++static void connect(struct backend_info *be)
++{
++ struct xenbus_transaction xbt;
++ int err;
++ struct xenbus_device *dev = be->dev;
++ unsigned long ready = 1;
++
++again:
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(be->dev, err, "starting transaction");
++ return;
++ }
++
++ err = xenbus_printf(xbt, be->dev->nodename,
++ "ready", "%lu", ready);
++ if (err) {
++ xenbus_dev_fatal(be->dev, err, "writing 'ready'");
++ goto abort;
++ }
++
++ err = xenbus_transaction_end(xbt, 0);
++ if (err == -EAGAIN)
++ goto again;
++ if (err)
++ xenbus_dev_fatal(be->dev, err, "end of transaction");
++
++ err = xenbus_switch_state(dev, XenbusStateConnected);
++ if (!err)
++ be->tpmif->status = CONNECTED;
++ return;
++abort:
++ xenbus_transaction_end(xbt, 1);
++}
++
++
++static int connect_ring(struct backend_info *be)
++{
++ struct xenbus_device *dev = be->dev;
++ unsigned long ring_ref;
++ unsigned int evtchn;
++ int err;
++
++ err = xenbus_gather(XBT_NIL, dev->otherend,
++ "ring-ref", "%lu", &ring_ref,
++ "event-channel", "%u", &evtchn, NULL);
++ if (err) {
++ xenbus_dev_error(dev, err,
++ "reading %s/ring-ref and event-channel",
++ dev->otherend);
++ return err;
++ }
++
++ if (!be->tpmif) {
++ be->tpmif = tpmif_find(dev->otherend_id, be);
++ if (IS_ERR(be->tpmif)) {
++ err = PTR_ERR(be->tpmif);
++ be->tpmif = NULL;
++ xenbus_dev_fatal(dev,err,"creating vtpm interface");
++ return err;
++ }
++ }
++
++ if (be->tpmif != NULL) {
++ err = tpmif_map(be->tpmif, ring_ref, evtchn);
++ if (err) {
++ xenbus_dev_error(dev, err,
++ "mapping shared-frame %lu port %u",
++ ring_ref, evtchn);
++ return err;
++ }
++ }
++ return 0;
++}
++
++
++static struct xenbus_device_id tpmback_ids[] = {
++ { "vtpm" },
++ { "" }
++};
++
++
++static struct xenbus_driver tpmback = {
++ .name = "vtpm",
++ .owner = THIS_MODULE,
++ .ids = tpmback_ids,
++ .probe = tpmback_probe,
++ .remove = tpmback_remove,
++ .otherend_changed = frontend_changed,
++};
++
++
++void tpmif_xenbus_init(void)
++{
++ xenbus_register_backend(&tpmback);
++}
++
++void tpmif_xenbus_exit(void)
++{
++ xenbus_unregister_driver(&tpmback);
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/util.c linux-2.6.18-xen/drivers/xen/util.c
+--- linux-2.6.18.1/drivers/xen/util.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/util.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,70 @@
++
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <xen/driver_util.h>
++
++static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
++{
++ /* apply_to_page_range() does all the hard work. */
++ return 0;
++}
++
++struct vm_struct *alloc_vm_area(unsigned long size)
++{
++ struct vm_struct *area;
++
++ area = get_vm_area(size, VM_IOREMAP);
++ if (area == NULL)
++ return NULL;
++
++ /*
++ * This ensures that page tables are constructed for this region
++ * of kernel virtual address space and mapped into init_mm.
++ */
++ if (apply_to_page_range(&init_mm, (unsigned long)area->addr,
++ area->size, f, NULL)) {
++ free_vm_area(area);
++ return NULL;
++ }
++
++ return area;
++}
++EXPORT_SYMBOL_GPL(alloc_vm_area);
++
++void free_vm_area(struct vm_struct *area)
++{
++ struct vm_struct *ret;
++ ret = remove_vm_area(area->addr);
++ BUG_ON(ret != area);
++ kfree(area);
++}
++EXPORT_SYMBOL_GPL(free_vm_area);
++
++void lock_vm_area(struct vm_struct *area)
++{
++ unsigned long i;
++ char c;
++
++ /*
++ * Prevent context switch to a lazy mm that doesn't have this area
++ * mapped into its page tables.
++ */
++ preempt_disable();
++
++ /*
++ * Ensure that the page tables are mapped into the current mm. The
++ * page-fault path will copy the page directory pointers from init_mm.
++ */
++ for (i = 0; i < area->size; i += PAGE_SIZE)
++ (void)__get_user(c, (char __user *)area->addr + i);
++}
++EXPORT_SYMBOL_GPL(lock_vm_area);
++
++void unlock_vm_area(struct vm_struct *area)
++{
++ preempt_enable();
++}
++EXPORT_SYMBOL_GPL(unlock_vm_area);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/Makefile linux-2.6.18-xen/drivers/xen/xenbus/Makefile
+--- linux-2.6.18.1/drivers/xen/xenbus/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/Makefile 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,12 @@
++obj-y += xenbus.o
++obj-$(CONFIG_XEN_BACKEND) += xenbus_be.o
++
++xenbus_be-objs =
++xenbus_be-objs += xenbus_backend_client.o
++
++xenbus-objs =
++xenbus-objs += xenbus_client.o
++xenbus-objs += xenbus_comms.o
++xenbus-objs += xenbus_xs.o
++xenbus-objs += xenbus_probe.o
++obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_backend_client.c linux-2.6.18-xen/drivers/xen/xenbus/xenbus_backend_client.c
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_backend_client.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_backend_client.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,147 @@
++/******************************************************************************
++ * Backend-client-facing interface for the Xenbus driver. In other words, the
++ * interface between the Xenbus and the device-specific code in the backend
++ * driver.
++ *
++ * Copyright (C) 2005-2006 XenSource Ltd
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/err.h>
++#include <xen/gnttab.h>
++#include <xen/xenbus.h>
++#include <xen/driver_util.h>
++
++/* Based on Rusty Russell's skeleton driver's map_page */
++struct vm_struct *xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref)
++{
++ struct gnttab_map_grant_ref op;
++ struct vm_struct *area;
++
++ area = alloc_vm_area(PAGE_SIZE);
++ if (!area)
++ return ERR_PTR(-ENOMEM);
++
++ gnttab_set_map_op(&op, (unsigned long)area->addr, GNTMAP_host_map,
++ gnt_ref, dev->otherend_id);
++
++ lock_vm_area(area);
++ BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
++ unlock_vm_area(area);
++
++ if (op.status != GNTST_okay) {
++ free_vm_area(area);
++ xenbus_dev_fatal(dev, op.status,
++ "mapping in shared page %d from domain %d",
++ gnt_ref, dev->otherend_id);
++ BUG_ON(!IS_ERR(ERR_PTR(op.status)));
++ return ERR_PTR(op.status);
++ }
++
++ /* Stuff the handle in an unused field */
++ area->phys_addr = (unsigned long)op.handle;
++
++ return area;
++}
++EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
++
++
++int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
++ grant_handle_t *handle, void *vaddr)
++{
++ struct gnttab_map_grant_ref op;
++
++ gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map,
++ gnt_ref, dev->otherend_id);
++ BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
++
++ if (op.status != GNTST_okay) {
++ xenbus_dev_fatal(dev, op.status,
++ "mapping in shared page %d from domain %d",
++ gnt_ref, dev->otherend_id);
++ } else
++ *handle = op.handle;
++
++ return op.status;
++}
++EXPORT_SYMBOL_GPL(xenbus_map_ring);
++
++
++/* Based on Rusty Russell's skeleton driver's unmap_page */
++int xenbus_unmap_ring_vfree(struct xenbus_device *dev, struct vm_struct *area)
++{
++ struct gnttab_unmap_grant_ref op;
++
++ gnttab_set_unmap_op(&op, (unsigned long)area->addr, GNTMAP_host_map,
++ (grant_handle_t)area->phys_addr);
++
++ lock_vm_area(area);
++ BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
++ unlock_vm_area(area);
++
++ if (op.status == GNTST_okay)
++ free_vm_area(area);
++ else
++ xenbus_dev_error(dev, op.status,
++ "unmapping page at handle %d error %d",
++ (int16_t)area->phys_addr, op.status);
++
++ return op.status;
++}
++EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
++
++
++int xenbus_unmap_ring(struct xenbus_device *dev,
++ grant_handle_t handle, void *vaddr)
++{
++ struct gnttab_unmap_grant_ref op;
++
++ gnttab_set_unmap_op(&op, (unsigned long)vaddr, GNTMAP_host_map,
++ handle);
++ BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
++
++ if (op.status != GNTST_okay)
++ xenbus_dev_error(dev, op.status,
++ "unmapping page at handle %d error %d",
++ handle, op.status);
++
++ return op.status;
++}
++EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
++
++int xenbus_dev_is_online(struct xenbus_device *dev)
++{
++ int rc, val;
++
++ rc = xenbus_scanf(XBT_NIL, dev->nodename, "online", "%d", &val);
++ if (rc != 1)
++ val = 0; /* no online node present */
++
++ return val;
++}
++EXPORT_SYMBOL_GPL(xenbus_dev_is_online);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_client.c linux-2.6.18-xen/drivers/xen/xenbus/xenbus_client.c
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_client.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_client.c 2006-09-21 01:33:31.000000000 +0200
+@@ -0,0 +1,299 @@
++/******************************************************************************
++ * Client-facing interface for the Xenbus driver. In other words, the
++ * interface between the Xenbus and the device-specific code, be it the
++ * frontend or the backend of that driver.
++ *
++ * Copyright (C) 2005 XenSource Ltd
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <xen/evtchn.h>
++#include <xen/gnttab.h>
++#include <xen/xenbus.h>
++#include <xen/driver_util.h>
++
++#define DPRINTK(fmt, args...) \
++ pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
++
++char *xenbus_strstate(enum xenbus_state state)
++{
++ static char *name[] = {
++ [ XenbusStateUnknown ] = "Unknown",
++ [ XenbusStateInitialising ] = "Initialising",
++ [ XenbusStateInitWait ] = "InitWait",
++ [ XenbusStateInitialised ] = "Initialised",
++ [ XenbusStateConnected ] = "Connected",
++ [ XenbusStateClosing ] = "Closing",
++ [ XenbusStateClosed ] = "Closed",
++ };
++ return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
++}
++
++int xenbus_watch_path(struct xenbus_device *dev, const char *path,
++ struct xenbus_watch *watch,
++ void (*callback)(struct xenbus_watch *,
++ const char **, unsigned int))
++{
++ int err;
++
++ watch->node = path;
++ watch->callback = callback;
++
++ err = register_xenbus_watch(watch);
++
++ if (err) {
++ watch->node = NULL;
++ watch->callback = NULL;
++ xenbus_dev_fatal(dev, err, "adding watch on %s", path);
++ }
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(xenbus_watch_path);
++
++
++int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
++ const char *path2, struct xenbus_watch *watch,
++ void (*callback)(struct xenbus_watch *,
++ const char **, unsigned int))
++{
++ int err;
++ char *state = kasprintf(GFP_KERNEL, "%s/%s", path, path2);
++ if (!state) {
++ xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
++ return -ENOMEM;
++ }
++ err = xenbus_watch_path(dev, state, watch, callback);
++
++ if (err)
++ kfree(state);
++ return err;
++}
++EXPORT_SYMBOL_GPL(xenbus_watch_path2);
++
++
++int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
++{
++ /* We check whether the state is currently set to the given value, and
++ if not, then the state is set. We don't want to unconditionally
++ write the given state, because we don't want to fire watches
++ unnecessarily. Furthermore, if the node has gone, we don't write
++ to it, as the device will be tearing down, and we don't want to
++ resurrect that directory.
++
++ Note that, because of this cached value of our state, this function
++ will not work inside a Xenstore transaction (something it was
++ trying to in the past) because dev->state would not get reset if
++ the transaction was aborted.
++
++ */
++
++ int current_state;
++ int err;
++
++ if (state == dev->state)
++ return 0;
++
++ err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
++ ¤t_state);
++ if (err != 1)
++ return 0;
++
++ err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
++ if (err) {
++ if (state != XenbusStateClosing) /* Avoid looping */
++ xenbus_dev_fatal(dev, err, "writing new state");
++ return err;
++ }
++
++ dev->state = state;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xenbus_switch_state);
++
++int xenbus_frontend_closed(struct xenbus_device *dev)
++{
++ xenbus_switch_state(dev, XenbusStateClosed);
++ complete(&dev->down);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
++
++/**
++ * Return the path to the error node for the given device, or NULL on failure.
++ * If the value returned is non-NULL, then it is the caller's to kfree.
++ */
++static char *error_path(struct xenbus_device *dev)
++{
++ return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
++}
++
++
++void _dev_error(struct xenbus_device *dev, int err, const char *fmt,
++ va_list ap)
++{
++ int ret;
++ unsigned int len;
++ char *printf_buffer = NULL, *path_buffer = NULL;
++
++#define PRINTF_BUFFER_SIZE 4096
++ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
++ if (printf_buffer == NULL)
++ goto fail;
++
++ len = sprintf(printf_buffer, "%i ", -err);
++ ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
++
++ BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
++
++ dev_err(&dev->dev, "%s\n", printf_buffer);
++
++ path_buffer = error_path(dev);
++
++ if (path_buffer == NULL) {
++ printk("xenbus: failed to write error node for %s (%s)\n",
++ dev->nodename, printf_buffer);
++ goto fail;
++ }
++
++ if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
++ printk("xenbus: failed to write error node for %s (%s)\n",
++ dev->nodename, printf_buffer);
++ goto fail;
++ }
++
++fail:
++ if (printf_buffer)
++ kfree(printf_buffer);
++ if (path_buffer)
++ kfree(path_buffer);
++}
++
++
++void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
++ ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ _dev_error(dev, err, fmt, ap);
++ va_end(ap);
++}
++EXPORT_SYMBOL_GPL(xenbus_dev_error);
++
++
++void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
++ ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ _dev_error(dev, err, fmt, ap);
++ va_end(ap);
++
++ xenbus_switch_state(dev, XenbusStateClosing);
++}
++EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
++
++
++int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
++{
++ int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
++ if (err < 0)
++ xenbus_dev_fatal(dev, err, "granting access to ring page");
++ return err;
++}
++EXPORT_SYMBOL_GPL(xenbus_grant_ring);
++
++
++int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
++{
++ struct evtchn_alloc_unbound alloc_unbound;
++ int err;
++
++ alloc_unbound.dom = DOMID_SELF;
++ alloc_unbound.remote_dom = dev->otherend_id;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
++ &alloc_unbound);
++ if (err)
++ xenbus_dev_fatal(dev, err, "allocating event channel");
++ else
++ *port = alloc_unbound.port;
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
++
++
++int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
++{
++ struct evtchn_bind_interdomain bind_interdomain;
++ int err;
++
++ bind_interdomain.remote_dom = dev->otherend_id;
++ bind_interdomain.remote_port = remote_port,
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++ if (err)
++ xenbus_dev_fatal(dev, err,
++ "binding to event channel %d from domain %d",
++ remote_port, dev->otherend_id);
++ else
++ *port = bind_interdomain.local_port;
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
++
++
++int xenbus_free_evtchn(struct xenbus_device *dev, int port)
++{
++ struct evtchn_close close;
++ int err;
++
++ close.port = port;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
++ if (err)
++ xenbus_dev_error(dev, err, "freeing event channel %d", port);
++
++ return err;
++}
++
++
++enum xenbus_state xenbus_read_driver_state(const char *path)
++{
++ enum xenbus_state result;
++ int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
++ if (err)
++ result = XenbusStateUnknown;
++
++ return result;
++}
++EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_comms.c linux-2.6.18-xen/drivers/xen/xenbus/xenbus_comms.c
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_comms.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_comms.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,203 @@
++/******************************************************************************
++ * xenbus_comms.c
++ *
++ * Low level code to talks to Xen Store: ringbuffer and event channel.
++ *
++ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <linux/wait.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/err.h>
++#include <xen/xenbus.h>
++#include "xenbus_comms.h"
++
++static int xenbus_irq;
++
++extern void xenbus_probe(void *);
++extern int xenstored_ready;
++static DECLARE_WORK(probe_work, xenbus_probe, NULL);
++
++DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
++
++static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
++{
++ if (unlikely(xenstored_ready == 0)) {
++ xenstored_ready = 1;
++ schedule_work(&probe_work);
++ }
++
++ wake_up(&xb_waitq);
++ return IRQ_HANDLED;
++}
++
++static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
++{
++ return ((prod - cons) <= XENSTORE_RING_SIZE);
++}
++
++static void *get_output_chunk(XENSTORE_RING_IDX cons,
++ XENSTORE_RING_IDX prod,
++ char *buf, uint32_t *len)
++{
++ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
++ if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
++ *len = XENSTORE_RING_SIZE - (prod - cons);
++ return buf + MASK_XENSTORE_IDX(prod);
++}
++
++static const void *get_input_chunk(XENSTORE_RING_IDX cons,
++ XENSTORE_RING_IDX prod,
++ const char *buf, uint32_t *len)
++{
++ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
++ if ((prod - cons) < *len)
++ *len = prod - cons;
++ return buf + MASK_XENSTORE_IDX(cons);
++}
++
++int xb_write(const void *data, unsigned len)
++{
++ struct xenstore_domain_interface *intf = xen_store_interface;
++ XENSTORE_RING_IDX cons, prod;
++ int rc;
++
++ while (len != 0) {
++ void *dst;
++ unsigned int avail;
++
++ rc = wait_event_interruptible(
++ xb_waitq,
++ (intf->req_prod - intf->req_cons) !=
++ XENSTORE_RING_SIZE);
++ if (rc < 0)
++ return rc;
++
++ /* Read indexes, then verify. */
++ cons = intf->req_cons;
++ prod = intf->req_prod;
++ mb();
++ if (!check_indexes(cons, prod)) {
++ intf->req_cons = intf->req_prod = 0;
++ return -EIO;
++ }
++
++ dst = get_output_chunk(cons, prod, intf->req, &avail);
++ if (avail == 0)
++ continue;
++ if (avail > len)
++ avail = len;
++
++ memcpy(dst, data, avail);
++ data += avail;
++ len -= avail;
++
++ /* Other side must not see new header until data is there. */
++ wmb();
++ intf->req_prod += avail;
++
++ /* This implies mb() before other side sees interrupt. */
++ notify_remote_via_evtchn(xen_store_evtchn);
++ }
++
++ return 0;
++}
++
++int xb_read(void *data, unsigned len)
++{
++ struct xenstore_domain_interface *intf = xen_store_interface;
++ XENSTORE_RING_IDX cons, prod;
++ int rc;
++
++ while (len != 0) {
++ unsigned int avail;
++ const char *src;
++
++ rc = wait_event_interruptible(
++ xb_waitq,
++ intf->rsp_cons != intf->rsp_prod);
++ if (rc < 0)
++ return rc;
++
++ /* Read indexes, then verify. */
++ cons = intf->rsp_cons;
++ prod = intf->rsp_prod;
++ mb();
++ if (!check_indexes(cons, prod)) {
++ intf->rsp_cons = intf->rsp_prod = 0;
++ return -EIO;
++ }
++
++ src = get_input_chunk(cons, prod, intf->rsp, &avail);
++ if (avail == 0)
++ continue;
++ if (avail > len)
++ avail = len;
++
++ /* We must read header before we read data. */
++ rmb();
++
++ memcpy(data, src, avail);
++ data += avail;
++ len -= avail;
++
++ /* Other side must not see free space until we've copied out */
++ mb();
++ intf->rsp_cons += avail;
++
++ pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
++
++ /* Implies mb(): they will see new header. */
++ notify_remote_via_evtchn(xen_store_evtchn);
++ }
++
++ return 0;
++}
++
++/* Set up interrupt handler off store event channel. */
++int xb_init_comms(void)
++{
++ int err;
++
++ if (xenbus_irq)
++ unbind_from_irqhandler(xenbus_irq, &xb_waitq);
++
++ err = bind_evtchn_to_irqhandler(
++ xen_store_evtchn, wake_waiting,
++ 0, "xenbus", &xb_waitq);
++ if (err <= 0) {
++ printk(KERN_ERR "XENBUS request irq failed %i\n", err);
++ return err;
++ }
++
++ xenbus_irq = err;
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_comms.h linux-2.6.18-xen/drivers/xen/xenbus/xenbus_comms.h
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_comms.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_comms.h 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,45 @@
++/*
++ * Private include for xenbus communications.
++ *
++ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 _XENBUS_COMMS_H
++#define _XENBUS_COMMS_H
++
++int xs_init(void);
++int xb_init_comms(void);
++
++/* Low level routines. */
++int xb_write(const void *data, unsigned len);
++int xb_read(void *data, unsigned len);
++int xs_input_avail(void);
++extern wait_queue_head_t xb_waitq;
++extern struct xenstore_domain_interface *xen_store_interface;
++extern int xen_store_evtchn;
++
++#endif /* _XENBUS_COMMS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_dev.c linux-2.6.18-xen/drivers/xen/xenbus/xenbus_dev.c
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_dev.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_dev.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,356 @@
++/*
++ * xenbus_dev.c
++ *
++ * Driver giving user-space access to the kernel's xenbus connection
++ * to xenstore.
++ *
++ * Copyright (c) 2005, Christian Limpach
++ * Copyright (c) 2005, Rusty Russell, IBM 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/uio.h>
++#include <linux/notifier.h>
++#include <linux/wait.h>
++#include <linux/fs.h>
++#include <linux/poll.h>
++
++#include "xenbus_comms.h"
++
++#include <asm/uaccess.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++#include <xen/xen_proc.h>
++#include <asm/hypervisor.h>
++
++struct xenbus_dev_transaction {
++ struct list_head list;
++ struct xenbus_transaction handle;
++};
++
++struct xenbus_dev_data {
++ /* In-progress transaction. */
++ struct list_head transactions;
++
++ /* Active watches. */
++ struct list_head watches;
++
++ /* Partial request. */
++ unsigned int len;
++ union {
++ struct xsd_sockmsg msg;
++ char buffer[PAGE_SIZE];
++ } u;
++
++ /* Response queue. */
++#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
++ char read_buffer[PAGE_SIZE];
++ unsigned int read_cons, read_prod;
++ wait_queue_head_t read_waitq;
++
++ struct mutex reply_mutex;
++};
++
++static struct proc_dir_entry *xenbus_dev_intf;
++
++static ssize_t xenbus_dev_read(struct file *filp,
++ char __user *ubuf,
++ size_t len, loff_t *ppos)
++{
++ struct xenbus_dev_data *u = filp->private_data;
++ int i;
++
++ if (wait_event_interruptible(u->read_waitq,
++ u->read_prod != u->read_cons))
++ return -EINTR;
++
++ for (i = 0; i < len; i++) {
++ if (u->read_cons == u->read_prod)
++ break;
++ put_user(u->read_buffer[MASK_READ_IDX(u->read_cons)], ubuf+i);
++ u->read_cons++;
++ }
++
++ return i;
++}
++
++static void queue_reply(struct xenbus_dev_data *u,
++ char *data, unsigned int len)
++{
++ int i;
++
++ mutex_lock(&u->reply_mutex);
++
++ for (i = 0; i < len; i++, u->read_prod++)
++ u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
++
++ BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
++
++ mutex_unlock(&u->reply_mutex);
++
++ wake_up(&u->read_waitq);
++}
++
++struct watch_adapter
++{
++ struct list_head list;
++ struct xenbus_watch watch;
++ struct xenbus_dev_data *dev_data;
++ char *token;
++};
++
++static void free_watch_adapter (struct watch_adapter *watch)
++{
++ kfree(watch->watch.node);
++ kfree(watch->token);
++ kfree(watch);
++}
++
++static void watch_fired(struct xenbus_watch *watch,
++ const char **vec,
++ unsigned int len)
++{
++ struct watch_adapter *adap =
++ container_of(watch, struct watch_adapter, watch);
++ struct xsd_sockmsg hdr;
++ const char *path, *token;
++ int path_len, tok_len, body_len;
++
++ path = vec[XS_WATCH_PATH];
++ token = adap->token;
++
++ path_len = strlen(path) + 1;
++ tok_len = strlen(token) + 1;
++ body_len = path_len + tok_len;
++
++ hdr.type = XS_WATCH_EVENT;
++ hdr.len = body_len;
++
++ queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr));
++ queue_reply(adap->dev_data, (char *)path, path_len);
++ queue_reply(adap->dev_data, (char *)token, tok_len);
++}
++
++static LIST_HEAD(watch_list);
++
++static ssize_t xenbus_dev_write(struct file *filp,
++ const char __user *ubuf,
++ size_t len, loff_t *ppos)
++{
++ struct xenbus_dev_data *u = filp->private_data;
++ struct xenbus_dev_transaction *trans = NULL;
++ uint32_t msg_type;
++ void *reply;
++ char *path, *token;
++ struct watch_adapter *watch, *tmp_watch;
++ int err;
++
++ if ((len + u->len) > sizeof(u->u.buffer))
++ return -EINVAL;
++
++ if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0)
++ return -EFAULT;
++
++ u->len += len;
++ if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
++ return len;
++
++ msg_type = u->u.msg.type;
++
++ switch (msg_type) {
++ case XS_TRANSACTION_START:
++ case XS_TRANSACTION_END:
++ case XS_DIRECTORY:
++ case XS_READ:
++ case XS_GET_PERMS:
++ case XS_RELEASE:
++ case XS_GET_DOMAIN_PATH:
++ case XS_WRITE:
++ case XS_MKDIR:
++ case XS_RM:
++ case XS_SET_PERMS:
++ if (msg_type == XS_TRANSACTION_START) {
++ trans = kmalloc(sizeof(*trans), GFP_KERNEL);
++ if (!trans)
++ return -ENOMEM;
++ }
++
++ reply = xenbus_dev_request_and_reply(&u->u.msg);
++ if (IS_ERR(reply)) {
++ kfree(trans);
++ return PTR_ERR(reply);
++ }
++
++ if (msg_type == XS_TRANSACTION_START) {
++ trans->handle.id = simple_strtoul(reply, NULL, 0);
++ list_add(&trans->list, &u->transactions);
++ } else if (msg_type == XS_TRANSACTION_END) {
++ list_for_each_entry(trans, &u->transactions, list)
++ if (trans->handle.id == u->u.msg.tx_id)
++ break;
++ BUG_ON(&trans->list == &u->transactions);
++ list_del(&trans->list);
++ kfree(trans);
++ }
++ queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
++ queue_reply(u, (char *)reply, u->u.msg.len);
++ kfree(reply);
++ break;
++
++ case XS_WATCH:
++ case XS_UNWATCH:
++ path = u->u.buffer + sizeof(u->u.msg);
++ token = memchr(path, 0, u->u.msg.len);
++ if (token == NULL)
++ return -EILSEQ;
++ token++;
++
++ if (msg_type == XS_WATCH) {
++ static const char * XS_WATCH_RESP = "OK";
++ struct xsd_sockmsg hdr;
++
++ watch = kmalloc(sizeof(*watch), GFP_KERNEL);
++ watch->watch.node = kmalloc(strlen(path)+1,
++ GFP_KERNEL);
++ strcpy((char *)watch->watch.node, path);
++ watch->watch.callback = watch_fired;
++ watch->token = kmalloc(strlen(token)+1, GFP_KERNEL);
++ strcpy(watch->token, token);
++ watch->dev_data = u;
++
++ err = register_xenbus_watch(&watch->watch);
++ if (err) {
++ free_watch_adapter(watch);
++ return err;
++ }
++
++ list_add(&watch->list, &u->watches);
++
++ hdr.type = XS_WATCH;
++ hdr.len = strlen(XS_WATCH_RESP) + 1;
++ queue_reply(u, (char *)&hdr, sizeof(hdr));
++ queue_reply(u, (char *)XS_WATCH_RESP, hdr.len);
++ } else {
++ list_for_each_entry_safe(watch, tmp_watch,
++ &u->watches, list) {
++ if (!strcmp(watch->token, token) &&
++ !strcmp(watch->watch.node, path))
++ break;
++ {
++ unregister_xenbus_watch(&watch->watch);
++ list_del(&watch->list);
++ free_watch_adapter(watch);
++ break;
++ }
++ }
++ }
++
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ u->len = 0;
++ return len;
++}
++
++static int xenbus_dev_open(struct inode *inode, struct file *filp)
++{
++ struct xenbus_dev_data *u;
++
++ if (xen_store_evtchn == 0)
++ return -ENOENT;
++
++ nonseekable_open(inode, filp);
++
++ u = kzalloc(sizeof(*u), GFP_KERNEL);
++ if (u == NULL)
++ return -ENOMEM;
++
++ INIT_LIST_HEAD(&u->transactions);
++ INIT_LIST_HEAD(&u->watches);
++ init_waitqueue_head(&u->read_waitq);
++
++ mutex_init(&u->reply_mutex);
++
++ filp->private_data = u;
++
++ return 0;
++}
++
++static int xenbus_dev_release(struct inode *inode, struct file *filp)
++{
++ struct xenbus_dev_data *u = filp->private_data;
++ struct xenbus_dev_transaction *trans, *tmp;
++ struct watch_adapter *watch, *tmp_watch;
++
++ list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
++ xenbus_transaction_end(trans->handle, 1);
++ list_del(&trans->list);
++ kfree(trans);
++ }
++
++ list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
++ unregister_xenbus_watch(&watch->watch);
++ list_del(&watch->list);
++ free_watch_adapter(watch);
++ }
++
++ kfree(u);
++
++ return 0;
++}
++
++static unsigned int xenbus_dev_poll(struct file *file, poll_table *wait)
++{
++ struct xenbus_dev_data *u = file->private_data;
++
++ poll_wait(file, &u->read_waitq, wait);
++ if (u->read_cons != u->read_prod)
++ return POLLIN | POLLRDNORM;
++ return 0;
++}
++
++static struct file_operations xenbus_dev_file_ops = {
++ .read = xenbus_dev_read,
++ .write = xenbus_dev_write,
++ .open = xenbus_dev_open,
++ .release = xenbus_dev_release,
++ .poll = xenbus_dev_poll,
++};
++
++int __init
++xenbus_dev_init(void)
++{
++ xenbus_dev_intf = create_xen_proc_entry("xenbus", 0400);
++ if (xenbus_dev_intf)
++ xenbus_dev_intf->proc_fops = &xenbus_dev_file_ops;
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_probe.c linux-2.6.18-xen/drivers/xen/xenbus/xenbus_probe.c
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_probe.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_probe.c 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,1190 @@
++/******************************************************************************
++ * Talks to Xen Store to figure out what devices we have.
++ *
++ * Copyright (C) 2005 Rusty Russell, IBM Corporation
++ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
++ * Copyright (C) 2005, 2006 XenSource Ltd
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#define DPRINTK(fmt, args...) \
++ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
++ __FUNCTION__, __LINE__, ##args)
++
++#include <linux/kernel.h>
++#include <linux/err.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/fcntl.h>
++#include <linux/mm.h>
++#include <linux/notifier.h>
++#include <linux/kthread.h>
++
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/maddr.h>
++#include <asm/pgtable.h>
++#include <asm/hypervisor.h>
++#include <asm/hypercall.h>
++#include <xen/xenbus.h>
++#include <xen/xen_proc.h>
++#include <xen/evtchn.h>
++#include <xen/features.h>
++#include <xen/hvm.h>
++
++#include "xenbus_comms.h"
++
++int xen_store_evtchn;
++struct xenstore_domain_interface *xen_store_interface;
++static unsigned long xen_store_mfn;
++
++extern struct mutex xenwatch_mutex;
++
++static BLOCKING_NOTIFIER_HEAD(xenstore_notifier_list);
++
++static void wait_for_devices(struct xenbus_driver *xendrv);
++
++static int xenbus_probe_frontend(const char *type, const char *name);
++static int xenbus_uevent_backend(struct device *dev, char **envp,
++ int num_envp, char *buffer, int buffer_size);
++static int xenbus_probe_backend(const char *type, const char *domid);
++
++static int xenbus_dev_probe(struct device *_dev);
++static int xenbus_dev_remove(struct device *_dev);
++static void xenbus_dev_shutdown(struct device *_dev);
++
++/* If something in array of ids matches this device, return it. */
++static const struct xenbus_device_id *
++match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
++{
++ for (; *arr->devicetype != '\0'; arr++) {
++ if (!strcmp(arr->devicetype, dev->devicetype))
++ return arr;
++ }
++ return NULL;
++}
++
++static int xenbus_match(struct device *_dev, struct device_driver *_drv)
++{
++ struct xenbus_driver *drv = to_xenbus_driver(_drv);
++
++ if (!drv->ids)
++ return 0;
++
++ return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
++}
++
++struct xen_bus_type
++{
++ char *root;
++ unsigned int levels;
++ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
++ int (*probe)(const char *type, const char *dir);
++ struct bus_type bus;
++ struct device dev;
++};
++
++
++/* device/<type>/<id> => <type>-<id> */
++static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
++{
++ nodename = strchr(nodename, '/');
++ if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
++ printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
++ return -EINVAL;
++ }
++
++ strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
++ if (!strchr(bus_id, '/')) {
++ printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
++ return -EINVAL;
++ }
++ *strchr(bus_id, '/') = '-';
++ return 0;
++}
++
++
++static void free_otherend_details(struct xenbus_device *dev)
++{
++ kfree(dev->otherend);
++ dev->otherend = NULL;
++}
++
++
++static void free_otherend_watch(struct xenbus_device *dev)
++{
++ if (dev->otherend_watch.node) {
++ unregister_xenbus_watch(&dev->otherend_watch);
++ kfree(dev->otherend_watch.node);
++ dev->otherend_watch.node = NULL;
++ }
++}
++
++
++static int read_otherend_details(struct xenbus_device *xendev,
++ char *id_node, char *path_node)
++{
++ int err = xenbus_gather(XBT_NIL, xendev->nodename,
++ id_node, "%i", &xendev->otherend_id,
++ path_node, NULL, &xendev->otherend,
++ NULL);
++ if (err) {
++ xenbus_dev_fatal(xendev, err,
++ "reading other end details from %s",
++ xendev->nodename);
++ return err;
++ }
++ if (strlen(xendev->otherend) == 0 ||
++ !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
++ xenbus_dev_fatal(xendev, -ENOENT,
++ "unable to read other end from %s. "
++ "missing or inaccessible.",
++ xendev->nodename);
++ free_otherend_details(xendev);
++ return -ENOENT;
++ }
++
++ return 0;
++}
++
++
++static int read_backend_details(struct xenbus_device *xendev)
++{
++ return read_otherend_details(xendev, "backend-id", "backend");
++}
++
++
++static int read_frontend_details(struct xenbus_device *xendev)
++{
++ return read_otherend_details(xendev, "frontend-id", "frontend");
++}
++
++
++/* Bus type for frontend drivers. */
++static struct xen_bus_type xenbus_frontend = {
++ .root = "device",
++ .levels = 2, /* device/type/<id> */
++ .get_bus_id = frontend_bus_id,
++ .probe = xenbus_probe_frontend,
++ .bus = {
++ .name = "xen",
++ .match = xenbus_match,
++ .probe = xenbus_dev_probe,
++ .remove = xenbus_dev_remove,
++ .shutdown = xenbus_dev_shutdown,
++ },
++ .dev = {
++ .bus_id = "xen",
++ },
++};
++
++/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
++static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
++{
++ int domid, err;
++ const char *devid, *type, *frontend;
++ unsigned int typelen;
++
++ type = strchr(nodename, '/');
++ if (!type)
++ return -EINVAL;
++ type++;
++ typelen = strcspn(type, "/");
++ if (!typelen || type[typelen] != '/')
++ return -EINVAL;
++
++ devid = strrchr(nodename, '/') + 1;
++
++ err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
++ "frontend", NULL, &frontend,
++ NULL);
++ if (err)
++ return err;
++ if (strlen(frontend) == 0)
++ err = -ERANGE;
++ if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
++ err = -ENOENT;
++
++ kfree(frontend);
++
++ if (err)
++ return err;
++
++ if (snprintf(bus_id, BUS_ID_SIZE,
++ "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
++ return -ENOSPC;
++ return 0;
++}
++
++static struct xen_bus_type xenbus_backend = {
++ .root = "backend",
++ .levels = 3, /* backend/type/<frontend>/<id> */
++ .get_bus_id = backend_bus_id,
++ .probe = xenbus_probe_backend,
++ .bus = {
++ .name = "xen-backend",
++ .match = xenbus_match,
++ .probe = xenbus_dev_probe,
++ .remove = xenbus_dev_remove,
++// .shutdown = xenbus_dev_shutdown,
++ .uevent = xenbus_uevent_backend,
++ },
++ .dev = {
++ .bus_id = "xen-backend",
++ },
++};
++
++static int xenbus_uevent_backend(struct device *dev, char **envp,
++ int num_envp, char *buffer, int buffer_size)
++{
++ struct xenbus_device *xdev;
++ struct xenbus_driver *drv;
++ int i = 0;
++ int length = 0;
++
++ DPRINTK("");
++
++ if (dev == NULL)
++ return -ENODEV;
++
++ xdev = to_xenbus_device(dev);
++ if (xdev == NULL)
++ return -ENODEV;
++
++ /* stuff we want to pass to /sbin/hotplug */
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "XENBUS_TYPE=%s", xdev->devicetype);
++
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "XENBUS_PATH=%s", xdev->nodename);
++
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "XENBUS_BASE_PATH=%s", xenbus_backend.root);
++
++ /* terminate, set to next free slot, shrink available space */
++ envp[i] = NULL;
++ envp = &envp[i];
++ num_envp -= i;
++ buffer = &buffer[length];
++ buffer_size -= length;
++
++ if (dev->driver) {
++ drv = to_xenbus_driver(dev->driver);
++ if (drv && drv->uevent)
++ return drv->uevent(xdev, envp, num_envp, buffer,
++ buffer_size);
++ }
++
++ return 0;
++}
++
++static void otherend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ struct xenbus_device *dev =
++ container_of(watch, struct xenbus_device, otherend_watch);
++ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
++ enum xenbus_state state;
++
++ /* Protect us against watches firing on old details when the otherend
++ details change, say immediately after a resume. */
++ if (!dev->otherend ||
++ strncmp(dev->otherend, vec[XS_WATCH_PATH],
++ strlen(dev->otherend))) {
++ DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]);
++ return;
++ }
++
++ state = xenbus_read_driver_state(dev->otherend);
++
++ DPRINTK("state is %d (%s), %s, %s", state, xenbus_strstate(state),
++ dev->otherend_watch.node, vec[XS_WATCH_PATH]);
++
++ /*
++ * Ignore xenbus transitions during shutdown. This prevents us doing
++ * work that can fail e.g., when the rootfs is gone.
++ */
++ if (system_state > SYSTEM_RUNNING) {
++ struct xen_bus_type *bus = bus;
++ bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
++ /* If we're frontend, drive the state machine to Closed. */
++ /* This should cause the backend to release our resources. */
++ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
++ xenbus_frontend_closed(dev);
++ return;
++ }
++
++ if (drv->otherend_changed)
++ drv->otherend_changed(dev, state);
++}
++
++
++static int talk_to_otherend(struct xenbus_device *dev)
++{
++ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
++
++ free_otherend_watch(dev);
++ free_otherend_details(dev);
++
++ return drv->read_otherend_details(dev);
++}
++
++
++static int watch_otherend(struct xenbus_device *dev)
++{
++ return xenbus_watch_path2(dev, dev->otherend, "state",
++ &dev->otherend_watch, otherend_changed);
++}
++
++
++static int xenbus_dev_probe(struct device *_dev)
++{
++ struct xenbus_device *dev = to_xenbus_device(_dev);
++ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
++ const struct xenbus_device_id *id;
++ int err;
++
++ DPRINTK("%s", dev->nodename);
++
++ if (!drv->probe) {
++ err = -ENODEV;
++ goto fail;
++ }
++
++ id = match_device(drv->ids, dev);
++ if (!id) {
++ err = -ENODEV;
++ goto fail;
++ }
++
++ err = talk_to_otherend(dev);
++ if (err) {
++ printk(KERN_WARNING
++ "xenbus_probe: talk_to_otherend on %s failed.\n",
++ dev->nodename);
++ return err;
++ }
++
++ err = drv->probe(dev, id);
++ if (err)
++ goto fail;
++
++ err = watch_otherend(dev);
++ if (err) {
++ printk(KERN_WARNING
++ "xenbus_probe: watch_otherend on %s failed.\n",
++ dev->nodename);
++ return err;
++ }
++
++ return 0;
++fail:
++ xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
++ xenbus_switch_state(dev, XenbusStateClosed);
++ return -ENODEV;
++}
++
++static int xenbus_dev_remove(struct device *_dev)
++{
++ struct xenbus_device *dev = to_xenbus_device(_dev);
++ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
++
++ DPRINTK("%s", dev->nodename);
++
++ free_otherend_watch(dev);
++ free_otherend_details(dev);
++
++ if (drv->remove)
++ drv->remove(dev);
++
++ xenbus_switch_state(dev, XenbusStateClosed);
++ return 0;
++}
++
++static void xenbus_dev_shutdown(struct device *_dev)
++{
++ struct xenbus_device *dev = to_xenbus_device(_dev);
++ unsigned long timeout = 5*HZ;
++
++ DPRINTK("%s", dev->nodename);
++
++ get_device(&dev->dev);
++ if (dev->state != XenbusStateConnected) {
++ printk("%s: %s: %s != Connected, skipping\n", __FUNCTION__,
++ dev->nodename, xenbus_strstate(dev->state));
++ goto out;
++ }
++ xenbus_switch_state(dev, XenbusStateClosing);
++ timeout = wait_for_completion_timeout(&dev->down, timeout);
++ if (!timeout)
++ printk("%s: %s timeout closing device\n", __FUNCTION__, dev->nodename);
++ out:
++ put_device(&dev->dev);
++}
++
++static int xenbus_register_driver_common(struct xenbus_driver *drv,
++ struct xen_bus_type *bus)
++{
++ int ret;
++
++ drv->driver.name = drv->name;
++ drv->driver.bus = &bus->bus;
++ drv->driver.owner = drv->owner;
++
++ mutex_lock(&xenwatch_mutex);
++ ret = driver_register(&drv->driver);
++ mutex_unlock(&xenwatch_mutex);
++ return ret;
++}
++
++int xenbus_register_frontend(struct xenbus_driver *drv)
++{
++ int ret;
++
++ drv->read_otherend_details = read_backend_details;
++
++ ret = xenbus_register_driver_common(drv, &xenbus_frontend);
++ if (ret)
++ return ret;
++
++ /* If this driver is loaded as a module wait for devices to attach. */
++ wait_for_devices(drv);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xenbus_register_frontend);
++
++int xenbus_register_backend(struct xenbus_driver *drv)
++{
++ drv->read_otherend_details = read_frontend_details;
++
++ return xenbus_register_driver_common(drv, &xenbus_backend);
++}
++EXPORT_SYMBOL_GPL(xenbus_register_backend);
++
++void xenbus_unregister_driver(struct xenbus_driver *drv)
++{
++ driver_unregister(&drv->driver);
++}
++EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
++
++struct xb_find_info
++{
++ struct xenbus_device *dev;
++ const char *nodename;
++};
++
++static int cmp_dev(struct device *dev, void *data)
++{
++ struct xenbus_device *xendev = to_xenbus_device(dev);
++ struct xb_find_info *info = data;
++
++ if (!strcmp(xendev->nodename, info->nodename)) {
++ info->dev = xendev;
++ get_device(dev);
++ return 1;
++ }
++ return 0;
++}
++
++struct xenbus_device *xenbus_device_find(const char *nodename,
++ struct bus_type *bus)
++{
++ struct xb_find_info info = { .dev = NULL, .nodename = nodename };
++
++ bus_for_each_dev(bus, NULL, &info, cmp_dev);
++ return info.dev;
++}
++
++static int cleanup_dev(struct device *dev, void *data)
++{
++ struct xenbus_device *xendev = to_xenbus_device(dev);
++ struct xb_find_info *info = data;
++ int len = strlen(info->nodename);
++
++ DPRINTK("%s", info->nodename);
++
++ /* Match the info->nodename path, or any subdirectory of that path. */
++ if (strncmp(xendev->nodename, info->nodename, len))
++ return 0;
++
++ /* If the node name is longer, ensure it really is a subdirectory. */
++ if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
++ return 0;
++
++ info->dev = xendev;
++ get_device(dev);
++ return 1;
++}
++
++static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
++{
++ struct xb_find_info info = { .nodename = path };
++
++ do {
++ info.dev = NULL;
++ bus_for_each_dev(bus, NULL, &info, cleanup_dev);
++ if (info.dev) {
++ device_unregister(&info.dev->dev);
++ put_device(&info.dev->dev);
++ }
++ } while (info.dev);
++}
++
++static void xenbus_dev_release(struct device *dev)
++{
++ if (dev)
++ kfree(to_xenbus_device(dev));
++}
++
++static ssize_t xendev_show_nodename(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
++}
++DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
++
++static ssize_t xendev_show_devtype(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
++}
++DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
++
++
++static int xenbus_probe_node(struct xen_bus_type *bus,
++ const char *type,
++ const char *nodename)
++{
++ int err;
++ struct xenbus_device *xendev;
++ size_t stringlen;
++ char *tmpstring;
++
++ enum xenbus_state state = xenbus_read_driver_state(nodename);
++
++ if (state != XenbusStateInitialising) {
++ /* Device is not new, so ignore it. This can happen if a
++ device is going away after switching to Closed. */
++ return 0;
++ }
++
++ stringlen = strlen(nodename) + 1 + strlen(type) + 1;
++ xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
++ if (!xendev)
++ return -ENOMEM;
++
++ /* Copy the strings into the extra space. */
++
++ tmpstring = (char *)(xendev + 1);
++ strcpy(tmpstring, nodename);
++ xendev->nodename = tmpstring;
++
++ tmpstring += strlen(tmpstring) + 1;
++ strcpy(tmpstring, type);
++ xendev->devicetype = tmpstring;
++ init_completion(&xendev->down);
++
++ xendev->dev.parent = &bus->dev;
++ xendev->dev.bus = &bus->bus;
++ xendev->dev.release = xenbus_dev_release;
++
++ err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
++ if (err)
++ goto fail;
++
++ /* Register with generic device framework. */
++ err = device_register(&xendev->dev);
++ if (err)
++ goto fail;
++
++ device_create_file(&xendev->dev, &dev_attr_nodename);
++ device_create_file(&xendev->dev, &dev_attr_devtype);
++
++ return 0;
++fail:
++ kfree(xendev);
++ return err;
++}
++
++/* device/<typename>/<name> */
++static int xenbus_probe_frontend(const char *type, const char *name)
++{
++ char *nodename;
++ int err;
++
++ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_frontend.root, type, name);
++ if (!nodename)
++ return -ENOMEM;
++
++ DPRINTK("%s", nodename);
++
++ err = xenbus_probe_node(&xenbus_frontend, type, nodename);
++ kfree(nodename);
++ return err;
++}
++
++/* backend/<typename>/<frontend-uuid>/<name> */
++static int xenbus_probe_backend_unit(const char *dir,
++ const char *type,
++ const char *name)
++{
++ char *nodename;
++ int err;
++
++ nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
++ if (!nodename)
++ return -ENOMEM;
++
++ DPRINTK("%s\n", nodename);
++
++ err = xenbus_probe_node(&xenbus_backend, type, nodename);
++ kfree(nodename);
++ return err;
++}
++
++/* backend/<typename>/<frontend-domid> */
++static int xenbus_probe_backend(const char *type, const char *domid)
++{
++ char *nodename;
++ int err = 0;
++ char **dir;
++ unsigned int i, dir_n = 0;
++
++ DPRINTK("");
++
++ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
++ if (!nodename)
++ return -ENOMEM;
++
++ dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
++ if (IS_ERR(dir)) {
++ kfree(nodename);
++ return PTR_ERR(dir);
++ }
++
++ for (i = 0; i < dir_n; i++) {
++ err = xenbus_probe_backend_unit(nodename, type, dir[i]);
++ if (err)
++ break;
++ }
++ kfree(dir);
++ kfree(nodename);
++ return err;
++}
++
++static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
++{
++ int err = 0;
++ char **dir;
++ unsigned int dir_n = 0;
++ int i;
++
++ dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
++ if (IS_ERR(dir))
++ return PTR_ERR(dir);
++
++ for (i = 0; i < dir_n; i++) {
++ err = bus->probe(type, dir[i]);
++ if (err)
++ break;
++ }
++ kfree(dir);
++ return err;
++}
++
++static int xenbus_probe_devices(struct xen_bus_type *bus)
++{
++ int err = 0;
++ char **dir;
++ unsigned int i, dir_n;
++
++ dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
++ if (IS_ERR(dir))
++ return PTR_ERR(dir);
++
++ for (i = 0; i < dir_n; i++) {
++ err = xenbus_probe_device_type(bus, dir[i]);
++ if (err)
++ break;
++ }
++ kfree(dir);
++ return err;
++}
++
++static unsigned int char_count(const char *str, char c)
++{
++ unsigned int i, ret = 0;
++
++ for (i = 0; str[i]; i++)
++ if (str[i] == c)
++ ret++;
++ return ret;
++}
++
++static int strsep_len(const char *str, char c, unsigned int len)
++{
++ unsigned int i;
++
++ for (i = 0; str[i]; i++)
++ if (str[i] == c) {
++ if (len == 0)
++ return i;
++ len--;
++ }
++ return (len == 0) ? i : -ERANGE;
++}
++
++static void dev_changed(const char *node, struct xen_bus_type *bus)
++{
++ int exists, rootlen;
++ struct xenbus_device *dev;
++ char type[BUS_ID_SIZE];
++ const char *p, *root;
++
++ if (char_count(node, '/') < 2)
++ return;
++
++ exists = xenbus_exists(XBT_NIL, node, "");
++ if (!exists) {
++ xenbus_cleanup_devices(node, &bus->bus);
++ return;
++ }
++
++ /* backend/<type>/... or device/<type>/... */
++ p = strchr(node, '/') + 1;
++ snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
++ type[BUS_ID_SIZE-1] = '\0';
++
++ rootlen = strsep_len(node, '/', bus->levels);
++ if (rootlen < 0)
++ return;
++ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
++ if (!root)
++ return;
++
++ dev = xenbus_device_find(root, &bus->bus);
++ if (!dev)
++ xenbus_probe_node(bus, type, root);
++ else
++ put_device(&dev->dev);
++
++ kfree(root);
++}
++
++static void frontend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ DPRINTK("");
++
++ dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
++}
++
++static void backend_changed(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
++{
++ DPRINTK("");
++
++ dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
++}
++
++/* We watch for devices appearing and vanishing. */
++static struct xenbus_watch fe_watch = {
++ .node = "device",
++ .callback = frontend_changed,
++};
++
++static struct xenbus_watch be_watch = {
++ .node = "backend",
++ .callback = backend_changed,
++};
++
++static int suspend_dev(struct device *dev, void *data)
++{
++ int err = 0;
++ struct xenbus_driver *drv;
++ struct xenbus_device *xdev;
++
++ DPRINTK("");
++
++ if (dev->driver == NULL)
++ return 0;
++ drv = to_xenbus_driver(dev->driver);
++ xdev = container_of(dev, struct xenbus_device, dev);
++ if (drv->suspend)
++ err = drv->suspend(xdev);
++ if (err)
++ printk(KERN_WARNING
++ "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
++ return 0;
++}
++
++static int resume_dev(struct device *dev, void *data)
++{
++ int err;
++ struct xenbus_driver *drv;
++ struct xenbus_device *xdev;
++
++ DPRINTK("");
++
++ if (dev->driver == NULL)
++ return 0;
++
++ drv = to_xenbus_driver(dev->driver);
++ xdev = container_of(dev, struct xenbus_device, dev);
++
++ err = talk_to_otherend(xdev);
++ if (err) {
++ printk(KERN_WARNING
++ "xenbus: resume (talk_to_otherend) %s failed: %i\n",
++ dev->bus_id, err);
++ return err;
++ }
++
++ xdev->state = XenbusStateInitialising;
++
++ if (drv->resume) {
++ err = drv->resume(xdev);
++ if (err) {
++ printk(KERN_WARNING
++ "xenbus: resume %s failed: %i\n",
++ dev->bus_id, err);
++ return err;
++ }
++ }
++
++ err = watch_otherend(xdev);
++ if (err) {
++ printk(KERN_WARNING
++ "xenbus_probe: resume (watch_otherend) %s failed: "
++ "%d.\n", dev->bus_id, err);
++ return err;
++ }
++
++ return 0;
++}
++
++void xenbus_suspend(void)
++{
++ DPRINTK("");
++
++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
++ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
++ xs_suspend();
++}
++EXPORT_SYMBOL_GPL(xenbus_suspend);
++
++void xenbus_resume(void)
++{
++ xb_init_comms();
++ xs_resume();
++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
++ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
++}
++EXPORT_SYMBOL_GPL(xenbus_resume);
++
++
++/* A flag to determine if xenstored is 'ready' (i.e. has started) */
++int xenstored_ready = 0;
++
++
++int register_xenstore_notifier(struct notifier_block *nb)
++{
++ int ret = 0;
++
++ if (xenstored_ready > 0)
++ ret = nb->notifier_call(nb, 0, NULL);
++ else
++ blocking_notifier_chain_register(&xenstore_notifier_list, nb);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(register_xenstore_notifier);
++
++void unregister_xenstore_notifier(struct notifier_block *nb)
++{
++ blocking_notifier_chain_unregister(&xenstore_notifier_list, nb);
++}
++EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
++
++
++void xenbus_probe(void *unused)
++{
++ BUG_ON((xenstored_ready <= 0));
++
++ /* Enumerate devices in xenstore. */
++ xenbus_probe_devices(&xenbus_frontend);
++ xenbus_probe_devices(&xenbus_backend);
++
++ /* Watch for changes. */
++ register_xenbus_watch(&fe_watch);
++ register_xenbus_watch(&be_watch);
++
++ /* Notify others that xenstore is up */
++ blocking_notifier_call_chain(&xenstore_notifier_list, 0, NULL);
++}
++
++
++#ifdef CONFIG_PROC_FS
++static struct file_operations xsd_kva_fops;
++static struct proc_dir_entry *xsd_kva_intf;
++static struct proc_dir_entry *xsd_port_intf;
++
++static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ size_t size = vma->vm_end - vma->vm_start;
++
++ if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
++ return -EINVAL;
++
++ if (remap_pfn_range(vma, vma->vm_start, mfn_to_pfn(xen_store_mfn),
++ size, vma->vm_page_prot))
++ return -EAGAIN;
++
++ return 0;
++}
++
++static int xsd_kva_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "0x%p", xen_store_interface);
++ *eof = 1;
++ return len;
++}
++
++static int xsd_port_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d", xen_store_evtchn);
++ *eof = 1;
++ return len;
++}
++#endif
++
++static int __init xenbus_probe_init(void)
++{
++ int err = 0;
++ unsigned long page = 0;
++
++ DPRINTK("");
++
++ if (!is_running_on_xen())
++ return -ENODEV;
++
++ /* Register ourselves with the kernel bus subsystem */
++ bus_register(&xenbus_frontend.bus);
++ bus_register(&xenbus_backend.bus);
++
++ /*
++ * Domain0 doesn't have a store_evtchn or store_mfn yet.
++ */
++ if (is_initial_xendomain()) {
++ struct evtchn_alloc_unbound alloc_unbound;
++
++ /* Allocate page. */
++ page = get_zeroed_page(GFP_KERNEL);
++ if (!page)
++ return -ENOMEM;
++
++ xen_store_mfn = xen_start_info->store_mfn =
++ pfn_to_mfn(virt_to_phys((void *)page) >>
++ PAGE_SHIFT);
++
++ /* Next allocate a local port which xenstored can bind to */
++ alloc_unbound.dom = DOMID_SELF;
++ alloc_unbound.remote_dom = 0;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
++ &alloc_unbound);
++ if (err == -ENOSYS)
++ goto err;
++ BUG_ON(err);
++ xen_store_evtchn = xen_start_info->store_evtchn =
++ alloc_unbound.port;
++
++#ifdef CONFIG_PROC_FS
++ /* And finally publish the above info in /proc/xen */
++ xsd_kva_intf = create_xen_proc_entry("xsd_kva", 0600);
++ if (xsd_kva_intf) {
++ memcpy(&xsd_kva_fops, xsd_kva_intf->proc_fops,
++ sizeof(xsd_kva_fops));
++ xsd_kva_fops.mmap = xsd_kva_mmap;
++ xsd_kva_intf->proc_fops = &xsd_kva_fops;
++ xsd_kva_intf->read_proc = xsd_kva_read;
++ }
++ xsd_port_intf = create_xen_proc_entry("xsd_port", 0400);
++ if (xsd_port_intf)
++ xsd_port_intf->read_proc = xsd_port_read;
++#endif
++ xen_store_interface = mfn_to_virt(xen_store_mfn);
++ } else {
++ xenstored_ready = 1;
++#ifdef CONFIG_XEN
++ xen_store_evtchn = xen_start_info->store_evtchn;
++ xen_store_mfn = xen_start_info->store_mfn;
++ xen_store_interface = mfn_to_virt(xen_store_mfn);
++#else
++ xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);
++ xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN);
++ xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT,
++ PAGE_SIZE);
++#endif
++ }
++
++
++ xenbus_dev_init();
++
++ /* Initialize the interface to xenstore. */
++ err = xs_init();
++ if (err) {
++ printk(KERN_WARNING
++ "XENBUS: Error initializing xenstore comms: %i\n", err);
++ goto err;
++ }
++
++ /* Register ourselves with the kernel device subsystem */
++ device_register(&xenbus_frontend.dev);
++ device_register(&xenbus_backend.dev);
++
++ if (!is_initial_xendomain())
++ xenbus_probe(NULL);
++
++ return 0;
++
++ err:
++ if (page)
++ free_page(page);
++
++ /*
++ * Do not unregister the xenbus front/backend buses here. The buses
++ * must exist because front/backend drivers will use them when they are
++ * registered.
++ */
++
++ return err;
++}
++
++postcore_initcall(xenbus_probe_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
++
++
++static int is_disconnected_device(struct device *dev, void *data)
++{
++ struct xenbus_device *xendev = to_xenbus_device(dev);
++ struct device_driver *drv = data;
++
++ /*
++ * A device with no driver will never connect. We care only about
++ * devices which should currently be in the process of connecting.
++ */
++ if (!dev->driver)
++ return 0;
++
++ /* Is this search limited to a particular driver? */
++ if (drv && (dev->driver != drv))
++ return 0;
++
++ return (xendev->state != XenbusStateConnected);
++}
++
++static int exists_disconnected_device(struct device_driver *drv)
++{
++ return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
++ is_disconnected_device);
++}
++
++static int print_device_status(struct device *dev, void *data)
++{
++ struct xenbus_device *xendev = to_xenbus_device(dev);
++ struct device_driver *drv = data;
++
++ /* Is this operation limited to a particular driver? */
++ if (drv && (dev->driver != drv))
++ return 0;
++
++ if (!dev->driver) {
++ /* Information only: is this too noisy? */
++ printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
++ xendev->nodename);
++ } else if (xendev->state != XenbusStateConnected) {
++ printk(KERN_WARNING "XENBUS: Timeout connecting "
++ "to device: %s (state %d)\n",
++ xendev->nodename, xendev->state);
++ }
++
++ return 0;
++}
++
++/* We only wait for device setup after most initcalls have run. */
++static int ready_to_wait_for_devices;
++
++/*
++ * On a 10 second timeout, wait for all devices currently configured. We need
++ * to do this to guarantee that the filesystems and / or network devices
++ * needed for boot are available, before we can allow the boot to proceed.
++ *
++ * This needs to be on a late_initcall, to happen after the frontend device
++ * drivers have been initialised, but before the root fs is mounted.
++ *
++ * A possible improvement here would be to have the tools add a per-device
++ * flag to the store entry, indicating whether it is needed at boot time.
++ * This would allow people who knew what they were doing to accelerate their
++ * boot slightly, but of course needs tools or manual intervention to set up
++ * those flags correctly.
++ */
++static void wait_for_devices(struct xenbus_driver *xendrv)
++{
++ unsigned long timeout = jiffies + 10*HZ;
++ struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
++
++ if (!ready_to_wait_for_devices || !is_running_on_xen())
++ return;
++
++ while (exists_disconnected_device(drv)) {
++ if (time_after(jiffies, timeout))
++ break;
++ schedule_timeout_interruptible(HZ/10);
++ }
++
++ bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
++ print_device_status);
++}
++
++#ifndef MODULE
++static int __init boot_wait_for_devices(void)
++{
++ ready_to_wait_for_devices = 1;
++ wait_for_devices(NULL);
++ return 0;
++}
++
++late_initcall(boot_wait_for_devices);
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/drivers/xen/xenbus/xenbus_xs.c linux-2.6.18-xen/drivers/xen/xenbus/xenbus_xs.c
+--- linux-2.6.18.1/drivers/xen/xenbus/xenbus_xs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/drivers/xen/xenbus/xenbus_xs.c 2006-09-04 16:31:13.000000000 +0200
+@@ -0,0 +1,853 @@
++/******************************************************************************
++ * xenbus_xs.c
++ *
++ * This is the kernel equivalent of the "xs" library. We don't need everything
++ * and we use xenbus_comms for communication.
++ *
++ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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.
++ */
++
++#include <linux/unistd.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/uio.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/fcntl.h>
++#include <linux/kthread.h>
++#include <linux/rwsem.h>
++#include <xen/xenbus.h>
++#include "xenbus_comms.h"
++
++struct xs_stored_msg {
++ struct list_head list;
++
++ struct xsd_sockmsg hdr;
++
++ union {
++ /* Queued replies. */
++ struct {
++ char *body;
++ } reply;
++
++ /* Queued watch events. */
++ struct {
++ struct xenbus_watch *handle;
++ char **vec;
++ unsigned int vec_size;
++ } watch;
++ } u;
++};
++
++struct xs_handle {
++ /* A list of replies. Currently only one will ever be outstanding. */
++ struct list_head reply_list;
++ spinlock_t reply_lock;
++ wait_queue_head_t reply_waitq;
++
++ /* One request at a time. */
++ struct mutex request_mutex;
++
++ /* Protect transactions against save/restore. */
++ struct rw_semaphore suspend_mutex;
++};
++
++static struct xs_handle xs_state;
++
++/* List of registered watches, and a lock to protect it. */
++static LIST_HEAD(watches);
++static DEFINE_SPINLOCK(watches_lock);
++
++/* List of pending watch callback events, and a lock to protect it. */
++static LIST_HEAD(watch_events);
++static DEFINE_SPINLOCK(watch_events_lock);
++
++/*
++ * Details of the xenwatch callback kernel thread. The thread waits on the
++ * watch_events_waitq for work to do (queued on watch_events list). When it
++ * wakes up it acquires the xenwatch_mutex before reading the list and
++ * carrying out work.
++ */
++static pid_t xenwatch_pid;
++/* static */ DEFINE_MUTEX(xenwatch_mutex);
++static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
++
++static int get_error(const char *errorstring)
++{
++ unsigned int i;
++
++ for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
++ if (i == ARRAY_SIZE(xsd_errors) - 1) {
++ printk(KERN_WARNING
++ "XENBUS xen store gave: unknown error %s",
++ errorstring);
++ return EINVAL;
++ }
++ }
++ return xsd_errors[i].errnum;
++}
++
++static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
++{
++ struct xs_stored_msg *msg;
++ char *body;
++
++ spin_lock(&xs_state.reply_lock);
++
++ while (list_empty(&xs_state.reply_list)) {
++ spin_unlock(&xs_state.reply_lock);
++ /* XXX FIXME: Avoid synchronous wait for response here. */
++ wait_event(xs_state.reply_waitq,
++ !list_empty(&xs_state.reply_list));
++ spin_lock(&xs_state.reply_lock);
++ }
++
++ msg = list_entry(xs_state.reply_list.next,
++ struct xs_stored_msg, list);
++ list_del(&msg->list);
++
++ spin_unlock(&xs_state.reply_lock);
++
++ *type = msg->hdr.type;
++ if (len)
++ *len = msg->hdr.len;
++ body = msg->u.reply.body;
++
++ kfree(msg);
++
++ return body;
++}
++
++/* Emergency write. */
++void xenbus_debug_write(const char *str, unsigned int count)
++{
++ struct xsd_sockmsg msg = { 0 };
++
++ msg.type = XS_DEBUG;
++ msg.len = sizeof("print") + count + 1;
++
++ mutex_lock(&xs_state.request_mutex);
++ xb_write(&msg, sizeof(msg));
++ xb_write("print", sizeof("print"));
++ xb_write(str, count);
++ xb_write("", 1);
++ mutex_unlock(&xs_state.request_mutex);
++}
++
++void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
++{
++ void *ret;
++ struct xsd_sockmsg req_msg = *msg;
++ int err;
++
++ if (req_msg.type == XS_TRANSACTION_START)
++ down_read(&xs_state.suspend_mutex);
++
++ mutex_lock(&xs_state.request_mutex);
++
++ err = xb_write(msg, sizeof(*msg) + msg->len);
++ if (err) {
++ msg->type = XS_ERROR;
++ ret = ERR_PTR(err);
++ } else
++ ret = read_reply(&msg->type, &msg->len);
++
++ mutex_unlock(&xs_state.request_mutex);
++
++ if ((req_msg.type == XS_TRANSACTION_END) ||
++ ((req_msg.type == XS_TRANSACTION_START) &&
++ (msg->type == XS_ERROR)))
++ up_read(&xs_state.suspend_mutex);
++
++ return ret;
++}
++
++/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
++static void *xs_talkv(struct xenbus_transaction t,
++ enum xsd_sockmsg_type type,
++ const struct kvec *iovec,
++ unsigned int num_vecs,
++ unsigned int *len)
++{
++ struct xsd_sockmsg msg;
++ void *ret = NULL;
++ unsigned int i;
++ int err;
++
++ msg.tx_id = t.id;
++ msg.req_id = 0;
++ msg.type = type;
++ msg.len = 0;
++ for (i = 0; i < num_vecs; i++)
++ msg.len += iovec[i].iov_len;
++
++ mutex_lock(&xs_state.request_mutex);
++
++ err = xb_write(&msg, sizeof(msg));
++ if (err) {
++ mutex_unlock(&xs_state.request_mutex);
++ return ERR_PTR(err);
++ }
++
++ for (i = 0; i < num_vecs; i++) {
++ err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
++ if (err) {
++ mutex_unlock(&xs_state.request_mutex);
++ return ERR_PTR(err);
++ }
++ }
++
++ ret = read_reply(&msg.type, len);
++
++ mutex_unlock(&xs_state.request_mutex);
++
++ if (IS_ERR(ret))
++ return ret;
++
++ if (msg.type == XS_ERROR) {
++ err = get_error(ret);
++ kfree(ret);
++ return ERR_PTR(-err);
++ }
++
++ if (msg.type != type) {
++ if (printk_ratelimit())
++ printk(KERN_WARNING
++ "XENBUS unexpected type [%d], expected [%d]\n",
++ msg.type, type);
++ kfree(ret);
++ return ERR_PTR(-EINVAL);
++ }
++ return ret;
++}
++
++/* Simplified version of xs_talkv: single message. */
++static void *xs_single(struct xenbus_transaction t,
++ enum xsd_sockmsg_type type,
++ const char *string,
++ unsigned int *len)
++{
++ struct kvec iovec;
++
++ iovec.iov_base = (void *)string;
++ iovec.iov_len = strlen(string) + 1;
++ return xs_talkv(t, type, &iovec, 1, len);
++}
++
++/* Many commands only need an ack, don't care what it says. */
++static int xs_error(char *reply)
++{
++ if (IS_ERR(reply))
++ return PTR_ERR(reply);
++ kfree(reply);
++ return 0;
++}
++
++static unsigned int count_strings(const char *strings, unsigned int len)
++{
++ unsigned int num;
++ const char *p;
++
++ for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
++ num++;
++
++ return num;
++}
++
++/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
++static char *join(const char *dir, const char *name)
++{
++ char *buffer;
++
++ if (strlen(name) == 0)
++ buffer = kasprintf(GFP_KERNEL, "%s", dir);
++ else
++ buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
++ return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
++}
++
++static char **split(char *strings, unsigned int len, unsigned int *num)
++{
++ char *p, **ret;
++
++ /* Count the strings. */
++ *num = count_strings(strings, len);
++
++ /* Transfer to one big alloc for easy freeing. */
++ ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
++ if (!ret) {
++ kfree(strings);
++ return ERR_PTR(-ENOMEM);
++ }
++ memcpy(&ret[*num], strings, len);
++ kfree(strings);
++
++ strings = (char *)&ret[*num];
++ for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
++ ret[(*num)++] = p;
++
++ return ret;
++}
++
++char **xenbus_directory(struct xenbus_transaction t,
++ const char *dir, const char *node, unsigned int *num)
++{
++ char *strings, *path;
++ unsigned int len;
++
++ path = join(dir, node);
++ if (IS_ERR(path))
++ return (char **)path;
++
++ strings = xs_single(t, XS_DIRECTORY, path, &len);
++ kfree(path);
++ if (IS_ERR(strings))
++ return (char **)strings;
++
++ return split(strings, len, num);
++}
++EXPORT_SYMBOL_GPL(xenbus_directory);
++
++/* Check if a path exists. Return 1 if it does. */
++int xenbus_exists(struct xenbus_transaction t,
++ const char *dir, const char *node)
++{
++ char **d;
++ int dir_n;
++
++ d = xenbus_directory(t, dir, node, &dir_n);
++ if (IS_ERR(d))
++ return 0;
++ kfree(d);
++ return 1;
++}
++EXPORT_SYMBOL_GPL(xenbus_exists);
++
++/* Get the value of a single file.
++ * Returns a kmalloced value: call free() on it after use.
++ * len indicates length in bytes.
++ */
++void *xenbus_read(struct xenbus_transaction t,
++ const char *dir, const char *node, unsigned int *len)
++{
++ char *path;
++ void *ret;
++
++ path = join(dir, node);
++ if (IS_ERR(path))
++ return (void *)path;
++
++ ret = xs_single(t, XS_READ, path, len);
++ kfree(path);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_read);
++
++/* Write the value of a single file.
++ * Returns -err on failure.
++ */
++int xenbus_write(struct xenbus_transaction t,
++ const char *dir, const char *node, const char *string)
++{
++ const char *path;
++ struct kvec iovec[2];
++ int ret;
++
++ path = join(dir, node);
++ if (IS_ERR(path))
++ return PTR_ERR(path);
++
++ iovec[0].iov_base = (void *)path;
++ iovec[0].iov_len = strlen(path) + 1;
++ iovec[1].iov_base = (void *)string;
++ iovec[1].iov_len = strlen(string);
++
++ ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
++ kfree(path);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_write);
++
++/* Create a new directory. */
++int xenbus_mkdir(struct xenbus_transaction t,
++ const char *dir, const char *node)
++{
++ char *path;
++ int ret;
++
++ path = join(dir, node);
++ if (IS_ERR(path))
++ return PTR_ERR(path);
++
++ ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
++ kfree(path);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_mkdir);
++
++/* Destroy a file or directory (directories must be empty). */
++int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
++{
++ char *path;
++ int ret;
++
++ path = join(dir, node);
++ if (IS_ERR(path))
++ return PTR_ERR(path);
++
++ ret = xs_error(xs_single(t, XS_RM, path, NULL));
++ kfree(path);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_rm);
++
++/* Start a transaction: changes by others will not be seen during this
++ * transaction, and changes will not be visible to others until end.
++ */
++int xenbus_transaction_start(struct xenbus_transaction *t)
++{
++ char *id_str;
++
++ down_read(&xs_state.suspend_mutex);
++
++ id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
++ if (IS_ERR(id_str)) {
++ up_read(&xs_state.suspend_mutex);
++ return PTR_ERR(id_str);
++ }
++
++ t->id = simple_strtoul(id_str, NULL, 0);
++ kfree(id_str);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xenbus_transaction_start);
++
++/* End a transaction.
++ * If abandon is true, transaction is discarded instead of committed.
++ */
++int xenbus_transaction_end(struct xenbus_transaction t, int abort)
++{
++ char abortstr[2];
++ int err;
++
++ if (abort)
++ strcpy(abortstr, "F");
++ else
++ strcpy(abortstr, "T");
++
++ err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
++
++ up_read(&xs_state.suspend_mutex);
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(xenbus_transaction_end);
++
++/* Single read and scanf: returns -errno or num scanned. */
++int xenbus_scanf(struct xenbus_transaction t,
++ const char *dir, const char *node, const char *fmt, ...)
++{
++ va_list ap;
++ int ret;
++ char *val;
++
++ val = xenbus_read(t, dir, node, NULL);
++ if (IS_ERR(val))
++ return PTR_ERR(val);
++
++ va_start(ap, fmt);
++ ret = vsscanf(val, fmt, ap);
++ va_end(ap);
++ kfree(val);
++ /* Distinctive errno. */
++ if (ret == 0)
++ return -ERANGE;
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_scanf);
++
++/* Single printf and write: returns -errno or 0. */
++int xenbus_printf(struct xenbus_transaction t,
++ const char *dir, const char *node, const char *fmt, ...)
++{
++ va_list ap;
++ int ret;
++#define PRINTF_BUFFER_SIZE 4096
++ char *printf_buffer;
++
++ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
++ if (printf_buffer == NULL)
++ return -ENOMEM;
++
++ va_start(ap, fmt);
++ ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
++ va_end(ap);
++
++ BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
++ ret = xenbus_write(t, dir, node, printf_buffer);
++
++ kfree(printf_buffer);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_printf);
++
++/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
++int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
++{
++ va_list ap;
++ const char *name;
++ int ret = 0;
++
++ va_start(ap, dir);
++ while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
++ const char *fmt = va_arg(ap, char *);
++ void *result = va_arg(ap, void *);
++ char *p;
++
++ p = xenbus_read(t, dir, name, NULL);
++ if (IS_ERR(p)) {
++ ret = PTR_ERR(p);
++ break;
++ }
++ if (fmt) {
++ if (sscanf(p, fmt, result) == 0)
++ ret = -EINVAL;
++ kfree(p);
++ } else
++ *(char **)result = p;
++ }
++ va_end(ap);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xenbus_gather);
++
++static int xs_watch(const char *path, const char *token)
++{
++ struct kvec iov[2];
++
++ iov[0].iov_base = (void *)path;
++ iov[0].iov_len = strlen(path) + 1;
++ iov[1].iov_base = (void *)token;
++ iov[1].iov_len = strlen(token) + 1;
++
++ return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
++ ARRAY_SIZE(iov), NULL));
++}
++
++static int xs_unwatch(const char *path, const char *token)
++{
++ struct kvec iov[2];
++
++ iov[0].iov_base = (char *)path;
++ iov[0].iov_len = strlen(path) + 1;
++ iov[1].iov_base = (char *)token;
++ iov[1].iov_len = strlen(token) + 1;
++
++ return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
++ ARRAY_SIZE(iov), NULL));
++}
++
++static struct xenbus_watch *find_watch(const char *token)
++{
++ struct xenbus_watch *i, *cmp;
++
++ cmp = (void *)simple_strtoul(token, NULL, 16);
++
++ list_for_each_entry(i, &watches, list)
++ if (i == cmp)
++ return i;
++
++ return NULL;
++}
++
++/* Register callback to watch this node. */
++int register_xenbus_watch(struct xenbus_watch *watch)
++{
++ /* Pointer in ascii is the token. */
++ char token[sizeof(watch) * 2 + 1];
++ int err;
++
++ sprintf(token, "%lX", (long)watch);
++
++ down_read(&xs_state.suspend_mutex);
++
++ spin_lock(&watches_lock);
++ BUG_ON(find_watch(token));
++ list_add(&watch->list, &watches);
++ spin_unlock(&watches_lock);
++
++ err = xs_watch(watch->node, token);
++
++ /* Ignore errors due to multiple registration. */
++ if ((err != 0) && (err != -EEXIST)) {
++ spin_lock(&watches_lock);
++ list_del(&watch->list);
++ spin_unlock(&watches_lock);
++ }
++
++ up_read(&xs_state.suspend_mutex);
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(register_xenbus_watch);
++
++void unregister_xenbus_watch(struct xenbus_watch *watch)
++{
++ struct xs_stored_msg *msg, *tmp;
++ char token[sizeof(watch) * 2 + 1];
++ int err;
++
++ sprintf(token, "%lX", (long)watch);
++
++ down_read(&xs_state.suspend_mutex);
++
++ spin_lock(&watches_lock);
++ BUG_ON(!find_watch(token));
++ list_del(&watch->list);
++ spin_unlock(&watches_lock);
++
++ err = xs_unwatch(watch->node, token);
++ if (err)
++ printk(KERN_WARNING
++ "XENBUS Failed to release watch %s: %i\n",
++ watch->node, err);
++
++ up_read(&xs_state.suspend_mutex);
++
++ /* Cancel pending watch events. */
++ spin_lock(&watch_events_lock);
++ list_for_each_entry_safe(msg, tmp, &watch_events, list) {
++ if (msg->u.watch.handle != watch)
++ continue;
++ list_del(&msg->list);
++ kfree(msg->u.watch.vec);
++ kfree(msg);
++ }
++ spin_unlock(&watch_events_lock);
++
++ /* Flush any currently-executing callback, unless we are it. :-) */
++ if (current->pid != xenwatch_pid) {
++ mutex_lock(&xenwatch_mutex);
++ mutex_unlock(&xenwatch_mutex);
++ }
++}
++EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
++
++void xs_suspend(void)
++{
++ struct xenbus_watch *watch;
++ char token[sizeof(watch) * 2 + 1];
++
++ down_write(&xs_state.suspend_mutex);
++
++ /* No need for watches_lock: the suspend_mutex is sufficient. */
++ list_for_each_entry(watch, &watches, list) {
++ sprintf(token, "%lX", (long)watch);
++ xs_unwatch(watch->node, token);
++ }
++
++ mutex_lock(&xs_state.request_mutex);
++}
++
++void xs_resume(void)
++{
++ struct xenbus_watch *watch;
++ char token[sizeof(watch) * 2 + 1];
++
++ mutex_unlock(&xs_state.request_mutex);
++
++ /* No need for watches_lock: the suspend_mutex is sufficient. */
++ list_for_each_entry(watch, &watches, list) {
++ sprintf(token, "%lX", (long)watch);
++ xs_watch(watch->node, token);
++ }
++
++ up_write(&xs_state.suspend_mutex);
++}
++
++static int xenwatch_handle_callback(void *data)
++{
++ struct xs_stored_msg *msg = data;
++
++ msg->u.watch.handle->callback(msg->u.watch.handle,
++ (const char **)msg->u.watch.vec,
++ msg->u.watch.vec_size);
++
++ kfree(msg->u.watch.vec);
++ kfree(msg);
++
++ /* Kill this kthread if we were spawned just for this callback. */
++ if (current->pid != xenwatch_pid)
++ do_exit(0);
++
++ return 0;
++}
++
++static int xenwatch_thread(void *unused)
++{
++ struct list_head *ent;
++ struct xs_stored_msg *msg;
++
++ for (;;) {
++ wait_event_interruptible(watch_events_waitq,
++ !list_empty(&watch_events));
++
++ if (kthread_should_stop())
++ break;
++
++ mutex_lock(&xenwatch_mutex);
++
++ spin_lock(&watch_events_lock);
++ ent = watch_events.next;
++ if (ent != &watch_events)
++ list_del(ent);
++ spin_unlock(&watch_events_lock);
++
++ if (ent != &watch_events) {
++ msg = list_entry(ent, struct xs_stored_msg, list);
++ if (msg->u.watch.handle->flags & XBWF_new_thread)
++ kthread_run(xenwatch_handle_callback,
++ msg, "xenwatch_cb");
++ else
++ xenwatch_handle_callback(msg);
++ }
++
++ mutex_unlock(&xenwatch_mutex);
++ }
++
++ return 0;
++}
++
++static int process_msg(void)
++{
++ struct xs_stored_msg *msg;
++ char *body;
++ int err;
++
++ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
++ if (msg == NULL)
++ return -ENOMEM;
++
++ err = xb_read(&msg->hdr, sizeof(msg->hdr));
++ if (err) {
++ kfree(msg);
++ return err;
++ }
++
++ body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
++ if (body == NULL) {
++ kfree(msg);
++ return -ENOMEM;
++ }
++
++ err = xb_read(body, msg->hdr.len);
++ if (err) {
++ kfree(body);
++ kfree(msg);
++ return err;
++ }
++ body[msg->hdr.len] = '\0';
++
++ if (msg->hdr.type == XS_WATCH_EVENT) {
++ msg->u.watch.vec = split(body, msg->hdr.len,
++ &msg->u.watch.vec_size);
++ if (IS_ERR(msg->u.watch.vec)) {
++ kfree(msg);
++ return PTR_ERR(msg->u.watch.vec);
++ }
++
++ spin_lock(&watches_lock);
++ msg->u.watch.handle = find_watch(
++ msg->u.watch.vec[XS_WATCH_TOKEN]);
++ if (msg->u.watch.handle != NULL) {
++ spin_lock(&watch_events_lock);
++ list_add_tail(&msg->list, &watch_events);
++ wake_up(&watch_events_waitq);
++ spin_unlock(&watch_events_lock);
++ } else {
++ kfree(msg->u.watch.vec);
++ kfree(msg);
++ }
++ spin_unlock(&watches_lock);
++ } else {
++ msg->u.reply.body = body;
++ spin_lock(&xs_state.reply_lock);
++ list_add_tail(&msg->list, &xs_state.reply_list);
++ spin_unlock(&xs_state.reply_lock);
++ wake_up(&xs_state.reply_waitq);
++ }
++
++ return 0;
++}
++
++static int xenbus_thread(void *unused)
++{
++ int err;
++
++ for (;;) {
++ err = process_msg();
++ if (err)
++ printk(KERN_WARNING "XENBUS error %d while reading "
++ "message\n", err);
++ if (kthread_should_stop())
++ break;
++ }
++
++ return 0;
++}
++
++int xs_init(void)
++{
++ int err;
++ struct task_struct *task;
++
++ INIT_LIST_HEAD(&xs_state.reply_list);
++ spin_lock_init(&xs_state.reply_lock);
++ init_waitqueue_head(&xs_state.reply_waitq);
++
++ mutex_init(&xs_state.request_mutex);
++ init_rwsem(&xs_state.suspend_mutex);
++
++ /* Initialize the shared memory rings to talk to xenstored */
++ err = xb_init_comms();
++ if (err)
++ return err;
++
++ task = kthread_run(xenwatch_thread, NULL, "xenwatch");
++ if (IS_ERR(task))
++ return PTR_ERR(task);
++ xenwatch_pid = task->pid;
++
++ task = kthread_run(xenbus_thread, NULL, "xenbus");
++ if (IS_ERR(task))
++ return PTR_ERR(task);
++
++ return 0;
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/fs/Kconfig linux-2.6.18-xen/fs/Kconfig
+--- linux-2.6.18.1/fs/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/fs/Kconfig 2006-09-04 16:31:13.000000000 +0200
+@@ -865,6 +865,7 @@
+ config HUGETLBFS
+ bool "HugeTLB file system support"
+ depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
++ depends !XEN
+ help
+ hugetlbfs is a filesystem backing for HugeTLB pages, based on
+ ramfs. For architectures that support it, say Y here and read
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-generic/vmlinux.lds.h linux-2.6.18-xen/include/asm-generic/vmlinux.lds.h
+--- linux-2.6.18.1/include/asm-generic/vmlinux.lds.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-generic/vmlinux.lds.h 2006-09-21 01:33:31.000000000 +0200
+@@ -194,3 +194,6 @@
+ .stab.index 0 : { *(.stab.index) } \
+ .stab.indexstr 0 : { *(.stab.indexstr) } \
+ .comment 0 : { *(.comment) }
++
++#define NOTES \
++ .notes : { *(.note.*) } :note
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/apic.h linux-2.6.18-xen/include/asm-i386/apic.h
+--- linux-2.6.18.1/include/asm-i386/apic.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-i386/apic.h 2006-09-04 16:31:16.000000000 +0200
+@@ -119,10 +119,12 @@
+
+ extern int disable_timer_pin_1;
+
++#ifndef CONFIG_XEN
+ void smp_send_timer_broadcast_ipi(struct pt_regs *regs);
+ void switch_APIC_timer_to_ipi(void *cpumask);
+ void switch_ipi_to_APIC_timer(void *cpumask);
+ #define ARCH_APICTIMER_STOPS_ON_C3 1
++#endif
+
+ extern int timer_over_8254;
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/fixmap.h linux-2.6.18-xen/include/asm-i386/fixmap.h
+--- linux-2.6.18.1/include/asm-i386/fixmap.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-i386/fixmap.h 2006-09-21 01:33:32.000000000 +0200
+@@ -19,6 +19,7 @@
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap.
+ */
++
+ #define __FIXADDR_TOP 0xfffff000
+
+ #ifndef __ASSEMBLY__
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-default/mach_traps.h linux-2.6.18-xen/include/asm-i386/mach-default/mach_traps.h
+--- linux-2.6.18.1/include/asm-i386/mach-default/mach_traps.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-i386/mach-default/mach_traps.h 2006-09-04 16:31:16.000000000 +0200
+@@ -15,6 +15,18 @@
+ outb(reason, 0x61);
+ }
+
++static inline void clear_io_check_error(unsigned char reason)
++{
++ unsigned long i;
++
++ reason = (reason & 0xf) | 8;
++ outb(reason, 0x61);
++ i = 2000;
++ while (--i) udelay(1000);
++ reason &= ~8;
++ outb(reason, 0x61);
++}
++
+ static inline unsigned char get_nmi_reason(void)
+ {
+ return inb(0x61);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/agp.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/agp.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/agp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/agp.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,37 @@
++#ifndef AGP_H
++#define AGP_H 1
++
++#include <asm/pgtable.h>
++#include <asm/cacheflush.h>
++#include <asm/system.h>
++
++/*
++ * Functions to keep the agpgart mappings coherent with the MMU.
++ * The GART gives the CPU a physical alias of pages in memory. The alias region is
++ * mapped uncacheable. Make sure there are no conflicting mappings
++ * with different cachability attributes for the same page. This avoids
++ * data corruption on some CPUs.
++ */
++
++int map_page_into_agp(struct page *page);
++int unmap_page_from_agp(struct page *page);
++#define flush_agp_mappings() global_flush_tlb()
++
++/* Could use CLFLUSH here if the cpu supports it. But then it would
++ need to be called for each cacheline of the whole page so it may not be
++ worth it. Would need a page for it. */
++#define flush_agp_cache() wbinvd()
++
++/* Convert a physical address to an address suitable for the GART. */
++#define phys_to_gart(x) phys_to_machine(x)
++#define gart_to_phys(x) machine_to_phys(x)
++
++/* GATT allocation. Returns/accepts GATT kernel virtual address. */
++#define alloc_gatt_pages(order) ({ \
++ char *_t; dma_addr_t _d; \
++ _t = dma_alloc_coherent(NULL,PAGE_SIZE<<(order),&_d,GFP_KERNEL); \
++ _t; })
++#define free_gatt_pages(table, order) \
++ dma_free_coherent(NULL,PAGE_SIZE<<(order),(table),virt_to_bus(table))
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/desc.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/desc.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/desc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/desc.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,164 @@
++#ifndef __ARCH_DESC_H
++#define __ARCH_DESC_H
++
++#include <asm/ldt.h>
++#include <asm/segment.h>
++
++#define CPU_16BIT_STACK_SIZE 1024
++
++#ifndef __ASSEMBLY__
++
++#include <linux/preempt.h>
++#include <linux/smp.h>
++
++#include <asm/mmu.h>
++
++extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
++
++DECLARE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
++
++struct Xgt_desc_struct {
++ unsigned short size;
++ unsigned long address __attribute__((packed));
++ unsigned short pad;
++} __attribute__ ((packed));
++
++extern struct Xgt_desc_struct idt_descr;
++DECLARE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
++
++
++static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
++{
++ return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address;
++}
++
++#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
++#define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8))
++
++#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
++#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
++#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr))
++#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt))
++
++#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr))
++#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr))
++#define store_tr(tr) __asm__ ("str %0":"=mr" (tr))
++#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt))
++
++/*
++ * This is the ldt that every process will get unless we need
++ * something other than this.
++ */
++extern struct desc_struct default_ldt[];
++extern void set_intr_gate(unsigned int irq, void * addr);
++
++#define _set_tssldt_desc(n,addr,limit,type) \
++__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
++ "movw %w1,2(%2)\n\t" \
++ "rorl $16,%1\n\t" \
++ "movb %b1,4(%2)\n\t" \
++ "movb %4,5(%2)\n\t" \
++ "movb $0,6(%2)\n\t" \
++ "movb %h1,7(%2)\n\t" \
++ "rorl $16,%1" \
++ : "=m"(*(n)) : "q" (addr), "r"(n), "ir"(limit), "i"(type))
++
++#ifndef CONFIG_X86_NO_TSS
++static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
++{
++ _set_tssldt_desc(&get_cpu_gdt_table(cpu)[entry], (int)addr,
++ offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89);
++}
++
++#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
++#endif
++
++static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
++{
++ _set_tssldt_desc(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82);
++}
++
++#define LDT_entry_a(info) \
++ ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
++
++#define LDT_entry_b(info) \
++ (((info)->base_addr & 0xff000000) | \
++ (((info)->base_addr & 0x00ff0000) >> 16) | \
++ ((info)->limit & 0xf0000) | \
++ (((info)->read_exec_only ^ 1) << 9) | \
++ ((info)->contents << 10) | \
++ (((info)->seg_not_present ^ 1) << 15) | \
++ ((info)->seg_32bit << 22) | \
++ ((info)->limit_in_pages << 23) | \
++ ((info)->useable << 20) | \
++ 0x7000)
++
++#define LDT_empty(info) (\
++ (info)->base_addr == 0 && \
++ (info)->limit == 0 && \
++ (info)->contents == 0 && \
++ (info)->read_exec_only == 1 && \
++ (info)->seg_32bit == 0 && \
++ (info)->limit_in_pages == 0 && \
++ (info)->seg_not_present == 1 && \
++ (info)->useable == 0 )
++
++extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b);
++
++#if TLS_SIZE != 24
++# error update this code.
++#endif
++
++static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
++{
++#define C(i) HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), *(u64 *)&t->tls_array[i])
++ C(0); C(1); C(2);
++#undef C
++}
++
++static inline void clear_LDT(void)
++{
++ int cpu = get_cpu();
++
++ /*
++ * NB. We load the default_ldt for lcall7/27 handling on demand, as
++ * it slows down context switching. Noone uses it anyway.
++ */
++ cpu = cpu; /* XXX avoid compiler warning */
++ xen_set_ldt(0UL, 0);
++ put_cpu();
++}
++
++/*
++ * load one particular LDT into the current CPU
++ */
++static inline void load_LDT_nolock(mm_context_t *pc, int cpu)
++{
++ void *segments = pc->ldt;
++ int count = pc->size;
++
++ if (likely(!count))
++ segments = NULL;
++
++ xen_set_ldt((unsigned long)segments, count);
++}
++
++static inline void load_LDT(mm_context_t *pc)
++{
++ int cpu = get_cpu();
++ load_LDT_nolock(pc, cpu);
++ put_cpu();
++}
++
++static inline unsigned long get_desc_base(unsigned long *desc)
++{
++ unsigned long base;
++ base = ((desc[0] >> 16) & 0x0000ffff) |
++ ((desc[1] << 16) & 0x00ff0000) |
++ (desc[1] & 0xff000000);
++ return base;
++}
++
++#endif /* !__ASSEMBLY__ */
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/dma-mapping.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/dma-mapping.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/dma-mapping.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/dma-mapping.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,151 @@
++#ifndef _ASM_I386_DMA_MAPPING_H
++#define _ASM_I386_DMA_MAPPING_H
++
++/*
++ * IOMMU interface. See Documentation/DMA-mapping.txt and DMA-API.txt for
++ * documentation.
++ */
++
++#include <linux/mm.h>
++#include <asm/cache.h>
++#include <asm/io.h>
++#include <asm/scatterlist.h>
++#include <asm/swiotlb.h>
++
++static inline int
++address_needs_mapping(struct device *hwdev, dma_addr_t addr)
++{
++ dma_addr_t mask = 0xffffffff;
++ /* If the device has a mask, use it, otherwise default to 32 bits */
++ if (hwdev && hwdev->dma_mask)
++ mask = *hwdev->dma_mask;
++ return (addr & ~mask) != 0;
++}
++
++static inline int
++range_straddles_page_boundary(void *p, size_t size)
++{
++ extern unsigned long *contiguous_bitmap;
++ return (((((unsigned long)p & ~PAGE_MASK) + size) > PAGE_SIZE) &&
++ !test_bit(__pa(p) >> PAGE_SHIFT, contiguous_bitmap));
++}
++
++#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, gfp_t flag);
++
++void dma_free_coherent(struct device *dev, size_t size,
++ void *vaddr, dma_addr_t dma_handle);
++
++extern dma_addr_t
++dma_map_single(struct device *dev, void *ptr, size_t size,
++ enum dma_data_direction direction);
++
++extern void
++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction direction);
++
++extern int dma_map_sg(struct device *hwdev, struct scatterlist *sg,
++ int nents, enum dma_data_direction direction);
++extern void dma_unmap_sg(struct device *hwdev, struct scatterlist *sg,
++ int nents, enum dma_data_direction direction);
++
++extern dma_addr_t
++dma_map_page(struct device *dev, struct page *page, unsigned long offset,
++ size_t size, enum dma_data_direction direction);
++
++extern void
++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
++ enum dma_data_direction direction);
++
++extern void
++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction direction);
++
++extern void
++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction 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)
++{
++ dma_sync_single_for_cpu(dev, 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)
++{
++ dma_sync_single_for_device(dev, 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 direction)
++{
++ if (swiotlb)
++ swiotlb_sync_sg_for_cpu(dev,sg,nelems,direction);
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
++ enum dma_data_direction direction)
++{
++ if (swiotlb)
++ swiotlb_sync_sg_for_device(dev,sg,nelems,direction);
++ flush_write_buffers();
++}
++
++extern int
++dma_mapping_error(dma_addr_t dma_addr);
++
++extern int
++dma_supported(struct device *dev, u64 mask);
++
++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)
++{
++ /* no easy way to get cache size on all x86, so return the
++ * maximum possible, to be safe */
++ return (1 << INTERNODE_CACHE_SHIFT);
++}
++
++#define dma_is_consistent(d) (1)
++
++static inline void
++dma_cache_sync(void *vaddr, size_t size,
++ enum dma_data_direction direction)
++{
++ flush_write_buffers();
++}
++
++#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
++extern int
++dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
++ dma_addr_t device_addr, size_t size, int flags);
++
++extern void
++dma_release_declared_memory(struct device *dev);
++
++extern void *
++dma_mark_declared_memory_occupied(struct device *dev,
++ dma_addr_t device_addr, size_t size);
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/fixmap.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/fixmap.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/fixmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/fixmap.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,156 @@
++/*
++ * fixmap.h: compile-time virtual memory allocation
++ *
++ * 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) 1998 Ingo Molnar
++ *
++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
++ */
++
++#ifndef _ASM_FIXMAP_H
++#define _ASM_FIXMAP_H
++
++
++/* used by vmalloc.c, vsyscall.lds.S.
++ *
++ * Leave one empty page between vmalloc'ed areas and
++ * the start of the fixmap.
++ */
++extern unsigned long __FIXADDR_TOP;
++
++#ifndef __ASSEMBLY__
++#include <linux/kernel.h>
++#include <asm/acpi.h>
++#include <asm/apicdef.h>
++#include <asm/page.h>
++#include <xen/gnttab.h>
++#ifdef CONFIG_HIGHMEM
++#include <linux/threads.h>
++#include <asm/kmap_types.h>
++#endif
++
++/*
++ * Here we define all the compile-time 'special' virtual
++ * addresses. The point is to have a constant address at
++ * compile time, but to set the physical address only
++ * in the boot process. We allocate these special addresses
++ * from the end of virtual memory (0xfffff000) backwards.
++ * Also this lets us do fail-safe vmalloc(), we
++ * can guarantee that these special addresses and
++ * vmalloc()-ed addresses never overlap.
++ *
++ * these 'compile-time allocated' memory buffers are
++ * fixed-size 4k pages. (or larger if used with an increment
++ * highger than 1) use fixmap_set(idx,phys) to associate
++ * physical memory with fixmap indices.
++ *
++ * TLB entries of such buffers will not be flushed across
++ * task switches.
++ */
++enum fixed_addresses {
++ FIX_HOLE,
++ FIX_VDSO,
++#ifdef CONFIG_X86_LOCAL_APIC
++ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
++#endif
++#ifdef CONFIG_X86_IO_APIC
++ FIX_IO_APIC_BASE_0,
++ FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
++#endif
++#ifdef CONFIG_X86_VISWS_APIC
++ FIX_CO_CPU, /* Cobalt timer */
++ FIX_CO_APIC, /* Cobalt APIC Redirection Table */
++ FIX_LI_PCIA, /* Lithium PCI Bridge A */
++ FIX_LI_PCIB, /* Lithium PCI Bridge B */
++#endif
++#ifdef CONFIG_X86_F00F_BUG
++ FIX_F00F_IDT, /* Virtual mapping for IDT */
++#endif
++#ifdef CONFIG_X86_CYCLONE_TIMER
++ FIX_CYCLONE_TIMER, /*cyclone timer register*/
++#endif
++#ifdef CONFIG_HIGHMEM
++ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
++ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
++#endif
++#ifdef CONFIG_ACPI
++ FIX_ACPI_BEGIN,
++ FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
++#endif
++#ifdef CONFIG_PCI_MMCONFIG
++ FIX_PCIE_MCFG,
++#endif
++ FIX_SHARED_INFO,
++#define NR_FIX_ISAMAPS 256
++ FIX_ISAMAP_END,
++ FIX_ISAMAP_BEGIN = FIX_ISAMAP_END + NR_FIX_ISAMAPS - 1,
++ __end_of_permanent_fixed_addresses,
++ /* temporary boot-time mappings, used before ioremap() is functional */
++#define NR_FIX_BTMAPS 16
++ FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
++ FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
++ FIX_WP_TEST,
++ __end_of_fixed_addresses
++};
++
++extern void __set_fixmap(enum fixed_addresses idx,
++ maddr_t phys, pgprot_t flags);
++
++extern void set_fixaddr_top(unsigned long top);
++
++#define set_fixmap(idx, phys) \
++ __set_fixmap(idx, phys, PAGE_KERNEL)
++/*
++ * Some hardware wants to get fixmapped without caching.
++ */
++#define set_fixmap_nocache(idx, phys) \
++ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
++
++#define clear_fixmap(idx) \
++ __set_fixmap(idx, 0, __pgprot(0))
++
++#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
++
++#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
++#define __FIXADDR_BOOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
++#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
++#define FIXADDR_BOOT_START (FIXADDR_TOP - __FIXADDR_BOOT_SIZE)
++
++#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
++#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
++
++extern void __this_fixmap_does_not_exist(void);
++
++/*
++ * 'index to address' translation. If anyone tries to use the idx
++ * directly without tranlation, we catch the bug with a NULL-deference
++ * kernel oops. Illegal ranges of incoming indices are caught too.
++ */
++static __always_inline unsigned long fix_to_virt(const unsigned int idx)
++{
++ /*
++ * this branch gets completely eliminated after inlining,
++ * except when someone tries to use fixaddr indices in an
++ * illegal way. (such as mixing up address types or using
++ * out-of-range indices).
++ *
++ * If it doesn't get removed, the linker will complain
++ * loudly with a reasonably clear error message..
++ */
++ if (idx >= __end_of_fixed_addresses)
++ __this_fixmap_does_not_exist();
++
++ return __fix_to_virt(idx);
++}
++
++static inline unsigned long virt_to_fix(const unsigned long vaddr)
++{
++ BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
++ return __virt_to_fix(vaddr);
++}
++
++#endif /* !__ASSEMBLY__ */
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/floppy.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/floppy.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/floppy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/floppy.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,147 @@
++/*
++ * Architecture specific parts of the Floppy driver
++ *
++ * 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
++ *
++ * Modifications for Xen are Copyright (c) 2004, Keir Fraser.
++ */
++#ifndef __ASM_XEN_I386_FLOPPY_H
++#define __ASM_XEN_I386_FLOPPY_H
++
++#include <linux/vmalloc.h>
++
++/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */
++#include <asm/dma.h>
++#undef MAX_DMA_ADDRESS
++#define MAX_DMA_ADDRESS 0
++#define CROSS_64KB(a,s) (0)
++
++#define fd_inb(port) inb_p(port)
++#define fd_outb(value,port) outb_p(value,port)
++
++#define fd_request_dma() (0)
++#define fd_free_dma() ((void)0)
++#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
++#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
++#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL)
++#define fd_get_dma_residue() (virtual_dma_count + virtual_dma_residue)
++#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
++/*
++ * Do not use vmalloc/vfree: floppy_release_irq_and_dma() gets called from
++ * softirq context via motor_off_callback. A generic bug we happen to trigger.
++ */
++#define fd_dma_mem_alloc(size) __get_free_pages(GFP_KERNEL, get_order(size))
++#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
++
++static int virtual_dma_count;
++static int virtual_dma_residue;
++static char *virtual_dma_addr;
++static int virtual_dma_mode;
++static int doing_pdma;
++
++static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
++{
++ register unsigned char st;
++ register int lcount;
++ register char *lptr;
++
++ if (!doing_pdma)
++ return floppy_interrupt(irq, dev_id, regs);
++
++ st = 1;
++ for(lcount=virtual_dma_count, lptr=virtual_dma_addr;
++ lcount; lcount--, lptr++) {
++ st=inb(virtual_dma_port+4) & 0xa0 ;
++ if(st != 0xa0)
++ break;
++ if(virtual_dma_mode)
++ outb_p(*lptr, virtual_dma_port+5);
++ else
++ *lptr = inb_p(virtual_dma_port+5);
++ }
++ virtual_dma_count = lcount;
++ virtual_dma_addr = lptr;
++ st = inb(virtual_dma_port+4);
++
++ if(st == 0x20)
++ return IRQ_HANDLED;
++ if(!(st & 0x20)) {
++ virtual_dma_residue += virtual_dma_count;
++ virtual_dma_count=0;
++ doing_pdma = 0;
++ floppy_interrupt(irq, dev_id, regs);
++ return IRQ_HANDLED;
++ }
++ return IRQ_HANDLED;
++}
++
++static void fd_disable_dma(void)
++{
++ doing_pdma = 0;
++ virtual_dma_residue += virtual_dma_count;
++ virtual_dma_count=0;
++}
++
++static int fd_request_irq(void)
++{
++ return request_irq(FLOPPY_IRQ, floppy_hardint,
++ IRQF_DISABLED, "floppy", NULL);
++}
++
++static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
++{
++ doing_pdma = 1;
++ virtual_dma_port = io;
++ virtual_dma_mode = (mode == DMA_MODE_WRITE);
++ virtual_dma_addr = addr;
++ virtual_dma_count = size;
++ virtual_dma_residue = 0;
++ return 0;
++}
++
++/* XEN: This trick to force 'virtual DMA' is from include/asm-m68k/floppy.h. */
++#define FDC1 xen_floppy_init()
++static int FDC2 = -1;
++
++static int xen_floppy_init(void)
++{
++ use_virtual_dma = 1;
++ can_use_virtual_dma = 1;
++ return 0x3f0;
++}
++
++/*
++ * Floppy types are stored in the rtc's CMOS RAM and so rtc_lock
++ * is needed to prevent corrupted CMOS RAM in case "insmod floppy"
++ * coincides with another rtc CMOS user. Paul G.
++ */
++#define FLOPPY0_TYPE ({ \
++ unsigned long flags; \
++ unsigned char val; \
++ spin_lock_irqsave(&rtc_lock, flags); \
++ val = (CMOS_READ(0x10) >> 4) & 15; \
++ spin_unlock_irqrestore(&rtc_lock, flags); \
++ val; \
++})
++
++#define FLOPPY1_TYPE ({ \
++ unsigned long flags; \
++ unsigned char val; \
++ spin_lock_irqsave(&rtc_lock, flags); \
++ val = CMOS_READ(0x10) & 15; \
++ spin_unlock_irqrestore(&rtc_lock, flags); \
++ val; \
++})
++
++#define N_FDC 2
++#define N_DRIVE 8
++
++#define FLOPPY_MOTOR_MASK 0xf0
++
++#define EXTRA_FLOPPY_PARAMS
++
++#endif /* __ASM_XEN_I386_FLOPPY_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/highmem.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/highmem.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/highmem.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/highmem.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,80 @@
++/*
++ * highmem.h: virtual kernel memory mappings for high memory
++ *
++ * Used in CONFIG_HIGHMEM systems for memory pages which
++ * are not addressable by direct kernel virtual addresses.
++ *
++ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
++ * Gerhard.Wichert at pdb.siemens.de
++ *
++ *
++ * Redesigned the x86 32-bit VM architecture to deal with
++ * up to 16 Terabyte physical memory. With current x86 CPUs
++ * we now support up to 64 Gigabytes physical RAM.
++ *
++ * Copyright (C) 1999 Ingo Molnar <mingo at redhat.com>
++ */
++
++#ifndef _ASM_HIGHMEM_H
++#define _ASM_HIGHMEM_H
++
++#ifdef __KERNEL__
++
++#include <linux/interrupt.h>
++#include <linux/threads.h>
++#include <asm/kmap_types.h>
++#include <asm/tlbflush.h>
++
++/* declarations for highmem.c */
++extern unsigned long highstart_pfn, highend_pfn;
++
++extern pte_t *kmap_pte;
++extern pgprot_t kmap_prot;
++extern pte_t *pkmap_page_table;
++
++/*
++ * Right now we initialize only a single pte table. It can be extended
++ * easily, subsequent pte tables have to be allocated in one physical
++ * chunk of RAM.
++ */
++#ifdef CONFIG_X86_PAE
++#define LAST_PKMAP 512
++#else
++#define LAST_PKMAP 1024
++#endif
++/*
++ * Ordering is:
++ *
++ * FIXADDR_TOP
++ * fixed_addresses
++ * FIXADDR_START
++ * temp fixed addresses
++ * FIXADDR_BOOT_START
++ * Persistent kmap area
++ * PKMAP_BASE
++ * VMALLOC_END
++ * Vmalloc area
++ * VMALLOC_START
++ * high_memory
++ */
++#define PKMAP_BASE ( (FIXADDR_BOOT_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK )
++#define LAST_PKMAP_MASK (LAST_PKMAP-1)
++#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
++#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
++
++extern void * FASTCALL(kmap_high(struct page *page));
++extern void FASTCALL(kunmap_high(struct page *page));
++
++void *kmap(struct page *page);
++void kunmap(struct page *page);
++void *kmap_atomic(struct page *page, enum km_type type);
++void *kmap_atomic_pte(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)
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_HIGHMEM_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/hw_irq.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/hw_irq.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/hw_irq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/hw_irq.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,72 @@
++#ifndef _ASM_HW_IRQ_H
++#define _ASM_HW_IRQ_H
++
++/*
++ * linux/include/asm/hw_irq.h
++ *
++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
++ *
++ * moved some of the old arch/i386/kernel/irq.h to here. VY
++ *
++ * IRQ/IPI changes taken from work by Thomas Radke
++ * <tomsoft at informatik.tu-chemnitz.de>
++ */
++
++#include <linux/profile.h>
++#include <asm/atomic.h>
++#include <asm/irq.h>
++#include <asm/sections.h>
++
++struct hw_interrupt_type;
++
++#define NMI_VECTOR 0x02
++
++/*
++ * Various low-level irq details needed by irq.c, process.c,
++ * time.c, io_apic.c and smp.c
++ *
++ * Interrupt entry/exit code at both C and assembly level
++ */
++
++extern u8 irq_vector[NR_IRQ_VECTORS];
++#define IO_APIC_VECTOR(irq) (irq_vector[irq])
++#define AUTO_ASSIGN -1
++
++extern void (*interrupt[NR_IRQS])(void);
++
++#ifdef CONFIG_SMP
++fastcall void reschedule_interrupt(void);
++fastcall void invalidate_interrupt(void);
++fastcall void call_function_interrupt(void);
++#endif
++
++#ifdef CONFIG_X86_LOCAL_APIC
++fastcall void apic_timer_interrupt(void);
++fastcall void error_interrupt(void);
++fastcall void spurious_interrupt(void);
++fastcall void thermal_interrupt(struct pt_regs *);
++#define platform_legacy_irq(irq) ((irq) < 16)
++#endif
++
++void disable_8259A_irq(unsigned int irq);
++void enable_8259A_irq(unsigned int irq);
++int i8259A_irq_pending(unsigned int irq);
++void make_8259A_irq(unsigned int irq);
++void init_8259A(int aeoi);
++void FASTCALL(send_IPI_self(int vector));
++void init_VISWS_APIC_irqs(void);
++void setup_IO_APIC(void);
++void disable_IO_APIC(void);
++void print_IO_APIC(void);
++int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
++void send_IPI(int dest, int vector);
++void setup_ioapic_dest(void);
++
++extern unsigned long io_apic_irqs;
++
++extern atomic_t irq_err_count;
++extern atomic_t irq_mis_count;
++
++#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
++
++#endif /* _ASM_HW_IRQ_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/hypercall.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/hypercall.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/hypercall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/hypercall.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,389 @@
++/******************************************************************************
++ * hypercall.h
++ *
++ * Linux-specific hypervisor handling.
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __HYPERCALL_H__
++#define __HYPERCALL_H__
++
++#include <linux/string.h> /* memcpy() */
++
++#ifndef __HYPERVISOR_H__
++# error "please don't include this file directly"
++#endif
++
++#define __STR(x) #x
++#define STR(x) __STR(x)
++
++#ifdef CONFIG_XEN
++#define HYPERCALL_STR(name) \
++ "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"
++#else
++#define HYPERCALL_STR(name) \
++ "mov hypercall_stubs,%%eax; " \
++ "add $("STR(__HYPERVISOR_##name)" * 32),%%eax; " \
++ "call *%%eax"
++#endif
++
++#define _hypercall0(type, name) \
++({ \
++ long __res; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res) \
++ : \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall1(type, name, a1) \
++({ \
++ long __res, __ign1; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=b" (__ign1) \
++ : "1" ((long)(a1)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall2(type, name, a1, a2) \
++({ \
++ long __res, __ign1, __ign2; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
++ : "1" ((long)(a1)), "2" ((long)(a2)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall3(type, name, a1, a2, a3) \
++({ \
++ long __res, __ign1, __ign2, __ign3; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
++ "=d" (__ign3) \
++ : "1" ((long)(a1)), "2" ((long)(a2)), \
++ "3" ((long)(a3)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall4(type, name, a1, a2, a3, a4) \
++({ \
++ long __res, __ign1, __ign2, __ign3, __ign4; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
++ "=d" (__ign3), "=S" (__ign4) \
++ : "1" ((long)(a1)), "2" ((long)(a2)), \
++ "3" ((long)(a3)), "4" ((long)(a4)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
++({ \
++ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
++ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
++ : "1" ((long)(a1)), "2" ((long)(a2)), \
++ "3" ((long)(a3)), "4" ((long)(a4)), \
++ "5" ((long)(a5)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++static inline int
++HYPERVISOR_set_trap_table(
++ trap_info_t *table)
++{
++ return _hypercall1(int, set_trap_table, table);
++}
++
++static inline int
++HYPERVISOR_mmu_update(
++ mmu_update_t *req, int count, int *success_count, domid_t domid)
++{
++ return _hypercall4(int, mmu_update, req, count, success_count, domid);
++}
++
++static inline int
++HYPERVISOR_mmuext_op(
++ struct mmuext_op *op, int count, int *success_count, domid_t domid)
++{
++ return _hypercall4(int, mmuext_op, op, count, success_count, domid);
++}
++
++static inline int
++HYPERVISOR_set_gdt(
++ unsigned long *frame_list, int entries)
++{
++ return _hypercall2(int, set_gdt, frame_list, entries);
++}
++
++static inline int
++HYPERVISOR_stack_switch(
++ unsigned long ss, unsigned long esp)
++{
++ return _hypercall2(int, stack_switch, ss, esp);
++}
++
++static inline int
++HYPERVISOR_set_callbacks(
++ unsigned long event_selector, unsigned long event_address,
++ unsigned long failsafe_selector, unsigned long failsafe_address)
++{
++ return _hypercall4(int, set_callbacks,
++ event_selector, event_address,
++ failsafe_selector, failsafe_address);
++}
++
++static inline int
++HYPERVISOR_fpu_taskswitch(
++ int set)
++{
++ return _hypercall1(int, fpu_taskswitch, set);
++}
++
++static inline int
++HYPERVISOR_sched_op_compat(
++ int cmd, unsigned long arg)
++{
++ return _hypercall2(int, sched_op_compat, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_sched_op(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, sched_op, cmd, arg);
++}
++
++static inline long
++HYPERVISOR_set_timer_op(
++ u64 timeout)
++{
++ unsigned long timeout_hi = (unsigned long)(timeout>>32);
++ unsigned long timeout_lo = (unsigned long)timeout;
++ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
++}
++
++static inline int
++HYPERVISOR_dom0_op(
++ dom0_op_t *dom0_op)
++{
++ dom0_op->interface_version = DOM0_INTERFACE_VERSION;
++ return _hypercall1(int, dom0_op, dom0_op);
++}
++
++static inline int
++HYPERVISOR_set_debugreg(
++ int reg, unsigned long value)
++{
++ return _hypercall2(int, set_debugreg, reg, value);
++}
++
++static inline unsigned long
++HYPERVISOR_get_debugreg(
++ int reg)
++{
++ return _hypercall1(unsigned long, get_debugreg, reg);
++}
++
++static inline int
++HYPERVISOR_update_descriptor(
++ u64 ma, u64 desc)
++{
++ return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
++}
++
++static inline int
++HYPERVISOR_memory_op(
++ unsigned int cmd, void *arg)
++{
++ return _hypercall2(int, memory_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_multicall(
++ void *call_list, int nr_calls)
++{
++ return _hypercall2(int, multicall, call_list, nr_calls);
++}
++
++static inline int
++HYPERVISOR_update_va_mapping(
++ unsigned long va, pte_t new_val, unsigned long flags)
++{
++ unsigned long pte_hi = 0;
++#ifdef CONFIG_X86_PAE
++ pte_hi = new_val.pte_high;
++#endif
++ return _hypercall4(int, update_va_mapping, va,
++ new_val.pte_low, pte_hi, flags);
++}
++
++static inline int
++HYPERVISOR_event_channel_op(
++ int cmd, void *arg)
++{
++ int rc = _hypercall2(int, event_channel_op, cmd, arg);
++ if (unlikely(rc == -ENOSYS)) {
++ struct evtchn_op op;
++ op.cmd = cmd;
++ memcpy(&op.u, arg, sizeof(op.u));
++ rc = _hypercall1(int, event_channel_op_compat, &op);
++ memcpy(arg, &op.u, sizeof(op.u));
++ }
++ return rc;
++}
++
++static inline int
++HYPERVISOR_acm_op(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, acm_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_xen_version(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, xen_version, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_console_io(
++ int cmd, int count, char *str)
++{
++ return _hypercall3(int, console_io, cmd, count, str);
++}
++
++static inline int
++HYPERVISOR_physdev_op(
++ int cmd, void *arg)
++{
++ int rc = _hypercall2(int, physdev_op, cmd, arg);
++ if (unlikely(rc == -ENOSYS)) {
++ struct physdev_op op;
++ op.cmd = cmd;
++ memcpy(&op.u, arg, sizeof(op.u));
++ rc = _hypercall1(int, physdev_op_compat, &op);
++ memcpy(arg, &op.u, sizeof(op.u));
++ }
++ return rc;
++}
++
++static inline int
++HYPERVISOR_grant_table_op(
++ unsigned int cmd, void *uop, unsigned int count)
++{
++ return _hypercall3(int, grant_table_op, cmd, uop, count);
++}
++
++static inline int
++HYPERVISOR_update_va_mapping_otherdomain(
++ unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
++{
++ unsigned long pte_hi = 0;
++#ifdef CONFIG_X86_PAE
++ pte_hi = new_val.pte_high;
++#endif
++ return _hypercall5(int, update_va_mapping_otherdomain, va,
++ new_val.pte_low, pte_hi, flags, domid);
++}
++
++static inline int
++HYPERVISOR_vm_assist(
++ unsigned int cmd, unsigned int type)
++{
++ return _hypercall2(int, vm_assist, cmd, type);
++}
++
++static inline int
++HYPERVISOR_vcpu_op(
++ int cmd, int vcpuid, void *extra_args)
++{
++ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
++}
++
++static inline int
++HYPERVISOR_suspend(
++ unsigned long srec)
++{
++ struct sched_shutdown sched_shutdown = {
++ .reason = SHUTDOWN_suspend
++ };
++
++ int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown,
++ &sched_shutdown, srec);
++
++ if (rc == -ENOSYS)
++ rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown,
++ SHUTDOWN_suspend, srec);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_nmi_op(
++ unsigned long op, void *arg)
++{
++ return _hypercall2(int, nmi_op, op, arg);
++}
++
++static inline unsigned long
++HYPERVISOR_hvm_op(
++ int op, void *arg)
++{
++ return _hypercall2(unsigned long, hvm_op, op, arg);
++}
++
++static inline int
++HYPERVISOR_callback_op(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, callback_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_xenoprof_op(
++ int op, void *arg)
++{
++ return _hypercall2(int, xenoprof_op, op, arg);
++}
++
++
++#endif /* __HYPERCALL_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/hypervisor.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/hypervisor.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/hypervisor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/hypervisor.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,234 @@
++/******************************************************************************
++ * hypervisor.h
++ *
++ * Linux-specific hypervisor handling.
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __HYPERVISOR_H__
++#define __HYPERVISOR_H__
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/dom0_ops.h>
++#include <xen/interface/event_channel.h>
++#include <xen/interface/physdev.h>
++#include <xen/interface/sched.h>
++#include <xen/interface/nmi.h>
++#include <asm/ptrace.h>
++#include <asm/page.h>
++#if defined(__i386__)
++# ifdef CONFIG_X86_PAE
++# include <asm-generic/pgtable-nopud.h>
++# else
++# include <asm-generic/pgtable-nopmd.h>
++# endif
++#endif
++
++extern shared_info_t *HYPERVISOR_shared_info;
++
++/* arch/xen/i386/kernel/setup.c */
++extern start_info_t *xen_start_info;
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
++#else
++#define is_initial_xendomain() 0
++#endif
++
++/* arch/xen/kernel/evtchn.c */
++/* Force a proper event-channel callback from Xen. */
++void force_evtchn_callback(void);
++
++/* arch/xen/kernel/process.c */
++void xen_cpu_idle (void);
++
++/* arch/xen/i386/kernel/hypervisor.c */
++void do_hypervisor_callback(struct pt_regs *regs);
++
++/* arch/xen/i386/mm/hypervisor.c */
++/*
++ * NB. ptr values should be PHYSICAL, not MACHINE. 'vals' should be already
++ * be MACHINE addresses.
++ */
++
++void xen_pt_switch(unsigned long ptr);
++void xen_new_user_pt(unsigned long ptr); /* x86_64 only */
++void xen_load_gs(unsigned int selector); /* x86_64 only */
++void xen_tlb_flush(void);
++void xen_invlpg(unsigned long ptr);
++
++void xen_l1_entry_update(pte_t *ptr, pte_t val);
++void xen_l2_entry_update(pmd_t *ptr, pmd_t val);
++void xen_l3_entry_update(pud_t *ptr, pud_t val); /* x86_64/PAE */
++void xen_l4_entry_update(pgd_t *ptr, pgd_t val); /* x86_64 only */
++void xen_pgd_pin(unsigned long ptr);
++void xen_pgd_unpin(unsigned long ptr);
++
++void xen_set_ldt(unsigned long ptr, unsigned long bytes);
++void xen_machphys_update(unsigned long mfn, unsigned long pfn);
++
++#ifdef CONFIG_SMP
++#include <linux/cpumask.h>
++void xen_tlb_flush_all(void);
++void xen_invlpg_all(unsigned long ptr);
++void xen_tlb_flush_mask(cpumask_t *mask);
++void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr);
++#endif
++
++/* Returns zero on success else negative errno. */
++int xen_create_contiguous_region(
++ unsigned long vstart, unsigned int order, unsigned int address_bits);
++void xen_destroy_contiguous_region(
++ unsigned long vstart, unsigned int order);
++
++/* Turn jiffies into Xen system time. */
++u64 jiffies_to_st(unsigned long jiffies);
++
++#include <asm/hypercall.h>
++
++#if defined(CONFIG_X86_64)
++#define MULTI_UVMFLAGS_INDEX 2
++#define MULTI_UVMDOMID_INDEX 3
++#else
++#define MULTI_UVMFLAGS_INDEX 3
++#define MULTI_UVMDOMID_INDEX 4
++#endif
++
++#define is_running_on_xen() 1
++
++static inline int
++HYPERVISOR_yield(
++ void)
++{
++ int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
++
++ if (rc == -ENOSYS)
++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_block(
++ void)
++{
++ int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL);
++
++ if (rc == -ENOSYS)
++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_block, 0);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_shutdown(
++ unsigned int reason)
++{
++ struct sched_shutdown sched_shutdown = {
++ .reason = reason
++ };
++
++ int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
++
++ if (rc == -ENOSYS)
++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_poll(
++ evtchn_port_t *ports, unsigned int nr_ports, u64 timeout)
++{
++ int rc;
++ struct sched_poll sched_poll = {
++ .nr_ports = nr_ports,
++ .timeout = jiffies_to_st(timeout)
++ };
++ set_xen_guest_handle(sched_poll.ports, ports);
++
++ rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll);
++ if (rc == -ENOSYS)
++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0);
++
++ return rc;
++}
++
++static inline void
++MULTI_update_va_mapping(
++ multicall_entry_t *mcl, unsigned long va,
++ pte_t new_val, unsigned long flags)
++{
++ mcl->op = __HYPERVISOR_update_va_mapping;
++ mcl->args[0] = va;
++#if defined(CONFIG_X86_64)
++ mcl->args[1] = new_val.pte;
++#elif defined(CONFIG_X86_PAE)
++ mcl->args[1] = new_val.pte_low;
++ mcl->args[2] = new_val.pte_high;
++#else
++ mcl->args[1] = new_val.pte_low;
++ mcl->args[2] = 0;
++#endif
++ mcl->args[MULTI_UVMFLAGS_INDEX] = flags;
++}
++
++static inline void
++MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd,
++ void *uop, unsigned int count)
++{
++ mcl->op = __HYPERVISOR_grant_table_op;
++ mcl->args[0] = cmd;
++ mcl->args[1] = (unsigned long)uop;
++ mcl->args[2] = count;
++}
++
++static inline void
++MULTI_update_va_mapping_otherdomain(
++ multicall_entry_t *mcl, unsigned long va,
++ pte_t new_val, unsigned long flags, domid_t domid)
++{
++ mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
++ mcl->args[0] = va;
++#if defined(CONFIG_X86_64)
++ mcl->args[1] = new_val.pte;
++#elif defined(CONFIG_X86_PAE)
++ mcl->args[1] = new_val.pte_low;
++ mcl->args[2] = new_val.pte_high;
++#else
++ mcl->args[1] = new_val.pte_low;
++ mcl->args[2] = 0;
++#endif
++ mcl->args[MULTI_UVMFLAGS_INDEX] = flags;
++ mcl->args[MULTI_UVMDOMID_INDEX] = domid;
++}
++
++#endif /* __HYPERVISOR_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/io.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/io.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/io.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/io.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,389 @@
++#ifndef _ASM_IO_H
++#define _ASM_IO_H
++
++#include <linux/string.h>
++#include <linux/compiler.h>
++
++/*
++ * This file contains the definitions for the x86 IO instructions
++ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
++ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
++ * versions of the single-IO instructions (inb_p/inw_p/..).
++ *
++ * This file is not meant to be obfuscating: it's just complicated
++ * to (a) handle it all in a way that makes gcc able to optimize it
++ * as well as possible and (b) trying to avoid writing the same thing
++ * over and over again with slight variations and possibly making a
++ * mistake somewhere.
++ */
++
++/*
++ * Thanks to James van Artsdalen for a better timing-fix than
++ * the two short jumps: using outb's to a nonexistent port seems
++ * to guarantee better timings even on fast machines.
++ *
++ * On the other hand, I'd like to be sure of a non-existent port:
++ * I feel a bit unsafe about using 0x80 (should be safe, though)
++ *
++ * Linus
++ */
++
++ /*
++ * Bit simplified and optimized by Jan Hubicka
++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
++ *
++ * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
++ * isa_read[wl] and isa_write[wl] fixed
++ * - Arnaldo Carvalho de Melo <acme at conectiva.com.br>
++ */
++
++#define IO_SPACE_LIMIT 0xffff
++
++#define XQUAD_PORTIO_BASE 0xfe400000
++#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
++
++#ifdef __KERNEL__
++
++#include <asm-generic/iomap.h>
++
++#include <linux/vmalloc.h>
++#include <asm/fixmap.h>
++
++/*
++ * 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
++
++/**
++ * virt_to_phys - map virtual addresses to physical
++ * @address: address to remap
++ *
++ * The returned physical address is the physical (CPU) mapping for
++ * the memory address given. It is only valid to use this function on
++ * addresses directly mapped or allocated via kmalloc.
++ *
++ * This function does not give bus mappings for DMA transfers. In
++ * almost all conceivable cases a device driver should not be using
++ * this function
++ */
++
++static inline unsigned long virt_to_phys(volatile void * address)
++{
++ return __pa(address);
++}
++
++/**
++ * phys_to_virt - map physical address to virtual
++ * @address: address to remap
++ *
++ * The returned virtual address is a current CPU mapping for
++ * the memory address given. It is only valid to use this function on
++ * addresses that have a kernel mapping
++ *
++ * This function does not handle bus mappings for DMA transfers. In
++ * almost all conceivable cases a device driver should not be using
++ * this function
++ */
++
++static inline void * phys_to_virt(unsigned long address)
++{
++ return __va(address);
++}
++
++/*
++ * Change "struct page" to physical address.
++ */
++#define page_to_pseudophys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
++#define page_to_phys(page) (phys_to_machine(page_to_pseudophys(page)))
++#define page_to_bus(page) (phys_to_machine(page_to_pseudophys(page)))
++
++#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \
++ (unsigned long) bio_offset((bio)))
++#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \
++ (unsigned long) (bv)->bv_offset)
++
++#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \
++ (((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) && \
++ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \
++ bvec_to_pseudophys((vec2))))
++
++extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
++
++/**
++ * ioremap - map bus memory into CPU space
++ * @offset: bus address of the memory
++ * @size: size of the resource to map
++ *
++ * ioremap performs a platform specific sequence of operations to
++ * make bus memory CPU accessible via the readb/readw/readl/writeb/
++ * writew/writel functions and the other mmio helpers. The returned
++ * address is not guaranteed to be usable directly as a virtual
++ * address.
++ */
++
++static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
++{
++ return __ioremap(offset, size, 0);
++}
++
++extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
++extern void iounmap(volatile void __iomem *addr);
++
++/*
++ * bt_ioremap() and bt_iounmap() are for temporary early boot-time
++ * mappings, before the real ioremap() is functional.
++ * A boot-time mapping is currently limited to at most 16 pages.
++ */
++extern void *bt_ioremap(unsigned long offset, unsigned long size);
++extern void bt_iounmap(void *addr, unsigned long size);
++
++/* Use early IO mappings for DMI because it's initialized early */
++#define dmi_ioremap bt_ioremap
++#define dmi_iounmap bt_iounmap
++#define dmi_alloc alloc_bootmem
++
++/*
++ * ISA I/O bus memory addresses are 1:1 with the physical address.
++ */
++#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x
++#define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x
++#define isa_bus_to_virt(_x) (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + (_x))
++
++/*
++ * However PCI ones are not necessarily 1:1 and therefore these interfaces
++ * are forbidden in portable PCI drivers.
++ *
++ * Allow them on x86 for legacy drivers, though.
++ */
++#define virt_to_bus(_x) phys_to_machine(__pa(_x))
++#define bus_to_virt(_x) __va(machine_to_phys(_x))
++
++/*
++ * readX/writeX() are used to access memory mapped devices. On some
++ * architectures the memory mapped IO stuff needs to be accessed
++ * differently. On the x86 architecture, we just read/write the
++ * memory location directly.
++ */
++
++static inline unsigned char readb(const volatile void __iomem *addr)
++{
++ return *(volatile unsigned char __force *) addr;
++}
++static inline unsigned short readw(const volatile void __iomem *addr)
++{
++ return *(volatile unsigned short __force *) addr;
++}
++static inline unsigned int readl(const volatile void __iomem *addr)
++{
++ return *(volatile unsigned int __force *) addr;
++}
++#define readb_relaxed(addr) readb(addr)
++#define readw_relaxed(addr) readw(addr)
++#define readl_relaxed(addr) readl(addr)
++#define __raw_readb readb
++#define __raw_readw readw
++#define __raw_readl readl
++
++static inline void writeb(unsigned char b, volatile void __iomem *addr)
++{
++ *(volatile unsigned char __force *) addr = b;
++}
++static inline void writew(unsigned short b, volatile void __iomem *addr)
++{
++ *(volatile unsigned short __force *) addr = b;
++}
++static inline void writel(unsigned int b, volatile void __iomem *addr)
++{
++ *(volatile unsigned int __force *) addr = b;
++}
++#define __raw_writeb writeb
++#define __raw_writew writew
++#define __raw_writel writel
++
++#define mmiowb()
++
++static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
++{
++ memset((void __force *) addr, val, count);
++}
++static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
++{
++ __memcpy(dst, (void __force *) src, count);
++}
++static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
++{
++ __memcpy((void __force *) dst, src, count);
++}
++
++/*
++ * ISA space is 'always mapped' on a typical x86 system, no need to
++ * explicitly ioremap() it. The fact that the ISA IO space is mapped
++ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
++ * are physical addresses. The following constant pointer can be
++ * used as the IO-area pointer (it can be iounmapped as well, so the
++ * analogy with PCI is quite large):
++ */
++#define __ISA_IO_base ((char __iomem *)(fix_to_virt(FIX_ISAMAP_BEGIN)))
++
++/*
++ * Again, i386 does not require mem IO specific function.
++ */
++
++#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d))
++
++/**
++ * check_signature - find BIOS signatures
++ * @io_addr: mmio address to check
++ * @signature: signature block
++ * @length: length of signature
++ *
++ * Perform a signature comparison with the mmio address io_addr. This
++ * address should have been obtained by ioremap.
++ * Returns 1 on a match.
++ */
++
++static inline int check_signature(volatile void __iomem * io_addr,
++ const unsigned char *signature, int length)
++{
++ int retval = 0;
++ do {
++ if (readb(io_addr) != *signature)
++ goto out;
++ io_addr++;
++ signature++;
++ length--;
++ } while (length);
++ retval = 1;
++out:
++ return retval;
++}
++
++/*
++ * Cache management
++ *
++ * This needed for two cases
++ * 1. Out of order aware processors
++ * 2. Accidentally out of order processors (PPro errata #51)
++ */
++
++#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
++
++static inline void flush_write_buffers(void)
++{
++ __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
++}
++
++#define dma_cache_inv(_start,_size) flush_write_buffers()
++#define dma_cache_wback(_start,_size) flush_write_buffers()
++#define dma_cache_wback_inv(_start,_size) flush_write_buffers()
++
++#else
++
++/* Nothing to do */
++
++#define dma_cache_inv(_start,_size) do { } while (0)
++#define dma_cache_wback(_start,_size) do { } while (0)
++#define dma_cache_wback_inv(_start,_size) do { } while (0)
++#define flush_write_buffers()
++
++#endif
++
++#endif /* __KERNEL__ */
++
++#ifdef SLOW_IO_BY_JUMPING
++#define __SLOW_DOWN_IO "jmp 1f; 1: jmp 1f; 1:"
++#else
++#define __SLOW_DOWN_IO "outb %%al,$0x80;"
++#endif
++
++static inline void slow_down_io(void) {
++ __asm__ __volatile__(
++ __SLOW_DOWN_IO
++#ifdef REALLY_SLOW_IO
++ __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
++#endif
++ : : );
++}
++
++#ifdef CONFIG_X86_NUMAQ
++extern void *xquad_portio; /* Where the IO area was mapped */
++#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
++#define __BUILDIO(bwl,bw,type) \
++static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \
++ if (xquad_portio) \
++ write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \
++ else \
++ out##bwl##_local(value, port); \
++} \
++static inline void out##bwl(unsigned type value, int port) { \
++ out##bwl##_quad(value, port, 0); \
++} \
++static inline unsigned type in##bwl##_quad(int port, int quad) { \
++ if (xquad_portio) \
++ return read##bwl(XQUAD_PORT_ADDR(port, quad)); \
++ else \
++ return in##bwl##_local(port); \
++} \
++static inline unsigned type in##bwl(int port) { \
++ return in##bwl##_quad(port, 0); \
++}
++#else
++#define __BUILDIO(bwl,bw,type) \
++static inline void out##bwl(unsigned type value, int port) { \
++ out##bwl##_local(value, port); \
++} \
++static inline unsigned type in##bwl(int port) { \
++ return in##bwl##_local(port); \
++}
++#endif
++
++
++#define BUILDIO(bwl,bw,type) \
++static inline void out##bwl##_local(unsigned type value, int port) { \
++ __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \
++} \
++static inline unsigned type in##bwl##_local(int port) { \
++ unsigned type value; \
++ __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \
++ return value; \
++} \
++static inline void out##bwl##_local_p(unsigned type value, int port) { \
++ out##bwl##_local(value, port); \
++ slow_down_io(); \
++} \
++static inline unsigned type in##bwl##_local_p(int port) { \
++ unsigned type value = in##bwl##_local(port); \
++ slow_down_io(); \
++ return value; \
++} \
++__BUILDIO(bwl,bw,type) \
++static inline void out##bwl##_p(unsigned type value, int port) { \
++ out##bwl(value, port); \
++ slow_down_io(); \
++} \
++static inline unsigned type in##bwl##_p(int port) { \
++ unsigned type value = in##bwl(port); \
++ slow_down_io(); \
++ return value; \
++} \
++static inline void outs##bwl(int port, const void *addr, unsigned long count) { \
++ __asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \
++} \
++static inline void ins##bwl(int port, void *addr, unsigned long count) { \
++ __asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \
++}
++
++BUILDIO(b,b,char)
++BUILDIO(w,w,short)
++BUILDIO(l,,int)
++
++/* We will be supplying our own /dev/mem implementation */
++#define ARCH_HAS_DEV_MEM
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/irqflags.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/irqflags.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/irqflags.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/irqflags.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,80 @@
++/*
++ * include/asm-i386/irqflags.h
++ *
++ * IRQ flags handling
++ *
++ * This file gets included from lowlevel asm headers too, to provide
++ * wrapped versions of the local_irq_*() APIs, based on the
++ * raw_local_irq_*() functions from the lowlevel headers.
++ */
++#ifndef _ASM_IRQFLAGS_H
++#define _ASM_IRQFLAGS_H
++
++#ifndef __ASSEMBLY__
++
++#define raw_local_save_flags(flags) \
++ do { (flags) = __raw_local_save_flags(); } while (0)
++
++unsigned long __raw_local_save_flags(void);
++void raw_local_irq_restore(unsigned long flags);
++void raw_local_irq_disable(void);
++void raw_local_irq_enable(void);
++
++/*
++ * Used in the idle loop; sti takes one instruction cycle
++ * to complete:
++ */
++void raw_safe_halt(void);
++
++/*
++ * Used when interrupts are already enabled or to
++ * shutdown the processor:
++ */
++void halt(void);
++
++static inline int raw_irqs_disabled_flags(unsigned long flags)
++{
++ return flags != 0;
++}
++
++int raw_irqs_disabled(void);
++
++/*
++ * For spinlocks, etc:
++ */
++unsigned long __raw_local_irq_save(void);
++#define raw_local_irq_save(flags) \
++ do { (flags) = __raw_local_irq_save(); } while (0)
++
++#endif /* __ASSEMBLY__ */
++
++/*
++ * Do the CPU's IRQ-state tracing from assembly code. We call a
++ * C function, so save all the C-clobbered registers:
++ */
++#ifdef CONFIG_TRACE_IRQFLAGS
++
++# define TRACE_IRQS_ON \
++ pushl %eax; \
++ pushl %ecx; \
++ pushl %edx; \
++ call trace_hardirqs_on; \
++ popl %edx; \
++ popl %ecx; \
++ popl %eax;
++
++# define TRACE_IRQS_OFF \
++ pushl %eax; \
++ pushl %ecx; \
++ pushl %edx; \
++ call trace_hardirqs_off; \
++ popl %edx; \
++ popl %ecx; \
++ popl %eax;
++
++#else
++# define TRACE_IRQS_ON
++# define TRACE_IRQS_OFF
++#endif
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/kmap_types.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/kmap_types.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/kmap_types.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/kmap_types.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,31 @@
++#ifndef _ASM_KMAP_TYPES_H
++#define _ASM_KMAP_TYPES_H
++
++
++#ifdef CONFIG_DEBUG_HIGHMEM
++# define D(n) __KM_FENCE_##n ,
++#else
++# define D(n)
++#endif
++
++enum km_type {
++D(0) KM_BOUNCE_READ,
++D(1) KM_SKB_SUNRPC_DATA,
++D(2) KM_SKB_DATA_SOFTIRQ,
++D(3) KM_USER0,
++D(4) KM_USER1,
++D(5) KM_BIO_SRC_IRQ,
++D(6) KM_BIO_DST_IRQ,
++D(7) KM_PTE0,
++D(8) KM_PTE1,
++D(9) KM_IRQ0,
++D(10) KM_IRQ1,
++D(11) KM_SOFTIRQ0,
++D(12) KM_SOFTIRQ1,
++D(13) KM_SWIOTLB,
++D(14) KM_TYPE_NR
++};
++
++#undef D
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/maddr.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/maddr.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/maddr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/maddr.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,160 @@
++#ifndef _I386_MADDR_H
++#define _I386_MADDR_H
++
++#include <xen/features.h>
++#include <xen/interface/xen.h>
++
++/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
++#define INVALID_P2M_ENTRY (~0UL)
++#define FOREIGN_FRAME_BIT (1UL<<31)
++#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
++
++#ifdef CONFIG_XEN
++
++extern unsigned long *phys_to_machine_mapping;
++
++#undef machine_to_phys_mapping
++extern unsigned long *machine_to_phys_mapping;
++extern unsigned int machine_to_phys_order;
++
++static inline unsigned long pfn_to_mfn(unsigned long pfn)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return pfn;
++ return phys_to_machine_mapping[(unsigned int)(pfn)] &
++ ~FOREIGN_FRAME_BIT;
++}
++
++static inline int phys_to_machine_mapping_valid(unsigned long pfn)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return 1;
++ return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
++}
++
++static inline unsigned long mfn_to_pfn(unsigned long mfn)
++{
++ extern unsigned long max_mapnr;
++ unsigned long pfn;
++
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return mfn;
++
++ if (unlikely((mfn >> machine_to_phys_order) != 0))
++ return max_mapnr;
++
++ /* The array access can fail (e.g., device space beyond end of RAM). */
++ asm (
++ "1: movl %1,%0\n"
++ "2:\n"
++ ".section .fixup,\"ax\"\n"
++ "3: movl %2,%0\n"
++ " jmp 2b\n"
++ ".previous\n"
++ ".section __ex_table,\"a\"\n"
++ " .align 4\n"
++ " .long 1b,3b\n"
++ ".previous"
++ : "=r" (pfn)
++ : "m" (machine_to_phys_mapping[mfn]), "m" (max_mapnr) );
++
++ return pfn;
++}
++
++/*
++ * We detect special mappings in one of two ways:
++ * 1. If the MFN is an I/O page then Xen will set the m2p entry
++ * to be outside our maximum possible pseudophys range.
++ * 2. If the MFN belongs to a different domain then we will certainly
++ * not have MFN in our p2m table. Conversely, if the page is ours,
++ * then we'll have p2m(m2p(MFN))==MFN.
++ * If we detect a special mapping then it doesn't have a 'struct page'.
++ * We force !pfn_valid() by returning an out-of-range pointer.
++ *
++ * NB. These checks require that, for any MFN that is not in our reservation,
++ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
++ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
++ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
++ *
++ * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
++ * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
++ * require. In all the cases we care about, the FOREIGN_FRAME bit is
++ * masked (e.g., pfn_to_mfn()) so behaviour there is correct.
++ */
++static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
++{
++ extern unsigned long max_mapnr;
++ unsigned long pfn = mfn_to_pfn(mfn);
++ if ((pfn < max_mapnr)
++ && !xen_feature(XENFEAT_auto_translated_physmap)
++ && (phys_to_machine_mapping[pfn] != mfn))
++ return max_mapnr; /* force !pfn_valid() */
++ return pfn;
++}
++
++static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap)) {
++ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
++ return;
++ }
++ phys_to_machine_mapping[pfn] = mfn;
++}
++
++
++#else /* !CONFIG_XEN */
++
++#define pfn_to_mfn(pfn) (pfn)
++#define mfn_to_pfn(mfn) (mfn)
++#define mfn_to_local_pfn(mfn) (mfn)
++#define set_phys_to_machine(pfn, mfn) BUG_ON((pfn) != (mfn))
++#define phys_to_machine_mapping_valid(pfn) (1)
++
++#endif /* !CONFIG_XEN */
++
++/* Definitions for machine and pseudophysical addresses. */
++#ifdef CONFIG_X86_PAE
++typedef unsigned long long paddr_t;
++typedef unsigned long long maddr_t;
++#else
++typedef unsigned long paddr_t;
++typedef unsigned long maddr_t;
++#endif
++
++static inline maddr_t phys_to_machine(paddr_t phys)
++{
++ maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
++ machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
++ return machine;
++}
++static inline paddr_t machine_to_phys(maddr_t machine)
++{
++ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
++ phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
++ return phys;
++}
++
++/* VIRT <-> MACHINE conversion */
++#define virt_to_machine(v) (phys_to_machine(__pa(v)))
++#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
++#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
++
++#ifdef CONFIG_X86_PAE
++static inline pte_t pfn_pte_ma(unsigned long page_nr, pgprot_t pgprot)
++{
++ pte_t pte;
++
++ pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | \
++ (pgprot_val(pgprot) >> 32);
++ pte.pte_high &= (__supported_pte_mask >> 32);
++ pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)) & \
++ __supported_pte_mask;
++ return pte;
++}
++#else
++#define pfn_pte_ma(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++#endif
++
++#define __pte_ma(x) ((pte_t) { (x) } )
++
++#endif /* _I386_MADDR_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/mmu_context.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/mmu_context.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/mmu_context.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/mmu_context.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,108 @@
++#ifndef __I386_SCHED_H
++#define __I386_SCHED_H
++
++#include <asm/desc.h>
++#include <asm/atomic.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++
++/*
++ * Used for LDT copy/destruction.
++ */
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
++void destroy_context(struct mm_struct *mm);
++
++
++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
++{
++#if 0 /* XEN: no lazy tlb */
++ unsigned cpu = smp_processor_id();
++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
++ per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_LAZY;
++#endif
++}
++
++#define prepare_arch_switch(next) __prepare_arch_switch()
++
++static inline void __prepare_arch_switch(void)
++{
++ /*
++ * Save away %fs and %gs. No need to save %es and %ds, as those
++ * are always kernel segments while inside the kernel. Must
++ * happen before reload of cr3/ldt (i.e., not in __switch_to).
++ */
++ asm volatile ( "mov %%fs,%0 ; mov %%gs,%1"
++ : "=m" (current->thread.fs),
++ "=m" (current->thread.gs));
++ asm volatile ( "movl %0,%%fs ; movl %0,%%gs"
++ : : "r" (0) );
++}
++
++extern void mm_pin(struct mm_struct *mm);
++extern void mm_unpin(struct mm_struct *mm);
++void mm_pin_all(void);
++
++static inline void switch_mm(struct mm_struct *prev,
++ struct mm_struct *next,
++ struct task_struct *tsk)
++{
++ int cpu = smp_processor_id();
++ struct mmuext_op _op[2], *op = _op;
++
++ if (likely(prev != next)) {
++ BUG_ON(!xen_feature(XENFEAT_writable_page_tables) &&
++ !test_bit(PG_pinned, &virt_to_page(next->pgd)->flags));
++
++ /* stop flush ipis for the previous mm */
++ cpu_clear(cpu, prev->cpu_vm_mask);
++#if 0 /* XEN: no lazy tlb */
++ per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
++ per_cpu(cpu_tlbstate, cpu).active_mm = next;
++#endif
++ cpu_set(cpu, next->cpu_vm_mask);
++
++ /* Re-load page tables: load_cr3(next->pgd) */
++ op->cmd = MMUEXT_NEW_BASEPTR;
++ op->arg1.mfn = pfn_to_mfn(__pa(next->pgd) >> PAGE_SHIFT);
++ op++;
++
++ /*
++ * load the LDT, if the LDT is different:
++ */
++ if (unlikely(prev->context.ldt != next->context.ldt)) {
++ /* load_LDT_nolock(&next->context, cpu) */
++ op->cmd = MMUEXT_SET_LDT;
++ op->arg1.linear_addr = (unsigned long)next->context.ldt;
++ op->arg2.nr_ents = next->context.size;
++ op++;
++ }
++
++ BUG_ON(HYPERVISOR_mmuext_op(_op, op-_op, NULL, DOMID_SELF));
++ }
++#if 0 /* XEN: no lazy tlb */
++ else {
++ per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
++ BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
++
++ if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
++ /* We were in lazy tlb mode and leave_mm disabled
++ * tlb flush IPI delivery. We must reload %cr3.
++ */
++ load_cr3(next->pgd);
++ load_LDT_nolock(&next->context, cpu);
++ }
++ }
++#endif
++}
++
++#define deactivate_mm(tsk, mm) \
++ asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0))
++
++static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
++{
++ if (!test_bit(PG_pinned, &virt_to_page(next->pgd)->flags))
++ mm_pin(next);
++ switch_mm(prev, next, NULL);
++}
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/mmu.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/mmu.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/mmu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/mmu.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,29 @@
++#ifndef __i386_MMU_H
++#define __i386_MMU_H
++
++#include <asm/semaphore.h>
++/*
++ * The i386 doesn't have a mmu context, but
++ * we put the segment information here.
++ *
++ * cpu_vm_mask is used to optimize ldt flushing.
++ */
++typedef struct {
++ int size;
++ struct semaphore sem;
++ void *ldt;
++ void *vdso;
++#ifdef CONFIG_XEN
++ int has_foreign_mappings;
++#endif
++} mm_context_t;
++
++/* mm/memory.c:exit_mmap hook */
++extern void _arch_exit_mmap(struct mm_struct *mm);
++#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm)
++
++/* kernel/fork.c:dup_mmap hook */
++extern void _arch_dup_mmap(struct mm_struct *mm);
++#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm))
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/page.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/page.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/page.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/page.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,220 @@
++#ifndef _I386_PAGE_H
++#define _I386_PAGE_H
++
++/* PAGE_SHIFT determines the page size */
++#define PAGE_SHIFT 12
++#define PAGE_SIZE (1UL << PAGE_SHIFT)
++#define PAGE_MASK (~(PAGE_SIZE-1))
++
++#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
++#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
++
++#ifdef __KERNEL__
++#ifndef __ASSEMBLY__
++
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/bug.h>
++#include <xen/interface/xen.h>
++#include <xen/features.h>
++#include <xen/foreign_page.h>
++
++#define arch_free_page(_page,_order) \
++({ int foreign = PageForeign(_page); \
++ if (foreign) \
++ (PageForeignDestructor(_page))(_page); \
++ foreign; \
++})
++#define HAVE_ARCH_FREE_PAGE
++
++#ifdef CONFIG_XEN_SCRUB_PAGES
++#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
++#else
++#define scrub_pages(_p,_n) ((void)0)
++#endif
++
++#ifdef CONFIG_X86_USE_3DNOW
++
++#include <asm/mmx.h>
++
++#define clear_page(page) mmx_clear_page((void *)(page))
++#define copy_page(to,from) mmx_copy_page(to,from)
++
++#else
++
++#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
++#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
++
++/*
++ * On older X86 processors it's not a win to use MMX here it seems.
++ * Maybe the K6-III ?
++ */
++
++#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
++#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
++
++#endif
++
++#define clear_user_page(page, vaddr, pg) clear_page(page)
++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
++
++/*
++ * These are used to make use of C type-checking..
++ */
++extern int nx_enabled;
++#ifdef CONFIG_X86_PAE
++extern unsigned long long __supported_pte_mask;
++typedef struct { unsigned long pte_low, pte_high; } pte_t;
++typedef struct { unsigned long long pmd; } pmd_t;
++typedef struct { unsigned long long pgd; } pgd_t;
++typedef struct { unsigned long long pgprot; } pgprot_t;
++#define pgprot_val(x) ((x).pgprot)
++#include <asm/maddr.h>
++#define __pte(x) ({ unsigned long long _x = (x); \
++ if (_x & 1) _x = phys_to_machine(_x); \
++ ((pte_t) {(unsigned long)(_x), (unsigned long)(_x>>32)}); })
++#define __pgd(x) ({ unsigned long long _x = (x); \
++ (((_x)&1) ? ((pgd_t) {phys_to_machine(_x)}) : ((pgd_t) {(_x)})); })
++#define __pmd(x) ({ unsigned long long _x = (x); \
++ (((_x)&1) ? ((pmd_t) {phys_to_machine(_x)}) : ((pmd_t) {(_x)})); })
++static inline unsigned long long pte_val(pte_t x)
++{
++ unsigned long long ret;
++
++ if (x.pte_low) {
++ ret = x.pte_low | (unsigned long long)x.pte_high << 32;
++ ret = machine_to_phys(ret) | 1;
++ } else {
++ ret = 0;
++ }
++ return ret;
++}
++static inline unsigned long long pmd_val(pmd_t x)
++{
++ unsigned long long ret = x.pmd;
++ if (ret) ret = machine_to_phys(ret) | 1;
++ return ret;
++}
++static inline unsigned long long pgd_val(pgd_t x)
++{
++ unsigned long long ret = x.pgd;
++ if (ret) ret = machine_to_phys(ret) | 1;
++ return ret;
++}
++static inline unsigned long long pte_val_ma(pte_t x)
++{
++ return (unsigned long long)x.pte_high << 32 | x.pte_low;
++}
++#define HPAGE_SHIFT 21
++#else
++typedef struct { unsigned long pte_low; } pte_t;
++typedef struct { unsigned long pgd; } pgd_t;
++typedef struct { unsigned long pgprot; } pgprot_t;
++#define pgprot_val(x) ((x).pgprot)
++#include <asm/maddr.h>
++#define boot_pte_t pte_t /* or would you rather have a typedef */
++#define pte_val(x) (((x).pte_low & 1) ? machine_to_phys((x).pte_low) : \
++ (x).pte_low)
++#define pte_val_ma(x) ((x).pte_low)
++#define __pte(x) ({ unsigned long _x = (x); \
++ (((_x)&1) ? ((pte_t) {phys_to_machine(_x)}) : ((pte_t) {(_x)})); })
++#define __pgd(x) ({ unsigned long _x = (x); \
++ (((_x)&1) ? ((pgd_t) {phys_to_machine(_x)}) : ((pgd_t) {(_x)})); })
++static inline unsigned long pgd_val(pgd_t x)
++{
++ unsigned long ret = x.pgd;
++ if (ret) ret = machine_to_phys(ret) | 1;
++ return ret;
++}
++#define HPAGE_SHIFT 22
++#endif
++#define PTE_MASK PAGE_MASK
++
++#ifdef CONFIG_HUGETLB_PAGE
++#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
++#define HPAGE_MASK (~(HPAGE_SIZE - 1))
++#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
++#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
++#endif
++
++#define __pgprot(x) ((pgprot_t) { (x) } )
++
++#endif /* !__ASSEMBLY__ */
++
++/* to align the pointer to the (next) page boundary */
++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
++
++/*
++ * This handles the memory map.. We could make this a config
++ * option, but too many people screw it up, and too few need
++ * it.
++ *
++ * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
++ * a virtual address space of one gigabyte, which limits the
++ * amount of physical memory you can use to about 950MB.
++ *
++ * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
++ * and CONFIG_HIGHMEM64G options in the kernel configuration.
++ */
++
++#ifndef __ASSEMBLY__
++
++struct vm_area_struct;
++
++/*
++ * This much address space is reserved for vmalloc() and iomap()
++ * as well as fixmap mappings.
++ */
++extern unsigned int __VMALLOC_RESERVE;
++
++extern int sysctl_legacy_va_layout;
++
++extern int page_is_ram(unsigned long pagenr);
++
++#endif /* __ASSEMBLY__ */
++
++#ifdef __ASSEMBLY__
++#define __PAGE_OFFSET CONFIG_PAGE_OFFSET
++#define __PHYSICAL_START CONFIG_PHYSICAL_START
++#else
++#define __PAGE_OFFSET ((unsigned long)CONFIG_PAGE_OFFSET)
++#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START)
++#endif
++#define __KERNEL_START (__PAGE_OFFSET + __PHYSICAL_START)
++
++#ifdef CONFIG_XEN_COMPAT_030002
++#undef LOAD_OFFSET
++#define LOAD_OFFSET 0
++#endif /* CONFIG_XEN_COMPAT_030002 */
++
++#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
++#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)
++#define MAXMEM (__FIXADDR_TOP-__PAGE_OFFSET-__VMALLOC_RESERVE)
++#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
++#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
++#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
++#ifdef CONFIG_FLATMEM
++#define pfn_valid(pfn) ((pfn) < max_mapnr)
++#endif /* CONFIG_FLATMEM */
++#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
++
++#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
++
++#define VM_DATA_DEFAULT_FLAGS \
++ (VM_READ | VM_WRITE | \
++ ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
++ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
++
++/* VIRT <-> MACHINE conversion */
++#define virt_to_machine(v) (phys_to_machine(__pa(v)))
++#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
++#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
++
++#include <asm-generic/memory_model.h>
++#include <asm-generic/page.h>
++
++#define __HAVE_ARCH_GATE_AREA 1
++#endif /* __KERNEL__ */
++
++#endif /* _I386_PAGE_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/param.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/param.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/param.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/param.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,23 @@
++#ifndef _ASMi386_PARAM_H
++#define _ASMi386_PARAM_H
++
++#ifdef __KERNEL__
++# define HZ CONFIG_HZ /* Internal kernel timer frequency */
++# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
++# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
++#endif
++
++#ifndef HZ
++#define HZ 100
++#endif
++
++#define EXEC_PAGESIZE 4096
++
++#ifndef NOGROUP
++#define NOGROUP (-1)
++#endif
++
++#define MAXHOSTNAMELEN 64 /* max length of hostname */
++#define COMMAND_LINE_SIZE 256
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pci.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pci.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pci.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,153 @@
++#ifndef __i386_PCI_H
++#define __i386_PCI_H
++
++
++#ifdef __KERNEL__
++#include <linux/mm.h> /* for struct page */
++
++/* 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 */
++
++#ifdef CONFIG_PCI
++extern unsigned int pcibios_assign_all_busses(void);
++#else
++#define pcibios_assign_all_busses() 0
++#endif
++#define pcibios_scan_all_fns(a, b) 0
++
++extern unsigned long pci_mem_start;
++#define PCIBIOS_MIN_IO 0x1000
++#define PCIBIOS_MIN_MEM (pci_mem_start)
++
++#define PCIBIOS_MIN_CARDBUS_IO 0x4000
++
++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, 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);
++
++/* Dynamic DMA mapping stuff.
++ * i386 has everything mapped statically.
++ */
++
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <asm/scatterlist.h>
++#include <linux/string.h>
++#include <asm/io.h>
++
++struct pci_dev;
++
++#ifdef CONFIG_SWIOTLB
++
++
++/* On Xen we use SWIOTLB instead of blk-specific bounce buffers. */
++#define PCI_DMA_BUS_IS_PHYS (0)
++
++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
++ dma_addr_t ADDR_NAME;
++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
++ __u32 LEN_NAME;
++#define pci_unmap_addr(PTR, ADDR_NAME) \
++ ((PTR)->ADDR_NAME)
++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
++ (((PTR)->ADDR_NAME) = (VAL))
++#define pci_unmap_len(PTR, LEN_NAME) \
++ ((PTR)->LEN_NAME)
++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
++ (((PTR)->LEN_NAME) = (VAL))
++
++#else
++
++/* 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 nop 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_unmap_len(PTR, LEN_NAME) (0)
++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
++
++#endif
++
++/* This is always fine. */
++#define pci_dac_dma_supported(pci_dev, mask) (1)
++
++static inline dma64_addr_t
++pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
++{
++ return ((dma64_addr_t) page_to_phys(page) +
++ (dma64_addr_t) offset);
++}
++
++static inline struct page *
++pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
++{
++ return pfn_to_page(dma_addr >> PAGE_SHIFT);
++}
++
++static inline unsigned long
++pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
++{
++ return (dma_addr & ~PAGE_MASK);
++}
++
++static inline void
++pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
++{
++}
++
++static inline void
++pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
++{
++ flush_write_buffers();
++}
++
++#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);
++
++
++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__ */
++
++#ifdef CONFIG_XEN_PCIDEV_FRONTEND
++#include <xen/pcifront.h>
++#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
++
++/* implement the pci_ DMA API in terms of the generic device dma_ one */
++#include <asm-generic/pci-dma-compat.h>
++
++/* generic pci stuff */
++#include <asm-generic/pci.h>
++
++/* On Xen we have to scan all functions since Xen hides bridges from
++ * us. If a bridge is at fn=0 and that slot has a multifunction
++ * device, we won't find the additional devices without scanning all
++ * functions. */
++#undef pcibios_scan_all_fns
++#define pcibios_scan_all_fns(a, b) 1
++
++#endif /* __i386_PCI_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgalloc.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgalloc.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgalloc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgalloc.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,63 @@
++#ifndef _I386_PGALLOC_H
++#define _I386_PGALLOC_H
++
++#include <asm/fixmap.h>
++#include <linux/threads.h>
++#include <linux/mm.h> /* for struct page */
++#include <asm/io.h> /* for phys_to_virt and page_to_pseudophys */
++
++/* Is this pagetable pinned? */
++#define PG_pinned PG_arch_1
++
++#define pmd_populate_kernel(mm, pmd, pte) \
++ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
++
++#define pmd_populate(mm, pmd, pte) \
++do { \
++ if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) { \
++ if (!PageHighMem(pte)) \
++ BUG_ON(HYPERVISOR_update_va_mapping( \
++ (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT),\
++ pfn_pte(page_to_pfn(pte), PAGE_KERNEL_RO), 0));\
++ set_pmd(pmd, __pmd(_PAGE_TABLE + \
++ ((unsigned long long)page_to_pfn(pte) << \
++ (unsigned long long) PAGE_SHIFT))); \
++ } else { \
++ *(pmd) = __pmd(_PAGE_TABLE + \
++ ((unsigned long long)page_to_pfn(pte) << \
++ (unsigned long long) PAGE_SHIFT)); \
++ } \
++} while (0)
++
++/*
++ * Allocate and free page tables.
++ */
++extern pgd_t *pgd_alloc(struct mm_struct *);
++extern void pgd_free(pgd_t *pgd);
++
++extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
++extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
++
++static inline void pte_free_kernel(pte_t *pte)
++{
++ free_page((unsigned long)pte);
++ make_page_writable(pte, XENFEAT_writable_page_tables);
++}
++
++extern void pte_free(struct page *pte);
++
++#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
++
++#ifdef CONFIG_X86_PAE
++/*
++ * In the PAE case we free the pmds as part of the pgd.
++ */
++#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
++#define pmd_free(x) do { } while (0)
++#define __pmd_free_tlb(tlb,x) do { } while (0)
++#define pud_populate(mm, pmd, pte) BUG()
++#endif
++
++#define check_pgt_cache() do { } while (0)
++
++#endif /* _I386_PGALLOC_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef _I386_PGTABLE_2LEVEL_DEFS_H
++#define _I386_PGTABLE_2LEVEL_DEFS_H
++
++#define HAVE_SHARED_KERNEL_PMD 0
++
++/*
++ * traditional i386 two-level paging structure:
++ */
++
++#define PGDIR_SHIFT 22
++#define PTRS_PER_PGD 1024
++#define PTRS_PER_PGD_NO_HV (HYPERVISOR_VIRT_START >> PGDIR_SHIFT)
++
++/*
++ * the i386 is two-level, so we don't really have any
++ * PMD directory physically.
++ */
++
++#define PTRS_PER_PTE 1024
++
++#endif /* _I386_PGTABLE_2LEVEL_DEFS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-2level.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-2level.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-2level.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-2level.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,87 @@
++#ifndef _I386_PGTABLE_2LEVEL_H
++#define _I386_PGTABLE_2LEVEL_H
++
++#include <asm-generic/pgtable-nopmd.h>
++
++#define pte_ERROR(e) \
++ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
++#define pgd_ERROR(e) \
++ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++
++/*
++ * Certain architectures need to do special things when PTEs
++ * within a page table are directly modified. Thus, the following
++ * hook is made available.
++ */
++#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
++
++#define set_pte_at(_mm,addr,ptep,pteval) do { \
++ if (((_mm) != current->mm && (_mm) != &init_mm) || \
++ HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \
++ set_pte((ptep), (pteval)); \
++} while (0)
++
++#define set_pte_at_sync(_mm,addr,ptep,pteval) do { \
++ if (((_mm) != current->mm && (_mm) != &init_mm) || \
++ HYPERVISOR_update_va_mapping((addr), (pteval), UVMF_INVLPG)) { \
++ set_pte((ptep), (pteval)); \
++ xen_invlpg((addr)); \
++ } \
++} while (0)
++
++#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
++
++#define set_pmd(pmdptr, pmdval) xen_l2_entry_update((pmdptr), (pmdval))
++
++#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
++
++#define ptep_get_and_clear(mm,addr,xp) __pte_ma(xchg(&(xp)->pte_low, 0))
++#define pte_same(a, b) ((a).pte_low == (b).pte_low)
++#define pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT)
++#define pte_pfn(_pte) mfn_to_local_pfn(pte_mfn(_pte))
++
++#define pte_page(_pte) pfn_to_page(pte_pfn(_pte))
++
++#define pte_none(x) (!(x).pte_low)
++#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++
++/*
++ * All present user pages are user-executable:
++ */
++static inline int pte_exec(pte_t pte)
++{
++ return pte_user(pte);
++}
++
++/*
++ * All present pages are kernel-executable:
++ */
++static inline int pte_exec_kernel(pte_t pte)
++{
++ return 1;
++}
++
++/*
++ * Bits 0, 6 and 7 are taken, split up the 29 bits of offset
++ * into this range:
++ */
++#define PTE_FILE_MAX_BITS 29
++
++#define pte_to_pgoff(pte) \
++ ((((pte).pte_low >> 1) & 0x1f ) + (((pte).pte_low >> 8) << 5 ))
++
++#define pgoff_to_pte(off) \
++ ((pte_t) { (((off) & 0x1f) << 1) + (((off) >> 5) << 8) + _PAGE_FILE })
++
++/* Encode and de-code a swap entry */
++#define __swp_type(x) (((x).val >> 1) & 0x1f)
++#define __swp_offset(x) ((x).val >> 8)
++#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
++#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
++#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
++
++void vmalloc_sync_all(void);
++
++#endif /* _I386_PGTABLE_2LEVEL_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,25 @@
++#ifndef _I386_PGTABLE_3LEVEL_DEFS_H
++#define _I386_PGTABLE_3LEVEL_DEFS_H
++
++#define HAVE_SHARED_KERNEL_PMD 0
++
++/*
++ * PGDIR_SHIFT determines what a top-level page table entry can map
++ */
++#define PGDIR_SHIFT 30
++#define PTRS_PER_PGD 4
++#define PTRS_PER_PGD_NO_HV 4
++
++/*
++ * PMD_SHIFT determines the size of the area a middle-level
++ * page table can map
++ */
++#define PMD_SHIFT 21
++#define PTRS_PER_PMD 512
++
++/*
++ * entries per page directory level
++ */
++#define PTRS_PER_PTE 512
++
++#endif /* _I386_PGTABLE_3LEVEL_DEFS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-3level.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-3level.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable-3level.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable-3level.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,185 @@
++#ifndef _I386_PGTABLE_3LEVEL_H
++#define _I386_PGTABLE_3LEVEL_H
++
++#include <asm-generic/pgtable-nopud.h>
++
++/*
++ * Intel Physical Address Extension (PAE) Mode - three-level page
++ * tables on PPro+ CPUs.
++ *
++ * Copyright (C) 1999 Ingo Molnar <mingo at redhat.com>
++ */
++
++#define pte_ERROR(e) \
++ printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, &(e), (e).pte_high, (e).pte_low)
++#define pmd_ERROR(e) \
++ printk("%s:%d: bad pmd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pmd_val(e))
++#define pgd_ERROR(e) \
++ printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
++
++#define pud_none(pud) 0
++#define pud_bad(pud) 0
++#define pud_present(pud) 1
++
++/*
++ * Is the pte executable?
++ */
++static inline int pte_x(pte_t pte)
++{
++ return !(pte_val(pte) & _PAGE_NX);
++}
++
++/*
++ * All present user-pages with !NX bit are user-executable:
++ */
++static inline int pte_exec(pte_t pte)
++{
++ return pte_user(pte) && pte_x(pte);
++}
++/*
++ * All present pages with !NX bit are kernel-executable:
++ */
++static inline int pte_exec_kernel(pte_t pte)
++{
++ return pte_x(pte);
++}
++
++/* Rules for using set_pte: the pte being assigned *must* be
++ * either not present or in a state where the hardware will
++ * not attempt to update the pte. In places where this is
++ * not possible, use pte_get_and_clear to obtain the old pte
++ * value and then use set_pte to update it. -ben
++ */
++#define __HAVE_ARCH_SET_PTE_ATOMIC
++
++#if 1
++/* use writable pagetables */
++static inline void set_pte(pte_t *ptep, pte_t pte)
++{
++ ptep->pte_high = pte.pte_high;
++ smp_wmb();
++ ptep->pte_low = pte.pte_low;
++}
++# define set_pte_atomic(pteptr,pteval) \
++ set_64bit((unsigned long long *)(pteptr),pte_val_ma(pteval))
++#else
++/* no writable pagetables */
++# define set_pte(pteptr,pteval) \
++ xen_l1_entry_update((pteptr), (pteval))
++# define set_pte_atomic(pteptr,pteval) set_pte(pteptr,pteval)
++#endif
++
++#define set_pte_at(_mm,addr,ptep,pteval) do { \
++ if (((_mm) != current->mm && (_mm) != &init_mm) || \
++ HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \
++ set_pte((ptep), (pteval)); \
++} while (0)
++
++#define set_pte_at_sync(_mm,addr,ptep,pteval) do { \
++ if (((_mm) != current->mm && (_mm) != &init_mm) || \
++ HYPERVISOR_update_va_mapping((addr), (pteval), UVMF_INVLPG)) { \
++ set_pte((ptep), (pteval)); \
++ xen_invlpg((addr)); \
++ } \
++} while (0)
++
++#define set_pmd(pmdptr,pmdval) \
++ xen_l2_entry_update((pmdptr), (pmdval))
++#define set_pud(pudptr,pudval) \
++ xen_l3_entry_update((pudptr), (pudval))
++
++/*
++ * Pentium-II erratum A13: in PAE mode we explicitly have to flush
++ * the TLB via cr3 if the top-level pgd is changed...
++ * We do not let the generic code free and clear pgd entries due to
++ * this erratum.
++ */
++static inline void pud_clear (pud_t * pud) { }
++
++#define pud_page(pud) \
++((struct page *) __va(pud_val(pud) & PAGE_MASK))
++
++#define pud_page_kernel(pud) \
++((unsigned long) __va(pud_val(pud) & PAGE_MASK))
++
++
++/* Find an entry in the second-level page table.. */
++#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
++ pmd_index(address))
++
++/*
++ * For PTEs and PDEs, we must clear the P-bit first when clearing a page table
++ * entry, so clear the bottom half first and enforce ordering with a compiler
++ * barrier.
++ */
++static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
++{
++ ptep->pte_low = 0;
++ smp_wmb();
++ ptep->pte_high = 0;
++}
++
++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
++
++static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
++{
++ pte_t res;
++
++ /* xchg acts as a barrier before the setting of the high bits */
++ res.pte_low = xchg(&ptep->pte_low, 0);
++ res.pte_high = ptep->pte_high;
++ ptep->pte_high = 0;
++
++ return res;
++}
++
++static inline int pte_same(pte_t a, pte_t b)
++{
++ return a.pte_low == b.pte_low && a.pte_high == b.pte_high;
++}
++
++#define pte_page(x) pfn_to_page(pte_pfn(x))
++
++static inline int pte_none(pte_t pte)
++{
++ return !pte.pte_low && !pte.pte_high;
++}
++
++#define pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) |\
++ (((_pte).pte_high & 0xfff) << (32-PAGE_SHIFT)))
++#define pte_pfn(_pte) mfn_to_local_pfn(pte_mfn(_pte))
++
++extern unsigned long long __supported_pte_mask;
++
++static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
++{
++ return pfn_pte_ma(pfn_to_mfn(page_nr), pgprot);
++}
++
++static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
++{
++ BUG(); panic("needs review");
++ return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | \
++ pgprot_val(pgprot)) & __supported_pte_mask);
++}
++
++/*
++ * Bits 0, 6 and 7 are taken in the low part of the pte,
++ * put the 32 bits of offset into the high part.
++ */
++#define pte_to_pgoff(pte) ((pte).pte_high)
++#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) })
++#define PTE_FILE_MAX_BITS 32
++
++/* Encode and de-code a swap entry */
++#define __swp_type(x) (((x).val) & 0x1f)
++#define __swp_offset(x) ((x).val >> 5)
++#define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) << 5})
++#define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high })
++#define __swp_entry_to_pte(x) ((pte_t){ 0, (x).val })
++
++#define __pmd_free_tlb(tlb, x) do { } while (0)
++
++#define vmalloc_sync_all() ((void)0)
++
++#endif /* _I386_PGTABLE_3LEVEL_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/pgtable.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/pgtable.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,508 @@
++#ifndef _I386_PGTABLE_H
++#define _I386_PGTABLE_H
++
++#include <asm/hypervisor.h>
++
++/*
++ * The Linux memory management assumes a three-level page table setup. On
++ * the i386, we use that, but "fold" the mid level into the top-level page
++ * table, so that we physically have the same two-level page table as the
++ * i386 mmu expects.
++ *
++ * This file contains the functions and defines necessary to modify and use
++ * the i386 page table tree.
++ */
++#ifndef __ASSEMBLY__
++#include <asm/processor.h>
++#include <asm/fixmap.h>
++#include <linux/threads.h>
++
++#ifndef _I386_BITOPS_H
++#include <asm/bitops.h>
++#endif
++
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++
++struct mm_struct;
++struct vm_area_struct;
++
++/*
++ * ZERO_PAGE is a global shared page that is always zero: used
++ * for zero-mapped memory areas etc..
++ */
++#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
++extern unsigned long empty_zero_page[1024];
++extern pgd_t *swapper_pg_dir;
++extern kmem_cache_t *pgd_cache;
++extern kmem_cache_t *pmd_cache;
++extern spinlock_t pgd_lock;
++extern struct page *pgd_list;
++
++void pmd_ctor(void *, kmem_cache_t *, unsigned long);
++void pgd_ctor(void *, kmem_cache_t *, unsigned long);
++void pgd_dtor(void *, kmem_cache_t *, unsigned long);
++void pgtable_cache_init(void);
++void paging_init(void);
++
++/*
++ * The Linux x86 paging architecture is 'compile-time dual-mode', it
++ * implements both the traditional 2-level x86 page tables and the
++ * newer 3-level PAE-mode page tables.
++ */
++#ifdef CONFIG_X86_PAE
++# include <asm/pgtable-3level-defs.h>
++# define PMD_SIZE (1UL << PMD_SHIFT)
++# define PMD_MASK (~(PMD_SIZE-1))
++#else
++# include <asm/pgtable-2level-defs.h>
++#endif
++
++#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
++#define PGDIR_MASK (~(PGDIR_SIZE-1))
++
++#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
++#define FIRST_USER_ADDRESS 0
++
++#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
++#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
++
++#define TWOLEVEL_PGDIR_SHIFT 22
++#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
++#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
++
++/* Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8MB value just means that there will be a 8MB "hole" after the
++ * physical memory until the kernel virtual memory starts. That means that
++ * any out-of-bounds memory accesses will hopefully be caught.
++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
++ * area for the same reason. ;)
++ */
++#define VMALLOC_OFFSET (8*1024*1024)
++#define VMALLOC_START (((unsigned long) high_memory + vmalloc_earlyreserve + \
++ 2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))
++#ifdef CONFIG_HIGHMEM
++# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
++#else
++# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
++#endif
++
++/*
++ * _PAGE_PSE set in the page directory entry just means that
++ * the page directory entry points directly to a 4MB-aligned block of
++ * memory.
++ */
++#define _PAGE_BIT_PRESENT 0
++#define _PAGE_BIT_RW 1
++#define _PAGE_BIT_USER 2
++#define _PAGE_BIT_PWT 3
++#define _PAGE_BIT_PCD 4
++#define _PAGE_BIT_ACCESSED 5
++#define _PAGE_BIT_DIRTY 6
++#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page, Pentium+, if present.. */
++#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
++#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
++#define _PAGE_BIT_UNUSED2 10
++#define _PAGE_BIT_UNUSED3 11
++#define _PAGE_BIT_NX 63
++
++#define _PAGE_PRESENT 0x001
++#define _PAGE_RW 0x002
++#define _PAGE_USER 0x004
++#define _PAGE_PWT 0x008
++#define _PAGE_PCD 0x010
++#define _PAGE_ACCESSED 0x020
++#define _PAGE_DIRTY 0x040
++#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */
++#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */
++#define _PAGE_UNUSED1 0x200 /* available for programmer */
++#define _PAGE_UNUSED2 0x400
++#define _PAGE_UNUSED3 0x800
++
++/* If _PAGE_PRESENT is clear, we use these: */
++#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */
++#define _PAGE_PROTNONE 0x080 /* if the user mapped it with PROT_NONE;
++ pte_present gives true */
++#ifdef CONFIG_X86_PAE
++#define _PAGE_NX (1ULL<<_PAGE_BIT_NX)
++#else
++#define _PAGE_NX 0
++#endif
++
++#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++
++#define PAGE_NONE \
++ __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
++#define PAGE_SHARED \
++ __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
++
++#define PAGE_SHARED_EXEC \
++ __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_COPY_NOEXEC \
++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
++#define PAGE_COPY_EXEC \
++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_COPY \
++ PAGE_COPY_NOEXEC
++#define PAGE_READONLY \
++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
++#define PAGE_READONLY_EXEC \
++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++
++#define _PAGE_KERNEL \
++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
++#define _PAGE_KERNEL_EXEC \
++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
++
++extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
++#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
++#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)
++#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
++#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
++
++#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
++#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
++#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
++#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)
++#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
++#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)
++
++/*
++ * The i386 can't do page protection for execute, and considers that
++ * the same are read. Also, write permissions imply read permissions.
++ * This is the closest we can get..
++ */
++#define __P000 PAGE_NONE
++#define __P001 PAGE_READONLY
++#define __P010 PAGE_COPY
++#define __P011 PAGE_COPY
++#define __P100 PAGE_READONLY_EXEC
++#define __P101 PAGE_READONLY_EXEC
++#define __P110 PAGE_COPY_EXEC
++#define __P111 PAGE_COPY_EXEC
++
++#define __S000 PAGE_NONE
++#define __S001 PAGE_READONLY
++#define __S010 PAGE_SHARED
++#define __S011 PAGE_SHARED
++#define __S100 PAGE_READONLY_EXEC
++#define __S101 PAGE_READONLY_EXEC
++#define __S110 PAGE_SHARED_EXEC
++#define __S111 PAGE_SHARED_EXEC
++
++/*
++ * Define this if things work differently on an i386 and an i486:
++ * it will (on an i486) warn about kernel memory accesses that are
++ * done without a 'access_ok(VERIFY_WRITE,..)'
++ */
++#undef TEST_ACCESS_OK
++
++/* The boot page tables (all created as a single array) */
++extern unsigned long pg0[];
++
++#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
++
++/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */
++#define pmd_none(x) (!(unsigned long)pmd_val(x))
++/* pmd_present doesn't just test the _PAGE_PRESENT bit since wr.p.t.
++ can temporarily clear it. */
++#define pmd_present(x) (pmd_val(x))
++#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & ~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT))
++
++
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++
++/*
++ * The following only work if pte_present() is true.
++ * Undefined behaviour if not..
++ */
++static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
++static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
++static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
++static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
++static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
++static inline int pte_huge(pte_t pte) { return (pte).pte_low & _PAGE_PSE; }
++
++/*
++ * The following only works if pte_present() is not true.
++ */
++static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; }
++
++static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
++static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
++static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
++static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
++static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; }
++static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
++static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
++static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
++static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
++static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
++static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return pte; }
++
++#ifdef CONFIG_X86_PAE
++# include <asm/pgtable-3level.h>
++#else
++# include <asm/pgtable-2level.h>
++#endif
++
++static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
++{
++ if (!pte_dirty(*ptep))
++ return 0;
++ return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
++}
++
++static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
++{
++ if (!pte_young(*ptep))
++ return 0;
++ return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
++}
++
++static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
++{
++ pte_t pte;
++ if (full) {
++ pte = *ptep;
++ pte_clear(mm, addr, ptep);
++ } else {
++ pte = ptep_get_and_clear(mm, addr, ptep);
++ }
++ return pte;
++}
++
++static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
++{
++ if (pte_write(*ptep))
++ clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
++}
++
++/*
++ * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
++ *
++ * dst - pointer to pgd range anwhere on a pgd page
++ * src - ""
++ * count - the number of pgds to copy.
++ *
++ * dst and src can be on the same page, but the range must not overlap,
++ * and must not cross a page boundary.
++ */
++static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
++{
++ memcpy(dst, src, count * sizeof(pgd_t));
++}
++
++/*
++ * Macro to mark a page protection value as "uncacheable". On processors which do not support
++ * it, this is a no-op.
++ */
++#define pgprot_noncached(prot) ((boot_cpu_data.x86 > 3) \
++ ? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) : (prot))
++
++/*
++ * 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 mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
++
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++ pte.pte_low &= _PAGE_CHG_MASK;
++ pte.pte_low |= pgprot_val(newprot);
++#ifdef CONFIG_X86_PAE
++ /*
++ * Chop off the NX bit (if present), and add the NX portion of
++ * the newprot (if present):
++ */
++ pte.pte_high &= ~(1 << (_PAGE_BIT_NX - 32));
++ pte.pte_high |= (pgprot_val(newprot) >> 32) & \
++ (__supported_pte_mask >> 32);
++#endif
++ return pte;
++}
++
++#define pmd_large(pmd) \
++((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT))
++
++/*
++ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
++ *
++ * this macro returns the index of the entry in the pgd page which would
++ * control the given virtual address
++ */
++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define pgd_index_k(addr) pgd_index(addr)
++
++/*
++ * pgd_offset() returns a (pgd_t *)
++ * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
++ */
++#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
++
++/*
++ * a shortcut which implies the use of the kernel's pgd, instead
++ * of a process's
++ */
++#define pgd_offset_k(address) pgd_offset(&init_mm, address)
++
++/*
++ * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
++ *
++ * this macro returns the index of the entry in the pmd page which would
++ * control the given virtual address
++ */
++#define pmd_index(address) \
++ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
++
++/*
++ * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
++ *
++ * this macro returns the index of the entry in the pte page which would
++ * control the given virtual address
++ */
++#define pte_index(address) \
++ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
++#define pte_offset_kernel(dir, address) \
++ ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
++
++#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
++
++#define pmd_page_kernel(pmd) \
++ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++
++/*
++ * Helper function that returns the kernel pagetable entry controlling
++ * the virtual address 'address'. NULL means no pagetable entry present.
++ * NOTE: the return type is pte_t but if the pmd is PSE then we return it
++ * as a pte too.
++ */
++extern pte_t *lookup_address(unsigned long address);
++
++/*
++ * Make a given kernel text page executable/non-executable.
++ * Returns the previous executability setting of that page (which
++ * is used to restore the previous state). Used by the SMP bootup code.
++ * NOTE: this is an __init function for security reasons.
++ */
++#ifdef CONFIG_X86_PAE
++ extern int set_kernel_exec(unsigned long vaddr, int enable);
++#else
++ static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;}
++#endif
++
++extern void noexec_setup(const char *str);
++
++#if defined(CONFIG_HIGHPTE)
++#define pte_offset_map(dir, address) \
++ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + \
++ pte_index(address))
++#define pte_offset_map_nested(dir, address) \
++ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + \
++ pte_index(address))
++#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
++#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
++#else
++#define pte_offset_map(dir, address) \
++ ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
++#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
++#define pte_unmap(pte) do { } while (0)
++#define pte_unmap_nested(pte) do { } while (0)
++#endif
++
++/*
++ * The i386 doesn't have any external MMU info: the kernel page
++ * tables contain all the necessary information.
++ *
++ * Also, we only update the dirty/accessed state if we set
++ * the dirty bit by hand in the kernel, since the hardware
++ * will do the accessed bit for us, and we don't want to
++ * race with other CPU's that might be updating the dirty
++ * bit at the same time.
++ */
++#define update_mmu_cache(vma,address,pte) do { } while (0)
++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
++#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
++ do { \
++ if (__dirty) { \
++ if ( likely((__vma)->vm_mm == current->mm) ) { \
++ BUG_ON(HYPERVISOR_update_va_mapping((__address), (__entry), UVMF_INVLPG|UVMF_MULTI|(unsigned long)((__vma)->vm_mm->cpu_vm_mask.bits))); \
++ } else { \
++ xen_l1_entry_update((__ptep), (__entry)); \
++ flush_tlb_page((__vma), (__address)); \
++ } \
++ } \
++ } while (0)
++
++#define __HAVE_ARCH_PTEP_ESTABLISH
++#define ptep_establish(__vma, __address, __ptep, __entry) \
++do { \
++ ptep_set_access_flags(__vma, __address, __ptep, __entry, 1); \
++} while (0)
++
++#include <xen/features.h>
++void make_lowmem_page_readonly(void *va, unsigned int feature);
++void make_lowmem_page_writable(void *va, unsigned int feature);
++void make_page_readonly(void *va, unsigned int feature);
++void make_page_writable(void *va, unsigned int feature);
++void make_pages_readonly(void *va, unsigned int nr, unsigned int feature);
++void make_pages_writable(void *va, unsigned int nr, unsigned int feature);
++
++#define virt_to_ptep(__va) \
++({ \
++ pgd_t *__pgd = pgd_offset_k((unsigned long)(__va)); \
++ pud_t *__pud = pud_offset(__pgd, (unsigned long)(__va)); \
++ pmd_t *__pmd = pmd_offset(__pud, (unsigned long)(__va)); \
++ pte_offset_kernel(__pmd, (unsigned long)(__va)); \
++})
++
++#define arbitrary_virt_to_machine(__va) \
++({ \
++ maddr_t m = (maddr_t)pte_mfn(*virt_to_ptep(__va)) << PAGE_SHIFT;\
++ m | ((unsigned long)(__va) & (PAGE_SIZE-1)); \
++})
++
++#endif /* !__ASSEMBLY__ */
++
++#ifdef CONFIG_FLATMEM
++#define kern_addr_valid(addr) (1)
++#endif /* CONFIG_FLATMEM */
++
++int direct_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid);
++int direct_kernel_remap_pfn_range(unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid);
++int create_lookup_pte_addr(struct mm_struct *mm,
++ unsigned long address,
++ uint64_t *ptep);
++int touch_pte_range(struct mm_struct *mm,
++ unsigned long address,
++ unsigned long size);
++
++#define io_remap_pfn_range(vma,from,pfn,size,prot) \
++direct_remap_pfn_range(vma,from,pfn,size,prot,DOMID_IO)
++
++#define MK_IOSPACE_PFN(space, pfn) (pfn)
++#define GET_IOSPACE(pfn) 0
++#define GET_PFN(pfn) (pfn)
++
++#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_GET_AND_CLEAR_FULL
++#define __HAVE_ARCH_PTEP_SET_WRPROTECT
++#define __HAVE_ARCH_PTE_SAME
++#include <asm-generic/pgtable.h>
++
++#endif /* _I386_PGTABLE_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/processor.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/processor.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/processor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/processor.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,741 @@
++/*
++ * include/asm-i386/processor.h
++ *
++ * Copyright (C) 1994 Linus Torvalds
++ */
++
++#ifndef __ASM_I386_PROCESSOR_H
++#define __ASM_I386_PROCESSOR_H
++
++#include <asm/vm86.h>
++#include <asm/math_emu.h>
++#include <asm/segment.h>
++#include <asm/page.h>
++#include <asm/types.h>
++#include <asm/sigcontext.h>
++#include <asm/cpufeature.h>
++#include <asm/msr.h>
++#include <asm/system.h>
++#include <linux/cache.h>
++#include <linux/threads.h>
++#include <asm/percpu.h>
++#include <linux/cpumask.h>
++#include <xen/interface/physdev.h>
++
++/* flag for disabling the tsc */
++extern int tsc_disable;
++
++struct desc_struct {
++ unsigned long a,b;
++};
++
++#define desc_empty(desc) \
++ (!((desc)->a | (desc)->b))
++
++#define desc_equal(desc1, desc2) \
++ (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
++/*
++ * Default implementation of macro that returns current
++ * instruction pointer ("program counter").
++ */
++#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
++
++/*
++ * CPU type and hardware bug flags. Kept separately for each CPU.
++ * Members of this structure are referenced in head.S, so think twice
++ * before touching them. [mj]
++ */
++
++struct cpuinfo_x86 {
++ __u8 x86; /* CPU family */
++ __u8 x86_vendor; /* CPU vendor */
++ __u8 x86_model;
++ __u8 x86_mask;
++ char wp_works_ok; /* It doesn't on 386's */
++ char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
++ char hard_math;
++ char rfu;
++ int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
++ unsigned long x86_capability[NCAPINTS];
++ char x86_vendor_id[16];
++ char x86_model_id[64];
++ int x86_cache_size; /* in KB - valid for CPUS which support this
++ call */
++ int x86_cache_alignment; /* In bytes */
++ char fdiv_bug;
++ char f00f_bug;
++ char coma_bug;
++ char pad0;
++ int x86_power;
++ unsigned long loops_per_jiffy;
++#ifdef CONFIG_SMP
++ cpumask_t llc_shared_map; /* cpus sharing the last level cache */
++#endif
++ unsigned char x86_max_cores; /* cpuid returned max cores value */
++ unsigned char apicid;
++#ifdef CONFIG_SMP
++ unsigned char booted_cores; /* number of cores as seen by OS */
++ __u8 phys_proc_id; /* Physical processor id. */
++ __u8 cpu_core_id; /* Core id */
++#endif
++} __attribute__((__aligned__(SMP_CACHE_BYTES)));
++
++#define X86_VENDOR_INTEL 0
++#define X86_VENDOR_CYRIX 1
++#define X86_VENDOR_AMD 2
++#define X86_VENDOR_UMC 3
++#define X86_VENDOR_NEXGEN 4
++#define X86_VENDOR_CENTAUR 5
++#define X86_VENDOR_RISE 6
++#define X86_VENDOR_TRANSMETA 7
++#define X86_VENDOR_NSC 8
++#define X86_VENDOR_NUM 9
++#define X86_VENDOR_UNKNOWN 0xff
++
++/*
++ * capabilities of CPUs
++ */
++
++extern struct cpuinfo_x86 boot_cpu_data;
++extern struct cpuinfo_x86 new_cpu_data;
++#ifndef CONFIG_X86_NO_TSS
++extern struct tss_struct doublefault_tss;
++DECLARE_PER_CPU(struct tss_struct, init_tss);
++#endif
++
++#ifdef CONFIG_SMP
++extern struct cpuinfo_x86 cpu_data[];
++#define current_cpu_data cpu_data[smp_processor_id()]
++#else
++#define cpu_data (&boot_cpu_data)
++#define current_cpu_data boot_cpu_data
++#endif
++
++extern int cpu_llc_id[NR_CPUS];
++extern char ignore_fpu_irq;
++
++extern void identify_cpu(struct cpuinfo_x86 *);
++extern void print_cpu_info(struct cpuinfo_x86 *);
++extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
++extern unsigned short num_cache_leaves;
++
++#ifdef CONFIG_X86_HT
++extern void detect_ht(struct cpuinfo_x86 *c);
++#else
++static inline void detect_ht(struct cpuinfo_x86 *c) {}
++#endif
++
++/*
++ * EFLAGS bits
++ */
++#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
++#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
++#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
++#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
++#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
++#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
++#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
++#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
++#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
++#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
++#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
++#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
++#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
++#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
++#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
++#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
++#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
++
++/*
++ * Generic CPUID function
++ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
++ * resulting in stale register contents being returned.
++ */
++static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
++{
++ __asm__(XEN_CPUID
++ : "=a" (*eax),
++ "=b" (*ebx),
++ "=c" (*ecx),
++ "=d" (*edx)
++ : "0" (op), "c"(0));
++}
++
++/* Some CPUID calls want 'count' to be placed in ecx */
++static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
++ int *edx)
++{
++ __asm__(XEN_CPUID
++ : "=a" (*eax),
++ "=b" (*ebx),
++ "=c" (*ecx),
++ "=d" (*edx)
++ : "0" (op), "c" (count));
++}
++
++/*
++ * CPUID functions returning a single datum
++ */
++static inline unsigned int cpuid_eax(unsigned int op)
++{
++ unsigned int eax;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax)
++ : "0" (op)
++ : "bx", "cx", "dx");
++ return eax;
++}
++static inline unsigned int cpuid_ebx(unsigned int op)
++{
++ unsigned int eax, ebx;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax), "=b" (ebx)
++ : "0" (op)
++ : "cx", "dx" );
++ return ebx;
++}
++static inline unsigned int cpuid_ecx(unsigned int op)
++{
++ unsigned int eax, ecx;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax), "=c" (ecx)
++ : "0" (op)
++ : "bx", "dx" );
++ return ecx;
++}
++static inline unsigned int cpuid_edx(unsigned int op)
++{
++ unsigned int eax, edx;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax), "=d" (edx)
++ : "0" (op)
++ : "bx", "cx");
++ return edx;
++}
++
++#define load_cr3(pgdir) write_cr3(__pa(pgdir))
++
++/*
++ * Intel CPU features in CR4
++ */
++#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
++#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
++#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
++#define X86_CR4_DE 0x0008 /* enable debugging extensions */
++#define X86_CR4_PSE 0x0010 /* enable page size extensions */
++#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
++#define X86_CR4_MCE 0x0040 /* Machine check enable */
++#define X86_CR4_PGE 0x0080 /* enable global pages */
++#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
++#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
++#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
++
++/*
++ * Save the cr4 feature set we're using (ie
++ * Pentium 4MB enable and PPro Global page
++ * enable), so that any CPU's that boot up
++ * after us can get the correct flags.
++ */
++extern unsigned long mmu_cr4_features;
++
++static inline void set_in_cr4 (unsigned long mask)
++{
++ unsigned cr4;
++ mmu_cr4_features |= mask;
++ cr4 = read_cr4();
++ cr4 |= mask;
++ write_cr4(cr4);
++}
++
++static inline void clear_in_cr4 (unsigned long mask)
++{
++ unsigned cr4;
++ mmu_cr4_features &= ~mask;
++ cr4 = read_cr4();
++ cr4 &= ~mask;
++ write_cr4(cr4);
++}
++
++/*
++ * NSC/Cyrix CPU configuration register indexes
++ */
++
++#define CX86_PCR0 0x20
++#define CX86_GCR 0xb8
++#define CX86_CCR0 0xc0
++#define CX86_CCR1 0xc1
++#define CX86_CCR2 0xc2
++#define CX86_CCR3 0xc3
++#define CX86_CCR4 0xe8
++#define CX86_CCR5 0xe9
++#define CX86_CCR6 0xea
++#define CX86_CCR7 0xeb
++#define CX86_PCR1 0xf0
++#define CX86_DIR0 0xfe
++#define CX86_DIR1 0xff
++#define CX86_ARR_BASE 0xc4
++#define CX86_RCR_BASE 0xdc
++
++/*
++ * NSC/Cyrix CPU indexed register access macros
++ */
++
++#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
++
++#define setCx86(reg, data) do { \
++ outb((reg), 0x22); \
++ outb((data), 0x23); \
++} while (0)
++
++/* Stop speculative execution */
++static inline void sync_core(void)
++{
++ int tmp;
++ asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
++}
++
++static inline void __monitor(const void *eax, unsigned long ecx,
++ unsigned long edx)
++{
++ /* "monitor %eax,%ecx,%edx;" */
++ asm volatile(
++ ".byte 0x0f,0x01,0xc8;"
++ : :"a" (eax), "c" (ecx), "d"(edx));
++}
++
++static inline void __mwait(unsigned long eax, unsigned long ecx)
++{
++ /* "mwait %eax,%ecx;" */
++ asm volatile(
++ ".byte 0x0f,0x01,0xc9;"
++ : :"a" (eax), "c" (ecx));
++}
++
++/* from system description table in BIOS. Mostly for MCA use, but
++others may find it useful. */
++extern unsigned int machine_id;
++extern unsigned int machine_submodel_id;
++extern unsigned int BIOS_revision;
++extern unsigned int mca_pentium_flag;
++
++/* Boot loader type from the setup header */
++extern int bootloader_type;
++
++/*
++ * User space process size: 3GB (default).
++ */
++#define TASK_SIZE (PAGE_OFFSET)
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
++
++#define HAVE_ARCH_PICK_MMAP_LAYOUT
++
++/*
++ * Size of io_bitmap.
++ */
++#define IO_BITMAP_BITS 65536
++#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8)
++#define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long))
++#ifndef CONFIG_X86_NO_TSS
++#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
++#endif
++#define INVALID_IO_BITMAP_OFFSET 0x8000
++#define INVALID_IO_BITMAP_OFFSET_LAZY 0x9000
++
++struct i387_fsave_struct {
++ long cwd;
++ long swd;
++ long twd;
++ long fip;
++ long fcs;
++ long foo;
++ long fos;
++ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
++ long status; /* software status information */
++};
++
++struct i387_fxsave_struct {
++ unsigned short cwd;
++ unsigned short swd;
++ unsigned short twd;
++ unsigned short fop;
++ long fip;
++ long fcs;
++ long foo;
++ long fos;
++ long mxcsr;
++ long mxcsr_mask;
++ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
++ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
++ long padding[56];
++} __attribute__ ((aligned (16)));
++
++struct i387_soft_struct {
++ long cwd;
++ long swd;
++ long twd;
++ long fip;
++ long fcs;
++ long foo;
++ long fos;
++ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
++ unsigned char ftop, changed, lookahead, no_update, rm, alimit;
++ struct info *info;
++ unsigned long entry_eip;
++};
++
++union i387_union {
++ struct i387_fsave_struct fsave;
++ struct i387_fxsave_struct fxsave;
++ struct i387_soft_struct soft;
++};
++
++typedef struct {
++ unsigned long seg;
++} mm_segment_t;
++
++struct thread_struct;
++
++#ifndef CONFIG_X86_NO_TSS
++struct tss_struct {
++ unsigned short back_link,__blh;
++ unsigned long esp0;
++ unsigned short ss0,__ss0h;
++ unsigned long esp1;
++ unsigned short ss1,__ss1h; /* ss1 is used to cache MSR_IA32_SYSENTER_CS */
++ unsigned long esp2;
++ unsigned short ss2,__ss2h;
++ unsigned long __cr3;
++ unsigned long eip;
++ unsigned long eflags;
++ unsigned long eax,ecx,edx,ebx;
++ unsigned long esp;
++ unsigned long ebp;
++ unsigned long esi;
++ unsigned long edi;
++ unsigned short es, __esh;
++ unsigned short cs, __csh;
++ unsigned short ss, __ssh;
++ unsigned short ds, __dsh;
++ unsigned short fs, __fsh;
++ unsigned short gs, __gsh;
++ unsigned short ldt, __ldth;
++ unsigned short trace, io_bitmap_base;
++ /*
++ * The extra 1 is there because the CPU will access an
++ * additional byte beyond the end of the IO permission
++ * bitmap. The extra byte must be all 1 bits, and must
++ * be within the limit.
++ */
++ unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
++ /*
++ * Cache the current maximum and the last task that used the bitmap:
++ */
++ unsigned long io_bitmap_max;
++ struct thread_struct *io_bitmap_owner;
++ /*
++ * pads the TSS to be cacheline-aligned (size is 0x100)
++ */
++ unsigned long __cacheline_filler[35];
++ /*
++ * .. and then another 0x100 bytes for emergency kernel stack
++ */
++ unsigned long stack[64];
++} __attribute__((packed));
++#endif
++
++#define ARCH_MIN_TASKALIGN 16
++
++struct thread_struct {
++/* cached TLS descriptors. */
++ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
++ unsigned long esp0;
++ unsigned long sysenter_cs;
++ unsigned long eip;
++ unsigned long esp;
++ unsigned long fs;
++ unsigned long gs;
++/* Hardware debugging registers */
++ unsigned long debugreg[8]; /* %%db0-7 debug registers */
++/* fault info */
++ unsigned long cr2, trap_no, error_code;
++/* floating point info */
++ union i387_union i387;
++/* virtual 86 mode info */
++ struct vm86_struct __user * vm86_info;
++ unsigned long screen_bitmap;
++ unsigned long v86flags, v86mask, saved_esp0;
++ unsigned int saved_fs, saved_gs;
++/* IO permissions */
++ unsigned long *io_bitmap_ptr;
++ unsigned long iopl;
++/* max allowed port in the bitmap, in bytes: */
++ unsigned long io_bitmap_max;
++};
++
++#define INIT_THREAD { \
++ .vm86_info = NULL, \
++ .sysenter_cs = __KERNEL_CS, \
++ .io_bitmap_ptr = NULL, \
++}
++
++#ifndef CONFIG_X86_NO_TSS
++/*
++ * Note that the .io_bitmap member must be extra-big. This is because
++ * the CPU will access an additional byte beyond the end of the IO
++ * permission bitmap. The extra byte must be all 1 bits, and must
++ * be within the limit.
++ */
++#define INIT_TSS { \
++ .esp0 = sizeof(init_stack) + (long)&init_stack, \
++ .ss0 = __KERNEL_DS, \
++ .ss1 = __KERNEL_CS, \
++ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \
++ .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \
++}
++
++static inline void __load_esp0(struct tss_struct *tss, struct thread_struct *thread)
++{
++ tss->esp0 = thread->esp0;
++ /* This can only happen when SEP is enabled, no need to test "SEP"arately */
++ if (unlikely(tss->ss1 != thread->sysenter_cs)) {
++ tss->ss1 = thread->sysenter_cs;
++ wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
++ }
++}
++#define load_esp0(tss, thread) \
++ __load_esp0(tss, thread)
++#else
++#define load_esp0(tss, thread) \
++ HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0)
++#endif
++
++#define start_thread(regs, new_eip, new_esp) do { \
++ __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
++ set_fs(USER_DS); \
++ regs->xds = __USER_DS; \
++ regs->xes = __USER_DS; \
++ regs->xss = __USER_DS; \
++ regs->xcs = __USER_CS; \
++ regs->eip = new_eip; \
++ regs->esp = new_esp; \
++} while (0)
++
++/*
++ * These special macros can be used to get or set a debugging register
++ */
++#define get_debugreg(var, register) \
++ (var) = HYPERVISOR_get_debugreg((register))
++#define set_debugreg(value, register) \
++ HYPERVISOR_set_debugreg((register), (value))
++
++/*
++ * Set IOPL bits in EFLAGS from given mask
++ */
++static inline void set_iopl_mask(unsigned mask)
++{
++ struct physdev_set_iopl set_iopl;
++
++ /* Force the change at ring 0. */
++ set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++}
++
++/* Forward declaration, a strange C thing */
++struct task_struct;
++struct mm_struct;
++
++/* Free all resources held by a thread. */
++extern void release_thread(struct task_struct *);
++
++/* Prepare to copy thread state - unlazy all lazy status */
++extern void prepare_to_copy(struct task_struct *tsk);
++
++/*
++ * create a kernel thread without removing it from tasklists
++ */
++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
++
++extern unsigned long thread_saved_pc(struct task_struct *tsk);
++void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack);
++
++unsigned long get_wchan(struct task_struct *p);
++
++#define THREAD_SIZE_LONGS (THREAD_SIZE/sizeof(unsigned long))
++#define KSTK_TOP(info) \
++({ \
++ unsigned long *__ptr = (unsigned long *)(info); \
++ (unsigned long)(&__ptr[THREAD_SIZE_LONGS]); \
++})
++
++/*
++ * The below -8 is to reserve 8 bytes on top of the ring0 stack.
++ * This is necessary to guarantee that the entire "struct pt_regs"
++ * is accessable even if the CPU haven't stored the SS/ESP registers
++ * on the stack (interrupt gate does not save these registers
++ * when switching to the same priv ring).
++ * Therefore beware: accessing the xss/esp fields of the
++ * "struct pt_regs" is possible, but they may contain the
++ * completely wrong values.
++ */
++#define task_pt_regs(task) \
++({ \
++ struct pt_regs *__regs__; \
++ __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \
++ __regs__ - 1; \
++})
++
++#define KSTK_EIP(task) (task_pt_regs(task)->eip)
++#define KSTK_ESP(task) (task_pt_regs(task)->esp)
++
++
++struct microcode_header {
++ unsigned int hdrver;
++ unsigned int rev;
++ unsigned int date;
++ unsigned int sig;
++ unsigned int cksum;
++ unsigned int ldrver;
++ unsigned int pf;
++ unsigned int datasize;
++ unsigned int totalsize;
++ unsigned int reserved[3];
++};
++
++struct microcode {
++ struct microcode_header hdr;
++ unsigned int bits[0];
++};
++
++typedef struct microcode microcode_t;
++typedef struct microcode_header microcode_header_t;
++
++/* microcode format is extended from prescott processors */
++struct extended_signature {
++ unsigned int sig;
++ unsigned int pf;
++ unsigned int cksum;
++};
++
++struct extended_sigtable {
++ unsigned int count;
++ unsigned int cksum;
++ unsigned int reserved[3];
++ struct extended_signature sigs[0];
++};
++
++/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
++static inline void rep_nop(void)
++{
++ __asm__ __volatile__("rep;nop": : :"memory");
++}
++
++#define cpu_relax() rep_nop()
++
++/* generic versions from gas */
++#define GENERIC_NOP1 ".byte 0x90\n"
++#define GENERIC_NOP2 ".byte 0x89,0xf6\n"
++#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n"
++#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n"
++#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4
++#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
++#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
++#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7
++
++/* Opteron nops */
++#define K8_NOP1 GENERIC_NOP1
++#define K8_NOP2 ".byte 0x66,0x90\n"
++#define K8_NOP3 ".byte 0x66,0x66,0x90\n"
++#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n"
++#define K8_NOP5 K8_NOP3 K8_NOP2
++#define K8_NOP6 K8_NOP3 K8_NOP3
++#define K8_NOP7 K8_NOP4 K8_NOP3
++#define K8_NOP8 K8_NOP4 K8_NOP4
++
++/* K7 nops */
++/* uses eax dependencies (arbitary choice) */
++#define K7_NOP1 GENERIC_NOP1
++#define K7_NOP2 ".byte 0x8b,0xc0\n"
++#define K7_NOP3 ".byte 0x8d,0x04,0x20\n"
++#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n"
++#define K7_NOP5 K7_NOP4 ASM_NOP1
++#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n"
++#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n"
++#define K7_NOP8 K7_NOP7 ASM_NOP1
++
++#ifdef CONFIG_MK8
++#define ASM_NOP1 K8_NOP1
++#define ASM_NOP2 K8_NOP2
++#define ASM_NOP3 K8_NOP3
++#define ASM_NOP4 K8_NOP4
++#define ASM_NOP5 K8_NOP5
++#define ASM_NOP6 K8_NOP6
++#define ASM_NOP7 K8_NOP7
++#define ASM_NOP8 K8_NOP8
++#elif defined(CONFIG_MK7)
++#define ASM_NOP1 K7_NOP1
++#define ASM_NOP2 K7_NOP2
++#define ASM_NOP3 K7_NOP3
++#define ASM_NOP4 K7_NOP4
++#define ASM_NOP5 K7_NOP5
++#define ASM_NOP6 K7_NOP6
++#define ASM_NOP7 K7_NOP7
++#define ASM_NOP8 K7_NOP8
++#else
++#define ASM_NOP1 GENERIC_NOP1
++#define ASM_NOP2 GENERIC_NOP2
++#define ASM_NOP3 GENERIC_NOP3
++#define ASM_NOP4 GENERIC_NOP4
++#define ASM_NOP5 GENERIC_NOP5
++#define ASM_NOP6 GENERIC_NOP6
++#define ASM_NOP7 GENERIC_NOP7
++#define ASM_NOP8 GENERIC_NOP8
++#endif
++
++#define ASM_NOP_MAX 8
++
++/* Prefetch instructions for Pentium III and AMD Athlon */
++/* It's not worth to care about 3dnow! prefetches for the K6
++ because they are microcoded there and very slow.
++ However we don't do prefetches for pre XP Athlons currently
++ That should be fixed. */
++#define ARCH_HAS_PREFETCH
++static inline void prefetch(const void *x)
++{
++ alternative_input(ASM_NOP4,
++ "prefetchnta (%1)",
++ X86_FEATURE_XMM,
++ "r" (x));
++}
++
++#define ARCH_HAS_PREFETCH
++#define ARCH_HAS_PREFETCHW
++#define ARCH_HAS_SPINLOCK_PREFETCH
++
++/* 3dnow! prefetch to get an exclusive cache line. Useful for
++ spinlocks to avoid one state transition in the cache coherency protocol. */
++static inline void prefetchw(const void *x)
++{
++ alternative_input(ASM_NOP4,
++ "prefetchw (%1)",
++ X86_FEATURE_3DNOW,
++ "r" (x));
++}
++#define spin_lock_prefetch(x) prefetchw(x)
++
++extern void select_idle_routine(const struct cpuinfo_x86 *c);
++
++#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
++
++extern unsigned long boot_option_idle_override;
++extern void enable_sep_cpu(void);
++extern int sysenter_setup(void);
++
++#endif /* __ASM_I386_PROCESSOR_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/ptrace.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/ptrace.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/ptrace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/ptrace.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,90 @@
++#ifndef _I386_PTRACE_H
++#define _I386_PTRACE_H
++
++#define EBX 0
++#define ECX 1
++#define EDX 2
++#define ESI 3
++#define EDI 4
++#define EBP 5
++#define EAX 6
++#define DS 7
++#define ES 8
++#define FS 9
++#define GS 10
++#define ORIG_EAX 11
++#define EIP 12
++#define CS 13
++#define EFL 14
++#define UESP 15
++#define SS 16
++#define FRAME_SIZE 17
++
++/* this struct defines the way the registers are stored on the
++ stack during a system call. */
++
++struct pt_regs {
++ long ebx;
++ long ecx;
++ long edx;
++ long esi;
++ long edi;
++ long ebp;
++ long eax;
++ int xds;
++ int xes;
++ long orig_eax;
++ long eip;
++ int xcs;
++ long eflags;
++ long esp;
++ int xss;
++};
++
++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
++#define PTRACE_GETREGS 12
++#define PTRACE_SETREGS 13
++#define PTRACE_GETFPREGS 14
++#define PTRACE_SETFPREGS 15
++#define PTRACE_GETFPXREGS 18
++#define PTRACE_SETFPXREGS 19
++
++#define PTRACE_OLDSETOPTIONS 21
++
++#define PTRACE_GET_THREAD_AREA 25
++#define PTRACE_SET_THREAD_AREA 26
++
++#define PTRACE_SYSEMU 31
++#define PTRACE_SYSEMU_SINGLESTEP 32
++
++#ifdef __KERNEL__
++
++#include <asm/vm86.h>
++
++struct task_struct;
++extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
++
++/*
++ * user_mode_vm(regs) determines whether a register set came from user mode.
++ * This is true if V8086 mode was enabled OR if the register set was from
++ * protected mode with RPL-3 CS value. This tricky test checks that with
++ * one comparison. Many places in the kernel can bypass this full check
++ * if they have already ruled out V8086 mode, so user_mode(regs) can be used.
++ */
++static inline int user_mode(struct pt_regs *regs)
++{
++ return (regs->xcs & 2) != 0;
++}
++static inline int user_mode_vm(struct pt_regs *regs)
++{
++ return ((regs->xcs & 2) | (regs->eflags & VM_MASK)) != 0;
++}
++#define instruction_pointer(regs) ((regs)->eip)
++#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
++extern unsigned long profile_pc(struct pt_regs *regs);
++#else
++#define profile_pc(regs) instruction_pointer(regs)
++#endif
++#endif /* __KERNEL__ */
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/scatterlist.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/scatterlist.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/scatterlist.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/scatterlist.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,22 @@
++#ifndef _I386_SCATTERLIST_H
++#define _I386_SCATTERLIST_H
++
++struct scatterlist {
++ struct page *page;
++ unsigned int offset;
++ unsigned int length;
++ dma_addr_t dma_address;
++ unsigned int dma_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.
++ */
++#define sg_dma_address(sg) ((sg)->dma_address)
++#define sg_dma_len(sg) ((sg)->dma_length)
++
++#define ISA_DMA_THRESHOLD (0x00ffffff)
++
++#endif /* !(_I386_SCATTERLIST_H) */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/segment.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/segment.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/segment.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/segment.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,117 @@
++#ifndef _ASM_SEGMENT_H
++#define _ASM_SEGMENT_H
++
++/*
++ * The layout of the per-CPU GDT under Linux:
++ *
++ * 0 - null
++ * 1 - reserved
++ * 2 - reserved
++ * 3 - reserved
++ *
++ * 4 - unused <==== new cacheline
++ * 5 - unused
++ *
++ * ------- start of TLS (Thread-Local Storage) segments:
++ *
++ * 6 - TLS segment #1 [ glibc's TLS segment ]
++ * 7 - TLS segment #2 [ Wine's %fs Win32 segment ]
++ * 8 - TLS segment #3
++ * 9 - reserved
++ * 10 - reserved
++ * 11 - reserved
++ *
++ * ------- start of kernel segments:
++ *
++ * 12 - kernel code segment <==== new cacheline
++ * 13 - kernel data segment
++ * 14 - default user CS
++ * 15 - default user DS
++ * 16 - TSS
++ * 17 - LDT
++ * 18 - PNPBIOS support (16->32 gate)
++ * 19 - PNPBIOS support
++ * 20 - PNPBIOS support
++ * 21 - PNPBIOS support
++ * 22 - PNPBIOS support
++ * 23 - APM BIOS support
++ * 24 - APM BIOS support
++ * 25 - APM BIOS support
++ *
++ * 26 - ESPFIX small SS
++ * 27 - unused
++ * 28 - unused
++ * 29 - unused
++ * 30 - unused
++ * 31 - TSS for double fault handler
++ */
++#define GDT_ENTRY_TLS_ENTRIES 3
++#define GDT_ENTRY_TLS_MIN 6
++#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
++
++#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
++
++#define GDT_ENTRY_DEFAULT_USER_CS 14
++#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)
++
++#define GDT_ENTRY_DEFAULT_USER_DS 15
++#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3)
++
++#define GDT_ENTRY_KERNEL_BASE 12
++
++#define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0)
++#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)
++#define GET_KERNEL_CS() (__KERNEL_CS | (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) )
++
++#define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1)
++#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)
++#define GET_KERNEL_DS() (__KERNEL_DS | (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) )
++
++#define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE + 4)
++#define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE + 5)
++
++#define GDT_ENTRY_PNPBIOS_BASE (GDT_ENTRY_KERNEL_BASE + 6)
++#define GDT_ENTRY_APMBIOS_BASE (GDT_ENTRY_KERNEL_BASE + 11)
++
++#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)
++#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
++
++#define GDT_ENTRY_DOUBLEFAULT_TSS 31
++
++/*
++ * The GDT has 32 entries
++ */
++#define GDT_ENTRIES 32
++
++#define GDT_SIZE (GDT_ENTRIES * 8)
++
++/* Simple and small GDT entries for booting only */
++
++#define GDT_ENTRY_BOOT_CS 2
++#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8)
++
++#define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1)
++#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8)
++
++/* The PnP BIOS entries in the GDT */
++#define GDT_ENTRY_PNPBIOS_CS32 (GDT_ENTRY_PNPBIOS_BASE + 0)
++#define GDT_ENTRY_PNPBIOS_CS16 (GDT_ENTRY_PNPBIOS_BASE + 1)
++#define GDT_ENTRY_PNPBIOS_DS (GDT_ENTRY_PNPBIOS_BASE + 2)
++#define GDT_ENTRY_PNPBIOS_TS1 (GDT_ENTRY_PNPBIOS_BASE + 3)
++#define GDT_ENTRY_PNPBIOS_TS2 (GDT_ENTRY_PNPBIOS_BASE + 4)
++
++/* The PnP BIOS selectors */
++#define PNP_CS32 (GDT_ENTRY_PNPBIOS_CS32 * 8) /* segment for calling fn */
++#define PNP_CS16 (GDT_ENTRY_PNPBIOS_CS16 * 8) /* code segment for BIOS */
++#define PNP_DS (GDT_ENTRY_PNPBIOS_DS * 8) /* data segment for BIOS */
++#define PNP_TS1 (GDT_ENTRY_PNPBIOS_TS1 * 8) /* transfer data segment */
++#define PNP_TS2 (GDT_ENTRY_PNPBIOS_TS2 * 8) /* another data segment */
++
++/*
++ * The interrupt descriptor table has room for 256 idt's,
++ * the global descriptor table is dependent on the number
++ * of tasks we can have..
++ */
++#define IDT_ENTRIES 256
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/setup.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/setup.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/setup.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/setup.h 2006-09-21 01:33:32.000000000 +0200
+@@ -0,0 +1,81 @@
++/*
++ * Just a place holder. We don't want to have to test x86 before
++ * we include stuff
++ */
++
++#ifndef _i386_SETUP_H
++#define _i386_SETUP_H
++
++#ifdef __KERNEL__
++#include <linux/pfn.h>
++
++/*
++ * Reserved space for vmalloc and iomap - defined in asm/page.h
++ */
++#define MAXMEM_PFN PFN_DOWN(MAXMEM)
++#define MAX_NONPAE_PFN (1 << 20)
++#endif
++
++#define PARAM_SIZE 4096
++#define COMMAND_LINE_SIZE 256
++
++#define OLD_CL_MAGIC_ADDR 0x90020
++#define OLD_CL_MAGIC 0xA33F
++#define OLD_CL_BASE_ADDR 0x90000
++#define OLD_CL_OFFSET 0x90022
++#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
++
++#ifndef __ASSEMBLY__
++/*
++ * This is set up by the setup-routine at boot-time
++ */
++extern unsigned char boot_params[PARAM_SIZE];
++
++#define PARAM (boot_params)
++#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
++#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
++#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
++#define E820_MAP_NR (*(char*) (PARAM+E820NR))
++#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
++#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
++#define IST_INFO (*(struct ist_info *) (PARAM+0x60))
++#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
++#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
++#define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
++#define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
++#define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
++#define EFI_MEMMAP ((void *) *((unsigned long *)(PARAM+0x1d0)))
++#define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4)))
++#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
++#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
++#define VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
++#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
++#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
++#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
++#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
++#define INITRD_START (__pa(xen_start_info->mod_start))
++#define INITRD_SIZE (xen_start_info->mod_len)
++#define EDID_INFO (*(struct edid_info *) (PARAM+0x440))
++#define EDD_NR (*(unsigned char *) (PARAM+EDDNR))
++#define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF))
++#define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
++#define EDD_BUF ((struct edd_info *) (PARAM+EDDBUF))
++
++/*
++ * Do NOT EVER look at the BIOS memory size location.
++ * It does not work on many machines.
++ */
++#define LOWMEMSIZE() (0x9f000)
++
++struct e820entry;
++
++char * __init machine_specific_memory_setup(void);
++
++int __init copy_e820_map(struct e820entry * biosmap, int nr_map);
++int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map);
++void __init add_memory_region(unsigned long long start,
++ unsigned long long size, int type);
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _i386_SETUP_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/smp.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/smp.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/smp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/smp.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,103 @@
++#ifndef __ASM_SMP_H
++#define __ASM_SMP_H
++
++/*
++ * We need the APIC definitions automatically as part of 'smp.h'
++ */
++#ifndef __ASSEMBLY__
++#include <linux/kernel.h>
++#include <linux/threads.h>
++#include <linux/cpumask.h>
++#endif
++
++#ifdef CONFIG_X86_LOCAL_APIC
++#ifndef __ASSEMBLY__
++#include <asm/fixmap.h>
++#include <asm/bitops.h>
++#include <asm/mpspec.h>
++#ifdef CONFIG_X86_IO_APIC
++#include <asm/io_apic.h>
++#endif
++#include <asm/apic.h>
++#endif
++#endif
++
++#define BAD_APICID 0xFFu
++#ifdef CONFIG_SMP
++#ifndef __ASSEMBLY__
++
++/*
++ * Private routines/data
++ */
++
++extern void smp_alloc_memory(void);
++extern int pic_mode;
++extern int smp_num_siblings;
++extern cpumask_t cpu_sibling_map[];
++extern cpumask_t cpu_core_map[];
++
++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[];
++
++#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu]
++
++#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(),
++ * so this is correct in the x86 case.
++ */
++#define raw_smp_processor_id() (current_thread_info()->cpu)
++
++extern cpumask_t cpu_possible_map;
++#define cpu_callin_map cpu_possible_map
++
++/* We don't mark CPUs online until __cpu_up(), so we need another measure */
++static inline int num_booting_cpus(void)
++{
++ return cpus_weight(cpu_possible_map);
++}
++
++#ifdef CONFIG_X86_LOCAL_APIC
++
++#ifdef APIC_DEFINITION
++extern int hard_smp_processor_id(void);
++#else
++#include <mach_apicdef.h>
++static inline int hard_smp_processor_id(void)
++{
++ /* we don't want to mark this access volatile - bad code generation */
++ return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
++}
++#endif
++
++static __inline int logical_smp_processor_id(void)
++{
++ /* we don't want to mark this access volatile - bad code generation */
++ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
++}
++
++#endif
++
++extern int __cpu_disable(void);
++extern void __cpu_die(unsigned int cpu);
++extern void prefill_possible_map(void);
++#endif /* !__ASSEMBLY__ */
++
++#else /* CONFIG_SMP */
++
++#define cpu_physical_id(cpu) boot_cpu_physical_apicid
++
++#define NO_PROC_ID 0xFF /* No processor magic marker */
++
++#endif
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/spinlock.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/spinlock.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/spinlock.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/spinlock.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,202 @@
++#ifndef __ASM_SPINLOCK_H
++#define __ASM_SPINLOCK_H
++
++#include <asm/atomic.h>
++#include <asm/rwlock.h>
++#include <asm/page.h>
++#include <linux/compiler.h>
++
++/*
++ * Your basic SMP spinlocks, allowing only a single CPU anywhere
++ *
++ * Simple spin lock operations. There are two variants, one clears IRQ's
++ * on the local processor, one does not.
++ *
++ * We make no fairness assumptions. They have a cost.
++ *
++ * (the type definitions are in asm/spinlock_types.h)
++ */
++
++#define __raw_spin_is_locked(x) \
++ (*(volatile signed char *)(&(x)->slock) <= 0)
++
++#define __raw_spin_lock_string \
++ "\n1:\t" \
++ LOCK_PREFIX " ; decb %0\n\t" \
++ "jns 3f\n" \
++ "2:\t" \
++ "rep;nop\n\t" \
++ "cmpb $0,%0\n\t" \
++ "jle 2b\n\t" \
++ "jmp 1b\n" \
++ "3:\n\t"
++
++/*
++ * NOTE: there's an irqs-on section here, which normally would have to be
++ * irq-traced, but on CONFIG_TRACE_IRQFLAGS we never use
++ * __raw_spin_lock_string_flags().
++ */
++#define __raw_spin_lock_string_flags \
++ "\n1:\t" \
++ LOCK_PREFIX " ; decb %0\n\t" \
++ "jns 5f\n" \
++ "2:\t" \
++ "testl $0x200, %1\n\t" \
++ "jz 4f\n\t" \
++ "#sti\n" \
++ "3:\t" \
++ "rep;nop\n\t" \
++ "cmpb $0, %0\n\t" \
++ "jle 3b\n\t" \
++ "#cli\n\t" \
++ "jmp 1b\n" \
++ "4:\t" \
++ "rep;nop\n\t" \
++ "cmpb $0, %0\n\t" \
++ "jg 1b\n\t" \
++ "jmp 4b\n" \
++ "5:\n\t"
++
++static inline void __raw_spin_lock(raw_spinlock_t *lock)
++{
++ asm(__raw_spin_lock_string : "+m" (lock->slock) : : "memory");
++}
++
++/*
++ * It is easier for the lock validator if interrupts are not re-enabled
++ * in the middle of a lock-acquire. This is a performance feature anyway
++ * so we turn it off:
++ */
++#ifndef CONFIG_PROVE_LOCKING
++static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
++{
++ asm(__raw_spin_lock_string_flags : "+m" (lock->slock) : "r" (flags) : "memory");
++}
++#endif
++
++static inline int __raw_spin_trylock(raw_spinlock_t *lock)
++{
++ char oldval;
++ __asm__ __volatile__(
++ "xchgb %b0,%1"
++ :"=q" (oldval), "+m" (lock->slock)
++ :"0" (0) : "memory");
++ return oldval > 0;
++}
++
++/*
++ * __raw_spin_unlock based on writing $1 to the low byte.
++ * This method works. Despite all the confusion.
++ * (except on PPro SMP or if we are using OOSTORE, so we use xchgb there)
++ * (PPro errata 66, 92)
++ */
++
++#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE)
++
++#define __raw_spin_unlock_string \
++ "movb $1,%0" \
++ :"+m" (lock->slock) : : "memory"
++
++
++static inline void __raw_spin_unlock(raw_spinlock_t *lock)
++{
++ __asm__ __volatile__(
++ __raw_spin_unlock_string
++ );
++}
++
++#else
++
++#define __raw_spin_unlock_string \
++ "xchgb %b0, %1" \
++ :"=q" (oldval), "+m" (lock->slock) \
++ :"0" (oldval) : "memory"
++
++static inline void __raw_spin_unlock(raw_spinlock_t *lock)
++{
++ char oldval = 1;
++
++ __asm__ __volatile__(
++ __raw_spin_unlock_string
++ );
++}
++
++#endif
++
++#define __raw_spin_unlock_wait(lock) \
++ do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
++
++/*
++ * Read-write spinlocks, allowing multiple readers
++ * but only one writer.
++ *
++ * NOTE! it is quite common to have readers in interrupts
++ * but no interrupt writers. For those circumstances we
++ * can "mix" irq-safe locks - any writer needs to get a
++ * irq-safe write-lock, but readers can get non-irqsafe
++ * read-locks.
++ *
++ * On x86, we implement read-write locks as a 32-bit counter
++ * with the high bit (sign) being the "contended" bit.
++ *
++ * The inline assembly is non-obvious. Think about it.
++ *
++ * Changed to use the same technique as rw semaphores. See
++ * semaphore.h for details. -ben
++ *
++ * the helpers are in arch/i386/kernel/semaphore.c
++ */
++
++/**
++ * read_can_lock - would read_trylock() succeed?
++ * @lock: the rwlock in question.
++ */
++#define __raw_read_can_lock(x) ((int)(x)->lock > 0)
++
++/**
++ * write_can_lock - would write_trylock() succeed?
++ * @lock: the rwlock in question.
++ */
++#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
++
++static inline void __raw_read_lock(raw_rwlock_t *rw)
++{
++ __build_read_lock(rw, "__read_lock_failed");
++}
++
++static inline void __raw_write_lock(raw_rwlock_t *rw)
++{
++ __build_write_lock(rw, "__write_lock_failed");
++}
++
++static inline int __raw_read_trylock(raw_rwlock_t *lock)
++{
++ atomic_t *count = (atomic_t *)lock;
++ atomic_dec(count);
++ if (atomic_read(count) >= 0)
++ return 1;
++ atomic_inc(count);
++ return 0;
++}
++
++static inline int __raw_write_trylock(raw_rwlock_t *lock)
++{
++ atomic_t *count = (atomic_t *)lock;
++ if (atomic_sub_and_test(RW_LOCK_BIAS, count))
++ return 1;
++ atomic_add(RW_LOCK_BIAS, count);
++ return 0;
++}
++
++static inline void __raw_read_unlock(raw_rwlock_t *rw)
++{
++ asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory");
++}
++
++static inline void __raw_write_unlock(raw_rwlock_t *rw)
++{
++ asm volatile(LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ", %0"
++ : "+m" (rw->lock) : : "memory");
++}
++
++#endif /* __ASM_SPINLOCK_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/swiotlb.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/swiotlb.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/swiotlb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/swiotlb.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,41 @@
++#ifndef _ASM_SWIOTLB_H
++#define _ASM_SWIOTLB_H 1
++
++/* SWIOTLB interface */
++
++extern dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size,
++ int dir);
++extern void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
++ size_t size, int dir);
++extern void swiotlb_sync_single_for_cpu(struct device *hwdev,
++ dma_addr_t dev_addr,
++ size_t size, int dir);
++extern void swiotlb_sync_single_for_device(struct device *hwdev,
++ dma_addr_t dev_addr,
++ size_t size, int dir);
++extern void swiotlb_sync_sg_for_cpu(struct device *hwdev,
++ struct scatterlist *sg, int nelems,
++ int dir);
++extern void swiotlb_sync_sg_for_device(struct device *hwdev,
++ struct scatterlist *sg, int nelems,
++ int dir);
++extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
++ int nents, int direction);
++extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg,
++ int nents, int direction);
++extern int swiotlb_dma_mapping_error(dma_addr_t dma_addr);
++extern dma_addr_t swiotlb_map_page(struct device *hwdev, struct page *page,
++ unsigned long offset, size_t size,
++ enum dma_data_direction direction);
++extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dma_address,
++ size_t size, enum dma_data_direction direction);
++extern int swiotlb_dma_supported(struct device *hwdev, u64 mask);
++extern void swiotlb_init(void);
++
++#ifdef CONFIG_SWIOTLB
++extern int swiotlb;
++#else
++#define swiotlb 0
++#endif
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/synch_bitops.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/synch_bitops.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/synch_bitops.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/synch_bitops.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,141 @@
++#ifndef __XEN_SYNCH_BITOPS_H__
++#define __XEN_SYNCH_BITOPS_H__
++
++/*
++ * Copyright 1992, Linus Torvalds.
++ * Heavily modified to provide guaranteed strong synchronisation
++ * when communicating with Xen or other guest OSes running on other CPUs.
++ */
++
++#define ADDR (*(volatile long *) addr)
++
++static __inline__ void synch_set_bit(int nr, volatile void * addr)
++{
++ __asm__ __volatile__ (
++ "lock btsl %1,%0"
++ : "+m" (ADDR) : "Ir" (nr) : "memory" );
++}
++
++static __inline__ void synch_clear_bit(int nr, volatile void * addr)
++{
++ __asm__ __volatile__ (
++ "lock btrl %1,%0"
++ : "+m" (ADDR) : "Ir" (nr) : "memory" );
++}
++
++static __inline__ void synch_change_bit(int nr, volatile void * addr)
++{
++ __asm__ __volatile__ (
++ "lock btcl %1,%0"
++ : "+m" (ADDR) : "Ir" (nr) : "memory" );
++}
++
++static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr)
++{
++ int oldbit;
++ __asm__ __volatile__ (
++ "lock btsl %2,%1\n\tsbbl %0,%0"
++ : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory");
++ return oldbit;
++}
++
++static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr)
++{
++ int oldbit;
++ __asm__ __volatile__ (
++ "lock btrl %2,%1\n\tsbbl %0,%0"
++ : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory");
++ return oldbit;
++}
++
++static __inline__ int synch_test_and_change_bit(int nr, volatile void * addr)
++{
++ int oldbit;
++
++ __asm__ __volatile__ (
++ "lock btcl %2,%1\n\tsbbl %0,%0"
++ : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory");
++ return oldbit;
++}
++
++struct __synch_xchg_dummy { unsigned long a[100]; };
++#define __synch_xg(x) ((struct __synch_xchg_dummy *)(x))
++
++#define synch_cmpxchg(ptr, old, new) \
++((__typeof__(*(ptr)))__synch_cmpxchg((ptr),\
++ (unsigned long)(old), \
++ (unsigned long)(new), \
++ sizeof(*(ptr))))
++
++static inline unsigned long __synch_cmpxchg(volatile void *ptr,
++ unsigned long old,
++ unsigned long new, int size)
++{
++ unsigned long prev;
++ switch (size) {
++ case 1:
++ __asm__ __volatile__("lock; cmpxchgb %b1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__synch_xg(ptr)),
++ "0"(old)
++ : "memory");
++ return prev;
++ case 2:
++ __asm__ __volatile__("lock; cmpxchgw %w1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__synch_xg(ptr)),
++ "0"(old)
++ : "memory");
++ return prev;
++#ifdef CONFIG_X86_64
++ case 4:
++ __asm__ __volatile__("lock; cmpxchgl %k1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__synch_xg(ptr)),
++ "0"(old)
++ : "memory");
++ return prev;
++ case 8:
++ __asm__ __volatile__("lock; cmpxchgq %1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__synch_xg(ptr)),
++ "0"(old)
++ : "memory");
++ return prev;
++#else
++ case 4:
++ __asm__ __volatile__("lock; cmpxchgl %1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__synch_xg(ptr)),
++ "0"(old)
++ : "memory");
++ return prev;
++#endif
++ }
++ return old;
++}
++
++static __always_inline int synch_const_test_bit(int nr,
++ const volatile void * addr)
++{
++ return ((1UL << (nr & 31)) &
++ (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
++}
++
++static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
++{
++ int oldbit;
++ __asm__ __volatile__ (
++ "btl %2,%1\n\tsbbl %0,%0"
++ : "=r" (oldbit) : "m" (ADDR), "Ir" (nr) );
++ return oldbit;
++}
++
++#define synch_test_bit(nr,addr) \
++(__builtin_constant_p(nr) ? \
++ synch_const_test_bit((nr),(addr)) : \
++ synch_var_test_bit((nr),(addr)))
++
++#define synch_cmpxchg_subword synch_cmpxchg
++
++#endif /* __XEN_SYNCH_BITOPS_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/system.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/system.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/system.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/system.h 2006-09-21 01:33:32.000000000 +0200
+@@ -0,0 +1,491 @@
++#ifndef __ASM_SYSTEM_H
++#define __ASM_SYSTEM_H
++
++#include <linux/kernel.h>
++#include <asm/segment.h>
++#include <asm/cpufeature.h>
++#include <linux/bitops.h> /* for LOCK_PREFIX */
++#include <asm/synch_bitops.h>
++#include <asm/hypervisor.h>
++
++#ifdef __KERNEL__
++
++#ifdef CONFIG_SMP
++#define __vcpu_id smp_processor_id()
++#else
++#define __vcpu_id 0
++#endif
++
++struct task_struct; /* one of the stranger aspects of C forward declarations.. */
++extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
++
++#define switch_to(prev,next,last) do { \
++ unsigned long esi,edi; \
++ asm volatile("pushfl\n\t" /* Save flags */ \
++ "pushl %%ebp\n\t" \
++ "movl %%esp,%0\n\t" /* save ESP */ \
++ "movl %5,%%esp\n\t" /* restore ESP */ \
++ "movl $1f,%1\n\t" /* save EIP */ \
++ "pushl %6\n\t" /* restore EIP */ \
++ "jmp __switch_to\n" \
++ "1:\t" \
++ "popl %%ebp\n\t" \
++ "popfl" \
++ :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
++ "=a" (last),"=S" (esi),"=D" (edi) \
++ :"m" (next->thread.esp),"m" (next->thread.eip), \
++ "2" (prev), "d" (next)); \
++} while (0)
++
++#define _set_base(addr,base) do { unsigned long __pr; \
++__asm__ __volatile__ ("movw %%dx,%1\n\t" \
++ "rorl $16,%%edx\n\t" \
++ "movb %%dl,%2\n\t" \
++ "movb %%dh,%3" \
++ :"=&d" (__pr) \
++ :"m" (*((addr)+2)), \
++ "m" (*((addr)+4)), \
++ "m" (*((addr)+7)), \
++ "0" (base) \
++ ); } while(0)
++
++#define _set_limit(addr,limit) do { unsigned long __lr; \
++__asm__ __volatile__ ("movw %%dx,%1\n\t" \
++ "rorl $16,%%edx\n\t" \
++ "movb %2,%%dh\n\t" \
++ "andb $0xf0,%%dh\n\t" \
++ "orb %%dh,%%dl\n\t" \
++ "movb %%dl,%2" \
++ :"=&d" (__lr) \
++ :"m" (*(addr)), \
++ "m" (*((addr)+6)), \
++ "0" (limit) \
++ ); } while(0)
++
++#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
++#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1) )
++
++/*
++ * Load a segment. Fall back on loading the zero
++ * segment if something goes wrong..
++ */
++#define loadsegment(seg,value) \
++ asm volatile("\n" \
++ "1:\t" \
++ "mov %0,%%" #seg "\n" \
++ "2:\n" \
++ ".section .fixup,\"ax\"\n" \
++ "3:\t" \
++ "pushl $0\n\t" \
++ "popl %%" #seg "\n\t" \
++ "jmp 2b\n" \
++ ".previous\n" \
++ ".section __ex_table,\"a\"\n\t" \
++ ".align 4\n\t" \
++ ".long 1b,3b\n" \
++ ".previous" \
++ : :"rm" (value))
++
++/*
++ * Save a segment register away
++ */
++#define savesegment(seg, value) \
++ asm volatile("mov %%" #seg ",%0":"=rm" (value))
++
++#define read_cr0() ({ \
++ unsigned int __dummy; \
++ __asm__ __volatile__( \
++ "movl %%cr0,%0\n\t" \
++ :"=r" (__dummy)); \
++ __dummy; \
++})
++#define write_cr0(x) \
++ __asm__ __volatile__("movl %0,%%cr0": :"r" (x))
++
++#define read_cr2() \
++ (HYPERVISOR_shared_info->vcpu_info[smp_processor_id()].arch.cr2)
++#define write_cr2(x) \
++ __asm__ __volatile__("movl %0,%%cr2": :"r" (x))
++
++#define read_cr3() ({ \
++ unsigned int __dummy; \
++ __asm__ ( \
++ "movl %%cr3,%0\n\t" \
++ :"=r" (__dummy)); \
++ __dummy = xen_cr3_to_pfn(__dummy); \
++ mfn_to_pfn(__dummy) << PAGE_SHIFT; \
++})
++#define write_cr3(x) ({ \
++ unsigned int __dummy = pfn_to_mfn((x) >> PAGE_SHIFT); \
++ __dummy = xen_pfn_to_cr3(__dummy); \
++ __asm__ __volatile__("movl %0,%%cr3": :"r" (__dummy)); \
++})
++
++#define read_cr4() ({ \
++ unsigned int __dummy; \
++ __asm__( \
++ "movl %%cr4,%0\n\t" \
++ :"=r" (__dummy)); \
++ __dummy; \
++})
++#define read_cr4_safe() ({ \
++ unsigned int __dummy; \
++ /* This could fault if %cr4 does not exist */ \
++ __asm__("1: movl %%cr4, %0 \n" \
++ "2: \n" \
++ ".section __ex_table,\"a\" \n" \
++ ".long 1b,2b \n" \
++ ".previous \n" \
++ : "=r" (__dummy): "0" (0)); \
++ __dummy; \
++})
++
++#define write_cr4(x) \
++ __asm__ __volatile__("movl %0,%%cr4": :"r" (x))
++/*
++ * Clear and set 'TS' bit respectively
++ */
++#define clts() (HYPERVISOR_fpu_taskswitch(0))
++#define stts() (HYPERVISOR_fpu_taskswitch(1))
++
++#endif /* __KERNEL__ */
++
++#define wbinvd() \
++ __asm__ __volatile__ ("wbinvd": : :"memory")
++
++static inline unsigned long get_limit(unsigned long segment)
++{
++ unsigned long __limit;
++ __asm__("lsll %1,%0"
++ :"=r" (__limit):"r" (segment));
++ return __limit+1;
++}
++
++#define nop() __asm__ __volatile__ ("nop")
++
++#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
++
++#define tas(ptr) (xchg((ptr),1))
++
++struct __xchg_dummy { unsigned long a[100]; };
++#define __xg(x) ((struct __xchg_dummy *)(x))
++
++
++#ifdef CONFIG_X86_CMPXCHG64
++
++/*
++ * The semantics of XCHGCMP8B are a bit strange, this is why
++ * there is a loop and the loading of %%eax and %%edx has to
++ * be inside. This inlines well in most cases, the cached
++ * cost is around ~38 cycles. (in the future we might want
++ * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
++ * might have an implicit FPU-save as a cost, so it's not
++ * clear which path to go.)
++ *
++ * cmpxchg8b must be used with the lock prefix here to allow
++ * the instruction to be executed atomically, see page 3-102
++ * of the instruction set reference 24319102.pdf. We need
++ * the reader side to see the coherent 64bit value.
++ */
++static inline void __set_64bit (unsigned long long * ptr,
++ unsigned int low, unsigned int high)
++{
++ __asm__ __volatile__ (
++ "\n1:\t"
++ "movl (%0), %%eax\n\t"
++ "movl 4(%0), %%edx\n\t"
++ "lock cmpxchg8b (%0)\n\t"
++ "jnz 1b"
++ : /* no outputs */
++ : "D"(ptr),
++ "b"(low),
++ "c"(high)
++ : "ax","dx","memory");
++}
++
++static inline void __set_64bit_constant (unsigned long long *ptr,
++ unsigned long long value)
++{
++ __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
++}
++#define ll_low(x) *(((unsigned int*)&(x))+0)
++#define ll_high(x) *(((unsigned int*)&(x))+1)
++
++static inline void __set_64bit_var (unsigned long long *ptr,
++ unsigned long long value)
++{
++ __set_64bit(ptr,ll_low(value), ll_high(value));
++}
++
++#define set_64bit(ptr,value) \
++(__builtin_constant_p(value) ? \
++ __set_64bit_constant(ptr, value) : \
++ __set_64bit_var(ptr, value) )
++
++#define _set_64bit(ptr,value) \
++(__builtin_constant_p(value) ? \
++ __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
++ __set_64bit(ptr, ll_low(value), ll_high(value)) )
++
++#endif
++
++/*
++ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
++ * Note 2: xchg has side effect, so that attribute volatile is necessary,
++ * but generally the primitive is invalid, *ptr is output argument. --ANK
++ */
++static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
++{
++ switch (size) {
++ case 1:
++ __asm__ __volatile__("xchgb %b0,%1"
++ :"=q" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ case 2:
++ __asm__ __volatile__("xchgw %w0,%1"
++ :"=r" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ case 4:
++ __asm__ __volatile__("xchgl %0,%1"
++ :"=r" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ }
++ return x;
++}
++
++/*
++ * Atomic compare and exchange. Compare OLD with MEM, if identical,
++ * store NEW in MEM. Return the initial value in MEM. Success is
++ * indicated by comparing RETURN with OLD.
++ */
++
++#ifdef CONFIG_X86_CMPXCHG
++#define __HAVE_ARCH_CMPXCHG 1
++#define cmpxchg(ptr,o,n)\
++ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
++ (unsigned long)(n),sizeof(*(ptr))))
++#endif
++
++static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
++ unsigned long new, int size)
++{
++ unsigned long prev;
++ switch (size) {
++ case 1:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 2:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 4:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ }
++ return old;
++}
++
++#ifndef CONFIG_X86_CMPXCHG
++/*
++ * Building a kernel capable running on 80386. It may be necessary to
++ * simulate the cmpxchg on the 80386 CPU. For that purpose we define
++ * a function for each of the sizes we support.
++ */
++
++extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
++extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
++extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
++
++static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
++ unsigned long new, int size)
++{
++ switch (size) {
++ case 1:
++ return cmpxchg_386_u8(ptr, old, new);
++ case 2:
++ return cmpxchg_386_u16(ptr, old, new);
++ case 4:
++ return cmpxchg_386_u32(ptr, old, new);
++ }
++ return old;
++}
++
++#define cmpxchg(ptr,o,n) \
++({ \
++ __typeof__(*(ptr)) __ret; \
++ if (likely(boot_cpu_data.x86 > 3)) \
++ __ret = __cmpxchg((ptr), (unsigned long)(o), \
++ (unsigned long)(n), sizeof(*(ptr))); \
++ else \
++ __ret = cmpxchg_386((ptr), (unsigned long)(o), \
++ (unsigned long)(n), sizeof(*(ptr))); \
++ __ret; \
++})
++#endif
++
++#ifdef CONFIG_X86_CMPXCHG64
++
++static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
++ unsigned long long new)
++{
++ unsigned long long prev;
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3"
++ : "=A"(prev)
++ : "b"((unsigned long)new),
++ "c"((unsigned long)(new >> 32)),
++ "m"(*__xg(ptr)),
++ "0"(old)
++ : "memory");
++ return prev;
++}
++
++#define cmpxchg64(ptr,o,n)\
++ ((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
++ (unsigned long long)(n)))
++
++#endif
++
++/*
++ * Force strict CPU ordering.
++ * And yes, this is required on UP too when we're talking
++ * to devices.
++ *
++ * For now, "wmb()" doesn't actually do anything, as all
++ * Intel CPU's follow what Intel calls a *Processor Order*,
++ * in which all writes are seen in the program order even
++ * outside the CPU.
++ *
++ * I expect future Intel CPU's to have a weaker ordering,
++ * but I'd also expect them to finally get their act together
++ * and add some real memory barriers if so.
++ *
++ * Some non intel clones support out of order store. wmb() ceases to be a
++ * nop for these.
++ */
++
++
++/*
++ * Actually only lfence would be needed for mb() because all stores done
++ * by the kernel should be already ordered. But keep a full barrier for now.
++ */
++
++#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
++#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
++
++/**
++ * read_barrier_depends - Flush all pending reads that subsequents reads
++ * depend on.
++ *
++ * No data-dependent reads from memory-like regions are ever reordered
++ * over this barrier. All reads preceding this primitive are guaranteed
++ * to access memory (but not necessarily other CPUs' caches) before any
++ * reads following this primitive that depend on the data return by
++ * any of the preceding reads. This primitive is much lighter weight than
++ * rmb() on most CPUs, and is never heavier weight than is
++ * rmb().
++ *
++ * These ordering constraints are respected by both the local CPU
++ * and the compiler.
++ *
++ * Ordering is not guaranteed by anything other than these primitives,
++ * not even by data dependencies. See the documentation for
++ * memory_barrier() for examples and URLs to more information.
++ *
++ * For example, the following code would force ordering (the initial
++ * value of "a" is zero, "b" is one, and "p" is "&a"):
++ *
++ * <programlisting>
++ * CPU 0 CPU 1
++ *
++ * b = 2;
++ * memory_barrier();
++ * p = &b; q = p;
++ * read_barrier_depends();
++ * d = *q;
++ * </programlisting>
++ *
++ * because the read of "*q" depends on the read of "p" and these
++ * two reads are separated by a read_barrier_depends(). However,
++ * the following code, with the same initial values for "a" and "b":
++ *
++ * <programlisting>
++ * CPU 0 CPU 1
++ *
++ * a = 2;
++ * memory_barrier();
++ * b = 3; y = b;
++ * read_barrier_depends();
++ * x = a;
++ * </programlisting>
++ *
++ * does not enforce ordering, since there is no data dependency between
++ * the read of "a" and the read of "b". Therefore, on some CPUs, such
++ * as Alpha, "y" could be set to 3 and "x" to 0. Use rmb()
++ * in cases like this where there are no data dependencies.
++ **/
++
++#define read_barrier_depends() do { } while(0)
++
++#ifdef CONFIG_X86_OOSTORE
++/* Actually there are no OOO store capable CPUs for now that do SSE,
++ but make it already an possibility. */
++#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
++#else
++#define wmb() __asm__ __volatile__ ("": : :"memory")
++#endif
++
++#ifdef CONFIG_SMP
++#define smp_mb() mb()
++#define smp_rmb() rmb()
++#define smp_wmb() wmb()
++#define smp_read_barrier_depends() read_barrier_depends()
++#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
++#else
++#define smp_mb() barrier()
++#define smp_rmb() barrier()
++#define smp_wmb() barrier()
++#define smp_read_barrier_depends() do { } while(0)
++#define set_mb(var, value) do { var = value; barrier(); } while (0)
++#endif
++
++#include <linux/irqflags.h>
++
++/*
++ * disable hlt during certain critical i/o operations
++ */
++#define HAVE_DISABLE_HLT
++void disable_hlt(void);
++void enable_hlt(void);
++
++extern int es7000_plat;
++void cpu_idle_wait(void);
++
++/*
++ * On SMP systems, when the scheduler does migration-cost autodetection,
++ * it needs a way to flush as much of the CPU's caches as possible:
++ */
++static inline void sched_cacheflush(void)
++{
++ wbinvd();
++}
++
++extern unsigned long arch_align_stack(unsigned long sp);
++extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
++
++void default_idle(void);
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/timer.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/timer.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/timer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/timer.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,70 @@
++#ifndef _ASMi386_TIMER_H
++#define _ASMi386_TIMER_H
++#include <linux/init.h>
++#include <linux/pm.h>
++
++/**
++ * struct timer_ops - used to define a timer source
++ *
++ * @name: name of the timer.
++ * @init: Probes and initializes the timer. Takes clock= override
++ * string as an argument. Returns 0 on success, anything else
++ * on failure.
++ * @mark_offset: called by the timer interrupt.
++ * @get_offset: called by gettimeofday(). Returns the number of microseconds
++ * since the last timer interupt.
++ * @monotonic_clock: returns the number of nanoseconds since the init of the
++ * timer.
++ * @delay: delays this many clock cycles.
++ */
++struct timer_opts {
++ char* name;
++ void (*mark_offset)(void);
++ unsigned long (*get_offset)(void);
++ unsigned long long (*monotonic_clock)(void);
++ void (*delay)(unsigned long);
++ unsigned long (*read_timer)(void);
++ int (*suspend)(pm_message_t state);
++ int (*resume)(void);
++};
++
++struct init_timer_opts {
++ int (*init)(char *override);
++ struct timer_opts *opts;
++};
++
++#define TICK_SIZE (tick_nsec / 1000)
++
++extern struct timer_opts* __init select_timer(void);
++extern void clock_fallback(void);
++void setup_pit_timer(void);
++
++/* Modifiers for buggy PIT handling */
++
++extern int pit_latch_buggy;
++
++extern struct timer_opts *cur_timer;
++extern int timer_ack;
++
++/* list of externed timers */
++extern struct timer_opts timer_none;
++extern struct timer_opts timer_pit;
++extern struct init_timer_opts timer_pit_init;
++extern struct init_timer_opts timer_tsc_init;
++#ifdef CONFIG_X86_CYCLONE_TIMER
++extern struct init_timer_opts timer_cyclone_init;
++#endif
++
++extern unsigned long calibrate_tsc(void);
++extern unsigned long read_timer_tsc(void);
++extern void init_cpu_khz(void);
++extern int recalibrate_cpu_khz(void);
++#ifdef CONFIG_HPET_TIMER
++extern struct init_timer_opts timer_hpet_init;
++extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
++#endif
++
++#ifdef CONFIG_X86_PM_TIMER
++extern struct init_timer_opts timer_pmtmr_init;
++#endif
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/tlbflush.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/tlbflush.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/tlbflush.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/tlbflush.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,101 @@
++#ifndef _I386_TLBFLUSH_H
++#define _I386_TLBFLUSH_H
++
++#include <linux/mm.h>
++#include <asm/processor.h>
++
++#define __flush_tlb() xen_tlb_flush()
++#define __flush_tlb_global() xen_tlb_flush()
++#define __flush_tlb_all() xen_tlb_flush()
++
++extern unsigned long pgkern_mask;
++
++#define cpu_has_invlpg (boot_cpu_data.x86 > 3)
++
++#define __flush_tlb_single(addr) xen_invlpg(addr)
++
++#define __flush_tlb_one(addr) __flush_tlb_single(addr)
++
++/*
++ * TLB flushing:
++ *
++ * - flush_tlb() flushes the current mm struct TLBs
++ * - flush_tlb_all() flushes all processes TLBs
++ * - flush_tlb_mm(mm) flushes the specified mm context TLB's
++ * - flush_tlb_page(vma, vmaddr) flushes one page
++ * - flush_tlb_range(vma, start, end) flushes a range of pages
++ * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
++ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
++ *
++ * ..but the i386 has somewhat limited tlb flushing capabilities,
++ * and page-granular flushes are available only on i486 and up.
++ */
++
++#ifndef CONFIG_SMP
++
++#define flush_tlb() __flush_tlb()
++#define flush_tlb_all() __flush_tlb_all()
++#define local_flush_tlb() __flush_tlb()
++
++static inline void flush_tlb_mm(struct mm_struct *mm)
++{
++ if (mm == current->active_mm)
++ __flush_tlb();
++}
++
++static inline void flush_tlb_page(struct vm_area_struct *vma,
++ unsigned long addr)
++{
++ if (vma->vm_mm == current->active_mm)
++ __flush_tlb_one(addr);
++}
++
++static inline void flush_tlb_range(struct vm_area_struct *vma,
++ unsigned long start, unsigned long end)
++{
++ if (vma->vm_mm == current->active_mm)
++ __flush_tlb();
++}
++
++#else
++
++#include <asm/smp.h>
++
++#define local_flush_tlb() \
++ __flush_tlb()
++
++extern void flush_tlb_all(void);
++extern void flush_tlb_current_task(void);
++extern void flush_tlb_mm(struct mm_struct *);
++extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
++
++#define flush_tlb() flush_tlb_current_task()
++
++static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
++{
++ flush_tlb_mm(vma->vm_mm);
++}
++
++#define TLBSTATE_OK 1
++#define TLBSTATE_LAZY 2
++
++struct tlb_state
++{
++ struct mm_struct *active_mm;
++ int state;
++ char __cacheline_padding[L1_CACHE_BYTES-8];
++};
++DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
++
++
++#endif
++
++#define flush_tlb_kernel_range(start, end) flush_tlb_all()
++
++static inline void flush_tlb_pgtables(struct mm_struct *mm,
++ unsigned long start, unsigned long end)
++{
++ /* i386 does not keep any page table caches in TLB */
++}
++
++#endif /* _I386_TLBFLUSH_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/asm/vga.h linux-2.6.18-xen/include/asm-i386/mach-xen/asm/vga.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/asm/vga.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/asm/vga.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,20 @@
++/*
++ * Access to VGA videoram
++ *
++ * (c) 1998 Martin Mares <mj at ucw.cz>
++ */
++
++#ifndef _LINUX_ASM_VGA_H_
++#define _LINUX_ASM_VGA_H_
++
++/*
++ * On the PC, we can just recalculate addresses and then
++ * access the videoram directly without any black magic.
++ */
++
++#define VGA_MAP_MEM(x,s) (unsigned long)isa_bus_to_virt(x)
++
++#define vga_readb(x) (*(x))
++#define vga_writeb(x,y) (*(y) = (x))
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/irq_vectors.h linux-2.6.18-xen/include/asm-i386/mach-xen/irq_vectors.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/irq_vectors.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/irq_vectors.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,125 @@
++/*
++ * This file should contain #defines for all of the interrupt vector
++ * numbers used by this architecture.
++ *
++ * In addition, there are some standard defines:
++ *
++ * FIRST_EXTERNAL_VECTOR:
++ * The first free place for external interrupts
++ *
++ * SYSCALL_VECTOR:
++ * The IRQ vector a syscall makes the user to kernel transition
++ * under.
++ *
++ * TIMER_IRQ:
++ * The IRQ number the timer interrupt comes in at.
++ *
++ * NR_IRQS:
++ * The total number of interrupt vectors (including all the
++ * architecture specific interrupts) needed.
++ *
++ */
++#ifndef _ASM_IRQ_VECTORS_H
++#define _ASM_IRQ_VECTORS_H
++
++/*
++ * IDT vectors usable for external interrupt sources start
++ * at 0x20:
++ */
++#define FIRST_EXTERNAL_VECTOR 0x20
++
++#define SYSCALL_VECTOR 0x80
++
++/*
++ * Vectors 0x20-0x2f are used for ISA interrupts.
++ */
++
++#if 0
++/*
++ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
++ *
++ * some of the following vectors are 'rare', they are merged
++ * into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
++ * TLB, reschedule and local APIC vectors are performance-critical.
++ *
++ * Vectors 0xf0-0xfa are free (reserved for future Linux use).
++ */
++#define SPURIOUS_APIC_VECTOR 0xff
++#define ERROR_APIC_VECTOR 0xfe
++#define INVALIDATE_TLB_VECTOR 0xfd
++#define RESCHEDULE_VECTOR 0xfc
++#define CALL_FUNCTION_VECTOR 0xfb
++
++#define THERMAL_APIC_VECTOR 0xf0
++/*
++ * Local APIC timer IRQ vector is on a different priority level,
++ * to work around the 'lost local interrupt if more than 2 IRQ
++ * sources per level' errata.
++ */
++#define LOCAL_TIMER_VECTOR 0xef
++#endif
++
++#define SPURIOUS_APIC_VECTOR 0xff
++#define ERROR_APIC_VECTOR 0xfe
++
++/*
++ * First APIC vector available to drivers: (vectors 0x30-0xee)
++ * we start at 0x31 to spread out vectors evenly between priority
++ * levels. (0x80 is the syscall vector)
++ */
++#define FIRST_DEVICE_VECTOR 0x31
++#define FIRST_SYSTEM_VECTOR 0xef
++
++/*
++ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
++ * Right now the APIC is mostly only used for SMP.
++ * 256 vectors is an architectural limit. (we can have
++ * more than 256 devices theoretically, but they will
++ * have to use shared interrupts)
++ * Since vectors 0x00-0x1f are used/reserved for the CPU,
++ * the usable vector space is 0x20-0xff (224 vectors)
++ */
++
++#define RESCHEDULE_VECTOR 0
++#define CALL_FUNCTION_VECTOR 1
++#define NR_IPIS 2
++
++/*
++ * The maximum number of vectors supported by i386 processors
++ * is limited to 256. For processors other than i386, NR_VECTORS
++ * should be changed accordingly.
++ */
++#define NR_VECTORS 256
++
++#define FPU_IRQ 13
++
++#define FIRST_VM86_IRQ 3
++#define LAST_VM86_IRQ 15
++#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15)
++
++/*
++ * The flat IRQ space is divided into two regions:
++ * 1. A one-to-one mapping of real physical IRQs. This space is only used
++ * if we have physical device-access privilege. This region is at the
++ * start of the IRQ space so that existing device drivers do not need
++ * to be modified to translate physical IRQ numbers into our IRQ space.
++ * 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These
++ * are bound using the provided bind/unbind functions.
++ */
++
++#define PIRQ_BASE 0
++#define NR_PIRQS 256
++
++#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
++#define NR_DYNIRQS 256
++
++#define NR_IRQS (NR_PIRQS + NR_DYNIRQS)
++#define NR_IRQ_VECTORS NR_IRQS
++
++#define pirq_to_irq(_x) ((_x) + PIRQ_BASE)
++#define irq_to_pirq(_x) ((_x) - PIRQ_BASE)
++
++#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE)
++#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE)
++
++#endif /* _ASM_IRQ_VECTORS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/mach_traps.h linux-2.6.18-xen/include/asm-i386/mach-xen/mach_traps.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/mach_traps.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/mach_traps.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * include/asm-xen/asm-i386/mach-xen/mach_traps.h
++ *
++ * Machine specific NMI handling for Xen
++ */
++#ifndef _MACH_TRAPS_H
++#define _MACH_TRAPS_H
++
++#include <linux/bitops.h>
++#include <xen/interface/nmi.h>
++
++static inline void clear_mem_error(unsigned char reason) {}
++static inline void clear_io_check_error(unsigned char reason) {}
++
++static inline unsigned char get_nmi_reason(void)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++ unsigned char reason = 0;
++
++ /* construct a value which looks like it came from
++ * port 0x61.
++ */
++ if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason))
++ reason |= 0x40;
++ if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason))
++ reason |= 0x80;
++
++ return reason;
++}
++
++static inline void reassert_nmi(void) {}
++
++#endif /* !_MACH_TRAPS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/mach-xen/setup_arch.h linux-2.6.18-xen/include/asm-i386/mach-xen/setup_arch.h
+--- linux-2.6.18.1/include/asm-i386/mach-xen/setup_arch.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-i386/mach-xen/setup_arch.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,5 @@
++/* Hook to call BIOS initialisation function */
++
++#define ARCH_SETUP machine_specific_arch_setup();
++
++void __init machine_specific_arch_setup(void);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/pgtable-2level-defs.h linux-2.6.18-xen/include/asm-i386/pgtable-2level-defs.h
+--- linux-2.6.18.1/include/asm-i386/pgtable-2level-defs.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-i386/pgtable-2level-defs.h 2006-09-04 16:31:16.000000000 +0200
+@@ -1,6 +1,8 @@
+ #ifndef _I386_PGTABLE_2LEVEL_DEFS_H
+ #define _I386_PGTABLE_2LEVEL_DEFS_H
+
++#define HAVE_SHARED_KERNEL_PMD 0
++
+ /*
+ * traditional i386 two-level paging structure:
+ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-i386/pgtable-3level-defs.h linux-2.6.18-xen/include/asm-i386/pgtable-3level-defs.h
+--- linux-2.6.18.1/include/asm-i386/pgtable-3level-defs.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-i386/pgtable-3level-defs.h 2006-09-04 16:31:16.000000000 +0200
+@@ -1,6 +1,8 @@
+ #ifndef _I386_PGTABLE_3LEVEL_DEFS_H
+ #define _I386_PGTABLE_3LEVEL_DEFS_H
+
++#define HAVE_SHARED_KERNEL_PMD 1
++
+ /*
+ * PGDIR_SHIFT determines what a top-level page table entry can map
+ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/agp.h linux-2.6.18-xen/include/asm-ia64/agp.h
+--- linux-2.6.18.1/include/asm-ia64/agp.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/agp.h 2006-09-04 16:31:16.000000000 +0200
+@@ -19,13 +19,49 @@
+ #define flush_agp_cache() mb()
+
+ /* Convert a physical address to an address suitable for the GART. */
++#ifndef CONFIG_XEN
+ #define phys_to_gart(x) (x)
+ #define gart_to_phys(x) (x)
++#else
++#define phys_to_gart(x) phys_to_machine_for_dma(x)
++#define gart_to_phys(x) machine_to_phys_for_dma(x)
++#endif
+
+ /* GATT allocation. Returns/accepts GATT kernel virtual address. */
+-#define alloc_gatt_pages(order) \
+- ((char *)__get_free_pages(GFP_KERNEL, (order)))
+-#define free_gatt_pages(table, order) \
+- free_pages((unsigned long)(table), (order))
++#ifdef CONFIG_XEN
++#include <asm/hypervisor.h>
++static inline char*
++alloc_gatt_pages(unsigned int order)
++{
++ unsigned long error;
++ unsigned long ret = __get_free_pages(GFP_KERNEL, (order));
++ if (ret == 0) {
++ goto out;
++ }
++ error = xen_create_contiguous_region(ret, order, 0);
++ if (error) {
++ free_pages(ret, order);
++ ret = 0;
++ }
++out:
++ return (char*)ret;
++}
++static inline void
++free_gatt_pages(void* table, unsigned int order)
++{
++ xen_destroy_contiguous_region((unsigned long)table, order);
++ free_pages((unsigned long)table, order);
++}
++#else /* CONFIG_XEN */
++/* Convert a physical address to an address suitable for the GART. */
++#define phys_to_gart(x) (x)
++#define gart_to_phys(x) (x)
++
++/* GATT allocation. Returns/accepts GATT kernel virtual address. */
++#define alloc_gatt_pages(order) \
++ ((char *)__get_free_pages(GFP_KERNEL, (order)))
++#define free_gatt_pages(table, order) \
++ free_pages((unsigned long)(table), (order))
++#endif /* CONFIG_XEN */
+
+ #endif /* _ASM_IA64_AGP_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/dma-mapping.h linux-2.6.18-xen/include/asm-ia64/dma-mapping.h
+--- linux-2.6.18.1/include/asm-ia64/dma-mapping.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/dma-mapping.h 2006-09-21 01:33:32.000000000 +0200
+@@ -7,19 +7,68 @@
+ */
+ #include <asm/machvec.h>
+
+-#define dma_alloc_coherent platform_dma_alloc_coherent
+-#define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */
+-#define dma_free_coherent platform_dma_free_coherent
+-#define dma_free_noncoherent platform_dma_free_coherent
+-#define dma_map_single platform_dma_map_single
+-#define dma_map_sg platform_dma_map_sg
+-#define dma_unmap_single platform_dma_unmap_single
+-#define dma_unmap_sg platform_dma_unmap_sg
+-#define dma_sync_single_for_cpu platform_dma_sync_single_for_cpu
+-#define dma_sync_sg_for_cpu platform_dma_sync_sg_for_cpu
++#ifndef CONFIG_XEN
++
++#define dma_alloc_coherent platform_dma_alloc_coherent
++#define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */
++#define dma_free_coherent platform_dma_free_coherent
++#define dma_free_noncoherent platform_dma_free_coherent
++#define dma_map_single platform_dma_map_single
++#define dma_map_sg platform_dma_map_sg
++#define dma_unmap_single platform_dma_unmap_single
++#define dma_unmap_sg platform_dma_unmap_sg
++#define dma_sync_single_for_cpu platform_dma_sync_single_for_cpu
++#define dma_sync_sg_for_cpu platform_dma_sync_sg_for_cpu
+ #define dma_sync_single_for_device platform_dma_sync_single_for_device
+-#define dma_sync_sg_for_device platform_dma_sync_sg_for_device
+-#define dma_mapping_error platform_dma_mapping_error
++#define dma_sync_sg_for_device platform_dma_sync_sg_for_device
++#define dma_mapping_error platform_dma_mapping_error
++
++
++#else /* CONFIG_XEN */
++/* Needed for arch/i386/kernel/swiotlb.c and arch/i386/kernel/pci-dma-xen.c */
++#include <asm/hypervisor.h>
++/* Needed for arch/i386/kernel/swiotlb.c */
++#include <asm-i386/mach-xen/asm/swiotlb.h>
++
++int dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
++ enum dma_data_direction direction);
++void dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
++ enum dma_data_direction direction);
++int dma_supported(struct device *dev, u64 mask);
++void *dma_alloc_coherent(struct device *dev, size_t size,
++ dma_addr_t *dma_handle, gfp_t gfp);
++void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++ dma_addr_t dma_handle);
++dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
++ enum dma_data_direction direction);
++void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction direction);
++void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
++ size_t size, enum dma_data_direction direction);
++void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
++ size_t size,
++ enum dma_data_direction direction);
++int dma_mapping_error(dma_addr_t dma_addr);
++
++#define flush_write_buffers() do { } while (0)
++static inline void
++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
++ enum dma_data_direction direction)
++{
++ if (swiotlb)
++ swiotlb_sync_sg_for_cpu(dev,sg,nelems,direction);
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
++ enum dma_data_direction direction)
++{
++ if (swiotlb)
++ swiotlb_sync_sg_for_device(dev,sg,nelems,direction);
++ flush_write_buffers();
++}
++#endif /* CONFIG_XEN */
+
+ #define dma_map_page(dev, pg, off, size, dir) \
+ dma_map_single(dev, page_address(pg) + (off), (size), (dir))
+@@ -36,7 +85,9 @@
+ #define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir) \
+ dma_sync_single_for_device(dev, dma_handle, size, dir)
+
++#ifndef CONFIG_XEN
+ #define dma_supported platform_dma_supported
++#endif
+
+ static inline int
+ dma_set_mask (struct device *dev, u64 mask)
+@@ -61,4 +112,29 @@
+
+ #define dma_is_consistent(dma_handle) (1) /* all we do is coherent memory... */
+
++#ifdef CONFIG_XEN
++/* arch/i386/kernel/swiotlb.o requires */
++void contiguous_bitmap_init(unsigned long end_pfn);
++
++static inline int
++address_needs_mapping(struct device *hwdev, dma_addr_t addr)
++{
++ dma_addr_t mask = DMA_64BIT_MASK;
++ /* If the device has a mask, use it, otherwise default to 64 bits */
++ if (hwdev && hwdev->dma_mask)
++ mask = *hwdev->dma_mask;
++ return (addr & ~mask) != 0;
++}
++#else
++#define contiguous_bitmap_init(end_pfn) ((void)end_pfn)
++#endif
++
++static inline int
++range_straddles_page_boundary(void *p, size_t size)
++{
++ extern unsigned long *contiguous_bitmap;
++ return (((((unsigned long)p & ~PAGE_MASK) + size) > PAGE_SIZE) &&
++ !test_bit(__pa(p) >> PAGE_SHIFT, contiguous_bitmap));
++}
++
+ #endif /* _ASM_IA64_DMA_MAPPING_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/fixmap.h linux-2.6.18-xen/include/asm-ia64/fixmap.h
+--- linux-2.6.18.1/include/asm-ia64/fixmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/fixmap.h 2006-09-04 16:31:16.000000000 +0200
+@@ -0,0 +1,2 @@
++#define clear_fixmap(x) do {} while (0)
++#define set_fixmap(x,y) do {} while (0)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/gcc_intrin.h linux-2.6.18-xen/include/asm-ia64/gcc_intrin.h
+--- linux-2.6.18.1/include/asm-ia64/gcc_intrin.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/gcc_intrin.h 2006-09-04 16:31:16.000000000 +0200
+@@ -26,7 +26,7 @@
+
+ register unsigned long ia64_r13 asm ("r13") __attribute_used__;
+
+-#define ia64_setreg(regnum, val) \
++#define __ia64_setreg(regnum, val) \
+ ({ \
+ switch (regnum) { \
+ case _IA64_REG_PSR_L: \
+@@ -55,7 +55,7 @@
+ } \
+ })
+
+-#define ia64_getreg(regnum) \
++#define __ia64_getreg(regnum) \
+ ({ \
+ __u64 ia64_intri_res; \
+ \
+@@ -92,7 +92,7 @@
+
+ #define ia64_hint_pause 0
+
+-#define ia64_hint(mode) \
++#define __ia64_hint(mode) \
+ ({ \
+ switch (mode) { \
+ case ia64_hint_pause: \
+@@ -374,7 +374,7 @@
+
+ #define ia64_invala() asm volatile ("invala" ::: "memory")
+
+-#define ia64_thash(addr) \
++#define __ia64_thash(addr) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("thash %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \
+@@ -394,18 +394,18 @@
+
+ #define ia64_nop(x) asm volatile ("nop %0"::"i"(x));
+
+-#define ia64_itci(addr) asm volatile ("itc.i %0;;" :: "r"(addr) : "memory")
++#define __ia64_itci(addr) asm volatile ("itc.i %0;;" :: "r"(addr) : "memory")
+
+-#define ia64_itcd(addr) asm volatile ("itc.d %0;;" :: "r"(addr) : "memory")
++#define __ia64_itcd(addr) asm volatile ("itc.d %0;;" :: "r"(addr) : "memory")
+
+
+-#define ia64_itri(trnum, addr) asm volatile ("itr.i itr[%0]=%1" \
++#define __ia64_itri(trnum, addr) asm volatile ("itr.i itr[%0]=%1" \
+ :: "r"(trnum), "r"(addr) : "memory")
+
+-#define ia64_itrd(trnum, addr) asm volatile ("itr.d dtr[%0]=%1" \
++#define __ia64_itrd(trnum, addr) asm volatile ("itr.d dtr[%0]=%1" \
+ :: "r"(trnum), "r"(addr) : "memory")
+
+-#define ia64_tpa(addr) \
++#define __ia64_tpa(addr) \
+ ({ \
+ __u64 ia64_pa; \
+ asm volatile ("tpa %0 = %1" : "=r"(ia64_pa) : "r"(addr) : "memory"); \
+@@ -415,22 +415,22 @@
+ #define __ia64_set_dbr(index, val) \
+ asm volatile ("mov dbr[%0]=%1" :: "r"(index), "r"(val) : "memory")
+
+-#define ia64_set_ibr(index, val) \
++#define __ia64_set_ibr(index, val) \
+ asm volatile ("mov ibr[%0]=%1" :: "r"(index), "r"(val) : "memory")
+
+-#define ia64_set_pkr(index, val) \
++#define __ia64_set_pkr(index, val) \
+ asm volatile ("mov pkr[%0]=%1" :: "r"(index), "r"(val) : "memory")
+
+-#define ia64_set_pmc(index, val) \
++#define __ia64_set_pmc(index, val) \
+ asm volatile ("mov pmc[%0]=%1" :: "r"(index), "r"(val) : "memory")
+
+-#define ia64_set_pmd(index, val) \
++#define __ia64_set_pmd(index, val) \
+ asm volatile ("mov pmd[%0]=%1" :: "r"(index), "r"(val) : "memory")
+
+-#define ia64_set_rr(index, val) \
++#define __ia64_set_rr(index, val) \
+ asm volatile ("mov rr[%0]=%1" :: "r"(index), "r"(val) : "memory");
+
+-#define ia64_get_cpuid(index) \
++#define __ia64_get_cpuid(index) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("mov %0=cpuid[%r1]" : "=r"(ia64_intri_res) : "rO"(index)); \
+@@ -444,21 +444,21 @@
+ ia64_intri_res; \
+ })
+
+-#define ia64_get_ibr(index) \
++#define __ia64_get_ibr(index) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("mov %0=ibr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \
+ ia64_intri_res; \
+ })
+
+-#define ia64_get_pkr(index) \
++#define __ia64_get_pkr(index) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("mov %0=pkr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \
+ ia64_intri_res; \
+ })
+
+-#define ia64_get_pmc(index) \
++#define __ia64_get_pmc(index) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("mov %0=pmc[%1]" : "=r"(ia64_intri_res) : "r"(index)); \
+@@ -466,48 +466,48 @@
+ })
+
+
+-#define ia64_get_pmd(index) \
++#define __ia64_get_pmd(index) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("mov %0=pmd[%1]" : "=r"(ia64_intri_res) : "r"(index)); \
+ ia64_intri_res; \
+ })
+
+-#define ia64_get_rr(index) \
++#define __ia64_get_rr(index) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("mov %0=rr[%1]" : "=r"(ia64_intri_res) : "r" (index)); \
+ ia64_intri_res; \
+ })
+
+-#define ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
++#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
+
+
+ #define ia64_sync_i() asm volatile (";; sync.i" ::: "memory")
+
+-#define ia64_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory")
+-#define ia64_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory")
++#define __ia64_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory")
++#define __ia64_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory")
+ #define ia64_sum(mask) asm volatile ("sum %0":: "i"((mask)) : "memory")
+ #define ia64_rum(mask) asm volatile ("rum %0":: "i"((mask)) : "memory")
+
+-#define ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr))
++#define __ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr))
+
+-#define ia64_ptcga(addr, size) \
++#define __ia64_ptcga(addr, size) \
+ do { \
+ asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory"); \
+ ia64_dv_serialize_data(); \
+ } while (0)
+
+-#define ia64_ptcl(addr, size) \
++#define __ia64_ptcl(addr, size) \
+ do { \
+ asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(size) : "memory"); \
+ ia64_dv_serialize_data(); \
+ } while (0)
+
+-#define ia64_ptri(addr, size) \
++#define __ia64_ptri(addr, size) \
+ asm volatile ("ptr.i %0,%1" :: "r"(addr), "r"(size) : "memory")
+
+-#define ia64_ptrd(addr, size) \
++#define __ia64_ptrd(addr, size) \
+ asm volatile ("ptr.d %0,%1" :: "r"(addr), "r"(size) : "memory")
+
+ /* Values for lfhint in ia64_lfetch and ia64_lfetch_fault */
+@@ -589,7 +589,7 @@
+ } \
+ })
+
+-#define ia64_intrin_local_irq_restore(x) \
++#define __ia64_intrin_local_irq_restore(x) \
+ do { \
+ asm volatile (";; cmp.ne p6,p7=%0,r0;;" \
+ "(p6) ssm psr.i;" \
+@@ -598,4 +598,6 @@
+ :: "r"((x)) : "p6", "p7", "memory"); \
+ } while (0)
+
++#define __ia64_get_psr_i() (__ia64_getreg(_IA64_REG_PSR) & 0x4000UL)
++
+ #endif /* _ASM_IA64_GCC_INTRIN_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/hw_irq.h linux-2.6.18-xen/include/asm-ia64/hw_irq.h
+--- linux-2.6.18.1/include/asm-ia64/hw_irq.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/hw_irq.h 2006-09-04 16:31:16.000000000 +0200
+@@ -15,7 +15,11 @@
+ #include <asm/ptrace.h>
+ #include <asm/smp.h>
+
++#ifndef CONFIG_XEN
+ typedef u8 ia64_vector;
++#else
++typedef u16 ia64_vector;
++#endif
+
+ /*
+ * 0 special
+@@ -99,6 +103,12 @@
+
+ static inline void ia64_resend_irq(unsigned int vector)
+ {
++#ifdef CONFIG_XEN
++ extern void resend_irq_on_evtchn(unsigned int i);
++ if (is_running_on_xen())
++ resend_irq_on_evtchn(vector);
++ else
++#endif /* CONFIG_XEN */
+ platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
+ }
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/hypercall.h linux-2.6.18-xen/include/asm-ia64/hypercall.h
+--- linux-2.6.18.1/include/asm-ia64/hypercall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/hypercall.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,423 @@
++/******************************************************************************
++ * hypercall.h
++ *
++ * Linux-specific hypervisor handling.
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __HYPERCALL_H__
++#define __HYPERCALL_H__
++
++#ifndef __HYPERVISOR_H__
++# error "please don't include this file directly"
++#endif
++
++#include <asm/xen/xcom_hcall.h>
++struct xencomm_handle;
++
++/*
++ * Assembler stubs for hyper-calls.
++ */
++
++#define _hypercall0(type, name) \
++({ \
++ long __res; \
++ __asm__ __volatile__ (";;\n" \
++ "mov r2=%1\n" \
++ "break 0x1000 ;;\n" \
++ "mov %0=r8 ;;\n" \
++ : "=r" (__res) \
++ : "J" (__HYPERVISOR_##name) \
++ : "r2","r8", \
++ "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall1(type, name, a1) \
++({ \
++ long __res; \
++ __asm__ __volatile__ (";;\n" \
++ "mov r14=%2\n" \
++ "mov r2=%1\n" \
++ "break 0x1000 ;;\n" \
++ "mov %0=r8 ;;\n" \
++ : "=r" (__res) \
++ : "J" (__HYPERVISOR_##name), \
++ "rI" ((unsigned long)(a1)) \
++ : "r14","r2","r8", \
++ "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall2(type, name, a1, a2) \
++({ \
++ long __res; \
++ __asm__ __volatile__ (";;\n" \
++ "mov r14=%2\n" \
++ "mov r15=%3\n" \
++ "mov r2=%1\n" \
++ "break 0x1000 ;;\n" \
++ "mov %0=r8 ;;\n" \
++ : "=r" (__res) \
++ : "J" (__HYPERVISOR_##name), \
++ "rI" ((unsigned long)(a1)), \
++ "rI" ((unsigned long)(a2)) \
++ : "r14","r15","r2","r8", \
++ "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall3(type, name, a1, a2, a3) \
++({ \
++ long __res; \
++ __asm__ __volatile__ (";;\n" \
++ "mov r14=%2\n" \
++ "mov r15=%3\n" \
++ "mov r16=%4\n" \
++ "mov r2=%1\n" \
++ "break 0x1000 ;;\n" \
++ "mov %0=r8 ;;\n" \
++ : "=r" (__res) \
++ : "J" (__HYPERVISOR_##name), \
++ "rI" ((unsigned long)(a1)), \
++ "rI" ((unsigned long)(a2)), \
++ "rI" ((unsigned long)(a3)) \
++ : "r14","r15","r16","r2","r8", \
++ "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall4(type, name, a1, a2, a3, a4) \
++({ \
++ long __res; \
++ __asm__ __volatile__ (";;\n" \
++ "mov r14=%2\n" \
++ "mov r15=%3\n" \
++ "mov r16=%4\n" \
++ "mov r17=%5\n" \
++ "mov r2=%1\n" \
++ "break 0x1000 ;;\n" \
++ "mov %0=r8 ;;\n" \
++ : "=r" (__res) \
++ : "J" (__HYPERVISOR_##name), \
++ "rI" ((unsigned long)(a1)), \
++ "rI" ((unsigned long)(a2)), \
++ "rI" ((unsigned long)(a3)), \
++ "rI" ((unsigned long)(a4)) \
++ : "r14","r15","r16","r2","r8", \
++ "r17","memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
++({ \
++ long __res; \
++ __asm__ __volatile__ (";;\n" \
++ "mov r14=%2\n" \
++ "mov r15=%3\n" \
++ "mov r16=%4\n" \
++ "mov r17=%5\n" \
++ "mov r18=%6\n" \
++ "mov r2=%1\n" \
++ "break 0x1000 ;;\n" \
++ "mov %0=r8 ;;\n" \
++ : "=r" (__res) \
++ : "J" (__HYPERVISOR_##name), \
++ "rI" ((unsigned long)(a1)), \
++ "rI" ((unsigned long)(a2)), \
++ "rI" ((unsigned long)(a3)), \
++ "rI" ((unsigned long)(a4)), \
++ "rI" ((unsigned long)(a5)) \
++ : "r14","r15","r16","r2","r8", \
++ "r17","r18","memory" ); \
++ (type)__res; \
++})
++
++
++static inline int
++xencomm_arch_hypercall_sched_op(int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, sched_op, cmd, arg);
++}
++
++static inline long
++HYPERVISOR_set_timer_op(u64 timeout)
++{
++ unsigned long timeout_hi = (unsigned long)(timeout >> 32);
++ unsigned long timeout_lo = (unsigned long)timeout;
++ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
++}
++
++static inline int
++xencomm_arch_hypercall_dom0_op(struct xencomm_handle *op)
++{
++ return _hypercall1(int, dom0_op, op);
++}
++
++static inline int
++xencomm_arch_hypercall_sysctl(struct xencomm_handle *op)
++{
++ return _hypercall1(int, sysctl, op);
++}
++
++static inline int
++xencomm_arch_hypercall_domctl(struct xencomm_handle *op)
++{
++ return _hypercall1(int, domctl, op);
++}
++
++static inline int
++xencomm_arch_hypercall_multicall(struct xencomm_handle *call_list,
++ int nr_calls)
++{
++ return _hypercall2(int, multicall, call_list, nr_calls);
++}
++
++static inline int
++xencomm_arch_hypercall_memory_op(unsigned int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, memory_op, cmd, arg);
++}
++
++static inline int
++xencomm_arch_hypercall_event_channel_op(int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, event_channel_op, cmd, arg);
++}
++
++static inline int
++xencomm_arch_hypercall_acm_op(unsigned int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, acm_op, cmd, arg);
++}
++
++static inline int
++xencomm_arch_hypercall_xen_version(int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, xen_version, cmd, arg);
++}
++
++static inline int
++xencomm_arch_hypercall_console_io(int cmd, int count,
++ struct xencomm_handle *str)
++{
++ return _hypercall3(int, console_io, cmd, count, str);
++}
++
++static inline int
++xencomm_arch_hypercall_physdev_op(int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, physdev_op, cmd, arg);
++}
++
++static inline int
++xencomm_arch_hypercall_grant_table_op(unsigned int cmd,
++ struct xencomm_handle *uop,
++ unsigned int count)
++{
++ return _hypercall3(int, grant_table_op, cmd, uop, count);
++}
++
++int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count);
++
++extern int xencomm_arch_hypercall_suspend(struct xencomm_handle *arg);
++
++static inline int
++xencomm_arch_hypercall_callback_op(int cmd, struct xencomm_handle *arg)
++{
++ return _hypercall2(int, callback_op, cmd, arg);
++}
++
++static inline unsigned long
++xencomm_arch_hypercall_hvm_op(int cmd, void *arg)
++{
++ return _hypercall2(unsigned long, hvm_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_physdev_op(int cmd, void *arg)
++{
++ switch (cmd) {
++ case PHYSDEVOP_eoi:
++ return _hypercall1(int, ia64_fast_eoi,
++ ((struct physdev_eoi *)arg)->irq);
++ default:
++ return xencomm_hypercall_physdev_op(cmd, arg);
++ }
++}
++
++extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
++static inline void exit_idle(void) {}
++#define do_IRQ(irq, regs) ({ \
++ irq_enter(); \
++ __do_IRQ((irq), (regs)); \
++ irq_exit(); \
++})
++
++#include <linux/err.h>
++#ifdef CONFIG_XEN
++#include <asm/xen/privop.h>
++#endif /* CONFIG_XEN */
++
++static inline unsigned long
++__HYPERVISOR_ioremap(unsigned long ioaddr, unsigned long size)
++{
++ return _hypercall3(unsigned long, ia64_dom0vp_op,
++ IA64_DOM0VP_ioremap, ioaddr, size);
++}
++
++static inline unsigned long
++HYPERVISOR_ioremap(unsigned long ioaddr, unsigned long size)
++{
++ unsigned long ret = ioaddr;
++ if (is_running_on_xen()) {
++ ret = __HYPERVISOR_ioremap(ioaddr, size);
++ if (unlikely(ret == -ENOSYS))
++ panic("hypercall %s failed with %ld. "
++ "Please check Xen and Linux config mismatch\n",
++ __func__, -ret);
++ else if (unlikely(IS_ERR_VALUE(ret)))
++ ret = ioaddr;
++ }
++ return ret;
++}
++
++static inline unsigned long
++__HYPERVISOR_phystomach(unsigned long gpfn)
++{
++ return _hypercall2(unsigned long, ia64_dom0vp_op,
++ IA64_DOM0VP_phystomach, gpfn);
++}
++
++static inline unsigned long
++HYPERVISOR_phystomach(unsigned long gpfn)
++{
++ unsigned long ret = gpfn;
++ if (is_running_on_xen()) {
++ ret = __HYPERVISOR_phystomach(gpfn);
++ }
++ return ret;
++}
++
++static inline unsigned long
++__HYPERVISOR_machtophys(unsigned long mfn)
++{
++ return _hypercall2(unsigned long, ia64_dom0vp_op,
++ IA64_DOM0VP_machtophys, mfn);
++}
++
++static inline unsigned long
++HYPERVISOR_machtophys(unsigned long mfn)
++{
++ unsigned long ret = mfn;
++ if (is_running_on_xen()) {
++ ret = __HYPERVISOR_machtophys(mfn);
++ }
++ return ret;
++}
++
++static inline unsigned long
++__HYPERVISOR_zap_physmap(unsigned long gpfn, unsigned int extent_order)
++{
++ return _hypercall3(unsigned long, ia64_dom0vp_op,
++ IA64_DOM0VP_zap_physmap, gpfn, extent_order);
++}
++
++static inline unsigned long
++HYPERVISOR_zap_physmap(unsigned long gpfn, unsigned int extent_order)
++{
++ unsigned long ret = 0;
++ if (is_running_on_xen()) {
++ ret = __HYPERVISOR_zap_physmap(gpfn, extent_order);
++ }
++ return ret;
++}
++
++static inline unsigned long
++__HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn,
++ unsigned long flags, domid_t domid)
++{
++ return _hypercall5(unsigned long, ia64_dom0vp_op,
++ IA64_DOM0VP_add_physmap, gpfn, mfn, flags, domid);
++}
++
++static inline unsigned long
++HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn,
++ unsigned long flags, domid_t domid)
++{
++ unsigned long ret = 0;
++ BUG_ON(!is_running_on_xen());//XXX
++ if (is_running_on_xen()) {
++ ret = __HYPERVISOR_add_physmap(gpfn, mfn, flags, domid);
++ }
++ return ret;
++}
++
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
++static inline unsigned long
++HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn,
++ unsigned long assign_start_gpfn,
++ unsigned long expose_size, unsigned long granule_pfn)
++{
++ return _hypercall5(unsigned long, ia64_dom0vp_op,
++ IA64_DOM0VP_expose_p2m, conv_start_gpfn,
++ assign_start_gpfn, expose_size, granule_pfn);
++}
++#endif
++
++// for balloon driver
++#define HYPERVISOR_update_va_mapping(va, new_val, flags) (0)
++
++/* Use xencomm to do hypercalls. */
++#ifdef MODULE
++#define HYPERVISOR_sched_op xencomm_mini_hypercall_sched_op
++#define HYPERVISOR_event_channel_op xencomm_mini_hypercall_event_channel_op
++#define HYPERVISOR_callback_op xencomm_mini_hypercall_callback_op
++#define HYPERVISOR_multicall xencomm_mini_hypercall_multicall
++#define HYPERVISOR_xen_version xencomm_mini_hypercall_xen_version
++#define HYPERVISOR_console_io xencomm_mini_hypercall_console_io
++#define HYPERVISOR_hvm_op xencomm_mini_hypercall_hvm_op
++#ifdef CONFIG_VMX_GUEST
++#define HYPERVISOR_memory_op 0
++#else
++#define HYPERVISOR_memory_op xencomm_mini_hypercall_memory_op
++#endif
++#else
++#define HYPERVISOR_sched_op xencomm_hypercall_sched_op
++#define HYPERVISOR_event_channel_op xencomm_hypercall_event_channel_op
++#define HYPERVISOR_callback_op xencomm_hypercall_callback_op
++#define HYPERVISOR_multicall xencomm_hypercall_multicall
++#define HYPERVISOR_xen_version xencomm_hypercall_xen_version
++#define HYPERVISOR_console_io xencomm_hypercall_console_io
++#define HYPERVISOR_hvm_op xencomm_hypercall_hvm_op
++#define HYPERVISOR_memory_op xencomm_hypercall_memory_op
++#endif
++
++#define HYPERVISOR_suspend xencomm_hypercall_suspend
++
++#endif /* __HYPERCALL_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/hypervisor.h linux-2.6.18-xen/include/asm-ia64/hypervisor.h
+--- linux-2.6.18.1/include/asm-ia64/hypervisor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/hypervisor.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,208 @@
++/******************************************************************************
++ * hypervisor.h
++ *
++ * Linux-specific hypervisor handling.
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __HYPERVISOR_H__
++#define __HYPERVISOR_H__
++
++#ifdef CONFIG_XEN
++extern int running_on_xen;
++#define is_running_on_xen() (running_on_xen)
++#else /* CONFIG_XEN */
++# ifdef CONFIG_VMX_GUEST
++# define is_running_on_xen() (1)
++# else /* CONFIG_VMX_GUEST */
++# define is_running_on_xen() (0)
++# define HYPERVISOR_ioremap(offset, size) (offset)
++# endif /* CONFIG_VMX_GUEST */
++#endif /* CONFIG_XEN */
++
++#if defined(CONFIG_XEN) || defined(CONFIG_VMX_GUEST)
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/dom0_ops.h>
++#include <xen/interface/event_channel.h>
++#include <xen/interface/physdev.h>
++#include <xen/interface/sched.h>
++#include <asm/hypercall.h>
++#include <asm/ptrace.h>
++#include <asm/page.h>
++
++extern shared_info_t *HYPERVISOR_shared_info;
++extern start_info_t *xen_start_info;
++
++void force_evtchn_callback(void);
++
++#ifndef CONFIG_VMX_GUEST
++/* Turn jiffies into Xen system time. XXX Implement me. */
++#define jiffies_to_st(j) 0
++
++static inline int
++HYPERVISOR_yield(
++ void)
++{
++ int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_block(
++ void)
++{
++ int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_shutdown(
++ unsigned int reason)
++{
++ struct sched_shutdown sched_shutdown = {
++ .reason = reason
++ };
++
++ int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_poll(
++ evtchn_port_t *ports, unsigned int nr_ports, u64 timeout)
++{
++ struct sched_poll sched_poll = {
++ .nr_ports = nr_ports,
++ .timeout = jiffies_to_st(timeout)
++ };
++
++ int rc;
++
++ set_xen_guest_handle(sched_poll.ports, ports);
++ rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll);
++
++ return rc;
++}
++
++#include <asm/hypercall.h>
++
++// for drivers/xen/privcmd/privcmd.c
++#define machine_to_phys_mapping 0
++struct vm_area_struct;
++int direct_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid);
++struct file;
++int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
++int privcmd_mmap(struct file * file, struct vm_area_struct * vma);
++#define HAVE_ARCH_PRIVCMD_MMAP
++
++// for drivers/xen/balloon/balloon.c
++#ifdef CONFIG_XEN_SCRUB_PAGES
++#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
++#else
++#define scrub_pages(_p,_n) ((void)0)
++#endif
++#define pte_mfn(_x) pte_pfn(_x)
++#define phys_to_machine_mapping_valid(_x) (1)
++
++#endif /* !CONFIG_VMX_GUEST */
++
++#define __pte_ma(_x) ((pte_t) {(_x)}) /* unmodified use */
++#define pfn_pte_ma(_x,_y) __pte_ma(0) /* unmodified use */
++
++#ifndef CONFIG_VMX_GUEST
++int __xen_create_contiguous_region(unsigned long vstart, unsigned int order, unsigned int address_bits);
++static inline int
++xen_create_contiguous_region(unsigned long vstart,
++ unsigned int order, unsigned int address_bits)
++{
++ int ret = 0;
++ if (is_running_on_xen()) {
++ ret = __xen_create_contiguous_region(vstart, order,
++ address_bits);
++ }
++ return ret;
++}
++
++void __xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
++static inline void
++xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
++{
++ if (is_running_on_xen())
++ __xen_destroy_contiguous_region(vstart, order);
++}
++
++#endif /* !CONFIG_VMX_GUEST */
++
++// for netfront.c, netback.c
++#define MULTI_UVMFLAGS_INDEX 0 //XXX any value
++
++static inline void
++MULTI_update_va_mapping(
++ multicall_entry_t *mcl, unsigned long va,
++ pte_t new_val, unsigned long flags)
++{
++ mcl->op = __HYPERVISOR_update_va_mapping;
++ mcl->result = 0;
++}
++
++static inline void
++MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd,
++ void *uop, unsigned int count)
++{
++ mcl->op = __HYPERVISOR_grant_table_op;
++ mcl->args[0] = cmd;
++ mcl->args[1] = (unsigned long)uop;
++ mcl->args[2] = count;
++}
++
++// for debug
++asmlinkage int xprintk(const char *fmt, ...);
++#define xprintd(fmt, ...) xprintk("%s:%d " fmt, __func__, __LINE__, \
++ ##__VA_ARGS__)
++
++#endif /* CONFIG_XEN || CONFIG_VMX_GUEST */
++
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
++#else
++#define is_initial_xendomain() 0
++#endif
++
++#endif /* __HYPERVISOR_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/intel_intrin.h linux-2.6.18-xen/include/asm-ia64/intel_intrin.h
+--- linux-2.6.18.1/include/asm-ia64/intel_intrin.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/intel_intrin.h 2006-09-04 16:31:16.000000000 +0200
+@@ -16,8 +16,10 @@
+ * intrinsic
+ */
+
+-#define ia64_getreg __getReg
+-#define ia64_setreg __setReg
++#define __ia64_getreg __getReg
++#define __ia64_setreg __setReg
++
++#define __ia64_hint(x)
+
+ #define ia64_hint __hint
+ #define ia64_hint_pause __hint_pause
+@@ -33,16 +35,16 @@
+ #define ia64_getf_exp __getf_exp
+ #define ia64_shrp _m64_shrp
+
+-#define ia64_tpa __tpa
++#define __ia64_tpa __tpa
+ #define ia64_invala __invala
+ #define ia64_invala_gr __invala_gr
+ #define ia64_invala_fr __invala_fr
+ #define ia64_nop __nop
+ #define ia64_sum __sum
+-#define ia64_ssm __ssm
++#define __ia64_ssm __ssm
+ #define ia64_rum __rum
+-#define ia64_rsm __rsm
+-#define ia64_fc __fc
++#define __ia64_rsm __rsm
++#define __ia64_fc __fc
+
+ #define ia64_ldfs __ldfs
+ #define ia64_ldfd __ldfd
+@@ -80,24 +82,24 @@
+
+ #define __ia64_set_dbr(index, val) \
+ __setIndReg(_IA64_REG_INDR_DBR, index, val)
+-#define ia64_set_ibr(index, val) \
++#define __ia64_set_ibr(index, val) \
+ __setIndReg(_IA64_REG_INDR_IBR, index, val)
+-#define ia64_set_pkr(index, val) \
++#define __ia64_set_pkr(index, val) \
+ __setIndReg(_IA64_REG_INDR_PKR, index, val)
+-#define ia64_set_pmc(index, val) \
++#define __ia64_set_pmc(index, val) \
+ __setIndReg(_IA64_REG_INDR_PMC, index, val)
+-#define ia64_set_pmd(index, val) \
++#define __ia64_set_pmd(index, val) \
+ __setIndReg(_IA64_REG_INDR_PMD, index, val)
+-#define ia64_set_rr(index, val) \
++#define __ia64_set_rr(index, val) \
+ __setIndReg(_IA64_REG_INDR_RR, index, val)
+
+-#define ia64_get_cpuid(index) __getIndReg(_IA64_REG_INDR_CPUID, index)
++#define __ia64_get_cpuid(index) __getIndReg(_IA64_REG_INDR_CPUID, index)
+ #define __ia64_get_dbr(index) __getIndReg(_IA64_REG_INDR_DBR, index)
+-#define ia64_get_ibr(index) __getIndReg(_IA64_REG_INDR_IBR, index)
+-#define ia64_get_pkr(index) __getIndReg(_IA64_REG_INDR_PKR, index)
+-#define ia64_get_pmc(index) __getIndReg(_IA64_REG_INDR_PMC, index)
+-#define ia64_get_pmd(index) __getIndReg(_IA64_REG_INDR_PMD, index)
+-#define ia64_get_rr(index) __getIndReg(_IA64_REG_INDR_RR, index)
++#define __ia64_get_ibr(index) __getIndReg(_IA64_REG_INDR_IBR, index)
++#define __ia64_get_pkr(index) __getIndReg(_IA64_REG_INDR_PKR, index)
++#define __ia64_get_pmc(index) __getIndReg(_IA64_REG_INDR_PMC, index)
++#define __ia64_get_pmd(index) __getIndReg(_IA64_REG_INDR_PMD, index)
++#define __ia64_get_rr(index) __getIndReg(_IA64_REG_INDR_RR, index)
+
+ #define ia64_srlz_d __dsrlz
+ #define ia64_srlz_i __isrlz
+@@ -116,18 +118,18 @@
+ #define ia64_ld8_acq __ld8_acq
+
+ #define ia64_sync_i __synci
+-#define ia64_thash __thash
+-#define ia64_ttag __ttag
+-#define ia64_itcd __itcd
+-#define ia64_itci __itci
+-#define ia64_itrd __itrd
+-#define ia64_itri __itri
+-#define ia64_ptce __ptce
+-#define ia64_ptcl __ptcl
+-#define ia64_ptcg __ptcg
+-#define ia64_ptcga __ptcga
+-#define ia64_ptri __ptri
+-#define ia64_ptrd __ptrd
++#define __ia64_thash __thash
++#define __ia64_ttag __ttag
++#define __ia64_itcd __itcd
++#define __ia64_itci __itci
++#define __ia64_itrd __itrd
++#define __ia64_itri __itri
++#define __ia64_ptce __ptce
++#define __ia64_ptcl __ptcl
++#define __ia64_ptcg __ptcg
++#define __ia64_ptcga __ptcga
++#define __ia64_ptri __ptri
++#define __ia64_ptrd __ptrd
+ #define ia64_dep_mi _m64_dep_mi
+
+ /* Values for lfhint in __lfetch and __lfetch_fault */
+@@ -142,16 +144,18 @@
+ #define ia64_lfetch_fault __lfetch_fault
+ #define ia64_lfetch_fault_excl __lfetch_fault_excl
+
+-#define ia64_intrin_local_irq_restore(x) \
++#define __ia64_intrin_local_irq_restore(x) \
+ do { \
+ if ((x) != 0) { \
+- ia64_ssm(IA64_PSR_I); \
++ __ia64_ssm(IA64_PSR_I); \
+ ia64_srlz_d(); \
+ } else { \
+- ia64_rsm(IA64_PSR_I); \
++ __ia64_rsm(IA64_PSR_I); \
+ } \
+ } while (0)
+
++#define __ia64_get_psr_i() (__ia64_getreg(_IA64_REG_PSR) & 0x4000UL)
++
+ #define __builtin_trap() __break(0);
+
+ #endif /* _ASM_IA64_INTEL_INTRIN_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/io.h linux-2.6.18-xen/include/asm-ia64/io.h
+--- linux-2.6.18.1/include/asm-ia64/io.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/io.h 2006-09-04 16:31:16.000000000 +0200
+@@ -66,9 +66,11 @@
+ #define PIO_RESERVED __IA64_UNCACHED_OFFSET
+ #define HAVE_ARCH_PIO_SIZE
+
++#include <asm/hypervisor.h>
+ #include <asm/intrinsics.h>
+ #include <asm/machvec.h>
+ #include <asm/page.h>
++#include <asm/privop.h>
+ #include <asm/system.h>
+ #include <asm-generic/iomap.h>
+
+@@ -96,9 +98,41 @@
+ * The following two macros are deprecated and scheduled for removal.
+ * Please use the PCI-DMA interface defined in <asm/pci.h> instead.
+ */
++#ifndef CONFIG_XEN
+ #define bus_to_virt phys_to_virt
+ #define virt_to_bus virt_to_phys
+ #define page_to_bus page_to_phys
++#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
++#define page_to_pseudophys(page) page_to_phys(page)
++#else /* CONFIG_XEN */
++#define bus_to_virt(bus) \
++ phys_to_virt(machine_to_phys_for_dma(bus))
++#define virt_to_bus(virt) \
++ phys_to_machine_for_dma(virt_to_phys(virt))
++#define page_to_bus(page) \
++ phys_to_machine_for_dma(page_to_pseudophys(page))
++
++#define page_to_pseudophys(page) \
++ ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
++
++/*
++ * Drivers that use page_to_phys() for bus addresses are broken.
++ * This includes:
++ * drivers/ide/cris/ide-cris.c
++ * drivers/scsi/dec_esp.c
++ */
++#define page_to_phys(page) (page_to_pseudophys(page))
++#define bvec_to_bus(bv) (page_to_bus((bv)->bv_page) + \
++ (unsigned long) (bv)->bv_offset)
++#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \
++ (unsigned long) bio_offset((bio)))
++#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \
++ (unsigned long) (bv)->bv_offset)
++#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \
++ (((bvec_to_bus((vec1)) + (vec1)->bv_len) == bvec_to_bus((vec2))) && \
++ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \
++ bvec_to_pseudophys((vec2))))
++#endif /* CONFIG_XEN */
+
+ # endif /* KERNEL */
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/iosapic.h linux-2.6.18-xen/include/asm-ia64/iosapic.h
+--- linux-2.6.18.1/include/asm-ia64/iosapic.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/iosapic.h 2006-09-04 16:31:16.000000000 +0200
+@@ -53,6 +53,7 @@
+
+ #define NR_IOSAPICS 256
+
++#ifndef CONFIG_XEN
+ static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
+ {
+ writel(reg, iosapic + IOSAPIC_REG_SELECT);
+@@ -64,6 +65,7 @@
+ writel(reg, iosapic + IOSAPIC_REG_SELECT);
+ writel(val, iosapic + IOSAPIC_WINDOW);
+ }
++#endif
+
+ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
+ {
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/irq.h linux-2.6.18-xen/include/asm-ia64/irq.h
+--- linux-2.6.18.1/include/asm-ia64/irq.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/irq.h 2006-09-04 16:31:16.000000000 +0200
+@@ -11,8 +11,39 @@
+ * 02/29/00 D.Mosberger moved most things into hw_irq.h
+ */
+
++#ifndef CONFIG_XEN
+ #define NR_IRQS 256
+ #define NR_IRQ_VECTORS NR_IRQS
++#else
++/*
++ * The flat IRQ space is divided into two regions:
++ * 1. A one-to-one mapping of real physical IRQs. This space is only used
++ * if we have physical device-access privilege. This region is at the
++ * start of the IRQ space so that existing device drivers do not need
++ * to be modified to translate physical IRQ numbers into our IRQ space.
++ * 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These
++ * are bound using the provided bind/unbind functions.
++ */
++
++#define PIRQ_BASE 0
++#define NR_PIRQS 256
++
++#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
++#define NR_DYNIRQS 256
++
++#define NR_IRQS (NR_PIRQS + NR_DYNIRQS)
++#define NR_IRQ_VECTORS NR_IRQS
++
++#define pirq_to_irq(_x) ((_x) + PIRQ_BASE)
++#define irq_to_pirq(_x) ((_x) - PIRQ_BASE)
++
++#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE)
++#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE)
++
++#define RESCHEDULE_VECTOR 0
++#define IPI_VECTOR 1
++#define NR_IPIS 2
++#endif /* CONFIG_XEN */
+
+ static __inline__ int
+ irq_canonicalize (int irq)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/machvec_dig.h linux-2.6.18-xen/include/asm-ia64/machvec_dig.h
+--- linux-2.6.18.1/include/asm-ia64/machvec_dig.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/machvec_dig.h 2006-09-21 01:33:32.000000000 +0200
+@@ -13,4 +13,19 @@
+ #define platform_name "dig"
+ #define platform_setup dig_setup
+
++#ifdef CONFIG_XEN
++# define platform_dma_map_sg dma_map_sg
++# define platform_dma_unmap_sg dma_unmap_sg
++# define platform_dma_mapping_error dma_mapping_error
++# define platform_dma_supported dma_supported
++# define platform_dma_alloc_coherent dma_alloc_coherent
++# define platform_dma_free_coherent dma_free_coherent
++# define platform_dma_map_single dma_map_single
++# define platform_dma_unmap_single dma_unmap_single
++# define platform_dma_sync_single_for_cpu \
++ dma_sync_single_for_cpu
++# define platform_dma_sync_single_for_device \
++ dma_sync_single_for_device
++#endif
++
+ #endif /* _ASM_IA64_MACHVEC_DIG_h */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/maddr.h linux-2.6.18-xen/include/asm-ia64/maddr.h
+--- linux-2.6.18.1/include/asm-ia64/maddr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/maddr.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,107 @@
++#ifndef _ASM_IA64_MADDR_H
++#define _ASM_IA64_MADDR_H
++
++#include <linux/kernel.h>
++#include <asm/hypervisor.h>
++#include <xen/features.h>
++#include <xen/interface/xen.h>
++
++#ifdef CONFIG_XEN
++
++#define INVALID_P2M_ENTRY (~0UL)
++
++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
++extern int p2m_initialized;
++extern unsigned long p2m_min_low_pfn;
++extern unsigned long p2m_max_low_pfn;
++extern unsigned long p2m_convert_min_pfn;
++extern unsigned long p2m_convert_max_pfn;
++extern volatile const pte_t* p2m_pte;
++unsigned long p2m_phystomach(unsigned long gpfn);
++#else
++#define p2m_initialized (0)
++#define p2m_phystomach(gpfn) INVALID_MFN
++#endif
++
++/* XXX xen page size != page size */
++static inline unsigned long
++pfn_to_mfn_for_dma(unsigned long pfn)
++{
++ unsigned long mfn;
++ if (p2m_initialized)
++ return p2m_phystomach(pfn);
++ mfn = HYPERVISOR_phystomach(pfn);
++ BUG_ON(mfn == 0); // XXX
++ BUG_ON(mfn == INVALID_P2M_ENTRY); // XXX
++ BUG_ON(mfn == INVALID_MFN);
++ return mfn;
++}
++
++static inline unsigned long
++phys_to_machine_for_dma(unsigned long phys)
++{
++ unsigned long machine =
++ pfn_to_mfn_for_dma(phys >> PAGE_SHIFT) << PAGE_SHIFT;
++ machine |= (phys & ~PAGE_MASK);
++ return machine;
++}
++
++static inline unsigned long
++mfn_to_pfn_for_dma(unsigned long mfn)
++{
++ unsigned long pfn;
++ pfn = HYPERVISOR_machtophys(mfn);
++ BUG_ON(pfn == 0);
++ //BUG_ON(pfn == INVALID_M2P_ENTRY);
++ return pfn;
++}
++
++static inline unsigned long
++machine_to_phys_for_dma(unsigned long machine)
++{
++ unsigned long phys =
++ mfn_to_pfn_for_dma(machine >> PAGE_SHIFT) << PAGE_SHIFT;
++ phys |= (machine & ~PAGE_MASK);
++ return phys;
++}
++
++static inline unsigned long
++mfn_to_local_pfn(unsigned long mfn)
++{
++ extern unsigned long max_mapnr;
++ unsigned long pfn = mfn_to_pfn_for_dma(mfn);
++ if (!pfn_valid(pfn))
++ return INVALID_P2M_ENTRY;
++ return pfn;
++}
++
++#else /* !CONFIG_XEN */
++
++#define pfn_to_mfn_for_dma(pfn) (pfn)
++#define mfn_to_pfn_for_dma(mfn) (mfn)
++#define phys_to_machine_for_dma(phys) (phys)
++#define machine_to_phys_for_dma(machine) (machine)
++#define mfn_to_local_pfn(mfn) (mfn)
++
++#endif /* !CONFIG_XEN */
++
++/* XXX to compile set_phys_to_machine(vaddr, FOREIGN_FRAME(m)) */
++#define FOREIGN_FRAME(m) (INVALID_P2M_ENTRY)
++
++#define mfn_to_pfn(mfn) (mfn)
++#define pfn_to_mfn(pfn) (pfn)
++
++#define mfn_to_virt(mfn) (__va((mfn) << PAGE_SHIFT))
++#define virt_to_mfn(virt) (__pa(virt) >> PAGE_SHIFT)
++#define virt_to_machine(virt) __pa(virt) // for tpmfront.c
++
++#define set_phys_to_machine(pfn, mfn) do { } while (0)
++#ifdef CONFIG_VMX_GUEST
++extern void xen_machphys_update(unsigned long mfn, unsigned long pfn);
++#else /* CONFIG_VMX_GUEST */
++#define xen_machphys_update(mfn, pfn) do { } while (0)
++#endif /* CONFIG_VMX_GUEST */
++
++typedef unsigned long maddr_t; // to compile netback, netfront
++
++#endif /* _ASM_IA64_MADDR_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/meminit.h linux-2.6.18-xen/include/asm-ia64/meminit.h
+--- linux-2.6.18.1/include/asm-ia64/meminit.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/meminit.h 2006-09-04 16:31:16.000000000 +0200
+@@ -16,10 +16,15 @@
+ * - command line string
+ * - kernel code & data
+ * - Kernel memory map built from EFI memory map
++ * - xen start info
+ *
+ * More could be added if necessary
+ */
++#ifndef CONFIG_XEN
+ #define IA64_MAX_RSVD_REGIONS 6
++#else
++#define IA64_MAX_RSVD_REGIONS 7
++#endif
+
+ struct rsvd_region {
+ unsigned long start; /* virtual address of beginning of element */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/page.h linux-2.6.18-xen/include/asm-ia64/page.h
+--- linux-2.6.18.1/include/asm-ia64/page.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/page.h 2006-09-21 01:33:32.000000000 +0200
+@@ -126,7 +126,9 @@
+ # define pfn_valid(pfn) (((pfn) >= min_low_pfn) && ((pfn) < max_low_pfn) && ia64_pfn_valid(pfn))
+ #endif
+
++#ifndef CONFIG_XEN
+ #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
++#endif
+ #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+ #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
+
+@@ -227,5 +229,53 @@
+ (((current->personality & READ_IMPLIES_EXEC) != 0) \
+ ? VM_EXEC : 0))
+
++#ifndef __ASSEMBLY__
++#ifdef CONFIG_XEN
++
++#include <linux/kernel.h>
++#include <asm/hypervisor.h>
++#include <xen/features.h> // to compile netback, netfront
++
++/*
++ * XXX hack!
++ * Linux/IA64 uses PG_arch_1.
++ * This hack will be removed once PG_foreign bit is taken.
++ * #include <xen/foreign_page.h>
++ */
++#ifdef __ASM_XEN_FOREIGN_PAGE_H__
++# error "don't include include/xen/foreign_page.h!"
++#endif
++
++extern struct address_space xen_ia64_foreign_dummy_mapping;
++#define PageForeign(page) \
++ ((page)->mapping == &xen_ia64_foreign_dummy_mapping)
++
++#define SetPageForeign(page, dtor) do { \
++ set_page_private((page), (unsigned long)(dtor)); \
++ (page)->mapping = &xen_ia64_foreign_dummy_mapping; \
++ smp_rmb(); \
++} while (0)
++
++#define ClearPageForeign(page) do { \
++ (page)->mapping = NULL; \
++ smp_rmb(); \
++ set_page_private((page), 0); \
++} while (0)
++
++#define PageForeignDestructor(page) \
++ ( (void (*) (struct page *)) page_private(page) )
++
++#define arch_free_page(_page,_order) \
++({ int foreign = PageForeign(_page); \
++ if (foreign) \
++ (PageForeignDestructor(_page))(_page); \
++ foreign; \
++})
++#define HAVE_ARCH_FREE_PAGE
++
++#include <asm/maddr.h>
++
++#endif /* CONFIG_XEN */
++#endif /* __ASSEMBLY__ */
+ # endif /* __KERNEL__ */
+ #endif /* _ASM_IA64_PAGE_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/pal.h linux-2.6.18-xen/include/asm-ia64/pal.h
+--- linux-2.6.18.1/include/asm-ia64/pal.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/pal.h 2006-09-04 16:31:16.000000000 +0200
+@@ -82,6 +82,7 @@
+ #ifndef __ASSEMBLY__
+
+ #include <linux/types.h>
++#include <asm/processor.h>
+ #include <asm/fpu.h>
+
+ /*
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/pgalloc.h linux-2.6.18-xen/include/asm-ia64/pgalloc.h
+--- linux-2.6.18.1/include/asm-ia64/pgalloc.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/pgalloc.h 2006-09-04 16:31:16.000000000 +0200
+@@ -125,7 +125,11 @@
+ static inline void
+ pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte)
+ {
++#ifndef CONFIG_XEN
+ pmd_val(*pmd_entry) = page_to_phys(pte);
++#else
++ pmd_val(*pmd_entry) = page_to_pseudophys(pte);
++#endif
+ }
+
+ static inline void
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/privop.h linux-2.6.18-xen/include/asm-ia64/privop.h
+--- linux-2.6.18.1/include/asm-ia64/privop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/privop.h 2006-09-04 16:31:17.000000000 +0200
+@@ -0,0 +1,59 @@
++#ifndef _ASM_IA64_PRIVOP_H
++#define _ASM_IA64_PRIVOP_H
++
++/*
++ * Copyright (C) 2005 Hewlett-Packard Co
++ * Dan Magenheimer <dan.magenheimer at hp.com>
++ *
++ */
++
++#ifdef CONFIG_XEN
++#include <asm/xen/privop.h>
++#endif
++
++#ifndef __ASSEMBLY
++
++#ifndef IA64_PARAVIRTUALIZED
++
++#define ia64_getreg __ia64_getreg
++#define ia64_setreg __ia64_setreg
++#define ia64_hint __ia64_hint
++#define ia64_thash __ia64_thash
++#define ia64_itci __ia64_itci
++#define ia64_itcd __ia64_itcd
++#define ia64_itri __ia64_itri
++#define ia64_itrd __ia64_itrd
++#define ia64_tpa __ia64_tpa
++#define ia64_set_ibr __ia64_set_ibr
++#define ia64_set_pkr __ia64_set_pkr
++#define ia64_set_pmc __ia64_set_pmc
++#define ia64_set_pmd __ia64_set_pmd
++#define ia64_set_rr __ia64_set_rr
++#define ia64_get_cpuid __ia64_get_cpuid
++#define ia64_get_ibr __ia64_get_ibr
++#define ia64_get_pkr __ia64_get_pkr
++#define ia64_get_pmc __ia64_get_pmc
++#define ia64_get_pmd __ia64_get_pmd
++#define ia64_get_rr __ia64_get_rr
++#define ia64_fc __ia64_fc
++#define ia64_ssm __ia64_ssm
++#define ia64_rsm __ia64_rsm
++#define ia64_ptce __ia64_ptce
++#define ia64_ptcga __ia64_ptcga
++#define ia64_ptcl __ia64_ptcl
++#define ia64_ptri __ia64_ptri
++#define ia64_ptrd __ia64_ptrd
++#define ia64_get_psr_i __ia64_get_psr_i
++#define ia64_intrin_local_irq_restore __ia64_intrin_local_irq_restore
++#define ia64_pal_halt_light __ia64_pal_halt_light
++#define ia64_leave_kernel __ia64_leave_kernel
++#define ia64_leave_syscall __ia64_leave_syscall
++#define ia64_trace_syscall __ia64_trace_syscall
++#define ia64_switch_to __ia64_switch_to
++#define ia64_pal_call_static __ia64_pal_call_static
++
++#endif /* !IA64_PARAVIRTUALIZED */
++
++#endif /* !__ASSEMBLY */
++
++#endif /* _ASM_IA64_PRIVOP_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/processor.h linux-2.6.18-xen/include/asm-ia64/processor.h
+--- linux-2.6.18.1/include/asm-ia64/processor.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/processor.h 2006-09-04 16:31:17.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/kregs.h>
+ #include <asm/ptrace.h>
+ #include <asm/ustack.h>
++#include <asm/privop.h>
+
+ #define IA64_NUM_DBG_REGS 8
+ /*
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/synch_bitops.h linux-2.6.18-xen/include/asm-ia64/synch_bitops.h
+--- linux-2.6.18.1/include/asm-ia64/synch_bitops.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/synch_bitops.h 2006-09-04 16:31:17.000000000 +0200
+@@ -0,0 +1,61 @@
++#ifndef __XEN_SYNCH_BITOPS_H__
++#define __XEN_SYNCH_BITOPS_H__
++
++/*
++ * Copyright 1992, Linus Torvalds.
++ * Heavily modified to provide guaranteed strong synchronisation
++ * when communicating with Xen or other guest OSes running on other CPUs.
++ */
++
++#define ADDR (*(volatile long *) addr)
++
++static __inline__ void synch_set_bit(int nr, volatile void * addr)
++{
++ set_bit(nr, addr);
++}
++
++static __inline__ void synch_clear_bit(int nr, volatile void * addr)
++{
++ clear_bit(nr, addr);
++}
++
++static __inline__ void synch_change_bit(int nr, volatile void * addr)
++{
++ change_bit(nr, addr);
++}
++
++static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr)
++{
++ return test_and_set_bit(nr, addr);
++}
++
++static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr)
++{
++ return test_and_clear_bit(nr, addr);
++}
++
++static __inline__ int synch_test_and_change_bit(int nr, volatile void * addr)
++{
++ return test_and_change_bit(nr, addr);
++}
++
++static __inline__ int synch_const_test_bit(int nr, const volatile void * addr)
++{
++ return test_bit(nr, addr);
++}
++
++static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
++{
++ return test_bit(nr, addr);
++}
++
++#define synch_cmpxchg ia64_cmpxchg4_acq
++
++#define synch_test_bit(nr,addr) \
++(__builtin_constant_p(nr) ? \
++ synch_const_test_bit((nr),(addr)) : \
++ synch_var_test_bit((nr),(addr)))
++
++#define synch_cmpxchg_subword synch_cmpxchg
++
++#endif /* __XEN_SYNCH_BITOPS_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/system.h linux-2.6.18-xen/include/asm-ia64/system.h
+--- linux-2.6.18.1/include/asm-ia64/system.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-ia64/system.h 2006-09-04 16:31:17.000000000 +0200
+@@ -123,7 +123,7 @@
+ #define __local_irq_save(x) \
+ do { \
+ ia64_stop(); \
+- (x) = ia64_getreg(_IA64_REG_PSR); \
++ (x) = ia64_get_psr_i(); \
+ ia64_stop(); \
+ ia64_rsm(IA64_PSR_I); \
+ } while (0)
+@@ -171,7 +171,7 @@
+ #endif /* !CONFIG_IA64_DEBUG_IRQ */
+
+ #define local_irq_enable() ({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); })
+-#define local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_getreg(_IA64_REG_PSR); })
++#define local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_get_psr_i(); })
+
+ #define irqs_disabled() \
+ ({ \
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/xen/privop.h linux-2.6.18-xen/include/asm-ia64/xen/privop.h
+--- linux-2.6.18.1/include/asm-ia64/xen/privop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/xen/privop.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,301 @@
++#ifndef _ASM_IA64_XEN_PRIVOP_H
++#define _ASM_IA64_XEN_PRIVOP_H
++
++/*
++ * Copyright (C) 2005 Hewlett-Packard Co
++ * Dan Magenheimer <dan.magenheimer at hp.com>
++ *
++ * Paravirtualizations of privileged operations for Xen/ia64
++ *
++ */
++
++
++#include <xen/interface/arch-ia64.h>
++
++#define IA64_PARAVIRTUALIZED
++
++/* At 1 MB, before per-cpu space but still addressable using addl instead
++ of movl. */
++#define XSI_BASE 0xfffffffffff00000
++
++/* Address of mapped regs. */
++#define XMAPPEDREGS_BASE (XSI_BASE + XSI_SIZE)
++
++#ifdef __ASSEMBLY__
++#define XEN_HYPER_RFI break HYPERPRIVOP_RFI
++#define XEN_HYPER_RSM_PSR_DT break HYPERPRIVOP_RSM_DT
++#define XEN_HYPER_SSM_PSR_DT break HYPERPRIVOP_SSM_DT
++#define XEN_HYPER_COVER break HYPERPRIVOP_COVER
++#define XEN_HYPER_ITC_D break HYPERPRIVOP_ITC_D
++#define XEN_HYPER_ITC_I break HYPERPRIVOP_ITC_I
++#define XEN_HYPER_SSM_I break HYPERPRIVOP_SSM_I
++#define XEN_HYPER_GET_IVR break HYPERPRIVOP_GET_IVR
++#define XEN_HYPER_GET_TPR break HYPERPRIVOP_GET_TPR
++#define XEN_HYPER_SET_TPR break HYPERPRIVOP_SET_TPR
++#define XEN_HYPER_EOI break HYPERPRIVOP_EOI
++#define XEN_HYPER_SET_ITM break HYPERPRIVOP_SET_ITM
++#define XEN_HYPER_THASH break HYPERPRIVOP_THASH
++#define XEN_HYPER_PTC_GA break HYPERPRIVOP_PTC_GA
++#define XEN_HYPER_ITR_D break HYPERPRIVOP_ITR_D
++#define XEN_HYPER_GET_RR break HYPERPRIVOP_GET_RR
++#define XEN_HYPER_SET_RR break HYPERPRIVOP_SET_RR
++#define XEN_HYPER_SET_KR break HYPERPRIVOP_SET_KR
++#define XEN_HYPER_FC break HYPERPRIVOP_FC
++#define XEN_HYPER_GET_CPUID break HYPERPRIVOP_GET_CPUID
++#define XEN_HYPER_GET_PMD break HYPERPRIVOP_GET_PMD
++#define XEN_HYPER_GET_EFLAG break HYPERPRIVOP_GET_EFLAG
++#define XEN_HYPER_SET_EFLAG break HYPERPRIVOP_SET_EFLAG
++#define XEN_HYPER_RSM_BE break HYPERPRIVOP_RSM_BE
++#define XEN_HYPER_GET_PSR break HYPERPRIVOP_GET_PSR
++
++#define XSI_IFS (XSI_BASE + XSI_IFS_OFS)
++#define XSI_PRECOVER_IFS (XSI_BASE + XSI_PRECOVER_IFS_OFS)
++#define XSI_INCOMPL_REGFR (XSI_BASE + XSI_INCOMPL_REGFR_OFS)
++#define XSI_IFA (XSI_BASE + XSI_IFA_OFS)
++#define XSI_ISR (XSI_BASE + XSI_ISR_OFS)
++#define XSI_IIM (XSI_BASE + XSI_IIM_OFS)
++#define XSI_ITIR (XSI_BASE + XSI_ITIR_OFS)
++#define XSI_PSR_I_ADDR (XSI_BASE + XSI_PSR_I_ADDR_OFS)
++#define XSI_PSR_IC (XSI_BASE + XSI_PSR_IC_OFS)
++#define XSI_IPSR (XSI_BASE + XSI_IPSR_OFS)
++#define XSI_IIP (XSI_BASE + XSI_IIP_OFS)
++#define XSI_BANK1_R16 (XSI_BASE + XSI_BANK1_R16_OFS)
++#define XSI_BANKNUM (XSI_BASE + XSI_BANKNUM_OFS)
++#define XSI_IHA (XSI_BASE + XSI_IHA_OFS)
++#endif
++
++#ifndef __ASSEMBLY__
++#define XEN_HYPER_SSM_I asm("break %0" : : "i" (HYPERPRIVOP_SSM_I))
++#define XEN_HYPER_GET_IVR asm("break %0" : : "i" (HYPERPRIVOP_GET_IVR))
++
++/************************************************/
++/* Instructions paravirtualized for correctness */
++/************************************************/
++
++/* "fc" and "thash" are privilege-sensitive instructions, meaning they
++ * may have different semantics depending on whether they are executed
++ * at PL0 vs PL!=0. When paravirtualized, these instructions mustn't
++ * be allowed to execute directly, lest incorrect semantics result. */
++extern unsigned long xen_fc(unsigned long addr);
++#define ia64_fc(addr) xen_fc((unsigned long)(addr))
++extern unsigned long xen_thash(unsigned long addr);
++#define ia64_thash(addr) xen_thash((unsigned long)(addr))
++/* Note that "ttag" and "cover" are also privilege-sensitive; "ttag"
++ * is not currently used (though it may be in a long-format VHPT system!)
++ * and the semantics of cover only change if psr.ic is off which is very
++ * rare (and currently non-existent outside of assembly code */
++
++/* There are also privilege-sensitive registers. These registers are
++ * readable at any privilege level but only writable at PL0. */
++extern unsigned long xen_get_cpuid(int index);
++#define ia64_get_cpuid(i) xen_get_cpuid(i)
++extern unsigned long xen_get_pmd(int index);
++#define ia64_get_pmd(i) xen_get_pmd(i)
++extern unsigned long xen_get_eflag(void); /* see xen_ia64_getreg */
++extern void xen_set_eflag(unsigned long); /* see xen_ia64_setreg */
++
++/************************************************/
++/* Instructions paravirtualized for performance */
++/************************************************/
++
++/* Xen uses memory-mapped virtual privileged registers for access to many
++ * performance-sensitive privileged registers. Some, like the processor
++ * status register (psr), are broken up into multiple memory locations.
++ * Others, like "pend", are abstractions based on privileged registers.
++ * "Pend" is guaranteed to be set if reading cr.ivr would return a
++ * (non-spurious) interrupt. */
++#define XEN_MAPPEDREGS ((struct mapped_regs *)XMAPPEDREGS_BASE)
++#define XSI_PSR_I \
++ (*XEN_MAPPEDREGS->interrupt_mask_addr)
++#define xen_get_virtual_psr_i() \
++ (!XSI_PSR_I)
++#define xen_set_virtual_psr_i(_val) \
++ ({ XSI_PSR_I = (uint8_t)(_val) ? 0 : 1; })
++#define xen_set_virtual_psr_ic(_val) \
++ ({ XEN_MAPPEDREGS->interrupt_collection_enabled = _val ? 1 : 0; })
++#define xen_get_virtual_pend() (XEN_MAPPEDREGS->pending_interruption)
++
++/* Hyperprivops are "break" instructions with a well-defined API.
++ * In particular, the virtual psr.ic bit must be off; in this way
++ * it is guaranteed to never conflict with a linux break instruction.
++ * Normally, this is done in a xen stub but this one is frequent enough
++ * that we inline it */
++#define xen_hyper_ssm_i() \
++({ \
++ xen_set_virtual_psr_i(0); \
++ xen_set_virtual_psr_ic(0); \
++ XEN_HYPER_SSM_I; \
++})
++
++/* turning off interrupts can be paravirtualized simply by writing
++ * to a memory-mapped virtual psr.i bit (implemented as a 16-bit bool) */
++#define xen_rsm_i() xen_set_virtual_psr_i(0)
++
++/* turning on interrupts is a bit more complicated.. write to the
++ * memory-mapped virtual psr.i bit first (to avoid race condition),
++ * then if any interrupts were pending, we have to execute a hyperprivop
++ * to ensure the pending interrupt gets delivered; else we're done! */
++#define xen_ssm_i() \
++({ \
++ int old = xen_get_virtual_psr_i(); \
++ xen_set_virtual_psr_i(1); \
++ if (!old && xen_get_virtual_pend()) xen_hyper_ssm_i(); \
++})
++
++#define xen_ia64_intrin_local_irq_restore(x) \
++{ \
++ if (is_running_on_xen()) { \
++ if ((x) & IA64_PSR_I) { xen_ssm_i(); } \
++ else { xen_rsm_i(); } \
++ } \
++ else __ia64_intrin_local_irq_restore((x)); \
++}
++
++#define xen_get_psr_i() \
++( \
++ (is_running_on_xen()) ? \
++ (xen_get_virtual_psr_i() ? IA64_PSR_I : 0) \
++ : __ia64_get_psr_i() \
++)
++
++#define xen_ia64_ssm(mask) \
++{ \
++ if ((mask)==IA64_PSR_I) { \
++ if (is_running_on_xen()) { xen_ssm_i(); } \
++ else { __ia64_ssm(mask); } \
++ } \
++ else { __ia64_ssm(mask); } \
++}
++
++#define xen_ia64_rsm(mask) \
++{ \
++ if ((mask)==IA64_PSR_I) { \
++ if (is_running_on_xen()) { xen_rsm_i(); } \
++ else { __ia64_rsm(mask); } \
++ } \
++ else { __ia64_rsm(mask); } \
++}
++
++
++/* Although all privileged operations can be left to trap and will
++ * be properly handled by Xen, some are frequent enough that we use
++ * hyperprivops for performance. */
++
++extern unsigned long xen_get_ivr(void);
++extern unsigned long xen_get_tpr(void);
++extern void xen_set_itm(unsigned long);
++extern void xen_set_tpr(unsigned long);
++extern void xen_eoi(void);
++extern void xen_set_rr(unsigned long index, unsigned long val);
++extern unsigned long xen_get_rr(unsigned long index);
++extern void xen_set_kr(unsigned long index, unsigned long val);
++extern void xen_ptcga(unsigned long addr, unsigned long size);
++
++/* Note: It may look wrong to test for is_running_on_xen() in each case.
++ * However regnum is always a constant so, as written, the compiler
++ * eliminates the switch statement, whereas is_running_on_xen() must be
++ * tested dynamically. */
++#define xen_ia64_getreg(regnum) \
++({ \
++ __u64 ia64_intri_res; \
++ \
++ switch(regnum) { \
++ case _IA64_REG_CR_IVR: \
++ ia64_intri_res = (is_running_on_xen()) ? \
++ xen_get_ivr() : \
++ __ia64_getreg(regnum); \
++ break; \
++ case _IA64_REG_CR_TPR: \
++ ia64_intri_res = (is_running_on_xen()) ? \
++ xen_get_tpr() : \
++ __ia64_getreg(regnum); \
++ break; \
++ case _IA64_REG_AR_EFLAG: \
++ ia64_intri_res = (is_running_on_xen()) ? \
++ xen_get_eflag() : \
++ __ia64_getreg(regnum); \
++ break; \
++ default: \
++ ia64_intri_res = __ia64_getreg(regnum); \
++ break; \
++ } \
++ ia64_intri_res; \
++})
++
++#define xen_ia64_setreg(regnum,val) \
++({ \
++ switch(regnum) { \
++ case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7: \
++ (is_running_on_xen()) ? \
++ xen_set_kr((regnum-_IA64_REG_AR_KR0), val) : \
++ __ia64_setreg(regnum,val); \
++ break; \
++ case _IA64_REG_CR_ITM: \
++ (is_running_on_xen()) ? \
++ xen_set_itm(val) : \
++ __ia64_setreg(regnum,val); \
++ break; \
++ case _IA64_REG_CR_TPR: \
++ (is_running_on_xen()) ? \
++ xen_set_tpr(val) : \
++ __ia64_setreg(regnum,val); \
++ break; \
++ case _IA64_REG_CR_EOI: \
++ (is_running_on_xen()) ? \
++ xen_eoi() : \
++ __ia64_setreg(regnum,val); \
++ break; \
++ case _IA64_REG_AR_EFLAG: \
++ (is_running_on_xen()) ? \
++ xen_set_eflag(val) : \
++ __ia64_setreg(regnum,val); \
++ break; \
++ default: \
++ __ia64_setreg(regnum,val); \
++ break; \
++ } \
++})
++
++#define ia64_ssm xen_ia64_ssm
++#define ia64_rsm xen_ia64_rsm
++#define ia64_intrin_local_irq_restore xen_ia64_intrin_local_irq_restore
++#define ia64_ptcga xen_ptcga
++#define ia64_set_rr(index,val) xen_set_rr(index,val)
++#define ia64_get_rr(index) xen_get_rr(index)
++#define ia64_getreg xen_ia64_getreg
++#define ia64_setreg xen_ia64_setreg
++#define ia64_get_psr_i xen_get_psr_i
++
++/* the remainder of these are not performance-sensitive so its
++ * OK to not paravirtualize and just take a privop trap and emulate */
++#define ia64_hint __ia64_hint
++#define ia64_set_pmd __ia64_set_pmd
++#define ia64_itci __ia64_itci
++#define ia64_itcd __ia64_itcd
++#define ia64_itri __ia64_itri
++#define ia64_itrd __ia64_itrd
++#define ia64_tpa __ia64_tpa
++#define ia64_set_ibr __ia64_set_ibr
++#define ia64_set_pkr __ia64_set_pkr
++#define ia64_set_pmc __ia64_set_pmc
++#define ia64_get_ibr __ia64_get_ibr
++#define ia64_get_pkr __ia64_get_pkr
++#define ia64_get_pmc __ia64_get_pmc
++#define ia64_ptce __ia64_ptce
++#define ia64_ptcl __ia64_ptcl
++#define ia64_ptri __ia64_ptri
++#define ia64_ptrd __ia64_ptrd
++
++#endif /* !__ASSEMBLY__ */
++
++/* these routines utilize privilege-sensitive or performance-sensitive
++ * privileged instructions so the code must be replaced with
++ * paravirtualized versions */
++#define ia64_pal_halt_light xen_pal_halt_light
++#define ia64_leave_kernel xen_leave_kernel
++#define ia64_leave_syscall xen_leave_syscall
++#define ia64_trace_syscall xen_trace_syscall
++#define ia64_switch_to xen_switch_to
++#define ia64_pal_call_static xen_pal_call_static
++
++#endif /* _ASM_IA64_XEN_PRIVOP_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/xen/xcom_hcall.h linux-2.6.18-xen/include/asm-ia64/xen/xcom_hcall.h
+--- linux-2.6.18.1/include/asm-ia64/xen/xcom_hcall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/xen/xcom_hcall.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,74 @@
++/*
++ * Copyright (C) 2006 Tristan Gingold <tristan.gingold at bull.net>, Bull SAS
++ *
++ * 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 _LINUX_XENCOMM_HCALL_H_
++#define _LINUX_XENCOMM_HCALL_H_
++
++/* These function creates inline descriptor for the parameters and
++ calls the corresponding xencomm_arch_hypercall_X.
++ Architectures should defines HYPERVISOR_xxx as xencomm_hypercall_xxx unless
++ they want to use their own wrapper. */
++extern int xencomm_hypercall_console_io(int cmd, int count, char *str);
++
++extern int xencomm_hypercall_event_channel_op(int cmd, void *op);
++
++extern int xencomm_hypercall_xen_version(int cmd, void *arg);
++
++extern int xencomm_hypercall_physdev_op(int cmd, void *op);
++
++extern int xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
++ unsigned int count);
++
++extern int xencomm_hypercall_sched_op(int cmd, void *arg);
++
++extern int xencomm_hypercall_multicall(void *call_list, int nr_calls);
++
++extern int xencomm_hypercall_callback_op(int cmd, void *arg);
++
++extern int xencomm_hypercall_memory_op(unsigned int cmd, void *arg);
++
++extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg);
++
++extern int xencomm_hypercall_suspend(unsigned long srec);
++
++/* Using mini xencomm. */
++extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str);
++
++extern int xencomm_mini_hypercall_event_channel_op(int cmd, void *op);
++
++extern int xencomm_mini_hypercall_xen_version(int cmd, void *arg);
++
++extern int xencomm_mini_hypercall_physdev_op(int cmd, void *op);
++
++extern int xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op,
++ unsigned int count);
++
++extern int xencomm_mini_hypercall_sched_op(int cmd, void *arg);
++
++extern int xencomm_mini_hypercall_multicall(void *call_list, int nr_calls);
++
++extern int xencomm_mini_hypercall_callback_op(int cmd, void *arg);
++
++extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg);
++
++/* For privcmd. Locally declare argument type to avoid include storm.
++ Type coherency will be checked within privcmd.c */
++struct privcmd_hypercall;
++extern int privcmd_hypercall(struct privcmd_hypercall *hypercall);
++
++#endif /* _LINUX_XENCOMM_HCALL_H_ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-ia64/xen/xencomm.h linux-2.6.18-xen/include/asm-ia64/xen/xencomm.h
+--- linux-2.6.18.1/include/asm-ia64/xen/xencomm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-ia64/xen/xencomm.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * Copyright (C) 2006 Hollis Blanchard <hollisb at us.ibm.com>, IBM Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _LINUX_XENCOMM_H_
++#define _LINUX_XENCOMM_H_
++
++#include <xen/interface/xencomm.h>
++
++#define XENCOMM_MINI_ADDRS 3
++struct xencomm_mini {
++ struct xencomm_desc _desc;
++ uint64_t address[XENCOMM_MINI_ADDRS];
++};
++
++/* To avoid additionnal virt to phys conversion, an opaque structure is
++ presented. */
++struct xencomm_handle;
++
++extern int xencomm_create(void *buffer, unsigned long bytes,
++ struct xencomm_handle **desc, gfp_t type);
++extern void xencomm_free(struct xencomm_handle *desc);
++
++extern int xencomm_create_mini(struct xencomm_mini *area, int *nbr_area,
++ void *buffer, unsigned long bytes,
++ struct xencomm_handle **ret);
++
++/* Translate virtual address to physical address. */
++extern unsigned long xencomm_vaddr_to_paddr(unsigned long vaddr);
++
++/* Inline version. To be used only on linear space (kernel space). */
++static inline struct xencomm_handle *
++xencomm_create_inline(void *buffer)
++{
++ unsigned long paddr;
++
++ paddr = xencomm_vaddr_to_paddr((unsigned long)buffer);
++ return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
++}
++
++#define xen_guest_handle(hnd) ((hnd).p)
++
++#endif /* _LINUX_XENCOMM_H_ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-um/page.h linux-2.6.18-xen/include/asm-um/page.h
+--- linux-2.6.18.1/include/asm-um/page.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-um/page.h 2006-09-04 16:31:18.000000000 +0200
+@@ -114,7 +114,7 @@
+ extern struct page *arch_validate(struct page *page, gfp_t mask, int order);
+ #define HAVE_ARCH_VALIDATE
+
+-extern void arch_free_page(struct page *page, int order);
++extern int arch_free_page(struct page *page, int order);
+ #define HAVE_ARCH_FREE_PAGE
+
+ #include <asm-generic/memory_model.h>
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/apic.h linux-2.6.18-xen/include/asm-x86_64/apic.h
+--- linux-2.6.18.1/include/asm-x86_64/apic.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-x86_64/apic.h 2006-09-04 16:31:18.000000000 +0200
+@@ -98,11 +98,13 @@
+ extern int disable_timer_pin_1;
+
+
++#ifndef CONFIG_XEN
+ void smp_send_timer_broadcast_ipi(void);
+ void switch_APIC_timer_to_ipi(void *cpumask);
+ void switch_ipi_to_APIC_timer(void *cpumask);
+
+ #define ARCH_APICTIMER_STOPS_ON_C3 1
++#endif
+
+ #endif /* CONFIG_X86_LOCAL_APIC */
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/ipi.h linux-2.6.18-xen/include/asm-x86_64/ipi.h
+--- linux-2.6.18.1/include/asm-x86_64/ipi.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/asm-x86_64/ipi.h 2006-09-21 01:33:32.000000000 +0200
+@@ -49,6 +49,7 @@
+ return SET_APIC_DEST_FIELD(mask);
+ }
+
++#ifndef CONFIG_XEN_UNPRIVILEGED_GUEST
+ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
+ {
+ /*
+@@ -113,5 +114,6 @@
+ }
+ local_irq_restore(flags);
+ }
++#endif /* CONFIG_XEN_UNPRIVILEGED_GUEST */
+
+ #endif /* __ASM_IPI_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/arch_hooks.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/arch_hooks.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/arch_hooks.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/arch_hooks.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,27 @@
++#ifndef _ASM_ARCH_HOOKS_H
++#define _ASM_ARCH_HOOKS_H
++
++#include <linux/interrupt.h>
++
++/*
++ * linux/include/asm/arch_hooks.h
++ *
++ * define the architecture specific hooks
++ */
++
++/* these aren't arch hooks, they are generic routines
++ * that can be used by the hooks */
++extern void init_ISA_irqs(void);
++extern void apic_intr_init(void);
++extern void smp_intr_init(void);
++extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++
++/* these are the defined hooks */
++extern void intr_init_hook(void);
++extern void pre_intr_init_hook(void);
++extern void pre_setup_arch_hook(void);
++extern void trap_init_hook(void);
++extern void time_init_hook(void);
++extern void mca_nmi_hook(void);
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/bootsetup.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/bootsetup.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/bootsetup.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/bootsetup.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,42 @@
++
++#ifndef _X86_64_BOOTSETUP_H
++#define _X86_64_BOOTSETUP_H 1
++
++#define BOOT_PARAM_SIZE 4096
++extern char x86_boot_params[BOOT_PARAM_SIZE];
++
++/*
++ * This is set up by the setup-routine at boot-time
++ */
++#define PARAM ((unsigned char *)x86_boot_params)
++#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
++#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
++#define ALT_MEM_K (*(unsigned int *) (PARAM+0x1e0))
++#define E820_MAP_NR (*(char*) (PARAM+E820NR))
++#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
++#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
++#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
++#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
++#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
++#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
++#define SAVED_VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
++#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
++#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
++#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
++#define KERNEL_START (*(unsigned int *) (PARAM+0x214))
++
++#define INITRD_START (__pa(xen_start_info->mod_start))
++#define INITRD_SIZE (xen_start_info->mod_len)
++#define EDID_INFO (*(struct edid_info *) (PARAM+0x440))
++
++#define EDD_NR (*(unsigned char *) (PARAM+EDDNR))
++#define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF))
++#define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
++#define EDD_BUF ((struct edd_info *) (PARAM+EDDBUF))
++#define COMMAND_LINE saved_command_line
++
++#define RAMDISK_IMAGE_START_MASK 0x07FF
++#define RAMDISK_PROMPT_FLAG 0x8000
++#define RAMDISK_LOAD_FLAG 0x4000
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/desc.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/desc.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/desc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/desc.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,263 @@
++/* Written 2000 by Andi Kleen */
++#ifndef __ARCH_DESC_H
++#define __ARCH_DESC_H
++
++#include <linux/threads.h>
++#include <asm/ldt.h>
++
++#ifndef __ASSEMBLY__
++
++#include <linux/string.h>
++#include <linux/smp.h>
++
++#include <asm/segment.h>
++#include <asm/mmu.h>
++
++// 8 byte segment descriptor
++struct desc_struct {
++ u16 limit0;
++ u16 base0;
++ unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
++ unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
++} __attribute__((packed));
++
++struct n_desc_struct {
++ unsigned int a,b;
++};
++
++enum {
++ GATE_INTERRUPT = 0xE,
++ GATE_TRAP = 0xF,
++ GATE_CALL = 0xC,
++};
++
++// 16byte gate
++struct gate_struct {
++ u16 offset_low;
++ u16 segment;
++ unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
++ u16 offset_middle;
++ u32 offset_high;
++ u32 zero1;
++} __attribute__((packed));
++
++#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF)
++#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
++#define PTR_HIGH(x) ((unsigned long)(x) >> 32)
++
++enum {
++ DESC_TSS = 0x9,
++ DESC_LDT = 0x2,
++};
++
++// LDT or TSS descriptor in the GDT. 16 bytes.
++struct ldttss_desc {
++ u16 limit0;
++ u16 base0;
++ unsigned base1 : 8, type : 5, dpl : 2, p : 1;
++ unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
++ u32 base3;
++ u32 zero1;
++} __attribute__((packed));
++
++struct desc_ptr {
++ unsigned short size;
++ unsigned long address;
++} __attribute__((packed)) ;
++
++extern struct desc_ptr idt_descr, cpu_gdt_descr[NR_CPUS];
++
++extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
++
++#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8))
++#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8))
++
++static inline void clear_LDT(void)
++{
++ int cpu = get_cpu();
++
++ /*
++ * NB. We load the default_ldt for lcall7/27 handling on demand, as
++ * it slows down context switching. Noone uses it anyway.
++ */
++ cpu = cpu; /* XXX avoid compiler warning */
++ xen_set_ldt(0UL, 0);
++ put_cpu();
++}
++
++/*
++ * This is the ldt that every process will get unless we need
++ * something other than this.
++ */
++extern struct desc_struct default_ldt[];
++#ifndef CONFIG_X86_NO_IDT
++extern struct gate_struct idt_table[];
++#endif
++extern struct desc_ptr cpu_gdt_descr[];
++
++/* the cpu gdt accessor */
++#define cpu_gdt(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address)
++
++static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist)
++{
++ struct gate_struct s;
++ s.offset_low = PTR_LOW(func);
++ s.segment = __KERNEL_CS;
++ s.ist = ist;
++ s.p = 1;
++ s.dpl = dpl;
++ s.zero0 = 0;
++ s.zero1 = 0;
++ s.type = type;
++ s.offset_middle = PTR_MIDDLE(func);
++ s.offset_high = PTR_HIGH(func);
++ /* does not need to be atomic because it is only done once at setup time */
++ memcpy(adr, &s, 16);
++}
++
++#ifndef CONFIG_X86_NO_IDT
++static inline void set_intr_gate(int nr, void *func)
++{
++ BUG_ON((unsigned)nr > 0xFF);
++ _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0);
++}
++
++static inline void set_intr_gate_ist(int nr, void *func, unsigned ist)
++{
++ BUG_ON((unsigned)nr > 0xFF);
++ _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist);
++}
++
++static inline void set_system_gate(int nr, void *func)
++{
++ BUG_ON((unsigned)nr > 0xFF);
++ _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0);
++}
++
++static inline void set_system_gate_ist(int nr, void *func, unsigned ist)
++{
++ _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist);
++}
++#endif
++
++static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type,
++ unsigned size)
++{
++ struct ldttss_desc d;
++ memset(&d,0,sizeof(d));
++ d.limit0 = size & 0xFFFF;
++ d.base0 = PTR_LOW(tss);
++ d.base1 = PTR_MIDDLE(tss) & 0xFF;
++ d.type = type;
++ d.p = 1;
++ d.limit1 = (size >> 16) & 0xF;
++ d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF;
++ d.base3 = PTR_HIGH(tss);
++ memcpy(ptr, &d, 16);
++}
++
++#ifndef CONFIG_X86_NO_TSS
++static inline void set_tss_desc(unsigned cpu, void *addr)
++{
++ /*
++ * sizeof(unsigned long) coming from an extra "long" at the end
++ * of the iobitmap. See tss_struct definition in processor.h
++ *
++ * -1? seg base+limit should be pointing to the address of the
++ * last valid byte
++ */
++ set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_TSS],
++ (unsigned long)addr, DESC_TSS,
++ IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1);
++}
++#endif
++
++static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
++{
++ set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_LDT], (unsigned long)addr,
++ DESC_LDT, size * 8 - 1);
++}
++
++static inline void set_seg_base(unsigned cpu, int entry, void *base)
++{
++ struct desc_struct *d = &cpu_gdt(cpu)[entry];
++ u32 addr = (u32)(u64)base;
++ BUG_ON((u64)base >> 32);
++ d->base0 = addr & 0xffff;
++ d->base1 = (addr >> 16) & 0xff;
++ d->base2 = (addr >> 24) & 0xff;
++}
++
++#define LDT_entry_a(info) \
++ ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
++/* Don't allow setting of the lm bit. It is useless anyways because
++ 64bit system calls require __USER_CS. */
++#define LDT_entry_b(info) \
++ (((info)->base_addr & 0xff000000) | \
++ (((info)->base_addr & 0x00ff0000) >> 16) | \
++ ((info)->limit & 0xf0000) | \
++ (((info)->read_exec_only ^ 1) << 9) | \
++ ((info)->contents << 10) | \
++ (((info)->seg_not_present ^ 1) << 15) | \
++ ((info)->seg_32bit << 22) | \
++ ((info)->limit_in_pages << 23) | \
++ ((info)->useable << 20) | \
++ /* ((info)->lm << 21) | */ \
++ 0x7000)
++
++#define LDT_empty(info) (\
++ (info)->base_addr == 0 && \
++ (info)->limit == 0 && \
++ (info)->contents == 0 && \
++ (info)->read_exec_only == 1 && \
++ (info)->seg_32bit == 0 && \
++ (info)->limit_in_pages == 0 && \
++ (info)->seg_not_present == 1 && \
++ (info)->useable == 0 && \
++ (info)->lm == 0)
++
++#if TLS_SIZE != 24
++# error update this code.
++#endif
++
++static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
++{
++#if 0
++ u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN);
++ gdt[0] = t->tls_array[0];
++ gdt[1] = t->tls_array[1];
++ gdt[2] = t->tls_array[2];
++#endif
++#define C(i) \
++ HYPERVISOR_update_descriptor(virt_to_machine(&cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]), t->tls_array[i])
++
++ C(0); C(1); C(2);
++#undef C
++}
++
++/*
++ * load one particular LDT into the current CPU
++ */
++static inline void load_LDT_nolock (mm_context_t *pc, int cpu)
++{
++ void *segments = pc->ldt;
++ int count = pc->size;
++
++ if (likely(!count))
++ segments = NULL;
++
++ xen_set_ldt((unsigned long)segments, count);
++}
++
++static inline void load_LDT(mm_context_t *pc)
++{
++ int cpu = get_cpu();
++ load_LDT_nolock(pc, cpu);
++ put_cpu();
++}
++
++extern struct desc_ptr idt_descr;
++
++#endif /* !__ASSEMBLY__ */
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/dma-mapping.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/dma-mapping.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/dma-mapping.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/dma-mapping.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,208 @@
++#ifndef _X8664_DMA_MAPPING_H
++#define _X8664_DMA_MAPPING_H 1
++
++/*
++ * IOMMU interface. See Documentation/DMA-mapping.txt and DMA-API.txt for
++ * documentation.
++ */
++
++
++#include <asm/scatterlist.h>
++#include <asm/io.h>
++#include <asm/swiotlb.h>
++
++struct dma_mapping_ops {
++ int (*mapping_error)(dma_addr_t dma_addr);
++ void* (*alloc_coherent)(struct device *dev, size_t size,
++ dma_addr_t *dma_handle, gfp_t gfp);
++ void (*free_coherent)(struct device *dev, size_t size,
++ void *vaddr, dma_addr_t dma_handle);
++ dma_addr_t (*map_single)(struct device *hwdev, void *ptr,
++ size_t size, int direction);
++ /* like map_single, but doesn't check the device mask */
++ dma_addr_t (*map_simple)(struct device *hwdev, char *ptr,
++ size_t size, int direction);
++ void (*unmap_single)(struct device *dev, dma_addr_t addr,
++ size_t size, int direction);
++ void (*sync_single_for_cpu)(struct device *hwdev,
++ dma_addr_t dma_handle, size_t size,
++ int direction);
++ void (*sync_single_for_device)(struct device *hwdev,
++ dma_addr_t dma_handle, size_t size,
++ int direction);
++ void (*sync_single_range_for_cpu)(struct device *hwdev,
++ dma_addr_t dma_handle, unsigned long offset,
++ size_t size, int direction);
++ void (*sync_single_range_for_device)(struct device *hwdev,
++ dma_addr_t dma_handle, unsigned long offset,
++ size_t size, int direction);
++ void (*sync_sg_for_cpu)(struct device *hwdev,
++ struct scatterlist *sg, int nelems,
++ int direction);
++ void (*sync_sg_for_device)(struct device *hwdev,
++ struct scatterlist *sg, int nelems,
++ int direction);
++ int (*map_sg)(struct device *hwdev, struct scatterlist *sg,
++ int nents, int direction);
++ void (*unmap_sg)(struct device *hwdev,
++ struct scatterlist *sg, int nents,
++ int direction);
++ int (*dma_supported)(struct device *hwdev, u64 mask);
++ int is_phys;
++};
++
++extern dma_addr_t bad_dma_address;
++extern struct dma_mapping_ops* dma_ops;
++extern int iommu_merge;
++
++#if 0
++static inline int valid_dma_direction(int dma_direction)
++{
++ return ((dma_direction == DMA_BIDIRECTIONAL) ||
++ (dma_direction == DMA_TO_DEVICE) ||
++ (dma_direction == DMA_FROM_DEVICE));
++}
++
++static inline int dma_mapping_error(dma_addr_t dma_addr)
++{
++ if (dma_ops->mapping_error)
++ return dma_ops->mapping_error(dma_addr);
++
++ return (dma_addr == bad_dma_address);
++}
++
++extern void *dma_alloc_coherent(struct device *dev, size_t size,
++ dma_addr_t *dma_handle, gfp_t gfp);
++extern 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 *hwdev, void *ptr, size_t size,
++ int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ return dma_ops->map_single(hwdev, ptr, size, direction);
++}
++
++static inline void
++dma_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
++ int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ dma_ops->unmap_single(dev, addr, size, direction);
++}
++
++#define dma_map_page(dev,page,offset,size,dir) \
++ dma_map_single((dev), page_address(page)+(offset), (size), (dir))
++
++#define dma_unmap_page dma_unmap_single
++
++static inline void
++dma_sync_single_for_cpu(struct device *hwdev, dma_addr_t dma_handle,
++ size_t size, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ if (dma_ops->sync_single_for_cpu)
++ dma_ops->sync_single_for_cpu(hwdev, dma_handle, size,
++ direction);
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_single_for_device(struct device *hwdev, dma_addr_t dma_handle,
++ size_t size, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ if (dma_ops->sync_single_for_device)
++ dma_ops->sync_single_for_device(hwdev, dma_handle, size,
++ direction);
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dma_handle,
++ unsigned long offset, size_t size, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ if (dma_ops->sync_single_range_for_cpu) {
++ dma_ops->sync_single_range_for_cpu(hwdev, dma_handle, offset, size, direction);
++ }
++
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_single_range_for_device(struct device *hwdev, dma_addr_t dma_handle,
++ unsigned long offset, size_t size, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ if (dma_ops->sync_single_range_for_device)
++ dma_ops->sync_single_range_for_device(hwdev, dma_handle,
++ offset, size, direction);
++
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
++ int nelems, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ if (dma_ops->sync_sg_for_cpu)
++ dma_ops->sync_sg_for_cpu(hwdev, sg, nelems, direction);
++ flush_write_buffers();
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
++ int nelems, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ if (dma_ops->sync_sg_for_device) {
++ dma_ops->sync_sg_for_device(hwdev, sg, nelems, direction);
++ }
++
++ flush_write_buffers();
++}
++
++static inline int
++dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ return dma_ops->map_sg(hwdev, sg, nents, direction);
++}
++
++static inline void
++dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
++ int direction)
++{
++ BUG_ON(!valid_dma_direction(direction));
++ dma_ops->unmap_sg(hwdev, sg, nents, direction);
++}
++
++extern int dma_supported(struct device *hwdev, u64 mask);
++
++/* same for gart, swiotlb, and nommu */
++static inline int dma_get_cache_alignment(void)
++{
++ return boot_cpu_data.x86_clflush_size;
++}
++
++#define dma_is_consistent(h) 1
++
++extern int dma_set_mask(struct device *dev, u64 mask);
++
++static inline void
++dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction dir)
++{
++ flush_write_buffers();
++}
++
++extern struct device fallback_dev;
++#endif
++
++extern int panic_on_overflow;
++
++#endif /* _X8664_DMA_MAPPING_H */
++
++#include <asm-i386/mach-xen/asm/dma-mapping.h>
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/dmi.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/dmi.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/dmi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/dmi.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,29 @@
++#ifndef _ASM_DMI_H
++#define _ASM_DMI_H 1
++
++#include <asm/io.h>
++
++extern void *dmi_ioremap(unsigned long addr, unsigned long size);
++extern void dmi_iounmap(void *addr, unsigned long size);
++extern void *bt_ioremap(unsigned long addr, unsigned long size);
++extern void bt_iounmap(void *addr, unsigned long size);
++
++#define DMI_MAX_DATA 2048
++
++extern int dmi_alloc_index;
++extern char dmi_alloc_data[DMI_MAX_DATA];
++
++/* This is so early that there is no good way to allocate dynamic memory.
++ Allocate data in an BSS array. */
++static inline void *dmi_alloc(unsigned len)
++{
++ int idx = dmi_alloc_index;
++ if ((dmi_alloc_index += len) > DMI_MAX_DATA)
++ return NULL;
++ return dmi_alloc_data + idx;
++}
++
++#define dmi_ioremap bt_ioremap
++#define dmi_iounmap bt_iounmap
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/e820.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/e820.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/e820.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/e820.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * structures and definitions for the int 15, ax=e820 memory map
++ * scheme.
++ *
++ * In a nutshell, setup.S populates a scratch table in the
++ * empty_zero_block that contains a list of usable address/size
++ * duples. setup.c, this information is transferred into the e820map,
++ * and in init.c/numa.c, that new information is used to mark pages
++ * reserved or not.
++ */
++#ifndef __E820_HEADER
++#define __E820_HEADER
++
++#include <linux/mmzone.h>
++
++#define E820MAP 0x2d0 /* our map */
++#define E820MAX 128 /* number of entries in E820MAP */
++#define E820NR 0x1e8 /* # entries in E820MAP */
++
++#define E820_RAM 1
++#define E820_RESERVED 2
++#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
++#define E820_NVS 4
++
++#define HIGH_MEMORY (1024*1024)
++
++#define LOWMEMSIZE() (0x9f000)
++
++#ifndef __ASSEMBLY__
++struct e820entry {
++ u64 addr; /* start of memory segment */
++ u64 size; /* size of memory segment */
++ u32 type; /* type of memory segment */
++} __attribute__((packed));
++
++struct e820map {
++ int nr_map;
++ struct e820entry map[E820MAX];
++};
++
++extern unsigned long find_e820_area(unsigned long start, unsigned long end,
++ unsigned size);
++extern void add_memory_region(unsigned long start, unsigned long size,
++ int type);
++extern void setup_memory_region(void);
++extern void contig_e820_setup(void);
++extern unsigned long e820_end_of_ram(void);
++extern void e820_reserve_resources(struct e820entry *e820, int nr_map);
++extern void e820_print_map(char *who);
++extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
++extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);
++
++extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
++extern void e820_setup_gap(struct e820entry *e820, int nr_map);
++extern unsigned long e820_hole_size(unsigned long start_pfn,
++ unsigned long end_pfn);
++
++extern void __init parse_memopt(char *p, char **end);
++extern void __init parse_memmapopt(char *p, char **end);
++
++extern struct e820map e820;
++#endif/*!__ASSEMBLY__*/
++
++#endif/*__E820_HEADER*/
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/fixmap.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/fixmap.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/fixmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/fixmap.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ * fixmap.h: compile-time virtual memory allocation
++ *
++ * 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) 1998 Ingo Molnar
++ */
++
++#ifndef _ASM_FIXMAP_H
++#define _ASM_FIXMAP_H
++
++#include <linux/kernel.h>
++#include <asm/apicdef.h>
++#include <xen/gnttab.h>
++#include <asm/page.h>
++#include <asm/vsyscall.h>
++#include <asm/vsyscall32.h>
++#include <asm/acpi.h>
++
++/*
++ * Here we define all the compile-time 'special' virtual
++ * addresses. The point is to have a constant address at
++ * compile time, but to set the physical address only
++ * in the boot process.
++ *
++ * these 'compile-time allocated' memory buffers are
++ * fixed-size 4k pages. (or larger if used with an increment
++ * highger than 1) use fixmap_set(idx,phys) to associate
++ * physical memory with fixmap indices.
++ *
++ * TLB entries of such buffers will not be flushed across
++ * task switches.
++ */
++
++enum fixed_addresses {
++ VSYSCALL_LAST_PAGE,
++ VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
++ VSYSCALL_HPET,
++ FIX_HPET_BASE,
++#ifdef CONFIG_X86_LOCAL_APIC
++ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
++#endif
++#ifdef CONFIG_X86_IO_APIC
++ FIX_IO_APIC_BASE_0,
++ FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
++#endif
++#ifdef CONFIG_ACPI
++ FIX_ACPI_BEGIN,
++ FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
++#endif
++ FIX_SHARED_INFO,
++#define NR_FIX_ISAMAPS 256
++ FIX_ISAMAP_END,
++ FIX_ISAMAP_BEGIN = FIX_ISAMAP_END + NR_FIX_ISAMAPS - 1,
++ __end_of_permanent_fixed_addresses,
++ /* temporary boot-time mappings, used before ioremap() is functional */
++#define NR_FIX_BTMAPS 16
++ FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
++ FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
++ __end_of_fixed_addresses
++};
++
++extern void __set_fixmap (enum fixed_addresses idx,
++ unsigned long phys, pgprot_t flags);
++
++#define set_fixmap(idx, phys) \
++ __set_fixmap(idx, phys, PAGE_KERNEL)
++/*
++ * Some hardware wants to get fixmapped without caching.
++ */
++#define set_fixmap_nocache(idx, phys) \
++ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
++
++#define clear_fixmap(idx) \
++ __set_fixmap(idx, 0, __pgprot(0))
++
++#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE)
++#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
++#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
++
++/* Only covers 32bit vsyscalls currently. Need another set for 64bit. */
++#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL)
++#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
++
++#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
++
++extern void __this_fixmap_does_not_exist(void);
++
++/*
++ * 'index to address' translation. If anyone tries to use the idx
++ * directly without translation, we catch the bug with a NULL-deference
++ * kernel oops. Illegal ranges of incoming indices are caught too.
++ */
++static __always_inline unsigned long fix_to_virt(const unsigned int idx)
++{
++ /*
++ * this branch gets completely eliminated after inlining,
++ * except when someone tries to use fixaddr indices in an
++ * illegal way. (such as mixing up address types or using
++ * out-of-range indices).
++ *
++ * If it doesn't get removed, the linker will complain
++ * loudly with a reasonably clear error message..
++ */
++ if (idx >= __end_of_fixed_addresses)
++ __this_fixmap_does_not_exist();
++
++ return __fix_to_virt(idx);
++}
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/floppy.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/floppy.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/floppy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/floppy.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,206 @@
++/*
++ * Architecture specific parts of the Floppy driver
++ *
++ * 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
++ *
++ * Modifications for Xen are Copyright (c) 2004, Keir Fraser.
++ */
++#ifndef __ASM_XEN_X86_64_FLOPPY_H
++#define __ASM_XEN_X86_64_FLOPPY_H
++
++#include <linux/vmalloc.h>
++
++/*
++ * The DMA channel used by the floppy controller cannot access data at
++ * addresses >= 16MB
++ *
++ * Went back to the 1MB limit, as some people had problems with the floppy
++ * driver otherwise. It doesn't matter much for performance anyway, as most
++ * floppy accesses go through the track buffer.
++ */
++#define _CROSS_64KB(a,s,vdma) \
++(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
++
++/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */
++#include <asm/dma.h>
++#undef MAX_DMA_ADDRESS
++#define MAX_DMA_ADDRESS 0
++#define CROSS_64KB(a,s) (0)
++
++#define fd_inb(port) inb_p(port)
++#define fd_outb(value,port) outb_p(value,port)
++
++#define fd_request_dma() (0)
++#define fd_free_dma() ((void)0)
++#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
++#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
++#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL)
++#define fd_get_dma_residue() vdma_get_dma_residue(FLOPPY_DMA)
++/*
++ * Do not use vmalloc/vfree: floppy_release_irq_and_dma() gets called from
++ * softirq context via motor_off_callback. A generic bug we happen to trigger.
++ */
++#define fd_dma_mem_alloc(size) __get_free_pages(GFP_KERNEL|__GFP_NORETRY, get_order(size))
++#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
++#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
++
++static int virtual_dma_count;
++static int virtual_dma_residue;
++static char *virtual_dma_addr;
++static int virtual_dma_mode;
++static int doing_pdma;
++
++static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
++{
++ register unsigned char st;
++
++#undef TRACE_FLPY_INT
++
++#ifdef TRACE_FLPY_INT
++ static int calls=0;
++ static int bytes=0;
++ static int dma_wait=0;
++#endif
++ if (!doing_pdma)
++ return floppy_interrupt(irq, dev_id, regs);
++
++#ifdef TRACE_FLPY_INT
++ if(!calls)
++ bytes = virtual_dma_count;
++#endif
++
++ {
++ register int lcount;
++ register char *lptr;
++
++ st = 1;
++ for(lcount=virtual_dma_count, lptr=virtual_dma_addr;
++ lcount; lcount--, lptr++) {
++ st=inb(virtual_dma_port+4) & 0xa0 ;
++ if(st != 0xa0)
++ break;
++ if(virtual_dma_mode)
++ outb_p(*lptr, virtual_dma_port+5);
++ else
++ *lptr = inb_p(virtual_dma_port+5);
++ }
++ virtual_dma_count = lcount;
++ virtual_dma_addr = lptr;
++ st = inb(virtual_dma_port+4);
++ }
++
++#ifdef TRACE_FLPY_INT
++ calls++;
++#endif
++ if(st == 0x20)
++ return IRQ_HANDLED;
++ if(!(st & 0x20)) {
++ virtual_dma_residue += virtual_dma_count;
++ virtual_dma_count=0;
++#ifdef TRACE_FLPY_INT
++ printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
++ virtual_dma_count, virtual_dma_residue, calls, bytes,
++ dma_wait);
++ calls = 0;
++ dma_wait=0;
++#endif
++ doing_pdma = 0;
++ floppy_interrupt(irq, dev_id, regs);
++ return IRQ_HANDLED;
++ }
++#ifdef TRACE_FLPY_INT
++ if(!virtual_dma_count)
++ dma_wait++;
++#endif
++ return IRQ_HANDLED;
++}
++
++static void fd_disable_dma(void)
++{
++ doing_pdma = 0;
++ virtual_dma_residue += virtual_dma_count;
++ virtual_dma_count=0;
++}
++
++static int vdma_get_dma_residue(unsigned int dummy)
++{
++ return virtual_dma_count + virtual_dma_residue;
++}
++
++
++static int fd_request_irq(void)
++{
++ return request_irq(FLOPPY_IRQ, floppy_hardint,
++ IRQF_DISABLED, "floppy", NULL);
++}
++
++#if 0
++static unsigned long vdma_mem_alloc(unsigned long size)
++{
++ return (unsigned long) vmalloc(size);
++
++}
++
++static void vdma_mem_free(unsigned long addr, unsigned long size)
++{
++ vfree((void *)addr);
++}
++#endif
++
++static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
++{
++ doing_pdma = 1;
++ virtual_dma_port = io;
++ virtual_dma_mode = (mode == DMA_MODE_WRITE);
++ virtual_dma_addr = addr;
++ virtual_dma_count = size;
++ virtual_dma_residue = 0;
++ return 0;
++}
++
++/* XEN: This trick to force 'virtual DMA' is from include/asm-m68k/floppy.h. */
++#define FDC1 xen_floppy_init()
++static int FDC2 = -1;
++
++static int xen_floppy_init(void)
++{
++ use_virtual_dma = 1;
++ can_use_virtual_dma = 1;
++ return 0x3f0;
++}
++
++/*
++ * Floppy types are stored in the rtc's CMOS RAM and so rtc_lock
++ * is needed to prevent corrupted CMOS RAM in case "insmod floppy"
++ * coincides with another rtc CMOS user. Paul G.
++ */
++#define FLOPPY0_TYPE ({ \
++ unsigned long flags; \
++ unsigned char val; \
++ spin_lock_irqsave(&rtc_lock, flags); \
++ val = (CMOS_READ(0x10) >> 4) & 15; \
++ spin_unlock_irqrestore(&rtc_lock, flags); \
++ val; \
++})
++
++#define FLOPPY1_TYPE ({ \
++ unsigned long flags; \
++ unsigned char val; \
++ spin_lock_irqsave(&rtc_lock, flags); \
++ val = CMOS_READ(0x10) & 15; \
++ spin_unlock_irqrestore(&rtc_lock, flags); \
++ val; \
++})
++
++#define N_FDC 2
++#define N_DRIVE 8
++
++#define FLOPPY_MOTOR_MASK 0xf0
++
++#define EXTRA_FLOPPY_PARAMS
++
++#endif /* __ASM_XEN_X86_64_FLOPPY_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/hw_irq.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/hw_irq.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/hw_irq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/hw_irq.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,136 @@
++#ifndef _ASM_HW_IRQ_H
++#define _ASM_HW_IRQ_H
++
++/*
++ * linux/include/asm/hw_irq.h
++ *
++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
++ *
++ * moved some of the old arch/i386/kernel/irq.h to here. VY
++ *
++ * IRQ/IPI changes taken from work by Thomas Radke
++ * <tomsoft at informatik.tu-chemnitz.de>
++ *
++ * hacked by Andi Kleen for x86-64.
++ */
++
++#ifndef __ASSEMBLY__
++#include <asm/atomic.h>
++#include <asm/irq.h>
++#include <linux/profile.h>
++#include <linux/smp.h>
++
++struct hw_interrupt_type;
++#endif
++
++#define NMI_VECTOR 0x02
++/*
++ * IDT vectors usable for external interrupt sources start
++ * at 0x20:
++ */
++#define FIRST_EXTERNAL_VECTOR 0x20
++
++#define IA32_SYSCALL_VECTOR 0x80
++
++
++/*
++ * Vectors 0x20-0x2f are used for ISA interrupts.
++ */
++
++/*
++ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
++ *
++ * some of the following vectors are 'rare', they are merged
++ * into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
++ * TLB, reschedule and local APIC vectors are performance-critical.
++ */
++#ifndef CONFIG_XEN
++#define SPURIOUS_APIC_VECTOR 0xff
++#define ERROR_APIC_VECTOR 0xfe
++#define RESCHEDULE_VECTOR 0xfd
++#define CALL_FUNCTION_VECTOR 0xfc
++/* fb free - please don't readd KDB here because it's useless
++ (hint - think what a NMI bit does to a vector) */
++#define THERMAL_APIC_VECTOR 0xfa
++#define THRESHOLD_APIC_VECTOR 0xf9
++/* f8 free */
++#define INVALIDATE_TLB_VECTOR_END 0xf7
++#define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f7 used for TLB flush */
++
++#define NUM_INVALIDATE_TLB_VECTORS 8
++#endif
++
++/*
++ * Local APIC timer IRQ vector is on a different priority level,
++ * to work around the 'lost local interrupt if more than 2 IRQ
++ * sources per level' errata.
++ */
++#define LOCAL_TIMER_VECTOR 0xef
++
++/*
++ * First APIC vector available to drivers: (vectors 0x30-0xee)
++ * we start at 0x31 to spread out vectors evenly between priority
++ * levels. (0x80 is the syscall vector)
++ */
++#define FIRST_DEVICE_VECTOR 0x31
++#define FIRST_SYSTEM_VECTOR 0xef /* duplicated in irq.h */
++
++
++#ifndef __ASSEMBLY__
++extern u8 irq_vector[NR_IRQ_VECTORS];
++#define IO_APIC_VECTOR(irq) (irq_vector[irq])
++#define AUTO_ASSIGN -1
++
++/*
++ * Various low-level irq details needed by irq.c, process.c,
++ * time.c, io_apic.c and smp.c
++ *
++ * Interrupt entry/exit code at both C and assembly level
++ */
++
++extern void disable_8259A_irq(unsigned int irq);
++extern void enable_8259A_irq(unsigned int irq);
++extern int i8259A_irq_pending(unsigned int irq);
++extern void make_8259A_irq(unsigned int irq);
++extern void init_8259A(int aeoi);
++extern void FASTCALL(send_IPI_self(int vector));
++extern void init_VISWS_APIC_irqs(void);
++extern void setup_IO_APIC(void);
++extern void disable_IO_APIC(void);
++extern void print_IO_APIC(void);
++extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
++extern void send_IPI(int dest, int vector);
++extern void setup_ioapic_dest(void);
++
++extern unsigned long io_apic_irqs;
++
++extern atomic_t irq_err_count;
++extern atomic_t irq_mis_count;
++
++#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
++
++#define __STR(x) #x
++#define STR(x) __STR(x)
++
++#include <asm/ptrace.h>
++
++#define IRQ_NAME2(nr) nr##_interrupt(void)
++#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
++
++/*
++ * SMP has a few special interrupts for IPI messages
++ */
++
++#define BUILD_IRQ(nr) \
++asmlinkage void IRQ_NAME(nr); \
++__asm__( \
++"\n.p2align\n" \
++"IRQ" #nr "_interrupt:\n\t" \
++ "push $" #nr "-256 ; " \
++ "jmp common_interrupt");
++
++#define platform_legacy_irq(irq) ((irq) < 16)
++
++#endif
++
++#endif /* _ASM_HW_IRQ_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/hypercall.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/hypercall.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/hypercall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/hypercall.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,389 @@
++/******************************************************************************
++ * hypercall.h
++ *
++ * Linux-specific hypervisor handling.
++ *
++ * Copyright (c) 2002-2004, K A Fraser
++ *
++ * 64-bit updates:
++ * Benjamin Liu <benjamin.liu at intel.com>
++ * Jun Nakajima <jun.nakajima at intel.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __HYPERCALL_H__
++#define __HYPERCALL_H__
++
++#include <linux/string.h> /* memcpy() */
++
++#ifndef __HYPERVISOR_H__
++# error "please don't include this file directly"
++#endif
++
++#define __STR(x) #x
++#define STR(x) __STR(x)
++
++#ifdef CONFIG_XEN
++#define HYPERCALL_STR(name) \
++ "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"
++#else
++#define HYPERCALL_STR(name) \
++ "mov hypercall_stubs,%%rax; " \
++ "add $("STR(__HYPERVISOR_##name)" * 32),%%rax; " \
++ "call *%%rax"
++#endif
++
++#define _hypercall0(type, name) \
++({ \
++ long __res; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res) \
++ : \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall1(type, name, a1) \
++({ \
++ long __res, __ign1; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=D" (__ign1) \
++ : "1" ((long)(a1)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall2(type, name, a1, a2) \
++({ \
++ long __res, __ign1, __ign2; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2) \
++ : "1" ((long)(a1)), "2" ((long)(a2)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall3(type, name, a1, a2, a3) \
++({ \
++ long __res, __ign1, __ign2, __ign3; \
++ asm volatile ( \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \
++ "=d" (__ign3) \
++ : "1" ((long)(a1)), "2" ((long)(a2)), \
++ "3" ((long)(a3)) \
++ : "memory" ); \
++ (type)__res; \
++})
++
++#define _hypercall4(type, name, a1, a2, a3, a4) \
++({ \
++ long __res, __ign1, __ign2, __ign3; \
++ asm volatile ( \
++ "movq %7,%%r10; " \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \
++ "=d" (__ign3) \
++ : "1" ((long)(a1)), "2" ((long)(a2)), \
++ "3" ((long)(a3)), "g" ((long)(a4)) \
++ : "memory", "r10" ); \
++ (type)__res; \
++})
++
++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
++({ \
++ long __res, __ign1, __ign2, __ign3; \
++ asm volatile ( \
++ "movq %7,%%r10; movq %8,%%r8; " \
++ HYPERCALL_STR(name) \
++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \
++ "=d" (__ign3) \
++ : "1" ((long)(a1)), "2" ((long)(a2)), \
++ "3" ((long)(a3)), "g" ((long)(a4)), \
++ "g" ((long)(a5)) \
++ : "memory", "r10", "r8" ); \
++ (type)__res; \
++})
++
++static inline int
++HYPERVISOR_set_trap_table(
++ trap_info_t *table)
++{
++ return _hypercall1(int, set_trap_table, table);
++}
++
++static inline int
++HYPERVISOR_mmu_update(
++ mmu_update_t *req, int count, int *success_count, domid_t domid)
++{
++ return _hypercall4(int, mmu_update, req, count, success_count, domid);
++}
++
++static inline int
++HYPERVISOR_mmuext_op(
++ struct mmuext_op *op, int count, int *success_count, domid_t domid)
++{
++ return _hypercall4(int, mmuext_op, op, count, success_count, domid);
++}
++
++static inline int
++HYPERVISOR_set_gdt(
++ unsigned long *frame_list, int entries)
++{
++ return _hypercall2(int, set_gdt, frame_list, entries);
++}
++
++static inline int
++HYPERVISOR_stack_switch(
++ unsigned long ss, unsigned long esp)
++{
++ return _hypercall2(int, stack_switch, ss, esp);
++}
++
++static inline int
++HYPERVISOR_set_callbacks(
++ unsigned long event_address, unsigned long failsafe_address,
++ unsigned long syscall_address)
++{
++ return _hypercall3(int, set_callbacks,
++ event_address, failsafe_address, syscall_address);
++}
++
++static inline int
++HYPERVISOR_fpu_taskswitch(
++ int set)
++{
++ return _hypercall1(int, fpu_taskswitch, set);
++}
++
++static inline int
++HYPERVISOR_sched_op_compat(
++ int cmd, unsigned long arg)
++{
++ return _hypercall2(int, sched_op_compat, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_sched_op(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, sched_op, cmd, arg);
++}
++
++static inline long
++HYPERVISOR_set_timer_op(
++ u64 timeout)
++{
++ return _hypercall1(long, set_timer_op, timeout);
++}
++
++static inline int
++HYPERVISOR_dom0_op(
++ dom0_op_t *dom0_op)
++{
++ dom0_op->interface_version = DOM0_INTERFACE_VERSION;
++ return _hypercall1(int, dom0_op, dom0_op);
++}
++
++static inline int
++HYPERVISOR_set_debugreg(
++ int reg, unsigned long value)
++{
++ return _hypercall2(int, set_debugreg, reg, value);
++}
++
++static inline unsigned long
++HYPERVISOR_get_debugreg(
++ int reg)
++{
++ return _hypercall1(unsigned long, get_debugreg, reg);
++}
++
++static inline int
++HYPERVISOR_update_descriptor(
++ unsigned long ma, unsigned long word)
++{
++ return _hypercall2(int, update_descriptor, ma, word);
++}
++
++static inline int
++HYPERVISOR_memory_op(
++ unsigned int cmd, void *arg)
++{
++ return _hypercall2(int, memory_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_multicall(
++ void *call_list, int nr_calls)
++{
++ return _hypercall2(int, multicall, call_list, nr_calls);
++}
++
++static inline int
++HYPERVISOR_update_va_mapping(
++ unsigned long va, pte_t new_val, unsigned long flags)
++{
++ return _hypercall3(int, update_va_mapping, va, new_val.pte, flags);
++}
++
++static inline int
++HYPERVISOR_event_channel_op(
++ int cmd, void *arg)
++{
++ int rc = _hypercall2(int, event_channel_op, cmd, arg);
++ if (unlikely(rc == -ENOSYS)) {
++ struct evtchn_op op;
++ op.cmd = cmd;
++ memcpy(&op.u, arg, sizeof(op.u));
++ rc = _hypercall1(int, event_channel_op_compat, &op);
++ memcpy(arg, &op.u, sizeof(op.u));
++ }
++ return rc;
++}
++
++static inline int
++HYPERVISOR_acm_op(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, acm_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_xen_version(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, xen_version, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_console_io(
++ int cmd, int count, char *str)
++{
++ return _hypercall3(int, console_io, cmd, count, str);
++}
++
++static inline int
++HYPERVISOR_physdev_op(
++ int cmd, void *arg)
++{
++ int rc = _hypercall2(int, physdev_op, cmd, arg);
++ if (unlikely(rc == -ENOSYS)) {
++ struct physdev_op op;
++ op.cmd = cmd;
++ memcpy(&op.u, arg, sizeof(op.u));
++ rc = _hypercall1(int, physdev_op_compat, &op);
++ memcpy(arg, &op.u, sizeof(op.u));
++ }
++ return rc;
++}
++
++static inline int
++HYPERVISOR_grant_table_op(
++ unsigned int cmd, void *uop, unsigned int count)
++{
++ return _hypercall3(int, grant_table_op, cmd, uop, count);
++}
++
++static inline int
++HYPERVISOR_update_va_mapping_otherdomain(
++ unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
++{
++ return _hypercall4(int, update_va_mapping_otherdomain, va,
++ new_val.pte, flags, domid);
++}
++
++static inline int
++HYPERVISOR_vm_assist(
++ unsigned int cmd, unsigned int type)
++{
++ return _hypercall2(int, vm_assist, cmd, type);
++}
++
++static inline int
++HYPERVISOR_vcpu_op(
++ int cmd, int vcpuid, void *extra_args)
++{
++ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
++}
++
++static inline int
++HYPERVISOR_set_segment_base(
++ int reg, unsigned long value)
++{
++ return _hypercall2(int, set_segment_base, reg, value);
++}
++
++static inline int
++HYPERVISOR_suspend(
++ unsigned long srec)
++{
++ struct sched_shutdown sched_shutdown = {
++ .reason = SHUTDOWN_suspend
++ };
++
++ int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown,
++ &sched_shutdown, srec);
++
++ if (rc == -ENOSYS)
++ rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown,
++ SHUTDOWN_suspend, srec);
++
++ return rc;
++}
++
++static inline int
++HYPERVISOR_nmi_op(
++ unsigned long op, void *arg)
++{
++ return _hypercall2(int, nmi_op, op, arg);
++}
++
++static inline unsigned long
++HYPERVISOR_hvm_op(
++ int op, void *arg)
++{
++ return _hypercall2(unsigned long, hvm_op, op, arg);
++}
++
++static inline int
++HYPERVISOR_callback_op(
++ int cmd, void *arg)
++{
++ return _hypercall2(int, callback_op, cmd, arg);
++}
++
++static inline int
++HYPERVISOR_xenoprof_op(
++ int op, void *arg)
++{
++ return _hypercall2(int, xenoprof_op, op, arg);
++}
++
++#endif /* __HYPERCALL_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/hypervisor.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/hypervisor.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/hypervisor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/hypervisor.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,2 @@
++
++#include <asm-i386/mach-xen/asm/hypervisor.h>
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/io.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/io.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/io.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/io.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,327 @@
++#ifndef _ASM_IO_H
++#define _ASM_IO_H
++
++#include <asm/fixmap.h>
++
++/*
++ * This file contains the definitions for the x86 IO instructions
++ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
++ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
++ * versions of the single-IO instructions (inb_p/inw_p/..).
++ *
++ * This file is not meant to be obfuscating: it's just complicated
++ * to (a) handle it all in a way that makes gcc able to optimize it
++ * as well as possible and (b) trying to avoid writing the same thing
++ * over and over again with slight variations and possibly making a
++ * mistake somewhere.
++ */
++
++/*
++ * Thanks to James van Artsdalen for a better timing-fix than
++ * the two short jumps: using outb's to a nonexistent port seems
++ * to guarantee better timings even on fast machines.
++ *
++ * On the other hand, I'd like to be sure of a non-existent port:
++ * I feel a bit unsafe about using 0x80 (should be safe, though)
++ *
++ * Linus
++ */
++
++ /*
++ * Bit simplified and optimized by Jan Hubicka
++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
++ *
++ * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
++ * isa_read[wl] and isa_write[wl] fixed
++ * - Arnaldo Carvalho de Melo <acme at conectiva.com.br>
++ */
++
++#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
++
++#ifdef REALLY_SLOW_IO
++#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
++#else
++#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
++#endif
++
++/*
++ * Talk about misusing macros..
++ */
++#define __OUT1(s,x) \
++static inline void out##s(unsigned x value, unsigned short port) {
++
++#define __OUT2(s,s1,s2) \
++__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
++
++#define __OUT(s,s1,x) \
++__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
++__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
++
++#define __IN1(s) \
++static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
++
++#define __IN2(s,s1,s2) \
++__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
++
++#define __IN(s,s1,i...) \
++__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
++__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
++
++#define __INS(s) \
++static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
++{ __asm__ __volatile__ ("rep ; ins" #s \
++: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
++
++#define __OUTS(s) \
++static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
++{ __asm__ __volatile__ ("rep ; outs" #s \
++: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
++
++#define RETURN_TYPE unsigned char
++__IN(b,"")
++#undef RETURN_TYPE
++#define RETURN_TYPE unsigned short
++__IN(w,"")
++#undef RETURN_TYPE
++#define RETURN_TYPE unsigned int
++__IN(l,"")
++#undef RETURN_TYPE
++
++__OUT(b,"b",char)
++__OUT(w,"w",short)
++__OUT(l,,int)
++
++__INS(b)
++__INS(w)
++__INS(l)
++
++__OUTS(b)
++__OUTS(w)
++__OUTS(l)
++
++#define IO_SPACE_LIMIT 0xffff
++
++#if defined(__KERNEL__) && __x86_64__
++
++#include <linux/vmalloc.h>
++
++#ifndef __i386__
++/*
++ * Change virtual addresses to physical addresses and vv.
++ * These are pretty trivial
++ */
++static inline unsigned long virt_to_phys(volatile void * address)
++{
++ return __pa(address);
++}
++
++static inline void * phys_to_virt(unsigned long address)
++{
++ return __va(address);
++}
++
++#define virt_to_bus(_x) phys_to_machine(__pa(_x))
++#define bus_to_virt(_x) __va(machine_to_phys(_x))
++#endif
++
++/*
++ * Change "struct page" to physical address.
++ */
++#define page_to_pseudophys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
++#define page_to_phys(page) (phys_to_machine(page_to_pseudophys(page)))
++#define page_to_bus(page) (phys_to_machine(page_to_pseudophys(page)))
++
++#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \
++ (unsigned long) bio_offset((bio)))
++#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \
++ (unsigned long) (bv)->bv_offset)
++
++#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \
++ (((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) && \
++ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \
++ bvec_to_pseudophys((vec2))))
++
++#include <asm-generic/iomap.h>
++
++extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags);
++
++static inline void __iomem * ioremap (unsigned long offset, unsigned long size)
++{
++ return __ioremap(offset, size, 0);
++}
++
++extern void *early_ioremap(unsigned long addr, unsigned long size);
++extern void early_iounmap(void *addr, unsigned long size);
++
++/*
++ * This one maps high address device memory and turns off caching for that area.
++ * it's useful if some control registers are in such an area and write combining
++ * or read caching is not desirable:
++ */
++extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
++extern void iounmap(volatile void __iomem *addr);
++
++/*
++ * ISA I/O bus memory addresses are 1:1 with the physical address.
++ */
++
++#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x
++#define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x
++#define isa_bus_to_virt(_x) (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + (_x))
++
++/*
++ * However PCI ones are not necessarily 1:1 and therefore these interfaces
++ * are forbidden in portable PCI drivers.
++ *
++ * Allow them on x86 for legacy drivers, though.
++ */
++#define virt_to_bus(_x) phys_to_machine(__pa(_x))
++#define bus_to_virt(_x) __va(machine_to_phys(_x))
++
++/*
++ * readX/writeX() are used to access memory mapped devices. On some
++ * architectures the memory mapped IO stuff needs to be accessed
++ * differently. On the x86 architecture, we just read/write the
++ * memory location directly.
++ */
++
++static inline __u8 __readb(const volatile void __iomem *addr)
++{
++ return *(__force volatile __u8 *)addr;
++}
++static inline __u16 __readw(const volatile void __iomem *addr)
++{
++ return *(__force volatile __u16 *)addr;
++}
++static __always_inline __u32 __readl(const volatile void __iomem *addr)
++{
++ return *(__force volatile __u32 *)addr;
++}
++static inline __u64 __readq(const volatile void __iomem *addr)
++{
++ return *(__force volatile __u64 *)addr;
++}
++#define readb(x) __readb(x)
++#define readw(x) __readw(x)
++#define readl(x) __readl(x)
++#define readq(x) __readq(x)
++#define readb_relaxed(a) readb(a)
++#define readw_relaxed(a) readw(a)
++#define readl_relaxed(a) readl(a)
++#define readq_relaxed(a) readq(a)
++#define __raw_readb readb
++#define __raw_readw readw
++#define __raw_readl readl
++#define __raw_readq readq
++
++#define mmiowb()
++
++static inline void __writel(__u32 b, volatile void __iomem *addr)
++{
++ *(__force volatile __u32 *)addr = b;
++}
++static inline void __writeq(__u64 b, volatile void __iomem *addr)
++{
++ *(__force volatile __u64 *)addr = b;
++}
++static inline void __writeb(__u8 b, volatile void __iomem *addr)
++{
++ *(__force volatile __u8 *)addr = b;
++}
++static inline void __writew(__u16 b, volatile void __iomem *addr)
++{
++ *(__force volatile __u16 *)addr = b;
++}
++#define writeq(val,addr) __writeq((val),(addr))
++#define writel(val,addr) __writel((val),(addr))
++#define writew(val,addr) __writew((val),(addr))
++#define writeb(val,addr) __writeb((val),(addr))
++#define __raw_writeb writeb
++#define __raw_writew writew
++#define __raw_writel writel
++#define __raw_writeq writeq
++
++void __memcpy_fromio(void*,unsigned long,unsigned);
++void __memcpy_toio(unsigned long,const void*,unsigned);
++
++static inline void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len)
++{
++ __memcpy_fromio(to,(unsigned long)from,len);
++}
++static inline void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len)
++{
++ __memcpy_toio((unsigned long)to,from,len);
++}
++
++void memset_io(volatile void __iomem *a, int b, size_t c);
++
++/*
++ * ISA space is 'always mapped' on a typical x86 system, no need to
++ * explicitly ioremap() it. The fact that the ISA IO space is mapped
++ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
++ * are physical addresses. The following constant pointer can be
++ * used as the IO-area pointer (it can be iounmapped as well, so the
++ * analogy with PCI is quite large):
++ */
++#define __ISA_IO_base ((char __iomem *)(fix_to_virt(FIX_ISAMAP_BEGIN)))
++
++/*
++ * Again, x86-64 does not require mem IO specific function.
++ */
++
++#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
++
++/**
++ * check_signature - find BIOS signatures
++ * @io_addr: mmio address to check
++ * @signature: signature block
++ * @length: length of signature
++ *
++ * Perform a signature comparison with the mmio address io_addr. This
++ * address should have been obtained by ioremap.
++ * Returns 1 on a match.
++ */
++
++static inline int check_signature(void __iomem *io_addr,
++ const unsigned char *signature, int length)
++{
++ int retval = 0;
++ do {
++ if (readb(io_addr) != *signature)
++ goto out;
++ io_addr++;
++ signature++;
++ length--;
++ } while (length);
++ retval = 1;
++out:
++ return retval;
++}
++
++/* Nothing to do */
++
++#define dma_cache_inv(_start,_size) do { } while (0)
++#define dma_cache_wback(_start,_size) do { } while (0)
++#define dma_cache_wback_inv(_start,_size) do { } while (0)
++
++#define flush_write_buffers()
++
++extern int iommu_bio_merge;
++#define BIO_VMERGE_BOUNDARY iommu_bio_merge
++
++/*
++ * 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__ */
++
++#define ARCH_HAS_DEV_MEM
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/irqflags.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/irqflags.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/irqflags.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/irqflags.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,65 @@
++/*
++ * include/asm-x86_64/irqflags.h
++ *
++ * IRQ flags handling
++ *
++ * This file gets included from lowlevel asm headers too, to provide
++ * wrapped versions of the local_irq_*() APIs, based on the
++ * raw_local_irq_*() functions from the lowlevel headers.
++ */
++#ifndef _ASM_IRQFLAGS_H
++#define _ASM_IRQFLAGS_H
++
++#ifndef __ASSEMBLY__
++/*
++ * Interrupt control:
++ */
++
++unsigned long __raw_local_save_flags(void);
++#define raw_local_save_flags(flags) \
++ do { (flags) = __raw_local_save_flags(); } while (0)
++
++void raw_local_irq_restore(unsigned long flags);
++void raw_local_irq_disable(void);
++void raw_local_irq_enable(void);
++
++static inline int raw_irqs_disabled_flags(unsigned long flags)
++{
++ return flags != 0;
++}
++
++/*
++ * For spinlocks, etc.:
++ */
++
++unsigned long __raw_local_irq_save(void);
++
++#define raw_local_irq_save(flags) \
++ do { (flags) = __raw_local_irq_save(); } while (0)
++
++int raw_irqs_disabled(void);
++
++/*
++ * Used in the idle loop; sti takes one instruction cycle
++ * to complete:
++ */
++void raw_safe_halt(void);
++
++
++/*
++ * Used when interrupts are already enabled or to
++ * shutdown the processor:
++ */
++void halt(void);
++
++#else /* __ASSEMBLY__: */
++# ifdef CONFIG_TRACE_IRQFLAGS
++# define TRACE_IRQS_ON call trace_hardirqs_on_thunk
++# define TRACE_IRQS_OFF call trace_hardirqs_off_thunk
++# else
++# define TRACE_IRQS_ON
++# define TRACE_IRQS_OFF
++# endif
++#endif
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/irq.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/irq.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/irq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/irq.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,38 @@
++#ifndef _ASM_IRQ_H
++#define _ASM_IRQ_H
++
++/*
++ * linux/include/asm/irq.h
++ *
++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
++ *
++ * IRQ/IPI changes taken from work by Thomas Radke
++ * <tomsoft at informatik.tu-chemnitz.de>
++ */
++
++#include <linux/sched.h>
++/* include comes from machine specific directory */
++#include "irq_vectors.h"
++#include <asm/thread_info.h>
++
++static __inline__ int irq_canonicalize(int irq)
++{
++ return ((irq == 2) ? 9 : irq);
++}
++
++#ifdef CONFIG_X86_LOCAL_APIC
++#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
++#endif
++
++#define KDB_VECTOR 0xf9
++
++# define irq_ctx_init(cpu) do { } while (0)
++
++#ifdef CONFIG_HOTPLUG_CPU
++#include <linux/cpumask.h>
++extern void fixup_irqs(cpumask_t map);
++#endif
++
++#define __ARCH_HAS_DO_SOFTIRQ 1
++
++#endif /* _ASM_IRQ_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/maddr.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/maddr.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/maddr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/maddr.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,139 @@
++#ifndef _X86_64_MADDR_H
++#define _X86_64_MADDR_H
++
++#include <xen/features.h>
++#include <xen/interface/xen.h>
++
++/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
++#define INVALID_P2M_ENTRY (~0UL)
++#define FOREIGN_FRAME_BIT (1UL<<63)
++#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
++
++#ifdef CONFIG_XEN
++
++extern unsigned long *phys_to_machine_mapping;
++
++#undef machine_to_phys_mapping
++extern unsigned long *machine_to_phys_mapping;
++extern unsigned int machine_to_phys_order;
++
++static inline unsigned long pfn_to_mfn(unsigned long pfn)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return pfn;
++ return phys_to_machine_mapping[(unsigned int)(pfn)] &
++ ~FOREIGN_FRAME_BIT;
++}
++
++static inline int phys_to_machine_mapping_valid(unsigned long pfn)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return 1;
++ return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
++}
++
++static inline unsigned long mfn_to_pfn(unsigned long mfn)
++{
++ unsigned long pfn;
++
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return mfn;
++
++ if (unlikely((mfn >> machine_to_phys_order) != 0))
++ return end_pfn;
++
++ /* The array access can fail (e.g., device space beyond end of RAM). */
++ asm (
++ "1: movq %1,%0\n"
++ "2:\n"
++ ".section .fixup,\"ax\"\n"
++ "3: movq %2,%0\n"
++ " jmp 2b\n"
++ ".previous\n"
++ ".section __ex_table,\"a\"\n"
++ " .align 8\n"
++ " .quad 1b,3b\n"
++ ".previous"
++ : "=r" (pfn)
++ : "m" (machine_to_phys_mapping[mfn]), "m" (end_pfn) );
++
++ return pfn;
++}
++
++/*
++ * We detect special mappings in one of two ways:
++ * 1. If the MFN is an I/O page then Xen will set the m2p entry
++ * to be outside our maximum possible pseudophys range.
++ * 2. If the MFN belongs to a different domain then we will certainly
++ * not have MFN in our p2m table. Conversely, if the page is ours,
++ * then we'll have p2m(m2p(MFN))==MFN.
++ * If we detect a special mapping then it doesn't have a 'struct page'.
++ * We force !pfn_valid() by returning an out-of-range pointer.
++ *
++ * NB. These checks require that, for any MFN that is not in our reservation,
++ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
++ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
++ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
++ *
++ * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
++ * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
++ * require. In all the cases we care about, the FOREIGN_FRAME bit is
++ * masked (e.g., pfn_to_mfn()) so behaviour there is correct.
++ */
++static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
++{
++ unsigned long pfn = mfn_to_pfn(mfn);
++ if ((pfn < end_pfn)
++ && !xen_feature(XENFEAT_auto_translated_physmap)
++ && (phys_to_machine_mapping[pfn] != mfn))
++ return end_pfn; /* force !pfn_valid() */
++ return pfn;
++}
++
++static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
++{
++ if (xen_feature(XENFEAT_auto_translated_physmap)) {
++ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
++ return;
++ }
++ phys_to_machine_mapping[pfn] = mfn;
++}
++
++#else /* !CONFIG_XEN */
++
++#define pfn_to_mfn(pfn) (pfn)
++#define mfn_to_pfn(mfn) (mfn)
++#define mfn_to_local_pfn(mfn) (mfn)
++#define set_phys_to_machine(pfn, mfn) BUG_ON((pfn) != (mfn))
++#define phys_to_machine_mapping_valid(pfn) (1)
++
++#endif /* !CONFIG_XEN */
++
++/* Definitions for machine and pseudophysical addresses. */
++typedef unsigned long paddr_t;
++typedef unsigned long maddr_t;
++
++static inline maddr_t phys_to_machine(paddr_t phys)
++{
++ maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
++ machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
++ return machine;
++}
++
++static inline paddr_t machine_to_phys(maddr_t machine)
++{
++ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
++ phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
++ return phys;
++}
++
++/* VIRT <-> MACHINE conversion */
++#define virt_to_machine(v) (phys_to_machine(__pa(v)))
++#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
++#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
++
++#define __pte_ma(x) ((pte_t) { (x) } )
++#define pfn_pte_ma(pfn, prot) __pte_ma((((pfn) << PAGE_SHIFT) | pgprot_val(prot)) & __supported_pte_mask)
++
++#endif /* _X86_64_MADDR_H */
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/mmu_context.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/mmu_context.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/mmu_context.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/mmu_context.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,135 @@
++#ifndef __X86_64_MMU_CONTEXT_H
++#define __X86_64_MMU_CONTEXT_H
++
++#include <asm/desc.h>
++#include <asm/atomic.h>
++#include <asm/pgalloc.h>
++#include <asm/page.h>
++#include <asm/pda.h>
++#include <asm/pgtable.h>
++#include <asm/tlbflush.h>
++
++/*
++ * possibly do the LDT unload here?
++ */
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
++void destroy_context(struct mm_struct *mm);
++
++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
++{
++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN)
++ if (read_pda(mmu_state) == TLBSTATE_OK)
++ write_pda(mmu_state, TLBSTATE_LAZY);
++#endif
++}
++
++#define prepare_arch_switch(next) __prepare_arch_switch()
++
++static inline void __prepare_arch_switch(void)
++{
++ /*
++ * Save away %es, %ds, %fs and %gs. Must happen before reload
++ * of cr3/ldt (i.e., not in __switch_to).
++ */
++ __asm__ __volatile__ (
++ "mov %%es,%0 ; mov %%ds,%1 ; mov %%fs,%2 ; mov %%gs,%3"
++ : "=m" (current->thread.es),
++ "=m" (current->thread.ds),
++ "=m" (current->thread.fsindex),
++ "=m" (current->thread.gsindex) );
++
++ if (current->thread.ds)
++ __asm__ __volatile__ ( "movl %0,%%ds" : : "r" (0) );
++
++ if (current->thread.es)
++ __asm__ __volatile__ ( "movl %0,%%es" : : "r" (0) );
++
++ if (current->thread.fsindex) {
++ __asm__ __volatile__ ( "movl %0,%%fs" : : "r" (0) );
++ current->thread.fs = 0;
++ }
++
++ if (current->thread.gsindex) {
++ load_gs_index(0);
++ current->thread.gs = 0;
++ }
++}
++
++extern void mm_pin(struct mm_struct *mm);
++extern void mm_unpin(struct mm_struct *mm);
++void mm_pin_all(void);
++
++static inline void load_cr3(pgd_t *pgd)
++{
++ asm volatile("movq %0,%%cr3" :: "r" (phys_to_machine(__pa(pgd))) :
++ "memory");
++}
++
++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
++ struct task_struct *tsk)
++{
++ unsigned cpu = smp_processor_id();
++ struct mmuext_op _op[3], *op = _op;
++
++ if (likely(prev != next)) {
++ BUG_ON(!next->context.pinned);
++
++ /* stop flush ipis for the previous mm */
++ cpu_clear(cpu, prev->cpu_vm_mask);
++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN)
++ write_pda(mmu_state, TLBSTATE_OK);
++ write_pda(active_mm, next);
++#endif
++ cpu_set(cpu, next->cpu_vm_mask);
++
++ /* load_cr3(next->pgd) */
++ op->cmd = MMUEXT_NEW_BASEPTR;
++ op->arg1.mfn = pfn_to_mfn(__pa(next->pgd) >> PAGE_SHIFT);
++ op++;
++
++ /* xen_new_user_pt(__pa(__user_pgd(next->pgd))) */
++ op->cmd = MMUEXT_NEW_USER_BASEPTR;
++ op->arg1.mfn = pfn_to_mfn(__pa(__user_pgd(next->pgd)) >> PAGE_SHIFT);
++ op++;
++
++ if (unlikely(next->context.ldt != prev->context.ldt)) {
++ /* load_LDT_nolock(&next->context, cpu) */
++ op->cmd = MMUEXT_SET_LDT;
++ op->arg1.linear_addr = (unsigned long)next->context.ldt;
++ op->arg2.nr_ents = next->context.size;
++ op++;
++ }
++
++ BUG_ON(HYPERVISOR_mmuext_op(_op, op-_op, NULL, DOMID_SELF));
++ }
++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN)
++ else {
++ write_pda(mmu_state, TLBSTATE_OK);
++ if (read_pda(active_mm) != next)
++ out_of_line_bug();
++ if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
++ /* We were in lazy tlb mode and leave_mm disabled
++ * tlb flush IPI delivery. We must reload CR3
++ * to make sure to use no freed page tables.
++ */
++ load_cr3(next->pgd);
++ xen_new_user_pt(__pa(__user_pgd(next->pgd)));
++ load_LDT_nolock(&next->context, cpu);
++ }
++ }
++#endif
++}
++
++#define deactivate_mm(tsk,mm) do { \
++ load_gs_index(0); \
++ asm volatile("movl %0,%%fs"::"r"(0)); \
++} while(0)
++
++static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
++{
++ if (!next->context.pinned)
++ mm_pin(next);
++ switch_mm(prev, next, NULL);
++}
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/mmu.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/mmu.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/mmu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/mmu.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,38 @@
++#ifndef __x86_64_MMU_H
++#define __x86_64_MMU_H
++
++#include <linux/spinlock.h>
++#include <asm/semaphore.h>
++
++/*
++ * The x86_64 doesn't have a mmu context, but
++ * we put the segment information here.
++ *
++ * cpu_vm_mask is used to optimize ldt flushing.
++ */
++typedef struct {
++ void *ldt;
++ rwlock_t ldtlock;
++ int size;
++ struct semaphore sem;
++#ifdef CONFIG_XEN
++ unsigned pinned:1;
++ unsigned has_foreign_mappings:1;
++ struct list_head unpinned;
++#endif
++} mm_context_t;
++
++#ifdef CONFIG_XEN
++extern struct list_head mm_unpinned;
++extern spinlock_t mm_unpinned_lock;
++
++/* mm/memory.c:exit_mmap hook */
++extern void _arch_exit_mmap(struct mm_struct *mm);
++#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm)
++
++/* kernel/fork.c:dup_mmap hook */
++extern void _arch_dup_mmap(struct mm_struct *mm);
++#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm))
++#endif
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/msr.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/msr.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/msr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/msr.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,399 @@
++#ifndef X86_64_MSR_H
++#define X86_64_MSR_H 1
++
++#ifndef __ASSEMBLY__
++/*
++ * Access to machine-specific registers (available on 586 and better only)
++ * Note: the rd* operations modify the parameters directly (without using
++ * pointer indirection), this allows gcc to optimize better
++ */
++
++#define rdmsr(msr,val1,val2) \
++ __asm__ __volatile__("rdmsr" \
++ : "=a" (val1), "=d" (val2) \
++ : "c" (msr))
++
++
++#define rdmsrl(msr,val) do { unsigned long a__,b__; \
++ __asm__ __volatile__("rdmsr" \
++ : "=a" (a__), "=d" (b__) \
++ : "c" (msr)); \
++ val = a__ | (b__<<32); \
++} while(0)
++
++#define wrmsr(msr,val1,val2) \
++ __asm__ __volatile__("wrmsr" \
++ : /* no outputs */ \
++ : "c" (msr), "a" (val1), "d" (val2))
++
++#define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32)
++
++/* wrmsr with exception handling */
++#define wrmsr_safe(msr,a,b) ({ int ret__; \
++ asm volatile("2: wrmsr ; xorl %0,%0\n" \
++ "1:\n\t" \
++ ".section .fixup,\"ax\"\n\t" \
++ "3: movl %4,%0 ; jmp 1b\n\t" \
++ ".previous\n\t" \
++ ".section __ex_table,\"a\"\n" \
++ " .align 8\n\t" \
++ " .quad 2b,3b\n\t" \
++ ".previous" \
++ : "=a" (ret__) \
++ : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \
++ ret__; })
++
++#define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
++
++#define rdmsr_safe(msr,a,b) \
++ ({ int ret__; \
++ asm volatile ("1: rdmsr\n" \
++ "2:\n" \
++ ".section .fixup,\"ax\"\n" \
++ "3: movl %4,%0\n" \
++ " jmp 2b\n" \
++ ".previous\n" \
++ ".section __ex_table,\"a\"\n" \
++ " .align 8\n" \
++ " .quad 1b,3b\n" \
++ ".previous":"=&bDS" (ret__), "=a"(*(a)), "=d"(*(b))\
++ :"c"(msr), "i"(-EIO), "0"(0)); \
++ ret__; })
++
++#define rdtsc(low,high) \
++ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
++
++#define rdtscl(low) \
++ __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
++
++#define rdtscll(val) do { \
++ unsigned int __a,__d; \
++ asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
++ (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
++} while(0)
++
++#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
++
++#define rdpmc(counter,low,high) \
++ __asm__ __volatile__("rdpmc" \
++ : "=a" (low), "=d" (high) \
++ : "c" (counter))
++
++static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx,
++ unsigned int *ecx, unsigned int *edx)
++{
++ __asm__(XEN_CPUID
++ : "=a" (*eax),
++ "=b" (*ebx),
++ "=c" (*ecx),
++ "=d" (*edx)
++ : "0" (op));
++}
++
++/* Some CPUID calls want 'count' to be placed in ecx */
++static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
++ int *edx)
++{
++ __asm__(XEN_CPUID
++ : "=a" (*eax),
++ "=b" (*ebx),
++ "=c" (*ecx),
++ "=d" (*edx)
++ : "0" (op), "c" (count));
++}
++
++/*
++ * CPUID functions returning a single datum
++ */
++static inline unsigned int cpuid_eax(unsigned int op)
++{
++ unsigned int eax;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax)
++ : "0" (op)
++ : "bx", "cx", "dx");
++ return eax;
++}
++static inline unsigned int cpuid_ebx(unsigned int op)
++{
++ unsigned int eax, ebx;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax), "=b" (ebx)
++ : "0" (op)
++ : "cx", "dx" );
++ return ebx;
++}
++static inline unsigned int cpuid_ecx(unsigned int op)
++{
++ unsigned int eax, ecx;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax), "=c" (ecx)
++ : "0" (op)
++ : "bx", "dx" );
++ return ecx;
++}
++static inline unsigned int cpuid_edx(unsigned int op)
++{
++ unsigned int eax, edx;
++
++ __asm__(XEN_CPUID
++ : "=a" (eax), "=d" (edx)
++ : "0" (op)
++ : "bx", "cx");
++ return edx;
++}
++
++#define MSR_IA32_UCODE_WRITE 0x79
++#define MSR_IA32_UCODE_REV 0x8b
++
++
++#endif
++
++/* AMD/K8 specific MSRs */
++#define MSR_EFER 0xc0000080 /* extended feature register */
++#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */
++#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */
++#define MSR_CSTAR 0xc0000083 /* compatibility mode SYSCALL target */
++#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */
++#define MSR_FS_BASE 0xc0000100 /* 64bit GS base */
++#define MSR_GS_BASE 0xc0000101 /* 64bit FS base */
++#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow (or USER_GS from kernel) */
++/* EFER bits: */
++#define _EFER_SCE 0 /* SYSCALL/SYSRET */
++#define _EFER_LME 8 /* Long mode enable */
++#define _EFER_LMA 10 /* Long mode active (read-only) */
++#define _EFER_NX 11 /* No execute enable */
++
++#define EFER_SCE (1<<_EFER_SCE)
++#define EFER_LME (1<<_EFER_LME)
++#define EFER_LMA (1<<_EFER_LMA)
++#define EFER_NX (1<<_EFER_NX)
++
++/* Intel MSRs. Some also available on other CPUs */
++#define MSR_IA32_TSC 0x10
++#define MSR_IA32_PLATFORM_ID 0x17
++
++#define MSR_IA32_PERFCTR0 0xc1
++#define MSR_IA32_PERFCTR1 0xc2
++
++#define MSR_MTRRcap 0x0fe
++#define MSR_IA32_BBL_CR_CTL 0x119
++
++#define MSR_IA32_SYSENTER_CS 0x174
++#define MSR_IA32_SYSENTER_ESP 0x175
++#define MSR_IA32_SYSENTER_EIP 0x176
++
++#define MSR_IA32_MCG_CAP 0x179
++#define MSR_IA32_MCG_STATUS 0x17a
++#define MSR_IA32_MCG_CTL 0x17b
++
++#define MSR_IA32_EVNTSEL0 0x186
++#define MSR_IA32_EVNTSEL1 0x187
++
++#define MSR_IA32_DEBUGCTLMSR 0x1d9
++#define MSR_IA32_LASTBRANCHFROMIP 0x1db
++#define MSR_IA32_LASTBRANCHTOIP 0x1dc
++#define MSR_IA32_LASTINTFROMIP 0x1dd
++#define MSR_IA32_LASTINTTOIP 0x1de
++
++#define MSR_MTRRfix64K_00000 0x250
++#define MSR_MTRRfix16K_80000 0x258
++#define MSR_MTRRfix16K_A0000 0x259
++#define MSR_MTRRfix4K_C0000 0x268
++#define MSR_MTRRfix4K_C8000 0x269
++#define MSR_MTRRfix4K_D0000 0x26a
++#define MSR_MTRRfix4K_D8000 0x26b
++#define MSR_MTRRfix4K_E0000 0x26c
++#define MSR_MTRRfix4K_E8000 0x26d
++#define MSR_MTRRfix4K_F0000 0x26e
++#define MSR_MTRRfix4K_F8000 0x26f
++#define MSR_MTRRdefType 0x2ff
++
++#define MSR_IA32_MC0_CTL 0x400
++#define MSR_IA32_MC0_STATUS 0x401
++#define MSR_IA32_MC0_ADDR 0x402
++#define MSR_IA32_MC0_MISC 0x403
++
++#define MSR_P6_PERFCTR0 0xc1
++#define MSR_P6_PERFCTR1 0xc2
++#define MSR_P6_EVNTSEL0 0x186
++#define MSR_P6_EVNTSEL1 0x187
++
++/* K7/K8 MSRs. Not complete. See the architecture manual for a more complete list. */
++#define MSR_K7_EVNTSEL0 0xC0010000
++#define MSR_K7_PERFCTR0 0xC0010004
++#define MSR_K7_EVNTSEL1 0xC0010001
++#define MSR_K7_PERFCTR1 0xC0010005
++#define MSR_K7_EVNTSEL2 0xC0010002
++#define MSR_K7_PERFCTR2 0xC0010006
++#define MSR_K7_EVNTSEL3 0xC0010003
++#define MSR_K7_PERFCTR3 0xC0010007
++#define MSR_K8_TOP_MEM1 0xC001001A
++#define MSR_K8_TOP_MEM2 0xC001001D
++#define MSR_K8_SYSCFG 0xC0010010
++#define MSR_K8_HWCR 0xC0010015
++
++/* K6 MSRs */
++#define MSR_K6_EFER 0xC0000080
++#define MSR_K6_STAR 0xC0000081
++#define MSR_K6_WHCR 0xC0000082
++#define MSR_K6_UWCCR 0xC0000085
++#define MSR_K6_PSOR 0xC0000087
++#define MSR_K6_PFIR 0xC0000088
++
++/* Centaur-Hauls/IDT defined MSRs. */
++#define MSR_IDT_FCR1 0x107
++#define MSR_IDT_FCR2 0x108
++#define MSR_IDT_FCR3 0x109
++#define MSR_IDT_FCR4 0x10a
++
++#define MSR_IDT_MCR0 0x110
++#define MSR_IDT_MCR1 0x111
++#define MSR_IDT_MCR2 0x112
++#define MSR_IDT_MCR3 0x113
++#define MSR_IDT_MCR4 0x114
++#define MSR_IDT_MCR5 0x115
++#define MSR_IDT_MCR6 0x116
++#define MSR_IDT_MCR7 0x117
++#define MSR_IDT_MCR_CTRL 0x120
++
++/* VIA Cyrix defined MSRs*/
++#define MSR_VIA_FCR 0x1107
++#define MSR_VIA_LONGHAUL 0x110a
++#define MSR_VIA_RNG 0x110b
++#define MSR_VIA_BCR2 0x1147
++
++/* Intel defined MSRs. */
++#define MSR_IA32_P5_MC_ADDR 0
++#define MSR_IA32_P5_MC_TYPE 1
++#define MSR_IA32_PLATFORM_ID 0x17
++#define MSR_IA32_EBL_CR_POWERON 0x2a
++
++#define MSR_IA32_APICBASE 0x1b
++#define MSR_IA32_APICBASE_BSP (1<<8)
++#define MSR_IA32_APICBASE_ENABLE (1<<11)
++#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
++
++/* P4/Xeon+ specific */
++#define MSR_IA32_MCG_EAX 0x180
++#define MSR_IA32_MCG_EBX 0x181
++#define MSR_IA32_MCG_ECX 0x182
++#define MSR_IA32_MCG_EDX 0x183
++#define MSR_IA32_MCG_ESI 0x184
++#define MSR_IA32_MCG_EDI 0x185
++#define MSR_IA32_MCG_EBP 0x186
++#define MSR_IA32_MCG_ESP 0x187
++#define MSR_IA32_MCG_EFLAGS 0x188
++#define MSR_IA32_MCG_EIP 0x189
++#define MSR_IA32_MCG_RESERVED 0x18A
++
++#define MSR_P6_EVNTSEL0 0x186
++#define MSR_P6_EVNTSEL1 0x187
++
++#define MSR_IA32_PERF_STATUS 0x198
++#define MSR_IA32_PERF_CTL 0x199
++
++#define MSR_IA32_THERM_CONTROL 0x19a
++#define MSR_IA32_THERM_INTERRUPT 0x19b
++#define MSR_IA32_THERM_STATUS 0x19c
++#define MSR_IA32_MISC_ENABLE 0x1a0
++
++#define MSR_IA32_DEBUGCTLMSR 0x1d9
++#define MSR_IA32_LASTBRANCHFROMIP 0x1db
++#define MSR_IA32_LASTBRANCHTOIP 0x1dc
++#define MSR_IA32_LASTINTFROMIP 0x1dd
++#define MSR_IA32_LASTINTTOIP 0x1de
++
++#define MSR_IA32_MC0_CTL 0x400
++#define MSR_IA32_MC0_STATUS 0x401
++#define MSR_IA32_MC0_ADDR 0x402
++#define MSR_IA32_MC0_MISC 0x403
++
++/* Pentium IV performance counter MSRs */
++#define MSR_P4_BPU_PERFCTR0 0x300
++#define MSR_P4_BPU_PERFCTR1 0x301
++#define MSR_P4_BPU_PERFCTR2 0x302
++#define MSR_P4_BPU_PERFCTR3 0x303
++#define MSR_P4_MS_PERFCTR0 0x304
++#define MSR_P4_MS_PERFCTR1 0x305
++#define MSR_P4_MS_PERFCTR2 0x306
++#define MSR_P4_MS_PERFCTR3 0x307
++#define MSR_P4_FLAME_PERFCTR0 0x308
++#define MSR_P4_FLAME_PERFCTR1 0x309
++#define MSR_P4_FLAME_PERFCTR2 0x30a
++#define MSR_P4_FLAME_PERFCTR3 0x30b
++#define MSR_P4_IQ_PERFCTR0 0x30c
++#define MSR_P4_IQ_PERFCTR1 0x30d
++#define MSR_P4_IQ_PERFCTR2 0x30e
++#define MSR_P4_IQ_PERFCTR3 0x30f
++#define MSR_P4_IQ_PERFCTR4 0x310
++#define MSR_P4_IQ_PERFCTR5 0x311
++#define MSR_P4_BPU_CCCR0 0x360
++#define MSR_P4_BPU_CCCR1 0x361
++#define MSR_P4_BPU_CCCR2 0x362
++#define MSR_P4_BPU_CCCR3 0x363
++#define MSR_P4_MS_CCCR0 0x364
++#define MSR_P4_MS_CCCR1 0x365
++#define MSR_P4_MS_CCCR2 0x366
++#define MSR_P4_MS_CCCR3 0x367
++#define MSR_P4_FLAME_CCCR0 0x368
++#define MSR_P4_FLAME_CCCR1 0x369
++#define MSR_P4_FLAME_CCCR2 0x36a
++#define MSR_P4_FLAME_CCCR3 0x36b
++#define MSR_P4_IQ_CCCR0 0x36c
++#define MSR_P4_IQ_CCCR1 0x36d
++#define MSR_P4_IQ_CCCR2 0x36e
++#define MSR_P4_IQ_CCCR3 0x36f
++#define MSR_P4_IQ_CCCR4 0x370
++#define MSR_P4_IQ_CCCR5 0x371
++#define MSR_P4_ALF_ESCR0 0x3ca
++#define MSR_P4_ALF_ESCR1 0x3cb
++#define MSR_P4_BPU_ESCR0 0x3b2
++#define MSR_P4_BPU_ESCR1 0x3b3
++#define MSR_P4_BSU_ESCR0 0x3a0
++#define MSR_P4_BSU_ESCR1 0x3a1
++#define MSR_P4_CRU_ESCR0 0x3b8
++#define MSR_P4_CRU_ESCR1 0x3b9
++#define MSR_P4_CRU_ESCR2 0x3cc
++#define MSR_P4_CRU_ESCR3 0x3cd
++#define MSR_P4_CRU_ESCR4 0x3e0
++#define MSR_P4_CRU_ESCR5 0x3e1
++#define MSR_P4_DAC_ESCR0 0x3a8
++#define MSR_P4_DAC_ESCR1 0x3a9
++#define MSR_P4_FIRM_ESCR0 0x3a4
++#define MSR_P4_FIRM_ESCR1 0x3a5
++#define MSR_P4_FLAME_ESCR0 0x3a6
++#define MSR_P4_FLAME_ESCR1 0x3a7
++#define MSR_P4_FSB_ESCR0 0x3a2
++#define MSR_P4_FSB_ESCR1 0x3a3
++#define MSR_P4_IQ_ESCR0 0x3ba
++#define MSR_P4_IQ_ESCR1 0x3bb
++#define MSR_P4_IS_ESCR0 0x3b4
++#define MSR_P4_IS_ESCR1 0x3b5
++#define MSR_P4_ITLB_ESCR0 0x3b6
++#define MSR_P4_ITLB_ESCR1 0x3b7
++#define MSR_P4_IX_ESCR0 0x3c8
++#define MSR_P4_IX_ESCR1 0x3c9
++#define MSR_P4_MOB_ESCR0 0x3aa
++#define MSR_P4_MOB_ESCR1 0x3ab
++#define MSR_P4_MS_ESCR0 0x3c0
++#define MSR_P4_MS_ESCR1 0x3c1
++#define MSR_P4_PMH_ESCR0 0x3ac
++#define MSR_P4_PMH_ESCR1 0x3ad
++#define MSR_P4_RAT_ESCR0 0x3bc
++#define MSR_P4_RAT_ESCR1 0x3bd
++#define MSR_P4_SAAT_ESCR0 0x3ae
++#define MSR_P4_SAAT_ESCR1 0x3af
++#define MSR_P4_SSU_ESCR0 0x3be
++#define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */
++#define MSR_P4_TBPU_ESCR0 0x3c2
++#define MSR_P4_TBPU_ESCR1 0x3c3
++#define MSR_P4_TC_ESCR0 0x3c4
++#define MSR_P4_TC_ESCR1 0x3c5
++#define MSR_P4_U2L_ESCR0 0x3b0
++#define MSR_P4_U2L_ESCR1 0x3b1
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/nmi.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/nmi.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/nmi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/nmi.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,93 @@
++/*
++ * linux/include/asm-i386/nmi.h
++ */
++#ifndef ASM_NMI_H
++#define ASM_NMI_H
++
++#include <linux/pm.h>
++#include <asm/io.h>
++
++#include <xen/interface/nmi.h>
++
++struct pt_regs;
++
++typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
++
++/**
++ * set_nmi_callback
++ *
++ * Set a handler for an NMI. Only one handler may be
++ * set. Return 1 if the NMI was handled.
++ */
++void set_nmi_callback(nmi_callback_t callback);
++
++/**
++ * unset_nmi_callback
++ *
++ * Remove the handler previously set.
++ */
++void unset_nmi_callback(void);
++
++#ifdef CONFIG_PM
++
++/** Replace the PM callback routine for NMI. */
++struct pm_dev * set_nmi_pm_callback(pm_callback callback);
++
++/** Unset the PM callback routine back to the default. */
++void unset_nmi_pm_callback(struct pm_dev * dev);
++
++#else
++
++static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback)
++{
++ return 0;
++}
++
++static inline void unset_nmi_pm_callback(struct pm_dev * dev)
++{
++}
++
++#endif /* CONFIG_PM */
++
++extern void default_do_nmi(struct pt_regs *);
++extern void die_nmi(char *str, struct pt_regs *regs);
++
++static inline unsigned char get_nmi_reason(void)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++ unsigned char reason = 0;
++
++ /* construct a value which looks like it came from
++ * port 0x61.
++ */
++ if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason))
++ reason |= 0x40;
++ if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason))
++ reason |= 0x80;
++
++ return reason;
++}
++
++extern int panic_on_timeout;
++extern int unknown_nmi_panic;
++
++extern int check_nmi_watchdog(void);
++
++extern void setup_apic_nmi_watchdog (void);
++extern int reserve_lapic_nmi(void);
++extern void release_lapic_nmi(void);
++extern void disable_timer_nmi_watchdog(void);
++extern void enable_timer_nmi_watchdog(void);
++extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
++
++extern void nmi_watchdog_default(void);
++extern int setup_nmi_watchdog(char *);
++
++extern unsigned int nmi_watchdog;
++#define NMI_DEFAULT -1
++#define NMI_NONE 0
++#define NMI_IO_APIC 1
++#define NMI_LOCAL_APIC 2
++#define NMI_INVALID 3
++
++#endif /* ASM_NMI_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/page.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/page.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/page.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/page.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,208 @@
++#ifndef _X86_64_PAGE_H
++#define _X86_64_PAGE_H
++
++/* #include <linux/string.h> */
++#ifndef __ASSEMBLY__
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <asm/bug.h>
++#endif
++#include <xen/interface/xen.h>
++#include <xen/foreign_page.h>
++
++#define arch_free_page(_page,_order) \
++({ int foreign = PageForeign(_page); \
++ if (foreign) \
++ (PageForeignDestructor(_page))(_page); \
++ foreign; \
++})
++#define HAVE_ARCH_FREE_PAGE
++
++#ifdef CONFIG_XEN_SCRUB_PAGES
++#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
++#else
++#define scrub_pages(_p,_n) ((void)0)
++#endif
++
++/* PAGE_SHIFT determines the page size */
++#define PAGE_SHIFT 12
++#ifdef __ASSEMBLY__
++#define PAGE_SIZE (0x1 << PAGE_SHIFT)
++#else
++#define PAGE_SIZE (1UL << PAGE_SHIFT)
++#endif
++#define PAGE_MASK (~(PAGE_SIZE-1))
++#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK)
++
++#define THREAD_ORDER 1
++#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
++#define CURRENT_MASK (~(THREAD_SIZE-1))
++
++#define EXCEPTION_STACK_ORDER 0
++#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
++
++#define DEBUG_STACK_ORDER (EXCEPTION_STACK_ORDER + 1)
++#define DEBUG_STKSZ (PAGE_SIZE << DEBUG_STACK_ORDER)
++
++#define IRQSTACK_ORDER 2
++#define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER)
++
++#define STACKFAULT_STACK 1
++#define DOUBLEFAULT_STACK 2
++#define NMI_STACK 3
++#define DEBUG_STACK 4
++#define MCE_STACK 5
++#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
++
++#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
++#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
++
++#define HPAGE_SHIFT PMD_SHIFT
++#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
++#define HPAGE_MASK (~(HPAGE_SIZE - 1))
++#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
++
++#ifdef __KERNEL__
++#ifndef __ASSEMBLY__
++
++extern unsigned long end_pfn;
++
++#include <asm/maddr.h>
++
++void clear_page(void *);
++void copy_page(void *, void *);
++
++#define clear_user_page(page, vaddr, pg) clear_page(page)
++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
++
++#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
++#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
++
++/*
++ * These are used to make use of C type-checking..
++ */
++typedef struct { unsigned long pte; } pte_t;
++typedef struct { unsigned long pmd; } pmd_t;
++typedef struct { unsigned long pud; } pud_t;
++typedef struct { unsigned long pgd; } pgd_t;
++#define PTE_MASK PHYSICAL_PAGE_MASK
++
++typedef struct { unsigned long pgprot; } pgprot_t;
++
++#define pte_val(x) (((x).pte & 1) ? machine_to_phys((x).pte) : \
++ (x).pte)
++#define pte_val_ma(x) ((x).pte)
++
++static inline unsigned long pmd_val(pmd_t x)
++{
++ unsigned long ret = x.pmd;
++ if (ret) ret = machine_to_phys(ret);
++ return ret;
++}
++
++static inline unsigned long pud_val(pud_t x)
++{
++ unsigned long ret = x.pud;
++ if (ret) ret = machine_to_phys(ret);
++ return ret;
++}
++
++static inline unsigned long pgd_val(pgd_t x)
++{
++ unsigned long ret = x.pgd;
++ if (ret) ret = machine_to_phys(ret);
++ return ret;
++}
++
++#define pgprot_val(x) ((x).pgprot)
++
++static inline pte_t __pte(unsigned long x)
++{
++ if (x & 1) x = phys_to_machine(x);
++ return ((pte_t) { (x) });
++}
++
++static inline pmd_t __pmd(unsigned long x)
++{
++ if ((x & 1)) x = phys_to_machine(x);
++ return ((pmd_t) { (x) });
++}
++
++static inline pud_t __pud(unsigned long x)
++{
++ if ((x & 1)) x = phys_to_machine(x);
++ return ((pud_t) { (x) });
++}
++
++static inline pgd_t __pgd(unsigned long x)
++{
++ if ((x & 1)) x = phys_to_machine(x);
++ return ((pgd_t) { (x) });
++}
++
++#define __pgprot(x) ((pgprot_t) { (x) } )
++
++#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START)
++#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
++#define __START_KERNEL_map 0xffffffff80000000UL
++#define __PAGE_OFFSET 0xffff880000000000UL
++
++#else
++#define __PHYSICAL_START CONFIG_PHYSICAL_START
++#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
++#define __START_KERNEL_map 0xffffffff80000000
++#define __PAGE_OFFSET 0xffff880000000000
++#endif /* !__ASSEMBLY__ */
++
++#ifdef CONFIG_XEN_COMPAT_030002
++#undef LOAD_OFFSET
++#define LOAD_OFFSET 0
++#endif /* CONFIG_XEN_COMPAT_030002 */
++
++/* to align the pointer to the (next) page boundary */
++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
++
++/* See Documentation/x86_64/mm.txt for a description of the memory map. */
++#define __PHYSICAL_MASK_SHIFT 46
++#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1)
++#define __VIRTUAL_MASK_SHIFT 48
++#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
++
++#define KERNEL_TEXT_SIZE (40UL*1024*1024)
++#define KERNEL_TEXT_START 0xffffffff80000000UL
++
++#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
++
++/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol.
++ Otherwise you risk miscompilation. */
++#define __pa(x) (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET)
++/* __pa_symbol should be used for C visible symbols.
++ This seems to be the official gcc blessed way to do such arithmetic. */
++#define __pa_symbol(x) \
++ ({unsigned long v; \
++ asm("" : "=r" (v) : "0" (x)); \
++ __pa(v); })
++
++#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
++#define __boot_va(x) __va(x)
++#define __boot_pa(x) __pa(x)
++#ifdef CONFIG_FLATMEM
++#define pfn_valid(pfn) ((pfn) < end_pfn)
++#endif
++
++#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
++#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
++#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
++
++#define VM_DATA_DEFAULT_FLAGS \
++ (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
++ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
++
++#define __HAVE_ARCH_GATE_AREA 1
++
++#include <asm-generic/memory_model.h>
++#include <asm-generic/page.h>
++
++#endif /* __KERNEL__ */
++
++#endif /* _X86_64_PAGE_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/param.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/param.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/param.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/param.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,22 @@
++#ifndef _ASMx86_64_PARAM_H
++#define _ASMx86_64_PARAM_H
++
++#ifdef __KERNEL__
++# define HZ CONFIG_HZ /* Internal kernel timer frequency */
++# define USER_HZ 100 /* .. some user interfaces are in "ticks */
++# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
++#endif
++
++#ifndef HZ
++#define HZ 100
++#endif
++
++#define EXEC_PAGESIZE 4096
++
++#ifndef NOGROUP
++#define NOGROUP (-1)
++#endif
++
++#define MAXHOSTNAMELEN 64 /* max length of hostname */
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/pci.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/pci.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/pci.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,173 @@
++#ifndef __x8664_PCI_H
++#define __x8664_PCI_H
++
++#include <asm/io.h>
++
++#ifdef __KERNEL__
++
++#include <linux/mm.h> /* for struct page */
++
++/* 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 */
++
++#ifdef CONFIG_PCI
++extern unsigned int pcibios_assign_all_busses(void);
++#else
++#define pcibios_assign_all_busses() 0
++#endif
++#define pcibios_scan_all_fns(a, b) 0
++
++extern unsigned long pci_mem_start;
++#define PCIBIOS_MIN_IO 0x1000
++#define PCIBIOS_MIN_MEM (pci_mem_start)
++
++#define PCIBIOS_MIN_CARDBUS_IO 0x4000
++
++void pcibios_config_init(void);
++struct pci_bus * pcibios_scan_root(int bus);
++extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
++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, 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);
++
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <asm/scatterlist.h>
++#include <linux/string.h>
++#include <asm/page.h>
++
++extern void pci_iommu_alloc(void);
++extern int iommu_setup(char *opt);
++
++/* The PCI address space does equal the physical memory
++ * address space. The networking and block device layers use
++ * this boolean for bounce buffer decisions
++ *
++ * On AMD64 it mostly equals, but we set it to zero if a hardware
++ * IOMMU (gart) of sotware IOMMU (swiotlb) is available.
++ */
++#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
++
++#if defined(CONFIG_IOMMU) || defined(CONFIG_CALGARY_IOMMU)
++
++/*
++ * x86-64 always supports DAC, but sometimes it is useful to force
++ * devices through the IOMMU to get automatic sg list merging.
++ * Optional right now.
++ */
++extern int iommu_sac_force;
++#define pci_dac_dma_supported(pci_dev, mask) (!iommu_sac_force)
++
++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
++ dma_addr_t ADDR_NAME;
++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
++ __u32 LEN_NAME;
++#define pci_unmap_addr(PTR, ADDR_NAME) \
++ ((PTR)->ADDR_NAME)
++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
++ (((PTR)->ADDR_NAME) = (VAL))
++#define pci_unmap_len(PTR, LEN_NAME) \
++ ((PTR)->LEN_NAME)
++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
++ (((PTR)->LEN_NAME) = (VAL))
++
++#elif defined(CONFIG_SWIOTLB)
++
++#define pci_dac_dma_supported(pci_dev, mask) 1
++
++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
++ dma_addr_t ADDR_NAME;
++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
++ __u32 LEN_NAME;
++#define pci_unmap_addr(PTR, ADDR_NAME) \
++ ((PTR)->ADDR_NAME)
++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
++ (((PTR)->ADDR_NAME) = (VAL))
++#define pci_unmap_len(PTR, LEN_NAME) \
++ ((PTR)->LEN_NAME)
++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
++ (((PTR)->LEN_NAME) = (VAL))
++
++#else
++/* No IOMMU */
++
++#define pci_dac_dma_supported(pci_dev, mask) 1
++
++#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_unmap_len(PTR, LEN_NAME) (0)
++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
++
++#endif
++
++#include <asm-generic/pci-dma-compat.h>
++
++static inline dma64_addr_t
++pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
++{
++ return ((dma64_addr_t) page_to_phys(page) +
++ (dma64_addr_t) offset);
++}
++
++static inline struct page *
++pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
++{
++ return virt_to_page(__va(dma_addr));
++}
++
++static inline unsigned long
++pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
++{
++ return (dma_addr & ~PAGE_MASK);
++}
++
++static inline void
++pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
++{
++}
++
++static inline void
++pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
++{
++ 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);
++
++static inline void pcibios_add_platform_entries(struct pci_dev *dev)
++{
++}
++
++#endif /* __KERNEL__ */
++
++/* generic pci stuff */
++#ifdef CONFIG_PCI
++#include <asm-generic/pci.h>
++#endif
++
++/* On Xen we have to scan all functions since Xen hides bridges from
++ * us. If a bridge is at fn=0 and that slot has a multifunction
++ * device, we won't find the additional devices without scanning all
++ * functions. */
++#undef pcibios_scan_all_fns
++#define pcibios_scan_all_fns(a, b) 1
++
++#endif /* __x8664_PCI_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/pgalloc.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/pgalloc.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/pgalloc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/pgalloc.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,226 @@
++#ifndef _X86_64_PGALLOC_H
++#define _X86_64_PGALLOC_H
++
++#include <asm/fixmap.h>
++#include <asm/pda.h>
++#include <linux/threads.h>
++#include <linux/mm.h>
++#include <asm/io.h> /* for phys_to_virt and page_to_pseudophys */
++
++#include <xen/features.h>
++void make_page_readonly(void *va, unsigned int feature);
++void make_page_writable(void *va, unsigned int feature);
++void make_pages_readonly(void *va, unsigned int nr, unsigned int feature);
++void make_pages_writable(void *va, unsigned int nr, unsigned int feature);
++
++#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD)
++
++static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
++{
++ set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)));
++}
++
++static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
++{
++ if (unlikely((mm)->context.pinned)) {
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)__va(page_to_pfn(pte) << PAGE_SHIFT),
++ pfn_pte(page_to_pfn(pte), PAGE_KERNEL_RO), 0));
++ set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
++ } else {
++ *(pmd) = __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT));
++ }
++}
++
++static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
++{
++ if (unlikely((mm)->context.pinned)) {
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)pmd,
++ pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT,
++ PAGE_KERNEL_RO), 0));
++ set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
++ } else {
++ *(pud) = __pud(_PAGE_TABLE | __pa(pmd));
++ }
++}
++
++/*
++ * We need to use the batch mode here, but pgd_pupulate() won't be
++ * be called frequently.
++ */
++static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
++{
++ if (unlikely((mm)->context.pinned)) {
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)pud,
++ pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT,
++ PAGE_KERNEL_RO), 0));
++ set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
++ set_pgd(__user_pgd(pgd), __pgd(_PAGE_TABLE | __pa(pud)));
++ } else {
++ *(pgd) = __pgd(_PAGE_TABLE | __pa(pud));
++ *(__user_pgd(pgd)) = *(pgd);
++ }
++}
++
++static inline void pmd_free(pmd_t *pmd)
++{
++ pte_t *ptep = virt_to_ptep(pmd);
++
++ if (!pte_write(*ptep)) {
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)pmd,
++ pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, PAGE_KERNEL),
++ 0));
++ }
++ free_page((unsigned long)pmd);
++}
++
++static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
++{
++ pmd_t *pmd = (pmd_t *) get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
++ return pmd;
++}
++
++static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
++{
++ pud_t *pud = (pud_t *) get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
++ return pud;
++}
++
++static inline void pud_free(pud_t *pud)
++{
++ pte_t *ptep = virt_to_ptep(pud);
++
++ if (!pte_write(*ptep)) {
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)pud,
++ pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, PAGE_KERNEL),
++ 0));
++ }
++ free_page((unsigned long)pud);
++}
++
++static inline void pgd_list_add(pgd_t *pgd)
++{
++ struct page *page = virt_to_page(pgd);
++
++ spin_lock(&pgd_lock);
++ page->index = (pgoff_t)pgd_list;
++ if (pgd_list)
++ pgd_list->private = (unsigned long)&page->index;
++ pgd_list = page;
++ page->private = (unsigned long)&pgd_list;
++ spin_unlock(&pgd_lock);
++}
++
++static inline void pgd_list_del(pgd_t *pgd)
++{
++ struct page *next, **pprev, *page = virt_to_page(pgd);
++
++ spin_lock(&pgd_lock);
++ next = (struct page *)page->index;
++ pprev = (struct page **)page->private;
++ *pprev = next;
++ if (next)
++ next->private = (unsigned long)pprev;
++ spin_unlock(&pgd_lock);
++}
++
++static inline pgd_t *pgd_alloc(struct mm_struct *mm)
++{
++ /*
++ * We allocate two contiguous pages for kernel and user.
++ */
++ unsigned boundary;
++ pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 1);
++
++ if (!pgd)
++ return NULL;
++ pgd_list_add(pgd);
++ /*
++ * Copy kernel pointers in from init.
++ * Could keep a freelist or slab cache of those because the kernel
++ * part never changes.
++ */
++ boundary = pgd_index(__PAGE_OFFSET);
++ memset(pgd, 0, boundary * sizeof(pgd_t));
++ memcpy(pgd + boundary,
++ init_level4_pgt + boundary,
++ (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
++
++ memset(__user_pgd(pgd), 0, PAGE_SIZE); /* clean up user pgd */
++ /*
++ * Set level3_user_pgt for vsyscall area
++ */
++ set_pgd(__user_pgd(pgd) + pgd_index(VSYSCALL_START),
++ mk_kernel_pgd(__pa_symbol(level3_user_pgt)));
++ return pgd;
++}
++
++static inline void pgd_free(pgd_t *pgd)
++{
++ pte_t *ptep = virt_to_ptep(pgd);
++
++ if (!pte_write(*ptep)) {
++ xen_pgd_unpin(__pa(pgd));
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)pgd,
++ pfn_pte(virt_to_phys(pgd)>>PAGE_SHIFT, PAGE_KERNEL),
++ 0));
++ }
++
++ ptep = virt_to_ptep(__user_pgd(pgd));
++
++ if (!pte_write(*ptep)) {
++ xen_pgd_unpin(__pa(__user_pgd(pgd)));
++ BUG_ON(HYPERVISOR_update_va_mapping(
++ (unsigned long)__user_pgd(pgd),
++ pfn_pte(virt_to_phys(__user_pgd(pgd))>>PAGE_SHIFT,
++ PAGE_KERNEL),
++ 0));
++ }
++
++ pgd_list_del(pgd);
++ free_pages((unsigned long)pgd, 1);
++}
++
++static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
++{
++ pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
++ if (pte)
++ make_page_readonly(pte, XENFEAT_writable_page_tables);
++
++ return pte;
++}
++
++static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
++{
++ struct page *pte;
++
++ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
++ return pte;
++}
++
++/* Should really implement gc for free page table pages. This could be
++ done with a reference count in struct page. */
++
++static inline void pte_free_kernel(pte_t *pte)
++{
++ BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
++ make_page_writable(pte, XENFEAT_writable_page_tables);
++ free_page((unsigned long)pte);
++}
++
++extern void pte_free(struct page *pte);
++
++//#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
++//#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
++//#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
++
++#define __pte_free_tlb(tlb,x) pte_free((x))
++#define __pmd_free_tlb(tlb,x) pmd_free((x))
++#define __pud_free_tlb(tlb,x) pud_free((x))
++
++#endif /* _X86_64_PGALLOC_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/pgtable.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/pgtable.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/pgtable.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/pgtable.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,558 @@
++#ifndef _X86_64_PGTABLE_H
++#define _X86_64_PGTABLE_H
++
++/*
++ * This file contains the functions and defines necessary to modify and use
++ * the x86-64 page table tree.
++ */
++#include <asm/processor.h>
++#include <asm/fixmap.h>
++#include <asm/bitops.h>
++#include <linux/threads.h>
++#include <linux/sched.h>
++#include <asm/pda.h>
++#ifdef CONFIG_XEN
++#include <asm/hypervisor.h>
++
++extern pud_t level3_user_pgt[512];
++extern pud_t init_level4_user_pgt[];
++
++extern void xen_init_pt(void);
++
++#define virt_to_ptep(__va) \
++({ \
++ pgd_t *__pgd = pgd_offset_k((unsigned long)(__va)); \
++ pud_t *__pud = pud_offset(__pgd, (unsigned long)(__va)); \
++ pmd_t *__pmd = pmd_offset(__pud, (unsigned long)(__va)); \
++ pte_offset_kernel(__pmd, (unsigned long)(__va)); \
++})
++
++#define arbitrary_virt_to_machine(__va) \
++({ \
++ maddr_t m = (maddr_t)pte_mfn(*virt_to_ptep(__va)) << PAGE_SHIFT;\
++ m | ((unsigned long)(__va) & (PAGE_SIZE-1)); \
++})
++#endif
++
++extern pud_t level3_kernel_pgt[512];
++extern pud_t level3_physmem_pgt[512];
++extern pud_t level3_ident_pgt[512];
++extern pmd_t level2_kernel_pgt[512];
++extern pgd_t init_level4_pgt[];
++extern pgd_t boot_level4_pgt[];
++extern unsigned long __supported_pte_mask;
++
++#define swapper_pg_dir init_level4_pgt
++
++extern int nonx_setup(char *str);
++extern void paging_init(void);
++extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
++
++extern unsigned long pgkern_mask;
++
++/*
++ * ZERO_PAGE is a global shared page that is always zero: used
++ * for zero-mapped memory areas etc..
++ */
++extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
++#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
++
++/*
++ * PGDIR_SHIFT determines what a top-level page table entry can map
++ */
++#define PGDIR_SHIFT 39
++#define PTRS_PER_PGD 512
++
++/*
++ * 3rd level page
++ */
++#define PUD_SHIFT 30
++#define PTRS_PER_PUD 512
++
++/*
++ * PMD_SHIFT determines the size of the area a middle-level
++ * page table can map
++ */
++#define PMD_SHIFT 21
++#define PTRS_PER_PMD 512
++
++/*
++ * entries per page directory level
++ */
++#define PTRS_PER_PTE 512
++
++#define pte_ERROR(e) \
++ printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
++#define pmd_ERROR(e) \
++ printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), pmd_val(e))
++#define pud_ERROR(e) \
++ printk("%s:%d: bad pud %p(%016lx).\n", __FILE__, __LINE__, &(e), pud_val(e))
++#define pgd_ERROR(e) \
++ printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
++
++#define pgd_none(x) (!pgd_val(x))
++#define pud_none(x) (!pud_val(x))
++
++#define set_pte_batched(pteptr, pteval) \
++ queue_l1_entry_update(pteptr, (pteval))
++
++extern inline int pud_present(pud_t pud) { return !pud_none(pud); }
++
++static inline void set_pte(pte_t *dst, pte_t val)
++{
++ *dst = val;
++}
++
++#define set_pmd(pmdptr, pmdval) xen_l2_entry_update(pmdptr, (pmdval))
++#define set_pud(pudptr, pudval) xen_l3_entry_update(pudptr, (pudval))
++#define set_pgd(pgdptr, pgdval) xen_l4_entry_update(pgdptr, (pgdval))
++
++static inline void pud_clear (pud_t * pud)
++{
++ set_pud(pud, __pud(0));
++}
++
++#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD)
++
++static inline void pgd_clear (pgd_t * pgd)
++{
++ set_pgd(pgd, __pgd(0));
++ set_pgd(__user_pgd(pgd), __pgd(0));
++}
++
++#define pud_page(pud) \
++ ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
++
++/*
++ * A note on implementation of this atomic 'get-and-clear' operation.
++ * This is actually very simple because Xen Linux can only run on a single
++ * processor. Therefore, we cannot race other processors setting the 'accessed'
++ * or 'dirty' bits on a page-table entry.
++ * Even if pages are shared between domains, that is not a problem because
++ * each domain will have separate page tables, with their own versions of
++ * accessed & dirty state.
++ */
++#define ptep_get_and_clear(mm,addr,xp) __pte_ma(xchg(&(xp)->pte, 0))
++
++#if 0
++static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *xp)
++{
++ pte_t pte = *xp;
++ if (pte.pte)
++ set_pte(xp, __pte_ma(0));
++ return pte;
++}
++#endif
++
++struct mm_struct;
++
++static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
++{
++ pte_t pte;
++ if (full) {
++ pte = *ptep;
++ *ptep = __pte(0);
++ } else {
++ pte = ptep_get_and_clear(mm, addr, ptep);
++ }
++ return pte;
++}
++
++#define pte_same(a, b) ((a).pte == (b).pte)
++
++#define pte_pgprot(a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK))
++
++#define PMD_SIZE (1UL << PMD_SHIFT)
++#define PMD_MASK (~(PMD_SIZE-1))
++#define PUD_SIZE (1UL << PUD_SHIFT)
++#define PUD_MASK (~(PUD_SIZE-1))
++#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
++#define PGDIR_MASK (~(PGDIR_SIZE-1))
++
++#define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1)
++#define FIRST_USER_ADDRESS 0
++
++#ifndef __ASSEMBLY__
++#define MAXMEM 0x3fffffffffffUL
++#define VMALLOC_START 0xffffc20000000000UL
++#define VMALLOC_END 0xffffe1ffffffffffUL
++#define MODULES_VADDR 0xffffffff88000000UL
++#define MODULES_END 0xfffffffffff00000UL
++#define MODULES_LEN (MODULES_END - MODULES_VADDR)
++
++#define _PAGE_BIT_PRESENT 0
++#define _PAGE_BIT_RW 1
++#define _PAGE_BIT_USER 2
++#define _PAGE_BIT_PWT 3
++#define _PAGE_BIT_PCD 4
++#define _PAGE_BIT_ACCESSED 5
++#define _PAGE_BIT_DIRTY 6
++#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */
++#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
++#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
++
++#define _PAGE_PRESENT 0x001
++#define _PAGE_RW 0x002
++#define _PAGE_USER 0x004
++#define _PAGE_PWT 0x008
++#define _PAGE_PCD 0x010
++#define _PAGE_ACCESSED 0x020
++#define _PAGE_DIRTY 0x040
++#define _PAGE_PSE 0x080 /* 2MB page */
++#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */
++#define _PAGE_GLOBAL 0x100 /* Global TLB entry */
++
++#define _PAGE_PROTNONE 0x080 /* If not present */
++#define _PAGE_NX (1UL<<_PAGE_BIT_NX)
++
++#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
++
++#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++
++#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
++#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
++#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
++#define PAGE_COPY PAGE_COPY_NOEXEC
++#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
++#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define __PAGE_KERNEL \
++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
++#define __PAGE_KERNEL_EXEC \
++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
++#define __PAGE_KERNEL_NOCACHE \
++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX)
++#define __PAGE_KERNEL_RO \
++ (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
++#define __PAGE_KERNEL_VSYSCALL \
++ (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define __PAGE_KERNEL_VSYSCALL_NOCACHE \
++ (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PCD)
++#define __PAGE_KERNEL_LARGE \
++ (__PAGE_KERNEL | _PAGE_PSE)
++#define __PAGE_KERNEL_LARGE_EXEC \
++ (__PAGE_KERNEL_EXEC | _PAGE_PSE)
++
++/*
++ * We don't support GLOBAL page in xenolinux64
++ */
++#define MAKE_GLOBAL(x) __pgprot((x))
++
++#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
++#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC)
++#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
++#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
++#define PAGE_KERNEL_VSYSCALL32 __pgprot(__PAGE_KERNEL_VSYSCALL)
++#define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
++#define PAGE_KERNEL_LARGE MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
++#define PAGE_KERNEL_VSYSCALL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL_NOCACHE)
++
++/* xwr */
++#define __P000 PAGE_NONE
++#define __P001 PAGE_READONLY
++#define __P010 PAGE_COPY
++#define __P011 PAGE_COPY
++#define __P100 PAGE_READONLY_EXEC
++#define __P101 PAGE_READONLY_EXEC
++#define __P110 PAGE_COPY_EXEC
++#define __P111 PAGE_COPY_EXEC
++
++#define __S000 PAGE_NONE
++#define __S001 PAGE_READONLY
++#define __S010 PAGE_SHARED
++#define __S011 PAGE_SHARED
++#define __S100 PAGE_READONLY_EXEC
++#define __S101 PAGE_READONLY_EXEC
++#define __S110 PAGE_SHARED_EXEC
++#define __S111 PAGE_SHARED_EXEC
++
++static inline unsigned long pgd_bad(pgd_t pgd)
++{
++ unsigned long val = pgd_val(pgd);
++ val &= ~PTE_MASK;
++ val &= ~(_PAGE_USER | _PAGE_DIRTY);
++ return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED);
++}
++
++static inline unsigned long pud_bad(pud_t pud)
++{
++ unsigned long val = pud_val(pud);
++ val &= ~PTE_MASK;
++ val &= ~(_PAGE_USER | _PAGE_DIRTY);
++ return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED);
++}
++
++#define set_pte_at(_mm,addr,ptep,pteval) do { \
++ if (((_mm) != current->mm && (_mm) != &init_mm) || \
++ HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \
++ set_pte((ptep), (pteval)); \
++} while (0)
++
++#define pte_none(x) (!(x).pte)
++#define pte_present(x) ((x).pte & (_PAGE_PRESENT | _PAGE_PROTNONE))
++#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
++
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++
++#define pte_mfn(_pte) (((_pte).pte & PTE_MASK) >> PAGE_SHIFT)
++#define pte_pfn(_pte) mfn_to_local_pfn(pte_mfn(_pte))
++
++#define pte_page(x) pfn_to_page(pte_pfn(x))
++
++static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
++{
++ pte_t pte;
++
++ (pte).pte = (pfn_to_mfn(page_nr) << PAGE_SHIFT);
++ (pte).pte |= pgprot_val(pgprot);
++ (pte).pte &= __supported_pte_mask;
++ return pte;
++}
++
++/*
++ * The following only work if pte_present() is true.
++ * Undefined behaviour if not..
++ */
++#define __pte_val(x) ((x).pte)
++
++#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
++static inline int pte_user(pte_t pte) { return __pte_val(pte) & _PAGE_USER; }
++static inline int pte_read(pte_t pte) { return __pte_val(pte) & _PAGE_USER; }
++static inline int pte_exec(pte_t pte) { return __pte_val(pte) & _PAGE_USER; }
++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_write(pte_t pte) { return __pte_val(pte) & _PAGE_RW; }
++static inline int pte_file(pte_t pte) { return __pte_val(pte) & _PAGE_FILE; }
++static inline int pte_huge(pte_t pte) { return __pte_val(pte) & _PAGE_PSE; }
++
++static inline pte_t pte_rdprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; return pte; }
++static inline pte_t pte_exprotect(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_wrprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_RW; return pte; }
++static inline pte_t pte_mkread(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; }
++static inline pte_t pte_mkexec(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; }
++static inline pte_t pte_mkhuge(pte_t pte) { __pte_val(pte) |= _PAGE_PSE; return pte; }
++
++struct vm_area_struct;
++
++static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
++{
++ pte_t pte = *ptep;
++ int ret = pte_dirty(pte);
++ if (ret)
++ set_pte(ptep, pte_mkclean(pte));
++ return ret;
++}
++
++static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
++{
++ pte_t pte = *ptep;
++ int ret = pte_young(pte);
++ if (ret)
++ set_pte(ptep, pte_mkold(pte));
++ return ret;
++}
++
++static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
++{
++ pte_t pte = *ptep;
++ if (pte_write(pte))
++ set_pte(ptep, pte_wrprotect(pte));
++}
++
++/*
++ * Macro to mark a page protection value as "uncacheable".
++ */
++#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT))
++
++static inline int pmd_large(pmd_t pte) {
++ return (pmd_val(pte) & __LARGE_PTE) == __LARGE_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.
++ */
++
++/*
++ * Level 4 access.
++ * Never use these in the common code.
++ */
++#define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & PTE_MASK))
++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
++#define pgd_offset_k(address) (pgd_t *)(init_level4_pgt + pgd_index(address))
++#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT)
++#define mk_kernel_pgd(address) __pgd((address) | _KERNPG_TABLE)
++
++/* PUD - Level3 access */
++/* to find an entry in a page-table-directory. */
++#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
++#define pud_offset(pgd, address) ((pud_t *) pgd_page(*(pgd)) + pud_index(address))
++
++/* Find correct pud via the hidden fourth level page level: */
++
++/* This accesses the reference page table of the boot cpu.
++ Other CPUs get synced lazily via the page fault handler. */
++static inline pud_t *pud_offset_k(pgd_t *pgd, unsigned long address)
++{
++ return pud_offset(pgd_offset_k(address), address);
++}
++
++/* PMD - Level 2 access */
++#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
++#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
++
++#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
++#define pmd_offset(dir, address) ((pmd_t *) pud_page(*(dir)) + \
++ pmd_index(address))
++#define pmd_none(x) (!pmd_val(x))
++/* pmd_present doesn't just test the _PAGE_PRESENT bit since wr.p.t.
++ can temporarily clear it. */
++#define pmd_present(x) (pmd_val(x))
++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
++#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & ~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT))
++#define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
++#define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
++
++#define pte_to_pgoff(pte) ((pte_val(pte) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
++#define pgoff_to_pte(off) ((pte_t) { ((off) << PAGE_SHIFT) | _PAGE_FILE })
++#define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT
++
++/* PTE - Level 1 access. */
++
++/* page, protection -> pte */
++#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
++#define mk_pte_huge(entry) (pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE)
++
++/* physical address -> PTE */
++static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
++{
++ pte_t pte;
++ (pte).pte = physpage | pgprot_val(pgprot);
++ return pte;
++}
++
++/* Change flags of a PTE */
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++ (pte).pte &= _PAGE_CHG_MASK;
++ (pte).pte |= pgprot_val(newprot);
++ (pte).pte &= __supported_pte_mask;
++ return pte;
++}
++
++#define pte_index(address) \
++ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
++#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \
++ pte_index(address))
++
++/* x86-64 always has all page tables mapped. */
++#define pte_offset_map(dir,address) pte_offset_kernel(dir,address)
++#define pte_offset_map_nested(dir,address) pte_offset_kernel(dir,address)
++#define pte_unmap(pte) /* NOP */
++#define pte_unmap_nested(pte) /* NOP */
++
++#define update_mmu_cache(vma,address,pte) do { } while (0)
++
++/* We only update the dirty/accessed state if we set
++ * the dirty bit by hand in the kernel, since the hardware
++ * will do the accessed bit for us, and we don't want to
++ * race with other CPU's that might be updating the dirty
++ * bit at the same time. */
++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
++#if 0
++#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
++ do { \
++ if (__dirty) { \
++ set_pte(__ptep, __entry); \
++ flush_tlb_page(__vma, __address); \
++ } \
++ } while (0)
++#endif
++#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
++ do { \
++ if (__dirty) { \
++ if ( likely((__vma)->vm_mm == current->mm) ) { \
++ BUG_ON(HYPERVISOR_update_va_mapping((__address), (__entry), UVMF_INVLPG|UVMF_MULTI|(unsigned long)((__vma)->vm_mm->cpu_vm_mask.bits))); \
++ } else { \
++ xen_l1_entry_update((__ptep), (__entry)); \
++ flush_tlb_page((__vma), (__address)); \
++ } \
++ } \
++ } while (0)
++
++/* Encode and de-code a swap entry */
++#define __swp_type(x) (((x).val >> 1) & 0x3f)
++#define __swp_offset(x) ((x).val >> 8)
++#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
++#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
++
++extern spinlock_t pgd_lock;
++extern struct page *pgd_list;
++void vmalloc_sync_all(void);
++
++#endif /* !__ASSEMBLY__ */
++
++extern int kern_addr_valid(unsigned long addr);
++
++#define DOMID_LOCAL (0xFFFFU)
++
++int direct_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid);
++
++int direct_kernel_remap_pfn_range(unsigned long address,
++ unsigned long mfn,
++ unsigned long size,
++ pgprot_t prot,
++ domid_t domid);
++
++int create_lookup_pte_addr(struct mm_struct *mm,
++ unsigned long address,
++ uint64_t *ptep);
++
++int touch_pte_range(struct mm_struct *mm,
++ unsigned long address,
++ unsigned long size);
++
++#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
++ direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO)
++
++#define MK_IOSPACE_PFN(space, pfn) (pfn)
++#define GET_IOSPACE(pfn) 0
++#define GET_PFN(pfn) (pfn)
++
++#define HAVE_ARCH_UNMAPPED_AREA
++
++#define pgtable_cache_init() do { } while (0)
++#define check_pgt_cache() do { } while (0)
++
++#define PAGE_AGP PAGE_KERNEL_NOCACHE
++#define HAVE_PAGE_AGP 1
++
++/* fs/proc/kcore.c */
++#define kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK)
++#define kc_offset_to_vaddr(o) \
++ (((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o))
++
++#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_GET_AND_CLEAR_FULL
++#define __HAVE_ARCH_PTEP_SET_WRPROTECT
++#define __HAVE_ARCH_PTE_SAME
++#include <asm-generic/pgtable.h>
++
++#endif /* _X86_64_PGTABLE_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/processor.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/processor.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/processor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/processor.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,504 @@
++/*
++ * include/asm-x86_64/processor.h
++ *
++ * Copyright (C) 1994 Linus Torvalds
++ */
++
++#ifndef __ASM_X86_64_PROCESSOR_H
++#define __ASM_X86_64_PROCESSOR_H
++
++#include <asm/segment.h>
++#include <asm/page.h>
++#include <asm/types.h>
++#include <asm/sigcontext.h>
++#include <asm/cpufeature.h>
++#include <linux/threads.h>
++#include <asm/msr.h>
++#include <asm/current.h>
++#include <asm/system.h>
++#include <asm/mmsegment.h>
++#include <asm/percpu.h>
++#include <linux/personality.h>
++#include <linux/cpumask.h>
++
++#define TF_MASK 0x00000100
++#define IF_MASK 0x00000200
++#define IOPL_MASK 0x00003000
++#define NT_MASK 0x00004000
++#define VM_MASK 0x00020000
++#define AC_MASK 0x00040000
++#define VIF_MASK 0x00080000 /* virtual interrupt flag */
++#define VIP_MASK 0x00100000 /* virtual interrupt pending */
++#define ID_MASK 0x00200000
++
++#define desc_empty(desc) \
++ (!((desc)->a | (desc)->b))
++
++#define desc_equal(desc1, desc2) \
++ (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
++
++/*
++ * Default implementation of macro that returns current
++ * instruction pointer ("program counter").
++ */
++#define current_text_addr() ({ void *pc; asm volatile("leaq 1f(%%rip),%0\n1:":"=r"(pc)); pc; })
++
++/*
++ * CPU type and hardware bug flags. Kept separately for each CPU.
++ */
++
++struct cpuinfo_x86 {
++ __u8 x86; /* CPU family */
++ __u8 x86_vendor; /* CPU vendor */
++ __u8 x86_model;
++ __u8 x86_mask;
++ int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
++ __u32 x86_capability[NCAPINTS];
++ char x86_vendor_id[16];
++ char x86_model_id[64];
++ int x86_cache_size; /* in KB */
++ int x86_clflush_size;
++ int x86_cache_alignment;
++ int x86_tlbsize; /* number of 4K pages in DTLB/ITLB combined(in pages)*/
++ __u8 x86_virt_bits, x86_phys_bits;
++ __u8 x86_max_cores; /* cpuid returned max cores value */
++ __u32 x86_power;
++ __u32 extended_cpuid_level; /* Max extended CPUID function supported */
++ unsigned long loops_per_jiffy;
++#ifdef CONFIG_SMP
++ cpumask_t llc_shared_map; /* cpus sharing the last level cache */
++#endif
++ __u8 apicid;
++#ifdef CONFIG_SMP
++ __u8 booted_cores; /* number of cores as seen by OS */
++ __u8 phys_proc_id; /* Physical Processor id. */
++ __u8 cpu_core_id; /* Core id. */
++#endif
++} ____cacheline_aligned;
++
++#define X86_VENDOR_INTEL 0
++#define X86_VENDOR_CYRIX 1
++#define X86_VENDOR_AMD 2
++#define X86_VENDOR_UMC 3
++#define X86_VENDOR_NEXGEN 4
++#define X86_VENDOR_CENTAUR 5
++#define X86_VENDOR_RISE 6
++#define X86_VENDOR_TRANSMETA 7
++#define X86_VENDOR_NUM 8
++#define X86_VENDOR_UNKNOWN 0xff
++
++#ifdef CONFIG_SMP
++extern struct cpuinfo_x86 cpu_data[];
++#define current_cpu_data cpu_data[smp_processor_id()]
++#else
++#define cpu_data (&boot_cpu_data)
++#define current_cpu_data boot_cpu_data
++#endif
++
++extern char ignore_irq13;
++
++extern void identify_cpu(struct cpuinfo_x86 *);
++extern void print_cpu_info(struct cpuinfo_x86 *);
++extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
++extern unsigned short num_cache_leaves;
++
++/*
++ * EFLAGS bits
++ */
++#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
++#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
++#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
++#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
++#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
++#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
++#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
++#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
++#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
++#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
++#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
++#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
++#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
++#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
++#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
++#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
++#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
++
++/*
++ * Intel CPU features in CR4
++ */
++#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
++#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
++#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
++#define X86_CR4_DE 0x0008 /* enable debugging extensions */
++#define X86_CR4_PSE 0x0010 /* enable page size extensions */
++#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
++#define X86_CR4_MCE 0x0040 /* Machine check enable */
++#define X86_CR4_PGE 0x0080 /* enable global pages */
++#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
++#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
++#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
++
++/*
++ * Save the cr4 feature set we're using (ie
++ * Pentium 4MB enable and PPro Global page
++ * enable), so that any CPU's that boot up
++ * after us can get the correct flags.
++ */
++extern unsigned long mmu_cr4_features;
++
++static inline void set_in_cr4 (unsigned long mask)
++{
++ mmu_cr4_features |= mask;
++ __asm__("movq %%cr4,%%rax\n\t"
++ "orq %0,%%rax\n\t"
++ "movq %%rax,%%cr4\n"
++ : : "irg" (mask)
++ :"ax");
++}
++
++static inline void clear_in_cr4 (unsigned long mask)
++{
++ mmu_cr4_features &= ~mask;
++ __asm__("movq %%cr4,%%rax\n\t"
++ "andq %0,%%rax\n\t"
++ "movq %%rax,%%cr4\n"
++ : : "irg" (~mask)
++ :"ax");
++}
++
++
++/*
++ * Bus types
++ */
++#define MCA_bus 0
++#define MCA_bus__is_a_macro
++
++/*
++ * User space process size. 47bits minus one guard page.
++ */
++#define TASK_SIZE64 (0x800000000000UL - 4096)
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000)
++
++#define TASK_SIZE (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE64)
++#define TASK_SIZE_OF(child) ((test_tsk_thread_flag(child, TIF_IA32)) ? IA32_PAGE_OFFSET : TASK_SIZE64)
++
++#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3)
++
++/*
++ * Size of io_bitmap.
++ */
++#define IO_BITMAP_BITS 65536
++#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8)
++#define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long))
++#ifndef CONFIG_X86_NO_TSS
++#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
++#endif
++#define INVALID_IO_BITMAP_OFFSET 0x8000
++
++struct i387_fxsave_struct {
++ u16 cwd;
++ u16 swd;
++ u16 twd;
++ u16 fop;
++ u64 rip;
++ u64 rdp;
++ u32 mxcsr;
++ u32 mxcsr_mask;
++ u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
++ u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 128 bytes */
++ u32 padding[24];
++} __attribute__ ((aligned (16)));
++
++union i387_union {
++ struct i387_fxsave_struct fxsave;
++};
++
++#ifndef CONFIG_X86_NO_TSS
++struct tss_struct {
++ u32 reserved1;
++ u64 rsp0;
++ u64 rsp1;
++ u64 rsp2;
++ u64 reserved2;
++ u64 ist[7];
++ u32 reserved3;
++ u32 reserved4;
++ u16 reserved5;
++ u16 io_bitmap_base;
++ /*
++ * The extra 1 is there because the CPU will access an
++ * additional byte beyond the end of the IO permission
++ * bitmap. The extra byte must be all 1 bits, and must
++ * be within the limit. Thus we have:
++ *
++ * 128 bytes, the bitmap itself, for ports 0..0x3ff
++ * 8 bytes, for an extra "long" of ~0UL
++ */
++ unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
++} __attribute__((packed)) ____cacheline_aligned;
++
++DECLARE_PER_CPU(struct tss_struct,init_tss);
++#endif
++
++
++extern struct cpuinfo_x86 boot_cpu_data;
++/* Save the original ist values for checking stack pointers during debugging */
++struct orig_ist {
++ unsigned long ist[7];
++};
++DECLARE_PER_CPU(struct orig_ist, orig_ist);
++
++#ifdef CONFIG_X86_VSMP
++#define ARCH_MIN_TASKALIGN (1 << INTERNODE_CACHE_SHIFT)
++#define ARCH_MIN_MMSTRUCT_ALIGN (1 << INTERNODE_CACHE_SHIFT)
++#else
++#define ARCH_MIN_TASKALIGN 16
++#define ARCH_MIN_MMSTRUCT_ALIGN 0
++#endif
++
++struct thread_struct {
++ unsigned long rsp0;
++ unsigned long rsp;
++ unsigned long userrsp; /* Copy from PDA */
++ unsigned long fs;
++ unsigned long gs;
++ unsigned short es, ds, fsindex, gsindex;
++/* Hardware debugging registers */
++ unsigned long debugreg0;
++ unsigned long debugreg1;
++ unsigned long debugreg2;
++ unsigned long debugreg3;
++ unsigned long debugreg6;
++ unsigned long debugreg7;
++/* fault info */
++ unsigned long cr2, trap_no, error_code;
++/* floating point info */
++ union i387_union i387 __attribute__((aligned(16)));
++/* IO permissions. the bitmap could be moved into the GDT, that would make
++ switch faster for a limited number of ioperm using tasks. -AK */
++ int ioperm;
++ unsigned long *io_bitmap_ptr;
++ unsigned io_bitmap_max;
++/* cached TLS descriptors. */
++ u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
++ unsigned int iopl;
++} __attribute__((aligned(16)));
++
++#define INIT_THREAD { \
++ .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \
++}
++
++#ifndef CONFIG_X86_NO_TSS
++#define INIT_TSS { \
++ .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \
++}
++#endif
++
++#define INIT_MMAP \
++{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
++
++#define start_thread(regs,new_rip,new_rsp) do { \
++ asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0)); \
++ load_gs_index(0); \
++ (regs)->rip = (new_rip); \
++ (regs)->rsp = (new_rsp); \
++ write_pda(oldrsp, (new_rsp)); \
++ (regs)->cs = __USER_CS; \
++ (regs)->ss = __USER_DS; \
++ (regs)->eflags = 0x200; \
++ set_fs(USER_DS); \
++} while(0)
++
++#define get_debugreg(var, register) \
++ var = HYPERVISOR_get_debugreg(register)
++#define set_debugreg(value, register) \
++ HYPERVISOR_set_debugreg(register, value)
++
++struct task_struct;
++struct mm_struct;
++
++/* Free all resources held by a thread. */
++extern void release_thread(struct task_struct *);
++
++/* Prepare to copy thread state - unlazy all lazy status */
++extern void prepare_to_copy(struct task_struct *tsk);
++
++/*
++ * create a kernel thread without removing it from tasklists
++ */
++extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
++
++/*
++ * Return saved PC of a blocked thread.
++ * What is this good for? it will be always the scheduler or ret_from_fork.
++ */
++#define thread_saved_pc(t) (*(unsigned long *)((t)->thread.rsp - 8))
++
++extern unsigned long get_wchan(struct task_struct *p);
++#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.rsp0 - 1)
++#define KSTK_EIP(tsk) (task_pt_regs(tsk)->rip)
++#define KSTK_ESP(tsk) -1 /* sorry. doesn't work for syscall. */
++
++
++struct microcode_header {
++ unsigned int hdrver;
++ unsigned int rev;
++ unsigned int date;
++ unsigned int sig;
++ unsigned int cksum;
++ unsigned int ldrver;
++ unsigned int pf;
++ unsigned int datasize;
++ unsigned int totalsize;
++ unsigned int reserved[3];
++};
++
++struct microcode {
++ struct microcode_header hdr;
++ unsigned int bits[0];
++};
++
++typedef struct microcode microcode_t;
++typedef struct microcode_header microcode_header_t;
++
++/* microcode format is extended from prescott processors */
++struct extended_signature {
++ unsigned int sig;
++ unsigned int pf;
++ unsigned int cksum;
++};
++
++struct extended_sigtable {
++ unsigned int count;
++ unsigned int cksum;
++ unsigned int reserved[3];
++ struct extended_signature sigs[0];
++};
++
++
++#define ASM_NOP1 K8_NOP1
++#define ASM_NOP2 K8_NOP2
++#define ASM_NOP3 K8_NOP3
++#define ASM_NOP4 K8_NOP4
++#define ASM_NOP5 K8_NOP5
++#define ASM_NOP6 K8_NOP6
++#define ASM_NOP7 K8_NOP7
++#define ASM_NOP8 K8_NOP8
++
++/* Opteron nops */
++#define K8_NOP1 ".byte 0x90\n"
++#define K8_NOP2 ".byte 0x66,0x90\n"
++#define K8_NOP3 ".byte 0x66,0x66,0x90\n"
++#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n"
++#define K8_NOP5 K8_NOP3 K8_NOP2
++#define K8_NOP6 K8_NOP3 K8_NOP3
++#define K8_NOP7 K8_NOP4 K8_NOP3
++#define K8_NOP8 K8_NOP4 K8_NOP4
++
++#define ASM_NOP_MAX 8
++
++/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
++static inline void rep_nop(void)
++{
++ __asm__ __volatile__("rep;nop": : :"memory");
++}
++
++/* Stop speculative execution */
++static inline void sync_core(void)
++{
++ int tmp;
++ asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
++}
++
++#define cpu_has_fpu 1
++
++#define ARCH_HAS_PREFETCH
++static inline void prefetch(void *x)
++{
++ asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
++}
++
++#define ARCH_HAS_PREFETCHW 1
++static inline void prefetchw(void *x)
++{
++ alternative_input("prefetcht0 (%1)",
++ "prefetchw (%1)",
++ X86_FEATURE_3DNOW,
++ "r" (x));
++}
++
++#define ARCH_HAS_SPINLOCK_PREFETCH 1
++
++#define spin_lock_prefetch(x) prefetchw(x)
++
++#define cpu_relax() rep_nop()
++
++/*
++ * NSC/Cyrix CPU configuration register indexes
++ */
++#define CX86_CCR0 0xc0
++#define CX86_CCR1 0xc1
++#define CX86_CCR2 0xc2
++#define CX86_CCR3 0xc3
++#define CX86_CCR4 0xe8
++#define CX86_CCR5 0xe9
++#define CX86_CCR6 0xea
++#define CX86_CCR7 0xeb
++#define CX86_DIR0 0xfe
++#define CX86_DIR1 0xff
++#define CX86_ARR_BASE 0xc4
++#define CX86_RCR_BASE 0xdc
++
++/*
++ * NSC/Cyrix CPU indexed register access macros
++ */
++
++#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
++
++#define setCx86(reg, data) do { \
++ outb((reg), 0x22); \
++ outb((data), 0x23); \
++} while (0)
++
++static inline void serialize_cpu(void)
++{
++ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
++}
++
++static inline void __monitor(const void *eax, unsigned long ecx,
++ unsigned long edx)
++{
++ /* "monitor %eax,%ecx,%edx;" */
++ asm volatile(
++ ".byte 0x0f,0x01,0xc8;"
++ : :"a" (eax), "c" (ecx), "d"(edx));
++}
++
++static inline void __mwait(unsigned long eax, unsigned long ecx)
++{
++ /* "mwait %eax,%ecx;" */
++ asm volatile(
++ ".byte 0x0f,0x01,0xc9;"
++ : :"a" (eax), "c" (ecx));
++}
++
++#define stack_current() \
++({ \
++ struct thread_info *ti; \
++ asm("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \
++ ti->task; \
++})
++
++#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
++
++extern unsigned long boot_option_idle_override;
++/* Boot loader type from the setup header */
++extern int bootloader_type;
++
++#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
++
++#endif /* __ASM_X86_64_PROCESSOR_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/ptrace.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/ptrace.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/ptrace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/ptrace.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,125 @@
++#ifndef _X86_64_PTRACE_H
++#define _X86_64_PTRACE_H
++
++#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS)
++#define R15 0
++#define R14 8
++#define R13 16
++#define R12 24
++#define RBP 32
++#define RBX 40
++/* arguments: interrupts/non tracing syscalls only save upto here*/
++#define R11 48
++#define R10 56
++#define R9 64
++#define R8 72
++#define RAX 80
++#define RCX 88
++#define RDX 96
++#define RSI 104
++#define RDI 112
++#define ORIG_RAX 120 /* = ERROR */
++/* end of arguments */
++/* cpu exception frame or undefined in case of fast syscall. */
++#define RIP 128
++#define CS 136
++#define EFLAGS 144
++#define RSP 152
++#define SS 160
++#define ARGOFFSET R11
++#endif /* __ASSEMBLY__ */
++
++/* top of stack page */
++#define FRAME_SIZE 168
++
++#define PTRACE_OLDSETOPTIONS 21
++
++#ifndef __ASSEMBLY__
++
++struct pt_regs {
++ unsigned long r15;
++ unsigned long r14;
++ unsigned long r13;
++ unsigned long r12;
++ unsigned long rbp;
++ unsigned long rbx;
++/* arguments: non interrupts/non tracing syscalls only save upto here*/
++ unsigned long r11;
++ unsigned long r10;
++ unsigned long r9;
++ unsigned long r8;
++ unsigned long rax;
++ unsigned long rcx;
++ unsigned long rdx;
++ unsigned long rsi;
++ unsigned long rdi;
++ unsigned long orig_rax;
++/* end of arguments */
++/* cpu exception frame or undefined */
++ unsigned long rip;
++ unsigned long cs;
++ unsigned long eflags;
++ unsigned long rsp;
++ unsigned long ss;
++/* top of stack page */
++};
++
++#endif
++
++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
++#define PTRACE_GETREGS 12
++#define PTRACE_SETREGS 13
++#define PTRACE_GETFPREGS 14
++#define PTRACE_SETFPREGS 15
++#define PTRACE_GETFPXREGS 18
++#define PTRACE_SETFPXREGS 19
++
++/* only useful for access 32bit programs */
++#define PTRACE_GET_THREAD_AREA 25
++#define PTRACE_SET_THREAD_AREA 26
++
++#define PTRACE_ARCH_PRCTL 30 /* arch_prctl for child */
++
++#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
++#define user_mode(regs) (!!((regs)->cs & 3))
++#define user_mode_vm(regs) user_mode(regs)
++#define instruction_pointer(regs) ((regs)->rip)
++#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
++extern unsigned long profile_pc(struct pt_regs *regs);
++#else
++#define profile_pc(regs) instruction_pointer(regs)
++#endif
++
++void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
++
++struct task_struct;
++
++extern unsigned long
++convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs);
++
++enum {
++ EF_CF = 0x00000001,
++ EF_PF = 0x00000004,
++ EF_AF = 0x00000010,
++ EF_ZF = 0x00000040,
++ EF_SF = 0x00000080,
++ EF_TF = 0x00000100,
++ EF_IE = 0x00000200,
++ EF_DF = 0x00000400,
++ EF_OF = 0x00000800,
++ EF_IOPL = 0x00003000,
++ EF_IOPL_RING0 = 0x00000000,
++ EF_IOPL_RING1 = 0x00001000,
++ EF_IOPL_RING2 = 0x00002000,
++ EF_NT = 0x00004000, /* nested task */
++ EF_RF = 0x00010000, /* resume */
++ EF_VM = 0x00020000, /* virtual mode */
++ EF_AC = 0x00040000, /* alignment */
++ EF_VIF = 0x00080000, /* virtual interrupt */
++ EF_VIP = 0x00100000, /* virtual interrupt pending */
++ EF_ID = 0x00200000, /* id */
++};
++
++#endif
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/smp.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/smp.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/smp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/smp.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,150 @@
++#ifndef __ASM_SMP_H
++#define __ASM_SMP_H
++
++/*
++ * We need the APIC definitions automatically as part of 'smp.h'
++ */
++#ifndef __ASSEMBLY__
++#include <linux/threads.h>
++#include <linux/cpumask.h>
++#include <linux/bitops.h>
++extern int disable_apic;
++#endif
++
++#ifdef CONFIG_X86_LOCAL_APIC
++#ifndef __ASSEMBLY__
++#include <asm/fixmap.h>
++#include <asm/mpspec.h>
++#ifdef CONFIG_X86_IO_APIC
++#include <asm/io_apic.h>
++#endif
++#include <asm/apic.h>
++#include <asm/thread_info.h>
++#endif
++#endif
++
++#ifdef CONFIG_SMP
++#ifndef ASSEMBLY
++
++#include <asm/pda.h>
++
++struct pt_regs;
++
++extern cpumask_t cpu_present_mask;
++extern cpumask_t cpu_possible_map;
++extern cpumask_t cpu_online_map;
++extern cpumask_t cpu_initialized;
++
++/*
++ * Private routines/data
++ */
++
++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_send_reschedule(int cpu);
++void smp_stop_cpu(void);
++extern int smp_call_function_single(int cpuid, void (*func) (void *info),
++ void *info, int retry, int wait);
++
++extern cpumask_t cpu_sibling_map[NR_CPUS];
++extern cpumask_t cpu_core_map[NR_CPUS];
++extern u8 cpu_llc_id[NR_CPUS];
++
++#define SMP_TRAMPOLINE_BASE 0x6000
++
++/*
++ * On x86 all CPUs are mapped 1:1 to the APIC space.
++ * This simplifies scheduling and IPI sending and
++ * compresses data structures.
++ */
++
++static inline int num_booting_cpus(void)
++{
++ return cpus_weight(cpu_possible_map);
++}
++
++#define raw_smp_processor_id() read_pda(cpunumber)
++
++#ifdef CONFIG_X86_LOCAL_APIC
++static inline int hard_smp_processor_id(void)
++{
++ /* we don't want to mark this access volatile - bad code generation */
++ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
++}
++#endif
++
++extern int safe_smp_processor_id(void);
++extern int __cpu_disable(void);
++extern void __cpu_die(unsigned int cpu);
++extern void prefill_possible_map(void);
++extern unsigned num_processors;
++extern unsigned disabled_cpus;
++
++#endif /* !ASSEMBLY */
++
++#define NO_PROC_ID 0xFF /* No processor magic marker */
++
++#endif
++
++#ifndef ASSEMBLY
++/*
++ * Some lowlevel functions might want to know about
++ * the real APIC ID <-> CPU # mapping.
++ */
++extern u8 x86_cpu_to_apicid[NR_CPUS]; /* physical ID */
++extern u8 x86_cpu_to_log_apicid[NR_CPUS];
++extern u8 bios_cpu_apicid[];
++
++#ifdef CONFIG_X86_LOCAL_APIC
++static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
++{
++ return cpus_addr(cpumask)[0];
++}
++
++static inline int cpu_present_to_apicid(int mps_cpu)
++{
++ if (mps_cpu < NR_CPUS)
++ return (int)bios_cpu_apicid[mps_cpu];
++ else
++ return BAD_APICID;
++}
++#endif
++
++#endif /* !ASSEMBLY */
++
++#ifndef CONFIG_SMP
++#define stack_smp_processor_id() 0
++#define safe_smp_processor_id() 0
++#define cpu_logical_map(x) (x)
++#else
++#include <asm/thread_info.h>
++#define stack_smp_processor_id() \
++({ \
++ struct thread_info *ti; \
++ __asm__("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \
++ ti->cpu; \
++})
++#endif
++
++#ifndef __ASSEMBLY__
++#ifdef CONFIG_X86_LOCAL_APIC
++static __inline int logical_smp_processor_id(void)
++{
++ /* we don't want to mark this access volatile - bad code generation */
++ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
++}
++#endif
++#endif
++
++#ifdef CONFIG_SMP
++#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu]
++#else
++#define cpu_physical_id(cpu) boot_cpu_id
++#endif
++
++#endif
++
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/synch_bitops.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/synch_bitops.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/synch_bitops.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/synch_bitops.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,2 @@
++
++#include <asm-i386/mach-xen/asm/synch_bitops.h>
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/system.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/system.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/system.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/system.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,264 @@
++#ifndef __ASM_SYSTEM_H
++#define __ASM_SYSTEM_H
++
++#include <linux/kernel.h>
++#include <asm/segment.h>
++#include <asm/synch_bitops.h>
++#include <asm/hypervisor.h>
++#include <xen/interface/arch-x86_64.h>
++
++#ifdef __KERNEL__
++
++#ifdef CONFIG_SMP
++#define __vcpu_id smp_processor_id()
++#else
++#define __vcpu_id 0
++#endif
++
++#define __STR(x) #x
++#define STR(x) __STR(x)
++
++#define __SAVE(reg,offset) "movq %%" #reg ",(14-" #offset ")*8(%%rsp)\n\t"
++#define __RESTORE(reg,offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t"
++
++/* frame pointer must be last for get_wchan */
++#define SAVE_CONTEXT "pushq %%rbp ; movq %%rsi,%%rbp\n\t"
++#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\n\t"
++
++#define __EXTRA_CLOBBER \
++ ,"rcx","rbx","rdx","r8","r9","r10","r11","r12","r13","r14","r15"
++
++#define switch_to(prev,next,last) \
++ asm volatile(SAVE_CONTEXT \
++ "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
++ "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \
++ "call __switch_to\n\t" \
++ ".globl thread_return\n" \
++ "thread_return:\n\t" \
++ "movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \
++ "movq %P[thread_info](%%rsi),%%r8\n\t" \
++ LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \
++ "movq %%rax,%%rdi\n\t" \
++ "jc ret_from_fork\n\t" \
++ RESTORE_CONTEXT \
++ : "=a" (last) \
++ : [next] "S" (next), [prev] "D" (prev), \
++ [threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \
++ [ti_flags] "i" (offsetof(struct thread_info, flags)),\
++ [tif_fork] "i" (TIF_FORK), \
++ [thread_info] "i" (offsetof(struct task_struct, thread_info)), \
++ [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)) \
++ : "memory", "cc" __EXTRA_CLOBBER)
++
++
++extern void load_gs_index(unsigned);
++
++/*
++ * Load a segment. Fall back on loading the zero
++ * segment if something goes wrong..
++ */
++#define loadsegment(seg,value) \
++ asm volatile("\n" \
++ "1:\t" \
++ "movl %k0,%%" #seg "\n" \
++ "2:\n" \
++ ".section .fixup,\"ax\"\n" \
++ "3:\t" \
++ "movl %1,%%" #seg "\n\t" \
++ "jmp 2b\n" \
++ ".previous\n" \
++ ".section __ex_table,\"a\"\n\t" \
++ ".align 8\n\t" \
++ ".quad 1b,3b\n" \
++ ".previous" \
++ : :"r" (value), "r" (0))
++
++/*
++ * Clear and set 'TS' bit respectively
++ */
++#define clts() (HYPERVISOR_fpu_taskswitch(0))
++
++static inline unsigned long read_cr0(void)
++{
++ unsigned long cr0;
++ asm volatile("movq %%cr0,%0" : "=r" (cr0));
++ return cr0;
++}
++
++static inline void write_cr0(unsigned long val)
++{
++ asm volatile("movq %0,%%cr0" :: "r" (val));
++}
++
++#define read_cr3() ({ \
++ unsigned long __dummy; \
++ asm("movq %%cr3,%0" : "=r" (__dummy)); \
++ machine_to_phys(__dummy); \
++})
++
++static inline unsigned long read_cr4(void)
++{
++ unsigned long cr4;
++ asm("movq %%cr4,%0" : "=r" (cr4));
++ return cr4;
++}
++
++static inline void write_cr4(unsigned long val)
++{
++ asm volatile("movq %0,%%cr4" :: "r" (val));
++}
++
++#define stts() (HYPERVISOR_fpu_taskswitch(1))
++
++#define wbinvd() \
++ __asm__ __volatile__ ("wbinvd": : :"memory");
++
++/*
++ * On SMP systems, when the scheduler does migration-cost autodetection,
++ * it needs a way to flush as much of the CPU's caches as possible.
++ */
++static inline void sched_cacheflush(void)
++{
++ wbinvd();
++}
++
++#endif /* __KERNEL__ */
++
++#define nop() __asm__ __volatile__ ("nop")
++
++#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
++
++#define tas(ptr) (xchg((ptr),1))
++
++#define __xg(x) ((volatile long *)(x))
++
++static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
++{
++ *ptr = val;
++}
++
++#define _set_64bit set_64bit
++
++/*
++ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
++ * Note 2: xchg has side effect, so that attribute volatile is necessary,
++ * but generally the primitive is invalid, *ptr is output argument. --ANK
++ */
++static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
++{
++ switch (size) {
++ case 1:
++ __asm__ __volatile__("xchgb %b0,%1"
++ :"=q" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ case 2:
++ __asm__ __volatile__("xchgw %w0,%1"
++ :"=r" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ case 4:
++ __asm__ __volatile__("xchgl %k0,%1"
++ :"=r" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ case 8:
++ __asm__ __volatile__("xchgq %0,%1"
++ :"=r" (x)
++ :"m" (*__xg(ptr)), "0" (x)
++ :"memory");
++ break;
++ }
++ return x;
++}
++
++/*
++ * Atomic compare and exchange. Compare OLD with MEM, if identical,
++ * store NEW in MEM. Return the initial value in MEM. Success is
++ * indicated by comparing RETURN with OLD.
++ */
++
++#define __HAVE_ARCH_CMPXCHG 1
++
++static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
++ unsigned long new, int size)
++{
++ unsigned long prev;
++ switch (size) {
++ case 1:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 2:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 4:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 8:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
++ : "=a"(prev)
++ : "r"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ }
++ return old;
++}
++
++#define cmpxchg(ptr,o,n)\
++ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
++ (unsigned long)(n),sizeof(*(ptr))))
++
++#ifdef CONFIG_SMP
++#define smp_mb() mb()
++#define smp_rmb() rmb()
++#define smp_wmb() wmb()
++#define smp_read_barrier_depends() do {} while(0)
++#else
++#define smp_mb() barrier()
++#define smp_rmb() barrier()
++#define smp_wmb() barrier()
++#define smp_read_barrier_depends() do {} while(0)
++#endif
++
++
++/*
++ * Force strict CPU ordering.
++ * And yes, this is required on UP too when we're talking
++ * to devices.
++ */
++#define mb() asm volatile("mfence":::"memory")
++#define rmb() asm volatile("lfence":::"memory")
++
++#ifdef CONFIG_UNORDERED_IO
++#define wmb() asm volatile("sfence" ::: "memory")
++#else
++#define wmb() asm volatile("" ::: "memory")
++#endif
++#define read_barrier_depends() do {} while(0)
++#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
++
++#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
++
++void safe_halt(void);
++void halt(void);
++
++#include <linux/irqflags.h>
++
++void cpu_idle_wait(void);
++
++extern unsigned long arch_align_stack(unsigned long sp);
++extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/timer.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/timer.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/timer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/timer.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,67 @@
++#ifndef _ASMi386_TIMER_H
++#define _ASMi386_TIMER_H
++#include <linux/init.h>
++
++/**
++ * struct timer_ops - used to define a timer source
++ *
++ * @name: name of the timer.
++ * @init: Probes and initializes the timer. Takes clock= override
++ * string as an argument. Returns 0 on success, anything else
++ * on failure.
++ * @mark_offset: called by the timer interrupt.
++ * @get_offset: called by gettimeofday(). Returns the number of microseconds
++ * since the last timer interupt.
++ * @monotonic_clock: returns the number of nanoseconds since the init of the
++ * timer.
++ * @delay: delays this many clock cycles.
++ */
++struct timer_opts {
++ char* name;
++ void (*mark_offset)(void);
++ unsigned long (*get_offset)(void);
++ unsigned long long (*monotonic_clock)(void);
++ void (*delay)(unsigned long);
++ unsigned long (*read_timer)(void);
++ int (*suspend)(pm_message_t state);
++ int (*resume)(void);
++};
++
++struct init_timer_opts {
++ int (*init)(char *override);
++ struct timer_opts *opts;
++};
++
++#define TICK_SIZE (tick_nsec / 1000)
++
++extern struct timer_opts* __init select_timer(void);
++extern void clock_fallback(void);
++void setup_pit_timer(void);
++
++/* Modifiers for buggy PIT handling */
++
++extern int pit_latch_buggy;
++
++extern struct timer_opts *cur_timer;
++extern int timer_ack;
++
++/* list of externed timers */
++extern struct timer_opts timer_none;
++extern struct timer_opts timer_pit;
++extern struct init_timer_opts timer_pit_init;
++extern struct init_timer_opts timer_tsc_init;
++#ifdef CONFIG_X86_CYCLONE_TIMER
++extern struct init_timer_opts timer_cyclone_init;
++#endif
++
++extern unsigned long calibrate_tsc(void);
++extern void init_cpu_khz(void);
++#ifdef CONFIG_HPET_TIMER
++extern struct init_timer_opts timer_hpet_init;
++extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
++#endif
++
++#ifdef CONFIG_X86_PM_TIMER
++extern struct init_timer_opts timer_pmtmr_init;
++#endif
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/tlbflush.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/tlbflush.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/tlbflush.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/tlbflush.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,103 @@
++#ifndef _X8664_TLBFLUSH_H
++#define _X8664_TLBFLUSH_H
++
++#include <linux/mm.h>
++#include <asm/processor.h>
++
++#define __flush_tlb() xen_tlb_flush()
++
++/*
++ * Global pages have to be flushed a bit differently. Not a real
++ * performance problem because this does not happen often.
++ */
++#define __flush_tlb_global() xen_tlb_flush()
++
++
++extern unsigned long pgkern_mask;
++
++#define __flush_tlb_all() __flush_tlb_global()
++
++#define __flush_tlb_one(addr) xen_invlpg((unsigned long)addr)
++
++
++/*
++ * TLB flushing:
++ *
++ * - flush_tlb() flushes the current mm struct TLBs
++ * - flush_tlb_all() flushes all processes TLBs
++ * - flush_tlb_mm(mm) flushes the specified mm context TLB's
++ * - flush_tlb_page(vma, vmaddr) flushes one page
++ * - flush_tlb_range(vma, start, end) flushes a range of pages
++ * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
++ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
++ *
++ * x86-64 can only flush individual pages or full VMs. For a range flush
++ * we always do the full VM. Might be worth trying if for a small
++ * range a few INVLPGs in a row are a win.
++ */
++
++#ifndef CONFIG_SMP
++
++#define flush_tlb() __flush_tlb()
++#define flush_tlb_all() __flush_tlb_all()
++#define local_flush_tlb() __flush_tlb()
++
++static inline void flush_tlb_mm(struct mm_struct *mm)
++{
++ if (mm == current->active_mm)
++ __flush_tlb();
++}
++
++static inline void flush_tlb_page(struct vm_area_struct *vma,
++ unsigned long addr)
++{
++ if (vma->vm_mm == current->active_mm)
++ __flush_tlb_one(addr);
++}
++
++static inline void flush_tlb_range(struct vm_area_struct *vma,
++ unsigned long start, unsigned long end)
++{
++ if (vma->vm_mm == current->active_mm)
++ __flush_tlb();
++}
++
++#else
++
++#include <asm/smp.h>
++
++#define local_flush_tlb() \
++ __flush_tlb()
++
++extern void flush_tlb_all(void);
++extern void flush_tlb_current_task(void);
++extern void flush_tlb_mm(struct mm_struct *);
++extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
++
++#define flush_tlb() flush_tlb_current_task()
++
++static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
++{
++ flush_tlb_mm(vma->vm_mm);
++}
++
++#define TLBSTATE_OK 1
++#define TLBSTATE_LAZY 2
++
++/* Roughly an IPI every 20MB with 4k pages for freeing page table
++ ranges. Cost is about 42k of memory for each CPU. */
++#define ARCH_FREE_PTE_NR 5350
++
++#endif
++
++#define flush_tlb_kernel_range(start, end) flush_tlb_all()
++
++static inline void flush_tlb_pgtables(struct mm_struct *mm,
++ unsigned long start, unsigned long end)
++{
++ /* x86_64 does not keep any page table caches in a software TLB.
++ The CPUs do in their hardware TLBs, but they are handled
++ by the normal TLB flushing algorithms. */
++}
++
++#endif /* _X8664_TLBFLUSH_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/vga.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/vga.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/vga.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/vga.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,20 @@
++/*
++ * Access to VGA videoram
++ *
++ * (c) 1998 Martin Mares <mj at ucw.cz>
++ */
++
++#ifndef _LINUX_ASM_VGA_H_
++#define _LINUX_ASM_VGA_H_
++
++/*
++ * On the PC, we can just recalculate addresses and then
++ * access the videoram directly without any black magic.
++ */
++
++#define VGA_MAP_MEM(x,s) (unsigned long)isa_bus_to_virt(x)
++
++#define vga_readb(x) (*(x))
++#define vga_writeb(x,y) (*(y) = (x))
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/xor.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/xor.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/asm/xor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/asm/xor.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,328 @@
++/*
++ * x86-64 changes / gcc fixes from Andi Kleen.
++ * Copyright 2002 Andi Kleen, SuSE Labs.
++ *
++ * This hasn't been optimized for the hammer yet, but there are likely
++ * no advantages to be gotten from x86-64 here anyways.
++ */
++
++typedef struct { unsigned long a,b; } __attribute__((aligned(16))) xmm_store_t;
++
++/* Doesn't use gcc to save the XMM registers, because there is no easy way to
++ tell it to do a clts before the register saving. */
++#define XMMS_SAVE do { \
++ preempt_disable(); \
++ if (!(current_thread_info()->status & TS_USEDFPU)) \
++ clts(); \
++ __asm__ __volatile__ ( \
++ "movups %%xmm0,(%1) ;\n\t" \
++ "movups %%xmm1,0x10(%1) ;\n\t" \
++ "movups %%xmm2,0x20(%1) ;\n\t" \
++ "movups %%xmm3,0x30(%1) ;\n\t" \
++ : "=&r" (cr0) \
++ : "r" (xmm_save) \
++ : "memory"); \
++} while(0)
++
++#define XMMS_RESTORE do { \
++ asm volatile ( \
++ "sfence ;\n\t" \
++ "movups (%1),%%xmm0 ;\n\t" \
++ "movups 0x10(%1),%%xmm1 ;\n\t" \
++ "movups 0x20(%1),%%xmm2 ;\n\t" \
++ "movups 0x30(%1),%%xmm3 ;\n\t" \
++ : \
++ : "r" (cr0), "r" (xmm_save) \
++ : "memory"); \
++ if (!(current_thread_info()->status & TS_USEDFPU)) \
++ stts(); \
++ preempt_enable(); \
++} while(0)
++
++#define OFFS(x) "16*("#x")"
++#define PF_OFFS(x) "256+16*("#x")"
++#define PF0(x) " prefetchnta "PF_OFFS(x)"(%[p1]) ;\n"
++#define LD(x,y) " movaps "OFFS(x)"(%[p1]), %%xmm"#y" ;\n"
++#define ST(x,y) " movaps %%xmm"#y", "OFFS(x)"(%[p1]) ;\n"
++#define PF1(x) " prefetchnta "PF_OFFS(x)"(%[p2]) ;\n"
++#define PF2(x) " prefetchnta "PF_OFFS(x)"(%[p3]) ;\n"
++#define PF3(x) " prefetchnta "PF_OFFS(x)"(%[p4]) ;\n"
++#define PF4(x) " prefetchnta "PF_OFFS(x)"(%[p5]) ;\n"
++#define PF5(x) " prefetchnta "PF_OFFS(x)"(%[p6]) ;\n"
++#define XO1(x,y) " xorps "OFFS(x)"(%[p2]), %%xmm"#y" ;\n"
++#define XO2(x,y) " xorps "OFFS(x)"(%[p3]), %%xmm"#y" ;\n"
++#define XO3(x,y) " xorps "OFFS(x)"(%[p4]), %%xmm"#y" ;\n"
++#define XO4(x,y) " xorps "OFFS(x)"(%[p5]), %%xmm"#y" ;\n"
++#define XO5(x,y) " xorps "OFFS(x)"(%[p6]), %%xmm"#y" ;\n"
++
++
++static void
++xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
++{
++ unsigned int lines = bytes >> 8;
++ unsigned long cr0;
++ xmm_store_t xmm_save[4];
++
++ XMMS_SAVE;
++
++ asm volatile (
++#undef BLOCK
++#define BLOCK(i) \
++ LD(i,0) \
++ LD(i+1,1) \
++ PF1(i) \
++ PF1(i+2) \
++ LD(i+2,2) \
++ LD(i+3,3) \
++ PF0(i+4) \
++ PF0(i+6) \
++ XO1(i,0) \
++ XO1(i+1,1) \
++ XO1(i+2,2) \
++ XO1(i+3,3) \
++ ST(i,0) \
++ ST(i+1,1) \
++ ST(i+2,2) \
++ ST(i+3,3) \
++
++
++ PF0(0)
++ PF0(2)
++
++ " .align 32 ;\n"
++ " 1: ;\n"
++
++ BLOCK(0)
++ BLOCK(4)
++ BLOCK(8)
++ BLOCK(12)
++
++ " addq %[inc], %[p1] ;\n"
++ " addq %[inc], %[p2] ;\n"
++ " decl %[cnt] ; jnz 1b"
++ : [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines)
++ : [inc] "r" (256UL)
++ : "memory");
++
++ XMMS_RESTORE;
++}
++
++static void
++xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++ unsigned long *p3)
++{
++ unsigned int lines = bytes >> 8;
++ xmm_store_t xmm_save[4];
++ unsigned long cr0;
++
++ XMMS_SAVE;
++
++ __asm__ __volatile__ (
++#undef BLOCK
++#define BLOCK(i) \
++ PF1(i) \
++ PF1(i+2) \
++ LD(i,0) \
++ LD(i+1,1) \
++ LD(i+2,2) \
++ LD(i+3,3) \
++ PF2(i) \
++ PF2(i+2) \
++ PF0(i+4) \
++ PF0(i+6) \
++ XO1(i,0) \
++ XO1(i+1,1) \
++ XO1(i+2,2) \
++ XO1(i+3,3) \
++ XO2(i,0) \
++ XO2(i+1,1) \
++ XO2(i+2,2) \
++ XO2(i+3,3) \
++ ST(i,0) \
++ ST(i+1,1) \
++ ST(i+2,2) \
++ ST(i+3,3) \
++
++
++ PF0(0)
++ PF0(2)
++
++ " .align 32 ;\n"
++ " 1: ;\n"
++
++ BLOCK(0)
++ BLOCK(4)
++ BLOCK(8)
++ BLOCK(12)
++
++ " addq %[inc], %[p1] ;\n"
++ " addq %[inc], %[p2] ;\n"
++ " addq %[inc], %[p3] ;\n"
++ " decl %[cnt] ; jnz 1b"
++ : [cnt] "+r" (lines),
++ [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
++ : [inc] "r" (256UL)
++ : "memory");
++ XMMS_RESTORE;
++}
++
++static void
++xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++ unsigned long *p3, unsigned long *p4)
++{
++ unsigned int lines = bytes >> 8;
++ xmm_store_t xmm_save[4];
++ unsigned long cr0;
++
++ XMMS_SAVE;
++
++ __asm__ __volatile__ (
++#undef BLOCK
++#define BLOCK(i) \
++ PF1(i) \
++ PF1(i+2) \
++ LD(i,0) \
++ LD(i+1,1) \
++ LD(i+2,2) \
++ LD(i+3,3) \
++ PF2(i) \
++ PF2(i+2) \
++ XO1(i,0) \
++ XO1(i+1,1) \
++ XO1(i+2,2) \
++ XO1(i+3,3) \
++ PF3(i) \
++ PF3(i+2) \
++ PF0(i+4) \
++ PF0(i+6) \
++ XO2(i,0) \
++ XO2(i+1,1) \
++ XO2(i+2,2) \
++ XO2(i+3,3) \
++ XO3(i,0) \
++ XO3(i+1,1) \
++ XO3(i+2,2) \
++ XO3(i+3,3) \
++ ST(i,0) \
++ ST(i+1,1) \
++ ST(i+2,2) \
++ ST(i+3,3) \
++
++
++ PF0(0)
++ PF0(2)
++
++ " .align 32 ;\n"
++ " 1: ;\n"
++
++ BLOCK(0)
++ BLOCK(4)
++ BLOCK(8)
++ BLOCK(12)
++
++ " addq %[inc], %[p1] ;\n"
++ " addq %[inc], %[p2] ;\n"
++ " addq %[inc], %[p3] ;\n"
++ " addq %[inc], %[p4] ;\n"
++ " decl %[cnt] ; jnz 1b"
++ : [cnt] "+c" (lines),
++ [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
++ : [inc] "r" (256UL)
++ : "memory" );
++
++ XMMS_RESTORE;
++}
++
++static void
++xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++ unsigned long *p3, unsigned long *p4, unsigned long *p5)
++{
++ unsigned int lines = bytes >> 8;
++ xmm_store_t xmm_save[4];
++ unsigned long cr0;
++
++ XMMS_SAVE;
++
++ __asm__ __volatile__ (
++#undef BLOCK
++#define BLOCK(i) \
++ PF1(i) \
++ PF1(i+2) \
++ LD(i,0) \
++ LD(i+1,1) \
++ LD(i+2,2) \
++ LD(i+3,3) \
++ PF2(i) \
++ PF2(i+2) \
++ XO1(i,0) \
++ XO1(i+1,1) \
++ XO1(i+2,2) \
++ XO1(i+3,3) \
++ PF3(i) \
++ PF3(i+2) \
++ XO2(i,0) \
++ XO2(i+1,1) \
++ XO2(i+2,2) \
++ XO2(i+3,3) \
++ PF4(i) \
++ PF4(i+2) \
++ PF0(i+4) \
++ PF0(i+6) \
++ XO3(i,0) \
++ XO3(i+1,1) \
++ XO3(i+2,2) \
++ XO3(i+3,3) \
++ XO4(i,0) \
++ XO4(i+1,1) \
++ XO4(i+2,2) \
++ XO4(i+3,3) \
++ ST(i,0) \
++ ST(i+1,1) \
++ ST(i+2,2) \
++ ST(i+3,3) \
++
++
++ PF0(0)
++ PF0(2)
++
++ " .align 32 ;\n"
++ " 1: ;\n"
++
++ BLOCK(0)
++ BLOCK(4)
++ BLOCK(8)
++ BLOCK(12)
++
++ " addq %[inc], %[p1] ;\n"
++ " addq %[inc], %[p2] ;\n"
++ " addq %[inc], %[p3] ;\n"
++ " addq %[inc], %[p4] ;\n"
++ " addq %[inc], %[p5] ;\n"
++ " decl %[cnt] ; jnz 1b"
++ : [cnt] "+c" (lines),
++ [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4),
++ [p5] "+r" (p5)
++ : [inc] "r" (256UL)
++ : "memory");
++
++ XMMS_RESTORE;
++}
++
++static struct xor_block_template xor_block_sse = {
++ .name = "generic_sse",
++ .do_2 = xor_sse_2,
++ .do_3 = xor_sse_3,
++ .do_4 = xor_sse_4,
++ .do_5 = xor_sse_5,
++};
++
++#undef XOR_TRY_TEMPLATES
++#define XOR_TRY_TEMPLATES \
++ do { \
++ xor_speed(&xor_block_sse); \
++ } while (0)
++
++/* We force the use of the SSE xor block because it can write around L2.
++ We may also be able to load into the L1 only depending on how the cpu
++ deals with a load to a line that is being prefetched. */
++#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/irq_vectors.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/irq_vectors.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/irq_vectors.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/irq_vectors.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,123 @@
++/*
++ * This file should contain #defines for all of the interrupt vector
++ * numbers used by this architecture.
++ *
++ * In addition, there are some standard defines:
++ *
++ * FIRST_EXTERNAL_VECTOR:
++ * The first free place for external interrupts
++ *
++ * SYSCALL_VECTOR:
++ * The IRQ vector a syscall makes the user to kernel transition
++ * under.
++ *
++ * TIMER_IRQ:
++ * The IRQ number the timer interrupt comes in at.
++ *
++ * NR_IRQS:
++ * The total number of interrupt vectors (including all the
++ * architecture specific interrupts) needed.
++ *
++ */
++#ifndef _ASM_IRQ_VECTORS_H
++#define _ASM_IRQ_VECTORS_H
++
++/*
++ * IDT vectors usable for external interrupt sources start
++ * at 0x20:
++ */
++#define FIRST_EXTERNAL_VECTOR 0x20
++
++#define SYSCALL_VECTOR 0x80
++
++/*
++ * Vectors 0x20-0x2f are used for ISA interrupts.
++ */
++
++#if 0
++/*
++ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
++ *
++ * some of the following vectors are 'rare', they are merged
++ * into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
++ * TLB, reschedule and local APIC vectors are performance-critical.
++ *
++ * Vectors 0xf0-0xfa are free (reserved for future Linux use).
++ */
++#define INVALIDATE_TLB_VECTOR 0xfd
++#define RESCHEDULE_VECTOR 0xfc
++#define CALL_FUNCTION_VECTOR 0xfb
++
++#define THERMAL_APIC_VECTOR 0xf0
++/*
++ * Local APIC timer IRQ vector is on a different priority level,
++ * to work around the 'lost local interrupt if more than 2 IRQ
++ * sources per level' errata.
++ */
++#define LOCAL_TIMER_VECTOR 0xef
++#endif
++
++#define SPURIOUS_APIC_VECTOR 0xff
++#define ERROR_APIC_VECTOR 0xfe
++
++/*
++ * First APIC vector available to drivers: (vectors 0x30-0xee)
++ * we start at 0x31 to spread out vectors evenly between priority
++ * levels. (0x80 is the syscall vector)
++ */
++#define FIRST_DEVICE_VECTOR 0x31
++#define FIRST_SYSTEM_VECTOR 0xef
++
++/*
++ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
++ * Right now the APIC is mostly only used for SMP.
++ * 256 vectors is an architectural limit. (we can have
++ * more than 256 devices theoretically, but they will
++ * have to use shared interrupts)
++ * Since vectors 0x00-0x1f are used/reserved for the CPU,
++ * the usable vector space is 0x20-0xff (224 vectors)
++ */
++
++#define RESCHEDULE_VECTOR 0
++#define CALL_FUNCTION_VECTOR 1
++#define NR_IPIS 2
++
++/*
++ * The maximum number of vectors supported by i386 processors
++ * is limited to 256. For processors other than i386, NR_VECTORS
++ * should be changed accordingly.
++ */
++#define NR_VECTORS 256
++
++#define FPU_IRQ 13
++
++#define FIRST_VM86_IRQ 3
++#define LAST_VM86_IRQ 15
++#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15)
++
++/*
++ * The flat IRQ space is divided into two regions:
++ * 1. A one-to-one mapping of real physical IRQs. This space is only used
++ * if we have physical device-access privilege. This region is at the
++ * start of the IRQ space so that existing device drivers do not need
++ * to be modified to translate physical IRQ numbers into our IRQ space.
++ * 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These
++ * are bound using the provided bind/unbind functions.
++ */
++
++#define PIRQ_BASE 0
++#define NR_PIRQS 256
++
++#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
++#define NR_DYNIRQS 256
++
++#define NR_IRQS (NR_PIRQS + NR_DYNIRQS)
++#define NR_IRQ_VECTORS NR_IRQS
++
++#define pirq_to_irq(_x) ((_x) + PIRQ_BASE)
++#define irq_to_pirq(_x) ((_x) - PIRQ_BASE)
++
++#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE)
++#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE)
++
++#endif /* _ASM_IRQ_VECTORS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/mach_time.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/mach_time.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/mach_time.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/mach_time.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,111 @@
++/*
++ * include/asm-i386/mach-default/mach_time.h
++ *
++ * Machine specific set RTC function for generic.
++ * Split out from time.c by Osamu Tomita <tomita at cinet.co.jp>
++ */
++#ifndef _MACH_TIME_H
++#define _MACH_TIME_H
++
++#include <asm-i386/mc146818rtc.h>
++
++/* for check timing call set_rtc_mmss() 500ms */
++/* used in arch/i386/time.c::do_timer_interrupt() */
++#define USEC_AFTER 500000
++#define USEC_BEFORE 500000
++
++/*
++ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
++ * called 500 ms after the second nowtime has started, because when
++ * nowtime is written into the registers of the CMOS clock, it will
++ * jump to the next second precisely 500 ms later. Check the Motorola
++ * MC146818A or Dallas DS12887 data sheet for details.
++ *
++ * BUG: This routine does not handle hour overflow properly; it just
++ * sets the minutes. Usually you'll only notice that after reboot!
++ */
++static inline int mach_set_rtc_mmss(unsigned long nowtime)
++{
++ int retval = 0;
++ int real_seconds, real_minutes, cmos_minutes;
++ unsigned char save_control, save_freq_select;
++
++ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
++ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
++
++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
++ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
++
++ cmos_minutes = CMOS_READ(RTC_MINUTES);
++ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
++ BCD_TO_BIN(cmos_minutes);
++
++ /*
++ * since we're only adjusting minutes and seconds,
++ * don't interfere with hour overflow. This avoids
++ * messing with unknown time zones but requires your
++ * RTC not to be off by more than 15 minutes
++ */
++ real_seconds = nowtime % 60;
++ real_minutes = nowtime / 60;
++ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
++ real_minutes += 30; /* correct for half hour time zone */
++ real_minutes %= 60;
++
++ if (abs(real_minutes - cmos_minutes) < 30) {
++ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
++ BIN_TO_BCD(real_seconds);
++ BIN_TO_BCD(real_minutes);
++ }
++ CMOS_WRITE(real_seconds,RTC_SECONDS);
++ CMOS_WRITE(real_minutes,RTC_MINUTES);
++ } else {
++ printk(KERN_WARNING
++ "set_rtc_mmss: can't update from %d to %d\n",
++ cmos_minutes, real_minutes);
++ retval = -1;
++ }
++
++ /* The following flags have to be released exactly in this order,
++ * otherwise the DS12887 (popular MC146818A clone with integrated
++ * battery and quartz) will not reset the oscillator and will not
++ * update precisely 500 ms later. You won't find this mentioned in
++ * the Dallas Semiconductor data sheets, but who believes data
++ * sheets anyway ... -- Markus Kuhn
++ */
++ CMOS_WRITE(save_control, RTC_CONTROL);
++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
++
++ return retval;
++}
++
++static inline unsigned long mach_get_cmos_time(void)
++{
++ unsigned int year, mon, day, hour, min, sec;
++
++ do {
++ sec = CMOS_READ(RTC_SECONDS);
++ min = CMOS_READ(RTC_MINUTES);
++ hour = CMOS_READ(RTC_HOURS);
++ day = CMOS_READ(RTC_DAY_OF_MONTH);
++ mon = CMOS_READ(RTC_MONTH);
++ year = CMOS_READ(RTC_YEAR);
++ } while (sec != CMOS_READ(RTC_SECONDS));
++
++ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
++ BCD_TO_BIN(sec);
++ BCD_TO_BIN(min);
++ BCD_TO_BIN(hour);
++ BCD_TO_BIN(day);
++ BCD_TO_BIN(mon);
++ BCD_TO_BIN(year);
++ }
++
++ year += 1900;
++ if (year < 1970)
++ year += 100;
++
++ return mktime(year, mon, day, hour, min, sec);
++}
++
++#endif /* !_MACH_TIME_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/mach_timer.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/mach_timer.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/mach_timer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/mach_timer.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * include/asm-i386/mach-default/mach_timer.h
++ *
++ * Machine specific calibrate_tsc() for generic.
++ * Split out from timer_tsc.c by Osamu Tomita <tomita at cinet.co.jp>
++ */
++/* ------ Calibrate the TSC -------
++ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
++ * Too much 64-bit arithmetic here to do this cleanly in C, and for
++ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
++ * output busy loop as low as possible. We avoid reading the CTC registers
++ * directly because of the awkward 8-bit access mechanism of the 82C54
++ * device.
++ */
++#ifndef _MACH_TIMER_H
++#define _MACH_TIMER_H
++
++#define CALIBRATE_LATCH (5 * LATCH)
++
++static inline void mach_prepare_counter(void)
++{
++ /* Set the Gate high, disable speaker */
++ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
++
++ /*
++ * Now let's take care of CTC channel 2
++ *
++ * Set the Gate high, program CTC channel 2 for mode 0,
++ * (interrupt on terminal count mode), binary count,
++ * load 5 * LATCH count, (LSB and MSB) to begin countdown.
++ *
++ * Some devices need a delay here.
++ */
++ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
++ outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
++ outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
++}
++
++static inline void mach_countup(unsigned long *count_p)
++{
++ unsigned long count = 0;
++ do {
++ count++;
++ } while ((inb_p(0x61) & 0x20) == 0);
++ *count_p = count;
++}
++
++#endif /* !_MACH_TIMER_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/setup_arch_post.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/setup_arch_post.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/setup_arch_post.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/setup_arch_post.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,58 @@
++/**
++ * machine_specific_* - Hooks for machine specific setup.
++ *
++ * Description:
++ * This is included late in kernel/setup.c so that it can make
++ * use of all of the static functions.
++ **/
++
++#include <xen/interface/callback.h>
++
++extern void hypervisor_callback(void);
++extern void failsafe_callback(void);
++extern void nmi(void);
++
++static void __init machine_specific_arch_setup(void)
++{
++ int ret;
++ struct callback_register event = {
++ .type = CALLBACKTYPE_event,
++ .address = (unsigned long) hypervisor_callback,
++ };
++ struct callback_register failsafe = {
++ .type = CALLBACKTYPE_failsafe,
++ .address = (unsigned long)failsafe_callback,
++ };
++ struct callback_register syscall = {
++ .type = CALLBACKTYPE_syscall,
++ .address = (unsigned long)system_call,
++ };
++#ifdef CONFIG_X86_LOCAL_APIC
++ struct callback_register nmi_cb = {
++ .type = CALLBACKTYPE_nmi,
++ .address = (unsigned long)nmi,
++ };
++#endif
++
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
++ if (ret == 0)
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
++ if (ret == 0)
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &syscall);
++ if (ret == -ENOSYS)
++ ret = HYPERVISOR_set_callbacks(
++ event.address,
++ failsafe.address,
++ syscall.address);
++ BUG_ON(ret);
++
++#ifdef CONFIG_X86_LOCAL_APIC
++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
++ if (ret == -ENOSYS) {
++ struct xennmi_callback cb;
++
++ cb.handler_address = nmi_cb.address;
++ HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
++ }
++#endif
++}
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/asm-x86_64/mach-xen/setup_arch_pre.h linux-2.6.18-xen/include/asm-x86_64/mach-xen/setup_arch_pre.h
+--- linux-2.6.18.1/include/asm-x86_64/mach-xen/setup_arch_pre.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/asm-x86_64/mach-xen/setup_arch_pre.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,5 @@
++/* Hook to call BIOS initialisation function */
++
++#define ARCH_SETUP machine_specific_arch_setup();
++
++static void __init machine_specific_arch_setup(void);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/elfnote.h linux-2.6.18-xen/include/linux/elfnote.h
+--- linux-2.6.18.1/include/linux/elfnote.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/linux/elfnote.h 2006-09-04 16:31:18.000000000 +0200
+@@ -0,0 +1,90 @@
++#ifndef _LINUX_ELFNOTE_H
++#define _LINUX_ELFNOTE_H
++/*
++ * Helper macros to generate ELF Note structures, which are put into a
++ * PT_NOTE segment of the final vmlinux image. These are useful for
++ * including name-value pairs of metadata into the kernel binary (or
++ * modules?) for use by external programs.
++ *
++ * Each note has three parts: a name, a type and a desc. The name is
++ * intended to distinguish the note's originator, so it would be a
++ * company, project, subsystem, etc; it must be in a suitable form for
++ * use in a section name. The type is an integer which is used to tag
++ * the data, and is considered to be within the "name" namespace (so
++ * "FooCo"'s type 42 is distinct from "BarProj"'s type 42). The
++ * "desc" field is the actual data. There are no constraints on the
++ * desc field's contents, though typically they're fairly small.
++ *
++ * All notes from a given NAME are put into a section named
++ * .note.NAME. When the kernel image is finally linked, all the notes
++ * are packed into a single .notes section, which is mapped into the
++ * PT_NOTE segment. Because notes for a given name are grouped into
++ * the same section, they'll all be adjacent the output file.
++ *
++ * This file defines macros for both C and assembler use. Their
++ * syntax is slightly different, but they're semantically similar.
++ *
++ * See the ELF specification for more detail about ELF notes.
++ */
++
++#ifdef __ASSEMBLER__
++/*
++ * Generate a structure with the same shape as Elf{32,64}_Nhdr (which
++ * turn out to be the same size and shape), followed by the name and
++ * desc data with appropriate padding. The 'desctype' argument is the
++ * assembler pseudo op defining the type of the data e.g. .asciz while
++ * 'descdata' is the data itself e.g. "hello, world".
++ *
++ * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
++ * ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
++ */
++#define ELFNOTE(name, type, desctype, descdata) \
++.pushsection .note.name ; \
++ .align 4 ; \
++ .long 2f - 1f /* namesz */ ; \
++ .long 4f - 3f /* descsz */ ; \
++ .long type ; \
++1:.asciz "name" ; \
++2:.align 4 ; \
++3:desctype descdata ; \
++4:.align 4 ; \
++.popsection ;
++#else /* !__ASSEMBLER__ */
++#include <linux/elf.h>
++/*
++ * Use an anonymous structure which matches the shape of
++ * Elf{32,64}_Nhdr, but includes the name and desc data. The size and
++ * type of name and desc depend on the macro arguments. "name" must
++ * be a literal string, and "desc" must be passed by value. You may
++ * only define one note per line, since __LINE__ is used to generate
++ * unique symbols.
++ */
++#define _ELFNOTE_PASTE(a,b) a##b
++#define _ELFNOTE(size, name, unique, type, desc) \
++ static const struct { \
++ struct elf##size##_note _nhdr; \
++ unsigned char _name[sizeof(name)] \
++ __attribute__((aligned(sizeof(Elf##size##_Word)))); \
++ typeof(desc) _desc \
++ __attribute__((aligned(sizeof(Elf##size##_Word)))); \
++ } _ELFNOTE_PASTE(_note_, unique) \
++ __attribute_used__ \
++ __attribute__((section(".note." name), \
++ aligned(sizeof(Elf##size##_Word)), \
++ unused)) = { \
++ { \
++ sizeof(name), \
++ sizeof(desc), \
++ type, \
++ }, \
++ name, \
++ desc \
++ }
++#define ELFNOTE(size, name, type, desc) \
++ _ELFNOTE(size, name, __LINE__, type, desc)
++
++#define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc)
++#define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc)
++#endif /* __ASSEMBLER__ */
++
++#endif /* _LINUX_ELFNOTE_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/gfp.h linux-2.6.18-xen/include/linux/gfp.h
+--- linux-2.6.18.1/include/linux/gfp.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/gfp.h 2006-09-04 16:31:18.000000000 +0200
+@@ -99,7 +99,11 @@
+ */
+
+ #ifndef HAVE_ARCH_FREE_PAGE
+-static inline void arch_free_page(struct page *page, int order) { }
++/*
++ * If arch_free_page returns non-zero then the generic free_page code can
++ * immediately bail: the arch-specific function has done all the work.
++ */
++static inline int arch_free_page(struct page *page, int order) { return 0; }
+ #endif
+
+ extern struct page *
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/highmem.h linux-2.6.18-xen/include/linux/highmem.h
+--- linux-2.6.18.1/include/linux/highmem.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/highmem.h 2006-09-04 16:31:18.000000000 +0200
+@@ -24,10 +24,16 @@
+
+ /* declarations for linux/mm/highmem.c */
+ unsigned int nr_free_highpages(void);
++#ifdef CONFIG_XEN
++void kmap_flush_unused(void);
++#endif
+
+ #else /* CONFIG_HIGHMEM */
+
+ static inline unsigned int nr_free_highpages(void) { return 0; }
++#ifdef CONFIG_XEN
++static inline void kmap_flush_unused(void) { }
++#endif
+
+ static inline void *kmap(struct page *page)
+ {
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/interrupt.h linux-2.6.18-xen/include/linux/interrupt.h
+--- linux-2.6.18.1/include/linux/interrupt.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/interrupt.h 2006-09-04 16:31:18.000000000 +0200
+@@ -166,6 +166,12 @@
+
+ #endif /* CONFIG_GENERIC_HARDIRQS */
+
++#ifdef CONFIG_HAVE_IRQ_IGNORE_UNHANDLED
++int irq_ignore_unhandled(unsigned int irq);
++#else
++#define irq_ignore_unhandled(irq) 0
++#endif
++
+ #ifndef __ARCH_SET_SOFTIRQ_PENDING
+ #define set_softirq_pending(x) (local_softirq_pending() = (x))
+ #define or_softirq_pending(x) (local_softirq_pending() |= (x))
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/mm.h linux-2.6.18-xen/include/linux/mm.h
+--- linux-2.6.18.1/include/linux/mm.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/mm.h 2006-09-04 16:31:19.000000000 +0200
+@@ -164,6 +164,9 @@
+ #define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */
+ #define VM_MAPPED_COPY 0x01000000 /* T if mapped copy of data (nommu mmap) */
+ #define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */
++#ifdef CONFIG_XEN
++#define VM_FOREIGN 0x04000000 /* Has pages belonging to another VM */
++#endif
+
+ #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
+ #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
+@@ -1027,6 +1030,13 @@
+ #define FOLL_GET 0x04 /* do get_page on page */
+ #define FOLL_ANON 0x08 /* give ZERO_PAGE if no pgtable */
+
++#ifdef CONFIG_XEN
++typedef int (*pte_fn_t)(pte_t *pte, struct page *pmd_page, unsigned long addr,
++ void *data);
++extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
++ unsigned long size, pte_fn_t fn, void *data);
++#endif
++
+ #ifdef CONFIG_PROC_FS
+ void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
+ #else
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/oprofile.h linux-2.6.18-xen/include/linux/oprofile.h
+--- linux-2.6.18.1/include/linux/oprofile.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/oprofile.h 2006-09-04 16:31:19.000000000 +0200
+@@ -16,6 +16,10 @@
+ #include <linux/types.h>
+ #include <linux/spinlock.h>
+ #include <asm/atomic.h>
++
++#ifdef CONFIG_XEN
++#include <xen/interface/xenoprof.h>
++#endif
+
+ struct super_block;
+ struct dentry;
+@@ -27,6 +31,11 @@
+ /* create any necessary configuration files in the oprofile fs.
+ * Optional. */
+ int (*create_files)(struct super_block * sb, struct dentry * root);
++ /* setup active domains with Xen */
++ int (*set_active)(int *active_domains, unsigned int adomains);
++ /* setup passive domains with Xen */
++ int (*set_passive)(int *passive_domains, unsigned int pdomains);
++
+ /* Do any necessary interrupt setup. Optional. */
+ int (*setup)(void);
+ /* Do any necessary interrupt shutdown. Optional. */
+@@ -78,6 +87,8 @@
+ /* add a backtrace entry, to be called from the ->backtrace callback */
+ void oprofile_add_trace(unsigned long eip);
+
++/* add a domain switch entry */
++int oprofile_add_domain_switch(int32_t domain_id);
+
+ /**
+ * Create a file of the given name as a child of the given root, with
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/pfn.h linux-2.6.18-xen/include/linux/pfn.h
+--- linux-2.6.18.1/include/linux/pfn.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/pfn.h 2006-10-17 15:01:58.000000000 +0200
+@@ -4,6 +4,10 @@
+ #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
+ #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+ #define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
++#if defined(CONFIG_X86_XEN) && defined(CONFIG_X86_PAE)
++#define PFN_PHYS(x) ((unsigned long long)(x) << PAGE_SHIFT)
++#else
+ #define PFN_PHYS(x) ((x) << PAGE_SHIFT)
++#endif
+
+ #endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/linux/skbuff.h linux-2.6.18-xen/include/linux/skbuff.h
+--- linux-2.6.18.1/include/linux/skbuff.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/include/linux/skbuff.h 2006-09-04 16:31:19.000000000 +0200
+@@ -203,6 +203,8 @@
+ * @local_df: allow local fragmentation
+ * @cloned: Head may be cloned (check refcnt to be sure)
+ * @nohdr: Payload reference only, must not modify header
++ * @proto_data_valid: Protocol data validated since arriving at localhost
++ * @proto_csum_blank: Protocol csum must be added before leaving localhost
+ * @pkt_type: Packet class
+ * @fclone: skbuff clone status
+ * @ip_summed: Driver fed us an IP checksum
+@@ -282,7 +284,13 @@
+ nfctinfo:3;
+ __u8 pkt_type:3,
+ fclone:2,
++#ifndef CONFIG_XEN
+ ipvs_property:1;
++#else
++ ipvs_property:1,
++ proto_data_valid:1,
++ proto_csum_blank:1;
++#endif
+ __be16 protocol;
+
+ void (*destructor)(struct sk_buff *skb);
+@@ -345,7 +353,8 @@
+
+ extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
+ unsigned int size,
+- gfp_t priority);
++ gfp_t priority,
++ int fclone);
+ extern void kfree_skbmem(struct sk_buff *skb);
+ extern struct sk_buff *skb_clone(struct sk_buff *skb,
+ gfp_t priority);
+@@ -1086,6 +1095,7 @@
+ kfree_skb(skb);
+ }
+
++#ifndef CONFIG_HAVE_ARCH_DEV_ALLOC_SKB
+ /**
+ * __dev_alloc_skb - allocate an skbuff for receiving
+ * @length: length to allocate
+@@ -1106,6 +1116,9 @@
+ skb_reserve(skb, NET_SKB_PAD);
+ return skb;
+ }
++#else
++extern struct sk_buff *__dev_alloc_skb(unsigned int length, gfp_t gfp_mask);
++#endif
+
+ /**
+ * dev_alloc_skb - allocate an skbuff for receiving
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/balloon.h linux-2.6.18-xen/include/xen/balloon.h
+--- linux-2.6.18.1/include/xen/balloon.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/balloon.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,57 @@
++/******************************************************************************
++ * balloon.h
++ *
++ * Xen balloon driver - enables returning/claiming memory to/from Xen.
++ *
++ * Copyright (c) 2003, B Dragovic
++ * Copyright (c) 2003-2004, M Williamson, K Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __ASM_BALLOON_H__
++#define __ASM_BALLOON_H__
++
++/*
++ * Inform the balloon driver that it should allow some slop for device-driver
++ * memory activities.
++ */
++void balloon_update_driver_allowance(long delta);
++
++/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
++struct page **alloc_empty_pages_and_pagevec(int nr_pages);
++void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
++
++void balloon_release_driver_page(struct page *page);
++
++/*
++ * Prevent the balloon driver from changing the memory reservation during
++ * a driver critical region.
++ */
++extern spinlock_t balloon_lock;
++#define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags)
++#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
++
++#endif /* __ASM_BALLOON_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/cpu_hotplug.h linux-2.6.18-xen/include/xen/cpu_hotplug.h
+--- linux-2.6.18.1/include/xen/cpu_hotplug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/cpu_hotplug.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,43 @@
++#ifndef __XEN_CPU_HOTPLUG_H__
++#define __XEN_CPU_HOTPLUG_H__
++
++#include <linux/kernel.h>
++#include <linux/cpumask.h>
++
++#if defined(CONFIG_HOTPLUG_CPU)
++
++#if defined(CONFIG_X86)
++void cpu_initialize_context(unsigned int cpu);
++#else
++#define cpu_initialize_context(cpu) ((void)0)
++#endif
++
++int cpu_up_check(unsigned int cpu);
++void init_xenbus_allowed_cpumask(void);
++int smp_suspend(void);
++void smp_resume(void);
++
++void cpu_bringup(void);
++
++#else /* !defined(CONFIG_HOTPLUG_CPU) */
++
++#define cpu_up_check(cpu) (0)
++#define init_xenbus_allowed_cpumask() ((void)0)
++
++static inline int smp_suspend(void)
++{
++ if (num_online_cpus() > 1) {
++ printk(KERN_WARNING "Can't suspend SMP guests "
++ "without CONFIG_HOTPLUG_CPU\n");
++ return -EOPNOTSUPP;
++ }
++ return 0;
++}
++
++static inline void smp_resume(void)
++{
++}
++
++#endif /* !defined(CONFIG_HOTPLUG_CPU) */
++
++#endif /* __XEN_CPU_HOTPLUG_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/driver_util.h linux-2.6.18-xen/include/xen/driver_util.h
+--- linux-2.6.18.1/include/xen/driver_util.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/driver_util.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,15 @@
++
++#ifndef __ASM_XEN_DRIVER_UTIL_H__
++#define __ASM_XEN_DRIVER_UTIL_H__
++
++#include <linux/vmalloc.h>
++
++/* Allocate/destroy a 'vmalloc' VM area. */
++extern struct vm_struct *alloc_vm_area(unsigned long size);
++extern void free_vm_area(struct vm_struct *area);
++
++/* Lock an area so that PTEs are accessible in the current address space. */
++extern void lock_vm_area(struct vm_struct *area);
++extern void unlock_vm_area(struct vm_struct *area);
++
++#endif /* __ASM_XEN_DRIVER_UTIL_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/evtchn.h linux-2.6.18-xen/include/xen/evtchn.h
+--- linux-2.6.18.1/include/xen/evtchn.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/evtchn.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,113 @@
++/******************************************************************************
++ * evtchn.h
++ *
++ * Communication via Xen event channels.
++ * Also definitions for the device that demuxes notifications to userspace.
++ *
++ * Copyright (c) 2004-2005, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __ASM_EVTCHN_H__
++#define __ASM_EVTCHN_H__
++
++#include <linux/interrupt.h>
++#include <asm/hypervisor.h>
++#include <asm/ptrace.h>
++#include <asm/synch_bitops.h>
++#include <xen/interface/event_channel.h>
++#include <linux/smp.h>
++
++/*
++ * LOW-LEVEL DEFINITIONS
++ */
++
++/*
++ * Dynamically bind an event source to an IRQ-like callback handler.
++ * On some platforms this may not be implemented via the Linux IRQ subsystem.
++ * The IRQ argument passed to the callback handler is the same as returned
++ * from the bind call. It may not correspond to a Linux IRQ number.
++ * Returns IRQ or negative errno.
++ * UNBIND: Takes IRQ to unbind from; automatically closes the event channel.
++ */
++extern int bind_evtchn_to_irqhandler(
++ unsigned int evtchn,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id);
++extern int bind_virq_to_irqhandler(
++ unsigned int virq,
++ unsigned int cpu,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id);
++extern int bind_ipi_to_irqhandler(
++ unsigned int ipi,
++ unsigned int cpu,
++ irqreturn_t (*handler)(int, void *, struct pt_regs *),
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id);
++
++/*
++ * Common unbind function for all event sources. Takes IRQ to unbind from.
++ * Automatically closes the underlying event channel (even for bindings
++ * made with bind_evtchn_to_irqhandler()).
++ */
++extern void unbind_from_irqhandler(unsigned int irq, void *dev_id);
++
++extern void irq_resume(void);
++
++/* Entry point for notifications into Linux subsystems. */
++asmlinkage void evtchn_do_upcall(struct pt_regs *regs);
++
++/* Entry point for notifications into the userland character device. */
++extern void evtchn_device_upcall(int port);
++
++extern void mask_evtchn(int port);
++extern void unmask_evtchn(int port);
++
++static inline void clear_evtchn(int port)
++{
++ shared_info_t *s = HYPERVISOR_shared_info;
++ synch_clear_bit(port, &s->evtchn_pending[0]);
++}
++
++static inline void notify_remote_via_evtchn(int port)
++{
++ struct evtchn_send send = { .port = port };
++ (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
++}
++
++/*
++ * Unlike notify_remote_via_evtchn(), this is safe to use across
++ * save/restore. Notifications on a broken connection are silently dropped.
++ */
++extern void notify_remote_via_irq(int irq);
++
++#endif /* __ASM_EVTCHN_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/features.h linux-2.6.18-xen/include/xen/features.h
+--- linux-2.6.18.1/include/xen/features.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/features.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,20 @@
++/******************************************************************************
++ * features.h
++ *
++ * Query the features reported by Xen.
++ *
++ * Copyright (c) 2006, Ian Campbell
++ */
++
++#ifndef __ASM_XEN_FEATURES_H__
++#define __ASM_XEN_FEATURES_H__
++
++#include <xen/interface/version.h>
++
++extern void setup_xen_features(void);
++
++extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
++
++#define xen_feature(flag) (xen_features[flag])
++
++#endif /* __ASM_XEN_FEATURES_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/foreign_page.h linux-2.6.18-xen/include/xen/foreign_page.h
+--- linux-2.6.18.1/include/xen/foreign_page.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/foreign_page.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,30 @@
++/******************************************************************************
++ * foreign_page.h
++ *
++ * Provide a "foreign" page type, that is owned by a foreign allocator and
++ * not the normal buddy allocator in page_alloc.c
++ *
++ * Copyright (c) 2004, K A Fraser
++ */
++
++#ifndef __ASM_XEN_FOREIGN_PAGE_H__
++#define __ASM_XEN_FOREIGN_PAGE_H__
++
++#define PG_foreign PG_arch_1
++
++#define PageForeign(page) test_bit(PG_foreign, &(page)->flags)
++
++#define SetPageForeign(page, dtor) do { \
++ set_bit(PG_foreign, &(page)->flags); \
++ (page)->mapping = (void *)dtor; \
++} while (0)
++
++#define ClearPageForeign(page) do { \
++ clear_bit(PG_foreign, &(page)->flags); \
++ (page)->mapping = NULL; \
++} while (0)
++
++#define PageForeignDestructor(page) \
++ ( (void (*) (struct page *)) (page)->mapping )
++
++#endif /* __ASM_XEN_FOREIGN_PAGE_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/gnttab.h linux-2.6.18-xen/include/xen/gnttab.h
+--- linux-2.6.18.1/include/xen/gnttab.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/gnttab.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,150 @@
++/******************************************************************************
++ * gnttab.h
++ *
++ * Two sets of functionality:
++ * 1. Granting foreign access to our memory reservation.
++ * 2. Accessing others' memory reservations via grant references.
++ * (i.e., mechanisms for both sender and recipient of grant references)
++ *
++ * Copyright (c) 2004-2005, K A Fraser
++ * Copyright (c) 2005, Christopher Clark
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __ASM_GNTTAB_H__
++#define __ASM_GNTTAB_H__
++
++#include <asm/hypervisor.h>
++#include <xen/interface/grant_table.h>
++#include <xen/features.h>
++
++/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
++#ifdef __ia64__
++#define NR_GRANT_FRAMES 1
++#else
++#define NR_GRANT_FRAMES 4
++#endif
++
++struct gnttab_free_callback {
++ struct gnttab_free_callback *next;
++ void (*fn)(void *);
++ void *arg;
++ u16 count;
++};
++
++int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
++ int readonly);
++
++/*
++ * End access through the given grant reference, iff the grant entry is no
++ * longer in use. Return 1 if the grant entry was freed, 0 if it is still in
++ * use.
++ */
++int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
++
++/*
++ * Eventually end access through the given grant reference, and once that
++ * access has been ended, free the given page too. Access will be ended
++ * immediately iff the grant entry is not in use, otherwise it will happen
++ * some time later. page may be 0, in which case no freeing will occur.
++ */
++void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
++ unsigned long page);
++
++int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
++
++unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
++unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
++
++int gnttab_query_foreign_access(grant_ref_t ref);
++
++/*
++ * operations on reserved batches of grant references
++ */
++int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head);
++
++void gnttab_free_grant_reference(grant_ref_t ref);
++
++void gnttab_free_grant_references(grant_ref_t head);
++
++int gnttab_empty_grant_references(const grant_ref_t *pprivate_head);
++
++int gnttab_claim_grant_reference(grant_ref_t *pprivate_head);
++
++void gnttab_release_grant_reference(grant_ref_t *private_head,
++ grant_ref_t release);
++
++void gnttab_request_free_callback(struct gnttab_free_callback *callback,
++ void (*fn)(void *), void *arg, u16 count);
++void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
++
++void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
++ unsigned long frame, int readonly);
++
++void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
++ unsigned long pfn);
++
++#ifdef __ia64__
++#define gnttab_map_vaddr(map) __va(map.dev_bus_addr)
++#else
++#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
++#endif
++
++int gnttab_suspend(void);
++int gnttab_resume(void);
++
++static inline void
++gnttab_set_map_op(struct gnttab_map_grant_ref *map, unsigned long addr,
++ uint32_t flags, grant_ref_t ref, domid_t domid)
++{
++ if (flags & GNTMAP_contains_pte)
++ map->host_addr = addr;
++ else if (xen_feature(XENFEAT_auto_translated_physmap))
++ map->host_addr = __pa(addr);
++ else
++ map->host_addr = addr;
++
++ map->flags = flags;
++ map->ref = ref;
++ map->dom = domid;
++}
++
++static inline void
++gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, unsigned long addr,
++ uint32_t flags, grant_handle_t handle)
++{
++ if (flags & GNTMAP_contains_pte)
++ unmap->host_addr = addr;
++ else if (xen_feature(XENFEAT_auto_translated_physmap))
++ unmap->host_addr = __pa(addr);
++ else
++ unmap->host_addr = addr;
++
++ unmap->handle = handle;
++ unmap->dev_bus_addr = 0;
++}
++
++#endif /* __ASM_GNTTAB_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/hvm.h linux-2.6.18-xen/include/xen/hvm.h
+--- linux-2.6.18.1/include/xen/hvm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/hvm.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,24 @@
++/* Simple wrappers around HVM functions */
++#ifndef XEN_HVM_H__
++#define XEN_HVM_H__
++
++#include <xen/interface/hvm/params.h>
++#include <asm/hypercall.h>
++
++static inline unsigned long hvm_get_parameter(int idx)
++{
++ struct xen_hvm_param xhv;
++ int r;
++
++ xhv.domid = DOMID_SELF;
++ xhv.index = idx;
++ r = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
++ if (r < 0) {
++ printk(KERN_ERR "cannot get hvm parameter %d: %d.\n",
++ idx, r);
++ return 0;
++ }
++ return xhv.value;
++}
++
++#endif /* XEN_HVM_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/hypervisor_sysfs.h linux-2.6.18-xen/include/xen/hypervisor_sysfs.h
+--- linux-2.6.18.1/include/xen/hypervisor_sysfs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/hypervisor_sysfs.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * copyright (c) 2006 IBM Corporation
++ * Authored by: Mike D. Day <ncmike at 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _HYP_SYSFS_H_
++#define _HYP_SYSFS_H_
++
++#include <linux/kobject.h>
++#include <linux/sysfs.h>
++
++#define HYPERVISOR_ATTR_RO(_name) \
++static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name)
++
++#define HYPERVISOR_ATTR_RW(_name) \
++static struct hyp_sysfs_attr _name##_attr = \
++ __ATTR(_name, 0644, _name##_show, _name##_store)
++
++extern struct subsystem hypervisor_subsys;
++
++struct hyp_sysfs_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct hyp_sysfs_attr *, char *);
++ ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);
++ void *hyp_attr_data;
++};
++
++#endif /* _HYP_SYSFS_H_ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/acm.h linux-2.6.18-xen/include/xen/interface/acm.h
+--- linux-2.6.18.1/include/xen/interface/acm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/acm.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,187 @@
++/*
++ * acm.h: Xen access control module interface defintions
++ *
++ * Reiner Sailer <sailer at watson.ibm.com>
++ * Copyright (c) 2005, International Business Machines Corporation.
++ */
++
++#ifndef _XEN_PUBLIC_ACM_H
++#define _XEN_PUBLIC_ACM_H
++
++#include "xen.h"
++
++/* if ACM_DEBUG defined, all hooks should
++ * print a short trace message (comment it out
++ * when not in testing mode )
++ */
++/* #define ACM_DEBUG */
++
++#ifdef ACM_DEBUG
++# define printkd(fmt, args...) printk(fmt,## args)
++#else
++# define printkd(fmt, args...)
++#endif
++
++/* default ssid reference value if not supplied */
++#define ACM_DEFAULT_SSID 0x0
++#define ACM_DEFAULT_LOCAL_SSID 0x0
++
++/* Internal ACM ERROR types */
++#define ACM_OK 0
++#define ACM_UNDEF -1
++#define ACM_INIT_SSID_ERROR -2
++#define ACM_INIT_SOID_ERROR -3
++#define ACM_ERROR -4
++
++/* External ACCESS DECISIONS */
++#define ACM_ACCESS_PERMITTED 0
++#define ACM_ACCESS_DENIED -111
++#define ACM_NULL_POINTER_ERROR -200
++
++/* primary policy in lower 4 bits */
++#define ACM_NULL_POLICY 0
++#define ACM_CHINESE_WALL_POLICY 1
++#define ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY 2
++#define ACM_POLICY_UNDEFINED 15
++
++/* combinations have secondary policy component in higher 4bit */
++#define ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY \
++ ((ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY << 4) | ACM_CHINESE_WALL_POLICY)
++
++/* policy: */
++#define ACM_POLICY_NAME(X) \
++ ((X) == (ACM_NULL_POLICY)) ? "NULL" : \
++ ((X) == (ACM_CHINESE_WALL_POLICY)) ? "CHINESE WALL" : \
++ ((X) == (ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY)) ? "SIMPLE TYPE ENFORCEMENT" : \
++ ((X) == (ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY)) ? "CHINESE WALL AND SIMPLE TYPE ENFORCEMENT" : \
++ "UNDEFINED"
++
++/* the following policy versions must be increased
++ * whenever the interpretation of the related
++ * policy's data structure changes
++ */
++#define ACM_POLICY_VERSION 2
++#define ACM_CHWALL_VERSION 1
++#define ACM_STE_VERSION 1
++
++/* defines a ssid reference used by xen */
++typedef uint32_t ssidref_t;
++
++/* hooks that are known to domains */
++#define ACMHOOK_none 0
++#define ACMHOOK_sharing 1
++
++/* -------security policy relevant type definitions-------- */
++
++/* type identifier; compares to "equal" or "not equal" */
++typedef uint16_t domaintype_t;
++
++/* CHINESE WALL POLICY DATA STRUCTURES
++ *
++ * current accumulated conflict type set:
++ * When a domain is started and has a type that is in
++ * a conflict set, the conflicting types are incremented in
++ * the aggregate set. When a domain is destroyed, the
++ * conflicting types to its type are decremented.
++ * If a domain has multiple types, this procedure works over
++ * all those types.
++ *
++ * conflict_aggregate_set[i] holds the number of
++ * running domains that have a conflict with type i.
++ *
++ * running_types[i] holds the number of running domains
++ * that include type i in their ssidref-referenced type set
++ *
++ * conflict_sets[i][j] is "0" if type j has no conflict
++ * with type i and is "1" otherwise.
++ */
++/* high-16 = version, low-16 = check magic */
++#define ACM_MAGIC 0x0001debc
++
++/* each offset in bytes from start of the struct they
++ * are part of */
++
++/* each buffer consists of all policy information for
++ * the respective policy given in the policy code
++ *
++ * acm_policy_buffer, acm_chwall_policy_buffer,
++ * and acm_ste_policy_buffer need to stay 32-bit aligned
++ * because we create binary policies also with external
++ * tools that assume packed representations (e.g. the java tool)
++ */
++struct acm_policy_buffer {
++ uint32_t policy_version; /* ACM_POLICY_VERSION */
++ uint32_t magic;
++ uint32_t len;
++ uint32_t policy_reference_offset;
++ uint32_t primary_policy_code;
++ uint32_t primary_buffer_offset;
++ uint32_t secondary_policy_code;
++ uint32_t secondary_buffer_offset;
++};
++
++struct acm_policy_reference_buffer {
++ uint32_t len;
++};
++
++struct acm_chwall_policy_buffer {
++ uint32_t policy_version; /* ACM_CHWALL_VERSION */
++ uint32_t policy_code;
++ uint32_t chwall_max_types;
++ uint32_t chwall_max_ssidrefs;
++ uint32_t chwall_max_conflictsets;
++ uint32_t chwall_ssid_offset;
++ uint32_t chwall_conflict_sets_offset;
++ uint32_t chwall_running_types_offset;
++ uint32_t chwall_conflict_aggregate_offset;
++};
++
++struct acm_ste_policy_buffer {
++ uint32_t policy_version; /* ACM_STE_VERSION */
++ uint32_t policy_code;
++ uint32_t ste_max_types;
++ uint32_t ste_max_ssidrefs;
++ uint32_t ste_ssid_offset;
++};
++
++struct acm_stats_buffer {
++ uint32_t magic;
++ uint32_t len;
++ uint32_t primary_policy_code;
++ uint32_t primary_stats_offset;
++ uint32_t secondary_policy_code;
++ uint32_t secondary_stats_offset;
++};
++
++struct acm_ste_stats_buffer {
++ uint32_t ec_eval_count;
++ uint32_t gt_eval_count;
++ uint32_t ec_denied_count;
++ uint32_t gt_denied_count;
++ uint32_t ec_cachehit_count;
++ uint32_t gt_cachehit_count;
++};
++
++struct acm_ssid_buffer {
++ uint32_t len;
++ ssidref_t ssidref;
++ uint32_t policy_reference_offset;
++ uint32_t primary_policy_code;
++ uint32_t primary_max_types;
++ uint32_t primary_types_offset;
++ uint32_t secondary_policy_code;
++ uint32_t secondary_max_types;
++ uint32_t secondary_types_offset;
++};
++
++#endif
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/acm_ops.h linux-2.6.18-xen/include/xen/interface/acm_ops.h
+--- linux-2.6.18.1/include/xen/interface/acm_ops.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/acm_ops.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,102 @@
++/*
++ * acm_ops.h: Xen access control module hypervisor commands
++ *
++ * Reiner Sailer <sailer at watson.ibm.com>
++ * Copyright (c) 2005,2006 International Business Machines Corporation.
++ */
++
++#ifndef __XEN_PUBLIC_ACM_OPS_H__
++#define __XEN_PUBLIC_ACM_OPS_H__
++
++#include "xen.h"
++#include "acm.h"
++
++/*
++ * Make sure you increment the interface version whenever you modify this file!
++ * This makes sure that old versions of acm tools will stop working in a
++ * well-defined way (rather than crashing the machine, for instance).
++ */
++#define ACM_INTERFACE_VERSION 0xAAAA0008
++
++/************************************************************************/
++
++/*
++ * Prototype for this hypercall is:
++ * int acm_op(int cmd, void *args)
++ * @cmd == ACMOP_??? (access control module operation).
++ * @args == Operation-specific extra arguments (NULL if none).
++ */
++
++
++#define ACMOP_setpolicy 1
++struct acm_setpolicy {
++ /* IN */
++ uint32_t interface_version;
++ XEN_GUEST_HANDLE(void) pushcache;
++ uint32_t pushcache_size;
++};
++
++
++#define ACMOP_getpolicy 2
++struct acm_getpolicy {
++ /* IN */
++ uint32_t interface_version;
++ XEN_GUEST_HANDLE(void) pullcache;
++ uint32_t pullcache_size;
++};
++
++
++#define ACMOP_dumpstats 3
++struct acm_dumpstats {
++ /* IN */
++ uint32_t interface_version;
++ XEN_GUEST_HANDLE(void) pullcache;
++ uint32_t pullcache_size;
++};
++
++
++#define ACMOP_getssid 4
++#define ACM_GETBY_ssidref 1
++#define ACM_GETBY_domainid 2
++struct acm_getssid {
++ /* IN */
++ uint32_t interface_version;
++ uint32_t get_ssid_by; /* ACM_GETBY_* */
++ union {
++ domaintype_t domainid;
++ ssidref_t ssidref;
++ } id;
++ XEN_GUEST_HANDLE(void) ssidbuf;
++ uint32_t ssidbuf_size;
++};
++
++#define ACMOP_getdecision 5
++struct acm_getdecision {
++ /* IN */
++ uint32_t interface_version;
++ uint32_t get_decision_by1; /* ACM_GETBY_* */
++ uint32_t get_decision_by2; /* ACM_GETBY_* */
++ union {
++ domaintype_t domainid;
++ ssidref_t ssidref;
++ } id1;
++ union {
++ domaintype_t domainid;
++ ssidref_t ssidref;
++ } id2;
++ uint32_t hook;
++ /* OUT */
++ uint32_t acm_decision;
++};
++
++#endif /* __XEN_PUBLIC_ACM_OPS_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/arch-ia64.h linux-2.6.18-xen/include/xen/interface/arch-ia64.h
+--- linux-2.6.18.1/include/xen/interface/arch-ia64.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/arch-ia64.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,444 @@
++/******************************************************************************
++ * arch-ia64/hypervisor-if.h
++ *
++ * Guest OS interface to IA64 Xen.
++ */
++
++#ifndef __HYPERVISOR_IF_IA64_H__
++#define __HYPERVISOR_IF_IA64_H__
++
++/* Structural guest handles introduced in 0x00030201. */
++#if __XEN_INTERFACE_VERSION__ >= 0x00030201
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef struct { type *p; } __guest_handle_ ## name
++#else
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef type * __guest_handle_ ## name
++#endif
++
++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name
++#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0)
++#ifdef __XEN_TOOLS__
++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
++#endif
++
++#ifndef __ASSEMBLY__
++/* Guest handles for primitive C types. */
++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int);
++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
++DEFINE_XEN_GUEST_HANDLE(char);
++DEFINE_XEN_GUEST_HANDLE(int);
++DEFINE_XEN_GUEST_HANDLE(long);
++DEFINE_XEN_GUEST_HANDLE(void);
++
++typedef unsigned long xen_pfn_t;
++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
++#endif
++
++/* Arch specific VIRQs definition */
++#define VIRQ_ITC VIRQ_ARCH_0 /* V. Virtual itc timer */
++
++/* Maximum number of virtual CPUs in multi-processor guests. */
++/* WARNING: before changing this, check that shared_info fits on a page */
++#define MAX_VIRT_CPUS 64
++
++#ifndef __ASSEMBLY__
++
++typedef unsigned long xen_ulong_t;
++
++#define INVALID_MFN (~0UL)
++
++#define MEM_G (1UL << 30)
++#define MEM_M (1UL << 20)
++
++#define MMIO_START (3 * MEM_G)
++#define MMIO_SIZE (512 * MEM_M)
++
++#define VGA_IO_START 0xA0000UL
++#define VGA_IO_SIZE 0x20000
++
++#define LEGACY_IO_START (MMIO_START + MMIO_SIZE)
++#define LEGACY_IO_SIZE (64*MEM_M)
++
++#define IO_PAGE_START (LEGACY_IO_START + LEGACY_IO_SIZE)
++#define IO_PAGE_SIZE PAGE_SIZE
++
++#define STORE_PAGE_START (IO_PAGE_START + IO_PAGE_SIZE)
++#define STORE_PAGE_SIZE PAGE_SIZE
++
++#define IO_SAPIC_START 0xfec00000UL
++#define IO_SAPIC_SIZE 0x100000
++
++#define PIB_START 0xfee00000UL
++#define PIB_SIZE 0x200000
++
++#define GFW_START (4*MEM_G -16*MEM_M)
++#define GFW_SIZE (16*MEM_M)
++
++struct pt_fpreg {
++ union {
++ unsigned long bits[2];
++ long double __dummy; /* force 16-byte alignment */
++ } u;
++};
++
++struct cpu_user_regs {
++ /* The following registers are saved by SAVE_MIN: */
++ unsigned long b6; /* scratch */
++ unsigned long b7; /* scratch */
++
++ unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */
++ unsigned long ar_ssd; /* reserved for future use (scratch) */
++
++ unsigned long r8; /* scratch (return value register 0) */
++ unsigned long r9; /* scratch (return value register 1) */
++ unsigned long r10; /* scratch (return value register 2) */
++ unsigned long r11; /* scratch (return value register 3) */
++
++ unsigned long cr_ipsr; /* interrupted task's psr */
++ unsigned long cr_iip; /* interrupted task's instruction pointer */
++ unsigned long cr_ifs; /* interrupted task's function state */
++
++ unsigned long ar_unat; /* interrupted task's NaT register (preserved) */
++ unsigned long ar_pfs; /* prev function state */
++ unsigned long ar_rsc; /* RSE configuration */
++ /* The following two are valid only if cr_ipsr.cpl > 0: */
++ unsigned long ar_rnat; /* RSE NaT */
++ unsigned long ar_bspstore; /* RSE bspstore */
++
++ unsigned long pr; /* 64 predicate registers (1 bit each) */
++ unsigned long b0; /* return pointer (bp) */
++ unsigned long loadrs; /* size of dirty partition << 16 */
++
++ unsigned long r1; /* the gp pointer */
++ unsigned long r12; /* interrupted task's memory stack pointer */
++ unsigned long r13; /* thread pointer */
++
++ unsigned long ar_fpsr; /* floating point status (preserved) */
++ unsigned long r15; /* scratch */
++
++ /* The remaining registers are NOT saved for system calls. */
++
++ unsigned long r14; /* scratch */
++ unsigned long r2; /* scratch */
++ unsigned long r3; /* scratch */
++ unsigned long r16; /* scratch */
++ unsigned long r17; /* scratch */
++ unsigned long r18; /* scratch */
++ unsigned long r19; /* scratch */
++ unsigned long r20; /* scratch */
++ unsigned long r21; /* scratch */
++ unsigned long r22; /* scratch */
++ unsigned long r23; /* scratch */
++ unsigned long r24; /* scratch */
++ unsigned long r25; /* scratch */
++ unsigned long r26; /* scratch */
++ unsigned long r27; /* scratch */
++ unsigned long r28; /* scratch */
++ unsigned long r29; /* scratch */
++ unsigned long r30; /* scratch */
++ unsigned long r31; /* scratch */
++ unsigned long ar_ccv; /* compare/exchange value (scratch) */
++
++ /*
++ * Floating point registers that the kernel considers scratch:
++ */
++ struct pt_fpreg f6; /* scratch */
++ struct pt_fpreg f7; /* scratch */
++ struct pt_fpreg f8; /* scratch */
++ struct pt_fpreg f9; /* scratch */
++ struct pt_fpreg f10; /* scratch */
++ struct pt_fpreg f11; /* scratch */
++ unsigned long r4; /* preserved */
++ unsigned long r5; /* preserved */
++ unsigned long r6; /* preserved */
++ unsigned long r7; /* preserved */
++ unsigned long eml_unat; /* used for emulating instruction */
++ unsigned long pad0; /* alignment pad */
++
++};
++typedef struct cpu_user_regs cpu_user_regs_t;
++
++union vac {
++ unsigned long value;
++ struct {
++ int a_int:1;
++ int a_from_int_cr:1;
++ int a_to_int_cr:1;
++ int a_from_psr:1;
++ int a_from_cpuid:1;
++ int a_cover:1;
++ int a_bsw:1;
++ long reserved:57;
++ };
++};
++typedef union vac vac_t;
++
++union vdc {
++ unsigned long value;
++ struct {
++ int d_vmsw:1;
++ int d_extint:1;
++ int d_ibr_dbr:1;
++ int d_pmc:1;
++ int d_to_pmd:1;
++ int d_itm:1;
++ long reserved:58;
++ };
++};
++typedef union vdc vdc_t;
++
++struct mapped_regs {
++ union vac vac;
++ union vdc vdc;
++ unsigned long virt_env_vaddr;
++ unsigned long reserved1[29];
++ unsigned long vhpi;
++ unsigned long reserved2[95];
++ union {
++ unsigned long vgr[16];
++ unsigned long bank1_regs[16]; // bank1 regs (r16-r31) when bank0 active
++ };
++ union {
++ unsigned long vbgr[16];
++ unsigned long bank0_regs[16]; // bank0 regs (r16-r31) when bank1 active
++ };
++ unsigned long vnat;
++ unsigned long vbnat;
++ unsigned long vcpuid[5];
++ unsigned long reserved3[11];
++ unsigned long vpsr;
++ unsigned long vpr;
++ unsigned long reserved4[76];
++ union {
++ unsigned long vcr[128];
++ struct {
++ unsigned long dcr; // CR0
++ unsigned long itm;
++ unsigned long iva;
++ unsigned long rsv1[5];
++ unsigned long pta; // CR8
++ unsigned long rsv2[7];
++ unsigned long ipsr; // CR16
++ unsigned long isr;
++ unsigned long rsv3;
++ unsigned long iip;
++ unsigned long ifa;
++ unsigned long itir;
++ unsigned long iipa;
++ unsigned long ifs;
++ unsigned long iim; // CR24
++ unsigned long iha;
++ unsigned long rsv4[38];
++ unsigned long lid; // CR64
++ unsigned long ivr;
++ unsigned long tpr;
++ unsigned long eoi;
++ unsigned long irr[4];
++ unsigned long itv; // CR72
++ unsigned long pmv;
++ unsigned long cmcv;
++ unsigned long rsv5[5];
++ unsigned long lrr0; // CR80
++ unsigned long lrr1;
++ unsigned long rsv6[46];
++ };
++ };
++ union {
++ unsigned long reserved5[128];
++ struct {
++ unsigned long precover_ifs;
++ unsigned long unat; // not sure if this is needed until NaT arch is done
++ int interrupt_collection_enabled; // virtual psr.ic
++ /* virtual interrupt deliverable flag is evtchn_upcall_mask in
++ * shared info area now. interrupt_mask_addr is the address
++ * of evtchn_upcall_mask for current vcpu
++ */
++ unsigned char *interrupt_mask_addr;
++ int pending_interruption;
++ int incomplete_regframe; // see SDM vol2 6.8
++ unsigned char vpsr_pp;
++ unsigned char reserved5_2[7];
++ unsigned long reserved5_1[3];
++ int metaphysical_mode; // 1 = use metaphys mapping, 0 = use virtual
++ int banknum; // 0 or 1, which virtual register bank is active
++ unsigned long rrs[8]; // region registers
++ unsigned long krs[8]; // kernel registers
++ unsigned long pkrs[8]; // protection key registers
++ unsigned long tmp[8]; // temp registers (e.g. for hyperprivops)
++ };
++ };
++};
++typedef struct mapped_regs mapped_regs_t;
++
++struct vpd {
++ struct mapped_regs vpd_low;
++ unsigned long reserved6[3456];
++ unsigned long vmm_avail[128];
++ unsigned long reserved7[4096];
++};
++typedef struct vpd vpd_t;
++
++struct arch_vcpu_info {
++};
++typedef struct arch_vcpu_info arch_vcpu_info_t;
++
++struct arch_shared_info {
++ /* PFN of the start_info page. */
++ unsigned long start_info_pfn;
++
++ /* Interrupt vector for event channel. */
++ int evtchn_vector;
++
++ uint64_t pad[32];
++};
++typedef struct arch_shared_info arch_shared_info_t;
++
++typedef unsigned long xen_callback_t;
++
++struct ia64_tr_entry {
++ unsigned long pte;
++ unsigned long itir;
++ unsigned long vadr;
++ unsigned long rid;
++};
++
++struct vcpu_extra_regs {
++ struct ia64_tr_entry itrs[8];
++ struct ia64_tr_entry dtrs[8];
++ unsigned long iva;
++ unsigned long dcr;
++ unsigned long event_callback_ip;
++};
++
++struct vcpu_guest_context {
++#define VGCF_EXTRA_REGS (1<<1) /* Get/Set extra regs. */
++ unsigned long flags; /* VGCF_* flags */
++
++ struct cpu_user_regs user_regs;
++ struct vcpu_extra_regs extra_regs;
++ unsigned long privregs_pfn;
++};
++typedef struct vcpu_guest_context vcpu_guest_context_t;
++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
++
++/* dom0 vp op */
++#define __HYPERVISOR_ia64_dom0vp_op __HYPERVISOR_arch_0
++/* Map io space in machine address to dom0 physical address space.
++ Currently physical assigned address equals to machine address. */
++#define IA64_DOM0VP_ioremap 0
++
++/* Convert a pseudo physical page frame number to the corresponding
++ machine page frame number. If no page is assigned, INVALID_MFN or
++ GPFN_INV_MASK is returned depending on domain's non-vti/vti mode. */
++#define IA64_DOM0VP_phystomach 1
++
++/* Convert a machine page frame number to the corresponding pseudo physical
++ page frame number of the caller domain. */
++#define IA64_DOM0VP_machtophys 3
++
++/* Reserved for future use. */
++#define IA64_DOM0VP_iounmap 4
++
++/* Unmap and free pages contained in the specified pseudo physical region. */
++#define IA64_DOM0VP_zap_physmap 5
++
++/* Assign machine page frame to dom0's pseudo physical address space. */
++#define IA64_DOM0VP_add_physmap 6
++
++/* expose the p2m table into domain */
++#define IA64_DOM0VP_expose_p2m 7
++
++// flags for page assignement to pseudo physical address space
++#define _ASSIGN_readonly 0
++#define ASSIGN_readonly (1UL << _ASSIGN_readonly)
++#define ASSIGN_writable (0UL << _ASSIGN_readonly) // dummy flag
++/* Internal only: memory attribute must be WC/UC/UCE. */
++#define _ASSIGN_nocache 1
++#define ASSIGN_nocache (1UL << _ASSIGN_nocache)
++
++/* This structure has the same layout of struct ia64_boot_param, defined in
++ <asm/system.h>. It is redefined here to ease use. */
++struct xen_ia64_boot_param {
++ unsigned long command_line; /* physical address of cmd line args */
++ unsigned long efi_systab; /* physical address of EFI system table */
++ unsigned long efi_memmap; /* physical address of EFI memory map */
++ unsigned long efi_memmap_size; /* size of EFI memory map */
++ unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */
++ unsigned int efi_memdesc_version; /* memory descriptor version */
++ struct {
++ unsigned short num_cols; /* number of columns on console. */
++ unsigned short num_rows; /* number of rows on console. */
++ unsigned short orig_x; /* cursor's x position */
++ unsigned short orig_y; /* cursor's y position */
++ } console_info;
++ unsigned long fpswa; /* physical address of the fpswa interface */
++ unsigned long initrd_start;
++ unsigned long initrd_size;
++ unsigned long domain_start; /* va where the boot time domain begins */
++ unsigned long domain_size; /* how big is the boot domain */
++};
++
++#endif /* !__ASSEMBLY__ */
++
++/* Size of the shared_info area (this is not related to page size). */
++#define XSI_SHIFT 14
++#define XSI_SIZE (1 << XSI_SHIFT)
++/* Log size of mapped_regs area (64 KB - only 4KB is used). */
++#define XMAPPEDREGS_SHIFT 12
++#define XMAPPEDREGS_SIZE (1 << XMAPPEDREGS_SHIFT)
++/* Offset of XASI (Xen arch shared info) wrt XSI_BASE. */
++#define XMAPPEDREGS_OFS XSI_SIZE
++
++/* Hyperprivops. */
++#define HYPERPRIVOP_RFI 0x1
++#define HYPERPRIVOP_RSM_DT 0x2
++#define HYPERPRIVOP_SSM_DT 0x3
++#define HYPERPRIVOP_COVER 0x4
++#define HYPERPRIVOP_ITC_D 0x5
++#define HYPERPRIVOP_ITC_I 0x6
++#define HYPERPRIVOP_SSM_I 0x7
++#define HYPERPRIVOP_GET_IVR 0x8
++#define HYPERPRIVOP_GET_TPR 0x9
++#define HYPERPRIVOP_SET_TPR 0xa
++#define HYPERPRIVOP_EOI 0xb
++#define HYPERPRIVOP_SET_ITM 0xc
++#define HYPERPRIVOP_THASH 0xd
++#define HYPERPRIVOP_PTC_GA 0xe
++#define HYPERPRIVOP_ITR_D 0xf
++#define HYPERPRIVOP_GET_RR 0x10
++#define HYPERPRIVOP_SET_RR 0x11
++#define HYPERPRIVOP_SET_KR 0x12
++#define HYPERPRIVOP_FC 0x13
++#define HYPERPRIVOP_GET_CPUID 0x14
++#define HYPERPRIVOP_GET_PMD 0x15
++#define HYPERPRIVOP_GET_EFLAG 0x16
++#define HYPERPRIVOP_SET_EFLAG 0x17
++#define HYPERPRIVOP_RSM_BE 0x18
++#define HYPERPRIVOP_GET_PSR 0x19
++#define HYPERPRIVOP_MAX 0x19
++
++/* Fast and light hypercalls. */
++#define __HYPERVISOR_ia64_fast_eoi 0x0200
++
++/* Xencomm macros. */
++#define XENCOMM_INLINE_MASK 0xf800000000000000UL
++#define XENCOMM_INLINE_FLAG 0x8000000000000000UL
++
++#define XENCOMM_IS_INLINE(addr) \
++ (((unsigned long)(addr) & XENCOMM_INLINE_MASK) == XENCOMM_INLINE_FLAG)
++#define XENCOMM_INLINE_ADDR(addr) \
++ ((unsigned long)(addr) & ~XENCOMM_INLINE_MASK)
++#endif /* __HYPERVISOR_IF_IA64_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/arch-powerpc.h linux-2.6.18-xen/include/xen/interface/arch-powerpc.h
+--- linux-2.6.18.1/include/xen/interface/arch-powerpc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/arch-powerpc.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,115 @@
++/*
++ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++ *
++ * Copyright (C) IBM Corp. 2005, 2006
++ *
++ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
++ */
++
++#ifndef __XEN_PUBLIC_ARCH_PPC_64_H__
++#define __XEN_PUBLIC_ARCH_PPC_64_H__
++
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef struct { \
++ int __pad[(sizeof (long long) - sizeof (void *)) / sizeof (int)]; \
++ type *p; \
++ } __attribute__((__aligned__(8))) __guest_handle_ ## name
++
++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name
++#define set_xen_guest_handle(hnd, val) \
++ do { \
++ if (sizeof ((hnd).__pad)) \
++ (hnd).__pad[0] = 0; \
++ (hnd).p = val; \
++ } while (0)
++
++#ifdef __XEN_TOOLS__
++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
++#endif
++
++#ifndef __ASSEMBLY__
++/* Guest handles for primitive C types. */
++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int);
++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
++DEFINE_XEN_GUEST_HANDLE(char);
++DEFINE_XEN_GUEST_HANDLE(int);
++DEFINE_XEN_GUEST_HANDLE(long);
++DEFINE_XEN_GUEST_HANDLE(void);
++
++typedef unsigned long long xen_pfn_t;
++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
++#endif
++
++/*
++ * Pointers and other address fields inside interface structures are padded to
++ * 64 bits. This means that field alignments aren't different between 32- and
++ * 64-bit architectures.
++ */
++/* NB. Multi-level macro ensures __LINE__ is expanded before concatenation. */
++#define __MEMORY_PADDING(_X)
++#define _MEMORY_PADDING(_X) __MEMORY_PADDING(_X)
++#define MEMORY_PADDING _MEMORY_PADDING(__LINE__)
++
++/* And the trap vector is... */
++#define TRAP_INSTR "li 0,-1; sc" /* XXX just "sc"? */
++
++#ifndef __ASSEMBLY__
++
++typedef uint64_t xen_ulong_t;
++
++/* User-accessible registers: need to be saved/restored for every nested Xen
++ * invocation. */
++struct cpu_user_regs
++{
++ uint64_t gprs[32];
++ uint64_t lr;
++ uint64_t ctr;
++ uint64_t srr0;
++ uint64_t srr1;
++ uint64_t pc;
++ uint64_t msr;
++ uint64_t fpscr;
++ uint64_t xer;
++ uint64_t hid4;
++ uint32_t cr;
++ uint32_t entry_vector;
++};
++typedef struct cpu_user_regs cpu_user_regs_t;
++
++typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ /* XXX timebase */
++
++/* ONLY used to communicate with dom0! See also struct exec_domain. */
++struct vcpu_guest_context {
++ cpu_user_regs_t user_regs; /* User-level CPU registers */
++ uint64_t sdr1; /* Pagetable base */
++ /* XXX etc */
++};
++typedef struct vcpu_guest_context vcpu_guest_context_t;
++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
++
++struct arch_shared_info {
++ uint64_t pad[32];
++};
++
++struct arch_vcpu_info {
++};
++
++/* Support for multi-processor guests. */
++#define MAX_VIRT_CPUS 32
++#endif
++
++#endif
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/arch-x86_32.h linux-2.6.18-xen/include/xen/interface/arch-x86_32.h
+--- linux-2.6.18.1/include/xen/interface/arch-x86_32.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/arch-x86_32.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,255 @@
++/******************************************************************************
++ * arch-x86_32.h
++ *
++ * Guest OS interface to x86 32-bit Xen.
++ *
++ * Copyright (c) 2004, K A Fraser
++ */
++
++#ifndef __XEN_PUBLIC_ARCH_X86_32_H__
++#define __XEN_PUBLIC_ARCH_X86_32_H__
++
++/*
++ * Hypercall interface:
++ * Input: %ebx, %ecx, %edx, %esi, %edi (arguments 1-5)
++ * Output: %eax
++ * Access is via hypercall page (set up by guest loader or via a Xen MSR):
++ * call hypercall_page + hypercall-number * 32
++ * Clobbered: Argument registers (e.g., 2-arg hypercall clobbers %ebx,%ecx)
++ */
++
++#if __XEN_INTERFACE_VERSION__ < 0x00030203
++/*
++ * Legacy hypercall interface:
++ * As above, except the entry sequence to the hypervisor is:
++ * mov $hypercall-number*32,%eax ; int $0x82
++ */
++#define TRAP_INSTR "int $0x82"
++#endif
++
++/* Structural guest handles introduced in 0x00030201. */
++#if __XEN_INTERFACE_VERSION__ >= 0x00030201
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef struct { type *p; } __guest_handle_ ## name
++#else
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef type * __guest_handle_ ## name
++#endif
++
++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name
++#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0)
++#ifdef __XEN_TOOLS__
++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
++#endif
++
++#ifndef __ASSEMBLY__
++/* Guest handles for primitive C types. */
++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int);
++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
++DEFINE_XEN_GUEST_HANDLE(char);
++DEFINE_XEN_GUEST_HANDLE(int);
++DEFINE_XEN_GUEST_HANDLE(long);
++DEFINE_XEN_GUEST_HANDLE(void);
++
++typedef unsigned long xen_pfn_t;
++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
++#endif
++
++/*
++ * SEGMENT DESCRIPTOR TABLES
++ */
++/*
++ * A number of GDT entries are reserved by Xen. These are not situated at the
++ * start of the GDT because some stupid OSes export hard-coded selector values
++ * in their ABI. These hard-coded values are always near the start of the GDT,
++ * so Xen places itself out of the way, at the far end of the GDT.
++ */
++#define FIRST_RESERVED_GDT_PAGE 14
++#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
++#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
++
++/*
++ * These flat segments are in the Xen-private section of every GDT. Since these
++ * are also present in the initial GDT, many OSes will be able to avoid
++ * installing their own GDT.
++ */
++#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
++#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
++#define FLAT_RING1_SS 0xe021 /* GDT index 260 */
++#define FLAT_RING3_CS 0xe02b /* GDT index 261 */
++#define FLAT_RING3_DS 0xe033 /* GDT index 262 */
++#define FLAT_RING3_SS 0xe033 /* GDT index 262 */
++
++#define FLAT_KERNEL_CS FLAT_RING1_CS
++#define FLAT_KERNEL_DS FLAT_RING1_DS
++#define FLAT_KERNEL_SS FLAT_RING1_SS
++#define FLAT_USER_CS FLAT_RING3_CS
++#define FLAT_USER_DS FLAT_RING3_DS
++#define FLAT_USER_SS FLAT_RING3_SS
++
++/*
++ * Virtual addresses beyond this are not modifiable by guest OSes. The
++ * machine->physical mapping table starts at this address, read-only.
++ */
++#ifdef CONFIG_X86_PAE
++#define __HYPERVISOR_VIRT_START 0xF5800000
++#define __MACH2PHYS_VIRT_START 0xF5800000
++#define __MACH2PHYS_VIRT_END 0xF6800000
++#else
++#define __HYPERVISOR_VIRT_START 0xFC000000
++#define __MACH2PHYS_VIRT_START 0xFC000000
++#define __MACH2PHYS_VIRT_END 0xFC400000
++#endif
++
++#ifndef HYPERVISOR_VIRT_START
++#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
++#endif
++
++#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
++#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
++#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>2)
++#ifndef machine_to_phys_mapping
++#define machine_to_phys_mapping ((unsigned long *)MACH2PHYS_VIRT_START)
++#endif
++
++/* Maximum number of virtual CPUs in multi-processor guests. */
++#define MAX_VIRT_CPUS 32
++
++#ifndef __ASSEMBLY__
++
++typedef unsigned long xen_ulong_t;
++
++/*
++ * Send an array of these to HYPERVISOR_set_trap_table()
++ */
++#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
++#define TI_GET_IF(_ti) ((_ti)->flags & 4)
++#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
++#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2))
++struct trap_info {
++ uint8_t vector; /* exception vector */
++ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
++ uint16_t cs; /* code selector */
++ unsigned long address; /* code offset */
++};
++typedef struct trap_info trap_info_t;
++DEFINE_XEN_GUEST_HANDLE(trap_info_t);
++
++struct cpu_user_regs {
++ uint32_t ebx;
++ uint32_t ecx;
++ uint32_t edx;
++ uint32_t esi;
++ uint32_t edi;
++ uint32_t ebp;
++ uint32_t eax;
++ uint16_t error_code; /* private */
++ uint16_t entry_vector; /* private */
++ uint32_t eip;
++ uint16_t cs;
++ uint8_t saved_upcall_mask;
++ uint8_t _pad0;
++ uint32_t eflags; /* eflags.IF == !saved_upcall_mask */
++ uint32_t esp;
++ uint16_t ss, _pad1;
++ uint16_t es, _pad2;
++ uint16_t ds, _pad3;
++ uint16_t fs, _pad4;
++ uint16_t gs, _pad5;
++};
++typedef struct cpu_user_regs cpu_user_regs_t;
++DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t);
++
++typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
++
++/*
++ * The following is all CPU context. Note that the fpu_ctxt block is filled
++ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
++ */
++struct vcpu_guest_context {
++ /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
++ struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
++#define VGCF_I387_VALID (1<<0)
++#define VGCF_HVM_GUEST (1<<1)
++#define VGCF_IN_KERNEL (1<<2)
++#define _VGCF_i387_valid 0
++#define VGCF_i387_valid (1<<_VGCF_i387_valid)
++#define _VGCF_hvm_guest 1
++#define VGCF_hvm_guest (1<<_VGCF_hvm_guest)
++#define _VGCF_in_kernel 2
++#define VGCF_in_kernel (1<<_VGCF_in_kernel)
++#define _VGCF_failsafe_disables_events 3
++#define VGCF_failsafe_disables_events (1<<_VGCF_failsafe_disables_events)
++ unsigned long flags; /* VGCF_* flags */
++ struct cpu_user_regs user_regs; /* User-level CPU registers */
++ struct trap_info trap_ctxt[256]; /* Virtual IDT */
++ unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
++ unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
++ unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
++ unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */
++ unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
++ unsigned long event_callback_cs; /* CS:EIP of event callback */
++ unsigned long event_callback_eip;
++ unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */
++ unsigned long failsafe_callback_eip;
++ unsigned long vm_assist; /* VMASST_TYPE_* bitmap */
++};
++typedef struct vcpu_guest_context vcpu_guest_context_t;
++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
++
++/*
++ * Page-directory addresses above 4GB do not fit into architectural %cr3.
++ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
++ * must use the following accessor macros to pack/unpack valid MFNs.
++ */
++#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
++#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
++
++struct arch_shared_info {
++ unsigned long max_pfn; /* max pfn that appears in table */
++ /* Frame containing list of mfns containing list of mfns containing p2m. */
++ xen_pfn_t pfn_to_mfn_frame_list_list;
++ unsigned long nmi_reason;
++ uint64_t pad[32];
++};
++typedef struct arch_shared_info arch_shared_info_t;
++
++struct arch_vcpu_info {
++ unsigned long cr2;
++ unsigned long pad[5]; /* sizeof(vcpu_info_t) == 64 */
++};
++typedef struct arch_vcpu_info arch_vcpu_info_t;
++
++struct xen_callback {
++ unsigned long cs;
++ unsigned long eip;
++};
++typedef struct xen_callback xen_callback_t;
++
++#endif /* !__ASSEMBLY__ */
++
++/*
++ * Prefix forces emulation of some non-trapping instructions.
++ * Currently only CPUID.
++ */
++#ifdef __ASSEMBLY__
++#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
++#define XEN_CPUID XEN_EMULATE_PREFIX cpuid
++#else
++#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
++#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid"
++#endif
++
++#endif
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/arch-x86_64.h linux-2.6.18-xen/include/xen/interface/arch-x86_64.h
+--- linux-2.6.18.1/include/xen/interface/arch-x86_64.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/arch-x86_64.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,322 @@
++/******************************************************************************
++ * arch-x86_64.h
++ *
++ * Guest OS interface to x86 64-bit Xen.
++ *
++ * Copyright (c) 2004, K A Fraser
++ */
++
++#ifndef __XEN_PUBLIC_ARCH_X86_64_H__
++#define __XEN_PUBLIC_ARCH_X86_64_H__
++
++/*
++ * Hypercall interface:
++ * Input: %rdi, %rsi, %rdx, %r10, %r8 (arguments 1-5)
++ * Output: %rax
++ * Access is via hypercall page (set up by guest loader or via a Xen MSR):
++ * call hypercall_page + hypercall-number * 32
++ * Clobbered: argument registers (e.g., 2-arg hypercall clobbers %rdi,%rsi)
++ */
++
++#if __XEN_INTERFACE_VERSION__ < 0x00030203
++/*
++ * Legacy hypercall interface:
++ * As above, except the entry sequence to the hypervisor is:
++ * mov $hypercall-number*32,%eax ; syscall
++ * Clobbered: %rcx, %r11, argument registers (as above)
++ */
++#define TRAP_INSTR "syscall"
++#endif
++
++/* Structural guest handles introduced in 0x00030201. */
++#if __XEN_INTERFACE_VERSION__ >= 0x00030201
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef struct { type *p; } __guest_handle_ ## name
++#else
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++ typedef type * __guest_handle_ ## name
++#endif
++
++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name
++#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0)
++#ifdef __XEN_TOOLS__
++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
++#endif
++
++#ifndef __ASSEMBLY__
++/* Guest handles for primitive C types. */
++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int);
++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
++DEFINE_XEN_GUEST_HANDLE(char);
++DEFINE_XEN_GUEST_HANDLE(int);
++DEFINE_XEN_GUEST_HANDLE(long);
++DEFINE_XEN_GUEST_HANDLE(void);
++
++typedef unsigned long xen_pfn_t;
++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
++#endif
++
++/*
++ * SEGMENT DESCRIPTOR TABLES
++ */
++/*
++ * A number of GDT entries are reserved by Xen. These are not situated at the
++ * start of the GDT because some stupid OSes export hard-coded selector values
++ * in their ABI. These hard-coded values are always near the start of the GDT,
++ * so Xen places itself out of the way, at the far end of the GDT.
++ */
++#define FIRST_RESERVED_GDT_PAGE 14
++#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
++#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
++
++/*
++ * 64-bit segment selectors
++ * These flat segments are in the Xen-private section of every GDT. Since these
++ * are also present in the initial GDT, many OSes will be able to avoid
++ * installing their own GDT.
++ */
++
++#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */
++#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */
++#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */
++#define FLAT_RING3_DS64 0x0000 /* NULL selector */
++#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */
++#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */
++
++#define FLAT_KERNEL_DS64 FLAT_RING3_DS64
++#define FLAT_KERNEL_DS32 FLAT_RING3_DS32
++#define FLAT_KERNEL_DS FLAT_KERNEL_DS64
++#define FLAT_KERNEL_CS64 FLAT_RING3_CS64
++#define FLAT_KERNEL_CS32 FLAT_RING3_CS32
++#define FLAT_KERNEL_CS FLAT_KERNEL_CS64
++#define FLAT_KERNEL_SS64 FLAT_RING3_SS64
++#define FLAT_KERNEL_SS32 FLAT_RING3_SS32
++#define FLAT_KERNEL_SS FLAT_KERNEL_SS64
++
++#define FLAT_USER_DS64 FLAT_RING3_DS64
++#define FLAT_USER_DS32 FLAT_RING3_DS32
++#define FLAT_USER_DS FLAT_USER_DS64
++#define FLAT_USER_CS64 FLAT_RING3_CS64
++#define FLAT_USER_CS32 FLAT_RING3_CS32
++#define FLAT_USER_CS FLAT_USER_CS64
++#define FLAT_USER_SS64 FLAT_RING3_SS64
++#define FLAT_USER_SS32 FLAT_RING3_SS32
++#define FLAT_USER_SS FLAT_USER_SS64
++
++#define __HYPERVISOR_VIRT_START 0xFFFF800000000000
++#define __HYPERVISOR_VIRT_END 0xFFFF880000000000
++#define __MACH2PHYS_VIRT_START 0xFFFF800000000000
++#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
++
++#ifndef HYPERVISOR_VIRT_START
++#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
++#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END)
++#endif
++
++#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
++#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
++#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
++#ifndef machine_to_phys_mapping
++#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
++#endif
++
++/* Maximum number of virtual CPUs in multi-processor guests. */
++#define MAX_VIRT_CPUS 32
++
++#ifndef __ASSEMBLY__
++
++typedef unsigned long xen_ulong_t;
++
++/*
++ * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
++ * @which == SEGBASE_* ; @base == 64-bit base address
++ * Returns 0 on success.
++ */
++#define SEGBASE_FS 0
++#define SEGBASE_GS_USER 1
++#define SEGBASE_GS_KERNEL 2
++#define SEGBASE_GS_USER_SEL 3 /* Set user %gs specified in base[15:0] */
++
++/*
++ * int HYPERVISOR_iret(void)
++ * All arguments are on the kernel stack, in the following format.
++ * Never returns if successful. Current kernel context is lost.
++ * The saved CS is mapped as follows:
++ * RING0 -> RING3 kernel mode.
++ * RING1 -> RING3 kernel mode.
++ * RING2 -> RING3 kernel mode.
++ * RING3 -> RING3 user mode.
++ * However RING0 indicates that the guest kernel should return to iteself
++ * directly with
++ * orb $3,1*8(%rsp)
++ * iretq
++ * If flags contains VGCF_IN_SYSCALL:
++ * Restore RAX, RIP, RFLAGS, RSP.
++ * Discard R11, RCX, CS, SS.
++ * Otherwise:
++ * Restore RAX, R11, RCX, CS:RIP, RFLAGS, SS:RSP.
++ * All other registers are saved on hypercall entry and restored to user.
++ */
++/* Guest exited in SYSCALL context? Return to guest with SYSRET? */
++#define VGCF_IN_SYSCALL (1<<8)
++struct iret_context {
++ /* Top of stack (%rsp at point of hypercall). */
++ uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
++ /* Bottom of iret stack frame. */
++};
++
++/*
++ * Send an array of these to HYPERVISOR_set_trap_table().
++ * N.B. As in x86/32 mode, the privilege level specifies which modes may enter
++ * a trap via a software interrupt. Since rings 1 and 2 are unavailable, we
++ * allocate privilege levels as follows:
++ * Level == 0: Noone may enter
++ * Level == 1: Kernel may enter
++ * Level == 2: Kernel may enter
++ * Level == 3: Everyone may enter
++ */
++#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
++#define TI_GET_IF(_ti) ((_ti)->flags & 4)
++#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
++#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2))
++struct trap_info {
++ uint8_t vector; /* exception vector */
++ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
++ uint16_t cs; /* code selector */
++ unsigned long address; /* code offset */
++};
++typedef struct trap_info trap_info_t;
++DEFINE_XEN_GUEST_HANDLE(trap_info_t);
++
++#ifdef __GNUC__
++/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */
++#define __DECL_REG(name) union { uint64_t r ## name, e ## name; }
++#else
++/* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */
++#define __DECL_REG(name) uint64_t r ## name
++#endif
++
++struct cpu_user_regs {
++ uint64_t r15;
++ uint64_t r14;
++ uint64_t r13;
++ uint64_t r12;
++ __DECL_REG(bp);
++ __DECL_REG(bx);
++ uint64_t r11;
++ uint64_t r10;
++ uint64_t r9;
++ uint64_t r8;
++ __DECL_REG(ax);
++ __DECL_REG(cx);
++ __DECL_REG(dx);
++ __DECL_REG(si);
++ __DECL_REG(di);
++ uint32_t error_code; /* private */
++ uint32_t entry_vector; /* private */
++ __DECL_REG(ip);
++ uint16_t cs, _pad0[1];
++ uint8_t saved_upcall_mask;
++ uint8_t _pad1[3];
++ __DECL_REG(flags); /* rflags.IF == !saved_upcall_mask */
++ __DECL_REG(sp);
++ uint16_t ss, _pad2[3];
++ uint16_t es, _pad3[3];
++ uint16_t ds, _pad4[3];
++ uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */
++ uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */
++};
++typedef struct cpu_user_regs cpu_user_regs_t;
++DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t);
++
++#undef __DECL_REG
++
++typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
++
++/*
++ * The following is all CPU context. Note that the fpu_ctxt block is filled
++ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
++ */
++struct vcpu_guest_context {
++ /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
++ struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
++#define VGCF_I387_VALID (1<<0)
++#define VGCF_HVM_GUEST (1<<1)
++#define VGCF_IN_KERNEL (1<<2)
++#define _VGCF_i387_valid 0
++#define VGCF_i387_valid (1<<_VGCF_i387_valid)
++#define _VGCF_hvm_guest 1
++#define VGCF_hvm_guest (1<<_VGCF_hvm_guest)
++#define _VGCF_in_kernel 2
++#define VGCF_in_kernel (1<<_VGCF_in_kernel)
++#define _VGCF_failsafe_disables_events 3
++#define VGCF_failsafe_disables_events (1<<_VGCF_failsafe_disables_events)
++#define _VGCF_syscall_disables_events 4
++#define VGCF_syscall_disables_events (1<<_VGCF_syscall_disables_events)
++ unsigned long flags; /* VGCF_* flags */
++ struct cpu_user_regs user_regs; /* User-level CPU registers */
++ struct trap_info trap_ctxt[256]; /* Virtual IDT */
++ unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
++ unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
++ unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
++ unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */
++ unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
++ unsigned long event_callback_eip;
++ unsigned long failsafe_callback_eip;
++ unsigned long syscall_callback_eip;
++ unsigned long vm_assist; /* VMASST_TYPE_* bitmap */
++ /* Segment base addresses. */
++ uint64_t fs_base;
++ uint64_t gs_base_kernel;
++ uint64_t gs_base_user;
++};
++typedef struct vcpu_guest_context vcpu_guest_context_t;
++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
++
++#define xen_pfn_to_cr3(pfn) ((unsigned long)(pfn) << 12)
++#define xen_cr3_to_pfn(cr3) ((unsigned long)(cr3) >> 12)
++
++struct arch_shared_info {
++ unsigned long max_pfn; /* max pfn that appears in table */
++ /* Frame containing list of mfns containing list of mfns containing p2m. */
++ xen_pfn_t pfn_to_mfn_frame_list_list;
++ unsigned long nmi_reason;
++ uint64_t pad[32];
++};
++typedef struct arch_shared_info arch_shared_info_t;
++
++struct arch_vcpu_info {
++ unsigned long cr2;
++ unsigned long pad; /* sizeof(vcpu_info_t) == 64 */
++};
++typedef struct arch_vcpu_info arch_vcpu_info_t;
++
++typedef unsigned long xen_callback_t;
++
++#endif /* !__ASSEMBLY__ */
++
++/*
++ * Prefix forces emulation of some non-trapping instructions.
++ * Currently only CPUID.
++ */
++#ifdef __ASSEMBLY__
++#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
++#define XEN_CPUID XEN_EMULATE_PREFIX cpuid
++#else
++#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
++#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid"
++#endif
++
++#endif
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/callback.h linux-2.6.18-xen/include/xen/interface/callback.h
+--- linux-2.6.18.1/include/xen/interface/callback.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/callback.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,74 @@
++/******************************************************************************
++ * callback.h
++ *
++ * Register guest OS callbacks with Xen.
++ *
++ * Copyright (c) 2006, Ian Campbell
++ */
++
++#ifndef __XEN_PUBLIC_CALLBACK_H__
++#define __XEN_PUBLIC_CALLBACK_H__
++
++#include "xen.h"
++
++/*
++ * Prototype for this hypercall is:
++ * long callback_op(int cmd, void *extra_args)
++ * @cmd == CALLBACKOP_??? (callback operation).
++ * @extra_args == Operation-specific extra arguments (NULL if none).
++ */
++
++#define CALLBACKTYPE_event 0
++#define CALLBACKTYPE_failsafe 1
++#define CALLBACKTYPE_syscall 2 /* x86_64 only */
++/*
++ * sysenter is only available on x86_32 with the
++ * supervisor_mode_kernel option enabled.
++ */
++#define CALLBACKTYPE_sysenter 3
++#define CALLBACKTYPE_nmi 4
++
++/*
++ * Disable event deliver during callback? This flag is ignored for event and
++ * NMI callbacks: event delivery is unconditionally disabled.
++ */
++#define _CALLBACKF_mask_events 0
++#define CALLBACKF_mask_events (1U << _CALLBACKF_mask_events)
++
++/*
++ * Register a callback.
++ */
++#define CALLBACKOP_register 0
++struct callback_register {
++ uint16_t type;
++ uint16_t flags;
++ xen_callback_t address;
++};
++typedef struct callback_register callback_register_t;
++DEFINE_XEN_GUEST_HANDLE(callback_register_t);
++
++/*
++ * Unregister a callback.
++ *
++ * Not all callbacks can be unregistered. -EINVAL will be returned if
++ * you attempt to unregister such a callback.
++ */
++#define CALLBACKOP_unregister 1
++struct callback_unregister {
++ uint16_t type;
++ uint16_t _unused;
++};
++typedef struct callback_unregister callback_unregister_t;
++DEFINE_XEN_GUEST_HANDLE(callback_unregister_t);
++
++#endif /* __XEN_PUBLIC_CALLBACK_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/dom0_ops.h linux-2.6.18-xen/include/xen/interface/dom0_ops.h
+--- linux-2.6.18.1/include/xen/interface/dom0_ops.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/dom0_ops.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,102 @@
++/******************************************************************************
++ * dom0_ops.h
++ *
++ * Process command requests from domain-0 guest OS.
++ *
++ * Copyright (c) 2002-2003, B Dragovic
++ * Copyright (c) 2002-2006, K Fraser
++ */
++
++#ifndef __XEN_PUBLIC_DOM0_OPS_H__
++#define __XEN_PUBLIC_DOM0_OPS_H__
++
++#include "xen.h"
++#include "platform.h"
++
++#if __XEN_INTERFACE_VERSION__ >= 0x00030204
++#error "dom0_ops.h is a compatibility interface only"
++#endif
++
++#define DOM0_INTERFACE_VERSION XENPF_INTERFACE_VERSION
++
++#define DOM0_SETTIME XENPF_settime
++#define dom0_settime xenpf_settime
++#define dom0_settime_t xenpf_settime_t
++
++#define DOM0_ADD_MEMTYPE XENPF_add_memtype
++#define dom0_add_memtype xenpf_add_memtype
++#define dom0_add_memtype_t xenpf_add_memtype_t
++
++#define DOM0_DEL_MEMTYPE XENPF_del_memtype
++#define dom0_del_memtype xenpf_del_memtype
++#define dom0_del_memtype_t xenpf_del_memtype_t
++
++#define DOM0_READ_MEMTYPE XENPF_read_memtype
++#define dom0_read_memtype xenpf_read_memtype
++#define dom0_read_memtype_t xenpf_read_memtype_t
++
++#define DOM0_MICROCODE XENPF_microcode_update
++#define dom0_microcode xenpf_microcode_update
++#define dom0_microcode_t xenpf_microcode_update_t
++
++#define DOM0_PLATFORM_QUIRK XENPF_platform_quirk
++#define dom0_platform_quirk xenpf_platform_quirk
++#define dom0_platform_quirk_t xenpf_platform_quirk_t
++
++typedef uint64_t cpumap_t;
++
++/* Unsupported legacy operation -- defined for API compatibility. */
++#define DOM0_MSR 15
++struct dom0_msr {
++ /* IN variables. */
++ uint32_t write;
++ cpumap_t cpu_mask;
++ uint32_t msr;
++ uint32_t in1;
++ uint32_t in2;
++ /* OUT variables. */
++ uint32_t out1;
++ uint32_t out2;
++};
++typedef struct dom0_msr dom0_msr_t;
++DEFINE_XEN_GUEST_HANDLE(dom0_msr_t);
++
++/* Unsupported legacy operation -- defined for API compatibility. */
++#define DOM0_PHYSICAL_MEMORY_MAP 40
++struct dom0_memory_map_entry {
++ uint64_t start, end;
++ uint32_t flags; /* reserved */
++ uint8_t is_ram;
++};
++typedef struct dom0_memory_map_entry dom0_memory_map_entry_t;
++DEFINE_XEN_GUEST_HANDLE(dom0_memory_map_entry_t);
++
++struct dom0_op {
++ uint32_t cmd;
++ uint32_t interface_version; /* DOM0_INTERFACE_VERSION */
++ union {
++ struct dom0_msr msr;
++ struct dom0_settime settime;
++ struct dom0_add_memtype add_memtype;
++ struct dom0_del_memtype del_memtype;
++ struct dom0_read_memtype read_memtype;
++ struct dom0_microcode microcode;
++ struct dom0_platform_quirk platform_quirk;
++ struct dom0_memory_map_entry physical_memory_map;
++ uint8_t pad[128];
++ } u;
++};
++typedef struct dom0_op dom0_op_t;
++DEFINE_XEN_GUEST_HANDLE(dom0_op_t);
++
++#endif /* __XEN_PUBLIC_DOM0_OPS_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/domctl.h linux-2.6.18-xen/include/xen/interface/domctl.h
+--- linux-2.6.18.1/include/xen/interface/domctl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/domctl.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,392 @@
++/******************************************************************************
++ * domctl.h
++ *
++ * Domain management operations. For use by node control stack.
++ *
++ * Copyright (c) 2002-2003, B Dragovic
++ * Copyright (c) 2002-2006, K Fraser
++ */
++
++#ifndef __XEN_PUBLIC_DOMCTL_H__
++#define __XEN_PUBLIC_DOMCTL_H__
++
++#if !defined(__XEN__) && !defined(__XEN_TOOLS__)
++#error "domctl operations are intended for use by node control tools only"
++#endif
++
++#include "xen.h"
++
++#define XEN_DOMCTL_INTERFACE_VERSION 0x00000003
++
++struct xenctl_cpumap {
++ XEN_GUEST_HANDLE(uint8_t) bitmap;
++ uint32_t nr_cpus;
++};
++
++/*
++ * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
++ * If it is specified as zero, an id is auto-allocated and returned.
++ */
++#define XEN_DOMCTL_createdomain 1
++struct xen_domctl_createdomain {
++ /* IN parameters */
++ uint32_t ssidref;
++ xen_domain_handle_t handle;
++};
++typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t);
++
++#define XEN_DOMCTL_destroydomain 2
++#define XEN_DOMCTL_pausedomain 3
++#define XEN_DOMCTL_unpausedomain 4
++
++#define XEN_DOMCTL_getdomaininfo 5
++struct xen_domctl_getdomaininfo {
++ /* OUT variables. */
++ domid_t domain; /* Also echoed in domctl.domain */
++#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
++#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
++#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
++#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
++#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
++#define DOMFLAGS_CPUMASK 255 /* CPU to which this domain is bound. */
++#define DOMFLAGS_CPUSHIFT 8
++#define DOMFLAGS_SHUTDOWNMASK 255 /* DOMFLAGS_SHUTDOWN guest-supplied code. */
++#define DOMFLAGS_SHUTDOWNSHIFT 16
++ uint32_t flags;
++ uint64_t tot_pages;
++ uint64_t max_pages;
++ uint64_t shared_info_frame; /* MFN of shared_info struct */
++ uint64_t cpu_time;
++ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
++ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
++ uint32_t ssidref;
++ xen_domain_handle_t handle;
++};
++typedef struct xen_domctl_getdomaininfo xen_domctl_getdomaininfo_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getdomaininfo_t);
++
++
++#define XEN_DOMCTL_getmemlist 6
++struct xen_domctl_getmemlist {
++ /* IN variables. */
++ /* Max entries to write to output buffer. */
++ uint64_t max_pfns;
++ /* Start index in guest's page list. */
++ uint64_t start_pfn;
++ XEN_GUEST_HANDLE(xen_pfn_t) buffer;
++ /* OUT variables. */
++ uint64_t num_pfns;
++};
++typedef struct xen_domctl_getmemlist xen_domctl_getmemlist_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getmemlist_t);
++
++
++#define XEN_DOMCTL_getpageframeinfo 7
++
++#define XEN_DOMCTL_PFINFO_LTAB_SHIFT 28
++#define XEN_DOMCTL_PFINFO_NOTAB (0x0<<28)
++#define XEN_DOMCTL_PFINFO_L1TAB (0x1<<28)
++#define XEN_DOMCTL_PFINFO_L2TAB (0x2<<28)
++#define XEN_DOMCTL_PFINFO_L3TAB (0x3<<28)
++#define XEN_DOMCTL_PFINFO_L4TAB (0x4<<28)
++#define XEN_DOMCTL_PFINFO_LTABTYPE_MASK (0x7<<28)
++#define XEN_DOMCTL_PFINFO_LPINTAB (0x1<<31)
++#define XEN_DOMCTL_PFINFO_XTAB (0xf<<28) /* invalid page */
++#define XEN_DOMCTL_PFINFO_LTAB_MASK (0xf<<28)
++
++struct xen_domctl_getpageframeinfo {
++ /* IN variables. */
++ uint64_t gmfn; /* GMFN to query */
++ /* OUT variables. */
++ /* Is the page PINNED to a type? */
++ uint32_t type; /* see above type defs */
++};
++typedef struct xen_domctl_getpageframeinfo xen_domctl_getpageframeinfo_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo_t);
++
++
++#define XEN_DOMCTL_getpageframeinfo2 8
++struct xen_domctl_getpageframeinfo2 {
++ /* IN variables. */
++ uint64_t num;
++ /* IN/OUT variables. */
++ XEN_GUEST_HANDLE(ulong) array;
++};
++typedef struct xen_domctl_getpageframeinfo2 xen_domctl_getpageframeinfo2_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo2_t);
++
++
++/*
++ * Control shadow pagetables operation
++ */
++#define XEN_DOMCTL_shadow_op 10
++
++/* Disable shadow mode. */
++#define XEN_DOMCTL_SHADOW_OP_OFF 0
++
++/* Enable shadow mode (mode contains ORed XEN_DOMCTL_SHADOW_ENABLE_* flags). */
++#define XEN_DOMCTL_SHADOW_OP_ENABLE 32
++
++/* Log-dirty bitmap operations. */
++ /* Return the bitmap and clean internal copy for next round. */
++#define XEN_DOMCTL_SHADOW_OP_CLEAN 11
++ /* Return the bitmap but do not modify internal copy. */
++#define XEN_DOMCTL_SHADOW_OP_PEEK 12
++
++/* Memory allocation accessors. */
++#define XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION 30
++#define XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION 31
++
++/* Legacy enable operations. */
++ /* Equiv. to ENABLE with no mode flags. */
++#define XEN_DOMCTL_SHADOW_OP_ENABLE_TEST 1
++ /* Equiv. to ENABLE with mode flag ENABLE_LOG_DIRTY. */
++#define XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY 2
++ /* Equiv. to ENABLE with mode flags ENABLE_REFCOUNT and ENABLE_TRANSLATE. */
++#define XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE 3
++
++/* Mode flags for XEN_DOMCTL_SHADOW_OP_ENABLE. */
++ /*
++ * Shadow pagetables are refcounted: guest does not use explicit mmu
++ * operations nor write-protect its pagetables.
++ */
++#define XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT (1 << 1)
++ /*
++ * Log pages in a bitmap as they are dirtied.
++ * Used for live relocation to determine which pages must be re-sent.
++ */
++#define XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY (1 << 2)
++ /*
++ * Automatically translate GPFNs into MFNs.
++ */
++#define XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE (1 << 3)
++ /*
++ * Xen does not steal virtual address space from the guest.
++ * Requires HVM support.
++ */
++#define XEN_DOMCTL_SHADOW_ENABLE_EXTERNAL (1 << 4)
++
++struct xen_domctl_shadow_op_stats {
++ uint32_t fault_count;
++ uint32_t dirty_count;
++};
++typedef struct xen_domctl_shadow_op_stats xen_domctl_shadow_op_stats_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_shadow_op_stats_t);
++
++struct xen_domctl_shadow_op {
++ /* IN variables. */
++ uint32_t op; /* XEN_DOMCTL_SHADOW_OP_* */
++
++ /* OP_ENABLE */
++ uint32_t mode; /* XEN_DOMCTL_SHADOW_ENABLE_* */
++
++ /* OP_GET_ALLOCATION / OP_SET_ALLOCATION */
++ uint32_t mb; /* Shadow memory allocation in MB */
++
++ /* OP_PEEK / OP_CLEAN */
++ XEN_GUEST_HANDLE(ulong) dirty_bitmap;
++ uint64_t pages; /* Size of buffer. Updated with actual size. */
++ struct xen_domctl_shadow_op_stats stats;
++};
++typedef struct xen_domctl_shadow_op xen_domctl_shadow_op_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_shadow_op_t);
++
++
++#define XEN_DOMCTL_max_mem 11
++struct xen_domctl_max_mem {
++ /* IN variables. */
++ uint64_t max_memkb;
++};
++typedef struct xen_domctl_max_mem xen_domctl_max_mem_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_max_mem_t);
++
++
++#define XEN_DOMCTL_setvcpucontext 12
++#define XEN_DOMCTL_getvcpucontext 13
++struct xen_domctl_vcpucontext {
++ uint32_t vcpu; /* IN */
++ XEN_GUEST_HANDLE(vcpu_guest_context_t) ctxt; /* IN/OUT */
++};
++typedef struct xen_domctl_vcpucontext xen_domctl_vcpucontext_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpucontext_t);
++
++
++#define XEN_DOMCTL_getvcpuinfo 14
++struct xen_domctl_getvcpuinfo {
++ /* IN variables. */
++ uint32_t vcpu;
++ /* OUT variables. */
++ uint8_t online; /* currently online (not hotplugged)? */
++ uint8_t blocked; /* blocked waiting for an event? */
++ uint8_t running; /* currently scheduled on its CPU? */
++ uint64_t cpu_time; /* total cpu time consumed (ns) */
++ uint32_t cpu; /* current mapping */
++};
++typedef struct xen_domctl_getvcpuinfo xen_domctl_getvcpuinfo_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getvcpuinfo_t);
++
++
++/* Get/set which physical cpus a vcpu can execute on. */
++#define XEN_DOMCTL_setvcpuaffinity 9
++#define XEN_DOMCTL_getvcpuaffinity 25
++struct xen_domctl_vcpuaffinity {
++ uint32_t vcpu; /* IN */
++ struct xenctl_cpumap cpumap; /* IN/OUT */
++};
++typedef struct xen_domctl_vcpuaffinity xen_domctl_vcpuaffinity_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpuaffinity_t);
++
++
++#define XEN_DOMCTL_max_vcpus 15
++struct xen_domctl_max_vcpus {
++ uint32_t max; /* maximum number of vcpus */
++};
++typedef struct xen_domctl_max_vcpus xen_domctl_max_vcpus_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_max_vcpus_t);
++
++
++#define XEN_DOMCTL_scheduler_op 16
++/* Scheduler types. */
++#define XEN_SCHEDULER_SEDF 4
++#define XEN_SCHEDULER_CREDIT 5
++/* Set or get info? */
++#define XEN_DOMCTL_SCHEDOP_putinfo 0
++#define XEN_DOMCTL_SCHEDOP_getinfo 1
++struct xen_domctl_scheduler_op {
++ uint32_t sched_id; /* XEN_SCHEDULER_* */
++ uint32_t cmd; /* XEN_DOMCTL_SCHEDOP_* */
++ union {
++ struct xen_domctl_sched_sedf {
++ uint64_t period;
++ uint64_t slice;
++ uint64_t latency;
++ uint32_t extratime;
++ uint32_t weight;
++ } sedf;
++ struct xen_domctl_sched_credit {
++ uint16_t weight;
++ uint16_t cap;
++ } credit;
++ } u;
++};
++typedef struct xen_domctl_scheduler_op xen_domctl_scheduler_op_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_scheduler_op_t);
++
++
++#define XEN_DOMCTL_setdomainhandle 17
++struct xen_domctl_setdomainhandle {
++ xen_domain_handle_t handle;
++};
++typedef struct xen_domctl_setdomainhandle xen_domctl_setdomainhandle_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_setdomainhandle_t);
++
++
++#define XEN_DOMCTL_setdebugging 18
++struct xen_domctl_setdebugging {
++ uint8_t enable;
++};
++typedef struct xen_domctl_setdebugging xen_domctl_setdebugging_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_setdebugging_t);
++
++
++#define XEN_DOMCTL_irq_permission 19
++struct xen_domctl_irq_permission {
++ uint8_t pirq;
++ uint8_t allow_access; /* flag to specify enable/disable of IRQ access */
++};
++typedef struct xen_domctl_irq_permission xen_domctl_irq_permission_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_irq_permission_t);
++
++
++#define XEN_DOMCTL_iomem_permission 20
++struct xen_domctl_iomem_permission {
++ uint64_t first_mfn; /* first page (physical page number) in range */
++ uint64_t nr_mfns; /* number of pages in range (>0) */
++ uint8_t allow_access; /* allow (!0) or deny (0) access to range? */
++};
++typedef struct xen_domctl_iomem_permission xen_domctl_iomem_permission_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_iomem_permission_t);
++
++
++#define XEN_DOMCTL_ioport_permission 21
++struct xen_domctl_ioport_permission {
++ uint32_t first_port; /* first port int range */
++ uint32_t nr_ports; /* size of port range */
++ uint8_t allow_access; /* allow or deny access to range? */
++};
++typedef struct xen_domctl_ioport_permission xen_domctl_ioport_permission_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_ioport_permission_t);
++
++#define XEN_DOMCTL_hypercall_init 22
++struct xen_domctl_hypercall_init {
++ uint64_t gmfn; /* GMFN to be initialised */
++};
++typedef struct xen_domctl_hypercall_init xen_domctl_hypercall_init_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_hypercall_init_t);
++
++#define XEN_DOMCTL_arch_setup 23
++#define _XEN_DOMAINSETUP_hvm_guest 0
++#define XEN_DOMAINSETUP_hvm_guest (1UL<<_XEN_DOMAINSETUP_hvm_guest)
++#define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save) */
++#define XEN_DOMAINSETUP_query (1UL<<_XEN_DOMAINSETUP_query)
++typedef struct xen_domctl_arch_setup {
++ uint64_t flags; /* XEN_DOMAINSETUP_* */
++#ifdef __ia64__
++ uint64_t bp; /* mpaddr of boot param area */
++ uint64_t maxmem; /* Highest memory address for MDT. */
++ uint64_t xsi_va; /* Xen shared_info area virtual address. */
++ uint32_t hypercall_imm; /* Break imm for Xen hypercalls. */
++#endif
++} xen_domctl_arch_setup_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_arch_setup_t);
++
++#define XEN_DOMCTL_settimeoffset 24
++struct xen_domctl_settimeoffset {
++ int32_t time_offset_seconds; /* applied to domain wallclock time */
++};
++typedef struct xen_domctl_settimeoffset xen_domctl_settimeoffset_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_settimeoffset_t);
++
++struct xen_domctl {
++ uint32_t cmd;
++ uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
++ domid_t domain;
++ union {
++ struct xen_domctl_createdomain createdomain;
++ struct xen_domctl_getdomaininfo getdomaininfo;
++ struct xen_domctl_getmemlist getmemlist;
++ struct xen_domctl_getpageframeinfo getpageframeinfo;
++ struct xen_domctl_getpageframeinfo2 getpageframeinfo2;
++ struct xen_domctl_vcpuaffinity vcpuaffinity;
++ struct xen_domctl_shadow_op shadow_op;
++ struct xen_domctl_max_mem max_mem;
++ struct xen_domctl_vcpucontext vcpucontext;
++ struct xen_domctl_getvcpuinfo getvcpuinfo;
++ struct xen_domctl_max_vcpus max_vcpus;
++ struct xen_domctl_scheduler_op scheduler_op;
++ struct xen_domctl_setdomainhandle setdomainhandle;
++ struct xen_domctl_setdebugging setdebugging;
++ struct xen_domctl_irq_permission irq_permission;
++ struct xen_domctl_iomem_permission iomem_permission;
++ struct xen_domctl_ioport_permission ioport_permission;
++ struct xen_domctl_hypercall_init hypercall_init;
++ struct xen_domctl_arch_setup arch_setup;
++ struct xen_domctl_settimeoffset settimeoffset;
++ uint8_t pad[128];
++ } u;
++};
++typedef struct xen_domctl xen_domctl_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_t);
++
++#endif /* __XEN_PUBLIC_DOMCTL_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/elfnote.h linux-2.6.18-xen/include/xen/interface/elfnote.h
+--- linux-2.6.18.1/include/xen/interface/elfnote.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/elfnote.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,133 @@
++/******************************************************************************
++ * elfnote.h
++ *
++ * Definitions used for the Xen ELF notes.
++ *
++ * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
++ */
++
++#ifndef __XEN_PUBLIC_ELFNOTE_H__
++#define __XEN_PUBLIC_ELFNOTE_H__
++
++/*
++ * The notes should live in a SHT_NOTE segment and have "Xen" in the
++ * name field.
++ *
++ * Numeric types are either 4 or 8 bytes depending on the content of
++ * the desc field.
++ *
++ * LEGACY indicated the fields in the legacy __xen_guest string which
++ * this a note type replaces.
++ */
++
++/*
++ * NAME=VALUE pair (string).
++ *
++ * LEGACY: FEATURES and PAE
++ */
++#define XEN_ELFNOTE_INFO 0
++
++/*
++ * The virtual address of the entry point (numeric).
++ *
++ * LEGACY: VIRT_ENTRY
++ */
++#define XEN_ELFNOTE_ENTRY 1
++
++/* The virtual address of the hypercall transfer page (numeric).
++ *
++ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page
++ * number not a virtual address)
++ */
++#define XEN_ELFNOTE_HYPERCALL_PAGE 2
++
++/* The virtual address where the kernel image should be mapped (numeric).
++ *
++ * Defaults to 0.
++ *
++ * LEGACY: VIRT_BASE
++ */
++#define XEN_ELFNOTE_VIRT_BASE 3
++
++/*
++ * The offset of the ELF paddr field from the acutal required
++ * psuedo-physical address (numeric).
++ *
++ * This is used to maintain backwards compatibility with older kernels
++ * which wrote __PAGE_OFFSET into that field. This field defaults to 0
++ * if not present.
++ *
++ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE)
++ */
++#define XEN_ELFNOTE_PADDR_OFFSET 4
++
++/*
++ * The version of Xen that we work with (string).
++ *
++ * LEGACY: XEN_VER
++ */
++#define XEN_ELFNOTE_XEN_VERSION 5
++
++/*
++ * The name of the guest operating system (string).
++ *
++ * LEGACY: GUEST_OS
++ */
++#define XEN_ELFNOTE_GUEST_OS 6
++
++/*
++ * The version of the guest operating system (string).
++ *
++ * LEGACY: GUEST_VER
++ */
++#define XEN_ELFNOTE_GUEST_VERSION 7
++
++/*
++ * The loader type (string).
++ *
++ * LEGACY: LOADER
++ */
++#define XEN_ELFNOTE_LOADER 8
++
++/*
++ * The kernel supports PAE (x86/32 only, string = "yes" or "no").
++ *
++ * LEGACY: PAE (n.b. The legacy interface included a provision to
++ * indicate 'extended-cr3' support allowing L3 page tables to be
++ * placed above 4G. It is assumed that any kernel new enough to use
++ * these ELF notes will include this and therefore "yes" here is
++ * equivalent to "yes[entended-cr3]" in the __xen_guest interface.
++ */
++#define XEN_ELFNOTE_PAE_MODE 9
++
++/*
++ * The features supported/required by this kernel (string).
++ *
++ * The string must consist of a list of feature names (as given in
++ * features.h, without the "XENFEAT_" prefix) separated by '|'
++ * characters. If a feature is required for the kernel to function
++ * then the feature name must be preceded by a '!' character.
++ *
++ * LEGACY: FEATURES
++ */
++#define XEN_ELFNOTE_FEATURES 10
++
++/*
++ * The kernel requires the symbol table to be loaded (string = "yes" or "no")
++ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence
++ * of this string as a boolean flag rather than requiring "yes" or
++ * "no".
++ */
++#define XEN_ELFNOTE_BSD_SYMTAB 11
++
++#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/event_channel.h linux-2.6.18-xen/include/xen/interface/event_channel.h
+--- linux-2.6.18.1/include/xen/interface/event_channel.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/event_channel.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,233 @@
++/******************************************************************************
++ * event_channel.h
++ *
++ * Event channels between domains.
++ *
++ * Copyright (c) 2003-2004, K A Fraser.
++ */
++
++#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__
++#define __XEN_PUBLIC_EVENT_CHANNEL_H__
++
++/*
++ * Prototype for this hypercall is:
++ * int event_channel_op(int cmd, void *args)
++ * @cmd == EVTCHNOP_??? (event-channel operation).
++ * @args == Operation-specific extra arguments (NULL if none).
++ */
++
++typedef uint32_t evtchn_port_t;
++DEFINE_XEN_GUEST_HANDLE(evtchn_port_t);
++
++/*
++ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
++ * accepting interdomain bindings from domain <remote_dom>. A fresh port
++ * is allocated in <dom> and returned as <port>.
++ * NOTES:
++ * 1. If the caller is unprivileged then <dom> must be DOMID_SELF.
++ * 2. <rdom> may be DOMID_SELF, allowing loopback connections.
++ */
++#define EVTCHNOP_alloc_unbound 6
++struct evtchn_alloc_unbound {
++ /* IN parameters */
++ domid_t dom, remote_dom;
++ /* OUT parameters */
++ evtchn_port_t port;
++};
++typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t;
++
++/*
++ * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
++ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
++ * a port that is unbound and marked as accepting bindings from the calling
++ * domain. A fresh port is allocated in the calling domain and returned as
++ * <local_port>.
++ * NOTES:
++ * 2. <remote_dom> may be DOMID_SELF, allowing loopback connections.
++ */
++#define EVTCHNOP_bind_interdomain 0
++struct evtchn_bind_interdomain {
++ /* IN parameters. */
++ domid_t remote_dom;
++ evtchn_port_t remote_port;
++ /* OUT parameters. */
++ evtchn_port_t local_port;
++};
++typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t;
++
++/*
++ * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified
++ * vcpu.
++ * NOTES:
++ * 1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list
++ * in xen.h for the classification of each VIRQ.
++ * 2. Global VIRQs must be allocated on VCPU0 but can subsequently be
++ * re-bound via EVTCHNOP_bind_vcpu.
++ * 3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu.
++ * The allocated event channel is bound to the specified vcpu and the
++ * binding cannot be changed.
++ */
++#define EVTCHNOP_bind_virq 1
++struct evtchn_bind_virq {
++ /* IN parameters. */
++ uint32_t virq;
++ uint32_t vcpu;
++ /* OUT parameters. */
++ evtchn_port_t port;
++};
++typedef struct evtchn_bind_virq evtchn_bind_virq_t;
++
++/*
++ * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ <irq>.
++ * NOTES:
++ * 1. A physical IRQ may be bound to at most one event channel per domain.
++ * 2. Only a sufficiently-privileged domain may bind to a physical IRQ.
++ */
++#define EVTCHNOP_bind_pirq 2
++struct evtchn_bind_pirq {
++ /* IN parameters. */
++ uint32_t pirq;
++#define BIND_PIRQ__WILL_SHARE 1
++ uint32_t flags; /* BIND_PIRQ__* */
++ /* OUT parameters. */
++ evtchn_port_t port;
++};
++typedef struct evtchn_bind_pirq evtchn_bind_pirq_t;
++
++/*
++ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
++ * NOTES:
++ * 1. The allocated event channel is bound to the specified vcpu. The binding
++ * may not be changed.
++ */
++#define EVTCHNOP_bind_ipi 7
++struct evtchn_bind_ipi {
++ uint32_t vcpu;
++ /* OUT parameters. */
++ evtchn_port_t port;
++};
++typedef struct evtchn_bind_ipi evtchn_bind_ipi_t;
++
++/*
++ * EVTCHNOP_close: Close a local event channel <port>. If the channel is
++ * interdomain then the remote end is placed in the unbound state
++ * (EVTCHNSTAT_unbound), awaiting a new connection.
++ */
++#define EVTCHNOP_close 3
++struct evtchn_close {
++ /* IN parameters. */
++ evtchn_port_t port;
++};
++typedef struct evtchn_close evtchn_close_t;
++
++/*
++ * EVTCHNOP_send: Send an event to the remote end of the channel whose local
++ * endpoint is <port>.
++ */
++#define EVTCHNOP_send 4
++struct evtchn_send {
++ /* IN parameters. */
++ evtchn_port_t port;
++};
++typedef struct evtchn_send evtchn_send_t;
++
++/*
++ * EVTCHNOP_status: Get the current status of the communication channel which
++ * has an endpoint at <dom, port>.
++ * NOTES:
++ * 1. <dom> may be specified as DOMID_SELF.
++ * 2. Only a sufficiently-privileged domain may obtain the status of an event
++ * channel for which <dom> is not DOMID_SELF.
++ */
++#define EVTCHNOP_status 5
++struct evtchn_status {
++ /* IN parameters */
++ domid_t dom;
++ evtchn_port_t port;
++ /* OUT parameters */
++#define EVTCHNSTAT_closed 0 /* Channel is not in use. */
++#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/
++#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
++#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
++#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
++#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */
++ uint32_t status;
++ uint32_t vcpu; /* VCPU to which this channel is bound. */
++ union {
++ struct {
++ domid_t dom;
++ } unbound; /* EVTCHNSTAT_unbound */
++ struct {
++ domid_t dom;
++ evtchn_port_t port;
++ } interdomain; /* EVTCHNSTAT_interdomain */
++ uint32_t pirq; /* EVTCHNSTAT_pirq */
++ uint32_t virq; /* EVTCHNSTAT_virq */
++ } u;
++};
++typedef struct evtchn_status evtchn_status_t;
++
++/*
++ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
++ * event is pending.
++ * NOTES:
++ * 1. IPI-bound channels always notify the vcpu specified at bind time.
++ * This binding cannot be changed.
++ * 2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time.
++ * This binding cannot be changed.
++ * 3. All other channels notify vcpu0 by default. This default is set when
++ * the channel is allocated (a port that is freed and subsequently reused
++ * has its binding reset to vcpu0).
++ */
++#define EVTCHNOP_bind_vcpu 8
++struct evtchn_bind_vcpu {
++ /* IN parameters. */
++ evtchn_port_t port;
++ uint32_t vcpu;
++};
++typedef struct evtchn_bind_vcpu evtchn_bind_vcpu_t;
++
++/*
++ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
++ * a notification to the appropriate VCPU if an event is pending.
++ */
++#define EVTCHNOP_unmask 9
++struct evtchn_unmask {
++ /* IN parameters. */
++ evtchn_port_t port;
++};
++typedef struct evtchn_unmask evtchn_unmask_t;
++
++/*
++ * Argument to event_channel_op_compat() hypercall. Superceded by new
++ * event_channel_op() hypercall since 0x00030202.
++ */
++struct evtchn_op {
++ uint32_t cmd; /* EVTCHNOP_* */
++ union {
++ struct evtchn_alloc_unbound alloc_unbound;
++ struct evtchn_bind_interdomain bind_interdomain;
++ struct evtchn_bind_virq bind_virq;
++ struct evtchn_bind_pirq bind_pirq;
++ struct evtchn_bind_ipi bind_ipi;
++ struct evtchn_close close;
++ struct evtchn_send send;
++ struct evtchn_status status;
++ struct evtchn_bind_vcpu bind_vcpu;
++ struct evtchn_unmask unmask;
++ } u;
++};
++typedef struct evtchn_op evtchn_op_t;
++DEFINE_XEN_GUEST_HANDLE(evtchn_op_t);
++
++#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/features.h linux-2.6.18-xen/include/xen/interface/features.h
+--- linux-2.6.18.1/include/xen/interface/features.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/features.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,53 @@
++/******************************************************************************
++ * features.h
++ *
++ * Feature flags, reported by XENVER_get_features.
++ *
++ * Copyright (c) 2006, Keir Fraser <keir at xensource.com>
++ */
++
++#ifndef __XEN_PUBLIC_FEATURES_H__
++#define __XEN_PUBLIC_FEATURES_H__
++
++/*
++ * If set, the guest does not need to write-protect its pagetables, and can
++ * update them via direct writes.
++ */
++#define XENFEAT_writable_page_tables 0
++
++/*
++ * If set, the guest does not need to write-protect its segment descriptor
++ * tables, and can update them via direct writes.
++ */
++#define XENFEAT_writable_descriptor_tables 1
++
++/*
++ * If set, translation between the guest's 'pseudo-physical' address space
++ * and the host's machine address space are handled by the hypervisor. In this
++ * mode the guest does not need to perform phys-to/from-machine translations
++ * when performing page table operations.
++ */
++#define XENFEAT_auto_translated_physmap 2
++
++/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */
++#define XENFEAT_supervisor_mode_kernel 3
++
++/*
++ * If set, the guest does not need to allocate x86 PAE page directories
++ * below 4GB. This flag is usually implied by auto_translated_physmap.
++ */
++#define XENFEAT_pae_pgdir_above_4gb 4
++
++#define XENFEAT_NR_SUBMAPS 1
++
++#endif /* __XEN_PUBLIC_FEATURES_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/grant_table.h linux-2.6.18-xen/include/xen/interface/grant_table.h
+--- linux-2.6.18.1/include/xen/interface/grant_table.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/grant_table.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,362 @@
++/******************************************************************************
++ * grant_table.h
++ *
++ * Interface for granting foreign access to page frames, and receiving
++ * page-ownership transfers.
++ *
++ * Copyright (c) 2004, K A Fraser
++ */
++
++#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
++#define __XEN_PUBLIC_GRANT_TABLE_H__
++
++
++/***********************************
++ * GRANT TABLE REPRESENTATION
++ */
++
++/* Some rough guidelines on accessing and updating grant-table entries
++ * in a concurrency-safe manner. For more information, Linux contains a
++ * reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
++ *
++ * NB. WMB is a no-op on current-generation x86 processors. However, a
++ * compiler barrier will still be required.
++ *
++ * Introducing a valid entry into the grant table:
++ * 1. Write ent->domid.
++ * 2. Write ent->frame:
++ * GTF_permit_access: Frame to which access is permitted.
++ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
++ * frame, or zero if none.
++ * 3. Write memory barrier (WMB).
++ * 4. Write ent->flags, inc. valid type.
++ *
++ * Invalidating an unused GTF_permit_access entry:
++ * 1. flags = ent->flags.
++ * 2. Observe that !(flags & (GTF_reading|GTF_writing)).
++ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
++ * NB. No need for WMB as reuse of entry is control-dependent on success of
++ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
++ *
++ * Invalidating an in-use GTF_permit_access entry:
++ * This cannot be done directly. Request assistance from the domain controller
++ * which can set a timeout on the use of a grant entry and take necessary
++ * action. (NB. This is not yet implemented!).
++ *
++ * Invalidating an unused GTF_accept_transfer entry:
++ * 1. flags = ent->flags.
++ * 2. Observe that !(flags & GTF_transfer_committed). [*]
++ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
++ * NB. No need for WMB as reuse of entry is control-dependent on success of
++ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
++ * [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
++ * The guest must /not/ modify the grant entry until the address of the
++ * transferred frame is written. It is safe for the guest to spin waiting
++ * for this to occur (detect by observing GTF_transfer_completed in
++ * ent->flags).
++ *
++ * Invalidating a committed GTF_accept_transfer entry:
++ * 1. Wait for (ent->flags & GTF_transfer_completed).
++ *
++ * Changing a GTF_permit_access from writable to read-only:
++ * Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
++ *
++ * Changing a GTF_permit_access from read-only to writable:
++ * Use SMP-safe bit-setting instruction.
++ */
++
++/*
++ * A grant table comprises a packed array of grant entries in one or more
++ * page frames shared between Xen and a guest.
++ * [XEN]: This field is written by Xen and read by the sharing guest.
++ * [GST]: This field is written by the guest and read by Xen.
++ */
++struct grant_entry {
++ /* GTF_xxx: various type and flag information. [XEN,GST] */
++ uint16_t flags;
++ /* The domain being granted foreign privileges. [GST] */
++ domid_t domid;
++ /*
++ * GTF_permit_access: Frame that @domid is allowed to map and access. [GST]
++ * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN]
++ */
++ uint32_t frame;
++};
++typedef struct grant_entry grant_entry_t;
++
++/*
++ * Type of grant entry.
++ * GTF_invalid: This grant entry grants no privileges.
++ * GTF_permit_access: Allow @domid to map/access @frame.
++ * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
++ * to this guest. Xen writes the page number to @frame.
++ */
++#define GTF_invalid (0U<<0)
++#define GTF_permit_access (1U<<0)
++#define GTF_accept_transfer (2U<<0)
++#define GTF_type_mask (3U<<0)
++
++/*
++ * Subflags for GTF_permit_access.
++ * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
++ * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
++ * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
++ */
++#define _GTF_readonly (2)
++#define GTF_readonly (1U<<_GTF_readonly)
++#define _GTF_reading (3)
++#define GTF_reading (1U<<_GTF_reading)
++#define _GTF_writing (4)
++#define GTF_writing (1U<<_GTF_writing)
++
++/*
++ * Subflags for GTF_accept_transfer:
++ * GTF_transfer_committed: Xen sets this flag to indicate that it is committed
++ * to transferring ownership of a page frame. When a guest sees this flag
++ * it must /not/ modify the grant entry until GTF_transfer_completed is
++ * set by Xen.
++ * GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
++ * after reading GTF_transfer_committed. Xen will always write the frame
++ * address, followed by ORing this flag, in a timely manner.
++ */
++#define _GTF_transfer_committed (2)
++#define GTF_transfer_committed (1U<<_GTF_transfer_committed)
++#define _GTF_transfer_completed (3)
++#define GTF_transfer_completed (1U<<_GTF_transfer_completed)
++
++
++/***********************************
++ * GRANT TABLE QUERIES AND USES
++ */
++
++/*
++ * Reference to a grant entry in a specified domain's grant table.
++ */
++typedef uint32_t grant_ref_t;
++
++/*
++ * Handle to track a mapping created via a grant reference.
++ */
++typedef uint32_t grant_handle_t;
++
++/*
++ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
++ * by devices and/or host CPUs. If successful, <handle> is a tracking number
++ * that must be presented later to destroy the mapping(s). On error, <handle>
++ * is a negative status code.
++ * NOTES:
++ * 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
++ * via which I/O devices may access the granted frame.
++ * 2. If GNTMAP_host_map is specified then a mapping will be added at
++ * either a host virtual address in the current address space, or at
++ * a PTE at the specified machine address. The type of mapping to
++ * perform is selected through the GNTMAP_contains_pte flag, and the
++ * address is specified in <host_addr>.
++ * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
++ * host mapping is destroyed by other means then it is *NOT* guaranteed
++ * to be accounted to the correct grant reference!
++ */
++#define GNTTABOP_map_grant_ref 0
++struct gnttab_map_grant_ref {
++ /* IN parameters. */
++ uint64_t host_addr;
++ uint32_t flags; /* GNTMAP_* */
++ grant_ref_t ref;
++ domid_t dom;
++ /* OUT parameters. */
++ int16_t status; /* GNTST_* */
++ grant_handle_t handle;
++ uint64_t dev_bus_addr;
++};
++typedef struct gnttab_map_grant_ref gnttab_map_grant_ref_t;
++DEFINE_XEN_GUEST_HANDLE(gnttab_map_grant_ref_t);
++
++/*
++ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
++ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
++ * field is ignored. If non-zero, they must refer to a device/host mapping
++ * that is tracked by <handle>
++ * NOTES:
++ * 1. The call may fail in an undefined manner if either mapping is not
++ * tracked by <handle>.
++ * 3. After executing a batch of unmaps, it is guaranteed that no stale
++ * mappings will remain in the device or host TLBs.
++ */
++#define GNTTABOP_unmap_grant_ref 1
++struct gnttab_unmap_grant_ref {
++ /* IN parameters. */
++ uint64_t host_addr;
++ uint64_t dev_bus_addr;
++ grant_handle_t handle;
++ /* OUT parameters. */
++ int16_t status; /* GNTST_* */
++};
++typedef struct gnttab_unmap_grant_ref gnttab_unmap_grant_ref_t;
++DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t);
++
++/*
++ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
++ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
++ * Only <nr_frames> addresses are written, even if the table is larger.
++ * NOTES:
++ * 1. <dom> may be specified as DOMID_SELF.
++ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
++ * 3. Xen may not support more than a single grant-table page per domain.
++ */
++#define GNTTABOP_setup_table 2
++struct gnttab_setup_table {
++ /* IN parameters. */
++ domid_t dom;
++ uint32_t nr_frames;
++ /* OUT parameters. */
++ int16_t status; /* GNTST_* */
++ XEN_GUEST_HANDLE(ulong) frame_list;
++};
++typedef struct gnttab_setup_table gnttab_setup_table_t;
++DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_t);
++
++/*
++ * GNTTABOP_dump_table: Dump the contents of the grant table to the
++ * xen console. Debugging use only.
++ */
++#define GNTTABOP_dump_table 3
++struct gnttab_dump_table {
++ /* IN parameters. */
++ domid_t dom;
++ /* OUT parameters. */
++ int16_t status; /* GNTST_* */
++};
++typedef struct gnttab_dump_table gnttab_dump_table_t;
++DEFINE_XEN_GUEST_HANDLE(gnttab_dump_table_t);
++
++/*
++ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
++ * foreign domain has previously registered its interest in the transfer via
++ * <domid, ref>.
++ *
++ * Note that, even if the transfer fails, the specified page no longer belongs
++ * to the calling domain *unless* the error is GNTST_bad_page.
++ */
++#define GNTTABOP_transfer 4
++struct gnttab_transfer {
++ /* IN parameters. */
++ xen_pfn_t mfn;
++ domid_t domid;
++ grant_ref_t ref;
++ /* OUT parameters. */
++ int16_t status;
++};
++typedef struct gnttab_transfer gnttab_transfer_t;
++DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t);
++
++
++/*
++ * GNTTABOP_copy: Hypervisor based copy
++ * source and destinations can be eithers MFNs or, for foreign domains,
++ * grant references. the foreign domain has to grant read/write access
++ * in its grant table.
++ *
++ * The flags specify what type source and destinations are (either MFN
++ * or grant reference).
++ *
++ * Note that this can also be used to copy data between two domains
++ * via a third party if the source and destination domains had previously
++ * grant appropriate access to their pages to the third party.
++ *
++ * source_offset specifies an offset in the source frame, dest_offset
++ * the offset in the target frame and len specifies the number of
++ * bytes to be copied.
++ */
++
++#define _GNTCOPY_source_gref (0)
++#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref)
++#define _GNTCOPY_dest_gref (1)
++#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref)
++
++#define GNTTABOP_copy 5
++typedef struct gnttab_copy {
++ /* IN parameters. */
++ struct {
++ union {
++ grant_ref_t ref;
++ xen_pfn_t gmfn;
++ } u;
++ domid_t domid;
++ uint16_t offset;
++ } source, dest;
++ uint16_t len;
++ uint16_t flags; /* GNTCOPY_* */
++ /* OUT parameters. */
++ int16_t status;
++} gnttab_copy_t;
++DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t);
++
++
++/*
++ * Bitfield values for update_pin_status.flags.
++ */
++ /* Map the grant entry for access by I/O devices. */
++#define _GNTMAP_device_map (0)
++#define GNTMAP_device_map (1<<_GNTMAP_device_map)
++ /* Map the grant entry for access by host CPUs. */
++#define _GNTMAP_host_map (1)
++#define GNTMAP_host_map (1<<_GNTMAP_host_map)
++ /* Accesses to the granted frame will be restricted to read-only access. */
++#define _GNTMAP_readonly (2)
++#define GNTMAP_readonly (1<<_GNTMAP_readonly)
++ /*
++ * GNTMAP_host_map subflag:
++ * 0 => The host mapping is usable only by the guest OS.
++ * 1 => The host mapping is usable by guest OS + current application.
++ */
++#define _GNTMAP_application_map (3)
++#define GNTMAP_application_map (1<<_GNTMAP_application_map)
++
++ /*
++ * GNTMAP_contains_pte subflag:
++ * 0 => This map request contains a host virtual address.
++ * 1 => This map request contains the machine addess of the PTE to update.
++ */
++#define _GNTMAP_contains_pte (4)
++#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte)
++
++/*
++ * Values for error status returns. All errors are -ve.
++ */
++#define GNTST_okay (0) /* Normal return. */
++#define GNTST_general_error (-1) /* General undefined error. */
++#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */
++#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */
++#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */
++#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */
++#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/
++#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */
++#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */
++#define GNTST_bad_page (-9) /* Specified page was invalid for op. */
++#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary */
++
++#define GNTTABOP_error_msgs { \
++ "okay", \
++ "undefined error", \
++ "unrecognised domain id", \
++ "invalid grant reference", \
++ "invalid mapping handle", \
++ "invalid virtual address", \
++ "invalid device address", \
++ "no spare translation slot in the I/O MMU", \
++ "permission denied", \
++ "bad page", \
++ "copy arguments cross page boundary" \
++}
++
++#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/hvm/e820.h linux-2.6.18-xen/include/xen/interface/hvm/e820.h
+--- linux-2.6.18.1/include/xen/interface/hvm/e820.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/hvm/e820.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,32 @@
++#ifndef __XEN_PUBLIC_HVM_E820_H__
++#define __XEN_PUBLIC_HVM_E820_H__
++
++/* PC BIOS standard E820 types. */
++#define E820_RAM 1
++#define E820_RESERVED 2
++#define E820_ACPI 3
++#define E820_NVS 4
++
++/* Xen HVM extended E820 types. */
++#define E820_IO 16
++#define E820_SHARED_PAGE 17
++#define E820_XENSTORE 18
++#define E820_BUFFERED_IO 19
++
++/* E820 location in HVM virtual address space. */
++#define E820_MAP_PAGE 0x00090000
++#define E820_MAP_NR_OFFSET 0x000001E8
++#define E820_MAP_OFFSET 0x000002D0
++
++struct e820entry {
++ uint64_t addr;
++ uint64_t size;
++ uint32_t type;
++} __attribute__((packed));
++
++#define HVM_BELOW_4G_RAM_END 0xF0000000
++
++#define HVM_BELOW_4G_MMIO_START HVM_BELOW_4G_RAM_END
++#define HVM_BELOW_4G_MMIO_LENGTH ((1ULL << 32) - HVM_BELOW_4G_MMIO_START)
++
++#endif /* __XEN_PUBLIC_HVM_E820_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/hvm/hvm_info_table.h linux-2.6.18-xen/include/xen/interface/hvm/hvm_info_table.h
+--- linux-2.6.18.1/include/xen/interface/hvm/hvm_info_table.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/hvm/hvm_info_table.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,22 @@
++/******************************************************************************
++ * hvm/hvm_info_table.h
++ *
++ * HVM parameter and information table, written into guest memory map.
++ */
++
++#ifndef __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__
++#define __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__
++
++#define HVM_INFO_PFN 0x09F
++#define HVM_INFO_OFFSET 0x800
++#define HVM_INFO_PADDR ((HVM_INFO_PFN << 12) + HVM_INFO_OFFSET)
++
++struct hvm_info_table {
++ char signature[8]; /* "HVM INFO" */
++ uint32_t length;
++ uint8_t checksum;
++ uint8_t acpi_enabled;
++ uint32_t nr_vcpus;
++};
++
++#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/hvm/ioreq.h linux-2.6.18-xen/include/xen/interface/hvm/ioreq.h
+--- linux-2.6.18.1/include/xen/interface/hvm/ioreq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/hvm/ioreq.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,99 @@
++/*
++ * ioreq.h: I/O request definitions for device models
++ * Copyright (c) 2004, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ *
++ */
++
++#ifndef _IOREQ_H_
++#define _IOREQ_H_
++
++#define IOREQ_READ 1
++#define IOREQ_WRITE 0
++
++#define STATE_INVALID 0
++#define STATE_IOREQ_READY 1
++#define STATE_IOREQ_INPROCESS 2
++#define STATE_IORESP_READY 3
++
++#define IOREQ_TYPE_PIO 0 /* pio */
++#define IOREQ_TYPE_COPY 1 /* mmio ops */
++#define IOREQ_TYPE_AND 2
++#define IOREQ_TYPE_OR 3
++#define IOREQ_TYPE_XOR 4
++#define IOREQ_TYPE_XCHG 5
++
++/*
++ * VMExit dispatcher should cooperate with instruction decoder to
++ * prepare this structure and notify service OS and DM by sending
++ * virq
++ */
++struct ioreq {
++ uint64_t addr; /* physical address */
++ uint64_t size; /* size in bytes */
++ uint64_t count; /* for rep prefixes */
++ union {
++ uint64_t data; /* data */
++ void *pdata; /* pointer to data */
++ } u;
++ uint8_t state:4;
++ uint8_t pdata_valid:1; /* if 1, use pdata above */
++ uint8_t dir:1; /* 1=read, 0=write */
++ uint8_t df:1;
++ uint8_t type; /* I/O type */
++ uint64_t io_count; /* How many IO done on a vcpu */
++};
++typedef struct ioreq ioreq_t;
++
++struct global_iodata {
++ uint16_t pic_elcr;
++ uint16_t pic_irr;
++ uint16_t pic_last_irr;
++ uint16_t pic_clear_irr;
++};
++typedef struct global_iodata global_iodata_t;
++
++struct vcpu_iodata {
++ struct ioreq vp_ioreq;
++ /* Event channel port */
++ unsigned int vp_eport; /* VMX vcpu uses this to notify DM */
++};
++typedef struct vcpu_iodata vcpu_iodata_t;
++
++struct shared_iopage {
++ struct global_iodata sp_global;
++ struct vcpu_iodata vcpu_iodata[1];
++};
++typedef struct shared_iopage shared_iopage_t;
++
++#define IOREQ_BUFFER_SLOT_NUM 80
++struct buffered_iopage {
++ unsigned long read_pointer;
++ unsigned long write_pointer;
++ ioreq_t ioreq[IOREQ_BUFFER_SLOT_NUM];
++}; /* sizeof this structure must be in one page */
++typedef struct buffered_iopage buffered_iopage_t;
++
++#endif /* _IOREQ_H_ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/hvm/params.h linux-2.6.18-xen/include/xen/interface/hvm/params.h
+--- linux-2.6.18.1/include/xen/interface/hvm/params.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/hvm/params.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,24 @@
++#ifndef __XEN_PUBLIC_HVM_PARAMS_H__
++#define __XEN_PUBLIC_HVM_PARAMS_H__
++
++/* Parameter space. */
++#define HVM_PARAM_CALLBACK_IRQ 0
++#define HVM_PARAM_STORE_PFN 1
++#define HVM_PARAM_STORE_EVTCHN 2
++#define HVM_PARAM_APIC_ENABLED 3
++#define HVM_PARAM_PAE_ENABLED 4
++#define HVM_NR_PARAMS 5
++
++/* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */
++#define HVMOP_set_param 0
++#define HVMOP_get_param 1
++
++struct xen_hvm_param {
++ domid_t domid; /* IN */
++ uint32_t index; /* IN */
++ uint64_t value; /* IN/OUT */
++};
++typedef struct xen_hvm_param xen_hvm_param_t;
++DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t);
++
++#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/hvm/vmx_assist.h linux-2.6.18-xen/include/xen/interface/hvm/vmx_assist.h
+--- linux-2.6.18.1/include/xen/interface/hvm/vmx_assist.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/hvm/vmx_assist.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,98 @@
++/*
++ * vmx_assist.h: Context definitions for the VMXASSIST world switch.
++ *
++ * Leendert van Doorn, leendert at watson.ibm.com
++ * Copyright (c) 2005, International Business Machines Corporation.
++ */
++
++#ifndef _VMX_ASSIST_H_
++#define _VMX_ASSIST_H_
++
++#define VMXASSIST_BASE 0xD0000
++#define VMXASSIST_MAGIC 0x17101966
++#define VMXASSIST_MAGIC_OFFSET (VMXASSIST_BASE+8)
++
++#define VMXASSIST_NEW_CONTEXT (VMXASSIST_BASE + 12)
++#define VMXASSIST_OLD_CONTEXT (VMXASSIST_NEW_CONTEXT + 4)
++
++#ifndef __ASSEMBLY__
++
++union vmcs_arbytes {
++ struct arbyte_fields {
++ unsigned int seg_type : 4,
++ s : 1,
++ dpl : 2,
++ p : 1,
++ reserved0 : 4,
++ avl : 1,
++ reserved1 : 1,
++ default_ops_size: 1,
++ g : 1,
++ null_bit : 1,
++ reserved2 : 15;
++ } fields;
++ unsigned int bytes;
++};
++
++/*
++ * World switch state
++ */
++struct vmx_assist_context {
++ uint32_t eip; /* execution pointer */
++ uint32_t esp; /* stack pointer */
++ uint32_t eflags; /* flags register */
++ uint32_t cr0;
++ uint32_t cr3; /* page table directory */
++ uint32_t cr4;
++ uint32_t idtr_limit; /* idt */
++ uint32_t idtr_base;
++ uint32_t gdtr_limit; /* gdt */
++ uint32_t gdtr_base;
++ uint32_t cs_sel; /* cs selector */
++ uint32_t cs_limit;
++ uint32_t cs_base;
++ union vmcs_arbytes cs_arbytes;
++ uint32_t ds_sel; /* ds selector */
++ uint32_t ds_limit;
++ uint32_t ds_base;
++ union vmcs_arbytes ds_arbytes;
++ uint32_t es_sel; /* es selector */
++ uint32_t es_limit;
++ uint32_t es_base;
++ union vmcs_arbytes es_arbytes;
++ uint32_t ss_sel; /* ss selector */
++ uint32_t ss_limit;
++ uint32_t ss_base;
++ union vmcs_arbytes ss_arbytes;
++ uint32_t fs_sel; /* fs selector */
++ uint32_t fs_limit;
++ uint32_t fs_base;
++ union vmcs_arbytes fs_arbytes;
++ uint32_t gs_sel; /* gs selector */
++ uint32_t gs_limit;
++ uint32_t gs_base;
++ union vmcs_arbytes gs_arbytes;
++ uint32_t tr_sel; /* task selector */
++ uint32_t tr_limit;
++ uint32_t tr_base;
++ union vmcs_arbytes tr_arbytes;
++ uint32_t ldtr_sel; /* ldtr selector */
++ uint32_t ldtr_limit;
++ uint32_t ldtr_base;
++ union vmcs_arbytes ldtr_arbytes;
++};
++typedef struct vmx_assist_context vmx_assist_context_t;
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _VMX_ASSIST_H_ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/blkif.h linux-2.6.18-xen/include/xen/interface/io/blkif.h
+--- linux-2.6.18.1/include/xen/interface/io/blkif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/blkif.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,87 @@
++/******************************************************************************
++ * blkif.h
++ *
++ * Unified block-device I/O interface for Xen guest OSes.
++ *
++ * Copyright (c) 2003-2004, Keir Fraser
++ */
++
++#ifndef __XEN_PUBLIC_IO_BLKIF_H__
++#define __XEN_PUBLIC_IO_BLKIF_H__
++
++#include "ring.h"
++#include "../grant_table.h"
++
++/*
++ * Front->back notifications: When enqueuing a new request, sending a
++ * notification can be made conditional on req_event (i.e., the generic
++ * hold-off mechanism provided by the ring macros). Backends must set
++ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()).
++ *
++ * Back->front notifications: When enqueuing a new response, sending a
++ * notification can be made conditional on rsp_event (i.e., the generic
++ * hold-off mechanism provided by the ring macros). Frontends must set
++ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()).
++ */
++
++#ifndef blkif_vdev_t
++#define blkif_vdev_t uint16_t
++#endif
++#define blkif_sector_t uint64_t
++
++#define BLKIF_OP_READ 0
++#define BLKIF_OP_WRITE 1
++
++/*
++ * Maximum scatter/gather segments per request.
++ * This is carefully chosen so that sizeof(blkif_ring_t) <= PAGE_SIZE.
++ * NB. This could be 12 if the ring indexes weren't stored in the same page.
++ */
++#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
++
++struct blkif_request {
++ uint8_t operation; /* BLKIF_OP_??? */
++ uint8_t nr_segments; /* number of segments */
++ blkif_vdev_t handle; /* only for read/write requests */
++ uint64_t id; /* private guest value, echoed in resp */
++ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
++ struct blkif_request_segment {
++ grant_ref_t gref; /* reference to I/O buffer frame */
++ /* @first_sect: first sector in frame to transfer (inclusive). */
++ /* @last_sect: last sector in frame to transfer (inclusive). */
++ uint8_t first_sect, last_sect;
++ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++};
++typedef struct blkif_request blkif_request_t;
++
++struct blkif_response {
++ uint64_t id; /* copied from request */
++ uint8_t operation; /* copied from request */
++ int16_t status; /* BLKIF_RSP_??? */
++};
++typedef struct blkif_response blkif_response_t;
++
++#define BLKIF_RSP_ERROR -1 /* non-specific 'error' */
++#define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */
++
++/*
++ * Generate blkif ring structures and types.
++ */
++
++DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
++
++#define VDISK_CDROM 0x1
++#define VDISK_REMOVABLE 0x2
++#define VDISK_READONLY 0x4
++
++#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/console.h linux-2.6.18-xen/include/xen/interface/io/console.h
+--- linux-2.6.18.1/include/xen/interface/io/console.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/console.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,33 @@
++/******************************************************************************
++ * console.h
++ *
++ * Console I/O interface for Xen guest OSes.
++ *
++ * Copyright (c) 2005, Keir Fraser
++ */
++
++#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
++#define __XEN_PUBLIC_IO_CONSOLE_H__
++
++typedef uint32_t XENCONS_RING_IDX;
++
++#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
++
++struct xencons_interface {
++ char in[1024];
++ char out[2048];
++ XENCONS_RING_IDX in_cons, in_prod;
++ XENCONS_RING_IDX out_cons, out_prod;
++};
++
++#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/netif.h linux-2.6.18-xen/include/xen/interface/io/netif.h
+--- linux-2.6.18.1/include/xen/interface/io/netif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/netif.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,166 @@
++/******************************************************************************
++ * netif.h
++ *
++ * Unified network-device I/O interface for Xen guest OSes.
++ *
++ * Copyright (c) 2003-2004, Keir Fraser
++ */
++
++#ifndef __XEN_PUBLIC_IO_NETIF_H__
++#define __XEN_PUBLIC_IO_NETIF_H__
++
++#include "ring.h"
++#include "../grant_table.h"
++
++/*
++ * Notifications after enqueuing any type of message should be conditional on
++ * the appropriate req_event or rsp_event field in the shared ring.
++ * If the client sends notification for rx requests then it should specify
++ * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume
++ * that it cannot safely queue packets (as it may not be kicked to send them).
++ */
++
++/*
++ * This is the 'wire' format for packets:
++ * Request 1: netif_tx_request -- NETTXF_* (any flags)
++ * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info)
++ * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE)
++ * Request 4: netif_tx_request -- NETTXF_more_data
++ * Request 5: netif_tx_request -- NETTXF_more_data
++ * ...
++ * Request N: netif_tx_request -- 0
++ */
++
++/* Protocol checksum field is blank in the packet (hardware offload)? */
++#define _NETTXF_csum_blank (0)
++#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank)
++
++/* Packet data has been validated against protocol checksum. */
++#define _NETTXF_data_validated (1)
++#define NETTXF_data_validated (1U<<_NETTXF_data_validated)
++
++/* Packet continues in the next request descriptor. */
++#define _NETTXF_more_data (2)
++#define NETTXF_more_data (1U<<_NETTXF_more_data)
++
++/* Packet to be followed by extra descriptor(s). */
++#define _NETTXF_extra_info (3)
++#define NETTXF_extra_info (1U<<_NETTXF_extra_info)
++
++struct netif_tx_request {
++ grant_ref_t gref; /* Reference to buffer page */
++ uint16_t offset; /* Offset within buffer page */
++ uint16_t flags; /* NETTXF_* */
++ uint16_t id; /* Echoed in response message. */
++ uint16_t size; /* Packet size in bytes. */
++};
++typedef struct netif_tx_request netif_tx_request_t;
++
++/* Types of netif_extra_info descriptors. */
++#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
++#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
++#define XEN_NETIF_EXTRA_TYPE_MAX (2)
++
++/* netif_extra_info flags. */
++#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
++#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
++
++/* GSO types - only TCPv4 currently supported. */
++#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
++
++/*
++ * This structure needs to fit within both netif_tx_request and
++ * netif_rx_response for compatibility.
++ */
++struct netif_extra_info {
++ uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */
++ uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */
++
++ union {
++ struct {
++ /*
++ * Maximum payload size of each segment. For example, for TCP this
++ * is just the path MSS.
++ */
++ uint16_t size;
++
++ /*
++ * GSO type. This determines the protocol of the packet and any
++ * extra features required to segment the packet properly.
++ */
++ uint8_t type; /* XEN_NETIF_GSO_TYPE_* */
++
++ /* Future expansion. */
++ uint8_t pad;
++
++ /*
++ * GSO features. This specifies any extra GSO features required
++ * to process this packet, such as ECN support for TCPv4.
++ */
++ uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
++ } gso;
++
++ uint16_t pad[3];
++ } u;
++};
++
++struct netif_tx_response {
++ uint16_t id;
++ int16_t status; /* NETIF_RSP_* */
++};
++typedef struct netif_tx_response netif_tx_response_t;
++
++struct netif_rx_request {
++ uint16_t id; /* Echoed in response message. */
++ grant_ref_t gref; /* Reference to incoming granted frame */
++};
++typedef struct netif_rx_request netif_rx_request_t;
++
++/* Packet data has been validated against protocol checksum. */
++#define _NETRXF_data_validated (0)
++#define NETRXF_data_validated (1U<<_NETRXF_data_validated)
++
++/* Protocol checksum field is blank in the packet (hardware offload)? */
++#define _NETRXF_csum_blank (1)
++#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank)
++
++/* Packet continues in the next request descriptor. */
++#define _NETRXF_more_data (2)
++#define NETRXF_more_data (1U<<_NETRXF_more_data)
++
++/* Packet to be followed by extra descriptor(s). */
++#define _NETRXF_extra_info (3)
++#define NETRXF_extra_info (1U<<_NETRXF_extra_info)
++
++struct netif_rx_response {
++ uint16_t id;
++ uint16_t offset; /* Offset in page of start of received packet */
++ uint16_t flags; /* NETRXF_* */
++ int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
++};
++typedef struct netif_rx_response netif_rx_response_t;
++
++/*
++ * Generate netif ring structures and types.
++ */
++
++DEFINE_RING_TYPES(netif_tx, struct netif_tx_request, struct netif_tx_response);
++DEFINE_RING_TYPES(netif_rx, struct netif_rx_request, struct netif_rx_response);
++
++#define NETIF_RSP_DROPPED -2
++#define NETIF_RSP_ERROR -1
++#define NETIF_RSP_OKAY 0
++/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
++#define NETIF_RSP_NULL 1
++
++#endif
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/pciif.h linux-2.6.18-xen/include/xen/interface/io/pciif.h
+--- linux-2.6.18.1/include/xen/interface/io/pciif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/pciif.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,55 @@
++/*
++ * PCI Backend/Frontend Common Data Structures & Macros
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#ifndef __XEN_PCI_COMMON_H__
++#define __XEN_PCI_COMMON_H__
++
++/* Be sure to bump this number if you change this file */
++#define XEN_PCI_MAGIC "7"
++
++/* xen_pci_sharedinfo flags */
++#define _XEN_PCIF_active (0)
++#define XEN_PCIF_active (1<<_XEN_PCI_active)
++
++/* xen_pci_op commands */
++#define XEN_PCI_OP_conf_read (0)
++#define XEN_PCI_OP_conf_write (1)
++
++/* xen_pci_op error numbers */
++#define XEN_PCI_ERR_success (0)
++#define XEN_PCI_ERR_dev_not_found (-1)
++#define XEN_PCI_ERR_invalid_offset (-2)
++#define XEN_PCI_ERR_access_denied (-3)
++#define XEN_PCI_ERR_not_implemented (-4)
++/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
++#define XEN_PCI_ERR_op_failed (-5)
++
++struct xen_pci_op {
++ /* IN: what action to perform: XEN_PCI_OP_* */
++ uint32_t cmd;
++
++ /* OUT: will contain an error number (if any) from errno.h */
++ int32_t err;
++
++ /* IN: which device to touch */
++ uint32_t domain; /* PCI Domain/Segment */
++ uint32_t bus;
++ uint32_t devfn;
++
++ /* IN: which configuration registers to touch */
++ int32_t offset;
++ int32_t size;
++
++ /* IN/OUT: Contains the result after a READ or the value to WRITE */
++ uint32_t value;
++};
++
++struct xen_pci_sharedinfo {
++ /* flags - XEN_PCIF_* */
++ uint32_t flags;
++ struct xen_pci_op op;
++};
++
++#endif /* __XEN_PCI_COMMON_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/ring.h linux-2.6.18-xen/include/xen/interface/io/ring.h
+--- linux-2.6.18.1/include/xen/interface/io/ring.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/ring.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,273 @@
++/******************************************************************************
++ * ring.h
++ *
++ * Shared producer-consumer ring macros.
++ *
++ * Tim Deegan and Andrew Warfield November 2004.
++ */
++
++#ifndef __XEN_PUBLIC_IO_RING_H__
++#define __XEN_PUBLIC_IO_RING_H__
++
++typedef unsigned int RING_IDX;
++
++/* Round a 32-bit unsigned constant down to the nearest power of two. */
++#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1))
++#define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x))
++#define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x))
++#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x))
++#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
++
++/*
++ * Calculate size of a shared ring, given the total available space for the
++ * ring and indexes (_sz), and the name tag of the request/response structure.
++ * A ring contains as many entries as will fit, rounded down to the nearest
++ * power of two (so we can mask with (size-1) to loop around).
++ */
++#define __RING_SIZE(_s, _sz) \
++ (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
++
++/*
++ * Macros to make the correct C datatypes for a new kind of ring.
++ *
++ * To make a new ring datatype, you need to have two message structures,
++ * let's say request_t, and response_t already defined.
++ *
++ * In a header where you want the ring datatype declared, you then do:
++ *
++ * DEFINE_RING_TYPES(mytag, request_t, response_t);
++ *
++ * These expand out to give you a set of types, as you can see below.
++ * The most important of these are:
++ *
++ * mytag_sring_t - The shared ring.
++ * mytag_front_ring_t - The 'front' half of the ring.
++ * mytag_back_ring_t - The 'back' half of the ring.
++ *
++ * To initialize a ring in your code you need to know the location and size
++ * of the shared memory area (PAGE_SIZE, for instance). To initialise
++ * the front half:
++ *
++ * mytag_front_ring_t front_ring;
++ * SHARED_RING_INIT((mytag_sring_t *)shared_page);
++ * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
++ *
++ * Initializing the back follows similarly (note that only the front
++ * initializes the shared ring):
++ *
++ * mytag_back_ring_t back_ring;
++ * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
++ */
++
++#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \
++ \
++/* Shared ring entry */ \
++union __name##_sring_entry { \
++ __req_t req; \
++ __rsp_t rsp; \
++}; \
++ \
++/* Shared ring page */ \
++struct __name##_sring { \
++ RING_IDX req_prod, req_event; \
++ RING_IDX rsp_prod, rsp_event; \
++ uint8_t pad[48]; \
++ union __name##_sring_entry ring[1]; /* variable-length */ \
++}; \
++ \
++/* "Front" end's private variables */ \
++struct __name##_front_ring { \
++ RING_IDX req_prod_pvt; \
++ RING_IDX rsp_cons; \
++ unsigned int nr_ents; \
++ struct __name##_sring *sring; \
++}; \
++ \
++/* "Back" end's private variables */ \
++struct __name##_back_ring { \
++ RING_IDX rsp_prod_pvt; \
++ RING_IDX req_cons; \
++ unsigned int nr_ents; \
++ struct __name##_sring *sring; \
++}; \
++ \
++/* Syntactic sugar */ \
++typedef struct __name##_sring __name##_sring_t; \
++typedef struct __name##_front_ring __name##_front_ring_t; \
++typedef struct __name##_back_ring __name##_back_ring_t
++
++/*
++ * Macros for manipulating rings.
++ *
++ * FRONT_RING_whatever works on the "front end" of a ring: here
++ * requests are pushed on to the ring and responses taken off it.
++ *
++ * BACK_RING_whatever works on the "back end" of a ring: here
++ * requests are taken off the ring and responses put on.
++ *
++ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
++ * This is OK in 1-for-1 request-response situations where the
++ * requestor (front end) never has more than RING_SIZE()-1
++ * outstanding requests.
++ */
++
++/* Initialising empty rings */
++#define SHARED_RING_INIT(_s) do { \
++ (_s)->req_prod = (_s)->rsp_prod = 0; \
++ (_s)->req_event = (_s)->rsp_event = 1; \
++ memset((_s)->pad, 0, sizeof((_s)->pad)); \
++} while(0)
++
++#define FRONT_RING_INIT(_r, _s, __size) do { \
++ (_r)->req_prod_pvt = 0; \
++ (_r)->rsp_cons = 0; \
++ (_r)->nr_ents = __RING_SIZE(_s, __size); \
++ (_r)->sring = (_s); \
++} while (0)
++
++#define BACK_RING_INIT(_r, _s, __size) do { \
++ (_r)->rsp_prod_pvt = 0; \
++ (_r)->req_cons = 0; \
++ (_r)->nr_ents = __RING_SIZE(_s, __size); \
++ (_r)->sring = (_s); \
++} while (0)
++
++/* Initialize to existing shared indexes -- for recovery */
++#define FRONT_RING_ATTACH(_r, _s, __size) do { \
++ (_r)->sring = (_s); \
++ (_r)->req_prod_pvt = (_s)->req_prod; \
++ (_r)->rsp_cons = (_s)->rsp_prod; \
++ (_r)->nr_ents = __RING_SIZE(_s, __size); \
++} while (0)
++
++#define BACK_RING_ATTACH(_r, _s, __size) do { \
++ (_r)->sring = (_s); \
++ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \
++ (_r)->req_cons = (_s)->req_prod; \
++ (_r)->nr_ents = __RING_SIZE(_s, __size); \
++} while (0)
++
++/* How big is this ring? */
++#define RING_SIZE(_r) \
++ ((_r)->nr_ents)
++
++/* Number of free requests (for use on front side only). */
++#define RING_FREE_REQUESTS(_r) \
++ (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
++
++/* Test if there is an empty slot available on the front ring.
++ * (This is only meaningful from the front. )
++ */
++#define RING_FULL(_r) \
++ (RING_FREE_REQUESTS(_r) == 0)
++
++/* Test if there are outstanding messages to be processed on a ring. */
++#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
++ ((_r)->sring->rsp_prod - (_r)->rsp_cons)
++
++#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
++ ({ \
++ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
++ unsigned int rsp = RING_SIZE(_r) - \
++ ((_r)->req_cons - (_r)->rsp_prod_pvt); \
++ req < rsp ? req : rsp; \
++ })
++
++/* Direct access to individual ring elements, by index. */
++#define RING_GET_REQUEST(_r, _idx) \
++ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
++
++#define RING_GET_RESPONSE(_r, _idx) \
++ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
++
++/* Loop termination condition: Would the specified index overflow the ring? */
++#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \
++ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
++
++#define RING_PUSH_REQUESTS(_r) do { \
++ wmb(); /* back sees requests /before/ updated producer index */ \
++ (_r)->sring->req_prod = (_r)->req_prod_pvt; \
++} while (0)
++
++#define RING_PUSH_RESPONSES(_r) do { \
++ wmb(); /* front sees responses /before/ updated producer index */ \
++ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
++} while (0)
++
++/*
++ * Notification hold-off (req_event and rsp_event):
++ *
++ * When queueing requests or responses on a shared ring, it may not always be
++ * necessary to notify the remote end. For example, if requests are in flight
++ * in a backend, the front may be able to queue further requests without
++ * notifying the back (if the back checks for new requests when it queues
++ * responses).
++ *
++ * When enqueuing requests or responses:
++ *
++ * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
++ * is a boolean return value. True indicates that the receiver requires an
++ * asynchronous notification.
++ *
++ * After dequeuing requests or responses (before sleeping the connection):
++ *
++ * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
++ * The second argument is a boolean return value. True indicates that there
++ * are pending messages on the ring (i.e., the connection should not be put
++ * to sleep).
++ *
++ * These macros will set the req_event/rsp_event field to trigger a
++ * notification on the very next message that is enqueued. If you want to
++ * create batches of work (i.e., only receive a notification after several
++ * messages have been enqueued) then you will need to create a customised
++ * version of the FINAL_CHECK macro in your own code, which sets the event
++ * field appropriately.
++ */
++
++#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \
++ RING_IDX __old = (_r)->sring->req_prod; \
++ RING_IDX __new = (_r)->req_prod_pvt; \
++ wmb(); /* back sees requests /before/ updated producer index */ \
++ (_r)->sring->req_prod = __new; \
++ mb(); /* back sees new requests /before/ we check req_event */ \
++ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \
++ (RING_IDX)(__new - __old)); \
++} while (0)
++
++#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \
++ RING_IDX __old = (_r)->sring->rsp_prod; \
++ RING_IDX __new = (_r)->rsp_prod_pvt; \
++ wmb(); /* front sees responses /before/ updated producer index */ \
++ (_r)->sring->rsp_prod = __new; \
++ mb(); /* front sees new responses /before/ we check rsp_event */ \
++ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \
++ (RING_IDX)(__new - __old)); \
++} while (0)
++
++#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \
++ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
++ if (_work_to_do) break; \
++ (_r)->sring->req_event = (_r)->req_cons + 1; \
++ mb(); \
++ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
++} while (0)
++
++#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \
++ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
++ if (_work_to_do) break; \
++ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \
++ mb(); \
++ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
++} while (0)
++
++#endif /* __XEN_PUBLIC_IO_RING_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/tpmif.h linux-2.6.18-xen/include/xen/interface/io/tpmif.h
+--- linux-2.6.18.1/include/xen/interface/io/tpmif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/tpmif.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,59 @@
++/******************************************************************************
++ * tpmif.h
++ *
++ * TPM I/O interface for Xen guest OSes.
++ *
++ * Copyright (c) 2005, IBM Corporation
++ *
++ * Author: Stefan Berger, stefanb at us.ibm.com
++ * Grant table support: Mahadevan Gomathisankaran
++ *
++ * This code has been derived from tools/libxc/xen/io/netif.h
++ *
++ * Copyright (c) 2003-2004, Keir Fraser
++ */
++
++#ifndef __XEN_PUBLIC_IO_TPMIF_H__
++#define __XEN_PUBLIC_IO_TPMIF_H__
++
++#include "../grant_table.h"
++
++struct tpmif_tx_request {
++ unsigned long addr; /* Machine address of packet. */
++ grant_ref_t ref; /* grant table access reference */
++ uint16_t unused;
++ uint16_t size; /* Packet size in bytes. */
++};
++typedef struct tpmif_tx_request tpmif_tx_request_t;
++
++/*
++ * The TPMIF_TX_RING_SIZE defines the number of pages the
++ * front-end and backend can exchange (= size of array).
++ */
++typedef uint32_t TPMIF_RING_IDX;
++
++#define TPMIF_TX_RING_SIZE 10
++
++/* This structure must fit in a memory page. */
++
++struct tpmif_ring {
++ struct tpmif_tx_request req;
++};
++typedef struct tpmif_ring tpmif_ring_t;
++
++struct tpmif_tx_interface {
++ struct tpmif_ring ring[TPMIF_TX_RING_SIZE];
++};
++typedef struct tpmif_tx_interface tpmif_tx_interface_t;
++
++#endif
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/xenbus.h linux-2.6.18-xen/include/xen/interface/io/xenbus.h
+--- linux-2.6.18.1/include/xen/interface/io/xenbus.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/xenbus.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,45 @@
++/*****************************************************************************
++ * xenbus.h
++ *
++ * Xenbus protocol details.
++ *
++ * Copyright (C) 2005 XenSource Ltd.
++ */
++
++#ifndef _XEN_PUBLIC_IO_XENBUS_H
++#define _XEN_PUBLIC_IO_XENBUS_H
++
++/*
++ * The state of either end of the Xenbus, i.e. the current communication
++ * status of initialisation across the bus. States here imply nothing about
++ * the state of the connection between the driver and the kernel's device
++ * layers.
++ */
++enum xenbus_state {
++ XenbusStateUnknown = 0,
++
++ XenbusStateInitialising = 1,
++
++ /*
++ * InitWait: Finished early initialisation but waiting for information
++ * from the peer or hotplug scripts.
++ */
++ XenbusStateInitWait = 2,
++
++ /*
++ * Initialised: Waiting for a connection from the peer.
++ */
++ XenbusStateInitialised = 3,
++
++ XenbusStateConnected = 4,
++
++ /*
++ * Closing: The device is being closed due to an error or an unplug event.
++ */
++ XenbusStateClosing = 5,
++
++ XenbusStateClosed = 6
++};
++typedef enum xenbus_state XenbusState;
++
++#endif /* _XEN_PUBLIC_IO_XENBUS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/io/xs_wire.h linux-2.6.18-xen/include/xen/interface/io/xs_wire.h
+--- linux-2.6.18.1/include/xen/interface/io/xs_wire.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/io/xs_wire.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * Details of the "wire" protocol between Xen Store Daemon and client
++ * library or guest kernel.
++ * Copyright (C) 2005 Rusty Russell IBM Corporation
++ */
++
++#ifndef _XS_WIRE_H
++#define _XS_WIRE_H
++
++enum xsd_sockmsg_type
++{
++ XS_DEBUG,
++ XS_DIRECTORY,
++ XS_READ,
++ XS_GET_PERMS,
++ XS_WATCH,
++ XS_UNWATCH,
++ XS_TRANSACTION_START,
++ XS_TRANSACTION_END,
++ XS_INTRODUCE,
++ XS_RELEASE,
++ XS_GET_DOMAIN_PATH,
++ XS_WRITE,
++ XS_MKDIR,
++ XS_RM,
++ XS_SET_PERMS,
++ XS_WATCH_EVENT,
++ XS_ERROR,
++ XS_IS_DOMAIN_INTRODUCED
++};
++
++#define XS_WRITE_NONE "NONE"
++#define XS_WRITE_CREATE "CREATE"
++#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"
++
++/* We hand errors as strings, for portability. */
++struct xsd_errors
++{
++ int errnum;
++ const char *errstring;
++};
++#define XSD_ERROR(x) { x, #x }
++static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
++ XSD_ERROR(EINVAL),
++ XSD_ERROR(EACCES),
++ XSD_ERROR(EEXIST),
++ XSD_ERROR(EISDIR),
++ XSD_ERROR(ENOENT),
++ XSD_ERROR(ENOMEM),
++ XSD_ERROR(ENOSPC),
++ XSD_ERROR(EIO),
++ XSD_ERROR(ENOTEMPTY),
++ XSD_ERROR(ENOSYS),
++ XSD_ERROR(EROFS),
++ XSD_ERROR(EBUSY),
++ XSD_ERROR(EAGAIN),
++ XSD_ERROR(EISCONN)
++};
++
++struct xsd_sockmsg
++{
++ uint32_t type; /* XS_??? */
++ uint32_t req_id;/* Request identifier, echoed in daemon's response. */
++ uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */
++ uint32_t len; /* Length of data following this. */
++
++ /* Generally followed by nul-terminated string(s). */
++};
++
++enum xs_watch_type
++{
++ XS_WATCH_PATH = 0,
++ XS_WATCH_TOKEN
++};
++
++/* Inter-domain shared memory communications. */
++#define XENSTORE_RING_SIZE 1024
++typedef uint32_t XENSTORE_RING_IDX;
++#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))
++struct xenstore_domain_interface {
++ char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */
++ char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
++ XENSTORE_RING_IDX req_cons, req_prod;
++ XENSTORE_RING_IDX rsp_cons, rsp_prod;
++};
++
++#endif /* _XS_WIRE_H */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/memory.h linux-2.6.18-xen/include/xen/interface/memory.h
+--- linux-2.6.18.1/include/xen/interface/memory.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/memory.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,243 @@
++/******************************************************************************
++ * memory.h
++ *
++ * Memory reservation and information.
++ *
++ * Copyright (c) 2005, Keir Fraser <keir at xensource.com>
++ */
++
++#ifndef __XEN_PUBLIC_MEMORY_H__
++#define __XEN_PUBLIC_MEMORY_H__
++
++/*
++ * Increase or decrease the specified domain's memory reservation. Returns the
++ * number of extents successfully allocated or freed.
++ * arg == addr of struct xen_memory_reservation.
++ */
++#define XENMEM_increase_reservation 0
++#define XENMEM_decrease_reservation 1
++#define XENMEM_populate_physmap 6
++struct xen_memory_reservation {
++
++ /*
++ * XENMEM_increase_reservation:
++ * OUT: MFN (*not* GMFN) bases of extents that were allocated
++ * XENMEM_decrease_reservation:
++ * IN: GMFN bases of extents to free
++ * XENMEM_populate_physmap:
++ * IN: GPFN bases of extents to populate with memory
++ * OUT: GMFN bases of extents that were allocated
++ * (NB. This command also updates the mach_to_phys translation table)
++ */
++ XEN_GUEST_HANDLE(xen_pfn_t) extent_start;
++
++ /* Number of extents, and size/alignment of each (2^extent_order pages). */
++ xen_ulong_t nr_extents;
++ unsigned int extent_order;
++
++ /*
++ * Maximum # bits addressable by the user of the allocated region (e.g.,
++ * I/O devices often have a 32-bit limitation even in 64-bit systems). If
++ * zero then the user has no addressing restriction.
++ * This field is not used by XENMEM_decrease_reservation.
++ */
++ unsigned int address_bits;
++
++ /*
++ * Domain whose reservation is being changed.
++ * Unprivileged domains can specify only DOMID_SELF.
++ */
++ domid_t domid;
++};
++typedef struct xen_memory_reservation xen_memory_reservation_t;
++DEFINE_XEN_GUEST_HANDLE(xen_memory_reservation_t);
++
++/*
++ * An atomic exchange of memory pages. If return code is zero then
++ * @out.extent_list provides GMFNs of the newly-allocated memory.
++ * Returns zero on complete success, otherwise a negative error code.
++ * On complete success then always @nr_exchanged == @in.nr_extents.
++ * On partial success @nr_exchanged indicates how much work was done.
++ */
++#define XENMEM_exchange 11
++struct xen_memory_exchange {
++ /*
++ * [IN] Details of memory extents to be exchanged (GMFN bases).
++ * Note that @in.address_bits is ignored and unused.
++ */
++ struct xen_memory_reservation in;
++
++ /*
++ * [IN/OUT] Details of new memory extents.
++ * We require that:
++ * 1. @in.domid == @out.domid
++ * 2. @in.nr_extents << @in.extent_order ==
++ * @out.nr_extents << @out.extent_order
++ * 3. @in.extent_start and @out.extent_start lists must not overlap
++ * 4. @out.extent_start lists GPFN bases to be populated
++ * 5. @out.extent_start is overwritten with allocated GMFN bases
++ */
++ struct xen_memory_reservation out;
++
++ /*
++ * [OUT] Number of input extents that were successfully exchanged:
++ * 1. The first @nr_exchanged input extents were successfully
++ * deallocated.
++ * 2. The corresponding first entries in the output extent list correctly
++ * indicate the GMFNs that were successfully exchanged.
++ * 3. All other input and output extents are untouched.
++ * 4. If not all input exents are exchanged then the return code of this
++ * command will be non-zero.
++ * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
++ */
++ xen_ulong_t nr_exchanged;
++};
++typedef struct xen_memory_exchange xen_memory_exchange_t;
++DEFINE_XEN_GUEST_HANDLE(xen_memory_exchange_t);
++
++/*
++ * Returns the maximum machine frame number of mapped RAM in this system.
++ * This command always succeeds (it never returns an error code).
++ * arg == NULL.
++ */
++#define XENMEM_maximum_ram_page 2
++
++/*
++ * Returns the current or maximum memory reservation, in pages, of the
++ * specified domain (may be DOMID_SELF). Returns -ve errcode on failure.
++ * arg == addr of domid_t.
++ */
++#define XENMEM_current_reservation 3
++#define XENMEM_maximum_reservation 4
++
++/*
++ * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys
++ * mapping table. Architectures which do not have a m2p table do not implement
++ * this command.
++ * arg == addr of xen_machphys_mfn_list_t.
++ */
++#define XENMEM_machphys_mfn_list 5
++struct xen_machphys_mfn_list {
++ /*
++ * Size of the 'extent_start' array. Fewer entries will be filled if the
++ * machphys table is smaller than max_extents * 2MB.
++ */
++ unsigned int max_extents;
++
++ /*
++ * Pointer to buffer to fill with list of extent starts. If there are
++ * any large discontiguities in the machine address space, 2MB gaps in
++ * the machphys table will be represented by an MFN base of zero.
++ */
++ XEN_GUEST_HANDLE(xen_pfn_t) extent_start;
++
++ /*
++ * Number of extents written to the above array. This will be smaller
++ * than 'max_extents' if the machphys table is smaller than max_e * 2MB.
++ */
++ unsigned int nr_extents;
++};
++typedef struct xen_machphys_mfn_list xen_machphys_mfn_list_t;
++DEFINE_XEN_GUEST_HANDLE(xen_machphys_mfn_list_t);
++
++/*
++ * Returns the location in virtual address space of the machine_to_phys
++ * mapping table. Architectures which do not have a m2p table, or which do not
++ * map it by default into guest address space, do not implement this command.
++ * arg == addr of xen_machphys_mapping_t.
++ */
++#define XENMEM_machphys_mapping 12
++struct xen_machphys_mapping {
++ xen_ulong_t v_start, v_end; /* Start and end virtual addresses. */
++ xen_ulong_t max_mfn; /* Maximum MFN that can be looked up. */
++};
++typedef struct xen_machphys_mapping xen_machphys_mapping_t;
++DEFINE_XEN_GUEST_HANDLE(xen_machphys_mapping_t);
++
++/*
++ * Sets the GPFN at which a particular page appears in the specified guest's
++ * pseudophysical address space.
++ * arg == addr of xen_add_to_physmap_t.
++ */
++#define XENMEM_add_to_physmap 7
++struct xen_add_to_physmap {
++ /* Which domain to change the mapping for. */
++ domid_t domid;
++
++ /* Source mapping space. */
++#define XENMAPSPACE_shared_info 0 /* shared info page */
++#define XENMAPSPACE_grant_table 1 /* grant table page */
++ unsigned int space;
++
++ /* Index into source mapping space. */
++ xen_ulong_t idx;
++
++ /* GPFN where the source mapping page should appear. */
++ xen_pfn_t gpfn;
++};
++typedef struct xen_add_to_physmap xen_add_to_physmap_t;
++DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t);
++
++/*
++ * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
++ * code on failure. This call only works for auto-translated guests.
++ */
++#define XENMEM_translate_gpfn_list 8
++struct xen_translate_gpfn_list {
++ /* Which domain to translate for? */
++ domid_t domid;
++
++ /* Length of list. */
++ xen_ulong_t nr_gpfns;
++
++ /* List of GPFNs to translate. */
++ XEN_GUEST_HANDLE(xen_pfn_t) gpfn_list;
++
++ /*
++ * Output list to contain MFN translations. May be the same as the input
++ * list (in which case each input GPFN is overwritten with the output MFN).
++ */
++ XEN_GUEST_HANDLE(xen_pfn_t) mfn_list;
++};
++typedef struct xen_translate_gpfn_list xen_translate_gpfn_list_t;
++DEFINE_XEN_GUEST_HANDLE(xen_translate_gpfn_list_t);
++
++/*
++ * Returns the pseudo-physical memory map as it was when the domain
++ * was started.
++ */
++#define XENMEM_memory_map 9
++struct xen_memory_map {
++ /*
++ * On call the number of entries which can be stored in buffer. On
++ * return the number of entries which have been stored in
++ * buffer.
++ */
++ unsigned int nr_entries;
++
++ /*
++ * Entries in the buffer are in the same format as returned by the
++ * BIOS INT 0x15 EAX=0xE820 call.
++ */
++ XEN_GUEST_HANDLE(void) buffer;
++};
++typedef struct xen_memory_map xen_memory_map_t;
++DEFINE_XEN_GUEST_HANDLE(xen_memory_map_t);
++
++/*
++ * Returns the real physical memory map. Passes the same structure as
++ * XENMEM_memory_map.
++ */
++#define XENMEM_machine_memory_map 10
++
++#endif /* __XEN_PUBLIC_MEMORY_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/nmi.h linux-2.6.18-xen/include/xen/interface/nmi.h
+--- linux-2.6.18.1/include/xen/interface/nmi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/nmi.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,60 @@
++/******************************************************************************
++ * nmi.h
++ *
++ * NMI callback registration and reason codes.
++ *
++ * Copyright (c) 2005, Keir Fraser <keir at xensource.com>
++ */
++
++#ifndef __XEN_PUBLIC_NMI_H__
++#define __XEN_PUBLIC_NMI_H__
++
++/*
++ * NMI reason codes:
++ * Currently these are x86-specific, stored in arch_shared_info.nmi_reason.
++ */
++ /* I/O-check error reported via ISA port 0x61, bit 6. */
++#define _XEN_NMIREASON_io_error 0
++#define XEN_NMIREASON_io_error (1UL << _XEN_NMIREASON_io_error)
++ /* Parity error reported via ISA port 0x61, bit 7. */
++#define _XEN_NMIREASON_parity_error 1
++#define XEN_NMIREASON_parity_error (1UL << _XEN_NMIREASON_parity_error)
++ /* Unknown hardware-generated NMI. */
++#define _XEN_NMIREASON_unknown 2
++#define XEN_NMIREASON_unknown (1UL << _XEN_NMIREASON_unknown)
++
++/*
++ * long nmi_op(unsigned int cmd, void *arg)
++ * NB. All ops return zero on success, else a negative error code.
++ */
++
++/*
++ * Register NMI callback for this (calling) VCPU. Currently this only makes
++ * sense for domain 0, vcpu 0. All other callers will be returned EINVAL.
++ * arg == pointer to xennmi_callback structure.
++ */
++#define XENNMI_register_callback 0
++struct xennmi_callback {
++ unsigned long handler_address;
++ unsigned long pad;
++};
++typedef struct xennmi_callback xennmi_callback_t;
++DEFINE_XEN_GUEST_HANDLE(xennmi_callback_t);
++
++/*
++ * Deregister NMI callback for this (calling) VCPU.
++ * arg == NULL.
++ */
++#define XENNMI_unregister_callback 1
++
++#endif /* __XEN_PUBLIC_NMI_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/physdev.h linux-2.6.18-xen/include/xen/interface/physdev.h
+--- linux-2.6.18.1/include/xen/interface/physdev.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/physdev.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,149 @@
++
++#ifndef __XEN_PUBLIC_PHYSDEV_H__
++#define __XEN_PUBLIC_PHYSDEV_H__
++
++/*
++ * Prototype for this hypercall is:
++ * int physdev_op(int cmd, void *args)
++ * @cmd == PHYSDEVOP_??? (physdev operation).
++ * @args == Operation-specific extra arguments (NULL if none).
++ */
++
++/*
++ * Notify end-of-interrupt (EOI) for the specified IRQ.
++ * @arg == pointer to physdev_eoi structure.
++ */
++#define PHYSDEVOP_eoi 12
++struct physdev_eoi {
++ /* IN */
++ uint32_t irq;
++};
++typedef struct physdev_eoi physdev_eoi_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t);
++
++/*
++ * Query the status of an IRQ line.
++ * @arg == pointer to physdev_irq_status_query structure.
++ */
++#define PHYSDEVOP_irq_status_query 5
++struct physdev_irq_status_query {
++ /* IN */
++ uint32_t irq;
++ /* OUT */
++ uint32_t flags; /* XENIRQSTAT_* */
++};
++typedef struct physdev_irq_status_query physdev_irq_status_query_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_irq_status_query_t);
++
++/* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */
++#define _XENIRQSTAT_needs_eoi (0)
++#define XENIRQSTAT_needs_eoi (1U<<_XENIRQSTAT_needs_eoi)
++
++/* IRQ shared by multiple guests? */
++#define _XENIRQSTAT_shared (1)
++#define XENIRQSTAT_shared (1U<<_XENIRQSTAT_shared)
++
++/*
++ * Set the current VCPU's I/O privilege level.
++ * @arg == pointer to physdev_set_iopl structure.
++ */
++#define PHYSDEVOP_set_iopl 6
++struct physdev_set_iopl {
++ /* IN */
++ uint32_t iopl;
++};
++typedef struct physdev_set_iopl physdev_set_iopl_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_set_iopl_t);
++
++/*
++ * Set the current VCPU's I/O-port permissions bitmap.
++ * @arg == pointer to physdev_set_iobitmap structure.
++ */
++#define PHYSDEVOP_set_iobitmap 7
++struct physdev_set_iobitmap {
++ /* IN */
++ uint8_t *bitmap;
++ uint32_t nr_ports;
++};
++typedef struct physdev_set_iobitmap physdev_set_iobitmap_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_set_iobitmap_t);
++
++/*
++ * Read or write an IO-APIC register.
++ * @arg == pointer to physdev_apic structure.
++ */
++#define PHYSDEVOP_apic_read 8
++#define PHYSDEVOP_apic_write 9
++struct physdev_apic {
++ /* IN */
++ unsigned long apic_physbase;
++ uint32_t reg;
++ /* IN or OUT */
++ uint32_t value;
++};
++typedef struct physdev_apic physdev_apic_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_apic_t);
++
++/*
++ * Allocate or free a physical upcall vector for the specified IRQ line.
++ * @arg == pointer to physdev_irq structure.
++ */
++#define PHYSDEVOP_alloc_irq_vector 10
++#define PHYSDEVOP_free_irq_vector 11
++struct physdev_irq {
++ /* IN */
++ uint32_t irq;
++ /* IN or OUT */
++ uint32_t vector;
++};
++typedef struct physdev_irq physdev_irq_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_irq_t);
++
++/*
++ * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
++ * hypercall since 0x00030202.
++ */
++struct physdev_op {
++ uint32_t cmd;
++ union {
++ struct physdev_irq_status_query irq_status_query;
++ struct physdev_set_iopl set_iopl;
++ struct physdev_set_iobitmap set_iobitmap;
++ struct physdev_apic apic_op;
++ struct physdev_irq irq_op;
++ } u;
++};
++typedef struct physdev_op physdev_op_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_op_t);
++
++/*
++ * Notify that some PIRQ-bound event channels have been unmasked.
++ * ** This command is obsolete since interface version 0x00030202 and is **
++ * ** unsupported by newer versions of Xen. **
++ */
++#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4
++
++/*
++ * These all-capitals physdev operation names are superceded by the new names
++ * (defined above) since interface version 0x00030202.
++ */
++#define PHYSDEVOP_IRQ_STATUS_QUERY PHYSDEVOP_irq_status_query
++#define PHYSDEVOP_SET_IOPL PHYSDEVOP_set_iopl
++#define PHYSDEVOP_SET_IOBITMAP PHYSDEVOP_set_iobitmap
++#define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read
++#define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write
++#define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector
++#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi
++#define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared
++
++#endif /* __XEN_PUBLIC_PHYSDEV_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/platform.h linux-2.6.18-xen/include/xen/interface/platform.h
+--- linux-2.6.18.1/include/xen/interface/platform.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/platform.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,125 @@
++/******************************************************************************
++ * platform.h
++ *
++ * Hardware platform operations. Intended for use by domain-0 kernel.
++ *
++ * Copyright (c) 2002-2006, K Fraser
++ */
++
++#ifndef __XEN_PUBLIC_PLATFORM_H__
++#define __XEN_PUBLIC_PLATFORM_H__
++
++#include "xen.h"
++
++#define XENPF_INTERFACE_VERSION 0x03000001
++
++/*
++ * Set clock such that it would read <secs,nsecs> after 00:00:00 UTC,
++ * 1 January, 1970 if the current system time was <system_time>.
++ */
++#define XENPF_settime 17
++struct xenpf_settime {
++ /* IN variables. */
++ uint32_t secs;
++ uint32_t nsecs;
++ uint64_t system_time;
++};
++typedef struct xenpf_settime xenpf_settime_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_settime_t);
++
++/*
++ * Request memory range (@mfn, @mfn+ at nr_mfns-1) to have type @type.
++ * On x86, @type is an architecture-defined MTRR memory type.
++ * On success, returns the MTRR that was used (@reg) and a handle that can
++ * be passed to XENPF_DEL_MEMTYPE to accurately tear down the new setting.
++ * (x86-specific).
++ */
++#define XENPF_add_memtype 31
++struct xenpf_add_memtype {
++ /* IN variables. */
++ xen_pfn_t mfn;
++ uint64_t nr_mfns;
++ uint32_t type;
++ /* OUT variables. */
++ uint32_t handle;
++ uint32_t reg;
++};
++typedef struct xenpf_add_memtype xenpf_add_memtype_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_add_memtype_t);
++
++/*
++ * Tear down an existing memory-range type. If @handle is remembered then it
++ * should be passed in to accurately tear down the correct setting (in case
++ * of overlapping memory regions with differing types). If it is not known
++ * then @handle should be set to zero. In all cases @reg must be set.
++ * (x86-specific).
++ */
++#define XENPF_del_memtype 32
++struct xenpf_del_memtype {
++ /* IN variables. */
++ uint32_t handle;
++ uint32_t reg;
++};
++typedef struct xenpf_del_memtype xenpf_del_memtype_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_del_memtype_t);
++
++/* Read current type of an MTRR (x86-specific). */
++#define XENPF_read_memtype 33
++struct xenpf_read_memtype {
++ /* IN variables. */
++ uint32_t reg;
++ /* OUT variables. */
++ xen_pfn_t mfn;
++ uint64_t nr_mfns;
++ uint32_t type;
++};
++typedef struct xenpf_read_memtype xenpf_read_memtype_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_read_memtype_t);
++
++#define XENPF_microcode_update 35
++struct xenpf_microcode_update {
++ /* IN variables. */
++ XEN_GUEST_HANDLE(void) data; /* Pointer to microcode data */
++ uint32_t length; /* Length of microcode data. */
++};
++typedef struct xenpf_microcode_update xenpf_microcode_update_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_microcode_update_t);
++
++#define XENPF_platform_quirk 39
++#define QUIRK_NOIRQBALANCING 1 /* Do not restrict IO-APIC RTE targets */
++#define QUIRK_IOAPIC_BAD_REGSEL 2 /* IO-APIC REGSEL forgets its value */
++#define QUIRK_IOAPIC_GOOD_REGSEL 3 /* IO-APIC REGSEL behaves properly */
++struct xenpf_platform_quirk {
++ /* IN variables. */
++ uint32_t quirk_id;
++};
++typedef struct xenpf_platform_quirk xenpf_platform_quirk_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t);
++
++struct xen_platform_op {
++ uint32_t cmd;
++ uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
++ union {
++ struct xenpf_settime settime;
++ struct xenpf_add_memtype add_memtype;
++ struct xenpf_del_memtype del_memtype;
++ struct xenpf_read_memtype read_memtype;
++ struct xenpf_microcode_update microcode;
++ struct xenpf_platform_quirk platform_quirk;
++ uint8_t pad[128];
++ } u;
++};
++typedef struct xen_platform_op xen_platform_op_t;
++DEFINE_XEN_GUEST_HANDLE(xen_platform_op_t);
++
++#endif /* __XEN_PUBLIC_PLATFORM_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/sched.h linux-2.6.18-xen/include/xen/interface/sched.h
+--- linux-2.6.18.1/include/xen/interface/sched.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/sched.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,103 @@
++/******************************************************************************
++ * sched.h
++ *
++ * Scheduler state interactions
++ *
++ * Copyright (c) 2005, Keir Fraser <keir at xensource.com>
++ */
++
++#ifndef __XEN_PUBLIC_SCHED_H__
++#define __XEN_PUBLIC_SCHED_H__
++
++#include "event_channel.h"
++
++/*
++ * The prototype for this hypercall is:
++ * long sched_op(int cmd, void *arg)
++ * @cmd == SCHEDOP_??? (scheduler operation).
++ * @arg == Operation-specific extra argument(s), as described below.
++ *
++ * Versions of Xen prior to 3.0.2 provided only the following legacy version
++ * of this hypercall, supporting only the commands yield, block and shutdown:
++ * long sched_op(int cmd, unsigned long arg)
++ * @cmd == SCHEDOP_??? (scheduler operation).
++ * @arg == 0 (SCHEDOP_yield and SCHEDOP_block)
++ * == SHUTDOWN_* code (SCHEDOP_shutdown)
++ * This legacy version is available to new guests as sched_op_compat().
++ */
++
++/*
++ * Voluntarily yield the CPU.
++ * @arg == NULL.
++ */
++#define SCHEDOP_yield 0
++
++/*
++ * Block execution of this VCPU until an event is received for processing.
++ * If called with event upcalls masked, this operation will atomically
++ * reenable event delivery and check for pending events before blocking the
++ * VCPU. This avoids a "wakeup waiting" race.
++ * @arg == NULL.
++ */
++#define SCHEDOP_block 1
++
++/*
++ * Halt execution of this domain (all VCPUs) and notify the system controller.
++ * @arg == pointer to sched_shutdown structure.
++ */
++#define SCHEDOP_shutdown 2
++struct sched_shutdown {
++ unsigned int reason; /* SHUTDOWN_* */
++};
++typedef struct sched_shutdown sched_shutdown_t;
++DEFINE_XEN_GUEST_HANDLE(sched_shutdown_t);
++
++/*
++ * Poll a set of event-channel ports. Return when one or more are pending. An
++ * optional timeout may be specified.
++ * @arg == pointer to sched_poll structure.
++ */
++#define SCHEDOP_poll 3
++struct sched_poll {
++ XEN_GUEST_HANDLE(evtchn_port_t) ports;
++ unsigned int nr_ports;
++ uint64_t timeout;
++};
++typedef struct sched_poll sched_poll_t;
++DEFINE_XEN_GUEST_HANDLE(sched_poll_t);
++
++/*
++ * Declare a shutdown for another domain. The main use of this function is
++ * in interpreting shutdown requests and reasons for fully-virtualized
++ * domains. A para-virtualized domain may use SCHEDOP_shutdown directly.
++ * @arg == pointer to sched_remote_shutdown structure.
++ */
++#define SCHEDOP_remote_shutdown 4
++struct sched_remote_shutdown {
++ domid_t domain_id; /* Remote domain ID */
++ unsigned int reason; /* SHUTDOWN_xxx reason */
++};
++typedef struct sched_remote_shutdown sched_remote_shutdown_t;
++DEFINE_XEN_GUEST_HANDLE(sched_remote_shutdown_t);
++
++/*
++ * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
++ * software to determine the appropriate action. For the most part, Xen does
++ * not care about the shutdown code.
++ */
++#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
++#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
++#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
++#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
++
++#endif /* __XEN_PUBLIC_SCHED_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/sysctl.h linux-2.6.18-xen/include/xen/interface/sysctl.h
+--- linux-2.6.18.1/include/xen/interface/sysctl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/sysctl.h 2006-09-04 16:31:19.000000000 +0200
+@@ -0,0 +1,151 @@
++/******************************************************************************
++ * sysctl.h
++ *
++ * System management operations. For use by node control stack.
++ *
++ * Copyright (c) 2002-2006, K Fraser
++ */
++
++#ifndef __XEN_PUBLIC_SYSCTL_H__
++#define __XEN_PUBLIC_SYSCTL_H__
++
++#if !defined(__XEN__) && !defined(__XEN_TOOLS__)
++#error "sysctl operations are intended for use by node control tools only"
++#endif
++
++#include "xen.h"
++#include "domctl.h"
++
++#define XEN_SYSCTL_INTERFACE_VERSION 0x00000002
++
++/*
++ * Read console content from Xen buffer ring.
++ */
++#define XEN_SYSCTL_readconsole 1
++struct xen_sysctl_readconsole {
++ /* IN variables. */
++ uint32_t clear; /* Non-zero -> clear after reading. */
++ XEN_GUEST_HANDLE(char) buffer; /* Buffer start */
++ /* IN/OUT variables. */
++ uint32_t count; /* In: Buffer size; Out: Used buffer size */
++};
++typedef struct xen_sysctl_readconsole xen_sysctl_readconsole_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_readconsole_t);
++
++/* Get trace buffers machine base address */
++#define XEN_SYSCTL_tbuf_op 2
++struct xen_sysctl_tbuf_op {
++ /* IN variables */
++#define XEN_SYSCTL_TBUFOP_get_info 0
++#define XEN_SYSCTL_TBUFOP_set_cpu_mask 1
++#define XEN_SYSCTL_TBUFOP_set_evt_mask 2
++#define XEN_SYSCTL_TBUFOP_set_size 3
++#define XEN_SYSCTL_TBUFOP_enable 4
++#define XEN_SYSCTL_TBUFOP_disable 5
++ uint32_t cmd;
++ /* IN/OUT variables */
++ struct xenctl_cpumap cpu_mask;
++ uint32_t evt_mask;
++ /* OUT variables */
++ uint64_t buffer_mfn;
++ uint32_t size;
++};
++typedef struct xen_sysctl_tbuf_op xen_sysctl_tbuf_op_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_tbuf_op_t);
++
++/*
++ * Get physical information about the host machine
++ */
++#define XEN_SYSCTL_physinfo 3
++struct xen_sysctl_physinfo {
++ uint32_t threads_per_core;
++ uint32_t cores_per_socket;
++ uint32_t sockets_per_node;
++ uint32_t nr_nodes;
++ uint32_t cpu_khz;
++ uint64_t total_pages;
++ uint64_t free_pages;
++ uint64_t scrub_pages;
++ uint32_t hw_cap[8];
++};
++typedef struct xen_sysctl_physinfo xen_sysctl_physinfo_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_physinfo_t);
++
++/*
++ * Get the ID of the current scheduler.
++ */
++#define XEN_SYSCTL_sched_id 4
++struct xen_sysctl_sched_id {
++ /* OUT variable */
++ uint32_t sched_id;
++};
++typedef struct xen_sysctl_sched_id xen_sysctl_sched_id_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_sched_id_t);
++
++/* Interface for controlling Xen software performance counters. */
++#define XEN_SYSCTL_perfc_op 5
++/* Sub-operations: */
++#define XEN_SYSCTL_PERFCOP_reset 1 /* Reset all counters to zero. */
++#define XEN_SYSCTL_PERFCOP_query 2 /* Get perfctr information. */
++struct xen_sysctl_perfc_desc {
++ char name[80]; /* name of perf counter */
++ uint32_t nr_vals; /* number of values for this counter */
++};
++typedef struct xen_sysctl_perfc_desc xen_sysctl_perfc_desc_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t);
++typedef uint32_t xen_sysctl_perfc_val_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t);
++
++struct xen_sysctl_perfc_op {
++ /* IN variables. */
++ uint32_t cmd; /* XEN_SYSCTL_PERFCOP_??? */
++ /* OUT variables. */
++ uint32_t nr_counters; /* number of counters description */
++ uint32_t nr_vals; /* number of values */
++ /* counter information (or NULL) */
++ XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc;
++ /* counter values (or NULL) */
++ XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t) val;
++};
++typedef struct xen_sysctl_perfc_op xen_sysctl_perfc_op_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_perfc_op_t);
++
++#define XEN_SYSCTL_getdomaininfolist 6
++struct xen_sysctl_getdomaininfolist {
++ /* IN variables. */
++ domid_t first_domain;
++ uint32_t max_domains;
++ XEN_GUEST_HANDLE(xen_domctl_getdomaininfo_t) buffer;
++ /* OUT variables. */
++ uint32_t num_domains;
++};
++typedef struct xen_sysctl_getdomaininfolist xen_sysctl_getdomaininfolist_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getdomaininfolist_t);
++
++struct xen_sysctl {
++ uint32_t cmd;
++ uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
++ union {
++ struct xen_sysctl_readconsole readconsole;
++ struct xen_sysctl_tbuf_op tbuf_op;
++ struct xen_sysctl_physinfo physinfo;
++ struct xen_sysctl_sched_id sched_id;
++ struct xen_sysctl_perfc_op perfc_op;
++ struct xen_sysctl_getdomaininfolist getdomaininfolist;
++ uint8_t pad[128];
++ } u;
++};
++typedef struct xen_sysctl xen_sysctl_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_t);
++
++#endif /* __XEN_PUBLIC_SYSCTL_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/trace.h linux-2.6.18-xen/include/xen/interface/trace.h
+--- linux-2.6.18.1/include/xen/interface/trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/trace.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,87 @@
++/******************************************************************************
++ * include/public/trace.h
++ *
++ * Mark Williamson, (C) 2004 Intel Research Cambridge
++ * Copyright (C) 2005 Bin Ren
++ */
++
++#ifndef __XEN_PUBLIC_TRACE_H__
++#define __XEN_PUBLIC_TRACE_H__
++
++/* Trace classes */
++#define TRC_CLS_SHIFT 16
++#define TRC_GEN 0x0001f000 /* General trace */
++#define TRC_SCHED 0x0002f000 /* Xen Scheduler trace */
++#define TRC_DOM0OP 0x0004f000 /* Xen DOM0 operation trace */
++#define TRC_VMX 0x0008f000 /* Xen VMX trace */
++#define TRC_MEM 0x000af000 /* Xen memory trace */
++#define TRC_ALL 0xfffff000
++
++/* Trace subclasses */
++#define TRC_SUBCLS_SHIFT 12
++/* trace subclasses for VMX */
++#define TRC_VMXEXIT 0x00081000 /* VMX exit trace */
++#define TRC_VMXTIMER 0x00082000 /* VMX timer trace */
++#define TRC_VMXINT 0x00084000 /* VMX interrupt trace */
++#define TRC_VMXIO 0x00088000 /* VMX io emulation trace */
++
++/* Trace events per class */
++#define TRC_LOST_RECORDS (TRC_GEN + 1)
++
++#define TRC_SCHED_DOM_ADD (TRC_SCHED + 1)
++#define TRC_SCHED_DOM_REM (TRC_SCHED + 2)
++#define TRC_SCHED_SLEEP (TRC_SCHED + 3)
++#define TRC_SCHED_WAKE (TRC_SCHED + 4)
++#define TRC_SCHED_YIELD (TRC_SCHED + 5)
++#define TRC_SCHED_BLOCK (TRC_SCHED + 6)
++#define TRC_SCHED_SHUTDOWN (TRC_SCHED + 7)
++#define TRC_SCHED_CTL (TRC_SCHED + 8)
++#define TRC_SCHED_ADJDOM (TRC_SCHED + 9)
++#define TRC_SCHED_SWITCH (TRC_SCHED + 10)
++#define TRC_SCHED_S_TIMER_FN (TRC_SCHED + 11)
++#define TRC_SCHED_T_TIMER_FN (TRC_SCHED + 12)
++#define TRC_SCHED_DOM_TIMER_FN (TRC_SCHED + 13)
++#define TRC_SCHED_SWITCH_INFPREV (TRC_SCHED + 14)
++#define TRC_SCHED_SWITCH_INFNEXT (TRC_SCHED + 15)
++
++#define TRC_MEM_PAGE_GRANT_MAP (TRC_MEM + 1)
++#define TRC_MEM_PAGE_GRANT_UNMAP (TRC_MEM + 2)
++#define TRC_MEM_PAGE_GRANT_TRANSFER (TRC_MEM + 3)
++
++/* trace events per subclass */
++#define TRC_VMX_VMEXIT (TRC_VMXEXIT + 1)
++#define TRC_VMX_VMENTRY (TRC_VMXEXIT + 2)
++
++#define TRC_VMX_TIMER_INTR (TRC_VMXTIMER + 1)
++
++#define TRC_VMX_INT (TRC_VMXINT + 1)
++
++
++/* This structure represents a single trace buffer record. */
++struct t_rec {
++ uint64_t cycles; /* cycle counter timestamp */
++ uint32_t event; /* event ID */
++ unsigned long data[5]; /* event data items */
++};
++
++/*
++ * This structure contains the metadata for a single trace buffer. The head
++ * field, indexes into an array of struct t_rec's.
++ */
++struct t_buf {
++ uint32_t cons; /* Next item to be consumed by control tools. */
++ uint32_t prod; /* Next item to be produced by Xen. */
++ /* 'nr_recs' records follow immediately after the meta-data header. */
++};
++
++#endif /* __XEN_PUBLIC_TRACE_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/vcpu.h linux-2.6.18-xen/include/xen/interface/vcpu.h
+--- linux-2.6.18.1/include/xen/interface/vcpu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/vcpu.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,121 @@
++/******************************************************************************
++ * vcpu.h
++ *
++ * VCPU initialisation, query, and hotplug.
++ *
++ * Copyright (c) 2005, Keir Fraser <keir at xensource.com>
++ */
++
++#ifndef __XEN_PUBLIC_VCPU_H__
++#define __XEN_PUBLIC_VCPU_H__
++
++/*
++ * Prototype for this hypercall is:
++ * int vcpu_op(int cmd, int vcpuid, void *extra_args)
++ * @cmd == VCPUOP_??? (VCPU operation).
++ * @vcpuid == VCPU to operate on.
++ * @extra_args == Operation-specific extra arguments (NULL if none).
++ */
++
++/*
++ * Initialise a VCPU. Each VCPU can be initialised only once. A
++ * newly-initialised VCPU will not run until it is brought up by VCPUOP_up.
++ *
++ * @extra_arg == pointer to vcpu_guest_context structure containing initial
++ * state for the VCPU.
++ */
++#define VCPUOP_initialise 0
++
++/*
++ * Bring up a VCPU. This makes the VCPU runnable. This operation will fail
++ * if the VCPU has not been initialised (VCPUOP_initialise).
++ */
++#define VCPUOP_up 1
++
++/*
++ * Bring down a VCPU (i.e., make it non-runnable).
++ * There are a few caveats that callers should observe:
++ * 1. This operation may return, and VCPU_is_up may return false, before the
++ * VCPU stops running (i.e., the command is asynchronous). It is a good
++ * idea to ensure that the VCPU has entered a non-critical loop before
++ * bringing it down. Alternatively, this operation is guaranteed
++ * synchronous if invoked by the VCPU itself.
++ * 2. After a VCPU is initialised, there is currently no way to drop all its
++ * references to domain memory. Even a VCPU that is down still holds
++ * memory references via its pagetable base pointer and GDT. It is good
++ * practise to move a VCPU onto an 'idle' or default page table, LDT and
++ * GDT before bringing it down.
++ */
++#define VCPUOP_down 2
++
++/* Returns 1 if the given VCPU is up. */
++#define VCPUOP_is_up 3
++
++/*
++ * Return information about the state and running time of a VCPU.
++ * @extra_arg == pointer to vcpu_runstate_info structure.
++ */
++#define VCPUOP_get_runstate_info 4
++struct vcpu_runstate_info {
++ /* VCPU's current state (RUNSTATE_*). */
++ int state;
++ /* When was current state entered (system time, ns)? */
++ uint64_t state_entry_time;
++ /*
++ * Time spent in each RUNSTATE_* (ns). The sum of these times is
++ * guaranteed not to drift from system time.
++ */
++ uint64_t time[4];
++};
++typedef struct vcpu_runstate_info vcpu_runstate_info_t;
++
++/* VCPU is currently running on a physical CPU. */
++#define RUNSTATE_running 0
++
++/* VCPU is runnable, but not currently scheduled on any physical CPU. */
++#define RUNSTATE_runnable 1
++
++/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */
++#define RUNSTATE_blocked 2
++
++/*
++ * VCPU is not runnable, but it is not blocked.
++ * This is a 'catch all' state for things like hotplug and pauses by the
++ * system administrator (or for critical sections in the hypervisor).
++ * RUNSTATE_blocked dominates this state (it is the preferred state).
++ */
++#define RUNSTATE_offline 3
++
++/*
++ * Register a shared memory area from which the guest may obtain its own
++ * runstate information without needing to execute a hypercall.
++ * Notes:
++ * 1. The registered address may be virtual or physical, depending on the
++ * platform. The virtual address should be registered on x86 systems.
++ * 2. Only one shared area may be registered per VCPU. The shared area is
++ * updated by the hypervisor each time the VCPU is scheduled. Thus
++ * runstate.state will always be RUNSTATE_running and
++ * runstate.state_entry_time will indicate the system time at which the
++ * VCPU was last scheduled to run.
++ * @extra_arg == pointer to vcpu_register_runstate_memory_area structure.
++ */
++#define VCPUOP_register_runstate_memory_area 5
++struct vcpu_register_runstate_memory_area {
++ union {
++ struct vcpu_runstate_info *v;
++ uint64_t p;
++ } addr;
++};
++typedef struct vcpu_register_runstate_memory_area vcpu_register_runstate_memory_area_t;
++
++#endif /* __XEN_PUBLIC_VCPU_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/version.h linux-2.6.18-xen/include/xen/interface/version.h
+--- linux-2.6.18.1/include/xen/interface/version.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/version.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,73 @@
++/******************************************************************************
++ * version.h
++ *
++ * Xen version, type, and compile information.
++ *
++ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh at gmail.com>
++ * Copyright (c) 2005, Keir Fraser <keir at xensource.com>
++ */
++
++#ifndef __XEN_PUBLIC_VERSION_H__
++#define __XEN_PUBLIC_VERSION_H__
++
++/* NB. All ops return zero on success, except XENVER_{version,pagesize} */
++
++/* arg == NULL; returns major:minor (16:16). */
++#define XENVER_version 0
++
++/* arg == xen_extraversion_t. */
++#define XENVER_extraversion 1
++typedef char xen_extraversion_t[16];
++#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
++
++/* arg == xen_compile_info_t. */
++#define XENVER_compile_info 2
++struct xen_compile_info {
++ char compiler[64];
++ char compile_by[16];
++ char compile_domain[32];
++ char compile_date[32];
++};
++typedef struct xen_compile_info xen_compile_info_t;
++
++#define XENVER_capabilities 3
++typedef char xen_capabilities_info_t[1024];
++#define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t))
++
++#define XENVER_changeset 4
++typedef char xen_changeset_info_t[64];
++#define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t))
++
++#define XENVER_platform_parameters 5
++struct xen_platform_parameters {
++ unsigned long virt_start;
++};
++typedef struct xen_platform_parameters xen_platform_parameters_t;
++
++#define XENVER_get_features 6
++struct xen_feature_info {
++ unsigned int submap_idx; /* IN: which 32-bit submap to return */
++ uint32_t submap; /* OUT: 32-bit submap */
++};
++typedef struct xen_feature_info xen_feature_info_t;
++
++/* Declares the features reported by XENVER_get_features. */
++#include "features.h"
++
++/* arg == NULL; returns host memory page size. */
++#define XENVER_pagesize 7
++
++/* arg == xen_domain_handle_t. */
++#define XENVER_guest_handle 8
++
++#endif /* __XEN_PUBLIC_VERSION_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/xencomm.h linux-2.6.18-xen/include/xen/interface/xencomm.h
+--- linux-2.6.18.1/include/xen/interface/xencomm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/xencomm.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2006 Hollis Blanchard <hollisb at us.ibm.com>, IBM Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _XEN_XENCOMM_H_
++#define _XEN_XENCOMM_H_
++
++/* A xencomm descriptor is a scatter/gather list containing physical
++ * addresses corresponding to a virtually contiguous memory area. The
++ * hypervisor translates these physical addresses to machine addresses to copy
++ * to and from the virtually contiguous area.
++ */
++
++#define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */
++#define XENCOMM_INVALID (~0UL)
++
++struct xencomm_desc {
++ uint32_t magic;
++ uint32_t nr_addrs; /* the number of entries in address[] */
++ uint64_t address[0];
++};
++
++#endif /* _XEN_XENCOMM_H_ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/xen-compat.h linux-2.6.18-xen/include/xen/interface/xen-compat.h
+--- linux-2.6.18.1/include/xen/interface/xen-compat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/xen-compat.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,26 @@
++/******************************************************************************
++ * xen-compat.h
++ *
++ * Guest OS interface to Xen. Compatibility layer.
++ *
++ * Copyright (c) 2006, Christian Limpach
++ */
++
++#ifndef __XEN_PUBLIC_XEN_COMPAT_H__
++#define __XEN_PUBLIC_XEN_COMPAT_H__
++
++#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030204
++
++#if defined(__XEN__) || defined(__XEN_TOOLS__)
++/* Xen is built with matching headers and implements the latest interface. */
++#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__
++#elif !defined(__XEN_INTERFACE_VERSION__)
++/* Guests which do not specify a version get the legacy interface. */
++#define __XEN_INTERFACE_VERSION__ 0x00000000
++#endif
++
++#if __XEN_INTERFACE_VERSION__ > __XEN_LATEST_INTERFACE_VERSION__
++#error "These header files do not support the requested interface version."
++#endif
++
++#endif /* __XEN_PUBLIC_XEN_COMPAT_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/xen.h linux-2.6.18-xen/include/xen/interface/xen.h
+--- linux-2.6.18.1/include/xen/interface/xen.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/xen.h 2006-09-21 01:33:32.000000000 +0200
+@@ -0,0 +1,581 @@
++/******************************************************************************
++ * xen.h
++ *
++ * Guest OS interface to Xen.
++ *
++ * Copyright (c) 2004, K A Fraser
++ */
++
++#ifndef __XEN_PUBLIC_XEN_H__
++#define __XEN_PUBLIC_XEN_H__
++
++#include "xen-compat.h"
++
++#if defined(__i386__)
++#include "arch-x86_32.h"
++#elif defined(__x86_64__)
++#include "arch-x86_64.h"
++#elif defined(__ia64__)
++#include "arch-ia64.h"
++#elif defined(__powerpc__)
++#include "arch-powerpc.h"
++#else
++#error "Unsupported architecture"
++#endif
++
++/*
++ * HYPERCALLS
++ */
++
++#define __HYPERVISOR_set_trap_table 0
++#define __HYPERVISOR_mmu_update 1
++#define __HYPERVISOR_set_gdt 2
++#define __HYPERVISOR_stack_switch 3
++#define __HYPERVISOR_set_callbacks 4
++#define __HYPERVISOR_fpu_taskswitch 5
++#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */
++#define __HYPERVISOR_platform_op 7
++#define __HYPERVISOR_set_debugreg 8
++#define __HYPERVISOR_get_debugreg 9
++#define __HYPERVISOR_update_descriptor 10
++#define __HYPERVISOR_memory_op 12
++#define __HYPERVISOR_multicall 13
++#define __HYPERVISOR_update_va_mapping 14
++#define __HYPERVISOR_set_timer_op 15
++#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */
++#define __HYPERVISOR_xen_version 17
++#define __HYPERVISOR_console_io 18
++#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */
++#define __HYPERVISOR_grant_table_op 20
++#define __HYPERVISOR_vm_assist 21
++#define __HYPERVISOR_update_va_mapping_otherdomain 22
++#define __HYPERVISOR_iret 23 /* x86 only */
++#define __HYPERVISOR_vcpu_op 24
++#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
++#define __HYPERVISOR_mmuext_op 26
++#define __HYPERVISOR_acm_op 27
++#define __HYPERVISOR_nmi_op 28
++#define __HYPERVISOR_sched_op 29
++#define __HYPERVISOR_callback_op 30
++#define __HYPERVISOR_xenoprof_op 31
++#define __HYPERVISOR_event_channel_op 32
++#define __HYPERVISOR_physdev_op 33
++#define __HYPERVISOR_hvm_op 34
++#define __HYPERVISOR_sysctl 35
++#define __HYPERVISOR_domctl 36
++#define __HYPERVISOR_kexec_op 37
++
++/* Architecture-specific hypercall definitions. */
++#define __HYPERVISOR_arch_0 48
++#define __HYPERVISOR_arch_1 49
++#define __HYPERVISOR_arch_2 50
++#define __HYPERVISOR_arch_3 51
++#define __HYPERVISOR_arch_4 52
++#define __HYPERVISOR_arch_5 53
++#define __HYPERVISOR_arch_6 54
++#define __HYPERVISOR_arch_7 55
++
++/*
++ * HYPERCALL COMPATIBILITY.
++ */
++
++/* New sched_op hypercall introduced in 0x00030101. */
++#if __XEN_INTERFACE_VERSION__ < 0x00030101
++#undef __HYPERVISOR_sched_op
++#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat
++#endif
++
++/* New event-channel and physdev hypercalls introduced in 0x00030202. */
++#if __XEN_INTERFACE_VERSION__ < 0x00030202
++#undef __HYPERVISOR_event_channel_op
++#define __HYPERVISOR_event_channel_op __HYPERVISOR_event_channel_op_compat
++#undef __HYPERVISOR_physdev_op
++#define __HYPERVISOR_physdev_op __HYPERVISOR_physdev_op_compat
++#endif
++
++/* New platform_op hypercall introduced in 0x00030204. */
++#if __XEN_INTERFACE_VERSION__ < 0x00030204
++#define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op
++#endif
++
++/*
++ * VIRTUAL INTERRUPTS
++ *
++ * Virtual interrupts that a guest OS may receive from Xen.
++ *
++ * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a
++ * global VIRQ. The former can be bound once per VCPU and cannot be re-bound.
++ * The latter can be allocated only once per guest: they must initially be
++ * allocated to VCPU0 but can subsequently be re-bound.
++ */
++#define VIRQ_TIMER 0 /* V. Timebase update, and/or requested timeout. */
++#define VIRQ_DEBUG 1 /* V. Request guest to dump debug info. */
++#define VIRQ_CONSOLE 2 /* G. (DOM0) Bytes received on emergency console. */
++#define VIRQ_DOM_EXC 3 /* G. (DOM0) Exceptional event for some domain. */
++#define VIRQ_TBUF 4 /* G. (DOM0) Trace buffer has records available. */
++#define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */
++#define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */
++
++/* Architecture-specific VIRQ definitions. */
++#define VIRQ_ARCH_0 16
++#define VIRQ_ARCH_1 17
++#define VIRQ_ARCH_2 18
++#define VIRQ_ARCH_3 19
++#define VIRQ_ARCH_4 20
++#define VIRQ_ARCH_5 21
++#define VIRQ_ARCH_6 22
++#define VIRQ_ARCH_7 23
++
++#define NR_VIRQS 24
++
++/*
++ * MMU-UPDATE REQUESTS
++ *
++ * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
++ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
++ * Where the FD has some effect, it is described below.
++ * ptr[1:0] specifies the appropriate MMU_* command.
++ *
++ * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
++ * Updates an entry in a page table. If updating an L1 table, and the new
++ * table entry is valid/present, the mapped frame must belong to the FD, if
++ * an FD has been specified. If attempting to map an I/O page then the
++ * caller assumes the privilege of the FD.
++ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
++ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
++ * ptr[:2] -- Machine address of the page-table entry to modify.
++ * val -- Value to write.
++ *
++ * ptr[1:0] == MMU_MACHPHYS_UPDATE:
++ * Updates an entry in the machine->pseudo-physical mapping table.
++ * ptr[:2] -- Machine address within the frame whose mapping to modify.
++ * The frame must belong to the FD, if one is specified.
++ * val -- Value to write into the mapping entry.
++ */
++#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
++#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */
++
++/*
++ * MMU EXTENDED OPERATIONS
++ *
++ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
++ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
++ * Where the FD has some effect, it is described below.
++ *
++ * cmd: MMUEXT_(UN)PIN_*_TABLE
++ * mfn: Machine frame number to be (un)pinned as a p.t. page.
++ * The frame must belong to the FD, if one is specified.
++ *
++ * cmd: MMUEXT_NEW_BASEPTR
++ * mfn: Machine frame number of new page-table base to install in MMU.
++ *
++ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
++ * mfn: Machine frame number of new page-table base to install in MMU
++ * when in user space.
++ *
++ * cmd: MMUEXT_TLB_FLUSH_LOCAL
++ * No additional arguments. Flushes local TLB.
++ *
++ * cmd: MMUEXT_INVLPG_LOCAL
++ * linear_addr: Linear address to be flushed from the local TLB.
++ *
++ * cmd: MMUEXT_TLB_FLUSH_MULTI
++ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
++ *
++ * cmd: MMUEXT_INVLPG_MULTI
++ * linear_addr: Linear address to be flushed.
++ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
++ *
++ * cmd: MMUEXT_TLB_FLUSH_ALL
++ * No additional arguments. Flushes all VCPUs' TLBs.
++ *
++ * cmd: MMUEXT_INVLPG_ALL
++ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
++ *
++ * cmd: MMUEXT_FLUSH_CACHE
++ * No additional arguments. Writes back and flushes cache contents.
++ *
++ * cmd: MMUEXT_SET_LDT
++ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
++ * nr_ents: Number of entries in LDT.
++ */
++#define MMUEXT_PIN_L1_TABLE 0
++#define MMUEXT_PIN_L2_TABLE 1
++#define MMUEXT_PIN_L3_TABLE 2
++#define MMUEXT_PIN_L4_TABLE 3
++#define MMUEXT_UNPIN_TABLE 4
++#define MMUEXT_NEW_BASEPTR 5
++#define MMUEXT_TLB_FLUSH_LOCAL 6
++#define MMUEXT_INVLPG_LOCAL 7
++#define MMUEXT_TLB_FLUSH_MULTI 8
++#define MMUEXT_INVLPG_MULTI 9
++#define MMUEXT_TLB_FLUSH_ALL 10
++#define MMUEXT_INVLPG_ALL 11
++#define MMUEXT_FLUSH_CACHE 12
++#define MMUEXT_SET_LDT 13
++#define MMUEXT_NEW_USER_BASEPTR 15
++
++#ifndef __ASSEMBLY__
++struct mmuext_op {
++ unsigned int cmd;
++ union {
++ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
++ xen_pfn_t mfn;
++ /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
++ unsigned long linear_addr;
++ } arg1;
++ union {
++ /* SET_LDT */
++ unsigned int nr_ents;
++ /* TLB_FLUSH_MULTI, INVLPG_MULTI */
++ void *vcpumask;
++ } arg2;
++};
++typedef struct mmuext_op mmuext_op_t;
++DEFINE_XEN_GUEST_HANDLE(mmuext_op_t);
++#endif
++
++/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
++/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */
++/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */
++#define UVMF_NONE (0UL<<0) /* No flushing at all. */
++#define UVMF_TLB_FLUSH (1UL<<0) /* Flush entire TLB(s). */
++#define UVMF_INVLPG (2UL<<0) /* Flush only one entry. */
++#define UVMF_FLUSHTYPE_MASK (3UL<<0)
++#define UVMF_MULTI (0UL<<2) /* Flush subset of TLBs. */
++#define UVMF_LOCAL (0UL<<2) /* Flush local TLB. */
++#define UVMF_ALL (1UL<<2) /* Flush all TLBs. */
++
++/*
++ * Commands to HYPERVISOR_console_io().
++ */
++#define CONSOLEIO_write 0
++#define CONSOLEIO_read 1
++
++/*
++ * Commands to HYPERVISOR_vm_assist().
++ */
++#define VMASST_CMD_enable 0
++#define VMASST_CMD_disable 1
++
++/* x86/32 guests: simulate full 4GB segment limits. */
++#define VMASST_TYPE_4gb_segments 0
++
++/* x86/32 guests: trap (vector 15) whenever above vmassist is used. */
++#define VMASST_TYPE_4gb_segments_notify 1
++
++/*
++ * x86 guests: support writes to bottom-level PTEs.
++ * NB1. Page-directory entries cannot be written.
++ * NB2. Guest must continue to remove all writable mappings of PTEs.
++ */
++#define VMASST_TYPE_writable_pagetables 2
++
++/* x86/PAE guests: support PDPTs above 4GB. */
++#define VMASST_TYPE_pae_extended_cr3 3
++
++#define MAX_VMASST_TYPE 3
++
++#ifndef __ASSEMBLY__
++
++typedef uint16_t domid_t;
++
++/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
++#define DOMID_FIRST_RESERVED (0x7FF0U)
++
++/* DOMID_SELF is used in certain contexts to refer to oneself. */
++#define DOMID_SELF (0x7FF0U)
++
++/*
++ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
++ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
++ * is useful to ensure that no mappings to the OS's own heap are accidentally
++ * installed. (e.g., in Linux this could cause havoc as reference counts
++ * aren't adjusted on the I/O-mapping code path).
++ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
++ * be specified by any calling domain.
++ */
++#define DOMID_IO (0x7FF1U)
++
++/*
++ * DOMID_XEN is used to allow privileged domains to map restricted parts of
++ * Xen's heap space (e.g., the machine_to_phys table).
++ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
++ * the caller is privileged.
++ */
++#define DOMID_XEN (0x7FF2U)
++
++/*
++ * Send an array of these to HYPERVISOR_mmu_update().
++ * NB. The fields are natural pointer/address size for this architecture.
++ */
++struct mmu_update {
++ uint64_t ptr; /* Machine address of PTE. */
++ uint64_t val; /* New contents of PTE. */
++};
++typedef struct mmu_update mmu_update_t;
++DEFINE_XEN_GUEST_HANDLE(mmu_update_t);
++
++/*
++ * Send an array of these to HYPERVISOR_multicall().
++ * NB. The fields are natural register size for this architecture.
++ */
++struct multicall_entry {
++ unsigned long op, result;
++ unsigned long args[6];
++};
++typedef struct multicall_entry multicall_entry_t;
++DEFINE_XEN_GUEST_HANDLE(multicall_entry_t);
++
++/*
++ * Event channel endpoints per domain:
++ * 1024 if a long is 32 bits; 4096 if a long is 64 bits.
++ */
++#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64)
++
++struct vcpu_time_info {
++ /*
++ * Updates to the following values are preceded and followed by an
++ * increment of 'version'. The guest can therefore detect updates by
++ * looking for changes to 'version'. If the least-significant bit of
++ * the version number is set then an update is in progress and the guest
++ * must wait to read a consistent set of values.
++ * The correct way to interact with the version number is similar to
++ * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry.
++ */
++ uint32_t version;
++ uint32_t pad0;
++ uint64_t tsc_timestamp; /* TSC at last update of time vals. */
++ uint64_t system_time; /* Time, in nanosecs, since boot. */
++ /*
++ * Current system time:
++ * system_time +
++ * ((((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul) >> 32)
++ * CPU frequency (Hz):
++ * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift
++ */
++ uint32_t tsc_to_system_mul;
++ int8_t tsc_shift;
++ int8_t pad1[3];
++}; /* 32 bytes */
++typedef struct vcpu_time_info vcpu_time_info_t;
++
++struct vcpu_info {
++ /*
++ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
++ * a pending notification for a particular VCPU. It is then cleared
++ * by the guest OS /before/ checking for pending work, thus avoiding
++ * a set-and-check race. Note that the mask is only accessed by Xen
++ * on the CPU that is currently hosting the VCPU. This means that the
++ * pending and mask flags can be updated by the guest without special
++ * synchronisation (i.e., no need for the x86 LOCK prefix).
++ * This may seem suboptimal because if the pending flag is set by
++ * a different CPU then an IPI may be scheduled even when the mask
++ * is set. However, note:
++ * 1. The task of 'interrupt holdoff' is covered by the per-event-
++ * channel mask bits. A 'noisy' event that is continually being
++ * triggered can be masked at source at this very precise
++ * granularity.
++ * 2. The main purpose of the per-VCPU mask is therefore to restrict
++ * reentrant execution: whether for concurrency control, or to
++ * prevent unbounded stack usage. Whatever the purpose, we expect
++ * that the mask will be asserted only for short periods at a time,
++ * and so the likelihood of a 'spurious' IPI is suitably small.
++ * The mask is read before making an event upcall to the guest: a
++ * non-zero mask therefore guarantees that the VCPU will not receive
++ * an upcall activation. The mask is cleared when the VCPU requests
++ * to block: this avoids wakeup-waiting races.
++ */
++ uint8_t evtchn_upcall_pending;
++ uint8_t evtchn_upcall_mask;
++ unsigned long evtchn_pending_sel;
++ struct arch_vcpu_info arch;
++ struct vcpu_time_info time;
++}; /* 64 bytes (x86) */
++typedef struct vcpu_info vcpu_info_t;
++
++/*
++ * Xen/kernel shared data -- pointer provided in start_info.
++ *
++ * This structure is defined to be both smaller than a page, and the
++ * only data on the shared page, but may vary in actual size even within
++ * compatible Xen versions; guests should not rely on the size
++ * of this structure remaining constant.
++ */
++struct shared_info {
++ struct vcpu_info vcpu_info[MAX_VIRT_CPUS];
++
++ /*
++ * A domain can create "event channels" on which it can send and receive
++ * asynchronous event notifications. There are three classes of event that
++ * are delivered by this mechanism:
++ * 1. Bi-directional inter- and intra-domain connections. Domains must
++ * arrange out-of-band to set up a connection (usually by allocating
++ * an unbound 'listener' port and avertising that via a storage service
++ * such as xenstore).
++ * 2. Physical interrupts. A domain with suitable hardware-access
++ * privileges can bind an event-channel port to a physical interrupt
++ * source.
++ * 3. Virtual interrupts ('events'). A domain can bind an event-channel
++ * port to a virtual interrupt source, such as the virtual-timer
++ * device or the emergency console.
++ *
++ * Event channels are addressed by a "port index". Each channel is
++ * associated with two bits of information:
++ * 1. PENDING -- notifies the domain that there is a pending notification
++ * to be processed. This bit is cleared by the guest.
++ * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING
++ * will cause an asynchronous upcall to be scheduled. This bit is only
++ * updated by the guest. It is read-only within Xen. If a channel
++ * becomes pending while the channel is masked then the 'edge' is lost
++ * (i.e., when the channel is unmasked, the guest must manually handle
++ * pending notifications as no upcall will be scheduled by Xen).
++ *
++ * To expedite scanning of pending notifications, any 0->1 pending
++ * transition on an unmasked channel causes a corresponding bit in a
++ * per-vcpu selector word to be set. Each bit in the selector covers a
++ * 'C long' in the PENDING bitfield array.
++ */
++ unsigned long evtchn_pending[sizeof(unsigned long) * 8];
++ unsigned long evtchn_mask[sizeof(unsigned long) * 8];
++
++ /*
++ * Wallclock time: updated only by control software. Guests should base
++ * their gettimeofday() syscall on this wallclock-base value.
++ */
++ uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
++ uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
++ uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
++
++ struct arch_shared_info arch;
++
++};
++typedef struct shared_info shared_info_t;
++
++/*
++ * Start-of-day memory layout for the initial domain (DOM0):
++ * 1. The domain is started within contiguous virtual-memory region.
++ * 2. The contiguous region begins and ends on an aligned 4MB boundary.
++ * 3. The region start corresponds to the load address of the OS image.
++ * If the load address is not 4MB aligned then the address is rounded down.
++ * 4. This the order of bootstrap elements in the initial virtual region:
++ * a. relocated kernel image
++ * b. initial ram disk [mod_start, mod_len]
++ * c. list of allocated page frames [mfn_list, nr_pages]
++ * d. start_info_t structure [register ESI (x86)]
++ * e. bootstrap page tables [pt_base, CR3 (x86)]
++ * f. bootstrap stack [register ESP (x86)]
++ * 5. Bootstrap elements are packed together, but each is 4kB-aligned.
++ * 6. The initial ram disk may be omitted.
++ * 7. The list of page frames forms a contiguous 'pseudo-physical' memory
++ * layout for the domain. In particular, the bootstrap virtual-memory
++ * region is a 1:1 mapping to the first section of the pseudo-physical map.
++ * 8. All bootstrap elements are mapped read-writable for the guest OS. The
++ * only exception is the bootstrap page table, which is mapped read-only.
++ * 9. There is guaranteed to be at least 512kB padding after the final
++ * bootstrap element. If necessary, the bootstrap virtual region is
++ * extended by an extra 4MB to ensure this.
++ */
++
++#define MAX_GUEST_CMDLINE 1024
++struct start_info {
++ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */
++ char magic[32]; /* "xen-<version>-<platform>". */
++ unsigned long nr_pages; /* Total pages allocated to this domain. */
++ unsigned long shared_info; /* MACHINE address of shared info struct. */
++ uint32_t flags; /* SIF_xxx flags. */
++ xen_pfn_t store_mfn; /* MACHINE page number of shared page. */
++ uint32_t store_evtchn; /* Event channel for store communication. */
++ union {
++ struct {
++ xen_pfn_t mfn; /* MACHINE page number of console page. */
++ uint32_t evtchn; /* Event channel for console page. */
++ } domU;
++ struct {
++ uint32_t info_off; /* Offset of console_info struct. */
++ uint32_t info_size; /* Size of console_info struct from start.*/
++ } dom0;
++ } console;
++ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */
++ unsigned long pt_base; /* VIRTUAL address of page directory. */
++ unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */
++ unsigned long mfn_list; /* VIRTUAL address of page-frame list. */
++ unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */
++ unsigned long mod_len; /* Size (bytes) of pre-loaded module. */
++ int8_t cmd_line[MAX_GUEST_CMDLINE];
++};
++typedef struct start_info start_info_t;
++
++/* New console union for dom0 introduced in 0x00030203. */
++#if __XEN_INTERFACE_VERSION__ < 0x00030203
++#define console_mfn console.domU.mfn
++#define console_evtchn console.domU.evtchn
++#endif
++
++/* These flags are passed in the 'flags' field of start_info_t. */
++#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
++#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
++
++typedef struct dom0_vga_console_info {
++ uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */
++#define XEN_VGATYPE_TEXT_MODE_3 0x03
++#define XEN_VGATYPE_VESA_LFB 0x23
++
++ union {
++ struct {
++ /* Font height, in pixels. */
++ uint16_t font_height;
++ /* Cursor location (column, row). */
++ uint16_t cursor_x, cursor_y;
++ /* Number of rows and columns (dimensions in characters). */
++ uint16_t rows, columns;
++ } text_mode_3;
++
++ struct {
++ /* Width and height, in pixels. */
++ uint16_t width, height;
++ /* Bytes per scan line. */
++ uint16_t bytes_per_line;
++ /* Bits per pixel. */
++ uint16_t bits_per_pixel;
++ /* LFB physical address, and size (in units of 64kB). */
++ uint32_t lfb_base;
++ uint32_t lfb_size;
++ /* RGB mask offsets and sizes, as defined by VBE 1.2+ */
++ uint8_t red_pos, red_size;
++ uint8_t green_pos, green_size;
++ uint8_t blue_pos, blue_size;
++ uint8_t rsvd_pos, rsvd_size;
++ } vesa_lfb;
++ } u;
++} dom0_vga_console_info_t;
++
++typedef uint8_t xen_domain_handle_t[16];
++
++/* Turn a plain number into a C unsigned long constant. */
++#define __mk_unsigned_long(x) x ## UL
++#define mk_unsigned_long(x) __mk_unsigned_long(x)
++
++DEFINE_XEN_GUEST_HANDLE(uint8_t);
++DEFINE_XEN_GUEST_HANDLE(uint16_t);
++DEFINE_XEN_GUEST_HANDLE(uint32_t);
++DEFINE_XEN_GUEST_HANDLE(uint64_t);
++
++#else /* __ASSEMBLY__ */
++
++/* In assembly code we cannot use C numeric constant suffixes. */
++#define mk_unsigned_long(x) x
++
++#endif /* !__ASSEMBLY__ */
++
++#endif /* __XEN_PUBLIC_XEN_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/interface/xenoprof.h linux-2.6.18-xen/include/xen/interface/xenoprof.h
+--- linux-2.6.18.1/include/xen/interface/xenoprof.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/interface/xenoprof.h 2006-09-21 01:33:32.000000000 +0200
+@@ -0,0 +1,110 @@
++/******************************************************************************
++ * xenoprof.h
++ *
++ * Interface for enabling system wide profiling based on hardware performance
++ * counters
++ *
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ * Written by Aravind Menon & Jose Renato Santos
++ */
++
++#ifndef __XEN_PUBLIC_XENOPROF_H__
++#define __XEN_PUBLIC_XENOPROF_H__
++
++/*
++ * Commands to HYPERVISOR_xenoprof_op().
++ */
++#define XENOPROF_init 0
++#define XENOPROF_reset_active_list 1
++#define XENOPROF_reset_passive_list 2
++#define XENOPROF_set_active 3
++#define XENOPROF_set_passive 4
++#define XENOPROF_reserve_counters 5
++#define XENOPROF_counter 6
++#define XENOPROF_setup_events 7
++#define XENOPROF_enable_virq 8
++#define XENOPROF_start 9
++#define XENOPROF_stop 10
++#define XENOPROF_disable_virq 11
++#define XENOPROF_release_counters 12
++#define XENOPROF_shutdown 13
++#define XENOPROF_get_buffer 14
++#define XENOPROF_last_op 14
++
++#define MAX_OPROF_EVENTS 32
++#define MAX_OPROF_DOMAINS 25
++#define XENOPROF_CPU_TYPE_SIZE 64
++
++/* Xenoprof performance events (not Xen events) */
++struct event_log {
++ uint64_t eip;
++ uint8_t mode;
++ uint8_t event;
++};
++
++/* Xenoprof buffer shared between Xen and domain - 1 per VCPU */
++struct xenoprof_buf {
++ uint32_t event_head;
++ uint32_t event_tail;
++ uint32_t event_size;
++ uint32_t vcpu_id;
++ uint64_t xen_samples;
++ uint64_t kernel_samples;
++ uint64_t user_samples;
++ uint64_t lost_samples;
++ struct event_log event_log[1];
++};
++typedef struct xenoprof_buf xenoprof_buf_t;
++DEFINE_XEN_GUEST_HANDLE(xenoprof_buf_t);
++
++struct xenoprof_init {
++ int32_t num_events;
++ int32_t is_primary;
++ char cpu_type[XENOPROF_CPU_TYPE_SIZE];
++};
++typedef struct xenoprof_init xenoprof_init_t;
++DEFINE_XEN_GUEST_HANDLE(xenoprof_init_t);
++
++struct xenoprof_get_buffer {
++ int32_t max_samples;
++ int32_t nbuf;
++ int32_t bufsize;
++ uint64_t buf_maddr;
++};
++typedef struct xenoprof_get_buffer xenoprof_get_buffer_t;
++DEFINE_XEN_GUEST_HANDLE(xenoprof_get_buffer_t);
++
++struct xenoprof_counter {
++ uint32_t ind;
++ uint64_t count;
++ uint32_t enabled;
++ uint32_t event;
++ uint32_t hypervisor;
++ uint32_t kernel;
++ uint32_t user;
++ uint64_t unit_mask;
++};
++typedef struct xenoprof_counter xenoprof_counter_t;
++DEFINE_XEN_GUEST_HANDLE(xenoprof_counter_t);
++
++typedef struct xenoprof_passive {
++ uint16_t domain_id;
++ int32_t max_samples;
++ int32_t nbuf;
++ int32_t bufsize;
++ uint64_t buf_maddr;
++} xenoprof_passive_t;
++DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t);
++
++
++#endif /* __XEN_PUBLIC_XENOPROF_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/pcifront.h linux-2.6.18-xen/include/xen/pcifront.h
+--- linux-2.6.18.1/include/xen/pcifront.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/pcifront.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,76 @@
++/*
++ * PCI Frontend - arch-dependendent declarations
++ *
++ * Author: Ryan Wilson <hap9 at epoch.ncsc.mil>
++ */
++#ifndef __XEN_ASM_PCIFRONT_H__
++#define __XEN_ASM_PCIFRONT_H__
++
++#include <linux/spinlock.h>
++
++#ifdef __KERNEL__
++
++#ifndef __ia64__
++
++struct pcifront_device;
++struct pci_bus;
++
++struct pcifront_sd {
++ int domain;
++ struct pcifront_device *pdev;
++};
++
++static inline struct pcifront_device *
++pcifront_get_pdev(struct pcifront_sd *sd)
++{
++ return sd->pdev;
++}
++
++static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain,
++ struct pcifront_device *pdev)
++{
++ sd->domain = domain;
++ sd->pdev = pdev;
++}
++
++#if defined(CONFIG_PCI_DOMAINS)
++static inline int pci_domain_nr(struct pci_bus *bus)
++{
++ struct pcifront_sd *sd = bus->sysdata;
++ return sd->domain;
++}
++static inline int pci_proc_domain(struct pci_bus *bus)
++{
++ return pci_domain_nr(bus);
++}
++#endif /* CONFIG_PCI_DOMAINS */
++
++#else /* __ia64__ */
++
++#include <asm/pci.h>
++#define pcifront_sd pci_controller
++
++static inline struct pcifront_device *
++pcifront_get_pdev(struct pcifront_sd *sd)
++{
++ return (struct pcifront_device *)sd->platform_data;
++}
++
++static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain,
++ struct pcifront_device *pdev)
++{
++ sd->segment = domain;
++ sd->acpi_handle = NULL;
++ sd->iommu = NULL;
++ sd->windows = 0;
++ sd->window = NULL;
++ sd->platform_data = pdev;
++}
++
++#endif /* __ia64__ */
++
++extern struct rw_semaphore pci_bus_sem;
++
++#endif /* __KERNEL__ */
++
++#endif /* __XEN_ASM_PCIFRONT_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/public/evtchn.h linux-2.6.18-xen/include/xen/public/evtchn.h
+--- linux-2.6.18.1/include/xen/public/evtchn.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/public/evtchn.h 2006-10-17 15:01:58.000000000 +0200
+@@ -0,0 +1,88 @@
++/******************************************************************************
++ * evtchn.h
++ *
++ * Interface to /dev/xen/evtchn.
++ *
++ * Copyright (c) 2003-2005, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __LINUX_PUBLIC_EVTCHN_H__
++#define __LINUX_PUBLIC_EVTCHN_H__
++
++/*
++ * Bind a fresh port to VIRQ @virq.
++ * Return allocated port.
++ */
++#define IOCTL_EVTCHN_BIND_VIRQ \
++ _IOC(_IOC_NONE, 'E', 0, sizeof(struct ioctl_evtchn_bind_virq))
++struct ioctl_evtchn_bind_virq {
++ unsigned int virq;
++};
++
++/*
++ * Bind a fresh port to remote <@remote_domain, @remote_port>.
++ * Return allocated port.
++ */
++#define IOCTL_EVTCHN_BIND_INTERDOMAIN \
++ _IOC(_IOC_NONE, 'E', 1, sizeof(struct ioctl_evtchn_bind_interdomain))
++struct ioctl_evtchn_bind_interdomain {
++ unsigned int remote_domain, remote_port;
++};
++
++/*
++ * Allocate a fresh port for binding to @remote_domain.
++ * Return allocated port.
++ */
++#define IOCTL_EVTCHN_BIND_UNBOUND_PORT \
++ _IOC(_IOC_NONE, 'E', 2, sizeof(struct ioctl_evtchn_bind_unbound_port))
++struct ioctl_evtchn_bind_unbound_port {
++ unsigned int remote_domain;
++};
++
++/*
++ * Unbind previously allocated @port.
++ */
++#define IOCTL_EVTCHN_UNBIND \
++ _IOC(_IOC_NONE, 'E', 3, sizeof(struct ioctl_evtchn_unbind))
++struct ioctl_evtchn_unbind {
++ unsigned int port;
++};
++
++/*
++ * Unbind previously allocated @port.
++ */
++#define IOCTL_EVTCHN_NOTIFY \
++ _IOC(_IOC_NONE, 'E', 4, sizeof(struct ioctl_evtchn_notify))
++struct ioctl_evtchn_notify {
++ unsigned int port;
++};
++
++/* Clear and reinitialise the event buffer. Clear error condition. */
++#define IOCTL_EVTCHN_RESET \
++ _IOC(_IOC_NONE, 'E', 5, 0)
++
++#endif /* __LINUX_PUBLIC_EVTCHN_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/public/privcmd.h linux-2.6.18-xen/include/xen/public/privcmd.h
+--- linux-2.6.18.1/include/xen/public/privcmd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/public/privcmd.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,79 @@
++/******************************************************************************
++ * privcmd.h
++ *
++ * Interface to /proc/xen/privcmd.
++ *
++ * Copyright (c) 2003-2005, K A Fraser
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 __LINUX_PUBLIC_PRIVCMD_H__
++#define __LINUX_PUBLIC_PRIVCMD_H__
++
++#include <linux/types.h>
++
++#ifndef __user
++#define __user
++#endif
++
++typedef struct privcmd_hypercall
++{
++ __u64 op;
++ __u64 arg[5];
++} privcmd_hypercall_t;
++
++typedef struct privcmd_mmap_entry {
++ __u64 va;
++ __u64 mfn;
++ __u64 npages;
++} privcmd_mmap_entry_t;
++
++typedef struct privcmd_mmap {
++ int num;
++ domid_t dom; /* target domain */
++ privcmd_mmap_entry_t __user *entry;
++} privcmd_mmap_t;
++
++typedef struct privcmd_mmapbatch {
++ int num; /* number of pages to populate */
++ domid_t dom; /* target domain */
++ __u64 addr; /* virtual address */
++ xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */
++} privcmd_mmapbatch_t;
++
++/*
++ * @cmd: IOCTL_PRIVCMD_HYPERCALL
++ * @arg: &privcmd_hypercall_t
++ * Return: Value returned from execution of the specified hypercall.
++ */
++#define IOCTL_PRIVCMD_HYPERCALL \
++ _IOC(_IOC_NONE, 'P', 0, sizeof(privcmd_hypercall_t))
++#define IOCTL_PRIVCMD_MMAP \
++ _IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t))
++#define IOCTL_PRIVCMD_MMAPBATCH \
++ _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t))
++
++#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/xenbus.h linux-2.6.18-xen/include/xen/xenbus.h
+--- linux-2.6.18.1/include/xen/xenbus.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/xenbus.h 2006-09-21 01:33:32.000000000 +0200
+@@ -0,0 +1,306 @@
++/******************************************************************************
++ * xenbus.h
++ *
++ * Talks to Xen Store to figure out what devices we have.
++ *
++ * Copyright (C) 2005 Rusty Russell, IBM Corporation
++ * Copyright (C) 2005 XenSource Ltd.
++ *
++ * 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; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (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 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
++ * 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 _XEN_XENBUS_H
++#define _XEN_XENBUS_H
++
++#include <linux/device.h>
++#include <linux/notifier.h>
++#include <linux/mutex.h>
++#include <linux/completion.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/grant_table.h>
++#include <xen/interface/io/xenbus.h>
++#include <xen/interface/io/xs_wire.h>
++
++/* Register callback to watch this node. */
++struct xenbus_watch
++{
++ struct list_head list;
++
++ /* Path being watched. */
++ const char *node;
++
++ /* Callback (executed in a process context with no locks held). */
++ void (*callback)(struct xenbus_watch *,
++ const char **vec, unsigned int len);
++
++ /* See XBWF_ definitions below. */
++ unsigned long flags;
++};
++
++/*
++ * Execute callback in its own kthread. Useful if the callback is long
++ * running or heavily serialised, to avoid taking out the main xenwatch thread
++ * for a long period of time (or even unwittingly causing a deadlock).
++ */
++#define XBWF_new_thread 1
++
++/* A xenbus device. */
++struct xenbus_device {
++ const char *devicetype;
++ const char *nodename;
++ const char *otherend;
++ int otherend_id;
++ struct xenbus_watch otherend_watch;
++ struct device dev;
++ enum xenbus_state state;
++ struct completion down;
++};
++
++static inline struct xenbus_device *to_xenbus_device(struct device *dev)
++{
++ return container_of(dev, struct xenbus_device, dev);
++}
++
++struct xenbus_device_id
++{
++ /* .../device/<device_type>/<identifier> */
++ char devicetype[32]; /* General class of device. */
++};
++
++/* A xenbus driver. */
++struct xenbus_driver {
++ char *name;
++ struct module *owner;
++ const struct xenbus_device_id *ids;
++ int (*probe)(struct xenbus_device *dev,
++ const struct xenbus_device_id *id);
++ void (*otherend_changed)(struct xenbus_device *dev,
++ enum xenbus_state backend_state);
++ int (*remove)(struct xenbus_device *dev);
++ int (*suspend)(struct xenbus_device *dev);
++ int (*resume)(struct xenbus_device *dev);
++ int (*uevent)(struct xenbus_device *, char **, int, char *, int);
++ struct device_driver driver;
++ int (*read_otherend_details)(struct xenbus_device *dev);
++};
++
++static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
++{
++ return container_of(drv, struct xenbus_driver, driver);
++}
++
++int xenbus_register_frontend(struct xenbus_driver *drv);
++int xenbus_register_backend(struct xenbus_driver *drv);
++void xenbus_unregister_driver(struct xenbus_driver *drv);
++
++struct xenbus_transaction
++{
++ u32 id;
++};
++
++/* Nil transaction ID. */
++#define XBT_NIL ((struct xenbus_transaction) { 0 })
++
++char **xenbus_directory(struct xenbus_transaction t,
++ const char *dir, const char *node, unsigned int *num);
++void *xenbus_read(struct xenbus_transaction t,
++ const char *dir, const char *node, unsigned int *len);
++int xenbus_write(struct xenbus_transaction t,
++ const char *dir, const char *node, const char *string);
++int xenbus_mkdir(struct xenbus_transaction t,
++ const char *dir, const char *node);
++int xenbus_exists(struct xenbus_transaction t,
++ const char *dir, const char *node);
++int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node);
++int xenbus_transaction_start(struct xenbus_transaction *t);
++int xenbus_transaction_end(struct xenbus_transaction t, int abort);
++
++/* Single read and scanf: returns -errno or num scanned if > 0. */
++int xenbus_scanf(struct xenbus_transaction t,
++ const char *dir, const char *node, const char *fmt, ...)
++ __attribute__((format(scanf, 4, 5)));
++
++/* Single printf and write: returns -errno or 0. */
++int xenbus_printf(struct xenbus_transaction t,
++ const char *dir, const char *node, const char *fmt, ...)
++ __attribute__((format(printf, 4, 5)));
++
++/* Generic read function: NULL-terminated triples of name,
++ * sprintf-style type string, and pointer. Returns 0 or errno.*/
++int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
++
++/* notifer routines for when the xenstore comes up */
++int register_xenstore_notifier(struct notifier_block *nb);
++void unregister_xenstore_notifier(struct notifier_block *nb);
++
++int register_xenbus_watch(struct xenbus_watch *watch);
++void unregister_xenbus_watch(struct xenbus_watch *watch);
++void xs_suspend(void);
++void xs_resume(void);
++
++/* Used by xenbus_dev to borrow kernel's store connection. */
++void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
++
++/* Called from xen core code. */
++void xenbus_suspend(void);
++void xenbus_resume(void);
++
++#define XENBUS_IS_ERR_READ(str) ({ \
++ if (!IS_ERR(str) && strlen(str) == 0) { \
++ kfree(str); \
++ str = ERR_PTR(-ERANGE); \
++ } \
++ IS_ERR(str); \
++})
++
++#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
++
++
++/**
++ * Register a watch on the given path, using the given xenbus_watch structure
++ * for storage, and the given callback function as the callback. Return 0 on
++ * success, or -errno on error. On success, the given path will be saved as
++ * watch->node, and remains the caller's to free. On error, watch->node will
++ * be NULL, the device will switch to XenbusStateClosing, and the error will
++ * be saved in the store.
++ */
++int xenbus_watch_path(struct xenbus_device *dev, const char *path,
++ struct xenbus_watch *watch,
++ void (*callback)(struct xenbus_watch *,
++ const char **, unsigned int));
++
++
++/**
++ * Register a watch on the given path/path2, using the given xenbus_watch
++ * structure for storage, and the given callback function as the callback.
++ * Return 0 on success, or -errno on error. On success, the watched path
++ * (path/path2) will be saved as watch->node, and becomes the caller's to
++ * kfree(). On error, watch->node will be NULL, so the caller has nothing to
++ * free, the device will switch to XenbusStateClosing, and the error will be
++ * saved in the store.
++ */
++int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
++ const char *path2, struct xenbus_watch *watch,
++ void (*callback)(struct xenbus_watch *,
++ const char **, unsigned int));
++
++
++/**
++ * Advertise in the store a change of the given driver to the given new_state.
++ * Return 0 on success, or -errno on error. On error, the device will switch
++ * to XenbusStateClosing, and the error will be saved in the store.
++ */
++int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
++
++
++/**
++ * Grant access to the given ring_mfn to the peer of the given device. Return
++ * 0 on success, or -errno on error. On error, the device will switch to
++ * XenbusStateClosing, and the error will be saved in the store.
++ */
++int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
++
++
++/**
++ * Map a page of memory into this domain from another domain's grant table.
++ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
++ * page to that address, and sets *vaddr to that address.
++ * xenbus_map_ring does not allocate the virtual address space (you must do
++ * this yourself!). It only maps in the page to the specified address.
++ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
++ * or -ENOMEM on error. If an error is returned, device will switch to
++ * XenbusStateClosing and the error message will be saved in XenStore.
++ */
++struct vm_struct *xenbus_map_ring_valloc(struct xenbus_device *dev,
++ int gnt_ref);
++int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
++ grant_handle_t *handle, void *vaddr);
++
++
++/**
++ * Unmap a page of memory in this domain that was imported from another domain.
++ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
++ * xenbus_map_ring_valloc (it will free the virtual address space).
++ * Returns 0 on success and returns GNTST_* on error
++ * (see xen/include/interface/grant_table.h).
++ */
++int xenbus_unmap_ring_vfree(struct xenbus_device *dev, struct vm_struct *);
++int xenbus_unmap_ring(struct xenbus_device *dev,
++ grant_handle_t handle, void *vaddr);
++
++
++/**
++ * Allocate an event channel for the given xenbus_device, assigning the newly
++ * created local port to *port. Return 0 on success, or -errno on error. On
++ * error, the device will switch to XenbusStateClosing, and the error will be
++ * saved in the store.
++ */
++int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
++
++
++/**
++ * Bind to an existing interdomain event channel in another domain. Returns 0
++ * on success and stores the local port in *port. On error, returns -errno,
++ * switches the device to XenbusStateClosing, and saves the error in XenStore.
++ */
++int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port);
++
++
++/**
++ * Free an existing event channel. Returns 0 on success or -errno on error.
++ */
++int xenbus_free_evtchn(struct xenbus_device *dev, int port);
++
++
++/**
++ * Return the state of the driver rooted at the given store path, or
++ * XenbusStateUnknown if no state can be read.
++ */
++enum xenbus_state xenbus_read_driver_state(const char *path);
++
++
++/***
++ * Report the given negative errno into the store, along with the given
++ * formatted message.
++ */
++void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
++ ...);
++
++
++/***
++ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
++ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
++ * closedown of this driver and its peer.
++ */
++void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
++ ...);
++
++int __init xenbus_dev_init(void);
++
++char *xenbus_strstate(enum xenbus_state state);
++int xenbus_dev_is_online(struct xenbus_device *dev);
++int xenbus_frontend_closed(struct xenbus_device *dev);
++
++#endif /* _XEN_XENBUS_H */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/xencons.h linux-2.6.18-xen/include/xen/xencons.h
+--- linux-2.6.18.1/include/xen/xencons.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/xencons.h 2006-09-21 01:33:32.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef __ASM_XENCONS_H__
++#define __ASM_XENCONS_H__
++
++struct dom0_vga_console_info;
++void dom0_init_screen_info(const struct dom0_vga_console_info *info);
++
++void xencons_force_flush(void);
++void xencons_resume(void);
++
++/* Interrupt work hooks. Receive data, or kick data out. */
++void xencons_rx(char *buf, unsigned len, struct pt_regs *regs);
++void xencons_tx(void);
++
++int xencons_ring_init(void);
++int xencons_ring_send(const char *data, unsigned len);
++
++#endif /* __ASM_XENCONS_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/include/xen/xen_proc.h linux-2.6.18-xen/include/xen/xen_proc.h
+--- linux-2.6.18.1/include/xen/xen_proc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/include/xen/xen_proc.h 2006-09-04 16:31:20.000000000 +0200
+@@ -0,0 +1,12 @@
++
++#ifndef __ASM_XEN_PROC_H__
++#define __ASM_XEN_PROC_H__
++
++#include <linux/proc_fs.h>
++
++extern struct proc_dir_entry *create_xen_proc_entry(
++ const char *name, mode_t mode);
++extern void remove_xen_proc_entry(
++ const char *name);
++
++#endif /* __ASM_XEN_PROC_H__ */
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/kernel/fork.c linux-2.6.18-xen/kernel/fork.c
+--- linux-2.6.18.1/kernel/fork.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/kernel/fork.c 2006-09-05 10:45:48.000000000 +0200
+@@ -276,6 +276,9 @@
+ if (retval)
+ goto out;
+ }
++#ifdef arch_dup_mmap
++ arch_dup_mmap(mm, oldmm);
++#endif
+ retval = 0;
+ out:
+ up_write(&mm->mmap_sem);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/kernel/irq/manage.c linux-2.6.18-xen/kernel/irq/manage.c
+--- linux-2.6.18.1/kernel/irq/manage.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/kernel/irq/manage.c 2006-09-04 16:31:20.000000000 +0200
+@@ -350,7 +350,6 @@
+ struct irqaction **p;
+ unsigned long flags;
+
+- WARN_ON(in_interrupt());
+ if (irq >= NR_IRQS)
+ return;
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/kernel/Kconfig.preempt linux-2.6.18-xen/kernel/Kconfig.preempt
+--- linux-2.6.18.1/kernel/Kconfig.preempt 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/kernel/Kconfig.preempt 2006-09-04 16:31:20.000000000 +0200
+@@ -35,6 +35,7 @@
+
+ config PREEMPT
+ bool "Preemptible Kernel (Low-Latency Desktop)"
++ depends on !XEN
+ help
+ This option reduces the latency of the kernel by making
+ all kernel code (that is not executing in a critical section)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/lib/Kconfig.debug linux-2.6.18-xen/lib/Kconfig.debug
+--- linux-2.6.18.1/lib/Kconfig.debug 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/lib/Kconfig.debug 2006-09-04 16:31:20.000000000 +0200
+@@ -325,7 +325,7 @@
+
+ config UNWIND_INFO
+ bool "Compile the kernel with frame unwind information"
+- depends on !IA64 && !PARISC
++ depends on !IA64 && !PARISC && !X86_64_XEN
+ depends on !MODULES || !(MIPS || PPC || SUPERH || V850)
+ help
+ If you say Y here the resulting kernel image will be slightly larger
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/lib/Makefile linux-2.6.18-xen/lib/Makefile
+--- linux-2.6.18.1/lib/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/lib/Makefile 2006-10-17 15:01:59.000000000 +0200
+@@ -52,6 +52,7 @@
+ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
+
+ obj-$(CONFIG_SWIOTLB) += swiotlb.o
++swiotlb-$(CONFIG_XEN) := ../arch/i386/kernel/swiotlb.o
+
+ hostprogs-y := gen_crc32table
+ clean-files := crc32table.h
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/mm/highmem.c linux-2.6.18-xen/mm/highmem.c
+--- linux-2.6.18.1/mm/highmem.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/mm/highmem.c 2006-09-04 16:31:20.000000000 +0200
+@@ -142,6 +142,17 @@
+ return vaddr;
+ }
+
++#ifdef CONFIG_XEN
++void kmap_flush_unused(void)
++{
++ spin_lock(&kmap_lock);
++ flush_all_zero_pkmaps();
++ spin_unlock(&kmap_lock);
++}
++
++EXPORT_SYMBOL(kmap_flush_unused);
++#endif
++
+ void fastcall *kmap_high(struct page *page)
+ {
+ unsigned long vaddr;
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/mm/Kconfig linux-2.6.18-xen/mm/Kconfig
+--- linux-2.6.18.1/mm/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/mm/Kconfig 2006-09-22 16:38:35.000000000 +0200
+@@ -116,7 +116,6 @@
+ config MEMORY_HOTPLUG
+ bool "Allow for memory hot-add"
+ depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
+- depends on (IA64 || X86 || PPC64)
+
+ comment "Memory hotplug is currently incompatible with Software Suspend"
+ depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
+@@ -127,11 +126,14 @@
+ # Default to 4 for wider testing, though 8 might be more appropriate.
+ # ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock.
+ # PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes.
++# XEN on x86 architecture uses the mapping field on pagetable pages to store a
++# pointer to the destructor. This conflicts with pte_lock_deinit().
+ #
+ config SPLIT_PTLOCK_CPUS
+ int
+ default "4096" if ARM && !CPU_CACHE_VIPT
+ default "4096" if PARISC && !PA20
++ default "4096" if X86_XEN || X86_64_XEN
+ default "4"
+
+ #
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/mm/memory.c linux-2.6.18-xen/mm/memory.c
+--- linux-2.6.18.1/mm/memory.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/mm/memory.c 2006-10-17 15:01:59.000000000 +0200
+@@ -403,7 +403,8 @@
+ * and that the resulting page looks ok.
+ */
+ if (unlikely(!pfn_valid(pfn))) {
+- print_bad_pte(vma, pte, addr);
++ if (!(vma->vm_flags & VM_RESERVED))
++ print_bad_pte(vma, pte, addr);
+ return NULL;
+ }
+
+@@ -891,6 +892,7 @@
+ tlb_finish_mmu(tlb, address, end);
+ return end;
+ }
++EXPORT_SYMBOL(zap_page_range);
+
+ /*
+ * Do a quick page-table lookup for a single page.
+@@ -1030,6 +1032,26 @@
+ continue;
+ }
+
++#ifdef CONFIG_XEN
++ if (vma && (vma->vm_flags & VM_FOREIGN)) {
++ struct page **map = vma->vm_private_data;
++ int offset = (start - vma->vm_start) >> PAGE_SHIFT;
++ if (map[offset] != NULL) {
++ if (pages) {
++ struct page *page = map[offset];
++
++ pages[i] = page;
++ get_page(page);
++ }
++ if (vmas)
++ vmas[i] = vma;
++ i++;
++ start += PAGE_SIZE;
++ len--;
++ continue;
++ }
++ }
++#endif
+ if (!vma || (vma->vm_flags & (VM_IO | VM_PFNMAP))
+ || !(vm_flags & vma->vm_flags))
+ return i ? : -EFAULT;
+@@ -1369,6 +1391,102 @@
+ }
+ EXPORT_SYMBOL(remap_pfn_range);
+
++#ifdef CONFIG_XEN
++static inline int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
++ unsigned long addr, unsigned long end,
++ pte_fn_t fn, void *data)
++{
++ pte_t *pte;
++ int err;
++ struct page *pmd_page;
++ spinlock_t *ptl;
++
++ pte = (mm == &init_mm) ?
++ pte_alloc_kernel(pmd, addr) :
++ pte_alloc_map_lock(mm, pmd, addr, &ptl);
++ if (!pte)
++ return -ENOMEM;
++
++ BUG_ON(pmd_huge(*pmd));
++
++ pmd_page = pmd_page(*pmd);
++
++ do {
++ err = fn(pte, pmd_page, addr, data);
++ if (err)
++ break;
++ } while (pte++, addr += PAGE_SIZE, addr != end);
++
++ if (mm != &init_mm)
++ pte_unmap_unlock(pte-1, ptl);
++ return err;
++}
++
++static inline int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
++ unsigned long addr, unsigned long end,
++ pte_fn_t fn, void *data)
++{
++ pmd_t *pmd;
++ unsigned long next;
++ int err;
++
++ pmd = pmd_alloc(mm, pud, addr);
++ if (!pmd)
++ return -ENOMEM;
++ do {
++ next = pmd_addr_end(addr, end);
++ err = apply_to_pte_range(mm, pmd, addr, next, fn, data);
++ if (err)
++ break;
++ } while (pmd++, addr = next, addr != end);
++ return err;
++}
++
++static inline int apply_to_pud_range(struct mm_struct *mm, pgd_t *pgd,
++ unsigned long addr, unsigned long end,
++ pte_fn_t fn, void *data)
++{
++ pud_t *pud;
++ unsigned long next;
++ int err;
++
++ pud = pud_alloc(mm, pgd, addr);
++ if (!pud)
++ return -ENOMEM;
++ do {
++ next = pud_addr_end(addr, end);
++ err = apply_to_pmd_range(mm, pud, addr, next, fn, data);
++ if (err)
++ break;
++ } while (pud++, addr = next, addr != end);
++ return err;
++}
++
++/*
++ * Scan a region of virtual memory, filling in page tables as necessary
++ * and calling a provided function on each leaf page table.
++ */
++int apply_to_page_range(struct mm_struct *mm, unsigned long addr,
++ unsigned long size, pte_fn_t fn, void *data)
++{
++ pgd_t *pgd;
++ unsigned long next;
++ unsigned long end = addr + size;
++ int err;
++
++ BUG_ON(addr >= end);
++ pgd = pgd_offset(mm, addr);
++ do {
++ next = pgd_addr_end(addr, end);
++ err = apply_to_pud_range(mm, pgd, addr, next, fn, data);
++ if (err)
++ break;
++ } while (pgd++, addr = next, addr != end);
++ return err;
++}
++EXPORT_SYMBOL_GPL(apply_to_page_range);
++#endif
++
+ /*
+ * handle_pte_fault chooses page fault handler according to an entry
+ * which was read non-atomically. Before making any commitment, on
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/mm/mmap.c linux-2.6.18-xen/mm/mmap.c
+--- linux-2.6.18.1/mm/mmap.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/mm/mmap.c 2006-09-21 01:33:32.000000000 +0200
+@@ -1963,6 +1963,10 @@
+ unsigned long nr_accounted = 0;
+ unsigned long end;
+
++#ifdef arch_exit_mmap
++ arch_exit_mmap(mm);
++#endif
++
+ lru_add_drain();
+ flush_cache_mm(mm);
+ tlb = tlb_gather_mmu(mm, 1);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/mm/page_alloc.c linux-2.6.18-xen/mm/page_alloc.c
+--- linux-2.6.18.1/mm/page_alloc.c 2006-10-19 11:01:25.000000000 +0200
++++ linux-2.6.18-xen/mm/page_alloc.c 2006-10-17 15:01:59.000000000 +0200
+@@ -443,7 +443,8 @@
+ int i;
+ int reserved = 0;
+
+- arch_free_page(page, order);
++ if (arch_free_page(page, order))
++ return;
+ if (!PageHighMem(page))
+ debug_check_no_locks_freed(page_address(page),
+ PAGE_SIZE<<order);
+@@ -717,7 +718,8 @@
+ struct per_cpu_pages *pcp;
+ unsigned long flags;
+
+- arch_free_page(page, 0);
++ if (arch_free_page(page, 0))
++ return;
+
+ if (PageAnon(page))
+ page->mapping = NULL;
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/net/core/dev.c linux-2.6.18-xen/net/core/dev.c
+--- linux-2.6.18.1/net/core/dev.c 2006-10-19 11:01:25.000000000 +0200
++++ linux-2.6.18-xen/net/core/dev.c 2006-10-17 15:01:59.000000000 +0200
+@@ -118,6 +118,12 @@
+ #include <linux/err.h>
+ #include <linux/ctype.h>
+
++#ifdef CONFIG_XEN
++#include <net/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#endif
++
+ /*
+ * The list of packet types we will receive (as opposed to discard)
+ * and the routines to invoke.
+@@ -1391,6 +1397,43 @@
+ } \
+ }
+
++#ifdef CONFIG_XEN
++inline int skb_checksum_setup(struct sk_buff *skb)
++{
++ if (skb->proto_csum_blank) {
++ if (skb->protocol != htons(ETH_P_IP))
++ goto out;
++ skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
++ if (skb->h.raw >= skb->tail)
++ goto out;
++ switch (skb->nh.iph->protocol) {
++ case IPPROTO_TCP:
++ skb->csum = offsetof(struct tcphdr, check);
++ break;
++ case IPPROTO_UDP:
++ skb->csum = offsetof(struct udphdr, check);
++ break;
++ default:
++ if (net_ratelimit())
++ printk(KERN_ERR "Attempting to checksum a non-"
++ "TCP/UDP packet, dropping a protocol"
++ " %d packet", skb->nh.iph->protocol);
++ goto out;
++ }
++ if ((skb->h.raw + skb->csum + 2) > skb->tail)
++ goto out;
++ skb->ip_summed = CHECKSUM_HW;
++ skb->proto_csum_blank = 0;
++ }
++ return 0;
++out:
++ return -EPROTO;
++}
++#else
++inline int skb_checksum_setup(struct sk_buff *skb) { return 0; }
++#endif
++
++
+ /**
+ * dev_queue_xmit - transmit a buffer
+ * @skb: buffer to transmit
+@@ -1423,6 +1466,12 @@
+ struct Qdisc *q;
+ int rc = -ENOMEM;
+
++ /* If a checksum-deferred packet is forwarded to a device that needs a
++ * checksum, correct the pointers and force checksumming.
++ */
++ if (skb_checksum_setup(skb))
++ goto out_kfree_skb;
++
+ /* GSO will handle the following emulations directly. */
+ if (netif_needs_gso(dev, skb))
+ goto gso;
+@@ -1798,6 +1847,19 @@
+ }
+ #endif
+
++#ifdef CONFIG_XEN
++ switch (skb->ip_summed) {
++ case CHECKSUM_UNNECESSARY:
++ skb->proto_data_valid = 1;
++ break;
++ case CHECKSUM_HW:
++ /* XXX Implement me. */
++ default:
++ skb->proto_data_valid = 0;
++ break;
++ }
++#endif
++
+ list_for_each_entry_rcu(ptype, &ptype_all, list) {
+ if (!ptype->dev || ptype->dev == skb->dev) {
+ if (pt_prev)
+@@ -3584,6 +3646,7 @@
+ EXPORT_SYMBOL(net_enable_timestamp);
+ EXPORT_SYMBOL(net_disable_timestamp);
+ EXPORT_SYMBOL(dev_get_flags);
++EXPORT_SYMBOL(skb_checksum_setup);
+
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ EXPORT_SYMBOL(br_handle_frame_hook);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/net/core/skbuff.c linux-2.6.18-xen/net/core/skbuff.c
+--- linux-2.6.18.1/net/core/skbuff.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/net/core/skbuff.c 2006-09-04 16:31:21.000000000 +0200
+@@ -139,6 +139,7 @@
+ * Buffers may only be allocated from interrupts using a @gfp_mask of
+ * %GFP_ATOMIC.
+ */
++#ifndef CONFIG_HAVE_ARCH_ALLOC_SKB
+ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
+ int fclone)
+ {
+@@ -193,6 +194,7 @@
+ skb = NULL;
+ goto out;
+ }
++#endif /* !CONFIG_HAVE_ARCH_ALLOC_SKB */
+
+ /**
+ * alloc_skb_from_cache - allocate a network buffer
+@@ -210,14 +212,17 @@
+ */
+ struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
+ unsigned int size,
+- gfp_t gfp_mask)
++ gfp_t gfp_mask,
++ int fclone)
+ {
++ kmem_cache_t *cache;
+ struct sk_buff *skb;
+ u8 *data;
+
++ cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;
++
+ /* Get the HEAD */
+- skb = kmem_cache_alloc(skbuff_head_cache,
+- gfp_mask & ~__GFP_DMA);
++ skb = kmem_cache_alloc(cache, gfp_mask & ~__GFP_DMA);
+ if (!skb)
+ goto out;
+
+@@ -241,10 +246,20 @@
+ skb_shinfo(skb)->gso_segs = 0;
+ skb_shinfo(skb)->gso_type = 0;
+ skb_shinfo(skb)->frag_list = NULL;
++
++ if (fclone) {
++ struct sk_buff *child = skb + 1;
++ atomic_t *fclone_ref = (atomic_t *) (child + 1);
++
++ skb->fclone = SKB_FCLONE_ORIG;
++ atomic_set(fclone_ref, 1);
++
++ child->fclone = SKB_FCLONE_UNAVAILABLE;
++ }
+ out:
+ return skb;
+ nodata:
+- kmem_cache_free(skbuff_head_cache, skb);
++ kmem_cache_free(cache, skb);
+ skb = NULL;
+ goto out;
+ }
+@@ -464,6 +479,10 @@
+ C(local_df);
+ n->cloned = 1;
+ n->nohdr = 0;
++#ifdef CONFIG_XEN
++ C(proto_data_valid);
++ C(proto_csum_blank);
++#endif
+ C(pkt_type);
+ C(ip_summed);
+ C(priority);
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.6.18-xen/net/ipv4/netfilter/ip_nat_proto_tcp.c
+--- linux-2.6.18.1/net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-09-04 16:31:22.000000000 +0200
+@@ -129,7 +129,12 @@
+ if (hdrsize < sizeof(*hdr))
+ return 1;
+
+- hdr->check = ip_nat_cheat_check(~oldip, newip,
++#ifdef CONFIG_XEN
++ if ((*pskb)->proto_csum_blank)
++ hdr->check = ip_nat_cheat_check(oldip, ~newip, hdr->check);
++ else
++#endif
++ hdr->check = ip_nat_cheat_check(~oldip, newip,
+ ip_nat_cheat_check(oldport ^ 0xFFFF,
+ newport,
+ hdr->check));
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/net/ipv4/netfilter/ip_nat_proto_udp.c linux-2.6.18-xen/net/ipv4/netfilter/ip_nat_proto_udp.c
+--- linux-2.6.18.1/net/ipv4/netfilter/ip_nat_proto_udp.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/net/ipv4/netfilter/ip_nat_proto_udp.c 2006-09-04 16:31:22.000000000 +0200
+@@ -114,7 +114,12 @@
+ portptr = &hdr->dest;
+ }
+ if (hdr->check) /* 0 is a special case meaning no checksum */
+- hdr->check = ip_nat_cheat_check(~oldip, newip,
++#ifdef CONFIG_XEN
++ if ((*pskb)->proto_csum_blank)
++ hdr->check = ip_nat_cheat_check(oldip, ~newip, hdr->check);
++ else
++#endif
++ hdr->check = ip_nat_cheat_check(~oldip, newip,
+ ip_nat_cheat_check(*portptr ^ 0xFFFF,
+ newport,
+ hdr->check));
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/net/ipv4/xfrm4_output.c linux-2.6.18-xen/net/ipv4/xfrm4_output.c
+--- linux-2.6.18.1/net/ipv4/xfrm4_output.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/net/ipv4/xfrm4_output.c 2006-09-04 16:31:23.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <net/xfrm.h>
+ #include <net/icmp.h>
+
++extern int skb_checksum_setup(struct sk_buff *skb);
++
+ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
+ {
+ int mtu, ret = 0;
+@@ -48,6 +50,10 @@
+ struct xfrm_state *x = dst->xfrm;
+ int err;
+
++ err = skb_checksum_setup(skb);
++ if (err)
++ goto error_nolock;
++
+ if (skb->ip_summed == CHECKSUM_HW) {
+ err = skb_checksum_help(skb, 0);
+ if (err)
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/net/ipv6/addrconf.c linux-2.6.18-xen/net/ipv6/addrconf.c
+--- linux-2.6.18.1/net/ipv6/addrconf.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-xen/net/ipv6/addrconf.c 2006-09-04 16:31:23.000000000 +0200
+@@ -2514,6 +2514,7 @@
+ spin_lock_bh(&ifp->lock);
+
+ if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
++ !(dev->flags&IFF_MULTICAST) ||
+ !(ifp->flags&IFA_F_TENTATIVE)) {
+ ifp->flags &= ~IFA_F_TENTATIVE;
+ spin_unlock_bh(&ifp->lock);
+@@ -2598,6 +2599,7 @@
+ if (ifp->idev->cnf.forwarding == 0 &&
+ ifp->idev->cnf.rtr_solicits > 0 &&
+ (dev->flags&IFF_LOOPBACK) == 0 &&
++ (dev->flags & IFF_MULTICAST) &&
+ (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
+ struct in6_addr all_routers;
+
+diff -urN -x .hg -x .hgtags linux-2.6.18.1/scripts/Makefile.xen linux-2.6.18-xen/scripts/Makefile.xen
+--- linux-2.6.18.1/scripts/Makefile.xen 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-xen/scripts/Makefile.xen 2006-09-04 16:31:23.000000000 +0200
+@@ -0,0 +1,14 @@
++
++# cherrypickxen($1 = allobj)
++cherrypickxen = $(foreach var, $(1), \
++ $(shell o=$(var); \
++ c=$${o%.o}-xen.c; \
++ s=$${o%.o}-xen.S; \
++ oxen=$${o%.o}-xen.o; \
++ [ -f $(srctree)/$(src)/$${c} ] || \
++ [ -f $(srctree)/$(src)/$${s} ] \
++ && echo $$oxen \
++ || echo $(var) ) \
++ )
++# filterxen($1 = allobj, $2 = noobjs)
++filterxen = $(filter-out $(2), $(1))
Added: people/maks-guest/linux-2.6/debian/patches/features/all/xen/gen-patch-vserver-update
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/xen/gen-patch-vserver-update Sat Nov 11 02:48:00 2006
@@ -0,0 +1,25 @@
+#!/bin/sh
+set -e
+vserverpatch="$1"
+
+error() {
+ echo "$@";
+ exit 1
+}
+
+[ "$vserverpatch" ] || error "please specify the reference vserver patch"
+
+patch="$(dirname $0)/vserver-update.patch"
+root="$(dirname $0)/../../../../.."
+source="$root/debian/build/source-amd64-xen-vserver-patch"
+
+make -C "$root" -f debian/rules debian/stamps
+make -C "$root" -f debian/rules.gen source-amd64-xen
+rm -rf "$source"
+cp -al "$root/debian/build/source-amd64-xen" "$source"
+
+for i in $(cd "$source"; find arch/i386 arch/x86_64 -name '*-xen.[chS]'); do
+ f=${i/-xen/};
+ filterdiff -p 1 -i "$f" "$vserverpatch" | patch -d "$source" --no-backup-if-mismatch -F 0 -p 1 $i
+done
+(cd "$source/.."; diff -ur source-amd64-xen/arch source-amd64-xen-vserver-patch/arch) > "$patch"
Added: people/maks-guest/linux-2.6/debian/patches/features/all/xen/vserver-clash.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/xen/vserver-clash.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,16 @@
+diff -urN test1/net/core/dev.c test2/net/core/dev.c
+--- test1/net/core/dev.c 2006-09-25 21:01:06.000000000 +0200
++++ test2/net/core/dev.c 2006-09-25 21:01:44.000000000 +0200
+@@ -113,11 +113,11 @@
+ #include <linux/wireless.h>
+ #include <net/iw_handler.h>
+ #include <asm/current.h>
++#include <linux/vs_network.h>
+ #include <linux/audit.h>
+ #include <linux/dmaengine.h>
+ #include <linux/err.h>
+ #include <linux/ctype.h>
+-#include <linux/vs_network.h>
+
+ /*
+ * The list of packet types we will receive (as opposed to discard)
Added: people/maks-guest/linux-2.6/debian/patches/features/all/xen/vserver-update.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/all/xen/vserver-update.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,155 @@
+diff -ur source-amd64-xen/arch/i386/kernel/irq-xen.c source-amd64-xen-vserver-patch/arch/i386/kernel/irq-xen.c
+--- source-amd64-xen/arch/i386/kernel/irq-xen.c 2006-11-06 11:57:48.000000000 +0100
++++ source-amd64-xen-vserver-patch/arch/i386/kernel/irq-xen.c 2006-11-06 12:06:08.000000000 +0100
+@@ -18,6 +18,7 @@
+ #include <linux/notifier.h>
+ #include <linux/cpu.h>
+ #include <linux/delay.h>
++#include <linux/vs_context.h>
+
+ DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
+ EXPORT_PER_CPU_SYMBOL(irq_stat);
+@@ -55,6 +56,7 @@
+ {
+ /* high bit used in ret_from_ code */
+ int irq = ~regs->orig_eax;
++ struct vx_info_save vxis;
+ #ifdef CONFIG_4KSTACKS
+ union irq_ctx *curctx, *irqctx;
+ u32 *isp;
+@@ -81,7 +83,7 @@
+ }
+ }
+ #endif
+-
++ __enter_vx_admin(&vxis);
+ #ifdef CONFIG_4KSTACKS
+
+ curctx = (union irq_ctx *) current_thread_info();
+@@ -120,6 +122,7 @@
+ } else
+ #endif
+ __do_IRQ(irq, regs);
++ __leave_vx_admin(&vxis);
+
+ irq_exit();
+
+diff -ur source-amd64-xen/arch/i386/kernel/traps-xen.c source-amd64-xen-vserver-patch/arch/i386/kernel/traps-xen.c
+--- source-amd64-xen/arch/i386/kernel/traps-xen.c 2006-11-06 11:57:48.000000000 +0100
++++ source-amd64-xen-vserver-patch/arch/i386/kernel/traps-xen.c 2006-11-06 12:06:08.000000000 +0100
+@@ -53,6 +53,7 @@
+ #include <asm/kdebug.h>
+
+ #include <linux/module.h>
++#include <linux/vserver/debug.h>
+
+ #include "mach_traps.h"
+
+@@ -309,8 +310,8 @@
+ regs->esi, regs->edi, regs->ebp, esp);
+ printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n",
+ regs->xds & 0xffff, regs->xes & 0xffff, ss);
+- printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
+- TASK_COMM_LEN, current->comm, current->pid,
++ printk(KERN_EMERG "Process %.*s (pid: %d[#%u], ti=%p task=%p task.ti=%p)",
++ TASK_COMM_LEN, current->comm, current->pid, current->xid,
+ current_thread_info(), current, current->thread_info);
+ /*
+ * When in-kernel, we also print out the stack and code at the
+@@ -392,6 +393,8 @@
+
+ oops_enter();
+
++ vxh_throw_oops();
++
+ if (die.lock_owner != raw_smp_processor_id()) {
+ console_verbose();
+ spin_lock_irqsave(&die.lock, flags);
+@@ -428,9 +431,9 @@
+ if (nl)
+ printk("\n");
+ if (notify_die(DIE_OOPS, str, regs, err,
+- current->thread.trap_no, SIGSEGV) !=
+- NOTIFY_STOP) {
++ current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) {
+ show_registers(regs);
++ vxh_dump_history();
+ /* Executive summary in case the oops scrolled away */
+ esp = (unsigned long) (®s->esp);
+ savesegment(ss, ss);
+diff -ur source-amd64-xen/arch/x86_64/ia32/ia32entry-xen.S source-amd64-xen-vserver-patch/arch/x86_64/ia32/ia32entry-xen.S
+--- source-amd64-xen/arch/x86_64/ia32/ia32entry-xen.S 2006-11-06 11:57:48.000000000 +0100
++++ source-amd64-xen-vserver-patch/arch/x86_64/ia32/ia32entry-xen.S 2006-11-06 12:06:08.000000000 +0100
+@@ -695,7 +695,7 @@
+ .quad sys_tgkill /* 270 */
+ .quad compat_sys_utimes
+ .quad sys32_fadvise64_64
+- .quad quiet_ni_syscall /* sys_vserver */
++ .quad sys32_vserver
+ .quad sys_mbind
+ .quad compat_sys_get_mempolicy /* 275 */
+ .quad sys_set_mempolicy
+diff -ur source-amd64-xen/arch/x86_64/ia32/syscall32-xen.c source-amd64-xen-vserver-patch/arch/x86_64/ia32/syscall32-xen.c
+--- source-amd64-xen/arch/x86_64/ia32/syscall32-xen.c 2006-11-06 11:57:48.000000000 +0100
++++ source-amd64-xen-vserver-patch/arch/x86_64/ia32/syscall32-xen.c 2006-11-06 12:06:08.000000000 +0100
+@@ -10,6 +10,7 @@
+ #include <linux/init.h>
+ #include <linux/stringify.h>
+ #include <linux/security.h>
++#include <linux/vs_memory.h>
+ #include <asm/proto.h>
+ #include <asm/tlbflush.h>
+ #include <asm/ia32_unistd.h>
+@@ -75,7 +76,7 @@
+ kmem_cache_free(vm_area_cachep, vma);
+ return ret;
+ }
+- mm->total_vm += npages;
++ vx_vmpages_add(mm, npages);
+ up_write(&mm->mmap_sem);
+ return 0;
+ }
+diff -ur source-amd64-xen/arch/x86_64/kernel/irq-xen.c source-amd64-xen-vserver-patch/arch/x86_64/kernel/irq-xen.c
+--- source-amd64-xen/arch/x86_64/kernel/irq-xen.c 2006-11-06 11:57:48.000000000 +0100
++++ source-amd64-xen-vserver-patch/arch/x86_64/kernel/irq-xen.c 2006-11-06 12:06:08.000000000 +0100
+@@ -15,6 +15,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/module.h>
+ #include <linux/delay.h>
++#include <linux/vs_context.h>
+ #include <asm/uaccess.h>
+ #include <asm/io_apic.h>
+ #include <asm/idle.h>
+@@ -117,6 +118,7 @@
+ {
+ /* high bit used in ret_from_ code */
+ unsigned irq = ~regs->orig_rax;
++ struct vx_info_save vxis;
+
+ if (unlikely(irq >= NR_IRQS)) {
+ printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+@@ -130,7 +132,9 @@
+ #ifdef CONFIG_DEBUG_STACKOVERFLOW
+ stack_overflow_check(regs);
+ #endif
++ __enter_vx_admin(&vxis);
+ __do_IRQ(irq, regs);
++ __leave_vx_admin(&vxis);
+ irq_exit();
+
+ return 1;
+diff -ur source-amd64-xen/arch/x86_64/kernel/traps-xen.c source-amd64-xen-vserver-patch/arch/x86_64/kernel/traps-xen.c
+--- source-amd64-xen/arch/x86_64/kernel/traps-xen.c 2006-11-06 11:57:48.000000000 +0100
++++ source-amd64-xen-vserver-patch/arch/x86_64/kernel/traps-xen.c 2006-11-06 12:06:08.000000000 +0100
+@@ -436,8 +436,9 @@
+
+ printk("CPU %d ", cpu);
+ __show_regs(regs);
+- printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
+- cur->comm, cur->pid, task_thread_info(cur), cur);
++ printk("Process %s (pid: %d[#%u], threadinfo %p, task %p)\n",
++ cur->comm, cur->pid, cur->xid,
++ task_thread_info(cur), cur);
+
+ /*
+ * When in-kernel, we also print out the stack and code at the
Added: people/maks-guest/linux-2.6/debian/patches/features/alpha/titan-video.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/alpha/titan-video.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,720 @@
+diff -uNr source/arch/alpha/Kconfig source-es45/arch/alpha/Kconfig
+--- source/arch/alpha/Kconfig 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/Kconfig 2006-09-30 03:14:44.000000000 -0700
+@@ -469,6 +469,11 @@
+ depends on ALPHA_GENERIC || ALPHA_PC164
+ default y
+
++config VGA_HOSE
++ bool "VGA on arbitrary hose"
++ depends on ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL || ALPHA_TSUNAMI
++ default y
++
+ config ALPHA_SRM
+ bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME
+ default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
+@@ -626,6 +631,13 @@
+
+ source "drivers/Kconfig"
+
++# DUMMY_CONSOLE may be defined in drivers/video/console/Kconfig
++# but we also need it if VGA_HOSE is set
++config DUMMY_CONSOLE
++ bool
++ depends on VGA_HOSE
++ default y
++
+ source "fs/Kconfig"
+
+ source "arch/alpha/oprofile/Kconfig"
+diff -uNr source/arch/alpha/kernel/alpha_ksyms.c source-es45/arch/alpha/kernel/alpha_ksyms.c
+--- source/arch/alpha/kernel/alpha_ksyms.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/alpha_ksyms.c 2006-09-30 03:14:44.000000000 -0700
+@@ -206,3 +206,7 @@
+ EXPORT_SYMBOL(irongate_ioremap);
+ EXPORT_SYMBOL(irongate_iounmap);
+ #endif
++
++#ifdef CONFIG_VGA_HOSE
++EXPORT_SYMBOL(pci_vga_hose);
++#endif
+diff -uNr source/arch/alpha/kernel/console.c source-es45/arch/alpha/kernel/console.c
+--- source/arch/alpha/kernel/console.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/console.c 2006-09-30 03:14:44.000000000 -0700
+@@ -8,17 +8,16 @@
+ #include <linux/pci.h>
+ #include <linux/init.h>
+ #include <linux/tty.h>
++#include <linux/vt.h>
+ #include <linux/console.h>
+ #include <asm/vga.h>
+ #include <asm/machvec.h>
+
++#include "pci_impl.h"
++
+ #ifdef CONFIG_VGA_HOSE
+
+-/*
+- * Externally-visible vga hose bases
+- */
+-unsigned long __vga_hose_io_base = 0; /* base for default hose */
+-unsigned long __vga_hose_mem_base = 0; /* base for default hose */
++struct pci_controller *pci_vga_hose = NULL;
+
+ static struct pci_controller * __init
+ default_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
+@@ -32,10 +31,7 @@
+ void __init
+ set_vga_hose(struct pci_controller *hose)
+ {
+- if (hose) {
+- __vga_hose_io_base = hose->io_space->start;
+- __vga_hose_mem_base = hose->mem_space->start;
+- }
++ pci_vga_hose = hose;
+ }
+
+ void __init
+@@ -44,18 +40,18 @@
+ struct pci_controller *hose = NULL;
+ struct pci_dev *dev = NULL;
+
++ /* Default the select function */
+ if (!sel_func) sel_func = (void *)default_vga_hose_select;
+
++ /* Find the console VGA device */
+ for(dev=NULL; (dev=pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) {
+ if (!hose) hose = dev->sysdata;
+ else hose = sel_func(hose, dev->sysdata);
+ }
+
+- /* Did we already inititialize the correct one? */
+- if (conswitchp == &vga_con &&
+- __vga_hose_io_base == hose->io_space->start &&
+- __vga_hose_mem_base == hose->mem_space->start)
+- return;
++ /* Did we already initialize the correct one? Is there one? */
++ if (!hose || (conswitchp == &vga_con && pci_vga_hose == hose))
++ return;
+
+ /* Set the VGA hose and init the new console */
+ set_vga_hose(hose);
+diff -uNr source/arch/alpha/kernel/core_marvel.c source-es45/arch/alpha/kernel/core_marvel.c
+--- source/arch/alpha/kernel/core_marvel.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/core_marvel.c 2006-09-30 03:14:44.000000000 -0700
+@@ -684,9 +684,6 @@
+ /*
+ * IO map support.
+ */
+-
+-#define __marvel_is_mem_vga(a) (((a) >= 0xa0000) && ((a) <= 0xc0000))
+-
+ void __iomem *
+ marvel_ioremap(unsigned long addr, unsigned long size)
+ {
+@@ -698,13 +695,9 @@
+ unsigned long pfn;
+
+ /*
+- * Adjust the addr.
++ * Adjust the address.
+ */
+-#ifdef CONFIG_VGA_HOSE
+- if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
+- addr += pci_vga_hose->mem_space->start;
+- }
+-#endif
++ FIXUP_MEMADDR_VGA(addr);
+
+ /*
+ * Find the hose.
+@@ -781,7 +774,7 @@
+ return (void __iomem *) vaddr;
+ }
+
+- return NULL;
++ return (void __iomem *) NULL;
+ }
+
+ void
+@@ -803,8 +796,6 @@
+ return (addr & 0xFF000000UL) == 0;
+ }
+
+-#define __marvel_is_port_vga(a) \
+- (((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3))
+ #define __marvel_is_port_kbd(a) (((a) == 0x60) || ((a) == 0x64))
+ #define __marvel_is_port_rtc(a) (((a) == 0x70) || ((a) == 0x71))
+
+@@ -813,7 +804,7 @@
+ if (__marvel_is_port_rtc (addr) || __marvel_is_port_kbd(addr))
+ ;
+ #ifdef CONFIG_VGA_HOSE
+- else if (__marvel_is_port_vga (addr) && pci_vga_hose)
++ else if (__is_port_vga (addr) && pci_vga_hose)
+ addr += pci_vga_hose->io_space->start;
+ #endif
+ else
+diff -uNr source/arch/alpha/kernel/core_titan.c source-es45/arch/alpha/kernel/core_titan.c
+--- source/arch/alpha/kernel/core_titan.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/core_titan.c 2006-09-30 03:14:44.000000000 -0700
+@@ -35,6 +35,17 @@
+ } saved_config[4] __attribute__((common));
+
+ /*
++ * Is PChip 1 present? No need to query it more than once.
++ */
++static int titan_pchip1_present;
++
++/* hoseno to index mapping */
++#define H2I(h) ((((h)&2)>>1)|(((h)&1)<<1))
++/* index to hoseno mapping */
++#define I2H(i) ((((i)&2)>>1)|(((i)&1)<<1))
++
++
++/*
+ * BIOS32-style PCI interface:
+ */
+
+@@ -196,14 +207,14 @@
+ titan_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+ {
+ titan_pachip *pachip =
+- (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0;
++ (hose->index & 2) ? TITAN_pachip1 : TITAN_pachip0;
+ titan_pachip_port *port;
+ volatile unsigned long *csr;
+ unsigned long value;
+
+ /* Get the right hose. */
+ port = &pachip->g_port;
+- if (hose->index & 2)
++ if (hose->index & 1)
+ port = &pachip->a_port;
+
+ /* We can invalidate up to 8 tlb entries in a go. The flush
+@@ -238,12 +249,12 @@
+ }
+
+ static void __init
+-titan_init_one_pachip_port(titan_pachip_port *port, int index)
++titan_init_one_pachip_port(titan_pachip_port *port, int hoseno)
+ {
+ struct pci_controller *hose;
+
+ hose = alloc_pci_controller();
+- if (index == 0)
++ if (hoseno == 0)
+ pci_isa_hose = hose;
+ hose->io_space = alloc_resource();
+ hose->mem_space = alloc_resource();
+@@ -258,47 +269,47 @@
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base
+- = (TITAN_MEM(index) & 0xffffffffffUL) | 0x80000000000UL;
++ = (TITAN_MEM(hoseno) & 0xffffffffffUL) | 0x80000000000UL;
+ hose->dense_io_base
+- = (TITAN_IO(index) & 0xffffffffffUL) | 0x80000000000UL;
++ = (TITAN_IO(hoseno) & 0xffffffffffUL) | 0x80000000000UL;
+
+- hose->config_space_base = TITAN_CONF(index);
+- hose->index = index;
++ hose->config_space_base = TITAN_CONF(hoseno);
++ hose->index = H2I(hoseno);
+
+- hose->io_space->start = TITAN_IO(index) - TITAN_IO_BIAS;
++ hose->io_space->start = TITAN_IO(hoseno) - TITAN_IO_BIAS;
+ hose->io_space->end = hose->io_space->start + TITAN_IO_SPACE - 1;
+- hose->io_space->name = pci_io_names[index];
++ hose->io_space->name = pci_io_names[hoseno];
+ hose->io_space->flags = IORESOURCE_IO;
+
+- hose->mem_space->start = TITAN_MEM(index) - TITAN_MEM_BIAS;
++ hose->mem_space->start = TITAN_MEM(hoseno) - TITAN_MEM_BIAS;
+ hose->mem_space->end = hose->mem_space->start + 0xffffffff;
+- hose->mem_space->name = pci_mem_names[index];
++ hose->mem_space->name = pci_mem_names[hoseno];
+ hose->mem_space->flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, hose->io_space) < 0)
+- printk(KERN_ERR "Failed to request IO on hose %d\n", index);
++ printk(KERN_ERR "Failed to request IO on hose %d\n", hoseno);
+ if (request_resource(&iomem_resource, hose->mem_space) < 0)
+- printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
++ printk(KERN_ERR "Failed to request MEM on hose %d\n", hoseno);
+
+ /*
+ * Save the existing PCI window translations. SRM will
+ * need them when we go to reboot.
+ */
+- saved_config[index].wsba[0] = port->wsba[0].csr;
+- saved_config[index].wsm[0] = port->wsm[0].csr;
+- saved_config[index].tba[0] = port->tba[0].csr;
+-
+- saved_config[index].wsba[1] = port->wsba[1].csr;
+- saved_config[index].wsm[1] = port->wsm[1].csr;
+- saved_config[index].tba[1] = port->tba[1].csr;
+-
+- saved_config[index].wsba[2] = port->wsba[2].csr;
+- saved_config[index].wsm[2] = port->wsm[2].csr;
+- saved_config[index].tba[2] = port->tba[2].csr;
+-
+- saved_config[index].wsba[3] = port->wsba[3].csr;
+- saved_config[index].wsm[3] = port->wsm[3].csr;
+- saved_config[index].tba[3] = port->tba[3].csr;
++ saved_config[hoseno].wsba[0] = port->wsba[0].csr;
++ saved_config[hoseno].wsm[0] = port->wsm[0].csr;
++ saved_config[hoseno].tba[0] = port->tba[0].csr;
++
++ saved_config[hoseno].wsba[1] = port->wsba[1].csr;
++ saved_config[hoseno].wsm[1] = port->wsm[1].csr;
++ saved_config[hoseno].tba[1] = port->tba[1].csr;
++
++ saved_config[hoseno].wsba[2] = port->wsba[2].csr;
++ saved_config[hoseno].wsm[2] = port->wsm[2].csr;
++ saved_config[hoseno].tba[2] = port->tba[2].csr;
++
++ saved_config[hoseno].wsba[3] = port->wsba[3].csr;
++ saved_config[hoseno].wsm[3] = port->wsm[3].csr;
++ saved_config[hoseno].tba[3] = port->tba[3].csr;
+
+ /*
+ * Set up the PCI to main memory translation windows.
+@@ -344,14 +355,14 @@
+ static void __init
+ titan_init_pachips(titan_pachip *pachip0, titan_pachip *pachip1)
+ {
+- int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
++ titan_pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
+
+ /* Init the ports in hose order... */
+ titan_init_one_pachip_port(&pachip0->g_port, 0); /* hose 0 */
+- if (pchip1_present)
++ if (titan_pchip1_present)
+ titan_init_one_pachip_port(&pachip1->g_port, 1);/* hose 1 */
+ titan_init_one_pachip_port(&pachip0->a_port, 2); /* hose 2 */
+- if (pchip1_present)
++ if (titan_pchip1_present)
+ titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */
+ }
+
+@@ -366,16 +377,18 @@
+ int h = (pu64[30] >> 24) & 0xff; /* console hose # */
+
+ /*
+- * Our hose numbering matches the console's, so just find
++ * Our hose numbering does NOT match the console's, so find
+ * the right one...
+ */
+ for (hose = hose_head; hose; hose = hose->next) {
+- if (hose->index == h) break;
++ if (I2H(hose->index) == h) break;
+ }
+
+ if (hose) {
+- printk("Console graphics on hose %d\n", hose->index);
++ printk("Console graphics on hose %d\n", h);
+ pci_vga_hose = hose;
++ } else {
++ printk("ERROR: Console graphics hose not found\n");
+ }
+ }
+ #endif /* CONFIG_VGA_HOSE */
+@@ -406,6 +419,7 @@
+
+ /* With multiple PCI busses, we play with I/O as physical addrs. */
+ ioport_resource.end = ~0UL;
++ iomem_resource.end = ~0UL;
+
+ /* PCI DMA Direct Mapping is 1GB at 2GB. */
+ __direct_map_base = 0x80000000;
+@@ -441,9 +455,7 @@
+ static void
+ titan_kill_pachips(titan_pachip *pachip0, titan_pachip *pachip1)
+ {
+- int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
+-
+- if (pchip1_present) {
++ if (titan_pchip1_present) {
+ titan_kill_one_pachip_port(&pachip1->g_port, 1);
+ titan_kill_one_pachip_port(&pachip1->a_port, 3);
+ }
+@@ -474,12 +486,12 @@
+ unsigned long *ptes;
+ unsigned long pfn;
+
++#ifdef CONFIG_VGA_HOSE
+ /*
+- * Adjust the addr.
++ * Adjust the address and hose, if necessary.
+ */
+-#ifdef CONFIG_VGA_HOSE
+- if (pci_vga_hose && __titan_is_mem_vga(addr)) {
+- h = pci_vga_hose->index;
++ if (pci_vga_hose && __is_mem_vga(addr)) {
++ h = I2H(pci_vga_hose->index);
+ addr += pci_vga_hose->mem_space->start;
+ }
+ #endif
+@@ -488,7 +500,7 @@
+ * Find the hose.
+ */
+ for (hose = hose_head; hose; hose = hose->next)
+- if (hose->index == h)
++ if (I2H(hose->index) == h)
+ break;
+ if (!hose)
+ return NULL;
+@@ -521,8 +533,10 @@
+ * Map it
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+- if (!area)
++ if (!area) {
++ printk("ioremap failed... no vm_area...\n");
+ return NULL;
++ }
+
+ ptes = hose->sg_pci->ptes;
+ for (vaddr = (unsigned long)area->addr;
+@@ -539,7 +553,7 @@
+ if (__alpha_remap_area_pages(vaddr,
+ pfn << PAGE_SHIFT,
+ PAGE_SIZE, 0)) {
+- printk("FAILED to map...\n");
++ printk("FAILED to remap_area_pages...\n");
+ vfree(area->addr);
+ return NULL;
+ }
+@@ -551,7 +565,8 @@
+ return (void __iomem *) vaddr;
+ }
+
+- return NULL;
++ /* Assume a legacy (read: VGA) address, and return appropriately. */
++ return (void __iomem *)(addr + TITAN_MEM_BIAS);
+ }
+
+ void
+@@ -750,6 +765,7 @@
+ if (titan_query_agp(port))
+ hosenum = 2;
+ if (hosenum < 0 &&
++ titan_pchip1_present &&
+ titan_query_agp(port = &TITAN_pachip1->a_port))
+ hosenum = 3;
+
+@@ -757,7 +773,7 @@
+ * Find the hose the port is on.
+ */
+ for (hose = hose_head; hose; hose = hose->next)
+- if (hose->index == hosenum)
++ if (I2H(hose->index) == hosenum)
+ break;
+
+ if (!hose || !hose->sg_pci)
+diff -uNr source/arch/alpha/kernel/core_tsunami.c source-es45/arch/alpha/kernel/core_tsunami.c
+--- source/arch/alpha/kernel/core_tsunami.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/core_tsunami.c 2006-09-30 03:14:44.000000000 -0700
+@@ -349,6 +349,32 @@
+ tsunami_pci_tbi(hose, 0, -1);
+ }
+
++static void __init
++tsunami_init_vga_hose(void)
++{
++#ifdef CONFIG_VGA_HOSE
++ u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
++
++ if (pu64[7] == 3) { /* TERM_TYPE == graphics */
++ struct pci_controller *hose;
++ int h = (pu64[30] >> 24) & 0xff; /* console hose # */
++
++ /*
++ * Our hose numbering does NOT match the console's, so find
++ * the right one...
++ */
++ for (hose = hose_head; hose; hose = hose->next) {
++ if (hose->index == h) break;
++ }
++
++ if (hose) {
++ printk("Console graphics on hose %d\n", h);
++ pci_vga_hose = hose;
++ }
++ }
++#endif /* CONFIG_VGA_HOSE */
++}
++
+ void __init
+ tsunami_init_arch(void)
+ {
+@@ -393,6 +419,9 @@
+ tsunami_init_one_pchip(TSUNAMI_pchip0, 0);
+ if (TSUNAMI_cchip->csc.csr & 1L<<14)
+ tsunami_init_one_pchip(TSUNAMI_pchip1, 1);
++
++ /* Check for graphic console location (if any). */
++ tsunami_init_vga_hose();
+ }
+
+ static void
+diff -uNr source/arch/alpha/kernel/proto.h source-es45/arch/alpha/kernel/proto.h
+--- source/arch/alpha/kernel/proto.h 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/proto.h 2006-09-30 03:14:44.000000000 -0700
+@@ -106,6 +106,9 @@
+ extern unsigned long wildfire_node_mem_start(int);
+ extern unsigned long wildfire_node_mem_size(int);
+
++/* console.c */
++ extern void locate_and_init_vga(void *(*)(void *, void *));
++
+ /* setup.c */
+ extern unsigned long srm_hae;
+ extern int boot_cpuid;
+diff -uNr source/arch/alpha/kernel/setup.c source-es45/arch/alpha/kernel/setup.c
+--- source/arch/alpha/kernel/setup.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/setup.c 2006-09-30 03:14:44.000000000 -0700
+@@ -787,9 +787,9 @@
+ static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
+
+ static char titan_names[][16] = {
+- "DEFAULT", "Privateer", "Falcon", "Granite"
++ "DEFAULT", "Privateer", "Falcon", "Granite", "HyperBrick2"
+ };
+-static int titan_indices[] = {0,1,2,2,3};
++static int titan_indices[] = {0,1,2,2,3,4};
+
+ static char tsunami_names[][16] = {
+ "0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper",
+@@ -891,6 +891,7 @@
+ &privateer_mv, /* privateer */
+ &titan_mv, /* falcon */
+ &privateer_mv, /* granite */
++ &titan_mv, /* hyperbrick2 */
+ };
+
+ static struct alpha_machine_vector *tsunami_vecs[] __initdata =
+diff -uNr source/arch/alpha/kernel/sys_dp264.c source-es45/arch/alpha/kernel/sys_dp264.c
+--- source/arch/alpha/kernel/sys_dp264.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/arch/alpha/kernel/sys_dp264.c 2006-09-30 03:14:44.000000000 -0700
+@@ -42,6 +42,14 @@
+ /* dp264 boards handle at max four CPUs */
+ static unsigned long cpu_irq_affinity[4] = { 0UL, 0UL, 0UL, 0UL };
+
++#ifdef CONFIG_VGA_HOSE
++extern void locate_and_init_vga(void *(*handler)(void *, void *));
++#else
++static inline void locate_and_init_vga(void *(*handler)(void *, void *))
++{
++}
++#endif
++
+ DEFINE_SPINLOCK(dp264_irq_lock);
+
+ static void
+@@ -543,6 +551,7 @@
+ {
+ common_init_pci();
+ SMC669_Init(0);
++ locate_and_init_vga(NULL);
+ }
+
+ static void __init
+@@ -551,6 +560,14 @@
+ common_init_pci();
+ SMC669_Init(1);
+ es1888_init();
++ locate_and_init_vga(NULL);
++}
++
++static void __init
++clipper_init_pci(void)
++{
++ common_init_pci();
++ locate_and_init_vga(NULL);
+ }
+
+ static void __init
+@@ -655,7 +672,7 @@
+ .init_arch = tsunami_init_arch,
+ .init_irq = clipper_init_irq,
+ .init_rtc = common_init_rtc,
+- .init_pci = common_init_pci,
++ .init_pci = clipper_init_pci,
+ .kill_arch = tsunami_kill_arch,
+ .pci_map_irq = clipper_map_irq,
+ .pci_swizzle = common_swizzle,
+diff -uNr source/drivers/video/console/vgacon.c source-es45/drivers/video/console/vgacon.c
+--- source/drivers/video/console/vgacon.c 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/drivers/video/console/vgacon.c 2006-09-30 03:14:44.000000000 -0700
+@@ -52,6 +52,11 @@
+ #include <video/vga.h>
+ #include <asm/io.h>
+
++/* wait until after includes to test for this, to allow arch-specific mod. */
++#ifndef vga_request_resource
++# define vga_request_resource request_resource
++#endif
++
+ static DEFINE_SPINLOCK(vga_lock);
+ static int cursor_size_lastfrom;
+ static int cursor_size_lastto;
+@@ -393,7 +398,7 @@
+ vga_video_type = VIDEO_TYPE_EGAM;
+ vga_vram_size = 0x8000;
+ display_desc = "EGA+";
+- request_resource(&ioport_resource,
++ vga_request_resource(&ioport_resource,
+ &ega_console_resource);
+ } else {
+ static struct resource mda1_console_resource =
+@@ -403,9 +408,9 @@
+ vga_video_type = VIDEO_TYPE_MDA;
+ vga_vram_size = 0x2000;
+ display_desc = "*MDA";
+- request_resource(&ioport_resource,
++ vga_request_resource(&ioport_resource,
+ &mda1_console_resource);
+- request_resource(&ioport_resource,
++ vga_request_resource(&ioport_resource,
+ &mda2_console_resource);
+ vga_video_font_height = 14;
+ }
+@@ -425,14 +430,14 @@
+ = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
+ vga_video_type = VIDEO_TYPE_EGAC;
+ display_desc = "EGA";
+- request_resource(&ioport_resource,
++ vga_request_resource(&ioport_resource,
+ &ega_console_resource);
+ } else {
+ static struct resource vga_console_resource
+ = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
+ vga_video_type = VIDEO_TYPE_VGAC;
+ display_desc = "VGA+";
+- request_resource(&ioport_resource,
++ vga_request_resource(&ioport_resource,
+ &vga_console_resource);
+
+ #ifdef VGA_CAN_DO_64KB
+@@ -477,7 +482,7 @@
+ vga_video_type = VIDEO_TYPE_CGA;
+ vga_vram_size = 0x2000;
+ display_desc = "*CGA";
+- request_resource(&ioport_resource,
++ vga_request_resource(&ioport_resource,
+ &cga_console_resource);
+ vga_video_font_height = 8;
+ }
+diff -uNr source/include/asm-alpha/core_titan.h source-es45/include/asm-alpha/core_titan.h
+--- source/include/asm-alpha/core_titan.h 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/include/asm-alpha/core_titan.h 2006-09-30 03:14:44.000000000 -0700
+@@ -3,6 +3,7 @@
+
+ #include <linux/types.h>
+ #include <linux/pci.h>
++#include <asm/pci.h>
+ #include <asm/compiler.h>
+
+ /*
+@@ -383,6 +384,7 @@
+
+ __EXTERN_INLINE void __iomem *titan_ioportmap(unsigned long addr)
+ {
++ FIXUP_IOADDR_VGA(addr);
+ return (void __iomem *)(addr + TITAN_IO_BIAS);
+ }
+
+diff -uNr source/include/asm-alpha/core_tsunami.h source-es45/include/asm-alpha/core_tsunami.h
+--- source/include/asm-alpha/core_tsunami.h 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/include/asm-alpha/core_tsunami.h 2006-09-30 03:14:44.000000000 -0700
+@@ -2,6 +2,8 @@
+ #define __ALPHA_TSUNAMI__H__
+
+ #include <linux/types.h>
++#include <linux/pci.h>
++#include <asm/pci.h>
+ #include <asm/compiler.h>
+
+ /*
+@@ -305,12 +307,14 @@
+
+ __EXTERN_INLINE void __iomem *tsunami_ioportmap(unsigned long addr)
+ {
++ FIXUP_IOADDR_VGA(addr);
+ return (void __iomem *)(addr + TSUNAMI_IO_BIAS);
+ }
+
+ __EXTERN_INLINE void __iomem *tsunami_ioremap(unsigned long addr,
+ unsigned long size)
+ {
++ FIXUP_MEMADDR_VGA(addr);
+ return (void __iomem *)(addr + TSUNAMI_MEM_BIAS);
+ }
+
+diff -uNr source/include/asm-alpha/io.h source-es45/include/asm-alpha/io.h
+--- source/include/asm-alpha/io.h 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/include/asm-alpha/io.h 2006-09-30 03:14:44.000000000 -0700
+@@ -126,6 +126,30 @@
+ return (long)address <= 0 ? NULL : virt;
+ }
+
++#ifdef CONFIG_VGA_HOSE
++extern struct pci_controller *pci_vga_hose;
++
++# define __is_port_vga(a) \
++ (((a) >= 0x3b0) && ((a) < 0x3e0) && \
++ ((a) != 0x3b3) && ((a) != 0x3d3))
++
++# define __is_mem_vga(a) \
++ (((a) >= 0xa0000) && ((a) <= 0xc0000))
++
++# define FIXUP_IOADDR_VGA(a) do { \
++ if (pci_vga_hose && __is_port_vga(a)) \
++ a += pci_vga_hose->io_space->start; \
++ } while(0)
++
++# define FIXUP_MEMADDR_VGA(a) do { \
++ if (pci_vga_hose && __is_mem_vga(a)) \
++ a += pci_vga_hose->io_space->start; \
++ } while(0)
++
++#else /* CONFIG_VGA_HOSE */
++# define FIXUP_IOADDR_VGA(a)
++#endif /* CONFIG_VGA_HOSE */
++
+ /*
+ * There are different chipsets to interface the Alpha CPUs to the world.
+ */
+diff -uNr source/include/asm-alpha/vga.h source-es45/include/asm-alpha/vga.h
+--- source/include/asm-alpha/vga.h 2006-09-19 20:42:06.000000000 -0700
++++ source-es45/include/asm-alpha/vga.h 2006-09-30 03:14:44.000000000 -0700
+@@ -48,4 +48,26 @@
+
+ #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s))
+
++#ifdef CONFIG_VGA_HOSE
++#include <linux/ioport.h>
++#include <linux/pci.h>
++
++extern struct pci_controller *pci_vga_hose;
++
++#define vga_request_resource alpha_vga_request_resource
++
++static int inline
++alpha_vga_request_resource(struct resource *root, struct resource *new)
++{
++ /* First, fixup the VGA resource bounds WRT the hose it is on. */
++ if (pci_vga_hose) {
++ new->start += pci_vga_hose->io_space->start;
++ new->end += pci_vga_hose->io_space->start;
++ }
++
++ /* Finally, do a normal request_resource(). */
++ return request_resource(root, new);
++}
++#endif /* CONFIG_VGA_HOSE */
++
+ #endif
Added: people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-0.2.1-driver.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-0.2.1-driver.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,3087 @@
+diff --git a/Documentation/networking/ixp4xx/IxNpeMicrocode.h b/Documentation/networking/ixp4xx/IxNpeMicrocode.h
+new file mode 100644
+index 0000000..a85f326
+Index: linux-2.6.18/Documentation/networking/ixp4xx/IxNpeMicrocode.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/Documentation/networking/ixp4xx/IxNpeMicrocode.h 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,149 @@
++/*
++ * IxNpeMicrocode.h - Headerfile for compiling the Intel microcode C file
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ *
++ *
++ * compile with
++ *
++ * gcc -Wall IxNpeMicrocode.c -o IxNpeMicrocode
++ *
++ * Executing the resulting binary on your build-host creates the
++ * "NPE-[ABC].xxxxxxxx" files containing the selected microcode
++ * The options -le and -be controll the output format of the microcode
++ * the default is -be independent of the host endianess
++ *
++ * The download functions in the driver are smart enough to discover
++ * and correct firmware with wrong endianess
++ *
++ * fetch the IxNpeMicrocode.c from the Intel Access Library.
++ * It will include this header.
++ *
++ * select Images for every NPE from the following
++ * (used C++ comments for easy uncommenting ....)
++ */
++
++// #define IX_NPEDL_NPEIMAGE_NPEA_ETH_SPAN_MASK_FIREWALL_VLAN_QOS_HDR_CONV_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEA_ETH_SPAN_VLAN_QOS_HDR_CONV_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEA_ETH_LEARN_FILTER_SPAN_MASK_FIREWALL_VLAN_QOS_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEA_HSS_TSLOT_SWITCH
++// #define IX_NPEDL_NPEIMAGE_NPEA_ETH_SPAN_FIREWALL_VLAN_QOS_HDR_CONV
++// #define IX_NPEDL_NPEIMAGE_NPEA_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS
++// #define IX_NPEDL_NPEIMAGE_NPEA_ETH_LEARN_FILTER_SPAN_FIREWALL
++// #define IX_NPEDL_NPEIMAGE_NPEA_HSS_2_PORT
++// #define IX_NPEDL_NPEIMAGE_NPEA_DMA
++// #define IX_NPEDL_NPEIMAGE_NPEA_ATM_MPHY_12_PORT
++// #define IX_NPEDL_NPEIMAGE_NPEA_HSS0_ATM_MPHY_1_PORT
++// #define IX_NPEDL_NPEIMAGE_NPEA_HSS0_ATM_SPHY_1_PORT
++// #define IX_NPEDL_NPEIMAGE_NPEA_HSS0
++// #define IX_NPEDL_NPEIMAGE_NPEA_WEP
++
++
++// #define IX_NPEDL_NPEIMAGE_NPEB_ETH_SPAN_MASK_FIREWALL_VLAN_QOS_HDR_CONV_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEB_ETH_SPAN_VLAN_QOS_HDR_CONV_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEB_ETH_LEARN_FILTER_SPAN_MASK_FIREWALL_VLAN_QOS_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEB_DMA
++// #define IX_NPEDL_NPEIMAGE_NPEB_ETH_SPAN_FIREWALL_VLAN_QOS_HDR_CONV
++// #define IX_NPEDL_NPEIMAGE_NPEB_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS
++#define IX_NPEDL_NPEIMAGE_NPEB_ETH_LEARN_FILTER_SPAN_FIREWALL
++
++
++// #define IX_NPEDL_NPEIMAGE_NPEC_ETH_SPAN_MASK_FIREWALL_VLAN_QOS_HDR_CONV_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEC_ETH_SPAN_VLAN_QOS_HDR_CONV_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEC_ETH_LEARN_FILTER_SPAN_MASK_FIREWALL_VLAN_QOS_EXTMIB
++// #define IX_NPEDL_NPEIMAGE_NPEC_DMA
++// #define IX_NPEDL_NPEIMAGE_NPEC_CRYPTO_AES_ETH_LEARN_FILTER_SPAN
++// #define IX_NPEDL_NPEIMAGE_NPEC_CRYPTO_AES_ETH_LEARN_FILTER_FIREWALL
++#define IX_NPEDL_NPEIMAGE_NPEC_CRYPTO_AES_CCM_ETH
++// #define IX_NPEDL_NPEIMAGE_NPEC_CRYPTO_ETH_LEARN_FILTER_SPAN_FIREWALL
++// #define IX_NPEDL_NPEIMAGE_NPEC_ETH_SPAN_FIREWALL_VLAN_QOS_HDR_CONV
++// #define IX_NPEDL_NPEIMAGE_NPEC_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS
++// #define IX_NPEDL_NPEIMAGE_NPEC_ETH_LEARN_FILTER_SPAN_FIREWALL
++
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <netinet/in.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <endian.h>
++#include <byteswap.h>
++#include <string.h>
++
++#if __BYTE_ORDER == __LITTLE_ENDIAN
++#define to_le32(x) (x)
++#define to_be32(x) bswap_32(x)
++#else
++#define to_be32(x) (x)
++#define to_le32(x) bswap_32(x)
++#endif
++
++struct dl_image {
++ unsigned magic;
++ unsigned id;
++ unsigned size;
++ unsigned data[0];
++};
++
++const unsigned IxNpeMicrocode_array[];
++
++int main(int argc, char *argv[])
++{
++ struct dl_image *image = (struct dl_image *)IxNpeMicrocode_array;
++ int imgsiz, i, fd, cnt;
++ const unsigned *arrayptr = IxNpeMicrocode_array;
++ const char *names[] = { "IXP425", "IXP465", "unknown" };
++ int bigendian = 1;
++
++ if (argc > 1) {
++ if (!strcmp(argv[1], "-le"))
++ bigendian = 0;
++ else if (!strcmp(argv[1], "-be"))
++ bigendian = 1;
++ else {
++ printf("Usage: %s <-le|-be>\n", argv[0]);
++ return EXIT_FAILURE;
++ }
++ }
++ printf("Output format is %s endian\n", bigendian ? "big" : "little");
++
++ for (image = (struct dl_image *)arrayptr, cnt=0;
++ (image->id != 0xfeedf00d) && (image->magic == 0xfeedf00d);
++ image = (struct dl_image *)(arrayptr), cnt++)
++ {
++ unsigned char field[4];
++ imgsiz = image->size + 3;
++ *(unsigned*)field = to_be32(image->id);
++ char filename[40], slnk[10];
++
++ sprintf(filename, "NPE-%c.%08x", (field[0] & 0xf) + 'A',
++ image->id);
++ sprintf(slnk, "NPE-%c", (field[0] & 0xf) + 'A');
++ printf("Writing image: %s.NPE_%c Func: %2x Rev: %02x.%02x "
++ "Size: %5d to: '%s'\n",
++ names[field[0] >> 4], (field[0] & 0xf) + 'A',
++ field[1], field[2], field[3], imgsiz*4, filename);
++ fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, 0644);
++ if (fd >= 0) {
++ for (i=0; i<imgsiz; i++) {
++ *(unsigned*)field = bigendian ?
++ to_be32(arrayptr[i]) :
++ to_le32(arrayptr[i]);
++ write(fd, field, sizeof(field));
++ }
++ close(fd);
++ unlink(slnk);
++ symlink(filename, slnk);
++ } else {
++ perror(filename);
++ }
++ arrayptr += imgsiz;
++ }
++ close(fd);
++ return 0;
++}
+Index: linux-2.6.18/Documentation/networking/ixp4xx/README
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/Documentation/networking/ixp4xx/README 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,72 @@
++Informations about the Networking Driver using the IXP4XX CPU internal NPEs
++and Queue manager.
++
++If this driver is used, the IAL (Intel Access Library) must not be loaded.
++However, the IAL may be loaded, if this Modules are unloaded:
++ ixp4xx_npe.ko, ixp4xx_qmgr.ko ixp4xx_mac.ko
++
++This also means that HW crypto accelleration does NOT work when using this
++driver, unless I have finished my crypto driver for NPE-C
++
++
++Adoption to your custom board:
++------------------------------
++use "arch/arm/mach-ixp4xx/ixdp425-setup.c" as template:
++
++in "static struct mac_plat_info" adopt the entry "phy_id" to your needs
++(Ask your hardware designer about the PHY id)
++If in doubt, try the values from the ixdp425 board.
++
++The order of "&mac0" and "&mac1" in the "struct platform_device"
++determines which of them becomes eth0 and eth1.
++
++
++The Microcode:
++---------------
++
++The Download functions below are endianess independent.
++If the image comes in wrong endianess, it is swapped automatically.
++
++Solution 1)
++ Configure "CONFIG_HOTPLUG" and "CONFIG_FW_LOADER" and configure
++ IXP4XX_NPE as module.
++ The default hotplug script will load the Firmware from
++ /usr/lib/hotplug/firmware/NPE-[ABC]
++ see Documentation/firmware_class/hotplug-script
++
++ You should take care, that $ACTION is "add" and $SUBSYSTEM is "firmware"
++ to avoid unnessecary calls:
++ test $ACTION = "remove" -o $SUBSYSTEM != "firmware" && exit
++
++Solution 2)
++ create a char-dev: "mknod /dev/ixp4xx_ucode c 10 184".
++ If you are using "udev" or busybox "mdev", they will do this
++ for you automatically during module load.
++ cat the Microcode into it:
++ cat /usr/lib/hotplug/firmware/NPE-* > /dev/ixp4xx_ucode
++ This also works if the driver is linked to the kernel
++
++Having a mix of both (e.g. solution 1 for NPE-B and solution 2 for NPE-C)
++is perfectly ok and works.
++
++The state of the NPEs can be seen and changed at:
++/sys/bus/platform/devices/ixp4xx_npe.X/state
++
++
++Obtaining the Microcode:
++------------------------
++1) IxNpeMicrocode.h in this directory:
++ Download IPL_IXP400NPELIBRARYWITHCRYPTO-2_1.ZIP from Intel
++ It unpacks the Microcode IxNpeMicrocode.c
++ Read the Licence !
++ Read the top of IxNpeMicrocode.h for more details.
++ Compile it with "gcc -Wall IxNpeMicrocode.c -o IxNpeMicrocode" on your host.
++ The resulting images can be moved to "/usr/lib/hotplug/firmware"
++ The endianeess of the written microcode can be controlled by the
++ switches -le -be. Default is big-endian.
++
++2) mc_grab.c in this directory:
++ Compile and execute it either on the host or on the target
++ to grab the microcode from a binary image like the RedBoot bootloader.
++ (big-endian images only)
++
+Index: linux-2.6.18/Documentation/networking/ixp4xx/mc_grab.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/Documentation/networking/ixp4xx/mc_grab.c 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,97 @@
++/*
++ * mc_grab.c - grabs IXP4XX microcode from a binary datastream
++ * e.g. The redboot bootloader....
++ *
++ * usage: mc_grab 1010200 2010200 < /dev/mtd/0 > /dev/misc/npe
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <netinet/in.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <string.h>
++
++#define MAX_IMG 6
++
++static void print_mc_info(unsigned id, int siz)
++{
++ unsigned char buf[sizeof(unsigned)];
++ *(unsigned*)buf = id;
++ unsigned idx;
++ const char *names[] = { "IXP425", "IXP465", "unknown" };
++
++ idx = (buf[0] >> 4) < 2 ? (buf[0] >> 4) : 2;
++
++ fprintf(stderr, "Device: %s:NPE_%c Func: %2x Rev: %02x.%02x "
++ "Size: %5d bytes ID:%08x\n", names[idx], (buf[0] & 0xf)+'A',
++ buf[1], buf[2], buf[3], siz*4, ntohl(id));
++}
++
++int main(int argc, char *argv[])
++{
++ int i,j;
++ unsigned char buf[sizeof(unsigned)];
++ unsigned magic = htonl(0xfeedf00d);
++ unsigned id, my_ids[MAX_IMG+1], siz, sizbe;
++ int ret=1, verbose=0;
++
++ for (i=0, j=0; i<argc-1 && j<MAX_IMG; i++) {
++ if (!strcmp(argv[i+1], "-v"))
++ verbose = 1;
++ else
++ my_ids[j++] = htonl(strtoul(argv[i+1], NULL, 16));
++ }
++ my_ids[j] = 0;
++ if (my_ids[0] == 0 && !verbose) {
++ fprintf(stderr, "Usage: %s <-v> [ID1] [ID2] [IDn]\n", argv[0]);
++ return 1;
++ }
++
++ while ((ret=read(0, buf, sizeof(unsigned))) == sizeof(unsigned)) {
++ if (*(unsigned*)buf != magic)
++ continue;
++ if ((ret=read(0, buf, sizeof(unsigned))) != sizeof(unsigned) )
++ break;
++ id = *(unsigned*)buf;
++
++ if (read(0, buf, sizeof(siz)) != sizeof(siz) )
++ break;
++ sizbe = *(unsigned*)buf;
++ siz = ntohl(sizbe);
++
++ if (verbose)
++ print_mc_info(id, siz);
++
++ for(i=0; my_ids[i]; i++)
++ if (id == my_ids[i])
++ break;
++ if (!my_ids[i])
++ continue;
++
++ if (!verbose)
++ print_mc_info(id, siz);
++
++ write(1, &magic, sizeof(magic));
++ write(1, &id, sizeof(id));
++ write(1, &sizbe, sizeof(sizbe));
++ for (i=0; i<siz; i++) {
++ if (read(0, buf, sizeof(unsigned)) != sizeof(unsigned))
++ break;
++ write(1, buf, sizeof(unsigned));
++ }
++ if (i != siz)
++ break;
++ }
++ if (ret)
++ fprintf(stderr, "Error reading Microcode\n");
++ return ret;
++}
+Index: linux-2.6.18/arch/arm/mach-ixp4xx/common.c
+===================================================================
+--- linux-2.6.18.orig/arch/arm/mach-ixp4xx/common.c 2006-10-17 05:26:00.000000000 -0700
++++ linux-2.6.18/arch/arm/mach-ixp4xx/common.c 2006-10-17 05:26:01.000000000 -0700
+@@ -13,6 +13,7 @@
+ * warranty of any kind, whether express or implied.
+ */
+
++#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+ #include <linux/init.h>
+@@ -278,7 +279,7 @@
+
+ static struct irqaction ixp4xx_timer_irq = {
+ .name = "IXP4xx Timer Tick",
+- .flags = IRQF_DISABLED | IRQF_TIMER,
++ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = ixp4xx_timer_interrupt,
+ };
+
+@@ -330,6 +331,97 @@
+ &ixp46x_i2c_controller
+ };
+
++static struct npe_plat_data npea = {
++ .name = "NPE-A",
++ .data_size = 0x800,
++ .inst_size = 0x1000,
++ .id = 0,
++};
++
++static struct npe_plat_data npeb = {
++ .name = "NPE-B",
++ .data_size = 0x800,
++ .inst_size = 0x800,
++ .id = 1,
++};
++
++static struct npe_plat_data npec = {
++ .name = "NPE-C",
++ .data_size = 0x800,
++ .inst_size = 0x800,
++ .id = 2,
++};
++
++static struct resource res_npea = {
++ .start = IXP4XX_NPEA_BASE_PHYS,
++ .end = IXP4XX_NPEA_BASE_PHYS + 0xfff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct resource res_npeb = {
++ .start = IXP4XX_NPEB_BASE_PHYS,
++ .end = IXP4XX_NPEB_BASE_PHYS + 0xfff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct resource res_npec = {
++ .start = IXP4XX_NPEC_BASE_PHYS,
++ .end = IXP4XX_NPEC_BASE_PHYS + 0xfff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device dev_npea = {
++ .name = "ixp4xx_npe",
++ .id = 0,
++ .dev.platform_data = &npea,
++ .num_resources = 1,
++ .resource = &res_npea,
++};
++
++static struct platform_device dev_npeb = {
++ .name = "ixp4xx_npe",
++ .id = 1,
++ .dev.platform_data = &npeb,
++ .num_resources = 1,
++ .resource = &res_npeb,
++};
++
++static struct platform_device dev_npec = {
++ .name = "ixp4xx_npe",
++ .id = 2,
++ .dev.platform_data = &npec,
++ .num_resources = 1,
++ .resource = &res_npec,
++};
++
++/* QMGR */
++static struct resource res_qmgr[] = {
++{
++ .start = IXP4XX_QMGR_BASE_PHYS,
++ .end = IXP4XX_QMGR_BASE_PHYS + IXP4XX_QMGR_REGION_SIZE -1,
++ .flags = IORESOURCE_MEM,
++}, {
++ .start = IRQ_IXP4XX_QM1,
++ .flags = IORESOURCE_IRQ,
++} };
++
++static struct platform_device qmgr = {
++ .name = "ixp4xx_qmgr",
++ .id = 0,
++ .dev = {
++ .coherent_dma_mask = DMA_32BIT_MASK,
++ },
++ .num_resources = ARRAY_SIZE(res_qmgr),
++ .resource = res_qmgr,
++};
++
++static struct platform_device *npes_qmgr[] __initdata = {
++ &qmgr,
++ &dev_npea,
++ &dev_npeb,
++ &dev_npec,
++};
++
+ unsigned long ixp4xx_exp_bus_size;
+ EXPORT_SYMBOL(ixp4xx_exp_bus_size);
+
+@@ -349,7 +441,10 @@
+ break;
+ }
+ }
++ npeb.inst_size = 0x1000;
++ npec.inst_size = 0x1000;
+ }
++ platform_add_devices(npes_qmgr, ARRAY_SIZE(npes_qmgr));
+
+ printk("IXP4xx: Using %luMiB expansion bus window size\n",
+ ixp4xx_exp_bus_size >> 20);
+Index: linux-2.6.18/arch/arm/mach-ixp4xx/ixdp425-setup.c
+===================================================================
+--- linux-2.6.18.orig/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-10-17 05:26:01.000000000 -0700
+@@ -101,10 +101,57 @@
+ .resource = ixdp425_uart_resources
+ };
+
++/* MACs */
++static struct resource res_mac0 = {
++ .start = IXP4XX_EthB_BASE_PHYS,
++ .end = IXP4XX_EthB_BASE_PHYS + 0x1ff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct resource res_mac1 = {
++ .start = IXP4XX_EthC_BASE_PHYS,
++ .end = IXP4XX_EthC_BASE_PHYS + 0x1ff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct mac_plat_info plat_mac0 = {
++ .npe_id = 1,
++ .phy_id = 0,
++ .eth_id = 0,
++ .rxq_id = 27,
++ .txq_id = 24,
++};
++
++static struct mac_plat_info plat_mac1 = {
++ .npe_id = 2,
++ .phy_id = 1,
++ .eth_id = 1,
++ .rxq_id = 28,
++ .txq_id = 25,
++};
++
++static struct platform_device mac0 = {
++ .name = "ixp4xx_mac",
++ .id = 0,
++ .dev.platform_data = &plat_mac0,
++ .num_resources = 1,
++ .resource = &res_mac0,
++};
++
++static struct platform_device mac1 = {
++ .name = "ixp4xx_mac",
++ .id = 1,
++ .dev.platform_data = &plat_mac1,
++ .num_resources = 1,
++ .resource = &res_mac1,
++};
++
+ static struct platform_device *ixdp425_devices[] __initdata = {
+ &ixdp425_i2c_controller,
+ &ixdp425_flash,
+- &ixdp425_uart
++ &ixdp425_uart,
++ &mac0,
++ &mac1,
+ };
+
+ static void __init ixdp425_init(void)
+Index: linux-2.6.18/drivers/net/Kconfig
+===================================================================
+--- linux-2.6.18.orig/drivers/net/Kconfig 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/drivers/net/Kconfig 2006-10-17 05:26:01.000000000 -0700
+@@ -187,6 +187,8 @@
+
+ source "drivers/net/arm/Kconfig"
+
++source "drivers/net/ixp4xx/Kconfig"
++
+ config MACE
+ tristate "MACE (Power Mac ethernet) support"
+ depends on NET_ETHERNET && PPC_PMAC && PPC32
+Index: linux-2.6.18/drivers/net/Makefile
+===================================================================
+--- linux-2.6.18.orig/drivers/net/Makefile 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/drivers/net/Makefile 2006-10-17 05:26:01.000000000 -0700
+@@ -214,6 +214,7 @@
+ obj-$(CONFIG_IRDA) += irda/
+ obj-$(CONFIG_ETRAX_ETHERNET) += cris/
+ obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/
++obj-$(CONFIG_IXP4XX_NPE) += ixp4xx/
+
+ obj-$(CONFIG_NETCONSOLE) += netconsole.o
+
+Index: linux-2.6.18/drivers/net/ixp4xx/Kconfig
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/Kconfig 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,40 @@
++config IXP4XX_QMGR
++ tristate "IXP4xx Queue Manager support"
++ depends on ARCH_IXP4XX
++ depends on NET_ETHERNET
++ help
++ The IXP4XX Queue manager is a configurable hardware ringbuffer.
++ It is used by the NPEs to exchange data from and to the CPU.
++ You can either use this OR the Intel Access Library (IAL)
++
++config IXP4XX_NPE
++ tristate "IXP4xx NPE support"
++ depends on ARCH_IXP4XX
++ depends on NET_ETHERNET
++ help
++ The IXP4XX NPE driver supports the 3 CPU co-processors called
++ "Network Processing Engines" (NPE). It adds support fo downloading
++ the Microcode (firmware) via Hotplug or character-special-device.
++ More about this at: Documentation/networking/ixp4xx/README.
++ You can either use this OR the Intel Access Library (IAL)
++
++config IXP4XX_FW_LOAD
++ bool "Use Firmware hotplug for Microcode download"
++ depends on IXP4XX_NPE
++ select HOTPLUG
++ select FW_LOADER
++ help
++ The default hotplug script will load the Firmware from
++ /usr/lib/hotplug/firmware/NPE-[ABC]
++ see Documentation/firmware_class/hotplug-script
++
++config IXP4XX_MAC
++ tristate "IXP4xx MAC support"
++ depends on IXP4XX_NPE
++ depends on IXP4XX_QMGR
++ depends on NET_ETHERNET
++ select MII
++ help
++ The IXP4XX MAC driver supports the MACs on the IXP4XX CPUs.
++ There are 2 on ixp425 and up to 5 on ixdp465.
++ You can either use this OR the Intel Access Library (IAL)
+Index: linux-2.6.18/drivers/net/ixp4xx/Makefile
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/Makefile 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,6 @@
++obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
++obj-$(CONFIG_IXP4XX_NPE) += ixp4xx_npe.o
++obj-$(CONFIG_IXP4XX_MAC) += ixp4xx_mac.o
++
++ixp4xx_npe-objs := ucode_dl.o npe_mh.o
++ixp4xx_mac-objs := mac_driver.o qmgr_eth.o phy.o
+Index: linux-2.6.18/drivers/net/ixp4xx/ixp4xx_qmgr.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/ixp4xx_qmgr.c 2006-10-17 05:40:09.000000000 -0700
+@@ -0,0 +1,390 @@
++/*
++ * qmgr.c - reimplementation of the queue configuration interface.
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/dmapool.h>
++#include <linux/interrupt.h>
++#include <linux/err.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++
++#include <linux/ixp_qmgr.h>
++#include <linux/ixp_npe.h>
++
++#define IXQMGR_VERSION "IXP4XX Q Manager 0.2.0"
++
++static struct device *qmgr_dev = NULL;
++
++int queue_len(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ int diff, offs;
++ u32 val;
++
++ offs = queue->id/8 + QUE_LOW_STAT0;
++ val = *(qmgr->addr + IX_QMGR_QCFG_BASE + queue->id);
++
++ diff = (val - (val >> 7)) & 0x7f;
++ if (!diff) {
++ /* diff == 0 means either empty or full, must look at STAT0 */
++ if ((*(qmgr->addr + offs) >> ((queue->id % 8)*4)) & 0x04)
++ diff = queue->len;
++ }
++ return diff;
++}
++
++static int request_pool(struct device *dev, int count)
++{
++ int i;
++ struct npe_cont *cont;
++ struct qm_qmgr *qmgr = dev_get_drvdata(dev);
++ dma_addr_t handle;
++
++ for (i=0; i<count; i++) {
++ cont = dma_pool_alloc(qmgr->dmapool, GFP_KERNEL, &handle);
++ if (!cont) {
++ return -ENOMEM;
++ }
++ cont->phys = handle;
++ cont->virt = cont;
++ write_lock(&qmgr->lock);
++ cont->next = qmgr->pool;
++ qmgr->pool = cont;
++ write_unlock(&qmgr->lock);
++ }
++ return 0;
++}
++
++static int free_pool(struct device *dev, int count)
++{
++ int i;
++ struct npe_cont *cont;
++ struct qm_qmgr *qmgr = dev_get_drvdata(dev);
++
++ for (i=0; i<count; i++) {
++ write_lock(&qmgr->lock);
++ cont = qmgr->pool;
++ if (!cont) {
++ write_unlock(&qmgr->lock);
++ return -1;
++ }
++ qmgr->pool = cont->next;
++ write_unlock(&qmgr->lock);
++ dma_pool_free(qmgr->dmapool, cont, cont->phys);
++ }
++ return 0;
++}
++
++static int get_free_qspace(struct qm_qmgr *qmgr, int len)
++{
++ int words = (qmgr->res->end - qmgr->res->start + 1) / 4 -
++ IX_QMGR_SRAM_SPACE;
++ int i,q;
++
++ for (i=0; i<words; i+=len) {
++ for (q=0; q<MAX_QUEUES; q++) {
++ struct qm_queue *qu = qmgr->queues[q];
++ if (!qu)
++ continue;
++ if ((qu->addr + qu->len > i) && (qu->addr < i + len))
++ break;
++ }
++ if (q == MAX_QUEUES) {
++ /* we have a free address */
++ return i;
++ }
++ }
++ return -1;
++}
++
++static inline int log2(int x)
++{
++ int r=0;
++ while(x>>=1)
++ r++;
++ return r;
++}
++
++/*
++ * 32bit Config registers at IX_QMGR_QUECONFIG_BASE_OFFSET[Qid]
++ * 0 - 6 WRPTR Word offset to baseaddr (index 0 .. BSIZE-1)
++ * 7 -13 RDPTR ''
++ * 14 -21 BADDR baseaddr = (offset to IX_QMGR_QUEBUFFER_SPACE_OFFSET) >> 6
++ * 22 -23 ESIZE entrySizeInWords (always 00 because entrySizeInWords==1)
++ * 24 -25 BSIZE qSizeInWords 00=16,01=32,10=64,11=128
++ * 26 -28 NE nearly empty
++ * 29 -31 NF nearly full
++ */
++static int conf_q_regs(struct qm_queue *queue)
++{
++ int bsize = log2(queue->len/16);
++ int baddr = queue->addr + IX_QMGR_QCFG_SIZE;
++
++ /* +2, because baddr is in words and not in bytes */
++ queue_write_cfg_reg(queue, (bsize << 24) | (baddr<<(14-6+2)) );
++
++ return 0;
++}
++
++void queue_set_watermarks(struct qm_queue *queue, unsigned ne, unsigned nf)
++{
++ u32 val;
++ /* calculate the register values
++ * 0->0, 1->1, 2->2, 4->3, 8->4 16->5...*/
++ ne = log2(ne<<1) & 0x7;
++ nf = log2(nf<<1) & 0x7;
++
++ /* Mask out old watermarks */
++ val = queue_read_cfg_reg(queue) & ~0xfc000000;
++ queue_write_cfg_reg(queue, val | (ne << 26) | (nf << 29));
++}
++
++int queue_set_irq_src(struct qm_queue *queue, int flag)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ u32 reg;
++ int offs, bitoffs;
++
++ /* Q 0-7 are in REG0, 8-15 are in REG1, etc. They occupy 4 bits/Q */
++ offs = queue->id/8 + INT0_SRC_SELREG0;
++ bitoffs = (queue->id % 8)*4;
++
++ reg = *(qmgr->addr + offs) & ~(0xf << bitoffs);
++ *(qmgr->addr + offs) = reg | (flag << bitoffs);
++
++ return 0;
++}
++
++static irqreturn_t irq_qm1(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct qm_qmgr *qmgr = dev_id;
++ int offs, reg;
++ struct qm_queue *queue;
++
++ reg = *(qmgr->addr + QUE_INT_REG0);
++ while(reg) {
++ /*
++ * count leading zeros. "offs" gets
++ * the amount of leading 0 in "reg"
++ */
++ asm ("clz %0, %1;" : "=r"(offs) : "r"(reg));
++ offs = 31 - offs;
++ reg &= ~(1 << offs);
++ queue = qmgr->queues[offs];
++ if (likely(queue)) {
++ if (likely(queue->irq_cb)) {
++ queue->irq_cb(queue);
++ } else {
++ printk(KERN_ERR "Missing callback for Q %d\n",
++ offs);
++ }
++ } else {
++ printk(KERN_ERR "IRQ for unregistered Q %d\n", offs);
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++struct qm_queue *request_queue(int qid, int len)
++{
++ int ram;
++ struct qm_qmgr *qmgr;
++ struct qm_queue *queue;
++
++ if (!qmgr_dev)
++ return ERR_PTR(-ENODEV);
++
++ if ((qid < 0) || (qid > MAX_QUEUES))
++ return ERR_PTR(-ERANGE);
++
++ switch (len) {
++ case 16:
++ case 32:
++ case 64:
++ case 128: break;
++ default : return ERR_PTR(-EINVAL);
++ }
++
++ qmgr = dev_get_drvdata(qmgr_dev);
++
++ if (qmgr->queues[qid]) {
++ /* not an error, just in use already */
++ return NULL;
++ }
++ if ((ram = get_free_qspace(qmgr, len)) < 0) {
++ printk(KERN_ERR "No free SRAM space for this queue\n");
++ return ERR_PTR(-ENOMEM);
++ }
++ if (!(queue = kzalloc(sizeof(struct qm_queue), GFP_KERNEL)))
++ return ERR_PTR(-ENOMEM);
++
++ if (!try_module_get(THIS_MODULE)) {
++ kfree(queue);
++ return ERR_PTR(-ENODEV);
++ }
++
++ queue->addr = ram;
++ queue->len = len;
++ queue->id = qid;
++ queue->dev = get_device(qmgr_dev);
++ queue->acc_reg = qmgr->addr + (4 * qid);
++ qmgr->queues[qid] = queue;
++ if (request_pool(qmgr_dev, len)) {
++ printk(KERN_ERR "Failed to request DMA pool of Q %d\n", qid);
++ }
++
++ conf_q_regs(queue);
++ return queue;
++}
++
++void release_queue(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++
++ BUG_ON(qmgr->queues[queue->id] != queue);
++ qmgr->queues[queue->id] = NULL;
++
++ if (free_pool(queue->dev, queue->len)) {
++ printk(KERN_ERR "Failed to release DMA pool of Q %d\n",
++ queue->id);
++ }
++ queue_disable_irq(queue);
++ queue_write_cfg_reg(queue, 0);
++
++ module_put(THIS_MODULE);
++ put_device(queue->dev);
++ kfree(queue);
++}
++
++static int qmgr_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ struct qm_qmgr *qmgr;
++ int size, ret=0, i;
++
++ if (!(res = platform_get_resource(pdev, IORESOURCE_MEM, 0)))
++ return -EIO;
++
++ if ((i = platform_get_irq(pdev, 0)) < 0)
++ return -EIO;
++
++ if (!(qmgr = kzalloc(sizeof(struct qm_qmgr), GFP_KERNEL)))
++ return -ENOMEM;
++
++ qmgr->irq = i;
++ size = res->end - res->start +1;
++ qmgr->res = request_mem_region(res->start, size, "ixp_qmgr");
++ if (!qmgr->res) {
++ ret = -EBUSY;
++ goto out_free;
++ }
++
++ qmgr->addr = ioremap(res->start, size);
++ if (!qmgr->addr) {
++ ret = -ENOMEM;
++ goto out_rel;
++ }
++
++ /* Reset Q registers */
++ for (i=0; i<4; i++)
++ *(qmgr->addr + QUE_LOW_STAT0 +i) = 0x33333333;
++ for (i=0; i<10; i++)
++ *(qmgr->addr + QUE_UO_STAT0 +i) = 0x0;
++ for (i=0; i<4; i++)
++ *(qmgr->addr + INT0_SRC_SELREG0 +i) = 0x0;
++ for (i=0; i<2; i++) {
++ *(qmgr->addr + QUE_IE_REG0 +i) = 0x00;
++ *(qmgr->addr + QUE_INT_REG0 +i) = 0xffffffff;
++ }
++ for (i=0; i<64; i++) {
++ *(qmgr->addr + IX_QMGR_QCFG_BASE + i) = 0x0;
++ }
++
++ ret = request_irq(qmgr->irq, irq_qm1, SA_SHIRQ | SA_INTERRUPT,
++ "qmgr", qmgr);
++ if (ret) {
++ printk(KERN_ERR "Failed to request IRQ(%d)\n", qmgr->irq);
++ ret = -EIO;
++ goto out_rel;
++ }
++
++ rwlock_init(&qmgr->lock);
++ qmgr->dmapool = dma_pool_create("qmgr", &pdev->dev,
++ sizeof(struct npe_cont), 32, 0);
++ platform_set_drvdata(pdev, qmgr);
++
++ qmgr_dev = &pdev->dev;
++
++ printk(KERN_INFO IXQMGR_VERSION " initialized.\n");
++
++ return 0;
++
++out_rel:
++ release_resource(qmgr->res);
++out_free:
++ kfree(qmgr);
++ return ret;
++}
++
++static int qmgr_remove(struct platform_device *pdev)
++{
++ struct qm_qmgr *qmgr = platform_get_drvdata(pdev);
++ int i;
++
++ for (i=0; i<MAX_QUEUES; i++) {
++ if (qmgr->queues[i]) {
++ printk(KERN_ERR "WARNING Unreleased Q: %d\n", i);
++ release_queue(qmgr->queues[i]);
++ }
++ }
++
++ synchronize_irq (qmgr->irq);
++ free_irq(qmgr->irq, qmgr);
++
++ dma_pool_destroy(qmgr->dmapool);
++ iounmap(qmgr->addr);
++ release_resource(qmgr->res);
++ platform_set_drvdata(pdev, NULL);
++ qmgr_dev = NULL;
++ kfree(qmgr);
++ return 0;
++}
++
++static struct platform_driver ixp4xx_qmgr = {
++ .driver.name = "ixp4xx_qmgr",
++ .probe = qmgr_probe,
++ .remove = qmgr_remove,
++};
++
++
++static int __init init_qmgr(void)
++{
++ return platform_driver_register(&ixp4xx_qmgr);
++}
++
++static void __exit finish_qmgr(void)
++{
++ platform_driver_unregister(&ixp4xx_qmgr);
++}
++
++module_init(init_qmgr);
++module_exit(finish_qmgr);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt at innominate.com>");
++
++EXPORT_SYMBOL(request_queue);
++EXPORT_SYMBOL(release_queue);
++EXPORT_SYMBOL(queue_set_irq_src);
++EXPORT_SYMBOL(queue_set_watermarks);
++EXPORT_SYMBOL(queue_len);
+Index: linux-2.6.18/drivers/net/ixp4xx/mac.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/mac.h 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,221 @@
++/*
++ * Copyright (C) 2002-2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#include <linux/resource.h>
++#include <linux/netdevice.h>
++#include <linux/io.h>
++#include <linux/mii.h>
++#include <linux/workqueue.h>
++#include <asm/hardware.h>
++#include <linux/ixp_qmgr.h>
++
++
++/* 32 bit offsets to be added to u32 *pointers */
++#define MAC_TX_CNTRL1 0x00 // 0x000
++#define MAC_TX_CNTRL2 0x01 // 0x004
++#define MAC_RX_CNTRL1 0x04 // 0x010
++#define MAC_RX_CNTRL2 0x05 // 0x014
++#define MAC_RANDOM_SEED 0x08 // 0x020
++#define MAC_THRESH_P_EMPTY 0x0c // 0x030
++#define MAC_THRESH_P_FULL 0x0e // 0x038
++#define MAC_BUF_SIZE_TX 0x10 // 0x040
++#define MAC_TX_DEFER 0x14 // 0x050
++#define MAC_RX_DEFER 0x15 // 0x054
++#define MAC_TX_TWO_DEFER_1 0x18 // 0x060
++#define MAC_TX_TWO_DEFER_2 0x19 // 0x064
++#define MAC_SLOT_TIME 0x1c // 0x070
++#define MAC_MDIO_CMD 0x20 // 0x080 4 registers 0x20 - 0x23
++#define MAC_MDIO_STS 0x24 // 0x090 4 registers 0x24 - 0x27
++#define MAC_ADDR_MASK 0x28 // 0x0A0 6 registers 0x28 - 0x2d
++#define MAC_ADDR 0x30 // 0x0C0 6 registers 0x30 - 0x35
++#define MAC_INT_CLK_THRESH 0x38 // 0x0E0 1 register
++#define MAC_UNI_ADDR 0x3c // 0x0F0 6 registers 0x3c - 0x41
++#define MAC_CORE_CNTRL 0x7f // 0x1fC
++
++/* TX Control Register 1*/
++
++#define TX_CNTRL1_TX_EN BIT(0)
++#define TX_CNTRL1_DUPLEX BIT(1)
++#define TX_CNTRL1_RETRY BIT(2)
++#define TX_CNTRL1_PAD_EN BIT(3)
++#define TX_CNTRL1_FCS_EN BIT(4)
++#define TX_CNTRL1_2DEFER BIT(5)
++#define TX_CNTRL1_RMII BIT(6)
++
++/* TX Control Register 2 */
++#define TX_CNTRL2_RETRIES_MASK 0xf
++
++/* RX Control Register 1 */
++#define RX_CNTRL1_RX_EN BIT(0)
++#define RX_CNTRL1_PADSTRIP_EN BIT(1)
++#define RX_CNTRL1_CRC_EN BIT(2)
++#define RX_CNTRL1_PAUSE_EN BIT(3)
++#define RX_CNTRL1_LOOP_EN BIT(4)
++#define RX_CNTRL1_ADDR_FLTR_EN BIT(5)
++#define RX_CNTRL1_RX_RUNT_EN BIT(6)
++#define RX_CNTRL1_BCAST_DIS BIT(7)
++
++/* RX Control Register 2 */
++#define RX_CNTRL2_DEFER_EN BIT(0)
++
++/* Core Control Register */
++#define CORE_RESET BIT(0)
++#define CORE_RX_FIFO_FLUSH BIT(1)
++#define CORE_TX_FIFO_FLUSH BIT(2)
++#define CORE_SEND_JAM BIT(3)
++#define CORE_MDC_EN BIT(4)
++
++/* Definitions for MII access routines*/
++
++#define MII_REG_SHL 16
++#define MII_ADDR_SHL 21
++
++#define MII_GO BIT(31)
++#define MII_WRITE BIT(26)
++#define MII_READ_FAIL BIT(31)
++
++#define MII_TIMEOUT_10TH_SECS 5
++#define MII_10TH_SEC_IN_MILLIS 100
++
++/*
++ *
++ * Default values
++ *
++ */
++
++
++#define MAC_TX_CNTRL1_DEFAULT (\
++ TX_CNTRL1_TX_EN | \
++ TX_CNTRL1_RETRY | \
++ TX_CNTRL1_FCS_EN | \
++ TX_CNTRL1_2DEFER | \
++ TX_CNTRL1_PAD_EN )
++
++#define MAC_TX_MAX_RETRIES_DEFAULT 0x0f
++
++#define MAC_RX_CNTRL1_DEFAULT ( \
++ RX_CNTRL1_PADSTRIP_EN | \
++ RX_CNTRL1_CRC_EN | \
++ RX_CNTRL1_RX_EN )
++
++#define MAC_RX_CNTRL2_DEFAULT 0x0
++#define MAC_TX_CNTRL2_DEFAULT TX_CNTRL2_RETRIES_MASK
++
++/* Thresholds determined by NPE firmware FS */
++#define MAC_THRESH_P_EMPTY_DEFAULT 0x12
++#define MAC_THRESH_P_FULL_DEFAULT 0x30
++
++/* Number of bytes that must be in the tx fifo before
++ * transmission commences */
++#define MAC_BUF_SIZE_TX_DEFAULT 0x8
++
++/* One-part deferral values */
++#define MAC_TX_DEFER_DEFAULT 0x15
++#define MAC_RX_DEFER_DEFAULT 0x16
++
++/* Two-part deferral values... */
++#define MAC_TX_TWO_DEFER_1_DEFAULT 0x08
++#define MAC_TX_TWO_DEFER_2_DEFAULT 0x07
++
++/* This value applies to MII */
++#define MAC_SLOT_TIME_DEFAULT 0x80
++
++/* This value applies to RMII */
++#define MAC_SLOT_TIME_RMII_DEFAULT 0xFF
++
++#define MAC_ADDR_MASK_DEFAULT 0xFF
++
++#define MAC_INT_CLK_THRESH_DEFAULT 0x1
++/* The following is a value chosen at random */
++#define RANDOM_SEED_DEFAULT 0x8
++
++/* By default we must configure the MAC to generate the MDC clock*/
++#define CORE_DEFAULT (CORE_MDC_EN)
++
++/* End of Intel provided register information */
++
++extern int
++mdio_read_register(struct net_device *dev, int phy_addr, int phy_reg);
++extern void
++mdio_write_register(struct net_device *dev, int phy_addr, int phy_reg, int val);
++extern void init_mdio(struct net_device *dev, int phy_id);
++
++struct mac_info {
++ u32 __iomem *addr;
++ struct resource *res;
++ struct device *npe_dev;
++ struct qm_qmgr *qmgr;
++ struct qm_queue *rxq;
++ struct qm_queue *txq;
++ u32 irqflags;
++ struct net_device_stats stat;
++ struct mii_if_info mii;
++ struct work_struct mdio_thread;
++ int rxq_pkt;
++ int unloading;
++ struct mac_plat_info *plat;
++};
++
++static inline void mac_write_reg(struct mac_info *mac, int offset, u32 val)
++{
++ *(mac->addr + offset) = val;
++}
++static inline u32 mac_read_reg(struct mac_info *mac, int offset)
++{
++ return *(mac->addr + offset);
++}
++static inline void mac_set_regbit(struct mac_info *mac, int offset, u32 bit)
++{
++ mac_write_reg(mac, offset, mac_read_reg(mac, offset) | bit);
++}
++static inline void mac_reset_regbit(struct mac_info *mac, int offset, u32 bit)
++{
++ mac_write_reg(mac, offset, mac_read_reg(mac, offset) & ~bit);
++}
++
++static inline void mac_mdio_cmd_write(struct mac_info *mac, u32 cmd)
++{
++ int i;
++ for(i=0; i<4; i++) {
++ mac_write_reg(mac, MAC_MDIO_CMD + i, cmd & 0xff);
++ cmd >>=8;
++ }
++}
++
++#define mac_mdio_cmd_read(mac) mac_mdio_read((mac), MAC_MDIO_CMD)
++#define mac_mdio_status_read(mac) mac_mdio_read((mac), MAC_MDIO_STS)
++static inline u32 mac_mdio_read(struct mac_info *mac, int offset)
++{
++ int i;
++ u32 data = 0;
++ for(i=0; i<4; i++) {
++ data |= (mac_read_reg(mac, offset + i) & 0xff) << (i*8);
++ }
++ return data;
++}
++
++static inline u32 mdio_cmd(int phy_addr, int phy_reg)
++{
++ return phy_addr << MII_ADDR_SHL |
++ phy_reg << MII_REG_SHL |
++ MII_GO;
++}
++
++#define MAC_REG_LIST { \
++ MAC_TX_CNTRL1, MAC_TX_CNTRL2, \
++ MAC_RX_CNTRL1, MAC_RX_CNTRL2, \
++ MAC_RANDOM_SEED, MAC_THRESH_P_EMPTY, MAC_THRESH_P_FULL, \
++ MAC_BUF_SIZE_TX, MAC_TX_DEFER, MAC_RX_DEFER, \
++ MAC_TX_TWO_DEFER_1, MAC_TX_TWO_DEFER_2, MAC_SLOT_TIME, \
++ MAC_ADDR_MASK +0, MAC_ADDR_MASK +1, MAC_ADDR_MASK +2, \
++ MAC_ADDR_MASK +3, MAC_ADDR_MASK +4, MAC_ADDR_MASK +5, \
++ MAC_ADDR +0, MAC_ADDR +1, MAC_ADDR +2, \
++ MAC_ADDR +3, MAC_ADDR +4, MAC_ADDR +5, \
++ MAC_INT_CLK_THRESH, \
++ MAC_UNI_ADDR +0, MAC_UNI_ADDR +1, MAC_UNI_ADDR +2, \
++ MAC_UNI_ADDR +3, MAC_UNI_ADDR +4, MAC_UNI_ADDR +5, \
++ MAC_CORE_CNTRL \
++}
+Index: linux-2.6.18/drivers/net/ixp4xx/mac_driver.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/mac_driver.c 2006-10-17 05:40:03.000000000 -0700
+@@ -0,0 +1,578 @@
++/*
++ * mac_driver.c - provide a network interface for each MAC
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++
++#include <linux/ixp_qmgr.h>
++#include <linux/ixp_npe.h>
++#include "mac.h"
++
++#define MDIO_INTERVAL (3*HZ)
++#define RX_QUEUE_PREFILL 64
++
++#define IXMAC_NAME "ixp4xx_mac"
++#define IXMAC_VERSION "0.2.1"
++
++#define MAC_DEFAULT_REG(mac, name) \
++ mac_write_reg(mac, MAC_ ## name, MAC_ ## name ## _DEFAULT)
++
++#define RX_DONE_QID 4
++#define TX_DONE_QID 31
++
++extern int queue_send_skb(struct qm_queue *queue, struct sk_buff *skb);
++extern int queue_fill_skb(struct qm_queue *queue, struct net_device *dev);
++extern int queue_drain(struct qm_queue *queue);
++extern struct sk_buff *queue_return_skb(struct qm_queue *queue);
++
++
++/* Since the NPEs use 1 Return Q for sent frames, we need a device
++ * independent return Q. We call it tx_doneq.
++ * It will be initialized during module load and uninitialized
++ * during module unload. Evil hack, but there is no choice :-(
++ */
++
++static struct qm_queue *tx_doneq = NULL;
++static struct qm_queue *rx_doneq = NULL;
++
++static void mac_init(struct mac_info *mac)
++{
++ MAC_DEFAULT_REG(mac, TX_CNTRL2);
++ MAC_DEFAULT_REG(mac, THRESH_P_EMPTY);
++ MAC_DEFAULT_REG(mac, THRESH_P_FULL);
++ MAC_DEFAULT_REG(mac, TX_DEFER);
++ MAC_DEFAULT_REG(mac, TX_TWO_DEFER_1);
++ MAC_DEFAULT_REG(mac, TX_TWO_DEFER_2);
++ MAC_DEFAULT_REG(mac, SLOT_TIME);
++ MAC_DEFAULT_REG(mac, INT_CLK_THRESH);
++ MAC_DEFAULT_REG(mac, BUF_SIZE_TX);
++ MAC_DEFAULT_REG(mac, TX_CNTRL1);
++ MAC_DEFAULT_REG(mac, RX_CNTRL1);
++}
++
++static void mac_set_uniaddr(struct net_device *dev)
++{
++ int i;
++ struct mac_info *mac = netdev_priv(dev);
++ struct npe_info *npe = dev_get_drvdata(mac->npe_dev);
++
++ /* check for multicast */
++ if (dev->dev_addr[0] & 1)
++ return;
++
++ npe_mh_setportaddr(npe, mac->plat, dev->dev_addr);
++ npe_mh_disable_firewall(npe, mac->plat);
++ for (i=0; i<dev->addr_len; i++)
++ mac_write_reg(mac, MAC_UNI_ADDR + i, dev->dev_addr[i]);
++}
++
++static void update_duplex_mode(struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ printk("Duplex mode %s =%d\n", dev->name, mac->mii.full_duplex);
++ if (mac->mii.full_duplex) {
++ mac_reset_regbit(mac, MAC_TX_CNTRL1, TX_CNTRL1_DUPLEX);
++ } else {
++ mac_set_regbit(mac, MAC_TX_CNTRL1, TX_CNTRL1_DUPLEX);
++ }
++}
++
++static int media_check(struct net_device *dev, int init)
++{
++ struct mac_info *mac = netdev_priv(dev);
++
++ if (mii_check_media(&mac->mii, 1, init)) {
++ update_duplex_mode(dev);
++ return 1;
++ }
++ return 0;
++}
++
++static void irqcb_recv(struct qm_queue *queue)
++{
++ struct net_device *dev;
++ struct mac_info *mac;
++ struct sk_buff *skb;
++
++ queue_ack_irq(queue);
++ skb = queue_return_skb(queue);
++ while (skb) {
++ int rc;
++ dev = skb->dev;
++ mac = netdev_priv(dev);
++ skb->protocol = eth_type_trans(skb, dev);
++ dev->last_rx = jiffies;
++ rc = netif_rx(skb);
++ if (rc == NET_RX_DROP) {
++ mac->stat.rx_dropped++;
++ } else {
++ mac->stat.rx_packets++;
++ mac->stat.rx_bytes += skb->len;
++ }
++
++ if (!mac->unloading)
++ queue_fill_skb(mac->rxq, dev);
++ else
++ mac->rxq_pkt--;
++
++ skb = queue_return_skb(queue);
++ }
++}
++
++void irqcb_txdone(struct qm_queue *queue)
++{
++ queue_ack_irq(queue);
++ while (queue_drain(queue));
++}
++
++static void ixmac_set_rx_mode (struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ struct dev_mc_list *mclist;
++ u8 aset[dev->addr_len], aclear[dev->addr_len];
++ int i,j;
++
++ if (dev->flags & IFF_PROMISC) {
++ mac_reset_regbit(mac, MAC_RX_CNTRL1, RX_CNTRL1_ADDR_FLTR_EN);
++ } else {
++ mac_set_regbit(mac, MAC_RX_CNTRL1, RX_CNTRL1_ADDR_FLTR_EN);
++
++ mclist = dev->mc_list;
++ memset(aset, 0xff, dev->addr_len);
++ memset(aclear, 0x00, dev->addr_len);
++ for (i = 0; mclist && i < dev->mc_count; i++) {
++ for (j=0; j< dev->addr_len; j++) {
++ aset[j] &= mclist->dmi_addr[j];
++ aclear[j] |= mclist->dmi_addr[j];
++ }
++ mclist = mclist->next;
++ }
++ for (j=0; j< dev->addr_len; j++) {
++ aclear[j] = aset[j] | ~aclear[j];
++ }
++ for (i=0; i<dev->addr_len; i++) {
++ mac_write_reg(mac, MAC_ADDR + i, aset[i]);
++ mac_write_reg(mac, MAC_ADDR_MASK + i, aclear[i]);
++ }
++ }
++}
++
++static int ixmac_open (struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ struct npe_info *npe = dev_get_drvdata(mac->npe_dev);
++ int i;
++
++ /* first check if Microcode was downloaded into this NPE */
++ if (!( npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN)) {
++ printk(KERN_ERR "Missing microcode for %s\n", npe->plat->name);
++ return -EIO;
++ }
++
++ for (i=0; i<RX_QUEUE_PREFILL; i++) {
++ queue_fill_skb(mac->rxq, dev);
++ }
++ mac->rxq_pkt += RX_QUEUE_PREFILL;
++
++ mac_init(mac);
++ npe_mh_set_rxqid(npe, mac->plat, RX_DONE_QID);
++ mac_set_uniaddr(dev);
++
++ media_check(dev, 1);
++
++ ixmac_set_rx_mode(dev);
++
++ netif_start_queue(dev);
++ schedule_delayed_work(&mac->mdio_thread, MDIO_INTERVAL);
++ return 0;
++}
++
++static int ixmac_start_xmit (struct sk_buff *skb, struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++
++ if (queue_send_skb(mac->txq, skb)) {
++ mac->stat.tx_packets++;
++ mac->stat.tx_bytes += skb->len;
++ } else {
++ mac->stat.tx_errors++;
++ dev_kfree_skb(skb);
++ }
++
++ dev->trans_start = jiffies;
++ return 0;
++}
++
++static int ixmac_close (struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++
++ netif_stop_queue (dev);
++
++ if (mac->mdio_thread.pending)
++ cancel_rearming_delayed_work(&mac->mdio_thread);
++
++
++ /* After doing all our business, the rxfreeq must
++ * carry as much packets as we gave it during setup.
++ * Here we calc the missing packets.
++ */
++ mac->rxq_pkt -= queue_len(mac->rxq);
++
++ while (queue_drain(mac->txq));
++ while (queue_drain(mac->rxq));
++
++ return 0;
++}
++
++static int ixmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ int rc, duplex_changed;
++
++ if (!netif_running(dev))
++ return -EINVAL;
++
++
++ if (!try_module_get(THIS_MODULE))
++ return -ENODEV;
++ rc = generic_mii_ioctl(&mac->mii, if_mii(rq), cmd, &duplex_changed);
++ module_put(THIS_MODULE);
++ if (duplex_changed)
++ update_duplex_mode(dev);
++ return rc;
++}
++
++static struct net_device_stats *ixmac_stats (struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ return &mac->stat;
++}
++
++static void ixmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ struct npe_info *npe = dev_get_drvdata(mac->npe_dev);
++
++ strcpy(info->driver, IXMAC_NAME);
++ strcpy(info->version, IXMAC_VERSION);
++ if (npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN) {
++ snprintf(info->fw_version, 32, "%d.%d func [%d]",
++ npe->img_info[2], npe->img_info[3], npe->img_info[1]);
++ }
++ strncpy(info->bus_info, npe->plat->name, ETHTOOL_BUSINFO_LEN);
++}
++
++static int ixmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ mii_ethtool_gset(&mac->mii, cmd);
++ return 0;
++}
++
++static int ixmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ int rc;
++ rc = mii_ethtool_sset(&mac->mii, cmd);
++ return rc;
++}
++
++static int ixmac_nway_reset(struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ return mii_nway_restart(&mac->mii);
++}
++
++static u32 ixmac_get_link(struct net_device *dev)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ return mii_link_ok(&mac->mii);
++}
++
++static const int mac_reg_list[] = MAC_REG_LIST;
++
++static int ixmac_get_regs_len(struct net_device *dev)
++{
++ return ARRAY_SIZE(mac_reg_list);
++}
++
++static void
++ixmac_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
++{
++ int i;
++ struct mac_info *mac = netdev_priv(dev);
++ u8 *buf = regbuf;
++
++ for (i=0; i<regs->len; i++) {
++ buf[i] = mac_read_reg(mac, mac_reg_list[i]);
++ }
++}
++
++static struct ethtool_ops ixmac_ethtool_ops = {
++ .get_drvinfo = ixmac_get_drvinfo,
++ .get_settings = ixmac_get_settings,
++ .set_settings = ixmac_set_settings,
++ .nway_reset = ixmac_nway_reset,
++ .get_link = ixmac_get_link,
++ .get_regs_len = ixmac_get_regs_len,
++ .get_regs = ixmac_get_regs,
++ .get_perm_addr = ethtool_op_get_perm_addr,
++};
++static void mac_mdio_thread (void *_data)
++{
++ struct net_device *dev = _data;
++ struct mac_info *mac = netdev_priv(dev);
++
++ media_check(dev, 0);
++ schedule_delayed_work(&mac->mdio_thread, MDIO_INTERVAL);
++}
++
++static int mac_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ struct mac_info *mac;
++ struct net_device* dev;
++ struct npe_info *npe;
++ struct mac_plat_info *plat = pdev->dev.platform_data;
++ int size, ret;
++
++ if (!(res = platform_get_resource(pdev, IORESOURCE_MEM, 0))) {
++ return -EIO;
++ }
++ if (!(dev = alloc_etherdev (sizeof(struct mac_info)))) {
++ return -ENOMEM;
++ }
++ SET_MODULE_OWNER(dev);
++ SET_NETDEV_DEV(dev, &pdev->dev);
++ mac = netdev_priv(dev);
++
++ size = res->end - res->start +1;
++ mac->res = request_mem_region(res->start, size, IXMAC_NAME);
++ if (!mac->res) {
++ ret = -EBUSY;
++ goto out_free;
++ }
++
++ mac->addr = ioremap(res->start, size);
++ if (!mac->addr) {
++ ret = -ENOMEM;
++ goto out_rel;
++ }
++
++ dev->open = ixmac_open;
++ dev->hard_start_xmit = ixmac_start_xmit;
++ dev->stop = ixmac_close;
++ dev->get_stats = ixmac_stats;
++ dev->do_ioctl = ixmac_ioctl;
++ dev->set_multicast_list = ixmac_set_rx_mode;
++ dev->ethtool_ops = &ixmac_ethtool_ops;
++
++ mac->npe_dev = get_npe_by_id(plat->npe_id);
++ if (!mac->npe_dev) {
++ ret = -EIO;
++ goto out_unmap;
++ }
++ if (!try_module_get(mac->npe_dev->driver->owner)) {
++ put_device(mac->npe_dev);
++ ret = -EIO;
++ goto out_unmap;
++ }
++
++ npe = dev_get_drvdata(mac->npe_dev);
++
++ mac->rxq = request_queue(plat->rxq_id, 128);
++ if (IS_ERR(mac->rxq)) {
++ printk(KERN_ERR "Error requesting Q: %d\n", plat->rxq_id);
++ ret = -EBUSY;
++ goto out_putmod;
++ }
++ mac->txq = request_queue(plat->txq_id, 128);
++ if (IS_ERR(mac->txq)) {
++ printk(KERN_ERR "Error requesting Q: %d\n", plat->txq_id);
++ release_queue(mac->rxq);
++ ret = -EBUSY;
++ goto out_putmod;
++ }
++
++ mac->qmgr = dev_get_drvdata(mac->rxq->dev);
++ if (register_netdev (dev)) {
++ release_queue(mac->rxq);
++ release_queue(mac->txq);
++ ret = -EIO;
++ goto out_putmod;
++ }
++
++ mac->plat = plat;
++ platform_set_drvdata(pdev, dev);
++
++ mac_write_reg(mac, MAC_CORE_CNTRL, CORE_RESET);
++ udelay(500);
++ mac_write_reg(mac, MAC_CORE_CNTRL, CORE_MDC_EN);
++
++ init_mdio(dev, plat->phy_id);
++
++ INIT_WORK(&mac->mdio_thread, mac_mdio_thread, dev);
++
++ /* The place of the MAC address is very system dependent.
++ * Here we use a random one to be replaced by one of the
++ * following commands:
++ * "ip link set address 02:03:04:04:04:01 dev eth0"
++ * "ifconfig eth0 hw ether 02:03:04:04:04:07"
++ */
++ random_ether_addr(dev->dev_addr);
++ dev->dev_addr[5] = plat->phy_id;
++
++ printk(KERN_INFO IXMAC_NAME " driver " IXMAC_VERSION
++ ": %s on %s with PHY[%d] initialized\n",
++ dev->name, npe->plat->name, plat->phy_id);
++
++ return 0;
++
++out_putmod:
++ module_put(mac->npe_dev->driver->owner);
++out_unmap:
++ iounmap(mac->addr);
++out_rel:
++ release_resource(mac->res);
++out_free:
++ kfree(mac);
++ return ret;
++}
++
++static int mac_remove(struct platform_device *pdev)
++{
++ struct net_device* dev = platform_get_drvdata(pdev);
++ struct mac_info *mac = netdev_priv(dev);
++ struct npe_info *npe = dev_get_drvdata(mac->npe_dev);
++ int loop = 0;
++ struct sk_buff *skb;
++
++ ixmac_close(dev);
++
++ mac->unloading = 1;
++
++ /* Now there are some skb hold by the NPE.
++ * We switch the MAC in loopback mode and send a pseudo packet
++ * that will be returned by the NPE in its last SKB.
++ * We will also try to isolate the PHY to keep the packets internal.
++ */
++
++ if (npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN) {
++ mac_reset_regbit(mac, MAC_CORE_CNTRL, CORE_MDC_EN);
++ mac_set_regbit(mac, MAC_RX_CNTRL1, RX_CNTRL1_LOOP_EN);
++
++ npe_mh_npe_loopback_mode(npe, mac->plat, 1);
++ mdelay(200);
++
++ while (mac->rxq_pkt && loop++ < 2000 ) {
++ skb = dev_alloc_skb(128);
++ skb_put(skb, 64);
++ /* actually the packets should never leave the system,
++ * but if they do, they shall contain 0s instead of
++ * intresting random data....
++ */
++ memset(skb->data, 0, skb->len);
++ queue_send_skb(mac->txq, skb);
++
++ mdelay(1);
++ }
++
++ npe_mh_npe_loopback_mode(npe, mac->plat, 0);
++ }
++ /* Flush MAC TX fifo to drain the bogus packages */
++ mac_set_regbit(mac, MAC_CORE_CNTRL, CORE_TX_FIFO_FLUSH);
++ mac_reset_regbit(mac, MAC_RX_CNTRL1, RX_CNTRL1_RX_EN);
++ mac_reset_regbit(mac, MAC_TX_CNTRL1, TX_CNTRL1_TX_EN);
++ mac_reset_regbit(mac, MAC_RX_CNTRL1, RX_CNTRL1_LOOP_EN);
++ mac_reset_regbit(mac, MAC_CORE_CNTRL, CORE_TX_FIFO_FLUSH);
++ mac_reset_regbit(mac, MAC_CORE_CNTRL, CORE_TX_FIFO_FLUSH);
++
++ unregister_netdev(dev);
++
++ while (queue_drain(mac->txq));
++ release_queue(mac->txq);
++ while (queue_drain(mac->rxq));
++ release_queue(mac->rxq);
++
++ module_put(mac->npe_dev->driver->owner);
++ put_device(mac->npe_dev);
++
++ iounmap(mac->addr);
++ release_resource(mac->res);
++ platform_set_drvdata(pdev, NULL);
++ free_netdev(dev);
++ return 0;
++}
++
++static struct platform_driver ixp4xx_mac = {
++ .driver.name = IXMAC_NAME,
++ .probe = mac_probe,
++ .remove = mac_remove,
++};
++
++static int __init init_mac(void)
++{
++ /* The TX done Queue handles skbs sent out by the NPE */
++ tx_doneq = request_queue(TX_DONE_QID, 128);
++ if (IS_ERR(tx_doneq)) {
++ printk(KERN_ERR "Error requesting Q: %d\n", TX_DONE_QID);
++ return -EBUSY;
++ }
++ tx_doneq->irq_cb = irqcb_txdone;
++ /* drain the TX queue if it is half full */
++ queue_set_watermarks(tx_doneq, 0, 64);
++ queue_set_irq_src(tx_doneq, Q_IRQ_ID_NF);
++ queue_enable_irq(tx_doneq);
++
++ /* RX Queue handles SKBs with a valid frame */
++ rx_doneq = request_queue(RX_DONE_QID, 128);
++ if (IS_ERR(rx_doneq)) {
++ printk(KERN_ERR "Error requesting Q: %d\n", RX_DONE_QID);
++ return -EBUSY;
++ }
++ irqcb_recv(rx_doneq);
++ rx_doneq->irq_cb = irqcb_recv;
++ queue_set_watermarks(rx_doneq, 0, 0);
++ queue_set_irq_src(rx_doneq, Q_IRQ_ID_NOT_E);
++ queue_enable_irq(rx_doneq);
++
++ return platform_driver_register(&ixp4xx_mac);
++}
++
++static void __exit finish_mac(void)
++{
++ platform_driver_unregister(&ixp4xx_mac);
++ if (tx_doneq) {
++ queue_disable_irq(tx_doneq);
++ while (queue_drain(tx_doneq));
++ release_queue(tx_doneq);
++ }
++ if (rx_doneq) {
++ queue_disable_irq(rx_doneq);
++ while (queue_drain(rx_doneq));
++ release_queue(rx_doneq);
++ }
++}
++
++module_init(init_mac);
++module_exit(finish_mac);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt at innominate.com>");
++
+Index: linux-2.6.18/drivers/net/ixp4xx/npe_mh.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/npe_mh.c 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,137 @@
++/*
++ * npe_mh.c - NPE message handler.
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#include <linux/ixp_npe.h>
++#include <linux/slab.h>
++
++#define MAX_RETRY 200
++
++struct npe_mh_msg {
++ union {
++ u8 byte[8]; /* Very desciptive name, I know ... */
++ u32 data[2];
++ } u;
++};
++
++/*
++ * The whole code in this function must be reworked.
++ * It is in a state that works but is not rock solid
++ */
++static int send_message(struct npe_info *npe, struct npe_mh_msg *msg)
++{
++ int i,j;
++ u32 send[2], recv[2];
++
++ for (i=0; i<2; i++)
++ send[i] = be32_to_cpu(msg->u.data[i]);
++
++ if ((npe_reg_read(npe, IX_NPEDL_REG_OFFSET_STAT) &
++ IX_NPEMH_NPE_STAT_IFNE))
++ return -1;
++
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_FIFO, send[0]);
++ for(i=0; i<MAX_RETRY; i++) {
++ /* if the IFNF status bit is unset then the inFIFO is full */
++ if (npe_reg_read(npe, IX_NPEDL_REG_OFFSET_STAT) &
++ IX_NPEMH_NPE_STAT_IFNF)
++ break;
++ }
++ if (i>=MAX_RETRY)
++ return -1;
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_FIFO, send[1]);
++ i=0;
++ while (!(npe_reg_read(npe, IX_NPEDL_REG_OFFSET_STAT) &
++ IX_NPEMH_NPE_STAT_OFNE)) {
++ if (i++>MAX_RETRY) {
++ printk("Waiting for Output FIFO NotEmpty failed\n");
++ return -1;
++ }
++ }
++ //printk("Output FIFO Not Empty. Loops: %d\n", i);
++ j=0;
++ while (npe_reg_read(npe, IX_NPEDL_REG_OFFSET_STAT) &
++ IX_NPEMH_NPE_STAT_OFNE) {
++ recv[j&1] = npe_reg_read(npe,IX_NPEDL_REG_OFFSET_FIFO);
++ j++;
++ }
++ if ((recv[0] != send[0]) || (recv[1] != send[1])) {
++ printk("Unexpected answer: Send %08x:%08x Ret %08x:%08x\n",
++ send[0], send[1], recv[0], recv[1]);
++ }
++ return 0;
++}
++
++#define CMD 0
++#define PORT 1
++#define MAC 2
++
++#define IX_ETHNPE_EDB_SETPORTADDRESS 0x01
++#define IX_ETHNPE_FW_SETFIREWALLMODE 0x0E
++#define IX_ETHNPE_VLAN_SETRXQOSENTRY 0x0B
++#define IX_ETHNPE_SETLOOPBACK_MODE 0x12
++
++#define logical_id(mp) (((mp)->npe_id << 4) | ((mp)->port_id & 0xf))
++
++int npe_mh_setportaddr(struct npe_info *npe, struct mac_plat_info *mp,
++ u8 *macaddr)
++{
++ struct npe_mh_msg msg;
++
++ msg.u.byte[CMD] = IX_ETHNPE_EDB_SETPORTADDRESS;
++ msg.u.byte[PORT] = mp->eth_id;
++ memcpy(msg.u.byte + MAC, macaddr, 6);
++
++ return send_message(npe, &msg);
++}
++
++int npe_mh_disable_firewall(struct npe_info *npe, struct mac_plat_info *mp)
++{
++ struct npe_mh_msg msg;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.u.byte[CMD] = IX_ETHNPE_FW_SETFIREWALLMODE;
++ msg.u.byte[PORT] = logical_id(mp);
++
++ return send_message(npe, &msg);
++}
++
++int npe_mh_npe_loopback_mode(struct npe_info *npe, struct mac_plat_info *mp,
++ int enable)
++{
++ struct npe_mh_msg msg;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.u.byte[CMD] = IX_ETHNPE_SETLOOPBACK_MODE;
++ msg.u.byte[PORT] = logical_id(mp);
++ msg.u.byte[3] = enable ? 1 : 0;
++
++ return send_message(npe, &msg);
++}
++
++int npe_mh_set_rxqid(struct npe_info *npe, struct mac_plat_info *mp, int qid)
++{
++ struct npe_mh_msg msg;
++ int i, ret;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.u.byte[CMD] = IX_ETHNPE_VLAN_SETRXQOSENTRY;
++ msg.u.byte[PORT] = logical_id(mp);
++ msg.u.byte[5] = qid | 0x80;
++ msg.u.byte[7] = qid<<4;
++ for(i=0; i<8; i++) {
++ msg.u.byte[3] = i;
++ if ((ret = send_message(npe, &msg)))
++ return ret;
++ }
++ return 0;
++}
++
++EXPORT_SYMBOL(npe_mh_setportaddr);
++EXPORT_SYMBOL(npe_mh_disable_firewall);
++EXPORT_SYMBOL(npe_mh_set_rxqid);
++EXPORT_SYMBOL(npe_mh_npe_loopback_mode);
+Index: linux-2.6.18/drivers/net/ixp4xx/phy.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/phy.c 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,113 @@
++/*
++ * phy.c - MDIO functions and mii initialisation
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++
++#include <linux/mutex.h>
++#include "mac.h"
++
++#define MAX_PHYS (1<<5)
++
++/*
++ * We must always use the same MAC for acessing the MDIO
++ * We may not use each MAC for its PHY :-(
++ */
++
++static struct net_device *phy_dev = NULL;
++static struct mutex mtx;
++
++/* here we remember if the PHY is alive, to avoid log dumping */
++static int phy_works[MAX_PHYS];
++
++int mdio_read_register(struct net_device *dev, int phy_addr, int phy_reg)
++{
++ struct mac_info *mac;
++ u32 cmd, reg;
++ int cnt = 0;
++
++ if (!phy_dev)
++ return 0;
++
++ mac = netdev_priv(phy_dev);
++ cmd = mdio_cmd(phy_addr, phy_reg);
++ mutex_lock_interruptible(&mtx);
++ mac_mdio_cmd_write(mac, cmd);
++ while((cmd = mac_mdio_cmd_read(mac)) & MII_GO) {
++ if (++cnt >= 100) {
++ printk("%s: PHY[%d] access failed\n",
++ dev->name, phy_addr);
++ break;
++ }
++ schedule();
++ }
++ reg = mac_mdio_status_read(mac);
++ mutex_unlock(&mtx);
++ if (reg & MII_READ_FAIL) {
++ if (phy_works[phy_addr]) {
++ printk("%s: PHY[%d] unresponsive\n",
++ dev->name, phy_addr);
++ }
++ reg = 0;
++ phy_works[phy_addr] = 0;
++ } else {
++ if ( !phy_works[phy_addr]) {
++ printk("%s: PHY[%d] responsive again\n",
++ dev->name, phy_addr);
++ }
++ phy_works[phy_addr] = 1;
++ }
++ return reg & 0xffff;
++}
++
++void
++mdio_write_register(struct net_device *dev, int phy_addr, int phy_reg, int val)
++{
++ struct mac_info *mac;
++ u32 cmd;
++ int cnt=0;
++
++ if (!phy_dev)
++ return;
++
++ mac = netdev_priv(phy_dev);
++ cmd = mdio_cmd(phy_addr, phy_reg) | MII_WRITE | val;
++
++ mutex_lock_interruptible(&mtx);
++ mac_mdio_cmd_write(mac, cmd);
++ while((cmd = mac_mdio_cmd_read(mac)) & MII_GO) {
++ if (++cnt >= 100) {
++ printk("%s: PHY[%d] access failed\n",
++ dev->name, phy_addr);
++ break;
++ }
++ schedule();
++ }
++ mutex_unlock(&mtx);
++}
++
++void init_mdio(struct net_device *dev, int phy_id)
++{
++ struct mac_info *mac = netdev_priv(dev);
++ int i;
++
++ /* All phy operations should use the same MAC
++ * (my experience)
++ */
++ if (mac->plat->eth_id == 0) {
++ mutex_init(&mtx);
++ phy_dev = dev;
++ for (i=0; i<MAX_PHYS; i++)
++ phy_works[i] = 1;
++ }
++ mac->mii.dev = dev;
++ mac->mii.phy_id = phy_id;
++ mac->mii.phy_id_mask = MAX_PHYS - 1;
++ mac->mii.reg_num_mask = 0x1f;
++ mac->mii.mdio_read = mdio_read_register;
++ mac->mii.mdio_write = mdio_write_register;
++}
++
+Index: linux-2.6.18/drivers/net/ixp4xx/qmgr_eth.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/qmgr_eth.c 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,127 @@
++/*
++ * qmgr_eth.c - Glue between qmgr and MAC. Linked to mac to keep qmgr.ko
++ * more virtual
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#include <linux/skbuff.h>
++#include <linux/dma-mapping.h>
++#include <linux/netdevice.h>
++#include <linux/ixp_qmgr.h>
++
++#define SKB_SIZE 1688
++
++int queue_send_skb(struct qm_queue *queue, struct sk_buff *skb)
++{
++ struct npe_cont *cont;
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++
++ cont = qmgr_get_cont(qmgr);
++ if (!cont)
++ return 0;
++
++ cont->h.skb = skb;
++#ifndef __ARMEB__
++ /* swap the payload of the SKB */
++ {
++ u32 *p = (u32*)((unsigned)skb->data & ~0x3);
++ u32 *e = (u32*)(((unsigned)skb->data + skb->len + 3) & ~0x3);
++ while (p < e)
++ *p = cpu_to_be32(*p), ++p;
++ }
++#endif
++ /* fill the NPE information record */
++ cont->ctl.eth.next = 0;
++ cont->ctl.eth.buf_len = skb->end - skb->head;
++ cont->ctl.eth.pkt_len = skb->len;
++ cont->ctl.eth.phys_addr =
++ dma_map_single(queue->dev, skb->data, skb->len, DMA_TO_DEVICE);
++
++ queue_put_entry(queue, cont->phys);
++
++ if (queue_stat(queue) == 2) { /* overflow */
++ return 0;
++ }
++ return 1;
++}
++
++int queue_fill_skb(struct qm_queue *queue, struct net_device *dev)
++{
++ struct npe_cont *cont;
++ struct sk_buff *skb;
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ int len;
++
++ cont = qmgr_get_cont(qmgr);
++ if (!cont)
++ return 0;
++ skb = dev_alloc_skb(SKB_SIZE);
++ if (!skb) {
++ qmgr_return_cont(qmgr, cont);
++ return 0;
++ }
++ len = skb->end - skb->data;
++ skb->dev = dev;
++ cont->h.skb = skb;
++ cont->ctl.eth.next = 0;
++ cont->ctl.eth.buf_len = len;
++ cont->ctl.eth.pkt_len = 0;
++ cont->ctl.eth.phys_addr =
++ dma_map_single(queue->dev, skb->data, len, DMA_FROM_DEVICE);
++
++ queue_put_entry(queue, cont->phys);
++
++ /* TODO: check quelen ?
++ * The current use guarantees that this queues will never overflow.
++ */
++ return 1;
++}
++
++int queue_drain(struct qm_queue *queue)
++{
++ u32 phys = *queue->acc_reg & ~0xf;
++ struct npe_cont *cont;
++
++ if (!phys)
++ return 0;
++ cont = dma_to_virt(queue->dev, phys);
++ cont = cont->virt;
++ dev_kfree_skb_any(cont->h.skb);
++ qmgr_return_cont(dev_get_drvdata(queue->dev), cont);
++ return 1;
++}
++
++struct sk_buff *queue_return_skb(struct qm_queue *queue)
++{
++ u32 phys = *queue->acc_reg & ~0xf;
++ struct sk_buff *skb;
++ struct npe_cont *cont;
++ int len, buflen;
++
++ if (!phys)
++ return NULL;
++
++ cont = dma_to_virt(queue->dev, phys);
++ cont = cont->virt;
++ skb = cont->h.skb;
++ buflen = cont->ctl.eth.buf_len;
++ len = cont->ctl.eth.pkt_len;
++ dma_unmap_single(queue->dev, cont->ctl.eth.phys_addr,
++ buflen, DMA_FROM_DEVICE);
++ qmgr_return_cont(dev_get_drvdata(queue->dev), cont);
++ skb_put(skb, len);
++#ifndef __ARMEB__
++ /* swap the payload of the SKB */
++ {
++ u32 *p = (u32*)((unsigned)skb->data & ~0x3);
++ u32 *e = (u32*)(((unsigned)skb->data + skb->len + 3) & ~0x3);
++ while (p < e)
++ *p = cpu_to_be32(*p), ++p;
++ }
++#endif
++ return skb;
++}
++
+Index: linux-2.6.18/drivers/net/ixp4xx/ucode_dl.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/drivers/net/ixp4xx/ucode_dl.c 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,466 @@
++/*
++ * ucode_dl.c - provide an NPE device and a char-dev for microcode download
++ *
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/miscdevice.h>
++#include <linux/platform_device.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/firmware.h>
++#include <linux/dma-mapping.h>
++#include <linux/byteorder/swab.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++
++#include <linux/ixp_npe.h>
++
++#define IXNPE_VERSION "IXP4XX NPE driver Version 0.2.0"
++
++#define DL_MAGIC 0xfeedf00d
++#define DL_MAGIC_SWAP 0x0df0edfe
++
++#define EOF_BLOCK 0xf
++#define IMG_SIZE(image) (((image)->size * sizeof(u32)) + \
++ sizeof(struct dl_image))
++
++#define BT_INSTR 0
++#define BT_DATA 1
++
++enum blk_type {
++ instruction,
++ data,
++};
++
++struct dl_block {
++ u32 type;
++ u32 offset;
++};
++
++struct dl_image {
++ u32 magic;
++ u32 id;
++ u32 size;
++ union {
++ u32 data[0];
++ struct dl_block block[0];
++ } u;
++};
++
++struct dl_codeblock {
++ u32 npe_addr;
++ u32 size;
++ u32 data[0];
++};
++
++static struct platform_driver ixp4xx_npe_driver;
++
++static void npe_stop(struct npe_info *npe)
++{
++ npe_write_exctl(npe, IX_NPEDL_EXCTL_CMD_NPE_STOP);
++ npe_write_exctl(npe, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
++}
++static void npe_reset_active(struct npe_info *npe, u32 reg)
++{
++ u32 regval;
++
++ regval = npe_read_ecs_reg(npe, reg);
++ regval &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
++ npe_write_ecs_reg(npe, reg, regval);
++}
++
++static void npe_start(struct npe_info *npe)
++{
++ npe_reset_active(npe, IX_NPEDL_ECS_PRI_1_CTXT_REG_0);
++ npe_reset_active(npe, IX_NPEDL_ECS_PRI_2_CTXT_REG_0);
++ npe_reset_active(npe, IX_NPEDL_ECS_DBG_CTXT_REG_0);
++
++ npe_write_exctl(npe, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
++ npe_write_exctl(npe, IX_NPEDL_EXCTL_CMD_NPE_START);
++}
++
++static int
++download_block(struct npe_info *npe, struct dl_codeblock *cb, unsigned type)
++{
++ int i;
++ int cmd;
++
++ switch (type) {
++ case BT_DATA:
++ cmd = IX_NPEDL_EXCTL_CMD_WR_DATA_MEM;
++ if (cb->npe_addr + cb->size > npe->plat->data_size) {
++ printk(KERN_INFO "Data size too large: %d+%d > %d\n",
++ cb->npe_addr, cb->size, npe->plat->data_size);
++ return -EIO;
++ }
++ break;
++ case BT_INSTR:
++ cmd = IX_NPEDL_EXCTL_CMD_WR_INS_MEM;
++ if (cb->npe_addr + cb->size > npe->plat->inst_size) {
++ printk(KERN_INFO "Instr size too large: %d+%d > %d\n",
++ cb->npe_addr, cb->size, npe->plat->inst_size);
++ return -EIO;
++ }
++ break;
++ default:
++ printk(KERN_INFO "Unknown CMD: %d\n", type);
++ return -EIO;
++ }
++
++ for (i=0; i < cb->size; i++) {
++ npe_write_cmd(npe, cb->npe_addr + i, cb->data[i], cmd);
++ }
++
++ return 0;
++}
++
++static int match_by_npeid(struct device *dev, void *id)
++{
++ struct npe_info *npe = dev_get_drvdata(dev);
++ if (!npe->plat)
++ return 0;
++ return (npe->plat->id == *(int*)id);
++}
++
++struct device *get_npe_by_id(int id)
++{
++ return driver_find_device(&ixp4xx_npe_driver.driver, NULL,
++ &id, match_by_npeid);
++}
++
++static int store_npe_image(struct dl_image *image, struct device *dev)
++{
++ struct dl_block *blk;
++ struct dl_codeblock *cb;
++ struct npe_info *npe;
++ int ret=0;
++
++ if (!dev) {
++ dev = get_npe_by_id( (image->id >> 24) & 0xf);
++ put_device(dev);
++ }
++ if (!dev)
++ return -ENODEV;
++
++ npe = dev_get_drvdata(dev);
++
++ if ( npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN) {
++ printk(KERN_INFO "Cowardly refusing to reload an Image "
++ "into the running %s\n", npe->plat->name);
++ return 0; /* indicate success anyway... */
++ }
++ npe_stop(npe);
++
++ for (blk = image->u.block; blk->type != EOF_BLOCK; blk++) {
++ if (blk->offset > image->size) {
++ printk(KERN_INFO "Block offset out of range\n");
++ return -EIO;
++ }
++ cb = (struct dl_codeblock*)&image->u.data[blk->offset];
++ if (blk->offset + cb->size + 2 > image->size) {
++ printk(KERN_INFO "Codeblock size out of range\n");
++ return -EIO;
++ }
++ if ((ret = download_block(npe, cb, blk->type)))
++ return ret;
++ }
++ *(u32*)npe->img_info = cpu_to_be32(image->id);
++ npe_start(npe);
++
++ printk(KERN_INFO "Image loaded to %s Func:%x, Rel: %x:%x, Status: %x\n",
++ npe->plat->name, npe->img_info[1], npe->img_info[2],
++ npe->img_info[3], npe_status(npe));
++ return 0;
++}
++
++static int ucode_open(struct inode *inode, struct file *file)
++{
++ file->private_data = kmalloc(sizeof(struct dl_image), GFP_KERNEL);
++ if (!file->private_data)
++ return -ENOMEM;
++ return 0;
++}
++
++static int ucode_close(struct inode *inode, struct file *file)
++{
++ kfree(file->private_data);
++ return 0;
++}
++
++static ssize_t ucode_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ union {
++ char *data;
++ struct dl_image *image;
++ } u;
++ const char __user *cbuf = buf;
++
++ u.data = file->private_data;
++
++ while (count) {
++ int len;
++ if (*ppos < sizeof(struct dl_image)) {
++ len = sizeof(struct dl_image) - *ppos;
++ len = len > count ? count : len;
++ if (copy_from_user(u.data + *ppos, cbuf, len))
++ return -EFAULT;
++ count -= len;
++ *ppos += len;
++ cbuf += len;
++ continue;
++ } else if (*ppos == sizeof(struct dl_image)) {
++ void *data;
++ if (u.image->magic == DL_MAGIC_SWAP) {
++ printk(KERN_INFO "swapped image found\n");
++ u.image->id = swab32(u.image->id);
++ u.image->size = swab32(u.image->size);
++ } else if (u.image->magic != DL_MAGIC) {
++ printk(KERN_INFO "Bad magic:%x\n",
++ u.image->magic);
++ return -EFAULT;
++ }
++ len = IMG_SIZE(u.image);
++ data = kmalloc(len, GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++ memcpy(data, u.data, *ppos);
++ kfree(u.data);
++ u.data = (char*)data;
++ file->private_data = data;
++ }
++ len = IMG_SIZE(u.image) - *ppos;
++ len = len > count ? count : len;
++ if (copy_from_user(u.data + *ppos, cbuf, len))
++ return -EFAULT;
++ count -= len;
++ *ppos += len;
++ cbuf += len;
++ if (*ppos == IMG_SIZE(u.image)) {
++ int ret, i;
++ *ppos = 0;
++ if (u.image->magic == DL_MAGIC_SWAP) {
++ for (i=0; i<u.image->size; i++) {
++ u.image->u.data[i] =
++ swab32(u.image->u.data[i]);
++ }
++ u.image->magic = swab32(u.image->magic);
++ }
++ ret = store_npe_image(u.image, NULL);
++ if (ret) {
++ printk(KERN_INFO "Error in NPE image: %x\n",
++ u.image->id);
++ return ret;
++ }
++ }
++ }
++ return (cbuf-buf);
++}
++
++static void npe_firmware_probe(struct device *dev)
++{
++#if (defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)) \
++ && defined(MODULE)
++ const struct firmware *fw_entry;
++ struct npe_info *npe = dev_get_drvdata(dev);
++ struct dl_image *image;
++ int ret = -1, i;
++
++ if (request_firmware(&fw_entry, npe->plat->name, dev) != 0) {
++ return;
++ }
++ image = (struct dl_image*)fw_entry->data;
++ /* Sanity checks */
++ if (fw_entry->size < sizeof(struct dl_image)) {
++ printk(KERN_ERR "Firmware error: too small\n");
++ goto out;
++ }
++ if (image->magic == DL_MAGIC_SWAP) {
++ printk(KERN_INFO "swapped image found\n");
++ image->id = swab32(image->id);
++ image->size = swab32(image->size);
++ } else if (image->magic != DL_MAGIC) {
++ printk(KERN_ERR "Bad magic:%x\n", image->magic);
++ goto out;
++ }
++ if (IMG_SIZE(image) != fw_entry->size) {
++ printk(KERN_ERR "Firmware error: bad size\n");
++ goto out;
++ }
++ if (((image->id >> 24) & 0xf) != npe->plat->id) {
++ printk(KERN_ERR "NPE id missmatch\n");
++ goto out;
++ }
++ if (image->magic == DL_MAGIC_SWAP) {
++ for (i=0; i<image->size; i++) {
++ image->u.data[i] = swab32(image->u.data[i]);
++ }
++ image->magic = swab32(image->magic);
++ }
++
++ ret = store_npe_image(image, dev);
++out:
++ if (ret) {
++ printk(KERN_ERR "Error downloading Firmware for %s\n",
++ npe->plat->name);
++ }
++ release_firmware(fw_entry);
++#endif
++}
++
++static void disable_npe_irq(struct npe_info *npe)
++{
++ u32 reg;
++ reg = npe_reg_read(npe, IX_NPEDL_REG_OFFSET_CTL);
++ reg &= ~(IX_NPEMH_NPE_CTL_OFE | IX_NPEMH_NPE_CTL_IFE);
++ reg |= IX_NPEMH_NPE_CTL_OFEWE | IX_NPEMH_NPE_CTL_IFEWE;
++}
++
++static ssize_t show_npe_state(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct npe_info *npe = dev_get_drvdata(dev);
++
++ strcpy(buf, npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN ?
++ "start\n" : "stop\n");
++ return strlen(buf);
++}
++
++static ssize_t set_npe_state(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct npe_info *npe = dev_get_drvdata(dev);
++
++ if (!strncmp(buf, "start", 5)) {
++ printk("NPE start\n");
++ npe_start(npe);
++ }
++ if (!strncmp(buf, "stop", 4)) {
++ printk("NPE stop\n");
++ npe_stop(npe);
++ }
++ return count;
++}
++
++static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_npe_state, set_npe_state);
++
++static int npe_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ struct npe_info *npe;
++ struct npe_plat_data *plat = pdev->dev.platform_data;
++ int size, ret=0;
++
++ if (!(res = platform_get_resource(pdev, IORESOURCE_MEM, 0)))
++ return -EIO;
++
++ if (!(npe = kzalloc(sizeof(struct npe_info), GFP_KERNEL)))
++ return -ENOMEM;
++
++ size = res->end - res->start +1;
++ npe->res = request_mem_region(res->start, size, plat->name);
++ if (!npe->res) {
++ ret = -EBUSY;
++ printk(KERN_ERR "Failed to get memregion(%x, %x)\n",
++ res->start, size);
++ goto out_free;
++ }
++
++ npe->addr = ioremap(res->start, size);
++ if (!npe->addr) {
++ ret = -ENOMEM;
++ printk(KERN_ERR "Failed to ioremap(%x, %x)\n",
++ res->start, size);
++ goto out_rel;
++ }
++
++ pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
++
++ platform_set_drvdata(pdev, npe);
++
++ device_create_file(&pdev->dev, &dev_attr_state);
++
++ npe->plat = plat;
++ disable_npe_irq(npe);
++ if (! (npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN))
++ npe_firmware_probe(&pdev->dev);
++
++ return 0;
++
++out_rel:
++ release_resource(npe->res);
++out_free:
++ kfree(npe);
++ return ret;
++}
++
++static struct file_operations ucode_dl_fops = {
++ .owner = THIS_MODULE,
++ .write = ucode_write,
++ .open = ucode_open,
++ .release = ucode_close,
++};
++
++static struct miscdevice ucode_dl_dev = {
++ .minor = MICROCODE_MINOR,
++ .name = "ixp4xx_ucode",
++ .fops = &ucode_dl_fops,
++};
++
++static int npe_remove(struct platform_device *pdev)
++{
++ struct npe_info *npe = platform_get_drvdata(pdev);
++
++ device_remove_file(&pdev->dev, &dev_attr_state);
++
++ iounmap(npe->addr);
++ release_resource(npe->res);
++ kfree(npe);
++ return 0;
++}
++
++static struct platform_driver ixp4xx_npe_driver = {
++ .driver = {
++ .name = "ixp4xx_npe",
++ .owner = THIS_MODULE,
++ },
++ .probe = npe_probe,
++ .remove = npe_remove,
++};
++
++static int __init init_npedriver(void)
++{
++ int ret;
++ if ((ret = misc_register(&ucode_dl_dev))){
++ printk(KERN_ERR "Failed to register misc device %d\n",
++ MICROCODE_MINOR);
++ return ret;
++ }
++ if ((ret = platform_driver_register(&ixp4xx_npe_driver)))
++ misc_deregister(&ucode_dl_dev);
++ else
++ printk(KERN_INFO IXNPE_VERSION " initialized\n");
++
++ return ret;
++
++}
++
++static void __exit finish_npedriver(void)
++{
++ misc_deregister(&ucode_dl_dev);
++ platform_driver_unregister(&ixp4xx_npe_driver);
++}
++
++module_init(init_npedriver);
++module_exit(finish_npedriver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt at innominate.com>");
++
++EXPORT_SYMBOL(get_npe_by_id);
+Index: linux-2.6.18/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
+===================================================================
+--- linux-2.6.18.orig/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h 2006-09-19 20:42:06.000000000 -0700
++++ linux-2.6.18/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h 2006-10-17 05:26:01.000000000 -0700
+@@ -22,6 +22,8 @@
+ #ifndef _ASM_ARM_IXP4XX_H_
+ #define _ASM_ARM_IXP4XX_H_
+
++#include "npe_regs.h"
++
+ /*
+ * IXP4xx Linux Memory Map:
+ *
+Index: linux-2.6.18/include/asm-arm/arch-ixp4xx/npe_regs.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/include/asm-arm/arch-ixp4xx/npe_regs.h 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,82 @@
++#ifndef NPE_REGS_H
++#define NPE_REGS_H
++
++/* Execution Address */
++#define IX_NPEDL_REG_OFFSET_EXAD 0x00
++/* Execution Data */
++#define IX_NPEDL_REG_OFFSET_EXDATA 0x04
++/* Execution Control */
++#define IX_NPEDL_REG_OFFSET_EXCTL 0x08
++/* Execution Count */
++#define IX_NPEDL_REG_OFFSET_EXCT 0x0C
++/* Action Point 0 */
++#define IX_NPEDL_REG_OFFSET_AP0 0x10
++/* Action Point 1 */
++#define IX_NPEDL_REG_OFFSET_AP1 0x14
++/* Action Point 2 */
++#define IX_NPEDL_REG_OFFSET_AP2 0x18
++/* Action Point 3 */
++#define IX_NPEDL_REG_OFFSET_AP3 0x1C
++/* Watchpoint FIFO */
++#define IX_NPEDL_REG_OFFSET_WFIFO 0x20
++/* Watch Count */
++#define IX_NPEDL_REG_OFFSET_WC 0x24
++/* Profile Count */
++#define IX_NPEDL_REG_OFFSET_PROFCT 0x28
++
++/* Messaging Status */
++#define IX_NPEDL_REG_OFFSET_STAT 0x2C
++/* Messaging Control */
++#define IX_NPEDL_REG_OFFSET_CTL 0x30
++/* Mailbox Status */
++#define IX_NPEDL_REG_OFFSET_MBST 0x34
++/* messaging in/out FIFO */
++#define IX_NPEDL_REG_OFFSET_FIFO 0x38
++
++
++#define IX_NPEDL_MASK_ECS_DBG_REG_2_IF 0x00100000
++#define IX_NPEDL_MASK_ECS_DBG_REG_2_IE 0x00080000
++#define IX_NPEDL_MASK_ECS_REG_0_ACTIVE 0x80000000
++
++#define IX_NPEDL_EXCTL_CMD_NPE_STEP 0x01
++#define IX_NPEDL_EXCTL_CMD_NPE_START 0x02
++#define IX_NPEDL_EXCTL_CMD_NPE_STOP 0x03
++#define IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE 0x04
++#define IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT 0x0C
++#define IX_NPEDL_EXCTL_CMD_RD_INS_MEM 0x10
++#define IX_NPEDL_EXCTL_CMD_WR_INS_MEM 0x11
++#define IX_NPEDL_EXCTL_CMD_RD_DATA_MEM 0x12
++#define IX_NPEDL_EXCTL_CMD_WR_DATA_MEM 0x13
++#define IX_NPEDL_EXCTL_CMD_RD_ECS_REG 0x14
++#define IX_NPEDL_EXCTL_CMD_WR_ECS_REG 0x15
++
++#define IX_NPEDL_EXCTL_STATUS_RUN 0x80000000
++#define IX_NPEDL_EXCTL_STATUS_STOP 0x40000000
++#define IX_NPEDL_EXCTL_STATUS_CLEAR 0x20000000
++
++#define IX_NPEDL_MASK_WFIFO_VALID 0x80000000
++#define IX_NPEDL_MASK_STAT_OFNE 0x00010000
++#define IX_NPEDL_MASK_STAT_IFNE 0x00080000
++
++#define IX_NPEDL_ECS_DBG_CTXT_REG_0 0x0C
++#define IX_NPEDL_ECS_PRI_1_CTXT_REG_0 0x04
++#define IX_NPEDL_ECS_PRI_2_CTXT_REG_0 0x08
++
++/* NPE control register bit definitions */
++#define IX_NPEMH_NPE_CTL_OFE (1 << 16) /**< OutFifoEnable */
++#define IX_NPEMH_NPE_CTL_IFE (1 << 17) /**< InFifoEnable */
++#define IX_NPEMH_NPE_CTL_OFEWE (1 << 24) /**< OutFifoEnableWriteEnable */
++#define IX_NPEMH_NPE_CTL_IFEWE (1 << 25) /**< InFifoEnableWriteEnable */
++
++/* NPE status register bit definitions */
++#define IX_NPEMH_NPE_STAT_OFNE (1 << 16) /**< OutFifoNotEmpty */
++#define IX_NPEMH_NPE_STAT_IFNF (1 << 17) /**< InFifoNotFull */
++#define IX_NPEMH_NPE_STAT_OFNF (1 << 18) /**< OutFifoNotFull */
++#define IX_NPEMH_NPE_STAT_IFNE (1 << 19) /**< InFifoNotEmpty */
++#define IX_NPEMH_NPE_STAT_MBINT (1 << 20) /**< Mailbox interrupt */
++#define IX_NPEMH_NPE_STAT_IFINT (1 << 21) /**< InFifo interrupt */
++#define IX_NPEMH_NPE_STAT_OFINT (1 << 22) /**< OutFifo interrupt */
++#define IX_NPEMH_NPE_STAT_WFINT (1 << 23) /**< WatchFifo interrupt */
++
++#endif
++
+Index: linux-2.6.18/include/asm-arm/arch-ixp4xx/platform.h
+===================================================================
+--- linux-2.6.18.orig/include/asm-arm/arch-ixp4xx/platform.h 2006-10-17 05:26:00.000000000 -0700
++++ linux-2.6.18/include/asm-arm/arch-ixp4xx/platform.h 2006-10-17 05:40:03.000000000 -0700
+@@ -86,6 +86,22 @@
+ unsigned long scl_pin;
+ };
+
++struct npe_plat_data {
++ const char *name;
++ int data_size;
++ int inst_size;
++ int id; /* Node ID */
++};
++
++struct mac_plat_info {
++ int npe_id; /* Node ID of the NPE for this port */
++ int port_id; /* Port ID for NPE-B @ ixp465 */
++ int eth_id; /* Physical ID */
++ int phy_id; /* ID of the connected PHY (PCB/platform dependent) */
++ int rxq_id; /* Queue ID of the RX-free q*/
++ int txq_id; /* Where to push the outgoing packets */
++};
++
+
+ struct sys_timer;
+
+Index: linux-2.6.18/include/linux/ixp_npe.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/include/linux/ixp_npe.h 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#ifndef NPE_DEVICE_H
++#define NPE_DEVICE_H
++
++#include <linux/miscdevice.h>
++#include <asm/hardware.h>
++
++struct npe_info {
++ struct resource *res;
++ void __iomem *addr;
++ struct npe_plat_data *plat;
++ u8 img_info[4];
++ u32 exec_count;
++ u32 ctx_reg2;
++};
++
++
++static inline void npe_reg_write(struct npe_info *npe, u32 reg, u32 val)
++{
++ *(volatile u32*)((u8*)(npe->addr) + reg) = val;
++}
++
++static inline u32 npe_reg_read(struct npe_info *npe, u32 reg)
++{
++ return *(volatile u32*)((u8*)(npe->addr) + reg);
++}
++
++static inline u32 npe_status(struct npe_info *npe)
++{
++ return npe_reg_read(npe, IX_NPEDL_REG_OFFSET_EXCTL);
++}
++
++/* ixNpeDlNpeMgrCommandIssue */
++static inline void npe_write_exctl(struct npe_info *npe, u32 cmd)
++{
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
++}
++/* ixNpeDlNpeMgrWriteCommandIssue */
++static inline void
++npe_write_cmd(struct npe_info *npe, u32 addr, u32 data, int cmd)
++{
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_EXDATA, data);
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_EXAD, addr);
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
++}
++/* ixNpeDlNpeMgrReadCommandIssue */
++static inline u32
++npe_read_cmd(struct npe_info *npe, u32 addr, int cmd)
++{
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_EXAD, addr);
++ npe_reg_write(npe, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
++ /* Intel reads the data twice - so do we... */
++ npe_reg_read(npe, IX_NPEDL_REG_OFFSET_EXDATA);
++ return npe_reg_read(npe, IX_NPEDL_REG_OFFSET_EXDATA);
++}
++
++/* ixNpeDlNpeMgrExecAccRegWrite */
++static inline void npe_write_ecs_reg(struct npe_info *npe, u32 addr, u32 data)
++{
++ npe_write_cmd(npe, addr, data, IX_NPEDL_EXCTL_CMD_WR_ECS_REG);
++}
++/* ixNpeDlNpeMgrExecAccRegRead */
++static inline u32 npe_read_ecs_reg(struct npe_info *npe, u32 addr)
++{
++ return npe_read_cmd(npe, addr, IX_NPEDL_EXCTL_CMD_RD_ECS_REG);
++}
++
++extern struct device *get_npe_by_id(int id);
++
++/* NPE Messages */
++extern int
++npe_mh_setportaddr(struct npe_info *npe, struct mac_plat_info *mp, u8 *macaddr);
++extern int
++npe_mh_disable_firewall(struct npe_info *npe, struct mac_plat_info *mp);
++extern int
++npe_mh_set_rxqid(struct npe_info *npe, struct mac_plat_info *mp, int qid);
++extern int
++npe_mh_npe_loopback_mode(struct npe_info *npe, struct mac_plat_info *mp, int enable);
++
++#endif
+Index: linux-2.6.18/include/linux/ixp_qmgr.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/include/linux/ixp_qmgr.h 2006-10-17 05:26:01.000000000 -0700
+@@ -0,0 +1,188 @@
++/*
++ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt at innominate.com>
++ *
++ * This file is released under the GPLv2
++ */
++
++#ifndef IX_QMGR_H
++#define IX_QMGR_H
++
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <linux/if_ether.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <asm/atomic.h>
++
++/* All offsets are in 32bit words */
++#define QUE_LOW_STAT0 0x100 /* 4x Status of the 32 lower queues 0-31 */
++#define QUE_UO_STAT0 0x104 /* 2x Underflow/Overflow status bits*/
++#define QUE_UPP_STAT0 0x106 /* 2x Status of thew 32 upper queues 32-63 */
++#define INT0_SRC_SELREG0 0x108 /* 4x */
++#define QUE_IE_REG0 0x10c /* 2x */
++#define QUE_INT_REG0 0x10e /* 2x IRQ reg, write 1 to reset IRQ */
++
++#define IX_QMGR_QCFG_BASE 0x800
++#define IX_QMGR_QCFG_SIZE 0x40
++#define IX_QMGR_SRAM_SPACE (IX_QMGR_QCFG_BASE + IX_QMGR_QCFG_SIZE)
++
++#define MAX_QUEUES 32 /* first, we only support the lower 32 queues */
++#define MAX_NPES 3
++
++enum {
++ Q_IRQ_ID_E = 0, /* Queue Empty due to last read */
++ Q_IRQ_ID_NE, /* Queue Nearly Empty due to last read */
++ Q_IRQ_ID_NF, /* Queue Nearly Full due to last write */
++ Q_IRQ_ID_F, /* Queue Full due to last write */
++ Q_IRQ_ID_NOT_E, /* Queue Not Empty due to last write */
++ Q_IRQ_ID_NOT_NE, /* Queue Not Nearly Empty due to last write */
++ Q_IRQ_ID_NOT_NF, /* Queue Not Nearly Full due to last read */
++ Q_IRQ_ID_NOT_F /* Queue Not Full due to last read */
++};
++
++extern struct qm_queue *request_queue(int qid, int len);
++extern void release_queue(struct qm_queue *queue);
++extern int queue_set_irq_src(struct qm_queue *queue, int flag);
++extern void queue_set_watermarks(struct qm_queue *, unsigned ne, unsigned nf);
++extern int queue_len(struct qm_queue *queue);
++
++struct qm_qmgr;
++struct qm_queue;
++
++typedef void(*queue_cb)(struct qm_queue *);
++
++struct qm_queue {
++ int addr; /* word offset from IX_QMGR_SRAM_SPACE */
++ int len; /* size in words */
++ int id; /* Q Id */
++ u32 __iomem *acc_reg;
++ struct device *dev;
++ atomic_t use;
++ queue_cb irq_cb;
++ void *cb_data;
++};
++
++struct eth_ctl {
++ u32 next;
++#ifdef __ARMEB__
++ u16 buf_len;
++ u16 pkt_len;
++#else
++ u16 pkt_len;
++ u16 buf_len;
++#endif
++ u32 phys_addr;
++ u8 dest_id;
++ u8 src_id;
++ u16 flags;
++ u8 qos;
++ u8 padlen;
++ u16 vlan_tci;
++ u8 dest_mac[ETH_ALEN];
++ u8 src_mac[ETH_ALEN];
++};
++
++struct npe_cont {
++ union {
++ struct eth_ctl eth;
++ } ctl;
++ union {
++ struct sk_buff *skb;
++ void *ptr;
++ } h;
++ struct npe_cont *next;
++ struct npe_cont *virt;
++ dma_addr_t phys;
++};
++
++struct qm_qmgr {
++ u32 __iomem *addr;
++ struct resource *res;
++ struct qm_queue *queues[MAX_QUEUES];
++ rwlock_t lock;
++ struct npe_cont *pool;
++ struct dma_pool *dmapool;
++ int irq;
++};
++
++static inline void queue_write_cfg_reg(struct qm_queue *queue, u32 val)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ *(qmgr->addr + IX_QMGR_QCFG_BASE + queue->id) = val;
++}
++static inline u32 queue_read_cfg_reg(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ return *(qmgr->addr + IX_QMGR_QCFG_BASE + queue->id);
++}
++
++static inline void queue_ack_irq(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ *(qmgr->addr + QUE_INT_REG0) = 1 << queue->id;
++}
++
++static inline void queue_enable_irq(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ *(qmgr->addr + QUE_IE_REG0) |= 1 << queue->id;
++}
++
++static inline void queue_disable_irq(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ *(qmgr->addr + QUE_IE_REG0) &= ~(1 << queue->id);
++}
++
++static inline void queue_put_entry(struct qm_queue *queue, u32 entry)
++{
++ *(queue->acc_reg) = entry;
++}
++
++static inline struct npe_cont *qmgr_get_cont(struct qm_qmgr *qmgr)
++{
++ unsigned long flags;
++ struct npe_cont *cont;
++
++ if (!qmgr->pool)
++ return NULL;
++ write_lock_irqsave(&qmgr->lock, flags);
++ cont = qmgr->pool;
++ qmgr->pool = cont->next;
++ write_unlock_irqrestore(&qmgr->lock, flags);
++ return cont;
++}
++
++static inline void qmgr_return_cont(struct qm_qmgr *qmgr,struct npe_cont *cont)
++{
++ unsigned long flags;
++
++ write_lock_irqsave(&qmgr->lock, flags);
++ cont->next = qmgr->pool;
++ qmgr->pool = cont;
++ write_unlock_irqrestore(&qmgr->lock, flags);
++}
++
++static inline int queue_stat(struct qm_queue *queue)
++{
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++ u32 reg = *(qmgr->addr + QUE_UO_STAT0 + (queue->id >> 4));
++ return (reg >> (queue->id & 0xf) << 1) & 3;
++}
++
++/* Prints the queue state, which is very, very helpfull for debugging */
++static inline void queue_state(struct qm_queue *queue)
++{
++ u32 val=0, lstat=0;
++ int offs;
++ struct qm_qmgr *qmgr = dev_get_drvdata(queue->dev);
++
++ offs = queue->id/8 + QUE_LOW_STAT0;
++ val = *(qmgr->addr + IX_QMGR_QCFG_BASE + queue->id);
++ lstat = (*(qmgr->addr + offs) >> ((queue->id % 8)*4)) & 0x0f;
++
++ printk("Qid[%02d]: Wptr=%4x, Rptr=%4x, diff=%4x, Stat:%x\n", queue->id,
++ val&0x7f, (val>>7) &0x7f, (val - (val >> 7)) & 0x7f, lstat);
++}
++
++#endif
Added: people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-net-driver-fix-qmgr.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-net-driver-fix-qmgr.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,36 @@
+
+---
+ drivers/net/ixp4xx/ixp4xx_qmgr.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- linux-ixp4xx.orig/drivers/net/ixp4xx/ixp4xx_qmgr.c 2006-10-15 18:52:35.000000000 +0200
++++ linux-ixp4xx/drivers/net/ixp4xx/ixp4xx_qmgr.c 2006-10-15 18:54:32.000000000 +0200
+@@ -107,7 +107,7 @@ static int get_free_qspace(struct qm_qmg
+ return -1;
+ }
+
+-static inline int log2(int x)
++static inline int _log2(int x)
+ {
+ int r=0;
+ while(x>>=1)
+@@ -127,7 +127,7 @@ static inline int log2(int x)
+ */
+ static int conf_q_regs(struct qm_queue *queue)
+ {
+- int bsize = log2(queue->len/16);
++ int bsize = _log2(queue->len/16);
+ int baddr = queue->addr + IX_QMGR_QCFG_SIZE;
+
+ /* +2, because baddr is in words and not in bytes */
+@@ -141,8 +141,8 @@ void queue_set_watermarks(struct qm_queu
+ u32 val;
+ /* calculate the register values
+ * 0->0, 1->1, 2->2, 4->3, 8->4 16->5...*/
+- ne = log2(ne<<1) & 0x7;
+- nf = log2(nf<<1) & 0x7;
++ ne = _log2(ne<<1) & 0x7;
++ nf = _log2(nf<<1) & 0x7;
+
+ /* Mask out old watermarks */
+ val = queue_read_cfg_reg(queue) & ~0xfc000000;
Added: people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-net-driver-improve-mac-handling.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/arm/ixp4xx-net-driver-improve-mac-handling.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,57 @@
+Index: linux-2.6.18/include/asm-arm/arch-ixp4xx/platform.h
+===================================================================
+--- linux-2.6.18.orig/include/asm-arm/arch-ixp4xx/platform.h 2006-10-25 04:42:17.000000000 -0700
++++ linux-2.6.18/include/asm-arm/arch-ixp4xx/platform.h 2006-10-25 04:42:17.000000000 -0700
+@@ -100,6 +100,7 @@
+ int phy_id; /* ID of the connected PHY (PCB/platform dependent) */
+ int rxq_id; /* Queue ID of the RX-free q*/
+ int txq_id; /* Where to push the outgoing packets */
++ unsigned char hwaddr[6]; /* Desired hardware address */
+ };
+
+
+Index: linux-2.6.18/drivers/net/ixp4xx/mac_driver.c
+===================================================================
+--- linux-2.6.18.orig/drivers/net/ixp4xx/mac_driver.c 2006-10-25 04:42:17.000000000 -0700
++++ linux-2.6.18/drivers/net/ixp4xx/mac_driver.c 2006-10-25 04:42:17.000000000 -0700
+@@ -189,6 +189,21 @@
+ }
+ mac->rxq_pkt += RX_QUEUE_PREFILL;
+
++ /* printk(KERN_INFO "...Platform MAC=0x%02x%02x%02x%02x%02x%02x\n",
++ mac->plat->hwaddr[0],
++ mac->plat->hwaddr[1],
++ mac->plat->hwaddr[2],
++ mac->plat->hwaddr[3],
++ mac->plat->hwaddr[4],
++ mac->plat->hwaddr[5]
++ ); */
++ if (is_zero_ether_addr(mac->plat->hwaddr)) {
++ random_ether_addr(dev->dev_addr);
++ dev->dev_addr[5] = mac->plat->phy_id;
++ }
++ else
++ memcpy(dev->dev_addr, mac->plat->hwaddr, 6);
++
+ mac_init(mac);
+ npe_mh_set_rxqid(npe, mac->plat, RX_DONE_QID);
+ mac_set_uniaddr(dev);
+@@ -434,9 +449,15 @@
+ * following commands:
+ * "ip link set address 02:03:04:04:04:01 dev eth0"
+ * "ifconfig eth0 hw ether 02:03:04:04:04:07"
+- */
+- random_ether_addr(dev->dev_addr);
+- dev->dev_addr[5] = plat->phy_id;
++ */
++/* Note: moved to ixmac_open to allow notifiers to run for compiled in modules
++ if (is_zero_ether_addr(plat->hwaddr)) {
++ random_ether_addr(dev->dev_addr);
++ dev->dev_addr[5] = plat->phy_id;
++ }
++ else
++ memcpy(dev->dev_addr, plat->hwaddr, 6);
++*/
+
+ printk(KERN_INFO IXMAC_NAME " driver " IXMAC_VERSION
+ ": %s on %s with PHY[%d] initialized\n",
Added: people/maks-guest/linux-2.6/debian/patches/features/arm/nslu2-eth-mac.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/arm/nslu2-eth-mac.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,57 @@
+--- a/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-10-31 15:39:50.000000000 +0100
++++ b/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-10-31 15:43:35.000000000 +0100
+@@ -17,6 +17,7 @@
+ #include <linux/kernel.h>
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
++#include <linux/mtd/mtd.h>
+ #include <linux/leds.h>
+
+ #include <asm/mach-types.h>
+@@ -180,10 +181,46 @@
+ gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
+ }
+
++/*
++ * When the RedBoot partition is added the MAC address is read from
++ * it.
++ */
++static void nslu2_flash_add(struct mtd_info *mtd) {
++ if (strcmp(mtd->name, "RedBoot") == 0) {
++ size_t retlen;
++ u_char mac[6];
++
++ /* The MAC is at a known offset... */
++ if (mtd->read(mtd, 0x3FFB0, 6, &retlen, mac) == 0 && retlen == 6) {
++ printk(KERN_INFO "NSLU2 MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ memcpy(&plat_mac0.hwaddr, mac, 6);
++ } else {
++ printk(KERN_ERR "NSLU2 MAC: read failed\n");
++ }
++ }
++}
++
++/*
++ * Nothing to do on remove at present.
++ */
++static void nslu2_flash_remove(struct mtd_info *mtd) {
++}
++
++static struct mtd_notifier nslu2_flash_notifier = {
++ .add = nslu2_flash_add,
++ .remove = nslu2_flash_remove,
++};
++
+ static void __init nslu2_init(void)
+ {
+ ixp4xx_timer_freq = NSLU2_FREQ;
+
++ /* The flash has an ethernet MAC embedded in it which we need,
++ * that is all this notifier does.
++ */
++ register_mtd_user(&nslu2_flash_notifier);
++
+ ixp4xx_sys_init();
+
+ nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
Added: people/maks-guest/linux-2.6/debian/patches/features/arm/nslu2-setup-mac.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/arm/nslu2-setup-mac.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,41 @@
+Index: linux-2.6.18/arch/arm/mach-ixp4xx/nslu2-setup.c
+===================================================================
+--- linux-2.6.18.orig/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-10-01 23:12:35.000000000 +0200
++++ linux-2.6.18/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-10-01 23:12:40.000000000 +0200
+@@ -139,6 +139,28 @@
+ .resource = nslu2_uart_resources,
+ };
+
++static struct resource res_mac0 = {
++ .start = IXP4XX_EthB_BASE_PHYS,
++ .end = IXP4XX_EthB_BASE_PHYS + 0x1ff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct mac_plat_info plat_mac0 = {
++ .npe_id = 1,
++ .phy_id = 1,
++ .eth_id = 0,
++ .rxq_id = 27,
++ .txq_id = 24,
++};
++
++static struct platform_device mac0 = {
++ .name = "ixp4xx_mac",
++ .id = 0,
++ .dev.platform_data = &plat_mac0,
++ .num_resources = 1,
++ .resource = &res_mac0,
++};
++
+ static struct platform_device *nslu2_devices[] __initdata = {
+ &nslu2_i2c_controller,
+ &nslu2_flash,
+@@ -146,6 +168,7 @@
+ #ifdef CONFIG_LEDS_IXP4XX
+ &nslu2_leds,
+ #endif
++ &mac0
+ };
+
+ static void nslu2_power_off(void)
Added: people/maks-guest/linux-2.6/debian/patches/features/fintek-f75375.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/fintek-f75375.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,671 @@
+diff -urpN linux-2.6.17/drivers/hwmon/f75375s.c linux-2.6.18-rc6/drivers/hwmon/f75375s.c
+--- linux-2.6.17/drivers/hwmon/f75375s.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.18-rc6/drivers/hwmon/f75375s.c 2006-10-31 21:54:04.000000000 +0200
+@@ -0,0 +1,636 @@
++/*
++ * f75375.c - driver for the Fintek F75375/SP and F75373
++ * hardware monitoring features
++ *
++ * Copyright (C) 2005 Riku Voipio <riku.voipio at movial.fi>
++ *
++ * The F75375/SP is a I2C chip made by Fintek. It integrates
++ * complete hardware monitoring features: voltage, fan and temperature
++ * sensors, and manual and automatic fan speed control.
++ *
++ * Datasheets at:
++ *
++ * http://www.fintek.com.tw/eng/products.asp?BID=4&SID=5
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/jiffies.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/i2c.h>
++#include <linux/err.h>
++#include <linux/mutex.h>
++#include <asm/io.h>
++
++/* Addresses to scan */
++static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
++
++/* Insmod parameters */
++I2C_CLIENT_INSMOD_1(f75375);
++
++/* Fintek F75375 registers */
++#define F75375_REG_CONFIG0 0x0 /* |start|x|x|x|x|x|soft_pwdn|init| */
++#define F75375_REG_CONFIG1 0x1 /* |pin2_mode|pin4_mode|t1_mode|t2_mode|fan1_linear_mode|fan2_linear_mode|x|x| */
++#define F75375_REG_CONFIG2 0x2
++#define F75375_REG_CONFIG3 0x3
++#define F75375_REG_ADDR 0x4
++#define F75375_REG_INTR 0x31 /* fault registers upto 38 */
++#define F75375_CHIP_ID 0x5A
++#define F75375_REG_VERSION 0x5C
++#define F75375_REG_VENDOR 0x5D
++#define F75375_REG_FAN_TIMER 0x60 /* 6-7 fan2 speed/temp/man|4-5 fan3 */
++
++#define F75375_REG_VOLT(nr) (0x10 + (nr))
++#define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2 )
++#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2 )
++
++#define F75375_REG_TEMP(nr) (0x14 + (nr))
++#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2 )
++#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2 )
++
++#define F75375_REG_FAN(nr) (0x16 + (nr) * 2 )
++#define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2 )
++#define F75375_REG_FAN_MAX(nr) (0x70 + (nr) * 0x10 )
++ /*72 - 75 expect count */
++#define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10 )
++#define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10 )
++
++#define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10 )
++#define F75375_REG_FAN_B_TEMP(nr,step) ((0xA0 + (nr) * 0x10) + (step)) /* 1..4 */
++#define F75375_REG_FAN_B_SPEED(nr,step) ((0xA5 + (nr) * 0x10) + (step) * 2 )
++
++#define F75375_REG_PWM1_RAISE_DUTY 0x69
++#define F75375_REG_PWM2_RAISE_DUTY 0x6A
++#define F75375_REG_PWM1_DROP_DUTY 0x6B
++#define F75375_REG_PWM2_DROP_DUTY 0x6C
++
++#define F75375_FAN1_LINEAR_MODE 0x10
++#define F75375_FAN2_LINEAR_MODE 0x20
++
++#define F75375_FAN1_MANUAL_MODE 0x30
++#define F75375_FAN2_MANUAL_MODE 0xc0
++
++#define F75375_PWM_DEFAULT 0xFF
++
++/*
++ * Data structures and manipulation thereof
++ */
++
++struct f75375_data {
++ unsigned short addr;
++ struct i2c_client client;
++ struct class_device *class_dev;
++
++ const char *name;
++ struct mutex update_lock;
++ char valid;
++ unsigned long last_updated; /* In jiffies */
++ unsigned long last_limits; /* In jiffies */
++
++ /* Register values */
++ u8 in[4];
++ u8 in_max[4];
++ u8 in_min[4];
++ u16 fan[2];
++ u16 fan_min[2];
++ u16 fan_max[2];
++ u16 fan_exp[2];
++ u8 fan_timer;
++ u8 pwm[2];
++ u8 temp[2];
++ u8 temp_high[2];
++ u8 temp_max_hyst[2];
++ u8 alarms[3];
++ u8 fan_enabled; /* Read once at init time */
++};
++
++static int f75375_attach_adapter(struct i2c_adapter *adapter);
++static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
++static void f75375_init_client(struct i2c_client *client);
++static int f75375_detach_client(struct i2c_client *client);
++static inline int f75375_read_value(struct i2c_client *client, u8 reg);
++static inline int f75375_write_value(struct i2c_client *client, u8 reg,
++ u8 value);
++static struct f75375_data *f75375_update_device(struct device *dev);
++
++static struct i2c_driver f75375_driver = {
++ .driver = {
++ .name = "f75375",
++ },
++ .attach_adapter = f75375_attach_adapter,
++ .detach_client = f75375_detach_client,
++};
++
++static inline int f75375_read_value(struct i2c_client *client, u8 reg)
++{
++ return i2c_smbus_read_byte_data(client, reg);
++}
++static inline u16 f75375_read_value16(struct i2c_client *client, u8 reg)
++{
++ return ((i2c_smbus_read_byte_data(client, reg) << 8)
++ | i2c_smbus_read_byte_data(client, reg + 1));
++}
++
++static inline int f75375_write_value(struct i2c_client *client, u8 reg,
++ u8 value)
++{
++ return i2c_smbus_write_byte_data(client, reg, value);
++}
++static inline int f75375_write_value16(struct i2c_client *client, u8 reg,
++ u16 value)
++{
++ int err = i2c_smbus_write_byte_data(client, reg, (value << 8));
++ if (err)
++ return err;
++ return i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
++}
++static struct f75375_data *f75375_update_device(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int nr;
++
++ mutex_lock(&data->update_lock);
++
++ /* Limit registers cache is refreshed after 60 seconds */
++ if (time_after(jiffies, data->last_updated + 60 * HZ)
++ || !data->valid) {
++ for (nr = 0; nr < 2; nr++) {
++ data->temp_high[nr] = f75375_read_value(client,
++ F75375_REG_TEMP_HIGH
++ (nr));
++ data->temp_max_hyst[nr] =
++ f75375_read_value(client, F75375_REG_TEMP_HYST(nr));
++ data->fan_max[nr] =
++ f75375_read_value16(client, F75375_REG_FAN_MAX(nr));
++ data->fan_exp[nr] =
++ f75375_read_value16(client, F75375_REG_FAN_EXP(nr));
++
++ }
++ for (nr = 0; nr < 4; nr++) {
++ data->in_max[nr] = f75375_read_value(client,
++ F75375_REG_VOLT_HIGH
++ (nr));
++ data->in_min[nr] =
++ f75375_read_value(client, F75375_REG_VOLT_LOW(nr));
++ }
++ data->fan_timer = f75375_read_value(client,
++ F75375_REG_FAN_TIMER);
++ data->last_limits = jiffies;
++ }
++
++ /* Measurement registers cache is refreshed after 2 second */
++ if (time_after(jiffies, data->last_updated + 2 * HZ)
++ || !data->valid) {
++ for (nr = 0; nr < 2; nr++) {
++ data->temp[nr] = f75375_read_value(client,
++ F75375_REG_TEMP(nr));
++ data->fan[nr] = f75375_read_value16(client,
++ F75375_REG_FAN(nr));
++ }
++ for (nr = 0; nr < 4; nr++) {
++ data->in[nr] = f75375_read_value(client,
++ F75375_REG_VOLT(nr));
++ }
++ /*for (nr = 0; nr < 3; nr++) {
++ data->alarms[nr] = f75375_read8(data,
++ F71805F_REG_STATUS(nr));
++ } */
++
++ data->last_updated = jiffies;
++ data->valid = 1;
++ }
++
++ mutex_unlock(&data->update_lock);
++ return data;
++}
++
++#define show(thing) \
++static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
++ char *buf)\
++{\
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);\
++ int nr = sensor_attr->index;\
++ struct f75375_data *data = f75375_update_device(dev); \
++ return sprintf(buf, "%d\n", data->thing[nr]); \
++}
++
++static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ data->fan_min[nr] = val;
++ f75375_write_value16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ data->fan_exp[nr] = val;
++ f75375_write_value16(client, F75375_REG_FAN_MIN(nr),
++ data->fan_exp[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++show(fan);
++show(fan_min);
++show(fan_max);
++show(fan_exp);
++
++#define show_fan_offset(offset) \
++static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
++ show_fan, NULL, offset - 1);\
++static SENSOR_DEVICE_ATTR(fan##offset##_max, S_IRUGO, \
++ show_fan_max, NULL, offset - 1);\
++static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
++ show_fan_min, set_fan_min, offset - 1); \
++static SENSOR_DEVICE_ATTR(fan##offset##_exp, S_IRUGO | S_IWUSR, \
++ show_fan_exp, set_fan_exp, offset - 1); \
++
++show_fan_offset(1);
++show_fan_offset(2);
++
++show(pwm);
++
++static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ data->pwm[nr] = val;
++ f75375_write_value(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
++static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
++
++#define VOLT_FROM_REG(val) ((val)*8000)
++#define VOLT_TO_REG(val) ((val)/8000)
++
++static ssize_t show_in(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct f75375_data *data = f75375_update_device(dev);
++ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
++}
++
++static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct f75375_data *data = f75375_update_device(dev);
++ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
++}
++
++static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct f75375_data *data = f75375_update_device(dev);
++ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
++}
++
++static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++ mutex_lock(&data->update_lock);
++ data->in_max[nr] = VOLT_TO_REG(val);
++ f75375_write_value(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++ mutex_lock(&data->update_lock);
++ data->in_min[nr] = VOLT_TO_REG(val);
++ f75375_write_value(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++#define show_in_offset(offset) \
++static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
++ show_in, NULL, offset);\
++static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
++ show_in_max, set_in_max, offset);\
++static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
++ show_in_min, set_in_min, offset); \
++
++show_in_offset(0);
++show_in_offset(1);
++show_in_offset(2);
++show_in_offset(3);
++
++#define TEMP_FROM_REG(val) ((val)*1000)
++#define TEMP_TO_REG(val) ((val)/1000)
++
++static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct f75375_data *data = f75375_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
++}
++
++static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct f75375_data *data = f75375_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
++}
++
++static ssize_t show_temp_max_hyst(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct f75375_data *data = f75375_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
++}
++
++static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ data->temp_high[nr] = TEMP_TO_REG(val);
++ f75375_write_value(client, F75375_REG_TEMP_HIGH(nr),
++ data->temp_high[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++static ssize_t set_temp_max_hyst(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++
++ struct i2c_client *client = to_i2c_client(dev);
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int val = simple_strtol(buf, NULL, 10);
++
++ mutex_lock(&data->update_lock);
++ data->temp_max_hyst[nr] = TEMP_TO_REG(val);
++ f75375_write_value(client, F75375_REG_TEMP_HYST(nr),
++ data->temp_max_hyst[nr]);
++ mutex_unlock(&data->update_lock);
++ return count;
++}
++
++#define show_temp_offset(offset) \
++static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
++ show_temp, NULL, offset - 1); \
++static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
++ show_temp_max_hyst, set_temp_max_hyst, offset - 1); \
++static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
++ show_temp_max, set_temp_max, offset - 1);
++
++show_temp_offset(1);
++show_temp_offset(2);
++
++static void f75375_init_client(struct i2c_client *client)
++{
++ /* Start the fans in manual mode */
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int tmp = F75375_FAN1_LINEAR_MODE | F75375_FAN2_LINEAR_MODE;
++ mutex_lock(&data->update_lock);
++ f75375_write_value(client, F75375_REG_CONFIG1, tmp);
++ tmp = F75375_FAN1_MANUAL_MODE | F75375_FAN2_MANUAL_MODE;
++ f75375_write_value(client, F75375_REG_FAN_TIMER, tmp);
++ f75375_write_value(client, F75375_REG_FAN_PWM_DUTY(0),
++ F75375_PWM_DEFAULT);
++ f75375_write_value(client, F75375_REG_FAN_PWM_DUTY(1),
++ F75375_PWM_DEFAULT);
++ printk(KERN_INFO "f75375: fan timer after: %X \n", data->fan_timer);
++ mutex_unlock(&data->update_lock);
++}
++
++static int f75375_attach_adapter(struct i2c_adapter *adapter)
++{
++ printk(KERN_INFO "f75375: attaching\n");
++ return i2c_probe(adapter, &addr_data, f75375_detect);
++}
++
++static int f75375_detach_client(struct i2c_client *client)
++{
++ struct f75375_data *data = i2c_get_clientdata(client);
++ int err;
++
++ hwmon_device_unregister(data->class_dev);
++
++ err = i2c_detach_client(client);
++ if (err) {
++ dev_err(&client->dev,
++ "Client deregistration failed, "
++ "client not detached.\n");
++ return err;
++ }
++ kfree(data);
++ return 0;
++}
++
++/* This function is called by i2c_probe */
++static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
++{
++ struct i2c_client *new_client;
++ struct f75375_data *data;
++ int err = 0;
++ char *name = "";
++
++ if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++ new_client = &data->client;
++ i2c_set_clientdata(new_client, data);
++ new_client->addr = address;
++ new_client->adapter = adapter;
++ new_client->driver = &f75375_driver;
++ new_client->flags = 0;
++
++ if (kind < 0) {
++ u16 chipid =
++ (i2c_smbus_read_byte_data(new_client, F75375_CHIP_ID) << 8)
++ | i2c_smbus_read_byte_data(new_client, F75375_CHIP_ID + 1);
++ u8 version =
++ i2c_smbus_read_byte_data(new_client, F75375_REG_VERSION);
++ u16 vendid =
++ (i2c_smbus_read_byte_data(new_client, F75375_REG_VENDOR) <<
++ 8)
++ | i2c_smbus_read_byte_data(new_client,
++ F75375_REG_VENDOR + 1);
++ if (chipid == 0x0306 && vendid == 0x1934) {
++ pr_info("F75375: found F75375 version: %02X\n",
++ version);
++ name = "F75375";
++ } else if (chipid == 0x0204 && vendid == 0x1934) {
++ pr_info("F75375: found F75373 version: %02X\n",
++ version);
++ name = "F75373";
++ } else {
++ printk(KERN_INFO "f75375: failed,%02X,%02X,%02X\n",
++ chipid, version, vendid);
++ goto exit_free;
++ }
++ }
++ strlcpy(new_client->name, name, I2C_NAME_SIZE);
++ data->valid = 0;
++ mutex_init(&data->update_lock);
++ if ((err = i2c_attach_client(new_client)))
++ goto exit_free;
++
++ /* Initialize the chip */
++ f75375_init_client(new_client);
++
++ /* Register sysfs hooks */
++ data->class_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_detach;
++ }
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp1_input.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp1_max.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp1_max_hyst.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp2_input.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp2_max.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp2_max_hyst.dev_attr);
++
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_input.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_max.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_min.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan1_exp.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_input.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_max.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_min.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_fan2_exp.dev_attr);
++
++ device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
++
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_in0_input.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_in1_input.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_in2_input.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_in3_input.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
++ device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
++
++ return 0;
++
++ exit_detach:
++ i2c_detach_client(new_client);
++ exit_free:
++ kfree(data);
++ exit:
++ return err;
++}
++
++static int __init sensors_f75375_init(void)
++{
++ return i2c_add_driver(&f75375_driver);
++}
++
++static void __exit sensors_f75375_exit(void)
++{
++ i2c_del_driver(&f75375_driver);
++}
++
++MODULE_AUTHOR("Riku Voipio <riku.voipio at movial.fi>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver");
++
++module_init(sensors_f75375_init);
++module_exit(sensors_f75375_exit);
+diff -urpN linux-2.6.17/drivers/hwmon/Kconfig linux-2.6.18-rc6/drivers/hwmon/Kconfig
+--- linux-2.6.17/drivers/hwmon/Kconfig 2006-10-31 20:00:09.000000000 +0200
++++ linux-2.6.18-rc6/drivers/hwmon/Kconfig 2006-10-15 15:05:55.000000000 +0300
+@@ -139,6 +139,16 @@ config SENSORS_F71805F
+ This driver can also be built as a module. If so, the module
+ will be called f71805f.
+
++config SENSORS_F75375S
++ tristate "Fintek F75375S/SP and F75373"
++ depends on HWMON && I2C && EXPERIMENTAL
++ help
++ If you say yes here you get support for hardware monitoring
++ features of the Fintek F75375S/SP and F75373
++
++ This driver can also be built as a module. If so, the module
++ will be called f75375s.
++
+ config SENSORS_FSCHER
+ tristate "FSC Hermes"
+ depends on HWMON && I2C && EXPERIMENTAL
+diff -urpN linux-2.6.17/drivers/hwmon/Makefile linux-2.6.18-rc6/drivers/hwmon/Makefile
+--- linux-2.6.17/drivers/hwmon/Makefile 2006-10-31 20:00:09.000000000 +0200
++++ linux-2.6.18-rc6/drivers/hwmon/Makefile 2006-10-15 15:02:16.000000000 +0300
+@@ -21,6 +21,7 @@ obj-$(CONFIG_SENSORS_ADM9240) += adm9240
+ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
+ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
+ obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
++obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
+ obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
+ obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
+ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
Added: people/maks-guest/linux-2.6/debian/patches/features/mips/backtrace.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/mips/backtrace.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,401 @@
+# Kernel backtraces for mips/mipsel, from linux-mips.org 2.6.18-stable,
+# in kernel.org mainline.
+
+
+diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
+index 7ab67f7..951bf9c 100644
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -281,62 +281,63 @@ static struct mips_frame_info {
+ } *schedule_frame, mfinfo[64];
+ static int mfinfo_num;
+
+-static int __init get_frame_info(struct mips_frame_info *info)
++static inline int is_ra_save_ins(union mips_instruction *ip)
+ {
+- int i;
+- void *func = info->func;
+- union mips_instruction *ip = (union mips_instruction *)func;
++ /* sw / sd $ra, offset($sp) */
++ return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
++ ip->i_format.rs == 29 &&
++ ip->i_format.rt == 31;
++}
++
++static inline int is_jal_jalr_jr_ins(union mips_instruction *ip)
++{
++ if (ip->j_format.opcode == jal_op)
++ return 1;
++ if (ip->r_format.opcode != spec_op)
++ return 0;
++ return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
++}
++
++static inline int is_sp_move_ins(union mips_instruction *ip)
++{
++ /* addiu/daddiu sp,sp,-imm */
++ if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
++ return 0;
++ if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
++ return 1;
++ return 0;
++}
++
++static int get_frame_info(struct mips_frame_info *info)
++{
++ union mips_instruction *ip = info->func;
++ int i, max_insns =
++ min(128UL, info->func_size / sizeof(union mips_instruction));
++
+ info->pc_offset = -1;
+ info->frame_size = 0;
+- for (i = 0; i < 128; i++, ip++) {
+- /* if jal, jalr, jr, stop. */
+- if (ip->j_format.opcode == jal_op ||
+- (ip->r_format.opcode == spec_op &&
+- (ip->r_format.func == jalr_op ||
+- ip->r_format.func == jr_op)))
+- break;
+
+- if (info->func_size && i >= info->func_size / 4)
++ for (i = 0; i < max_insns; i++, ip++) {
++
++ if (is_jal_jalr_jr_ins(ip))
+ break;
+- if (
+-#ifdef CONFIG_32BIT
+- ip->i_format.opcode == addiu_op &&
+-#endif
+-#ifdef CONFIG_64BIT
+- ip->i_format.opcode == daddiu_op &&
+-#endif
+- ip->i_format.rs == 29 &&
+- ip->i_format.rt == 29) {
+- /* addiu/daddiu sp,sp,-imm */
+- if (info->frame_size)
+- continue;
+- info->frame_size = - ip->i_format.simmediate;
++ if (!info->frame_size) {
++ if (is_sp_move_ins(ip))
++ info->frame_size = - ip->i_format.simmediate;
++ continue;
+ }
+-
+- if (
+-#ifdef CONFIG_32BIT
+- ip->i_format.opcode == sw_op &&
+-#endif
+-#ifdef CONFIG_64BIT
+- ip->i_format.opcode == sd_op &&
+-#endif
+- ip->i_format.rs == 29 &&
+- ip->i_format.rt == 31) {
+- /* sw / sd $ra, offset($sp) */
+- if (info->pc_offset != -1)
+- continue;
++ if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
+ info->pc_offset =
+ ip->i_format.simmediate / sizeof(long);
++ break;
+ }
+ }
+- if (info->pc_offset == -1 || info->frame_size == 0) {
+- if (func == schedule)
+- printk("Can't analyze prologue code at %p\n", func);
+- info->pc_offset = -1;
+- info->frame_size = 0;
+- }
+-
+- return 0;
++ if (info->frame_size && info->pc_offset >= 0) /* nested */
++ return 0;
++ if (info->pc_offset < 0) /* leaf */
++ return 1;
++ /* prologue seems boggus... */
++ return -1;
+ }
+
+ static int __init frame_info_init(void)
+@@ -368,7 +369,14 @@ #else
+ schedule_frame = &mfinfo[0];
+ #endif
+ for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++)
+- get_frame_info(&mfinfo[i]);
++ get_frame_info(mfinfo + i);
++
++ /*
++ * Without schedule() frame info, result given by
++ * thread_saved_pc() and get_wchan() are not reliable.
++ */
++ if (schedule_frame->pc_offset < 0)
++ printk("Can't analyze schedule() prologue at %p\n", schedule);
+
+ mfinfo_num = i;
+ return 0;
+@@ -427,6 +435,8 @@ #ifdef CONFIG_KALLSYMS
+ if (i < 0)
+ break;
+
++ if (mfinfo[i].pc_offset < 0)
++ break;
+ pc = ((unsigned long *)frame)[mfinfo[i].pc_offset];
+ if (!mfinfo[i].frame_size)
+ break;
+@@ -437,3 +447,49 @@ #endif
+ return pc;
+ }
+
++#ifdef CONFIG_KALLSYMS
++/* used by show_backtrace() */
++unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
++ unsigned long pc, unsigned long ra)
++{
++ unsigned long stack_page;
++ struct mips_frame_info info;
++ char *modname;
++ char namebuf[KSYM_NAME_LEN + 1];
++ unsigned long size, ofs;
++ int leaf;
++
++ stack_page = (unsigned long)task_stack_page(task);
++ if (!stack_page)
++ return 0;
++
++ if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf))
++ return 0;
++ if (ofs == 0)
++ return 0;
++
++ info.func = (void *)(pc - ofs);
++ info.func_size = ofs; /* analyze from start to ofs */
++ leaf = get_frame_info(&info);
++ if (leaf < 0)
++ return 0;
++
++ if (*sp < stack_page ||
++ *sp + info.frame_size > stack_page + THREAD_SIZE - 32)
++ return 0;
++
++ if (leaf)
++ /*
++ * For some extreme cases, get_frame_info() can
++ * consider wrongly a nested function as a leaf
++ * one. In that cases avoid to return always the
++ * same value.
++ */
++ pc = pc != ra ? ra : 0;
++ else
++ pc = ((unsigned long *)(*sp))[info.pc_offset];
++
++ *sp += info.frame_size;
++ return __kernel_text_address(pc) ? pc : 0;
++}
++#endif
+diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
+index 954a198..e51d8fd 100644
+--- a/arch/mips/kernel/traps.c
++++ b/arch/mips/kernel/traps.c
+@@ -20,6 +20,7 @@ #include <linux/smp_lock.h>
+ #include <linux/spinlock.h>
+ #include <linux/kallsyms.h>
+ #include <linux/bootmem.h>
++#include <linux/interrupt.h>
+
+ #include <asm/bootinfo.h>
+ #include <asm/branch.h>
+@@ -72,28 +73,68 @@ void (*board_nmi_handler_setup)(void);
+ void (*board_ejtag_handler_setup)(void);
+ void (*board_bind_eic_interrupt)(int irq, int regset);
+
+-/*
+- * These constant is for searching for possible module text segments.
+- * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
+- */
+-#define MODULE_RANGE (8*1024*1024)
++
++static void show_raw_backtrace(unsigned long reg29)
++{
++ unsigned long *sp = (unsigned long *)reg29;
++ unsigned long addr;
++
++ printk("Call Trace:");
++#ifdef CONFIG_KALLSYMS
++ printk("\n");
++#endif
++ while (!kstack_end(sp)) {
++ addr = *sp++;
++ if (__kernel_text_address(addr))
++ print_ip_sym(addr);
++ }
++ printk("\n");
++}
++
++#ifdef CONFIG_KALLSYMS
++static int raw_show_trace;
++static int __init set_raw_show_trace(char *str)
++{
++ raw_show_trace = 1;
++ return 1;
++}
++__setup("raw_show_trace", set_raw_show_trace);
++
++extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
++ unsigned long pc, unsigned long ra);
++
++static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
++{
++ unsigned long sp = regs->regs[29];
++ unsigned long ra = regs->regs[31];
++ unsigned long pc = regs->cp0_epc;
++
++ if (raw_show_trace || !__kernel_text_address(pc)) {
++ show_raw_backtrace(sp);
++ return;
++ }
++ printk("Call Trace:\n");
++ do {
++ print_ip_sym(pc);
++ pc = unwind_stack(task, &sp, pc, ra);
++ ra = 0;
++ } while (pc);
++ printk("\n");
++}
++#else
++#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]);
++#endif
+
+ /*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+-void show_stack(struct task_struct *task, unsigned long *sp)
++static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
+ {
+ const int field = 2 * sizeof(unsigned long);
+ long stackdata;
+ int i;
+-
+- if (!sp) {
+- if (task && task != current)
+- sp = (unsigned long *) task->thread.reg29;
+- else
+- sp = (unsigned long *) &sp;
+- }
++ unsigned long *sp = (unsigned long *)regs->regs[29];
+
+ printk("Stack :");
+ i = 0;
+@@ -114,32 +155,48 @@ void show_stack(struct task_struct *task
+ i++;
+ }
+ printk("\n");
++ show_backtrace(task, regs);
+ }
+
+-void show_trace(struct task_struct *task, unsigned long *stack)
++static __always_inline void prepare_frametrace(struct pt_regs *regs)
+ {
+- const int field = 2 * sizeof(unsigned long);
+- unsigned long addr;
+-
+- if (!stack) {
+- if (task && task != current)
+- stack = (unsigned long *) task->thread.reg29;
+- else
+- stack = (unsigned long *) &stack;
+- }
+-
+- printk("Call Trace:");
+-#ifdef CONFIG_KALLSYMS
+- printk("\n");
++ __asm__ __volatile__(
++ ".set push\n\t"
++ ".set noat\n\t"
++#ifdef CONFIG_64BIT
++ "1: dla $1, 1b\n\t"
++ "sd $1, %0\n\t"
++ "sd $29, %1\n\t"
++ "sd $31, %2\n\t"
++#else
++ "1: la $1, 1b\n\t"
++ "sw $1, %0\n\t"
++ "sw $29, %1\n\t"
++ "sw $31, %2\n\t"
+ #endif
+- while (!kstack_end(stack)) {
+- addr = *stack++;
+- if (__kernel_text_address(addr)) {
+- printk(" [<%0*lx>] ", field, addr);
+- print_symbol("%s\n", addr);
++ ".set pop\n\t"
++ : "=m" (regs->cp0_epc),
++ "=m" (regs->regs[29]), "=m" (regs->regs[31])
++ : : "memory");
++}
++
++void show_stack(struct task_struct *task, unsigned long *sp)
++{
++ struct pt_regs regs;
++ if (sp) {
++ regs.regs[29] = (unsigned long)sp;
++ regs.regs[31] = 0;
++ regs.cp0_epc = 0;
++ } else {
++ if (task && task != current) {
++ regs.regs[29] = task->thread.reg29;
++ regs.regs[31] = 0;
++ regs.cp0_epc = task->thread.reg31;
++ } else {
++ prepare_frametrace(®s);
+ }
+ }
+- printk("\n");
++ show_stacktrace(task, ®s);
+ }
+
+ /*
+@@ -147,9 +204,15 @@ #endif
+ */
+ void dump_stack(void)
+ {
+- unsigned long stack;
++ struct pt_regs regs;
+
+- show_trace(current, &stack);
++ /*
++ * Remove any garbage that may be in regs (specially func
++ * addresses) to avoid show_raw_backtrace() to report them
++ */
++ memset(®s, 0, sizeof(regs));
++ prepare_frametrace(®s);
++ show_backtrace(current, ®s);
+ }
+
+ EXPORT_SYMBOL(dump_stack);
+@@ -268,8 +331,7 @@ void show_registers(struct pt_regs *regs
+ print_modules();
+ printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
+ current->comm, current->pid, current_thread_info(), current);
+- show_stack(current, (long *) regs->regs[29]);
+- show_trace(current, (long *) regs->regs[29]);
++ show_stacktrace(current, regs);
+ show_code((unsigned int *) regs->cp0_epc);
+ printk("\n");
+ }
+@@ -292,6 +354,16 @@ #endif /* CONFIG_MIPS_MT_SMTC */
+ printk("%s[#%d]:\n", str, ++die_counter);
+ show_registers(regs);
+ 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(SIGSEGV);
+ }
+
Added: people/maks-guest/linux-2.6/debian/patches/features/mips/qemu-kernel.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/mips/qemu-kernel.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,231 @@
+# Qemu kernel config for mips/mipsel, from linux-mips.org 2.6.18-stable,
+# some initialization bits should eventually happen in qemu BIOS.
+
+
+diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile
+index 078cd30..493259c 100644
+--- a/arch/mips/qemu/Makefile
++++ b/arch/mips/qemu/Makefile
+@@ -4,4 +4,5 @@ #
+
+ obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o q-reset.o
+
++obj-$(CONFIG_VT) += q-vga.o
+ obj-$(CONFIG_SMP) += q-smp.o
+diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c
+index 8413943..37c2f73 100644
+--- a/arch/mips/qemu/q-setup.c
++++ b/arch/mips/qemu/q-setup.c
+@@ -2,6 +2,7 @@ #include <linux/init.h>
+ #include <asm/io.h>
+ #include <asm/time.h>
+
++extern void qvga_init(void);
+ extern void qemu_reboot_setup(void);
+
+ #define QEMU_PORT_BASE 0xb4000000
+@@ -23,5 +24,9 @@ void __init plat_timer_setup(struct irqa
+ void __init plat_mem_setup(void)
+ {
+ set_io_port_base(QEMU_PORT_BASE);
++#ifdef CONFIG_VT
++ qvga_init();
++#endif
++
+ qemu_reboot_setup();
+ }
+diff --git a/arch/mips/qemu/q-vga.c b/arch/mips/qemu/q-vga.c
+new file mode 100644
+index 0000000..e26109a
+--- /dev/null
++++ b/arch/mips/qemu/q-vga.c
+@@ -0,0 +1,189 @@
++/*
++ * 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 by Ralf Baechle (ralf at linux-mips.org)
++ *
++ * This will eventually go into the qemu firmware.
++ */
++#include <linux/init.h>
++#include <linux/screen_info.h>
++#include <linux/tty.h>
++#include <asm/io.h>
++#include <video/vga.h>
++
++/*
++ * This will eventually be done by the firmware; right now Linux assumes to
++ * run on the uninitialized hardware.
++ */
++#undef LOAD_VGA_FONT
++
++static unsigned char sr[8] __initdata = { /* Sequencer */
++ 0x03, 0x00, 0x03, 0x04, 0x02, 0x00, 0x00, 0x00
++};
++
++static unsigned char gr[16] __initdata= { /* Graphics Controller */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++static unsigned char ar[21] __initdata= { /* Attribute Controller */
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++ 0x0c, 0x01, 0x07, 0x13, 0x00
++};
++
++static unsigned char cr[32] __initdata= { /* CRT Controller */
++ 0x91, 0x4f, 0x4f, 0x95, 0x57, 0x4f, 0xc0, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x02, 0x30, 0x09, 0xb0,
++ 0x90, 0x83, 0x8f, 0x28, 0x1f, 0x8f, 0xc1, 0xa3,
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++static struct rgb {
++ unsigned char r;
++ unsigned char g;
++ unsigned char b;
++} palette[16] __initdata= {
++ [ 0] = {0x00, 0x00, 0x00},
++ [ 1] = {0x00, 0x00, 0x2a},
++ [ 2] = {0x00, 0x2a, 0x00},
++ [ 3] = {0x00, 0x2a, 0x2a},
++ [ 4] = {0x2a, 0x00, 0x00},
++ [ 5] = {0x2a, 0x00, 0x2a},
++ [ 6] = {0x2a, 0x15, 0x00},
++ [ 7] = {0x2a, 0x2a, 0x2a},
++ [ 8] = {0x15, 0x15, 0x15},
++ [ 9] = {0x15, 0x15, 0x3f},
++ [10] = {0x15, 0x3f, 0x15},
++ [11] = {0x15, 0x3f, 0x3f},
++ [12] = {0x3f, 0x15, 0x15},
++ [13] = {0x3f, 0x15, 0x3f},
++ [14] = {0x3f, 0x3f, 0x15},
++ [15] = {0x3f, 0x3f, 0x3f}
++
++};
++
++void __init qvga_init_ibm(void)
++{
++ int i;
++
++ for (i = 0; i < 8; i++) { /* Sequencer registers */
++ outb(i, 0x3c4);
++ outb(sr[i], 0x3c5);
++ }
++
++ for (i = 0; i < 16; i++) { /* Graphics Controller registers */
++ outb(i, 0x3ce);
++ outb(gr[i], 0x3cf);
++ }
++
++ for (i = 0; i < 21; i++) { /* Attribute Controller registers */
++ outb(i, 0x3c0);
++ outb(ar[i], 0x3c1);
++ }
++ outb(0x20, 0x3c0); /* enable bit in *index* register */
++
++ for (i = 0; i < 32; i++) { /* CRT Controller registers */
++ outb(i, 0x3d4);
++ outb(cr[i], 0x3d5);
++ }
++
++ for (i = 0; i < 16; i++) { /* palette */
++ outb(i, 0x3c8);
++ outb(palette[i].r, 0x3c9);
++ outb(palette[i].g, 0x3c9);
++ outb(palette[i].b, 0x3c9);
++ }
++
++#if 1
++ for (i = 0; i < 0x20000; i += 2)
++ *(volatile unsigned short *) (0xb00a0000 + i) = 0xaaaa;
++#endif
++}
++
++#ifdef LOAD_VGA_FONT
++#include "/home/ralf/src/qemu/qemu-mips/vgafont.h"
++
++static void __init
++qvga_load_font(unsigned char *def, unsigned int c)
++{
++ volatile void *w = (volatile void *) 0xb00a0000;
++
++ vga_wseq(NULL, 0, 1);
++ vga_wseq(NULL, 2, 4);
++ vga_wseq(NULL, 4, 7);
++ vga_wseq(NULL, 0, 3);
++ vga_wgfx(NULL, 4, 2);
++ vga_wgfx(NULL, 5, 0);
++ vga_wgfx(NULL, 6, 0);
++
++ memcpy(w, def, c);
++
++ vga_wseq(NULL, 0, 1);
++ vga_wseq(NULL, 2, 3);
++ vga_wseq(NULL, 4, 3);
++ vga_wseq(NULL, 0, 3);
++ vga_wgfx(NULL, 4, 0);
++ vga_wgfx(NULL, 5, 0x10);
++ vga_wgfx(NULL, 6, 0xe);
++}
++#endif
++
++void __init qvga_init(void)
++{
++ struct screen_info *si = &screen_info;
++ unsigned int h;
++ int i;
++
++#if LOAD_VGA_FONT
++ qvga_load_font(vgafont16, 4096);
++#endif
++
++ vga_wgfx(NULL, 5, 0x10); /* Set odd/even mode */
++ vga_wgfx(NULL, 6, 0x0c); /* map to offset 0xb8000, text mode */
++ vga_wseq(NULL, 2, 3); /* Planes 0 & 1 */
++ vga_wseq(NULL, 3, 4); /* Font offset */
++ outb(1, VGA_MIS_W); /* set msr to MSR_COLOR_EMULATION */
++ vga_wcrt(NULL, 1, 79); /* 80 columns */
++ vga_wcrt(NULL, 9, 15); /* 16 pixels per character */
++ vga_wcrt(NULL, 0x0c, 0); /* start address high 8 bit */
++ vga_wcrt(NULL, 0x0d, 0); /* start address low 8 bit */
++ vga_wcrt(NULL, 0x13, 0x28); /* line offset */
++ vga_wcrt(NULL, 0x07, 0x1f); /* line compare bit 8 */
++ vga_wcrt(NULL, 0x09, 0x4f); /* line compare bit 9 */
++ vga_wcrt(NULL, 0x18, 0xff); /* line compare low 8 bit */
++
++ h = (25 * 16);
++ vga_wcrt(NULL, 0x12, h);
++
++ outb(7, 0x3d4);
++ outb((inb(0x3d5) & ~0x42) | ((h >> 7) & 2) | ((h >> 3) & 0x40), 0x3d5);
++
++ for (i = 0; i < 21; i++) /* Attribute Controller */
++ vga_wattr(NULL, i, ar[i]);
++ outb(0x20, 0x3c0); /* Set bit 5 in Attribute Controller */
++ /* index ... VGA is so stupid I want */
++ /* to cry all day ... */
++ outb(0, VGA_PEL_IW);
++ for (i = 0; i < 16; i++) { /* palette */
++ outb(palette[i].r, VGA_PEL_D);
++ outb(palette[i].g, VGA_PEL_D);
++ outb(palette[i].b, VGA_PEL_D);
++ }
++
++ si->orig_x = 0; /* Cursor x position */
++ si->orig_y = 0; /* Cursor y position */
++ si->orig_video_cols = 80; /* Columns */
++ si->orig_video_lines = 25; /* Lines */
++ si->orig_video_isVGA = VIDEO_TYPE_VGAC; /* Card type */
++ si->orig_video_points = 16;
++
++#if 0
++ for (i = 0; i < 80; i += 2)
++ //*(volatile unsigned short *) (0xb00b8000 + i) = 0x0100 | 'A';
++ scr_writew(0x0100 | 'A', (volatile unsigned short *) (0xb00b8000 + i));
++ while (1);
++#endif
++}
Added: people/maks-guest/linux-2.6/debian/patches/features/net-forcedeth-swsusp.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/net-forcedeth-swsusp.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,66 @@
+
+Francois Romieu:
+ forcedeth: restore network after swsup/resume or ACPI S3
+
+
+diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
+index 35467e0..c41a886 100644
+--- a/drivers/net/forcedeth.c
++++ b/drivers/net/forcedeth.c
+@@ -4603,6 +4603,47 @@ static void __devexit nv_remove(struct p
+ pci_set_drvdata(pci_dev, NULL);
+ }
+
++
++static int nv_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++ struct net_device *dev = pci_get_drvdata(pdev);
++ struct fe_priv *np = netdev_priv(dev);
++ int rc = 0;
++
++ if (!netif_running(dev))
++ goto out;
++
++ netif_device_detach(dev);
++
++ /* Gross. */
++ rc = nv_close(dev);
++
++ pci_save_state(pdev);
++ pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled);
++ pci_set_power_state(pdev, pci_choose_state(pdev, state));
++out:
++ return rc;
++}
++
++static int nv_resume(struct pci_dev *pdev)
++{
++ struct net_device *dev = pci_get_drvdata(pdev);
++ int rc = 0;
++
++ if (!netif_running(dev))
++ goto out;
++
++ netif_device_attach(dev);
++
++ pci_set_power_state(pdev, PCI_D0);
++ pci_restore_state(pdev);
++ pci_enable_wake(pdev, PCI_D0, 0);
++
++ rc = nv_open(dev);
++out:
++ return rc;
++}
++
+ static struct pci_device_id pci_tbl[] = {
+ { /* nForce Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1),
+@@ -4704,6 +4745,8 @@ static struct pci_driver driver = {
+ .id_table = pci_tbl,
+ .probe = nv_probe,
+ .remove = __devexit_p(nv_remove),
++ .suspend = nv_suspend,
++ .resume = nv_resume,
+ };
+
+
Added: people/maks-guest/linux-2.6/debian/patches/features/s390/drivers-ccw-uevent-cleanup.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/s390/drivers-ccw-uevent-cleanup.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,62 @@
+## Upstream status: pending
+
+diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
+index ea4652b..5f07dd0 100644
+--- a/drivers/s390/cio/device.c
++++ b/drivers/s390/cio/device.c
+@@ -85,43 +85,19 @@ ccw_uevent (struct device *dev, char **e
+ return -ENODEV;
+
+ /* what we want to pass to /sbin/hotplug */
+-
+- envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "CU_TYPE=%04X",
+- cdev->id.cu_type);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
+- return -ENOMEM;
+- ++length;
+- buffer += length;
+-
+- envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "CU_MODEL=%02X",
+- cdev->id.cu_model);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
+- return -ENOMEM;
+- ++length;
+- buffer += length;
+-
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "CU_TYPE=%04X", cdev->id.cu_type);
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "CU_MODEL=%02X", cdev->id.cu_model);
+ /* The next two can be zero, that's ok for us */
+- envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "DEV_TYPE=%04X",
+- cdev->id.dev_type);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
+- return -ENOMEM;
+- ++length;
+- buffer += length;
+-
+- envp[i++] = buffer;
+- length += scnprintf(buffer, buffer_size - length, "DEV_MODEL=%02X",
+- cdev->id.dev_model);
+- if ((buffer_size - length <= 0) || (i >= num_envp))
+- return -ENOMEM;
+- ++length;
+- buffer += length;
+-
+- envp[i++] = buffer;
+- length += tmp_length = scnprintf(buffer, buffer_size - length, "MODALIAS=");
+- length += modalias_print(cdev, buffer + tmp_length, buffer_size - length);
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "DEV_TYPE=%04X", cdev->id.dev_type);
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "DEV_MODEL=%02X", cdev->id.dev_model);
++
++ envp[i++] = buffer + length;
++ length += scnprintf(buffer + length, buffer_size - length, "MODALIAS=");
++ length += modalias_print(cdev, buffer + length, buffer_size - length);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+
Added: people/maks-guest/linux-2.6/debian/patches/features/s390/drivers-ccw-uevent-modalias.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/features/s390/drivers-ccw-uevent-modalias.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,74 @@
+## Upstream status: In mm-tree.
+
+diff -u b/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
+--- b/drivers/s390/cio/device.c
++++ b/drivers/s390/cio/device.c
+@@ -53,6 +53,22 @@
+ return 1;
+ }
+
++static ssize_t
++modalias_print (struct ccw_device *cdev, char *buf, size_t size)
++{
++ struct ccw_device_id *id = &(cdev->id);
++ ssize_t len;
++
++ len = snprintf(buf, size, "ccw:t%04Xm%02X",
++ id->cu_type, id->cu_model);
++ if (id->dev_type != 0)
++ len += snprintf(buf + len, size - len, "dt%04Xdm%02X",
++ id->dev_type, id->dev_model);
++ else
++ len += snprintf(buf + len, size - len, "dtdm");
++ return len;
++}
++
+ /*
+ * Hotplugging interface for ccw devices.
+ * Heavily modeled on pci and usb hotplug.
+@@ -63,7 +79,7 @@
+ {
+ struct ccw_device *cdev = to_ccwdev(dev);
+ int i = 0;
+- int length = 0;
++ int length = 0, tmp_length = 0;
+
+ if (!cdev)
+ return -ENODEV;
+@@ -100,6 +116,14 @@
+ cdev->id.dev_model);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
++ ++length;
++ buffer += length;
++
++ envp[i++] = buffer;
++ length += tmp_length = scnprintf(buffer, buffer_size - length, "MODALIAS=");
++ length += modalias_print(cdev, buffer + tmp_length, buffer_size - length);
++ if ((buffer_size - length <= 0) || (i >= num_envp))
++ return -ENOMEM;
+
+ envp[i] = NULL;
+
+@@ -251,17 +275,11 @@
+ modalias_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct ccw_device *cdev = to_ccwdev(dev);
+- struct ccw_device_id *id = &(cdev->id);
+- int ret;
++ ssize_t len;
+
+- ret = sprintf(buf, "ccw:t%04Xm%02X",
+- id->cu_type, id->cu_model);
+- if (id->dev_type != 0)
+- ret += sprintf(buf + ret, "dt%04Xdm%02X\n",
+- id->dev_type, id->dev_model);
+- else
+- ret += sprintf(buf + ret, "dtdm\n");
+- return ret;
++ len = modalias_print(cdev, buf, PAGE_SIZE);
++ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
++ return len;
+ }
+
+ static ssize_t
Added: people/maks-guest/linux-2.6/debian/patches/hppa-fix-cross-compile.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/hppa-fix-cross-compile.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,12 @@
+--- a/arch/parisc/Makefile.orig 2006-10-12 16:44:54.000000000 +0000
++++ b/arch/parisc/Makefile 2006-10-12 16:45:21.000000000 +0000
+@@ -20,8 +20,7 @@
+ CHECKFLAGS += -D__hppa__=1
+
+ ifdef CONFIG_64BIT
+-CROSS_COMPILE := $(shell if [ -x /usr/bin/hppa64-linux-gnu-gcc ]; then \
+- echo hppa64-linux-gnu-; else echo hppa64-linux-; fi)
++CROSS_COMPILE := hppa64-linux-gnu-
+ UTS_MACHINE := parisc64
+ CHECKFLAGS += -D__LP64__=1 -m64
+ else
Added: people/maks-guest/linux-2.6/debian/patches/hppa.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/hppa.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,8053 @@
+diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
+index 6dd0ea8..d210123 100644
+--- a/arch/parisc/Kconfig
++++ b/arch/parisc/Kconfig
+@@ -127,7 +127,7 @@ config PA11
+
+ config PREFETCH
+ def_bool y
+- depends on PA8X00
++ depends on PA8X00 || PA7200
+
+ config 64BIT
+ bool "64-bit kernel"
+diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig
+index 41fd069..4ca8e8f 100644
+--- a/arch/parisc/configs/712_defconfig
++++ b/arch/parisc/configs/712_defconfig
+@@ -1,15 +1,19 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.16-pa6
+-# Sun Mar 26 19:59:51 2006
++# Linux kernel version: 2.6.18-rc1-pa1
++# Thu Jul 13 10:20:05 2006
+ #
+ CONFIG_PARISC=y
+ CONFIG_MMU=y
+ CONFIG_STACK_GROWSUP=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+@@ -31,6 +35,7 @@ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
++# CONFIG_RELAY is not set
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+ # CONFIG_EMBEDDED is not set
+@@ -42,14 +47,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -60,7 +63,6 @@ #
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+-CONFIG_OBSOLETE_MODPARM=y
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+@@ -68,6 +70,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++# CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+ # IO Schedulers
+@@ -91,6 +94,9 @@ # CONFIG_PA7200 is not set
+ # CONFIG_PA7300LC is not set
+ # CONFIG_PA8X00 is not set
+ CONFIG_PA11=y
++CONFIG_PARISC_PAGE_SIZE_4KB=y
++# CONFIG_PARISC_PAGE_SIZE_16KB is not set
++# CONFIG_PARISC_PAGE_SIZE_64KB is not set
+ # CONFIG_SMP is not set
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ # CONFIG_PREEMPT_NONE is not set
+@@ -108,6 +114,7 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
+ # CONFIG_HPUX is not set
+
+ #
+@@ -135,6 +142,7 @@ # PA-RISC specific drivers
+ #
+ CONFIG_CHASSIS_LCD_LED=y
+ # CONFIG_PDC_CHASSIS is not set
++CONFIG_PDC_CHASSIS_WARN=y
+ CONFIG_PDC_STABLE=y
+
+ #
+@@ -174,7 +182,10 @@ # CONFIG_SYN_COOKIES is not set
+ CONFIG_INET_AH=m
+ CONFIG_INET_ESP=m
+ # CONFIG_INET_IPCOMP is not set
+-CONFIG_INET_TUNNEL=m
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+ CONFIG_INET_DIAG=m
+ CONFIG_INET_TCP_DIAG=m
+ # CONFIG_TCP_CONG_ADVANCED is not set
+@@ -185,6 +196,9 @@ # IP: Virtual Server Configuration
+ #
+ # CONFIG_IP_VS is not set
+ # CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
+ CONFIG_NETFILTER=y
+ # CONFIG_NETFILTER_DEBUG is not set
+
+@@ -208,6 +222,8 @@ # CONFIG_IP_NF_NETBIOS_NS is not set
+ CONFIG_IP_NF_TFTP=m
+ CONFIG_IP_NF_AMANDA=m
+ # CONFIG_IP_NF_PPTP is not set
++# CONFIG_IP_NF_H323 is not set
++# CONFIG_IP_NF_SIP is not set
+ CONFIG_IP_NF_QUEUE=m
+
+ #
+@@ -251,6 +267,7 @@ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_IEEE80211 is not set
++CONFIG_WIRELESS_EXT=y
+
+ #
+ # Device Drivers
+@@ -263,6 +280,7 @@ # CONFIG_STANDALONE is not set
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ CONFIG_FW_LOADER=y
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -283,6 +301,7 @@ # CONFIG_PARPORT_PC_FIFO is not set
+ # CONFIG_PARPORT_PC_SUPERIO is not set
+ CONFIG_PARPORT_NOT_PC=y
+ CONFIG_PARPORT_GSC=y
++# CONFIG_PARPORT_AX88796 is not set
+ # CONFIG_PARPORT_1284 is not set
+
+ #
+@@ -363,8 +382,8 @@ CONFIG_MD_LINEAR=m
+ CONFIG_MD_RAID0=m
+ CONFIG_MD_RAID1=m
+ # CONFIG_MD_RAID10 is not set
+-# CONFIG_MD_RAID5 is not set
+-# CONFIG_MD_RAID6 is not set
++CONFIG_MD_RAID456=m
++CONFIG_MD_RAID5_RESHAPE=y
+ # CONFIG_MD_MULTIPATH is not set
+ # CONFIG_MD_FAULTY is not set
+ # CONFIG_BLK_DEV_DM is not set
+@@ -420,12 +439,12 @@ #
+ # Wireless LAN (non-hamradio)
+ #
+ CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+ #
+ # Obsolete Wireless cards support (pre-802.11)
+ #
+ # CONFIG_STRIP is not set
+-# CONFIG_ATMEL is not set
+ # CONFIG_HOSTAP is not set
+
+ #
+@@ -516,6 +535,7 @@ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -523,6 +543,7 @@ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_GSC=y
+ CONFIG_SERIAL_8250_NR_UARTS=17
+ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ CONFIG_SERIAL_8250_EXTENDED=y
+@@ -555,6 +576,7 @@ #
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
+ CONFIG_GEN_RTC=y
+ CONFIG_GEN_RTC_X=y
+ # CONFIG_DTLK is not set
+@@ -586,7 +608,6 @@ # CONFIG_SPI_MASTER is not set
+ #
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -599,13 +620,10 @@ # Misc devices
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -615,11 +633,13 @@ # CONFIG_DVB is not set
+ #
+ # Graphics support
+ #
++# CONFIG_FIRMWARE_EDID is not set
+ CONFIG_FB=y
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ CONFIG_FB_MODE_HELPERS=y
+ CONFIG_FB_TILEBLITTING=y
+ CONFIG_FB_STI=y
+@@ -673,9 +693,11 @@ # CONFIG_SND_SEQ_DUMMY is not set
+ CONFIG_SND_OSSEMUL=y
+ CONFIG_SND_MIXER_OSS=y
+ CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
+ CONFIG_SND_SEQUENCER_OSS=y
+ # CONFIG_SND_DYNAMIC_MINORS is not set
+ CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
+ # CONFIG_SND_VERBOSE_PRINTK is not set
+ # CONFIG_SND_DEBUG is not set
+
+@@ -703,6 +725,7 @@ # USB support
+ #
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+@@ -719,6 +742,19 @@ #
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+
+@@ -727,6 +763,24 @@ # EDAC - error detection and reporting (
+ #
+
+ #
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+@@ -744,7 +798,6 @@ # CONFIG_JFS_DEBUG is not set
+ # CONFIG_JFS_STATISTICS is not set
+ CONFIG_FS_POSIX_ACL=y
+ CONFIG_XFS_FS=m
+-CONFIG_XFS_EXPORT=y
+ # CONFIG_XFS_QUOTA is not set
+ # CONFIG_XFS_SECURITY is not set
+ # CONFIG_XFS_POSIX_ACL is not set
+@@ -753,6 +806,7 @@ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+@@ -787,7 +841,6 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+ # CONFIG_CONFIGFS_FS is not set
+
+ #
+@@ -806,6 +859,8 @@ # CONFIG_HPFS_FS is not set
+ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ CONFIG_UFS_FS=m
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_UFS_DEBUG is not set
+
+ #
+ # Network File Systems
+@@ -834,7 +889,9 @@ CONFIG_SMB_NLS_DEFAULT=y
+ CONFIG_SMB_NLS_REMOTE="cp437"
+ CONFIG_CIFS=m
+ # CONFIG_CIFS_STATS is not set
++# CONFIG_CIFS_WEAK_PW_HASH is not set
+ # CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_CIFS_EXPERIMENTAL is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+@@ -902,14 +959,19 @@ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=16
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+-CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+@@ -967,3 +1029,6 @@ CONFIG_CRC32=y
+ CONFIG_LIBCRC32C=m
+ CONFIG_ZLIB_INFLATE=m
+ CONFIG_ZLIB_DEFLATE=m
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_PLIST=y
+diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
+index f3b812f..57c5b68 100644
+--- a/arch/parisc/configs/a500_defconfig
++++ b/arch/parisc/configs/a500_defconfig
+@@ -1,24 +1,25 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.14-rc5-pa1
+-# Fri Oct 21 23:04:54 2005
++# Linux kernel version: 2.6.18-rc1-pa1
++# Fri Jul 7 01:02:53 2006
+ #
+ CONFIG_PARISC=y
+ CONFIG_MMU=y
+ CONFIG_STACK_GROWSUP=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_TIME_LOW_RES=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ CONFIG_EXPERIMENTAL=y
+-# CONFIG_CLEAN_COMPILE is not set
+-CONFIG_BROKEN=y
+-CONFIG_BROKEN_ON_SMP=y
+ CONFIG_LOCK_KERNEL=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+
+@@ -33,29 +34,30 @@ CONFIG_POSIX_MQUEUE=y
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+-CONFIG_HOTPLUG=y
+-CONFIG_KOBJECT_UEVENT=y
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_CPUSETS is not set
++CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_EMBEDDED=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++# CONFIG_EMBEDDED is not set
+ CONFIG_KALLSYMS=y
+ CONFIG_KALLSYMS_ALL=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
++CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
+
+ #
+ # Loadable module support
+@@ -63,13 +65,30 @@ #
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+-CONFIG_OBSOLETE_MODPARM=y
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+ CONFIG_STOP_MACHINE=y
+
+ #
++# Block layer
++#
++# CONFIG_BLK_DEV_IO_TRACE is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++
++#
+ # Processor type and features
+ #
+ # CONFIG_PA7000 is not set
+@@ -80,9 +99,20 @@ CONFIG_PA8X00=y
+ CONFIG_PA20=y
+ CONFIG_PREFETCH=y
+ CONFIG_64BIT=y
++CONFIG_PARISC_PAGE_SIZE_4KB=y
++# CONFIG_PARISC_PAGE_SIZE_16KB is not set
++# CONFIG_PARISC_PAGE_SIZE_64KB is not set
+ CONFIG_SMP=y
+ CONFIG_HOTPLUG_CPU=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+ CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
++CONFIG_NODES_SHIFT=3
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_PREEMPT_BKL is not set
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+ # CONFIG_HZ_1000 is not set
+@@ -95,7 +125,8 @@ CONFIG_DISCONTIGMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ CONFIG_NEED_MULTIPLE_NODES=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+-# CONFIG_PREEMPT is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_RESOURCES_64BIT=y
+ CONFIG_COMPAT=y
+ CONFIG_NR_CPUS=8
+
+@@ -104,7 +135,6 @@ # Bus options (PCI, PCMCIA, EISA, GSC, I
+ #
+ # CONFIG_GSC is not set
+ CONFIG_PCI=y
+-CONFIG_PCI_LEGACY_PROC=y
+ # CONFIG_PCI_DEBUG is not set
+ CONFIG_PCI_LBA=y
+ CONFIG_IOSAPIC=y
+@@ -124,6 +154,11 @@ #
+ # PC-card bridges
+ #
+ CONFIG_YENTA=m
++CONFIG_YENTA_O2=y
++CONFIG_YENTA_RICOH=y
++CONFIG_YENTA_TI=y
++CONFIG_YENTA_ENE_TUNE=y
++CONFIG_YENTA_TOSHIBA=y
+ CONFIG_PD6729=m
+ CONFIG_I82092=m
+ CONFIG_PCCARD_NONSTATIC=m
+@@ -139,6 +174,7 @@ #
+ # CONFIG_SUPERIO is not set
+ # CONFIG_CHASSIS_LCD_LED is not set
+ CONFIG_PDC_CHASSIS=y
++CONFIG_PDC_CHASSIS_WARN=y
+ CONFIG_PDC_STABLE=y
+
+ #
+@@ -155,6 +191,7 @@ CONFIG_NET=y
+ #
+ # Networking options
+ #
++# CONFIG_NETDEBUG is not set
+ CONFIG_PACKET=y
+ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+@@ -177,7 +214,10 @@ # CONFIG_SYN_COOKIES is not set
+ CONFIG_INET_AH=m
+ CONFIG_INET_ESP=m
+ # CONFIG_INET_IPCOMP is not set
+-CONFIG_INET_TUNNEL=m
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+@@ -189,14 +229,51 @@ #
+ # CONFIG_IP_VS is not set
+ CONFIG_IPV6=m
+ # CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
++CONFIG_INET6_XFRM_TUNNEL=m
+ CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
+ CONFIG_IPV6_TUNNEL=m
++# CONFIG_NETWORK_SECMARK is not set
+ CONFIG_NETFILTER=y
+ # CONFIG_NETFILTER_DEBUG is not set
+-# CONFIG_NETFILTER_NETLINK is not set
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=m
++CONFIG_NETFILTER_NETLINK_QUEUE=m
++CONFIG_NETFILTER_NETLINK_LOG=m
++CONFIG_NETFILTER_XTABLES=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_SCTP=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+ #
+ # IP: Netfilter Configuration
+@@ -205,47 +282,33 @@ CONFIG_IP_NF_CONNTRACK=m
+ # CONFIG_IP_NF_CT_ACCT is not set
+ CONFIG_IP_NF_CONNTRACK_MARK=y
+ # CONFIG_IP_NF_CONNTRACK_EVENTS is not set
++CONFIG_IP_NF_CONNTRACK_NETLINK=m
+ CONFIG_IP_NF_CT_PROTO_SCTP=m
+ CONFIG_IP_NF_FTP=m
+ CONFIG_IP_NF_IRC=m
+-# CONFIG_IP_NF_NETBIOS_NS is not set
++CONFIG_IP_NF_NETBIOS_NS=m
+ CONFIG_IP_NF_TFTP=m
+ CONFIG_IP_NF_AMANDA=m
+-# CONFIG_IP_NF_PPTP is not set
++CONFIG_IP_NF_PPTP=m
++CONFIG_IP_NF_H323=m
++CONFIG_IP_NF_SIP=m
+ CONFIG_IP_NF_QUEUE=m
+ CONFIG_IP_NF_IPTABLES=m
+-CONFIG_IP_NF_MATCH_LIMIT=m
+ CONFIG_IP_NF_MATCH_IPRANGE=m
+-CONFIG_IP_NF_MATCH_MAC=m
+-CONFIG_IP_NF_MATCH_PKTTYPE=m
+-CONFIG_IP_NF_MATCH_MARK=m
+-CONFIG_IP_NF_MATCH_MULTIPORT=m
+ CONFIG_IP_NF_MATCH_TOS=m
+ CONFIG_IP_NF_MATCH_RECENT=m
+ CONFIG_IP_NF_MATCH_ECN=m
+ CONFIG_IP_NF_MATCH_DSCP=m
+-CONFIG_IP_NF_MATCH_AH_ESP=m
+-CONFIG_IP_NF_MATCH_LENGTH=m
++CONFIG_IP_NF_MATCH_AH=m
+ CONFIG_IP_NF_MATCH_TTL=m
+-CONFIG_IP_NF_MATCH_TCPMSS=m
+-CONFIG_IP_NF_MATCH_HELPER=m
+-CONFIG_IP_NF_MATCH_STATE=m
+-CONFIG_IP_NF_MATCH_CONNTRACK=m
+ CONFIG_IP_NF_MATCH_OWNER=m
+-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+-# CONFIG_IP_NF_MATCH_REALM is not set
+-CONFIG_IP_NF_MATCH_SCTP=m
+-# CONFIG_IP_NF_MATCH_DCCP is not set
+-CONFIG_IP_NF_MATCH_COMMENT=m
+-CONFIG_IP_NF_MATCH_CONNMARK=m
++CONFIG_IP_NF_MATCH_ADDRTYPE=m
+ CONFIG_IP_NF_MATCH_HASHLIMIT=m
+-# CONFIG_IP_NF_MATCH_STRING is not set
+ CONFIG_IP_NF_FILTER=m
+ CONFIG_IP_NF_TARGET_REJECT=m
+ CONFIG_IP_NF_TARGET_LOG=m
+ CONFIG_IP_NF_TARGET_ULOG=m
+ CONFIG_IP_NF_TARGET_TCPMSS=m
+-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
+ CONFIG_IP_NF_NAT=m
+ CONFIG_IP_NF_NAT_NEEDED=y
+ CONFIG_IP_NF_TARGET_MASQUERADE=m
+@@ -257,17 +320,16 @@ CONFIG_IP_NF_NAT_IRC=m
+ CONFIG_IP_NF_NAT_FTP=m
+ CONFIG_IP_NF_NAT_TFTP=m
+ CONFIG_IP_NF_NAT_AMANDA=m
++CONFIG_IP_NF_NAT_PPTP=m
++CONFIG_IP_NF_NAT_H323=m
++CONFIG_IP_NF_NAT_SIP=m
+ CONFIG_IP_NF_MANGLE=m
+ CONFIG_IP_NF_TARGET_TOS=m
+ CONFIG_IP_NF_TARGET_ECN=m
+ CONFIG_IP_NF_TARGET_DSCP=m
+-CONFIG_IP_NF_TARGET_MARK=m
+-CONFIG_IP_NF_TARGET_CLASSIFY=m
+-# CONFIG_IP_NF_TARGET_TTL is not set
+-CONFIG_IP_NF_TARGET_CONNMARK=m
++CONFIG_IP_NF_TARGET_TTL=m
+ CONFIG_IP_NF_TARGET_CLUSTERIP=m
+ CONFIG_IP_NF_RAW=m
+-CONFIG_IP_NF_TARGET_NOTRACK=m
+ CONFIG_IP_NF_ARPTABLES=m
+ CONFIG_IP_NF_ARPFILTER=m
+ CONFIG_IP_NF_ARP_MANGLE=m
+@@ -275,28 +337,21 @@ CONFIG_IP_NF_ARP_MANGLE=m
+ #
+ # IPv6: Netfilter Configuration (EXPERIMENTAL)
+ #
+-# CONFIG_IP6_NF_QUEUE is not set
++CONFIG_IP6_NF_QUEUE=m
+ CONFIG_IP6_NF_IPTABLES=m
+-# CONFIG_IP6_NF_MATCH_LIMIT is not set
+-CONFIG_IP6_NF_MATCH_MAC=m
+ CONFIG_IP6_NF_MATCH_RT=m
+ CONFIG_IP6_NF_MATCH_OPTS=m
+ CONFIG_IP6_NF_MATCH_FRAG=m
+ CONFIG_IP6_NF_MATCH_HL=m
+-# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
+-# CONFIG_IP6_NF_MATCH_OWNER is not set
+-# CONFIG_IP6_NF_MATCH_MARK is not set
++CONFIG_IP6_NF_MATCH_OWNER=m
+ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+-# CONFIG_IP6_NF_MATCH_AHESP is not set
+-# CONFIG_IP6_NF_MATCH_LENGTH is not set
+-# CONFIG_IP6_NF_MATCH_EUI64 is not set
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
+ CONFIG_IP6_NF_FILTER=m
+ CONFIG_IP6_NF_TARGET_LOG=m
+ CONFIG_IP6_NF_TARGET_REJECT=m
+-# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
+ CONFIG_IP6_NF_MANGLE=m
+-# CONFIG_IP6_NF_TARGET_MARK is not set
+-# CONFIG_IP6_NF_TARGET_HL is not set
++CONFIG_IP6_NF_TARGET_HL=m
+ CONFIG_IP6_NF_RAW=m
+
+ #
+@@ -304,10 +359,12 @@ # DCCP Configuration (EXPERIMENTAL)
+ #
+ CONFIG_IP_DCCP=m
+ CONFIG_INET_DCCP_DIAG=m
++CONFIG_IP_DCCP_ACKVEC=y
+
+ #
+ # DCCP CCIDs Configuration (EXPERIMENTAL)
+ #
++CONFIG_IP_DCCP_CCID2=m
+ # CONFIG_IP_DCCP_CCID3 is not set
+
+ #
+@@ -319,6 +376,11 @@ #
+ # SCTP Configuration (EXPERIMENTAL)
+ #
+ # CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC is not set
+ # CONFIG_ATM is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_VLAN_8021Q is not set
+@@ -332,8 +394,12 @@ # 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
++CONFIG_NET_CLS_ROUTE=y
+
+ #
+ # Network testing
+@@ -343,6 +409,7 @@ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_IEEE80211 is not set
++CONFIG_WIRELESS_EXT=y
+
+ #
+ # Device Drivers
+@@ -355,6 +422,7 @@ # CONFIG_STANDALONE is not set
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ CONFIG_FW_LOADER=y
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -378,7 +446,6 @@ #
+ #
+ # 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
+@@ -393,14 +460,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=6144
+ CONFIG_BLK_DEV_INITRD=y
+ # 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
+
+ #
+@@ -444,6 +503,7 @@ CONFIG_SCSI_SAS_ATTRS=m
+ #
+ # SCSI low-level drivers
+ #
++# CONFIG_ISCSI_TCP is not set
+ # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+ # CONFIG_SCSI_3W_9XXX is not set
+ # CONFIG_SCSI_ACARD is not set
+@@ -451,14 +511,12 @@ # CONFIG_SCSI_AACRAID is not set
+ # CONFIG_SCSI_AIC7XXX is not set
+ # CONFIG_SCSI_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_ADVANSYS is not set
+ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+ # CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_CPQFCTS is not set
++# CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+-# CONFIG_SCSI_EATA_PIO is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+ # CONFIG_SCSI_IPS is not set
+ # CONFIG_SCSI_INITIO is not set
+@@ -467,20 +525,10 @@ CONFIG_SCSI_SYM53C8XX_2=y
+ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
++CONFIG_SCSI_SYM53C8XX_MMIO=y
+ # CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_ISP is not set
+-CONFIG_SCSI_QLOGIC_FC=m
+-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+ CONFIG_SCSI_QLOGIC_1280=m
+-# CONFIG_SCSI_QLOGIC_1280_1040 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-CONFIG_SCSI_QLA2300=m
+-CONFIG_SCSI_QLA2322=m
+-# CONFIG_SCSI_QLA6312 is not set
+-# CONFIG_SCSI_QLA24XX is not set
++# CONFIG_SCSI_QLA_FC is not set
+ # CONFIG_SCSI_LPFC is not set
+ # CONFIG_SCSI_DC395x is not set
+ # CONFIG_SCSI_DC390T is not set
+@@ -502,8 +550,8 @@ CONFIG_MD_LINEAR=y
+ CONFIG_MD_RAID0=y
+ CONFIG_MD_RAID1=y
+ # CONFIG_MD_RAID10 is not set
+-# CONFIG_MD_RAID5 is not set
+-# CONFIG_MD_RAID6 is not set
++CONFIG_MD_RAID456=y
++# CONFIG_MD_RAID5_RESHAPE is not set
+ # CONFIG_MD_MULTIPATH is not set
+ # CONFIG_MD_FAULTY is not set
+ # CONFIG_BLK_DEV_DM is not set
+@@ -573,7 +621,6 @@ # CONFIG_WINBOND_840 is not set
+ # CONFIG_DM9102 is not set
+ # CONFIG_ULI526X is not set
+ CONFIG_PCMCIA_XIRCOM=m
+-# CONFIG_PCMCIA_XIRTULIP is not set
+ CONFIG_HP100=m
+ CONFIG_NET_PCI=y
+ CONFIG_PCNET32=m
+@@ -609,6 +656,7 @@ # CONFIG_YELLOWFIN is not set
+ # CONFIG_R8169 is not set
+ # CONFIG_SIS190 is not set
+ # CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ CONFIG_TIGON3=m
+@@ -620,6 +668,7 @@ #
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -630,6 +679,7 @@ #
+ # Wireless LAN (non-hamradio)
+ #
+ CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+ #
+ # Obsolete Wireless cards support (pre-802.11)
+@@ -646,6 +696,8 @@ CONFIG_PCMCIA_RAYCS=m
+ #
+ # Wireless 802.11b ISA/PCI cards support
+ #
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
+ CONFIG_HERMES=m
+ CONFIG_PLX_HERMES=m
+ CONFIG_TMD_HERMES=m
+@@ -694,6 +746,7 @@ CONFIG_PPP_ASYNC=m
+ CONFIG_PPP_SYNC_TTY=m
+ CONFIG_PPP_DEFLATE=m
+ CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPP_MPPE is not set
+ # CONFIG_PPPOE is not set
+ # CONFIG_SLIP is not set
+ # CONFIG_NET_FC is not set
+@@ -720,7 +773,10 @@ CONFIG_INPUT=y
+ #
+ # Userland interfaces
+ #
+-# CONFIG_INPUT_MOUSEDEV is not set
++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
+@@ -747,6 +803,7 @@ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -754,8 +811,10 @@ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
+ CONFIG_SERIAL_8250_CS=m
+ CONFIG_SERIAL_8250_NR_UARTS=17
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ CONFIG_SERIAL_8250_EXTENDED=y
+ CONFIG_SERIAL_8250_MANY_PORTS=y
+ CONFIG_SERIAL_8250_SHARE_IRQ=y
+@@ -765,7 +824,6 @@ # CONFIG_SERIAL_8250_RSA is not set
+ #
+ # Non-8250 serial port support
+ #
+-# CONFIG_SERIAL_MUX is not set
+ CONFIG_PDC_CONSOLE=y
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -782,6 +840,7 @@ #
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
+ CONFIG_GEN_RTC=y
+ CONFIG_GEN_RTC_X=y
+ # CONFIG_DTLK is not set
+@@ -797,6 +856,8 @@ #
+ # PCMCIA character devices
+ #
+ # CONFIG_SYNCLINK_CS is not set
++# CONFIG_CARDMAN_4000 is not set
++# CONFIG_CARDMAN_4040 is not set
+ CONFIG_RAW_DRIVER=y
+ CONFIG_MAX_RAW_DEVS=256
+
+@@ -804,6 +865,7 @@ #
+ # TPM devices
+ #
+ # CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
+
+ #
+ # I2C support
+@@ -811,9 +873,14 @@ #
+ # CONFIG_I2C is not set
+
+ #
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++
++#
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -826,13 +893,10 @@ # Misc devices
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -842,6 +906,7 @@ # CONFIG_DVB is not set
+ #
+ # Graphics support
+ #
++# CONFIG_FIRMWARE_EDID is not set
+ # CONFIG_FB is not set
+
+ #
+@@ -862,9 +927,14 @@ # USB support
+ #
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
+ # CONFIG_USB is not set
+
+ #
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
+ # USB Gadget Support
+ #
+ # CONFIG_USB_GADGET is not set
+@@ -875,12 +945,43 @@ #
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
+-# SN Devices
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
+ #
+
+ #
+@@ -901,14 +1002,16 @@ # CONFIG_JFS_DEBUG is not set
+ # CONFIG_JFS_STATISTICS is not set
+ CONFIG_FS_POSIX_ACL=y
+ CONFIG_XFS_FS=m
+-CONFIG_XFS_EXPORT=y
+ # CONFIG_XFS_QUOTA is not set
+ # CONFIG_XFS_SECURITY is not set
+ # CONFIG_XFS_POSIX_ACL is not set
+ # CONFIG_XFS_RT is not set
++CONFIG_OCFS2_FS=m
++CONFIG_OCFS2_DEBUG_MASKLOG=y
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+@@ -941,10 +1044,9 @@ CONFIG_PROC_FS=y
+ CONFIG_PROC_KCORE=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+-# CONFIG_HUGETLBFS is not set
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
++CONFIG_CONFIGFS_FS=m
+
+ #
+ # Miscellaneous filesystems
+@@ -963,6 +1065,7 @@ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ CONFIG_UFS_FS=m
+ # CONFIG_UFS_FS_WRITE is not set
++# CONFIG_UFS_DEBUG is not set
+
+ #
+ # Network File Systems
+@@ -990,7 +1093,9 @@ CONFIG_SMB_NLS_DEFAULT=y
+ CONFIG_SMB_NLS_REMOTE="cp437"
+ CONFIG_CIFS=m
+ # CONFIG_CIFS_STATS is not set
++# CONFIG_CIFS_WEAK_PW_HASH is not set
+ # CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_CIFS_EXPERIMENTAL is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+@@ -1057,19 +1162,28 @@ #
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
+-CONFIG_DEBUG_KERNEL=y
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=16
+-CONFIG_DETECT_SOFTLOCKUP=y
++# CONFIG_DETECT_SOFTLOCKUP is not set
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+-# CONFIG_DEBUG_IOREMAP is not set
+ # CONFIG_DEBUG_FS is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_FORCED_INLINING=y
++# CONFIG_RCU_TORTURE_TEST is not set
+ # CONFIG_DEBUG_RWLOCK is not set
++# CONFIG_DEBUG_RODATA is not set
+
+ #
+ # Security options
+@@ -1096,7 +1210,7 @@ CONFIG_CRYPTO_BLOWFISH=m
+ # 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_CAST5=m
+ # CONFIG_CRYPTO_CAST6 is not set
+ # CONFIG_CRYPTO_TEA is not set
+ # CONFIG_CRYPTO_ARC4 is not set
+@@ -1120,3 +1234,8 @@ CONFIG_CRC32=y
+ CONFIG_LIBCRC32C=m
+ CONFIG_ZLIB_INFLATE=m
+ CONFIG_ZLIB_DEFLATE=m
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_TEXTSEARCH_BM=m
++CONFIG_TEXTSEARCH_FSM=m
++CONFIG_PLIST=y
+diff --git a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig
+index 3509361..91cb36f 100644
+--- a/arch/parisc/configs/b180_defconfig
++++ b/arch/parisc/configs/b180_defconfig
+@@ -1,21 +1,24 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.16-rc1-pa0
+-# Tue Jan 17 08:21:01 2006
++# Linux kernel version: 2.6.18-rc1-pa1
++# Thu Jul 13 10:21:41 2006
+ #
+ CONFIG_PARISC=y
+ CONFIG_MMU=y
+ CONFIG_STACK_GROWSUP=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+ #
+ # CONFIG_EXPERIMENTAL is not set
+-CONFIG_CLEAN_COMPILE=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+
+@@ -31,6 +34,7 @@ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
++CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_EMBEDDED is not set
+ CONFIG_KALLSYMS=y
+@@ -41,14 +45,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -58,7 +60,6 @@ # 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 is not set
+@@ -66,6 +67,7 @@ # CONFIG_KMOD is not set
+ #
+ # Block layer
+ #
++# CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+ # IO Schedulers
+@@ -89,7 +91,14 @@ # CONFIG_PA7200 is not set
+ # CONFIG_PA7300LC is not set
+ # CONFIG_PA8X00 is not set
+ CONFIG_PA11=y
++CONFIG_PARISC_PAGE_SIZE_4KB=y
++# CONFIG_PARISC_PAGE_SIZE_16KB is not set
++# CONFIG_PARISC_PAGE_SIZE_64KB is not set
+ # CONFIG_SMP is not set
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+ # CONFIG_HZ_1000 is not set
+@@ -98,7 +107,7 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
+-# CONFIG_PREEMPT is not set
++# CONFIG_RESOURCES_64BIT is not set
+ # CONFIG_HPUX is not set
+
+ #
+@@ -113,7 +122,6 @@ CONFIG_EISA=y
+ CONFIG_EISA_NAMES=y
+ CONFIG_ISA=y
+ CONFIG_PCI=y
+-CONFIG_PCI_LEGACY_PROC=y
+ # CONFIG_PCI_DEBUG is not set
+ CONFIG_GSC_DINO=y
+ # CONFIG_PCI_LBA is not set
+@@ -132,6 +140,7 @@ # PA-RISC specific drivers
+ #
+ CONFIG_CHASSIS_LCD_LED=y
+ # CONFIG_PDC_CHASSIS is not set
++CONFIG_PDC_CHASSIS_WARN=y
+ CONFIG_PDC_STABLE=y
+
+ #
+@@ -148,6 +157,7 @@ CONFIG_NET=y
+ #
+ # Networking options
+ #
++# CONFIG_NETDEBUG is not set
+ CONFIG_PACKET=y
+ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+@@ -167,18 +177,26 @@ # 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_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+ CONFIG_INET_DIAG=y
+ CONFIG_INET_TCP_DIAG=y
+ # CONFIG_TCP_CONG_ADVANCED is not set
+ CONFIG_TCP_CONG_BIC=y
+ CONFIG_IPV6=y
+ # CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
+ # CONFIG_INET6_AH is not set
+ # CONFIG_INET6_ESP is not set
+ # CONFIG_INET6_IPCOMP is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
+ # CONFIG_INET6_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+ # CONFIG_IPV6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_VLAN_8021Q is not set
+@@ -200,6 +218,7 @@ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_IEEE80211 is not set
++CONFIG_WIRELESS_EXT=y
+
+ #
+ # Device Drivers
+@@ -212,6 +231,7 @@ CONFIG_STANDALONE=y
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ # CONFIG_FW_LOADER is not set
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -231,6 +251,7 @@ CONFIG_PARPORT_PC=y
+ # CONFIG_PARPORT_SERIAL is not set
+ CONFIG_PARPORT_NOT_PC=y
+ CONFIG_PARPORT_GSC=y
++# CONFIG_PARPORT_AX88796 is not set
+ # CONFIG_PARPORT_1284 is not set
+
+ #
+@@ -251,10 +272,9 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
+ # 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_BLK_DEV_INITRD is not set
+ CONFIG_CDROM_PKTCDVD=m
+ CONFIG_CDROM_PKTCDVD_BUFFERS=8
+-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+ CONFIG_ATA_OVER_ETH=y
+
+ #
+@@ -314,6 +334,7 @@ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_DTC3280 is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+@@ -341,7 +362,6 @@ # CONFIG_SCSI_NCR53C8XX_PROFILE is not s
+ # CONFIG_SCSI_PAS16 is not set
+ # CONFIG_SCSI_PSI240I is not set
+ # CONFIG_SCSI_QLOGIC_FAS is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
+ # CONFIG_SCSI_LPFC is not set
+@@ -365,8 +385,7 @@ CONFIG_BLK_DEV_MD=y
+ CONFIG_MD_LINEAR=y
+ CONFIG_MD_RAID0=y
+ CONFIG_MD_RAID1=y
+-CONFIG_MD_RAID5=y
+-CONFIG_MD_RAID6=y
++CONFIG_MD_RAID456=y
+ # CONFIG_MD_MULTIPATH is not set
+ # CONFIG_MD_FAULTY is not set
+ # CONFIG_BLK_DEV_DM is not set
+@@ -448,6 +467,7 @@ # CONFIG_NS83820 is not set
+ # CONFIG_HAMACHI is not set
+ # CONFIG_R8169 is not set
+ # CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
+@@ -458,6 +478,7 @@ #
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -468,6 +489,7 @@ #
+ # Wireless LAN (non-hamradio)
+ #
+ CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+ #
+ # Obsolete Wireless cards support (pre-802.11)
+@@ -479,6 +501,8 @@ # CONFIG_WAVELAN is not set
+ #
+ # Wireless 802.11b ISA/PCI cards support
+ #
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
+ # CONFIG_HERMES is not set
+ # CONFIG_ATMEL is not set
+
+@@ -579,6 +603,7 @@ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -586,6 +611,8 @@ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_GSC=y
++CONFIG_SERIAL_8250_PCI=y
+ CONFIG_SERIAL_8250_NR_UARTS=13
+ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ CONFIG_SERIAL_8250_EXTENDED=y
+@@ -605,6 +632,7 @@ CONFIG_SERIAL_MUX=y
+ CONFIG_SERIAL_MUX_CONSOLE=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
+@@ -622,6 +650,7 @@ #
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
+ CONFIG_GEN_RTC=y
+ # CONFIG_GEN_RTC_X is not set
+ # CONFIG_DTLK is not set
+@@ -652,7 +681,6 @@ # CONFIG_SPI_MASTER is not set
+ #
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -665,13 +693,10 @@ # Misc devices
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+@@ -681,11 +706,13 @@ # CONFIG_DVB is not set
+ #
+ # Graphics support
+ #
++# CONFIG_FIRMWARE_EDID is not set
+ CONFIG_FB=y
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ # CONFIG_FB_MODE_HELPERS is not set
+ # CONFIG_FB_TILEBLITTING is not set
+ # CONFIG_FB_CIRRUS is not set
+@@ -698,7 +725,6 @@ # CONFIG_FB_S1D13XXX 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
+ # CONFIG_FB_RADEON is not set
+ # CONFIG_FB_ATY128 is not set
+ # CONFIG_FB_ATY is not set
+@@ -749,8 +775,11 @@ # CONFIG_SND_SEQ_DUMMY is not set
+ CONFIG_SND_OSSEMUL=y
+ CONFIG_SND_MIXER_OSS=y
+ CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
+ CONFIG_SND_SEQUENCER_OSS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
+ CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
+ # CONFIG_SND_VERBOSE_PRINTK is not set
+ # CONFIG_SND_DEBUG is not set
+
+@@ -767,6 +796,7 @@ #
+ # PCI devices
+ #
+ # CONFIG_SND_AD1889 is not set
++# CONFIG_SND_ALS300 is not set
+ # CONFIG_SND_ALI5451 is not set
+ # CONFIG_SND_ATIIXP is not set
+ # CONFIG_SND_ATIIXP_MODEM is not set
+@@ -791,6 +821,7 @@ # CONFIG_SND_HDSPM is not set
+ # CONFIG_SND_ICE1712 is not set
+ # CONFIG_SND_ICE1724 is not set
+ # CONFIG_SND_INTEL8X0 is not set
++# CONFIG_SND_INTEL8X0M is not set
+ # CONFIG_SND_KORG1212 is not set
+ # CONFIG_SND_MAESTRO3 is not set
+ # CONFIG_SND_MIXART is not set
+@@ -821,6 +852,7 @@ # USB support
+ #
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
+ # CONFIG_USB is not set
+
+ #
+@@ -838,12 +870,42 @@ #
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+
+ #
+-# SN Devices
++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++#
++
++#
++# Real Time Clock
++#
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
+ #
+
+ #
+@@ -863,6 +925,7 @@ # CONFIG_XFS_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+@@ -893,7 +956,6 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+
+ #
+ # Miscellaneous filesystems
+@@ -925,6 +987,7 @@ CONFIG_SUNRPC=y
+ CONFIG_SMB_FS=y
+ # CONFIG_SMB_NLS_DEFAULT is not set
+ # CONFIG_CIFS is not set
++# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+
+@@ -983,17 +1046,21 @@ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=16
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+-# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+-# CONFIG_DEBUG_IOREMAP is not set
+ # CONFIG_DEBUG_FS is not set
+ # CONFIG_DEBUG_VM is not set
+ CONFIG_FORCED_INLINING=y
+@@ -1008,7 +1075,6 @@ CONFIG_SECURITY=y
+ # CONFIG_SECURITY_NETWORK is not set
+ CONFIG_SECURITY_CAPABILITIES=y
+ # CONFIG_SECURITY_SECLVL is not set
+-# CONFIG_SECURITY_SELINUX is not set
+
+ #
+ # Cryptographic options
+@@ -1050,3 +1116,4 @@ # CONFIG_CRC_CCITT is not set
+ # CONFIG_CRC16 is not set
+ CONFIG_CRC32=y
+ # CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
+diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
+index 782906b..e5a00dc 100644
+--- a/arch/parisc/configs/c3000_defconfig
++++ b/arch/parisc/configs/c3000_defconfig
+@@ -1,15 +1,19 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.16-pa6
+-# Sun Mar 26 20:03:29 2006
++# Linux kernel version: 2.6.18-rc1-pa1
++# Thu Jul 13 10:18:04 2006
+ #
+ CONFIG_PARISC=y
+ CONFIG_MMU=y
+ CONFIG_STACK_GROWSUP=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+@@ -31,6 +35,7 @@ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
++CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+ # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+@@ -42,14 +47,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -60,7 +63,6 @@ #
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+-CONFIG_OBSOLETE_MODPARM=y
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+@@ -68,6 +70,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++# CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+ # IO Schedulers
+@@ -93,6 +96,9 @@ CONFIG_PA8X00=y
+ CONFIG_PA20=y
+ CONFIG_PREFETCH=y
+ # CONFIG_64BIT is not set
++CONFIG_PARISC_PAGE_SIZE_4KB=y
++# CONFIG_PARISC_PAGE_SIZE_16KB is not set
++# CONFIG_PARISC_PAGE_SIZE_64KB is not set
+ # CONFIG_SMP is not set
+ CONFIG_ARCH_FLATMEM_ENABLE=y
+ # CONFIG_PREEMPT_NONE is not set
+@@ -110,6 +116,7 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
+ # CONFIG_HPUX is not set
+
+ #
+@@ -117,7 +124,6 @@ # Bus options (PCI, PCMCIA, EISA, GSC, I
+ #
+ # CONFIG_GSC is not set
+ CONFIG_PCI=y
+-CONFIG_PCI_LEGACY_PROC=y
+ # CONFIG_PCI_DEBUG is not set
+ CONFIG_PCI_LBA=y
+ CONFIG_IOSAPIC=y
+@@ -139,6 +145,7 @@ #
+ CONFIG_SUPERIO=y
+ CONFIG_CHASSIS_LCD_LED=y
+ # CONFIG_PDC_CHASSIS is not set
++CONFIG_PDC_CHASSIS_WARN=y
+ CONFIG_PDC_STABLE=y
+
+ #
+@@ -178,7 +185,10 @@ # 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_XFRM_TUNNEL is not set
+ # CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+ # CONFIG_INET_DIAG is not set
+ # CONFIG_TCP_CONG_ADVANCED is not set
+ CONFIG_TCP_CONG_BIC=y
+@@ -189,11 +199,16 @@ #
+ # CONFIG_IP_VS is not set
+ CONFIG_IPV6=m
+ # CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
+ # CONFIG_INET6_AH is not set
+ # CONFIG_INET6_ESP is not set
+ CONFIG_INET6_IPCOMP=m
++CONFIG_INET6_XFRM_TUNNEL=m
+ CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
+ CONFIG_IPV6_TUNNEL=m
++# CONFIG_NETWORK_SECMARK is not set
+ CONFIG_NETFILTER=y
+ CONFIG_NETFILTER_DEBUG=y
+
+@@ -217,6 +232,8 @@ # CONFIG_IP_NF_NETBIOS_NS is not set
+ CONFIG_IP_NF_TFTP=m
+ CONFIG_IP_NF_AMANDA=m
+ # CONFIG_IP_NF_PPTP is not set
++# CONFIG_IP_NF_H323 is not set
++CONFIG_IP_NF_SIP=m
+ CONFIG_IP_NF_QUEUE=m
+
+ #
+@@ -276,6 +293,7 @@ # CONFIG_STANDALONE is not set
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ CONFIG_FW_LOADER=y
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -310,7 +328,7 @@ # CONFIG_BLK_DEV_NBD is not set
+ # CONFIG_BLK_DEV_SX8 is not set
+ # CONFIG_BLK_DEV_UB is not set
+ # CONFIG_BLK_DEV_RAM is not set
+-CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_INITRD=y
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+
+@@ -426,6 +444,7 @@ CONFIG_SCSI_ATA_PIIX=m
+ # CONFIG_SCSI_SATA_MV is not set
+ # CONFIG_SCSI_SATA_NV is not set
+ # CONFIG_SCSI_PDC_ADMA is not set
++# CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_SATA_QSTOR is not set
+ CONFIG_SCSI_SATA_PROMISE=m
+ # CONFIG_SCSI_SATA_SX4 is not set
+@@ -447,7 +466,6 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+ CONFIG_SCSI_SYM53C8XX_MMIO=y
+ # CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
+ # CONFIG_SCSI_LPFC is not set
+@@ -465,8 +483,7 @@ CONFIG_MD_LINEAR=y
+ CONFIG_MD_RAID0=y
+ CONFIG_MD_RAID1=y
+ # CONFIG_MD_RAID10 is not set
+-# CONFIG_MD_RAID5 is not set
+-# CONFIG_MD_RAID6 is not set
++# CONFIG_MD_RAID456 is not set
+ # CONFIG_MD_MULTIPATH is not set
+ # CONFIG_MD_FAULTY is not set
+ CONFIG_BLK_DEV_DM=m
+@@ -587,6 +604,7 @@ #
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -680,6 +698,7 @@ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -687,6 +706,7 @@ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
+ CONFIG_SERIAL_8250_NR_UARTS=13
+ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+ CONFIG_SERIAL_8250_EXTENDED=y
+@@ -715,6 +735,7 @@ #
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
+ CONFIG_GEN_RTC=y
+ CONFIG_GEN_RTC_X=y
+ # CONFIG_DTLK is not set
+@@ -748,7 +769,6 @@ # CONFIG_SPI_MASTER is not set
+ #
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -761,27 +781,27 @@ # Misc devices
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+ #
+ # CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
+
+ #
+ # Graphics support
+ #
++# CONFIG_FIRMWARE_EDID is not set
+ CONFIG_FB=y
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ # CONFIG_FB_MODE_HELPERS is not set
+ # CONFIG_FB_TILEBLITTING is not set
+ # CONFIG_FB_CIRRUS is not set
+@@ -794,7 +814,6 @@ # CONFIG_FB_S1D13XXX 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
+ # CONFIG_FB_RADEON is not set
+ # CONFIG_FB_ATY128 is not set
+ # CONFIG_FB_ATY is not set
+@@ -846,9 +865,11 @@ # CONFIG_SND_SEQ_DUMMY is not set
+ CONFIG_SND_OSSEMUL=y
+ CONFIG_SND_MIXER_OSS=y
+ CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
+ CONFIG_SND_SEQUENCER_OSS=y
+ # CONFIG_SND_DYNAMIC_MINORS is not set
+ CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
+ # CONFIG_SND_VERBOSE_PRINTK is not set
+ # CONFIG_SND_DEBUG is not set
+
+@@ -867,7 +888,7 @@ #
+ # PCI devices
+ #
+ CONFIG_SND_AD1889=y
+-# CONFIG_SND_AD1889_OPL3 is not set
++# CONFIG_SND_ALS300 is not set
+ # CONFIG_SND_ALI5451 is not set
+ # CONFIG_SND_ATIIXP is not set
+ # CONFIG_SND_ATIIXP_MODEM is not set
+@@ -880,6 +901,18 @@ # CONFIG_SND_CA0106 is not set
+ # CONFIG_SND_CMIPCI is not set
+ # CONFIG_SND_CS4281 is not set
+ # CONFIG_SND_CS46XX is not set
++# CONFIG_SND_DARLA20 is not set
++# CONFIG_SND_GINA20 is not set
++# CONFIG_SND_LAYLA20 is not set
++# CONFIG_SND_DARLA24 is not set
++# CONFIG_SND_GINA24 is not set
++# CONFIG_SND_LAYLA24 is not set
++# CONFIG_SND_MONA is not set
++# CONFIG_SND_MIA is not set
++# CONFIG_SND_ECHO3G is not set
++# CONFIG_SND_INDIGO is not set
++# CONFIG_SND_INDIGOIO is not set
++# CONFIG_SND_INDIGODJ is not set
+ # CONFIG_SND_EMU10K1 is not set
+ # CONFIG_SND_EMU10K1X is not set
+ # CONFIG_SND_ENS1370 is not set
+@@ -899,6 +932,7 @@ # CONFIG_SND_MAESTRO3 is not set
+ # CONFIG_SND_MIXART is not set
+ # CONFIG_SND_NM256 is not set
+ # CONFIG_SND_PCXHR is not set
++# CONFIG_SND_RIPTIDE is not set
+ # CONFIG_SND_RME32 is not set
+ # CONFIG_SND_RME96 is not set
+ # CONFIG_SND_RME9652 is not set
+@@ -924,6 +958,7 @@ # USB support
+ #
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
+ CONFIG_USB=y
+ CONFIG_USB_DEBUG=y
+
+@@ -949,7 +984,6 @@ # CONFIG_USB_SL811_HCD is not set
+ #
+ # USB Device Class drivers
+ #
+-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+ # CONFIG_USB_ACM is not set
+ CONFIG_USB_PRINTER=m
+
+@@ -986,9 +1020,7 @@ # 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_TOUCHSCREEN is not set
+ # CONFIG_USB_YEALINK is not set
+ # CONFIG_USB_XPAD is not set
+ # CONFIG_USB_ATI_REMOTE is not set
+@@ -1003,15 +1035,6 @@ CONFIG_USB_MDC800=m
+ CONFIG_USB_MICROTEK=m
+
+ #
+-# USB Multimedia devices
+-#
+-# CONFIG_USB_DABUSB is not set
+-
+-#
+-# Video4Linux support is needed for USB Multimedia device support
+-#
+-
+-#
+ # USB Network Adapters
+ #
+ # CONFIG_USB_CATC is not set
+@@ -1040,10 +1063,12 @@ # CONFIG_USB_RIO500 is not set
+ CONFIG_USB_LEGOTOWER=m
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
++# CONFIG_USB_CY7C63 is not set
+ # 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_APPLEDISPLAY is not set
+ # CONFIG_USB_LD is not set
+ # CONFIG_USB_TEST is not set
+
+@@ -1062,6 +1087,19 @@ #
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+@@ -1071,6 +1109,24 @@ # EDAC - error detection and reporting (
+ #
+
+ #
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+@@ -1084,7 +1140,6 @@ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+ # CONFIG_FS_POSIX_ACL is not set
+ CONFIG_XFS_FS=m
+-CONFIG_XFS_EXPORT=y
+ # CONFIG_XFS_QUOTA is not set
+ # CONFIG_XFS_SECURITY is not set
+ # CONFIG_XFS_POSIX_ACL is not set
+@@ -1093,6 +1148,7 @@ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ # CONFIG_AUTOFS_FS is not set
+@@ -1126,7 +1182,6 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+ # CONFIG_CONFIGFS_FS is not set
+
+ #
+@@ -1169,6 +1224,7 @@ # 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_CIFS_DEBUG2 is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+@@ -1235,14 +1291,19 @@ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=16
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+-CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+@@ -1299,3 +1360,6 @@ CONFIG_CRC32=y
+ CONFIG_LIBCRC32C=m
+ CONFIG_ZLIB_INFLATE=m
+ CONFIG_ZLIB_DEFLATE=m
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_PLIST=y
+diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig
+index b38b58e..524f611 100644
+--- a/arch/parisc/defconfig
++++ b/arch/parisc/defconfig
+@@ -1,15 +1,19 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.16-pa10
+-# Sun Apr 2 15:26:38 2006
++# Linux kernel version: 2.6.18-rc1-pa1
++# Thu Jul 13 10:23:14 2006
+ #
+ CONFIG_PARISC=y
+ CONFIG_MMU=y
+ CONFIG_STACK_GROWSUP=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_IRQ_PER_CPU=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+ #
+ # Code maturity level options
+@@ -31,6 +35,7 @@ CONFIG_SYSCTL=y
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
++CONFIG_RELAY=y
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+ # CONFIG_EMBEDDED is not set
+@@ -42,14 +47,12 @@ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
+ CONFIG_BASE_FULL=y
++CONFIG_RT_MUTEXES=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=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_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=0
+ # CONFIG_SLOB is not set
+@@ -60,7 +63,6 @@ #
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+-CONFIG_OBSOLETE_MODPARM=y
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+@@ -68,6 +70,7 @@ CONFIG_KMOD=y
+ #
+ # Block layer
+ #
++# CONFIG_BLK_DEV_IO_TRACE is not set
+
+ #
+ # IO Schedulers
+@@ -111,6 +114,7 @@ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
+ # CONFIG_HPUX is not set
+
+ #
+@@ -125,7 +129,6 @@ CONFIG_EISA=y
+ CONFIG_EISA_NAMES=y
+ # CONFIG_ISA is not set
+ CONFIG_PCI=y
+-CONFIG_PCI_LEGACY_PROC=y
+ # CONFIG_PCI_DEBUG is not set
+ CONFIG_GSC_DINO=y
+ CONFIG_PCI_LBA=y
+@@ -166,6 +169,7 @@ #
+ CONFIG_SUPERIO=y
+ CONFIG_CHASSIS_LCD_LED=y
+ CONFIG_PDC_CHASSIS=y
++CONFIG_PDC_CHASSIS_WARN=y
+ CONFIG_PDC_STABLE=y
+
+ #
+@@ -205,18 +209,26 @@ # CONFIG_SYN_COOKIES is not set
+ CONFIG_INET_AH=m
+ CONFIG_INET_ESP=m
+ # CONFIG_INET_IPCOMP is not set
+-CONFIG_INET_TUNNEL=m
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_DIAG=m
+ CONFIG_INET_TCP_DIAG=m
+ # CONFIG_TCP_CONG_ADVANCED is not set
+ CONFIG_TCP_CONG_BIC=y
+ CONFIG_IPV6=y
+ # CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
+ CONFIG_INET6_AH=y
+ CONFIG_INET6_ESP=y
+ CONFIG_INET6_IPCOMP=y
++CONFIG_INET6_XFRM_TUNNEL=y
+ CONFIG_INET6_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
+ # CONFIG_IPV6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
+ # CONFIG_NETFILTER is not set
+
+ #
+@@ -260,6 +272,7 @@ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_IEEE80211 is not set
++CONFIG_WIRELESS_EXT=y
+
+ #
+ # Device Drivers
+@@ -272,6 +285,7 @@ # CONFIG_STANDALONE is not set
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ CONFIG_FW_LOADER=y
+ # CONFIG_DEBUG_DRIVER is not set
++# CONFIG_SYS_HYPERVISOR is not set
+
+ #
+ # Connector - unified userspace <-> kernelspace linker
+@@ -294,6 +308,7 @@ # CONFIG_PARPORT_PC_SUPERIO is not set
+ CONFIG_PARPORT_PC_PCMCIA=m
+ CONFIG_PARPORT_NOT_PC=y
+ CONFIG_PARPORT_GSC=y
++# CONFIG_PARPORT_AX88796 is not set
+ CONFIG_PARPORT_1284=y
+
+ #
+@@ -429,6 +444,7 @@ # CONFIG_MEGARAID_NEWGEN is not set
+ # CONFIG_MEGARAID_LEGACY is not set
+ # CONFIG_MEGARAID_SAS is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
+ # CONFIG_SCSI_DMX3191D is not set
+ # CONFIG_SCSI_FUTURE_DOMAIN is not set
+ # CONFIG_SCSI_IPS is not set
+@@ -449,7 +465,6 @@ CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+ CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+ CONFIG_SCSI_NCR53C8XX_SYNC=20
+ # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+ # CONFIG_SCSI_QLOGIC_1280 is not set
+ # CONFIG_SCSI_QLA_FC is not set
+ # CONFIG_SCSI_LPFC is not set
+@@ -477,8 +492,8 @@ CONFIG_MD_LINEAR=y
+ CONFIG_MD_RAID0=y
+ CONFIG_MD_RAID1=y
+ CONFIG_MD_RAID10=y
+-CONFIG_MD_RAID5=y
+-CONFIG_MD_RAID6=y
++CONFIG_MD_RAID456=y
++CONFIG_MD_RAID5_RESHAPE=y
+ # CONFIG_MD_MULTIPATH is not set
+ # CONFIG_MD_FAULTY is not set
+ CONFIG_BLK_DEV_DM=y
+@@ -604,6 +619,7 @@ #
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
+
+ #
+ # Token Ring devices
+@@ -614,6 +630,7 @@ #
+ # Wireless LAN (non-hamradio)
+ #
+ CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+ #
+ # Obsolete Wireless cards support (pre-802.11)
+@@ -630,6 +647,8 @@ # CONFIG_PCMCIA_RAYCS is not set
+ #
+ # Wireless 802.11b ISA/PCI cards support
+ #
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
+ CONFIG_HERMES=y
+ # CONFIG_PLX_HERMES is not set
+ # CONFIG_TMD_HERMES is not set
+@@ -649,6 +668,7 @@ #
+ # Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+ #
+ # CONFIG_PRISM54 is not set
++# CONFIG_USB_ZD1201 is not set
+ # CONFIG_HOSTAP is not set
+ CONFIG_NET_WIRELESS=y
+
+@@ -757,6 +777,7 @@ #
+ CONFIG_VT=y
+ CONFIG_VT_CONSOLE=y
+ CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+
+ #
+@@ -764,6 +785,8 @@ # Serial drivers
+ #
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_GSC=y
++CONFIG_SERIAL_8250_PCI=y
+ CONFIG_SERIAL_8250_CS=y
+ CONFIG_SERIAL_8250_NR_UARTS=17
+ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+@@ -798,6 +821,7 @@ #
+ # Watchdog Cards
+ #
+ # CONFIG_WATCHDOG is not set
++# CONFIG_HW_RANDOM is not set
+ CONFIG_GEN_RTC=y
+ CONFIG_GEN_RTC_X=y
+ # CONFIG_DTLK is not set
+@@ -837,7 +861,6 @@ # CONFIG_SPI_MASTER is not set
+ #
+ # Dallas's 1-wire bus
+ #
+-# CONFIG_W1 is not set
+
+ #
+ # Hardware Monitoring support
+@@ -850,27 +873,27 @@ # Misc devices
+ #
+
+ #
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+ # Multimedia devices
+ #
+ # CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_V4L2=y
+
+ #
+ # Digital Video Broadcasting Devices
+ #
+ # CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
+
+ #
+ # Graphics support
+ #
++# CONFIG_FIRMWARE_EDID is not set
+ CONFIG_FB=y
+ CONFIG_FB_CFB_FILLRECT=y
+ CONFIG_FB_CFB_COPYAREA=y
+ CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
+ CONFIG_FB_MODE_HELPERS=y
+ CONFIG_FB_TILEBLITTING=y
+ # CONFIG_FB_CIRRUS is not set
+@@ -883,7 +906,6 @@ # CONFIG_FB_S1D13XXX 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
+ # CONFIG_FB_RADEON is not set
+ # CONFIG_FB_ATY128 is not set
+ # CONFIG_FB_ATY is not set
+@@ -938,22 +960,22 @@ #
+ CONFIG_SND=y
+ CONFIG_SND_TIMER=y
+ CONFIG_SND_PCM=y
+-CONFIG_SND_HWDEP=y
+ CONFIG_SND_SEQUENCER=y
+ # CONFIG_SND_SEQ_DUMMY is not set
+ CONFIG_SND_OSSEMUL=y
+ CONFIG_SND_MIXER_OSS=y
+ CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
+ CONFIG_SND_SEQUENCER_OSS=y
+ CONFIG_SND_DYNAMIC_MINORS=y
+ CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
+ # CONFIG_SND_VERBOSE_PRINTK is not set
+ # CONFIG_SND_DEBUG is not set
+
+ #
+ # Generic devices
+ #
+-CONFIG_SND_OPL3_LIB=y
+ CONFIG_SND_AC97_CODEC=y
+ CONFIG_SND_AC97_BUS=y
+ # CONFIG_SND_DUMMY is not set
+@@ -966,7 +988,7 @@ #
+ # PCI devices
+ #
+ CONFIG_SND_AD1889=y
+-CONFIG_SND_AD1889_OPL3=y
++# CONFIG_SND_ALS300 is not set
+ # CONFIG_SND_ALI5451 is not set
+ # CONFIG_SND_ATIIXP is not set
+ # CONFIG_SND_ATIIXP_MODEM is not set
+@@ -979,6 +1001,18 @@ # CONFIG_SND_CA0106 is not set
+ # CONFIG_SND_CMIPCI is not set
+ # CONFIG_SND_CS4281 is not set
+ # CONFIG_SND_CS46XX is not set
++# CONFIG_SND_DARLA20 is not set
++# CONFIG_SND_GINA20 is not set
++# CONFIG_SND_LAYLA20 is not set
++# CONFIG_SND_DARLA24 is not set
++# CONFIG_SND_GINA24 is not set
++# CONFIG_SND_LAYLA24 is not set
++# CONFIG_SND_MONA is not set
++# CONFIG_SND_MIA is not set
++# CONFIG_SND_ECHO3G is not set
++# CONFIG_SND_INDIGO is not set
++# CONFIG_SND_INDIGOIO is not set
++# CONFIG_SND_INDIGODJ is not set
+ # CONFIG_SND_EMU10K1 is not set
+ # CONFIG_SND_EMU10K1X is not set
+ # CONFIG_SND_ENS1370 is not set
+@@ -998,6 +1032,7 @@ # CONFIG_SND_MAESTRO3 is not set
+ # CONFIG_SND_MIXART is not set
+ # CONFIG_SND_NM256 is not set
+ # CONFIG_SND_PCXHR is not set
++# CONFIG_SND_RIPTIDE is not set
+ # CONFIG_SND_RME32 is not set
+ # CONFIG_SND_RME96 is not set
+ # CONFIG_SND_RME9652 is not set
+@@ -1016,6 +1051,8 @@ # CONFIG_SND_USB_AUDIO is not set
+ #
+ # PCMCIA devices
+ #
++# CONFIG_SND_VXPOCKET is not set
++# CONFIG_SND_PDAUDIOCF is not set
+
+ #
+ # GSC devices
+@@ -1032,6 +1069,7 @@ # USB support
+ #
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
+ CONFIG_USB=y
+ # CONFIG_USB_DEBUG is not set
+
+@@ -1057,7 +1095,6 @@ # CONFIG_USB_SL811_HCD is not set
+ #
+ # USB Device Class drivers
+ #
+-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+ # CONFIG_USB_ACM is not set
+ # CONFIG_USB_PRINTER is not set
+
+@@ -1084,9 +1121,7 @@ # 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_TOUCHSCREEN is not set
+ # CONFIG_USB_YEALINK is not set
+ # CONFIG_USB_XPAD is not set
+ # CONFIG_USB_ATI_REMOTE is not set
+@@ -1101,15 +1136,6 @@ # CONFIG_USB_MDC800 is not set
+ # CONFIG_USB_MICROTEK is not set
+
+ #
+-# USB Multimedia devices
+-#
+-# CONFIG_USB_DABUSB is not set
+-
+-#
+-# Video4Linux support is needed for USB Multimedia device support
+-#
+-
+-#
+ # USB Network Adapters
+ #
+ # CONFIG_USB_CATC is not set
+@@ -1117,7 +1143,6 @@ # CONFIG_USB_KAWETH is not set
+ # CONFIG_USB_PEGASUS is not set
+ # CONFIG_USB_RTL8150 is not set
+ # CONFIG_USB_USBNET is not set
+-# CONFIG_USB_ZD1201 is not set
+ CONFIG_USB_MON=y
+
+ #
+@@ -1140,10 +1165,12 @@ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_LEGOTOWER is not set
+ # CONFIG_USB_LCD is not set
+ # CONFIG_USB_LED is not set
++# CONFIG_USB_CY7C63 is not set
+ # 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_APPLEDISPLAY is not set
+ # CONFIG_USB_LD is not set
+ # CONFIG_USB_TEST is not set
+
+@@ -1162,6 +1189,19 @@ #
+ # CONFIG_MMC is not set
+
+ #
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++
++#
+ # InfiniBand support
+ #
+ # CONFIG_INFINIBAND is not set
+@@ -1171,6 +1211,24 @@ # EDAC - error detection and reporting (
+ #
+
+ #
++# Real Time Clock
++#
++# CONFIG_RTC_CLASS is not set
++
++#
++# DMA Engine support
++#
++# CONFIG_DMA_ENGINE is not set
++
++#
++# DMA Clients
++#
++
++#
++# DMA Devices
++#
++
++#
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+@@ -1188,6 +1246,7 @@ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+ CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ CONFIG_DNOTIFY=y
+ CONFIG_AUTOFS_FS=y
+@@ -1221,7 +1280,6 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_HUGETLB_PAGE is not set
+ CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+ # CONFIG_CONFIGFS_FS is not set
+
+ #
+@@ -1268,7 +1326,9 @@ CONFIG_SMB_NLS_DEFAULT=y
+ CONFIG_SMB_NLS_REMOTE="cp437"
+ CONFIG_CIFS=m
+ # CONFIG_CIFS_STATS is not set
++# CONFIG_CIFS_WEAK_PW_HASH is not set
+ # CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
+ # CONFIG_CIFS_EXPERIMENTAL is not set
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+@@ -1336,14 +1396,19 @@ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
+ CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_KERNEL=y
+ CONFIG_LOG_BUF_SHIFT=16
+ CONFIG_DETECT_SOFTLOCKUP=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_DEBUG_SLAB is not set
+-CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_RWSEMS is not set
+ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+ # CONFIG_DEBUG_KOBJECT is not set
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_FS is not set
+@@ -1401,3 +1466,4 @@ CONFIG_CRC32=y
+ CONFIG_LIBCRC32C=m
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
+diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
+index d7c80ed..fc87f55 100644
+--- a/arch/parisc/hpux/fs.c
++++ b/arch/parisc/hpux/fs.c
+@@ -92,7 +92,7 @@ static int filldir(void * __buf, const c
+ put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+- ((char *) dirent) += reclen;
++ dirent = (void __user *)dirent + reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
+index d1833f1..1e64e7b 100644
+--- a/arch/parisc/kernel/binfmt_elf32.c
++++ b/arch/parisc/kernel/binfmt_elf32.c
+@@ -87,7 +87,7 @@ #define ELF_PLATFORM ("PARISC32\0")
+ */
+
+ #define SET_PERSONALITY(ex, ibcs2) \
+- current->personality = PER_LINUX32; \
++ set_thread_flag(TIF_32BIT); \
+ current->thread.map_base = DEFAULT_MAP_BASE32; \
+ current->thread.task_size = DEFAULT_TASK_SIZE32 \
+
+@@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_
+ }
+
+ #include "../../../fs/binfmt_elf.c"
+-
+-/* Set up a separate execution domain for ELF32 binaries running
+- * on an ELF64 kernel */
+-
+-static struct exec_domain parisc32_exec_domain = {
+- .name = "Linux/ELF32",
+- .pers_low = PER_LINUX32,
+- .pers_high = PER_LINUX32,
+-};
+-
+-static int __init parisc32_exec_init(void)
+-{
+- /* steal the identity signal mappings from the default domain */
+- parisc32_exec_domain.signal_map = default_exec_domain.signal_map;
+- parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
+-
+- register_exec_domain(&parisc32_exec_domain);
+-
+- return 0;
+-}
+-
+-__initcall(parisc32_exec_init);
+diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
+index bc7c4a4..0be51e9 100644
+--- a/arch/parisc/kernel/cache.c
++++ b/arch/parisc/kernel/cache.c
+@@ -35,15 +35,12 @@ int icache_stride __read_mostly;
+ EXPORT_SYMBOL(dcache_stride);
+
+
+-#if defined(CONFIG_SMP)
+ /* On some machines (e.g. ones with the Merced bus), there can be
+ * only a single PxTLB broadcast at a time; this must be guaranteed
+ * by software. We put a spinlock around all TLB flushes to
+ * ensure this.
+ */
+ DEFINE_SPINLOCK(pa_tlb_lock);
+-EXPORT_SYMBOL(pa_tlb_lock);
+-#endif
+
+ struct pdc_cache_info cache_info __read_mostly;
+ #ifndef CONFIG_PA20
+@@ -91,7 +88,8 @@ update_mmu_cache(struct vm_area_struct *
+
+ flush_kernel_dcache_page(page);
+ clear_bit(PG_dcache_dirty, &page->flags);
+- }
++ } else if (parisc_requires_coherency())
++ flush_kernel_dcache_page(page);
+ }
+
+ void
+@@ -370,3 +368,45 @@ void parisc_setup_cache_timing(void)
+
+ printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
+ }
++
++extern void purge_kernel_dcache_page(unsigned long);
++extern void clear_user_page_asm(void *page, unsigned long vaddr);
++
++void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
++{
++ purge_kernel_dcache_page((unsigned long)page);
++ purge_tlb_start();
++ pdtlb_kernel(page);
++ purge_tlb_end();
++ clear_user_page_asm(page, vaddr);
++}
++EXPORT_SYMBOL(clear_user_page);
++
++void flush_kernel_dcache_page_addr(void *addr)
++{
++ flush_kernel_dcache_page_asm(addr);
++ purge_tlb_start();
++ pdtlb_kernel(addr);
++ purge_tlb_end();
++}
++EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
++
++void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
++ struct page *pg)
++{
++ /* no coherency needed (all in kmap/kunmap) */
++ copy_user_page_asm(vto, vfrom);
++ if (!parisc_requires_coherency())
++ flush_kernel_dcache_page_asm(vto);
++}
++EXPORT_SYMBOL(copy_user_page);
++
++#ifdef CONFIG_PA8X00
++
++void kunmap_parisc(void *addr)
++{
++ if (parisc_requires_coherency())
++ flush_kernel_dcache_page_addr(addr);
++}
++EXPORT_SYMBOL(kunmap_parisc);
++#endif
+diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
+index 95c1b8e..a659951 100644
+--- a/arch/parisc/kernel/entry.S
++++ b/arch/parisc/kernel/entry.S
+@@ -30,6 +30,7 @@ #include <asm/asm-offsets.h>
+
+
+ #include <asm/psw.h>
++#include <asm/cache.h> /* for L1_CACHE_SHIFT */
+ #include <asm/assembly.h> /* for LDREG/STREG defines */
+ #include <asm/pgtable.h>
+ #include <asm/signal.h>
+@@ -478,11 +479,7 @@ #endif
+ bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
+ DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
+ copy \pmd,%r9
+-#ifdef CONFIG_64BIT
+- shld %r9,PxD_VALUE_SHIFT,\pmd
+-#else
+- shlw %r9,PxD_VALUE_SHIFT,\pmd
+-#endif
++ SHLREG %r9,PxD_VALUE_SHIFT,\pmd
+ EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
+ DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
+ shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
+@@ -970,11 +967,7 @@ #ifdef CONFIG_SMP
+ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
+ ** irq_stat[] is defined using ____cacheline_aligned.
+ */
+-#ifdef CONFIG_64BIT
+- shld %r1, 6, %r20
+-#else
+- shlw %r1, 5, %r20
+-#endif
++ SHLREG %r1,L1_CACHE_SHIFT,%r20
+ add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
+ #endif /* CONFIG_SMP */
+
+@@ -1076,7 +1069,7 @@ intr_do_preempt:
+ BL preempt_schedule_irq, %r2
+ nop
+
+- b intr_restore /* ssm PSW_SM_I done by intr_restore */
++ b,n intr_restore /* ssm PSW_SM_I done by intr_restore */
+ #endif /* CONFIG_PREEMPT */
+
+ .import do_signal,code
+@@ -2115,11 +2108,7 @@ #ifdef CONFIG_SMP
+ ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
+
+ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
+-#ifdef CONFIG_64BIT
+- shld %r26, 6, %r20
+-#else
+- shlw %r26, 5, %r20
+-#endif
++ SHLREG %r26,L1_CACHE_SHIFT,%r20
+ add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
+ #endif /* CONFIG_SMP */
+
+diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
+index 3058bff..db33fcb 100644
+--- a/arch/parisc/kernel/hardware.c
++++ b/arch/parisc/kernel/hardware.c
+@@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_li
+ {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
+ {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
+ {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
++ {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"},
+ {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
+ {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
+ {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
+@@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_li
+ {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"},
+ {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"},
+ {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"},
++ {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"},
+ {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"},
+ {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"},
++ {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"},
+ {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"},
+ {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"},
+ {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"},
+diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
+index 5b8803c..9075603 100644
+--- a/arch/parisc/kernel/irq.c
++++ b/arch/parisc/kernel/irq.c
+@@ -35,9 +35,6 @@ #include <asm/smp.h>
+
+ #undef PARISC_IRQ_CR16_COUNTS
+
+-extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
+-extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
+-
+ #define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq))
+
+ /* Bits in EIEM correlate with cpu_irq_action[].
+@@ -45,6 +42,17 @@ #define EIEM_MASK(irq) (1UL<<(CPU_
+ */
+ static volatile unsigned long cpu_eiem = 0;
+
++/*
++** ack bitmap ... habitually set to 1, but reset to zero
++** between ->ack() and ->end() of the interrupt to prevent
++** re-interruption of a processing interrupt.
++*/
++static volatile unsigned long global_ack_eiem = ~0UL;
++/*
++** Local bitmap, same as above but for per-cpu interrupts
++*/
++static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
++
+ static void cpu_disable_irq(unsigned int irq)
+ {
+ unsigned long eirr_bit = EIEM_MASK(irq);
+@@ -62,13 +70,6 @@ static void cpu_enable_irq(unsigned int
+
+ cpu_eiem |= eirr_bit;
+
+- /* FIXME: while our interrupts aren't nested, we cannot reset
+- * the eiem mask if we're already in an interrupt. Once we
+- * implement nested interrupts, this can go away
+- */
+- if (!in_interrupt())
+- set_eiem(cpu_eiem);
+-
+ /* This is just a simple NOP IPI. But what it does is cause
+ * all the other CPUs to do a set_eiem(cpu_eiem) at the end
+ * of the interrupt handler */
+@@ -84,13 +85,45 @@ static unsigned int cpu_startup_irq(unsi
+ void no_ack_irq(unsigned int irq) { }
+ void no_end_irq(unsigned int irq) { }
+
++void cpu_ack_irq(struct irq_desc *dummy, unsigned int irq)
++{
++ unsigned long mask = EIEM_MASK(irq);
++ int cpu = smp_processor_id();
++
++ /* Clear in EIEM so we can no longer process */
++ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
++ per_cpu(local_ack_eiem, cpu) &= ~mask;
++ else
++ global_ack_eiem &= ~mask;
++
++ /* disable the interrupt */
++ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
++ /* and now ack it */
++ mtctl(mask, 23);
++}
++
++void cpu_end_irq(struct irq_desc *dummy, unsigned int irq)
++{
++ unsigned long mask = EIEM_MASK(irq);
++ int cpu = smp_processor_id();
++
++ /* set it in the eiems---it's no longer in process */
++ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
++ per_cpu(local_ack_eiem, cpu) |= mask;
++ else
++ global_ack_eiem |= mask;
++
++ /* enable the interrupt */
++ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
++}
++
+ #ifdef CONFIG_SMP
+ int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
+ {
+ int cpu_dest;
+
+ /* timer and ipi have to always be received on all CPUs */
+- if (irq == TIMER_IRQ || irq == IPI_IRQ) {
++ if (CHECK_IRQ_PER_CPU(irq)) {
+ /* Bad linux design decision. The mask has already
+ * been set; we must reset it */
+ irq_desc[irq].affinity = CPU_MASK_ALL;
+@@ -119,8 +152,6 @@ static struct hw_interrupt_type cpu_inte
+ .shutdown = cpu_disable_irq,
+ .enable = cpu_enable_irq,
+ .disable = cpu_disable_irq,
+- .ack = no_ack_irq,
+- .end = no_end_irq,
+ #ifdef CONFIG_SMP
+ .set_affinity = cpu_set_affinity_irq,
+ #endif
+@@ -209,7 +240,7 @@ #endif
+ ** Then use that to get the Transaction address and data.
+ */
+
+-int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
++int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
+ {
+ if (irq_desc[irq].action)
+ return -EBUSY;
+@@ -217,8 +248,8 @@ int cpu_claim_irq(unsigned int irq, stru
+ return -EBUSY;
+
+ if (type) {
+- irq_desc[irq].chip = type;
+- irq_desc[irq].chip_data = data;
++ set_irq_chip(irq, type);
++ set_irq_chip_data(irq, data);
+ cpu_interrupt_type.enable(irq);
+ }
+ return 0;
+@@ -298,97 +329,86 @@ unsigned int txn_alloc_data(unsigned int
+ return virt_irq - CPU_IRQ_BASE;
+ }
+
++static inline int eirr_to_irq(unsigned long eirr)
++{
++#ifdef CONFIG_64BIT
++ int bit = fls64(eirr);
++#else
++ int bit = fls(eirr);
++#endif
++ return (BITS_PER_LONG - bit) + TIMER_IRQ;
++}
++
+ /* ONLY called from entry.S:intr_extint() */
+ void do_cpu_irq_mask(struct pt_regs *regs)
+ {
+ unsigned long eirr_val;
+-
+- irq_enter();
+-
+- /*
+- * Don't allow TIMER or IPI nested interrupts.
+- * Allowing any single interrupt to nest can lead to that CPU
+- * handling interrupts with all enabled interrupts unmasked.
+- */
+- set_eiem(0UL);
+-
+- /* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
+- * 2) We loop here on EIRR contents in order to avoid
+- * nested interrupts or having to take another interrupt
+- * when we could have just handled it right away.
+- */
+- for (;;) {
+- unsigned long bit = (1UL << (BITS_PER_LONG - 1));
+- unsigned int irq;
+- eirr_val = mfctl(23) & cpu_eiem;
+- if (!eirr_val)
+- break;
+-
+- mtctl(eirr_val, 23); /* reset bits we are going to process */
+-
+- /* Work our way from MSb to LSb...same order we alloc EIRs */
+- for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
++ int irq, cpu = smp_processor_id();
+ #ifdef CONFIG_SMP
+- cpumask_t dest = irq_desc[irq].affinity;
++ cpumask_t dest;
+ #endif
+- if (!(bit & eirr_val))
+- continue;
+
+- /* clear bit in mask - can exit loop sooner */
+- eirr_val &= ~bit;
++ local_irq_disable();
++ irq_enter();
+
+-#ifdef CONFIG_SMP
+- /* FIXME: because generic set affinity mucks
+- * with the affinity before sending it to us
+- * we can get the situation where the affinity is
+- * wrong for our CPU type interrupts */
+- if (irq != TIMER_IRQ && irq != IPI_IRQ &&
+- !cpu_isset(smp_processor_id(), dest)) {
+- int cpu = first_cpu(dest);
+-
+- printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
+- irq, smp_processor_id(), cpu);
+- gsc_writel(irq + CPU_IRQ_BASE,
+- cpu_data[cpu].hpa);
+- continue;
+- }
+-#endif
++ eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem &
++ per_cpu(local_ack_eiem, cpu);
++ if (!eirr_val)
++ goto set_out;
++ irq = eirr_to_irq(eirr_val);
+
+- __do_IRQ(irq, regs);
+- }
++#ifdef CONFIG_SMP
++ dest = irq_desc[irq].affinity;
++ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
++ !cpu_isset(smp_processor_id(), dest)) {
++ int cpu = first_cpu(dest);
++
++ printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
++ irq, smp_processor_id(), cpu);
++ gsc_writel(irq + CPU_IRQ_BASE,
++ cpu_data[cpu].hpa);
++ goto set_out;
+ }
++#endif
++ generic_handle_irq(irq, regs);
+
+- set_eiem(cpu_eiem); /* restore original mask */
++ out:
+ irq_exit();
+-}
++ return;
+
++ set_out:
++ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
++ goto out;
++}
+
+ static struct irqaction timer_action = {
+ .handler = timer_interrupt,
+ .name = "timer",
+- .flags = IRQF_DISABLED,
++ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
+ };
+
+ #ifdef CONFIG_SMP
+ static struct irqaction ipi_action = {
+ .handler = ipi_interrupt,
+ .name = "IPI",
+- .flags = IRQF_DISABLED,
++ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ };
+ #endif
+
+ static void claim_cpu_irqs(void)
+ {
+ int i;
+- for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
+- irq_desc[i].chip = &cpu_interrupt_type;
+- }
++ for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++)
++ set_irq_chip_and_handler(i, &cpu_interrupt_type,
++ handle_level_irq_chip);
+
+ irq_desc[TIMER_IRQ].action = &timer_action;
+ irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU;
++ set_irq_handler(TIMER_IRQ, handle_specific_irq_timer);
+ #ifdef CONFIG_SMP
+ irq_desc[IPI_IRQ].action = &ipi_action;
+ irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
++ set_irq_handler(IPI_IRQ, handle_specific_irq_ipi);
+ #endif
+ }
+
+diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
+index 99d7fca..fb81e56 100644
+--- a/arch/parisc/kernel/processor.c
++++ b/arch/parisc/kernel/processor.c
+@@ -143,8 +143,9 @@ #endif
+ p = &cpu_data[cpuid];
+ boot_cpu_data.cpu_count++;
+
+- /* initialize counters */
+- memset(p, 0, sizeof(struct cpuinfo_parisc));
++ /* initialize counters - CPU 0 gets it_value set in time_init() */
++ if (cpuid)
++ memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+ p->loops_per_jiffy = loops_per_jiffy;
+ p->dev = dev; /* Save IODC data in case we need it */
+diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
+index bb83880..9a04272 100644
+--- a/arch/parisc/kernel/signal.c
++++ b/arch/parisc/kernel/signal.c
+@@ -26,7 +26,6 @@ #include <linux/unistd.h>
+ #include <linux/stddef.h>
+ #include <linux/compat.h>
+ #include <linux/elf.h>
+-#include <linux/personality.h>
+ #include <asm/ucontext.h>
+ #include <asm/rt_sigframe.h>
+ #include <asm/uaccess.h>
+@@ -35,7 +34,6 @@ #include <asm/cacheflush.h>
+ #include <asm/asm-offsets.h>
+
+ #ifdef CONFIG_COMPAT
+-#include <linux/compat.h>
+ #include "signal32.h"
+ #endif
+
+@@ -318,6 +316,7 @@ #ifdef __LP64__
+ if (is_compat_task()) {
+ DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
+ err |= copy_siginfo_to_user32(&compat_frame->info, info);
++
+ DBG(1,"SETUP_RT_FRAME: 1\n");
+ compat_val = (compat_int_t)current->sas_ss_sp;
+ err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp);
+@@ -433,13 +432,13 @@ #endif
+ if (in_syscall) {
+ regs->gr[31] = haddr;
+ #ifdef __LP64__
+- if (personality(current->personality) == PER_LINUX)
++ if (!test_thread_flag(TIF_32BIT))
+ sigframe_size |= 1;
+ #endif
+ } else {
+ unsigned long psw = USER_PSW;
+ #ifdef __LP64__
+- if (personality(current->personality) == PER_LINUX)
++ if (!test_thread_flag(TIF_32BIT))
+ psw |= PSW_W;
+ #endif
+
+diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
+index e39b38a..73fbd5a 100644
+--- a/arch/parisc/kernel/signal32.h
++++ b/arch/parisc/kernel/signal32.h
+@@ -73,7 +73,6 @@ typedef struct compat_siginfo {
+ struct {
+ compat_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+- char _pad[sizeof(unsigned int) - sizeof(int)];
+ compat_sigval_t _sigval; /* same as below */
+ int _sys_private; /* not to be passed to user */
+ } _timer;
+diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
+index 98e4095..faad338 100644
+--- a/arch/parisc/kernel/smp.c
++++ b/arch/parisc/kernel/smp.c
+@@ -262,6 +262,9 @@ #endif /* kDEBUG */
+ this_cpu, which);
+ return IRQ_NONE;
+ } /* Switch */
++ /* let in any pending interrupts */
++ local_irq_enable();
++ local_irq_disable();
+ } /* while (ops) */
+ }
+ return IRQ_HANDLED;
+@@ -430,8 +433,9 @@ smp_do_timer(struct pt_regs *regs)
+ static void __init
+ smp_cpu_init(int cpunum)
+ {
+- extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */
++ extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */
+ extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */
++ extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
+
+ /* Set modes and Enable floating point coprocessor */
+ (void) init_per_cpu(cpunum);
+@@ -457,6 +461,7 @@ smp_cpu_init(int cpunum)
+ enter_lazy_tlb(&init_mm, current);
+
+ init_IRQ(); /* make sure no IRQ's are enabled or pending */
++ start_cpu_itimer();
+ }
+
+
+diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
+index 8b5df98..eeca660 100644
+--- a/arch/parisc/kernel/sys_parisc.c
++++ b/arch/parisc/kernel/sys_parisc.c
+@@ -31,6 +31,8 @@ #include <linux/mman.h>
+ #include <linux/shm.h>
+ #include <linux/smp_lock.h>
+ #include <linux/syscalls.h>
++#include <linux/utsname.h>
++#include <linux/personality.h>
+
+ int sys_pipe(int __user *fildes)
+ {
+@@ -248,3 +250,46 @@ asmlinkage int sys_free_hugepages(unsign
+ {
+ return -EINVAL;
+ }
++
++long parisc_personality(unsigned long personality)
++{
++ long err;
++
++ if (personality(current->personality) == PER_LINUX32
++ && personality == PER_LINUX)
++ personality = PER_LINUX32;
++
++ err = sys_personality(personality);
++ if (err == PER_LINUX32)
++ err = PER_LINUX;
++
++ return err;
++}
++
++static inline int override_machine(char __user *mach) {
++#ifdef CONFIG_COMPAT
++ if (personality(current->personality) == PER_LINUX32) {
++ if (__put_user(0, mach + 6) ||
++ __put_user(0, mach + 7))
++ return -EFAULT;
++ }
++
++ return 0;
++#else /*!CONFIG_COMPAT*/
++ return 0;
++#endif /*CONFIG_COMPAT*/
++}
++
++long parisc_newuname(struct new_utsname __user *utsname)
++{
++ int err = 0;
++
++ down_read(&uts_sem);
++ if (copy_to_user(utsname, &system_utsname, sizeof(*utsname)))
++ err = -EFAULT;
++ up_read(&uts_sem);
++
++ err = override_machine(utsname->machine);
++
++ return (long)err;
++}
+diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
+index e27b432..701d66a 100644
+--- a/arch/parisc/kernel/syscall_table.S
++++ b/arch/parisc/kernel/syscall_table.S
+@@ -132,7 +132,7 @@ #endif
+ ENTRY_SAME(socketpair)
+ ENTRY_SAME(setpgid)
+ ENTRY_SAME(send)
+- ENTRY_SAME(newuname)
++ ENTRY_OURS(newuname)
+ ENTRY_SAME(umask) /* 60 */
+ ENTRY_SAME(chroot)
+ ENTRY_SAME(ustat)
+@@ -221,7 +221,7 @@ #endif
+ ENTRY_SAME(fchdir)
+ ENTRY_SAME(bdflush)
+ ENTRY_SAME(sysfs) /* 135 */
+- ENTRY_SAME(personality)
++ ENTRY_OURS(personality)
+ ENTRY_SAME(ni_syscall) /* for afs_syscall */
+ ENTRY_SAME(setfsuid)
+ ENTRY_SAME(setfsgid)
+diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
+index 5facc9b..acb8b31 100644
+--- a/arch/parisc/kernel/time.c
++++ b/arch/parisc/kernel/time.c
+@@ -35,8 +35,7 @@ #include <linux/timex.h>
+ /* xtime and wall_jiffies keep wall-clock time */
+ extern unsigned long wall_jiffies;
+
+-static long clocktick __read_mostly; /* timer cycles per tick */
+-static long halftick __read_mostly;
++static unsigned long clocktick __read_mostly; /* timer cycles per tick */
+
+ #ifdef CONFIG_SMP
+ extern void smp_do_timer(struct pt_regs *regs);
+@@ -44,46 +43,106 @@ #endif
+
+ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+- long now;
+- long next_tick;
+- int nticks;
+- int cpu = smp_processor_id();
++ unsigned long now;
++ unsigned long next_tick;
++ unsigned long cycles_elapsed;
++ unsigned long cycles_remainder;
++ unsigned int cpu = smp_processor_id();
++
++ /* gcc can optimize for "read-only" case with a local clocktick */
++ unsigned long cpt = clocktick;
+
+ profile_tick(CPU_PROFILING, regs);
+
+- now = mfctl(16);
+- /* initialize next_tick to time at last clocktick */
++ /* Initialize next_tick to the expected tick time. */
+ next_tick = cpu_data[cpu].it_value;
+
+- /* since time passes between the interrupt and the mfctl()
+- * above, it is never true that last_tick + clocktick == now. If we
+- * never miss a clocktick, we could set next_tick = last_tick + clocktick
+- * but maybe we'll miss ticks, hence the loop.
+- *
+- * Variables are *signed*.
++ /* Get current interval timer.
++ * CR16 reads as 64 bits in CPU wide mode.
++ * CR16 reads as 32 bits in CPU narrow mode.
+ */
++ now = mfctl(16);
++
++ cycles_elapsed = now - next_tick;
+
+- nticks = 0;
+- while((next_tick - now) < halftick) {
+- next_tick += clocktick;
+- nticks++;
++ if ((cycles_elapsed >> 5) < cpt) {
++ /* use "cheap" math (add/subtract) instead
++ * of the more expensive div/mul method
++ */
++ cycles_remainder = cycles_elapsed;
++ while (cycles_remainder > cpt) {
++ cycles_remainder -= cpt;
++ }
++ } else {
++ cycles_remainder = cycles_elapsed % cpt;
+ }
+- mtctl(next_tick, 16);
++
++ /* Can we differentiate between "early CR16" (aka Scenario 1) and
++ * "long delay" (aka Scenario 3)? I don't think so.
++ *
++ * We expected timer_interrupt to be delivered at least a few hundred
++ * cycles after the IT fires. But it's arbitrary how much time passes
++ * before we call it "late". I've picked one second.
++ */
++/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
++#if HZ == 1000
++ if (cycles_elapsed > (cpt << 10) )
++#elif HZ == 250
++ if (cycles_elapsed > (cpt << 8) )
++#elif HZ == 100
++ if (cycles_elapsed > (cpt << 7) )
++#else
++#warn WTF is HZ set to anyway?
++ if (cycles_elapsed > (HZ * cpt) )
++#endif
++ {
++ /* Scenario 3: very long delay? bad in any case */
++ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
++ " cycles %lX rem %lX "
++ " next/now %lX/%lX\n",
++ cpu,
++ cycles_elapsed, cycles_remainder,
++ next_tick, now );
++ }
++
++ /* convert from "division remainder" to "remainder of clock tick" */
++ cycles_remainder = cpt - cycles_remainder;
++
++ /* Determine when (in CR16 cycles) next IT interrupt will fire.
++ * We want IT to fire modulo clocktick even if we miss/skip some.
++ * But those interrupts don't in fact get delivered that regularly.
++ */
++ next_tick = now + cycles_remainder;
++
+ cpu_data[cpu].it_value = next_tick;
+
+- while (nticks--) {
++ /* Skip one clocktick on purpose if we are likely to miss next_tick.
++ * We want to avoid the new next_tick being less than CR16.
++ * If that happened, itimer wouldn't fire until CR16 wrapped.
++ * We'll catch the tick we missed on the tick after that.
++ */
++ if (!(cycles_remainder >> 13))
++ next_tick += cpt;
++
++ /* Program the IT when to deliver the next interrupt. */
++ /* Only bottom 32-bits of next_tick are written to cr16. */
++ mtctl(next_tick, 16);
++
++
++ /* Done mucking with unreliable delivery of interrupts.
++ * Go do system house keeping.
++ */
+ #ifdef CONFIG_SMP
+- smp_do_timer(regs);
++ smp_do_timer(regs);
+ #else
+- update_process_times(user_mode(regs));
++ update_process_times(user_mode(regs));
+ #endif
+- if (cpu == 0) {
+- write_seqlock(&xtime_lock);
+- do_timer(regs);
+- write_sequnlock(&xtime_lock);
+- }
++ if (cpu == 0) {
++ write_seqlock(&xtime_lock);
++ do_timer(regs);
++ write_sequnlock(&xtime_lock);
+ }
+-
++
+ /* check soft power switch status */
+ if (cpu == 0 && !atomic_read(&power_tasklet.count))
+ tasklet_schedule(&power_tasklet);
+@@ -109,14 +168,12 @@ #endif
+ EXPORT_SYMBOL(profile_pc);
+
+
+-/*** converted from ia64 ***/
+ /*
+ * Return the number of micro-seconds that elapsed since the last
+ * update to wall time (aka xtime aka wall_jiffies). The xtime_lock
+ * must be at least read-locked when calling this routine.
+ */
+-static inline unsigned long
+-gettimeoffset (void)
++static inline unsigned long gettimeoffset (void)
+ {
+ #ifndef CONFIG_SMP
+ /*
+@@ -124,21 +181,47 @@ #ifndef CONFIG_SMP
+ * Once parisc-linux learns the cr16 difference between processors,
+ * this could be made to work.
+ */
+- long last_tick;
+- long elapsed_cycles;
+-
+- /* it_value is the intended time of the next tick */
+- last_tick = cpu_data[smp_processor_id()].it_value;
++ unsigned long now;
++ unsigned long prev_tick;
++ unsigned long next_tick;
++ unsigned long elapsed_cycles;
++ unsigned long usec;
++ unsigned long cpuid = smp_processor_id();
++ unsigned long cpt = clocktick;
++
++ next_tick = cpu_data[cpuid].it_value;
++ now = mfctl(16); /* Read the hardware interval timer. */
++
++ prev_tick = next_tick - cpt;
++
++ /* Assume Scenario 1: "now" is later than prev_tick. */
++ elapsed_cycles = now - prev_tick;
++
++/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
++#if HZ == 1000
++ if (elapsed_cycles > (cpt << 10) )
++#elif HZ == 250
++ if (elapsed_cycles > (cpt << 8) )
++#elif HZ == 100
++ if (elapsed_cycles > (cpt << 7) )
++#else
++#warn WTF is HZ set to anyway?
++ if (elapsed_cycles > (HZ * cpt) )
++#endif
++ {
++ /* Scenario 3: clock ticks are missing. */
++ printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
++ " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n",
++ cpuid, elapsed_cycles / cpt,
++ elapsed_cycles, prev_tick, now, next_tick, cpt);
++ }
+
+- /* Subtract one tick and account for possible difference between
+- * when we expected the tick and when it actually arrived.
+- * (aka wall vs real)
+- */
+- last_tick -= clocktick * (jiffies - wall_jiffies + 1);
+- elapsed_cycles = mfctl(16) - last_tick;
++ /* FIXME: Can we improve the precision? Not with PAGE0. */
++ usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec;
+
+- /* the precision of this math could be improved */
+- return elapsed_cycles / (PAGE0->mem_10msec / 10000);
++ /* add in "lost" jiffies */
++ usec += cpt * (jiffies - wall_jiffies);
++ return usec;
+ #else
+ return 0;
+ #endif
+@@ -149,6 +232,7 @@ do_gettimeofday (struct timeval *tv)
+ {
+ unsigned long flags, seq, usec, sec;
+
++ /* Hold xtime_lock and adjust timeval. */
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = gettimeoffset();
+@@ -156,25 +240,13 @@ do_gettimeofday (struct timeval *tv)
+ usec += (xtime.tv_nsec / 1000);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+- if (unlikely(usec > LONG_MAX)) {
+- /* This can happen if the gettimeoffset adjustment is
+- * negative and xtime.tv_nsec is smaller than the
+- * adjustment */
+- printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
+- usec += USEC_PER_SEC;
+- --sec;
+- /* This should never happen, it means the negative
+- * time adjustment was more than a second, so there's
+- * something seriously wrong */
+- BUG_ON(usec > LONG_MAX);
+- }
+-
+-
++ /* Move adjusted usec's into sec's. */
+ while (usec >= USEC_PER_SEC) {
+ usec -= USEC_PER_SEC;
+ ++sec;
+ }
+
++ /* Return adjusted result. */
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+ }
+@@ -226,22 +298,23 @@ unsigned long long sched_clock(void)
+ }
+
+
++void __init start_cpu_itimer(void)
++{
++ unsigned int cpu = smp_processor_id();
++ unsigned long next_tick = mfctl(16) + clocktick;
++
++ mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */
++
++ cpu_data[cpu].it_value = next_tick;
++}
++
+ void __init time_init(void)
+ {
+- unsigned long next_tick;
+ static struct pdc_tod tod_data;
+
+ clocktick = (100 * PAGE0->mem_10msec) / HZ;
+- halftick = clocktick / 2;
+
+- /* Setup clock interrupt timing */
+-
+- next_tick = mfctl(16);
+- next_tick += clocktick;
+- cpu_data[smp_processor_id()].it_value = next_tick;
+-
+- /* kick off Itimer (CR16) */
+- mtctl(next_tick, 16);
++ start_cpu_itimer(); /* get CPU 0 started */
+
+ if(pdc_tod_read(&tod_data) == 0) {
+ write_seqlock_irq(&xtime_lock);
+diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
+index f2b96f1..780f344 100644
+--- a/arch/parisc/mm/init.c
++++ b/arch/parisc/mm/init.c
+@@ -31,10 +31,7 @@ #include <asm/sections.h>
+
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+-extern char _text; /* start of kernel code, defined by linker */
+ extern int data_start;
+-extern char _end; /* end of BSS, defined by linker */
+-extern char __init_begin, __init_end;
+
+ #ifdef CONFIG_DISCONTIGMEM
+ struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
+@@ -319,8 +316,8 @@ #define PDC_CONSOLE_IO_IODC_SIZE 32768
+
+ reserve_bootmem_node(NODE_DATA(0), 0UL,
+ (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
+- reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
+- (unsigned long)(&_end - &_text));
++ reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
++ (unsigned long)(_end - _text));
+ reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
+ ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
+
+@@ -355,8 +352,8 @@ #ifdef CONFIG_BLK_DEV_INITRD
+ #endif
+
+ data_resource.start = virt_to_phys(&data_start);
+- data_resource.end = virt_to_phys(&_end)-1;
+- code_resource.start = virt_to_phys(&_text);
++ data_resource.end = virt_to_phys(_end) - 1;
++ code_resource.start = virt_to_phys(_text);
+ code_resource.end = virt_to_phys(&data_start)-1;
+
+ /* We don't know which region the kernel will be in, so try
+@@ -385,12 +382,12 @@ #ifdef CONFIG_DEBUG_KERNEL
+ */
+ local_irq_disable();
+
+- memset(&__init_begin, 0x00,
+- (unsigned long)&__init_end - (unsigned long)&__init_begin);
++ memset(__init_begin, 0x00,
++ (unsigned long)__init_end - (unsigned long)__init_begin);
+
+ flush_data_cache();
+ asm volatile("sync" : : );
+- flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
++ flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
+ asm volatile("sync" : : );
+
+ local_irq_enable();
+@@ -398,8 +395,8 @@ #endif
+
+ /* align __init_begin and __init_end to page size,
+ ignoring linker script where we might have tried to save RAM */
+- init_begin = PAGE_ALIGN((unsigned long)(&__init_begin));
+- init_end = PAGE_ALIGN((unsigned long)(&__init_end));
++ init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
++ init_end = PAGE_ALIGN((unsigned long)(__init_end));
+ for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+@@ -578,7 +575,7 @@ static void __init map_pages(unsigned lo
+ extern const unsigned long fault_vector_20;
+ extern void * const linux_gateway_page;
+
+- ro_start = __pa((unsigned long)&_text);
++ ro_start = __pa((unsigned long)_text);
+ ro_end = __pa((unsigned long)&data_start);
+ fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
+ gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
+diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
+index 2738456..47a1d2a 100644
+--- a/arch/parisc/mm/ioremap.c
++++ b/arch/parisc/mm/ioremap.c
+@@ -188,7 +188,7 @@ #endif
+ }
+ EXPORT_SYMBOL(__ioremap);
+
+-void iounmap(void __iomem *addr)
++void iounmap(const volatile void __iomem *addr)
+ {
+ if (addr > high_memory)
+ return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
+diff --git a/block/Kconfig b/block/Kconfig
+index b6f5f0a..973be43 100644
+--- a/block/Kconfig
++++ b/block/Kconfig
+@@ -1,11 +1,9 @@
+ #
+ # Block layer core configuration
+ #
+-#XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64
+-#for instance.
+ config LBD
+ bool "Support for Large Block Devices"
+- depends on X86 || (MIPS && 32BIT) || PPC32 || (S390 && !64BIT) || SUPERH || UML
++ depends on !64BIT
+ help
+ Say Y here if you want to attach large (bigger than 2TB) discs to
+ your machine, or if you want to have a raid or loopback device
+@@ -26,7 +24,7 @@ config BLK_DEV_IO_TRACE
+
+ config LSF
+ bool "Support for Large Single Files"
+- depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML
++ depends on !64BIT
+ help
+ Say Y here if you want to be able to handle very large files (bigger
+ than 2TB), otherwise say N.
+diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
+index 22f8cf2..a9f9c48 100644
+--- a/drivers/char/agp/Kconfig
++++ b/drivers/char/agp/Kconfig
+@@ -1,6 +1,6 @@
+ config AGP
+ tristate "/dev/agpgart (AGP Support)"
+- depends on ALPHA || IA64 || PPC || X86
++ depends on ALPHA || IA64 || PARISC || PPC || X86
+ depends on PCI
+ ---help---
+ AGP (Accelerated Graphics Port) is a bus system mainly used to
+@@ -86,7 +86,7 @@ config AGP_NVIDIA
+
+ config AGP_SIS
+ tristate "SiS chipset support"
+- depends on AGP
++ depends on AGP && X86
+ help
+ This option gives you AGP support for the GLX component of
+ X on Silicon Integrated Systems [SiS] chipsets.
+@@ -103,7 +103,7 @@ config AGP_SWORKS
+
+ config AGP_VIA
+ tristate "VIA chipset support"
+- depends on AGP
++ depends on AGP && X86
+ help
+ This option gives you AGP support for the GLX component of
+ X on VIA MVP3/Apollo Pro chipsets.
+@@ -122,6 +122,14 @@ config AGP_HP_ZX1
+ This option gives you AGP GART support for the HP ZX1 chipset
+ for IA64 processors.
+
++config AGP_PARISC
++ tristate "HP Quicksilver AGP support"
++ depends on AGP && PARISC && 64BIT
++ help
++ This option gives you AGP GART support for the HP Quicksilver
++ AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000
++ workstation...)
++
+ config AGP_ALPHA_CORE
+ tristate "Alpha AGP support"
+ depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
+diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
+index d33a22f..3e58160 100644
+--- a/drivers/char/agp/Makefile
++++ b/drivers/char/agp/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_AGP_AMD64) += amd64-agp.o
+ obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o
+ obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o
+ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
++obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
+ obj-$(CONFIG_AGP_I460) += i460-agp.o
+ obj-$(CONFIG_AGP_INTEL) += intel-agp.o
+ obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
+diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
+new file mode 100644
+index 0000000..17c50b0
+--- /dev/null
++++ b/drivers/char/agp/parisc-agp.c
+@@ -0,0 +1,416 @@
++/*
++ * HP Quicksilver AGP GART routines
++ *
++ * Copyright (c) 2006, Kyle McMartin <kyle at parisc-linux.org>
++ *
++ * Based on drivers/char/agpgart/hp-agp.c which is
++ * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
++ * Bjorn Helgaas <bjorn.helgaas at hp.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/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/klist.h>
++#include <linux/agp_backend.h>
++
++#include <asm-parisc/parisc-device.h>
++#include <asm-parisc/ropes.h>
++
++#include "agp.h"
++
++#define DRVNAME "quicksilver"
++#define DRVPFX DRVNAME ": "
++
++#ifndef log2
++#define log2(x) ffz(~(x))
++#endif
++
++#define AGP8X_MODE_BIT 3
++#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
++
++static struct _parisc_agp_info {
++ void __iomem *ioc_regs;
++ void __iomem *lba_regs;
++
++ int lba_cap_offset;
++
++ u64 *gatt;
++ u64 gatt_entries;
++
++ u64 gart_base;
++ u64 gart_size;
++
++ int io_page_size;
++ int io_pages_per_kpage;
++} parisc_agp_info;
++
++static struct gatt_mask parisc_agp_masks[] =
++{
++ {
++ .mask = SBA_PDIR_VALID_BIT,
++ .type = 0
++ }
++};
++
++static struct aper_size_info_fixed parisc_agp_sizes[] =
++{
++ {0, 0, 0}, /* filled in by parisc_agp_fetch_size() */
++};
++
++static int
++parisc_agp_fetch_size(void)
++{
++ int size;
++
++ size = parisc_agp_info.gart_size / MB(1);
++ parisc_agp_sizes[0].size = size;
++ agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
++
++ return size;
++}
++
++static int
++parisc_agp_configure(void)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++
++ agp_bridge->gart_bus_addr = info->gart_base;
++ agp_bridge->capndx = info->lba_cap_offset;
++ agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
++
++ return 0;
++}
++
++static void
++parisc_agp_tlbflush(struct agp_memory *mem)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++
++ writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
++ readq(info->ioc_regs+IOC_PCOM); /* flush */
++}
++
++static int
++parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int i;
++
++ for (i = 0; i < info->gatt_entries; i++) {
++ info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
++ }
++
++ return 0;
++}
++
++static int
++parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++
++ info->gatt[0] = SBA_AGPGART_COOKIE;
++
++ return 0;
++}
++
++static int
++parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int i, k;
++ off_t j, io_pg_start;
++ int io_pg_count;
++
++ if (type != 0 || mem->type != 0) {
++ return -EINVAL;
++ }
++
++ io_pg_start = info->io_pages_per_kpage * pg_start;
++ io_pg_count = info->io_pages_per_kpage * mem->page_count;
++ if ((io_pg_start + io_pg_count) > info->gatt_entries) {
++ return -EINVAL;
++ }
++
++ j = io_pg_start;
++ while (j < (io_pg_start + io_pg_count)) {
++ if (info->gatt[j])
++ return -EBUSY;
++ j++;
++ }
++
++ if (mem->is_flushed == FALSE) {
++ global_cache_flush();
++ mem->is_flushed = TRUE;
++ }
++
++ for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
++ unsigned long paddr;
++
++ paddr = mem->memory[i];
++ for (k = 0;
++ k < info->io_pages_per_kpage;
++ k++, j++, paddr += info->io_page_size) {
++ info->gatt[j] =
++ agp_bridge->driver->mask_memory(agp_bridge,
++ paddr, type);
++ }
++ }
++
++ agp_bridge->driver->tlb_flush(mem);
++
++ return 0;
++}
++
++static int
++parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int i, io_pg_start, io_pg_count;
++
++ if (type != 0 || mem->type != 0) {
++ return -EINVAL;
++ }
++
++ io_pg_start = info->io_pages_per_kpage * pg_start;
++ io_pg_count = info->io_pages_per_kpage * mem->page_count;
++ for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
++ info->gatt[i] = agp_bridge->scratch_page;
++ }
++
++ agp_bridge->driver->tlb_flush(mem);
++ return 0;
++}
++
++static unsigned long
++parisc_agp_mask_memory(struct agp_bridge_data *bridge,
++ unsigned long addr, int type)
++{
++ return SBA_PDIR_VALID_BIT | addr;
++}
++
++static void
++parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ u32 command;
++
++ command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
++
++ command = agp_collect_device_status(bridge, mode, command);
++ command |= 0x00000100;
++
++ writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
++
++ agp_device_command(command, (mode & AGP8X_MODE) != 0);
++}
++
++struct agp_bridge_driver parisc_agp_driver = {
++ .owner = THIS_MODULE,
++ .size_type = FIXED_APER_SIZE,
++ .configure = parisc_agp_configure,
++ .fetch_size = parisc_agp_fetch_size,
++ .tlb_flush = parisc_agp_tlbflush,
++ .mask_memory = parisc_agp_mask_memory,
++ .masks = parisc_agp_masks,
++ .agp_enable = parisc_agp_enable,
++ .cache_flush = global_cache_flush,
++ .create_gatt_table = parisc_agp_create_gatt_table,
++ .free_gatt_table = parisc_agp_free_gatt_table,
++ .insert_memory = parisc_agp_insert_memory,
++ .remove_memory = parisc_agp_remove_memory,
++ .alloc_by_type = agp_generic_alloc_by_type,
++ .free_by_type = agp_generic_free_by_type,
++ .agp_alloc_page = agp_generic_alloc_page,
++ .agp_destroy_page = agp_generic_destroy_page,
++ .cant_use_aperture = 1,
++};
++
++static int __init
++agp_ioc_init(void __iomem *ioc_regs)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ u64 *iova_base, *io_pdir, io_tlb_ps;
++ int io_tlb_shift;
++
++ printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
++
++ info->ioc_regs = ioc_regs;
++
++ io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
++ switch (io_tlb_ps) {
++ case 0: io_tlb_shift = 12; break;
++ case 1: io_tlb_shift = 13; break;
++ case 2: io_tlb_shift = 14; break;
++ case 3: io_tlb_shift = 16; break;
++ default:
++ printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
++ "configuration 0x%llx\n", io_tlb_ps);
++ info->gatt = NULL;
++ info->gatt_entries = 0;
++ return -ENODEV;
++ }
++ info->io_page_size = 1 << io_tlb_shift;
++ info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
++
++ iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
++ info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
++
++ info->gart_size = PLUTO_GART_SIZE;
++ info->gatt_entries = info->gart_size / info->io_page_size;
++
++ io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
++ info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
++
++ if (info->gatt[0] != SBA_AGPGART_COOKIE) {
++ info->gatt = NULL;
++ info->gatt_entries = 0;
++ printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
++ "GART disabled\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int
++lba_find_capability(int cap)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ u16 status;
++ u8 pos, id;
++ int ttl = 48;
++
++ status = readw(info->lba_regs + PCI_STATUS);
++ if (!(status & PCI_STATUS_CAP_LIST))
++ return 0;
++ pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
++ while (ttl-- && pos >= 0x40) {
++ pos &= ~3;
++ id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
++ if (id == 0xff)
++ break;
++ if (id == cap)
++ return pos;
++ pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
++ }
++ return 0;
++}
++
++static int __init
++agp_lba_init(void __iomem *lba_hpa)
++{
++ struct _parisc_agp_info *info = &parisc_agp_info;
++ int cap;
++
++ info->lba_regs = lba_hpa;
++ info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
++
++ cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
++ if (cap != PCI_CAP_ID_AGP) {
++ printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
++ cap, info->lba_cap_offset);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int __init
++parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
++{
++ struct pci_dev *fake_bridge_dev = NULL;
++ struct agp_bridge_data *bridge;
++ int error = 0;
++
++ fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
++ if (!fake_bridge_dev) {
++ error = -ENOMEM;
++ goto fail;
++ }
++
++ error = agp_ioc_init(ioc_hpa);
++ if (error)
++ goto fail;
++
++ error = agp_lba_init(lba_hpa);
++ if (error)
++ goto fail;
++
++ bridge = agp_alloc_bridge();
++ if (!bridge) {
++ error = -ENOMEM;
++ goto fail;
++ }
++ bridge->driver = &parisc_agp_driver;
++
++ fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
++ fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
++ bridge->dev = fake_bridge_dev;
++
++ error = agp_add_bridge(bridge);
++
++fail:
++ return error;
++}
++
++static struct device *next_device(struct klist_iter *i) {
++ struct klist_node * n = klist_next(i);
++ return n ? container_of(n, struct device, knode_parent) : NULL;
++}
++
++static int
++parisc_agp_init(void)
++{
++ extern struct sba_device *sba_list;
++
++ int err = -1;
++ struct parisc_device *sba = NULL, *lba = NULL;
++ struct lba_device *lbadev = NULL;
++ struct device *dev = NULL;
++ struct klist_iter i;
++
++ if (!sba_list)
++ goto out;
++
++ /* Find our parent Pluto */
++ sba = sba_list->dev;
++ if (!IS_PLUTO(sba)) {
++ printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
++ goto out;
++ }
++
++ /* Now search our Pluto for our precious AGP device... */
++ klist_iter_init(&sba->dev.klist_children, &i);
++ while ((dev = next_device(&i))) {
++ struct parisc_device *padev = to_parisc_device(dev);
++ if (IS_QUICKSILVER(padev))
++ lba = padev;
++ }
++ klist_iter_exit(&i);
++
++ if (!lba) {
++ printk(KERN_INFO DRVPFX "No AGP devices found.\n");
++ goto out;
++ }
++
++ lbadev = parisc_get_drvdata(lba);
++
++ /* w00t, let's go find our cookies... */
++ parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
++
++ return 0;
++
++out:
++ return err;
++}
++
++module_init(parisc_agp_init);
++
++MODULE_AUTHOR("Kyle McMartin <kyle at parisc-linux.org>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
+index 683f14b..ffba0c1 100644
+--- a/drivers/net/tulip/21142.c
++++ b/drivers/net/tulip/21142.c
+@@ -26,9 +26,9 @@ static u16 t21142_csr15[] = { 0x0008, 0x
+
+ /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+ of available transceivers. */
+-void t21142_timer(unsigned long data)
++void t21142_media_task(void *data)
+ {
+- struct net_device *dev = (struct net_device *)data;
++ struct net_device *dev = data;
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
+ int csr12 = ioread32(ioaddr + CSR12);
+diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
+index d05c5aa..150a05a 100644
+--- a/drivers/net/tulip/de2104x.c
++++ b/drivers/net/tulip/de2104x.c
+@@ -1730,7 +1730,7 @@ static void __init de21040_get_media_inf
+ }
+
+ /* Note: this routine returns extra data bits for size detection. */
+-static unsigned __init tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
++static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
+ {
+ int i;
+ unsigned retval = 0;
+@@ -1926,7 +1926,7 @@ bad_srom:
+ goto fill_defaults;
+ }
+
+-static int __init de_init_one (struct pci_dev *pdev,
++static int __devinit de_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
+ struct net_device *dev;
+@@ -2082,7 +2082,7 @@ err_out_free:
+ return rc;
+ }
+
+-static void __exit de_remove_one (struct pci_dev *pdev)
++static void __devexit de_remove_one (struct pci_dev *pdev)
+ {
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct de_private *de = dev->priv;
+diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
+index 99ccf2e..19faa0e 100644
+--- a/drivers/net/tulip/interrupt.c
++++ b/drivers/net/tulip/interrupt.c
+@@ -87,6 +87,10 @@ int tulip_refill_rx(struct net_device *d
+ }
+ tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
+ }
++
++/* FIXME: restarting DMA breaks tulip_down() code path.
++ tulip_down() will unmap the RX and TX descriptors.
++ */
+ if(tp->chip_id == LC82C168) {
+ if(((ioread32(tp->base_addr + CSR5)>>17)&0x07) == 4) {
+ /* Rx stopped due to out of buffers,
+diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
+index e9bc2a9..01e1ea4 100644
+--- a/drivers/net/tulip/media.c
++++ b/drivers/net/tulip/media.c
+@@ -44,8 +44,10 @@ static const unsigned char comet_miireg2
+
+ /* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+- MDIO protocol. See the MII specifications or DP83840A data sheet
+- for details. */
++ MDIO protocol.
++ See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
++ or DP83840A data sheet for more details.
++ */
+
+ int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
+ {
+@@ -261,24 +263,56 @@ void tulip_select_media(struct net_devic
+ u16 *reset_sequence = &((u16*)(p+3))[init_length];
+ int reset_length = p[2 + init_length*2];
+ misc_info = reset_sequence + reset_length;
+- if (startup)
++ if (startup) {
++ int timeout = 30;
+ for (i = 0; i < reset_length; i++)
+ iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
++
++ /* flush posted writes */
++ ioread32(ioaddr + CSR15);
++
++ /* Sect 3.10.3 in DP83840A.pdf (p39) */
++ udelay(500);
++
++ /* Section 4.2 in DP83840A.pdf (p43) */
++ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
++ while (timeout-- &&
++ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
++ udelay(100);
++ }
+ for (i = 0; i < init_length; i++)
+ iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
++
++ ioread32(ioaddr + CSR15); /* flush posted writes */
+ } else {
+ u8 *init_sequence = p + 2;
+ u8 *reset_sequence = p + 3 + init_length;
+ int reset_length = p[2 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (startup) {
++ int timeout = 30;
+ iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ for (i = 0; i < reset_length; i++)
+ iowrite32(reset_sequence[i], ioaddr + CSR12);
++
++ /* flush posted writes */
++ ioread32(ioaddr + CSR12);
++
++ /* Sect 3.10.3 in DP83840A.pdf (p39) */
++ udelay(500);
++
++ /* Section 4.2 in DP83840A.pdf (p43) */
++ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
++ while (timeout-- &&
++ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
++ udelay(100);
+ }
+ for (i = 0; i < init_length; i++)
+ iowrite32(init_sequence[i], ioaddr + CSR12);
++
++ ioread32(ioaddr + CSR12); /* flush posted writes */
+ }
++
+ tmp_info = get_u16(&misc_info[1]);
+ if (tmp_info)
+ tp->advertising[phy_num] = tmp_info | 1;
+diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
+index e058a9f..272ef62 100644
+--- a/drivers/net/tulip/timer.c
++++ b/drivers/net/tulip/timer.c
+@@ -18,13 +18,14 @@ #include <linux/pci.h>
+ #include "tulip.h"
+
+
+-void tulip_timer(unsigned long data)
++void tulip_media_task(void *data)
+ {
+- struct net_device *dev = (struct net_device *)data;
++ struct net_device *dev = data;
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
+ u32 csr12 = ioread32(ioaddr + CSR12);
+ int next_tick = 2*HZ;
++ unsigned long flags;
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
+@@ -126,6 +127,15 @@ void tulip_timer(unsigned long data)
+ }
+ break;
+ }
++
++
++ spin_lock_irqsave(&tp->lock, flags);
++ if (tp->timeout_recovery) {
++ tulip_tx_timeout_complete(tp, ioaddr);
++ tp->timeout_recovery = 0;
++ }
++ spin_unlock_irqrestore(&tp->lock, flags);
++
+ /* mod_timer synchronizes us with potential add_timer calls
+ * from interrupts.
+ */
+diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
+index 3bcfbf3..408fe46 100644
+--- a/drivers/net/tulip/tulip.h
++++ b/drivers/net/tulip/tulip.h
+@@ -30,11 +30,10 @@ #include <asm/irq.h>
+ /* undefine, or define to various debugging levels (>4 == obscene levels) */
+ #define TULIP_DEBUG 1
+
+-/* undefine USE_IO_OPS for MMIO, define for PIO */
+ #ifdef CONFIG_TULIP_MMIO
+-# undef USE_IO_OPS
++#define TULIP_BAR 1 /* CBMA */
+ #else
+-# define USE_IO_OPS 1
++#define TULIP_BAR 0 /* CBIO */
+ #endif
+
+
+@@ -44,7 +43,8 @@ struct tulip_chip_table {
+ int io_size;
+ int valid_intrs; /* CSR7 interrupt enable settings */
+ int flags;
+- void (*media_timer) (unsigned long data);
++ void (*media_timer) (unsigned long);
++ void (*media_task) (void *);
+ };
+
+
+@@ -142,6 +142,7 @@ enum status_bits {
+ RxNoBuf = 0x80,
+ RxIntr = 0x40,
+ TxFIFOUnderflow = 0x20,
++ RxErrIntr = 0x10,
+ TxJabber = 0x08,
+ TxNoBuf = 0x04,
+ TxDied = 0x02,
+@@ -192,9 +193,14 @@ struct tulip_tx_desc {
+
+
+ enum desc_status_bits {
+- DescOwned = 0x80000000,
+- RxDescFatalErr = 0x8000,
+- RxWholePkt = 0x0300,
++ DescOwned = 0x80000000,
++ DescWholePkt = 0x60000000,
++ DescEndPkt = 0x40000000,
++ DescStartPkt = 0x20000000,
++ DescEndRing = 0x02000000,
++ DescUseLink = 0x01000000,
++ RxDescFatalErr = 0x008000,
++ RxWholePkt = 0x00000300,
+ };
+
+
+@@ -366,6 +372,7 @@ #endif
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
++ unsigned int timeout_recovery:1;
+ unsigned int csr0; /* CSR0 setting. */
+ unsigned int csr6; /* Current CSR6 control settings. */
+ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
+@@ -384,6 +391,7 @@ #endif
+ void __iomem *base_addr;
+ int csr12_shadow;
+ int pad0; /* Used for 8-byte alignment */
++ struct work_struct media_work;
+ };
+
+
+@@ -398,7 +406,7 @@ struct eeprom_fixup {
+
+ /* 21142.c */
+ extern u16 t21142_csr14[];
+-void t21142_timer(unsigned long data);
++void t21142_media_task(void *data);
+ void t21142_start_nway(struct net_device *dev);
+ void t21142_lnk_change(struct net_device *dev, int csr5);
+
+@@ -436,7 +444,7 @@ void pnic_lnk_change(struct net_device *
+ void pnic_timer(unsigned long data);
+
+ /* timer.c */
+-void tulip_timer(unsigned long data);
++void tulip_media_task(void *data);
+ void mxic_timer(unsigned long data);
+ void comet_timer(unsigned long data);
+
+@@ -473,8 +481,11 @@ static inline void tulip_stop_rxtx(struc
+ udelay(10);
+
+ if (!i)
+- printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
+- pci_name(tp->pdev));
++ printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed"
++ " (CSR5 0x%x CSR6 0x%x)\n",
++ pci_name(tp->pdev),
++ ioread32(ioaddr + CSR5),
++ ioread32(ioaddr + CSR6));
+ }
+ }
+
+@@ -485,4 +496,14 @@ static inline void tulip_restart_rxtx(st
+ tulip_start_rxtx(tp);
+ }
+
++static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr)
++{
++ /* Stop and restart the chip's Tx processes. */
++ tulip_restart_rxtx(tp);
++ /* Trigger an immediate transmit demand. */
++ iowrite32(0, ioaddr + CSR1);
++
++ tp->stats.tx_errors++;
++}
++
+ #endif /* __NET_TULIP_H__ */
+diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
+index 7351831..21eaeb2 100644
+--- a/drivers/net/tulip/tulip_core.c
++++ b/drivers/net/tulip/tulip_core.c
+@@ -130,7 +130,14 @@ #else
+ int tulip_debug = 1;
+ #endif
+
++static void tulip_timer(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct tulip_private *tp = netdev_priv(dev);
+
++ if (netif_running(dev))
++ schedule_work(&tp->media_work);
++}
+
+ /*
+ * This table use during operation for capabilities and media timer.
+@@ -144,59 +151,60 @@ struct tulip_chip_table tulip_tbl[] = {
+
+ /* DC21140 */
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
+- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer },
++ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer,
++ tulip_media_task },
+
+ /* DC21142, DC21143 */
+- { "Digital DS21143 Tulip", 128, 0x0801fbff,
++ { "Digital DS21142/43 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
+- | HAS_INTR_MITIGATION | HAS_PCI_MWI, t21142_timer },
++ | HAS_INTR_MITIGATION | HAS_PCI_MWI, tulip_timer, t21142_media_task },
+
+ /* LC82C168 */
+ { "Lite-On 82c168 PNIC", 256, 0x0001fbef,
+- HAS_MII | HAS_PNICNWAY, pnic_timer },
++ HAS_MII | HAS_PNICNWAY, pnic_timer, },
+
+ /* MX98713 */
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
++ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer, },
+
+ /* MX98715 */
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+- HAS_MEDIA_TABLE, mxic_timer },
++ HAS_MEDIA_TABLE, mxic_timer, },
+
+ /* MX98725 */
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+- HAS_MEDIA_TABLE, mxic_timer },
++ HAS_MEDIA_TABLE, mxic_timer, },
+
+ /* AX88140 */
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY
+- | IS_ASIX, tulip_timer },
++ | IS_ASIX, tulip_timer, tulip_media_task },
+
+ /* PNIC2 */
+ { "Lite-On PNIC-II", 256, 0x0801fbff,
+- HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer },
++ HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer, },
+
+ /* COMET */
+ { "ADMtek Comet", 256, 0x0001abef,
+- HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
++ HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer, },
+
+ /* COMPEX9881 */
+ { "Compex 9881 PMAC", 128, 0x0001ebef,
+- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
++ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer, },
+
+ /* I21145 */
+ { "Intel DS21145 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI
+- | HAS_NWAY | HAS_PCI_MWI, t21142_timer },
++ | HAS_NWAY | HAS_PCI_MWI, tulip_timer, tulip_media_task },
+
+ /* DM910X */
+ { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
+- tulip_timer },
++ tulip_timer, tulip_media_task },
+
+ /* RS7112 */
+ { "Conexant LANfinity", 256, 0x0001ebef,
+- HAS_MII | HAS_ACPI, tulip_timer },
++ HAS_MII | HAS_ACPI, tulip_timer, tulip_media_task },
+
+ };
+
+@@ -295,12 +303,14 @@ static void tulip_up(struct net_device *
+
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ iowrite32(0x00000001, ioaddr + CSR0);
++ pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ udelay(100);
+
+ /* Deassert reset.
+ Wait the specified 50 PCI cycles after a reset by initializing
+ Tx and Rx queues and the address filter list. */
+ iowrite32(tp->csr0, ioaddr + CSR0);
++ pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ udelay(100);
+
+ if (tulip_debug > 1)
+@@ -522,20 +532,9 @@ static void tulip_tx_timeout(struct net_
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
+ ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+- if ( ! tp->medialock && tp->mtable) {
+- do
+- --tp->cur_index;
+- while (tp->cur_index >= 0
+- && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media]
+- & MediaIsFD));
+- if (--tp->cur_index < 0) {
+- /* We start again, but should instead look for default. */
+- tp->cur_index = tp->mtable->leafcount - 1;
+- }
+- tulip_select_media(dev, 0);
+- printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+- "media.\n", dev->name, medianame[dev->if_port]);
+- }
++ tp->timeout_recovery = 1;
++ schedule_work(&tp->media_work);
++ goto out_unlock;
+ } else if (tp->chip_id == PNIC2) {
+ printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
+ "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
+@@ -575,14 +574,9 @@ #if defined(way_too_many_messages)
+ }
+ #endif
+
+- /* Stop and restart the chip's Tx processes . */
+-
+- tulip_restart_rxtx(tp);
+- /* Trigger an immediate transmit demand. */
+- iowrite32(0, ioaddr + CSR1);
+-
+- tp->stats.tx_errors++;
++ tulip_tx_timeout_complete(tp, ioaddr);
+
++out_unlock:
+ spin_unlock_irqrestore (&tp->lock, flags);
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+@@ -732,6 +726,8 @@ static void tulip_down (struct net_devic
+ void __iomem *ioaddr = tp->base_addr;
+ unsigned long flags;
+
++ flush_scheduled_work();
++
+ del_timer_sync (&tp->timer);
+ #ifdef CONFIG_TULIP_NAPI
+ del_timer_sync (&tp->oom_timer);
+@@ -740,21 +736,20 @@ #endif
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ iowrite32 (0x00000000, ioaddr + CSR7);
++ ioread32 (ioaddr + CSR7); /* flush posted write */
+
+- /* Stop the Tx and Rx processes. */
+- tulip_stop_rxtx(tp);
++ spin_unlock_irqrestore (&tp->lock, flags);
+
+- /* prepare receive buffers */
+- tulip_refill_rx(dev);
++ free_irq (dev->irq, dev); /* no more races after this */
++ tulip_stop_rxtx(tp); /* Stop DMA */
+
+- /* release any unconsumed transmit buffers */
+- tulip_clean_tx_ring(tp);
++ /* Put driver back into the state we start with */
++ tulip_refill_rx(dev); /* prepare RX buffers */
++ tulip_clean_tx_ring(tp); /* clean up unsent TX buffers */
+
+ if (ioread32 (ioaddr + CSR6) != 0xffffffff)
+ tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff;
+
+- spin_unlock_irqrestore (&tp->lock, flags);
+-
+ init_timer(&tp->timer);
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+@@ -780,7 +775,6 @@ static int tulip_close (struct net_devic
+ printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, ioread32 (ioaddr + CSR5));
+
+- free_irq (dev->irq, dev);
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+@@ -1361,11 +1355,8 @@ #endif
+ if (pci_request_regions (pdev, "tulip"))
+ goto err_out_free_netdev;
+
+-#ifndef USE_IO_OPS
+- ioaddr = pci_iomap(pdev, 1, tulip_tbl[chip_idx].io_size);
+-#else
+- ioaddr = pci_iomap(pdev, 0, tulip_tbl[chip_idx].io_size);
+-#endif
++ ioaddr = pci_iomap(pdev, TULIP_BAR, tulip_tbl[chip_idx].io_size);
++
+ if (!ioaddr)
+ goto err_out_free_res;
+
+@@ -1398,6 +1389,8 @@ #endif
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+
++ INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task, dev);
++
+ dev->base_addr = (unsigned long)ioaddr;
+
+ #ifdef CONFIG_TULIP_MWI
+@@ -1644,8 +1637,14 @@ #endif
+ if (register_netdev(dev))
+ goto err_out_free_ring;
+
+- printk(KERN_INFO "%s: %s rev %d at %p,",
+- dev->name, chip_name, chip_rev, ioaddr);
++ printk(KERN_INFO "%s: %s rev %d at "
++#ifdef CONFIG_TULIP_MMIO
++ "MMIO"
++#else
++ "Port"
++#endif
++ " 0x%lx,", dev->name, chip_name, chip_rev,
++ pci_resource_start(pdev, TULIP_BAR));
+ pci_set_drvdata(pdev, dev);
+
+ if (eeprom_missing)
+@@ -1747,7 +1746,6 @@ static int tulip_suspend (struct pci_dev
+ tulip_down(dev);
+
+ netif_device_detach(dev);
+- free_irq(dev->irq, dev);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
+index eba9083..78e99ab 100644
+--- a/drivers/net/tulip/winbond-840.c
++++ b/drivers/net/tulip/winbond-840.c
+@@ -90,10 +90,8 @@ static int full_duplex[MAX_UNITS] = {-1,
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+-#define TX_RING_SIZE 16
+ #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
+ #define TX_QUEUE_LEN_RESTART 5
+-#define RX_RING_SIZE 32
+
+ #define TX_BUFLIMIT (1024-128)
+
+@@ -137,6 +135,8 @@ #include <asm/processor.h> /* Processor
+ #include <asm/io.h>
+ #include <asm/irq.h>
+
++#include "tulip.h"
++
+ /* These identify the driver base version and may not be removed. */
+ static char version[] =
+ KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker <becker at scyld.com>\n"
+@@ -242,8 +242,8 @@ static const struct pci_id_info pci_id_t
+ };
+
+ /* This driver was written to use PCI memory space, however some x86 systems
+- work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space
+- accesses instead of memory space. */
++ work only with I/O space accesses. See CONFIG_TULIP_MMIO in .config
++*/
+
+ /* Offsets to the Command and Status Registers, "CSRs".
+ While similar to the Tulip, these registers are longword aligned.
+@@ -261,21 +261,11 @@ enum w840_offsets {
+ CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
+ };
+
+-/* Bits in the interrupt status/enable registers. */
+-/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
+-enum intr_status_bits {
+- NormalIntr=0x10000, AbnormalIntr=0x8000,
+- IntrPCIErr=0x2000, TimerInt=0x800,
+- IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
+- TxFIFOUnderflow=0x20, RxErrIntr=0x10,
+- TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
+-};
+-
+ /* Bits in the NetworkConfig register. */
+ enum rx_mode_bits {
+- AcceptErr=0x80, AcceptRunt=0x40,
+- AcceptBroadcast=0x20, AcceptMulticast=0x10,
+- AcceptAllPhys=0x08, AcceptMyPhys=0x02,
++ AcceptErr=0x80,
++ RxAcceptBroadcast=0x20, AcceptMulticast=0x10,
++ RxAcceptAllPhys=0x08, AcceptMyPhys=0x02,
+ };
+
+ enum mii_reg_bits {
+@@ -297,13 +287,6 @@ struct w840_tx_desc {
+ u32 buffer1, buffer2;
+ };
+
+-/* Bits in network_desc.status */
+-enum desc_status_bits {
+- DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
+- DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
+- DescIntr=0x80000000,
+-};
+-
+ #define MII_CNT 1 /* winbond only supports one MII */
+ struct netdev_private {
+ struct w840_rx_desc *rx_ring;
+@@ -371,7 +354,6 @@ static int __devinit w840_probe1 (struct
+ int irq;
+ int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
+ void __iomem *ioaddr;
+- int bar = 1;
+
+ i = pci_enable_device(pdev);
+ if (i) return i;
+@@ -393,10 +375,8 @@ static int __devinit w840_probe1 (struct
+
+ if (pci_request_regions(pdev, DRV_NAME))
+ goto err_out_netdev;
+-#ifdef USE_IO_OPS
+- bar = 0;
+-#endif
+- ioaddr = pci_iomap(pdev, bar, netdev_res_size);
++
++ ioaddr = pci_iomap(pdev, TULIP_BAR, netdev_res_size);
+ if (!ioaddr)
+ goto err_out_free_res;
+
+@@ -838,7 +818,7 @@ static void init_rxtx_rings(struct net_d
+ np->rx_buf_sz,PCI_DMA_FROMDEVICE);
+
+ np->rx_ring[i].buffer1 = np->rx_addr[i];
+- np->rx_ring[i].status = DescOwn;
++ np->rx_ring[i].status = DescOwned;
+ }
+
+ np->cur_rx = 0;
+@@ -923,7 +903,7 @@ #if defined (__i386__) && !defined(MODUL
+ }
+ #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
+ i |= 0xE000;
+-#elif defined(__sparc__)
++#elif defined(__sparc__) || defined (CONFIG_PARISC)
+ i |= 0x4800;
+ #else
+ #warning Processor architecture undefined
+@@ -1043,11 +1023,11 @@ static int start_tx(struct sk_buff *skb,
+
+ /* Now acquire the irq spinlock.
+ * The difficult race is the the ordering between
+- * increasing np->cur_tx and setting DescOwn:
++ * increasing np->cur_tx and setting DescOwned:
+ * - if np->cur_tx is increased first the interrupt
+ * handler could consider the packet as transmitted
+- * since DescOwn is cleared.
+- * - If DescOwn is set first the NIC could report the
++ * since DescOwned is cleared.
++ * - If DescOwned is set first the NIC could report the
+ * packet as sent, but the interrupt handler would ignore it
+ * since the np->cur_tx was not yet increased.
+ */
+@@ -1055,7 +1035,7 @@ static int start_tx(struct sk_buff *skb,
+ np->cur_tx++;
+
+ wmb(); /* flush length, buffer1, buffer2 */
+- np->tx_ring[entry].status = DescOwn;
++ np->tx_ring[entry].status = DescOwned;
+ wmb(); /* flush status and kick the hardware */
+ iowrite32(0, np->base_addr + TxStartDemand);
+ np->tx_q_bytes += skb->len;
+@@ -1155,12 +1135,12 @@ static irqreturn_t intr_handler(int irq,
+
+ handled = 1;
+
+- if (intr_status & (IntrRxDone | RxNoBuf))
++ if (intr_status & (RxIntr | RxNoBuf))
+ netdev_rx(dev);
+ if (intr_status & RxNoBuf)
+ iowrite32(0, ioaddr + RxStartDemand);
+
+- if (intr_status & (TxIdle | IntrTxDone) &&
++ if (intr_status & (TxNoBuf | TxIntr) &&
+ np->cur_tx != np->dirty_tx) {
+ spin_lock(&np->lock);
+ netdev_tx_done(dev);
+@@ -1168,8 +1148,8 @@ static irqreturn_t intr_handler(int irq,
+ }
+
+ /* Abnormal error summary/uncommon events handlers. */
+- if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |
+- TimerInt | IntrTxStopped))
++ if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
++ TimerInt | TxDied))
+ netdev_error(dev, intr_status);
+
+ if (--work_limit < 0) {
+@@ -1305,7 +1285,7 @@ #endif
+ np->rx_ring[entry].buffer1 = np->rx_addr[entry];
+ }
+ wmb();
+- np->rx_ring[entry].status = DescOwn;
++ np->rx_ring[entry].status = DescOwned;
+ }
+
+ return 0;
+@@ -1342,7 +1322,7 @@ #endif
+ dev->name, new);
+ update_csr6(dev, new);
+ }
+- if (intr_status & IntrRxDied) { /* Missed a Rx frame. */
++ if (intr_status & RxDied) { /* Missed a Rx frame. */
+ np->stats.rx_errors++;
+ }
+ if (intr_status & TimerInt) {
+@@ -1381,13 +1361,13 @@ static u32 __set_rx_mode(struct net_devi
+ /* Unconditionally log net taps. */
+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
++ rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys
+ | AcceptMyPhys;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to match, or accept all multicasts. */
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
++ rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ } else {
+ struct dev_mc_list *mclist;
+ int i;
+@@ -1398,7 +1378,7 @@ static u32 __set_rx_mode(struct net_devi
+ filterbit &= 0x3f;
+ mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
+ }
+- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
++ rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ }
+ iowrite32(mc_filter[0], ioaddr + MulticastFilter0);
+ iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
+diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
+index 1fbda77..b0b7799 100644
+--- a/drivers/parisc/iosapic.c
++++ b/drivers/parisc/iosapic.c
+@@ -146,7 +146,7 @@ #ifdef CONFIG_SUPERIO
+ #include <asm/superio.h>
+ #endif
+
+-#include <asm/iosapic.h>
++#include <asm/ropes.h>
+ #include "./iosapic_private.h"
+
+ #define MODULE_NAME "iosapic"
+@@ -686,12 +686,13 @@ #endif
+ * i386/ia64 support ISA devices and have to deal with
+ * edge-triggered interrupts too.
+ */
+-static void iosapic_end_irq(unsigned int irq)
++void iosapic_end_irq(struct irq_desc *dummy, unsigned int irq)
+ {
+ struct vector_info *vi = iosapic_get_vector(irq);
+ DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
+ vi->eoi_addr, vi->eoi_data);
+ iosapic_eoi(vi->eoi_addr, vi->eoi_data);
++ cpu_end_irq(NULL, irq);
+ }
+
+ static unsigned int iosapic_startup_irq(unsigned int irq)
+@@ -728,8 +729,6 @@ static struct hw_interrupt_type iosapic_
+ .shutdown = iosapic_disable_irq,
+ .enable = iosapic_enable_irq,
+ .disable = iosapic_disable_irq,
+- .ack = no_ack_irq,
+- .end = iosapic_end_irq,
+ #ifdef CONFIG_SMP
+ .set_affinity = iosapic_set_affinity_irq,
+ #endif
+@@ -818,6 +817,7 @@ #endif /* CONFIG_SUPERIO */
+ vi->eoi_data = cpu_to_le32(vi->txn_data);
+
+ cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi);
++ set_irq_handler(vi->txn_irq, handle_level_irq_iosapic);
+
+ out:
+ pcidev->irq = vi->txn_irq;
+diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
+index 3fe4a77..ba67699 100644
+--- a/drivers/parisc/lba_pci.c
++++ b/drivers/parisc/lba_pci.c
+@@ -46,9 +46,9 @@ #include <asm/pdcpat.h>
+ #include <asm/page.h>
+ #include <asm/system.h>
+
++#include <asm/ropes.h>
+ #include <asm/hardware.h> /* for register_parisc_driver() stuff */
+ #include <asm/parisc-device.h>
+-#include <asm/iosapic.h> /* for iosapic_register() */
+ #include <asm/io.h> /* read/write stuff */
+
+ #undef DEBUG_LBA /* general stuff */
+@@ -100,113 +100,10 @@ #endif
+
+ #define MODULE_NAME "LBA"
+
+-#define LBA_FUNC_ID 0x0000 /* function id */
+-#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+-#define LBA_CAPABLE 0x0030 /* capabilities register */
+-
+-#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
+-#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
+-
+-#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
+-#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
+-#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
+-
+-#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
+-#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
+-#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
+-#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
+-
+-#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
+-
+-#define LBA_STAT_CTL 0x0108 /* Status & Control */
+-#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
+-#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
+-#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
+-#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
+-
+-#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
+-#define LBA_LMMIO_MASK 0x0208
+-
+-#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
+-#define LBA_GMMIO_MASK 0x0218
+-
+-#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
+-#define LBA_WLMMIO_MASK 0x0228
+-
+-#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
+-#define LBA_WGMMIO_MASK 0x0238
+-
+-#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
+-#define LBA_IOS_MASK 0x0248
+-
+-#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
+-#define LBA_ELMMIO_MASK 0x0258
+-
+-#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
+-#define LBA_EIOS_MASK 0x0268
+-
+-#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
+-#define LBA_DMA_CTL 0x0278 /* firmware sets this */
+-
+-#define LBA_IBASE 0x0300 /* SBA DMA support */
+-#define LBA_IMASK 0x0308
+-
+-/* FIXME: ignore DMA Hint stuff until we can measure performance */
+-#define LBA_HINT_CFG 0x0310
+-#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
+-
+-#define LBA_BUS_MODE 0x0620
+-
+-/* ERROR regs are needed for config cycle kluges */
+-#define LBA_ERROR_CONFIG 0x0680
+-#define LBA_SMART_MODE 0x20
+-#define LBA_ERROR_STATUS 0x0688
+-#define LBA_ROPE_CTL 0x06A0
+-
+-#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
+-
+ /* non-postable I/O port space, densely packed */
+ #define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL)
+ static void __iomem *astro_iop_base __read_mostly;
+
+-#define ELROY_HVERS 0x782
+-#define MERCURY_HVERS 0x783
+-#define QUICKSILVER_HVERS 0x784
+-
+-static inline int IS_ELROY(struct parisc_device *d)
+-{
+- return (d->id.hversion == ELROY_HVERS);
+-}
+-
+-static inline int IS_MERCURY(struct parisc_device *d)
+-{
+- return (d->id.hversion == MERCURY_HVERS);
+-}
+-
+-static inline int IS_QUICKSILVER(struct parisc_device *d)
+-{
+- return (d->id.hversion == QUICKSILVER_HVERS);
+-}
+-
+-
+-/*
+-** lba_device: Per instance Elroy data structure
+-*/
+-struct lba_device {
+- struct pci_hba_data hba;
+-
+- spinlock_t lba_lock;
+- void *iosapic_obj;
+-
+-#ifdef CONFIG_64BIT
+- void __iomem * iop_base; /* PA_VIEW - for IO port accessor funcs */
+-#endif
+-
+- int flags; /* state/functionality enabled */
+- int hw_rev; /* HW revision of chip */
+-};
+-
+-
+ static u32 lba_t32;
+
+ /* lba flags */
+@@ -1542,8 +1439,8 @@ lba_driver_probe(struct parisc_device *d
+ default: version = "TR4+";
+ }
+
+- printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+- MODULE_NAME, version, func_class & 0xf, dev->hpa.start);
++ printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
++ version, func_class & 0xf, dev->hpa.start);
+
+ if (func_class < 2) {
+ printk(KERN_WARNING "Can't support LBA older than "
+@@ -1563,14 +1460,18 @@ #endif
+ }
+
+ } else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
++ int major, minor;
++
+ func_class &= 0xff;
+- version = kmalloc(6, GFP_KERNEL);
+- snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf));
++ major = func_class >> 4, minor = func_class & 0xf;
++
+ /* We could use one printk for both Elroy and Mercury,
+ * but for the mask for func_class.
+ */
+- printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+- MODULE_NAME, version, func_class & 0xff, dev->hpa.start);
++ printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
++ IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
++ minor, func_class, dev->hpa.start);
++
+ cfg_ops = &mercury_cfg_ops;
+ } else {
+ printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
+@@ -1600,6 +1501,7 @@ #endif
+ lba_dev->hba.dev = dev;
+ lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */
+ lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */
++ parisc_set_drvdata(dev, lba_dev);
+
+ /* ------------ Second : initialize common stuff ---------- */
+ pci_bios = &lba_bios_ops;
+diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
+index 8b47328..1b709f6 100644
+--- a/drivers/parisc/sba_iommu.c
++++ b/drivers/parisc/sba_iommu.c
+@@ -38,22 +38,15 @@ #include <asm/hardware.h> /* for registe
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+
++#include <asm/ropes.h>
++#include <asm/mckinley.h> /* for proc_mckinley_root */
+ #include <asm/runway.h> /* for proc_runway_root */
+ #include <asm/pdc.h> /* for PDC_MODEL_* */
+ #include <asm/pdcpat.h> /* for is_pdc_pat() */
+ #include <asm/parisc-device.h>
+
+-
+-/* declared in arch/parisc/kernel/setup.c */
+-extern struct proc_dir_entry * proc_mckinley_root;
+-
+ #define MODULE_NAME "SBA"
+
+-#ifdef CONFIG_PROC_FS
+-/* depends on proc fs support. But costs CPU performance */
+-#undef SBA_COLLECT_STATS
+-#endif
+-
+ /*
+ ** The number of debug flags is a clue - this code is fragile.
+ ** Don't even think about messing with it unless you have
+@@ -92,202 +85,12 @@ #else
+ #define DBG_RES(x...)
+ #endif
+
+-#if defined(CONFIG_64BIT)
+-/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
+-#define ZX1_SUPPORT
+-#endif
+-
+ #define SBA_INLINE __inline__
+
+-
+-/*
+-** The number of pdir entries to "free" before issueing
+-** a read to PCOM register to flush out PCOM writes.
+-** Interacts with allocation granularity (ie 4 or 8 entries
+-** allocated and free'd/purged at a time might make this
+-** less interesting).
+-*/
+-#define DELAYED_RESOURCE_CNT 16
+-
+ #define DEFAULT_DMA_HINT_REG 0
+
+-#define ASTRO_RUNWAY_PORT 0x582
+-#define IKE_MERCED_PORT 0x803
+-#define REO_MERCED_PORT 0x804
+-#define REOG_MERCED_PORT 0x805
+-#define PLUTO_MCKINLEY_PORT 0x880
+-
+-#define SBA_FUNC_ID 0x0000 /* function id */
+-#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+-
+-#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT)
+-#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT)
+-#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT)
+-
+-#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
+-
+-#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
+-#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
+-/* Ike's IOC's occupy functions 2 and 3 */
+-#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
+-
+-#define IOC_CTRL 0x8 /* IOC_CTRL offset */
+-#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
+-#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
+-#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
+-#define IOC_CTRL_RM (1 << 8) /* Real Mode */
+-#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
+-#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
+-#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
+-
+-#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
+-
+-#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
+-
+-
+-/*
+-** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
+-** Firmware programs this stuff. Don't touch it.
+-*/
+-#define LMMIO_DIRECT0_BASE 0x300
+-#define LMMIO_DIRECT0_MASK 0x308
+-#define LMMIO_DIRECT0_ROUTE 0x310
+-
+-#define LMMIO_DIST_BASE 0x360
+-#define LMMIO_DIST_MASK 0x368
+-#define LMMIO_DIST_ROUTE 0x370
+-
+-#define IOS_DIST_BASE 0x390
+-#define IOS_DIST_MASK 0x398
+-#define IOS_DIST_ROUTE 0x3A0
+-
+-#define IOS_DIRECT_BASE 0x3C0
+-#define IOS_DIRECT_MASK 0x3C8
+-#define IOS_DIRECT_ROUTE 0x3D0
+-
+-/*
+-** Offsets into I/O TLB (Function 2 and 3 on Ike)
+-*/
+-#define ROPE0_CTL 0x200 /* "regbus pci0" */
+-#define ROPE1_CTL 0x208
+-#define ROPE2_CTL 0x210
+-#define ROPE3_CTL 0x218
+-#define ROPE4_CTL 0x220
+-#define ROPE5_CTL 0x228
+-#define ROPE6_CTL 0x230
+-#define ROPE7_CTL 0x238
+-
+-#define IOC_ROPE0_CFG 0x500 /* pluto only */
+-#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
+-
+-
+-
+-#define HF_ENABLE 0x40
+-
+-
+-#define IOC_IBASE 0x300 /* IO TLB */
+-#define IOC_IMASK 0x308
+-#define IOC_PCOM 0x310
+-#define IOC_TCNFG 0x318
+-#define IOC_PDIR_BASE 0x320
+-
+-/* AGP GART driver looks for this */
+-#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
+-
+-
+-/*
+-** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+-** It's safer (avoid memory corruption) to keep DMA page mappings
+-** equivalently sized to VM PAGE_SIZE.
+-**
+-** We really can't avoid generating a new mapping for each
+-** page since the Virtual Coherence Index has to be generated
+-** and updated for each page.
+-**
+-** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
+-*/
+-#define IOVP_SIZE PAGE_SIZE
+-#define IOVP_SHIFT PAGE_SHIFT
+-#define IOVP_MASK PAGE_MASK
+-
+-#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
+-#define SBA_PERF_MASK1 0x718
+-#define SBA_PERF_MASK2 0x730
+-
+-
+-/*
+-** Offsets into PCI Performance Counters (functions 12 and 13)
+-** Controlled by PERF registers in function 2 & 3 respectively.
+-*/
+-#define SBA_PERF_CNT1 0x200
+-#define SBA_PERF_CNT2 0x208
+-#define SBA_PERF_CNT3 0x210
+-
+-
+-struct ioc {
+- void __iomem *ioc_hpa; /* I/O MMU base address */
+- char *res_map; /* resource map, bit == pdir entry */
+- u64 *pdir_base; /* physical base address */
+- unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
+- unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
+-#ifdef ZX1_SUPPORT
+- unsigned long iovp_mask; /* help convert IOVA to IOVP */
+-#endif
+- unsigned long *res_hint; /* next avail IOVP - circular search */
+- spinlock_t res_lock;
+- unsigned int res_bitshift; /* from the LEFT! */
+- unsigned int res_size; /* size of resource map in bytes */
+-#ifdef SBA_HINT_SUPPORT
+-/* FIXME : DMA HINTs not used */
+- unsigned long hint_mask_pdir; /* bits used for DMA hints */
+- unsigned int hint_shift_pdir;
+-#endif
+-#if DELAYED_RESOURCE_CNT > 0
+- int saved_cnt;
+- struct sba_dma_pair {
+- dma_addr_t iova;
+- size_t size;
+- } saved[DELAYED_RESOURCE_CNT];
+-#endif
+-
+-#ifdef SBA_COLLECT_STATS
+-#define SBA_SEARCH_SAMPLE 0x100
+- unsigned long avg_search[SBA_SEARCH_SAMPLE];
+- unsigned long avg_idx; /* current index into avg_search */
+- unsigned long used_pages;
+- unsigned long msingle_calls;
+- unsigned long msingle_pages;
+- unsigned long msg_calls;
+- unsigned long msg_pages;
+- unsigned long usingle_calls;
+- unsigned long usingle_pages;
+- unsigned long usg_calls;
+- unsigned long usg_pages;
+-#endif
+-
+- /* STUFF We don't need in performance path */
+- unsigned int pdir_size; /* in bytes, determined by IOV Space size */
+-};
+-
+-struct sba_device {
+- struct sba_device *next; /* list of SBA's in system */
+- struct parisc_device *dev; /* dev found in bus walk */
+- struct parisc_device_id *iodc; /* data about dev from firmware */
+- const char *name;
+- void __iomem *sba_hpa; /* base address */
+- spinlock_t sba_lock;
+- unsigned int flags; /* state/functionality enabled */
+- unsigned int hw_rev; /* HW revision of chip */
+-
+- struct resource chip_resv; /* MMIO reserved for chip */
+- struct resource iommu_resv; /* MMIO reserved for iommu */
+-
+- unsigned int num_ioc; /* number of on-board IOC's */
+- struct ioc ioc[MAX_IOC];
+-};
+-
+-
+-static struct sba_device *sba_list;
++struct sba_device *sba_list;
++EXPORT_SYMBOL_GPL(sba_list);
+
+ static unsigned long ioc_needs_fdc = 0;
+
+@@ -300,8 +103,14 @@ static unsigned long piranha_bad_128k =
+ /* Looks nice and keeps the compiler happy */
+ #define SBA_DEV(d) ((struct sba_device *) (d))
+
++#ifdef CONFIG_AGP_PARISC
++#define SBA_AGP_SUPPORT
++#endif /*CONFIG_AGP_PARISC*/
++
+ #ifdef SBA_AGP_SUPPORT
+-static int reserve_sba_gart = 1;
++static int sba_reserve_agpgart = 1;
++module_param(sba_reserve_agpgart, int, 1);
++MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
+ #endif
+
+ #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
+@@ -741,7 +550,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t
+ asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+ pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */
+
+- pa |= 0x8000000000000000ULL; /* set "valid" bit */
++ pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
+ *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
+
+ /*
+@@ -1498,6 +1307,10 @@ #endif
+ WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
+
+ #ifdef SBA_AGP_SUPPORT
++{
++ struct klist_iter i;
++ struct device *dev = NULL;
++
+ /*
+ ** If an AGP device is present, only use half of the IOV space
+ ** for PCI DMA. Unfortunately we can't know ahead of time
+@@ -1506,20 +1319,22 @@ #ifdef SBA_AGP_SUPPORT
+ ** We program the next pdir index after we stop w/ a key for
+ ** the GART code to handshake on.
+ */
+- device=NULL;
+- for (lba = sba->child; lba; lba = lba->sibling) {
++ klist_iter_init(&sba->dev.klist_children, &i);
++ while (dev = next_device(&i)) {
++ struct parisc_device *lba = to_parisc_device(dev);
+ if (IS_QUICKSILVER(lba))
+- break;
++ agp_found = 1;
+ }
++ klist_iter_exit(&i);
+
+- if (lba) {
+- DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
++ if (agp_found && sba_reserve_agpgart) {
++ printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
++ __FUNCTION__, (iova_space_size/2) >> 20);
+ ioc->pdir_size /= 2;
+- ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
+- } else {
+- DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
++ ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
+ }
+-#endif /* 0 */
++}
++#endif /*SBA_AGP_SUPPORT*/
+
+ }
+
+@@ -1701,7 +1516,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%
+ }
+ #endif
+
+- if (!IS_PLUTO(sba_dev->iodc)) {
++ if (!IS_PLUTO(sba_dev->dev)) {
+ ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
+ DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
+ __FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
+@@ -1718,9 +1533,8 @@ #ifdef DEBUG_SBA_INIT
+ #endif
+ } /* if !PLUTO */
+
+- if (IS_ASTRO(sba_dev->iodc)) {
++ if (IS_ASTRO(sba_dev->dev)) {
+ int err;
+- /* PAT_PDC (L-class) also reports the same goofy base */
+ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
+ num_ioc = 1;
+
+@@ -1730,13 +1544,9 @@ #endif
+ err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
+ BUG_ON(err < 0);
+
+- } else if (IS_PLUTO(sba_dev->iodc)) {
++ } else if (IS_PLUTO(sba_dev->dev)) {
+ int err;
+
+- /* We use a negative value for IOC HPA so it gets
+- * corrected when we add it with IKE's IOC offset.
+- * Doesnt look clean, but fewer code.
+- */
+ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
+ num_ioc = 1;
+
+@@ -1752,14 +1562,14 @@ #endif
+ err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
+ WARN_ON(err < 0);
+ } else {
+- /* IS_IKE (ie N-class, L3000, L1500) */
++ /* IKE, REO */
+ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
+ sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
+ num_ioc = 2;
+
+ /* TODO - LOOKUP Ike/Stretch chipset mem map */
+ }
+- /* XXX: What about Reo? */
++ /* XXX: What about Reo Grande? */
+
+ sba_dev->num_ioc = num_ioc;
+ for (i = 0; i < num_ioc; i++) {
+@@ -1774,7 +1584,7 @@ #endif
+ * Overrides bit 1 in DMA Hint Sets.
+ * Improves netperf UDP_STREAM by ~10% for bcm5701.
+ */
+- if (IS_PLUTO(sba_dev->iodc)) {
++ if (IS_PLUTO(sba_dev->dev)) {
+ void __iomem *rope_cfg;
+ unsigned long cfg_val;
+
+@@ -1803,7 +1613,7 @@ #endif
+ READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
+ );
+
+- if (IS_PLUTO(sba_dev->iodc)) {
++ if (IS_PLUTO(sba_dev->dev)) {
+ sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
+ } else {
+ sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
+@@ -2067,7 +1877,7 @@ sba_driver_callback(struct parisc_device
+ /* Read HW Rev First */
+ func_class = READ_REG(sba_addr + SBA_FCLASS);
+
+- if (IS_ASTRO(&dev->id)) {
++ if (IS_ASTRO(dev)) {
+ unsigned long fclass;
+ static char astro_rev[]="Astro ?.?";
+
+@@ -2078,11 +1888,11 @@ sba_driver_callback(struct parisc_device
+ astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
+ version = astro_rev;
+
+- } else if (IS_IKE(&dev->id)) {
++ } else if (IS_IKE(dev)) {
+ static char ike_rev[] = "Ike rev ?";
+ ike_rev[8] = '0' + (char) (func_class & 0xff);
+ version = ike_rev;
+- } else if (IS_PLUTO(&dev->id)) {
++ } else if (IS_PLUTO(dev)) {
+ static char pluto_rev[]="Pluto ?.?";
+ pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4);
+ pluto_rev[8] = '0' + (char) (func_class & 0x0f);
+@@ -2097,7 +1907,7 @@ sba_driver_callback(struct parisc_device
+ global_ioc_cnt = count_parisc_driver(&sba_driver);
+
+ /* Astro and Pluto have one IOC per SBA */
+- if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id)))
++ if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))
+ global_ioc_cnt *= 2;
+ }
+
+@@ -2117,7 +1927,6 @@ sba_driver_callback(struct parisc_device
+
+ sba_dev->dev = dev;
+ sba_dev->hw_rev = func_class;
+- sba_dev->iodc = &dev->id;
+ sba_dev->name = dev->name;
+ sba_dev->sba_hpa = sba_addr;
+
+diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
+index 657a3ab..dcfba12 100644
+--- a/drivers/scsi/53c700.c
++++ b/drivers/scsi/53c700.c
+@@ -294,6 +294,7 @@ NCR_700_detect(struct scsi_host_template
+ __u8 *memory;
+ __u32 *script;
+ struct Scsi_Host *host;
++ const char *chipname;
+ static int banner = 0;
+ int j;
+
+@@ -392,11 +393,11 @@ NCR_700_detect(struct scsi_host_template
+ printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley at HansenPartnership.com\n");
+ banner = 1;
+ }
++ chipname = hostdata->chip710 ? "53c710" : \
++ (hostdata->fast ? "53c700-66" : "53c700");
+ printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no,
+- hostdata->chip710 ? "53c710" :
+- (hostdata->fast ? "53c700-66" : "53c700"),
+- hostdata->rev, hostdata->differential ?
+- "(Differential)" : "");
++ chipname, hostdata->rev,
++ hostdata->differential ? "(Differential)" : "");
+ /* reset the chip */
+ NCR_700_chip_reset(host);
+
+diff --git a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl
+index 7d651d9..d8847ec 100644
+--- a/drivers/scsi/script_asm.pl
++++ b/drivers/scsi/script_asm.pl
+@@ -156,11 +156,11 @@ # Parsing regular expressions
+ $hexnum = '0[xX][0-9A-Fa-f]+';
+ $constant = "$hexnum|$decnum";
+
+-# yucky - since we can't control grouping of # $constant, we need to
++# yucky - since we can't control grouping of $constant, we need to
+ # expand out each alternative for $value.
+
+-$value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
+- "$identifier\\s*[+-]\s*$hexnum|$constant";
++$value = "$identifier\\s*[+-]\\s*$decnum|$identifier\\s*[+-]\s*$hexnum|".
++ "$identifier\\s*[+-]\\s*$identifier|$identifier|$constant";
+
+ print STDERR "value regex = $value\n" if ($debug);
+
+@@ -490,7 +490,12 @@ print STDERR "Parsing MOVE FROM $transfe
+ $address += 2;
+ } elsif ($rest =~ /^MEMORY\s+(.*)/i) {
+ $rest = $1;
+- $code[$address] = 0xc0_00_00_00;
++ if ($rest =~ /^NO\s*FLUSH\s+(.*)/i) {
++ $rest = $1;
++ $code[$address] = 0xc1_00_00_00;
++ } else {
++ $code[$address] = 0xc0_00_00_00;
++ }
+ if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
+ $count = $1;
+ $source = $2;
+@@ -715,7 +720,7 @@ # with this syntax to set target mode.
+ } else {
+ $code[$address] = 0x98_00_00_00;
+ }
+-print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
++print STDERR "parsing $instruction, rest = $rest\n" if ($debug);
+
+ # Relative jump.
+ if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) {
+@@ -743,7 +748,7 @@ # Absolute jump, requires no more gunk
+ } else {
+ die
+ "$0 : syntax error in line $lineno : $_
+- expected , <conditional> or end of line, got $1
++ expected , <conditional> or end of line, got $rest
+ ";
+ }
+
+diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
+index 739d3ef..52abce4 100644
+--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
++++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
+@@ -204,13 +204,6 @@ void sym_xpt_done(struct sym_hcb *np, st
+ cmd->scsi_done(cmd);
+ }
+
+-static void sym_xpt_done2(struct sym_hcb *np, struct scsi_cmnd *cmd, int cam_status)
+-{
+- sym_set_cam_status(cmd, cam_status);
+- sym_xpt_done(np, cmd);
+-}
+-
+-
+ /*
+ * Tell the SCSI layer about a BUS RESET.
+ */
+@@ -415,10 +408,8 @@ static int sym_queue_command(struct sym_
+ * Minimal checkings, so that we will not
+ * go outside our tables.
+ */
+- if (sdev->id == np->myaddr) {
+- sym_xpt_done2(np, cmd, DID_NO_CONNECT);
+- return 0;
+- }
++ if (sdev->id == np->myaddr)
++ goto nodev;
+
+ /*
+ * Retrieve the target descriptor.
+@@ -439,6 +430,11 @@ static int sym_queue_command(struct sym_
+ return 1; /* Means resource shortage */
+ sym_queue_scsiio(np, cmd, cp);
+ return 0;
++
++ nodev:
++ cmd->result = DID_NO_CONNECT << 16;
++ cmd->scsi_done(cmd);
++ return 0;
+ }
+
+ /*
+@@ -1349,7 +1345,7 @@ static int sym_host_info(struct sym_hcb
+ "revision id 0x%x\n",
+ np->s.chip_name, np->device_id, np->revision_id);
+ copy_info(&info, "At PCI address %s, IRQ " IRQ_FMT "\n",
+- pci_name(np->s.device), IRQ_PRM(np->s.irq));
++ pci_name(np->s.device), IRQ_PRM(np->s.device->irq));
+ copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n",
+ (int) (np->minsync_dt ? np->minsync_dt : np->minsync),
+ np->maxwide ? "Wide" : "Narrow",
+@@ -1402,8 +1398,8 @@ static void sym_free_resources(struct sy
+ /*
+ * Free O/S specific resources.
+ */
+- if (np->s.irq)
+- free_irq(np->s.irq, np);
++ if (pdev->irq)
++ free_irq(pdev->irq, np);
+ if (np->s.ioaddr)
+ pci_iounmap(pdev, np->s.ioaddr);
+ if (np->s.ramaddr)
+@@ -1552,7 +1548,6 @@ static struct Scsi_Host * __devinit sym_
+ sym_name(np), pdev->irq);
+ goto attach_failed;
+ }
+- np->s.irq = pdev->irq;
+
+ /*
+ * After SCSI devices have been opened, we cannot
+@@ -1592,6 +1587,10 @@ static struct Scsi_Host * __devinit sym_
+ BUG_ON(sym2_transport_template == NULL);
+ instance->transportt = sym2_transport_template;
+
++ /* 53c896 rev 1 errata: DMA may not cross 16MB boundary */
++ if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && np->revision_id < 2)
++ instance->dma_boundary = 0xFFFFFF;
++
+ spin_unlock_irqrestore(instance->host_lock, flags);
+
+ return instance;
+diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
+index e022d3c..d4d98ae 100644
+--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
++++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
+@@ -184,7 +184,6 @@ struct sym_shcb {
+ void __iomem * ioaddr; /* MMIO kernel io address */
+ void __iomem * ramaddr; /* RAM kernel io address */
+ u_short io_ws; /* IO window size */
+- int irq; /* IRQ number */
+
+ struct timer_list timer; /* Timer handler link header */
+ u_long lasttime;
+diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
+index 913c71c..4d65fb7 100644
+--- a/drivers/serial/8250_gsc.c
++++ b/drivers/serial/8250_gsc.c
+@@ -22,7 +22,6 @@ #include <linux/types.h>
+ #include <asm/hardware.h>
+ #include <asm/parisc-device.h>
+ #include <asm/io.h>
+-#include <asm/serial.h> /* for LASI_BASE_BAUD */
+
+ #include "8250.h"
+
+@@ -54,7 +53,8 @@ serial_init_chip(struct parisc_device *d
+
+ memset(&port, 0, sizeof(port));
+ port.iotype = UPIO_MEM;
+- port.uartclk = LASI_BASE_BAUD * 16;
++ /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
++ port.uartclk = 7272727;
+ port.mapbase = address;
+ port.membase = ioremap_nocache(address, 16);
+ port.irq = dev->irq;
+diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
+index 5b48ac2..1c1994f 100644
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -556,10 +556,11 @@ config SERIAL_MUX
+ default y
+ ---help---
+ Saying Y here will enable the hardware MUX serial driver for
+- the Nova and K class systems. The hardware MUX is not 8250/16550
+- compatible therefore the /dev/ttyB0 device is shared between the
+- Serial MUX and the PDC software console. The following steps
+- need to be completed to use the Serial MUX:
++ the Nova, K class systems and D class with a 'remote control card'.
++ The hardware MUX is not 8250/16550 compatible therefore the
++ /dev/ttyB0 device is shared between the Serial MUX and the PDC
++ software console. The following steps need to be completed to use
++ the Serial MUX:
+
+ 1. create the device entry (mknod /dev/ttyB0 c 11 0)
+ 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
+index 372e47f..9bc49c9 100644
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -2023,6 +2023,7 @@ static inline void
+ uart_report_port(struct uart_driver *drv, struct uart_port *port)
+ {
+ char address[64];
++ char irq[16];
+
+ switch (port->iotype) {
+ case UPIO_PORT:
+@@ -2045,10 +2046,19 @@ uart_report_port(struct uart_driver *drv
+ break;
+ }
+
+- printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
++#ifndef NO_IRQ
++#define NO_IRQ (-1)
++#endif
++ if (port->irq == NO_IRQ) {
++ strlcpy(irq, "polled", sizeof(irq));
++ } else {
++ snprintf(irq, sizeof(irq), "irq = %d", port->irq);
++ }
++
++ printk(KERN_INFO "%s%s%s%d at %s (%s) is a %s\n",
+ port->dev ? port->dev->bus_id : "",
+ port->dev ? ": " : "",
+- drv->dev_name, port->line, address, port->irq, uart_type(port));
++ drv->dev_name, port->line, address, irq, uart_type(port));
+ }
+
+ static void
+diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
+index a2c56b2..26e33c7 100644
+--- a/drivers/usb/input/hid-core.c
++++ b/drivers/usb/input/hid-core.c
+@@ -752,21 +752,31 @@ static __inline__ __u32 s32ton(__s32 val
+ }
+
+ /*
+- * Extract/implement a data field from/to a report.
++ * Extract/implement a data field from/to a little endian report (bit array).
+ */
+
+ 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) & ((1ULL << n) - 1);
++ u32 x;
++
++ report += offset >> 3; /* adjust byte index */
++ offset &= 8 - 1;
++ x = get_unaligned((u32 *) report);
++ x = le32_to_cpu(x);
++ x = (x >> offset) & ((1 << n) - 1);
++ return x;
+ }
+
+ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+ {
+- report += (offset >> 5) << 2; offset &= 31;
+- put_unaligned((get_unaligned((__le64*)report)
+- & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))
+- | cpu_to_le64((__u64)value << offset), (__le64*)report);
++ u32 x;
++
++ report += offset >> 3;
++ offset &= 8 - 1;
++ x = get_unaligned((u32 *)report);
++ x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset));
++ x |= cpu_to_le32(value << offset);
++ put_unaligned(x,(u32 *)report);
+ }
+
+ /*
+diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
+index 32b5d62..5bcdaaf 100644
+--- a/fs/binfmt_som.c
++++ b/fs/binfmt_som.c
+@@ -29,6 +29,7 @@ #include <linux/shm.h>
+ #include <linux/personality.h>
+ #include <linux/init.h>
+
++#include <asm/a.out.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+
+@@ -194,6 +195,7 @@ load_som_binary(struct linux_binprm * bp
+ unsigned long som_entry;
+ struct som_hdr *som_ex;
+ struct som_exec_auxhdr *hpuxhdr;
++ struct files_struct *files;
+
+ /* Get the exec-header */
+ som_ex = (struct som_hdr *) bprm->buf;
+@@ -208,15 +210,27 @@ load_som_binary(struct linux_binprm * bp
+ size = som_ex->aux_header_size;
+ if (size > SOM_PAGESIZE)
+ goto out;
+- hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL);
++ hpuxhdr = kmalloc(size, GFP_KERNEL);
+ if (!hpuxhdr)
+ goto out;
+
+ retval = kernel_read(bprm->file, som_ex->aux_header_location,
+ (char *) hpuxhdr, size);
++ if (retval != size) {
++ if (retval >= 0)
++ retval = -EIO;
++ goto out_free;
++ }
++
++ files = current->files; /* Refcounted so ok */
++ retval = unshare_files();
+ if (retval < 0)
+ goto out_free;
+-#error "Fix security hole before enabling me"
++ if (files == current->files) {
++ put_files_struct(files);
++ files = NULL;
++ }
++
+ retval = get_unused_fd();
+ if (retval < 0)
+ goto out_free;
+diff --git a/include/asm-generic/compat_signal.h b/include/asm-generic/compat_signal.h
+new file mode 100644
+index 0000000..889d57f
+--- /dev/null
++++ b/include/asm-generic/compat_signal.h
+@@ -0,0 +1,25 @@
++#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H
++#define _ASM_GENERIC_COMPAT_SIGNAL_H
++
++#ifndef __ASSEMBLY__
++#include <linux/compat.h>
++
++typedef compat_uptr_t compat_sighandler_t;
++
++typedef struct compat_sigaltstack {
++ compat_uptr_t ss_sp;
++ compat_int_t ss_flags;
++ compat_size_t ss_size;
++} compat_stack_t;
++
++/* Most things should be clean enough to redefine this at will, if care
++ is taken to make libc match. */
++
++struct compat_sigaction {
++ compat_sighandler_t sa_handler;
++ compat_uint_t sa_flags;
++ compat_sigset_t sa_mask; /* mask last for extensibility */
++};
++
++#endif /* !__ASSEMBLY__ */
++#endif /* !_ASM_GENERIC_COMPAT_SIGNAL_H */
+diff --git a/include/asm-parisc/agp.h b/include/asm-parisc/agp.h
+new file mode 100644
+index 0000000..9f61d4e
+--- /dev/null
++++ b/include/asm-parisc/agp.h
+@@ -0,0 +1,25 @@
++#ifndef _ASM_PARISC_AGP_H
++#define _ASM_PARISC_AGP_H
++
++/*
++ * PARISC specific AGP definitions.
++ * Copyright (c) 2006 Kyle McMartin <kyle at parisc-linux.org>
++ *
++ */
++
++#define map_page_into_agp(page) /* nothing */
++#define unmap_page_from_agp(page) /* nothing */
++#define flush_agp_mappings() /* nothing */
++#define flush_agp_cache() mb()
++
++/* Convert a physical address to an address suitable for the GART. */
++#define phys_to_gart(x) (x)
++#define gart_to_phys(x) (x)
++
++/* GATT allocation. Returns/accepts GATT kernel virtual address. */
++#define alloc_gatt_pages(order) \
++ ((char *)__get_free_pages(GFP_KERNEL, (order)))
++#define free_gatt_pages(table, order) \
++ free_pages((unsigned long)(table), (order))
++
++#endif /* _ASM_PARISC_AGP_H */
+diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
+index 1a7bfe6..5a1e0e8 100644
+--- a/include/asm-parisc/assembly.h
++++ b/include/asm-parisc/assembly.h
+@@ -29,7 +29,8 @@ #define STREG std
+ #define LDREGX ldd,s
+ #define LDREGM ldd,mb
+ #define STREGM std,ma
+-#define SHRREG shrd
++#define SHRREG shrd
++#define SHLREG shld
+ #define RP_OFFSET 16
+ #define FRAME_SIZE 128
+ #define CALLEE_REG_FRAME_SIZE 144
+@@ -39,7 +40,8 @@ #define STREG stw
+ #define LDREGX ldwx,s
+ #define LDREGM ldwm
+ #define STREGM stwm
+-#define SHRREG shr
++#define SHRREG shr
++#define SHLREG shlw
+ #define RP_OFFSET 20
+ #define FRAME_SIZE 64
+ #define CALLEE_REG_FRAME_SIZE 128
+diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
+index 0b459cd..2bc41f2 100644
+--- a/include/asm-parisc/cacheflush.h
++++ b/include/asm-parisc/cacheflush.h
+@@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsig
+ }
+ #define ARCH_HAS_FLUSH_ANON_PAGE
+
+-static inline void
+-flush_kernel_dcache_page(struct page *page)
++#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
++void flush_kernel_dcache_page_addr(void *addr);
++static inline void flush_kernel_dcache_page(struct page *page)
+ {
+- flush_kernel_dcache_page_asm(page_address(page));
++ flush_kernel_dcache_page_addr(page_address(page));
+ }
+-#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+
+ #ifdef CONFIG_DEBUG_RODATA
+ void mark_rodata_ro(void);
+ #endif
+
++#ifdef CONFIG_PA8X00
++/* Only pa8800, pa8900 needs this */
++#define ARCH_HAS_KMAP
++
++void kunmap_parisc(void *addr);
++
++static inline void *kmap(struct page *page)
++{
++ might_sleep();
++ return page_address(page);
++}
++
++#define kunmap(page) kunmap_parisc(page_address(page))
++
++#define kmap_atomic(page, idx) page_address(page)
++
++#define kunmap_atomic(addr, idx) kunmap_parisc(addr)
++
++#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn))
++#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
++#endif
++
+ #endif /* _PARISC_CACHEFLUSH_H */
+
+diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
+index 71b4eee..d834058 100644
+--- a/include/asm-parisc/compat.h
++++ b/include/asm-parisc/compat.h
+@@ -5,7 +5,7 @@ #define _ASM_PARISC_COMPAT_H
+ */
+ #include <linux/types.h>
+ #include <linux/sched.h>
+-#include <linux/personality.h>
++#include <linux/thread_info.h>
+
+ #define COMPAT_USER_HZ 100
+
+@@ -150,9 +150,10 @@ static __inline__ void __user *compat_al
+ return (void __user *)regs->gr[30];
+ }
+
++#define HAVE_ARCH_IS_COMPAT_TASK
+ static inline int __is_compat_task(struct task_struct *t)
+ {
+- return personality(t->personality) == PER_LINUX32;
++ return test_ti_thread_flag(t->thread_info, TIF_32BIT);
+ }
+
+ static inline int is_compat_task(void)
+diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h
+index 9979c3c..da2cf37 100644
+--- a/include/asm-parisc/dma.h
++++ b/include/asm-parisc/dma.h
+@@ -72,18 +72,13 @@ #define DMA2_CLR_MASK_REG 0xDC
+ #define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
+ #define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG)
+
+-extern spinlock_t dma_spin_lock;
+-
+ static __inline__ unsigned long claim_dma_lock(void)
+ {
+- unsigned long flags;
+- spin_lock_irqsave(&dma_spin_lock, flags);
+- return flags;
++ return 0;
+ }
+
+ static __inline__ void release_dma_lock(unsigned long flags)
+ {
+- spin_unlock_irqrestore(&dma_spin_lock, flags);
+ }
+
+
+diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
+index 6a332a9..d84bbb2 100644
+--- a/include/asm-parisc/futex.h
++++ b/include/asm-parisc/futex.h
+@@ -1,6 +1,71 @@
+-#ifndef _ASM_FUTEX_H
+-#define _ASM_FUTEX_H
++#ifndef _ASM_PARISC_FUTEX_H
++#define _ASM_PARISC_FUTEX_H
+
+-#include <asm-generic/futex.h>
++#ifdef __KERNEL__
+
++#include <linux/futex.h>
++#include <asm/errno.h>
++#include <asm/uaccess.h>
++
++static inline int
++futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
++{
++ int op = (encoded_op >> 28) & 7;
++ int cmp = (encoded_op >> 24) & 15;
++ int oparg = (encoded_op << 8) >> 20;
++ int cmparg = (encoded_op << 20) >> 20;
++ int oldval = 0, ret;
++ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
++ oparg = 1 << oparg;
++
++ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
++ return -EFAULT;
++
++ inc_preempt_count();
++
++ switch (op) {
++ case FUTEX_OP_SET:
++ case FUTEX_OP_ADD:
++ case FUTEX_OP_OR:
++ case FUTEX_OP_ANDN:
++ case FUTEX_OP_XOR:
++ default:
++ ret = -ENOSYS;
++ }
++
++ dec_preempt_count();
++
++ if (!ret) {
++ switch (cmp) {
++ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
++ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
++ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
++ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
++ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
++ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
++ default: ret = -ENOSYS;
++ }
++ }
++ return ret;
++}
++
++/* Non-atomic version */
++static inline int
++futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
++{
++ int err = 0;
++ int uval;
++
++ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
++ return -EFAULT;
++
++ err = get_user(uval, uaddr);
++ if (err) return -EFAULT;
++ if (uval == oldval)
++ err = put_user(newval, uaddr);
++ if (err) return -EFAULT;
++ return uval;
++}
++
++#endif
+ #endif
+diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
+index b9eb245..c1963ce 100644
+--- a/include/asm-parisc/io.h
++++ b/include/asm-parisc/io.h
+@@ -134,7 +134,7 @@ extern inline void __iomem * ioremap(uns
+ }
+ #define ioremap_nocache(off, sz) ioremap((off), (sz))
+
+-extern void iounmap(void __iomem *addr);
++extern void iounmap(const volatile void __iomem *addr);
+
+ static inline unsigned char __raw_readb(const volatile void __iomem *addr)
+ {
+diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h
+deleted file mode 100644
+index 613390e..0000000
+--- a/include/asm-parisc/iosapic.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*
+-** This file is private to iosapic driver.
+-** If stuff needs to be used by another driver, move it to a common file.
+-**
+-** WARNING: fields most data structures here are ordered to make sure
+-** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
+-*/
+-
+-
+-/*
+-** I/O SAPIC init function
+-** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
+-** Call setup as part of per instance initialization.
+-** (ie *not* init_module() function unless only one is present.)
+-** fixup_irq is to initialize PCI IRQ line support and
+-** virtualize pcidev->irq value. To be called by pci_fixup_bus().
+-*/
+-extern void *iosapic_register(unsigned long hpa);
+-extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
+-
+-
+-#ifdef __IA64__
+-/*
+-** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter.
+-** and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field.
+-**
+-** IA64: PIB is handled by "Local SAPIC" (integrated in the processor).
+-*/
+-struct local_sapic_info {
+- struct local_sapic_info *lsi_next; /* point to next CPU info */
+- int *lsi_cpu_id; /* point to logical CPU id */
+- unsigned long *lsi_id_eid; /* point to IA-64 CPU id */
+- int *lsi_status; /* point to CPU status */
+- void *lsi_private; /* point to special info */
+-};
+-
+-/*
+-** "root" data structure which ties everything together.
+-** Should always be able to start with sapic_root and locate
+-** the desired information.
+-*/
+-struct sapic_info {
+- struct sapic_info *si_next; /* info is per cell */
+- int si_cellid; /* cell id */
+- unsigned int si_status; /* status */
+- char *si_pib_base; /* intr blk base address */
+- local_sapic_info_t *si_local_info;
+- io_sapic_info_t *si_io_info;
+- extint_info_t *si_extint_info;/* External Intr info */
+-};
+-
+-#endif /* IA64 */
+-
+diff --git a/include/asm-parisc/irq-handlers.h b/include/asm-parisc/irq-handlers.h
+new file mode 100644
+index 0000000..95a9d1b
+--- /dev/null
++++ b/include/asm-parisc/irq-handlers.h
+@@ -0,0 +1,15 @@
++HANDLE_LEVEL_IRQ(_chip, cpu_ack_irq, cpu_end_irq)
++HANDLE_SPECIFIC_IRQ(_timer, cpu_ack_irq, cpu_end_irq, timer_interrupt)
++#ifdef CONFIG_SMP
++HANDLE_SPECIFIC_IRQ(_ipi, cpu_ack_irq, cpu_end_irq, ipi_interrupt)
++#endif
++#ifdef CONFIG_IOSAPIC
++HANDLE_LEVEL_IRQ(_iosapic, cpu_ack_irq, iosapic_end_irq)
++#endif
++
++static inline char *arch_handle_irq_name(void fastcall (*handle)(unsigned int,
++ struct irq_desc *,
++ struct pt_regs *))
++{
++ return NULL;
++}
+diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
+index 5cae260..0bdcab3 100644
+--- a/include/asm-parisc/irq.h
++++ b/include/asm-parisc/irq.h
+@@ -8,6 +8,7 @@ #ifndef _ASM_PARISC_IRQ_H
+ #define _ASM_PARISC_IRQ_H
+
+ #include <linux/cpumask.h>
++#include <linux/irqreturn.h>
+ #include <asm/types.h>
+
+ #define NO_IRQ (-1)
+@@ -26,12 +27,28 @@ #define CPU_IRQ_MAX (CPU_IRQ_BASE + (BIT
+
+ #define NR_IRQS (CPU_IRQ_MAX + 1)
+
++#define ARCH_HAS_IRQ_HANDLERS
++
++struct irq_desc;
++
++void fastcall handle_level_irq_chip(unsigned int irq, struct irq_desc *desc,
++ struct pt_regs *regs);
++void fastcall handle_level_irq_iosapic(unsigned int irq, struct irq_desc *desc,
++ struct pt_regs *regs);
++void fastcall handle_percpu_irq_chip(unsigned int irq, struct irq_desc *desc,
++ struct pt_regs *regs);
++void fastcall handle_specific_irq_timer(unsigned int irq,
++ struct irq_desc *desc,
++ struct pt_regs *regs);
++void fastcall handle_specific_irq_ipi(unsigned int irq, struct irq_desc *desc,
++ struct pt_regs *regs);
++
+ static __inline__ int irq_canonicalize(int irq)
+ {
+ return (irq == 2) ? 9 : irq;
+ }
+
+-struct hw_interrupt_type;
++struct irq_chip;
+
+ /*
+ * Some useful "we don't have to do anything here" handlers. Should
+@@ -39,6 +56,9 @@ struct hw_interrupt_type;
+ */
+ void no_ack_irq(unsigned int irq);
+ void no_end_irq(unsigned int irq);
++void cpu_ack_irq(struct irq_desc *, unsigned int irq);
++void cpu_end_irq(struct irq_desc *, unsigned int irq);
++void iosapic_end_irq(struct irq_desc *, unsigned int irq);
+
+ extern int txn_alloc_irq(unsigned int nbits);
+ extern int txn_claim_irq(int);
+@@ -46,9 +66,13 @@ extern unsigned int txn_alloc_data(unsig
+ extern unsigned long txn_alloc_addr(unsigned int);
+ extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
+
+-extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
++extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
+ extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest);
+
++/* Prototypes for the two directly called interrupts */
++extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
++extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
++
+ /* soft power switch support (power.c) */
+ extern struct tasklet_struct power_tasklet;
+
+diff --git a/include/asm-parisc/mckinley.h b/include/asm-parisc/mckinley.h
+new file mode 100644
+index 0000000..d1ea6f1
+--- /dev/null
++++ b/include/asm-parisc/mckinley.h
+@@ -0,0 +1,9 @@
++#ifndef ASM_PARISC_MCKINLEY_H
++#define ASM_PARISC_MCKINLEY_H
++#ifdef __KERNEL__
++
++/* declared in arch/parisc/kernel/setup.c */
++extern struct proc_dir_entry * proc_mckinley_root;
++
++#endif /*__KERNEL__*/
++#endif /*ASM_PARISC_MCKINLEY_H*/
+diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
+index 57d6d82..3567208 100644
+--- a/include/asm-parisc/page.h
++++ b/include/asm-parisc/page.h
+@@ -26,24 +26,10 @@ #define copy_page(to,from) copy_use
+
+ struct page;
+
+-extern void purge_kernel_dcache_page(unsigned long);
+-extern void copy_user_page_asm(void *to, void *from);
+-extern void clear_user_page_asm(void *page, unsigned long vaddr);
+-
+-static inline void
+-copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
+-{
+- copy_user_page_asm(vto, vfrom);
+- flush_kernel_dcache_page_asm(vto);
+- /* XXX: ppc flushes icache too, should we? */
+-}
+-
+-static inline void
+-clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+-{
+- purge_kernel_dcache_page((unsigned long)page);
+- clear_user_page_asm(page, vaddr);
+-}
++void copy_user_page_asm(void *to, void *from);
++void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
++ struct page *pg);
++void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+
+ /*
+ * These are used to make use of C type-checking..
+diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h
+index 07cb9b9..32e03d8 100644
+--- a/include/asm-parisc/param.h
++++ b/include/asm-parisc/param.h
+@@ -2,13 +2,9 @@ #ifndef _ASMPARISC_PARAM_H
+ #define _ASMPARISC_PARAM_H
+
+ #ifdef __KERNEL__
+-# ifdef CONFIG_PA20
+-# define HZ 1000 /* Faster machines */
+-# else
+-# define HZ 100 /* Internal kernel timer frequency */
+-# endif
+-# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
+-# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
++#define HZ CONFIG_HZ
++#define USER_HZ 100 /* some user API use "ticks" */
++#define CLOCKS_PER_SEC (USER_HZ) /* like times() */
+ #endif
+
+ #ifndef HZ
+diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h
+index 1d247e3..e12624d 100644
+--- a/include/asm-parisc/parisc-device.h
++++ b/include/asm-parisc/parisc-device.h
+@@ -1,3 +1,6 @@
++#ifndef _ASM_PARISC_PARISC_DEVICE_H_
++#define _ASM_PARISC_PARISC_DEVICE_H_
++
+ #include <linux/device.h>
+
+ struct parisc_device {
+@@ -57,3 +60,5 @@ parisc_get_drvdata(struct parisc_device
+ }
+
+ extern struct bus_type parisc_bus_type;
++
++#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
+diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
+index 8b631f4..7b8ad11 100644
+--- a/include/asm-parisc/pci.h
++++ b/include/asm-parisc/pci.h
+@@ -293,4 +293,9 @@ static inline void pcibios_penalize_isa_
+ /* We don't need to penalize isa irq's */
+ }
+
++static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
++{
++ return channel ? 15 : 14;
++}
++
+ #endif /* __ASM_PARISC_PCI_H */
+diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h
+new file mode 100644
+index 0000000..5d02172
+--- /dev/null
++++ b/include/asm-parisc/prefetch.h
+@@ -0,0 +1,39 @@
++/*
++ * include/asm-parisc/prefetch.h
++ *
++ * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
++ * In addition, many implementations do hardware prefetching of both
++ * instructions and data.
++ *
++ * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
++ * to gr0 but not in a way that Linux can use. If the load would cause an
++ * interruption (eg due to prefetching 0), it is suppressed on PA2.0
++ * processors, but not on 7300LC.
++ *
++ */
++
++#ifndef __ASM_PARISC_PREFETCH_H
++#define __ASM_PARISC_PREFETCH_H
++
++#ifndef __ASSEMBLY__
++#ifdef CONFIG_PREFETCH
++
++#define ARCH_HAS_PREFETCH
++extern inline void prefetch(const void *addr)
++{
++ __asm__("ldw 0(%0), %%r0" : : "r" (addr));
++}
++
++/* LDD is a PA2.0 addition. */
++#ifdef CONFIG_PA20
++#define ARCH_HAS_PREFETCHW
++extern inline void prefetchw(const void *addr)
++{
++ __asm__("ldd 0(%0), %%r0" : : "r" (addr));
++}
++#endif /* CONFIG_PA20 */
++
++#endif /* CONFIG_PREFETCH */
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_PARISC_PROCESSOR_H */
+diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
+index b73626f..fd7866d 100644
+--- a/include/asm-parisc/processor.h
++++ b/include/asm-parisc/processor.h
+@@ -9,6 +9,8 @@ #ifndef __ASM_PARISC_PROCESSOR_H
+ #define __ASM_PARISC_PROCESSOR_H
+
+ #ifndef __ASSEMBLY__
++#include <asm/prefetch.h> /* lockdep.h needs <linux/prefetch.h> */
++
+ #include <linux/threads.h>
+ #include <linux/spinlock_types.h>
+
+@@ -276,7 +278,7 @@ on downward growing arches, it looks lik
+ */
+
+ #ifdef __LP64__
+-#define USER_WIDE_MODE (personality(current->personality) == PER_LINUX)
++#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT))
+ #else
+ #define USER_WIDE_MODE 0
+ #endif
+@@ -328,33 +330,20 @@ extern unsigned long get_wchan(struct ta
+ #define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
+ #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
+
++#define cpu_relax() barrier()
+
+-/*
+- * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
+- * In addition, many implementations do hardware prefetching of both
+- * instructions and data.
+- *
+- * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
+- * to gr0 but not in a way that Linux can use. If the load would cause an
+- * interruption (eg due to prefetching 0), it is suppressed on PA2.0
+- * processors, but not on 7300LC.
+- */
+-#ifdef CONFIG_PREFETCH
+-#define ARCH_HAS_PREFETCH
+-#define ARCH_HAS_PREFETCHW
+-
+-extern inline void prefetch(const void *addr)
+-{
+- __asm__("ldw 0(%0), %%r0" : : "r" (addr));
+-}
+-
+-extern inline void prefetchw(const void *addr)
++/* Used as a macro to identify the combined VIPT/PIPT cached
++ * CPUs which require a guarantee of coherency (no inequivalent
++ * aliases with different data, whether clean or not) to operate */
++static inline int parisc_requires_coherency(void)
+ {
+- __asm__("ldd 0(%0), %%r0" : : "r" (addr));
+-}
++#ifdef CONFIG_PA8X00
++ /* FIXME: also pa8900 - when we see one */
++ return boot_cpu_data.cpu_type == mako;
++#else
++ return 0;
+ #endif
+-
+-#define cpu_relax() barrier()
++}
+
+ #endif /* __ASSEMBLY__ */
+
+diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h
+new file mode 100644
+index 0000000..5542dd0
+--- /dev/null
++++ b/include/asm-parisc/ropes.h
+@@ -0,0 +1,322 @@
++#ifndef _ASM_PARISC_ROPES_H_
++#define _ASM_PARISC_ROPES_H_
++
++#include <asm-parisc/parisc-device.h>
++
++#ifdef CONFIG_64BIT
++/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
++#define ZX1_SUPPORT
++#endif
++
++#ifdef CONFIG_PROC_FS
++/* depends on proc fs support. But costs CPU performance */
++#undef SBA_COLLECT_STATS
++#endif
++
++/*
++** The number of pdir entries to "free" before issueing
++** a read to PCOM register to flush out PCOM writes.
++** Interacts with allocation granularity (ie 4 or 8 entries
++** allocated and free'd/purged at a time might make this
++** less interesting).
++*/
++#define DELAYED_RESOURCE_CNT 16
++
++#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
++#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
++
++struct ioc {
++ void __iomem *ioc_hpa; /* I/O MMU base address */
++ char *res_map; /* resource map, bit == pdir entry */
++ u64 *pdir_base; /* physical base address */
++ unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
++ unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
++#ifdef ZX1_SUPPORT
++ unsigned long iovp_mask; /* help convert IOVA to IOVP */
++#endif
++ unsigned long *res_hint; /* next avail IOVP - circular search */
++ spinlock_t res_lock;
++ unsigned int res_bitshift; /* from the LEFT! */
++ unsigned int res_size; /* size of resource map in bytes */
++#ifdef SBA_HINT_SUPPORT
++/* FIXME : DMA HINTs not used */
++ unsigned long hint_mask_pdir; /* bits used for DMA hints */
++ unsigned int hint_shift_pdir;
++#endif
++#if DELAYED_RESOURCE_CNT > 0
++ int saved_cnt;
++ struct sba_dma_pair {
++ dma_addr_t iova;
++ size_t size;
++ } saved[DELAYED_RESOURCE_CNT];
++#endif
++
++#ifdef SBA_COLLECT_STATS
++#define SBA_SEARCH_SAMPLE 0x100
++ unsigned long avg_search[SBA_SEARCH_SAMPLE];
++ unsigned long avg_idx; /* current index into avg_search */
++ unsigned long used_pages;
++ unsigned long msingle_calls;
++ unsigned long msingle_pages;
++ unsigned long msg_calls;
++ unsigned long msg_pages;
++ unsigned long usingle_calls;
++ unsigned long usingle_pages;
++ unsigned long usg_calls;
++ unsigned long usg_pages;
++#endif
++ /* STUFF We don't need in performance path */
++ unsigned int pdir_size; /* in bytes, determined by IOV Space size */
++};
++
++struct sba_device {
++ struct sba_device *next; /* list of SBA's in system */
++ struct parisc_device *dev; /* dev found in bus walk */
++ const char *name;
++ void __iomem *sba_hpa; /* base address */
++ spinlock_t sba_lock;
++ unsigned int flags; /* state/functionality enabled */
++ unsigned int hw_rev; /* HW revision of chip */
++
++ struct resource chip_resv; /* MMIO reserved for chip */
++ struct resource iommu_resv; /* MMIO reserved for iommu */
++
++ unsigned int num_ioc; /* number of on-board IOC's */
++ struct ioc ioc[MAX_IOC];
++};
++
++#define ASTRO_RUNWAY_PORT 0x582
++#define IKE_MERCED_PORT 0x803
++#define REO_MERCED_PORT 0x804
++#define REOG_MERCED_PORT 0x805
++#define PLUTO_MCKINLEY_PORT 0x880
++
++static inline int IS_ASTRO(struct parisc_device *d) {
++ return d->id.hversion == ASTRO_RUNWAY_PORT;
++}
++
++static inline int IS_IKE(struct parisc_device *d) {
++ return d->id.hversion == IKE_MERCED_PORT;
++}
++
++static inline int IS_PLUTO(struct parisc_device *d) {
++ return d->id.hversion == PLUTO_MCKINLEY_PORT;
++}
++
++#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */
++#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */
++#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2)
++
++#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL
++
++#define SBA_AGPGART_COOKIE 0x0000badbadc0ffeeULL
++
++#define SBA_FUNC_ID 0x0000 /* function id */
++#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
++
++#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
++
++#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
++#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
++/* Ike's IOC's occupy functions 2 and 3 */
++#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
++
++#define IOC_CTRL 0x8 /* IOC_CTRL offset */
++#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
++#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
++#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
++#define IOC_CTRL_RM (1 << 8) /* Real Mode */
++#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
++#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
++#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
++
++/*
++** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
++** Firmware programs this stuff. Don't touch it.
++*/
++#define LMMIO_DIRECT0_BASE 0x300
++#define LMMIO_DIRECT0_MASK 0x308
++#define LMMIO_DIRECT0_ROUTE 0x310
++
++#define LMMIO_DIST_BASE 0x360
++#define LMMIO_DIST_MASK 0x368
++#define LMMIO_DIST_ROUTE 0x370
++
++#define IOS_DIST_BASE 0x390
++#define IOS_DIST_MASK 0x398
++#define IOS_DIST_ROUTE 0x3A0
++
++#define IOS_DIRECT_BASE 0x3C0
++#define IOS_DIRECT_MASK 0x3C8
++#define IOS_DIRECT_ROUTE 0x3D0
++
++/*
++** Offsets into I/O TLB (Function 2 and 3 on Ike)
++*/
++#define ROPE0_CTL 0x200 /* "regbus pci0" */
++#define ROPE1_CTL 0x208
++#define ROPE2_CTL 0x210
++#define ROPE3_CTL 0x218
++#define ROPE4_CTL 0x220
++#define ROPE5_CTL 0x228
++#define ROPE6_CTL 0x230
++#define ROPE7_CTL 0x238
++
++#define IOC_ROPE0_CFG 0x500 /* pluto only */
++#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
++
++#define HF_ENABLE 0x40
++
++#define IOC_IBASE 0x300 /* IO TLB */
++#define IOC_IMASK 0x308
++#define IOC_PCOM 0x310
++#define IOC_TCNFG 0x318
++#define IOC_PDIR_BASE 0x320
++
++/*
++** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
++** It's safer (avoid memory corruption) to keep DMA page mappings
++** equivalently sized to VM PAGE_SIZE.
++**
++** We really can't avoid generating a new mapping for each
++** page since the Virtual Coherence Index has to be generated
++** and updated for each page.
++**
++** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
++*/
++#define IOVP_SIZE PAGE_SIZE
++#define IOVP_SHIFT PAGE_SHIFT
++#define IOVP_MASK PAGE_MASK
++
++#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
++#define SBA_PERF_MASK1 0x718
++#define SBA_PERF_MASK2 0x730
++
++/*
++** Offsets into PCI Performance Counters (functions 12 and 13)
++** Controlled by PERF registers in function 2 & 3 respectively.
++*/
++#define SBA_PERF_CNT1 0x200
++#define SBA_PERF_CNT2 0x208
++#define SBA_PERF_CNT3 0x210
++
++/*
++** lba_device: Per instance Elroy data structure
++*/
++struct lba_device {
++ struct pci_hba_data hba;
++
++ spinlock_t lba_lock;
++ void *iosapic_obj;
++
++#ifdef CONFIG_64BIT
++ void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */
++#endif
++
++ int flags; /* state/functionality enabled */
++ int hw_rev; /* HW revision of chip */
++};
++
++#define ELROY_HVERS 0x782
++#define MERCURY_HVERS 0x783
++#define QUICKSILVER_HVERS 0x784
++
++static inline int IS_ELROY(struct parisc_device *d) {
++ return (d->id.hversion == ELROY_HVERS);
++}
++
++static inline int IS_MERCURY(struct parisc_device *d) {
++ return (d->id.hversion == MERCURY_HVERS);
++}
++
++static inline int IS_QUICKSILVER(struct parisc_device *d) {
++ return (d->id.hversion == QUICKSILVER_HVERS);
++}
++
++static inline int agp_mode_mercury(void __iomem *hpa) {
++ u64 bus_mode;
++
++ bus_mode = readl(hpa + 0x0620);
++ if (bus_mode & 1)
++ return 1;
++
++ return 0;
++}
++
++/*
++** I/O SAPIC init function
++** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
++** Call setup as part of per instance initialization.
++** (ie *not* init_module() function unless only one is present.)
++** fixup_irq is to initialize PCI IRQ line support and
++** virtualize pcidev->irq value. To be called by pci_fixup_bus().
++*/
++extern void *iosapic_register(unsigned long hpa);
++extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
++
++#define LBA_FUNC_ID 0x0000 /* function id */
++#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
++#define LBA_CAPABLE 0x0030 /* capabilities register */
++
++#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
++#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
++
++#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
++#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
++#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
++
++#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
++#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
++#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
++#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
++
++#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
++
++#define LBA_STAT_CTL 0x0108 /* Status & Control */
++#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
++#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
++#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
++#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
++
++#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
++#define LBA_LMMIO_MASK 0x0208
++
++#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
++#define LBA_GMMIO_MASK 0x0218
++
++#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
++#define LBA_WLMMIO_MASK 0x0228
++
++#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
++#define LBA_WGMMIO_MASK 0x0238
++
++#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
++#define LBA_IOS_MASK 0x0248
++
++#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
++#define LBA_ELMMIO_MASK 0x0258
++
++#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
++#define LBA_EIOS_MASK 0x0268
++
++#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
++#define LBA_DMA_CTL 0x0278 /* firmware sets this */
++
++#define LBA_IBASE 0x0300 /* SBA DMA support */
++#define LBA_IMASK 0x0308
++
++/* FIXME: ignore DMA Hint stuff until we can measure performance */
++#define LBA_HINT_CFG 0x0310
++#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
++
++#define LBA_BUS_MODE 0x0620
++
++/* ERROR regs are needed for config cycle kluges */
++#define LBA_ERROR_CONFIG 0x0680
++#define LBA_SMART_MODE 0x20
++#define LBA_ERROR_STATUS 0x0688
++#define LBA_ROPE_CTL 0x06A0
++
++#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
++
++#endif /*_ASM_PARISC_ROPES_H_*/
+diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
+index 82fd820..d7e3cc6 100644
+--- a/include/asm-parisc/serial.h
++++ b/include/asm-parisc/serial.h
+@@ -3,20 +3,8 @@
+ */
+
+ /*
+- * This assumes you have a 7.272727 MHz clock for your UART.
+- * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
+- * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO
++ * This is used for 16550-compatible UARTs
+ */
++#define BASE_BAUD ( 1843200 / 16 )
+
+-#define LASI_BASE_BAUD ( 7272727 / 16 )
+-#define BASE_BAUD LASI_BASE_BAUD
+-
+-/*
+- * We don't use the ISA probing code, so these entries are just to reserve
+- * space. Some example (maximal) configurations:
+- * - 712 w/ additional Lasi & RJ16 ports: 4
+- * - J5k w/ PCI serial cards: 2 + 4 * card ~= 34
+- * A500 w/ PCI serial cards: 5 + 4 * card ~= 17
+- */
+-
+ #define SERIAL_PORT_DFNS
+diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
+index a93960e..7c737a0 100644
+--- a/include/asm-parisc/spinlock.h
++++ b/include/asm-parisc/spinlock.h
+@@ -56,50 +56,79 @@ static inline int __raw_spin_trylock(raw
+ }
+
+ /*
+- * Read-write spinlocks, allowing multiple readers
+- * but only one writer.
++ * Read-write spinlocks, allowing multiple readers but only one writer.
++ * Linux rwlocks are unfair to writers; they can be starved for an indefinite
++ * time by readers. With care, they can also be taken in interrupt context.
++ *
++ * In the PA-RISC implementation, we have a spinlock and a counter.
++ * Readers use the lock to serialise their access to the counter (which
++ * records how many readers currently hold the lock).
++ * Writers hold the spinlock, preventing any readers or other writers from
++ * grabbing the rwlock.
+ */
+
+-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+-
+-/* read_lock, read_unlock are pretty straightforward. Of course it somehow
+- * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
+-
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to grab the same read lock */
+ static __inline__ void __raw_read_lock(raw_rwlock_t *rw)
+ {
+- __raw_spin_lock(&rw->lock);
+-
++ unsigned long flags;
++ local_irq_save(flags);
++ __raw_spin_lock_flags(&rw->lock, flags);
+ rw->counter++;
+-
+ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
+ }
+
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to grab the same read lock */
+ static __inline__ void __raw_read_unlock(raw_rwlock_t *rw)
+ {
+- __raw_spin_lock(&rw->lock);
+-
++ unsigned long flags;
++ local_irq_save(flags);
++ __raw_spin_lock_flags(&rw->lock, flags);
+ rw->counter--;
+-
+ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
+ }
+
+-/* write_lock is less trivial. We optimistically grab the lock and check
+- * if we surprised any readers. If so we release the lock and wait till
+- * they're all gone before trying again
+- *
+- * Also note that we don't use the _irqsave / _irqrestore suffixes here.
+- * If we're called with interrupts enabled and we've got readers (or other
+- * writers) in interrupt handlers someone fucked up and we'd dead-lock
+- * sooner or later anyway. prumpf */
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to grab the same read lock */
++static __inline__ int __raw_read_trylock(raw_rwlock_t *rw)
++{
++ unsigned long flags;
++ retry:
++ local_irq_save(flags);
++ if (__raw_spin_trylock(&rw->lock)) {
++ rw->counter++;
++ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
++ return 1;
++ }
+
+-static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
++ local_irq_restore(flags);
++ /* If write-locked, we fail to acquire the lock */
++ if (rw->counter < 0)
++ return 0;
++
++ /* Wait until we have a realistic chance at the lock */
++ while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0)
++ cpu_relax();
++
++ goto retry;
++}
++
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to read_trylock() this lock */
++static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
+ {
++ unsigned long flags;
+ retry:
+- __raw_spin_lock(&rw->lock);
++ local_irq_save(flags);
++ __raw_spin_lock_flags(&rw->lock, flags);
+
+- if(rw->counter != 0) {
+- /* this basically never happens */
++ if (rw->counter != 0) {
+ __raw_spin_unlock(&rw->lock);
++ local_irq_restore(flags);
+
+ while (rw->counter != 0)
+ cpu_relax();
+@@ -107,31 +136,37 @@ retry:
+ goto retry;
+ }
+
+- /* got it. now leave without unlocking */
+- rw->counter = -1; /* remember we are locked */
++ rw->counter = -1; /* mark as write-locked */
++ mb();
++ local_irq_restore(flags);
+ }
+
+-/* write_unlock is absolutely trivial - we don't have to wait for anything */
+-
+-static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
++static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
+ {
+ rw->counter = 0;
+ __raw_spin_unlock(&rw->lock);
+ }
+
+-static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
++/* Note that we have to ensure interrupts are disabled in case we're
++ * interrupted by some other code that wants to read_trylock() this lock */
++static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
+ {
+- __raw_spin_lock(&rw->lock);
+- if (rw->counter != 0) {
+- /* this basically never happens */
+- __raw_spin_unlock(&rw->lock);
+-
+- return 0;
++ unsigned long flags;
++ int result = 0;
++
++ local_irq_save(flags);
++ if (__raw_spin_trylock(&rw->lock)) {
++ if (rw->counter == 0) {
++ rw->counter = -1;
++ result = 1;
++ } else {
++ /* Read-locked. Oh well. */
++ __raw_spin_unlock(&rw->lock);
++ }
+ }
++ local_irq_restore(flags);
+
+- /* got it. now leave without unlocking */
+- rw->counter = -1; /* remember we are locked */
+- return 1;
++ return result;
+ }
+
+ /*
+diff --git a/include/linux/compat.h b/include/linux/compat.h
+index 9760753..f72df4d 100644
+--- a/include/linux/compat.h
++++ b/include/linux/compat.h
+@@ -5,10 +5,16 @@ #define _LINUX_COMPAT_H
+ * syscall compatibility layer.
+ */
+
+-#ifdef CONFIG_COMPAT
++#ifndef CONFIG_COMPAT
++
++/* Non-native task requiring compat... doesn't exist */
++#define is_compat_task() 0
++
++#else
+
+ #include <linux/stat.h>
+ #include <linux/param.h> /* for HZ */
++#include <linux/personality.h> /* Conditional process compat */
+ #include <linux/sem.h>
+
+ #include <asm/compat.h>
+@@ -17,6 +23,11 @@ #include <asm/siginfo.h>
+ #define compat_jiffies_to_clock_t(x) \
+ (((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
+
++/* Non-native task requiring compat */
++#ifndef HAVE_ARCH_IS_COMPAT_TASK
++#define is_compat_task() (personality(current->personality) == PER_LINUX32)
++#endif
++
+ typedef __compat_uid32_t compat_uid_t;
+ typedef __compat_gid32_t compat_gid_t;
+
+@@ -199,10 +210,6 @@ long compat_get_bitmap(unsigned long *ma
+ unsigned long bitmap_size);
+ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
+ unsigned long bitmap_size);
+-int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from);
+-int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from);
+-int get_compat_sigevent(struct sigevent *event,
+- const struct compat_sigevent __user *u_event);
+
+ static inline int compat_timeval_compare(struct compat_timeval *lhs,
+ struct compat_timeval *rhs)
+diff --git a/include/linux/compat_siginfo.h b/include/linux/compat_siginfo.h
+new file mode 100644
+index 0000000..f3342d4
+--- /dev/null
++++ b/include/linux/compat_siginfo.h
+@@ -0,0 +1,141 @@
++#ifndef _ASM_GENERIC_COMPAT_SIGINFO_H
++#define _ASM_GENERIC_COMPAT_SIGINFO_H
++
++#include <linux/config.h>
++#include <linux/compat.h>
++
++#ifndef CONFIG_COMPAT
++
++/* No compatibility layer required, add empty definitions for the compiler */
++
++typedef struct compat_siginfo{
++} compat_siginfo_t;
++
++static inline int compat_copy_siginfo_to_user(compat_siginfo_t __user *to,
++ struct siginfo *from)
++{
++ return -1;
++}
++
++static inline int compat_copy_siginfo_from_user(struct siginfo *to,
++ compat_siginfo_t __user *from)
++{
++ return -1;
++}
++
++#else
++
++#include <linux/compiler.h>
++#include <asm/siginfo.h>
++
++/*
++ * This is the size (including padding) of the part of the
++ * struct siginfo that is before the union.
++ */
++#ifndef __ARCH_SI_COMPAT_PREAMBLE_SIZE
++#define __ARCH_SI_COMPAT_PREAMBLE_SIZE (3 * sizeof(compat_int_t))
++#endif
++
++#define SI_COMPAT_MAX_SIZE 128
++#ifndef SI_COMPAT_PAD_SIZE
++#define SI_COMPAT_PAD_SIZE \
++ ((SI_COMPAT_MAX_SIZE - __ARCH_SI_COMPAT_PREAMBLE_SIZE) / sizeof(compat_int_t))
++#endif
++
++/* 32-bit view of si.uid_t */
++#ifndef __ARCH_SI_COMPAT_UID_T
++#define __ARCH_SI_COMPAT_UID_T compat_uid_t
++#endif
++
++/* 32-bit view of si.band_t */
++#ifndef __ARCH_SI_COMPAT_BAND_T
++#define __ARCH_SI_COMPAT_BAND_T compat_int_t
++#endif
++
++#ifndef HAVE_ARCH_COMPAT_SIGINFO_T
++
++/* Compat view of siginfo_t */
++typedef struct compat_siginfo {
++ compat_int_t si_signo;
++ compat_int_t si_errno;
++ compat_int_t si_code;
++
++ union {
++ compat_int_t _pad[SI_COMPAT_PAD_SIZE];
++
++ /* kill() */
++ struct {
++ compat_pid_t _pid; /* sender's pid */
++ __ARCH_SI_COMPAT_UID_T _uid; /* sender's uid */
++ } _kill;
++
++ /* POSIX.1b timers */
++ struct {
++ compat_timer_t _tid; /* timer id */
++ compat_int_t _overrun; /* overrun count */
++ char _pad[sizeof(__ARCH_SI_COMPAT_UID_T) - sizeof(compat_int_t)];
++ compat_sigval_t _sigval; /* same as below */
++ compat_int_t _sys_private; /* not to be passed to user */
++ } _timer;
++
++ /* POSIX.1b signals */
++ struct {
++ compat_pid_t _pid; /* sender's pid */
++ __ARCH_SI_COMPAT_UID_T _uid; /* sender's uid */
++ compat_sigval_t _sigval;
++ } _rt;
++
++ /* SIGCHLD */
++ struct {
++ compat_pid_t _pid; /* which child */
++ __ARCH_SI_COMPAT_UID_T _uid; /* sender's uid */
++ compat_int_t _status; /* exit code */
++ compat_clock_t _utime;
++ compat_clock_t _stime;
++ } _sigchld;
++
++ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
++ struct {
++ compat_uptr_t _addr; /* faulting insn/memory ref. */
++#ifdef __ARCH_SI_COMPAT_TRAPNO
++ compat_int_t _trapno; /* TRAP # which caused the signal */
++#endif
++ } _sigfault;
++
++ /* SIGPOLL */
++ struct {
++ __ARCH_SI_COMPAT_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
++ compat_int_t _fd;
++ } _sigpoll;
++ } _sifields;
++} compat_siginfo_t;
++#endif /* !HAVE_ARCH_COMPAT_SIGINFO_T */
++
++#ifdef __ARCH_SI_COMPAT_TRAPNO
++#define si_trapno _sifields._sigfault._trapno
++#endif
++
++#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO
++
++#include <linux/string.h>
++
++static inline void compat_copy_siginfo(struct compat_siginfo *to, struct compat_siginfo *from)
++{
++ if (from->si_code < 0)
++ memcpy(to, from, sizeof(*to));
++ else
++ /* _sigchld is currently the largest know union member */
++ memcpy(to, from, __ARCH_SI_COMPAT_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
++}
++
++#endif /* !HAVE_ARCH_COMPAT_COPY_SIGINFO */
++
++extern int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, struct siginfo *from);
++extern int compat_copy_siginfo_from_user(struct siginfo *to, compat_siginfo_t __user *from);
++
++extern int compat_copy_sigevent_from_user(struct sigevent *to, compat_sigevent_t __user *from);
++extern int compat_copy_sigevent_to_user(compat_sigevent_t __user *to, struct sigevent *from);
++
++#endif /* CONFIG_COMPAT */
++#endif /* _ASM_GENERIC_COMPAT_SIGINFO_H */
++
+diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
+index 88dafa2..952bee7 100644
+--- a/include/linux/debug_locks.h
++++ b/include/linux/debug_locks.h
+@@ -43,6 +43,8 @@ #else
+ # define locking_selftest() do { } while (0)
+ #endif
+
++struct task_struct;
++
+ #ifdef CONFIG_LOCKDEP
+ extern void debug_show_all_locks(void);
+ extern void debug_show_held_locks(struct task_struct *task);
+diff --git a/include/linux/highmem.h b/include/linux/highmem.h
+index 85ce7ef..42620e7 100644
+--- a/include/linux/highmem.h
++++ b/include/linux/highmem.h
+@@ -29,6 +29,7 @@ #else /* CONFIG_HIGHMEM */
+
+ static inline unsigned int nr_free_highpages(void) { return 0; }
+
++#ifndef ARCH_HAS_KMAP
+ static inline void *kmap(struct page *page)
+ {
+ might_sleep();
+@@ -41,6 +42,7 @@ #define kmap_atomic(page, idx) page_add
+ #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
+
+ #endif /* CONFIG_HIGHMEM */
+
+diff --git a/include/linux/io.h b/include/linux/io.h
+index 420e2fd..a3c128f 100644
+--- a/include/linux/io.h
++++ b/include/linux/io.h
+@@ -23,4 +23,31 @@ #include <asm/io.h>
+ void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
+ void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
+
++/**
++ * check_signature - find BIOS signatures
++ * @io_addr: mmio address to check
++ * @signature: signature block
++ * @length: length of signature
++ *
++ * Perform a signature comparison with the mmio address io_addr. This
++ * address should have been obtained by ioremap.
++ * Returns 1 on a match.
++ */
++
++static inline int check_signature(const volatile void __iomem * io_addr,
++ const unsigned char *signature, int length)
++{
++ int retval = 0;
++ do {
++ if (readb(io_addr) != *signature)
++ goto out;
++ io_addr++;
++ signature++;
++ length--;
++ } while (length);
++ retval = 1;
++out:
++ return retval;
++}
++
+ #endif /* _LINUX_IO_H */
+diff --git a/include/linux/signal.h b/include/linux/signal.h
+index 117135e..e9bdea1 100644
+--- a/include/linux/signal.h
++++ b/include/linux/signal.h
+@@ -241,6 +241,9 @@ extern int sigprocmask(int, sigset_t *,
+ struct pt_regs;
+ extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
+
++int copy_siginfo_from_user(siginfo_t *to, siginfo_t __user *from);
++int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from);
++
+ #endif /* __KERNEL__ */
+
+ #endif /* _LINUX_SIGNAL_H */
+diff --git a/include/linux/types.h b/include/linux/types.h
+index 3f23566..475ac63 100644
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -129,14 +129,19 @@ #define aligned_u64 unsigned long long _
+
+ /*
+ * The type used for indexing onto a disc or disc partition.
+- * If required, asm/types.h can override it and define
+- * HAVE_SECTOR_T
+ */
+-#ifndef HAVE_SECTOR_T
++#ifdef CONFIG_LBD
++typedef u64 sector_t;
++#else
+ typedef unsigned long sector_t;
+ #endif
+
+-#ifndef HAVE_BLKCNT_T
++/*
++ * The type of the inode's block count.
++ */
++#ifdef CONFIG_LSF
++typedef u64 blkcnt_t;
++#else
+ typedef unsigned long blkcnt_t;
+ #endif
+
+diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
+index d8d1e9f..41572f3 100644
+--- a/ipc/compat_mq.c
++++ b/ipc/compat_mq.c
+@@ -7,6 +7,7 @@
+ */
+
+ #include <linux/compat.h>
++#include <linux/compat_siginfo.h>
+ #include <linux/fs.h>
+ #include <linux/kernel.h>
+ #include <linux/mqueue.h>
+diff --git a/kernel/Makefile b/kernel/Makefile
+index d62ec66..4448483 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -35,7 +35,7 @@ obj-$(CONFIG_STACK_UNWIND) += unwind.o
+ obj-$(CONFIG_PM) += power/
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+-obj-$(CONFIG_COMPAT) += compat.o
++obj-$(CONFIG_COMPAT) += compat.o compat_signal.o
+ obj-$(CONFIG_CPUSETS) += cpuset.o
+ obj-$(CONFIG_IKCONFIG) += configs.o
+ obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
+diff --git a/kernel/compat.c b/kernel/compat.c
+index 126dee9..5f24154 100644
+--- a/kernel/compat.c
++++ b/kernel/compat.c
+@@ -13,6 +13,7 @@
+
+ #include <linux/linkage.h>
+ #include <linux/compat.h>
++#include <linux/compat_siginfo.h>
+ #include <linux/errno.h>
+ #include <linux/time.h>
+ #include <linux/signal.h>
+@@ -417,7 +418,11 @@ asmlinkage long compat_sys_waitid(int wh
+
+ BUG_ON(info.si_code & __SI_MASK);
+ info.si_code |= __SI_CHLD;
+- return copy_siginfo_to_user32(uinfo, &info);
++
++ if (compat_copy_siginfo_to_user(uinfo, &info) != 0)
++ return -EFAULT;
++
++ return 0;
+ }
+
+ static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
+@@ -794,7 +799,7 @@ compat_sys_rt_sigtimedwait (compat_sigse
+ if (sig) {
+ ret = sig;
+ if (uinfo) {
+- if (copy_siginfo_to_user32(uinfo, &info))
++ if (compat_copy_siginfo_to_user(uinfo, &info))
+ ret = -EFAULT;
+ }
+ }else {
+diff --git a/kernel/compat_signal.c b/kernel/compat_signal.c
+new file mode 100644
+index 0000000..b6bc6f9
+--- /dev/null
++++ b/kernel/compat_signal.c
+@@ -0,0 +1,280 @@
++/*
++ * Copyright (C) 2003 Carlos O'Donell
++ *
++ * 2003-12-20 Carlos O'Donell
++ * Copied linux/kernel/compat_signal.c (copy_siginfo_to_user)
++ * and modified to use compat_siginfo_t for thunking down to
++ * 32-bit userspace from a 64-bit kernel.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/compat_siginfo.h>
++#include <asm/errno.h>
++#include <asm/uaccess.h>
++#include <asm/siginfo.h>
++
++#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO_TO_USER
++int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, siginfo_t *from)
++{
++ int err;
++ compat_siginfo_t compat_from;
++
++ if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
++ return -EFAULT;
++
++ /*
++ * If you change compat_siginfo_t structure *or* siginfo_t,
++ * please be sure this code is fixed accordingly.
++ * It should never copy any pad contained in the structure
++ * to avoid security leaks, but must copy the generic
++ * 3 ints plus the relevant union member.
++ */
++
++ /* Convert structure, don't leak anything in the copy */
++ memset(&compat_from,'\0',sizeof(compat_siginfo_t));
++
++ /* Always copy si_signo, si_errno, and si_code */
++ compat_from.si_signo = (compat_int_t)(from->si_signo);
++ compat_from.si_errno = (compat_int_t)(from->si_errno);
++ /* si_code is only a (short) value, remove kernel bits. */
++ compat_from.si_code = (short)(from->si_code);
++
++ err = __put_user(compat_from.si_signo, &to->si_signo);
++ err |= __put_user(compat_from.si_errno, &to->si_errno);
++ err |= __put_user(compat_from.si_code, &to->si_code);
++
++ /* siginfo_t came from userspace, so it is the right
++ * size, no need for conversion
++ */
++ if (from->si_code < 0) {
++ return __copy_to_user(&to->_sifields._pad,
++ &from->_sifields._pad,
++ SI_COMPAT_PAD_SIZE)
++ ? -EFAULT : 0;
++ }
++
++ switch (from->si_code & __SI_MASK) {
++ case __SI_KILL:
++ compat_from.si_pid = (compat_pid_t)(from->si_pid);
++ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
++ err |= __put_user(compat_from.si_pid, &to->si_pid);
++ err |= __put_user(compat_from.si_uid, &to->si_uid);
++ break;
++ case __SI_TIMER:
++ compat_from.si_pid = (compat_timer_t)(from->si_tid);
++ compat_from.si_overrun = (compat_int_t)(from->si_overrun);
++ compat_from.si_ptr = (compat_uptr_t)((u64 __force)(from->si_ptr) & 0xffffffffUL);
++ err |= __put_user(compat_from.si_tid, &to->si_tid);
++ err |= __put_user(compat_from.si_overrun, &to->si_overrun);
++ err |= __put_user(compat_from.si_ptr, &to->si_ptr);
++ break;
++ case __SI_POLL:
++ compat_from.si_band = (__ARCH_SI_COMPAT_BAND_T)(from->si_band);
++ compat_from.si_fd = (compat_int_t)(from->si_fd);
++ err |= __put_user(compat_from.si_band, &to->si_band);
++ err |= __put_user(compat_from.si_fd, &to->si_fd);
++ break;
++ case __SI_FAULT:
++ compat_from.si_addr = (compat_uptr_t)((u64 __force)(from->si_addr) & 0xffffffffUL);
++ err |= __put_user(compat_from.si_addr, &to->si_addr);
++#ifdef __ARCH_SI_COMPAT_TRAPNO
++ compat_from.si_trapno = (compat_int_t)(from->si_addr);
++ err |= __put_user(compat_from.si_trapno, &to->si_trapno);
++#endif
++ break;
++ case __SI_CHLD:
++ compat_from.si_pid = (compat_pid_t)(from->si_pid);
++ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
++ compat_from.si_status = (compat_int_t)(from->si_status);
++ compat_from.si_utime = (compat_clock_t)(from->si_utime);
++ compat_from.si_stime = (compat_clock_t)(from->si_stime);
++ err |= __put_user(compat_from.si_pid, &to->si_pid);
++ err |= __put_user(compat_from.si_uid, &to->si_uid);
++ err |= __put_user(compat_from.si_status, &to->si_status);
++ err |= __put_user(compat_from.si_utime, &to->si_utime);
++ err |= __put_user(compat_from.si_stime, &to->si_stime);
++ break;
++ case __SI_RT: /* This is not generated by the kernel as of now. */
++ case __SI_MESGQ: /* But this is */
++ compat_from.si_pid = (compat_pid_t)(from->si_pid);
++ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
++ compat_from.si_int = (compat_int_t)(from->si_int);
++ compat_from.si_ptr = (compat_uptr_t)((u64 __force)(from->si_ptr) & 0xffffffffUL);
++ err |= __put_user(compat_from.si_pid, &to->si_pid);
++ err |= __put_user(compat_from.si_uid, &to->si_uid);
++ err |= __put_user(compat_from.si_int, &to->si_int);
++ err |= __put_user(compat_from.si_ptr, &to->si_ptr);
++ break;
++ default: /* this is just in case for now ... */
++ compat_from.si_pid = (compat_pid_t)(from->si_pid);
++ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
++ err |= __put_user(compat_from.si_pid, &to->si_pid);
++ err |= __put_user(compat_from.si_uid, &to->si_uid);
++ break;
++ }
++ return err;
++}
++#endif
++
++#ifndef HAVE_ARCH_COPY_SIGINFO_FROM_USER
++int compat_copy_siginfo_from_user(siginfo_t *to, compat_siginfo_t __user *from)
++{
++ int err;
++ u64 scratch;
++
++ if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
++ return -EFAULT;
++
++ /*
++ * If you change compat_siginfo_t structure *or* siginfo_t,
++ * please be sure this code is fixed accordingly.
++ */
++
++ /* Always copy si_signo, si_errno, and si_code */
++ err = __get_user(to->si_signo, &from->si_signo);
++ err |= __get_user(to->si_errno, &from->si_errno);
++ err |= __get_user(to->si_code, &from->si_code);
++
++ /* siginfo_t came from userspace, so it is the right
++ * size, no need for conversion
++ */
++ if (to->si_code < 0) {
++ return __copy_from_user(&to->_sifields._pad,
++ &from->_sifields._pad,
++ SI_COMPAT_PAD_SIZE)
++ ? -EFAULT : 0;
++ }
++
++ switch (to->si_code & __SI_MASK) {
++ case __SI_KILL:
++ err |= __get_user(to->si_pid, &from->si_pid);
++ err |= __get_user(to->si_uid, &from->si_uid);
++ break;
++ case __SI_TIMER:
++ err |= __get_user(to->si_tid, &from->si_tid);
++ err |= __get_user(to->si_overrun, &from->si_overrun);
++ err |= __get_user(scratch, &from->si_ptr);
++ to->si_ptr = (u64 __user*)scratch;
++ break;
++ case __SI_POLL:
++ err |= __get_user(to->si_band, &from->si_band);
++ err |= __get_user(to->si_fd, &from->si_fd);
++ break;
++ case __SI_FAULT:
++ err |= __get_user(scratch, &from->si_addr);
++ to->si_addr = (u64 __user*)scratch;
++#ifdef __ARCH_SI_COMPAT_TRAPNO
++ err |= __get_user(to->si_trapno, &from->si_trapno);
++#endif
++ break;
++ case __SI_CHLD:
++ err |= __get_user(to->si_pid, &from->si_pid);
++ err |= __get_user(to->si_uid, &from->si_uid);
++ err |= __get_user(to->si_status, &from->si_status);
++ err |= __get_user(to->si_utime, &from->si_utime);
++ err |= __get_user(to->si_stime, &from->si_stime);
++ break;
++ case __SI_RT: /* This is not generated by the kernel as of now. */
++ case __SI_MESGQ: /* But this is */
++ err |= __get_user(to->si_pid, &from->si_pid);
++ err |= __get_user(to->si_uid, &from->si_uid);
++ err |= __get_user(to->si_int, &from->si_int);
++ err |= __get_user(scratch, &from->si_ptr);
++ to->si_ptr = (u64 __user*)scratch;
++ break;
++ default: /* this is just in case for now ... */
++ err |= __get_user(to->si_pid, &from->si_pid);
++ err |= __get_user(to->si_uid, &from->si_uid);
++ break;
++ }
++ return err;
++}
++#endif
++
++#ifndef HAVE_ARCH_COPY_SIGEVENT_FROM_USER
++int compat_copy_sigevent_from_user(sigevent_t *to, compat_sigevent_t __user *from)
++{
++ int err;
++ u64 scratch;
++
++ /* copy sigval_t sigev_value
++ int_t sival_int (same)
++ uptr_t sival_ptr (32 vs 64)*/
++ err = __get_user(to->sigev_value.sival_int,
++ &from->sigev_value.sival_int);
++ err |= __get_user(scratch, &from->sigev_value.sival_ptr);
++ to->sigev_value.sival_ptr = (u64 __user *)scratch;
++
++ /* copy int_t sigev_signo (same)*/
++ err |= __get_user(to->sigev_signo, &from->sigev_signo);
++
++ /* copy int_t sigev_notify (same)*/
++ err |= __get_user(to->sigev_notify, &from->sigev_notify);
++
++ /* never copy _sigev_un padding */
++
++ /* copy int_t _tid (same),
++ good_sigevent() uses this value of */
++ err |= __get_user(to->sigev_notify_thread_id, &from->sigev_notify_thread_id);
++
++ /* XXX: Do not copy these, they aren't used by
++ anyone. We would need to distinguish the uses of the union.
++ copy _sigev_thread
++ uptr_t _function (32 vs 64)
++ uptr_t _attribute (32 vs 64)*/
++
++ return err;
++}
++#endif
++
++#ifndef HAVE_ARCH_COPY_SIGEVENT_TO_USER
++int compat_copy_sigevent_to_user(compat_sigevent_t __user *to, sigevent_t *from)
++{
++ int err;
++ u32 scratch;
++
++ /* copy sigval_t sigev_value
++ int_t sival_int (same)
++ uptr_t sival_ptr (32 vs 64)*/
++ err = __put_user(from->sigev_value.sival_int,
++ &to->sigev_value.sival_int);
++ scratch = (u32)((u64 __force)from->sigev_value.sival_ptr & 0xffffffffUL);
++ err |= __put_user((compat_uptr_t)scratch, &to->sigev_value.sival_ptr);
++
++ /* copy int_t sigev_signo (same)*/
++ err |= __put_user(from->sigev_signo, &to->sigev_signo);
++
++ /* copy int_t sigev_notify (same)*/
++ err |= __put_user(from->sigev_notify, &to->sigev_notify);
++
++ /* never copy _sigev_un padding */
++
++ /* copy int_t _tid (same),
++ good_sigevent() uses this value of */
++ err |= __put_user(from->sigev_notify_thread_id, &to->sigev_notify_thread_id);
++
++ /* XXX: Do not copy these, they aren't used by
++ anyone. We would need to distinguish the uses of the union.
++ copy _sigev_thread
++ uptr_t _function (32 vs 64)
++ uptr_t _attribute (32 vs 64)*/
++
++ return err;
++}
++#endif
++
+diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
+index ac1f850..931614f 100644
+--- a/kernel/irq/chip.c
++++ b/kernel/irq/chip.c
+@@ -17,6 +17,90 @@ #include <linux/kernel_stat.h>
+
+ #include "internals.h"
+
++/* Helpers for constructing IRQ handlers */
++
++#ifdef CONFIG_SMP
++#define HANDLE_PERCPU_IRQ(NAME, ACK, EOI) \
++void fastcall \
++handle_percpu_irq##NAME(unsigned int irq, struct irq_desc *desc, \
++ struct pt_regs *regs) \
++{ \
++ irqreturn_t action_ret; \
++ \
++ kstat_this_cpu.irqs[irq]++; \
++ \
++ ACK(desc, irq); \
++ \
++ action_ret = handle_IRQ_event(irq, regs, desc->action); \
++ if (!noirqdebug) \
++ note_interrupt(irq, desc, action_ret, regs); \
++ \
++ EOI(desc,irq); \
++}
++#else
++#define HANDLE_PERCPU_IRQ(NAME, ACK, END)
++#endif /* CONFIG_SMP */
++
++#define HANDLE_LEVEL_IRQ(NAME, MASK, UNMASK) \
++void fastcall \
++handle_level_irq##NAME(unsigned int irq, struct irq_desc *desc, \
++ struct pt_regs *regs) \
++{ \
++ unsigned int cpu = smp_processor_id(); \
++ struct irqaction *action; \
++ irqreturn_t action_ret; \
++ \
++ spin_lock(&desc->lock); \
++ MASK(desc, irq); \
++ \
++ if (unlikely(desc->status & IRQ_INPROGRESS)) \
++ goto out_unlock; \
++ desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); \
++ kstat_cpu(cpu).irqs[irq]++; \
++ \
++ /* \
++ * If its disabled or no action available \
++ * keep it masked and get out of here \
++ */ \
++ action = desc->action; \
++ if (unlikely(!action || (desc->status & IRQ_DISABLED))) { \
++ desc->status |= IRQ_PENDING; \
++ goto out_unlock; \
++ } \
++ \
++ desc->status |= IRQ_INPROGRESS; \
++ desc->status &= ~IRQ_PENDING; \
++ spin_unlock(&desc->lock); \
++ \
++ action_ret = handle_IRQ_event(irq, regs, action); \
++ if (!noirqdebug) \
++ note_interrupt(irq, desc, action_ret, regs); \
++ \
++ spin_lock(&desc->lock); \
++ desc->status &= ~IRQ_INPROGRESS; \
++ UNMASK(desc,irq); \
++out_unlock: \
++ spin_unlock(&desc->lock); \
++}
++
++#define HANDLE_SPECIFIC_IRQ(NAME, ACK, EOI, HANDLER) \
++void fastcall \
++handle_specific_irq##NAME(unsigned int irq, struct irq_desc *desc, \
++ struct pt_regs *regs) \
++{ \
++ irqreturn_t action_ret; \
++ \
++ kstat_this_cpu.irqs[irq]++; \
++ \
++ ACK(desc, irq); \
++ \
++ action_ret = HANDLER(irq, desc->action->dev_id, regs); \
++ if (!noirqdebug) \
++ note_interrupt(irq, desc, action_ret, regs); \
++ \
++ EOI(desc,irq); \
++}
++
+ /**
+ * set_irq_chip - set the irq chip for an irq
+ * @irq: irq number
+@@ -186,6 +270,24 @@ static inline void mask_ack_irq(struct i
+ }
+ }
+
++static inline void unmask_enabled_irq(struct irq_desc *desc, int irq)
++{
++ if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
++ desc->chip->unmask(irq);
++}
++
++static inline void ack_irq(struct irq_desc *desc, int irq)
++{
++ if (desc->chip->ack)
++ desc->chip->ack(irq);
++}
++
++static inline void eoi_irq(struct irq_desc *desc, int irq)
++{
++ if (desc->chip->eoi)
++ desc->chip->eoi(irq);
++}
++
+ /**
+ * handle_simple_irq - Simple and software-decoded IRQs.
+ * @irq: the interrupt number
+@@ -241,46 +343,7 @@ out_unlock:
+ * it after the associated handler has acknowledged the device, so the
+ * interrupt line is back to inactive.
+ */
+-void fastcall
+-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+-{
+- unsigned int cpu = smp_processor_id();
+- struct irqaction *action;
+- irqreturn_t action_ret;
+-
+- spin_lock(&desc->lock);
+- mask_ack_irq(desc, irq);
+-
+- if (unlikely(desc->status & IRQ_INPROGRESS))
+- goto out_unlock;
+- desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+- kstat_cpu(cpu).irqs[irq]++;
+-
+- /*
+- * If its disabled or no action available
+- * keep it masked and get out of here
+- */
+- action = desc->action;
+- if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
+- desc->status |= IRQ_PENDING;
+- goto out_unlock;
+- }
+-
+- desc->status |= IRQ_INPROGRESS;
+- desc->status &= ~IRQ_PENDING;
+- spin_unlock(&desc->lock);
+-
+- action_ret = handle_IRQ_event(irq, regs, action);
+- if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
+-
+- spin_lock(&desc->lock);
+- desc->status &= ~IRQ_INPROGRESS;
+- if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+- desc->chip->unmask(irq);
+-out_unlock:
+- spin_unlock(&desc->lock);
+-}
++HANDLE_LEVEL_IRQ(, mask_ack_irq, unmask_enabled_irq)
+
+ /**
+ * handle_fasteoi_irq - irq handler for transparent controllers
+@@ -416,7 +479,6 @@ out_unlock:
+ spin_unlock(&desc->lock);
+ }
+
+-#ifdef CONFIG_SMP
+ /**
+ * handle_percpu_IRQ - Per CPU local irq handler
+ * @irq: the interrupt number
+@@ -425,25 +487,19 @@ #ifdef CONFIG_SMP
+ *
+ * Per CPU interrupts on SMP machines without locking requirements
+ */
+-void fastcall
+-handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
++HANDLE_PERCPU_IRQ(, ack_irq, eoi_irq)
++
++#ifdef ARCH_HAS_IRQ_HANDLERS
++#include <asm/irq-handlers.h>
++#else
++static inline char *arch_handle_irq_name(void fastcall (*handle)(unsigned int,
++ struct irq_desc *,
++ struct pt_regs *))
+ {
+- irqreturn_t action_ret;
+-
+- kstat_this_cpu.irqs[irq]++;
+-
+- if (desc->chip->ack)
+- desc->chip->ack(irq);
+-
+- action_ret = handle_IRQ_event(irq, regs, desc->action);
+- if (!noirqdebug)
+- note_interrupt(irq, desc, action_ret, regs);
+-
+- if (desc->chip->eoi)
+- desc->chip->eoi(irq);
++ return NULL;
+ }
++#endif
+
+-#endif /* CONFIG_SMP */
+
+ void
+ __set_irq_handler(unsigned int irq,
+@@ -533,5 +589,5 @@ #endif
+ if (handle == handle_bad_irq)
+ return "bad ";
+
+- return NULL;
++ return arch_handle_irq_name(handle);
+ }
+diff --git a/kernel/ptrace.c b/kernel/ptrace.c
+index 9a111f7..fce2838 100644
+--- a/kernel/ptrace.c
++++ b/kernel/ptrace.c
+@@ -399,7 +399,7 @@ static int ptrace_setsiginfo(struct task
+ siginfo_t newinfo;
+ int error = -ESRCH;
+
+- if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
++ if (copy_siginfo_from_user(&newinfo, data) != 0)
+ return -EFAULT;
+
+ read_lock(&tasklist_lock);
+diff --git a/kernel/resource.c b/kernel/resource.c
+index 4628643..4aa21cc 100644
+--- a/kernel/resource.c
++++ b/kernel/resource.c
+@@ -178,6 +178,8 @@ static int __release_resource(struct res
+ {
+ struct resource *tmp, **p;
+
++ BUG_ON(old->child);
++
+ p = &old->parent->child;
+ for (;;) {
+ tmp = *p;
+@@ -344,12 +346,11 @@ EXPORT_SYMBOL(allocate_resource);
+ *
+ * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+- * This function is equivalent of request_resource when no conflict
++ * This function is equivalent to request_resource when no conflict
+ * happens. If a conflict happens, and the conflicting resources
+ * entirely fit within the range of the new resource, then the new
+- * resource is inserted and the conflicting resources become childs of
+- * the new resource. Otherwise the new resource becomes the child of
+- * the conflicting resource
++ * resource is inserted and the conflicting resources become children of
++ * the new resource.
+ */
+ int insert_resource(struct resource *parent, struct resource *new)
+ {
+@@ -357,20 +358,21 @@ int insert_resource(struct resource *par
+ struct resource *first, *next;
+
+ write_lock(&resource_lock);
+- begin:
+- result = 0;
+- first = __request_resource(parent, new);
+- if (!first)
+- goto out;
+
+- result = -EBUSY;
+- if (first == parent)
+- goto out;
++ for (;; parent = first) {
++ result = 0;
++ first = __request_resource(parent, new);
++ if (!first)
++ goto out;
+
+- /* Resource fully contained by the clashing resource? Recurse into it */
+- if (first->start <= new->start && first->end >= new->end) {
+- parent = first;
+- goto begin;
++ result = -EBUSY;
++ if (first == parent)
++ goto out;
++
++ if ((first->start > new->start) || (first->end < new->end))
++ break;
++ if ((first->start == new->start) && (first->end == new->end))
++ break;
+ }
+
+ for (next = first; ; next = next->sibling) {
+diff --git a/kernel/signal.c b/kernel/signal.c
+index bfdb568..f2df625 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -21,6 +21,7 @@ #include <linux/binfmts.h>
+ #include <linux/security.h>
+ #include <linux/syscalls.h>
+ #include <linux/ptrace.h>
++#include <linux/compat_siginfo.h>
+ #include <linux/signal.h>
+ #include <linux/capability.h>
+ #include <asm/param.h>
+@@ -2038,17 +2039,35 @@ sys_rt_sigpending(sigset_t __user *set,
+ return do_sigpending(set, sigsetsize);
+ }
+
++#ifndef HAVE_ARCH_COPY_SIGINFO_FROM_USER
++
++int copy_siginfo_from_user(siginfo_t *to, siginfo_t __user *from)
++{
++ if(is_compat_task())
++ return compat_copy_siginfo_from_user(to,(compat_siginfo_t __user *)from);
++
++ return copy_from_user(&to, from, sizeof(siginfo_t));
++}
++
++#endif
++
+ #ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER
+
+ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)
+ {
+ int err;
+
++ /* Use compat_siginfo_t with 32-bit signals */
++ if(is_compat_task()){
++ return compat_copy_siginfo_to_user((compat_siginfo_t __user *)to,from);
++ }
++
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t))
+ ? -EFAULT : 0;
++
+ /*
+ * If you change siginfo_t structure, please be sure
+ * this code is fixed accordingly.
+@@ -2263,7 +2282,7 @@ sys_rt_sigqueueinfo(int pid, int sig, si
+ {
+ siginfo_t info;
+
+- if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
++ if (copy_siginfo_from_user(&info, uinfo))
+ return -EFAULT;
+
+ /* Not even root can pretend to send signals from the kernel.
+diff --git a/mm/Kconfig b/mm/Kconfig
+index 8f5b456..aadd1c3 100644
+--- a/mm/Kconfig
++++ b/mm/Kconfig
+@@ -148,7 +148,7 @@ config MIGRATION
+ the page.
+
+ config RESOURCES_64BIT
+- bool "64 bit Memory and IO resources (EXPERIMENTAL)" if (!64BIT && EXPERIMENTAL)
++ bool "64 bit Memory and IO resources (EXPERIMENTAL)" if (!64BIT && !PARISC && EXPERIMENTAL)
+ default 64BIT
+ help
+ This option allows memory and IO resources to be 64 bit.
+diff --git a/mm/shmem.c b/mm/shmem.c
+index db21c51..5e96f34 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -625,7 +625,7 @@ done2:
+ }
+ }
+
+-static void shmem_truncate(struct inode *inode)
++/* static gcc-3.3 OPD bug - GGG */ void shmem_truncate(struct inode *inode)
+ {
+ shmem_truncate_range(inode, inode->i_size, (loff_t)-1);
+ }
Added: people/maks-guest/linux-2.6/debian/patches/ia64-irq-affinity-upfix.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/ia64-irq-affinity-upfix.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,18 @@
+## DP: Description: Add a no-op set_irq_affinity_info() for non-SMP
+## DP: Patch author: dann frazier <dannf at hp.com>
+## DP: Upstream status: Submitted
+#
+--- linux-2.6-2.6.13/arch/ia64/kernel/irq.c~ 2005-10-20 17:28:56.000000000 -0600
++++ linux-2.6-2.6.13/arch/ia64/kernel/irq.c 2005-10-20 17:29:41.000000000 -0600
+@@ -105,6 +105,11 @@
+ irq_redir[irq] = (char) (redir & 0xff);
+ }
+ }
++
++#else /* !CONFIG_SMP */
++void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
++{
++}
+ #endif /* CONFIG_SMP */
+
+ #ifdef CONFIG_HOTPLUG_CPU
Added: people/maks-guest/linux-2.6/debian/patches/m68k-2.6.18.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/m68k-2.6.18.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,5549 @@
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/Makefile linux-m68k/Makefile
+--- linux-i386/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/Makefile 2006-09-24 16:30:54.000000000 +0200
+@@ -173,7 +173,7 @@
+ # Default value for CROSS_COMPILE is not to prefix executables
+ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+
+-ARCH ?= $(SUBARCH)
++ARCH ?= m68k
+ CROSS_COMPILE ?=
+
+ # Architecture as present in compile.h
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/Kconfig linux-m68k/arch/m68k/Kconfig
+--- linux-i386/arch/m68k/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/Kconfig 2006-09-05 16:31:20.000000000 +0200
+@@ -344,8 +344,9 @@
+ adventurous.
+
+ config SINGLE_MEMORY_CHUNK
+- bool "Use one physical chunk of memory only"
+- depends on ADVANCED && !SUN3
++ bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
++ default y if SUN3
++ select NEED_MULTIPLE_NODES
+ help
+ Ignore all but the first contiguous chunk of physical memory for VM
+ purposes. This will save a few bytes kernel size and may speed up
+@@ -366,6 +367,14 @@
+ is hardwired on. The 53c710 SCSI driver is known to suffer from
+ this problem.
+
++config ARCH_DISCONTIGMEM_ENABLE
++ def_bool !SINGLE_MEMORY_CHUNK
++
++config NODES_SHIFT
++ int
++ default "3"
++ depends on !SINGLE_MEMORY_CHUNK
++
+ source "mm/Kconfig"
+
+ endmenu
+@@ -600,7 +609,7 @@
+
+ config SERIAL167
+ bool "CD2401 support for MVME166/7 serial ports"
+- depends on MVME16x && BROKEN
++ depends on MVME16x
+ help
+ This is the driver for the serial ports on the Motorola MVME166,
+ 167, and 172 boards. Everyone using one of these boards should say
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/Makefile linux-m68k/arch/m68k/Makefile
+--- linux-i386/arch/m68k/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/Makefile 2006-06-06 01:17:27.000000000 +0200
+@@ -19,6 +19,7 @@
+ # override top level makefile
+ AS += -m68020
+ LDFLAGS := -m m68kelf
++LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
+ ifneq ($(COMPILE_ARCH),$(ARCH))
+ # prefix for cross-compiling binaries
+ CROSS_COMPILE = m68k-linux-
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/atari/ataints.c linux-m68k/arch/m68k/atari/ataints.c
+--- linux-i386/arch/m68k/atari/ataints.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/atari/ataints.c 2006-09-05 16:31:20.000000000 +0200
+@@ -332,6 +332,9 @@
+ atari_disable_irq(irq);
+ atari_turnoff_irq(irq);
+ m68k_irq_shutdown(irq);
++
++ if (irq == IRQ_AUTO_4)
++ vectors[VEC_INT4] = falcon_hblhandler;
+ }
+
+ static struct irq_controller atari_irq_controller = {
+@@ -356,7 +359,7 @@
+
+ void __init atari_init_IRQ(void)
+ {
+- m68k_setup_user_interrupt(VEC_USER, 192, NULL);
++ m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL);
+ m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
+
+ /* Initialize the MFP(s) */
+@@ -403,8 +406,10 @@
+ * gets overruns)
+ */
+
+- if (!MACH_IS_HADES)
++ if (!MACH_IS_HADES) {
+ vectors[VEC_INT2] = falcon_hblhandler;
++ vectors[VEC_INT4] = falcon_hblhandler;
++ }
+ }
+
+ if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/atari/time.c linux-m68k/arch/m68k/atari/time.c
+--- linux-i386/arch/m68k/atari/time.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/atari/time.c 2006-09-05 16:31:20.000000000 +0200
+@@ -16,6 +16,7 @@
+ #include <linux/init.h>
+ #include <linux/rtc.h>
+ #include <linux/bcd.h>
++#include <linux/delay.h>
+
+ #include <asm/atariints.h>
+
+@@ -212,8 +213,12 @@
+ * additionally the RTC_SET bit is set to prevent an update cycle.
+ */
+
+- while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP )
+- schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
++ while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
++ if (in_atomic() || irqs_disabled())
++ mdelay(1);
++ else
++ schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
++ }
+
+ local_irq_save(flags);
+ RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/bios32.c linux-m68k/arch/m68k/kernel/bios32.c
+--- linux-i386/arch/m68k/kernel/bios32.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/bios32.c 2006-09-24 16:31:35.000000000 +0200
+@@ -284,7 +284,7 @@
+
+ DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
+
+- if (!bus->devices && !bus->children)
++ if (list_empty(&bus->devices) && list_empty(&bus->children))
+ return;
+
+ /*
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/entry.S linux-m68k/arch/m68k/kernel/entry.S
+--- linux-i386/arch/m68k/kernel/entry.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/entry.S 2006-09-24 16:31:35.000000000 +0200
+@@ -706,4 +706,9 @@
+ .long sys_add_key
+ .long sys_request_key /* 280 */
+ .long sys_keyctl
++ .long sys_ioprio_set
++ .long sys_ioprio_get
++ .long sys_inotify_init
++ .long sys_inotify_add_watch /* 285 */
++ .long sys_inotify_rm_watch
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/ints.c linux-m68k/arch/m68k/kernel/ints.c
+--- linux-i386/arch/m68k/kernel/ints.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/ints.c 2006-09-24 16:31:35.000000000 +0200
+@@ -131,6 +131,7 @@
+ {
+ int i;
+
++ BUG_ON(IRQ_USER + cnt >= NR_IRQS);
+ m68k_first_user_vec = vec;
+ for (i = 0; i < cnt; i++)
+ irq_controller[IRQ_USER + i] = &user_irq_controller;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/m68k_ksyms.c linux-m68k/arch/m68k/kernel/m68k_ksyms.c
+--- linux-i386/arch/m68k/kernel/m68k_ksyms.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/m68k_ksyms.c 2006-09-24 16:31:36.000000000 +0200
+@@ -1,7 +1,6 @@
+ #include <linux/module.h>
+ #include <linux/linkage.h>
+ #include <linux/sched.h>
+-#include <linux/string.h>
+ #include <linux/mm.h>
+ #include <linux/user.h>
+ #include <linux/elfcore.h>
+@@ -32,13 +31,6 @@
+ #ifndef CONFIG_SUN3
+ EXPORT_SYMBOL(cache_push);
+ EXPORT_SYMBOL(cache_clear);
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-EXPORT_SYMBOL(mm_vtop);
+-EXPORT_SYMBOL(mm_ptov);
+-EXPORT_SYMBOL(mm_end_of_chunk);
+-#else
+-EXPORT_SYMBOL(m68k_memoffset);
+-#endif /* !CONFIG_SINGLE_MEMORY_CHUNK */
+ EXPORT_SYMBOL(__ioremap);
+ EXPORT_SYMBOL(iounmap);
+ EXPORT_SYMBOL(kernel_set_cachemode);
+@@ -53,9 +45,6 @@
+ #endif
+ EXPORT_SYMBOL(dump_fpu);
+ EXPORT_SYMBOL(dump_thread);
+-EXPORT_SYMBOL(strnlen);
+-EXPORT_SYMBOL(strrchr);
+-EXPORT_SYMBOL(strstr);
+ EXPORT_SYMBOL(kernel_thread);
+ #ifdef CONFIG_VME
+ EXPORT_SYMBOL(vme_brdtype);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/module.c linux-m68k/arch/m68k/kernel/module.c
+--- linux-i386/arch/m68k/kernel/module.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/module.c 2006-09-05 16:31:20.000000000 +0200
+@@ -1,3 +1,9 @@
++/*
++ * 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/moduleloader.h>
+ #include <linux/elf.h>
+ #include <linux/vmalloc.h>
+@@ -116,10 +122,29 @@
+ return 0;
+ }
+
++void module_fixup(struct module *mod, struct m68k_fixup_info *start,
++ struct m68k_fixup_info *end)
++{
++ struct m68k_fixup_info *fixup;
++
++ for (fixup = start; fixup < end; fixup++) {
++ switch (fixup->type) {
++ case m68k_fixup_memoffset:
++ *(u32 *)fixup->addr = m68k_memoffset;
++ break;
++ case m68k_fixup_vnode_shift:
++ *(u16 *)fixup->addr += m68k_virt_to_node_shift;
++ break;
++ }
++ }
++}
++
+ int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+- struct module *me)
++ struct module *mod)
+ {
++ module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
++
+ return 0;
+ }
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/module.lds linux-m68k/arch/m68k/kernel/module.lds
+--- linux-i386/arch/m68k/kernel/module.lds 1970-01-01 01:00:00.000000000 +0100
++++ linux-m68k/arch/m68k/kernel/module.lds 2006-06-06 01:17:28.000000000 +0200
+@@ -0,0 +1,7 @@
++SECTIONS {
++ .m68k_fixup : {
++ __start_fixup = .;
++ *(.m68k_fixup)
++ __stop_fixup = .;
++ }
++}
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/setup.c linux-m68k/arch/m68k/kernel/setup.c
+--- linux-i386/arch/m68k/kernel/setup.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/setup.c 2006-09-24 16:31:36.000000000 +0200
+@@ -58,7 +58,7 @@
+ unsigned long m68k_memoffset;
+ struct mem_info m68k_memory[NUM_MEMINFO];
+
+-static struct mem_info m68k_ramdisk;
++struct mem_info m68k_ramdisk;
+
+ static char m68k_command_line[CL_SIZE];
+
+@@ -196,9 +196,6 @@
+ void __init setup_arch(char **cmdline_p)
+ {
+ extern int _etext, _edata, _end;
+-#ifndef CONFIG_SUN3
+- unsigned long endmem, startmem;
+-#endif
+ int i;
+ char *p, *q;
+
+@@ -339,30 +336,16 @@
+ panic ("No configuration setup");
+ }
+
+-#ifndef CONFIG_SUN3
+- startmem= m68k_memory[0].addr;
+- endmem = startmem + m68k_memory[0].size;
+- high_memory = (void *)PAGE_OFFSET;
+- for (i = 0; i < m68k_num_memory; i++) {
+- m68k_memory[i].size &= MASK_256K;
+- if (m68k_memory[i].addr < startmem)
+- startmem = m68k_memory[i].addr;
+- if (m68k_memory[i].addr+m68k_memory[i].size > endmem)
+- endmem = m68k_memory[i].addr+m68k_memory[i].size;
+- high_memory += m68k_memory[i].size;
+- }
+-
+- availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT,
+- startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT);
+-
+- for (i = 0; i < m68k_num_memory; i++)
+- free_bootmem(m68k_memory[i].addr, m68k_memory[i].size);
+-
+- reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr);
++ paging_init();
+
++#ifndef CONFIG_SUN3
++ for (i = 1; i < m68k_num_memory; i++)
++ free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
++ m68k_memory[i].size);
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (m68k_ramdisk.size) {
+- reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size);
++ reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
++ m68k_ramdisk.addr, m68k_ramdisk.size);
+ initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
+ initrd_end = initrd_start + m68k_ramdisk.size;
+ printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
+@@ -381,8 +364,6 @@
+
+ #endif /* !CONFIG_SUN3 */
+
+- paging_init();
+-
+ /* set ISA defs early as possible */
+ #if defined(CONFIG_ISA) && defined(MULTI_ISA)
+ #if defined(CONFIG_Q40)
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/sun3-head.S linux-m68k/arch/m68k/kernel/sun3-head.S
+--- linux-i386/arch/m68k/kernel/sun3-head.S 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/sun3-head.S 2006-05-11 13:14:10.000000000 +0200
+@@ -66,17 +66,7 @@
+ /* Following code executes at high addresses (0xE000xxx). */
+ 1: lea init_task,%curptr | get initial thread...
+ lea init_thread_union+THREAD_SIZE,%sp | ...and its stack.
+-
+-/* copy bootinfo records from the loader to _end */
+- lea _end, %a1
+- lea BI_START, %a0
+- /* number of longs to copy */
+- movel %a0@, %d0
+-1: addl #4, %a0
+- movel %a0@, %a1@
+- addl #4, %a1
+- dbf %d0, 1b
+-
++
+ /* Point MSP at an invalid page to trap if it's used. --m */
+ movl #(PAGESIZE),%d0
+ movc %d0,%msp
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/vmlinux-std.lds linux-m68k/arch/m68k/kernel/vmlinux-std.lds
+--- linux-i386/arch/m68k/kernel/vmlinux-std.lds 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/vmlinux-std.lds 2006-06-06 01:17:28.000000000 +0200
+@@ -66,6 +66,11 @@
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
++ .m68k_fixup : {
++ __start_fixup = .;
++ *(.m68k_fixup)
++ __stop_fixup = .;
++ }
+ SECURITY_INIT
+ . = ALIGN(8192);
+ __initramfs_start = .;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/kernel/vmlinux-sun3.lds linux-m68k/arch/m68k/kernel/vmlinux-sun3.lds
+--- linux-i386/arch/m68k/kernel/vmlinux-sun3.lds 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/kernel/vmlinux-sun3.lds 2006-06-06 01:17:28.000000000 +0200
+@@ -8,7 +8,7 @@
+ jiffies = jiffies_64 + 4;
+ SECTIONS
+ {
+- . = 0xE004000;
++ . = 0xE002000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.head)
+@@ -60,6 +60,11 @@
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
++ .m68k_fixup : {
++ __start_fixup = .;
++ *(.m68k_fixup)
++ __stop_fixup = .;
++ }
+ SECURITY_INIT
+ . = ALIGN(8192);
+ __initramfs_start = .;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/lib/string.c linux-m68k/arch/m68k/lib/string.c
+--- linux-i386/arch/m68k/lib/string.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/lib/string.c 2006-09-05 16:31:20.000000000 +0200
+@@ -1,6 +1,19 @@
++/*
++ * 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.
++ */
++
++#define __IN_STRING_C
+
+-#include <linux/types.h>
+ #include <linux/module.h>
++#include <linux/string.h>
++
++char *strcpy(char *dest, const char *src)
++{
++ return __kernel_strcpy(dest, src);
++}
++EXPORT_SYMBOL(strcpy);
+
+ void *memset(void *s, int c, size_t count)
+ {
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/lib/uaccess.c linux-m68k/arch/m68k/lib/uaccess.c
+--- linux-i386/arch/m68k/lib/uaccess.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/lib/uaccess.c 2006-09-27 16:31:43.000000000 +0200
+@@ -84,7 +84,7 @@
+ " .even\n"
+ "20: lsl.l #2,%0\n"
+ "50: add.l %5,%0\n"
+- " jra 7b\n"
++ " jra 8b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/mm/init.c linux-m68k/arch/m68k/mm/init.c
+--- linux-i386/arch/m68k/mm/init.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/mm/init.c 2006-09-24 16:31:37.000000000 +0200
+@@ -7,6 +7,7 @@
+ * to motorola.c and sun3mmu.c
+ */
+
++#include <linux/module.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+@@ -31,6 +32,37 @@
+
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
++static bootmem_data_t __initdata bootmem_data[MAX_NUMNODES];
++
++pg_data_t pg_data_map[MAX_NUMNODES];
++EXPORT_SYMBOL(pg_data_map);
++
++int m68k_virt_to_node_shift;
++
++#ifndef CONFIG_SINGLE_MEMORY_CHUNK
++pg_data_t *pg_data_table[65];
++EXPORT_SYMBOL(pg_data_table);
++#endif
++
++void m68k_setup_node(int node)
++{
++#ifndef CONFIG_SINGLE_MEMORY_CHUNK
++ struct mem_info *info = m68k_memory + node;
++ int i, end;
++
++ i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift();
++ end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift();
++ for (; i <= end; i++) {
++ if (pg_data_table[i])
++ printk("overlap at %u for chunk %u\n", i, node);
++ pg_data_table[i] = pg_data_map + node;
++ }
++#endif
++ pg_data_map[node].bdata = bootmem_data + node;
++ node_set_online(node);
++}
++
++
+ /*
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+@@ -40,52 +72,51 @@
+
+ void show_mem(void)
+ {
+- unsigned long i;
+- int free = 0, total = 0, reserved = 0, shared = 0;
+- int cached = 0;
+-
+- printk("\nMem-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 free pages\n",free);
+- printk("%d reserved pages\n",reserved);
+- printk("%d pages shared\n",shared);
+- printk("%d pages swap cached\n",cached);
++ pg_data_t *pgdat;
++ int free = 0, total = 0, reserved = 0, shared = 0;
++ int cached = 0;
++ int i;
++
++ printk("\nMem-info:\n");
++ show_free_areas();
++ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
++ for_each_online_pgdat(pgdat) {
++ for (i = 0; i < pgdat->node_spanned_pages; i++) {
++ struct page *page = pgdat->node_mem_map + i;
++ total++;
++ if (PageReserved(page))
++ reserved++;
++ else if (PageSwapCache(page))
++ cached++;
++ else if (!page_count(page))
++ free++;
++ else
++ shared += page_count(page) - 1;
++ }
++ }
++ printk("%d pages of RAM\n",total);
++ printk("%d free pages\n",free);
++ printk("%d reserved pages\n",reserved);
++ printk("%d pages shared\n",shared);
++ printk("%d pages swap cached\n",cached);
+ }
+
+ extern void init_pointer_table(unsigned long ptable);
+
+ /* References to section boundaries */
+
+-extern char _text, _etext, _edata, __bss_start, _end;
+-extern char __init_begin, __init_end;
++extern char _text[], _etext[];
++extern char __init_begin[], __init_end[];
+
+ extern pmd_t *zero_pgtable;
+
+ void __init mem_init(void)
+ {
++ pg_data_t *pgdat;
+ int codepages = 0;
+ int datapages = 0;
+ int initpages = 0;
+- unsigned long tmp;
+-#ifndef CONFIG_SUN3
+ int i;
+-#endif
+-
+- max_mapnr = num_physpages = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT);
+
+ #ifdef CONFIG_ATARI
+ if (MACH_IS_ATARI)
+@@ -93,19 +124,25 @@
+ #endif
+
+ /* this will put all memory onto the freelists */
+- totalram_pages = free_all_bootmem();
+-
+- for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) {
+- if (PageReserved(virt_to_page(tmp))) {
+- if (tmp >= (unsigned long)&_text
+- && tmp < (unsigned long)&_etext)
++ totalram_pages = num_physpages = 0;
++ for_each_online_pgdat(pgdat) {
++ num_physpages += pgdat->node_present_pages;
++
++ totalram_pages += free_all_bootmem_node(pgdat);
++ for (i = 0; i < pgdat->node_spanned_pages; i++) {
++ struct page *page = pgdat->node_mem_map + i;
++ char *addr = page_to_virt(page);
++
++ if (!PageReserved(page))
++ continue;
++ if (addr >= _text &&
++ addr < _etext)
+ codepages++;
+- else if (tmp >= (unsigned long) &__init_begin
+- && tmp < (unsigned long) &__init_end)
++ else if (addr >= __init_begin &&
++ addr < __init_end)
+ initpages++;
+ else
+ datapages++;
+- continue;
+ }
+ }
+
+@@ -124,7 +161,7 @@
+
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
+ (unsigned long)nr_free_pages() << (PAGE_SHIFT-10),
+- max_mapnr << (PAGE_SHIFT-10),
++ totalram_pages << (PAGE_SHIFT-10),
+ codepages << (PAGE_SHIFT-10),
+ datapages << (PAGE_SHIFT-10),
+ initpages << (PAGE_SHIFT-10));
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/mm/memory.c linux-m68k/arch/m68k/mm/memory.c
+--- linux-i386/arch/m68k/mm/memory.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/mm/memory.c 2006-09-24 16:31:37.000000000 +0200
+@@ -126,67 +126,6 @@
+ return 0;
+ }
+
+-#ifdef DEBUG_INVALID_PTOV
+-int mm_inv_cnt = 5;
+-#endif
+-
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-/*
+- * The following two routines map from a physical address to a kernel
+- * virtual address and vice versa.
+- */
+-unsigned long mm_vtop(unsigned long vaddr)
+-{
+- int i=0;
+- unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
+-
+- do {
+- if (voff < m68k_memory[i].size) {
+-#ifdef DEBUGPV
+- printk ("VTOP(%p)=%lx\n", vaddr,
+- m68k_memory[i].addr + voff);
+-#endif
+- return m68k_memory[i].addr + voff;
+- }
+- voff -= m68k_memory[i].size;
+- } while (++i < m68k_num_memory);
+-
+- /* As a special case allow `__pa(high_memory)'. */
+- if (voff == 0)
+- return m68k_memory[i-1].addr + m68k_memory[i-1].size;
+-
+- return -1;
+-}
+-#endif
+-
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-unsigned long mm_ptov (unsigned long paddr)
+-{
+- int i = 0;
+- unsigned long poff, voff = PAGE_OFFSET;
+-
+- do {
+- poff = paddr - m68k_memory[i].addr;
+- if (poff < m68k_memory[i].size) {
+-#ifdef DEBUGPV
+- printk ("PTOV(%lx)=%lx\n", paddr, poff + voff);
+-#endif
+- return poff + voff;
+- }
+- voff += m68k_memory[i].size;
+- } while (++i < m68k_num_memory);
+-
+-#ifdef DEBUG_INVALID_PTOV
+- if (mm_inv_cnt > 0) {
+- mm_inv_cnt--;
+- printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n",
+- paddr, __builtin_return_address(0));
+- }
+-#endif
+- return -1;
+-}
+-#endif
+-
+ /* invalidate page in both caches */
+ static inline void clear040(unsigned long paddr)
+ {
+@@ -350,15 +289,3 @@
+ mach_l2_flush(1);
+ #endif
+ }
+-
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-int mm_end_of_chunk (unsigned long addr, int len)
+-{
+- int i;
+-
+- for (i = 0; i < m68k_num_memory; i++)
+- if (m68k_memory[i].addr + m68k_memory[i].size == addr + len)
+- return 1;
+- return 0;
+-}
+-#endif
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/mm/motorola.c linux-m68k/arch/m68k/mm/motorola.c
+--- linux-i386/arch/m68k/mm/motorola.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/mm/motorola.c 2006-09-24 16:31:37.000000000 +0200
+@@ -43,6 +43,12 @@
+ EXPORT_SYMBOL(mm_cachebits);
+ #endif
+
++/* size of memory already mapped in head.S */
++#define INIT_MAPPED_SIZE (4UL<<20)
++
++extern unsigned long availmem;
++extern struct mem_info m68k_ramdisk;
++
+ static pte_t * __init kernel_page_table(void)
+ {
+ pte_t *ptablep;
+@@ -98,19 +104,20 @@
+ return last_pgtable;
+ }
+
+-static unsigned long __init
+-map_chunk (unsigned long addr, long size)
++static void __init map_node(int node)
+ {
+ #define PTRTREESIZE (256*1024)
+ #define ROOTTREESIZE (32*1024*1024)
+- static unsigned long virtaddr = PAGE_OFFSET;
+- unsigned long physaddr;
++ unsigned long physaddr, virtaddr, size;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+- physaddr = (addr | m68k_supervisor_cachemode |
+- _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
++ size = m68k_memory[node].size;
++ physaddr = m68k_memory[node].addr;
++ virtaddr = (unsigned long)phys_to_virt(physaddr);
++ physaddr |= m68k_supervisor_cachemode |
++ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY;
+ if (CPU_IS_040_OR_060)
+ physaddr |= _PAGE_GLOBAL040;
+
+@@ -190,8 +197,6 @@
+ #ifdef DEBUG
+ printk("\n");
+ #endif
+-
+- return virtaddr;
+ }
+
+ /*
+@@ -200,15 +205,16 @@
+ */
+ void __init paging_init(void)
+ {
+- int chunk;
+- unsigned long mem_avail = 0;
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
++ unsigned long min_addr, max_addr;
++ unsigned long addr, size, end;
++ int i;
+
+ #ifdef DEBUG
+ {
+ extern unsigned long availmem;
+- printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
+- kernel_pg_dir, availmem, start_mem, end_mem);
++ printk ("start of paging_init (%p, %lx)\n",
++ kernel_pg_dir, availmem);
+ }
+ #endif
+
+@@ -222,24 +228,62 @@
+ pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
+ }
+
++ min_addr = m68k_memory[0].addr;
++ max_addr = min_addr + m68k_memory[0].size;
++ for (i = 1; i < m68k_num_memory;) {
++ if (m68k_memory[i].addr < min_addr) {
++ printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n",
++ m68k_memory[i].addr, m68k_memory[i].size);
++ printk("Fix your bootloader or use a memfile to make use of this area!\n");
++ m68k_num_memory--;
++ memmove(m68k_memory + i, m68k_memory + i + 1,
++ (m68k_num_memory - i) * sizeof(struct mem_info));
++ continue;
++ }
++ addr = m68k_memory[i].addr + m68k_memory[i].size;
++ if (addr > max_addr)
++ max_addr = addr;
++ i++;
++ }
++ m68k_memoffset = min_addr - PAGE_OFFSET;
++ m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6;
++
++ module_fixup(NULL, __start_fixup, __stop_fixup);
++ flush_icache();
++
++ high_memory = phys_to_virt(max_addr);
++
++ min_low_pfn = availmem >> PAGE_SHIFT;
++ max_low_pfn = max_addr >> PAGE_SHIFT;
++
++ for (i = 0; i < m68k_num_memory; i++) {
++ addr = m68k_memory[i].addr;
++ end = addr + m68k_memory[i].size;
++ m68k_setup_node(i);
++ availmem = PAGE_ALIGN(availmem);
++ availmem += init_bootmem_node(NODE_DATA(i),
++ availmem >> PAGE_SHIFT,
++ addr >> PAGE_SHIFT,
++ end >> PAGE_SHIFT);
++ }
++
+ /*
+ * Map the physical memory available into the kernel virtual
+- * address space. It may allocate some memory for page
+- * tables and thus modify availmem.
++ * address space. First initialize the bootmem allocator with
++ * the memory we already mapped, so map_node() has something
++ * to allocate.
+ */
++ addr = m68k_memory[0].addr;
++ size = m68k_memory[0].size;
++ free_bootmem_node(NODE_DATA(0), availmem, min(INIT_MAPPED_SIZE, size) - (availmem - addr));
++ map_node(0);
++ if (size > INIT_MAPPED_SIZE)
++ free_bootmem_node(NODE_DATA(0), addr + INIT_MAPPED_SIZE, size - INIT_MAPPED_SIZE);
+
+- for (chunk = 0; chunk < m68k_num_memory; chunk++) {
+- mem_avail = map_chunk (m68k_memory[chunk].addr,
+- m68k_memory[chunk].size);
+-
+- }
++ for (i = 1; i < m68k_num_memory; i++)
++ map_node(i);
+
+ flush_tlb_all();
+-#ifdef DEBUG
+- printk ("memory available is %ldKB\n", mem_avail >> 10);
+- printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
+- start_mem, end_mem);
+-#endif
+
+ /*
+ * initialize the bad page table and bad page to point
+@@ -256,14 +300,11 @@
+ #ifdef DEBUG
+ printk ("before free_area_init\n");
+ #endif
+- zones_size[ZONE_DMA] = (mach_max_dma_address < (unsigned long)high_memory ?
+- (mach_max_dma_address+1) : (unsigned long)high_memory);
+- zones_size[ZONE_NORMAL] = (unsigned long)high_memory - zones_size[0];
+-
+- zones_size[ZONE_DMA] = (zones_size[ZONE_DMA] - PAGE_OFFSET) >> PAGE_SHIFT;
+- zones_size[ZONE_NORMAL] >>= PAGE_SHIFT;
+-
+- free_area_init(zones_size);
++ for (i = 0; i < m68k_num_memory; i++) {
++ zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT;
++ free_area_init_node(i, pg_data_map + i, zones_size,
++ m68k_memory[i].addr >> PAGE_SHIFT, NULL);
++ }
+ }
+
+ extern char __init_begin, __init_end;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/mm/sun3mmu.c linux-m68k/arch/m68k/mm/sun3mmu.c
+--- linux-i386/arch/m68k/mm/sun3mmu.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/mm/sun3mmu.c 2006-05-11 13:14:11.000000000 +0200
+@@ -49,7 +49,6 @@
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+ unsigned long size;
+
+-
+ #ifdef TEST_VERIFY_AREA
+ wp_works_ok = 0;
+ #endif
+@@ -94,7 +93,11 @@
+ /* memory sizing is a hack stolen from motorola.c.. hope it works for us */
+ zones_size[ZONE_DMA] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+
+- free_area_init(zones_size);
++ /* I really wish I knew why the following change made things better... -- Sam */
++/* free_area_init(zones_size); */
++ free_area_init_node(0, NODE_DATA(0), zones_size,
++ (__pa(PAGE_OFFSET) >> PAGE_SHIFT) + 1, NULL);
++
+
+ }
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/arch/m68k/sun3/config.c linux-m68k/arch/m68k/sun3/config.c
+--- linux-i386/arch/m68k/sun3/config.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/arch/m68k/sun3/config.c 2006-09-24 16:31:37.000000000 +0200
+@@ -21,6 +21,7 @@
+ #include <asm/contregs.h>
+ #include <asm/movs.h>
+ #include <asm/pgtable.h>
++#include <asm/pgalloc.h>
+ #include <asm/sun3-head.h>
+ #include <asm/sun3mmu.h>
+ #include <asm/rtc.h>
+@@ -127,6 +128,7 @@
+ high_memory = (void *)memory_end;
+ availmem = memory_start;
+
++ m68k_setup_node(0);
+ availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
+ availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/char/16c552.h linux-m68k/drivers/char/16c552.h
+--- linux-i386/drivers/char/16c552.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-m68k/drivers/char/16c552.h 2001-10-22 11:34:32.000000000 +0200
+@@ -0,0 +1,165 @@
++/*
++ * Definitions for the 16c552 DACE
++ * (dual-asynchronous-communications-element) used on the GVP
++ * IO-Extender.
++ *
++ * Basically this is two 16c550 uarts's and a parallel port, which is
++ * why the serial definitions should be valid for the 16c550 uart
++ * aswell.
++ *
++ * Data was taken from National Semiconductors duart 16c552
++ * data-sheets and the Texas Instruments DACE 16c552 data-sheets (the
++ * NS version of the chip is _non_ standard and their data-sheets did
++ * cost me several wasted hours of work).
++ *
++ * This file is (C) 1995 Jes Sorensen (jds at kom.auc.dk)
++ *
++ * Moved from drivers/char/ to include/linux/, because it's useful
++ * on more than just the one card. I'm using it on the hp300 DCA
++ * serial driver, for example.
++ * -- Peter Maydell <pmaydell at chiark.greenend.org.uk> 05/1998
++ */
++
++#ifndef _16C552_H_
++#define _16C552_H_
++
++/* Serial stuff */
++
++struct uart_16c550 {
++ volatile u_char skip0;
++ volatile u_char RBR;
++ volatile u_char skip1;
++ volatile u_char IER;
++ volatile u_char skip2;
++ volatile u_char IIR;
++ volatile u_char skip3;
++ volatile u_char LCR;
++ volatile u_char skip4;
++ volatile u_char MCR;
++ volatile u_char skip5;
++ volatile u_char LSR;
++ volatile u_char skip6;
++ volatile u_char MSR;
++ volatile u_char skip7;
++ volatile u_char SCR;
++};
++
++#define THR RBR
++#define FCR IIR
++#define DLL RBR
++#define DLM IER
++#define AFR IIR
++
++/*
++ * Bit-defines for the various registers.
++ */
++
++
++/* IER */
++
++#define ERDAI (1<<0)
++#define ETHREI (1<<1)
++#define ELSI (1<<2)
++#define EMSI (1<<3)
++
++/* IIR - Interrupt Ident. Register */
++
++#define IRQ_PEND (1<<0) /* NOTE: IRQ_PEND=0 implies irq pending */
++#define IRQ_ID1 (1<<1)
++#define IRQ_ID2 (1<<2)
++#define IRQ_ID3 (1<<3)
++#define FIFO_ENA0 (1<<6) /* Both these are set when FCR(1<<0)=1 */
++#define FIFO_ENA1 (1<<7)
++
++#define IRQ_RLS (IRQ_ID1 | IRQ_ID2)
++#define IRQ_RDA (IRQ_ID2)
++#define IRQ_CTI (IRQ_ID2 | IRQ_ID3)
++#define IRQ_THRE (IRQ_ID1)
++#define IRQ_MS 0
++
++/* FCR - FIFO Control Register */
++
++#define FIFO_ENA (1<<0)
++#define RCVR_FIFO_RES (1<<1)
++#define XMIT_FIFO_RES (1<<2)
++#define DMA_MODE_SEL (1<<3)
++#define RCVR_TRIG_LSB (1<<6)
++#define RCVR_TRIG_MSB (1<<7)
++
++#define FIFO_TRIG_1 0x00
++#define FIFO_TRIG_4 RCVR_TRIG_LSB
++#define FIFO_TRIG_8 RCVR_TRIG_MSB
++#define FIFO_TRIG_14 RCVR_TRIG_LSB|RCVR_TRIG_MSB
++
++/* LCR - Line Control Register */
++
++#define WLS0 (1<<0)
++#define WLS1 (1<<1)
++#define STB (1<<2)
++#define PEN (1<<3)
++#define EPS (1<<4)
++#define STICK_PARITY (1<<5)
++#define SET_BREAK (1<<6)
++#define DLAB (1<<7)
++
++#define data_5bit 0x00
++#define data_6bit 0x01
++#define data_7bit 0x02
++#define data_8bit 0x03
++
++
++/* MCR - Modem Control Register */
++
++#define DTR (1<<0)
++#define RTS (1<<1)
++#define OUT1 (1<<2)
++#define OUT2 (1<<3)
++#define LOOP (1<<4)
++
++/* LSR - Line Status Register */
++
++#define DR (1<<0)
++#define OE (1<<1)
++#define PE (1<<2)
++#define FE (1<<3)
++#define BI (1<<4)
++#define THRE (1<<5)
++#define TEMT (1<<6)
++#define RCVR_FIFO_ERR (1<<7)
++
++/* MSR - Modem Status Register */
++
++#define DCTS (1<<0)
++#define DDSR (1<<1)
++#define TERI (1<<2)
++#define DDCD (1<<3)
++#define CTS (1<<4)
++#define DSR (1<<5)
++#define RING_I (1<<6)
++#define DCD (1<<7)
++
++/* AFR - Alternate Function Register */
++
++#define CONCUR_WRITE (1<<0)
++#define BAUDOUT (1<<1)
++#define RXRDY (1<<2)
++
++/* Parallel stuff */
++
++/*
++ * Unfortunately National Semiconductors did not supply the
++ * specifications for the parallel port in the chip :-(
++ * TI succed though, so here they are :-)
++ *
++ * Defines for the bits can be found by including <linux/lp.h>
++ */
++struct IOEXT_par {
++ volatile u_char skip0;
++ volatile u_char DATA;
++ volatile u_char skip1;
++ volatile u_char STATUS;
++ volatile u_char skip2;
++ volatile u_char CTRL;
++};
++
++#endif
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/char/ioext.h linux-m68k/drivers/char/ioext.h
+--- linux-i386/drivers/char/ioext.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-m68k/drivers/char/ioext.h 2001-10-22 11:34:32.000000000 +0200
+@@ -0,0 +1,108 @@
++/*
++ * Shared data structure for GVP IO-Extender support.
++ *
++ * Merge of ioext.h and ser_ioext.h
++ */
++#ifndef _IOEXT_H_
++#define _IOEXT_H_
++
++#include <linux/config.h>
++#include <linux/netdevice.h>
++
++#include "16c552.h"
++
++#define MAX_IOEXT 5 /*
++ * The maximum number of io-extenders is 5, as you
++ * can't have more than 5 ZII boards in any Amiga.
++ */
++
++#define UART_CLK 7372800
++
++#define IOEXT_BAUD_BASE (UART_CLK / 16)
++
++#define IOEXT_MAX_LINES 2
++
++#define IOEXT_PAR_PLIP 0x0001
++#define IOEXT_PAR_LP 0x0002
++
++
++/*
++ * Macros for the serial driver.
++ */
++#define curruart(info) ((struct uart_16c550 *)(info->port))
++
++#define ser_DTRon(info) curruart(info)->MCR |= DTR
++#define ser_RTSon(info) curruart(info)->MCR |= RTS
++#define ser_DTRoff(info) curruart(info)->MCR &= ~DTR
++#define ser_RTSoff(info) curruart(info)->MCR &= ~RTS
++
++
++/*
++ * CNTR defines (copied from the GVP SCSI-driver file gvp11.h
++ */
++#define GVP_BUSY (1<<0)
++#define GVP_IRQ_PEND (1<<1)
++#define GVP_IRQ_ENA (1<<3)
++#define GVP_DIR_WRITE (1<<4)
++
++
++/*
++ * CTRL defines
++ */
++#define PORT0_MIDI (1<<0) /* CLR = DRIVERS SET = MIDI */
++#define PORT1_MIDI (1<<1) /* CLR = DRIVERS SET = MIDI */
++#define PORT0_DRIVER (1<<2) /* CLR = RS232, SET = MIDI */
++#define PORT1_DRIVER (1<<3) /* CLR = RS232, SET = MIDI */
++#define IRQ_SEL (1<<4) /* CLR = INT2, SET = INT6 */
++#define ROM_BANK_SEL (1<<5) /* CLR = LOW 32K, SET = HIGH 32K */
++#define PORT0_CTRL (1<<6) /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */
++#define PORT1_CTRL (1<<7) /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */
++
++
++/*
++ * This is the struct describing the registers on the IO-Extender.
++ * NOTE: The board uses a dual uart (16c552), which should be equal to
++ * two 16c550 uarts.
++ */
++typedef struct {
++ char gap0[0x41];
++ volatile unsigned char CNTR; /* GVP DMAC CNTR (status register) */
++ char gap1[0x11e];
++ struct uart_16c550 uart0; /* The first uart */
++ char gap2[0xf0];
++ struct uart_16c550 uart1; /* The second uart */
++ char gap3[0xf0];
++ struct IOEXT_par par; /* The parallel port */
++ char gap4[0xfb];
++ volatile unsigned char CTRL; /* The control-register on the board */
++} IOEXT_struct;
++
++
++typedef struct {
++ int num_uarts;
++ int line[IOEXT_MAX_LINES];
++ volatile struct uart_16c550 *uart[IOEXT_MAX_LINES];
++ IOEXT_struct *board;
++ int spurious_count;
++ unsigned char par_use; /* IOEXT_PAR_xxx */
++#if defined(CONFIG_GVPIOEXT_PLIP) || defined(CONFIG_GVPIOEXT_PLIP_MODULE)
++ struct nt_device *dev;
++#endif
++#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE)
++ struct lp_struct *lp_table;
++ int lp_dev;
++ int lp_interrupt;
++#endif
++} IOExtInfoType;
++
++/* Number of detected boards. */
++extern int ioext_num;
++extern IOExtInfoType ioext_info[MAX_IOEXT];
++
++void ioext_plip_interrupt(struct net_device *dev, int *spurious_count);
++void ioext_lp_interrupt(int dev, int *spurious_count);
++
++extern struct net_device ioext_dev_plip[3];
++extern struct lp_struct ioext_lp_table[1];
++
++#endif
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/char/mc68681.h linux-m68k/drivers/char/mc68681.h
+--- linux-i386/drivers/char/mc68681.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-m68k/drivers/char/mc68681.h 2001-10-22 11:34:32.000000000 +0200
+@@ -0,0 +1,131 @@
++#ifndef _MC68681_H_
++#define _MC68681_H_
++
++/*
++ * This describes an MC68681 DUART. It has almost only overlayed registers, which
++ * the structure very ugly.
++ * Note that the ri-register isn't really a register of the duart but a kludge of bsc
++ * to make the ring indicator available.
++ *
++ * The data came from the MFC-31-Developer Kit (from Ralph Seidel,
++ * zodiac at darkness.gun.de) and the data sheet of Phillip's clone device (SCN68681)
++ * (from Richard Hirst, srh at gpt.co.uk)
++ *
++ * 11.11.95 copyright Joerg Dorchain (dorchain at mpi-sb.mpg.de)
++ *
++ */
++
++struct duarthalf {
++union {
++volatile u_char mr1; /* rw */
++volatile u_char mr2; /* rw */
++} mr;
++volatile u_char ri; /* special, read */
++union {
++volatile u_char sr; /* read */
++volatile u_char csr; /* write */
++} sr_csr;
++u_char pad1;
++volatile u_char cr; /* write */
++u_char pad2;
++union {
++volatile u_char rhr; /* read */
++volatile u_char thr; /* write */
++} hr;
++u_char pad3;
++};
++
++struct duart {
++struct duarthalf pa;
++union {
++volatile u_char ipcr; /* read */
++volatile u_char acr; /* write */
++} ipcr_acr;
++u_char pad1;
++union {
++volatile u_char isr; /* read */
++volatile u_char imr; /* write */
++} ir;
++u_char pad2;
++volatile u_char ctu;
++u_char pad3;
++volatile u_char ctl;
++u_char pad4;
++struct duarthalf pb;
++volatile u_char ivr;
++u_char pad5;
++union {
++volatile u_char ipr; /* read */
++volatile u_char opcr; /* write */
++} ipr_opcr;
++u_char pad6;
++union {
++volatile u_char start; /* read */
++volatile u_char sopc; /* write */
++} start_sopc;
++u_char pad7;
++union {
++volatile u_char stop; /* read */
++volatile u_char ropc; /* write */
++} stop_ropc;
++u_char pad8;
++};
++
++#define MR1_BITS 3
++#define MR1_5BITS 0
++#define MR1_6BITS 1
++#define MR1_7BITS 2
++#define MR1_8BITS 3
++
++#define MR1_PARITY_ODD 4
++
++#define MR1_PARITY 24
++#define MR1_PARITY_WITH 0
++#define MR1_PARITY_FORCE 8
++#define MR1_PARITY_NO 16
++#define MR1_PARITY_MULTIDROP 24
++
++#define MR1_ERROR_BLOCK 32
++#define MR1_FFULL_IRQ 64
++#define MR1_RxRTS_ON 128
++
++#define MR2_STOPS 15
++#define MR2_1STOP 7
++#define MR2_2STOP 15
++
++#define MR2_CTS_ON 16
++#define MR2_TxRTS_ON 32
++
++#define MR2_MODE 192
++#define MR2_NORMAL 0
++#define MR2_ECHO 64
++#define MR2_LOCALLOOP 128
++#define MR2_REMOTELOOP 192
++
++#define CR_RXCOMMAND 3
++#define CR_NONE 0
++#define CR_RX_ON 1
++#define CR_RX_OFF 2
++#define CR_TXCOMMAND 12
++#define CR_TX_ON 4
++#define CR_TX_OFF 8
++#define CR_MISC 112
++#define CR_RESET_MR 16
++#define CR_RESET_RX 32
++#define CR_RESET_TX 48
++#define CR_RESET_ERR 64
++#define CR_RESET_BREAK 80
++#define CR_START_BREAK 96
++#define CR_STOP_BREAK 112
++
++#define SR_RXRDY 1
++#define SR_FFULL 2
++#define SR_TXRDY 4
++#define SR_TXEMPT 8
++#define SR_OVERRUN 16
++#define SR_PARITY 32
++#define SR_FRAMING 64
++#define SR_BREAK 128
++
++
++#endif
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/char/plip_ioext.c linux-m68k/drivers/char/plip_ioext.c
+--- linux-i386/drivers/char/plip_ioext.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-m68k/drivers/char/plip_ioext.c 2004-10-24 22:59:56.000000000 +0200
+@@ -0,0 +1,1058 @@
++/*
++ * plip_ioext: A parallel port "network" driver for GVP IO-Extender.
++ *
++ * Authors: See drivers/net/plip.c
++ * IO-Extender version by Steve Bennett, <msteveb at ozemail.com.au>
++ *
++ * This driver is for use with a 5-bit cable (LapLink (R) cable).
++ */
++
++static const char *version = "NET3 PLIP version 2.2/m68k";
++
++#define __NO_VERSION__
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/termios.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++
++#include <asm/setup.h>
++#include <asm/irq.h>
++#include <asm/amigahw.h>
++#include <asm/amigaints.h>
++#include <linux/zorro.h>
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/fcntl.h>
++#include <linux/string.h>
++#include <linux/ptrace.h>
++#include <linux/if_ether.h>
++
++#include <asm/system.h>
++
++#include <linux/in.h>
++#include <linux/delay.h>
++/*#include <linux/lp_m68k.h>*/
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/skbuff.h>
++#include <linux/if_plip.h>
++
++#include <linux/tqueue.h>
++#include <linux/ioport.h>
++#include <linux/bitops.h>
++#include <asm/byteorder.h>
++
++#include "ioext.h"
++
++#define DEBUG 0
++
++/* Map 'struct device *' to our control structure */
++#define PLIP_DEV(DEV) (&ioext_info[(DEV)->irq])
++
++/************************************************************************
++**
++** PLIP definitions
++**
++*************************************************************************
++*/
++
++/* Use 0 for production, 1 for verification, >2 for debug */
++#ifndef NET_DEBUG
++#define NET_DEBUG 2
++#endif
++static unsigned int net_debug = NET_DEBUG;
++
++/* In micro second */
++#define PLIP_DELAY_UNIT 1
++
++/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */
++#define PLIP_TRIGGER_WAIT 500
++
++/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
++#define PLIP_NIBBLE_WAIT 3000
++
++#define PAR_DATA(dev) ((dev)->base_addr+0)
++#define PAR_STATUS(dev) ((dev)->base_addr+2)
++#define PAR_CONTROL(dev) ((dev)->base_addr+4)
++
++static void enable_par_irq(struct device *dev, int on);
++static int plip_init(struct device *dev);
++
++/* Bottom halfs */
++static void plip_kick_bh(struct device *dev);
++static void plip_bh(struct device *dev);
++
++/* Functions for DEV methods */
++static int plip_rebuild_header(struct sk_buff *skb);
++static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
++static int plip_open(struct device *dev);
++static int plip_close(struct device *dev);
++static struct enet_statistics *plip_get_stats(struct device *dev);
++static int plip_config(struct device *dev, struct ifmap *map);
++static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
++
++enum plip_connection_state {
++ PLIP_CN_NONE=0,
++ PLIP_CN_RECEIVE,
++ PLIP_CN_SEND,
++ PLIP_CN_CLOSING,
++ PLIP_CN_ERROR
++};
++
++enum plip_packet_state {
++ PLIP_PK_DONE=0,
++ PLIP_PK_TRIGGER,
++ PLIP_PK_LENGTH_LSB,
++ PLIP_PK_LENGTH_MSB,
++ PLIP_PK_DATA,
++ PLIP_PK_CHECKSUM
++};
++
++enum plip_nibble_state {
++ PLIP_NB_BEGIN,
++ PLIP_NB_1,
++ PLIP_NB_2,
++};
++
++struct plip_local {
++ enum plip_packet_state state;
++ enum plip_nibble_state nibble;
++ union {
++ struct {
++#if defined(__LITTLE_ENDIAN)
++ unsigned char lsb;
++ unsigned char msb;
++#elif defined(__BIG_ENDIAN)
++ unsigned char msb;
++ unsigned char lsb;
++#else
++#error "Please fix the endianness defines in <asm/byteorder.h>"
++#endif
++ } b;
++ unsigned short h;
++ } length;
++ unsigned short byte;
++ unsigned char checksum;
++ unsigned char data;
++ struct sk_buff *skb;
++};
++
++struct net_local {
++ struct enet_statistics enet_stats;
++ struct tq_struct immediate;
++ struct tq_struct deferred;
++ struct plip_local snd_data;
++ struct plip_local rcv_data;
++ unsigned long trigger;
++ unsigned long nibble;
++ enum plip_connection_state connection;
++ unsigned short timeout_count;
++ char is_deferred;
++ int (*orig_rebuild_header)(struct sk_buff *skb);
++};
++
++struct device ioext_dev_plip[] = {
++ {
++ "plip0",
++ 0, 0, 0, 0, /* memory */
++ 0, 0, /* base, irq */
++ 0, 0, 0, NULL, plip_init
++ },
++ {
++ "plip1",
++ 0, 0, 0, 0, /* memory */
++ 0, 0, /* base, irq */
++ 0, 0, 0, NULL, plip_init
++ },
++ {
++ "plip2",
++ 0, 0, 0, 0, /* memory */
++ 0, 0, /* base, irq */
++ 0, 0, 0, NULL, plip_init
++ }
++};
++
++/*
++ * Check for and handle an interrupt for this PLIP device.
++ *
++ */
++void ioext_plip_interrupt(struct device *dev, int *spurious_count)
++{
++ struct net_local *nl;
++ struct plip_local *rcv;
++ unsigned char c0;
++ unsigned long flags;
++
++ nl = (struct net_local *)dev->priv;
++ rcv = &nl->rcv_data;
++
++ c0 = z_readb(PAR_STATUS(dev));
++
++ if (dev->interrupt) {
++ return;
++ }
++
++ if ((c0 & 0xf8) != 0xc0) {
++ /* Not for us */
++ ++*spurious_count;
++ return;
++ }
++
++ *spurious_count = 0;
++ dev->interrupt = 1;
++
++ local_irq_save(flags);
++
++ switch (nl->connection) {
++ case PLIP_CN_CLOSING:
++ dev->tbusy = 0;
++ case PLIP_CN_NONE:
++ case PLIP_CN_SEND:
++ dev->last_rx = jiffies;
++ rcv->state = PLIP_PK_TRIGGER;
++ nl->connection = PLIP_CN_RECEIVE;
++ nl->timeout_count = 0;
++ queue_task(&nl->immediate, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ local_irq_restore(flags);
++#if 0
++ printk("%s: receive irq in SEND/NONE/CLOSING (%d) ok\n",
++ dev->name, nl->connection);
++#endif
++ break;
++
++ case PLIP_CN_RECEIVE:
++ local_irq_restore(flags);
++ printk("%s: receive interrupt when receiving packet\n",
++ dev->name);
++ break;
++
++ case PLIP_CN_ERROR:
++ local_irq_restore(flags);
++ printk("%s: receive interrupt in error state\n", dev->name);
++ break;
++ }
++}
++
++
++/* Bottom half handler for the delayed request.
++ This routine is kicked by do_timer().
++ Request `plip_bh' to be invoked. */
++static void
++plip_kick_bh(struct device *dev)
++{
++ struct net_local *nl = (struct net_local *)dev->priv;
++
++ if (nl->is_deferred) {
++ queue_task(&nl->immediate, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++}
++
++/* Forward declarations of internal routines */
++static int plip_none(struct device *, struct net_local *,
++ struct plip_local *, struct plip_local *);
++static int plip_receive_packet(struct device *, struct net_local *,
++ struct plip_local *, struct plip_local *);
++static int plip_send_packet(struct device *, struct net_local *,
++ struct plip_local *, struct plip_local *);
++static int plip_connection_close(struct device *, struct net_local *,
++ struct plip_local *, struct plip_local *);
++static int plip_error(struct device *, struct net_local *,
++ struct plip_local *, struct plip_local *);
++static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
++ struct plip_local *snd,
++ struct plip_local *rcv,
++ int error);
++
++#define OK 0
++#define TIMEOUT 1
++#define ERROR 2
++
++typedef int (*plip_func)(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv);
++
++static plip_func connection_state_table[] =
++{
++ plip_none,
++ plip_receive_packet,
++ plip_send_packet,
++ plip_connection_close,
++ plip_error
++};
++
++/*
++** enable_par_irq()
++**
++** Enable or disable parallel irq for 'dev' according to 'on'.
++**
++** It is NOT possible to disable only the parallel irq.
++** So we disable the board interrupt instead. This means that
++** during reception of a PLIP packet, no serial interrupts can
++** happen. Sorry.
++*/
++static void enable_par_irq(struct device *dev, int on)
++{
++ if (on) {
++ PLIP_DEV(dev)->board->CNTR |= GVP_IRQ_ENA;
++ }
++ else {
++ PLIP_DEV(dev)->board->CNTR &= ~GVP_IRQ_ENA;
++ }
++}
++
++/* Bottom half handler of PLIP. */
++static void
++plip_bh(struct device *dev)
++{
++ struct net_local *nl = (struct net_local *)dev->priv;
++ struct plip_local *snd = &nl->snd_data;
++ struct plip_local *rcv = &nl->rcv_data;
++ plip_func f;
++ int r;
++
++ nl->is_deferred = 0;
++ f = connection_state_table[nl->connection];
++ if ((r = (*f)(dev, nl, snd, rcv)) != OK
++ && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
++ nl->is_deferred = 1;
++ queue_task(&nl->deferred, &tq_timer);
++ }
++}
++
++static int
++plip_bh_timeout_error(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv,
++ int error)
++{
++ unsigned char c0;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ if (nl->connection == PLIP_CN_SEND) {
++
++ if (error != ERROR) { /* Timeout */
++ nl->timeout_count++;
++ if ((snd->state == PLIP_PK_TRIGGER
++ && nl->timeout_count <= 10)
++ || nl->timeout_count <= 3) {
++ local_irq_restore(flags);
++ /* Try again later */
++ return TIMEOUT;
++ }
++ c0 = z_readb(PAR_STATUS(dev));
++ printk(KERN_INFO "%s: transmit timeout(%d,%02x)\n",
++ dev->name, snd->state, c0);
++ }
++ nl->enet_stats.tx_errors++;
++ nl->enet_stats.tx_aborted_errors++;
++ } else if (nl->connection == PLIP_CN_RECEIVE) {
++ if (rcv->state == PLIP_PK_TRIGGER) {
++ /* Transmission was interrupted. */
++ local_irq_restore(flags);
++ return OK;
++ }
++ if (error != ERROR) { /* Timeout */
++ if (++nl->timeout_count <= 3) {
++ local_irq_restore(flags);
++ /* Try again later */
++ return TIMEOUT;
++ }
++ c0 = z_readb(PAR_STATUS(dev));
++ printk(KERN_INFO "%s: receive timeout(%d,%02x)\n",
++ dev->name, rcv->state, c0);
++ }
++ nl->enet_stats.rx_dropped++;
++ }
++ rcv->state = PLIP_PK_DONE;
++ if (rcv->skb) {
++ kfree_skb(rcv->skb);
++ rcv->skb = NULL;
++ }
++ snd->state = PLIP_PK_DONE;
++ if (snd->skb) {
++ dev_kfree_skb(snd->skb);
++ snd->skb = NULL;
++ }
++ enable_par_irq(dev, 0);
++ dev->tbusy = 1;
++ nl->connection = PLIP_CN_ERROR;
++ z_writeb(0x00, PAR_DATA(dev));
++ local_irq_restore(flags);
++
++ return TIMEOUT;
++}
++
++static int
++plip_none(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv)
++{
++ return OK;
++}
++
++/* PLIP_RECEIVE --- receive a byte(two nibbles)
++ Returns OK on success, TIMEOUT on timeout */
++inline static int
++plip_receive(struct device *dev, unsigned short nibble_timeout,
++ enum plip_nibble_state *ns_p, unsigned char *data_p)
++{
++ unsigned char c0, c1;
++ unsigned int cx;
++
++ switch (*ns_p) {
++ case PLIP_NB_BEGIN:
++ cx = nibble_timeout;
++ while (1) {
++ c0 = z_readb(PAR_STATUS(dev));
++ udelay(PLIP_DELAY_UNIT);
++ if ((c0 & 0x80) == 0) {
++ c1 = z_readb(PAR_STATUS(dev));
++ if (c0 == c1)
++ break;
++ }
++ if (--cx == 0)
++ return TIMEOUT;
++ }
++#if 0
++ printk("received first nybble: %02X -> %02X\n",
++ c0, (c0 >> 3) & 0x0F);
++#endif
++ *data_p = (c0 >> 3) & 0x0f;
++ z_writeb(0x10, PAR_DATA(dev)); /* send ACK */
++ *ns_p = PLIP_NB_1;
++
++ case PLIP_NB_1:
++ cx = nibble_timeout;
++ while (1) {
++ c0 = z_readb(PAR_STATUS(dev));
++ udelay(PLIP_DELAY_UNIT);
++ if (c0 & 0x80) {
++ c1 = z_readb(PAR_STATUS(dev));
++ if (c0 == c1)
++ break;
++ }
++ if (--cx == 0)
++ return TIMEOUT;
++ }
++#if 0
++ printk("received second nybble: %02X -> %02X\n",
++ c0, (c0 << 1) & 0xF0);
++#endif
++ *data_p |= (c0 << 1) & 0xf0;
++ z_writeb(0x00, PAR_DATA(dev)); /* send ACK */
++ *ns_p = PLIP_NB_BEGIN;
++ case PLIP_NB_2:
++ break;
++ }
++ return OK;
++}
++
++/* PLIP_RECEIVE_PACKET --- receive a packet */
++static int
++plip_receive_packet(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv)
++{
++ unsigned short nibble_timeout = nl->nibble;
++ unsigned char *lbuf;
++ unsigned long flags;
++
++ switch (rcv->state) {
++ case PLIP_PK_TRIGGER:
++ enable_par_irq(dev, 0);
++ dev->interrupt = 0;
++ z_writeb(0x01, PAR_DATA(dev)); /* send ACK */
++ if (net_debug > 2)
++ printk(KERN_DEBUG "%s: receive start\n", dev->name);
++ rcv->state = PLIP_PK_LENGTH_LSB;
++ rcv->nibble = PLIP_NB_BEGIN;
++
++ case PLIP_PK_LENGTH_LSB:
++ if (snd->state != PLIP_PK_DONE) {
++ if (plip_receive(dev, nl->trigger,
++ &rcv->nibble, &rcv->length.b.lsb)) {
++ /* collision, here dev->tbusy == 1 */
++ rcv->state = PLIP_PK_DONE;
++ nl->is_deferred = 1;
++ nl->connection = PLIP_CN_SEND;
++ queue_task(&nl->deferred, &tq_timer);
++ enable_par_irq(dev, 1);
++ return OK;
++ }
++ } else {
++ if (plip_receive(dev, nibble_timeout,
++ &rcv->nibble, &rcv->length.b.lsb))
++ return TIMEOUT;
++ }
++ rcv->state = PLIP_PK_LENGTH_MSB;
++
++ case PLIP_PK_LENGTH_MSB:
++ if (plip_receive(dev, nibble_timeout,
++ &rcv->nibble, &rcv->length.b.msb))
++ return TIMEOUT;
++ if (rcv->length.h > dev->mtu + dev->hard_header_len
++ || rcv->length.h < 8) {
++ printk(KERN_INFO "%s: bogus packet size %d.\n",
++ dev->name, rcv->length.h);
++ return ERROR;
++ }
++ /* Malloc up new buffer. */
++ rcv->skb = dev_alloc_skb(rcv->length.h);
++ if (rcv->skb == NULL) {
++ printk(KERN_INFO "%s: Memory squeeze.\n", dev->name);
++ return ERROR;
++ }
++ skb_put(rcv->skb,rcv->length.h);
++ rcv->skb->dev = dev;
++ rcv->state = PLIP_PK_DATA;
++ rcv->byte = 0;
++ rcv->checksum = 0;
++
++ case PLIP_PK_DATA:
++ lbuf = rcv->skb->data;
++ do
++ if (plip_receive(dev, nibble_timeout,
++ &rcv->nibble, &lbuf[rcv->byte]))
++ return TIMEOUT;
++ while (++rcv->byte < rcv->length.h);
++ do
++ rcv->checksum += lbuf[--rcv->byte];
++ while (rcv->byte);
++ rcv->state = PLIP_PK_CHECKSUM;
++
++ case PLIP_PK_CHECKSUM:
++ if (plip_receive(dev, nibble_timeout,
++ &rcv->nibble, &rcv->data))
++ return TIMEOUT;
++ if (rcv->data != rcv->checksum) {
++ nl->enet_stats.rx_crc_errors++;
++ if (net_debug)
++ printk(KERN_INFO "%s: checksum error\n",
++ dev->name);
++ return ERROR;
++ }
++ rcv->state = PLIP_PK_DONE;
++
++ case PLIP_PK_DONE:
++ /* Inform the upper layer for the arrival of a packet. */
++ rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
++ netif_rx(rcv->skb);
++ nl->enet_stats.rx_packets++;
++ rcv->skb = NULL;
++ if (net_debug > 2)
++ printk(KERN_DEBUG "%s: receive end\n", dev->name);
++
++ /* Close the connection. */
++ z_writeb (0x00, PAR_DATA(dev));
++
++ local_irq_save(flags);
++ if (snd->state != PLIP_PK_DONE) {
++ nl->connection = PLIP_CN_SEND;
++ local_irq_restore(flags);
++ queue_task(&nl->immediate, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ enable_par_irq(dev, 1);
++ return OK;
++ } else {
++ nl->connection = PLIP_CN_NONE;
++ local_irq_restore(flags);
++ enable_par_irq(dev, 1);
++ return OK;
++ }
++ }
++ return OK;
++}
++
++/* PLIP_SEND --- send a byte (two nibbles)
++ Returns OK on success, TIMEOUT when timeout */
++inline static int
++plip_send(struct device *dev, unsigned short nibble_timeout,
++ enum plip_nibble_state *ns_p, unsigned char data)
++{
++ unsigned char c0;
++ unsigned int cx;
++
++ switch (*ns_p) {
++ case PLIP_NB_BEGIN:
++ z_writeb((data & 0x0f), PAR_DATA(dev));
++ *ns_p = PLIP_NB_1;
++
++ case PLIP_NB_1:
++ z_writeb(0x10 | (data & 0x0f), PAR_DATA(dev));
++ cx = nibble_timeout;
++ while (1) {
++ c0 = z_readb(PAR_STATUS(dev));
++ if ((c0 & 0x80) == 0)
++ break;
++ if (--cx == 0)
++ return TIMEOUT;
++ udelay(PLIP_DELAY_UNIT);
++ }
++ z_writeb(0x10 | (data >> 4), PAR_DATA(dev));
++ *ns_p = PLIP_NB_2;
++
++ case PLIP_NB_2:
++ z_writeb((data >> 4), PAR_DATA(dev));
++ cx = nibble_timeout;
++ while (1) {
++ c0 = z_readb(PAR_STATUS(dev));
++ if (c0 & 0x80)
++ break;
++ if (--cx == 0)
++ return TIMEOUT;
++ udelay(PLIP_DELAY_UNIT);
++ }
++ *ns_p = PLIP_NB_BEGIN;
++ return OK;
++ }
++ return OK;
++}
++
++/* PLIP_SEND_PACKET --- send a packet */
++static int
++plip_send_packet(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv)
++{
++ unsigned short nibble_timeout = nl->nibble;
++ unsigned char *lbuf;
++ unsigned char c0;
++ unsigned int cx;
++ unsigned long flags;
++
++ if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
++ printk(KERN_INFO "%s: send skb lost\n", dev->name);
++ snd->state = PLIP_PK_DONE;
++ snd->skb = NULL;
++ return ERROR;
++ }
++
++ if (snd->length.h == 0) {
++ return OK;
++ }
++
++ switch (snd->state) {
++ case PLIP_PK_TRIGGER:
++ if ((z_readb(PAR_STATUS(dev)) & 0xf8) != 0x80)
++ return TIMEOUT;
++
++ /* Trigger remote rx interrupt. */
++ z_writeb(0x08, PAR_DATA(dev));
++ cx = nl->trigger;
++ while (1) {
++ udelay(PLIP_DELAY_UNIT);
++ local_irq_save(flags);
++ if (nl->connection == PLIP_CN_RECEIVE) {
++ local_irq_restore(flags);
++ /* interrupted */
++ nl->enet_stats.collisions++;
++ if (net_debug > 1)
++ printk(KERN_INFO "%s: collision.\n",
++ dev->name);
++ return OK;
++ }
++ c0 = z_readb(PAR_STATUS(dev));
++ if (c0 & 0x08) {
++ enable_par_irq(dev, 0);
++ if (net_debug > 2)
++ printk(KERN_DEBUG "%s: send start\n",
++ dev->name);
++ snd->state = PLIP_PK_LENGTH_LSB;
++ snd->nibble = PLIP_NB_BEGIN;
++ nl->timeout_count = 0;
++ local_irq_restore(flags);
++ break;
++ }
++ local_irq_restore(flags);
++ if (--cx == 0) {
++ z_writeb(0x00, PAR_DATA(dev));
++ return TIMEOUT;
++ }
++ }
++
++ case PLIP_PK_LENGTH_LSB:
++ if (plip_send(dev, nibble_timeout,
++ &snd->nibble, snd->length.b.lsb))
++ return TIMEOUT;
++ snd->state = PLIP_PK_LENGTH_MSB;
++
++ case PLIP_PK_LENGTH_MSB:
++ if (plip_send(dev, nibble_timeout,
++ &snd->nibble, snd->length.b.msb))
++ return TIMEOUT;
++ snd->state = PLIP_PK_DATA;
++ snd->byte = 0;
++ snd->checksum = 0;
++
++ case PLIP_PK_DATA:
++ do
++ if (plip_send(dev, nibble_timeout,
++ &snd->nibble, lbuf[snd->byte]))
++ return TIMEOUT;
++ while (++snd->byte < snd->length.h);
++ do
++ snd->checksum += lbuf[--snd->byte];
++ while (snd->byte);
++ snd->state = PLIP_PK_CHECKSUM;
++
++ case PLIP_PK_CHECKSUM:
++ if (plip_send(dev, nibble_timeout,
++ &snd->nibble, snd->checksum))
++ return TIMEOUT;
++
++ dev_kfree_skb(snd->skb);
++ nl->enet_stats.tx_packets++;
++ snd->state = PLIP_PK_DONE;
++
++ case PLIP_PK_DONE:
++ /* Close the connection */
++ z_writeb (0x00, PAR_DATA(dev));
++ snd->skb = NULL;
++ if (net_debug > 2)
++ printk(KERN_DEBUG "%s: send end\n", dev->name);
++ nl->connection = PLIP_CN_CLOSING;
++ nl->is_deferred = 1;
++ queue_task(&nl->deferred, &tq_timer);
++ enable_par_irq(dev, 1);
++ return OK;
++ }
++ return OK;
++}
++
++static int
++plip_connection_close(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ if (nl->connection == PLIP_CN_CLOSING) {
++ nl->connection = PLIP_CN_NONE;
++ dev->tbusy = 0;
++ mark_bh(NET_BH);
++ }
++ local_irq_restore(flags);
++ return OK;
++}
++
++/* PLIP_ERROR --- wait till other end settled */
++static int
++plip_error(struct device *dev, struct net_local *nl,
++ struct plip_local *snd, struct plip_local *rcv)
++{
++ unsigned char status;
++
++ status = z_readb(PAR_STATUS(dev));
++ if ((status & 0xf8) == 0x80) {
++ if (net_debug > 2)
++ printk(KERN_DEBUG "%s: reset interface.\n", dev->name);
++ nl->connection = PLIP_CN_NONE;
++ dev->tbusy = 0;
++ dev->interrupt = 0;
++ enable_par_irq(dev, 1);
++ mark_bh(NET_BH);
++ } else {
++ nl->is_deferred = 1;
++ queue_task(&nl->deferred, &tq_timer);
++ }
++
++ return OK;
++}
++
++/* We don't need to send arp, for plip is point-to-point. */
++static int
++plip_rebuild_header(struct sk_buff *skb)
++{
++ struct device *dev = skb->dev;
++ struct net_local *nl = (struct net_local *)dev->priv;
++ struct ethhdr *eth = (struct ethhdr *)skb->data;
++ int i;
++
++ if ((dev->flags & IFF_NOARP)==0)
++ return nl->orig_rebuild_header(skb);
++
++ if (eth->h_proto != __constant_htons(ETH_P_IP)
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++ && eth->h_proto != __constant_htons(ETH_P_IPV6)
++#endif
++ ) {
++ printk(KERN_ERR "plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
++ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
++ return 0;
++ }
++
++ for (i=0; i < ETH_ALEN - sizeof(u32); i++)
++ eth->h_dest[i] = 0xfc;
++#if 0
++ *(u32 *)(eth->h_dest+i) = dst;
++#else
++ /* Do not want to include net/route.h here.
++ * In any case, it is TOP of silliness to emulate
++ * hardware addresses on PtP link. --ANK
++ */
++ *(u32 *)(eth->h_dest+i) = 0;
++#endif
++ return 0;
++}
++
++static int
++plip_tx_packet(struct sk_buff *skb, struct device *dev)
++{
++ struct net_local *nl = (struct net_local *)dev->priv;
++ struct plip_local *snd = &nl->snd_data;
++ unsigned long flags;
++
++ if (dev->tbusy)
++ return 1;
++
++ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
++ printk(KERN_ERR "%s: Transmitter access conflict.\n",
++ dev->name);
++ return 1;
++ }
++
++ if (skb->len > dev->mtu + dev->hard_header_len) {
++ printk(KERN_ERR "%s: packet too big, %d.\n",
++ dev->name, (int)skb->len);
++ dev->tbusy = 0;
++ return 0;
++ }
++
++ if (net_debug > 2)
++ printk(KERN_DEBUG "%s: send request\n", dev->name);
++
++ local_irq_save(flags);
++ dev->trans_start = jiffies;
++ snd->skb = skb;
++ snd->length.h = skb->len;
++ snd->state = PLIP_PK_TRIGGER;
++ if (nl->connection == PLIP_CN_NONE) {
++ nl->connection = PLIP_CN_SEND;
++ nl->timeout_count = 0;
++ }
++ queue_task(&nl->immediate, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++/* Open/initialize the board. This is called (in the current kernel)
++ sometime after booting when the 'ifconfig' program is run.
++
++ */
++static int
++plip_open(struct device *dev)
++{
++ struct net_local *nl = (struct net_local *)dev->priv;
++ struct in_device *in_dev;
++
++#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE)
++ /* Yes, there is a race condition here. Fix it later */
++ if (PLIP_DEV(dev)->par_use & IOEXT_PAR_LP) {
++ /* Can't open if lp is in use */
++#if DEBUG
++ printk("par is in use by lp\n");
++#endif
++ return(-EBUSY);
++ }
++#endif
++ PLIP_DEV(dev)->par_use |= IOEXT_PAR_PLIP;
++
++#if DEBUG
++ printk("plip_open(): sending 00 to data port\n");
++#endif
++
++ /* Clear the data port. */
++ z_writeb (0x00, PAR_DATA(dev));
++
++#if DEBUG
++ printk("plip_open(): sent\n");
++#endif
++
++ /* Initialize the state machine. */
++ nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
++ nl->rcv_data.skb = nl->snd_data.skb = NULL;
++ nl->connection = PLIP_CN_NONE;
++ nl->is_deferred = 0;
++
++ /* Fill in the MAC-level header.
++ (ab)Use "dev->broadcast" to store point-to-point MAC address.
++
++ PLIP doesn't have a real mac address, but we need to create one
++ to be DOS compatible. */
++ memset(dev->dev_addr, 0xfc, ETH_ALEN);
++ memset(dev->broadcast, 0xfc, ETH_ALEN);
++
++ if ((in_dev=dev->ip_ptr) != NULL) {
++ /*
++ * Any address will do - we take the first
++ */
++ struct in_ifaddr *ifa=in_dev->ifa_list;
++ if (ifa != NULL) {
++ memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
++ memcpy(dev->broadcast+2, &ifa->ifa_address, 4);
++ }
++ }
++
++ dev->interrupt = 0;
++ dev->start = 1;
++ dev->tbusy = 0;
++
++ MOD_INC_USE_COUNT;
++
++ /* Enable rx interrupt. */
++ enable_par_irq(dev, 1);
++
++ return 0;
++}
++
++/* The inverse routine to plip_open (). */
++static int
++plip_close(struct device *dev)
++{
++ struct net_local *nl = (struct net_local *)dev->priv;
++ struct plip_local *snd = &nl->snd_data;
++ struct plip_local *rcv = &nl->rcv_data;
++ unsigned long flags;
++
++ dev->tbusy = 1;
++ dev->start = 0;
++ local_irq_save(flags);
++ nl->is_deferred = 0;
++ nl->connection = PLIP_CN_NONE;
++ local_irq_restore(flags);
++ z_writeb(0x00, PAR_DATA(dev));
++
++ snd->state = PLIP_PK_DONE;
++ if (snd->skb) {
++ dev_kfree_skb(snd->skb);
++ snd->skb = NULL;
++ }
++ rcv->state = PLIP_PK_DONE;
++ if (rcv->skb) {
++ kfree_skb(rcv->skb);
++ rcv->skb = NULL;
++ }
++
++ PLIP_DEV(dev)->par_use &= ~IOEXT_PAR_PLIP;
++
++ MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++static struct enet_statistics *
++plip_get_stats(struct device *dev)
++{
++ struct net_local *nl = (struct net_local *)dev->priv;
++ struct enet_statistics *r = &nl->enet_stats;
++
++ return r;
++}
++
++static int
++plip_config(struct device *dev, struct ifmap *map)
++{
++ if (dev->flags & IFF_UP)
++ return -EBUSY;
++
++ printk(KERN_INFO "%s: This interface is autodetected (ignored).\n",
++ dev->name);
++
++ return 0;
++}
++
++static int
++plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
++{
++ struct net_local *nl = (struct net_local *) dev->priv;
++ struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
++
++ switch(pc->pcmd) {
++ case PLIP_GET_TIMEOUT:
++ pc->trigger = nl->trigger;
++ pc->nibble = nl->nibble;
++ break;
++ case PLIP_SET_TIMEOUT:
++ nl->trigger = pc->trigger;
++ nl->nibble = pc->nibble;
++ break;
++ default:
++ return -EOPNOTSUPP;
++ }
++ return 0;
++}
++
++/*
++ * Detect and initialize all IO-Extenders in this system.
++ *
++ * Both PLIP and serial devices are configured.
++ */
++int plip_init(struct device *dev)
++{
++ IOEXT_struct *board;
++ struct net_local *nl;
++
++ if (ioext_num == 0) {
++ printk(KERN_INFO "%s\n", version);
++ }
++
++ board = PLIP_DEV(dev)->board;
++ dev->base_addr = (unsigned long)&board->par.DATA;
++
++ /* Cheat and use irq to index into our table */
++ dev->irq = ioext_num;
++
++ printk(KERN_INFO "%s: IO-Extender parallel port at 0x%08lX\n", dev->name, dev->base_addr);
++
++ /* Fill in the generic fields of the device structure. */
++ ether_setup(dev);
++
++ /* Then, override parts of it */
++ dev->hard_start_xmit = plip_tx_packet;
++ dev->open = plip_open;
++ dev->stop = plip_close;
++ dev->get_stats = plip_get_stats;
++ dev->set_config = plip_config;
++ dev->do_ioctl = plip_ioctl;
++ dev->tx_queue_len = 10;
++ dev->flags = IFF_POINTOPOINT|IFF_NOARP;
++
++ /* Set the private structure */
++ dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
++ if (dev->priv == NULL) {
++ printk(KERN_ERR "%s: out of memory\n", dev->name);
++ return -ENOMEM;
++ }
++ memset(dev->priv, 0, sizeof(struct net_local));
++ nl = (struct net_local *) dev->priv;
++
++ nl->orig_rebuild_header = dev->rebuild_header;
++ dev->rebuild_header = plip_rebuild_header;
++
++ /* Initialize constants */
++ nl->trigger = PLIP_TRIGGER_WAIT;
++ nl->nibble = PLIP_NIBBLE_WAIT;
++
++ /* Initialize task queue structures */
++ nl->immediate.next = NULL;
++ nl->immediate.sync = 0;
++ nl->immediate.routine = (void *)(void *)plip_bh;
++ nl->immediate.data = dev;
++
++ nl->deferred.next = NULL;
++ nl->deferred.sync = 0;
++ nl->deferred.routine = (void *)(void *)plip_kick_bh;
++ nl->deferred.data = dev;
++
++ /* Don't enable interrupts yet */
++
++ return 0;
++}
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/char/serial167.c linux-m68k/drivers/char/serial167.c
+--- linux-i386/drivers/char/serial167.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/char/serial167.c 2006-09-24 16:32:38.000000000 +0200
+@@ -62,6 +62,7 @@
+ #include <linux/console.h>
+ #include <linux/module.h>
+ #include <linux/bitops.h>
++#include <linux/tty_flip.h>
+
+ #include <asm/system.h>
+ #include <asm/io.h>
+@@ -438,8 +439,9 @@
+ overflowing, we still loose
+ the next incoming character.
+ */
+- tty_insert_flip_char(tty, data, TTY_NORMAL);
+- }
++ if (tty_buffer_request_room(tty, 1) != 0){
++ tty_insert_flip_char(tty, data, TTY_FRAME);
++ }
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* else if(data & CyTIMEOUT) */
+@@ -448,14 +450,14 @@
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
+ }
+ }else{
+- tty_insert_flip_char(tty, data, TTY_NORMAL);
++ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ }
+ }else{
+ /* there was a software buffer overrun
+ and nothing could be done about it!!! */
+ }
+ }
+- schedule_delayed_work(&tty->flip.work, 1);
++ tty_schedule_flip(tty);
+ /* end of service */
+ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
+ return IRQ_HANDLED;
+@@ -646,6 +648,7 @@
+ char data;
+ int char_count;
+ int save_cnt;
++ int len;
+
+ /* determine the channel and change to that context */
+ channel = (u_short ) (base_addr[CyLICR] >> 2);
+@@ -678,14 +681,15 @@
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
+ #endif
+- while(char_count--){
++ len = tty_buffer_request_room(tty, char_count);
++ while(len--){
+ data = base_addr[CyRDR];
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ #ifdef CYCLOM_16Y_HACK
+ udelay(10L);
+ #endif
+ }
+- schedule_delayed_work(&tty->flip.work, 1);
++ tty_schedule_flip(tty);
+ }
+ /* end of service */
+ base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
+@@ -1433,7 +1437,6 @@
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ unsigned long flags;
+ unsigned char status;
+- unsigned int result;
+
+ channel = info->line;
+
+@@ -1457,7 +1460,6 @@
+ int channel;
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ unsigned long flags;
+- unsigned int arg;
+
+ channel = info->line;
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/ide/ide-iops.c linux-m68k/drivers/ide/ide-iops.c
+--- linux-i386/drivers/ide/ide-iops.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/ide/ide-iops.c 2006-09-24 16:32:47.000000000 +0200
+@@ -337,6 +337,23 @@
+ int i;
+ u16 *stringcast;
+
++#ifdef __mc68000__
++ if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
++ return;
++
++#ifdef M68K_IDE_SWAPW
++ if (M68K_IDE_SWAPW) { /* fix bus byteorder first */
++ u_char *p = (u_char *)id;
++ u_char t;
++ for (i = 0; i < 512; i += 2) {
++ t = p[i];
++ p[i] = p[i+1];
++ p[i+1] = t;
++ }
++ }
++#endif
++#endif /* __mc68000__ */
++
+ id->config = __le16_to_cpu(id->config);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->reserved2 = __le16_to_cpu(id->reserved2);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/input/keyboard/Kconfig linux-m68k/drivers/input/keyboard/Kconfig
+--- linux-i386/drivers/input/keyboard/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/input/keyboard/Kconfig 2006-06-18 19:08:22.000000000 +0200
+@@ -155,7 +155,7 @@
+
+ config KEYBOARD_HIL_OLD
+ tristate "HP HIL keyboard support (simple driver)"
+- depends on GSC
++ depends on GSC || HP300
+ default y
+ help
+ The "Human Interface Loop" is a older, 8-channel USB-like
+@@ -172,7 +172,7 @@
+
+ config KEYBOARD_HIL
+ tristate "HP HIL keyboard support"
+- depends on GSC
++ depends on GSC || HP300
+ default y
+ select HP_SDC
+ select HIL_MLC
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/input/misc/Kconfig linux-m68k/drivers/input/misc/Kconfig
+--- linux-i386/drivers/input/misc/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/input/misc/Kconfig 2006-09-24 16:32:52.000000000 +0200
+@@ -73,7 +73,7 @@
+
+ config HP_SDC_RTC
+ tristate "HP SDC Real Time Clock"
+- depends on GSC
++ depends on GSC || HP300
+ select HP_SDC
+ help
+ Say Y here if you want to support the built-in real time clock
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/input/mouse/Kconfig linux-m68k/drivers/input/mouse/Kconfig
+--- linux-i386/drivers/input/mouse/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/input/mouse/Kconfig 2006-04-10 00:22:40.000000000 +0200
+@@ -119,7 +119,7 @@
+
+ config MOUSE_HIL
+ tristate "HIL pointers (mice etc)."
+- depends on GSC
++ depends on GSC || HP300
+ select HP_SDC
+ select HIL_MLC
+ help
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/input/serio/Kconfig linux-m68k/drivers/input/serio/Kconfig
+--- linux-i386/drivers/input/serio/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/input/serio/Kconfig 2005-08-29 21:17:45.000000000 +0200
+@@ -112,7 +112,7 @@
+
+ config HP_SDC
+ tristate "HP System Device Controller i8042 Support"
+- depends on GSC && SERIO
++ depends on (GSC || HP300) && SERIO
+ default y
+ ---help---
+ This option enables supports for the the "System Device
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/macintosh/adb.c linux-m68k/drivers/macintosh/adb.c
+--- linux-i386/drivers/macintosh/adb.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/macintosh/adb.c 2006-09-24 16:32:59.000000000 +0200
+@@ -478,13 +478,15 @@
+ use_sreq = 1;
+ } else
+ use_sreq = 0;
+- req->nbytes = nbytes+1;
++ i = (flags & ADBREQ_RAW) ? 0 : 1;
++ req->nbytes = nbytes+i;
+ req->done = done;
+ req->reply_expected = flags & ADBREQ_REPLY;
+ req->data[0] = ADB_PACKET;
+ va_start(list, nbytes);
+- for (i = 0; i < nbytes; ++i)
+- req->data[i+1] = va_arg(list, int);
++ while (i < req->nbytes) {
++ req->data[i++] = va_arg(list, int);
++ }
+ va_end(list);
+
+ if (flags & ADBREQ_NOSEND)
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/net/7990.c linux-m68k/drivers/net/7990.c
+--- linux-i386/drivers/net/7990.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/net/7990.c 2006-06-18 19:08:38.000000000 +0200
+@@ -500,7 +500,7 @@
+ int res;
+
+ /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
+- if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
++ if (request_irq(lp->irq, lance_interrupt, SA_SHIRQ, lp->name, dev))
+ return -EAGAIN;
+
+ res = lance_reset(dev);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/net/Kconfig linux-m68k/drivers/net/Kconfig
+--- linux-i386/drivers/net/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/net/Kconfig 2006-09-24 16:33:13.000000000 +0200
+@@ -307,7 +307,7 @@
+
+ config MAC89x0
+ tristate "Macintosh CS89x0 based ethernet cards"
+- depends on NET_ETHERNET && MAC && BROKEN
++ depends on NET_ETHERNET && MAC
+ ---help---
+ Support for CS89x0 chipset based Ethernet cards. If you have a
+ Nubus or LC-PDS network (Ethernet) card of this type, say Y and
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/net/hplance.c linux-m68k/drivers/net/hplance.c
+--- linux-i386/drivers/net/hplance.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/net/hplance.c 2006-06-18 19:08:39.000000000 +0200
+@@ -77,6 +77,7 @@
+ {
+ struct net_device *dev;
+ int err = -ENOMEM;
++ int i;
+
+ dev = alloc_etherdev(sizeof(struct hplance_private));
+ if (!dev)
+@@ -93,6 +94,15 @@
+ goto out_release_mem_region;
+
+ dio_set_drvdata(d, dev);
++
++ printk(KERN_INFO "%s: %s; select code %d, addr %2.2x", dev->name, d->name, d->scode, dev->dev_addr[0]);
++
++ for (i=1; i<6; i++) {
++ printk(":%2.2x", dev->dev_addr[i]);
++ }
++
++ printk(", irq %d\n", d->ipl);
++
+ return 0;
+
+ out_release_mem_region:
+@@ -118,9 +128,7 @@
+ unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
+ struct hplance_private *lp;
+ int i;
+-
+- printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
+-
++
+ /* reset the board */
+ out_8(va+DIO_IDOFF, 0xff);
+ udelay(100); /* ariba! ariba! udelay! udelay! */
+@@ -143,7 +151,6 @@
+ */
+ dev->dev_addr[i] = ((in_8(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
+ | (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+- printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
+ }
+
+ lp = netdev_priv(dev);
+@@ -160,7 +167,6 @@
+ lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+ lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+ lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+- printk(", irq %d\n", lp->lance.irq);
+ }
+
+ /* This is disgusting. We have to check the DIO status register for ack every
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/net/mac89x0.c linux-m68k/drivers/net/mac89x0.c
+--- linux-i386/drivers/net/mac89x0.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/net/mac89x0.c 2006-06-18 19:08:40.000000000 +0200
+@@ -128,7 +128,7 @@
+ extern void reset_chip(struct net_device *dev);
+ #endif
+ static int net_open(struct net_device *dev);
+-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
++static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+ static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+ static void set_multicast_list(struct net_device *dev);
+ static void net_rx(struct net_device *dev);
+@@ -374,56 +374,37 @@
+ static int
+ net_send_packet(struct sk_buff *skb, struct net_device *dev)
+ {
+- if (dev->tbusy) {
+- /* If we get here, some higher level has decided we are broken.
+- There should really be a "kick me" function call instead. */
+- int tickssofar = jiffies - dev->trans_start;
+- if (tickssofar < 5)
+- return 1;
+- if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+- tx_done(dev) ? "IRQ conflict" : "network cable problem");
+- /* Try to restart the adaptor. */
+- dev->tbusy=0;
+- dev->trans_start = jiffies;
+- }
+-
+- /* Block a timer-based transmit from overlapping. This could better be
+- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+- printk("%s: Transmitter access conflict.\n", dev->name);
+- else {
+- struct net_local *lp = netdev_priv(dev);
+- unsigned long flags;
+-
+- if (net_debug > 3)
+- printk("%s: sent %d byte packet of type %x\n",
+- dev->name, skb->len,
+- (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+- | skb->data[ETH_ALEN+ETH_ALEN+1]);
+-
+- /* keep the upload from being interrupted, since we
+- ask the chip to start transmitting before the
+- whole packet has been completely uploaded. */
+- local_irq_save(flags);
+-
+- /* initiate a transmit sequence */
+- writereg(dev, PP_TxCMD, lp->send_cmd);
+- writereg(dev, PP_TxLength, skb->len);
+-
+- /* Test to see if the chip has allocated memory for the packet */
+- if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+- /* Gasp! It hasn't. But that shouldn't happen since
+- we're waiting for TxOk, so return 1 and requeue this packet. */
+- local_irq_restore(flags);
+- return 1;
+- }
++ struct net_local *lp = netdev_priv(dev);
++ unsigned long flags;
+
+- /* Write the contents of the packet */
+- memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
++ if (net_debug > 3)
++ printk("%s: sent %d byte packet of type %x\n",
++ dev->name, skb->len,
++ (skb->data[ETH_ALEN+ETH_ALEN] << 8)
++ | skb->data[ETH_ALEN+ETH_ALEN+1]);
++
++ /* keep the upload from being interrupted, since we
++ ask the chip to start transmitting before the
++ whole packet has been completely uploaded. */
++ local_irq_save(flags);
+
++ /* initiate a transmit sequence */
++ writereg(dev, PP_TxCMD, lp->send_cmd);
++ writereg(dev, PP_TxLength, skb->len);
++
++ /* Test to see if the chip has allocated memory for the packet */
++ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
++ /* Gasp! It hasn't. But that shouldn't happen since
++ we're waiting for TxOk, so return 1 and requeue this packet. */
+ local_irq_restore(flags);
+- dev->trans_start = jiffies;
++ return 1;
+ }
++
++ /* Write the contents of the packet */
++ memcpy((void *)(dev->mem_start + PP_TxFrame), skb->data, skb->len+1);
++
++ local_irq_restore(flags);
++ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+
+ return 0;
+@@ -441,9 +422,6 @@
+ printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+ return IRQ_NONE;
+ }
+- if (dev->interrupt)
+- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+- dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+@@ -464,8 +442,7 @@
+ break;
+ case ISQ_TRANSMITTER_EVENT:
+ lp->stats.tx_packets++;
+- dev->tbusy = 0;
+- mark_bh(NET_BH); /* Inform upper layers. */
++ netif_wake_queue(dev);
+ if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+ if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+ if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+@@ -479,8 +456,7 @@
+ That shouldn't happen since we only ever
+ load one packet. Shrug. Do the right
+ thing anyway. */
+- dev->tbusy = 0;
+- mark_bh(NET_BH); /* Inform upper layers. */
++ netif_wake_queue(dev);
+ }
+ if (status & TX_UNDERRUN) {
+ if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
+@@ -497,7 +473,6 @@
+ break;
+ }
+ }
+- dev->interrupt = 0;
+ return IRQ_HANDLED;
+ }
+
+@@ -532,7 +507,7 @@
+ skb_put(skb, length);
+ skb->dev = dev;
+
+- memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
++ memcpy(skb->data, (void *)(dev->mem_start + PP_RxFrame), length);
+
+ if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
+ dev->name, length,
+@@ -611,8 +586,6 @@
+ static int set_mac_address(struct net_device *dev, void *addr)
+ {
+ int i;
+- if (dev->start)
+- return -EBUSY;
+ printk("%s: Setting MAC address to ", dev->name);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/53c7xx.c linux-m68k/drivers/scsi/53c7xx.c
+--- linux-i386/drivers/scsi/53c7xx.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/53c7xx.c 2006-09-24 16:33:34.000000000 +0200
+@@ -307,7 +307,7 @@
+
+ static int check_address (unsigned long addr, int size);
+ static void dump_events (struct Scsi_Host *host, int count);
+-static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host,
++static struct scsi_cmnd * return_outstanding_commands (struct Scsi_Host *host,
+ int free, int issue);
+ static void hard_reset (struct Scsi_Host *host);
+ static void ncr_scsi_reset (struct Scsi_Host *host);
+@@ -316,7 +316,7 @@
+ int scntl3, int now_connected);
+ static int datapath_residual (struct Scsi_Host *host);
+ static const char * sbcl_to_phase (int sbcl);
+-static void print_progress (Scsi_Cmnd *cmd);
++static void print_progress (struct scsi_cmnd *cmd);
+ static void print_queues (struct Scsi_Host *host);
+ static void process_issue_queue (unsigned long flags);
+ static int shutdown (struct Scsi_Host *host);
+@@ -341,9 +341,8 @@
+ static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
+
+ /* Size of event list (per host adapter) */
+-static int track_events = 0;
+-static struct Scsi_Host *first_host = NULL; /* Head of list of NCR boards */
+-static struct scsi_host_template *the_template = NULL;
++static int track_events;
++static struct scsi_host_template *the_template;
+
+ /* NCR53c710 script handling code */
+
+@@ -666,8 +665,11 @@
+
+ static struct Scsi_Host *
+ find_host (int host) {
+- struct Scsi_Host *h;
+- for (h = first_host; h && h->host_no != host; h = h->next);
++ struct Scsi_Host *h, *s;
++ list_for_each_entry_safe(h, s, &the_template->legacy_hosts, sht_legacy_list) {
++ if (h->host_no == host)
++ break;
++ }
+ if (!h) {
+ printk (KERN_ALERT "scsi%d not found\n", host);
+ return NULL;
+@@ -715,14 +717,14 @@
+ }
+ hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ if (hostdata->initiate_sdtr & (1 << target)) {
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ printk (KERN_ALERT "target %d already doing SDTR\n", target);
+ return -1;
+ }
+ hostdata->initiate_sdtr |= (1 << target);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return 0;
+ }
+ #endif
+@@ -1033,9 +1035,6 @@
+
+ ccf = clock_to_ccf_710 (expected_clock);
+
+- for (i = 0; i < 16; ++i)
+- hostdata->cmd_allocated[i] = 0;
+-
+ if (hostdata->init_save_regs)
+ hostdata->init_save_regs (host);
+ if (hostdata->init_fixup)
+@@ -1043,7 +1042,6 @@
+
+ if (!the_template) {
+ the_template = host->hostt;
+- first_host = host;
+ }
+
+ /*
+@@ -1306,7 +1304,6 @@
+ hostdata->free->size = max_cmd_size;
+ hostdata->free->free = NULL;
+ hostdata->free->next = NULL;
+- hostdata->extra_allocate = 0;
+
+ /* Allocate command start code space */
+ hostdata->schedule = (chip == 700 || chip == 70066) ?
+@@ -1589,10 +1586,10 @@
+
+ /* The NCR chip _must_ be idle to run the test scripts */
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ if (!hostdata->idle) {
+ printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return -1;
+ }
+
+@@ -1616,7 +1613,7 @@
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
+ DCNTL_STD);
+ printk (" started\n");
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+
+ /*
+ * This is currently a .5 second timeout, since (in theory) no slow
+@@ -1655,7 +1652,7 @@
+ hostdata->script, start);
+ printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
+ NCR53c7x0_read32(DSPS_REG));
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return -1;
+ }
+ hostdata->test_running = 0;
+@@ -1693,7 +1690,7 @@
+ local_irq_disable();
+ if (!hostdata->idle) {
+ printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return -1;
+ }
+
+@@ -1709,7 +1706,7 @@
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+
+ timeout = jiffies + 5 * HZ; /* arbitrary */
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
+@@ -1731,19 +1728,19 @@
+ host->host_no, i);
+ if (!hostdata->idle) {
+ printk("scsi%d : not idle\n", host->host_no);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return -1;
+ }
+ } else if (hostdata->test_completed == -1) {
+ printk ("scsi%d : test 2 timed out\n", host->host_no);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return -1;
+ }
+ hostdata->test_running = 0;
+ }
+ }
+
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return 0;
+ }
+
+@@ -1759,7 +1756,7 @@
+
+ static void
+ NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
+- Scsi_Cmnd *c = cmd->cmd;
++ struct scsi_cmnd *c = cmd->cmd;
+ struct Scsi_Host *host = c->device->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+@@ -1845,7 +1842,7 @@
+ *
+ * Purpose : mark SCSI command as finished, OR'ing the host portion
+ * of the result word into the result field of the corresponding
+- * Scsi_Cmnd structure, and removing it from the internal queues.
++ * scsi_cmnd structure, and removing it from the internal queues.
+ *
+ * Inputs : cmd - command, result - entire result field
+ *
+@@ -1856,7 +1853,7 @@
+
+ static void
+ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
+- Scsi_Cmnd *c = cmd->cmd;
++ struct scsi_cmnd *c = cmd->cmd;
+ struct Scsi_Host *host = c->device->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+@@ -1870,7 +1867,7 @@
+ printk ("scsi%d: abnormal finished\n", host->host_no);
+ #endif
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ found = 0;
+ /*
+ * Traverse the NCR issue array until we find a match or run out
+@@ -1953,7 +1950,7 @@
+ c->result = result;
+ c->scsi_done(c);
+
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ run_process_issue_queue();
+ }
+
+@@ -1975,7 +1972,7 @@
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_break *bp;
+ #if 0
+- Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
++ struct scsi_cmnd *c = cmd ? cmd->cmd : NULL;
+ #endif
+ u32 *dsp;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+@@ -1988,7 +1985,7 @@
+ * dump the appropriate debugging information to standard
+ * output.
+ */
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ for (bp = hostdata->breakpoints; bp && bp->address != dsp;
+ bp = bp->next);
+@@ -2010,7 +2007,7 @@
+ * instruction in bytes.
+ */
+
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+ /*
+ * Function : static void print_synchronous (const char *prefix,
+@@ -2252,7 +2249,7 @@
+ NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ int print;
+- Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
++ struct scsi_cmnd *c = cmd ? cmd->cmd : NULL;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+ u32 dsps,*dsp; /* Argument of the INT instruction */
+@@ -2916,7 +2913,7 @@
+ host->hostdata[0];
+ NCR53c7x0_local_setup(host);
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+
+ /* Disable scsi chip and s/w level 7 ints */
+
+@@ -3017,12 +3014,12 @@
+ }
+ #endif
+ /* Anything needed for your hardware? */
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+
+
+ /*
+- * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
++ * Function static struct NCR53c7x0_cmd *allocate_cmd (struct scsi_cmnd *cmd)
+ *
+ * Purpose : Return the first free NCR53c7x0_cmd structure (which are
+ * reused in a LIFO manner to minimize cache thrashing).
+@@ -3049,86 +3046,25 @@
+ }
+
+ static struct NCR53c7x0_cmd *
+-allocate_cmd (Scsi_Cmnd *cmd) {
++allocate_cmd (struct scsi_cmnd *cmd) {
+ struct Scsi_Host *host = cmd->device->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata[0];
+- u32 real; /* Real address */
+- int size; /* Size of *tmp */
+ struct NCR53c7x0_cmd *tmp;
+ unsigned long flags;
+
+ if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+ printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
+- " target = %d, lun = %d, %s\n",
++ " target = %d, lun = %d\n",
+ host->host_no, hostdata->num_cmds, host->can_queue,
+- cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] &
+- (1 << cmd->device->lun)) ? "already allocated" : "not allocated");
+-
+-/*
+- * If we have not yet reserved commands for this I_T_L nexus, and
+- * the device exists (as indicated by permanent Scsi_Cmnd structures
+- * being allocated under 1.3.x, or being outside of scan_scsis in
+- * 1.2.x), do so now.
+- */
+- if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) &&
+- cmd->device && cmd->device->has_cmdblocks) {
+- if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
+- hostdata->extra_allocate += host->cmd_per_lun;
+- hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun);
+- }
+-
+- for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate,
+- ++hostdata->num_cmds) {
+- /* historically, kmalloc has returned unaligned addresses; pad so we
+- have enough room to ROUNDUP */
+- size = hostdata->max_cmd_size + sizeof (void *);
+-#ifdef FORCE_DSA_ALIGNMENT
+- /*
+- * 53c710 rev.0 doesn't have an add-with-carry instruction.
+- * Ensure we allocate enough memory to force alignment.
+- */
+- size += 256;
+-#endif
+-/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
++ cmd->device->id, cmd->device->lun);
+
+- if (size > 4096) {
+- printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
+- return NULL;
+- }
+- real = get_zeroed_page(GFP_ATOMIC);
+- if (real == 0)
+- return NULL;
+- memset((void *)real, 0, 4096);
+- cache_push(virt_to_phys((void *)real), 4096);
+- cache_clear(virt_to_phys((void *)real), 4096);
+- kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
+- tmp = ROUNDUP(real, void *);
+-#ifdef FORCE_DSA_ALIGNMENT
+- {
+- if (((u32)tmp & 0xff) > CmdPageStart)
+- tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
+- tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
+-#if 0
+- printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
+- size, real, (u32)tmp);
+-#endif
+- }
+-#endif
+- tmp->real = (void *)real;
+- tmp->size = size;
+- tmp->free = ((void (*)(void *, int)) my_free_page);
+- local_irq_save(flags);
+- tmp->next = hostdata->free;
+- hostdata->free = tmp;
+- local_irq_restore(flags);
+- }
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ tmp = (struct NCR53c7x0_cmd *) hostdata->free;
+ if (tmp) {
+ hostdata->free = tmp->next;
+ }
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ if (!tmp)
+ printk ("scsi%d : can't allocate command for target %d lun %d\n",
+ host->host_no, cmd->device->id, cmd->device->lun);
+@@ -3136,11 +3072,11 @@
+ }
+
+ /*
+- * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd)
++ * Function static struct NCR53c7x0_cmd *create_cmd (struct scsi_cmnd *cmd)
+ *
+ *
+ * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the
+- * Scsi_Cmnd structure passed in cmd, including dsa and Linux field
++ * scsi_cmnd structure passed in cmd, including dsa and Linux field
+ * initialization, and dsa code relocation.
+ *
+ * Inputs : cmd - SCSI command
+@@ -3149,7 +3085,7 @@
+ * NULL on failure.
+ */
+ static struct NCR53c7x0_cmd *
+-create_cmd (Scsi_Cmnd *cmd) {
++create_cmd (struct scsi_cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host = cmd->device->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+@@ -3173,7 +3109,7 @@
+ return NULL;
+
+ /*
+- * Copy CDB and initialised result fields from Scsi_Cmnd to NCR53c7x0_cmd.
++ * Copy CDB and initialised result fields from scsi_cmnd to NCR53c7x0_cmd.
+ * We do this because NCR53c7x0_cmd may have a special cache mode
+ * selected to cope with lack of bus snooping, etc.
+ */
+@@ -3316,7 +3252,7 @@
+
+ patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+ /*
+- * XXX is this giving 53c710 access to the Scsi_Cmnd in some way?
++ * XXX is this giving 53c710 access to the scsi_cmnd in some way?
+ * Do we need to change it for caching reasons?
+ */
+ patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+@@ -3347,17 +3283,17 @@
+ memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
+ sizeof(wdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ hostdata->initiate_wdtr &= ~(1 << cmd->device->id);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) {
+ memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
+ sizeof(sdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+ tmp->flags |= CMD_FLAG_SDTR;
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ hostdata->initiate_sdtr &= ~(1 << cmd->device->id);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+
+ }
+ #if 1
+@@ -3570,8 +3506,8 @@
+ }
+
+ /*
+- * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
+- * void (*done)(Scsi_Cmnd *))
++ * Function : int NCR53c7xx_queue_command (struct scsi_cmnd *cmd,
++ * void (*done)(struct scsi_cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+@@ -3585,18 +3521,18 @@
+ * twiddling done to the host specific fields of cmd. If the
+ * process_issue_queue coroutine isn't running, it is restarted.
+ *
+- * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to
++ * NOTE : we use the host_scribble field of the scsi_cmnd structure to
+ * hold our own data, and pervert the ptr field of the SCp field
+ * to create a linked list.
+ */
+
+ int
+-NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
++NCR53c7xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) {
+ struct Scsi_Host *host = cmd->device->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata[0];
+ unsigned long flags;
+- Scsi_Cmnd *tmp;
++ struct scsi_cmnd *tmp;
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+@@ -3614,7 +3550,7 @@
+ }
+ #endif
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
+ || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+ !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun)))
+@@ -3629,7 +3565,7 @@
+ cmd->device->id, cmd->device->lun);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return 0;
+ }
+
+@@ -3638,7 +3574,7 @@
+ printk("scsi%d : maximum commands exceeded\n", host->host_no);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return 0;
+ }
+
+@@ -3650,7 +3586,7 @@
+ host->host_no);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return 0;
+ }
+ }
+@@ -3673,18 +3609,18 @@
+ cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr;
+- tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
++ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp->SCp.ptr;
++ tmp = (struct scsi_cmnd *) tmp->SCp.ptr);
+ tmp->SCp.ptr = (unsigned char *) cmd;
+ }
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ run_process_issue_queue();
+ return 0;
+ }
+
+ /*
+ * Function : void to_schedule_list (struct Scsi_Host *host,
+- * struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
++ * struct NCR53c7x0_hostdata * hostdata, struct scsi_cmnd *cmd)
+ *
+ * Purpose : takes a SCSI command which was just removed from the
+ * issue queue, and deals with it by inserting it in the first
+@@ -3705,7 +3641,7 @@
+ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+- Scsi_Cmnd *tmp = cmd->cmd;
++ struct scsi_cmnd *tmp = cmd->cmd;
+ unsigned long flags;
+ /* dsa start is negative, so subtraction is used */
+ volatile u32 *ncrcurrent;
+@@ -3717,7 +3653,7 @@
+ virt_to_bus(hostdata->dsa), hostdata->dsa);
+ #endif
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+
+ /*
+ * Work around race condition : if an interrupt fired and we
+@@ -3730,7 +3666,7 @@
+ cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ hostdata->free = cmd;
+ tmp->scsi_done(tmp);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return;
+ }
+
+@@ -3760,7 +3696,7 @@
+ cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ hostdata->free = cmd;
+ tmp->scsi_done(tmp);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return;
+ }
+
+@@ -3781,12 +3717,12 @@
+ NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
+ }
+
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+
+ /*
+ * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata
+- * *hostdata, Scsi_Cmnd *cmd)
++ * *hostdata, struct scsi_cmnd *cmd)
+ *
+ * Purpose : decide if we can pass the given SCSI command on to the
+ * device in question or not.
+@@ -3796,7 +3732,7 @@
+
+ static __inline__ int
+ busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+- Scsi_Cmnd *cmd) {
++ struct scsi_cmnd *cmd) {
+ /* FIXME : in the future, this needs to accommodate SCSI-II tagged
+ queuing, and we may be able to play with fairness here a bit.
+ */
+@@ -3822,8 +3758,8 @@
+
+ static void
+ process_issue_queue (unsigned long flags) {
+- Scsi_Cmnd *tmp, *prev;
+- struct Scsi_Host *host;
++ struct scsi_cmnd *tmp, *prev;
++ struct Scsi_Host *host, *s;
+ struct NCR53c7x0_hostdata *hostdata;
+ int done;
+
+@@ -3841,14 +3777,13 @@
+ do {
+ local_irq_disable(); /* Freeze request queues */
+ done = 1;
+- for (host = first_host; host && host->hostt == the_template;
+- host = host->next) {
++ list_for_each_entry_safe(host, s, &the_template->legacy_hosts, sht_legacy_list) {
+ hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
+- local_irq_disable();
++ spin_lock_irq(host->host_lock);
+ if (hostdata->issue_queue) {
+ if (hostdata->state == STATE_DISABLED) {
+- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+- hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
++ tmp = (struct scsi_cmnd *) hostdata->issue_queue;
++ hostdata->issue_queue = (struct scsi_cmnd *) tmp->SCp.ptr;
+ tmp->result = (DID_BAD_TARGET << 16);
+ if (tmp->host_scribble) {
+ ((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
+@@ -3860,15 +3795,15 @@
+ tmp->scsi_done (tmp);
+ done = 0;
+ } else
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+- prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
++ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
++ prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *)
+ tmp->SCp.ptr)
+ if (!tmp->host_scribble ||
+ !busyp (host, hostdata, tmp)) {
+ if (prev)
+ prev->SCp.ptr = tmp->SCp.ptr;
+ else
+- hostdata->issue_queue = (Scsi_Cmnd *)
++ hostdata->issue_queue = (struct scsi_cmnd *)
+ tmp->SCp.ptr;
+ tmp->SCp.ptr = NULL;
+ if (tmp->host_scribble) {
+@@ -3893,6 +3828,7 @@
+ done = 0;
+ } /* if target/lun is not busy */
+ } /* if hostdata->issue_queue */
++ spin_unlock(host->host_lock);
+ if (!done)
+ local_irq_restore(flags);
+ } /* for host */
+@@ -4103,7 +4039,7 @@
+ int cnt = 0;
+ int i = insn_log_index;
+ int size;
+- struct Scsi_Host *host = first_host;
++ struct Scsi_Host *host = (struct Scsi_Host *)the_template->legacy_hosts->next;
+
+ while (cnt < 4096) {
+ printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4);
+@@ -4161,14 +4097,14 @@
+ * completion.
+ */
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ restart:
+ for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list),
+ cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+ cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
+ cmd = (struct NCR53c7x0_cmd *) cmd->next)
+ {
+- Scsi_Cmnd *tmp;
++ struct scsi_cmnd *tmp;
+
+ if (!cmd) {
+ printk("scsi%d : very weird.\n", host->host_no);
+@@ -4176,7 +4112,7 @@
+ }
+
+ if (!(tmp = cmd->cmd)) {
+- printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n",
++ printk("scsi%d : weird. NCR53c7x0_cmd has no scsi_cmnd\n",
+ host->host_no);
+ continue;
+ }
+@@ -4215,7 +4151,7 @@
+ tmp->scsi_done(tmp);
+ goto restart;
+ }
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+
+ if (!search_found) {
+ printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
+@@ -4250,7 +4186,7 @@
+ struct NCR53c7x0_cmd *cmd; /* command which halted */
+ u32 *dsa; /* DSA */
+ int handled = 0;
+-
++ unsigned long flags;
+ #ifdef NCR_DEBUG
+ char buf[80]; /* Debugging sprintf buffer */
+ size_t buflen; /* Length of same */
+@@ -4259,6 +4195,7 @@
+ host = (struct Scsi_Host *)dev_id;
+ hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
+ NCR53c7x0_local_setup(host);
++ spin_lock_irqsave(host->host_lock, flags);
+
+ /*
+ * Only read istat once per loop, since reading it again will unstack
+@@ -4351,7 +4288,8 @@
+ }
+ }
+ }
+- return IRQ_HANDLED;
++ spin_unlock_irqrestore(host->host_lock, flags);
++ return IRQ_RETVAL(handled);
+ }
+
+
+@@ -4360,7 +4298,7 @@
+ *
+ * Purpose : Assuming that the NCR SCSI processor is currently
+ * halted, break the currently established nexus. Clean
+- * up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
++ * up of the NCR53c7x0_cmd and scsi_cmnd structures should
+ * be done on receipt of the abort interrupt.
+ *
+ * Inputs : host - SCSI host
+@@ -4899,12 +4837,12 @@
+ /* Don't print instr. until we write DSP at end of intr function */
+ } else if (hostdata->options & OPTION_DEBUG_SINGLE) {
+ print_insn (host, dsp, "s ", 0);
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ /* XXX - should we do this, or can we get away with writing dsp? */
+
+ NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
+ ~DCNTL_SSM) | DCNTL_STD);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ } else {
+ printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
+ " ", host->host_no);
+@@ -5127,7 +5065,7 @@
+ }
+
+ /*
+- * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
++ * Function : int NCR53c7xx_abort (struct scsi_cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command, doing all necessary
+ * cleanup of the issue_queue, running_list, shared Linux/NCR
+@@ -5139,14 +5077,14 @@
+ */
+
+ int
+-NCR53c7xx_abort (Scsi_Cmnd *cmd) {
++NCR53c7xx_abort (struct scsi_cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host = cmd->device->host;
+ struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
+ host->hostdata[0] : NULL;
+ unsigned long flags;
+ struct NCR53c7x0_cmd *curr, **prev;
+- Scsi_Cmnd *me, **last;
++ struct scsi_cmnd *me, **last;
+ #if 0
+ static long cache_pid = -1;
+ #endif
+@@ -5155,10 +5093,10 @@
+ if (!host) {
+ printk ("Bogus SCSI command pid %ld; no host structure\n",
+ cmd->pid);
+- return SCSI_ABORT_ERROR;
++ return FAILED;
+ } else if (!hostdata) {
+ printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
+- return SCSI_ABORT_ERROR;
++ return FAILED;
+ }
+ NCR53c7x0_local_setup(host);
+
+@@ -5179,10 +5117,10 @@
+ printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
+ cmd->pid);
+ NCR53c7x0_intr (host->irq, NULL, NULL);
+- return SCSI_ABORT_BUSY;
++ return FAILED;
+ }
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ #if 0
+ if (cache_pid == cmd->pid)
+ panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
+@@ -5201,13 +5139,13 @@
+ * pull the command out of the old queue, and call it aborted.
+ */
+
+- for (me = (Scsi_Cmnd *) hostdata->issue_queue,
+- last = (Scsi_Cmnd **) &(hostdata->issue_queue);
+- me && me != cmd; last = (Scsi_Cmnd **)&(me->SCp.ptr),
+- me = (Scsi_Cmnd *)me->SCp.ptr);
++ for (me = (struct scsi_cmnd *) hostdata->issue_queue,
++ last = (struct scsi_cmnd **) &(hostdata->issue_queue);
++ me && me != cmd; last = (struct scsi_cmnd **)&(me->SCp.ptr),
++ me = (struct scsi_cmnd *)me->SCp.ptr);
+
+ if (me) {
+- *last = (Scsi_Cmnd *) me->SCp.ptr;
++ *last = (struct scsi_cmnd *) me->SCp.ptr;
+ if (me->host_scribble) {
+ ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
+ hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
+@@ -5217,9 +5155,9 @@
+ cmd->scsi_done(cmd);
+ printk ("scsi%d : found command %ld in Linux issue queue\n",
+ host->host_no, me->pid);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ run_process_issue_queue();
+- return SCSI_ABORT_SUCCESS;
++ return SUCCESS;
+ }
+
+ /*
+@@ -5243,13 +5181,13 @@
+ cmd->scsi_done(cmd);
+ printk ("scsi%d : found finished command %ld in running list\n",
+ host->host_no, cmd->pid);
+- local_irq_restore(flags);
+- return SCSI_ABORT_NOT_RUNNING;
++ spin_unlock_irqrestore(host->host_lock, flags);
++ return SUCCESS;
+ } else {
+ printk ("scsi%d : DANGER : command running, can not abort.\n",
+ cmd->device->host->host_no);
+- local_irq_restore(flags);
+- return SCSI_ABORT_BUSY;
++ spin_unlock_irqrestore(host->host_lock, flags);
++ return FAILED;
+ }
+ }
+
+@@ -5280,21 +5218,20 @@
+ */
+ --hostdata->busy[cmd->device->id][cmd->device->lun];
+ }
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ cmd->scsi_done(cmd);
+
+ /*
+ * We need to run process_issue_queue since termination of this command
+ * may allow another queued command to execute first?
+ */
+- return SCSI_ABORT_NOT_RUNNING;
++ return SUCCESS;
+ }
+
+ /*
+- * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd)
++ * Function : int NCR53c7xx_reset (struct scsi_cmnd *cmd)
+ *
+- * Purpose : perform a hard reset of the SCSI bus and NCR
+- * chip.
++ * Purpose : perform a hard reset of the SCSI bus.
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+@@ -5302,12 +5239,12 @@
+ */
+
+ int
+-NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
++NCR53c7xx_reset (struct scsi_cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ int found = 0;
+ struct NCR53c7x0_cmd * c;
+- Scsi_Cmnd *tmp;
++ struct scsi_cmnd *tmp;
+ /*
+ * When we call scsi_done(), it's going to wake up anything sleeping on the
+ * resources which were in use by the aborted commands, and we'll start to
+@@ -5322,19 +5259,19 @@
+ * pointer), do our reinitialization, and then call the done function for
+ * each command.
+ */
+- Scsi_Cmnd *nuke_list = NULL;
++ struct scsi_cmnd *nuke_list = NULL;
+ struct Scsi_Host *host = cmd->device->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata[0];
+
+ NCR53c7x0_local_setup(host);
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ ncr_halt (host);
+ print_lots (host);
+ dump_events (host, 30);
+ ncr_scsi_reset (host);
+ for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
+- 0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
++ 0 /* issue */ ); tmp; tmp = (struct scsi_cmnd *) tmp->SCp.buffer)
+ if (tmp == cmd) {
+ found = 1;
+ break;
+@@ -5357,19 +5294,21 @@
+ }
+
+ NCR53c7x0_driver_init (host);
++#if 0
+ hostdata->soft_reset (host);
++#endif
+ if (hostdata->resets == 0)
+ disable(host);
+ else if (hostdata->resets != -1)
+ --hostdata->resets;
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ for (; nuke_list; nuke_list = tmp) {
+- tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
++ tmp = (struct scsi_cmnd *) nuke_list->SCp.buffer;
+ nuke_list->result = DID_RESET << 16;
+ nuke_list->scsi_done (nuke_list);
+ }
+- local_irq_restore(flags);
+- return SCSI_RESET_SUCCESS;
++ spin_unlock_irqrestore(host->host_lock, flags);
++ return SUCCESS;
+ }
+
+ /*
+@@ -5378,7 +5317,7 @@
+ */
+
+ /*
+- * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
++ * Function : int insn_to_offset (struct scsi_cmnd *cmd, u32 *insn)
+ *
+ * Purpose : convert instructions stored at NCR pointer into data
+ * pointer offset.
+@@ -5391,7 +5330,7 @@
+
+
+ static int
+-insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
++insn_to_offset (struct scsi_cmnd *cmd, u32 *insn) {
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0];
+ struct NCR53c7x0_cmd *ncmd =
+@@ -5445,7 +5384,7 @@
+
+
+ /*
+- * Function : void print_progress (Scsi_Cmnd *cmd)
++ * Function : void print_progress (struct scsi_cmnd *cmd)
+ *
+ * Purpose : print the current location of the saved data pointer
+ *
+@@ -5454,7 +5393,7 @@
+ */
+
+ static void
+-print_progress (Scsi_Cmnd *cmd) {
++print_progress (struct scsi_cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_cmd *ncmd =
+ (struct NCR53c7x0_cmd *) cmd->host_scribble;
+@@ -5512,7 +5451,7 @@
+ host->hostdata[0];
+ int i, len;
+ char *ptr;
+- Scsi_Cmnd *cmd;
++ struct scsi_cmnd *cmd;
+
+ if (check_address ((unsigned long) dsa, hostdata->dsa_end -
+ hostdata->dsa_start) == -1) {
+@@ -5548,7 +5487,7 @@
+
+ printk(" + %d : select_indirect = 0x%x\n",
+ hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
+- cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
++ cmd = (struct scsi_cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+ printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
+ (u32) virt_to_bus(cmd));
+ /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
+@@ -5588,16 +5527,16 @@
+ u32 *dsa, *next_dsa;
+ volatile u32 *ncrcurrent;
+ int left;
+- Scsi_Cmnd *cmd, *next_cmd;
++ struct scsi_cmnd *cmd, *next_cmd;
+ unsigned long flags;
+
+ printk ("scsi%d : issue queue\n", host->host_no);
+
+- for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue;
++ for (left = host->can_queue, cmd = (struct scsi_cmnd *) hostdata->issue_queue;
+ left >= 0 && cmd;
+ cmd = next_cmd) {
+- next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
+- local_irq_save(flags);
++ next_cmd = (struct scsi_cmnd *) cmd->SCp.ptr;
++ spin_lock_irqsave(host->host_lock, flags);
+ if (cmd->host_scribble) {
+ if (check_address ((unsigned long) (cmd->host_scribble),
+ sizeof (cmd->host_scribble)) == -1)
+@@ -5610,7 +5549,7 @@
+ } else
+ printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
+ host->host_no, cmd->pid, cmd->device->id, cmd->device->lun);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+
+ if (left <= 0) {
+@@ -5642,7 +5581,7 @@
+ dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+ left >= 0 && dsa;
+ dsa = next_dsa) {
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
+ printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
+ dsa);
+@@ -5653,7 +5592,7 @@
+ next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+ print_dsa (host, dsa, "");
+ }
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+ printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
+ if (left < 0)
+@@ -5743,14 +5682,14 @@
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+ NCR53c7x0_local_setup(host);
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ /* Get in a state where we can reset the SCSI bus */
+ ncr_halt (host);
+ ncr_scsi_reset (host);
+ hostdata->soft_reset(host);
+
+ disable (host);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ return 0;
+ }
+
+@@ -5765,11 +5704,11 @@
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ udelay(25); /* Minimum amount of time to assert RST */
+ NCR53c7x0_write8(SCNTL1_REG, 0);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+
+ /*
+@@ -5782,26 +5721,26 @@
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+ unsigned long flags;
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ ncr_scsi_reset(host);
+ NCR53c7x0_driver_init (host);
+ if (hostdata->soft_reset)
+ hostdata->soft_reset (host);
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ }
+
+
+ /*
+- * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
++ * Function : struct scsi_cmnd *return_outstanding_commands (struct Scsi_Host *host,
+ * int free, int issue)
+ *
+ * Purpose : return a linked list (using the SCp.buffer field as next,
+ * so we don't perturb hostdata. We don't use a field of the
+ * NCR53c7x0_cmd structure since we may not have allocated one
+- * for the command causing the reset.) of Scsi_Cmnd structures that
++ * for the command causing the reset.) of scsi_cmnd structures that
+ * had propagated below the Linux issue queue level. If free is set,
+ * free the NCR53c7x0_cmd structures which are associated with
+- * the Scsi_Cmnd structures, and clean up any internal
++ * the scsi_cmnd structures, and clean up any internal
+ * NCR lists that the commands were on. If issue is set,
+ * also return commands in the issue queue.
+ *
+@@ -5811,14 +5750,14 @@
+ * if the free flag is set.
+ */
+
+-static Scsi_Cmnd *
++static struct scsi_cmnd *
+ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+ struct NCR53c7x0_cmd *c;
+ int i;
+ u32 *ncrcurrent;
+- Scsi_Cmnd *list = NULL, *tmp;
++ struct scsi_cmnd *list = NULL, *tmp, *next_cmd;
+ for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
+ c = (struct NCR53c7x0_cmd *) c->next) {
+ if (c->cmd->SCp.buffer) {
+@@ -5847,7 +5786,9 @@
+ }
+
+ if (issue) {
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
++ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp; tmp = next_cmd) {
++ next_cmd = (struct scsi_cmnd *) tmp->SCp.ptr;
++
+ if (tmp->SCp.buffer) {
+ printk ("scsi%d : loop detected in issue queue!\n",
+ host->host_no);
+@@ -5882,17 +5823,17 @@
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata[0];
+ unsigned long flags;
+- Scsi_Cmnd *nuke_list, *tmp;
+- local_irq_save(flags);
++ struct scsi_cmnd *nuke_list, *tmp;
++ spin_lock_irqsave(host->host_lock, flags);
+ if (hostdata->state != STATE_HALTED)
+ ncr_halt (host);
+ nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
+ hard_reset (host);
+ hostdata->state = STATE_DISABLED;
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ printk ("scsi%d : nuking commands\n", host->host_no);
+ for (; nuke_list; nuke_list = tmp) {
+- tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
++ tmp = (struct scsi_cmnd *) nuke_list->SCp.buffer;
+ nuke_list->result = DID_ERROR << 16;
+ nuke_list->scsi_done(nuke_list);
+ }
+@@ -5922,7 +5863,7 @@
+ int stage;
+ NCR53c7x0_local_setup(host);
+
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ /* Stage 0 : eat all interrupts
+ Stage 1 : set ABORT
+ Stage 2 : eat all but abort interrupts
+@@ -5957,7 +5898,7 @@
+ }
+ }
+ hostdata->state = STATE_HALTED;
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ #if 0
+ print_lots (host);
+ #endif
+@@ -6011,7 +5952,7 @@
+ * still be guaranteed that they're happening on the same
+ * event structure.
+ */
+- local_irq_save(flags);
++ spin_lock_irqsave(host->host_lock, flags);
+ #if 0
+ event = hostdata->events[i];
+ #else
+@@ -6019,7 +5960,7 @@
+ sizeof(event));
+ #endif
+
+- local_irq_restore(flags);
++ spin_unlock_irqrestore(host->host_lock, flags);
+ printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
+ host->host_no, event_name (event.event), count,
+ (long) event.time.tv_sec, (long) event.time.tv_usec,
+@@ -6054,6 +5995,72 @@
+ return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0);
+ }
+
++int
++NCR53c7xx_slave_configure(struct scsi_device *sdev) {
++ struct Scsi_Host *host = sdev->host;
++ struct NCR53c7x0_hostdata *hostdata =
++ (struct NCR53c7x0_hostdata *) host->hostdata[0];
++ struct NCR53c7x0_cmd *tmp;
++ u32 real; /* Real address */
++ int size; /* Size of *tmp */
++ unsigned long flags;
++ int extra_allocate = 0;
++
++/*
++ * Reserve commands for this I_T_L nexus.
++ */
++ if (hostdata->num_cmds < host->can_queue)
++ extra_allocate = host->cmd_per_lun;
++
++ for (; extra_allocate > 0 ; --extra_allocate,
++ ++hostdata->num_cmds) {
++ /* historically, kmalloc has returned unaligned addresses; pad so we
++ have enough room to ROUNDUP */
++ size = hostdata->max_cmd_size + sizeof (void *);
++#ifdef FORCE_DSA_ALIGNMENT
++ /*
++ * 53c710 rev.0 doesn't have an add-with-carry instruction.
++ * Ensure we allocate enough memory to force alignment.
++ */
++ size += 256;
++#endif
++/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
++
++ if (size > 4096) {
++ printk (KERN_ERR "53c7xx: slave_configure size > 4K\n");
++ return -ENOMEM;
++ }
++ real = get_zeroed_page(GFP_ATOMIC);
++ if (real == 0)
++ return -ENOMEM;
++ memset((void *)real, 0, 4096);
++ cache_push(virt_to_phys((void *)real), 4096);
++ cache_clear(virt_to_phys((void *)real), 4096);
++ kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
++ tmp = ROUNDUP(real, void *);
++#ifdef FORCE_DSA_ALIGNMENT
++ {
++ if (((u32)tmp & 0xff) > CmdPageStart)
++ tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
++ tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
++#if 0
++ printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
++ size, real, (u32)tmp);
++#endif
++ }
++#endif
++ tmp->real = (void *)real;
++ tmp->size = size;
++ tmp->free = ((void (*)(void *, int)) my_free_page);
++ spin_lock_irqsave(host->host_lock, flags);
++ tmp->next = hostdata->free;
++ hostdata->free = tmp;
++ spin_unlock_irqrestore(host->host_lock, flags);
++ }
++
++ return 0;
++}
++
+ #ifdef MODULE
+ int
+ NCR53c7x0_release(struct Scsi_Host *host) {
+@@ -6063,19 +6070,22 @@
+ shutdown (host);
+ if (host->irq != SCSI_IRQ_NONE)
+ {
+- int irq_count;
+- struct Scsi_Host *tmp;
+- for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
+- if (tmp->hostt == the_template && tmp->irq == host->irq)
++ int irq_count = 0;
++ struct Scsi_Host *tmp, *s;
++ list_for_each_entry_safe(tmp, s, &the_template->legacy_hosts, sht_legacy_list) {
++ if (tmp->irq == host->irq)
+ ++irq_count;
++ }
+ if (irq_count == 1)
+ free_irq(host->irq, NULL);
+ }
++#ifdef CONFIG_ISA
+ if (host->dma_channel != DMA_NONE)
+ free_dma(host->dma_channel);
++#endif
+ if (host->io_port)
+ release_region(host->io_port, host->n_io_port);
+-
++
+ for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp,
+ --hostdata->num_cmds) {
+ tmp = (struct NCR53c7x0_cmd *) cmd->next;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/53c7xx.h linux-m68k/drivers/scsi/53c7xx.h
+--- linux-i386/drivers/scsi/53c7xx.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/53c7xx.h 2004-10-30 14:41:36.000000000 +0200
+@@ -997,7 +997,7 @@
+ u32 *dsa; /* What's in the DSA register now (virt) */
+ /*
+ * A few things from that SCSI pid so we know what happened after
+- * the Scsi_Cmnd structure in question may have disappeared.
++ * the scsi_cmnd structure in question may have disappeared.
+ */
+ unsigned long pid; /* The SCSI PID which caused this
+ event */
+@@ -1029,8 +1029,8 @@
+ void (* free)(void *, int); /* Command to deallocate; NULL
+ for structures allocated with
+ scsi_register, etc. */
+- Scsi_Cmnd *cmd; /* Associated Scsi_Cmnd
+- structure, Scsi_Cmnd points
++ struct scsi_cmnd *cmd; /* Associated scsi_cmnd
++ structure, scsi_cmnd points
+ at NCR53c7x0_cmd using
+ host_scribble structure */
+
+@@ -1039,8 +1039,8 @@
+
+ int flags; /* CMD_* flags */
+
+- unsigned char cmnd[12]; /* CDB, copied from Scsi_Cmnd */
+- int result; /* Copy to Scsi_Cmnd when done */
++ unsigned char cmnd[12]; /* CDB, copied from scsi_cmnd */
++ int result; /* Copy to scsi_cmnd when done */
+
+ struct { /* Private non-cached bounce buffer */
+ unsigned char buf[256];
+@@ -1339,7 +1339,7 @@
+ volatile struct NCR53c7x0_synchronous sync[16]
+ __attribute__ ((aligned (4)));
+
+- volatile Scsi_Cmnd *issue_queue
++ volatile struct scsi_cmnd *issue_queue
+ __attribute__ ((aligned (4)));
+ /* waiting to be issued by
+ Linux driver */
+@@ -1363,10 +1363,6 @@
+ */
+ volatile int num_cmds; /* Number of commands
+ allocated */
+- volatile int extra_allocate;
+- volatile unsigned char cmd_allocated[16]; /* Have we allocated commands
+- for this target yet? If not,
+- do so ASAP */
+ volatile unsigned char busy[16][8]; /* number of commands
+ executing on each target
+ */
+@@ -1589,11 +1585,11 @@
+ /* Patch field in dsa structure (assignment should be +=?) */
+ #define patch_dsa_32(dsa, symbol, word, value) \
+ { \
+- (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \
++ (dsa)[(hostdata->symbol - hostdata->dsa_start) / sizeof(u32) \
+ + (word)] = (value); \
+ if (hostdata->options & OPTION_DEBUG_DSA) \
+ printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
+- #dsa, #symbol, hostdata->##symbol, \
++ #dsa, #symbol, hostdata->symbol, \
+ (word), (u32) (value)); \
+ }
+
+@@ -1603,6 +1599,12 @@
+ extern int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
+ unsigned long base, int io_port, int irq, int dma,
+ long long options, int clock);
++extern const char *NCR53c7x0_info(void);
++extern int NCR53c7xx_queue_command(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
++extern int NCR53c7xx_abort(struct scsi_cmnd *);
++extern int NCR53c7x0_release (struct Scsi_Host *);
++extern int NCR53c7xx_reset(struct scsi_cmnd *);
++extern int NCR53c7xx_slave_configure(struct scsi_device *);
+
+ #endif /* NCR53c710_C */
+ #endif /* NCR53c710_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/Kconfig linux-m68k/drivers/scsi/Kconfig
+--- linux-i386/drivers/scsi/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/Kconfig 2006-09-24 16:33:34.000000000 +0200
+@@ -1671,7 +1671,7 @@
+
+ config SCSI_AMIGA7XX
+ bool "Amiga NCR53c710 SCSI support (EXPERIMENTAL)"
+- depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN
++ depends on AMIGA && SCSI && EXPERIMENTAL
+ help
+ Support for various NCR53c710-based SCSI controllers on the Amiga.
+ This includes:
+@@ -1771,7 +1771,7 @@
+
+ config MVME16x_SCSI
+ bool "NCR53C710 SCSI driver for MVME16x"
+- depends on MVME16x && SCSI && BROKEN
++ depends on MVME16x && SCSI
+ select SCSI_SPI_ATTRS
+ help
+ The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
+@@ -1780,7 +1780,7 @@
+
+ config BVME6000_SCSI
+ bool "NCR53C710 SCSI driver for BVME6000"
+- depends on BVME6000 && SCSI && BROKEN
++ depends on BVME6000 && SCSI
+ select SCSI_SPI_ATTRS
+ help
+ The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
+@@ -1797,7 +1797,7 @@
+
+ config SUN3_SCSI
+ tristate "Sun3 NCR5380 SCSI"
+- depends on SUN3 && SCSI && BROKEN
++ depends on SUN3 && SCSI
+ select SCSI_SPI_ATTRS
+ help
+ This option will enable support for the OBIO (onboard io) NCR5380
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/NCR5380.c linux-m68k/drivers/scsi/NCR5380.c
+--- linux-i386/drivers/scsi/NCR5380.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/NCR5380.c 2006-09-24 16:33:34.000000000 +0200
+@@ -354,6 +354,7 @@
+ return -ETIMEDOUT;
+ }
+
++#if NDEBUG
+ static struct {
+ unsigned char value;
+ const char *name;
+@@ -367,7 +368,6 @@
+ {PHASE_UNKNOWN, "UNKNOWN"}
+ };
+
+-#if NDEBUG
+ static struct {
+ unsigned char mask;
+ const char *name;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/amiga7xx.c linux-m68k/drivers/scsi/amiga7xx.c
+--- linux-i386/drivers/scsi/amiga7xx.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/amiga7xx.c 2006-09-24 16:33:34.000000000 +0200
+@@ -25,8 +25,14 @@
+ #include "scsi.h"
+ #include <scsi/scsi_host.h>
+ #include "53c7xx.h"
+-#include "amiga7xx.h"
+
++#ifndef CMD_PER_LUN
++#define CMD_PER_LUN 3
++#endif
++
++#ifndef CAN_QUEUE
++#define CAN_QUEUE 24
++#endif
+
+ static int amiga7xx_register_one(struct scsi_host_template *tpnt,
+ unsigned long address)
+@@ -113,8 +119,10 @@
+ {
+ if (shost->irq)
+ free_irq(shost->irq, NULL);
++#ifdef CONFIG_ISA
+ if (shost->dma_channel != 0xff)
+ free_dma(shost->dma_channel);
++#endif
+ if (shost->io_port && shost->n_io_port)
+ release_region(shost->io_port, shost->n_io_port);
+ scsi_unregister(shost);
+@@ -126,8 +134,9 @@
+ .detect = amiga7xx_detect,
+ .release = amiga7xx_release,
+ .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
++ .eh_abort_handler = NCR53c7xx_abort,
++ .eh_bus_reset_handler = NCR53c7xx_reset,
++ .slave_configure = NCR53c7xx_slave_configure,
+ .can_queue = 24,
+ .this_id = 7,
+ .sg_tablesize = 63,
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/amiga7xx.h linux-m68k/drivers/scsi/amiga7xx.h
+--- linux-i386/drivers/scsi/amiga7xx.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/amiga7xx.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,23 +0,0 @@
+-#ifndef AMIGA7XX_H
+-
+-#include <linux/types.h>
+-
+-int amiga7xx_detect(struct scsi_host_template *);
+-const char *NCR53c7x0_info(void);
+-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int NCR53c7xx_abort(Scsi_Cmnd *);
+-int NCR53c7x0_release (struct Scsi_Host *);
+-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+-
+-#ifndef CMD_PER_LUN
+-#define CMD_PER_LUN 3
+-#endif
+-
+-#ifndef CAN_QUEUE
+-#define CAN_QUEUE 24
+-#endif
+-
+-#include <scsi/scsicam.h>
+-
+-#endif /* AMIGA7XX_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/bvme6000.c linux-m68k/drivers/scsi/bvme6000.c
+--- linux-i386/drivers/scsi/bvme6000.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/bvme6000.c 2006-01-15 02:01:21.000000000 +0100
+@@ -18,10 +18,16 @@
+ #include "scsi.h"
+ #include <scsi/scsi_host.h>
+ #include "53c7xx.h"
+-#include "bvme6000.h"
+
+ #include<linux/stat.h>
+
++#ifndef CMD_PER_LUN
++#define CMD_PER_LUN 3
++#endif
++
++#ifndef CAN_QUEUE
++#define CAN_QUEUE 24
++#endif
+
+ int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
+ {
+@@ -51,8 +57,10 @@
+ {
+ if (shost->irq)
+ free_irq(shost->irq, NULL);
++#ifdef CONFIG_ISA
+ if (shost->dma_channel != 0xff)
+ free_dma(shost->dma_channel);
++#endif
+ if (shost->io_port && shost->n_io_port)
+ release_region(shost->io_port, shost->n_io_port);
+ scsi_unregister(shost);
+@@ -64,8 +72,9 @@
+ .detect = bvme6000_scsi_detect,
+ .release = bvme6000_scsi_release,
+ .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
++ .eh_abort_handler = NCR53c7xx_abort,
++ .eh_bus_reset_handler = NCR53c7xx_reset,
++ .slave_configure = NCR53c7xx_slave_configure,
+ .can_queue = 24,
+ .this_id = 7,
+ .sg_tablesize = 63,
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/bvme6000.h linux-m68k/drivers/scsi/bvme6000.h
+--- linux-i386/drivers/scsi/bvme6000.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/bvme6000.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,24 +0,0 @@
+-#ifndef BVME6000_SCSI_H
+-#define BVME6000_SCSI_H
+-
+-#include <linux/types.h>
+-
+-int bvme6000_scsi_detect(struct scsi_host_template *);
+-const char *NCR53c7x0_info(void);
+-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int NCR53c7xx_abort(Scsi_Cmnd *);
+-int NCR53c7x0_release (struct Scsi_Host *);
+-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+-
+-#ifndef CMD_PER_LUN
+-#define CMD_PER_LUN 3
+-#endif
+-
+-#ifndef CAN_QUEUE
+-#define CAN_QUEUE 24
+-#endif
+-
+-#include <scsi/scsicam.h>
+-
+-#endif /* BVME6000_SCSI_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/mvme16x.c linux-m68k/drivers/scsi/mvme16x.c
+--- linux-i386/drivers/scsi/mvme16x.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/mvme16x.c 2006-01-15 02:01:22.000000000 +0100
+@@ -16,10 +16,16 @@
+ #include "scsi.h"
+ #include <scsi/scsi_host.h>
+ #include "53c7xx.h"
+-#include "mvme16x.h"
+
+ #include<linux/stat.h>
+
++#ifndef CMD_PER_LUN
++#define CMD_PER_LUN 3
++#endif
++
++#ifndef CAN_QUEUE
++#define CAN_QUEUE 24
++#endif
+
+ int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
+ {
+@@ -53,8 +59,10 @@
+ {
+ if (shost->irq)
+ free_irq(shost->irq, NULL);
++#ifdef CONFIG_ISA
+ if (shost->dma_channel != 0xff)
+ free_dma(shost->dma_channel);
++#endif
+ if (shost->io_port && shost->n_io_port)
+ release_region(shost->io_port, shost->n_io_port);
+ scsi_unregister(shost);
+@@ -66,8 +74,9 @@
+ .detect = mvme16x_scsi_detect,
+ .release = mvme16x_scsi_release,
+ .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
++ .eh_abort_handler = NCR53c7xx_abort,
++ .eh_bus_reset_handler = NCR53c7xx_reset,
++ .slave_configure = NCR53c7xx_slave_configure,
+ .can_queue = 24,
+ .this_id = 7,
+ .sg_tablesize = 63,
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/mvme16x.h linux-m68k/drivers/scsi/mvme16x.h
+--- linux-i386/drivers/scsi/mvme16x.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/mvme16x.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,24 +0,0 @@
+-#ifndef MVME16x_SCSI_H
+-#define MVME16x_SCSI_H
+-
+-#include <linux/types.h>
+-
+-int mvme16x_scsi_detect(struct scsi_host_template *);
+-const char *NCR53c7x0_info(void);
+-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int NCR53c7xx_abort(Scsi_Cmnd *);
+-int NCR53c7x0_release (struct Scsi_Host *);
+-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+-
+-#ifndef CMD_PER_LUN
+-#define CMD_PER_LUN 3
+-#endif
+-
+-#ifndef CAN_QUEUE
+-#define CAN_QUEUE 24
+-#endif
+-
+-#include <scsi/scsicam.h>
+-
+-#endif /* MVME16x_SCSI_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/sun3_NCR5380.c linux-m68k/drivers/scsi/sun3_NCR5380.c
+--- linux-i386/drivers/scsi/sun3_NCR5380.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/sun3_NCR5380.c 2006-09-24 16:33:37.000000000 +0200
+@@ -1268,7 +1268,7 @@
+ NCR_PRINT(NDEBUG_INTR);
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+ done = 0;
+- ENABLE_IRQ();
++// ENABLE_IRQ();
+ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+ NCR5380_reselect(instance);
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+@@ -1301,7 +1301,7 @@
+ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+ NCR5380_dma_complete( instance );
+ done = 0;
+- ENABLE_IRQ();
++// ENABLE_IRQ();
+ } else
+ #endif /* REAL_DMA */
+ {
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/sun3_scsi.c linux-m68k/drivers/scsi/sun3_scsi.c
+--- linux-i386/drivers/scsi/sun3_scsi.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/sun3_scsi.c 2006-05-11 13:16:27.000000000 +0200
+@@ -75,9 +75,9 @@
+ #define REAL_DMA
+
+ #include "scsi.h"
++#include "initio.h"
+ #include <scsi/scsi_host.h>
+ #include "sun3_scsi.h"
+-#include "NCR5380.h"
+
+ static void NCR5380_print(struct Scsi_Host *instance);
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/sun3_scsi.h linux-m68k/drivers/scsi/sun3_scsi.h
+--- linux-i386/drivers/scsi/sun3_scsi.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/sun3_scsi.h 2006-05-11 13:16:27.000000000 +0200
+@@ -220,7 +220,7 @@
+ *
+ */
+
+-
++#include "NCR5380.h"
+
+ #if NDEBUG & NDEBUG_ARBITRATION
+ #define ARB_PRINTK(format, args...) \
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/drivers/scsi/sun3_scsi_vme.c linux-m68k/drivers/scsi/sun3_scsi_vme.c
+--- linux-i386/drivers/scsi/sun3_scsi_vme.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/drivers/scsi/sun3_scsi_vme.c 2006-05-11 13:16:27.000000000 +0200
+@@ -41,9 +41,9 @@
+ #define REAL_DMA
+
+ #include "scsi.h"
++#include "initio.h"
+ #include <scsi/scsi_host.h>
+ #include "sun3_scsi.h"
+-#include "NCR5380.h"
+
+ extern int sun3_map_test(unsigned long, char *);
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/fs/fat/inode.c linux-m68k/fs/fat/inode.c
+--- linux-i386/fs/fat/inode.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/fs/fat/inode.c 2006-09-24 16:34:00.000000000 +0200
+@@ -11,12 +11,14 @@
+ */
+
+ #include <linux/module.h>
++#include <linux/config.h>
+ #include <linux/init.h>
+ #include <linux/time.h>
+ #include <linux/slab.h>
+ #include <linux/smp_lock.h>
+ #include <linux/seq_file.h>
+ #include <linux/msdos_fs.h>
++#include <linux/major.h>
+ #include <linux/pagemap.h>
+ #include <linux/mpage.h>
+ #include <linux/buffer_head.h>
+@@ -857,7 +859,7 @@
+ Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
+ Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase,
+ Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
+- Opt_dots, Opt_nodots,
++ Opt_dots, Opt_nodots, Opt_atari_no, Opt_atari_yes,
+ Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
+ Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
+ Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
+@@ -882,6 +884,9 @@
+ {Opt_showexec, "showexec"},
+ {Opt_debug, "debug"},
+ {Opt_immutable, "sys_immutable"},
++ {Opt_atari_yes, "atari=yes"},
++ {Opt_atari_yes, "atari"},
++ {Opt_atari_no, "atari=no"},
+ {Opt_obsolate, "conv=binary"},
+ {Opt_obsolate, "conv=text"},
+ {Opt_obsolate, "conv=auto"},
+@@ -956,6 +961,13 @@
+ opts->utf8 = opts->unicode_xlate = 0;
+ opts->numtail = 1;
+ opts->nocase = 0;
++ opts->atari = 0;
++
++#ifdef CONFIG_ATARI
++ if(MACH_IS_ATARI)
++ /* make Atari GEMDOS format the default if machine is an Atari */
++ opts->atari = 1;
++#endif
+ *debug = 0;
+
+ if (!options)
+@@ -1004,6 +1016,12 @@
+ case Opt_immutable:
+ opts->sys_immutable = 1;
+ break;
++ case Opt_atari_yes:
++ opts->atari = 1;
++ break;
++ case Opt_atari_no:
++ opts->atari = 0;
++ break;
+ case Opt_uid:
+ if (match_int(&args[0], &option))
+ return 0;
+@@ -1339,8 +1357,31 @@
+
+ total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
+
+- if (sbi->fat_bits != 32)
+- sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
++ if (!sbi->options.atari) {
++ if (sbi->fat_bits != 32)
++ sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
++ } else {
++ int sectors;
++ /* Atari GEMDOS partitions always have 16-bit fat */
++ if (sbi->fat_bits != 32)
++ sbi->fat_bits = 16;
++ /* If more clusters than fat entries in 16-bit fat, we assume
++ * it's a real MSDOS partition with 12-bit fat.
++ */
++ if (sbi->fat_bits != 32 && total_clusters+2 > sbi->
++ fat_length*SECTOR_SIZE*8/sbi->fat_bits)
++ sbi->fat_bits = 12;
++ /* if it's a floppy disk --> 12bit fat */
++ if (sbi->fat_bits != 32 && MAJOR(sb->s_dev) == FLOPPY_MAJOR)
++ sbi->fat_bits = 12;
++ /* if it's a ramdisk or loopback device and has one of the usual
++ * floppy sizes -> 12bit FAT */
++ sectors = total_sectors + sbi->data_start;
++ if (sbi->fat_bits != 32 && (MAJOR(sb->s_dev) == RAMDISK_MAJOR ||
++ MAJOR(sb->s_dev) == LOOP_MAJOR) &&
++ (sectors == 720 || sectors == 1440 || sectors == 2880))
++ sbi->fat_bits = 12;
++ }
+
+ /* check that FAT table does not overflow */
+ fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/io.h linux-m68k/include/asm-m68k/io.h
+--- linux-i386/include/asm-m68k/io.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/io.h 2006-09-24 16:34:33.000000000 +0200
+@@ -324,8 +324,6 @@
+ #define writel(val,addr) out_le32((addr),(val))
+ #endif
+
+-#define mmiowb()
+-
+ static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size)
+ {
+ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/irq.h linux-m68k/include/asm-m68k/irq.h
+--- linux-i386/include/asm-m68k/irq.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/irq.h 2006-09-24 16:34:33.000000000 +0200
+@@ -2,7 +2,6 @@
+ #define _M68K_IRQ_H_
+
+ #include <linux/linkage.h>
+-#include <linux/hardirq.h>
+ #include <linux/spinlock_types.h>
+
+ /*
+@@ -61,6 +60,7 @@
+ extern unsigned int irq_canonicalize(unsigned int irq);
+ extern void enable_irq(unsigned int);
+ extern void disable_irq(unsigned int);
++
+ #define disable_irq_nosync disable_irq
+
+ struct pt_regs;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/mmzone.h linux-m68k/include/asm-m68k/mmzone.h
+--- linux-i386/include/asm-m68k/mmzone.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-m68k/include/asm-m68k/mmzone.h 2006-09-03 17:54:54.000000000 +0200
+@@ -0,0 +1,9 @@
++#ifndef _ASM_M68K_MMZONE_H_
++#define _ASM_M68K_MMZONE_H_
++
++extern pg_data_t pg_data_map[];
++
++#define NODE_DATA(nid) (&pg_data_map[nid])
++#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map)
++
++#endif /* _ASM_M68K_MMZONE_H_ */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/module.h linux-m68k/include/asm-m68k/module.h
+--- linux-i386/include/asm-m68k/module.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/module.h 2006-09-05 16:34:01.000000000 +0200
+@@ -1,7 +1,39 @@
+ #ifndef _ASM_M68K_MODULE_H
+ #define _ASM_M68K_MODULE_H
+-struct mod_arch_specific { };
++
++struct mod_arch_specific {
++ struct m68k_fixup_info *fixup_start, *fixup_end;
++};
++
++#define MODULE_ARCH_INIT { \
++ .fixup_start = __start_fixup, \
++ .fixup_end = __stop_fixup, \
++}
++
+ #define Elf_Shdr Elf32_Shdr
+ #define Elf_Sym Elf32_Sym
+ #define Elf_Ehdr Elf32_Ehdr
++
++
++enum m68k_fixup_type {
++ m68k_fixup_memoffset,
++ m68k_fixup_vnode_shift,
++};
++
++struct m68k_fixup_info {
++ enum m68k_fixup_type type;
++ void *addr;
++};
++
++#define m68k_fixup(type, addr) \
++ " .section \".m68k_fixup\",\"aw\"\n" \
++ " .long " #type "," #addr "\n" \
++ " .previous\n"
++
++extern struct m68k_fixup_info __start_fixup[], __stop_fixup[];
++
++struct module;
++extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
++ struct m68k_fixup_info *end);
++
+ #endif /* _ASM_M68K_MODULE_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/motorola_pgtable.h linux-m68k/include/asm-m68k/motorola_pgtable.h
+--- linux-i386/include/asm-m68k/motorola_pgtable.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/motorola_pgtable.h 2006-09-24 16:34:33.000000000 +0200
+@@ -130,7 +130,7 @@
+ #define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+ #define pte_clear(mm,addr,ptep) ({ pte_val(*(ptep)) = 0; })
+
+-#define pte_page(pte) (mem_map + ((unsigned long)(__va(pte_val(pte)) - PAGE_OFFSET) >> PAGE_SHIFT))
++#define pte_page(pte) virt_to_page(__va(pte_val(pte)))
+ #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
+ #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+@@ -143,7 +143,7 @@
+ while (--__i >= 0) \
+ *__ptr++ = 0; \
+ })
+-#define pmd_page(pmd) (mem_map + ((unsigned long)(__va(pmd_val(pmd)) - PAGE_OFFSET) >> PAGE_SHIFT))
++#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
+
+
+ #define pgd_none(pgd) (!pgd_val(pgd))
+@@ -222,10 +222,10 @@
+ return (pte_t *)__pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+ }
+
+-#define pte_offset_map(pmdp,address) ((pte_t *)kmap(pmd_page(*pmdp)) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
++#define pte_offset_map(pmdp,address) ((pte_t *)__pmd_page(*pmdp) + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+ #define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address)
+-#define pte_unmap(pte) kunmap(pte)
+-#define pte_unmap_nested(pte) kunmap(pte)
++#define pte_unmap(pte) ((void)0)
++#define pte_unmap_nested(pte) ((void)0)
+
+ /*
+ * Allocate and free page tables. The xxx_kernel() versions are
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/page.h linux-m68k/include/asm-m68k/page.h
+--- linux-i386/include/asm-m68k/page.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/page.h 2006-09-24 16:34:33.000000000 +0200
+@@ -1,6 +1,7 @@
+ #ifndef _M68K_PAGE_H
+ #define _M68K_PAGE_H
+
++#include <linux/compiler.h>
+
+ #ifdef __KERNEL__
+
+@@ -27,6 +28,8 @@
+
+ #ifndef __ASSEMBLY__
+
++#include <asm/module.h>
++
+ #define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
+ #define free_user_page(page, addr) free_page(addr)
+
+@@ -114,18 +117,33 @@
+
+ #ifndef __ASSEMBLY__
+
++extern unsigned long m68k_memoffset;
++
+ #ifndef CONFIG_SUN3
+
+ #define WANT_PAGE_VIRTUAL
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+-extern unsigned long m68k_memoffset;
+
+-#define __pa(vaddr) ((unsigned long)(vaddr)+m68k_memoffset)
+-#define __va(paddr) ((void *)((unsigned long)(paddr)-m68k_memoffset))
+-#else
+-#define __pa(vaddr) virt_to_phys((void *)(vaddr))
+-#define __va(paddr) phys_to_virt((unsigned long)(paddr))
+-#endif
++static inline unsigned long ___pa(void *vaddr)
++{
++ unsigned long paddr;
++ asm (
++ "1: addl #0,%0\n"
++ m68k_fixup(%c2, 1b+2)
++ : "=r" (paddr)
++ : "0" (vaddr), "i" (m68k_fixup_memoffset));
++ return paddr;
++}
++#define __pa(vaddr) ___pa((void *)(vaddr))
++static inline void *__va(unsigned long paddr)
++{
++ void *vaddr;
++ asm (
++ "1: subl #0,%0\n"
++ m68k_fixup(%c2, 1b+2)
++ : "=r" (vaddr)
++ : "0" (paddr), "i" (m68k_fixup_memoffset));
++ return vaddr;
++}
+
+ #else /* !CONFIG_SUN3 */
+ /* This #define is a horrible hack to suppress lots of warnings. --m */
+@@ -161,11 +179,47 @@
+ #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
+ #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
+
+-#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr)-PAGE_OFFSET) >> PAGE_SHIFT))
+-#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
++extern int m68k_virt_to_node_shift;
++
++#ifdef CONFIG_SINGLE_MEMORY_CHUNK
++#define __virt_to_node(addr) (&pg_data_map[0])
++#else
++extern struct pglist_data *pg_data_table[];
++
++static inline __attribute_const__ int __virt_to_node_shift(void)
++{
++ int shift;
++
++ asm (
++ "1: moveq #0,%0\n"
++ m68k_fixup(%c1, 1b)
++ : "=d" (shift)
++ : "i" (m68k_fixup_vnode_shift));
++ return shift;
++}
++
++#define __virt_to_node(addr) (pg_data_table[(unsigned long)(addr) >> __virt_to_node_shift()])
++#endif
+
+-#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn))
+-#define page_to_pfn(page) virt_to_pfn(page_to_virt(page))
++#define virt_to_page(addr) ({ \
++ pfn_to_page(virt_to_pfn(addr)); \
++})
++#define page_to_virt(page) ({ \
++ pfn_to_virt(page_to_pfn(page)); \
++})
++
++#define pfn_to_page(pfn) ({ \
++ unsigned long __pfn = (pfn); \
++ struct pglist_data *pgdat; \
++ pgdat = __virt_to_node((unsigned long)pfn_to_virt(__pfn)); \
++ pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn); \
++})
++#define page_to_pfn(_page) ({ \
++ struct page *__p = (_page); \
++ struct pglist_data *pgdat; \
++ pgdat = &pg_data_map[page_to_nid(__p)]; \
++ ((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn; \
++})
+
+ #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
+ #define pfn_valid(pfn) virt_addr_valid(pfn_to_virt(pfn))
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/pgalloc.h linux-m68k/include/asm-m68k/pgalloc.h
+--- linux-i386/include/asm-m68k/pgalloc.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/pgalloc.h 2006-09-24 16:34:33.000000000 +0200
+@@ -8,11 +8,12 @@
+ #include <asm/virtconvert.h>
+
+
+-
+ #ifdef CONFIG_SUN3
+ #include <asm/sun3_pgalloc.h>
+ #else
+ #include <asm/motorola_pgalloc.h>
+ #endif
+
++extern void m68k_setup_node(int node);
++
+ #endif /* M68K_PGALLOC_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/pgtable.h linux-m68k/include/asm-m68k/pgtable.h
+--- linux-i386/include/asm-m68k/pgtable.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/pgtable.h 2006-09-24 16:34:33.000000000 +0200
+@@ -107,22 +107,7 @@
+ /* 64-bit machines, beware! SRB. */
+ #define SIZEOF_PTR_LOG2 2
+
+-/*
+- * Check if the addr/len goes up to the end of a physical
+- * memory chunk. Used for DMA functions.
+- */
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+-/*
+- * It makes no sense to consider whether we cross a memory boundary if
+- * we support just one physical chunk of memory.
+- */
+-static inline int mm_end_of_chunk(unsigned long addr, int len)
+-{
+- return 0;
+-}
+-#else
+-int mm_end_of_chunk (unsigned long addr, int len);
+-#endif
++#define mm_end_of_chunk(addr, len) 0
+
+ extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode);
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/serial.h linux-m68k/include/asm-m68k/serial.h
+--- linux-i386/include/asm-m68k/serial.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/serial.h 2006-09-24 16:34:33.000000000 +0200
+@@ -25,9 +25,11 @@
+ #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+ #endif
+
++#ifdef CONFIG_ISA
+ #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 */
++#endif
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/string.h linux-m68k/include/asm-m68k/string.h
+--- linux-i386/include/asm-m68k/string.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/string.h 2006-09-05 16:34:01.000000000 +0200
+@@ -1,138 +1,114 @@
+ #ifndef _M68K_STRING_H_
+ #define _M68K_STRING_H_
+
+-#include <asm/setup.h>
+-#include <asm/page.h>
++#include <linux/types.h>
++#include <linux/compiler.h>
+
+-#define __HAVE_ARCH_STRCPY
+-static inline char * strcpy(char * dest,const char *src)
++static inline size_t __kernel_strlen(const char *s)
+ {
+- char *xdest = dest;
++ const char *sc;
+
+- __asm__ __volatile__
+- ("1:\tmoveb %1 at +,%0 at +\n\t"
+- "jne 1b"
+- : "=a" (dest), "=a" (src)
+- : "0" (dest), "1" (src) : "memory");
+- return xdest;
++ for (sc = s; *sc++; )
++ ;
++ return sc - s - 1;
+ }
+
+-#define __HAVE_ARCH_STRNCPY
+-static inline char * strncpy(char *dest, const char *src, size_t n)
++static inline char *__kernel_strcpy(char *dest, const char *src)
+ {
+- char *xdest = dest;
++ char *xdest = dest;
+
+- if (n == 0)
+- return xdest;
+-
+- __asm__ __volatile__
+- ("1:\tmoveb %1 at +,%0 at +\n\t"
+- "jeq 2f\n\t"
+- "subql #1,%2\n\t"
+- "jne 1b\n\t"
+- "2:"
+- : "=a" (dest), "=a" (src), "=d" (n)
+- : "0" (dest), "1" (src), "2" (n)
+- : "memory");
+- return xdest;
++ asm volatile ("\n"
++ "1: move.b (%1)+,(%0)+\n"
++ " jne 1b"
++ : "+a" (dest), "+a" (src)
++ : : "memory");
++ return xdest;
+ }
+
+-#define __HAVE_ARCH_STRCAT
+-static inline char * strcat(char * dest, const char * src)
+-{
+- char *tmp = dest;
+-
+- while (*dest)
+- dest++;
+- while ((*dest++ = *src++))
+- ;
++#ifndef __IN_STRING_C
+
+- return tmp;
++#define __HAVE_ARCH_STRLEN
++#define strlen(s) (__builtin_constant_p(s) ? \
++ __builtin_strlen(s) : \
++ __kernel_strlen(s))
++
++#define __HAVE_ARCH_STRNLEN
++static inline size_t strnlen(const char *s, size_t count)
++{
++ const char *sc = s;
++
++ asm volatile ("\n"
++ "1: subq.l #1,%1\n"
++ " jcs 2f\n"
++ " tst.b (%0)+\n"
++ " jne 1b\n"
++ " subq.l #1,%0\n"
++ "2:"
++ : "+a" (sc), "+d" (count));
++ return sc - s;
+ }
+
+-#define __HAVE_ARCH_STRNCAT
+-static inline char * strncat(char *dest, const char *src, size_t count)
+-{
+- char *tmp = dest;
+-
+- if (count) {
+- while (*dest)
+- dest++;
+- while ((*dest++ = *src++)) {
+- if (--count == 0) {
+- *dest++='\0';
+- break;
+- }
+- }
+- }
+-
+- return tmp;
+-}
++#define __HAVE_ARCH_STRCPY
++#if __GNUC__ >= 4
++#define strcpy(d, s) (__builtin_constant_p(s) && \
++ __builtin_strlen(s) <= 32 ? \
++ __builtin_strcpy(d, s) : \
++ __kernel_strcpy(d, s))
++#else
++#define strcpy(d, s) __kernel_strcpy(d, s)
++#endif
+
+-#define __HAVE_ARCH_STRCHR
+-static inline char * strchr(const char * s, int c)
++#define __HAVE_ARCH_STRNCPY
++static inline char *strncpy(char *dest, const char *src, size_t n)
+ {
+- const char ch = c;
++ char *xdest = dest;
+
+- for(; *s != ch; ++s)
+- if (*s == '\0')
+- return( NULL );
+- return( (char *) s);
++ asm volatile ("\n"
++ " jra 2f\n"
++ "1: move.b (%1),(%0)+\n"
++ " jeq 2f\n"
++ " addq.l #1,%1\n"
++ "2: subq.l #1,%2\n"
++ " jcc 1b\n"
++ : "+a" (dest), "+a" (src), "+d" (n)
++ : : "memory");
++ return xdest;
+ }
+
+-/* strstr !! */
++#define __HAVE_ARCH_STRCAT
++#define strcat(d, s) ({ \
++ char *__d = (d); \
++ strcpy(__d + strlen(__d), (s)); \
++})
+
+-#define __HAVE_ARCH_STRLEN
+-static inline size_t strlen(const char * s)
++#define __HAVE_ARCH_STRCHR
++static inline char *strchr(const char *s, int c)
+ {
+- const char *sc;
+- for (sc = s; *sc != '\0'; ++sc) ;
+- return(sc - s);
+-}
++ char sc, ch = c;
+
+-/* strnlen !! */
++ for (; (sc = *s++) != ch; ) {
++ if (!sc)
++ return NULL;
++ }
++ return (char *)s - 1;
++}
+
+ #define __HAVE_ARCH_STRCMP
+-static inline int strcmp(const char * cs,const char * ct)
++static inline int strcmp(const char *cs, const char *ct)
+ {
+- char __res;
++ char res;
+
+- __asm__
+- ("1:\tmoveb %0 at +,%2\n\t" /* get *cs */
+- "cmpb %1 at +,%2\n\t" /* compare a byte */
+- "jne 2f\n\t" /* not equal, break out */
+- "tstb %2\n\t" /* at end of cs? */
+- "jne 1b\n\t" /* no, keep going */
+- "jra 3f\n\t" /* strings are equal */
+- "2:\tsubb %1 at -,%2\n\t" /* *cs - *ct */
+- "3:"
+- : "=a" (cs), "=a" (ct), "=d" (__res)
+- : "0" (cs), "1" (ct));
+- return __res;
+-}
+-
+-#define __HAVE_ARCH_STRNCMP
+-static inline int strncmp(const char * cs,const char * ct,size_t count)
+-{
+- char __res;
+-
+- if (!count)
+- return 0;
+- __asm__
+- ("1:\tmovb %0 at +,%3\n\t" /* get *cs */
+- "cmpb %1 at +,%3\n\t" /* compare a byte */
+- "jne 3f\n\t" /* not equal, break out */
+- "tstb %3\n\t" /* at end of cs? */
+- "jeq 4f\n\t" /* yes, all done */
+- "subql #1,%2\n\t" /* no, adjust count */
+- "jne 1b\n\t" /* more to do, keep going */
+- "2:\tmoveq #0,%3\n\t" /* strings are equal */
+- "jra 4f\n\t"
+- "3:\tsubb %1 at -,%3\n\t" /* *cs - *ct */
+- "4:"
+- : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res)
+- : "0" (cs), "1" (ct), "2" (count));
+- return __res;
++ asm ("\n"
++ "1: move.b (%0)+,%2\n" /* get *cs */
++ " cmp.b (%1)+,%2\n" /* compare a byte */
++ " jne 2f\n" /* not equal, break out */
++ " tst.b %2\n" /* at end of cs? */
++ " jne 1b\n" /* no, keep going */
++ " jra 3f\n" /* strings are equal */
++ "2: sub.b -(%1),%2\n" /* *cs - *ct */
++ "3:"
++ : "+a" (cs), "+a" (ct), "=d" (res));
++ return res;
+ }
+
+ #define __HAVE_ARCH_MEMSET
+@@ -150,4 +126,6 @@
+ extern int memcmp(const void *, const void *, __kernel_size_t);
+ #define memcmp(d, s, n) __builtin_memcmp(d, s, n)
+
++#endif
++
+ #endif /* _M68K_STRING_H_ */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/sun3-head.h linux-m68k/include/asm-m68k/sun3-head.h
+--- linux-i386/include/asm-m68k/sun3-head.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/sun3-head.h 2006-05-11 13:14:11.000000000 +0200
+@@ -4,7 +4,6 @@
+
+ #define KERNBASE 0xE000000 /* First address the kernel will eventually be */
+ #define LOAD_ADDR 0x4000 /* prom jumps to us here unless this is elf /boot */
+-#define BI_START (KERNBASE + 0x3000) /* beginning of the bootinfo records */
+ #define FC_CONTROL 3
+ #define FC_SUPERD 5
+ #define FC_CPU 7
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/sun3_pgtable.h linux-m68k/include/asm-m68k/sun3_pgtable.h
+--- linux-i386/include/asm-m68k/sun3_pgtable.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/sun3_pgtable.h 2006-09-05 16:34:01.000000000 +0200
+@@ -132,8 +132,8 @@
+ #define pfn_pte(pfn, pgprot) \
+ ({ pte_t __pte; pte_val(__pte) = pfn | pgprot_val(pgprot); __pte; })
+
+-#define pte_page(pte) (mem_map+((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT))
+-#define pmd_page(pmd) (mem_map+((__pmd_page(pmd) - PAGE_OFFSET) >> PAGE_SHIFT))
++#define pte_page(pte) virt_to_page(__pte_page(pte))
++#define pmd_page(pmd) virt_to_page(__pmd_page(pmd))
+
+
+ static inline int pmd_none2 (pmd_t *pmd) { return !pmd_val (*pmd); }
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/sun3ints.h linux-m68k/include/asm-m68k/sun3ints.h
+--- linux-i386/include/asm-m68k/sun3ints.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/sun3ints.h 2006-05-11 13:14:11.000000000 +0200
+@@ -16,6 +16,7 @@
+ #include <asm/intersil.h>
+ #include <asm/oplib.h>
+ #include <asm/traps.h>
++#include <asm/irq.h>
+
+ #define SUN3_INT_VECS 192
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/system.h linux-m68k/include/asm-m68k/system.h
+--- linux-i386/include/asm-m68k/system.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/system.h 2006-09-24 16:34:34.000000000 +0200
+@@ -78,13 +78,13 @@
+ #define mb() barrier()
+ #define rmb() barrier()
+ #define wmb() barrier()
+-#define read_barrier_depends() do { } while(0)
+-#define set_mb(var, value) do { xchg(&var, value); } while (0)
++#define read_barrier_depends() ((void)0)
++#define set_mb(var, value) ({ (var) = (value); wmb(); })
+
+ #define smp_mb() barrier()
+ #define smp_rmb() barrier()
+ #define smp_wmb() barrier()
+-#define smp_read_barrier_depends() do { } while(0)
++#define smp_read_barrier_depends() ((void)0)
+
+
+ #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/thread_info.h linux-m68k/include/asm-m68k/thread_info.h
+--- linux-i386/include/asm-m68k/thread_info.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/thread_info.h 2006-04-11 01:58:28.000000000 +0200
+@@ -26,24 +26,24 @@
+
+ /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */
+ #if PAGE_SHIFT == 13 /* 8k machines */
+-#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,0))
+-#define free_thread_info(ti) free_pages((unsigned long)(ti),0)
++#define alloc_thread_stack(tsk) ((void *)__get_free_pages(GFP_KERNEL,0))
++#define free_thread_stack(ti) free_pages((unsigned long)(ti),0)
+ #else /* otherwise assume 4k pages */
+-#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 alloc_thread_stack(tsk) ((void *)__get_free_pages(GFP_KERNEL,1))
++#define free_thread_stack(ti) free_pages((unsigned long)(ti),1)
+ #endif /* PAGE_SHIFT == 13 */
+
+ #define init_thread_info (init_task.thread.info)
+ #define init_stack (init_thread_union.stack)
+
+ #define task_thread_info(tsk) (&(tsk)->thread.info)
+-#define task_stack_page(tsk) ((void *)(tsk)->thread_info)
++#define task_stack_page(tsk) ((void *)(tsk)->stack)
+ #define current_thread_info() task_thread_info(current)
+
+ #define __HAVE_THREAD_FUNCTIONS
+
+ #define setup_thread_stack(p, org) ({ \
+- *(struct task_struct **)(p)->thread_info = (p); \
++ *(struct task_struct **)(p)->stack = (p); \
+ task_thread_info(p)->task = (p); \
+ })
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/unistd.h linux-m68k/include/asm-m68k/unistd.h
+--- linux-i386/include/asm-m68k/unistd.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/unistd.h 2006-09-24 16:34:34.000000000 +0200
+@@ -284,10 +284,15 @@
+ #define __NR_add_key 279
+ #define __NR_request_key 280
+ #define __NR_keyctl 281
++#define __NR_ioprio_set 282
++#define __NR_ioprio_get 283
++#define __NR_inotify_init 284
++#define __NR_inotify_add_watch 285
++#define __NR_inotify_rm_watch 286
+
+ #ifdef __KERNEL__
+
+-#define NR_syscalls 282
++#define NR_syscalls 287
+
+ /* user-visible error numbers are in the range -1 - -124: see
+ <asm-m68k/errno.h> */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/asm-m68k/virtconvert.h linux-m68k/include/asm-m68k/virtconvert.h
+--- linux-i386/include/asm-m68k/virtconvert.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/asm-m68k/virtconvert.h 2006-09-24 16:34:34.000000000 +0200
+@@ -8,56 +8,34 @@
+ #ifdef __KERNEL__
+
+ #include <linux/compiler.h>
++#include <linux/mmzone.h>
+ #include <asm/setup.h>
+ #include <asm/page.h>
+
+-#ifdef CONFIG_AMIGA
+-#include <asm/amigahw.h>
+-#endif
+-
+ /*
+ * Change virtual addresses to physical addresses and vv.
+ */
+-#ifndef CONFIG_SUN3
+-extern unsigned long mm_vtop(unsigned long addr) __attribute_const__;
+-extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+-#else
+-static inline unsigned long mm_vtop(unsigned long vaddr)
+-{
+- return __pa(vaddr);
+-}
+-
+-static inline unsigned long mm_ptov(unsigned long paddr)
+-{
+- return (unsigned long)__va(paddr);
+-}
+-#endif
+-
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+-static inline unsigned long virt_to_phys(void *vaddr)
+-{
+- return (unsigned long)vaddr - PAGE_OFFSET + m68k_memory[0].addr;
+-}
+-
+-static inline void * phys_to_virt(unsigned long paddr)
+-{
+- return (void *)(paddr - m68k_memory[0].addr + PAGE_OFFSET);
+-}
+-#else
+ static inline unsigned long virt_to_phys(void *address)
+ {
+- return mm_vtop((unsigned long)address);
++ return __pa(address);
+ }
+
+ static inline void *phys_to_virt(unsigned long address)
+ {
+- return (void *) mm_ptov(address);
++ return __va(address);
+ }
+-#endif
+
+ /* Permanent address of a page. */
+-#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+-#define page_to_phys(page) virt_to_phys((void *)__page_address(page))
++#ifdef CONFIG_SINGLE_MEMORY_CHUNK
++#define page_to_phys(page) \
++ __pa(PAGE_OFFSET + (((page) - pg_data_map[0].node_mem_map) << PAGE_SHIFT))
++#else
++#define page_to_phys(page) ({ \
++ struct pglist_data *pgdat; \
++ pgdat = pg_data_table[page_to_nid(page)]; \
++ page_to_pfn(page) << PAGE_SHIFT; \
++})
++#endif
+
+ /*
+ * IO bus memory addresses are 1:1 with the physical address,
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/adb.h linux-m68k/include/linux/adb.h
+--- linux-i386/include/linux/adb.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/adb.h 2006-06-18 19:10:20.000000000 +0200
+@@ -76,6 +76,7 @@
+ #define ADBREQ_REPLY 1 /* expect reply */
+ #define ADBREQ_SYNC 2 /* poll until done */
+ #define ADBREQ_NOSEND 4 /* build the request, but don't send it */
++#define ADBREQ_RAW 8 /* send raw packet (don't prepend ADB_PACKET) */
+
+ /* Messages sent thru the client_list notifier. You should NOT stop
+ the operation, at least not with this version */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/bootmem.h linux-m68k/include/linux/bootmem.h
+--- linux-i386/include/linux/bootmem.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/bootmem.h 2006-09-24 16:34:56.000000000 +0200
+@@ -61,11 +61,11 @@
+ #define alloc_bootmem(x) \
+ __alloc_bootmem((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+ #define alloc_bootmem_low(x) \
+- __alloc_bootmem_low((x), SMP_CACHE_BYTES, 0)
++ __alloc_bootmem_low((x), SMP_CACHE_BYTES, __pa(PAGE_OFFSET))
+ #define alloc_bootmem_pages(x) \
+ __alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+ #define alloc_bootmem_low_pages(x) \
+- __alloc_bootmem_low((x), PAGE_SIZE, 0)
++ __alloc_bootmem_low((x), PAGE_SIZE, __pa(PAGE_OFFSET))
+ #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
+ extern unsigned long __init free_all_bootmem (void);
+ extern void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/file.h linux-m68k/include/linux/file.h
+--- linux-i386/include/linux/file.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/file.h 2006-06-18 19:10:21.000000000 +0200
+@@ -5,7 +5,6 @@
+ #ifndef __LINUX_FILE_H
+ #define __LINUX_FILE_H
+
+-#include <asm/atomic.h>
+ #include <linux/posix_types.h>
+ #include <linux/compiler.h>
+ #include <linux/spinlock.h>
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/hardirq.h linux-m68k/include/linux/hardirq.h
+--- linux-i386/include/linux/hardirq.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/hardirq.h 2006-09-27 16:34:52.000000000 +0200
+@@ -3,9 +3,7 @@
+
+ #include <linux/preempt.h>
+ #include <linux/smp_lock.h>
+-#include <linux/lockdep.h>
+ #include <asm/hardirq.h>
+-#include <asm/system.h>
+
+ /*
+ * We put the hardirq and softirq counter into the preemption
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/ide.h linux-m68k/include/linux/ide.h
+--- linux-i386/include/linux/ide.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/ide.h 2006-09-24 16:34:57.000000000 +0200
+@@ -509,7 +509,7 @@
+ * sense_key : Sense key of the last failed packet command
+ */
+ typedef union {
+- unsigned all :8;
++ u8 all;
+ struct {
+ #if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned ili :1;
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/init_task.h linux-m68k/include/linux/init_task.h
+--- linux-i386/include/linux/init_task.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/init_task.h 2006-09-24 16:34:57.000000000 +0200
+@@ -83,7 +83,7 @@
+ #define INIT_TASK(tsk) \
+ { \
+ .state = 0, \
+- .thread_info = &init_thread_info, \
++ .stack = &init_stack, \
+ .usage = ATOMIC_INIT(2), \
+ .flags = 0, \
+ .lock_depth = -1, \
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/module.h linux-m68k/include/linux/module.h
+--- linux-i386/include/linux/module.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/module.h 2006-09-24 16:34:58.000000000 +0200
+@@ -346,6 +346,9 @@
+ keeping pointers to this stuff */
+ char *args;
+ };
++#ifndef MODULE_ARCH_INIT
++#define MODULE_ARCH_INIT {}
++#endif
+
+ /* FIXME: It'd be nice to isolate modules during init, too, so they
+ aren't used before they (may) fail. But presently too much code
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/sched.h linux-m68k/include/linux/sched.h
+--- linux-i386/include/linux/sched.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/sched.h 2006-09-24 16:35:00.000000000 +0200
+@@ -766,7 +766,8 @@
+
+ struct task_struct {
+ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
+- struct thread_info *thread_info;
++ //struct thread_info *thread_info;
++ void *stack;
+ atomic_t usage;
+ unsigned long flags; /* per process flags, defined below */
+ unsigned long ptrace;
+@@ -1395,6 +1396,7 @@
+ /* set thread flags in other task's structures
+ * - see asm/thread_info.h for TIF_xxxx flags available
+ */
++
+ static inline void set_tsk_thread_flag(struct task_struct *tsk, int flag)
+ {
+ set_ti_thread_flag(task_thread_info(tsk), flag);
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/include/linux/thread_info.h linux-m68k/include/linux/thread_info.h
+--- linux-i386/include/linux/thread_info.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/include/linux/thread_info.h 2005-05-30 02:26:01.000000000 +0200
+@@ -66,6 +66,6 @@
+ #define set_need_resched() set_thread_flag(TIF_NEED_RESCHED)
+ #define clear_need_resched() clear_thread_flag(TIF_NEED_RESCHED)
+
+-#endif
++#endif /* __KERNEL__ */
+
+ #endif /* _LINUX_THREAD_INFO_H */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/kernel/fork.c linux-m68k/kernel/fork.c
+--- linux-i386/kernel/fork.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/kernel/fork.c 2006-09-24 16:35:10.000000000 +0200
+@@ -102,7 +102,7 @@
+
+ void free_task(struct task_struct *tsk)
+ {
+- free_thread_info(tsk->thread_info);
++ free_thread_stack(tsk->stack);
+ rt_mutex_debug_task_free(tsk);
+ free_task_struct(tsk);
+ }
+@@ -157,7 +157,7 @@
+ static struct task_struct *dup_task_struct(struct task_struct *orig)
+ {
+ struct task_struct *tsk;
+- struct thread_info *ti;
++ void *stack;
+
+ prepare_to_copy(orig);
+
+@@ -165,14 +165,14 @@
+ if (!tsk)
+ return NULL;
+
+- ti = alloc_thread_info(tsk);
+- if (!ti) {
++ stack = alloc_thread_stack(tsk);
++ if (!stack) {
+ free_task_struct(tsk);
+ return NULL;
+ }
+
+ *tsk = *orig;
+- tsk->thread_info = ti;
++ tsk->stack = stack;
+ setup_thread_stack(tsk, orig);
+
+ /* One for us, one for whoever does the "release_task()" (usually parent) */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/kernel/mutex.c linux-m68k/kernel/mutex.c
+--- linux-i386/kernel/mutex.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/kernel/mutex.c 2006-09-24 16:35:10.000000000 +0200
+@@ -133,7 +133,7 @@
+
+ debug_mutex_lock_common(lock, &waiter);
+ mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
+- debug_mutex_add_waiter(lock, &waiter, task->thread_info);
++ debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
+
+ /* add waiting tasks to the end of the waitqueue (FIFO): */
+ list_add_tail(&waiter.list, &lock->wait_list);
+@@ -159,7 +159,7 @@
+ */
+ if (unlikely(state == TASK_INTERRUPTIBLE &&
+ signal_pending(task))) {
+- mutex_remove_waiter(lock, &waiter, task->thread_info);
++ mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+ mutex_release(&lock->dep_map, 1, _RET_IP_);
+ spin_unlock_mutex(&lock->wait_lock, flags);
+
+@@ -175,8 +175,8 @@
+ }
+
+ /* got the lock - rejoice! */
+- mutex_remove_waiter(lock, &waiter, task->thread_info);
+- debug_mutex_set_owner(lock, task->thread_info);
++ mutex_remove_waiter(lock, &waiter, task_thread_info(task));
++ debug_mutex_set_owner(lock, task_thread_info(task));
+
+ /* set it to 0 if there are no waiters left: */
+ if (likely(list_empty(&lock->wait_list)))
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/lib/kref.c linux-m68k/lib/kref.c
+--- linux-i386/lib/kref.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/lib/kref.c 2006-06-18 19:10:31.000000000 +0200
+@@ -11,8 +11,8 @@
+ *
+ */
+
+-#include <linux/kref.h>
+ #include <linux/module.h>
++#include <linux/kref.h>
+
+ /**
+ * kref_init - initialize object.
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/mm/bootmem.c linux-m68k/mm/bootmem.c
+--- linux-i386/mm/bootmem.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/mm/bootmem.c 2006-09-24 16:35:13.000000000 +0200
+@@ -303,7 +303,6 @@
+
+ count = 0;
+ /* first extant page of the node */
+- pfn = bdata->node_boot_start >> PAGE_SHIFT;
+ idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
+ map = bdata->node_bootmem_map;
+ /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */
+@@ -316,26 +315,24 @@
+ if (gofast && v == ~0UL) {
+ int order;
+
+- page = pfn_to_page(pfn);
++ page = virt_to_page(phys_to_virt((i << PAGE_SHIFT) +
++ bdata->node_boot_start));
+ count += BITS_PER_LONG;
+ order = ffs(BITS_PER_LONG) - 1;
+ __free_pages_bootmem(page, order);
+ i += BITS_PER_LONG;
+- page += BITS_PER_LONG;
+ } else if (v) {
+ unsigned long m;
+-
+- page = pfn_to_page(pfn);
+- for (m = 1; m && i < idx; m<<=1, page++, i++) {
++ for (m = 1; m && i < idx; m<<=1, i++) {
+ if (v & m) {
++ page = virt_to_page(phys_to_virt((i << PAGE_SHIFT) +
++ bdata->node_boot_start));
+ count++;
+ __free_pages_bootmem(page, 0);
+ }
+ }
+- } else {
++ } else
+ i+=BITS_PER_LONG;
+- }
+- pfn += BITS_PER_LONG;
+ }
+ total += count;
+
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/mm/page_alloc.c linux-m68k/mm/page_alloc.c
+--- linux-i386/mm/page_alloc.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/mm/page_alloc.c 2006-09-24 16:35:13.000000000 +0200
+@@ -2063,7 +2063,7 @@
+ map = alloc_bootmem_node(pgdat, size);
+ pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
+ }
+-#ifdef CONFIG_FLATMEM
++#ifndef CONFIG_NEED_MULTIPLE_NODES
+ /*
+ * With no DISCONTIG, the global mem_map is just set as node 0's
+ */
+diff -urN --exclude-from=/usr/src/exclude-file linux-i386/scripts/mod/modpost.c linux-m68k/scripts/mod/modpost.c
+--- linux-i386/scripts/mod/modpost.c 2006-09-20 05:42:06.000000000 +0200
++++ linux-m68k/scripts/mod/modpost.c 2006-09-24 16:35:30.000000000 +0200
+@@ -1181,6 +1181,7 @@
+ buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ " .exit = cleanup_module,\n"
+ "#endif\n");
++ buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "};\n");
+ }
+
Added: people/maks-guest/linux-2.6/debian/patches/m68k-as.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/m68k-as.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,308 @@
+From: Al Viro <viro at zeniv.linux.org.uk>
+Date: 1134413482 -0500
+
+recent as(1) doesn't think that . terminates a macro name, so
+getuser.l is _not_ treated as invoking getuser with .l as the
+first argument.
+
+Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
+
+---
+
+ arch/m68k/math-emu/fp_cond.S | 2 +-
+ arch/m68k/math-emu/fp_decode.h | 4 ++--
+ arch/m68k/math-emu/fp_move.S | 14 +++++++-------
+ arch/m68k/math-emu/fp_movem.S | 16 ++++++++--------
+ arch/m68k/math-emu/fp_scan.S | 22 +++++++++++-----------
+ arch/m68k/math-emu/fp_util.S | 16 ++++++++--------
+ 6 files changed, 37 insertions(+), 37 deletions(-)
+
+3c4ab44571b5a46917ad28620995c326e386a909
+diff --git a/arch/m68k/math-emu/fp_cond.S b/arch/m68k/math-emu/fp_cond.S
+index ddae8b1..1cddeb0 100644
+--- a/arch/m68k/math-emu/fp_cond.S
++++ b/arch/m68k/math-emu/fp_cond.S
+@@ -163,7 +163,7 @@ fp_absolute_long:
+
+ fp_do_scc:
+ swap %d1
+- putuser.b %d1,(%a0),fp_err_ua1,%a0
++ putuser .b,%d1,(%a0),fp_err_ua1,%a0
+ printf PDECODE,"\n"
+ jra fp_end
+
+diff --git a/arch/m68k/math-emu/fp_decode.h b/arch/m68k/math-emu/fp_decode.h
+index 759679d..a2595d9 100644
+--- a/arch/m68k/math-emu/fp_decode.h
++++ b/arch/m68k/math-emu/fp_decode.h
+@@ -311,7 +311,7 @@ debug move.l "(%sp)+,%d1"
+ btst #2,%d2
+ jne 1f
+ printf PDECODE,")@("
+- getuser.l (%a1),%a1,fp_err_ua1,%a1
++ getuser .l,(%a1),%a1,fp_err_ua1,%a1
+ debug jra "2f"
+ 1: printf PDECODE,","
+ 2:
+@@ -322,7 +322,7 @@ debug jra "2f"
+ btst #2,%d2
+ jeq 1f
+ printf PDECODE,")@("
+- getuser.l (%a1),%a1,fp_err_ua1,%a1
++ getuser .l,(%a1),%a1,fp_err_ua1,%a1
+ debug jra "2f"
+ 1: printf PDECODE,","
+ 2:
+diff --git a/arch/m68k/math-emu/fp_move.S b/arch/m68k/math-emu/fp_move.S
+index 71bdf83..9bd0334 100644
+--- a/arch/m68k/math-emu/fp_move.S
++++ b/arch/m68k/math-emu/fp_move.S
+@@ -200,12 +200,12 @@ fp_putdest:
+
+ fp_format_long:
+ jsr fp_conv_ext2long
+- putuser.l %d0,(%a1),fp_err_ua1,%a1
++ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_single:
+ jsr fp_conv_ext2single
+- putuser.l %d0,(%a1),fp_err_ua1,%a1
++ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_extended:
+@@ -213,11 +213,11 @@ fp_format_extended:
+ lsl.w #1,%d0
+ lsl.l #7,%d0
+ lsl.l #8,%d0
+- putuser.l %d0,(%a1)+,fp_err_ua1,%a1
++ putuser .l,%d0,(%a1)+,fp_err_ua1,%a1
+ move.l (%a0)+,%d0
+- putuser.l %d0,(%a1)+,fp_err_ua1,%a1
++ putuser .l,%d0,(%a1)+,fp_err_ua1,%a1
+ move.l (%a0),%d0
+- putuser.l %d0,(%a1),fp_err_ua1,%a1
++ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_packed:
+@@ -227,7 +227,7 @@ fp_format_packed:
+
+ fp_format_word:
+ jsr fp_conv_ext2short
+- putuser.w %d0,(%a1),fp_err_ua1,%a1
++ putuser .w,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_double:
+@@ -236,7 +236,7 @@ fp_format_double:
+
+ fp_format_byte:
+ jsr fp_conv_ext2byte
+- putuser.b %d0,(%a1),fp_err_ua1,%a1
++ putuser .b,%d0,(%a1),fp_err_ua1,%a1
+ | jra fp_finish_move
+
+ fp_finish_move:
+diff --git a/arch/m68k/math-emu/fp_movem.S b/arch/m68k/math-emu/fp_movem.S
+index 8354d39..9c74134 100644
+--- a/arch/m68k/math-emu/fp_movem.S
++++ b/arch/m68k/math-emu/fp_movem.S
+@@ -141,14 +141,14 @@ fpr_do_movem:
+ | move register from memory into fpu
+ jra 3f
+ 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
+- getuser.l (%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
+ lsr.l #8,%d2
+ lsr.l #7,%d2
+ lsr.w #1,%d2
+ move.l %d2,(%a1)+
+- getuser.l (%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
+ move.l %d2,(%a1)+
+- getuser.l (%a0),%d2,fp_err_ua1,%a0
++ getuser .l,(%a0),%d2,fp_err_ua1,%a0
+ move.l %d2,(%a1)
+ subq.l #8,%a0
+ subq.l #8,%a1
+@@ -164,11 +164,11 @@ fpr_do_movem:
+ lsl.w #1,%d2
+ lsl.l #7,%d2
+ lsl.l #8,%d2
+- putuser.l %d2,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d2,(%a0)+,fp_err_ua1,%a0
+ move.l (%a1)+,%d2
+- putuser.l %d2,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d2,(%a0)+,fp_err_ua1,%a0
+ move.l (%a1),%d2
+- putuser.l %d2,(%a0),fp_err_ua1,%a0
++ putuser .l,%d2,(%a0),fp_err_ua1,%a0
+ subq.l #8,%a1
+ subq.l #8,%a0
+ add.l %d0,%a0
+@@ -325,7 +325,7 @@ fpc_do_movem:
+ | move register from memory into fpu
+ jra 3f
+ 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
+- getuser.l (%a0)+,%d0,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d0,fp_err_ua1,%a0
+ move.l %d0,(%a1)
+ 2: addq.l #4,%a1
+ 3: lsl.b #1,%d1
+@@ -336,7 +336,7 @@ fpc_do_movem:
+ | move register from fpu into memory
+ 1: printf PMOVEM,"(%p>%p)",2,%a1,%a0
+ move.l (%a1),%d0
+- putuser.l %d0,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d0,(%a0)+,fp_err_ua1,%a0
+ 2: addq.l #4,%a1
+ 4: lsl.b #1,%d1
+ jcs 1b
+diff --git a/arch/m68k/math-emu/fp_scan.S b/arch/m68k/math-emu/fp_scan.S
+index e4146ed..5f49b93 100644
+--- a/arch/m68k/math-emu/fp_scan.S
++++ b/arch/m68k/math-emu/fp_scan.S
+@@ -64,7 +64,7 @@ fp_scan:
+ | normal fpu instruction? (this excludes fsave/frestore)
+ fp_get_pc %a0
+ printf PDECODE,"%08x: ",1,%a0
+- getuser.b (%a0),%d0,fp_err_ua1,%a0
++ getuser .b,(%a0),%d0,fp_err_ua1,%a0
+ #if 1
+ cmp.b #0xf2,%d0 | cpid = 1
+ #else
+@@ -72,7 +72,7 @@ fp_scan:
+ #endif
+ jne fp_nonstd
+ | first two instruction words are kept in %d2
+- getuser.l (%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
+ fp_put_pc %a0
+ fp_decode_cond: | separate conditional instr
+ fp_decode_cond_instr_type
+@@ -230,7 +230,7 @@ fp_immediate:
+ movel %a0,%a1
+ clr.l %d1
+ jra 2f
+-1: getuser.b (%a1)+,%d1,fp_err_ua1,%a1
++1: getuser .b,(%a1)+,%d1,fp_err_ua1,%a1
+ printf PDECODE,"%02x",1,%d1
+ 2: dbra %d0,1b
+ movem.l (%sp)+,%d0/%d1
+@@ -252,24 +252,24 @@ fp_fetchsource:
+ .long fp_byte, fp_ill
+
+ fp_long:
+- getuser.l (%a1),%d0,fp_err_ua1,%a1
++ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ jsr fp_conv_long2ext
+ jra fp_getdest
+
+ fp_single:
+- getuser.l (%a1),%d0,fp_err_ua1,%a1
++ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ jsr fp_conv_single2ext
+ jra fp_getdest
+
+ fp_ext:
+- getuser.l (%a1)+,%d0,fp_err_ua1,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua1,%a1
+ lsr.l #8,%d0
+ lsr.l #7,%d0
+ lsr.w #1,%d0
+ move.l %d0,(%a0)+
+- getuser.l (%a1)+,%d0,fp_err_ua1,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua1,%a1
+ move.l %d0,(%a0)+
+- getuser.l (%a1),%d0,fp_err_ua1,%a1
++ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ move.l %d0,(%a0)
+ subq.l #8,%a0
+ jra fp_getdest
+@@ -279,7 +279,7 @@ fp_pack:
+ jra fp_ill
+
+ fp_word:
+- getuser.w (%a1),%d0,fp_err_ua1,%a1
++ getuser .w,(%a1),%d0,fp_err_ua1,%a1
+ ext.l %d0
+ jsr fp_conv_long2ext
+ jra fp_getdest
+@@ -289,7 +289,7 @@ fp_double:
+ jra fp_getdest
+
+ fp_byte:
+- getuser.b (%a1),%d0,fp_err_ua1,%a1
++ getuser .b,(%a1),%d0,fp_err_ua1,%a1
+ extb.l %d0
+ jsr fp_conv_long2ext
+ | jra fp_getdest
+@@ -465,7 +465,7 @@ fp_fdsub:
+
+ fp_nonstd:
+ fp_get_pc %a0
+- getuser.l (%a0),%d0,fp_err_ua1,%a0
++ getuser .l,(%a0),%d0,fp_err_ua1,%a0
+ printf ,"nonstd ((%08x)=%08x)\n",2,%a0,%d0
+ moveq #-1,%d0
+ rts
+diff --git a/arch/m68k/math-emu/fp_util.S b/arch/m68k/math-emu/fp_util.S
+index a9f7f01..f9f24d5 100644
+--- a/arch/m68k/math-emu/fp_util.S
++++ b/arch/m68k/math-emu/fp_util.S
+@@ -160,11 +160,11 @@ fp_s2e_large:
+
+ fp_conv_double2ext:
+ #ifdef FPU_EMU_DEBUG
+- getuser.l %a1@(0),%d0,fp_err_ua2,%a1
+- getuser.l %a1@(4),%d1,fp_err_ua2,%a1
++ getuser .l,%a1@(0),%d0,fp_err_ua2,%a1
++ getuser .l,%a1@(4),%d1,fp_err_ua2,%a1
+ printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
+ #endif
+- getuser.l (%a1)+,%d0,fp_err_ua2,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua2,%a1
+ move.l %d0,%d1
+ lsl.l #8,%d0 | shift high mantissa
+ lsl.l #3,%d0
+@@ -178,7 +178,7 @@ fp_conv_double2ext:
+ add.w #0x3fff-0x3ff,%d1 | re-bias the exponent.
+ 9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp
+ move.l %d0,(%a0)+
+- getuser.l (%a1)+,%d0,fp_err_ua2,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua2,%a1
+ move.l %d0,%d1
+ lsl.l #8,%d0
+ lsl.l #3,%d0
+@@ -1287,17 +1287,17 @@ fp_conv_ext2double:
+ lsr.l #4,%d0
+ lsr.l #8,%d0
+ or.l %d2,%d0
+- putuser.l %d0,(%a1)+,fp_err_ua2,%a1
++ putuser .l,%d0,(%a1)+,fp_err_ua2,%a1
+ moveq #21,%d0
+ lsl.l %d0,%d1
+ move.l (%a0),%d0
+ lsr.l #4,%d0
+ lsr.l #7,%d0
+ or.l %d1,%d0
+- putuser.l %d0,(%a1),fp_err_ua2,%a1
++ putuser .l,%d0,(%a1),fp_err_ua2,%a1
+ #ifdef FPU_EMU_DEBUG
+- getuser.l %a1@(-4),%d0,fp_err_ua2,%a1
+- getuser.l %a1@(0),%d1,fp_err_ua2,%a1
++ getuser .l,%a1@(-4),%d0,fp_err_ua2,%a1
++ getuser .l,%a1@(0),%d1,fp_err_ua2,%a1
+ printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1
+ #endif
+ rts
+--
+0.99.9.GIT
+
+-
+To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+
Added: people/maks-guest/linux-2.6/debian/patches/m68k-fbcon.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/m68k-fbcon.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,35 @@
+Log message:
+fix the survivors of fbcon_vbl_handler() renaming
+
+Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
+
+Modified files:
+ linux/drivers/video/console:
+ fbcon.c
+
+
+Index: linux/drivers/video/console/fbcon.c
+Stats: 4 modifications
+http://linux-m68k-cvs.ubb.ca/c/cvsweb/linux/drivers/video/console/fbcon%2ec.diff?r1=1.1.1.23&r2=1.4
+========================================================================
+--- linux/drivers/video/console/fbcon.c 23 Sep 2006 17:01:53 -0000 1.1.1.23
++++ linux/drivers/video/console/fbcon.c 27 Sep 2006 23:15:51 -0000 1.4
+@@ -3197,11 +3197,11 @@
+ return;
+
+ #ifdef CONFIG_ATARI
+- free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
++ free_irq(IRQ_AUTO_4, fb_vbl_handler);
+ #endif
+ #ifdef CONFIG_MAC
+ if (MACH_IS_MAC && vbl_detected)
+- free_irq(IRQ_MAC_VBL, fbcon_vbl_handler);
++ free_irq(IRQ_MAC_VBL, fb_vbl_handler);
+ #endif
+
+ kfree((void *)softback_buf);
+-
+To unsubscribe from this list: send the line "unsubscribe linux-m68k-cvscommit" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+
Added: people/maks-guest/linux-2.6/debian/patches/m68k-macro.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/m68k-macro.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,149 @@
+From: Al Viro <viro at zeniv.linux.org.uk>
+Date: 1134435322 -0500
+
+cretinous thing doesn't believe that (%a0)+ is one macro argument and
+splits it in two; worked around by quoting the argument...
+
+Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
+
+---
+
+ arch/m68k/math-emu/fp_move.S | 4 ++--
+ arch/m68k/math-emu/fp_movem.S | 12 ++++++------
+ arch/m68k/math-emu/fp_scan.S | 6 +++---
+ arch/m68k/math-emu/fp_util.S | 6 +++---
+ 4 files changed, 14 insertions(+), 14 deletions(-)
+
+5ea87cc472a0aebf479e94ac287c50e1c070f741
+diff --git a/arch/m68k/math-emu/fp_move.S b/arch/m68k/math-emu/fp_move.S
+index 9bd0334..19363b3 100644
+--- a/arch/m68k/math-emu/fp_move.S
++++ b/arch/m68k/math-emu/fp_move.S
+@@ -213,9 +213,9 @@ fp_format_extended:
+ lsl.w #1,%d0
+ lsl.l #7,%d0
+ lsl.l #8,%d0
+- putuser .l,%d0,(%a1)+,fp_err_ua1,%a1
++ putuser .l,%d0,"(%a1)+",fp_err_ua1,%a1
+ move.l (%a0)+,%d0
+- putuser .l,%d0,(%a1)+,fp_err_ua1,%a1
++ putuser .l,%d0,"(%a1)+",fp_err_ua1,%a1
+ move.l (%a0),%d0
+ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+diff --git a/arch/m68k/math-emu/fp_movem.S b/arch/m68k/math-emu/fp_movem.S
+index 9c74134..4173655 100644
+--- a/arch/m68k/math-emu/fp_movem.S
++++ b/arch/m68k/math-emu/fp_movem.S
+@@ -141,12 +141,12 @@ fpr_do_movem:
+ | move register from memory into fpu
+ jra 3f
+ 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
+- getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,"(%a0)+",%d2,fp_err_ua1,%a0
+ lsr.l #8,%d2
+ lsr.l #7,%d2
+ lsr.w #1,%d2
+ move.l %d2,(%a1)+
+- getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,"(%a0)+",%d2,fp_err_ua1,%a0
+ move.l %d2,(%a1)+
+ getuser .l,(%a0),%d2,fp_err_ua1,%a0
+ move.l %d2,(%a1)
+@@ -164,9 +164,9 @@ fpr_do_movem:
+ lsl.w #1,%d2
+ lsl.l #7,%d2
+ lsl.l #8,%d2
+- putuser .l,%d2,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d2,"(%a0)+",fp_err_ua1,%a0
+ move.l (%a1)+,%d2
+- putuser .l,%d2,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d2,"(%a0)+",fp_err_ua1,%a0
+ move.l (%a1),%d2
+ putuser .l,%d2,(%a0),fp_err_ua1,%a0
+ subq.l #8,%a1
+@@ -325,7 +325,7 @@ fpc_do_movem:
+ | move register from memory into fpu
+ jra 3f
+ 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
+- getuser .l,(%a0)+,%d0,fp_err_ua1,%a0
++ getuser .l,"(%a0)+",%d0,fp_err_ua1,%a0
+ move.l %d0,(%a1)
+ 2: addq.l #4,%a1
+ 3: lsl.b #1,%d1
+@@ -336,7 +336,7 @@ fpc_do_movem:
+ | move register from fpu into memory
+ 1: printf PMOVEM,"(%p>%p)",2,%a1,%a0
+ move.l (%a1),%d0
+- putuser .l,%d0,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d0,"(%a0)+",fp_err_ua1,%a0
+ 2: addq.l #4,%a1
+ 4: lsl.b #1,%d1
+ jcs 1b
+diff --git a/arch/m68k/math-emu/fp_scan.S b/arch/m68k/math-emu/fp_scan.S
+index 5f49b93..6a71ed1 100644
+--- a/arch/m68k/math-emu/fp_scan.S
++++ b/arch/m68k/math-emu/fp_scan.S
+@@ -72,7 +72,7 @@ fp_scan:
+ #endif
+ jne fp_nonstd
+ | first two instruction words are kept in %d2
+- getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,"(%a0)+",%d2,fp_err_ua1,%a0
+ fp_put_pc %a0
+ fp_decode_cond: | separate conditional instr
+ fp_decode_cond_instr_type
+@@ -262,12 +262,12 @@ fp_single:
+ jra fp_getdest
+
+ fp_ext:
+- getuser .l,(%a1)+,%d0,fp_err_ua1,%a1
++ getuser .l,"(%a1)+",%d0,fp_err_ua1,%a1
+ lsr.l #8,%d0
+ lsr.l #7,%d0
+ lsr.w #1,%d0
+ move.l %d0,(%a0)+
+- getuser .l,(%a1)+,%d0,fp_err_ua1,%a1
++ getuser .l,"(%a1)+",%d0,fp_err_ua1,%a1
+ move.l %d0,(%a0)+
+ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ move.l %d0,(%a0)
+diff --git a/arch/m68k/math-emu/fp_util.S b/arch/m68k/math-emu/fp_util.S
+index f9f24d5..170110a 100644
+--- a/arch/m68k/math-emu/fp_util.S
++++ b/arch/m68k/math-emu/fp_util.S
+@@ -164,7 +164,7 @@ fp_conv_double2ext:
+ getuser .l,%a1@(4),%d1,fp_err_ua2,%a1
+ printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
+ #endif
+- getuser .l,(%a1)+,%d0,fp_err_ua2,%a1
++ getuser .l,"(%a1)+",%d0,fp_err_ua2,%a1
+ move.l %d0,%d1
+ lsl.l #8,%d0 | shift high mantissa
+ lsl.l #3,%d0
+@@ -178,7 +178,7 @@ fp_conv_double2ext:
+ add.w #0x3fff-0x3ff,%d1 | re-bias the exponent.
+ 9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp
+ move.l %d0,(%a0)+
+- getuser .l,(%a1)+,%d0,fp_err_ua2,%a1
++ getuser .l,"(%a1)+",%d0,fp_err_ua2,%a1
+ move.l %d0,%d1
+ lsl.l #8,%d0
+ lsl.l #3,%d0
+@@ -1287,7 +1287,7 @@ fp_conv_ext2double:
+ lsr.l #4,%d0
+ lsr.l #8,%d0
+ or.l %d2,%d0
+- putuser .l,%d0,(%a1)+,fp_err_ua2,%a1
++ putuser .l,%d0,"(%a1)+",fp_err_ua2,%a1
+ moveq #21,%d0
+ lsl.l %d0,%d1
+ move.l (%a0),%d0
+--
+0.99.9.GIT
+
+-
+To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+
Added: people/maks-guest/linux-2.6/debian/patches/m68k-no-backlight.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/m68k-no-backlight.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,31 @@
+Log message:
+asm/backlight.h is ppc-only
+
+Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
+
+Modified files:
+ linux/drivers/macintosh:
+ adbhid.c
+
+
+Index: linux/drivers/macintosh/adbhid.c
+Stats: 1 insertion, 1 deletion
+http://linux-m68k-cvs.ubb.ca/c/cvsweb/linux/drivers/macintosh/adbhid%2ec.diff?r1=1.1.1.23&r2=1.9
+========================================================================
+--- linux/drivers/macintosh/adbhid.c 23 Sep 2006 16:43:55 -0000 1.1.1.23
++++ linux/drivers/macintosh/adbhid.c 27 Sep 2006 23:14:35 -0000 1.9
+@@ -45,8 +45,8 @@
+ #include <linux/pmu.h>
+
+ #include <asm/machdep.h>
+-#include <asm/backlight.h>
+ #ifdef CONFIG_PPC_PMAC
++#include <asm/backlight.h>
+ #include <asm/pmac_feature.h>
+ #endif
+
+-
+To unsubscribe from this list: send the line "unsubscribe linux-m68k-cvscommit" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+
Added: people/maks-guest/linux-2.6/debian/patches/mips-arch-makefile.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-arch-makefile.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,22 @@
+## DP: Add -mfix7000 to CONFIG_SGI_IP22
+## DP: Patch author: Thiemo Seufer <ths at networkno.de>
+## DP: Upstream status: unclear
+
+From: Thiemo Seufer <ths at networkno.de>
+
+Add -mfix7000 to CONFIG_SGI_IP22
+
+Signed-off-by: Thiemo Seufer <ths at networkno.de>
+Signed-off-by: Martin Michlmayr <tbm at cyrius.com>
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -478,7 +478,7 @@ load-$(CONFIG_PNX8550_JBS) += 0xffffffff
+ # address by 8kb.
+ #
+ core-$(CONFIG_SGI_IP22) += arch/mips/sgi-ip22/
+-cflags-$(CONFIG_SGI_IP22) += -Iinclude/asm-mips/mach-ip22
++cflags-$(CONFIG_SGI_IP22) += -Iinclude/asm-mips/mach-ip22 -Wa,-mfix7000
+ ifdef CONFIG_32BIT
+ load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
+ endif
Added: people/maks-guest/linux-2.6/debian/patches/mips-ide-scan.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-ide-scan.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,98 @@
+## DP: Fix long IDE detection delay by not scanning non-existent channels.
+## DP: Patch author: Peter Horton <pdh at colonel-panic.org>
+## DP: Upstream status: submitted to linux-mips
+
+# Fix long delay during Cobalt boot whilst scanning non-existent
+# interfaces. The logic is copied from i386 i.e. we only scan 2 legacy
+# ports if we have PCI IDE.
+
+# Signed-off-by: Peter Horton <pdh at colonel-panic.org>
+# Acked-by: Alan Cox <alan at lxorguk.ukuu.org.uk>
+
+--- linux.git.orig/include/asm-mips/mach-generic/ide.h 2006-01-24 22:07:36.000000000 +0000
++++ linux.git/include/asm-mips/mach-generic/ide.h 2006-01-24 23:41:19.000000000 +0000
+@@ -30,7 +30,7 @@
+
+ #define IDE_ARCH_OBSOLETE_DEFAULTS
+
+-static __inline__ int ide_probe_legacy(void)
++static __inline__ int ide_legacy_ports(void)
+ {
+ #ifdef CONFIG_PCI
+ struct pci_dev *dev;
+@@ -38,11 +38,11 @@
+ (dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL)) != NULL) {
+ pci_dev_put(dev);
+
+- return 1;
++ return 2;
+ }
+ return 0;
+ #elif defined(CONFIG_EISA) || defined(CONFIG_ISA)
+- return 1;
++ return 6;
+ #else
+ return 0;
+ #endif
+@@ -50,30 +50,26 @@
+
+ static __inline__ int ide_default_irq(unsigned long base)
+ {
+- if (ide_probe_legacy())
+- switch (base) {
+- case 0x1f0:
+- return 14;
+- case 0x170:
+- return 15;
+- case 0x1e8:
+- return 11;
+- case 0x168:
+- return 10;
+- case 0x1e0:
+- return 8;
+- case 0x160:
+- return 12;
+- default:
+- return 0;
+- }
+- else
+- return 0;
++ switch (base) {
++ case 0x1f0:
++ return 14;
++ case 0x170:
++ return 15;
++ case 0x1e8:
++ return 11;
++ case 0x168:
++ return 10;
++ case 0x1e0:
++ return 8;
++ case 0x160:
++ return 12;
++ }
++ return 0;
+ }
+
+ static __inline__ unsigned long ide_default_io_base(int index)
+ {
+- if (ide_probe_legacy())
++ if (index < ide_legacy_ports())
+ switch (index) {
+ case 0:
+ return 0x1f0;
+@@ -87,11 +83,8 @@
+ return 0x1e0;
+ case 5:
+ return 0x160;
+- default:
+- return 0;
+- }
+- else
+- return 0;
++ }
++ return 0;
+ }
+
+ #define IDE_ARCH_OBSOLETE_INIT
+
Added: people/maks-guest/linux-2.6/debian/patches/mips-sb1-duart-tts.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-sb1-duart-tts.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+Patch: change the name of the sb1250 DUART from duart to ttyS
+Needed for debian-installer
+Status: the sb1250_duart.c driver needs a completely re-write...
+
+--- a/drivers/char/sb1250_duart.c~ 2006-09-05 15:04:15.015419723 +0200
++++ b/drivers/char/sb1250_duart.c 2006-09-05 15:04:24.442152073 +0200
+@@ -762,7 +762,7 @@
+ return -ENOMEM;
+
+ sb1250_duart_driver->owner = THIS_MODULE;
+- sb1250_duart_driver->name = "duart";
++ sb1250_duart_driver->name = "ttyS";
+ sb1250_duart_driver->major = TTY_MAJOR;
+ sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
+ sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL;
Added: people/maks-guest/linux-2.6/debian/patches/mips-sb1-duart.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-sb1-duart.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,959 @@
+DUART support for Sibyte SB1
+
+Status: in linux-mips git; still needs to be merged into mainline
+
+
+--- a/include/linux/serial.h~ 2006-03-13 19:32:04.000000000 +0000
++++ b/include/linux/serial.h 2006-03-13 19:32:27.000000000 +0000
+@@ -76,7 +76,8 @@
+ #define PORT_16654 11
+ #define PORT_16850 12
+ #define PORT_RSA 13 /* RSA-DV II/S card */
+-#define PORT_MAX 13
++#define PORT_SB1250 14
++#define PORT_MAX 14
+
+ #define SERIAL_IO_PORT 0
+ #define SERIAL_IO_HUB6 1
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -353,6 +353,14 @@ config AU1000_SERIAL_CONSOLE
+ If you have an Alchemy AU1000 processor (MIPS based) and you want
+ to use a console on a serial port, say Y. Otherwise, say N.
+
++config SIBYTE_SB1250_DUART
++ bool "Support for BCM1xxx onchip DUART"
++ depends on MIPS && SIBYTE_SB1xxx_SOC=y
++
++config SIBYTE_SB1250_DUART_CONSOLE
++ bool "Console on BCM1xxx DUART"
++ depends on SIBYTE_SB1250_DUART
++
+ config QTRONIX_KEYBOARD
+ bool "Enable Qtronix 990P Keyboard Support"
+ depends on IT8712
+diff --git a/drivers/char/Makefile b/drivers/char/Makefile
+index 503dd90..2db5532 100644
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_ISTALLION) += istallion.o
+ obj-$(CONFIG_DIGIEPCA) += epca.o
+ obj-$(CONFIG_SPECIALIX) += specialix.o
+ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
++obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
+ obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
+ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
+ obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
+--- /dev/null 2006-08-04 20:47:12.000000000 +0200
++++ b/drivers/char/sb1250_duart.c 2006-09-05 15:02:53.718727952 +0200
+@@ -0,0 +1,910 @@
++/*
++ * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Driver support for the on-chip sb1250 dual-channel serial port,
++ * running in asynchronous mode. Also, support for doing a serial console
++ * on one of those ports
++ */
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/console.h>
++#include <linux/kdev_t.h>
++#include <linux/major.h>
++#include <linux/termios.h>
++#include <linux/spinlock.h>
++#include <linux/irq.h>
++#include <linux/errno.h>
++#include <linux/tty.h>
++#include <linux/sched.h>
++#include <linux/tty_flip.h>
++#include <linux/timer.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <asm/delay.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/sibyte/swarm.h>
++#include <asm/sibyte/sb1250.h>
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#include <asm/sibyte/bcm1480_regs.h>
++#include <asm/sibyte/bcm1480_int.h>
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#include <asm/sibyte/sb1250_regs.h>
++#include <asm/sibyte/sb1250_int.h>
++#else
++#error invalid SiByte UART configuation
++#endif
++#include <asm/sibyte/sb1250_uart.h>
++#include <asm/war.h>
++
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#define UNIT_CHANREG(n,reg) A_BCM1480_DUART_CHANREG((n),(reg))
++#define UNIT_IMRREG(n) A_BCM1480_DUART_IMRREG(n)
++#define UNIT_INT(n) (K_BCM1480_INT_UART_0 + (n))
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#define UNIT_CHANREG(n,reg) A_DUART_CHANREG((n),(reg))
++#define UNIT_IMRREG(n) A_DUART_IMRREG(n)
++#define UNIT_INT(n) (K_INT_UART_0 + (n))
++#else
++#error invalid SiByte UART configuation
++#endif
++
++/* Toggle spewing of debugging output */
++#undef DEBUG
++
++#define DEFAULT_CFLAGS (CS8 | B115200)
++
++#define TX_INTEN 1
++#define DUART_INITIALIZED 2
++
++#define DUART_MAX_LINE 4
++char sb1250_duart_present[DUART_MAX_LINE];
++EXPORT_SYMBOL(sb1250_duart_present);
++
++/*
++ * Still not sure what the termios structures set up here are for,
++ * but we have to supply pointers to them to register the tty driver
++ */
++static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver;
++
++/*
++ * This lock protects both the open flags for all the uart states as
++ * well as the reference count for the module
++ */
++static DEFINE_SPINLOCK(open_lock);
++
++typedef struct {
++ unsigned char outp_buf[SERIAL_XMIT_SIZE];
++ unsigned int outp_head;
++ unsigned int outp_tail;
++ unsigned int outp_count;
++ spinlock_t outp_lock;
++ unsigned int open;
++ unsigned int line;
++ unsigned int last_cflags;
++ unsigned long flags;
++ struct tty_struct *tty;
++ /* CSR addresses */
++ volatile u32 *status;
++ volatile u32 *imr;
++ volatile u32 *tx_hold;
++ volatile u32 *rx_hold;
++ volatile u32 *mode_1;
++ volatile u32 *mode_2;
++ volatile u32 *clk_sel;
++ volatile u32 *cmd;
++} uart_state_t;
++
++static uart_state_t uart_states[DUART_MAX_LINE];
++
++/*
++ * Inline functions local to this module
++ */
++
++/*
++ * In bug 1956, we get glitches that can mess up uart registers. This
++ * "write-mode-1 after any register access" is the accepted
++ * workaround.
++ */
++#if SIBYTE_1956_WAR
++static unsigned int last_mode1[DUART_MAX_LINE];
++#endif
++
++static inline u32 READ_SERCSR(volatile u32 *addr, int line)
++{
++ u32 val = csr_in32(addr);
++#if SIBYTE_1956_WAR
++ csr_out32(last_mode1[line], uart_states[line].mode_1);
++#endif
++ return val;
++}
++
++static inline void WRITE_SERCSR(u32 val, volatile u32 *addr, int line)
++{
++ csr_out32(val, addr);
++#if SIBYTE_1956_WAR
++ csr_out32(last_mode1[line], uart_states[line].mode_1);
++#endif
++}
++
++static void init_duart_port(uart_state_t *port, int line)
++{
++ if (!(port->flags & DUART_INITIALIZED)) {
++ port->line = line;
++ port->status = IOADDR(UNIT_CHANREG(line, R_DUART_STATUS));
++ port->imr = IOADDR(UNIT_IMRREG(line));
++ port->tx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_TX_HOLD));
++ port->rx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_RX_HOLD));
++ port->mode_1 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_1));
++ port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2));
++ port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL));
++ port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD));
++ port->flags |= DUART_INITIALIZED;
++ }
++}
++
++/*
++ * Mask out the passed interrupt lines at the duart level. This should be
++ * called while holding the associated outp_lock.
++ */
++static inline void duart_mask_ints(unsigned int line, unsigned int mask)
++{
++ uart_state_t *port = uart_states + line;
++ u64 tmp = READ_SERCSR(port->imr, line);
++ WRITE_SERCSR(tmp & ~mask, port->imr, line);
++}
++
++
++/* Unmask the passed interrupt lines at the duart level */
++static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
++{
++ uart_state_t *port = uart_states + line;
++ u64 tmp = READ_SERCSR(port->imr, line);
++ WRITE_SERCSR(tmp | mask, port->imr, line);
++}
++
++static inline void transmit_char_pio(uart_state_t *us)
++{
++ struct tty_struct *tty = us->tty;
++ int blocked = 0;
++
++ if (spin_trylock(&us->outp_lock)) {
++ for (;;) {
++ if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
++ break;
++ if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
++ break;
++ } else {
++ WRITE_SERCSR(us->outp_buf[us->outp_head],
++ us->tx_hold, us->line);
++ us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
++ if (--us->outp_count <= 0)
++ break;
++ }
++ udelay(10);
++ }
++ spin_unlock(&us->outp_lock);
++ } else {
++ blocked = 1;
++ }
++
++ if (!us->outp_count || tty->stopped ||
++ tty->hw_stopped || blocked) {
++ us->flags &= ~TX_INTEN;
++ duart_mask_ints(us->line, M_DUART_IMR_TX);
++ }
++
++ if (us->open &&
++ (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
++ /*
++ * We told the discipline at one point that we had no
++ * space, so it went to sleep. Wake it up when we hit
++ * half empty
++ */
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ tty->ldisc.write_wakeup(tty);
++ wake_up_interruptible(&tty->write_wait);
++ }
++}
++
++/*
++ * Generic interrupt handler for both channels. dev_id is a pointer
++ * to the proper uart_states structure, so from that we can derive
++ * which port interrupted
++ */
++
++static irqreturn_t duart_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ uart_state_t *us = (uart_state_t *)dev_id;
++ struct tty_struct *tty = us->tty;
++ unsigned int status = READ_SERCSR(us->status, us->line);
++
++ pr_debug("DUART INT\n");
++
++ if (status & M_DUART_RX_RDY) {
++ int counter = 2048;
++ unsigned int ch;
++
++ if (status & M_DUART_OVRUN_ERR)
++ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
++ if (status & M_DUART_PARITY_ERR) {
++ printk("Parity error!\n");
++ } else if (status & M_DUART_FRM_ERR) {
++ printk("Frame error!\n");
++ }
++
++ while (counter > 0) {
++ if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
++ break;
++ ch = READ_SERCSR(us->rx_hold, us->line);
++ tty_insert_flip_char(tty, ch, 0);
++ udelay(1);
++ counter--;
++ }
++ tty_flip_buffer_push(tty);
++ }
++
++ if (status & M_DUART_TX_RDY) {
++ transmit_char_pio(us);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Actual driver functions
++ */
++
++/* Return the number of characters we can accomodate in a write at this instant */
++static int duart_write_room(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ int retval;
++
++ retval = SERIAL_XMIT_SIZE - us->outp_count;
++
++ pr_debug("duart_write_room called, returning %i\n", retval);
++
++ return retval;
++}
++
++/* memcpy the data from src to destination, but take extra care if the
++ data is coming from user space */
++static inline int copy_buf(char *dest, const char *src, int size, int from_user)
++{
++ if (from_user) {
++ (void) copy_from_user(dest, src, size);
++ } else {
++ memcpy(dest, src, size);
++ }
++ return size;
++}
++
++/*
++ * Buffer up to count characters from buf to be written. If we don't have
++ * other characters buffered, enable the tx interrupt to start sending
++ */
++static int duart_write(struct tty_struct *tty, const unsigned char *buf,
++ int count)
++{
++ uart_state_t *us;
++ int c, t, total = 0;
++ unsigned long flags;
++
++ if (!tty) return 0;
++
++ us = tty->driver_data;
++ if (!us) return 0;
++
++ pr_debug("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
++
++ spin_lock_irqsave(&us->outp_lock, flags);
++
++ for (;;) {
++ c = count;
++
++ t = SERIAL_XMIT_SIZE - us->outp_tail;
++ if (t < c) c = t;
++
++ t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
++ if (t < c) c = t;
++
++ if (c <= 0) break;
++
++ memcpy(us->outp_buf + us->outp_tail, buf, c);
++
++ us->outp_count += c;
++ us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
++ buf += c;
++ count -= c;
++ total += c;
++ }
++
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++
++ if (us->outp_count && !tty->stopped &&
++ !tty->hw_stopped && !(us->flags & TX_INTEN)) {
++ us->flags |= TX_INTEN;
++ duart_unmask_ints(us->line, M_DUART_IMR_TX);
++ }
++
++ return total;
++}
++
++
++/* Buffer one character to be written. If there's not room for it, just drop
++ it on the floor. This is used for echo, among other things */
++static void duart_put_char(struct tty_struct *tty, u_char ch)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long flags;
++
++ pr_debug("duart_put_char called. Char is %x (%c)\n", (int)ch, ch);
++
++ spin_lock_irqsave(&us->outp_lock, flags);
++
++ if (us->outp_count == SERIAL_XMIT_SIZE) {
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++ return;
++ }
++
++ us->outp_buf[us->outp_tail] = ch;
++ us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
++ us->outp_count++;
++
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++}
++
++static void duart_flush_chars(struct tty_struct * tty)
++{
++ uart_state_t *port;
++
++ if (!tty) return;
++
++ port = tty->driver_data;
++
++ if (!port) return;
++
++ if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
++ return;
++ }
++
++ port->flags |= TX_INTEN;
++ duart_unmask_ints(port->line, M_DUART_IMR_TX);
++}
++
++/* Return the number of characters in the output buffer that have yet to be
++ written */
++static int duart_chars_in_buffer(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ int retval;
++
++ retval = us->outp_count;
++
++ pr_debug("duart_chars_in_buffer returning %i\n", retval);
++
++ return retval;
++}
++
++/* Kill everything we haven't yet shoved into the FIFO. Turn off the
++ transmit interrupt since we've nothing more to transmit */
++static void duart_flush_buffer(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long flags;
++
++ pr_debug("duart_flush_buffer called\n");
++ spin_lock_irqsave(&us->outp_lock, flags);
++ us->outp_head = us->outp_tail = us->outp_count = 0;
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++
++ wake_up_interruptible(&us->tty->write_wait);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ tty->ldisc.write_wakeup(tty);
++}
++
++
++/* See sb1250 user manual for details on these registers */
++static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
++{
++ unsigned int mode_reg1 = 0, mode_reg2 = 0;
++ unsigned int clk_divisor;
++ uart_state_t *port = uart_states + line;
++
++ switch (cflag & CSIZE) {
++ case CS7:
++ mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
++
++ default:
++ /* We don't handle CS5 or CS6...is there a way we're supposed to flag this?
++ right now we just force them to CS8 */
++ mode_reg1 |= 0x0;
++ break;
++ }
++ if (cflag & CSTOPB) {
++ mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
++ }
++ if (!(cflag & PARENB)) {
++ mode_reg1 |= V_DUART_PARITY_MODE_NONE;
++ }
++ if (cflag & PARODD) {
++ mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
++ }
++
++ /* Formula for this is (5000000/baud)-1, but we saturate
++ at 12 bits, which means we can't actually do anything less
++ that 1200 baud */
++ switch (cflag & CBAUD) {
++ case B200:
++ case B300:
++ case B1200: clk_divisor = 4095; break;
++ case B1800: clk_divisor = 2776; break;
++ case B2400: clk_divisor = 2082; break;
++ case B4800: clk_divisor = 1040; break;
++ default:
++ case B9600: clk_divisor = 519; break;
++ case B19200: clk_divisor = 259; break;
++ case B38400: clk_divisor = 129; break;
++ case B57600: clk_divisor = 85; break;
++ case B115200: clk_divisor = 42; break;
++ }
++ WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
++ WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
++ WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
++ port->last_cflags = cflag;
++}
++
++
++/* Handle notification of a termios change. */
++static void duart_set_termios(struct tty_struct *tty, struct termios *old)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ pr_debug("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
++ if (old && tty->termios->c_cflag == old->c_cflag)
++ return;
++ duart_set_cflag(us->line, tty->termios->c_cflag);
++}
++
++static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
++
++ struct serial_struct tmp;
++
++ memset(&tmp, 0, sizeof(tmp));
++
++ tmp.type=PORT_SB1250;
++ tmp.line=us->line;
++ tmp.port=UNIT_CHANREG(tmp.line,0);
++ tmp.irq=UNIT_INT(tmp.line);
++ tmp.xmit_fifo_size=16; /* fixed by hw */
++ tmp.baud_base=5000000;
++ tmp.io_type=SERIAL_IO_MEM;
++
++ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
++ return -EFAULT;
++
++ return 0;
++}
++
++static int duart_ioctl(struct tty_struct *tty, struct file * file,
++ unsigned int cmd, unsigned long arg)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++/* if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
++ return -ENODEV;*/
++ switch (cmd) {
++ case TIOCMGET:
++ printk("Ignoring TIOCMGET\n");
++ break;
++ case TIOCMBIS:
++ printk("Ignoring TIOCMBIS\n");
++ break;
++ case TIOCMBIC:
++ printk("Ignoring TIOCMBIC\n");
++ break;
++ case TIOCMSET:
++ printk("Ignoring TIOCMSET\n");
++ break;
++ case TIOCGSERIAL:
++ return get_serial_info(us,(struct serial_struct *) arg);
++ case TIOCSSERIAL:
++ printk("Ignoring TIOCSSERIAL\n");
++ break;
++ case TIOCSERCONFIG:
++ printk("Ignoring TIOCSERCONFIG\n");
++ break;
++ case TIOCSERGETLSR: /* Get line status register */
++ printk("Ignoring TIOCSERGETLSR\n");
++ break;
++ case TIOCSERGSTRUCT:
++ printk("Ignoring TIOCSERGSTRUCT\n");
++ break;
++ case TIOCMIWAIT:
++ printk("Ignoring TIOCMIWAIT\n");
++ break;
++ case TIOCGICOUNT:
++ printk("Ignoring TIOCGICOUNT\n");
++ break;
++ case TIOCSERGWILD:
++ printk("Ignoring TIOCSERGWILD\n");
++ break;
++ case TIOCSERSWILD:
++ printk("Ignoring TIOCSERSWILD\n");
++ break;
++ default:
++ break;
++ }
++// printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm);
++ return -ENOIOCTLCMD;
++}
++
++/* XXXKW locking? */
++static void duart_start(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ pr_debug("duart_start called\n");
++
++ if (us->outp_count && !(us->flags & TX_INTEN)) {
++ us->flags |= TX_INTEN;
++ duart_unmask_ints(us->line, M_DUART_IMR_TX);
++ }
++}
++
++/* XXXKW locking? */
++static void duart_stop(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ pr_debug("duart_stop called\n");
++
++ if (us->outp_count && (us->flags & TX_INTEN)) {
++ us->flags &= ~TX_INTEN;
++ duart_mask_ints(us->line, M_DUART_IMR_TX);
++ }
++}
++
++/* Not sure on the semantics of this; are we supposed to wait until the stuff
++ already in the hardware FIFO drains, or are we supposed to wait until
++ we've drained the output buffer, too? I'm assuming the former, 'cause thats
++ what the other drivers seem to assume
++*/
++
++static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long orig_jiffies;
++
++ orig_jiffies = jiffies;
++ pr_debug("duart_wait_until_sent(%d)+\n", timeout);
++ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1);
++ if (signal_pending(current))
++ break;
++ if (timeout && time_after(jiffies, orig_jiffies + timeout))
++ break;
++ }
++ pr_debug("duart_wait_until_sent()-\n");
++}
++
++/*
++ * duart_hangup() --- called by tty_hangup() when a hangup is signaled.
++ */
++static void duart_hangup(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ duart_flush_buffer(tty);
++ us->open = 0;
++ us->tty = 0;
++}
++
++/*
++ * Open a tty line. Note that this can be called multiple times, so ->open can
++ * be >1. Only set up the tty struct if this is a "new" open, e.g. ->open was
++ * zero
++ */
++static int duart_open(struct tty_struct *tty, struct file *filp)
++{
++ uart_state_t *us;
++ unsigned int line = tty->index;
++ unsigned long flags;
++
++ if ((line >= tty->driver->num) || !sb1250_duart_present[line])
++ return -ENODEV;
++
++ pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
++ current->pid, current->comm, tty, tty->read_wait,
++ tty->write_wait);
++
++ us = uart_states + line;
++ tty->driver_data = us;
++
++ spin_lock_irqsave(&open_lock, flags);
++ if (!us->open) {
++ us->tty = tty;
++ us->tty->termios->c_cflag = us->last_cflags;
++ }
++ us->open++;
++ us->flags &= ~TX_INTEN;
++ duart_unmask_ints(line, M_DUART_IMR_RX);
++ spin_unlock_irqrestore(&open_lock, flags);
++
++ return 0;
++}
++
++
++/*
++ * Close a reference count out. If reference count hits zero, null the
++ * tty, kill the interrupts. The tty_io driver is responsible for making
++ * sure we've cleared out our internal buffers before calling close()
++ */
++static void duart_close(struct tty_struct *tty, struct file *filp)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long flags;
++
++ pr_debug("duart_close called by %i (%s)\n", current->pid, current->comm);
++
++ if (!us || !us->open)
++ return;
++
++ spin_lock_irqsave(&open_lock, flags);
++ if (tty_hung_up_p(filp)) {
++ spin_unlock_irqrestore(&open_lock, flags);
++ return;
++ }
++
++ if (--us->open < 0) {
++ us->open = 0;
++ printk(KERN_ERR "duart: bad open count: %d\n", us->open);
++ }
++ if (us->open) {
++ spin_unlock_irqrestore(&open_lock, flags);
++ return;
++ }
++
++ spin_unlock_irqrestore(&open_lock, flags);
++
++ tty->closing = 1;
++
++ /* Stop accepting input */
++ duart_mask_ints(us->line, M_DUART_IMR_RX);
++ /* Wait for FIFO to drain */
++ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
++ ;
++
++ if (tty->driver->flush_buffer)
++ tty->driver->flush_buffer(tty);
++ if (tty->ldisc.flush_buffer)
++ tty->ldisc.flush_buffer(tty);
++ tty->closing = 0;
++}
++
++
++static struct tty_operations duart_ops = {
++ .open = duart_open,
++ .close = duart_close,
++ .write = duart_write,
++ .put_char = duart_put_char,
++ .flush_chars = duart_flush_chars,
++ .write_room = duart_write_room,
++ .chars_in_buffer = duart_chars_in_buffer,
++ .flush_buffer = duart_flush_buffer,
++ .ioctl = duart_ioctl,
++// .throttle = duart_throttle,
++// .unthrottle = duart_unthrottle,
++ .set_termios = duart_set_termios,
++ .stop = duart_stop,
++ .start = duart_start,
++ .hangup = duart_hangup,
++ .wait_until_sent = duart_wait_until_sent,
++};
++
++/* Initialize the sb1250_duart_present array based on SOC type. */
++static void __init sb1250_duart_init_present_lines(void)
++{
++ int i, max_lines;
++
++ /* Set the number of available units based on the SOC type. */
++ switch (soc_type) {
++ case K_SYS_SOC_TYPE_BCM1x55:
++ case K_SYS_SOC_TYPE_BCM1x80:
++ max_lines = 4;
++ break;
++ default:
++ /* Assume at least two serial ports at the normal address. */
++ max_lines = 2;
++ break;
++ }
++ if (max_lines > DUART_MAX_LINE)
++ max_lines = DUART_MAX_LINE;
++
++ for (i = 0; i < max_lines; i++)
++ sb1250_duart_present[i] = 1;
++}
++
++/* Set up the driver and register it, register the UART interrupts. This
++ is called from tty_init, or as a part of the module init */
++static int __init sb1250_duart_init(void)
++{
++ int i;
++
++ sb1250_duart_init_present_lines();
++
++ sb1250_duart_driver = alloc_tty_driver(DUART_MAX_LINE);
++ if (!sb1250_duart_driver)
++ return -ENOMEM;
++
++ sb1250_duart_driver->owner = THIS_MODULE;
++ sb1250_duart_driver->name = "duart";
++ sb1250_duart_driver->major = TTY_MAJOR;
++ sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
++ sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL;
++ sb1250_duart_driver->subtype = SERIAL_TYPE_NORMAL;
++ sb1250_duart_driver->init_termios = tty_std_termios;
++ sb1250_duart_driver->flags = TTY_DRIVER_REAL_RAW;
++ tty_set_operations(sb1250_duart_driver, &duart_ops);
++
++ for (i=0; i<DUART_MAX_LINE; i++) {
++ uart_state_t *port = uart_states + i;
++
++ if (!sb1250_duart_present[i])
++ continue;
++
++ init_duart_port(port, i);
++ spin_lock_init(&port->outp_lock);
++ duart_mask_ints(i, M_DUART_IMR_ALL);
++ if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) {
++ panic("Couldn't get uart0 interrupt line");
++ }
++ __raw_writeq(M_DUART_RX_EN|M_DUART_TX_EN,
++ IOADDR(UNIT_CHANREG(i, R_DUART_CMD)));
++ duart_set_cflag(i, DEFAULT_CFLAGS);
++ }
++
++ /* Interrupts are now active, our ISR can be called. */
++
++ if (tty_register_driver(sb1250_duart_driver)) {
++ printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
++ put_tty_driver(sb1250_duart_driver);
++ return 1;
++ }
++ return 0;
++}
++
++/* Unload the driver. Unregister stuff, get ready to go away */
++static void __exit sb1250_duart_fini(void)
++{
++ unsigned long flags;
++ int i;
++
++ local_irq_save(flags);
++ tty_unregister_driver(sb1250_duart_driver);
++ put_tty_driver(sb1250_duart_driver);
++
++ for (i=0; i<DUART_MAX_LINE; i++) {
++ if (!sb1250_duart_present[i])
++ continue;
++ free_irq(UNIT_INT(i), &uart_states[i]);
++ disable_irq(UNIT_INT(i));
++ }
++ local_irq_restore(flags);
++}
++
++module_init(sb1250_duart_init);
++module_exit(sb1250_duart_fini);
++MODULE_DESCRIPTION("SB1250 Duart serial driver");
++MODULE_AUTHOR("Broadcom Corp.");
++
++#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
++
++/*
++ * Serial console stuff. Very basic, polling driver for doing serial
++ * console output. The console_sem is held by the caller, so we
++ * shouldn't be interrupted for more console activity.
++ * XXXKW What about getting interrupted by uart driver activity?
++ */
++
++void serial_outc(unsigned char c, int line)
++{
++ uart_state_t *port = uart_states + line;
++ while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
++ WRITE_SERCSR(c, port->tx_hold, line);
++ while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
++}
++
++static void ser_console_write(struct console *cons, const char *s,
++ unsigned int count)
++{
++ int line = cons->index;
++ uart_state_t *port = uart_states + line;
++ u32 imr;
++
++ imr = READ_SERCSR(port->imr, line);
++ WRITE_SERCSR(0, port->imr, line);
++ while (count--) {
++ if (*s == '\n')
++ serial_outc('\r', line);
++ serial_outc(*s++, line);
++ }
++ WRITE_SERCSR(imr, port->imr, line);
++}
++
++static struct tty_driver *ser_console_device(struct console *c, int *index)
++{
++ *index = c->index;
++ return sb1250_duart_driver;
++}
++
++static int ser_console_setup(struct console *cons, char *str)
++{
++ int i;
++
++ sb1250_duart_init_present_lines();
++
++ for (i=0; i<DUART_MAX_LINE; i++) {
++ uart_state_t *port = uart_states + i;
++
++ if (!sb1250_duart_present[i])
++ continue;
++
++ init_duart_port(port, i);
++#if SIBYTE_1956_WAR
++ last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
++#endif
++ WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
++ port->mode_1, i);
++ WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
++ port->mode_2, i);
++ WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
++ port->clk_sel, i);
++ WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
++ port->cmd, i);
++ }
++ return 0;
++}
++
++static struct console sb1250_ser_cons = {
++ .name = "duart",
++ .write = ser_console_write,
++ .device = ser_console_device,
++ .setup = ser_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++static int __init sb1250_serial_console_init(void)
++{
++ register_console(&sb1250_ser_cons);
++ return 0;
++}
++
++console_initcall(sb1250_serial_console_init);
++
++#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */
Added: people/maks-guest/linux-2.6/debian/patches/mips-sb1-eth-napi.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-sb1-eth-napi.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,379 @@
+Broadcom Sibyte SB1xxx NAPI ethernet support
+Status: submitted to linux-mips for review
+Dependency: mips-sb1-eth-1480.patch
+
+
+From: Tom Rix <trix at specifix.com>
+Subject: [PATCH] Broadcom Sibyte SB1xxx NAPI ethernet support
+Date: Thu, 09 Mar 2006 22:42:21 -0600
+To: Martin Michlmayr <tbm at cyrius.com>, linux-mips at linux-mips.org
+Cc: Mark E Mason <mark.e.mason at broadcom.com>
+
+This patch adds NAPI support for the Broadcom Sibyte SB1xxx family. The
+changes are limited to adding a new config key SBMAC_NAPI to the
+drivers/net/Kconfig and by adding the poll op and interrupt support to
+drivers/net/sb1250-mac.c.
+
+This patch also has a fix to drivers/net/sb1250-mac.c, the dma descriptor
+table ptr is allocated, aligned and the aligned ptr is freed. If the ptr
+was not already aligned (usually is) then the free would not work of what
+was returned by the kmalloc. A variable was added to store the unaligned
+pointer so that it could be properly freed.
+
+I have tested this patch on a BCM91250A-SWARM Pass 2 / An.
+
+Mark Mason from Broadcom was very helpful and tested this patch on at
+least a 1480.
+
+Tom
+
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index aa633fa..84ad238 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -456,6 +456,23 @@ config NET_SB1250_MAC
+ tristate "SB1250 Ethernet support"
+ depends on NET_ETHERNET && SIBYTE_SB1xxx_SOC
+
++config SBMAC_NAPI
++ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
++ depends on NET_SB1250_MAC && EXPERIMENTAL
++ help
++ NAPI is a new driver API designed to reduce CPU and interrupt load
++ when the driver is receiving lots of packets from the card. It is
++ still somewhat experimental and thus not yet enabled by default.
++
++ If your estimated Rx load is 10kpps or more, or if the card will be
++ deployed on potentially unfriendly networks (e.g. in a firewall),
++ then say Y here.
++
++ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
++ information.
++
++ If in doubt, say y.
++
+ config SGI_IOC3_ETH
+ bool "SGI IOC3 Ethernet"
+ depends on NET_ETHERNET && PCI && SGI_IP27
+diff -rup a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
+--- a/drivers/net/sb1250-mac.c 2006-03-09 04:25:41.000000000 -0600
++++ b/drivers/net/sb1250-mac.c 2006-03-09 05:30:52.000000000 -0600
+@@ -209,6 +209,7 @@ typedef struct sbmacdma_s {
+ * This stuff is for maintenance of the ring
+ */
+
++ sbdmadscr_t *sbdma_dscrtable_unaligned;
+ sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
+ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
+
+@@ -291,8 +292,8 @@ static int sbdma_add_rcvbuffer(sbmacdma_
+ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
+ static void sbdma_emptyring(sbmacdma_t *d);
+ static void sbdma_fillring(sbmacdma_t *d);
+-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
++static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
++static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
+ static int sbmac_initctx(struct sbmac_softc *s);
+ static void sbmac_channel_start(struct sbmac_softc *s);
+ static void sbmac_channel_stop(struct sbmac_softc *s);
+@@ -313,6 +314,10 @@ static struct net_device_stats *sbmac_ge
+ static void sbmac_set_rx_mode(struct net_device *dev);
+ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+ static int sbmac_close(struct net_device *dev);
++#if defined (CONFIG_SBMAC_NAPI)
++static int sbmac_poll(struct net_device *poll_dev, int *budget);
++#endif
++
+ static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+ static int sbmac_mii_probe(struct net_device *dev);
+
+@@ -740,7 +745,7 @@ static void sbdma_initctx(sbmacdma_t *d,
+
+ d->sbdma_maxdescr = maxdescr;
+
+- d->sbdma_dscrtable = (sbdmadscr_t *)
++ d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = (sbdmadscr_t *)
+ kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
+
+ /*
+@@ -782,7 +787,6 @@ static void sbdma_initctx(sbmacdma_t *d,
+ d->sbdma_int_timeout = 0;
+ }
+ #endif
+-
+ }
+
+ /**********************************************************************
+@@ -1150,13 +1154,14 @@ static void sbdma_fillring(sbmacdma_t *d
+ * nothing
+ ********************************************************************* */
+
+-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
++static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
+ {
+ int curidx;
+ int hwidx;
+ sbdmadscr_t *dsc;
+ struct sk_buff *sb;
+ int len;
++ int work_done = 0;
+
+ for (;;) {
+ /*
+@@ -1234,8 +1239,15 @@ static void sbdma_rx_process(struct sbma
+ sb->ip_summed = CHECKSUM_NONE;
+ }
+ }
+-
++
++#if defined(CONFIG_SBMAC_NAPI)
++ if (0 == poll)
++ netif_rx(sb);
++ else
++ netif_receive_skb(sb);
++#else
+ netif_rx(sb);
++#endif
+ }
+ } else {
+ /*
+@@ -1252,8 +1264,9 @@ static void sbdma_rx_process(struct sbma
+ */
+
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+-
++ work_done++;
+ }
++ return work_done;
+ }
+
+
+@@ -1275,15 +1288,22 @@ static void sbdma_rx_process(struct sbma
+ * nothing
+ ********************************************************************* */
+
+-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
++static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
+ {
+ int curidx;
+ int hwidx;
+ sbdmadscr_t *dsc;
+ struct sk_buff *sb;
+ unsigned long flags;
++ int packets_handled = 0;
+
+ spin_lock_irqsave(&(sc->sbm_lock), flags);
++
++ if (d->sbdma_remptr == d->sbdma_addptr)
++ goto end_unlock;
++
++ hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
++ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
+ for (;;) {
+ /*
+@@ -1298,15 +1318,12 @@ static void sbdma_tx_process(struct sbma
+ */
+
+ curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one that
+ * the hardware is working on right now.
+ */
+-
+ if (curidx == hwidx)
+ break;
+
+@@ -1337,6 +1354,7 @@ static void sbdma_tx_process(struct sbma
+
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+
++ packets_handled++;
+ }
+
+ /*
+@@ -1344,15 +1362,15 @@ static void sbdma_tx_process(struct sbma
+ * Other drivers seem to do this when we reach a low
+ * watermark on the transmit queue.
+ */
++
++ if (packets_handled)
++ netif_wake_queue(d->sbdma_eth->sbm_dev);
+
+- netif_wake_queue(d->sbdma_eth->sbm_dev);
+-
++ end_unlock:
+ spin_unlock_irqrestore(&(sc->sbm_lock), flags);
+
+ }
+
+-
+-
+ /**********************************************************************
+ * SBMAC_INITCTX(s)
+ *
+@@ -1396,7 +1414,6 @@ static int sbmac_initctx(struct sbmac_so
+ * Initialize the DMA channels. Right now, only one per MAC is used
+ * Note: Only do this _once_, as it allocates memory from the kernel!
+ */
+-
+ sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
+ sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
+
+@@ -1420,9 +1437,9 @@ static int sbmac_initctx(struct sbmac_so
+
+ static void sbdma_uninitctx(struct sbmacdma_s *d)
+ {
+- if (d->sbdma_dscrtable) {
+- kfree(d->sbdma_dscrtable);
+- d->sbdma_dscrtable = NULL;
++ if (d->sbdma_dscrtable_unaligned) {
++ kfree(d->sbdma_dscrtable_unaligned);
++ d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = NULL;
+ }
+
+ if (d->sbdma_ctxtable) {
+@@ -1609,12 +1626,12 @@ static void sbmac_channel_start(struct s
+
+ #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+ __raw_writeq(M_MAC_RXDMA_EN0 |
+- M_MAC_TXDMA_EN0, s->sbm_macenable);
++ M_MAC_TXDMA_EN0, s->sbm_macenable);
+ #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+ __raw_writeq(M_MAC_RXDMA_EN0 |
+- M_MAC_TXDMA_EN0 |
+- M_MAC_RX_ENABLE |
+- M_MAC_TX_ENABLE, s->sbm_macenable);
++ M_MAC_TXDMA_EN0 |
++ M_MAC_RX_ENABLE |
++ M_MAC_TX_ENABLE, s->sbm_macenable);
+ #else
+ #error invalid SiByte MAC configuation
+ #endif
+@@ -1624,15 +1641,15 @@ static void sbmac_channel_start(struct s
+ * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
+ */
+ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+- ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr);
++ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
++ s->sbm_imr);
+ #else
+ /*
+ * Accept any kind of interrupt on TX and RX DMA channel 0
+ */
+ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+- (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr);
++ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr);
+ #endif
+-
+ /*
+ * Enable receiving unicasts and broadcasts
+ */
+@@ -2067,7 +2084,6 @@ static irqreturn_t sbmac_intr(int irq,vo
+ * Read the ISR (this clears the bits in the real
+ * register, except for counter addr)
+ */
+-
+ isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
+
+ if (isr == 0)
+@@ -2079,13 +2095,31 @@ static irqreturn_t sbmac_intr(int irq,vo
+ * Transmits on channel 0
+ */
+
++#if defined(CONFIG_SBMAC_NAPI)
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+- sbdma_tx_process(sc,&(sc->sbm_txdma));
++ sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
+ }
+
+ /*
+ * Receives on channel 0
+ */
++ if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
++ if (netif_rx_schedule_prep(dev))
++ {
++ __raw_writeq(0, sc->sbm_imr);
++ __netif_rx_schedule(dev);
++ }
++ else
++ {
++ sbdma_rx_process(sc,&(sc->sbm_rxdma), 0);
++ }
++ }
++#else
++ /* Non NAPI */
++
++ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
++ sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
++ }
+
+ /*
+ * It's important to test all the bits (or at least the
+@@ -2105,8 +2139,9 @@ static irqreturn_t sbmac_intr(int irq,vo
+
+
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+- sbdma_rx_process(sc,&(sc->sbm_rxdma));
++ sbdma_rx_process(sc,&(sc->sbm_rxdma), 0);
+ }
++#endif
+ }
+ return IRQ_RETVAL(handled);
+ }
+@@ -2405,7 +2440,10 @@ static int sbmac_init(struct net_device
+ dev->do_ioctl = sbmac_mii_ioctl;
+ dev->tx_timeout = sbmac_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+-
++#if defined(CONFIG_SBMAC_NAPI)
++ dev->poll = sbmac_poll;
++ dev->weight = 16;
++#endif
+ dev->change_mtu = sb1250_change_mtu;
+
+ /* This is needed for PASS2 for Rx H/W checksum feature */
+@@ -2818,7 +2856,37 @@ static int sbmac_close(struct net_device
+ return 0;
+ }
+
++#if defined(CONFIG_SBMAC_NAPI)
++static int sbmac_poll(struct net_device *dev, int *budget)
++{
++ int work_to_do;
++ int work_done;
++ struct sbmac_softc *sc = netdev_priv(dev);
++
++ work_to_do = min(*budget, dev->quota);
++ work_done = sbdma_rx_process(sc,&(sc->sbm_rxdma), 1);
+
++ sbdma_tx_process(sc,&(sc->sbm_txdma), 1);
++
++ *budget -= work_done;
++ dev->quota -= work_done;
++
++ if (work_done < work_to_do) {
++ netif_rx_complete(dev);
++
++#ifdef CONFIG_SBMAC_COALESCE
++ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
++ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
++ sc->sbm_imr);
++#else
++ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
++ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
++#endif
++ }
++
++ return (work_done >= work_to_do);
++}
++#endif
+
+ #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
+ static void
Added: people/maks-guest/linux-2.6/debian/patches/mips-tulip.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-tulip.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,135 @@
+## DP: Tulip - fixes compile on MIPS64.
+## DP: Path author: Grant Grundler <grundler at parisc-linux.org>
+## DP: Basically got rejected as it by Jeff Garzik but needed for now.
+## DP: Has been used by the HPPA folks for years
+
+From: Jim Gifford <maillist at jg555.com>
+
+I have been working on getting the RaQ2 to build using 64 bit. I ran
+into numerous issues. After I got the kernel to compile, the tulip
+driver didn't work. It kept showing error messages like
+tulip_stop_rxtx() failed
+
+This patch fixes the compile issue, this patch was create by Grant
+Grundler of linux-parsic. This patch matches the tulip driver follow the
+specs laid out by the manufacture. On 32 bit this patch seemed to make
+the tulip more responsive on my RaQ2 systems.
+
+diff -urN linux-mips/drivers/net/tulip/de2104x.c new/drivers/net/tulip/de2104x.c
+--- linux-mips/drivers/net/tulip/de2104x.c 2006-01-10 11:21:43.000000000 +0000
++++ new/drivers/net/tulip/de2104x.c 2006-01-16 16:54:50.000000000 +0000
+@@ -1932,7 +1927,7 @@
+ goto fill_defaults;
+ }
+
+-static int __init de_init_one (struct pci_dev *pdev,
++static int __devinit de_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
+ struct net_device *dev;
+diff -urN linux-mips/drivers/net/tulip/de4x5.c new/drivers/net/tulip/de4x5.c
+--- linux-mips/drivers/net/tulip/de4x5.c 2006-01-10 11:21:43.000000000 +0000
++++ new/drivers/net/tulip/de4x5.c 2006-01-16 16:54:50.000000000 +0000
+@@ -2124,7 +2124,6 @@
+ .remove = __devexit_p (de4x5_eisa_remove),
+ }
+ };
+-MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
+ #endif
+
+ #ifdef CONFIG_PCI
+diff -urN linux-mips/drivers/net/tulip/media.c new/drivers/net/tulip/media.c
+--- linux-mips/drivers/net/tulip/media.c 2006-01-10 11:21:43.000000000 +0000
++++ new/drivers/net/tulip/media.c 2006-01-16 16:54:50.000000000 +0000
+@@ -44,8 +44,10 @@
+
+ /* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+- MDIO protocol. See the MII specifications or DP83840A data sheet
+- for details. */
++ MDIO protocol.
++ See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
++ or DP83840A data sheet for more details.
++ */
+
+ int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
+ {
+@@ -272,13 +274,29 @@
+ int reset_length = p[2 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (startup) {
++ int timeout = 10; /* max 1 ms */
+ iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ for (i = 0; i < reset_length; i++)
+ iowrite32(reset_sequence[i], ioaddr + CSR12);
++
++ /* flush posted writes */
++ ioread32(ioaddr + CSR12);
++
++ /* Sect 3.10.3 in DP83840A.pdf (p39) */
++ udelay(500);
++
++ /* Section 4.2 in DP83840A.pdf (p43) */
++ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
++ while (timeout-- &&
++ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
++ udelay(100);
+ }
+ for (i = 0; i < init_length; i++)
+ iowrite32(init_sequence[i], ioaddr + CSR12);
++
++ ioread32(ioaddr + CSR12); /* flush posted writes */
+ }
++
+ tmp_info = get_u16(&misc_info[1]);
+ if (tmp_info)
+ tp->advertising[phy_num] = tmp_info | 1;
+@@ -365,8 +383,6 @@
+
+ tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+
+- mdelay(1);
+-
+ return;
+ }
+
+diff -urN linux-mips/drivers/net/tulip/tulip.h new/drivers/net/tulip/tulip.h
+--- linux-mips/drivers/net/tulip/tulip.h 2006-01-10 11:21:43.000000000 +0000
++++ new/drivers/net/tulip/tulip.h 2006-01-16 16:54:50.000000000 +0000
+@@ -474,8 +474,11 @@
+ udelay(10);
+
+ if (!i)
+- printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
+- pci_name(tp->pdev));
++ printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed"
++ " (CSR5 0x%x CSR6 0x%x)\n",
++ pci_name(tp->pdev),
++ ioread32(ioaddr + CSR5),
++ ioread32(ioaddr + CSR6));
+ }
+ }
+
+diff -urN linux-mips/drivers/net/tulip/tulip_core.c new/drivers/net/tulip/tulip_core.c
+--- linux-mips/drivers/net/tulip/tulip_core.c 2006-01-10 11:21:43.000000000 +0000
++++ new/drivers/net/tulip/tulip_core.c 2006-01-16 16:54:50.000000000 +0000
+@@ -22,7 +22,7 @@
+ #else
+ #define DRV_VERSION "1.1.13"
+ #endif
+-#define DRV_RELDATE "May 11, 2002"
++#define DRV_RELDATE "December 15, 2004"
+
+
+ #include <linux/module.h>
+@@ -1505,8 +1505,8 @@
+ (PCI_SLOT(pdev->devfn) == 12))) {
+ /* Cobalt MAC address in first EEPROM locations. */
+ sa_offset = 0;
+- /* Ensure our media table fixup get's applied */
+- memcpy(ee_data + 16, ee_data, 8);
++ /* No media table either */
++ tp->flags &= ~HAS_MEDIA_TABLE;
+ }
+ #endif
+ #ifdef CONFIG_GSC
Added: people/maks-guest/linux-2.6/debian/patches/mips-tulip_dc21143.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/mips-tulip_dc21143.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,86 @@
+## DP: TULIP_MWI fix for Cobalt
+## DP: Patch author: Peter Horton <pdh at colonel-panic.org>
+## DP: Upstream status: submitted to netdev
+
+This patch works around the MWI bug on the DC21143 rev 65 Tulip by ensuring
+that the receive buffers don't end on a cache line boundary (as documented
+in the errata).
+
+This patch is required for the MIPs based Cobalt Qube/RaQ as supporting the
+extra PCI commands seems to reduce the chance of a hard lockup between the
+Tulip and the PCI bridge.
+
+--- linux.git.orig/drivers/net/tulip/tulip_core.c 2006-01-29 21:43:40.000000000 +0000
++++ linux.git/drivers/net/tulip/tulip_core.c 2006-01-29 21:56:50.000000000 +0000
+@@ -294,6 +294,8 @@
+ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
+ iowrite32(0x00040000, ioaddr + CSR6);
+
++ printk(KERN_DEBUG "%s: CSR0 %08x\n", dev->name, tp->csr0);
++
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ iowrite32(0x00000001, ioaddr + CSR0);
+ udelay(100);
+@@ -1155,8 +1157,10 @@
+ /* if we have any cache line size at all, we can do MRM */
+ csr0 |= MRM;
+
++#ifndef CONFIG_TULIP_MWI_DC21143
+ /* ...and barring hardware bugs, MWI */
+ if (!(tp->chip_id == DC21143 && tp->revision == 65))
++#endif
+ csr0 |= MWI;
+
+ /* set or disable MWI in the standard PCI command bit.
+@@ -1182,7 +1186,7 @@
+ */
+ switch (cache) {
+ case 8:
+- csr0 |= MRL | (1 << CALShift) | (16 << BurstLenShift);
++ csr0 |= MRL | (1 << CALShift) | (8 << BurstLenShift);
+ break;
+ case 16:
+ csr0 |= MRL | (2 << CALShift) | (16 << BurstLenShift);
+Index: linux.git/drivers/net/tulip/tulip.h
+===================================================================
+--- linux.git.orig/drivers/net/tulip/tulip.h 2006-01-29 21:43:40.000000000 +0000
++++ linux.git/drivers/net/tulip/tulip.h 2006-01-29 21:52:01.000000000 +0000
+@@ -262,7 +262,15 @@
+ #define RX_RING_SIZE 128
+ #define MEDIA_MASK 31
+
+-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
++/* MWI can fail on 21143 rev 65 if the receive buffer ends
++ on a cache line boundary. Ensure it doesn't ...
++*/
++
++#ifdef CONFIG_TULIP_MWI_DC21143
++#define PKT_BUF_SZ (1536 + 4) /* Size of each temporary Rx buffer. */
++#else
++#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
++#endif
+
+ #define TULIP_MIN_CACHE_LINE 8 /* in units of 32-bit words */
+
+Index: linux.git/drivers/net/tulip/Kconfig
+===================================================================
+--- linux.git.orig/drivers/net/tulip/Kconfig 2006-01-29 21:48:09.000000000 +0000
++++ linux.git/drivers/net/tulip/Kconfig 2006-01-29 21:50:28.000000000 +0000
+@@ -57,6 +57,16 @@
+
+ If unsure, say N.
+
++config TULIP_MWI_DC21143
++ bool "Enable MWI workaround on dc21143 controllers"
++ depends on TULIP_MWI
++ help
++ This enables a workaround for MWI ("New bus configuration") on DC21143
++ controllers. Normally MWI is disabled on these chips because of
++ hardware errata.
++
++ If unsure, say N.
++
+ config TULIP_MMIO
+ bool "Use PCI shared mem for NIC registers"
+ depends on TULIP
+
Added: people/maks-guest/linux-2.6/debian/patches/modular-ide-pnp.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/modular-ide-pnp.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,74 @@
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Allow modular built of ide-pnp
+## DP: Patch author: Herbert Xu, Christoph Hellwig
+## DP: Upstream status: submitted
+#
+diff -aurN a/drivers/ide/Kconfig b/drivers/ide/Kconfig
+--- a/drivers/ide/Kconfig 2005-06-06 11:22:29.000000000 -0400
++++ b/drivers/ide/Kconfig 2005-06-15 22:15:06.000000000 -0400
+@@ -315,7 +315,7 @@
+ Otherwise say N.
+
+ config BLK_DEV_IDEPNP
+- bool "PNP EIDE support"
++ tristate "PNP EIDE support"
+ depends on PNP
+ help
+ If you have a PnP (Plug and Play) compatible EIDE card and
+diff -aurN a/drivers/ide/Makefile b/drivers/ide/Makefile
+--- a/drivers/ide/Makefile 2005-06-06 11:22:29.000000000 -0400
++++ b/drivers/ide/Makefile 2005-06-15 22:15:06.000000000 -0400
+@@ -23,6 +23,5 @@
+ ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
+ ide-core-$(CONFIG_PROC_FS) += ide-proc.o
+-ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+
+ # built-in only drivers from arm/
+ ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
+@@ -43,6 +42,7 @@
+
+ obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o
+ obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
++obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+
+ obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o
+ obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o
+diff -aurN a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
+--- a/drivers/ide/ide-pnp.c 2005-06-06 11:22:29.000000000 -0400
++++ b/drivers/ide/ide-pnp.c 2005-06-15 22:15:06.000000000 -0400
+@@ -69,7 +69,21 @@
+ .remove = idepnp_remove,
+ };
+
+-void __init pnpide_init(void)
++int __init pnpide_init(void)
+ {
+- pnp_register_driver(&idepnp_driver);
++ return pnp_register_driver(&idepnp_driver);
+ }
++
++#ifdef MODULE
++static void __exit pnpide_exit(void)
++{
++ pnp_unregister_driver(&idepnp_driver);
++}
++
++module_init(pnpide_init);
++module_exit(pnpide_exit);
++#endif
++
++MODULE_AUTHOR("Andrey Panin");
++MODULE_DESCRIPTION("Enabler for ISAPNP IDE devices");
++MODULE_LICENSE("GPL");
+diff -aurN a/drivers/ide/ide.c b/drivers/ide/ide.c
+--- a/drivers/ide/ide.c 2005-06-06 11:22:29.000000000 -0400
++++ b/drivers/ide/ide.c 2005-06-15 22:15:06.000000000 -0400
+@@ -1789,7 +1789,7 @@
+ return 1;
+ }
+
+-extern void pnpide_init(void);
++extern int pnpide_init(void);
+ extern void h8300_ide_init(void);
+
+ /*
Added: people/maks-guest/linux-2.6/debian/patches/series/1
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/series/1 Sat Nov 11 02:48:00 2006
@@ -0,0 +1,62 @@
++ 2.6.19-rc5
++ debian/version.patch
++ debian/kernelvariables.patch
++ debian/doc-build-parallel.patch
++ debian/scripts-kconfig-reportoldconfig.patch
+#+ debian/powerpc-mkvmlinuz-support-ppc.patch
+#+ debian/powerpc-mkvmlinuz-support-powerpc.patch
+
++ modular-ide-pnp.patch
++ fbdev-radeon-noaccel.patch
++ ia64-irq-affinity-upfix.patch
++ bugfix/powerpc/build-links.patch
++ bugfix/powerpc/prep-utah-ide-interrupt.patch
++ bugfix/powerpc/mv643xx-hotplug-support.patch
++ sparc64-hme-lockup.patch
++ sparc64-atyfb-xl-gr.patch
++ mips-arch-makefile.patch
++ mips-ide-scan.patch
++ mips-sb1-eth-napi.patch
+#+ mips-sb1-duart.patch
+#+ mips-sb1-duart-tts.patch
++ video-vino-64-bit-fix-kernel.diff
+#+ features/s390/drivers-ccw-uevent-modalias.patch
+#+ features/s390/drivers-ccw-uevent-cleanup.patch
+#+ arm-iop-generic-backport.patch
+#+ arm-iop-mtd-maps.patch
+#+ arm-get_unaligned-gcc41-const.patch
++ bugfix/powerpc/serial.patch
++ bugfix/powerpc/oldworld-boot-fix.patch
+#+ features/all/fs-asfs.patch
++ bugfix/fdomain-pci-id-table.patch
++ alpha-prctl.patch
+- sparc64-atyfb-xl-gr.patch
+#+ bugfix/arm/n2100-serial-irq.patch
+#+ bugfix/arm/n2100-eth1-irq.patch
++ bugfix/net-netpoll.patch
++ features/net-forcedeth-swsusp.patch
+#+ bugfix/arm/arm-generic-time.patch
++ features/arm/nslu2-setup-mac.patch
++ features/arm/nslu2-eth-mac.patch
++ features/arm/ixp4xx-0.2.1-driver.patch
++ features/arm/ixp4xx-net-driver-fix-qmgr.patch
++ features/arm/ixp4xx-net-driver-improve-mac-handling.patch
+#+ bugfix/copy-user-highpage.patch
+#- mips-sb1-duart-tts.patch
+#+ bugfix/mips/syscall-wiring.patch
+#+ bugfix/mips/sb1-flush-cache-data-page.patch
+#+ bugfix/mips/smp-cpu-bringup.patch
+#+ bugfix/mips/header-exports.patch
+#+ bugfix/mips/sb1-interrupt-handler.patch
++ bugfix/mips/ip22-zilog-console.patch
+#+ bugfix/mips/signal-handling.patch
+#+ bugfix/mips/sb1-duart-tts.patch
+#+ bugfix/mips/wait-race.patch
+#+ bugfix/mips/sgi-ioc3.patch
++ features/mips/qemu-kernel.patch
+#+ features/mips/backtrace.patch
++ features/fintek-f75375.patch
+#+ bugfix/arm/iop3xx-mtd-map-fix.patch
++ bugfix/copy-user-highpage-2.patch
++ bugfix/alpha/asm-subarchs.patch
+#+ features/alpha/titan-video.patch
Added: people/maks-guest/linux-2.6/debian/patches/series/1-extra
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/series/1-extra Sat Nov 11 02:48:00 2006
@@ -0,0 +1,17 @@
+#+ debian/vserver-version.patch *_vserver *_xen-vserver
+#+ mips-tulip.patch mipsel
++ mips-tulip_dc21143.patch mipsel
+#+ hppa.patch hppa
+#+ m68k-2.6.18.patch m68k
++ m68k-as.patch m68k
++ m68k-macro.patch m68k
+#+ m68k-no-backlight.patch m68k
+#+ m68k-fbcon.patch m68k
++ hppa-fix-cross-compile.patch hppa
++ bugfix/mips/dec-scsi.patch mipsel
+#+ bugfix/mips/dec-serial.patch mipsel
+#+ features/all/vserver/vs2.0.2.2-rc6.patch *_vserver *_xen-vserver
+#+ features/all/vserver/bindmount-dev.patch *_vserver *_xen-vserver
+#+ features/all/xen/vserver-clash.patch *_xen-vserver
+#+ features/all/xen/fedora-36252.patch *_xen *_xen-vserver
+#+ features/all/xen/vserver-update.patch *_xen-vserver
Added: people/maks-guest/linux-2.6/debian/patches/sparc64-atyfb-xl-gr.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/sparc64-atyfb-xl-gr.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+--- a/drivers/video/aty/atyfb_base.c 2006-02-03 05:23:59.000000000 -0800
++++ b/drivers/video/aty/atyfb_base.c 2006-02-09 21:25:53.163445232 -0800
+@@ -415,7 +415,7 @@
+ { PCI_CHIP_MACH64GN, "3D RAGE XC (Mach64 GN, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GL, "3D RAGE XC (Mach64 GL, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL },
+- { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL },
++ { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33)", 235, 83, 63, 135, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL },
+ { PCI_CHIP_MACH64GS, "3D RAGE XC (Mach64 GS, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL },
+
+ { PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },
Added: people/maks-guest/linux-2.6/debian/patches/sparc64-hme-lockup.patch
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/sparc64-hme-lockup.patch Sat Nov 11 02:48:00 2006
@@ -0,0 +1,16 @@
+# origin: Debian (bcollins)
+# cset: n/a
+# inclusion: not suitable for upstream
+# revision date: 2004-10-08
+
+diff -aurN a/drivers/net/sunhme.c b/drivers/net/sunhme.c
+--- a/drivers/net/sunhme.c 2005-06-17 15:48:29.000000000 -0400
++++ b/drivers/net/sunhme.c 2005-06-18 12:12:18.000000000 -0400
+@@ -1996,6 +1996,7 @@
+ }
+ hp->tx_old = elem;
+ TXD((">"));
++ udelay(1);
+
+ if (netif_queue_stopped(dev) &&
+ TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))
Added: people/maks-guest/linux-2.6/debian/patches/video-vino-64-bit-fix-kernel.diff
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/patches/video-vino-64-bit-fix-kernel.diff Sat Nov 11 02:48:00 2006
@@ -0,0 +1,256 @@
+Upstream status: will go into 2.6.17
+
+
+Fix VINO drivers when using a 64-bit kernel
+
+This patch should fix problems with VINO drivers when using a 64-bit
+kernel.
+
+There are also other bugs which prevent V4L drivers from functioning
+correctly when using 32-bit userland with a 64-bit kernel as the ioctl
+compatibility layer (in drivers/media/video/compat_ioctl32.c) doesn't seem
+to handle VIDIOC_CROPCAP. I'm not sure if any other ioctls are missing.
+
+
+diff -urN a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
+--- a/drivers/media/video/indycam.c 2006-03-17 14:04:42.000000000 +0200
++++ b/drivers/media/video/indycam.c 2006-03-17 14:04:55.000000000 +0200
+@@ -2,7 +2,7 @@
+ * indycam.c - Silicon Graphics IndyCam digital camera driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis at linux-mips.org>
+- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia at cc.hut.fi>
++ * Copyright (C) 2004,2005,2006 Mikael Nousiainen <tmnousia at cc.hut.fi>
+ *
+ * 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
+@@ -27,7 +27,7 @@
+
+ #include "indycam.h"
+
+-#define INDYCAM_MODULE_VERSION "0.0.5"
++#define INDYCAM_MODULE_VERSION "0.0.6"
+
+ MODULE_DESCRIPTION("SGI IndyCam driver");
+ MODULE_VERSION(INDYCAM_MODULE_VERSION);
+diff -urN a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
+--- a/drivers/media/video/saa7191.c 2006-03-17 14:04:42.000000000 +0200
++++ b/drivers/media/video/saa7191.c 2006-03-17 14:04:55.000000000 +0200
+@@ -2,7 +2,7 @@
+ * saa7191.c - Philips SAA7191 video decoder driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis at linux-mips.org>
+- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia at cc.hut.fi>
++ * Copyright (C) 2004,2005,2006 Mikael Nousiainen <tmnousia at cc.hut.fi>
+ *
+ * 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
+@@ -26,7 +26,7 @@
+
+ #include "saa7191.h"
+
+-#define SAA7191_MODULE_VERSION "0.0.5"
++#define SAA7191_MODULE_VERSION "0.0.6"
+
+ MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
+ MODULE_VERSION(SAA7191_MODULE_VERSION);
+diff -urN a/drivers/media/video/vino.c b/drivers/media/video/vino.c
+--- a/drivers/media/video/vino.c 2006-03-17 14:04:42.000000000 +0200
++++ b/drivers/media/video/vino.c 2006-03-17 14:04:55.000000000 +0200
+@@ -4,7 +4,7 @@
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia at cc.hut.fi>
++ * Copyright (C) 2004,2005,2006 Mikael Nousiainen <tmnousia at cc.hut.fi>
+ *
+ * Based on the previous version of the driver for 2.4 kernels by:
+ * Copyright (C) 2003 Ladislav Michl <ladis at linux-mips.org>
+@@ -58,8 +58,8 @@
+ // #define VINO_DEBUG
+ // #define VINO_DEBUG_INT
+
+-#define VINO_MODULE_VERSION "0.0.5"
+-#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 5)
++#define VINO_MODULE_VERSION "0.0.6"
++#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 6)
+
+ MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
+ MODULE_VERSION(VINO_MODULE_VERSION);
+@@ -150,6 +150,9 @@
+
+ /* Internal data structure definitions */
+
++/* DMA addresses in VINO descriptor table are always 32-bit */
++typedef u32 vino_dma_addr_t;
++
+ struct vino_input {
+ char *name;
+ v4l2_std_id std;
+@@ -190,7 +193,7 @@
+
+ /* cpu address for the VINO descriptor table
+ * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+- unsigned long *dma_cpu;
++ vino_dma_addr_t *dma_cpu;
+ /* dma address for the VINO descriptor table
+ * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+ dma_addr_t dma;
+@@ -817,7 +820,7 @@
+
+ dma_free_coherent(NULL,
+ VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *
+- sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,
++ sizeof(vino_dma_addr_t), (void *)fb->desc_table.dma_cpu,
+ fb->desc_table.dma);
+ kfree(fb->desc_table.virtual);
+
+@@ -857,7 +860,7 @@
+ * (has space for four extra descriptors) */
+ fb->desc_table.dma_cpu =
+ dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+- sizeof(dma_addr_t), &fb->desc_table.dma,
++ sizeof(vino_dma_addr_t), &fb->desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.dma_cpu) {
+ ret = -ENOMEM;
+@@ -913,93 +916,6 @@
+ return ret;
+ }
+
+-#if 0
+-/* user buffers not fully implemented yet */
+-static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
+- void *user,
+- unsigned int size)
+-{
+- unsigned int count, i, j;
+- int ret = 0;
+-
+- dprintk("vino_prepare_user_buffer():\n");
+-
+- if (size < 1)
+- return -EINVAL;
+-
+- memset(fb, 0, sizeof(struct vino_framebuffer));
+-
+- count = ((size / PAGE_SIZE)) & ~3;
+-
+- dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",
+- size, count);
+-
+- /* allocate memory for table with virtual (page) addresses */
+- fb->desc_table.virtual = (unsigned long *)
+- kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+- if (!fb->desc_table.virtual)
+- return -ENOMEM;
+-
+- /* allocate memory for table with dma addresses
+- * (has space for four extra descriptors) */
+- fb->desc_table.dma_cpu =
+- dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+- sizeof(dma_addr_t), &fb->desc_table.dma,
+- GFP_KERNEL | GFP_DMA);
+- if (!fb->desc_table.dma_cpu) {
+- ret = -ENOMEM;
+- goto out_free_virtual;
+- }
+-
+- /* allocate pages for the buffer and acquire the according
+- * dma addresses */
+- for (i = 0; i < count; i++) {
+- dma_addr_t dma_data_addr;
+-
+- fb->desc_table.virtual[i] =
+- get_zeroed_page(GFP_KERNEL | GFP_DMA);
+- if (!fb->desc_table.virtual[i]) {
+- ret = -ENOBUFS;
+- break;
+- }
+-
+- dma_data_addr =
+- dma_map_single(NULL,
+- (void *)fb->desc_table.virtual[i],
+- PAGE_SIZE, DMA_FROM_DEVICE);
+-
+- for (j = 0; j < VINO_PAGE_RATIO; j++) {
+- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+- dma_data_addr + VINO_PAGE_SIZE * j;
+- }
+-
+- SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+- }
+-
+- /* page_count needs to be set anyway, because the descriptor table has
+- * been allocated according to this number */
+- fb->desc_table.page_count = count;
+-
+- if (ret) {
+- /* the descriptor with index i doesn't contain
+- * a valid address yet */
+- vino_free_buffer_with_count(fb, i);
+- return ret;
+- }
+-
+- //fb->size = size;
+- fb->size = count * PAGE_SIZE;
+-
+- /* set the dma stop-bit for the last (count+1)th descriptor */
+- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+- return 0;
+-
+- out_free_virtual:
+- kfree(fb->desc_table.virtual);
+- return ret;
+-}
+-#endif
+-
+ static void vino_sync_buffer(struct vino_framebuffer *fb)
+ {
+ int i;
+@@ -4394,6 +4310,7 @@
+ .open = vino_open,
+ .release = vino_close,
+ .ioctl = vino_ioctl,
++ .compat_ioctl = v4l_compat_ioctl32,
+ .mmap = vino_mmap,
+ .poll = vino_poll,
+ .llseek = no_llseek,
+@@ -4436,8 +4353,8 @@
+ dma_unmap_single(NULL,
+ vino_drvdata->dummy_desc_table.dma_cpu[0],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+- dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT
+- * sizeof(dma_addr_t),
++ dma_free_coherent(NULL, vino_drvdata->dummy_desc_table.page_count
++ * sizeof(vino_dma_addr_t),
+ (void *)vino_drvdata->
+ dummy_desc_table.dma_cpu,
+ vino_drvdata->dummy_desc_table.dma);
+@@ -4514,11 +4431,13 @@
+ }
+ vino_init_stage++;
+
+- // TODO: use page_count in dummy_desc_table
++ vino_drvdata->dummy_desc_table.page_count =
++ VINO_DUMMY_DESC_COUNT;
+
+ vino_drvdata->dummy_desc_table.dma_cpu =
+ dma_alloc_coherent(NULL,
+- VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t),
++ vino_drvdata->dummy_desc_table.page_count *
++ sizeof(vino_dma_addr_t),
+ &vino_drvdata->dummy_desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!vino_drvdata->dummy_desc_table.dma_cpu) {
+@@ -4529,8 +4448,8 @@
+
+ dma_dummy_address = dma_map_single(NULL,
+ (void *)vino_drvdata->dummy_page,
+- PAGE_SIZE, DMA_FROM_DEVICE);
+- for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) {
++ PAGE_SIZE, DMA_FROM_DEVICE);
++ for (i = 0; i < vino_drvdata->dummy_desc_table.page_count; i++) {
+ vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address;
+ }
+
Added: people/maks-guest/linux-2.6/debian/rules
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/rules Sat Nov 11 02:48:00 2006
@@ -0,0 +1,118 @@
+#!/usr/bin/make -f
+#
+# Generally nothing needs to be modified below this line
+#
+SHELL := sh -e
+DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_BUILD_ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH)
+srcver := $(shell dpkg-parsechangelog | awk '/^Version:/ {print $$2}')
+VERSION := $(shell echo $(srcver) | sed -e 's,-[^-]*$$,,')
+MAJOR := $(word 1,$(subst ., ,$(VERSION))).$(word 2,$(subst ., ,$(VERSION)))
+
+include debian/rules.defs
+
+source: debian/control $(STAMPS_DIR)/source-base
+$(STAMPS_DIR)/source-base: $(BUILD_DIR) $(STAMPS_DIR)
+ dh_testdir
+ $(MAKE) -f debian/rules.gen source-$(DEB_HOST_ARCH)
+ touch $@
+
+source-all: debian/control $(BUILD_DIR) $(STAMPS_DIR)
+ dh_testdir
+ $(MAKE) -f debian/rules.gen source
+
+setup: debian/control $(STAMPS_DIR)/setup-base
+$(STAMPS_DIR)/setup-base: $(STAMPS_DIR)/source-base
+ dh_testdir
+ $(MAKE) -f debian/rules.gen setup-$(DEB_HOST_ARCH)
+ touch $@
+
+build: debian/control $(STAMPS_DIR)/build-base
+$(STAMPS_DIR)/build-base: $(STAMPS_DIR)/setup-base
+ dh_testdir
+ $(MAKE) -f debian/rules.gen build-$(DEB_HOST_ARCH)
+ touch $@
+
+$(BUILD_DIR) $(STAMPS_DIR):
+ @[ -d $@ ] || mkdir $@
+
+DIR_ORIG = ../orig/linux-$(MAJOR)-$(VERSION)
+TAR_ORIG = ../linux-$(MAJOR)_$(VERSION).orig.tar.gz
+
+orig: $(DIR_ORIG)
+ rsync --delete --exclude debian --exclude .svn --link-dest=$(DIR_ORIG)/ -a $(DIR_ORIG)/ .
+
+$(DIR_ORIG):
+ if [ -f $(TAR_ORIG) ]; then \
+ mkdir -p ../orig; \
+ tar -C ../orig -xzf $(TAR_ORIG); \
+ else \
+ echo "Can't find orig tarball." >&2; \
+ exit 1; \
+ fi
+
+maintainerclean:
+ rm -f debian/control debian/control.md5sum debian/rules.gen debian/bin/patch.* debian/linux-*
+ rm -rf $(filter-out debian .svn, $(wildcard * .[^.]*))
+
+clean: debian/control
+ dh_testdir
+ rm -rf $(BUILD_DIR) $(STAMPS_DIR) debian/lib/python/debian_linux/*.pyc
+ dh_clean
+
+binary-indep: $(STAMPS_DIR)/source-base
+ dh_testdir
+ $(MAKE) -f debian/rules.gen binary-indep
+
+binary-arch: $(STAMPS_DIR)/build-base
+ dh_testdir
+ $(MAKE) -f debian/rules.gen binary-arch-$(DEB_HOST_ARCH)
+
+binary: binary-indep binary-arch
+
+#
+# Makes the master debian/control file by substituting
+# variable values into the template.
+#
+CONTROL_FILES = debian/changelog $(wildcard debian/templates/control.*)
+CONTROL_FILES += debian/arch/defines $(wildcard debian/arch/*/defines) $(wildcard debian/arch/*/*/defines)
+debian/control debian/rules.gen: debian/bin/gencontrol.py $(CONTROL_FILES)
+ if [ -f debian/control.md5sum ]; then \
+ if md5sum $^ | diff - debian/control.md5sum > /dev/null; then true; else \
+ $(MAKE) -f debian/rules debian/control-real; \
+ fi \
+ else \
+ $(MAKE) -f debian/rules debian/control-real; \
+ fi
+
+debian/control-real: debian/bin/gencontrol.py $(CONTROL_FILES)
+ chmod +x $<
+ $<
+ md5sum $^ > debian/control.md5sum
+ @echo
+ @echo This target is made to fail intentionally, to make sure
+ @echo that it is NEVER run during the automated build. Please
+ @echo ignore the following error, the debian/control file has
+ @echo been generated SUCCESSFULLY.
+ @echo
+ exit 1
+
+#
+# Rule to check all configs snipplets in debian/arch
+#
+
+CheckConfs_DIR := $(BUILD_DIR)/check
+
+$(CheckConfs_DIR) source-configs: debian/control $(BUILD_DIR) $(STAMPS_DIR)
+ $(MAKE) -f debian/rules.gen setup-$(DEB_HOST_ARCH)-real
+ rm -rf '$(CheckConfs_DIR)'
+ cp -al $(BUILD_DIR)/source $(CheckConfs_DIR)
+
+check-configs: $(CheckConfs_DIR)
+ @echo "Checking all configuration files"
+ ocaml debian/bin/kconfig.ml -c -b "debian/arch"
+
+clean-configs:
+ rm -rf '$(CheckConfs_DIR)'
+
+.PHONY: clean build setup binary-indep binary-arch binary
Added: people/maks-guest/linux-2.6/debian/rules.defs
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/rules.defs Sat Nov 11 02:48:00 2006
@@ -0,0 +1,4 @@
+BUILD_DIR = debian/build
+STAMPS_DIR = debian/stamps
+TEMPLATES_DIR = debian/templates
+
Added: people/maks-guest/linux-2.6/debian/rules.gen
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/rules.gen Sat Nov 11 02:48:00 2006
@@ -0,0 +1,1324 @@
+.NOTPARALLEL:
+binary-indep:
+ $(MAKE) -f debian/rules.real binary-indep ABINAME='' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' MAJOR='2.6' VERSION='2.6.18' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5'
+binary-arch:: binary-arch-alpha
+binary-arch-alpha:: binary-arch-alpha-real
+build:: build-alpha
+build-alpha:: build-alpha-real
+setup:: setup-alpha
+setup-alpha:: setup-alpha-real
+source:: source-alpha
+source-alpha:: source-alpha-real
+binary-arch-alpha-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='alpha'
+build-alpha-real:
+setup-alpha-real:
+source-alpha-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='alpha'
+binary-arch-alpha:: binary-arch-alpha-none
+binary-arch-alpha-none:: binary-arch-alpha-none-real
+build-alpha:: build-alpha-none
+build-alpha-none:: build-alpha-none-real
+setup-alpha:: setup-alpha-none
+setup-alpha-none:: setup-alpha-none-real
+source-alpha:: source-alpha-none
+source-alpha-none:: source-alpha-none-real
+binary-arch-alpha-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='alpha'
+build-alpha-none-real:
+setup-alpha-none-real:
+source-alpha-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='alpha'
+binary-arch-alpha-none:: binary-arch-alpha-none-alpha-generic
+binary-arch-alpha-none-alpha-generic:: binary-arch-alpha-none-alpha-generic-real
+build-alpha-none:: build-alpha-none-alpha-generic
+build-alpha-none-alpha-generic:: build-alpha-none-alpha-generic-real
+setup-alpha-none:: setup-alpha-none-alpha-generic
+setup-alpha-none-alpha-generic:: setup-alpha-none-alpha-generic-real
+source-alpha-none:: source-alpha-none-alpha-generic
+source-alpha-none-alpha-generic:: source-alpha-none-alpha-generic-real
+binary-arch-alpha-none-alpha-generic-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='alpha-generic' KCONFIG='config alpha/config alpha/config.alpha-generic' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-generic' ARCH='alpha' COMPILER='gcc-4.1'
+build-alpha-none-alpha-generic-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='alpha-generic' KCONFIG='config alpha/config alpha/config.alpha-generic' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-generic' ARCH='alpha' COMPILER='gcc-4.1'
+setup-alpha-none-alpha-generic-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='alpha-generic' KCONFIG='config alpha/config alpha/config.alpha-generic' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-generic' ARCH='alpha' COMPILER='gcc-4.1'
+source-alpha-none-alpha-generic-real:
+binary-arch-alpha-none:: binary-arch-alpha-none-alpha-smp
+binary-arch-alpha-none-alpha-smp:: binary-arch-alpha-none-alpha-smp-real
+build-alpha-none:: build-alpha-none-alpha-smp
+build-alpha-none-alpha-smp:: build-alpha-none-alpha-smp-real
+setup-alpha-none:: setup-alpha-none-alpha-smp
+setup-alpha-none-alpha-smp:: setup-alpha-none-alpha-smp-real
+source-alpha-none:: source-alpha-none-alpha-smp
+source-alpha-none-alpha-smp:: source-alpha-none-alpha-smp-real
+binary-arch-alpha-none-alpha-smp-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='alpha-smp' KCONFIG='config alpha/config alpha/config.alpha-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-smp' ARCH='alpha' COMPILER='gcc-4.1'
+build-alpha-none-alpha-smp-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='alpha-smp' KCONFIG='config alpha/config alpha/config.alpha-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-smp' ARCH='alpha' COMPILER='gcc-4.1'
+setup-alpha-none-alpha-smp-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='alpha-smp' KCONFIG='config alpha/config alpha/config.alpha-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-smp' ARCH='alpha' COMPILER='gcc-4.1'
+source-alpha-none-alpha-smp-real:
+binary-arch-alpha-none:: binary-arch-alpha-none-alpha-legacy
+binary-arch-alpha-none-alpha-legacy:: binary-arch-alpha-none-alpha-legacy-real
+build-alpha-none:: build-alpha-none-alpha-legacy
+build-alpha-none-alpha-legacy:: build-alpha-none-alpha-legacy-real
+setup-alpha-none:: setup-alpha-none-alpha-legacy
+setup-alpha-none-alpha-legacy:: setup-alpha-none-alpha-legacy-real
+source-alpha-none:: source-alpha-none-alpha-legacy
+source-alpha-none-alpha-legacy:: source-alpha-none-alpha-legacy-real
+binary-arch-alpha-none-alpha-legacy-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='alpha-legacy' KCONFIG='config alpha/config alpha/config.alpha-legacy' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-legacy' ARCH='alpha' COMPILER='gcc-4.1'
+build-alpha-none-alpha-legacy-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='alpha-legacy' KCONFIG='config alpha/config alpha/config.alpha-legacy' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-legacy' ARCH='alpha' COMPILER='gcc-4.1'
+setup-alpha-none-alpha-legacy-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='alpha-legacy' KCONFIG='config alpha/config alpha/config.alpha-legacy' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-alpha-legacy' ARCH='alpha' COMPILER='gcc-4.1'
+source-alpha-none-alpha-legacy-real:
+binary-arch-alpha:: binary-arch-alpha-vserver
+binary-arch-alpha-vserver:: binary-arch-alpha-vserver-real
+build-alpha:: build-alpha-vserver
+build-alpha-vserver:: build-alpha-vserver-real
+setup-alpha:: setup-alpha-vserver
+setup-alpha-vserver:: setup-alpha-vserver-real
+source-alpha:: source-alpha-vserver
+source-alpha-vserver:: source-alpha-vserver-real
+binary-arch-alpha-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='alpha'
+build-alpha-vserver-real:
+setup-alpha-vserver-real:
+source-alpha-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='alpha'
+binary-arch-alpha-vserver:: binary-arch-alpha-vserver-alpha
+binary-arch-alpha-vserver-alpha:: binary-arch-alpha-vserver-alpha-real
+build-alpha-vserver:: build-alpha-vserver-alpha
+build-alpha-vserver-alpha:: build-alpha-vserver-alpha-real
+setup-alpha-vserver:: setup-alpha-vserver-alpha
+setup-alpha-vserver-alpha:: setup-alpha-vserver-alpha-real
+source-alpha-vserver:: source-alpha-vserver-alpha
+source-alpha-vserver-alpha:: source-alpha-vserver-alpha-real
+binary-arch-alpha-vserver-alpha-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='alpha' KCONFIG='config alpha/config _vserver/config alpha/config.alpha-generic' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-alpha' ARCH='alpha' COMPILER='gcc-4.1'
+build-alpha-vserver-alpha-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='alpha' KCONFIG='config alpha/config _vserver/config alpha/config.alpha-generic' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-alpha' ARCH='alpha' COMPILER='gcc-4.1'
+setup-alpha-vserver-alpha-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='alpha' KCONFIG='config alpha/config _vserver/config alpha/config.alpha-generic' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='alpha' KERNEL_ARCH='alpha' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-alpha' ARCH='alpha' COMPILER='gcc-4.1'
+source-alpha-vserver-alpha-real:
+binary-arch:: binary-arch-amd64
+binary-arch-amd64:: binary-arch-amd64-real
+build:: build-amd64
+build-amd64:: build-amd64-real
+setup:: setup-amd64
+setup-amd64:: setup-amd64-real
+source:: source-amd64
+source-amd64:: source-amd64-real
+binary-arch-amd64-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='amd64'
+build-amd64-real:
+setup-amd64-real:
+source-amd64-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='amd64'
+binary-arch-amd64:: binary-arch-amd64-none
+binary-arch-amd64-none:: binary-arch-amd64-none-real
+build-amd64:: build-amd64-none
+build-amd64-none:: build-amd64-none-real
+setup-amd64:: setup-amd64-none
+setup-amd64-none:: setup-amd64-none-real
+source-amd64:: source-amd64-none
+source-amd64-none:: source-amd64-none-real
+binary-arch-amd64-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+build-amd64-none-real:
+setup-amd64-none-real:
+source-amd64-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+binary-arch-amd64-none:: binary-arch-amd64-none-amd64
+binary-arch-amd64-none-amd64:: binary-arch-amd64-none-amd64-real
+build-amd64-none:: build-amd64-none-amd64
+build-amd64-none-amd64:: build-amd64-none-amd64-real
+setup-amd64-none:: setup-amd64-none-amd64
+setup-amd64-none-amd64:: setup-amd64-none-amd64-real
+source-amd64-none:: source-amd64-none-amd64
+source-amd64-none-amd64:: source-amd64-none-amd64-real
+binary-arch-amd64-none-amd64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/config.amd64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+build-amd64-none-amd64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/config.amd64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+setup-amd64-none-amd64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/config.amd64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+source-amd64-none-amd64-real:
+binary-arch-amd64:: binary-arch-amd64-vserver
+binary-arch-amd64-vserver:: binary-arch-amd64-vserver-real
+build-amd64:: build-amd64-vserver
+build-amd64-vserver:: build-amd64-vserver-real
+setup-amd64:: setup-amd64-vserver
+setup-amd64-vserver:: setup-amd64-vserver-real
+source-amd64:: source-amd64-vserver
+source-amd64-vserver:: source-amd64-vserver-real
+binary-arch-amd64-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+build-amd64-vserver-real:
+setup-amd64-vserver-real:
+source-amd64-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+binary-arch-amd64-vserver:: binary-arch-amd64-vserver-amd64
+binary-arch-amd64-vserver-amd64:: binary-arch-amd64-vserver-amd64-real
+build-amd64-vserver:: build-amd64-vserver-amd64
+build-amd64-vserver-amd64:: build-amd64-vserver-amd64-real
+setup-amd64-vserver:: setup-amd64-vserver-amd64
+setup-amd64-vserver-amd64:: setup-amd64-vserver-amd64-real
+source-amd64-vserver:: source-amd64-vserver-amd64
+source-amd64-vserver-amd64:: source-amd64-vserver-amd64-real
+binary-arch-amd64-vserver-amd64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/config.amd64' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+build-amd64-vserver-amd64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/config.amd64' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+setup-amd64-vserver-amd64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/config.amd64' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+source-amd64-vserver-amd64-real:
+binary-arch-amd64:: binary-arch-amd64-xen
+binary-arch-amd64-xen:: binary-arch-amd64-xen-real
+build-amd64:: build-amd64-xen
+build-amd64-xen:: build-amd64-xen-real
+setup-amd64:: setup-amd64-xen
+setup-amd64-xen:: setup-amd64-xen-real
+source-amd64:: source-amd64-xen
+source-amd64-xen:: source-amd64-xen-real
+binary-arch-amd64-xen-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+build-amd64-xen-real:
+setup-amd64-xen-real:
+source-amd64-xen-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+binary-arch-amd64-xen:: binary-arch-amd64-xen-amd64
+binary-arch-amd64-xen-amd64:: binary-arch-amd64-xen-amd64-real
+build-amd64-xen:: build-amd64-xen-amd64
+build-amd64-xen-amd64:: build-amd64-xen-amd64-real
+setup-amd64-xen:: setup-amd64-xen-amd64
+setup-amd64-xen-amd64:: setup-amd64-xen-amd64-real
+source-amd64-xen:: source-amd64-xen-amd64
+source-amd64-xen-amd64:: source-amd64-xen-amd64-real
+binary-arch-amd64-xen-amd64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+ $(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-pxen-linux-system-2.6.18-6~2.6.19-rc5-xen-amd64' MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+build-amd64-xen-amd64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+setup-amd64-xen-amd64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+source-amd64-xen-amd64-real:
+binary-arch-amd64:: binary-arch-amd64-xen-vserver
+binary-arch-amd64-xen-vserver:: binary-arch-amd64-xen-vserver-real
+build-amd64:: build-amd64-xen-vserver
+build-amd64-xen-vserver:: build-amd64-xen-vserver-real
+setup-amd64:: setup-amd64-xen-vserver
+setup-amd64-xen-vserver:: setup-amd64-xen-vserver-real
+source-amd64:: source-amd64-xen-vserver
+source-amd64-xen-vserver:: source-amd64-xen-vserver-real
+binary-arch-amd64-xen-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+build-amd64-xen-vserver-real:
+setup-amd64-xen-vserver-real:
+source-amd64-xen-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' ABINAME='' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='amd64'
+binary-arch-amd64-xen-vserver:: binary-arch-amd64-xen-vserver-amd64
+binary-arch-amd64-xen-vserver-amd64:: binary-arch-amd64-xen-vserver-amd64-real
+build-amd64-xen-vserver:: build-amd64-xen-vserver-amd64
+build-amd64-xen-vserver-amd64:: build-amd64-xen-vserver-amd64-real
+setup-amd64-xen-vserver:: setup-amd64-xen-vserver-amd64
+setup-amd64-xen-vserver-amd64:: setup-amd64-xen-vserver-amd64-real
+source-amd64-xen-vserver:: source-amd64-xen-vserver-amd64
+source-amd64-xen-vserver-amd64:: source-amd64-xen-vserver-amd64-real
+binary-arch-amd64-xen-vserver-amd64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+ $(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-pxen-linux-system-2.6.18-6~2.6.19-rc5-xen-vserver-amd64' MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+build-amd64-xen-vserver-amd64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+setup-amd64-xen-vserver-amd64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='amd64' KCONFIG='config amd64/config _vserver/config amd64/xen/config _xen/config amd64/config.amd64' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-amd64' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='x86_64 i386' KERNEL_ARCH='x86_64' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-amd64' ARCH='amd64' COMPILER='gcc-4.1'
+source-amd64-xen-vserver-amd64-real:
+binary-arch:: binary-arch-arm
+binary-arch-arm:: binary-arch-arm-real
+build:: build-arm
+build-arm:: build-arm-real
+setup:: setup-arm
+setup-arm:: setup-arm-real
+source:: source-arm
+source-arm:: source-arm-real
+binary-arch-arm-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='arm'
+build-arm-real:
+setup-arm-real:
+source-arm-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='arm'
+binary-arch-arm:: binary-arch-arm-none
+binary-arch-arm-none:: binary-arch-arm-none-real
+build-arm:: build-arm-none
+build-arm-none:: build-arm-none-real
+setup-arm:: setup-arm-none
+setup-arm-none:: setup-arm-none-real
+source-arm:: source-arm-none
+source-arm-none:: source-arm-none-real
+binary-arch-arm-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='arm'
+build-arm-none-real:
+setup-arm-none-real:
+source-arm-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='arm'
+binary-arch-arm-none:: binary-arch-arm-none-footbridge
+binary-arch-arm-none-footbridge:: binary-arch-arm-none-footbridge-real
+build-arm-none:: build-arm-none-footbridge
+build-arm-none-footbridge:: build-arm-none-footbridge-real
+setup-arm-none:: setup-arm-none-footbridge
+setup-arm-none-footbridge:: setup-arm-none-footbridge-real
+source-arm-none:: source-arm-none-footbridge
+source-arm-none-footbridge:: source-arm-none-footbridge-real
+binary-arch-arm-none-footbridge-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='footbridge' KCONFIG='config arm/config arm/config.footbridge' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-footbridge' ARCH='arm' COMPILER='gcc-4.1'
+build-arm-none-footbridge-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='footbridge' KCONFIG='config arm/config arm/config.footbridge' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-footbridge' ARCH='arm' COMPILER='gcc-4.1'
+setup-arm-none-footbridge-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='footbridge' KCONFIG='config arm/config arm/config.footbridge' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-footbridge' ARCH='arm' COMPILER='gcc-4.1'
+source-arm-none-footbridge-real:
+binary-arch-arm-none:: binary-arch-arm-none-iop32x
+binary-arch-arm-none-iop32x:: binary-arch-arm-none-iop32x-real
+build-arm-none:: build-arm-none-iop32x
+build-arm-none-iop32x:: build-arm-none-iop32x-real
+setup-arm-none:: setup-arm-none-iop32x
+setup-arm-none-iop32x:: setup-arm-none-iop32x-real
+source-arm-none:: source-arm-none-iop32x
+source-arm-none-iop32x:: source-arm-none-iop32x-real
+binary-arch-arm-none-iop32x-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='iop32x' KCONFIG='config arm/config arm/config.iop32x' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-iop32x' ARCH='arm' COMPILER='gcc-4.1'
+build-arm-none-iop32x-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='iop32x' KCONFIG='config arm/config arm/config.iop32x' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-iop32x' ARCH='arm' COMPILER='gcc-4.1'
+setup-arm-none-iop32x-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='iop32x' KCONFIG='config arm/config arm/config.iop32x' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-iop32x' ARCH='arm' COMPILER='gcc-4.1'
+source-arm-none-iop32x-real:
+binary-arch-arm-none:: binary-arch-arm-none-ixp4xx
+binary-arch-arm-none-ixp4xx:: binary-arch-arm-none-ixp4xx-real
+build-arm-none:: build-arm-none-ixp4xx
+build-arm-none-ixp4xx:: build-arm-none-ixp4xx-real
+setup-arm-none:: setup-arm-none-ixp4xx
+setup-arm-none-ixp4xx:: setup-arm-none-ixp4xx-real
+source-arm-none:: source-arm-none-ixp4xx
+source-arm-none-ixp4xx:: source-arm-none-ixp4xx-real
+binary-arch-arm-none-ixp4xx-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='ixp4xx' KCONFIG='config arm/config arm/config.ixp4xx' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-ixp4xx' ARCH='arm' COMPILER='gcc-4.1'
+build-arm-none-ixp4xx-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='ixp4xx' KCONFIG='config arm/config arm/config.ixp4xx' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-ixp4xx' ARCH='arm' COMPILER='gcc-4.1'
+setup-arm-none-ixp4xx-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='ixp4xx' KCONFIG='config arm/config arm/config.ixp4xx' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-ixp4xx' ARCH='arm' COMPILER='gcc-4.1'
+source-arm-none-ixp4xx-real:
+binary-arch-arm-none:: binary-arch-arm-none-rpc
+binary-arch-arm-none-rpc:: binary-arch-arm-none-rpc-real
+build-arm-none:: build-arm-none-rpc
+build-arm-none-rpc:: build-arm-none-rpc-real
+setup-arm-none:: setup-arm-none-rpc
+setup-arm-none-rpc:: setup-arm-none-rpc-real
+source-arm-none:: source-arm-none-rpc
+source-arm-none-rpc:: source-arm-none-rpc-real
+binary-arch-arm-none-rpc-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='rpc' KCONFIG='config arm/config arm/config.rpc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-rpc' ARCH='arm' COMPILER='gcc-4.1'
+build-arm-none-rpc-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='rpc' KCONFIG='config arm/config arm/config.rpc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-rpc' ARCH='arm' COMPILER='gcc-4.1'
+setup-arm-none-rpc-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='rpc' KCONFIG='config arm/config arm/config.rpc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-rpc' ARCH='arm' COMPILER='gcc-4.1'
+source-arm-none-rpc-real:
+binary-arch-arm-none:: binary-arch-arm-none-s3c2410
+binary-arch-arm-none-s3c2410:: binary-arch-arm-none-s3c2410-real
+build-arm-none:: build-arm-none-s3c2410
+build-arm-none-s3c2410:: build-arm-none-s3c2410-real
+setup-arm-none:: setup-arm-none-s3c2410
+setup-arm-none-s3c2410:: setup-arm-none-s3c2410-real
+source-arm-none:: source-arm-none-s3c2410
+source-arm-none-s3c2410:: source-arm-none-s3c2410-real
+binary-arch-arm-none-s3c2410-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='s3c2410' KCONFIG='config arm/config arm/config.s3c2410' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s3c2410' ARCH='arm' COMPILER='gcc-4.1'
+build-arm-none-s3c2410-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='s3c2410' KCONFIG='config arm/config arm/config.s3c2410' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s3c2410' ARCH='arm' COMPILER='gcc-4.1'
+setup-arm-none-s3c2410-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='s3c2410' KCONFIG='config arm/config arm/config.s3c2410' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='arm' KERNEL_ARCH='arm' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s3c2410' ARCH='arm' COMPILER='gcc-4.1'
+source-arm-none-s3c2410-real:
+binary-arch:: binary-arch-hppa
+binary-arch-hppa:: binary-arch-hppa-real
+build:: build-hppa
+build-hppa:: build-hppa-real
+setup:: setup-hppa
+setup-hppa:: setup-hppa-real
+source:: source-hppa
+source-hppa:: source-hppa-real
+binary-arch-hppa-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='hppa'
+build-hppa-real:
+setup-hppa-real:
+source-hppa-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='hppa'
+binary-arch-hppa:: binary-arch-hppa-none
+binary-arch-hppa-none:: binary-arch-hppa-none-real
+build-hppa:: build-hppa-none
+build-hppa-none:: build-hppa-none-real
+setup-hppa:: setup-hppa-none
+setup-hppa-none:: setup-hppa-none-real
+source-hppa:: source-hppa-none
+source-hppa-none:: source-hppa-none-real
+binary-arch-hppa-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='hppa'
+build-hppa-none-real:
+setup-hppa-none-real:
+source-hppa-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='hppa'
+binary-arch-hppa-none:: binary-arch-hppa-none-parisc
+binary-arch-hppa-none-parisc:: binary-arch-hppa-none-parisc-real
+build-hppa-none:: build-hppa-none-parisc
+build-hppa-none-parisc:: build-hppa-none-parisc-real
+setup-hppa-none:: setup-hppa-none-parisc
+setup-hppa-none-parisc:: setup-hppa-none-parisc-real
+source-hppa-none:: source-hppa-none-parisc
+source-hppa-none-parisc:: source-hppa-none-parisc-real
+binary-arch-hppa-none-parisc-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='parisc' KCONFIG='config hppa/config hppa/config.parisc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc' ARCH='hppa' COMPILER='gcc-4.1'
+build-hppa-none-parisc-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='parisc' KCONFIG='config hppa/config hppa/config.parisc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc' ARCH='hppa' COMPILER='gcc-4.1'
+setup-hppa-none-parisc-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='parisc' KCONFIG='config hppa/config hppa/config.parisc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc' ARCH='hppa' COMPILER='gcc-4.1'
+source-hppa-none-parisc-real:
+binary-arch-hppa-none:: binary-arch-hppa-none-parisc-smp
+binary-arch-hppa-none-parisc-smp:: binary-arch-hppa-none-parisc-smp-real
+build-hppa-none:: build-hppa-none-parisc-smp
+build-hppa-none-parisc-smp:: build-hppa-none-parisc-smp-real
+setup-hppa-none:: setup-hppa-none-parisc-smp
+setup-hppa-none-parisc-smp:: setup-hppa-none-parisc-smp-real
+source-hppa-none:: source-hppa-none-parisc-smp
+source-hppa-none-parisc-smp:: source-hppa-none-parisc-smp-real
+binary-arch-hppa-none-parisc-smp-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='parisc-smp' KCONFIG='config hppa/config hppa/config.parisc-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc-smp' ARCH='hppa' COMPILER='gcc-4.1'
+build-hppa-none-parisc-smp-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='parisc-smp' KCONFIG='config hppa/config hppa/config.parisc-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc-smp' ARCH='hppa' COMPILER='gcc-4.1'
+setup-hppa-none-parisc-smp-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='parisc-smp' KCONFIG='config hppa/config hppa/config.parisc-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc-smp' ARCH='hppa' COMPILER='gcc-4.1'
+source-hppa-none-parisc-smp-real:
+binary-arch-hppa-none:: binary-arch-hppa-none-parisc64
+binary-arch-hppa-none-parisc64:: binary-arch-hppa-none-parisc64-real
+build-hppa-none:: build-hppa-none-parisc64
+build-hppa-none-parisc64:: build-hppa-none-parisc64-real
+setup-hppa-none:: setup-hppa-none-parisc64
+setup-hppa-none-parisc64:: setup-hppa-none-parisc64-real
+source-hppa-none:: source-hppa-none-parisc64
+source-hppa-none-parisc64:: source-hppa-none-parisc64-real
+binary-arch-hppa-none-parisc64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='parisc64' KCONFIG='config hppa/config hppa/config.parisc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc64' ARCH='hppa' COMPILER='gcc-4.1'
+build-hppa-none-parisc64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='parisc64' KCONFIG='config hppa/config hppa/config.parisc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc64' ARCH='hppa' COMPILER='gcc-4.1'
+setup-hppa-none-parisc64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='parisc64' KCONFIG='config hppa/config hppa/config.parisc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc64' ARCH='hppa' COMPILER='gcc-4.1'
+source-hppa-none-parisc64-real:
+binary-arch-hppa-none:: binary-arch-hppa-none-parisc64-smp
+binary-arch-hppa-none-parisc64-smp:: binary-arch-hppa-none-parisc64-smp-real
+build-hppa-none:: build-hppa-none-parisc64-smp
+build-hppa-none-parisc64-smp:: build-hppa-none-parisc64-smp-real
+setup-hppa-none:: setup-hppa-none-parisc64-smp
+setup-hppa-none-parisc64-smp:: setup-hppa-none-parisc64-smp-real
+source-hppa-none:: source-hppa-none-parisc64-smp
+source-hppa-none-parisc64-smp:: source-hppa-none-parisc64-smp-real
+binary-arch-hppa-none-parisc64-smp-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='parisc64-smp' KCONFIG='config hppa/config hppa/config.parisc64-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc64-smp' ARCH='hppa' COMPILER='gcc-4.1'
+build-hppa-none-parisc64-smp-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='parisc64-smp' KCONFIG='config hppa/config hppa/config.parisc64-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc64-smp' ARCH='hppa' COMPILER='gcc-4.1'
+setup-hppa-none-parisc64-smp-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='parisc64-smp' KCONFIG='config hppa/config hppa/config.parisc64-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='parisc' KERNEL_ARCH='parisc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-parisc64-smp' ARCH='hppa' COMPILER='gcc-4.1'
+source-hppa-none-parisc64-smp-real:
+binary-arch:: binary-arch-i386
+binary-arch-i386:: binary-arch-i386-real
+build:: build-i386
+build-i386:: build-i386-real
+setup:: setup-i386
+setup-i386:: setup-i386-real
+source:: source-i386
+source-i386:: source-i386-real
+binary-arch-i386-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='i386'
+build-i386-real:
+setup-i386-real:
+source-i386-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='i386'
+binary-arch-i386:: binary-arch-i386-none
+binary-arch-i386-none:: binary-arch-i386-none-real
+build-i386:: build-i386-none
+build-i386-none:: build-i386-none-real
+setup-i386:: setup-i386-none
+setup-i386-none:: setup-i386-none-real
+source-i386:: source-i386-none
+source-i386-none:: source-i386-none-real
+binary-arch-i386-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+build-i386-none-real:
+setup-i386-none-real:
+source-i386-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+binary-arch-i386-none:: binary-arch-i386-none-486
+binary-arch-i386-none-486:: binary-arch-i386-none-486-real
+build-i386-none:: build-i386-none-486
+build-i386-none-486:: build-i386-none-486-real
+setup-i386-none:: setup-i386-none-486
+setup-i386-none-486:: setup-i386-none-486-real
+source-i386-none:: source-i386-none-486
+source-i386-none-486:: source-i386-none-486-real
+binary-arch-i386-none-486-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='486' KCONFIG='config i386/config i386/config.486' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-486' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-none-486-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='486' KCONFIG='config i386/config i386/config.486' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-486' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-none-486-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='486' KCONFIG='config i386/config i386/config.486' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-486' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-none-486-real:
+binary-arch-i386-none:: binary-arch-i386-none-686
+binary-arch-i386-none-686:: binary-arch-i386-none-686-real
+build-i386-none:: build-i386-none-686
+build-i386-none-686:: build-i386-none-686-real
+setup-i386-none:: setup-i386-none-686
+setup-i386-none-686:: setup-i386-none-686-real
+source-i386-none:: source-i386-none-686
+source-i386-none-686:: source-i386-none-686-real
+binary-arch-i386-none-686-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/config.686' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-686' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-none-686-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/config.686' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-686' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-none-686-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/config.686' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-686' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-none-686-real:
+binary-arch-i386-none:: binary-arch-i386-none-k7
+binary-arch-i386-none-k7:: binary-arch-i386-none-k7-real
+build-i386-none:: build-i386-none-k7
+build-i386-none-k7:: build-i386-none-k7-real
+setup-i386-none:: setup-i386-none-k7
+setup-i386-none-k7:: setup-i386-none-k7-real
+source-i386-none:: source-i386-none-k7
+source-i386-none-k7:: source-i386-none-k7-real
+binary-arch-i386-none-k7-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/config.k7' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-k7' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-none-k7-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/config.k7' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-k7' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-none-k7-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/config.k7' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-k7' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-none-k7-real:
+binary-arch-i386-none:: binary-arch-i386-none-686-bigmem
+binary-arch-i386-none-686-bigmem:: binary-arch-i386-none-686-bigmem-real
+build-i386-none:: build-i386-none-686-bigmem
+build-i386-none-686-bigmem:: build-i386-none-686-bigmem-real
+setup-i386-none:: setup-i386-none-686-bigmem
+setup-i386-none-686-bigmem:: setup-i386-none-686-bigmem-real
+source-i386-none:: source-i386-none-686-bigmem
+source-i386-none-686-bigmem:: source-i386-none-686-bigmem-real
+binary-arch-i386-none-686-bigmem-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='686-bigmem' KCONFIG='config i386/config i386/config.686-bigmem' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-686-bigmem' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-none-686-bigmem-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='686-bigmem' KCONFIG='config i386/config i386/config.686-bigmem' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-686-bigmem' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-none-686-bigmem-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='686-bigmem' KCONFIG='config i386/config i386/config.686-bigmem' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-686-bigmem' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-none-686-bigmem-real:
+binary-arch-i386:: binary-arch-i386-vserver
+binary-arch-i386-vserver:: binary-arch-i386-vserver-real
+build-i386:: build-i386-vserver
+build-i386-vserver:: build-i386-vserver-real
+setup-i386:: setup-i386-vserver
+setup-i386-vserver:: setup-i386-vserver-real
+source-i386:: source-i386-vserver
+source-i386-vserver:: source-i386-vserver-real
+binary-arch-i386-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+build-i386-vserver-real:
+setup-i386-vserver-real:
+source-i386-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+binary-arch-i386-vserver:: binary-arch-i386-vserver-686
+binary-arch-i386-vserver-686:: binary-arch-i386-vserver-686-real
+build-i386-vserver:: build-i386-vserver-686
+build-i386-vserver-686:: build-i386-vserver-686-real
+setup-i386-vserver:: setup-i386-vserver-686
+setup-i386-vserver-686:: setup-i386-vserver-686-real
+source-i386-vserver:: source-i386-vserver-686
+source-i386-vserver-686:: source-i386-vserver-686-real
+binary-arch-i386-vserver-686-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/config.686' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-vserver-686-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/config.686' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-vserver-686-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/config.686' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-vserver-686-real:
+binary-arch-i386-vserver:: binary-arch-i386-vserver-k7
+binary-arch-i386-vserver-k7:: binary-arch-i386-vserver-k7-real
+build-i386-vserver:: build-i386-vserver-k7
+build-i386-vserver-k7:: build-i386-vserver-k7-real
+setup-i386-vserver:: setup-i386-vserver-k7
+setup-i386-vserver-k7:: setup-i386-vserver-k7-real
+source-i386-vserver:: source-i386-vserver-k7
+source-i386-vserver-k7:: source-i386-vserver-k7-real
+binary-arch-i386-vserver-k7-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config _vserver/config i386/config.k7' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-k7' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-vserver-k7-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config _vserver/config i386/config.k7' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-k7' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-vserver-k7-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config _vserver/config i386/config.k7' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-k7' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-vserver-k7-real:
+binary-arch-i386:: binary-arch-i386-xen
+binary-arch-i386-xen:: binary-arch-i386-xen-real
+build-i386:: build-i386-xen
+build-i386-xen:: build-i386-xen-real
+setup-i386:: setup-i386-xen
+setup-i386-xen:: setup-i386-xen-real
+source-i386:: source-i386-xen
+source-i386-xen:: source-i386-xen-real
+binary-arch-i386-xen-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+build-i386-xen-real:
+setup-i386-xen-real:
+source-i386-xen-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+binary-arch-i386-xen:: binary-arch-i386-xen-686
+binary-arch-i386-xen-686:: binary-arch-i386-xen-686-real
+build-i386-xen:: build-i386-xen-686
+build-i386-xen-686:: build-i386-xen-686-real
+setup-i386-xen:: setup-i386-xen-686
+setup-i386-xen-686:: setup-i386-xen-686-real
+source-i386-xen:: source-i386-xen-686
+source-i386-xen-686:: source-i386-xen-686-real
+binary-arch-i386-xen-686-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-686' ARCH='i386' COMPILER='gcc-4.1'
+ $(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-pxen-linux-system-2.6.18-6~2.6.19-rc5-xen-686' MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-686' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-xen-686-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-686' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-xen-686-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-686' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-xen-686-real:
+binary-arch-i386-xen:: binary-arch-i386-xen-k7
+binary-arch-i386-xen-k7:: binary-arch-i386-xen-k7-real
+build-i386-xen:: build-i386-xen-k7
+build-i386-xen-k7:: build-i386-xen-k7-real
+setup-i386-xen:: setup-i386-xen-k7
+setup-i386-xen-k7:: setup-i386-xen-k7-real
+source-i386-xen:: source-i386-xen-k7
+source-i386-xen-k7:: source-i386-xen-k7-real
+binary-arch-i386-xen-k7-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.k7' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-k7' ARCH='i386' COMPILER='gcc-4.1'
+ $(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-pxen-linux-system-2.6.18-6~2.6.19-rc5-xen-k7' MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.k7' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-k7' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-xen-k7-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.k7' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-k7' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-xen-k7-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='k7' KCONFIG='config i386/config i386/xen/config _xen/config i386/config.k7' LOCALVERSION_HEADERS='-xen' SUBARCH='xen' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-k7' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-xen-k7-real:
+binary-arch-i386:: binary-arch-i386-xen-vserver
+binary-arch-i386-xen-vserver:: binary-arch-i386-xen-vserver-real
+build-i386:: build-i386-xen-vserver
+build-i386-xen-vserver:: build-i386-xen-vserver-real
+setup-i386:: setup-i386-xen-vserver
+setup-i386-xen-vserver:: setup-i386-xen-vserver-real
+source-i386:: source-i386-xen-vserver
+source-i386-xen-vserver:: source-i386-xen-vserver-real
+binary-arch-i386-xen-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+build-i386-xen-vserver-real:
+setup-i386-xen-vserver-real:
+source-i386-xen-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-xen-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' ABINAME='' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='i386'
+binary-arch-i386-xen-vserver:: binary-arch-i386-xen-vserver-686
+binary-arch-i386-xen-vserver-686:: binary-arch-i386-xen-vserver-686-real
+build-i386-xen-vserver:: build-i386-xen-vserver-686
+build-i386-xen-vserver-686:: build-i386-xen-vserver-686-real
+setup-i386-xen-vserver:: setup-i386-xen-vserver-686
+setup-i386-xen-vserver-686:: setup-i386-xen-vserver-686-real
+source-i386-xen-vserver:: source-i386-xen-vserver-686
+source-i386-xen-vserver-686:: source-i386-xen-vserver-686-real
+binary-arch-i386-xen-vserver-686-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+ $(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-pxen-linux-system-2.6.18-6~2.6.19-rc5-xen-vserver-686' MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+build-i386-xen-vserver-686-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+setup-i386-xen-vserver-686-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='686' KCONFIG='config i386/config _vserver/config i386/xen/config _xen/config i386/config.686' LOCALVERSION_HEADERS='-xen-vserver' SUBARCH='xen-vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg' MODULES='True' XEN_VERSIONS='3.0.3-1-i386' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='i386' KERNEL_ARCH='i386' ABINAME='' TYPE='plain-xen' LOCALVERSION='-xen-vserver-686' ARCH='i386' COMPILER='gcc-4.1'
+source-i386-xen-vserver-686-real:
+binary-arch:: binary-arch-ia64
+binary-arch-ia64:: binary-arch-ia64-real
+build:: build-ia64
+build-ia64:: build-ia64-real
+setup:: setup-ia64
+setup-ia64:: setup-ia64-real
+source:: source-ia64
+source-ia64:: source-ia64-real
+binary-arch-ia64-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='ia64'
+build-ia64-real:
+setup-ia64-real:
+source-ia64-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='ia64'
+binary-arch-ia64:: binary-arch-ia64-none
+binary-arch-ia64-none:: binary-arch-ia64-none-real
+build-ia64:: build-ia64-none
+build-ia64-none:: build-ia64-none-real
+setup-ia64:: setup-ia64-none
+setup-ia64-none:: setup-ia64-none-real
+source-ia64:: source-ia64-none
+source-ia64-none:: source-ia64-none-real
+binary-arch-ia64-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='ia64'
+build-ia64-none-real:
+setup-ia64-none-real:
+source-ia64-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='ia64'
+binary-arch-ia64-none:: binary-arch-ia64-none-itanium
+binary-arch-ia64-none-itanium:: binary-arch-ia64-none-itanium-real
+build-ia64-none:: build-ia64-none-itanium
+build-ia64-none-itanium:: build-ia64-none-itanium-real
+setup-ia64-none:: setup-ia64-none-itanium
+setup-ia64-none-itanium:: setup-ia64-none-itanium-real
+source-ia64-none:: source-ia64-none-itanium
+source-ia64-none-itanium:: source-ia64-none-itanium-real
+binary-arch-ia64-none-itanium-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='itanium' KCONFIG='config ia64/config ia64/config.itanium' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' KERNEL_ARCH='ia64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-itanium' ARCH='ia64' COMPILER='gcc-4.1'
+build-ia64-none-itanium-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='itanium' KCONFIG='config ia64/config ia64/config.itanium' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' KERNEL_ARCH='ia64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-itanium' ARCH='ia64' COMPILER='gcc-4.1'
+setup-ia64-none-itanium-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='itanium' KCONFIG='config ia64/config ia64/config.itanium' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' KERNEL_ARCH='ia64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-itanium' ARCH='ia64' COMPILER='gcc-4.1'
+source-ia64-none-itanium-real:
+binary-arch-ia64-none:: binary-arch-ia64-none-mckinley
+binary-arch-ia64-none-mckinley:: binary-arch-ia64-none-mckinley-real
+build-ia64-none:: build-ia64-none-mckinley
+build-ia64-none-mckinley:: build-ia64-none-mckinley-real
+setup-ia64-none:: setup-ia64-none-mckinley
+setup-ia64-none-mckinley:: setup-ia64-none-mckinley-real
+source-ia64-none:: source-ia64-none-mckinley
+source-ia64-none-mckinley:: source-ia64-none-mckinley-real
+binary-arch-ia64-none-mckinley-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='mckinley' KCONFIG='config ia64/config ia64/config.mckinley' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' KERNEL_ARCH='ia64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-mckinley' ARCH='ia64' COMPILER='gcc-4.1'
+build-ia64-none-mckinley-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='mckinley' KCONFIG='config ia64/config ia64/config.mckinley' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' KERNEL_ARCH='ia64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-mckinley' ARCH='ia64' COMPILER='gcc-4.1'
+setup-ia64-none-mckinley-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='mckinley' KCONFIG='config ia64/config ia64/config.mckinley' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='ia64' KERNEL_ARCH='ia64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-mckinley' ARCH='ia64' COMPILER='gcc-4.1'
+source-ia64-none-mckinley-real:
+binary-arch:: binary-arch-m68k
+binary-arch-m68k:: binary-arch-m68k-real
+build:: build-m68k
+build-m68k:: build-m68k-real
+setup:: setup-m68k
+setup-m68k:: setup-m68k-real
+source:: source-m68k
+source-m68k:: source-m68k-real
+binary-arch-m68k-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='m68k'
+build-m68k-real:
+setup-m68k-real:
+source-m68k-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='m68k'
+binary-arch-m68k:: binary-arch-m68k-none
+binary-arch-m68k-none:: binary-arch-m68k-none-real
+build-m68k:: build-m68k-none
+build-m68k-none:: build-m68k-none-real
+setup-m68k:: setup-m68k-none
+setup-m68k-none:: setup-m68k-none-real
+source-m68k:: source-m68k-none
+source-m68k-none:: source-m68k-none-real
+binary-arch-m68k-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='m68k'
+build-m68k-none-real:
+setup-m68k-none-real:
+source-m68k-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='m68k'
+binary-arch-m68k-none:: binary-arch-m68k-none-amiga
+binary-arch-m68k-none-amiga:: binary-arch-m68k-none-amiga-real
+build-m68k-none:: build-m68k-none-amiga
+build-m68k-none-amiga:: build-m68k-none-amiga-real
+setup-m68k-none:: setup-m68k-none-amiga
+setup-m68k-none-amiga:: setup-m68k-none-amiga-real
+source-m68k-none:: source-m68k-none-amiga
+source-m68k-none-amiga:: source-m68k-none-amiga-real
+binary-arch-m68k-none-amiga-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='amiga' KCONFIG='config m68k/config m68k/config.amiga' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' KERNEL_ARCH='m68k' ABINAME='' TYPE='kernel-package' LOCALVERSION='-amiga' ARCH='m68k' COMPILER='gcc-3.3'
+build-m68k-none-amiga-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='amiga' KCONFIG='config m68k/config m68k/config.amiga' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' KERNEL_ARCH='m68k' ABINAME='' TYPE='kernel-package' LOCALVERSION='-amiga' ARCH='m68k' COMPILER='gcc-3.3'
+setup-m68k-none-amiga-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='amiga' KCONFIG='config m68k/config m68k/config.amiga' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' KERNEL_ARCH='m68k' ABINAME='' TYPE='kernel-package' LOCALVERSION='-amiga' ARCH='m68k' COMPILER='gcc-3.3'
+source-m68k-none-amiga-real:
+binary-arch-m68k-none:: binary-arch-m68k-none-mac
+binary-arch-m68k-none-mac:: binary-arch-m68k-none-mac-real
+build-m68k-none:: build-m68k-none-mac
+build-m68k-none-mac:: build-m68k-none-mac-real
+setup-m68k-none:: setup-m68k-none-mac
+setup-m68k-none-mac:: setup-m68k-none-mac-real
+source-m68k-none:: source-m68k-none-mac
+source-m68k-none-mac:: source-m68k-none-mac-real
+binary-arch-m68k-none-mac-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='mac' KCONFIG='config m68k/config m68k/config.mac' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' KERNEL_ARCH='m68k' ABINAME='' TYPE='kernel-package' LOCALVERSION='-mac' ARCH='m68k' COMPILER='gcc-3.3'
+build-m68k-none-mac-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='mac' KCONFIG='config m68k/config m68k/config.mac' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' KERNEL_ARCH='m68k' ABINAME='' TYPE='kernel-package' LOCALVERSION='-mac' ARCH='m68k' COMPILER='gcc-3.3'
+setup-m68k-none-mac-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='mac' KCONFIG='config m68k/config m68k/config.mac' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='m68k' KERNEL_ARCH='m68k' ABINAME='' TYPE='kernel-package' LOCALVERSION='-mac' ARCH='m68k' COMPILER='gcc-3.3'
+source-m68k-none-mac-real:
+binary-arch:: binary-arch-mips
+binary-arch-mips:: binary-arch-mips-real
+build:: build-mips
+build-mips:: build-mips-real
+setup:: setup-mips
+setup-mips:: setup-mips-real
+source:: source-mips
+source-mips:: source-mips-real
+binary-arch-mips-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='mips'
+build-mips-real:
+setup-mips-real:
+source-mips-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='mips'
+binary-arch-mips:: binary-arch-mips-none
+binary-arch-mips-none:: binary-arch-mips-none-real
+build-mips:: build-mips-none
+build-mips-none:: build-mips-none-real
+setup-mips:: setup-mips-none
+setup-mips-none:: setup-mips-none-real
+source-mips:: source-mips-none
+source-mips-none:: source-mips-none-real
+binary-arch-mips-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='mips'
+build-mips-none-real:
+setup-mips-none-real:
+source-mips-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='mips'
+binary-arch-mips-none:: binary-arch-mips-none-r4k-ip22
+binary-arch-mips-none-r4k-ip22:: binary-arch-mips-none-r4k-ip22-real
+build-mips-none:: build-mips-none-r4k-ip22
+build-mips-none-r4k-ip22:: build-mips-none-r4k-ip22-real
+setup-mips-none:: setup-mips-none-r4k-ip22
+setup-mips-none-r4k-ip22:: setup-mips-none-r4k-ip22-real
+source-mips-none:: source-mips-none-r4k-ip22
+source-mips-none-r4k-ip22:: source-mips-none-r4k-ip22-real
+binary-arch-mips-none-r4k-ip22-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='r4k-ip22' KCONFIG='config mips/config mips/config.r4k-ip22' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r4k-ip22' ARCH='mips' COMPILER='gcc-4.1'
+build-mips-none-r4k-ip22-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='r4k-ip22' KCONFIG='config mips/config mips/config.r4k-ip22' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r4k-ip22' ARCH='mips' COMPILER='gcc-4.1'
+setup-mips-none-r4k-ip22-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='r4k-ip22' KCONFIG='config mips/config mips/config.r4k-ip22' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r4k-ip22' ARCH='mips' COMPILER='gcc-4.1'
+source-mips-none-r4k-ip22-real:
+binary-arch-mips-none:: binary-arch-mips-none-r5k-ip32
+binary-arch-mips-none-r5k-ip32:: binary-arch-mips-none-r5k-ip32-real
+build-mips-none:: build-mips-none-r5k-ip32
+build-mips-none-r5k-ip32:: build-mips-none-r5k-ip32-real
+setup-mips-none:: setup-mips-none-r5k-ip32
+setup-mips-none-r5k-ip32:: setup-mips-none-r5k-ip32-real
+source-mips-none:: source-mips-none-r5k-ip32
+source-mips-none-r5k-ip32:: source-mips-none-r5k-ip32-real
+binary-arch-mips-none-r5k-ip32-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='r5k-ip32' KCONFIG='config mips/config mips/config.r5k-ip32' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r5k-ip32' ARCH='mips' COMPILER='gcc-4.1'
+build-mips-none-r5k-ip32-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='r5k-ip32' KCONFIG='config mips/config mips/config.r5k-ip32' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r5k-ip32' ARCH='mips' COMPILER='gcc-4.1'
+setup-mips-none-r5k-ip32-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='r5k-ip32' KCONFIG='config mips/config mips/config.r5k-ip32' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r5k-ip32' ARCH='mips' COMPILER='gcc-4.1'
+source-mips-none-r5k-ip32-real:
+binary-arch-mips-none:: binary-arch-mips-none-sb1-bcm91250a
+binary-arch-mips-none-sb1-bcm91250a:: binary-arch-mips-none-sb1-bcm91250a-real
+build-mips-none:: build-mips-none-sb1-bcm91250a
+build-mips-none-sb1-bcm91250a:: build-mips-none-sb1-bcm91250a-real
+setup-mips-none:: setup-mips-none-sb1-bcm91250a
+setup-mips-none-sb1-bcm91250a:: setup-mips-none-sb1-bcm91250a-real
+source-mips-none:: source-mips-none-sb1-bcm91250a
+source-mips-none-sb1-bcm91250a:: source-mips-none-sb1-bcm91250a-real
+binary-arch-mips-none-sb1-bcm91250a-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sb1-bcm91250a' KCONFIG='config mips/config mips/config.sb1-bcm91250a' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1-bcm91250a' ARCH='mips' COMPILER='gcc-4.1'
+build-mips-none-sb1-bcm91250a-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sb1-bcm91250a' KCONFIG='config mips/config mips/config.sb1-bcm91250a' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1-bcm91250a' ARCH='mips' COMPILER='gcc-4.1'
+setup-mips-none-sb1-bcm91250a-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sb1-bcm91250a' KCONFIG='config mips/config mips/config.sb1-bcm91250a' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1-bcm91250a' ARCH='mips' COMPILER='gcc-4.1'
+source-mips-none-sb1-bcm91250a-real:
+binary-arch-mips-none:: binary-arch-mips-none-sb1a-bcm91480b
+binary-arch-mips-none-sb1a-bcm91480b:: binary-arch-mips-none-sb1a-bcm91480b-real
+build-mips-none:: build-mips-none-sb1a-bcm91480b
+build-mips-none-sb1a-bcm91480b:: build-mips-none-sb1a-bcm91480b-real
+setup-mips-none:: setup-mips-none-sb1a-bcm91480b
+setup-mips-none-sb1a-bcm91480b:: setup-mips-none-sb1a-bcm91480b-real
+source-mips-none:: source-mips-none-sb1a-bcm91480b
+source-mips-none-sb1a-bcm91480b:: source-mips-none-sb1a-bcm91480b-real
+binary-arch-mips-none-sb1a-bcm91480b-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sb1a-bcm91480b' KCONFIG='config mips/config mips/config.sb1a-bcm91480b' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1a-bcm91480b' ARCH='mips' COMPILER='gcc-4.1'
+build-mips-none-sb1a-bcm91480b-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sb1a-bcm91480b' KCONFIG='config mips/config mips/config.sb1a-bcm91480b' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1a-bcm91480b' ARCH='mips' COMPILER='gcc-4.1'
+setup-mips-none-sb1a-bcm91480b-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sb1a-bcm91480b' KCONFIG='config mips/config mips/config.sb1a-bcm91480b' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1a-bcm91480b' ARCH='mips' COMPILER='gcc-4.1'
+source-mips-none-sb1a-bcm91480b-real:
+binary-arch-mips-none:: binary-arch-mips-none-qemu
+binary-arch-mips-none-qemu:: binary-arch-mips-none-qemu-real
+build-mips-none:: build-mips-none-qemu
+build-mips-none-qemu:: build-mips-none-qemu-real
+setup-mips-none:: setup-mips-none-qemu
+setup-mips-none-qemu:: setup-mips-none-qemu-real
+source-mips-none:: source-mips-none-qemu
+source-mips-none-qemu:: source-mips-none-qemu-real
+binary-arch-mips-none-qemu-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='qemu' KCONFIG='config mips/config mips/config.qemu' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-qemu' ARCH='mips' COMPILER='gcc-4.1'
+build-mips-none-qemu-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='qemu' KCONFIG='config mips/config mips/config.qemu' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-qemu' ARCH='mips' COMPILER='gcc-4.1'
+setup-mips-none-qemu-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='qemu' KCONFIG='config mips/config mips/config.qemu' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-qemu' ARCH='mips' COMPILER='gcc-4.1'
+source-mips-none-qemu-real:
+binary-arch:: binary-arch-mipsel
+binary-arch-mipsel:: binary-arch-mipsel-real
+build:: build-mipsel
+build-mipsel:: build-mipsel-real
+setup:: setup-mipsel
+setup-mipsel:: setup-mipsel-real
+source:: source-mipsel
+source-mipsel:: source-mipsel-real
+binary-arch-mipsel-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='mipsel'
+build-mipsel-real:
+setup-mipsel-real:
+source-mipsel-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='mipsel'
+binary-arch-mipsel:: binary-arch-mipsel-none
+binary-arch-mipsel-none:: binary-arch-mipsel-none-real
+build-mipsel:: build-mipsel-none
+build-mipsel-none:: build-mipsel-none-real
+setup-mipsel:: setup-mipsel-none
+setup-mipsel-none:: setup-mipsel-none-real
+source-mipsel:: source-mipsel-none
+source-mipsel-none:: source-mipsel-none-real
+binary-arch-mipsel-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='mipsel'
+build-mipsel-none-real:
+setup-mipsel-none-real:
+source-mipsel-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='mipsel'
+binary-arch-mipsel-none:: binary-arch-mipsel-none-r5k-cobalt
+binary-arch-mipsel-none-r5k-cobalt:: binary-arch-mipsel-none-r5k-cobalt-real
+build-mipsel-none:: build-mipsel-none-r5k-cobalt
+build-mipsel-none-r5k-cobalt:: build-mipsel-none-r5k-cobalt-real
+setup-mipsel-none:: setup-mipsel-none-r5k-cobalt
+setup-mipsel-none-r5k-cobalt:: setup-mipsel-none-r5k-cobalt-real
+source-mipsel-none:: source-mipsel-none-r5k-cobalt
+source-mipsel-none-r5k-cobalt:: source-mipsel-none-r5k-cobalt-real
+binary-arch-mipsel-none-r5k-cobalt-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='r5k-cobalt' KCONFIG='config mipsel/config mipsel/config.r5k-cobalt' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r5k-cobalt' ARCH='mipsel' COMPILER='gcc-4.1'
+build-mipsel-none-r5k-cobalt-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='r5k-cobalt' KCONFIG='config mipsel/config mipsel/config.r5k-cobalt' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r5k-cobalt' ARCH='mipsel' COMPILER='gcc-4.1'
+setup-mipsel-none-r5k-cobalt-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='r5k-cobalt' KCONFIG='config mipsel/config mipsel/config.r5k-cobalt' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r5k-cobalt' ARCH='mipsel' COMPILER='gcc-4.1'
+source-mipsel-none-r5k-cobalt-real:
+binary-arch-mipsel-none:: binary-arch-mipsel-none-sb1-bcm91250a
+binary-arch-mipsel-none-sb1-bcm91250a:: binary-arch-mipsel-none-sb1-bcm91250a-real
+build-mipsel-none:: build-mipsel-none-sb1-bcm91250a
+build-mipsel-none-sb1-bcm91250a:: build-mipsel-none-sb1-bcm91250a-real
+setup-mipsel-none:: setup-mipsel-none-sb1-bcm91250a
+setup-mipsel-none-sb1-bcm91250a:: setup-mipsel-none-sb1-bcm91250a-real
+source-mipsel-none:: source-mipsel-none-sb1-bcm91250a
+source-mipsel-none-sb1-bcm91250a:: source-mipsel-none-sb1-bcm91250a-real
+binary-arch-mipsel-none-sb1-bcm91250a-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sb1-bcm91250a' KCONFIG='config mipsel/config mipsel/config.sb1-bcm91250a' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1-bcm91250a' ARCH='mipsel' COMPILER='gcc-4.1'
+build-mipsel-none-sb1-bcm91250a-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sb1-bcm91250a' KCONFIG='config mipsel/config mipsel/config.sb1-bcm91250a' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1-bcm91250a' ARCH='mipsel' COMPILER='gcc-4.1'
+setup-mipsel-none-sb1-bcm91250a-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sb1-bcm91250a' KCONFIG='config mipsel/config mipsel/config.sb1-bcm91250a' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1-bcm91250a' ARCH='mipsel' COMPILER='gcc-4.1'
+source-mipsel-none-sb1-bcm91250a-real:
+binary-arch-mipsel-none:: binary-arch-mipsel-none-sb1a-bcm91480b
+binary-arch-mipsel-none-sb1a-bcm91480b:: binary-arch-mipsel-none-sb1a-bcm91480b-real
+build-mipsel-none:: build-mipsel-none-sb1a-bcm91480b
+build-mipsel-none-sb1a-bcm91480b:: build-mipsel-none-sb1a-bcm91480b-real
+setup-mipsel-none:: setup-mipsel-none-sb1a-bcm91480b
+setup-mipsel-none-sb1a-bcm91480b:: setup-mipsel-none-sb1a-bcm91480b-real
+source-mipsel-none:: source-mipsel-none-sb1a-bcm91480b
+source-mipsel-none-sb1a-bcm91480b:: source-mipsel-none-sb1a-bcm91480b-real
+binary-arch-mipsel-none-sb1a-bcm91480b-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sb1a-bcm91480b' KCONFIG='config mipsel/config mipsel/config.sb1a-bcm91480b' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1a-bcm91480b' ARCH='mipsel' COMPILER='gcc-4.1'
+build-mipsel-none-sb1a-bcm91480b-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sb1a-bcm91480b' KCONFIG='config mipsel/config mipsel/config.sb1a-bcm91480b' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1a-bcm91480b' ARCH='mipsel' COMPILER='gcc-4.1'
+setup-mipsel-none-sb1a-bcm91480b-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sb1a-bcm91480b' KCONFIG='config mipsel/config mipsel/config.sb1a-bcm91480b' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sb1a-bcm91480b' ARCH='mipsel' COMPILER='gcc-4.1'
+source-mipsel-none-sb1a-bcm91480b-real:
+binary-arch-mipsel-none:: binary-arch-mipsel-none-r3k-kn02
+binary-arch-mipsel-none-r3k-kn02:: binary-arch-mipsel-none-r3k-kn02-real
+build-mipsel-none:: build-mipsel-none-r3k-kn02
+build-mipsel-none-r3k-kn02:: build-mipsel-none-r3k-kn02-real
+setup-mipsel-none:: setup-mipsel-none-r3k-kn02
+setup-mipsel-none-r3k-kn02:: setup-mipsel-none-r3k-kn02-real
+source-mipsel-none:: source-mipsel-none-r3k-kn02
+source-mipsel-none-r3k-kn02:: source-mipsel-none-r3k-kn02-real
+binary-arch-mipsel-none-r3k-kn02-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='r3k-kn02' KCONFIG='config mipsel/config mipsel/config.r3k-kn02' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r3k-kn02' ARCH='mipsel' COMPILER='gcc-4.1'
+build-mipsel-none-r3k-kn02-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='r3k-kn02' KCONFIG='config mipsel/config mipsel/config.r3k-kn02' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r3k-kn02' ARCH='mipsel' COMPILER='gcc-4.1'
+setup-mipsel-none-r3k-kn02-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='r3k-kn02' KCONFIG='config mipsel/config mipsel/config.r3k-kn02' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r3k-kn02' ARCH='mipsel' COMPILER='gcc-4.1'
+source-mipsel-none-r3k-kn02-real:
+binary-arch-mipsel-none:: binary-arch-mipsel-none-r4k-kn04
+binary-arch-mipsel-none-r4k-kn04:: binary-arch-mipsel-none-r4k-kn04-real
+build-mipsel-none:: build-mipsel-none-r4k-kn04
+build-mipsel-none-r4k-kn04:: build-mipsel-none-r4k-kn04-real
+setup-mipsel-none:: setup-mipsel-none-r4k-kn04
+setup-mipsel-none-r4k-kn04:: setup-mipsel-none-r4k-kn04-real
+source-mipsel-none:: source-mipsel-none-r4k-kn04
+source-mipsel-none-r4k-kn04:: source-mipsel-none-r4k-kn04-real
+binary-arch-mipsel-none-r4k-kn04-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='r4k-kn04' KCONFIG='config mipsel/config mipsel/config.r4k-kn04' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r4k-kn04' ARCH='mipsel' COMPILER='gcc-4.1'
+build-mipsel-none-r4k-kn04-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='r4k-kn04' KCONFIG='config mipsel/config mipsel/config.r4k-kn04' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r4k-kn04' ARCH='mipsel' COMPILER='gcc-4.1'
+setup-mipsel-none-r4k-kn04-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='r4k-kn04' KCONFIG='config mipsel/config mipsel/config.r4k-kn04' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-r4k-kn04' ARCH='mipsel' COMPILER='gcc-4.1'
+source-mipsel-none-r4k-kn04-real:
+binary-arch-mipsel-none:: binary-arch-mipsel-none-qemu
+binary-arch-mipsel-none-qemu:: binary-arch-mipsel-none-qemu-real
+build-mipsel-none:: build-mipsel-none-qemu
+build-mipsel-none-qemu:: build-mipsel-none-qemu-real
+setup-mipsel-none:: setup-mipsel-none-qemu
+setup-mipsel-none-qemu:: setup-mipsel-none-qemu-real
+source-mipsel-none:: source-mipsel-none-qemu
+source-mipsel-none-qemu:: source-mipsel-none-qemu-real
+binary-arch-mipsel-none-qemu-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='qemu' KCONFIG='config mipsel/config mipsel/config.qemu' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-qemu' ARCH='mipsel' COMPILER='gcc-4.1'
+build-mipsel-none-qemu-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='qemu' KCONFIG='config mipsel/config mipsel/config.qemu' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-qemu' ARCH='mipsel' COMPILER='gcc-4.1'
+setup-mipsel-none-qemu-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='qemu' KCONFIG='config mipsel/config mipsel/config.qemu' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' MODULES='True' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='mips' KERNEL_ARCH='mips' ABINAME='' TYPE='kernel-package' LOCALVERSION='-qemu' ARCH='mipsel' COMPILER='gcc-4.1'
+source-mipsel-none-qemu-real:
+binary-arch:: binary-arch-powerpc
+binary-arch-powerpc:: binary-arch-powerpc-real
+build:: build-powerpc
+build-powerpc:: build-powerpc-real
+setup:: setup-powerpc
+setup-powerpc:: setup-powerpc-real
+source:: source-powerpc
+source-powerpc:: source-powerpc-real
+binary-arch-powerpc-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='powerpc'
+build-powerpc-real:
+setup-powerpc-real:
+source-powerpc-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='powerpc'
+binary-arch-powerpc:: binary-arch-powerpc-none
+binary-arch-powerpc-none:: binary-arch-powerpc-none-real
+build-powerpc:: build-powerpc-none
+build-powerpc-none:: build-powerpc-none-real
+setup-powerpc:: setup-powerpc-none
+setup-powerpc-none:: setup-powerpc-none-real
+source-powerpc:: source-powerpc-none
+source-powerpc-none:: source-powerpc-none-real
+binary-arch-powerpc-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='powerpc'
+build-powerpc-none-real:
+setup-powerpc-none-real:
+source-powerpc-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='powerpc'
+binary-arch-powerpc-none:: binary-arch-powerpc-none-powerpc
+binary-arch-powerpc-none-powerpc:: binary-arch-powerpc-none-powerpc-real
+build-powerpc-none:: build-powerpc-none-powerpc
+build-powerpc-none-powerpc:: build-powerpc-none-powerpc-real
+setup-powerpc-none:: setup-powerpc-none-powerpc
+setup-powerpc-none-powerpc:: setup-powerpc-none-powerpc-real
+source-powerpc-none:: source-powerpc-none-powerpc
+source-powerpc-none-powerpc:: source-powerpc-none-powerpc-real
+binary-arch-powerpc-none-powerpc-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='powerpc' KCONFIG='config powerpc/config powerpc/config.powerpc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-none-powerpc-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='powerpc' KCONFIG='config powerpc/config powerpc/config.powerpc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-none-powerpc-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='powerpc' KCONFIG='config powerpc/config powerpc/config.powerpc' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-none-powerpc-real:
+binary-arch-powerpc-none:: binary-arch-powerpc-none-powerpc-smp
+binary-arch-powerpc-none-powerpc-smp:: binary-arch-powerpc-none-powerpc-smp-real
+build-powerpc-none:: build-powerpc-none-powerpc-smp
+build-powerpc-none-powerpc-smp:: build-powerpc-none-powerpc-smp-real
+setup-powerpc-none:: setup-powerpc-none-powerpc-smp
+setup-powerpc-none-powerpc-smp:: setup-powerpc-none-powerpc-smp-real
+source-powerpc-none:: source-powerpc-none-powerpc-smp
+source-powerpc-none-powerpc-smp:: source-powerpc-none-powerpc-smp-real
+binary-arch-powerpc-none-powerpc-smp-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='powerpc-smp' KCONFIG='config powerpc/config powerpc/config.powerpc-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc-smp' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-none-powerpc-smp-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='powerpc-smp' KCONFIG='config powerpc/config powerpc/config.powerpc-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc-smp' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-none-powerpc-smp-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='powerpc-smp' KCONFIG='config powerpc/config powerpc/config.powerpc-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc-smp' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-none-powerpc-smp-real:
+binary-arch-powerpc-none:: binary-arch-powerpc-none-powerpc-miboot
+binary-arch-powerpc-none-powerpc-miboot:: binary-arch-powerpc-none-powerpc-miboot-real
+build-powerpc-none:: build-powerpc-none-powerpc-miboot
+build-powerpc-none-powerpc-miboot:: build-powerpc-none-powerpc-miboot-real
+setup-powerpc-none:: setup-powerpc-none-powerpc-miboot
+setup-powerpc-none-powerpc-miboot:: setup-powerpc-none-powerpc-miboot-real
+source-powerpc-none:: source-powerpc-none-powerpc-miboot
+source-powerpc-none-powerpc-miboot:: source-powerpc-none-powerpc-miboot-real
+binary-arch-powerpc-none-powerpc-miboot-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='powerpc-miboot' KCONFIG='config powerpc/config powerpc/config.powerpc-miboot' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc-miboot' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-none-powerpc-miboot-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='powerpc-miboot' KCONFIG='config powerpc/config powerpc/config.powerpc-miboot' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc-miboot' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-none-powerpc-miboot-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='powerpc-miboot' KCONFIG='config powerpc/config powerpc/config.powerpc-miboot' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc-miboot' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-none-powerpc-miboot-real:
+binary-arch-powerpc-none:: binary-arch-powerpc-none-powerpc64
+binary-arch-powerpc-none-powerpc64:: binary-arch-powerpc-none-powerpc64-real
+build-powerpc-none:: build-powerpc-none-powerpc64
+build-powerpc-none-powerpc64:: build-powerpc-none-powerpc64-real
+setup-powerpc-none:: setup-powerpc-none-powerpc64
+setup-powerpc-none-powerpc64:: setup-powerpc-none-powerpc64-real
+source-powerpc-none:: source-powerpc-none-powerpc64
+source-powerpc-none-powerpc64:: source-powerpc-none-powerpc64-real
+binary-arch-powerpc-none-powerpc64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='powerpc64' KCONFIG='config powerpc/config powerpc/config.powerpc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='powerpc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc64' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-none-powerpc64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='powerpc64' KCONFIG='config powerpc/config powerpc/config.powerpc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='powerpc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc64' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-none-powerpc64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='powerpc64' KCONFIG='config powerpc/config powerpc/config.powerpc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='powerpc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-powerpc64' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-none-powerpc64-real:
+binary-arch-powerpc-none:: binary-arch-powerpc-none-prep
+binary-arch-powerpc-none-prep:: binary-arch-powerpc-none-prep-real
+build-powerpc-none:: build-powerpc-none-prep
+build-powerpc-none-prep:: build-powerpc-none-prep-real
+setup-powerpc-none:: setup-powerpc-none-prep
+setup-powerpc-none-prep:: setup-powerpc-none-prep-real
+source-powerpc-none:: source-powerpc-none-prep
+source-powerpc-none-prep:: source-powerpc-none-prep-real
+binary-arch-powerpc-none-prep-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='prep' KCONFIG='config powerpc/config powerpc/config.prep' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='prep' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='ppc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-prep' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-none-prep-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='prep' KCONFIG='config powerpc/config powerpc/config.prep' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='prep' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='ppc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-prep' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-none-prep-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='prep' KCONFIG='config powerpc/config powerpc/config.prep' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='prep' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='ppc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-prep' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-none-prep-real:
+binary-arch-powerpc:: binary-arch-powerpc-vserver
+binary-arch-powerpc-vserver:: binary-arch-powerpc-vserver-real
+build-powerpc:: build-powerpc-vserver
+build-powerpc-vserver:: build-powerpc-vserver-real
+setup-powerpc:: setup-powerpc-vserver
+setup-powerpc-vserver:: setup-powerpc-vserver-real
+source-powerpc:: source-powerpc-vserver
+source-powerpc-vserver:: source-powerpc-vserver-real
+binary-arch-powerpc-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='powerpc'
+build-powerpc-vserver-real:
+setup-powerpc-vserver-real:
+source-powerpc-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='powerpc'
+binary-arch-powerpc-vserver:: binary-arch-powerpc-vserver-powerpc
+binary-arch-powerpc-vserver-powerpc:: binary-arch-powerpc-vserver-powerpc-real
+build-powerpc-vserver:: build-powerpc-vserver-powerpc
+build-powerpc-vserver-powerpc:: build-powerpc-vserver-powerpc-real
+setup-powerpc-vserver:: setup-powerpc-vserver-powerpc
+setup-powerpc-vserver-powerpc:: setup-powerpc-vserver-powerpc-real
+source-powerpc-vserver:: source-powerpc-vserver-powerpc
+source-powerpc-vserver-powerpc:: source-powerpc-vserver-powerpc-real
+binary-arch-powerpc-vserver-powerpc-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='powerpc' KCONFIG='config powerpc/config _vserver/config powerpc/config.powerpc-smp' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-powerpc' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-vserver-powerpc-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='powerpc' KCONFIG='config powerpc/config _vserver/config powerpc/config.powerpc-smp' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-powerpc' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-vserver-powerpc-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='powerpc' KCONFIG='config powerpc/config _vserver/config powerpc/config.powerpc-smp' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='ppc' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-powerpc' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-vserver-powerpc-real:
+binary-arch-powerpc-vserver:: binary-arch-powerpc-vserver-powerpc64
+binary-arch-powerpc-vserver-powerpc64:: binary-arch-powerpc-vserver-powerpc64-real
+build-powerpc-vserver:: build-powerpc-vserver-powerpc64
+build-powerpc-vserver-powerpc64:: build-powerpc-vserver-powerpc64-real
+setup-powerpc-vserver:: setup-powerpc-vserver-powerpc64
+setup-powerpc-vserver-powerpc64:: setup-powerpc-vserver-powerpc64-real
+source-powerpc-vserver:: source-powerpc-vserver-powerpc64
+source-powerpc-vserver-powerpc64:: source-powerpc-vserver-powerpc64-real
+binary-arch-powerpc-vserver-powerpc64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='powerpc64' KCONFIG='config powerpc/config _vserver/config powerpc/config.powerpc64' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='powerpc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-powerpc64' ARCH='powerpc' COMPILER='gcc-4.1'
+build-powerpc-vserver-powerpc64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='powerpc64' KCONFIG='config powerpc/config _vserver/config powerpc/config.powerpc64' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='powerpc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-powerpc64' ARCH='powerpc' COMPILER='gcc-4.1'
+setup-powerpc-vserver-powerpc64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='powerpc64' KCONFIG='config powerpc/config _vserver/config powerpc/config.powerpc64' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='powerpc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='powerpc ppc m68k' KERNEL_ARCH='powerpc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-powerpc64' ARCH='powerpc' COMPILER='gcc-4.1'
+source-powerpc-vserver-powerpc64-real:
+binary-arch:: binary-arch-s390
+binary-arch-s390:: binary-arch-s390-real
+build:: build-s390
+build-s390:: build-s390-real
+setup:: setup-s390
+setup-s390:: setup-s390-real
+source:: source-s390
+source-s390:: source-s390-real
+binary-arch-s390-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='s390'
+build-s390-real:
+setup-s390-real:
+source-s390-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='s390'
+binary-arch-s390:: binary-arch-s390-none
+binary-arch-s390-none:: binary-arch-s390-none-real
+build-s390:: build-s390-none
+build-s390-none:: build-s390-none-real
+setup-s390:: setup-s390-none
+setup-s390-none:: setup-s390-none-real
+source-s390:: source-s390-none
+source-s390-none:: source-s390-none-real
+binary-arch-s390-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='s390'
+build-s390-none-real:
+setup-s390-none-real:
+source-s390-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='s390'
+binary-arch-s390-none:: binary-arch-s390-none-s390
+binary-arch-s390-none-s390:: binary-arch-s390-none-s390-real
+build-s390-none:: build-s390-none-s390
+build-s390-none-s390:: build-s390-none-s390-real
+setup-s390-none:: setup-s390-none-s390
+setup-s390-none-s390:: setup-s390-none-s390-real
+source-s390-none:: source-s390-none-s390
+source-s390-none-s390:: source-s390-none-s390-real
+binary-arch-s390-none-s390-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='s390' KCONFIG='config s390/config s390/config.s390' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s390' ARCH='s390' COMPILER='gcc-4.1'
+build-s390-none-s390-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='s390' KCONFIG='config s390/config s390/config.s390' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s390' ARCH='s390' COMPILER='gcc-4.1'
+setup-s390-none-s390-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='s390' KCONFIG='config s390/config s390/config.s390' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s390' ARCH='s390' COMPILER='gcc-4.1'
+source-s390-none-s390-real:
+binary-arch-s390-none:: binary-arch-s390-none-s390-tape
+binary-arch-s390-none-s390-tape:: binary-arch-s390-none-s390-tape-real
+build-s390-none:: build-s390-none-s390-tape
+build-s390-none-s390-tape:: build-s390-none-s390-tape-real
+setup-s390-none:: setup-s390-none-s390-tape
+setup-s390-none-s390-tape:: setup-s390-none-s390-tape-real
+source-s390-none:: source-s390-none-s390-tape
+source-s390-none-s390-tape:: source-s390-none-s390-tape-real
+binary-arch-s390-none-s390-tape-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='s390-tape' KCONFIG='config s390/config s390/config.s390-tape' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='plain-s390-tape' LOCALVERSION='-s390-tape' ARCH='s390' COMPILER='gcc-4.1'
+build-s390-none-s390-tape-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='s390-tape' KCONFIG='config s390/config s390/config.s390-tape' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='plain-s390-tape' LOCALVERSION='-s390-tape' ARCH='s390' COMPILER='gcc-4.1'
+setup-s390-none-s390-tape-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='s390-tape' KCONFIG='config s390/config s390/config.s390-tape' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRAMFS='False' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='plain-s390-tape' LOCALVERSION='-s390-tape' ARCH='s390' COMPILER='gcc-4.1'
+source-s390-none-s390-tape-real:
+binary-arch-s390-none:: binary-arch-s390-none-s390x
+binary-arch-s390-none-s390x:: binary-arch-s390-none-s390x-real
+build-s390-none:: build-s390-none-s390x
+build-s390-none-s390x:: build-s390-none-s390x-real
+setup-s390-none:: setup-s390-none-s390x
+setup-s390-none-s390x:: setup-s390-none-s390x-real
+source-s390-none:: source-s390-none-s390x
+source-s390-none-s390x:: source-s390-none-s390x-real
+binary-arch-s390-none-s390x-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='s390x' KCONFIG='config s390/config s390/config.s390x' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s390x' ARCH='s390' COMPILER='gcc-4.1'
+build-s390-none-s390x-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='s390x' KCONFIG='config s390/config s390/config.s390x' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s390x' ARCH='s390' COMPILER='gcc-4.1'
+setup-s390-none-s390x-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='s390x' KCONFIG='config s390/config s390/config.s390x' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-s390x' ARCH='s390' COMPILER='gcc-4.1'
+source-s390-none-s390x-real:
+binary-arch-s390:: binary-arch-s390-vserver
+binary-arch-s390-vserver:: binary-arch-s390-vserver-real
+build-s390:: build-s390-vserver
+build-s390-vserver:: build-s390-vserver-real
+setup-s390:: setup-s390-vserver
+setup-s390-vserver:: setup-s390-vserver-real
+source-s390:: source-s390-vserver
+source-s390-vserver:: source-s390-vserver-real
+binary-arch-s390-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='s390'
+build-s390-vserver-real:
+setup-s390-vserver-real:
+source-s390-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='s390'
+binary-arch-s390-vserver:: binary-arch-s390-vserver-s390x
+binary-arch-s390-vserver-s390x:: binary-arch-s390-vserver-s390x-real
+build-s390-vserver:: build-s390-vserver-s390x
+build-s390-vserver-s390x:: build-s390-vserver-s390x-real
+setup-s390-vserver:: setup-s390-vserver-s390x
+setup-s390-vserver-s390x:: setup-s390-vserver-s390x-real
+source-s390-vserver:: source-s390-vserver-s390x
+source-s390-vserver-s390x:: source-s390-vserver-s390x-real
+binary-arch-s390-vserver-s390x-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='s390x' KCONFIG='config s390/config _vserver/config s390/config.s390x' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-s390x' ARCH='s390' COMPILER='gcc-4.1'
+build-s390-vserver-s390x-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='s390x' KCONFIG='config s390/config _vserver/config s390/config.s390x' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-s390x' ARCH='s390' COMPILER='gcc-4.1'
+setup-s390-vserver-s390x-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='s390x' KCONFIG='config s390/config _vserver/config s390/config.s390x' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' KERNEL_HEADER_DIRS='s390' KERNEL_ARCH='s390' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-s390x' ARCH='s390' COMPILER='gcc-4.1'
+source-s390-vserver-s390x-real:
+binary-arch:: binary-arch-sparc
+binary-arch-sparc:: binary-arch-sparc-real
+build:: build-sparc
+build-sparc:: build-sparc-real
+setup:: setup-sparc
+setup-sparc:: setup-sparc-real
+source:: source-sparc
+source-sparc:: source-sparc-real
+binary-arch-sparc-real:
+ $(MAKE) -f debian/rules.real binary-arch-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='sparc'
+build-sparc-real:
+setup-sparc-real:
+source-sparc-real:
+ $(MAKE) -f debian/rules.real source-arch MAJOR='2.6' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' VERSION='2.6.18' ABINAME='' ARCH='sparc'
+binary-arch-sparc:: binary-arch-sparc-none
+binary-arch-sparc-none:: binary-arch-sparc-none-real
+build-sparc:: build-sparc-none
+build-sparc-none:: build-sparc-none-real
+setup-sparc:: setup-sparc-none
+setup-sparc-none:: setup-sparc-none-real
+source-sparc:: source-sparc-none
+source-sparc-none:: source-sparc-none-real
+binary-arch-sparc-none-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='sparc'
+build-sparc-none-real:
+setup-sparc-none-real:
+source-sparc-none-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' ABINAME='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='sparc'
+binary-arch-sparc-none:: binary-arch-sparc-none-sparc32
+binary-arch-sparc-none-sparc32:: binary-arch-sparc-none-sparc32-real
+build-sparc-none:: build-sparc-none-sparc32
+build-sparc-none-sparc32:: build-sparc-none-sparc32-real
+setup-sparc-none:: setup-sparc-none-sparc32
+setup-sparc-none-sparc32:: setup-sparc-none-sparc32-real
+source-sparc-none:: source-sparc-none-sparc32
+source-sparc-none-sparc32:: source-sparc-none-sparc32-real
+binary-arch-sparc-none-sparc32-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sparc32' KCONFIG='config sparc/config sparc/config.sparc32' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' IMAGE_POSTPROC='sparc32-image-postproc' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc32' ARCH='sparc' COMPILER='gcc-4.1'
+build-sparc-none-sparc32-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sparc32' KCONFIG='config sparc/config sparc/config.sparc32' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' IMAGE_POSTPROC='sparc32-image-postproc' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc32' ARCH='sparc' COMPILER='gcc-4.1'
+setup-sparc-none-sparc32-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sparc32' KCONFIG='config sparc/config sparc/config.sparc32' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' IMAGE_POSTPROC='sparc32-image-postproc' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc32' ARCH='sparc' COMPILER='gcc-4.1'
+source-sparc-none-sparc32-real:
+binary-arch-sparc-none:: binary-arch-sparc-none-sparc64
+binary-arch-sparc-none-sparc64:: binary-arch-sparc-none-sparc64-real
+build-sparc-none:: build-sparc-none-sparc64
+build-sparc-none-sparc64:: build-sparc-none-sparc64-real
+setup-sparc-none:: setup-sparc-none-sparc64
+setup-sparc-none-sparc64:: setup-sparc-none-sparc64-real
+source-sparc-none:: source-sparc-none-sparc64
+source-sparc-none-sparc64:: source-sparc-none-sparc64-real
+binary-arch-sparc-none-sparc64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sparc64' KCONFIG='config sparc/config sparc/config.sparc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc64' ARCH='sparc' COMPILER='gcc-4.1'
+build-sparc-none-sparc64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sparc64' KCONFIG='config sparc/config sparc/config.sparc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc64' ARCH='sparc' COMPILER='gcc-4.1'
+setup-sparc-none-sparc64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sparc64' KCONFIG='config sparc/config sparc/config.sparc64' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc64' ARCH='sparc' COMPILER='gcc-4.1'
+source-sparc-none-sparc64-real:
+binary-arch-sparc-none:: binary-arch-sparc-none-sparc64-smp
+binary-arch-sparc-none-sparc64-smp:: binary-arch-sparc-none-sparc64-smp-real
+build-sparc-none:: build-sparc-none-sparc64-smp
+build-sparc-none-sparc64-smp:: build-sparc-none-sparc64-smp-real
+setup-sparc-none:: setup-sparc-none-sparc64-smp
+setup-sparc-none-sparc64-smp:: setup-sparc-none-sparc64-smp-real
+source-sparc-none:: source-sparc-none-sparc64-smp
+source-sparc-none-sparc64-smp:: source-sparc-none-sparc64-smp-real
+binary-arch-sparc-none-sparc64-smp-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sparc64-smp' KCONFIG='config sparc/config sparc/config.sparc64-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc64-smp' ARCH='sparc' COMPILER='gcc-4.1'
+build-sparc-none-sparc64-smp-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sparc64-smp' KCONFIG='config sparc/config sparc/config.sparc64-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc64-smp' ARCH='sparc' COMPILER='gcc-4.1'
+setup-sparc-none-sparc64-smp-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sparc64-smp' KCONFIG='config sparc/config sparc/config.sparc64-smp' LOCALVERSION_HEADERS='' SUBARCH='none' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-sparc64-smp' ARCH='sparc' COMPILER='gcc-4.1'
+source-sparc-none-sparc64-smp-real:
+binary-arch-sparc:: binary-arch-sparc-vserver
+binary-arch-sparc-vserver:: binary-arch-sparc-vserver-real
+build-sparc:: build-sparc-vserver
+build-sparc-vserver:: build-sparc-vserver-real
+setup-sparc:: setup-sparc-vserver
+setup-sparc-vserver:: setup-sparc-vserver-real
+source-sparc:: source-sparc-vserver
+source-sparc-vserver:: source-sparc-vserver-real
+binary-arch-sparc-vserver-real:
+ $(MAKE) -f debian/rules.real binary-arch-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='sparc'
+build-sparc-vserver-real:
+setup-sparc-vserver-real:
+source-sparc-vserver-real:
+ $(MAKE) -f debian/rules.real source-subarch SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' LOCALVERSION_HEADERS='-vserver' MAJOR='2.6' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' ABINAME='' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' ARCH='sparc'
+binary-arch-sparc-vserver:: binary-arch-sparc-vserver-sparc64
+binary-arch-sparc-vserver-sparc64:: binary-arch-sparc-vserver-sparc64-real
+build-sparc-vserver:: build-sparc-vserver-sparc64
+build-sparc-vserver-sparc64:: build-sparc-vserver-sparc64-real
+setup-sparc-vserver:: setup-sparc-vserver-sparc64
+setup-sparc-vserver-sparc64:: setup-sparc-vserver-sparc64-real
+source-sparc-vserver:: source-sparc-vserver-sparc64
+source-sparc-vserver-sparc64:: source-sparc-vserver-sparc64-real
+binary-arch-sparc-vserver-sparc64-real:
+ $(MAKE) -f debian/rules.real binary-arch-flavour MAJOR='2.6' FLAVOUR='sparc64' KCONFIG='config sparc/config _vserver/config sparc/config.sparc64-smp' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-sparc64' ARCH='sparc' COMPILER='gcc-4.1'
+build-sparc-vserver-sparc64-real:
+ $(MAKE) -f debian/rules.real build MAJOR='2.6' FLAVOUR='sparc64' KCONFIG='config sparc/config _vserver/config sparc/config.sparc64-smp' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-sparc64' ARCH='sparc' COMPILER='gcc-4.1'
+setup-sparc-vserver-sparc64-real:
+ $(MAKE) -f debian/rules.real setup-flavour MAJOR='2.6' FLAVOUR='sparc64' KCONFIG='config sparc/config _vserver/config sparc/config.sparc64-smp' LOCALVERSION_HEADERS='-vserver' SUBARCH='vserver' UPSTREAMVERSION='2.6.18-6~2.6.19-rc5' INITRD_CMD='mkinitramfs-kpkg mkinitrd.yaird' MODULES='True' SOURCEVERSION='2.6.18-6~2.6.19-rc5-1' KPKG_SUBARCH='sparc64' VERSION='2.6.18' KERNEL_HEADER_DIRS='sparc sparc64' KERNEL_ARCH='sparc64' ABINAME='' TYPE='kernel-package' LOCALVERSION='-vserver-sparc64' ARCH='sparc' COMPILER='gcc-4.1'
+source-sparc-vserver-sparc64-real:
Added: people/maks-guest/linux-2.6/debian/rules.real
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/rules.real Sat Nov 11 02:48:00 2006
@@ -0,0 +1,407 @@
+#
+# This Makefile executes the unpack/build/binary targets for a single
+# subarch, which is passed in the subarch variable. Empty subarch
+# variable means that we are building for an arch without the subarch.
+# Additionally, variables version, abiname and ltver are
+# expected to be available (need to be exported from the parent process).
+#
+SHELL := bash -e
+DEB_HOST_ARCH := $(shell dpkg-architecture -a'$(ARCH)' -qDEB_HOST_ARCH)
+DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -a'$(ARCH)' -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_ARCH := $(shell dpkg-architecture -a'$(ARCH)' -qDEB_BUILD_ARCH)
+
+export PYTHONPATH = $(CURDIR)/debian/lib/python
+export DH_OPTIONS
+export DEB_HOST_ARCH DEB_HOST_GNU_TYPE DEB_BUILD_ARCH
+
+#
+# Build the list of common config files to be included
+#
+ifeq ($(SUBARCH),none)
+ basedir := debian/arch/$(ARCH)
+else
+ basedir := debian/arch/$(ARCH)/$(SUBARCH)
+endif
+
+-include $(basedir)/Makefile.inc
+
+include debian/rules.defs
+
+#
+# Here we construct the command lines for different make-kpkg
+# calls (build, linux-image, linux-headers) based on the values
+# of variables defined so far and provided by the arch/subarch
+# in Makefile.inc. @flavour@ in the expressions is going to be
+# replaced by the flavour for which the command is run.
+#
+kpkg_image := make-kpkg
+kpkg_image += --arch '$(ARCH)'
+kpkg_image += --stem linux
+kpkg_image += --config silentoldconfig
+ifneq ($(INITRAMFS),False)
+ kpkg_image += --initrd
+endif
+ifdef KPKG_SUBARCH
+ kpkg_image += --subarch '$(KPKG_SUBARCH)'
+endif
+setup_env := env -u ABINAME -u ARCH -u SUBARCH -u FLAVOUR -u VERSION -u LOCALVERSION -u MAKEFLAGS
+ifneq ($(DEB_BUILD_ARCH),$(DEB_HOST_ARCH))
+ kpkg_image += --cross-compile='$(DEB_HOST_GNU_TYPE)'
+endif
+
+ifdef DEBIAN_KERNEL_JOBS
+ setup_env_kpkg_jobs = CONCURRENCY_LEVEL=$(DEBIAN_KERNEL_JOBS)
+ JOBS_ARG = -j$(DEBIAN_KERNEL_JOBS)
+endif
+
+#
+# Targets
+#
+binary-arch-arch: install-headers-$(ARCH)
+binary-arch-subarch: install-headers-$(ARCH)-$(SUBARCH)
+binary-arch-flavour: install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE)
+ifeq ($(MODULES),True)
+ binary-arch-flavour: install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR)
+endif
+
+binary-indep: install-doc
+binary-indep: install-patch
+binary-indep: install-source
+binary-indep: install-support
+binary-indep: install-tree
+
+build: $(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE)
+
+setup-flavour: $(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE)
+
+source-arch: $(STAMPS_DIR)/source
+source-subarch: $(STAMPS_DIR)/source-$(ARCH)-$(SUBARCH)
+
+$(BUILD_DIR)/config.$(ARCH)-$(SUBARCH)-$(FLAVOUR): $(foreach t,$(KCONFIG),debian/arch/$(t))
+ python2.4 debian/bin/kconfig.py '$@' $(KCONFIG)
+
+$(BUILD_DIR)/linux-source-$(UPSTREAMVERSION).tar.bz2: SOURCE_DIR=$(BUILD_DIR)/source
+$(BUILD_DIR)/linux-source-$(UPSTREAMVERSION).tar.bz2: DIR = $(BUILD_DIR)/linux-source-$(UPSTREAMVERSION)
+$(BUILD_DIR)/linux-source-$(UPSTREAMVERSION).tar.bz2: $(STAMPS_DIR)/source
+ rm -rf '$@' '$(DIR)'
+ cp -al '$(SOURCE_DIR)' '$(DIR)'
+ chmod -R u+rw,go=rX '$(DIR)'
+ cd '$(BUILD_DIR)'; tar -cjf 'linux-source-$(UPSTREAMVERSION).tar.bz2' 'linux-source-$(UPSTREAMVERSION)'
+ rm -rf '$(DIR)'
+
+define patch_cmd
+cd '$(DIR)'; python2.4 '$(CURDIR)/debian/bin/patch.apply' --overwrite-home='$(CURDIR)/debian/patches'
+endef
+
+srcfiles := $(filter-out debian, $(wildcard * .[^.]*))
+$(STAMPS_DIR)/source: DIR=$(BUILD_DIR)/source
+$(STAMPS_DIR)/source:
+ rm -rf '$(DIR)'
+ mkdir -p '$(DIR)'
+ cp -al $(srcfiles) '$(DIR)'
+ $(patch_cmd)
+ touch '$@'
+
+$(STAMPS_DIR)/source-$(ARCH)-$(SUBARCH): SOURCE_DIR=$(BUILD_DIR)/source
+$(STAMPS_DIR)/source-$(ARCH)-$(SUBARCH): DIR=$(BUILD_DIR)/source-$(ARCH)-$(SUBARCH)
+$(STAMPS_DIR)/source-$(ARCH)-$(SUBARCH): $(STAMPS_DIR)/source
+ rm -rf '$(DIR)'
+ cp -al '$(SOURCE_DIR)' '$(DIR)'
+ mkdir -p '$(DIR)/debian'
+ cp debian/changelog '$(DIR)/debian'
+ cp debian/copyright '$(DIR)/debian'
+ cp debian/control '$(DIR)/debian/control'
+ touch '$(DIR)/debian/official'
+ $(patch_cmd) -a $(ARCH) -s $(SUBARCH)
+ touch '$@'
+
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): CONFIG=$(BUILD_DIR)/config.$(ARCH)-$(SUBARCH)-$(FLAVOUR)
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): SOURCE_DIR=$(BUILD_DIR)/source-$(ARCH)-$(SUBARCH)
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): DIR=$(BUILD_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): $(BUILD_DIR)/config.$(ARCH)-$(SUBARCH)-$(FLAVOUR) $(STAMPS_DIR)/source-$(ARCH)-$(SUBARCH)
+
+define SETUP_DIR
+ rm -rf '$(DIR)'
+ cp -al '$(SOURCE_DIR)' '$(DIR)'
+ cp '$(CONFIG)' '$(DIR)/.config'
+ echo '$(ABINAME)$(LOCALVERSION)' > '$(DIR)/localversion'
+ echo 'override ARCH = $(KERNEL_ARCH)' >> '$(DIR)/.kernelvariables'
+ echo 'CCACHE = ccache' >> '$(DIR)/.kernelvariables'
+ echo 'CC = $$(if $$(DEBIAN_KERNEL_USE_CCACHE),$$(CCACHE)) $$(CROSS_COMPILE)$(COMPILER)' >> '$(DIR)/.kernelvariables'
+ echo 'ifneq ($$(DEB_BUILD_ARCH),$$(DEB_HOST_ARCH))' >> '$(DIR)/.kernelvariables'
+ echo 'override CROSS_COMPILE = $$(DEB_HOST_GNU_TYPE)-' >> '$(DIR)/.kernelvariables'
+ echo 'endif' >> '$(DIR)/.kernelvariables'
+ cd '$(DIR)'; $(setup_env) make reportoldconfig
+endef
+
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-kernel-package:
+ $(SETUP_DIR)
+ cd '$(DIR)'; $(setup_env) $(kpkg_image) configure
+ touch '$@'
+
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-s390-tape:
+ $(SETUP_DIR)
+ cd '$(DIR)'; $(setup_env) make prepare $(JOBS_ARG)
+ touch '$@'
+
+$(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-xen:
+ $(SETUP_DIR)
+ cd '$(DIR)'; $(setup_env) make prepare $(JOBS_ARG)
+ touch '$@'
+
+$(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): DIR=$(BUILD_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)
+$(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): $(STAMPS_DIR)/setup-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE)
+
+$(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-kernel-package:
+ cd '$(DIR)'; $(setup_env) $(setup_env_kpkg_jobs) PATH='$(CURDIR)/build:$(CURDIR)/bin:$(PATH)' $(kpkg_image) build
+ python2.4 debian/bin/abicheck.py $(DIR) $(ARCH) $(SUBARCH) $(FLAVOUR)
+ touch '$@'
+
+$(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-s390-tape:
+ cd '$(DIR)'; $(setup_env) make $(JOBS_ARG) image
+ touch '$@'
+
+$(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-xen:
+ cd '$(DIR)'; $(setup_env) make $(JOBS_ARG)
+ python2.4 debian/bin/abicheck.py $(DIR) $(ARCH) $(SUBARCH) $(FLAVOUR)
+ touch '$@'
+
+install-base:
+ dh_installchangelogs
+ dh_installdocs
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_gencontrol -- $(GENCONTROL_ARGS)
+ dh_md5sums
+ dh_builddeb
+
+install-doc: PACKAGE_NAME_DOC = linux-doc-$(VERSION)
+install-doc: PACKAGE_NAME_MANUAL = linux-manual-$(VERSION)
+install-doc: SOURCE_DIR=$(BUILD_DIR)/source
+install-doc: DIR=$(BUILD_DIR)/$@
+install-doc: PACKAGE_DIR_DOC = $(CURDIR)/debian/$(PACKAGE_NAME_DOC)
+install-doc: PACKAGE_DIR_MANUAL = $(CURDIR)/debian/$(PACKAGE_NAME_MANUAL)
+install-doc: OUT_DIR_DOC = $(PACKAGE_DIR_DOC)/usr/share/doc/$(PACKAGE_NAME_DOC)
+install-doc: DH_OPTIONS = -p$(PACKAGE_NAME_DOC) -p$(PACKAGE_NAME_MANUAL)
+install-doc: $(STAMPS_DIR)/source
+ rm -rf '$(DIR)'
+ cp -al '$(SOURCE_DIR)' '$(DIR)'
+ dh_clean -d -k
+ cd '$(DIR)'; $(setup_env) make $(JOBS_ARG) htmldocs mandocs
+ DH_OPTIONS= dh_installman -p$(PACKAGE_NAME_MANUAL) '$(DIR)/Documentation/DocBook/'*.9 '$(DIR)/Documentation/DocBook/man/'*.9
+ cd $(DIR)/Documentation; \
+ find . \
+ -path './DocBook/man/*' -prune -o \
+ -path './DocBook/*' -a \( -name '*.tmpl' -o -name '*.xml' -o -name '*.9' \) -prune -o \
+ \( -name 'Makefile*' -o -name '.*.cmd' -o -name '.gitignore' \) -prune -o \
+ -print \
+ | \
+ cpio -pd --preserve-modification-time '$(OUT_DIR_DOC)/Documentation'
+ mv '$(OUT_DIR_DOC)/Documentation/DocBook' '$(OUT_DIR_DOC)/html'
+ -gzip -9qfr '$(OUT_DIR_DOC)/Documentation'
+ $(MAKE) -f debian/rules.real install-base
+
+install-dummy:
+ dh_testdir
+ dh_testroot
+ dh_clean -d -k
+ $(MAKE) -f debian/rules.real install-base
+
+install-headers-$(ARCH): PACKAGE_NAMES = linux-headers-$(UPSTREAMVERSION)$(ABINAME)-all linux-headers-$(UPSTREAMVERSION)$(ABINAME)-all-$(ARCH)
+install-headers-$(ARCH): DH_OPTIONS = $(foreach p, $(PACKAGE_NAMES), -p$(p))
+install-headers-$(ARCH):
+ dh_testdir
+ dh_testroot
+ $(MAKE) -f debian/rules.real install-base GENCONTROL_ARGS='-Vkernel:Arch=$(ARCH)'
+
+install-headers-$(ARCH)-$(SUBARCH): PACKAGE_NAME = linux-headers-$(UPSTREAMVERSION)$(ABINAME)$(LOCALVERSION_HEADERS)
+install-headers-$(ARCH)-$(SUBARCH): DH_OPTIONS = -p$(PACKAGE_NAME)
+install-headers-$(ARCH)-$(SUBARCH): BASE_DIR = /usr/src/$(PACKAGE_NAME)
+install-headers-$(ARCH)-$(SUBARCH): SOURCE_DIR = $(BUILD_DIR)/source-$(ARCH)-$(SUBARCH)
+install-headers-$(ARCH)-$(SUBARCH): DIR = $(CURDIR)/debian/$(PACKAGE_NAME)/$(BASE_DIR)
+install-headers-$(ARCH)-$(SUBARCH): $(STAMPS_DIR)/source-$(ARCH)-$(SUBARCH)
+ dh_testdir
+ dh_testroot
+ dh_clean -k -d
+ cd $(SOURCE_DIR); \
+ ( \
+ find . \
+ -path './Documentation/*' -prune -o \
+ -path './arch/*' -prune -o \
+ -path './include/asm*' -prune -o \
+ -path './scripts/*' -prune -o \
+ -path './include/*' -print -o \
+ \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Rules.make' \) -print; \
+ find include/asm-generic -print; \
+ for i in $(KERNEL_HEADER_DIRS); do \
+ find arch/$$i \
+ \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Rules.make' \) -print; \
+ find include/asm-$$i -print; \
+ done; \
+ ) \
+ | \
+ cpio -pd --preserve-modification-time $(DIR)
+ $(MAKE) -f debian/rules.real install-base
+
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): REAL_VERSION = $(UPSTREAMVERSION)$(ABINAME)$(LOCALVERSION)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): PACKAGE_NAME = linux-headers-$(REAL_VERSION)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): PACKAGE_NAME_HEADERS = linux-headers-$(UPSTREAMVERSION)$(ABINAME)$(LOCALVERSION_HEADERS)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): PACKAGE_NAME_KBUILD = linux-kbuild-$(VERSION)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): DH_OPTIONS = -p$(PACKAGE_NAME)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): BASE_DIR = /usr/src/$(PACKAGE_NAME)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): SOURCE_DIR = $(BUILD_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): REF_DIR = $(BUILD_DIR)/source-$(ARCH)-$(SUBARCH)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): PACKAGE_DIR = $(CURDIR)/debian/$(PACKAGE_NAME)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): DIR = $(PACKAGE_DIR)/$(BASE_DIR)
+install-headers-$(ARCH)-$(SUBARCH)-$(FLAVOUR): $(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE)
+ dh_testdir
+ dh_testroot
+ dh_clean -k -d
+
+ mkdir -p "${DIR}/arch/${KERNEL_ARCH}/kernel"
+ mkdir -p "${DIR}/include"
+ cp -a ${SOURCE_DIR}/{.config,.kernel*,Module.symvers} "${DIR}"
+
+ cd ${SOURCE_DIR}; \
+ find . -mindepth 1 -maxdepth 1 \
+ ! -name debian -a ! -name Documentation -a ! -name include -a \
+ ! -name DEBIAN -a ! -name scripts -a ! -name arch -a ! -name '.*' -a \( \
+ -name Makefile -o -type d \) \
+ -printf "../${PACKAGE_NAME_HEADERS}/%f\n" | \
+ xargs ln -s --target-directory="${DIR}"
+
+ cd ${SOURCE_DIR}; \
+ find "arch/${KERNEL_ARCH}" -mindepth 1 -maxdepth 1 \( \
+ -type d -a ! -name include -a ! -name kernel -o \
+ -type f -a \( -name 'Makefile*' -o -name 'Kconfig*' \) \) \
+ -printf "../../../${PACKAGE_NAME_HEADERS}/%p\n" | \
+ xargs ln -s --target-directory="${DIR}/arch/${KERNEL_ARCH}"
+
+ [ -d "${SOURCE_DIR}/arch/${KERNEL_ARCH}/include" ] && \
+ cp -a "${SOURCE_DIR}/arch/${KERNEL_ARCH}/include" "${DIR}/arch/${KERNEL_ARCH}/include" || :
+ [ -f "${SOURCE_DIR}/arch/${KERNEL_ARCH}/kernel/asm-offsets.s" ] && \
+ ln -f "${SOURCE_DIR}/arch/${KERNEL_ARCH}/kernel/asm-offsets.s" "${DIR}/arch/${KERNEL_ARCH}/kernel" || :
+ [ -f "${SOURCE_DIR}/arch/${KERNEL_ARCH}/module.lds" ] && \
+ ln -f "${SOURCE_DIR}/arch/${KERNEL_ARCH}/module.lds" "${DIR}/arch/${KERNEL_ARCH}" || :
+ ln -s "../../../../${PACKAGE_NAME_HEADERS}/arch/${KERNEL_ARCH}/kernel/Makefile" "${DIR}/arch/${KERNEL_ARCH}/kernel"
+
+ cd ${SOURCE_DIR}; \
+ find include -mindepth 1 -maxdepth 1 \
+ ! -name config -a ! -name linux -a ! -name 'asm*' \
+ -printf "../../${PACKAGE_NAME_HEADERS}/%p\n" | \
+ xargs ln -s --target-directory="${DIR}/include"
+ cp -a ${SOURCE_DIR}/include/config "${DIR}/include"
+
+ ln -sf "asm-${KERNEL_ARCH}" "${DIR}/include/asm"
+
+ cd ${SOURCE_DIR}; \
+ for dir in linux asm-generic $(foreach t, $(KERNEL_HEADER_DIRS), asm-$(t)); do \
+ mkdir "${DIR}/include/$$dir"; \
+ for file in $$(find "include/$$dir" -mindepth 1 -maxdepth 1); do \
+ if [ -e ${CURDIR}/${REF_DIR}/$$file ]; then \
+ ln -s --target-directory="${DIR}/include/$$dir" "../../../${PACKAGE_NAME_HEADERS}/$$file"; \
+ elif [ -d ${CURDIR}/${SOURCE_DIR}/$$file ]; then \
+ cp -a "${CURDIR}/${SOURCE_DIR}/$$file" "${DIR}/include/$$dir"; \
+ else \
+ ln -f --target-directory="${DIR}/include/$$dir" "${CURDIR}/${SOURCE_DIR}/$$file"; \
+ fi \
+ done \
+ done
+
+ mkdir -p "${PACKAGE_DIR}/lib/modules/${REAL_VERSION}"
+ ln -s "/usr/src/${PACKAGE_NAME}" "${PACKAGE_DIR}/lib/modules/${REAL_VERSION}/build"
+
+ ln -s "../${PACKAGE_NAME_KBUILD}/scripts" "${DIR}"
+
+ $(MAKE) -f debian/rules.real install-base
+
+install-support: PACKAGE_NAME = linux-support-$(UPSTREAMVERSION)$(ABINAME)
+install-support: DH_OPTIONS = -p$(PACKAGE_NAME)
+install-support: PACKAGE_DIR = $(CURDIR)/debian/$(PACKAGE_NAME)
+install-support:
+ dh_testdir
+ dh_testroot
+ dh_clean -k -d
+ chmod a+x debian/modules/gencontrol.py
+ dh_install debian/arch debian/lib debian/modules /usr/src/$(PACKAGE_NAME)
+ dh_python -V 2.4 /usr/src/$(PACKAGE_NAME)/lib/python
+ echo -e "[version]\nsource: $(SOURCEVERSION)\nabiname: $(ABINAME)" > $(PACKAGE_DIR)/usr/src/$(PACKAGE_NAME)/version
+ $(MAKE) -f debian/rules.real install-base
+
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): REAL_VERSION = $(UPSTREAMVERSION)$(ABINAME)$(LOCALVERSION)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): PACKAGE_NAME = linux-image-$(REAL_VERSION)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): PACKAGE_DIR = $(CURDIR)/debian/$(PACKAGE_NAME)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): INSTALL_DIR = $(PACKAGE_DIR)/boot
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): DIR=$(BUILD_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE): $(STAMPS_DIR)/build-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-$(TYPE)
+
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-kernel-package:
+ifdef IMAGE_POSTPROC
+# Install the postproc script into the hook directory
+ install -d '$(DIR)/debian/image.d'
+ install 'debian/bin/$(IMAGE_POSTPROC)' '$(DIR)/debian/image.d'
+endif
+ cd '$(DIR)'; $(setup_env) $(kpkg_image) kernel-image
+ cat '$(DIR)/debian/files' >> debian/files
+ @for i in $$(awk '{ print $$1; }' '$(DIR)/debian/files'); do \
+ echo "mv \"$(BUILD_DIR)/$$i\" .."; \
+ mv "$(BUILD_DIR)/$$i" ..; \
+ done
+
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-s390-tape: DH_OPTIONS = -p$(PACKAGE_NAME)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-s390-tape:
+ dh_testdir
+ dh_testroot
+ dh_clean -d -k
+ dh_installdirs 'boot'
+ cp '$(DIR)/arch/s390/boot/image' $(PACKAGE_DIR)/boot/vmlinuz-$(REAL_VERSION)
+ $(MAKE) -f debian/rules.real install-base
+
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-xen: MODULES_PACKAGE_NAME = linux-modules-$(REAL_VERSION)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-xen: MODULES_PACKAGE_DIR = $(CURDIR)/debian/$(MODULES_PACKAGE_NAME)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-xen: DH_OPTIONS = -p$(PACKAGE_NAME) -p$(MODULES_PACKAGE_NAME)
+install-image-$(ARCH)-$(SUBARCH)-$(FLAVOUR)-plain-xen:
+ dh_testdir
+ dh_testroot
+ dh_clean -d -k
+ DH_OPTIONS= dh_installdirs -p$(PACKAGE_NAME) 'boot' 'var/lib/$(PACKAGE_NAME)'
+ DH_OPTIONS= dh_installdirs -p$(MODULES_PACKAGE_NAME) 'boot'
+ cp $(DIR)/vmlinuz $(INSTALL_DIR)/vmlinuz-$(REAL_VERSION)
+ cd $(DIR); $(setup_env) make modules_install INSTALL_MOD_PATH=$(MODULES_PACKAGE_DIR)
+ cp $(DIR)/.config $(MODULES_PACKAGE_DIR)/boot/config-$(REAL_VERSION)
+ cp $(DIR)/System.map $(MODULES_PACKAGE_DIR)/boot/System.map-$(REAL_VERSION)
+ rm $(MODULES_PACKAGE_DIR)/lib/modules/$(REAL_VERSION)/{build,source}
+ DH_OPTIONS= dh_installmodules -p$(MODULES_PACKAGE_NAME)
+ for i in $(XEN_VERSIONS); do echo $$i >> $(PACKAGE_DIR)/var/lib/$(PACKAGE_NAME)/xen-versions; done
+ install -d $(PACKAGE_DIR)/DEBIAN
+ echo /var/lib/$(PACKAGE_NAME)/xen-versions >> $(PACKAGE_DIR)/DEBIAN/conffiles
+ $(MAKE) -f debian/rules.real install-base
+
+install-patch: PACKAGE = linux-patch-debian-$(VERSION)
+install-patch: pbase := /usr/src/kernel-patches/all/$(UPSTREAMVERSION)
+install-patch: pfull := debian/$(PACKAGE)$(pbase)
+install-patch: DH_OPTIONS = -p$(PACKAGE)
+install-patch:
+ dh_testdir
+ dh_testroot
+ dh_clean -d -k $(DH_OPTIONS)
+ dh_installdirs $(DH_OPTIONS) '$(pbase)/apply' '$(pbase)/debian' '$(pbase)/unpatch'
+ dh_install $(DH_OPTIONS) debian/patches/* '$(pbase)/debian'
+ install debian/bin/patch.apply '$(pfull)/apply/debian'
+ install debian/bin/patch.unpatch '$(pfull)/unpatch/debian'
+ find '$(pfull)/debian' ! -path '*/series/*' -type f -execdir bzip2 '{}' ';' -execdir chmod 644 '{}.bz2' ';'
+ $(MAKE) -f debian/rules.real install-base DH_OPTIONS='$(DH_OPTIONS)'
+
+install-source: DH_OPTIONS = -plinux-source-$(VERSION)
+install-source: $(BUILD_DIR)/linux-source-$(UPSTREAMVERSION).tar.bz2
+ dh_testdir
+ dh_testroot
+ dh_install $(DH_OPTIONS) '$<' /usr/src
+ $(MAKE) -f debian/rules.real install-base DH_OPTIONS='$(DH_OPTIONS)'
+
+install-tree: DH_OPTIONS = -plinux-tree-$(VERSION)
+install-tree:
+ $(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='$(DH_OPTIONS)'
+
+# vim: filetype=make
Added: people/maks-guest/linux-2.6/debian/templates/control.headers.arch.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.headers.arch.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,19 @@
+Package: linux-headers- at upstreamversion@@abiname at -all
+Section: devel
+Priority: optional
+Provides: linux-headers- at major@-all, linux-headers- at version@-all
+Depends: linux-headers- at upstreamversion@@abiname at -all-${kernel:Arch} (= ${Source-Version})
+Description: All header files for Linux @version@
+ This package depends against all architecture-specific kernel header files
+ for Linux kernel version @upstreamversion@, generally used for building out-of-tree
+ kernel modules.
+
+Package: linux-headers- at upstreamversion@@abiname at -all-@arch@
+Section: devel
+Priority: optional
+Provides: linux-headers- at major@-all- at arch@, linux-headers- at version@-all- at arch@
+Description: All header files for Linux @version@
+ This package depends against all architecture-specific kernel header files
+ for Linux kernel version @upstreamversion@, generally used for building out-of-tree
+ kernel modules.
+
Added: people/maks-guest/linux-2.6/debian/templates/control.headers.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.headers.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,12 @@
+Package: linux-headers- at upstreamversion@@abiname@@localversion@
+Section: devel
+Priority: optional
+Depends: linux-headers- at upstreamversion@@abiname@@localversion_headers@ (= ${Source-Version}), linux-kbuild- at version@
+Provides: linux-headers, linux-headers- at major@
+Description: Header files for Linux @upstreamversion@ on @class@
+ This package provides the architecture-specific kernel header files
+ for Linux kernel @upstreamversion@ on @longclass@ machines, generally
+ used for building out-of-tree kernel modules. These files are going to be
+ installed into /usr/src/linux-headers- at upstreamversion@@abiname@@localversion@, and can
+ be used for building modules that load into the kernel provided by the
+ linux-image- at upstreamversion@@abiname@@localversion@ package.
Added: people/maks-guest/linux-2.6/debian/templates/control.headers.subarch.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.headers.subarch.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,15 @@
+Package: linux-headers- at upstreamversion@@abiname@@localversion_headers@
+Section: devel
+Priority: optional
+Provides: linux-headers, linux-headers- at major@
+Description: Common header files for Linux @upstreamversion@
+ This package provides the (sub)architecture-specific common kernel header files
+ for Linux kernel version @upstreamversion@, generally used for building out-of-tree
+ kernel modules. To obtain a complete set of headers you also need to install
+ the linux-headers- at upstreamversion@@abiname at -(flavour) package, matching the
+ flavour of the kernel you intend the build for. To obtain such a set for the
+ currently running kernel it is sufficient to run a command
+ .
+ apt-get install linux-headers-$(uname -r)
+ .
+ and it will be unpacked in /usr/src/linux-headers- at upstreamversion@@abiname at -(flavour).
Added: people/maks-guest/linux-2.6/debian/templates/control.image.type-modulesextra.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.image.type-modulesextra.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,19 @@
+Package: linux-image- at upstreamversion@@abiname@@localversion@
+Section: admin
+Priority: optional
+Provides: linux-image, linux-image- at major@
+Depends: linux-modules- at upstreamversion@@abiname@@localversion@ (= ${Source-Version})
+Suggests: linux-doc- at version@
+Description: Linux @upstreamversion@ image on @class@
+ This package provides the binary image for
+ Linux kernel @upstreamversion@ on @longclass@ machines.
+ .
+ @desc@
+
+Package: linux-modules- at upstreamversion@@abiname@@localversion@
+Section: admin
+Priority: optional
+Depends: module-init-tools (>= 0.9.13)
+Description: Linux @upstreamversion@ modules on @class@
+ This package provides pre-built loadable modules for
+ Linux kernel @version@ on @longclass@ machines.
Added: people/maks-guest/linux-2.6/debian/templates/control.image.type-modulesinline.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.image.type-modulesinline.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,11 @@
+Package: linux-image- at upstreamversion@@abiname@@localversion@
+Section: admin
+Priority: optional
+Provides: linux-image, linux-image- at major@, linux-modules- at upstreamversion@@abiname@@localversion@
+Depends: module-init-tools (>= 0.9.13)
+Suggests: linux-doc- at version@
+Description: Linux @upstreamversion@ image on @class@
+ This package provides the binary image and pre-built loadable modules for
+ Linux kernel @upstreamversion@ on @longclass@ machines.
+ .
+ @desc@
Added: people/maks-guest/linux-2.6/debian/templates/control.image.type-standalone.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.image.type-standalone.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,10 @@
+Package: linux-image- at upstreamversion@@abiname@@localversion@
+Section: admin
+Priority: optional
+Provides: linux-image, linux-image- at major@
+Suggests: linux-doc- at version@
+Description: Linux @upstreamversion@ image on @class@
+ This package provides the binary image for
+ Linux kernel @upstreamversion@ on @longclass@ machines.
+ .
+ @desc@
Added: people/maks-guest/linux-2.6/debian/templates/control.main.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.main.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,64 @@
+Package: linux-source- at version@
+Architecture: all
+Section: devel
+Priority: optional
+Provides: linux-source, linux-source- at major@
+Depends: binutils, bzip2
+Recommends: libc6-dev | libc-dev, gcc, make
+Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-mt-dev
+Description: Linux kernel source for version @version@ with Debian patches
+ This package provides source code for the Linux kernel version @version at .
+ This source closely tracks official Linux kernel releases. Debian's
+ modifications to that source consist of security fixes, bug fixes, and
+ features that have already been (or we believe will be) accepted by the
+ upstream maintainers.
+ .
+ If you wish to use this package to create a custom Linux kernel, then
+ it is suggested that you investigate the package kernel-package,
+ which has been designed to ease the task of creating kernel image
+ packages.
+
+Package: linux-doc- at version@
+Architecture: all
+Section: doc
+Priority: optional
+Provides: linux-doc- at major@
+Description: Linux kernel specific documentation for version @version@
+ This package provides the various README files and HTML documentation for
+ the Linux kernel version @version at . Plenty of information, including the
+ descriptions of various kernel subsystems, filesystems, driver-specific
+ notes and the like. Consult the file
+ .
+ /usr/share/doc/linux-doc- at version@/Documentation/00-INDEX
+ .
+ for the detailed description of the contents.
+
+Package: linux-manual- at version@
+Architecture: all
+Section: doc
+Priority: optional
+Provides: linux-manual, kernel-manual- at major@
+Conflicts: linux-manual, kernel-manual- at major@
+Replaces: linux-manual, kernel-manual- at major@
+Description: Linux kernel API manual pages for version @version@
+ This package provides the Kernel Hacker's Guide in the form of
+ manual pages, describing the kernel API functions. They
+ are installed into section 9 of the manual.
+ .
+ As the files containing manual pages for different kernel versions
+ are installed in the same location, only one linux-manual package
+ may be installed at a time. The linux-doc package containing the
+ documentation in other formats is free from such restriction.
+
+Package: linux-patch-debian- at version@
+Architecture: all
+Section: devel
+Priority: optional
+Depends: bzip2, python2.4-minimal
+Suggests: linux-source- at version@
+Description: Debian patches to version @version@ of the Linux kernel
+ This package includes the patches used to produce the prepackaged
+ linux-source- at version@ package, as well as architecture-specific
+ patches. Note that these patches do NOT apply against a pristine
+ Linux @version@ kernel but only against the kernel tarball
+ linux- at major@_ at source_upstream@.orig.tar.gz from the Debian archive.
Added: people/maks-guest/linux-2.6/debian/templates/control.source.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.source.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,8 @@
+Source: linux- at major@
+Section: devel
+Priority: optional
+Maintainer: Debian Kernel Team <debian-kernel at lists.debian.org>
+Uploaders: Andres Salomon <dilinger at debian.org>, Bastian Blank <waldi at debian.org>, Simon Horman <horms at debian.org>, Sven Luther <luther at debian.org>, Jonas Smedegaard <dr at jones.dk>, Norbert Tretkowski <nobse at debian.org>, Frederik Schüler <fs at debian.org>
+Standards-Version: 3.6.1.0
+Build-Depends: debhelper (>= 4.1.0), module-init-tools, dpkg-dev (>= 1.10.23), debianutils (>= 1.6), bzip2, sparc-utils [sparc], kernel-package (>= 10.063), python, python2.4-minimal
+Build-Depends-Indep: docbook-utils, gs, transfig, xmlto
Added: people/maks-guest/linux-2.6/debian/templates/control.support.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.support.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,8 @@
+Package: linux-support- at upstreamversion@@abiname@
+Architecture: all
+Section: devel
+Priority: optional
+Depends: python2.4-minimal
+Description: Support files for Linux @upstreamversion@
+ This package provides support files for the Linux kernel build.
+
Added: people/maks-guest/linux-2.6/debian/templates/control.tree.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.tree.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,24 @@
+Package: linux-tree- at version@
+Architecture: all
+Section: devel
+Priority: optional
+Description: Linux kernel source tree for building Debian kernel images
+ This meta package is used as a build dependency of Debian
+ linux-image packages to prevent a version discrepancy between
+ the linux-image and corresponding linux-sources packages in the
+ fast-moving unstable archive. The package's dependency relations
+ are structured so that a linux-image package's build
+ dependencies can always be satisfied, even if the linux-source
+ package that had been used to compile the image has been
+ superseeded by a newer Debian revision since the last build.
+ .
+ The package provides a list of virtual packages, corresponding to
+ Debian revisions of a linux-source package. The Debian
+ linux-patch contains the information needed to roll back the
+ current linux-source to any of the revisions identified by the
+ provided virtual packages. Therefore, the linux-tree package
+ ensures the availability of the Linux kernel source tree corresponding
+ to each of the virtual packages listed.
+ .
+ The package serves no purpose outside of the Debian build and
+ archive infrastructure.
Added: people/maks-guest/linux-2.6/debian/templates/control.xen-linux-system.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/control.xen-linux-system.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,7 @@
+Package: xen-linux-system- at upstreamversion@@abiname@@localversion@
+Section: admin
+Priority: extra
+Depends: linux-image- at upstreamversion@@abiname@@localversion@ (= ${Source-Version})
+Description: XEN system with Linux @upstreamversion@ image on @class@
+ This package depends on the binary Linux image and the correct hypervisor.
+
Added: people/maks-guest/linux-2.6/debian/templates/image.xen.postinst.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/image.xen.postinst.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+case "$1" in
+ configure)
+ if [ "$2" ]; then
+ update-initramfs -u -k @upstreamversion@@abiname@@localversion@
+ else
+ update-initramfs -c -k @upstreamversion@@abiname@@localversion@
+ command -v update-grub > /dev/null && update-grub
+ fi
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
+
Added: people/maks-guest/linux-2.6/debian/templates/image.xen.postrm.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/image.xen.postrm.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+case "$1" in
+ remove)
+ command -v update-grub > /dev/null && update-grub
+ ;;
+
+ purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
Added: people/maks-guest/linux-2.6/debian/templates/image.xen.prerm.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/image.xen.prerm.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+case "$1" in
+ remove)
+ update-initramfs -d -k @upstreamversion@@abiname@@localversion@ || true
+ ;;
+
+ upgrade|deconfigure|failed-upgrade)
+ ;;
+
+ *)
+ echo "prerm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
+
Added: people/maks-guest/linux-2.6/debian/templates/patch.apply.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/patch.apply.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,423 @@
+#!/usr/bin/env python2.4
+
+import os, os.path, re, sys
+from warnings import warn
+
+_default_home = "@home@"
+_default_revisions = "@revisions@"
+_default_source = "@source@"
+
+class series(list):
+ def __init__(self, name, home, reverse = False):
+ self.name = name
+ self.reverse = reverse
+
+ filename = os.path.join(home, 'series', name)
+ if not os.path.exists(filename):
+ raise RuntimeError, "Can't find series file for %s" % name
+
+ f = file(filename)
+ for line in f.readlines():
+ line = line.strip()
+
+ if len(line) == 0 or line[0] == '#':
+ continue
+
+ items = line.split(' ')
+ if len(items) != 2:
+ raise RuntimeError, "Line '%s' in file %s malformed." % (line, filename)
+ else:
+ operation, patch = items
+
+ if operation in ('+', '-'):
+ patchfile = os.path.join(home, patch)
+ for suffix, type in (('', 0), ('.bz2', 1), ('.gz', 2)):
+ if os.path.exists(patchfile + suffix):
+ patchinfo = patchfile + suffix, type
+ break
+ else:
+ raise RuntimeError, "Can't find patch %s for series %s" % (patchfile, name)
+ else:
+ raise RuntimeError, 'Undefined operation "%s" in series %s' % (operation, name)
+
+ self.append((operation, patch, patchinfo))
+
+ def __repr__(self):
+ return '<%s object for %s>' % (self.__class__.__name__, self.name)
+
+ def apply(self):
+ if self.reverse:
+ for operation, patch, patchinfo in self[::-1]:
+ if operation == '.':
+ print """\
+ (.) IGNORED %s\
+""" % patch
+ elif operation == '+':
+ self.patch_deapply(patch, patchinfo)
+ elif operation == '-':
+ self.patch_apply(patch, patchinfo)
+ print "--> %s fully unapplied." % self.name
+
+ else:
+ for operation, patch, patchinfo in self:
+ if operation == '.':
+ print """\
+ (.) IGNORED %s\
+""" % patch
+ elif operation == '+':
+ self.patch_apply(patch, patchinfo)
+ elif operation == '-':
+ self.patch_deapply(patch, patchinfo)
+ print "--> %s fully applied." % self.name
+
+ def patch_apply(self, patch, patchinfo):
+ ret = self.patch_call(patchinfo, '--fuzz=1')
+ if ret == 0:
+ print """\
+ (+) OK %s\
+""" % patch
+ else:
+ print """\
+ (+) FAIL %s\
+""" % patch
+ raise SystemExit, 1
+
+ def patch_call(self, patchinfo, patchargs):
+ patchfile, type = patchinfo
+ cmdline = []
+ if type == 0:
+ cmdline.append('cat')
+ elif type == 1:
+ cmdline.append('bzcat')
+ elif type == 2:
+ cmdline.append('zcat')
+ cmdline.append(patchfile + ' | patch -p1 -f -s -t --no-backup-if-mismatch')
+ cmdline.append(patchargs)
+ return os.spawnv(os.P_WAIT, '/bin/sh', ['sh', '-c', ' '.join(cmdline)])
+
+ def patch_deapply(self, patch, patchinfo):
+ ret = self.patch_call(patchinfo, '-R')
+ if ret == 0:
+ print """\
+ (-) OK %s\
+""" % patch
+ else:
+ print """\
+ (-) FAIL %s\
+""" % patch
+ raise SystemExit, 1
+
+ @staticmethod
+ def read_all(s, home, reverse = False):
+ ret = []
+
+ for name in s:
+ filename = os.path.join(home, 'series', name)
+ if not os.path.exists(filename):
+ warn("Can't find series file for %s" % name)
+ else:
+ i = series(name, home, reverse)
+ ret.append(i)
+
+ return ret
+
+class series_extra(series):
+ def __init__(self, name, home, extra, reverse = False):
+ self.extra = extra
+ self.extra_used = ()
+ self.name = name
+ self.reverse = reverse
+
+ filename = os.path.join(home, 'series', name + '-extra')
+ if not os.path.exists(filename):
+ raise RuntimeError, "Can't find series file for %s" % name
+
+ f = file(filename)
+ for line in f.readlines():
+ line = line.strip()
+
+ if len(line) == 0 or line[0] == '#':
+ continue
+
+ items = line.split(' ')
+ operation, patch = items[:2]
+
+ if operation in ('+', '-'):
+ patchfile = os.path.join(home, patch)
+ for suffix, type in (('', 0), ('.bz2', 1), ('.gz', 2)):
+ if os.path.exists(patchfile + suffix):
+ patchinfo = patchfile + suffix, type
+ break
+ else:
+ raise RuntimeError, "Can't find patch %s for series %s" % (patchfile, name)
+ else:
+ raise RuntimeError, 'Undefined operation "%s" in series %s' % (operation, name)
+
+ extra = {}
+ for s in items[2:]:
+ s = tuple(s.split('_'))
+ if len(s) > 3:
+ raise RuntimeError, "parse error"
+ if len(s) == 3:
+ raise RuntimeError, "Patch per flavour is not supported currently"
+ extra[s] = True
+ if not self._check_extra(extra):
+ operation = '.'
+
+ self.append((operation, patch, patchinfo))
+
+ def _check_extra(self, extra):
+ for i in (1, 2, 3):
+ t = self.extra[:i]
+ if extra.has_key(t):
+ if i > len(self.extra_used):
+ self.extra_used = t
+ return True
+ for i in (2, 3):
+ t = ('*',) + self.extra[1:i]
+ if extra.has_key(t):
+ if i > len(self.extra_used):
+ self.extra_used = t
+ return True
+ return False
+
+ @staticmethod
+ def read_all(s, home, extra, reverse = False):
+ ret = []
+
+ for name in s:
+ filename = os.path.join(home, 'series', name + '-extra')
+ if not os.path.exists(filename):
+ warn("Can't find series file for %s" % name)
+ else:
+ i = series_extra(name, home, extra, reverse)
+ ret.append(i)
+
+ return ret
+
+class version(object):
+ __slots__ = "upstream", "revision"
+
+ def __init__(self, string = None):
+ if string is not None:
+ self.upstream, self.revision = self.parse(string)
+
+ def __str__(self):
+ return "%s-%s" % (self.upstream, self.revision)
+
+ _re = r"""
+^
+(
+ (?:
+ \d+\.\d+\.\d+\+
+ )?
+ \d+\.\d+\.\d+
+ (?:
+ -.+?
+ )?
+)
+-
+([^-]+)
+$
+"""
+
+ def parse(self, version):
+ match = re.match(self._re, version, re.X)
+ if match is None:
+ raise ValueError
+ return match.groups()
+
+class version_file(object):
+ _file = 'version.Debian'
+ extra = ()
+ in_progress = False
+
+ def __init__(self, ver = None, overwrite = False):
+ if overwrite:
+ self._read(ver)
+ elif os.path.exists(self._file):
+ s = file(self._file).readline().strip()
+ self._read(s)
+ elif ver:
+ warn('No %s file, assuming pristine Linux %s' % (self._file, ver.upstream))
+ self.version = version()
+ self.version.upstream = ver.upstream
+ self.version.revision = '0'
+ else:
+ raise RuntimeError, "Not possible to determine version"
+
+ def __str__(self):
+ if self.in_progress:
+ return "unstable"
+ if self.extra:
+ return "%s %s" % (self.version, '_'.join(self.extra))
+ return str(self.version)
+
+ def _read(self, s):
+ list = s.split(' ')
+ if len(list) > 2:
+ raise RuntimeError, "Can't parse %s" % self._file
+ try:
+ self.version = version(list[0])
+ except ValueError:
+ raise RuntimeError, 'Can\'t read version in %s: "%s"' % (self._file, list[0])
+ if len(list) == 2:
+ self.extra = tuple(list[1].split('_'))
+
+ def _write(self):
+ if os.path.lexists(self._file):
+ os.unlink(self._file)
+ file(self._file, 'w').write('%s\n' % self)
+
+ def begin(self):
+ self.in_progress = True
+ self._write()
+
+ def commit(self, version = None, extra = None):
+ self.in_progress = False
+ if version is not None:
+ self.version = version
+ if extra is not None:
+ self.extra = extra
+ self._write()
+
+def main():
+ options, args = parse_options()
+
+ if len(args) > 1:
+ print "Too much arguments"
+ return
+
+ home = options.home
+ revisions = ['0'] + options.revisions.split()
+ source = version(options.source)
+ if len(args) == 1:
+ target = version(args[0])
+ else:
+ target = source
+
+ if options.current is not None:
+ vfile = version_file(options.current, True)
+ else:
+ vfile = version_file(source)
+ current = vfile.version
+ current_extra = vfile.extra
+
+ target_extra = []
+ if options.arch: target_extra.append(options.arch)
+ if options.subarch: target_extra.append(options.subarch)
+ if options.flavour: target_extra.append(options.flavour)
+ target_extra = tuple(target_extra)
+
+ if current.revision not in revisions:
+ raise RuntimeError, "Current revision is not in our list of revisions"
+ if target.revision not in revisions:
+ raise RuntimeError, "Target revision is not in our list of revisions"
+
+ if current.revision == target.revision and current_extra == target_extra:
+ print "Nothing to do"
+ return
+
+ current_index = revisions.index(current.revision)
+ source_index = revisions.index(source.revision)
+ target_index = revisions.index(target.revision)
+
+ if current_extra:
+ if current_index != source_index:
+ raise RuntimeError, "Can't patch from %s with options %s" % (current, ' '.join(current_extra))
+ consider = revisions[current_index:0:-1]
+ s = series_extra.read_all(consider, home, current_extra, reverse = True)
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(current, ())
+
+ if current_index < target_index:
+ consider = revisions[current_index + 1:target_index + 1]
+ s = series.read_all(consider, home)
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(target, ())
+ elif current_index > target_index:
+ consider = revisions[current_index:target_index:-1]
+ s = series.read_all(consider, home, reverse = True)
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(target, ())
+
+ if target_extra:
+ consider = revisions[1:target_index + 1]
+ s = series_extra.read_all(consider, home, target_extra)
+ real_extra = ()
+ for i in s:
+ t = i.extra_used
+ if len(t) > len(real_extra):
+ real_extra = t
+ vfile.begin()
+ for i in s:
+ i.apply()
+ vfile.commit(target, real_extra)
+
+def parse_options():
+ from optparse import OptionParser
+ parser = OptionParser(
+ usage = "%prog [OPTION]... [TARGET]",
+ )
+ parser.add_option(
+ '-a', '--arch',
+ dest = 'arch',
+ help = "arch",
+ )
+ parser.add_option(
+ '-f', '--flavour',
+ dest = 'flavour',
+ help = "flavour",
+ )
+ parser.add_option(
+ '-s', '--subarch',
+ dest = 'subarch',
+ help = "subarch",
+ )
+ parser.add_option(
+ '-C', '--overwrite-current',
+ dest = 'current',
+ help = "overwrite current",
+ )
+ parser.add_option(
+ '-H', '--overwrite-home',
+ default = _default_home, dest = 'home',
+ help = "overwrite home [default: %default]",
+ )
+ parser.add_option(
+ '-R', '--overwrite-revisions',
+ default = _default_revisions, dest = 'revisions',
+ help = "overwrite revisions [default: %default]",
+ )
+ parser.add_option(
+ '-S', '--overwrite-source',
+ default = _default_source, dest = 'source',
+ help = "overwrite source [default: %default]",
+ )
+
+ options, args = parser.parse_args()
+
+ if options.arch is None and options.subarch is not None:
+ raise RuntimeError('You specified a subarch without an arch, this is not really working')
+ if options.subarch is None and options.flavour is not None:
+ raise RuntimeError('You specified a flavour without a subarch, this is not really working')
+
+ return options, args
+
+if __name__ == '__main__':
+ def showwarning(message, category, filename, lineno):
+ sys.stderr.write("Warning: %s\n" % message)
+ import warnings
+ warnings.showwarning = showwarning
+ try:
+ main()
+ except RuntimeError, e:
+ sys.stderr.write("Error: %s\n" % e)
+ raise SystemExit, 1
+
Added: people/maks-guest/linux-2.6/debian/templates/patch.unpatch.in
==============================================================================
--- (empty file)
+++ people/maks-guest/linux-2.6/debian/templates/patch.unpatch.in Sat Nov 11 02:48:00 2006
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -e
+
+upstream="@upstream@"
+exec "/usr/src/kernel-patches/all/$upstream/apply/debian" "$upstream-0"
More information about the Kernel-svn-changes
mailing list